aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-07-23 10:20:10 +0100
committerDavid Woodhouse <dwmw2@infradead.org>2007-07-23 10:20:10 +0100
commit39fe5434cb9de5da40510028b17b96bc4eb312b3 (patch)
tree7a02a317b9ad57da51ca99887c119e779ccf3f13
parent[JFFS2] Add declaration of jffs2_lzo_{init,exit} to compr.h (diff)
parentLinux 2.6.23-rc1 (diff)
downloadlinux-dev-39fe5434cb9de5da40510028b17b96bc4eb312b3.tar.xz
linux-dev-39fe5434cb9de5da40510028b17b96bc4eb312b3.zip
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
-rw-r--r--.gitignore4
-rw-r--r--CREDITS10
-rw-r--r--Documentation/00-INDEX142
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb13
-rw-r--r--Documentation/CodingStyle59
-rw-r--r--Documentation/DMA-mapping.txt103
-rw-r--r--Documentation/DocBook/Makefile10
-rw-r--r--Documentation/DocBook/kernel-api.tmpl64
-rw-r--r--Documentation/DocBook/kernel-locking.tmpl2
-rw-r--r--Documentation/DocBook/libata.tmpl5
-rw-r--r--Documentation/DocBook/procfs-guide.tmpl82
-rw-r--r--Documentation/DocBook/uio-howto.tmpl611
-rw-r--r--Documentation/HOWTO3
-rw-r--r--Documentation/RCU/checklist.txt10
-rw-r--r--Documentation/SubmitChecklist3
-rw-r--r--Documentation/SubmittingPatches22
-rw-r--r--Documentation/accounting/getdelays.c19
-rw-r--r--Documentation/accounting/taskstats-struct.txt6
-rw-r--r--Documentation/blackfin/kgdb.txt155
-rw-r--r--Documentation/cachetlb.txt2
-rw-r--r--Documentation/cdrom/00-INDEX22
-rw-r--r--Documentation/cdrom/aztcd822
-rw-r--r--Documentation/cdrom/cdu31a196
-rw-r--r--Documentation/cdrom/cm206185
-rw-r--r--Documentation/cdrom/gscd60
-rw-r--r--Documentation/cdrom/isp16100
-rw-r--r--Documentation/cdrom/mcdx29
-rw-r--r--Documentation/cdrom/optcd57
-rw-r--r--Documentation/cdrom/sbpcd1061
-rw-r--r--Documentation/cdrom/sjcd60
-rw-r--r--Documentation/cdrom/sonycd535122
-rw-r--r--Documentation/connector/cn_test.c3
-rw-r--r--Documentation/console/console.txt2
-rw-r--r--Documentation/driver-model/devres.txt2
-rw-r--r--Documentation/drivers/edac/edac.txt192
-rw-r--r--Documentation/dvb/bt8xx.txt32
-rw-r--r--Documentation/dvb/get_dvb_firmware63
-rw-r--r--Documentation/dvb/opera-firmware.txt27
-rw-r--r--Documentation/fault-injection/failcmd.sh4
-rw-r--r--Documentation/fault-injection/failmodule.sh31
-rw-r--r--Documentation/fault-injection/fault-injection.txt110
-rw-r--r--Documentation/feature-removal-schedule.txt148
-rw-r--r--Documentation/filesystems/Locking13
-rw-r--r--Documentation/filesystems/configfs/configfs.txt57
-rw-r--r--Documentation/filesystems/configfs/configfs_example.c8
-rw-r--r--Documentation/filesystems/ecryptfs.txt (renamed from Documentation/ecryptfs.txt)0
-rw-r--r--Documentation/filesystems/proc.txt125
-rw-r--r--Documentation/filesystems/vfs.txt51
-rw-r--r--Documentation/firmware_class/firmware_sample_firmware_class.c2
-rw-r--r--Documentation/gpio.txt3
-rw-r--r--Documentation/hrtimer/timer_stats.txt4
-rw-r--r--Documentation/hwmon/abituguru31
-rw-r--r--Documentation/hwmon/abituguru365
-rw-r--r--Documentation/hwmon/dme1737257
-rw-r--r--Documentation/hwmon/f71805f35
-rw-r--r--Documentation/hwmon/it879
-rw-r--r--Documentation/hwmon/lm9036
-rw-r--r--Documentation/hwmon/lm93412
-rw-r--r--Documentation/hwmon/smsc47b3977
-rw-r--r--Documentation/hwmon/sysfs-interface15
-rw-r--r--Documentation/hwmon/w83627ehf6
-rw-r--r--Documentation/i2c/busses/i2c-i8014
-rw-r--r--Documentation/i2c/busses/i2c-piix42
-rw-r--r--Documentation/i2c/busses/i2c-taos-evm46
-rw-r--r--Documentation/i2c/chips/max68752
-rw-r--r--Documentation/i2c/chips/x120538
-rw-r--r--Documentation/i2c/summary2
-rw-r--r--Documentation/i2c/writing-clients2
-rw-r--r--Documentation/i386/zero-page.txt1
-rw-r--r--Documentation/ia64/aliasing-test.c26
-rw-r--r--Documentation/ia64/aliasing.txt12
-rw-r--r--Documentation/ioctl-number.txt2
-rw-r--r--Documentation/ja_JP/HOWTO650
-rw-r--r--Documentation/ja_JP/stable_api_nonsense.txt263
-rw-r--r--Documentation/kbuild/makefiles.txt14
-rw-r--r--Documentation/kernel-parameters.txt150
-rw-r--r--Documentation/kprobes.txt8
-rw-r--r--Documentation/lguest/Makefile27
-rw-r--r--Documentation/lguest/lguest.c1012
-rw-r--r--Documentation/lguest/lguest.txt129
-rw-r--r--Documentation/m68k/kernel-options.txt7
-rw-r--r--Documentation/networking/ip-sysctl.txt9
-rw-r--r--Documentation/networking/l2tp.txt169
-rw-r--r--Documentation/networking/mac80211-injection.txt59
-rw-r--r--Documentation/networking/multiqueue.txt111
-rw-r--r--Documentation/networking/net-modules.txt6
-rw-r--r--Documentation/networking/netdevices.txt38
-rw-r--r--Documentation/networking/radiotap-headers.txt152
-rw-r--r--Documentation/oops-tracing.txt16
-rw-r--r--Documentation/pci.txt8
-rw-r--r--Documentation/power/freezing-of-tasks.txt162
-rw-r--r--Documentation/power/kernel_threads.txt40
-rw-r--r--Documentation/power/notifiers.txt50
-rw-r--r--Documentation/power/pci.txt37
-rw-r--r--Documentation/power/swsusp.txt21
-rw-r--r--Documentation/powerpc/booting-without-of.txt46
-rw-r--r--Documentation/rtc.txt2
-rw-r--r--Documentation/scsi/aacraid.txt3
-rw-r--r--Documentation/scsi/scsi_fc_transport.txt450
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt75
-rw-r--r--Documentation/sound/alsa/Audiophile-Usb.txt242
-rw-r--r--Documentation/sound/alsa/OSS-Emulation.txt15
-rw-r--r--Documentation/sound/oss/AD181684
-rw-r--r--Documentation/sound/oss/NM256280
-rw-r--r--Documentation/sound/oss/OPL3-SA2210
-rw-r--r--Documentation/sound/oss/VIA-chipset43
-rw-r--r--Documentation/sound/oss/cs46xx138
-rw-r--r--Documentation/spi/spi-lm70llp69
-rw-r--r--Documentation/spinlocks.txt20
-rw-r--r--Documentation/sysctl/ctl_unnumbered.txt22
-rw-r--r--Documentation/sysctl/vm.txt63
-rw-r--r--Documentation/sysfs-rules.txt166
-rw-r--r--Documentation/thinkpad-acpi.txt353
-rw-r--r--Documentation/time_interpolators.txt41
-rw-r--r--Documentation/usb/dma.txt52
-rw-r--r--Documentation/usb/persist.txt156
-rw-r--r--Documentation/video4linux/CARDLIST.bttv4
-rw-r--r--Documentation/video4linux/CARDLIST.cx881
-rw-r--r--Documentation/video4linux/CARDLIST.saa71341
-rw-r--r--Documentation/video4linux/CARDLIST.tuner3
-rw-r--r--Documentation/video4linux/sn9c102.txt3
-rw-r--r--Documentation/video4linux/zr364xx.txt2
-rw-r--r--Documentation/vm/hugetlbpage.txt10
-rw-r--r--Documentation/vm/slub.txt139
-rw-r--r--Documentation/x86_64/boot-options.txt14
-rw-r--r--Documentation/x86_64/machinecheck14
-rw-r--r--Documentation/zh_CN/HOWTO536
-rw-r--r--Documentation/zh_CN/stable_api_nonsense.txt157
-rw-r--r--Kbuild1
-rw-r--r--MAINTAINERS264
-rw-r--r--Makefile39
-rw-r--r--arch/alpha/Kconfig3
-rw-r--r--arch/alpha/kernel/module.c3
-rw-r--r--arch/alpha/kernel/pci_iommu.c32
-rw-r--r--arch/alpha/kernel/ptrace.c4
-rw-r--r--arch/alpha/kernel/smp.c6
-rw-r--r--arch/alpha/kernel/srmcons.c2
-rw-r--r--arch/alpha/kernel/sys_marvel.c2
-rw-r--r--arch/alpha/kernel/time.c2
-rw-r--r--arch/alpha/kernel/traps.c1
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S10
-rw-r--r--arch/alpha/lib/checksum.c1
-rw-r--r--arch/alpha/mm/fault.c22
-rw-r--r--arch/arm/Kconfig19
-rw-r--r--arch/arm/Kconfig.debug18
-rw-r--r--arch/arm/Makefile3
-rw-r--r--arch/arm/boot/Makefile8
-rw-r--r--arch/arm/boot/compressed/.gitignore1
-rw-r--r--arch/arm/boot/compressed/Makefile15
-rw-r--r--arch/arm/boot/compressed/head-xscale.S5
-rw-r--r--arch/arm/boot/compressed/head.S95
-rw-r--r--arch/arm/common/locomo.c11
-rw-r--r--arch/arm/common/sa1111.c13
-rw-r--r--arch/arm/common/sharpsl_pm.c2
-rw-r--r--arch/arm/configs/badge4_defconfig1
-rw-r--r--arch/arm/configs/clps7500_defconfig1
-rw-r--r--arch/arm/configs/em_x270_defconfig1265
-rw-r--r--arch/arm/configs/footbridge_defconfig1
-rw-r--r--arch/arm/configs/neponset_defconfig1
-rw-r--r--arch/arm/configs/picotux200_defconfig1
-rw-r--r--arch/arm/configs/rpc_defconfig1
-rw-r--r--arch/arm/configs/s3c2410_defconfig11
-rw-r--r--arch/arm/kernel/head-common.S40
-rw-r--r--arch/arm/kernel/head.S7
-rw-r--r--arch/arm/kernel/process.c8
-rw-r--r--arch/arm/kernel/ptrace.c15
-rw-r--r--arch/arm/kernel/setup.c6
-rw-r--r--arch/arm/kernel/traps.c1
-rw-r--r--arch/arm/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c10
-rw-r--r--arch/arm/mach-at91/board-csb337.c10
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c130
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c64
-rw-r--r--arch/arm/mach-davinci/Makefile3
-rw-r--r--arch/arm/mach-davinci/board-evm.c2
-rw-r--r--arch/arm/mach-davinci/clock.c323
-rw-r--r--arch/arm/mach-davinci/clock.h33
-rw-r--r--arch/arm/mach-davinci/gpio.c286
-rw-r--r--arch/arm/mach-davinci/io.c6
-rw-r--r--arch/arm/mach-davinci/mux.c41
-rw-r--r--arch/arm/mach-davinci/psc.c87
-rw-r--r--arch/arm/mach-davinci/time.c2
-rw-r--r--arch/arm/mach-imx/generic.c118
-rw-r--r--arch/arm/mach-imx/time.c122
-rw-r--r--arch/arm/mach-iop13xx/pci.c3
-rw-r--r--arch/arm/mach-iop13xx/setup.c217
-rw-r--r--arch/arm/mach-iop13xx/tpmi.c32
-rw-r--r--arch/arm/mach-iop32x/Kconfig7
-rw-r--r--arch/arm/mach-iop32x/Makefile1
-rw-r--r--arch/arm/mach-iop32x/em7210.c215
-rw-r--r--arch/arm/mach-iop32x/glantank.c2
-rw-r--r--arch/arm/mach-iop32x/iq31244.c5
-rw-r--r--arch/arm/mach-iop32x/iq80321.c3
-rw-r--r--arch/arm/mach-iop32x/irq.c3
-rw-r--r--arch/arm/mach-iop32x/n2100.c12
-rw-r--r--arch/arm/mach-iop33x/iq80331.c3
-rw-r--r--arch/arm/mach-iop33x/iq80332.c3
-rw-r--r--arch/arm/mach-ixp4xx/Kconfig16
-rw-r--r--arch/arm/mach-ixp4xx/Makefile4
-rw-r--r--arch/arm/mach-ixp4xx/common.c4
-rw-r--r--arch/arm/mach-ixp4xx/gateway7001-pci.c63
-rw-r--r--arch/arm/mach-ixp4xx/gateway7001-setup.c108
-rw-r--r--arch/arm/mach-ixp4xx/gtwx5715-pci.c8
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-setup.c96
-rw-r--r--arch/arm/mach-ixp4xx/wg302v2-pci.c63
-rw-r--r--arch/arm/mach-ixp4xx/wg302v2-setup.c109
-rw-r--r--arch/arm/mach-ks8695/Makefile2
-rw-r--r--arch/arm/mach-ks8695/gpio.c218
-rw-r--r--arch/arm/mach-ks8695/irq.c1
-rw-r--r--arch/arm/mach-mx3/Kconfig12
-rw-r--r--arch/arm/mach-mx3/Makefile8
-rw-r--r--arch/arm/mach-mx3/Makefile.boot3
-rw-r--r--arch/arm/mach-mx3/mm.c64
-rw-r--r--arch/arm/mach-mx3/mx31ads.c142
-rw-r--r--arch/arm/mach-mx3/time.c152
-rw-r--r--arch/arm/mach-ns9xxx/Makefile1
-rw-r--r--arch/arm/mach-ns9xxx/board-a9m9750dev.c7
-rw-r--r--arch/arm/mach-ns9xxx/generic.c2
-rw-r--r--arch/arm/mach-ns9xxx/irq.c11
-rw-r--r--arch/arm/mach-ns9xxx/mach-cc9p9360js.c2
-rw-r--r--arch/arm/mach-omap1/time.c1
-rw-r--r--arch/arm/mach-pxa/Kconfig4
-rw-r--r--arch/arm/mach-pxa/Makefile1
-rw-r--r--arch/arm/mach-pxa/clock.c15
-rw-r--r--arch/arm/mach-pxa/corgi.c7
-rw-r--r--arch/arm/mach-pxa/devices.h11
-rw-r--r--arch/arm/mach-pxa/dma.c44
-rw-r--r--arch/arm/mach-pxa/em-x270.c354
-rw-r--r--arch/arm/mach-pxa/generic.c101
-rw-r--r--arch/arm/mach-pxa/generic.h6
-rw-r--r--arch/arm/mach-pxa/idp.c3
-rw-r--r--arch/arm/mach-pxa/irq.c106
-rw-r--r--arch/arm/mach-pxa/lpd270.c3
-rw-r--r--arch/arm/mach-pxa/lubbock.c3
-rw-r--r--arch/arm/mach-pxa/mainstone.c3
-rw-r--r--arch/arm/mach-pxa/pm.c184
-rw-r--r--arch/arm/mach-pxa/poodle.c3
-rw-r--r--arch/arm/mach-pxa/pxa25x.c137
-rw-r--r--arch/arm/mach-pxa/pxa27x.c183
-rw-r--r--arch/arm/mach-pxa/sleep.S112
-rw-r--r--arch/arm/mach-pxa/spitz.c7
-rw-r--r--arch/arm/mach-pxa/time.c263
-rw-r--r--arch/arm/mach-pxa/tosa.c4
-rw-r--r--arch/arm/mach-pxa/trizeps4.c3
-rw-r--r--arch/arm/mach-rpc/riscpc.c2
-rw-r--r--arch/arm/mach-s3c2410/Kconfig1
-rw-r--r--arch/arm/mach-s3c2410/clock.c2
-rw-r--r--arch/arm/mach-s3c2410/dma.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-amlm5900.c2
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c65
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c4
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c4
-rw-r--r--arch/arm/mach-s3c2410/mach-otom.c2
-rw-r--r--arch/arm/mach-s3c2410/mach-qt2410.c6
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c2
-rw-r--r--arch/arm/mach-s3c2410/mach-vr1000.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c3
-rw-r--r--arch/arm/mach-s3c2410/sleep.S2
-rw-r--r--arch/arm/mach-s3c2412/Kconfig1
-rw-r--r--arch/arm/mach-s3c2412/clock.c2
-rw-r--r--arch/arm/mach-s3c2412/dma.c8
-rw-r--r--arch/arm/mach-s3c2412/mach-smdk2413.c4
-rw-r--r--arch/arm/mach-s3c2412/mach-vstms.c4
-rw-r--r--arch/arm/mach-s3c2412/s3c2412.c5
-rw-r--r--arch/arm/mach-s3c2440/Kconfig1
-rw-r--r--arch/arm/mach-s3c2440/dma.c8
-rw-r--r--arch/arm/mach-s3c2440/mach-anubis.c145
-rw-r--r--arch/arm/mach-s3c2440/mach-nexcoder.c2
-rw-r--r--arch/arm/mach-s3c2440/mach-osiris.c42
-rw-r--r--arch/arm/mach-s3c2440/mach-rx3715.c4
-rw-r--r--arch/arm/mach-s3c2440/mach-smdk2440.c2
-rw-r--r--arch/arm/mach-s3c2442/Kconfig1
-rw-r--r--arch/arm/mach-s3c2443/Kconfig1
-rw-r--r--arch/arm/mach-s3c2443/dma.c8
-rw-r--r--arch/arm/mach-s3c2443/mach-smdk2443.c2
-rw-r--r--arch/arm/mach-sa1100/Kconfig13
-rw-r--r--arch/arm/mach-sa1100/Makefile2
-rw-r--r--arch/arm/mach-sa1100/jornada720_ssp.c201
-rw-r--r--arch/arm/mach-sa1100/neponset.c17
-rw-r--r--arch/arm/mach-sa1100/pm.c9
-rw-r--r--arch/arm/mach-sa1100/time.c24
-rw-r--r--arch/arm/mm/Kconfig18
-rw-r--r--arch/arm/mm/cache-l2x0.c6
-rw-r--r--arch/arm/mm/fault.c40
-rw-r--r--arch/arm/mm/ioremap.c10
-rw-r--r--arch/arm/mm/mmu.c14
-rw-r--r--arch/arm/mm/proc-syms.c2
-rw-r--r--arch/arm/mm/proc-v7.S33
-rw-r--r--arch/arm/plat-iop/Makefile2
-rw-r--r--arch/arm/plat-iop/adma.c209
-rw-r--r--arch/arm/plat-iop/time.c8
-rw-r--r--arch/arm/plat-mxc/Kconfig20
-rw-r--r--arch/arm/plat-mxc/Makefile10
-rw-r--r--arch/arm/plat-mxc/irq.c83
-rw-r--r--arch/arm/plat-omap/timer32k.c2
-rw-r--r--arch/arm/plat-s3c/Kconfig104
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig60
-rw-r--r--arch/arm/plat-s3c24xx/common-smdk.c2
-rw-r--r--arch/arm/plat-s3c24xx/cpu.c2
-rw-r--r--arch/arm/plat-s3c24xx/devs.c6
-rw-r--r--arch/arm/plat-s3c24xx/dma.c2
-rw-r--r--arch/arm/plat-s3c24xx/pm.c2
-rw-r--r--arch/arm/plat-s3c24xx/s3c244x.c3
-rw-r--r--arch/arm/plat-s3c24xx/sleep.S2
-rw-r--r--arch/arm/plat-s3c24xx/time.c2
-rw-r--r--arch/arm/vfp/vfphw.S12
-rw-r--r--arch/arm/vfp/vfpmodule.c12
-rw-r--r--arch/arm26/Kconfig3
-rw-r--r--arch/arm26/defconfig1
-rw-r--r--arch/arm26/kernel/armksyms.c2
-rw-r--r--arch/arm26/kernel/irq.c6
-rw-r--r--arch/arm26/kernel/ptrace.c15
-rw-r--r--arch/arm26/kernel/traps.c1
-rw-r--r--arch/arm26/mm/fault.c30
-rw-r--r--arch/arm26/mm/init.c3
-rw-r--r--arch/arm26/mm/memc.c4
-rw-r--r--arch/avr32/Kconfig25
-rw-r--r--arch/avr32/boards/atngw100/setup.c31
-rw-r--r--arch/avr32/boards/atstk1000/Kconfig53
-rw-r--r--arch/avr32/boards/atstk1000/atstk1002.c50
-rw-r--r--arch/avr32/configs/atngw100_defconfig16
-rw-r--r--arch/avr32/kernel/ptrace.c13
-rw-r--r--arch/avr32/kernel/setup.c4
-rw-r--r--arch/avr32/kernel/traps.c3
-rw-r--r--arch/avr32/mach-at32ap/Makefile1
-rw-r--r--arch/avr32/mach-at32ap/at32ap.c31
-rw-r--r--arch/avr32/mach-at32ap/at32ap7000.c340
-rw-r--r--arch/avr32/mach-at32ap/cpufreq.c112
-rw-r--r--arch/avr32/mach-at32ap/extint.c200
-rw-r--r--arch/avr32/mach-at32ap/pm.h112
-rw-r--r--arch/avr32/mach-at32ap/sm.h242
-rw-r--r--arch/avr32/mm/fault.c23
-rw-r--r--arch/blackfin/Kconfig59
-rw-r--r--arch/blackfin/Makefile2
-rw-r--r--arch/blackfin/boot/Makefile3
-rw-r--r--arch/blackfin/configs/BF548-EZKIT_defconfig1100
-rw-r--r--arch/blackfin/kernel/Makefile7
-rw-r--r--arch/blackfin/kernel/asm-offsets.c7
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c251
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c11
-rw-r--r--arch/blackfin/kernel/bfin_ksyms.c5
-rw-r--r--arch/blackfin/kernel/cacheinit.c66
-rw-r--r--arch/blackfin/kernel/cplbinit.c433
-rw-r--r--arch/blackfin/kernel/dma-mapping.c13
-rw-r--r--arch/blackfin/kernel/dualcore_test.c6
-rw-r--r--arch/blackfin/kernel/fixed_code.S132
-rw-r--r--arch/blackfin/kernel/flat.c55
-rw-r--r--arch/blackfin/kernel/irqchip.c2
-rw-r--r--arch/blackfin/kernel/kgdb.c421
-rw-r--r--arch/blackfin/kernel/module.c32
-rw-r--r--arch/blackfin/kernel/process.c75
-rw-r--r--arch/blackfin/kernel/ptrace.c6
-rw-r--r--arch/blackfin/kernel/setup.c368
-rw-r--r--arch/blackfin/kernel/signal.c10
-rw-r--r--arch/blackfin/kernel/sys_bfin.c8
-rw-r--r--arch/blackfin/kernel/time.c4
-rw-r--r--arch/blackfin/kernel/traps.c62
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S12
-rw-r--r--arch/blackfin/lib/strcmp.c3
-rw-r--r--arch/blackfin/lib/strcpy.c3
-rw-r--r--arch/blackfin/lib/strncmp.c3
-rw-r--r--arch/blackfin/lib/strncpy.c3
-rw-r--r--arch/blackfin/mach-bf533/Makefile4
-rw-r--r--arch/blackfin/mach-bf533/boards/cm_bf533.c14
-rw-r--r--arch/blackfin/mach-bf533/boards/ezkit.c8
-rw-r--r--arch/blackfin/mach-bf533/boards/generic_board.c6
-rw-r--r--arch/blackfin/mach-bf533/boards/stamp.c30
-rw-r--r--arch/blackfin/mach-bf533/cpu.c3
-rw-r--r--arch/blackfin/mach-bf533/dma.c95
-rw-r--r--arch/blackfin/mach-bf533/head.S5
-rw-r--r--arch/blackfin/mach-bf533/ints-priority.c2
-rw-r--r--arch/blackfin/mach-bf537/Makefile2
-rw-r--r--arch/blackfin/mach-bf537/boards/cm_bf537.c16
-rw-r--r--arch/blackfin/mach-bf537/boards/eth_mac.c5
-rw-r--r--arch/blackfin/mach-bf537/boards/generic_board.c36
-rw-r--r--arch/blackfin/mach-bf537/boards/pnav10.c54
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c77
-rw-r--r--arch/blackfin/mach-bf537/dma.c115
-rw-r--r--arch/blackfin/mach-bf537/head.S6
-rw-r--r--arch/blackfin/mach-bf537/ints-priority.c2
-rw-r--r--arch/blackfin/mach-bf548/Kconfig316
-rw-r--r--arch/blackfin/mach-bf548/Makefile9
-rw-r--r--arch/blackfin/mach-bf548/boards/Makefile5
-rw-r--r--arch/blackfin/mach-bf548/boards/ezkit.c114
-rw-r--r--arch/blackfin/mach-bf548/boards/led.S172
-rw-r--r--arch/blackfin/mach-bf548/cpu.c159
-rw-r--r--arch/blackfin/mach-bf548/dma.c156
-rw-r--r--arch/blackfin/mach-bf548/gpio.c323
-rw-r--r--arch/blackfin/mach-bf548/head.S512
-rw-r--r--arch/blackfin/mach-bf548/ints-priority.c137
-rw-r--r--arch/blackfin/mach-bf561/Makefile2
-rw-r--r--arch/blackfin/mach-bf561/boards/cm_bf561.c32
-rw-r--r--arch/blackfin/mach-bf561/boards/ezkit.c33
-rw-r--r--arch/blackfin/mach-bf561/boards/generic_board.c6
-rw-r--r--arch/blackfin/mach-bf561/boards/tepla.c6
-rw-r--r--arch/blackfin/mach-bf561/coreb.c18
-rw-r--r--arch/blackfin/mach-bf561/dma.c131
-rw-r--r--arch/blackfin/mach-bf561/head.S6
-rw-r--r--arch/blackfin/mach-bf561/ints-priority.c2
-rw-r--r--arch/blackfin/mach-common/Makefile4
-rw-r--r--arch/blackfin/mach-common/cacheinit.S89
-rw-r--r--arch/blackfin/mach-common/cplbinfo.c13
-rw-r--r--arch/blackfin/mach-common/entry.S76
-rw-r--r--arch/blackfin/mach-common/interrupt.S8
-rw-r--r--arch/blackfin/mach-common/ints-priority-dc.c13
-rw-r--r--arch/blackfin/mach-common/ints-priority-sc.c405
-rw-r--r--arch/blackfin/mach-common/pm.c4
-rw-r--r--arch/blackfin/mm/blackfin_sram.c7
-rw-r--r--arch/blackfin/mm/init.c47
-rw-r--r--arch/blackfin/oprofile/common.c6
-rw-r--r--arch/blackfin/oprofile/op_model_bf533.c6
-rw-r--r--arch/blackfin/oprofile/timer_int.c3
-rw-r--r--arch/cris/arch-v10/defconfig1
-rw-r--r--arch/cris/arch-v10/drivers/pcf8563.c4
-rw-r--r--arch/cris/arch-v10/kernel/ptrace.c21
-rw-r--r--arch/cris/arch-v10/vmlinux.lds.S2
-rw-r--r--arch/cris/arch-v32/drivers/cryptocop.c8
-rw-r--r--arch/cris/arch-v32/drivers/i2c.c8
-rw-r--r--arch/cris/arch-v32/drivers/pcf8563.c12
-rw-r--r--arch/cris/arch-v32/drivers/pci/dma.c6
-rw-r--r--arch/cris/arch-v32/kernel/ptrace.c7
-rw-r--r--arch/cris/arch-v32/vmlinux.lds.S7
-rw-r--r--arch/cris/mm/fault.c23
-rw-r--r--arch/frv/Makefile2
-rw-r--r--arch/frv/kernel/entry.S4
-rw-r--r--arch/frv/kernel/gdb-stub.c12
-rw-r--r--arch/frv/kernel/ptrace.c16
-rw-r--r--arch/frv/kernel/setup.c17
-rw-r--r--arch/frv/kernel/vmlinux.lds.S5
-rw-r--r--arch/frv/mm/fault.c23
-rw-r--r--arch/h8300/Kconfig3
-rw-r--r--arch/h8300/Makefile7
-rw-r--r--arch/h8300/boot/compressed/Makefile4
-rw-r--r--arch/h8300/boot/compressed/head.S2
-rw-r--r--arch/h8300/boot/compressed/vmlinux.lds32
-rw-r--r--arch/h8300/boot/compressed/vmlinux.scr9
-rw-r--r--arch/h8300/kernel/Makefile3
-rw-r--r--arch/h8300/kernel/entry.S (renamed from arch/h8300/platform/h8s/entry.S)302
-rw-r--r--arch/h8300/kernel/ints.c256
-rw-r--r--arch/h8300/kernel/ptrace.c7
-rw-r--r--arch/h8300/kernel/signal.c6
-rw-r--r--arch/h8300/platform/h8300h/Makefile2
-rw-r--r--arch/h8300/platform/h8300h/entry.S332
-rw-r--r--arch/h8300/platform/h8s/Makefile2
-rw-r--r--arch/i386/Kconfig36
-rw-r--r--arch/i386/Kconfig.cpu11
-rw-r--r--arch/i386/Makefile4
-rw-r--r--arch/i386/boot/.gitignore2
-rw-r--r--arch/i386/boot/Makefile48
-rw-r--r--arch/i386/boot/a20.c161
-rw-r--r--arch/i386/boot/apm.c97
-rw-r--r--arch/i386/boot/bitops.h45
-rw-r--r--arch/i386/boot/boot.h296
-rw-r--r--arch/i386/boot/bootsect.S98
-rw-r--r--arch/i386/boot/cmdline.c97
-rw-r--r--arch/i386/boot/code16gcc.h15
-rw-r--r--arch/i386/boot/compressed/Makefile7
-rw-r--r--arch/i386/boot/compressed/head.S6
-rw-r--r--arch/i386/boot/compressed/relocs.c3
-rw-r--r--arch/i386/boot/copy.S101
-rw-r--r--arch/i386/boot/cpu.c69
-rw-r--r--arch/i386/boot/cpucheck.c267
-rw-r--r--arch/i386/boot/edd.S231
-rw-r--r--arch/i386/boot/edd.c196
-rw-r--r--arch/i386/boot/header.S283
-rw-r--r--arch/i386/boot/main.c161
-rw-r--r--arch/i386/boot/mca.c43
-rw-r--r--arch/i386/boot/memory.c99
-rw-r--r--arch/i386/boot/pm.c170
-rw-r--r--arch/i386/boot/pmjump.S54
-rw-r--r--arch/i386/boot/printf.c307
-rw-r--r--arch/i386/boot/setup.S1075
-rw-r--r--arch/i386/boot/setup.ld54
-rw-r--r--arch/i386/boot/string.c52
-rw-r--r--arch/i386/boot/tools/build.c162
-rw-r--r--arch/i386/boot/tty.c112
-rw-r--r--arch/i386/boot/version.c23
-rw-r--r--arch/i386/boot/vesa.h79
-rw-r--r--arch/i386/boot/video-bios.c125
-rw-r--r--arch/i386/boot/video-vesa.c284
-rw-r--r--arch/i386/boot/video-vga.c260
-rw-r--r--arch/i386/boot/video.S2043
-rw-r--r--arch/i386/boot/video.c461
-rw-r--r--arch/i386/boot/video.h152
-rw-r--r--arch/i386/boot/voyager.c46
-rw-r--r--arch/i386/defconfig265
-rw-r--r--arch/i386/kernel/Makefile1
-rw-r--r--arch/i386/kernel/acpi/boot.c44
-rw-r--r--arch/i386/kernel/acpi/sleep.c12
-rw-r--r--arch/i386/kernel/acpi/wakeup.S37
-rw-r--r--arch/i386/kernel/alternative.c69
-rw-r--r--arch/i386/kernel/apic.c10
-rw-r--r--arch/i386/kernel/apm.c2
-rw-r--r--arch/i386/kernel/asm-offsets.c29
-rw-r--r--arch/i386/kernel/cpu/Makefile3
-rw-r--r--arch/i386/kernel/cpu/addon_cpuid_features.c50
-rw-r--r--arch/i386/kernel/cpu/amd.c11
-rw-r--r--arch/i386/kernel/cpu/common.c4
-rw-r--r--arch/i386/kernel/cpu/cpufreq/Kconfig31
-rw-r--r--arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c17
-rw-r--r--arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c6
-rw-r--r--arch/i386/kernel/cpu/cpufreq/gx-suspmod.c6
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c216
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.h12
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k8.c29
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c276
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-ich.c4
-rw-r--r--arch/i386/kernel/cpu/cyrix.c2
-rw-r--r--arch/i386/kernel/cpu/intel_cacheinfo.c79
-rw-r--r--arch/i386/kernel/cpu/mcheck/mce.c14
-rw-r--r--arch/i386/kernel/cpu/mcheck/non-fatal.c4
-rw-r--r--arch/i386/kernel/cpu/mcheck/therm_throt.c6
-rw-r--r--arch/i386/kernel/cpu/mtrr/cyrix.c1
-rw-r--r--arch/i386/kernel/cpu/mtrr/generic.c2
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c2
-rw-r--r--arch/i386/kernel/cpu/mtrr/state.c1
-rw-r--r--arch/i386/kernel/cpu/perfctr-watchdog.c10
-rw-r--r--arch/i386/kernel/cpu/proc.c21
-rw-r--r--arch/i386/kernel/cpu/rise.c52
-rw-r--r--arch/i386/kernel/e820.c34
-rw-r--r--arch/i386/kernel/efi.c2
-rw-r--r--arch/i386/kernel/entry.S87
-rw-r--r--arch/i386/kernel/geode.c155
-rw-r--r--arch/i386/kernel/head.S13
-rw-r--r--arch/i386/kernel/hpet.c98
-rw-r--r--arch/i386/kernel/i8253.c32
-rw-r--r--arch/i386/kernel/init_task.c2
-rw-r--r--arch/i386/kernel/io_apic.c27
-rw-r--r--arch/i386/kernel/irq.c10
-rw-r--r--arch/i386/kernel/kprobes.c9
-rw-r--r--arch/i386/kernel/nmi.c10
-rw-r--r--arch/i386/kernel/paravirt.c55
-rw-r--r--arch/i386/kernel/process.c85
-rw-r--r--arch/i386/kernel/ptrace.c39
-rw-r--r--arch/i386/kernel/reboot.c9
-rw-r--r--arch/i386/kernel/setup.c25
-rw-r--r--arch/i386/kernel/signal.c7
-rw-r--r--arch/i386/kernel/smp.c5
-rw-r--r--arch/i386/kernel/smpboot.c8
-rw-r--r--arch/i386/kernel/smpcommon.c8
-rw-r--r--arch/i386/kernel/syscall_table.S1
-rw-r--r--arch/i386/kernel/sysenter.c4
-rw-r--r--arch/i386/kernel/time.c50
-rw-r--r--arch/i386/kernel/traps.c53
-rw-r--r--arch/i386/kernel/tsc.c27
-rw-r--r--arch/i386/kernel/verify_cpu.S94
-rw-r--r--arch/i386/kernel/vmi.c4
-rw-r--r--arch/i386/kernel/vmiclock.c8
-rw-r--r--arch/i386/kernel/vmlinux.lds.S8
-rw-r--r--arch/i386/kernel/vsyscall-note.S52
-rw-r--r--arch/i386/lib/Makefile2
-rw-r--r--arch/i386/lib/string.c257
-rw-r--r--arch/i386/mach-generic/es7000.c2
-rw-r--r--arch/i386/mach-visws/traps.c4
-rw-r--r--arch/i386/mach-voyager/voyager_thread.c2
-rw-r--r--arch/i386/mm/fault.c33
-rw-r--r--arch/i386/mm/init.c27
-rw-r--r--arch/i386/mm/ioremap.c2
-rw-r--r--arch/i386/mm/pageattr.c22
-rw-r--r--arch/i386/mm/pgtable.c6
-rw-r--r--arch/i386/pci/acpi.c32
-rw-r--r--arch/i386/pci/common.c13
-rw-r--r--arch/i386/pci/fixup.c9
-rw-r--r--arch/i386/pci/mmconfig-shared.c48
-rw-r--r--arch/i386/video/Makefile1
-rw-r--r--arch/i386/video/fbdev.c32
-rw-r--r--arch/i386/xen/Kconfig11
-rw-r--r--arch/i386/xen/Makefile4
-rw-r--r--arch/i386/xen/enlighten.c1144
-rw-r--r--arch/i386/xen/events.c591
-rw-r--r--arch/i386/xen/features.c29
-rw-r--r--arch/i386/xen/manage.c143
-rw-r--r--arch/i386/xen/mmu.c564
-rw-r--r--arch/i386/xen/mmu.h60
-rw-r--r--arch/i386/xen/multicalls.c90
-rw-r--r--arch/i386/xen/multicalls.h45
-rw-r--r--arch/i386/xen/setup.c111
-rw-r--r--arch/i386/xen/smp.c404
-rw-r--r--arch/i386/xen/time.c593
-rw-r--r--arch/i386/xen/vdso.h4
-rw-r--r--arch/i386/xen/xen-asm.S291
-rw-r--r--arch/i386/xen/xen-head.S38
-rw-r--r--arch/i386/xen/xen-ops.h71
-rw-r--r--arch/ia64/Kconfig16
-rw-r--r--arch/ia64/configs/bigsur_defconfig2
-rw-r--r--arch/ia64/configs/gensparse_defconfig2
-rw-r--r--arch/ia64/configs/sim_defconfig2
-rw-r--r--arch/ia64/configs/sn2_defconfig2
-rw-r--r--arch/ia64/configs/tiger_defconfig322
-rw-r--r--arch/ia64/configs/zx1_defconfig2
-rw-r--r--arch/ia64/defconfig338
-rw-r--r--arch/ia64/hp/common/sba_iommu.c20
-rw-r--r--arch/ia64/hp/sim/boot/fw-emu.c5
-rw-r--r--arch/ia64/hp/sim/simserial.c4
-rw-r--r--arch/ia64/ia32/binfmt_elf32.c67
-rw-r--r--arch/ia64/ia32/ia32_entry.S2
-rw-r--r--arch/ia64/ia32/ia32_support.c2
-rw-r--r--arch/ia64/kernel/asm-offsets.c35
-rw-r--r--arch/ia64/kernel/cyclone.c46
-rw-r--r--arch/ia64/kernel/efi.c1
-rw-r--r--arch/ia64/kernel/entry.S2
-rw-r--r--arch/ia64/kernel/fsys.S181
-rw-r--r--arch/ia64/kernel/fsyscall_gtod_data.h23
-rw-r--r--arch/ia64/kernel/gate.S1
-rw-r--r--arch/ia64/kernel/iosapic.c652
-rw-r--r--arch/ia64/kernel/irq.c2
-rw-r--r--arch/ia64/kernel/irq_ia64.c317
-rw-r--r--arch/ia64/kernel/kprobes.c7
-rw-r--r--arch/ia64/kernel/mca.c60
-rw-r--r--arch/ia64/kernel/mca_asm.S12
-rw-r--r--arch/ia64/kernel/mca_drv_asm.S6
-rw-r--r--arch/ia64/kernel/msi_ia64.c23
-rw-r--r--arch/ia64/kernel/process.c3
-rw-r--r--arch/ia64/kernel/setup.c13
-rw-r--r--arch/ia64/kernel/smp.c2
-rw-r--r--arch/ia64/kernel/smpboot.c4
-rw-r--r--arch/ia64/kernel/time.c96
-rw-r--r--arch/ia64/kernel/traps.c1
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S1
-rw-r--r--arch/ia64/lib/checksum.c1
-rw-r--r--arch/ia64/mm/fault.c26
-rw-r--r--arch/ia64/mm/tlb.c2
-rw-r--r--arch/ia64/pci/pci.c22
-rw-r--r--arch/ia64/sn/kernel/io_acpi_init.c17
-rw-r--r--arch/ia64/sn/kernel/io_init.c20
-rw-r--r--arch/ia64/sn/kernel/sn2/sn_hwperf.c3
-rw-r--r--arch/ia64/sn/kernel/sn2/timer.c29
-rw-r--r--arch/ia64/sn/kernel/tiocx.c2
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_provider.c2
-rw-r--r--arch/m32r/Kconfig3
-rw-r--r--arch/m32r/kernel/ptrace.c19
-rw-r--r--arch/m32r/kernel/vmlinux.lds.S5
-rw-r--r--arch/m32r/m32104ut/defconfig.m32104ut1
-rw-r--r--arch/m32r/mm/fault.c23
-rw-r--r--arch/m68k/Kconfig7
-rw-r--r--arch/m68k/apollo/config.c4
-rw-r--r--arch/m68k/apollo/dn_ints.c2
-rw-r--r--arch/m68k/atari/atakeyb.c9
-rw-r--r--arch/m68k/bvme6000/config.c2
-rw-r--r--arch/m68k/kernel/head.S2
-rw-r--r--arch/m68k/kernel/ints.c4
-rw-r--r--arch/m68k/kernel/ptrace.c8
-rw-r--r--arch/m68k/kernel/setup.c1
-rw-r--r--arch/m68k/kernel/sun3-head.S2
-rw-r--r--arch/m68k/kernel/time.c2
-rw-r--r--arch/m68k/kernel/traps.c1
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds1
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds2
-rw-r--r--arch/m68k/lib/checksum.c1
-rw-r--r--arch/m68k/mac/config.c7
-rw-r--r--arch/m68k/mac/macints.c4
-rw-r--r--arch/m68k/mm/fault.c21
-rw-r--r--arch/m68k/mm/init.c2
-rw-r--r--arch/m68k/mm/sun3kmap.c2
-rw-r--r--arch/m68k/mvme147/config.c2
-rw-r--r--arch/m68k/mvme16x/config.c2
-rw-r--r--arch/m68k/q40/q40ints.c2
-rw-r--r--arch/m68k/sun3/sun3ints.c2
-rw-r--r--arch/m68k/sun3x/prom.c2
-rw-r--r--arch/m68knommu/Kconfig4
-rw-r--r--arch/m68knommu/kernel/Makefile4
-rw-r--r--arch/m68knommu/kernel/asm-offsets.c5
-rw-r--r--arch/m68knommu/kernel/irq.c82
-rw-r--r--arch/m68knommu/kernel/m68k_ksyms.c2
-rw-r--r--arch/m68knommu/kernel/process.c2
-rw-r--r--arch/m68knommu/kernel/ptrace.c17
-rw-r--r--arch/m68knommu/kernel/setup.c106
-rw-r--r--arch/m68knommu/kernel/traps.c5
-rw-r--r--arch/m68knommu/mm/memory.c100
-rw-r--r--arch/m68knommu/platform/5307/Makefile2
-rw-r--r--arch/m68knommu/platform/5307/entry.S42
-rw-r--r--arch/m68knommu/platform/5307/ints.c279
-rw-r--r--arch/m68knommu/platform/5307/vectors.c29
-rw-r--r--arch/m68knommu/platform/68328/entry.S10
-rw-r--r--arch/m68knommu/platform/68328/ints.c130
-rw-r--r--arch/m68knommu/platform/68360/entry.S6
-rw-r--r--arch/m68knommu/platform/68360/ints.c233
-rw-r--r--arch/mips/Kconfig32
-rw-r--r--arch/mips/au1000/common/setup.c9
-rw-r--r--arch/mips/au1000/common/time.c29
-rw-r--r--arch/mips/au1000/pb1200/board_setup.c9
-rw-r--r--arch/mips/basler/excite/excite_setup.c1
-rw-r--r--arch/mips/configs/jazz_defconfig2
-rw-r--r--arch/mips/configs/qemu_defconfig2
-rw-r--r--arch/mips/configs/rm200_defconfig2
-rw-r--r--arch/mips/configs/yosemite_defconfig2
-rw-r--r--arch/mips/gt64120/wrppmc/setup.c1
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/kernel/branch.c5
-rw-r--r--arch/mips/kernel/cpu-probe.c26
-rw-r--r--arch/mips/kernel/entry.S2
-rw-r--r--arch/mips/kernel/genex.S2
-rw-r--r--arch/mips/kernel/pcspeaker.c (renamed from arch/mips/kernel/i8253.c)0
-rw-r--r--arch/mips/kernel/process.c14
-rw-r--r--arch/mips/kernel/ptrace.c18
-rw-r--r--arch/mips/kernel/r4k_switch.S7
-rw-r--r--arch/mips/kernel/traps.c11
-rw-r--r--arch/mips/kernel/vmlinux.lds.S5
-rw-r--r--arch/mips/lib/dump_tlb.c1
-rw-r--r--arch/mips/lib/r3k_dump_tlb.c1
-rw-r--r--arch/mips/lib/uncached.c1
-rw-r--r--arch/mips/math-emu/cp1emu.c19
-rw-r--r--arch/mips/math-emu/dsemul.c12
-rw-r--r--arch/mips/mips-boards/atlas/atlas_setup.c1
-rw-r--r--arch/mips/mips-boards/sead/sead_setup.c1
-rw-r--r--arch/mips/mipssim/sim_int.c2
-rw-r--r--arch/mips/mipssim/sim_setup.c3
-rw-r--r--arch/mips/mipssim/sim_time.c1
-rw-r--r--arch/mips/mm/fault.c23
-rw-r--r--arch/mips/pci/Makefile2
-rw-r--r--arch/mips/pci/fixup-cobalt.c10
-rw-r--r--arch/mips/pci/pci-dac.c79
-rw-r--r--arch/mips/pci/pci.c2
-rw-r--r--arch/mips/pmc-sierra/msp71xx/msp_serial.c1
-rw-r--r--arch/mips/pmc-sierra/yosemite/setup.c1
-rw-r--r--arch/mips/sibyte/bcm1480/setup.c1
-rw-r--r--arch/mips/sibyte/sb1250/setup.c1
-rw-r--r--arch/mips/sibyte/swarm/time.c244
-rw-r--r--arch/mips/sni/a20r.c8
-rw-r--r--arch/mips/sni/rm200.c4
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c19
-rw-r--r--arch/mips/vr41xx/common/Makefile2
-rw-r--r--arch/mips/vr41xx/common/giu.c122
-rw-r--r--arch/mips/vr41xx/common/rtc.c117
-rw-r--r--arch/mips/vr41xx/common/siu.c120
-rw-r--r--arch/parisc/kernel/ptrace.c13
-rw-r--r--arch/parisc/kernel/traps.c3
-rw-r--r--arch/parisc/kernel/unwind.c2
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S7
-rw-r--r--arch/parisc/mm/fault.c23
-rw-r--r--arch/powerpc/Kconfig283
-rw-r--r--arch/powerpc/Makefile10
-rw-r--r--arch/powerpc/boot/44x.c45
-rw-r--r--arch/powerpc/boot/44x.h3
-rw-r--r--arch/powerpc/boot/Makefile81
-rw-r--r--arch/powerpc/boot/cuboot-83xx.c13
-rw-r--r--arch/powerpc/boot/cuboot-85xx.c13
-rw-r--r--arch/powerpc/boot/cuboot-ebony.c16
-rw-r--r--arch/powerpc/boot/cuboot.c35
-rw-r--r--arch/powerpc/boot/cuboot.h14
-rw-r--r--arch/powerpc/boot/dcr.h37
-rw-r--r--arch/powerpc/boot/dts/ebony.dts12
-rw-r--r--arch/powerpc/boot/dts/holly.dts52
-rw-r--r--arch/powerpc/boot/dts/mpc7448hpc2.dts33
-rw-r--r--arch/powerpc/boot/dts/mpc8272ads.dts42
-rw-r--r--arch/powerpc/boot/dts/mpc832x_mds.dts16
-rw-r--r--arch/powerpc/boot/dts/mpc832x_rdb.dts16
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitx.dts10
-rw-r--r--arch/powerpc/boot/dts/mpc834x_mds.dts10
-rw-r--r--arch/powerpc/boot/dts/mpc836x_mds.dts16
-rw-r--r--arch/powerpc/boot/dts/mpc8540ads.dts147
-rw-r--r--arch/powerpc/boot/dts/mpc8541cds.dts90
-rw-r--r--arch/powerpc/boot/dts/mpc8544ds.dts18
-rw-r--r--arch/powerpc/boot/dts/mpc8548cds.dts108
-rw-r--r--arch/powerpc/boot/dts/mpc8555cds.dts90
-rw-r--r--arch/powerpc/boot/dts/mpc8560ads.dts148
-rw-r--r--arch/powerpc/boot/dts/mpc8568mds.dts66
-rw-r--r--arch/powerpc/boot/dts/mpc8641_hpcn.dts151
-rw-r--r--arch/powerpc/boot/dts/mpc866ads.dts31
-rw-r--r--arch/powerpc/boot/dts/mpc885ads.dts54
-rw-r--r--arch/powerpc/boot/dts/prpmc2800.dts2
-rw-r--r--arch/powerpc/boot/dts/ps3.dts68
-rw-r--r--arch/powerpc/boot/ebony.c19
-rw-r--r--arch/powerpc/boot/main.c2
-rw-r--r--arch/powerpc/boot/of.c212
-rw-r--r--arch/powerpc/boot/of.h21
-rw-r--r--arch/powerpc/boot/ofconsole.c45
-rw-r--r--arch/powerpc/boot/oflib.c202
-rw-r--r--arch/powerpc/boot/ops.h4
-rw-r--r--arch/powerpc/boot/ps3-head.S82
-rw-r--r--arch/powerpc/boot/ps3-hvcall.S186
-rw-r--r--arch/powerpc/boot/ps3.c161
-rw-r--r--arch/powerpc/boot/serial.c2
-rw-r--r--arch/powerpc/boot/stdio.c10
-rw-r--r--arch/powerpc/boot/types.h4
-rwxr-xr-xarch/powerpc/boot/wrapper55
-rw-r--r--arch/powerpc/boot/zImage.ps3.lds.S50
-rw-r--r--arch/powerpc/configs/cell_defconfig3
-rw-r--r--arch/powerpc/configs/holly_defconfig6
-rw-r--r--arch/powerpc/configs/prpmc2800_defconfig2
-rw-r--r--arch/powerpc/configs/ps3_defconfig52
-rw-r--r--arch/powerpc/kernel/Makefile7
-rw-r--r--arch/powerpc/kernel/cputable.c35
-rw-r--r--arch/powerpc/kernel/crash.c67
-rw-r--r--arch/powerpc/kernel/head_32.S122
-rw-r--r--arch/powerpc/kernel/head_64.S4
-rw-r--r--arch/powerpc/kernel/io.c12
-rw-r--r--arch/powerpc/kernel/irq.c60
-rw-r--r--arch/powerpc/kernel/isa-bridge.c271
-rw-r--r--arch/powerpc/kernel/kprobes.c11
-rw-r--r--arch/powerpc/kernel/lparcfg.c3
-rw-r--r--arch/powerpc/kernel/misc_32.S10
-rw-r--r--arch/powerpc/kernel/misc_64.S26
-rw-r--r--arch/powerpc/kernel/of_device.c122
-rw-r--r--arch/powerpc/kernel/of_platform.c93
-rw-r--r--arch/powerpc/kernel/pci-common.c457
-rw-r--r--arch/powerpc/kernel/pci_32.c510
-rw-r--r--arch/powerpc/kernel/pci_64.c752
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c5
-rw-r--r--arch/powerpc/kernel/process.c14
-rw-r--r--arch/powerpc/kernel/prom.c281
-rw-r--r--arch/powerpc/kernel/prom_init.c4
-rw-r--r--arch/powerpc/kernel/ptrace-common.h161
-rw-r--r--arch/powerpc/kernel/ptrace.c343
-rw-r--r--arch/powerpc/kernel/ptrace32.c239
-rw-r--r--arch/powerpc/kernel/rtas_flash.c2
-rw-r--r--arch/powerpc/kernel/rtas_pci.c7
-rw-r--r--arch/powerpc/kernel/setup-common.c21
-rw-r--r--arch/powerpc/kernel/setup_32.c12
-rw-r--r--arch/powerpc/kernel/signal.c180
-rw-r--r--arch/powerpc/kernel/signal.h55
-rw-r--r--arch/powerpc/kernel/signal_32.c191
-rw-r--r--arch/powerpc/kernel/signal_64.c182
-rw-r--r--arch/powerpc/kernel/smp.c7
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c7
-rw-r--r--arch/powerpc/kernel/sysfs.c5
-rw-r--r--arch/powerpc/kernel/time.c66
-rw-r--r--arch/powerpc/kernel/traps.c3
-rw-r--r--arch/powerpc/kernel/vdso.c2
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S13
-rw-r--r--arch/powerpc/mm/44x_mmu.c1
-rw-r--r--arch/powerpc/mm/4xx_mmu.c1
-rw-r--r--arch/powerpc/mm/Makefile3
-rw-r--r--arch/powerpc/mm/fault.c36
-rw-r--r--arch/powerpc/mm/fsl_booke_mmu.c1
-rw-r--r--arch/powerpc/mm/hash_native_64.c27
-rw-r--r--arch/powerpc/mm/hash_utils_64.c6
-rw-r--r--arch/powerpc/mm/hugetlbpage.c2
-rw-r--r--arch/powerpc/mm/imalloc.c313
-rw-r--r--arch/powerpc/mm/init_32.c1
-rw-r--r--arch/powerpc/mm/init_64.c4
-rw-r--r--arch/powerpc/mm/mem.c3
-rw-r--r--arch/powerpc/mm/mmu_context_32.c1
-rw-r--r--arch/powerpc/mm/mmu_decl.h17
-rw-r--r--arch/powerpc/mm/pgtable_32.c123
-rw-r--r--arch/powerpc/mm/pgtable_64.c206
-rw-r--r--arch/powerpc/mm/ppc_mmu_32.c7
-rw-r--r--arch/powerpc/mm/stab.c4
-rw-r--r--arch/powerpc/mm/tlb_32.c3
-rw-r--r--arch/powerpc/mm/tlb_64.c57
-rw-r--r--arch/powerpc/oprofile/Kconfig7
-rw-r--r--arch/powerpc/oprofile/Makefile4
-rw-r--r--arch/powerpc/oprofile/cell/pr_util.h97
-rw-r--r--arch/powerpc/oprofile/cell/spu_profiler.c221
-rw-r--r--arch/powerpc/oprofile/cell/spu_task_sync.c484
-rw-r--r--arch/powerpc/oprofile/cell/vma_map.c287
-rw-r--r--arch/powerpc/oprofile/common.c51
-rw-r--r--arch/powerpc/oprofile/op_model_7450.c14
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c607
-rw-r--r--arch/powerpc/oprofile/op_model_fsl_booke.c11
-rw-r--r--arch/powerpc/oprofile/op_model_pa6t.c12
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c25
-rw-r--r--arch/powerpc/oprofile/op_model_rs64.c10
-rw-r--r--arch/powerpc/platforms/52xx/efika.c13
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c2
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c18
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pm.c8
-rw-r--r--arch/powerpc/platforms/82xx/Kconfig2
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx_ads.c17
-rw-r--r--arch/powerpc/platforms/83xx/Kconfig2
-rw-r--r--arch/powerpc/platforms/83xx/Makefile2
-rw-r--r--arch/powerpc/platforms/83xx/mpc8313_rdb.c8
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c7
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c7
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.c9
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_mds.c56
-rw-r--r--arch/powerpc/platforms/83xx/mpc836x_mds.c7
-rw-r--r--arch/powerpc/platforms/83xx/mpc83xx.h34
-rw-r--r--arch/powerpc/platforms/83xx/pci.c18
-rw-r--r--arch/powerpc/platforms/83xx/usb.c181
-rw-r--r--arch/powerpc/platforms/85xx/misc.c32
-rw-r--r--arch/powerpc/platforms/85xx/mpc8544_ds.c15
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx.h2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c32
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c116
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c28
-rw-r--r--arch/powerpc/platforms/85xx/pci.c11
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig2
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx.h11
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c27
-rw-r--r--arch/powerpc/platforms/86xx/pci.c67
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c5
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads_setup.c188
-rw-r--r--arch/powerpc/platforms/Kconfig39
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype221
-rw-r--r--arch/powerpc/platforms/apus/Kconfig130
-rw-r--r--arch/powerpc/platforms/cell/Kconfig10
-rw-r--r--arch/powerpc/platforms/cell/Makefile6
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c445
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c217
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.h24
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c115
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c148
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c7
-rw-r--r--arch/powerpc/platforms/cell/cbe_thermal.c25
-rw-r--r--arch/powerpc/platforms/cell/io-workarounds.c2
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c345
-rw-r--r--arch/powerpc/platforms/cell/spu_manage.c4
-rw-r--r--arch/powerpc/platforms/cell/spu_syscalls.c17
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c53
-rw-r--r--arch/powerpc/platforms/cell/spufs/coredump.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/fault.c51
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c237
-rw-r--r--arch/powerpc/platforms/cell/spufs/gang.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c144
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c81
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c739
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_restore.c8
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped480
-rw-r--r--arch/powerpc/platforms/cell/spufs/spu_save.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h111
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c90
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c34
-rw-r--r--arch/powerpc/platforms/chrp/Kconfig1
-rw-r--r--arch/powerpc/platforms/chrp/Makefile3
-rw-r--r--arch/powerpc/platforms/chrp/pci.c7
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig4
-rw-r--r--arch/powerpc/platforms/embedded6xx/holly.c2
-rw-r--r--arch/powerpc/platforms/embedded6xx/linkstation.c10
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c9
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h5
-rw-r--r--arch/powerpc/platforms/iseries/call_hpt.h9
-rw-r--r--arch/powerpc/platforms/iseries/htab.c8
-rw-r--r--arch/powerpc/platforms/iseries/pci.c7
-rw-r--r--arch/powerpc/platforms/iseries/setup.c6
-rw-r--r--arch/powerpc/platforms/maple/pci.c41
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig9
-rw-r--r--arch/powerpc/platforms/pasemi/Makefile1
-rw-r--r--arch/powerpc/platforms/pasemi/electra_ide.c96
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c24
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c2
-rw-r--r--arch/powerpc/platforms/powermac/Kconfig1
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c23
-rw-r--r--arch/powerpc/platforms/powermac/pci.c46
-rw-r--r--arch/powerpc/platforms/ps3/Kconfig62
-rw-r--r--arch/powerpc/platforms/ps3/Makefile1
-rw-r--r--arch/powerpc/platforms/ps3/device-init.c785
-rw-r--r--arch/powerpc/platforms/ps3/htab.c31
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c272
-rw-r--r--arch/powerpc/platforms/ps3/mm.c632
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c4
-rw-r--r--arch/powerpc/platforms/ps3/platform.h43
-rw-r--r--arch/powerpc/platforms/ps3/repository.c586
-rw-r--r--arch/powerpc/platforms/ps3/setup.c105
-rw-r--r--arch/powerpc/platforms/ps3/smp.c18
-rw-r--r--arch/powerpc/platforms/ps3/spu.c19
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c562
-rw-r--r--arch/powerpc/platforms/ps3/time.c2
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c19
-rw-r--r--arch/powerpc/platforms/pseries/eeh_cache.c5
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c6
-rw-r--r--arch/powerpc/platforms/pseries/eeh_sysfs.c87
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c19
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c17
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c9
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h15
-rw-r--r--arch/powerpc/platforms/pseries/pseries.h4
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c21
-rw-r--r--arch/powerpc/platforms/pseries/xics.c53
-rw-r--r--arch/powerpc/sysdev/Makefile7
-rw-r--r--arch/powerpc/sysdev/axonram.c381
-rw-r--r--arch/powerpc/sysdev/fsl_pcie.c171
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c22
-rw-r--r--arch/powerpc/sysdev/indirect_pci.c44
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.h11
-rw-r--r--arch/powerpc/sysdev/mpic.c32
-rw-r--r--arch/powerpc/sysdev/mv64x60_dev.c28
-rw-r--r--arch/powerpc/sysdev/mv64x60_pci.c7
-rw-r--r--arch/powerpc/sysdev/pmi.c51
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc.c2
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc_fast.c8
-rw-r--r--arch/powerpc/sysdev/rtc_cmos_setup.c49
-rw-r--r--arch/powerpc/sysdev/timer.c14
-rw-r--r--arch/powerpc/sysdev/tsi108_dev.c33
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c10
-rw-r--r--arch/powerpc/xmon/nonstdio.c5
-rw-r--r--arch/powerpc/xmon/nonstdio.h3
-rw-r--r--arch/powerpc/xmon/start.c2
-rw-r--r--arch/powerpc/xmon/xmon.c4
-rw-r--r--arch/ppc/8260_io/enet.c4
-rw-r--r--arch/ppc/8260_io/fcc_enet.c4
-rw-r--r--arch/ppc/8xx_io/enet.c4
-rw-r--r--arch/ppc/8xx_io/fec.c2
-rw-r--r--arch/ppc/Kconfig6
-rw-r--r--arch/ppc/configs/ev64260_defconfig1
-rw-r--r--arch/ppc/configs/mpc8540_ads_defconfig1
-rw-r--r--arch/ppc/configs/mpc8548_cds_defconfig1
-rw-r--r--arch/ppc/configs/mpc8555_cds_defconfig1
-rw-r--r--arch/ppc/configs/mpc8560_ads_defconfig1
-rw-r--r--arch/ppc/configs/radstone_ppc7d_defconfig1
-rw-r--r--arch/ppc/configs/stx_gp3_defconfig1
-rw-r--r--arch/ppc/configs/sycamore_defconfig1
-rw-r--r--arch/ppc/kernel/misc.S8
-rw-r--r--arch/ppc/kernel/pci.c6
-rw-r--r--arch/ppc/kernel/ppc_ksyms.c1
-rw-r--r--arch/ppc/kernel/setup.c2
-rw-r--r--arch/ppc/kernel/traps.c3
-rw-r--r--arch/ppc/kernel/vmlinux.lds.S5
-rw-r--r--arch/ppc/mm/fault.c23
-rw-r--r--arch/ppc/mm/tlb.c1
-rw-r--r--arch/ppc/platforms/4xx/bamboo.c1
-rw-r--r--arch/ppc/platforms/4xx/bubinga.c1
-rw-r--r--arch/ppc/platforms/4xx/cpci405.c1
-rw-r--r--arch/ppc/platforms/4xx/ebony.c1
-rw-r--r--arch/ppc/platforms/4xx/luan.c1
-rw-r--r--arch/ppc/platforms/4xx/ocotea.c1
-rw-r--r--arch/ppc/platforms/4xx/taishan.c1
-rw-r--r--arch/ppc/platforms/4xx/yucca.c1
-rw-r--r--arch/ppc/platforms/85xx/sbc8560.c1
-rw-r--r--arch/ppc/platforms/chestnut.c1
-rw-r--r--arch/ppc/platforms/ev64260.c1
-rw-r--r--arch/ppc/platforms/prep_setup.c3
-rw-r--r--arch/ppc/platforms/radstone_ppc7d.c1
-rw-r--r--arch/ppc/platforms/spruce.c1
-rw-r--r--arch/ppc/syslib/Makefile1
-rw-r--r--arch/ppc/syslib/indirect_pci.c134
-rw-r--r--arch/ppc/syslib/mv64x60.c16
-rw-r--r--arch/ppc/syslib/virtex_devices.c38
-rw-r--r--arch/ppc/syslib/virtex_devices.h7
-rw-r--r--arch/s390/Makefile2
-rw-r--r--arch/s390/defconfig110
-rw-r--r--arch/s390/kernel/dis.c7
-rw-r--r--arch/s390/kernel/ipl.c12
-rw-r--r--arch/s390/kernel/ptrace.c11
-rw-r--r--arch/s390/kernel/stacktrace.c26
-rw-r--r--arch/s390/kernel/traps.c3
-rw-r--r--arch/s390/kernel/vmlinux.lds.S7
-rw-r--r--arch/s390/lib/uaccess_pt.c23
-rw-r--r--arch/s390/mm/fault.c30
-rw-r--r--arch/sh/Kconfig451
-rw-r--r--arch/sh/Kconfig.debug5
-rw-r--r--arch/sh/Makefile107
-rw-r--r--arch/sh/boards/dreamcast/setup.c3
-rw-r--r--arch/sh/boards/hp6xx/mach.c46
-rw-r--r--arch/sh/boards/hp6xx/setup.c3
-rw-r--r--arch/sh/boards/landisk/setup.c3
-rw-r--r--arch/sh/boards/lboxre2/setup.c3
-rw-r--r--arch/sh/boards/mpc1211/pci.c2
-rw-r--r--arch/sh/boards/mpc1211/setup.c3
-rw-r--r--arch/sh/boards/renesas/edosk7705/setup.c3
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/setup.c3
-rw-r--r--arch/sh/boards/renesas/r7780rp/Kconfig6
-rw-r--r--arch/sh/boards/renesas/r7780rp/setup.c57
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/setup.c6
-rw-r--r--arch/sh/boards/renesas/sh7710voipgw/setup.c3
-rw-r--r--arch/sh/boards/renesas/systemh/setup.c3
-rw-r--r--arch/sh/boards/saturn/Makefile8
-rw-r--r--arch/sh/boards/saturn/io.c26
-rw-r--r--arch/sh/boards/saturn/irq.c118
-rw-r--r--arch/sh/boards/saturn/setup.c31
-rw-r--r--arch/sh/boards/saturn/smp.c68
-rw-r--r--arch/sh/boards/se/7206/setup.c3
-rw-r--r--arch/sh/boards/se/7300/setup.c3
-rw-r--r--arch/sh/boards/se/73180/setup.c3
-rw-r--r--arch/sh/boards/se/7343/setup.c3
-rw-r--r--arch/sh/boards/se/7619/setup.c3
-rw-r--r--arch/sh/boards/se/770x/irq.c124
-rw-r--r--arch/sh/boards/se/770x/setup.c3
-rw-r--r--arch/sh/boards/se/7722/irq.c87
-rw-r--r--arch/sh/boards/se/7722/setup.c8
-rw-r--r--arch/sh/boards/se/7751/irq.c59
-rw-r--r--arch/sh/boards/se/7751/setup.c3
-rw-r--r--arch/sh/boards/se/7780/irq.c45
-rw-r--r--arch/sh/boards/se/7780/setup.c3
-rw-r--r--arch/sh/boards/sh03/setup.c31
-rw-r--r--arch/sh/boards/shmin/setup.c33
-rw-r--r--arch/sh/boards/snapgear/setup.c31
-rw-r--r--arch/sh/boards/superh/microdev/setup.c3
-rw-r--r--arch/sh/boards/titan/setup.c25
-rw-r--r--arch/sh/boards/unknown/Makefile6
-rw-r--r--arch/sh/boards/unknown/setup.c21
-rw-r--r--arch/sh/cchips/Kconfig6
-rw-r--r--arch/sh/cchips/hd6446x/Makefile2
-rw-r--r--arch/sh/cchips/hd6446x/hd64461.c (renamed from arch/sh/cchips/hd6446x/hd64461/setup.c)1
-rw-r--r--arch/sh/cchips/hd6446x/hd64461/Makefile6
-rw-r--r--arch/sh/cchips/hd6446x/hd64461/io.c150
-rw-r--r--arch/sh/configs/dreamcast_defconfig338
-rw-r--r--arch/sh/configs/landisk_defconfig2
-rw-r--r--arch/sh/configs/lboxre2_defconfig2
-rw-r--r--arch/sh/configs/r7780mp_defconfig1223
-rw-r--r--arch/sh/configs/r7780rp_defconfig2
-rw-r--r--arch/sh/configs/r7785rp_defconfig296
-rw-r--r--arch/sh/configs/rts7751r2d_defconfig8
-rw-r--r--arch/sh/configs/se7206_defconfig272
-rw-r--r--arch/sh/configs/se7619_defconfig215
-rw-r--r--arch/sh/configs/se7722_defconfig291
-rw-r--r--arch/sh/configs/se7750_defconfig2
-rw-r--r--arch/sh/configs/se7780_defconfig1
-rw-r--r--arch/sh/configs/shx3_defconfig756
-rw-r--r--arch/sh/drivers/dma/Kconfig20
-rw-r--r--arch/sh/drivers/heartbeat.c2
-rw-r--r--arch/sh/drivers/pci/Kconfig1
-rw-r--r--arch/sh/drivers/pci/Makefile1
-rw-r--r--arch/sh/drivers/pci/ops-sh4.c2
-rw-r--r--arch/sh/drivers/pci/pci-st40.c2
-rw-r--r--arch/sh/drivers/pci/pci.c2
-rw-r--r--arch/sh/drivers/push-switch.c2
-rw-r--r--arch/sh/kernel/Makefile9
-rw-r--r--arch/sh/kernel/cf-enabler.c6
-rw-r--r--arch/sh/kernel/cpu/clock.c16
-rw-r--r--arch/sh/kernel/cpu/init.c15
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile1
-rw-r--r--arch/sh/kernel/cpu/irq/intc.c405
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c63
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c59
-rw-r--r--arch/sh/kernel/cpu/sh2/entry.S1
-rw-r--r--arch/sh/kernel/cpu/sh2/probe.c13
-rw-r--r--arch/sh/kernel/cpu/sh2/setup-sh7619.c26
-rw-r--r--arch/sh/kernel/cpu/sh2a/setup-sh7206.c26
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S19
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c40
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c112
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c42
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c8
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c249
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c41
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c3
-rw-r--r--arch/sh/kernel/cpu/sh4a/Makefile2
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c15
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-shx3.c135
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7722.c185
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7780.c216
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-sh7785.c18
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c85
-rw-r--r--arch/sh/kernel/cpufreq.c215
-rw-r--r--arch/sh/kernel/head.S3
-rw-r--r--arch/sh/kernel/irq.c17
-rw-r--r--arch/sh/kernel/machvec.c130
-rw-r--r--arch/sh/kernel/process.c18
-rw-r--r--arch/sh/kernel/ptrace.c24
-rw-r--r--arch/sh/kernel/setup.c217
-rw-r--r--arch/sh/kernel/sh_bios.c3
-rw-r--r--arch/sh/kernel/sh_ksyms.c45
-rw-r--r--arch/sh/kernel/signal.c3
-rw-r--r--arch/sh/kernel/syscalls.S7
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c8
-rw-r--r--arch/sh/kernel/topology.c49
-rw-r--r--arch/sh/kernel/traps.c8
-rw-r--r--arch/sh/kernel/vmlinux.lds.S26
-rw-r--r--arch/sh/lib/div64-generic.c9
-rw-r--r--arch/sh/lib/div64.S6
-rw-r--r--arch/sh/math-emu/math.c18
-rw-r--r--arch/sh/mm/Kconfig101
-rw-r--r--arch/sh/mm/Makefile5
-rw-r--r--arch/sh/mm/fault.c68
-rw-r--r--arch/sh/mm/init.c107
-rw-r--r--arch/sh/mm/numa.c92
-rw-r--r--arch/sh/mm/pg-dma.c95
-rw-r--r--arch/sh/mm/pmb.c2
-rw-r--r--arch/sh/tools/Makefile1
-rw-r--r--arch/sh/tools/mach-types2
-rw-r--r--arch/sh64/configs/cayman_defconfig158
-rw-r--r--arch/sh64/kernel/head.S2
-rw-r--r--arch/sh64/kernel/pci_sh5.c4
-rw-r--r--arch/sh64/kernel/ptrace.c17
-rw-r--r--arch/sh64/kernel/syscalls.S1
-rw-r--r--arch/sh64/kernel/vmlinux.lds.S6
-rw-r--r--arch/sh64/lib/c-checksum.c1
-rw-r--r--arch/sh64/mm/fault.c24
-rw-r--r--arch/sh64/mm/ioremap.c2
-rw-r--r--arch/sparc/Kconfig12
-rw-r--r--arch/sparc/kernel/ebus.c5
-rw-r--r--arch/sparc/kernel/entry.S14
-rw-r--r--arch/sparc/kernel/irq.c27
-rw-r--r--arch/sparc/kernel/irq.h68
-rw-r--r--arch/sparc/kernel/of_device.c227
-rw-r--r--arch/sparc/kernel/pcic.c1
-rw-r--r--arch/sparc/kernel/process.c8
-rw-r--r--arch/sparc/kernel/prom.c304
-rw-r--r--arch/sparc/kernel/setup.c65
-rw-r--r--arch/sparc/kernel/smp.c2
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c2
-rw-r--r--arch/sparc/kernel/sun4c_irq.c15
-rw-r--r--arch/sparc/kernel/sun4d_irq.c6
-rw-r--r--arch/sparc/kernel/sun4d_smp.c1
-rw-r--r--arch/sparc/kernel/sun4m_irq.c74
-rw-r--r--arch/sparc/kernel/sun4m_smp.c2
-rw-r--r--arch/sparc/kernel/systbls.S9
-rw-r--r--arch/sparc/kernel/tick14.c6
-rw-r--r--arch/sparc/kernel/time.c4
-rw-r--r--arch/sparc/kernel/traps.c1
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S5
-rw-r--r--arch/sparc/mm/fault.c22
-rw-r--r--arch/sparc/mm/init.c3
-rw-r--r--arch/sparc/mm/srmmu.c6
-rw-r--r--arch/sparc/mm/sun4c.c8
-rw-r--r--arch/sparc/prom/console.c116
-rw-r--r--arch/sparc/prom/misc.c4
-rw-r--r--arch/sparc64/Kconfig31
-rw-r--r--arch/sparc64/defconfig175
-rw-r--r--arch/sparc64/kernel/Makefile3
-rw-r--r--arch/sparc64/kernel/auxio.c2
-rw-r--r--arch/sparc64/kernel/ds.c1246
-rw-r--r--arch/sparc64/kernel/ebus.c5
-rw-r--r--arch/sparc64/kernel/head.S1
-rw-r--r--arch/sparc64/kernel/hvtramp.S140
-rw-r--r--arch/sparc64/kernel/irq.c148
-rw-r--r--arch/sparc64/kernel/isa.c5
-rw-r--r--arch/sparc64/kernel/ldc.c2373
-rw-r--r--arch/sparc64/kernel/mdesc.c798
-rw-r--r--arch/sparc64/kernel/of_device.c243
-rw-r--r--arch/sparc64/kernel/pci.c1
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c4
-rw-r--r--arch/sparc64/kernel/power.c72
-rw-r--r--arch/sparc64/kernel/process.c27
-rw-r--r--arch/sparc64/kernel/prom.c231
-rw-r--r--arch/sparc64/kernel/setup.c75
-rw-r--r--arch/sparc64/kernel/signal.c15
-rw-r--r--arch/sparc64/kernel/smp.c251
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c18
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c12
-rw-r--r--arch/sparc64/kernel/sysfs.c2
-rw-r--r--arch/sparc64/kernel/systbls.S11
-rw-r--r--arch/sparc64/kernel/time.c163
-rw-r--r--arch/sparc64/kernel/traps.c1
-rw-r--r--arch/sparc64/kernel/vio.c443
-rw-r--r--arch/sparc64/kernel/viohs.c822
-rw-r--r--arch/sparc64/kernel/vmlinux.lds.S6
-rw-r--r--arch/sparc64/lib/Makefile2
-rw-r--r--arch/sparc64/lib/delay.c46
-rw-r--r--arch/sparc64/mm/fault.c24
-rw-r--r--arch/sparc64/mm/tsb.c3
-rw-r--r--arch/sparc64/prom/console.c85
-rw-r--r--arch/sparc64/prom/misc.c17
-rw-r--r--arch/sparc64/prom/p1275.c1
-rw-r--r--arch/sparc64/prom/tree.c21
-rw-r--r--arch/sparc64/solaris/socksys.c3
-rw-r--r--arch/um/Kconfig.debug9
-rw-r--r--arch/um/Makefile2
-rw-r--r--arch/um/config.release333
-rw-r--r--arch/um/defconfig4
-rw-r--r--arch/um/drivers/chan_kern.c23
-rw-r--r--arch/um/drivers/chan_user.c78
-rw-r--r--arch/um/drivers/cow_sys.h2
-rw-r--r--arch/um/drivers/daemon_user.c4
-rw-r--r--arch/um/drivers/fd.c2
-rw-r--r--arch/um/drivers/harddog_user.c2
-rw-r--r--arch/um/drivers/line.c65
-rw-r--r--arch/um/drivers/mcast_user.c2
-rw-r--r--arch/um/drivers/mconsole_user.c5
-rw-r--r--arch/um/drivers/net_user.c4
-rw-r--r--arch/um/drivers/pcap_user.c2
-rw-r--r--arch/um/drivers/port_user.c4
-rw-r--r--arch/um/drivers/pty.c78
-rw-r--r--arch/um/drivers/slip_user.c4
-rw-r--r--arch/um/drivers/slirp_user.c2
-rw-r--r--arch/um/drivers/ssl.c10
-rw-r--r--arch/um/drivers/stdio_console.c9
-rw-r--r--arch/um/drivers/tty.c2
-rw-r--r--arch/um/drivers/ubd_kern.c8
-rw-r--r--arch/um/drivers/ubd_user.c6
-rw-r--r--arch/um/drivers/xterm.c174
-rw-r--r--arch/um/drivers/xterm_kern.c49
-rw-r--r--arch/um/include/chan_kern.h2
-rw-r--r--arch/um/include/chan_user.h5
-rw-r--r--arch/um/include/common-offsets.h3
-rw-r--r--arch/um/include/os.h6
-rw-r--r--arch/um/include/um_malloc.h12
-rw-r--r--arch/um/kernel/irq.c1
-rw-r--r--arch/um/kernel/process.c16
-rw-r--r--arch/um/kernel/ptrace.c18
-rw-r--r--arch/um/kernel/trap.c29
-rw-r--r--arch/um/os-Linux/aio.c11
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c6
-rw-r--r--arch/um/os-Linux/drivers/tuntap_user.c2
-rw-r--r--arch/um/os-Linux/helper.c23
-rw-r--r--arch/um/os-Linux/main.c4
-rw-r--r--arch/um/os-Linux/sigio.c23
-rw-r--r--arch/um/os-Linux/skas/process.c2
-rw-r--r--arch/um/os-Linux/user_syms.c20
-rw-r--r--arch/v850/kernel/ptrace.c14
-rw-r--r--arch/x86_64/Kconfig20
-rw-r--r--arch/x86_64/Makefile3
-rw-r--r--arch/x86_64/boot/.gitignore2
-rw-r--r--arch/x86_64/boot/Makefile136
-rw-r--r--arch/x86_64/boot/bootsect.S98
-rw-r--r--arch/x86_64/boot/compressed/Makefile11
-rw-r--r--arch/x86_64/boot/compressed/head.S6
-rw-r--r--arch/x86_64/boot/install.sh2
-rw-r--r--arch/x86_64/boot/mtools.conf.in17
-rw-r--r--arch/x86_64/boot/setup.S826
-rw-r--r--arch/x86_64/boot/tools/build.c185
-rw-r--r--arch/x86_64/defconfig288
-rw-r--r--arch/x86_64/ia32/ia32_aout.c2
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c59
-rw-r--r--arch/x86_64/ia32/ia32entry.S8
-rw-r--r--arch/x86_64/ia32/sys_ia32.c8
-rw-r--r--arch/x86_64/kernel/Makefile2
-rw-r--r--arch/x86_64/kernel/acpi/sleep.c8
-rw-r--r--arch/x86_64/kernel/acpi/wakeup.S32
-rw-r--r--arch/x86_64/kernel/aperture.c4
-rw-r--r--arch/x86_64/kernel/apic.c77
-rw-r--r--arch/x86_64/kernel/cpufreq/Kconfig6
-rw-r--r--arch/x86_64/kernel/e820.c138
-rw-r--r--arch/x86_64/kernel/early-quirks.c1
-rw-r--r--arch/x86_64/kernel/early_printk.c5
-rw-r--r--arch/x86_64/kernel/entry.S6
-rw-r--r--arch/x86_64/kernel/head.S23
-rw-r--r--arch/x86_64/kernel/hpet.c8
-rw-r--r--arch/x86_64/kernel/i8259.c18
-rw-r--r--arch/x86_64/kernel/init_task.c2
-rw-r--r--arch/x86_64/kernel/io_apic.c58
-rw-r--r--arch/x86_64/kernel/kprobes.c10
-rw-r--r--arch/x86_64/kernel/mce.c255
-rw-r--r--arch/x86_64/kernel/mce_amd.c6
-rw-r--r--arch/x86_64/kernel/mpparse.c21
-rw-r--r--arch/x86_64/kernel/nmi.c25
-rw-r--r--arch/x86_64/kernel/pci-calgary.c570
-rw-r--r--arch/x86_64/kernel/pci-dma.c10
-rw-r--r--arch/x86_64/kernel/pci-gart.c27
-rw-r--r--arch/x86_64/kernel/pci-nommu.c8
-rw-r--r--arch/x86_64/kernel/pci-swiotlb.c2
-rw-r--r--arch/x86_64/kernel/process.c21
-rw-r--r--arch/x86_64/kernel/ptrace.c40
-rw-r--r--arch/x86_64/kernel/reboot.c4
-rw-r--r--arch/x86_64/kernel/setup.c33
-rw-r--r--arch/x86_64/kernel/signal.c9
-rw-r--r--arch/x86_64/kernel/smp.c18
-rw-r--r--arch/x86_64/kernel/suspend.c20
-rw-r--r--arch/x86_64/kernel/tce.c12
-rw-r--r--arch/x86_64/kernel/time.c158
-rw-r--r--arch/x86_64/kernel/traps.c21
-rw-r--r--arch/x86_64/kernel/tsc.c41
-rw-r--r--arch/x86_64/kernel/verify_cpu.S22
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S37
-rw-r--r--arch/x86_64/kernel/vsyscall.c22
-rw-r--r--arch/x86_64/mm/fault.c48
-rw-r--r--arch/x86_64/mm/init.c58
-rw-r--r--arch/x86_64/mm/k8topology.c13
-rw-r--r--arch/x86_64/mm/numa.c15
-rw-r--r--arch/x86_64/mm/pageattr.c25
-rw-r--r--arch/x86_64/mm/srat.c97
-rw-r--r--arch/x86_64/pci/k8-bus.c6
-rw-r--r--arch/x86_64/vdso/Makefile49
-rw-r--r--arch/x86_64/vdso/vclock_gettime.c120
-rw-r--r--arch/x86_64/vdso/vdso-note.S12
-rw-r--r--arch/x86_64/vdso/vdso-start.S2
-rw-r--r--arch/x86_64/vdso/vdso.S2
-rw-r--r--arch/x86_64/vdso/vdso.lds.S77
-rw-r--r--arch/x86_64/vdso/vextern.h16
-rw-r--r--arch/x86_64/vdso/vgetcpu.c50
-rw-r--r--arch/x86_64/vdso/vma.c139
-rw-r--r--arch/x86_64/vdso/voffset.h1
-rw-r--r--arch/x86_64/vdso/vvar.c12
-rw-r--r--arch/xtensa/kernel/ptrace.c17
-rw-r--r--arch/xtensa/kernel/traps.c1
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S8
-rw-r--r--arch/xtensa/mm/fault.c23
-rw-r--r--block/Kconfig13
-rw-r--r--block/Makefile1
-rw-r--r--block/as-iosched.c3
-rw-r--r--block/bsg.c1080
-rw-r--r--block/cfq-iosched.c85
-rw-r--r--block/deadline-iosched.c3
-rw-r--r--block/elevator.c3
-rw-r--r--block/genhd.c20
-rw-r--r--block/ll_rw_blk.c11
-rw-r--r--block/scsi_ioctl.c163
-rw-r--r--crypto/Kconfig16
-rw-r--r--crypto/Makefile6
-rw-r--r--crypto/ablkcipher.c31
-rw-r--r--crypto/algapi.c4
-rw-r--r--crypto/api.c2
-rw-r--r--crypto/async_tx/Kconfig16
-rw-r--r--crypto/async_tx/Makefile4
-rw-r--r--crypto/async_tx/async_memcpy.c120
-rw-r--r--crypto/async_tx/async_memset.c109
-rw-r--r--crypto/async_tx/async_tx.c497
-rw-r--r--crypto/async_tx/async_xor.c327
-rw-r--r--crypto/blkcipher.c25
-rw-r--r--crypto/cipher.c33
-rw-r--r--crypto/hash.c38
-rw-r--r--crypto/proc.c17
-rw-r--r--crypto/xor.c (renamed from drivers/md/xor.c)55
-rw-r--r--drivers/Kconfig5
-rw-r--r--drivers/Makefile5
-rw-r--r--drivers/acpi/Kconfig23
-rw-r--r--drivers/acpi/battery.c673
-rw-r--r--drivers/acpi/bay.c19
-rw-r--r--drivers/acpi/bus.c4
-rw-r--r--drivers/acpi/dock.c127
-rw-r--r--drivers/acpi/ec.c247
-rw-r--r--drivers/acpi/event.c153
-rw-r--r--drivers/acpi/events/evgpeblk.c4
-rw-r--r--drivers/acpi/events/evrgnini.c1
-rw-r--r--drivers/acpi/glue.c2
-rw-r--r--drivers/acpi/numa.c31
-rw-r--r--drivers/acpi/osl.c42
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/processor_core.c13
-rw-r--r--drivers/acpi/processor_idle.c24
-rw-r--r--drivers/acpi/processor_throttling.c410
-rw-r--r--drivers/acpi/sbs.c33
-rw-r--r--drivers/acpi/sleep/main.c19
-rw-r--r--drivers/acpi/sleep/poweroff.c41
-rw-r--r--drivers/acpi/system.c165
-rw-r--r--drivers/acpi/tables/tbfadt.c44
-rw-r--r--drivers/acpi/thermal.c24
-rw-r--r--drivers/acpi/utilities/uteval.c17
-rw-r--r--drivers/acpi/video.c124
-rw-r--r--drivers/ata/Kconfig10
-rw-r--r--drivers/ata/ahci.c255
-rw-r--r--drivers/ata/ata_piix.c8
-rw-r--r--drivers/ata/libata-core.c153
-rw-r--r--drivers/ata/libata-eh.c300
-rw-r--r--drivers/ata/libata-scsi.c63
-rw-r--r--drivers/ata/libata-sff.c292
-rw-r--r--drivers/ata/libata.h3
-rw-r--r--drivers/ata/pata_ali.c34
-rw-r--r--drivers/ata/pata_amd.c4
-rw-r--r--drivers/ata/pata_cs5520.c2
-rw-r--r--drivers/ata/pata_cs5530.c2
-rw-r--r--drivers/ata/pata_hpt3x3.c93
-rw-r--r--drivers/ata/pata_it821x.c3
-rw-r--r--drivers/ata/pata_mpc52xx.c18
-rw-r--r--drivers/ata/pata_pcmcia.c1
-rw-r--r--drivers/ata/pata_platform.c5
-rw-r--r--drivers/ata/pata_scc.c63
-rw-r--r--drivers/ata/pata_serverworks.c5
-rw-r--r--drivers/ata/pata_sis.c11
-rw-r--r--drivers/ata/pata_sl82c105.c5
-rw-r--r--drivers/ata/pata_via.c6
-rw-r--r--drivers/ata/sata_inic162x.c16
-rw-r--r--drivers/ata/sata_mv.c1044
-rw-r--r--drivers/ata/sata_nv.c40
-rw-r--r--drivers/ata/sata_promise.c66
-rw-r--r--drivers/ata/sata_qstor.c18
-rw-r--r--drivers/ata/sata_sil.c25
-rw-r--r--drivers/ata/sata_sil24.c139
-rw-r--r--drivers/ata/sata_sis.c24
-rw-r--r--drivers/ata/sata_svw.c13
-rw-r--r--drivers/ata/sata_uli.c18
-rw-r--r--drivers/ata/sata_via.c29
-rw-r--r--drivers/ata/sata_vsc.c13
-rw-r--r--drivers/atm/Kconfig10
-rw-r--r--drivers/atm/ambassador.c4
-rw-r--r--drivers/atm/eni.c28
-rw-r--r--drivers/atm/firestream.c14
-rw-r--r--drivers/atm/idt77252.c19
-rw-r--r--drivers/atm/iphase.c11
-rw-r--r--drivers/atm/lanai.c31
-rw-r--r--drivers/atm/nicstarmac.c2
-rw-r--r--drivers/atm/zatm.c10
-rw-r--r--drivers/auxdisplay/Kconfig8
-rw-r--r--drivers/base/attribute_container.c1
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/bus.c24
-rw-r--r--drivers/base/class.c46
-rw-r--r--drivers/base/core.c226
-rw-r--r--drivers/base/dd.c21
-rw-r--r--drivers/base/devres.c2
-rw-r--r--drivers/base/dmapool.c2
-rw-r--r--drivers/base/firmware_class.c6
-rw-r--r--drivers/base/power/Makefile4
-rw-r--r--drivers/base/power/main.c44
-rw-r--r--drivers/base/power/power.h9
-rw-r--r--drivers/base/power/resume.c23
-rw-r--r--drivers/base/power/runtime.c85
-rw-r--r--drivers/base/power/suspend.c72
-rw-r--r--drivers/base/power/sysfs.c66
-rw-r--r--drivers/base/power/trace.c5
-rw-r--r--drivers/base/sys.c24
-rw-r--r--drivers/block/Kconfig35
-rw-r--r--drivers/block/Makefile6
-rw-r--r--drivers/block/acsi_slm.c1032
-rw-r--r--drivers/block/aoe/aoeblk.c4
-rw-r--r--drivers/block/cciss.c2
-rw-r--r--drivers/block/cciss_scsi.c75
-rw-r--r--drivers/block/lguest_blk.c275
-rw-r--r--drivers/block/loop.c11
-rw-r--r--drivers/block/nbd.c22
-rw-r--r--drivers/block/pktcdvd.c7
-rw-r--r--drivers/block/ps3disk.c630
-rw-r--r--drivers/block/sunvdc.c887
-rw-r--r--drivers/block/sx8.c3
-rw-r--r--drivers/block/ub.c14
-rw-r--r--drivers/block/umem.c58
-rw-r--r--drivers/block/viodasd.c4
-rw-r--r--drivers/block/xen-blkfront.c988
-rw-r--r--drivers/block/xsysace.c1164
-rw-r--r--drivers/block/z2ram.c7
-rw-r--r--drivers/bluetooth/hci_usb.c88
-rw-r--r--drivers/bluetooth/hci_usb.h5
-rw-r--r--drivers/bluetooth/hci_vhci.c6
-rw-r--r--drivers/cdrom/cdrom.c3
-rw-r--r--drivers/char/Kconfig82
-rw-r--r--drivers/char/Makefile5
-rw-r--r--drivers/char/agp/amd-k7-agp.c4
-rw-r--r--drivers/char/agp/amd64-agp.c6
-rw-r--r--drivers/char/agp/backend.c2
-rw-r--r--drivers/char/amiserial.c10
-rw-r--r--drivers/char/apm-emulation.c12
-rw-r--r--drivers/char/briq_panel.c10
-rw-r--r--drivers/char/consolemap.c78
-rw-r--r--drivers/char/cyclades.c371
-rw-r--r--drivers/char/decserial.c67
-rw-r--r--drivers/char/drm/ati_pcigart.c8
-rw-r--r--drivers/char/drm/drm.h329
-rw-r--r--drivers/char/drm/drmP.h356
-rw-r--r--drivers/char/drm/drm_agpsupport.c116
-rw-r--r--drivers/char/drm/drm_auth.c40
-rw-r--r--drivers/char/drm/drm_bufs.c209
-rw-r--r--drivers/char/drm/drm_context.c226
-rw-r--r--drivers/char/drm/drm_dma.c12
-rw-r--r--drivers/char/drm/drm_drawable.c270
-rw-r--r--drivers/char/drm/drm_drv.c87
-rw-r--r--drivers/char/drm/drm_fops.c68
-rw-r--r--drivers/char/drm/drm_hashtab.c34
-rw-r--r--drivers/char/drm/drm_hashtab.h24
-rw-r--r--drivers/char/drm/drm_ioc32.c82
-rw-r--r--drivers/char/drm/drm_ioctl.c68
-rw-r--r--drivers/char/drm/drm_irq.c58
-rw-r--r--drivers/char/drm/drm_lock.c28
-rw-r--r--drivers/char/drm/drm_memory.c8
-rw-r--r--drivers/char/drm/drm_mm.c66
-rw-r--r--drivers/char/drm/drm_os_linux.h22
-rw-r--r--drivers/char/drm/drm_pci.c6
-rw-r--r--drivers/char/drm/drm_proc.c50
-rw-r--r--drivers/char/drm/drm_sarea.h26
-rw-r--r--drivers/char/drm/drm_scatter.c22
-rw-r--r--drivers/char/drm/drm_sman.c93
-rw-r--r--drivers/char/drm/drm_sman.h50
-rw-r--r--drivers/char/drm/drm_stub.c32
-rw-r--r--drivers/char/drm/drm_sysfs.c4
-rw-r--r--drivers/char/drm/drm_vm.c106
-rw-r--r--drivers/char/drm/i810_dma.c164
-rw-r--r--drivers/char/drm/i810_drm.h2
-rw-r--r--drivers/char/drm/i810_drv.h18
-rw-r--r--drivers/char/drm/i830_dma.c157
-rw-r--r--drivers/char/drm/i830_drm.h2
-rw-r--r--drivers/char/drm/i830_drv.h24
-rw-r--r--drivers/char/drm/i830_irq.c20
-rw-r--r--drivers/char/drm/i915_dma.c44
-rw-r--r--drivers/char/drm/i915_drm.h8
-rw-r--r--drivers/char/drm/i915_drv.h22
-rw-r--r--drivers/char/drm/i915_irq.c28
-rw-r--r--drivers/char/drm/i915_mem.c6
-rw-r--r--drivers/char/drm/mga_dma.c79
-rw-r--r--drivers/char/drm/mga_drm.h6
-rw-r--r--drivers/char/drm/mga_drv.c4
-rw-r--r--drivers/char/drm/mga_drv.h22
-rw-r--r--drivers/char/drm/mga_irq.c12
-rw-r--r--drivers/char/drm/mga_state.c36
-rw-r--r--drivers/char/drm/r128_cce.c41
-rw-r--r--drivers/char/drm/r128_drm.h4
-rw-r--r--drivers/char/drm/r128_drv.h20
-rw-r--r--drivers/char/drm/r128_irq.c10
-rw-r--r--drivers/char/drm/r128_state.c60
-rw-r--r--drivers/char/drm/r300_cmdbuf.c53
-rw-r--r--drivers/char/drm/r300_reg.h1163
-rw-r--r--drivers/char/drm/radeon_cp.c54
-rw-r--r--drivers/char/drm/radeon_drm.h12
-rw-r--r--drivers/char/drm/radeon_drv.c3
-rw-r--r--drivers/char/drm/radeon_drv.h45
-rw-r--r--drivers/char/drm/radeon_irq.c118
-rw-r--r--drivers/char/drm/radeon_state.c108
-rw-r--r--drivers/char/drm/savage_bci.c44
-rw-r--r--drivers/char/drm/savage_drm.h4
-rw-r--r--drivers/char/drm/savage_drv.h20
-rw-r--r--drivers/char/drm/savage_state.c28
-rw-r--r--drivers/char/drm/sis_drv.c4
-rw-r--r--drivers/char/drm/sis_drv.h9
-rw-r--r--drivers/char/drm/sis_mm.c18
-rw-r--r--drivers/char/drm/via_dma.c10
-rw-r--r--drivers/char/drm/via_dmablit.c23
-rw-r--r--drivers/char/drm/via_dmablit.h2
-rw-r--r--drivers/char/drm/via_drm.h4
-rw-r--r--drivers/char/drm/via_drv.h32
-rw-r--r--drivers/char/drm/via_irq.c12
-rw-r--r--drivers/char/drm/via_map.c10
-rw-r--r--drivers/char/drm/via_mm.c6
-rw-r--r--drivers/char/drm/via_verifier.c12
-rw-r--r--drivers/char/drm/via_verifier.h6
-rw-r--r--drivers/char/esp.c13
-rw-r--r--drivers/char/generic_serial.c120
-rw-r--r--drivers/char/genrtc.c22
-rw-r--r--drivers/char/hpet.c70
-rw-r--r--drivers/char/hvc_console.c3
-rw-r--r--drivers/char/hvc_iseries.c8
-rw-r--r--drivers/char/hvc_lguest.c102
-rw-r--r--drivers/char/hvc_rtas.c2
-rw-r--r--drivers/char/hvc_xen.c159
-rw-r--r--drivers/char/hvcs.c12
-rw-r--r--drivers/char/hw_random/Kconfig2
-rw-r--r--drivers/char/hw_random/intel-rng.c10
-rw-r--r--drivers/char/ip2/i2ellis.c44
-rw-r--r--drivers/char/ip2/ip2main.c4
-rw-r--r--drivers/char/ipmi/Kconfig15
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c13
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c2
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c2
-rw-r--r--drivers/char/isicom.c93
-rw-r--r--drivers/char/istallion.c12
-rw-r--r--drivers/char/keyboard.c26
-rw-r--r--drivers/char/mbcs.c27
-rw-r--r--drivers/char/mbcs.h10
-rw-r--r--drivers/char/misc.c18
-rw-r--r--drivers/char/moxa.c37
-rw-r--r--drivers/char/mspec.c2
-rw-r--r--drivers/char/mxser.c16
-rw-r--r--drivers/char/mxser_new.c22
-rw-r--r--drivers/char/n_hdlc.c16
-rw-r--r--drivers/char/n_r3964.c14
-rw-r--r--drivers/char/n_tty.c23
-rw-r--r--drivers/char/nvram.c192
-rw-r--r--drivers/char/pcmcia/synclink_cs.c3
-rw-r--r--drivers/char/ps3flash.c440
-rw-r--r--drivers/char/random.c9
-rw-r--r--drivers/char/rio/rio_linux.c4
-rw-r--r--drivers/char/rio/riocmd.c4
-rw-r--r--drivers/char/rio/riotable.c3
-rw-r--r--drivers/char/riscom8.c12
-rw-r--r--drivers/char/rocket.c6
-rw-r--r--drivers/char/rtc.c35
-rw-r--r--drivers/char/selection.c48
-rw-r--r--drivers/char/serial167.c6
-rw-r--r--drivers/char/sonypi.c47
-rw-r--r--drivers/char/specialix.c16
-rw-r--r--drivers/char/stallion.c10
-rw-r--r--drivers/char/synclink.c11
-rw-r--r--drivers/char/synclink_gt.c11
-rw-r--r--drivers/char/synclinkmp.c11
-rw-r--r--drivers/char/tpm/Kconfig18
-rw-r--r--drivers/char/tpm/tpm_bios.c22
-rw-r--r--drivers/char/tty_audit.c345
-rw-r--r--drivers/char/tty_io.c65
-rw-r--r--drivers/char/tty_ioctl.c32
-rw-r--r--drivers/char/viotape.c19
-rw-r--r--drivers/char/vme_scc.c8
-rw-r--r--drivers/char/vr41xx_giu.c132
-rw-r--r--drivers/char/vt.c35
-rw-r--r--drivers/char/watchdog/Kconfig27
-rw-r--r--drivers/char/watchdog/Makefile4
-rw-r--r--drivers/char/watchdog/at32ap700x_wdt.c386
-rw-r--r--drivers/char/watchdog/ep93xx_wdt.c4
-rw-r--r--drivers/char/watchdog/iop_wdt.c262
-rw-r--r--drivers/char/watchdog/mixcomwd.c127
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c3
-rw-r--r--drivers/char/watchdog/pcwd_usb.c3
-rw-r--r--drivers/char/watchdog/pnx4008_wdt.c4
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c41
-rw-r--r--drivers/clocksource/acpi_pm.c7
-rw-r--r--drivers/connector/Kconfig7
-rw-r--r--drivers/cpufreq/cpufreq.c47
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c30
-rw-r--r--drivers/cpufreq/cpufreq_stats.c3
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c25
-rw-r--r--drivers/cpufreq/freq_table.c1
-rw-r--r--drivers/crypto/Kconfig9
-rw-r--r--drivers/dma/Kconfig14
-rw-r--r--drivers/dma/Makefile1
-rw-r--r--drivers/dma/dmaengine.c419
-rw-r--r--drivers/dma/ioatdma.c369
-rw-r--r--drivers/dma/ioatdma.h16
-rw-r--r--drivers/dma/ioatdma_io.h118
-rw-r--r--drivers/dma/iop-adma.c1467
-rw-r--r--drivers/edac/Kconfig65
-rw-r--r--drivers/edac/Makefile17
-rw-r--r--drivers/edac/amd76x_edac.c75
-rw-r--r--drivers/edac/e752x_edac.c320
-rw-r--r--drivers/edac/e7xxx_edac.c125
-rw-r--r--drivers/edac/edac_core.h (renamed from drivers/edac/edac_mc.h)506
-rw-r--r--drivers/edac/edac_device.c746
-rw-r--r--drivers/edac/edac_device_sysfs.c896
-rw-r--r--drivers/edac/edac_mc.c1675
-rw-r--r--drivers/edac/edac_mc_sysfs.c1024
-rw-r--r--drivers/edac/edac_module.c222
-rw-r--r--drivers/edac/edac_module.h77
-rw-r--r--drivers/edac/edac_pci.c433
-rw-r--r--drivers/edac/edac_pci_sysfs.c620
-rw-r--r--drivers/edac/edac_stub.c46
-rw-r--r--drivers/edac/i3000_edac.c506
-rw-r--r--drivers/edac/i5000_edac.c1505
-rw-r--r--drivers/edac/i82443bxgx_edac.c402
-rw-r--r--drivers/edac/i82860_edac.c56
-rw-r--r--drivers/edac/i82875p_edac.c92
-rw-r--r--drivers/edac/i82975x_edac.c666
-rw-r--r--drivers/edac/pasemi_edac.c299
-rw-r--r--drivers/edac/r82600_edac.c77
-rw-r--r--drivers/firewire/fw-ohci.c3
-rw-r--r--drivers/firewire/fw-sbp2.c18
-rw-r--r--drivers/firewire/fw-transaction.c9
-rw-r--r--drivers/firewire/fw-transaction.h4
-rw-r--r--drivers/firmware/Kconfig9
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/dcdbas.c10
-rw-r--r--drivers/firmware/dcdbas.h3
-rw-r--r--drivers/firmware/dell_rbu.c31
-rw-r--r--drivers/firmware/dmi-id.c222
-rw-r--r--drivers/firmware/dmi_scan.c73
-rw-r--r--drivers/firmware/edd.c9
-rw-r--r--drivers/firmware/efivars.c6
-rw-r--r--drivers/firmware/pcdp.c6
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hwmon/Kconfig82
-rw-r--r--drivers/hwmon/Makefile3
-rw-r--r--drivers/hwmon/abituguru.c45
-rw-r--r--drivers/hwmon/abituguru3.c1140
-rw-r--r--drivers/hwmon/coretemp.c2
-rw-r--r--drivers/hwmon/dme1737.c2080
-rw-r--r--drivers/hwmon/ds1621.c161
-rw-r--r--drivers/hwmon/f71805f.c178
-rw-r--r--drivers/hwmon/it87.c497
-rw-r--r--drivers/hwmon/lm63.c4
-rw-r--r--drivers/hwmon/lm70.c4
-rw-r--r--drivers/hwmon/lm83.c12
-rw-r--r--drivers/hwmon/lm90.c78
-rw-r--r--drivers/hwmon/lm93.c2655
-rw-r--r--drivers/hwmon/pc87360.c232
-rw-r--r--drivers/hwmon/pc87427.c2
-rw-r--r--drivers/hwmon/sis5595.c510
-rw-r--r--drivers/hwmon/smsc47b397.c7
-rw-r--r--drivers/hwmon/smsc47m1.c12
-rw-r--r--drivers/hwmon/smsc47m192.c37
-rw-r--r--drivers/hwmon/via686a.c538
-rw-r--r--drivers/hwmon/vt8231.c318
-rw-r--r--drivers/hwmon/w83627ehf.c615
-rw-r--r--drivers/hwmon/w83627hf.c153
-rw-r--r--drivers/i2c/algos/Kconfig4
-rw-r--r--drivers/i2c/busses/Kconfig36
-rw-r--r--drivers/i2c/busses/Makefile4
-rw-r--r--drivers/i2c/busses/i2c-acorn.c2
-rw-r--r--drivers/i2c/busses/i2c-gpio.c12
-rw-r--r--drivers/i2c/busses/i2c-i801.c249
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c3
-rw-r--r--drivers/i2c/busses/i2c-isa.c192
-rw-r--r--drivers/i2c/busses/i2c-mpc.c26
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c3
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c44
-rw-r--r--drivers/i2c/busses/i2c-piix4.c4
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c653
-rw-r--r--drivers/i2c/busses/i2c-powermac.c3
-rw-r--r--drivers/i2c/busses/i2c-pxa.c9
-rw-r--r--drivers/i2c/busses/i2c-rpx.c101
-rw-r--r--drivers/i2c/busses/i2c-savage4.c21
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c27
-rw-r--r--drivers/i2c/busses/i2c-taos-evm.c330
-rw-r--r--drivers/i2c/busses/i2c-viapro.c5
-rw-r--r--drivers/i2c/busses/scx200_acb.c16
-rw-r--r--drivers/i2c/chips/Kconfig45
-rw-r--r--drivers/i2c/chips/Makefile3
-rw-r--r--drivers/i2c/chips/ds1682.c259
-rw-r--r--drivers/i2c/chips/eeprom.c10
-rw-r--r--drivers/i2c/chips/max6875.c7
-rw-r--r--drivers/i2c/chips/menelaus.c1281
-rw-r--r--drivers/i2c/chips/tsl2550.c460
-rw-r--r--drivers/i2c/i2c-core.c27
-rw-r--r--drivers/i2c/i2c-dev.c9
-rw-r--r--drivers/ide/arm/icside.c2
-rw-r--r--drivers/ide/cris/ide-cris.c9
-rw-r--r--drivers/ide/ide-floppy.c47
-rw-r--r--drivers/ide/ide-io.c22
-rw-r--r--drivers/ide/ide-lib.c72
-rw-r--r--drivers/ide/ide-probe.c4
-rw-r--r--drivers/ide/ide-timing.h20
-rw-r--r--drivers/ide/ide.c86
-rw-r--r--drivers/ide/legacy/ali14xx.c7
-rw-r--r--drivers/ide/legacy/dtc2278.c3
-rw-r--r--drivers/ide/legacy/falconide.c2
-rw-r--r--drivers/ide/legacy/hd.c73
-rw-r--r--drivers/ide/legacy/ht6560b.c12
-rw-r--r--drivers/ide/legacy/ide-cs.c1
-rw-r--r--drivers/ide/legacy/qd65xx.c21
-rw-r--r--drivers/ide/legacy/umc8672.c4
-rw-r--r--drivers/ide/mips/au1xxx-ide.c4
-rw-r--r--drivers/ide/mips/swarm.c3
-rw-r--r--drivers/ide/pci/aec62xx.c18
-rw-r--r--drivers/ide/pci/alim15x3.c7
-rw-r--r--drivers/ide/pci/amd74xx.c32
-rw-r--r--drivers/ide/pci/atiixp.c37
-rw-r--r--drivers/ide/pci/cmd640.c19
-rw-r--r--drivers/ide/pci/cmd64x.c30
-rw-r--r--drivers/ide/pci/cs5520.c6
-rw-r--r--drivers/ide/pci/cs5530.c6
-rw-r--r--drivers/ide/pci/cs5535.c9
-rw-r--r--drivers/ide/pci/cy82c693.c5
-rw-r--r--drivers/ide/pci/generic.c15
-rw-r--r--drivers/ide/pci/hpt34x.c17
-rw-r--r--drivers/ide/pci/hpt366.c56
-rw-r--r--drivers/ide/pci/it8213.c7
-rw-r--r--drivers/ide/pci/it821x.c8
-rw-r--r--drivers/ide/pci/jmicron.c4
-rw-r--r--drivers/ide/pci/ns87415.c1
-rw-r--r--drivers/ide/pci/opti621.c8
-rw-r--r--drivers/ide/pci/pdc202xx_new.c23
-rw-r--r--drivers/ide/pci/pdc202xx_old.c20
-rw-r--r--drivers/ide/pci/piix.c14
-rw-r--r--drivers/ide/pci/rz1000.c1
-rw-r--r--drivers/ide/pci/sc1200.c43
-rw-r--r--drivers/ide/pci/scc_pata.c76
-rw-r--r--drivers/ide/pci/serverworks.c118
-rw-r--r--drivers/ide/pci/sgiioc4.c3
-rw-r--r--drivers/ide/pci/siimage.c139
-rw-r--r--drivers/ide/pci/sis5513.c12
-rw-r--r--drivers/ide/pci/sl82c105.c26
-rw-r--r--drivers/ide/pci/slc90e66.c4
-rw-r--r--drivers/ide/pci/tc86c001.c7
-rw-r--r--drivers/ide/pci/triflex.c4
-rw-r--r--drivers/ide/pci/trm290.c1
-rw-r--r--drivers/ide/pci/via82cxxx.c35
-rw-r--r--drivers/ide/ppc/mpc8xx.c5
-rw-r--r--drivers/ide/ppc/pmac.c16
-rw-r--r--drivers/ide/setup-pci.c18
-rw-r--r--drivers/ieee1394/eth1394.c2
-rw-r--r--drivers/ieee1394/ieee1394_core.c3
-rw-r--r--drivers/ieee1394/nodemgr.c3
-rw-r--r--drivers/ieee1394/sbp2.c75
-rw-r--r--drivers/infiniband/Kconfig15
-rw-r--r--drivers/infiniband/core/addr.c3
-rw-r--r--drivers/infiniband/core/agent.c19
-rw-r--r--drivers/infiniband/core/cm.c247
-rw-r--r--drivers/infiniband/core/cm_msgs.h1
-rw-r--r--drivers/infiniband/core/cma.c3
-rw-r--r--drivers/infiniband/core/mad.c51
-rw-r--r--drivers/infiniband/core/multicast.c2
-rw-r--r--drivers/infiniband/core/sa.h2
-rw-r--r--drivers/infiniband/core/sa_query.c87
-rw-r--r--drivers/infiniband/core/smi.c16
-rw-r--r--drivers/infiniband/core/smi.h2
-rw-r--r--drivers/infiniband/core/sysfs.c3
-rw-r--r--drivers/infiniband/core/ucm.c1
-rw-r--r--drivers/infiniband/core/umem.c1
-rw-r--r--drivers/infiniband/hw/amso1100/Kconfig2
-rw-r--r--drivers/infiniband/hw/amso1100/c2_vq.c2
-rw-r--r--drivers/infiniband/hw/cxgb3/Kconfig2
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c6
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_wr.h3
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c112
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.h1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c7
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c7
-rw-r--r--drivers/infiniband/hw/ehca/Kconfig2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_av.c10
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h163
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes_pSeries.h156
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c62
-rw-r--r--drivers/infiniband/hw/ehca/ehca_eq.c11
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c87
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c232
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.h1
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h25
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c181
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c1354
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.h23
-rw-r--r--drivers/infiniband/hw/ehca/ehca_pd.c27
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qes.h22
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c874
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c100
-rw-r--r--drivers/infiniband/hw/ehca/ehca_tools.h45
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c25
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.c112
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.h1
-rw-r--r--drivers/infiniband/hw/ehca/hcp_phyp.c2
-rw-r--r--drivers/infiniband/hw/ehca/hipz_fns_core.h4
-rw-r--r--drivers/infiniband/hw/ehca/hipz_hw.h41
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.c222
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.h58
-rw-r--r--drivers/infiniband/hw/ipath/Kconfig2
-rw-r--r--drivers/infiniband/hw/ipath/Makefile1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h33
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_debug.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c41
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c196
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c303
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c205
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c9
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c101
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c92
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c26
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c143
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h87
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.c365
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.h71
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c11
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mmap.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mr.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c19
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c116
-rw-r--r--drivers/infiniband/hw/ipath/ipath_registers.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c38
-rw-r--r--drivers/infiniband/hw/ipath/ipath_srq.c4
-rw-r--r--drivers/infiniband/hw/ipath/ipath_stats.c25
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c43
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c9
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c28
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c31
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h9
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs_mcast.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_ppc64.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_x86_64.c29
-rw-r--r--drivers/infiniband/hw/mlx4/Kconfig1
-rw-r--r--drivers/infiniband/hw/mlx4/main.c6
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h4
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c250
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c18
-rw-r--r--drivers/infiniband/hw/mthca/Kconfig2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_allocator.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c3
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c22
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c221
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c28
-rw-r--r--drivers/infiniband/hw/mthca/mthca_wqe.h15
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c33
-rw-r--r--drivers/infiniband/ulp/iser/Kconfig2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c42
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h9
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c14
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c4
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c51
-rw-r--r--drivers/infiniband/ulp/srp/Kconfig2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c63
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h5
-rw-r--r--drivers/input/gameport/gameport.c1
-rw-r--r--drivers/input/input.c29
-rw-r--r--drivers/input/joystick/Kconfig7
-rw-r--r--drivers/input/joystick/xpad.c190
-rw-r--r--drivers/input/misc/pcspkr.c11
-rw-r--r--drivers/input/mouse/appletouch.c111
-rw-r--r--drivers/input/mouse/lifebook.c2
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/serio/ambakmi.c6
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h36
-rw-r--r--drivers/input/serio/pcips2.c6
-rw-r--r--drivers/input/serio/sa1111ps2.c6
-rw-r--r--drivers/input/serio/serio.c1
-rw-r--r--drivers/input/touchscreen/Kconfig13
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ads7846.c80
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c189
-rw-r--r--drivers/input/touchscreen/ucb1400_ts.c1
-rw-r--r--drivers/isdn/Kconfig27
-rw-r--r--drivers/isdn/act2000/Kconfig2
-rw-r--r--drivers/isdn/capi/Kconfig7
-rw-r--r--drivers/isdn/capi/capi.c2
-rw-r--r--drivers/isdn/capi/kcapi.c6
-rw-r--r--drivers/isdn/capi/kcapi_proc.c28
-rw-r--r--drivers/isdn/gigaset/Kconfig10
-rw-r--r--drivers/isdn/hardware/Kconfig1
-rw-r--r--drivers/isdn/hardware/avm/Kconfig23
-rw-r--r--drivers/isdn/hardware/eicon/Kconfig22
-rw-r--r--drivers/isdn/hardware/eicon/idifunc.c1
-rw-r--r--drivers/isdn/hisax/Kconfig1
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c108
-rw-r--r--drivers/isdn/hisax/bkm_a8.c4
-rw-r--r--drivers/isdn/hisax/config.c245
-rw-r--r--drivers/isdn/hisax/enternow_pci.c165
-rw-r--r--drivers/isdn/hisax/hfc_pci.c191
-rw-r--r--drivers/isdn/hisax/nj_s.c194
-rw-r--r--drivers/isdn/hisax/nj_u.c167
-rw-r--r--drivers/isdn/hisax/sedlbauer.c8
-rw-r--r--drivers/isdn/i4l/Kconfig4
-rw-r--r--drivers/isdn/icn/Kconfig2
-rw-r--r--drivers/isdn/pcbit/Kconfig2
-rw-r--r--drivers/isdn/sc/Kconfig2
-rw-r--r--drivers/isdn/sc/card.h2
-rw-r--r--drivers/isdn/sc/command.c2
-rw-r--r--drivers/isdn/sc/timer.c2
-rw-r--r--drivers/kvm/Kconfig9
-rw-r--r--drivers/kvm/kvm.h126
-rw-r--r--drivers/kvm/kvm_main.c530
-rw-r--r--drivers/kvm/mmu.c396
-rw-r--r--drivers/kvm/paging_tmpl.h275
-rw-r--r--drivers/kvm/svm.c59
-rw-r--r--drivers/kvm/svm.h3
-rw-r--r--drivers/kvm/vmx.c652
-rw-r--r--drivers/kvm/x86_emulate.c70
-rw-r--r--drivers/leds/Kconfig22
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/led-class.c49
-rw-r--r--drivers/leds/led-triggers.c27
-rw-r--r--drivers/leds/leds-gpio.c199
-rw-r--r--drivers/leds/leds-locomo.c2
-rw-r--r--drivers/leds/leds.h8
-rw-r--r--drivers/leds/ledtrig-timer.c49
-rw-r--r--drivers/lguest/Kconfig20
-rw-r--r--drivers/lguest/Makefile7
-rw-r--r--drivers/lguest/core.c462
-rw-r--r--drivers/lguest/hypercalls.c192
-rw-r--r--drivers/lguest/interrupts_and_traps.c268
-rw-r--r--drivers/lguest/io.c399
-rw-r--r--drivers/lguest/lg.h261
-rw-r--r--drivers/lguest/lguest.c630
-rw-r--r--drivers/lguest/lguest_asm.S54
-rw-r--r--drivers/lguest/lguest_bus.c148
-rw-r--r--drivers/lguest/lguest_user.c236
-rw-r--r--drivers/lguest/page_tables.c411
-rw-r--r--drivers/lguest/segments.c125
-rw-r--r--drivers/lguest/switcher.S159
-rw-r--r--drivers/macintosh/adb.c10
-rw-r--r--drivers/macintosh/macio_asic.c3
-rw-r--r--drivers/macintosh/rack-meter.c1
-rw-r--r--drivers/macintosh/smu.c3
-rw-r--r--drivers/macintosh/therm_adt746x.c1
-rw-r--r--drivers/macintosh/therm_pm72.c6
-rw-r--r--drivers/macintosh/therm_windtunnel.c3
-rw-r--r--drivers/macintosh/windfarm_core.c6
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c3
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c28
-rw-r--r--drivers/md/Kconfig23
-rw-r--r--drivers/md/Makefile6
-rw-r--r--drivers/md/bitmap.c169
-rw-r--r--drivers/md/dm-bio-list.h4
-rw-r--r--drivers/md/dm-crypt.c35
-rw-r--r--drivers/md/dm-delay.c23
-rw-r--r--drivers/md/dm-exception-store.c77
-rw-r--r--drivers/md/dm-io.c5
-rw-r--r--drivers/md/dm-mpath-rdac.c700
-rw-r--r--drivers/md/dm-mpath.c34
-rw-r--r--drivers/md/dm-raid1.c78
-rw-r--r--drivers/md/dm-round-robin.c2
-rw-r--r--drivers/md/dm-snap.c116
-rw-r--r--drivers/md/dm-snap.h6
-rw-r--r--drivers/md/dm.c37
-rw-r--r--drivers/md/dm.h40
-rw-r--r--drivers/md/kcopyd.c11
-rw-r--r--drivers/md/md.c73
-rw-r--r--drivers/md/raid1.c3
-rw-r--r--drivers/md/raid10.c3
-rw-r--r--drivers/md/raid5.c2731
-rw-r--r--drivers/media/Kconfig4
-rw-r--r--drivers/media/common/ir-functions.c27
-rw-r--r--drivers/media/common/saa7146_core.c8
-rw-r--r--drivers/media/common/saa7146_video.c8
-rw-r--r--drivers/media/dvb/b2c2/Kconfig2
-rw-r--r--drivers/media/dvb/b2c2/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c4
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--drivers/media/dvb/bt8xx/Makefile2
-rw-r--r--drivers/media/dvb/bt8xx/dst.c2
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c5
-rw-r--r--drivers/media/dvb/cinergyT2/Makefile2
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c22
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c12
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c5
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c10
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig29
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile8
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-fe.c1503
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-remote.c157
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-script.h203
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c1141
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.h3496
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c18
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c53
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h1
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c21
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c79
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h6
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h11
-rw-r--r--drivers/media/dvb/dvb-usb/gl861.c7
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c127
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.h5
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c25
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c8
-rw-r--r--drivers/media/dvb/frontends/Makefile2
-rw-r--r--drivers/media/dvb/frontends/cx22702.c1
-rw-r--r--drivers/media/dvb/frontends/cx24123.c2
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c256
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h73
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c23
-rw-r--r--drivers/media/dvb/frontends/nxt200x.h3
-rw-r--r--drivers/media/dvb/frontends/or51132.c1
-rw-r--r--drivers/media/dvb/frontends/or51211.c31
-rw-r--r--drivers/media/dvb/frontends/stv0299.c2
-rw-r--r--drivers/media/dvb/frontends/tda10023.c2
-rw-r--r--drivers/media/dvb/pluto2/Makefile2
-rw-r--r--drivers/media/dvb/ttpci/Kconfig2
-rw-r--r--drivers/media/dvb/ttpci/Makefile2
-rw-r--r--drivers/media/dvb/ttpci/av7110.c15
-rw-r--r--drivers/media/dvb/ttpci/av7110.h1
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c20
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c4
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c8
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.h2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c31
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/dvb/ttusb-budget/Makefile2
-rw-r--r--drivers/media/dvb/ttusb-dec/Makefile2
-rw-r--r--drivers/media/radio/Kconfig4
-rw-r--r--drivers/media/radio/radio-aimslab.c3
-rw-r--r--drivers/media/radio/radio-aztech.c1
-rw-r--r--drivers/media/radio/radio-cadet.c4
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c8
-rw-r--r--drivers/media/radio/radio-gemtek.c1
-rw-r--r--drivers/media/radio/radio-rtrack2.c1
-rw-r--r--drivers/media/radio/radio-sf16fmi.c1
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c1
-rw-r--r--drivers/media/radio/radio-terratec.c1
-rw-r--r--drivers/media/radio/radio-trust.c1
-rw-r--r--drivers/media/radio/radio-typhoon.c1
-rw-r--r--drivers/media/video/Kconfig9
-rw-r--r--drivers/media/video/Makefile6
-rw-r--r--drivers/media/video/adv7170.c8
-rw-r--r--drivers/media/video/adv7175.c8
-rw-r--r--drivers/media/video/bt819.c9
-rw-r--r--drivers/media/video/bt856.c8
-rw-r--r--drivers/media/video/bt866.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c444
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c34
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c4
-rw-r--r--drivers/media/video/bt8xx/bttv.h2
-rw-r--r--drivers/media/video/bt8xx/bttvp.h6
-rw-r--r--drivers/media/video/c-qcam.c4
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c13
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c8
-rw-r--r--drivers/media/video/cx88/Kconfig2
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c14
-rw-r--r--drivers/media/video/cx88/cx88-cards.c24
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c122
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c25
-rw-r--r--drivers/media/video/cx88/cx88-input.c25
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c2
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c1
-rw-r--r--drivers/media/video/cx88/cx88-video.c8
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c12
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.h7
-rw-r--r--drivers/media/video/cx88/cx88.h8
-rw-r--r--drivers/media/video/et61x251/Kconfig2
-rw-r--r--drivers/media/video/et61x251/et61x251.h23
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c189
-rw-r--r--drivers/media/video/et61x251/et61x251_sensor.h8
-rw-r--r--drivers/media/video/et61x251/et61x251_tas5130d1b.c2
-rw-r--r--drivers/media/video/ir-kbd-i2c.c53
-rw-r--r--drivers/media/video/ivtv/Kconfig5
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c54
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h21
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c14
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c29
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c11
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c20
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c47
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c33
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c45
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c31
-rw-r--r--drivers/media/video/meye.c4
-rw-r--r--drivers/media/video/msp3400-driver.c9
-rw-r--r--drivers/media/video/msp3400-kthreads.c6
-rw-r--r--drivers/media/video/mt20xx.c80
-rw-r--r--drivers/media/video/ov7670.c4
-rw-r--r--drivers/media/video/planb.c3
-rw-r--r--drivers/media/video/pwc/pwc-if.c12
-rw-r--r--drivers/media/video/pwc/pwc.h4
-rw-r--r--drivers/media/video/saa5249.c8
-rw-r--r--drivers/media/video/saa7110.c4
-rw-r--r--drivers/media/video/saa7111.c8
-rw-r--r--drivers/media/video/saa7114.c10
-rw-r--r--drivers/media/video/saa7134/Kconfig2
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c16
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c41
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c169
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c8
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c20
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c42
-rw-r--r--drivers/media/video/saa7134/saa7134.h8
-rw-r--r--drivers/media/video/saa7185.c8
-rw-r--r--drivers/media/video/sn9c102/sn9c102.h9
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c173
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7630.c214
-rw-r--r--drivers/media/video/sn9c102/sn9c102_ov7660.c88
-rw-r--r--drivers/media/video/stradis.c2
-rw-r--r--drivers/media/video/stv680.c7
-rw-r--r--drivers/media/video/tda8290.c129
-rw-r--r--drivers/media/video/tda9887.c57
-rw-r--r--drivers/media/video/tea5761.c243
-rw-r--r--drivers/media/video/tea5767.c16
-rw-r--r--drivers/media/video/tuner-core.c95
-rw-r--r--drivers/media/video/tuner-driver.h107
-rw-r--r--drivers/media/video/tuner-simple.c27
-rw-r--r--drivers/media/video/tuner-types.c22
-rw-r--r--drivers/media/video/tvaudio.c6
-rw-r--r--drivers/media/video/tveeprom.c8
-rw-r--r--drivers/media/video/tvp5150.c2
-rw-r--r--drivers/media/video/usbvideo/konicawc.c2
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c4
-rw-r--r--drivers/media/video/usbvideo/vicam.c184
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c8
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c43
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c1561
-rw-r--r--drivers/media/video/usbvision/usbvision.h13
-rw-r--r--drivers/media/video/v4l2-common.c19
-rw-r--r--drivers/media/video/video-buf-dvb.c1
-rw-r--r--drivers/media/video/vino.c6
-rw-r--r--drivers/media/video/vivi.c179
-rw-r--r--drivers/media/video/wm8739.c2
-rw-r--r--drivers/media/video/wm8775.c2
-rw-r--r--drivers/media/video/zc0301/Kconfig2
-rw-r--r--drivers/media/video/zc0301/zc0301.h21
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c147
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c1
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c1
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h2
-rw-r--r--drivers/media/video/zoran_driver.c63
-rw-r--r--drivers/media/video/zr364xx.c18
-rw-r--r--drivers/message/fusion/Kconfig1
-rw-r--r--drivers/message/fusion/linux_compat.h9
-rw-r--r--drivers/message/fusion/lsi/mpi.h7
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h61
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt66
-rw-r--r--drivers/message/fusion/lsi/mpi_inb.h221
-rw-r--r--drivers/message/fusion/lsi/mpi_init.h10
-rw-r--r--drivers/message/fusion/lsi/mpi_ioc.h40
-rw-r--r--drivers/message/fusion/lsi/mpi_raid.h11
-rw-r--r--drivers/message/fusion/mptbase.c422
-rw-r--r--drivers/message/fusion/mptbase.h15
-rw-r--r--drivers/message/fusion/mptctl.c2
-rw-r--r--drivers/message/fusion/mptctl.h2
-rw-r--r--drivers/message/fusion/mptfc.c6
-rw-r--r--drivers/message/fusion/mptlan.c2
-rw-r--r--drivers/message/fusion/mptlan.h2
-rw-r--r--drivers/message/fusion/mptsas.c74
-rw-r--r--drivers/message/fusion/mptscsih.c417
-rw-r--r--drivers/message/fusion/mptscsih.h3
-rw-r--r--drivers/message/fusion/mptspi.c12
-rw-r--r--drivers/message/i2o/Kconfig22
-rw-r--r--drivers/message/i2o/debug.c134
-rw-r--r--drivers/message/i2o/device.c18
-rw-r--r--drivers/message/i2o/exec-osm.c10
-rw-r--r--drivers/message/i2o/i2o_block.c5
-rw-r--r--drivers/message/i2o/i2o_config.c62
-rw-r--r--drivers/message/i2o/i2o_scsi.c24
-rw-r--r--drivers/message/i2o/iop.c2
-rw-r--r--drivers/mfd/mcp-core.c3
-rw-r--r--drivers/mfd/ucb1x00-core.c3
-rw-r--r--drivers/mfd/ucb1x00-ts.c1
-rw-r--r--drivers/misc/Kconfig24
-rw-r--r--drivers/misc/asus-laptop.c6
-rw-r--r--drivers/misc/ibmasm/command.c20
-rw-r--r--drivers/misc/ibmasm/dot_command.c10
-rw-r--r--drivers/misc/ibmasm/dot_command.h2
-rw-r--r--drivers/misc/ibmasm/event.c8
-rw-r--r--drivers/misc/ibmasm/heartbeat.c2
-rw-r--r--drivers/misc/ibmasm/i2o.h10
-rw-r--r--drivers/misc/ibmasm/ibmasm.h70
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c27
-rw-r--r--drivers/misc/ibmasm/lowlevel.c2
-rw-r--r--drivers/misc/ibmasm/lowlevel.h16
-rw-r--r--drivers/misc/ibmasm/module.c13
-rw-r--r--drivers/misc/ibmasm/r_heartbeat.c10
-rw-r--r--drivers/misc/ibmasm/remote.c37
-rw-r--r--drivers/misc/ibmasm/remote.h8
-rw-r--r--drivers/misc/ibmasm/uart.c2
-rw-r--r--drivers/misc/msi-laptop.c44
-rw-r--r--drivers/misc/sony-laptop.c371
-rw-r--r--drivers/misc/thinkpad_acpi.c602
-rw-r--r--drivers/misc/thinkpad_acpi.h42
-rw-r--r--drivers/mmc/card/block.c3
-rw-r--r--drivers/mmc/card/queue.c7
-rw-r--r--drivers/mmc/host/at91_mci.c13
-rw-r--r--drivers/mmc/host/pxamci.h22
-rw-r--r--drivers/mmc/host/sdhci.c2
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/mtd/mtd_blkdevs.c3
-rw-r--r--drivers/mtd/ubi/build.c25
-rw-r--r--drivers/mtd/ubi/cdev.c49
-rw-r--r--drivers/mtd/ubi/debug.c44
-rw-r--r--drivers/mtd/ubi/debug.h2
-rw-r--r--drivers/mtd/ubi/eba.c104
-rw-r--r--drivers/mtd/ubi/gluebi.c27
-rw-r--r--drivers/mtd/ubi/io.c65
-rw-r--r--drivers/mtd/ubi/kapi.c19
-rw-r--r--drivers/mtd/ubi/misc.c4
-rw-r--r--drivers/mtd/ubi/scan.c127
-rw-r--r--drivers/mtd/ubi/scan.h2
-rw-r--r--drivers/mtd/ubi/ubi.h3
-rw-r--r--drivers/mtd/ubi/upd.c4
-rw-r--r--drivers/mtd/ubi/vmt.c53
-rw-r--r--drivers/mtd/ubi/vtbl.c85
-rw-r--r--drivers/mtd/ubi/wl.c96
-rw-r--r--drivers/net/3c523.c2
-rw-r--r--drivers/net/7990.c4
-rw-r--r--drivers/net/8139cp.c34
-rw-r--r--drivers/net/8139too.c9
-rw-r--r--drivers/net/Kconfig114
-rw-r--r--drivers/net/Makefile9
-rw-r--r--drivers/net/Space.c8
-rw-r--r--drivers/net/a2065.c4
-rw-r--r--drivers/net/ariadne.c2
-rw-r--r--drivers/net/arm/Kconfig1
-rw-r--r--drivers/net/arm/ep93xx_eth.c2
-rw-r--r--drivers/net/arm/ether1.c3
-rw-r--r--drivers/net/arm/ether3.c5
-rw-r--r--drivers/net/arm/etherh.c1
-rw-r--r--drivers/net/atari_bionet.c675
-rw-r--r--drivers/net/atari_pamsnet.c878
-rw-r--r--drivers/net/atl1/atl1.h157
-rw-r--r--drivers/net/atl1/atl1_main.c2181
-rw-r--r--drivers/net/au1000_eth.c4
-rw-r--r--drivers/net/ax88796.c4
-rw-r--r--drivers/net/b44.c3
-rw-r--r--drivers/net/bfin_mac.c1009
-rw-r--r--drivers/net/bfin_mac.h132
-rw-r--r--drivers/net/bnx2.c608
-rw-r--r--drivers/net/bnx2.h76
-rw-r--r--drivers/net/bsd_comp.c3
-rw-r--r--drivers/net/cassini.c12
-rw-r--r--drivers/net/cxgb3/version.h2
-rw-r--r--drivers/net/dl2k.c7
-rw-r--r--drivers/net/dl2k.h1
-rw-r--r--drivers/net/dm9000.c17
-rw-r--r--drivers/net/dummy.c82
-rw-r--r--drivers/net/e100.c8
-rw-r--r--drivers/net/e1000/e1000_main.c3
-rw-r--r--drivers/net/eepro100.c9
-rw-r--r--drivers/net/ehea/ehea.h23
-rw-r--r--drivers/net/ehea/ehea_main.c181
-rw-r--r--drivers/net/ehea/ehea_phyp.h3
-rw-r--r--drivers/net/ehea/ehea_qmr.c156
-rw-r--r--drivers/net/ehea/ehea_qmr.h14
-rw-r--r--drivers/net/epic100.c2
-rw-r--r--drivers/net/fealnx.c4
-rw-r--r--drivers/net/fec.c2
-rw-r--r--drivers/net/forcedeth.c172
-rw-r--r--drivers/net/gianfar.c12
-rw-r--r--drivers/net/gianfar_mii.c1
-rw-r--r--drivers/net/hamachi.c4
-rw-r--r--drivers/net/hamradio/baycom_epp.c2
-rw-r--r--drivers/net/hamradio/dmascc.c6
-rw-r--r--drivers/net/ibmveth.c2
-rw-r--r--drivers/net/ifb.c78
-rw-r--r--drivers/net/irda/Kconfig11
-rw-r--r--drivers/net/irda/Makefile1
-rw-r--r--drivers/net/irda/ep7211-sir.c89
-rw-r--r--drivers/net/irda/irport.c3
-rw-r--r--drivers/net/irda/irtty-sir.c3
-rw-r--r--drivers/net/irda/kingsun-sir.c4
-rw-r--r--drivers/net/irda/vlsi_ir.c27
-rw-r--r--drivers/net/irda/vlsi_ir.h2
-rw-r--r--drivers/net/iseries_veth.c6
-rw-r--r--drivers/net/ixp2000/ixpdev.c2
-rw-r--r--drivers/net/lance.c7
-rw-r--r--drivers/net/lguest_net.c354
-rw-r--r--drivers/net/mac89x0.c2
-rw-r--r--drivers/net/macb.c563
-rw-r--r--drivers/net/macb.h10
-rw-r--r--drivers/net/macvlan.c496
-rw-r--r--drivers/net/mlx4/catas.c106
-rw-r--r--drivers/net/mlx4/cmd.c3
-rw-r--r--drivers/net/mlx4/eq.c56
-rw-r--r--drivers/net/mlx4/fw.c3
-rw-r--r--drivers/net/mlx4/fw.h1
-rw-r--r--drivers/net/mlx4/intf.c2
-rw-r--r--drivers/net/mlx4/main.c27
-rw-r--r--drivers/net/mlx4/mlx4.h14
-rw-r--r--drivers/net/mlx4/qp.c21
-rw-r--r--drivers/net/mlx4/srq.c30
-rw-r--r--drivers/net/myri10ge/myri10ge.c6
-rw-r--r--drivers/net/natsemi.c6
-rw-r--r--drivers/net/ne2k-pci.c7
-rw-r--r--drivers/net/netxen/netxen_nic_main.c7
-rw-r--r--drivers/net/ni5010.c6
-rw-r--r--drivers/net/ni52.c2
-rw-r--r--drivers/net/ni65.c4
-rw-r--r--drivers/net/ns83820.c2
-rw-r--r--drivers/net/pci-skeleton.c2
-rw-r--r--drivers/net/pcmcia/com20020_cs.c3
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c3
-rw-r--r--drivers/net/pcnet32.c4
-rw-r--r--drivers/net/phy/vitesse.c46
-rw-r--r--drivers/net/ppp_async.c3
-rw-r--r--drivers/net/ppp_deflate.c6
-rw-r--r--drivers/net/ppp_generic.c3
-rw-r--r--drivers/net/ppp_mppe.c3
-rw-r--r--drivers/net/ppp_synctty.c3
-rw-r--r--drivers/net/pppol2tp.c2496
-rw-r--r--drivers/net/r8169.c2
-rw-r--r--drivers/net/s2io.c29
-rw-r--r--drivers/net/s2io.h1
-rw-r--r--drivers/net/saa9730.c13
-rw-r--r--drivers/net/sgiseeq.c2
-rw-r--r--drivers/net/shaper.c3
-rw-r--r--drivers/net/sis190.c2
-rw-r--r--drivers/net/sky2.c7
-rw-r--r--drivers/net/starfire.c4
-rw-r--r--drivers/net/sun3_82586.c2
-rw-r--r--drivers/net/sun3lance.c5
-rw-r--r--drivers/net/sunbmac.c2
-rw-r--r--drivers/net/sundance.c9
-rw-r--r--drivers/net/sunhme.c8
-rw-r--r--drivers/net/sunlance.c4
-rw-r--r--drivers/net/sunqe.c4
-rw-r--r--drivers/net/sunvnet.c1295
-rw-r--r--drivers/net/sunvnet.h83
-rw-r--r--drivers/net/tc35815.c2
-rw-r--r--drivers/net/tg3.c258
-rw-r--r--drivers/net/tg3.h10
-rw-r--r--drivers/net/tlan.c5
-rw-r--r--drivers/net/tokenring/smctr.c6
-rw-r--r--drivers/net/tulip/de4x5.c8
-rw-r--r--drivers/net/tulip/dmfe.c26
-rw-r--r--drivers/net/tulip/interrupt.c8
-rw-r--r--drivers/net/tulip/tulip_core.c15
-rw-r--r--drivers/net/tulip/winbond-840.c2
-rw-r--r--drivers/net/tulip/xircom_cb.c7
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c8
-rw-r--r--drivers/net/tun.c15
-rw-r--r--drivers/net/typhoon.c9
-rw-r--r--drivers/net/usb/catc.c2
-rw-r--r--drivers/net/usb/cdc_subset.c3
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/via-rhine.c17
-rw-r--r--drivers/net/via-velocity.c3
-rw-r--r--drivers/net/wan/Kconfig2
-rw-r--r--drivers/net/wan/c101.c3
-rw-r--r--drivers/net/wan/cosa.c4
-rw-r--r--drivers/net/wan/cycx_main.c4
-rw-r--r--drivers/net/wan/cycx_x25.c3
-rw-r--r--drivers/net/wan/dscc4.c6
-rw-r--r--drivers/net/wan/farsync.c3
-rw-r--r--drivers/net/wan/hostess_sv11.c3
-rw-r--r--drivers/net/wan/n2.c3
-rw-r--r--drivers/net/wan/pc300_drv.c9
-rw-r--r--drivers/net/wan/pc300too.c5
-rw-r--r--drivers/net/wan/pci200syn.c5
-rw-r--r--drivers/net/wan/sbni.c7
-rw-r--r--drivers/net/wan/sdla.c3
-rw-r--r--drivers/net/wan/sealevel.c3
-rw-r--r--drivers/net/wan/wanxl.c3
-rw-r--r--drivers/net/wan/x25_asy.c4
-rw-r--r--drivers/net/wireless/airo.c211
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c6
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c3
-rw-r--r--drivers/net/wireless/ipw2100.c17
-rw-r--r--drivers/net/wireless/ipw2200.c23
-rw-r--r--drivers/net/wireless/libertas/cmd.c2
-rw-r--r--drivers/net/wireless/libertas/main.c1
-rw-r--r--drivers/net/wireless/libertas/rx.c1
-rw-r--r--drivers/net/wireless/libertas/version.h1
-rw-r--r--drivers/net/wireless/libertas/wext.c3
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c22
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c4
-rw-r--r--drivers/net/wireless/rtl8187_rtl8225.c4
-rw-r--r--drivers/net/wireless/wl3501_cs.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c88
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h13
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c59
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c3
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c12
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_uw2453.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c102
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h3
-rw-r--r--drivers/net/xen-netfront.c1863
-rw-r--r--drivers/net/yellowfin.c2
-rw-r--r--drivers/nubus/nubus.c6
-rw-r--r--drivers/of/Kconfig3
-rw-r--r--drivers/of/Makefile2
-rw-r--r--drivers/of/base.c275
-rw-r--r--drivers/of/device.c131
-rw-r--r--drivers/of/platform.c96
-rw-r--r--drivers/oprofile/buffer_sync.c3
-rw-r--r--drivers/oprofile/event_buffer.h20
-rw-r--r--drivers/oprofile/oprof.c28
-rw-r--r--drivers/parisc/hppb.c1
-rw-r--r--drivers/parisc/pdc_stable.c4
-rw-r--r--drivers/parisc/superio.c1
-rw-r--r--drivers/parport/Kconfig26
-rw-r--r--drivers/parport/parport_cs.c3
-rw-r--r--drivers/parport/parport_pc.c5
-rw-r--r--drivers/parport/parport_serial.c3
-rw-r--r--drivers/pci/Makefile4
-rw-r--r--drivers/pci/hotplug/acpiphp.h1
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c6
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c53
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c7
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c66
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c2
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c12
-rw-r--r--drivers/pci/hotplug/pciehp.h1
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c12
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c191
-rw-r--r--drivers/pci/hotplug/rpadlpar_core.c6
-rw-r--r--drivers/pci/pci-acpi.c8
-rw-r--r--drivers/pci/pci-sysfs.c35
-rw-r--r--drivers/pci/pci.c200
-rw-r--r--drivers/pci/pcie/aer/Kconfig2
-rw-r--r--drivers/pci/pcie/aer/Makefile3
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c5
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h14
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c36
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c34
-rw-r--r--drivers/pci/probe.c17
-rw-r--r--drivers/pci/proc.c3
-rw-r--r--drivers/pci/quirks.c30
-rw-r--r--drivers/pci/rom.c73
-rw-r--r--drivers/pci/search.c11
-rw-r--r--drivers/pci/setup-bus.c8
-rw-r--r--drivers/pci/syscall.c20
-rw-r--r--drivers/pcmcia/Kconfig17
-rw-r--r--drivers/pcmcia/cs.c1
-rw-r--r--drivers/pcmcia/ds.c40
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c829
-rw-r--r--drivers/pcmcia/socket_sysfs.c10
-rw-r--r--drivers/pnp/Kconfig13
-rw-r--r--drivers/pnp/core.c3
-rw-r--r--drivers/pnp/isapnp/Kconfig2
-rw-r--r--drivers/pnp/isapnp/core.c2
-rw-r--r--drivers/pnp/pnpbios/Kconfig2
-rw-r--r--drivers/pnp/pnpbios/core.c3
-rw-r--r--drivers/power/Kconfig1
-rw-r--r--drivers/power/apm_power.c4
-rw-r--r--drivers/power/ds2760_battery.c7
-rw-r--r--drivers/power/olpc_battery.c1
-rw-r--r--drivers/power/pda_power.c22
-rw-r--r--drivers/power/pmu_battery.c2
-rw-r--r--drivers/power/power_supply_core.c6
-rw-r--r--drivers/power/power_supply_leds.c8
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/ps3/Makefile5
-rw-r--r--drivers/ps3/ps3av.c372
-rw-r--r--drivers/ps3/ps3av_cmd.c51
-rw-r--r--drivers/ps3/ps3stor_lib.c302
-rw-r--r--drivers/ps3/sys-manager-core.c68
-rw-r--r--drivers/ps3/sys-manager.c290
-rw-r--r--drivers/ps3/vuart.c817
-rw-r--r--drivers/ps3/vuart.h71
-rw-r--r--drivers/rapidio/rio-scan.c6
-rw-r--r--drivers/rapidio/rio-sysfs.c7
-rw-r--r--drivers/rtc/Kconfig81
-rw-r--r--drivers/rtc/Makefile5
-rw-r--r--drivers/rtc/rtc-at32ap700x.c317
-rw-r--r--drivers/rtc/rtc-cmos.c33
-rw-r--r--drivers/rtc/rtc-dev.c2
-rw-r--r--drivers/rtc/rtc-ds1216.c226
-rw-r--r--drivers/rtc/rtc-ds1307.c300
-rw-r--r--drivers/rtc/rtc-ds1553.c13
-rw-r--r--drivers/rtc/rtc-ds1742.c13
-rw-r--r--drivers/rtc/rtc-m41t80.c917
-rw-r--r--drivers/rtc/rtc-m48t59.c491
-rw-r--r--drivers/rtc/rtc-max6900.c96
-rw-r--r--drivers/rtc/rtc-rs5c372.c95
-rw-r--r--drivers/rtc/rtc-stk17ta8.c420
-rw-r--r--drivers/rtc/rtc-vr41xx.c186
-rw-r--r--drivers/rtc/rtc-x1205.c5
-rw-r--r--drivers/s390/block/dasd_devmap.c2
-rw-r--r--drivers/s390/block/dcssblk.c7
-rw-r--r--drivers/s390/char/Kconfig7
-rw-r--r--drivers/s390/char/Makefile1
-rw-r--r--drivers/s390/char/tape_34xx.c3
-rw-r--r--drivers/s390/char/vmcp.c89
-rw-r--r--drivers/s390/char/vmcp.h4
-rw-r--r--drivers/s390/char/vmur.c906
-rw-r--r--drivers/s390/char/vmur.h104
-rw-r--r--drivers/s390/cio/chp.c12
-rw-r--r--drivers/s390/cio/device.c2
-rw-r--r--drivers/s390/cio/qdio.c16
-rw-r--r--drivers/s390/net/claw.c9
-rw-r--r--drivers/s390/net/qeth.h9
-rw-r--r--drivers/s390/net/qeth_main.c183
-rw-r--r--drivers/s390/net/qeth_proc.c6
-rw-r--r--drivers/s390/net/qeth_sys.c2
-rw-r--r--drivers/s390/scsi/zfcp_aux.c35
-rw-r--r--drivers/s390/scsi/zfcp_def.h1
-rw-r--r--drivers/s390/scsi/zfcp_erp.c10
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c2
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c113
-rw-r--r--drivers/sbus/char/bbc_envctrl.c5
-rw-r--r--drivers/sbus/char/bbc_i2c.c3
-rw-r--r--drivers/sbus/char/cpwatchdog.c1
-rw-r--r--drivers/sbus/char/envctrl.c7
-rw-r--r--drivers/sbus/char/jsflash.c3
-rw-r--r--drivers/sbus/char/vfc_dev.c5
-rw-r--r--drivers/sbus/sbus.c5
-rw-r--r--drivers/scsi/3w-9xxx.c205
-rw-r--r--drivers/scsi/3w-9xxx.h5
-rw-r--r--drivers/scsi/3w-xxxx.c104
-rw-r--r--drivers/scsi/53c700.c77
-rw-r--r--drivers/scsi/53c700.h5
-rw-r--r--drivers/scsi/53c7xx.c6102
-rw-r--r--drivers/scsi/53c7xx.h1608
-rw-r--r--drivers/scsi/53c7xx.scr1591
-rw-r--r--drivers/scsi/53c7xx_d.h_shipped2874
-rw-r--r--drivers/scsi/53c7xx_u.h_shipped102
-rw-r--r--drivers/scsi/BusLogic.c51
-rw-r--r--drivers/scsi/Kconfig70
-rw-r--r--drivers/scsi/Makefile24
-rw-r--r--drivers/scsi/NCR5380.c14
-rw-r--r--drivers/scsi/NCR5380.h6
-rw-r--r--drivers/scsi/NCR53C9x.c10
-rw-r--r--drivers/scsi/NCR53c406a.c45
-rw-r--r--drivers/scsi/NCR_D700.c3
-rw-r--r--drivers/scsi/NCR_Q720.c3
-rw-r--r--drivers/scsi/a100u2w.c1239
-rw-r--r--drivers/scsi/a100u2w.h297
-rw-r--r--drivers/scsi/a4000t.c144
-rw-r--r--drivers/scsi/aacraid/aachba.c462
-rw-r--r--drivers/scsi/aacraid/aacraid.h54
-rw-r--r--drivers/scsi/aacraid/commsup.c226
-rw-r--r--drivers/scsi/aacraid/linit.c104
-rw-r--r--drivers/scsi/aacraid/rx.c33
-rw-r--r--drivers/scsi/advansys.c101
-rw-r--r--drivers/scsi/advansys.h36
-rw-r--r--drivers/scsi/aha152x.c50
-rw-r--r--drivers/scsi/aha1740.c48
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c51
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h4
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c59
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h4
-rw-r--r--drivers/scsi/aic7xxx_old.c57
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c16
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c20
-rw-r--r--drivers/scsi/amiga7xx.c138
-rw-r--r--drivers/scsi/amiga7xx.h23
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h4
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c18
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c559
-rw-r--r--drivers/scsi/arm/cumana_1.c207
-rw-r--r--drivers/scsi/arm/ecoscsi.c152
-rw-r--r--drivers/scsi/arm/oak.c74
-rw-r--r--drivers/scsi/bvme6000.c76
-rw-r--r--drivers/scsi/bvme6000.h24
-rw-r--r--drivers/scsi/bvme6000_scsi.c136
-rw-r--r--drivers/scsi/dc395x.c163
-rw-r--r--drivers/scsi/dpt_i2o.c33
-rw-r--r--drivers/scsi/eata.c48
-rw-r--r--drivers/scsi/esp_scsi.c30
-rw-r--r--drivers/scsi/esp_scsi.h4
-rw-r--r--drivers/scsi/fdomain.c70
-rw-r--r--drivers/scsi/gdth.c4
-rw-r--r--drivers/scsi/hptiop.c76
-rw-r--r--drivers/scsi/ibmmca.c1267
-rw-r--r--drivers/scsi/ibmmca.h21
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c463
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h2
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c20
-rw-r--r--drivers/scsi/imm.c3
-rw-r--r--drivers/scsi/initio.c3819
-rw-r--r--drivers/scsi/initio.h313
-rw-r--r--drivers/scsi/ipr.c184
-rw-r--r--drivers/scsi/ips.c413
-rw-r--r--drivers/scsi/ips.h44
-rw-r--r--drivers/scsi/iscsi_tcp.c606
-rw-r--r--drivers/scsi/iscsi_tcp.h9
-rw-r--r--drivers/scsi/jazz_esp.c4
-rw-r--r--drivers/scsi/lasi700.c3
-rw-r--r--drivers/scsi/libiscsi.c650
-rw-r--r--drivers/scsi/libsas/Kconfig7
-rw-r--r--drivers/scsi/libsas/Makefile1
-rw-r--r--drivers/scsi/libsas/sas_ata.c817
-rw-r--r--drivers/scsi/libsas/sas_discover.c402
-rw-r--r--drivers/scsi/libsas/sas_expander.c227
-rw-r--r--drivers/scsi/libsas/sas_init.c3
-rw-r--r--drivers/scsi/libsas/sas_internal.h3
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c87
-rw-r--r--drivers/scsi/lpfc/Makefile5
-rw-r--r--drivers/scsi/lpfc/lpfc.h358
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c774
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h182
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c971
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c508
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h50
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h15
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c3377
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c2262
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h558
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c956
-rw-r--r--drivers/scsi/lpfc/lpfc_logmsg.h1
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c306
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c101
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c1325
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c557
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c2047
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h47
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.c523
-rw-r--r--drivers/scsi/lpfc/lpfc_vport.h113
-rw-r--r--drivers/scsi/mac53c94.c62
-rw-r--r--drivers/scsi/megaraid.c141
-rw-r--r--drivers/scsi/megaraid/mega_common.h1
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c185
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c3
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c116
-rw-r--r--drivers/scsi/mesh.c46
-rw-r--r--drivers/scsi/mvme16x.c78
-rw-r--r--drivers/scsi/mvme16x.h24
-rw-r--r--drivers/scsi/mvme16x_scsi.c159
-rw-r--r--drivers/scsi/ncr53c8xx.c70
-rw-r--r--drivers/scsi/nsp32.c204
-rw-r--r--drivers/scsi/pcmcia/Kconfig7
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c3
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c3
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c45
-rw-r--r--drivers/scsi/ppa.c60
-rw-r--r--drivers/scsi/ps3rom.c533
-rw-r--r--drivers/scsi/qla2xxx/Makefile2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c253
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c1118
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h48
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h105
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h127
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h45
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c85
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c304
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c252
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c140
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c454
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c497
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c619
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c35
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h6
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c174
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h78
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h426
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h7
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c105
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c101
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c114
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c274
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.c3
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c98
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h3
-rw-r--r--drivers/scsi/qlogicfas408.c30
-rw-r--r--drivers/scsi/scsi.c50
-rw-r--r--drivers/scsi/scsi_debug.c4
-rw-r--r--drivers/scsi/scsi_devinfo.c1
-rw-r--r--drivers/scsi/scsi_error.c29
-rw-r--r--drivers/scsi/scsi_lib.c4
-rw-r--r--drivers/scsi/scsi_lib_dma.c50
-rw-r--r--drivers/scsi/scsi_scan.c67
-rw-r--r--drivers/scsi/scsi_sysctl.c1
-rw-r--r--drivers/scsi/scsi_sysfs.c41
-rw-r--r--drivers/scsi/scsi_tgt_lib.c2
-rw-r--r--drivers/scsi/scsi_transport_fc.c833
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c138
-rw-r--r--drivers/scsi/scsi_transport_sas.c125
-rw-r--r--drivers/scsi/sd.c4
-rw-r--r--drivers/scsi/seagate.c2
-rw-r--r--drivers/scsi/sg.c2
-rw-r--r--drivers/scsi/sim710.c6
-rw-r--r--drivers/scsi/sni_53c710.c10
-rw-r--r--drivers/scsi/sr.c8
-rw-r--r--drivers/scsi/st.c3
-rw-r--r--drivers/scsi/stex.c111
-rw-r--r--drivers/scsi/sun_esp.c2
-rw-r--r--drivers/scsi/sym53c416.c44
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c83
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.h2
-rw-r--r--drivers/scsi/tmscsim.c88
-rw-r--r--drivers/scsi/tmscsim.h10
-rw-r--r--drivers/scsi/u14-34f.c60
-rw-r--r--drivers/scsi/ultrastor.c19
-rw-r--r--drivers/scsi/wd33c93.c4
-rw-r--r--drivers/scsi/wd7000.c20
-rw-r--r--drivers/scsi/zorro7xx.c181
-rw-r--r--drivers/serial/68360serial.c7
-rw-r--r--drivers/serial/8250.c28
-rw-r--r--drivers/serial/8250_early.c117
-rw-r--r--drivers/serial/8250_hp300.c1
-rw-r--r--drivers/serial/Kconfig120
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/serial/amba-pl011.c3
-rw-r--r--drivers/serial/atmel_serial.c32
-rw-r--r--drivers/serial/bfin_5xx.c182
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/serial/imx.c2
-rw-r--r--drivers/serial/ip22zilog.c3
-rw-r--r--drivers/serial/jsm/jsm_driver.c2
-rw-r--r--drivers/serial/of_serial.c33
-rw-r--r--drivers/serial/s3c2410.c2
-rw-r--r--drivers/serial/sb1250-duart.c972
-rw-r--r--drivers/serial/serial_core.c6
-rw-r--r--drivers/serial/sh-sci.c4
-rw-r--r--drivers/serial/sh-sci.h50
-rw-r--r--drivers/serial/sn_console.c4
-rw-r--r--drivers/serial/suncore.c123
-rw-r--r--drivers/serial/suncore.h2
-rw-r--r--drivers/serial/sunhv.c55
-rw-r--r--drivers/serial/sunsab.c41
-rw-r--r--drivers/serial/sunsu.c37
-rw-r--r--drivers/serial/sunzilog.c41
-rw-r--r--drivers/serial/vr41xx_siu.c143
-rw-r--r--drivers/serial/zs.c1287
-rw-r--r--drivers/serial/zs.h284
-rw-r--r--drivers/sh/superhyway/superhyway.c3
-rw-r--r--drivers/sn/ioc3.c3
-rw-r--r--drivers/spi/Kconfig45
-rw-r--r--drivers/spi/Makefile5
-rw-r--r--drivers/spi/at25.c7
-rw-r--r--drivers/spi/atmel_spi.c185
-rw-r--r--drivers/spi/au1550_spi.c9
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c9
-rw-r--r--drivers/spi/omap2_mcspi.c1081
-rw-r--r--drivers/spi/omap_uwire.c9
-rw-r--r--drivers/spi/pxa2xx_spi.c9
-rw-r--r--drivers/spi/spi.c14
-rw-r--r--drivers/spi/spi_bitbang.c8
-rw-r--r--drivers/spi/spi_imx.c24
-rw-r--r--drivers/spi/spi_lm70llp.c361
-rw-r--r--drivers/spi/spi_mpc83xx.c47
-rw-r--r--drivers/spi/spi_s3c24xx.c8
-rw-r--r--drivers/spi/spi_txx9.c474
-rw-r--r--drivers/spi/spidev.c6
-rw-r--r--drivers/spi/tle62x0.c328
-rw-r--r--drivers/spi/xilinx_spi.c434
-rw-r--r--drivers/tc/Makefile1
-rw-r--r--drivers/tc/zs.c2203
-rw-r--r--drivers/tc/zs.h404
-rw-r--r--drivers/telephony/Kconfig13
-rw-r--r--drivers/telephony/ixj.c7
-rw-r--r--drivers/telephony/ixj_pcmcia.c3
-rw-r--r--drivers/uio/Kconfig29
-rw-r--r--drivers/uio/Makefile2
-rw-r--r--drivers/uio/uio.c701
-rw-r--r--drivers/uio/uio_cif.c156
-rw-r--r--drivers/usb/Kconfig10
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/atm/cxacru.c76
-rw-r--r--drivers/usb/atm/speedtch.c7
-rw-r--r--drivers/usb/atm/ueagle-atm.c7
-rw-r--r--drivers/usb/atm/usbatm.c11
-rw-r--r--drivers/usb/class/cdc-acm.c21
-rw-r--r--drivers/usb/class/usblp.c621
-rw-r--r--drivers/usb/core/Kconfig25
-rw-r--r--drivers/usb/core/config.c42
-rw-r--r--drivers/usb/core/devices.c26
-rw-r--r--drivers/usb/core/driver.c155
-rw-r--r--drivers/usb/core/file.c29
-rw-r--r--drivers/usb/core/generic.c29
-rw-r--r--drivers/usb/core/hcd-pci.c3
-rw-r--r--drivers/usb/core/hcd.c247
-rw-r--r--drivers/usb/core/hcd.h14
-rw-r--r--drivers/usb/core/hub.c661
-rw-r--r--drivers/usb/core/message.c72
-rw-r--r--drivers/usb/core/quirks.c18
-rw-r--r--drivers/usb/core/sysfs.c162
-rw-r--r--drivers/usb/core/urb.c193
-rw-r--r--drivers/usb/core/usb.c12
-rw-r--r--drivers/usb/core/usb.h14
-rw-r--r--drivers/usb/gadget/Kconfig74
-rw-r--r--drivers/usb/gadget/Makefile7
-rw-r--r--drivers/usb/gadget/amd5536udc.c3454
-rw-r--r--drivers/usb/gadget/amd5536udc.h626
-rw-r--r--drivers/usb/gadget/at91_udc.c21
-rw-r--r--drivers/usb/gadget/dummy_hcd.c39
-rw-r--r--drivers/usb/gadget/ether.c12
-rw-r--r--drivers/usb/gadget/file_storage.c25
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.c99
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h4
-rw-r--r--drivers/usb/gadget/gadget_chips.h35
-rw-r--r--drivers/usb/gadget/gmidi.c8
-rw-r--r--drivers/usb/gadget/goku_udc.c87
-rw-r--r--drivers/usb/gadget/goku_udc.h10
-rw-r--r--drivers/usb/gadget/inode.c8
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c27
-rw-r--r--drivers/usb/gadget/m66592-udc.c1633
-rw-r--r--drivers/usb/gadget/m66592-udc.h575
-rw-r--r--drivers/usb/gadget/net2280.c99
-rw-r--r--drivers/usb/gadget/omap_udc.c108
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c473
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h48
-rw-r--r--drivers/usb/gadget/rndis.c164
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c2045
-rw-r--r--drivers/usb/gadget/s3c2410_udc.h110
-rw-r--r--drivers/usb/gadget/serial.c42
-rw-r--r--drivers/usb/gadget/zero.c9
-rw-r--r--drivers/usb/host/Kconfig28
-rw-r--r--drivers/usb/host/Makefile2
-rw-r--r--drivers/usb/host/ehci-dbg.c183
-rw-r--r--drivers/usb/host/ehci-fsl.c10
-rw-r--r--drivers/usb/host/ehci-hcd.c118
-rw-r--r--drivers/usb/host/ehci-hub.c122
-rw-r--r--drivers/usb/host/ehci-mem.c27
-rw-r--r--drivers/usb/host/ehci-pci.c10
-rw-r--r--drivers/usb/host/ehci-ppc-soc.c182
-rw-r--r--drivers/usb/host/ehci-ps3.c86
-rw-r--r--drivers/usb/host/ehci-q.c96
-rw-r--r--drivers/usb/host/ehci-sched.c339
-rw-r--r--drivers/usb/host/ehci.h234
-rw-r--r--drivers/usb/host/isp116x-hcd.c187
-rw-r--r--drivers/usb/host/ohci-dbg.c4
-rw-r--r--drivers/usb/host/ohci-hcd.c95
-rw-r--r--drivers/usb/host/ohci-hub.c5
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-pci.c57
-rw-r--r--drivers/usb/host/ohci-pnx4008.c2
-rw-r--r--drivers/usb/host/ohci-ps3.c87
-rw-r--r--drivers/usb/host/ohci.h2
-rw-r--r--drivers/usb/host/r8a66597-hcd.c2242
-rw-r--r--drivers/usb/host/r8a66597.h631
-rw-r--r--drivers/usb/host/sl811_cs.c3
-rw-r--r--drivers/usb/host/u132-hcd.c17
-rw-r--r--drivers/usb/host/uhci-hcd.c7
-rw-r--r--drivers/usb/host/uhci-q.c59
-rw-r--r--drivers/usb/image/mdc800.c45
-rw-r--r--drivers/usb/image/microtek.c19
-rw-r--r--drivers/usb/misc/adutux.c86
-rw-r--r--drivers/usb/misc/appledisplay.c13
-rw-r--r--drivers/usb/misc/auerswald.c35
-rw-r--r--drivers/usb/misc/berry_charge.c35
-rw-r--r--drivers/usb/misc/ftdi-elan.c21
-rw-r--r--drivers/usb/misc/idmouse.c54
-rw-r--r--drivers/usb/misc/iowarrior.c47
-rw-r--r--drivers/usb/misc/ldusb.c53
-rw-r--r--drivers/usb/misc/legousbtower.c52
-rw-r--r--drivers/usb/misc/phidgetkit.c13
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c13
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c38
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c25
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.h2
-rw-r--r--drivers/usb/misc/usblcd.c78
-rw-r--r--drivers/usb/misc/usbtest.c4
-rw-r--r--drivers/usb/misc/uss720.c5
-rw-r--r--drivers/usb/mon/mon_bin.c34
-rw-r--r--drivers/usb/mon/mon_main.c14
-rw-r--r--drivers/usb/mon/mon_text.c31
-rw-r--r--drivers/usb/mon/usb_mon.h7
-rw-r--r--drivers/usb/serial/Kconfig10
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/aircable.c16
-rw-r--r--drivers/usb/serial/airprime.c10
-rw-r--r--drivers/usb/serial/ark3116.c61
-rw-r--r--drivers/usb/serial/belkin_sa.c78
-rw-r--r--drivers/usb/serial/cyberjack.c17
-rw-r--r--drivers/usb/serial/cypress_m8.c18
-rw-r--r--drivers/usb/serial/digi_acceleport.c99
-rw-r--r--drivers/usb/serial/empeg.c14
-rw-r--r--drivers/usb/serial/ftdi_sio.c119
-rw-r--r--drivers/usb/serial/garmin_gps.c47
-rw-r--r--drivers/usb/serial/generic.c97
-rw-r--r--drivers/usb/serial/io_edgeport.c40
-rw-r--r--drivers/usb/serial/io_fw_down3.h1460
-rw-r--r--drivers/usb/serial/io_ti.c134
-rw-r--r--drivers/usb/serial/io_usbvend.h12
-rw-r--r--drivers/usb/serial/ipaq.c14
-rw-r--r--drivers/usb/serial/ipw.c12
-rw-r--r--drivers/usb/serial/ir-usb.c154
-rw-r--r--drivers/usb/serial/keyspan.c456
-rw-r--r--drivers/usb/serial/keyspan.h74
-rw-r--r--drivers/usb/serial/keyspan_pda.c17
-rw-r--r--drivers/usb/serial/keyspan_usa67msg.h254
-rw-r--r--drivers/usb/serial/kl5kusb105.c22
-rw-r--r--drivers/usb/serial/kobil_sct.c26
-rw-r--r--drivers/usb/serial/mct_u232.c149
-rw-r--r--drivers/usb/serial/mct_u232.h15
-rw-r--r--drivers/usb/serial/mos7720.c48
-rw-r--r--drivers/usb/serial/mos7840.c125
-rw-r--r--drivers/usb/serial/navman.c7
-rw-r--r--drivers/usb/serial/omninet.c20
-rw-r--r--drivers/usb/serial/option.c34
-rw-r--r--drivers/usb/serial/oti6858.c1342
-rw-r--r--drivers/usb/serial/oti6858.h15
-rw-r--r--drivers/usb/serial/pl2303.c90
-rw-r--r--drivers/usb/serial/safe_serial.c6
-rw-r--r--drivers/usb/serial/sierra.c490
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c46
-rw-r--r--drivers/usb/serial/usb-serial.c35
-rw-r--r--drivers/usb/serial/visor.c64
-rw-r--r--drivers/usb/serial/whiteheat.c122
-rw-r--r--drivers/usb/storage/dpcm.c56
-rw-r--r--drivers/usb/storage/onetouch.c13
-rw-r--r--drivers/usb/storage/scsiglue.c21
-rw-r--r--drivers/usb/storage/unusual_devs.h206
-rw-r--r--drivers/usb/storage/usb.c94
-rw-r--r--drivers/usb/storage/usb.h1
-rw-r--r--drivers/usb/usb-skeleton.c151
-rw-r--r--drivers/video/68328fb.c2
-rw-r--r--drivers/video/Kconfig30
-rw-r--r--drivers/video/Makefile4
-rw-r--r--drivers/video/amba-clcd.c3
-rw-r--r--drivers/video/atmel_lcdfb.c67
-rw-r--r--drivers/video/aty/ati_ids.h1
-rw-r--r--drivers/video/aty/aty128fb.c2
-rw-r--r--drivers/video/aty/atyfb_base.c11
-rw-r--r--drivers/video/aty/radeon_backlight.c4
-rw-r--r--drivers/video/aty/radeon_base.c12
-rw-r--r--drivers/video/aty/radeonfb.h2
-rw-r--r--drivers/video/au1200fb.c3
-rw-r--r--drivers/video/backlight/Kconfig26
-rw-r--r--drivers/video/backlight/backlight.c125
-rw-r--r--drivers/video/backlight/cr_bllcd.c4
-rw-r--r--drivers/video/backlight/lcd.c112
-rw-r--r--drivers/video/clps711xfb.c3
-rw-r--r--drivers/video/console/Kconfig18
-rw-r--r--drivers/video/console/fbcon.c366
-rw-r--r--drivers/video/console/vgacon.c6
-rw-r--r--drivers/video/controlfb.c2
-rw-r--r--drivers/video/cyber2000fb.c3
-rw-r--r--drivers/video/cyblafb.c21
-rw-r--r--drivers/video/epson1355fb.c21
-rw-r--r--drivers/video/fbmem.c299
-rw-r--r--drivers/video/fm2fb.c16
-rw-r--r--drivers/video/gbefb.c41
-rw-r--r--drivers/video/i810/i810.h2
-rw-r--r--drivers/video/igafb.c4
-rw-r--r--drivers/video/intelfb/intelfb.h2
-rw-r--r--drivers/video/kyro/STG4000InitDevice.c5
-rw-r--r--drivers/video/logo/Kconfig5
-rw-r--r--drivers/video/logo/Makefile2
-rw-r--r--drivers/video/logo/logo.c7
-rw-r--r--drivers/video/logo/logo_spe_clut224.ppm283
-rw-r--r--drivers/video/macfb.c93
-rw-r--r--drivers/video/macmodes.c5
-rw-r--r--drivers/video/macmodes.h8
-rw-r--r--drivers/video/matrox/matroxfb_accel.c11
-rw-r--r--drivers/video/matrox/matroxfb_base.c8
-rw-r--r--drivers/video/matrox/matroxfb_base.h2
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.c6
-rw-r--r--drivers/video/matrox/matroxfb_crtc2.h4
-rw-r--r--drivers/video/matrox/matroxfb_maven.c9
-rw-r--r--drivers/video/nvidia/nv_backlight.c2
-rw-r--r--drivers/video/nvidia/nv_hw.c62
-rw-r--r--drivers/video/nvidia/nv_setup.c12
-rw-r--r--drivers/video/nvidia/nv_type.h1
-rw-r--r--drivers/video/nvidia/nvidia.c9
-rw-r--r--drivers/video/offb.c2
-rw-r--r--drivers/video/omap/Kconfig58
-rw-r--r--drivers/video/omap/Makefile29
-rw-r--r--drivers/video/omap/blizzard.c1568
-rw-r--r--drivers/video/omap/dispc.c1502
-rw-r--r--drivers/video/omap/dispc.h43
-rw-r--r--drivers/video/omap/hwa742.c1077
-rw-r--r--drivers/video/omap/lcd_h3.c141
-rw-r--r--drivers/video/omap/lcd_h4.c117
-rw-r--r--drivers/video/omap/lcd_inn1510.c124
-rw-r--r--drivers/video/omap/lcd_inn1610.c150
-rw-r--r--drivers/video/omap/lcd_osk.c144
-rw-r--r--drivers/video/omap/lcd_palmte.c123
-rw-r--r--drivers/video/omap/lcd_palmtt.c127
-rw-r--r--drivers/video/omap/lcd_palmz71.c123
-rw-r--r--drivers/video/omap/lcd_sx1.c334
-rw-r--r--drivers/video/omap/lcdc.c893
-rw-r--r--drivers/video/omap/lcdc.h7
-rw-r--r--drivers/video/omap/omapfb_main.c1941
-rw-r--r--drivers/video/omap/rfbi.c588
-rw-r--r--drivers/video/omap/sossi.c686
-rw-r--r--drivers/video/platinumfb.c2
-rw-r--r--drivers/video/pm2fb.c202
-rw-r--r--drivers/video/pm3fb.c270
-rw-r--r--drivers/video/ps3fb.c293
-rw-r--r--drivers/video/pvr2fb.c111
-rw-r--r--drivers/video/q40fb.c2
-rw-r--r--drivers/video/riva/fbdev.c4
-rw-r--r--drivers/video/riva/riva_hw.c7
-rw-r--r--drivers/video/savage/savagefb_driver.c3
-rw-r--r--drivers/video/sgivwfb.c2
-rw-r--r--drivers/video/sis/sis.h2
-rw-r--r--drivers/video/sis/sis_main.c8
-rw-r--r--drivers/video/sstfb.c2
-rw-r--r--drivers/video/tgafb.c5
-rw-r--r--drivers/video/tridentfb.c30
-rw-r--r--drivers/video/tx3912fb.c2
-rw-r--r--drivers/video/valkyriefb.c3
-rw-r--r--drivers/video/vt8623fb.c42
-rw-r--r--drivers/w1/Kconfig12
-rw-r--r--drivers/w1/masters/Kconfig7
-rw-r--r--drivers/w1/masters/matrox_w1.c3
-rw-r--r--drivers/w1/slaves/Kconfig4
-rw-r--r--drivers/w1/slaves/w1_ds2433.c14
-rw-r--r--drivers/w1/slaves/w1_ds2760.c9
-rw-r--r--drivers/w1/slaves/w1_therm.c8
-rw-r--r--drivers/w1/w1.c18
-rw-r--r--drivers/w1/w1_int.c3
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/grant-table.c582
-rw-r--r--drivers/xen/xenbus/Makefile7
-rw-r--r--drivers/xen/xenbus/xenbus_client.c569
-rw-r--r--drivers/xen/xenbus/xenbus_comms.c233
-rw-r--r--drivers/xen/xenbus/xenbus_comms.h46
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c935
-rw-r--r--drivers/xen/xenbus/xenbus_probe.h74
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c861
-rw-r--r--drivers/zorro/zorro-sysfs.c6
-rw-r--r--fs/9p/9p.h375
-rw-r--r--fs/9p/Makefile6
-rw-r--r--fs/9p/conv.h50
-rw-r--r--fs/9p/debug.h77
-rw-r--r--fs/9p/error.c93
-rw-r--r--fs/9p/fcall.c427
-rw-r--r--fs/9p/fid.c168
-rw-r--r--fs/9p/fid.h43
-rw-r--r--fs/9p/trans_fd.c308
-rw-r--r--fs/9p/v9fs.c295
-rw-r--r--fs/9p/v9fs.h32
-rw-r--r--fs/9p/v9fs_vfs.h6
-rw-r--r--fs/9p/vfs_addr.c57
-rw-r--r--fs/9p/vfs_dentry.c37
-rw-r--r--fs/9p/vfs_dir.c155
-rw-r--r--fs/9p/vfs_file.c166
-rw-r--r--fs/9p/vfs_inode.c754
-rw-r--r--fs/9p/vfs_super.c93
-rw-r--r--fs/Kconfig17
-rw-r--r--fs/adfs/super.c4
-rw-r--r--fs/affs/super.c2
-rw-r--r--fs/afs/Makefile1
-rw-r--r--fs/afs/afs.h8
-rw-r--r--fs/afs/afs_fs.h3
-rw-r--r--fs/afs/callback.c3
-rw-r--r--fs/afs/dir.c1
-rw-r--r--fs/afs/file.c2
-rw-r--r--fs/afs/flock.c559
-rw-r--r--fs/afs/fsclient.c155
-rw-r--r--fs/afs/internal.h30
-rw-r--r--fs/afs/main.c1
-rw-r--r--fs/afs/misc.c1
-rw-r--r--fs/afs/proc.c81
-rw-r--r--fs/afs/rxrpc.c21
-rw-r--r--fs/afs/super.c6
-rw-r--r--fs/afs/vnode.c132
-rw-r--r--fs/anon_inodes.c11
-rw-r--r--fs/attr.c4
-rw-r--r--fs/befs/linuxvfs.c4
-rw-r--r--fs/bfs/inode.c4
-rw-r--r--fs/binfmt_elf.c58
-rw-r--r--fs/binfmt_elf_fdpic.c64
-rw-r--r--fs/binfmt_misc.c4
-rw-r--r--fs/binfmt_script.c4
-rw-r--r--fs/bio.c2
-rw-r--r--fs/block_dev.c65
-rw-r--r--fs/buffer.c110
-rw-r--r--fs/char_dev.c3
-rw-r--r--fs/cifs/CHANGES13
-rw-r--r--fs/cifs/README38
-rw-r--r--fs/cifs/TODO12
-rw-r--r--fs/cifs/asn1.c57
-rw-r--r--fs/cifs/cifs_debug.c103
-rw-r--r--fs/cifs/cifs_fs_sb.h2
-rw-r--r--fs/cifs/cifs_unicode.c2
-rw-r--r--fs/cifs/cifs_unicode.h39
-rw-r--r--fs/cifs/cifs_uniupr.h8
-rw-r--r--fs/cifs/cifsencrypt.c262
-rw-r--r--fs/cifs/cifsfs.c210
-rw-r--r--fs/cifs/cifsfs.h23
-rw-r--r--fs/cifs/cifsglob.h78
-rw-r--r--fs/cifs/cifspdu.h297
-rw-r--r--fs/cifs/cifsproto.h123
-rw-r--r--fs/cifs/cifssmb.c1621
-rw-r--r--fs/cifs/connect.c1263
-rw-r--r--fs/cifs/dir.c22
-rw-r--r--fs/cifs/export.c50
-rw-r--r--fs/cifs/fcntl.c2
-rw-r--r--fs/cifs/file.c287
-rw-r--r--fs/cifs/inode.c320
-rw-r--r--fs/cifs/ioctl.c4
-rw-r--r--fs/cifs/link.c116
-rw-r--r--fs/cifs/md4.c10
-rw-r--r--fs/cifs/md5.c8
-rw-r--r--fs/cifs/misc.c239
-rw-r--r--fs/cifs/netmisc.c171
-rw-r--r--fs/cifs/nterr.c8
-rw-r--r--fs/cifs/nterr.h8
-rw-r--r--fs/cifs/ntlmssp.h22
-rw-r--r--fs/cifs/readdir.c375
-rw-r--r--fs/cifs/sess.c249
-rw-r--r--fs/cifs/smbdes.c30
-rw-r--r--fs/cifs/smbencrypt.c52
-rw-r--r--fs/cifs/smberr.h8
-rw-r--r--fs/cifs/transport.c248
-rw-r--r--fs/cifs/xattr.c229
-rw-r--r--fs/coda/cache.c7
-rw-r--r--fs/coda/cnode.c7
-rw-r--r--fs/coda/coda_int.h7
-rw-r--r--fs/coda/dir.c305
-rw-r--r--fs/coda/file.c80
-rw-r--r--fs/coda/inode.c50
-rw-r--r--fs/coda/psdev.c88
-rw-r--r--fs/coda/symlink.c2
-rw-r--r--fs/coda/sysctl.c228
-rw-r--r--fs/coda/upcall.c499
-rw-r--r--fs/compat.c128
-rw-r--r--fs/compat_ioctl.c4
-rw-r--r--fs/configfs/configfs_internal.h7
-rw-r--r--fs/configfs/dir.c289
-rw-r--r--fs/configfs/file.c28
-rw-r--r--fs/configfs/item.c29
-rw-r--r--fs/configfs/mount.c2
-rw-r--r--fs/dcache.c11
-rw-r--r--fs/dcookies.c2
-rw-r--r--fs/debugfs/inode.c68
-rw-r--r--fs/dlm/config.c20
-rw-r--r--fs/dlm/lowcomms.c2
-rw-r--r--fs/dlm/memory.c14
-rw-r--r--fs/dnotify.c2
-rw-r--r--fs/dquot.c11
-rw-r--r--fs/drop_caches.c2
-rw-r--r--fs/ecryptfs/inode.c9
-rw-r--r--fs/ecryptfs/main.c4
-rw-r--r--fs/ecryptfs/mmap.c5
-rw-r--r--fs/efs/namei.c32
-rw-r--r--fs/efs/super.c6
-rw-r--r--fs/eventpoll.c4
-rw-r--r--fs/exec.c679
-rw-r--r--fs/exportfs/expfs.c439
-rw-r--r--fs/ext2/acl.c2
-rw-r--r--fs/ext2/file.c6
-rw-r--r--fs/ext2/ioctl.c4
-rw-r--r--fs/ext2/super.c29
-rw-r--r--fs/ext3/acl.c2
-rw-r--r--fs/ext3/dir.c14
-rw-r--r--fs/ext3/inode.c2
-rw-r--r--fs/ext3/ioctl.c6
-rw-r--r--fs/ext3/namei.c10
-rw-r--r--fs/ext3/super.c54
-rw-r--r--fs/ext4/acl.c2
-rw-r--r--fs/ext4/balloc.c6
-rw-r--r--fs/ext4/dir.c14
-rw-r--r--fs/ext4/extents.c682
-rw-r--r--fs/ext4/file.c1
-rw-r--r--fs/ext4/ialloc.c8
-rw-r--r--fs/ext4/inode.c120
-rw-r--r--fs/ext4/ioctl.c15
-rw-r--r--fs/ext4/namei.c86
-rw-r--r--fs/ext4/super.c101
-rw-r--r--fs/ext4/xattr.c276
-rw-r--r--fs/ext4/xattr.h17
-rw-r--r--fs/fat/cache.c2
-rw-r--r--fs/fat/dir.c31
-rw-r--r--fs/fat/fatent.c7
-rw-r--r--fs/fat/inode.c6
-rw-r--r--fs/fcntl.c4
-rw-r--r--fs/freevxfs/vxfs_dir.h2
-rw-r--r--fs/freevxfs/vxfs_super.c4
-rw-r--r--fs/fuse/dev.c2
-rw-r--r--fs/fuse/inode.c2
-rw-r--r--fs/generic_acl.c2
-rw-r--r--fs/gfs2/acl.c2
-rw-r--r--fs/gfs2/eaops.c1
-rw-r--r--fs/gfs2/main.c6
-rw-r--r--fs/gfs2/ops_address.c2
-rw-r--r--fs/gfs2/ops_export.c1
-rw-r--r--fs/gfs2/ops_file.c24
-rw-r--r--fs/gfs2/ops_vm.c64
-rw-r--r--fs/hfs/super.c2
-rw-r--r--fs/hfsplus/btree.c4
-rw-r--r--fs/hfsplus/dir.c2
-rw-r--r--fs/hfsplus/hfsplus_fs.h4
-rw-r--r--fs/hfsplus/inode.c5
-rw-r--r--fs/hfsplus/ioctl.c2
-rw-r--r--fs/hfsplus/super.c6
-rw-r--r--fs/hfsplus/unicode.c230
-rw-r--r--fs/hpfs/super.c4
-rw-r--r--fs/hugetlbfs/inode.c98
-rw-r--r--fs/inode.c20
-rw-r--r--fs/inotify_user.c4
-rw-r--r--fs/ioctl.c22
-rw-r--r--fs/isofs/dir.c87
-rw-r--r--fs/isofs/inode.c417
-rw-r--r--fs/isofs/isofs.h1
-rw-r--r--fs/isofs/joliet.c10
-rw-r--r--fs/isofs/namei.c26
-rw-r--r--fs/jbd/commit.c3
-rw-r--r--fs/jbd/journal.c8
-rw-r--r--fs/jbd/revoke.c9
-rw-r--r--fs/jbd2/commit.c3
-rw-r--r--fs/jbd2/journal.c87
-rw-r--r--fs/jbd2/recovery.c8
-rw-r--r--fs/jbd2/revoke.c9
-rw-r--r--fs/jffs2/acl.c2
-rw-r--r--fs/jffs2/background.c1
-rw-r--r--fs/jffs2/malloc.c18
-rw-r--r--fs/jffs2/super.c2
-rw-r--r--fs/jfs/ioctl.c2
-rw-r--r--fs/jfs/jfs_inode.h1
-rw-r--r--fs/jfs/jfs_metapage.c2
-rw-r--r--fs/jfs/namei.c32
-rw-r--r--fs/jfs/super.c4
-rw-r--r--fs/jfs/xattr.c2
-rw-r--r--fs/lockd/host.c39
-rw-r--r--fs/lockd/mon.c2
-rw-r--r--fs/lockd/svc.c35
-rw-r--r--fs/locks.c114
-rw-r--r--fs/mbcache.c11
-rw-r--r--fs/minix/inode.c4
-rw-r--r--fs/namei.c41
-rw-r--r--fs/namespace.c25
-rw-r--r--fs/ncpfs/file.c2
-rw-r--r--fs/ncpfs/inode.c4
-rw-r--r--fs/ncpfs/mmap.c40
-rw-r--r--fs/nfs/Makefile4
-rw-r--r--fs/nfs/callback.c2
-rw-r--r--fs/nfs/callback_xdr.c10
-rw-r--r--fs/nfs/client.c82
-rw-r--r--fs/nfs/delegation.c186
-rw-r--r--fs/nfs/delegation.h26
-rw-r--r--fs/nfs/dir.c24
-rw-r--r--fs/nfs/direct.c36
-rw-r--r--fs/nfs/file.c16
-rw-r--r--fs/nfs/inode.c77
-rw-r--r--fs/nfs/internal.h4
-rw-r--r--fs/nfs/mount_clnt.c169
-rw-r--r--fs/nfs/nfs2xdr.c25
-rw-r--r--fs/nfs/nfs3proc.c64
-rw-r--r--fs/nfs/nfs3xdr.c32
-rw-r--r--fs/nfs/nfs4_fs.h42
-rw-r--r--fs/nfs/nfs4proc.c876
-rw-r--r--fs/nfs/nfs4state.c310
-rw-r--r--fs/nfs/nfs4xdr.c384
-rw-r--r--fs/nfs/nfsroot.c5
-rw-r--r--fs/nfs/pagelist.c62
-rw-r--r--fs/nfs/proc.c40
-rw-r--r--fs/nfs/read.c42
-rw-r--r--fs/nfs/super.c1206
-rw-r--r--fs/nfs/unlink.c195
-rw-r--r--fs/nfs/write.c151
-rw-r--r--fs/nfsctl.c16
-rw-r--r--fs/nfsd/auth.c19
-rw-r--r--fs/nfsd/export.c289
-rw-r--r--fs/nfsd/lockd.c1
-rw-r--r--fs/nfsd/nfs4acl.c12
-rw-r--r--fs/nfsd/nfs4callback.c20
-rw-r--r--fs/nfsd/nfs4idmap.c13
-rw-r--r--fs/nfsd/nfs4proc.c35
-rw-r--r--fs/nfsd/nfs4state.c65
-rw-r--r--fs/nfsd/nfs4xdr.c101
-rw-r--r--fs/nfsd/nfsctl.c3
-rw-r--r--fs/nfsd/nfsfh.c51
-rw-r--r--fs/nfsd/nfsproc.c3
-rw-r--r--fs/nfsd/nfssvc.c12
-rw-r--r--fs/nfsd/vfs.c122
-rw-r--r--fs/nls/Makefile2
-rw-r--r--fs/ntfs/namei.c1
-rw-r--r--fs/ntfs/super.c10
-rw-r--r--fs/ocfs2/alloc.c2676
-rw-r--r--fs/ocfs2/alloc.h43
-rw-r--r--fs/ocfs2/aops.c1017
-rw-r--r--fs/ocfs2/aops.h61
-rw-r--r--fs/ocfs2/cluster/heartbeat.c96
-rw-r--r--fs/ocfs2/cluster/heartbeat.h6
-rw-r--r--fs/ocfs2/cluster/masklog.c1
-rw-r--r--fs/ocfs2/cluster/nodemanager.c42
-rw-r--r--fs/ocfs2/cluster/nodemanager.h5
-rw-r--r--fs/ocfs2/cluster/tcp.c21
-rw-r--r--fs/ocfs2/dir.c2
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c8
-rw-r--r--fs/ocfs2/dlm/dlmfs.c2
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c42
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c79
-rw-r--r--fs/ocfs2/dlmglue.c6
-rw-r--r--fs/ocfs2/endian.h5
-rw-r--r--fs/ocfs2/export.h2
-rw-r--r--fs/ocfs2/extent_map.c41
-rw-r--r--fs/ocfs2/file.c744
-rw-r--r--fs/ocfs2/file.h10
-rw-r--r--fs/ocfs2/heartbeat.c12
-rw-r--r--fs/ocfs2/ioctl.c17
-rw-r--r--fs/ocfs2/journal.c6
-rw-r--r--fs/ocfs2/journal.h2
-rw-r--r--fs/ocfs2/mmap.c183
-rw-r--r--fs/ocfs2/namei.c2
-rw-r--r--fs/ocfs2/ocfs2.h14
-rw-r--r--fs/ocfs2/ocfs2_fs.h33
-rw-r--r--fs/ocfs2/slot_map.c12
-rw-r--r--fs/ocfs2/suballoc.c46
-rw-r--r--fs/ocfs2/suballoc.h17
-rw-r--r--fs/ocfs2/super.c29
-rw-r--r--fs/ocfs2/super.h2
-rw-r--r--fs/ocfs2/uptodate.c2
-rw-r--r--fs/open.c73
-rw-r--r--fs/openpromfs/inode.c2
-rw-r--r--fs/partitions/acorn.c9
-rw-r--r--fs/partitions/check.c4
-rw-r--r--fs/partitions/ldm.c137
-rw-r--r--fs/partitions/ldm.h2
-rw-r--r--fs/proc/array.c68
-rw-r--r--fs/proc/base.c176
-rw-r--r--fs/proc/generic.c52
-rw-r--r--fs/proc/inode.c258
-rw-r--r--fs/proc/proc_misc.c25
-rw-r--r--fs/proc/proc_tty.c15
-rw-r--r--fs/qnx4/inode.c2
-rw-r--r--fs/quota.c118
-rw-r--r--fs/ramfs/inode.c1
-rw-r--r--fs/reiserfs/file.c1
-rw-r--r--fs/reiserfs/inode.c1
-rw-r--r--fs/reiserfs/ioctl.c5
-rw-r--r--fs/reiserfs/super.c3
-rw-r--r--fs/reiserfs/xattr_acl.c2
-rw-r--r--fs/romfs/inode.c4
-rw-r--r--fs/seq_file.c18
-rw-r--r--fs/smbfs/inode.c4
-rw-r--r--fs/smbfs/request.c2
-rw-r--r--fs/splice.c83
-rw-r--r--fs/super.c1
-rw-r--r--fs/sysfs/bin.c195
-rw-r--r--fs/sysfs/dir.c1300
-rw-r--r--fs/sysfs/file.c380
-rw-r--r--fs/sysfs/group.c55
-rw-r--r--fs/sysfs/inode.c221
-rw-r--r--fs/sysfs/mount.c38
-rw-r--r--fs/sysfs/symlink.c154
-rw-r--r--fs/sysfs/sysfs.h168
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/udf/balloc.c543
-rw-r--r--fs/udf/crc.c19
-rw-r--r--fs/udf/dir.c108
-rw-r--r--fs/udf/directory.c173
-rw-r--r--fs/udf/ecma_167.h191
-rw-r--r--fs/udf/file.c102
-rw-r--r--fs/udf/fsync.c6
-rw-r--r--fs/udf/ialloc.c42
-rw-r--r--fs/udf/inode.c1239
-rw-r--r--fs/udf/lowlevel.c21
-rw-r--r--fs/udf/misc.c113
-rw-r--r--fs/udf/namei.c564
-rw-r--r--fs/udf/osta_udf.h75
-rw-r--r--fs/udf/partition.c119
-rw-r--r--fs/udf/super.c1256
-rw-r--r--fs/udf/symlink.c54
-rw-r--r--fs/udf/truncate.c166
-rw-r--r--fs/udf/udf_sb.h20
-rw-r--r--fs/udf/udfdecl.h102
-rw-r--r--fs/udf/udfend.h18
-rw-r--r--fs/udf/udftime.c87
-rw-r--r--fs/udf/unicode.c258
-rw-r--r--fs/ufs/super.c9
-rw-r--r--fs/utimes.c2
-rw-r--r--fs/xattr.c3
-rw-r--r--fs/xfs/Makefile-linux-2.62
-rw-r--r--fs/xfs/linux-2.6/kmem.h23
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c43
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c67
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c51
-rw-r--r--fs/xfs/linux-2.6/xfs_globals.c1
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c321
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_super.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_sysctl.c11
-rw-r--r--fs/xfs/linux-2.6/xfs_sysctl.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_vfs.h15
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h5
-rw-r--r--fs/xfs/quota/xfs_qm.c13
-rw-r--r--fs/xfs/xfs.h1
-rw-r--r--fs/xfs/xfs_ag.h9
-rw-r--r--fs/xfs/xfs_alloc.c101
-rw-r--r--fs/xfs/xfs_alloc.h6
-rw-r--r--fs/xfs/xfs_alloc_btree.c20
-rw-r--r--fs/xfs/xfs_bit.c91
-rw-r--r--fs/xfs/xfs_bit.h4
-rw-r--r--fs/xfs/xfs_bmap.c369
-rw-r--r--fs/xfs/xfs_bmap.h6
-rw-r--r--fs/xfs/xfs_bmap_btree.c88
-rw-r--r--fs/xfs/xfs_btree.h32
-rw-r--r--fs/xfs/xfs_buf_item.c4
-rw-r--r--fs/xfs/xfs_clnt.h2
-rw-r--r--fs/xfs/xfs_dinode.h4
-rw-r--r--fs/xfs/xfs_dir2.c12
-rw-r--r--fs/xfs/xfs_dir2_block.c98
-rw-r--r--fs/xfs/xfs_dir2_block.h2
-rw-r--r--fs/xfs/xfs_dir2_data.c54
-rw-r--r--fs/xfs/xfs_dir2_data.h12
-rw-r--r--fs/xfs/xfs_dir2_leaf.c106
-rw-r--r--fs/xfs/xfs_dir2_leaf.h29
-rw-r--r--fs/xfs/xfs_dir2_node.c66
-rw-r--r--fs/xfs/xfs_dir2_node.h4
-rw-r--r--fs/xfs/xfs_dir2_sf.c204
-rw-r--r--fs/xfs/xfs_dir2_sf.h20
-rw-r--r--fs/xfs/xfs_filestream.c771
-rw-r--r--fs/xfs/xfs_filestream.h136
-rw-r--r--fs/xfs/xfs_fs.h2
-rw-r--r--fs/xfs/xfs_fsops.c17
-rw-r--r--fs/xfs/xfs_ialloc.c28
-rw-r--r--fs/xfs/xfs_ialloc.h10
-rw-r--r--fs/xfs/xfs_inode.c39
-rw-r--r--fs/xfs/xfs_inode.h16
-rw-r--r--fs/xfs/xfs_iomap.c41
-rw-r--r--fs/xfs/xfs_itable.c42
-rw-r--r--fs/xfs/xfs_itable.h20
-rw-r--r--fs/xfs/xfs_log.c41
-rw-r--r--fs/xfs/xfs_log_recover.c8
-rw-r--r--fs/xfs/xfs_mount.c237
-rw-r--r--fs/xfs/xfs_mount.h15
-rw-r--r--fs/xfs/xfs_mru_cache.c608
-rw-r--r--fs/xfs/xfs_mru_cache.h57
-rw-r--r--fs/xfs/xfs_rtalloc.c4
-rw-r--r--fs/xfs/xfs_rw.h36
-rw-r--r--fs/xfs/xfs_sb.h16
-rw-r--r--fs/xfs/xfs_trans.c125
-rw-r--r--fs/xfs/xfs_trans.h3
-rw-r--r--fs/xfs/xfs_vfsops.c159
-rw-r--r--fs/xfs/xfs_vnodeops.c149
-rw-r--r--include/acpi/acmacros.h63
-rw-r--r--include/acpi/acoutput.h4
-rw-r--r--include/acpi/acpi_bus.h3
-rw-r--r--include/acpi/acpi_numa.h1
-rw-r--r--include/acpi/platform/acenv.h2
-rw-r--r--include/acpi/platform/aclinux.h3
-rw-r--r--include/acpi/processor.h47
-rw-r--r--include/asm-alpha/a.out.h2
-rw-r--r--include/asm-alpha/fb.h13
-rw-r--r--include/asm-alpha/io.h13
-rw-r--r--include/asm-alpha/irq.h4
-rw-r--r--include/asm-alpha/page.h3
-rw-r--r--include/asm-alpha/pci.h29
-rw-r--r--include/asm-alpha/pgtable.h6
-rw-r--r--include/asm-alpha/system.h10
-rw-r--r--include/asm-alpha/termios.h4
-rw-r--r--include/asm-arm/Kbuild2
-rw-r--r--include/asm-arm/a.out.h1
-rw-r--r--include/asm-arm/arch-at91/at91_dbgu.h13
-rw-r--r--include/asm-arm/arch-at91/at91_mci.h3
-rw-r--r--include/asm-arm/arch-at91/at91x40.h55
-rw-r--r--include/asm-arm/arch-at91/board.h1
-rw-r--r--include/asm-arm/arch-at91/cpu.h5
-rw-r--r--include/asm-arm/arch-at91/hardware.h17
-rw-r--r--include/asm-arm/arch-at91/timex.h5
-rw-r--r--include/asm-arm/arch-at91/uncompress.h4
-rw-r--r--include/asm-arm/arch-davinci/clock.h22
-rw-r--r--include/asm-arm/arch-davinci/gpio.h156
-rw-r--r--include/asm-arm/arch-davinci/hardware.h38
-rw-r--r--include/asm-arm/arch-davinci/mux.h55
-rw-r--r--include/asm-arm/arch-imx/gpio.h102
-rw-r--r--include/asm-arm/arch-imx/imx-regs.h2
-rw-r--r--include/asm-arm/arch-iop13xx/adma.h544
-rw-r--r--include/asm-arm/arch-iop13xx/iop13xx.h81
-rw-r--r--include/asm-arm/arch-iop13xx/system.h34
-rw-r--r--include/asm-arm/arch-iop13xx/uncompress.h3
-rw-r--r--include/asm-arm/arch-iop32x/adma.h5
-rw-r--r--include/asm-arm/arch-iop32x/uncompress.h2
-rw-r--r--include/asm-arm/arch-iop33x/adma.h5
-rw-r--r--include/asm-arm/arch-ixp4xx/ixdp425.h4
-rw-r--r--include/asm-arm/arch-ixp4xx/udc.h22
-rw-r--r--include/asm-arm/arch-ixp4xx/uncompress.h5
-rw-r--r--include/asm-arm/arch-ks8695/gpio.h79
-rw-r--r--include/asm-arm/arch-mxc/board-mx31ads.h142
-rw-r--r--include/asm-arm/arch-mxc/common.h20
-rw-r--r--include/asm-arm/arch-mxc/dma.h21
-rw-r--r--include/asm-arm/arch-mxc/entry-macro.S39
-rw-r--r--include/asm-arm/arch-mxc/hardware.h52
-rw-r--r--include/asm-arm/arch-mxc/io.h33
-rw-r--r--include/asm-arm/arch-mxc/irqs.h38
-rw-r--r--include/asm-arm/arch-mxc/memory.h36
-rw-r--r--include/asm-arm/arch-mxc/mx31.h335
-rw-r--r--include/asm-arm/arch-mxc/mxc.h149
-rw-r--r--include/asm-arm/arch-mxc/system.h50
-rw-r--r--include/asm-arm/arch-mxc/timex.h25
-rw-r--r--include/asm-arm/arch-mxc/uncompress.h79
-rw-r--r--include/asm-arm/arch-mxc/vmalloc.h36
-rw-r--r--include/asm-arm/arch-ns9xxx/regs-bbu.h28
-rw-r--r--include/asm-arm/arch-ns9xxx/regs-mem.h6
-rw-r--r--include/asm-arm/arch-ns9xxx/regs-sys.h2
-rw-r--r--include/asm-arm/arch-pxa/dma.h22
-rw-r--r--include/asm-arm/arch-pxa/entry-macro.S30
-rw-r--r--include/asm-arm/arch-pxa/hardware.h36
-rw-r--r--include/asm-arm/arch-pxa/irqs.h26
-rw-r--r--include/asm-arm/arch-pxa/pm.h17
-rw-r--r--include/asm-arm/arch-pxa/pxa-regs.h22
-rw-r--r--include/asm-arm/arch-pxa/udc.h33
-rw-r--r--include/asm-arm/arch-s3c2400/map.h66
-rw-r--r--include/asm-arm/arch-s3c2400/memory.h23
-rw-r--r--include/asm-arm/arch-s3c2410/debug-macro.S84
-rw-r--r--include/asm-arm/arch-s3c2410/map.h85
-rw-r--r--include/asm-arm/arch-s3c2410/memory.h13
-rw-r--r--include/asm-arm/arch-s3c2410/regs-lcd.h2
-rw-r--r--include/asm-arm/arch-s3c2410/system.h2
-rw-r--r--include/asm-arm/arch-s3c2410/uncompress.h145
-rw-r--r--include/asm-arm/arch-sa1100/jornada720.h27
-rw-r--r--include/asm-arm/elf.h24
-rw-r--r--include/asm-arm/fb.h19
-rw-r--r--include/asm-arm/floppy.h18
-rw-r--r--include/asm-arm/hardware/iop3xx-adma.h892
-rw-r--r--include/asm-arm/hardware/iop3xx.h101
-rw-r--r--include/asm-arm/hardware/iop_adma.h118
-rw-r--r--include/asm-arm/hwcap.h28
-rw-r--r--include/asm-arm/pci.h9
-rw-r--r--include/asm-arm/pgtable-nommu.h3
-rw-r--r--include/asm-arm/pgtable.h12
-rw-r--r--include/asm-arm/plat-s3c/debug-macro.S75
-rw-r--r--include/asm-arm/plat-s3c/iic.h (renamed from include/asm-arm/arch-s3c2410/iic.h)0
-rw-r--r--include/asm-arm/plat-s3c/map.h40
-rw-r--r--include/asm-arm/plat-s3c/nand.h (renamed from include/asm-arm/arch-s3c2410/nand.h)0
-rw-r--r--include/asm-arm/plat-s3c/regs-ac97.h (renamed from include/asm-arm/arch-s3c2410/regs-ac97.h)0
-rw-r--r--include/asm-arm/plat-s3c/regs-adc.h (renamed from include/asm-arm/arch-s3c2410/regs-adc.h)0
-rw-r--r--include/asm-arm/plat-s3c/regs-iic.h (renamed from include/asm-arm/arch-s3c2410/regs-iic.h)0
-rw-r--r--include/asm-arm/plat-s3c/regs-nand.h (renamed from include/asm-arm/arch-s3c2410/regs-nand.h)0
-rw-r--r--include/asm-arm/plat-s3c/regs-rtc.h (renamed from include/asm-arm/arch-s3c2410/regs-rtc.h)0
-rw-r--r--include/asm-arm/plat-s3c/regs-serial.h (renamed from include/asm-arm/arch-s3c2410/regs-serial.h)8
-rw-r--r--include/asm-arm/plat-s3c/regs-timer.h (renamed from include/asm-arm/arch-s3c2410/regs-timer.h)16
-rw-r--r--include/asm-arm/plat-s3c/regs-watchdog.h (renamed from include/asm-arm/arch-s3c2410/regs-watchdog.h)8
-rw-r--r--include/asm-arm/plat-s3c/uncompress.h155
-rw-r--r--include/asm-arm/plat-s3c24xx/regs-iis.h (renamed from include/asm-arm/arch-s3c2410/regs-iis.h)0
-rw-r--r--include/asm-arm/plat-s3c24xx/regs-spi.h (renamed from include/asm-arm/arch-s3c2410/regs-spi.h)0
-rw-r--r--include/asm-arm/plat-s3c24xx/regs-udc.h (renamed from include/asm-arm/arch-s3c2410/regs-udc.h)0
-rw-r--r--include/asm-arm/plat-s3c24xx/udc.h (renamed from include/asm-arm/arch-s3c2410/udc.h)0
-rw-r--r--include/asm-arm/ptrace.h16
-rw-r--r--include/asm-arm/system.h10
-rw-r--r--include/asm-arm/thread_info.h1
-rw-r--r--include/asm-arm/unistd.h1
-rw-r--r--include/asm-arm/vfp.h4
-rw-r--r--include/asm-arm26/a.out.h1
-rw-r--r--include/asm-arm26/dma-mapping.h2
-rw-r--r--include/asm-arm26/fb.h12
-rw-r--r--include/asm-arm26/ioctls.h4
-rw-r--r--include/asm-arm26/irq.h5
-rw-r--r--include/asm-arm26/pgtable.h4
-rw-r--r--include/asm-arm26/system.h10
-rw-r--r--include/asm-arm26/termbits.h5
-rw-r--r--include/asm-arm26/termios.h6
-rw-r--r--include/asm-avr32/a.out.h1
-rw-r--r--include/asm-avr32/arch-at32ap/board.h15
-rw-r--r--include/asm-avr32/arch-at32ap/sm.h27
-rw-r--r--include/asm-avr32/atomic.h4
-rw-r--r--include/asm-avr32/fb.h21
-rw-r--r--include/asm-avr32/pgtable.h28
-rw-r--r--include/asm-avr32/unaligned.h15
-rw-r--r--include/asm-blackfin/Kbuild2
-rw-r--r--include/asm-blackfin/bfin-global.h12
-rw-r--r--include/asm-blackfin/cplbinit.h133
-rw-r--r--include/asm-blackfin/fb.h12
-rw-r--r--include/asm-blackfin/fixed_code.h20
-rw-r--r--include/asm-blackfin/gpio.h58
-rw-r--r--include/asm-blackfin/hardirq.h4
-rw-r--r--include/asm-blackfin/kgdb.h183
-rw-r--r--include/asm-blackfin/mach-bf533/dma.h3
-rw-r--r--include/asm-blackfin/mach-bf533/portmux.h65
-rw-r--r--include/asm-blackfin/mach-bf537/dma.h3
-rw-r--r--include/asm-blackfin/mach-bf537/portmux.h109
-rw-r--r--include/asm-blackfin/mach-bf548/anomaly.h74
-rw-r--r--include/asm-blackfin/mach-bf548/bf548.h271
-rw-r--r--include/asm-blackfin/mach-bf548/bfin_serial_5xx.h193
-rw-r--r--include/asm-blackfin/mach-bf548/blackfin.h168
-rw-r--r--include/asm-blackfin/mach-bf548/cdefBF54x_base.h72
-rw-r--r--include/asm-blackfin/mach-bf548/defBF542.h281
-rw-r--r--include/asm-blackfin/mach-bf548/defBF544.h60
-rw-r--r--include/asm-blackfin/mach-bf548/defBF548.h341
-rw-r--r--include/asm-blackfin/mach-bf548/defBF549.h763
-rw-r--r--include/asm-blackfin/mach-bf548/defBF54x_base.h1366
-rw-r--r--include/asm-blackfin/mach-bf548/dma.h73
-rw-r--r--include/asm-blackfin/mach-bf548/gpio.h216
-rw-r--r--include/asm-blackfin/mach-bf548/irq.h467
-rw-r--r--include/asm-blackfin/mach-bf548/mem_init.h189
-rw-r--r--include/asm-blackfin/mach-bf548/mem_map.h97
-rw-r--r--include/asm-blackfin/mach-bf548/portmux.h270
-rw-r--r--include/asm-blackfin/mach-bf561/cdefBF561.h9
-rw-r--r--include/asm-blackfin/mach-bf561/dma.h3
-rw-r--r--include/asm-blackfin/mach-bf561/portmux.h87
-rw-r--r--include/asm-blackfin/mach-common/cdef_LPBlackfin.h23
-rw-r--r--include/asm-blackfin/mman.h2
-rw-r--r--include/asm-blackfin/page.h4
-rw-r--r--include/asm-blackfin/portmux.h1133
-rw-r--r--include/asm-blackfin/trace.h52
-rw-r--r--include/asm-cris/a.out.h1
-rw-r--r--include/asm-cris/fb.h12
-rw-r--r--include/asm-cris/ioctls.h4
-rw-r--r--include/asm-cris/page.h3
-rw-r--r--include/asm-cris/pci.h36
-rw-r--r--include/asm-cris/pgtable.h30
-rw-r--r--include/asm-cris/termbits.h1
-rw-r--r--include/asm-cris/termios.h6
-rw-r--r--include/asm-frv/fb.h12
-rw-r--r--include/asm-frv/mem-layout.h1
-rw-r--r--include/asm-frv/pci.h7
-rw-r--r--include/asm-frv/pgtable.h14
-rw-r--r--include/asm-frv/uaccess.h2
-rw-r--r--include/asm-frv/unistd.h6
-rw-r--r--include/asm-generic/bug.h2
-rw-r--r--include/asm-generic/dma-mapping-broken.h82
-rw-r--r--include/asm-generic/fcntl.h3
-rw-r--r--include/asm-generic/percpu.h8
-rw-r--r--include/asm-generic/pgtable.h44
-rw-r--r--include/asm-generic/unaligned.h16
-rw-r--r--include/asm-generic/vmlinux.lds.h14
-rw-r--r--include/asm-h8300/a.out.h1
-rw-r--r--include/asm-h8300/dma-mapping.h1
-rw-r--r--include/asm-h8300/fb.h12
-rw-r--r--include/asm-h8300/ioctls.h4
-rw-r--r--include/asm-h8300/irq.h3
-rw-r--r--include/asm-h8300/page.h3
-rw-r--r--include/asm-h8300/pci.h4
-rw-r--r--include/asm-h8300/termbits.h5
-rw-r--r--include/asm-h8300/termios.h6
-rw-r--r--include/asm-h8300/thread_info.h2
-rw-r--r--include/asm-i386/a.out.h1
-rw-r--r--include/asm-i386/alternative.h2
-rw-r--r--include/asm-i386/boot.h6
-rw-r--r--include/asm-i386/bootparam.h85
-rw-r--r--include/asm-i386/cmpxchg.h16
-rw-r--r--include/asm-i386/cpufeature.h26
-rw-r--r--include/asm-i386/e820.h22
-rw-r--r--include/asm-i386/fb.h17
-rw-r--r--include/asm-i386/fixmap.h2
-rw-r--r--include/asm-i386/geode.h159
-rw-r--r--include/asm-i386/hpet.h126
-rw-r--r--include/asm-i386/i8253.h16
-rw-r--r--include/asm-i386/ide.h4
-rw-r--r--include/asm-i386/io.h1
-rw-r--r--include/asm-i386/irq.h1
-rw-r--r--include/asm-i386/kprobes.h1
-rw-r--r--include/asm-i386/mach-default/do_timer.h2
-rw-r--r--include/asm-i386/mach-default/io_ports.h5
-rw-r--r--include/asm-i386/mach-default/irq_vectors_limits.h2
-rw-r--r--include/asm-i386/mach-default/mach_reboot.h25
-rw-r--r--include/asm-i386/mach-voyager/do_timer.h2
-rw-r--r--include/asm-i386/mc146818rtc.h5
-rw-r--r--include/asm-i386/mce.h4
-rw-r--r--include/asm-i386/mmu_context.h2
-rw-r--r--include/asm-i386/nmi.h2
-rw-r--r--include/asm-i386/page.h4
-rw-r--r--include/asm-i386/paravirt.h22
-rw-r--r--include/asm-i386/pci.h42
-rw-r--r--include/asm-i386/percpu.h5
-rw-r--r--include/asm-i386/pgalloc.h6
-rw-r--r--include/asm-i386/pgtable-2level.h8
-rw-r--r--include/asm-i386/pgtable-3level.h17
-rw-r--r--include/asm-i386/pgtable.h40
-rw-r--r--include/asm-i386/processor-cyrix.h30
-rw-r--r--include/asm-i386/processor.h17
-rw-r--r--include/asm-i386/required-features.h41
-rw-r--r--include/asm-i386/resume-trace.h13
-rw-r--r--include/asm-i386/setup.h14
-rw-r--r--include/asm-i386/smp.h5
-rw-r--r--include/asm-i386/string.h243
-rw-r--r--include/asm-i386/system.h9
-rw-r--r--include/asm-i386/thread_info.h5
-rw-r--r--include/asm-i386/timer.h34
-rw-r--r--include/asm-i386/tlbflush.h6
-rw-r--r--include/asm-i386/topology.h2
-rw-r--r--include/asm-i386/tsc.h1
-rw-r--r--include/asm-i386/uaccess.h2
-rw-r--r--include/asm-i386/unistd.h3
-rw-r--r--include/asm-i386/vmi_time.h2
-rw-r--r--include/asm-i386/xen/hypercall.h413
-rw-r--r--include/asm-i386/xen/hypervisor.h73
-rw-r--r--include/asm-i386/xen/interface.h188
-rw-r--r--include/asm-ia64/compat.h2
-rw-r--r--include/asm-ia64/fb.h23
-rw-r--r--include/asm-ia64/hw_irq.h18
-rw-r--r--include/asm-ia64/ioctls.h4
-rw-r--r--include/asm-ia64/iosapic.h6
-rw-r--r--include/asm-ia64/irq.h12
-rw-r--r--include/asm-ia64/kprobes.h2
-rw-r--r--include/asm-ia64/mca.h1
-rw-r--r--include/asm-ia64/page.h13
-rw-r--r--include/asm-ia64/pci.h22
-rw-r--r--include/asm-ia64/percpu.h10
-rw-r--r--include/asm-ia64/pgtable.h26
-rw-r--r--include/asm-ia64/processor.h4
-rw-r--r--include/asm-ia64/rwsem.h4
-rw-r--r--include/asm-ia64/sn/sn_sal.h20
-rw-r--r--include/asm-ia64/system.h1
-rw-r--r--include/asm-ia64/termbits.h5
-rw-r--r--include/asm-ia64/termios.h6
-rw-r--r--include/asm-ia64/unistd.h2
-rw-r--r--include/asm-ia64/ustack.h1
-rw-r--r--include/asm-m32r/a.out.h1
-rw-r--r--include/asm-m32r/dma-mapping.h6
-rw-r--r--include/asm-m32r/fb.h19
-rw-r--r--include/asm-m32r/ioctls.h4
-rw-r--r--include/asm-m32r/page.h3
-rw-r--r--include/asm-m32r/pgtable.h40
-rw-r--r--include/asm-m32r/system.h10
-rw-r--r--include/asm-m32r/termbits.h5
-rw-r--r--include/asm-m32r/termios.h6
-rw-r--r--include/asm-m68k/a.out.h1
-rw-r--r--include/asm-m68k/atari_SLM.h28
-rw-r--r--include/asm-m68k/atari_acsi.h37
-rw-r--r--include/asm-m68k/fb.h34
-rw-r--r--include/asm-m68k/io.h75
-rw-r--r--include/asm-m68k/irq.h3
-rw-r--r--include/asm-m68k/motorola_pgtable.h6
-rw-r--r--include/asm-m68k/pci.h4
-rw-r--r--include/asm-m68k/raw_io.h8
-rw-r--r--include/asm-m68k/sun3_pgtable.h6
-rw-r--r--include/asm-m68knommu/fb.h12
-rw-r--r--include/asm-m68knommu/irq.h75
-rw-r--r--include/asm-m68knommu/irqnode.h36
-rw-r--r--include/asm-m68knommu/m68360.h8
-rw-r--r--include/asm-m68knommu/page.h3
-rw-r--r--include/asm-m68knommu/pci.h10
-rw-r--r--include/asm-m68knommu/pgtable.h1
-rw-r--r--include/asm-m68knommu/traps.h4
-rw-r--r--include/asm-m68knommu/uaccess.h11
-rw-r--r--include/asm-mips/a.out.h1
-rw-r--r--include/asm-mips/atomic.h33
-rw-r--r--include/asm-mips/barrier.h9
-rw-r--r--include/asm-mips/bitops.h10
-rw-r--r--include/asm-mips/compat.h5
-rw-r--r--include/asm-mips/dec/serial.h36
-rw-r--r--include/asm-mips/ds1216.h31
-rw-r--r--include/asm-mips/fb.h19
-rw-r--r--include/asm-mips/futex.h8
-rw-r--r--include/asm-mips/gfx.h55
-rw-r--r--include/asm-mips/io.h3
-rw-r--r--include/asm-mips/irq.h2
-rw-r--r--include/asm-mips/mach-cobalt/cpu-feature-overrides.h4
-rw-r--r--include/asm-mips/mach-excite/cpu-feature-overrides.h3
-rw-r--r--include/asm-mips/mach-ip22/cpu-feature-overrides.h4
-rw-r--r--include/asm-mips/mach-ip27/cpu-feature-overrides.h4
-rw-r--r--include/asm-mips/mach-ip32/cpu-feature-overrides.h4
-rw-r--r--include/asm-mips/mach-qemu/cpu-feature-overrides.h3
-rw-r--r--include/asm-mips/mach-rm/cpu-feature-overrides.h4
-rw-r--r--include/asm-mips/mach-sibyte/cpu-feature-overrides.h4
-rw-r--r--include/asm-mips/mach-tx49xx/ioremap.h3
-rw-r--r--include/asm-mips/mach-yosemite/cpu-feature-overrides.h4
-rw-r--r--include/asm-mips/mipsregs.h20
-rw-r--r--include/asm-mips/pci.h18
-rw-r--r--include/asm-mips/pgtable.h34
-rw-r--r--include/asm-mips/rtc.h73
-rw-r--r--include/asm-mips/sibyte/bcm1480_regs.h30
-rw-r--r--include/asm-mips/sibyte/sb1250_regs.h76
-rw-r--r--include/asm-mips/sibyte/sb1250_uart.h7
-rw-r--r--include/asm-mips/spinlock.h18
-rw-r--r--include/asm-mips/system.h20
-rw-r--r--include/asm-mips/tlbdebug.h4
-rw-r--r--include/asm-mips/vr41xx/giu.h9
-rw-r--r--include/asm-mips/vr41xx/siu.h2
-rw-r--r--include/asm-parisc/a.out.h1
-rw-r--r--include/asm-parisc/compat.h2
-rw-r--r--include/asm-parisc/fb.h19
-rw-r--r--include/asm-parisc/fcntl.h29
-rw-r--r--include/asm-parisc/pci.h7
-rw-r--r--include/asm-parisc/pgtable.h20
-rw-r--r--include/asm-parisc/system.h11
-rw-r--r--include/asm-powerpc/a.out.h3
-rw-r--r--include/asm-powerpc/cache.h4
-rw-r--r--include/asm-powerpc/compat.h2
-rw-r--r--include/asm-powerpc/cputable.h111
-rw-r--r--include/asm-powerpc/dma-mapping.h1
-rw-r--r--include/asm-powerpc/fb.h21
-rw-r--r--include/asm-powerpc/floppy.h6
-rw-r--r--include/asm-powerpc/hvcall.h1
-rw-r--r--include/asm-powerpc/io.h26
-rw-r--r--include/asm-powerpc/irq.h9
-rw-r--r--include/asm-powerpc/kprobes.h6
-rw-r--r--include/asm-powerpc/lppaca.h2
-rw-r--r--include/asm-powerpc/lv1call.h3
-rw-r--r--include/asm-powerpc/machdep.h2
-rw-r--r--include/asm-powerpc/mmu-8xx.h147
-rw-r--r--include/asm-powerpc/mmu-fsl-booke.h88
-rw-r--r--include/asm-powerpc/mmu-hash32.h91
-rw-r--r--include/asm-powerpc/mmu-hash64.h9
-rw-r--r--include/asm-powerpc/mmu.h13
-rw-r--r--include/asm-powerpc/mmu_context.h202
-rw-r--r--include/asm-powerpc/mpc86xx.h6
-rw-r--r--include/asm-powerpc/mpc8xx.h4
-rw-r--r--include/asm-powerpc/mpic.h3
-rw-r--r--include/asm-powerpc/of_device.h22
-rw-r--r--include/asm-powerpc/of_platform.h38
-rw-r--r--include/asm-powerpc/oprofile_impl.h10
-rw-r--r--include/asm-powerpc/pci-bridge.h148
-rw-r--r--include/asm-powerpc/pci.h31
-rw-r--r--include/asm-powerpc/percpu.h7
-rw-r--r--include/asm-powerpc/pgtable-ppc32.h67
-rw-r--r--include/asm-powerpc/pgtable-ppc64.h91
-rw-r--r--include/asm-powerpc/pgtable.h28
-rw-r--r--include/asm-powerpc/pmi.h8
-rw-r--r--include/asm-powerpc/ppc-pci.h9
-rw-r--r--include/asm-powerpc/processor.h8
-rw-r--r--include/asm-powerpc/prom.h58
-rw-r--r--include/asm-powerpc/ps3.h182
-rw-r--r--include/asm-powerpc/ps3av.h48
-rw-r--r--include/asm-powerpc/ps3fb.h12
-rw-r--r--include/asm-powerpc/ps3stor.h71
-rw-r--r--include/asm-powerpc/ptrace.h22
-rw-r--r--include/asm-powerpc/reg.h2
-rw-r--r--include/asm-powerpc/spu.h76
-rw-r--r--include/asm-powerpc/spu_csa.h8
-rw-r--r--include/asm-powerpc/syscalls.h7
-rw-r--r--include/asm-powerpc/systbl.h1
-rw-r--r--include/asm-powerpc/system.h14
-rw-r--r--include/asm-powerpc/termbits.h4
-rw-r--r--include/asm-powerpc/thread_info.h12
-rw-r--r--include/asm-powerpc/time.h4
-rw-r--r--include/asm-powerpc/tlbflush.h5
-rw-r--r--include/asm-powerpc/unistd.h3
-rw-r--r--include/asm-ppc/pci.h8
-rw-r--r--include/asm-ppc/pgtable.h17
-rw-r--r--include/asm-ppc/system.h11
-rw-r--r--include/asm-s390/a.out.h1
-rw-r--r--include/asm-s390/compat.h2
-rw-r--r--include/asm-s390/dma-mapping.h12
-rw-r--r--include/asm-s390/fb.h12
-rw-r--r--include/asm-s390/kprobes.h2
-rw-r--r--include/asm-s390/page.h3
-rw-r--r--include/asm-s390/percpu.h7
-rw-r--r--include/asm-s390/pgtable.h66
-rw-r--r--include/asm-s390/system.h10
-rw-r--r--include/asm-sh/a.out.h1
-rw-r--r--include/asm-sh/bugs.h4
-rw-r--r--include/asm-sh/cache.h4
-rw-r--r--include/asm-sh/clock.h1
-rw-r--r--include/asm-sh/cpu-sh2/cache.h20
-rw-r--r--include/asm-sh/cpu-sh3/timer.h4
-rw-r--r--include/asm-sh/cpu-sh4/freq.h2
-rw-r--r--include/asm-sh/cpu-sh4/timer.h57
-rw-r--r--include/asm-sh/fb.h19
-rw-r--r--include/asm-sh/futex-irq.h111
-rw-r--r--include/asm-sh/futex.h79
-rw-r--r--include/asm-sh/hd64461.h397
-rw-r--r--include/asm-sh/hw_irq.h113
-rw-r--r--include/asm-sh/irq.h40
-rw-r--r--include/asm-sh/machvec.h4
-rw-r--r--include/asm-sh/machvec_init.h53
-rw-r--r--include/asm-sh/mmzone.h46
-rw-r--r--include/asm-sh/page.h10
-rw-r--r--include/asm-sh/parport.h16
-rw-r--r--include/asm-sh/pci.h9
-rw-r--r--include/asm-sh/pgtable.h12
-rw-r--r--include/asm-sh/processor.h8
-rw-r--r--include/asm-sh/rwsem.h6
-rw-r--r--include/asm-sh/saturn/io.h19
-rw-r--r--include/asm-sh/saturn/smpc.h34
-rw-r--r--include/asm-sh/se7722.h40
-rw-r--r--include/asm-sh/sections.h2
-rw-r--r--include/asm-sh/setup.h1
-rw-r--r--include/asm-sh/sh03/io.h4
-rw-r--r--include/asm-sh/smp.h2
-rw-r--r--include/asm-sh/snapgear.h4
-rw-r--r--include/asm-sh/sparsemem.h16
-rw-r--r--include/asm-sh/system.h26
-rw-r--r--include/asm-sh/topology.h30
-rw-r--r--include/asm-sh/uaccess.h40
-rw-r--r--include/asm-sh/ubc.h9
-rw-r--r--include/asm-sh/unistd.h3
-rw-r--r--include/asm-sh64/a.out.h1
-rw-r--r--include/asm-sh64/fb.h19
-rw-r--r--include/asm-sh64/irq.h4
-rw-r--r--include/asm-sh64/pci.h9
-rw-r--r--include/asm-sh64/pgtable.h7
-rw-r--r--include/asm-sh64/unistd.h3
-rw-r--r--include/asm-sparc/a.out.h1
-rw-r--r--include/asm-sparc/device.h14
-rw-r--r--include/asm-sparc/fb.h21
-rw-r--r--include/asm-sparc/irq.h166
-rw-r--r--include/asm-sparc/of_device.h49
-rw-r--r--include/asm-sparc/of_platform.h32
-rw-r--r--include/asm-sparc/oplib.h26
-rw-r--r--include/asm-sparc/pci.h6
-rw-r--r--include/asm-sparc/pgtable.h5
-rw-r--r--include/asm-sparc/prom.h66
-rw-r--r--include/asm-sparc/system.h10
-rw-r--r--include/asm-sparc/unistd.h6
-rw-r--r--include/asm-sparc64/a.out.h2
-rw-r--r--include/asm-sparc64/bugs.h5
-rw-r--r--include/asm-sparc64/compat.h2
-rw-r--r--include/asm-sparc64/cpudata.h5
-rw-r--r--include/asm-sparc64/delay.h32
-rw-r--r--include/asm-sparc64/fb.h27
-rw-r--r--include/asm-sparc64/hvtramp.h37
-rw-r--r--include/asm-sparc64/hypervisor.h2
-rw-r--r--include/asm-sparc64/io.h5
-rw-r--r--include/asm-sparc64/irq.h2
-rw-r--r--include/asm-sparc64/kprobes.h1
-rw-r--r--include/asm-sparc64/ldc.h138
-rw-r--r--include/asm-sparc64/mdesc.h92
-rw-r--r--include/asm-sparc64/mmu_context.h3
-rw-r--r--include/asm-sparc64/of_device.h50
-rw-r--r--include/asm-sparc64/of_platform.h33
-rw-r--r--include/asm-sparc64/oplib.h28
-rw-r--r--include/asm-sparc64/parport.h233
-rw-r--r--include/asm-sparc64/pci.h47
-rw-r--r--include/asm-sparc64/percpu.h7
-rw-r--r--include/asm-sparc64/pgtable.h18
-rw-r--r--include/asm-sparc64/prom.h66
-rw-r--r--include/asm-sparc64/smp.h11
-rw-r--r--include/asm-sparc64/system.h16
-rw-r--r--include/asm-sparc64/unistd.h6
-rw-r--r--include/asm-sparc64/vio.h406
-rw-r--r--include/asm-um/a.out.h2
-rw-r--r--include/asm-um/pgtable.h18
-rw-r--r--include/asm-um/thread_info.h15
-rw-r--r--include/asm-v850/fb.h12
-rw-r--r--include/asm-v850/ioctls.h4
-rw-r--r--include/asm-v850/irq.h10
-rw-r--r--include/asm-v850/pci.h4
-rw-r--r--include/asm-v850/rte_cb.h1
-rw-r--r--include/asm-v850/termbits.h5
-rw-r--r--include/asm-v850/termios.h6
-rw-r--r--include/asm-x86_64/a.out.h3
-rw-r--r--include/asm-x86_64/acpi.h11
-rw-r--r--include/asm-x86_64/alternative.h70
-rw-r--r--include/asm-x86_64/apic.h6
-rw-r--r--include/asm-x86_64/auxvec.h2
-rw-r--r--include/asm-x86_64/boot.h16
-rw-r--r--include/asm-x86_64/bootparam.h1
-rw-r--r--include/asm-x86_64/calgary.h9
-rw-r--r--include/asm-x86_64/cmpxchg.h2
-rw-r--r--include/asm-x86_64/compat.h2
-rw-r--r--include/asm-x86_64/cpufeature.h115
-rw-r--r--include/asm-x86_64/dmi.h5
-rw-r--r--include/asm-x86_64/e820.h4
-rw-r--r--include/asm-x86_64/elf.h13
-rw-r--r--include/asm-x86_64/fb.h19
-rw-r--r--include/asm-x86_64/fixmap.h10
-rw-r--r--include/asm-x86_64/hpet.h62
-rw-r--r--include/asm-x86_64/hw_irq.h20
-rw-r--r--include/asm-x86_64/hypertransport.h43
-rw-r--r--include/asm-x86_64/i8253.h6
-rw-r--r--include/asm-x86_64/io.h1
-rw-r--r--include/asm-x86_64/iommu.h29
-rw-r--r--include/asm-x86_64/kprobes.h1
-rw-r--r--include/asm-x86_64/mce.h5
-rw-r--r--include/asm-x86_64/mmu.h1
-rw-r--r--include/asm-x86_64/msidef.h48
-rw-r--r--include/asm-x86_64/nmi.h2
-rw-r--r--include/asm-x86_64/page.h3
-rw-r--r--include/asm-x86_64/pci.h63
-rw-r--r--include/asm-x86_64/percpu.h7
-rw-r--r--include/asm-x86_64/pgalloc.h73
-rw-r--r--include/asm-x86_64/pgtable.h17
-rw-r--r--include/asm-x86_64/processor.h15
-rw-r--r--include/asm-x86_64/proto.h20
-rw-r--r--include/asm-x86_64/ptrace.h1
-rw-r--r--include/asm-x86_64/required-features.h46
-rw-r--r--include/asm-x86_64/resume-trace.h13
-rw-r--r--include/asm-x86_64/segment.h8
-rw-r--r--include/asm-x86_64/string.h5
-rw-r--r--include/asm-x86_64/system.h45
-rw-r--r--include/asm-x86_64/thread_info.h2
-rw-r--r--include/asm-x86_64/timex.h1
-rw-r--r--include/asm-x86_64/tlbflush.h6
-rw-r--r--include/asm-x86_64/topology.h2
-rw-r--r--include/asm-x86_64/unistd.h2
-rw-r--r--include/asm-x86_64/vgtod.h29
-rw-r--r--include/asm-x86_64/vsyscall.h3
-rw-r--r--include/asm-xtensa/a.out.h1
-rw-r--r--include/asm-xtensa/fb.h12
-rw-r--r--include/asm-xtensa/pci.h7
-rw-r--r--include/asm-xtensa/pgtable.h15
-rw-r--r--include/linux/Kbuild3
-rw-r--r--include/linux/acpi.h7
-rw-r--r--include/linux/aer.h10
-rw-r--r--include/linux/aio.h2
-rw-r--r--include/linux/async_tx.h150
-rw-r--r--include/linux/ata.h38
-rw-r--r--include/linux/attribute_container.h1
-rw-r--r--include/linux/audit.h43
-rw-r--r--include/linux/backing-dev.h1
-rw-r--r--include/linux/backlight.h11
-rw-r--r--include/linux/binfmts.h19
-rw-r--r--include/linux/blkdev.h23
-rw-r--r--include/linux/bsg.h69
-rw-r--r--include/linux/buffer_head.h2
-rw-r--r--include/linux/bug.h7
-rw-r--r--include/linux/capability.h1
-rw-r--r--include/linux/cdrom.h4
-rw-r--r--include/linux/clockchips.h5
-rw-r--r--include/linux/clocksource.h6
-rw-r--r--include/linux/cobalt-nvram.h109
-rw-r--r--include/linux/coda_linux.h4
-rw-r--r--include/linux/coda_proc.h76
-rw-r--r--include/linux/coda_psdev.h15
-rw-r--r--include/linux/compiler-gcc4.h18
-rw-r--r--include/linux/compiler.h9
-rw-r--r--include/linux/configfs.h34
-rw-r--r--include/linux/console.h3
-rw-r--r--include/linux/consolemap.h5
-rw-r--r--include/linux/cpu.h1
-rw-r--r--include/linux/crc7.h14
-rw-r--r--include/linux/crypto.h20
-rw-r--r--include/linux/dcookies.h1
-rw-r--r--include/linux/debugfs.h9
-rw-r--r--include/linux/device.h15
-rw-r--r--include/linux/dma-mapping.h4
-rw-r--r--include/linux/dmaengine.h293
-rw-r--r--include/linux/dmi.h8
-rw-r--r--include/linux/ds17287rtc.h1
-rw-r--r--include/linux/edac.h29
-rw-r--r--include/linux/edd.h4
-rw-r--r--include/linux/efs_fs.h1
-rw-r--r--include/linux/elf-em.h3
-rw-r--r--include/linux/elfnote.h22
-rw-r--r--include/linux/etherdevice.h9
-rw-r--r--include/linux/ethtool.h1
-rw-r--r--include/linux/exportfs.h126
-rw-r--r--include/linux/ext2_fs_sb.h2
-rw-r--r--include/linux/ext3_fs_sb.h2
-rw-r--r--include/linux/ext4_fs.h104
-rw-r--r--include/linux/ext4_fs_extents.h43
-rw-r--r--include/linux/ext4_fs_i.h5
-rw-r--r--include/linux/ext4_fs_sb.h5
-rw-r--r--include/linux/falloc.h6
-rw-r--r--include/linux/fb.h3
-rw-r--r--include/linux/file.h1
-rw-r--r--include/linux/freezer.h23
-rw-r--r--include/linux/fs.h166
-rw-r--r--include/linux/fsl_devices.h8
-rw-r--r--include/linux/fuse.h2
-rw-r--r--include/linux/genetlink.h13
-rw-r--r--include/linux/gfp.h19
-rw-r--r--include/linux/highmem.h36
-rw-r--r--include/linux/hrtimer.h5
-rw-r--r--include/linux/hugetlb.h2
-rw-r--r--include/linux/i2c-id.h7
-rw-r--r--include/linux/i2c-isa.h36
-rw-r--r--include/linux/i2c.h20
-rw-r--r--include/linux/i2o.h8
-rw-r--r--include/linux/ide.h31
-rw-r--r--include/linux/idr.h32
-rw-r--r--include/linux/ieee80211.h11
-rw-r--r--include/linux/if_link.h47
-rw-r--r--include/linux/if_macvlan.h9
-rw-r--r--include/linux/if_ppp.h16
-rw-r--r--include/linux/if_pppol2tp.h69
-rw-r--r--include/linux/if_pppox.h16
-rw-r--r--include/linux/if_tun.h2
-rw-r--r--include/linux/if_vlan.h19
-rw-r--r--include/linux/init.h12
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/input.h3
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--include/linux/io.h29
-rw-r--r--include/linux/ioprio.h8
-rw-r--r--include/linux/ip_mp_alg.h22
-rw-r--r--include/linux/ipc.h12
-rw-r--r--include/linux/ipv6.h10
-rw-r--r--include/linux/irda.h29
-rw-r--r--include/linux/irq.h1
-rw-r--r--include/linux/jbd2.h6
-rw-r--r--include/linux/kallsyms.h6
-rw-r--r--include/linux/kernel.h9
-rw-r--r--include/linux/kernelcapi.h2
-rw-r--r--include/linux/kmod.h52
-rw-r--r--include/linux/kobject.h34
-rw-r--r--include/linux/kprobes.h6
-rw-r--r--include/linux/ktime.h10
-rw-r--r--include/linux/lcd.h14
-rw-r--r--include/linux/leds.h18
-rw-r--r--include/linux/lguest.h85
-rw-r--r--include/linux/lguest_bus.h48
-rw-r--r--include/linux/lguest_launcher.h73
-rw-r--r--include/linux/libata.h48
-rw-r--r--include/linux/limits.h2
-rw-r--r--include/linux/linux_logo.h8
-rw-r--r--include/linux/lockd/bind.h9
-rw-r--r--include/linux/lockd/lockd.h1
-rw-r--r--include/linux/lockdep.h71
-rw-r--r--include/linux/lzo.h2
-rw-r--r--include/linux/magic.h1
-rw-r--r--include/linux/major.h2
-rw-r--r--include/linux/mempolicy.h6
-rw-r--r--include/linux/mlx4/device.h2
-rw-r--r--include/linux/mlx4/qp.h3
-rw-r--r--include/linux/mm.h148
-rw-r--r--include/linux/mmzone.h33
-rw-r--r--include/linux/mnt_namespace.h2
-rw-r--r--include/linux/module.h1
-rw-r--r--include/linux/msdos_fs.h2
-rw-r--r--include/linux/namei.h4
-rw-r--r--include/linux/ncp_fs.h2
-rw-r--r--include/linux/netdevice.h141
-rw-r--r--include/linux/netfilter.h3
-rw-r--r--include/linux/netfilter/nf_conntrack_pptp.h2
-rw-r--r--include/linux/netfilter/x_tables.h36
-rw-r--r--include/linux/netfilter/xt_connlimit.h17
-rw-r--r--include/linux/netfilter/xt_u32.h40
-rw-r--r--include/linux/netfilter_ipv4/ipt_CLUSTERIP.h4
-rw-r--r--include/linux/netfilter_ipv4/ipt_iprange.h2
-rw-r--r--include/linux/netfilter_ipv6/ip6_tables.h10
-rw-r--r--include/linux/netlink.h2
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs4_mount.h3
-rw-r--r--include/linux/nfs_fs.h32
-rw-r--r--include/linux/nfs_fs_sb.h8
-rw-r--r--include/linux/nfs_mount.h3
-rw-r--r--include/linux/nfs_page.h25
-rw-r--r--include/linux/nfs_xdr.h37
-rw-r--r--include/linux/nfsd/export.h30
-rw-r--r--include/linux/nfsd/interface.h13
-rw-r--r--include/linux/nfsd/nfsd.h9
-rw-r--r--include/linux/nfsd/state.h3
-rw-r--r--include/linux/nfsd/xdr4.h7
-rw-r--r--include/linux/notifier.h9
-rw-r--r--include/linux/nsproxy.h3
-rw-r--r--include/linux/of.h61
-rw-r--r--include/linux/of_device.h26
-rw-r--r--include/linux/of_platform.h57
-rw-r--r--include/linux/oprofile.h35
-rw-r--r--include/linux/page-flags.h50
-rw-r--r--include/linux/pci.h20
-rw-r--r--include/linux/pci_ids.h85
-rw-r--r--include/linux/percpu.h2
-rw-r--r--include/linux/percpu_counter.h18
-rw-r--r--include/linux/pid_namespace.h2
-rw-r--r--include/linux/pkt_cls.h17
-rw-r--r--include/linux/pkt_sched.h9
-rw-r--r--include/linux/pm.h17
-rw-r--r--include/linux/prctl.h4
-rw-r--r--include/linux/prefetch.h2
-rw-r--r--include/linux/proc_fs.h13
-rw-r--r--include/linux/ptrace.h2
-rw-r--r--include/linux/raid/bitmap.h6
-rw-r--r--include/linux/raid/md_k.h2
-rw-r--r--include/linux/raid/raid5.h97
-rw-r--r--include/linux/raid/xor.h5
-rw-r--r--include/linux/reboot.h5
-rw-r--r--include/linux/resume-trace.h19
-rw-r--r--include/linux/rtc/m48t59.h57
-rw-r--r--include/linux/rtnetlink.h20
-rw-r--r--include/linux/sched.h41
-rw-r--r--include/linux/screen_info.h9
-rw-r--r--include/linux/scx200_gpio.h2
-rw-r--r--include/linux/seccomp.h19
-rw-r--r--include/linux/security.h17
-rw-r--r--include/linux/serial.h6
-rw-r--r--include/linux/serial_8250.h6
-rw-r--r--include/linux/serial_core.h8
-rw-r--r--include/linux/serio.h2
-rw-r--r--include/linux/signal.h4
-rw-r--r--include/linux/skbuff.h67
-rw-r--r--include/linux/slab.h153
-rw-r--r--include/linux/slab_def.h38
-rw-r--r--include/linux/slob_def.h36
-rw-r--r--include/linux/slub_def.h35
-rw-r--r--include/linux/smp.h13
-rw-r--r--include/linux/smp_lock.h1
-rw-r--r--include/linux/socket.h4
-rw-r--r--include/linux/sonypi.h2
-rw-r--r--include/linux/spi/ads7846.h14
-rw-r--r--include/linux/spi/spi.h1
-rw-r--r--include/linux/spi/spi_bitbang.h1
-rw-r--r--include/linux/spi/tle62x0.h24
-rw-r--r--include/linux/spinlock.h7
-rw-r--r--include/linux/spinlock_types.h4
-rw-r--r--include/linux/spinlock_types_up.h9
-rw-r--r--include/linux/stacktrace.h2
-rw-r--r--include/linux/string.h4
-rw-r--r--include/linux/sunrpc/auth.h48
-rw-r--r--include/linux/sunrpc/auth_gss.h6
-rw-r--r--include/linux/sunrpc/clnt.h33
-rw-r--r--include/linux/sunrpc/gss_api.h3
-rw-r--r--include/linux/sunrpc/rpc_pipe_fs.h2
-rw-r--r--include/linux/sunrpc/sched.h6
-rw-r--r--include/linux/sunrpc/svc.h2
-rw-r--r--include/linux/sunrpc/svcauth.h1
-rw-r--r--include/linux/sunrpc/svcauth_gss.h1
-rw-r--r--include/linux/sunrpc/svcsock.h1
-rw-r--r--include/linux/sunrpc/xdr.h16
-rw-r--r--include/linux/sunrpc/xprt.h16
-rw-r--r--include/linux/suspend.h52
-rw-r--r--include/linux/swap.h3
-rw-r--r--include/linux/syscalls.h3
-rw-r--r--include/linux/sysdev.h3
-rw-r--r--include/linux/sysfs.h43
-rw-r--r--include/linux/taskstats.h5
-rw-r--r--include/linux/time.h8
-rw-r--r--include/linux/timer.h16
-rw-r--r--include/linux/timex.h60
-rw-r--r--include/linux/topology.h2
-rw-r--r--include/linux/tty.h39
-rw-r--r--include/linux/udp.h6
-rw-r--r--include/linux/uio.h9
-rw-r--r--include/linux/uio_driver.h91
-rw-r--r--include/linux/usb.h69
-rw-r--r--include/linux/usb/Kbuild1
-rw-r--r--include/linux/usb/gadgetfs.h (renamed from include/linux/usb_gadgetfs.h)24
-rw-r--r--include/linux/usb/quirks.h3
-rw-r--r--include/linux/usb/serial.h7
-rw-r--r--include/linux/usb_gadget.h48
-rw-r--r--include/linux/user_namespace.h61
-rw-r--r--include/linux/utsname.h16
-rw-r--r--include/linux/videodev2.h1
-rw-r--r--include/linux/vmalloc.h14
-rw-r--r--include/linux/vmstat.h5
-rw-r--r--include/linux/vt_kern.h2
-rw-r--r--include/linux/workqueue.h15
-rw-r--r--include/media/saa7146.h6
-rw-r--r--include/media/tuner.h71
-rw-r--r--include/mtd/ubi-header.h101
-rw-r--r--include/net/9p/9p.h417
-rw-r--r--include/net/9p/client.h80
-rw-r--r--include/net/9p/conn.h (renamed from fs/9p/mux.h)42
-rw-r--r--include/net/9p/transport.h (renamed from fs/9p/transport.h)28
-rw-r--r--include/net/act_api.h32
-rw-r--r--include/net/addrconf.h2
-rw-r--r--include/net/af_unix.h3
-rw-r--r--include/net/bluetooth/hci.h18
-rw-r--r--include/net/bluetooth/hci_core.h5
-rw-r--r--include/net/bluetooth/rfcomm.h1
-rw-r--r--include/net/cfg80211.h38
-rw-r--r--include/net/dn.h1
-rw-r--r--include/net/dst.h1
-rw-r--r--include/net/flow.h4
-rw-r--r--include/net/genetlink.h22
-rw-r--r--include/net/inet_timewait_sock.h3
-rw-r--r--include/net/ip_fib.h16
-rw-r--r--include/net/ip_mp_alg.h96
-rw-r--r--include/net/ipv6.h4
-rw-r--r--include/net/irda/irda.h3
-rw-r--r--include/net/irda/irlap.h2
-rw-r--r--include/net/iucv/af_iucv.h1
-rw-r--r--include/net/mac80211.h22
-rw-r--r--include/net/mip6.h4
-rw-r--r--include/net/netfilter/ipv4/nf_conntrack_ipv4.h25
-rw-r--r--include/net/netfilter/ipv6/nf_conntrack_ipv6.h2
-rw-r--r--include/net/netfilter/nf_conntrack.h70
-rw-r--r--include/net/netfilter/nf_conntrack_core.h11
-rw-r--r--include/net/netfilter/nf_conntrack_ecache.h17
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h42
-rw-r--r--include/net/netfilter/nf_conntrack_extend.h85
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h16
-rw-r--r--include/net/netfilter/nf_conntrack_l3proto.h10
-rw-r--r--include/net/netfilter/nf_conntrack_tuple.h78
-rw-r--r--include/net/netfilter/nf_nat.h28
-rw-r--r--include/net/netfilter/nf_nat_core.h1
-rw-r--r--include/net/netlabel.h62
-rw-r--r--include/net/netlink.h84
-rw-r--r--include/net/pkt_cls.h10
-rw-r--r--include/net/pkt_sched.h4
-rw-r--r--include/net/rawv6.h9
-rw-r--r--include/net/route.h3
-rw-r--r--include/net/rtnetlink.h58
-rw-r--r--include/net/sch_generic.h2
-rw-r--r--include/net/scm.h2
-rw-r--r--include/net/tcp.h6
-rw-r--r--include/net/tipc/tipc_port.h6
-rw-r--r--include/net/xfrm.h22
-rw-r--r--include/rdma/ib_cm.h1
-rw-r--r--include/rdma/ib_mad.h3
-rw-r--r--include/scsi/iscsi_if.h34
-rw-r--r--include/scsi/libiscsi.h67
-rw-r--r--include/scsi/libsas.h15
-rw-r--r--include/scsi/sas_ata.h60
-rw-r--r--include/scsi/scsi_cmnd.h20
-rw-r--r--include/scsi/scsi_device.h2
-rw-r--r--include/scsi/scsi_host.h12
-rw-r--r--include/scsi/scsi_transport_fc.h186
-rw-r--r--include/scsi/scsi_transport_iscsi.h16
-rw-r--r--include/scsi/scsi_transport_sas.h11
-rw-r--r--include/sound/ak4xxx-adda.h1
-rw-r--r--include/sound/cs46xx.h4
-rw-r--r--include/sound/cs46xx_dsp_spos.h2
-rw-r--r--include/sound/emu10k1.h16
-rw-r--r--include/sound/sb.h1
-rw-r--r--include/sound/version.h2
-rw-r--r--include/sound/wavefront_fx.h9
-rw-r--r--include/video/tgafb.h1
-rw-r--r--include/xen/events.h48
-rw-r--r--include/xen/features.h23
-rw-r--r--include/xen/grant_table.h107
-rw-r--r--include/xen/hvc-console.h6
-rw-r--r--include/xen/interface/elfnote.h133
-rw-r--r--include/xen/interface/event_channel.h195
-rw-r--r--include/xen/interface/features.h43
-rw-r--r--include/xen/interface/grant_table.h375
-rw-r--r--include/xen/interface/io/blkif.h94
-rw-r--r--include/xen/interface/io/console.h23
-rw-r--r--include/xen/interface/io/netif.h158
-rw-r--r--include/xen/interface/io/ring.h260
-rw-r--r--include/xen/interface/io/xenbus.h44
-rw-r--r--include/xen/interface/io/xs_wire.h87
-rw-r--r--include/xen/interface/memory.h145
-rw-r--r--include/xen/interface/physdev.h145
-rw-r--r--include/xen/interface/sched.h77
-rw-r--r--include/xen/interface/vcpu.h167
-rw-r--r--include/xen/interface/version.h60
-rw-r--r--include/xen/interface/xen.h447
-rw-r--r--include/xen/page.h179
-rw-r--r--include/xen/xenbus.h234
-rw-r--r--init/Kconfig29
-rw-r--r--init/do_mounts.c24
-rw-r--r--init/do_mounts_initrd.c7
-rw-r--r--init/main.c59
-rw-r--r--ipc/mqueue.c2
-rw-r--r--ipc/msg.c8
-rw-r--r--ipc/sem.c6
-rw-r--r--ipc/shm.c12
-rw-r--r--ipc/util.c11
-rw-r--r--ipc/util.h8
-rw-r--r--kernel/Makefile6
-rw-r--r--kernel/audit.c97
-rw-r--r--kernel/audit.h1
-rw-r--r--kernel/auditfilter.c25
-rw-r--r--kernel/auditsc.c140
-rw-r--r--kernel/cpu.c16
-rw-r--r--kernel/cpuset.c11
-rw-r--r--kernel/exit.c40
-rw-r--r--kernel/fork.c31
-rw-r--r--kernel/futex.c159
-rw-r--r--kernel/hrtimer.c17
-rw-r--r--kernel/irq/proc.c10
-rw-r--r--kernel/irq/spurious.c12
-rw-r--r--kernel/kallsyms.c27
-rw-r--r--kernel/kfifo.c3
-rw-r--r--kernel/kmod.c303
-rw-r--r--kernel/kprobes.c9
-rw-r--r--kernel/ksysfs.c28
-rw-r--r--kernel/kthread.c2
-rw-r--r--kernel/lockdep.c1501
-rw-r--r--kernel/lockdep_proc.c301
-rw-r--r--kernel/module.c72
-rw-r--r--kernel/mutex.c8
-rw-r--r--kernel/nsproxy.c72
-rw-r--r--kernel/panic.c5
-rw-r--r--kernel/params.c1
-rw-r--r--kernel/pid.c2
-rw-r--r--kernel/posix-timers.c2
-rw-r--r--kernel/power/Kconfig29
-rw-r--r--kernel/power/disk.c251
-rw-r--r--kernel/power/main.c108
-rw-r--r--kernel/power/power.h29
-rw-r--r--kernel/power/process.c90
-rw-r--r--kernel/power/swap.c20
-rw-r--r--kernel/power/user.c154
-rw-r--r--kernel/printk.c55
-rw-r--r--kernel/ptrace.c28
-rw-r--r--kernel/rcutorture.c4
-rw-r--r--kernel/relay.c19
-rw-r--r--kernel/rtmutex-debug.c6
-rw-r--r--kernel/rtmutex-tester.c1
-rw-r--r--kernel/rtmutex.c6
-rw-r--r--kernel/rtmutex_common.h9
-rw-r--r--kernel/rwsem.c8
-rw-r--r--kernel/sched.c91
-rw-r--r--kernel/sched_debug.c2
-rw-r--r--kernel/seccomp.c29
-rw-r--r--kernel/signal.c43
-rw-r--r--kernel/softirq.c9
-rw-r--r--kernel/softlockup.c2
-rw-r--r--kernel/spinlock.c32
-rw-r--r--kernel/stop_machine.c8
-rw-r--r--kernel/sys.c104
-rw-r--r--kernel/sys_ni.c1
-rw-r--r--kernel/sysctl.c121
-rw-r--r--kernel/taskstats.c4
-rw-r--r--kernel/time.c79
-rw-r--r--kernel/time/clockevents.c41
-rw-r--r--kernel/time/ntp.c71
-rw-r--r--kernel/time/tick-broadcast.c35
-rw-r--r--kernel/time/tick-common.c16
-rw-r--r--kernel/time/tick-oneshot.c15
-rw-r--r--kernel/time/tick-sched.c7
-rw-r--r--kernel/time/timekeeping.c45
-rw-r--r--kernel/time/timer_list.c2
-rw-r--r--kernel/time/timer_stats.c16
-rw-r--r--kernel/timer.c231
-rw-r--r--kernel/user.c20
-rw-r--r--kernel/user_namespace.c87
-rw-r--r--kernel/utsname.c12
-rw-r--r--kernel/utsname_sysctl.c5
-rw-r--r--kernel/workqueue.c60
-rw-r--r--lib/Kconfig8
-rw-r--r--lib/Kconfig.debug24
-rw-r--r--lib/Makefile5
-rw-r--r--lib/argv_split.c105
-rw-r--r--lib/bug.c5
-rw-r--r--lib/check_signature.c26
-rw-r--r--lib/crc7.c68
-rw-r--r--lib/genalloc.c3
-rw-r--r--lib/idr.c436
-rw-r--r--lib/kobject.c19
-rw-r--r--lib/kobject_uevent.c32
-rw-r--r--lib/percpu_counter.c68
-rw-r--r--lib/radix-tree.c3
-rw-r--r--lib/swiotlb.c5
-rw-r--r--lib/vsprintf.c173
-rw-r--r--mm/Kconfig10
-rw-r--r--mm/Makefile4
-rw-r--r--mm/allocpercpu.c9
-rw-r--r--mm/backing-dev.c16
-rw-r--r--mm/filemap.c404
-rw-r--r--mm/filemap_xip.c41
-rw-r--r--mm/fremap.c179
-rw-r--r--mm/highmem.c7
-rw-r--r--mm/hugetlb.c80
-rw-r--r--mm/madvise.c6
-rw-r--r--mm/memory.c341
-rw-r--r--mm/mempolicy.c65
-rw-r--r--mm/mempool.c6
-rw-r--r--mm/migrate.c3
-rw-r--r--mm/mlock.c5
-rw-r--r--mm/mmap.c98
-rw-r--r--mm/mprotect.c2
-rw-r--r--mm/mremap.c15
-rw-r--r--mm/nommu.c57
-rw-r--r--mm/page-writeback.c33
-rw-r--r--mm/page_alloc.c631
-rw-r--r--mm/pdflush.c1
-rw-r--r--mm/readahead.c516
-rw-r--r--mm/rmap.c6
-rw-r--r--mm/shmem.c94
-rw-r--r--mm/slab.c141
-rw-r--r--mm/slob.c600
-rw-r--r--mm/slub.c753
-rw-r--r--mm/sparse.c2
-rw-r--r--mm/swap_state.c5
-rw-r--r--mm/swapfile.c2
-rw-r--r--mm/truncate.c59
-rw-r--r--mm/util.c74
-rw-r--r--mm/vmalloc.c78
-rw-r--r--mm/vmscan.c212
-rw-r--r--mm/vmstat.c2
-rw-r--r--net/802/tr.c2
-rw-r--r--net/8021q/Makefile2
-rw-r--r--net/8021q/vlan.c496
-rw-r--r--net/8021q/vlan.h25
-rw-r--r--net/8021q/vlan_dev.c378
-rw-r--r--net/8021q/vlan_netlink.c243
-rw-r--r--net/8021q/vlanproc.c6
-rw-r--r--net/9p/Kconfig21
-rw-r--r--net/9p/Makefile13
-rw-r--r--net/9p/client.c965
-rw-r--r--net/9p/conv.c (renamed from fs/9p/conv.c)424
-rw-r--r--net/9p/error.c (renamed from fs/9p/error.h)79
-rw-r--r--net/9p/fcprint.c (renamed from fs/9p/fcprint.c)187
-rw-r--r--net/9p/mod.c85
-rw-r--r--net/9p/mux.c (renamed from fs/9p/mux.c)515
-rw-r--r--net/9p/sysctl.c81
-rw-r--r--net/9p/trans_fd.c363
-rw-r--r--net/9p/util.c125
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile2
-rw-r--r--net/appletalk/aarp.c2
-rw-r--r--net/appletalk/atalk_proc.c6
-rw-r--r--net/atm/br2684.c28
-rw-r--r--net/atm/clip.c2
-rw-r--r--net/atm/lec.c2
-rw-r--r--net/atm/mpoa_proc.c2
-rw-r--r--net/atm/proc.c10
-rw-r--r--net/ax25/af_ax25.c4
-rw-r--r--net/ax25/ax25_route.c2
-rw-r--r--net/ax25/ax25_uid.c2
-rw-r--r--net/bluetooth/bnep/core.c2
-rw-r--r--net/bluetooth/cmtp/core.c2
-rw-r--r--net/bluetooth/hci_conn.c51
-rw-r--r--net/bluetooth/hci_core.c100
-rw-r--r--net/bluetooth/hci_event.c29
-rw-r--r--net/bluetooth/hidp/core.c2
-rw-r--r--net/bluetooth/rfcomm/core.c2
-rw-r--r--net/bluetooth/rfcomm/tty.c34
-rw-r--r--net/bridge/br_fdb.c2
-rw-r--r--net/bridge/br_if.c10
-rw-r--r--net/bridge/br_stp_if.c2
-rw-r--r--net/bridge/br_sysfs_br.c8
-rw-r--r--net/bridge/br_sysfs_if.c3
-rw-r--r--net/bridge/netfilter/ebtables.c4
-rw-r--r--net/compat.c3
-rw-r--r--net/core/dev.c431
-rw-r--r--net/core/dev_mcast.c200
-rw-r--r--net/core/ethtool.c12
-rw-r--r--net/core/flow.c2
-rw-r--r--net/core/gen_estimator.c82
-rw-r--r--net/core/neighbour.c2
-rw-r--r--net/core/netpoll.c10
-rw-r--r--net/core/pktgen.c251
-rw-r--r--net/core/rtnetlink.c470
-rw-r--r--net/core/scm.c3
-rw-r--r--net/core/skbuff.c17
-rw-r--r--net/core/sock.c74
-rw-r--r--net/dccp/ackvec.c4
-rw-r--r--net/dccp/ccid.c2
-rw-r--r--net/dccp/ccids/ccid3.c212
-rw-r--r--net/dccp/ccids/ccid3.h5
-rw-r--r--net/dccp/ccids/lib/loss_interval.c246
-rw-r--r--net/dccp/ccids/lib/loss_interval.h46
-rw-r--r--net/dccp/ccids/lib/packet_history.c4
-rw-r--r--net/dccp/dccp.h4
-rw-r--r--net/dccp/ipv6.c20
-rw-r--r--net/dccp/probe.c2
-rw-r--r--net/dccp/proto.c2
-rw-r--r--net/decnet/af_decnet.c2
-rw-r--r--net/decnet/dn_dev.c5
-rw-r--r--net/decnet/dn_neigh.c2
-rw-r--r--net/decnet/dn_route.c4
-rw-r--r--net/decnet/dn_table.c2
-rw-r--r--net/ethernet/eth.c12
-rw-r--r--net/ieee80211/ieee80211_wx.c7
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c5
-rw-r--r--net/ipv4/Kconfig42
-rw-r--r--net/ipv4/Makefile5
-rw-r--r--net/ipv4/af_inet.c3
-rw-r--r--net/ipv4/ah4.c1
-rw-r--r--net/ipv4/arp.c2
-rw-r--r--net/ipv4/esp4.c1
-rw-r--r--net/ipv4/fib_frontend.c6
-rw-r--r--net/ipv4/fib_hash.c4
-rw-r--r--net/ipv4/fib_semantics.c16
-rw-r--r--net/ipv4/fib_trie.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c5
-rw-r--r--net/ipv4/inetpeer.c6
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_gre.c3
-rw-r--r--net/ipv4/ip_output.c6
-rw-r--r--net/ipv4/ipcomp.c1
-rw-r--r--net/ipv4/ipip.c3
-rw-r--r--net/ipv4/ipmr.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_app.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_conn.c4
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c2
-rw-r--r--net/ipv4/multipath.c55
-rw-r--r--net/ipv4/multipath_drr.c249
-rw-r--r--net/ipv4/multipath_random.c114
-rw-r--r--net/ipv4/multipath_rr.c95
-rw-r--r--net/ipv4/multipath_wrandom.c329
-rw-r--r--net/ipv4/netfilter/Kconfig2
-rw-r--r--net/ipv4/netfilter/arp_tables.c8
-rw-r--r--net/ipv4/netfilter/arpt_mangle.c10
-rw-r--r--net/ipv4/netfilter/ip_tables.c177
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c118
-rw-r--r--net/ipv4/netfilter/ipt_ECN.c36
-rw-r--r--net/ipv4/netfilter/ipt_LOG.c56
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c30
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c23
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c20
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c30
-rw-r--r--net/ipv4/netfilter/ipt_SAME.c69
-rw-r--r--net/ipv4/netfilter/ipt_TOS.c8
-rw-r--r--net/ipv4/netfilter/ipt_TTL.c14
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c68
-rw-r--r--net/ipv4/netfilter/ipt_addrtype.c14
-rw-r--r--net/ipv4/netfilter/ipt_ah.c25
-rw-r--r--net/ipv4/netfilter/ipt_ecn.c59
-rw-r--r--net/ipv4/netfilter/ipt_iprange.c50
-rw-r--r--net/ipv4/netfilter/ipt_owner.c20
-rw-r--r--net/ipv4/netfilter/ipt_recent.c45
-rw-r--r--net/ipv4/netfilter/ipt_tos.c6
-rw-r--r--net/ipv4/netfilter/ipt_ttl.c26
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c61
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c115
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c71
-rw-r--r--net/ipv4/netfilter/nf_nat_amanda.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_core.c127
-rw-r--r--net/ipv4/netfilter/nf_nat_ftp.c18
-rw-r--r--net/ipv4/netfilter/nf_nat_h323.c121
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c59
-rw-r--r--net/ipv4/netfilter/nf_nat_irc.c17
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c43
-rw-r--r--net/ipv4/netfilter/nf_nat_proto_gre.c17
-rw-r--r--net/ipv4/netfilter/nf_nat_rule.c48
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c18
-rw-r--r--net/ipv4/netfilter/nf_nat_snmp_basic.c6
-rw-r--r--net/ipv4/netfilter/nf_nat_standalone.c47
-rw-r--r--net/ipv4/netfilter/nf_nat_tftp.c2
-rw-r--r--net/ipv4/route.c263
-rw-r--r--net/ipv4/tcp.c28
-rw-r--r--net/ipv4/tcp_bic.c2
-rw-r--r--net/ipv4/tcp_cong.c3
-rw-r--r--net/ipv4/tcp_cubic.c2
-rw-r--r--net/ipv4/tcp_highspeed.c2
-rw-r--r--net/ipv4/tcp_htcp.c2
-rw-r--r--net/ipv4/tcp_hybla.c4
-rw-r--r--net/ipv4/tcp_illinois.c2
-rw-r--r--net/ipv4/tcp_input.c12
-rw-r--r--net/ipv4/tcp_ipv4.c19
-rw-r--r--net/ipv4/tcp_lp.c5
-rw-r--r--net/ipv4/tcp_output.c10
-rw-r--r--net/ipv4/tcp_probe.c197
-rw-r--r--net/ipv4/tcp_scalable.c2
-rw-r--r--net/ipv4/tcp_vegas.c6
-rw-r--r--net/ipv4/tcp_veno.c6
-rw-r--r--net/ipv4/tcp_yeah.c2
-rw-r--r--net/ipv4/udp.c140
-rw-r--r--net/ipv4/xfrm4_input.c114
-rw-r--r--net/ipv4/xfrm4_tunnel.c1
-rw-r--r--net/ipv6/Kconfig2
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/addrconf.c10
-rw-r--r--net/ipv6/af_inet6.c10
-rw-r--r--net/ipv6/ah6.c13
-rw-r--r--net/ipv6/anycast.c2
-rw-r--r--net/ipv6/datagram.c5
-rw-r--r--net/ipv6/esp6.c1
-rw-r--r--net/ipv6/exthdrs.c140
-rw-r--r--net/ipv6/icmp.c4
-rw-r--r--net/ipv6/ip6_fib.c2
-rw-r--r--net/ipv6/ip6_flowlabel.c2
-rw-r--r--net/ipv6/ip6_output.c6
-rw-r--r--net/ipv6/ip6_tunnel.c8
-rw-r--r--net/ipv6/ipcomp6.c2
-rw-r--r--net/ipv6/ipv6_sockglue.c15
-rw-r--r--net/ipv6/mcast.c4
-rw-r--r--net/ipv6/mip6.c24
-rw-r--r--net/ipv6/netfilter/ip6_tables.c202
-rw-r--r--net/ipv6/netfilter/ip6t_HL.c14
-rw-r--r--net/ipv6/netfilter/ip6t_LOG.c57
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c45
-rw-r--r--net/ipv6/netfilter/ip6t_ah.c82
-rw-r--r--net/ipv6/netfilter/ip6t_eui64.c20
-rw-r--r--net/ipv6/netfilter/ip6t_frag.c111
-rw-r--r--net/ipv6/netfilter/ip6t_hbh.c88
-rw-r--r--net/ipv6/netfilter/ip6t_hl.c22
-rw-r--r--net/ipv6/netfilter/ip6t_ipv6header.c22
-rw-r--r--net/ipv6/netfilter/ip6t_mh.c30
-rw-r--r--net/ipv6/netfilter/ip6t_owner.c26
-rw-r--r--net/ipv6/netfilter/ip6t_rt.c134
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c6
-rw-r--r--net/ipv6/netfilter/ip6table_raw.c6
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c47
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c60
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c52
-rw-r--r--net/ipv6/raw.c40
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/ipv6/sit.c3
-rw-r--r--net/ipv6/tcp_ipv6.c20
-rw-r--r--net/ipv6/xfrm6_policy.c4
-rw-r--r--net/ipv6/xfrm6_state.c4
-rw-r--r--net/ipv6/xfrm6_tunnel.c3
-rw-r--r--net/ipx/ipx_proc.c6
-rw-r--r--net/irda/Makefile2
-rw-r--r--net/irda/af_irda.c2
-rw-r--r--net/irda/discovery.c2
-rw-r--r--net/irda/ircomm/ircomm_core.c2
-rw-r--r--net/irda/irda_device.c4
-rw-r--r--net/irda/iriap.c4
-rw-r--r--net/irda/irias_object.c43
-rw-r--r--net/irda/irlan/irlan_common.c2
-rw-r--r--net/irda/irlap.c4
-rw-r--r--net/irda/irlap_frame.c7
-rw-r--r--net/irda/irlmp.c4
-rw-r--r--net/irda/irmod.c48
-rw-r--r--net/irda/irnetlink.c170
-rw-r--r--net/irda/irproc.c2
-rw-r--r--net/irda/irsysctl.c2
-rw-r--r--net/irda/irttp.c33
-rw-r--r--net/iucv/Kconfig8
-rw-r--r--net/iucv/af_iucv.c16
-rw-r--r--net/iucv/iucv.c5
-rw-r--r--net/llc/llc_proc.c4
-rw-r--r--net/mac80211/Makefile1
-rw-r--r--net/mac80211/debugfs_netdev.c11
-rw-r--r--net/mac80211/hostapd_ioctl.h8
-rw-r--r--net/mac80211/ieee80211.c452
-rw-r--r--net/mac80211/ieee80211_common.h9
-rw-r--r--net/mac80211/ieee80211_i.h19
-rw-r--r--net/mac80211/ieee80211_iface.c3
-rw-r--r--net/mac80211/ieee80211_ioctl.c392
-rw-r--r--net/mac80211/ieee80211_rate.c3
-rw-r--r--net/mac80211/ieee80211_sta.c107
-rw-r--r--net/mac80211/rc80211_simple.c20
-rw-r--r--net/mac80211/regdomain.c158
-rw-r--r--net/netfilter/Kconfig43
-rw-r--r--net/netfilter/Makefile6
-rw-r--r--net/netfilter/core.c10
-rw-r--r--net/netfilter/nf_conntrack_amanda.c17
-rw-r--r--net/netfilter/nf_conntrack_core.c550
-rw-r--r--net/netfilter/nf_conntrack_ecache.c16
-rw-r--r--net/netfilter/nf_conntrack_expect.c367
-rw-r--r--net/netfilter/nf_conntrack_extend.c195
-rw-r--r--net/netfilter/nf_conntrack_ftp.c143
-rw-r--r--net/netfilter/nf_conntrack_h323_asn1.c18
-rw-r--r--net/netfilter/nf_conntrack_h323_main.c307
-rw-r--r--net/netfilter/nf_conntrack_helper.c131
-rw-r--r--net/netfilter/nf_conntrack_irc.c39
-rw-r--r--net/netfilter/nf_conntrack_l3proto_generic.c22
-rw-r--r--net/netfilter/nf_conntrack_netbios_ns.c12
-rw-r--r--net/netfilter/nf_conntrack_netlink.c182
-rw-r--r--net/netfilter/nf_conntrack_pptp.c120
-rw-r--r--net/netfilter/nf_conntrack_proto_generic.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c30
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c99
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c133
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c4
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c266
-rw-r--r--net/netfilter/nf_conntrack_sane.c45
-rw-r--r--net/netfilter/nf_conntrack_sip.c37
-rw-r--r--net/netfilter/nf_conntrack_standalone.c52
-rw-r--r--net/netfilter/nf_conntrack_tftp.c32
-rw-r--r--net/netfilter/nf_log.c4
-rw-r--r--net/netfilter/nf_queue.c59
-rw-r--r--net/netfilter/nfnetlink_log.c2
-rw-r--r--net/netfilter/nfnetlink_queue.c6
-rw-r--r--net/netfilter/x_tables.c11
-rw-r--r--net/netfilter/xt_CLASSIFY.c2
-rw-r--r--net/netfilter/xt_CONNMARK.c18
-rw-r--r--net/netfilter/xt_CONNSECMARK.c18
-rw-r--r--net/netfilter/xt_DSCP.c18
-rw-r--r--net/netfilter/xt_MARK.c24
-rw-r--r--net/netfilter/xt_NFLOG.c12
-rw-r--r--net/netfilter/xt_NFQUEUE.c2
-rw-r--r--net/netfilter/xt_NOTRACK.c2
-rw-r--r--net/netfilter/xt_SECMARK.c26
-rw-r--r--net/netfilter/xt_TCPMSS.c28
-rw-r--r--net/netfilter/xt_TRACE.c53
-rw-r--r--net/netfilter/xt_comment.c8
-rw-r--r--net/netfilter/xt_connbytes.c32
-rw-r--r--net/netfilter/xt_connlimit.c313
-rw-r--r--net/netfilter/xt_connmark.c26
-rw-r--r--net/netfilter/xt_conntrack.c42
-rw-r--r--net/netfilter/xt_dccp.c50
-rw-r--r--net/netfilter/xt_dscp.c48
-rw-r--r--net/netfilter/xt_esp.c24
-rw-r--r--net/netfilter/xt_hashlimit.c67
-rw-r--r--net/netfilter/xt_helper.c61
-rw-r--r--net/netfilter/xt_length.c14
-rw-r--r--net/netfilter/xt_limit.c23
-rw-r--r--net/netfilter/xt_mac.c16
-rw-r--r--net/netfilter/xt_mark.c16
-rw-r--r--net/netfilter/xt_multiport.c54
-rw-r--r--net/netfilter/xt_physdev.c48
-rw-r--r--net/netfilter/xt_pkttype.c10
-rw-r--r--net/netfilter/xt_policy.c50
-rw-r--r--net/netfilter/xt_quota.c21
-rw-r--r--net/netfilter/xt_realm.c8
-rw-r--r--net/netfilter/xt_sctp.c61
-rw-r--r--net/netfilter/xt_state.c20
-rw-r--r--net/netfilter/xt_statistic.c20
-rw-r--r--net/netfilter/xt_string.c38
-rw-r--r--net/netfilter/xt_tcpmss.c10
-rw-r--r--net/netfilter/xt_tcpudp.c63
-rw-r--r--net/netfilter/xt_u32.c135
-rw-r--r--net/netlabel/netlabel_cipso_v4.c5
-rw-r--r--net/netlabel/netlabel_kapi.c21
-rw-r--r--net/netlabel/netlabel_mgmt.c65
-rw-r--r--net/netlabel/netlabel_mgmt.h5
-rw-r--r--net/netlabel/netlabel_user.c4
-rw-r--r--net/netlink/af_netlink.c168
-rw-r--r--net/netlink/attr.c11
-rw-r--r--net/netlink/genetlink.c235
-rw-r--r--net/netrom/af_netrom.c4
-rw-r--r--net/netrom/nr_route.c4
-rw-r--r--net/packet/af_packet.c4
-rw-r--r--net/rfkill/rfkill-input.c4
-rw-r--r--net/rfkill/rfkill.c2
-rw-r--r--net/rose/af_rose.c4
-rw-r--r--net/rose/rose_route.c6
-rw-r--r--net/rxrpc/af_rxrpc.c12
-rw-r--r--net/rxrpc/ar-proc.c52
-rw-r--r--net/sched/Kconfig37
-rw-r--r--net/sched/Makefile1
-rw-r--r--net/sched/act_api.c23
-rw-r--r--net/sched/act_gact.c11
-rw-r--r--net/sched/act_ipt.c12
-rw-r--r--net/sched/act_mirred.c12
-rw-r--r--net/sched/act_pedit.c11
-rw-r--r--net/sched/act_police.c278
-rw-r--r--net/sched/act_simple.c1
-rw-r--r--net/sched/cls_api.c50
-rw-r--r--net/sched/cls_basic.c1
-rw-r--r--net/sched/cls_fw.c19
-rw-r--r--net/sched/cls_route.c20
-rw-r--r--net/sched/cls_rsvp.c17
-rw-r--r--net/sched/cls_rsvp6.c16
-rw-r--r--net/sched/cls_tcindex.c3
-rw-r--r--net/sched/cls_u32.c21
-rw-r--r--net/sched/em_cmp.c1
-rw-r--r--net/sched/em_meta.c2
-rw-r--r--net/sched/em_nbyte.c2
-rw-r--r--net/sched/em_text.c2
-rw-r--r--net/sched/em_u32.c2
-rw-r--r--net/sched/ematch.c15
-rw-r--r--net/sched/sch_api.c91
-rw-r--r--net/sched/sch_atm.c478
-rw-r--r--net/sched/sch_blackhole.c1
-rw-r--r--net/sched/sch_cbq.c82
-rw-r--r--net/sched/sch_dsmark.c35
-rw-r--r--net/sched/sch_fifo.c1
-rw-r--r--net/sched/sch_generic.c219
-rw-r--r--net/sched/sch_gred.c1
-rw-r--r--net/sched/sch_hfsc.c24
-rw-r--r--net/sched/sch_htb.c126
-rw-r--r--net/sched/sch_ingress.c28
-rw-r--r--net/sched/sch_netem.c2
-rw-r--r--net/sched/sch_prio.c145
-rw-r--r--net/sched/sch_red.c1
-rw-r--r--net/sched/sch_sfq.c18
-rw-r--r--net/sched/sch_tbf.c21
-rw-r--r--net/sched/sch_teql.c24
-rw-r--r--net/sctp/proc.c4
-rw-r--r--net/sctp/protocol.c4
-rw-r--r--net/sctp/sm_statefuns.c2
-rw-r--r--net/sctp/socket.c4
-rw-r--r--net/socket.c7
-rw-r--r--net/sunrpc/auth.c362
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c349
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c3
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c14
-rw-r--r--net/sunrpc/auth_gss/gss_spkm3_mech.c3
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c32
-rw-r--r--net/sunrpc/auth_null.c10
-rw-r--r--net/sunrpc/auth_unix.c54
-rw-r--r--net/sunrpc/cache.c2
-rw-r--r--net/sunrpc/clnt.c371
-rw-r--r--net/sunrpc/rpc_pipe.c98
-rw-r--r--net/sunrpc/rpcb_clnt.c65
-rw-r--r--net/sunrpc/sched.c213
-rw-r--r--net/sunrpc/sunrpc_syms.c8
-rw-r--r--net/sunrpc/svcauth_unix.c7
-rw-r--r--net/sunrpc/svcsock.c20
-rw-r--r--net/sunrpc/xprt.c19
-rw-r--r--net/sunrpc/xprtsock.c81
-rw-r--r--net/tipc/eth_media.c11
-rw-r--r--net/tipc/handler.c2
-rw-r--r--net/tipc/link.c16
-rw-r--r--net/tipc/name_table.c3
-rw-r--r--net/tipc/port.c10
-rw-r--r--net/tipc/port.h6
-rw-r--r--net/tipc/socket.c80
-rw-r--r--net/unix/af_unix.c8
-rw-r--r--net/unix/garbage.c325
-rw-r--r--net/wanrouter/wanproc.c4
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/radiotap.c257
-rw-r--r--net/x25/x25_proc.c6
-rw-r--r--net/xfrm/xfrm_input.c2
-rw-r--r--net/xfrm/xfrm_policy.c6
-rw-r--r--net/xfrm/xfrm_state.c33
-rw-r--r--scripts/Kbuild.include7
-rwxr-xr-xscripts/Lindent2
-rw-r--r--scripts/Makefile.build16
-rw-r--r--scripts/Makefile.headersinst14
-rw-r--r--scripts/Makefile.modpost4
-rwxr-xr-xscripts/checkpatch.pl535
-rwxr-xr-xscripts/cleanfile54
-rwxr-xr-xscripts/cleanpatch58
-rw-r--r--scripts/decodecode51
-rw-r--r--scripts/gcc-version.sh15
-rw-r--r--scripts/gen_initramfs_list.sh12
-rw-r--r--scripts/kallsyms.c21
-rw-r--r--scripts/kconfig/Makefile35
-rw-r--r--scripts/kconfig/confdata.c37
-rw-r--r--scripts/kconfig/kxgettext.c4
-rw-r--r--scripts/kconfig/lxdialog/check-lxdialog.sh2
-rw-r--r--scripts/kconfig/mconf.c11
-rwxr-xr-xscripts/kernel-doc28
-rw-r--r--scripts/mod/modpost.c313
-rw-r--r--scripts/mod/modpost.h3
-rw-r--r--security/commoncap.c2
-rw-r--r--security/dummy.c8
-rw-r--r--security/keys/key.c2
-rw-r--r--security/keys/request_key.c3
-rw-r--r--security/security.c1
-rw-r--r--security/selinux/avc.c29
-rw-r--r--security/selinux/hooks.c46
-rw-r--r--security/selinux/include/av_perm_to_string.h1
-rw-r--r--security/selinux/include/av_permissions.h1
-rw-r--r--security/selinux/include/avc.h6
-rw-r--r--security/selinux/include/class_to_string.h1
-rw-r--r--security/selinux/include/flask.h1
-rw-r--r--security/selinux/include/security.h4
-rw-r--r--security/selinux/netlabel.c49
-rw-r--r--security/selinux/nlmsgtab.c2
-rw-r--r--security/selinux/selinuxfs.c269
-rw-r--r--security/selinux/ss/avtab.c2
-rw-r--r--security/selinux/ss/policydb.c7
-rw-r--r--security/selinux/ss/services.c144
-rw-r--r--sound/Kconfig2
-rw-r--r--sound/Makefile2
-rw-r--r--sound/aoa/codecs/snd-aoa-codec-onyx.c4
-rw-r--r--sound/core/pcm_native.c2
-rw-r--r--sound/core/seq/seq_instr.c6
-rw-r--r--sound/core/seq/seq_virmidi.c3
-rw-r--r--sound/core/sound.c3
-rw-r--r--sound/core/timer.c27
-rw-r--r--sound/drivers/dummy.c2
-rw-r--r--sound/drivers/mpu401/mpu401.c2
-rw-r--r--sound/drivers/portman2x4.c2
-rw-r--r--sound/drivers/serial-u16550.c2
-rw-r--r--sound/drivers/virmidi.c2
-rw-r--r--sound/i2c/other/ak4xxx-adda.c24
-rw-r--r--sound/isa/Kconfig32
-rw-r--r--sound/isa/ad1848/ad1848_lib.c4
-rw-r--r--sound/isa/opl3sa2.c2
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c3
-rw-r--r--sound/isa/sb/Makefile15
-rw-r--r--sound/isa/sb/sb16_main.c10
-rw-r--r--sound/isa/sb/sb_common.c5
-rw-r--r--sound/isa/sb/sb_mixer.c3
-rw-r--r--sound/isa/sscape.c4
-rw-r--r--sound/isa/wavefront/wavefront_synth.c2
-rw-r--r--sound/oss/Kconfig80
-rw-r--r--sound/oss/Makefile13
-rw-r--r--sound/oss/ac97.c432
-rw-r--r--sound/oss/ac97.h201
-rw-r--r--sound/oss/aci.c712
-rw-r--r--sound/oss/aci.h57
-rw-r--r--sound/oss/ad1816.c1368
-rw-r--r--sound/oss/ad1889.c1101
-rw-r--r--sound/oss/ad1889.h135
-rw-r--r--sound/oss/adlib_card.c73
-rw-r--r--sound/oss/cs461x.h1691
-rw-r--r--sound/oss/cs461x_image.h322
-rw-r--r--sound/oss/cs46xx.c5444
-rw-r--r--sound/oss/cs46xx_wrapper-24.h56
-rw-r--r--sound/oss/cs46xxpm.h70
-rw-r--r--sound/oss/emu10k1/8010.h737
-rw-r--r--sound/oss/emu10k1/Makefile17
-rw-r--r--sound/oss/emu10k1/audio.c1595
-rw-r--r--sound/oss/emu10k1/audio.h44
-rw-r--r--sound/oss/emu10k1/cardmi.c832
-rw-r--r--sound/oss/emu10k1/cardmi.h97
-rw-r--r--sound/oss/emu10k1/cardmo.c229
-rw-r--r--sound/oss/emu10k1/cardmo.h62
-rw-r--r--sound/oss/emu10k1/cardwi.c384
-rw-r--r--sound/oss/emu10k1/cardwi.h91
-rw-r--r--sound/oss/emu10k1/cardwo.c643
-rw-r--r--sound/oss/emu10k1/cardwo.h90
-rw-r--r--sound/oss/emu10k1/ecard.c157
-rw-r--r--sound/oss/emu10k1/ecard.h113
-rw-r--r--sound/oss/emu10k1/efxmgr.c220
-rw-r--r--sound/oss/emu10k1/efxmgr.h270
-rw-r--r--sound/oss/emu10k1/emuadxmg.c104
-rw-r--r--sound/oss/emu10k1/hwaccess.c507
-rw-r--r--sound/oss/emu10k1/hwaccess.h247
-rw-r--r--sound/oss/emu10k1/icardmid.h163
-rw-r--r--sound/oss/emu10k1/icardwav.h53
-rw-r--r--sound/oss/emu10k1/irqmgr.c113
-rw-r--r--sound/oss/emu10k1/irqmgr.h52
-rw-r--r--sound/oss/emu10k1/main.c1471
-rw-r--r--sound/oss/emu10k1/midi.c614
-rw-r--r--sound/oss/emu10k1/midi.h78
-rw-r--r--sound/oss/emu10k1/mixer.c690
-rw-r--r--sound/oss/emu10k1/passthrough.c240
-rw-r--r--sound/oss/emu10k1/passthrough.h99
-rw-r--r--sound/oss/emu10k1/recmgr.c147
-rw-r--r--sound/oss/emu10k1/recmgr.h48
-rw-r--r--sound/oss/emu10k1/timer.c176
-rw-r--r--sound/oss/emu10k1/timer.h54
-rw-r--r--sound/oss/emu10k1/voicemgr.c398
-rw-r--r--sound/oss/emu10k1/voicemgr.h103
-rw-r--r--sound/oss/es1371.c2
-rw-r--r--sound/oss/mpu401.c7
-rw-r--r--sound/oss/nm256.h292
-rw-r--r--sound/oss/nm256_audio.c1662
-rw-r--r--sound/oss/nm256_coeff.h4697
-rw-r--r--sound/oss/opl3.c14
-rw-r--r--sound/oss/opl3.h5
-rw-r--r--sound/oss/opl3sa2.c1020
-rw-r--r--sound/oss/trident.c367
-rw-r--r--sound/pci/Kconfig11
-rw-r--r--sound/pci/Makefile2
-rw-r--r--sound/pci/ali5451/ali5451.c9
-rw-r--r--sound/pci/als300.c7
-rw-r--r--sound/pci/atiixp.c6
-rw-r--r--sound/pci/atiixp_modem.c5
-rw-r--r--sound/pci/au88x0/au88x0.c6
-rw-r--r--sound/pci/ca0106/ca0106.h1
-rw-r--r--sound/pci/ca0106/ca0106_main.c24
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c77
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.h3
-rw-r--r--sound/pci/cs46xx/dsp_spos.c170
-rw-r--r--sound/pci/cs5530.c306
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c129
-rw-r--r--sound/pci/emu10k1/emu10k1x.c2
-rw-r--r--sound/pci/emu10k1/emufx.c78
-rw-r--r--sound/pci/emu10k1/emumixer.c16
-rw-r--r--sound/pci/emu10k1/emupcm.c39
-rw-r--r--sound/pci/ens1370.c8
-rw-r--r--sound/pci/fm801.c4
-rw-r--r--sound/pci/hda/hda_intel.c53
-rw-r--r--sound/pci/hda/hda_proc.c6
-rw-r--r--sound/pci/hda/patch_analog.c630
-rw-r--r--sound/pci/hda/patch_atihdmi.c1
-rw-r--r--sound/pci/hda/patch_conexant.c2
-rw-r--r--sound/pci/hda/patch_realtek.c919
-rw-r--r--sound/pci/hda/patch_si3054.c4
-rw-r--r--sound/pci/hda/patch_sigmatel.c266
-rw-r--r--sound/pci/ice1712/revo.c7
-rw-r--r--sound/pci/mixart/mixart_hwdep.c1
-rw-r--r--sound/pci/nm256/nm256.c3
-rw-r--r--sound/pci/rme9652/rme9652.c2
-rw-r--r--sound/pci/via82xx.c18
-rw-r--r--sound/pci/via82xx_modem.c8
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c2
-rw-r--r--sound/ppc/Kconfig20
-rw-r--r--sound/ppc/Makefile3
-rw-r--r--sound/ppc/snd_ps3.c1125
-rw-r--r--sound/ppc/snd_ps3.h135
-rw-r--r--sound/ppc/snd_ps3_reg.h891
-rw-r--r--sound/sh/Kconfig14
-rw-r--r--sound/sh/Makefile8
-rw-r--r--sound/sh/aica.c665
-rw-r--r--sound/sh/aica.h81
-rw-r--r--sound/soc/Kconfig1
-rw-r--r--sound/soc/Makefile2
-rw-r--r--sound/soc/s3c24xx/Kconfig27
-rw-r--r--sound/soc/s3c24xx/Makefile9
-rw-r--r--sound/soc/s3c24xx/lm4857.h32
-rw-r--r--sound/soc/s3c24xx/neo1973_wm8753.c670
-rw-r--r--sound/soc/s3c24xx/s3c2443-ac97.c401
-rw-r--r--sound/soc/s3c24xx/s3c24xx-ac97.h25
-rw-r--r--sound/soc/s3c24xx/s3c24xx-i2s.c4
-rw-r--r--sound/soc/s3c24xx/smdk2443_wm9710.c85
-rw-r--r--sound/soc/sh/Kconfig38
-rw-r--r--sound/soc/sh/Makefile14
-rw-r--r--sound/soc/sh/dma-sh7760.c354
-rw-r--r--sound/soc/sh/hac.c322
-rw-r--r--sound/soc/sh/sh7760-ac97.c92
-rw-r--r--sound/soc/sh/ssi.c400
-rw-r--r--sound/usb/usbaudio.c22
-rw-r--r--sound/usb/usbquirks.h72
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c7
-rw-r--r--usr/.gitignore1
-rw-r--r--usr/gen_init_cpio.c4
5093 files changed, 284052 insertions, 165764 deletions
diff --git a/.gitignore b/.gitignore
index 060a71d41ad7..a232295b99ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,6 +22,7 @@
tags
TAGS
vmlinux*
+!vmlinux.lds.S
System.map
Module.symvers
@@ -45,3 +46,6 @@ series
# cscope files
cscope.*
+
+*.orig
+*.rej
diff --git a/CREDITS b/CREDITS
index 79fd13dbb8e4..10c214dc95e7 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2212,13 +2212,13 @@ S: 2300 Copenhagen S
S: Denmark
N: Claudio S. Matsuoka
-E: claudio@conectiva.com
-E: claudio@helllabs.org
+E: cmatsuoka@gmail.com
+E: claudio@mandriva.com
W: http://helllabs.org/~claudio
-D: V4L, OV511 driver hacks
+D: V4L, OV511 and HDA-codec hacks
S: Conectiva S.A.
-S: R. Tocantins 89
-S: 80050-430 Curitiba PR
+S: Souza Naves 1250
+S: 80050-040 Curitiba PR
S: Brazil
N: Heinz Mauelshagen
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index f08ca9535733..8b0563633442 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -12,6 +12,8 @@ Following translations are available on the WWW:
00-INDEX
- this file.
+ABI/
+ - info on kernel <-> userspace ABI and relative interface stability.
BUG-HUNTING
- brute force method of doing binary search of patches to find bug.
Changes
@@ -25,37 +27,57 @@ DMA-mapping.txt
DocBook/
- directory with DocBook templates etc. for kernel documentation.
HOWTO
- - The process and procedures of how to do Linux kernel development.
+ - the process and procedures of how to do Linux kernel development.
IO-mapping.txt
- how to access I/O mapped memory from within device drivers.
IPMI.txt
- info on Linux Intelligent Platform Management Interface (IPMI) Driver.
IRQ-affinity.txt
- how to select which CPU(s) handle which interrupt events on SMP.
+IRQ.txt
+ - description of what an IRQ is.
ManagementStyle
- how to (attempt to) manage kernel hackers.
MSI-HOWTO.txt
- the Message Signaled Interrupts (MSI) Driver Guide HOWTO and FAQ.
+PCIEBUS-HOWTO.txt
+ - a guide describing the PCI Express Port Bus driver.
RCU/
- directory with info on RCU (read-copy update).
README.DAC960
- info on Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux.
+README.cycladesZ
+ - info on Cyclades-Z firmware loading.
SAK.txt
- info on Secure Attention Keys.
+SecurityBugs
+ - procedure for reporting security bugs found in the kernel.
+SubmitChecklist
+ - Linux kernel patch submission checklist.
SubmittingDrivers
- procedure to get a new driver source included into the kernel tree.
SubmittingPatches
- procedure to get a source patch included into the kernel tree.
VGA-softcursor.txt
- how to change your VGA cursor from a blinking underscore.
+accounting/
+ - documentation on accounting and taskstats.
+aoe/
+ - description of AoE (ATA over Ethernet) along with config examples.
applying-patches.txt
- description of various trees and how to apply their patches.
arm/
- directory with info about Linux on the ARM architecture.
+atomic_ops.txt
+ - semantics and behavior of atomic and bitmask operations.
+auxdisplay/
+ - misc. LCD driver documentation (cfag12864b, ks0108).
basic_profiling.txt
- basic instructions for those who wants to profile Linux kernel.
binfmt_misc.txt
- info on the kernel support for extra binary formats.
+blackfin/
+ - directory with documentation for the Blackfin arch.
block/
- info on the Block I/O (BIO) layer.
cachetlb.txt
@@ -68,16 +90,32 @@ cli-sti-removal.txt
- cli()/sti() removal guide.
computone.txt
- info on Computone Intelliport II/Plus Multiport Serial Driver.
+connector/
+ - docs on the netlink based userspace<->kernel space communication mod.
+console/
+ - documentation on Linux console drivers.
cpqarray.txt
- info on using Compaq's SMART2 Intelligent Disk Array Controllers.
cpu-freq/
- info on CPU frequency and voltage scaling.
+cpu-hotplug.txt
+ - document describing CPU hotplug support in the Linux kernel.
+cpu-load.txt
+ - document describing how CPU load statistics are collected.
+cpusets.txt
+ - documents the cpusets feature; assign CPUs and Mem to a set of tasks.
+cputopology.txt
+ - documentation on how CPU topology info is exported via sysfs.
cris/
- directory with info about Linux on CRIS architecture.
crypto/
- directory with info on the Crypto API.
+dcdbas.txt
+ - information on the Dell Systems Management Base Driver.
debugging-modules.txt
- some notes on debugging modules after Linux 2.6.3.
+dell_rbu.txt
+ - document demonstrating the use of the Dell Remote BIOS Update driver.
device-mapper/
- directory with info on Device Mapper.
devices.txt
@@ -86,32 +124,52 @@ digiepca.txt
- info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
dnotify.txt
- info about directory notification in Linux.
+dontdiff
+ - file containing a list of files that should never be diff'ed.
driver-model/
- directory with info about Linux driver model.
+drivers/
+ - directory with driver documentation (currently only EDAC).
dvb/
- info on Linux Digital Video Broadcast (DVB) subsystem.
early-userspace/
- info about initramfs, klibc, and userspace early during boot.
+ecryptfs.txt
+ - docs on eCryptfs: stacked cryptographic filesystem for Linux.
eisa.txt
- info on EISA bus support.
exception.txt
- how Linux v2.2 handles exceptions without verify_area etc.
+fault-injection/
+ - dir with docs about the fault injection capabilities infrastructure.
fb/
- directory with info on the frame buffer graphics abstraction layer.
+feature-removal-schedule.txt
+ - list of files and features that are going to be removed.
filesystems/
- directory with info on the various filesystems that Linux supports.
firmware_class/
- request_firmware() hotplug interface info.
floppy.txt
- notes and driver options for the floppy disk driver.
+fujitsu/
+ - Fujitsu FR-V Linux documentation.
+gpio.txt
+ - overview of GPIO (General Purpose Input/Output) access conventions.
hayes-esp.txt
- info on using the Hayes ESP serial driver.
highuid.txt
- notes on the change from 16 bit to 32 bit user/group IDs.
hpet.txt
- High Precision Event Timer Driver for Linux.
+hrtimer/
+ - info on the timer_stats debugging facility for timer (ab)use.
+hrtimers/
+ - info on the hrtimers subsystem for high-resolution kernel timers.
hw_random.txt
- info on Linux support for random number generator in i8xx chipsets.
+hwmon/
+ - directory with docs on various hardware monitoring drivers.
i2c/
- directory with info about the I2C bus/protocol (2 wire, kHz speed).
i2o/
@@ -122,16 +180,22 @@ ia64/
- directory with info about Linux on Intel 64 bit architecture.
ide.txt
- important info for users of ATA devices (IDE/EIDE disks and CD-ROMS).
+infiniband/
+ - directory with documents concerning Linux InfiniBand support.
initrd.txt
- how to use the RAM disk as an initial/temporary root filesystem.
input/
- info on Linux input device support.
io_ordering.txt
- info on ordering I/O writes to memory-mapped addresses.
+ioctl/
+ - directory with documents describing various IOCTL calls.
ioctl-number.txt
- how to implement and register device/driver ioctl calls.
iostats.txt
- info on I/O statistics Linux kernel provides.
+irqflags-tracing.txt
+ - how to use the irq-flags tracing feature.
isapnp.txt
- info on Linux ISA Plug & Play support.
isdn/
@@ -140,26 +204,40 @@ java.txt
- info on the in-kernel binary support for Java(tm).
kbuild/
- directory with info about the kernel build process.
-kdumpt.txt
- - mini HowTo on getting the crash dump code to work.
+kdump/
+ - directory with mini HowTo on getting the crash dump code to work.
kernel-doc-nano-HOWTO.txt
- mini HowTo on generation and location of kernel documentation files.
kernel-docs.txt
- listing of various WWW + books that document kernel internals.
kernel-parameters.txt
- summary listing of command line / boot prompt args for the kernel.
+keys-request-key.txt
+ - description of the kernel key request service.
+keys.txt
+ - description of the kernel key retention service.
kobject.txt
- info of the kobject infrastructure of the Linux kernel.
+kprobes.txt
+ - documents the kernel probes debugging feature.
+kref.txt
+ - docs on adding reference counters (krefs) to kernel objects.
laptop-mode.txt
- - How to conserve battery power using laptop-mode.
+ - how to conserve battery power using laptop-mode.
ldm.txt
- a brief description of LDM (Windows Dynamic Disks).
+leds-class.txt
+ - documents LED handling under Linux.
+local_ops.txt
+ - semantics and behavior of local atomic operations.
+lockdep-design.txt
+ - documentation on the runtime locking correctness validator.
locks.txt
- info on file locking implementations, flock() vs. fcntl(), etc.
logo.gif
- - Full colour GIF image of Linux logo (penguin).
+ - full colour GIF image of Linux logo (penguin - Tux).
logo.txt
- - Info on creator of above logo & site to get additional images from.
+ - info on creator of above logo & site to get additional images from.
m68k/
- directory with info about Linux on Motorola 68k architecture.
magic-number.txt
@@ -170,6 +248,8 @@ mca.txt
- info on supporting Micro Channel Architecture (e.g. PS/2) systems.
md.txt
- info on boot arguments for the multiple devices driver.
+memory-barriers.txt
+ - info on Linux kernel memory barriers.
memory.txt
- info on typical Linux memory problems.
mips/
@@ -177,9 +257,11 @@ mips/
mono.txt
- how to execute Mono-based .NET binaries with the help of BINFMT_MISC.
moxa-smartio
- - info on installing/using Moxa multiport serial driver.
+ - file with info on installing/using Moxa multiport serial driver.
mtrr.txt
- how to use PPro Memory Type Range Registers to increase performance.
+mutex-design.txt
+ - info on the generic mutex subsystem.
nbd.txt
- info on a TCP implementation of a network block device.
netlabel/
@@ -190,6 +272,8 @@ nfsroot.txt
- short guide on setting up a diskless box with NFS root filesystem.
nmi_watchdog.txt
- info on NMI watchdog for SMP systems.
+nommu-mmap.txt
+ - documentation about no-mmu memory mapping support.
numastat.txt
- info on how to read Numa policy hit/miss statistics in sysfs.
oops-tracing.txt
@@ -202,8 +286,16 @@ parport.txt
- how to use the parallel-port driver.
parport-lowlevel.txt
- description and usage of the low level parallel port functions.
+pci-error-recovery.txt
+ - info on PCI error recovery.
pci.txt
- info on the PCI subsystem for device driver authors.
+pcieaer-howto.txt
+ - the PCI Express Advanced Error Reporting Driver Guide HOWTO.
+pcmcia/
+ - info on the Linux PCMCIA driver.
+pi-futex.txt
+ - documentation on lightweight PI-futexes.
pm.txt
- info on Linux power management support.
pnp.txt
@@ -214,18 +306,32 @@ powerpc/
- directory with info on using Linux with the PowerPC.
preempt-locking.txt
- info on locking under a preemptive kernel.
+prio_tree.txt
+ - info on radix-priority-search-tree use for indexing vmas.
ramdisk.txt
- short guide on how to set up and use the RAM disk.
+rbtree.txt
+ - info on what red-black trees are and what they are for.
riscom8.txt
- notes on using the RISCom/8 multi-port serial driver.
+robust-futex-ABI.txt
+ - documentation of the robust futex ABI.
+robust-futexes.txt
+ - a description of what robust futexes are.
rocket.txt
- info on the Comtrol RocketPort multiport serial driver.
rpc-cache.txt
- introduction to the caching mechanisms in the sunrpc layer.
+rt-mutex-design.txt
+ - description of the RealTime mutex implementation design.
+rt-mutex.txt
+ - desc. of RT-mutex subsystem with PI (Priority Inheritance) support.
rtc.txt
- notes on how to use the Real Time Clock (aka CMOS clock) driver.
s390/
- directory with info on using Linux on the IBM S390.
+sched-arch.txt
+ - CPU Scheduler implementation hints for architecture specific code.
sched-coding.txt
- reference for various scheduler-related methods in the O(1) scheduler.
sched-design.txt
@@ -240,22 +346,32 @@ serial/
- directory with info on the low level serial API.
serial-console.txt
- how to set up Linux with a serial line console as the default.
+sgi-ioc4.txt
+ - description of the SGI IOC4 PCI (multi function) device.
sgi-visws.txt
- short blurb on the SGI Visual Workstations.
sh/
- directory with info on porting Linux to a new architecture.
+sharedsubtree.txt
+ - a description of shared subtrees for namespaces.
smart-config.txt
- description of the Smart Config makefile feature.
smp.txt
- a few notes on symmetric multi-processing.
+sony-laptop.txt
+ - Sony Notebook Control Driver (SNC) Readme.
sonypi.txt
- info on Linux Sony Programmable I/O Device support.
sound/
- directory with info on sound card support.
sparc/
- directory with info on using Linux on Sparc architecture.
+sparse.txt
+ - info on how to obtain and use the sparse tool for typechecking.
specialix.txt
- info on hardware/driver for specialix IO8+ multiport serial card.
+spi/
+ - overview of Linux kernel Serial Peripheral Interface (SPI) support.
spinlocks.txt
- info on using spinlocks to provide exclusive access in kernel.
stable_api_nonsense.txt
@@ -274,24 +390,32 @@ sysrq.txt
- info on the magic SysRq key.
telephony/
- directory with info on telephony (e.g. voice over IP) support.
+thinkpad-acpi.txt
+ - information on the (IBM and Lenovo) ThinkPad ACPI Extras driver.
time_interpolators.txt
- info on time interpolators.
tipar.txt
- information about Parallel link cable for Texas Instruments handhelds.
tty.txt
- guide to the locking policies of the tty layer.
-unicode.txt
- - info on the Unicode character/font mapping used in Linux.
uml/
- directory with information about User Mode Linux.
+unicode.txt
+ - info on the Unicode character/font mapping used in Linux.
+unshare.txt
+ - description of the Linux unshare system call.
usb/
- directory with info regarding the Universal Serial Bus.
+video-output.txt
+ - sysfs class driver interface to enable/disable a video output device.
video4linux/
- directory with info regarding video/TV/radio cards and linux.
vm/
- directory with info on the Linux vm code.
voyager.txt
- guide to running Linux on the Voyager architecture.
+w1/
+ - directory with documents regarding the 1-wire (w1) subsystem.
watchdog/
- how to auto-reboot Linux if it has "fallen and can't get up". ;-)
x86_64/
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index f9937add033d..9734577d1711 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -39,3 +39,16 @@ Description:
If you want to suspend a device immediately but leave it
free to wake up in response to I/O requests, you should
write "0" to power/autosuspend.
+
+What: /sys/bus/usb/devices/.../power/persist
+Date: May 2007
+KernelVersion: 2.6.23
+Contact: Alan Stern <stern@rowland.harvard.edu>
+Description:
+ If CONFIG_USB_PERSIST is set, then each USB device directory
+ will contain a file named power/persist. The file holds a
+ boolean value (0 or 1) indicating whether or not the
+ "USB-Persist" facility is enabled for the device. Since the
+ facility is inherently dangerous, it is disabled by default
+ for all devices except hubs. For more information, see
+ Documentation/usb/persist.txt.
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index b49b92edb396..7f1730f1a1ae 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -218,6 +218,18 @@ no space after the prefix increment & decrement unary operators:
and no space around the '.' and "->" structure member operators.
+Do not leave trailing whitespace at the ends of lines. Some editors with
+"smart" indentation will insert whitespace at the beginning of new lines as
+appropriate, so you can start typing the next line of code right away.
+However, some such editors do not remove the whitespace if you end up not
+putting a line of code there, such as if you leave a blank line. As a result,
+you end up with lines containing trailing whitespace.
+
+Git will warn you about patches that introduce trailing whitespace, and can
+optionally strip the trailing whitespace for you; however, if applying a series
+of patches, this may make later patches in the series fail by changing their
+context lines.
+
Chapter 4: Naming
@@ -621,12 +633,27 @@ covers RTL which is used frequently with assembly language in the kernel.
Kernel developers like to be seen as literate. Do mind the spelling
of kernel messages to make a good impression. Do not use crippled
-words like "dont" and use "do not" or "don't" instead.
+words like "dont"; use "do not" or "don't" instead. Make the messages
+concise, clear, and unambiguous.
Kernel messages do not have to be terminated with a period.
Printing numbers in parentheses (%d) adds no value and should be avoided.
+There are a number of driver model diagnostic macros in <linux/device.h>
+which you should use to make sure messages are matched to the right device
+and driver, and are tagged with the right level: dev_err(), dev_warn(),
+dev_info(), and so forth. For messages that aren't associated with a
+particular device, <linux/kernel.h> defines pr_debug() and pr_info().
+
+Coming up with good debugging messages can be quite a challenge; and once
+you have them, they can be a huge help for remote troubleshooting. Such
+messages should be compiled out when the DEBUG symbol is not defined (that
+is, by default they are not included). When you use dev_dbg() or pr_debug(),
+that's automatic. Many subsystems have Kconfig options to turn on -DDEBUG.
+A related convention uses VERBOSE_DEBUG to add dev_vdbg() messages to the
+ones already enabled by DEBUG.
+
Chapter 14: Allocating memory
@@ -726,6 +753,33 @@ need them. Feel free to peruse that header file to see what else is already
defined that you shouldn't reproduce in your code.
+ Chapter 18: Editor modelines and other cruft
+
+Some editors can interpret configuration information embedded in source files,
+indicated with special markers. For example, emacs interprets lines marked
+like this:
+
+-*- mode: c -*-
+
+Or like this:
+
+/*
+Local Variables:
+compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
+End:
+*/
+
+Vim interprets markers that look like this:
+
+/* vim:set sw=8 noet */
+
+Do not include any of these in source files. People have their own personal
+editor configurations, and your source files should not override them. This
+includes markers for indentation and mode configuration. People may use their
+own custom mode, or may have some other magic method for making indentation
+work correctly.
+
+
Appendix I: References
@@ -751,4 +805,5 @@ Kernel CodingStyle, by greg@kroah.com at OLS 2002:
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
--
-Last updated on 2006-December-06.
+Last updated on 2007-July-13.
+
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index 028614cdd062..e07f2530326b 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -664,109 +664,6 @@ It is that simple.
Well, not for some odd devices. See the next section for information
about that.
- DAC Addressing for Address Space Hungry Devices
-
-There exists a class of devices which do not mesh well with the PCI
-DMA mapping API. By definition these "mappings" are a finite
-resource. The number of total available mappings per bus is platform
-specific, but there will always be a reasonable amount.
-
-What is "reasonable"? Reasonable means that networking and block I/O
-devices need not worry about using too many mappings.
-
-As an example of a problematic device, consider compute cluster cards.
-They can potentially need to access gigabytes of memory at once via
-DMA. Dynamic mappings are unsuitable for this kind of access pattern.
-
-To this end we've provided a small API by which a device driver
-may use DAC cycles to directly address all of physical memory.
-Not all platforms support this, but most do. It is easy to determine
-whether the platform will work properly at probe time.
-
-First, understand that there may be a SEVERE performance penalty for
-using these interfaces on some platforms. Therefore, you MUST only
-use these interfaces if it is absolutely required. %99 of devices can
-use the normal APIs without any problems.
-
-Note that for streaming type mappings you must either use these
-interfaces, or the dynamic mapping interfaces above. You may not mix
-usage of both for the same device. Such an act is illegal and is
-guaranteed to put a banana in your tailpipe.
-
-However, consistent mappings may in fact be used in conjunction with
-these interfaces. Remember that, as defined, consistent mappings are
-always going to be SAC addressable.
-
-The first thing your driver needs to do is query the PCI platform
-layer if it is capable of handling your devices DAC addressing
-capabilities:
-
- int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask);
-
-You may not use the following interfaces if this routine fails.
-
-Next, DMA addresses using this API are kept track of using the
-dma64_addr_t type. It is guaranteed to be big enough to hold any
-DAC address the platform layer will give to you from the following
-routines. If you have consistent mappings as well, you still
-use plain dma_addr_t to keep track of those.
-
-All mappings obtained here will be direct. The mappings are not
-translated, and this is the purpose of this dialect of the DMA API.
-
-All routines work with page/offset pairs. This is the _ONLY_ way to
-portably refer to any piece of memory. If you have a cpu pointer
-(which may be validly DMA'd too) you may easily obtain the page
-and offset using something like this:
-
- struct page *page = virt_to_page(ptr);
- unsigned long offset = offset_in_page(ptr);
-
-Here are the interfaces:
-
- dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
- struct page *page,
- unsigned long offset,
- int direction);
-
-The DAC address for the tuple PAGE/OFFSET are returned. The direction
-argument is the same as for pci_{map,unmap}_single(). The same rules
-for cpu/device access apply here as for the streaming mapping
-interfaces. To reiterate:
-
- The cpu may touch the buffer before pci_dac_page_to_dma.
- The device may touch the buffer after pci_dac_page_to_dma
- is made, but the cpu may NOT.
-
-When the DMA transfer is complete, invoke:
-
- void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
- dma64_addr_t dma_addr,
- size_t len, int direction);
-
-This must be done before the CPU looks at the buffer again.
-This interface behaves identically to pci_dma_sync_{single,sg}_for_cpu().
-
-And likewise, if you wish to let the device get back at the buffer after
-the cpu has read/written it, invoke:
-
- void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
- dma64_addr_t dma_addr,
- size_t len, int direction);
-
-before letting the device access the DMA area again.
-
-If you need to get back to the PAGE/OFFSET tuple from a dma64_addr_t
-the following interfaces are provided:
-
- struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
- dma64_addr_t dma_addr);
- unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
- dma64_addr_t dma_addr);
-
-This is possible with the DAC interfaces purely because they are
-not translated in any way.
-
Optimizing Unmap State Space Consumption
On many platforms, pci_unmap_{single,page}() is simply a nop.
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 6fd1646d3204..08687e45e19d 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -15,11 +15,11 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \
###
# The build process is as follows (targets):
-# (xmldocs)
-# file.tmpl --> file.xml +--> file.ps (psdocs)
-# +--> file.pdf (pdfdocs)
-# +--> DIR=file (htmldocs)
-# +--> man/ (mandocs)
+# (xmldocs) [by docproc]
+# file.tmpl --> file.xml +--> file.ps (psdocs) [by db2ps or xmlto]
+# +--> file.pdf (pdfdocs) [by db2pdf or xmlto]
+# +--> DIR=file (htmldocs) [by xmlto]
+# +--> man/ (mandocs) [by xmlto]
# for PDF and PS output you can choose between xmlto and docbook-utils tools
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 8c5698a8c2e1..eb42bf9847cb 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -139,8 +139,10 @@ X!Ilib/string.c
!Elib/cmdline.c
</sect1>
- <sect1><title>CRC Functions</title>
+ <sect1 id="crc"><title>CRC Functions</title>
+!Elib/crc7.c
!Elib/crc16.c
+!Elib/crc-itu-t.c
!Elib/crc32.c
!Elib/crc-ccitt.c
</sect1>
@@ -157,7 +159,6 @@ X!Ilib/string.c
!Earch/i386/lib/usercopy.c
</sect1>
<sect1><title>More Memory Management Functions</title>
-!Iinclude/linux/rmap.h
!Emm/readahead.c
!Emm/filemap.c
!Emm/memory.c
@@ -406,6 +407,10 @@ X!Edrivers/pnp/system.c
!Edrivers/pnp/manager.c
!Edrivers/pnp/support.c
</sect1>
+ <sect1><title>Userspace IO devices</title>
+!Edrivers/uio/uio.c
+!Iinclude/linux/uio_driver.h
+ </sect1>
</chapter>
<chapter id="blkdev">
@@ -643,6 +648,60 @@ X!Idrivers/video/console/fonts.c
!Edrivers/spi/spi.c
</chapter>
+ <chapter id="i2c">
+ <title>I<superscript>2</superscript>C and SMBus Subsystem</title>
+
+ <para>
+ I<superscript>2</superscript>C (or without fancy typography, "I2C")
+ is an acronym for the "Inter-IC" bus, a simple bus protocol which is
+ widely used where low data rate communications suffice.
+ Since it's also a licensed trademark, some vendors use another
+ name (such as "Two-Wire Interface", TWI) for the same bus.
+ I2C only needs two signals (SCL for clock, SDA for data), conserving
+ board real estate and minimizing signal quality issues.
+ Most I2C devices use seven bit addresses, and bus speeds of up
+ to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
+ found wide use.
+ I2C is a multi-master bus; open drain signaling is used to
+ arbitrate between masters, as well as to handshake and to
+ synchronize clocks from slower clients.
+ </para>
+
+ <para>
+ The Linux I2C programming interfaces support only the master
+ side of bus interactions, not the slave side.
+ The programming interface is structured around two kinds of driver,
+ and two kinds of device.
+ An I2C "Adapter Driver" abstracts the controller hardware; it binds
+ to a physical device (perhaps a PCI device or platform_device) and
+ exposes a <structname>struct i2c_adapter</structname> representing
+ each I2C bus segment it manages.
+ On each I2C bus segment will be I2C devices represented by a
+ <structname>struct i2c_client</structname>. Those devices will
+ be bound to a <structname>struct i2c_driver</structname>,
+ which should follow the standard Linux driver model.
+ (At this writing, a legacy model is more widely used.)
+ There are functions to perform various I2C protocol operations; at
+ this writing all such functions are usable only from task context.
+ </para>
+
+ <para>
+ The System Management Bus (SMBus) is a sibling protocol. Most SMBus
+ systems are also I2C conformant. The electrical constraints are
+ tighter for SMBus, and it standardizes particular protocol messages
+ and idioms. Controllers that support I2C can also support most
+ SMBus operations, but SMBus controllers don't support all the protocol
+ options that an I2C controller will.
+ There are functions to perform various SMBus protocol operations,
+ either using I2C primitives or by issuing SMBus commands to
+ i2c_adapter devices which don't support those I2C operations.
+ </para>
+
+!Iinclude/linux/i2c.h
+!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
+!Edrivers/i2c/i2c-core.c
+ </chapter>
+
<chapter id="splice">
<title>splice API</title>
<para>)
@@ -654,4 +713,5 @@ X!Idrivers/video/console/fonts.c
!Ffs/splice.c
</chapter>
+
</book>
diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl
index 0a441f73261a..01825ee7db64 100644
--- a/Documentation/DocBook/kernel-locking.tmpl
+++ b/Documentation/DocBook/kernel-locking.tmpl
@@ -219,7 +219,7 @@
</para>
<sect1 id="lock-intro">
- <title>Two Main Types of Kernel Locks: Spinlocks and Semaphores</title>
+ <title>Three Main Types of Kernel Locks: Spinlocks, Mutexes and Semaphores</title>
<para>
There are three main types of kernel locks. The fundamental type
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index e2e24b4778d4..ba9975771503 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -456,8 +456,9 @@ void (*irq_clear) (struct ata_port *);
<sect2><title>SATA phy read/write</title>
<programlisting>
-u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
-void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
+int (*scr_read) (struct ata_port *ap, unsigned int sc_reg,
+ u32 *val);
+int (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
u32 val);
</programlisting>
diff --git a/Documentation/DocBook/procfs-guide.tmpl b/Documentation/DocBook/procfs-guide.tmpl
index 45cad23efefa..2de84dc195a8 100644
--- a/Documentation/DocBook/procfs-guide.tmpl
+++ b/Documentation/DocBook/procfs-guide.tmpl
@@ -352,49 +352,93 @@ entry->write_proc = write_proc_foo;
<funcsynopsis>
<funcprototype>
<funcdef>int <function>read_func</function></funcdef>
- <paramdef>char* <parameter>page</parameter></paramdef>
+ <paramdef>char* <parameter>buffer</parameter></paramdef>
<paramdef>char** <parameter>start</parameter></paramdef>
<paramdef>off_t <parameter>off</parameter></paramdef>
<paramdef>int <parameter>count</parameter></paramdef>
- <paramdef>int* <parameter>eof</parameter></paramdef>
+ <paramdef>int* <parameter>peof</parameter></paramdef>
<paramdef>void* <parameter>data</parameter></paramdef>
</funcprototype>
</funcsynopsis>
<para>
The read function should write its information into the
- <parameter>page</parameter>. For proper use, the function
- should start writing at an offset of
- <parameter>off</parameter> in <parameter>page</parameter> and
- write at most <parameter>count</parameter> bytes, but because
- most read functions are quite simple and only return a small
- amount of information, these two parameters are usually
- ignored (it breaks pagers like <literal>more</literal> and
- <literal>less</literal>, but <literal>cat</literal> still
- works).
+ <parameter>buffer</parameter>, which will be exactly
+ <literal>PAGE_SIZE</literal> bytes long.
</para>
<para>
- If the <parameter>off</parameter> and
- <parameter>count</parameter> parameters are properly used,
- <parameter>eof</parameter> should be used to signal that the
+ The parameter
+ <parameter>peof</parameter> should be used to signal that the
end of the file has been reached by writing
<literal>1</literal> to the memory location
- <parameter>eof</parameter> points to.
+ <parameter>peof</parameter> points to.
</para>
<para>
- The parameter <parameter>start</parameter> doesn't seem to be
- used anywhere in the kernel. The <parameter>data</parameter>
+ The <parameter>data</parameter>
parameter can be used to create a single call back function for
several files, see <xref linkend="usingdata"/>.
</para>
<para>
- The <function>read_func</function> function must return the
- number of bytes written into the <parameter>page</parameter>.
+ The rest of the parameters and the return value are described
+ by a comment in <filename>fs/proc/generic.c</filename> as follows:
</para>
+ <blockquote>
+ <para>
+ You have three ways to return data:
+ </para>
+ <orderedlist>
+ <listitem>
+ <para>
+ Leave <literal>*start = NULL</literal>. (This is the default.)
+ Put the data of the requested offset at that
+ offset within the buffer. Return the number (<literal>n</literal>)
+ of bytes there are from the beginning of the
+ buffer up to the last byte of data. If the
+ number of supplied bytes (<literal>= n - offset</literal>) is
+ greater than zero and you didn't signal eof
+ and the reader is prepared to take more data
+ you will be called again with the requested
+ offset advanced by the number of bytes
+ absorbed. This interface is useful for files
+ no larger than the buffer.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Set <literal>*start</literal> to an unsigned long value less than
+ the buffer address but greater than zero.
+ Put the data of the requested offset at the
+ beginning of the buffer. Return the number of
+ bytes of data placed there. If this number is
+ greater than zero and you didn't signal eof
+ and the reader is prepared to take more data
+ you will be called again with the requested
+ offset advanced by <literal>*start</literal>. This interface is
+ useful when you have a large file consisting
+ of a series of blocks which you want to count
+ and return as wholes.
+ (Hack by Paul.Russell@rustcorp.com.au)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Set <literal>*start</literal> to an address within the buffer.
+ Put the data of the requested offset at <literal>*start</literal>.
+ Return the number of bytes of data placed there.
+ If this number is greater than zero and you
+ didn't signal eof and the reader is prepared to
+ take more data you will be called again with the
+ requested offset advanced by the number of bytes
+ absorbed.
+ </para>
+ </listitem>
+ </orderedlist>
+ </blockquote>
+
<para>
<xref linkend="example"/> shows how to use a read call back
function.
diff --git a/Documentation/DocBook/uio-howto.tmpl b/Documentation/DocBook/uio-howto.tmpl
new file mode 100644
index 000000000000..e3bb29a8d8dd
--- /dev/null
+++ b/Documentation/DocBook/uio-howto.tmpl
@@ -0,0 +1,611 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" []>
+
+<book id="index">
+<bookinfo>
+<title>The Userspace I/O HOWTO</title>
+
+<author>
+ <firstname>Hans-Jürgen</firstname>
+ <surname>Koch</surname>
+ <authorblurb><para>Linux developer, Linutronix</para></authorblurb>
+ <affiliation>
+ <orgname>
+ <ulink url="http://www.linutronix.de">Linutronix</ulink>
+ </orgname>
+
+ <address>
+ <email>hjk@linutronix.de</email>
+ </address>
+ </affiliation>
+</author>
+
+<pubdate>2006-12-11</pubdate>
+
+<abstract>
+ <para>This HOWTO describes concept and usage of Linux kernel's
+ Userspace I/O system.</para>
+</abstract>
+
+<revhistory>
+ <revision>
+ <revnumber>0.3</revnumber>
+ <date>2007-04-29</date>
+ <authorinitials>hjk</authorinitials>
+ <revremark>Added section about userspace drivers.</revremark>
+ </revision>
+ <revision>
+ <revnumber>0.2</revnumber>
+ <date>2007-02-13</date>
+ <authorinitials>hjk</authorinitials>
+ <revremark>Update after multiple mappings were added.</revremark>
+ </revision>
+ <revision>
+ <revnumber>0.1</revnumber>
+ <date>2006-12-11</date>
+ <authorinitials>hjk</authorinitials>
+ <revremark>First draft.</revremark>
+ </revision>
+</revhistory>
+</bookinfo>
+
+<chapter id="aboutthisdoc">
+<?dbhtml filename="about.html"?>
+<title>About this document</title>
+
+<sect1 id="copyright">
+<?dbhtml filename="copyright.html"?>
+<title>Copyright and License</title>
+<para>
+ Copyright (c) 2006 by Hans-Jürgen Koch.</para>
+<para>
+This documentation is Free Software licensed under the terms of the
+GPL version 2.
+</para>
+</sect1>
+
+<sect1 id="translations">
+<?dbhtml filename="translations.html"?>
+<title>Translations</title>
+
+<para>If you know of any translations for this document, or you are
+interested in translating it, please email me
+<email>hjk@linutronix.de</email>.
+</para>
+</sect1>
+
+<sect1 id="preface">
+<title>Preface</title>
+ <para>
+ For many types of devices, creating a Linux kernel driver is
+ overkill. All that is really needed is some way to handle an
+ interrupt and provide access to the memory space of the
+ device. The logic of controlling the device does not
+ necessarily have to be within the kernel, as the device does
+ not need to take advantage of any of other resources that the
+ kernel provides. One such common class of devices that are
+ like this are for industrial I/O cards.
+ </para>
+ <para>
+ To address this situation, the userspace I/O system (UIO) was
+ designed. For typical industrial I/O cards, only a very small
+ kernel module is needed. The main part of the driver will run in
+ user space. This simplifies development and reduces the risk of
+ serious bugs within a kernel module.
+ </para>
+</sect1>
+
+<sect1 id="thanks">
+<title>Acknowledgments</title>
+ <para>I'd like to thank Thomas Gleixner and Benedikt Spranger of
+ Linutronix, who have not only written most of the UIO code, but also
+ helped greatly writing this HOWTO by giving me all kinds of background
+ information.</para>
+</sect1>
+
+<sect1 id="feedback">
+<title>Feedback</title>
+ <para>Find something wrong with this document? (Or perhaps something
+ right?) I would love to hear from you. Please email me at
+ <email>hjk@linutronix.de</email>.</para>
+</sect1>
+</chapter>
+
+<chapter id="about">
+<?dbhtml filename="about.html"?>
+<title>About UIO</title>
+
+<para>If you use UIO for your card's driver, here's what you get:</para>
+
+<itemizedlist>
+<listitem>
+ <para>only one small kernel module to write and maintain.</para>
+</listitem>
+<listitem>
+ <para>develop the main part of your driver in user space,
+ with all the tools and libraries you're used to.</para>
+</listitem>
+<listitem>
+ <para>bugs in your driver won't crash the kernel.</para>
+</listitem>
+<listitem>
+ <para>updates of your driver can take place without recompiling
+ the kernel.</para>
+</listitem>
+<listitem>
+ <para>if you need to keep some parts of your driver closed source,
+ you can do so without violating the GPL license on the kernel.</para>
+</listitem>
+</itemizedlist>
+
+<sect1 id="how_uio_works">
+<title>How UIO works</title>
+ <para>
+ Each UIO device is accessed through a device file and several
+ sysfs attribute files. The device file will be called
+ <filename>/dev/uio0</filename> for the first device, and
+ <filename>/dev/uio1</filename>, <filename>/dev/uio2</filename>
+ and so on for subsequent devices.
+ </para>
+
+ <para><filename>/dev/uioX</filename> is used to access the
+ address space of the card. Just use
+ <function>mmap()</function> to access registers or RAM
+ locations of your card.
+ </para>
+
+ <para>
+ Interrupts are handled by reading from
+ <filename>/dev/uioX</filename>. A blocking
+ <function>read()</function> from
+ <filename>/dev/uioX</filename> will return as soon as an
+ interrupt occurs. You can also use
+ <function>select()</function> on
+ <filename>/dev/uioX</filename> to wait for an interrupt. The
+ integer value read from <filename>/dev/uioX</filename>
+ represents the total interrupt count. You can use this number
+ to figure out if you missed some interrupts.
+ </para>
+
+ <para>
+ To handle interrupts properly, your custom kernel module can
+ provide its own interrupt handler. It will automatically be
+ called by the built-in handler.
+ </para>
+
+ <para>
+ For cards that don't generate interrupts but need to be
+ polled, there is the possibility to set up a timer that
+ triggers the interrupt handler at configurable time intervals.
+ See <filename>drivers/uio/uio_dummy.c</filename> for an
+ example of this technique.
+ </para>
+
+ <para>
+ Each driver provides attributes that are used to read or write
+ variables. These attributes are accessible through sysfs
+ files. A custom kernel driver module can add its own
+ attributes to the device owned by the uio driver, but not added
+ to the UIO device itself at this time. This might change in the
+ future if it would be found to be useful.
+ </para>
+
+ <para>
+ The following standard attributes are provided by the UIO
+ framework:
+ </para>
+<itemizedlist>
+<listitem>
+ <para>
+ <filename>name</filename>: The name of your device. It is
+ recommended to use the name of your kernel module for this.
+ </para>
+</listitem>
+<listitem>
+ <para>
+ <filename>version</filename>: A version string defined by your
+ driver. This allows the user space part of your driver to deal
+ with different versions of the kernel module.
+ </para>
+</listitem>
+<listitem>
+ <para>
+ <filename>event</filename>: The total number of interrupts
+ handled by the driver since the last time the device node was
+ read.
+ </para>
+</listitem>
+</itemizedlist>
+<para>
+ These attributes appear under the
+ <filename>/sys/class/uio/uioX</filename> directory. Please
+ note that this directory might be a symlink, and not a real
+ directory. Any userspace code that accesses it must be able
+ to handle this.
+</para>
+<para>
+ Each UIO device can make one or more memory regions available for
+ memory mapping. This is necessary because some industrial I/O cards
+ require access to more than one PCI memory region in a driver.
+</para>
+<para>
+ Each mapping has its own directory in sysfs, the first mapping
+ appears as <filename>/sys/class/uio/uioX/maps/map0/</filename>.
+ Subsequent mappings create directories <filename>map1/</filename>,
+ <filename>map2/</filename>, and so on. These directories will only
+ appear if the size of the mapping is not 0.
+</para>
+<para>
+ Each <filename>mapX/</filename> directory contains two read-only files
+ that show start address and size of the memory:
+</para>
+<itemizedlist>
+<listitem>
+ <para>
+ <filename>addr</filename>: The address of memory that can be mapped.
+ </para>
+</listitem>
+<listitem>
+ <para>
+ <filename>size</filename>: The size, in bytes, of the memory
+ pointed to by addr.
+ </para>
+</listitem>
+</itemizedlist>
+
+<para>
+ From userspace, the different mappings are distinguished by adjusting
+ the <varname>offset</varname> parameter of the
+ <function>mmap()</function> call. To map the memory of mapping N, you
+ have to use N times the page size as your offset:
+</para>
+<programlisting format="linespecific">
+offset = N * getpagesize();
+</programlisting>
+
+</sect1>
+</chapter>
+
+<chapter id="using-uio_dummy" xreflabel="Using uio_dummy">
+<?dbhtml filename="using-uio_dummy.html"?>
+<title>Using uio_dummy</title>
+ <para>
+ Well, there is no real use for uio_dummy. Its only purpose is
+ to test most parts of the UIO system (everything except
+ hardware interrupts), and to serve as an example for the
+ kernel module that you will have to write yourself.
+ </para>
+
+<sect1 id="what_uio_dummy_does">
+<title>What uio_dummy does</title>
+ <para>
+ The kernel module <filename>uio_dummy.ko</filename> creates a
+ device that uses a timer to generate periodic interrupts. The
+ interrupt handler does nothing but increment a counter. The
+ driver adds two custom attributes, <varname>count</varname>
+ and <varname>freq</varname>, that appear under
+ <filename>/sys/devices/platform/uio_dummy/</filename>.
+ </para>
+
+ <para>
+ The attribute <varname>count</varname> can be read and
+ written. The associated file
+ <filename>/sys/devices/platform/uio_dummy/count</filename>
+ appears as a normal text file and contains the total number of
+ timer interrupts. If you look at it (e.g. using
+ <function>cat</function>), you'll notice it is slowly counting
+ up.
+ </para>
+
+ <para>
+ The attribute <varname>freq</varname> can be read and written.
+ The content of
+ <filename>/sys/devices/platform/uio_dummy/freq</filename>
+ represents the number of system timer ticks between two timer
+ interrupts. The default value of <varname>freq</varname> is
+ the value of the kernel variable <varname>HZ</varname>, which
+ gives you an interval of one second. Lower values will
+ increase the frequency. Try the following:
+ </para>
+<programlisting format="linespecific">
+cd /sys/devices/platform/uio_dummy/
+echo 100 > freq
+</programlisting>
+ <para>
+ Use <function>cat count</function> to see how the interrupt
+ frequency changes.
+ </para>
+</sect1>
+</chapter>
+
+<chapter id="custom_kernel_module" xreflabel="Writing your own kernel module">
+<?dbhtml filename="custom_kernel_module.html"?>
+<title>Writing your own kernel module</title>
+ <para>
+ Please have a look at <filename>uio_dummy.c</filename> as an
+ example. The following paragraphs explain the different
+ sections of this file.
+ </para>
+
+<sect1 id="uio_info">
+<title>struct uio_info</title>
+ <para>
+ This structure tells the framework the details of your driver,
+ Some of the members are required, others are optional.
+ </para>
+
+<itemizedlist>
+<listitem><para>
+<varname>char *name</varname>: Required. The name of your driver as
+it will appear in sysfs. I recommend using the name of your module for this.
+</para></listitem>
+
+<listitem><para>
+<varname>char *version</varname>: Required. This string appears in
+<filename>/sys/class/uio/uioX/version</filename>.
+</para></listitem>
+
+<listitem><para>
+<varname>struct uio_mem mem[ MAX_UIO_MAPS ]</varname>: Required if you
+have memory that can be mapped with <function>mmap()</function>. For each
+mapping you need to fill one of the <varname>uio_mem</varname> structures.
+See the description below for details.
+</para></listitem>
+
+<listitem><para>
+<varname>long irq</varname>: Required. If your hardware generates an
+interrupt, it's your modules task to determine the irq number during
+initialization. If you don't have a hardware generated interrupt but
+want to trigger the interrupt handler in some other way, set
+<varname>irq</varname> to <varname>UIO_IRQ_CUSTOM</varname>. The
+uio_dummy module does this as it triggers the event mechanism in a timer
+routine. If you had no interrupt at all, you could set
+<varname>irq</varname> to <varname>UIO_IRQ_NONE</varname>, though this
+rarely makes sense.
+</para></listitem>
+
+<listitem><para>
+<varname>unsigned long irq_flags</varname>: Required if you've set
+<varname>irq</varname> to a hardware interrupt number. The flags given
+here will be used in the call to <function>request_irq()</function>.
+</para></listitem>
+
+<listitem><para>
+<varname>int (*mmap)(struct uio_info *info, struct vm_area_struct
+*vma)</varname>: Optional. If you need a special
+<function>mmap()</function> function, you can set it here. If this
+pointer is not NULL, your <function>mmap()</function> will be called
+instead of the built-in one.
+</para></listitem>
+
+<listitem><para>
+<varname>int (*open)(struct uio_info *info, struct inode *inode)
+</varname>: Optional. You might want to have your own
+<function>open()</function>, e.g. to enable interrupts only when your
+device is actually used.
+</para></listitem>
+
+<listitem><para>
+<varname>int (*release)(struct uio_info *info, struct inode *inode)
+</varname>: Optional. If you define your own
+<function>open()</function>, you will probably also want a custom
+<function>release()</function> function.
+</para></listitem>
+</itemizedlist>
+
+<para>
+Usually, your device will have one or more memory regions that can be mapped
+to user space. For each region, you have to set up a
+<varname>struct uio_mem</varname> in the <varname>mem[]</varname> array.
+Here's a description of the fields of <varname>struct uio_mem</varname>:
+</para>
+
+<itemizedlist>
+<listitem><para>
+<varname>int memtype</varname>: Required if the mapping is used. Set this to
+<varname>UIO_MEM_PHYS</varname> if you you have physical memory on your
+card to be mapped. Use <varname>UIO_MEM_LOGICAL</varname> for logical
+memory (e.g. allocated with <function>kmalloc()</function>). There's also
+<varname>UIO_MEM_VIRTUAL</varname> for virtual memory.
+</para></listitem>
+
+<listitem><para>
+<varname>unsigned long addr</varname>: Required if the mapping is used.
+Fill in the address of your memory block. This address is the one that
+appears in sysfs.
+</para></listitem>
+
+<listitem><para>
+<varname>unsigned long size</varname>: Fill in the size of the
+memory block that <varname>addr</varname> points to. If <varname>size</varname>
+is zero, the mapping is considered unused. Note that you
+<emphasis>must</emphasis> initialize <varname>size</varname> with zero for
+all unused mappings.
+</para></listitem>
+
+<listitem><para>
+<varname>void *internal_addr</varname>: If you have to access this memory
+region from within your kernel module, you will want to map it internally by
+using something like <function>ioremap()</function>. Addresses
+returned by this function cannot be mapped to user space, so you must not
+store it in <varname>addr</varname>. Use <varname>internal_addr</varname>
+instead to remember such an address.
+</para></listitem>
+</itemizedlist>
+
+<para>
+Please do not touch the <varname>kobj</varname> element of
+<varname>struct uio_mem</varname>! It is used by the UIO framework
+to set up sysfs files for this mapping. Simply leave it alone.
+</para>
+</sect1>
+
+<sect1 id="adding_irq_handler">
+<title>Adding an interrupt handler</title>
+ <para>
+ What you need to do in your interrupt handler depends on your
+ hardware and on how you want to handle it. You should try to
+ keep the amount of code in your kernel interrupt handler low.
+ If your hardware requires no action that you
+ <emphasis>have</emphasis> to perform after each interrupt,
+ then your handler can be empty.</para> <para>If, on the other
+ hand, your hardware <emphasis>needs</emphasis> some action to
+ be performed after each interrupt, then you
+ <emphasis>must</emphasis> do it in your kernel module. Note
+ that you cannot rely on the userspace part of your driver. Your
+ userspace program can terminate at any time, possibly leaving
+ your hardware in a state where proper interrupt handling is
+ still required.
+ </para>
+
+ <para>
+ There might also be applications where you want to read data
+ from your hardware at each interrupt and buffer it in a piece
+ of kernel memory you've allocated for that purpose. With this
+ technique you could avoid loss of data if your userspace
+ program misses an interrupt.
+ </para>
+
+ <para>
+ A note on shared interrupts: Your driver should support
+ interrupt sharing whenever this is possible. It is possible if
+ and only if your driver can detect whether your hardware has
+ triggered the interrupt or not. This is usually done by looking
+ at an interrupt status register. If your driver sees that the
+ IRQ bit is actually set, it will perform its actions, and the
+ handler returns IRQ_HANDLED. If the driver detects that it was
+ not your hardware that caused the interrupt, it will do nothing
+ and return IRQ_NONE, allowing the kernel to call the next
+ possible interrupt handler.
+ </para>
+
+ <para>
+ If you decide not to support shared interrupts, your card
+ won't work in computers with no free interrupts. As this
+ frequently happens on the PC platform, you can save yourself a
+ lot of trouble by supporting interrupt sharing.
+ </para>
+</sect1>
+
+</chapter>
+
+<chapter id="userspace_driver" xreflabel="Writing a driver in user space">
+<?dbhtml filename="userspace_driver.html"?>
+<title>Writing a driver in userspace</title>
+ <para>
+ Once you have a working kernel module for your hardware, you can
+ write the userspace part of your driver. You don't need any special
+ libraries, your driver can be written in any reasonable language,
+ you can use floating point numbers and so on. In short, you can
+ use all the tools and libraries you'd normally use for writing a
+ userspace application.
+ </para>
+
+<sect1 id="getting_uio_information">
+<title>Getting information about your UIO device</title>
+ <para>
+ Information about all UIO devices is available in sysfs. The
+ first thing you should do in your driver is check
+ <varname>name</varname> and <varname>version</varname> to
+ make sure your talking to the right device and that its kernel
+ driver has the version you expect.
+ </para>
+ <para>
+ You should also make sure that the memory mapping you need
+ exists and has the size you expect.
+ </para>
+ <para>
+ There is a tool called <varname>lsuio</varname> that lists
+ UIO devices and their attributes. It is available here:
+ </para>
+ <para>
+ <ulink url="http://www.osadl.org/projects/downloads/UIO/user/">
+ http://www.osadl.org/projects/downloads/UIO/user/</ulink>
+ </para>
+ <para>
+ With <varname>lsuio</varname> you can quickly check if your
+ kernel module is loaded and which attributes it exports.
+ Have a look at the manpage for details.
+ </para>
+ <para>
+ The source code of <varname>lsuio</varname> can serve as an
+ example for getting information about an UIO device.
+ The file <filename>uio_helper.c</filename> contains a lot of
+ functions you could use in your userspace driver code.
+ </para>
+</sect1>
+
+<sect1 id="mmap_device_memory">
+<title>mmap() device memory</title>
+ <para>
+ After you made sure you've got the right device with the
+ memory mappings you need, all you have to do is to call
+ <function>mmap()</function> to map the device's memory
+ to userspace.
+ </para>
+ <para>
+ The parameter <varname>offset</varname> of the
+ <function>mmap()</function> call has a special meaning
+ for UIO devices: It is used to select which mapping of
+ your device you want to map. To map the memory of
+ mapping N, you have to use N times the page size as
+ your offset:
+ </para>
+<programlisting format="linespecific">
+ offset = N * getpagesize();
+</programlisting>
+ <para>
+ N starts from zero, so if you've got only one memory
+ range to map, set <varname>offset = 0</varname>.
+ A drawback of this technique is that memory is always
+ mapped beginning with its start address.
+ </para>
+</sect1>
+
+<sect1 id="wait_for_interrupts">
+<title>Waiting for interrupts</title>
+ <para>
+ After you successfully mapped your devices memory, you
+ can access it like an ordinary array. Usually, you will
+ perform some initialization. After that, your hardware
+ starts working and will generate an interrupt as soon
+ as it's finished, has some data available, or needs your
+ attention because an error occured.
+ </para>
+ <para>
+ <filename>/dev/uioX</filename> is a read-only file. A
+ <function>read()</function> will always block until an
+ interrupt occurs. There is only one legal value for the
+ <varname>count</varname> parameter of
+ <function>read()</function>, and that is the size of a
+ signed 32 bit integer (4). Any other value for
+ <varname>count</varname> causes <function>read()</function>
+ to fail. The signed 32 bit integer read is the interrupt
+ count of your device. If the value is one more than the value
+ you read the last time, everything is OK. If the difference
+ is greater than one, you missed interrupts.
+ </para>
+ <para>
+ You can also use <function>select()</function> on
+ <filename>/dev/uioX</filename>.
+ </para>
+</sect1>
+
+</chapter>
+
+<appendix id="app1">
+<title>Further information</title>
+<itemizedlist>
+ <listitem><para>
+ <ulink url="http://www.osadl.org">
+ OSADL homepage.</ulink>
+ </para></listitem>
+ <listitem><para>
+ <ulink url="http://www.linutronix.de">
+ Linutronix homepage.</ulink>
+ </para></listitem>
+</itemizedlist>
+</appendix>
+
+</book>
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 98e2701c746f..f8cc3f8ed152 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -249,6 +249,9 @@ 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
It is worth mentioning what Andrew Morton wrote on the linux-kernel
mailing list about kernel releases:
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index f4dffadbcb00..42b01bc2e1b4 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -222,7 +222,15 @@ over a rather long period of time, but improvements are always welcome!
deadlock as soon as the RCU callback happens to interrupt that
acquisition's critical section.
-13. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu())
+13. RCU callbacks can be and are executed in parallel. In many cases,
+ the callback code simply wrappers around kfree(), so that this
+ is not an issue (or, more accurately, to the extent that it is
+ an issue, the memory-allocator locking handles it). However,
+ if the callbacks do manipulate a shared data structure, they
+ must use whatever locking or other synchronization is required
+ to safely access and/or modify that data structure.
+
+14. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu())
may only be invoked from process context. Unlike other forms of
RCU, it -is- permissible to block in an SRCU read-side critical
section (demarked by srcu_read_lock() and srcu_read_unlock()),
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index 6ebffb57e3db..19e7f65c269f 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -1,4 +1,4 @@
-Linux Kernel patch sumbittal checklist
+Linux Kernel patch submission checklist
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here are some basic things that developers should do if they want to see their
@@ -9,7 +9,6 @@ Documentation/SubmittingPatches and elsewhere regarding submitting Linux
kernel patches.
-
1: Builds cleanly with applicable or modified CONFIG options =y, =m, and
=n. No gcc warnings/errors, no linker warnings/errors.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 0958e97d4bf4..d6b45a9b29b4 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -122,7 +122,7 @@ then only post say 15 or so at a time and wait for review and integration.
Check your patch for basic style violations, details of which can be
found in Documentation/CodingStyle. Failure to do so simply wastes
-the reviewers time and will get your patch rejected, probabally
+the reviewers time and will get your patch rejected, probably
without even being read.
At a minimum you should check your patches with the patch style
@@ -464,9 +464,25 @@ section Linus Computer Science 101.
Nuff said. If your code deviates too much from this, it is likely
to be rejected without further review, and without comment.
+Once significant exception is when moving code from one file to
+another in this case you should not modify the moved code at all in
+the same patch which moves it. This clearly delineates the act of
+moving the code and your changes. This greatly aids review of the
+actual differences and allows tools to better track the history of
+the code itself.
+
Check your patches with the patch style checker prior to submission
-(scripts/checkpatch.pl). You should be able to justify all
-violations that remain in your patch.
+(scripts/checkpatch.pl). The style checker should be viewed as
+a guide not as the final word. If your code looks better with
+a violation then its probably best left alone.
+
+The checker reports at three levels:
+ - ERROR: things that are very likely to be wrong
+ - WARNING: things requiring careful review
+ - CHECK: things requiring thought
+
+You should be able to justify all violations that remain in your
+patch.
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index 71acc28ed0d1..24c5aade8998 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -49,6 +49,7 @@ char name[100];
int dbg;
int print_delays;
int print_io_accounting;
+int print_task_context_switch_counts;
__u64 stime, utime;
#define PRINTF(fmt, arg...) { \
@@ -195,7 +196,7 @@ void print_delayacct(struct taskstats *t)
"IO %15s%15s\n"
" %15llu%15llu\n"
"MEM %15s%15s\n"
- " %15llu%15llu\n\n",
+ " %15llu%15llu\n"
"count", "real total", "virtual total", "delay total",
t->cpu_count, t->cpu_run_real_total, t->cpu_run_virtual_total,
t->cpu_delay_total,
@@ -204,6 +205,14 @@ void print_delayacct(struct taskstats *t)
"count", "delay total", t->swapin_count, t->swapin_delay_total);
}
+void task_context_switch_counts(struct taskstats *t)
+{
+ printf("\n\nTask %15s%15s\n"
+ " %15lu%15lu\n",
+ "voluntary", "nonvoluntary",
+ t->nvcsw, t->nivcsw);
+}
+
void print_ioacct(struct taskstats *t)
{
printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
@@ -235,7 +244,7 @@ int main(int argc, char *argv[])
struct msgtemplate msg;
while (1) {
- c = getopt(argc, argv, "diw:r:m:t:p:vl");
+ c = getopt(argc, argv, "qdiw:r:m:t:p:vl");
if (c < 0)
break;
@@ -248,6 +257,10 @@ int main(int argc, char *argv[])
printf("printing IO accounting\n");
print_io_accounting = 1;
break;
+ case 'q':
+ printf("printing task/process context switch rates\n");
+ print_task_context_switch_counts = 1;
+ break;
case 'w':
logfile = strdup(optarg);
printf("write to file %s\n", logfile);
@@ -389,6 +402,8 @@ int main(int argc, char *argv[])
print_delayacct((struct taskstats *) NLA_DATA(na));
if (print_io_accounting)
print_ioacct((struct taskstats *) NLA_DATA(na));
+ if (print_task_context_switch_counts)
+ task_context_switch_counts((struct taskstats *) NLA_DATA(na));
if (fd) {
if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
err(1,"write error\n");
diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt
index 661c797eaf79..8aa7529f8258 100644
--- a/Documentation/accounting/taskstats-struct.txt
+++ b/Documentation/accounting/taskstats-struct.txt
@@ -22,6 +22,8 @@ There are three different groups of fields in the struct taskstats:
/* Extended accounting fields end */
Their values are collected if CONFIG_TASK_XACCT is set.
+4) Per-task and per-thread context switch count statistics
+
Future extension should add fields to the end of the taskstats struct, and
should not change the relative position of each field within the struct.
@@ -158,4 +160,8 @@ struct taskstats {
/* Extended accounting fields end */
+4) Per-task and per-thread statistics
+ __u64 nvcsw; /* Context voluntary switch counter */
+ __u64 nivcsw; /* Context involuntary switch counter */
+
}
diff --git a/Documentation/blackfin/kgdb.txt b/Documentation/blackfin/kgdb.txt
new file mode 100644
index 000000000000..84f6a484ae9a
--- /dev/null
+++ b/Documentation/blackfin/kgdb.txt
@@ -0,0 +1,155 @@
+ A Simple Guide to Configure KGDB
+
+ Sonic Zhang <sonic.zhang@analog.com>
+ Aug. 24th 2006
+
+
+This KGDB patch enables the kernel developer to do source level debugging on
+the kernel for the Blackfin architecture. The debugging works over either the
+ethernet interface or one of the uarts. Both software breakpoints and
+hardware breakpoints are supported in this version.
+http://docs.blackfin.uclinux.org/doku.php?id=kgdb
+
+
+2 known issues:
+1. This bug:
+ http://blackfin.uclinux.org/tracker/index.php?func=detail&aid=544&group_id=18&atid=145
+ The GDB client for Blackfin uClinux causes incorrect values of local
+ variables to be displayed when the user breaks the running of kernel in GDB.
+2. Because of a hardware bug in Blackfin 533 v1.0.3:
+ 05000067 - Watchpoints (Hardware Breakpoints) are not supported
+ Hardware breakpoints cannot be set properly.
+
+
+Debug over Ethernet:
+
+1. Compile and install the cross platform version of gdb for blackfin, which
+ can be found at $(BINROOT)/bfin-elf-gdb.
+
+2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
+ "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
+ With this selected, option "Full Symbolic/Source Debugging support" and
+ "Compile the kernel with frame pointers" are also selected.
+
+3. Select option "KGDB: connect over (Ethernet)". Add "kgdboe=@target-IP/,@host-IP/" to
+ the option "Compiled-in Kernel Boot Parameter" under "Kernel hacking".
+
+4. Connect minicom to the serial port and boot the kernel image.
+
+5. Configure the IP "/> ifconfig eth0 target-IP"
+
+6. Start GDB client "bfin-elf-gdb vmlinux".
+
+7. Connect to the target "(gdb) target remote udp:target-IP:6443".
+
+8. Set software breakpoint "(gdb) break sys_open".
+
+9. Continue "(gdb) c".
+
+10. Run ls in the target console "/> ls".
+
+11. Breakpoint hits. "Breakpoint 1: sys_open(..."
+
+12. Display local variables and function paramters.
+ (*) This operation gives wrong results, see known issue 1.
+
+13. Single stepping "(gdb) si".
+
+14. Remove breakpoint 1. "(gdb) del 1"
+
+15. Set hardware breakpoint "(gdb) hbreak sys_open".
+
+16. Continue "(gdb) c".
+
+17. Run ls in the target console "/> ls".
+
+18. Hardware breakpoint hits. "Breakpoint 1: sys_open(...".
+ (*) This hardware breakpoint will not be hit, see known issue 2.
+
+19. Continue "(gdb) c".
+
+20. Interrupt the target in GDB "Ctrl+C".
+
+21. Detach from the target "(gdb) detach".
+
+22. Exit GDB "(gdb) quit".
+
+
+Debug over the UART:
+
+1. Compile and install the cross platform version of gdb for blackfin, which
+ can be found at $(BINROOT)/bfin-elf-gdb.
+
+2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
+ "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
+ With this selected, option "Full Symbolic/Source Debugging support" and
+ "Compile the kernel with frame pointers" are also selected.
+
+3. Select option "KGDB: connect over (UART)". Set "KGDB: UART port number" to be
+ a different one from the console. Don't forget to change the mode of
+ blackfin serial driver to PIO. Otherwise kgdb works incorrectly on UART.
+
+4. If you want connect to kgdb when the kernel boots, enable
+ "KGDB: Wait for gdb connection early"
+
+5. Compile kernel.
+
+6. Connect minicom to the serial port of the console and boot the kernel image.
+
+7. Start GDB client "bfin-elf-gdb vmlinux".
+
+8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
+
+9. Connect to the target on the second serial port "(gdb) target remote /dev/ttyS1".
+
+10. Set software breakpoint "(gdb) break sys_open".
+
+11. Continue "(gdb) c".
+
+12. Run ls in the target console "/> ls".
+
+13. A breakpoint is hit. "Breakpoint 1: sys_open(..."
+
+14. All other operations are the same as that in KGDB over Ethernet.
+
+
+Debug over the same UART as console:
+
+1. Compile and install the cross platform version of gdb for blackfin, which
+ can be found at $(BINROOT)/bfin-elf-gdb.
+
+2. Apply this patch to the 2.6.x kernel. Select the menuconfig option under
+ "Kernel hacking" -> "Kernel debugging" -> "KGDB: kernel debug with remote gdb".
+ With this selected, option "Full Symbolic/Source Debugging support" and
+ "Compile the kernel with frame pointers" are also selected.
+
+3. Select option "KGDB: connect over UART". Set "KGDB: UART port number" to console.
+ Don't forget to change the mode of blackfin serial driver to PIO.
+ Otherwise kgdb works incorrectly on UART.
+
+4. If you want connect to kgdb when the kernel boots, enable
+ "KGDB: Wait for gdb connection early"
+
+5. Connect minicom to the serial port and boot the kernel image.
+
+6. (Optional) Ask target to wait for gdb connection by entering Ctrl+A. In minicom, you should enter Ctrl+A+A.
+
+7. Start GDB client "bfin-elf-gdb vmlinux".
+
+8. Set the baud rate in GDB "(gdb) set remotebaud 57600".
+
+9. Connect to the target "(gdb) target remote /dev/ttyS0".
+
+10. Set software breakpoint "(gdb) break sys_open".
+
+11. Continue "(gdb) c". Then enter Ctrl+C twice to stop GDB connection.
+
+12. Run ls in the target console "/> ls". Dummy string can be seen on the console.
+
+13. Then connect the gdb to target again. "(gdb) target remote /dev/ttyS0".
+ Now you will find a breakpoint is hit. "Breakpoint 1: sys_open(..."
+
+14. All other operations are the same as that in KGDB over Ethernet. The only
+ difference is that after continue command in GDB, please stop GDB
+ connection by 2 "Ctrl+C"s and connect again after breakpoints are hit or
+ Ctrl+A is entered.
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
index debf6813934a..866b76139420 100644
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -253,7 +253,7 @@ Here are the routines, one by one:
The first of these two routines is invoked after map_vm_area()
has installed the page table entries. The second is invoked
- before unmap_vm_area() deletes the page table entries.
+ before unmap_kernel_range() deletes the page table entries.
There exists another whole class of cpu cache issues which currently
require a whole different set of interfaces to handle properly.
diff --git a/Documentation/cdrom/00-INDEX b/Documentation/cdrom/00-INDEX
index 916dafe29d3f..433edf23dc49 100644
--- a/Documentation/cdrom/00-INDEX
+++ b/Documentation/cdrom/00-INDEX
@@ -2,32 +2,10 @@
- this file (info on CD-ROMs and Linux)
Makefile
- only used to generate TeX output from the documentation.
-aztcd
- - info on Aztech/Orchid/Okano/Wearnes/Conrad/CyCDROM driver.
cdrom-standard.tex
- LaTeX document on standardizing the CD-ROM programming interface.
-cdu31a
- - info on the Sony CDU31A/CDU33A CD-ROM driver.
-cm206
- - info on the Philips/LMS cm206/cm260 CD-ROM driver.
-gscd
- - info on the Goldstar R420 CD-ROM driver.
ide-cd
- info on setting up and using ATAPI (aka IDE) CD-ROMs.
-isp16
- - info on the CD-ROM interface on ISP16, MAD16 or Mozart sound card.
-mcd
- - info on limitations of standard Mitsumi CD-ROM driver.
-mcdx
- - info on improved Mitsumi CD-ROM driver.
-optcd
- - info on the Optics Storage 8000 AT CD-ROM driver
packet-writing.txt
- Info on the CDRW packet writing module
-sbpcd
- - info on the SoundBlaster/Panasonic CD-ROM interface driver.
-sjcd
- - info on the SANYO CDR-H94A CD-ROM interface driver.
-sonycd535
- - info on the Sony CDU-535 (and 531) CD-ROM driver.
diff --git a/Documentation/cdrom/aztcd b/Documentation/cdrom/aztcd
deleted file mode 100644
index 6bf0290ef7ce..000000000000
--- a/Documentation/cdrom/aztcd
+++ /dev/null
@@ -1,822 +0,0 @@
-$Id: README.aztcd,v 2.60 1997/11/29 09:51:25 root Exp root $
- Readme-File Documentation/cdrom/aztcd
- for
- AZTECH CD-ROM CDA268-01A, ORCHID CD-3110,
- OKANO/WEARNES CDD110, CONRAD TXC, CyCDROM CR520, CR540
- CD-ROM Drives
- Version 2.6 and newer
- (for other drives see 6.-8.)
-
-NOTE: THIS DRIVER WILL WORK WITH THE CD-ROM DRIVES LISTED, WHICH HAVE
- A PROPRIETARY INTERFACE (implemented on a sound card or on an
- ISA-AT-bus card).
- IT WILL DEFINITELY NOT WORK WITH CD-ROM DRIVES WITH *IDE*-INTERFACE,
- such as the Aztech CDA269-031SE !!! (The only known exceptions are
- 'faked' IDE drives like the CyCDROM CR520ie which work with aztcd
- under certain conditions, see 7.). IF YOU'RE USING A CD-ROM DRIVE
- WITH IDE-INTERFACE, SOMETIMES ALSO CALLED ATAPI-COMPATIBLE, PLEASE
- USE THE ide-cd.c DRIVER, WRITTEN BY MARK LORD AND SCOTT SNYDER !
- THE STANDARD-KERNEL 1.2.x NOW ALSO SUPPORTS IDE-CDROM-DRIVES, SEE THE
- HARDDISK (!) SECTION OF make config, WHEN COMPILING A NEW KERNEL!!!
-----------------------------------------------------------------------------
-
-Contents of this file:
- 1. NOTE
- 2. INSTALLATION
- 3. CONFIGURING YOUR KERNEL
- 4. RECOMPILING YOUR KERNEL
- 4.1 AZTCD AS A RUN-TIME LOADABLE MODULE
- 4.2 CDROM CONNECTED TO A SOUNDCARD
- 5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS
- 5.1 MULTISESSION SUPPORT
- 5.2 STATUS RECOGNITION
- 5.3 DOSEMU's CDROM SUPPORT
- 6. BUG REPORTS
- 7. OTHER DRIVES
- 8. IF YOU DON'T SUCCEED ... DEBUGGING
- 9. TECHNICAL HISTORY OF THE DRIVER
- 10. ACKNOWLEDGMENTS
- 11. PROGRAMMING ADD ONS: CDPLAY.C
- APPENDIX: Source code of cdplay.c
-----------------------------------------------------------------------------
-
-1. NOTE
-This software has been successfully in alpha and beta test and is part of
-the standard kernel since kernel 1.1.8x since December 1994. It works with
-AZTECH CDA268-01A, ORCHID CDS-3110, ORCHID/WEARNES CDD110 and CONRAD TXC
-(Nr.99 31 23 -series 04) and has proven to be stable with kernel
-versions 1.0.9 and newer. But with any software there still may be bugs in it.
-So if you encounter problems, you are invited to help us improve this software.
-Please send me a detailed bug report (see chapter BUG REPORTS). You are also
-invited in helping us to increase the number of drives, which are supported.
-
-Please read the README-files carefully and always keep a backup copy of your
-old kernel, in order to reboot if something goes wrong!
-
-2. INSTALLATION
-The driver consists of a header file 'aztcd.h', which normally should reside
-in /usr/src/linux/drivers/cdrom and the source code 'aztcd.c', which normally
-resides in the same place. It uses /dev/aztcd (/dev/aztcd0 in some distri-
-butions), which must be a valid block device with major number 29 and reside
-in directory /dev. To mount a CD-ROM, your kernel needs to have the ISO9660-
-filesystem support included.
-
-PLEASE NOTE: aztcd.c has been developed in parallel to the linux kernel,
-which had and is having many major and minor changes which are not backward
-compatible. Quite definitely aztcd.c version 1.80 and newer will NOT work
-in kernels older than 1.3.33. So please always use the most recent version
-of aztcd.c with the appropriate linux-kernel.
-
-3. CONFIGURING YOUR KERNEL
-If your kernel is already configured for using the AZTECH driver you will
-see the following message while Linux boots:
- Aztech CD-ROM Init: DriverVersion=<version number> BaseAddress=<baseaddress>
- Aztech CD-ROM Init: FirmwareVersion=<firmware version id of your I/O-card>>>
- Aztech CD-ROM Init: <drive type> detected
- Aztech CD-ROM Init: End
-If the message looks different and you are sure to have a supported drive,
-it may have a different base address. The Aztech driver does look for the
-CD-ROM drive at the base address specified in aztcd.h at compile time. This
-address can be overwritten by boot parameter aztcd=....You should reboot and
-start Linux with boot parameter aztcd=<base address>, e.g. aztcd=0x320. If
-you do not know the base address, start your PC with DOS and look at the boot
-message of your CD-ROM's DOS driver. If that still does not help, use boot
-parameter aztcd=<base address>,0x79 , this tells aztcd to try a little harder.
-aztcd may be configured to use autoprobing the base address by recompiling
-it (see chapter 4.).
-
-If the message looks correct, as user 'root' you should be able to mount the
-drive by
- mount -t iso9660 -r /dev/aztcd0 /mnt
-and use it as any other filesystem. (If this does not work, check if
-/dev/aztcd0 and /mnt do exist and create them, if necessary by doing
- mknod /dev/aztcd0 b 29 0
- mkdir /mnt
-
-If you still get a different message while Linux boots or when you get the
-message, that the ISO9660-filesystem is not supported by your kernel, when
-you try to mount the CD-ROM drive, you have to recompile your kernel.
-
-If you do *not* have an Aztech/Orchid/Okano/Wearnes/TXC drive and want to
-bypass drive detection during Linux boot up, start with boot parameter aztcd=0.
-
-Most distributions nowadays do contain a boot disk image containing aztcd.
-Please note, that this driver will not work with IDE/ATAPI drives! With these
-you must use ide-cd.c instead.
-
-4. RECOMPILING YOUR KERNEL
-If your kernel is not yet configured for the AZTECH driver and the ISO9660-
-filesystem, you have to recompile your kernel:
-
-- Edit aztcd.h to set the I/O-address to your I/O-Base address (AZT_BASE_ADDR),
- the driver does not use interrupts or DMA, so if you are using an AZTECH
- CD268, an ORCHID CD-3110 or ORCHID/WEARNES CDD110 that's the only item you
- have to set up. If you have a soundcard, read chapter 4.2.
- Users of other drives should read chapter OTHER DRIVES of this file.
- You also can configure that address by kernel boot parameter aztcd=...
-- aztcd may be configured to use autoprobing the base address by setting
- AZT_BASE_ADDR to '-1'. In that case aztcd probes the addresses listed
- under AZT_BASE_AUTO. But please remember, that autoprobing always may
- incorrectly influence other hardware components too!
-- There are some other points, which may be configured, e.g. auto-eject the
- CD when unmounting a drive, tray locking etc., see aztcd.h for details.
-- If you're using a linux kernel version prior to 2.1.0, in aztcd.h
- uncomment the line '#define AZT_KERNEL_PRIOR_2_1'
-- Build a new kernel, configure it for 'Aztech/Orchid/Okano/Wearnes support'
- (if you want aztcd to be part of the kernel). Do not configure it for
- 'Aztech... support', if you want to use aztcd as a run time loadable module.
- But in any case you must have the ISO9660-filesystem included in your
- kernel.
-- Activate the new kernel, normally this is done by running LILO (don't for-
- get to configure it before and to keep a copy of your old kernel in case
- something goes wrong!).
-- Reboot
-- If you've included aztcd in your kernel, you now should see during boot
- some messages like
- Aztech CD-ROM Init: DriverVersion=<version number> BaseAddress=<baseaddress>
- Aztech CD-ROM Init: FirmwareVersion=<firmware version id of your I/O-card>
- Aztech CD-ROM Init: <drive type> detected
- Aztech CD-ROM Init: End
-- If you have not included aztcd in your kernel, but want to load aztcd as a
- run time loadable module see 4.1.
-- If the message looks correct, as user 'root' you should be able to mount
- the drive by
- mount -t iso9660 -r /dev/aztcd0 /mnt
- and use it as any other filesystem. (If this does not work, check if
- /dev/aztcd0 and /mnt do exist and create them, if necessary by doing
- mknod /dev/aztcd0 b 29 0
- mkdir /mnt
-- If this still does not help, see chapters OTHER DRIVES and DEBUGGING.
-
-4.1 AZTCD AS A RUN-TIME LOADABLE MODULE
-If you do not need aztcd permanently, you can also load and remove the driver
-during runtime via insmod and rmmod. To build aztcd as a loadable module you
-must configure your kernel for AZTECH module support (answer 'm' when con-
-figuring the kernel). Anyhow, you may run into problems, if the version of
-your boot kernel is not the same than the source kernel version, from which
-you create the modules. So rebuild your kernel, if necessary.
-
-Now edit the base address of your AZTECH interface card in
-/usr/src/linux/drivers/cdrom/aztcd.h to the appropriate value.
-aztcd may be configured to use autoprobing the base address by setting
-AZT_BASE_ADDR to '-1'. In that case aztcd probes the addresses listed
-under AZT_BASE_AUTO. But please remember, that autoprobing always may
-incorrectly influence other hardware components too!
-There are also some special features which may be configured, e.g.
-auto-eject a CD when unmounting the drive etc; see aztcd.h for details.
-Then change to /usr/src/linux and do a
- make modules
- make modules_install
-After that you can run-time load the driver via
- insmod /lib/modules/X.X.X/misc/aztcd.o
-and remove it via rmmod aztcd.
-If you did not set the correct base address in aztcd.h, you can also supply the
-base address when loading the driver via
- insmod /lib/modules/X.X.X/misc/aztcd.o aztcd=<base address>
-Again specifying aztcd=-1 will cause autoprobing.
-If you do not have the iso9660-filesystem in your boot kernel, you also have
-to load it before you can mount the CDROM:
- insmod /lib/modules/X.X.X/fs/isofs.o
-The mount procedure works as described in 4. above.
-(In all commands 'X.X.X' is the current linux kernel version number)
-
-4.2 CDROM CONNECTED TO A SOUNDCARD
-Most soundcards do have a bus interface to the CDROM-drive. In many cases
-this soundcard needs to be configured, before the CDROM can be used. This
-configuration procedure consists of writing some kind of initialization
-data to the soundcard registers. The AZTECH-CDROM driver in the moment does
-only support one type of soundcard (SoundWave32). Users of other soundcards
-should try to boot DOS first and let their DOS drivers initialize the
-soundcard and CDROM, then warm boot (or use loadlin) their PC to start
-Linux.
-Support for the CDROM-interface of SoundWave32-soundcards is directly
-implemented in the AZTECH driver. Please edit linux/drivers/cdrom/aztdc.h,
-uncomment line '#define AZT_SW32' and set the appropriate value for
-AZT_BASE_ADDR and AZT_SW32_BASE_ADDR. This support was tested with an Orchid
-CDS-3110 connected to a SoundWave32.
-If you want your soundcard to be supported, find out, how it needs to be
-configured and mail me (see 6.) the appropriate information.
-
-5. KNOWN PROBLEMS, FUTURE DEVELOPMENTS
-5.1 MULTISESSION SUPPORT
-Multisession support for CD's still is a myth. I implemented and tested a basic
-support for multisession and XA CDs, but I still have not enough CDs and appli-
-cations to test it rigorously. So if you'd like to help me, please contact me
-(Email address see below). As of version 1.4 and newer you can enable the
-multisession support in aztcd.h by setting AZT_MULTISESSION to 1. Doing so
-will cause the ISO9660-filesystem to deal with multisession CDs, ie. redirect
-requests to the Table of Contents (TOC) information from the last session,
-which contains the info of all previous sessions etc.. If you do set
-AZT_MULTISESSION to 0, you can use multisession CDs anyway. In that case the
-drive's firmware will do automatic redirection. For the ISO9660-filesystem any
-multisession CD will then look like a 'normal' single session CD. But never-
-theless the data of all sessions are viewable and accessible. So with practical-
-ly all real world applications you won't notice the difference. But as future
-applications may make use of advanced multisession features, I've started to
-implement the interface for the ISO9660 multisession interface via ioctl
-CDROMMULTISESSION.
-
-5.2 STATUS RECOGNITION
-The drive status recognition does not work correctly in all cases. Changing
-a disk or having the door open, when a drive is already mounted, is detected
-by the Aztech driver itself, but nevertheless causes multiple read attempts
-by the different layers of the ISO9660-filesystem driver, which finally timeout,
-so you have to wait quite a little... But isn't it bad style to change a disk
-in a mounted drive, anyhow ?!
-
-The driver uses busy wait in most cases for the drive handshake (macros
-STEN_LOW and DTEN_LOW). I tested with a 486/DX2 at 66MHz and a Pentium at
-60MHz and 90MHz. Whenever you use a much faster machine you are likely to get
-timeout messages. In that case edit aztcd.h and increase the timeout value
-AZT_TIMEOUT.
-
-For some 'slow' drive commands I implemented waiting with a timer waitqueue
-(macro STEN_LOW_WAIT). If you get this timeout message, you may also edit
-aztcd.h and increase the timeout value AZT_STATUS_DELAY. The waitqueue has
-shown to be a little critical. If you get kernel panic messages, edit aztcd.c
-and substitute STEN_LOW_WAIT by STEN_LOW. Busy waiting with STEN_LOW is more
-stable, but also causes CPU overhead.
-
-5.3 DOSEMU's CD-ROM SUPPORT
-With release 1.20 aztcd was modified to allow access to CD-ROMS when running
-under dosemu-0.60.0 aztcd-versions before 1.20 are most likely to crash
-Linux, when a CD-ROM is accessed under dosemu. This problem has partly been
-fixed, but still when accessing a directory for the first time the system
-might hang for some 30sec. So be patient, when using dosemu's CD-ROM support
-in combination with aztcd :-) !
-This problem has now (July 1995) been fixed by a modification to dosemu's
-CD-ROM driver. The new version came with dosemu-0.60.2, see dosemu's
-README.CDROM.
-
-6. BUG REPORTS
-Please send detailed bug reports and bug fixes via EMail to
-
- Werner.Zimmermann@fht-esslingen.de
-
-Please include a description of your CD-ROM drive type and interface card,
-the exact firmware message during Linux bootup, the version number of the
-AZTECH-CDROM-driver and the Linux kernel version. Also a description of your
-system's other hardware could be of interest, especially microprocessor type,
-clock frequency, other interface cards such as soundcards, ethernet adapter,
-game cards etc..
-
-I will try to collect the reports and make the necessary modifications from
-time to time. I may also come back to you directly with some bug fixes and
-ask you to do further testing and debugging.
-
-Editors of CD-ROMs are invited to send a 'cooperation' copy of their
-CD-ROMs to the volunteers, who provided the CD-ROM support for Linux. My
-snail mail address for such 'stuff' is
- Prof. Dr. W. Zimmermann
- Fachhochschule fuer Technik Esslingen
- Fachbereich IT
- Flandernstrasse 101
- D-73732 Esslingen
- Germany
-
-
-7. OTHER DRIVES
-The following drives ORCHID CDS3110, OKANO CDD110, WEARNES CDD110 and Conrad
-TXC Nr. 993123-series 04 nearly look the same as AZTECH CDA268-01A, especially
-they seem to use the same command codes. So it was quite simple to make the
-AZTECH driver work with these drives.
-
-Unfortunately I do not have any of these drives available, so I couldn't test
-it myself. In some installations, it seems necessary to initialize the drive
-with the DOS driver before (especially if combined with a sound card) and then
-do a warm boot (CTRL-ALT-RESET) or start Linux from DOS, e.g. with 'loadlin'.
-
-If you do not succeed, read chapter DEBUGGING. Thanks in advance!
-
-Sorry for the inconvenience, but it is difficult to develop for hardware,
-which you don't have available for testing. So if you like, please help us.
-
-If you do have a CyCDROM CR520ie thanks to Hilmar Berger's help your chances
-are good, that it will work with aztcd. The CR520ie is sold as an IDE-drive
-and really is connected to the IDE interface (primary at 0x1F0 or secondary
-at 0x170, configured as slave, not as master). Nevertheless it is not ATAPI
-compatible but still uses Aztech's command codes.
-
-
-8. DEBUGGING : IF YOU DON'T SUCCEED, TRY THE FOLLOWING
--reread the complete README file
--make sure, that your drive is hardware configured for
- transfer mode: polled
- IRQ: not used
- DMA: not used
- Base Address: something like 300, 320 ...
- You can check this, when you start the DOS driver, which came with your
- drive. By appropriately configuring the drive and the DOS driver you can
- check, whether your drive does operate in this mode correctly under DOS. If
- it does not operate under DOS, it won't under Linux.
- If your drive's base address is something like 0x170 or 0x1F0 (and it is
- not a CyCDROM CR520ie or CR 940ie) you most likely are having an IDE/ATAPI-
- compatible drive, which is not supported by aztcd.c, use ide-cd.c instead.
- Make sure the Base Address is configured correctly in aztcd.h, also make
- sure, that /dev/aztcd0 exists with the correct major number (compare it with
- the entry in file /usr/include/linux/major.h for the Aztech drive).
--insert a CD-ROM and close the tray
--cold boot your PC (i.e. via the power on switch or the reset button)
--if you start Linux via DOS, e.g. using loadlin, make sure, that the DOS
- driver for the CD-ROM drive is not loaded (comment out the calling lines
- in DOS' config.sys!)
--look for the aztcd: init message during Linux init and note them exactly
--log in as root and do a mount -t iso9660 /dev/aztcd0 /mnt
--if you don't succeed in the first time, try several times. Try also to open
- and close the tray, then mount again. Please note carefully all commands
- you typed in and the aztcd-messages, which you get.
--if you get an 'Aztech CD-ROM init: aborted' message, read the remarks about
- the version string below.
-
-If this does not help, do the same with the following differences
--start DOS before; make now sure, that the DOS driver for the CD-ROM is
- loaded under DOS (i.e. uncomment it again in config.sys)
--warm boot your PC (i.e. via CTRL-ALT-DEL)
- if you have it, you can also start via loadlin (try both).
- ...
- Again note all commands and the aztcd-messages.
-
-If you see STEN_LOW or STEN_LOW_WAIT error messages, increase the timeout
-values.
-
-If this still does not help,
--look in aztcd.c for the lines #if 0
- #define AZT_TEST1
- ...
- #endif
- and substitute '#if 0' by '#if 1'.
--recompile your kernel and repeat the above two procedures. You will now get
- a bundle of debugging messages from the driver. Again note your commands
- and the appropriate messages. If you have syslogd running, these messages
- may also be found in syslogd's kernel log file. Nevertheless in some
- installations syslogd does not yet run, when init() is called, thus look for
- the aztcd-messages during init, before the login-prompt appears.
- Then look in aztcd.c, to find out, what happened. The normal calling sequence
- is: aztcd_init() during Linux bootup procedure init()
- after doing a 'mount -t iso9660 /dev/aztcd0 /mnt' the normal calling sequence is
- aztcd_open() -> Status 2c after cold reboot with CDROM or audio CD inserted
- -> Status 8 after warm reboot with CDROM inserted
- -> Status 2e after cold reboot with no disk, closed tray
- -> Status 6e after cold reboot, mount with door open
- aztUpdateToc()
- aztGetDiskInfo()
- aztGetQChannelInfo() repeated several times
- aztGetToc()
- aztGetQChannelInfo() repeated several times
- a list of track information
- do_aztcd_request() }
- azt_transfer() } repeated several times
- azt_poll }
- Check, if there is a difference in the calling sequence or the status flags!
-
- There are a lot of other messages, eg. the ACMD-command code (defined in
- aztcd.h), status info from the getAztStatus-command and the state sequence of
- the finite state machine in azt_poll(). The most important are the status
- messages, look how they are defined and try to understand, if they make
- sense in the context where they appear. With a CD-ROM inserted the status
- should always be 8, except in aztcd_open(). Try to open the tray, insert an
- audio disk, insert no disk or reinsert the CD-ROM and check, if the status
- bits change accordingly. The status bits are the most likely point, where
- the drive manufacturers may implement changes.
-
-If you still don't succeed, a good point to start is to look in aztcd.c in
-function aztcd_init, where the drive should be detected during init. Do the
-following:
--reboot the system with boot parameter 'aztcd=<your base address>,0x79'. With
- parameter 0x79 most of the drive version detection is bypassed. After that
- you should see the complete version string including leading and trailing
- blanks during init.
- Now adapt the statement
- if ((result[1]=='A')&&(result[2]=='Z' ...)
- in aztcd_init() to exactly match the first 3 or 4 letters you have seen.
--Another point is the 'smart' card detection feature in aztcd_init(). Normally
- the CD-ROM drive is ready, when aztcd_init is trying to read the version
- string and a time consuming ACMD_SOFT_RESET command can be avoided. This is
- detected by looking, if AFL_OP_OK can be read correctly. If the CD-ROM drive
- hangs in some unknown state, e.g. because of an error before a warm start or
- because you first operated under DOS, even the version string may be correct,
- but the following commands will not. Then change the code in such a way,
- that the ACMD_SOFT_RESET is issued in any case, by substituting the
- if-statement 'if ( ...=AFL_OP_OK)' by 'if (1)'.
-
-If you succeed, please mail me the exact version string of your drive and
-the code modifications, you have made together with a short explanation.
-If you don't succeed, you may mail me the output of the debugging messages.
-But remember, they are only useful, if they are exact and complete and you
-describe in detail your hardware setup and what you did (cold/warm reboot,
-with/without DOS, DOS-driver started/not started, which Linux-commands etc.)
-
-
-9. TECHNICAL HISTORY OF THE DRIVER
-The AZTECH-Driver is a rework of the Mitsumi-Driver. Four major items had to
-be reworked:
-
-a) The Mitsumi drive does issue complete status information acknowledging
-each command, the Aztech drive does only signal that the command was
-processed. So whenever the complete status information is needed, an extra
-ACMD_GET_STATUS command is issued. The handshake procedure for the drive
-can be found in the functions aztSendCmd(), sendAztCmd() and getAztStatus().
-
-b) The Aztech Drive does not have a ACMD_GET_DISK_INFO command, so the
-necessary info about the number of tracks (firstTrack, lastTrack), disk
-length etc. has to be read from the TOC in the lead in track (see function
-aztGetDiskInfo()).
-
-c) Whenever data is read from the drive, the Mitsumi drive is started with a
-command to read an indefinite (0xffffff) number of sectors. When the appropriate
-number of sectors is read, the drive is stopped by a ACDM_STOP command. This
-does not work with the Aztech drive. I did not find a way to stop it. The
-stop and pause commands do only work in AUDIO mode but not in DATA mode.
-Therefore I had to modify the 'finite state machine' in function azt_poll to
-only read a certain number of sectors and then start a new read on demand. As I
-have not completely understood, how the buffer/caching scheme of the Mitsumi
-driver was implemented, I am not sure, if I have covered all cases correctly,
-whenever you get timeout messages, the bug is most likely to be in that
-function azt_poll() around switch(cmd) .... case ACD_S_DATA.
-
-d) I did not get information about changing drive mode. So I doubt, that the
-code around function azt_poll() case AZT_S_MODE does work. In my test I have
-not been able to switch to reading in raw mode. For reading raw mode, Aztech
-uses a different command than for cooked mode, which I only have implemen-
-ted in the ioctl-section but not in the section which is used by the ISO9660.
-
-The driver was developed on an AST PC with Intel 486/DX2, 8MB RAM, 340MB IDE
-hard disk and on an AST PC with Intel Pentium 60MHz, 16MB RAM, 520MB IDE
-running Linux kernel version 1.0.9 from the LST 1.8 Distribution. The kernel
-was compiled with gcc.2.5.8. My CD-ROM drive is an Aztech CDA268-01A. My
-drive says, that it has Firmware Version AZT26801A1.3. It came with an ISA-bus
-interface card and works with polled I/O without DMA and without interrupts.
-The code for all other drives was 'remote' tested and debugged by a number of
-volunteers on the Internet.
-
-Points, where I feel that possible problems might be and all points where I
-did not completely understand the drive's behaviour or trust my own code are
-marked with /*???*/ in the source code. There are also some parts in the
-Mitsumi driver, where I did not completely understand their code.
-
-
-10. ACKNOWLEDGMENTS
-Without the help of P.Bush, Aztech, who delivered technical information
-about the Aztech Drive and without the help of E.Moenkeberg, GWDG, who did a
-great job in analyzing the command structure of various CD-ROM drives, this
-work would not have been possible. E.Moenkeberg was also a great help in
-making the software 'kernel ready' and in answering many of the CDROM-related
-questions in the newsgroups. He really is *the* Linux CD-ROM guru. Thanks
-also to all the guys on the Internet, who collected valuable technical
-information about CDROMs.
-
-Joe Nardone (joe@access.digex.net) was a patient tester even for my first
-trial, which was more than slow, and made suggestions for code improvement.
-Especially the 'finite state machine' azt_poll() was rewritten by Joe to get
-clean C code and avoid the ugly 'gotos', which I copied from mcd.c.
-
-Robby Schirmer (schirmer@fmi.uni-passau.de) tested the audio stuff (ioctls)
-and suggested a lot of patches for them.
-
-Joseph Piskor and Peter Nugent were the first users with the ORCHID CD3110
-and also were very patient with the problems which occurred.
-
-Reinhard Max delivered the information for the CDROM-interface of the
-SoundWave32 soundcards.
-
-Jochen Kunz and Olaf Kaluza delivered the information for supporting Conrad's
-TXC drive.
-
-Hilmar Berger delivered the patches for supporting CyCDROM CR520ie.
-
-Anybody, who is interested in these items should have a look at 'ftp.gwdg.de',
-directory 'pub/linux/cdrom' and at 'ftp.cdrom.com', directory 'pub/cdrom'.
-
-11. PROGRAMMING ADD ONs: cdplay.c
-You can use the ioctl-functions included in aztcd.c in your own programs. As
-an example on how to do this, you will find a tiny CD Player for audio CDs
-named 'cdplay.c'. It allows you to play audio CDs. You can play a specified
-track, pause and resume or skip tracks forward and backwards. If you quit the
-program without stopping the drive, playing is continued. You can also
-(mis)use cdplay to read and hexdump data disks. You can find the code in the
-APPENDIX of this file, which you should cut out with an editor and store in a
-separate file 'cdplay.c'. To compile it and make it executable, do
- gcc -s -Wall -O2 -L/usr/lib cdplay.c -o /usr/local/bin/cdplay # compiles it
- chmod +755 /usr/local/bin/cdplay # makes it executable
- ln -s /dev/aztcd0 /dev/cdrom # creates a link
- (for /usr/lib substitute the top level directory, where your include files
- reside, and for /usr/local/bin the directory, where you want the executable
- binary to reside )
-
-You have to set the correct permissions for cdplay *and* for /dev/mcd0 or
-/dev/aztcd0 in order to use it. Remember, that you should not have /dev/cdrom
-mounted, when you're playing audio CDs.
-
-This program is just a hack for testing the ioctl-functions in aztcd.c. I will
-not maintain it, so if you run into problems, discard it or have a look into
-the source code 'cdplay.c'. The program does only contain a minimum of user
-protection and input error detection. If you use the commands in the wrong
-order or if you try to read a CD at wrong addresses, you may get error messages
-or even hang your machine. If you get STEN_LOW, STEN_LOW_WAIT or segment violation
-error messages when using cdplay, after that, the system might not be stable
-any more, so you'd better reboot. As the ioctl-functions run in kernel mode,
-most normal Linux-multitasking protection features do not work. By using
-uninitialized 'wild' pointers etc., it is easy to write to other users' data
-and program areas, destroy kernel tables etc.. So if you experiment with ioctls
-as always when you are doing systems programming and kernel hacking, you
-should have a backup copy of your system in a safe place (and you also
-should try restoring from a backup copy first)!
-
-A reworked and improved version called 'cdtester.c', which has yet more
-features for testing CDROM-drives can be found in
-Documentation/cdrom/sbpcd, written by E.Moenkeberg.
-
-Werner Zimmermann
-Fachhochschule fuer Technik Esslingen
-(EMail: Werner.Zimmermann@fht-esslingen.de)
-October, 1997
-
----------------------------------------------------------------------------
-APPENDIX: Source code of cdplay.c
-
-/* Tiny Audio CD Player
-
- Copyright 1994, 1995, 1996 Werner Zimmermann (Werner.Zimmermann@fht-esslingen.de)
-
-This program originally was written to test the audio functions of the
-AZTECH.CDROM-driver, but it should work with every CD-ROM drive. Before
-using it, you should set a symlink from /dev/cdrom to your real CDROM
-device.
-
-The GNU General Public License applies to this program.
-
-History: V0.1 W.Zimmermann: First release. Nov. 8, 1994
- V0.2 W.Zimmermann: Enhanced functionality. Nov. 9, 1994
- V0.3 W.Zimmermann: Additional functions. Nov. 28, 1994
- V0.4 W.Zimmermann: fixed some bugs. Dec. 17, 1994
- V0.5 W.Zimmermann: clean 'scanf' commands without compiler warnings
- Jan. 6, 1995
- V0.6 W.Zimmermann: volume control (still experimental). Jan. 24, 1995
- V0.7 W.Zimmermann: read raw modified. July 26, 95
-*/
-
-#include <stdio.h>
-#include <ctype.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/cdrom.h>
-#include <linux/../../drivers/cdrom/aztcd.h>
-
-void help(void)
-{ printf("Available Commands: STOP s EJECT/CLOSE e QUIT q\n");
- printf(" PLAY TRACK t PAUSE p RESUME r\n");
- printf(" NEXT TRACK n REPEAT LAST l HELP h\n");
- printf(" SUB CHANNEL c TRACK INFO i PLAY AT a\n");
- printf(" READ d READ RAW w VOLUME v\n");
-}
-
-int main(void)
-{ int handle;
- unsigned char command=' ', ini=0, first=1, last=1;
- unsigned int cmd, i,j,k, arg1,arg2,arg3;
- struct cdrom_ti ti;
- struct cdrom_tochdr tocHdr;
- struct cdrom_subchnl subchnl;
- struct cdrom_tocentry entry;
- struct cdrom_msf msf;
- union { struct cdrom_msf msf;
- unsigned char buf[CD_FRAMESIZE_RAW];
- } azt;
- struct cdrom_volctrl volctrl;
-
- printf("\nMini-Audio CD-Player V0.72 (C) 1994,1995,1996 W.Zimmermann\n");
- handle=open("/dev/cdrom",O_RDWR);
- ioctl(handle,CDROMRESUME);
-
- if (handle<=0)
- { printf("Drive Error: already playing, no audio disk, door open\n");
- printf(" or no permission (you must be ROOT in order to use this program)\n");
- }
- else
- { help();
- while (1)
- { printf("Type command (h = help): ");
- scanf("%s",&command);
- switch (command)
- { case 'e': cmd=CDROMEJECT;
- ioctl(handle,cmd);
- break;
- case 'p': if (!ini)
- { printf("Command not allowed - play track first\n");
- }
- else
- { cmd=CDROMPAUSE;
- if (ioctl(handle,cmd)) printf("Drive Error\n");
- }
- break;
- case 'r': if (!ini)
- { printf("Command not allowed - play track first\n");
- }
- else
- { cmd=CDROMRESUME;
- if (ioctl(handle,cmd)) printf("Drive Error\n");
- }
- break;
- case 's': cmd=CDROMPAUSE;
- if (ioctl(handle,cmd)) printf("Drive error or already stopped\n");
- cmd=CDROMSTOP;
- if (ioctl(handle,cmd)) printf("Drive error\n");
- break;
- case 't': cmd=CDROMREADTOCHDR;
- if (ioctl(handle,cmd,&tocHdr)) printf("Drive Error\n");
- first=tocHdr.cdth_trk0;
- last= tocHdr.cdth_trk1;
- if ((first==0)||(first>last))
- { printf ("--could not read TOC\n");
- }
- else
- { printf("--first track: %d --last track: %d --enter track number: ",first,last);
- cmd=CDROMPLAYTRKIND;
- scanf("%i",&arg1);
- ti.cdti_trk0=arg1;
- if (ti.cdti_trk0<first) ti.cdti_trk0=first;
- if (ti.cdti_trk0>last) ti.cdti_trk0=last;
- ti.cdti_ind0=0;
- ti.cdti_trk1=last;
- ti.cdti_ind1=0;
- if (ioctl(handle,cmd,&ti)) printf("Drive Error\n");
- ini=1;
- }
- break;
- case 'n': if (!ini++)
- { if (ioctl(handle,CDROMREADTOCHDR,&tocHdr)) printf("Drive Error\n");
- first=tocHdr.cdth_trk0;
- last= tocHdr.cdth_trk1;
- ti.cdti_trk0=first-1;
- }
- if ((first==0)||(first>last))
- { printf ("--could not read TOC\n");
- }
- else
- { cmd=CDROMPLAYTRKIND;
- if (++ti.cdti_trk0 > last) ti.cdti_trk0=last;
- ti.cdti_ind0=0;
- ti.cdti_trk1=last;
- ti.cdti_ind1=0;
- if (ioctl(handle,cmd,&ti)) printf("Drive Error\n");
- ini=1;
- }
- break;
- case 'l': if (!ini++)
- { if (ioctl(handle,CDROMREADTOCHDR,&tocHdr)) printf("Drive Error\n");
- first=tocHdr.cdth_trk0;
- last= tocHdr.cdth_trk1;
- ti.cdti_trk0=first+1;
- }
- if ((first==0)||(first>last))
- { printf ("--could not read TOC\n");
- }
- else
- { cmd=CDROMPLAYTRKIND;
- if (--ti.cdti_trk0 < first) ti.cdti_trk0=first;
- ti.cdti_ind0=0;
- ti.cdti_trk1=last;
- ti.cdti_ind1=0;
- if (ioctl(handle,cmd,&ti)) printf("Drive Error\n");
- ini=1;
- }
- break;
- case 'c': subchnl.cdsc_format=CDROM_MSF;
- if (ioctl(handle,CDROMSUBCHNL,&subchnl))
- printf("Drive Error\n");
- else
- { printf("AudioStatus:%s Track:%d Mode:%d MSF=%d:%d:%d\n", \
- subchnl.cdsc_audiostatus==CDROM_AUDIO_PLAY ? "PLAYING":"NOT PLAYING",\
- subchnl.cdsc_trk,subchnl.cdsc_adr, \
- subchnl.cdsc_absaddr.msf.minute, subchnl.cdsc_absaddr.msf.second, \
- subchnl.cdsc_absaddr.msf.frame);
- }
- break;
- case 'i': if (!ini)
- { printf("Command not allowed - play track first\n");
- }
- else
- { cmd=CDROMREADTOCENTRY;
- printf("Track No.: ");
- scanf("%d",&arg1);
- entry.cdte_track=arg1;
- if (entry.cdte_track<first) entry.cdte_track=first;
- if (entry.cdte_track>last) entry.cdte_track=last;
- entry.cdte_format=CDROM_MSF;
- if (ioctl(handle,cmd,&entry))
- { printf("Drive error or invalid track no.\n");
- }
- else
- { printf("Mode %d Track, starts at %d:%d:%d\n", \
- entry.cdte_adr,entry.cdte_addr.msf.minute, \
- entry.cdte_addr.msf.second,entry.cdte_addr.msf.frame);
- }
- }
- break;
- case 'a': cmd=CDROMPLAYMSF;
- printf("Address (min:sec:frame) ");
- scanf("%d:%d:%d",&arg1,&arg2,&arg3);
- msf.cdmsf_min0 =arg1;
- msf.cdmsf_sec0 =arg2;
- msf.cdmsf_frame0=arg3;
- if (msf.cdmsf_sec0 > 59) msf.cdmsf_sec0 =59;
- if (msf.cdmsf_frame0> 74) msf.cdmsf_frame0=74;
- msf.cdmsf_min1=60;
- msf.cdmsf_sec1=00;
- msf.cdmsf_frame1=00;
- if (ioctl(handle,cmd,&msf))
- { printf("Drive error or invalid address\n");
- }
- break;
-#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
- case 'd': cmd=CDROMREADCOOKED;
- printf("Address (min:sec:frame) ");
- scanf("%d:%d:%d",&arg1,&arg2,&arg3);
- azt.msf.cdmsf_min0 =arg1;
- azt.msf.cdmsf_sec0 =arg2;
- azt.msf.cdmsf_frame0=arg3;
- if (azt.msf.cdmsf_sec0 > 59) azt.msf.cdmsf_sec0 =59;
- if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
- if (ioctl(handle,cmd,&azt.msf))
- { printf("Drive error, invalid address or unsupported command\n");
- }
- k=0;
- getchar();
- for (i=0;i<128;i++)
- { printf("%4d:",i*16);
- for (j=0;j<16;j++)
- { printf("%2x ",azt.buf[i*16+j]);
- }
- for (j=0;j<16;j++)
- { if (isalnum(azt.buf[i*16+j]))
- printf("%c",azt.buf[i*16+j]);
- else
- printf(".");
- }
- printf("\n");
- k++;
- if (k>=20)
- { printf("press ENTER to continue\n");
- getchar();
- k=0;
- }
- }
- break;
- case 'w': cmd=CDROMREADRAW;
- printf("Address (min:sec:frame) ");
- scanf("%d:%d:%d",&arg1,&arg2,&arg3);
- azt.msf.cdmsf_min0 =arg1;
- azt.msf.cdmsf_sec0 =arg2;
- azt.msf.cdmsf_frame0=arg3;
- if (azt.msf.cdmsf_sec0 > 59) azt.msf.cdmsf_sec0 =59;
- if (azt.msf.cdmsf_frame0> 74) azt.msf.cdmsf_frame0=74;
- if (ioctl(handle,cmd,&azt))
- { printf("Drive error, invalid address or unsupported command\n");
- }
- k=0;
- for (i=0;i<147;i++)
- { printf("%4d:",i*16);
- for (j=0;j<16;j++)
- { printf("%2x ",azt.buf[i*16+j]);
- }
- for (j=0;j<16;j++)
- { if (isalnum(azt.buf[i*16+j]))
- printf("%c",azt.buf[i*16+j]);
- else
- printf(".");
- }
- printf("\n");
- k++;
- if (k>=20)
- { getchar();
- k=0;
- }
- }
- break;
-#endif
- case 'v': cmd=CDROMVOLCTRL;
- printf("--Channel 0 Left (0-255): ");
- scanf("%d",&arg1);
- printf("--Channel 1 Right (0-255): ");
- scanf("%d",&arg2);
- volctrl.channel0=arg1;
- volctrl.channel1=arg2;
- volctrl.channel2=0;
- volctrl.channel3=0;
- if (ioctl(handle,cmd,&volctrl))
- { printf("Drive error or unsupported command\n");
- }
- break;
- case 'q': if (close(handle)) printf("Drive Error: CLOSE\n");
- exit(0);
- case 'h': help();
- break;
- default: printf("unknown command\n");
- break;
- }
- }
- }
- return 0;
-}
diff --git a/Documentation/cdrom/cdu31a b/Documentation/cdrom/cdu31a
deleted file mode 100644
index c0667da09c00..000000000000
--- a/Documentation/cdrom/cdu31a
+++ /dev/null
@@ -1,196 +0,0 @@
-
- CDU31A/CDU33A Driver Info
- -------------------------
-
-Information on the Sony CDU31A/CDU33A CDROM driver for the Linux
-kernel.
-
- Corey Minyard (minyard@metronet.com)
-
- Colossians 3:17
-
-Crude Table of Contents
------------------------
-
- Setting Up the Hardware
- Configuring the Kernel
- Configuring as a Module
- Driver Special Features
-
-
-This device driver handles Sony CDU31A/CDU33A CDROM drives and
-provides a complete block-level interface as well as an ioctl()
-interface as specified in include/linux/cdrom.h). With this
-interface, CDROMs can be accessed, standard audio CDs can be played
-back normally, and CD audio information can be read off the drive.
-
-Note that this will only work for CDU31A/CDU33A drives. Some vendors
-market their drives as CDU31A compatible. They lie. Their drives are
-really CDU31A hardware interface compatible (they can plug into the
-same card). They are not software compatible.
-
-Setting Up the Hardware
------------------------
-
-The CDU31A driver is unable to safely tell if an interface card is
-present that it can use because the interface card does not announce
-its presence in any way besides placing 4 I/O locations in memory. It
-used to just probe memory and attempt commands, but Linus wisely asked
-me to remove that because it could really screw up other hardware in
-the system.
-
-Because of this, you must tell the kernel where the drive interface
-is, what interrupts are used, and possibly if you are on a PAS-16
-soundcard.
-
-If you have the Sony CDU31A/CDU33A drive interface card, the following
-diagram will help you set it up. If you have another card, you are on
-your own. You need to make sure that the I/O address and interrupt is
-not used by another card in the system. You will need to know the I/O
-address and interrupt you have set. Note that use of interrupts is
-highly recommended, if possible, it really cuts down on CPU used.
-Unfortunately, most soundcards do not support interrupts for their
-CDROM interfaces. By default, the Sony interface card comes with
-interrupts disabled.
-
- +----------+-----------------+----------------------+
- | JP1 | 34 Pin Conn | |
- | JP2 +-----------------+ |
- | JP3 |
- | JP4 |
- | +--+
- | | +-+
- | | | | External
- | | | | Connector
- | | | |
- | | +-+
- | +--+
- | |
- | +--------+
- | |
- +------------------------------------------+
-
- JP1 sets the Base Address, using the following settings:
-
- Address Pin 1 Pin 2
- ------- ----- -----
- 0x320 Short Short
- 0x330 Short Open
- 0x340 Open Short
- 0x360 Open Open
-
- JP2 and JP3 configure the DMA channel; they must be set the same.
-
- DMA Pin 1 Pin 2 Pin 3
- --- ----- ----- -----
- 1 On Off On
- 2 Off On Off
- 3 Off Off On
-
- JP4 Configures the IRQ:
-
- IRQ Pin 1 Pin 2 Pin 3 Pin 4
- --- ----- ----- ----- -----
- 3 Off Off On Off
- 4 Off Off* Off On
- 5 On Off Off Off
- 6 Off On Off Off
-
- The documentation states to set this for interrupt
- 4, but I think that is a mistake.
-
-Note that if you have another interface card, you will need to look at
-the documentation to find the I/O base address. This is specified to
-the SLCD.SYS driver for DOS with the /B: parameter, so you can look at
-you DOS driver setup to find the address, if necessary.
-
-Configuring the Kernel
-----------------------
-
-You must tell the kernel where the drive is at boot time. This can be
-done at the Linux boot prompt, by using LILO, or by using Bootlin.
-Note that this is no substitute for HOWTOs and LILO documentation, if
-you are confused please read those for info on bootline configuration
-and LILO.
-
-At the linux boot prompt, press the ALT key and add the following line
-after the boot name (you can let the kernel boot, it will tell you the
-default boot name while booting):
-
- cdu31a=<base address>,<interrupt>[,PAS]
-
-The base address needs to have "0x" in front of it, since it is in
-hex. For instance, to configure a drive at address 320 on interrupt 5,
-use the following:
-
- cdu31a=0x320,5
-
-I use the following boot line:
-
- cdu31a=0x1f88,0,PAS
-
-because I have a PAS-16 which does not support interrupt for the
-CDU31A interface.
-
-Adding this as an append line at the beginning of the /etc/lilo.conf
-file will set it for lilo configurations. I have the following as the
-first line in my lilo.conf file:
-
- append="cdu31a=0x1f88,0"
-
-I'm not sure how to set up Bootlin (I have never used it), if someone
-would like to fill in this section please do.
-
-
-Configuring as a Module
------------------------
-
-The driver supports loading as a module. However, you must specify
-the boot address and interrupt on the boot line to insmod. You can't
-use modprobe to load it, since modprobe doesn't support setting
-variables.
-
-Anyway, I use the following line to load my driver as a module
-
- /sbin/insmod /lib/modules/`uname -r`/misc/cdu31a.o cdu31a_port=0x1f88
-
-You can set the following variables in the driver:
-
- cdu31a_port=<I/O address> - sets the base I/O. If hex, put 0x in
- front of it. This must be specified.
-
- cdu31a_irq=<interrupt> - Sets the interrupt number. Leaving this
- off will turn interrupts off.
-
-
-Driver Special Features
------------------------
-
-This section describes features beyond the normal audio and CD-ROM
-functions of the drive.
-
-2048 byte buffer mode
-
-If a disk is mounted with -o block=2048, data is copied straight from
-the drive data port to the buffer. Otherwise, the readahead buffer
-must be involved to hold the other 1K of data when a 1K block
-operation is done. Note that with 2048 byte blocks you cannot execute
-files from the CD.
-
-XA compatibility
-
-The driver should support XA disks for both the CDU31A and CDU33A. It
-does this transparently, the using program doesn't need to set it.
-
-Multi-Session
-
-A multi-session disk looks just like a normal disk to the user. Just
-mount one normally, and all the data should be there. A special
-thanks to Koen for help with this!
-
-Raw sector I/O
-
-Using the CDROMREADAUDIO it is possible to read raw audio and data
-tracks. Both operations return 2352 bytes per sector. On the data
-tracks, the first 12 bytes is not returned by the drive and the value
-of that data is indeterminate.
diff --git a/Documentation/cdrom/cm206 b/Documentation/cdrom/cm206
deleted file mode 100644
index 810368f4f7c4..000000000000
--- a/Documentation/cdrom/cm206
+++ /dev/null
@@ -1,185 +0,0 @@
-This is the readme file for the driver for the Philips/LMS cdrom drive
-cm206 in combination with the cm260 host adapter card.
-
- (c) 1995 David A. van Leeuwen
-
-Changes since version 0.99
---------------------------
-- Interfacing to the kernel is routed though an extra interface layer,
- cdrom.c. This allows runtime-configurable `behavior' of the cdrom-drive,
- independent of the driver.
-
-Features since version 0.33
----------------------------
-- Full audio support, that is, both workman, workbone and cdp work
- now reasonably. Reading TOC still takes some time. xmcd has been
- reported to run successfully.
-- Made auto-probe code a little better, I hope
-
-Features since version 0.28
----------------------------
-- Full speed transfer rate (300 kB/s).
-- Minimum kernel memory usage for buffering (less than 3 kB).
-- Multisession support.
-- Tray locking.
-- Statistics of driver accessible to the user.
-- Module support.
-- Auto-probing of adapter card's base port and irq line,
- also configurable at boot time or module load time.
-
-
-Decide how you are going to use the driver. There are two
-options:
-
- (a) installing the driver as a resident part of the kernel
- (b) compiling the driver as a loadable module
-
- Further, you must decide if you are going to specify the base port
- address and the interrupt request line of the adapter card cm260 as
- boot options for (a), module parameters for (b), use automatic
- probing of these values, or hard-wire your adaptor card's settings
- into the source code. If you don't care, you can choose
- autoprobing, which is the default. In that case you can move on to
- the next step.
-
-Compiling the kernel
---------------------
-1) move to /usr/src/linux and do a
-
- make config
-
- If you have chosen option (a), answer yes to CONFIG_CM206 and
- CONFIG_ISO9660_FS.
-
- If you have chosen option (b), answer yes to CONFIG_MODVERSIONS
- and no (!) to CONFIG_CM206 and CONFIG_ISO9660_FS.
-
-2) then do a
-
- make clean; make zImage; make modules
-
-3) do the usual things to install a new image (backup the old one, run
- `rdev -R zImage 1', copy the new image in place, run lilo). Might
- be `make zlilo'.
-
-Using the driver as a module
-----------------------------
-If you will only occasionally use the cd-rom driver, you can choose
-option (b), install as a loadable module. You may have to re-compile
-the module when you upgrade the kernel to a new version.
-
-Since version 0.96, much of the functionality has been transferred to
-a generic cdrom interface in the file cdrom.c. The module cm206.o
-depends on cdrom.o. If the latter is not compiled into the kernel,
-you must explicitly load it before cm206.o:
-
- insmod /usr/src/linux/modules/cdrom.o
-
-To install the module, you use the command, as root
-
- insmod /usr/src/linux/modules/cm206.o
-
-You can specify the base address on the command line as well as the irq
-line to be used, e.g.
-
- insmod /usr/src/linux/modules/cm206.o cm206=0x300,11
-
-The order of base port and irq line doesn't matter; if you specify only
-one, the other will have the value of the compiled-in default. You
-may also have to install the file-system module `iso9660.o', if you
-didn't compile that into the kernel.
-
-
-Using the driver as part of the kernel
---------------------------------------
-If you have chosen option (a), you can specify the base-port
-address and irq on the lilo boot command line, e.g.:
-
- LILO: linux cm206=0x340,11
-
-This assumes that your linux kernel image keyword is `linux'.
-If you specify either IRQ (3--11) or base port (0x300--0x370),
-auto probing is turned off for both settings, thus setting the
-other value to the compiled-in default.
-
-Note that you can also put these parameters in the lilo configuration file:
-
-# linux config
-image = /vmlinuz
- root = /dev/hda1
- label = Linux
- append = "cm206=0x340,11"
- read-only
-
-
-If module parameters and LILO config options don't work
--------------------------------------------------------
-If autoprobing does not work, you can hard-wire the default values
-of the base port address (CM206_BASE) and interrupt request line
-(CM206_IRQ) into the file /usr/src/linux/drivers/cdrom/cm206.h. Change
-the defines of CM206_IRQ and CM206_BASE.
-
-
-Mounting the cdrom
-------------------
-1) Make sure that the right device is installed in /dev.
-
- mknod /dev/cm206cd b 32 0
-
-2) Make sure there is a mount point, e.g., /cdrom
-
- mkdir /cdrom
-
-3) mount using a command like this (run as root):
-
- mount -rt iso9660 /dev/cm206cd /cdrom
-
-4) For user-mounts, add a line in /etc/fstab
-
- /dev/cm206cd /cdrom iso9660 ro,noauto,user
-
- This will allow users to give the commands
-
- mount /cdrom
- umount /cdrom
-
-If things don't work
---------------------
-
-- Try to do a `dmesg' to find out if the driver said anything about
- what is going wrong during the initialization.
-
-- Try to do a `dd if=/dev/cm206cd | od -tc | less' to read from the
- CD.
-
-- Look in the /proc directory to see if `cm206' shows up under one of
- `interrupts', `ioports', `devices' or `modules' (if applicable).
-
-
-DISCLAIMER
-----------
-I cannot guarantee that this driver works, or that the hardware will
-not be harmed, although I consider it most unlikely.
-
-I hope that you'll find this driver in some way useful.
-
- David van Leeuwen
- david@tm.tno.nl
-
-Note for Linux CDROM vendors
------------------------------
-You are encouraged to include this driver on your Linux CDROM. If
-you do, you might consider sending me a free copy of that cd-rom.
-You can contact me through my e-mail address, david@tm.tno.nl.
-If this driver is compiled into a kernel to boot off a cdrom,
-you should actually send me a free copy of that cd-rom.
-
-Copyright
----------
-The copyright of the cm206 driver for Linux is
-
- (c) 1995 David A. van Leeuwen
-
-The driver is released under the conditions of the GNU general public
-license, which can be found in the file COPYING in the root of this
-source tree.
diff --git a/Documentation/cdrom/gscd b/Documentation/cdrom/gscd
deleted file mode 100644
index d01ca36b5c43..000000000000
--- a/Documentation/cdrom/gscd
+++ /dev/null
@@ -1,60 +0,0 @@
- Goldstar R420 CD-Rom device driver README
-
-For all kind of other information about the GoldStar R420 CDROM
-and this Linux device driver see the WWW page:
-
- http://linux.rz.fh-hannover.de/~raupach
-
-
- If you are the editor of a Linux CD, you should
- enable gscd.c within your boot floppy kernel. Please,
- send me one of your CDs for free.
-
-
-This current driver version 0.4a only supports reading data from the disk.
-Currently we have no audio and no multisession or XA support.
-The polling interface is used, no DMA.
-
-
-Sometimes the GoldStar R420 is sold in a 'Reveal Multimedia Kit'. This kit's
-drive interface is compatible, too.
-
-
-Installation
-------------
-
-Change to '/usr/src/linux/drivers/cdrom' and edit the file 'gscd.h'. Insert
-the i/o address of your interface card.
-
-The default base address is 0x340. This will work for most applications.
-Address selection is accomplished by jumpers PN801-1 to PN801-4 on the
-GoldStar Interface Card.
-Appropriate settings are: 0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360
-0x370, 0x380, 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0
-
-Then go back to '/usr/src/linux/' and 'make config' to build the new
-configuration for your kernel. If you want to use the GoldStar driver
-like a module, don't select 'GoldStar CDROM support'. By the way, you
-have to include the iso9660 filesystem.
-
-Now start compiling the kernel with 'make zImage'.
-If you want to use the driver as a module, you have to do 'make modules'
-and 'make modules_install', additionally.
-Install your new kernel as usual - maybe you do it with 'make zlilo'.
-
-Before you can use the driver, you have to
- mknod /dev/gscd0 b 16 0
-to create the appropriate device file (you only need to do this once).
-
-If you use modules, you can try to insert the driver.
-Say: 'insmod /usr/src/linux/modules/gscd.o'
-or: 'insmod /usr/src/linux/modules/gscd.o gscd=<address>'
-The driver should report its results.
-
-That's it! Mount a disk, i.e. 'mount -rt iso9660 /dev/gscd0 /cdrom'
-
-Feel free to report errors and suggestions to the following address.
-Be sure, I'm very happy to receive your comments!
-
- Oliver Raupach Hannover, Juni 1995
-(raupach@nwfs1.rz.fh-hannover.de)
diff --git a/Documentation/cdrom/isp16 b/Documentation/cdrom/isp16
deleted file mode 100644
index cc86533ac9f3..000000000000
--- a/Documentation/cdrom/isp16
+++ /dev/null
@@ -1,100 +0,0 @@
- -- Documentation/cdrom/isp16
-
-Docs by Eric van der Maarel <H.T.M.v.d.Maarel@marin.nl>
-
-This is the README for version 0.6 of the cdrom interface on an
-ISP16, MAD16 or Mozart sound card.
-
-The detection and configuration of this interface used to be included
-in both the sjcd and optcd cdrom driver. Drives supported by these
-drivers came packed with Media Magic's multi media kit, which also
-included the ISP16 card. The idea (thanks Leo Spiekman)
-to move it from these drivers into a separate module and moreover, not to
-rely on the MAD16 sound driver, are as follows:
--duplication of code in the kernel is a waste of resources and should
- be avoided;
--however, kernels and notably those included with Linux distributions
- (cf Slackware 3.0 included version 0.5 of the isp16 configuration
- code included in the drivers) don't always come with sound support
- included. Especially when they already include a bunch of cdrom drivers.
- Hence, the cdrom interface should be configurable _independently_ of
- sound support.
-
-The ISP16, MAD16 and Mozart sound cards have an OPTi 82C928 or an
-OPTi 82C929 chip. The interface on these cards should work with
-any cdrom attached to the card, which is 'electrically' compatible
-with Sanyo/Panasonic, Sony or Mitsumi non-ide drives. However, the
-command sets for any proprietary drives may differ
-(and hence may not be supported in the kernel) from these four types.
-For a fact I know the interface works and the way of configuration
-as described in this documentation works in combination with the
-sjcd (in Sanyo/Panasonic compatibility mode) cdrom drivers
-(probably with the optcd (in Sony compatibility mode) as well).
-If you have such an OPTi based sound card and you want to use the
-cdrom interface with a cdrom drive supported by any of the other cdrom
-drivers, it will probably work. Please let me know any experience you
-might have).
-I understand that cards based on the OPTi 82C929 chips may be configured
-(hardware jumpers that is) as an IDE interface. Initialisation of such a
-card in this mode is not supported (yet?).
-
-The suggestion to configure the ISP16 etc. sound card by booting DOS and
-do a warm reboot to boot Linux somehow doesn't work, at least not
-on my machine (IPC P90), with the OPTi 82C928 based card.
-
-Booting the kernel through the boot manager LILO allows the use
-of some command line options on the 'LILO boot:' prompt. At boot time
-press Alt or Shift while the LILO prompt is written on the screen and enter
-any kernel options. Alternatively these options may be used in
-the appropriate section in /etc/lilo.conf. Adding 'append="<cmd_line_options>"'
-will do the trick as well.
-The syntax of 'cmd_line_options' is
-
- isp16=[<port>[,<irq>[,<dma>]]][[,]<drive_type>]
-
-If there is no ISP16 or compatibles detected, there's probably no harm done.
-These options indicate the values that your cdrom drive has been (or will be)
-configured to use.
-Valid values for the base i/o address are:
- port=0x340,0x320,0x330,0x360
-for the interrupt request number
- irq=0,3,5,7,9,10,11
-for the direct memory access line
- dma=0,3,5,6,7
-and for the type of drive
- drive_type=noisp16,Sanyo,Panasonic,Sony,Mitsumi.
-Note that these options are case sensitive.
-The values 0 for irq and dma indicate that they are not used, and
-the drive will be used in 'polling' mode. The values 5 and 7 for irq
-should be avoided in order to avoid any conflicts with optional
-sound card configuration.
-The syntax of the command line does not allow the specification of
-irq when there's nothing specified for the base address and no
-specification of dma when there is no specification of irq.
-The value 'noisp16' for drive_type, which may be used as the first
-non-integer option value (e.g. 'isp16=noisp16'), makes sure that probing
-for and subsequent configuration of an ISP16-compatible card is skipped
-all together. This can be useful to overcome possible conflicts which
-may arise while the kernel is probing your hardware.
-The default values are
- port=0x340
- irq=0
- dma=0
- drive_type=Sanyo
-reflecting my own configuration. The defaults can be changed in
-the file linux/drivers/cdrom/ips16.h.
-
-The cdrom interface can be configured at run time by loading the
-initialisation driver as a module. In that case, the interface
-parameters can be set by giving appropriate values on the command
-line. Configuring the driver can then be done by the following
-command (assuming you have iso16.o installed in a proper place):
-
- insmod isp16.o isp16_cdrom_base=<port> isp16_cdrom_irq=<irq> \
- isp16_cdrom_dma=<dma> isp16_cdrom_type=<drive_type>
-
-where port, irq, dma and drive_type can have any of the values mentioned
-above.
-
-
-Have fun!
diff --git a/Documentation/cdrom/mcdx b/Documentation/cdrom/mcdx
deleted file mode 100644
index 2bac4b7ff6da..000000000000
--- a/Documentation/cdrom/mcdx
+++ /dev/null
@@ -1,29 +0,0 @@
-If you are using the driver as a module, you can specify your ports and IRQs
-like
-
- # insmod mcdx.o mcdx=0x300,11,0x304,5
-
-and so on ("address,IRQ" pairs).
-This will override the configuration in mcdx.h.
-
-This driver:
-
- o handles XA and (hopefully) multi session CDs as well as
- ordinary CDs;
- o supports up to 5 drives (of course, you'll need free
- IRQs, i/o ports and slots);
- o plays audio
-
-This version doesn't support yet:
-
- o shared IRQs (but it seems to be possible - I've successfully
- connected two drives to the same irq. So it's `only' a
- problem of the driver.)
-
-This driver never will:
-
- o Read digital audio (i.e. copy directly), due to missing
- hardware features.
-
-
-heiko@lotte.sax.de
diff --git a/Documentation/cdrom/optcd b/Documentation/cdrom/optcd
deleted file mode 100644
index 6f46c7adb243..000000000000
--- a/Documentation/cdrom/optcd
+++ /dev/null
@@ -1,57 +0,0 @@
-This is the README file for the Optics Storage 8000 AT CDROM device driver.
-
-This is the driver for the so-called 'DOLPHIN' drive, with the 34-pin
-Sony-compatible interface. For the IDE-compatible Optics Storage 8001
-drive, you will want the ATAPI CDROM driver. The driver also seems to
-work with the Lasermate CR328A. If you have a drive that works with
-this driver, and that doesn't report itself as DOLPHIN, please drop me
-a mail.
-
-The support for multisession CDs is in ALPHA stage. If you use it,
-please mail me your experiences. Multisession support can be disabled
-at compile time.
-
-You can find some older versions of the driver at
- dutette.et.tudelft.nl:/pub/linux/
-and at Eberhard's mirror
- ftp.gwdg.de:/pub/linux/cdrom/drivers/optics/
-
-Before you can use the driver, you have to create the device file once:
- # mknod /dev/optcd0 b 17 0
-
-To specify the base address if the driver is "compiled-in" to your kernel,
-you can use the kernel command line item (LILO option)
- optcd=0x340
-with the right address.
-
-If you have compiled optcd as a module, you can load it with
- # insmod /usr/src/linux/modules/optcd.o
-or
- # insmod /usr/src/linux/modules/optcd.o optcd=0x340
-with the matching address value of your interface card.
-
-The driver employs a number of buffers to do read-ahead and block size
-conversion. The number of buffers is configurable in optcd.h, and has
-influence on the driver performance. For my machine (a P75), 6 buffers
-seems optimal, as can be seen from this table:
-
-#bufs kb/s %cpu
-1 97 0.1
-2 191 0.3
-3 188 0.2
-4 246 0.3
-5 189 19
-6 280 0.4
-7 281 7.0
-8 246 2.8
-16 281 3.4
-
-If you get a throughput significantly below 300 kb/s, try tweaking
-N_BUFS, and don't forget to mail me your results!
-
-I'd appreciate success/failure reports. If you find a bug, try
-recompiling the driver with some strategically chosen debug options
-(these can be found in optcd.h) and include the messages generated in
-your bug report. Good luck.
-
-Leo Spiekman (spiekman@dutette.et.tudelft.nl)
diff --git a/Documentation/cdrom/sbpcd b/Documentation/cdrom/sbpcd
deleted file mode 100644
index b3ba63f4ce3e..000000000000
--- a/Documentation/cdrom/sbpcd
+++ /dev/null
@@ -1,1061 +0,0 @@
-This README belongs to release 4.2 or newer of the SoundBlaster Pro
-(Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and Teac)
-CD-ROM driver for Linux.
-
-sbpcd really, really is NOT for ANY IDE/ATAPI drive!
-Not even if you have an "original" SoundBlaster card with an IDE interface!
-So, you'd better have a look into README.ide if your port address is 0x1F0,
-0x170, 0x1E8, 0x168 or similar.
-I get tons of mails from IDE/ATAPI drive users - I really can't continue
-any more to answer them all. So, if your drive/interface information sheets
-mention "IDE" (primary, secondary, tertiary, quaternary) and the DOS driver
-invoking line within your CONFIG.SYS is using an address below 0x230:
-DON'T ROB MY LAST NERVE - jumper your interface to address 0x170 and IRQ 15
-(that is the "secondary IDE" configuration), set your drive to "master" and
-use ide-cd as your driver. If you do not have a second IDE hard disk, use the
-LILO commands
- hdb=noprobe hdc=cdrom
-and get lucky.
-To make it fully clear to you: if you mail me about IDE/ATAPI drive problems,
-my answer is above, and I simply will discard your mail, hoping to stop the
-flood and to find time to lead my 12-year old son towards happy computing.
-
-The driver is able to drive the whole family of "traditional" AT-style (that
-is NOT the new "Enhanced IDE" or "ATAPI" drive standard) Matsushita,
-Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The
-well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563.
-CR-574 is an IDE/ATAPI drive.
-
-The Longshine LCS-7260 is a double-speed drive which uses the "old"
-Matsushita command set. It is supported - with help by Serge Robyns.
-Vertos ("Elitegroup Computer Systems", ECS) has a similar drive - support
-has started; get in contact if you have such a "Vertos 100" or "ECS-AT"
-drive.
-
-There exists an "IBM External ISA CD-ROM Drive" which in fact is a CR-563
-with a special controller board. This drive is supported (the interface is
-of the "LaserMate" type), and it is possibly the best buy today (cheaper than
-an internal drive, and you can use it as an internal, too - e.g. plug it into
-a soundcard).
-
-CreativeLabs has a new drive "CD200" and a similar drive "CD200F". The latter
-is made by Funai and sometimes named "E2550UA", newer models may be named
-"MK4015". The CD200F drives should fully work.
-CD200 drives without "F" are still giving problems: drive detection and
-playing audio should work, data access will result in errors. I need qualified
-feedback about the bugs within the data functions or a drive (I never saw a
-CD200).
-
-The quad-speed Teac CD-55A drive is supported, but still does not reach "full
-speed". The data rate already reaches 500 kB/sec if you set SBP_BUFFER_FRAMES
-to 64 (it is not recommended to do that for normal "file access" usage, but it
-can speed up things a lot if you use something like "dd" to read from the
-drive; I use it for verifying self-written CDs this way).
-The drive itself is able to deliver 600 kB/sec, so this needs
-work; with the normal setup, the performance currently is not even as good as
-double-speed.
-
-This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives,
-and again: this driver is in no way usable for any IDE/ATAPI drive. If you
-think your drive should work and it doesn't: send me the DOS driver for your
-beast (gzipped + uuencoded) and your CONFIG.SYS if you want to ask me for help,
-and include an original log message excerpt, and try to give all information
-a complete idiot needs to understand your hassle already with your first
-mail. And if you want to say "as I have mailed you before", be sure that I
-don't remember your "case" by such remarks; at the moment, I have some
-hundreds of open correspondences about Linux CDROM questions (hope to reduce if
-the IDE/ATAPI user questions disappear).
-
-
-This driver will work with the soundcard interfaces (SB Pro, SB 16, Galaxy,
-SoundFX, Mozart, MAD16 ...) and with the "no-sound" cards (Panasonic CI-101P,
-LaserMate, WDH-7001C, Longshine LCS-6853, Teac ...).
-
-It works with the "configurable" interface "Sequoia S-1000", too, which is
-used on the Spea Media FX and Ensonic Soundscape sound cards. You have to
-specify the type "SBPRO 2" and the true CDROM port address with it, not the
-"configuration port" address.
-
-If you have a sound card which needs a "configuration driver" instead of
-jumpers for interface types and addresses (like Mozart cards) - those
-drivers get invoked before the DOS CDROM driver in your CONFIG.SYS, typical
-names are "cdsetup.sys" and "mztinit.sys" - let the sound driver do the
-CDROM port configuration (the leading comments in linux/drivers/sound/mad16.c
-are just for you!). Hannu Savolainen's mad16.c code is able to set up my
-Mozart card - I simply had to add
- #define MAD16_CONF 0x06
- #define MAD16_CDSEL 0x03
-to configure the CDROM interface for type "Panasonic" (LaserMate) and address
-0x340.
-
-The interface type has to get configured in linux/drivers/cdrom/sbpcd.h,
-because the register layout is different between the "SoundBlaster" and the
-"LaserMate" type.
-
-I got a report that the Teac interface card "I/F E117098" is of type
-"SoundBlaster" (i.e. you have to set SBPRO to 1) even with the addresses
-0x300 and above. This is unusual, and it can't get covered by the auto
-probing scheme.
-The Teac 16-bit interface cards (like P/N E950228-00A, default address 0x2C0)
-need the SBPRO 3 setup.
-
-If auto-probing found the drive, the address is correct. The reported type
-may be wrong. A "mount" will give success only if the interface type is set
-right. Playing audio should work with a wrong set interface type, too.
-
-With some Teac and some CD200 drives I have seen interface cards which seem
-to lack the "drive select" lines; always drive 0 gets addressed. To avoid
-"mirror drives" (four drives detected where you only have one) with such
-interface cards, set MAX_DRIVES to 1 and jumper your drive to ID 0 (if
-possible).
-
-
-Up to 4 drives per interface card, and up to 4 interface cards are supported.
-All supported drive families can be mixed, but the CR-521 drives are
-hard-wired to drive ID 0. The drives have to use different drive IDs, and each
-drive has to get a unique minor number (0...3), corresponding indirectly to
-its drive ID.
-The drive IDs may be selected freely from 0 to 3 - they do not have to be in
-consecutive order.
-
-As Don Carroll, don@ds9.us.dell.com or FIDO 1:382/14, told me, it is possible
-to change old drives to any ID, too. He writes in this sense:
- "In order to be able to use more than one single speed drive
- (they do not have the ID jumpers) you must add a DIP switch
- and two resistors. The pads are already on the board next to
- the power connector. You will see the silkscreen for the
- switch if you remove the top cover.
- 1 2 3 4
- ID 0 = x F F x O = "on"
- ID 1 = x O F x F = "off"
- ID 2 = x F O x x = "don't care"
- ID 3 = x O O x
- Next to the switch are the positions for R76 (7k) and R78
- (12k). I had to play around with the resistor values - ID 3
- did not work with other values. If the values are not good,
- ID 3 behaves like ID 0."
-
-To use more than 4 drives, you simply need a second controller card at a
-different address and a second cable.
-
-The driver supports reading of data from the CD and playing of audio tracks.
-The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
-CDplayer and WorkBone - tell me if it is not compatible with other software.
-The only accepted measure for correctness with the audio functions is the
-"cdtester" utility (appended) - most audio player programmers seem to be
-better musicians than programmers. ;-)
-
-With the CR-56x and the CD200 drives, the reading of audio frames is possible.
-This is implemented by an IOCTL function which reads READ_AUDIO frames of
-2352 bytes at once (configurable with the "READ_AUDIO" define, default is 0).
-Reading the same frame a second time gives different data; the frame data
-start at a different position, but all read bytes are valid, and we always
-read 98 consecutive chunks (of 24 Bytes) as a frame. Reading more than 1 frame
-at once possibly misses some chunks at each frame boundary. This lack has to
-get corrected by external, "higher level" software which reads the same frame
-again and tries to find and eliminate overlapping chunks (24-byte-pieces).
-
-The transfer rate with reading audio (1-frame-pieces) currently is very slow.
-This can be better reading bigger chunks, but the "missing" chunks possibly
-occur at the beginning of each single frame.
-The software interface possibly may change a bit the day the SCSI driver
-supports it too.
-
-With all but the CR-52x drives, MultiSession is supported.
-Photo CDs work (the "old" drives like CR-521 can access only the first
-session of a photoCD).
-At ftp.gwdg.de:/pub/linux/hpcdtoppm/ you will find Hadmut Danisch's package to
-convert photo CD image files and Gerd Knorr's viewing utility.
-
-The transfer rate will reach 150 kB/sec with CR-52x drives, 300 kB/sec with
-CR-56x drives, and currently not more than 500 kB/sec (usually less than
-250 kB/sec) with the Teac quad speed drives.
-XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
-
-This release consists of
-- this README file
-- the driver file linux/drivers/cdrom/sbpcd.c
-- the stub files linux/drivers/cdrom/sbpcd[234].c
-- the header file linux/drivers/cdrom/sbpcd.h.
-
-
-To install:
------------
-
-1. Setup your hardware parameters. Though the driver does "auto-probing" at a
- lot of (not all possible!) addresses, this step is recommended for
- everyday use. You should let sbpcd auto-probe once and use the reported
- address if a drive got found. The reported type may be incorrect; it is
- correct if you can mount a data CD. There is no choice for you with the
- type; only one is right, the others are deadly wrong.
-
- a. Go into /usr/src/linux/drivers/cdrom/sbpcd.h and configure it for your
- hardware (near the beginning):
- a1. Set it up for the appropriate type of interface board.
- "Original" CreativeLabs sound cards need "SBPRO 1".
- Most "compatible" sound cards (almost all "non-CreativeLabs" cards)
- need "SBPRO 0".
- The "no-sound" board from OmniCd needs the "SBPRO 1" setup.
- The Teac 8-bit "no-sound" boards need the "SBPRO 1" setup.
- The Teac 16-bit "no-sound" boards need the "SBPRO 3" setup.
- All other "no-sound" boards need the "SBPRO 0" setup.
- The Spea Media FX and Ensoniq SoundScape cards need "SBPRO 2".
- sbpcd.c holds some examples in its auto-probe list.
- If you configure "SBPRO" wrong, the playing of audio CDs will work,
- but you will not be able to mount a data CD.
- a2. Tell the address of your CDROM_PORT (not of the sound port).
- a3. If 4 drives get found, but you have only one, set MAX_DRIVES to 1.
- a4. Set DISTRIBUTION to 0.
- b. Additionally for 2.a1 and 2.a2, the setup may be done during
- boot time (via the "kernel command line" or "LILO option"):
- sbpcd=0x320,LaserMate
- or
- sbpcd=0x230,SoundBlaster
- or
- sbpcd=0x338,SoundScape
- or
- sbpcd=0x2C0,Teac16bit
- This is especially useful if you install a fresh distribution.
- If the second parameter is a number, it gets taken as the type
- setting; 0 is "LaserMate", 1 is "SoundBlaster", 2 is "SoundScape",
- 3 is "Teac16bit".
- So, for example
- sbpcd=0x230,1
- is equivalent to
- sbpcd=0x230,SoundBlaster
-
-2. "cd /usr/src/linux" and do a "make config" and select "y" for Matsushita
- CD-ROM support and for ISO9660 FileSystem support. If you do not have a
- second, third, or fourth controller installed, do not say "y" to the
- secondary Matsushita CD-ROM questions.
-
-3. Then make the kernel image ("make zlilo" or similar).
-
-4. Make the device file(s). This step usually already has been done by the
- MAKEDEV script.
- The driver uses MAJOR 25, so, if necessary, do
- mknod /dev/sbpcd b 25 0 (if you have only one drive)
- and/or
- mknod /dev/sbpcd0 b 25 0
- mknod /dev/sbpcd1 b 25 1
- mknod /dev/sbpcd2 b 25 2
- mknod /dev/sbpcd3 b 25 3
- to make the node(s).
-
- The "first found" drive gets MINOR 0 (regardless of its jumpered ID), the
- "next found" (at the same cable) gets MINOR 1, ...
-
- For a second interface board, you have to make nodes like
- mknod /dev/sbpcd4 b 26 0
- mknod /dev/sbpcd5 b 26 1
- and so on. Use the MAJORs 26, 27, 28.
-
- If you further make a link like
- ln -s sbpcd /dev/cdrom
- you can use the name /dev/cdrom, too.
-
-5. Reboot with the new kernel.
-
-You should now be able to do
- mkdir /CD
-and
- mount -rt iso9660 /dev/sbpcd /CD
-or
- mount -rt iso9660 -o block=2048 /dev/sbpcd /CD
-and see the contents of your CD in the /CD directory.
-To use audio CDs, a mounting is not recommended (and it would fail if the
-first track is not a data track).
-
-
-Using sbpcd as a "loadable module":
------------------------------------
-
-If you do NOT select "Matsushita/Panasonic CDROM driver support" during the
-"make config" of your kernel, you can build the "loadable module" sbpcd.o.
-
-If sbpcd gets used as a module, the support of more than one interface
-card (i.e. drives 4...15) is disabled.
-
-You can specify interface address and type with the "insmod" command like:
- # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x340,0
-or
- # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x230,1
-or
- # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x338,2
-where the last number represents the SBPRO setting (no strings allowed here).
-
-
-Things of interest:
--------------------
-
-The driver is configured to try the LaserMate type of interface at I/O port
-0x0340 first. If this is not appropriate, sbpcd.h should get changed
-(you will find the right place - just at the beginning).
-
-No DMA and no IRQ is used.
-
-To reduce or increase the amount of kernel messages, edit sbpcd.c and play
-with the "DBG_xxx" switches (initialization of the variable "sbpcd_debug").
-Don't forget to reflect on what you do; enabling all DBG_xxx switches at once
-may crash your system, and each message line is accompanied by a delay.
-
-The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
-specify "block=2048" as a mount option. Doing this will disable the direct
-execution of a binary from the CD; you have to copy it to a device with the
-standard BLOCK_SIZE (1024) first. So, do not use this if your system is
-directly "running from the CDROM" (like some of Yggdrasil's installation
-variants). There are CDs on the market (like the German "unifix" Linux
-distribution) which MUST get handled with a block_size of 1024. Generally,
-one can say all the CDs which hold files of the name YMTRANS.TBL are defective;
-do not use block=2048 with those.
-
-Within sbpcd.h, you will find some "#define"s (e.g. EJECT and JUKEBOX). With
-these, you can configure the driver for some special things.
-You can use the appended program "cdtester" to set the auto-eject feature
-during runtime. Jeff Tranter's "eject" utility can do this, too (and more)
-for you.
-
-There is an ioctl CDROMMULTISESSION to obtain with a user program if
-the CD is an XA disk and - if it is - where the last session starts. The
-"cdtester" program illustrates how to call it.
-
-
-Auto-probing at boot time:
---------------------------
-
-The driver does auto-probing at many well-known interface card addresses,
-but not all:
-Some probings can cause a hang if an NE2000 ethernet card gets touched, because
-SBPCD's auto-probing happens before the initialization of the net drivers.
-Those "hazardous" addresses are excluded from auto-probing; the "kernel
-command line" feature has to be used during installation if you have your
-drive at those addresses. The "module" version is allowed to probe at those
-addresses, too.
-
-The auto-probing looks first at the configured address resp. the address
-submitted by the kernel command line. With this, it is possible to use this
-driver within installation boot floppies, and for any non-standard address,
-too.
-
-Auto-probing will make an assumption about the interface type ("SBPRO" or not),
-based upon the address. That assumption may be wrong (initialization will be
-o.k., but you will get I/O errors during mount). In that case, use the "kernel
-command line" feature and specify address & type at boot time to find out the
-right setup.
-
-For everyday use, address and type should get configured within sbpcd.h. That
-will stop the auto-probing due to success with the first try.
-
-The kernel command "sbpcd=0" suppresses each auto-probing and causes
-the driver not to find any drive; it is meant for people who love sbpcd
-so much that they do not want to miss it, even if they miss the drives. ;-)
-
-If you configure "#define CDROM_PORT 0" in sbpcd.h, the auto-probing is
-initially disabled and needs an explicit kernel command to get activated.
-Once activated, it does not stop before success or end-of-list. This may be
-useful within "universal" CDROM installation boot floppies (but using the
-loadable module would be better because it allows an "extended" auto-probing
-without fearing NE2000 cards).
-
-To shorten the auto-probing list to a single entry, set DISTRIBUTION 0 within
-sbpcd.h.
-
-
-Setting up address and interface type:
---------------------------------------
-
-If your I/O port address is not 0x340, you have to look for the #defines near
-the beginning of sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and
-change CDROM_PORT to the address of your CDROM I/O port.
-
-Almost all of the "SoundBlaster compatible" cards behave like the no-sound
-interfaces, i.e. need SBPRO 0!
-
-With "original" SB Pro cards, an initial setting of CD_volume through the
-sound card's MIXER register gets done.
-If you are using a "compatible" sound card of types "LaserMate" or "SPEA",
-you can set SOUND_BASE (in sbpcd.h) to get it done with your card, too...
-
-
-Using audio CDs:
-----------------
-
-Workman, WorkBone, xcdplayer, cdplayer and the nice little tool "cdplay" (see
-README.aztcd from the Aztech driver package) should work.
-
-The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants
-"/dev/rsr0", workman loves "/dev/sr0" or "/dev/cdrom" - so, make the
-appropriate links to use them without the need to supply parameters.
-
-
-Copying audio tracks:
----------------------
-
-The following program will copy track 1 (or a piece of it) from an audio CD
-into the file "track01":
-
-/*=================== begin program ========================================*/
-/*
- * read an audio track from a CD
- *
- * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
- * may be used & enhanced freely
- *
- * Due to non-existent sync bytes at the beginning of each audio frame (or due
- * to a firmware bug within all known drives?), it is currently a kind of
- * fortune if two consecutive frames fit together.
- * Usually, they overlap, or a little piece is missing. This happens in units
- * of 24-byte chunks. It has to get fixed by higher-level software (reading
- * until an overlap occurs, and then eliminate the overlapping chunks).
- * ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.*.tar.gz holds an example of
- * such an algorithm.
- * This example program further is missing to obtain the SubChannel data
- * which belong to each frame.
- *
- * This is only an example of the low-level access routine. The read data are
- * pure 16-bit CDDA values; they have to get converted to make sound out of
- * them.
- * It is no fun to listen to it without prior overlap/underlap correction!
- */
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <linux/cdrom.h>
-
-static struct cdrom_tochdr hdr;
-static struct cdrom_tocentry entry[101];
-static struct cdrom_read_audio arg;
-static u_char buffer[CD_FRAMESIZE_RAW];
-static int datafile, drive;
-static int i, j, limit, track, err;
-static char filename[32];
-
-int main(int argc, char *argv[])
-{
-/*
- * open /dev/cdrom
- */
- drive=open("/dev/cdrom", 0);
- if (drive<0)
- {
- fprintf(stderr, "can't open drive.\n");
- exit (-1);
- }
-/*
- * get TocHeader
- */
- fprintf(stdout, "getting TocHeader...\n");
- err=ioctl(drive, CDROMREADTOCHDR, &hdr);
- if (err!=0)
- {
- fprintf(stderr, "can't get TocHeader (error %d).\n", err);
- exit (-1);
- }
- else
- fprintf(stdout, "TocHeader: %d %d\n", hdr.cdth_trk0, hdr.cdth_trk1);
-/*
- * get and display all TocEntries
- */
- fprintf(stdout, "getting TocEntries...\n");
- for (i=1;i<=hdr.cdth_trk1+1;i++)
- {
- if (i!=hdr.cdth_trk1+1) entry[i].cdte_track = i;
- else entry[i].cdte_track = CDROM_LEADOUT;
- entry[i].cdte_format = CDROM_LBA;
- err=ioctl(drive, CDROMREADTOCENTRY, &entry[i]);
- if (err!=0)
- {
- fprintf(stderr, "can't get TocEntry #%d (error %d).\n", i, err);
- exit (-1);
- }
- else
- {
- fprintf(stdout, "TocEntry #%d: %1X %1X %06X %02X\n",
- entry[i].cdte_track,
- entry[i].cdte_adr,
- entry[i].cdte_ctrl,
- entry[i].cdte_addr.lba,
- entry[i].cdte_datamode);
- }
- }
- fprintf(stdout, "got all TocEntries.\n");
-/*
- * ask for track number (not implemented here)
- */
-track=1;
-#if 0 /* just read a little piece (4 seconds) */
-entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300;
-#endif
-/*
- * read track into file
- */
- sprintf(filename, "track%02d\0", track);
- datafile=creat(filename, 0755);
- if (datafile<0)
- {
- fprintf(stderr, "can't open datafile %s.\n", filename);
- exit (-1);
- }
- arg.addr.lba=entry[track].cdte_addr.lba;
- arg.addr_format=CDROM_LBA; /* CDROM_MSF would be possible here, too. */
- arg.nframes=1;
- arg.buf=&buffer[0];
- limit=entry[track+1].cdte_addr.lba;
- for (;arg.addr.lba<limit;arg.addr.lba++)
- {
- err=ioctl(drive, CDROMREADAUDIO, &arg);
- if (err!=0)
- {
- fprintf(stderr, "can't read abs. frame #%d (error %d).\n",
- arg.addr.lba, err);
- }
- j=write(datafile, &buffer[0], CD_FRAMESIZE_RAW);
- if (j!=CD_FRAMESIZE_RAW)
- {
- fprintf(stderr,"I/O error (datafile) at rel. frame %d\n",
- arg.addr.lba-entry[track].cdte_addr.lba);
- }
- arg.addr.lba++;
- }
- return 0;
-}
-/*===================== end program ========================================*/
-
-At ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.*.tar.gz is an adapted version of
-Heiko Eissfeldt's digital-audio to .WAV converter (the original is there, too).
-This is preliminary, as Heiko himself will care about it.
-
-
-Known problems:
----------------
-
-Currently, the detection of disk change or removal is actively disabled.
-
-Most attempts to read the UPC/EAN code result in a stream of zeroes. All my
-drives are mostly telling there is no UPC/EAN code on disk or there is, but it
-is an all-zero number. I guess now almost no CD holds such a number.
-
-Bug reports, comments, wishes, donations (technical information is a donation,
-too :-) etc. to emoenke@gwdg.de.
-
-SnailMail address, preferable for CD editors if they want to submit a free
-"cooperation" copy:
- Eberhard Moenkeberg
- Reinholdstr. 14
- D-37083 Goettingen
- Germany
----
-
-
-Appendix -- the "cdtester" utility:
-
-/*
- * cdtester.c -- test the audio functions of a CD driver
- *
- * (c) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>
- * published under the GPL
- *
- * made under heavy use of the "Tiny Audio CD Player"
- * from Werner Zimmermann <zimmerma@rz.fht-esslingen.de>
- * (see linux/drivers/block/README.aztcd)
- */
-#undef AZT_PRIVATE_IOCTLS /* not supported by every CDROM driver */
-#define SBP_PRIVATE_IOCTLS /* not supported by every CDROM driver */
-
-#include <stdio.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <linux/cdrom.h>
-
-#ifdef AZT_PRIVATE_IOCTLS
-#include <linux/../../drivers/cdrom/aztcd.h>
-#endif /* AZT_PRIVATE_IOCTLS */
-#ifdef SBP_PRIVATE_IOCTLS
-#include <linux/../../drivers/cdrom/sbpcd.h>
-#include <linux/fs.h>
-#endif /* SBP_PRIVATE_IOCTLS */
-
-struct cdrom_tochdr hdr;
-struct cdrom_tochdr tocHdr;
-struct cdrom_tocentry TocEntry[101];
-struct cdrom_tocentry entry;
-struct cdrom_multisession ms_info;
-struct cdrom_read_audio read_audio;
-struct cdrom_ti ti;
-struct cdrom_subchnl subchnl;
-struct cdrom_msf msf;
-struct cdrom_volctrl volctrl;
-#ifdef AZT_PRIVATE_IOCTLS
-union
-{
- struct cdrom_msf msf;
- unsigned char buf[CD_FRAMESIZE_RAW];
-} azt;
-#endif /* AZT_PRIVATE_IOCTLS */
-int i, i1, i2, i3, j, k;
-unsigned char sequence=0;
-unsigned char command[80];
-unsigned char first=1, last=1;
-char *default_device="/dev/cdrom";
-char dev[20];
-char filename[20];
-int drive;
-int datafile;
-int rc;
-
-void help(void)
-{
- printf("Available Commands:\n");
- printf("STOP s EJECT e QUIT q\n");
- printf("PLAY TRACK t PAUSE p RESUME r\n");
- printf("NEXT TRACK n REPEAT LAST l HELP h\n");
- printf("SUBCHANNEL_Q c TRACK INFO i PLAY AT a\n");
- printf("READ d READ RAW w READ AUDIO A\n");
- printf("MS-INFO M TOC T START S\n");
- printf("SET EJECTSW X DEVICE D DEBUG Y\n");
- printf("AUDIO_BUFSIZ Z RESET R SET VOLUME v\n");
- printf("GET VOLUME V\n");
-}
-
-/*
- * convert MSF number (3 bytes only) to Logical_Block_Address
- */
-int msf2lba(u_char *msf)
-{
- int i;
-
- i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_BLOCK_OFFSET;
- if (i<0) return (0);
- return (i);
-}
-/*
- * convert logical_block_address to m-s-f_number (3 bytes only)
- */
-void lba2msf(int lba, unsigned char *msf)
-{
- lba += CD_BLOCK_OFFSET;
- msf[0] = lba / (CD_SECS*CD_FRAMES);
- lba %= CD_SECS*CD_FRAMES;
- msf[1] = lba / CD_FRAMES;
- msf[2] = lba % CD_FRAMES;
-}
-
-int init_drive(char *dev)
-{
- unsigned char msf_ent[3];
-
- /*
- * open the device
- */
- drive=open(dev,0);
- if (drive<0) return (-1);
- /*
- * get TocHeader
- */
- printf("getting TocHeader...\n");
- rc=ioctl(drive,CDROMREADTOCHDR,&hdr);
- if (rc!=0)
- {
- printf("can't get TocHeader (error %d).\n",rc);
- return (-2);
- }
- else
- first=hdr.cdth_trk0;
- last=hdr.cdth_trk1;
- printf("TocHeader: %d %d\n",hdr.cdth_trk0,hdr.cdth_trk1);
- /*
- * get and display all TocEntries
- */
- printf("getting TocEntries...\n");
- for (i=1;i<=hdr.cdth_trk1+1;i++)
- {
- if (i!=hdr.cdth_trk1+1) TocEntry[i].cdte_track = i;
- else TocEntry[i].cdte_track = CDROM_LEADOUT;
- TocEntry[i].cdte_format = CDROM_LBA;
- rc=ioctl(drive,CDROMREADTOCENTRY,&TocEntry[i]);
- if (rc!=0)
- {
- printf("can't get TocEntry #%d (error %d).\n",i,rc);
- }
- else
- {
- lba2msf(TocEntry[i].cdte_addr.lba,&msf_ent[0]);
- if (TocEntry[i].cdte_track==CDROM_LEADOUT)
- {
- printf("TocEntry #%02X: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n",
- TocEntry[i].cdte_track,
- TocEntry[i].cdte_adr,
- TocEntry[i].cdte_ctrl,
- msf_ent[0],
- msf_ent[1],
- msf_ent[2],
- TocEntry[i].cdte_addr.lba,
- TocEntry[i].cdte_datamode);
- }
- else
- {
- printf("TocEntry #%02d: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n",
- TocEntry[i].cdte_track,
- TocEntry[i].cdte_adr,
- TocEntry[i].cdte_ctrl,
- msf_ent[0],
- msf_ent[1],
- msf_ent[2],
- TocEntry[i].cdte_addr.lba,
- TocEntry[i].cdte_datamode);
- }
- }
- }
- return (hdr.cdth_trk1); /* number of tracks */
-}
-
-void display(int size,unsigned char *buffer)
-{
- k=0;
- getchar();
- for (i=0;i<(size+1)/16;i++)
- {
- printf("%4d:",i*16);
- for (j=0;j<16;j++)
- {
- printf(" %02X",buffer[i*16+j]);
- }
- printf(" ");
- for (j=0;j<16;j++)
- {
- if (isalnum(buffer[i*16+j]))
- printf("%c",buffer[i*16+j]);
- else
- printf(".");
- }
- printf("\n");
- k++;
- if (k>=20)
- {
- printf("press ENTER to continue\n");
- getchar();
- k=0;
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- printf("\nTesting tool for a CDROM driver's audio functions V0.1\n");
- printf("(C) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>\n");
- printf("initializing...\n");
-
- rc=init_drive(default_device);
- if (rc<0) printf("could not open %s (rc=%d).\n",default_device,rc);
- help();
- while (1)
- {
- printf("Give a one-letter command (h = help): ");
- scanf("%s",command);
- command[1]=0;
- switch (command[0])
- {
- case 'D':
- printf("device name (f.e. /dev/sbpcd3): ? ");
- scanf("%s",&dev);
- close(drive);
- rc=init_drive(dev);
- if (rc<0) printf("could not open %s (rc %d).\n",dev,rc);
- break;
- case 'e':
- rc=ioctl(drive,CDROMEJECT);
- if (rc<0) printf("CDROMEJECT: rc=%d.\n",rc);
- break;
- case 'p':
- rc=ioctl(drive,CDROMPAUSE);
- if (rc<0) printf("CDROMPAUSE: rc=%d.\n",rc);
- break;
- case 'r':
- rc=ioctl(drive,CDROMRESUME);
- if (rc<0) printf("CDROMRESUME: rc=%d.\n",rc);
- break;
- case 's':
- rc=ioctl(drive,CDROMSTOP);
- if (rc<0) printf("CDROMSTOP: rc=%d.\n",rc);
- break;
- case 'S':
- rc=ioctl(drive,CDROMSTART);
- if (rc<0) printf("CDROMSTART: rc=%d.\n",rc);
- break;
- case 't':
- rc=ioctl(drive,CDROMREADTOCHDR,&tocHdr);
- if (rc<0)
- {
- printf("CDROMREADTOCHDR: rc=%d.\n",rc);
- break;
- }
- first=tocHdr.cdth_trk0;
- last= tocHdr.cdth_trk1;
- if ((first==0)||(first>last))
- {
- printf ("--got invalid TOC data.\n");
- }
- else
- {
- printf("--enter track number(first=%d, last=%d): ",first,last);
- scanf("%d",&i1);
- ti.cdti_trk0=i1;
- if (ti.cdti_trk0<first) ti.cdti_trk0=first;
- if (ti.cdti_trk0>last) ti.cdti_trk0=last;
- ti.cdti_ind0=0;
- ti.cdti_trk1=last;
- ti.cdti_ind1=0;
- rc=ioctl(drive,CDROMSTOP);
- rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
- if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
- }
- break;
- case 'n':
- rc=ioctl(drive,CDROMSTOP);
- if (++ti.cdti_trk0>last) ti.cdti_trk0=last;
- ti.cdti_ind0=0;
- ti.cdti_trk1=last;
- ti.cdti_ind1=0;
- rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
- if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
- break;
- case 'l':
- rc=ioctl(drive,CDROMSTOP);
- if (--ti.cdti_trk0<first) ti.cdti_trk0=first;
- ti.cdti_ind0=0;
- ti.cdti_trk1=last;
- ti.cdti_ind1=0;
- rc=ioctl(drive,CDROMPLAYTRKIND,&ti);
- if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc);
- break;
- case 'c':
- subchnl.cdsc_format=CDROM_MSF;
- rc=ioctl(drive,CDROMSUBCHNL,&subchnl);
- if (rc<0) printf("CDROMSUBCHNL: rc=%d.\n",rc);
- else
- {
- printf("AudioStatus:%s Track:%d Mode:%d MSF=%02d:%02d:%02d\n",
- subchnl.cdsc_audiostatus==CDROM_AUDIO_PLAY ? "PLAYING":"NOT PLAYING",
- subchnl.cdsc_trk,subchnl.cdsc_adr,
- subchnl.cdsc_absaddr.msf.minute,
- subchnl.cdsc_absaddr.msf.second,
- subchnl.cdsc_absaddr.msf.frame);
- }
- break;
- case 'i':
- printf("Track No.: ");
- scanf("%d",&i1);
- entry.cdte_track=i1;
- if (entry.cdte_track<first) entry.cdte_track=first;
- if (entry.cdte_track>last) entry.cdte_track=last;
- entry.cdte_format=CDROM_MSF;
- rc=ioctl(drive,CDROMREADTOCENTRY,&entry);
- if (rc<0) printf("CDROMREADTOCENTRY: rc=%d.\n",rc);
- else
- {
- printf("Mode %d Track, starts at %02d:%02d:%02d\n",
- entry.cdte_adr,
- entry.cdte_addr.msf.minute,
- entry.cdte_addr.msf.second,
- entry.cdte_addr.msf.frame);
- }
- break;
- case 'a':
- printf("Address (min:sec:frm) ");
- scanf("%d:%d:%d",&i1,&i2,&i3);
- msf.cdmsf_min0=i1;
- msf.cdmsf_sec0=i2;
- msf.cdmsf_frame0=i3;
- if (msf.cdmsf_sec0>59) msf.cdmsf_sec0=59;
- if (msf.cdmsf_frame0>74) msf.cdmsf_frame0=74;
- lba2msf(TocEntry[last+1].cdte_addr.lba-1,&msf.cdmsf_min1);
- rc=ioctl(drive,CDROMSTOP);
- rc=ioctl(drive,CDROMPLAYMSF,&msf);
- if (rc<0) printf("CDROMPLAYMSF: rc=%d.\n",rc);
- break;
- case 'V':
- rc=ioctl(drive,CDROMVOLREAD,&volctrl);
- if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc);
- printf("Volume: channel 0 (left) %d, channel 1 (right) %d\n",volctrl.channel0,volctrl.channel1);
- break;
- case 'R':
- rc=ioctl(drive,CDROMRESET);
- if (rc<0) printf("CDROMRESET: rc=%d.\n",rc);
- break;
-#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/
- case 'd':
- printf("Address (min:sec:frm) ");
- scanf("%d:%d:%d",&i1,&i2,&i3);
- azt.msf.cdmsf_min0=i1;
- azt.msf.cdmsf_sec0=i2;
- azt.msf.cdmsf_frame0=i3;
- if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59;
- if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74;
- rc=ioctl(drive,CDROMREADMODE1,&azt.msf);
- if (rc<0) printf("CDROMREADMODE1: rc=%d.\n",rc);
- else display(CD_FRAMESIZE,azt.buf);
- break;
- case 'w':
- printf("Address (min:sec:frame) ");
- scanf("%d:%d:%d",&i1,&i2,&i3);
- azt.msf.cdmsf_min0=i1;
- azt.msf.cdmsf_sec0=i2;
- azt.msf.cdmsf_frame0=i3;
- if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59;
- if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74;
- rc=ioctl(drive,CDROMREADMODE2,&azt.msf);
- if (rc<0) printf("CDROMREADMODE2: rc=%d.\n",rc);
- else display(CD_FRAMESIZE_RAW,azt.buf); /* currently only 2336 */
- break;
-#endif
- case 'v':
- printf("--Channel 0 (Left) (0-255): ");
- scanf("%d",&i1);
- volctrl.channel0=i1;
- printf("--Channel 1 (Right) (0-255): ");
- scanf("%d",&i1);
- volctrl.channel1=i1;
- volctrl.channel2=0;
- volctrl.channel3=0;
- rc=ioctl(drive,CDROMVOLCTRL,&volctrl);
- if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc);
- break;
- case 'q':
- close(drive);
- exit(0);
- case 'h':
- help();
- break;
- case 'T': /* display TOC entry - without involving the driver */
- scanf("%d",&i);
- if ((i<hdr.cdth_trk0)||(i>hdr.cdth_trk1))
- printf("invalid track number.\n");
- else
- printf("TocEntry %02d: adr=%01X ctrl=%01X msf=%02d:%02d:%02d mode=%02X\n",
- TocEntry[i].cdte_track,
- TocEntry[i].cdte_adr,
- TocEntry[i].cdte_ctrl,
- TocEntry[i].cdte_addr.msf.minute,
- TocEntry[i].cdte_addr.msf.second,
- TocEntry[i].cdte_addr.msf.frame,
- TocEntry[i].cdte_datamode);
- break;
- case 'A': /* read audio data into file */
- printf("Address (min:sec:frm) ? ");
- scanf("%d:%d:%d",&i1,&i2,&i3);
- read_audio.addr.msf.minute=i1;
- read_audio.addr.msf.second=i2;
- read_audio.addr.msf.frame=i3;
- read_audio.addr_format=CDROM_MSF;
- printf("# of frames ? ");
- scanf("%d",&i1);
- read_audio.nframes=i1;
- k=read_audio.nframes*CD_FRAMESIZE_RAW;
- read_audio.buf=malloc(k);
- if (read_audio.buf==NULL)
- {
- printf("can't malloc %d bytes.\n",k);
- break;
- }
- sprintf(filename,"audio_%02d%02d%02d_%02d.%02d\0",
- read_audio.addr.msf.minute,
- read_audio.addr.msf.second,
- read_audio.addr.msf.frame,
- read_audio.nframes,
- ++sequence);
- datafile=creat(filename, 0755);
- if (datafile<0)
- {
- printf("can't open datafile %s.\n",filename);
- break;
- }
- rc=ioctl(drive,CDROMREADAUDIO,&read_audio);
- if (rc!=0)
- {
- printf("CDROMREADAUDIO: rc=%d.\n",rc);
- }
- else
- {
- rc=write(datafile,&read_audio.buf,k);
- if (rc!=k) printf("datafile I/O error (%d).\n",rc);
- }
- close(datafile);
- break;
- case 'X': /* set EJECT_SW (0: disable, 1: enable auto-ejecting) */
- scanf("%d",&i);
- rc=ioctl(drive,CDROMEJECT_SW,i);
- if (rc!=0)
- printf("CDROMEJECT_SW: rc=%d.\n",rc);
- else
- printf("EJECT_SW set to %d\n",i);
- break;
- case 'M': /* get the multisession redirection info */
- ms_info.addr_format=CDROM_LBA;
- rc=ioctl(drive,CDROMMULTISESSION,&ms_info);
- if (rc!=0)
- {
- printf("CDROMMULTISESSION(lba): rc=%d.\n",rc);
- }
- else
- {
- if (ms_info.xa_flag) printf("MultiSession offset (lba): %d (0x%06X)\n",ms_info.addr.lba,ms_info.addr.lba);
- else
- {
- printf("this CD is not an XA disk.\n");
- break;
- }
- }
- ms_info.addr_format=CDROM_MSF;
- rc=ioctl(drive,CDROMMULTISESSION,&ms_info);
- if (rc!=0)
- {
- printf("CDROMMULTISESSION(msf): rc=%d.\n",rc);
- }
- else
- {
- if (ms_info.xa_flag)
- printf("MultiSession offset (msf): %02d:%02d:%02d (0x%02X%02X%02X)\n",
- ms_info.addr.msf.minute,
- ms_info.addr.msf.second,
- ms_info.addr.msf.frame,
- ms_info.addr.msf.minute,
- ms_info.addr.msf.second,
- ms_info.addr.msf.frame);
- else printf("this CD is not an XA disk.\n");
- }
- break;
-#ifdef SBP_PRIVATE_IOCTLS
- case 'Y': /* set the driver's message level */
-#if 0 /* not implemented yet */
- printf("enter switch name (f.e. DBG_CMD): ");
- scanf("%s",&dbg_switch);
- j=get_dbg_num(dbg_switch);
-#else
- printf("enter DDIOCSDBG switch number: ");
- scanf("%d",&j);
-#endif
- printf("enter 0 for \"off\", 1 for \"on\": ");
- scanf("%d",&i);
- if (i==0) j|=0x80;
- printf("calling \"ioctl(drive,DDIOCSDBG,%d)\"\n",j);
- rc=ioctl(drive,DDIOCSDBG,j);
- printf("DDIOCSDBG: rc=%d.\n",rc);
- break;
- case 'Z': /* set the audio buffer size */
- printf("# frames wanted: ? ");
- scanf("%d",&j);
- rc=ioctl(drive,CDROMAUDIOBUFSIZ,j);
- printf("%d frames granted.\n",rc);
- break;
-#endif /* SBP_PRIVATE_IOCTLS */
- default:
- printf("unknown command: \"%s\".\n",command);
- break;
- }
- }
- return 0;
-}
-/*==========================================================================*/
-
diff --git a/Documentation/cdrom/sjcd b/Documentation/cdrom/sjcd
deleted file mode 100644
index 74a14847b93a..000000000000
--- a/Documentation/cdrom/sjcd
+++ /dev/null
@@ -1,60 +0,0 @@
- -- Documentation/cdrom/sjcd
- 80% of the work takes 20% of the time,
- 20% of the work takes 80% of the time...
- (Murphy's law)
-
- Once started, training can not be stopped...
- (Star Wars)
-
-This is the README for the sjcd cdrom driver, version 1.6.
-
-This file is meant as a tips & tricks edge for the usage of the SANYO CDR-H94A
-cdrom drive. It will grow as the questions arise. ;-)
-For info on configuring the ISP16 sound card look at Documentation/cdrom/isp16.
-
-The driver should work with any of the Panasonic, Sony or Mitsumi style
-CDROM interfaces.
-The cdrom interface on Media Magic's soft configurable sound card ISP16,
-which used to be included in the driver, is now supported in a separate module.
-This initialisation module will probably also work with other interfaces
-based on an OPTi 82C928 or 82C929 chip (like MAD16 and Mozart): see the
-documentation Documentation/cdrom/isp16.
-
-The device major for sjcd is 18, and minor is 0. Create a block special
-file in your /dev directory (e.g., /dev/sjcd) with these numbers.
-(For those who don't know, being root and doing the following should do
-the trick:
- mknod -m 644 /dev/sjcd b 18 0
-and mount the cdrom by /dev/sjcd).
-
-The default configuration parameters are:
- base address 0x340
- no irq
- no dma
-(Actually the CDR-H94A doesn't know how to use irq and dma.)
-As of version 1.2, setting base address at boot time is supported
-through the use of command line options: type at the "boot:" prompt:
- linux sjcd=<base_address>
-(where you would use the kernel labeled "linux" in lilo's configuration
-file /etc/lilo.conf). You could also use 'append="sjcd=<configuration_info>"'
-in the appropriate section of /etc/lilo.conf
-If you're building a kernel yourself you can set your default base
-i/o address with SJCD_BASE_ADDR in /usr/src/linux/drivers/cdrom/sjcd.h.
-
-The sjcd driver supports being loaded as a module. The following
-command will set the base i/o address on the fly (assuming you
-have installed the module in an appropriate place).
- insmod sjcd.o sjcd_base=<base_address>
-
-
-Have fun!
-
-If something is wrong, please email to vadim@rbrf.ru
- or vadim@ipsun.ras.ru
- or model@cecmow.enet.dec.com
- or H.T.M.v.d.Maarel@marin.nl
-
-It happens sometimes that Vadim is not reachable by mail. For these
-instances, Eric van der Maarel will help too.
-
- Vadim V. Model, Eric van der Maarel, Eberhard Moenkeberg
diff --git a/Documentation/cdrom/sonycd535 b/Documentation/cdrom/sonycd535
deleted file mode 100644
index b81e109970aa..000000000000
--- a/Documentation/cdrom/sonycd535
+++ /dev/null
@@ -1,122 +0,0 @@
- README FOR LINUX SONY CDU-535/531 DRIVER
- ========================================
-
-This is the Sony CDU-535 (and 531) driver version 0.7 for Linux.
-I do not think I have the documentation to add features like DMA support
-so if anyone else wants to pursue it or help me with it, please do.
-(I need to see what was done for the CDU-31A driver -- perhaps I can
-steal some of that code.)
-
-This is a Linux device driver for the Sony CDU-535 CDROM drive. This is
-one of the older Sony drives with its own interface card (Sony bus).
-The DOS driver for this drive is named SONY_CDU.SYS - when you boot DOS
-your drive should be identified as a SONY CDU-535. The driver works
-with a CDU-531 also. One user reported that the driver worked on drives
-OEM'ed by Procomm, drive and interface board were labelled Procomm.
-
-The Linux driver is based on Corey Minyard's sonycd 0.3 driver for
-the CDU-31A. Ron Jeppesen just changed the commands that were sent
-to the drive to correspond to the CDU-535 commands and registers.
-There were enough changes to let bugs creep in but it seems to be stable.
-Ron was able to tar an entire CDROM (should read all blocks) and built
-ghostview and xfig off Walnut Creek's X11R5/GNU CDROM. xcdplayer and
-workman work with the driver. Others have used the driver without
-problems except those dealing with wait loops (fixed in third release).
-Like Minyard's original driver this one uses a polled interface (this
-is also the default setup for the DOS driver). It has not been tried
-with interrupts or DMA enabled on the board.
-
-REQUIREMENTS
-============
-
- - Sony CDU-535 drive, preferably without interrupts and DMA
- enabled on the card.
-
- - Drive must be set up as unit 1. Only the first unit will be
- recognized
-
- - You must enter your interface address into
- /usr/src/linux/drivers/cdrom/sonycd535.h and build the
- appropriate kernel or use the "kernel command line" parameter
- sonycd535=0x320
- with the correct interface address.
-
-NOTES:
-======
-
-1) The drive MUST be turned on when booting or it will not be recognized!
- (but see comments on modularized version below)
-
-2) when the cdrom device is opened the eject button is disabled to keep the
- user from ejecting a mounted disk and replacing it with another.
- Unfortunately xcdplayer and workman also open the cdrom device so you
- have to use the eject button in the software. Keep this in mind if your
- cdrom player refuses to give up its disk -- exit workman or xcdplayer, or
- umount the drive if it has been mounted.
-
-THANKS
-======
-
-Many thanks to Ron Jeppesen (ronj.an@site007.saic.com) for getting
-this project off the ground. He wrote the initial release
-and the first two patches to this driver (0.1, 0.2, and 0.3).
-Thanks also to Eberhard Moenkeberg (emoenke@gwdg.de) for prodding
-me to place this code into the mainstream Linux source tree
-(as of Linux version 1.1.91), as well as some patches to make
-it a better device citizen. Further thanks to Joel Katz
-<joelkatz@webchat.org> for his MODULE patches (see details below),
-Porfiri Claudio <C.Porfiri@nisms.tei.ericsson.se> for patches
-to make the driver work with the older CDU-510/515 series, and
-Heiko Eissfeldt <heiko@colossus.escape.de> for pointing out that
-the verify_area() checks were ignoring the results of said checks
-(note: verify_area() has since been replaced by access_ok()).
-
-(Acknowledgments from Ron Jeppesen in the 0.3 release:)
-Thanks to Corey Minyard who wrote the original CDU-31A driver on which
-this driver is based. Thanks to Ken Pizzini and Bob Blair who provided
-patches and feedback on the first release of this driver.
-
-Ken Pizzini
-ken@halcyon.com
-
-------------------------------------------------------------------------------
-(The following is from Joel Katz <joelkatz@webchat.org>.)
-
- To build a version of sony535.o that can be installed as a module,
-use the following command:
-
-gcc -c -D__KERNEL__ -DMODULE -O2 sonycd535.c -o sonycd535.o
-
- To install the module, simply type:
-
-insmod sony535.o
- or
-insmod sony535.o sonycd535=<address>
-
- And to remove it:
-
-rmmod sony535
-
- The code checks to see if MODULE is defined and behaves as it used
-to if MODULE is not defined. That means your patched file should behave
-exactly as it used to if compiled into the kernel.
-
- I have an external drive, and I usually leave it powered off. I used
-to have to reboot if I needed to use the CDROM drive. Now I don't.
-
- Even if you have an internal drive, why waste the 96K of memory
-(unswappable) that the driver uses if you use your CD-ROM drive infrequently?
-
- This driver will not install (whether compiled in or loaded as a
-module) if the CDROM drive is not available during its initialization. This
-means that you can have the driver compiled into the kernel and still load
-the module later (assuming the driver doesn't install itself during
-power-on). This only wastes 12K when you boot with the CDROM drive off.
-
- This is what I usually do; I leave the driver compiled into the
-kernel, but load it as a module if I powered the system up with the drive
-off and then later decided to use the CDROM drive.
-
- Since the driver only uses a single page to point to the chunks,
-attempting to set the buffer cache to more than 2 Megabytes would be very
-bad; don't do that.
diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c
index 3e73231695b3..be7af146dd30 100644
--- a/Documentation/connector/cn_test.c
+++ b/Documentation/connector/cn_test.c
@@ -124,9 +124,8 @@ static void cn_test_timer_func(unsigned long __data)
struct cn_msg *m;
char data[32];
- m = kmalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
+ m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC);
if (m) {
- memset(m, 0, sizeof(*m) + sizeof(data));
memcpy(&m->id, &cn_test_id, sizeof(m->id));
m->seq = cn_test_timer_counter;
diff --git a/Documentation/console/console.txt b/Documentation/console/console.txt
index d3e17447321c..877a1b26cc3d 100644
--- a/Documentation/console/console.txt
+++ b/Documentation/console/console.txt
@@ -29,7 +29,7 @@ In newer kernels, the following are also available:
If sysfs is enabled, the contents of /sys/class/vtconsole can be
examined. This shows the console backends currently registered by the
-system which are named vtcon<n> where <n> is an integer fro 0 to 15. Thus:
+system which are named vtcon<n> where <n> is an integer from 0 to 15. Thus:
ls /sys/class/vtconsole
. .. vtcon0 vtcon1
diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt
index 6c8d8f27db34..8569072fa387 100644
--- a/Documentation/driver-model/devres.txt
+++ b/Documentation/driver-model/devres.txt
@@ -207,7 +207,7 @@ responsibility. This is usually non-issue because bus ops and
resource allocations already do the job.
For an example of single-instance devres type, read pcim_iomap_table()
-in lib/iomap.c.
+in lib/devres.c.
All devres interface functions can be called without context if the
right gfp mask is given.
diff --git a/Documentation/drivers/edac/edac.txt b/Documentation/drivers/edac/edac.txt
index 3c5a9e4297b4..a5c36842ecef 100644
--- a/Documentation/drivers/edac/edac.txt
+++ b/Documentation/drivers/edac/edac.txt
@@ -2,22 +2,42 @@
EDAC - Error Detection And Correction
-Written by Doug Thompson <norsk5@xmission.com>
+Written by Doug Thompson <dougthompson@xmission.com>
7 Dec 2005
+17 Jul 2007 Updated
-EDAC was written by:
- Thayne Harbaugh,
- modified by Dave Peterson, Doug Thompson, et al,
- from the bluesmoke.sourceforge.net project.
+EDAC is maintained and written by:
+ Doug Thompson, Dave Jiang, Dave Peterson et al,
+ original author: Thayne Harbaugh,
+
+Contact:
+ website: bluesmoke.sourceforge.net
+ mailing list: bluesmoke-devel@lists.sourceforge.net
+
+"bluesmoke" was the name for this device driver when it was "out-of-tree"
+and maintained at sourceforge.net. When it was pushed into 2.6.16 for the
+first time, it was renamed to 'EDAC'.
+
+The bluesmoke project at sourceforge.net is now utilized as a 'staging area'
+for EDAC development, before it is sent upstream to kernel.org
+
+At the bluesmoke/EDAC project site, is a series of quilt patches against
+recent kernels, stored in a SVN respository. For easier downloading, there
+is also a tarball snapshot available.
============================================================================
EDAC PURPOSE
The 'edac' kernel module goal is to detect and report errors that occur
-within the computer system. In the initial release, memory Correctable Errors
-(CE) and Uncorrectable Errors (UE) are the primary errors being harvested.
+within the computer system running under linux.
+
+MEMORY
+
+In the initial release, memory Correctable Errors (CE) and Uncorrectable
+Errors (UE) are the primary errors being harvested. These types of errors
+are harvested by the 'edac_mc' class of device.
Detecting CE events, then harvesting those events and reporting them,
CAN be a predictor of future UE events. With CE events, the system can
@@ -25,9 +45,27 @@ continue to operate, but with less safety. Preventive maintenance and
proactive part replacement of memory DIMMs exhibiting CEs can reduce
the likelihood of the dreaded UE events and system 'panics'.
+NON-MEMORY
+
+A new feature for EDAC, the edac_device class of device, was added in
+the 2.6.23 version of the kernel.
+
+This new device type allows for non-memory type of ECC hardware detectors
+to have their states harvested and presented to userspace via the sysfs
+interface.
+
+Some architectures have ECC detectors for L1, L2 and L3 caches, along with DMA
+engines, fabric switches, main data path switches, interconnections,
+and various other hardware data paths. If the hardware reports it, then
+a edac_device device probably can be constructed to harvest and present
+that to userspace.
+
+
+PCI BUS SCANNING
In addition, PCI Bus Parity and SERR Errors are scanned for on PCI devices
in order to determine if errors are occurring on data transfers.
+
The presence of PCI Parity errors must be examined with a grain of salt.
There are several add-in adapters that do NOT follow the PCI specification
with regards to Parity generation and reporting. The specification says
@@ -35,11 +73,17 @@ the vendor should tie the parity status bits to 0 if they do not intend
to generate parity. Some vendors do not do this, and thus the parity bit
can "float" giving false positives.
-[There are patches in the kernel queue which will allow for storage of
-quirks of PCI devices reporting false parity positives. The 2.6.18
-kernel should have those patches included. When that becomes available,
-then EDAC will be patched to utilize that information to "skip" such
-devices.]
+In the kernel there is a pci device attribute located in sysfs that is
+checked by the EDAC PCI scanning code. If that attribute is set,
+PCI parity/error scannining is skipped for that device. The attribute
+is:
+
+ broken_parity_status
+
+as is located in /sys/devices/pci<XXX>/0000:XX:YY.Z directorys for
+PCI devices.
+
+FUTURE HARDWARE SCANNING
EDAC will have future error detectors that will be integrated with
EDAC or added to it, in the following list:
@@ -57,13 +101,14 @@ and the like.
============================================================================
EDAC VERSIONING
-EDAC is composed of a "core" module (edac_mc.ko) and several Memory
+EDAC is composed of a "core" module (edac_core.ko) and several Memory
Controller (MC) driver modules. On a given system, the CORE
is loaded and one MC driver will be loaded. Both the CORE and
-the MC driver have individual versions that reflect current release
-level of their respective modules. Thus, to "report" on what version
-a system is running, one must report both the CORE's and the
-MC driver's versions.
+the MC driver (or edac_device driver) have individual versions that reflect
+current release level of their respective modules.
+
+Thus, to "report" on what version a system is running, one must report both
+the CORE's and the MC driver's versions.
LOADING
@@ -88,8 +133,9 @@ EDAC sysfs INTERFACE
EDAC presents a 'sysfs' interface for control, reporting and attribute
reporting purposes.
-EDAC lives in the /sys/devices/system/edac directory. Within this directory
-there currently reside 2 'edac' components:
+EDAC lives in the /sys/devices/system/edac directory.
+
+Within this directory there currently reside 2 'edac' components:
mc memory controller(s) system
pci PCI control and status system
@@ -188,7 +234,7 @@ In directory 'mc' are EDAC system overall control and attribute files:
Panic on UE control file:
- 'panic_on_ue'
+ 'edac_mc_panic_on_ue'
An uncorrectable error will cause a machine panic. This is usually
desirable. It is a bad idea to continue when an uncorrectable error
@@ -199,12 +245,12 @@ Panic on UE control file:
LOAD TIME: module/kernel parameter: panic_on_ue=[0|1]
- RUN TIME: echo "1" >/sys/devices/system/edac/mc/panic_on_ue
+ RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_panic_on_ue
Log UE control file:
- 'log_ue'
+ 'edac_mc_log_ue'
Generate kernel messages describing uncorrectable errors. These errors
are reported through the system message log system. UE statistics
@@ -212,12 +258,12 @@ Log UE control file:
LOAD TIME: module/kernel parameter: log_ue=[0|1]
- RUN TIME: echo "1" >/sys/devices/system/edac/mc/log_ue
+ RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ue
Log CE control file:
- 'log_ce'
+ 'edac_mc_log_ce'
Generate kernel messages describing correctable errors. These
errors are reported through the system message log system.
@@ -225,12 +271,12 @@ Log CE control file:
LOAD TIME: module/kernel parameter: log_ce=[0|1]
- RUN TIME: echo "1" >/sys/devices/system/edac/mc/log_ce
+ RUN TIME: echo "1" >/sys/devices/system/edac/mc/edac_mc_log_ce
Polling period control file:
- 'poll_msec'
+ 'edac_mc_poll_msec'
The time period, in milliseconds, for polling for error information.
Too small a value wastes resources. Too large a value might delay
@@ -241,7 +287,7 @@ Polling period control file:
LOAD TIME: module/kernel parameter: poll_msec=[0|1]
- RUN TIME: echo "1000" >/sys/devices/system/edac/mc/poll_msec
+ RUN TIME: echo "1000" >/sys/devices/system/edac/mc/edac_mc_poll_msec
============================================================================
@@ -587,3 +633,95 @@ Parity Count:
=======================================================================
+
+
+EDAC_DEVICE type of device
+
+In the header file, edac_core.h, there is a series of edac_device structures
+and APIs for the EDAC_DEVICE.
+
+User space access to an edac_device is through the sysfs interface.
+
+At the location /sys/devices/system/edac (sysfs) new edac_device devices will
+appear.
+
+There is a three level tree beneath the above 'edac' directory. For example,
+the 'test_device_edac' device (found at the bluesmoke.sourceforget.net website)
+installs itself as:
+
+ /sys/devices/systm/edac/test-instance
+
+in this directory are various controls, a symlink and one or more 'instance'
+directorys.
+
+The standard default controls are:
+
+ log_ce boolean to log CE events
+ log_ue boolean to log UE events
+ panic_on_ue boolean to 'panic' the system if an UE is encountered
+ (default off, can be set true via startup script)
+ poll_msec time period between POLL cycles for events
+
+The test_device_edac device adds at least one of its own custom control:
+
+ test_bits which in the current test driver does nothing but
+ show how it is installed. A ported driver can
+ add one or more such controls and/or attributes
+ for specific uses.
+ One out-of-tree driver uses controls here to allow
+ for ERROR INJECTION operations to hardware
+ injection registers
+
+The symlink points to the 'struct dev' that is registered for this edac_device.
+
+INSTANCES
+
+One or more instance directories are present. For the 'test_device_edac' case:
+
+ test-instance0
+
+
+In this directory there are two default counter attributes, which are totals of
+counter in deeper subdirectories.
+
+ ce_count total of CE events of subdirectories
+ ue_count total of UE events of subdirectories
+
+BLOCKS
+
+At the lowest directory level is the 'block' directory. There can be 0, 1
+or more blocks specified in each instance.
+
+ test-block0
+
+
+In this directory the default attributes are:
+
+ ce_count which is counter of CE events for this 'block'
+ of hardware being monitored
+ ue_count which is counter of UE events for this 'block'
+ of hardware being monitored
+
+
+The 'test_device_edac' device adds 4 attributes and 1 control:
+
+ test-block-bits-0 for every POLL cycle this counter
+ is incremented
+ test-block-bits-1 every 10 cycles, this counter is bumped once,
+ and test-block-bits-0 is set to 0
+ test-block-bits-2 every 100 cycles, this counter is bumped once,
+ and test-block-bits-1 is set to 0
+ test-block-bits-3 every 1000 cycles, this counter is bumped once,
+ and test-block-bits-2 is set to 0
+
+
+ reset-counters writing ANY thing to this control will
+ reset all the above counters.
+
+
+Use of the 'test_device_edac' driver should any others to create their own
+unique drivers for their hardware systems.
+
+The 'test_device_edac' sample driver is located at the
+bluesmoke.sourceforge.net project site for EDAC.
+
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index 4e7614e606c5..ecb47adda063 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -9,19 +9,29 @@ for accessing the i2c bus and the gpio pins of the bt8xx chipset.
Please see Documentation/dvb/cards.txt => o Cards based on the Conexant Bt8xx PCI bridge:
Compiling kernel please enable:
-a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "BT848 Video For Linux"
-b.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
+a.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Enable Video for Linux API 1 (DEPRECATED)"
+b.)"Device drivers" => "Multimedia devices" => "Video For Linux" => "Video Capture Adapters" => "BT848 Video For Linux"
+c.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices" => "DVB for Linux" "DVB Core Support" "Bt8xx based PCI Cards"
-2) Loading Modules
-==================
+Please use the following options with care as deselection of drivers which are in fact necessary
+may result in DVB devices that cannot be tuned due to lack of driver support:
+You can save RAM by deselecting every frontend module that your DVB card does not need.
+
+First please remove the static dependency of DVB card drivers on all frontend modules for all possible card variants by enabling:
+d.) "Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Load and attach frontend modules as needed"
-In default cases bttv is loaded automatically.
-To load the backend either place dvb-bt8xx in etc/modules, or apply manually:
+If you know the frontend driver that your card needs please enable:
+e.)"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
+ => "DVB for Linux" "DVB Core Support" "Customise DVB Frontends" => "Customise the frontend modules to build"
+ Then please select your card-specific frontend module.
- $ modprobe dvb-bt8xx
+2) Loading Modules
+==================
-All frontends will be loaded automatically.
+Regular case: If the bttv driver detects a bt8xx-based DVB card, all frontend and backend modules will be loaded automatically.
+Exceptions are:
+- Old TwinHan DST cards or clones with or without CA slot and not containing an Eeprom.
People running udev please see Documentation/dvb/udev.txt.
In the following cases overriding the PCI type detection for dvb-bt8xx might be necessary:
@@ -30,7 +40,6 @@ In the following cases overriding the PCI type detection for dvb-bt8xx might be
------------------------------
$ modprobe bttv card=113
- $ modprobe dvb-bt8xx
$ modprobe dst
Useful parameters for verbosity level and debugging the dst module:
@@ -65,10 +74,9 @@ DViCO FusionHDTV 5 Lite: 135
Notice: The order of the card ID should be uprising:
Example:
$ modprobe bttv card=113 card=135
- $ modprobe dvb-bt8xx
For a full list of card ID's please see Documentation/video4linux/CARDLIST.bttv.
-In case of further problems send questions to the mailing list: www.linuxdvb.org.
+In case of further problems please subscribe and send questions to the mailing list: linux-dvb@linuxtv.org.
Authors: Richard Walker,
Jamie Honan,
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 4820366b6ae8..b4d306ae9234 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -24,7 +24,8 @@ use IO::Handle;
@components = ( "sp8870", "sp887x", "tda10045", "tda10046",
"tda10046lifeview", "av7110", "dec2000t", "dec2540t",
"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
- "or51211", "or51132_qam", "or51132_vsb", "bluebird");
+ "or51211", "or51132_qam", "or51132_vsb", "bluebird",
+ "opera1");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -56,7 +57,7 @@ syntax();
sub sp8870 {
my $sourcefile = "tt_Premium_217g.zip";
- my $url = "http://www.technotrend.de/new/217g/$sourcefile";
+ my $url = "http://www.softwarepatch.pl/9999ccd06a4813cb827dbb0005071c71/$sourcefile";
my $hash = "53970ec17a538945a6d8cb608a7b3899";
my $outfile = "dvb-fe-sp8870.fw";
my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
@@ -210,6 +211,45 @@ sub dec3000s {
$outfile;
}
+sub opera1{
+ my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);
+
+ checkstandard();
+ my $fwfile1="dvb-usb-opera1-fpga-01.fw";
+ my $fwfile2="dvb-usb-opera-01.fw";
+ extract("2830SCap2.sys", 0x62e8, 55024, "$tmpdir/opera1-fpga.fw");
+ extract("2830SLoad2.sys",0x3178,0x3685-0x3178,"$tmpdir/fw1part1");
+ extract("2830SLoad2.sys",0x0980,0x3150-0x0980,"$tmpdir/fw1part2");
+ delzero("$tmpdir/fw1part1","$tmpdir/fw1part1-1");
+ delzero("$tmpdir/fw1part2","$tmpdir/fw1part2-1");
+ verify("$tmpdir/fw1part1-1","5e0909858fdf0b5b09ad48b9fe622e70");
+ verify("$tmpdir/fw1part2-1","d6e146f321427e931df2c6fcadac37a1");
+ verify("$tmpdir/opera1-fpga.fw","0f8133f5e9051f5f3c1928f7e5a1b07d");
+
+ my $RES1="\x01\x92\x7f\x00\x01\x00";
+ my $RES0="\x01\x92\x7f\x00\x00\x00";
+ my $DAT1="\x01\x00\xe6\x00\x01\x00";
+ my $DAT0="\x01\x00\xe6\x00\x00\x00";
+ open FW,">$tmpdir/opera.fw";
+ print FW "$RES1";
+ print FW "$DAT1";
+ print FW "$RES1";
+ print FW "$DAT1";
+ appendfile(FW,"$tmpdir/fw1part1-1");
+ print FW "$RES0";
+ print FW "$DAT0";
+ print FW "$RES1";
+ print FW "$DAT1";
+ appendfile(FW,"$tmpdir/fw1part2-1");
+ print FW "$RES1";
+ print FW "$DAT1";
+ print FW "$RES0";
+ print FW "$DAT0";
+ copy ("$tmpdir/opera1-fpga.fw",$fwfile1);
+ copy ("$tmpdir/opera.fw",$fwfile2);
+
+ $fwfile1.",".$fwfile2;
+}
sub vp7041 {
my $sourcefile = "2.422.zip";
@@ -440,6 +480,25 @@ sub appendfile {
close(INFILE);
}
+sub delzero{
+ my ($infile,$outfile) =@_;
+
+ open INFILE,"<$infile";
+ open OUTFILE,">$outfile";
+ while (1){
+ $rcount=sysread(INFILE,$buf,22);
+ $len=ord(substr($buf,0,1));
+ print OUTFILE substr($buf,0,1);
+ print OUTFILE substr($buf,2,$len+3);
+ last if ($rcount<1);
+ printf OUTFILE "%c",0;
+#print $len." ".length($buf)."\n";
+
+ }
+ close(INFILE);
+ close(OUTFILE);
+}
+
sub syntax() {
print STDERR "syntax: get_dvb_firmware <component>\n";
print STDERR "Supported components:\n";
diff --git a/Documentation/dvb/opera-firmware.txt b/Documentation/dvb/opera-firmware.txt
new file mode 100644
index 000000000000..93e784c2607b
--- /dev/null
+++ b/Documentation/dvb/opera-firmware.txt
@@ -0,0 +1,27 @@
+To extract the firmware for the Opera DVB-S1 USB-Box
+you need to copy the files:
+
+2830SCap2.sys
+2830SLoad2.sys
+
+from the windriver disk into this directory.
+
+Then run
+
+./get_dvb_firware opera1
+
+and after that you have 2 files:
+
+dvb-usb-opera-01.fw
+dvb-usb-opera1-fpga-01.fw
+
+in here.
+
+Copy them into /lib/firmware/ .
+
+After that the driver can load the firmware
+(if you have enabled firmware loading
+in kernel config and have hotplug running).
+
+
+Marco Gittler <g.marco@freenet.de> \ No newline at end of file
diff --git a/Documentation/fault-injection/failcmd.sh b/Documentation/fault-injection/failcmd.sh
deleted file mode 100644
index 63177aba8106..000000000000
--- a/Documentation/fault-injection/failcmd.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-echo 1 > /proc/self/make-it-fail
-exec $*
diff --git a/Documentation/fault-injection/failmodule.sh b/Documentation/fault-injection/failmodule.sh
deleted file mode 100644
index 474a8b971f9c..000000000000
--- a/Documentation/fault-injection/failmodule.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-#
-# Usage: failmodule <failname> <modulename> [stacktrace-depth]
-#
-# <failname>: "failslab", "fail_alloc_page", or "fail_make_request"
-#
-# <modulename>: module name that you want to inject faults.
-#
-# [stacktrace-depth]: the maximum number of stacktrace walking allowed
-#
-
-STACKTRACE_DEPTH=5
-if [ $# -gt 2 ]; then
- STACKTRACE_DEPTH=$3
-fi
-
-if [ ! -d /debug/$1 ]; then
- echo "Fault-injection $1 does not exist" >&2
- exit 1
-fi
-if [ ! -d /sys/module/$2 ]; then
- echo "Module $2 does not exist" >&2
- exit 1
-fi
-
-# Disable any fault injection
-echo 0 > /debug/$1/stacktrace-depth
-
-echo `cat /sys/module/$2/sections/.text` > /debug/$1/require-start
-echo `cat /sys/module/$2/sections/.exit.text` > /debug/$1/require-end
-echo $STACKTRACE_DEPTH > /debug/$1/stacktrace-depth
diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt
index b7ca560b9340..4bc374a14345 100644
--- a/Documentation/fault-injection/fault-injection.txt
+++ b/Documentation/fault-injection/fault-injection.txt
@@ -103,6 +103,11 @@ configuration of fault-injection capabilities.
default is 'N', setting it to 'Y' will inject failures
only into non-sleep allocations (GFP_ATOMIC allocations).
+- /debug/fail_page_alloc/min-order:
+
+ specifies the minimum page allocation order to be injected
+ failures.
+
o Boot option
In order to inject faults while debugfs is not available (early boot time),
@@ -156,70 +161,77 @@ o add a hook to insert failures
Application Examples
--------------------
-o inject slab allocation failures into module init/cleanup code
+o Inject slab allocation failures into module init/exit code
-------------------------------------------------------------------------------
#!/bin/bash
-FAILCMD=Documentation/fault-injection/failcmd.sh
-BLACKLIST="root_plug evbug"
-
-FAILNAME=failslab
-echo Y > /debug/$FAILNAME/task-filter
-echo 10 > /debug/$FAILNAME/probability
-echo 100 > /debug/$FAILNAME/interval
-echo -1 > /debug/$FAILNAME/times
-echo 2 > /debug/$FAILNAME/verbose
-echo 1 > /debug/$FAILNAME/ignore-gfp-wait
+FAILTYPE=failslab
+echo Y > /debug/$FAILTYPE/task-filter
+echo 10 > /debug/$FAILTYPE/probability
+echo 100 > /debug/$FAILTYPE/interval
+echo -1 > /debug/$FAILTYPE/times
+echo 0 > /debug/$FAILTYPE/space
+echo 2 > /debug/$FAILTYPE/verbose
+echo 1 > /debug/$FAILTYPE/ignore-gfp-wait
-blacklist()
+faulty_system()
{
- echo $BLACKLIST | grep $1 > /dev/null 2>&1
+ bash -c "echo 1 > /proc/self/make-it-fail && exec $*"
}
-oops()
-{
- dmesg | grep BUG > /dev/null 2>&1
-}
+if [ $# -eq 0 ]
+then
+ echo "Usage: $0 modulename [ modulename ... ]"
+ exit 1
+fi
+
+for m in $*
+do
+ echo inserting $m...
+ faulty_system modprobe $m
-find /lib/modules/`uname -r` -name '*.ko' -exec basename {} .ko \; |
- while read i
- do
- oops && exit 1
-
- if ! blacklist $i
- then
- echo inserting $i...
- bash $FAILCMD modprobe $i
- fi
- done
-
-lsmod | awk '{ if ($3 == 0) { print $1 } }' |
- while read i
- do
- oops && exit 1
-
- if ! blacklist $i
- then
- echo removing $i...
- bash $FAILCMD modprobe -r $i
- fi
- done
+ echo removing $m...
+ faulty_system modprobe -r $m
+done
------------------------------------------------------------------------------
-o inject slab allocation failures only for a specific module
+o Inject page allocation failures only for a specific module
-------------------------------------------------------------------------------
#!/bin/bash
-FAILMOD=Documentation/fault-injection/failmodule.sh
+FAILTYPE=fail_page_alloc
+module=$1
-echo injecting errors into the module $1...
+if [ -z $module ]
+then
+ echo "Usage: $0 <modulename>"
+ exit 1
+fi
-modprobe $1
-bash $FAILMOD failslab $1 10
-echo 25 > /debug/failslab/probability
+modprobe $module
-------------------------------------------------------------------------------
+if [ ! -d /sys/module/$module/sections ]
+then
+ echo Module $module is not loaded
+ exit 1
+fi
+
+cat /sys/module/$module/sections/.text > /debug/$FAILTYPE/require-start
+cat /sys/module/$module/sections/.data > /debug/$FAILTYPE/require-end
+
+echo N > /debug/$FAILTYPE/task-filter
+echo 10 > /debug/$FAILTYPE/probability
+echo 100 > /debug/$FAILTYPE/interval
+echo -1 > /debug/$FAILTYPE/times
+echo 0 > /debug/$FAILTYPE/space
+echo 2 > /debug/$FAILTYPE/verbose
+echo 1 > /debug/$FAILTYPE/ignore-gfp-wait
+echo 1 > /debug/$FAILTYPE/ignore-gfp-highmem
+echo 10 > /debug/$FAILTYPE/stacktrace-depth
+
+trap "echo 0 > /debug/$FAILTYPE/probability" SIGINT SIGTERM EXIT
+
+echo "Injecting errors into the module $module... (interrupt to stop)"
+sleep 1000000
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 3a159dac04f5..c175eedadb5f 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -26,9 +26,7 @@ Who: Hans Verkuil <hverkuil@xs4all.nl> and
---------------------------
-What: /sys/devices/.../power/state
- dev->power.power_state
- dpm_runtime_{suspend,resume)()
+What: dev->power.power_state
When: July 2007
Why: Broken design for runtime control over driver power states, confusing
driver-internal runtime power management with: mechanisms to support
@@ -41,14 +39,6 @@ Who: Pavel Machek <pavel@suse.cz>
---------------------------
-What: RAW driver (CONFIG_RAW_DRIVER)
-When: December 2005
-Why: declared obsolete since kernel 2.6.3
- O_DIRECT can be used instead
-Who: Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
What: old NCR53C9x driver
When: October 2007
Why: Replaced by the much better esp_scsi driver. Actual low-level
@@ -61,6 +51,7 @@ Who: David Miller <davem@davemloft.net>
What: Video4Linux API 1 ioctls and video_decoder.h from Video devices.
When: December 2006
Files: include/linux/video_decoder.h
+Check: include/linux/video_decoder.h
Why: V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
series. The old API have lots of drawbacks and don't provide enough
means to work with all video and audio standards. The newer API is
@@ -94,7 +85,7 @@ Who: Dominik Brodowski <linux@brodo.de>
What: remove EXPORT_SYMBOL(kernel_thread)
When: August 2006
Files: arch/*/kernel/*_ksyms.c
-Funcs: kernel_thread
+Check: kernel_thread
Why: kernel_thread is a low-level implementation detail. Drivers should
use the <linux/kthread.h> API instead which shields them from
implementation details and provides a higherlevel interface that
@@ -119,13 +110,6 @@ Who: Adrian Bunk <bunk@stusta.de>
---------------------------
-What: drivers depending on OSS_OBSOLETE_DRIVER
-When: options in 2.6.20, code in 2.6.22
-Why: OSS drivers with ALSA replacements
-Who: Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports
(temporary transition config option provided until then)
The transition config option will also be removed at the same time.
@@ -152,6 +136,15 @@ Who: Greg Kroah-Hartman <gregkh@suse.de>
---------------------------
+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: Interrupt only SA_* flags
When: September 2007
Why: The interrupt related SA_* flags are replaced by IRQF_* to move them
@@ -171,15 +164,6 @@ Who: Kay Sievers <kay.sievers@suse.de>
---------------------------
-What: i2c-isa
-When: December 2006
-Why: i2c-isa is a non-sense and doesn't fit in the device driver
- model. Drivers relying on it are better implemented as platform
- drivers.
-Who: Jean Delvare <khali@linux-fr.org>
-
----------------------------
-
What: i2c_adapter.list
When: July 2007
Why: Superfluous, this list duplicates the one maintained by the driver
@@ -196,46 +180,11 @@ Who: Adrian Bunk <bunk@stusta.de>
---------------------------
-What: ACPI hooks (X86_SPEEDSTEP_CENTRINO_ACPI) in speedstep-centrino driver
-When: December 2006
-Why: Speedstep-centrino driver with ACPI hooks and acpi-cpufreq driver are
- functionally very much similar. They talk to ACPI in same way. Only
- difference between them is the way they do frequency transitions.
- One uses MSRs and the other one uses IO ports. Functionaliy of
- speedstep_centrino with ACPI hooks is now merged into acpi-cpufreq.
- That means one common driver will support all Intel Enhanced Speedstep
- capable CPUs. That means less confusion over name of
- speedstep-centrino driver (with that driver supposed to be used on
- non-centrino platforms). That means less duplication of code and
- less maintenance effort and no possibility of these two drivers
- going out of sync.
- Current users of speedstep_centrino with ACPI hooks are requested to
- switch over to acpi-cpufreq driver. speedstep-centrino will continue
- to work using older non-ACPI static table based scheme even after this
- date.
-
-Who: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
-
----------------------------
-
-What: /sys/firmware/acpi/namespace
-When: 2.6.21
-Why: The ACPI namespace is effectively the symbol list for
- the BIOS. The device names are completely arbitrary
- and have no place being exposed to user-space.
-
- For those interested in the BIOS ACPI namespace,
- the BIOS can be extracted and disassembled with acpidump
- and iasl as documented in the pmtools package here:
- http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils
-Who: Len Brown <len.brown@intel.com>
-
----------------------------
-
What: ACPI procfs interface
-When: July 2007
-Why: After ACPI sysfs conversion, ACPI attributes will be duplicated
- in sysfs and the ACPI procfs interface should be removed.
+When: July 2008
+Why: ACPI sysfs conversion should be finished by January 2008.
+ ACPI procfs interface will be removed in July 2008 so that
+ there is enough time for the user space to catch up.
Who: Zhang Rui <rui.zhang@intel.com>
---------------------------
@@ -262,25 +211,6 @@ Who: Richard Purdie <rpurdie@rpsys.net>
---------------------------
-What: Multipath cached routing support in ipv4
-When: in 2.6.23
-Why: Code was merged, then submitter immediately disappeared leaving
- us with no maintainer and lots of bugs. The code should not have
- been merged in the first place, and many aspects of it's
- implementation are blocking more critical core networking
- development. It's marked EXPERIMENTAL and no distribution
- enables it because it cause obscure crashes due to unfixable bugs
- (interfaces don't return errors so memory allocation can't be
- handled, calling contexts of these interfaces make handling
- errors impossible too because they get called after we've
- totally commited to creating a route object, for example).
- This problem has existed for years and no forward progress
- has ever been made, and nobody steps up to try and salvage
- this code, so we're going to finally just get rid of it.
-Who: David S. Miller <davem@davemloft.net>
-
----------------------------
-
What: read_dev_chars(), read_conf_data{,_lpm}() (s390 common I/O layer)
When: December 2007
Why: These functions are a leftover from 2.4 times. They have several
@@ -305,6 +235,14 @@ Who: Jean Delvare <khali@linux-fr.org>
---------------------------
+What: 'time' kernel boot parameter
+When: January 2008
+Why: replaced by 'printk.time=<value>' so that printk timestamps can be
+ enabled or disabled as needed
+Who: Randy Dunlap <randy.dunlap@oracle.com>
+
+---------------------------
+
What: drivers depending on OSS_OBSOLETE
When: options in 2.6.23, code in 2.6.25
Why: obsolete OSS drivers
@@ -330,3 +268,41 @@ Who: Tejun Heo <htejun@gmail.com>
---------------------------
+What: Legacy RTC drivers (under drivers/i2c/chips)
+When: November 2007
+Why: Obsolete. We have a RTC subsystem with better drivers.
+Who: Jean Delvare <khali@linux-fr.org>
+
+---------------------------
+
+What: iptables SAME target
+When: 1.1. 2008
+Files: net/ipv4/netfilter/ipt_SAME.c, include/linux/netfilter_ipv4/ipt_SAME.h
+Why: Obsolete for multiple years now, NAT core provides the same behaviour.
+ Unfixable broken wrt. 32/64 bit cleanness.
+Who: Patrick McHardy <kaber@trash.net>
+
+---------------------------
+
+What: The arch/ppc and include/asm-ppc directories
+When: Jun 2008
+Why: The arch/powerpc tree is the merged architecture for ppc32 and ppc64
+ platforms. Currently there are efforts underway to port the remaining
+ arch/ppc platforms to the merged tree. New submissions to the arch/ppc
+ tree have been frozen with the 2.6.22 kernel release and that tree will
+ remain in bug-fix only mode until its scheduled removal. Platforms
+ that are not ported by June 2008 will be removed due to the lack of an
+ interested maintainer.
+Who: linuxppc-dev@ozlabs.org
+
+---------------------------
+
+What: mthca driver's MSI support
+When: January 2008
+Files: drivers/infiniband/hw/mthca/*.[ch]
+Why: All mthca hardware also supports MSI-X, which provides
+ strictly more functionality than MSI. So there is no point in
+ having both MSI-X and MSI support in the driver.
+Who: Roland Dreier <rolandd@cisco.com>
+
+---------------------------
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index d866551be037..f0f825808ca4 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -510,13 +510,24 @@ More details about quota locking can be found in fs/dquot.c.
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:
- BKL mmap_sem
+ BKL mmap_sem PageLocked(page)
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
+about to become writeable. The file system is responsible for
+protecting against truncate races. Once appropriate action has been
+taking to lock out truncate, the page range should be verified to be
+within i_size. The page mapping should also be checked that it is not
+NULL.
================================================================================
Dubious stuff
diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
index b34cdb50eab4..d1b98257d000 100644
--- a/Documentation/filesystems/configfs/configfs.txt
+++ b/Documentation/filesystems/configfs/configfs.txt
@@ -238,6 +238,8 @@ config_item_type.
struct config_group *(*make_group)(struct config_group *group,
const char *name);
int (*commit_item)(struct config_item *item);
+ void (*disconnect_notify)(struct config_group *group,
+ struct config_item *item);
void (*drop_item)(struct config_group *group,
struct config_item *item);
};
@@ -268,6 +270,16 @@ the item in other threads, the memory is safe. It may take some time
for the item to actually disappear from the subsystem's usage. But it
is gone from configfs.
+When drop_item() is called, the item's linkage has already been torn
+down. It no longer has a reference on its parent and has no place in
+the item hierarchy. If a client needs to do some cleanup before this
+teardown happens, the subsystem can implement the
+ct_group_ops->disconnect_notify() method. The method is called after
+configfs has removed the item from the filesystem view but before the
+item is removed from its parent group. Like drop_item(),
+disconnect_notify() is void and cannot fail. Client subsystems should
+not drop any references here, as they still must do it in drop_item().
+
A config_group cannot be removed while it still has child items. This
is implemented in the configfs rmdir(2) code. ->drop_item() will not be
called, as the item has not been dropped. rmdir(2) will fail, as the
@@ -280,18 +292,18 @@ tells configfs to make the subsystem appear in the file tree.
struct configfs_subsystem {
struct config_group su_group;
- struct semaphore su_sem;
+ struct mutex su_mutex;
};
int configfs_register_subsystem(struct configfs_subsystem *subsys);
void configfs_unregister_subsystem(struct configfs_subsystem *subsys);
- A subsystem consists of a toplevel config_group and a semaphore.
+ A subsystem consists of a toplevel config_group and a mutex.
The group is where child config_items are created. For a subsystem,
this group is usually defined statically. Before calling
configfs_register_subsystem(), the subsystem must have initialized the
group via the usual group _init() functions, and it must also have
-initialized the semaphore.
+initialized the mutex.
When the register call returns, the subsystem is live, and it
will be visible via configfs. At that point, mkdir(2) can be called and
the subsystem must be ready for it.
@@ -303,7 +315,7 @@ subsystem/group and the simple_child item in configfs_example.c It
shows a trivial object displaying and storing an attribute, and a simple
group creating and destroying these children.
-[Hierarchy Navigation and the Subsystem Semaphore]
+[Hierarchy Navigation and the Subsystem Mutex]
There is an extra bonus that configfs provides. The config_groups and
config_items are arranged in a hierarchy due to the fact that they
@@ -314,19 +326,19 @@ and config_item->ci_parent structure members.
A subsystem can navigate the cg_children list and the ci_parent pointer
to see the tree created by the subsystem. This can race with configfs'
-management of the hierarchy, so configfs uses the subsystem semaphore to
+management of the hierarchy, so configfs uses the subsystem mutex to
protect modifications. Whenever a subsystem wants to navigate the
hierarchy, it must do so under the protection of the subsystem
-semaphore.
+mutex.
-A subsystem will be prevented from acquiring the semaphore while a newly
+A subsystem will be prevented from acquiring the mutex while a newly
allocated item has not been linked into this hierarchy. Similarly, it
-will not be able to acquire the semaphore while a dropping item has not
+will not be able to acquire the mutex while a dropping item has not
yet been unlinked. This means that an item's ci_parent pointer will
never be NULL while the item is in configfs, and that an item will only
be in its parent's cg_children list for the same duration. This allows
a subsystem to trust ci_parent and cg_children while they hold the
-semaphore.
+mutex.
[Item Aggregation Via symlink(2)]
@@ -386,6 +398,33 @@ As a consequence of this, default_groups cannot be removed directly via
rmdir(2). They also are not considered when rmdir(2) on the parent
group is checking for children.
+[Dependant Subsystems]
+
+Sometimes other drivers depend on particular configfs items. For
+example, ocfs2 mounts depend on a heartbeat region item. If that
+region item is removed with rmdir(2), the ocfs2 mount must BUG or go
+readonly. Not happy.
+
+configfs provides two additional API calls: configfs_depend_item() and
+configfs_undepend_item(). A client driver can call
+configfs_depend_item() on an existing item to tell configfs that it is
+depended on. configfs will then return -EBUSY from rmdir(2) for that
+item. When the item is no longer depended on, the client driver calls
+configfs_undepend_item() on it.
+
+These API cannot be called underneath any configfs callbacks, as
+they will conflict. They can block and allocate. A client driver
+probably shouldn't calling them of its own gumption. Rather it should
+be providing an API that external subsystems call.
+
+How does this work? Imagine the ocfs2 mount process. When it mounts,
+it asks for a heartbeat region item. This is done via a call into the
+heartbeat code. Inside the heartbeat code, the region item is looked
+up. Here, the heartbeat code calls configfs_depend_item(). If it
+succeeds, then heartbeat knows the region is safe to give to ocfs2.
+If it fails, it was being torn down anyway, and heartbeat can gracefully
+pass up an error.
+
[Committable Items]
NOTE: Committable items are currently unimplemented.
diff --git a/Documentation/filesystems/configfs/configfs_example.c b/Documentation/filesystems/configfs/configfs_example.c
index 2d6a14a463e0..25151fd5c2c6 100644
--- a/Documentation/filesystems/configfs/configfs_example.c
+++ b/Documentation/filesystems/configfs/configfs_example.c
@@ -277,11 +277,10 @@ static struct config_item *simple_children_make_item(struct config_group *group,
{
struct simple_child *simple_child;
- simple_child = kmalloc(sizeof(struct simple_child), GFP_KERNEL);
+ simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL);
if (!simple_child)
return NULL;
- memset(simple_child, 0, sizeof(struct simple_child));
config_item_init_type_name(&simple_child->item, name,
&simple_child_type);
@@ -364,12 +363,11 @@ static struct config_group *group_children_make_group(struct config_group *group
{
struct simple_children *simple_children;
- simple_children = kmalloc(sizeof(struct simple_children),
+ simple_children = kzalloc(sizeof(struct simple_children),
GFP_KERNEL);
if (!simple_children)
return NULL;
- memset(simple_children, 0, sizeof(struct simple_children));
config_group_init_type_name(&simple_children->group, name,
&simple_children_type);
@@ -453,7 +451,7 @@ static int __init configfs_example_init(void)
subsys = example_subsys[i];
config_group_init(&subsys->su_group);
- init_MUTEX(&subsys->su_sem);
+ mutex_init(&subsys->su_mutex);
ret = configfs_register_subsystem(subsys);
if (ret) {
printk(KERN_ERR "Error %d while registering subsystem %s\n",
diff --git a/Documentation/ecryptfs.txt b/Documentation/filesystems/ecryptfs.txt
index 01d8a08351ac..01d8a08351ac 100644
--- a/Documentation/ecryptfs.txt
+++ b/Documentation/filesystems/ecryptfs.txt
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 8756a07f4dc3..4a37e25e694c 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -42,6 +42,7 @@ Table of Contents
2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
2.13 /proc/<pid>/oom_score - Display current oom-killer score
2.14 /proc/<pid>/io - Display the IO accounting fields
+ 2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
------------------------------------------------------------------------------
Preface
@@ -171,7 +172,9 @@ read the file /proc/PID/status:
This shows you nearly the same information you would get if you viewed it with
the ps command. In fact, ps uses the proc file system to obtain its
information. The statm file contains more detailed information about the
-process memory usage. Its seven fields are explained in Table 1-2.
+process memory usage. Its seven fields are explained in Table 1-2. The stat
+file contains details information about the process itself. Its fields are
+explained in Table 1-3.
Table 1-2: Contents of the statm files (as of 2.6.8-rc3)
@@ -188,16 +191,65 @@ Table 1-2: Contents of the statm files (as of 2.6.8-rc3)
dt number of dirty pages (always 0 on 2.6)
..............................................................................
+
+Table 1-3: Contents of the stat files (as of 2.6.22-rc3)
+..............................................................................
+ Field Content
+ pid process id
+ tcomm filename of the executable
+ state state (R is running, S is sleeping, D is sleeping in an
+ uninterruptible wait, Z is zombie, T is traced or stopped)
+ ppid process id of the parent process
+ pgrp pgrp of the process
+ sid session id
+ tty_nr tty the process uses
+ tty_pgrp pgrp of the tty
+ flags task flags
+ min_flt number of minor faults
+ cmin_flt number of minor faults with child's
+ maj_flt number of major faults
+ cmaj_flt number of major faults with child's
+ utime user mode jiffies
+ stime kernel mode jiffies
+ cutime user mode jiffies with child's
+ cstime kernel mode jiffies with child's
+ priority priority level
+ nice nice level
+ num_threads number of threads
+ start_time time the process started after system boot
+ vsize virtual memory size
+ rss resident set memory size
+ rsslim current limit in bytes on the rss
+ start_code address above which program text can run
+ end_code address below which program text can run
+ start_stack address of the start of the stack
+ esp current value of ESP
+ eip current value of EIP
+ pending bitmap of pending signals (obsolete)
+ blocked bitmap of blocked signals (obsolete)
+ sigign bitmap of ignored signals (obsolete)
+ sigcatch bitmap of catched signals (obsolete)
+ wchan address where process went to sleep
+ 0 (place holder)
+ 0 (place holder)
+ exit_signal signal to send to parent thread on exit
+ task_cpu which CPU the task is scheduled on
+ rt_priority realtime priority
+ policy scheduling policy (man sched_setscheduler)
+ blkio_ticks time spent waiting for block IO
+..............................................................................
+
+
1.2 Kernel data
---------------
Similar to the process entries, the kernel data files give information about
the running kernel. The files used to obtain this information are contained in
-/proc and are listed in Table 1-3. Not all of these will be present in your
+/proc and are listed in Table 1-4. Not all of these will be present in your
system. It depends on the kernel configuration and the loaded modules, which
files are there, and which are missing.
-Table 1-3: Kernel info in /proc
+Table 1-4: Kernel info in /proc
..............................................................................
File Content
apm Advanced power management info
@@ -473,10 +525,10 @@ IDE devices:
More detailed information can be found in the controller specific
subdirectories. These are named ide0, ide1 and so on. Each of these
-directories contains the files shown in table 1-4.
+directories contains the files shown in table 1-5.
-Table 1-4: IDE controller info in /proc/ide/ide?
+Table 1-5: IDE controller info in /proc/ide/ide?
..............................................................................
File Content
channel IDE channel (0 or 1)
@@ -486,11 +538,11 @@ Table 1-4: IDE controller info in /proc/ide/ide?
..............................................................................
Each device connected to a controller has a separate subdirectory in the
-controllers directory. The files listed in table 1-5 are contained in these
+controllers directory. The files listed in table 1-6 are contained in these
directories.
-Table 1-5: IDE device information
+Table 1-6: IDE device information
..............................................................................
File Content
cache The cache
@@ -1014,6 +1066,13 @@ check the amount of free space (value is in seconds). Default settings are: 4,
resume it if we have a value of 3 or more percent; consider information about
the amount of free space valid for 30 seconds
+audit_argv_kb
+-------------
+
+The file contains a single value denoting the limit on the argv array size
+for execve (in KiB). This limit is only applied when system call auditing for
+execve is enabled, otherwise the value is ignored.
+
ctrl-alt-del
------------
@@ -1297,6 +1356,21 @@ nr_hugepages configures number of hugetlb page reserved for the system.
hugetlb_shm_group contains group id that is allowed to create SysV shared
memory segment using hugetlb page.
+hugepages_treat_as_movable
+--------------------------
+
+This parameter is only useful when kernelcore= is specified at boot time to
+create ZONE_MOVABLE for pages that may be reclaimed or migrated. Huge pages
+are not movable so are not normally allocated from ZONE_MOVABLE. A non-zero
+value written to hugepages_treat_as_movable allows huge pages to be allocated
+from ZONE_MOVABLE.
+
+Once enabled, the ZONE_MOVABLE is treated as an area of memory the huge
+pages pool can easily grow or shrink within. Assuming that applications are
+not running that mlock() a lot of memory, it is likely the huge pages pool
+can grow to the size of ZONE_MOVABLE by repeatedly entering the desired value
+into nr_hugepages and triggering page reclaim.
+
laptop_mode
-----------
@@ -2111,4 +2185,41 @@ those 64-bit counters, process A could see an intermediate result.
More information about this can be found within the taskstats documentation in
Documentation/accounting.
+2.15 /proc/<pid>/coredump_filter - Core dump filtering settings
+---------------------------------------------------------------
+When a process is dumped, all anonymous memory is written to a core file as
+long as the size of the core file isn't limited. But sometimes we don't want
+to dump some memory segments, for example, huge shared memory. Conversely,
+sometimes we want to save file-backed memory segments into a core file, not
+only the individual files.
+
+/proc/<pid>/coredump_filter allows you to customize which memory segments
+will be dumped when the <pid> process is dumped. coredump_filter is a bitmask
+of memory types. If a bit of the bitmask is set, memory segments of the
+corresponding memory type are dumped, otherwise they are not dumped.
+
+The following 4 memory types are supported:
+ - (bit 0) anonymous private memory
+ - (bit 1) anonymous shared memory
+ - (bit 2) file-backed private memory
+ - (bit 3) file-backed shared memory
+
+ Note that MMIO pages such as frame buffer are never dumped and vDSO pages
+ are always dumped regardless of the bitmask status.
+
+Default value of coredump_filter is 0x3; this means all anonymous memory
+segments are dumped.
+
+If you don't want to dump all shared memory segments attached to pid 1234,
+write 1 to the process's proc file.
+
+ $ echo 0x1 > /proc/1234/coredump_filter
+
+When a new process is created, the process inherits the bitmask status from its
+parent. It is useful to set up coredump_filter before the program runs.
+For example:
+
+ $ echo 0x7 > /proc/self/coredump_filter
+ $ ./some_program
+
------------------------------------------------------------------------------
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index a47cc819f37b..045f3e055a28 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -3,7 +3,7 @@
Original author: Richard Gooch <rgooch@atnf.csiro.au>
- Last updated on October 28, 2005
+ Last updated on June 24, 2007.
Copyright (C) 1999 Richard Gooch
Copyright (C) 2005 Pekka Enberg
@@ -107,7 +107,7 @@ file /proc/filesystems.
struct file_system_type
-----------------------
-This describes the filesystem. As of kernel 2.6.13, the following
+This describes the filesystem. As of kernel 2.6.22, the following
members are defined:
struct file_system_type {
@@ -119,6 +119,8 @@ struct file_system_type {
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
+ struct lock_class_key s_lock_key;
+ struct lock_class_key s_umount_key;
};
name: the name of the filesystem type, such as "ext2", "iso9660",
@@ -137,11 +139,12 @@ struct file_system_type {
next: for internal VFS use: you should initialize this to NULL
+ s_lock_key, s_umount_key: lockdep-specific
+
The get_sb() method has the following arguments:
- struct super_block *sb: the superblock structure. This is partially
- initialized by the VFS and the rest must be initialized by the
- get_sb() method
+ struct file_system_type *fs_type: decribes the filesystem, partly initialized
+ by the specific filesystem code
int flags: mount flags
@@ -150,12 +153,13 @@ The get_sb() method has the following arguments:
void *data: arbitrary mount options, usually comes as an ASCII
string
- int silent: whether or not to be silent on error
+ struct vfsmount *mnt: a vfs-internal representation of a mount point
The get_sb() method must determine if the block device specified
-in the superblock contains a filesystem of the type the method
-supports. On success the method returns the superblock pointer, on
-failure it returns NULL.
+in the dev_name and fs_type contains a filesystem of the type the method
+supports. If it succeeds in opening the named block device, it initializes a
+struct super_block descriptor for the filesystem contained by the block device.
+On failure it returns an error.
The most interesting member of the superblock structure that the
get_sb() method fills in is the "s_op" field. This is a pointer to
@@ -193,7 +197,7 @@ struct super_operations
-----------------------
This describes how the VFS can manipulate the superblock of your
-filesystem. As of kernel 2.6.13, the following members are defined:
+filesystem. As of kernel 2.6.22, the following members are defined:
struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
@@ -216,8 +220,6 @@ struct super_operations {
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
- void (*sync_inodes) (struct super_block *sb,
- struct writeback_control *wbc);
int (*show_options)(struct seq_file *, struct vfsmount *);
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
@@ -300,9 +302,6 @@ or bottom half).
umount_begin: called when the VFS is unmounting a filesystem.
- sync_inodes: called when the VFS is writing out dirty data associated with
- a superblock.
-
show_options: called by the VFS to show mount options for /proc/<pid>/mounts.
quota_read: called by the VFS to read from filesystem quota file.
@@ -324,7 +323,7 @@ struct inode_operations
-----------------------
This describes how the VFS can manipulate an inode in your
-filesystem. As of kernel 2.6.13, the following members are defined:
+filesystem. As of kernel 2.6.22, the following members are defined:
struct inode_operations {
int (*create) (struct inode *,struct dentry *,int, struct nameidata *);
@@ -348,6 +347,7 @@ struct inode_operations {
ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
+ void (*truncate_range)(struct inode *, loff_t, loff_t);
};
Again, all methods are called without any locks being held, unless
@@ -444,6 +444,9 @@ otherwise noted.
removexattr: called by the VFS to remove an extended attribute from
a file. This method is called by removexattr(2) system call.
+ truncate_range: a method provided by the underlying filesystem to truncate a
+ range of blocks , i.e. punch a hole somewhere in a file.
+
The Address Space Object
========================
@@ -522,7 +525,7 @@ struct address_space_operations
-------------------------------
This describes how the VFS can manipulate mapping of a file to page cache in
-your filesystem. As of kernel 2.6.16, the following members are defined:
+your filesystem. As of kernel 2.6.22, the following members are defined:
struct address_space_operations {
int (*writepage)(struct page *page, struct writeback_control *wbc);
@@ -543,6 +546,7 @@ struct address_space_operations {
int);
/* migrate the contents of a page to the specified target */
int (*migratepage) (struct page *, struct page *);
+ int (*launder_page) (struct page *);
};
writepage: called by the VM to write a dirty page to backing store.
@@ -689,6 +693,10 @@ struct address_space_operations {
transfer any private data across and update any references
that it has to the page.
+ launder_page: Called before freeing a page - it writes back the dirty page. To
+ prevent redirtying the page, it is kept locked during the whole
+ operation.
+
The File Object
===============
@@ -699,9 +707,10 @@ struct file_operations
----------------------
This describes how the VFS can manipulate an open file. As of kernel
-2.6.17, the following members are defined:
+2.6.22, the following members are defined:
struct file_operations {
+ struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
@@ -728,10 +737,8 @@ struct file_operations {
int (*check_flags)(int);
int (*dir_notify)(struct file *filp, unsigned long arg);
int (*flock) (struct file *, int, struct file_lock *);
- ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned
-int);
- ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned
-int);
+ ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int);
+ ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
};
Again, all methods are called without any locks being held, unless
diff --git a/Documentation/firmware_class/firmware_sample_firmware_class.c b/Documentation/firmware_class/firmware_sample_firmware_class.c
index 4994f1f28f8c..fba943aacf93 100644
--- a/Documentation/firmware_class/firmware_sample_firmware_class.c
+++ b/Documentation/firmware_class/firmware_sample_firmware_class.c
@@ -78,6 +78,7 @@ static CLASS_DEVICE_ATTR(loading, 0644,
firmware_loading_show, firmware_loading_store);
static ssize_t firmware_data_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
@@ -88,6 +89,7 @@ static ssize_t firmware_data_read(struct kobject *kobj,
return count;
}
static ssize_t firmware_data_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 36af58eba136..218a8650f48d 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -75,6 +75,9 @@ using the include file:
If you stick to this convention then it'll be easier for other developers to
see what your code is doing, and help maintain it.
+Note that these operations include I/O barriers on platforms which need to
+use them; drivers don't need to add them explicitly.
+
Identifying GPIOs
-----------------
diff --git a/Documentation/hrtimer/timer_stats.txt b/Documentation/hrtimer/timer_stats.txt
index 22b0814d0ad0..20d368c59814 100644
--- a/Documentation/hrtimer/timer_stats.txt
+++ b/Documentation/hrtimer/timer_stats.txt
@@ -67,3 +67,7 @@ executed on expiry.
Thomas, Ingo
+Added flag to indicate 'deferrable timer' in /proc/timer_stats. A deferrable
+timer will appear as follows
+ 10D, 1 swapper queue_delayed_work_on (delayed_work_timer_fn)
+
diff --git a/Documentation/hwmon/abituguru b/Documentation/hwmon/abituguru
index b2c0d61b39a2..87ffa0f5ec70 100644
--- a/Documentation/hwmon/abituguru
+++ b/Documentation/hwmon/abituguru
@@ -2,7 +2,7 @@ Kernel driver abituguru
=======================
Supported chips:
- * Abit uGuru revision 1-3 (Hardware Monitor part only)
+ * Abit uGuru revision 1 & 2 (Hardware Monitor part only)
Prefix: 'abituguru'
Addresses scanned: ISA 0x0E0
Datasheet: Not available, this driver is based on reverse engineering.
@@ -20,8 +20,8 @@ Supported chips:
uGuru 2.1.0.0 ~ 2.1.2.8 (AS8, AV8, AA8, AG8, AA8XE, AX8)
uGuru 2.2.0.0 ~ 2.2.0.6 (AA8 Fatal1ty)
uGuru 2.3.0.0 ~ 2.3.0.9 (AN8)
- uGuru 3.0.0.0 ~ 3.0.1.2 (AW8, AL8, NI8)
- uGuru 4.xxxxx? (AT8 32X) (2)
+ uGuru 3.0.0.0 ~ 3.0.x.x (AW8, AL8, AT8, NI8 SLI, AT8 32X, AN8 32X,
+ AW9D-MAX) (2)
1) For revisions 2 and 3 uGuru's the driver can autodetect the
sensortype (Volt or Temp) for bank1 sensors, for revision 1 uGuru's
this doesnot always work. For these uGuru's the autodection can
@@ -30,8 +30,9 @@ Supported chips:
bank1_types=1,1,0,0,0,0,0,2,0,0,0,0,2,0,0,1
You may also need to specify the fan_sensors option for these boards
fan_sensors=5
- 2) The current version of the abituguru driver is known to NOT work
- on these Motherboards
+ 2) There is a seperate abituguru3 driver for these motherboards,
+ the abituguru (without the 3 !) driver will not work on these
+ motherboards (and visa versa)!
Authors:
Hans de Goede <j.w.r.degoede@hhs.nl>,
@@ -43,8 +44,10 @@ Module Parameters
-----------------
* force: bool Force detection. Note this parameter only causes the
- detection to be skipped, if the uGuru can't be read
- the module initialization (insmod) will still fail.
+ detection to be skipped, and thus the insmod to
+ succeed. If the uGuru can't be read the actual hwmon
+ driver will not load and thus no hwmon device will get
+ registered.
* bank1_types: int[] Bank1 sensortype autodetection override:
-1 autodetect (default)
0 volt sensor
@@ -69,13 +72,15 @@ dmesg | grep abituguru
Description
-----------
-This driver supports the hardware monitoring features of the Abit uGuru chip
-found on Abit uGuru featuring motherboards (most modern Abit motherboards).
+This driver supports the hardware monitoring features of the first and
+second revision of the Abit uGuru chip found on Abit uGuru featuring
+motherboards (most modern Abit motherboards).
-The uGuru chip in reality is a Winbond W83L950D in disguise (despite Abit
-claiming it is "a new microprocessor designed by the ABIT Engineers").
-Unfortunatly this doesn't help since the W83L950D is a generic
-microcontroller with a custom Abit application running on it.
+The first and second revision of the uGuru chip in reality is a Winbond
+W83L950D in disguise (despite Abit claiming it is "a new microprocessor
+designed by the ABIT Engineers"). Unfortunatly this doesn't help since the
+W83L950D is a generic microcontroller with a custom Abit application running
+on it.
Despite Abit not releasing any information regarding the uGuru, Olle
Sandberg <ollebull@gmail.com> has managed to reverse engineer the sensor part
diff --git a/Documentation/hwmon/abituguru3 b/Documentation/hwmon/abituguru3
new file mode 100644
index 000000000000..fa598aac22fa
--- /dev/null
+++ b/Documentation/hwmon/abituguru3
@@ -0,0 +1,65 @@
+Kernel driver abituguru3
+========================
+
+Supported chips:
+ * Abit uGuru revision 3 (Hardware Monitor part, reading only)
+ Prefix: 'abituguru3'
+ Addresses scanned: ISA 0x0E0
+ Datasheet: Not available, this driver is based on reverse engineering.
+ Note:
+ The uGuru is a microcontroller with onboard firmware which programs
+ it to behave as a hwmon IC. There are many different revisions of the
+ firmware and thus effectivly many different revisions of the uGuru.
+ Below is an incomplete list with which revisions are used for which
+ Motherboards:
+ uGuru 1.00 ~ 1.24 (AI7, KV8-MAX3, AN7)
+ uGuru 2.0.0.0 ~ 2.0.4.2 (KV8-PRO)
+ uGuru 2.1.0.0 ~ 2.1.2.8 (AS8, AV8, AA8, AG8, AA8XE, AX8)
+ uGuru 2.3.0.0 ~ 2.3.0.9 (AN8)
+ uGuru 3.0.0.0 ~ 3.0.x.x (AW8, AL8, AT8, NI8 SLI, AT8 32X, AN8 32X,
+ AW9D-MAX)
+ The abituguru3 driver is only for revison 3.0.x.x motherboards,
+ this driver will not work on older motherboards. For older
+ motherboards use the abituguru (without the 3 !) driver.
+
+Authors:
+ Hans de Goede <j.w.r.degoede@hhs.nl>,
+ (Initial reverse engineering done by Louis Kruger)
+
+
+Module Parameters
+-----------------
+
+* force: bool Force detection. Note this parameter only causes the
+ detection to be skipped, and thus the insmod to
+ succeed. If the uGuru can't be read the actual hwmon
+ driver will not load and thus no hwmon device will get
+ registered.
+* verbose: bool Should the driver be verbose?
+ 0/off/false normal output
+ 1/on/true + verbose error reporting (default)
+ Default: 1 (the driver is still in the testing phase)
+
+Description
+-----------
+
+This driver supports the hardware monitoring features of the third revision of
+the Abit uGuru chip, found on recent Abit uGuru featuring motherboards.
+
+The 3rd revision of the uGuru chip in reality is a Winbond W83L951G.
+Unfortunatly this doesn't help since the W83L951G is a generic microcontroller
+with a custom Abit application running on it.
+
+Despite Abit not releasing any information regarding the uGuru revision 3,
+Louis Kruger has managed to reverse engineer the sensor part of the uGuru.
+Without his work this driver would not have been possible.
+
+Known Issues
+------------
+
+The voltage and frequency control parts of the Abit uGuru are not supported,
+neither is writing any of the sensor settings and writing / reading the
+fanspeed control registers (FanEQ)
+
+If you encounter any problems please mail me <j.w.r.degoede@hhs.nl> and
+include the output of: "dmesg | grep abituguru"
diff --git a/Documentation/hwmon/dme1737 b/Documentation/hwmon/dme1737
new file mode 100644
index 000000000000..1a0f3d64ab80
--- /dev/null
+++ b/Documentation/hwmon/dme1737
@@ -0,0 +1,257 @@
+Kernel driver dme1737
+=====================
+
+Supported chips:
+ * SMSC DME1737 and compatibles (like Asus A8000)
+ Prefix: 'dme1737'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: Provided by SMSC upon request and under NDA
+
+Authors:
+ Juerg Haefliger <juergh@gmail.com>
+
+
+Module Parameters
+-----------------
+
+* force_start: bool Enables the monitoring of voltage, fan and temp inputs
+ and PWM output control functions. Using this parameter
+ shouldn't be required since the BIOS usually takes care
+ of this.
+
+Note that there is no need to use this parameter if the driver loads without
+complaining. The driver will say so if it is necessary.
+
+
+Description
+-----------
+
+This driver implements support for the hardware monitoring capabilities of the
+SMSC DME1737 and Asus A8000 (which are the same) Super-I/O chips. This chip
+features monitoring of 3 temp sensors temp[1-3] (2 remote diodes and 1
+internal), 7 voltages in[0-6] (6 external and 1 internal) and 6 fan speeds
+fan[1-6]. Additionally, the chip implements 5 PWM outputs pwm[1-3,5-6] for
+controlling fan speeds both manually and automatically.
+
+Fan[3-6] and pwm[3,5-6] are optional features and their availability is
+dependent on the configuration of the chip. The driver will detect which
+features are present during initialization and create the sysfs attributes
+accordingly.
+
+
+Voltage Monitoring
+------------------
+
+The voltage inputs are sampled with 12-bit resolution and have internal
+scaling resistors. The values returned by the driver therefore reflect true
+millivolts and don't need scaling. The voltage inputs are mapped as follows
+(the last column indicates the input ranges):
+
+ in0: +5VTR (+5V standby) 0V - 6.64V
+ in1: Vccp (processor core) 0V - 3V
+ in2: VCC (internal +3.3V) 0V - 4.38V
+ in3: +5V 0V - 6.64V
+ in4: +12V 0V - 16V
+ in5: VTR (+3.3V standby) 0V - 4.38V
+ in6: Vbat (+3.0V) 0V - 4.38V
+
+Each voltage input has associated min and max limits which trigger an alarm
+when crossed.
+
+
+Temperature Monitoring
+----------------------
+
+Temperatures are measured with 12-bit resolution and reported in millidegree
+Celsius. The chip also features offsets for all 3 temperature inputs which -
+when programmed - get added to the input readings. The chip does all the
+scaling by itself and the driver therefore reports true temperatures that don't
+need any user-space adjustments. The temperature inputs are mapped as follows
+(the last column indicates the input ranges):
+
+ temp1: Remote diode 1 (3904 type) temperature -127C - +127C
+ temp2: DME1737 internal temperature -127C - +127C
+ temp3: Remote diode 2 (3904 type) temperature -127C - +127C
+
+Each temperature input has associated min and max limits which trigger an alarm
+when crossed. Additionally, each temperature input has a fault attribute that
+returns 1 when a faulty diode or an unconnected input is detected and 0
+otherwise.
+
+
+Fan Monitoring
+--------------
+
+Fan RPMs are measured with 16-bit resolution. The chip provides inputs for 6
+fan tachometers. All 6 inputs have an associated min limit which triggers an
+alarm when crossed. Fan inputs 1-4 provide type attributes that need to be set
+to the number of pulses per fan revolution that the connected tachometer
+generates. Supported values are 1, 2, and 4. Fan inputs 5-6 only support fans
+that generate 2 pulses per revolution. Fan inputs 5-6 also provide a max
+attribute that needs to be set to the maximum attainable RPM (fan at 100% duty-
+cycle) of the input. The chip adjusts the sampling rate based on this value.
+
+
+PWM Output Control
+------------------
+
+This chip features 5 PWM outputs. PWM outputs 1-3 are associated with fan
+inputs 1-3 and PWM outputs 5-6 are associated with fan inputs 5-6. PWM outputs
+1-3 can be configured to operate either in manual or automatic mode by setting
+the appropriate enable attribute accordingly. PWM outputs 5-6 can only operate
+in manual mode, their enable attributes are therefore read-only. When set to
+manual mode, the fan speed is set by writing the duty-cycle value to the
+appropriate PWM attribute. In automatic mode, the PWM attribute returns the
+current duty-cycle as set by the fan controller in the chip. All PWM outputs
+support the setting of the output frequency via the freq attribute.
+
+In automatic mode, the chip supports the setting of the PWM ramp rate which
+defines how fast the PWM output is adjusting to changes of the associated
+temperature input. Associating PWM outputs to temperature inputs is done via
+temperature zones. The chip features 3 zones whose assignments to temperature
+inputs is static and determined during initialization. These assignments can
+be retrieved via the zone[1-3]_auto_channels_temp attributes. Each PWM output
+is assigned to one (or hottest of multiple) temperature zone(s) through the
+pwm[1-3]_auto_channels_zone attributes. Each PWM output has 3 distinct output
+duty-cycles: full, low, and min. Full is internally hard-wired to 255 (100%)
+and low and min can be programmed via pwm[1-3]_auto_point1_pwm and
+pwm[1-3]_auto_pwm_min, respectively. The thermal thresholds of the zones are
+programmed via zone[1-3]_auto_point[1-3]_temp and
+zone[1-3]_auto_point1_temp_hyst:
+
+ pwm[1-3]_auto_point2_pwm full-speed duty-cycle (255, i.e., 100%)
+ pwm[1-3]_auto_point1_pwm low-speed duty-cycle
+ pwm[1-3]_auto_pwm_min min-speed duty-cycle
+
+ zone[1-3]_auto_point3_temp full-speed temp (all outputs)
+ zone[1-3]_auto_point2_temp full-speed temp
+ zone[1-3]_auto_point1_temp low-speed temp
+ zone[1-3]_auto_point1_temp_hyst min-speed temp
+
+The chip adjusts the output duty-cycle linearly in the range of auto_point1_pwm
+to auto_point2_pwm if the temperature of the associated zone is between
+auto_point1_temp and auto_point2_temp. If the temperature drops below the
+auto_point1_temp_hyst value, the output duty-cycle is set to the auto_pwm_min
+value which only supports two values: 0 or auto_point1_pwm. That means that the
+fan either turns completely off or keeps spinning with the low-speed
+duty-cycle. If any of the temperatures rise above the auto_point3_temp value,
+all PWM outputs are set to 100% duty-cycle.
+
+Following is another representation of how the chip sets the output duty-cycle
+based on the temperature of the associated thermal zone:
+
+ Duty-Cycle Duty-Cycle
+ Temperature Rising Temp Falling Temp
+ ----------- ----------- ------------
+ full-speed full-speed full-speed
+
+ < linearly adjusted duty-cycle >
+
+ low-speed low-speed low-speed
+ min-speed low-speed
+ min-speed min-speed min-speed
+ min-speed min-speed
+
+
+Sysfs Attributes
+----------------
+
+Following is a list of all sysfs attributes that the driver provides, their
+permissions and a short description:
+
+Name Perm Description
+---- ---- -----------
+cpu0_vid RO CPU core reference voltage in
+ millivolts.
+vrm RW Voltage regulator module version
+ number.
+
+in[0-6]_input RO Measured voltage in millivolts.
+in[0-6]_min RW Low limit for voltage input.
+in[0-6]_max RW High limit for voltage input.
+in[0-6]_alarm RO Voltage input alarm. Returns 1 if
+ voltage input is or went outside the
+ associated min-max range, 0 otherwise.
+
+temp[1-3]_input RO Measured temperature in millidegree
+ Celsius.
+temp[1-3]_min RW Low limit for temp input.
+temp[1-3]_max RW High limit for temp input.
+temp[1-3]_offset RW Offset for temp input. This value will
+ be added by the chip to the measured
+ temperature.
+temp[1-3]_alarm RO Alarm for temp input. Returns 1 if temp
+ input is or went outside the associated
+ min-max range, 0 otherwise.
+temp[1-3]_fault RO Temp input fault. Returns 1 if the chip
+ detects a faulty thermal diode or an
+ unconnected temp input, 0 otherwise.
+
+zone[1-3]_auto_channels_temp RO Temperature zone to temperature input
+ mapping. This attribute is a bitfield
+ and supports the following values:
+ 1: temp1
+ 2: temp2
+ 4: temp3
+zone[1-3]_auto_point1_temp_hyst RW Auto PWM temp point1 hysteresis. The
+ output of the corresponding PWM is set
+ to the pwm_auto_min value if the temp
+ falls below the auto_point1_temp_hyst
+ value.
+zone[1-3]_auto_point[1-3]_temp RW Auto PWM temp points. Auto_point1 is
+ the low-speed temp, auto_point2 is the
+ full-speed temp, and auto_point3 is the
+ temp at which all PWM outputs are set
+ to full-speed (100% duty-cycle).
+
+fan[1-6]_input RO Measured fan speed in RPM.
+fan[1-6]_min RW Low limit for fan input.
+fan[1-6]_alarm RO Alarm for fan input. Returns 1 if fan
+ input is or went below the associated
+ min value, 0 otherwise.
+fan[1-4]_type RW Type of attached fan. Expressed in
+ number of pulses per revolution that
+ the fan generates. Supported values are
+ 1, 2, and 4.
+fan[5-6]_max RW Max attainable RPM at 100% duty-cycle.
+ Required for chip to adjust the
+ sampling rate accordingly.
+
+pmw[1-3,5-6] RO/RW Duty-cycle of PWM output. Supported
+ values are 0-255 (0%-100%). Only
+ writeable if the associated PWM is in
+ manual mode.
+pwm[1-3]_enable RW Enable of PWM outputs 1-3. Supported
+ values are:
+ 0: turned off (output @ 100%)
+ 1: manual mode
+ 2: automatic mode
+pwm[5-6]_enable RO Enable of PWM outputs 5-6. Always
+ returns 1 since these 2 outputs are
+ hard-wired to manual mode.
+pmw[1-3,5-6]_freq RW Frequency of PWM output. Supported
+ values are in the range 11Hz-30000Hz
+ (default is 25000Hz).
+pmw[1-3]_ramp_rate RW Ramp rate of PWM output. Determines how
+ fast the PWM duty-cycle will change
+ when the PWM is in automatic mode.
+ Expressed in ms per PWM step. Supported
+ values are in the range 0ms-206ms
+ (default is 0, which means the duty-
+ cycle changes instantly).
+pwm[1-3]_auto_channels_zone RW PWM output to temperature zone mapping.
+ This attribute is a bitfield and
+ supports the following values:
+ 1: zone1
+ 2: zone2
+ 4: zone3
+ 6: highest of zone[2-3]
+ 7: highest of zone[1-3]
+pwm[1-3]_auto_pwm_min RW Auto PWM min pwm. Minimum PWM duty-
+ cycle. Supported values are 0 or
+ auto_point1_pwm.
+pwm[1-3]_auto_point1_pwm RW Auto PWM pwm point. Auto_point1 is the
+ low-speed duty-cycle.
+pwm[1-3]_auto_point2_pwm RO Auto PWM pwm point. Auto_point2 is the
+ full-speed duty-cycle which is hard-
+ wired to 255 (100% duty-cycle).
diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f
index bfd0f154959c..94e0d2cbd3d2 100644
--- a/Documentation/hwmon/f71805f
+++ b/Documentation/hwmon/f71805f
@@ -5,11 +5,11 @@ Supported chips:
* Fintek F71805F/FG
Prefix: 'f71805f'
Addresses scanned: none, address read from Super I/O config space
- Datasheet: Provided by Fintek on request
+ Datasheet: Available from the Fintek website
* Fintek F71872F/FG
Prefix: 'f71872f'
Addresses scanned: none, address read from Super I/O config space
- Datasheet: Provided by Fintek on request
+ Datasheet: Available from the Fintek website
Author: Jean Delvare <khali@linux-fr.org>
@@ -128,7 +128,9 @@ it.
When the PWM method is used, you can select the operating frequency,
from 187.5 kHz (default) to 31 Hz. The best frequency depends on the
fan model. As a rule of thumb, lower frequencies seem to give better
-control, but may generate annoying high-pitch noise. Fintek recommends
+control, but may generate annoying high-pitch noise. So a frequency just
+above the audible range, such as 25 kHz, may be a good choice; if this
+doesn't give you good linear control, try reducing it. Fintek recommends
not going below 1 kHz, as the fan tachometers get confused by lower
frequencies as well.
@@ -136,16 +138,23 @@ When the DC method is used, Fintek recommends not going below 5 V, which
corresponds to a pwm value of 106 for the driver. The driver doesn't
enforce this limit though.
-Three different fan control modes are supported:
+Three different fan control modes are supported; the mode number is written
+to the pwm<n>_enable file.
-* Manual mode
- You ask for a specific PWM duty cycle or DC voltage.
+* 1: Manual mode
+ You ask for a specific PWM duty cycle or DC voltage by writing to the
+ pwm<n> file.
-* Fan speed mode
- You ask for a specific fan speed. This mode assumes that pwm1
- corresponds to fan1, pwm2 to fan2 and pwm3 to fan3.
+* 2: Temperature mode
+ You define 3 temperature/fan speed trip points using the
+ pwm<n>_auto_point<m>_temp and _fan files. These define a staircase
+ relationship between temperature and fan speed with two additional points
+ interpolated between the values that you define. When the temperature
+ is below auto_point1_temp the fan is switched off.
-* Temperature mode
- You define 3 temperature/fan speed trip points, and the fan speed is
- adjusted depending on the measured temperature, using interpolation.
- This mode is not yet supported by the driver.
+* 3: Fan speed mode
+ You ask for a specific fan speed by writing to the fan<n>_target file.
+
+Both of the automatic modes require that pwm1 corresponds to fan1, pwm2 to
+fan2 and pwm3 to fan3. Temperature mode also requires that temp1 corresponds
+to pwm1 and fan1, etc.
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index c0528d6f9ace..81ecc7e41c50 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -12,11 +12,12 @@ Supported chips:
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/
- * IT8716F
+ * IT8716F/IT8726F
Prefix: 'it8716'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP
+ http://www.ite.com.tw/product_info/file/pc/IT8726F_V0.3.pdf
* IT8718F
Prefix: 'it8718'
Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -68,7 +69,7 @@ Description
-----------
This driver implements support for the IT8705F, IT8712F, IT8716F,
-IT8718F and SiS950 chips.
+IT8718F, IT8726F and SiS950 chips.
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
joysticks and other miscellaneous stuff. For hardware monitoring, they
@@ -97,6 +98,10 @@ clock divider mess) but not compatible with the older chips and
revisions. For now, the driver only uses the 16-bit mode on the
IT8716F and IT8718F.
+The IT8726F is just bit enhanced IT8716F with additional hardware
+for AMD power sequencing. Therefore the chip will appear as IT8716F
+to userspace applications.
+
Temperatures are measured in degrees Celsius. An alarm is triggered once
when the Overtemperature Shutdown limit is crossed.
diff --git a/Documentation/hwmon/lm90 b/Documentation/hwmon/lm90
index 438cb24cee5b..aa4a0ec20081 100644
--- a/Documentation/hwmon/lm90
+++ b/Documentation/hwmon/lm90
@@ -48,6 +48,18 @@ Supported chips:
Addresses scanned: I2C 0x4c, 0x4d (unsupported 0x4e)
Datasheet: Publicly available at the Maxim website
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2578
+ * Maxim MAX6680
+ Prefix: 'max6680'
+ Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+ 0x4c, 0x4d and 0x4e
+ Datasheet: Publicly available at the Maxim website
+ http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
+ * Maxim MAX6681
+ Prefix: 'max6680'
+ Addresses scanned: I2C 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+ 0x4c, 0x4d and 0x4e
+ Datasheet: Publicly available at the Maxim website
+ http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
Author: Jean Delvare <khali@linux-fr.org>
@@ -59,11 +71,15 @@ Description
The LM90 is a digital temperature sensor. It senses its own temperature as
well as the temperature of up to one external diode. It is compatible
with many other devices such as the LM86, the LM89, the LM99, the ADM1032,
-the MAX6657, MAX6658 and the MAX6659 all of which are supported by this driver.
-Note that there is no easy way to differentiate between the last three
-variants. The extra address and features of the MAX6659 are not supported by
-this driver. Additionally, the ADT7461 is supported if found in ADM1032
-compatibility mode.
+the MAX6657, MAX6658, MAX6659, MAX6680 and the MAX6681 all of which are
+supported by this driver.
+
+Note that there is no easy way to differentiate between the MAX6657,
+MAX6658 and MAX6659 variants. The extra address and features of the
+MAX6659 are not supported by this driver. The MAX6680 and MAX6681 only
+differ in their pinout, therefore they obviously can't (and don't need to)
+be distinguished. Additionally, the ADT7461 is supported if found in
+ADM1032 compatibility mode.
The specificity of this family of chipsets over the ADM1021/LM84
family is that it features critical limits with hysteresis, and an
@@ -93,18 +109,22 @@ ADM1032:
* ALERT is triggered by open remote sensor.
* SMBus PEC support for Write Byte and Receive Byte transactions.
-ADT7461
+ADT7461:
* Extended temperature range (breaks compatibility)
* Lower resolution for remote temperature
MAX6657 and MAX6658:
* Remote sensor type selection
-MAX6659
+MAX6659:
* Selectable address
* Second critical temperature limit
* Remote sensor type selection
+MAX6680 and MAX6681:
+ * Selectable address
+ * Remote sensor type selection
+
All temperature values are given in degrees Celsius. Resolution
is 1.0 degree for the local temperature, 0.125 degree for the remote
temperature.
@@ -141,7 +161,7 @@ SMBus Read Byte, and PEC will work properly.
Additionally, the ADM1032 doesn't support SMBus Send Byte with PEC.
Instead, it will try to write the PEC value to the register (because the
SMBus Send Byte transaction with PEC is similar to a Write Byte transaction
-without PEC), which is not what we want. Thus, PEC is explicitely disabled
+without PEC), which is not what we want. Thus, PEC is explicitly disabled
on SMBus Send Byte transactions in the lm90 driver.
PEC on byte data transactions represents a significant increase in bandwidth
diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93
new file mode 100644
index 000000000000..4e4a1dc1d2da
--- /dev/null
+++ b/Documentation/hwmon/lm93
@@ -0,0 +1,412 @@
+Kernel driver lm93
+==================
+
+Supported chips:
+ * National Semiconductor LM93
+ Prefix 'lm93'
+ Addresses scanned: I2C 0x2c-0x2e
+ Datasheet: http://www.national.com/ds.cgi/LM/LM93.pdf
+
+Author:
+ Mark M. Hoffman <mhoffman@lightlink.com>
+ Ported to 2.6 by Eric J. Bowersox <ericb@aspsys.com>
+ Adapted to 2.6.20 by Carsten Emde <ce@osadl.org>
+ Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+
+Module Parameters
+-----------------
+
+(specific to LM93)
+* init: integer
+ Set to non-zero to force some initializations (default is 0).
+* disable_block: integer
+ A "0" allows SMBus block data transactions if the host supports them. A "1"
+ disables SMBus block data transactions. The default is 0.
+* vccp_limit_type: integer array (2)
+ Configures in7 and in8 limit type, where 0 means absolute and non-zero
+ means relative. "Relative" here refers to "Dynamic Vccp Monitoring using
+ VID" from the datasheet. It greatly simplifies the interface to allow
+ only one set of limits (absolute or relative) to be in operation at a
+ time (even though the hardware is capable of enabling both). There's
+ not a compelling use case for enabling both at once, anyway. The default
+ is "0,0".
+* vid_agtl: integer
+ A "0" configures the VID pins for V(ih) = 2.1V min, V(il) = 0.8V max.
+ A "1" configures the VID pins for V(ih) = 0.8V min, V(il) = 0.4V max.
+ (The latter setting is referred to as AGTL+ Compatible in the datasheet.)
+ I.e. this parameter controls the VID pin input thresholds; if your VID
+ inputs are not working, try changing this. The default value is "0".
+
+(common among sensor drivers)
+* force: short array (min = 1, max = 48)
+ List of adapter,address pairs to assume to be present. Autodetection
+ of the target device will still be attempted. Use one of the more
+ specific force directives below if this doesn't detect the device.
+* force_lm93: short array (min = 1, max = 48)
+ List of adapter,address pairs which are unquestionably assumed to contain
+ a 'lm93' chip
+* ignore: short array (min = 1, max = 48)
+ List of adapter,address pairs not to scan
+* ignore_range: short array (min = 1, max = 48)
+ List of adapter,start-addr,end-addr triples not to scan
+* probe: short array (min = 1, max = 48)
+ List of adapter,address pairs to scan additionally
+* probe_range: short array (min = 1, max = 48)
+ List of adapter,start-addr,end-addr triples to scan additionally
+
+
+Hardware Description
+--------------------
+
+(from the datasheet)
+
+The LM93, hardware monitor, has a two wire digital interface compatible with
+SMBus 2.0. Using an 8-bit ADC, the LM93 measures the temperature of two remote
+diode connected transistors as well as its own die and 16 power supply
+voltages. To set fan speed, the LM93 has two PWM outputs that are each
+controlled by up to four temperature zones. The fancontrol algorithm is lookup
+table based. The LM93 includes a digital filter that can be invoked to smooth
+temperature readings for better control of fan speed. The LM93 has four
+tachometer inputs to measure fan speed. Limit and status registers for all
+measured values are included. The LM93 builds upon the functionality of
+previous motherboard management ASICs and uses some of the LM85 s features
+(i.e. smart tachometer mode). It also adds measurement and control support
+for dynamic Vccp monitoring and PROCHOT. It is designed to monitor a dual
+processor Xeon class motherboard with a minimum of external components.
+
+
+Driver Description
+------------------
+
+This driver implements support for the National Semiconductor LM93.
+
+
+User Interface
+--------------
+
+#PROCHOT:
+
+The LM93 can monitor two #PROCHOT signals. The results are found in the
+sysfs files prochot1, prochot2, prochot1_avg, prochot2_avg, prochot1_max,
+and prochot2_max. prochot1_max and prochot2_max contain the user limits
+for #PROCHOT1 and #PROCHOT2, respectively. prochot1 and prochot2 contain
+the current readings for the most recent complete time interval. The
+value of prochot1_avg and prochot2_avg is something like a 2 period
+exponential moving average (but not quite - check the datasheet). Note
+that this third value is calculated by the chip itself. All values range
+from 0-255 where 0 indicates no throttling, and 255 indicates > 99.6%.
+
+The monitoring intervals for the two #PROCHOT signals is also configurable.
+These intervals can be found in the sysfs files prochot1_interval and
+prochot2_interval. The values in these files specify the intervals for
+#P1_PROCHOT and #P2_PROCHOT, respectively. Selecting a value not in this
+list will cause the driver to use the next largest interval. The available
+intervals are:
+
+#PROCHOT intervals: 0.73, 1.46, 2.9, 5.8, 11.7, 23.3, 46.6, 93.2, 186, 372
+
+It is possible to configure the LM93 to logically short the two #PROCHOT
+signals. I.e. when #P1_PROCHOT is asserted, the LM93 will automatically
+assert #P2_PROCHOT, and vice-versa. This mode is enabled by writing a
+non-zero integer to the sysfs file prochot_short.
+
+The LM93 can also override the #PROCHOT pins by driving a PWM signal onto
+one or both of them. When overridden, the signal has a period of 3.56 mS,
+a minimum pulse width of 5 clocks (at 22.5kHz => 6.25% duty cycle), and
+a maximum pulse width of 80 clocks (at 22.5kHz => 99.88% duty cycle).
+
+The sysfs files prochot1_override and prochot2_override contain boolean
+intgers which enable or disable the override function for #P1_PROCHOT and
+#P2_PROCHOT, respectively. The sysfs file prochot_override_duty_cycle
+contains a value controlling the duty cycle for the PWM signal used when
+the override function is enabled. This value ranges from 0 to 15, with 0
+indicating minimum duty cycle and 15 indicating maximum.
+
+#VRD_HOT:
+
+The LM93 can monitor two #VRD_HOT signals. The results are found in the
+sysfs files vrdhot1 and vrdhot2. There is one value per file: a boolean for
+which 1 indicates #VRD_HOT is asserted and 0 indicates it is negated. These
+files are read-only.
+
+Smart Tach Mode:
+
+(from the datasheet)
+
+ If a fan is driven using a low-side drive PWM, the tachometer
+ output of the fan is corrupted. The LM93 includes smart tachometer
+ circuitry that allows an accurate tachometer reading to be
+ achieved despite the signal corruption. In smart tach mode all
+ four signals are measured within 4 seconds.
+
+Smart tach mode is enabled by the driver by writing 1 or 2 (associating the
+the fan tachometer with a pwm) to the sysfs file fan<n>_smart_tach. A zero
+will disable the function for that fan. Note that Smart tach mode cannot be
+enabled if the PWM output frequency is 22500 Hz (see below).
+
+Manual PWM:
+
+The LM93 has a fixed or override mode for the two PWM outputs (although, there
+are still some conditions that will override even this mode - see section
+15.10.6 of the datasheet for details.) The sysfs files pwm1_override
+and pwm2_override are used to enable this mode; each is a boolean integer
+where 0 disables and 1 enables the manual control mode. The sysfs files pwm1
+and pwm2 are used to set the manual duty cycle; each is an integer (0-255)
+where 0 is 0% duty cycle, and 255 is 100%. Note that the duty cycle values
+are constrained by the hardware. Selecting a value which is not available
+will cause the driver to use the next largest value. Also note: when manual
+PWM mode is disabled, the value of pwm1 and pwm2 indicates the current duty
+cycle chosen by the h/w.
+
+PWM Output Frequency:
+
+The LM93 supports several different frequencies for the PWM output channels.
+The sysfs files pwm1_freq and pwm2_freq are used to select the frequency. The
+frequency values are constrained by the hardware. Selecting a value which is
+not available will cause the driver to use the next largest value. Also note
+that this parameter has implications for the Smart Tach Mode (see above).
+
+PWM Output Frequencies: 12, 36, 48, 60, 72, 84, 96, 22500 (h/w default)
+
+Automatic PWM:
+
+The LM93 is capable of complex automatic fan control, with many different
+points of configuration. To start, each PWM output can be bound to any
+combination of eight control sources. The final PWM is the largest of all
+individual control sources to which the PWM output is bound.
+
+The eight control sources are: temp1-temp4 (aka "zones" in the datasheet),
+#PROCHOT 1 & 2, and #VRDHOT 1 & 2. The bindings are expressed as a bitmask
+in the sysfs files pwm<n>_auto_channels, where a "1" enables the binding, and
+ a "0" disables it. The h/w default is 0x0f (all temperatures bound).
+
+ 0x01 - Temp 1
+ 0x02 - Temp 2
+ 0x04 - Temp 3
+ 0x08 - Temp 4
+ 0x10 - #PROCHOT 1
+ 0x20 - #PROCHOT 2
+ 0x40 - #VRDHOT 1
+ 0x80 - #VRDHOT 2
+
+The function y = f(x) takes a source temperature x to a PWM output y. This
+function of the LM93 is derived from a base temperature and a table of 12
+temperature offsets. The base temperature is expressed in degrees C in the
+sysfs files temp<n>_auto_base. The offsets are expressed in cumulative
+degrees C, with the value of offset <i> for temperature value <n> being
+contained in the file temp<n>_auto_offset<i>. E.g. if the base temperature
+is 40C:
+
+ offset # temp<n>_auto_offset<i> range pwm
+ 1 0 - 25.00%
+ 2 0 - 28.57%
+ 3 1 40C - 41C 32.14%
+ 4 1 41C - 42C 35.71%
+ 5 2 42C - 44C 39.29%
+ 6 2 44C - 46C 42.86%
+ 7 2 48C - 50C 46.43%
+ 8 2 50C - 52C 50.00%
+ 9 2 52C - 54C 53.57%
+ 10 2 54C - 56C 57.14%
+ 11 2 56C - 58C 71.43%
+ 12 2 58C - 60C 85.71%
+ > 60C 100.00%
+
+Valid offsets are in the range 0C <= x <= 7.5C in 0.5C increments.
+
+There is an independent base temperature for each temperature channel. Note,
+however, there are only two tables of offsets: one each for temp[12] and
+temp[34]. Therefore, any change to e.g. temp1_auto_offset<i> will also
+affect temp2_auto_offset<i>.
+
+The LM93 can also apply hysteresis to the offset table, to prevent unwanted
+oscillation between two steps in the offsets table. These values are found in
+the sysfs files temp<n>_auto_offset_hyst. The value in this file has the
+same representation as in temp<n>_auto_offset<i>.
+
+If a temperature reading falls below the base value for that channel, the LM93
+will use the minimum PWM value. These values are found in the sysfs files
+temp<n>_auto_pwm_min. Note, there are only two minimums: one each for temp[12]
+and temp[34]. Therefore, any change to e.g. temp1_auto_pwm_min will also
+affect temp2_auto_pwm_min.
+
+PWM Spin-Up Cycle:
+
+A spin-up cycle occurs when a PWM output is commanded from 0% duty cycle to
+some value > 0%. The LM93 supports a minimum duty cycle during spin-up. These
+values are found in the sysfs files pwm<n>_auto_spinup_min. The value in this
+file has the same representation as other PWM duty cycle values. The
+duration of the spin-up cycle is also configurable. These values are found in
+the sysfs files pwm<n>_auto_spinup_time. The value in this file is
+the spin-up time in seconds. The available spin-up times are constrained by
+the hardware. Selecting a value which is not available will cause the driver
+to use the next largest value.
+
+Spin-up Durations: 0 (disabled, h/w default), 0.1, 0.25, 0.4, 0.7, 1.0,
+ 2.0, 4.0
+
+#PROCHOT and #VRDHOT PWM Ramping:
+
+If the #PROCHOT or #VRDHOT signals are asserted while bound to a PWM output
+channel, the LM93 will ramp the PWM output up to 100% duty cycle in discrete
+steps. The duration of each step is configurable. There are two files, with
+one value each in seconds: pwm_auto_prochot_ramp and pwm_auto_vrdhot_ramp.
+The available ramp times are constrained by the hardware. Selecting a value
+which is not available will cause the driver to use the next largest value.
+
+Ramp Times: 0 (disabled, h/w default) to 0.75 in 0.05 second intervals
+
+Fan Boost:
+
+For each temperature channel, there is a boost temperature: if the channel
+exceeds this limit, the LM93 will immediately drive both PWM outputs to 100%.
+This limit is expressed in degrees C in the sysfs files temp<n>_auto_boost.
+There is also a hysteresis temperature for this function: after the boost
+limit is reached, the temperature channel must drop below this value before
+the boost function is disabled. This temperature is also expressed in degrees
+C in the sysfs files temp<n>_auto_boost_hyst.
+
+GPIO Pins:
+
+The LM93 can monitor the logic level of four dedicated GPIO pins as well as the
+four tach input pins. GPIO0-GPIO3 correspond to (fan) tach 1-4, respectively.
+All eight GPIOs are read by reading the bitmask in the sysfs file gpio. The
+LSB is GPIO0, and the MSB is GPIO7.
+
+
+LM93 Unique sysfs Files
+-----------------------
+
+ file description
+ -------------------------------------------------------------
+
+ prochot<n> current #PROCHOT %
+
+ prochot<n>_avg moving average #PROCHOT %
+
+ prochot<n>_max limit #PROCHOT %
+
+ prochot_short enable or disable logical #PROCHOT pin short
+
+ prochot<n>_override force #PROCHOT assertion as PWM
+
+ prochot_override_duty_cycle
+ duty cycle for the PWM signal used when
+ #PROCHOT is overridden
+
+ prochot<n>_interval #PROCHOT PWM sampling interval
+
+ vrdhot<n> 0 means negated, 1 means asserted
+
+ fan<n>_smart_tach enable or disable smart tach mode
+
+ pwm<n>_auto_channels select control sources for PWM outputs
+
+ pwm<n>_auto_spinup_min minimum duty cycle during spin-up
+
+ pwm<n>_auto_spinup_time duration of spin-up
+
+ pwm_auto_prochot_ramp ramp time per step when #PROCHOT asserted
+
+ pwm_auto_vrdhot_ramp ramp time per step when #VRDHOT asserted
+
+ temp<n>_auto_base temperature channel base
+
+ temp<n>_auto_offset[1-12]
+ temperature channel offsets
+
+ temp<n>_auto_offset_hyst
+ temperature channel offset hysteresis
+
+ temp<n>_auto_boost temperature channel boost (PWMs to 100%) limit
+
+ temp<n>_auto_boost_hyst temperature channel boost hysteresis
+
+ gpio input state of 8 GPIO pins; read-only
+
+
+Sample Configuration File
+-------------------------
+
+Here is a sample LM93 chip config for sensors.conf:
+
+---------- cut here ----------
+chip "lm93-*"
+
+# VOLTAGE INPUTS
+
+ # labels and scaling based on datasheet recommendations
+ label in1 "+12V1"
+ compute in1 @ * 12.945, @ / 12.945
+ set in1_min 12 * 0.90
+ set in1_max 12 * 1.10
+
+ label in2 "+12V2"
+ compute in2 @ * 12.945, @ / 12.945
+ set in2_min 12 * 0.90
+ set in2_max 12 * 1.10
+
+ label in3 "+12V3"
+ compute in3 @ * 12.945, @ / 12.945
+ set in3_min 12 * 0.90
+ set in3_max 12 * 1.10
+
+ label in4 "FSB_Vtt"
+
+ label in5 "3GIO"
+
+ label in6 "ICH_Core"
+
+ label in7 "Vccp1"
+
+ label in8 "Vccp2"
+
+ label in9 "+3.3V"
+ set in9_min 3.3 * 0.90
+ set in9_max 3.3 * 1.10
+
+ label in10 "+5V"
+ set in10_min 5.0 * 0.90
+ set in10_max 5.0 * 1.10
+
+ label in11 "SCSI_Core"
+
+ label in12 "Mem_Core"
+
+ label in13 "Mem_Vtt"
+
+ label in14 "Gbit_Core"
+
+ # Assuming R1/R2 = 4.1143, and 3.3V reference
+ # -12V = (4.1143 + 1) * (@ - 3.3) + 3.3
+ label in15 "-12V"
+ compute in15 @ * 5.1143 - 13.57719, (@ + 13.57719) / 5.1143
+ set in15_min -12 * 0.90
+ set in15_max -12 * 1.10
+
+ label in16 "+3.3VSB"
+ set in16_min 3.3 * 0.90
+ set in16_max 3.3 * 1.10
+
+# TEMPERATURE INPUTS
+
+ label temp1 "CPU1"
+ label temp2 "CPU2"
+ label temp3 "LM93"
+
+# TACHOMETER INPUTS
+
+ label fan1 "Fan1"
+ set fan1_min 3000
+ label fan2 "Fan2"
+ set fan2_min 3000
+ label fan3 "Fan3"
+ set fan3_min 3000
+ label fan4 "Fan4"
+ set fan4_min 3000
+
+# PWM OUTPUTS
+
+ label pwm1 "CPU1"
+ label pwm2 "CPU2"
+
diff --git a/Documentation/hwmon/smsc47b397 b/Documentation/hwmon/smsc47b397
index 20682f15ae41..3a43b6948924 100644
--- a/Documentation/hwmon/smsc47b397
+++ b/Documentation/hwmon/smsc47b397
@@ -4,6 +4,7 @@ Kernel driver smsc47b397
Supported chips:
* SMSC LPC47B397-NC
* SMSC SCH5307-NS
+ * SMSC SCH5317
Prefix: 'smsc47b397'
Addresses scanned: none, address read from Super I/O config space
Datasheet: In this file
@@ -18,8 +19,8 @@ The following specification describes the SMSC LPC47B397-NC[1] sensor chip
provided by Craig Kelly (In-Store Broadcast Network) and edited/corrected
by Mark M. Hoffman <mhoffman@lightlink.com>.
-[1] And SMSC SCH5307-NS, which has a different device ID but is otherwise
-compatible.
+[1] And SMSC SCH5307-NS and SCH5317, which have different device IDs but are
+otherwise compatible.
* * * * *
@@ -131,7 +132,7 @@ OUT DX,AL
The registers of interest for identifying the SIO on the dc7100 are Device ID
(0x20) and Device Rev (0x21).
-The Device ID will read 0x6F (for SCH5307-NS, 0x81)
+The Device ID will read 0x6F (0x81 for SCH5307-NS, and 0x85 for SCH5317)
The Device Rev currently reads 0x01
Obtaining the HWM Base Address.
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface
index a9a18ad0d17a..b3a9e1b9dbda 100644
--- a/Documentation/hwmon/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
@@ -172,11 +172,10 @@ pwm[1-*] Pulse width modulation fan control.
255 is max or 100%.
pwm[1-*]_enable
- Switch PWM on and off.
- Not always present even if pwmN is.
- 0: turn off
- 1: turn on in manual mode
- 2+: turn on in automatic mode
+ Fan speed control method:
+ 0: no fan speed control (i.e. fan at full speed)
+ 1: manual fan speed control enabled (using pwm[1-*])
+ 2+: automatic fan speed control enabled
Check individual chip documentation files for automatic mode
details.
RW
@@ -343,9 +342,9 @@ to notify open diodes, unconnected fans etc. where the hardware
supports it. When this boolean has value 1, the measurement for that
channel should not be trusted.
-in[0-*]_input_fault
-fan[1-*]_input_fault
-temp[1-*]_input_fault
+in[0-*]_fault
+fan[1-*]_fault
+temp[1-*]_fault
Input fault condition
0: no fault occured
1: fault condition
diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
index 030fac6cec7a..ccc2bcb61068 100644
--- a/Documentation/hwmon/w83627ehf
+++ b/Documentation/hwmon/w83627ehf
@@ -22,9 +22,9 @@ This driver implements support for the Winbond W83627EHF, W83627EHG, and
W83627DHG super I/O chips. We will refer to them collectively as Winbond chips.
The chips implement three temperature sensors, five fan rotation
-speed sensors, ten analog voltage sensors (only nine for the 627DHG), alarms
-with beep warnings (control unimplemented), and some automatic fan regulation
-strategies (plus manual fan control mode).
+speed sensors, ten analog voltage sensors (only nine for the 627DHG), one
+VID (6 pins), alarms with beep warnings (control unimplemented), and
+some automatic fan regulation strategies (plus manual fan control mode).
Temperatures are measured in degrees Celsius and measurement resolution is 1
degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index c34f0db78a30..fe6406f2f9a6 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -5,8 +5,8 @@ Supported adapters:
'810' and '810E' chipsets)
* Intel 82801BA (ICH2 - part of the '815E' chipset)
* Intel 82801CA/CAM (ICH3)
- * Intel 82801DB (ICH4) (HW PEC supported, 32 byte buffer not supported)
- * Intel 82801EB/ER (ICH5) (HW PEC supported, 32 byte buffer not supported)
+ * Intel 82801DB (ICH4) (HW PEC supported)
+ * Intel 82801EB/ER (ICH5) (HW PEC supported)
* Intel 6300ESB
* Intel 82801FB/FR/FW/FRW (ICH6)
* Intel 82801G (ICH7)
diff --git a/Documentation/i2c/busses/i2c-piix4 b/Documentation/i2c/busses/i2c-piix4
index 7cbe43fa2701..fa0c786a8bf5 100644
--- a/Documentation/i2c/busses/i2c-piix4
+++ b/Documentation/i2c/busses/i2c-piix4
@@ -6,7 +6,7 @@ Supported adapters:
Datasheet: Publicly available at the Intel website
* ServerWorks OSB4, CSB5, CSB6 and HT-1000 southbridges
Datasheet: Only available via NDA from ServerWorks
- * ATI IXP200, IXP300, IXP400 and SB600 southbridges
+ * ATI IXP200, IXP300, IXP400, SB600 and SB700 southbridges
Datasheet: Not publicly available
* Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
Datasheet: Publicly available at the SMSC website http://www.smsc.com
diff --git a/Documentation/i2c/busses/i2c-taos-evm b/Documentation/i2c/busses/i2c-taos-evm
new file mode 100644
index 000000000000..9146e33be6dd
--- /dev/null
+++ b/Documentation/i2c/busses/i2c-taos-evm
@@ -0,0 +1,46 @@
+Kernel driver i2c-taos-evm
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+This is a driver for the evaluation modules for TAOS I2C/SMBus chips.
+The modules include an SMBus master with limited capabilities, which can
+be controlled over the serial port. Virtually all evaluation modules
+are supported, but a few lines of code need to be added for each new
+module to instantiate the right I2C chip on the bus. Obviously, a driver
+for the chip in question is also needed.
+
+Currently supported devices are:
+
+* TAOS TSL2550 EVM
+
+For addtional information on TAOS products, please see
+ http://www.taosinc.com/
+
+
+Using this driver
+-----------------
+
+In order to use this driver, you'll need the serport driver, and the
+inputattach tool, which is part of the input-utils package. The following
+commands will tell the kernel that you have a TAOS EVM on the first
+serial port:
+
+# modprobe serport
+# inputattach --taos-evm /dev/ttyS0
+
+
+Technical details
+-----------------
+
+Only 4 SMBus transaction types are supported by the TAOS evaluation
+modules:
+* Receive Byte
+* Send Byte
+* Read Byte
+* Write Byte
+
+The communication protocol is text-based and pretty simple. It is
+described in a PDF document on the CD which comes with the evaluation
+module. The communication is rather slow, because the serial port has
+to operate at 1200 bps. However, I don't think this is a big concern in
+practice, as these modules are meant for evaluation and testing only.
diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875
index 96fec562a8e9..a0cd8af2f408 100644
--- a/Documentation/i2c/chips/max6875
+++ b/Documentation/i2c/chips/max6875
@@ -99,7 +99,7 @@ And then read the data
or
- count = i2c_smbus_read_i2c_block_data(fd, 0x84, buffer);
+ count = i2c_smbus_read_i2c_block_data(fd, 0x84, 16, buffer);
The block read should read 16 bytes.
0x84 is the block read command.
diff --git a/Documentation/i2c/chips/x1205 b/Documentation/i2c/chips/x1205
deleted file mode 100644
index 09407c991fe5..000000000000
--- a/Documentation/i2c/chips/x1205
+++ /dev/null
@@ -1,38 +0,0 @@
-Kernel driver x1205
-===================
-
-Supported chips:
- * Xicor X1205 RTC
- Prefix: 'x1205'
- Addresses scanned: none
- Datasheet: http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
-
-Authors:
- Karen Spearel <kas11@tampabay.rr.com>,
- Alessandro Zummo <a.zummo@towertech.it>
-
-Description
------------
-
-This module aims to provide complete access to the Xicor X1205 RTC.
-Recently Xicor has merged with Intersil, but the chip is
-still sold under the Xicor brand.
-
-This chip is located at address 0x6f and uses a 2-byte 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
-explicitely set the probe parameter.
-
-example:
-
-modprobe x1205 probe=0,0x6f
-
-The module supports one more option, hctosys, which is used to set the
-software clock from the x1205. On systems where the x1205 is the
-only hardware rtc, this parameter could be used to achieve a correct
-date/time earlier in the system boot sequence.
-
-example:
-
-modprobe x1205 probe=0,0x6f hctosys=1
diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary
index aea60bf7e8f0..003c7319b8c7 100644
--- a/Documentation/i2c/summary
+++ b/Documentation/i2c/summary
@@ -67,7 +67,6 @@ i2c-proc: The /proc/sys/dev/sensors interface for device (client) drivers
Algorithm drivers
-----------------
-i2c-algo-8xx: An algorithm for CPM's I2C device in Motorola 8xx processors (NOT BUILT BY DEFAULT)
i2c-algo-bit: A bit-banging algorithm
i2c-algo-pcf: A PCF 8584 style algorithm
i2c-algo-ibm_ocp: An algorithm for the I2C device in IBM 4xx processors (NOT BUILT BY DEFAULT)
@@ -81,6 +80,5 @@ i2c-pcf-epp: PCF8584 on a EPP parallel port (uses i2c-algo-pcf) (NOT mkpatch
i2c-philips-par: Philips style parallel port adapter (uses i2c-algo-bit)
i2c-adap-ibm_ocp: IBM 4xx processor I2C device (uses i2c-algo-ibm_ocp) (NOT BUILT BY DEFAULT)
i2c-pport: Primitive parallel port adapter (uses i2c-algo-bit)
-i2c-rpx: RPX board Motorola 8xx I2C device (uses i2c-algo-8xx) (NOT BUILT BY DEFAULT)
i2c-velleman: Velleman K8000 parallel port adapter (uses i2c-algo-bit)
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index 3d8d36b0ad12..2c170032bf37 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -571,7 +571,7 @@ SMBus communication
u8 command, u8 length,
u8 *values);
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
- u8 command, u8 *values);
+ u8 command, u8 length, u8 *values);
These ones were removed in Linux 2.6.10 because they had no users, but could
be added back later if needed:
diff --git a/Documentation/i386/zero-page.txt b/Documentation/i386/zero-page.txt
index c04a421f4a7c..75b3680c41eb 100644
--- a/Documentation/i386/zero-page.txt
+++ b/Documentation/i386/zero-page.txt
@@ -37,6 +37,7 @@ Offset Type Description
0x1d0 unsigned long EFI memory descriptor map pointer
0x1d4 unsigned long EFI memory descriptor map size
0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb
+0x1e4 unsigned long Scratch field for the kernel setup code
0x1e8 char number of entries in E820MAP (below)
0x1e9 unsigned char number of entries in EDDBUF (below)
0x1ea unsigned char number of entries in EDD_MBR_SIG_BUFFER (below)
diff --git a/Documentation/ia64/aliasing-test.c b/Documentation/ia64/aliasing-test.c
index d485256ee1ce..773a814d4093 100644
--- a/Documentation/ia64/aliasing-test.c
+++ b/Documentation/ia64/aliasing-test.c
@@ -19,6 +19,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <linux/pci.h>
int sum;
@@ -34,13 +35,19 @@ int map_mem(char *path, off_t offset, size_t length, int touch)
return -1;
}
+ if (fnmatch("/proc/bus/pci/*", path, 0) == 0) {
+ rc = ioctl(fd, PCIIOC_MMAP_IS_MEM);
+ if (rc == -1)
+ perror("PCIIOC_MMAP_IS_MEM ioctl");
+ }
+
addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
if (addr == MAP_FAILED)
return 1;
if (touch) {
c = (int *) addr;
- while (c < (int *) (offset + length))
+ while (c < (int *) (addr + length))
sum += *c++;
}
@@ -54,7 +61,7 @@ int map_mem(char *path, off_t offset, size_t length, int touch)
return 0;
}
-int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch)
+int scan_tree(char *path, char *file, off_t offset, size_t length, int touch)
{
struct dirent **namelist;
char *name, *path2;
@@ -93,7 +100,7 @@ int scan_sysfs(char *path, char *file, off_t offset, size_t length, int touch)
} else {
r = lstat(path2, &buf);
if (r == 0 && S_ISDIR(buf.st_mode)) {
- rc = scan_sysfs(path2, file, offset, length, touch);
+ rc = scan_tree(path2, file, offset, length, touch);
if (rc < 0)
return rc;
}
@@ -238,10 +245,15 @@ int main()
else
fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
- scan_sysfs("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
+ scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
+ scan_tree("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
+ scan_tree("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
+ scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
scan_rom("/sys/devices", "rom");
+
+ scan_tree("/proc/bus/pci", "??.?", 0, 0xA0000, 1);
+ scan_tree("/proc/bus/pci", "??.?", 0xA0000, 0x20000, 0);
+ scan_tree("/proc/bus/pci", "??.?", 0xC0000, 0x40000, 1);
+ scan_tree("/proc/bus/pci", "??.?", 0, 1024*1024, 0);
}
diff --git a/Documentation/ia64/aliasing.txt b/Documentation/ia64/aliasing.txt
index 9a431a7d0f5d..aa3e953f0f7b 100644
--- a/Documentation/ia64/aliasing.txt
+++ b/Documentation/ia64/aliasing.txt
@@ -112,6 +112,18 @@ POTENTIAL ATTRIBUTE ALIASING CASES
The /dev/mem mmap constraints apply.
+ mmap of /proc/bus/pci/.../??.?
+
+ This is an MMIO mmap of PCI functions, which additionally may or
+ may not be requested as using the WC attribute.
+
+ If WC is requested, and the region in kern_memmap is either WC
+ or UC, and the EFI memory map designates the region as WC, then
+ the WC mapping is allowed.
+
+ Otherwise, the user mapping must use the same attribute as the
+ kernel mapping.
+
read/write of /dev/mem
This uses copy_from_user(), which implicitly uses a kernel
diff --git a/Documentation/ioctl-number.txt b/Documentation/ioctl-number.txt
index 3de7d379cf07..5c7fbf9d96b4 100644
--- a/Documentation/ioctl-number.txt
+++ b/Documentation/ioctl-number.txt
@@ -67,7 +67,7 @@ Code Seq# Include File Comments
0x00 00-1F linux/wavefront.h conflict!
0x02 all linux/fd.h
0x03 all linux/hdreg.h
-0x04 all linux/umsdos_fs.h
+0x04 D2-DC linux/umsdos_fs.h Dead since 2.6.11, but don't reuse these.
0x06 all linux/lp.h
0x09 all linux/md.h
0x12 all linux/fs.h
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
new file mode 100644
index 000000000000..b2446a090870
--- /dev/null
+++ b/Documentation/ja_JP/HOWTO
@@ -0,0 +1,650 @@
+NOTE:
+This is Japanese translated version of "Documentation/HOWTO".
+This one is maintained by Tsugikazu Shibata <tshibata@ab.jp.nec.com>
+and JF Project team <www.linux.or.jp/JF>.
+If you find difference with original file or problem in translation,
+please contact maintainer of this file or JF project.
+
+Please also note that purpose of this file is easier to read for non
+English natives and not to be intended to fork. So, if you have any
+comments or updates of this file, please try to update Original(English)
+file at first.
+
+Last Updated: 2007/06/04
+==================================
+ã“ã‚Œã¯ã€
+linux-2.6.21/Documentation/HOWTO
+ã®å’Œè¨³ã§ã™ã€‚
+
+翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
+翻訳日: 2007/06/04
+翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
+校正者: æ¾å€‰ã•ã‚“ <nbh--mats at nifty dot com>
+ å°æž— é›…å…¸ã•ã‚“ (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
+ 武井伸光ã•ã‚“ã€<takei at webmasters dot gr dot jp>
+ ã‹ã­ã“ã•ã‚“ (Seiji Kaneko) <skaneko at a2 dot mbn dot or dot jp>
+ 野å£ã•ã‚“ (Kenji Noguchi) <tokyo246 at gmail dot com>
+ 河内ã•ã‚“ (Takayoshi Kochi) <t-kochi at bq dot jp dot nec dot com>
+ 岩本ã•ã‚“ (iwamoto) <iwamoto.kn at ncos dot nec dot co dot jp>
+==================================
+
+Linux カーãƒãƒ«é–‹ç™ºã®ã‚„ã‚Šæ–¹
+-------------------------------
+
+ã“ã‚Œã¯ä¸Šã®ãƒˆãƒ”ック( Linux カーãƒãƒ«é–‹ç™ºã®ã‚„ã‚Šæ–¹)ã®é‡è¦ãªäº‹æŸ„を網羅ã—ãŸ
+ドキュメントã§ã™ã€‚ã“ã“ã«ã¯ Linux カーãƒãƒ«é–‹ç™ºè€…ã«ãªã‚‹ãŸã‚ã®æ–¹æ³•ã¨
+Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨å…±ã«æ´»å‹•ã™ã‚‹ã‚„り方を学ã¶æ–¹æ³•ãŒå«ã¾ã‚Œã¦
+ã„ã¾ã™ã€‚カーãƒãƒ«ãƒ—ログラミングã«é–¢ã™ã‚‹æŠ€è¡“çš„ãªé …ç›®ã«é–¢ã™ã‚‹ã“ã¨ã¯ä½•ã‚‚å«
+ã‚ãªã„よã†ã«ã—ã¦ã„ã¾ã™ãŒã€ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…ã¨ãªã‚‹ãŸã‚ã®æ­£ã—ã„æ–¹å‘ã«å‘ã‹ã†
+手助ã‘ã«ãªã‚Šã¾ã™ã€‚
+
+ã‚‚ã—ã€ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®ã©ã“ã‹ãŒå¤ããªã£ã¦ã„ãŸå ´åˆã«ã¯ã€ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³
+トã®æœ€å¾Œã«ãƒªã‚¹ãƒˆã—ãŸãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼ã«ãƒ‘ッãƒã‚’é€ã£ã¦ãã ã•ã„。
+
+ã¯ã˜ã‚ã«
+---------
+
+ã‚ãªãŸã¯ã€€Linux カーãƒãƒ«ã®é–‹ç™ºè€…ã«ãªã‚‹æ–¹æ³•ã‚’å­¦ã³ãŸã„ã®ã§ã—ょã†ã‹ï¼Ÿã€€ã
+ã‚Œã¨ã‚‚ã‚ãªãŸã¯ä¸Šå¸ã‹ã‚‰ã€Œã“ã®ãƒ‡ãƒã‚¤ã‚¹ã® Linux ドライãƒã‚’書ãよã†ã«ã€ã¨
+言ã‚ã‚Œã¦ã„ã‚‹ã®ã§ã—ょã†ã‹ï¼Ÿã€€
+ã“ã®æ–‡æ›¸ã®ç›®çš„ã¯ã€ã‚ãªãŸãŒè¸ã‚€ã¹ã手順ã¨ã€ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨ä¸€ç·’ã«ã†ã¾ãåƒ
+ãヒントを書ã下ã™ã“ã¨ã§ã€ã‚ãªãŸãŒçŸ¥ã‚‹ã¹ãå…¨ã¦ã®ã“ã¨ã‚’æ•™ãˆã‚‹ã“ã¨ã§ã™ã€‚
+ã¾ãŸã€ã“ã®ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ãŒãªãœä»Šã†ã¾ãã¾ã‚ã£ã¦ã„ã‚‹ã®ã‹ã¨ã„ã†ç†ç”±ã®ä¸€éƒ¨ã‚‚
+説明ã—よã†ã¨è©¦ã¿ã¦ã„ã¾ã™ã€‚
+
+カーãƒãƒ«ã¯ å°‘é‡ã®ã‚¢ãƒ¼ã‚­ãƒ†ã‚¯ãƒãƒ£ä¾å­˜éƒ¨åˆ†ãŒã‚¢ã‚»ãƒ³ãƒ–リ言語ã§æ›¸ã‹ã‚Œã¦ã„ã‚‹
+以外ã¯å¤§éƒ¨åˆ†ã¯ C 言語ã§æ›¸ã‹ã‚Œã¦ã„ã¾ã™ã€‚C言語をよãç†è§£ã—ã¦ã„ã‚‹ã“ã¨ã¯ã‚«ãƒ¼
+ãƒãƒ«é–‹ç™ºè€…ã«ã¯å¿…è¦ã§ã™ã€‚アーキテクãƒãƒ£å‘ã‘ã®ä½Žãƒ¬ãƒ™ãƒ«éƒ¨åˆ†ã®é–‹ç™ºã‚’ã™ã‚‹ã®
+ã§ãªã‘ã‚Œã°ã€(ã©ã‚“ãªã‚¢ãƒ¼ã‚­ãƒ†ã‚¯ãƒãƒ£ã§ã‚‚)アセンブリ(訳注: 言語)ã¯å¿…è¦ã‚ã‚Š
+ã¾ã›ã‚“。以下ã®æœ¬ã¯ã€C 言語ã®å分ãªçŸ¥è­˜ã‚„何年もã®çµŒé¨“ã«å–ã£ã¦ä»£ã‚ã‚‹ã‚‚ã®
+ã§ã¯ã‚ã‚Šã¾ã›ã‚“ãŒã€å°‘ãªãã¨ã‚‚リファレンスã¨ã—ã¦ã¯ã„ã„本ã§ã™ã€‚
+ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
+ -『プログラミング言語C第2版ã€(B.W. カーニãƒãƒ³/D.M. リッãƒãƒ¼è‘— 石田晴久訳) [共立出版]
+ - "Practical C Programming" by Steve Oualline [O'Reilly]
+ - 『C実践プログラミング第3版ã€(Steve Ouallineè‘— 望月康å¸ç›£è¨³ è°·å£åŠŸè¨³) [オライリージャパン]
+ - "C: A Reference Manual" by Harbison and Steele [Prentice Hall]
+ - 『新・詳説 C 言語 H&S リファレンスã€
+ (サミュエル P ãƒãƒ¼ãƒ“ソン/ガイ L スティール共著 斉藤 信男監訳)[ソフトãƒãƒ³ã‚¯]
+
+カーãƒãƒ«ã¯ GNU C 㨠GNU ツールãƒã‚§ã‚¤ãƒ³ã‚’使ã£ã¦æ›¸ã‹ã‚Œã¦ã„ã¾ã™ã€‚カーãƒãƒ«
+㯠ISO C89 仕様ã«æº–æ‹ ã—ã¦æ›¸ã一方ã§ã€æ¨™æº–ã«ã¯ç„¡ã„言語拡張を多ã使ã£ã¦
+ã„ã¾ã™ã€‚カーãƒãƒ«ã¯æ¨™æº– C ライブラリã¨ã¯é–¢ä¿‚ãŒãªã„ã¨ã„ã£ãŸã€C 言語フリー
+スタンディング環境ã§ã™ã€‚ãã®ãŸã‚ã€C ã®æ¨™æº–ã§ä½¿ãˆãªã„ã‚‚ã®ã‚‚ã‚ã‚Šã¾ã™ã€‚ä»»
+æ„ã® long long ã®é™¤ç®—や浮動å°æ•°ç‚¹ã¯ä½¿ãˆã¾ã›ã‚“。
+ã¨ãã©ãã€ã‚«ãƒ¼ãƒãƒ«ãŒãƒ„ールãƒã‚§ã‚¤ãƒ³ã‚„ C 言語拡張ã«ç½®ã„ã¦ã„ã‚‹å‰æãŒã©ã†
+ãªã£ã¦ã„ã‚‹ã®ã‹ã‚ã‹ã‚Šã«ãã„ã“ã¨ãŒã‚ã‚Šã€ã¾ãŸã€æ®‹å¿µãªã“ã¨ã«æ±ºå®šçš„ãªãƒªãƒ•ã‚¡
+レンスã¯å­˜åœ¨ã—ã¾ã›ã‚“。情報を得るã«ã¯ã€gcc ã® info ページ( info gcc )ã‚’
+ã¿ã¦ãã ã•ã„。
+
+ã‚ãªãŸã¯æ—¢å­˜ã®é–‹ç™ºã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨ä¸€ç·’ã«ä½œæ¥­ã™ã‚‹æ–¹æ³•ã‚’å­¦ã¼ã†ã¨ã—ã¦ã„ã‚‹ã“
+ã¨ã«ç•™æ„ã—ã¦ãã ã•ã„。ãã®ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã€ã‚¹ã‚¿ã‚¤ãƒ«ã€
+開発手順ã«ã¤ã„ã¦é«˜åº¦ãªæ¨™æº–ã‚’æŒã¤ã€å¤šæ§˜ãªäººã®é›†ã¾ã‚Šã§ã™ã€‚
+地ç†çš„ã«åˆ†æ•£ã—ãŸå¤§è¦æ¨¡ãªãƒãƒ¼ãƒ ã«å¯¾ã—ã¦ã‚‚ã£ã¨ã‚‚ã†ã¾ãã„ãã¨ã‚ã‹ã£ãŸã“ã¨
+をベースã«ã—ãªãŒã‚‰ã€ã“れらã®æ¨™æº–ã¯é•·ã„時間をã‹ã‘ã¦ç¯‰ã‹ã‚Œã¦ãã¾ã—ãŸã€‚
+ã“れらã¯ãã¡ã‚“ã¨æ–‡æ›¸åŒ–ã•ã‚Œã¦ã„ã¾ã™ã‹ã‚‰ã€äº‹å‰ã«ã“れらã®æ¨™æº–ã«ã¤ã„ã¦ã§ã
+ã‚‹ã ã‘ãŸãã•ã‚“学んã§ãã ã•ã„。ã¾ãŸçš†ãŒã‚ãªãŸã‚„ã‚ãªãŸã®ä¼šç¤¾ã®ã‚„ã‚Šæ–¹ã«åˆã‚
+ã›ã¦ãれるã¨æ€ã‚ãªã„ã§ãã ã•ã„。
+
+法的å•é¡Œ
+------------
+
+Linux カーãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã¯ GPL ライセンスã®ä¸‹ã§ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¦ã„ã¾
+ã™ã€‚ライセンスã®è©³ç´°ã«ã¤ã„ã¦ã¯ã€ã‚½ãƒ¼ã‚¹ãƒ„リーã®ãƒ¡ã‚¤ãƒ³ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å­˜åœ¨
+ã™ã‚‹ã€COPYING ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ã¿ã¦ãã ã•ã„。もã—ライセンスã«ã¤ã„ã¦ã•ã‚‰ã«è³ª
+å•ãŒã‚ã‚Œã°ã€Linux Kernel メーリングリストã«è³ªå•ã™ã‚‹ã®ã§ã¯ãªãã€ã©ã†ãž
+法律家ã«ç›¸è«‡ã—ã¦ãã ã•ã„。メーリングリストã®äººé”ã¯æ³•å¾‹å®¶ã§ã¯ãªãã€æ³•çš„
+å•é¡Œã«ã¤ã„ã¦ã¯å½¼ã‚‰ã®å£°æ˜Žã¯ã‚ã¦ã«ã™ã‚‹ã¹ãã§ã¯ã‚ã‚Šã¾ã›ã‚“。
+
+GPL ã«é–¢ã™ã‚‹å…±é€šã®è³ªå•ã‚„回答ã«ã¤ã„ã¦ã¯ã€ä»¥ä¸‹ã‚’å‚ç…§ã—ã¦ãã ã•ã„。
+ http://www.gnu.org/licenses/gpl-faq.html
+
+ドキュメント
+------------
+
+Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã¯å¹…広ã„範囲ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’å«ã‚“ã§ãŠã‚Šã€ãã‚Œ
+らã¯ã‚«ãƒ¼ãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨ä¼šè©±ã™ã‚‹æ–¹æ³•ã‚’å­¦ã¶ã®ã«éžå¸¸ã«è²´é‡ãªã‚‚ã®ã§ã™ã€‚
+æ–°ã—ã„機能ãŒã‚«ãƒ¼ãƒãƒ«ã«è¿½åŠ ã•ã‚Œã‚‹å ´åˆã€ãã®æ©Ÿèƒ½ã®ä½¿ã„æ–¹ã«ã¤ã„ã¦èª¬æ˜Žã—ãŸ
+æ–°ã—ã„ドキュメントファイルも追加ã™ã‚‹ã“ã¨ã‚’勧ã‚ã¾ã™ã€‚
+カーãƒãƒ«ã®å¤‰æ›´ãŒã€ã‚«ãƒ¼ãƒãƒ«ãŒãƒ¦ãƒ¼ã‚¶ç©ºé–“ã«å…¬é–‹ã—ã¦ã„るインターフェイスã®
+変更を引ãèµ·ã“ã™å ´åˆã€ãã®å¤‰æ›´ã‚’説明ã™ã‚‹ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ãƒšãƒ¼ã‚¸ã®ãƒ‘ッãƒã‚„情報
+をマニュアルページã®ãƒ¡ãƒ³ãƒ†ãƒŠ mtk-manpages@gmx.net ã«é€ã‚‹ã“ã¨ã‚’勧ã‚ã¾ã™ã€‚
+
+以下ã¯ã‚«ãƒ¼ãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã«å«ã¾ã‚Œã¦ã„る読んã§ãŠãã¹ãファイルã®ä¸€è¦§ã§
+ã™-
+
+ README
+ ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯ Linuxカーãƒãƒ«ã®ç°¡å˜ãªèƒŒæ™¯ã¨ã‚«ãƒ¼ãƒãƒ«ã‚’設定(訳注
+ configure )ã—ã€ç”Ÿæˆ(訳注 build )ã™ã‚‹ãŸã‚ã«å¿…è¦ãªã“ã¨ã¯ä½•ã‹ãŒæ›¸ã‹ã‚Œ
+ ã¦ã„ã¾ã™ã€‚カーãƒãƒ«ã«é–¢ã—ã¦åˆã‚ã¦ã®äººã¯ã“ã“ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã™ã‚‹ã¨ã‚ˆã„ã§
+ ã—ょã†ã€‚
+
+ Documentation/Changes
+ ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯ã‚«ãƒ¼ãƒãƒ«ã‚’ã†ã¾ã生æˆ(訳注 build )ã—ã€èµ°ã‚‰ã›ã‚‹ã®ã«æœ€
+ å°é™ã®ãƒ¬ãƒ™ãƒ«ã§å¿…è¦ãªæ•°ã€…ã®ã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ãƒ‘ッケージã®ä¸€è¦§ã‚’示ã—ã¦ã„
+ ã¾ã™ã€‚
+
+ Documentation/CodingStyle
+ ã“れ㯠Linux カーãƒãƒ«ã®ã‚³ãƒ¼ãƒ‡ã‚£ãƒ³ã‚°ã‚¹ã‚¿ã‚¤ãƒ«ã¨èƒŒæ™¯ã«ã‚ã‚‹ç†ç”±ã‚’記述
+ ã—ã¦ã„ã¾ã™ã€‚å…¨ã¦ã®æ–°ã—ã„コードã¯ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã«ã‚るガイドライン
+ ã«å¾“ã£ã¦ã„ã‚‹ã“ã¨ã‚’期待ã•ã‚Œã¦ã„ã¾ã™ã€‚大部分ã®ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼ã¯ã“れらã®ãƒ«ãƒ¼
+ ルã«å¾“ã£ã¦ã„ã‚‹ã‚‚ã®ã ã‘ã‚’å—ã‘付ã‘ã€å¤šãã®äººã¯æ­£ã—ã„スタイルã®ã‚³ãƒ¼ãƒ‰
+ ã ã‘をレビューã—ã¾ã™ã€‚
+
+ Documentation/SubmittingPatches
+ Documentation/SubmittingDrivers
+ ã“れらã®ãƒ•ã‚¡ã‚¤ãƒ«ã«ã¯ã€ã©ã†ã‚„ã£ã¦ã†ã¾ãパッãƒã‚’作ã£ã¦æŠ•ç¨¿ã™ã‚‹ã‹ã«
+ ã¤ã„ã¦éžå¸¸ã«è©³ã—ã書ã‹ã‚Œã¦ãŠã‚Šã€ä»¥ä¸‹ã‚’å«ã¿ã¾ã™(ã“ã‚Œã ã‘ã«é™ã‚‰ãªã„
+ ã‘ã‚Œã©ã‚‚)
+ - Email ã«å«ã‚€ã“ã¨
+ - Email ã®å½¢å¼
+ - ã ã‚Œã«é€ã‚‹ã‹
+ ã“れらã®ãƒ«ãƒ¼ãƒ«ã«å¾“ãˆã°ã†ã¾ãã„ãã“ã¨ã‚’ä¿è¨¼ã™ã‚‹ã“ã¨ã§ã¯ã‚ã‚Šã¾ã›ã‚“
+ ㌠(ã™ã¹ã¦ã®ãƒ‘ッãƒã¯å†…容ã¨ã‚¹ã‚¿ã‚¤ãƒ«ã«ã¤ã„ã¦ç²¾æŸ»ã‚’å—ã‘ã‚‹ã®ã§)ã€
+ ルールã«å¾“ã‚ãªã‘ã‚Œã°é–“é•ã„ãªãã†ã¾ãã„ã‹ãªã„ã§ã—ょã†ã€‚
+ ã“ã®ä»–ã«ãƒ‘ッãƒã‚’作る方法ã«ã¤ã„ã¦ã®ã‚ˆãã§ããŸè¨˜è¿°ã¯-
+
+ "The Perfect Patch"
+ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ "Linux kernel patch submission format"
+ http://linux.yyz.us/patch-format.html
+
+ Documentation/stable_api_nonsense.txt
+ ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯ã‚«ãƒ¼ãƒãƒ«ã®ä¸­ã«ä¸å¤‰ã®APIã‚’æŒãŸãªã„ã“ã¨ã«ã—ãŸæ„識的ãª
+ 決断ã®èƒŒæ™¯ã«ã‚ã‚‹ç†ç”±ã«ã¤ã„ã¦æ›¸ã‹ã‚Œã¦ã„ã¾ã™ã€‚以下ã®ã‚ˆã†ãªã“ã¨ã‚’å«
+ ã‚“ã§ã„ã¾ã™-
+ - サブシステムã¨ã®é–“ã«å±¤ã‚’作るã“ã¨(コンパãƒãƒ“リティã®ãŸã‚?)
+ - オペレーティングシステム間ã®ãƒ‰ãƒ©ã‚¤ãƒã®ç§»æ¤æ€§
+ - カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã®ç´ æ—©ã„変更をé…らã›ã‚‹(ã‚‚ã—ãã¯ç´ æ—©ã„変更
+ を妨ã’ã‚‹)
+ ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ Linux 開発ã®æ€æƒ³ã‚’ç†è§£ã™ã‚‹ã®ã«éžå¸¸ã«é‡è¦ã§ã™ã€‚
+ ãã—ã¦ã€ä»–ã®OSã§ã®é–‹ç™ºè€…㌠Linux ã«ç§»ã‚‹æ™‚ã«ã¨ã¦ã‚‚é‡è¦ã§ã™ã€‚
+
+ Documentation/SecurityBugs
+ ã‚‚ã— Linux カーãƒãƒ«ã§ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£å•é¡Œã‚’発見ã—ãŸã‚ˆã†ã«æ€ã£ãŸã‚‰ã€ã“
+ ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®ã‚¹ãƒ†ãƒƒãƒ—ã«å¾“ã£ã¦ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…ã«é€£çµ¡ã—ã€å•é¡Œè§£æ±ºã‚’
+ 支æ´ã—ã¦ãã ã•ã„。
+
+ Documentation/ManagementStyle
+ ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ Linux カーãƒãƒ«ã®ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼é”ãŒã©ã†è¡Œå‹•ã™ã‚‹ã‹ã€
+ 彼らã®æ‰‹æ³•ã®èƒŒæ™¯ã«ã‚る共有ã•ã‚Œã¦ã„る精神ã«ã¤ã„ã¦è¨˜è¿°ã—ã¦ã„ã¾ã™ã€‚ã“
+ ã‚Œã¯ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºã®åˆå¿ƒè€…ãªã‚‰ï¼ˆã‚‚ã—ãã¯ã€å˜ã«èˆˆå‘³ãŒã‚ã‚‹ã ã‘ã®äººã§ã‚‚)
+ é‡è¦ã§ã™ã€‚ãªãœãªã‚‰ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ã€ã‚«ãƒ¼ãƒãƒ«ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼é”ã®ç‹¬ç‰¹ãª
+ 行動ã«ã¤ã„ã¦ã®å¤šãã®èª¤è§£ã‚„混乱を解消ã™ã‚‹ã‹ã‚‰ã§ã™ã€‚
+
+ Documentation/stable_kernel_rules.txt
+ ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯ã©ã®ã‚ˆã†ã« stable カーãƒãƒ«ã®ãƒªãƒªãƒ¼ã‚¹ãŒè¡Œã‚れるã‹ã®ãƒ«ãƒ¼
+ ルãŒè¨˜è¿°ã•ã‚Œã¦ã„ã¾ã™ã€‚ãã—ã¦ã“れらã®ãƒªãƒªãƒ¼ã‚¹ã®ä¸­ã®ã©ã“ã‹ã§å¤‰æ›´ã‚’å–
+ り入れã¦ã‚‚らã„ãŸã„å ´åˆã«ä½•ã‚’ã™ã‚Œã°ã„ã„ã‹ãŒç¤ºã•ã‚Œã¦ã„ã¾ã™ã€‚
+
+ Documentation/kernel-docs.txt
+  カーãƒãƒ«é–‹ç™ºã«ä»˜éšã™ã‚‹å¤–部ドキュメントã®ãƒªã‚¹ãƒˆã§ã™ã€‚ã‚‚ã—ã‚ãªãŸãŒ
+ 探ã—ã¦ã„ã‚‹ã‚‚ã®ãŒã‚«ãƒ¼ãƒãƒ«å†…ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã§ã¿ã¤ã‹ã‚‰ãªã‹ã£ãŸå ´åˆã€
+ ã“ã®ãƒªã‚¹ãƒˆã‚’ã‚ãŸã£ã¦ã¿ã¦ãã ã•ã„。
+
+ Documentation/applying-patches.txt
+ パッãƒã¨ã¯ãªã«ã‹ã€ãƒ‘ッãƒã‚’ã©ã†ã‚„ã£ã¦æ§˜ã€…ãªã‚«ãƒ¼ãƒãƒ«ã®é–‹ç™ºãƒ–ランãƒã«
+ é©ç”¨ã™ã‚‹ã®ã‹ã«ã¤ã„ã¦æ­£ç¢ºã«è¨˜è¿°ã—ãŸè‰¯ã„入門書ã§ã™ã€‚
+
+カーãƒãƒ«ã¯ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã‹ã‚‰è‡ªå‹•çš„ã«ç”Ÿæˆå¯èƒ½ãªå¤šæ•°ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’自分自
+身ã§ã‚‚ã£ã¦ã„ã¾ã™ã€‚ã“ã‚Œã«ã¯ã‚«ãƒ¼ãƒãƒ«å†… API ã®ã™ã¹ã¦ã®è¨˜è¿°ã‚„ã€ã©ã†æ­£ã—ã
+ロックをã‹ã‘ã‚‹ã‹ã®è¦å‰‡ãŒå«ã¾ã‚Œã¾ã™ã€‚ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯
+Documentation/DocBook/ ディレクトリã«ä½œã‚‰ã‚Œã€ä»¥ä¸‹ã®ã‚ˆã†ã«
+ make pdfdocs
+ make psdocs
+ make htmldocs
+ make mandocs
+コマンドを実行ã™ã‚‹ã¨ãƒ¡ã‚¤ãƒ³ã‚«ãƒ¼ãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‹ã‚‰
+ãã‚Œãžã‚Œã€PDF, Postscript, HTML, man page ã®å½¢å¼ã§ç”Ÿæˆã•ã‚Œã¾ã™ã€‚
+
+カーãƒãƒ«é–‹ç™ºè€…ã«ãªã‚‹ã«ã¯
+---------------------------
+
+ã‚‚ã—ã‚ãªãŸãŒã€Linux カーãƒãƒ«é–‹ç™ºã«ã¤ã„ã¦ä½•ã‚‚知らãªã„ãªã‚‰ã°ã€
+KernelNewbies プロジェクトを見るã¹ãã§ã™
+ http://kernelnewbies.org
+
+ã“ã®ã‚µã‚¤ãƒˆã«ã¯å½¹ã«ç«‹ã¤ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆãŒã‚ã‚Šã€åŸºæœ¬çš„ãªã‚«ãƒ¼ãƒãƒ«é–‹ç™ºã«é–¢
+ã™ã‚‹ã»ã¨ã‚“ã©ã©ã‚“ãªç¨®é¡žã®è³ªå•ã‚‚ã§ãã¾ã™ (æ—¢ã«å›žç­”ã•ã‚Œã¦ã„るよã†ãªã“ã¨ã‚’
+èžãå‰ã«ã¾ãšã¯ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–を調ã¹ã¦ãã ã•ã„)。
+ã¾ãŸã“ã“ã«ã¯ã€ãƒªã‚¢ãƒ«ã‚¿ã‚¤ãƒ ã§è³ªå•ã‚’èžãã“ã¨ãŒã§ãã‚‹ IRC ãƒãƒ£ãƒãƒ«ã‚„ã€Linux
+カーãƒãƒ«ã®é–‹ç™ºã«é–¢ã—ã¦å­¦ã¶ã®ã«ä¾¿åˆ©ãªãŸãã•ã‚“ã®å½¹ã«ç«‹ã¤ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆãŒã‚
+ã‚Šã¾ã™ã€‚
+
+web サイトã«ã¯ã€ã‚³ãƒ¼ãƒ‰ã®æ§‹æˆã€ã‚µãƒ–システムã€ç¾åœ¨å­˜åœ¨ã™ã‚‹ãƒ—ロジェクト(ツ
+リーã«ã‚ã‚‹ã‚‚ã®ç„¡ã„ã‚‚ã®ã®ä¸¡æ–¹)ã®åŸºæœ¬çš„ãªç®¡ç†æƒ…å ±ãŒã‚ã‚Šã¾ã™ã€‚
+ã“ã“ã«ã¯ã€ã¾ãŸã€ã‚«ãƒ¼ãƒãƒ«ã®ã‚³ãƒ³ãƒ‘イルã®ã‚„り方やパッãƒã®å½“ã¦æ–¹ãªã©ã®é–“接
+çš„ãªåŸºæœ¬æƒ…報も記述ã•ã‚Œã¦ã„ã¾ã™ã€‚
+
+ã‚ãªãŸãŒã©ã“ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã—ã¦ã‚ˆã„ã‹ã‚ã‹ã‚‰ãªã„ãŒã€Linux カーãƒãƒ«é–‹ç™ºã‚³ãƒŸãƒ¥
+ニティã«å‚加ã—ã¦ä½•ã‹ã™ã‚‹ã“ã¨ã‚’ã•ãŒã—ã¦ã„ã‚‹å ´åˆã«ã¯ã€Linux kernel
+Janitor's プロジェクトã«ã„ã‘ã°ã‚ˆã„ã§ã—ょㆠ-
+ http://janitor.kernelnewbies.org/
+ã“ã“ã¯ãã®ã‚ˆã†ãªã‚¹ã‚¿ãƒ¼ãƒˆã‚’ã™ã‚‹ã®ã«ã†ã£ã¦ã¤ã‘ã®å ´æ‰€ã§ã™ã€‚ã“ã“ã«ã¯ã€
+Linux カーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ„リーã®ä¸­ã«å«ã¾ã‚Œã‚‹ã€ãã‚Œã„ã«ã—ã€ä¿®æ­£ã—ãªã‘ã‚Œã°ãª
+らãªã„ã€å˜ç´”ãªå•é¡Œã®ãƒªã‚¹ãƒˆãŒè¨˜è¿°ã•ã‚Œã¦ã„ã¾ã™ã€‚ã“ã®ãƒ—ロジェクトã«é–¢ã‚ã‚‹
+開発者ã¨ä¸€ç·’ã«ä½œæ¥­ã™ã‚‹ã“ã¨ã§ã€ã‚ãªãŸã®ãƒ‘ッãƒã‚’ Linuxカーãƒãƒ«ãƒ„リーã«å…¥
+れるãŸã‚ã®åŸºç¤Žã‚’å­¦ã¶ã“ã¨ãŒã§ãã€ãã—ã¦ã‚‚ã—ã‚ãªãŸãŒã¾ã ã‚¢ã‚¤ãƒ‡ã‚£ã‚¢ã‚’æŒã£
+ã¦ã„ãªã„å ´åˆã«ã¯ã€æ¬¡ã«ã‚„る仕事ã®æ–¹å‘性ãŒè¦‹ãˆã¦ãã‚‹ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“。
+
+ã‚‚ã—ã‚ãªãŸãŒã€ã™ã§ã«ã²ã¨ã¾ã¨ã¾ã‚Šã‚³ãƒ¼ãƒ‰ã‚’書ã„ã¦ã„ã¦ã€ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã«å…¥
+ã‚ŒãŸã„ã¨æ€ã£ã¦ã„ãŸã‚Šã€ãã‚Œã«é–¢ã™ã‚‹é©åˆ‡ãªæ”¯æ´ã‚’求ã‚ãŸã„å ´åˆã€ã‚«ãƒ¼ãƒãƒ«
+メンターズプロジェクトã¯ãã®ã‚ˆã†ãªçš†ã•ã‚“を助ã‘ã‚‹ãŸã‚ã«ã§ãã¾ã—ãŸã€‚
+ã“ã“ã«ã¯ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆãŒã‚ã‚Šã€ä»¥ä¸‹ã‹ã‚‰å‚ç…§ã§ãã¾ã™
+ http://selenic.com/mailman/listinfo/kernel-mentors
+
+実際㫠Linux カーãƒãƒ«ã®ã‚³ãƒ¼ãƒ‰ã«ã¤ã„ã¦ä¿®æ­£ã‚’加ãˆã‚‹å‰ã«ã€ã©ã†ã‚„ã£ã¦ãã®
+コードãŒå‹•ä½œã™ã‚‹ã®ã‹ã‚’ç†è§£ã™ã‚‹ã“ã¨ãŒå¿…è¦ã§ã™ã€‚ãã®ãŸã‚ã«ã¯ã€ç‰¹åˆ¥ãªãƒ„ー
+ルã®åŠ©ã‘を借りã¦ã§ã‚‚ã€ãれを直接よã読むã“ã¨ãŒæœ€è‰¯ã®æ–¹æ³•ã§ã™(ã»ã¨ã‚“ã©
+ã®ãƒˆãƒªãƒƒã‚­ãƒ¼ãªéƒ¨åˆ†ã¯å分ã«ã‚³ãƒ¡ãƒ³ãƒˆã—ã¦ã‚ã‚Šã¾ã™ã‹ã‚‰)。ãã†ã„ã†ãƒ„ールã§
+特ã«ãŠã™ã™ã‚ãªã®ã¯ã€Linux クロスリファレンスプロジェクトã§ã™ã€‚ã“ã‚Œã¯ã€
+自己å‚照方å¼ã§ã€ç´¢å¼•ãŒã¤ã„㟠web å½¢å¼ã§ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã‚’å‚ç…§ã™ã‚‹ã“ã¨ãŒ
+ã§ãã¾ã™ã€‚ã“ã®æœ€æ–°ã®ç´ æ™´ã—ã„カーãƒãƒ«ã‚³ãƒ¼ãƒ‰ã®ãƒªãƒã‚¸ãƒˆãƒªã¯ä»¥ä¸‹ã§è¦‹ã¤ã‹ã‚Š
+ã¾ã™-
+ http://sosdg.org/~coywolf/lxr/
+
+開発プロセス
+-----------------------
+
+Linux カーãƒãƒ«ã®é–‹ç™ºãƒ—ロセスã¯ç¾åœ¨å¹¾ã¤ã‹ã®ç•°ãªã‚‹ãƒ¡ã‚¤ãƒ³ã‚«ãƒ¼ãƒãƒ«ã€Œãƒ–ラン
+ãƒã€ã¨å¤šæ•°ã®ã‚µãƒ–システム毎ã®ã‚«ãƒ¼ãƒãƒ«ãƒ–ランãƒã‹ã‚‰æ§‹æˆã•ã‚Œã¾ã™ã€‚
+ã“れらã®ãƒ–ランãƒã¨ã¯-
+ - メイン㮠2.6.x カーãƒãƒ«ãƒ„リー
+ - 2.6.x.y -stable カーãƒãƒ«ãƒ„リー
+ - 2.6.x -git カーãƒãƒ«ãƒ‘ッãƒ
+ - 2.6.x -mm カーãƒãƒ«ãƒ‘ッãƒ
+ - サブシステム毎ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒ
+
+2.6.x カーãƒãƒ«ãƒ„リー
+-----------------
+
+2.6.x カーãƒãƒ«ã¯ Linus Torvalds ã«ã‚ˆã£ã¦ãƒ¡ãƒ³ãƒ†ãƒŠãƒ³ã‚¹ã•ã‚Œã€kernel.org
+ã® pub/linux/kernel/v2.6/ ディレクトリã«å­˜åœ¨ã—ã¾ã™ã€‚ã“ã®é–‹ç™ºãƒ—ロセスã¯
+以下ã®ã¨ãŠã‚Š-
+
+ - æ–°ã—ã„カーãƒãƒ«ãŒãƒªãƒªãƒ¼ã‚¹ã•ã‚ŒãŸç›´å¾Œã«ã€2週間ã®ç‰¹åˆ¥æœŸé–“ãŒè¨­ã‘られã€
+ ã“ã®æœŸé–“中ã«ã€ãƒ¡ãƒ³ãƒ†ãƒŠãƒ¼é”㯠Linus ã«å¤§ããªå·®åˆ†ã‚’é€ã‚‹ã“ã¨ãŒã§ãã¾
+ ã™ã€‚ã“ã®ã‚ˆã†ãªå·®åˆ†ã¯é€šå¸¸ -mm カーãƒãƒ«ã«æ•°é€±é–“å«ã¾ã‚Œã¦ããŸãƒ‘ッãƒã§
+ ã™ã€‚ 大ããªå¤‰æ›´ã¯ git(カーãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ç®¡ç†ãƒ„ールã€è©³ç´°ã¯
+ http://git.or.cz/ å‚ç…§) を使ã£ã¦é€ã‚‹ã®ãŒå¥½ã¾ã—ã„ã‚„ã‚Šæ–¹ã§ã™ãŒã€ãƒ‘ッ
+ ãƒãƒ•ã‚¡ã‚¤ãƒ«ã®å½¢å¼ã®ã¾ã¾é€ã‚‹ã®ã§ã‚‚å分ã§ã™ã€‚
+
+ - 2週間後ã€-rc1 カーãƒãƒ«ãŒãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã€ã“ã®å¾Œã«ã¯ã‚«ãƒ¼ãƒãƒ«å…¨ä½“ã®å®‰å®š
+ 性ã«å½±éŸ¿ã‚’ã‚ãŸãˆã‚‹ã‚ˆã†ãªæ–°æ©Ÿèƒ½ã¯å«ã¾ãªã„é¡žã®ãƒ‘ッãƒã—ã‹å–り込むã“ã¨
+ ã¯ã§ãã¾ã›ã‚“。新ã—ã„ドライãƒ(ã‚‚ã—ãã¯ãƒ•ã‚¡ã‚¤ãƒ«ã‚·ã‚¹ãƒ†ãƒ )ã®ãƒ‘ッãƒã¯
+ -rc1 ã®å¾Œã§å—ã‘付ã‘られるã“ã¨ã‚‚ã‚ã‚‹ã“ã¨ã‚’覚ãˆã¦ãŠã„ã¦ãã ã•ã„。ãª
+ ãœãªã‚‰ã€å¤‰æ›´ãŒç‹¬ç«‹ã—ã¦ã„ã¦ã€è¿½åŠ ã•ã‚ŒãŸã‚³ãƒ¼ãƒ‰ã®å¤–ã®é ˜åŸŸã«å½±éŸ¿ã‚’与ãˆ
+ ãªã„é™ã‚Šã€é€€è¡Œã®ãƒªã‚¹ã‚¯ã¯ç„¡ã„ã‹ã‚‰ã§ã™ã€‚-rc1 ãŒãƒªãƒªãƒ¼ã‚¹ã•ã‚ŒãŸå¾Œã€
+ Linus ã¸ãƒ‘ッãƒã‚’é€ä»˜ã™ã‚‹ã®ã« git を使ã†ã“ã¨ã‚‚ã§ãã¾ã™ãŒã€ãƒ‘ッãƒã¯
+ レビューã®ãŸã‚ã«ã€ãƒ‘ブリックãªãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã¸ã‚‚åŒæ™‚ã«é€ã‚‹å¿…è¦ãŒ
+ ã‚ã‚Šã¾ã™ã€‚
+
+ - æ–°ã—ã„ -rc 㯠Linus ãŒã€æœ€æ–°ã® git ツリーãŒãƒ†ã‚¹ãƒˆç›®çš„ã§ã‚ã‚Œã°å分
+ ã«å®‰å®šã—ãŸçŠ¶æ…‹ã«ã‚ã‚‹ã¨åˆ¤æ–­ã—ãŸã¨ãã«ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¾ã™ã€‚目標ã¯æ¯Žé€±æ–°
+ ã—ã„ -rc カーãƒãƒ«ã‚’リリースã™ã‚‹ã“ã¨ã§ã™ã€‚
+
+ - ã“ã®ãƒ—ロセスã¯ã‚«ãƒ¼ãƒãƒ«ãŒ 「準備ãŒã§ããŸã€ã¨è€ƒãˆã‚‰ã‚Œã‚‹ã¾ã§ç¶™ç¶šã—ã¾
+ ã™ã€‚ã“ã®ãƒ—ロセスã¯ã ã„ãŸã„ 6週間継続ã—ã¾ã™ã€‚
+
+Andrew Morton ㌠Linux-kernel メーリングリストã«ã‚«ãƒ¼ãƒãƒ«ãƒªãƒªãƒ¼ã‚¹ã«ã¤ã„
+ã¦æ›¸ã„ãŸã“ã¨ã‚’ã“ã“ã§è¨€ã£ã¦ãŠãã“ã¨ã¯ä¾¡å€¤ãŒã‚ã‚Šã¾ã™-
+ 「カーãƒãƒ«ãŒã„ã¤ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã‚‹ã‹ã¯èª°ã‚‚知りã¾ã›ã‚“。ãªãœãªã‚‰ã€ã“ã‚Œã¯ç¾
+ 実ã«èªè­˜ã•ã‚ŒãŸãƒã‚°ã®çŠ¶æ³ã«ã‚ˆã‚Šãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã‚‹ã®ã§ã‚ã‚Šã€å‰ã‚‚ã£ã¦æ±ºã‚ら
+ ã‚ŒãŸè¨ˆç”»ã«ã‚ˆã£ã¦ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã‚‹ã‚‚ã®ã§ã¯ãªã„ã‹ã‚‰ã§ã™ã€‚ã€
+
+2.6.x.y -stable カーãƒãƒ«ãƒ„リー
+---------------------------
+
+ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«4ã¤ç›®ã®æ•°å­—ãŒã¤ã„ãŸã‚«ãƒ¼ãƒãƒ«ã¯ -stable カーãƒãƒ«ã§ã™ã€‚ã“ã‚Œã«
+ã¯ã€2.6.x カーãƒãƒ«ã§è¦‹ã¤ã‹ã£ãŸã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£å•é¡Œã‚„é‡å¤§ãªå¾Œæˆ»ã‚Šã«å¯¾ã™ã‚‹æ¯”
+較的å°ã•ã„é‡è¦ãªä¿®æ­£ãŒå«ã¾ã‚Œã¾ã™ã€‚
+
+ã“ã‚Œã¯ã€é–‹ç™º/実験的ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ãƒ†ã‚¹ãƒˆã«å”力ã™ã‚‹ã“ã¨ã«èˆˆå‘³ãŒç„¡ãã€
+最新ã®å®‰å®šã—ãŸã‚«ãƒ¼ãƒãƒ«ã‚’使ã„ãŸã„ユーザã«æŽ¨å¥¨ã™ã‚‹ãƒ–ランãƒã§ã™ã€‚
+
+ã‚‚ã—ã€2.6.x.y カーãƒãƒ«ãŒå­˜åœ¨ã—ãªã„å ´åˆã«ã¯ã€ç•ªå·ãŒä¸€ç•ªå¤§ãã„ 2.6.x
+ãŒæœ€æ–°ã®å®‰å®šç‰ˆã‚«ãƒ¼ãƒãƒ«ã§ã™ã€‚
+
+2.6.x.y 㯠"stable" ãƒãƒ¼ãƒ  <stable@kernel.org> ã§ãƒ¡ãƒ³ãƒ†ã•ã‚Œã¦ãŠã‚Šã€ã 
+ã„ãŸã„隔週ã§ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¦ã„ã¾ã™ã€‚
+
+カーãƒãƒ«ãƒ„リーã«å…¥ã£ã¦ã„ã‚‹ã€Documentation/stable_kernel_rules.txt ファ
+イルã«ã¯ã©ã®ã‚ˆã†ãªç¨®é¡žã®å¤‰æ›´ãŒ -stable ツリーã«å—ã‘入れå¯èƒ½ã‹ã€ã¾ãŸãƒª
+リースプロセスãŒã©ã†å‹•ãã‹ãŒè¨˜è¿°ã•ã‚Œã¦ã„ã¾ã™ã€‚
+
+2.6.x -git パッãƒ
+------------------
+
+git リãƒã‚¸ãƒˆãƒªã§ç®¡ç†ã•ã‚Œã¦ã„ã‚‹Linus ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã®æ¯Žæ—¥ã®ã‚¹ãƒŠãƒƒãƒ—
+ショットãŒã‚ã‚Šã¾ã™ã€‚(ã ã‹ã‚‰ -git ã¨ã„ã†åå‰ãŒã¤ã„ã¦ã„ã¾ã™)。ã“れらã®ãƒ‘ッ
+ãƒã¯ãŠãŠã‚€ã­æ¯Žæ—¥ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¦ãŠã‚Šã€Linus ã®ãƒ„リーã®ç¾çŠ¶ã‚’表ã—ã¾ã™ã€‚ã“
+れ㯠-rc カーãƒãƒ«ã¨æ¯”ã¹ã¦ã€ãƒ‘ッãƒãŒå¤§ä¸ˆå¤«ã‹ã©ã†ã‹ã‚‚確èªã—ãªã„ã§è‡ªå‹•çš„
+ã«ç”Ÿæˆã•ã‚Œã‚‹ã®ã§ã€ã‚ˆã‚Šå®Ÿé¨“çš„ã§ã™ã€‚
+
+2.6.x -mm カーãƒãƒ«ãƒ‘ッãƒ
+------------------------
+
+Andrew Morton ã«ã‚ˆã£ã¦ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã‚‹å®Ÿé¨“çš„ãªã‚«ãƒ¼ãƒãƒ«ãƒ‘ッãƒç¾¤ã§ã™ã€‚
+Andrew ã¯å€‹åˆ¥ã®ã‚µãƒ–システムカーãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒã‚’å…¨ã¦é›†ã‚ã¦ãã¦
+linux-kernel メーリングリストã§åŽé›†ã•ã‚ŒãŸå¤šæ•°ã®ãƒ‘ッãƒã¨åŒæ™‚ã«ä¸€ã¤ã«ã¾
+ã¨ã‚ã¾ã™ã€‚
+ã“ã®ãƒ„リーã¯æ–°æ©Ÿèƒ½ã¨ãƒ‘ッãƒãŒæ¤œè¨¼ã•ã‚Œã‚‹å ´ã¨ãªã‚Šã¾ã™ã€‚ã‚る期間ã®é–“パッãƒ
+㌠-mm ã«å…¥ã£ã¦ä¾¡å€¤ã‚’証明ã•ã‚ŒãŸã‚‰ã€Andrew やサブシステムメンテナãŒã€ãƒ¡
+インラインã¸å…¥ã‚Œã‚‹ã‚ˆã†ã« Linus ã«ãƒ—ッシュã—ã¾ã™ã€‚
+
+メインカーãƒãƒ«ãƒ„リーã«å«ã‚ã‚‹ãŸã‚ã« Linus ã«é€ã‚‹å‰ã«ã€ã™ã¹ã¦ã®æ–°ã—ã„パッ
+ãƒãŒ -mm ツリーã§ãƒ†ã‚¹ãƒˆã•ã‚Œã‚‹ã“ã¨ãŒå¼·ã推奨ã•ã‚Œã¾ã™ã€‚
+
+ã“れらã®ã‚«ãƒ¼ãƒãƒ«ã¯å®‰å®šã—ã¦å‹•ä½œã™ã¹ãシステムã¨ã—ã¦ä½¿ã†ã®ã«ã¯é©åˆ‡ã§ã¯ã‚
+ã‚Šã¾ã›ã‚“ã—ã€ã‚«ãƒ¼ãƒãƒ«ãƒ–ランãƒã®ä¸­ã§ã‚‚ã‚‚ã£ã¨ã‚‚動作ã«ãƒªã‚¹ã‚¯ãŒé«˜ã„ã‚‚ã®ã§ã™ã€‚
+
+ã‚‚ã—ã‚ãªãŸãŒã€ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºãƒ—ロセスã®æ”¯æ´ã‚’ã—ãŸã„ã¨æ€ã£ã¦ã„ã‚‹ã®ã§ã‚ã‚Œã°ã€
+ã©ã†ãžã“れらã®ã‚«ãƒ¼ãƒãƒ«ãƒªãƒªãƒ¼ã‚¹ã‚’テストã«ä½¿ã£ã¦ã¿ã¦ã€ãã—ã¦ã‚‚ã—å•é¡ŒãŒã‚
+ã‚Œã°ã€ã¾ãŸã‚‚ã—å…¨ã¦ãŒæ­£ã—ã動作ã—ãŸã¨ã—ã¦ã‚‚ã€linux-kernel メーリングリ
+ストã«ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’æä¾›ã—ã¦ãã ã•ã„。
+
+ã™ã¹ã¦ã®ä»–ã®å®Ÿé¨“的パッãƒã«åŠ ãˆã¦ã€ã“れらã®ã‚«ãƒ¼ãƒãƒ«ã¯é€šå¸¸ãƒªãƒªãƒ¼ã‚¹æ™‚点ã§
+メインライン㮠-git カーãƒãƒ«ã«å«ã¾ã‚Œã‚‹å…¨ã¦ã®å¤‰æ›´ã‚‚å«ã‚“ã§ã„ã¾ã™ã€‚
+
+-mm カーãƒãƒ«ã¯æ±ºã¾ã£ãŸã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã§ã¯ãƒªãƒªãƒ¼ã‚¹ã•ã‚Œã¾ã›ã‚“ã€ã—ã‹ã—通常幾
+ã¤ã‹ã® -mm カーãƒãƒ« (1 ã‹ã‚‰ 3 ãŒæ™®é€šï¼‰ãŒå„-rc カーãƒãƒ«ã®é–“ã«ãƒªãƒªãƒ¼ã‚¹ã•
+ã‚Œã¾ã™ã€‚
+
+サブシステム毎ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒ
+-------------------------------------------
+
+カーãƒãƒ«ã®æ§˜ã€…ãªé ˜åŸŸã§ä½•ãŒèµ·ãã¦ã„ã‚‹ã‹ã‚’見られるよã†ã«ã™ã‚‹ãŸã‚ã€å¤šãã®
+カーãƒãƒ«ã‚µãƒ–システム開発者ã¯å½¼ã‚‰ã®é–‹ç™ºãƒ„リーを公開ã—ã¦ã„ã¾ã™ã€‚ã“れらã®
+ツリーã¯èª¬æ˜Žã—ãŸã‚ˆã†ã« -mm カーãƒãƒ«ãƒªãƒªãƒ¼ã‚¹ã«å…¥ã‚Œè¾¼ã¾ã‚Œã¾ã™ã€‚
+
+以下ã¯ã•ã¾ã–ã¾ãªã‚«ãƒ¼ãƒãƒ«ãƒ„リーã®ä¸­ã®ã„ãã¤ã‹ã®ãƒªã‚¹ãƒˆ-
+
+ git ツリー-
+ - Kbuild ã®é–‹ç™ºãƒ„リーã€Sam Ravnborg <sam@ravnborg.org>
+ kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
+
+ - ACPI ã®é–‹ç™ºãƒ„リー〠Len Brown <len.brown@intel.com>
+ kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
+
+ - Block ã®é–‹ç™ºãƒ„リーã€Jens Axboe <axboe@suse.de>
+ kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
+
+ - DRM ã®é–‹ç™ºãƒ„リーã€Dave Airlie <airlied@linux.ie>
+ kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+
+ - ia64 ã®é–‹ç™ºãƒ„リーã€Tony Luck <tony.luck@intel.com>
+ kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
+
+ - ieee1394 ã®é–‹ç™ºãƒ„リーã€Jody McIntyre <scjody@modernduck.com>
+ kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git
+
+ - infiniband, Roland Dreier <rolandd@cisco.com>
+ kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
+
+ - libata, Jeff Garzik <jgarzik@pobox.com>
+ kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
+
+ - ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ‰ãƒ©ã‚¤ãƒ, Jeff Garzik <jgarzik@pobox.com>
+ kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
+
+ - pcmcia, Dominik Brodowski <linux@dominikbrodowski.net>
+ kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
+
+ - SCSI, James Bottomley <James.Bottomley@SteelEye.com>
+ kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
+
+ ãã®ä»–ã® git カーãƒãƒ«ãƒ„リー㯠http://kernel.org/git ã«ä¸€è¦§è¡¨ãŒã‚ã‚Šã¾
+ ã™ã€‚
+
+ quilt ツリー-
+ - USB, PCI ドライãƒã‚³ã‚¢ã¨ I2C, Greg Kroah-Hartman <gregkh@suse.de>
+ kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+
+ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆ
+-------------
+
+bugzilla.kernel.org 㯠Linux カーãƒãƒ«é–‹ç™ºè€…ãŒã‚«ãƒ¼ãƒãƒ«ã®ãƒã‚°ã‚’追跡ã™ã‚‹
+場所ã§ã™ã€‚ユーザã¯è¦‹ã¤ã‘ãŸãƒã‚°ã®å…¨ã¦ã‚’ã“ã®ãƒ„ールã§å ±å‘Šã™ã¹ãã§ã™ã€‚
+ã©ã† kernel bugzilla を使ã†ã‹ã®è©³ç´°ã¯ã€ä»¥ä¸‹ã‚’å‚ç…§ã—ã¦ãã ã•ã„-
+ http://test.kernel.org/bugzilla/faq.html
+
+メインカーãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ã‚るファイル REPORTING-BUGS ã¯ã‚«ãƒ¼ãƒ
+ルãƒã‚°ã‚‰ã—ã„ã‚‚ã®ã«ã¤ã„ã¦ã©ã†ãƒ¬ãƒãƒ¼ãƒˆã™ã‚‹ã‹ã®è‰¯ã„テンプレートã§ã‚ã‚Šã€å•
+é¡Œã®è¿½è·¡ã‚’助ã‘ã‚‹ãŸã‚ã«ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…ã«ã¨ã£ã¦ã©ã‚“ãªæƒ…å ±ãŒå¿…è¦ãªã®ã‹ã®è©³
+ç´°ãŒæ›¸ã‹ã‚Œã¦ã„ã¾ã™ã€‚
+
+メーリングリスト
+-------------
+
+上ã®ã„ãã¤ã‹ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã§è¿°ã¹ã¦ã„ã¾ã™ãŒã€ã‚³ã‚¢ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…ã®å¤§éƒ¨åˆ†
+㯠Linux kernel メーリングリストã«å‚加ã—ã¦ã„ã¾ã™ã€‚ã“ã®ãƒªã‚¹ãƒˆã®ç™»éŒ²/脱
+退ã®æ–¹æ³•ã«ã¤ã„ã¦ã¯ä»¥ä¸‹ã‚’å‚ç…§ã—ã¦ãã ã•ã„-
+ http://vger.kernel.org/vger-lists.html#linux-kernel
+
+ã“ã®ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã®ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–㯠web 上ã®å¤šæ•°ã®å ´æ‰€ã«å­˜åœ¨ã—ã¾ã™ã€‚ã“
+れらã®ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–を探ã™ã«ã¯ã‚µãƒ¼ãƒã‚¨ãƒ³ã‚¸ãƒ³ã‚’使ã„ã¾ã—ょã†ã€‚例ãˆã°-
+ http://dir.gmane.org/gmane.linux.kernel
+
+リストã«æŠ•ç¨¿ã™ã‚‹å‰ã«ã™ã§ã«ãã®è©±é¡ŒãŒã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã«å­˜åœ¨ã™ã‚‹ã‹ã©ã†ã‹ã‚’検索
+ã™ã‚‹ã“ã¨ã‚’是éžã‚„ã£ã¦ãã ã•ã„。多数ã®äº‹ãŒã™ã§ã«è©³ç´°ã«æ¸¡ã£ã¦è­°è«–ã•ã‚Œã¦
+ãŠã‚Šã€ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã«ã®ã¿è¨˜éŒ²ã•ã‚Œã¦ã„ã¾ã™ã€‚
+
+大部分ã®ã‚«ãƒ¼ãƒãƒ«ã‚µãƒ–システムも自分ã®å€‹åˆ¥ã®é–‹ç™ºã‚’実施ã™ã‚‹ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹
+トをæŒã£ã¦ã„ã¾ã™ã€‚個々ã®ã‚°ãƒ«ãƒ¼ãƒ—ãŒã©ã‚“ãªãƒªã‚¹ãƒˆã‚’æŒã£ã¦ã„ã‚‹ã‹ã¯ã€
+MAINTAINERS ファイルã«ãƒªã‚¹ãƒˆãŒã‚ã‚Šã¾ã™ã®ã§å‚ç…§ã—ã¦ãã ã•ã„。
+
+多ãã®ãƒªã‚¹ãƒˆã¯ kernel.org ã§ãƒ›ã‚¹ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚ã“れらã®æƒ…å ±ã¯ä»¥ä¸‹ã«ã‚
+ã‚Šã¾ã™-
+ http://vger.kernel.org/vger-lists.html
+
+メーリングリストを使ã†å ´åˆã€è‰¯ã„行動習慣ã«å¾“ã†ã‚ˆã†ã«ã—ã¾ã—ょã†ã€‚
+å°‘ã—安ã£ã½ã„ãŒã€ä»¥ä¸‹ã® URL ã¯ä¸Šã®ãƒªã‚¹ãƒˆ(ã‚„ä»–ã®ãƒªã‚¹ãƒˆ)ã§ä¼šè©±ã™ã‚‹å ´åˆã®
+シンプルãªã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³ã‚’示ã—ã¦ã„ã¾ã™-
+ http://www.albion.com/netiquette/
+
+ã‚‚ã—複数ã®äººãŒã‚ãªãŸã®ãƒ¡ãƒ¼ãƒ«ã«è¿”事をã—ãŸå ´åˆã€CC: ã§å—ã‘る人ã®ãƒªã‚¹ãƒˆã¯
+ã ã„ã¶å¤šããªã‚‹ã§ã—ょã†ã€‚良ã„ç†ç”±ãŒãªã„å ´åˆã€CC: リストã‹ã‚‰èª°ã‹ã‚’削除を
+ã—ãªã„よã†ã«ã€ã¾ãŸã€ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã ã‘ã«ãƒªãƒ—ライã™ã‚‹ã“ã¨ã®
+ãªã„よã†ã«ã—ã¾ã—ょã†ã€‚1ã¤ã¯é€ä¿¡è€…ã‹ã‚‰ã€ã‚‚ã†1ã¤ã¯ãƒªã‚¹ãƒˆã‹ã‚‰ã®ã‚ˆã†ã«ã€ãƒ¡ãƒ¼
+ルを2回å—ã‘ã‚‹ã“ã¨ã«ãªã£ã¦ã‚‚ãã‚Œã«æ…£ã‚Œã€ã—ゃれãŸãƒ¡ãƒ¼ãƒ«ãƒ˜ãƒƒãƒ€ãƒ¼ã‚’追加ã—
+ã¦ã“ã®çŠ¶æ…‹ã‚’変ãˆã‚ˆã†ã¨ã—ãªã„よã†ã«ã€‚人々ã¯ãã®ã‚ˆã†ãªã“ã¨ã¯å¥½ã¿ã¾ã›ã‚“。
+
+今ã¾ã§ã®ãƒ¡ãƒ¼ãƒ«ã§ã®ã‚„ã‚Šã¨ã‚Šã¨ãã®é–“ã®ã‚ãªãŸã®ç™ºè¨€ã¯ãã®ã¾ã¾æ®‹ã—ã€
+"John Kernlehacker wrote ...:" ã®è¡Œã‚’ã‚ãªãŸã®ãƒªãƒ—ライã®å…ˆé ­è¡Œã«ã—ã¦ã€
+メールã®å…ˆé ­ã§ãªãã€å„引用行ã®é–“ã«ã‚ãªãŸã®è¨€ã„ãŸã„ã“ã¨ã‚’追加ã™ã‚‹ã¹ãã§
+ã™ã€‚
+
+ã‚‚ã—パッãƒã‚’メールã«ä»˜ã‘ã‚‹å ´åˆã¯ã€Documentaion/SubmittingPatches ã«æ
+示ã•ã‚Œã¦ã„るよã†ã«ã€ãれ㯠プレーンãªå¯èª­ãƒ†ã‚­ã‚¹ãƒˆã«ã™ã‚‹ã“ã¨ã‚’忘れãªã„
+よã†ã«ã—ã¾ã—ょã†ã€‚カーãƒãƒ«é–‹ç™ºè€…㯠添付や圧縮ã—ãŸãƒ‘ッãƒã‚’扱ã„ãŸãŒã‚Šã¾
+ã›ã‚“-
+彼らã¯ã‚ãªãŸã®ãƒ‘ッãƒã®è¡Œæ¯Žã«ã‚³ãƒ¡ãƒ³ãƒˆã‚’入れãŸã„ã®ã§ã€ãã®ãŸã‚ã«ã¯ãã†ã™
+ã‚‹ã—ã‹ã‚ã‚Šã¾ã›ã‚“。ã‚ãªãŸã®ãƒ¡ãƒ¼ãƒ«ãƒ—ログラムãŒç©ºç™½ã‚„タブを圧縮ã—ãªã„よã†
+ã«ç¢ºèªã—ãŸæ–¹ãŒã„ã„ã§ã™ã€‚最åˆã®è‰¯ã„テストã¨ã—ã¦ã¯ã€è‡ªåˆ†ã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ã£ã¦
+ã¿ã¦ã€ãã®ãƒ‘ッãƒã‚’自分ã§å½“ã¦ã¦ã¿ã‚‹ã“ã¨ã§ã™ã€‚ã‚‚ã—ãã‚ŒãŒã†ã¾ãè¡Œã‹ãªã„ãª
+らã€ã‚ãªãŸã®ãƒ¡ãƒ¼ãƒ«ãƒ—ログラムを直ã—ã¦ã‚‚らã†ã‹ã€æ­£ã—ãå‹•ãよã†ã«å¤‰ãˆã‚‹ã¹
+ãã§ã™ã€‚
+
+ã¨ã‚Šã‚ã‘ã€ä»–ã®ç™»éŒ²è€…ã«å¯¾ã™ã‚‹å°Šæ•¬ã‚’表ã™ã‚ˆã†ã«ã™ã‚‹ã“ã¨ã‚’覚ãˆã¦ãŠã„ã¦ãã 
+ã•ã„。
+
+コミュニティã¨å…±ã«åƒãã“ã¨
+--------------------------
+
+カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã®ã‚´ãƒ¼ãƒ«ã¯å¯èƒ½ãªã‹ãŽã‚Šæœ€é«˜ã®ã‚«ãƒ¼ãƒãƒ«ã‚’æä¾›ã™ã‚‹ã“ã¨
+ã§ã™ã€‚ã‚ãªãŸãŒãƒ‘ッãƒã‚’å—ã‘入れã¦ã‚‚らã†ãŸã‚ã«æŠ•ç¨¿ã—ãŸå ´åˆã€ãã‚Œã¯ã€æŠ€è¡“
+的メリットã ã‘ãŒãƒ¬ãƒ“ューã•ã‚Œã¾ã™ã€‚ãã®éš›ã€ã‚ãªãŸã¯ä½•ã‚’予想ã™ã¹ãã§ã—ょ
+ã†ã‹?
+ - 批判
+ - コメント
+ - 変更ã®è¦æ±‚
+ - パッãƒã®æ­£å½“性ã®è¨¼æ˜Žè¦æ±‚
+ - 沈黙
+
+æ€ã„出ã—ã¦ãã ã•ã„ã€ã“ã“ã¯ã‚ãªãŸã®ãƒ‘ッãƒã‚’カーãƒãƒ«ã«å…¥ã‚Œã‚‹è©±ã§ã™ã€‚ã‚
+ãªãŸã¯ã€ã‚ãªãŸã®ãƒ‘ッãƒã«å¯¾ã™ã‚‹æ‰¹åˆ¤ã¨ã‚³ãƒ¡ãƒ³ãƒˆã‚’å—ã‘入れるã¹ãã§ã€ãれら
+を技術的レベルã§è©•ä¾¡ã—ã¦ã€ãƒ‘ッãƒã‚’å†ä½œæˆã™ã‚‹ã‹ã€ãªãœãれらã®å¤‰æ›´ã‚’ã™ã¹
+ãã§ãªã„ã‹ã‚’明確ã§ç°¡æ½”ãªç†ç”±ã®èª¬æ˜Žã‚’æä¾›ã—ã¦ãã ã•ã„。
+ã‚‚ã—ã€ã‚ãªãŸã®ãƒ‘ッãƒã«ä½•ã‚‚åå¿œãŒãªã„å ´åˆã€ãŸã¾ã«ã¯ãƒ¡ãƒ¼ãƒ«ã®å±±ã«åŸ‹ã‚‚ã‚Œã¦
+見逃ã•ã‚Œã€ã‚ãªãŸã®æŠ•ç¨¿ãŒå¿˜ã‚Œã‚‰ã‚Œã¦ã—ã¾ã†ã“ã¨ã‚‚ã‚ã‚‹ã®ã§ã€æ•°æ—¥å¾…ã£ã¦å†åº¦
+投稿ã—ã¦ãã ã•ã„。
+
+ã‚ãªãŸãŒã‚„ã‚‹ã¹ãã§ãªã„ã‚‚ã®ã¯?
+ - 質å•ãªã—ã«ã‚ãªãŸã®ãƒ‘ッãƒãŒå—ã‘入れられるã¨æƒ³åƒã™ã‚‹ã“ã¨
+ - 守りã«å…¥ã‚‹ã“ã¨
+ - コメントを無視ã™ã‚‹ã“ã¨
+ - è¦æ±‚ã•ã‚ŒãŸå¤‰æ›´ã‚’何もã—ãªã„ã§ãƒ‘ッãƒã‚’出ã—ç›´ã™ã“ã¨
+
+å¯èƒ½ãªé™ã‚Šæœ€é«˜ã®æŠ€è¡“的解決を求ã‚ã¦ã„るコミュニティã§ã¯ã€ãƒ‘ッãƒãŒã©ã®ã
+らã„有益ãªã®ã‹ã«ã¤ã„ã¦ã¯å¸¸ã«ç•°ãªã‚‹æ„見ãŒã‚ã‚Šã¾ã™ã€‚ã‚ãªãŸã¯å”調的ã§ã‚ã‚‹
+ã¹ãã§ã™ã—ã€ã¾ãŸã€ã‚ãªãŸã®ã‚¢ã‚¤ãƒ‡ã‚£ã‚¢ã‚’カーãƒãƒ«ã«å¯¾ã—ã¦ã†ã¾ãåˆã‚ã›ã‚‹ã‚ˆ
+ã†ã«ã™ã‚‹ã“ã¨ãŒæœ›ã¾ã‚Œã¦ã„ã¾ã™ã€‚ã‚‚ã—ãã¯ã€æœ€ä½Žé™ã‚ãªãŸã®ã‚¢ã‚¤ãƒ‡ã‚£ã‚¢ãŒãã‚Œ
+ã ã‘ã®ä¾¡å€¤ãŒã‚ã‚‹ã¨ã™ã™ã‚“ã§è¨¼æ˜Žã™ã‚‹ã‚ˆã†ã«ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。
+æ­£ã—ã„解決ã«å‘ã‹ã£ã¦é€²ã‚‚ã†ã¨ã„ã†æ„å¿—ãŒã‚ã‚‹é™ã‚Šã€é–“é•ã†ã“ã¨ãŒã‚ã£ã¦ã‚‚許
+容ã•ã‚Œã‚‹ã“ã¨ã‚’忘れãªã„ã§ãã ã•ã„。
+
+ã‚ãªãŸã®æœ€åˆã®ãƒ‘ッãƒã«å˜ã« 1ダースもã®ä¿®æ­£ã‚’求ã‚るリストã®è¿”ç­”ã«ãªã‚‹ã“
+ã¨ã‚‚普通ã®ã“ã¨ã§ã™ã€‚ã“ã‚Œã¯ã‚ãªãŸã®ãƒ‘ッãƒãŒå—ã‘入れられãªã„ã¨ã„ã†ã“ã¨ã§
+㯠*ã‚ã‚Šã¾ã›ã‚“*ã€ãã—ã¦ã‚ãªãŸè‡ªèº«ã«å対ã™ã‚‹ã“ã¨ã‚’æ„味ã™ã‚‹ã®ã§ã‚‚ *ã‚ã‚Šã¾
+ã›ã‚“*。å˜ã«è‡ªåˆ†ã®ãƒ‘ッãƒã«å¯¾ã—ã¦æŒ‡æ‘˜ã•ã‚ŒãŸå•é¡Œã‚’å…¨ã¦ä¿®æ­£ã—ã¦å†é€ã™ã‚Œã°
+ã„ã„ã®ã§ã™ã€‚
+
+カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨ä¼æ¥­çµ„ç¹”ã®ã¡ãŒã„
+-----------------------------------------------------------------
+
+カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯å¤§éƒ¨åˆ†ã®ä¼çµ±çš„ãªä¼šç¤¾ã®é–‹ç™ºç’°å¢ƒã¨ã¯ç•°ã£ãŸã‚„ã‚Šæ–¹ã§
+å‹•ã„ã¦ã„ã¾ã™ã€‚以下ã¯å•é¡Œã‚’é¿ã‘ã‚‹ãŸã‚ã«ã§ãã‚‹ã¨ã‚ˆã„ã“ã¨ã®ã®ãƒªã‚¹ãƒˆã§ã™-
+
+ ã‚ãªãŸã®æ案ã™ã‚‹å¤‰æ›´ã«ã¤ã„ã¦è¨€ã†ã¨ãã®ã†ã¾ã„言ã„方:
+
+ - "ã“ã‚Œã¯è¤‡æ•°ã®å•é¡Œã‚’解決ã—ã¾ã™"
+ - "ã“ã‚Œã¯2000è¡Œã®ã‚³ãƒ¼ãƒ‰ã‚’削除ã—ã¾ã™"
+ - "以下ã®ãƒ‘ッãƒã¯ã€ç§ãŒè¨€ãŠã†ã¨ã—ã¦ã„ã‚‹ã“ã¨ã‚’説明ã™ã‚‹ã‚‚ã®ã§ã™"
+ - "ç§ã¯ã“れを5ã¤ã®ç•°ãªã‚‹ã‚¢ãƒ¼ã‚­ãƒ†ã‚¯ãƒãƒ£ã§ãƒ†ã‚¹ãƒˆã—ãŸã®ã§ã™ãŒ..."
+ - "以下ã¯ä¸€é€£ã®å°ã•ãªãƒ‘ッãƒç¾¤ã§ã™ãŒ..."
+ - "ã“ã‚Œã¯å…¸åž‹çš„ãªãƒžã‚·ãƒ³ã§ã®æ€§èƒ½ã‚’å‘上ã•ã›ã¾ã™.."
+
+ ã‚„ã‚ãŸæ–¹ãŒã„ã„悪ã„言ã„方:
+
+ - ã“ã®ã‚„り方㧠AIX/ptx/Solaris ã§ã¯ã§ããŸã®ã§ã€ã§ãã‚‹ã¯ãšã 
+ - ç§ã¯ã“れを20å¹´ã‚‚ã®é–“ã‚„ã£ã¦ããŸã€ã ã‹ã‚‰
+ - ã“ã‚Œã¯ã€ç§ã®ä¼šç¤¾ãŒé‡‘儲ã‘ã‚’ã™ã‚‹ãŸã‚ã«å¿…è¦ã 
+ - ã“ã‚Œã¯æˆ‘々ã®ã‚¨ãƒ³ã‚¿ãƒ¼ãƒ—ライズå‘ã‘商å“ラインã®ãŸã‚ã§ã‚ã‚‹
+ - ã“れ㯠ç§ãŒè‡ªåˆ†ã®ã‚¢ã‚¤ãƒ‡ã‚£ã‚¢ã‚’記述ã—ãŸã€1000ページã®è¨­è¨ˆè³‡æ–™ã§ã‚ã‚‹
+ - ç§ã¯ã“ã‚Œã«ã¤ã„ã¦ã€6ケ月作業ã—ã¦ã„る。
+ - 以下㯠... ã«é–¢ã™ã‚‹5000è¡Œã®ãƒ‘ッãƒã§ã™
+ - ç§ã¯ç¾åœ¨ã®ãã¡ã‚ƒãã¡ã‚ƒã‚’全部書ãç›´ã—ãŸã€ãã‚ŒãŒä»¥ä¸‹ã§ã™...
+ - ç§ã¯ã€†åˆ‡ãŒã‚ã‚‹ã€ãã®ãŸã‚ã“ã®ãƒ‘ッãƒã¯ä»Šã™ãé©ç”¨ã•ã‚Œã‚‹å¿…è¦ãŒã‚ã‚‹
+
+カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ãŒå¤§éƒ¨åˆ†ã®ä¼çµ±çš„ãªã‚½ãƒ•ãƒˆã‚¦ã‚§ã‚¢ã‚¨ãƒ³ã‚¸ãƒ‹ã‚¢ãƒªãƒ³ã‚°ã®åŠ´
+åƒç’°å¢ƒã¨ç•°ãªã‚‹ã‚‚ã†ä¸€ã¤ã®ç‚¹ã¯ã€ã‚„ã‚Šã¨ã‚Šã«é¡”ã‚’åˆã‚ã›ãªã„ã¨ã„ã†ã“ã¨ã§ã™ã€‚
+email 㨠irc を第一ã®ã‚³ãƒŸãƒ¥ãƒ‹ã‚±ãƒ¼ã‚·ãƒ§ãƒ³ã®å½¢ã¨ã™ã‚‹ä¸€ã¤ã®åˆ©ç‚¹ã¯ã€æ€§åˆ¥ã‚„
+æ°‘æ—ã®å·®åˆ¥ãŒãªã„ã“ã¨ã§ã™ã€‚Linux カーãƒãƒ«ã®è·å ´ç’°å¢ƒã¯å¥³æ€§ã‚„å°‘æ•°æ°‘æ—ã‚’å—
+容ã—ã¾ã™ã€‚ãªãœãªã‚‰ã€email アドレスã«ã‚ˆã£ã¦ã®ã¿ã‚ãªãŸãŒèªè­˜ã•ã‚Œã‚‹ã‹ã‚‰ã§
+ã™ã€‚
+国際的ãªå´é¢ã‹ã‚‰ã‚‚活動領域をå‡ç­‰ã«ã™ã‚‹ã‚ˆã†ã«ã—ã¾ã™ã€‚ãªãœãªã‚‰ã°ã€ã‚ãªãŸ
+ã¯äººã®åå‰ã§æ€§åˆ¥ã‚’想åƒã§ããªã„ã‹ã‚‰ã§ã™ã€‚ã‚る男性㌠アンドレアã¨ã„ã†å
+å‰ã§ã€å¥³æ€§ã®åå‰ã¯ パット ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“ (訳注 Andrea ã¯ç±³å›½ã§ã¯å¥³æ€§ã€
+ãれ以外(欧州ãªã©)ã§ã¯ç”·æ€§åã¨ã—ã¦ä½¿ã‚れるã“ã¨ãŒå¤šã„。åŒæ§˜ã«ã€Pat ã¯
+Patricia (主ã«å¥³æ€§å)ã‚„ Patrick (主ã«ç”·æ€§å)ã®ç•¥ç§°)。
+Linux カーãƒãƒ«ã®æ´»å‹•ã‚’ã—ã¦ã€æ„見を表明ã—ãŸã“ã¨ãŒã‚る大部分ã®å¥³æ€§ã¯ã€å‰
+å‘ããªçµŒé¨“ã‚’ã‚‚ã£ã¦ã„ã¾ã™ã€‚
+
+言葉ã®å£ã¯è‹±èªžãŒå¾—æ„ã§ãªã„一部ã®äººã«ã¯å•é¡Œã«ãªã‚Šã¾ã™ã€‚
+メーリングリストã®ä¸­ã§ãã¡ã‚“ã¨ã‚¢ã‚¤ãƒ‡ã‚£ã‚¢ã‚’交æ›ã™ã‚‹ã«ã¯ã€ç›¸å½“ã†ã¾ã英語
+ã‚’æ“れる必è¦ãŒã‚ã‚‹ã“ã¨ã‚‚ã‚ã‚Šã¾ã™ã€‚ãã®ãŸã‚ã€ã‚ãªãŸã¯è‡ªåˆ†ã®ãƒ¡ãƒ¼ãƒ«
+ã‚’é€ã‚‹å‰ã«è‹±èªžã§æ„味ãŒé€šã˜ã¦ã„ã‚‹ã‹ã‚’ãƒã‚§ãƒƒã‚¯ã™ã‚‹ã“ã¨ã‚’ãŠè–¦ã‚ã—ã¾ã™ã€‚
+
+変更を分割ã™ã‚‹
+---------------------
+
+Linux カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ä¸€åº¦ã«å¤§é‡ã®ã‚³ãƒ¼ãƒ‰ã®å¡Šã‚’喜んã§å—容ã™ã‚‹ã“
+ã¨ã¯ã‚ã‚Šã¾ã›ã‚“。変更ã¯æ­£ç¢ºã«èª¬æ˜Žã•ã‚Œã‚‹å¿…è¦ãŒã‚ã‚Šã€è­°è«–ã•ã‚Œã€å°ã•ã„ã€å€‹
+別ã®éƒ¨åˆ†ã«åˆ†å‰²ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã“ã‚Œã¯ã“ã‚Œã¾ã§å¤šãã®ä¼šç¤¾ãŒã‚„り慣れã¦
+ããŸã“ã¨ã¨å…¨ãæ­£å対ã®ã“ã¨ã§ã™ã€‚ã‚ãªãŸã®ãƒ—ロãƒãƒ¼ã‚¶ãƒ«ã¯ã€é–‹ç™ºãƒ—ロセスã®ã¨
+ã¦ã‚‚æ—©ã„段階ã‹ã‚‰ç´¹ä»‹ã•ã‚Œã‚‹ã¹ãã§ã™ã€‚ãã†ã™ã‚Œã° ã‚ãªãŸã¯è‡ªåˆ†ã®ã‚„ã£ã¦ã„
+ã‚‹ã“ã¨ã«ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’得られã¾ã™ã€‚ã“ã‚Œã¯ã€ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã‹ã‚‰ã¿ã‚Œã°ã€ã‚
+ãªãŸãŒå½¼ã‚‰ã¨ä¸€ç·’ã«ã‚„ã£ã¦ã„るよã†ã«æ„Ÿã˜ã‚‰ã‚Œã€å˜ã«ã‚ãªãŸã®æ案ã™ã‚‹æ©Ÿèƒ½ã®
+ゴミæ¨ã¦å ´ã¨ã—ã¦ä½¿ã£ã¦ã„ã‚‹ã®ã§ã¯ãªã„ã€ã¨æ„Ÿã˜ã‚‰ã‚Œã‚‹ã§ã—ょã†ã€‚
+ã—ã‹ã—ã€ä¸€åº¦ã« 50 ã‚‚ã® email をメーリングリストã«é€ã‚Šã¤ã‘るよã†ãªã“ã¨ã¯
+ã‚„ã£ã¦ã¯ã„ã‘ã¾ã›ã‚“ã€ã‚ãªãŸã®ãƒ‘ッãƒç¾¤ã¯ã„ã¤ã‚‚ã©ã‚“ãªæ™‚ã§ã‚‚ãれよりã¯å°ã•
+ããªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。
+
+パッãƒã‚’分割ã™ã‚‹ç†ç”±ã¯ä»¥ä¸‹ã§ã™-
+
+1) å°ã•ã„パッãƒã¯ã‚ãªãŸã®ãƒ‘ッãƒãŒé©ç”¨ã•ã‚Œã‚‹è¦‹è¾¼ã¿ã‚’大ããã—ã¾ã™ã€ã‚«ãƒ¼
+ ãƒãƒ«ã®äººé”ã¯ãƒ‘ッãƒãŒæ­£ã—ã„ã‹ã©ã†ã‹ã‚’確èªã™ã‚‹æ™‚間や労力をã‹ã‘ãªã„ã‹
+ らã§ã™ã€‚5è¡Œã®ãƒ‘ッãƒã¯ãƒ¡ãƒ³ãƒ†ãƒŠãŒãŸã£ãŸ1秒見るã ã‘ã§é©ç”¨ã§ãã¾ã™ã€‚ã—
+ ã‹ã—ã€500è¡Œã®ãƒ‘ッãƒã¯ã€æ­£ã—ã„ã“ã¨ã‚’レビューã™ã‚‹ã®ã«æ•°æ™‚é–“ã‹ã‹ã‚‹ã‹ã‚‚
+ ã—ã‚Œã¾ã›ã‚“(時間ã¯ãƒ‘ッãƒã®ã‚µã‚¤ã‚ºãªã©ã«ã‚ˆã‚ŠæŒ‡æ•°é–¢æ•°ã«æ¯”例ã—ã¦ã‹ã‹ã‚Šã¾
+ ã™)
+ å°ã•ã„パッãƒã¯ä½•ã‹ã‚ã£ãŸã¨ãã«ãƒ‡ãƒãƒƒã‚°ã‚‚ã¨ã¦ã‚‚ç°¡å˜ã«ãªã‚Šã¾ã™ã€‚パッ
+ ãƒã‚’1個1個å–り除ãã®ã¯ã€ã¨ã¦ã‚‚大ããªãƒ‘ッãƒã‚’当ã¦ãŸå¾Œã«(ã‹ã¤ã€ä½•ã‹ãŠ
+ ã‹ã—ããªã£ãŸå¾Œã§)解剖ã™ã‚‹ã®ã«æ¯”ã¹ã‚Œã°ã¨ã¦ã‚‚ç°¡å˜ã§ã™ã€‚
+
+2) å°ã•ã„パッãƒã‚’é€ã‚‹ã ã‘ã§ãªãã€é€ã‚‹ã¾ãˆã«ã€æ›¸ãç›´ã—ã¦ã€ã‚·ãƒ³ãƒ—ルã«ã™
+ ã‚‹(ã‚‚ã—ãã¯ã€å˜ã«é †ç•ªã‚’変ãˆã‚‹ã ã‘ã§ã‚‚)ã“ã¨ã‚‚ã€ã¨ã¦ã‚‚é‡è¦ã§ã™ã€‚
+
+以下ã¯ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…ã® Al Viro ã®ãŸã¨ãˆè©±ã—ã§ã™ï¼š
+
+ "生徒ã®æ•°å­¦ã®å®¿é¡Œã‚’採点ã™ã‚‹å…ˆç”Ÿã®ã“ã¨ã‚’考ãˆã¦ã¿ã¦ãã ã•ã„ã€å…ˆ
+ 生ã¯ç”Ÿå¾’ãŒè§£ã«åˆ°é”ã™ã‚‹ã¾ã§ã®è©¦è¡ŒéŒ¯èª¤ã‚’ã¿ãŸã„ã¨ã¯æ€ã‚ãªã„ã§ã—ょ
+ ã†ã€‚先生ã¯ç°¡æ½”ãªæœ€é«˜ã®è§£ã‚’ã¿ãŸã„ã®ã§ã™ã€‚良ã„生徒ã¯ã“れを知ã£ã¦
+ ãŠã‚Šã€ãã—ã¦æœ€çµ‚解ã®å‰ã®ä¸­é–“作業をæ出ã™ã‚‹ã“ã¨ã¯æ±ºã—ã¦ãªã„ã®ã§
+ ã™"
+ カーãƒãƒ«é–‹ç™ºã§ã‚‚ã“ã‚Œã¯åŒã˜ã§ã™ã€‚メンテナーé”ã¨ãƒ¬ãƒ“ューアé”ã¯ã€
+ å•é¡Œã‚’解決ã™ã‚‹è§£ã®èƒŒå¾Œã«ãªã‚‹æ€è€ƒãƒ—ロセスをã¿ãŸã„ã¨ã¯æ€ã„ã¾ã›ã‚“。
+ 彼らã¯å˜ç´”ã§ã‚ã–ã‚„ã‹ãªè§£æ±ºæ–¹æ³•ã‚’ã¿ãŸã„ã®ã§ã™ã€‚
+
+ã‚ã–ã‚„ã‹ãªè§£ã‚’説明ã™ã‚‹ã®ã¨ã€ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¨å…±ã«ä»•äº‹ã‚’ã—ã€æœªè§£æ±ºã®ä»•äº‹ã‚’
+è­°è«–ã™ã‚‹ã“ã¨ã®ãƒãƒ©ãƒ³ã‚¹ã‚’キープã™ã‚‹ã®ã¯é›£ã—ã„ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“。
+ã§ã™ã‹ã‚‰ã€é–‹ç™ºãƒ—ロセスã®æ—©æœŸæ®µéšŽã§æ”¹å–„ã®ãŸã‚ã®ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’もらã†ã‚ˆ
+ã†ã«ã™ã‚‹ã®ã‚‚ã„ã„ã§ã™ãŒã€å¤‰æ›´ç‚¹ã‚’å°ã•ã„部分ã«åˆ†å‰²ã—ã¦å…¨ä½“ã§ã¯ã¾ã å®Œæˆã—
+ã¦ã„ãªã„仕事を(部分的ã«)å–り込んã§ã‚‚らãˆã‚‹ã‚ˆã†ã«ã™ã‚‹ã“ã¨ã‚‚ã„ã„ã“ã¨ã§ã™ã€‚
+
+ã¾ãŸã€ã§ã上ãŒã£ã¦ã„ãªã„ã‚‚ã®ã‚„ã€"å°†æ¥ç›´ã™" よã†ãªãƒ‘ッãƒã‚’ã€æœ¬æµã«å«ã‚
+ã¦ã‚‚らã†ã‚ˆã†ã«é€ã£ã¦ã‚‚ã€ãã‚Œã¯å—ã‘付ã‘られãªã„ã“ã¨ã‚’ç†è§£ã—ã¦ãã ã•ã„。
+
+ã‚ãªãŸã®å¤‰æ›´ã‚’正当化ã™ã‚‹
+-------------------
+
+ã‚ãªãŸã®ãƒ‘ッãƒã‚’分割ã™ã‚‹ã®ã¨åŒæ™‚ã«ã€ãªãœãã®å¤‰æ›´ã‚’追加ã—ãªã‘ã‚Œã°ãªã‚‰ãª
+ã„ã‹ã‚’ Linux コミュニティã«çŸ¥ã‚‰ã›ã‚‹ã“ã¨ã¯ã¨ã¦ã‚‚é‡è¦ã§ã™ã€‚新機能ã¯å¿…è¦
+性ã¨æœ‰ç”¨æ€§ã§æ­£å½“化ã•ã‚Œãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。
+
+ã‚ãªãŸã®å¤‰æ›´ã®èª¬æ˜Ž
+--------------------
+
+ã‚ãªãŸã®ãƒ‘ッãƒã‚’é€ä»˜ã™ã‚‹å ´åˆã«ã¯ã€ãƒ¡ãƒ¼ãƒ«ã®ä¸­ã®ãƒ†ã‚­ã‚¹ãƒˆã§ä½•ã‚’言ã†ã‹ã«ã¤
+ã„ã¦ã€ç‰¹åˆ¥ã«æ³¨æ„を払ã£ã¦ãã ã•ã„。ã“ã®æƒ…å ±ã¯ãƒ‘ッãƒã® ChangeLog ã«ä½¿ã‚
+ã‚Œã€ã„ã¤ã‚‚皆ãŒã¿ã‚‰ã‚Œã‚‹ã‚ˆã†ã«ä¿ç®¡ã•ã‚Œã¾ã™ã€‚ã“ã‚Œã¯æ¬¡ã®ã‚ˆã†ãªé …目をå«ã‚ã€
+パッãƒã‚’完全ã«è¨˜è¿°ã™ã‚‹ã¹ãã§ã™-
+
+ - ãªãœå¤‰æ›´ãŒå¿…è¦ã‹
+ - パッãƒå…¨ä½“ã®è¨­è¨ˆã‚¢ãƒ—ローãƒ
+ - 実装ã®è©³ç´°
+ - テストçµæžœ
+
+ã“ã‚Œã«ã¤ã„ã¦å…¨ã¦ãŒã©ã®ã‚ˆã†ã«ã‚ã‚‹ã¹ãã‹ã«ã¤ã„ã¦ã®è©³ç´°ã¯ã€ä»¥ä¸‹ã®ãƒ‰ã‚­ãƒ¥ãƒ¡
+ント㮠ChangeLog セクションをã¿ã¦ãã ã•ã„-
+ "The Perfect Patch"
+ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+
+ã“れらã®ã©ã‚Œã‚‚ãŒã€æ™‚ã«ã¯ã¨ã¦ã‚‚困難ã§ã™ã€‚ã“れらã®æ…£ä¾‹ã‚’完璧ã«å®Ÿæ–½ã™ã‚‹ã«
+ã¯æ•°å¹´ã‹ã‹ã‚‹ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“。ã“ã‚Œã¯ç¶™ç¶šçš„ãªæ”¹å–„ã®ãƒ—ロセスã§ã‚ã‚Šã€ãã®ãŸ
+ã‚ã«ã¯å¤šæ•°ã®å¿è€ã¨æ±ºæ„ã‚’å¿…è¦ã¨ã™ã‚‹ã‚‚ã®ã§ã™ã€‚ã§ã‚‚ã€è«¦ã‚ãªã„ã§ã€ã“ã‚Œã¯å¯
+能ãªã“ã¨ã§ã™ã€‚多数ã®äººãŒã™ã§ã«ã§ãã¦ã„ã¾ã™ã—ã€å½¼ã‚‰ã‚‚皆最åˆã¯ã‚ãªãŸã¨åŒ
+ã˜ã¨ã“ã‚ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã—ãŸã®ã§ã™ã‹ã‚‰ã€‚
+
+Paolo Ciarrocchi ã«æ„Ÿè¬ã€å½¼ã¯å½¼ã®æ›¸ã„㟠"Development Process"
+(http://linux.tar.bz/articles/2.6-development_process)セクショ
+ンをã“ã®ãƒ†ã‚­ã‚¹ãƒˆã®åŽŸåž‹ã«ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¦ãã‚Œã¾ã—ãŸã€‚
+Rundy Dunlap 㨠Gerrit Huizenga ã¯ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã§ã‚„ã‚‹ã¹ãã“ã¨ã¨ã‚„ã£
+ã¦ã¯ã„ã‘ãªã„ã“ã¨ã®ãƒªã‚¹ãƒˆã‚’æä¾›ã—ã¦ãã‚Œã¾ã—ãŸã€‚
+以下ã®äººã€…ã®ãƒ¬ãƒ“ューã€ã‚³ãƒ¡ãƒ³ãƒˆã€è²¢çŒ®ã«æ„Ÿè¬ã€‚
+Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers,
+Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, Andrew Morton, Andi
+Kleen, Vadim Lobanov, Jesper Juhl, Adrian Bunk, Keri Harris, Frans Pop,
+David A. Wheeler, Junio Hamano, Michael Kerrisk, 㨠Alex Shepard
+彼らã®æ”¯æ´ãªã—ã§ã¯ã€ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã¯ã§ããªã‹ã£ãŸã§ã—ょã†ã€‚
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Documentation/ja_JP/stable_api_nonsense.txt b/Documentation/ja_JP/stable_api_nonsense.txt
new file mode 100644
index 000000000000..b3f2b27f0881
--- /dev/null
+++ b/Documentation/ja_JP/stable_api_nonsense.txt
@@ -0,0 +1,263 @@
+NOTE:
+This is a Japanese translated version of
+"Documentation/stable_api_nonsense.txt".
+This one is maintained by
+IKEDA, Munehiro <m-ikeda@ds.jp.nec.com>
+and JF Project team <http://www.linux.or.jp/JF/>.
+If you find difference with original file or problem in translation,
+please contact the maintainer of this file or JF project.
+
+Please also note that purpose of this file is easier to read for non
+English natives and not to be intended to fork. So, if you have any
+comments or updates of this file, please try to update
+Original(English) file at first.
+
+==================================
+ã“ã‚Œã¯ã€
+linux-2.6.22-rc4/Documentation/stable_api_nonsense.txt ã®å’Œè¨³
+ã§ã™ã€‚
+翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
+翻訳日 : 2007/06/11
+原著作者: Greg Kroah-Hartman < greg at kroah dot com >
+翻訳者 : 池田 宗広 < m-ikeda at ds dot jp dot nec dot com >
+校正者 : Masanori Kobayashi ã•ã‚“ < zap03216 at nifty dot ne dot jp >
+ Seiji Kaneko ã•ã‚“ < skaneko at a2 dot mbn dot or dot jp >
+==================================
+
+
+
+Linux カーãƒãƒ«ã®ãƒ‰ãƒ©ã‚¤ãƒã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹
+(ã‚ãªãŸã®è³ªå•ã™ã¹ã¦ã«å¯¾ã™ã‚‹å›žç­”ã¨ãã®ä»–諸々)
+
+Greg Kroah-Hartman <greg at kroah dot com>
+
+
+ã“ã®æ–‡æ›¸ã¯ã€ãªãœ Linux ã§ã¯ãƒã‚¤ãƒŠãƒªã‚«ãƒ¼ãƒãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ãŒå®šç¾©
+ã•ã‚Œã¦ã„ãªã„ã®ã‹ã€ã¾ãŸã¯ãªãœä¸å¤‰ã®ã‚«ãƒ¼ãƒãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã‚’æŒãŸãª
+ã„ã®ã‹ã€ã¨ã„ã†ã“ã¨ã‚’説明ã™ã‚‹ãŸã‚ã«æ›¸ã‹ã‚ŒãŸã€‚ã“ã“ã§ã®è©±é¡Œã¯ã€Œã‚«ãƒ¼ãƒ
+ル内部ã®ã€ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã«ã¤ã„ã¦ã§ã‚ã‚Šã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ç©ºé–“ã¨ã®ã‚¤ãƒ³ã‚¿ãƒ¼
+フェースã§ã¯ãªã„ã“ã¨ã‚’ç†è§£ã—ã¦ã»ã—ã„。カーãƒãƒ«ã¨ãƒ¦ãƒ¼ã‚¶ãƒ¼ç©ºé–“ã¨ã®ã‚¤
+ンターフェースã¨ã¯ã‚¢ãƒ—リケーションプログラムãŒä½¿ç”¨ã™ã‚‹ã‚‚ã®ã§ã‚ã‚Šã€
+ã¤ã¾ã‚Šã‚·ã‚¹ãƒ†ãƒ ã‚³ãƒ¼ãƒ«ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ãŒã“ã‚Œã«å½“ãŸã‚‹ã€‚ã“ã‚Œã¯ä»Šã¾ã§
+é•·ãã«æ¸¡ã‚Šã€ã‹ã¤ä»Šå¾Œã‚‚「ã¾ã•ã—ãã€ä¸å¤‰ã§ã‚る。ç§ã¯ç¢ºã‹ 0.9 ã‹ä½•ã‹
+よりå‰ã®ã‚«ãƒ¼ãƒãƒ«ã‚’使ã£ã¦ãƒ“ルドã—ãŸå¤ã„プログラムをæŒã£ã¦ã„ã‚‹ãŒã€ã
+ã‚Œã¯æœ€æ–°ã® 2.6 カーãƒãƒ«ã§ã‚‚ãã¡ã‚“ã¨å‹•ä½œã™ã‚‹ã€‚ユーザー空間ã¨ã®ã‚¤ãƒ³
+ターフェースã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¨ã‚¢ãƒ—リケーションプログラマãŒä¸å¤‰æ€§ã‚’ä¿¡é ¼
+ã—ã¦ã‚ˆã„ã‚‚ã®ã®ä¸€ã¤ã§ã‚る。
+
+
+è¦æ—¨
+----
+
+ã‚ãªãŸã¯ä¸å¤‰ã®ã‚«ãƒ¼ãƒãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ãŒå¿…è¦ã ã¨è€ƒãˆã¦ã„ã‚‹ã‹ã‚‚ã—ã‚Œ
+ãªã„ãŒã€å®Ÿéš›ã®ã¨ã“ã‚ã¯ãã†ã§ã¯ãªã„。ã‚ãªãŸã¯å¿…è¦ã¨ã—ã¦ã„ã‚‹ã‚‚ã®ãŒåˆ†
+ã‹ã£ã¦ã„ãªã„。ã‚ãªãŸãŒå¿…è¦ã¨ã—ã¦ã„ã‚‹ã‚‚ã®ã¯å®‰å®šã—ã¦å‹•ä½œã™ã‚‹ãƒ‰ãƒ©ã‚¤ãƒ
+ã§ã‚ã‚Šã€ãã‚Œã¯ãƒ‰ãƒ©ã‚¤ãƒãŒãƒ¡ã‚¤ãƒ³ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã«å«ã¾ã‚Œã‚‹å ´åˆã®ã¿å¾—
+ã‚‹ã“ã¨ãŒã§ãる。ドライãƒãŒãƒ¡ã‚¤ãƒ³ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã«å«ã¾ã‚Œã¦ã„ã‚‹ã¨ã€
+ä»–ã«ã‚‚多ãã®è‰¯ã„ã“ã¨ãŒã‚る。ãã‚Œã¯ã€Linux をより強固ã§ã€å®‰å®šãªã€æˆ
+熟ã—ãŸã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°ã‚·ã‚¹ãƒ†ãƒ ã«ã™ã‚‹ã“ã¨ãŒã§ãã‚‹ã¨ã„ã†ã“ã¨ã ã€‚ã“ã‚Œ
+ã“ãã€ãã‚‚ãã‚‚ã‚ãªãŸãŒ Linux を使ã†ç†ç”±ã®ã¯ãšã ã€‚
+
+
+ã¯ã˜ã‚ã«
+--------
+
+カーãƒãƒ«å†…部ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹å¤‰æ›´ã‚’心é…ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„ドライãƒ
+を書ããŸã„ãªã©ã¨ã„ã†ã®ã¯ã€å¤‰ã‚り者ã ã‘ã ã€‚ã“ã®ä¸–ç•Œã®ã»ã¨ã‚“ã©ã®äººã¯ã€
+ãã®ã‚ˆã†ãªãƒ‰ãƒ©ã‚¤ãƒãŒã©ã‚“ãªã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã‚’使ã£ã¦ã„ã‚‹ã‹ãªã©çŸ¥ã‚‰ãª
+ã„ã—ã€ãã‚“ãªãƒ‰ãƒ©ã‚¤ãƒã®ã“ã¨ãªã©å…¨ãæ°—ã«ã‚‚ã‹ã‘ã¦ã„ãªã„。
+
+
+ã¾ãšåˆã‚ã«ã€ã‚¯ãƒ­ãƒ¼ã‚ºã‚½ãƒ¼ã‚¹ã¨ã‹ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã®éš è”½ã¨ã‹ã€ãƒã‚¤ãƒŠãƒªã®
+ã¿ãŒé…布ã•ã‚Œã‚‹ä½¿ã„物ã«ãªã‚‰ãªã„代物[訳注(1)]ã¨ã‹ã€å®Ÿä½“ã¯ãƒã‚¤ãƒŠãƒª
+コードã§ãれを読ã¿è¾¼ã‚€ãŸã‚ã®ãƒ©ãƒƒãƒ‘ー部分ã®ã¿ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ãŒå…¬é–‹ã•ã‚Œ
+ã¦ã„ã‚‹ã¨ã‹ã€ãã®ä»–用語ã¯ä½•ã§ã‚ã‚Œ GPL ã®ä¸‹ã«ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ãŒãƒªãƒªãƒ¼ã‚¹
+ã•ã‚Œã¦ã„ãªã„カーãƒãƒ«ãƒ‰ãƒ©ã‚¤ãƒã«é–¢ã™ã‚‹æ³•çš„ãªå•é¡Œã«ã¤ã„ã¦ã€ç§ã¯ã€Œã„ã‹
+ãªã‚‹è­°è«–ã‚‚ã€è¡Œã†ã¤ã‚‚ã‚ŠãŒãªã„。法的ãªç–‘å•ãŒã‚ã‚‹ã®ãªã‚‰ã°ã€ãƒ—ログラマ
+ã§ã‚ã‚‹ç§ã§ã¯ãªãã€å¼è­·å£«ã«ç›¸è«‡ã—ã¦æ¬²ã—ã„。ã“ã“ã§ã¯å˜ã«ã€æŠ€è¡“çš„ãªå•
+é¡Œã«ã¤ã„ã¦è¿°ã¹ã‚‹ã“ã¨ã«ã™ã‚‹ã€‚(法的ãªå•é¡Œã‚’軽視ã—ã¦ã„ã‚‹ã‚ã‘ã§ã¯ãªã„。
+ãれらã¯å®Ÿéš›ã«å­˜åœ¨ã™ã‚‹ã—ã€ã‚ãªãŸã¯ãれをã„ã¤ã‚‚æ°—ã«ã‹ã‘ã¦ãŠãå¿…è¦ãŒ
+ã‚る)
+
+訳注(1)
+「使ã„物ã«ãªã‚‰ãªã„代物ã€ã®åŽŸæ–‡ã¯ "blob"
+
+
+ã•ã¦ã“ã“ã§ã¯ã€ãƒã‚¤ãƒŠãƒªã‚«ãƒ¼ãƒãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã«ã¤ã„ã¦ã¨ã€ã‚½ãƒ¼ã‚¹ãƒ¬
+ベルã§ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã®ä¸å¤‰æ€§ã«ã¤ã„ã¦ã€ã¨ã„ã†äºŒã¤ã®è©±é¡Œã‚’å–り上
+ã’る。ã“ã®äºŒã¤ã¯äº’ã„ã«ä¾å­˜ã™ã‚‹é–¢ä¿‚ã«ã‚ã‚‹ãŒã€ã¾ãšã¯ãƒã‚¤ãƒŠãƒªã‚¤ãƒ³ã‚¿ãƒ¼
+フェースã«ã¤ã„ã¦è­°è«–ã‚’è¡Œã„ã‚„ã£ã¤ã‘ã¦ã—ã¾ãŠã†ã€‚
+
+
+ãƒã‚¤ãƒŠãƒªã‚«ãƒ¼ãƒãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹
+--------------------------------
+
+ã‚‚ã—ソースレベルã§ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ãŒä¸å¤‰ãªã‚‰ã°ã€ãƒã‚¤ãƒŠãƒªã‚¤ãƒ³ã‚¿ãƒ¼
+フェースも当然ã®ã‚ˆã†ã«ä¸å¤‰ã§ã‚ã‚‹ã€ã¨ã„ã†ã®ã¯æ­£ã—ã„ã ã‚ã†ã‹ï¼Ÿæ­£ã—ã
+ãªã„。Linux カーãƒãƒ«ã«é–¢ã™ã‚‹ä»¥ä¸‹ã®äº‹å®Ÿã‚’考ãˆã¦ã¿ã¦ã»ã—ã„。
+ - ã‚ãªãŸãŒä½¿ç”¨ã™ã‚‹ï¼£ã‚³ãƒ³ãƒ‘イラã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«ã‚ˆã£ã¦ã€ã‚«ãƒ¼ãƒãƒ«å†…部
+ ã®æ§‹é€ ä½“ã®é…置構造ã¯ç•°ãªã£ãŸã‚‚ã®ã«ãªã‚‹ã€‚ã¾ãŸã€é–¢æ•°ã¯ç•°ãªã£ãŸæ–¹
+ 法ã§ã‚«ãƒ¼ãƒãƒ«ã«å«ã¾ã‚Œã‚‹ã“ã¨ã«ãªã‚‹ã‹ã‚‚ã—ã‚Œãªã„(例ãˆã°ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³
+ 関数ã¨ã—ã¦æ‰±ã‚ã‚ŒãŸã‚Šã€æ‰±ã‚ã‚Œãªã‹ã£ãŸã‚Šã™ã‚‹ï¼‰ã€‚個々ã®é–¢æ•°ãŒã©ã®
+ よã†ã«ã‚³ãƒ³ãƒ‘イルã•ã‚Œã‚‹ã‹ã¯ãã‚Œã»ã©é‡è¦ã§ã¯ãªã„ãŒã€æ§‹é€ ä½“ã®ãƒ‘デ
+ ィングãŒç•°ãªã‚‹ã¨ã„ã†ã®ã¯éžå¸¸ã«é‡è¦ã§ã‚る。
+ - ã‚ãªãŸãŒã‚«ãƒ¼ãƒãƒ«ã®ãƒ“ルドオプションをã©ã®ã‚ˆã†ã«è¨­å®šã™ã‚‹ã‹ã«ã‚ˆã£
+ ã¦ã€ã‚«ãƒ¼ãƒãƒ«ã«ã¯åºƒã„範囲ã§ç•°ãªã£ãŸäº‹æ…‹ãŒèµ·ã“り得る。
+ - データ構造ã¯ç•°ãªã‚‹ãƒ‡ãƒ¼ã‚¿ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’æŒã¤ã‹ã‚‚ã—ã‚Œãªã„
+ - ã„ãã¤ã‹ã®é–¢æ•°ã¯å…¨ã実装ã•ã‚Œã¦ã„ãªã„状態ã«ãªã‚Šå¾—ã‚‹
+ (例:SMPå‘ã‘ã§ã¯ãªã„ビルドã§ã¯ã€ã„ãã¤ã‹ã®ãƒ­ãƒƒã‚¯ã¯ä¸­èº«ãŒ
+ カラã«ã‚³ãƒ³ãƒ‘イルã•ã‚Œã‚‹ï¼‰
+ - カーãƒãƒ«å†…ã®ãƒ¡ãƒ¢ãƒªã¯ã€ç•°ãªã£ãŸæ–¹æ³•ã§é…ç½®ã•ã‚Œå¾—る。ã“ã‚Œã¯ãƒ“
+ ルドオプションã«ä¾å­˜ã—ã¦ã„る。
+ - Linux ã¯æ§˜ã€…ãªç•°ãªã‚‹ãƒ—ロセッサアーキテクãƒãƒ£ä¸Šã§å‹•ä½œã™ã‚‹ã€‚
+ ã‚るアーキテクãƒãƒ£ç”¨ã®ãƒã‚¤ãƒŠãƒªãƒ‰ãƒ©ã‚¤ãƒã‚’ã€ä»–ã®ã‚¢ãƒ¼ã‚­ãƒ†ã‚¯ãƒãƒ£ã§
+ 正常ã«å‹•ä½œã•ã›ã‚‹æ–¹æ³•ã¯ãªã„。
+
+
+ã‚る特定ã®ã‚«ãƒ¼ãƒãƒ«è¨­å®šã‚’使用ã—ã€ã‚«ãƒ¼ãƒãƒ«ã‚’ビルドã—ãŸã®ã¨æ­£ç¢ºã«åŒã˜
+Cコンパイラを使用ã—ã¦å˜ã«ã‚«ãƒ¼ãƒãƒ«ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’コンパイルã™ã‚‹ã ã‘ã§
+ã‚‚ã€ã‚ãªãŸã¯ã“れらã„ãã¤ã‚‚ã®å•é¡Œã«ç›´é¢ã™ã‚‹ã“ã¨ã«ãªã‚‹ã€‚ã‚る特定ã®
+Linux ディストリビューションã®ã€ã‚る特定ã®ãƒªãƒªãƒ¼ã‚¹ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç”¨ã«ãƒ¢
+ジュールをæä¾›ã—よã†ã¨æ€ã£ãŸã ã‘ã§ã‚‚ã€ã“れらã®å•é¡Œã‚’引ãèµ·ã“ã™ã«ã¯
+å分ã§ã‚る。ã«ã‚‚é–¢ã‚ら㚠Linux ディストリビューションã®æ•°ã¨ã€ã‚µ
+ãƒãƒ¼ãƒˆã™ã‚‹ãƒ‡ã‚£ã‚¹ãƒˆãƒªãƒ“ューションã®ãƒªãƒªãƒ¼ã‚¹æ•°ã‚’掛ã‘ç®—ã—ã€ãれら一ã¤
+一ã¤ã«ã¤ã„ã¦ãƒ“ルドを行ã£ãŸã¨ã—ãŸã‚‰ã€ä»Šåº¦ã¯ãƒªãƒªãƒ¼ã‚¹ã”ã¨ã®ãƒ“ルドオプ
+ションã®é•ã„ã¨ã„ã†æ‚ªå¤¢ã«ã™ãã•ã¾æ‚©ã¾ã•ã‚Œã‚‹ã“ã¨ã«ãªã‚‹ã€‚ã¾ãŸã€ãƒ‡ã‚£ã‚¹
+トリビューションã®å„リリースãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«ã¯ã€ç•°ãªã‚‹ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ï¼ˆãƒ—
+ロセッサタイプや種々ã®ã‚ªãƒ—ション)ã«å¯¾å¿œã™ã‚‹ãŸã‚ã€ä½•ç¨®é¡žã‹ã®ã‚«ãƒ¼ãƒ
+ルãŒå«ã¾ã‚Œã¦ã„ã‚‹ã¨ã„ã†ã“ã¨ã‚‚ç†è§£ã—ã¦æ¬²ã—ã„。従ã£ã¦ã€ã‚る一ã¤ã®ãƒª
+リースãƒãƒ¼ã‚¸ãƒ§ãƒ³ã ã‘ã®ãŸã‚ã«ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’作æˆã™ã‚‹å ´åˆã§ã‚‚ã€ã‚ãªãŸã¯
+何ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚‚ã®ãƒ¢ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’用æ„ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„。
+
+
+ä¿¡ã˜ã¦æ¬²ã—ã„。ã“ã®ã‚ˆã†ãªæ–¹æ³•ã§ã‚µãƒãƒ¼ãƒˆã‚’続ã‘よã†ã¨ã™ã‚‹ãªã‚‰ã€ã‚ãªãŸ
+ã¯ã„ãšã‚Œæ­£æ°—を失ã†ã ã‚ã†ã€‚é ã„昔ã€ç§ã¯ãã‚ŒãŒã„ã‹ã«å›°é›£ãªã“ã¨ã‹ã€èº«
+ã‚’ã‚‚ã£ã¦å­¦ã‚“ã ã®ã ãƒ»ãƒ»ãƒ»
+
+
+ä¸å¤‰ã®ã‚«ãƒ¼ãƒãƒ«ã‚½ãƒ¼ã‚¹ãƒ¬ãƒ™ãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹
+------------------------------------------
+
+メインカーãƒãƒ«ãƒ„リーã«å«ã¾ã‚Œã¦ã„ãªã„ Linux カーãƒãƒ«ãƒ‰ãƒ©ã‚¤ãƒã‚’継続
+ã—ã¦ã‚µãƒãƒ¼ãƒˆã—ã¦ã„ã“ã†ã¨ã—ã¦ã„る人ãŸã¡ã¨ã®è­°è«–ã«ãŠã„ã¦ã¯ã€ã“ã‚Œã¯æ¥µ
+ã‚ã¦ã€Œå¼•ç«æ€§ã®é«˜ã„ã€è©±é¡Œã§ã‚る。[訳注(2)]
+
+訳注(2)
+「引ç«æ€§ã®é«˜ã„ã€ã®åŽŸæ–‡ã¯ "volatile"。
+volatile ã«ã¯ã€Œæ®ç™ºæ€§ã®ã€ã€Œçˆ†ç™ºã—ã‚„ã™ã„ã€ã¨ã„ã†æ„味ã®ä»–ã€ã€Œå¤‰ã‚ã‚Š
+ã‚„ã™ã„ã€ã€Œç§»ã‚Šæ°—ãªã€ã¨ã„ã†æ„味ãŒã‚る。
+「(ã“ã®è©±é¡Œã¯ï¼‰çˆ†ç™ºçš„ã«æ¿€ã—ã„論争を巻ãèµ·ã“ã—ã‹ã­ãªã„ã€ã¨ã„ã†ã“ã¨
+ã‚’ã€ã€Œï¼ˆã‚«ãƒ¼ãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ãƒ¬ãƒ™ãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã¯ï¼‰ç§»ã‚ã„è¡Œãã‚‚ã®ã§
+ã‚ã‚‹ã€ã¨ã„ã†ã“ã¨ã‚’連想ã•ã›ã‚‹ "volatile" ã¨ã„ã†å˜èªžã§è¡¨ç¾ã—ã¦ã„る。
+
+
+Linux カーãƒãƒ«ã®é–‹ç™ºã¯ç¶™ç¶šçš„ã«é€Ÿã„ペースã§è¡Œã‚ã‚Œã€æ±ºã—ã¦æ­©ã¿ã‚’ç·©ã‚
+ã‚‹ã“ã¨ãŒãªã„。ãã®ä¸­ã§ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºè€…é”ã¯ã€ç¾çŠ¶ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã«
+ã‚ã‚‹ãƒã‚°ã‚’見ã¤ã‘ã€ã‚ˆã‚Šè‰¯ã„方法を考ãˆå‡ºã™ã€‚彼らã¯ã‚„ãŒã¦ã€ç¾çŠ¶ã®ã‚¤ãƒ³
+ターフェースãŒã‚ˆã‚Šæ­£ã—ã動作ã™ã‚‹ã‚ˆã†ã«ä¿®æ­£ã‚’è¡Œã†ã€‚ãã®éŽç¨‹ã§é–¢æ•°ã®
+åå‰ã¯å¤‰æ›´ã•ã‚Œã‚‹ã‹ã‚‚ã—ã‚Œãšã€æ§‹é€ ä½“ã¯å¤§ããã€ã¾ãŸã¯å°ã•ããªã‚‹ã‹ã‚‚ã—
+ã‚Œãšã€é–¢æ•°ã®å¼•æ•°ã¯æ¤œè¨Žã—ãªãŠã•ã‚Œã‚‹ã‹ã‚‚ã—ã‚Œãªã„。ãã®ã‚ˆã†ãªå ´åˆã€å¼•
+ã続ãå…¨ã¦ãŒæ­£å¸¸ã«å‹•ä½œã™ã‚‹ã‚ˆã†ã€ã‚«ãƒ¼ãƒãƒ«å†…ã§ã“れらã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼
+スを使用ã—ã¦ã„る個所も全ã¦åŒæ™‚ã«ä¿®æ­£ã•ã‚Œã‚‹ã€‚
+
+
+具体的ãªä¾‹ã¨ã—ã¦ã€ã‚«ãƒ¼ãƒãƒ«å†…ã® USB インターフェースを挙ã’る。USB
+サブシステムã¯ã“ã‚Œã¾ã§ã«å°‘ãªãã¨ã‚‚3回ã®æ›¸ãç›´ã—ãŒè¡Œã‚ã‚Œã€ãã®çµæžœ
+インターフェースãŒå¤‰æ›´ã•ã‚ŒãŸã€‚ã“れらã®æ›¸ãç›´ã—ã¯ã„ãã¤ã‹ã®ç•°ãªã£ãŸ
+å•é¡Œã‚’修正ã™ã‚‹ãŸã‚ã«è¡Œã‚ã‚ŒãŸã€‚
+ - åŒæœŸçš„データストリームãŒéžåŒæœŸã«å¤‰æ›´ã•ã‚ŒãŸã€‚ã“ã‚Œã«ã‚ˆã‚Šå¤šæ•°ã®ãƒ‰
+ ライãƒã‚’å˜ç´”化ã§ãã€å…¨ã¦ã®ãƒ‰ãƒ©ã‚¤ãƒã®ã‚¹ãƒ«ãƒ¼ãƒ—ットãŒå‘上ã—ãŸã€‚今
+ ã‚„ã»ã¨ã‚“ã©å…¨ã¦ã® USB デãƒã‚¤ã‚¹ã¯ã€è€ƒãˆã‚‰ã‚Œã‚‹æœ€é«˜ã®é€Ÿåº¦ã§å‹•ä½œã—
+ ã¦ã„る。
+ - USB ドライãƒãŒ USB サブシステムã®ã‚³ã‚¢ã‹ã‚‰è¡Œã†ã€ãƒ‡ãƒ¼ã‚¿ãƒ‘ケット
+ 用ã®ãƒ¡ãƒ¢ãƒªç¢ºä¿æ–¹æ³•ãŒå¤‰æ›´ã•ã‚ŒãŸã€‚ã“ã‚Œã«ä¼´ã„ã€ã„ãã¤ã‚‚ã®æ–‡æ›¸åŒ–ã•
+ ã‚ŒãŸãƒ‡ãƒƒãƒ‰ãƒ­ãƒƒã‚¯æ¡ä»¶ã‚’回é¿ã™ã‚‹ãŸã‚ã€å…¨ã¦ã® USB ドライãƒã¯ã‚ˆã‚Š
+ 多ãã®æƒ…報を USB コアã«æä¾›ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„よã†ã«ãªã£ã¦ã„る。
+
+
+ã“ã®ã§ãã”ã¨ã¯ã€æ•°å¤šã存在ã™ã‚‹ã‚¯ãƒ­ãƒ¼ã‚ºã‚½ãƒ¼ã‚¹ã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°ã‚·ã‚¹
+テムã¨ã¯å…¨ã対照的ã ã€‚ãれらã¯é•·æœŸã«æ¸¡ã‚Šå¤ã„ USB インターフェース
+をメンテナンスã—ãªã‘ã‚Œã°ãªã‚‰ãªã„。å¤ã„インターフェースãŒæ®‹ã‚‹ã“ã¨ã§ã€
+æ–°ãŸãªé–‹ç™ºè€…ãŒå¶ç„¶å¤ã„インターフェースを使ã„ã€æ­£ã—ããªã„方法ã§é–‹ç™º
+ã‚’è¡Œã£ã¦ã—ã¾ã†å¯èƒ½æ€§ãŒç”Ÿã˜ã‚‹ã€‚ã“ã‚Œã«ã‚ˆã‚Šã‚·ã‚¹ãƒ†ãƒ ã®å®‰å®šæ€§ã¯å±é™ºã«ã•
+らã•ã‚Œã‚‹ã“ã¨ã«ãªã‚‹ã€‚
+
+
+上ã«æŒ™ã’ãŸã©ã¡ã‚‰ã®ä¾‹ã«ãŠã„ã¦ã‚‚ã€é–‹ç™ºè€…é”ã¯ãã®å¤‰æ›´ãŒé‡è¦ã‹ã¤å¿…è¦ã§
+ã‚ã‚‹ã“ã¨ã«åˆæ„ã—ã€æ¯”較的楽ã«ãれを実行ã—ãŸã€‚ã‚‚ã— Linux ãŒã‚½ãƒ¼ã‚¹ãƒ¬
+ベルã§ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã®ä¸å¤‰æ€§ã‚’ä¿è¨¼ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„ã¨ã—ãŸã‚‰ã€æ–°
+ã—ã„インターフェースを作るã¨åŒæ™‚ã«ã€å¤ã„ã€å•é¡Œã®ã‚る方を今後ã¨ã‚‚メ
+ンテナンスã™ã‚‹ã¨ã„ã†ä½™è¨ˆãªä»•äº‹ã‚’ USB ã®é–‹ç™ºè€…ã«ã•ã›ãªã‘ã‚Œã°ãªã‚‰ãª
+ã„。Linux ã® USB 開発者ã¯ã€è‡ªåˆ†ã®æ™‚間を使ã£ã¦ä»•äº‹ã‚’ã—ã¦ã„る。よã£
+ã¦ã€ä¾¡å€¤ã®ãªã„余計ãªä»•äº‹ã‚’報酬もãªã—ã«å®Ÿè¡Œã—ã‚ã¨è¨€ã†ã“ã¨ã¯ã§ããªã„。
+
+
+セキュリティå•é¡Œã‚‚ã€Linux ã«ã¨ã£ã¦ã¯éžå¸¸ã«é‡è¦ã§ã‚る。ã²ã¨ãŸã³ã‚»ã‚­
+ュリティã«é–¢ã™ã‚‹å•é¡ŒãŒç™ºè¦‹ã•ã‚Œã‚Œã°ã€ãã‚Œã¯æ¥µã‚ã¦çŸ­æœŸé–“ã®ã†ã¡ã«ä¿®æ­£
+ã•ã‚Œã‚‹ã€‚セキュリティå•é¡Œã®ç™ºç”Ÿã‚’防ããŸã‚ã®ä¿®æ­£ã¯ã€ã‚«ãƒ¼ãƒãƒ«ã®å†…部イ
+ンターフェースã®å¤‰æ›´ã‚’何度も引ãèµ·ã“ã—ã¦ããŸã€‚ãã®éš›åŒæ™‚ã«ã€å¤‰æ›´ã•
+ã‚ŒãŸã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã‚’使用ã™ã‚‹å…¨ã¦ã®ãƒ‰ãƒ©ã‚¤ãƒã‚‚ã¾ãŸå¤‰æ›´ã•ã‚ŒãŸã€‚ã“ã‚Œ
+ã«ã‚ˆã‚Šå•é¡ŒãŒè§£æ¶ˆã—ã€å°†æ¥å¶ç„¶ã«å•é¡ŒãŒå†ç™ºã—ã¦ã—ã¾ã‚ãªã„ã“ã¨ãŒä¿è¨¼ã•
+れる。もã—内部インターフェースã®å¤‰æ›´ãŒè¨±ã•ã‚Œãªã„ã¨ã—ãŸã‚‰ã€ã“ã®ã‚ˆã†
+ã«ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£å•é¡Œã‚’修正ã—ã€å°†æ¥å†ç™ºã—ãªã„ã“ã¨ã‚’ä¿è¨¼ã™ã‚‹ã“ã¨ãªã©ä¸
+å¯èƒ½ãªã®ã ã€‚
+
+
+カーãƒãƒ«ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã¯æ™‚ãŒçµŒã¤ã«ã¤ã‚Œã‚¯ãƒªãƒ¼ãƒ³ãƒŠãƒƒãƒ—ã‚’å—ã‘る。
+誰も使ã£ã¦ã„ãªã„インターフェースã¯å‰Šé™¤ã•ã‚Œã‚‹ã€‚ã“ã‚Œã«ã‚ˆã‚Šã€å¯èƒ½ãªé™
+りカーãƒãƒ«ãŒå°ã•ãä¿ãŸã‚Œã€ç¾å½¹ã®å…¨ã¦ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ãŒå¯èƒ½ãªé™ã‚Š
+テストã•ã‚Œã‚‹ã“ã¨ã‚’ä¿è¨¼ã—ã¦ã„ã‚‹ã®ã ã€‚(使ã‚ã‚Œã¦ã„ãªã„インターフェー
+スã®å¦¥å½“性をテストã™ã‚‹ã“ã¨ã¯ä¸å¯èƒ½ã¨è¨€ã£ã¦ã„ã„ã ã‚ã†ï¼‰
+
+
+
+ã“ã‚Œã‹ã‚‰ä½•ã‚’ã™ã¹ãã‹
+-----------------------
+
+ã§ã¯ã€ã‚‚ã—メインã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã«å«ã¾ã‚Œãªã„ Linux カーãƒãƒ«ãƒ‰ãƒ©ã‚¤
+ãƒãŒã‚ã£ãŸã¨ã—ã¦ã€ã‚ãªãŸã¯ã€ã¤ã¾ã‚Šé–‹ç™ºè€…ã¯ä½•ã‚’ã™ã‚‹ã¹ãã ã‚ã†ã‹ï¼Ÿå…¨
+ã¦ã®ãƒ‡ã‚£ã‚¹ãƒˆãƒªãƒ“ューションã®å…¨ã¦ã®ã‚«ãƒ¼ãƒãƒ«ãƒãƒ¼ã‚¸ãƒ§ãƒ³å‘ã‘ã«ãƒã‚¤ãƒŠãƒª
+ã®ãƒ‰ãƒ©ã‚¤ãƒã‚’供給ã™ã‚‹ã“ã¨ã¯æ‚ªå¤¢ã§ã‚ã‚Šã€ã‚«ãƒ¼ãƒãƒ«ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã®å¤‰
+更を追ã„ã‹ã‘続ã‘ã‚‹ã“ã¨ã‚‚ã¾ãŸéŽé…·ãªä»•äº‹ã ã€‚
+
+
+ç­”ãˆã¯ç°¡å˜ã€‚ãã®ãƒ‰ãƒ©ã‚¤ãƒã‚’メインã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã«å…¥ã‚Œã¦ã—ã¾ãˆã°ã‚ˆ
+ã„。(ã“ã“ã§è¨€åŠã—ã¦ã„ã‚‹ã®ã¯ã€GPL ã«å¾“ã£ã¦å…¬é–‹ã•ã‚Œã‚‹ãƒ‰ãƒ©ã‚¤ãƒã®ã“ã¨
+ã ã¨ã„ã†ã“ã¨ã«æ³¨æ„ã—ã¦ã»ã—ã„。ã‚ãªãŸã®ã‚³ãƒ¼ãƒ‰ãŒãã‚Œã«è©²å½“ã—ãªã„ãªã‚‰
+ã°ã€ã•ã‚ˆãªã‚‰ã€‚幸é‹ã‚’祈りã¾ã™ã€‚ã”自分ã§ä½•ã¨ã‹ã—ã¦ãã ã•ã„。Andrew
+㨠Linus ã‹ã‚‰ã®ã‚³ãƒ¡ãƒ³ãƒˆï¼œAndrew 㨠Linus ã®ã‚³ãƒ¡ãƒ³ãƒˆã¸ã®ãƒªãƒ³ã‚¯ã‚’ã“
+ã“ã«ç½®ã>をã©ã†ãžï¼‰ãƒ‰ãƒ©ã‚¤ãƒãŒãƒ¡ã‚¤ãƒ³ãƒ„リーã«å…¥ã‚Œã°ã€ã‚«ãƒ¼ãƒãƒ«ã®ã‚¤ãƒ³
+ターフェースãŒå¤‰æ›´ã•ã‚ŒãŸå ´åˆã€å¤‰æ›´ã‚’è¡Œã£ãŸé–‹ç™ºè€…ã«ã‚ˆã£ã¦ãƒ‰ãƒ©ã‚¤ãƒã‚‚
+修正ã•ã‚Œã‚‹ã“ã¨ã«ãªã‚‹ã ã‚ã†ã€‚ã‚ãªãŸã¯ã»ã¨ã‚“ã©åŠ´åŠ›ã‚’払ã†ã“ã¨ãªã—ã«ã€
+常ã«ãƒ“ルドå¯èƒ½ã§ãã¡ã‚“ã¨å‹•ä½œã™ã‚‹ãƒ‰ãƒ©ã‚¤ãƒã‚’手ã«å…¥ã‚Œã‚‹ã“ã¨ãŒã§ãる。
+
+
+ドライãƒã‚’メインã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã«å…¥ã‚Œã‚‹ã¨ã€éžå¸¸ã«å¥½ã¾ã—ã„以下ã®åŠ¹
+æžœãŒã‚る。
+ - ドライãƒã®å“質ãŒå‘上ã™ã‚‹ä¸€æ–¹ã§ã€ï¼ˆå…ƒã®é–‹ç™ºè€…ã«ã¨ã£ã¦ã®ï¼‰ãƒ¡ãƒ³ãƒ†
+ ナンスコストã¯ä¸‹ãŒã‚‹ã€‚
+ - ã‚ãªãŸã®ãƒ‰ãƒ©ã‚¤ãƒã«ä»–ã®é–‹ç™ºè€…ãŒæ©Ÿèƒ½ã‚’追加ã—ã¦ãれる。
+ - 誰ã‹ãŒã‚ãªãŸã®ãƒ‰ãƒ©ã‚¤ãƒã«ã‚ã‚‹ãƒã‚°ã‚’見ã¤ã‘ã€ä¿®æ­£ã—ã¦ãれる。
+ - 誰ã‹ãŒã‚ãªãŸã®ãƒ‰ãƒ©ã‚¤ãƒã«ã‚る改善点を見ã¤ã‘ã¦ãれる。
+ - 外部インターフェースãŒå¤‰æ›´ã•ã‚Œãƒ‰ãƒ©ã‚¤ãƒã®æ›´æ–°ãŒå¿…è¦ã«ãªã£ãŸå ´åˆã€
+ 誰ã‹ãŒã‚ãªãŸã®ä»£ã‚ã‚Šã«æ›´æ–°ã—ã¦ãれる。
+ - ドライãƒã‚’入れã¦ãã‚Œã¨ãƒ‡ã‚£ã‚¹ãƒˆãƒ­ã«é ¼ã¾ãªãã¦ã‚‚ã€ãã®ãƒ‰ãƒ©ã‚¤ãƒã¯
+ å…¨ã¦ã® Linux ディストリビューションã«è‡ªå‹•çš„ã«å«ã¾ã‚Œã¦ãƒªãƒªãƒ¼ã‚¹
+ ã•ã‚Œã‚‹ã€‚
+
+
+Linux ã§ã¯ã€ä»–ã®ã©ã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚°ã‚·ã‚¹ãƒ†ãƒ ã‚ˆã‚Šã‚‚数多ãã®ãƒ‡ãƒã‚¤ã‚¹
+ãŒã€Œãã®ã¾ã¾ã€ä½¿ç”¨ã§ãるよã†ã«ãªã£ãŸã€‚ã¾ãŸ Linux ã¯ã€ã©ã®ã‚ªãƒšãƒ¬ãƒ¼
+ティングシステムよりも数多ãã®ãƒ—ロセッサアーキテクãƒãƒ£ä¸Šã§ãれらã®
+デãƒã‚¤ã‚¹ã‚’使用ã™ã‚‹ã“ã¨ãŒã§ãるよã†ã«ã‚‚ãªã£ãŸã€‚ã“ã®ã‚ˆã†ã«ã€Linux ã®
+開発モデルã¯å®Ÿè¨¼ã•ã‚Œã¦ãŠã‚Šã€ä»Šå¾Œã‚‚é–“é•ã„ãªãæ­£ã—ã„æ–¹å‘ã¸ã¨é€²ã‚“ã§ã„
+ãã ã‚ã†ã€‚:)
+
+
+
+------
+
+ã“ã®æ–‡æ›¸ã®åˆæœŸã®è‰ç¨¿ã«å¯¾ã—ã€Randy Dunlap, Andrew Morton, David
+Brownell, Hanna Linder, Robert Love, Nishanth Aravamudan ã‹ã‚‰æŸ»èª­
+ã¨åŠ©è¨€ã‚’é ‚ãã¾ã—ãŸã€‚æ„Ÿè¬ç”³ã—上ã’ã¾ã™ã€‚
+
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index bb5306e9a5c3..e08ef8759a07 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -501,6 +501,20 @@ more details, with real examples.
The third parameter may be a text as in this example, but it may also
be an expanded variable or a macro.
+ cc-fullversion
+ cc-fullversion is useful when the exact version of gcc is needed.
+ One typical use-case is when a specific GCC version is broken.
+ cc-fullversion points out a more specific version than cc-version does.
+
+ Example:
+ #arch/powerpc/Makefile
+ $(Q)if test "$(call cc-fullversion)" = "040200" ; then \
+ echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
+ false ; \
+ fi
+
+ In this example for a specific GCC version the build will error out explaining
+ to the user why it stops.
=== 4 Host Program support
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4d880b3d1f35..fb80e9ffea68 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -34,7 +34,6 @@ parameter is applicable:
APIC APIC support is enabled.
APM Advanced Power Management support is enabled.
AX25 Appropriate AX.25 support is enabled.
- CD Appropriate CD support is enabled.
DRM Direct Rendering Management support is enabled.
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
EFI EFI Partitioning (GPT) is enabled
@@ -238,16 +237,9 @@ and is between 256 and 4096 characters. It is defined in the file
Disable PIN 1 of APIC timer
Can be useful to work around chipset bugs.
- ad1816= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma2>
- See also Documentation/sound/oss/AD1816.
-
ad1848= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2>,<type>
- adlib= [HW,OSS]
- Format: <io>
-
advansys= [HW,SCSI]
See header of drivers/scsi/advansys.c.
@@ -326,9 +318,6 @@ and is between 256 and 4096 characters. It is defined in the file
autotest [IA64]
- aztcd= [HW,CD] Aztech CD268 CDROM driver
- Format: <io>,0x79 (?)
-
baycom_epp= [HW,AX25]
Format: <io>,<mode>
@@ -371,10 +360,6 @@ and is between 256 and 4096 characters. It is defined in the file
possible to determine what the correct size should be.
This option provides an override for these situations.
- cdu31a= [HW,CD]
- Format: <io>,<irq>[,PAS]
- See header of drivers/cdrom/cdu31a.c.
-
chandev= [HW,NET] Generic channel device initialisation
checkreqprot [SELINUX] Set initial checkreqprot flag value.
@@ -428,9 +413,6 @@ and is between 256 and 4096 characters. It is defined in the file
hpet= [IA-32,HPET] option to disable HPET and use PIT.
Format: disable
- cm206= [HW,CD]
- Format: { auto | [<io>,][<irq>] }
-
com20020= [HW,NET] ARCnet - COM20020 chipset
Format:
<io>[,<irq>[,<nodeID>[,<backplane>[,<ckp>[,<timeout>]]]]]
@@ -462,13 +444,20 @@ and is between 256 and 4096 characters. It is defined in the file
Documentation/networking/netconsole.txt for an
alternative.
- uart,io,<addr>[,options]
- uart,mmio,<addr>[,options]
+ uart[8250],io,<addr>[,options]
+ uart[8250],mmio,<addr>[,options]
Start an early, polled-mode console on the 8250/16550
UART at the specified I/O port or MMIO address,
switching to the matching ttyS device later. The
options are the same as for ttyS, above.
+ earlycon= [KNL] Output early console device and options.
+ uart[8250],io,<addr>[,options]
+ uart[8250],mmio,<addr>[,options]
+ Start an early, polled-mode console on the 8250/16550
+ UART at the specified I/O port or MMIO address.
+ The options are the same as for ttyS, above.
+
cpcihp_generic= [HW,PCI] Generic port I/O CompactPCI driver
Format:
<first_slot>,<last_slot>,<port>,<enum_bit>[,<debug>]
@@ -660,9 +649,6 @@ and is between 256 and 4096 characters. It is defined in the file
gpt [EFI] Forces disk with valid GPT signature but
invalid Protective MBR to be treated as GPT.
- gscd= [HW,CD]
- Format: <io>
-
gvp11= [HW,SCSI]
hashdist= [KNL,NUMA] Large hashes allocated during boot
@@ -826,14 +812,37 @@ and is between 256 and 4096 characters. It is defined in the file
tasks in the system -- can cause problems and
suboptimal load balancer performance.
- isp16= [HW,CD]
- Format: <io>,<irq>,<dma>,<setup>
-
iucv= [HW,NET]
js= [HW,JOY] Analog joystick
See Documentation/input/joystick.txt.
+ kernelcore=nn[KMG] [KNL,IA-32,IA-64,PPC,X86-64] This parameter
+ specifies the amount of memory usable by the kernel
+ for non-movable allocations. The requested amount is
+ spread evenly throughout all nodes in the system. The
+ remaining memory in each node is used for Movable
+ pages. In the event, a node is too small to have both
+ kernelcore and Movable pages, kernelcore pages will
+ take priority and other nodes will have a larger number
+ of kernelcore pages. The Movable zone is used for the
+ allocation of pages that may be reclaimed or moved
+ by the page migration subsystem. This means that
+ HugeTLB pages may not be allocated from this zone.
+ Note that allocations like PTEs-from-HighMem still
+ use the HighMem zone if it exists, and the Normal
+ zone if it does not.
+
+ movablecore=nn[KMG] [KNL,IA-32,IA-64,PPC,X86-64] This parameter
+ is similar to kernelcore except it specifies the
+ amount of memory used for migratable allocations.
+ If both kernelcore and movablecore is specified,
+ then kernelcore will be at *least* the specified
+ value but may be more. If movablecore on its own
+ is specified, the administrator must be careful
+ that the amount of memory usable for all allocations
+ is not too small.
+
keepinitrd [HW,ARM]
kstack=N [IA-32,X86-64] Print N words from the kernel stack
@@ -967,11 +976,6 @@ and is between 256 and 4096 characters. It is defined in the file
mcatest= [IA-64]
- mcd= [HW,CD]
- Format: <port>,<irq>,<mitsumi_bug_93_wait>
-
- mcdx= [HW,CD]
-
mce [IA-32] Machine Check Exception
md= [HW] RAID subsystems devices and level
@@ -1150,6 +1154,8 @@ and is between 256 and 4096 characters. It is defined in the file
nointroute [IA-64]
+ nojitter [IA64] Disables jitter checking for ITC timers.
+
nolapic [IA-32,APIC] Do not enable or use the local APIC.
nolapic_timer [IA-32,APIC] Do not use the local APIC timer.
@@ -1181,6 +1187,8 @@ and is between 256 and 4096 characters. It is defined in the file
nosmp [SMP] Tells an SMP kernel to act as a UP kernel.
+ nosoftlockup [KNL] Disable the soft-lockup detector.
+
nosync [HW,M68K] Disables sync negotiation for all devices.
notsc [BUGS=IA-32] Disable Time Stamp Counter
@@ -1189,20 +1197,19 @@ and is between 256 and 4096 characters. It is defined in the file
nowb [ARM]
+ numa_zonelist_order= [KNL, BOOT] Select zonelist order for NUMA.
+ one of ['zone', 'node', 'default'] can be specified
+ This can be set from sysctl after boot.
+ See Documentation/sysctl/vm.txt for details.
+
nr_uarts= [SERIAL] maximum number of UARTs to be registered.
opl3= [HW,OSS]
Format: <io>
- opl3sa2= [HW,OSS] Format:
- <io>,<irq>,<dma>,<dma2>,<mss_io>,<mpu_io>,<ymode>,<loopback>[,<isapnp>,<multiple]
-
oprofile.timer= [HW]
Use timer interrupt instead of performance counters
- optcd= [HW,CD]
- Format: <io>
-
osst= [HW,SCSI] SCSI Tape Driver
Format: <buffer_size>,<write_threshold>
See also Documentation/scsi/st.txt.
@@ -1381,6 +1388,15 @@ and is between 256 and 4096 characters. It is defined in the file
autoconfiguration.
Ranges are in pairs (memory base and size).
+ print-fatal-signals=
+ [KNL] debug: print fatal signals
+ print-fatal-signals=1: print segfault info to
+ the kernel console.
+ default: off.
+
+ printk.time= Show timing data prefixed to each printk message line
+ Format: <bool> (1/Y/y=enable, 0/N/n=disable)
+
profile= [KNL] Enable kernel profiling via /proc/profile
Format: [schedule,]<number>
Param: "schedule" - profile schedule points.
@@ -1493,6 +1509,10 @@ and is between 256 and 4096 characters. It is defined in the file
rootfstype= [KNL] Set root filesystem type
+ rootwait [KNL] Wait (indefinitely) for root device to show up.
+ Useful for devices that are detected asynchronously
+ (e.g. USB and MMC devices).
+
rw [KNL] Mount root device read-write on boot
S [KNL] Run init in single mode
@@ -1505,11 +1525,6 @@ and is between 256 and 4096 characters. It is defined in the file
sbni= [NET] Granch SBNI12 leased line adapter
- sbpcd= [HW,CD] Soundblaster CD adapter
- Format: <io>,<type>
- See a comment before function sbpcd_setup() in
- drivers/cdrom/sbpcd.c.
-
sc1200wdt= [HW,WDT] SC1200 WDT (watchdog) driver
Format: <io>[,<timeout>[,<isapnp>]]
@@ -1562,41 +1577,41 @@ and is between 256 and 4096 characters. It is defined in the file
simeth= [IA-64]
simscsi=
- sjcd= [HW,CD]
- Format: <io>,<irq>,<dma>
- See header of drivers/cdrom/sjcd.c.
-
slram= [HW,MTD]
- slub_debug [MM, SLUB]
- Enabling slub_debug allows one to determine the culprit
- if slab objects become corrupted. Enabling slub_debug
- creates guard zones around objects and poisons objects
- when not in use. Also tracks the last alloc / free.
- For more information see Documentation/vm/slub.txt.
+ slub_debug[=options[,slabs]] [MM, SLUB]
+ Enabling slub_debug allows one to determine the
+ culprit if slab objects become corrupted. Enabling
+ slub_debug can create guard zones around objects and
+ may poison objects when not in use. Also tracks the
+ last alloc / free. For more information see
+ Documentation/vm/slub.txt.
slub_max_order= [MM, SLUB]
- Determines the maximum allowed order for slabs. Setting
- this too high may cause fragmentation.
- For more information see Documentation/vm/slub.txt.
+ Determines the maximum allowed order for slabs.
+ A high setting may cause OOMs due to memory
+ fragmentation. For more information see
+ Documentation/vm/slub.txt.
slub_min_objects= [MM, SLUB]
- The minimum objects per slab. SLUB will increase the
- slab order up to slub_max_order to generate a
- sufficiently big slab to satisfy the number of objects.
- The higher the number of objects the smaller the overhead
- of tracking slabs.
+ The minimum number of objects per slab. SLUB will
+ increase the slab order up to slub_max_order to
+ generate a sufficiently large slab able to contain
+ the number of objects indicated. The higher the number
+ of objects the smaller the overhead of tracking slabs
+ and the less frequently locks need to be acquired.
For more information see Documentation/vm/slub.txt.
slub_min_order= [MM, SLUB]
Determines the mininum page order for slabs. Must be
- lower than slub_max_order
+ lower than slub_max_order.
For more information see Documentation/vm/slub.txt.
slub_nomerge [MM, SLUB]
- Disable merging of slabs of similar size. May be
+ Disable merging of slabs with similar size. May be
necessary if there is some reason to distinguish
- allocs to different slabs.
+ allocs to different slabs. Debug options disable
+ merging on their own.
For more information see Documentation/vm/slub.txt.
smart2= [HW]
@@ -1738,9 +1753,6 @@ and is between 256 and 4096 characters. It is defined in the file
snd-ymfpci= [HW,ALSA]
- sonycd535= [HW,CD]
- Format: <io>[,<irq>]
-
sonypi.*= [HW] Sony Programmable I/O Control Device driver
See Documentation/sonypi.txt
@@ -1812,6 +1824,7 @@ and is between 256 and 4096 characters. It is defined in the file
Set number of hash buckets for TCP connection
time Show timing data prefixed to each printk message line
+ [deprecated, see 'printk.time']
tipar.timeout= [HW,PPT]
Set communications timeout in tenths of a second
@@ -1869,11 +1882,14 @@ and is between 256 and 4096 characters. It is defined in the file
usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at.
- vdso= [IA-32,SH]
+ vdso= [IA-32,SH,x86-64]
vdso=2: enable compat VDSO (default with COMPAT_VDSO)
vdso=1: enable VDSO (default)
vdso=0: disable VDSO mapping
+ vector= [IA-64,SMP]
+ vector=percpu: enable percpu vector domain
+
video= [FB] Frame buffer configuration
See Documentation/fb/modedb.txt.
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index da5404ab7569..cb12ae175aa2 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -247,12 +247,6 @@ control to Kprobes.) If the probed function is declared asmlinkage,
fastcall, or anything else that affects how args are passed, the
handler's declaration must match.
-NOTE: A macro JPROBE_ENTRY is provided to handle architecture-specific
-aliasing of jp->entry. In the interest of portability, it is advised
-to use:
-
- jp->entry = JPROBE_ENTRY(handler);
-
register_jprobe() returns 0 on success, or a negative errno otherwise.
4.3 register_kretprobe
@@ -518,7 +512,7 @@ long jdo_fork(unsigned long clone_flags, unsigned long stack_start,
}
static struct jprobe my_jprobe = {
- .entry = JPROBE_ENTRY(jdo_fork)
+ .entry = jdo_fork
};
static int __init jprobe_init(void)
diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile
new file mode 100644
index 000000000000..b9b9427376e9
--- /dev/null
+++ b/Documentation/lguest/Makefile
@@ -0,0 +1,27 @@
+# This creates the demonstration utility "lguest" which runs a Linux guest.
+
+# For those people that have a separate object dir, look there for .config
+KBUILD_OUTPUT := ../..
+ifdef O
+ ifeq ("$(origin O)", "command line")
+ KBUILD_OUTPUT := $(O)
+ endif
+endif
+# We rely on CONFIG_PAGE_OFFSET to know where to put lguest binary.
+include $(KBUILD_OUTPUT)/.config
+LGUEST_GUEST_TOP := ($(CONFIG_PAGE_OFFSET) - 0x08000000)
+
+CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 \
+ -static -DLGUEST_GUEST_TOP="$(LGUEST_GUEST_TOP)" -Wl,-T,lguest.lds
+LDLIBS:=-lz
+
+all: lguest.lds lguest
+
+# The linker script on x86 is so complex the only way of creating one
+# which will link our binary in the right place is to mangle the
+# default one.
+lguest.lds:
+ $(LD) --verbose | awk '/^==========/ { PRINT=1; next; } /SIZEOF_HEADERS/ { gsub(/0x[0-9A-F]*/, "$(LGUEST_GUEST_TOP)") } { if (PRINT) print $$0; }' > $@
+
+clean:
+ rm -f lguest.lds lguest
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
new file mode 100644
index 000000000000..1432b502a2d9
--- /dev/null
+++ b/Documentation/lguest/lguest.c
@@ -0,0 +1,1012 @@
+/* Simple program to layout "physical" memory for new lguest guest.
+ * Linked high to avoid likely physical memory. */
+#define _LARGEFILE64_SOURCE
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <time.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <linux/sockios.h>
+#include <linux/if_tun.h>
+#include <sys/uio.h>
+#include <termios.h>
+#include <getopt.h>
+#include <zlib.h>
+typedef unsigned long long u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+#include "../../include/linux/lguest_launcher.h"
+#include "../../include/asm-i386/e820.h"
+
+#define PAGE_PRESENT 0x7 /* Present, RW, Execute */
+#define NET_PEERNUM 1
+#define BRIDGE_PFX "bridge:"
+#ifndef SIOCBRADDIF
+#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
+#endif
+
+static bool verbose;
+#define verbose(args...) \
+ do { if (verbose) printf(args); } while(0)
+static int waker_fd;
+
+struct device_list
+{
+ fd_set infds;
+ int max_infd;
+
+ struct device *dev;
+ struct device **lastdev;
+};
+
+struct device
+{
+ struct device *next;
+ struct lguest_device_desc *desc;
+ void *mem;
+
+ /* Watch this fd if handle_input non-NULL. */
+ int fd;
+ bool (*handle_input)(int fd, struct device *me);
+
+ /* Watch DMA to this key if handle_input non-NULL. */
+ unsigned long watch_key;
+ u32 (*handle_output)(int fd, const struct iovec *iov,
+ unsigned int num, struct device *me);
+
+ /* Device-specific data. */
+ void *priv;
+};
+
+static int open_or_die(const char *name, int flags)
+{
+ int fd = open(name, flags);
+ if (fd < 0)
+ err(1, "Failed to open %s", name);
+ return fd;
+}
+
+static void *map_zeroed_pages(unsigned long addr, unsigned int num)
+{
+ static int fd = -1;
+
+ if (fd == -1)
+ fd = open_or_die("/dev/zero", O_RDONLY);
+
+ if (mmap((void *)addr, getpagesize() * num,
+ PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0)
+ != (void *)addr)
+ err(1, "Mmaping %u pages of /dev/zero @%p", num, (void *)addr);
+ return (void *)addr;
+}
+
+/* Find magic string marking entry point, return entry point. */
+static unsigned long entry_point(void *start, void *end,
+ unsigned long page_offset)
+{
+ void *p;
+
+ for (p = start; p < end; p++)
+ if (memcmp(p, "GenuineLguest", strlen("GenuineLguest")) == 0)
+ return (long)p + strlen("GenuineLguest") + page_offset;
+
+ err(1, "Is this image a genuine lguest?");
+}
+
+/* Returns the entry point */
+static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
+ unsigned long *page_offset)
+{
+ void *addr;
+ Elf32_Phdr phdr[ehdr->e_phnum];
+ unsigned int i;
+ unsigned long start = -1UL, end = 0;
+
+ /* Sanity checks. */
+ if (ehdr->e_type != ET_EXEC
+ || ehdr->e_machine != EM_386
+ || ehdr->e_phentsize != sizeof(Elf32_Phdr)
+ || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
+ errx(1, "Malformed elf header");
+
+ if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
+ err(1, "Seeking to program headers");
+ if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
+ err(1, "Reading program headers");
+
+ *page_offset = 0;
+ /* We map the loadable segments at virtual addresses corresponding
+ * to their physical addresses (our virtual == guest physical). */
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_type != PT_LOAD)
+ continue;
+
+ verbose("Section %i: size %i addr %p\n",
+ i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
+
+ /* We expect linear address space. */
+ if (!*page_offset)
+ *page_offset = phdr[i].p_vaddr - phdr[i].p_paddr;
+ else if (*page_offset != phdr[i].p_vaddr - phdr[i].p_paddr)
+ errx(1, "Page offset of section %i different", i);
+
+ if (phdr[i].p_paddr < start)
+ start = phdr[i].p_paddr;
+ if (phdr[i].p_paddr + phdr[i].p_filesz > end)
+ end = phdr[i].p_paddr + phdr[i].p_filesz;
+
+ /* We map everything private, writable. */
+ addr = mmap((void *)phdr[i].p_paddr,
+ phdr[i].p_filesz,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE,
+ elf_fd, phdr[i].p_offset);
+ if (addr != (void *)phdr[i].p_paddr)
+ err(1, "Mmaping vmlinux seg %i gave %p not %p",
+ i, addr, (void *)phdr[i].p_paddr);
+ }
+
+ return entry_point((void *)start, (void *)end, *page_offset);
+}
+
+/* This is amazingly reliable. */
+static unsigned long intuit_page_offset(unsigned char *img, unsigned long len)
+{
+ unsigned int i, possibilities[256] = { 0 };
+
+ for (i = 0; i + 4 < len; i++) {
+ /* mov 0xXXXXXXXX,%eax */
+ if (img[i] == 0xA1 && ++possibilities[img[i+4]] > 3)
+ return (unsigned long)img[i+4] << 24;
+ }
+ errx(1, "could not determine page offset");
+}
+
+static unsigned long unpack_bzimage(int fd, unsigned long *page_offset)
+{
+ gzFile f;
+ int ret, len = 0;
+ void *img = (void *)0x100000;
+
+ f = gzdopen(fd, "rb");
+ while ((ret = gzread(f, img + len, 65536)) > 0)
+ len += ret;
+ if (ret < 0)
+ err(1, "reading image from bzImage");
+
+ verbose("Unpacked size %i addr %p\n", len, img);
+ *page_offset = intuit_page_offset(img, len);
+
+ return entry_point(img, img + len, *page_offset);
+}
+
+static unsigned long load_bzimage(int fd, unsigned long *page_offset)
+{
+ unsigned char c;
+ int state = 0;
+
+ /* Ugly brute force search for gzip header. */
+ while (read(fd, &c, 1) == 1) {
+ switch (state) {
+ case 0:
+ if (c == 0x1F)
+ state++;
+ break;
+ case 1:
+ if (c == 0x8B)
+ state++;
+ else
+ state = 0;
+ break;
+ case 2 ... 8:
+ state++;
+ break;
+ case 9:
+ lseek(fd, -10, SEEK_CUR);
+ if (c != 0x03) /* Compressed under UNIX. */
+ state = -1;
+ else
+ return unpack_bzimage(fd, page_offset);
+ }
+ }
+ errx(1, "Could not find kernel in bzImage");
+}
+
+static unsigned long load_kernel(int fd, unsigned long *page_offset)
+{
+ Elf32_Ehdr hdr;
+
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+ err(1, "Reading kernel");
+
+ if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
+ return map_elf(fd, &hdr, page_offset);
+
+ return load_bzimage(fd, page_offset);
+}
+
+static inline unsigned long page_align(unsigned long addr)
+{
+ return ((addr + getpagesize()-1) & ~(getpagesize()-1));
+}
+
+/* initrd gets loaded at top of memory: return length. */
+static unsigned long load_initrd(const char *name, unsigned long mem)
+{
+ int ifd;
+ struct stat st;
+ unsigned long len;
+ void *iaddr;
+
+ ifd = open_or_die(name, O_RDONLY);
+ if (fstat(ifd, &st) < 0)
+ err(1, "fstat() on initrd '%s'", name);
+
+ len = page_align(st.st_size);
+ iaddr = mmap((void *)mem - len, st.st_size,
+ PROT_READ|PROT_EXEC|PROT_WRITE,
+ MAP_FIXED|MAP_PRIVATE, ifd, 0);
+ if (iaddr != (void *)mem - len)
+ err(1, "Mmaping initrd '%s' returned %p not %p",
+ name, iaddr, (void *)mem - len);
+ close(ifd);
+ verbose("mapped initrd %s size=%lu @ %p\n", name, st.st_size, iaddr);
+ return len;
+}
+
+static unsigned long setup_pagetables(unsigned long mem,
+ unsigned long initrd_size,
+ unsigned long page_offset)
+{
+ u32 *pgdir, *linear;
+ unsigned int mapped_pages, i, linear_pages;
+ unsigned int ptes_per_page = getpagesize()/sizeof(u32);
+
+ /* If we can map all of memory above page_offset, we do so. */
+ if (mem <= -page_offset)
+ mapped_pages = mem/getpagesize();
+ else
+ mapped_pages = -page_offset/getpagesize();
+
+ /* Each linear PTE page can map ptes_per_page pages. */
+ linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;
+
+ /* We lay out top-level then linear mapping immediately below initrd */
+ pgdir = (void *)mem - initrd_size - getpagesize();
+ linear = (void *)pgdir - linear_pages*getpagesize();
+
+ for (i = 0; i < mapped_pages; i++)
+ linear[i] = ((i * getpagesize()) | PAGE_PRESENT);
+
+ /* Now set up pgd so that this memory is at page_offset */
+ for (i = 0; i < mapped_pages; i += ptes_per_page) {
+ pgdir[(i + page_offset/getpagesize())/ptes_per_page]
+ = (((u32)linear + i*sizeof(u32)) | PAGE_PRESENT);
+ }
+
+ verbose("Linear mapping of %u pages in %u pte pages at %p\n",
+ mapped_pages, linear_pages, linear);
+
+ return (unsigned long)pgdir;
+}
+
+static void concat(char *dst, char *args[])
+{
+ unsigned int i, len = 0;
+
+ for (i = 0; args[i]; i++) {
+ strcpy(dst+len, args[i]);
+ strcat(dst+len, " ");
+ len += strlen(args[i]) + 1;
+ }
+ /* In case it's empty. */
+ dst[len] = '\0';
+}
+
+static int tell_kernel(u32 pgdir, u32 start, u32 page_offset)
+{
+ u32 args[] = { LHREQ_INITIALIZE,
+ LGUEST_GUEST_TOP/getpagesize(), /* Just below us */
+ pgdir, start, page_offset };
+ int fd;
+
+ fd = open_or_die("/dev/lguest", O_RDWR);
+ if (write(fd, args, sizeof(args)) < 0)
+ err(1, "Writing to /dev/lguest");
+ return fd;
+}
+
+static void set_fd(int fd, struct device_list *devices)
+{
+ FD_SET(fd, &devices->infds);
+ if (fd > devices->max_infd)
+ devices->max_infd = fd;
+}
+
+/* When input arrives, we tell the kernel to kick lguest out with -EAGAIN. */
+static void wake_parent(int pipefd, int lguest_fd, struct device_list *devices)
+{
+ set_fd(pipefd, devices);
+
+ for (;;) {
+ fd_set rfds = devices->infds;
+ u32 args[] = { LHREQ_BREAK, 1 };
+
+ select(devices->max_infd+1, &rfds, NULL, NULL, NULL);
+ if (FD_ISSET(pipefd, &rfds)) {
+ int ignorefd;
+ if (read(pipefd, &ignorefd, sizeof(ignorefd)) == 0)
+ exit(0);
+ FD_CLR(ignorefd, &devices->infds);
+ } else
+ write(lguest_fd, args, sizeof(args));
+ }
+}
+
+static int setup_waker(int lguest_fd, struct device_list *device_list)
+{
+ int pipefd[2], child;
+
+ pipe(pipefd);
+ child = fork();
+ if (child == -1)
+ err(1, "forking");
+
+ if (child == 0) {
+ close(pipefd[1]);
+ wake_parent(pipefd[0], lguest_fd, device_list);
+ }
+ close(pipefd[0]);
+
+ return pipefd[1];
+}
+
+static void *_check_pointer(unsigned long addr, unsigned int size,
+ unsigned int line)
+{
+ if (addr >= LGUEST_GUEST_TOP || addr + size >= LGUEST_GUEST_TOP)
+ errx(1, "%s:%i: Invalid address %li", __FILE__, line, addr);
+ return (void *)addr;
+}
+#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
+
+/* Returns pointer to dma->used_len */
+static u32 *dma2iov(unsigned long dma, struct iovec iov[], unsigned *num)
+{
+ unsigned int i;
+ struct lguest_dma *udma;
+
+ udma = check_pointer(dma, sizeof(*udma));
+ for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+ if (!udma->len[i])
+ break;
+
+ iov[i].iov_base = check_pointer(udma->addr[i], udma->len[i]);
+ iov[i].iov_len = udma->len[i];
+ }
+ *num = i;
+ return &udma->used_len;
+}
+
+static u32 *get_dma_buffer(int fd, void *key,
+ struct iovec iov[], unsigned int *num, u32 *irq)
+{
+ u32 buf[] = { LHREQ_GETDMA, (u32)key };
+ unsigned long udma;
+ u32 *res;
+
+ udma = write(fd, buf, sizeof(buf));
+ if (udma == (unsigned long)-1)
+ return NULL;
+
+ /* Kernel stashes irq in ->used_len. */
+ res = dma2iov(udma, iov, num);
+ *irq = *res;
+ return res;
+}
+
+static void trigger_irq(int fd, u32 irq)
+{
+ u32 buf[] = { LHREQ_IRQ, irq };
+ if (write(fd, buf, sizeof(buf)) != 0)
+ err(1, "Triggering irq %i", irq);
+}
+
+static void discard_iovec(struct iovec *iov, unsigned int *num)
+{
+ static char discard_buf[1024];
+ *num = 1;
+ iov->iov_base = discard_buf;
+ iov->iov_len = sizeof(discard_buf);
+}
+
+static struct termios orig_term;
+static void restore_term(void)
+{
+ tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
+}
+
+struct console_abort
+{
+ int count;
+ struct timeval start;
+};
+
+/* We DMA input to buffer bound at start of console page. */
+static bool handle_console_input(int fd, struct device *dev)
+{
+ u32 irq = 0, *lenp;
+ int len;
+ unsigned int num;
+ struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+ struct console_abort *abort = dev->priv;
+
+ lenp = get_dma_buffer(fd, dev->mem, iov, &num, &irq);
+ if (!lenp) {
+ warn("console: no dma buffer!");
+ discard_iovec(iov, &num);
+ }
+
+ len = readv(dev->fd, iov, num);
+ if (len <= 0) {
+ warnx("Failed to get console input, ignoring console.");
+ len = 0;
+ }
+
+ if (lenp) {
+ *lenp = len;
+ trigger_irq(fd, irq);
+ }
+
+ /* Three ^C within one second? Exit. */
+ if (len == 1 && ((char *)iov[0].iov_base)[0] == 3) {
+ if (!abort->count++)
+ gettimeofday(&abort->start, NULL);
+ else if (abort->count == 3) {
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ if (now.tv_sec <= abort->start.tv_sec+1) {
+ /* Make sure waker is not blocked in BREAK */
+ u32 args[] = { LHREQ_BREAK, 0 };
+ close(waker_fd);
+ write(fd, args, sizeof(args));
+ exit(2);
+ }
+ abort->count = 0;
+ }
+ } else
+ abort->count = 0;
+
+ if (!len) {
+ restore_term();
+ return false;
+ }
+ return true;
+}
+
+static u32 handle_console_output(int fd, const struct iovec *iov,
+ unsigned num, struct device*dev)
+{
+ return writev(STDOUT_FILENO, iov, num);
+}
+
+static u32 handle_tun_output(int fd, const struct iovec *iov,
+ unsigned num, struct device *dev)
+{
+ /* Now we've seen output, we should warn if we can't get buffers. */
+ *(bool *)dev->priv = true;
+ return writev(dev->fd, iov, num);
+}
+
+static unsigned long peer_offset(unsigned int peernum)
+{
+ return 4 * peernum;
+}
+
+static bool handle_tun_input(int fd, struct device *dev)
+{
+ u32 irq = 0, *lenp;
+ int len;
+ unsigned num;
+ struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+
+ lenp = get_dma_buffer(fd, dev->mem+peer_offset(NET_PEERNUM), iov, &num,
+ &irq);
+ if (!lenp) {
+ if (*(bool *)dev->priv)
+ warn("network: no dma buffer!");
+ discard_iovec(iov, &num);
+ }
+
+ len = readv(dev->fd, iov, num);
+ if (len <= 0)
+ err(1, "reading network");
+ if (lenp) {
+ *lenp = len;
+ trigger_irq(fd, irq);
+ }
+ verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
+ ((u8 *)iov[0].iov_base)[0], ((u8 *)iov[0].iov_base)[1],
+ lenp ? "sent" : "discarded");
+ return true;
+}
+
+static u32 handle_block_output(int fd, const struct iovec *iov,
+ unsigned num, struct device *dev)
+{
+ struct lguest_block_page *p = dev->mem;
+ u32 irq, *lenp;
+ unsigned int len, reply_num;
+ struct iovec reply[LGUEST_MAX_DMA_SECTIONS];
+ off64_t device_len, off = (off64_t)p->sector * 512;
+
+ device_len = *(off64_t *)dev->priv;
+
+ if (off >= device_len)
+ err(1, "Bad offset %llu vs %llu", off, device_len);
+ if (lseek64(dev->fd, off, SEEK_SET) != off)
+ err(1, "Bad seek to sector %i", p->sector);
+
+ verbose("Block: %s at offset %llu\n", p->type ? "WRITE" : "READ", off);
+
+ lenp = get_dma_buffer(fd, dev->mem, reply, &reply_num, &irq);
+ if (!lenp)
+ err(1, "Block request didn't give us a dma buffer");
+
+ if (p->type) {
+ len = writev(dev->fd, iov, num);
+ if (off + len > device_len) {
+ ftruncate(dev->fd, device_len);
+ errx(1, "Write past end %llu+%u", off, len);
+ }
+ *lenp = 0;
+ } else {
+ len = readv(dev->fd, reply, reply_num);
+ *lenp = len;
+ }
+
+ p->result = 1 + (p->bytes != len);
+ trigger_irq(fd, irq);
+ return 0;
+}
+
+static void handle_output(int fd, unsigned long dma, unsigned long key,
+ struct device_list *devices)
+{
+ struct device *i;
+ u32 *lenp;
+ struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
+ unsigned num = 0;
+
+ lenp = dma2iov(dma, iov, &num);
+ for (i = devices->dev; i; i = i->next) {
+ if (i->handle_output && key == i->watch_key) {
+ *lenp = i->handle_output(fd, iov, num, i);
+ return;
+ }
+ }
+ warnx("Pending dma %p, key %p", (void *)dma, (void *)key);
+}
+
+static void handle_input(int fd, struct device_list *devices)
+{
+ struct timeval poll = { .tv_sec = 0, .tv_usec = 0 };
+
+ for (;;) {
+ struct device *i;
+ fd_set fds = devices->infds;
+
+ if (select(devices->max_infd+1, &fds, NULL, NULL, &poll) == 0)
+ break;
+
+ for (i = devices->dev; i; i = i->next) {
+ if (i->handle_input && FD_ISSET(i->fd, &fds)) {
+ if (!i->handle_input(fd, i)) {
+ FD_CLR(i->fd, &devices->infds);
+ /* Tell waker to ignore it too... */
+ write(waker_fd, &i->fd, sizeof(i->fd));
+ }
+ }
+ }
+ }
+}
+
+static struct lguest_device_desc *new_dev_desc(u16 type, u16 features,
+ u16 num_pages)
+{
+ static unsigned long top = LGUEST_GUEST_TOP;
+ struct lguest_device_desc *desc;
+
+ desc = malloc(sizeof(*desc));
+ desc->type = type;
+ desc->num_pages = num_pages;
+ desc->features = features;
+ desc->status = 0;
+ if (num_pages) {
+ top -= num_pages*getpagesize();
+ map_zeroed_pages(top, num_pages);
+ desc->pfn = top / getpagesize();
+ } else
+ desc->pfn = 0;
+ return desc;
+}
+
+static struct device *new_device(struct device_list *devices,
+ u16 type, u16 num_pages, u16 features,
+ int fd,
+ bool (*handle_input)(int, struct device *),
+ unsigned long watch_off,
+ u32 (*handle_output)(int,
+ const struct iovec *,
+ unsigned,
+ struct device *))
+{
+ struct device *dev = malloc(sizeof(*dev));
+
+ /* Append to device list. */
+ *devices->lastdev = dev;
+ dev->next = NULL;
+ devices->lastdev = &dev->next;
+
+ dev->fd = fd;
+ if (handle_input)
+ set_fd(dev->fd, devices);
+ dev->desc = new_dev_desc(type, features, num_pages);
+ dev->mem = (void *)(dev->desc->pfn * getpagesize());
+ dev->handle_input = handle_input;
+ dev->watch_key = (unsigned long)dev->mem + watch_off;
+ dev->handle_output = handle_output;
+ return dev;
+}
+
+static void setup_console(struct device_list *devices)
+{
+ struct device *dev;
+
+ if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
+ struct termios term = orig_term;
+ term.c_lflag &= ~(ISIG|ICANON|ECHO);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+ atexit(restore_term);
+ }
+
+ /* We don't currently require a page for the console. */
+ dev = new_device(devices, LGUEST_DEVICE_T_CONSOLE, 0, 0,
+ STDIN_FILENO, handle_console_input,
+ LGUEST_CONSOLE_DMA_KEY, handle_console_output);
+ dev->priv = malloc(sizeof(struct console_abort));
+ ((struct console_abort *)dev->priv)->count = 0;
+ verbose("device %p: console\n",
+ (void *)(dev->desc->pfn * getpagesize()));
+}
+
+static void setup_block_file(const char *filename, struct device_list *devices)
+{
+ int fd;
+ struct device *dev;
+ off64_t *device_len;
+ struct lguest_block_page *p;
+
+ fd = open_or_die(filename, O_RDWR|O_LARGEFILE|O_DIRECT);
+ dev = new_device(devices, LGUEST_DEVICE_T_BLOCK, 1,
+ LGUEST_DEVICE_F_RANDOMNESS,
+ fd, NULL, 0, handle_block_output);
+ device_len = dev->priv = malloc(sizeof(*device_len));
+ *device_len = lseek64(fd, 0, SEEK_END);
+ p = dev->mem;
+
+ p->num_sectors = *device_len/512;
+ verbose("device %p: block %i sectors\n",
+ (void *)(dev->desc->pfn * getpagesize()), p->num_sectors);
+}
+
+/* We use fnctl locks to reserve network slots (autocleanup!) */
+static unsigned int find_slot(int netfd, const char *filename)
+{
+ struct flock fl;
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_len = 1;
+ for (fl.l_start = 0;
+ fl.l_start < getpagesize()/sizeof(struct lguest_net);
+ fl.l_start++) {
+ if (fcntl(netfd, F_SETLK, &fl) == 0)
+ return fl.l_start;
+ }
+ errx(1, "No free slots in network file %s", filename);
+}
+
+static void setup_net_file(const char *filename,
+ struct device_list *devices)
+{
+ int netfd;
+ struct device *dev;
+
+ netfd = open(filename, O_RDWR, 0);
+ if (netfd < 0) {
+ if (errno == ENOENT) {
+ netfd = open(filename, O_RDWR|O_CREAT, 0600);
+ if (netfd >= 0) {
+ char page[getpagesize()];
+ memset(page, 0, sizeof(page));
+ write(netfd, page, sizeof(page));
+ }
+ }
+ if (netfd < 0)
+ err(1, "cannot open net file '%s'", filename);
+ }
+
+ dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
+ find_slot(netfd, filename)|LGUEST_NET_F_NOCSUM,
+ -1, NULL, 0, NULL);
+
+ /* We overwrite the /dev/zero mapping with the actual file. */
+ if (mmap(dev->mem, getpagesize(), PROT_READ|PROT_WRITE,
+ MAP_FIXED|MAP_SHARED, netfd, 0) != dev->mem)
+ err(1, "could not mmap '%s'", filename);
+ verbose("device %p: shared net %s, peer %i\n",
+ (void *)(dev->desc->pfn * getpagesize()), filename,
+ dev->desc->features & ~LGUEST_NET_F_NOCSUM);
+}
+
+static u32 str2ip(const char *ipaddr)
+{
+ unsigned int byte[4];
+
+ sscanf(ipaddr, "%u.%u.%u.%u", &byte[0], &byte[1], &byte[2], &byte[3]);
+ return (byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3];
+}
+
+/* adapted from libbridge */
+static void add_to_bridge(int fd, const char *if_name, const char *br_name)
+{
+ int ifidx;
+ struct ifreq ifr;
+
+ if (!*br_name)
+ errx(1, "must specify bridge name");
+
+ ifidx = if_nametoindex(if_name);
+ if (!ifidx)
+ errx(1, "interface %s does not exist!", if_name);
+
+ strncpy(ifr.ifr_name, br_name, IFNAMSIZ);
+ ifr.ifr_ifindex = ifidx;
+ if (ioctl(fd, SIOCBRADDIF, &ifr) < 0)
+ err(1, "can't add %s to bridge %s", if_name, br_name);
+}
+
+static void configure_device(int fd, const char *devname, u32 ipaddr,
+ unsigned char hwaddr[6])
+{
+ struct ifreq ifr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, devname);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = htonl(ipaddr);
+ if (ioctl(fd, SIOCSIFADDR, &ifr) != 0)
+ err(1, "Setting %s interface address", devname);
+ ifr.ifr_flags = IFF_UP;
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0)
+ err(1, "Bringing interface %s up", devname);
+
+ if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
+ err(1, "getting hw address for %s", devname);
+
+ memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);
+}
+
+static void setup_tun_net(const char *arg, struct device_list *devices)
+{
+ struct device *dev;
+ struct ifreq ifr;
+ int netfd, ipfd;
+ u32 ip;
+ const char *br_name = NULL;
+
+ netfd = open_or_die("/dev/net/tun", O_RDWR);
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strcpy(ifr.ifr_name, "tap%d");
+ if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
+ err(1, "configuring /dev/net/tun");
+ ioctl(netfd, TUNSETNOCSUM, 1);
+
+ /* You will be peer 1: we should create enough jitter to randomize */
+ dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
+ NET_PEERNUM|LGUEST_DEVICE_F_RANDOMNESS, netfd,
+ handle_tun_input, peer_offset(0), handle_tun_output);
+ dev->priv = malloc(sizeof(bool));
+ *(bool *)dev->priv = false;
+
+ ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (ipfd < 0)
+ err(1, "opening IP socket");
+
+ if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
+ ip = INADDR_ANY;
+ br_name = arg + strlen(BRIDGE_PFX);
+ add_to_bridge(ipfd, ifr.ifr_name, br_name);
+ } else
+ ip = str2ip(arg);
+
+ /* We are peer 0, ie. first slot. */
+ configure_device(ipfd, ifr.ifr_name, ip, dev->mem);
+
+ /* Set "promisc" bit: we want every single packet. */
+ *((u8 *)dev->mem) |= 0x1;
+
+ close(ipfd);
+
+ verbose("device %p: tun net %u.%u.%u.%u\n",
+ (void *)(dev->desc->pfn * getpagesize()),
+ (u8)(ip>>24), (u8)(ip>>16), (u8)(ip>>8), (u8)ip);
+ if (br_name)
+ verbose("attached to bridge: %s\n", br_name);
+}
+
+/* Now we know how much memory we have, we copy in device descriptors */
+static void map_device_descriptors(struct device_list *devs, unsigned long mem)
+{
+ struct device *i;
+ unsigned int num;
+ struct lguest_device_desc *descs;
+
+ /* Device descriptor array sits just above top of normal memory */
+ descs = map_zeroed_pages(mem, 1);
+
+ for (i = devs->dev, num = 0; i; i = i->next, num++) {
+ if (num == LGUEST_MAX_DEVICES)
+ errx(1, "too many devices");
+ verbose("Device %i: %s\n", num,
+ i->desc->type == LGUEST_DEVICE_T_NET ? "net"
+ : i->desc->type == LGUEST_DEVICE_T_CONSOLE ? "console"
+ : i->desc->type == LGUEST_DEVICE_T_BLOCK ? "block"
+ : "unknown");
+ descs[num] = *i->desc;
+ free(i->desc);
+ i->desc = &descs[num];
+ }
+}
+
+static void __attribute__((noreturn))
+run_guest(int lguest_fd, struct device_list *device_list)
+{
+ for (;;) {
+ u32 args[] = { LHREQ_BREAK, 0 };
+ unsigned long arr[2];
+ int readval;
+
+ /* We read from the /dev/lguest device to run the Guest. */
+ readval = read(lguest_fd, arr, sizeof(arr));
+
+ if (readval == sizeof(arr)) {
+ handle_output(lguest_fd, arr[0], arr[1], device_list);
+ continue;
+ } else if (errno == ENOENT) {
+ char reason[1024] = { 0 };
+ read(lguest_fd, reason, sizeof(reason)-1);
+ errx(1, "%s", reason);
+ } else if (errno != EAGAIN)
+ err(1, "Running guest failed");
+ handle_input(lguest_fd, device_list);
+ if (write(lguest_fd, args, sizeof(args)) < 0)
+ err(1, "Resetting break");
+ }
+}
+
+static struct option opts[] = {
+ { "verbose", 0, NULL, 'v' },
+ { "sharenet", 1, NULL, 's' },
+ { "tunnet", 1, NULL, 't' },
+ { "block", 1, NULL, 'b' },
+ { "initrd", 1, NULL, 'i' },
+ { NULL },
+};
+static void usage(void)
+{
+ errx(1, "Usage: lguest [--verbose] "
+ "[--sharenet=<filename>|--tunnet=(<ipaddr>|bridge:<bridgename>)\n"
+ "|--block=<filename>|--initrd=<filename>]...\n"
+ "<mem-in-mb> vmlinux [args...]");
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned long mem, pgdir, start, page_offset, initrd_size = 0;
+ int c, lguest_fd;
+ struct device_list device_list;
+ void *boot = (void *)0;
+ const char *initrd_name = NULL;
+
+ device_list.max_infd = -1;
+ device_list.dev = NULL;
+ device_list.lastdev = &device_list.dev;
+ FD_ZERO(&device_list.infds);
+
+ while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) {
+ switch (c) {
+ case 'v':
+ verbose = true;
+ break;
+ case 's':
+ setup_net_file(optarg, &device_list);
+ break;
+ case 't':
+ setup_tun_net(optarg, &device_list);
+ break;
+ case 'b':
+ setup_block_file(optarg, &device_list);
+ break;
+ case 'i':
+ initrd_name = optarg;
+ break;
+ default:
+ warnx("Unknown argument %s", argv[optind]);
+ usage();
+ }
+ }
+ if (optind + 2 > argc)
+ usage();
+
+ /* We need a console device */
+ setup_console(&device_list);
+
+ /* First we map /dev/zero over all of guest-physical memory. */
+ mem = atoi(argv[optind]) * 1024 * 1024;
+ map_zeroed_pages(0, mem / getpagesize());
+
+ /* Now we load the kernel */
+ start = load_kernel(open_or_die(argv[optind+1], O_RDONLY),
+ &page_offset);
+
+ /* Write the device descriptors into memory. */
+ map_device_descriptors(&device_list, mem);
+
+ /* Map the initrd image if requested */
+ if (initrd_name) {
+ initrd_size = load_initrd(initrd_name, mem);
+ *(unsigned long *)(boot+0x218) = mem - initrd_size;
+ *(unsigned long *)(boot+0x21c) = initrd_size;
+ *(unsigned char *)(boot+0x210) = 0xFF;
+ }
+
+ /* Set up the initial linar pagetables. */
+ pgdir = setup_pagetables(mem, initrd_size, page_offset);
+
+ /* E820 memory map: ours is a simple, single region. */
+ *(char*)(boot+E820NR) = 1;
+ *((struct e820entry *)(boot+E820MAP))
+ = ((struct e820entry) { 0, mem, E820_RAM });
+ /* Command line pointer and command line (at 4096) */
+ *(void **)(boot + 0x228) = boot + 4096;
+ concat(boot + 4096, argv+optind+2);
+ /* Paravirt type: 1 == lguest */
+ *(int *)(boot + 0x23c) = 1;
+
+ lguest_fd = tell_kernel(pgdir, start, page_offset);
+ waker_fd = setup_waker(lguest_fd, &device_list);
+
+ run_guest(lguest_fd, &device_list);
+}
diff --git a/Documentation/lguest/lguest.txt b/Documentation/lguest/lguest.txt
new file mode 100644
index 000000000000..821617bd6c04
--- /dev/null
+++ b/Documentation/lguest/lguest.txt
@@ -0,0 +1,129 @@
+Rusty's Remarkably Unreliable Guide to Lguest
+ - or, A Young Coder's Illustrated Hypervisor
+http://lguest.ozlabs.org
+
+Lguest is designed to be a minimal hypervisor for the Linux kernel, for
+Linux developers and users to experiment with virtualization with the
+minimum of complexity. Nonetheless, it should have sufficient
+features to make it useful for specific tasks, and, of course, you are
+encouraged to fork and enhance it.
+
+Features:
+
+- Kernel module which runs in a normal kernel.
+- Simple I/O model for communication.
+- Simple program to create new guests.
+- Logo contains cute puppies: http://lguest.ozlabs.org
+
+Developer features:
+
+- Fun to hack on.
+- No ABI: being tied to a specific kernel anyway, you can change anything.
+- Many opportunities for improvement or feature implementation.
+
+Running Lguest:
+
+- Lguest runs the same kernel as guest and host. You can configure
+ them differently, but usually it's easiest not to.
+
+ You will need to configure your kernel with the following options:
+
+ CONFIG_HIGHMEM64G=n ("High Memory Support" "64GB")[1]
+ CONFIG_TUN=y/m ("Universal TUN/TAP device driver support")
+ CONFIG_EXPERIMENTAL=y ("Prompt for development and/or incomplete code/drivers")
+ CONFIG_PARAVIRT=y ("Paravirtualization support (EXPERIMENTAL)")
+ CONFIG_LGUEST=y/m ("Linux hypervisor example code")
+
+ and I recommend:
+ CONFIG_HZ=100 ("Timer frequency")[2]
+
+- A tool called "lguest" is available in this directory: type "make"
+ to build it. If you didn't build your kernel in-tree, use "make
+ O=<builddir>".
+
+- Create or find a root disk image. There are several useful ones
+ around, such as the xm-test tiny root image at
+ http://xm-test.xensource.com/ramdisks/initrd-1.1-i386.img
+
+ For more serious work, I usually use a distribution ISO image and
+ install it under qemu, then make multiple copies:
+
+ dd if=/dev/zero of=rootfile bs=1M count=2048
+ qemu -cdrom image.iso -hda rootfile -net user -net nic -boot d
+
+- "modprobe lg" if you built it as a module.
+
+- Run an lguest as root:
+
+ Documentation/lguest/lguest 64m vmlinux --tunnet=192.168.19.1 --block=rootfile root=/dev/lgba
+
+ Explanation:
+ 64m: the amount of memory to use.
+
+ vmlinux: the kernel image found in the top of your build directory. You
+ can also use a standard bzImage.
+
+ --tunnet=192.168.19.1: configures a "tap" device for networking with this
+ IP address.
+
+ --block=rootfile: a file or block device which becomes /dev/lgba
+ inside the guest.
+
+ root=/dev/lgba: this (and anything else on the command line) are
+ kernel boot parameters.
+
+- Configuring networking. I usually have the host masquerade, using
+ "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE" and "echo 1 >
+ /proc/sys/net/ipv4/ip_forward". In this example, I would configure
+ eth0 inside the guest at 192.168.19.2.
+
+ Another method is to bridge the tap device to an external interface
+ using --tunnet=bridge:<bridgename>, and perhaps run dhcp on the guest
+ to obtain an IP address. The bridge needs to be configured first:
+ this option simply adds the tap interface to it.
+
+ A simple example on my system:
+
+ ifconfig eth0 0.0.0.0
+ brctl addbr lg0
+ ifconfig lg0 up
+ brctl addif lg0 eth0
+ dhclient lg0
+
+ Then use --tunnet=bridge:lg0 when launching the guest.
+
+ See http://linux-net.osdl.org/index.php/Bridge for general information
+ on how to get bridging working.
+
+- You can also create an inter-guest network using
+ "--sharenet=<filename>": any two guests using the same file are on
+ the same network. This file is created if it does not exist.
+
+Lguest I/O model:
+
+Lguest uses a simplified DMA model plus shared memory for I/O. Guests
+can communicate with each other if they share underlying memory
+(usually by the lguest program mmaping the same file), but they can
+use any non-shared memory to communicate with the lguest process.
+
+Guests can register DMA buffers at any key (must be a valid physical
+address) using the LHCALL_BIND_DMA(key, dmabufs, num<<8|irq)
+hypercall. "dmabufs" is the physical address of an array of "num"
+"struct lguest_dma": each contains a used_len, and an array of
+physical addresses and lengths. When a transfer occurs, the
+"used_len" field of one of the buffers which has used_len 0 will be
+set to the length transferred and the irq will fire.
+
+Using an irq value of 0 unbinds the dma buffers.
+
+To send DMA, the LHCALL_SEND_DMA(key, dma_physaddr) hypercall is used,
+and the bytes used is written to the used_len field. This can be 0 if
+noone else has bound a DMA buffer to that key or some other error.
+DMA buffers bound by the same guest are ignored.
+
+Cheers!
+Rusty Russell rusty@rustcorp.com.au.
+
+[1] These are on various places on the TODO list, waiting for you to
+ get annoyed enough at the limitation to fix it.
+[2] Lguest is not yet tickless when idle. See [1].
diff --git a/Documentation/m68k/kernel-options.txt b/Documentation/m68k/kernel-options.txt
index 1c41db21d3c1..59108cebe163 100644
--- a/Documentation/m68k/kernel-options.txt
+++ b/Documentation/m68k/kernel-options.txt
@@ -82,13 +82,6 @@ Valid names are:
/dev/fd : -> 0x0200 (floppy disk)
/dev/xda: -> 0x0c00 (first XT disk, unused in Linux/m68k)
/dev/xdb: -> 0x0c40 (second XT disk, unused in Linux/m68k)
- /dev/ada: -> 0x1c00 (first ACSI device)
- /dev/adb: -> 0x1c10 (second ACSI device)
- /dev/adc: -> 0x1c20 (third ACSI device)
- /dev/add: -> 0x1c30 (forth ACSI device)
-
-The last four names are available only if the kernel has been compiled
-with Atari and ACSI support.
The name must be followed by a decimal number, that stands for the
partition number. Internally, the value of the number is just
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index af6a63ab9026..32c2e9da5f3a 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -433,6 +433,12 @@ tcp_workaround_signed_windows - BOOLEAN
not receive a window scaling option from them.
Default: 0
+tcp_dma_copybreak - INTEGER
+ Lower limit, in bytes, of the size of socket reads that will be
+ offloaded to a DMA copy engine, if one is present in the system
+ and CONFIG_NET_DMA is enabled.
+ Default: 4096
+
CIPSOv4 Variables:
cipso_cache_enable - BOOLEAN
@@ -874,8 +880,7 @@ accept_redirects - BOOLEAN
accept_source_route - INTEGER
Accept source routing (routing extension header).
- > 0: Accept routing header.
- = 0: Accept only routing header type 2.
+ >= 0: Accept only routing header type 2.
< 0: Do not accept routing header.
Default: 0
diff --git a/Documentation/networking/l2tp.txt b/Documentation/networking/l2tp.txt
new file mode 100644
index 000000000000..2451f551c505
--- /dev/null
+++ b/Documentation/networking/l2tp.txt
@@ -0,0 +1,169 @@
+This brief document describes how to use the kernel's PPPoL2TP driver
+to provide L2TP functionality. L2TP is a protocol that tunnels one or
+more PPP sessions over a UDP tunnel. It is commonly used for VPNs
+(L2TP/IPSec) and by ISPs to tunnel subscriber PPP sessions over an IP
+network infrastructure.
+
+Design
+======
+
+The PPPoL2TP driver, drivers/net/pppol2tp.c, provides a mechanism by
+which PPP frames carried through an L2TP session are passed through
+the kernel's PPP subsystem. The standard PPP daemon, pppd, handles all
+PPP interaction with the peer. PPP network interfaces are created for
+each local PPP endpoint.
+
+The L2TP protocol http://www.faqs.org/rfcs/rfc2661.html defines L2TP
+control and data frames. L2TP control frames carry messages between
+L2TP clients/servers and are used to setup / teardown tunnels and
+sessions. An L2TP client or server is implemented in userspace and
+will use a regular UDP socket per tunnel. L2TP data frames carry PPP
+frames, which may be PPP control or PPP data. The kernel's PPP
+subsystem arranges for PPP control frames to be delivered to pppd,
+while data frames are forwarded as usual.
+
+Each tunnel and session within a tunnel is assigned a unique tunnel_id
+and session_id. These ids are carried in the L2TP header of every
+control and data packet. The pppol2tp driver uses them to lookup
+internal tunnel and/or session contexts. Zero tunnel / session ids are
+treated specially - zero ids are never assigned to tunnels or sessions
+in the network. In the driver, the tunnel context keeps a pointer to
+the tunnel UDP socket. The session context keeps a pointer to the
+PPPoL2TP socket, as well as other data that lets the driver interface
+to the kernel PPP subsystem.
+
+Note that the pppol2tp kernel driver handles only L2TP data frames;
+L2TP control frames are simply passed up to userspace in the UDP
+tunnel socket. The kernel handles all datapath aspects of the
+protocol, including data packet resequencing (if enabled).
+
+There are a number of requirements on the userspace L2TP daemon in
+order to use the pppol2tp driver.
+
+1. Use a UDP socket per tunnel.
+
+2. Create a single PPPoL2TP socket per tunnel bound to a special null
+ session id. This is used only for communicating with the driver but
+ must remain open while the tunnel is active. Opening this tunnel
+ management socket causes the driver to mark the tunnel socket as an
+ L2TP UDP encapsulation socket and flags it for use by the
+ referenced tunnel id. This hooks up the UDP receive path via
+ udp_encap_rcv() in net/ipv4/udp.c. PPP data frames are never passed
+ in this special PPPoX socket.
+
+3. Create a PPPoL2TP socket per L2TP session. This is typically done
+ by starting pppd with the pppol2tp plugin and appropriate
+ arguments. A PPPoL2TP tunnel management socket (Step 2) must be
+ created before the first PPPoL2TP session socket is created.
+
+When creating PPPoL2TP sockets, the application provides information
+to the driver about the socket in a socket connect() call. Source and
+destination tunnel and session ids are provided, as well as the file
+descriptor of a UDP socket. See struct pppol2tp_addr in
+include/linux/if_ppp.h. Note that zero tunnel / session ids are
+treated specially. When creating the per-tunnel PPPoL2TP management
+socket in Step 2 above, zero source and destination session ids are
+specified, which tells the driver to prepare the supplied UDP file
+descriptor for use as an L2TP tunnel socket.
+
+Userspace may control behavior of the tunnel or session using
+setsockopt and ioctl on the PPPoX socket. The following socket
+options are supported:-
+
+DEBUG - bitmask of debug message categories. See below.
+SENDSEQ - 0 => don't send packets with sequence numbers
+ 1 => send packets with sequence numbers
+RECVSEQ - 0 => receive packet sequence numbers are optional
+ 1 => drop receive packets without sequence numbers
+LNSMODE - 0 => act as LAC.
+ 1 => act as LNS.
+REORDERTO - reorder timeout (in millisecs). If 0, don't try to reorder.
+
+Only the DEBUG option is supported by the special tunnel management
+PPPoX socket.
+
+In addition to the standard PPP ioctls, a PPPIOCGL2TPSTATS is provided
+to retrieve tunnel and session statistics from the kernel using the
+PPPoX socket of the appropriate tunnel or session.
+
+Debugging
+=========
+
+The driver supports a flexible debug scheme where kernel trace
+messages may be optionally enabled per tunnel and per session. Care is
+needed when debugging a live system since the messages are not
+rate-limited and a busy system could be swamped. Userspace uses
+setsockopt on the PPPoX socket to set a debug mask.
+
+The following debug mask bits are available:
+
+PPPOL2TP_MSG_DEBUG verbose debug (if compiled in)
+PPPOL2TP_MSG_CONTROL userspace - kernel interface
+PPPOL2TP_MSG_SEQ sequence numbers handling
+PPPOL2TP_MSG_DATA data packets
+
+Sample Userspace Code
+=====================
+
+1. Create tunnel management PPPoX socket
+
+ kernel_fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
+ if (kernel_fd >= 0) {
+ struct sockaddr_pppol2tp sax;
+ struct sockaddr_in const *peer_addr;
+
+ peer_addr = l2tp_tunnel_get_peer_addr(tunnel);
+ memset(&sax, 0, sizeof(sax));
+ sax.sa_family = AF_PPPOX;
+ sax.sa_protocol = PX_PROTO_OL2TP;
+ sax.pppol2tp.fd = udp_fd; /* fd of tunnel UDP socket */
+ sax.pppol2tp.addr.sin_addr.s_addr = peer_addr->sin_addr.s_addr;
+ sax.pppol2tp.addr.sin_port = peer_addr->sin_port;
+ sax.pppol2tp.addr.sin_family = AF_INET;
+ sax.pppol2tp.s_tunnel = tunnel_id;
+ sax.pppol2tp.s_session = 0; /* special case: mgmt socket */
+ sax.pppol2tp.d_tunnel = 0;
+ sax.pppol2tp.d_session = 0; /* special case: mgmt socket */
+
+ if(connect(kernel_fd, (struct sockaddr *)&sax, sizeof(sax) ) < 0 ) {
+ perror("connect failed");
+ result = -errno;
+ goto err;
+ }
+ }
+
+2. Create session PPPoX data socket
+
+ struct sockaddr_pppol2tp sax;
+ int fd;
+
+ /* Note, the target socket must be bound already, else it will not be ready */
+ sax.sa_family = AF_PPPOX;
+ sax.sa_protocol = PX_PROTO_OL2TP;
+ sax.pppol2tp.fd = tunnel_fd;
+ sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr;
+ sax.pppol2tp.addr.sin_port = addr->sin_port;
+ sax.pppol2tp.addr.sin_family = AF_INET;
+ sax.pppol2tp.s_tunnel = tunnel_id;
+ sax.pppol2tp.s_session = session_id;
+ sax.pppol2tp.d_tunnel = peer_tunnel_id;
+ sax.pppol2tp.d_session = peer_session_id;
+
+ /* session_fd is the fd of the session's PPPoL2TP socket.
+ * tunnel_fd is the fd of the tunnel UDP socket.
+ */
+ fd = connect(session_fd, (struct sockaddr *)&sax, sizeof(sax));
+ if (fd < 0 ) {
+ return -errno;
+ }
+ return 0;
+
+Miscellanous
+============
+
+The PPPoL2TP driver was developed as part of the OpenL2TP project by
+Katalix Systems Ltd. OpenL2TP is a full-featured L2TP client / server,
+designed from the ground up to have the L2TP datapath in the
+kernel. The project also implemented the pppol2tp plugin for pppd
+which allows pppd to use the kernel driver. Details can be found at
+http://openl2tp.sourceforge.net.
diff --git a/Documentation/networking/mac80211-injection.txt b/Documentation/networking/mac80211-injection.txt
new file mode 100644
index 000000000000..53ef7a06f49c
--- /dev/null
+++ b/Documentation/networking/mac80211-injection.txt
@@ -0,0 +1,59 @@
+How to use packet injection with mac80211
+=========================================
+
+mac80211 now allows arbitrary packets to be injected down any Monitor Mode
+interface from userland. The packet you inject needs to be composed in the
+following format:
+
+ [ radiotap header ]
+ [ ieee80211 header ]
+ [ payload ]
+
+The radiotap format is discussed in
+./Documentation/networking/radiotap-headers.txt.
+
+Despite 13 radiotap argument types are currently defined, most only make sense
+to appear on received packets. Currently three kinds of argument are used by
+the injection code, although it knows to skip any other arguments that are
+present (facilitating replay of captured radiotap headers directly):
+
+ - IEEE80211_RADIOTAP_RATE - u8 arg in 500kbps units (0x02 --> 1Mbps)
+
+ - IEEE80211_RADIOTAP_ANTENNA - u8 arg, 0x00 = ant1, 0x01 = ant2
+
+ - IEEE80211_RADIOTAP_DBM_TX_POWER - u8 arg, dBm
+
+Here is an example valid radiotap header defining these three parameters
+
+ 0x00, 0x00, // <-- radiotap version
+ 0x0b, 0x00, // <- radiotap header length
+ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap
+ 0x6c, // <-- rate
+ 0x0c, //<-- tx power
+ 0x01 //<-- antenna
+
+The ieee80211 header follows immediately afterwards, looking for example like
+this:
+
+ 0x08, 0x01, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
+ 0x10, 0x86
+
+Then lastly there is the payload.
+
+After composing the packet contents, it is sent by send()-ing it to a logical
+mac80211 interface that is in Monitor mode. Libpcap can also be used,
+(which is easier than doing the work to bind the socket to the right
+interface), along the following lines:
+
+ ppcap = pcap_open_live(szInterfaceName, 800, 1, 20, szErrbuf);
+...
+ r = pcap_inject(ppcap, u8aSendBuffer, nLength);
+
+You can also find sources for a complete inject test applet here:
+
+http://penumbra.warmcat.com/_twk/tiki-index.php?page=packetspammer
+
+Andy Green <andy@warmcat.com>
diff --git a/Documentation/networking/multiqueue.txt b/Documentation/networking/multiqueue.txt
new file mode 100644
index 000000000000..00b60cce2224
--- /dev/null
+++ b/Documentation/networking/multiqueue.txt
@@ -0,0 +1,111 @@
+
+ HOWTO for multiqueue network device support
+ ===========================================
+
+Section 1: Base driver requirements for implementing multiqueue support
+Section 2: Qdisc support for multiqueue devices
+Section 3: Brief howto using PRIO or RR for multiqueue devices
+
+
+Intro: Kernel support for multiqueue devices
+---------------------------------------------------------
+
+Kernel support for multiqueue devices is only an API that is presented to the
+netdevice layer for base drivers to implement. This feature is part of the
+core networking stack, and all network devices will be running on the
+multiqueue-aware stack. If a base driver only has one queue, then these
+changes are transparent to that driver.
+
+
+Section 1: Base driver requirements for implementing multiqueue support
+-----------------------------------------------------------------------
+
+Base drivers are required to use the new alloc_etherdev_mq() or
+alloc_netdev_mq() functions to allocate the subqueues for the device. The
+underlying kernel API will take care of the allocation and deallocation of
+the subqueue memory, as well as netdev configuration of where the queues
+exist in memory.
+
+The base driver will also need to manage the queues as it does the global
+netdev->queue_lock today. Therefore base drivers should use the
+netif_{start|stop|wake}_subqueue() functions to manage each queue while the
+device is still operational. netdev->queue_lock is still used when the device
+comes online or when it's completely shut down (unregister_netdev(), etc.).
+
+Finally, the base driver should indicate that it is a multiqueue device. The
+feature flag NETIF_F_MULTI_QUEUE should be added to the netdev->features
+bitmap on device initialization. Below is an example from e1000:
+
+#ifdef CONFIG_E1000_MQ
+ if ( (adapter->hw.mac.type == e1000_82571) ||
+ (adapter->hw.mac.type == e1000_82572) ||
+ (adapter->hw.mac.type == e1000_80003es2lan))
+ netdev->features |= NETIF_F_MULTI_QUEUE;
+#endif
+
+
+Section 2: Qdisc support for multiqueue devices
+-----------------------------------------------
+
+Currently two qdiscs support multiqueue devices. A new round-robin qdisc,
+sch_rr, and sch_prio. The qdisc is responsible for classifying the skb's to
+bands and queues, and will store the queue mapping into skb->queue_mapping.
+Use this field in the base driver to determine which queue to send the skb
+to.
+
+sch_rr has been added for hardware that doesn't want scheduling policies from
+software, so it's a straight round-robin qdisc. It uses the same syntax and
+classification priomap that sch_prio uses, so it should be intuitive to
+configure for people who've used sch_prio.
+
+The PRIO qdisc naturally plugs into a multiqueue device. If PRIO has been
+built with NET_SCH_PRIO_MQ, then upon load, it will make sure the number of
+bands requested is equal to the number of queues on the hardware. If they
+are equal, it sets a one-to-one mapping up between the queues and bands. If
+they're not equal, it will not load the qdisc. This is the same behavior
+for RR. Once the association is made, any skb that is classified will have
+skb->queue_mapping set, which will allow the driver to properly queue skb's
+to multiple queues.
+
+
+Section 3: Brief howto using PRIO and RR for multiqueue devices
+---------------------------------------------------------------
+
+The userspace command 'tc,' part of the iproute2 package, is used to configure
+qdiscs. To add the PRIO qdisc to your network device, assuming the device is
+called eth0, run the following command:
+
+# tc qdisc add dev eth0 root handle 1: prio bands 4 multiqueue
+
+This will create 4 bands, 0 being highest priority, and associate those bands
+to the queues on your NIC. Assuming eth0 has 4 Tx queues, the band mapping
+would look like:
+
+band 0 => queue 0
+band 1 => queue 1
+band 2 => queue 2
+band 3 => queue 3
+
+Traffic will begin flowing through each queue if your TOS values are assigning
+traffic across the various bands. For example, ssh traffic will always try to
+go out band 0 based on TOS -> Linux priority conversion (realtime traffic),
+so it will be sent out queue 0. ICMP traffic (pings) fall into the "normal"
+traffic classification, which is band 1. Therefore pings will be send out
+queue 1 on the NIC.
+
+Note the use of the multiqueue keyword. This is only in versions of iproute2
+that support multiqueue networking devices; if this is omitted when loading
+a qdisc onto a multiqueue device, the qdisc will load and operate the same
+if it were loaded onto a single-queue device (i.e. - sends all traffic to
+queue 0).
+
+Another alternative to multiqueue band allocation can be done by using the
+multiqueue option and specify 0 bands. If this is the case, the qdisc will
+allocate the number of bands to equal the number of queues that the device
+reports, and bring the qdisc online.
+
+The behavior of tc filters remains the same, where it will override TOS priority
+classification.
+
+
+Author: Peter P. Waskiewicz Jr. <peter.p.waskiewicz.jr@intel.com>
diff --git a/Documentation/networking/net-modules.txt b/Documentation/networking/net-modules.txt
index 0b27863f155c..98c4392dd0fd 100644
--- a/Documentation/networking/net-modules.txt
+++ b/Documentation/networking/net-modules.txt
@@ -146,12 +146,6 @@ at1700.c:
irq = 0
(Probes ports: 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300)
-atari_bionet.c:
- Supports full autoprobing. (m68k/Atari)
-
-atari_pamsnet.c:
- Supports full autoprobing. (m68k/Atari)
-
atarilance.c:
Supports full autoprobing. (m68k/Atari)
diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
index ce1361f95243..37869295fc70 100644
--- a/Documentation/networking/netdevices.txt
+++ b/Documentation/networking/netdevices.txt
@@ -20,6 +20,30 @@ private data which gets freed when the network device is freed. If
separately allocated data is attached to the network device
(dev->priv) then it is up to the module exit handler to free that.
+MTU
+===
+Each network device has a Maximum Transfer Unit. The MTU does not
+include any link layer protocol overhead. Upper layer protocols must
+not pass a socket buffer (skb) to a device to transmit with more data
+than the mtu. The MTU does not include link layer header overhead, so
+for example on Ethernet if the standard MTU is 1500 bytes used, the
+actual skb will contain up to 1514 bytes because of the Ethernet
+header. Devices should allow for the 4 byte VLAN header as well.
+
+Segmentation Offload (GSO, TSO) is an exception to this rule. The
+upper layer protocol may pass a large socket buffer to the device
+transmit routine, and the device will break that up into separate
+packets based on the current MTU.
+
+MTU is symmetrical and applies both to receive and transmit. A device
+must be able to receive at least the maximum size packet allowed by
+the MTU. A network device may use the MTU as mechanism to size receive
+buffers, but the device should allow packets with VLAN header. With
+standard Ethernet mtu of 1500 bytes, the device should allow up to
+1518 byte packets (1500 + 14 header + 4 tag). The device may either:
+drop, truncate, or pass up oversize packets, but dropping oversize
+packets is preferred.
+
struct net_device synchronization rules
=======================================
@@ -43,16 +67,17 @@ dev->get_stats:
dev->hard_start_xmit:
Synchronization: netif_tx_lock spinlock.
+
When the driver sets NETIF_F_LLTX in dev->features this will be
called without holding netif_tx_lock. In this case the driver
has to lock by itself when needed. It is recommended to use a try lock
- for this and return -1 when the spin lock fails.
+ for this and return NETDEV_TX_LOCKED when the spin lock fails.
The locking there should also properly protect against
- set_multicast_list
- Context: Process with BHs disabled or BH (timer).
- Notes: netif_queue_stopped() is guaranteed false
- Interrupts must be enabled when calling hard_start_xmit.
- (Interrupts must also be enabled when enabling the BH handler.)
+ set_multicast_list.
+
+ Context: Process with BHs disabled or BH (timer),
+ will be called with interrupts disabled by netconsole.
+
Return codes:
o NETDEV_TX_OK everything ok.
o NETDEV_TX_BUSY Cannot transmit packet, try later
@@ -74,4 +99,5 @@ dev->poll:
Synchronization: __LINK_STATE_RX_SCHED bit in dev->state. See
dev_close code and comments in net/core/dev.c for more info.
Context: softirq
+ will be called with interrupts disabled by netconsole.
diff --git a/Documentation/networking/radiotap-headers.txt b/Documentation/networking/radiotap-headers.txt
new file mode 100644
index 000000000000..953331c7984f
--- /dev/null
+++ b/Documentation/networking/radiotap-headers.txt
@@ -0,0 +1,152 @@
+How to use radiotap headers
+===========================
+
+Pointer to the radiotap include file
+------------------------------------
+
+Radiotap headers are variable-length and extensible, you can get most of the
+information you need to know on them from:
+
+./include/net/ieee80211_radiotap.h
+
+This document gives an overview and warns on some corner cases.
+
+
+Structure of the header
+-----------------------
+
+There is a fixed portion at the start which contains a u32 bitmap that defines
+if the possible argument associated with that bit is present or not. So if b0
+of the it_present member of ieee80211_radiotap_header is set, it means that
+the header for argument index 0 (IEEE80211_RADIOTAP_TSFT) is present in the
+argument area.
+
+ < 8-byte ieee80211_radiotap_header >
+ [ <possible argument bitmap extensions ... > ]
+ [ <argument> ... ]
+
+At the moment there are only 13 possible argument indexes defined, but in case
+we run out of space in the u32 it_present member, it is defined that b31 set
+indicates that there is another u32 bitmap following (shown as "possible
+argument bitmap extensions..." above), and the start of the arguments is moved
+forward 4 bytes each time.
+
+Note also that the it_len member __le16 is set to the total number of bytes
+covered by the ieee80211_radiotap_header and any arguments following.
+
+
+Requirements for arguments
+--------------------------
+
+After the fixed part of the header, the arguments follow for each argument
+index whose matching bit is set in the it_present member of
+ieee80211_radiotap_header.
+
+ - the arguments are all stored little-endian!
+
+ - the argument payload for a given argument index has a fixed size. So
+ IEEE80211_RADIOTAP_TSFT being present always indicates an 8-byte argument is
+ present. See the comments in ./include/net/ieee80211_radiotap.h for a nice
+ breakdown of all the argument sizes
+
+ - the arguments must be aligned to a boundary of the argument size using
+ padding. So a u16 argument must start on the next u16 boundary if it isn't
+ already on one, a u32 must start on the next u32 boundary and so on.
+
+ - "alignment" is relative to the start of the ieee80211_radiotap_header, ie,
+ the first byte of the radiotap header. The absolute alignment of that first
+ byte isn't defined. So even if the whole radiotap header is starting at, eg,
+ address 0x00000003, still the first byte of the radiotap header is treated as
+ 0 for alignment purposes.
+
+ - the above point that there may be no absolute alignment for multibyte
+ entities in the fixed radiotap header or the argument region means that you
+ have to take special evasive action when trying to access these multibyte
+ entities. Some arches like Blackfin cannot deal with an attempt to
+ dereference, eg, a u16 pointer that is pointing to an odd address. Instead
+ you have to use a kernel API get_unaligned() to dereference the pointer,
+ which will do it bytewise on the arches that require that.
+
+ - The arguments for a given argument index can be a compound of multiple types
+ together. For example IEEE80211_RADIOTAP_CHANNEL has an argument payload
+ consisting of two u16s of total length 4. When this happens, the padding
+ rule is applied dealing with a u16, NOT dealing with a 4-byte single entity.
+
+
+Example valid radiotap header
+-----------------------------
+
+ 0x00, 0x00, // <-- radiotap version + pad byte
+ 0x0b, 0x00, // <- radiotap header length
+ 0x04, 0x0c, 0x00, 0x00, // <-- bitmap
+ 0x6c, // <-- rate (in 500kHz units)
+ 0x0c, //<-- tx power
+ 0x01 //<-- antenna
+
+
+Using the Radiotap Parser
+-------------------------
+
+If you are having to parse a radiotap struct, you can radically simplify the
+job by using the radiotap parser that lives in net/wireless/radiotap.c and has
+its prototypes available in include/net/cfg80211.h. You use it like this:
+
+#include <net/cfg80211.h>
+
+/* buf points to the start of the radiotap header part */
+
+int MyFunction(u8 * buf, int buflen)
+{
+ int pkt_rate_100kHz = 0, antenna = 0, pwr = 0;
+ struct ieee80211_radiotap_iterator iterator;
+ int ret = ieee80211_radiotap_iterator_init(&iterator, buf, buflen);
+
+ while (!ret) {
+
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_RATE:
+ /* radiotap "rate" u8 is in
+ * 500kbps units, eg, 0x02=1Mbps
+ */
+ pkt_rate_100kHz = (*iterator.this_arg) * 5;
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ /* radiotap uses 0 for 1st ant */
+ antenna = *iterator.this_arg);
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER:
+ pwr = *iterator.this_arg;
+ break;
+
+ default:
+ break;
+ }
+ } /* while more rt headers */
+
+ if (ret != -ENOENT)
+ return TXRX_DROP;
+
+ /* discard the radiotap header part */
+ buf += iterator.max_length;
+ buflen -= iterator.max_length;
+
+ ...
+
+}
+
+Andy Green <andy@warmcat.com>
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index 7d5b60dea551..7f60dfe642ca 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -86,6 +86,20 @@ stuff are the values reported by the Oops - you can just cut-and-paste
and do a replace of spaces to "\x" - that's what I do, as I'm too lazy
to write a program to automate this all).
+Alternatively, you can use the shell script in scripts/decodecode.
+Its usage is: decodecode < oops.txt
+
+The hex bytes that follow "Code:" may (in some architectures) have a series
+of bytes that precede the current instruction pointer as well as bytes at and
+following the current instruction pointer. In some cases, one instruction
+byte or word is surrounded by <> or (), as in "<86>" or "(f00d)". These
+<> or () markings indicate the current instruction pointer. Example from
+i386, split into multiple lines for readability:
+
+Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
+64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
+7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
+
Finally, if you want to see where the code comes from, you can do
cd /usr/src/linux
@@ -237,6 +251,8 @@ characters, each representing a particular tainted value.
7: 'U' if a user or user application specifically requested that the
Tainted flag be set, ' ' otherwise.
+ 8: 'D' if the kernel has died recently, i.e. there was an OOPS or BUG.
+
The primary reason for the 'Tainted: ' string is to tell kernel
debuggers if this is a clean kernel or if anything unusual has
occurred. Tainting is permanent: even if an offending module is
diff --git a/Documentation/pci.txt b/Documentation/pci.txt
index d38261b67905..7754f5aea4e9 100644
--- a/Documentation/pci.txt
+++ b/Documentation/pci.txt
@@ -113,9 +113,6 @@ initialization with a pointer to a structure describing the driver
(Please see Documentation/power/pci.txt for descriptions
of PCI Power Management and the related functions.)
- enable_wake Enable device to generate wake events from a low power
- state.
-
shutdown Hook into reboot_notifier_list (kernel/sys.c).
Intended to stop any idling DMA operations.
Useful for enabling wake-on-lan (NIC) or changing
@@ -299,7 +296,10 @@ If the PCI device can use the PCI Memory-Write-Invalidate transaction,
call pci_set_mwi(). This enables the PCI_COMMAND bit for Mem-Wr-Inval
and also ensures that the cache line size register is set correctly.
Check the return value of pci_set_mwi() as not all architectures
-or chip-sets may support Memory-Write-Invalidate.
+or chip-sets may support Memory-Write-Invalidate. Alternatively,
+if Mem-Wr-Inval would be nice to have but is not required, call
+pci_try_set_mwi() to have the system do its best effort at enabling
+Mem-Wr-Inval.
3.2 Request MMIO/IOP resources
diff --git a/Documentation/power/freezing-of-tasks.txt b/Documentation/power/freezing-of-tasks.txt
new file mode 100644
index 000000000000..04dc1cf9d215
--- /dev/null
+++ b/Documentation/power/freezing-of-tasks.txt
@@ -0,0 +1,162 @@
+Freezing of tasks
+ (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+I. What is the freezing of tasks?
+
+The freezing of tasks is a mechanism by which user space processes and some
+kernel threads are controlled during hibernation or system-wide suspend (on some
+architectures).
+
+II. How does it work?
+
+There are four per-task flags used for that, PF_NOFREEZE, PF_FROZEN, TIF_FREEZE
+and PF_FREEZER_SKIP (the last one is auxiliary). The tasks that have
+PF_NOFREEZE unset (all user space processes and some kernel threads) are
+regarded as 'freezable' and treated in a special way before the system enters a
+suspend state as well as before a hibernation image is created (in what follows
+we only consider hibernation, but the description also applies to suspend).
+
+Namely, as the first step of the hibernation procedure the function
+freeze_processes() (defined in kernel/power/process.c) is called. It executes
+try_to_freeze_tasks() that sets TIF_FREEZE for all of the freezable tasks and
+sends a fake signal to each of them. A task that receives such a signal and has
+TIF_FREEZE set, should react to it by calling the refrigerator() function
+(defined in kernel/power/process.c), which sets the task's PF_FROZEN flag,
+changes its state to TASK_UNINTERRUPTIBLE and makes it loop until PF_FROZEN is
+cleared for it. Then, we say that the task is 'frozen' and therefore the set of
+functions handling this mechanism is called 'the freezer' (these functions are
+defined in kernel/power/process.c and include/linux/freezer.h). User space
+processes are generally frozen before kernel threads.
+
+It is not recommended to call refrigerator() directly. Instead, it is
+recommended to use the try_to_freeze() function (defined in
+include/linux/freezer.h), that checks the task's TIF_FREEZE flag and makes the
+task enter refrigerator() if the flag is set.
+
+For user space processes try_to_freeze() is called automatically from the
+signal-handling code, but the freezable kernel threads need to call it
+explicitly in suitable places. The code to do this may look like the following:
+
+ do {
+ hub_events();
+ wait_event_interruptible(khubd_wait,
+ !list_empty(&hub_event_list));
+ try_to_freeze();
+ } while (!signal_pending(current));
+
+(from drivers/usb/core/hub.c::hub_thread()).
+
+If a freezable kernel thread fails to call try_to_freeze() after the freezer has
+set TIF_FREEZE for it, the freezing of tasks will fail and the entire
+hibernation operation will be cancelled. For this reason, freezable kernel
+threads must call try_to_freeze() somewhere.
+
+After the system memory state has been restored from a hibernation image and
+devices have been reinitialized, the function thaw_processes() is called in
+order to clear the PF_FROZEN flag for each frozen task. Then, the tasks that
+have been frozen leave refrigerator() and continue running.
+
+III. Which kernel threads are freezable?
+
+Kernel threads are not freezable by default. However, a kernel thread may clear
+PF_NOFREEZE for itself by calling set_freezable() (the resetting of PF_NOFREEZE
+directly is strongly discouraged). From this point it is regarded as freezable
+and must call try_to_freeze() in a suitable place.
+
+IV. Why do we do that?
+
+Generally speaking, there is a couple of reasons to use the freezing of tasks:
+
+1. The principal reason is to prevent filesystems from being damaged after
+hibernation. At the moment we have no simple means of checkpointing
+filesystems, so if there are any modifications made to filesystem data and/or
+metadata on disks, we cannot bring them back to the state from before the
+modifications. At the same time each hibernation image contains some
+filesystem-related information that must be consistent with the state of the
+on-disk data and metadata after the system memory state has been restored from
+the image (otherwise the filesystems will be damaged in a nasty way, usually
+making them almost impossible to repair). We therefore freeze tasks that might
+cause the on-disk filesystems' data and metadata to be modified after the
+hibernation image has been created and before the system is finally powered off.
+The majority of these are user space processes, but if any of the kernel threads
+may cause something like this to happen, they have to be freezable.
+
+2. The second reason is to prevent user space processes and some kernel threads
+from interfering with the suspending and resuming of devices. A user space
+process running on a second CPU while we are suspending devices may, for
+example, be troublesome and without the freezing of tasks we would need some
+safeguards against race conditions that might occur in such a case.
+
+Although Linus Torvalds doesn't like the freezing of tasks, he said this in one
+of the discussions on LKML (http://lkml.org/lkml/2007/4/27/608):
+
+"RJW:> Why we freeze tasks at all or why we freeze kernel threads?
+
+Linus: In many ways, 'at all'.
+
+I _do_ realize the IO request queue issues, and that we cannot actually do
+s2ram with some devices in the middle of a DMA. So we want to be able to
+avoid *that*, there's no question about that. And I suspect that stopping
+user threads and then waiting for a sync is practically one of the easier
+ways to do so.
+
+So in practice, the 'at all' may become a 'why freeze kernel threads?' and
+freezing user threads I don't find really objectionable."
+
+Still, there are kernel threads that may want to be freezable. For example, if
+a kernel that belongs to a device driver accesses the device directly, it in
+principle needs to know when the device is suspended, so that it doesn't try to
+access it at that time. However, if the kernel thread is freezable, it will be
+frozen before the driver's .suspend() callback is executed and it will be
+thawed after the driver's .resume() callback has run, so it won't be accessing
+the device while it's suspended.
+
+3. Another reason for freezing tasks is to prevent user space processes from
+realizing that hibernation (or suspend) operation takes place. Ideally, user
+space processes should not notice that such a system-wide operation has occurred
+and should continue running without any problems after the restore (or resume
+from suspend). Unfortunately, in the most general case this is quite difficult
+to achieve without the freezing of tasks. Consider, for example, a process
+that depends on all CPUs being online while it's running. Since we need to
+disable nonboot CPUs during the hibernation, if this process is not frozen, it
+may notice that the number of CPUs has changed and may start to work incorrectly
+because of that.
+
+V. Are there any problems related to the freezing of tasks?
+
+Yes, there are.
+
+First of all, the freezing of kernel threads may be tricky if they depend one
+on another. For example, if kernel thread A waits for a completion (in the
+TASK_UNINTERRUPTIBLE state) that needs to be done by freezable kernel thread B
+and B is frozen in the meantime, then A will be blocked until B is thawed, which
+may be undesirable. That's why kernel threads are not freezable by default.
+
+Second, there are the following two problems related to the freezing of user
+space processes:
+1. Putting processes into an uninterruptible sleep distorts the load average.
+2. Now that we have FUSE, plus the framework for doing device drivers in
+userspace, it gets even more complicated because some userspace processes are
+now doing the sorts of things that kernel threads do
+(https://lists.linux-foundation.org/pipermail/linux-pm/2007-May/012309.html).
+
+The problem 1. seems to be fixable, although it hasn't been fixed so far. The
+other one is more serious, but it seems that we can work around it by using
+hibernation (and suspend) notifiers (in that case, though, we won't be able to
+avoid the realization by the user space processes that the hibernation is taking
+place).
+
+There are also problems that the freezing of tasks tends to expose, although
+they are not directly related to it. For example, if request_firmware() is
+called from a device driver's .resume() routine, it will timeout and eventually
+fail, because the user land process that should respond to the request is frozen
+at this point. So, seemingly, the failure is due to the freezing of tasks.
+Suppose, however, that the firmware file is located on a filesystem accessible
+only through another device that hasn't been resumed yet. In that case,
+request_firmware() will fail regardless of whether or not the freezing of tasks
+is used. Consequently, the problem is not really related to the freezing of
+tasks, since it generally exists anyway.
+
+A driver must have all firmwares it may need in RAM before suspend() is called.
+If keeping them is not practical, for example due to their size, they must be
+requested early enough using the suspend notifier API described in notifiers.txt.
diff --git a/Documentation/power/kernel_threads.txt b/Documentation/power/kernel_threads.txt
deleted file mode 100644
index fb57784986b1..000000000000
--- a/Documentation/power/kernel_threads.txt
+++ /dev/null
@@ -1,40 +0,0 @@
-KERNEL THREADS
-
-
-Freezer
-
-Upon entering a suspended state the system will freeze all
-tasks. This is done by delivering pseudosignals. This affects
-kernel threads, too. To successfully freeze a kernel thread
-the thread has to check for the pseudosignal and enter the
-refrigerator. Code to do this looks like this:
-
- do {
- hub_events();
- wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
- try_to_freeze();
- } while (!signal_pending(current));
-
-from drivers/usb/core/hub.c::hub_thread()
-
-
-The Unfreezable
-
-Some kernel threads however, must not be frozen. The kernel must
-be able to finish pending IO operations and later on be able to
-write the memory image to disk. Kernel threads needed to do IO
-must stay awake. Such threads must mark themselves unfreezable
-like this:
-
- /*
- * This thread doesn't need any user-level access,
- * so get rid of all our resources.
- */
- daemonize("usb-storage");
-
- current->flags |= PF_NOFREEZE;
-
-from drivers/usb/storage/usb.c::usb_stor_control_thread()
-
-Such drivers are themselves responsible for staying quiet during
-the actual snapshotting.
diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt
new file mode 100644
index 000000000000..9293e4bc857c
--- /dev/null
+++ b/Documentation/power/notifiers.txt
@@ -0,0 +1,50 @@
+Suspend notifiers
+ (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+There are some operations that device drivers may want to carry out in their
+.suspend() routines, but shouldn't, because they can cause the hibernation or
+suspend to fail. For example, a driver may want to allocate a substantial amount
+of memory (like 50 MB) in .suspend(), but that shouldn't be done after the
+swsusp's memory shrinker has run.
+
+Also, there may be some operations, that subsystems want to carry out before a
+hibernation/suspend or after a restore/resume, requiring the system to be fully
+functional, so the drivers' .suspend() and .resume() routines are not suitable
+for this purpose. For example, device drivers may want to upload firmware to
+their devices after a restore from a hibernation image, but they cannot do it by
+calling request_firmware() from their .resume() routines (user land processes
+are frozen at this point). The solution may be to load the firmware into
+memory before processes are frozen and upload it from there in the .resume()
+routine. Of course, a hibernation notifier may be used for this purpose.
+
+The subsystems that have such needs can register suspend notifiers that will be
+called upon the following events by the suspend core:
+
+PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will
+ be frozen immediately.
+
+PM_POST_HIBERNATION The system memory state has been restored from a
+ hibernation image or an error occured during the
+ hibernation. Device drivers' .resume() callbacks have
+ been executed and tasks have been thawed.
+
+PM_SUSPEND_PREPARE The system is preparing for a suspend.
+
+PM_POST_SUSPEND The system has just resumed or an error occured during
+ the suspend. Device drivers' .resume() callbacks have
+ been executed and tasks have been thawed.
+
+It is generally assumed that whatever the notifiers do for
+PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION. Analogously,
+operations performed for PM_SUSPEND_PREPARE should be reversed for
+PM_POST_SUSPEND. Additionally, all of the notifiers are called for
+PM_POST_HIBERNATION if one of them fails for PM_HIBERNATION_PREPARE, and
+all of the notifiers are called for PM_POST_SUSPEND if one of them fails for
+PM_SUSPEND_PREPARE.
+
+The hibernation and suspend notifiers are called with pm_mutex held. They are
+defined in the usual way, but their last argument is meaningless (it is always
+NULL). To register and/or unregister a suspend notifier use the functions
+register_pm_notifier() and unregister_pm_notifier(), respectively, defined in
+include/linux/suspend.h . If you don't need to unregister the notifier, you can
+also use the pm_notifier() macro defined in include/linux/suspend.h .
diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt
index e00b099a4b86..dd8fe43888d3 100644
--- a/Documentation/power/pci.txt
+++ b/Documentation/power/pci.txt
@@ -164,7 +164,6 @@ struct pci_driver:
int (*suspend) (struct pci_dev *dev, pm_message_t state);
int (*resume) (struct pci_dev *dev);
- int (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable);
suspend
@@ -251,42 +250,6 @@ The driver should update the current_state field in its pci_dev structure in
this function, except for PM-capable devices when pci_set_power_state is used.
-enable_wake
------------
-
-Usage:
-
-if (dev->driver && dev->driver->enable_wake)
- dev->driver->enable_wake(dev,state,enable);
-
-This callback is generally only relevant for devices that support the PCI PM
-spec and have the ability to generate a PME# (Power Management Event Signal)
-to wake the system up. (However, it is possible that a device may support
-some non-standard way of generating a wake event on sleep.)
-
-Bits 15:11 of the PMC (Power Mgmt Capabilities) Register in a device's
-PM Capabilities describe what power states the device supports generating a
-wake event from:
-
-+------------------+
-| Bit | State |
-+------------------+
-| 11 | D0 |
-| 12 | D1 |
-| 13 | D2 |
-| 14 | D3hot |
-| 15 | D3cold |
-+------------------+
-
-A device can use this to enable wake events:
-
- pci_enable_wake(dev,state,enable);
-
-Note that to enable PME# from D3cold, a value of 4 should be passed to
-pci_enable_wake (since it uses an index into a bitmask). If a driver gets
-a request to enable wake events from D3, two calls should be made to
-pci_enable_wake (one for both D3hot and D3cold).
-
A reference implementation
-------------------------
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index 5b8d6953f05e..aea7e9209667 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -140,21 +140,11 @@ should be sent to the mailing list available through the suspend2
website, and not to the Linux Kernel Mailing List. We are working
toward merging suspend2 into the mainline kernel.
-Q: A kernel thread must voluntarily freeze itself (call 'refrigerator').
-I found some kernel threads that don't do it, and they don't freeze
-so the system can't sleep. Is this a known behavior?
-
-A: All such kernel threads need to be fixed, one by one. Select the
-place where the thread is safe to be frozen (no kernel semaphores
-should be held at that point and it must be safe to sleep there), and
-add:
-
- try_to_freeze();
-
-If the thread is needed for writing the image to storage, you should
-instead set the PF_NOFREEZE process flag when creating the thread (and
-be very careful).
+Q: What is the freezing of tasks and why are we using it?
+A: The freezing of tasks is a mechanism by which user space processes and some
+kernel threads are controlled during hibernation or system-wide suspend (on some
+architectures). See freezing-of-tasks.txt for details.
Q: What is the difference between "platform" and "shutdown"?
@@ -393,6 +383,9 @@ safest thing is to unmount all filesystems on removable media (such USB,
Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays)
before suspending; then remount them after resuming.
+There is a work-around for this problem. For more information, see
+Documentation/usb/persist.txt.
+
Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
compiled with the similar configuration files. Anyway I found that
suspend to disk (and resume) is much slower on 2.6.16 compared to
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index d42d98107d49..76733a3962f0 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -42,15 +42,16 @@ Table of Contents
1) Defining child nodes of an SOC
2) Representing devices without a current OF specification
a) MDIO IO device
- c) PHY nodes
b) Gianfar-compatible ethernet nodes
+ c) PHY nodes
d) Interrupt controllers
e) I2C
f) Freescale SOC USB controllers
g) Freescale SOC SEC Security Engines
h) Board Control and Status (BCSR)
i) Freescale QUICC Engine module (QE)
- g) Flash chip nodes
+ j) Flash chip nodes
+ k) Global Utilities Block
VII - Specifying interrupt information for devices
1) interrupts property
@@ -626,6 +627,14 @@ So the node content can be summarized as a start token, a full path,
a list of properties, a list of child nodes, and an end token. Every
child node is a full node structure itself as defined above.
+NOTE: The above definition requires that all property definitions for
+a particular node MUST precede any subnode definitions for that node.
+Although the structure would not be ambiguous if properties and
+subnodes were intermingled, the kernel parser requires that the
+properties come first (up until at least 2.6.22). Any tools
+manipulating a flattened tree must take care to preserve this
+constraint.
+
4) Device tree "strings" block
In order to save space, property names, which are generally redundant,
@@ -1241,6 +1250,12 @@ platforms are moved over to use the flattened-device-tree model.
network device. This is used by the bootwrapper to interpret
MAC addresses passed by the firmware when no information other
than indices is available to associate an address with a device.
+ - phy-connection-type : a string naming the controller/PHY interface type,
+ i.e., "mii" (default), "rmii", "gmii", "rgmii", "rgmii-id", "sgmii",
+ "tbi", or "rtbi". This property is only really needed if the connection
+ is of type "rgmii-id", as all other connection types are detected by
+ hardware.
+
Example:
@@ -1782,6 +1797,33 @@ platforms are moved over to use the flattened-device-tree model.
partition-names = "fs\0firmware";
};
+ k) Global Utilities Block
+
+ The global utilities block controls power management, I/O device
+ enabling, power-on-reset configuration monitoring, general-purpose
+ I/O signal configuration, alternate function selection for multiplexed
+ signals, and clock control.
+
+ Required properties:
+
+ - compatible : Should define the compatible device type for
+ global-utilities.
+ - reg : Offset and length of the register set for the device.
+
+ Recommended properties:
+
+ - fsl,has-rstcr : Indicates that the global utilities register set
+ contains a functioning "reset control register" (i.e. the board
+ is wired to reset upon setting the HRESET_REQ bit in this register).
+
+ Example:
+
+ global-utilities@e0000 { /* global utilities block */
+ compatible = "fsl,mpc8548-guts";
+ reg = <e0000 1000>;
+ fsl,has-rstcr;
+ };
+
More devices will be defined as this spec matures.
VII - Specifying interrupt information for devices
diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt
index 7c701b88d6d5..c931d613f641 100644
--- a/Documentation/rtc.txt
+++ b/Documentation/rtc.txt
@@ -385,7 +385,7 @@ test_PIE:
/* not all RTCs support periodic IRQs */
if (errno == ENOTTY) {
fprintf(stderr, "\nNo periodic IRQ support\n");
- return 0;
+ goto done;
}
perror("RTC_IRQP_READ ioctl");
exit(errno);
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index ce3cb42507bd..cc12b55d4b3d 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -50,6 +50,9 @@ Supported Cards/Chipsets
9005:0285:9005:02be Adaptec 31605 (Marauder160)
9005:0285:9005:02c3 Adaptec 51205 (Voodoo120)
9005:0285:9005:02c4 Adaptec 51605 (Voodoo160)
+ 9005:0285:9005:02ce Adaptec 51245 (Voodoo124)
+ 9005:0285:9005:02cf Adaptec 51645 (Voodoo164)
+ 9005:0285:9005:02d0 Adaptec 52445 (Voodoo244)
1011:0046:9005:0364 Adaptec 5400S (Mustang)
9005:0287:9005:0800 Adaptec Themisto (Jupiter)
9005:0200:9005:0200 Adaptec Themisto (Jupiter)
diff --git a/Documentation/scsi/scsi_fc_transport.txt b/Documentation/scsi/scsi_fc_transport.txt
new file mode 100644
index 000000000000..d403e46d8463
--- /dev/null
+++ b/Documentation/scsi/scsi_fc_transport.txt
@@ -0,0 +1,450 @@
+ SCSI FC Tansport
+ =============================================
+
+Date: 4/12/2007
+Kernel Revisions for features:
+ rports : <<TBS>>
+ vports : 2.6.22 (? TBD)
+
+
+Introduction
+============
+This file documents the features and components of the SCSI FC Transport.
+It also provides documents the API between the transport and FC LLDDs.
+The FC transport can be found at:
+ drivers/scsi/scsi_transport_fc.c
+ include/scsi/scsi_transport_fc.h
+ include/scsi/scsi_netlink_fc.h
+
+This file is found at Documentation/scsi/scsi_fc_transport.txt
+
+
+FC Remote Ports (rports)
+========================================================================
+<< To Be Supplied >>
+
+
+FC Virtual Ports (vports)
+========================================================================
+
+Overview:
+-------------------------------
+
+ New FC standards have defined mechanisms which allows for a single physical
+ port to appear on as multiple communication ports. Using the N_Port Id
+ Virtualization (NPIV) mechanism, a point-to-point connection to a Fabric
+ can be assigned more than 1 N_Port_ID. Each N_Port_ID appears as a
+ separate port to other endpoints on the fabric, even though it shares one
+ physical link to the switch for communication. Each N_Port_ID can have a
+ unique view of the fabric based on fabric zoning and array lun-masking
+ (just like a normal non-NPIV adapter). Using the Virtual Fabric (VF)
+ mechanism, adding a fabric header to each frame allows the port to
+ interact with the Fabric Port to join multiple fabrics. The port will
+ obtain an N_Port_ID on each fabric it joins. Each fabric will have its
+ own unique view of endpoints and configuration parameters. NPIV may be
+ used together with VF so that the port can obtain multiple N_Port_IDs
+ on each virtual fabric.
+
+ The FC transport is now recognizing a new object - a vport. A vport is
+ an entity that has a world-wide unique World Wide Port Name (wwpn) and
+ World Wide Node Name (wwnn). The transport also allows for the FC4's to
+ be specified for the vport, with FCP_Initiator being the primary role
+ expected. Once instantiated by one of the above methods, it will have a
+ distinct N_Port_ID and view of fabric endpoints and storage entities.
+ The fc_host associated with the physical adapter will export the ability
+ to create vports. The transport will create the vport object within the
+ Linux device tree, and instruct the fc_host's driver to instantiate the
+ virtual port. Typically, the driver will create a new scsi_host instance
+ on the vport, resulting in a unique <H,C,T,L> namespace for the vport.
+ Thus, whether a FC port is based on a physical port or on a virtual port,
+ each will appear as a unique scsi_host with its own target and lun space.
+
+ Note: At this time, the transport is written to create only NPIV-based
+ vports. However, consideration was given to VF-based vports and it
+ should be a minor change to add support if needed. The remaining
+ discussion will concentrate on NPIV.
+
+ Note: World Wide Name assignment (and uniqueness guarantees) are left
+ up to an administrative entity controling the vport. For example,
+ if vports are to be associated with virtual machines, a XEN mgmt
+ utility would be responsible for creating wwpn/wwnn's for the vport,
+ using it's own naming authority and OUI. (Note: it already does this
+ for virtual MAC addresses).
+
+
+Device Trees and Vport Objects:
+-------------------------------
+
+ Today, the device tree typically contains the scsi_host object,
+ with rports and scsi target objects underneath it. Currently the FC
+ transport creates the vport object and places it under the scsi_host
+ object corresponding to the physical adapter. The LLDD will allocate
+ a new scsi_host for the vport and link it's object under the vport.
+ The remainder of the tree under the vports scsi_host is the same
+ as the non-NPIV case. The transport is written currently to easily
+ allow the parent of the vport to be something other than the scsi_host.
+ This could be used in the future to link the object onto a vm-specific
+ device tree. If the vport's parent is not the physical port's scsi_host,
+ a symbolic link to the vport object will be placed in the physical
+ port's scsi_host.
+
+ Here's what to expect in the device tree :
+ The typical Physical Port's Scsi_Host:
+ /sys/devices/.../host17/
+ and it has the typical decendent tree:
+ /sys/devices/.../host17/rport-17:0-0/target17:0:0/17:0:0:0:
+ and then the vport is created on the Physical Port:
+ /sys/devices/.../host17/vport-17:0-0
+ and the vport's Scsi_Host is then created:
+ /sys/devices/.../host17/vport-17:0-0/host18
+ and then the rest of the tree progresses, such as:
+ /sys/devices/.../host17/vport-17:0-0/host18/rport-18:0-0/target18:0:0/18:0:0:0:
+
+ Here's what to expect in the sysfs tree :
+ scsi_hosts:
+ /sys/class/scsi_host/host17 physical port's scsi_host
+ /sys/class/scsi_host/host18 vport's scsi_host
+ fc_hosts:
+ /sys/class/fc_host/host17 physical port's fc_host
+ /sys/class/fc_host/host18 vport's fc_host
+ fc_vports:
+ /sys/class/fc_vports/vport-17:0-0 the vport's fc_vport
+ fc_rports:
+ /sys/class/fc_remote_ports/rport-17:0-0 rport on the physical port
+ /sys/class/fc_remote_ports/rport-18:0-0 rport on the vport
+
+
+Vport Attributes:
+-------------------------------
+
+ The new fc_vport class object has the following attributes
+
+ node_name: Read_Only
+ The WWNN of the vport
+
+ port_name: Read_Only
+ The WWPN of the vport
+
+ roles: Read_Only
+ Indicates the FC4 roles enabled on the vport.
+
+ symbolic_name: Read_Write
+ A string, appended to the driver's symbolic port name string, which
+ is registered with the switch to identify the vport. For example,
+ a hypervisor could set this string to "Xen Domain 2 VM 5 Vport 2",
+ and this set of identifiers can be seen on switch management screens
+ to identify the port.
+
+ vport_delete: Write_Only
+ When written with a "1", will tear down the vport.
+
+ vport_disable: Write_Only
+ When written with a "1", will transition the vport to a disabled.
+ state. The vport will still be instantiated with the Linux kernel,
+ but it will not be active on the FC link.
+ When written with a "0", will enable the vport.
+
+ vport_last_state: Read_Only
+ Indicates the previous state of the vport. See the section below on
+ "Vport States".
+
+ vport_state: Read_Only
+ Indicates the state of the vport. See the section below on
+ "Vport States".
+
+ vport_type: Read_Only
+ Reflects the FC mechanism used to create the virtual port.
+ Only NPIV is supported currently.
+
+
+ For the fc_host class object, the following attributes are added for vports:
+
+ max_npiv_vports: Read_Only
+ Indicates the maximum number of NPIV-based vports that the
+ driver/adapter can support on the fc_host.
+
+ npiv_vports_inuse: Read_Only
+ Indicates how many NPIV-based vports have been instantiated on the
+ fc_host.
+
+ vport_create: Write_Only
+ A "simple" create interface to instantiate a vport on an fc_host.
+ A "<WWPN>:<WWNN>" string is written to the attribute. The transport
+ then instantiates the vport object and calls the LLDD to create the
+ vport with the role of FCP_Initiator. Each WWN is specified as 16
+ hex characters and may *not* contain any prefixes (e.g. 0x, x, etc).
+
+ vport_delete: Write_Only
+ A "simple" delete interface to teardown a vport. A "<WWPN>:<WWNN>"
+ string is written to the attribute. The transport will locate the
+ vport on the fc_host with the same WWNs and tear it down. Each WWN
+ is specified as 16 hex characters and may *not* contain any prefixes
+ (e.g. 0x, x, etc).
+
+
+Vport States:
+-------------------------------
+
+ Vport instantiation consists of two parts:
+ - Creation with the kernel and LLDD. This means all transport and
+ driver data structures are built up, and device objects created.
+ This is equivalent to a driver "attach" on an adapter, which is
+ independent of the adapter's link state.
+ - Instantiation of the vport on the FC link via ELS traffic, etc.
+ This is equivalent to a "link up" and successfull link initialization.
+ Futher information can be found in the interfaces section below for
+ Vport Creation.
+
+ Once a vport has been instantiated with the kernel/LLDD, a vport state
+ can be reported via the sysfs attribute. The following states exist:
+
+ FC_VPORT_UNKNOWN - Unknown
+ An temporary state, typically set only while the vport is being
+ instantiated with the kernel and LLDD.
+
+ FC_VPORT_ACTIVE - Active
+ The vport has been successfully been created on the FC link.
+ It is fully functional.
+
+ FC_VPORT_DISABLED - Disabled
+ The vport instantiated, but "disabled". The vport is not instantiated
+ on the FC link. This is equivalent to a physical port with the
+ link "down".
+
+ FC_VPORT_LINKDOWN - Linkdown
+ The vport is not operational as the physical link is not operational.
+
+ FC_VPORT_INITIALIZING - Initializing
+ The vport is in the process of instantiating on the FC link.
+ The LLDD will set this state just prior to starting the ELS traffic
+ to create the vport. This state will persist until the vport is
+ successfully created (state becomes FC_VPORT_ACTIVE) or it fails
+ (state is one of the values below). As this state is transitory,
+ it will not be preserved in the "vport_last_state".
+
+ FC_VPORT_NO_FABRIC_SUPP - No Fabric Support
+ The vport is not operational. One of the following conditions were
+ encountered:
+ - The FC topology is not Point-to-Point
+ - The FC port is not connected to an F_Port
+ - The F_Port has indicated that NPIV is not supported.
+
+ FC_VPORT_NO_FABRIC_RSCS - No Fabric Resources
+ The vport is not operational. The Fabric failed FDISC with a status
+ indicating that it does not have sufficient resources to complete
+ the operation.
+
+ FC_VPORT_FABRIC_LOGOUT - Fabric Logout
+ The vport is not operational. The Fabric has LOGO'd the N_Port_ID
+ associated with the vport.
+
+ FC_VPORT_FABRIC_REJ_WWN - Fabric Rejected WWN
+ The vport is not operational. The Fabric failed FDISC with a status
+ indicating that the WWN's are not valid.
+
+ FC_VPORT_FAILED - VPort Failed
+ The vport is not operational. This is a catchall for all other
+ error conditions.
+
+
+ The following state table indicates the different state transitions:
+
+ State Event New State
+ --------------------------------------------------------------------
+ n/a Initialization Unknown
+ Unknown: Link Down Linkdown
+ Link Up & Loop No Fabric Support
+ Link Up & no Fabric No Fabric Support
+ Link Up & FLOGI response No Fabric Support
+ indicates no NPIV support
+ Link Up & FDISC being sent Initializing
+ Disable request Disable
+ Linkdown: Link Up Unknown
+ Initializing: FDISC ACC Active
+ FDISC LS_RJT w/ no resources No Fabric Resources
+ FDISC LS_RJT w/ invalid Fabric Rejected WWN
+ pname or invalid nport_id
+ FDISC LS_RJT failed for Vport Failed
+ other reasons
+ Link Down Linkdown
+ Disable request Disable
+ Disable: Enable request Unknown
+ Active: LOGO received from fabric Fabric Logout
+ Link Down Linkdown
+ Disable request Disable
+ Fabric Logout: Link still up Unknown
+
+ The following 4 error states all have the same transitions:
+ No Fabric Support:
+ No Fabric Resources:
+ Fabric Rejected WWN:
+ Vport Failed:
+ Disable request Disable
+ Link goes down Linkdown
+
+
+Transport <-> LLDD Interfaces :
+-------------------------------
+
+Vport support by LLDD:
+
+ The LLDD indicates support for vports by supplying a vport_create()
+ function in the transport template. The presense of this function will
+ cause the creation of the new attributes on the fc_host. As part of
+ the physical port completing its initialization relative to the
+ transport, it should set the max_npiv_vports attribute to indicate the
+ maximum number of vports the driver and/or adapter supports.
+
+
+Vport Creation:
+
+ The LLDD vport_create() syntax is:
+
+ int vport_create(struct fc_vport *vport, bool disable)
+
+ where:
+ vport: Is the newly allocated vport object
+ disable: If "true", the vport is to be created in a disabled stated.
+ If "false", the vport is to be enabled upon creation.
+
+ When a request is made to create a new vport (via sgio/netlink, or the
+ vport_create fc_host attribute), the transport will validate that the LLDD
+ can support another vport (e.g. max_npiv_vports > npiv_vports_inuse).
+ If not, the create request will be failed. If space remains, the transport
+ will increment the vport count, create the vport object, and then call the
+ LLDD's vport_create() function with the newly allocated vport object.
+
+ As mentioned above, vport creation is divided into two parts:
+ - Creation with the kernel and LLDD. This means all transport and
+ driver data structures are built up, and device objects created.
+ This is equivalent to a driver "attach" on an adapter, which is
+ independent of the adapter's link state.
+ - Instantiation of the vport on the FC link via ELS traffic, etc.
+ This is equivalent to a "link up" and successfull link initialization.
+
+ The LLDD's vport_create() function will not synchronously wait for both
+ parts to be fully completed before returning. It must validate that the
+ infrastructure exists to support NPIV, and complete the first part of
+ vport creation (data structure build up) before returning. We do not
+ hinge vport_create() on the link-side operation mainly because:
+ - The link may be down. It is not a failure if it is. It simply
+ means the vport is in an inoperable state until the link comes up.
+ This is consistent with the link bouncing post vport creation.
+ - The vport may be created in a disabled state.
+ - This is consistent with a model where: the vport equates to a
+ FC adapter. The vport_create is synonymous with driver attachment
+ to the adapter, which is independent of link state.
+
+ Note: special error codes have been defined to delineate infrastructure
+ failure cases for quicker resolution.
+
+ The expected behavior for the LLDD's vport_create() function is:
+ - Validate Infrastructure:
+ - If the driver or adapter cannot support another vport, whether
+ due to improper firmware, (a lie about) max_npiv, or a lack of
+ some other resource - return VPCERR_UNSUPPORTED.
+ - If the driver validates the WWN's against those already active on
+ the adapter and detects an overlap - return VPCERR_BAD_WWN.
+ - If the driver detects the topology is loop, non-fabric, or the
+ FLOGI did not support NPIV - return VPCERR_NO_FABRIC_SUPP.
+ - Allocate data structures. If errors are encountered, such as out
+ of memory conditions, return the respective negative Exxx error code.
+ - If the role is FCP Initiator, the LLDD is to :
+ - Call scsi_host_alloc() to allocate a scsi_host for the vport.
+ - Call scsi_add_host(new_shost, &vport->dev) to start the scsi_host
+ and bind it as a child of the vport device.
+ - Initializes the fc_host attribute values.
+ - Kick of further vport state transitions based on the disable flag and
+ link state - and return success (zero).
+
+ LLDD Implementers Notes:
+ - It is suggested that there be a different fc_function_templates for
+ the physical port and the virtual port. The physical port's template
+ would have the vport_create, vport_delete, and vport_disable functions,
+ while the vports would not.
+ - It is suggested that there be different scsi_host_templates
+ for the physical port and virtual port. Likely, there are driver
+ attributes, embedded into the scsi_host_template, that are applicable
+ for the physical port only (link speed, topology setting, etc). This
+ ensures that the attributes are applicable to the respective scsi_host.
+
+
+Vport Disable/Enable:
+
+ The LLDD vport_disable() syntax is:
+
+ int vport_disable(struct fc_vport *vport, bool disable)
+
+ where:
+ vport: Is vport to to be enabled or disabled
+ disable: If "true", the vport is to be disabled.
+ If "false", the vport is to be enabled.
+
+ When a request is made to change the disabled state on a vport, the
+ transport will validate the request against the existing vport state.
+ If the request is to disable and the vport is already disabled, the
+ request will fail. Similarly, if the request is to enable, and the
+ vport is not in a disabled state, the request will fail. If the request
+ is valid for the vport state, the transport will call the LLDD to
+ change the vport's state.
+
+ Within the LLDD, if a vport is disabled, it remains instantiated with
+ the kernel and LLDD, but it is not active or visible on the FC link in
+ any way. (see Vport Creation and the 2 part instantiation discussion).
+ The vport will remain in this state until it is deleted or re-enabled.
+ When enabling a vport, the LLDD reinstantiates the vport on the FC
+ link - essentially restarting the LLDD statemachine (see Vport States
+ above).
+
+
+Vport Deletion:
+
+ The LLDD vport_delete() syntax is:
+
+ int vport_delete(struct fc_vport *vport)
+
+ where:
+ vport: Is vport to delete
+
+ When a request is made to delete a vport (via sgio/netlink, or via the
+ fc_host or fc_vport vport_delete attributes), the transport will call
+ the LLDD to terminate the vport on the FC link, and teardown all other
+ datastructures and references. If the LLDD completes successfully,
+ the transport will teardown the vport objects and complete the vport
+ removal. If the LLDD delete request fails, the vport object will remain,
+ but will be in an indeterminate state.
+
+ Within the LLDD, the normal code paths for a scsi_host teardown should
+ be followed. E.g. If the vport has a FCP Initiator role, the LLDD
+ will call fc_remove_host() for the vports scsi_host, followed by
+ scsi_remove_host() and scsi_host_put() for the vports scsi_host.
+
+
+Other:
+ fc_host port_type attribute:
+ There is a new fc_host port_type value - FC_PORTTYPE_NPIV. This value
+ must be set on all vport-based fc_hosts. Normally, on a physical port,
+ the port_type attribute would be set to NPORT, NLPORT, etc based on the
+ topology type and existence of the fabric. As this is not applicable to
+ a vport, it makes more sense to report the FC mechanism used to create
+ the vport.
+
+ Driver unload:
+ FC drivers are required to call fc_remove_host() prior to calling
+ scsi_remove_host(). This allows the fc_host to tear down all remote
+ ports prior the scsi_host being torn down. The fc_remove_host() call
+ was updated to remove all vports for the fc_host as well.
+
+
+Credits
+=======
+The following people have contributed to this document:
+
+
+
+
+
+
+James Smart
+james.smart@emulex.com
+
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 355ff0a2bb7c..241e26c4ff92 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -467,7 +467,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
above explicitly.
The power-management is supported.
-
+
+ Module snd-cs5530
+ _________________
+
+ Module for Cyrix/NatSemi Geode 5530 chip.
+
Module snd-cs5535audio
----------------------
@@ -759,6 +764,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
model - force the model name
position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)
+ probe_mask - Bitmask to probe codecs (default = -1, meaning all slots)
single_cmd - Use single immediate commands to communicate with
codecs (for debugging only)
enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
@@ -803,6 +809,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
hp-3013 HP machines (3013-variant)
fujitsu Fujitsu S7020
acer Acer TravelMate
+ will Will laptops (PB V7900)
+ replacer Replacer 672V
basic fixed pin assignment (old default model)
auto auto-config reading BIOS (default)
@@ -811,16 +819,31 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
hp-bpc HP xw4400/6400/8400/9400 laptops
hp-bpc-d7000 HP BPC D7000
benq Benq ED8
+ benq-t31 Benq T31
hippo Hippo (ATI) with jack detection, Sony UX-90s
hippo_1 Hippo (Benq) with jack detection
+ sony-assamd Sony ASSAMD
basic fixed pin assignment w/o SPDIF
auto auto-config reading BIOS (default)
+ ALC268
+ 3stack 3-stack model
+ auto auto-config reading BIOS (default)
+
+ ALC662
+ 3stack-dig 3-stack (2-channel) with SPDIF
+ 3stack-6ch 3-stack (6-channel)
+ 3stack-6ch-dig 3-stack (6-channel) with SPDIF
+ 6stack-dig 6-stack with SPDIF
+ lenovo-101e Lenovo laptop
+ auto auto-config reading BIOS (default)
+
ALC882/885
3stack-dig 3-jack with SPDIF I/O
6stack-dig 6-jack digital with SPDIF I/O
arima Arima W820Di1
macpro MacPro support
+ imac24 iMac 24'' with jack detection
w2jc ASUS W2JC
auto auto-config reading BIOS (default)
@@ -832,9 +855,15 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
6stack-dig-demo 6-jack digital for Intel demo board
acer Acer laptops (Travelmate 3012WTMi, Aspire 5600, etc)
medion Medion Laptops
+ medion-md2 Medion MD2
targa-dig Targa/MSI
targa-2ch-dig Targs/MSI with 2-channel
laptop-eapd 3-jack with SPDIF I/O and EAPD (Clevo M540JE, M550JE)
+ lenovo-101e Lenovo 101E
+ lenovo-nb0763 Lenovo NB0763
+ lenovo-ms7195-dig Lenovo MS7195
+ 6stack-hp HP machines with 6stack (Nettle boards)
+ 3stack-hp HP machines with 3stack (Lucknow, Samba boards)
auto auto-config reading BIOS (default)
ALC861/660
@@ -853,7 +882,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
3stack-dig 3-jack with SPDIF OUT
6stack-dig 6-jack with SPDIF OUT
3stack-660 3-jack (for ALC660VD)
+ 3stack-660-digout 3-jack with SPDIF OUT (for ALC660VD)
lenovo Lenovo 3000 C200
+ dallas Dallas laptops
auto auto-config reading BIOS (default)
CMI9880
@@ -864,12 +895,26 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
allout 5-jack in back, 2-jack in front, SPDIF out
auto auto-config reading BIOS (default)
+ AD1882
+ 3stack 3-stack mode (default)
+ 6stack 6-stack mode
+
+ AD1884
+ N/A
+
AD1981
basic 3-jack (default)
hp HP nx6320
thinkpad Lenovo Thinkpad T60/X60/Z60
toshiba Toshiba U205
+ AD1983
+ N/A
+
+ AD1984
+ basic default configuration
+ thinkpad Lenovo Thinkpad T61/X61
+
AD1986A
6stack 6-jack, separate surrounds (default)
3stack 3-stack, shared surrounds
@@ -907,11 +952,18 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
ref Reference board
3stack D945 3stack
5stack D945 5stack + SPDIF
- macmini Intel Mac Mini
- macbook Intel Mac Book
- macbook-pro-v1 Intel Mac Book Pro 1st generation
- macbook-pro Intel Mac Book Pro 2nd generation
- imac-intel Intel iMac
+ dell Dell XPS M1210
+ intel-mac-v1 Intel Mac Type 1
+ intel-mac-v2 Intel Mac Type 2
+ intel-mac-v3 Intel Mac Type 3
+ intel-mac-v4 Intel Mac Type 4
+ intel-mac-v5 Intel Mac Type 5
+ macmini Intel Mac Mini (equivalent with type 3)
+ macbook Intel Mac Book (eq. type 5)
+ macbook-pro-v1 Intel Mac Book Pro 1st generation (eq. type 3)
+ macbook-pro Intel Mac Book Pro 2nd generation (eq. type 3)
+ imac-intel Intel iMac (eq. type 2)
+ imac-intel-20 Intel iMac (newer version) (eq. type 3)
STAC9202/9250/9251
ref Reference board, base config
@@ -956,6 +1008,17 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
from the irq. Remember this is a last resort, and should be
avoided as much as possible...
+ MORE NOTES ON "azx_get_response timeout" PROBLEMS:
+ On some hardwares, you may need to add a proper probe_mask option
+ to avoid the "azx_get_response timeout" problem above, instead.
+ This occurs when the access to non-existing or non-working codec slot
+ (likely a modem one) causes a stall of the communication via HD-audio
+ bus. You can see which codec slots are probed by enabling
+ CONFIG_SND_DEBUG_DETECT, or simply from the file name of the codec
+ proc files. Then limit the slots to probe by probe_mask option.
+ For example, probe_mask=1 means to probe only the first slot, and
+ probe_mask=4 means only the third slot.
+
The power-management is supported.
Module snd-hdsp
diff --git a/Documentation/sound/alsa/Audiophile-Usb.txt b/Documentation/sound/alsa/Audiophile-Usb.txt
index e40cce83327c..2ad5e6306c44 100644
--- a/Documentation/sound/alsa/Audiophile-Usb.txt
+++ b/Documentation/sound/alsa/Audiophile-Usb.txt
@@ -1,4 +1,4 @@
- Guide to using M-Audio Audiophile USB with ALSA and Jack v1.3
+ Guide to using M-Audio Audiophile USB with ALSA and Jack v1.5
========================================================
Thibault Le Meur <Thibault.LeMeur@supelec.fr>
@@ -6,8 +6,19 @@
This document is a guide to using the M-Audio Audiophile USB (tm) device with
ALSA and JACK.
+History
+=======
+* v1.4 - Thibault Le Meur (2007-07-11)
+ - Added Low Endianness nature of 16bits-modes
+ found by Hakan Lennestal <Hakan.Lennestal@brfsodrahamn.se>
+ - Modifying document structure
+* v1.5 - Thibault Le Meur (2007-07-12)
+ - Added AC3/DTS passthru info
+
+
1 - Audiophile USB Specs and correct usage
==========================================
+
This part is a reminder of important facts about the functions and limitations
of the device.
@@ -25,18 +36,18 @@ The device has 4 audio interfaces, and 2 MIDI ports:
The internal DAC/ADC has the following characteristics:
* sample depth of 16 or 24 bits
* sample rate from 8kHz to 96kHz
-* Two ports can't use different sample depths at the same time. Moreover, the
-Audiophile USB documentation gives the following Warning: "Please exit any
-audio application running before switching between bit depths"
+* Two interfaces can't use different sample depths at the same time.
+Moreover, the Audiophile USB documentation gives the following Warning:
+"Please exit any audio application running before switching between bit depths"
Due to the USB 1.1 bandwidth limitation, a limited number of interfaces can be
activated at the same time depending on the audio mode selected:
- * 16-bit/48kHz ==> 4 channels in/4 channels out
+ * 16-bit/48kHz ==> 4 channels in + 4 channels out
- Ai+Ao+Di+Do
- * 24-bit/48kHz ==> 4 channels in/2 channels out,
- or 2 channels in/4 channels out
+ * 24-bit/48kHz ==> 4 channels in + 2 channels out,
+ or 2 channels in + 4 channels out
- Ai+Ao+Do or Ai+Di+Ao or Ai+Di+Do or Di+Ao+Do
- * 24-bit/96kHz ==> 2 channels in, or 2 channels out (half duplex only)
+ * 24-bit/96kHz ==> 2 channels in _or_ 2 channels out (half duplex only)
- Ai or Ao or Di or Do
Important facts about the Digital interface:
@@ -52,44 +63,56 @@ source is connected
synchronization error (for instance sound played at an odd sample rate)
-2 - Audiophile USB support in ALSA
-==================================
+2 - Audiophile USB MIDI support in ALSA
+=======================================
-2.1 - MIDI ports
-----------------
-The Audiophile USB MIDI ports will be automatically supported once the
+The Audiophile USB MIDI ports will be automatically supported once the
following modules have been loaded:
* snd-usb-audio
* snd-seq-midi
No additional setting is required.
-2.2 - Audio ports
------------------
+
+3 - Audiophile USB Audio support in ALSA
+========================================
Audio functions of the Audiophile USB device are handled by the snd-usb-audio
module. This module can work in a default mode (without any device-specific
parameter), or in an "advanced" mode with the device-specific parameter called
"device_setup".
-2.2.1 - Default Alsa driver mode
-
-The default behavior of the snd-usb-audio driver is to parse the device
-capabilities at startup and enable all functions inside the device (including
-all ports at any supported sample rates and sample depths). This approach
-has the advantage to let the driver easily switch from sample rates/depths
-automatically according to the need of the application claiming the device.
-
-In this case the Audiophile ports are mapped to alsa pcm devices in the
-following way (I suppose the device's index is 1):
+3.1 - Default Alsa driver mode
+------------------------------
+
+The default behavior of the snd-usb-audio driver is to list the device
+capabilities at startup and activate the required mode when required
+by the applications: for instance if the user is recording in a
+24bit-depth-mode and immediately after wants to switch to a 16bit-depth mode,
+the snd-usb-audio module will reconfigure the device on the fly.
+
+This approach has the advantage to let the driver automatically switch from sample
+rates/depths automatically according to the user's needs. However, those who
+are using the device under windows know that this is not how the device is meant to
+work: under windows applications must be closed before using the m-audio control
+panel to switch the device working mode. Thus as we'll see in next section, this
+Default Alsa driver mode can lead to device misconfigurations.
+
+Let's get back to the Default Alsa driver mode for now. In this case the
+Audiophile interfaces are mapped to alsa pcm devices in the following
+way (I suppose the device's index is 1):
* hw:1,0 is Ao in playback and Di in capture
* hw:1,1 is Do in playback and Ai in capture
* hw:1,2 is Do in AC3/DTS passthrough mode
-You must note as well that the device uses Big Endian byte encoding so that
-supported audio format are S16_BE for 16-bit depth modes and S24_3BE for
-24-bits depth mode. One exception is the hw:1,2 port which is Little Endian
-compliant and thus uses S16_LE.
+In this mode, the device uses Big Endian byte-encoding so that
+supported audio format are S16_BE for 16-bit depth modes and S24_3BE for
+24-bits depth mode.
+
+One exception is the hw:1,2 port which was reported to be Little Endian
+compliant (supposedly supporting S16_LE) but processes in fact only S16_BE streams.
+This has been fixed in kernel 2.6.23 and above and now the hw:1,2 interface
+is reported to be big endian in this default driver mode.
Examples:
* playing a S24_3BE encoded raw file to the Ao port
@@ -98,22 +121,26 @@ Examples:
% arecord -D hw:1,1 -c2 -t raw -r48000 -fS24_3BE test.raw
* playing a S16_BE encoded raw file to the Do port
% aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test.raw
+ * playing an ac3 sample file to the Do port
+ % aplay -D hw:1,2 --channels=6 ac3_S16_BE_encoded_file.raw
-If you're happy with the default Alsa driver setup and don't experience any
+If you're happy with the default Alsa driver mode and don't experience any
issue with this mode, then you can skip the following chapter.
-2.2.2 - Advanced module setup
+3.2 - Advanced module setup
+---------------------------
Due to the hardware constraints described above, the device initialization made
by the Alsa driver in default mode may result in a corrupted state of the
device. For instance, a particularly annoying issue is that the sound captured
-from the Ai port sounds distorted (as if boosted with an excessive high volume
-gain).
+from the Ai interface sounds distorted (as if boosted with an excessive high
+volume gain).
For people having this problem, the snd-usb-audio module has a new module
-parameter called "device_setup".
+parameter called "device_setup" (this parameter was introduced in kernel
+release 2.6.17)
-2.2.2.1 - Initializing the working mode of the Audiophile USB
+3.2.1 - Initializing the working mode of the Audiophile USB
As far as the Audiophile USB device is concerned, this value let the user
specify:
@@ -121,33 +148,57 @@ specify:
* the sample rate
* whether the Di port is used or not
-Here is a list of supported device_setup values for this device:
- * device_setup=0x00 (or omitted)
- - Alsa driver default mode
- - maintains backward compatibility with setups that do not use this
- parameter by not introducing any change
- - results sometimes in corrupted sound as described earlier
+When initialized with "device_setup=0x00", the snd-usb-audio module has
+the same behaviour as when the parameter is omitted (see paragraph "Default
+Alsa driver mode" above)
+
+Others modes are described in the following subsections.
+
+3.2.1.1 - 16-bit modes
+
+The two supported modes are:
+
* device_setup=0x01
- 16bits 48kHz mode with Di disabled
- Ai,Ao,Do can be used at the same time
- hw:1,0 is not available in capture mode
- hw:1,2 is not available
+
* device_setup=0x11
- 16bits 48kHz mode with Di enabled
- Ai,Ao,Di,Do can be used at the same time
- hw:1,0 is available in capture mode
- hw:1,2 is not available
+
+In this modes the device operates only at 16bits-modes. Before kernel 2.6.23,
+the devices where reported to be Big-Endian when in fact they were Little-Endian
+so that playing a file was a matter of using:
+ % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_BE test_S16_LE.raw
+where "test_S16_LE.raw" was in fact a little-endian sample file.
+
+Thanks to Hakan Lennestal (who discovered the Little-Endiannes of the device in
+these modes) a fix has been committed (expected in kernel 2.6.23) and
+Alsa now reports Little-Endian interfaces. Thus playing a file now is as simple as
+using:
+ % aplay -D hw:1,1 -c2 -t raw -r48000 -fS16_LE test_S16_LE.raw
+
+3.2.1.2 - 24-bit modes
+
+The three supported modes are:
+
* device_setup=0x09
- 24bits 48kHz mode with Di disabled
- Ai,Ao,Do can be used at the same time
- hw:1,0 is not available in capture mode
- hw:1,2 is not available
+
* device_setup=0x19
- 24bits 48kHz mode with Di enabled
- 3 ports from {Ai,Ao,Di,Do} can be used at the same time
- hw:1,0 is available in capture mode and an active digital source must be
connected to Di
- hw:1,2 is not available
+
* device_setup=0x0D or 0x10
- 24bits 96kHz mode
- Di is enabled by default for this mode but does not need to be connected
@@ -155,34 +206,64 @@ Here is a list of supported device_setup values for this device:
- Only 1 port from {Ai,Ao,Di,Do} can be used at the same time
- hw:1,0 is available in captured mode
- hw:1,2 is not available
+
+In these modes the device is only Big-Endian compliant (see "Default Alsa driver
+mode" above for an aplay command example)
+
+3.2.1.3 - AC3 w/ DTS passthru mode
+
+Thanks to Hakan Lennestal, I now have a report saying that this mode works.
+
* device_setup=0x03
- 16bits 48kHz mode with only the Do port enabled
- - AC3 with DTS passthru (not tested)
+ - AC3 with DTS passthru
- Caution with this setup the Do port is mapped to the pcm device hw:1,0
-2.2.2.2 - Setting and switching configurations with the device_setup parameter
+The command line used to playback the AC3/DTS encoded .wav-files in this mode:
+ % aplay -D hw:1,0 --channels=6 ac3_S16_LE_encoded_file.raw
+
+3.2.2 - How to use the device_setup parameter
+----------------------------------------------
The parameter can be given:
+
* By manually probing the device (as root):
# modprobe -r snd-usb-audio
# modprobe snd-usb-audio index=1 device_setup=0x09
+
* Or while configuring the modules options in your modules configuration file
- For Fedora distributions, edit the /etc/modprobe.conf file:
alias snd-card-1 snd-usb-audio
options snd-usb-audio index=1 device_setup=0x09
-IMPORTANT NOTE WHEN SWITCHING CONFIGURATION:
--------------------------------------------
- * You may need to _first_ initialize the module with the correct device_setup
- parameter and _only_after_ turn on the Audiophile USB device
- * This is especially true when switching the sample depth:
+CAUTION when initializaing the device
+-------------------------------------
+
+ * Correct initialization on the device requires that device_setup is given to
+ the module BEFORE the device is turned on. So, if you use the "manual probing"
+ method described above, take care to power-on the device AFTER this initialization.
+
+ * Failing to respect this will lead in a misconfiguration of the device. In this case
+ turn off the device, unproble the snd-usb-audio module, then probe it again with
+ correct device_setup parameter and then (and only then) turn on the device again.
+
+ * If you've correctly initialized the device in a valid mode and then want to switch
+ to another mode (possibly with another sample-depth), please use also the following
+ procedure:
- first turn off the device
- de-register the snd-usb-audio module (modprobe -r)
- change the device_setup parameter by changing the device_setup
option in /etc/modprobe.conf
- turn on the device
+ * A workaround for this last issue has been applied to kernel 2.6.23, but it may not
+ be enough to ensure the 'stability' of the device initialization.
-2.2.2.3 - Audiophile USB's device_setup structure
+3.2.3 - Technical details for hackers
+-------------------------------------
+This section is for hackers, wanting to understand details about the device
+internals and how Alsa supports it.
+
+3.2.3.1 - Audiophile USB's device_setup structure
If you want to understand the device_setup magic numbers for the Audiophile
USB, you need some very basic understanding of binary computation. However,
@@ -228,12 +309,12 @@ Caution:
- choosing b2 will prepare all interfaces for 24bits/96kHz but you'll
only be able to use one at the same time
-2.2.3 - USB implementation details for this device
+3.2.3.2 - USB implementation details for this device
You may safely skip this section if you're not interested in driver
-development.
+hacking.
-This section describes some internal aspects of the device and summarize the
+This section describes some internal aspects of the device and summarizes the
data I got by usb-snooping the windows and Linux drivers.
The M-Audio Audiophile USB has 7 USB Interfaces:
@@ -293,43 +374,45 @@ parse_audio_endpoints function uses a quirk called
"audiophile_skip_setting_quirk" in order to prevent AltSettings not
corresponding to device_setup from being registered in the driver.
-3 - Audiophile USB and Jack support
+4 - Audiophile USB and Jack support
===================================
This section deals with support of the Audiophile USB device in Jack.
-The main issue regarding this support is that the device is Big Endian
-compliant.
-3.1 - Using the plug alsa plugin
---------------------------------
+There are 2 main potential issues when using Jackd with the device:
+* support for Big-Endian devices in 24-bit modes
+* support for 4-in / 4-out channels
+
+4.1 - Direct support in Jackd
+-----------------------------
-Jack doesn't directly support big endian devices. Thus, one way to have support
-for this device with Alsa is to use the Alsa "plug" converter.
+Jack supports big endian devices only in recent versions (thanks to
+Andreas Steinmetz for his first big-endian patch). I can't remember
+extacly when this support was released into jackd, let's just say that
+with jackd version 0.103.0 it's almost ok (just a small bug is affecting
+16bits Big-Endian devices, but since you've read carefully the above
+paragraphs, you're now using kernel >= 2.6.23 and your 16bits devices
+are now Little Endians ;-) ).
+
+You can run jackd with the following command for playback with Ao and
+record with Ai:
+ % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
+
+4.2 - Using Alsa plughw
+-----------------------
+If you don't have a recent Jackd installed, you can downgrade to using
+the Alsa "plug" converter.
For instance here is one way to run Jack with 2 playback channels on Ao and 2
capture channels from Ai:
% jackd -R -dalsa -dplughw:1 -r48000 -p256 -n2 -D -Cplughw:1,1
-
However you may see the following warning message:
"You appear to be using the ALSA software "plug" layer, probably a result of
using the "default" ALSA device. This is less efficient than it could be.
Consider using a hardware device instead rather than using the plug layer."
-3.2 - Patching alsa to use direct pcm device
---------------------------------------------
-A patch for Jack by Andreas Steinmetz adds support for Big Endian devices.
-However it has not been included in the CVS tree.
-
-You can find it at the following URL:
-http://sourceforge.net/tracker/index.php?func=detail&aid=1289682&group_id=39687&
-atid=425939
-
-After having applied the patch you can run jackd with the following command
-line:
- % jackd -R -dalsa -Phw:1,0 -r48000 -p128 -n2 -D -Chw:1,1
-
-3.2 - Getting 2 input and/or output interfaces in Jack
+4.3 - Getting 2 input and/or output interfaces in Jack
------------------------------------------------------
As you can see, starting the Jack server this way will only enable 1 stereo
@@ -339,6 +422,7 @@ This is due to the following restrictions:
* Jack can only open one capture device and one playback device at a time
* The Audiophile USB is seen as 2 (or three) Alsa devices: hw:1,0, hw:1,1
(and optionally hw:1,2)
+
If you want to get Ai+Di and/or Ao+Do support with Jack, you would need to
combine the Alsa devices into one logical "complex" device.
@@ -348,13 +432,11 @@ It is related to another device (ice1712) but can be adapted to suit
the Audiophile USB.
Enabling multiple Audiophile USB interfaces for Jackd will certainly require:
-* patching Jack with the previously mentioned "Big Endian" patch
-* patching Jackd with the MMAP_COMPLEX patch (see the ice1712 page)
-* patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
+* Making sure your Jackd version has the MMAP_COMPLEX patch (see the ice1712 page)
+* (maybe) patching the alsa-lib/src/pcm/pcm_multi.c file (see the ice1712 page)
* define a multi device (combination of hw:1,0 and hw:1,1) in your .asoundrc
file
* start jackd with this device
-I had no success in testing this for now, but this may be due to my OS
-configuration. If you have any success with this kind of setup, please
-drop me an email.
+I had no success in testing this for now, if you have any success with this kind
+of setup, please drop me an email.
diff --git a/Documentation/sound/alsa/OSS-Emulation.txt b/Documentation/sound/alsa/OSS-Emulation.txt
index ec2a02541d5b..bfa0c9aacb4b 100644
--- a/Documentation/sound/alsa/OSS-Emulation.txt
+++ b/Documentation/sound/alsa/OSS-Emulation.txt
@@ -278,6 +278,21 @@ current mixer configuration by reading and writing the whole file
image.
+Duplex Streams
+==============
+
+Note that when attempting to use a single device file for playback and
+capture, the OSS API provides no way to set the format, sample rate or
+number of channels different in each direction. Thus
+ io_handle = open("device", O_RDWR)
+will only function correctly if the values are the same in each direction.
+
+To use different values in the two directions, use both
+ input_handle = open("device", O_RDONLY)
+ output_handle = open("device", O_WRONLY)
+and set the values for the corresponding handle.
+
+
Unsupported Features
====================
diff --git a/Documentation/sound/oss/AD1816 b/Documentation/sound/oss/AD1816
deleted file mode 100644
index 14bd8f25d523..000000000000
--- a/Documentation/sound/oss/AD1816
+++ /dev/null
@@ -1,84 +0,0 @@
-Documentation for the AD1816(A) sound driver
-============================================
-
-Installation:
--------------
-
-To get your AD1816(A) based sound card work, you'll have to enable support for
-experimental code ("Prompt for development and/or incomplete code/drivers")
-and isapnp ("Plug and Play support", "ISA Plug and Play support"). Enable
-"Sound card support", "OSS modules support" and "Support for AD1816(A) based
-cards (EXPERIMENTAL)" in the sound configuration menu, too. Now build, install
-and reboot the new kernel as usual.
-
-Features:
----------
-
-List of features supported by this driver:
-- full-duplex support
-- supported audio formats: unsigned 8bit, signed 16bit little endian,
- signed 16bit big endian, µ-law, A-law
-- supported channels: mono and stereo
-- supported recording sources: Master, CD, Line, Line1, Line2, Mic
-- supports phat 3d stereo circuit (Line 3)
-
-
-Supported cards:
-----------------
-
-The following cards are known to work with this driver:
-- Terratec Base 1
-- Terratec Base 64
-- HP Kayak
-- Acer FX-3D
-- SY-1816
-- Highscreen Sound-Boostar 32 Wave 3D
-- Highscreen Sound-Boostar 16
-- AVM Apex Pro card
-- (Aztech SC-16 3D)
-- (Newcom SC-16 3D)
-- (Terratec EWS64S)
-
-Cards listed in brackets are not supported reliable. If you have such a card
-you should add the extra parameter:
- options=1
-when loading the ad1816 module via modprobe.
-
-
-Troubleshooting:
-----------------
-
-First of all you should check, if the driver has been loaded
-properly.
-
-If loading of the driver succeeds, but playback/capture fails, check
-if you used the correct values for irq, dma and dma2 when loading the module.
-If one of them is wrong you usually get the following error message:
-
-Nov 6 17:06:13 tek01 kernel: Sound: DMA (output) timed out - IRQ/DRQ config error?
-
-If playback/capture is too fast or to slow, you should have a look at
-the clock chip of your sound card. The AD1816 was designed for a 33MHz
-oscillator, however most sound card manufacturer use slightly
-different oscillators as they are cheaper than 33MHz oscillators. If
-you have such a card you have to adjust the ad1816_clockfreq parameter
-above. For example: For a card using a 32.875MHz oscillator use
-ad1816_clockfreq=32875 instead of ad1816_clockfreq=33000.
-
-
-Updates, bugfixes and bugreports:
---------------------------------
-
-As the driver is still experimental and under development, you should
-watch out for updates. Updates of the driver are available on the
-Internet from one of my home pages:
- http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
-or:
- http://www.tu-darmstadt.de/~tek01/projects/linux.html
-
-Bugreports, bugfixes and related questions should be sent via E-Mail to:
- tek@rbg.informatik.tu-darmstadt.de
-
-Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
-Christoph Hellwig <hch@infradead.org>
- Last modified: 2000/09/20
diff --git a/Documentation/sound/oss/NM256 b/Documentation/sound/oss/NM256
deleted file mode 100644
index b503217488b3..000000000000
--- a/Documentation/sound/oss/NM256
+++ /dev/null
@@ -1,280 +0,0 @@
-=======================================================
-Documentation for the NeoMagic 256AV/256ZX sound driver
-=======================================================
-
-You're looking at version 1.1 of the driver. (Woohoo!) It has been
-successfully tested against the following laptop models:
-
- Sony Z505S/Z505SX/Z505DX/Z505RX
- Sony F150, F160, F180, F250, F270, F280, PCG-F26
- Dell Latitude CPi, CPt (various submodels)
-
-There are a few caveats, which is why you should read the entirety of
-this document first.
-
-This driver was developed without any support or assistance from
-NeoMagic. There is no warranty, expressed, implied, or otherwise. It
-is free software in the public domain; feel free to use it, sell it,
-give it to your best friends, even claim that you wrote it (but why?!)
-but don't go whining to me, NeoMagic, Sony, Dell, or anyone else
-when it blows up your computer.
-
-Version 1.1 contains a change to try and detect non-AC97 versions of
-the hardware, and not install itself appropriately. It should also
-reinitialize the hardware on an APM resume event, assuming that APM
-was configured into your kernel.
-
-============
-Installation
-============
-
-Enable the sound drivers, the OSS sound drivers, and then the NM256
-driver. The NM256 driver *must* be configured as a module (it won't
-give you any other choice).
-
-Next, do the usual "make modules" and "make modules_install".
-Finally, insmod the soundcore, sound and nm256 modules.
-
-When the nm256 driver module is loaded, you should see a couple of
-confirmation messages in the kernel logfile indicating that it found
-the device (the device does *not* use any I/O ports or DMA channels).
-Now try playing a wav file, futz with the CD-ROM if you have one, etc.
-
-The NM256 is entirely a PCI-based device, and all the necessary
-information is automatically obtained from the card. It can only be
-configured as a module in a vain attempt to prevent people from
-hurting themselves. It works correctly if it shares an IRQ with
-another device (it normally shares IRQ 9 with the builtin eepro100
-ethernet on the Sony Z505 laptops).
-
-It does not run the card in any sort of compatibility mode. It will
-not work on laptops that have the SB16-compatible, AD1848-compatible
-or CS4232-compatible codec/mixer; you will want to use the appropriate
-compatible OSS driver with these chipsets. I cannot provide any
-assistance with machines using the SB16, AD1848 or CS4232 compatible
-versions. (The driver now attempts to detect the mixer version, and
-will refuse to load if it believes the hardware is not
-AC97-compatible.)
-
-The sound support is very basic, but it does include simultaneous
-playback and record capability. The mixer support is also quite
-simple, although this is in keeping with the rather limited
-functionality of the chipset.
-
-There is no hardware synthesizer available, as the Losedows OPL-3 and
-MIDI support is done via hardware emulation.
-
-Only three recording devices are available on the Sony: the
-microphone, the CD-ROM input, and the volume device (which corresponds
-to the stereo output). (Other devices may be available on other
-models of laptops.) The Z505 series does not have a builtin CD-ROM,
-so of course the CD-ROM input doesn't work. It does work on laptops
-with a builtin CD-ROM drive.
-
-The mixer device does not appear to have any tone controls, at least
-on the Z505 series. The mixer module checks for tone controls in the
-AC97 mixer, and will enable them if they are available.
-
-==============
-Known problems
-==============
-
- * There are known problems with PCMCIA cards and the eepro100 ethernet
- driver on the Z505S/Z505SX/Z505DX. Keep reading.
-
- * There are also potential problems with using a virtual X display, and
- also problems loading the module after the X server has been started.
- Keep reading.
-
- * The volume control isn't anywhere near linear. Sorry. This will be
- fixed eventually, when I get sufficiently annoyed with it. (I doubt
- it will ever be fixed now, since I've never gotten sufficiently
- annoyed with it and nobody else seems to care.)
-
- * There are reports that the CD-ROM volume is very low. Since I do not
- have a CD-ROM equipped laptop, I cannot test this (it's kinda hard to
- do remotely).
-
- * Only 8 fixed-rate speeds are supported. This is mainly a chipset
- limitation. It may be possible to support other speeds in the future.
-
- * There is no support for the telephone mixer/codec. There is support
- for a phonein/phoneout device in the mixer driver; whether or not
- it does anything is anyone's guess. (Reports on this would be
- appreciated. You'll have to figure out how to get the phone to
- go off-hook before it'll work, tho.)
-
- * This driver was not written with any cooperation or support from
- NeoMagic. If you have any questions about this, see their website
- for their official stance on supporting open source drivers.
-
-============
-Video memory
-============
-
-The NeoMagic sound engine uses a portion of the display memory to hold
-the sound buffer. (Crazy, eh?) The NeoMagic video BIOS sets up a
-special pointer at the top of video RAM to indicate where the top of
-the audio buffer should be placed.
-
-At the present time XFree86 is apparently not aware of this. It will
-thus write over either the pointer or the sound buffer with abandon.
-(Accelerated-X seems to do a better job here.)
-
-This implies a few things:
-
- * Sometimes the NM256 driver has to guess at where the buffer
- should be placed, especially if the module is loaded after the
- X server is started. It's usually correct, but it will consistently
- fail on the Sony F250.
-
- * Virtual screens greater than 1024x768x16 under XFree86 are
- problematic on laptops with only 2.5MB of screen RAM. This
- includes all of the 256AV-equipped laptops. (Virtual displays
- may or may not work on the 256ZX, which has at least 4MB of
- video RAM.)
-
-If you start having problems with random noise being output either
-constantly (this is the usual symptom on the F250), or when windows
-are moved around (this is the usual symptom when using a virtual
-screen), the best fix is to
-
- * Don't use a virtual frame buffer.
- * Make sure you load the NM256 module before the X server is
- started.
-
-On the F250, it is possible to force the driver to load properly even
-after the XFree86 server is started by doing:
-
- insmod nm256 buffertop=0x25a800
-
-This forces the audio buffers to the correct offset in screen RAM.
-
-One user has reported a similar problem on the Sony F270, although
-others apparently aren't seeing any problems. His suggested command
-is
-
- insmod nm256 buffertop=0x272800
-
-=================
-Official WWW site
-=================
-
-The official site for the NM256 driver is:
-
- http://www.uglx.org/sony.html
-
-You should always be able to get the latest version of the driver there,
-and the driver will be supported for the foreseeable future.
-
-==============
-Z505RX and IDE
-==============
-
-There appears to be a problem with the IDE chipset on the Z505RX; one
-of the symptoms is that sound playback periodically hangs (when the
-disk is accessed). The user reporting the problem also reported that
-enabling all of the IDE chipset workarounds in the kernel solved the
-problem, tho obviously only one of them should be needed--if someone
-can give me more details I would appreciate it.
-
-==============================
-Z505S/Z505SX on-board Ethernet
-==============================
-
-If you're using the on-board Ethernet Pro/100 ethernet support on the Z505
-series, I strongly encourage you to download the latest eepro100 driver from
-Donald Becker's site:
-
- ftp://cesdis.gsfc.nasa.gov/pub/linux/drivers/test/eepro100.c
-
-There was a reported problem on the Z505SX that if the ethernet
-interface is disabled and reenabled while the sound driver is loaded,
-the machine would lock up. I have included a workaround that is
-working satisfactorily. However, you may occasionally see a message
-about "Releasing interrupts, over 1000 bad interrupts" which indicates
-that the workaround is doing its job.
-
-==================================
-PCMCIA and the Z505S/Z505SX/Z505DX
-==================================
-
-There is also a known problem with the Sony Z505S and Z505SX hanging
-if a PCMCIA card is inserted while the ethernet driver is loaded, or
-in some cases if the laptop is suspended. This is caused by tons of
-spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges.
-
-There is currently no fix for the problem that works in every case.
-The only known workarounds are to disable the ethernet interface
-before inserting or removing a PCMCIA card, or with some cards
-disabling the PCMCIA card before ejecting it will also help the
-problem with the laptop hanging when the card is ejected.
-
-One user has reported that setting the tcic's cs_irq to some value
-other than 9 (like 11) fixed the problem. This doesn't work on my
-Z505S, however--changing the value causes the cardmgr to stop seeing
-card insertions and removals, cards don't seem to work correctly, and
-I still get hangs if a card is inserted when the kernel is booted.
-
-Using the latest ethernet driver and pcmcia package allows me to
-insert an Adaptec 1480A SlimScsi card without the laptop hanging,
-although I still have to shut down the card before ejecting or
-powering down the laptop. However, similar experiments with a DE-660
-ethernet card still result in hangs when the card is inserted. I am
-beginning to think that the interrupts are CardBus-related, since the
-Adaptec card is a CardBus card, and the DE-660 is not; however, I
-don't have any other CardBus cards to test with.
-
-======
-Thanks
-======
-
-First, I want to thank everyone (except NeoMagic of course) for their
-generous support and encouragement. I'd like to list everyone's name
-here that replied during the development phase, but the list is
-amazingly long.
-
-I will be rather unfair and single out a few people, however:
-
- Justin Maurer, for being the first random net.person to try it,
- and for letting me login to his Z505SX to get it working there
-
- Edi Weitz for trying out several different versions, and giving
- me a lot of useful feedback
-
- Greg Rumple for letting me login remotely to get the driver
- functional on the 256ZX, for his assistance on tracking
- down all sorts of random stuff, and for trying out Accel-X
-
- Zach Brown, for the initial AC97 mixer interface design
-
- Jeff Garzik, for various helpful suggestions on the AC97
- interface
-
- "Mr. Bumpy" for feedback on the Z505RX
-
- Bill Nottingham, for generous assistance in getting the mixer ID
- code working
-
-=================
-Previous versions
-=================
-
-Versions prior to 0.3 (aka `noname') had problems with weird artifacts
-in the output and failed to set the recording rate properly. These
-problems have long since been fixed.
-
-Versions prior to 0.5 had problems with clicks in the output when
-anything other than 16-bit stereo sound was being played, and also had
-periodic clicks when recording.
-
-Version 0.7 first incorporated support for the NM256ZX chipset, which
-is found on some Dell Latitude laptops (the CPt, and apparently
-some CPi models as well). It also included the generic AC97
-mixer module.
-
-Version 0.75 renamed all the functions and files with slightly more
-generic names.
-
-Note that previous versions of this document claimed that recording was
-8-bit only; it actually has been working for 16-bits all along.
diff --git a/Documentation/sound/oss/OPL3-SA2 b/Documentation/sound/oss/OPL3-SA2
deleted file mode 100644
index d8b6d2bbada6..000000000000
--- a/Documentation/sound/oss/OPL3-SA2
+++ /dev/null
@@ -1,210 +0,0 @@
-Documentation for the OPL3-SA2, SA3, and SAx driver (opl3sa2.o)
----------------------------------------------------------------
-
-Scott Murray, scott@spiteful.org
-January 7, 2001
-
-NOTE: All trade-marked terms mentioned below are properties of their
- respective owners.
-
-
-Supported Devices
------------------
-
-This driver is for PnP soundcards based on the following Yamaha audio
-controller chipsets:
-
-YMF711 aka OPL3-SA2
-YMF715 and YMF719 aka OPL3-SA3
-
-Up until recently (December 2000), I'd thought the 719 to be a
-different chipset, the OPL3-SAx. After an email exhange with
-Yamaha, however, it turns out that the 719 is just a re-badged
-715, and the chipsets are identical. The chipset detection code
-has been updated to reflect this.
-
-Anyways, all of these chipsets implement the following devices:
-
-OPL3 FM synthesizer
-Soundblaster Pro
-Microsoft/Windows Sound System
-MPU401 MIDI interface
-
-Note that this driver uses the MSS device, and to my knowledge these
-chipsets enforce an either/or situation with the Soundblaster Pro
-device and the MSS device. Since the MSS device has better
-capabilities, I have implemented the driver to use it.
-
-
-Mixer Channels
---------------
-
-Older versions of this driver (pre-December 2000) had two mixers,
-an OPL3-SA2 or SA3 mixer and a MSS mixer. The OPL3-SA[23] mixer
-device contained a superset of mixer channels consisting of its own
-channels and all of the MSS mixer channels. To simplify the driver
-considerably, and to partition functionality better, the OPL3-SA[23]
-mixer device now contains has its own specific mixer channels. They
-are:
-
-Volume - Hardware master volume control
-Bass - SA3 only, now supports left and right channels
-Treble - SA3 only, now supports left and right channels
-Microphone - Hardware microphone input volume control
-Digital1 - Yamaha 3D enhancement "Wide" mixer
-
-All other mixer channels (e.g. "PCM", "CD", etc.) now have to be
-controlled via the "MS Sound System (CS4231)" mixer. To facilitate
-this, the mixer device creation order has been switched so that
-the MSS mixer is created first. This allows accessing the majority
-of the useful mixer channels even via single mixer-aware tools
-such as "aumix".
-
-
-Plug 'n Play
-------------
-
-In previous kernels (2.2.x), some configuration was required to
-get the driver to talk to the card. Being the new millennium and
-all, the 2.4.x kernels now support auto-configuration if ISA PnP
-support is configured in. Theoretically, the driver even supports
-having more than one card in this case.
-
-With the addition of PnP support to the driver, two new parameters
-have been added to control it:
-
-isapnp - set to 0 to disable ISA PnP card detection
-
-multiple - set to 0 to disable multiple PnP card detection
-
-
-Optional Parameters
--------------------
-
-Recent (December 2000) additions to the driver (based on a patch
-provided by Peter Englmaier) are two new parameters:
-
-ymode - Set Yamaha 3D enhancement mode:
- 0 = Desktop/Normal 5-12 cm speakers
- 1 = Notebook PC (1) 3 cm speakers
- 2 = Notebook PC (2) 1.5 cm speakers
- 3 = Hi-Fi 16-38 cm speakers
-
-loopback - Set A/D input source. Useful for echo cancellation:
- 0 = Mic Right channel (default)
- 1 = Mono output loopback
-
-The ymode parameter has been tested and does work. The loopback
-parameter, however, is untested. Any feedback on its usefulness
-would be appreciated.
-
-
-Manual Configuration
---------------------
-
-If for some reason you decide not to compile ISA PnP support into
-your kernel, or disabled the driver's usage of it by setting the
-isapnp parameter as discussed above, then you will need to do some
-manual configuration. There are two ways of doing this. The most
-common is to use the isapnptools package to initialize the card, and
-use the kernel module form of the sound subsystem and sound drivers.
-Alternatively, some BIOS's allow manual configuration of installed
-PnP devices in a BIOS menu, which should allow using the non-modular
-sound drivers, i.e. built into the kernel.
-
-I personally use isapnp and modules, and do not have access to a PnP
-BIOS machine to test. If you have such a beast, configuring the
-driver to be built into the kernel should just work (thanks to work
-done by David Luyer <luyer@ucs.uwa.edu.au>). You will still need
-to specify settings, which can be done by adding:
-
-opl3sa2=<io>,<irq>,<dma>,<dma2>,<mssio>,<mpuio>
-
-to the kernel command line. For example:
-
-opl3sa2=0x370,5,0,1,0x530,0x330
-
-If you are instead using the isapnp tools (as most people have been
-before Linux 2.4.x), follow the directions in their documentation to
-produce a configuration file. Here is the relevant excerpt I used to
-use for my SA3 card from my isapnp.conf:
-
-(CONFIGURE YMH0800/-1 (LD 0
-
-# NOTE: IO 0 is for the unused SoundBlaster part of the chipset.
-(IO 0 (BASE 0x0220))
-(IO 1 (BASE 0x0530))
-(IO 2 (BASE 0x0388))
-(IO 3 (BASE 0x0330))
-(IO 4 (BASE 0x0370))
-(INT 0 (IRQ 5 (MODE +E)))
-(DMA 0 (CHANNEL 0))
-(DMA 1 (CHANNEL 1))
-
-Here, note that:
-
-Port Acceptable Range Purpose
----- ---------------- -------
-IO 0 0x0220 - 0x0280 SB base address, unused.
-IO 1 0x0530 - 0x0F48 MSS base address
-IO 2 0x0388 - 0x03F8 OPL3 base address
-IO 3 0x0300 - 0x0334 MPU base address
-IO 4 0x0100 - 0x0FFE card's own base address for its control I/O ports
-
-The IRQ and DMA values can be any that are considered acceptable for a
-MSS. Assuming you've got isapnp all happy, then you should be able to
-do something like the following (which matches up with the isapnp
-configuration above):
-
-modprobe mpu401
-modprobe ad1848
-modprobe opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=5 dma=0 dma2=1
-modprobe opl3 io=0x388
-
-See the section "Automatic Module Loading" below for how to set up
-/etc/modprobe.conf to automate this.
-
-An important thing to remember that the opl3sa2 module's io argument is
-for it's own control port, which handles the card's master mixer for
-volume (on all cards), and bass and treble (on SA3 cards).
-
-
-Troubleshooting
----------------
-
-If all goes well and you see no error messages, you should be able to
-start using the sound capabilities of your system. If you get an
-error message while trying to insert the opl3sa2 module, then make
-sure that the values of the various arguments match what you specified
-in your isapnp configuration file, and that there is no conflict with
-another device for an I/O port or interrupt. Checking the contents of
-/proc/ioports and /proc/interrupts can be useful to see if you're
-butting heads with another device.
-
-If you still cannot get the module to load, look at the contents of
-your system log file, usually /var/log/messages. If you see the
-message "opl3sa2: Unknown Yamaha audio controller version", then you
-have a different chipset version than I've encountered so far. Look
-for all messages in the log file that start with "opl3sa2: " and see
-if they provide any clues. If you do not see the chipset version
-message, and none of the other messages present in the system log are
-helpful, email me some details and I'll try my best to help.
-
-
-Automatic Module Loading
-------------------------
-
-Lastly, if you're using modules and want to set up automatic module
-loading with kmod, the kernel module loader, here is the section I
-currently use in my modprobe.conf file:
-
-# Sound
-alias sound-slot-0 opl3sa2
-options opl3sa2 io=0x370 mss_io=0x530 mpu_io=0x330 irq=7 dma=0 dma2=3
-options opl3 io=0x388
-
-That's all it currently takes to get an OPL3-SA3 card working on my
-system. Once again, if you have any other problems, email me at the
-address listed above.
-
-Scott
diff --git a/Documentation/sound/oss/VIA-chipset b/Documentation/sound/oss/VIA-chipset
deleted file mode 100644
index 37865234e54d..000000000000
--- a/Documentation/sound/oss/VIA-chipset
+++ /dev/null
@@ -1,43 +0,0 @@
-Running sound cards on VIA chipsets
-
-o There are problems with VIA chipsets and sound cards that appear to
- lock the hardware solidly. Test programs under DOS have verified the
- problem exists on at least some (but apparently not all) VIA boards
-
-o VIA have so far failed to bother to answer support mail on the subject
- so if you are a VIA engineer feeling aggrieved as you read this
- document go chase your own people. If there is a workaround please
- let us know so we can implement it.
-
-
-Certain patterns of ISA DMA access used for most PC sound cards cause the
-VIA chipsets to lock up. From the collected reports this appears to cover a
-wide range of boards. Some also lock up with sound cards under Win* as well.
-
-Linux implements a workaround providing your chipset is PCI and you compiled
-with PCI Quirks enabled. If so you will see a message
- "Activating ISA DMA bug workarounds"
-
-during booting. If you have a VIA PCI chipset that hangs when you use the
-sound and is not generating this message even with PCI quirks enabled
-please report the information to the linux-kernel list (see REPORTING-BUGS).
-
-If you are one of the tiny number of unfortunates with a 486 ISA/VLB VIA
-chipset board you need to do the following to build a special kernel for
-your board
-
- edit linux/include/asm-i386/dma.h
-
-change
-
-#define isa_dma_bridge_buggy (0)
-
-to
-
-#define isa_dma_bridge_buggy (1)
-
-and rebuild a kernel without PCI quirk support.
-
-
-Other than this particular glitch the VIA [M]VP* chipsets appear to work
-perfectly with Linux.
diff --git a/Documentation/sound/oss/cs46xx b/Documentation/sound/oss/cs46xx
deleted file mode 100644
index b54432709863..000000000000
--- a/Documentation/sound/oss/cs46xx
+++ /dev/null
@@ -1,138 +0,0 @@
-
-Documentation for the Cirrus Logic/Crystal SoundFusion cs46xx/cs4280 audio
-controller chips (2001/05/11)
-
-The cs46xx audio driver supports the DSP line of Cirrus controllers.
-Specifically, the cs4610, cs4612, cs4614, cs4622, cs4624, cs4630 and the cs4280
-products. This driver uses the generic ac97_codec driver for AC97 codec
-support.
-
-
-Features:
-
-Full Duplex Playback/Capture supported from 8k-48k.
-16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
-
-APM/PM - 2.2.x PM is enabled and functional. APM can also
-be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
-definition.
-
-DMA playback buffer size is configurable from 16k (defaultorder=2) up to 2Meg
-(defaultorder=11). DMA capture buffer size is fixed at a single 4k page as
-two 2k fragments.
-
-MMAP seems to work well with QuakeIII, and test XMMS plugin.
-
-Myth2 works, but the polling logic is not fully correct, but is functional.
-
-The 2.4.4-ac6 gameport code in the cs461x joystick driver has been tested
-with a Microsoft Sidewinder joystick (cs461x.o and sidewinder.o). This
-audio driver must be loaded prior to the joystick driver to enable the
-DSP task image supporting the joystick device.
-
-
-Limitations:
-
-SPDIF is currently not supported.
-
-Primary codec support only. No secondary codec support is implemented.
-
-
-
-NOTES:
-
-Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
-and has been tested.
-Module parameter hercules_egpio_disable set to 1, will force a 0 to EGPIODR
-to disable the external amplifier.
-
-VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
-the external amplifier for the "back" speakers, since we do not
-support the secondary codec then this external amp is not
-turned on. The primary codec external amplifier is supported but
-note that the AC97 EAPD bit is inverted logic (amp_voyetra()).
-
-DMA buffer size - there are issues with many of the Linux applications
-concerning the optimal buffer size. Several applications request a
-certain fragment size and number and then do not verify that the driver
-has the ability to support the requested configuration.
-SNDCTL_DSP_SETFRAGMENT ioctl is used to request a fragment size and
-number of fragments. Some applications exit if an error is returned
-on this particular ioctl. Therefore, in alignment with the other OSS audio
-drivers, no error is returned when a SETFRAGs IOCTL is received, but the
-values passed from the app are not used in any buffer calculation
-(ossfragshift/ossmaxfrags are not used).
-Use the "defaultorder=N" module parameter to change the buffer size if
-you have an application that requires a specific number of fragments
-or a specific buffer size (see below).
-
-Debug Interface
----------------
-There is an ioctl debug interface to allow runtime modification of the
-debug print levels. This debug interface code can be disabled from the
-compilation process with commenting the following define:
-#define CSDEBUG_INTERFACE 1
-There is also a debug print methodolgy to select printf statements from
-different areas of the driver. A debug print level is also used to allow
-additional printfs to be active. Comment out the following line in the
-driver to disable compilation of the CS_DBGOUT print statements:
-#define CSDEBUG 1
-
-Please see the definitions for cs_debuglevel and cs_debugmask for additional
-information on the debug levels and sections.
-
-There is also a csdbg executable to allow runtime manipulation of these
-parameters. for a copy email: twoller@crystal.cirrus.com
-
-
-
-MODULE_PARMS definitions
-------------------------
-module_param(defaultorder, ulong, 0);
-defaultorder=N
-where N is a value from 1 to 12
-The buffer order determines the size of the dma buffer for the driver.
-under Linux, a smaller buffer allows more responsiveness from many of the
-applications (e.g. games). A larger buffer allows some of the apps (esound)
-to not underrun the dma buffer as easily. As default, use 32k (order=3)
-rather than 64k as some of the games work more responsively.
-(2^N) * PAGE_SIZE = allocated buffer size
-
-module_param(cs_debuglevel, ulong, 0644);
-module_param(cs_debugmask, ulong, 0644);
-cs_debuglevel=N
-cs_debugmask=0xMMMMMMMM
-where N is a value from 0 (no debug printfs), to 9 (maximum)
-0xMMMMMMMM is a debug mask corresponding to the CS_xxx bits (see driver source).
-
-module_param(hercules_egpio_disable, ulong, 0);
-hercules_egpio_disable=N
-where N is a 0 (enable egpio), or a 1 (disable egpio support)
-
-module_param(initdelay, ulong, 0);
-initdelay=N
-This value is used to determine the millescond delay during the initialization
-code prior to powering up the PLL. On laptops this value can be used to
-assist with errors on resume, mostly with IBM laptops. Basically, if the
-system is booted under battery power then the mdelay()/udelay() functions fail to
-properly delay the required time. Also, if the system is booted under AC power
-and then the power removed, the mdelay()/udelay() functions will not delay properly.
-
-module_param(powerdown, ulong, 0);
-powerdown=N
-where N is 0 (disable any powerdown of the internal blocks) or 1 (enable powerdown)
-
-
-module_param(external_amp, bool, 0);
-external_amp=1
-if N is set to 1, then force enabling the EAPD support in the primary AC97 codec.
-override the detection logic and force the external amp bit in the AC97 0x26 register
-to be reset (0). EAPD should be 0 for powerup, and 1 for powerdown. The VTB Santa Cruz
-card has inverted logic, so there is a special function for these cards.
-
-module_param(thinkpad, bool, 0);
-thinkpad=1
-if N is set to 1, then force enabling the clkrun functionality.
-Currently, when the part is being used, then clkrun is disabled for the entire system,
-but re-enabled when the driver is released or there is no outstanding open count.
-
diff --git a/Documentation/spi/spi-lm70llp b/Documentation/spi/spi-lm70llp
new file mode 100644
index 000000000000..154bd02220b9
--- /dev/null
+++ b/Documentation/spi/spi-lm70llp
@@ -0,0 +1,69 @@
+spi_lm70llp : LM70-LLP parport-to-SPI adapter
+==============================================
+
+Supported board/chip:
+ * National Semiconductor LM70 LLP evaluation board
+ Datasheet: http://www.national.com/pf/LM/LM70.html
+
+Author:
+ Kaiwan N Billimoria <kaiwan@designergraphix.com>
+
+Description
+-----------
+This driver provides glue code connecting a National Semiconductor LM70 LLP
+temperature sensor evaluation board to the kernel's SPI core subsystem.
+
+In effect, this driver turns the parallel port interface on the eval board
+into a SPI bus with a single device, which will be driven by the generic
+LM70 driver (drivers/hwmon/lm70.c).
+
+The hardware interfacing on the LM70 LLP eval board is as follows:
+
+ Parallel LM70 LLP
+ Port Direction JP2 Header
+ ----------- --------- ----------------
+ D0 2 - -
+ D1 3 --> V+ 5
+ D2 4 --> V+ 5
+ D3 5 --> V+ 5
+ D4 6 --> V+ 5
+ D5 7 --> nCS 8
+ D6 8 --> SCLK 3
+ D7 9 --> SI/O 5
+ GND 25 - GND 7
+ Select 13 <-- SI/O 1
+ ----------- --------- ----------------
+
+Note that since the LM70 uses a "3-wire" variant of SPI, the SI/SO pin
+is connected to both pin D7 (as Master Out) and Select (as Master In)
+using an arrangment that lets either the parport or the LM70 pull the
+pin low. This can't be shared with true SPI devices, but other 3-wire
+devices might share the same SI/SO pin.
+
+The bitbanger routine in this driver (lm70_txrx) is called back from
+the bound "hwmon/lm70" protocol driver through its sysfs hook, using a
+spi_write_then_read() call. It performs Mode 0 (SPI/Microwire) bitbanging.
+The lm70 driver then inteprets the resulting digital temperature value
+and exports it through sysfs.
+
+A "gotcha": National Semiconductor's LM70 LLP eval board circuit schematic
+shows that the SI/O line from the LM70 chip is connected to the base of a
+transistor Q1 (and also a pullup, and a zener diode to D7); while the
+collector is tied to VCC.
+
+Interpreting this circuit, when the LM70 SI/O line is High (or tristate
+and not grounded by the host via D7), the transistor conducts and switches
+the collector to zero, which is reflected on pin 13 of the DB25 parport
+connector. When SI/O is Low (driven by the LM70 or the host) on the other
+hand, the transistor is cut off and the voltage tied to it's collector is
+reflected on pin 13 as a High level.
+
+So: the getmiso inline routine in this driver takes this fact into account,
+inverting the value read at pin 13.
+
+
+Thanks to
+---------
+o David Brownell for mentoring the SPI-side driver development.
+o Dr.Craig Hollabaugh for the (early) "manual" bitbanging driver version.
+o Nadir Billimoria for help interpreting the circuit schematic.
diff --git a/Documentation/spinlocks.txt b/Documentation/spinlocks.txt
index a661d684768e..471e75389778 100644
--- a/Documentation/spinlocks.txt
+++ b/Documentation/spinlocks.txt
@@ -1,7 +1,12 @@
-UPDATE March 21 2005 Amit Gud <gud@eth.net>
+SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED defeat lockdep state tracking and
+are hence deprecated.
-Macros SPIN_LOCK_UNLOCKED and RW_LOCK_UNLOCKED are deprecated and will be
-removed soon. So for any new code dynamic initialization should be used:
+Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or
+__SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate for static
+initialization.
+
+Dynamic initialization, when necessary, may be performed as
+demonstrated below.
spinlock_t xxx_lock;
rwlock_t xxx_rw_lock;
@@ -15,12 +20,9 @@ removed soon. So for any new code dynamic initialization should be used:
module_init(xxx_init);
-Reasons for deprecation
- - it hurts automatic lock validators
- - it becomes intrusive for the realtime preemption patches
-
-Following discussion is still valid, however, with the dynamic initialization
-of spinlocks instead of static.
+The following discussion is still valid, however, with the dynamic
+initialization of spinlocks or with DEFINE_SPINLOCK, etc., used
+instead of SPIN_LOCK_UNLOCKED.
-----------------------
diff --git a/Documentation/sysctl/ctl_unnumbered.txt b/Documentation/sysctl/ctl_unnumbered.txt
new file mode 100644
index 000000000000..23003a8ea3e7
--- /dev/null
+++ b/Documentation/sysctl/ctl_unnumbered.txt
@@ -0,0 +1,22 @@
+
+Except for a few extremely rare exceptions user space applications do not use
+the binary sysctl interface. Instead everyone uses /proc/sys/... with
+readable ascii names.
+
+Recently the kernel has started supporting setting the binary sysctl value to
+CTL_UNNUMBERED so we no longer need to assign a binary sysctl path to allow
+sysctls to show up in /proc/sys.
+
+Assigning binary sysctl numbers is an endless source of conflicts in sysctl.h,
+breaking of the user space ABI (because of those conflicts), and maintenance
+problems. A complete pass through all of the sysctl users revealed multiple
+instances where the sysctl binary interface was broken and had gone undetected
+for years.
+
+So please do not add new binary sysctl numbers. They are unneeded and
+problematic.
+
+If you really need a new binary sysctl number please first merge your sysctl
+into the kernel and then as a separate patch allocate a binary sysctl number.
+
+(ebiederm@xmission.com, June 2007)
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 1d192565e182..a0ccc5b60260 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -31,12 +31,15 @@ Currently, these files are in /proc/sys/vm:
- min_unmapped_ratio
- min_slab_ratio
- panic_on_oom
+- mmap_min_address
+- numa_zonelist_order
==============================================================
dirty_ratio, dirty_background_ratio, dirty_expire_centisecs,
dirty_writeback_centisecs, vfs_cache_pressure, laptop_mode,
-block_dump, swap_token_timeout, drop-caches:
+block_dump, swap_token_timeout, drop-caches,
+hugepages_treat_as_movable:
See Documentation/filesystems/proc.txt
@@ -216,3 +219,61 @@ above-mentioned.
The default value is 0.
1 and 2 are for failover of clustering. Please select either
according to your policy of failover.
+
+==============================================================
+
+mmap_min_addr
+
+This file indicates the amount of address space which a user process will
+be restricted from mmaping. Since kernel null dereference bugs could
+accidentally operate based on the information in the first couple of pages
+of memory userspace processes should not be allowed to write to them. By
+default this value is set to 0 and no protections will be enforced by the
+security module. Setting this value to something like 64k will allow the
+vast majority of applications to work correctly and provide defense in depth
+against future potential kernel bugs.
+
+==============================================================
+
+numa_zonelist_order
+
+This sysctl is only for NUMA.
+'where the memory is allocated from' is controlled by zonelists.
+(This documentation ignores ZONE_HIGHMEM/ZONE_DMA32 for simple explanation.
+ you may be able to read ZONE_DMA as ZONE_DMA32...)
+
+In non-NUMA case, a zonelist for GFP_KERNEL is ordered as following.
+ZONE_NORMAL -> ZONE_DMA
+This means that a memory allocation request for GFP_KERNEL will
+get memory from ZONE_DMA only when ZONE_NORMAL is not available.
+
+In NUMA case, you can think of following 2 types of order.
+Assume 2 node NUMA and below is zonelist of Node(0)'s GFP_KERNEL
+
+(A) Node(0) ZONE_NORMAL -> Node(0) ZONE_DMA -> Node(1) ZONE_NORMAL
+(B) Node(0) ZONE_NORMAL -> Node(1) ZONE_NORMAL -> Node(0) ZONE_DMA.
+
+Type(A) offers the best locality for processes on Node(0), but ZONE_DMA
+will be used before ZONE_NORMAL exhaustion. This increases possibility of
+out-of-memory(OOM) of ZONE_DMA because ZONE_DMA is tend to be small.
+
+Type(B) cannot offer the best locality but is more robust against OOM of
+the DMA zone.
+
+Type(A) is called as "Node" order. Type (B) is "Zone" order.
+
+"Node order" orders the zonelists by node, then by zone within each node.
+Specify "[Nn]ode" for zone order
+
+"Zone Order" orders the zonelists by zone type, then by node within each
+zone. Specify "[Zz]one"for zode order.
+
+Specify "[Dd]efault" to request automatic configuration. Autoconfiguration
+will select "node" order in following case.
+(1) if the DMA zone does not exist or
+(2) if the DMA zone comprises greater than 50% of the available memory or
+(3) if any node's DMA zone comprises greater than 60% of its local memory and
+ the amount of local memory is big enough.
+
+Otherwise, "zone" order will be selected. Default order is recommended unless
+this is causing problems for your system/application.
diff --git a/Documentation/sysfs-rules.txt b/Documentation/sysfs-rules.txt
new file mode 100644
index 000000000000..42861bb0bc9b
--- /dev/null
+++ b/Documentation/sysfs-rules.txt
@@ -0,0 +1,166 @@
+Rules on how to access information in the Linux kernel sysfs
+
+The kernel exported sysfs exports internal kernel implementation-details
+and depends on internal kernel structures and layout. It is agreed upon
+by the kernel developers that the Linux kernel does not provide a stable
+internal API. As sysfs is a direct export of kernel internal
+structures, the sysfs interface can not provide a stable interface eighter,
+it may always change along with internal kernel changes.
+
+To minimize the risk of breaking users of sysfs, which are in most cases
+low-level userspace applications, with a new kernel release, the users
+of sysfs must follow some rules to use an as abstract-as-possible way to
+access this filesystem. The current udev and HAL programs already
+implement this and users are encouraged to plug, if possible, into the
+abstractions these programs provide instead of accessing sysfs
+directly.
+
+But if you really do want or need to access sysfs directly, please follow
+the following rules and then your programs should work with future
+versions of the sysfs interface.
+
+- Do not use libsysfs
+ It makes assumptions about sysfs which are not true. Its API does not
+ offer any abstraction, it exposes all the kernel driver-core
+ implementation details in its own API. Therefore it is not better than
+ reading directories and opening the files yourself.
+ Also, it is not actively maintained, in the sense of reflecting the
+ current kernel-development. The goal of providing a stable interface
+ to sysfs has failed, it causes more problems, than it solves. It
+ violates many of the rules in this document.
+
+- sysfs is always at /sys
+ Parsing /proc/mounts is a waste of time. Other mount points are a
+ system configuration bug you should not try to solve. For test cases,
+ possibly support a SYSFS_PATH environment variable to overwrite the
+ applications behavior, but never try to search for sysfs. Never try
+ to mount it, if you are not an early boot script.
+
+- devices are only "devices"
+ There is no such thing like class-, bus-, physical devices,
+ interfaces, and such that you can rely on in userspace. Everything is
+ just simply a "device". Class-, bus-, physical, ... types are just
+ kernel implementation details, which should not be expected by
+ applications that look for devices in sysfs.
+
+ The properties of a device are:
+ o devpath (/devices/pci0000:00/0000:00:1d.1/usb2/2-2/2-2:1.0)
+ - identical to the DEVPATH value in the event sent from the kernel
+ at device creation and removal
+ - the unique key to the device at that point in time
+ - the kernels path to the device-directory without the leading
+ /sys, and always starting with with a slash
+ - all elements of a devpath must be real directories. Symlinks
+ pointing to /sys/devices must always be resolved to their real
+ target, and the target path must be used to access the device.
+ That way the devpath to the device matches the devpath of the
+ kernel used at event time.
+ - using or exposing symlink values as elements in a devpath string
+ is a bug in the application
+
+ o kernel name (sda, tty, 0000:00:1f.2, ...)
+ - a directory name, identical to the last element of the devpath
+ - applications need to handle spaces and characters like '!' in
+ the name
+
+ o subsystem (block, tty, pci, ...)
+ - simple string, never a path or a link
+ - retrieved by reading the "subsystem"-link and using only the
+ last element of the target path
+
+ o driver (tg3, ata_piix, uhci_hcd)
+ - a simple string, which may contain spaces, never a path or a
+ link
+ - it is retrieved by reading the "driver"-link and using only the
+ last element of the target path
+ - devices which do not have "driver"-link, just do not have a
+ driver; copying the driver value in a child device context, is a
+ bug in the application
+
+ o attributes
+ - the files in the device directory or files below a subdirectories
+ of the same device directory
+ - accessing attributes reached by a symlink pointing to another device,
+ like the "device"-link, is a bug in the application
+
+ Everything else is just a kernel driver-core implementation detail,
+ that should not be assumed to be stable across kernel releases.
+
+- Properties of parent devices never belong into a child device.
+ Always look at the parent devices themselves for determining device
+ context properties. If the device 'eth0' or 'sda' does not have a
+ "driver"-link, then this device does not have a driver. Its value is empty.
+ Never copy any property of the parent-device into a child-device. Parent
+ device-properties may change dynamically without any notice to the
+ child device.
+
+- Hierarchy in a single device-tree
+ There is only one valid place in sysfs where hierarchy can be examined
+ and this is below: /sys/devices.
+ It is planned, that all device directories will end up in the tree
+ below this directory.
+
+- Classification by subsystem
+ There are currently three places for classification of devices:
+ /sys/block, /sys/class and /sys/bus. It is planned that these will
+ not contain any device-directories themselves, but only flat lists of
+ symlinks pointing to the unified /sys/devices tree.
+ All three places have completely different rules on how to access
+ device information. It is planned to merge all three
+ classification-directories into one place at /sys/subsystem,
+ following the layout of the bus-directories. All buses and
+ classes, including the converted block-subsystem, will show up
+ there.
+ The devices belonging to a subsystem will create a symlink in the
+ "devices" directory at /sys/subsystem/<name>/devices.
+
+ If /sys/subsystem exists, /sys/bus, /sys/class and /sys/block can be
+ ignored. If it does not exist, you have always to scan all three
+ places, as the kernel is free to move a subsystem from one place to
+ the other, as long as the devices are still reachable by the same
+ subsystem name.
+
+ Assuming /sys/class/<subsystem> and /sys/bus/<subsystem>, or
+ /sys/block and /sys/class/block are not interchangeable, is a bug in
+ the application.
+
+- Block
+ The converted block-subsystem at /sys/class/block, or
+ /sys/subsystem/block will contain the links for disks and partitions
+ at the same level, never in a hierarchy. Assuming the block-subsytem to
+ contain only disks and not partition-devices in the same flat list is
+ a bug in the application.
+
+- "device"-link and <subsystem>:<kernel name>-links
+ Never depend on the "device"-link. The "device"-link is a workaround
+ for the old layout, where class-devices are not created in
+ /sys/devices/ like the bus-devices. If the link-resolving of a
+ device-directory does not end in /sys/devices/, you can use the
+ "device"-link to find the parent devices in /sys/devices/. That is the
+ single valid use of the "device"-link, it must never appear in any
+ path as an element. Assuming the existence of the "device"-link for
+ a device in /sys/devices/ is a bug in the application.
+ Accessing /sys/class/net/eth0/device is a bug in the application.
+
+ Never depend on the class-specific links back to the /sys/class
+ directory. These links are also a workaround for the design mistake
+ that class-devices are not created in /sys/devices. If a device
+ directory does not contain directories for child devices, these links
+ may be used to find the child devices in /sys/class. That is the single
+ valid use of these links, they must never appear in any path as an
+ element. Assuming the existence of these links for devices which are
+ real child device directories in the /sys/devices tree, is a bug in
+ the application.
+
+ It is planned to remove all these links when when all class-device
+ directories live in /sys/devices.
+
+- Position of devices along device chain can change.
+ Never depend on a specific parent device position in the devpath,
+ or the chain of parent devices. The kernel is free to insert devices into
+ the chain. You must always request the parent device you are looking for
+ by its subsystem value. You need to walk up the chain until you find
+ the device that matches the expected subsystem. Depending on a specific
+ position of a parent device, or exposing relative paths, using "../" to
+ access the chain of parents, is a bug in the application.
+
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index 9e6b94face4b..6711fbcf4080 100644
--- a/Documentation/thinkpad-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -1,11 +1,11 @@
ThinkPad ACPI Extras Driver
- Version 0.14
- April 21st, 2007
+ Version 0.15
+ July 1st, 2007
Borislav Deianov <borislav@users.sf.net>
- Henrique de Moraes Holschuh <hmh@hmh.eng.br>
- http://ibm-acpi.sf.net/
+ Henrique de Moraes Holschuh <hmh@hmh.eng.br>
+ http://ibm-acpi.sf.net/
This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
@@ -134,54 +134,68 @@ end of this document. Changes to the sysfs interface done by the kernel
subsystems are not documented here, nor are they tracked by this
attribute.
+Changes to the thinkpad-acpi sysfs interface are only considered
+non-experimental when they are submitted to Linux mainline, at which
+point the changes in this interface are documented and interface_version
+may be updated. If you are using any thinkpad-acpi features not yet
+sent to mainline for merging, you do so on your own risk: these features
+may disappear, or be implemented in a different and incompatible way by
+the time they are merged in Linux mainline.
+
+Changes that are backwards-compatible by nature (e.g. the addition of
+attributes that do not change the way the other attributes work) do not
+always warrant an update of interface_version. Therefore, one must
+expect that an attribute might not be there, and deal with it properly
+(an attribute not being there *is* a valid way to make it clear that a
+feature is not available in sysfs).
+
Hot keys
--------
procfs: /proc/acpi/ibm/hotkey
sysfs device attribute: hotkey_*
-Without this driver, only the Fn-F4 key (sleep button) generates an
-ACPI event. With the driver loaded, the hotkey feature enabled and the
-mask set (see below), the various hot keys generate ACPI events in the
+In a ThinkPad, the ACPI HKEY handler is responsible for comunicating
+some important events and also keyboard hot key presses to the operating
+system. Enabling the hotkey functionality of thinkpad-acpi signals the
+firmware that such a driver is present, and modifies how the ThinkPad
+firmware will behave in many situations.
+
+When the hotkey feature is enabled and the hot key mask is set (see
+below), the various hot keys either generate ACPI events in the
following format:
ibm/hotkey HKEY 00000080 0000xxxx
-The last four digits vary depending on the key combination pressed.
-All labeled Fn-Fx key combinations generate distinct events. In
-addition, the lid microswitch and some docking station buttons may
-also generate such events.
-
-The bit mask allows some control over which hot keys generate ACPI
-events. Not all bits in the mask can be modified. Not all bits that
-can be modified do anything. Not all hot keys can be individually
-controlled by the mask. Most recent ThinkPad models honor the
-following bits (assuming the hot keys feature has been enabled):
-
- key bit behavior when set behavior when unset
-
- Fn-F3 always generates ACPI event
- Fn-F4 always generates ACPI event
- Fn-F5 0010 generate ACPI event enable/disable Bluetooth
- Fn-F7 0040 generate ACPI event switch LCD and external display
- Fn-F8 0080 generate ACPI event expand screen or none
- Fn-F9 0100 generate ACPI event none
- Fn-F12 always generates ACPI event
-
-Some models do not support all of the above. For example, the T30 does
-not support Fn-F5 and Fn-F9. Other models do not support the mask at
-all. On those models, hot keys cannot be controlled individually.
-
-Note that enabling ACPI events for some keys prevents their default
-behavior. For example, if events for Fn-F5 are enabled, that key will
-no longer enable/disable Bluetooth by itself. This can still be done
-from an acpid handler for the ibm/hotkey event.
-
-Note also that not all Fn key combinations are supported through
-ACPI. For example, on the X40, the brightness, volume and "Access IBM"
-buttons do not generate ACPI events even with this driver. They *can*
-be used through the "ThinkPad Buttons" utility, see
-http://www.nongnu.org/tpb/
+or events over the input layer. The input layer support accepts the
+standard IOCTLs to remap the keycodes assigned to each hotkey.
+
+When the input device is open, the driver will suppress any ACPI hot key
+events that get translated into a meaningful input layer event, in order
+to avoid sending duplicate events to userspace. Hot keys that are
+mapped to KEY_RESERVED in the keymap are not translated, and will always
+generate an ACPI ibm/hotkey HKEY event, and no input layer events.
+
+The hot key bit mask allows some control over which hot keys generate
+events. If a key is "masked" (bit set to 0 in the mask), the firmware
+will handle it. If it is "unmasked", it signals the firmware that
+thinkpad-acpi would prefer to handle it, if the firmware would be so
+kind to allow it (and it often doesn't!).
+
+Not all bits in the mask can be modified. Not all bits that can be
+modified do anything. Not all hot keys can be individually controlled
+by the mask. Some models do not support the mask at all, and in those
+models, hot keys cannot be controlled individually. The behaviour of
+the mask is, therefore, higly dependent on the ThinkPad model.
+
+Note that unmasking some keys prevents their default behavior. For
+example, if Fn+F5 is unmasked, that key will no longer enable/disable
+Bluetooth by itself.
+
+Note also that not all Fn key combinations are supported through ACPI.
+For example, on the X40, the brightness, volume and "Access IBM" buttons
+do not generate ACPI events even with this driver. They *can* be used
+through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/
procfs notes:
@@ -189,9 +203,9 @@ The following commands can be written to the /proc/acpi/ibm/hotkey file:
echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
- echo 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
- echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
- ... any other 4-hex-digit mask ...
+ echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
+ echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
+ ... any other 8-hex-digit mask ...
echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
sysfs notes:
@@ -202,7 +216,7 @@ sysfs notes:
key feature status will be restored to this value.
0: hot keys were disabled
- 1: hot keys were enabled
+ 1: hot keys were enabled (unusual)
hotkey_bios_mask:
Returns the hot keys mask when thinkpad-acpi was loaded.
@@ -217,9 +231,182 @@ sysfs notes:
1: enables the hot keys feature / feature enabled
hotkey_mask:
- bit mask to enable ACPI event generation for each hot
- key (see above). Returns the current status of the hot
- keys mask, and allows one to modify it.
+ bit mask to enable driver-handling and ACPI event
+ generation for each hot key (see above). Returns the
+ current status of the hot keys mask, and allows one to
+ modify it.
+
+ hotkey_all_mask:
+ bit mask that should enable event reporting for all
+ supported hot keys, when echoed to hotkey_mask above.
+ Unless you know which events need to be handled
+ passively (because the firmware *will* handle them
+ anyway), do *not* use hotkey_all_mask. Use
+ hotkey_recommended_mask, instead. You have been warned.
+
+ hotkey_recommended_mask:
+ bit mask that should enable event reporting for all
+ supported hot keys, except those which are always
+ handled by the firmware anyway. Echo it to
+ hotkey_mask above, to use.
+
+ hotkey_radio_sw:
+ if the ThinkPad has a hardware radio switch, this
+ attribute will read 0 if the switch is in the "radios
+ disabled" postition, and 1 if the switch is in the
+ "radios enabled" position.
+
+input layer notes:
+
+A Hot key is mapped to a single input layer EV_KEY event, possibly
+followed by an EV_MSC MSC_SCAN event that shall contain that key's scan
+code. An EV_SYN event will always be generated to mark the end of the
+event block.
+
+Do not use the EV_MSC MSC_SCAN events to process keys. They are to be
+used as a helper to remap keys, only. They are particularly useful when
+remapping KEY_UNKNOWN keys.
+
+The events are available in an input device, with the following id:
+
+ Bus: BUS_HOST
+ vendor: 0x1014 (PCI_VENDOR_ID_IBM) or
+ 0x17aa (PCI_VENDOR_ID_LENOVO)
+ product: 0x5054 ("TP")
+ version: 0x4101
+
+The version will have its LSB incremented if the keymap changes in a
+backwards-compatible way. The MSB shall always be 0x41 for this input
+device. If the MSB is not 0x41, do not use the device as described in
+this section, as it is either something else (e.g. another input device
+exported by a thinkpad driver, such as HDAPS) or its functionality has
+been changed in a non-backwards compatible way.
+
+Adding other event types for other functionalities shall be considered a
+backwards-compatible change for this input device.
+
+Thinkpad-acpi Hot Key event map (version 0x4101):
+
+ACPI Scan
+event code Key Notes
+
+0x1001 0x00 FN+F1 -
+0x1002 0x01 FN+F2 IBM: battery (rare)
+ Lenovo: Screen lock
+
+0x1003 0x02 FN+F3 Many IBM models always report
+ this hot key, even with hot keys
+ disabled or with Fn+F3 masked
+ off
+ IBM: screen lock
+ Lenovo: battery
+
+0x1004 0x03 FN+F4 Sleep button (ACPI sleep button
+ semanthics, i.e. sleep-to-RAM).
+ It is always generate some kind
+ of event, either the hot key
+ event or a ACPI sleep button
+ event. The firmware may
+ refuse to generate further FN+F4
+ key presses until a S3 or S4 ACPI
+ sleep cycle is performed or some
+ time passes.
+
+0x1005 0x04 FN+F5 Radio. Enables/disables
+ the internal BlueTooth hardware
+ and W-WAN card if left in control
+ of the firmware. Does not affect
+ the WLAN card.
+ Should be used to turn on/off all
+ radios (bluetooth+W-WAN+WLAN),
+ really.
+
+0x1006 0x05 FN+F6 -
+
+0x1007 0x06 FN+F7 Video output cycle.
+ Do you feel lucky today?
+
+0x1008 0x07 FN+F8 IBM: toggle screen expand
+ Lenovo: configure ultranav
+
+0x1009 0x08 FN+F9 -
+ .. .. ..
+0x100B 0x0A FN+F11 -
+
+0x100C 0x0B FN+F12 Sleep to disk. You are always
+ supposed to handle it yourself,
+ either through the ACPI event,
+ or through a hotkey event.
+ The firmware may refuse to
+ generate further FN+F4 key
+ press events until a S3 or S4
+ ACPI sleep cycle is performed,
+ or some time passes.
+
+0x100D 0x0C FN+BACKSPACE -
+0x100E 0x0D FN+INSERT -
+0x100F 0x0E FN+DELETE -
+
+0x1010 0x0F FN+HOME Brightness up. This key is
+ always handled by the firmware
+ in IBM ThinkPads, even when
+ unmasked. Just leave it alone.
+ For Lenovo ThinkPads with a new
+ BIOS, it has to be handled either
+ by the ACPI OSI, or by userspace.
+0x1011 0x10 FN+END Brightness down. See brightness
+ up for details.
+
+0x1012 0x11 FN+PGUP Thinklight toggle. This key is
+ always handled by the firmware,
+ even when unmasked.
+
+0x1013 0x12 FN+PGDOWN -
+
+0x1014 0x13 FN+SPACE Zoom key
+
+0x1015 0x14 VOLUME UP Internal mixer volume up. This
+ key is always handled by the
+ firmware, even when unmasked.
+ NOTE: Lenovo seems to be changing
+ this.
+0x1016 0x15 VOLUME DOWN Internal mixer volume up. This
+ key is always handled by the
+ firmware, even when unmasked.
+ NOTE: Lenovo seems to be changing
+ this.
+0x1017 0x16 MUTE Mute internal mixer. This
+ key is always handled by the
+ firmware, even when unmasked.
+
+0x1018 0x17 THINKPAD Thinkpad/Access IBM/Lenovo key
+
+0x1019 0x18 unknown
+.. .. ..
+0x1020 0x1F unknown
+
+The ThinkPad firmware does not allow one to differentiate when most hot
+keys are pressed or released (either that, or we don't know how to, yet).
+For these keys, the driver generates a set of events for a key press and
+immediately issues the same set of events for a key release. It is
+unknown by the driver if the ThinkPad firmware triggered these events on
+hot key press or release, but the firmware will do it for either one, not
+both.
+
+If a key is mapped to KEY_RESERVED, it generates no input events at all,
+and it may generate a legacy thinkpad-acpi ACPI hotkey event.
+
+If a key is mapped to KEY_UNKNOWN, it generates an input event that
+includes an scan code, and it may also generate a legacy thinkpad-acpi
+ACPI hotkey event.
+
+If a key is mapped to anything else, it will only generate legacy
+thinkpad-acpi ACPI hotkey events if nobody has opened the input device.
+
+Non hot-key ACPI HKEY event map:
+0x5001 Lid closed
+0x5002 Lid opened
+0x7000 Radio Switch may have changed state
Bluetooth
@@ -437,27 +624,34 @@ CMOS control
procfs: /proc/acpi/ibm/cmos
sysfs device attribute: cmos_command
-This feature is used internally by the ACPI firmware to control the
-ThinkLight on most newer ThinkPad models. It may also control LCD
-brightness, sounds volume and more, but only on some models.
+This feature is mostly used internally by the ACPI firmware to keep the legacy
+CMOS NVRAM bits in sync with the current machine state, and to record this
+state so that the ThinkPad will retain such settings across reboots.
+
+Some of these commands actually perform actions in some ThinkPad models, but
+this is expected to disappear more and more in newer models. As an example, in
+a T43 and in a X40, commands 12 and 13 still control the ThinkLight state for
+real, but commands 0 to 2 don't control the mixer anymore (they have been
+phased out) and just update the NVRAM.
The range of valid cmos command numbers is 0 to 21, but not all have an
effect and the behavior varies from model to model. Here is the behavior
on the X40 (tpb is the ThinkPad Buttons utility):
- 0 - no effect but tpb reports "Volume down"
- 1 - no effect but tpb reports "Volume up"
- 2 - no effect but tpb reports "Mute on"
- 3 - simulate pressing the "Access IBM" button
- 4 - LCD brightness up
- 5 - LCD brightness down
- 11 - toggle screen expansion
- 12 - ThinkLight on
- 13 - ThinkLight off
- 14 - no effect but tpb reports ThinkLight status change
+ 0 - Related to "Volume down" key press
+ 1 - Related to "Volume up" key press
+ 2 - Related to "Mute on" key press
+ 3 - Related to "Access IBM" key press
+ 4 - Related to "LCD brightness up" key pess
+ 5 - Related to "LCD brightness down" key press
+ 11 - Related to "toggle screen expansion" key press/function
+ 12 - Related to "ThinkLight on"
+ 13 - Related to "ThinkLight off"
+ 14 - Related to "ThinkLight" key press (toggle thinklight)
The cmos command interface is prone to firmware split-brain problems, as
-in newer ThinkPads it is just a compatibility layer.
+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
---------------------------------
@@ -516,23 +710,15 @@ Temperature sensors
procfs: /proc/acpi/ibm/thermal
sysfs device attributes: (hwmon) temp*_input
-Most ThinkPads include six or more separate temperature sensors but
-only expose the CPU temperature through the standard ACPI methods.
-This feature shows readings from up to eight different sensors on older
-ThinkPads, and it has experimental support for up to sixteen different
-sensors on newer ThinkPads.
-
-EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
-implementation directly accesses hardware registers and may not work as
-expected. USE WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module. When EXPERIMENTAL
-mode is enabled, reading the first 8 sensors on newer ThinkPads will
-also use an new experimental thermal sensor access mode.
+Most ThinkPads include six or more separate temperature sensors but only
+expose the CPU temperature through the standard ACPI methods. This
+feature shows readings from up to eight different sensors on older
+ThinkPads, and up to sixteen different sensors on newer ThinkPads.
For example, on the X40, a typical output may be:
temperatures: 42 42 45 41 36 -128 33 -128
-EXPERIMENTAL: On the T43/p, a typical output may be:
+On the T43/p, a typical output may be:
temperatures: 48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
The mapping of thermal sensors to physical locations varies depending on
@@ -562,7 +748,8 @@ http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
2: System board, left side (near PCMCIA slot), reported as HDAPS temp
3: PCMCIA slot
9: MCH (northbridge) to DRAM Bus
-10: ICH (southbridge), under Mini-PCI card, under touchpad
+10: Clock-generator, mini-pci card and ICH (southbridge), under Mini-PCI
+ card, under touchpad
11: Power regulator, underside of system board, below F2 key
The A31 has a very atypical layout for the thermal sensors
@@ -681,6 +868,12 @@ cannot be controlled.
The backlight control has eight levels, ranging from 0 to 7. Some of the
levels may not be distinct.
+There are two interfaces to the firmware for brightness control, EC and CMOS.
+To select which one should be used, use the brightness_mode module parameter:
+brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
+brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect
+which interface to use.
+
Procfs notes:
The available commands are:
@@ -976,3 +1169,9 @@ Sysfs interface changelog:
0x000100: Initial sysfs support, as a single platform driver and
device.
+0x000200: Hot key support for 32 hot keys, and radio slider switch
+ support.
+0x010000: Hot keys are now handled by default over the input
+ layer, the radio switch generates input event EV_RADIO,
+ and the driver enables hot key handling by default in
+ the firmware.
diff --git a/Documentation/time_interpolators.txt b/Documentation/time_interpolators.txt
deleted file mode 100644
index e3b60854fbc2..000000000000
--- a/Documentation/time_interpolators.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-Time Interpolators
-------------------
-
-Time interpolators are a base of time calculation between timer ticks and
-allow an accurate determination of time down to the accuracy of the time
-source in nanoseconds.
-
-The architecture specific code typically provides gettimeofday and
-settimeofday under Linux. The time interpolator provides both if an arch
-defines CONFIG_TIME_INTERPOLATION. The arch still must set up timer tick
-operations and call the necessary functions to advance the clock.
-
-With the time interpolator a standardized interface exists for time
-interpolation between ticks. The provided logic is highly scalable
-and has been tested in SMP situations of up to 512 CPUs.
-
-If CONFIG_TIME_INTERPOLATION is defined then the architecture specific code
-(or the device drivers - like HPET) may register time interpolators.
-These are typically defined in the following way:
-
-static struct time_interpolator my_interpolator {
- .frequency = MY_FREQUENCY,
- .source = TIME_SOURCE_MMIO32,
- .shift = 8, /* scaling for higher accuracy */
- .drift = -1, /* Unknown drift */
- .jitter = 0 /* time source is stable */
-};
-
-void time_init(void)
-{
- ....
- /* Initialization of the timer *.
- my_interpolator.address = &my_timer;
- register_time_interpolator(&my_interpolator);
- ....
-}
-
-For more details see include/linux/timex.h and kernel/timer.c.
-
-Christoph Lameter <christoph@lameter.com>, October 31, 2004
-
diff --git a/Documentation/usb/dma.txt b/Documentation/usb/dma.txt
index 62844aeba69c..e8b50b7de9d9 100644
--- a/Documentation/usb/dma.txt
+++ b/Documentation/usb/dma.txt
@@ -32,12 +32,15 @@ ELIMINATING COPIES
It's good to avoid making CPUs copy data needlessly. The costs can add up,
and effects like cache-trashing can impose subtle penalties.
-- When you're allocating a buffer for DMA purposes anyway, use the buffer
- primitives. Think of them as kmalloc and kfree that give you the right
- kind of addresses to store in urb->transfer_buffer and urb->transfer_dma,
- while guaranteeing that no hidden copies through DMA "bounce" buffers will
- slow things down. You'd also set URB_NO_TRANSFER_DMA_MAP in
- urb->transfer_flags:
+- If you're doing lots of small data transfers from the same buffer all
+ the time, that can really burn up resources on systems which use an
+ IOMMU to manage the DMA mappings. It can cost MUCH more to set up and
+ tear down the IOMMU mappings with each request than perform the I/O!
+
+ For those specific cases, USB has primitives to allocate less expensive
+ memory. They work like kmalloc and kfree versions that give you the right
+ kind of addresses to store in urb->transfer_buffer and urb->transfer_dma.
+ You'd also set URB_NO_TRANSFER_DMA_MAP in urb->transfer_flags:
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
int mem_flags, dma_addr_t *dma);
@@ -45,6 +48,10 @@ and effects like cache-trashing can impose subtle penalties.
void usb_buffer_free (struct usb_device *dev, size_t size,
void *addr, dma_addr_t dma);
+ Most drivers should *NOT* be using these primitives; they don't need
+ to use this type of memory ("dma-coherent"), and memory returned from
+ kmalloc() will work just fine.
+
For control transfers you can use the buffer primitives or not for each
of the transfer buffer and setup buffer independently. Set the flag bits
URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which
@@ -54,29 +61,39 @@ and effects like cache-trashing can impose subtle penalties.
The memory buffer returned is "dma-coherent"; sometimes you might need to
force a consistent memory access ordering by using memory barriers. It's
not using a streaming DMA mapping, so it's good for small transfers on
- systems where the I/O would otherwise tie up an IOMMU mapping. (See
+ systems where the I/O would otherwise thrash an IOMMU mapping. (See
Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming"
DMA mappings.)
Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
space-efficient.
+ On most systems the memory returned will be uncached, because the
+ semantics of dma-coherent memory require either bypassing CPU caches
+ or using cache hardware with bus-snooping support. While x86 hardware
+ has such bus-snooping, many other systems use software to flush cache
+ lines to prevent DMA conflicts.
+
- Devices on some EHCI controllers could handle DMA to/from high memory.
- Driver probe() routines can notice this using a generic DMA call, then
- tell higher level code (network, scsi, etc) about it like this:
- if (dma_supported (&intf->dev, 0xffffffffffffffffULL))
- net->features |= NETIF_F_HIGHDMA;
+ Unfortunately, the current Linux DMA infrastructure doesn't have a sane
+ way to expose these capabilities ... and in any case, HIGHMEM is mostly a
+ design wart specific to x86_32. So your best bet is to ensure you never
+ pass a highmem buffer into a USB driver. That's easy; it's the default
+ behavior. Just don't override it; e.g. with NETIF_F_HIGHDMA.
- That can eliminate dma bounce buffering of requests that originate (or
- terminate) in high memory, in cases where the buffers aren't allocated
- with usb_buffer_alloc() but instead are dma-mapped.
+ This may force your callers to do some bounce buffering, copying from
+ high memory to "normal" DMA memory. If you can come up with a good way
+ to fix this issue (for x86_32 machines with over 1 GByte of memory),
+ feel free to submit patches.
WORKING WITH EXISTING BUFFERS
Existing buffers aren't usable for DMA without first being mapped into the
-DMA address space of the device.
+DMA address space of the device. However, most buffers passed to your
+driver can safely be used with such DMA mapping. (See the first section
+of DMA-mapping.txt, titled "What memory is DMA-able?")
- When you're using scatterlists, you can map everything at once. On some
systems, this kicks in an IOMMU and turns the scatterlists into single
@@ -114,3 +131,8 @@ DMA address space of the device.
The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP
so that usbcore won't map or unmap the buffer. The same goes for
urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests.
+
+Note that several of those interfaces are currently commented out, since
+they don't have current users. See the source code. Other than the dmasync
+calls (where the underlying DMA primitives have changed), most of them can
+easily be commented back in if you want to use them.
diff --git a/Documentation/usb/persist.txt b/Documentation/usb/persist.txt
new file mode 100644
index 000000000000..df54d645cbb5
--- /dev/null
+++ b/Documentation/usb/persist.txt
@@ -0,0 +1,156 @@
+ USB device persistence during system suspend
+
+ Alan Stern <stern@rowland.harvard.edu>
+
+ September 2, 2006 (Updated May 29, 2007)
+
+
+ What is the problem?
+
+According to the USB specification, when a USB bus is suspended the
+bus must continue to supply suspend current (around 1-5 mA). This
+is so that devices can maintain their internal state and hubs can
+detect connect-change events (devices being plugged in or unplugged).
+The technical term is "power session".
+
+If a USB device's power session is interrupted then the system is
+required to behave as though the device has been unplugged. It's a
+conservative approach; in the absence of suspend current the computer
+has no way to know what has actually happened. Perhaps the same
+device is still attached or perhaps it was removed and a different
+device plugged into the port. The system must assume the worst.
+
+By default, Linux behaves according to the spec. If a USB host
+controller loses power during a system suspend, then when the system
+wakes up all the devices attached to that controller are treated as
+though they had disconnected. This is always safe and it is the
+"officially correct" thing to do.
+
+For many sorts of devices this behavior doesn't matter in the least.
+If the kernel wants to believe that your USB keyboard was unplugged
+while the system was asleep and a new keyboard was plugged in when the
+system woke up, who cares? It'll still work the same when you type on
+it.
+
+Unfortunately problems _can_ arise, particularly with mass-storage
+devices. The effect is exactly the same as if the device really had
+been unplugged while the system was suspended. If you had a mounted
+filesystem on the device, you're out of luck -- everything in that
+filesystem is now inaccessible. This is especially annoying if your
+root filesystem was located on the device, since your system will
+instantly crash.
+
+Loss of power isn't the only mechanism to worry about. Anything that
+interrupts a power session will have the same effect. For example,
+even though suspend current may have been maintained while the system
+was asleep, on many systems during the initial stages of wakeup the
+firmware (i.e., the BIOS) resets the motherboard's USB host
+controllers. Result: all the power sessions are destroyed and again
+it's as though you had unplugged all the USB devices. Yes, it's
+entirely the BIOS's fault, but that doesn't do _you_ any good unless
+you can convince the BIOS supplier to fix the problem (lots of luck!).
+
+On many systems the USB host controllers will get reset after a
+suspend-to-RAM. On almost all systems, no suspend current is
+available during hibernation (also known as swsusp or suspend-to-disk).
+You can check the kernel log after resuming to see if either of these
+has happened; look for lines saying "root hub lost power or was reset".
+
+In practice, people are forced to unmount any filesystems on a USB
+device before suspending. If the root filesystem is on a USB device,
+the system can't be suspended at all. (All right, it _can_ be
+suspended -- but it will crash as soon as it wakes up, which isn't
+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.
+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
+to each of the USB devices below that controller for which the
+"persist" attribute is set. It doesn't try to resume the device; that
+can't work once the power session is gone. Instead it issues a USB
+port reset and then re-enumerates the device. (This is exactly the
+same thing that happens whenever a USB device is reset.) If the
+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.
+
+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.
+
+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):
+
+ 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.
+
+
+ Is this the best solution?
+
+Perhaps not. Arguably, keeping track of mounted filesystems and
+memory mappings across device disconnects should be handled by a
+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.
+
+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
+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!!
+
+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
+device is still plugged into the port as before. But the checks
+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.
+
+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
+USB card reader while the system is asleep, the kernel will have no
+way to know you did it. The kernel will assume that nothing has
+happened and will continue to use the partition tables, inodes, and
+memory mappings for the old card.
+
+If the kernel gets fooled in this way, it's almost certain to cause
+data corruption and to crash your system. You'll have no one to blame
+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.
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index b60639130a51..177159c5f4c4 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -66,7 +66,7 @@
65 -> Lifeview FlyVideo 2000S LR90
66 -> Terratec TValueRadio [153b:1135,153b:ff3b]
67 -> IODATA GV-BCTV4/PCI [10fc:4050]
- 68 -> 3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA) [121a:3000,10b4:2637]
+ 68 -> 3Dfx VoodooTV FM (Euro) [10b4:2637]
69 -> Active Imaging AIMMS
70 -> Prolink Pixelview PV-BT878P+ (Rev.4C,8E)
71 -> Lifeview FlyVideo 98EZ (capture only) LR51 [1851:1851]
@@ -145,3 +145,5 @@
144 -> MagicTV
145 -> SSAI Security Video Interface [4149:5353]
146 -> SSAI Ultrasound Video Interface [414a:5353]
+147 -> VoodooTV 200 (USA) [121a:3000]
+148 -> DViCO FusionHDTV 2 [dbc0:d200]
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 60f838beb9c8..82ac8250e978 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -55,3 +55,4 @@
54 -> Norwood Micro TV Tuner
55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980]
56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602]
+ 57 -> ADS Tech Instant Video PCI [1421:0390]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 712e8c8333cc..3f8aeab50a10 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -114,3 +114,4 @@
113 -> Elitegroup ECS TVP3XP FM1246 Tuner Card (PAL,FM) [1019:4cb6]
114 -> KWorld DVB-T 210 [17de:7250]
115 -> Sabrent PCMCIA TV-PCB05 [0919:2003]
+116 -> 10MOONS TM300 TV Card [1131:2304]
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index 44134f04b82a..a88c02d23805 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -40,7 +40,7 @@ tuner=38 - Philips PAL/SECAM multi (FM1216ME MK3)
tuner=39 - LG NTSC (newer TAPC series)
tuner=40 - HITACHI V7-J180AT
tuner=41 - Philips PAL_MK (FI1216 MK)
-tuner=42 - Philips 1236D ATSC/NTSC dual in
+tuner=42 - Philips FCV1236D ATSC/NTSC dual in
tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
tuner=45 - Microtune 4049 FM5
@@ -72,3 +72,4 @@ tuner=70 - Samsung TCPN 2121P30A
tuner=71 - Xceive xc3028
tuner=72 - Thomson FE6600
tuner=73 - Samsung TCPG 6121P30A
+tuner=75 - Philips TEA5761 FM Radio
diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt
index 279717c96f63..1ffad19ce891 100644
--- a/Documentation/video4linux/sn9c102.txt
+++ b/Documentation/video4linux/sn9c102.txt
@@ -436,7 +436,7 @@ HV7131D Hynix Semiconductor | Yes No No No
HV7131R Hynix Semiconductor | No Yes Yes Yes
MI-0343 Micron Technology | Yes No No No
MI-0360 Micron Technology | No Yes Yes Yes
-OV7630 OmniVision Technologies | Yes Yes No No
+OV7630 OmniVision Technologies | Yes Yes Yes Yes
OV7660 OmniVision Technologies | No No Yes Yes
PAS106B PixArt Imaging | Yes No No No
PAS202B PixArt Imaging | Yes Yes No No
@@ -583,6 +583,7 @@ order):
- Bertrik Sikken, who reverse-engineered and documented the Huffman compression
algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and
implemented the first decoder;
+- Ronny Standke for the donation of a webcam;
- Mizuno Takafumi for the donation of a webcam;
- an "anonymous" donator (who didn't want his name to be revealed) for the
donation of a webcam.
diff --git a/Documentation/video4linux/zr364xx.txt b/Documentation/video4linux/zr364xx.txt
index c76992d0ff4d..4d9a0c33f2fd 100644
--- a/Documentation/video4linux/zr364xx.txt
+++ b/Documentation/video4linux/zr364xx.txt
@@ -62,4 +62,4 @@ Vendor Product Distributor Model
0x0784 0x0040 Traveler Slimline X5
0x06d6 0x0034 Trust Powerc@m 750
0x0a17 0x0062 Pentax Optio 50L
-
+0x06d6 0x003b Trust Powerc@m 970Z
diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt
index 687104bfd09a..51ccc48aa763 100644
--- a/Documentation/vm/hugetlbpage.txt
+++ b/Documentation/vm/hugetlbpage.txt
@@ -77,8 +77,9 @@ If the user applications are going to request hugepages using mmap system
call, then it is required that system administrator mount a file system of
type hugetlbfs:
- mount none /mnt/huge -t hugetlbfs <uid=value> <gid=value> <mode=value>
- <size=value> <nr_inodes=value>
+ mount -t hugetlbfs \
+ -o uid=<value>,gid=<value>,mode=<value>,size=<value>,nr_inodes=<value> \
+ none /mnt/huge
This command mounts a (pseudo) filesystem of type hugetlbfs on the directory
/mnt/huge. Any files created on /mnt/huge uses hugepages. The uid and gid
@@ -88,11 +89,10 @@ mode of root of file system to value & 0777. This value is given in octal.
By default the value 0755 is picked. The size option sets the maximum value of
memory (huge pages) allowed for that filesystem (/mnt/huge). The size is
rounded down to HPAGE_SIZE. The option nr_inodes sets the maximum number of
-inodes that /mnt/huge can use. If the size or nr_inodes options are not
+inodes that /mnt/huge can use. If the size or nr_inodes option is not
provided on command line then no limits are set. For size and nr_inodes
options, you can use [G|g]/[M|m]/[K|k] to represent giga/mega/kilo. For
-example, size=2K has the same meaning as size=2048. An example is given at
-the end of this document.
+example, size=2K has the same meaning as size=2048.
read and write system calls are not supported on files that reside on hugetlb
file systems.
diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt
index 1523320abd87..d17f324db9f5 100644
--- a/Documentation/vm/slub.txt
+++ b/Documentation/vm/slub.txt
@@ -41,6 +41,8 @@ Possible debug options are
P Poisoning (object and padding)
U User tracking (free and alloc)
T Trace (please only use on single slabs)
+ - Switch all debugging off (useful if the kernel is
+ configured with CONFIG_SLUB_DEBUG_ON)
F.e. in order to boot just with sanity checks and red zoning one would specify:
@@ -125,13 +127,20 @@ SLUB Debug output
Here is a sample of slub debug output:
-*** SLUB kmalloc-8: Redzone Active@0xc90f6d20 slab 0xc528c530 offset=3360 flags=0x400000c3 inuse=61 freelist=0xc90f6d58
- Bytes b4 0xc90f6d10: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
- Object 0xc90f6d20: 31 30 31 39 2e 30 30 35 1019.005
- Redzone 0xc90f6d28: 00 cc cc cc .
-FreePointer 0xc90f6d2c -> 0xc90f6d58
-Last alloc: get_modalias+0x61/0xf5 jiffies_ago=53 cpu=1 pid=554
-Filler 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
+====================================================================
+BUG kmalloc-8: Redzone overwritten
+--------------------------------------------------------------------
+
+INFO: 0xc90f6d28-0xc90f6d2b. First byte 0x00 instead of 0xcc
+INFO: Slab 0xc528c530 flags=0x400000c3 inuse=61 fp=0xc90f6d58
+INFO: Object 0xc90f6d20 @offset=3360 fp=0xc90f6d58
+INFO: Allocated in get_modalias+0x61/0xf5 age=53 cpu=1 pid=554
+
+Bytes b4 0xc90f6d10: 00 00 00 00 00 00 00 00 5a 5a 5a 5a 5a 5a 5a 5a ........ZZZZZZZZ
+ Object 0xc90f6d20: 31 30 31 39 2e 30 30 35 1019.005
+ Redzone 0xc90f6d28: 00 cc cc cc .
+ Padding 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
+
[<c010523d>] dump_trace+0x63/0x1eb
[<c01053df>] show_trace_log_lvl+0x1a/0x2f
[<c010601d>] show_trace+0x12/0x14
@@ -153,74 +162,108 @@ Filler 0xc90f6d50: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
[<c0104112>] sysenter_past_esp+0x5f/0x99
[<b7f7b410>] 0xb7f7b410
=======================
-@@@ SLUB kmalloc-8: Restoring redzone (0xcc) from 0xc90f6d28-0xc90f6d2b
+FIX kmalloc-8: Restoring Redzone 0xc90f6d28-0xc90f6d2b=0xcc
+If SLUB encounters a corrupted object (full detection requires the kernel
+to be booted with slub_debug) then the following output will be dumped
+into the syslog:
-If SLUB encounters a corrupted object then it will perform the following
-actions:
-
-1. Isolation and report of the issue
+1. Description of the problem encountered
This will be a message in the system log starting with
-*** SLUB <slab cache affected>: <What went wrong>@<object address>
-offset=<offset of object into slab> flags=<slabflags>
-inuse=<objects in use in this slab> freelist=<first free object in slab>
+===============================================
+BUG <slab cache affected>: <What went wrong>
+-----------------------------------------------
-2. Report on how the problem was dealt with in order to ensure the continued
-operation of the system.
+INFO: <corruption start>-<corruption_end> <more info>
+INFO: Slab <address> <slab information>
+INFO: Object <address> <object information>
+INFO: Allocated in <kernel function> age=<jiffies since alloc> cpu=<allocated by
+ cpu> pid=<pid of the process>
+INFO: Freed in <kernel function> age=<jiffies since free> cpu=<freed by cpu>
+ pid=<pid of the process>
-These are messages in the system log beginning with
-
-@@@ SLUB <slab cache affected>: <corrective action taken>
+(Object allocation / free information is only available if SLAB_STORE_USER is
+set for the slab. slub_debug sets that option)
+2. The object contents if an object was involved.
-In the above sample SLUB found that the Redzone of an active object has
-been overwritten. Here a string of 8 characters was written into a slab that
-has the length of 8 characters. However, a 8 character string needs a
-terminating 0. That zero has overwritten the first byte of the Redzone field.
-After reporting the details of the issue encountered the @@@ SLUB message
-tell us that SLUB has restored the redzone to its proper value and then
-system operations continue.
-
-Various types of lines can follow the @@@ SLUB line:
+Various types of lines can follow the BUG SLUB line:
Bytes b4 <address> : <bytes>
- Show a few bytes before the object where the problem was detected.
+ Shows a few bytes before the object where the problem was detected.
Can be useful if the corruption does not stop with the start of the
object.
Object <address> : <bytes>
The bytes of the object. If the object is inactive then the bytes
- typically contain poisoning values. Any non-poison value shows a
+ typically contain poison values. Any non-poison value shows a
corruption by a write after free.
Redzone <address> : <bytes>
- The redzone following the object. The redzone is used to detect
+ The Redzone following the object. The Redzone is used to detect
writes after the object. All bytes should always have the same
value. If there is any deviation then it is due to a write after
the object boundary.
-Freepointer
- The pointer to the next free object in the slab. May become
- corrupted if overwriting continues after the red zone.
-
-Last alloc:
-Last free:
- Shows the address from which the object was allocated/freed last.
- We note the pid, the time and the CPU that did so. This is usually
- the most useful information to figure out where things went wrong.
- Here get_modalias() did an kmalloc(8) instead of a kmalloc(9).
+ (Redzone information is only available if SLAB_RED_ZONE is set.
+ slub_debug sets that option)
-Filler <address> : <bytes>
+Padding <address> : <bytes>
Unused data to fill up the space in order to get the next object
properly aligned. In the debug case we make sure that there are
- at least 4 bytes of filler. This allow for the detection of writes
+ at least 4 bytes of padding. This allows the detection of writes
before the object.
-Following the filler will be a stackdump. That stackdump describes the
-location where the error was detected. The cause of the corruption is more
-likely to be found by looking at the information about the last alloc / free.
+3. A stackdump
+
+The stackdump describes the location where the error was detected. The cause
+of the corruption is may be more likely found by looking at the function that
+allocated or freed the object.
+
+4. Report on how the problem was dealt with in order to ensure the continued
+operation of the system.
+
+These are messages in the system log beginning with
+
+FIX <slab cache affected>: <corrective action taken>
+
+In the above sample SLUB found that the Redzone of an active object has
+been overwritten. Here a string of 8 characters was written into a slab that
+has the length of 8 characters. However, a 8 character string needs a
+terminating 0. That zero has overwritten the first byte of the Redzone field.
+After reporting the details of the issue encountered the FIX SLUB message
+tell us that SLUB has restored the Redzone to its proper value and then
+system operations continue.
+
+Emergency operations:
+---------------------
+
+Minimal debugging (sanity checks alone) can be enabled by booting with
+
+ slub_debug=F
+
+This will be generally be enough to enable the resiliency features of slub
+which will keep the system running even if a bad kernel component will
+keep corrupting objects. This may be important for production systems.
+Performance will be impacted by the sanity checks and there will be a
+continual stream of error messages to the syslog but no additional memory
+will be used (unlike full debugging).
+
+No guarantees. The kernel component still needs to be fixed. Performance
+may be optimized further by locating the slab that experiences corruption
+and enabling debugging only for that cache
+
+I.e.
+
+ slub_debug=F,dentry
+
+If the corruption occurs by writing after the end of the object then it
+may be advisable to enable a Redzone to avoid corrupting the beginning
+of other objects.
+
+ slub_debug=FZ,dentry
-Christoph Lameter, <clameter@sgi.com>, May 23, 2007
+Christoph Lameter, <clameter@sgi.com>, May 30, 2007
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index 6177d881983f..945311840a10 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -14,9 +14,11 @@ Machine check
mce=nobootlog
Disable boot machine check logging.
mce=tolerancelevel (number)
- 0: always panic, 1: panic if deadlock possible,
- 2: try to avoid panic, 3: never panic or exit (for testing)
- default is 1
+ 0: always panic on uncorrected errors, log corrected errors
+ 1: panic or SIGBUS on uncorrected errors, log corrected errors
+ 2: SIGBUS or log uncorrected errors, log corrected errors
+ 3: never panic or SIGBUS, log all errors (for testing only)
+ Default is 1
Can be also set using sysfs which is preferable.
nomce (for compatibility with i386): same as mce=off
@@ -134,12 +136,6 @@ Non Executable Mappings
SMP
- nosmp Only use a single CPU
-
- maxcpus=NUMBER only use upto NUMBER CPUs
-
- cpumask=MASK only use cpus with bits set in mask
-
additional_cpus=NUM Allow NUM more CPUs for hotplug
(defaults are specified by the BIOS, see Documentation/x86_64/cpu-hotplug-spec)
diff --git a/Documentation/x86_64/machinecheck b/Documentation/x86_64/machinecheck
index feaeaf6f6e4d..a05e58e7b159 100644
--- a/Documentation/x86_64/machinecheck
+++ b/Documentation/x86_64/machinecheck
@@ -49,12 +49,14 @@ tolerant
Since machine check exceptions can happen any time it is sometimes
risky for the kernel to kill a process because it defies
normal kernel locking rules. The tolerance level configures
- how hard the kernel tries to recover even at some risk of deadlock.
-
- 0: always panic,
- 1: panic if deadlock possible,
- 2: try to avoid panic,
- 3: never panic or exit (for testing only)
+ how hard the kernel tries to recover even at some risk of
+ deadlock. Higher tolerant values trade potentially better uptime
+ with the risk of a crash or even corruption (for tolerant >= 3).
+
+ 0: always panic on uncorrected errors, log corrected errors
+ 1: panic or SIGBUS on uncorrected errors, log corrected errors
+ 2: SIGBUS or log uncorrected errors, log corrected errors
+ 3: never panic or SIGBUS, log all errors (for testing only)
Default: 1
diff --git a/Documentation/zh_CN/HOWTO b/Documentation/zh_CN/HOWTO
new file mode 100644
index 000000000000..48fc67bfbe3d
--- /dev/null
+++ b/Documentation/zh_CN/HOWTO
@@ -0,0 +1,536 @@
+Chinese translated version of Documentation/HOWTO
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer, if this translation is outdated
+or there is problem with translation.
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
+Chinese maintainer: Li Yang <leoli@freescale.com>
+---------------------------------------------------------------------
+Documentation/HOWTO 的中文翻译
+
+如果想评论或更新本文的内容,请直接è”系原文档的维护者。如果你使用英文
+交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘中文版维护者求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻
+译存在问题,请è”系中文版维护者。
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
+中文版维护者: æŽé˜³ Li Yang <leoli@freescale.com>
+中文版翻译者: æŽé˜³ Li Yang <leoli@freescale.com>
+中文版校译者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
+ é™ˆç¦ Maggie Chen <chenqi@beyondsoft.com>
+ çŽ‹èª Wang Cong <xiyou.wangcong@gmail.com>
+
+以下为正文
+---------------------------------------------------------------------
+
+如何å‚与Linux内核开å‘
+---------------------
+
+这是一篇将如何å‚与Linux内核开å‘的相关问题一网打尽的终æžç§˜ç¬ˆã€‚它将指导你
+æˆä¸ºä¸€åLinux内核开å‘者,并且学会如何åŒLinux内核开å‘社区åˆä½œã€‚它尽å¯èƒ½ä¸
+包括任何关于内核编程的技术细节,但会给你指引一æ¡èŽ·å¾—这些知识的正确途径。
+
+如果这篇文章中的任何内容ä¸å†é€‚用,请给文末列出的文件维护者å‘é€è¡¥ä¸ã€‚
+
+
+入门
+----
+
+你想了解如何æˆä¸ºä¸€åLinux内核开å‘者?或者è€æ¿å©å’你“给这个设备写个Linux
+驱动程åºâ€ï¼Ÿè¿™ç¯‡æ–‡ç« çš„目的就是教会你达æˆè¿™äº›ç›®æ ‡çš„全部诀çªï¼Œå®ƒå°†æ述你需
+è¦ç»è¿‡çš„æµç¨‹ä»¥åŠç»™å‡ºå¦‚何åŒå†…核社区åˆä½œçš„一些æ示。它还将试图解释内核社区
+为何这样è¿ä½œã€‚
+
+Linux内核大部分是由C语言写æˆçš„,一些体系结构相关的代ç ç”¨åˆ°äº†æ±‡ç¼–语言。è¦
+å‚与内核开å‘,你必须精通C语言。除éžä½ æƒ³ä¸ºæŸä¸ªæž¶æž„å¼€å‘底层代ç ï¼Œå¦åˆ™ä½ å¹¶
+ä¸éœ€è¦äº†è§£ï¼ˆä»»ä½•ä½“系结构的)汇编语言。下é¢åˆ—举的书ç±è™½ç„¶ä¸èƒ½æ›¿ä»£æ‰Žå®žçš„C
+语言教育和多年的开å‘ç»éªŒï¼Œä½†å¦‚果需è¦çš„è¯ï¼Œåšä¸ºå‚考还是ä¸é”™çš„:
+ - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
+ 《C程åºè®¾è®¡è¯­è¨€ï¼ˆç¬¬2版·新版)》(å¾å®æ–‡ æŽå¿— 译)[机械工业出版社]
+ - "Practical C Programming" by Steve Oualline [O'Reilly]
+ 《实用C语言编程(第三版)》(郭大海 译)[中国电力出版社]
+ - "C: A Reference Manual" by Harbison and Steele [Prentice Hall]
+ 《C语言å‚考手册(原书第5版)》(邱仲潘 等译)[机械工业出版社]
+
+Linux内核使用GNU Cå’ŒGNU工具链开å‘。虽然它éµå¾ªISO C89标准,但也用到了一些
+标准中没有定义的扩展。内核是自给自足的C环境,ä¸ä¾èµ–于标准C库的支æŒï¼Œæ‰€ä»¥
+并ä¸æ”¯æŒC标准中的部分定义。比如long long类型的大数除法和浮点è¿ç®—å°±ä¸å…许
+使用。有时候确实很难弄清楚内核对工具链的è¦æ±‚和它所使用的扩展,ä¸å¹¸çš„是目
+å‰è¿˜æ²¡æœ‰æ˜Žç¡®çš„å‚考资料å¯ä»¥è§£é‡Šå®ƒä»¬ã€‚请查阅gccä¿¡æ¯é¡µï¼ˆä½¿ç”¨â€œinfo gccâ€å‘½ä»¤
+显示)获得一些这方é¢ä¿¡æ¯ã€‚
+
+请记ä½ä½ æ˜¯åœ¨å­¦ä¹ æ€Žä¹ˆå’Œå·²ç»å­˜åœ¨çš„å¼€å‘社区打交é“。它由一群形形色色的人组æˆï¼Œ
+他们对代ç ã€é£Žæ ¼å’Œè¿‡ç¨‹æœ‰ç€å¾ˆé«˜çš„标准。这些标准是在长期实践中总结出æ¥çš„,
+适应于地ç†ä¸Šåˆ†æ•£çš„大型开å‘团队。它们已ç»è¢«å¾ˆå¥½å¾—æ•´ç†æˆæ¡£ï¼Œå»ºè®®ä½ åœ¨å¼€å‘
+之å‰å°½å¯èƒ½å¤šçš„学习这些标准,而ä¸è¦æœŸæœ›åˆ«äººæ¥é€‚应你或者你公å¸çš„行为方å¼ã€‚
+
+
+法律问题
+--------
+
+Linux内核æºä»£ç éƒ½æ˜¯åœ¨GPL(通用公共许å¯è¯ï¼‰çš„ä¿æŠ¤ä¸‹å‘布的。è¦äº†è§£è¿™ç§è®¸å¯
+的细节请查看æºä»£ç ä¸»ç›®å½•ä¸‹çš„COPYING文件。如果你对它还有更深入问题请è”ç³»
+律师,而ä¸è¦åœ¨Linux内核邮件组上æ问。因为邮件组里的人并ä¸æ˜¯å¾‹å¸ˆï¼Œä¸è¦æœŸ
+望他们的è¯æœ‰æ³•å¾‹æ•ˆåŠ›ã€‚
+
+对于GPL的常è§é—®é¢˜å’Œè§£ç­”,请访问以下链接:
+ http://www.gnu.org/licenses/gpl-faq.html
+
+
+文档
+----
+
+Linux内核代ç ä¸­åŒ…å«æœ‰å¤§é‡çš„文档。这些文档对于学习如何与内核社区互动有ç€
+ä¸å¯ä¼°é‡çš„价值。当一个新的功能被加入内核,最好把解释如何使用这个功能的文
+档也放进内核。当内核的改动导致é¢å‘用户空间的接å£å‘生å˜åŒ–时,最好将相关信
+æ¯æˆ–手册页(manpages)çš„è¡¥ä¸å‘到mtk-manpages@gmx.net,以å‘手册页(manpages)
+的维护者解释这些å˜åŒ–。
+
+以下是内核代ç ä¸­éœ€è¦é˜…读的文档:
+ README
+ 文件简è¦ä»‹ç»äº†Linux内核的背景,并且æ述了如何é…置和编译内核。内核的
+ 新用户应该从这里开始。
+
+ Documentation/Changes
+ 文件给出了用æ¥ç¼–译和使用内核所需è¦çš„最å°è½¯ä»¶åŒ…列表。
+
+ Documentation/CodingStyle
+ æè¿°Linux内核的代ç é£Žæ ¼å’Œç†ç”±ã€‚所有新代ç éœ€è¦éµå®ˆè¿™ç¯‡æ–‡æ¡£ä¸­å®šä¹‰çš„规
+ 范。大多数维护者åªä¼šæŽ¥æ”¶ç¬¦åˆè§„定的补ä¸ï¼Œå¾ˆå¤šäººä¹Ÿåªä¼šå¸®å¿™æ£€æŸ¥ç¬¦åˆé£Žæ ¼
+ 的代ç ã€‚
+
+ Documentation/SubmittingPatches
+ Documentation/SubmittingDrivers
+ 这两份文档明确æ述如何创建和å‘é€è¡¥ä¸ï¼Œå…¶ä¸­åŒ…括(但ä¸ä»…é™äºŽ):
+ - 邮件内容
+ - 邮件格å¼
+ - 选择收件人
+ éµå®ˆè¿™äº›è§„定并ä¸èƒ½ä¿è¯æ交æˆåŠŸï¼ˆå› ä¸ºæ‰€æœ‰è¡¥ä¸éœ€è¦é€šè¿‡ä¸¥æ ¼çš„内容和风格
+ 审查),但是忽视他们几乎就æ„味ç€å¤±è´¥ã€‚
+
+ 其他关于如何正确地生æˆè¡¥ä¸çš„优秀文档包括:
+ "The Perfect Patch"
+ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ "Linux kernel patch submission format"
+ http://linux.yyz.us/patch-format.html
+
+ Documentation/stable_api_nonsense.txt
+ 论è¯å†…核为什么特æ„ä¸åŒ…括稳定的内核内部API,也就是说ä¸åŒ…括åƒè¿™æ ·çš„特
+ 性:
+ - å­ç³»ç»Ÿä¸­é—´å±‚(为了兼容性?)
+ - 在ä¸åŒæ“作系统间易于移æ¤çš„驱动程åº
+ - å‡ç¼“(甚至阻止)内核代ç çš„快速å˜åŒ–
+ 这篇文档对于ç†è§£Linuxçš„å¼€å‘哲学至关é‡è¦ã€‚对于将开å‘å¹³å°ä»Žå…¶ä»–æ“作系
+ 统转移到Linux的人æ¥è¯´ä¹Ÿå¾ˆé‡è¦ã€‚
+
+ Documentation/SecurityBugs
+ 如果你认为自己å‘现了Linux内核的安全性问题,请根æ®è¿™ç¯‡æ–‡æ¡£ä¸­çš„步骤æ¥
+ æ醒其他内核开å‘者并帮助解决这个问题。
+
+ Documentation/ManagementStyle
+ æ述内核维护者的工作方法åŠå…¶å…±æœ‰ç‰¹ç‚¹ã€‚这对于刚刚接触内核开å‘(或者对
+ 它感到好奇)的人æ¥è¯´å¾ˆé‡è¦ï¼Œå› ä¸ºå®ƒè§£é‡Šäº†å¾ˆå¤šå¯¹äºŽå†…核维护者独特行为的
+ æ™®é误解与迷惑。
+
+ Documentation/stable_kernel_rules.txt
+ 解释了稳定版内核å‘布的规则,以åŠå¦‚何将改动放入这些版本的步骤。
+
+ Documentation/kernel-docs.txt
+ 有助于内核开å‘的外部文档列表。如果你在内核自带的文档中没有找到你想找
+ 的内容,å¯ä»¥æŸ¥çœ‹è¿™äº›æ–‡æ¡£ã€‚
+
+ Documentation/applying-patches.txt
+ 关于补ä¸æ˜¯ä»€ä¹ˆä»¥åŠå¦‚何将它打在ä¸åŒå†…核开å‘分支上的好介ç»
+
+内核还拥有大é‡ä»Žä»£ç è‡ªåŠ¨ç”Ÿæˆçš„文档。它包å«å†…核内部APIçš„å…¨é¢ä»‹ç»ä»¥åŠå¦‚何
+妥善处ç†åŠ é”的规则。生æˆçš„文档会放在 Documentation/DocBook/目录下。在内
+æ ¸æºç çš„主目录中使用以下ä¸åŒå‘½ä»¤å°†ä¼šåˆ†åˆ«ç”ŸæˆPDFã€Postscriptã€HTML和手册
+页等ä¸åŒæ ¼å¼çš„文档:
+ make pdfdocs
+ make psdocs
+ make htmldocs
+ make mandocs
+
+
+如何æˆä¸ºå†…核开å‘者
+------------------
+如果你对Linux内核开å‘一无所知,你应该访问“Linux内核新手â€è®¡åˆ’:
+ http://kernelnewbies.org
+它拥有一个å¯ä»¥é—®å„ç§æœ€åŸºæœ¬çš„内核开å‘问题的邮件列表(在æ问之å‰ä¸€å®šè¦è®°å¾—
+查找已往的邮件,确认是å¦æœ‰äººå·²ç»å›žç­”过相åŒçš„问题)。它还拥有一个å¯ä»¥èŽ·å¾—
+实时å馈的IRCèŠå¤©é¢‘é“,以åŠå¤§é‡å¯¹äºŽå­¦ä¹ Linux内核开å‘相当有帮助的文档。
+
+网站简è¦ä»‹ç»äº†æºä»£ç ç»„织结构ã€å­ç³»ç»Ÿåˆ’分以åŠç›®å‰æ­£åœ¨è¿›è¡Œçš„项目(包括内核
+中的和å•ç‹¬ç»´æŠ¤çš„)。它还æ供了一些基本的帮助信æ¯ï¼Œæ¯”如如何编译内核和打补
+ä¸ã€‚
+
+如果你想加入内核开å‘社区并å助完æˆä¸€äº›ä»»åŠ¡ï¼Œå´æ‰¾ä¸åˆ°ä»Žå“ªé‡Œå¼€å§‹ï¼Œå¯ä»¥è®¿é—®
+“Linux内核房管员â€è®¡åˆ’:
+ http://janitor.kernelnewbies.org/
+这是æžä½³çš„起点。它æ供一个相对简å•çš„任务列表,列出内核代ç ä¸­éœ€è¦è¢«é‡æ–°
+æ•´ç†æˆ–者改正的地方。通过和负责这个计划的开å‘者们一åŒå·¥ä½œï¼Œä½ ä¼šå­¦åˆ°å°†è¡¥ä¸
+集æˆè¿›å†…核的基本原ç†ã€‚如果还没有决定下一步è¦åšä»€ä¹ˆçš„è¯ï¼Œä½ è¿˜å¯èƒ½ä¼šå¾—到方
+å‘性的指点。
+
+如果你已ç»æœ‰ä¸€äº›çŽ°æˆçš„代ç æƒ³è¦æ”¾åˆ°å†…核中,但是需è¦ä¸€äº›å¸®åŠ©æ¥ä½¿å®ƒä»¬æ‹¥æœ‰æ­£
+确的格å¼ã€‚请访问“内核导师â€è®¡åˆ’。这个计划就是用æ¥å¸®åŠ©ä½ å®Œæˆè¿™ä¸ªç›®æ ‡çš„。它
+是一个邮件列表,地å€å¦‚下:
+ http://selenic.com/mailman/listinfo/kernel-mentors
+
+在真正动手修改内核代ç ä¹‹å‰ï¼Œç†è§£è¦ä¿®æ”¹çš„代ç å¦‚何è¿ä½œæ˜¯å¿…需的。è¦è¾¾åˆ°è¿™ä¸ª
+目的,没什么办法比直接读代ç æ›´æœ‰æ•ˆäº†ï¼ˆå¤§å¤šæ•°èŠ±æ‹›éƒ½ä¼šæœ‰ç›¸åº”的注释),而且
+一些特制的工具还å¯ä»¥æ供帮助。例如,“Linux代ç äº¤å‰å¼•ç”¨â€é¡¹ç›®å°±æ˜¯ä¸€ä¸ªå€¼å¾—
+特别推è的帮助工具,它将æºä»£ç æ˜¾ç¤ºåœ¨æœ‰ç¼–目和索引的网页上。其中一个更新åŠ
+时的内核æºç åº“,å¯ä»¥é€šè¿‡ä»¥ä¸‹åœ°å€è®¿é—®ï¼š
+ http://sosdg.org/~coywolf/lxr/
+
+
+å¼€å‘æµç¨‹
+--------
+
+ç›®å‰Linux内核开å‘æµç¨‹åŒ…括几个“主内核分支â€å’Œå¾ˆå¤šå­ç³»ç»Ÿç›¸å…³çš„内核分支。这
+些分支包括:
+ - 2.6.x主内核æºç æ ‘
+ - 2.6.x.y -stable内核æºç æ ‘
+ - 2.6.x -git内核补ä¸é›†
+ - 2.6.x -mm内核补ä¸é›†
+ - å­ç³»ç»Ÿç›¸å…³çš„内核æºç æ ‘和补ä¸é›†
+
+
+2.6.x内核主æºç æ ‘
+-----------------
+2.6.x内核是由Linus Torvalds(Linux的创造者)亲自维护的。你å¯ä»¥åœ¨
+kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开å‘éµå¾ªä»¥ä¸‹æ­¥
+骤:
+ - æ¯å½“一个新版本的内核被å‘布,为期两周的集æˆçª—å£å°†è¢«æ‰“开。在这段时间里
+ 维护者å¯ä»¥å‘Linusæ交大段的修改,通常这些修改已ç»è¢«æ”¾åˆ°-mm内核中几个
+ 星期了。æ交大é‡ä¿®æ”¹çš„首选方å¼æ˜¯ä½¿ç”¨git工具(内核的代ç ç‰ˆæœ¬ç®¡ç†å·¥å…·
+ ,更多的信æ¯å¯ä»¥åœ¨http://git.or.cz/获å–),ä¸è¿‡ä½¿ç”¨æ™®é€šè¡¥ä¸ä¹Ÿæ˜¯å¯ä»¥
+ 的。
+ - 两个星期以åŽ-rc1版本内核å‘布。之åŽåªæœ‰ä¸åŒ…å«å¯èƒ½å½±å“整个内核稳定性的
+ 新功能的补ä¸æ‰å¯èƒ½è¢«æŽ¥å—。请注æ„一个全新的驱动程åºï¼ˆæˆ–者文件系统)有
+ å¯èƒ½åœ¨-rc1åŽè¢«æŽ¥å—是因为这样的修改完全独立,ä¸ä¼šå½±å“其他的代ç ï¼Œæ‰€ä»¥
+ 没有造æˆå†…核退步的风险。在-rc1以åŽä¹Ÿå¯ä»¥ç”¨gitå‘Linusæ交补ä¸ï¼Œä¸è¿‡æ‰€
+ 有的补ä¸éœ€è¦åŒæ—¶è¢«å‘é€åˆ°ç›¸åº”的公众邮件列表以å¾è¯¢æ„è§ã€‚
+ - 当Linus认为当å‰çš„gitæºç æ ‘å·²ç»è¾¾åˆ°ä¸€ä¸ªåˆç†å¥å…¨çš„状æ€è¶³ä»¥å‘布供人测试
+ 时,一个新的-rc版本就会被å‘布。计划是æ¯å‘¨éƒ½å‘布新的-rc版本。
+ - 这个过程一直æŒç»­ä¸‹åŽ»ç›´åˆ°å†…核被认为达到足够稳定的状æ€ï¼ŒæŒç»­æ—¶é—´å¤§æ¦‚是
+ 6个星期。
+
+关于内核å‘布,值得一æ的是Andrew Morton在linux-kernel邮件列表中如是说:
+ “没有人知é“新内核何时会被å‘布,因为å‘布是根æ®å·²çŸ¥bug的情况æ¥å†³å®š
+ 的,而ä¸æ˜¯æ ¹æ®ä¸€ä¸ªäº‹å…ˆåˆ¶å®šå¥½çš„时间表。â€
+
+
+2.6.x.y -stable(稳定版)内核æºç æ ‘
+-----------------------------------
+ç”±4个数字组æˆçš„内核版本å·è¯´æ˜Žæ­¤å†…核是-stable版本。它们包å«åŸºäºŽ2.6.x版本
+内核的相对较å°ä¸”至关é‡è¦çš„修补,这些修补针对安全性问题或者严é‡çš„内核退步。
+
+è¿™ç§ç‰ˆæœ¬çš„内核适用于那些期望获得最新的稳定版内核并且ä¸æƒ³å‚与测试开å‘版或
+者实验版的用户。
+
+如果没有2.6.x.y版本内核存在,那么最新的2.6.x版本内核就相当于是当å‰çš„稳定
+版内核。
+
+2.6.x.y版本由“稳定版â€å°ç»„(邮件地å€<stable@kernel.org>)维护,一般隔周å‘
+布新版本。
+
+内核æºç ä¸­çš„Documentation/stable_kernel_rules.txt文件具体æ述了å¯è¢«ç¨³å®š
+版内核接å—的修改类型以åŠå‘布的æµç¨‹ã€‚
+
+
+2.6.x -gitè¡¥ä¸é›†
+----------------
+Linus的内核æºç æ ‘çš„æ¯æ—¥å¿«ç…§ï¼Œè¿™ä¸ªæºç æ ‘是由git工具管ç†çš„(由此得å)。这
+些补ä¸é€šå¸¸æ¯å¤©æ›´æ–°ä»¥å映Linusçš„æºç æ ‘的最新状æ€ã€‚它们比-rc版本的内核æºç 
+树更具试验性质,因为这个补ä¸é›†æ˜¯å…¨è‡ªåŠ¨ç”Ÿæˆçš„,没有任何人æ¥ç¡®è®¤å…¶æ˜¯å¦çœŸæ­£
+å¥å…¨ã€‚
+
+
+2.6.x -mmè¡¥ä¸é›†
+---------------
+这是由Andrew Morton维护的试验性内核补ä¸é›†ã€‚Andrew将所有å­ç³»ç»Ÿçš„内核æºç 
+和补ä¸æ‹¼å‡‘到一起,并且加入了大é‡ä»Žlinux-kernel邮件列表中采集的补ä¸ã€‚这个
+æºç æ ‘是新功能和补ä¸çš„试炼场。当补ä¸åœ¨-mmè¡¥ä¸é›†é‡Œè¯æ˜Žäº†å…¶ä»·å€¼ä»¥åŽAndrew
+或者相应å­ç³»ç»Ÿçš„维护者会将补ä¸å‘ç»™Linus以便集æˆè¿›ä¸»å†…æ ¸æºç æ ‘。
+
+在将所有新补ä¸å‘ç»™Linus以集æˆåˆ°ä¸»å†…æ ¸æºç æ ‘之å‰ï¼Œæˆ‘们éžå¸¸é¼“励先把这些补
+ä¸æ”¾åœ¨-mm版内核æºç æ ‘中进行测试。
+
+这些内核版本ä¸é€‚åˆåœ¨éœ€è¦ç¨³å®šè¿è¡Œçš„系统上è¿è¡Œï¼Œå› ä¸ºè¿è¡Œå®ƒä»¬æ¯”è¿è¡Œä»»ä½•å…¶ä»–
+内核分支都更具有风险。
+
+如果你想为内核开å‘进程æ供帮助,请å°è¯•å¹¶ä½¿ç”¨è¿™äº›å†…核版本,并在
+linux-kernel邮件列表中æä¾›å馈,告诉大家你é‡åˆ°äº†é—®é¢˜è¿˜æ˜¯ä¸€åˆ‡æ­£å¸¸ã€‚
+
+通常-mm版补ä¸é›†ä¸å…‰åŒ…括这些é¢å¤–的试验性补ä¸ï¼Œè¿˜åŒ…括å‘布时-git版主æºç æ ‘
+中的改动。
+
+-mm版内核没有固定的å‘布周期,但是通常在æ¯ä¸¤ä¸ª-rc版内核å‘布之间都会有若干
+个-mm版内核å‘布(一般是1至3个)。
+
+
+å­ç³»ç»Ÿç›¸å…³å†…æ ¸æºç æ ‘和补ä¸é›†
+----------------------------
+相当一部分内核å­ç³»ç»Ÿå¼€å‘者会公开他们自己的开å‘æºç æ ‘,以便其他人能了解内
+核的ä¸åŒé¢†åŸŸæ­£åœ¨å‘生的事情。如上所述,这些æºç æ ‘会被集æˆåˆ°-mm版本内核中。
+
+下é¢æ˜¯ç›®å‰å¯ç”¨çš„一些内核æºç æ ‘的列表:
+ 通过git管ç†çš„æºç æ ‘:
+ - Kbuildå¼€å‘æºç æ ‘, Sam Ravnborg <sam@ravnborg.org>
+ git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
+
+ - ACPIå¼€å‘æºç æ ‘, Len Brown <len.brown@intel.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
+
+ - å—设备开å‘æºç æ ‘, Jens Axboe <axboe@suse.de>
+ git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
+
+ - DRMå¼€å‘æºç æ ‘, Dave Airlie <airlied@linux.ie>
+ git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
+
+ - ia64å¼€å‘æºç æ ‘, Tony Luck <tony.luck@intel.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
+
+ - ieee1394å¼€å‘æºç æ ‘, Jody McIntyre <scjody@modernduck.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git
+
+ - infinibandå¼€å‘æºç æ ‘, Roland Dreier <rolandd@cisco.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
+
+ - libataå¼€å‘æºç æ ‘, Jeff Garzik <jgarzik@pobox.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
+
+ - 网络驱动程åºå¼€å‘æºç æ ‘, Jeff Garzik <jgarzik@pobox.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
+
+ - pcmciaå¼€å‘æºç æ ‘, Dominik Brodowski <linux@dominikbrodowski.net>
+ git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
+
+ - SCSIå¼€å‘æºç æ ‘, James Bottomley <James.Bottomley@SteelEye.com>
+ git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
+
+ 使用quilt管ç†çš„è¡¥ä¸é›†ï¼š
+ - USB, PCI, 驱动程åºæ ¸å¿ƒå’ŒI2C, Greg Kroah-Hartman <gregkh@suse.de>
+ kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+ - x86-64, 部分i386, Andi Kleen <ak@suse.de>
+ ftp.firstfloor.org:/pub/ak/x86_64/quilt/
+
+ 其他内核æºç æ ‘å¯ä»¥åœ¨http://git.kernel.org的列表中和MAINTAINERS文件里
+ 找到。
+
+报告bug
+-------
+
+bugzilla.kernel.org是Linux内核开å‘者们用æ¥è·Ÿè¸ªå†…æ ¸Bug的网站。我们鼓励用
+户在这个工具中报告找到的所有bug。如何使用内核bugzilla的细节请访问:
+ http://test.kernel.org/bugzilla/faq.html
+
+内核æºç ä¸»ç›®å½•ä¸­çš„REPORTING-BUGS文件里有一个很好的模æ¿ã€‚它指导用户如何报
+å‘Šå¯èƒ½çš„内核bug以åŠéœ€è¦æ供哪些信æ¯æ¥å¸®åŠ©å†…核开å‘者们找到问题的根æºã€‚
+
+
+利用bug报告
+-----------
+
+练习内核开å‘技能的最好办法就是修改其他人报告的bug。你ä¸å…‰å¯ä»¥å¸®åŠ©å†…æ ¸å˜
+得更加稳定,还å¯ä»¥å­¦ä¼šå¦‚何解决实际问题从而æ高自己的技能,并且让其他开å‘
+者感å—到你的存在。修改bug是赢得其他开å‘者赞誉的最好办法,因为并ä¸æ˜¯å¾ˆå¤š
+人都喜欢浪费时间去修改别人报告的bug。
+
+è¦å°è¯•ä¿®æ”¹å·²çŸ¥çš„bug,请访问http://bugzilla.kernel.org网å€ã€‚如果你想获得
+最新bug的通知,å¯ä»¥è®¢é˜…bugme-new邮件列表(åªæœ‰æ–°çš„bug报告会被寄到这里)
+或者订阅bugme-janitor邮件列表(所有bugzillaçš„å˜åŠ¨éƒ½ä¼šè¢«å¯„到这里)。
+
+ http://lists.osdl.org/mailman/listinfo/bugme-new
+ http://lists.osdl.org/mailman/listinfo/bugme-janitors
+
+
+邮件列表
+--------
+
+正如上é¢çš„文档所æ述,大多数的骨干内核开å‘者都加入了Linux Kernel邮件列
+表。如何订阅和退订列表的细节å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ï¼š
+ http://vger.kernel.org/vger-lists.html#linux-kernel
+网上很多地方都有这个邮件列表的存档(archive)。å¯ä»¥ä½¿ç”¨æœç´¢å¼•æ“Žæ¥æ‰¾åˆ°è¿™äº›
+存档。比如:
+ http://dir.gmane.org/gmane.linux.kernel
+在å‘信之å‰ï¼Œæˆ‘们强烈建议你先在存档中æœç´¢ä½ æƒ³è¦è®¨è®ºçš„问题。很多已ç»è¢«è¯¦ç»†
+讨论过的问题åªåœ¨é‚®ä»¶åˆ—表的存档中å¯ä»¥æ‰¾åˆ°ã€‚
+
+大多数内核å­ç³»ç»Ÿä¹Ÿæœ‰è‡ªå·±ç‹¬ç«‹çš„邮件列表æ¥åè°ƒå„自的开å‘工作。从
+MAINTAINERS文件中å¯ä»¥æ‰¾åˆ°ä¸åŒè¯é¢˜å¯¹åº”的邮件列表。
+
+很多邮件列表架设在kernel.orgæœåŠ¡å™¨ä¸Šã€‚这些列表的信æ¯å¯ä»¥åœ¨è¿™é‡Œæ‰¾åˆ°ï¼š
+ http://vger.kernel.org/vger-lists.html
+
+在使用这些邮件列表时,请记ä½ä¿æŒè‰¯å¥½çš„行为习惯。下é¢çš„链接æ供了与这些列
+表(或任何其它邮件列表)交æµçš„一些简å•è§„则,虽然内容有点滥竽充数。
+ http://www.albion.com/netiquette/
+
+当有很多人回å¤ä½ çš„邮件时,邮件的抄é€åˆ—表会å˜å¾—很长。请ä¸è¦å°†ä»»ä½•äººä»ŽæŠ„é€
+列表中删除,除éžä½ æœ‰è¶³å¤Ÿçš„ç†ç”±è¿™ä¹ˆåšã€‚也ä¸è¦åªå›žå¤åˆ°é‚®ä»¶åˆ—表。请习惯于åŒ
+一å°é‚®ä»¶æŽ¥æ”¶ä¸¤æ¬¡ï¼ˆä¸€å°æ¥è‡ªå‘é€è€…一å°æ¥è‡ªé‚®ä»¶åˆ—表),而ä¸è¦è¯•å›¾é€šè¿‡æ·»åŠ ä¸€
+些奇特的邮件头æ¥è§£å†³è¿™ä¸ªé—®é¢˜ï¼Œäººä»¬ä¸ä¼šå–œæ¬¢çš„。
+
+è®°ä½ä¿ç•™ä½ æ‰€å›žå¤å†…容的上下文和æºå¤´ã€‚在你回å¤é‚®ä»¶çš„顶部ä¿ç•™â€œæŸæŸæŸè¯´åˆ°â€¦â€¦â€
+这几行。将你的评论加在被引用的段è½ä¹‹é—´è€Œä¸è¦æ”¾åœ¨é‚®ä»¶çš„顶部。
+
+如果你在邮件中附带补ä¸ï¼Œè¯·ç¡®è®¤å®ƒä»¬æ˜¯å¯ä»¥ç›´æŽ¥é˜…读的纯文本(如
+Documentation/SubmittingPatches文档中所述)。内核开å‘者们ä¸å¸Œæœ›é‡åˆ°é™„件
+或者被压缩了的补ä¸ã€‚åªæœ‰è¿™æ ·æ‰èƒ½ä¿è¯ä»–们å¯ä»¥ç›´æŽ¥è¯„论你的æ¯è¡Œä»£ç ã€‚请确ä¿
+你使用的邮件å‘é€ç¨‹åºä¸ä¼šä¿®æ”¹ç©ºæ ¼å’Œåˆ¶è¡¨ç¬¦ã€‚一个防范性的测试方法是先将邮件
+å‘é€ç»™è‡ªå·±ï¼Œç„¶åŽè‡ªå·±å°è¯•æ˜¯å¦å¯ä»¥é¡ºåˆ©åœ°æ‰“上收到的补ä¸ã€‚如果测试ä¸æˆåŠŸï¼Œè¯·
+调整或者更æ¢ä½ çš„邮件å‘é€ç¨‹åºç›´åˆ°å®ƒæ­£ç¡®å·¥ä½œä¸ºæ­¢ã€‚
+
+总而言之,请尊é‡å…¶ä»–的邮件列表订阅者。
+
+
+åŒå†…核社区åˆä½œ
+----------------
+
+内核社区的目标就是æ供尽善尽美的内核。所以当你æ交补ä¸æœŸæœ›è¢«æŽ¥å—进内核的
+时候,它的技术价值以åŠå…¶ä»–æ–¹é¢éƒ½å°†è¢«è¯„审。那么你å¯èƒ½ä¼šå¾—到什么呢?
+ - 批评
+ - 评论
+ - è¦æ±‚修改
+ - è¦æ±‚è¯æ˜Žä¿®æ”¹çš„å¿…è¦æ€§
+ - 沉默
+
+è¦è®°ä½ï¼Œè¿™äº›æ˜¯æŠŠè¡¥ä¸æ”¾è¿›å†…核的正常情况。你必须学会å¬å–对补ä¸çš„批评和评论,
+从技术层é¢è¯„估它们,然åŽè¦ä¹ˆé‡å†™ä½ çš„è¡¥ä¸è¦ä¹ˆç®€æ˜Žæ‰¼è¦åœ°è®ºè¯ä¿®æ”¹æ˜¯ä¸å¿…è¦
+的。如果你å‘的邮件没有得到任何回应,请过几天åŽå†è¯•ä¸€æ¬¡ï¼Œå› ä¸ºæœ‰æ—¶ä¿¡ä»¶ä¼šæ¹®
+没在茫茫信海中。
+
+ä½ ä¸åº”该åšçš„事情:
+ - 期望自己的补ä¸ä¸å—任何质疑就直接被接å—
+ - 翻脸
+ - 忽略别人的评论
+ - 没有按照别人的è¦æ±‚åšä»»ä½•ä¿®æ”¹å°±é‡æ–°æ交
+
+在一个努力追寻最好技术方案的社区里,对于一个补ä¸æœ‰å¤šå°‘好处总会有ä¸åŒçš„è§
+解。你必须è¦æŠ±ç€åˆä½œçš„æ€åº¦ï¼Œæ„¿æ„改å˜è‡ªå·±çš„观点æ¥é€‚应内核的风格。或者至少
+æ„¿æ„去è¯æ˜Žä½ çš„想法是有价值的。记ä½ï¼ŒçŠ¯é”™è¯¯æ˜¯å…许的,åªè¦ä½ æ„¿æ„æœç€æ­£ç¡®çš„
+方案去努力。
+
+如果你的第一个补ä¸æ¢æ¥çš„是一堆修改建议,这是很正常的。这并ä¸ä»£è¡¨ä½ çš„è¡¥ä¸
+ä¸ä¼šè¢«æŽ¥å—,也ä¸æ„味ç€æœ‰äººå’Œä½ ä½œå¯¹ã€‚ä½ åªéœ€è¦æ”¹æ­£æ‰€æœ‰æ出的问题然åŽé‡æ–°å‘
+é€ä½ çš„è¡¥ä¸ã€‚
+
+内核社区和公å¸æ–‡åŒ–的差异
+------------------------
+
+内核社区的工作模å¼åŒå¤§å¤šæ•°ä¼ ç»Ÿå…¬å¸å¼€å‘队ä¼çš„工作模å¼å¹¶ä¸ç›¸åŒã€‚下é¢è¿™äº›ä¾‹
+å­ï¼Œå¯ä»¥å¸®åŠ©ä½ é¿å…æŸäº›å¯èƒ½å‘生问题:
+ 用这些è¯ä»‹ç»ä½ çš„修改æ案会有好处:
+ - 它åŒæ—¶è§£å†³äº†å¤šä¸ªé—®é¢˜
+ - 它删除了2000行代ç 
+ - 这是补ä¸ï¼Œå®ƒå·²ç»è§£é‡Šäº†æˆ‘想è¦è¯´æ˜Žçš„
+ - 我在5ç§ä¸åŒçš„体系结构上测试过它……
+ - 这是一系列å°è¡¥ä¸ç”¨æ¥â€¦â€¦
+ - 这个修改æ高了普通机器的性能……
+
+ 应该é¿å…如下的说法:
+ - 我们在AIX/ptx/Solaris就是这么åšçš„,所以这么åšè‚¯å®šæ˜¯å¥½çš„……
+ - 我åšè¿™è¡Œå·²ç»20年了,所以……
+ - 为了我们公å¸èµšé’±è€ƒè™‘必须这么åš
+ - 这是我们的ä¼ä¸šäº§å“线所需è¦çš„
+ - 这里是æ述我观点的1000页设计文档
+ - 这是一个5000行的补ä¸ç”¨æ¥â€¦â€¦
+ - 我é‡å†™äº†çŽ°åœ¨ä¹±ä¸ƒå…«ç³Ÿçš„代ç ï¼Œè¿™å°±æ˜¯â€¦â€¦
+ - 我被规定了最åŽæœŸé™ï¼Œæ‰€ä»¥è¿™ä¸ªè¡¥ä¸éœ€è¦ç«‹åˆ»è¢«æŽ¥å—
+
+å¦å¤–一个内核社区与大部分传统公å¸çš„软件开å‘队ä¼ä¸åŒçš„地方是无法é¢å¯¹é¢åœ°äº¤
+æµã€‚使用电å­é‚®ä»¶å’ŒIRCèŠå¤©å·¥å…·åšä¸ºä¸»è¦æ²Ÿé€šå·¥å…·çš„一个好处是性别和ç§æ—歧视
+将会更少。Linux内核的工作环境更能接å—妇女和少数æ—群,因为æ¯ä¸ªäººåœ¨åˆ«äººçœ¼
+里åªæ˜¯ä¸€ä¸ªé‚®ä»¶åœ°å€ã€‚国际化也帮助了公平的实现,因为你无法通过姓åæ¥åˆ¤æ–­äºº
+的性别。男人有å¯èƒ½å«æŽä¸½ï¼Œå¥³äººä¹Ÿæœ‰å¯èƒ½å«çŽ‹åˆšã€‚大多数在Linux内核上工作过
+并表达过看法的女性对在linux上工作的ç»åŽ†éƒ½ç»™å‡ºäº†æ­£é¢çš„评价。
+
+对于一些ä¸ä¹ æƒ¯ä½¿ç”¨è‹±è¯­çš„人æ¥è¯´ï¼Œè¯­è¨€å¯èƒ½æ˜¯ä¸€ä¸ªå¼•èµ·é—®é¢˜çš„éšœç¢ã€‚在邮件列表
+中è¦æ­£ç¡®åœ°è¡¨è¾¾æƒ³æ³•å¿…需良好地掌æ¡è¯­è¨€ï¼Œæ‰€ä»¥å»ºè®®ä½ åœ¨å‘é€é‚®ä»¶ä¹‹å‰æœ€å¥½æ£€æŸ¥ä¸€
+下英文写得是å¦æ­£ç¡®ã€‚
+
+
+拆分修改
+--------
+
+Linux内核社区并ä¸å–œæ¬¢ä¸€ä¸‹æŽ¥æ”¶å¤§æ®µçš„代ç ã€‚修改需è¦è¢«æ°å½“地介ç»ã€è®¨è®ºå¹¶ä¸”
+拆分æˆç‹¬ç«‹çš„å°æ®µã€‚这几乎完全和公å¸ä¸­çš„习惯背é“而驰。你的想法应该在开å‘最
+开始的阶段就让大家知é“,这样你就å¯ä»¥åŠæ—¶èŽ·å¾—对你正在进行的开å‘çš„å馈。这
+样也会让社区觉得你是在和他们å作,而ä¸æ˜¯ä»…仅把他们当作倾销新功能的对象。
+无论如何,你ä¸è¦ä¸€æ¬¡æ€§åœ°å‘邮件列表å‘é€50å°ä¿¡ï¼Œä½ çš„è¡¥ä¸åºåˆ—应该永远用ä¸åˆ°
+这么多。
+
+将补ä¸æ‹†å¼€çš„原因如下:
+
+1) å°çš„è¡¥ä¸æ›´æœ‰å¯èƒ½è¢«æŽ¥å—,因为它们ä¸éœ€è¦å¤ªå¤šçš„时间和精力去验è¯å…¶æ­£ç¡®æ€§ã€‚
+ 一个5行的补ä¸ï¼Œå¯èƒ½åœ¨ç»´æŠ¤è€…看了一眼以åŽå°±ä¼šè¢«æŽ¥å—。而500行的补ä¸åˆ™
+ 需è¦æ•°ä¸ªå°æ—¶æ¥å®¡æŸ¥å…¶æ­£ç¡®æ€§ï¼ˆæ‰€éœ€æ—¶é—´éšè¡¥ä¸å¤§å°å¢žåŠ å¤§çº¦å‘ˆæŒ‡æ•°çº§å¢žé•¿ï¼‰ã€‚
+
+ 当出了问题的时候,å°çš„è¡¥ä¸ä¹Ÿä¼šè®©è°ƒè¯•å˜å¾—éžå¸¸å®¹æ˜“。一个一个补ä¸åœ°å›žæº¯
+ 将会比仔细剖æžä¸€ä¸ªè¢«æ‰“上的大补ä¸ï¼ˆè¿™ä¸ªè¡¥ä¸ç ´å了其他东西)容易得多。
+
+2)ä¸å…‰å‘é€å°çš„è¡¥ä¸å¾ˆé‡è¦ï¼Œåœ¨æ交之å‰é‡æ–°ç¼–排ã€åŒ–简(或者仅仅é‡æ–°æŽ’列)
+ è¡¥ä¸ä¹Ÿæ˜¯å¾ˆé‡è¦çš„。
+
+这里有内核开å‘者Al Viro打的一个比方:
+ “想象一个è€å¸ˆæ­£åœ¨ç»™å­¦ç”Ÿæ‰¹æ”¹æ•°å­¦ä½œä¸šã€‚è€å¸ˆå¹¶ä¸å¸Œæœ›çœ‹åˆ°å­¦ç”Ÿä¸ºäº†å¾—
+ 到正确解法所进行的å°è¯•å’Œäº§ç”Ÿçš„错误。他希望看到的是最干净最优雅的
+ 解答。好学生了解这点,ç»ä¸ä¼šæŠŠæœ€ç»ˆè§£å†³ä¹‹å‰çš„中间方案æ交上去。â€
+
+ 内核开å‘也是这样。维护者和评审者ä¸å¸Œæœ›çœ‹åˆ°ä¸€ä¸ªäººåœ¨è§£å†³é—®é¢˜æ—¶çš„æ€
+ 考过程。他们åªå¸Œæœ›çœ‹åˆ°ç®€å•å’Œä¼˜é›…的解决方案。
+
+直接给出一æµçš„解决方案,和社区一起å作讨论尚未完æˆçš„工作,这两者之间似乎
+很难找到一个平衡点。所以最好尽早开始收集有利于你进行改进的å馈;åŒæ—¶ä¹Ÿè¦
+ä¿è¯ä¿®æ”¹åˆ†æˆå¾ˆå¤šå°å—,这样在整个项目都准备好被包å«è¿›å†…核之å‰ï¼Œå…¶ä¸­çš„一部
+分å¯èƒ½ä¼šå…ˆè¢«æŽ¥æ”¶ã€‚
+
+必须了解这样åšæ˜¯ä¸å¯æŽ¥å—的:试图将未完æˆçš„工作æ交进内核,然åŽå†æ‰¾æ—¶é—´ä¿®
+å¤ã€‚
+
+
+è¯æ˜Žä¿®æ”¹çš„å¿…è¦æ€§
+----------------
+除了将补ä¸æ‹†æˆå°å—,很é‡è¦çš„一点是让Linux社区了解他们为什么需è¦è¿™æ ·ä¿®æ”¹ã€‚
+ä½ å¿…é¡»è¯æ˜Žæ–°åŠŸèƒ½æ˜¯æœ‰äººéœ€è¦çš„并且是有用的。
+
+
+记录修改
+--------
+
+当你å‘é€è¡¥ä¸çš„时候,需è¦ç‰¹åˆ«ç•™æ„邮件正文的内容。因为这里的信æ¯å°†ä¼šåšä¸ºè¡¥
+ä¸çš„修改记录(ChangeLog),会被一直ä¿ç•™ä»¥å¤‡å¤§å®¶æŸ¥é˜…。它需è¦å®Œå…¨åœ°æè¿°è¡¥ä¸ï¼Œ
+包括:
+ - 为什么需è¦è¿™ä¸ªä¿®æ”¹
+ - è¡¥ä¸çš„总体设计
+ - 实现细节
+ - 测试结果
+
+想了解它具体应该看起æ¥åƒä»€ä¹ˆï¼Œè¯·æŸ¥é˜…以下文档中的“ChangeLogâ€ç« èŠ‚:
+ “The Perfect Patchâ€
+ http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+
+
+这些事情有时候åšèµ·æ¥å¾ˆéš¾ã€‚è¦åœ¨ä»»ä½•æ–¹é¢éƒ½åšåˆ°å®Œç¾Žå¯èƒ½éœ€è¦å¥½å‡ å¹´æ—¶é—´ã€‚这是
+一个æŒç»­æ高的过程,它需è¦å¤§é‡çš„è€å¿ƒå’Œå†³å¿ƒã€‚åªè¦ä¸æ”¾å¼ƒï¼Œä½ ä¸€å®šå¯ä»¥åšåˆ°ã€‚
+很多人已ç»åšåˆ°äº†ï¼Œè€Œä»–们都曾ç»å’ŒçŽ°åœ¨çš„你站在åŒæ ·çš„起点上。
+
+
+---------------
+æ„Ÿè°¢Paolo Ciarrocchiå…许“开å‘æµç¨‹â€éƒ¨åˆ†åŸºäºŽä»–所写的文章
+(http://linux.tar.bz/articles/2.6-development_process),感谢Randy
+Dunlapå’ŒGerrit Huizenga完善了应该说和ä¸è¯¥è¯´çš„列表。感谢Pat Mochel, Hanna
+Linder, Randy Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer,
+Kees Cook, Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian
+Bunk, Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael
+Kerriskå’ŒAlex Shepard的评审ã€å»ºè®®å’Œè´¡çŒ®ã€‚没有他们的帮助,这篇文档是ä¸å¯
+能完æˆçš„。
+
+
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Documentation/zh_CN/stable_api_nonsense.txt b/Documentation/zh_CN/stable_api_nonsense.txt
new file mode 100644
index 000000000000..c26a27d1ee7d
--- /dev/null
+++ b/Documentation/zh_CN/stable_api_nonsense.txt
@@ -0,0 +1,157 @@
+Chinese translated version of Documentation/stable_api_nonsense.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have problem
+communicating in English you can also ask the Chinese maintainer for help.
+Contact the Chinese maintainer, if this translation is outdated or there
+is problem with translation.
+
+Maintainer: Greg Kroah-Hartman <greg@kroah.com>
+Chinese maintainer: TripleX Chung <zhongyu@18mail.cn>
+---------------------------------------------------------------------
+Documentation/stable_api_nonsense.txt 的中文翻译
+
+如果想评论或更新本文的内容,请直接è”系原文档的维护者。如果你使用英文
+交æµæœ‰å›°éš¾çš„è¯ï¼Œä¹Ÿå¯ä»¥å‘中文版维护者求助。如果本翻译更新ä¸åŠæ—¶æˆ–者翻
+译存在问题,请è”系中文版维护者。
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
+中文版维护者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
+中文版翻译者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
+中文版校译者: æŽé˜³ Li Yang <leoli@freescale.com>
+以下为正文
+---------------------------------------------------------------------
+
+写作本文档的目的,是为了解释为什么Linux既没有二进制内核接å£ï¼Œä¹Ÿæ²¡æœ‰ç¨³å®š
+的内核接å£ã€‚这里所说的内核接å£ï¼Œæ˜¯æŒ‡å†…核里的接å£ï¼Œè€Œä¸æ˜¯å†…核和用户空间
+的接å£ã€‚内核到用户空间的接å£ï¼Œæ˜¯æ供给应用程åºä½¿ç”¨çš„系统调用,系统调用
+在历å²ä¸Šå‡ ä¹Žæ²¡æœ‰è¿‡å˜åŒ–,将æ¥ä¹Ÿä¸ä¼šæœ‰å˜åŒ–。我有一些è€åº”用程åºæ˜¯åœ¨0.9版本
+或者更早版本的内核上编译的,在使用2.6版本内核的Linuxå‘布上ä¾ç„¶ç”¨å¾—很好
+。用户和应用程åºä½œè€…å¯ä»¥å°†è¿™ä¸ªæŽ¥å£çœ‹æˆæ˜¯ç¨³å®šçš„。
+
+
+执行纲è¦
+--------
+
+你也许以为自己想è¦ç¨³å®šçš„内核接å£ï¼Œä½†æ˜¯ä½ ä¸æ¸…楚你è¦çš„实际上ä¸æ˜¯å®ƒã€‚你需
+è¦çš„其实是稳定的驱动程åºï¼Œè€Œä½ åªæœ‰å°†é©±åŠ¨ç¨‹åºæ”¾åˆ°å…¬ç‰ˆå†…核的æºä»£ç æ ‘里,
+æ‰æœ‰å¯èƒ½è¾¾åˆ°è¿™ä¸ªç›®çš„。而且这样åšè¿˜æœ‰å¾ˆå¤šå…¶å®ƒå¥½å¤„,正是因为这些好处使得
+Linux能æˆä¸ºå¼ºå£®ï¼Œç¨³å®šï¼Œæˆç†Ÿçš„æ“作系统,这也是你最开始选择Linux的原因。
+
+
+入门
+-----
+
+åªæœ‰é‚£äº›å†™é©±åŠ¨ç¨‹åºçš„“怪人â€æ‰ä¼šæ‹…心内核接å£çš„改å˜ï¼Œå¯¹å¹¿å¤§ç”¨æˆ·æ¥è¯´ï¼Œæ—¢
+看ä¸åˆ°å†…核接å£ï¼Œä¹Ÿä¸éœ€è¦åŽ»å…³å¿ƒå®ƒã€‚
+
+首先,我ä¸æ‰“算讨论关于任何éžGPL许å¯çš„内核驱动的法律问题,这些éžGPL许å¯
+的驱动程åºåŒ…括ä¸å…¬å¼€æºä»£ç ï¼Œéšè—æºä»£ç ï¼ŒäºŒè¿›åˆ¶æˆ–者是用æºä»£ç åŒ…装,或者
+是其它任何形å¼çš„ä¸èƒ½ä»¥GPL许å¯å…¬å¼€æºä»£ç çš„驱动程åºã€‚如果有法律问题,请咨
+询律师,我åªæ˜¯ä¸€ä¸ªç¨‹åºå‘˜ï¼Œæ‰€ä»¥æˆ‘åªæ‰“算探讨技术问题(ä¸æ˜¯å°çœ‹æ³•å¾‹é—®é¢˜ï¼Œ
+法律问题很实际,并且需è¦ä¸€ç›´å…³æ³¨ï¼‰ã€‚
+
+既然åªè°ˆæŠ€æœ¯é—®é¢˜ï¼Œæˆ‘们就有了下é¢ä¸¤ä¸ªä¸»é¢˜ï¼šäºŒè¿›åˆ¶å†…核接å£å’Œç¨³å®šçš„内核æº
+代ç æŽ¥å£ã€‚这两个问题是互相关è”的,让我们先解决掉二进制接å£çš„问题。
+
+
+二进制内核接å£
+--------------
+å‡å¦‚我们有一个稳定的内核æºä»£ç æŽ¥å£ï¼Œé‚£ä¹ˆè‡ªç„¶è€Œç„¶çš„,我们就拥有了稳定的
+二进制接å£ï¼Œæ˜¯è¿™æ ·çš„å—?错。让我们看看关于Linux内核的几点事实:
+ - å–决于所用的C编译器的版本,ä¸åŒçš„内核数æ®ç»“构里的结构体的对é½æ–¹
+å¼ä¼šæœ‰å·®åˆ«ï¼Œä»£ç ä¸­ä¸åŒå‡½æ•°çš„表现形å¼ä¹Ÿä¸ä¸€æ ·ï¼ˆå‡½æ•°æ˜¯ä¸æ˜¯è¢«inline编译å–
+决于编译器行为)。ä¸åŒçš„函数的表现形å¼å¹¶ä¸é‡è¦ï¼Œä½†æ˜¯æ•°æ®ç»“构内部的对é½
+æ–¹å¼å¾ˆå…³é”®ã€‚
+ - å–决于内核的é…置选项,ä¸åŒçš„选项会让内核的很多东西å‘生改å˜ï¼š
+ - åŒä¸€ä¸ªç»“构体å¯èƒ½åŒ…å«ä¸åŒçš„æˆå‘˜å˜é‡
+ - 有的函数å¯èƒ½æ ¹æœ¬ä¸ä¼šè¢«å®žçŽ°ï¼ˆæ¯”如编译的时候没有选择SMP支æŒ
+,一些é”函数就会被定义æˆç©ºå‡½æ•°ï¼‰ã€‚
+ - 内核使用的内存会以ä¸åŒçš„æ–¹å¼å¯¹é½ï¼Œè¿™å–决于ä¸åŒçš„内核é…置选
+项。
+ - Linuxå¯ä»¥åœ¨å¾ˆå¤šçš„ä¸åŒä½“系结构的处ç†å™¨ä¸Šè¿è¡Œã€‚在æŸä¸ªä½“系结构上编
+译好的二进制驱动程åºï¼Œä¸å¯èƒ½åœ¨å¦å¤–一个体系结构上正确的è¿è¡Œã€‚
+
+对于一个特定的内核,满足这些æ¡ä»¶å¹¶ä¸éš¾ï¼Œä½¿ç”¨åŒä¸€ä¸ªC编译器和åŒæ ·çš„内核é…
+置选项æ¥ç¼–译驱动程åºæ¨¡å—å°±å¯ä»¥äº†ã€‚这对于给一个特定Linuxå‘布的特定版本æ
+供驱动程åºï¼Œæ˜¯å®Œå…¨å¯ä»¥æ»¡è¶³éœ€æ±‚的。但是如果你è¦ç»™ä¸åŒå‘布的ä¸åŒç‰ˆæœ¬éƒ½å‘
+布一个驱动程åºï¼Œå°±éœ€è¦åœ¨æ¯ä¸ªå‘布上用ä¸åŒçš„内核设置å‚数都编译一次内核,
+这简直跟噩梦一样。而且还è¦æ³¨æ„到,æ¯ä¸ªLinuxå‘布还æä¾›ä¸åŒçš„Linux内核,
+这些内核都针对ä¸åŒçš„硬件类型进行了优化(有很多ç§ä¸åŒçš„处ç†å™¨ï¼Œè¿˜æœ‰ä¸åŒ
+的内核设置选项)。所以æ¯å‘布一次驱动程åºï¼Œéƒ½éœ€è¦æ供很多ä¸åŒç‰ˆæœ¬çš„内核
+模å—。
+
+相信我,如果你真的è¦é‡‡å–è¿™ç§å‘布方å¼ï¼Œä¸€å®šä¼šæ…¢æ…¢ç–¯æŽ‰ï¼Œæˆ‘很久以å‰å°±æœ‰è¿‡
+深刻的教训...
+
+
+稳定的内核æºä»£ç æŽ¥å£
+--------------------
+
+如果有人ä¸å°†ä»–的内核驱动程åºï¼Œæ”¾å…¥å…¬ç‰ˆå†…核的æºä»£ç æ ‘,而åˆæƒ³è®©é©±åŠ¨ç¨‹åº
+一直ä¿æŒåœ¨æœ€æ–°çš„内核中å¯ç”¨ï¼Œé‚£ä¹ˆè¿™ä¸ªè¯é¢˜å°†ä¼šå˜å¾—没完没了。
+ 内核开å‘是æŒç»­è€Œä¸”快节å¥çš„,从æ¥éƒ½ä¸ä¼šæ…¢ä¸‹æ¥ã€‚内核开å‘人员在当å‰æŽ¥å£ä¸­
+找到bug,或者找到更好的实现方å¼ã€‚一旦å‘现这些,他们就很快会去修改当å‰çš„
+接å£ã€‚修改接å£æ„味ç€ï¼Œå‡½æ•°åå¯èƒ½ä¼šæ”¹å˜ï¼Œç»“构体å¯èƒ½è¢«æ‰©å……或者删å‡ï¼Œå‡½æ•°
+çš„å‚数也å¯èƒ½å‘生改å˜ã€‚一旦接å£è¢«ä¿®æ”¹ï¼Œå†…核中使用这些接å£çš„地方需è¦åŒæ—¶
+修正,这样æ‰èƒ½ä¿è¯æ‰€æœ‰çš„东西继续工作。
+
+举一个例å­ï¼Œå†…核的USB驱动程åºæŽ¥å£åœ¨USBå­ç³»ç»Ÿçš„整个生命周期中,至少ç»åŽ†
+了三次é‡å†™ã€‚这些é‡å†™è§£å†³ä»¥ä¸‹é—®é¢˜ï¼š
+ - 把数æ®æµä»ŽåŒæ­¥æ¨¡å¼æ”¹æˆéžåŒæ­¥æ¨¡å¼ï¼Œè¿™ä¸ªæ”¹åŠ¨å‡å°‘了一些驱动程åºçš„
+å¤æ‚度,æ高了所有USB驱动程åºçš„åžå率,这样几乎所有的USB设备都能以最大
+速率工作了。
+ - 修改了USB核心代ç ä¸­ä¸ºUSB驱动分é…æ•°æ®åŒ…内存的方å¼ï¼Œæ‰€æœ‰çš„驱动都
+需è¦æ供更多的å‚æ•°ç»™USB核心,以修正了很多已ç»è¢«è®°å½•åœ¨æ¡ˆçš„æ­»é”。
+
+这和一些å°é—­æºä»£ç çš„æ“作系统形æˆé²œæ˜Žçš„对比,在那些æ“作系统上,ä¸å¾—ä¸é¢
+外的维护旧的USB接å£ã€‚这导致了一个å¯èƒ½æ€§ï¼Œæ–°çš„å¼€å‘者ä¾ç„¶ä¼šä¸å°å¿ƒä½¿ç”¨æ—§çš„
+接å£ï¼Œä»¥ä¸æ°å½“çš„æ–¹å¼ç¼–写代ç ï¼Œè¿›è€Œå½±å“到æ“作系统的稳定性。
+ 在上é¢çš„例å­ä¸­ï¼Œæ‰€æœ‰çš„å¼€å‘者都åŒæ„这些é‡è¦çš„改动,在这样的情况下修改代
+价很低。如果Linuxä¿æŒä¸€ä¸ªç¨³å®šçš„内核æºä»£ç æŽ¥å£ï¼Œé‚£ä¹ˆå°±å¾—创建一个新的接å£
+;旧的,有问题的接å£å¿…须一直维护,给Linux USBå¼€å‘者带æ¥é¢å¤–的工作。既然
+所有的Linux USB驱动的作者都是利用自己的时间工作,那么è¦æ±‚他们去åšæ¯«æ— æ„
+义的å…è´¹é¢å¤–工作,是ä¸å¯èƒ½çš„。
+ 安全问题对Linuxæ¥è¯´å分é‡è¦ã€‚一个安全问题被å‘现,就会在短时间内得到修
+正。在很多情况下,这将导致Linux内核中的一些接å£è¢«é‡å†™ï¼Œä»¥ä»Žæ ¹æœ¬ä¸Šé¿å…安
+全问题。一旦接å£è¢«é‡å†™ï¼Œæ‰€æœ‰ä½¿ç”¨è¿™äº›æŽ¥å£çš„驱动程åºï¼Œå¿…é¡»åŒæ—¶å¾—到修正,
+以确定安全问题已ç»å¾—到修å¤å¹¶ä¸”ä¸å¯èƒ½åœ¨æœªæ¥è¿˜æœ‰åŒæ ·çš„安全问题。如果内核
+内部接å£ä¸å…许改å˜ï¼Œé‚£ä¹ˆå°±ä¸å¯èƒ½ä¿®å¤è¿™æ ·çš„安全问题,也ä¸å¯èƒ½ç¡®è®¤è¿™æ ·çš„
+安全问题以åŽä¸ä¼šå‘生。
+å¼€å‘者一直在清ç†å†…核接å£ã€‚如果一个接å£æ²¡æœ‰äººåœ¨ä½¿ç”¨äº†ï¼Œå®ƒå°±ä¼šè¢«åˆ é™¤ã€‚è¿™
+æ ·å¯ä»¥ç¡®ä¿å†…核尽å¯èƒ½çš„å°ï¼Œè€Œä¸”所有潜在的接å£éƒ½ä¼šå¾—到尽å¯èƒ½å®Œæ•´çš„测试
+(没有人使用的接å£æ˜¯ä¸å¯èƒ½å¾—到良好的测试的)。
+
+
+è¦åšä»€ä¹ˆ
+-------
+
+如果你写了一个Linux内核驱动,但是它还ä¸åœ¨Linuxæºä»£ç æ ‘里,作为一个开å‘
+者,你应该怎么åšï¼Ÿä¸ºæ¯ä¸ªå‘布的æ¯ä¸ªç‰ˆæœ¬æ供一个二进制驱动,那简直是一个
+噩梦,è¦è·Ÿä¸Šæ°¸è¿œå¤„于å˜åŒ–之中的内核接å£ï¼Œä¹Ÿæ˜¯ä¸€ä»¶è¾›è‹¦æ´»ã€‚
+很简å•ï¼Œè®©ä½ çš„驱动进入内核æºä»£ç æ ‘(è¦è®°å¾—我们在谈论的是以GPL许å¯å‘è¡Œ
+的驱动,如果你的代ç ä¸ç¬¦åˆGPL,那么ç¥ä½ å¥½è¿ï¼Œä½ åªèƒ½è‡ªå·±è§£å†³è¿™ä¸ªé—®é¢˜äº†ï¼Œ
+你这个å¸è¡€é¬¼<把Andrewå’ŒLinus对å¸è¡€é¬¼çš„定义链接到这里>)。当你的代ç åŠ å…¥
+公版内核æºä»£ç æ ‘之åŽï¼Œå¦‚果一个内核接å£æ”¹å˜ï¼Œä½ çš„驱动会直接被修改接å£çš„
+那个人修改。ä¿è¯ä½ çš„驱动永远都å¯ä»¥ç¼–译通过,并且一直工作,你几乎ä¸éœ€è¦
+åšä»€ä¹ˆäº‹æƒ…。
+
+把驱动放到内核æºä»£ç æ ‘里会有很多的好处:
+ - 驱动的质é‡ä¼šæå‡ï¼Œè€Œç»´æŠ¤æˆæœ¬ï¼ˆå¯¹åŽŸå§‹ä½œè€…æ¥è¯´ï¼‰ä¼šä¸‹é™ã€‚
+ - 其他人会给驱动添加新特性。
+ - 其他人会找到驱动中的bug并修å¤ã€‚
+ - 其他人会在驱动中找到性能优化的机会。
+ - 当外部的接å£çš„改å˜éœ€è¦ä¿®æ”¹é©±åŠ¨ç¨‹åºçš„时候,其他人会修改驱动程åº
+。
+ - ä¸éœ€è¦è”系任何å‘行商,这个驱动会自动的éšç€æ‰€æœ‰çš„Linuxå‘布一起å‘
+布。
+
+和别的æ“作系统相比,Linux为更多ä¸åŒçš„设备æ供现æˆçš„驱动,而且能在更多ä¸
+åŒä½“系结构的处ç†å™¨ä¸Šæ”¯æŒè¿™äº›è®¾å¤‡ã€‚这个ç»è¿‡è€ƒéªŒçš„å¼€å‘模å¼ï¼Œå¿…然是错ä¸äº†
+çš„ :)
+
+-------------
+æ„Ÿè°¢ Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
+Robert Love, and Nishanth Aravamudan 对于本文档早期版本的评审和建议。
+
+英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
diff --git a/Kbuild b/Kbuild
index 163f8cb020a4..56b8edf6a3bc 100644
--- a/Kbuild
+++ b/Kbuild
@@ -13,6 +13,7 @@ offsets-file := include/asm-$(ARCH)/asm-offsets.h
always := $(offsets-file)
targets := $(offsets-file)
targets += arch/$(ARCH)/kernel/asm-offsets.s
+clean-files := $(addprefix $(objtree)/,$(targets))
# Default sed regexp - multiline due to syntax constraints
define sed-y
diff --git a/MAINTAINERS b/MAINTAINERS
index 151f4ef978a4..01f222e51871 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -194,13 +194,6 @@ M: jes@trained-monkey.org
L: linux-acenic@sunsite.dk
S: Maintained
-ACI MIXER DRIVER
-P: Robert Siemer
-M: Robert.Siemer@gmx.de
-L: linux-sound@vger.kernel.org
-W: http://www.stud.uni-karlsruhe.de/~uh1b/
-S: Maintained
-
IPS SCSI RAID DRIVER
P: Adaptec OEM Raid Solutions
M: aacraid@adaptec.com
@@ -232,15 +225,15 @@ T: git kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
S: Supported
ACPI BATTERY DRIVERS
-P: Vladimir P. Lebedev
-M: vladimir.p.lebedev@intel.com
+P: Alexey Starikovskiy
+M: astarikovskiy@suse.de
L: linux-acpi@vger.kernel.org
W: http://acpi.sourceforge.net/
S: Supported
ACPI EC DRIVER
P: Alexey Starikovskiy
-M: alexey.y.starikovskiy@linux.intel.com
+M: astarikovskiy@suse.de
L: linux-acpi@vger.kernel.org
W: http://acpi.sourceforge.net/
S: Supported
@@ -272,21 +265,6 @@ L: linux-acpi@vger.kernel.org
W: http://acpi.sourceforge.net/
S: Supported
-AD1816 SOUND DRIVER
-P: Thorsten Knabe
-M: Thorsten Knabe <linux@thorsten-knabe.de>
-W: http://linux.thorsten-knabe.de
-S: Maintained
-
-AD1889 SOUND DRIVER
-P: Kyle McMartin
-M: kyle@parisc-linux.org
-P: Thibaut Varene
-M: T-Bone@parisc-linux.org
-W: http://wiki.parisc-linux.org/AD1889
-L: parisc-linux@lists.parisc-linux.org
-S: Maintained
-
ADM1025 HARDWARE MONITOR DRIVER
P: Jean Delvare
M: khali@linux-fr.org
@@ -315,10 +293,9 @@ M: zippel@linux-m68k.org
S: Maintained
AGPGART DRIVER
-P: Dave Jones
-M: davej@codemonkey.org.uk
-W: http://www.codemonkey.org.uk/projects/agp/
-T: git kernel.org:/pub/scm/linux/kernel/git/davej/agpgart.git
+P: David Airlie
+M: airlied@linux.ie
+T: git kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
S: Maintained
AHA152X SCSI DRIVER
@@ -352,6 +329,12 @@ P: Ivan Kokshaysky
M: ink@jurassic.park.msu.ru
S: Maintained for 2.4; PCI support for 2.6.
+AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
+P: Thomas Dahlmann
+M: thomas.dahlmann@amd.com
+L: info-linux@geode.amd.com
+S: Supported
+
AMD GEODE PROCESSOR/CHIPSET SUPPORT
P: Jordan Crouse
M: info-linux@geode.amd.com
@@ -371,7 +354,7 @@ P: Tom Tucker
M: tom@opengridcomputing.com
P: Steve Wise
M: swise@opengridcomputing.com
-L: openib-general@openib.org
+L: general@lists.openfabrics.org
S: Maintained
AOA (Apple Onboard Audio) ALSA DRIVER
@@ -480,7 +463,7 @@ S: Maintained
ARM/HP JORNADA 7XX MACHINE SUPPORT
P: Kristoffer Ericson
-M: kristoffer_e1@hotmail.com
+M: kristoffer.ericson@gmail.com
W: www.jlime.com
S: Maintained
@@ -630,6 +613,12 @@ W: http://sourceforge.net/projects/acpi4asus
W: http://xf.iksaif.net/acpi4asus
S: Maintained
+ASUS ASB100 HARDWARE MONITOR DRIVER
+P: Mark M. Hoffman
+M: mhoffman@lightlink.com
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
ASUS LAPTOP EXTRAS DRIVER
P: Corentin Chary
M: corentincj@iksaif.net
@@ -662,7 +651,12 @@ W: http://linux-atm.sourceforge.net
S: Maintained
ATMEL AT91 MCI DRIVER
-S: Orphan
+P: Nicolas Ferre
+M: nicolas.ferre@rfo.atmel.com
+L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W: http://www.atmel.com/products/AT91/
+W: http://www.at91.com/
+S: Maintained
ATMEL MACB ETHERNET DRIVER
P: Haavard Skinnemoen
@@ -755,6 +749,13 @@ L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
W: http://blackfin.uclinux.org
S: Supported
+BLACKFIN EMAC DRIVER
+P: Bryan Wu
+M: bryan.wu@analog.com
+L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
+W: http://blackfin.uclinux.org
+S: Supported
+
BLACKFIN RTC DRIVER
P: Mike Frysinger
M: michael.frysinger@analog.com
@@ -936,6 +937,12 @@ M: mchan@broadcom.com
L: netdev@vger.kernel.org
S: Supported
+BSG (block layer generic sg v4 driver)
+P: FUJITA Tomonori
+M: fujita.tomonori@lab.ntt.co.jp
+L: linux-scsi@vger.kernel.org
+S: Supported
+
BTTV VIDEO4LINUX DRIVER
P: Mauro Carvalho Chehab
M: mchehab@infradead.org
@@ -1277,6 +1284,18 @@ M: tori@unhappy.mine.nu
L: netdev@vger.kernel.org
S: Maintained
+DMA GENERIC MEMCPY SUBSYSTEM
+P: Shannon Nelson
+M: shannon.nelson@intel.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
+DME1737 HARDWARE MONITOR DRIVER
+P: Juerg Haefliger
+M: juergh@gmail.com
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
DOCBOOK FOR DOCUMENTATION
P: Randy Dunlap
M: rdunlap@xenotime.net
@@ -1356,21 +1375,60 @@ S: Supported
EDAC-CORE
P: Doug Thompson
-M: norsk5@xmission.com
+M: dougthompson@xmission.com
L: bluesmoke-devel@lists.sourceforge.net
W: bluesmoke.sourceforge.net
S: Supported
EDAC-E752X
P: Mark Gross
+P: Doug Thompson
M: mark.gross@intel.com
+M: dougthompson@xmission.com
L: bluesmoke-devel@lists.sourceforge.net
W: bluesmoke.sourceforge.net
S: Maintained
EDAC-E7XXX
P: Doug Thompson
-M: norsk5@xmission.com
+M: dougthompson@xmission.com
+L: bluesmoke-devel@lists.sourceforge.net
+W: bluesmoke.sourceforge.net
+S: Maintained
+
+EDAC-I82443BXGX
+P: Tim Small
+M: tim@buttersideup.com
+L: bluesmoke-devel@lists.sourceforge.net
+W: bluesmoke.sourceforge.net
+S: Maintained
+
+EDAC-I3000
+P: Jason Uhlenkott
+M: juhlenko@akamai.com
+L: bluesmoke-devel@lists.sourceforge.net
+W: bluesmoke.sourceforge.net
+S: Maintained
+
+EDAC-I5000
+P: Doug Thompson
+M: dougthompson@xmission.com
+L: bluesmoke-devel@lists.sourceforge.net
+W: bluesmoke.sourceforge.net
+S: Maintained
+
+EDAC-I82975X
+P: Ranganathan Desikan
+P: Arvind R.
+M: rdesikan@jetzbroadband.com
+M: arvind@acarlab.com
+L: bluesmoke-devel@lists.sourceforge.net
+W: bluesmoke.sourceforge.net
+S: Maintained
+
+EDAC-PASEMI
+P: Egor Martovetsky
+M: egor@pasemi.com
L: bluesmoke-devel@lists.sourceforge.net
W: bluesmoke.sourceforge.net
S: Maintained
@@ -1396,16 +1454,9 @@ P: Hoang-Nam Nguyen
M: hnguyen@de.ibm.com
P: Christoph Raisch
M: raisch@de.ibm.com
-L: openib-general@openib.org
+L: general@lists.openfabrics.org
S: Supported
-EMU10K1 SOUND DRIVER
-P: James Courtier-Dutton
-M: James@superbug.demon.co.uk
-L: emu10k1-devel@lists.sourceforge.net
-W: http://sourceforge.net/projects/emu10k1/
-S: Maintained
-
EMULEX LPFC FC SCSI DRIVER
P: James Smart
M: james.smart@emulex.com
@@ -1595,11 +1646,11 @@ W: http://gigaset307x.sourceforge.net/
S: Maintained
HARDWARE MONITORING
-P: Jean Delvare
-M: khali@linux-fr.org
+P: Mark M. Hoffman
+M: mhoffman@lightlink.com
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/
-T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-hwmon/
+T: git lm-sensors.org:/kernel/mhoffman/hwmon-2.6.git
S: Maintained
HARDWARE RANDOM NUMBER GENERATOR CORE
@@ -1735,6 +1786,12 @@ P: William Irwin
M: wli@holomorphy.com
S: Maintained
+I2C/SMBUS STUB DRIVER
+P: Mark M. Hoffman
+M: mhoffman@lightlink.com
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
I2C SUBSYSTEM
P: Jean Delvare
M: khali@linux-fr.org
@@ -1750,14 +1807,15 @@ T: http://www.harbaum.org/till/i2c_tiny_usb
S: Maintained
i386 BOOT CODE
-P: Riley H. Williams
-M: Riley@Williams.Name
+P: H. Peter Anvin
+M: hpa@zytor.com
L: Linux-Kernel@vger.kernel.org
S: Maintained
i386 SETUP CODE / CPU ERRATA WORKAROUNDS
P: H. Peter Anvin
M: hpa@zytor.com
+T: git.kernel.org:/pub/scm/linux/kernel/git/hpa/linux-2.6-x86setup.git
S: Maintained
IA64 (Itanium) PLATFORM
@@ -1850,8 +1908,8 @@ M: rolandd@cisco.com
P: Sean Hefty
M: mshefty@ichips.intel.com
P: Hal Rosenstock
-M: halr@voltaire.com
-L: openib-general@openib.org
+M: hal.rosenstock@gmail.com
+L: general@lists.openfabrics.org
W: http://www.openib.org/
T: git kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
S: Supported
@@ -1901,6 +1959,12 @@ P: Tigran Aivazian
M: tigran@aivazian.fsnet.co.uk
S: Maintained
+INTEL I/OAT DMA DRIVER
+P: Shannon Nelson
+M: shannon.nelson@intel.com
+L: linux-kernel@vger.kernel.org
+S: Supported
+
INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT
P: Deepak Saxena
M: dsaxena@plexity.net
@@ -1989,9 +2053,10 @@ M: jjciarla@raiz.uncu.edu.ar
S: Maintained
IPATH DRIVER:
-P: Bryan O'Sullivan
-M: support@pathscale.com
-L: openib-general@openib.org
+P: Arthur Jones
+M: infinipath@qlogic.com
+L: general@lists.openfabrics.org
+T: git git://git.qlogic.com/ipath-linux-2.6
S: Supported
IPMI SUBSYSTEM
@@ -2297,6 +2362,14 @@ M: matthew@wil.cx
L: linux-scsi@vger.kernel.org
S: Maintained
+M32R ARCHITECTURE
+P: Hirokazu Takata
+M: takata@linux-m32r.org
+L: linux-m32r@ml.linux-m32r.org
+L: linux-m32r-ja@ml.linux-m32r.org (in Japanese)
+W: http://www.linux-m32r.org/
+S: Maintained
+
M68K ARCHITECTURE
P: Geert Uytterhoeven
M: geert@linux-m68k.org
@@ -2330,6 +2403,12 @@ W: http://linuxwireless.org/
T: git kernel.org:/pub/scm/linux/kernel/git/jbenc/mac80211.git
S: Maintained
+MACVLAN DRIVER
+P: Patrick McHardy
+M: kaber@trash.net
+L: netdev@vger.kernel.org
+S: Maintained
+
MARVELL YUKON / SYSKONNECT DRIVER
P: Mirko Lindner
M: mlindner@syskonnect.de
@@ -2390,7 +2469,7 @@ P: Artem Bityutskiy
M: dedekind@infradead.org
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
-T: git git://git.infradead.org/ubi-2.6.git
+T: git git://git.infradead.org/~dedekind/ubi-2.6.git
S: Maintained
MICROTEK X6 SCANNER
@@ -2616,12 +2695,6 @@ M: yokota@netlab.is.tsukuba.ac.jp
W: http://www.netlab.is.tsukuba.ac.jp/~yokota/izumi/ninja/
S: Maintained
-NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility)
-P: Eberhard Moenkeberg
-M: emoenke@gwdg.de
-L: linux-kernel@vger.kernel.org
-S: Maintained
-
NTFS FILESYSTEM
P: Anton Altaparmakov
M: aia21@cantab.net
@@ -2704,12 +2777,6 @@ L: osst-users@lists.sourceforge.net
L: linux-scsi@vger.kernel.org
S: Maintained
-OPL3-SA2, SA3, and SAx DRIVER
-P: Zwane Mwaikambo
-M: zwane@arm.linux.org.uk
-L: linux-sound@vger.kernel.org
-S: Maintained
-
OPROFILE
P: Philippe Elie
M: phil.el@wanadoo.fr
@@ -2814,11 +2881,6 @@ P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
S: Supported
-PCI HOTPLUG COMPAQ DRIVER
-P: Greg Kroah-Hartman
-M: greg@kroah.com
-S: Maintained
-
PCIE HOTPLUG DRIVER
P: Kristen Carlson Accardi
M: kristen.c.accardi@intel.com
@@ -2863,11 +2925,21 @@ L: linux-kernel@vger.kernel.org
S: Maintained
POSIX CLOCKS and TIMERS
-P: George Anzinger
-M: george@mvista.com
+P: Thomas Gleixner
+M: tglx@linutronix.de
L: linux-kernel@vger.kernel.org
S: Supported
+POWER SUPPLY CLASS/SUBSYSTEM and DRIVERS
+P: Anton Vorontsov
+M: cbou@mail.ru
+P: David Woodhouse
+M: dwmw2@infradead.org
+L: linux-kernel@vger.kernel.org
+L: kernel-discuss@handhelds.org
+T: git git.infradead.org/battery-2.6.git
+S: Maintained
+
POWERPC 4xx EMAC DRIVER
P: Eugene Surovegin
M: ebs@ebshome.net
@@ -2903,6 +2975,11 @@ P: Michal Ostrowski
M: mostrows@speakeasy.net
S: Maintained
+PPP OVER L2TP
+P: James Chapman
+M: jchapman@katalix.com
+S: Maintained
+
PREEMPTIBLE KERNEL
P: Robert Love
M: rml@tech9.net
@@ -3104,12 +3181,6 @@ M: michael@mihu.de
W: http://www.mihu.de/linux/saa7146
S: Maintained
-SBPCD CDROM DRIVER
-P: Eberhard Moenkeberg
-M: emoenke@gwdg.de
-L: linux-kernel@vger.kernel.org
-S: Maintained
-
SC1200 WDT DRIVER
P: Zwane Mwaikambo
M: zwane@arm.linux.org.uk
@@ -3250,6 +3321,12 @@ W: http://www.brownhat.org/sis900.html
L: netdev@vger.kernel.org
S: Maintained
+SIS 96X I2C/SMBUS DRIVER
+P: Mark M. Hoffman
+M: mhoffman@lightlink.com
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
SIS FRAMEBUFFER DRIVER
P: Thomas Winischhofer
M: thomas@winischhofer.net
@@ -3267,6 +3344,12 @@ P: Nicolas Pitre
M: nico@cam.org
S: Maintained
+SMSC47B397 HARDWARE MONITOR DRIVER
+P: Mark M. Hoffman
+M: mhoffman@lightlink.com
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
SOFTMAC LAYER (IEEE 802.11)
P: Johannes Berg
M: johannes@sipsolutions.net
@@ -3286,9 +3369,19 @@ M: neilb@suse.de
L: linux-raid@vger.kernel.org
S: Supported
-SOFTWARE SUSPEND:
+HIBERNATION (aka Software Suspend, aka swsusp):
+P: Pavel Machek
+M: pavel@suse.cz
+P: Rafael J. Wysocki
+M: rjw@sisk.pl
+L: linux-pm@lists.linux-foundation.org
+S: Supported
+
+SUSPEND TO RAM:
P: Pavel Machek
M: pavel@suse.cz
+P: Rafael J. Wysocki
+M: rjw@sisk.pl
L: linux-pm@lists.linux-foundation.org
S: Maintained
@@ -3724,12 +3817,12 @@ L: netdev@vger.kernel.org
W: http://pegasus2.sourceforge.net/
S: Maintained
-USB PRINTER DRIVER
-P: Vojtech Pavlik
-M: vojtech@suse.cz
+USB PRINTER DRIVER (usblp)
+P: Pete Zaitcev
+M: zaitcev@redhat.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
-S: Maintained
+S: Supported
USB RTL8150 DRIVER
P: Petko Manolov
@@ -4115,6 +4208,11 @@ W: http://www.polyware.nl/~middelin/En/hobbies.html
W: http://www.polyware.nl/~middelin/hobbies.html
S: Maintained
+ZS DECSTATION Z85C30 SERIAL DRIVER
+P: Maciej W. Rozycki
+M: macro@linux-mips.org
+S: Maintained
+
THE REST
P: Linus Torvalds
S: Buried alive in reporters
diff --git a/Makefile b/Makefile
index de4f8f7d396c..23f81c9f698e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
-SUBLEVEL = 22
-EXTRAVERSION =
+SUBLEVEL = 23
+EXTRAVERSION =-rc1
NAME = Holy Dancing Manatees, Batman!
# *DOCUMENTATION*
@@ -313,7 +313,8 @@ LINUXINCLUDE := -Iinclude \
CPPFLAGS := -D__KERNEL__ $(LINUXINCLUDE)
CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
- -fno-strict-aliasing -fno-common
+ -fno-strict-aliasing -fno-common \
+ -Werror-implicit-function-declaration
AFLAGS := -D__ASSEMBLY__
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
@@ -491,7 +492,7 @@ endif
include $(srctree)/arch/$(ARCH)/Makefile
ifdef CONFIG_FRAME_POINTER
-CFLAGS += -fno-omit-frame-pointer $(call cc-option,-fno-optimize-sibling-calls,)
+CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
else
CFLAGS += -fomit-frame-pointer
endif
@@ -513,6 +514,12 @@ CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
# disable pointer signed / unsigned warnings in gcc 4.0
CFLAGS += $(call cc-option,-Wno-pointer-sign,)
+# Use --build-id when available.
+LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\
+ $(call ld-option, -Wl$(comma)--build-id,))
+LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
+LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)
+
# Default kernel image to build when no specific target is given.
# KBUILD_IMAGE may be overruled on the command line or
# set in the environment
@@ -611,7 +618,7 @@ quiet_cmd_vmlinux__ ?= LD $@
cmd_vmlinux__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) -o $@ \
-T $(vmlinux-lds) $(vmlinux-init) \
--start-group $(vmlinux-main) --end-group \
- $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
+ $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o FORCE ,$^)
# Generate new vmlinux version
quiet_cmd_vmlinux_version = GEN .version
@@ -735,15 +742,31 @@ debug_kallsyms: .tmp_map$(last_kallsyms)
endif # ifdef CONFIG_KALLSYMS
+# Do modpost on a prelinked vmlinux. The finally linked vmlinux has
+# relevant sections renamed as per the linker script.
+quiet_cmd_vmlinux-modpost = LD $@
+ cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@ \
+ $(vmlinux-init) --start-group $(vmlinux-main) --end-group \
+ $(filter-out $(vmlinux-init) $(vmlinux-main) $(vmlinux-lds) FORCE ,$^)
+define rule_vmlinux-modpost
+ :
+ +$(call cmd,vmlinux-modpost)
+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
+ $(Q)echo 'cmd_$@ := $(cmd_vmlinux-modpost)' > $(dot-target).cmd
+endef
+
# vmlinux image - including updated kernel symbols
-vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
+vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) vmlinux.o FORCE
ifdef CONFIG_HEADERS_CHECK
$(Q)$(MAKE) -f $(srctree)/Makefile headers_check
endif
+ $(call vmlinux-modpost)
$(call if_changed_rule,vmlinux__)
- $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
+vmlinux.o: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
+ $(call if_changed_rule,vmlinux-modpost)
+
# The actual objects are generated when descending,
# make sure no implicit rule kicks in
$(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
@@ -1316,7 +1339,7 @@ define xtags
-I __initdata,__exitdata,__acquires,__releases \
-I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
--extra=+f --c-kinds=+px \
- --regex-asm='/ENTRY\(([^)]*)\).*/\1/'; \
+ --regex-asm='/^ENTRY\(([^)]*)\).*/\1/'; \
$(all-kconfigs) | xargs $1 -a \
--langdef=kconfig \
--language-force=kconfig \
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 79c6e5a24456..2a85dc33907c 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -327,6 +327,9 @@ config PCI_DOMAINS
bool
default y
+config PCI_SYSCALL
+ def_bool PCI
+
config ALPHA_CORE_AGP
bool
depends on ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL
diff --git a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c
index bd03dc94c72b..026ba9af6d6a 100644
--- a/arch/alpha/kernel/module.c
+++ b/arch/alpha/kernel/module.c
@@ -119,8 +119,7 @@ module_frob_arch_sections(Elf64_Ehdr *hdr, Elf64_Shdr *sechdrs,
}
nsyms = symtab->sh_size / sizeof(Elf64_Sym);
- chains = kmalloc(nsyms * sizeof(struct got_entry), GFP_KERNEL);
- memset(chains, 0, nsyms * sizeof(struct got_entry));
+ chains = kcalloc(nsyms, sizeof(struct got_entry), GFP_KERNEL);
got->sh_size = 0;
got->sh_addralign = 8;
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 28c84e55feb9..6b07f89a72c7 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -207,6 +207,10 @@ iommu_arena_free(struct pci_iommu_arena *arena, long ofs, long n)
p[i] = 0;
}
+/* True if the machine supports DAC addressing, and DEV can
+ make use of it given MASK. */
+static int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask);
+
/* Map a single buffer of the indicated size for PCI DMA in streaming
mode. The 32-bit PCI bus mastering address to use is returned.
Once the device is given the dma address, the device owns this memory
@@ -897,7 +901,7 @@ iommu_unbind(struct pci_iommu_arena *arena, long pg_start, long pg_count)
/* True if the machine supports DAC addressing, and DEV can
make use of it given MASK. */
-int
+static int
pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
{
dma64_addr_t dac_offset = alpha_mv.pci_dac_offset;
@@ -917,32 +921,6 @@ pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
return ok;
}
-EXPORT_SYMBOL(pci_dac_dma_supported);
-
-dma64_addr_t
-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page,
- unsigned long offset, int direction)
-{
- return (alpha_mv.pci_dac_offset
- + __pa(page_address(page))
- + (dma64_addr_t) offset);
-}
-EXPORT_SYMBOL(pci_dac_page_to_dma);
-
-struct page *
-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- unsigned long paddr = (dma_addr & PAGE_MASK) - alpha_mv.pci_dac_offset;
- return virt_to_page(__va(paddr));
-}
-EXPORT_SYMBOL(pci_dac_dma_to_page);
-
-unsigned long
-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return (dma_addr & ~PAGE_MASK);
-}
-EXPORT_SYMBOL(pci_dac_dma_to_offset);
/* Helper for generic DMA-mapping functions. */
diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
index 0cd060598f9a..83a781842266 100644
--- a/arch/alpha/kernel/ptrace.c
+++ b/arch/alpha/kernel/ptrace.c
@@ -315,9 +315,7 @@ do_sys_ptrace(long request, long pid, long addr, long data,
/* When I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- tmp = data;
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
- ret = (copied == sizeof(tmp)) ? 0 : -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the specified register */
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 80cfb758ee2b..b28731437c31 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -65,7 +65,7 @@ enum ipi_message_type {
};
/* Set to a secondary's cpuid when it comes online. */
-static int smp_secondary_alive __initdata = 0;
+static int smp_secondary_alive __devinitdata = 0;
/* Which cpus ids came online. */
cpumask_t cpu_online_map;
@@ -173,7 +173,7 @@ smp_callin(void)
}
/* Wait until hwrpb->txrdy is clear for cpu. Return -1 on timeout. */
-static int __init
+static int __devinit
wait_for_txrdy (unsigned long cpumask)
{
unsigned long timeout;
@@ -358,7 +358,7 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
/*
* Bring one cpu online.
*/
-static int __init
+static int __devinit
smp_boot_one_cpu(int cpuid)
{
struct task_struct *idle;
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 930cedc8be24..783f4e50c111 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -289,7 +289,7 @@ srm_console_device(struct console *co, int *index)
return srmcons_driver;
}
-static int __init
+static int
srm_console_setup(struct console *co, char *options)
{
return 0;
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index 0bcb968cb60a..922143ea1cdb 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -420,7 +420,7 @@ marvel_init_pci(void)
io7_clear_errors(io7);
}
-static void
+static void __init
marvel_init_rtc(void)
{
init_rtc_irq();
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index 4748e14a28bc..1dd50d07693c 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -144,7 +144,7 @@ irqreturn_t timer_interrupt(int irq, void *dev)
return IRQ_HANDLED;
}
-void
+void __init
common_init_rtc(void)
{
unsigned char x;
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index d6e665d567bd..ec0f05e0d8ff 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -184,6 +184,7 @@ die_if_kernel(char * str, struct pt_regs *regs, long err, unsigned long *r9_15)
#endif
printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
dik_show_regs(regs, r9_15);
+ add_taint(TAINT_DIE);
dik_show_trace((unsigned long *)(regs+1));
dik_show_code((unsigned int *)regs->pc);
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 449e76f118d3..fe13daa5cb2c 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -3,7 +3,7 @@
OUTPUT_FORMAT("elf64-alpha")
OUTPUT_ARCH(alpha)
ENTRY(__start)
-PHDRS { kernel PT_LOAD ; }
+PHDRS { kernel PT_LOAD; note PT_NOTE; }
jiffies = jiffies_64;
SECTIONS
{
@@ -28,6 +28,9 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
+ NOTES :kernel :note
+ .dummy : { *(.dummy) } :kernel
+
RODATA
/* Will be freed after init */
@@ -69,10 +72,7 @@ SECTIONS
. = ALIGN(8);
SECURITY_INIT
- . = ALIGN(8192);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(8192)
. = ALIGN(2*8192);
__init_end = .;
diff --git a/arch/alpha/lib/checksum.c b/arch/alpha/lib/checksum.c
index ab3761c437a8..8698e0746f9f 100644
--- a/arch/alpha/lib/checksum.c
+++ b/arch/alpha/lib/checksum.c
@@ -69,6 +69,7 @@ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
result = (result & 0xffffffff) + (result >> 32);
return (__force __wsum)result;
}
+EXPORT_SYMBOL(csum_tcpudp_nofold);
/*
* Do a 64-bit checksum on an arbitrary memory area..
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index f5862792a167..a0e18da594d9 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -148,21 +148,17 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
the fault. */
fault = handle_mm_fault(mm, vma, address, cause > 0);
up_read(&mm->mmap_sem);
-
- switch (fault) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
return;
/* Something tried to access memory that isn't in our memory map.
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 50d9f3e4e0f1..85016313bd11 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -241,6 +241,9 @@ config ARCH_H720X
config ARCH_IMX
bool "IMX"
+ select GENERIC_GPIO
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
help
Support for Motorola's i.MX family of processors (MX1, MXL).
@@ -308,6 +311,7 @@ config ARCH_L7200
config ARCH_KS8695
bool "Micrel/Kendin KS8695"
+ select GENERIC_GPIO
help
Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
System-on-Chip devices.
@@ -320,6 +324,12 @@ config ARCH_NS9XXX
<http://www.digi.com/products/microprocessors/index.jsp>
+config ARCH_MXC
+ bool "Freescale MXC/iMX-based"
+ select ARCH_MTD_XIP
+ help
+ Support for Freescale MXC/iMX-based family of processors
+
config ARCH_PNX4008
bool "Philips Nexperia PNX4008 Mobile"
help
@@ -384,6 +394,7 @@ config ARCH_DAVINCI
bool "TI DaVinci"
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
+ select GENERIC_GPIO
help
Support for TI's DaVinci platform.
@@ -427,6 +438,7 @@ source "arch/arm/mach-omap1/Kconfig"
source "arch/arm/mach-omap2/Kconfig"
source "arch/arm/plat-s3c24xx/Kconfig"
+source "arch/arm/plat-s3c/Kconfig"
if ARCH_S3C2410
source "arch/arm/mach-s3c2400/Kconfig"
@@ -451,6 +463,8 @@ source "arch/arm/mach-realview/Kconfig"
source "arch/arm/mach-at91/Kconfig"
+source "arch/arm/plat-mxc/Kconfig"
+
source "arch/arm/mach-netx/Kconfig"
source "arch/arm/mach-ns9xxx/Kconfig"
@@ -531,6 +545,9 @@ config PCI
information about which PCI hardware does work under Linux and which
doesn't.
+config PCI_SYSCALL
+ def_bool PCI
+
# Select the host bridge type
config PCI_HOST_VIA82C505
bool
@@ -1034,6 +1051,8 @@ source "drivers/mmc/Kconfig"
source "drivers/rtc/Kconfig"
+source "drivers/dma/Kconfig"
+
endmenu
source "fs/Kconfig"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 40c5eb1f55c7..18101f5f5f24 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -82,24 +82,24 @@ config DEBUG_CLPS711X_UART2
output to the second serial port on these devices. Saying N will
cause the debug messages to appear on the first serial port.
-config DEBUG_S3C2410_PORT
- depends on DEBUG_LL && ARCH_S3C2410
- bool "Kernel low-level debugging messages via S3C2410 UART"
+config DEBUG_S3C_PORT
+ depends on DEBUG_LL && PLAT_S3C
+ bool "Kernel low-level debugging messages via S3C UART"
help
Say Y here if you want debug print routines to go to one of the
- S3C2410 internal UARTs. The chosen UART must have been configured
+ S3C internal UARTs. The chosen UART must have been configured
before it is used.
-config DEBUG_S3C2410_UART
- depends on ARCH_S3C2410
- int "S3C2410 UART to use for low-level debug"
+config DEBUG_S3C_UART
+ depends on PLAT_S3C
+ int "S3C UART to use for low-level debug"
default "0"
help
- Choice for UART for kernel low-level using S3C2410 UARTS,
+ Choice for UART for kernel low-level using S3C UARTS,
should be between zero and two. The port must have been
initialised by the boot-loader before use.
The uncompressor code port configuration is now handled
- by CONFIG_S3C2410_LOWLEVEL_UART_PORT.
+ by CONFIG_S3C_LOWLEVEL_UART_PORT.
endmenu
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index cbd5010d3bc3..fa4ea9ff0797 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -137,6 +137,8 @@ endif
textofs-$(CONFIG_ARCH_NS9XXX) := 0x00108000
machine-$(CONFIG_ARCH_DAVINCI) := davinci
machine-$(CONFIG_ARCH_KS8695) := ks8695
+ incdir-$(CONFIG_ARCH_MXC) := mxc
+ machine-$(CONFIG_ARCH_MX3) := mx3
ifeq ($(CONFIG_ARCH_EBSA110),y)
# This is what happens if you forget the IOCS16 line.
@@ -183,6 +185,7 @@ core-$(CONFIG_VFP) += arch/arm/vfp/
core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/
core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
core-$(CONFIG_PLAT_S3C24XX) += arch/arm/plat-s3c24xx/
+core-$(CONFIG_ARCH_MXC) += arch/arm/plat-mxc/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index ec9c400c7f82..25f12303b106 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -91,4 +91,12 @@ zinstall: $(obj)/zImage
$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
$(obj)/zImage System.map "$(INSTALL_PATH)"
+zi:
+ $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+ $(obj)/zImage System.map "$(INSTALL_PATH)"
+
+i:
+ $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \
+ $(obj)/Image System.map "$(INSTALL_PATH)"
+
subdir- := bootp compressed
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index aefee20cbf98..b15f927a5926 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -1 +1,2 @@
piggy.gz
+font.c
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index adddc7131685..6b8cbd69f249 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -6,15 +6,13 @@
HEAD = head.o
OBJS = misc.o
-FONTC = drivers/video/console/font_acorn_8x8.c
-
-FONT = $(addprefix ../../../../drivers/video/console/, font_acorn_8x8.o)
+FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c
#
# Architecture dependencies
#
ifeq ($(CONFIG_ARCH_ACORN),y)
-OBJS += ll_char_wr.o $(FONT)
+OBJS += ll_char_wr.o font.o
endif
ifeq ($(CONFIG_ARCH_SHARK),y)
@@ -73,9 +71,9 @@ endif
SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/
-targets := vmlinux vmlinux.lds piggy.gz piggy.o $(FONT) \
+targets := vmlinux vmlinux.lds piggy.gz piggy.o font.o font.c \
head.o misc.o $(OBJS)
-EXTRA_CFLAGS := -fpic
+EXTRA_CFLAGS := -fpic -fno-builtin
EXTRA_AFLAGS :=
# Supply ZRELADDR, INITRD_PHYS and PARAMS_PHYS to the decompressor via
@@ -105,7 +103,10 @@ $(obj)/piggy.gz: $(obj)/../Image FORCE
$(obj)/piggy.o: $(obj)/piggy.gz FORCE
-CFLAGS_font_acorn_8x8.o := -Dstatic=
+CFLAGS_font.o := -Dstatic=
+
+$(obj)/font.c: $(FONTC)
+ $(call cmd,shipped)
$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile .config
@sed "$(SEDFLAGS)" < $< > $@
diff --git a/arch/arm/boot/compressed/head-xscale.S b/arch/arm/boot/compressed/head-xscale.S
index 73c5d9e0201c..236bbe578312 100644
--- a/arch/arm/boot/compressed/head-xscale.S
+++ b/arch/arm/boot/compressed/head-xscale.S
@@ -41,11 +41,6 @@ __XScale_start:
mov r7, #MACH_TYPE_COTULLA_IDP
#endif
-#ifdef CONFIG_MACH_GTWX5715
- mov r7, #(MACH_TYPE_GTWX5715 & 0xff)
- orr r7, r7, #(MACH_TYPE_GTWX5715 & 0xff00)
-#endif
-
#ifdef CONFIG_ARCH_IXP2000
mov r1, #-1
mov r0, #0xd6000000
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 680ea6ed77b8..b9b03eda70e5 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -55,7 +55,7 @@
#elif defined(CONFIG_ARCH_S3C2410)
.macro loadsp, rb
mov \rb, #0x50000000
- add \rb, \rb, #0x4000 * CONFIG_S3C2410_LOWLEVEL_UART_PORT
+ add \rb, \rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT
.endm
#else
.macro loadsp, rb
@@ -436,6 +436,28 @@ __armv4_mmu_cache_on:
mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
mov pc, r12
+__armv7_mmu_cache_on:
+ mov r12, lr
+ mrc p15, 0, r11, c0, c1, 4 @ read ID_MMFR0
+ tst r11, #0xf @ VMSA
+ blne __setup_mmu
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
+ tst r11, #0xf @ VMSA
+ mcrne p15, 0, r0, c8, c7, 0 @ flush I,D TLBs
+ mrc p15, 0, r0, c1, c0, 0 @ read control reg
+ orr r0, r0, #0x5000 @ I-cache enable, RR cache replacement
+ orr r0, r0, #0x003c @ write buffer
+ orrne r0, r0, #1 @ MMU enabled
+ movne r1, #-1
+ mcrne p15, 0, r3, c2, c0, 0 @ load page table pointer
+ mcrne p15, 0, r1, c3, c0, 0 @ load domain access control
+ mcr p15, 0, r0, c1, c0, 0 @ load control register
+ mrc p15, 0, r0, c1, c0, 0 @ and read it back
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 4 @ ISB
+ mov pc, r12
+
__arm6_mmu_cache_on:
mov r12, lr
bl __setup_mmu
@@ -622,11 +644,17 @@ proc_types:
b __armv4_mmu_cache_flush
.word 0x0007b000 @ ARMv6
- .word 0x0007f000
+ .word 0x000ff000
b __armv4_mmu_cache_on
b __armv4_mmu_cache_off
b __armv6_mmu_cache_flush
+ .word 0x000f0000 @ new CPU Id
+ .word 0x000f0000
+ b __armv7_mmu_cache_on
+ b __armv7_mmu_cache_off
+ b __armv7_mmu_cache_flush
+
.word 0 @ unrecognised type
.word 0
mov pc, lr
@@ -674,6 +702,16 @@ __armv4_mmu_cache_off:
mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4
mov pc, lr
+__armv7_mmu_cache_off:
+ mrc p15, 0, r0, c1, c0
+ bic r0, r0, #0x000d
+ mcr p15, 0, r0, c1, c0 @ turn MMU and cache off
+ mov r12, lr
+ bl __armv7_mmu_cache_flush
+ mov r0, #0
+ mcr p15, 0, r0, c8, c7, 0 @ invalidate whole TLB
+ mov pc, r12
+
__arm6_mmu_cache_off:
mov r0, #0x00000030 @ ARM6 control reg.
b __armv3_mmu_cache_off
@@ -730,6 +768,59 @@ __armv6_mmu_cache_flush:
mcr p15, 0, r1, c7, c10, 4 @ drain WB
mov pc, lr
+__armv7_mmu_cache_flush:
+ mrc p15, 0, r10, c0, c1, 5 @ read ID_MMFR1
+ tst r10, #0xf << 16 @ hierarchical cache (ARMv7)
+ beq hierarchical
+ mov r10, #0
+ mcr p15, 0, r10, c7, c14, 0 @ clean+invalidate D
+ b iflush
+hierarchical:
+ stmfd sp!, {r0-r5, r7, r9-r11}
+ mrc p15, 1, r0, c0, c0, 1 @ read clidr
+ ands r3, r0, #0x7000000 @ extract loc from clidr
+ mov r3, r3, lsr #23 @ left align loc bit field
+ beq finished @ if loc is 0, then no need to clean
+ mov r10, #0 @ start clean at cache level 0
+loop1:
+ add r2, r10, r10, lsr #1 @ work out 3x current cache level
+ mov r1, r0, lsr r2 @ extract cache type bits from clidr
+ and r1, r1, #7 @ mask of the bits for current cache only
+ cmp r1, #2 @ see what cache we have at this level
+ blt skip @ skip if no cache, or just i-cache
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
+ mcr p15, 0, r10, c7, c5, 4 @ isb to sych the new cssr&csidr
+ mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
+ and r2, r1, #7 @ extract the length of the cache lines
+ add r2, r2, #4 @ add 4 (line length offset)
+ ldr r4, =0x3ff
+ ands r4, r4, r1, lsr #3 @ find maximum number on the way size
+ .word 0xe16f5f14 @ clz r5, r4 - find bit position of way size increment
+ ldr r7, =0x7fff
+ ands r7, r7, r1, lsr #13 @ extract max number of the index size
+loop2:
+ mov r9, r4 @ create working copy of max way size
+loop3:
+ orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
+ orr r11, r11, r7, lsl r2 @ factor index number into r11
+ mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way
+ subs r9, r9, #1 @ decrement the way
+ bge loop3
+ subs r7, r7, #1 @ decrement the index
+ bge loop2
+skip:
+ add r10, r10, #2 @ increment cache number
+ cmp r3, r10
+ bgt loop1
+finished:
+ mov r10, #0 @ swith back to cache level 0
+ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
+ ldmfd sp!, {r0-r5, r7, r9-r11}
+iflush:
+ mcr p15, 0, r10, c7, c5, 0 @ invalidate I+BTB
+ mcr p15, 0, r10, c7, c10, 4 @ drain WB
+ mov pc, lr
+
__armv4_mmu_cache_flush:
mov r2, #64*1024 @ default: 32K dcache size (*2)
mov r11, #32 @ default: 32 byte line size
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index cfe6f4650bc9..ae21755872ed 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -60,6 +60,9 @@ struct locomo {
unsigned int irq;
spinlock_t lock;
void __iomem *base;
+#ifdef CONFIG_PM
+ void *saved_state;
+#endif
};
struct locomo_dev_info {
@@ -565,7 +568,7 @@ static int locomo_suspend(struct platform_device *dev, pm_message_t state)
if (!save)
return -ENOMEM;
- dev->dev.power.saved_state = (void *) save;
+ lchip->saved_state = save;
spin_lock_irqsave(&lchip->lock, flags);
@@ -605,8 +608,8 @@ static int locomo_resume(struct platform_device *dev)
struct locomo_save_data *save;
unsigned long r;
unsigned long flags;
-
- save = (struct locomo_save_data *) dev->dev.power.saved_state;
+
+ save = lchip->saved_state;
if (!save)
return 0;
@@ -628,6 +631,8 @@ static int locomo_resume(struct platform_device *dev)
locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD);
spin_unlock_irqrestore(&lchip->lock, flags);
+
+ lchip->saved_state = NULL;
kfree(save);
return 0;
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 798bbfccafb7..eb06d0b2cb74 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -51,6 +51,9 @@ struct sa1111 {
int irq;
spinlock_t lock;
void __iomem *base;
+#ifdef CONFIG_PM
+ void *saved_state;
+#endif
};
/*
@@ -822,7 +825,7 @@ static int sa1111_suspend(struct platform_device *dev, pm_message_t state)
save = kmalloc(sizeof(struct sa1111_save_data), GFP_KERNEL);
if (!save)
return -ENOMEM;
- dev->dev.power.saved_state = save;
+ sachip->saved_state = save;
spin_lock_irqsave(&sachip->lock, flags);
@@ -878,7 +881,7 @@ static int sa1111_resume(struct platform_device *dev)
unsigned long flags, id;
void __iomem *base;
- save = (struct sa1111_save_data *)dev->dev.power.saved_state;
+ save = sachip->saved_state;
if (!save)
return 0;
@@ -923,7 +926,7 @@ static int sa1111_resume(struct platform_device *dev)
spin_unlock_irqrestore(&sachip->lock, flags);
- dev->dev.power.saved_state = NULL;
+ sachip->saved_state = NULL;
kfree(save);
return 0;
@@ -958,8 +961,8 @@ static int sa1111_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
#ifdef CONFIG_PM
- kfree(pdev->dev.power.saved_state);
- pdev->dev.power.saved_state = NULL;
+ kfree(sachip->saved_state);
+ sachip->saved_state = NULL;
#endif
}
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
index 3bf3a927ae22..111a7fa5debe 100644
--- a/arch/arm/common/sharpsl_pm.c
+++ b/arch/arm/common/sharpsl_pm.c
@@ -766,9 +766,7 @@ static void sharpsl_apm_get_power_status(struct apm_power_info *info)
}
static struct pm_ops sharpsl_pm_ops = {
- .prepare = pxa_pm_prepare,
.enter = corgi_pxa_pm_enter,
- .finish = pxa_pm_finish,
.valid = pm_valid_only_mem,
};
diff --git a/arch/arm/configs/badge4_defconfig b/arch/arm/configs/badge4_defconfig
index 821865f75605..b2bbf217c707 100644
--- a/arch/arm/configs/badge4_defconfig
+++ b/arch/arm/configs/badge4_defconfig
@@ -708,7 +708,6 @@ CONFIG_I2C_ALGOPCF=m
# I2C Hardware Bus support
#
CONFIG_I2C_ELEKTOR=m
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set
diff --git a/arch/arm/configs/clps7500_defconfig b/arch/arm/configs/clps7500_defconfig
index af9ae5389131..49e9f9d8b3d1 100644
--- a/arch/arm/configs/clps7500_defconfig
+++ b/arch/arm/configs/clps7500_defconfig
@@ -536,7 +536,6 @@ CONFIG_I2C_ALGOBIT=y
# I2C Hardware Bus support
#
# CONFIG_I2C_ELEKTOR is not set
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PCA_ISA is not set
diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig
new file mode 100644
index 000000000000..6bea0901bdf0
--- /dev/null
+++ b/arch/arm/configs/em_x270_defconfig
@@ -0,0 +1,1265 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22
+# Mon Jul 9 15:18:20 2007
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_GENERIC_CLOCKEVENTS is not set
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ZONE_DMA=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_VECTORS_BASE=0xffff0000
+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="-em-x270"
+# CONFIG_LOCALVERSION_AUTO is not set
+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=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# 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=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_PNX4008 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Intel PXA2xx Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_LOGICPD_PXA270 is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_PXA_SHARPSL is not set
+# CONFIG_MACH_TRIZEPS4 is not set
+CONFIG_MACH_EM_X270=y
+CONFIG_PXA27x=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_IWMMXT=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Bus support
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE 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=4096
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE=""
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+CONFIG_APM_EMULATION=m
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=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_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
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# 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=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+# CONFIG_BT_RFCOMM_TTY is not set
+CONFIG_BT_BNEP=m
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+CONFIG_BT_HCIUART=m
+# CONFIG_BT_HCIUART_H4 is not set
+# CONFIG_BT_HCIUART_BCSP is not set
+CONFIG_BT_HCIBCM203X=m
+CONFIG_BT_HCIBPA10X=m
+CONFIG_BT_HCIBFUSB=m
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+# CONFIG_IEEE80211_CRYPT_TKIP is not set
+# CONFIG_IEEE80211_SOFTMAC is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_CFI_NOSWAP is not set
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_SHARP_SL is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_H1900 is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_SHARPSL is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI 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_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_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=12000
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD 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
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+CONFIG_DM9000=y
+# CONFIG_SMC911X is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN 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
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_PXA27x=m
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# 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
+# CONFIG_HWMON is not set
+
+#
+# Misc devices
+#
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_MBX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+CONFIG_SND_PXA2XX_PCM=m
+CONFIG_SND_PXA2XX_AC97=m
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+
+#
+# System on Chip audio support
+#
+# CONFIG_SND_SOC is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+
+#
+# MMC/SD Host Controller Drivers
+#
+CONFIG_MMC_PXA=m
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+CONFIG_RTC_DRV_V3020=m
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=m
+
+#
+# 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 is not set
+# 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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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 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_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
+# 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 is not set
+# 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=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_DES is not set
+# 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=m
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# 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
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/arm/configs/footbridge_defconfig b/arch/arm/configs/footbridge_defconfig
index 2a612d23120b..299dc22294a0 100644
--- a/arch/arm/configs/footbridge_defconfig
+++ b/arch/arm/configs/footbridge_defconfig
@@ -748,7 +748,6 @@ CONFIG_I2C=m
# CONFIG_I2C_ELEKTOR is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/arm/configs/neponset_defconfig b/arch/arm/configs/neponset_defconfig
index e86794a10fc0..92ccdc6492f7 100644
--- a/arch/arm/configs/neponset_defconfig
+++ b/arch/arm/configs/neponset_defconfig
@@ -698,7 +698,6 @@ CONFIG_I2C_ALGOBIT=y
# I2C Hardware Bus support
#
# CONFIG_I2C_ELEKTOR is not set
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set
# CONFIG_I2C_PCA_ISA is not set
diff --git a/arch/arm/configs/picotux200_defconfig b/arch/arm/configs/picotux200_defconfig
index 339c48953a62..3c0c4f192dc1 100644
--- a/arch/arm/configs/picotux200_defconfig
+++ b/arch/arm/configs/picotux200_defconfig
@@ -735,7 +735,6 @@ CONFIG_I2C_CHARDEV=m
# I2C Hardware Bus support
#
CONFIG_I2C_AT91=m
-CONFIG_I2C_ISA=m
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set
diff --git a/arch/arm/configs/rpc_defconfig b/arch/arm/configs/rpc_defconfig
index bc091264d354..8452dc8c7cc3 100644
--- a/arch/arm/configs/rpc_defconfig
+++ b/arch/arm/configs/rpc_defconfig
@@ -558,7 +558,6 @@ CONFIG_I2C_ALGOBIT=y
#
# I2C Hardware Bus support
#
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_STUB is not set
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index a850da377a29..f8a1645b3d4a 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -138,11 +138,11 @@ CONFIG_ARCH_S3C2410=y
CONFIG_PLAT_S3C24XX=y
CONFIG_CPU_S3C244X=y
CONFIG_PM_SIMTEC=y
-# CONFIG_S3C2410_BOOT_WATCHDOG is not set
-# CONFIG_S3C2410_BOOT_ERROR_RESET is not set
+# CONFIG_S3C_BOOT_WATCHDOG is not set
+# CONFIG_S3C_BOOT_ERROR_RESET is not set
# CONFIG_S3C2410_PM_DEBUG is not set
# CONFIG_S3C2410_PM_CHECK is not set
-CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+CONFIG_S3C_LOWLEVEL_UART_PORT=0
CONFIG_S3C2410_DMA=y
# CONFIG_S3C2410_DMA_DEBUG is not set
CONFIG_MACH_SMDK=y
@@ -826,7 +826,6 @@ CONFIG_I2C_ALGOBIT=m
# I2C Hardware Bus support
#
# CONFIG_I2C_ELEKTOR is not set
-CONFIG_I2C_ISA=m
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
@@ -1393,8 +1392,8 @@ CONFIG_DEBUG_USER=y
# CONFIG_DEBUG_ERRORS is not set
CONFIG_DEBUG_LL=y
# CONFIG_DEBUG_ICEDCC is not set
-CONFIG_DEBUG_S3C2410_PORT=y
-CONFIG_DEBUG_S3C2410_UART=0
+CONFIG_DEBUG_S3C_PORT=y
+CONFIG_DEBUG_S3C_UART=0
#
# Security options
diff --git a/arch/arm/kernel/head-common.S b/arch/arm/kernel/head-common.S
index a52da0ddb43d..024a9cf469b4 100644
--- a/arch/arm/kernel/head-common.S
+++ b/arch/arm/kernel/head-common.S
@@ -20,7 +20,8 @@ __switch_data:
.long _end @ r7
.long processor_id @ r4
.long __machine_arch_type @ r5
- .long cr_alignment @ r6
+ .long __atags_pointer @ r6
+ .long cr_alignment @ r7
.long init_thread_union + THREAD_START_SP @ sp
/*
@@ -29,6 +30,7 @@ __switch_data:
*
* r0 = cp#15 control register
* r1 = machine ID
+ * r2 = atags pointer
* r9 = processor ID
*/
.type __mmap_switched, %function
@@ -47,11 +49,12 @@ __mmap_switched:
strcc fp, [r6],#4
bcc 1b
- ldmia r3, {r4, r5, r6, sp}
+ ldmia r3, {r4, r5, r6, r7, sp}
str r9, [r4] @ Save processor ID
str r1, [r5] @ Save machine type
+ str r2, [r6] @ Save atags pointer
bic r4, r0, #CR_A @ Clear 'A' bit
- stmia r6, {r0, r4} @ Save control register values
+ stmia r7, {r0, r4} @ Save control register values
b start_kernel
/*
@@ -215,3 +218,34 @@ ENTRY(lookup_machine_type)
bl __lookup_machine_type
mov r0, r5
ldmfd sp!, {r4 - r6, pc}
+
+/* Determine validity of the r2 atags pointer. The heuristic requires
+ * that the pointer be aligned, in the first 16k of physical RAM and
+ * that the ATAG_CORE marker is first and present. Future revisions
+ * of this function may be more lenient with the physical address and
+ * may also be able to move the ATAGS block if necessary.
+ *
+ * r8 = machinfo
+ *
+ * Returns:
+ * r2 either valid atags pointer, or zero
+ * r5, r6 corrupted
+ */
+
+ .type __vet_atags, %function
+__vet_atags:
+ tst r2, #0x3 @ aligned?
+ bne 1f
+
+ ldr r5, [r2, #0] @ is first tag ATAG_CORE?
+ subs r5, r5, #ATAG_CORE_SIZE
+ bne 1f
+ ldr r5, [r2, #4]
+ ldr r6, =ATAG_CORE
+ cmp r5, r6
+ bne 1f
+
+ mov pc, lr @ atag pointer is ok
+
+1: mov r2, #0
+ mov pc, lr
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 41f98b4ba2ee..7898cbc9861a 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -29,6 +29,10 @@
#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
+#define ATAG_CORE 0x54410001
+#define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
+
+
/*
* swapper_pg_dir is the virtual address of the initial page table.
* We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must
@@ -61,7 +65,7 @@
*
* This is normally called from the decompressor code. The requirements
* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
- * r1 = machine nr.
+ * r1 = machine nr, r2 = atags pointer.
*
* This code is mostly position independent, so if you link the kernel at
* 0xc0008000, you call this at __pa(0xc0008000).
@@ -85,6 +89,7 @@ ENTRY(stext)
bl __lookup_machine_type @ r5=machinfo
movs r8, r5 @ invalid machine (r5=0)?
beq __error_a @ yes, error 'a'
+ bl __vet_atags
bl __create_page_tables
/*
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 842361777d4e..93b7f8e22dcc 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -44,6 +44,10 @@ static const char *processor_modes[] = {
"UK8_32" , "UK9_32" , "UK10_32", "UND_32" , "UK12_32", "UK13_32", "UK14_32", "SYS_32"
};
+static const char *isa_modes[] = {
+ "ARM" , "Thumb" , "Jazelle", "ThumbEE"
+};
+
extern void setup_mm_for_reboot(char mode);
static volatile int hlt_counter;
@@ -230,11 +234,11 @@ void __show_regs(struct pt_regs *regs)
buf[3] = flags & PSR_V_BIT ? 'V' : 'v';
buf[4] = '\0';
- printk("Flags: %s IRQs o%s FIQs o%s Mode %s%s Segment %s\n",
+ printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n",
buf, interrupts_enabled(regs) ? "n" : "ff",
fast_interrupts_enabled(regs) ? "n" : "ff",
processor_modes[processor_mode(regs)],
- thumb_mode(regs) ? " (T)" : "",
+ isa_modes[isa_mode(regs)],
get_fs() == get_ds() ? "kernel" : "user");
#ifdef CONFIG_CPU_CP15
{
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 6f2f46c2e406..78c9f1a3d41f 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -657,7 +657,6 @@ static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp)
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
- unsigned long tmp;
int ret;
switch (request) {
@@ -666,12 +665,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
*/
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
- ret = access_process_vm(child, addr, &tmp,
- sizeof(unsigned long), 0);
- if (ret == sizeof(unsigned long))
- ret = put_user(tmp, (unsigned long __user *) data);
- else
- ret = -EIO;
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
case PTRACE_PEEKUSR:
@@ -683,12 +677,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
*/
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = access_process_vm(child, addr, &data,
- sizeof(unsigned long), 1);
- if (ret == sizeof(unsigned long))
- ret = 0;
- else
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR:
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 650eac1bc0a6..5be2e987b843 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -63,6 +63,8 @@ unsigned int processor_id;
unsigned int __machine_arch_type;
EXPORT_SYMBOL(__machine_arch_type);
+unsigned int __atags_pointer __initdata;
+
unsigned int system_rev;
EXPORT_SYMBOL(system_rev);
@@ -780,7 +782,9 @@ void __init setup_arch(char **cmdline_p)
if (mdesc->soft_reboot)
reboot_setup("s");
- if (mdesc->boot_params)
+ if (__atags_pointer)
+ tags = phys_to_virt(__atags_pointer);
+ else if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);
/*
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 237f4999b9a1..f2114bcf09d5 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -249,6 +249,7 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
bust_spinlocks(1);
__die(str, err, thread, regs);
bust_spinlocks(0);
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 2b7a8f5d8cf2..5ff5406666b4 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -66,6 +66,7 @@ SECTIONS
. = ALIGN(4096);
__per_cpu_start = .;
*(.data.percpu)
+ *(.data.percpu.shared_aligned)
__per_cpu_end = .;
#ifndef CONFIG_XIP_KERNEL
__init_begin = _stext;
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index 70599bcf451c..0417c165d50d 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -477,7 +477,7 @@ void __init at91_add_device_i2c(void) {}
* SPI
* -------------------------------------------------------------------- */
-#if defined(CONFIG_SPI_AT91) || defined(CONFIG_SPI_AT91_MODULE) || defined(CONFIG_AT91_SPI) || defined(CONFIG_AT91_SPI_MODULE)
+#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
static u64 spi_dmamask = 0xffffffffUL;
static struct resource spi_resources[] = {
@@ -494,7 +494,7 @@ static struct resource spi_resources[] = {
};
static struct platform_device at91rm9200_spi_device = {
- .name = "at91_spi",
+ .name = "atmel_spi",
.id = 0,
.dev = {
.dma_mask = &spi_dmamask,
@@ -522,18 +522,14 @@ void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
else
cs_pin = spi_standard_cs[devices[i].chip_select];
-#ifdef CONFIG_SPI_AT91_MANUAL_CS
+ /* enable chip-select pin */
at91_set_gpio_output(cs_pin, 1);
-#else
- at91_set_A_periph(cs_pin, 0);
-#endif
/* pass chip-select pin to driver */
devices[i].controller_data = (void *) cs_pin;
}
spi_register_board_info(devices, nr_devices);
- at91_clock_associate("spi_clk", &at91rm9200_spi_device.dev, "spi");
platform_device_register(&at91rm9200_spi_device);
}
#else
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index e18a41e61f0c..dde089922e3b 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -23,6 +23,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/mtd/physmap.h>
@@ -83,6 +84,13 @@ static struct at91_udc_data __initdata csb337_udc_data = {
.pullup_pin = AT91_PIN_PA24,
};
+static struct i2c_board_info __initdata csb337_i2c_devices[] = {
+ { I2C_BOARD_INFO("rtc-ds1307", 0x68),
+ .type = "ds1307",
+ },
+};
+
+
static struct at91_cf_data __initdata csb337_cf_data = {
/*
* connector P4 on the CSB 337 mates to
@@ -161,6 +169,8 @@ static void __init csb337_board_init(void)
at91_add_device_udc(&csb337_udc_data);
/* I2C */
at91_add_device_i2c();
+ i2c_register_board_info(0, csb337_i2c_devices,
+ ARRAY_SIZE(csb337_i2c_devices));
/* Compact Flash */
at91_set_gpio_input(AT91_PIN_PB22, 1); /* IOIS16 */
at91_add_device_cf(&csb337_cf_data);
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 26ca8ab3f62a..42e172cb0f49 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -27,6 +27,11 @@
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <linux/dm9000.h>
+#include <linux/fb.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+
+#include <video/atmel_lcdc.h>
#include <asm/hardware.h>
#include <asm/setup.h>
@@ -271,6 +276,127 @@ static struct spi_board_info ek_spi_devices[] = {
};
+/*
+ * LCD Controller
+ */
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static struct fb_videomode at91_tft_vga_modes[] = {
+ {
+ .name = "TX09D50VM1CCA @ 60",
+ .refresh = 60,
+ .xres = 240, .yres = 320,
+ .pixclock = KHZ2PICOS(4965),
+
+ .left_margin = 1, .right_margin = 33,
+ .upper_margin = 1, .lower_margin = 0,
+ .hsync_len = 5, .vsync_len = 1,
+
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED,
+ },
+};
+
+static struct fb_monspecs at91fb_default_monspecs = {
+ .manufacturer = "HIT",
+ .monitor = "TX09D50VM1CCA",
+
+ .modedb = at91_tft_vga_modes,
+ .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
+ .hfmin = 15000,
+ .hfmax = 64000,
+ .vfmin = 50,
+ .vfmax = 150,
+};
+
+#define AT91SAM9261_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
+ | ATMEL_LCDC_DISTYPE_TFT \
+ | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+static void at91_lcdc_power_control(int on)
+{
+ if (on)
+ at91_set_gpio_value(AT91_PIN_PA12, 0); /* power up */
+ else
+ at91_set_gpio_value(AT91_PIN_PA12, 1); /* power down */
+}
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .default_bpp = 16,
+ .default_dmacon = ATMEL_LCDC_DMAEN,
+ .default_lcdcon2 = AT91SAM9261_DEFAULT_LCDCON2,
+ .default_monspecs = &at91fb_default_monspecs,
+ .atmel_lcdfb_power_control = at91_lcdc_power_control,
+ .guard_time = 1,
+};
+
+#else
+static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+#endif
+
+
+/*
+ * GPIO Buttons
+ */
+#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
+static struct gpio_keys_button ek_buttons[] = {
+ {
+ .gpio = AT91_PIN_PA27,
+ .keycode = BTN_0,
+ .desc = "Button 0",
+ .active_low = 1,
+ },
+ {
+ .gpio = AT91_PIN_PA26,
+ .keycode = BTN_1,
+ .desc = "Button 1",
+ .active_low = 1,
+ },
+ {
+ .gpio = AT91_PIN_PA25,
+ .keycode = BTN_2,
+ .desc = "Button 2",
+ .active_low = 1,
+ },
+ {
+ .gpio = AT91_PIN_PA24,
+ .keycode = BTN_3,
+ .desc = "Button 3",
+ .active_low = 1,
+ }
+};
+
+static struct gpio_keys_platform_data ek_button_data = {
+ .buttons = ek_buttons,
+ .nbuttons = ARRAY_SIZE(ek_buttons),
+};
+
+static struct platform_device ek_button_device = {
+ .name = "gpio-keys",
+ .id = -1,
+ .num_resources = 0,
+ .dev = {
+ .platform_data = &ek_button_data,
+ }
+};
+
+static void __init ek_add_device_buttons(void)
+{
+ at91_set_gpio_input(AT91_PIN_PB27, 0); /* btn0 */
+ at91_set_deglitch(AT91_PIN_PB27, 1);
+ at91_set_gpio_input(AT91_PIN_PB26, 0); /* btn1 */
+ at91_set_deglitch(AT91_PIN_PB26, 1);
+ at91_set_gpio_input(AT91_PIN_PB25, 0); /* btn2 */
+ at91_set_deglitch(AT91_PIN_PB25, 1);
+ at91_set_gpio_input(AT91_PIN_PB24, 0); /* btn3 */
+ at91_set_deglitch(AT91_PIN_PB24, 1);
+
+ platform_device_register(&ek_button_device);
+}
+#else
+static void __init ek_add_device_buttons(void) {}
+#endif
+
static void __init ek_board_init(void)
{
/* Serial */
@@ -296,6 +422,10 @@ static void __init ek_board_init(void)
/* MMC */
at91_add_device_mmc(0, &ek_mmc_data);
#endif
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
+ /* Push Buttons */
+ ek_add_device_buttons();
}
MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index c164c8e58ae6..2a1cc73390b7 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -26,6 +26,9 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
+#include <linux/fb.h>
+
+#include <video/atmel_lcdc.h>
#include <asm/hardware.h>
#include <asm/setup.h>
@@ -202,6 +205,65 @@ static struct at91_nand_data __initdata ek_nand_data = {
/*
+ * LCD Controller
+ */
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static struct fb_videomode at91_tft_vga_modes[] = {
+ {
+ .name = "TX09D50VM1CCA @ 60",
+ .refresh = 60,
+ .xres = 240, .yres = 320,
+ .pixclock = KHZ2PICOS(4965),
+
+ .left_margin = 1, .right_margin = 33,
+ .upper_margin = 1, .lower_margin = 0,
+ .hsync_len = 5, .vsync_len = 1,
+
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .vmode = FB_VMODE_NONINTERLACED,
+ },
+};
+
+static struct fb_monspecs at91fb_default_monspecs = {
+ .manufacturer = "HIT",
+ .monitor = "TX09D70VM1CCA",
+
+ .modedb = at91_tft_vga_modes,
+ .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
+ .hfmin = 15000,
+ .hfmax = 64000,
+ .vfmin = 50,
+ .vfmax = 150,
+};
+
+#define AT91SAM9263_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
+ | ATMEL_LCDC_DISTYPE_TFT \
+ | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+static void at91_lcdc_power_control(int on)
+{
+ if (on)
+ at91_set_gpio_value(AT91_PIN_PD12, 0); /* power up */
+ else
+ at91_set_gpio_value(AT91_PIN_PD12, 1); /* power down */
+}
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+ .default_bpp = 16,
+ .default_dmacon = ATMEL_LCDC_DMAEN,
+ .default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2,
+ .default_monspecs = &at91fb_default_monspecs,
+ .atmel_lcdfb_power_control = at91_lcdc_power_control,
+ .guard_time = 1,
+};
+
+#else
+static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+#endif
+
+
+/*
* AC97
*/
static struct atmel_ac97_data ek_ac97_data = {
@@ -230,6 +292,8 @@ static void __init ek_board_init(void)
at91_add_device_nand(&ek_nand_data);
/* I2C */
at91_add_device_i2c();
+ /* LCD Controller */
+ at91_add_device_lcdc(&ek_lcdc_data);
/* AC97 */
at91_add_device_ac97(&ek_ac97_data);
}
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index a8f88cd29905..99ac2e55774d 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -4,7 +4,8 @@
#
# Common objects
-obj-y := time.o irq.o serial.o io.o id.o psc.o
+obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \
+ gpio.o mux.o
# Board specific
obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o
diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c
index 633c12e43044..9e4024c4965f 100644
--- a/arch/arm/mach-davinci/board-evm.c
+++ b/arch/arm/mach-davinci/board-evm.c
@@ -32,6 +32,7 @@
void __init davinci_psc_init(void);
void __init davinci_irq_init(void);
void __init davinci_map_common_io(void);
+void __init davinci_init_common_hw(void);
/* NOR Flash base address set to CS0 by default */
#define NOR_FLASH_PHYS 0x02000000
@@ -116,6 +117,7 @@ static __init void davinci_evm_init(void)
static __init void davinci_evm_irq_init(void)
{
+ davinci_init_common_hw();
davinci_irq_init();
}
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
new file mode 100644
index 000000000000..139ceaa35e24
--- /dev/null
+++ b/arch/arm/mach-davinci/clock.c
@@ -0,0 +1,323 @@
+/*
+ * TI DaVinci clock config file
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * 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/init.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/psc.h>
+#include "clock.h"
+
+/* PLL/Reset register offsets */
+#define PLLM 0x110
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
+
+static unsigned int commonrate;
+static unsigned int armrate;
+static unsigned int fixedrate = 27000000; /* 27 MHZ */
+
+extern void davinci_psc_config(unsigned int domain, unsigned int id, char enable);
+
+/*
+ * Returns a clock. Note that we first try to use device id on the bus
+ * and clock name. If this fails, we try to use clock name only.
+ */
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ struct clk *p, *clk = ERR_PTR(-ENOENT);
+ int idno;
+
+ if (dev == NULL || dev->bus != &platform_bus_type)
+ idno = -1;
+ else
+ idno = to_platform_device(dev)->id;
+
+ mutex_lock(&clocks_mutex);
+
+ list_for_each_entry(p, &clocks, node) {
+ if (p->id == idno &&
+ strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ goto found;
+ }
+ }
+
+ list_for_each_entry(p, &clocks, node) {
+ if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+
+found:
+ mutex_unlock(&clocks_mutex);
+
+ return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ if (clk && !IS_ERR(clk))
+ module_put(clk->owner);
+}
+EXPORT_SYMBOL(clk_put);
+
+static int __clk_enable(struct clk *clk)
+{
+ if (clk->flags & ALWAYS_ENABLED)
+ return 0;
+
+ davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 1);
+ return 0;
+}
+
+static void __clk_disable(struct clk *clk)
+{
+ if (clk->usecount)
+ return;
+
+ davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, clk->lpsc, 0);
+}
+
+int clk_enable(struct clk *clk)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ if (clk->usecount++ == 0) {
+ spin_lock_irqsave(&clockfw_lock, flags);
+ ret = __clk_enable(clk);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
+ if (clk->usecount > 0 && !(--clk->usecount)) {
+ spin_lock_irqsave(&clockfw_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+ }
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ return *(clk->rate);
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ return *(clk->rate);
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ /* changing the clk rate is not supported */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_register(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return -EINVAL;
+
+ mutex_lock(&clocks_mutex);
+ list_add(&clk->node, &clocks);
+ mutex_unlock(&clocks_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+ if (clk == NULL || IS_ERR(clk))
+ return;
+
+ mutex_lock(&clocks_mutex);
+ list_del(&clk->node);
+ mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+static struct clk davinci_clks[] = {
+ {
+ .name = "ARMCLK",
+ .rate = &armrate,
+ .lpsc = -1,
+ .flags = ALWAYS_ENABLED,
+ },
+ {
+ .name = "UART",
+ .rate = &fixedrate,
+ .lpsc = DAVINCI_LPSC_UART0,
+ },
+ {
+ .name = "EMACCLK",
+ .rate = &commonrate,
+ .lpsc = DAVINCI_LPSC_EMAC_WRAPPER,
+ },
+ {
+ .name = "I2CCLK",
+ .rate = &fixedrate,
+ .lpsc = DAVINCI_LPSC_I2C,
+ },
+ {
+ .name = "IDECLK",
+ .rate = &commonrate,
+ .lpsc = DAVINCI_LPSC_ATA,
+ },
+ {
+ .name = "McBSPCLK",
+ .rate = &commonrate,
+ .lpsc = DAVINCI_LPSC_McBSP,
+ },
+ {
+ .name = "MMCSDCLK",
+ .rate = &commonrate,
+ .lpsc = DAVINCI_LPSC_MMC_SD,
+ },
+ {
+ .name = "SPICLK",
+ .rate = &commonrate,
+ .lpsc = DAVINCI_LPSC_SPI,
+ },
+ {
+ .name = "gpio",
+ .rate = &commonrate,
+ .lpsc = DAVINCI_LPSC_GPIO,
+ },
+ {
+ .name = "AEMIFCLK",
+ .rate = &commonrate,
+ .lpsc = DAVINCI_LPSC_AEMIF,
+ .usecount = 1,
+ }
+};
+
+int __init davinci_clk_init(void)
+{
+ struct clk *clkp;
+ int count = 0;
+ u32 pll_mult;
+
+ pll_mult = davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLM);
+ commonrate = ((pll_mult + 1) * 27000000) / 6;
+ armrate = ((pll_mult + 1) * 27000000) / 2;
+
+ for (clkp = davinci_clks; count < ARRAY_SIZE(davinci_clks);
+ count++, clkp++) {
+ clk_register(clkp);
+
+ /* Turn on clocks that have been enabled in the
+ * table above */
+ if (clkp->usecount)
+ clk_enable(clkp);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void *davinci_ck_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < 1 ? (void *)1 : NULL;
+}
+
+static void *davinci_ck_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return NULL;
+}
+
+static void davinci_ck_stop(struct seq_file *m, void *v)
+{
+}
+
+static int davinci_ck_show(struct seq_file *m, void *v)
+{
+ struct clk *cp;
+
+ list_for_each_entry(cp, &clocks, node)
+ seq_printf(m,"%s %d %d\n", cp->name, *(cp->rate), cp->usecount);
+
+ return 0;
+}
+
+static struct seq_operations davinci_ck_op = {
+ .start = davinci_ck_start,
+ .next = davinci_ck_next,
+ .stop = davinci_ck_stop,
+ .show = davinci_ck_show
+};
+
+static int davinci_ck_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &davinci_ck_op);
+}
+
+static struct file_operations proc_davinci_ck_operations = {
+ .open = davinci_ck_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init davinci_ck_proc_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ entry = create_proc_entry("davinci_clocks", 0, NULL);
+ if (entry)
+ entry->proc_fops = &proc_davinci_ck_operations;
+ return 0;
+
+}
+__initcall(davinci_ck_proc_init);
+#endif /* CONFIG_DEBUG_PROC_FS */
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
new file mode 100644
index 000000000000..ed47079a52e4
--- /dev/null
+++ b/arch/arm/mach-davinci/clock.h
@@ -0,0 +1,33 @@
+/*
+ * TI DaVinci clock definitions
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_DAVINCI_CLOCK_H
+#define __ARCH_ARM_DAVINCI_CLOCK_H
+
+struct clk {
+ struct list_head node;
+ struct module *owner;
+ const char *name;
+ unsigned int *rate;
+ int id;
+ __s8 usecount;
+ __u8 flags;
+ __u8 lpsc;
+};
+
+/* Clock flags */
+#define RATE_CKCTL 1
+#define RATE_FIXED 2
+#define RATE_PROPAGATES 4
+#define VIRTUAL_CLOCK 8
+#define ALWAYS_ENABLED 16
+#define ENABLE_REG_32BIT 32
+
+#endif
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
new file mode 100644
index 000000000000..9c67886e7189
--- /dev/null
+++ b/arch/arm/mach-davinci/gpio.c
@@ -0,0 +1,286 @@
+/*
+ * TI DaVinci GPIO Support
+ *
+ * Copyright (c) 2006 David Brownell
+ * Copyright (c) 2007, 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.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/bitops.h>
+
+#include <asm/arch/irqs.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+
+#include <asm/mach/irq.h>
+
+static DEFINE_SPINLOCK(gpio_lock);
+static DECLARE_BITMAP(gpio_in_use, DAVINCI_N_GPIO);
+
+int gpio_request(unsigned gpio, const char *tag)
+{
+ if (gpio >= DAVINCI_N_GPIO)
+ return -EINVAL;
+
+ if (test_and_set_bit(gpio, gpio_in_use))
+ return -EBUSY;
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned gpio)
+{
+ if (gpio >= DAVINCI_N_GPIO)
+ return;
+
+ clear_bit(gpio, gpio_in_use);
+}
+EXPORT_SYMBOL(gpio_free);
+
+/* create a non-inlined version */
+static struct gpio_controller *__iomem gpio2controller(unsigned gpio)
+{
+ return __gpio_to_controller(gpio);
+}
+
+/*
+ * Assuming the pin is muxed as a gpio output, set its output value.
+ */
+void __gpio_set(unsigned gpio, int value)
+{
+ struct gpio_controller *__iomem g = gpio2controller(gpio);
+
+ __raw_writel(__gpio_mask(gpio), value ? &g->set_data : &g->clr_data);
+}
+EXPORT_SYMBOL(__gpio_set);
+
+
+/*
+ * Read the pin's value (works even if it's set up as output);
+ * returns zero/nonzero.
+ *
+ * Note that changes are synched to the GPIO clock, so reading values back
+ * right after you've set them may give old values.
+ */
+int __gpio_get(unsigned gpio)
+{
+ struct gpio_controller *__iomem g = gpio2controller(gpio);
+
+ return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
+}
+EXPORT_SYMBOL(__gpio_get);
+
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * board setup code *MUST* set PINMUX0 and PINMUX1 as
+ * needed, and enable the GPIO clock.
+ */
+
+int gpio_direction_input(unsigned gpio)
+{
+ struct gpio_controller *__iomem g = gpio2controller(gpio);
+ u32 temp;
+ u32 mask;
+
+ if (!g)
+ return -EINVAL;
+
+ spin_lock(&gpio_lock);
+ mask = __gpio_mask(gpio);
+ temp = __raw_readl(&g->dir);
+ temp |= mask;
+ __raw_writel(temp, &g->dir);
+ spin_unlock(&gpio_lock);
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+int gpio_direction_output(unsigned gpio, int value)
+{
+ struct gpio_controller *__iomem g = gpio2controller(gpio);
+ u32 temp;
+ u32 mask;
+
+ if (!g)
+ return -EINVAL;
+
+ spin_lock(&gpio_lock);
+ mask = __gpio_mask(gpio);
+ temp = __raw_readl(&g->dir);
+ temp &= ~mask;
+ __raw_writel(mask, value ? &g->set_data : &g->clr_data);
+ __raw_writel(temp, &g->dir);
+ spin_unlock(&gpio_lock);
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+/*
+ * We expect irqs will normally be set up as input pins, but they can also be
+ * used as output pins ... which is convenient for testing.
+ *
+ * NOTE: GPIO0..GPIO7 also have direct INTC hookups, which work in addition
+ * to their GPIOBNK0 irq (but with a bit less overhead). But we don't have
+ * a good way to hook those up ...
+ *
+ * All those INTC hookups (GPIO0..GPIO7 plus five IRQ banks) can also
+ * serve as EDMA event triggers.
+ */
+
+static void gpio_irq_disable(unsigned irq)
+{
+ struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ u32 mask = __gpio_mask(irq_to_gpio(irq));
+
+ __raw_writel(mask, &g->clr_falling);
+ __raw_writel(mask, &g->clr_rising);
+}
+
+static void gpio_irq_enable(unsigned irq)
+{
+ struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ u32 mask = __gpio_mask(irq_to_gpio(irq));
+
+ if (irq_desc[irq].status & IRQ_TYPE_EDGE_FALLING)
+ __raw_writel(mask, &g->set_falling);
+ if (irq_desc[irq].status & IRQ_TYPE_EDGE_RISING)
+ __raw_writel(mask, &g->set_rising);
+}
+
+static int gpio_irq_type(unsigned irq, unsigned trigger)
+{
+ struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ u32 mask = __gpio_mask(irq_to_gpio(irq));
+
+ if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+ return -EINVAL;
+
+ irq_desc[irq].status &= ~IRQ_TYPE_SENSE_MASK;
+ irq_desc[irq].status |= trigger;
+
+ __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING)
+ ? &g->set_falling : &g->clr_falling);
+ __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING)
+ ? &g->set_rising : &g->clr_rising);
+ return 0;
+}
+
+static struct irq_chip gpio_irqchip = {
+ .name = "GPIO",
+ .enable = gpio_irq_enable,
+ .disable = gpio_irq_disable,
+ .set_type = gpio_irq_type,
+};
+
+static void
+gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct gpio_controller *__iomem g = get_irq_chip_data(irq);
+ u32 mask = 0xffff;
+
+ /* we only care about one bank */
+ if (irq & 1)
+ mask <<= 16;
+
+ /* temporarily mask (level sensitive) parent IRQ */
+ desc->chip->ack(irq);
+ while (1) {
+ u32 status;
+ struct irq_desc *gpio;
+ int n;
+ int res;
+
+ /* ack any irqs */
+ status = __raw_readl(&g->intstat) & mask;
+ if (!status)
+ break;
+ __raw_writel(status, &g->intstat);
+ if (irq & 1)
+ status >>= 16;
+
+ /* now demux them to the right lowlevel handler */
+ n = (int)get_irq_data(irq);
+ gpio = &irq_desc[n];
+ while (status) {
+ res = ffs(status);
+ n += res;
+ gpio += res;
+ desc_handle_irq(n - 1, gpio - 1);
+ status >>= res;
+ }
+ }
+ desc->chip->unmask(irq);
+ /* now it may re-trigger */
+}
+
+/*
+ * NOTE: for suspend/resume, probably best to make a sysdev (and class)
+ * with its suspend/resume calls hooking into the results of the set_wake()
+ * calls ... so if no gpios are wakeup events the clock can be disabled,
+ * with outputs left at previously set levels, and so that VDD3P3V.IOPWDN0
+ * can be set appropriately for GPIOV33 pins.
+ */
+
+static int __init davinci_gpio_irq_setup(void)
+{
+ unsigned gpio, irq, bank;
+ struct clk *clk;
+
+ clk = clk_get(NULL, "gpio");
+ if (IS_ERR(clk)) {
+ printk(KERN_ERR "Error %ld getting gpio clock?\n",
+ PTR_ERR(clk));
+ return 0;
+ }
+
+ clk_enable(clk);
+
+ for (gpio = 0, irq = gpio_to_irq(0), bank = IRQ_GPIOBNK0;
+ gpio < DAVINCI_N_GPIO; bank++) {
+ struct gpio_controller *__iomem g = gpio2controller(gpio);
+ unsigned i;
+
+ __raw_writel(~0, &g->clr_falling);
+ __raw_writel(~0, &g->clr_rising);
+
+ /* set up all irqs in this bank */
+ set_irq_chained_handler(bank, gpio_irq_handler);
+ set_irq_chip_data(bank, g);
+ set_irq_data(bank, (void *)irq);
+
+ for (i = 0; i < 16 && gpio < DAVINCI_N_GPIO;
+ i++, irq++, gpio++) {
+ set_irq_chip(irq, &gpio_irqchip);
+ set_irq_chip_data(irq, g);
+ set_irq_handler(irq, handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+ }
+
+ /* BINTEN -- per-bank interrupt enable. genirq would also let these
+ * bits be set/cleared dynamically.
+ */
+ __raw_writel(0x1f, (void *__iomem)
+ IO_ADDRESS(DAVINCI_GPIO_BASE + 0x08));
+
+ printk(KERN_INFO "DaVinci: %d gpio irqs\n", irq - gpio_to_irq(0));
+
+ return 0;
+}
+
+arch_initcall(davinci_gpio_irq_setup);
diff --git a/arch/arm/mach-davinci/io.c b/arch/arm/mach-davinci/io.c
index 87fae6fb6ecf..47787ff84a6a 100644
--- a/arch/arm/mach-davinci/io.c
+++ b/arch/arm/mach-davinci/io.c
@@ -17,6 +17,7 @@
#include <asm/memory.h>
#include <asm/mach/map.h>
+#include <asm/arch/clock.h>
extern void davinci_check_revision(void);
@@ -49,3 +50,8 @@ void __init davinci_map_common_io(void)
*/
davinci_check_revision();
}
+
+void __init davinci_init_common_hw(void)
+{
+ davinci_clk_init();
+}
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c
new file mode 100644
index 000000000000..92d26bd305b7
--- /dev/null
+++ b/arch/arm/mach-davinci/mux.c
@@ -0,0 +1,41 @@
+/*
+ * DaVinci pin multiplexing configurations
+ *
+ * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * 2007 (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.
+ */
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+
+#include <asm/arch/mux.h>
+
+/* System control register offsets */
+#define PINMUX0 0x00
+#define PINMUX1 0x04
+
+static DEFINE_SPINLOCK(mux_lock);
+
+void davinci_mux_peripheral(unsigned int mux, unsigned int enable)
+{
+ u32 pinmux, muxreg = PINMUX0;
+
+ if (mux >= DAVINCI_MUX_LEVEL2) {
+ muxreg = PINMUX1;
+ mux -= DAVINCI_MUX_LEVEL2;
+ }
+
+ spin_lock(&mux_lock);
+ pinmux = davinci_readl(DAVINCI_SYSTEM_MODULE_BASE + muxreg);
+ if (enable)
+ pinmux |= (1 << mux);
+ else
+ pinmux &= ~(1 << mux);
+ davinci_writel(pinmux, DAVINCI_SYSTEM_MODULE_BASE + muxreg);
+ spin_unlock(&mux_lock);
+}
diff --git a/arch/arm/mach-davinci/psc.c b/arch/arm/mach-davinci/psc.c
index e1b0050283a6..1334416559ad 100644
--- a/arch/arm/mach-davinci/psc.c
+++ b/arch/arm/mach-davinci/psc.c
@@ -25,39 +25,40 @@
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/arch/psc.h>
+#include <asm/arch/mux.h>
-#define PTCMD __REG(0x01C41120)
-#define PDSTAT __REG(0x01C41200)
-#define PDCTL1 __REG(0x01C41304)
-#define EPCPR __REG(0x01C41070)
-#define PTSTAT __REG(0x01C41128)
+/* PSC register offsets */
+#define EPCPR 0x070
+#define PTCMD 0x120
+#define PTSTAT 0x128
+#define PDSTAT 0x200
+#define PDCTL1 0x304
+#define MDSTAT 0x800
+#define MDCTL 0xA00
-#define MDSTAT IO_ADDRESS(0x01C41800)
-#define MDCTL IO_ADDRESS(0x01C41A00)
-
-#define PINMUX0 __REG(0x01c40000)
-#define PINMUX1 __REG(0x01c40004)
-#define VDD3P3V_PWDN __REG(0x01C40048)
+/* System control register offsets */
+#define VDD3P3V_PWDN 0x48
static void davinci_psc_mux(unsigned int id)
{
switch (id) {
case DAVINCI_LPSC_ATA:
- PINMUX0 |= (1 << 17) | (1 << 16);
+ davinci_mux_peripheral(DAVINCI_MUX_HDIREN, 1);
+ davinci_mux_peripheral(DAVINCI_MUX_ATAEN, 1);
break;
case DAVINCI_LPSC_MMC_SD:
/* VDD power manupulations are done in U-Boot for CPMAC
* so applies to MMC as well
*/
/*Set up the pull regiter for MMC */
- VDD3P3V_PWDN = 0x0;
- PINMUX1 &= (~(1 << 9));
+ davinci_writel(0, DAVINCI_SYSTEM_MODULE_BASE + VDD3P3V_PWDN);
+ davinci_mux_peripheral(DAVINCI_MUX_MSTK, 0);
break;
case DAVINCI_LPSC_I2C:
- PINMUX1 |= (1 << 7);
+ davinci_mux_peripheral(DAVINCI_MUX_I2C, 1);
break;
case DAVINCI_LPSC_McBSP:
- PINMUX1 |= (1 << 10);
+ davinci_mux_peripheral(DAVINCI_MUX_ASP, 1);
break;
default:
break;
@@ -67,33 +68,59 @@ static void davinci_psc_mux(unsigned int id)
/* Enable or disable a PSC domain */
void davinci_psc_config(unsigned int domain, unsigned int id, char enable)
{
- volatile unsigned int *mdstat = (unsigned int *)((int)MDSTAT + 4 * id);
- volatile unsigned int *mdctl = (unsigned int *)((int)MDCTL + 4 * id);
+ u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl, mdstat_mask;
if (id < 0)
return;
+ mdctl = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id);
if (enable)
- *mdctl |= 0x00000003; /* Enable Module */
+ mdctl |= 0x00000003; /* Enable Module */
else
- *mdctl &= 0xFFFFFFF2; /* Disable Module */
+ mdctl &= 0xFFFFFFF2; /* Disable Module */
+ davinci_writel(mdctl, DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id);
+
+ pdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDSTAT);
+ if ((pdstat & 0x00000001) == 0) {
+ pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
+ pdctl1 |= 0x1;
+ davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
+
+ ptcmd = 1 << domain;
+ davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD);
- if ((PDSTAT & 0x00000001) == 0) {
- PDCTL1 |= 0x1;
- PTCMD = (1 << domain);
- while ((((EPCPR >> domain) & 1) == 0));
+ do {
+ epcpr = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+ EPCPR);
+ } while ((((epcpr >> domain) & 1) == 0));
- PDCTL1 |= 0x100;
- while (!(((PTSTAT >> domain) & 1) == 0));
+ pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
+ pdctl1 |= 0x100;
+ davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1);
+
+ do {
+ ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+ PTSTAT);
+ } while (!(((ptstat >> domain) & 1) == 0));
} else {
- PTCMD = (1 << domain);
- while (!(((PTSTAT >> domain) & 1) == 0));
+ ptcmd = 1 << domain;
+ davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD);
+
+ do {
+ ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+ PTSTAT);
+ } while (!(((ptstat >> domain) & 1) == 0));
}
if (enable)
- while (!((*mdstat & 0x0000001F) == 0x3));
+ mdstat_mask = 0x3;
else
- while (!((*mdstat & 0x0000001F) == 0x2));
+ mdstat_mask = 0x2;
+
+ do {
+ mdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE +
+ MDSTAT + 4 * id);
+ } while (!((mdstat & 0x0000001F) == mdstat_mask));
if (enable)
davinci_psc_mux(id);
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 4d8425de6922..e96a3dcdc1a7 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -285,6 +285,8 @@ static void davinci_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_SHUTDOWN:
t->opts = TIMER_OPTS_DISABLED;
break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
}
}
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c
index 1c474cf709ca..a58b678006df 100644
--- a/arch/arm/mach-imx/generic.c
+++ b/arch/arm/mach-imx/generic.c
@@ -28,12 +28,16 @@
#include <linux/module.h>
#include <linux/string.h>
+#include <asm/errno.h>
#include <asm/arch/imxfb.h>
#include <asm/hardware.h>
#include <asm/arch/imx-regs.h>
#include <asm/mach/map.h>
#include <asm/arch/mmc.h>
+#include <asm/arch/gpio.h>
+
+unsigned long imx_gpio_alloc_map[(GPIO_PORT_MAX + 1) * 32 / BITS_PER_LONG];
void imx_gpio_mode(int gpio_mode)
{
@@ -95,6 +99,120 @@ void imx_gpio_mode(int gpio_mode)
EXPORT_SYMBOL(imx_gpio_mode);
+int imx_gpio_request(unsigned gpio, const char *label)
+{
+ if(gpio >= (GPIO_PORT_MAX + 1) * 32)
+ printk(KERN_ERR "imx_gpio: Attempt to request nonexistent GPIO %d for \"%s\"\n",
+ gpio, label ? label : "?");
+ return -EINVAL;
+
+ if(test_and_set_bit(gpio, imx_gpio_alloc_map)) {
+ printk(KERN_ERR "imx_gpio: GPIO %d already used. Allocation for \"%s\" failed\n",
+ gpio, label ? label : "?");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(imx_gpio_request);
+
+void imx_gpio_free(unsigned gpio)
+{
+ if(gpio >= (GPIO_PORT_MAX + 1) * 32)
+ return;
+
+ clear_bit(gpio, imx_gpio_alloc_map);
+}
+
+EXPORT_SYMBOL(imx_gpio_free);
+
+int imx_gpio_direction_input(unsigned gpio)
+{
+ imx_gpio_mode(gpio| GPIO_IN);
+ return 0;
+}
+
+EXPORT_SYMBOL(imx_gpio_direction_input);
+
+int imx_gpio_direction_output(unsigned gpio, int value)
+{
+ imx_gpio_set_value(gpio, value);
+ imx_gpio_mode(gpio| GPIO_OUT);
+ return 0;
+}
+
+EXPORT_SYMBOL(imx_gpio_direction_output);
+
+int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
+ int alloc_mode, const char *label)
+{
+ const int *p = pin_list;
+ int i;
+ unsigned gpio;
+ unsigned mode;
+
+ for (i = 0; i < count; i++) {
+ gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
+ mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK);
+
+ if (gpio >= (GPIO_PORT_MAX + 1) * 32)
+ goto setup_error;
+
+ if (alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE)
+ imx_gpio_free(gpio);
+ else if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC))
+ if (imx_gpio_request(gpio, label))
+ if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC))
+ goto setup_error;
+
+ if (!(alloc_mode & (IMX_GPIO_ALLOC_MODE_ALLOC_ONLY |
+ IMX_GPIO_ALLOC_MODE_RELEASE)))
+ imx_gpio_mode(gpio | mode);
+
+ p++;
+ }
+ return 0;
+
+setup_error:
+ if(alloc_mode & (IMX_GPIO_ALLOC_MODE_NO_ALLOC |
+ IMX_GPIO_ALLOC_MODE_TRY_ALLOC))
+ return -EINVAL;
+
+ while (p != pin_list) {
+ p--;
+ gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
+ imx_gpio_free(gpio);
+ }
+
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL(imx_gpio_setup_multiple_pins);
+
+void __imx_gpio_set_value(unsigned gpio, int value)
+{
+ imx_gpio_set_value_inline(gpio, value);
+}
+
+EXPORT_SYMBOL(__imx_gpio_set_value);
+
+int imx_gpio_to_irq(unsigned gpio)
+{
+ return IRQ_GPIOA(0) + gpio;
+}
+
+EXPORT_SYMBOL(imx_gpio_to_irq);
+
+int imx_irq_to_gpio(unsigned irq)
+{
+ if (irq < IRQ_GPIOA(0))
+ return -EINVAL;
+ return irq - IRQ_GPIOA(0);
+}
+
+EXPORT_SYMBOL(imx_irq_to_gpio);
+
/*
* get the system pll clock in Hz
*
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 6960a9d04217..d86d124aea22 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2000-2001 Deep Blue Solutions
* Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.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
@@ -15,6 +16,7 @@
#include <linux/irq.h>
#include <linux/time.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <asm/hardware.h>
#include <asm/io.h>
@@ -25,7 +27,8 @@
/* Use timer 1 as system timer */
#define TIMER_BASE IMX_TIM1_BASE
-static unsigned long evt_diff;
+static struct clock_event_device clockevent_imx;
+static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
/*
* IRQ handler for the timer
@@ -33,25 +36,20 @@ static unsigned long evt_diff;
static irqreturn_t
imx_timer_interrupt(int irq, void *dev_id)
{
+ struct clock_event_device *evt = &clockevent_imx;
uint32_t tstat;
+ irqreturn_t ret = IRQ_NONE;
/* clear the interrupt */
tstat = IMX_TSTAT(TIMER_BASE);
IMX_TSTAT(TIMER_BASE) = 0;
if (tstat & TSTAT_COMP) {
- do {
-
- write_seqlock(&xtime_lock);
- timer_tick();
- write_sequnlock(&xtime_lock);
- IMX_TCMP(TIMER_BASE) += evt_diff;
-
- } while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE)
- - IMX_TCN(TIMER_BASE)) < 0));
+ evt->event_handler(evt);
+ ret = IRQ_HANDLED;
}
- return IRQ_HANDLED;
+ return ret;
}
static struct irqaction imx_timer_irq = {
@@ -70,10 +68,8 @@ static void __init imx_timer_hardware_init(void)
*/
IMX_TCTL(TIMER_BASE) = 0;
IMX_TPRER(TIMER_BASE) = 0;
- IMX_TCMP(TIMER_BASE) = LATCH - 1;
- IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_IRQEN | TCTL_TEN;
- evt_diff = LATCH;
+ IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_TEN;
}
cycle_t imx_get_cycles(void)
@@ -99,11 +95,109 @@ static int __init imx_clocksource_init(void)
return 0;
}
+static int imx_set_next_event(unsigned long evt,
+ struct clock_event_device *unused)
+{
+ unsigned long tcmp;
+
+ tcmp = IMX_TCN(TIMER_BASE) + evt;
+ IMX_TCMP(TIMER_BASE) = tcmp;
+
+ return (int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0 ? -ETIME : 0;
+}
+
+#ifdef DEBUG
+static const char *clock_event_mode_label[]={
+ [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
+ [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
+ [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
+ [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED"
+};
+#endif /*DEBUG*/
+
+static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+ unsigned long flags;
+
+ /*
+ * The timer interrupt generation is disabled at least
+ * for enough time to call imx_set_next_event()
+ */
+ local_irq_save(flags);
+ /* Disable interrupt in GPT module */
+ IMX_TCTL(TIMER_BASE) &= ~TCTL_IRQEN;
+ if (mode != clockevent_mode) {
+ /* Set event time into far-far future */
+ IMX_TCMP(TIMER_BASE) = IMX_TCN(TIMER_BASE) - 3;
+ /* Clear pending interrupt */
+ IMX_TSTAT(TIMER_BASE) &= ~TSTAT_COMP;
+ }
+
+#ifdef DEBUG
+ printk(KERN_INFO "imx_set_mode: changing mode from %s to %s\n",
+ clock_event_mode_label[clockevent_mode], clock_event_mode_label[mode]);
+#endif /*DEBUG*/
+
+ /* Remember timer mode */
+ clockevent_mode = mode;
+ local_irq_restore(flags);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ printk(KERN_ERR "imx_set_mode: Periodic mode is not supported for i.MX\n");
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /*
+ * Do not put overhead of interrupt enable/disable into
+ * imx_set_next_event(), the core has about 4 minutes
+ * to call imx_set_next_event() or shutdown clock after
+ * mode switching
+ */
+ local_irq_save(flags);
+ IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN;
+ local_irq_restore(flags);
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_RESUME:
+ /* Left event sources disabled, no more interrupts appears */
+ break;
+ }
+}
+
+static struct clock_event_device clockevent_imx = {
+ .name = "imx_timer1",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .set_mode = imx_set_mode,
+ .set_next_event = imx_set_next_event,
+ .rating = 200,
+};
+
+static int __init imx_clockevent_init(void)
+{
+ clockevent_imx.mult = div_sc(imx_get_perclk1(), NSEC_PER_SEC,
+ clockevent_imx.shift);
+ clockevent_imx.max_delta_ns =
+ clockevent_delta2ns(0xfffffffe, &clockevent_imx);
+ clockevent_imx.min_delta_ns =
+ clockevent_delta2ns(0xf, &clockevent_imx);
+
+ clockevent_imx.cpumask = cpumask_of_cpu(0);
+
+ clockevents_register_device(&clockevent_imx);
+
+ return 0;
+}
+
+
static void __init imx_timer_init(void)
{
imx_timer_hardware_init();
imx_clocksource_init();
+ imx_clockevent_init();
+
/*
* Make irqs happen for the system timer
*/
diff --git a/arch/arm/mach-iop13xx/pci.c b/arch/arm/mach-iop13xx/pci.c
index 9d63d7f260ca..99d94cb1bafd 100644
--- a/arch/arm/mach-iop13xx/pci.c
+++ b/arch/arm/mach-iop13xx/pci.c
@@ -1002,11 +1002,10 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
if (nr > 1)
return 0;
- res = kmalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+ res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
if (!res)
panic("PCI: unable to alloc resources");
- memset(res, 0, sizeof(struct resource) * 2);
/* 'nr' assumptions:
* ATUX is always 0
diff --git a/arch/arm/mach-iop13xx/setup.c b/arch/arm/mach-iop13xx/setup.c
index bc4871553f6a..bfe0c87e3397 100644
--- a/arch/arm/mach-iop13xx/setup.c
+++ b/arch/arm/mach-iop13xx/setup.c
@@ -25,6 +25,7 @@
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/hardware/iop_adma.h>
#define IOP13XX_UART_XTAL 33334000
#define IOP13XX_SETUP_DEBUG 0
@@ -236,19 +237,143 @@ static unsigned long iq8134x_probe_flash_size(void)
}
#endif
+/* ADMA Channels */
+static struct resource iop13xx_adma_0_resources[] = {
+ [0] = {
+ .start = IOP13XX_ADMA_PHYS_BASE(0),
+ .end = IOP13XX_ADMA_UPPER_PA(0),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_IOP13XX_ADMA0_EOT,
+ .end = IRQ_IOP13XX_ADMA0_EOT,
+ .flags = IORESOURCE_IRQ
+ },
+ [2] = {
+ .start = IRQ_IOP13XX_ADMA0_EOC,
+ .end = IRQ_IOP13XX_ADMA0_EOC,
+ .flags = IORESOURCE_IRQ
+ },
+ [3] = {
+ .start = IRQ_IOP13XX_ADMA0_ERR,
+ .end = IRQ_IOP13XX_ADMA0_ERR,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct resource iop13xx_adma_1_resources[] = {
+ [0] = {
+ .start = IOP13XX_ADMA_PHYS_BASE(1),
+ .end = IOP13XX_ADMA_UPPER_PA(1),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_IOP13XX_ADMA1_EOT,
+ .end = IRQ_IOP13XX_ADMA1_EOT,
+ .flags = IORESOURCE_IRQ
+ },
+ [2] = {
+ .start = IRQ_IOP13XX_ADMA1_EOC,
+ .end = IRQ_IOP13XX_ADMA1_EOC,
+ .flags = IORESOURCE_IRQ
+ },
+ [3] = {
+ .start = IRQ_IOP13XX_ADMA1_ERR,
+ .end = IRQ_IOP13XX_ADMA1_ERR,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct resource iop13xx_adma_2_resources[] = {
+ [0] = {
+ .start = IOP13XX_ADMA_PHYS_BASE(2),
+ .end = IOP13XX_ADMA_UPPER_PA(2),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_IOP13XX_ADMA2_EOT,
+ .end = IRQ_IOP13XX_ADMA2_EOT,
+ .flags = IORESOURCE_IRQ
+ },
+ [2] = {
+ .start = IRQ_IOP13XX_ADMA2_EOC,
+ .end = IRQ_IOP13XX_ADMA2_EOC,
+ .flags = IORESOURCE_IRQ
+ },
+ [3] = {
+ .start = IRQ_IOP13XX_ADMA2_ERR,
+ .end = IRQ_IOP13XX_ADMA2_ERR,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static u64 iop13xx_adma_dmamask = DMA_64BIT_MASK;
+static struct iop_adma_platform_data iop13xx_adma_0_data = {
+ .hw_id = 0,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct iop_adma_platform_data iop13xx_adma_1_data = {
+ .hw_id = 1,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct iop_adma_platform_data iop13xx_adma_2_data = {
+ .hw_id = 2,
+ .pool_size = PAGE_SIZE,
+};
+
+/* The ids are fixed up later in iop13xx_platform_init */
+static struct platform_device iop13xx_adma_0_channel = {
+ .name = "iop-adma",
+ .id = 0,
+ .num_resources = 4,
+ .resource = iop13xx_adma_0_resources,
+ .dev = {
+ .dma_mask = &iop13xx_adma_dmamask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ .platform_data = (void *) &iop13xx_adma_0_data,
+ },
+};
+
+static struct platform_device iop13xx_adma_1_channel = {
+ .name = "iop-adma",
+ .id = 0,
+ .num_resources = 4,
+ .resource = iop13xx_adma_1_resources,
+ .dev = {
+ .dma_mask = &iop13xx_adma_dmamask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ .platform_data = (void *) &iop13xx_adma_1_data,
+ },
+};
+
+static struct platform_device iop13xx_adma_2_channel = {
+ .name = "iop-adma",
+ .id = 0,
+ .num_resources = 4,
+ .resource = iop13xx_adma_2_resources,
+ .dev = {
+ .dma_mask = &iop13xx_adma_dmamask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ .platform_data = (void *) &iop13xx_adma_2_data,
+ },
+};
+
void __init iop13xx_map_io(void)
{
/* Initialize the Static Page Table maps */
iotable_init(iop13xx_std_desc, ARRAY_SIZE(iop13xx_std_desc));
}
-static int init_uart = 0;
-static int init_i2c = 0;
+static int init_uart;
+static int init_i2c;
+static int init_adma;
void __init iop13xx_platform_init(void)
{
int i;
- u32 uart_idx, i2c_idx, plat_idx;
+ u32 uart_idx, i2c_idx, adma_idx, plat_idx;
struct platform_device *iop13xx_devices[IQ81340_MAX_PLAT_DEVICES];
/* set the bases so we can read the device id */
@@ -294,6 +419,12 @@ void __init iop13xx_platform_init(void)
}
}
+ if (init_adma == IOP13XX_INIT_ADMA_DEFAULT) {
+ init_adma |= IOP13XX_INIT_ADMA_0;
+ init_adma |= IOP13XX_INIT_ADMA_1;
+ init_adma |= IOP13XX_INIT_ADMA_2;
+ }
+
plat_idx = 0;
uart_idx = 0;
i2c_idx = 0;
@@ -332,6 +463,56 @@ void __init iop13xx_platform_init(void)
}
}
+ /* initialize adma channel ids and capabilities */
+ adma_idx = 0;
+ for (i = 0; i < IQ81340_NUM_ADMA; i++) {
+ struct iop_adma_platform_data *plat_data;
+ if ((init_adma & (1 << i)) && IOP13XX_SETUP_DEBUG)
+ printk(KERN_INFO
+ "Adding adma%d to platform device list\n", i);
+ switch (init_adma & (1 << i)) {
+ case IOP13XX_INIT_ADMA_0:
+ iop13xx_adma_0_channel.id = adma_idx++;
+ iop13xx_devices[plat_idx++] = &iop13xx_adma_0_channel;
+ plat_data = &iop13xx_adma_0_data;
+ dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
+ dma_cap_set(DMA_XOR, plat_data->cap_mask);
+ dma_cap_set(DMA_DUAL_XOR, plat_data->cap_mask);
+ dma_cap_set(DMA_ZERO_SUM, plat_data->cap_mask);
+ dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
+ dma_cap_set(DMA_MEMCPY_CRC32C, plat_data->cap_mask);
+ dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
+ break;
+ case IOP13XX_INIT_ADMA_1:
+ iop13xx_adma_1_channel.id = adma_idx++;
+ iop13xx_devices[plat_idx++] = &iop13xx_adma_1_channel;
+ plat_data = &iop13xx_adma_1_data;
+ dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
+ dma_cap_set(DMA_XOR, plat_data->cap_mask);
+ dma_cap_set(DMA_DUAL_XOR, plat_data->cap_mask);
+ dma_cap_set(DMA_ZERO_SUM, plat_data->cap_mask);
+ dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
+ dma_cap_set(DMA_MEMCPY_CRC32C, plat_data->cap_mask);
+ dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
+ break;
+ case IOP13XX_INIT_ADMA_2:
+ iop13xx_adma_2_channel.id = adma_idx++;
+ iop13xx_devices[plat_idx++] = &iop13xx_adma_2_channel;
+ plat_data = &iop13xx_adma_2_data;
+ dma_cap_set(DMA_MEMCPY, plat_data->cap_mask);
+ dma_cap_set(DMA_XOR, plat_data->cap_mask);
+ dma_cap_set(DMA_DUAL_XOR, plat_data->cap_mask);
+ dma_cap_set(DMA_ZERO_SUM, plat_data->cap_mask);
+ dma_cap_set(DMA_MEMSET, plat_data->cap_mask);
+ dma_cap_set(DMA_MEMCPY_CRC32C, plat_data->cap_mask);
+ dma_cap_set(DMA_INTERRUPT, plat_data->cap_mask);
+ dma_cap_set(DMA_PQ_XOR, plat_data->cap_mask);
+ dma_cap_set(DMA_PQ_UPDATE, plat_data->cap_mask);
+ dma_cap_set(DMA_PQ_ZERO_SUM, plat_data->cap_mask);
+ break;
+ }
+ }
+
#ifdef CONFIG_MTD_PHYSMAP
iq8134x_flash_resource.end = iq8134x_flash_resource.start +
iq8134x_probe_flash_size() - 1;
@@ -399,5 +580,35 @@ static int __init iop13xx_init_i2c_setup(char *str)
return 1;
}
+static int __init iop13xx_init_adma_setup(char *str)
+{
+ if (str) {
+ while (*str != '\0') {
+ switch (*str) {
+ case '0':
+ init_adma |= IOP13XX_INIT_ADMA_0;
+ break;
+ case '1':
+ init_adma |= IOP13XX_INIT_ADMA_1;
+ break;
+ case '2':
+ init_adma |= IOP13XX_INIT_ADMA_2;
+ break;
+ case ',':
+ case '=':
+ break;
+ default:
+ PRINTK("\"iop13xx_init_adma\" malformed"
+ " at character: \'%c\'", *str);
+ *(str + 1) = '\0';
+ init_adma = IOP13XX_INIT_ADMA_DEFAULT;
+ }
+ str++;
+ }
+ }
+ return 1;
+}
+
+__setup("iop13xx_init_adma", iop13xx_init_adma_setup);
__setup("iop13xx_init_uart", iop13xx_init_uart_setup);
__setup("iop13xx_init_i2c", iop13xx_init_i2c_setup);
diff --git a/arch/arm/mach-iop13xx/tpmi.c b/arch/arm/mach-iop13xx/tpmi.c
index d3dc278213da..2476347ea62f 100644
--- a/arch/arm/mach-iop13xx/tpmi.c
+++ b/arch/arm/mach-iop13xx/tpmi.c
@@ -29,13 +29,15 @@
#define IOP13XX_TPMI_MMR(dev) IOP13XX_REG_ADDR32_PHYS(0x48000 + (dev << 12))
#define IOP13XX_TPMI_MEM(dev) IOP13XX_REG_ADDR32_PHYS(0x60000 + (dev << 13))
#define IOP13XX_TPMI_CTRL(dev) IOP13XX_REG_ADDR32_PHYS(0x50000 + (dev << 10))
+#define IOP13XX_TPMI_IOP_CTRL(dev) (IOP13XX_TPMI_CTRL(dev) + 0x2000)
#define IOP13XX_TPMI_MMR_SIZE (SZ_4K - 1)
#define IOP13XX_TPMI_MEM_SIZE (255)
#define IOP13XX_TPMI_MEM_CTRL (SZ_1K - 1)
#define IOP13XX_TPMI_RESOURCE_MMR 0
#define IOP13XX_TPMI_RESOURCE_MEM 1
#define IOP13XX_TPMI_RESOURCE_CTRL 2
-#define IOP13XX_TPMI_RESOURCE_IRQ 3
+#define IOP13XX_TPMI_RESOURCE_IOP_CTRL 3
+#define IOP13XX_TPMI_RESOURCE_IRQ 4
static struct resource iop13xx_tpmi_0_resources[] = {
[IOP13XX_TPMI_RESOURCE_MMR] = {
@@ -53,6 +55,11 @@ static struct resource iop13xx_tpmi_0_resources[] = {
.end = IOP13XX_TPMI_CTRL(0) + IOP13XX_TPMI_MEM_CTRL,
.flags = IORESOURCE_MEM,
},
+ [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = {
+ .start = IOP13XX_TPMI_IOP_CTRL(0),
+ .end = IOP13XX_TPMI_IOP_CTRL(0) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
[IOP13XX_TPMI_RESOURCE_IRQ] = {
.start = IRQ_IOP13XX_TPMI0_OUT,
.end = IRQ_IOP13XX_TPMI0_OUT,
@@ -76,6 +83,11 @@ static struct resource iop13xx_tpmi_1_resources[] = {
.end = IOP13XX_TPMI_CTRL(1) + IOP13XX_TPMI_MEM_CTRL,
.flags = IORESOURCE_MEM,
},
+ [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = {
+ .start = IOP13XX_TPMI_IOP_CTRL(1),
+ .end = IOP13XX_TPMI_IOP_CTRL(1) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
[IOP13XX_TPMI_RESOURCE_IRQ] = {
.start = IRQ_IOP13XX_TPMI1_OUT,
.end = IRQ_IOP13XX_TPMI1_OUT,
@@ -99,6 +111,11 @@ static struct resource iop13xx_tpmi_2_resources[] = {
.end = IOP13XX_TPMI_CTRL(2) + IOP13XX_TPMI_MEM_CTRL,
.flags = IORESOURCE_MEM,
},
+ [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = {
+ .start = IOP13XX_TPMI_IOP_CTRL(2),
+ .end = IOP13XX_TPMI_IOP_CTRL(2) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
[IOP13XX_TPMI_RESOURCE_IRQ] = {
.start = IRQ_IOP13XX_TPMI2_OUT,
.end = IRQ_IOP13XX_TPMI2_OUT,
@@ -122,6 +139,11 @@ static struct resource iop13xx_tpmi_3_resources[] = {
.end = IOP13XX_TPMI_CTRL(3) + IOP13XX_TPMI_MEM_CTRL,
.flags = IORESOURCE_MEM,
},
+ [IOP13XX_TPMI_RESOURCE_IOP_CTRL] = {
+ .start = IOP13XX_TPMI_IOP_CTRL(3),
+ .end = IOP13XX_TPMI_IOP_CTRL(3) + IOP13XX_TPMI_MEM_CTRL,
+ .flags = IORESOURCE_MEM,
+ },
[IOP13XX_TPMI_RESOURCE_IRQ] = {
.start = IRQ_IOP13XX_TPMI3_OUT,
.end = IRQ_IOP13XX_TPMI3_OUT,
@@ -133,7 +155,7 @@ u64 iop13xx_tpmi_mask = DMA_64BIT_MASK;
static struct platform_device iop13xx_tpmi_0_device = {
.name = "iop-tpmi",
.id = 0,
- .num_resources = 4,
+ .num_resources = ARRAY_SIZE(iop13xx_tpmi_0_resources),
.resource = iop13xx_tpmi_0_resources,
.dev = {
.dma_mask = &iop13xx_tpmi_mask,
@@ -144,7 +166,7 @@ static struct platform_device iop13xx_tpmi_0_device = {
static struct platform_device iop13xx_tpmi_1_device = {
.name = "iop-tpmi",
.id = 1,
- .num_resources = 4,
+ .num_resources = ARRAY_SIZE(iop13xx_tpmi_1_resources),
.resource = iop13xx_tpmi_1_resources,
.dev = {
.dma_mask = &iop13xx_tpmi_mask,
@@ -155,7 +177,7 @@ static struct platform_device iop13xx_tpmi_1_device = {
static struct platform_device iop13xx_tpmi_2_device = {
.name = "iop-tpmi",
.id = 2,
- .num_resources = 4,
+ .num_resources = ARRAY_SIZE(iop13xx_tpmi_2_resources),
.resource = iop13xx_tpmi_2_resources,
.dev = {
.dma_mask = &iop13xx_tpmi_mask,
@@ -166,7 +188,7 @@ static struct platform_device iop13xx_tpmi_2_device = {
static struct platform_device iop13xx_tpmi_3_device = {
.name = "iop-tpmi",
.id = 3,
- .num_resources = 4,
+ .num_resources = ARRAY_SIZE(iop13xx_tpmi_3_resources),
.resource = iop13xx_tpmi_3_resources,
.dev = {
.dma_mask = &iop13xx_tpmi_mask,
diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig
index 9bb02b6d7ae1..dbe07c9472ed 100644
--- a/arch/arm/mach-iop32x/Kconfig
+++ b/arch/arm/mach-iop32x/Kconfig
@@ -42,6 +42,13 @@ config IOP3XX_ATU
Say N if the IOP is an add in card, the host system owns the PCI
bus in this case.
+config MACH_EM7210
+ bool "Enable support for the Lanner EM7210"
+ help
+ Say Y here if you want to run your kernel on the Lanner EM7210
+ board. Say also Y here if you have a SS4000e Baxter Creek NAS
+ appliance."
+
endmenu
endif
diff --git a/arch/arm/mach-iop32x/Makefile b/arch/arm/mach-iop32x/Makefile
index 7b05b37e1f94..cfdf8a137c2b 100644
--- a/arch/arm/mach-iop32x/Makefile
+++ b/arch/arm/mach-iop32x/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_MACH_GLANTANK) += glantank.o
obj-$(CONFIG_ARCH_IQ80321) += iq80321.o
obj-$(CONFIG_ARCH_IQ31244) += iq31244.o
obj-$(CONFIG_MACH_N2100) += n2100.o
+obj-$(CONFIG_MACH_EM7210) += em7210.o
diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
new file mode 100644
index 000000000000..c947152f9a3c
--- /dev/null
+++ b/arch/arm/mach-iop32x/em7210.c
@@ -0,0 +1,215 @@
+/*
+ * arch/arm/mach-iop32x/em7210.c
+ *
+ * Board support code for the Lanner EM7210 platforms.
+ *
+ * Based on arch/arm/mach-iop32x/iq31244.c file.
+ *
+ * Copyright (C) 2007 Arnaud Patard <arnaud.patard@rtp-net.org>
+ *
+ * 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/mm.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <asm/hardware.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/arch/time.h>
+
+static void __init em7210_timer_init(void)
+{
+ /* http://www.kwaak.net/fotos/fotos-nas/slide_24.html */
+ /* 33.333 MHz crystal. */
+ iop_init_time(200000000);
+}
+
+static struct sys_timer em7210_timer = {
+ .init = em7210_timer_init,
+ .offset = iop_gettimeoffset,
+};
+
+/*
+ * EM7210 RTC
+ */
+static struct i2c_board_info __initdata em7210_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("rtc-rs5c372", 0x32),
+ .type = "rs5c372a",
+ },
+};
+
+/*
+ * EM7210 I/O
+ */
+static struct map_desc em7210_io_desc[] __initdata = {
+ { /* on-board devices */
+ .virtual = IQ31244_UART,
+ .pfn = __phys_to_pfn(IQ31244_UART),
+ .length = 0x00100000,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init em7210_map_io(void)
+{
+ iop3xx_map_io();
+ iotable_init(em7210_io_desc, ARRAY_SIZE(em7210_io_desc));
+}
+
+
+/*
+ * EM7210 PCI
+ */
+#define INTA IRQ_IOP32X_XINT0
+#define INTB IRQ_IOP32X_XINT1
+#define INTC IRQ_IOP32X_XINT2
+#define INTD IRQ_IOP32X_XINT3
+
+static int __init
+em7210_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ static int pci_irq_table[][4] = {
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {INTB, INTB, INTB, INTB}, /* console / uart */
+ {INTA, INTA, INTA, INTA}, /* 1st 82541 */
+ {INTD, INTD, INTD, INTD}, /* 2nd 82541 */
+ {INTC, INTC, INTC, INTC}, /* GD31244 */
+ {INTD, INTA, INTA, INTA}, /* mini-PCI */
+ {INTD, INTC, INTA, INTA}, /* NEC USB */
+ };
+
+ if (pin < 1 || pin > 4)
+ return -1;
+
+ return pci_irq_table[slot % 6][pin - 1];
+}
+
+static struct hw_pci em7210_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = em7210_pci_map_irq,
+};
+
+static int __init em7210_pci_init(void)
+{
+ if (machine_is_em7210())
+ pci_common_init(&em7210_pci);
+
+ return 0;
+}
+
+subsys_initcall(em7210_pci_init);
+
+
+/*
+ * EM7210 Flash
+ */
+static struct physmap_flash_data em7210_flash_data = {
+ .width = 2,
+};
+
+static struct resource em7210_flash_resource = {
+ .start = 0xf0000000,
+ .end = 0xf1ffffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device em7210_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &em7210_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &em7210_flash_resource,
+};
+
+
+/*
+ * EM7210 UART
+ * The physical address of the serial port is 0xfe800000,
+ * so it can be used for physical and virtual address.
+ */
+static struct plat_serial8250_port em7210_serial_port[] = {
+ {
+ .mapbase = IQ31244_UART,
+ .membase = (char *)IQ31244_UART,
+ .irq = IRQ_IOP32X_XINT1,
+ .flags = UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = 1843200,
+ },
+ { },
+};
+
+static struct resource em7210_uart_resource = {
+ .start = IQ31244_UART,
+ .end = IQ31244_UART + 7,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device em7210_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = em7210_serial_port,
+ },
+ .num_resources = 1,
+ .resource = &em7210_uart_resource,
+};
+
+void em7210_power_off(void)
+{
+ *IOP3XX_GPOE &= 0xfe;
+ *IOP3XX_GPOD |= 0x01;
+}
+
+static void __init em7210_init_machine(void)
+{
+ platform_device_register(&em7210_serial_device);
+ platform_device_register(&iop3xx_i2c0_device);
+ platform_device_register(&iop3xx_i2c1_device);
+ platform_device_register(&em7210_flash_device);
+ platform_device_register(&iop3xx_dma_0_channel);
+ platform_device_register(&iop3xx_dma_1_channel);
+
+ i2c_register_board_info(0, em7210_i2c_devices,
+ ARRAY_SIZE(em7210_i2c_devices));
+
+
+ pm_power_off = em7210_power_off;
+}
+
+MACHINE_START(EM7210, "Lanner EM7210")
+ .phys_io = IQ31244_UART,
+ .io_pg_offst = ((IQ31244_UART) >> 18) & 0xfffc,
+ .boot_params = 0xa0000100,
+ .map_io = em7210_map_io,
+ .init_irq = iop32x_init_irq,
+ .timer = &em7210_timer,
+ .init_machine = em7210_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
index 5776fd884115..2b086ab2668c 100644
--- a/arch/arm/mach-iop32x/glantank.c
+++ b/arch/arm/mach-iop32x/glantank.c
@@ -180,6 +180,8 @@ static void __init glantank_init_machine(void)
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&glantank_flash_device);
platform_device_register(&glantank_serial_device);
+ platform_device_register(&iop3xx_dma_0_channel);
+ platform_device_register(&iop3xx_dma_1_channel);
pm_power_off = glantank_power_off;
}
diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
index d4eefbea1fe6..98cfa1cd6bdb 100644
--- a/arch/arm/mach-iop32x/iq31244.c
+++ b/arch/arm/mach-iop32x/iq31244.c
@@ -298,9 +298,14 @@ static void __init iq31244_init_machine(void)
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq31244_flash_device);
platform_device_register(&iq31244_serial_device);
+ platform_device_register(&iop3xx_dma_0_channel);
+ platform_device_register(&iop3xx_dma_1_channel);
if (is_ep80219())
pm_power_off = ep80219_power_off;
+
+ if (!is_80219())
+ platform_device_register(&iop3xx_aau_channel);
}
static int __init force_ep80219_setup(char *str)
diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
index 8d9f49164a84..18ad29f213b2 100644
--- a/arch/arm/mach-iop32x/iq80321.c
+++ b/arch/arm/mach-iop32x/iq80321.c
@@ -181,6 +181,9 @@ static void __init iq80321_init_machine(void)
platform_device_register(&iop3xx_i2c1_device);
platform_device_register(&iq80321_flash_device);
platform_device_register(&iq80321_serial_device);
+ platform_device_register(&iop3xx_dma_0_channel);
+ platform_device_register(&iop3xx_dma_1_channel);
+ platform_device_register(&iop3xx_aau_channel);
}
MACHINE_START(IQ80321, "Intel IQ80321")
diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c
index c971171c2905..55cf0162e8c1 100644
--- a/arch/arm/mach-iop32x/irq.c
+++ b/arch/arm/mach-iop32x/irq.c
@@ -63,7 +63,8 @@ void __init iop32x_init_irq(void)
if (machine_is_glantank() ||
machine_is_iq80321() ||
machine_is_iq31244() ||
- machine_is_n2100())
+ machine_is_n2100() ||
+ machine_is_em7210())
*IOP3XX_PCIIRSR = 0x0f;
for (i = 0; i < NR_IRQS; i++) {
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
index d55005d64781..1873bd8cd1b2 100644
--- a/arch/arm/mach-iop32x/n2100.c
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -25,6 +25,7 @@
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <linux/mtd/physmap.h>
+#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <asm/hardware.h>
@@ -199,6 +200,12 @@ static struct platform_device n2100_serial_device = {
.resource = &n2100_uart_resource,
};
+static struct i2c_board_info __initdata n2100_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("rtc-rs5c372", 0x32),
+ .type = "rs5c372b",
+ },
+};
/*
* Pull PCA9532 GPIO #8 low to power off the machine.
@@ -245,6 +252,11 @@ static void __init n2100_init_machine(void)
platform_device_register(&iop3xx_i2c0_device);
platform_device_register(&n2100_flash_device);
platform_device_register(&n2100_serial_device);
+ platform_device_register(&iop3xx_dma_0_channel);
+ platform_device_register(&iop3xx_dma_1_channel);
+
+ i2c_register_board_info(0, n2100_i2c_devices,
+ ARRAY_SIZE(n2100_i2c_devices));
pm_power_off = n2100_power_off;
diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c
index 2b063180687a..433188ebff2a 100644
--- a/arch/arm/mach-iop33x/iq80331.c
+++ b/arch/arm/mach-iop33x/iq80331.c
@@ -136,6 +136,9 @@ static void __init iq80331_init_machine(void)
platform_device_register(&iop33x_uart0_device);
platform_device_register(&iop33x_uart1_device);
platform_device_register(&iq80331_flash_device);
+ platform_device_register(&iop3xx_dma_0_channel);
+ platform_device_register(&iop3xx_dma_1_channel);
+ platform_device_register(&iop3xx_aau_channel);
}
MACHINE_START(IQ80331, "Intel IQ80331")
diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c
index 7889ce3cb08e..416c09564cc6 100644
--- a/arch/arm/mach-iop33x/iq80332.c
+++ b/arch/arm/mach-iop33x/iq80332.c
@@ -136,6 +136,9 @@ static void __init iq80332_init_machine(void)
platform_device_register(&iop33x_uart0_device);
platform_device_register(&iop33x_uart1_device);
platform_device_register(&iq80332_flash_device);
+ platform_device_register(&iop3xx_dma_0_channel);
+ platform_device_register(&iop3xx_dma_1_channel);
+ platform_device_register(&iop3xx_aau_channel);
}
MACHINE_START(IQ80332, "Intel IQ80332")
diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
index 060909870b50..61b2dfcb89d6 100644
--- a/arch/arm/mach-ixp4xx/Kconfig
+++ b/arch/arm/mach-ixp4xx/Kconfig
@@ -41,6 +41,22 @@ config ARCH_ADI_COYOTE
Engineering Coyote Gateway Reference Platform. For more
information on this platform, see <file:Documentation/arm/IXP4xx>.
+config MACH_GATEWAY7001
+ bool "Gateway 7001"
+ select PCI
+ help
+ Say 'Y' here if you want your kernel to support Gateway's
+ 7001 Access Point. For more information on this platform,
+ see http://openwrt.org
+
+config MACH_WG302V2
+ bool "Netgear WG302 v2 / WAG302 v2"
+ select PCI
+ help
+ Say 'Y' here if you want your kernel to support Netgear's
+ WG302 v2 or WAG302 v2 Access Points. For more information
+ on this platform, see http://openwrt.org
+
config ARCH_IXDP425
bool "IXDP425"
help
diff --git a/arch/arm/mach-ixp4xx/Makefile b/arch/arm/mach-ixp4xx/Makefile
index 3b87c47e06cf..77e00ade5585 100644
--- a/arch/arm/mach-ixp4xx/Makefile
+++ b/arch/arm/mach-ixp4xx/Makefile
@@ -13,6 +13,8 @@ obj-pci-$(CONFIG_MACH_GTWX5715) += gtwx5715-pci.o
obj-pci-$(CONFIG_MACH_NSLU2) += nslu2-pci.o
obj-pci-$(CONFIG_MACH_NAS100D) += nas100d-pci.o
obj-pci-$(CONFIG_MACH_DSMG600) += dsmg600-pci.o
+obj-pci-$(CONFIG_MACH_GATEWAY7001) += gateway7001-pci.o
+obj-pci-$(CONFIG_MACH_WG302V2) += wg302v2-pci.o
obj-y += common.o
@@ -24,5 +26,7 @@ obj-$(CONFIG_MACH_GTWX5715) += gtwx5715-setup.o
obj-$(CONFIG_MACH_NSLU2) += nslu2-setup.o nslu2-power.o
obj-$(CONFIG_MACH_NAS100D) += nas100d-setup.o nas100d-power.o
obj-$(CONFIG_MACH_DSMG600) += dsmg600-setup.o dsmg600-power.o
+obj-$(CONFIG_MACH_GATEWAY7001) += gateway7001-setup.o
+obj-$(CONFIG_MACH_WG302V2) += wg302v2-setup.o
obj-$(CONFIG_PCI) += $(obj-pci-$(CONFIG_PCI)) common-pci.o
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 8112f726ffa0..c1271c449246 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -188,7 +188,7 @@ static int ixp4xx_set_irq_type(unsigned int irq, unsigned int type)
*int_reg |= (int_style << (line * IXP4XX_GPIO_STYLE_SIZE));
/* Configure the line as an input */
- gpio_line_config(line, IXP4XX_GPIO_IN);
+ gpio_line_config(irq2gpio[irq], IXP4XX_GPIO_IN);
return 0;
}
@@ -459,6 +459,8 @@ static void ixp4xx_set_mode(enum clock_event_mode mode,
default:
osrt = opts = 0;
break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
}
*IXP4XX_OSRT1 = osrt | opts;
diff --git a/arch/arm/mach-ixp4xx/gateway7001-pci.c b/arch/arm/mach-ixp4xx/gateway7001-pci.c
new file mode 100644
index 000000000000..6abf568322d3
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/gateway7001-pci.c
@@ -0,0 +1,63 @@
+/*
+ * arch/arch/mach-ixp4xx/gateway7001-pci.c
+ *
+ * PCI setup routines for Gateway 7001
+ *
+ * Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * based on coyote-pci.c:
+ * Copyright (C) 2002 Jungo Software Technologies.
+ * Copyright (C) 2003 MontaVista Softwrae, Inc.
+ *
+ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/pci.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/pci.h>
+
+void __init gateway7001_pci_preinit(void)
+{
+ set_irq_type(IRQ_IXP4XX_GPIO10, IRQT_LOW);
+ set_irq_type(IRQ_IXP4XX_GPIO11, IRQT_LOW);
+
+ ixp4xx_pci_preinit();
+}
+
+static int __init gateway7001_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (slot == 1)
+ return IRQ_IXP4XX_GPIO11;
+ else if (slot == 2)
+ return IRQ_IXP4XX_GPIO10;
+ else return -1;
+}
+
+struct hw_pci gateway7001_pci __initdata = {
+ .nr_controllers = 1,
+ .preinit = gateway7001_pci_preinit,
+ .swizzle = pci_std_swizzle,
+ .setup = ixp4xx_setup,
+ .scan = ixp4xx_scan_bus,
+ .map_irq = gateway7001_map_irq,
+};
+
+int __init gateway7001_pci_init(void)
+{
+ if (machine_is_gateway7001())
+ pci_common_init(&gateway7001_pci);
+ return 0;
+}
+
+subsys_initcall(gateway7001_pci_init);
diff --git a/arch/arm/mach-ixp4xx/gateway7001-setup.c b/arch/arm/mach-ixp4xx/gateway7001-setup.c
new file mode 100644
index 000000000000..37876832e141
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/gateway7001-setup.c
@@ -0,0 +1,108 @@
+/*
+ * arch/arm/mach-ixp4xx/gateway7001-setup.c
+ *
+ * Board setup for the Gateway 7001 board
+ *
+ * Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * based on coyote-setup.c:
+ * Copyright (C) 2003-2005 MontaVista Software, Inc.
+ *
+ * Author: Imre Kaloz <Kaloz@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/slab.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+static struct flash_platform_data gateway7001_flash_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+};
+
+static struct resource gateway7001_flash_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device gateway7001_flash = {
+ .name = "IXP4XX-Flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &gateway7001_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &gateway7001_flash_resource,
+};
+
+static struct resource gateway7001_uart_resource = {
+ .start = IXP4XX_UART2_BASE_PHYS,
+ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct plat_serial8250_port gateway7001_uart_data[] = {
+ {
+ .mapbase = IXP4XX_UART2_BASE_PHYS,
+ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+ .irq = IRQ_IXP4XX_UART2,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = IXP4XX_UART_XTAL,
+ },
+ { },
+};
+
+static struct platform_device gateway7001_uart = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = gateway7001_uart_data,
+ },
+ .num_resources = 1,
+ .resource = &gateway7001_uart_resource,
+};
+
+static struct platform_device *gateway7001_devices[] __initdata = {
+ &gateway7001_flash,
+ &gateway7001_uart
+};
+
+static void __init gateway7001_init(void)
+{
+ ixp4xx_sys_init();
+
+ gateway7001_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+ gateway7001_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
+
+ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
+ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
+
+ platform_add_devices(gateway7001_devices, ARRAY_SIZE(gateway7001_devices));
+}
+
+#ifdef CONFIG_MACH_GATEWAY7001
+MACHINE_START(GATEWAY7001, "Gateway 7001 AP")
+ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = ixp4xx_map_io,
+ .init_irq = ixp4xx_init_irq,
+ .timer = &ixp4xx_timer,
+ .boot_params = 0x0100,
+ .init_machine = gateway7001_init,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-pci.c b/arch/arm/mach-ixp4xx/gtwx5715-pci.c
index a66484b63d36..0d5a42455820 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-pci.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-pci.c
@@ -25,17 +25,13 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/irq.h>
+
#include <asm/mach-types.h>
#include <asm/hardware.h>
-#include <asm/irq.h>
#include <asm/arch/gtwx5715.h>
#include <asm/mach/pci.h>
-extern void ixp4xx_pci_preinit(void);
-extern int ixp4xx_setup(int nr, struct pci_sys_data *sys);
-extern struct pci_bus *ixp4xx_scan_bus(int nr, struct pci_sys_data *sys);
-
-
/*
* The exact GPIO pins and IRQs are defined in arch-ixp4xx/gtwx5715.h
* Slot 0 isn't actually populated with a card connector but
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index ec4f07950ec6..d5008d8fc9a5 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -15,6 +15,10 @@
#include <linux/tty.h>
#include <linux/serial_8250.h>
#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
#include <asm/types.h>
#include <asm/setup.h>
@@ -24,6 +28,7 @@
#include <asm/irq.h>
#include <asm/mach/arch.h>
#include <asm/mach/flash.h>
+#include <asm/delay.h>
static struct flash_platform_data ixdp425_flash_data = {
.map_name = "cfi_probe",
@@ -44,6 +49,77 @@ static struct platform_device ixdp425_flash = {
.resource = &ixdp425_flash_resource,
};
+#if defined(CONFIG_MTD_NAND_PLATFORM) || \
+ defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
+
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+
+static struct mtd_partition ixdp425_partitions[] = {
+ {
+ .name = "ixp400 NAND FS 0",
+ .offset = 0,
+ .size = SZ_8M
+ }, {
+ .name = "ixp400 NAND FS 1",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL
+ },
+};
+#endif
+
+static void
+ixdp425_flash_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ int offset = (int)this->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_NCE) {
+ gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_LOW);
+ udelay(5);
+ } else
+ gpio_line_set(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_HIGH);
+
+ offset = (ctrl & NAND_CLE) ? IXDP425_NAND_CMD_BYTE : 0;
+ offset |= (ctrl & NAND_ALE) ? IXDP425_NAND_ADDR_BYTE : 0;
+ this->priv = (void *)offset;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, this->IO_ADDR_W + offset);
+}
+
+static struct platform_nand_data ixdp425_flash_nand_data = {
+ .chip = {
+ .chip_delay = 30,
+ .options = NAND_NO_AUTOINCR,
+#ifdef CONFIG_MTD_PARTITIONS
+ .part_probe_types = part_probes,
+ .partitions = ixdp425_partitions,
+ .nr_partitions = ARRAY_SIZE(ixdp425_partitions),
+#endif
+ },
+ .ctrl = {
+ .cmd_ctrl = ixdp425_flash_nand_cmd_ctrl
+ }
+};
+
+static struct resource ixdp425_flash_nand_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ixdp425_flash_nand = {
+ .name = "gen_nand",
+ .id = -1,
+ .dev = {
+ .platform_data = &ixdp425_flash_nand_data,
+ },
+ .num_resources = 1,
+ .resource = &ixdp425_flash_nand_resource,
+};
+#endif /* CONFIG_MTD_NAND_PLATFORM */
+
static struct ixp4xx_i2c_pins ixdp425_i2c_gpio_pins = {
.sda_pin = IXDP425_SDA_PIN,
.scl_pin = IXDP425_SCL_PIN,
@@ -104,6 +180,10 @@ static struct platform_device ixdp425_uart = {
static struct platform_device *ixdp425_devices[] __initdata = {
&ixdp425_i2c_controller,
&ixdp425_flash,
+#if defined(CONFIG_MTD_NAND_PLATFORM) || \
+ defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
+ &ixdp425_flash_nand,
+#endif
&ixdp425_uart
};
@@ -115,6 +195,22 @@ static void __init ixdp425_init(void)
ixdp425_flash_resource.end =
IXP4XX_EXP_BUS_BASE(0) + ixp4xx_exp_bus_size - 1;
+#if defined(CONFIG_MTD_NAND_PLATFORM) || \
+ defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
+ ixdp425_flash_nand_resource.start = IXP4XX_EXP_BUS_BASE(3),
+ ixdp425_flash_nand_resource.end = IXP4XX_EXP_BUS_BASE(3) + 0x10 - 1;
+
+ gpio_line_config(IXDP425_NAND_NCE_PIN, IXP4XX_GPIO_OUT);
+
+ /* Configure expansion bus for NAND Flash */
+ *IXP4XX_EXP_CS3 = IXP4XX_EXP_BUS_CS_EN |
+ IXP4XX_EXP_BUS_STROBE_T(1) | /* extend by 1 clock */
+ IXP4XX_EXP_BUS_CYCLES(0) | /* Intel cycles */
+ IXP4XX_EXP_BUS_SIZE(0) | /* 512bytes addr space*/
+ IXP4XX_EXP_BUS_WR_EN |
+ IXP4XX_EXP_BUS_BYTE_EN; /* 8 bit data bus */
+#endif
+
if (cpu_is_ixp43x()) {
ixdp425_uart.num_resources = 1;
ixdp425_uart_data[1].flags = 0;
diff --git a/arch/arm/mach-ixp4xx/wg302v2-pci.c b/arch/arm/mach-ixp4xx/wg302v2-pci.c
new file mode 100644
index 000000000000..6588f2c758e2
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/wg302v2-pci.c
@@ -0,0 +1,63 @@
+/*
+ * arch/arch/mach-ixp4xx/wg302v2-pci.c
+ *
+ * PCI setup routines for the Netgear WG302 v2 and WAG302 v2
+ *
+ * Copyright (C) 2007 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * based on coyote-pci.c:
+ * Copyright (C) 2002 Jungo Software Technologies.
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ *
+ * Maintainer: Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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/pci.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+#include <asm/mach/pci.h>
+
+void __init wg302v2_pci_preinit(void)
+{
+ set_irq_type(IRQ_IXP4XX_GPIO8, IRQT_LOW);
+ set_irq_type(IRQ_IXP4XX_GPIO9, IRQT_LOW);
+
+ ixp4xx_pci_preinit();
+}
+
+static int __init wg302v2_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (slot == 1)
+ return IRQ_IXP4XX_GPIO8;
+ else if (slot == 2)
+ return IRQ_IXP4XX_GPIO9;
+ else return -1;
+}
+
+struct hw_pci wg302v2_pci __initdata = {
+ .nr_controllers = 1,
+ .preinit = wg302v2_pci_preinit,
+ .swizzle = pci_std_swizzle,
+ .setup = ixp4xx_setup,
+ .scan = ixp4xx_scan_bus,
+ .map_irq = wg302v2_map_irq,
+};
+
+int __init wg302v2_pci_init(void)
+{
+ if (machine_is_wg302v2())
+ pci_common_init(&wg302v2_pci);
+ return 0;
+}
+
+subsys_initcall(wg302v2_pci_init);
diff --git a/arch/arm/mach-ixp4xx/wg302v2-setup.c b/arch/arm/mach-ixp4xx/wg302v2-setup.c
new file mode 100644
index 000000000000..f7e09ad804e8
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/wg302v2-setup.c
@@ -0,0 +1,109 @@
+/*
+ * arch/arm/mach-ixp4xx/wg302-setup.c
+ *
+ * Board setup for the Netgear WG302 v2 and WAG302 v2
+ *
+ * Copyright (C) 2007 Imre Kaloz <Kaloz@openwrt.org>
+ *
+ * based on coyote-setup.c:
+ * Copyright (C) 2003-2005 MontaVista Software, Inc.
+ *
+ * Author: Imre Kaloz <kaloz@openwrt.org>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/slab.h>
+
+#include <asm/types.h>
+#include <asm/setup.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/flash.h>
+
+static struct flash_platform_data wg302v2_flash_data = {
+ .map_name = "cfi_probe",
+ .width = 2,
+};
+
+static struct resource wg302v2_flash_resource = {
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device wg302v2_flash = {
+ .name = "IXP4XX-Flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &wg302v2_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &wg302v2_flash_resource,
+};
+
+static struct resource wg302v2_uart_resource = {
+ .start = IXP4XX_UART2_BASE_PHYS,
+ .end = IXP4XX_UART2_BASE_PHYS + 0x0fff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct plat_serial8250_port wg302v2_uart_data[] = {
+ {
+ .mapbase = IXP4XX_UART2_BASE_PHYS,
+ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+ .irq = IRQ_IXP4XX_UART2,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = IXP4XX_UART_XTAL,
+ },
+ { },
+};
+
+static struct platform_device wg302v2_uart = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = wg302v2_uart_data,
+ },
+ .num_resources = 1,
+ .resource = &wg302v2_uart_resource,
+};
+
+static struct platform_device *wg302v2_devices[] __initdata = {
+ &wg302v2_flash,
+ &wg302v2_uart,
+};
+
+static void __init wg302v2_init(void)
+{
+ ixp4xx_sys_init();
+
+ wg302v2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
+ wg302v2_flash_resource.end = IXP4XX_EXP_BUS_BASE(0) + SZ_32M - 1;
+
+ *IXP4XX_EXP_CS0 |= IXP4XX_FLASH_WRITABLE;
+ *IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
+
+ platform_add_devices(wg302v2_devices, ARRAY_SIZE(wg302v2_devices));
+}
+
+#ifdef CONFIG_MACH_WG302V2
+MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2")
+ /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = ixp4xx_map_io,
+ .init_irq = ixp4xx_init_irq,
+ .timer = &ixp4xx_timer,
+ .boot_params = 0x0100,
+ .init_machine = wg302v2_init,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-ks8695/Makefile b/arch/arm/mach-ks8695/Makefile
index 56b7d337333a..2a07a281fa8a 100644
--- a/arch/arm/mach-ks8695/Makefile
+++ b/arch/arm/mach-ks8695/Makefile
@@ -3,7 +3,7 @@
# Makefile for KS8695 architecture support
#
-obj-y := cpu.o irq.o time.o devices.o
+obj-y := cpu.o irq.o time.o gpio.o devices.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/mach-ks8695/gpio.c b/arch/arm/mach-ks8695/gpio.c
new file mode 100644
index 000000000000..b1aa3cb3d4a3
--- /dev/null
+++ b/arch/arm/mach-ks8695/gpio.c
@@ -0,0 +1,218 @@
+/*
+ * arch/arm/mach-ks8695/gpio.c
+ *
+ * Copyright (C) 2006 Andrew Victor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/gpio.h>
+
+/*
+ * Configure a GPIO line for either GPIO function, or its internal
+ * function (Interrupt, Timer, etc).
+ */
+static void __init_or_module ks8695_gpio_mode(unsigned int pin, short gpio)
+{
+ unsigned int enable[] = { IOPC_IOEINT0EN, IOPC_IOEINT1EN, IOPC_IOEINT2EN, IOPC_IOEINT3EN, IOPC_IOTIM0EN, IOPC_IOTIM1EN };
+ unsigned long x, flags;
+
+ if (pin > KS8695_GPIO_5) /* only GPIO 0..5 have internal functions */
+ return;
+
+ local_irq_save(flags);
+
+ x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPC);
+ if (gpio) /* GPIO: set bit to 0 */
+ x &= ~enable[pin];
+ else /* Internal function: set bit to 1 */
+ x |= enable[pin];
+ __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPC);
+
+ local_irq_restore(flags);
+}
+
+
+static unsigned short gpio_irq[] = { KS8695_IRQ_EXTERN0, KS8695_IRQ_EXTERN1, KS8695_IRQ_EXTERN2, KS8695_IRQ_EXTERN3 };
+
+/*
+ * Configure GPIO pin as external interrupt source.
+ */
+int __init_or_module ks8695_gpio_interrupt(unsigned int pin, unsigned int type)
+{
+ unsigned long x, flags;
+
+ if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ /* set pin as input */
+ x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
+ x &= ~IOPM_(pin);
+ __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
+
+ local_irq_restore(flags);
+
+ /* Set IRQ triggering type */
+ set_irq_type(gpio_irq[pin], type);
+
+ /* enable interrupt mode */
+ ks8695_gpio_mode(pin, 0);
+
+ return 0;
+}
+EXPORT_SYMBOL(ks8695_gpio_interrupt);
+
+
+
+/* .... Generic GPIO interface .............................................. */
+
+/*
+ * Configure the GPIO line as an input.
+ */
+int __init_or_module gpio_direction_input(unsigned int pin)
+{
+ unsigned long x, flags;
+
+ if (pin > KS8695_GPIO_15)
+ return -EINVAL;
+
+ /* set pin to GPIO mode */
+ ks8695_gpio_mode(pin, 1);
+
+ local_irq_save(flags);
+
+ /* set pin as input */
+ x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
+ x &= ~IOPM_(pin);
+ __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+
+/*
+ * Configure the GPIO line as an output, with default state.
+ */
+int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state)
+{
+ unsigned long x, flags;
+
+ if (pin > KS8695_GPIO_15)
+ return -EINVAL;
+
+ /* set pin to GPIO mode */
+ ks8695_gpio_mode(pin, 1);
+
+ local_irq_save(flags);
+
+ /* set line state */
+ x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
+ if (state)
+ x |= (1 << pin);
+ else
+ x &= ~(1 << pin);
+ __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
+
+ /* set pin as output */
+ x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPM);
+ x |= IOPM_(pin);
+ __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPM);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+
+/*
+ * Set the state of an output GPIO line.
+ */
+void gpio_set_value(unsigned int pin, unsigned int state)
+{
+ unsigned long x, flags;
+
+ if (pin > KS8695_GPIO_15)
+ return;
+
+ local_irq_save(flags);
+
+ /* set output line state */
+ x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
+ if (state)
+ x |= (1 << pin);
+ else
+ x &= ~(1 << pin);
+ __raw_writel(x, KS8695_GPIO_VA + KS8695_IOPD);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+
+/*
+ * Read the state of a GPIO line.
+ */
+int gpio_get_value(unsigned int pin)
+{
+ unsigned long x;
+
+ if (pin > KS8695_GPIO_15)
+ return -EINVAL;
+
+ x = __raw_readl(KS8695_GPIO_VA + KS8695_IOPD);
+ return (x & (1 << pin)) != 0;
+}
+EXPORT_SYMBOL(gpio_get_value);
+
+
+/*
+ * Map GPIO line to IRQ number.
+ */
+int gpio_to_irq(unsigned int pin)
+{
+ if (pin > KS8695_GPIO_3) /* only GPIO 0..3 can generate IRQ */
+ return -EINVAL;
+
+ return gpio_irq[pin];
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+
+/*
+ * Map IRQ number to GPIO line.
+ */
+int irq_to_gpio(unsigned int irq)
+{
+ if ((irq < KS8695_IRQ_EXTERN0) || (irq > KS8695_IRQ_EXTERN3))
+ return -EINVAL;
+
+ return (irq - KS8695_IRQ_EXTERN0);
+}
+EXPORT_SYMBOL(irq_to_gpio);
diff --git a/arch/arm/mach-ks8695/irq.c b/arch/arm/mach-ks8695/irq.c
index 2407bba00547..4c3ab43e1046 100644
--- a/arch/arm/mach-ks8695/irq.c
+++ b/arch/arm/mach-ks8695/irq.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/ptrace.h>
#include <linux/sysdev.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
new file mode 100644
index 000000000000..5fe8606cac08
--- /dev/null
+++ b/arch/arm/mach-mx3/Kconfig
@@ -0,0 +1,12 @@
+menu "MX3 Options"
+ depends on ARCH_MX3
+
+config MACH_MX31ADS
+ bool "Support MX31ADS platforms"
+ default y
+ help
+ Include support for MX31ADS platform. This includes specific
+ configurations for the board and its peripherals.
+
+endmenu
+
diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile
new file mode 100644
index 000000000000..cbec997f332a
--- /dev/null
+++ b/arch/arm/mach-mx3/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Object file lists.
+
+obj-y := mm.o time.o
+obj-$(CONFIG_MACH_MX31ADS) += mx31ads.o
diff --git a/arch/arm/mach-mx3/Makefile.boot b/arch/arm/mach-mx3/Makefile.boot
new file mode 100644
index 000000000000..e1dd366f836b
--- /dev/null
+++ b/arch/arm/mach-mx3/Makefile.boot
@@ -0,0 +1,3 @@
+ zreladdr-y := 0x80008000
+params_phys-y := 0x80000100
+initrd_phys-y := 0x80800000
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
new file mode 100644
index 000000000000..41dad485ded9
--- /dev/null
+++ b/arch/arm/mach-mx3/mm.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 1999,2000 Arm Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * - add MX31 specific definitions
+ *
+ * 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/mm.h>
+#include <linux/init.h>
+#include <asm/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+#include <asm/arch/common.h>
+
+/*!
+ * @file mm.c
+ *
+ * @brief This file creates static virtual to physical mappings, common to all MX3 boards.
+ *
+ * @ingroup Memory
+ */
+
+/*!
+ * This table defines static virtual address mappings for I/O regions.
+ * These are the mappings common across all MX3 boards.
+ */
+static struct map_desc mxc_io_desc[] __initdata = {
+ {
+ .virtual = X_MEMC_BASE_ADDR_VIRT,
+ .pfn = __phys_to_pfn(X_MEMC_BASE_ADDR),
+ .length = X_MEMC_SIZE,
+ .type = MT_DEVICE
+ }, {
+ .virtual = AVIC_BASE_ADDR_VIRT,
+ .pfn = __phys_to_pfn(AVIC_BASE_ADDR),
+ .length = AVIC_SIZE,
+ .type = MT_NONSHARED_DEVICE
+ },
+};
+
+/*!
+ * This function initializes the memory map. It is called during the
+ * system startup to create static physical to virtual memory mappings
+ * for the IO modules.
+ */
+void __init mxc_map_io(void)
+{
+ iotable_init(mxc_io_desc, ARRAY_SIZE(mxc_io_desc));
+}
diff --git a/arch/arm/mach-mx3/mx31ads.c b/arch/arm/mach-mx3/mx31ads.c
new file mode 100644
index 000000000000..7e89bdc23a9f
--- /dev/null
+++ b/arch/arm/mach-mx3/mx31ads.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/serial_8250.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/memory.h>
+#include <asm/mach/map.h>
+#include <asm/arch/common.h>
+
+/*!
+ * @file mx31ads.c
+ *
+ * @brief This file contains the board-specific initialization routines.
+ *
+ * @ingroup System
+ */
+
+#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
+/*!
+ * The serial port definition structure.
+ */
+static struct plat_serial8250_port serial_platform_data[] = {
+ {
+ .membase = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTA),
+ .mapbase = (unsigned long)(CS4_BASE_ADDR + PBC_SC16C652_UARTA),
+ .irq = EXPIO_INT_XUART_INTA,
+ .uartclk = 14745600,
+ .regshift = 0,
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ,
+ }, {
+ .membase = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTB),
+ .mapbase = (unsigned long)(CS4_BASE_ADDR + PBC_SC16C652_UARTB),
+ .irq = EXPIO_INT_XUART_INTB,
+ .uartclk = 14745600,
+ .regshift = 0,
+ .iotype = UPIO_MEM,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ,
+ },
+ {},
+};
+
+static struct platform_device serial_device = {
+ .name = "serial8250",
+ .id = 0,
+ .dev = {
+ .platform_data = serial_platform_data,
+ },
+};
+
+static int __init mxc_init_extuart(void)
+{
+ return platform_device_register(&serial_device);
+}
+#else
+static inline int mxc_init_extuart(void)
+{
+ return 0;
+}
+#endif
+
+/*!
+ * This structure defines static mappings for the i.MX31ADS board.
+ */
+static struct map_desc mx31ads_io_desc[] __initdata = {
+ {
+ .virtual = AIPS1_BASE_ADDR_VIRT,
+ .pfn = __phys_to_pfn(AIPS1_BASE_ADDR),
+ .length = AIPS1_SIZE,
+ .type = MT_NONSHARED_DEVICE
+ }, {
+ .virtual = SPBA0_BASE_ADDR_VIRT,
+ .pfn = __phys_to_pfn(SPBA0_BASE_ADDR),
+ .length = SPBA0_SIZE,
+ .type = MT_NONSHARED_DEVICE
+ }, {
+ .virtual = AIPS2_BASE_ADDR_VIRT,
+ .pfn = __phys_to_pfn(AIPS2_BASE_ADDR),
+ .length = AIPS2_SIZE,
+ .type = MT_NONSHARED_DEVICE
+ }, {
+ .virtual = CS4_BASE_ADDR_VIRT,
+ .pfn = __phys_to_pfn(CS4_BASE_ADDR),
+ .length = CS4_SIZE / 2,
+ .type = MT_DEVICE
+ },
+};
+
+/*!
+ * Set up static virtual mappings.
+ */
+void __init mx31ads_map_io(void)
+{
+ mxc_map_io();
+ iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc));
+}
+
+/*!
+ * Board specific initialization.
+ */
+static void __init mxc_board_init(void)
+{
+ mxc_init_extuart();
+}
+
+/*
+ * The following uses standard kernel macros defined in arch.h in order to
+ * initialize __mach_desc_MX31ADS data structure.
+ */
+MACHINE_START(MX31ADS, "Freescale MX31ADS")
+ /* Maintainer: Freescale Semiconductor, Inc. */
+ .phys_io = AIPS1_BASE_ADDR,
+ .io_pg_offst = ((AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
+ .boot_params = PHYS_OFFSET + 0x100,
+ .map_io = mx31ads_map_io,
+ .init_irq = mxc_init_irq,
+ .init_machine = mxc_board_init,
+ .timer = &mxc_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mx3/time.c b/arch/arm/mach-mx3/time.c
new file mode 100644
index 000000000000..e81fb5c5d7c3
--- /dev/null
+++ b/arch/arm/mach-mx3/time.c
@@ -0,0 +1,152 @@
+/*
+ * System Timer Interrupt reconfigured to run in free-run mode.
+ * Author: Vitaly Wool
+ * Copyright 2004 MontaVista Software Inc.
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*!
+ * @file time.c
+ * @brief This file contains OS tick and wdog timer implementations.
+ *
+ * This file contains OS tick and wdog timer implementations.
+ *
+ * @ingroup Timers
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/hardware.h>
+#include <asm/mach/time.h>
+#include <asm/io.h>
+#include <asm/arch/common.h>
+
+/*!
+ * This is the timer interrupt service routine to do required tasks.
+ * It also services the WDOG timer at the frequency of twice per WDOG
+ * timeout value. For example, if the WDOG's timeout value is 4 (2
+ * seconds since the WDOG runs at 0.5Hz), it will be serviced once
+ * every 2/2=1 second.
+ *
+ * @param irq GPT interrupt source number (not used)
+ * @param dev_id this parameter is not used
+ * @return always returns \b IRQ_HANDLED as defined in
+ * include/linux/interrupt.h.
+ */
+static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
+{
+ unsigned int next_match;
+
+ write_seqlock(&xtime_lock);
+
+ if (__raw_readl(MXC_GPT_GPTSR) & GPTSR_OF1) {
+ do {
+ timer_tick();
+ next_match = __raw_readl(MXC_GPT_GPTOCR1) + LATCH;
+ __raw_writel(GPTSR_OF1, MXC_GPT_GPTSR);
+ __raw_writel(next_match, MXC_GPT_GPTOCR1);
+ } while ((signed long)(next_match -
+ __raw_readl(MXC_GPT_GPTCNT)) <= 0);
+ }
+
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * This function is used to obtain the number of microseconds since the last
+ * timer interrupt. Note that interrupts is disabled by do_gettimeofday().
+ *
+ * @return the number of microseconds since the last timer interrupt.
+ */
+static unsigned long mxc_gettimeoffset(void)
+{
+ unsigned long ticks_to_match, elapsed, usec, tick_usec, i;
+
+ /* Get ticks before next timer match */
+ ticks_to_match =
+ __raw_readl(MXC_GPT_GPTOCR1) - __raw_readl(MXC_GPT_GPTCNT);
+
+ /* We need elapsed ticks since last match */
+ elapsed = LATCH - ticks_to_match;
+
+ /* Now convert them to usec */
+ /* Insure no overflow when calculating the usec below */
+ for (i = 1, tick_usec = tick_nsec / 1000;; i *= 2) {
+ tick_usec /= i;
+ if ((0xFFFFFFFF / tick_usec) > elapsed)
+ break;
+ }
+ usec = (unsigned long)(elapsed * tick_usec) / (LATCH / i);
+
+ return usec;
+}
+
+/*!
+ * The OS tick timer interrupt structure.
+ */
+static struct irqaction timer_irq = {
+ .name = "MXC Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .handler = mxc_timer_interrupt
+};
+
+/*!
+ * This function is used to initialize the GPT to produce an interrupt
+ * based on HZ. It is called by start_kernel() during system startup.
+ */
+void __init mxc_init_time(void)
+{
+ u32 reg, v;
+ reg = __raw_readl(MXC_GPT_GPTCR);
+ reg &= ~GPTCR_ENABLE;
+ __raw_writel(reg, MXC_GPT_GPTCR);
+ reg |= GPTCR_SWR;
+ __raw_writel(reg, MXC_GPT_GPTCR);
+
+ while ((__raw_readl(MXC_GPT_GPTCR) & GPTCR_SWR) != 0)
+ cpu_relax();
+
+ reg = GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ;
+ __raw_writel(reg, MXC_GPT_GPTCR);
+
+ /* TODO: get timer rate from clk driver */
+ v = 66500000;
+
+ __raw_writel((v / CLOCK_TICK_RATE) - 1, MXC_GPT_GPTPR);
+
+ if ((v % CLOCK_TICK_RATE) != 0) {
+ pr_info("\nWARNING: Can't generate CLOCK_TICK_RATE at %d Hz\n",
+ CLOCK_TICK_RATE);
+ }
+ pr_info("Actual CLOCK_TICK_RATE is %d Hz\n",
+ v / ((__raw_readl(MXC_GPT_GPTPR) & 0xFFF) + 1));
+
+ reg = __raw_readl(MXC_GPT_GPTCNT);
+ reg += LATCH;
+ __raw_writel(reg, MXC_GPT_GPTOCR1);
+
+ setup_irq(MXC_INT_GPT, &timer_irq);
+
+ reg = __raw_readl(MXC_GPT_GPTCR);
+ reg =
+ GPTCR_FRR | GPTCR_CLKSRC_HIGHFREQ | GPTCR_STOPEN | GPTCR_DOZEN |
+ GPTCR_WAITEN | GPTCR_ENMOD | GPTCR_ENABLE;
+ __raw_writel(reg, MXC_GPT_GPTCR);
+
+ __raw_writel(GPTIR_OF1IE, MXC_GPT_GPTIR);
+}
+
+struct sys_timer mxc_timer = {
+ .init = mxc_init_time,
+ .offset = mxc_gettimeoffset,
+};
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile
index 53213a69f601..4476411b8140 100644
--- a/arch/arm/mach-ns9xxx/Makefile
+++ b/arch/arm/mach-ns9xxx/Makefile
@@ -1,6 +1,7 @@
obj-y := irq.o time.o generic.o
obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
+obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o
obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o
obj-$(CONFIG_BOARD_JSCC9P9360) += board-jscc9p9360.o
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
index 25289884a607..925048e7adfe 100644
--- a/arch/arm/mach-ns9xxx/board-a9m9750dev.c
+++ b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
@@ -77,7 +77,7 @@ static void a9m9750dev_fpga_demux_handler(unsigned int irq,
desc = irq_desc + FPGA_IRQ(irqno);
- desc_handle_irq(irqno, desc);
+ desc_handle_irq(FPGA_IRQ(irqno), desc);
}
}
@@ -91,7 +91,7 @@ void __init board_a9m9750dev_init_irq(void)
* use GPIO 11, because GPIO 32 is used for the LCD
*/
/* XXX: proper GPIO handling */
- BBU_GC(2) &= ~0x2000;
+ BBU_GCONFb1(1) &= ~0x2000;
for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) {
set_irq_chip(i, &a9m9750dev_fpga_chip);
@@ -178,7 +178,7 @@ void __init board_a9m9750dev_init_machine(void)
/* setup static CS0: memory configuration */
reg = MEM_SMC(0);
- REGSET(reg, MEM_SMC, WSMC, OFF);
+ REGSET(reg, MEM_SMC, PSMC, OFF);
REGSET(reg, MEM_SMC, BSMC, OFF);
REGSET(reg, MEM_SMC, EW, OFF);
REGSET(reg, MEM_SMC, PB, 1);
@@ -196,4 +196,3 @@ void __init board_a9m9750dev_init_machine(void)
platform_add_devices(board_a9m9750dev_devices,
ARRAY_SIZE(board_a9m9750dev_devices));
}
-
diff --git a/arch/arm/mach-ns9xxx/generic.c b/arch/arm/mach-ns9xxx/generic.c
index 83e2b6532b22..d742c921e34d 100644
--- a/arch/arm/mach-ns9xxx/generic.c
+++ b/arch/arm/mach-ns9xxx/generic.c
@@ -18,6 +18,8 @@
#include <asm/arch-ns9xxx/regs-mem.h>
#include <asm/arch-ns9xxx/board.h>
+#include "generic.h"
+
static struct map_desc standard_io_desc[] __initdata = {
{ /* BBus */
.virtual = io_p2v(0x90000000),
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c
index 83d92724a971..b8c7b00522e6 100644
--- a/arch/arm/mach-ns9xxx/irq.c
+++ b/arch/arm/mach-ns9xxx/irq.c
@@ -21,6 +21,15 @@ static void ns9xxx_ack_irq_timer(unsigned int irq)
{
u32 tc = SYS_TC(irq - IRQ_TIMER0);
+ /*
+ * If the timer is programmed to halt on terminal count, the
+ * timer must be disabled before clearing the interrupt.
+ */
+ if (REGGET(tc, SYS_TCx, REN) == 0) {
+ REGSET(tc, SYS_TCx, TEN, DIS);
+ SYS_TC(irq - IRQ_TIMER0) = tc;
+ }
+
REGSET(tc, SYS_TCx, INTC, SET);
SYS_TC(irq - IRQ_TIMER0) = tc;
@@ -28,7 +37,7 @@ static void ns9xxx_ack_irq_timer(unsigned int irq)
SYS_TC(irq - IRQ_TIMER0) = tc;
}
-void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = {
+static void (*ns9xxx_ack_irq_functions[NR_IRQS])(unsigned int) = {
[IRQ_TIMER0] = ns9xxx_ack_irq_timer,
[IRQ_TIMER1] = ns9xxx_ack_irq_timer,
[IRQ_TIMER2] = ns9xxx_ack_irq_timer,
diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
index d09d5fa5620a..85c8b41105c9 100644
--- a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
+++ b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
@@ -20,7 +20,7 @@ static void __init mach_cc9p9360js_init_machine(void)
board_jscc9p9360_init_machine();
}
-MACHINE_START(CC9P9360DEV, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard")
+MACHINE_START(CC9P9360JS, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard")
.map_io = ns9xxx_map_io,
.init_irq = ns9xxx_init_irq,
.init_machine = mach_cc9p9360js_init_machine,
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 3705d20c4e5c..237651ebae5d 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -156,6 +156,7 @@ static void omap_mpu_set_mode(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
break;
}
}
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 5c0a10041cd1..5ebec6d88b51 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -37,6 +37,10 @@ config MACH_TRIZEPS4
bool "Keith und Koep Trizeps4 DIMM-Module"
select PXA27x
+config MACH_EM_X270
+ bool "CompuLab EM-x270 platform"
+ select PXA27x
+
endchoice
if PXA_SHARPSL
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 9093eb1c94eb..7d6ab5c59ab9 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o sp
obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o
obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o
obj-$(CONFIG_MACH_TOSA) += tosa.o
+obj-$(CONFIG_MACH_EM_X270) += em-x270.o
# Support for blinky lights
led-y := leds.o
diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c
index 8f7c90a0593b..34a31caa6f9d 100644
--- a/arch/arm/mach-pxa/clock.c
+++ b/arch/arm/mach-pxa/clock.c
@@ -12,7 +12,6 @@
#include <asm/arch/pxa-regs.h>
#include <asm/hardware.h>
-#include <asm/semaphore.h>
struct clk {
struct list_head node;
@@ -25,21 +24,21 @@ struct clk {
};
static LIST_HEAD(clocks);
-static DECLARE_MUTEX(clocks_sem);
+static DEFINE_MUTEX(clocks_mutex);
static DEFINE_SPINLOCK(clocks_lock);
struct clk *clk_get(struct device *dev, const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
- down(&clocks_sem);
+ mutex_lock(&clocks_mutex);
list_for_each_entry(p, &clocks, node) {
if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
clk = p;
break;
}
}
- up(&clocks_sem);
+ mutex_unlock(&clocks_mutex);
return clk;
}
@@ -101,18 +100,18 @@ static struct clk clk_gpio27 = {
int clk_register(struct clk *clk)
{
- down(&clocks_sem);
+ mutex_lock(&clocks_mutex);
list_add(&clk->node, &clocks);
- up(&clocks_sem);
+ mutex_unlock(&clocks_mutex);
return 0;
}
EXPORT_SYMBOL(clk_register);
void clk_unregister(struct clk *clk)
{
- down(&clocks_sem);
+ mutex_lock(&clocks_mutex);
list_del(&clk->node);
- up(&clocks_sem);
+ mutex_unlock(&clocks_mutex);
}
EXPORT_SYMBOL(clk_unregister);
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index a1a900d16665..aab27297b3c6 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -44,6 +44,7 @@
#include <asm/hardware/scoop.h>
#include "generic.h"
+#include "devices.h"
#include "sharpsl.h"
@@ -368,7 +369,7 @@ MACHINE_START(CORGI, "SHARP Corgi")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_corgi,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa25x_init_irq,
.init_machine = corgi_init,
.timer = &pxa_timer,
MACHINE_END
@@ -380,7 +381,7 @@ MACHINE_START(SHEPHERD, "SHARP Shepherd")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_corgi,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa25x_init_irq,
.init_machine = corgi_init,
.timer = &pxa_timer,
MACHINE_END
@@ -392,7 +393,7 @@ MACHINE_START(HUSKY, "SHARP Husky")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_corgi,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa25x_init_irq,
.init_machine = corgi_init,
.timer = &pxa_timer,
MACHINE_END
diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
new file mode 100644
index 000000000000..636fdb1c049c
--- /dev/null
+++ b/arch/arm/mach-pxa/devices.h
@@ -0,0 +1,11 @@
+extern struct platform_device pxa_device_mci;
+extern struct platform_device pxa_device_udc;
+extern struct platform_device pxa_device_fb;
+extern struct platform_device pxa_device_ffuart;
+extern struct platform_device pxa_device_btuart;
+extern struct platform_device pxa_device_stuart;
+extern struct platform_device pxa_device_hwuart;
+extern struct platform_device pxa_device_i2c;
+extern struct platform_device pxa_device_i2s;
+extern struct platform_device pxa_device_ficp;
+extern struct platform_device pxa_device_rtc;
diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c
index 4440babe7b97..93c4f31f127f 100644
--- a/arch/arm/mach-pxa/dma.c
+++ b/arch/arm/mach-pxa/dma.c
@@ -25,12 +25,15 @@
#include <asm/arch/pxa-regs.h>
-static struct dma_channel {
+struct dma_channel {
char *name;
+ pxa_dma_prio prio;
void (*irq_handler)(int, void *);
void *data;
-} dma_channels[PXA_DMA_CHANNELS];
+};
+static struct dma_channel *dma_channels;
+static int num_dma_channels;
int pxa_request_dma (char *name, pxa_dma_prio prio,
void (*irq_handler)(int, void *),
@@ -47,8 +50,9 @@ int pxa_request_dma (char *name, pxa_dma_prio prio,
do {
/* try grabbing a DMA channel with the requested priority */
- pxa_for_each_dma_prio (i, prio) {
- if (!dma_channels[i].name) {
+ for (i = 0; i < num_dma_channels; i++) {
+ if ((dma_channels[i].prio == prio) &&
+ !dma_channels[i].name) {
found = 1;
break;
}
@@ -91,7 +95,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
int i, dint = DINT;
- for (i = 0; i < PXA_DMA_CHANNELS; i++) {
+ for (i = 0; i < num_dma_channels; i++) {
if (dint & (1 << i)) {
struct dma_channel *channel = &dma_channels[i];
if (channel->name && channel->irq_handler) {
@@ -109,18 +113,32 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int __init pxa_dma_init (void)
+int __init pxa_init_dma(int num_ch)
{
- int ret;
+ int i, ret;
- ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
- if (ret)
+ dma_channels = kzalloc(sizeof(struct dma_channel) * num_ch, GFP_KERNEL);
+ if (dma_channels == NULL)
+ return -ENOMEM;
+
+ ret = request_irq(IRQ_DMA, dma_irq_handler, IRQF_DISABLED, "DMA", NULL);
+ if (ret) {
printk (KERN_CRIT "Wow! Can't register IRQ for DMA\n");
- return ret;
-}
+ kfree(dma_channels);
+ return ret;
+ }
-arch_initcall(pxa_dma_init);
+ /* dma channel priorities on pxa2xx processors:
+ * ch 0 - 3, 16 - 19 <--> (0) DMA_PRIO_HIGH
+ * ch 4 - 7, 20 - 23 <--> (1) DMA_PRIO_MEDIUM
+ * ch 8 - 15, 24 - 31 <--> (2) DMA_PRIO_LOW
+ */
+ for (i = 0; i < num_ch; i++)
+ dma_channels[i].prio = min((i & 0xf) >> 2, DMA_PRIO_LOW);
+
+ num_dma_channels = num_ch;
+ return 0;
+}
EXPORT_SYMBOL(pxa_request_dma);
EXPORT_SYMBOL(pxa_free_dma);
-
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
new file mode 100644
index 000000000000..3d0ad5065ee5
--- /dev/null
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -0,0 +1,354 @@
+/*
+ * Support for CompuLab EM-x270 platform
+ *
+ * Copyright (C) 2007 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * 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/irq.h>
+#include <linux/platform_device.h>
+
+#include <linux/dm9000.h>
+#include <linux/rtc-v3020.h>
+
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pxafb.h>
+#include <asm/arch/ohci.h>
+#include <asm/arch/mmc.h>
+#include <asm/arch/bitfield.h>
+
+#include "generic.h"
+
+/* GPIO IRQ usage */
+#define EM_X270_MMC_PD (105)
+#define EM_X270_ETHIRQ IRQ_GPIO(41)
+#define EM_X270_MMC_IRQ IRQ_GPIO(13)
+
+static struct resource em_x270_dm9k_resource[] = {
+ [0] = {
+ .start = PXA_CS2_PHYS,
+ .end = PXA_CS2_PHYS + 3,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = PXA_CS2_PHYS + 8,
+ .end = PXA_CS2_PHYS + 8 + 0x3f,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = EM_X270_ETHIRQ,
+ .end = EM_X270_ETHIRQ,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+/* for the moment we limit ourselves to 32bit IO until some
+ * better IO routines can be written and tested
+ */
+static struct dm9000_plat_data em_x270_dm9k_platdata = {
+ .flags = DM9000_PLATF_32BITONLY,
+};
+
+/* Ethernet device */
+static struct platform_device em_x270_dm9k = {
+ .name = "dm9000",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(em_x270_dm9k_resource),
+ .resource = em_x270_dm9k_resource,
+ .dev = {
+ .platform_data = &em_x270_dm9k_platdata,
+ }
+};
+
+/* audio device */
+static struct platform_device em_x270_audio = {
+ .name = "pxa2xx-ac97",
+ .id = -1,
+};
+
+/* WM9712 touchscreen controller. Hopefully the driver will make it to
+ * the mainstream sometime */
+static struct platform_device em_x270_ts = {
+ .name = "wm97xx-ts",
+ .id = -1,
+};
+
+/* RTC */
+static struct resource em_x270_v3020_resource[] = {
+ [0] = {
+ .start = PXA_CS4_PHYS,
+ .end = PXA_CS4_PHYS + 3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct v3020_platform_data em_x270_v3020_platdata = {
+ .leftshift = 0,
+};
+
+static struct platform_device em_x270_rtc = {
+ .name = "v3020",
+ .num_resources = ARRAY_SIZE(em_x270_v3020_resource),
+ .resource = em_x270_v3020_resource,
+ .id = -1,
+ .dev = {
+ .platform_data = &em_x270_v3020_platdata,
+ }
+};
+
+/* NAND flash */
+#define GPIO_NAND_CS (11)
+#define GPIO_NAND_RB (56)
+
+static inline void nand_cs_on(void)
+{
+ GPCR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+}
+
+static void nand_cs_off(void)
+{
+ dsb();
+
+ GPSR(GPIO_NAND_CS) = GPIO_bit(GPIO_NAND_CS);
+}
+
+/* hardware specific access to control-lines */
+static void em_x270_nand_cmd_ctl(struct mtd_info *mtd, int dat,
+ unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long)this->IO_ADDR_W;
+
+ dsb();
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ if (ctrl & NAND_ALE)
+ nandaddr |= (1 << 3);
+ else
+ nandaddr &= ~(1 << 3);
+ if (ctrl & NAND_CLE)
+ nandaddr |= (1 << 2);
+ else
+ nandaddr &= ~(1 << 2);
+ if (ctrl & NAND_NCE)
+ nand_cs_on();
+ else
+ nand_cs_off();
+ }
+
+ dsb();
+ this->IO_ADDR_W = (void __iomem *)nandaddr;
+ if (dat != NAND_CMD_NONE)
+ writel(dat, this->IO_ADDR_W);
+
+ dsb();
+}
+
+/* read device ready pin */
+static int em_x270_nand_device_ready(struct mtd_info *mtd)
+{
+ dsb();
+
+ return GPLR(GPIO_NAND_RB) & GPIO_bit(GPIO_NAND_RB);
+}
+
+static struct mtd_partition em_x270_partition_info[] = {
+ [0] = {
+ .name = "em_x270-0",
+ .offset = 0,
+ .size = SZ_4M,
+ },
+ [1] = {
+ .name = "em_x270-1",
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL
+ },
+};
+
+static const char *em_x270_part_probes[] = { "cmdlinepart", NULL };
+
+struct platform_nand_data em_x270_nand_platdata = {
+ .chip = {
+ .nr_chips = 1,
+ .chip_offset = 0,
+ .nr_partitions = ARRAY_SIZE(em_x270_partition_info),
+ .partitions = em_x270_partition_info,
+ .chip_delay = 20,
+ .part_probe_types = em_x270_part_probes,
+ },
+ .ctrl = {
+ .hwcontrol = 0,
+ .dev_ready = em_x270_nand_device_ready,
+ .select_chip = 0,
+ .cmd_ctrl = em_x270_nand_cmd_ctl,
+ },
+};
+
+static struct resource em_x270_nand_resource[] = {
+ [0] = {
+ .start = PXA_CS1_PHYS,
+ .end = PXA_CS1_PHYS + 12,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device em_x270_nand = {
+ .name = "gen_nand",
+ .num_resources = ARRAY_SIZE(em_x270_nand_resource),
+ .resource = em_x270_nand_resource,
+ .id = -1,
+ .dev = {
+ .platform_data = &em_x270_nand_platdata,
+ }
+};
+
+/* platform devices */
+static struct platform_device *platform_devices[] __initdata = {
+ &em_x270_dm9k,
+ &em_x270_audio,
+ &em_x270_ts,
+ &em_x270_rtc,
+ &em_x270_nand,
+};
+
+
+/* PXA27x OHCI controller setup */
+static int em_x270_ohci_init(struct device *dev)
+{
+ /* Set the Power Control Polarity Low */
+ UHCHR = (UHCHR | UHCHR_PCPL) &
+ ~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSE);
+
+ /* enable port 2 transiever */
+ UP2OCR = UP2OCR_HXS | UP2OCR_HXOE;
+
+ return 0;
+}
+
+static struct pxaohci_platform_data em_x270_ohci_platform_data = {
+ .port_mode = PMM_PERPORT_MODE,
+ .init = em_x270_ohci_init,
+};
+
+
+static int em_x270_mci_init(struct device *dev,
+ irq_handler_t em_x270_detect_int,
+ void *data)
+{
+ int err;
+
+ /* setup GPIO for PXA27x MMC controller */
+ pxa_gpio_mode(GPIO32_MMCCLK_MD);
+ pxa_gpio_mode(GPIO112_MMCCMD_MD);
+ pxa_gpio_mode(GPIO92_MMCDAT0_MD);
+ pxa_gpio_mode(GPIO109_MMCDAT1_MD);
+ pxa_gpio_mode(GPIO110_MMCDAT2_MD);
+ pxa_gpio_mode(GPIO111_MMCDAT3_MD);
+
+ /* EM-X270 uses GPIO13 as SD power enable */
+ pxa_gpio_mode(EM_X270_MMC_PD | GPIO_OUT);
+
+ err = request_irq(EM_X270_MMC_IRQ, em_x270_detect_int,
+ IRQF_DISABLED | IRQF_TRIGGER_FALLING,
+ "MMC card detect", data);
+ if (err) {
+ printk(KERN_ERR "%s: can't request MMC card detect IRQ: %d\n",
+ __FUNCTION__, err);
+ return err;
+ }
+
+ return 0;
+}
+
+static void em_x270_mci_setpower(struct device *dev, unsigned int vdd)
+{
+ /*
+ FIXME: current hardware implementation does not allow to
+ enable/disable MMC power. This will be fixed in next HW releases,
+ and we'll need to add implmentation here.
+ */
+ return;
+}
+
+static void em_x270_mci_exit(struct device *dev, void *data)
+{
+ free_irq(EM_X270_MMC_IRQ, data);
+}
+
+static struct pxamci_platform_data em_x270_mci_platform_data = {
+ .ocr_mask = MMC_VDD_28_29|MMC_VDD_29_30|MMC_VDD_30_31,
+ .init = em_x270_mci_init,
+ .setpower = em_x270_mci_setpower,
+ .exit = em_x270_mci_exit,
+};
+
+/* LCD 480x640 */
+static struct pxafb_mode_info em_x270_lcd_mode = {
+ .pixclock = 50000,
+ .bpp = 16,
+ .xres = 480,
+ .yres = 640,
+ .hsync_len = 8,
+ .vsync_len = 2,
+ .left_margin = 8,
+ .upper_margin = 0,
+ .right_margin = 24,
+ .lower_margin = 4,
+ .cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info em_x270_lcd = {
+ .modes = &em_x270_lcd_mode,
+ .num_modes = 1,
+ .cmap_inverse = 0,
+ .cmap_static = 0,
+ .lccr0 = LCCR0_PAS,
+ .lccr3 = LCCR3_PixClkDiv(0x01) | LCCR3_Acb(0xff),
+};
+
+static void __init em_x270_init(void)
+{
+ /* setup LCD */
+ set_pxa_fb_info(&em_x270_lcd);
+
+ /* register EM-X270 platform devices */
+ platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+
+ /* set MCI and OHCI platform parameters */
+ pxa_set_mci_info(&em_x270_mci_platform_data);
+ pxa_set_ohci_info(&em_x270_ohci_platform_data);
+
+ /* setup STUART GPIOs */
+ pxa_gpio_mode(GPIO46_STRXD_MD);
+ pxa_gpio_mode(GPIO47_STTXD_MD);
+
+ /* setup BTUART GPIOs */
+ pxa_gpio_mode(GPIO42_BTRXD_MD);
+ pxa_gpio_mode(GPIO43_BTTXD_MD);
+ pxa_gpio_mode(GPIO44_BTCTS_MD);
+ pxa_gpio_mode(GPIO45_BTRTS_MD);
+
+ /* Setup interrupt for dm9000 */
+ set_irq_type(EM_X270_ETHIRQ, IRQT_RISING);
+}
+
+MACHINE_START(EM_X270, "Compulab EM-x270")
+ .boot_params = 0xa0000100,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .map_io = pxa_map_io,
+ .init_irq = pxa27x_init_irq,
+ .timer = &pxa_timer,
+ .init_machine = em_x270_init,
+MACHINE_END
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 64b08b744f9f..5510f6fdce55 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -43,6 +43,7 @@
#include <asm/arch/irda.h>
#include <asm/arch/i2c.h>
+#include "devices.h"
#include "generic.h"
/*
@@ -242,7 +243,7 @@ static struct resource pxamci_resources[] = {
static u64 pxamci_dmamask = 0xffffffffUL;
-static struct platform_device pxamci_device = {
+struct platform_device pxa_device_mci = {
.name = "pxa2xx-mci",
.id = -1,
.dev = {
@@ -255,7 +256,7 @@ static struct platform_device pxamci_device = {
void __init pxa_set_mci_info(struct pxamci_platform_data *info)
{
- pxamci_device.dev.platform_data = info;
+ pxa_device_mci.dev.platform_data = info;
}
@@ -281,7 +282,7 @@ static struct resource pxa2xx_udc_resources[] = {
static u64 udc_dma_mask = ~(u32)0;
-static struct platform_device udc_device = {
+struct platform_device pxa_device_udc = {
.name = "pxa2xx-udc",
.id = -1,
.resource = pxa2xx_udc_resources,
@@ -307,7 +308,7 @@ static struct resource pxafb_resources[] = {
static u64 fb_dma_mask = ~(u64)0;
-static struct platform_device pxafb_device = {
+struct platform_device pxa_device_fb = {
.name = "pxa2xx-fb",
.id = -1,
.dev = {
@@ -320,32 +321,32 @@ static struct platform_device pxafb_device = {
void __init set_pxa_fb_info(struct pxafb_mach_info *info)
{
- pxafb_device.dev.platform_data = info;
+ pxa_device_fb.dev.platform_data = info;
}
void __init set_pxa_fb_parent(struct device *parent_dev)
{
- pxafb_device.dev.parent = parent_dev;
+ pxa_device_fb.dev.parent = parent_dev;
}
-static struct platform_device ffuart_device = {
+struct platform_device pxa_device_ffuart= {
.name = "pxa2xx-uart",
.id = 0,
};
-static struct platform_device btuart_device = {
+struct platform_device pxa_device_btuart = {
.name = "pxa2xx-uart",
.id = 1,
};
-static struct platform_device stuart_device = {
+struct platform_device pxa_device_stuart = {
.name = "pxa2xx-uart",
.id = 2,
};
-static struct platform_device hwuart_device = {
+struct platform_device pxa_device_hwuart = {
.name = "pxa2xx-uart",
.id = 3,
};
-static struct resource i2c_resources[] = {
+static struct resource pxai2c_resources[] = {
{
.start = 0x40301680,
.end = 0x403016a3,
@@ -357,40 +358,19 @@ static struct resource i2c_resources[] = {
},
};
-static struct platform_device i2c_device = {
+struct platform_device pxa_device_i2c = {
.name = "pxa2xx-i2c",
.id = 0,
- .resource = i2c_resources,
- .num_resources = ARRAY_SIZE(i2c_resources),
+ .resource = pxai2c_resources,
+ .num_resources = ARRAY_SIZE(pxai2c_resources),
};
-#ifdef CONFIG_PXA27x
-static struct resource i2c_power_resources[] = {
- {
- .start = 0x40f00180,
- .end = 0x40f001a3,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_PWRI2C,
- .end = IRQ_PWRI2C,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device i2c_power_device = {
- .name = "pxa2xx-i2c",
- .id = 1,
- .resource = i2c_power_resources,
- .num_resources = ARRAY_SIZE(i2c_resources),
-};
-#endif
-
void __init pxa_set_i2c_info(struct i2c_pxa_platform_data *info)
{
- i2c_device.dev.platform_data = info;
+ pxa_device_i2c.dev.platform_data = info;
}
-static struct resource i2s_resources[] = {
+static struct resource pxai2s_resources[] = {
{
.start = 0x40400000,
.end = 0x40400083,
@@ -402,16 +382,16 @@ static struct resource i2s_resources[] = {
},
};
-static struct platform_device i2s_device = {
+struct platform_device pxa_device_i2s = {
.name = "pxa2xx-i2s",
.id = -1,
- .resource = i2s_resources,
- .num_resources = ARRAY_SIZE(i2s_resources),
+ .resource = pxai2s_resources,
+ .num_resources = ARRAY_SIZE(pxai2s_resources),
};
static u64 pxaficp_dmamask = ~(u32)0;
-static struct platform_device pxaficp_device = {
+struct platform_device pxa_device_ficp = {
.name = "pxa2xx-ir",
.id = -1,
.dev = {
@@ -422,45 +402,10 @@ static struct platform_device pxaficp_device = {
void __init pxa_set_ficp_info(struct pxaficp_platform_data *info)
{
- pxaficp_device.dev.platform_data = info;
+ pxa_device_ficp.dev.platform_data = info;
}
-static struct platform_device pxartc_device = {
+struct platform_device pxa_device_rtc = {
.name = "sa1100-rtc",
.id = -1,
};
-
-static struct platform_device *devices[] __initdata = {
- &pxamci_device,
- &udc_device,
- &pxafb_device,
- &ffuart_device,
- &btuart_device,
- &stuart_device,
- &pxaficp_device,
- &i2c_device,
-#ifdef CONFIG_PXA27x
- &i2c_power_device,
-#endif
- &i2s_device,
- &pxartc_device,
-};
-
-static int __init pxa_init(void)
-{
- int cpuid, ret;
-
- ret = platform_add_devices(devices, ARRAY_SIZE(devices));
- if (ret)
- return ret;
-
- /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
- cpuid = read_cpuid(CPUID_ID);
- if (((cpuid >> 4) & 0xfff) == 0x2d0 ||
- ((cpuid >> 4) & 0xfff) == 0x290)
- ret = platform_device_register(&hwuart_device);
-
- return ret;
-}
-
-subsys_initcall(pxa_init);
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index e54a8dd63c17..91ab2ad8b34b 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -12,8 +12,12 @@
struct sys_timer;
extern struct sys_timer pxa_timer;
+extern void __init pxa_init_irq_low(void);
+extern void __init pxa_init_irq_high(void);
+extern void __init pxa_init_irq_gpio(int gpio_nr);
+extern void __init pxa25x_init_irq(void);
+extern void __init pxa27x_init_irq(void);
extern void __init pxa_map_io(void);
-extern void __init pxa_init_irq(void);
extern unsigned int get_clk_frequency_khz(int info);
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 64df44043a65..465108da2851 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -38,6 +38,7 @@
#include <asm/arch/mmc.h>
#include "generic.h"
+#include "devices.h"
/* TODO:
* - add pxa2xx_audio_ops_t device structure
@@ -152,7 +153,7 @@ static void __init idp_init(void)
static void __init idp_init_irq(void)
{
- pxa_init_irq();
+ pxa25x_init_irq();
set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE);
}
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 4619d5fe606c..4b867b0789d5 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -30,12 +30,12 @@
static void pxa_mask_low_irq(unsigned int irq)
{
- ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
+ ICMR &= ~(1 << irq);
}
static void pxa_unmask_low_irq(unsigned int irq)
{
- ICMR |= (1 << (irq + PXA_IRQ_SKIP));
+ ICMR |= (1 << irq);
}
static int pxa_set_wake(unsigned int irq, unsigned int on)
@@ -67,7 +67,27 @@ static struct irq_chip pxa_internal_chip_low = {
.set_wake = pxa_set_wake,
};
-#if PXA_INTERNAL_IRQS > 32
+void __init pxa_init_irq_low(void)
+{
+ int irq;
+
+ /* disable all IRQs */
+ ICMR = 0;
+
+ /* all IRQs are IRQ, not FIQ */
+ ICLR = 0;
+
+ /* only unmasked interrupts kick us out of idle */
+ ICCR = 1;
+
+ for (irq = PXA_IRQ(0); irq <= PXA_IRQ(31); irq++) {
+ set_irq_chip(irq, &pxa_internal_chip_low);
+ set_irq_handler(irq, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+}
+
+#ifdef CONFIG_PXA27x
/*
* This is for the second set of internal IRQs as found on the PXA27x.
@@ -75,12 +95,12 @@ static struct irq_chip pxa_internal_chip_low = {
static void pxa_mask_high_irq(unsigned int irq)
{
- ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP));
+ ICMR2 &= ~(1 << (irq - 32));
}
static void pxa_unmask_high_irq(unsigned int irq)
{
- ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP));
+ ICMR2 |= (1 << (irq - 32));
}
static struct irq_chip pxa_internal_chip_high = {
@@ -90,6 +110,19 @@ static struct irq_chip pxa_internal_chip_high = {
.unmask = pxa_unmask_high_irq,
};
+void __init pxa_init_irq_high(void)
+{
+ int irq;
+
+ ICMR2 = 0;
+ ICLR2 = 0;
+
+ for (irq = PXA_IRQ(32); irq < PXA_IRQ(64); irq++) {
+ set_irq_chip(irq, &pxa_internal_chip_high);
+ set_irq_handler(irq, handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+}
#endif
/* Note that if an input/irq line ever gets changed to an output during
@@ -217,7 +250,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
do {
loop = 0;
- mask = GEDR0 & ~3;
+ mask = GEDR0 & GPIO_IRQ_mask[0] & ~3;
if (mask) {
GEDR0 = mask;
irq = IRQ_GPIO(2);
@@ -233,7 +266,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
loop = 1;
}
- mask = GEDR1;
+ mask = GEDR1 & GPIO_IRQ_mask[1];
if (mask) {
GEDR1 = mask;
irq = IRQ_GPIO(32);
@@ -248,7 +281,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
loop = 1;
}
- mask = GEDR2;
+ mask = GEDR2 & GPIO_IRQ_mask[2];
if (mask) {
GEDR2 = mask;
irq = IRQ_GPIO(64);
@@ -263,8 +296,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
loop = 1;
}
-#if PXA_LAST_GPIO >= 96
- mask = GEDR3;
+ mask = GEDR3 & GPIO_IRQ_mask[3];
if (mask) {
GEDR3 = mask;
irq = IRQ_GPIO(96);
@@ -278,7 +310,6 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
} while (mask);
loop = 1;
}
-#endif
} while (loop);
}
@@ -314,64 +345,27 @@ static struct irq_chip pxa_muxed_gpio_chip = {
.set_wake = pxa_set_gpio_wake,
};
-
-void __init pxa_init_irq(void)
+void __init pxa_init_irq_gpio(int gpio_nr)
{
- int irq;
-
- /* disable all IRQs */
- ICMR = 0;
-
- /* all IRQs are IRQ, not FIQ */
- ICLR = 0;
+ int irq, i;
/* clear all GPIO edge detects */
- GFER0 = 0;
- GFER1 = 0;
- GFER2 = 0;
- GRER0 = 0;
- GRER1 = 0;
- GRER2 = 0;
- GEDR0 = GEDR0;
- GEDR1 = GEDR1;
- GEDR2 = GEDR2;
-
-#ifdef CONFIG_PXA27x
- /* And similarly for the extra regs on the PXA27x */
- ICMR2 = 0;
- ICLR2 = 0;
- GFER3 = 0;
- GRER3 = 0;
- GEDR3 = GEDR3;
-#endif
-
- /* only unmasked interrupts kick us out of idle */
- ICCR = 1;
+ for (i = 0; i < gpio_nr; i += 32) {
+ GFER(i) = 0;
+ GRER(i) = 0;
+ GEDR(i) = GEDR(i);
+ }
/* GPIO 0 and 1 must have their mask bit always set */
GPIO_IRQ_mask[0] = 3;
- for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
- set_irq_chip(irq, &pxa_internal_chip_low);
- set_irq_handler(irq, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-
-#if PXA_INTERNAL_IRQS > 32
- for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) {
- set_irq_chip(irq, &pxa_internal_chip_high);
- set_irq_handler(irq, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-#endif
-
for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
set_irq_chip(irq, &pxa_low_gpio_chip);
set_irq_handler(irq, handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
- for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) {
+ for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(gpio_nr); irq++) {
set_irq_chip(irq, &pxa_muxed_gpio_chip);
set_irq_handler(irq, handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index e3097664ffe1..26116440a7c9 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -46,6 +46,7 @@
#include <asm/arch/ohci.h>
#include "generic.h"
+#include "devices.h"
static unsigned int lpd270_irq_enabled;
@@ -97,7 +98,7 @@ static void __init lpd270_init_irq(void)
{
int irq;
- pxa_init_irq();
+ pxa27x_init_irq();
__raw_writew(0, LPD270_INT_MASK);
__raw_writew(0, LPD270_INT_STATUS);
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 6377b2e29ff0..e70048fd00a5 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -48,6 +48,7 @@
#include <asm/arch/mmc.h>
#include "generic.h"
+#include "devices.h"
#define LUB_MISC_WR __LUB_REG(LUBBOCK_FPGA_PHYS + 0x080)
@@ -103,7 +104,7 @@ static void __init lubbock_init_irq(void)
{
int irq;
- pxa_init_irq();
+ pxa25x_init_irq();
/* setup extra lubbock irqs */
for (irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index ed99a81b98f3..b02c79c7e6a3 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -46,6 +46,7 @@
#include <asm/arch/ohci.h>
#include "generic.h"
+#include "devices.h"
static unsigned long mainstone_irq_enabled;
@@ -89,7 +90,7 @@ static void __init mainstone_init_irq(void)
{
int irq;
- pxa_init_irq();
+ pxa27x_init_irq();
/* setup extra Mainstone irqs */
for(irq = MAINSTONE_IRQ(0); irq <= MAINSTONE_IRQ(15); irq++) {
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 6bf15ae73848..b59a81a8e7d3 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -24,62 +24,13 @@
#include <asm/arch/lubbock.h>
#include <asm/mach/time.h>
-
-/*
- * Debug macros
- */
-#undef DEBUG
-
-#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
-#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
-
-#define RESTORE_GPLEVEL(n) do { \
- GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
- GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
-} while (0)
-
-/*
- * List of global PXA peripheral registers to preserve.
- * More ones like CP and general purpose register values are preserved
- * with the stack pointer in sleep.S.
- */
-enum { SLEEP_SAVE_START = 0,
-
- SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
- SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
- SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
- SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
- SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
-
- SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
- SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
- SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
- SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
-
- SLEEP_SAVE_PSTR,
-
- SLEEP_SAVE_ICMR,
- SLEEP_SAVE_CKEN,
-
-#ifdef CONFIG_PXA27x
- SLEEP_SAVE_MDREFR,
- SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
- SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
-#endif
-
- SLEEP_SAVE_CKSUM,
-
- SLEEP_SAVE_SIZE
-};
-
+struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
+static unsigned long *sleep_save;
int pxa_pm_enter(suspend_state_t state)
{
- unsigned long sleep_save[SLEEP_SAVE_SIZE];
- unsigned long checksum = 0;
- struct timespec delta, rtc;
+ unsigned long sleep_save_checksum = 0, checksum = 0;
int i;
- extern void pxa_cpu_pm_enter(suspend_state_t state);
#ifdef CONFIG_IWMMXT
/* force any iWMMXt context to ram **/
@@ -87,109 +38,35 @@ int pxa_pm_enter(suspend_state_t state)
iwmmxt_task_disable(NULL);
#endif
- /* preserve current time */
- rtc.tv_sec = RCNR;
- rtc.tv_nsec = 0;
- save_time_delta(&delta, &rtc);
-
- SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
- SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
- SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
- SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
- SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
-
- SAVE(GAFR0_L); SAVE(GAFR0_U);
- SAVE(GAFR1_L); SAVE(GAFR1_U);
- SAVE(GAFR2_L); SAVE(GAFR2_U);
-
-#ifdef CONFIG_PXA27x
- SAVE(MDREFR);
- SAVE(GPLR3); SAVE(GPDR3); SAVE(GRER3); SAVE(GFER3); SAVE(PGSR3);
- SAVE(GAFR3_L); SAVE(GAFR3_U);
- SAVE(PWER); SAVE(PCFR); SAVE(PRER);
- SAVE(PFER); SAVE(PKWR);
-#endif
-
- SAVE(ICMR);
- ICMR = 0;
-
- SAVE(CKEN);
- SAVE(PSTR);
-
- /* Note: wake up source are set up in each machine specific files */
-
- /* clear GPIO transition detect bits */
- GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
-#ifdef CONFIG_PXA27x
- GEDR3 = GEDR3;
-#endif
+ pxa_cpu_pm_fns->save(sleep_save);
/* Clear sleep reset status */
RCSR = RCSR_SMR;
/* before sleeping, calculate and save a checksum */
- for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
- checksum += sleep_save[i];
- sleep_save[SLEEP_SAVE_CKSUM] = checksum;
+ for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
+ sleep_save_checksum += sleep_save[i];
/* *** go zzz *** */
- pxa_cpu_pm_enter(state);
-
+ pxa_cpu_pm_fns->enter(state);
cpu_init();
/* after sleeping, validate the checksum */
- checksum = 0;
- for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
+ for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
checksum += sleep_save[i];
/* if invalid, display message and wait for a hardware reset */
- if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
+ if (checksum != sleep_save_checksum) {
#ifdef CONFIG_ARCH_LUBBOCK
LUB_HEXLED = 0xbadbadc5;
#endif
while (1)
- pxa_cpu_pm_enter(state);
+ pxa_cpu_pm_fns->enter(state);
}
- /* ensure not to come back here if it wasn't intended */
- PSPR = 0;
-
- /* restore registers */
- RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
- RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
- RESTORE(GAFR0_L); RESTORE(GAFR0_U);
- RESTORE(GAFR1_L); RESTORE(GAFR1_U);
- RESTORE(GAFR2_L); RESTORE(GAFR2_U);
- RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
- RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
- RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
-
-#ifdef CONFIG_PXA27x
- RESTORE(MDREFR);
- RESTORE_GPLEVEL(3); RESTORE(GPDR3);
- RESTORE(GAFR3_L); RESTORE(GAFR3_U);
- RESTORE(GRER3); RESTORE(GFER3); RESTORE(PGSR3);
- RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
- RESTORE(PFER); RESTORE(PKWR);
-#endif
-
- PSSR = PSSR_RDH | PSSR_PH;
-
- RESTORE(CKEN);
-
- ICLR = 0;
- ICCR = 1;
- RESTORE(ICMR);
+ pxa_cpu_pm_fns->restore(sleep_save);
- RESTORE(PSTR);
-
- /* restore current time */
- rtc.tv_sec = RCNR;
- restore_time_delta(&delta, &rtc);
-
-#ifdef DEBUG
- printk(KERN_DEBUG "*** made it back from resume\n");
-#endif
+ pr_debug("*** made it back from resume\n");
return 0;
}
@@ -201,37 +78,32 @@ unsigned long sleep_phys_sp(void *sp)
return virt_to_phys(sp);
}
-/*
- * Called after processes are frozen, but before we shut down devices.
- */
-int pxa_pm_prepare(suspend_state_t state)
+static int pxa_pm_valid(suspend_state_t state)
{
- extern int pxa_cpu_pm_prepare(suspend_state_t state);
+ if (pxa_cpu_pm_fns)
+ return pxa_cpu_pm_fns->valid(state);
- return pxa_cpu_pm_prepare(state);
+ return -EINVAL;
}
-EXPORT_SYMBOL_GPL(pxa_pm_prepare);
-
-/*
- * Called after devices are re-setup, but before processes are thawed.
- */
-int pxa_pm_finish(suspend_state_t state)
-{
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(pxa_pm_finish);
-
static struct pm_ops pxa_pm_ops = {
- .prepare = pxa_pm_prepare,
+ .valid = pxa_pm_valid,
.enter = pxa_pm_enter,
- .finish = pxa_pm_finish,
- .valid = pm_valid_only_mem,
};
static int __init pxa_pm_init(void)
{
+ if (!pxa_cpu_pm_fns) {
+ printk(KERN_ERR "no valid pxa_cpu_pm_fns defined\n");
+ return -EINVAL;
+ }
+
+ sleep_save = kmalloc(pxa_cpu_pm_fns->save_size, GFP_KERNEL);
+ if (!sleep_save) {
+ printk(KERN_ERR "failed to alloc memory for pm save\n");
+ return -ENOMEM;
+ }
+
pm_set_ops(&pxa_pm_ops);
return 0;
}
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 34fb80b37023..655668d4d0e9 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -45,6 +45,7 @@
#include <asm/mach/sharpsl_param.h>
#include "generic.h"
+#include "devices.h"
#include "sharpsl.h"
static struct resource poodle_scoop_resources[] = {
@@ -412,7 +413,7 @@ MACHINE_START(POODLE, "SHARP Poodle")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_poodle,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa25x_init_irq,
.timer = &pxa_timer,
.init_machine = poodle_init,
MACHINE_END
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index c1f21739bf71..6dfcca72e90f 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -19,12 +19,17 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/pm.h>
#include <asm/hardware.h>
+#include <asm/arch/irqs.h>
#include <asm/arch/pxa-regs.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/dma.h>
#include "generic.h"
+#include "devices.h"
/*
* Various clock factors driven by the CCCR register.
@@ -105,32 +110,138 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
#ifdef CONFIG_PM
-int pxa_cpu_pm_prepare(suspend_state_t state)
-{
- switch (state) {
- case PM_SUSPEND_MEM:
- break;
- default:
- return -EINVAL;
- }
+#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
+
+#define RESTORE_GPLEVEL(n) do { \
+ GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
+ GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
+} while (0)
+
+/*
+ * List of global PXA peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+enum { SLEEP_SAVE_START = 0,
- return 0;
+ SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
+ SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
+ SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
+ SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
+ SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2,
+
+ SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+ SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+ SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+
+ SLEEP_SAVE_PSTR,
+
+ SLEEP_SAVE_ICMR,
+ SLEEP_SAVE_CKEN,
+
+ SLEEP_SAVE_SIZE
+};
+
+
+static void pxa25x_cpu_pm_save(unsigned long *sleep_save)
+{
+ SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2);
+ SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
+ SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
+ SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
+ SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2);
+
+ SAVE(GAFR0_L); SAVE(GAFR0_U);
+ SAVE(GAFR1_L); SAVE(GAFR1_U);
+ SAVE(GAFR2_L); SAVE(GAFR2_U);
+
+ SAVE(ICMR);
+ SAVE(CKEN);
+ SAVE(PSTR);
}
-void pxa_cpu_pm_enter(suspend_state_t state)
+static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
{
- extern void pxa_cpu_suspend(unsigned int);
- extern void pxa_cpu_resume(void);
+ /* restore registers */
+ RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1); RESTORE_GPLEVEL(2);
+ RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
+ RESTORE(GAFR0_L); RESTORE(GAFR0_U);
+ RESTORE(GAFR1_L); RESTORE(GAFR1_U);
+ RESTORE(GAFR2_L); RESTORE(GAFR2_U);
+ RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
+ RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
+ RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2);
+
+ RESTORE(CKEN);
+ RESTORE(ICMR);
+ RESTORE(PSTR);
+}
+static void pxa25x_cpu_pm_enter(suspend_state_t state)
+{
CKEN = 0;
switch (state) {
case PM_SUSPEND_MEM:
/* set resume return address */
PSPR = virt_to_phys(pxa_cpu_resume);
- pxa_cpu_suspend(PWRMODE_SLEEP);
+ pxa25x_cpu_suspend(PWRMODE_SLEEP);
break;
}
}
+static struct pxa_cpu_pm_fns pxa25x_cpu_pm_fns = {
+ .save_size = SLEEP_SAVE_SIZE,
+ .valid = pm_valid_only_mem,
+ .save = pxa25x_cpu_pm_save,
+ .restore = pxa25x_cpu_pm_restore,
+ .enter = pxa25x_cpu_pm_enter,
+};
+
+static void __init pxa25x_init_pm(void)
+{
+ pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns;
+}
+#endif
+
+void __init pxa25x_init_irq(void)
+{
+ pxa_init_irq_low();
+ pxa_init_irq_gpio(85);
+}
+
+static struct platform_device *pxa25x_devices[] __initdata = {
+ &pxa_device_mci,
+ &pxa_device_udc,
+ &pxa_device_fb,
+ &pxa_device_ffuart,
+ &pxa_device_btuart,
+ &pxa_device_stuart,
+ &pxa_device_i2c,
+ &pxa_device_i2s,
+ &pxa_device_ficp,
+ &pxa_device_rtc,
+};
+
+static int __init pxa25x_init(void)
+{
+ int ret = 0;
+
+ if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
+ if ((ret = pxa_init_dma(16)))
+ return ret;
+#ifdef CONFIG_PM
+ pxa25x_init_pm();
#endif
+ ret = platform_add_devices(pxa25x_devices,
+ ARRAY_SIZE(pxa25x_devices));
+ }
+ /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
+ if (cpu_is_pxa25x())
+ ret = platform_device_register(&pxa_device_hwuart);
+
+ return ret;
+}
+
+subsys_initcall(pxa25x_init);
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 1939acc3f9f7..203371ab19db 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -19,10 +19,14 @@
#include <asm/hardware.h>
#include <asm/irq.h>
+#include <asm/arch/irqs.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/ohci.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/dma.h>
#include "generic.h"
+#include "devices.h"
/* Crystal clock: 13MHz */
#define BASE_CLK 13000000
@@ -122,25 +126,107 @@ EXPORT_SYMBOL(get_lcdclk_frequency_10khz);
#ifdef CONFIG_PM
-int pxa_cpu_pm_prepare(suspend_state_t state)
+#define SAVE(x) sleep_save[SLEEP_SAVE_##x] = x
+#define RESTORE(x) x = sleep_save[SLEEP_SAVE_##x]
+
+#define RESTORE_GPLEVEL(n) do { \
+ GPSR##n = sleep_save[SLEEP_SAVE_GPLR##n]; \
+ GPCR##n = ~sleep_save[SLEEP_SAVE_GPLR##n]; \
+} while (0)
+
+/*
+ * List of global PXA peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * with the stack pointer in sleep.S.
+ */
+enum { SLEEP_SAVE_START = 0,
+
+ SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2, SLEEP_SAVE_GPLR3,
+ SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2, SLEEP_SAVE_GPDR3,
+ SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2, SLEEP_SAVE_GRER3,
+ SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2, SLEEP_SAVE_GFER3,
+ SLEEP_SAVE_PGSR0, SLEEP_SAVE_PGSR1, SLEEP_SAVE_PGSR2, SLEEP_SAVE_PGSR3,
+
+ SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR0_U,
+ SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR1_U,
+ SLEEP_SAVE_GAFR2_L, SLEEP_SAVE_GAFR2_U,
+ SLEEP_SAVE_GAFR3_L, SLEEP_SAVE_GAFR3_U,
+
+ SLEEP_SAVE_PSTR,
+
+ SLEEP_SAVE_ICMR,
+ SLEEP_SAVE_CKEN,
+
+ SLEEP_SAVE_MDREFR,
+ SLEEP_SAVE_PWER, SLEEP_SAVE_PCFR, SLEEP_SAVE_PRER,
+ SLEEP_SAVE_PFER, SLEEP_SAVE_PKWR,
+
+ SLEEP_SAVE_SIZE
+};
+
+void pxa27x_cpu_pm_save(unsigned long *sleep_save)
{
- switch (state) {
- case PM_SUSPEND_MEM:
- case PM_SUSPEND_STANDBY:
- return 0;
- default:
- return -EINVAL;
- }
+ SAVE(GPLR0); SAVE(GPLR1); SAVE(GPLR2); SAVE(GPLR3);
+ SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2); SAVE(GPDR3);
+ SAVE(GRER0); SAVE(GRER1); SAVE(GRER2); SAVE(GRER3);
+ SAVE(GFER0); SAVE(GFER1); SAVE(GFER2); SAVE(GFER3);
+ SAVE(PGSR0); SAVE(PGSR1); SAVE(PGSR2); SAVE(PGSR3);
+
+ SAVE(GAFR0_L); SAVE(GAFR0_U);
+ SAVE(GAFR1_L); SAVE(GAFR1_U);
+ SAVE(GAFR2_L); SAVE(GAFR2_U);
+ SAVE(GAFR3_L); SAVE(GAFR3_U);
+
+ SAVE(MDREFR);
+ SAVE(PWER); SAVE(PCFR); SAVE(PRER);
+ SAVE(PFER); SAVE(PKWR);
+
+ SAVE(ICMR); ICMR = 0;
+ SAVE(CKEN);
+ SAVE(PSTR);
+
+ /* Clear GPIO transition detect bits */
+ GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2; GEDR3 = GEDR3;
+}
+
+void pxa27x_cpu_pm_restore(unsigned long *sleep_save)
+{
+ /* ensure not to come back here if it wasn't intended */
+ PSPR = 0;
+
+ /* restore registers */
+ RESTORE_GPLEVEL(0); RESTORE_GPLEVEL(1);
+ RESTORE_GPLEVEL(2); RESTORE_GPLEVEL(3);
+ RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2); RESTORE(GPDR3);
+ RESTORE(GAFR0_L); RESTORE(GAFR0_U);
+ RESTORE(GAFR1_L); RESTORE(GAFR1_U);
+ RESTORE(GAFR2_L); RESTORE(GAFR2_U);
+ RESTORE(GAFR3_L); RESTORE(GAFR3_U);
+ RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2); RESTORE(GRER3);
+ RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2); RESTORE(GFER3);
+ RESTORE(PGSR0); RESTORE(PGSR1); RESTORE(PGSR2); RESTORE(PGSR3);
+
+ RESTORE(MDREFR);
+ RESTORE(PWER); RESTORE(PCFR); RESTORE(PRER);
+ RESTORE(PFER); RESTORE(PKWR);
+
+ PSSR = PSSR_RDH | PSSR_PH;
+
+ RESTORE(CKEN);
+
+ ICLR = 0;
+ ICCR = 1;
+ RESTORE(ICMR);
+ RESTORE(PSTR);
}
-void pxa_cpu_pm_enter(suspend_state_t state)
+void pxa27x_cpu_pm_enter(suspend_state_t state)
{
extern void pxa_cpu_standby(void);
- extern void pxa_cpu_suspend(unsigned int);
- extern void pxa_cpu_resume(void);
if (state == PM_SUSPEND_STANDBY)
- CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) | (1 << CKEN_LCD) | (1 << CKEN_PWM0);
+ CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER) |
+ (1 << CKEN_LCD) | (1 << CKEN_PWM0);
else
CKEN = (1 << CKEN_MEMC) | (1 << CKEN_OSTIMER);
@@ -157,11 +243,28 @@ void pxa_cpu_pm_enter(suspend_state_t state)
case PM_SUSPEND_MEM:
/* set resume return address */
PSPR = virt_to_phys(pxa_cpu_resume);
- pxa_cpu_suspend(PWRMODE_SLEEP);
+ pxa27x_cpu_suspend(PWRMODE_SLEEP);
break;
}
}
+static int pxa27x_cpu_pm_valid(suspend_state_t state)
+{
+ return state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY;
+}
+
+static struct pxa_cpu_pm_fns pxa27x_cpu_pm_fns = {
+ .save_size = SLEEP_SAVE_SIZE,
+ .save = pxa27x_cpu_pm_save,
+ .restore = pxa27x_cpu_pm_restore,
+ .valid = pxa27x_cpu_pm_valid,
+ .enter = pxa27x_cpu_pm_enter,
+};
+
+static void __init pxa27x_init_pm(void)
+{
+ pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns;
+}
#endif
/*
@@ -183,7 +286,7 @@ static struct resource pxa27x_ohci_resources[] = {
},
};
-static struct platform_device ohci_device = {
+static struct platform_device pxa27x_device_ohci = {
.name = "pxa27x-ohci",
.id = -1,
.dev = {
@@ -196,16 +299,62 @@ static struct platform_device ohci_device = {
void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
{
- ohci_device.dev.platform_data = info;
+ pxa27x_device_ohci.dev.platform_data = info;
}
+static struct resource i2c_power_resources[] = {
+ {
+ .start = 0x40f00180,
+ .end = 0x40f001a3,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_PWRI2C,
+ .end = IRQ_PWRI2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device pxa27x_device_i2c_power = {
+ .name = "pxa2xx-i2c",
+ .id = 1,
+ .resource = i2c_power_resources,
+ .num_resources = ARRAY_SIZE(i2c_power_resources),
+};
+
static struct platform_device *devices[] __initdata = {
- &ohci_device,
+ &pxa_device_mci,
+ &pxa_device_udc,
+ &pxa_device_fb,
+ &pxa_device_ffuart,
+ &pxa_device_btuart,
+ &pxa_device_stuart,
+ &pxa_device_i2c,
+ &pxa_device_i2s,
+ &pxa_device_ficp,
+ &pxa_device_rtc,
+ &pxa27x_device_i2c_power,
+ &pxa27x_device_ohci,
};
+void __init pxa27x_init_irq(void)
+{
+ pxa_init_irq_low();
+ pxa_init_irq_high();
+ pxa_init_irq_gpio(128);
+}
+
static int __init pxa27x_init(void)
{
- return platform_add_devices(devices, ARRAY_SIZE(devices));
+ int ret = 0;
+ if (cpu_is_pxa27x()) {
+ if ((ret = pxa_init_dma(32)))
+ return ret;
+#ifdef CONFIG_PM
+ pxa27x_init_pm();
+#endif
+ ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+ }
+ return ret;
}
subsys_initcall(pxa27x_init);
diff --git a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
index 15874b360e51..aff71fec618a 100644
--- a/arch/arm/mach-pxa/sleep.S
+++ b/arch/arm/mach-pxa/sleep.S
@@ -17,28 +17,12 @@
#include <asm/arch/pxa-regs.h>
-#ifdef CONFIG_PXA27x // workaround for Errata 50
#define MDREFR_KDIV 0x200a4000 // all banks
#define CCCR_SLEEP 0x00000107 // L=7 2N=2 A=0 PPDIS=0 CPDIS=0
-#endif
.text
-/*
- * pxa_cpu_suspend()
- *
- * Forces CPU into sleep state.
- *
- * r0 = value for PWRMODE M field for desired sleep state
- */
-
-ENTRY(pxa_cpu_suspend)
-
-#ifndef CONFIG_IWMMXT
- mra r2, r3, acc0
-#endif
- stmfd sp!, {r2 - r12, lr} @ save registers on stack
-
+pxa_cpu_save_cp:
@ get coprocessor registers
mrc p14, 0, r3, c6, c0, 0 @ clock configuration, for turbo mode
mrc p15, 0, r4, c15, c1, 0 @ CP access reg
@@ -54,12 +38,36 @@ ENTRY(pxa_cpu_suspend)
mov r10, sp
stmfd sp!, {r3 - r10}
- mov r5, r0 @ save sleep mode
+ mov pc, lr
+
+pxa_cpu_save_sp:
@ preserve phys address of stack
mov r0, sp
+ mov r2, lr
bl sleep_phys_sp
ldr r1, =sleep_save_sp
str r0, [r1]
+ mov pc, r2
+
+/*
+ * pxa27x_cpu_suspend()
+ *
+ * Forces CPU into sleep state.
+ *
+ * r0 = value for PWRMODE M field for desired sleep state
+ */
+
+ENTRY(pxa27x_cpu_suspend)
+
+#ifndef CONFIG_IWMMXT
+ mra r2, r3, acc0
+#endif
+ stmfd sp!, {r2 - r12, lr} @ save registers on stack
+
+ bl pxa_cpu_save_cp
+
+ mov r5, r0 @ save sleep mode
+ bl pxa_cpu_save_sp
@ clean data cache
bl xscale_flush_kern_cache_all
@@ -80,13 +88,55 @@ ENTRY(pxa_cpu_suspend)
@ enable SDRAM self-refresh mode
orr r5, r5, #MDREFR_SLFRSH
-#ifdef CONFIG_PXA27x
@ set SDCLKx divide-by-2 bits (this is part of a workaround for Errata 50)
ldr r6, =MDREFR_KDIV
orr r5, r5, r6
-#endif
-#ifdef CONFIG_PXA25x
+ @ Intel PXA270 Specification Update notes problems sleeping
+ @ with core operating above 91 MHz
+ @ (see Errata 50, ...processor does not exit from sleep...)
+
+ ldr r6, =CCCR
+ ldr r8, [r6] @ keep original value for resume
+
+ ldr r7, =CCCR_SLEEP @ prepare CCCR sleep value
+ mov r0, #0x2 @ prepare value for CLKCFG
+
+ @ align execution to a cache line
+ b pxa_cpu_do_suspend
+
+/*
+ * pxa27x_cpu_suspend()
+ *
+ * Forces CPU into sleep state.
+ *
+ * r0 = value for PWRMODE M field for desired sleep state
+ */
+
+ENTRY(pxa25x_cpu_suspend)
+ stmfd sp!, {r2 - r12, lr} @ save registers on stack
+
+ bl pxa_cpu_save_cp
+
+ mov r5, r0 @ save sleep mode
+ bl pxa_cpu_save_sp
+
+ @ clean data cache
+ bl xscale_flush_kern_cache_all
+
+ @ prepare value for sleep mode
+ mov r1, r5 @ sleep mode
+
+ @ prepare pointer to physical address 0 (virtual mapping in generic.c)
+ mov r2, #UNCACHED_PHYS_0
+
+ @ prepare SDRAM refresh settings
+ ldr r4, =MDREFR
+ ldr r5, [r4]
+
+ @ enable SDRAM self-refresh mode
+ orr r5, r5, #MDREFR_SLFRSH
+
@ Intel PXA255 Specification Update notes problems
@ about suspending with PXBus operating above 133MHz
@ (see Errata 31, GPIO output signals, ... unpredictable in sleep
@@ -118,30 +168,15 @@ ENTRY(pxa_cpu_suspend)
mov r0, #0
mcr p14, 0, r0, c6, c0, 0
orr r0, r0, #2 @ initiate change bit
-#endif
-#ifdef CONFIG_PXA27x
- @ Intel PXA270 Specification Update notes problems sleeping
- @ with core operating above 91 MHz
- @ (see Errata 50, ...processor does not exit from sleep...)
-
- ldr r6, =CCCR
- ldr r8, [r6] @ keep original value for resume
-
- ldr r7, =CCCR_SLEEP @ prepare CCCR sleep value
- mov r0, #0x2 @ prepare value for CLKCFG
-#endif
-
- @ align execution to a cache line
- b 1f
+ b pxa_cpu_do_suspend
.ltorg
.align 5
-1:
+pxa_cpu_do_suspend:
@ All needed values are now in registers.
@ These last instructions should be in cache
-#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
@ initiate the frequency change...
str r7, [r6]
mcr p14, 0, r0, c6, c0, 0
@@ -155,7 +190,6 @@ ENTRY(pxa_cpu_suspend)
mov r0, #42
10: subs r0, r0, #1
bne 10b
-#endif
@ Do not reorder...
@ Intel PXA270 Specification Update notes problems performing
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 3cbac63bed3c..bae47e145de8 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -48,6 +48,7 @@
#include <asm/hardware/scoop.h>
#include "generic.h"
+#include "devices.h"
#include "sharpsl.h"
/*
@@ -560,7 +561,7 @@ MACHINE_START(SPITZ, "SHARP Spitz")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_spitz,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa27x_init_irq,
.init_machine = spitz_init,
.timer = &pxa_timer,
MACHINE_END
@@ -572,7 +573,7 @@ MACHINE_START(BORZOI, "SHARP Borzoi")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_spitz,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa27x_init_irq,
.init_machine = spitz_init,
.timer = &pxa_timer,
MACHINE_END
@@ -584,7 +585,7 @@ MACHINE_START(AKITA, "SHARP Akita")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_spitz,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa27x_init_irq,
.init_machine = akita_init,
.timer = &pxa_timer,
MACHINE_END
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 5248abe334d2..98d27e646b09 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -1,9 +1,11 @@
/*
* arch/arm/mach-pxa/time.c
*
- * Author: Nicolas Pitre
- * Created: Jun 15, 2001
- * Copyright: MontaVista Software Inc.
+ * PXA clocksource, clockevents, and OST interrupt handlers.
+ * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>.
+ *
+ * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001
+ * by MontaVista Software, Inc. (Nico, your code rocks!)
*
* 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
@@ -12,173 +14,160 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/clocksource.h>
-
-#include <asm/system.h>
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/leds.h>
-#include <asm/irq.h>
+#include <linux/clockchips.h>
+
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#include <asm/arch/pxa-regs.h>
-
-static inline unsigned long pxa_get_rtc_time(void)
+static irqreturn_t
+pxa_ost0_interrupt(int irq, void *dev_id)
{
- return RCNR;
+ int next_match;
+ struct clock_event_device *c = dev_id;
+
+ if (c->mode == CLOCK_EVT_MODE_ONESHOT) {
+ /* Disarm the compare/match, signal the event. */
+ OIER &= ~OIER_E0;
+ c->event_handler(c);
+ } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) {
+ /* Call the event handler as many times as necessary
+ * to recover missed events, if any (if we update
+ * OSMR0 and OSCR0 is still ahead of us, we've missed
+ * the event). As we're dealing with that, re-arm the
+ * compare/match for the next event.
+ *
+ * HACK ALERT:
+ *
+ * There's a latency between the instruction that
+ * writes to OSMR0 and the actual commit to the
+ * physical hardware, because the CPU doesn't (have
+ * to) run at bus speed, there's a write buffer
+ * between the CPU and the bus, etc. etc. So if the
+ * target OSCR0 is "very close", to the OSMR0 load
+ * value, the update to OSMR0 might not get to the
+ * hardware in time and we'll miss that interrupt.
+ *
+ * To be safe, if the new OSMR0 is "very close" to the
+ * target OSCR0 value, we call the event_handler as
+ * though the event actually happened. According to
+ * Nico's comment in the previous version of this
+ * code, experience has shown that 6 OSCR ticks is
+ * "very close" but he went with 8. We will use 16,
+ * based on the results of testing on PXA270.
+ *
+ * To be doubly sure, we also tell clkevt via
+ * clockevents_register_device() not to ask for
+ * anything that might put us "very close".
+ */
+#define MIN_OSCR_DELTA 16
+ do {
+ OSSR = OSSR_M0;
+ next_match = (OSMR0 += LATCH);
+ c->event_handler(c);
+ } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA)
+ && (c->mode == CLOCK_EVT_MODE_PERIODIC));
+ }
+
+ return IRQ_HANDLED;
}
-static int pxa_set_rtc(void)
+static int
+pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev)
{
- unsigned long current_time = xtime.tv_sec;
+ unsigned long irqflags;
- if (RTSR & RTSR_ALE) {
- /* make sure not to forward the clock over an alarm */
- unsigned long alarm = RTAR;
- if (current_time >= alarm && alarm >= RCNR)
- return -ERESTARTSYS;
- }
- RCNR = current_time;
+ raw_local_irq_save(irqflags);
+ OSMR0 = OSCR + delta;
+ OSSR = OSSR_M0;
+ OIER |= OIER_E0;
+ raw_local_irq_restore(irqflags);
return 0;
}
-#ifdef CONFIG_NO_IDLE_HZ
-static unsigned long initial_match;
-static int match_posponed;
-#endif
-
-static irqreturn_t
-pxa_timer_interrupt(int irq, void *dev_id)
+static void
+pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
{
- int next_match;
-
- write_seqlock(&xtime_lock);
-
-#ifdef CONFIG_NO_IDLE_HZ
- if (match_posponed) {
- match_posponed = 0;
- OSMR0 = initial_match;
+ unsigned long irqflags;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ raw_local_irq_save(irqflags);
+ OSMR0 = OSCR + LATCH;
+ OSSR = OSSR_M0;
+ OIER |= OIER_E0;
+ raw_local_irq_restore(irqflags);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ raw_local_irq_save(irqflags);
+ OIER &= ~OIER_E0;
+ raw_local_irq_restore(irqflags);
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /* initializing, released, or preparing for suspend */
+ raw_local_irq_save(irqflags);
+ OIER &= ~OIER_E0;
+ raw_local_irq_restore(irqflags);
+ break;
}
-#endif
-
- /* Loop until we get ahead of the free running timer.
- * This ensures an exact clock tick count and time accuracy.
- * Since IRQs are disabled at this point, coherence between
- * lost_ticks(updated in do_timer()) and the match reg value is
- * ensured, hence we can use do_gettimeofday() from interrupt
- * handlers.
- *
- * HACK ALERT: it seems that the PXA timer regs aren't updated right
- * away in all cases when a write occurs. We therefore compare with
- * 8 instead of 0 in the while() condition below to avoid missing a
- * match if OSCR has already reached the next OSMR value.
- * Experience has shown that up to 6 ticks are needed to work around
- * this problem, but let's use 8 to be conservative. Note that this
- * affect things only when the timer IRQ has been delayed by nearly
- * exactly one tick period which should be a pretty rare event.
- */
- do {
- timer_tick();
- OSSR = OSSR_M0; /* Clear match on timer 0 */
- next_match = (OSMR0 += LATCH);
- } while( (signed long)(next_match - OSCR) <= 8 );
-
- write_sequnlock(&xtime_lock);
-
- return IRQ_HANDLED;
}
-static struct irqaction pxa_timer_irq = {
- .name = "PXA Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = pxa_timer_interrupt,
+static struct clock_event_device ckevt_pxa_osmr0 = {
+ .name = "osmr0",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .rating = 200,
+ .cpumask = CPU_MASK_CPU0,
+ .set_next_event = pxa_osmr0_set_next_event,
+ .set_mode = pxa_osmr0_set_mode,
};
-static cycle_t pxa_get_cycles(void)
+static cycle_t pxa_read_oscr(void)
{
return OSCR;
}
-static struct clocksource clocksource_pxa = {
- .name = "pxa_timer",
+static struct clocksource cksrc_pxa_oscr0 = {
+ .name = "oscr0",
.rating = 200,
- .read = pxa_get_cycles,
+ .read = pxa_read_oscr,
.mask = CLOCKSOURCE_MASK(32),
.shift = 20,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
+static struct irqaction pxa_ost0_irq = {
+ .name = "ost0",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = pxa_ost0_interrupt,
+ .dev_id = &ckevt_pxa_osmr0,
+};
+
static void __init pxa_timer_init(void)
{
- struct timespec tv;
- unsigned long flags;
-
- set_rtc = pxa_set_rtc;
+ OIER = 0;
+ OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
- tv.tv_nsec = 0;
- tv.tv_sec = pxa_get_rtc_time();
- do_settimeofday(&tv);
+ ckevt_pxa_osmr0.mult =
+ div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift);
+ ckevt_pxa_osmr0.max_delta_ns =
+ clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
+ ckevt_pxa_osmr0.min_delta_ns =
+ clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1;
- OIER = 0; /* disable any timer interrupts */
- OSSR = 0xf; /* clear status on all timers */
- setup_irq(IRQ_OST0, &pxa_timer_irq);
- local_irq_save(flags);
- OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */
- OSMR0 = OSCR + LATCH; /* set initial match */
- local_irq_restore(flags);
-
- /*
- * OSCR runs continuously on PXA and is not written to,
- * so we can use it as clock source directly.
- */
- clocksource_pxa.mult =
- clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_pxa.shift);
- clocksource_register(&clocksource_pxa);
-}
-
-#ifdef CONFIG_NO_IDLE_HZ
-static int pxa_dyn_tick_enable_disable(void)
-{
- /* nothing to do */
- return 0;
-}
+ cksrc_pxa_oscr0.mult =
+ clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_pxa_oscr0.shift);
-static void pxa_dyn_tick_reprogram(unsigned long ticks)
-{
- if (ticks > 1) {
- initial_match = OSMR0;
- OSMR0 = initial_match + ticks * LATCH;
- match_posponed = 1;
- }
-}
+ setup_irq(IRQ_OST0, &pxa_ost0_irq);
-static irqreturn_t
-pxa_dyn_tick_handler(int irq, void *dev_id)
-{
- if (match_posponed) {
- match_posponed = 0;
- OSMR0 = initial_match;
- if ( (signed long)(initial_match - OSCR) <= 8 )
- return pxa_timer_interrupt(irq, dev_id);
- }
- return IRQ_NONE;
+ clocksource_register(&cksrc_pxa_oscr0);
+ clockevents_register_device(&ckevt_pxa_osmr0);
}
-static struct dyn_tick_timer pxa_dyn_tick = {
- .enable = pxa_dyn_tick_enable_disable,
- .disable = pxa_dyn_tick_enable_disable,
- .reprogram = pxa_dyn_tick_reprogram,
- .handler = pxa_dyn_tick_handler,
-};
-#endif
-
#ifdef CONFIG_PM
static unsigned long osmr[4], oier;
@@ -200,7 +189,10 @@ static void pxa_timer_resume(void)
OIER = oier;
/*
- * OSMR0 is the system timer: make sure OSCR is sufficiently behind
+ * OSCR0 is the system timer, which has to increase
+ * monotonically until it rolls over in hardware. The value
+ * (OSMR0 - LATCH) is OSCR0 at the most recent system tick,
+ * which is a handy value to restore to OSCR0.
*/
OSCR = OSMR0 - LATCH;
}
@@ -213,7 +205,4 @@ struct sys_timer pxa_timer = {
.init = pxa_timer_init,
.suspend = pxa_timer_suspend,
.resume = pxa_timer_resume,
-#ifdef CONFIG_NO_IDLE_HZ
- .dyn_tick = &pxa_dyn_tick,
-#endif
};
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 72738771fb57..240fd042083d 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -42,7 +42,7 @@
#include <asm/mach/sharpsl_param.h>
#include "generic.h"
-
+#include "devices.h"
/*
* SCOOP Device
@@ -332,7 +332,7 @@ MACHINE_START(TOSA, "SHARP Tosa")
.io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
.fixup = fixup_tosa,
.map_io = pxa_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa25x_init_irq,
.init_machine = tosa_init,
.timer = &pxa_timer,
MACHINE_END
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index 28c79bd0a3a0..e4ba43bdf85d 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -49,6 +49,7 @@
#include <asm/arch/ohci.h>
#include "generic.h"
+#include "devices.h"
/********************************************************************************************
* ONBOARD FLASH
@@ -503,7 +504,7 @@ MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module")
.boot_params = TRIZEPS4_SDRAM_BASE + 0x100,
.init_machine = trizeps4_init,
.map_io = trizeps4_map_io,
- .init_irq = pxa_init_irq,
+ .init_irq = pxa27x_init_irq,
.timer = &pxa_timer,
MACHINE_END
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 570cf937e73b..a454451c97c3 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -87,7 +87,7 @@ static void __init rpc_map_io(void)
/*
* Turn off floppy.
*/
- outb(0xc, 0x3f2);
+ writeb(0xc, PCIO_BASE + (0x3f2 << 2));
/*
* RiscPC can't handle half-word loads and stores
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index d4b013b283c3..e2079cf9266f 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -9,6 +9,7 @@ config CPU_S3C2410
depends on ARCH_S3C2410
select S3C2410_CLOCK
select S3C2410_GPIO
+ select CPU_LLSERIAL_S3C2410
select S3C2410_PM if PM
help
Support for S3C2410 and S3C2410A family from the S3C24XX line
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 5b4831c4c1d8..cab9d6265e9e 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -37,7 +37,7 @@
#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
index 67d1ad363973..80d83739ab9f 100644
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -23,14 +23,14 @@
#include <asm/plat-s3c24xx/cpu.h>
#include <asm/plat-s3c24xx/dma.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
[DMACH_XD0] = {
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
index 435adcce6482..43bb5e106302 100644
--- a/arch/arm/mach-s3c2410/mach-amlm5900.c
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -48,7 +48,7 @@
#include <asm/mach-types.h>
#include <asm/arch/fb.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h>
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index f01de807b72f..bc926992b4e4 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -20,6 +20,8 @@
#include <linux/platform_device.h>
#include <linux/dm9000.h>
+#include <net/ax88796.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -34,13 +36,13 @@
#include <asm/mach-types.h>
//#include <asm/debug-ll.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
-#include <asm/arch/nand.h>
-#include <asm/arch/iic.h>
+#include <asm/plat-s3c/nand.h>
+#include <asm/plat-s3c/iic.h>
#include <asm/arch/fb.h>
#include <linux/mtd/mtd.h>
@@ -409,6 +411,61 @@ static struct s3c2410_platform_i2c bast_i2c_info = {
.max_freq = 130*1000,
};
+/* Asix AX88796 10/100 ethernet controller */
+
+static struct ax_plat_data bast_asix_platdata = {
+ .flags = AXFLG_MAC_FROMDEV,
+ .wordlength = 2,
+ .dcr_val = 0x48,
+ .rcr_val = 0x40,
+};
+
+static struct resource bast_asix_resource[] = {
+ [0] = {
+ .start = S3C2410_CS5 + BAST_PA_ASIXNET,
+ .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20) - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
+ .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20),
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = IRQ_ASIX,
+ .end = IRQ_ASIX,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct platform_device bast_device_asix = {
+ .name = "ax88796",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bast_asix_resource),
+ .resource = bast_asix_resource,
+ .dev = {
+ .platform_data = &bast_asix_platdata
+ }
+};
+
+/* Asix AX88796 10/100 ethernet controller parallel port */
+
+static struct resource bast_asixpp_resource[] = {
+ [0] = {
+ .start = S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20),
+ .end = S3C2410_CS5 + BAST_PA_ASIXNET + (0x1b * 0x20) - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device bast_device_axpp = {
+ .name = "ax88796-pp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bast_asixpp_resource),
+ .resource = bast_asixpp_resource,
+};
+
+/* LCD/VGA controller */
static struct s3c2410fb_mach_info __initdata bast_lcd_info = {
.width = 640,
@@ -453,6 +510,8 @@ static struct platform_device *bast_devices[] __initdata = {
&s3c_device_nand,
&bast_device_nor,
&bast_device_dm9k,
+ &bast_device_asix,
+ &bast_device_axpp,
&bast_sio,
};
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 5c9bcea74767..9a172b4ad720 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -30,7 +30,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-clock.h>
@@ -38,7 +38,7 @@
#include <asm/arch/h1940.h>
#include <asm/arch/h1940-latch.h>
#include <asm/arch/fb.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c24xx/udc.h>
#include <asm/plat-s3c24xx/clock.h>
#include <asm/plat-s3c24xx/devs.h>
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index 412e50c3d28a..621f548da610 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -33,9 +33,9 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/iic.h>
+#include <asm/plat-s3c/iic.h>
#include <asm/plat-s3c24xx/s3c2410.h>
#include <asm/plat-s3c24xx/clock.h>
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index 1f899fa588df..717af40e4477 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -29,7 +29,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/plat-s3c24xx/s3c2410.h>
diff --git a/arch/arm/mach-s3c2410/mach-qt2410.c b/arch/arm/mach-s3c2410/mach-qt2410.c
index d86e6f18bac9..e670b1e1631b 100644
--- a/arch/arm/mach-s3c2410/mach-qt2410.c
+++ b/arch/arm/mach-s3c2410/mach-qt2410.c
@@ -49,10 +49,10 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/leds-gpio.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/fb.h>
-#include <asm/arch/nand.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c/nand.h>
+#include <asm/plat-s3c24xx/udc.h>
#include <asm/arch/spi.h>
#include <asm/arch/spi-gpio.h>
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index 5852d300d52f..226550504c85 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -47,7 +47,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/plat-s3c24xx/devs.h>
#include <asm/plat-s3c24xx/cpu.h>
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index 7b624bb00490..9f43f3f124f5 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -39,7 +39,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/leds-gpio.h>
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index 1a86a9803753..e580303cb0ab 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -29,7 +29,7 @@
#include <asm/irq.h>
#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/plat-s3c24xx/s3c2410.h>
#include <asm/plat-s3c24xx/cpu.h>
@@ -40,7 +40,6 @@
static struct map_desc s3c2410_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
- IODESC_ENT(LCD),
IODESC_ENT(TIMER),
IODESC_ENT(WATCHDOG),
};
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
index d1eeed2ad47c..8a9c5a2bb252 100644
--- a/arch/arm/mach-s3c2410/sleep.S
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -32,7 +32,7 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-mem.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
/* s3c2410_cpu_suspend
*
diff --git a/arch/arm/mach-s3c2412/Kconfig b/arch/arm/mach-s3c2412/Kconfig
index d5be5d053264..8e8fe48ea47f 100644
--- a/arch/arm/mach-s3c2412/Kconfig
+++ b/arch/arm/mach-s3c2412/Kconfig
@@ -7,6 +7,7 @@
config CPU_S3C2412
bool
depends on ARCH_S3C2410
+ select CPU_LLSERIAL_S3C2440
select S3C2412_PM if PM
select S3C2412_DMA if S3C2410_DMA
help
diff --git a/arch/arm/mach-s3c2412/clock.c b/arch/arm/mach-s3c2412/clock.c
index 6a8e4448770b..8543dd6df391 100644
--- a/arch/arm/mach-s3c2412/clock.c
+++ b/arch/arm/mach-s3c2412/clock.c
@@ -37,7 +37,7 @@
#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
diff --git a/arch/arm/mach-s3c2412/dma.c b/arch/arm/mach-s3c2412/dma.c
index 668cccefe7b0..4b9425c1bf72 100644
--- a/arch/arm/mach-s3c2412/dma.c
+++ b/arch/arm/mach-s3c2412/dma.c
@@ -24,14 +24,14 @@
#include <asm/plat-s3c24xx/dma.h>
#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
diff --git a/arch/arm/mach-s3c2412/mach-smdk2413.c b/arch/arm/mach-s3c2412/mach-smdk2413.c
index 063af09f899d..b126a530daa6 100644
--- a/arch/arm/mach-s3c2412/mach-smdk2413.c
+++ b/arch/arm/mach-s3c2412/mach-smdk2413.c
@@ -32,12 +32,12 @@
#include <asm/mach-types.h>
//#include <asm/debug-ll.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/idle.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c24xx/udc.h>
#include <asm/arch/fb.h>
#include <asm/plat-s3c24xx/s3c2410.h>
diff --git a/arch/arm/mach-s3c2412/mach-vstms.c b/arch/arm/mach-s3c2412/mach-vstms.c
index f2fbd65956ac..32982547cd63 100644
--- a/arch/arm/mach-s3c2412/mach-vstms.c
+++ b/arch/arm/mach-s3c2412/mach-vstms.c
@@ -33,14 +33,14 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/idle.h>
#include <asm/arch/fb.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
#include <asm/plat-s3c24xx/s3c2410.h>
#include <asm/plat-s3c24xx/s3c2412.h>
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index 782b5814ced2..e0ccb404623f 100644
--- a/arch/arm/mach-s3c2412/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -34,12 +34,12 @@
#include <asm/arch/idle.h>
#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-power.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
#include <asm/arch/regs-s3c2412.h>
#include <asm/plat-s3c24xx/s3c2412.h>
@@ -63,7 +63,6 @@ static inline void s3c2412_init_gpio2(void)
static struct map_desc s3c2412_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
- IODESC_ENT(LCD),
IODESC_ENT(TIMER),
IODESC_ENT(WATCHDOG),
};
diff --git a/arch/arm/mach-s3c2440/Kconfig b/arch/arm/mach-s3c2440/Kconfig
index e3bfda098c0f..f1915bd61d15 100644
--- a/arch/arm/mach-s3c2440/Kconfig
+++ b/arch/arm/mach-s3c2440/Kconfig
@@ -12,6 +12,7 @@ config CPU_S3C2440
select S3C2410_GPIO
select S3C2440_DMA if S3C2410_DMA
select CPU_S3C244X
+ select CPU_LLSERIAL_S3C2440
help
Support for S3C2440 Samsung Mobile CPU based systems.
diff --git a/arch/arm/mach-s3c2440/dma.c b/arch/arm/mach-s3c2440/dma.c
index cd035a3ec878..f509f062e749 100644
--- a/arch/arm/mach-s3c2440/dma.c
+++ b/arch/arm/mach-s3c2440/dma.c
@@ -23,14 +23,14 @@
#include <asm/plat-s3c24xx/dma.h>
#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
[DMACH_XD0] = {
diff --git a/arch/arm/mach-s3c2440/mach-anubis.c b/arch/arm/mach-s3c2440/mach-anubis.c
index bff7ddd06a52..3d3dfa95db8e 100644
--- a/arch/arm/mach-s3c2440/mach-anubis.c
+++ b/arch/arm/mach-s3c2440/mach-anubis.c
@@ -18,6 +18,9 @@
#include <linux/serial_core.h>
#include <linux/platform_device.h>
+#include <linux/sm501.h>
+#include <linux/sm501-regs.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
@@ -31,17 +34,19 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
+#include <net/ax88796.h>
+
#include <asm/plat-s3c24xx/clock.h>
#include <asm/plat-s3c24xx/devs.h>
#include <asm/plat-s3c24xx/cpu.h>
@@ -153,6 +158,29 @@ static struct mtd_partition anubis_default_nand_part[] = {
}
};
+static struct mtd_partition anubis_default_nand_part_large[] = {
+ [0] = {
+ .name = "Boot Agent",
+ .size = SZ_128K,
+ .offset = 0,
+ },
+ [1] = {
+ .name = "/boot",
+ .size = SZ_4M - SZ_128K,
+ .offset = SZ_128K,
+ },
+ [2] = {
+ .name = "user1",
+ .offset = SZ_4M,
+ .size = SZ_32M - SZ_4M,
+ },
+ [3] = {
+ .name = "user2",
+ .offset = SZ_32M,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
/* the Anubis has 3 selectable slots for nand-flash, the two
* on-board chip areas, as well as the external slot.
*
@@ -260,6 +288,104 @@ static struct platform_device anubis_device_ide1 = {
.resource = anubis_ide1_resource,
};
+/* Asix AX88796 10/100 ethernet controller */
+
+static struct ax_plat_data anubis_asix_platdata = {
+ .flags = AXFLG_MAC_FROMDEV,
+ .wordlength = 2,
+ .dcr_val = 0x48,
+ .rcr_val = 0x40,
+};
+
+static struct resource anubis_asix_resource[] = {
+ [0] = {
+ .start = S3C2410_CS5,
+ .end = S3C2410_CS5 + (0x20 * 0x20) -1,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = IRQ_ASIX,
+ .end = IRQ_ASIX,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct platform_device anubis_device_asix = {
+ .name = "ax88796",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(anubis_asix_resource),
+ .resource = anubis_asix_resource,
+ .dev = {
+ .platform_data = &anubis_asix_platdata,
+ }
+};
+
+/* SM501 */
+
+static struct resource anubis_sm501_resource[] = {
+ [0] = {
+ .start = S3C2410_CS2,
+ .end = S3C2410_CS2 + SZ_8M,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = S3C2410_CS2 + SZ_64M - SZ_2M,
+ .end = S3C2410_CS2 + SZ_64M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .start = IRQ_EINT0,
+ .end = IRQ_EINT0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sm501_initdata anubis_sm501_initdata = {
+ .gpio_high = {
+ .set = 0x3F000000, /* 24bit panel */
+ .mask = 0x0,
+ },
+ .misc_timing = {
+ .set = 0x010100, /* SDRAM timing */
+ .mask = 0x1F1F00,
+ },
+ .misc_control = {
+ .set = SM501_MISC_PNL_24BIT,
+ .mask = 0,
+ },
+
+ /* set the SDRAM and bus clocks */
+ .mclk = 72 * MHZ,
+ .m1xclk = 144 * MHZ,
+};
+
+static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = {
+ [0] = {
+ .pin_scl = 44,
+ .pin_sda = 45,
+ },
+ [1] = {
+ .pin_scl = 40,
+ .pin_sda = 41,
+ },
+};
+
+static struct sm501_platdata anubis_sm501_platdata = {
+ .init = &anubis_sm501_initdata,
+ .gpio_i2c = anubis_sm501_gpio_i2c,
+ .gpio_i2c_nr = ARRAY_SIZE(anubis_sm501_gpio_i2c),
+};
+
+static struct platform_device anubis_device_sm501 = {
+ .name = "sm501",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(anubis_sm501_resource),
+ .resource = anubis_sm501_resource,
+ .dev = {
+ .platform_data = &anubis_sm501_platdata,
+ },
+};
+
/* Standard Anubis devices */
static struct platform_device *anubis_devices[] __initdata = {
@@ -271,6 +397,8 @@ static struct platform_device *anubis_devices[] __initdata = {
&s3c_device_nand,
&anubis_device_ide0,
&anubis_device_ide1,
+ &anubis_device_asix,
+ &anubis_device_sm501,
};
static struct clk *anubis_clocks[] = {
@@ -304,8 +432,17 @@ static void __init anubis_map_io(void)
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs));
- /* ensure that the GPIO is setup */
- s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+ /* check for the newer revision boards with large page nand */
+
+ if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) {
+ printk(KERN_INFO "ANUBIS-B detected (revision %d)\n",
+ __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK);
+ anubis_nand_sets[0].partitions = anubis_default_nand_part_large;
+ anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large);
+ } else {
+ /* ensure that the GPIO is setup */
+ s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+ }
}
static void __init anubis_init(void)
diff --git a/arch/arm/mach-s3c2440/mach-nexcoder.c b/arch/arm/mach-s3c2440/mach-nexcoder.c
index 5e61f2166c76..afe0d7b7e389 100644
--- a/arch/arm/mach-s3c2440/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2440/mach-nexcoder.c
@@ -36,7 +36,7 @@
//#include <asm/debug-ll.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/plat-s3c24xx/s3c2410.h>
#include <asm/plat-s3c24xx/s3c2440.h>
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 15811601f03d..0ba7e9060c7b 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -31,11 +31,11 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@@ -166,6 +166,29 @@ static struct mtd_partition osiris_default_nand_part[] = {
}
};
+static struct mtd_partition osiris_default_nand_part_large[] = {
+ [0] = {
+ .name = "Boot Agent",
+ .size = SZ_128K,
+ .offset = 0,
+ },
+ [1] = {
+ .name = "/boot",
+ .size = SZ_4M - SZ_128K,
+ .offset = SZ_128K,
+ },
+ [2] = {
+ .name = "user1",
+ .offset = SZ_4M,
+ .size = SZ_32M - SZ_4M,
+ },
+ [3] = {
+ .name = "user2",
+ .offset = SZ_32M,
+ .size = MTDPART_SIZ_FULL,
+ }
+};
+
/* the Osiris has 3 selectable slots for nand-flash, the two
* on-board chip areas, as well as the external slot.
*
@@ -322,14 +345,23 @@ static void __init osiris_map_io(void)
s3c24xx_init_clocks(0);
s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs));
+ /* check for the newer revision boards with large page nand */
+
+ if ((__raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK) >= 4) {
+ printk(KERN_INFO "OSIRIS-B detected (revision %d)\n",
+ __raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK);
+ osiris_nand_sets[0].partitions = osiris_default_nand_part_large;
+ osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large);
+ } else {
+ /* write-protect line to the NAND */
+ s3c2410_gpio_setpin(S3C2410_GPA0, 1);
+ }
+
/* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */
local_irq_save(flags);
__raw_writel(__raw_readl(S3C2410_BWSCON) | S3C2410_BWSCON_ST1 | S3C2410_BWSCON_ST2 | S3C2410_BWSCON_ST3 | S3C2410_BWSCON_ST4 | S3C2410_BWSCON_ST5, S3C2410_BWSCON);
local_irq_restore(flags);
-
- /* write-protect line to the NAND */
- s3c2410_gpio_setpin(S3C2410_GPA0, 1);
}
static void __init osiris_init(void)
diff --git a/arch/arm/mach-s3c2440/mach-rx3715.c b/arch/arm/mach-s3c2440/mach-rx3715.c
index 866ff71c01dd..b59e6d39f2f2 100644
--- a/arch/arm/mach-s3c2440/mach-rx3715.c
+++ b/arch/arm/mach-s3c2440/mach-rx3715.c
@@ -38,12 +38,12 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/h1940.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
#include <asm/arch/fb.h>
#include <asm/plat-s3c24xx/clock.h>
diff --git a/arch/arm/mach-s3c2440/mach-smdk2440.c b/arch/arm/mach-s3c2440/mach-smdk2440.c
index e167254e232e..670115b8a12e 100644
--- a/arch/arm/mach-s3c2440/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2440/mach-smdk2440.c
@@ -31,7 +31,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
diff --git a/arch/arm/mach-s3c2442/Kconfig b/arch/arm/mach-s3c2442/Kconfig
index bf8d87abfab3..88d5fd34fe3b 100644
--- a/arch/arm/mach-s3c2442/Kconfig
+++ b/arch/arm/mach-s3c2442/Kconfig
@@ -11,6 +11,7 @@ config CPU_S3C2442
select S3C2410_GPIO
select S3C2410_PM if PM
select CPU_S3C244X
+ select CPU_LLSERIAL_S3C2440
help
Support for S3C2442 Samsung Mobile CPU based systems.
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
index c649bb2e7ce8..14252f573754 100644
--- a/arch/arm/mach-s3c2443/Kconfig
+++ b/arch/arm/mach-s3c2443/Kconfig
@@ -8,6 +8,7 @@ config CPU_S3C2443
bool
depends on ARCH_S3C2410
select S3C2443_DMA if S3C2410_DMA
+ select CPU_LLSERIAL_S3C2440
help
Support for the S3C2443 SoC from the S3C24XX line
diff --git a/arch/arm/mach-s3c2443/dma.c b/arch/arm/mach-s3c2443/dma.c
index f70e8ccffc3d..fc3ede82af8f 100644
--- a/arch/arm/mach-s3c2443/dma.c
+++ b/arch/arm/mach-s3c2443/dma.c
@@ -24,14 +24,14 @@
#include <asm/plat-s3c24xx/dma.h>
#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-ac97.h>
+#include <asm/plat-s3c/regs-ac97.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-lcd.h>
#include <asm/arch/regs-sdi.h>
-#include <asm/arch/regs-iis.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-iis.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
#define MAP(x) { \
[0] = (x) | DMA_CH_VALID, \
diff --git a/arch/arm/mach-s3c2443/mach-smdk2443.c b/arch/arm/mach-s3c2443/mach-smdk2443.c
index b1eb709ee65a..8cd93130ef36 100644
--- a/arch/arm/mach-s3c2443/mach-smdk2443.c
+++ b/arch/arm/mach-s3c2443/mach-smdk2443.c
@@ -31,7 +31,7 @@
#include <asm/irq.h>
#include <asm/mach-types.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-lcd.h>
diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig
index cd67ab1b217b..f99d9013905f 100644
--- a/arch/arm/mach-sa1100/Kconfig
+++ b/arch/arm/mach-sa1100/Kconfig
@@ -101,6 +101,16 @@ config SA1100_JORNADA720
handheld computer. See <http://www.hp.com/jornada/products/720>
for details.
+config SA1100_JORNADA720_SSP
+ bool "HP Jornada 720 Extended SSP driver"
+ select SA1100_SSP
+ depends on SA1100_JORNADA720
+ help
+ Say Y here if you have a HP Jornada 7xx handheld computer and you
+ want to access devices connected to the MCU. Those include the
+ keyboard, touchscreen, backlight and battery. This driver also activates
+ the generic SSP which it extends.
+
config SA1100_HACKKIT
bool "HackKit Core CPU Board"
help
@@ -145,8 +155,7 @@ config SA1100_SSP
help
Say Y here to enable support for the generic PIO SSP driver.
This isn't for audio support, but for attached sensors and
- other devices, eg for BadgePAD 4 sensor support, or Jornada
- 720 touchscreen support.
+ other devices, eg for BadgePAD 4 sensor support.
config H3600_SLEEVE
tristate "Compaq iPAQ Handheld sleeve support"
diff --git a/arch/arm/mach-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index e27f15042a22..7a61e8d33ab7 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_SA1100_HACKKIT) += hackkit.o
led-$(CONFIG_SA1100_HACKKIT) += leds-hackkit.o
obj-$(CONFIG_SA1100_JORNADA720) += jornada720.o
+obj-$(CONFIG_SA1100_JORNADA720_SSP) += jornada720_ssp.o
obj-$(CONFIG_SA1100_LART) += lart.o
led-$(CONFIG_SA1100_LART) += leds-lart.o
@@ -51,3 +52,4 @@ obj-$(CONFIG_LEDS) += $(led-y)
# Miscelaneous functions
obj-$(CONFIG_PM) += pm.o sleep.o
obj-$(CONFIG_SA1100_SSP) += ssp.o
+
diff --git a/arch/arm/mach-sa1100/jornada720_ssp.c b/arch/arm/mach-sa1100/jornada720_ssp.c
new file mode 100644
index 000000000000..0a45e1ac8ad6
--- /dev/null
+++ b/arch/arm/mach-sa1100/jornada720_ssp.c
@@ -0,0 +1,201 @@
+/**
+ * arch/arm/mac-sa1100/jornada720_ssp.c
+ *
+ * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl>
+ *
+ * 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.
+ *
+ * SSP driver for the HP Jornada 710/720/728
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/ssp.h>
+#include <asm/arch/jornada720.h>
+
+static DEFINE_SPINLOCK(jornada_ssp_lock);
+static unsigned long jornada_ssp_flags;
+
+/**
+ * jornada_ssp_reverse - reverses input byte
+ *
+ * we need to reverse all data we recieve from the mcu due to its physical location
+ * returns : 01110111 -> 11101110
+ */
+u8 inline jornada_ssp_reverse(u8 byte)
+{
+ return
+ ((0x80 & byte) >> 7) |
+ ((0x40 & byte) >> 5) |
+ ((0x20 & byte) >> 3) |
+ ((0x10 & byte) >> 1) |
+ ((0x08 & byte) << 1) |
+ ((0x04 & byte) << 3) |
+ ((0x02 & byte) << 5) |
+ ((0x01 & byte) << 7);
+};
+EXPORT_SYMBOL(jornada_ssp_reverse);
+
+/**
+ * jornada_ssp_byte - waits for ready ssp bus and sends byte
+ *
+ * waits for fifo buffer to clear and then transmits, if it doesn't then we will
+ * timeout after <timeout> rounds. Needs mcu running before its called.
+ *
+ * returns : %mcu output on success
+ * : %-ETIMEOUT on timeout
+ */
+int jornada_ssp_byte(u8 byte)
+{
+ int timeout = 400000;
+ u16 ret;
+
+ while ((GPLR & GPIO_GPIO10)) {
+ if (!--timeout) {
+ printk(KERN_WARNING "SSP: timeout while waiting for transmit\n");
+ return -ETIMEDOUT;
+ }
+ cpu_relax();
+ }
+
+ ret = jornada_ssp_reverse(byte) << 8;
+
+ ssp_write_word(ret);
+ ssp_read_word(&ret);
+
+ return jornada_ssp_reverse(ret);
+};
+EXPORT_SYMBOL(jornada_ssp_byte);
+
+/**
+ * jornada_ssp_inout - decide if input is command or trading byte
+ *
+ * returns : (jornada_ssp_byte(byte)) on success
+ * : %-ETIMEOUT on timeout failure
+ */
+int jornada_ssp_inout(u8 byte)
+{
+ int ret, i;
+
+ /* true means command byte */
+ if (byte != TXDUMMY) {
+ ret = jornada_ssp_byte(byte);
+ /* Proper return to commands is TxDummy */
+ if (ret != TXDUMMY) {
+ for (i = 0; i < 256; i++)/* flushing bus */
+ if (jornada_ssp_byte(TXDUMMY) == -1)
+ break;
+ return -ETIMEDOUT;
+ }
+ } else /* Exchange TxDummy for data */
+ ret = jornada_ssp_byte(TXDUMMY);
+
+ return ret;
+};
+EXPORT_SYMBOL(jornada_ssp_inout);
+
+/**
+ * jornada_ssp_start - enable mcu
+ *
+ */
+int jornada_ssp_start()
+{
+ spin_lock_irqsave(&jornada_ssp_lock, jornada_ssp_flags);
+ GPCR = GPIO_GPIO25;
+ udelay(50);
+ return 0;
+};
+EXPORT_SYMBOL(jornada_ssp_start);
+
+/**
+ * jornada_ssp_end - disable mcu and turn off lock
+ *
+ */
+int jornada_ssp_end()
+{
+ GPSR = GPIO_GPIO25;
+ spin_unlock_irqrestore(&jornada_ssp_lock, jornada_ssp_flags);
+ return 0;
+};
+EXPORT_SYMBOL(jornada_ssp_end);
+
+static int __init jornada_ssp_probe(struct platform_device *dev)
+{
+ int ret;
+
+ GPSR = GPIO_GPIO25;
+
+ ret = ssp_init();
+
+ /* worked fine, lets not bother with anything else */
+ if (!ret) {
+ printk(KERN_INFO "SSP: device initialized with irq\n");
+ return ret;
+ }
+
+ printk(KERN_WARNING "SSP: initialization failed, trying non-irq solution \n");
+
+ /* init of Serial 4 port */
+ Ser4MCCR0 = 0;
+ Ser4SSCR0 = 0x0387;
+ Ser4SSCR1 = 0x18;
+
+ /* clear out any left over data */
+ ssp_flush();
+
+ /* enable MCU */
+ jornada_ssp_start();
+
+ /* see if return value makes sense */
+ ret = jornada_ssp_inout(GETBRIGHTNESS);
+
+ /* seems like it worked, just feed it with TxDummy to get rid of data */
+ if (ret == TxDummy)
+ jornada_ssp_inout(TXDUMMY);
+
+ jornada_ssp_end();
+
+ /* failed, lets just kill everything */
+ if (ret == -ETIMEDOUT) {
+ printk(KERN_WARNING "SSP: attempts failed, bailing\n");
+ ssp_exit();
+ return -ENODEV;
+ }
+
+ /* all fine */
+ printk(KERN_INFO "SSP: device initialized\n");
+ return 0;
+};
+
+static int jornada_ssp_remove(struct platform_device *dev)
+{
+ /* Note that this doesnt actually remove the driver, since theres nothing to remove
+ * It just makes sure everything is turned off */
+ GPSR = GPIO_GPIO25;
+ ssp_exit();
+ return 0;
+};
+
+struct platform_driver jornadassp_driver = {
+ .probe = jornada_ssp_probe,
+ .remove = jornada_ssp_remove,
+ .driver = {
+ .name = "jornada_ssp",
+ },
+};
+
+static int __init jornada_ssp_init(void)
+{
+ return platform_driver_register(&jornadassp_driver);
+}
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index 4cbf9468f654..9f1ed1509301 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -185,28 +185,21 @@ static int __devinit neponset_probe(struct platform_device *dev)
/*
* LDM power management.
*/
+static unsigned int neponset_saved_state;
+
static int neponset_suspend(struct platform_device *dev, pm_message_t state)
{
/*
* Save state.
*/
- if (!dev->dev.power.saved_state)
- dev->dev.power.saved_state = kmalloc(sizeof(unsigned int), GFP_KERNEL);
- if (!dev->dev.power.saved_state)
- return -ENOMEM;
-
- *(unsigned int *)dev->dev.power.saved_state = NCR_0;
+ neponset_saved_state = NCR_0;
return 0;
}
static int neponset_resume(struct platform_device *dev)
{
- if (dev->dev.power.saved_state) {
- NCR_0 = *(unsigned int *)dev->dev.power.saved_state;
- kfree(dev->dev.power.saved_state);
- dev->dev.power.saved_state = NULL;
- }
+ NCR_0 = neponset_saved_state;
return 0;
}
@@ -299,6 +292,8 @@ static struct platform_device *devices[] __initdata = {
&smc91x_device,
};
+extern void sa1110_mb_disable(void);
+
static int __init neponset_init(void)
{
platform_driver_register(&neponset_device_driver);
diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
index d674cf343156..01a37d3c0727 100644
--- a/arch/arm/mach-sa1100/pm.c
+++ b/arch/arm/mach-sa1100/pm.c
@@ -57,12 +57,7 @@ enum { SLEEP_SAVE_SP = 0,
static int sa11x0_pm_enter(suspend_state_t state)
{
unsigned long gpio, sleep_save[SLEEP_SAVE_SIZE];
- struct timespec delta, rtc;
- /* preserve current time */
- rtc.tv_sec = RCNR;
- rtc.tv_nsec = 0;
- save_time_delta(&delta, &rtc);
gpio = GPLR;
/* save vital registers */
@@ -119,10 +114,6 @@ static int sa11x0_pm_enter(suspend_state_t state)
*/
PSSR = PSSR_PH;
- /* restore current time */
- rtc.tv_sec = RCNR;
- restore_time_delta(&delta, &rtc);
-
return 0;
}
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 29cb0c1604ab..fdf7b016e7ad 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -21,25 +21,6 @@
#define RTC_DEF_DIVIDER (32768 - 1)
#define RTC_DEF_TRIM 0
-static unsigned long __init sa1100_get_rtc_time(void)
-{
- /*
- * According to the manual we should be able to let RTTR be zero
- * and then a default divisor for a 32.768KHz clock is used.
- * Apparently this doesn't work, at least for my SA1110 rev 5.
- * If the clock divider is uninitialized then reset it to the
- * default value to get the 1Hz clock.
- */
- if (RTTR == 0) {
- RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
- printk(KERN_WARNING "Warning: uninitialized Real Time Clock\n");
- /* The current RTC value probably doesn't make sense either */
- RCNR = 0;
- return 0;
- }
- return RCNR;
-}
-
static int sa1100_set_rtc(void)
{
unsigned long current_time = xtime.tv_sec;
@@ -117,15 +98,10 @@ static struct irqaction sa1100_timer_irq = {
static void __init sa1100_timer_init(void)
{
- struct timespec tv;
unsigned long flags;
set_rtc = sa1100_set_rtc;
- tv.tv_nsec = 0;
- tv.tv_sec = sa1100_get_rtc_time();
- do_settimeofday(&tv);
-
OIER = 0; /* disable any timer interrupts */
OSSR = 0xf; /* clear status on all timers */
setup_irq(IRQ_OST0, &sa1100_timer_irq);
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index e7904bc92c73..12161ae445da 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -345,13 +345,14 @@ config CPU_XSC3
# ARMv6
config CPU_V6
bool "Support ARM V6 processor"
- depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2
+ depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB || ARCH_OMAP2 || ARCH_MX3
+ default y if ARCH_MX3
select CPU_32v6
select CPU_ABRT_EV6
select CPU_CACHE_V6
select CPU_CACHE_VIPT
select CPU_CP15_MMU
- select CPU_HAS_ASID
+ select CPU_HAS_ASID if MMU
select CPU_COPY_V6 if MMU
select CPU_TLB_V6 if MMU
@@ -359,7 +360,7 @@ config CPU_V6
config CPU_32v6K
bool "Support ARM V6K processor extensions" if !SMP
depends on CPU_V6
- default y if SMP
+ default y if SMP && !ARCH_MX3
help
Say Y here if your ARMv6 processor supports the 'K' extension.
This enables the kernel to use some instructions not present
@@ -377,7 +378,7 @@ config CPU_V7
select CPU_CACHE_V7
select CPU_CACHE_VIPT
select CPU_CP15_MMU
- select CPU_HAS_ASID
+ select CPU_HAS_ASID if MMU
select CPU_COPY_V6 if MMU
select CPU_TLB_V7 if MMU
@@ -405,6 +406,7 @@ config CPU_32v5
config CPU_32v6
bool
+ select TLS_REG_EMUL if !CPU_32v6K && !MMU
config CPU_32v7
bool
@@ -598,7 +600,7 @@ config CPU_DCACHE_SIZE
config CPU_DCACHE_WRITETHROUGH
bool "Force write through D-cache"
- depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE
+ depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE
default y if CPU_ARM925T
help
Say Y here to use the data cache in writethrough mode. Unless you
@@ -611,12 +613,6 @@ config CPU_CACHE_ROUND_ROBIN
Say Y here to use the predictable round-robin cache replacement
policy. Unless you specifically require this or are unsure, say N.
-config CPU_L2CACHE_DISABLE
- bool "Disable level 2 cache"
- depends on CPU_V7
- help
- Say Y here to disable the level 2 cache. If unsure, say N.
-
config CPU_BPREDICT_DISABLE
bool "Disable branch prediction"
depends on CPU_ARM1020 || CPU_V6 || CPU_XSC3 || CPU_V7
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 08a36f1b35d2..b4e9b734e0bd 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
+#include <linux/spinlock.h>
#include <asm/cacheflush.h>
#include <asm/io.h>
@@ -25,14 +26,19 @@
#define CACHE_LINE_SIZE 32
static void __iomem *l2x0_base;
+static DEFINE_SPINLOCK(l2x0_lock);
static inline void sync_writel(unsigned long val, unsigned long reg,
unsigned long complete_mask)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&l2x0_lock, flags);
writel(val, l2x0_base + reg);
/* wait for the operation to complete */
while (readl(l2x0_base + reg) & complete_mask)
;
+ spin_unlock_irqrestore(&l2x0_lock, flags);
}
static inline void cache_sync(void)
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index 75d491448e45..846cce48e2b7 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -145,8 +145,8 @@ void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
__do_kernel_fault(mm, addr, fsr, regs);
}
-#define VM_FAULT_BADMAP (-20)
-#define VM_FAULT_BADACCESS (-21)
+#define VM_FAULT_BADMAP 0x010000
+#define VM_FAULT_BADACCESS 0x020000
static int
__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
@@ -183,20 +183,20 @@ good_area:
*/
survive:
fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, fsr & (1 << 11));
-
- /*
- * Handle the "normal" cases first - successful and sigbus
- */
- switch (fault) {
- case VM_FAULT_MAJOR:
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ return fault;
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
tsk->maj_flt++;
- return fault;
- case VM_FAULT_MINOR:
+ else
tsk->min_flt++;
- case VM_FAULT_SIGBUS:
- return fault;
- }
+ return fault;
+out_of_memory:
if (!is_init(tsk))
goto out;
@@ -249,7 +249,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
/*
* Handle the "normal" case first - VM_FAULT_MAJOR / VM_FAULT_MINOR
*/
- if (fault >= VM_FAULT_MINOR)
+ if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
return 0;
/*
@@ -259,8 +259,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
if (!user_mode(regs))
goto no_context;
- switch (fault) {
- case VM_FAULT_OOM:
+ if (fault & VM_FAULT_OOM) {
/*
* We ran out of memory, or some other thing
* happened to us that made us unable to handle
@@ -269,17 +268,15 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
printk("VM: killing process %s\n", tsk->comm);
do_exit(SIGKILL);
return 0;
-
- case VM_FAULT_SIGBUS:
+ }
+ if (fault & VM_FAULT_SIGBUS) {
/*
* We had some memory, but were unable to
* successfully fix up this page fault.
*/
sig = SIGBUS;
code = BUS_ADRERR;
- break;
-
- default:
+ } else {
/*
* Something tried to access memory that
* isn't in our memory map..
@@ -287,7 +284,6 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
sig = SIGSEGV;
code = fault == VM_FAULT_BADACCESS ?
SEGV_ACCERR : SEGV_MAPERR;
- break;
}
__do_user_fault(tsk, addr, fsr, sig, code, regs);
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index f3ade18862aa..75952779ce19 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -280,7 +280,10 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
if (!type)
return NULL;
- size = PAGE_ALIGN(size);
+ /*
+ * Page align the mapping size, taking account of any offset.
+ */
+ size = PAGE_ALIGN(offset + size);
area = get_vm_area(size, VM_IOREMAP);
if (!area)
@@ -325,11 +328,6 @@ __arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
if (!size || last_addr < phys_addr)
return NULL;
- /*
- * Page align the mapping size
- */
- size = PAGE_ALIGN(last_addr + 1) - phys_addr;
-
return __arm_ioremap_pfn(pfn, offset, size, mtype);
}
EXPORT_SYMBOL(__arm_ioremap);
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 3b5e47dc0c97..e5d61ee3d4a1 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -114,6 +114,10 @@ static void __init early_cachepolicy(char **p)
}
if (i == ARRAY_SIZE(cache_policies))
printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
+ if (cpu_architecture() >= CPU_ARCH_ARMv6) {
+ printk(KERN_WARNING "Only cachepolicy=writeback supported on ARMv6 and later\n");
+ cachepolicy = CPOLICY_WRITEBACK;
+ }
flush_cache_all();
set_cr(cr_alignment);
}
@@ -252,13 +256,15 @@ static void __init build_mem_type_table(void)
int cpu_arch = cpu_architecture();
int i;
+ if (cpu_arch < CPU_ARCH_ARMv6) {
#if defined(CONFIG_CPU_DCACHE_DISABLE)
- if (cachepolicy > CPOLICY_BUFFERED)
- cachepolicy = CPOLICY_BUFFERED;
+ if (cachepolicy > CPOLICY_BUFFERED)
+ cachepolicy = CPOLICY_BUFFERED;
#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
- if (cachepolicy > CPOLICY_WRITETHROUGH)
- cachepolicy = CPOLICY_WRITETHROUGH;
+ if (cachepolicy > CPOLICY_WRITETHROUGH)
+ cachepolicy = CPOLICY_WRITETHROUGH;
#endif
+ }
if (cpu_arch < CPU_ARCH_ARMv5) {
if (cachepolicy >= CPOLICY_WRITEALLOC)
cachepolicy = CPOLICY_WRITEBACK;
diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c
index 9f396b4fa0b7..2b5ba396e3a6 100644
--- a/arch/arm/mm/proc-syms.c
+++ b/arch/arm/mm/proc-syms.c
@@ -31,12 +31,14 @@ EXPORT_SYMBOL(__cpuc_coherent_kern_range);
EXPORT_SYMBOL(cpu_cache);
#endif
+#ifdef CONFIG_MMU
#ifndef MULTI_USER
EXPORT_SYMBOL(__cpu_clear_user_page);
EXPORT_SYMBOL(__cpu_copy_user_page);
#else
EXPORT_SYMBOL(cpu_user);
#endif
+#endif
/*
* No module should need to touch the TLB (and currently
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 718f4782ee8b..e0acc5ae6f6f 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -77,6 +77,7 @@ ENTRY(cpu_v7_dcache_clean_area)
* - we are not using split page tables
*/
ENTRY(cpu_v7_switch_mm)
+#ifdef CONFIG_MMU
mov r2, #0
ldr r1, [r1, #MM_CONTEXT_ID] @ get mm->context.id
orr r0, r0, #TTB_RGN_OC_WB @ mark PTWs outer cacheable, WB
@@ -86,6 +87,7 @@ ENTRY(cpu_v7_switch_mm)
isb
mcr p15, 0, r1, c13, c0, 1 @ set context ID
isb
+#endif
mov pc, lr
/*
@@ -109,6 +111,7 @@ ENTRY(cpu_v7_switch_mm)
* 1111 0 1 1 r/w r/w
*/
ENTRY(cpu_v7_set_pte_ext)
+#ifdef CONFIG_MMU
str r1, [r0], #-2048 @ linux version
bic r3, r1, #0x000003f0
@@ -136,6 +139,7 @@ ENTRY(cpu_v7_set_pte_ext)
str r3, [r0]
mcr p15, 0, r0, c7, c10, 1 @ flush_pte
+#endif
mov pc, lr
cpu_v7_name:
@@ -169,6 +173,7 @@ __v7_setup:
mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate
#endif
dsb
+#ifdef CONFIG_MMU
mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs
mcr p15, 0, r10, c2, c0, 2 @ TTB control register
orr r4, r4, #TTB_RGN_OC_WB @ mark PTWs outer cacheable, WB
@@ -176,21 +181,12 @@ __v7_setup:
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
mov r10, #0x1f @ domains 0, 1 = manager
mcr p15, 0, r10, c3, c0, 0 @ load domain access register
-#ifndef CONFIG_CPU_L2CACHE_DISABLE
- @ L2 cache configuration in the L2 aux control register
- mrc p15, 1, r10, c9, c0, 2
- bic r10, r10, #(1 << 16) @ L2 outer cache
- mcr p15, 1, r10, c9, c0, 2
- @ L2 cache is enabled in the aux control register
- mrc p15, 0, r10, c1, c0, 1
- orr r10, r10, #2
- mcr p15, 0, r10, c1, c0, 1
#endif
- mrc p15, 0, r0, c1, c0, 0 @ read control register
- ldr r10, cr1_clear @ get mask for bits to clear
- bic r0, r0, r10 @ clear bits them
- ldr r10, cr1_set @ get mask for bits to set
- orr r0, r0, r10 @ set them
+ adr r5, v7_crval
+ ldmia r5, {r5, r6}
+ mrc p15, 0, r0, c1, c0, 0 @ read control register
+ bic r0, r0, r5 @ clear bits them
+ orr r0, r0, r6 @ set them
mov pc, lr @ return to head.S:__ret
/*
@@ -199,12 +195,9 @@ __v7_setup:
* rrrr rrrx xxx0 0101 xxxx xxxx x111 xxxx < forced
* 0 110 0011 1.00 .111 1101 < we want
*/
- .type cr1_clear, #object
- .type cr1_set, #object
-cr1_clear:
- .word 0x0120c302
-cr1_set:
- .word 0x00c0387d
+ .type v7_crval, #object
+v7_crval:
+ crval clear=0x0120c302, mmuset=0x00c0387d, ucset=0x00c0187c
__v7_setup_stack:
.space 4 * 11 @ 11 registers
diff --git a/arch/arm/plat-iop/Makefile b/arch/arm/plat-iop/Makefile
index 4d2b1da3cd82..36bff0325959 100644
--- a/arch/arm/plat-iop/Makefile
+++ b/arch/arm/plat-iop/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_ARCH_IOP32X) += setup.o
obj-$(CONFIG_ARCH_IOP32X) += time.o
obj-$(CONFIG_ARCH_IOP32X) += io.o
obj-$(CONFIG_ARCH_IOP32X) += cp6.o
+obj-$(CONFIG_ARCH_IOP32X) += adma.o
# IOP33X
obj-$(CONFIG_ARCH_IOP33X) += gpio.o
@@ -21,6 +22,7 @@ obj-$(CONFIG_ARCH_IOP33X) += setup.o
obj-$(CONFIG_ARCH_IOP33X) += time.o
obj-$(CONFIG_ARCH_IOP33X) += io.o
obj-$(CONFIG_ARCH_IOP33X) += cp6.o
+obj-$(CONFIG_ARCH_IOP33X) += adma.o
# IOP13XX
obj-$(CONFIG_ARCH_IOP13XX) += cp6.o
diff --git a/arch/arm/plat-iop/adma.c b/arch/arm/plat-iop/adma.c
new file mode 100644
index 000000000000..53c5e9a52eb1
--- /dev/null
+++ b/arch/arm/plat-iop/adma.c
@@ -0,0 +1,209 @@
+/*
+ * platform device definitions for the iop3xx dma/xor engines
+ * Copyright © 2006, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/platform_device.h>
+#include <asm/hardware/iop3xx.h>
+#include <linux/dma-mapping.h>
+#include <asm/arch/adma.h>
+#include <asm/hardware/iop_adma.h>
+
+#ifdef CONFIG_ARCH_IOP32X
+#define IRQ_DMA0_EOT IRQ_IOP32X_DMA0_EOT
+#define IRQ_DMA0_EOC IRQ_IOP32X_DMA0_EOC
+#define IRQ_DMA0_ERR IRQ_IOP32X_DMA0_ERR
+
+#define IRQ_DMA1_EOT IRQ_IOP32X_DMA1_EOT
+#define IRQ_DMA1_EOC IRQ_IOP32X_DMA1_EOC
+#define IRQ_DMA1_ERR IRQ_IOP32X_DMA1_ERR
+
+#define IRQ_AA_EOT IRQ_IOP32X_AA_EOT
+#define IRQ_AA_EOC IRQ_IOP32X_AA_EOC
+#define IRQ_AA_ERR IRQ_IOP32X_AA_ERR
+#endif
+#ifdef CONFIG_ARCH_IOP33X
+#define IRQ_DMA0_EOT IRQ_IOP33X_DMA0_EOT
+#define IRQ_DMA0_EOC IRQ_IOP33X_DMA0_EOC
+#define IRQ_DMA0_ERR IRQ_IOP33X_DMA0_ERR
+
+#define IRQ_DMA1_EOT IRQ_IOP33X_DMA1_EOT
+#define IRQ_DMA1_EOC IRQ_IOP33X_DMA1_EOC
+#define IRQ_DMA1_ERR IRQ_IOP33X_DMA1_ERR
+
+#define IRQ_AA_EOT IRQ_IOP33X_AA_EOT
+#define IRQ_AA_EOC IRQ_IOP33X_AA_EOC
+#define IRQ_AA_ERR IRQ_IOP33X_AA_ERR
+#endif
+/* AAU and DMA Channels */
+static struct resource iop3xx_dma_0_resources[] = {
+ [0] = {
+ .start = IOP3XX_DMA_PHYS_BASE(0),
+ .end = IOP3XX_DMA_UPPER_PA(0),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DMA0_EOT,
+ .end = IRQ_DMA0_EOT,
+ .flags = IORESOURCE_IRQ
+ },
+ [2] = {
+ .start = IRQ_DMA0_EOC,
+ .end = IRQ_DMA0_EOC,
+ .flags = IORESOURCE_IRQ
+ },
+ [3] = {
+ .start = IRQ_DMA0_ERR,
+ .end = IRQ_DMA0_ERR,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct resource iop3xx_dma_1_resources[] = {
+ [0] = {
+ .start = IOP3XX_DMA_PHYS_BASE(1),
+ .end = IOP3XX_DMA_UPPER_PA(1),
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_DMA1_EOT,
+ .end = IRQ_DMA1_EOT,
+ .flags = IORESOURCE_IRQ
+ },
+ [2] = {
+ .start = IRQ_DMA1_EOC,
+ .end = IRQ_DMA1_EOC,
+ .flags = IORESOURCE_IRQ
+ },
+ [3] = {
+ .start = IRQ_DMA1_ERR,
+ .end = IRQ_DMA1_ERR,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+
+static struct resource iop3xx_aau_resources[] = {
+ [0] = {
+ .start = IOP3XX_AAU_PHYS_BASE,
+ .end = IOP3XX_AAU_UPPER_PA,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_AA_EOT,
+ .end = IRQ_AA_EOT,
+ .flags = IORESOURCE_IRQ
+ },
+ [2] = {
+ .start = IRQ_AA_EOC,
+ .end = IRQ_AA_EOC,
+ .flags = IORESOURCE_IRQ
+ },
+ [3] = {
+ .start = IRQ_AA_ERR,
+ .end = IRQ_AA_ERR,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static u64 iop3xx_adma_dmamask = DMA_32BIT_MASK;
+
+static struct iop_adma_platform_data iop3xx_dma_0_data = {
+ .hw_id = DMA0_ID,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct iop_adma_platform_data iop3xx_dma_1_data = {
+ .hw_id = DMA1_ID,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct iop_adma_platform_data iop3xx_aau_data = {
+ .hw_id = AAU_ID,
+ .pool_size = 3 * PAGE_SIZE,
+};
+
+struct platform_device iop3xx_dma_0_channel = {
+ .name = "iop-adma",
+ .id = 0,
+ .num_resources = 4,
+ .resource = iop3xx_dma_0_resources,
+ .dev = {
+ .dma_mask = &iop3xx_adma_dmamask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ .platform_data = (void *) &iop3xx_dma_0_data,
+ },
+};
+
+struct platform_device iop3xx_dma_1_channel = {
+ .name = "iop-adma",
+ .id = 1,
+ .num_resources = 4,
+ .resource = iop3xx_dma_1_resources,
+ .dev = {
+ .dma_mask = &iop3xx_adma_dmamask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ .platform_data = (void *) &iop3xx_dma_1_data,
+ },
+};
+
+struct platform_device iop3xx_aau_channel = {
+ .name = "iop-adma",
+ .id = 2,
+ .num_resources = 4,
+ .resource = iop3xx_aau_resources,
+ .dev = {
+ .dma_mask = &iop3xx_adma_dmamask,
+ .coherent_dma_mask = DMA_64BIT_MASK,
+ .platform_data = (void *) &iop3xx_aau_data,
+ },
+};
+
+static int __init iop3xx_adma_cap_init(void)
+{
+ #ifdef CONFIG_ARCH_IOP32X /* the 32x DMA does not perform CRC32C */
+ dma_cap_set(DMA_MEMCPY, iop3xx_dma_0_data.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, iop3xx_dma_0_data.cap_mask);
+ #else
+ dma_cap_set(DMA_MEMCPY, iop3xx_dma_0_data.cap_mask);
+ dma_cap_set(DMA_MEMCPY_CRC32C, iop3xx_dma_0_data.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, iop3xx_dma_0_data.cap_mask);
+ #endif
+
+ #ifdef CONFIG_ARCH_IOP32X /* the 32x DMA does not perform CRC32C */
+ dma_cap_set(DMA_MEMCPY, iop3xx_dma_1_data.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, iop3xx_dma_1_data.cap_mask);
+ #else
+ dma_cap_set(DMA_MEMCPY, iop3xx_dma_1_data.cap_mask);
+ dma_cap_set(DMA_MEMCPY_CRC32C, iop3xx_dma_1_data.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, iop3xx_dma_1_data.cap_mask);
+ #endif
+
+ #ifdef CONFIG_ARCH_IOP32X /* the 32x AAU does not perform zero sum */
+ dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask);
+ dma_cap_set(DMA_MEMSET, iop3xx_aau_data.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask);
+ #else
+ dma_cap_set(DMA_XOR, iop3xx_aau_data.cap_mask);
+ dma_cap_set(DMA_ZERO_SUM, iop3xx_aau_data.cap_mask);
+ dma_cap_set(DMA_MEMSET, iop3xx_aau_data.cap_mask);
+ dma_cap_set(DMA_INTERRUPT, iop3xx_aau_data.cap_mask);
+ #endif
+
+ return 0;
+}
+
+arch_initcall(iop3xx_adma_cap_init);
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index 100d57ad98ed..ba3d21d8fba3 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -78,6 +78,13 @@ static struct irqaction iop_timer_irq = {
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
};
+static unsigned long iop_tick_rate;
+unsigned long get_iop_tick_rate(void)
+{
+ return iop_tick_rate;
+}
+EXPORT_SYMBOL(get_iop_tick_rate);
+
void __init iop_init_time(unsigned long tick_rate)
{
u32 timer_ctl;
@@ -85,6 +92,7 @@ void __init iop_init_time(unsigned long tick_rate)
ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
ticks_per_usec = tick_rate / 1000000;
next_jiffy_time = 0xffffffff;
+ iop_tick_rate = tick_rate;
timer_ctl = IOP_TMR_EN | IOP_TMR_PRIVILEGED |
IOP_TMR_RELOAD | IOP_TMR_RATIO_1_1;
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
new file mode 100644
index 000000000000..03a65c0dfb60
--- /dev/null
+++ b/arch/arm/plat-mxc/Kconfig
@@ -0,0 +1,20 @@
+if ARCH_MXC
+
+menu "Freescale MXC Implementations"
+
+choice
+ prompt "MXC/iMX System Type"
+ default 0
+
+config ARCH_MX3
+ bool "MX3-based"
+ help
+ This enables support for systems based on the Freescale i.MX3 family
+
+endchoice
+
+source "arch/arm/mach-mx3/Kconfig"
+
+endmenu
+
+endif
diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile
new file mode 100644
index 000000000000..66ad9c2b6d64
--- /dev/null
+++ b/arch/arm/plat-mxc/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := irq.o
+
+obj-m :=
+obj-n :=
+obj- :=
diff --git a/arch/arm/plat-mxc/irq.c b/arch/arm/plat-mxc/irq.c
new file mode 100644
index 000000000000..87d253bc3d3c
--- /dev/null
+++ b/arch/arm/plat-mxc/irq.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/arch/common.h>
+
+/*!
+ * Disable interrupt number "irq" in the AVIC
+ *
+ * @param irq interrupt source number
+ */
+static void mxc_mask_irq(unsigned int irq)
+{
+ __raw_writel(irq, AVIC_INTDISNUM);
+}
+
+/*!
+ * Enable interrupt number "irq" in the AVIC
+ *
+ * @param irq interrupt source number
+ */
+static void mxc_unmask_irq(unsigned int irq)
+{
+ __raw_writel(irq, AVIC_INTENNUM);
+}
+
+static struct irq_chip mxc_avic_chip = {
+ .mask_ack = mxc_mask_irq,
+ .mask = mxc_mask_irq,
+ .unmask = mxc_unmask_irq,
+};
+
+/*!
+ * This function initializes the AVIC hardware and disables all the
+ * interrupts. It registers the interrupt enable and disable functions
+ * to the kernel for each interrupt source.
+ */
+void __init mxc_init_irq(void)
+{
+ int i;
+ u32 reg;
+
+ /* put the AVIC into the reset value with
+ * all interrupts disabled
+ */
+ __raw_writel(0, AVIC_INTCNTL);
+ __raw_writel(0x1f, AVIC_NIMASK);
+
+ /* disable all interrupts */
+ __raw_writel(0, AVIC_INTENABLEH);
+ __raw_writel(0, AVIC_INTENABLEL);
+
+ /* all IRQ no FIQ */
+ __raw_writel(0, AVIC_INTTYPEH);
+ __raw_writel(0, AVIC_INTTYPEL);
+ for (i = 0; i < MXC_MAX_INT_LINES; i++) {
+ set_irq_chip(i, &mxc_avic_chip);
+ set_irq_handler(i, handle_level_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ /* Set WDOG2's interrupt the highest priority level (bit 28-31) */
+ reg = __raw_readl(AVIC_NIPRIORITY6);
+ reg |= (0xF << 28);
+ __raw_writel(reg, AVIC_NIPRIORITY6);
+
+ printk(KERN_INFO "MXC IRQ initialized\n");
+}
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
index 2feceec8eccd..b0af014b0e2c 100644
--- a/arch/arm/plat-omap/timer32k.c
+++ b/arch/arm/plat-omap/timer32k.c
@@ -156,6 +156,8 @@ static void omap_32k_timer_set_mode(enum clock_event_mode mode,
case CLOCK_EVT_MODE_SHUTDOWN:
omap_32k_timer_stop();
break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
}
}
diff --git a/arch/arm/plat-s3c/Kconfig b/arch/arm/plat-s3c/Kconfig
new file mode 100644
index 000000000000..31656c33e05e
--- /dev/null
+++ b/arch/arm/plat-s3c/Kconfig
@@ -0,0 +1,104 @@
+# arch/arm/plat-s3c/Kconfig
+#
+# Copyright 2007 Simtec Electronics
+#
+# Licensed under GPLv2
+
+config PLAT_S3C
+ bool
+ depends on ARCH_S3C2410
+ default y if ARCH_S3C2410
+ select NO_IOPORT
+ help
+ Base platform code for any Samsung S3C device
+
+# low-level serial option nodes
+
+config CPU_LLSERIAL_S3C2410_ONLY
+ bool
+ depends on ARCH_S3C2410
+ default y if CPU_LLSERIAL_S3C2410 && !CPU_LLSERIAL_S3C2440
+
+config CPU_LLSERIAL_S3C2440_ONLY
+ bool
+ depends on ARCH_S3C2410
+ default y if CPU_LLSERIAL_S3C2440 && !CPU_LLSERIAL_S3C2410
+
+config CPU_LLSERIAL_S3C2410
+ bool
+ depends on ARCH_S3C2410
+ help
+ Selected if there is an S3C2410 (or register compatible) serial
+ low-level implementation needed
+
+config CPU_LLSERIAL_S3C2440
+ bool
+ depends on ARCH_S3C2410
+ help
+ Selected if there is an S3C2440 (or register compatible) serial
+ low-level implementation needed
+
+# boot configurations
+
+comment "Boot options"
+
+config S3C_BOOT_WATCHDOG
+ bool "S3C Initialisation watchdog"
+ depends on PLAT_S3C && S3C2410_WATCHDOG
+ help
+ Say y to enable the watchdog during the kernel decompression
+ stage. If the kernel fails to uncompress, then the watchdog
+ will trigger a reset and the system should restart.
+
+config S3C_BOOT_ERROR_RESET
+ bool "S3C Reboot on decompression error"
+ depends on PLAT_S3C
+ help
+ Say y here to use the watchdog to reset the system if the
+ kernel decompressor detects an error during decompression.
+
+comment "Power management"
+
+config S3C2410_PM_DEBUG
+ bool "S3C2410 PM Suspend debug"
+ depends on PLAT_S3C && PM
+ help
+ Say Y here if you want verbose debugging from the PM Suspend and
+ Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+ for more information.
+
+config S3C2410_PM_CHECK
+ bool "S3C2410 PM Suspend Memory CRC"
+ depends on PLAT_S3C && PM && CRC32
+ help
+ Enable the PM code's memory area checksum over sleep. This option
+ will generate CRCs of all blocks of memory, and store them before
+ going to sleep. The blocks are then checked on resume for any
+ errors.
+
+ Note, this can take several seconds depending on memory size
+ and CPU speed.
+
+ See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+
+config S3C2410_PM_CHECK_CHUNKSIZE
+ int "S3C2410 PM Suspend CRC Chunksize (KiB)"
+ depends on PLAT_S3C && PM && S3C2410_PM_CHECK
+ default 64
+ help
+ Set the chunksize in Kilobytes of the CRC for checking memory
+ corruption over suspend and resume. A smaller value will mean that
+ the CRC data block will take more memory, but wil identify any
+ faults with better precision.
+
+ See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
+
+config S3C_LOWLEVEL_UART_PORT
+ int "S3C UART to use for low-level messages"
+ depends on PLAT_S3C
+ default 0
+ help
+ Choice of which UART port to use for the low-level messages,
+ such as the `Uncompressing...` at start time. The value of
+ this configuration should be between zero and two. The port
+ must have been initialised by the boot-loader before use.
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index b972f36d547c..b66fb3c4e228 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -10,7 +10,7 @@ config PLAT_S3C24XX
default y if ARCH_S3C2410
select NO_IOPORT
help
- Base platform code for any Samsung S3C device
+ Base platform code for any Samsung S3C24XX device
if PLAT_S3C24XX
@@ -26,64 +26,6 @@ config PM_SIMTEC
Common power management code for systems that are
compatible with the Simtec style of power management
-config S3C2410_BOOT_WATCHDOG
- bool "S3C2410 Initialisation watchdog"
- depends on ARCH_S3C2410 && S3C2410_WATCHDOG
- help
- Say y to enable the watchdog during the kernel decompression
- stage. If the kernel fails to uncompress, then the watchdog
- will trigger a reset and the system should restart.
-
-config S3C2410_BOOT_ERROR_RESET
- bool "S3C2410 Reboot on decompression error"
- depends on ARCH_S3C2410
- help
- Say y here to use the watchdog to reset the system if the
- kernel decompressor detects an error during decompression.
-
-config S3C2410_PM_DEBUG
- bool "S3C2410 PM Suspend debug"
- depends on ARCH_S3C2410 && PM
- help
- Say Y here if you want verbose debugging from the PM Suspend and
- Resume code. See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
- for more information.
-
-config S3C2410_PM_CHECK
- bool "S3C2410 PM Suspend Memory CRC"
- depends on ARCH_S3C2410 && PM && CRC32
- help
- Enable the PM code's memory area checksum over sleep. This option
- will generate CRCs of all blocks of memory, and store them before
- going to sleep. The blocks are then checked on resume for any
- errors.
-
- Note, this can take several seconds depending on memory size
- and CPU speed.
-
- See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
-
-config S3C2410_PM_CHECK_CHUNKSIZE
- int "S3C2410 PM Suspend CRC Chunksize (KiB)"
- depends on ARCH_S3C2410 && PM && S3C2410_PM_CHECK
- default 64
- help
- Set the chunksize in Kilobytes of the CRC for checking memory
- corruption over suspend and resume. A smaller value will mean that
- the CRC data block will take more memory, but wil identify any
- faults with better precision.
-
- See <file:Documentation/arm/Samsung-S3C24XX/Suspend.txt>
-
-config S3C2410_LOWLEVEL_UART_PORT
- int "S3C2410 UART to use for low-level messages"
- default 0
- help
- Choice of which UART port to use for the low-level messages,
- such as the `Uncompressing...` at start time. The value of
- this configuration should be between zero and two. The port
- must have been initialised by the boot-loader before use.
-
config S3C2410_DMA
bool "S3C2410 DMA support"
depends on ARCH_S3C2410
diff --git a/arch/arm/plat-s3c24xx/common-smdk.c b/arch/arm/plat-s3c24xx/common-smdk.c
index 7ed19b23ce56..398c7ac25296 100644
--- a/arch/arm/plat-s3c24xx/common-smdk.c
+++ b/arch/arm/plat-s3c24xx/common-smdk.c
@@ -38,7 +38,7 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/leds-gpio.h>
-#include <asm/arch/nand.h>
+#include <asm/plat-s3c/nand.h>
#include <asm/plat-s3c24xx/common-smdk.h>
#include <asm/plat-s3c24xx/devs.h>
diff --git a/arch/arm/plat-s3c24xx/cpu.c b/arch/arm/plat-s3c24xx/cpu.c
index 8ce4904d3131..f513ab083b8f 100644
--- a/arch/arm/plat-s3c24xx/cpu.c
+++ b/arch/arm/plat-s3c24xx/cpu.c
@@ -38,7 +38,7 @@
#include <asm/mach/map.h>
#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/plat-s3c24xx/cpu.h>
#include <asm/plat-s3c24xx/devs.h>
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 5875da0ae0eb..e546e933b3f7 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -28,12 +28,12 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/arch/regs-serial.h>
-#include <asm/arch/udc.h>
+#include <asm/plat-s3c/regs-serial.h>
+#include <asm/plat-s3c24xx/udc.h>
#include <asm/plat-s3c24xx/devs.h>
#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
/* Serial port registrations */
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 08d80f2f51f2..6d048490c559 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -1333,7 +1333,7 @@ int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
dma_kmem = kmem_cache_create("dma_desc",
sizeof(struct s3c2410_dma_buf), 0,
SLAB_HWCACHE_ALIGN,
- s3c2410_dma_cache_ctor, NULL);
+ s3c2410_dma_cache_ctor);
if (dma_kmem == NULL) {
printk(KERN_ERR "dma failed to make kmem cache\n");
diff --git a/arch/arm/plat-s3c24xx/pm.c b/arch/arm/plat-s3c24xx/pm.c
index 5692eccdf4d1..eab1850616d8 100644
--- a/arch/arm/plat-s3c24xx/pm.c
+++ b/arch/arm/plat-s3c24xx/pm.c
@@ -40,7 +40,7 @@
#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
diff --git a/arch/arm/plat-s3c24xx/s3c244x.c b/arch/arm/plat-s3c24xx/s3c244x.c
index 767f2e9a3a55..3444b13afac5 100644
--- a/arch/arm/plat-s3c24xx/s3c244x.c
+++ b/arch/arm/plat-s3c24xx/s3c244x.c
@@ -30,7 +30,7 @@
#include <asm/irq.h>
#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-gpioj.h>
#include <asm/arch/regs-dsc.h>
@@ -47,7 +47,6 @@ static struct map_desc s3c244x_iodesc[] __initdata = {
IODESC_ENT(CLKPWR),
IODESC_ENT(TIMER),
IODESC_ENT(WATCHDOG),
- IODESC_ENT(LCD),
};
/* uart initialisation */
diff --git a/arch/arm/plat-s3c24xx/sleep.S b/arch/arm/plat-s3c24xx/sleep.S
index 7b7ae790b00d..d47113bbc34c 100644
--- a/arch/arm/plat-s3c24xx/sleep.S
+++ b/arch/arm/plat-s3c24xx/sleep.S
@@ -32,7 +32,7 @@
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-clock.h>
#include <asm/arch/regs-mem.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not
* reset the UART configuration, only enable if you really need this!
diff --git a/arch/arm/plat-s3c24xx/time.c b/arch/arm/plat-s3c24xx/time.c
index b7667375bcec..2ec1daaa0e53 100644
--- a/arch/arm/plat-s3c24xx/time.c
+++ b/arch/arm/plat-s3c24xx/time.c
@@ -33,7 +33,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/arch/map.h>
-#include <asm/arch/regs-timer.h>
+#include <asm/plat-s3c/regs-timer.h>
#include <asm/arch/regs-irq.h>
#include <asm/mach/time.h>
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index d4b7b229631d..0ac022f800a1 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -74,14 +74,14 @@ vfp_support_entry:
VFPFMRX r1, FPEXC @ Is the VFP enabled?
DBGSTR1 "fpexc %08x", r1
- tst r1, #FPEXC_ENABLE
+ tst r1, #FPEXC_EN
bne look_for_VFP_exceptions @ VFP is already enabled
DBGSTR1 "enable %x", r10
ldr r3, last_VFP_context_address
- orr r1, r1, #FPEXC_ENABLE @ user FPEXC has the enable bit set
+ orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set
ldr r4, [r3, r11, lsl #2] @ last_VFP_context pointer
- bic r5, r1, #FPEXC_EXCEPTION @ make sure exceptions are disabled
+ bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled
cmp r4, r10
beq check_for_exception @ we are returning to the same
@ process, so the registers are
@@ -124,7 +124,7 @@ no_old_VFP_process:
VFPFMXR FPSCR, r5 @ restore status
check_for_exception:
- tst r1, #FPEXC_EXCEPTION
+ tst r1, #FPEXC_EX
bne process_exception @ might as well handle the pending
@ exception before retrying branch
@ out before setting an FPEXC that
@@ -136,10 +136,10 @@ check_for_exception:
look_for_VFP_exceptions:
- tst r1, #FPEXC_EXCEPTION
+ tst r1, #FPEXC_EX
bne process_exception
VFPFMRX r5, FPSCR
- tst r5, #FPSCR_IXE @ IXE doesn't set FPEXC_EXCEPTION !
+ tst r5, #FPSCR_IXE @ IXE doesn't set FPEXC_EX !
bne process_exception
@ Fall into hand on to next handler - appropriate coproc instr
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 1106b5f9cf19..04ddab2bd876 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -53,7 +53,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
* case the thread migrates to a different CPU. The
* restoring is done lazily.
*/
- if ((fpexc & FPEXC_ENABLE) && last_VFP_context[cpu]) {
+ if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
vfp_save_state(last_VFP_context[cpu], fpexc);
last_VFP_context[cpu]->hard.cpu = cpu;
}
@@ -70,7 +70,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
* Always disable VFP so we can lazily save/restore the
* old state.
*/
- fmxr(FPEXC, fpexc & ~FPEXC_ENABLE);
+ fmxr(FPEXC, fpexc & ~FPEXC_EN);
return NOTIFY_DONE;
}
@@ -81,13 +81,13 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
*/
memset(vfp, 0, sizeof(union vfp_state));
- vfp->hard.fpexc = FPEXC_ENABLE;
+ vfp->hard.fpexc = FPEXC_EN;
vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
/*
* Disable VFP to ensure we initialise it first.
*/
- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
}
/* flush and release case: Per-thread VFP cleanup. */
@@ -229,7 +229,7 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
/*
* Enable access to the VFP so we can handle the bounce.
*/
- fmxr(FPEXC, fpexc & ~(FPEXC_EXCEPTION|FPEXC_INV|FPEXC_UFC|FPEXC_IOC));
+ fmxr(FPEXC, fpexc & ~(FPEXC_EX|FPEXC_INV|FPEXC_UFC|FPEXC_IOC));
orig_fpscr = fpscr = fmrx(FPSCR);
@@ -248,7 +248,7 @@ void VFP9_bounce(u32 trigger, u32 fpexc, struct pt_regs *regs)
/*
* Modify fpscr to indicate the number of iterations remaining
*/
- if (fpexc & FPEXC_EXCEPTION) {
+ if (fpexc & FPEXC_EX) {
u32 len;
len = fpexc + (1 << FPEXC_LENGTH_BIT);
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index 20688bc13e9b..9044f33299f7 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -17,6 +17,9 @@ config MMU
bool
default y
+config NO_DMA
+ def_bool y
+
config ARCH_ACORN
bool
default y
diff --git a/arch/arm26/defconfig b/arch/arm26/defconfig
index c4a89703c3d8..2b7d44bf49bf 100644
--- a/arch/arm26/defconfig
+++ b/arch/arm26/defconfig
@@ -248,7 +248,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_JBD_DEBUG is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c
index f735d7e018e4..fe1e3ceed7cb 100644
--- a/arch/arm26/kernel/armksyms.c
+++ b/arch/arm26/kernel/armksyms.c
@@ -107,8 +107,6 @@ EXPORT_SYMBOL(__bug);
#endif
EXPORT_SYMBOL(__bad_xchg);
EXPORT_SYMBOL(__readwrite_bug);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
EXPORT_SYMBOL(set_irq_type);
EXPORT_SYMBOL(pm_idle);
EXPORT_SYMBOL(pm_power_off);
diff --git a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c
index d53382c83bf9..2ffe695b062e 100644
--- a/arch/arm26/kernel/irq.c
+++ b/arch/arm26/kernel/irq.c
@@ -95,6 +95,11 @@ void disable_irq(unsigned int irq)
desc->enabled = 0;
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
+EXPORT_SYMBOL(disable_irq);
+
+void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq")));
+
+EXPORT_SYMBOL(disable_irq_nosync);
/**
* enable_irq - enable interrupt handling on an irq
@@ -131,6 +136,7 @@ void enable_irq(unsigned int irq)
}
spin_unlock_irqrestore(&irq_controller_lock, flags);
}
+EXPORT_SYMBOL(enable_irq);
int show_interrupts(struct seq_file *p, void *v)
{
diff --git a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c
index 416927956721..0fefb86970c6 100644
--- a/arch/arm26/kernel/ptrace.c
+++ b/arch/arm26/kernel/ptrace.c
@@ -531,7 +531,6 @@ static int ptrace_setfpregs(struct task_struct *tsk, void *ufp)
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
- unsigned long tmp;
int ret;
switch (request) {
@@ -540,12 +539,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
*/
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
- ret = access_process_vm(child, addr, &tmp,
- sizeof(unsigned long), 0);
- if (ret == sizeof(unsigned long))
- ret = put_user(tmp, (unsigned long *) data);
- else
- ret = -EIO;
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
case PTRACE_PEEKUSR:
@@ -557,12 +551,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
*/
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = access_process_vm(child, addr, &data,
- sizeof(unsigned long), 1);
- if (ret == sizeof(unsigned long))
- ret = 0;
- else
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR:
diff --git a/arch/arm26/kernel/traps.c b/arch/arm26/kernel/traps.c
index d594fb59e945..2911e2eae80e 100644
--- a/arch/arm26/kernel/traps.c
+++ b/arch/arm26/kernel/traps.c
@@ -185,6 +185,7 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
printk("Internal error: %s: %x\n", str, err);
printk("CPU: %d\n", smp_processor_id());
show_regs(regs);
+ add_taint(TAINT_DIE);
printk("Process %s (pid: %d, stack limit = 0x%p)\n",
current->comm, current->pid, end_of_stack(tsk));
diff --git a/arch/arm26/mm/fault.c b/arch/arm26/mm/fault.c
index 93c0cee0fb5e..dec638a0c8d9 100644
--- a/arch/arm26/mm/fault.c
+++ b/arch/arm26/mm/fault.c
@@ -170,20 +170,20 @@ good_area:
*/
survive:
fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(fsr));
-
- /*
- * Handle the "normal" cases first - successful and sigbus
- */
- switch (fault) {
- case VM_FAULT_MAJOR:
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ return fault;
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
tsk->maj_flt++;
- return fault;
- case VM_FAULT_MINOR:
+ else
tsk->min_flt++;
- case VM_FAULT_SIGBUS:
- return fault;
- }
+ return fault;
+out_of_memory:
fault = -3; /* out of memory */
if (!is_init(tsk))
goto out;
@@ -225,13 +225,11 @@ int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
/*
* Handle the "normal" case first
*/
- switch (fault) {
- case VM_FAULT_MINOR:
- case VM_FAULT_MAJOR:
+ if (likely(!(fault & VM_FAULT_ERROR)))
return 0;
- case VM_FAULT_SIGBUS:
+ if (fault & VM_FAULT_SIGBUS)
goto do_sigbus;
- }
+ /* else VM_FAULT_OOM */
/*
* If we are in kernel mode at this point, we
diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c
index 562fac12eb95..36e7ee3f8321 100644
--- a/arch/arm26/mm/init.c
+++ b/arch/arm26/mm/init.c
@@ -33,9 +33,6 @@
#include <asm/map.h>
-
-#define TABLE_SIZE PTRS_PER_PTE * sizeof(pte_t))
-
struct mmu_gather mmu_gathers[NR_CPUS];
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
diff --git a/arch/arm26/mm/memc.c b/arch/arm26/mm/memc.c
index 42505541a9b1..ffecd8578247 100644
--- a/arch/arm26/mm/memc.c
+++ b/arch/arm26/mm/memc.c
@@ -176,9 +176,9 @@ void __init pgtable_cache_init(void)
{
pte_cache = kmem_cache_create("pte-cache",
sizeof(pte_t) * PTRS_PER_PTE,
- 0, SLAB_PANIC, pte_cache_ctor, NULL);
+ 0, SLAB_PANIC, pte_cache_ctor);
pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE +
sizeof(pgd_t) * PTRS_PER_PGD,
- 0, SLAB_PANIC, pgd_cache_ctor, NULL);
+ 0, SLAB_PANIC, pgd_cache_ctor);
}
diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig
index 3ec76586877e..d12346aaa88b 100644
--- a/arch/avr32/Kconfig
+++ b/arch/avr32/Kconfig
@@ -113,6 +113,10 @@ config BOARD_ATNGW100
bool "ATNGW100 Network Gateway"
endchoice
+if BOARD_ATSTK1000
+source "arch/avr32/boards/atstk1000/Kconfig"
+endif
+
choice
prompt "Boot loader type"
default LOADER_U_BOOT
@@ -185,6 +189,27 @@ config CMDLINE
endmenu
+menu "Power managment options"
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+config CPU_FREQ_AT32AP
+ bool "CPU frequency driver for AT32AP"
+ depends on CPU_FREQ && PLATFORM_AT32AP
+ default n
+ help
+ This enables the CPU frequency driver for AT32AP processors.
+
+ For details, take a look in <file:Documentation/cpu-freq>.
+
+ If in doubt, say N.
+
+endmenu
+
+endmenu
+
menu "Bus options"
config PCI
diff --git a/arch/avr32/boards/atngw100/setup.c b/arch/avr32/boards/atngw100/setup.c
index 6c4dc0a00e9f..2edcecdea8bd 100644
--- a/arch/avr32/boards/atngw100/setup.c
+++ b/arch/avr32/boards/atngw100/setup.c
@@ -13,6 +13,7 @@
#include <linux/linkage.h>
#include <linux/platform_device.h>
#include <linux/types.h>
+#include <linux/leds.h>
#include <linux/spi/spi.h>
#include <asm/io.h>
@@ -21,6 +22,7 @@
#include <asm/arch/at32ap7000.h>
#include <asm/arch/board.h>
#include <asm/arch/init.h>
+#include <asm/arch/portmux.h>
/* Initialized by bootloader-specific startup code. */
struct tag *bootloader_tags __initdata;
@@ -100,8 +102,31 @@ void __init setup_board(void)
at32_setup_serial_console(0);
}
+static const struct gpio_led ngw_leds[] = {
+ { .name = "sys", .gpio = GPIO_PIN_PA(16), .active_low = 1,
+ .default_trigger = "heartbeat",
+ },
+ { .name = "a", .gpio = GPIO_PIN_PA(19), .active_low = 1, },
+ { .name = "b", .gpio = GPIO_PIN_PE(19), .active_low = 1, },
+};
+
+static const struct gpio_led_platform_data ngw_led_data = {
+ .num_leds = ARRAY_SIZE(ngw_leds),
+ .leds = (void *) ngw_leds,
+};
+
+static struct platform_device ngw_gpio_leds = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .platform_data = (void *) &ngw_led_data,
+ }
+};
+
static int __init atngw100_init(void)
{
+ unsigned i;
+
/*
* ATNGW100 uses 16-bit SDRAM interface, so we don't need to
* reserve any pins for it.
@@ -116,6 +141,12 @@ static int __init atngw100_init(void)
at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+ for (i = 0; i < ARRAY_SIZE(ngw_leds); i++) {
+ at32_select_gpio(ngw_leds[i].gpio,
+ AT32_GPIOF_OUTPUT | AT32_GPIOF_HIGH);
+ }
+ platform_device_register(&ngw_gpio_leds);
+
return 0;
}
postcore_initcall(atngw100_init);
diff --git a/arch/avr32/boards/atstk1000/Kconfig b/arch/avr32/boards/atstk1000/Kconfig
new file mode 100644
index 000000000000..71bc7d364fb7
--- /dev/null
+++ b/arch/avr32/boards/atstk1000/Kconfig
@@ -0,0 +1,53 @@
+# STK1000 customization
+
+if BOARD_ATSTK1002
+
+config BOARD_ATSTK1002_CUSTOM
+ bool "Non-default STK-1002 jumper settings"
+ help
+ You will normally leave the jumpers on the CPU card at their
+ default settings. If you need to use certain peripherals,
+ you will need to change some of those jumpers.
+
+if BOARD_ATSTK1002_CUSTOM
+
+config BOARD_ATSTK1002_SW1_CUSTOM
+ bool "SW1: use SSC1 (not SPI0)"
+ help
+ This also prevents using the external DAC as an audio interface,
+ and means you can't initialize the on-board QVGA display.
+
+config BOARD_ATSTK1002_SW2_CUSTOM
+ bool "SW2: use IRDA or TIMER0 (not UART-A, MMC/SD, and PS2-A)"
+ help
+ If you change this you'll want an updated boot loader putting
+ the console on UART-C not UART-A.
+
+config BOARD_ATSTK1002_SW3_CUSTOM
+ bool "SW3: use TIMER1 (not SSC0 and GCLK)"
+ help
+ This also prevents using the external DAC as an audio interface.
+
+config BOARD_ATSTK1002_SW4_CUSTOM
+ bool "SW4: use ISI/Camera (not GPIOs, SPI1, and PS2-B)"
+ help
+ To use the camera interface you'll need a custom card (on the
+ PCI-format connector) connect a video sensor.
+
+config BOARD_ATSTK1002_SW5_CUSTOM
+ bool "SW5: use MACB1 (not LCDC)"
+
+config BOARD_ATSTK1002_SW6_CUSTOM
+ bool "SW6: more GPIOs (not MACB0)"
+
+endif # custom
+
+config BOARD_ATSTK1002_SPI1
+ bool "Configure SPI1 controller"
+ depends on !BOARD_ATSTK1002_SW4_CUSTOM
+ help
+ All the signals for the second SPI controller are available on
+ GPIO lines and accessed through the J1 jumper block. Say "y"
+ here to configure that SPI controller.
+
+endif # stk 1002
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index e253e86a1a39..cb93eabb9c6c 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -27,15 +27,27 @@
#include "atstk1000.h"
-#define SW2_DEFAULT /* MMCI and UART_A available */
struct eth_addr {
u8 addr[6];
};
static struct eth_addr __initdata hw_addr[2];
-static struct eth_platform_data __initdata eth_data[2];
+static struct eth_platform_data __initdata eth_data[2] = {
+ {
+ /*
+ * The MDIO pullups on STK1000 are a bit too weak for
+ * the autodetection to work properly, so we have to
+ * mask out everything but the correct address.
+ */
+ .phy_mask = ~(1U << 16),
+ },
+ {
+ .phy_mask = ~(1U << 17),
+ },
+};
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
static struct spi_board_info spi0_board_info[] __initdata = {
{
/* QVGA display */
@@ -45,6 +57,13 @@ static struct spi_board_info spi0_board_info[] __initdata = {
.mode = SPI_MODE_3,
},
};
+#endif
+
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+static struct spi_board_info spi1_board_info[] __initdata = { {
+ /* patch in custom entries here */
+} };
+#endif
/*
* The next two functions should go away as the boot loader is
@@ -103,10 +122,10 @@ static void __init set_hw_addr(struct platform_device *pdev)
void __init setup_board(void)
{
-#ifdef SW2_DEFAULT
- at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */
-#else
+#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
at32_map_usart(0, 1); /* USART 0/B: /dev/ttyS1, IRDA */
+#else
+ at32_map_usart(1, 0); /* USART 1/A: /dev/ttyS0, DB9 */
#endif
/* USART 2/unused: expansion connector */
at32_map_usart(3, 2); /* USART 3/C: /dev/ttyS2, DB9 */
@@ -140,18 +159,31 @@ static int __init atstk1002_init(void)
at32_add_system_devices();
-#ifdef SW2_DEFAULT
- at32_add_device_usart(0);
-#else
+#ifdef CONFIG_BOARD_ATSTK1002_SW2_CUSTOM
at32_add_device_usart(1);
+#else
+ at32_add_device_usart(0);
#endif
at32_add_device_usart(2);
+#ifndef CONFIG_BOARD_ATSTK1002_SW6_CUSTOM
set_hw_addr(at32_add_device_eth(0, &eth_data[0]));
-
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW1_CUSTOM
at32_add_device_spi(0, spi0_board_info, ARRAY_SIZE(spi0_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK1002_SPI1
+ at32_add_device_spi(1, spi1_board_info, ARRAY_SIZE(spi1_board_info));
+#endif
+#ifdef CONFIG_BOARD_ATSTK1002_SW5_CUSTOM
+ set_hw_addr(at32_add_device_eth(1, &eth_data[1]));
+#else
at32_add_device_lcdc(0, &atstk1000_lcdc_data,
fbmem_start, fbmem_size);
+#endif
+#ifndef CONFIG_BOARD_ATSTK1002_SW3_CUSTOM
+ at32_add_device_ssc(0, ATMEL_SSC_TX);
+#endif
return 0;
}
diff --git a/arch/avr32/configs/atngw100_defconfig b/arch/avr32/configs/atngw100_defconfig
index 49493ad3b5a9..b799a68ffd97 100644
--- a/arch/avr32/configs/atngw100_defconfig
+++ b/arch/avr32/configs/atngw100_defconfig
@@ -712,7 +712,21 @@ CONFIG_SPI_ATMEL=y
#
# LED devices
#
-# CONFIG_NEW_LEDS is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_GPIO=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+
#
# LED drivers
diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c
index 3c36c2d16148..39060cbeb2a3 100644
--- a/arch/avr32/kernel/ptrace.c
+++ b/arch/avr32/kernel/ptrace.c
@@ -153,7 +153,6 @@ static int ptrace_setregs(struct task_struct *tsk, const void __user *uregs)
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
- unsigned long tmp;
int ret;
pr_debug("arch_ptrace(%ld, %d, %#lx, %#lx)\n",
@@ -166,11 +165,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Read the word at location addr in the child process */
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
- ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (ret == sizeof(tmp))
- ret = put_user(tmp, (unsigned long __user *)data);
- else
- ret = -EIO;
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
case PTRACE_PEEKUSR:
@@ -181,11 +176,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Write the word in data at location addr */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = access_process_vm(child, addr, &data, sizeof(data), 1);
- if (ret == sizeof(data))
- ret = 0;
- else
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR:
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index b279d66acf5f..d08b0bc6b2bb 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -313,7 +313,7 @@ __tagtable(ATAG_MEM, parse_tag_mem);
static int __init parse_tag_rdimg(struct tag *tag)
{
-#ifdef CONFIG_INITRD
+#ifdef CONFIG_BLK_DEV_INITRD
struct tag_mem_range *mem = &tag->u.mem_range;
int ret;
@@ -323,7 +323,7 @@ static int __init parse_tag_rdimg(struct tag *tag)
return 0;
}
- ret = add_reserved_region(mem->start, mem->start + mem->size - 1,
+ ret = add_reserved_region(mem->addr, mem->addr + mem->size - 1,
"initrd");
if (ret) {
printk(KERN_WARNING
diff --git a/arch/avr32/kernel/traps.c b/arch/avr32/kernel/traps.c
index 86d107511dd4..9a73ce7eb50f 100644
--- a/arch/avr32/kernel/traps.c
+++ b/arch/avr32/kernel/traps.c
@@ -56,6 +56,7 @@ void NORET_TYPE die(const char *str, struct pt_regs *regs, long err)
show_regs_log_lvl(regs, KERN_EMERG);
show_stack_log_lvl(current, regs->sp, regs, KERN_EMERG);
bust_spinlocks(0);
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
@@ -184,7 +185,7 @@ asmlinkage void do_illegal_opcode(unsigned long ecr, struct pt_regs *regs)
if (!user_mode(regs) && (ecr == ECR_ILLEGAL_OPCODE)) {
enum bug_trap_type type;
- type = report_bug(regs->pc);
+ type = report_bug(regs->pc, regs);
switch (type) {
case BUG_TRAP_TYPE_NONE:
break;
diff --git a/arch/avr32/mach-at32ap/Makefile b/arch/avr32/mach-at32ap/Makefile
index f1d395724ac6..a8b445046e3e 100644
--- a/arch/avr32/mach-at32ap/Makefile
+++ b/arch/avr32/mach-at32ap/Makefile
@@ -1,3 +1,4 @@
obj-y += at32ap.o clock.o intc.o extint.o pio.o hsmc.o
obj-$(CONFIG_CPU_AT32AP7000) += at32ap7000.o
obj-$(CONFIG_CPU_AT32AP7000) += time-tc.o
+obj-$(CONFIG_CPU_FREQ_AT32AP) += cpufreq.o
diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/at32ap.c
index 90f207e8e96d..7c4987f3287a 100644
--- a/arch/avr32/mach-at32ap/at32ap.c
+++ b/arch/avr32/mach-at32ap/at32ap.c
@@ -11,41 +11,10 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <asm/io.h>
-
#include <asm/arch/init.h>
-#include <asm/arch/sm.h>
-
-struct at32_sm system_manager;
-
-static int __init at32_sm_init(void)
-{
- struct resource *regs;
- struct at32_sm *sm = &system_manager;
- int ret = -ENXIO;
-
- regs = platform_get_resource(&at32_sm_device, IORESOURCE_MEM, 0);
- if (!regs)
- goto fail;
-
- spin_lock_init(&sm->lock);
- sm->pdev = &at32_sm_device;
-
- ret = -ENOMEM;
- sm->regs = ioremap(regs->start, regs->end - regs->start + 1);
- if (!sm->regs)
- goto fail;
-
- return 0;
-
-fail:
- printk(KERN_ERR "Failed to initialize System Manager: %d\n", ret);
- return ret;
-}
void __init setup_platform(void)
{
- at32_sm_init();
at32_clock_init();
at32_portmux_init();
}
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 4dda42d3f6d5..64cc5583ddfb 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -17,14 +17,20 @@
#include <asm/arch/at32ap7000.h>
#include <asm/arch/board.h>
#include <asm/arch/portmux.h>
-#include <asm/arch/sm.h>
#include <video/atmel_lcdc.h>
#include "clock.h"
#include "hmatrix.h"
#include "pio.h"
-#include "sm.h"
+#include "pm.h"
+
+/*
+ * We can reduce the code size a bit by using a constant here. Since
+ * this file is completely chip-specific, it's safe to not use
+ * ioremap. Generic drivers should of course never do this.
+ */
+#define AT32_PM_BASE 0xfff00000
#define PBMEM(base) \
{ \
@@ -88,6 +94,8 @@ static struct clk devname##_##_name = { \
.index = _index, \
}
+static DEFINE_SPINLOCK(pm_lock);
+
unsigned long at32ap7000_osc_rates[3] = {
[0] = 32768,
/* FIXME: these are ATSTK1002-specific */
@@ -104,11 +112,11 @@ static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
{
unsigned long div, mul, rate;
- if (!(control & SM_BIT(PLLEN)))
+ if (!(control & PM_BIT(PLLEN)))
return 0;
- div = SM_BFEXT(PLLDIV, control) + 1;
- mul = SM_BFEXT(PLLMUL, control) + 1;
+ div = PM_BFEXT(PLLDIV, control) + 1;
+ mul = PM_BFEXT(PLLMUL, control) + 1;
rate = clk->parent->get_rate(clk->parent);
rate = (rate + div / 2) / div;
@@ -121,7 +129,7 @@ static unsigned long pll0_get_rate(struct clk *clk)
{
u32 control;
- control = sm_readl(&system_manager, PM_PLL0);
+ control = pm_readl(PLL0);
return pll_get_rate(clk, control);
}
@@ -130,7 +138,7 @@ static unsigned long pll1_get_rate(struct clk *clk)
{
u32 control;
- control = sm_readl(&system_manager, PM_PLL1);
+ control = pm_readl(PLL1);
return pll_get_rate(clk, control);
}
@@ -187,108 +195,139 @@ static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
static void cpu_clk_mode(struct clk *clk, int enabled)
{
- struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&sm->lock, flags);
- mask = sm_readl(sm, PM_CPU_MASK);
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(CPU_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
- sm_writel(sm, PM_CPU_MASK, mask);
- spin_unlock_irqrestore(&sm->lock, flags);
+ pm_writel(CPU_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
}
static unsigned long cpu_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
- cksel = sm_readl(&system_manager, PM_CKSEL);
- if (cksel & SM_BIT(CPUDIV))
- shift = SM_BFEXT(CPUSEL, cksel) + 1;
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(CPUDIV))
+ shift = PM_BFEXT(CPUSEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
+static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
+{
+ u32 control;
+ unsigned long parent_rate, child_div, actual_rate, div;
+
+ parent_rate = clk->parent->get_rate(clk->parent);
+ control = pm_readl(CKSEL);
+
+ if (control & PM_BIT(HSBDIV))
+ child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
+ else
+ child_div = 1;
+
+ if (rate > 3 * (parent_rate / 4) || child_div == 1) {
+ actual_rate = parent_rate;
+ control &= ~PM_BIT(CPUDIV);
+ } else {
+ unsigned int cpusel;
+ div = (parent_rate + rate / 2) / rate;
+ if (div > child_div)
+ div = child_div;
+ cpusel = (div > 1) ? (fls(div) - 2) : 0;
+ control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
+ actual_rate = parent_rate / (1 << (cpusel + 1));
+ }
+
+ pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
+ clk->name, rate, actual_rate);
+
+ if (apply)
+ pm_writel(CKSEL, control);
+
+ return actual_rate;
+}
+
static void hsb_clk_mode(struct clk *clk, int enabled)
{
- struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&sm->lock, flags);
- mask = sm_readl(sm, PM_HSB_MASK);
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(HSB_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
- sm_writel(sm, PM_HSB_MASK, mask);
- spin_unlock_irqrestore(&sm->lock, flags);
+ pm_writel(HSB_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
}
static unsigned long hsb_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
- cksel = sm_readl(&system_manager, PM_CKSEL);
- if (cksel & SM_BIT(HSBDIV))
- shift = SM_BFEXT(HSBSEL, cksel) + 1;
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(HSBDIV))
+ shift = PM_BFEXT(HSBSEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
static void pba_clk_mode(struct clk *clk, int enabled)
{
- struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&sm->lock, flags);
- mask = sm_readl(sm, PM_PBA_MASK);
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(PBA_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
- sm_writel(sm, PM_PBA_MASK, mask);
- spin_unlock_irqrestore(&sm->lock, flags);
+ pm_writel(PBA_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
}
static unsigned long pba_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
- cksel = sm_readl(&system_manager, PM_CKSEL);
- if (cksel & SM_BIT(PBADIV))
- shift = SM_BFEXT(PBASEL, cksel) + 1;
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(PBADIV))
+ shift = PM_BFEXT(PBASEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
static void pbb_clk_mode(struct clk *clk, int enabled)
{
- struct at32_sm *sm = &system_manager;
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&sm->lock, flags);
- mask = sm_readl(sm, PM_PBB_MASK);
+ spin_lock_irqsave(&pm_lock, flags);
+ mask = pm_readl(PBB_MASK);
if (enabled)
mask |= 1 << clk->index;
else
mask &= ~(1 << clk->index);
- sm_writel(sm, PM_PBB_MASK, mask);
- spin_unlock_irqrestore(&sm->lock, flags);
+ pm_writel(PBB_MASK, mask);
+ spin_unlock_irqrestore(&pm_lock, flags);
}
static unsigned long pbb_clk_get_rate(struct clk *clk)
{
unsigned long cksel, shift = 0;
- cksel = sm_readl(&system_manager, PM_CKSEL);
- if (cksel & SM_BIT(PBBDIV))
- shift = SM_BFEXT(PBBSEL, cksel) + 1;
+ cksel = pm_readl(CKSEL);
+ if (cksel & PM_BIT(PBBDIV))
+ shift = PM_BFEXT(PBBSEL, cksel) + 1;
return bus_clk_get_rate(clk, shift);
}
@@ -296,6 +335,7 @@ static unsigned long pbb_clk_get_rate(struct clk *clk)
static struct clk cpu_clk = {
.name = "cpu",
.get_rate = cpu_clk_get_rate,
+ .set_rate = cpu_clk_set_rate,
.users = 1,
};
static struct clk hsb_clk = {
@@ -327,12 +367,12 @@ static void genclk_mode(struct clk *clk, int enabled)
{
u32 control;
- control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+ control = pm_readl(GCCTRL(clk->index));
if (enabled)
- control |= SM_BIT(CEN);
+ control |= PM_BIT(CEN);
else
- control &= ~SM_BIT(CEN);
- sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+ control &= ~PM_BIT(CEN);
+ pm_writel(GCCTRL(clk->index), control);
}
static unsigned long genclk_get_rate(struct clk *clk)
@@ -340,9 +380,9 @@ static unsigned long genclk_get_rate(struct clk *clk)
u32 control;
unsigned long div = 1;
- control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
- if (control & SM_BIT(DIVEN))
- div = 2 * (SM_BFEXT(DIV, control) + 1);
+ control = pm_readl(GCCTRL(clk->index));
+ if (control & PM_BIT(DIVEN))
+ div = 2 * (PM_BFEXT(DIV, control) + 1);
return clk->parent->get_rate(clk->parent) / div;
}
@@ -353,23 +393,22 @@ static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
unsigned long parent_rate, actual_rate, div;
parent_rate = clk->parent->get_rate(clk->parent);
- control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+ control = pm_readl(GCCTRL(clk->index));
if (rate > 3 * parent_rate / 4) {
actual_rate = parent_rate;
- control &= ~SM_BIT(DIVEN);
+ control &= ~PM_BIT(DIVEN);
} else {
div = (parent_rate + rate) / (2 * rate) - 1;
- control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN);
+ control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
actual_rate = parent_rate / (2 * (div + 1));
}
- printk("clk %s: new rate %lu (actual rate %lu)\n",
- clk->name, rate, actual_rate);
+ dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
+ clk->name, rate, actual_rate);
if (apply)
- sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index,
- control);
+ pm_writel(GCCTRL(clk->index), control);
return actual_rate;
}
@@ -378,24 +417,24 @@ int genclk_set_parent(struct clk *clk, struct clk *parent)
{
u32 control;
- printk("clk %s: new parent %s (was %s)\n",
- clk->name, parent->name, clk->parent->name);
+ dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
+ clk->name, parent->name, clk->parent->name);
- control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
+ control = pm_readl(GCCTRL(clk->index));
if (parent == &osc1 || parent == &pll1)
- control |= SM_BIT(OSCSEL);
+ control |= PM_BIT(OSCSEL);
else if (parent == &osc0 || parent == &pll0)
- control &= ~SM_BIT(OSCSEL);
+ control &= ~PM_BIT(OSCSEL);
else
return -EINVAL;
if (parent == &pll0 || parent == &pll1)
- control |= SM_BIT(PLLSEL);
+ control |= PM_BIT(PLLSEL);
else
- control &= ~SM_BIT(PLLSEL);
+ control &= ~PM_BIT(PLLSEL);
- sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control);
+ pm_writel(GCCTRL(clk->index), control);
clk->parent = parent;
return 0;
@@ -408,11 +447,11 @@ static void __init genclk_init_parent(struct clk *clk)
BUG_ON(clk->index > 7);
- control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index);
- if (control & SM_BIT(OSCSEL))
- parent = (control & SM_BIT(PLLSEL)) ? &pll1 : &osc1;
+ control = pm_readl(GCCTRL(clk->index));
+ if (control & PM_BIT(OSCSEL))
+ parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
else
- parent = (control & SM_BIT(PLLSEL)) ? &pll0 : &osc0;
+ parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
clk->parent = parent;
}
@@ -420,21 +459,53 @@ static void __init genclk_init_parent(struct clk *clk)
/* --------------------------------------------------------------------
* System peripherals
* -------------------------------------------------------------------- */
-static struct resource sm_resource[] = {
- PBMEM(0xfff00000),
- NAMED_IRQ(19, "eim"),
- NAMED_IRQ(20, "pm"),
- NAMED_IRQ(21, "rtc"),
+static struct resource at32_pm0_resource[] = {
+ {
+ .start = 0xfff00000,
+ .end = 0xfff0007f,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(20),
};
-struct platform_device at32_sm_device = {
- .name = "sm",
- .id = 0,
- .resource = sm_resource,
- .num_resources = ARRAY_SIZE(sm_resource),
+
+static struct resource at32ap700x_rtc0_resource[] = {
+ {
+ .start = 0xfff00080,
+ .end = 0xfff000af,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(21),
+};
+
+static struct resource at32_wdt0_resource[] = {
+ {
+ .start = 0xfff000b0,
+ .end = 0xfff000bf,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct resource at32_eic0_resource[] = {
+ {
+ .start = 0xfff00100,
+ .end = 0xfff0013f,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ(19),
};
-static struct clk at32_sm_pclk = {
+
+DEFINE_DEV(at32_pm, 0);
+DEFINE_DEV(at32ap700x_rtc, 0);
+DEFINE_DEV(at32_wdt, 0);
+DEFINE_DEV(at32_eic, 0);
+
+/*
+ * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
+ * is always running.
+ */
+static struct clk at32_pm_pclk = {
.name = "pclk",
- .dev = &at32_sm_device.dev,
+ .dev = &at32_pm0_device.dev,
.parent = &pbb_clk,
.mode = pbb_clk_mode,
.get_rate = pbb_clk_get_rate,
@@ -583,10 +654,11 @@ DEV_CLK(mck, pio4, pba, 14);
void __init at32_add_system_devices(void)
{
- system_manager.eim_first_irq = EIM_IRQ_BASE;
-
- platform_device_register(&at32_sm_device);
+ platform_device_register(&at32_pm0_device);
platform_device_register(&at32_intc0_device);
+ platform_device_register(&at32ap700x_rtc0_device);
+ platform_device_register(&at32_wdt0_device);
+ platform_device_register(&at32_eic0_device);
platform_device_register(&smc0_device);
platform_device_register(&pdc_device);
@@ -1013,6 +1085,89 @@ err_dup_modedb:
}
/* --------------------------------------------------------------------
+ * SSC
+ * -------------------------------------------------------------------- */
+static struct resource ssc0_resource[] = {
+ PBMEM(0xffe01c00),
+ IRQ(10),
+};
+DEFINE_DEV(ssc, 0);
+DEV_CLK(pclk, ssc0, pba, 7);
+
+static struct resource ssc1_resource[] = {
+ PBMEM(0xffe02000),
+ IRQ(11),
+};
+DEFINE_DEV(ssc, 1);
+DEV_CLK(pclk, ssc1, pba, 8);
+
+static struct resource ssc2_resource[] = {
+ PBMEM(0xffe02400),
+ IRQ(12),
+};
+DEFINE_DEV(ssc, 2);
+DEV_CLK(pclk, ssc2, pba, 9);
+
+struct platform_device *__init
+at32_add_device_ssc(unsigned int id, unsigned int flags)
+{
+ struct platform_device *pdev;
+
+ switch (id) {
+ case 0:
+ pdev = &ssc0_device;
+ if (flags & ATMEL_SSC_RF)
+ select_peripheral(PA(21), PERIPH_A, 0); /* RF */
+ if (flags & ATMEL_SSC_RK)
+ select_peripheral(PA(22), PERIPH_A, 0); /* RK */
+ if (flags & ATMEL_SSC_TK)
+ select_peripheral(PA(23), PERIPH_A, 0); /* TK */
+ if (flags & ATMEL_SSC_TF)
+ select_peripheral(PA(24), PERIPH_A, 0); /* TF */
+ if (flags & ATMEL_SSC_TD)
+ select_peripheral(PA(25), PERIPH_A, 0); /* TD */
+ if (flags & ATMEL_SSC_RD)
+ select_peripheral(PA(26), PERIPH_A, 0); /* RD */
+ break;
+ case 1:
+ pdev = &ssc1_device;
+ if (flags & ATMEL_SSC_RF)
+ select_peripheral(PA(0), PERIPH_B, 0); /* RF */
+ if (flags & ATMEL_SSC_RK)
+ select_peripheral(PA(1), PERIPH_B, 0); /* RK */
+ if (flags & ATMEL_SSC_TK)
+ select_peripheral(PA(2), PERIPH_B, 0); /* TK */
+ if (flags & ATMEL_SSC_TF)
+ select_peripheral(PA(3), PERIPH_B, 0); /* TF */
+ if (flags & ATMEL_SSC_TD)
+ select_peripheral(PA(4), PERIPH_B, 0); /* TD */
+ if (flags & ATMEL_SSC_RD)
+ select_peripheral(PA(5), PERIPH_B, 0); /* RD */
+ break;
+ case 2:
+ pdev = &ssc2_device;
+ if (flags & ATMEL_SSC_TD)
+ select_peripheral(PB(13), PERIPH_A, 0); /* TD */
+ if (flags & ATMEL_SSC_RD)
+ select_peripheral(PB(14), PERIPH_A, 0); /* RD */
+ if (flags & ATMEL_SSC_TK)
+ select_peripheral(PB(15), PERIPH_A, 0); /* TK */
+ if (flags & ATMEL_SSC_TF)
+ select_peripheral(PB(16), PERIPH_A, 0); /* TF */
+ if (flags & ATMEL_SSC_RF)
+ select_peripheral(PB(17), PERIPH_A, 0); /* RF */
+ if (flags & ATMEL_SSC_RK)
+ select_peripheral(PB(18), PERIPH_A, 0); /* RK */
+ break;
+ default:
+ return NULL;
+ }
+
+ platform_device_register(pdev);
+ return pdev;
+}
+
+/* --------------------------------------------------------------------
* GCLK
* -------------------------------------------------------------------- */
static struct clk gclk0 = {
@@ -1066,7 +1221,7 @@ struct clk *at32_clock_list[] = {
&hsb_clk,
&pba_clk,
&pbb_clk,
- &at32_sm_pclk,
+ &at32_pm_pclk,
&at32_intc0_pclk,
&hmatrix_clk,
&ebi_clk,
@@ -1094,6 +1249,9 @@ struct clk *at32_clock_list[] = {
&atmel_spi1_spi_clk,
&atmel_lcdfb0_hck1,
&atmel_lcdfb0_pixclk,
+ &ssc0_pclk,
+ &ssc1_pclk,
+ &ssc2_pclk,
&gclk0,
&gclk1,
&gclk2,
@@ -1113,18 +1271,20 @@ void __init at32_portmux_init(void)
void __init at32_clock_init(void)
{
- struct at32_sm *sm = &system_manager;
u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
int i;
- if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL))
+ if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
main_clock = &pll0;
- else
+ cpu_clk.parent = &pll0;
+ } else {
main_clock = &osc0;
+ cpu_clk.parent = &osc0;
+ }
- if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC))
+ if (pm_readl(PLL0) & PM_BIT(PLLOSC))
pll0.parent = &osc1;
- if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC))
+ if (pm_readl(PLL1) & PM_BIT(PLLOSC))
pll1.parent = &osc1;
genclk_init_parent(&gclk0);
@@ -1157,8 +1317,8 @@ void __init at32_clock_init(void)
pbb_mask |= 1 << clk->index;
}
- sm_writel(sm, PM_CPU_MASK, cpu_mask);
- sm_writel(sm, PM_HSB_MASK, hsb_mask);
- sm_writel(sm, PM_PBA_MASK, pba_mask);
- sm_writel(sm, PM_PBB_MASK, pbb_mask);
+ pm_writel(CPU_MASK, cpu_mask);
+ pm_writel(HSB_MASK, hsb_mask);
+ pm_writel(PBA_MASK, pba_mask);
+ pm_writel(PBB_MASK, pbb_mask);
}
diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c
new file mode 100644
index 000000000000..235524b79193
--- /dev/null
+++ b/arch/avr32/mach-at32ap/cpufreq.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * Based on MIPS implementation arch/mips/kernel/time.c
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/system.h>
+
+static struct clk *cpuclk;
+
+static int at32_verify_speed(struct cpufreq_policy *policy)
+{
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ return 0;
+}
+
+static unsigned int at32_get_speed(unsigned int cpu)
+{
+ /* No SMP support */
+ if (cpu)
+ return 0;
+ return (unsigned int)((clk_get_rate(cpuclk) + 500) / 1000);
+}
+
+static int at32_set_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ long freq;
+
+ /* Convert target_freq from kHz to Hz */
+ freq = clk_round_rate(cpuclk, target_freq * 1000);
+
+ /* Check if policy->min <= new_freq <= policy->max */
+ if(freq < (policy->min * 1000) || freq > (policy->max * 1000))
+ return -EINVAL;
+
+ pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+
+ freqs.old = at32_get_speed(0);
+ freqs.new = (freq + 500) / 1000;
+ freqs.cpu = 0;
+ freqs.flags = 0;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ clk_set_rate(cpuclk, freq);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
+ return 0;
+}
+
+static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ cpuclk = clk_get(NULL, "cpu");
+ if (IS_ERR(cpuclk)) {
+ pr_debug("cpufreq: could not get CPU clk\n");
+ return PTR_ERR(cpuclk);
+ }
+
+ policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+ policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
+ policy->cpuinfo.transition_latency = 0;
+ policy->cur = at32_get_speed(0);
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ printk("cpufreq: AT32AP CPU frequency driver\n");
+
+ return 0;
+}
+
+static struct cpufreq_driver at32_driver = {
+ .name = "at32ap",
+ .owner = THIS_MODULE,
+ .init = at32_cpufreq_driver_init,
+ .verify = at32_verify_speed,
+ .target = at32_set_target,
+ .get = at32_get_speed,
+ .flags = CPUFREQ_STICKY,
+};
+
+static int __init at32_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&at32_driver);
+}
+
+arch_initcall(at32_cpufreq_init);
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
index 4a60eccfebd2..8acd01090031 100644
--- a/arch/avr32/mach-at32ap/extint.c
+++ b/arch/avr32/mach-at32ap/extint.c
@@ -17,42 +17,83 @@
#include <asm/io.h>
-#include <asm/arch/sm.h>
-
-#include "sm.h"
+/* EIC register offsets */
+#define EIC_IER 0x0000
+#define EIC_IDR 0x0004
+#define EIC_IMR 0x0008
+#define EIC_ISR 0x000c
+#define EIC_ICR 0x0010
+#define EIC_MODE 0x0014
+#define EIC_EDGE 0x0018
+#define EIC_LEVEL 0x001c
+#define EIC_TEST 0x0020
+#define EIC_NMIC 0x0024
+
+/* Bitfields in TEST */
+#define EIC_TESTEN_OFFSET 31
+#define EIC_TESTEN_SIZE 1
+
+/* Bitfields in NMIC */
+#define EIC_EN_OFFSET 0
+#define EIC_EN_SIZE 1
+
+/* Bit manipulation macros */
+#define EIC_BIT(name) \
+ (1 << EIC_##name##_OFFSET)
+#define EIC_BF(name,value) \
+ (((value) & ((1 << EIC_##name##_SIZE) - 1)) \
+ << EIC_##name##_OFFSET)
+#define EIC_BFEXT(name,value) \
+ (((value) >> EIC_##name##_OFFSET) \
+ & ((1 << EIC_##name##_SIZE) - 1))
+#define EIC_BFINS(name,value,old) \
+ (((old) & ~(((1 << EIC_##name##_SIZE) - 1) \
+ << EIC_##name##_OFFSET)) \
+ | EIC_BF(name,value))
+
+/* Register access macros */
+#define eic_readl(port,reg) \
+ __raw_readl((port)->regs + EIC_##reg)
+#define eic_writel(port,reg,value) \
+ __raw_writel((value), (port)->regs + EIC_##reg)
+
+struct eic {
+ void __iomem *regs;
+ struct irq_chip *chip;
+ unsigned int first_irq;
+};
-static void eim_ack_irq(unsigned int irq)
+static void eic_ack_irq(unsigned int irq)
{
- struct at32_sm *sm = get_irq_chip_data(irq);
- sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
+ struct eic *eic = get_irq_chip_data(irq);
+ eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
}
-static void eim_mask_irq(unsigned int irq)
+static void eic_mask_irq(unsigned int irq)
{
- struct at32_sm *sm = get_irq_chip_data(irq);
- sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+ struct eic *eic = get_irq_chip_data(irq);
+ eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
}
-static void eim_mask_ack_irq(unsigned int irq)
+static void eic_mask_ack_irq(unsigned int irq)
{
- struct at32_sm *sm = get_irq_chip_data(irq);
- sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq));
- sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq));
+ struct eic *eic = get_irq_chip_data(irq);
+ eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
+ eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
}
-static void eim_unmask_irq(unsigned int irq)
+static void eic_unmask_irq(unsigned int irq)
{
- struct at32_sm *sm = get_irq_chip_data(irq);
- sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq));
+ struct eic *eic = get_irq_chip_data(irq);
+ eic_writel(eic, IER, 1 << (irq - eic->first_irq));
}
-static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
+static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
{
- struct at32_sm *sm = get_irq_chip_data(irq);
+ struct eic *eic = get_irq_chip_data(irq);
struct irq_desc *desc;
- unsigned int i = irq - sm->eim_first_irq;
+ unsigned int i = irq - eic->first_irq;
u32 mode, edge, level;
- unsigned long flags;
int ret = 0;
flow_type &= IRQ_TYPE_SENSE_MASK;
@@ -60,11 +101,10 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
flow_type = IRQ_TYPE_LEVEL_LOW;
desc = &irq_desc[irq];
- spin_lock_irqsave(&sm->lock, flags);
- mode = sm_readl(sm, EIM_MODE);
- edge = sm_readl(sm, EIM_EDGE);
- level = sm_readl(sm, EIM_LEVEL);
+ mode = eic_readl(eic, MODE);
+ edge = eic_readl(eic, EDGE);
+ level = eic_readl(eic, LEVEL);
switch (flow_type) {
case IRQ_TYPE_LEVEL_LOW:
@@ -89,9 +129,9 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
}
if (ret == 0) {
- sm_writel(sm, EIM_MODE, mode);
- sm_writel(sm, EIM_EDGE, edge);
- sm_writel(sm, EIM_LEVEL, level);
+ eic_writel(eic, MODE, mode);
+ eic_writel(eic, EDGE, edge);
+ eic_writel(eic, LEVEL, level);
if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
flow_type |= IRQ_LEVEL;
@@ -99,35 +139,33 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type)
desc->status |= flow_type;
}
- spin_unlock_irqrestore(&sm->lock, flags);
-
return ret;
}
-struct irq_chip eim_chip = {
- .name = "eim",
- .ack = eim_ack_irq,
- .mask = eim_mask_irq,
- .mask_ack = eim_mask_ack_irq,
- .unmask = eim_unmask_irq,
- .set_type = eim_set_irq_type,
+struct irq_chip eic_chip = {
+ .name = "eic",
+ .ack = eic_ack_irq,
+ .mask = eic_mask_irq,
+ .mask_ack = eic_mask_ack_irq,
+ .unmask = eic_unmask_irq,
+ .set_type = eic_set_irq_type,
};
-static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
+static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
{
- struct at32_sm *sm = desc->handler_data;
+ struct eic *eic = desc->handler_data;
struct irq_desc *ext_desc;
unsigned long status, pending;
unsigned int i, ext_irq;
- status = sm_readl(sm, EIM_ISR);
- pending = status & sm_readl(sm, EIM_IMR);
+ status = eic_readl(eic, ISR);
+ pending = status & eic_readl(eic, IMR);
while (pending) {
i = fls(pending) - 1;
pending &= ~(1 << i);
- ext_irq = i + sm->eim_first_irq;
+ ext_irq = i + eic->first_irq;
ext_desc = irq_desc + ext_irq;
if (ext_desc->status & IRQ_LEVEL)
handle_level_irq(ext_irq, ext_desc);
@@ -136,51 +174,85 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
}
}
-static int __init eim_init(void)
+static int __init eic_probe(struct platform_device *pdev)
{
- struct at32_sm *sm = &system_manager;
+ struct eic *eic;
+ struct resource *regs;
unsigned int i;
unsigned int nr_irqs;
unsigned int int_irq;
+ int ret;
u32 pattern;
- /*
- * The EIM is really the same module as SM, so register
- * mapping, etc. has been taken care of already.
- */
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int_irq = platform_get_irq(pdev, 0);
+ if (!regs || !int_irq) {
+ dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
+ return -ENXIO;
+ }
+
+ ret = -ENOMEM;
+ eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
+ if (!eic) {
+ dev_dbg(&pdev->dev, "no memory for eic structure\n");
+ goto err_kzalloc;
+ }
+
+ eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
+ eic->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!eic->regs) {
+ dev_dbg(&pdev->dev, "failed to map regs\n");
+ goto err_ioremap;
+ }
/*
* Find out how many interrupt lines that are actually
* implemented in hardware.
*/
- sm_writel(sm, EIM_IDR, ~0UL);
- sm_writel(sm, EIM_MODE, ~0UL);
- pattern = sm_readl(sm, EIM_MODE);
+ eic_writel(eic, IDR, ~0UL);
+ eic_writel(eic, MODE, ~0UL);
+ pattern = eic_readl(eic, MODE);
nr_irqs = fls(pattern);
/* Trigger on falling edge unless overridden by driver */
- sm_writel(sm, EIM_MODE, 0UL);
- sm_writel(sm, EIM_EDGE, 0UL);
+ eic_writel(eic, MODE, 0UL);
+ eic_writel(eic, EDGE, 0UL);
- sm->eim_chip = &eim_chip;
+ eic->chip = &eic_chip;
for (i = 0; i < nr_irqs; i++) {
/* NOTE the handler we set here is ignored by the demux */
- set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip,
+ set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
handle_level_irq);
- set_irq_chip_data(sm->eim_first_irq + i, sm);
+ set_irq_chip_data(eic->first_irq + i, eic);
}
- int_irq = platform_get_irq_byname(sm->pdev, "eim");
-
- set_irq_chained_handler(int_irq, demux_eim_irq);
- set_irq_data(int_irq, sm);
+ set_irq_chained_handler(int_irq, demux_eic_irq);
+ set_irq_data(int_irq, eic);
- printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n",
- sm->regs, int_irq);
- printk("EIM: Handling %u external IRQs, starting with IRQ %u\n",
- nr_irqs, sm->eim_first_irq);
+ dev_info(&pdev->dev,
+ "External Interrupt Controller at 0x%p, IRQ %u\n",
+ eic->regs, int_irq);
+ dev_info(&pdev->dev,
+ "Handling %u external IRQs, starting with IRQ %u\n",
+ nr_irqs, eic->first_irq);
return 0;
+
+err_ioremap:
+ kfree(eic);
+err_kzalloc:
+ return ret;
+}
+
+static struct platform_driver eic_driver = {
+ .driver = {
+ .name = "at32_eic",
+ },
+};
+
+static int __init eic_init(void)
+{
+ return platform_driver_probe(&eic_driver, eic_probe);
}
-arch_initcall(eim_init);
+arch_initcall(eic_init);
diff --git a/arch/avr32/mach-at32ap/pm.h b/arch/avr32/mach-at32ap/pm.h
new file mode 100644
index 000000000000..a1f8aced0a8c
--- /dev/null
+++ b/arch/avr32/mach-at32ap/pm.h
@@ -0,0 +1,112 @@
+/*
+ * Register definitions for the Power Manager (PM)
+ */
+#ifndef __ARCH_AVR32_MACH_AT32AP_PM_H__
+#define __ARCH_AVR32_MACH_AT32AP_PM_H__
+
+/* PM register offsets */
+#define PM_MCCTRL 0x0000
+#define PM_CKSEL 0x0004
+#define PM_CPU_MASK 0x0008
+#define PM_HSB_MASK 0x000c
+#define PM_PBA_MASK 0x0010
+#define PM_PBB_MASK 0x0014
+#define PM_PLL0 0x0020
+#define PM_PLL1 0x0024
+#define PM_IER 0x0040
+#define PM_IDR 0x0044
+#define PM_IMR 0x0048
+#define PM_ISR 0x004c
+#define PM_ICR 0x0050
+#define PM_GCCTRL(x) (0x0060 + 4 * (x))
+#define PM_RCAUSE 0x00c0
+
+/* Bitfields in CKSEL */
+#define PM_CPUSEL_OFFSET 0
+#define PM_CPUSEL_SIZE 3
+#define PM_CPUDIV_OFFSET 7
+#define PM_CPUDIV_SIZE 1
+#define PM_HSBSEL_OFFSET 8
+#define PM_HSBSEL_SIZE 3
+#define PM_HSBDIV_OFFSET 15
+#define PM_HSBDIV_SIZE 1
+#define PM_PBASEL_OFFSET 16
+#define PM_PBASEL_SIZE 3
+#define PM_PBADIV_OFFSET 23
+#define PM_PBADIV_SIZE 1
+#define PM_PBBSEL_OFFSET 24
+#define PM_PBBSEL_SIZE 3
+#define PM_PBBDIV_OFFSET 31
+#define PM_PBBDIV_SIZE 1
+
+/* Bitfields in PLL0 */
+#define PM_PLLEN_OFFSET 0
+#define PM_PLLEN_SIZE 1
+#define PM_PLLOSC_OFFSET 1
+#define PM_PLLOSC_SIZE 1
+#define PM_PLLOPT_OFFSET 2
+#define PM_PLLOPT_SIZE 3
+#define PM_PLLDIV_OFFSET 8
+#define PM_PLLDIV_SIZE 8
+#define PM_PLLMUL_OFFSET 16
+#define PM_PLLMUL_SIZE 8
+#define PM_PLLCOUNT_OFFSET 24
+#define PM_PLLCOUNT_SIZE 6
+#define PM_PLLTEST_OFFSET 31
+#define PM_PLLTEST_SIZE 1
+
+/* Bitfields in ICR */
+#define PM_LOCK0_OFFSET 0
+#define PM_LOCK0_SIZE 1
+#define PM_LOCK1_OFFSET 1
+#define PM_LOCK1_SIZE 1
+#define PM_WAKE_OFFSET 2
+#define PM_WAKE_SIZE 1
+#define PM_CKRDY_OFFSET 5
+#define PM_CKRDY_SIZE 1
+#define PM_MSKRDY_OFFSET 6
+#define PM_MSKRDY_SIZE 1
+
+/* Bitfields in GCCTRL0 */
+#define PM_OSCSEL_OFFSET 0
+#define PM_OSCSEL_SIZE 1
+#define PM_PLLSEL_OFFSET 1
+#define PM_PLLSEL_SIZE 1
+#define PM_CEN_OFFSET 2
+#define PM_CEN_SIZE 1
+#define PM_DIVEN_OFFSET 4
+#define PM_DIVEN_SIZE 1
+#define PM_DIV_OFFSET 8
+#define PM_DIV_SIZE 8
+
+/* Bitfields in RCAUSE */
+#define PM_POR_OFFSET 0
+#define PM_POR_SIZE 1
+#define PM_EXT_OFFSET 2
+#define PM_EXT_SIZE 1
+#define PM_WDT_OFFSET 3
+#define PM_WDT_SIZE 1
+#define PM_NTAE_OFFSET 4
+#define PM_NTAE_SIZE 1
+
+/* Bit manipulation macros */
+#define PM_BIT(name) \
+ (1 << PM_##name##_OFFSET)
+#define PM_BF(name,value) \
+ (((value) & ((1 << PM_##name##_SIZE) - 1)) \
+ << PM_##name##_OFFSET)
+#define PM_BFEXT(name,value) \
+ (((value) >> PM_##name##_OFFSET) \
+ & ((1 << PM_##name##_SIZE) - 1))
+#define PM_BFINS(name,value,old)\
+ (((old) & ~(((1 << PM_##name##_SIZE) - 1) \
+ << PM_##name##_OFFSET)) \
+ | PM_BF(name,value))
+
+/* Register access macros */
+#define pm_readl(reg) \
+ __raw_readl((void __iomem *)AT32_PM_BASE + PM_##reg)
+#define pm_writel(reg,value) \
+ __raw_writel((value), (void __iomem *)AT32_PM_BASE + PM_##reg)
+
+#endif /* __ARCH_AVR32_MACH_AT32AP_PM_H__ */
diff --git a/arch/avr32/mach-at32ap/sm.h b/arch/avr32/mach-at32ap/sm.h
deleted file mode 100644
index cad02b512bcb..000000000000
--- a/arch/avr32/mach-at32ap/sm.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Register definitions for SM
- *
- * System Manager
- */
-#ifndef __ASM_AVR32_SM_H__
-#define __ASM_AVR32_SM_H__
-
-/* SM register offsets */
-#define SM_PM_MCCTRL 0x0000
-#define SM_PM_CKSEL 0x0004
-#define SM_PM_CPU_MASK 0x0008
-#define SM_PM_HSB_MASK 0x000c
-#define SM_PM_PBA_MASK 0x0010
-#define SM_PM_PBB_MASK 0x0014
-#define SM_PM_PLL0 0x0020
-#define SM_PM_PLL1 0x0024
-#define SM_PM_VCTRL 0x0030
-#define SM_PM_VMREF 0x0034
-#define SM_PM_VMV 0x0038
-#define SM_PM_IER 0x0040
-#define SM_PM_IDR 0x0044
-#define SM_PM_IMR 0x0048
-#define SM_PM_ISR 0x004c
-#define SM_PM_ICR 0x0050
-#define SM_PM_GCCTRL 0x0060
-#define SM_RTC_CTRL 0x0080
-#define SM_RTC_VAL 0x0084
-#define SM_RTC_TOP 0x0088
-#define SM_RTC_IER 0x0090
-#define SM_RTC_IDR 0x0094
-#define SM_RTC_IMR 0x0098
-#define SM_RTC_ISR 0x009c
-#define SM_RTC_ICR 0x00a0
-#define SM_WDT_CTRL 0x00b0
-#define SM_WDT_CLR 0x00b4
-#define SM_WDT_EXT 0x00b8
-#define SM_RC_RCAUSE 0x00c0
-#define SM_EIM_IER 0x0100
-#define SM_EIM_IDR 0x0104
-#define SM_EIM_IMR 0x0108
-#define SM_EIM_ISR 0x010c
-#define SM_EIM_ICR 0x0110
-#define SM_EIM_MODE 0x0114
-#define SM_EIM_EDGE 0x0118
-#define SM_EIM_LEVEL 0x011c
-#define SM_EIM_TEST 0x0120
-#define SM_EIM_NMIC 0x0124
-
-/* Bitfields in PM_MCCTRL */
-
-/* Bitfields in PM_CKSEL */
-#define SM_CPUSEL_OFFSET 0
-#define SM_CPUSEL_SIZE 3
-#define SM_CPUDIV_OFFSET 7
-#define SM_CPUDIV_SIZE 1
-#define SM_HSBSEL_OFFSET 8
-#define SM_HSBSEL_SIZE 3
-#define SM_HSBDIV_OFFSET 15
-#define SM_HSBDIV_SIZE 1
-#define SM_PBASEL_OFFSET 16
-#define SM_PBASEL_SIZE 3
-#define SM_PBADIV_OFFSET 23
-#define SM_PBADIV_SIZE 1
-#define SM_PBBSEL_OFFSET 24
-#define SM_PBBSEL_SIZE 3
-#define SM_PBBDIV_OFFSET 31
-#define SM_PBBDIV_SIZE 1
-
-/* Bitfields in PM_CPU_MASK */
-
-/* Bitfields in PM_HSB_MASK */
-
-/* Bitfields in PM_PBA_MASK */
-
-/* Bitfields in PM_PBB_MASK */
-
-/* Bitfields in PM_PLL0 */
-#define SM_PLLEN_OFFSET 0
-#define SM_PLLEN_SIZE 1
-#define SM_PLLOSC_OFFSET 1
-#define SM_PLLOSC_SIZE 1
-#define SM_PLLOPT_OFFSET 2
-#define SM_PLLOPT_SIZE 3
-#define SM_PLLDIV_OFFSET 8
-#define SM_PLLDIV_SIZE 8
-#define SM_PLLMUL_OFFSET 16
-#define SM_PLLMUL_SIZE 8
-#define SM_PLLCOUNT_OFFSET 24
-#define SM_PLLCOUNT_SIZE 6
-#define SM_PLLTEST_OFFSET 31
-#define SM_PLLTEST_SIZE 1
-
-/* Bitfields in PM_PLL1 */
-
-/* Bitfields in PM_VCTRL */
-#define SM_VAUTO_OFFSET 0
-#define SM_VAUTO_SIZE 1
-#define SM_PM_VCTRL_VAL_OFFSET 8
-#define SM_PM_VCTRL_VAL_SIZE 7
-
-/* Bitfields in PM_VMREF */
-#define SM_REFSEL_OFFSET 0
-#define SM_REFSEL_SIZE 4
-
-/* Bitfields in PM_VMV */
-#define SM_PM_VMV_VAL_OFFSET 0
-#define SM_PM_VMV_VAL_SIZE 8
-
-/* Bitfields in PM_IER */
-
-/* Bitfields in PM_IDR */
-
-/* Bitfields in PM_IMR */
-
-/* Bitfields in PM_ISR */
-
-/* Bitfields in PM_ICR */
-#define SM_LOCK0_OFFSET 0
-#define SM_LOCK0_SIZE 1
-#define SM_LOCK1_OFFSET 1
-#define SM_LOCK1_SIZE 1
-#define SM_WAKE_OFFSET 2
-#define SM_WAKE_SIZE 1
-#define SM_VOK_OFFSET 3
-#define SM_VOK_SIZE 1
-#define SM_VMRDY_OFFSET 4
-#define SM_VMRDY_SIZE 1
-#define SM_CKRDY_OFFSET 5
-#define SM_CKRDY_SIZE 1
-
-/* Bitfields in PM_GCCTRL */
-#define SM_OSCSEL_OFFSET 0
-#define SM_OSCSEL_SIZE 1
-#define SM_PLLSEL_OFFSET 1
-#define SM_PLLSEL_SIZE 1
-#define SM_CEN_OFFSET 2
-#define SM_CEN_SIZE 1
-#define SM_CPC_OFFSET 3
-#define SM_CPC_SIZE 1
-#define SM_DIVEN_OFFSET 4
-#define SM_DIVEN_SIZE 1
-#define SM_DIV_OFFSET 8
-#define SM_DIV_SIZE 8
-
-/* Bitfields in RTC_CTRL */
-#define SM_PCLR_OFFSET 1
-#define SM_PCLR_SIZE 1
-#define SM_TOPEN_OFFSET 2
-#define SM_TOPEN_SIZE 1
-#define SM_CLKEN_OFFSET 3
-#define SM_CLKEN_SIZE 1
-#define SM_PSEL_OFFSET 8
-#define SM_PSEL_SIZE 16
-
-/* Bitfields in RTC_VAL */
-#define SM_RTC_VAL_VAL_OFFSET 0
-#define SM_RTC_VAL_VAL_SIZE 31
-
-/* Bitfields in RTC_TOP */
-#define SM_RTC_TOP_VAL_OFFSET 0
-#define SM_RTC_TOP_VAL_SIZE 32
-
-/* Bitfields in RTC_IER */
-
-/* Bitfields in RTC_IDR */
-
-/* Bitfields in RTC_IMR */
-
-/* Bitfields in RTC_ISR */
-
-/* Bitfields in RTC_ICR */
-#define SM_TOPI_OFFSET 0
-#define SM_TOPI_SIZE 1
-
-/* Bitfields in WDT_CTRL */
-#define SM_KEY_OFFSET 24
-#define SM_KEY_SIZE 8
-
-/* Bitfields in WDT_CLR */
-
-/* Bitfields in WDT_EXT */
-
-/* Bitfields in RC_RCAUSE */
-#define SM_POR_OFFSET 0
-#define SM_POR_SIZE 1
-#define SM_BOD_OFFSET 1
-#define SM_BOD_SIZE 1
-#define SM_EXT_OFFSET 2
-#define SM_EXT_SIZE 1
-#define SM_WDT_OFFSET 3
-#define SM_WDT_SIZE 1
-#define SM_NTAE_OFFSET 4
-#define SM_NTAE_SIZE 1
-#define SM_SERP_OFFSET 5
-#define SM_SERP_SIZE 1
-
-/* Bitfields in EIM_IER */
-
-/* Bitfields in EIM_IDR */
-
-/* Bitfields in EIM_IMR */
-
-/* Bitfields in EIM_ISR */
-
-/* Bitfields in EIM_ICR */
-
-/* Bitfields in EIM_MODE */
-
-/* Bitfields in EIM_EDGE */
-#define SM_INT0_OFFSET 0
-#define SM_INT0_SIZE 1
-#define SM_INT1_OFFSET 1
-#define SM_INT1_SIZE 1
-#define SM_INT2_OFFSET 2
-#define SM_INT2_SIZE 1
-#define SM_INT3_OFFSET 3
-#define SM_INT3_SIZE 1
-
-/* Bitfields in EIM_LEVEL */
-
-/* Bitfields in EIM_TEST */
-#define SM_TESTEN_OFFSET 31
-#define SM_TESTEN_SIZE 1
-
-/* Bitfields in EIM_NMIC */
-#define SM_EN_OFFSET 0
-#define SM_EN_SIZE 1
-
-/* Bit manipulation macros */
-#define SM_BIT(name) (1 << SM_##name##_OFFSET)
-#define SM_BF(name,value) (((value) & ((1 << SM_##name##_SIZE) - 1)) << SM_##name##_OFFSET)
-#define SM_BFEXT(name,value) (((value) >> SM_##name##_OFFSET) & ((1 << SM_##name##_SIZE) - 1))
-#define SM_BFINS(name,value,old) (((old) & ~(((1 << SM_##name##_SIZE) - 1) << SM_##name##_OFFSET)) | SM_BF(name,value))
-
-/* Register access macros */
-#define sm_readl(port,reg) \
- __raw_readl((port)->regs + SM_##reg)
-#define sm_writel(port,reg,value) \
- __raw_writel((value), (port)->regs + SM_##reg)
-
-#endif /* __ASM_AVR32_SM_H__ */
diff --git a/arch/avr32/mm/fault.c b/arch/avr32/mm/fault.c
index 4b2495285d94..ae2d2c593b2b 100644
--- a/arch/avr32/mm/fault.c
+++ b/arch/avr32/mm/fault.c
@@ -64,6 +64,7 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
int writeaccess;
long signr;
int code;
+ int fault;
if (notify_page_fault(regs, ecr))
return;
@@ -132,20 +133,18 @@ good_area:
* fault.
*/
survive:
- switch (handle_mm_fault(mm, vma, address, writeaccess)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ fault = handle_mm_fault(mm, vma, address, writeaccess);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
up_read(&mm->mmap_sem);
return;
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index d98bafcaca59..017defaa525b 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -71,6 +71,7 @@ config GENERIC_CALIBRATE_DELAY
config IRQCHIP_DEMUX_GPIO
bool
+ depends on (BF53x || BF561 || BF54x)
default y
source "init/Kconfig"
@@ -114,6 +115,26 @@ config BF537
help
BF537 Processor Support.
+config BF542
+ bool "BF542"
+ help
+ BF542 Processor Support.
+
+config BF544
+ bool "BF544"
+ help
+ BF544 Processor Support.
+
+config BF548
+ bool "BF548"
+ help
+ BF548 Processor Support.
+
+config BF549
+ bool "BF549"
+ help
+ BF549 Processor Support.
+
config BF561
bool "BF561"
help
@@ -125,6 +146,11 @@ choice
prompt "Silicon Rev"
default BF_REV_0_2 if BF537
default BF_REV_0_3 if BF533
+ default BF_REV_0_0 if BF549
+
+config BF_REV_0_0
+ bool "0.0"
+ depends on (BF549)
config BF_REV_0_2
bool "0.2"
@@ -150,6 +176,16 @@ config BF_REV_NONE
endchoice
+config BF53x
+ bool
+ depends on (BF531 || BF532 || BF533 || BF534 || BF536 || BF537)
+ default y
+
+config BF54x
+ bool
+ depends on (BF542 || BF544 || BF548 || BF549)
+ default y
+
config BFIN_DUAL_CORE
bool
depends on (BF561)
@@ -198,6 +234,12 @@ config BFIN537_BLUETECHNIX_CM
help
CM-BF537 support for EVAL- and DEV-Board.
+config BFIN548_EZKIT
+ bool "BF548-EZKIT"
+ depends on (BF548 || BF549)
+ help
+ BFIN548-EZKIT board Support.
+
config BFIN561_BLUETECHNIX_CM
bool "Bluetechnix CM-BF561"
depends on (BF561)
@@ -265,6 +307,7 @@ config BFIN_SHARED_FLASH_ENET
source "arch/blackfin/mach-bf533/Kconfig"
source "arch/blackfin/mach-bf561/Kconfig"
source "arch/blackfin/mach-bf537/Kconfig"
+source "arch/blackfin/mach-bf548/Kconfig"
menu "Board customizations"
@@ -497,7 +540,8 @@ config IP_CHECKSUM_L1
config CACHELINE_ALIGNED_L1
bool "Locate cacheline_aligned data to L1 Data Memory"
- default y
+ default y if !BF54x
+ default n if BF54x
depends on !BF531
help
If enabled cacheline_anligned data is linked
@@ -541,9 +585,17 @@ endchoice
source "mm/Kconfig"
+config LARGE_ALLOCS
+ bool "Allow allocating large blocks (> 1MB) of memory"
+ help
+ Allow the slab memory allocator to keep chains for very large
+ memory sizes - upto 32MB. You may need this if your system has
+ a lot of RAM, and you need to able to allocate very large
+ contiguous chunks. If unsure, say N.
+
config BFIN_DMA_5XX
bool "Enable DMA Support"
- depends on (BF533 || BF532 || BF531 || BF537 || BF536 || BF534 || BF561)
+ depends on (BF533 || BF532 || BF531 || BF537 || BF536 || BF534 || BF561 || BF54x)
default y
help
DMA driver for BF5xx.
@@ -686,6 +738,7 @@ config C_AMCKEN
config C_CDPRIO
bool "DMA has priority over core for ext. accesses"
+ depends on !BF54x
default n
config C_B0PEN
@@ -839,7 +892,7 @@ endchoice
endmenu
-if (BF537 || BF533)
+if (BF537 || BF533 || BF54x)
menu "CPU Frequency scaling"
diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile
index 6971a4418dfe..1b75672dfc8f 100644
--- a/arch/blackfin/Makefile
+++ b/arch/blackfin/Makefile
@@ -24,6 +24,8 @@ machine-$(CONFIG_BF533) := bf533
machine-$(CONFIG_BF534) := bf537
machine-$(CONFIG_BF536) := bf537
machine-$(CONFIG_BF537) := bf537
+machine-$(CONFIG_BF548) := bf548
+machine-$(CONFIG_BF549) := bf548
machine-$(CONFIG_BF561) := bf561
MACHINE := $(machine-y)
export MACHINE
diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile
index 49e8098d4c21..8cd33560e817 100644
--- a/arch/blackfin/boot/Makefile
+++ b/arch/blackfin/boot/Makefile
@@ -13,7 +13,8 @@ extra-y += vmlinux.bin vmlinux.gz
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \
- -C gzip -a $(CONFIG_BOOT_LOAD) -e $(CONFIG_BOOT_LOAD) -n 'Linux-$(KERNELRELEASE)' \
+ -C gzip -n 'Linux-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \
+ -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \
-d $< $@
$(obj)/vmlinux.bin: vmlinux FORCE
diff --git a/arch/blackfin/configs/BF548-EZKIT_defconfig b/arch/blackfin/configs/BF548-EZKIT_defconfig
new file mode 100644
index 000000000000..ac8390fafa9c
--- /dev/null
+++ b/arch/blackfin/configs/BF548-EZKIT_defconfig
@@ -0,0 +1,1100 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.21.5
+#
+# CONFIG_MMU is not set
+# CONFIG_FPU is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_BLACKFIN=y
+CONFIG_ZONE_DMA=y
+CONFIG_BFIN=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_FORCE_MAX_ZONEORDER=14
+CONFIG_IRQCHIP_DEMUX_GPIO=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_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_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_BIG_ORDER_ALLOC_NOFAIL_MAGIC=3
+# CONFIG_NP2 is not set
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# 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 is not set
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+
+#
+# Blackfin Processor Options
+#
+
+#
+# Processor and Board Settings
+#
+# CONFIG_BF531 is not set
+# CONFIG_BF532 is not set
+# CONFIG_BF533 is not set
+# CONFIG_BF534 is not set
+# CONFIG_BF536 is not set
+# CONFIG_BF537 is not set
+# CONFIG_BF542 is not set
+# CONFIG_BF544 is not set
+# CONFIG_BF548 is not set
+CONFIG_BF549=y
+# CONFIG_BF561 is not set
+CONFIG_BF_REV_0_0=y
+# CONFIG_BF_REV_0_2 is not set
+# CONFIG_BF_REV_0_3 is not set
+# CONFIG_BF_REV_0_4 is not set
+# CONFIG_BF_REV_0_5 is not set
+# CONFIG_BF_REV_ANY is not set
+# CONFIG_BF_REV_NONE is not set
+CONFIG_BF54x=y
+CONFIG_BFIN_SINGLE_CORE=y
+# CONFIG_BFIN533_EZKIT is not set
+# CONFIG_BFIN533_STAMP is not set
+# CONFIG_BFIN537_STAMP is not set
+# CONFIG_BFIN533_BLUETECHNIX_CM is not set
+# CONFIG_BFIN537_BLUETECHNIX_CM is not set
+CONFIG_BFIN548_EZKIT=y
+# CONFIG_BFIN561_BLUETECHNIX_CM is not set
+# CONFIG_BFIN561_EZKIT is not set
+# CONFIG_BFIN561_TEPLA is not set
+# CONFIG_PNAV10 is not set
+# CONFIG_GENERIC_BOARD is not set
+CONFIG_IRQ_PLL_WAKEUP=7
+CONFIG_IRQ_TIMER0=11
+CONFIG_IRQ_TIMER1=11
+CONFIG_IRQ_TIMER2=11
+CONFIG_IRQ_TIMER3=11
+CONFIG_IRQ_TIMER4=11
+CONFIG_IRQ_TIMER5=11
+CONFIG_IRQ_TIMER6=11
+CONFIG_IRQ_TIMER7=11
+CONFIG_IRQ_TIMER8=11
+CONFIG_IRQ_TIMER9=11
+CONFIG_IRQ_TIMER10=11
+CONFIG_IRQ_RTC=8
+CONFIG_IRQ_SPORT0_RX=9
+CONFIG_IRQ_SPORT0_TX=9
+CONFIG_IRQ_SPORT1_RX=9
+CONFIG_IRQ_SPORT1_TX=9
+CONFIG_IRQ_UART0_RX=10
+CONFIG_IRQ_UART0_TX=10
+CONFIG_IRQ_UART1_RX=10
+CONFIG_IRQ_UART1_TX=10
+
+#
+# BF548 Specific Configuration
+#
+
+#
+# Interrupt Priority Assignment
+#
+
+#
+# Priority
+#
+CONFIG_IRQ_DMAC0_ERR=7
+CONFIG_IRQ_EPPI0_ERR=7
+CONFIG_IRQ_SPORT0_ERR=7
+CONFIG_IRQ_SPORT1_ERR=7
+CONFIG_IRQ_SPI0_ERR=7
+CONFIG_IRQ_UART0_ERR=7
+CONFIG_IRQ_EPPI0=8
+CONFIG_IRQ_SPI0=10
+CONFIG_IRQ_PINT0=12
+CONFIG_IRQ_PINT1=12
+CONFIG_IRQ_MDMAS0=13
+CONFIG_IRQ_MDMAS1=13
+CONFIG_IRQ_WATCHDOG=13
+CONFIG_IRQ_DMAC1_ERR=7
+CONFIG_IRQ_SPORT2_ERR=7
+CONFIG_IRQ_SPORT3_ERR=7
+CONFIG_IRQ_MXVR_DATA=7
+CONFIG_IRQ_SPI1_ERR=7
+CONFIG_IRQ_SPI2_ERR=7
+CONFIG_IRQ_UART1_ERR=7
+CONFIG_IRQ_UART2_ERR=7
+CONFIG_IRQ_CAN0_ERR=7
+CONFIG_IRQ_SPORT2_RX=9
+CONFIG_IRQ_SPORT2_TX=9
+CONFIG_IRQ_SPORT3_RX=9
+CONFIG_IRQ_SPORT3_TX=9
+CONFIG_IRQ_EPPI1=9
+CONFIG_IRQ_EPPI2=9
+CONFIG_IRQ_SPI1=10
+CONFIG_IRQ_SPI2=10
+CONFIG_IRQ_ATAPI_RX=10
+CONFIG_IRQ_ATAPI_TX=10
+CONFIG_IRQ_TWI0=11
+CONFIG_IRQ_TWI1=11
+CONFIG_IRQ_CAN0_RX=11
+CONFIG_IRQ_CAN0_TX=11
+CONFIG_IRQ_MDMAS2=13
+CONFIG_IRQ_MDMAS3=13
+CONFIG_IRQ_MXVR_ERR=11
+CONFIG_IRQ_MXVR_MSG=11
+CONFIG_IRQ_MXVR_PKT=11
+CONFIG_IRQ_EPPI1_ERR=7
+CONFIG_IRQ_EPPI2_ERR=7
+CONFIG_IRQ_UART3_ERR=7
+CONFIG_IRQ_HOST_ERR=7
+CONFIG_IRQ_PIXC_ERR=7
+CONFIG_IRQ_NFC_ERR=7
+CONFIG_IRQ_ATAPI_ERR=7
+CONFIG_IRQ_CAN1_ERR=7
+CONFIG_IRQ_HS_DMA_ERR=7
+CONFIG_IRQ_PIXC_IN0=8
+CONFIG_IRQ_PIXC_IN1=8
+CONFIG_IRQ_PIXC_OUT=8
+CONFIG_IRQ_SDH=8
+CONFIG_IRQ_CNT=8
+CONFIG_IRQ_KEY=8
+CONFIG_IRQ_CAN1_RX=11
+CONFIG_IRQ_CAN1_TX=11
+CONFIG_IRQ_SDH_MASK0=11
+CONFIG_IRQ_SDH_MASK1=11
+CONFIG_IRQ_USB_INT0=11
+CONFIG_IRQ_USB_INT1=11
+CONFIG_IRQ_USB_INT2=11
+CONFIG_IRQ_USB_DMA=11
+CONFIG_IRQ_OTPSEC=11
+CONFIG_IRQ_PINT2=11
+CONFIG_IRQ_PINT3=11
+
+#
+# Board customizations
+#
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Board Setup
+#
+CONFIG_CLKIN_HZ=25000000
+CONFIG_MEM_SIZE=64
+CONFIG_MEM_ADD_WIDTH=10
+CONFIG_BOOT_LOAD=0x1000
+
+#
+# Blackfin Kernel Optimizations
+#
+
+#
+# Timer Tick
+#
+# 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
+
+#
+# Memory Optimizations
+#
+CONFIG_I_ENTRY_L1=y
+CONFIG_EXCPT_IRQ_SYSC_L1=y
+CONFIG_DO_IRQ_L1=y
+CONFIG_CORE_TIMER_IRQ_L1=y
+CONFIG_IDLE_L1=y
+CONFIG_SCHEDULE_L1=y
+CONFIG_ARITHMETIC_OPS_L1=y
+CONFIG_ACCESS_OK_L1=y
+CONFIG_MEMSET_L1=y
+CONFIG_MEMCPY_L1=y
+CONFIG_SYS_BFIN_SPINLOCK_L1=y
+# CONFIG_IP_CHECKSUM_L1 is not set
+CONFIG_CACHELINE_ALIGNED_L1=y
+# CONFIG_SYSCALL_TAB_L1 is not set
+# CONFIG_CPLB_SWITCH_TAB_L1 is not set
+CONFIG_RAMKERNEL=y
+# CONFIG_ROMKERNEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_LARGE_ALLOCS=y
+CONFIG_BFIN_DMA_5XX=y
+# CONFIG_DMA_UNCACHED_2M is not set
+CONFIG_DMA_UNCACHED_1M=y
+# CONFIG_DMA_UNCACHED_NONE is not set
+
+#
+# Cache Support
+#
+CONFIG_BLKFIN_CACHE=y
+CONFIG_BLKFIN_DCACHE=y
+# CONFIG_BLKFIN_DCACHE_BANKA is not set
+# CONFIG_BLKFIN_CACHE_LOCK is not set
+# CONFIG_BLKFIN_WB is not set
+CONFIG_BLKFIN_WT=y
+CONFIG_L1_MAX_PIECE=16
+
+#
+# Clock Settings
+#
+# CONFIG_BFIN_KERNEL_CLOCK is not set
+
+#
+# Asynchonous Memory Configuration
+#
+
+#
+# EBIU_AMBCTL Global Control
+#
+CONFIG_C_AMCKEN=y
+CONFIG_C_CDPRIO=y
+# CONFIG_C_AMBEN is not set
+# CONFIG_C_AMBEN_B0 is not set
+# CONFIG_C_AMBEN_B0_B1 is not set
+# CONFIG_C_AMBEN_B0_B1_B2 is not set
+CONFIG_C_AMBEN_ALL=y
+
+#
+# EBIU_AMBCTL Control
+#
+CONFIG_BANK_0=0x7BB0
+CONFIG_BANK_1=0x7BB0
+CONFIG_BANK_2=0x7BB0
+CONFIG_BANK_3=0x99B3
+
+#
+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF_FDPIC=y
+CONFIG_BINFMT_FLAT=y
+CONFIG_BINFMT_ZFLAT=y
+# CONFIG_BINFMT_SHARED_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# 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 is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_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_NETLABEL 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_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_BF5xx is not set
+CONFIG_MTD_UCLINUX=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND 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_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+
+#
+# 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
+#
+
+#
+# I2O device support
+#
+
+#
+# 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
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_SMSC911X 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
+# 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=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_BF53X_PFBUTTONS is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_AD9960 is not set
+# CONFIG_SPI_ADC_BF533 is not set
+# CONFIG_BF5xx_PFLAGS is not set
+# CONFIG_BF5xx_PPIFCD is not set
+# CONFIG_BF5xx_TIMERS is not set
+# CONFIG_BF5xx_PPI is not set
+# CONFIG_BFIN_SPORT is not set
+# CONFIG_BFIN_TIMER_LATENCY is not set
+# CONFIG_BF5xx_FBDMA is not set
+# 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_BFIN=y
+CONFIG_SERIAL_BFIN_CONSOLE=y
+# CONFIG_SERIAL_BFIN_DMA is not set
+CONFIG_SERIAL_BFIN_PIO=y
+# CONFIG_SERIAL_BFIN_UART0 is not set
+CONFIG_SERIAL_BFIN_UART1=y
+# CONFIG_BFIN_UART1_CTSRTS is not set
+# CONFIG_SERIAL_BFIN_UART2 is not set
+# CONFIG_SERIAL_BFIN_UART3 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_BFIN_SPORT is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# CAN, the car bus and industrial fieldbus
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 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
+
+#
+# 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 is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# 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
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
+CONFIG_RTC_DRV_BFIN=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# Auxiliary Display support
+#
+
+#
+# Virtualization
+#
+
+#
+# PBX support
+#
+# CONFIG_PBX 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 is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_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_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS 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_YAFFS_FS is not set
+# CONFIG_JFFS2_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 is not set
+# CONFIG_NFSD 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 is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_DEBUG_HWERR=y
+# CONFIG_DEBUG_ICACHE_CHECK is not set
+# CONFIG_DEBUG_KERNEL_START is not set
+# CONFIG_DEBUG_SERIAL_EARLY_INIT is not set
+CONFIG_DEBUG_HUNT_FOR_ZERO=y
+# CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE is not set
+CONFIG_CPLB_INFO=y
+CONFIG_ACCESS_CHECK=y
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITY_NETWORK is not set
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index f3b7d2f9d49c..f429ebc3a961 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -6,9 +6,12 @@ extra-y := init_task.o vmlinux.lds
obj-y := \
entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \
- sys_bfin.o time.o traps.o irqchip.o dma-mapping.o bfin_gpio.o \
- flat.o
+ sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \
+ fixed_code.o cplbinit.o cacheinit.o
+obj-$(CONFIG_BF53x) += bfin_gpio.o
+obj-$(CONFIG_BF561) += bfin_gpio.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o
obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o
+obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
index e455f4504509..b56b2741cdea 100644
--- a/arch/blackfin/kernel/asm-offsets.c
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -32,11 +32,10 @@
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
-#include <asm/irq.h>
-#include <asm/thread_info.h>
+#include <linux/irq.h>
+#include <linux/thread_info.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
int main(void)
{
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 069a896a8f26..7cf02f02a1db 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -34,6 +34,7 @@
#include <linux/kernel.h>
#include <linux/param.h>
+#include <asm/blackfin.h>
#include <asm/dma.h>
#include <asm/cacheflush.h>
@@ -45,67 +46,6 @@
***************************************************************************/
static struct dma_channel dma_ch[MAX_BLACKFIN_DMA_CHANNEL];
-#if defined (CONFIG_BF561)
-static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
- (struct dma_register *) DMA1_0_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_1_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_2_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_3_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_4_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_5_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_6_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_7_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_8_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_9_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_10_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_11_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_0_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_1_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_2_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_3_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_4_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_5_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_6_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_7_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_8_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_9_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_10_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_11_NEXT_DESC_PTR,
- (struct dma_register *) MDMA1_D0_NEXT_DESC_PTR,
- (struct dma_register *) MDMA1_S0_NEXT_DESC_PTR,
- (struct dma_register *) MDMA1_D1_NEXT_DESC_PTR,
- (struct dma_register *) MDMA1_S1_NEXT_DESC_PTR,
- (struct dma_register *) MDMA2_D0_NEXT_DESC_PTR,
- (struct dma_register *) MDMA2_S0_NEXT_DESC_PTR,
- (struct dma_register *) MDMA2_D1_NEXT_DESC_PTR,
- (struct dma_register *) MDMA2_S1_NEXT_DESC_PTR,
- (struct dma_register *) IMDMA_D0_NEXT_DESC_PTR,
- (struct dma_register *) IMDMA_S0_NEXT_DESC_PTR,
- (struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
- (struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
-};
-#else
-static struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
- (struct dma_register *) DMA0_NEXT_DESC_PTR,
- (struct dma_register *) DMA1_NEXT_DESC_PTR,
- (struct dma_register *) DMA2_NEXT_DESC_PTR,
- (struct dma_register *) DMA3_NEXT_DESC_PTR,
- (struct dma_register *) DMA4_NEXT_DESC_PTR,
- (struct dma_register *) DMA5_NEXT_DESC_PTR,
- (struct dma_register *) DMA6_NEXT_DESC_PTR,
- (struct dma_register *) DMA7_NEXT_DESC_PTR,
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
- (struct dma_register *) DMA8_NEXT_DESC_PTR,
- (struct dma_register *) DMA9_NEXT_DESC_PTR,
- (struct dma_register *) DMA10_NEXT_DESC_PTR,
- (struct dma_register *) DMA11_NEXT_DESC_PTR,
-#endif
- (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
- (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
- (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
- (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
-};
-#endif
/*------------------------------------------------------------------------------
* Set the Buffer Clear bit in the Configuration register of specific DMA
@@ -138,149 +78,6 @@ static int __init blackfin_dma_init(void)
arch_initcall(blackfin_dma_init);
-/*
- * Form the channel find the irq number for that channel.
- */
-#if !defined(CONFIG_BF561)
-
-static int bf533_channel2irq(unsigned int channel)
-{
- int ret_irq = -1;
-
- switch (channel) {
- case CH_PPI:
- ret_irq = IRQ_PPI;
- break;
-
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF534) || defined(CONFIG_BF536))
- case CH_EMAC_RX:
- ret_irq = IRQ_MAC_RX;
- break;
-
- case CH_EMAC_TX:
- ret_irq = IRQ_MAC_TX;
- break;
-
- case CH_UART1_RX:
- ret_irq = IRQ_UART1_RX;
- break;
-
- case CH_UART1_TX:
- ret_irq = IRQ_UART1_TX;
- break;
-#endif
-
- case CH_SPORT0_RX:
- ret_irq = IRQ_SPORT0_RX;
- break;
-
- case CH_SPORT0_TX:
- ret_irq = IRQ_SPORT0_TX;
- break;
-
- case CH_SPORT1_RX:
- ret_irq = IRQ_SPORT1_RX;
- break;
-
- case CH_SPORT1_TX:
- ret_irq = IRQ_SPORT1_TX;
- break;
-
- case CH_SPI:
- ret_irq = IRQ_SPI;
- break;
-
- case CH_UART_RX:
- ret_irq = IRQ_UART_RX;
- break;
-
- case CH_UART_TX:
- ret_irq = IRQ_UART_TX;
- break;
-
- case CH_MEM_STREAM0_SRC:
- case CH_MEM_STREAM0_DEST:
- ret_irq = IRQ_MEM_DMA0;
- break;
-
- case CH_MEM_STREAM1_SRC:
- case CH_MEM_STREAM1_DEST:
- ret_irq = IRQ_MEM_DMA1;
- break;
- }
- return ret_irq;
-}
-
-# define channel2irq(channel) bf533_channel2irq(channel)
-
-#else
-
-static int bf561_channel2irq(unsigned int channel)
-{
- int ret_irq = -1;
-
- switch (channel) {
- case CH_PPI0:
- ret_irq = IRQ_PPI0;
- break;
- case CH_PPI1:
- ret_irq = IRQ_PPI1;
- break;
- case CH_SPORT0_RX:
- ret_irq = IRQ_SPORT0_RX;
- break;
- case CH_SPORT0_TX:
- ret_irq = IRQ_SPORT0_TX;
- break;
- case CH_SPORT1_RX:
- ret_irq = IRQ_SPORT1_RX;
- break;
- case CH_SPORT1_TX:
- ret_irq = IRQ_SPORT1_TX;
- break;
- case CH_SPI:
- ret_irq = IRQ_SPI;
- break;
- case CH_UART_RX:
- ret_irq = IRQ_UART_RX;
- break;
- case CH_UART_TX:
- ret_irq = IRQ_UART_TX;
- break;
-
- case CH_MEM_STREAM0_SRC:
- case CH_MEM_STREAM0_DEST:
- ret_irq = IRQ_MEM_DMA0;
- break;
- case CH_MEM_STREAM1_SRC:
- case CH_MEM_STREAM1_DEST:
- ret_irq = IRQ_MEM_DMA1;
- break;
- case CH_MEM_STREAM2_SRC:
- case CH_MEM_STREAM2_DEST:
- ret_irq = IRQ_MEM_DMA2;
- break;
- case CH_MEM_STREAM3_SRC:
- case CH_MEM_STREAM3_DEST:
- ret_irq = IRQ_MEM_DMA3;
- break;
-
- case CH_IMEM_STREAM0_SRC:
- case CH_IMEM_STREAM0_DEST:
- ret_irq = IRQ_IMEM_DMA0;
- break;
- case CH_IMEM_STREAM1_SRC:
- case CH_IMEM_STREAM1_DEST:
- ret_irq = IRQ_IMEM_DMA1;
- break;
- }
- return ret_irq;
-}
-
-# define channel2irq(channel) bf561_channel2irq(channel)
-
-#endif
-
/*------------------------------------------------------------------------------
* Request the specific DMA channel from the system.
*-----------------------------------------------------------------------------*/
@@ -535,7 +332,7 @@ set_bfin_dma_config(char direction, char flow_mode,
}
EXPORT_SYMBOL(set_bfin_dma_config);
-void set_dma_sg(unsigned int channel, struct dmasg * sg, int nr_sg)
+void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg)
{
BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE
&& channel < MAX_BLACKFIN_DMA_CHANNEL));
@@ -604,7 +401,7 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size)
if (size <= 0)
return NULL;
-
+
local_irq_save(flags);
if ((unsigned long)src < memory_end)
@@ -748,7 +545,6 @@ void *dma_memcpy(void *dest, const void *src, size_t size)
addr = __dma_memcpy(dest+bulk, src+bulk, rest);
return addr;
}
-
EXPORT_SYMBOL(dma_memcpy);
void *safe_dma_memcpy(void *dest, const void *src, size_t size)
@@ -761,14 +557,13 @@ EXPORT_SYMBOL(safe_dma_memcpy);
void dma_outsb(void __iomem *addr, const void *buf, unsigned short len)
{
-
unsigned long flags;
-
+
local_irq_save(flags);
-
- blackfin_dcache_flush_range((unsigned int)buf,(unsigned int)(buf) + len);
- bfin_write_MDMA_D0_START_ADDR(addr);
+ blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len);
+
+ bfin_write_MDMA_D0_START_ADDR(addr);
bfin_write_MDMA_D0_X_COUNT(len);
bfin_write_MDMA_D0_X_MODIFY(0);
bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
@@ -796,9 +591,9 @@ EXPORT_SYMBOL(dma_outsb);
void dma_insb(const void __iomem *addr, void *buf, unsigned short len)
{
unsigned long flags;
-
+
local_irq_save(flags);
- bfin_write_MDMA_D0_START_ADDR(buf);
+ bfin_write_MDMA_D0_START_ADDR(buf);
bfin_write_MDMA_D0_X_COUNT(len);
bfin_write_MDMA_D0_X_MODIFY(1);
bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
@@ -827,12 +622,12 @@ EXPORT_SYMBOL(dma_insb);
void dma_outsw(void __iomem *addr, const void *buf, unsigned short len)
{
unsigned long flags;
-
+
local_irq_save(flags);
-
- blackfin_dcache_flush_range((unsigned int)buf,(unsigned int)(buf) + len);
- bfin_write_MDMA_D0_START_ADDR(addr);
+ blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len);
+
+ bfin_write_MDMA_D0_START_ADDR(addr);
bfin_write_MDMA_D0_X_COUNT(len);
bfin_write_MDMA_D0_X_MODIFY(0);
bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
@@ -859,10 +654,10 @@ EXPORT_SYMBOL(dma_outsw);
void dma_insw(const void __iomem *addr, void *buf, unsigned short len)
{
unsigned long flags;
-
+
local_irq_save(flags);
-
- bfin_write_MDMA_D0_START_ADDR(buf);
+
+ bfin_write_MDMA_D0_START_ADDR(buf);
bfin_write_MDMA_D0_X_COUNT(len);
bfin_write_MDMA_D0_X_MODIFY(2);
bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
@@ -891,12 +686,12 @@ EXPORT_SYMBOL(dma_insw);
void dma_outsl(void __iomem *addr, const void *buf, unsigned short len)
{
unsigned long flags;
-
+
local_irq_save(flags);
-
- blackfin_dcache_flush_range((unsigned int)buf,(unsigned int)(buf) + len);
- bfin_write_MDMA_D0_START_ADDR(addr);
+ blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len);
+
+ bfin_write_MDMA_D0_START_ADDR(addr);
bfin_write_MDMA_D0_X_COUNT(len);
bfin_write_MDMA_D0_X_MODIFY(0);
bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
@@ -923,10 +718,10 @@ EXPORT_SYMBOL(dma_outsl);
void dma_insl(const void __iomem *addr, void *buf, unsigned short len)
{
unsigned long flags;
-
+
local_irq_save(flags);
-
- bfin_write_MDMA_D0_START_ADDR(buf);
+
+ bfin_write_MDMA_D0_START_ADDR(buf);
bfin_write_MDMA_D0_X_COUNT(len);
bfin_write_MDMA_D0_X_MODIFY(4);
bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR);
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index bb1f4fb2467c..bafcfa52142b 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -162,7 +162,7 @@ static void port_setup(unsigned short gpio, unsigned short usage)
static void default_gpio(unsigned short gpio)
{
- unsigned short bank,bitmask;
+ unsigned short bank, bitmask;
bank = gpio_bank(gpio);
bitmask = gpio_bit(gpio);
@@ -183,7 +183,7 @@ static int __init bfin_gpio_init(void)
printk(KERN_INFO "Blackfin GPIO Controller\n");
- for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE)
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE)
reserved_map[gpio_bank(i)] = 0;
#if defined(BF537_FAMILY) && (defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
@@ -478,7 +478,7 @@ u32 gpio_pm_setup(void)
u32 sic_iwr = 0;
u16 bank, mask, i, gpio;
- for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
mask = wakeup_map[gpio_bank(i)];
bank = gpio_bank(i);
@@ -522,12 +522,11 @@ u32 gpio_pm_setup(void)
return IWR_ENABLE_ALL;
}
-
void gpio_pm_restore(void)
{
u16 bank, mask, i;
- for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=GPIO_BANKSIZE) {
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
mask = wakeup_map[gpio_bank(i)];
bank = gpio_bank(i);
@@ -591,7 +590,6 @@ int gpio_request(unsigned short gpio, const char *label)
}
EXPORT_SYMBOL(gpio_request);
-
void gpio_free(unsigned short gpio)
{
unsigned long flags;
@@ -616,7 +614,6 @@ void gpio_free(unsigned short gpio)
}
EXPORT_SYMBOL(gpio_free);
-
void gpio_direction_input(unsigned short gpio)
{
unsigned long flags;
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
index f64ecb638fab..70455949cfd2 100644
--- a/arch/blackfin/kernel/bfin_ksyms.c
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -28,10 +28,11 @@
*/
#include <linux/module.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
+#include <linux/uaccess.h>
+
#include <asm/checksum.h>
#include <asm/cacheflush.h>
-#include <asm/uaccess.h>
/* platform dependent support */
diff --git a/arch/blackfin/kernel/cacheinit.c b/arch/blackfin/kernel/cacheinit.c
new file mode 100644
index 000000000000..4d41a40e8133
--- /dev/null
+++ b/arch/blackfin/kernel/cacheinit.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2004-2007 Analog Devices 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/cpu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/blackfin.h>
+#include <asm/cplbinit.h>
+
+#if defined(CONFIG_BLKFIN_CACHE)
+void bfin_icache_init(void)
+{
+ unsigned long *table = icplb_table;
+ unsigned long ctrl;
+ int i;
+
+ for (i = 0; i < MAX_CPLBS; i++) {
+ unsigned long addr = *table++;
+ unsigned long data = *table++;
+ if (addr == (unsigned long)-1)
+ break;
+ bfin_write32(ICPLB_ADDR0 + i * 4, addr);
+ bfin_write32(ICPLB_DATA0 + i * 4, data);
+ }
+ ctrl = bfin_read_IMEM_CONTROL();
+ ctrl |= IMC | ENICPLB;
+ bfin_write_IMEM_CONTROL(ctrl);
+}
+#endif
+
+#if defined(CONFIG_BLKFIN_DCACHE)
+void bfin_dcache_init(void)
+{
+ unsigned long *table = dcplb_table;
+ unsigned long ctrl;
+ int i;
+
+ for (i = 0; i < MAX_CPLBS; i++) {
+ unsigned long addr = *table++;
+ unsigned long data = *table++;
+ if (addr == (unsigned long)-1)
+ break;
+ bfin_write32(DCPLB_ADDR0 + i * 4, addr);
+ bfin_write32(DCPLB_DATA0 + i * 4, data);
+ }
+ ctrl = bfin_read_DMEM_CONTROL();
+ ctrl |= DMEM_CNTR;
+ bfin_write_DMEM_CONTROL(ctrl);
+}
+#endif
diff --git a/arch/blackfin/kernel/cplbinit.c b/arch/blackfin/kernel/cplbinit.c
new file mode 100644
index 000000000000..bbdb403fcb55
--- /dev/null
+++ b/arch/blackfin/kernel/cplbinit.c
@@ -0,0 +1,433 @@
+/*
+ * Blackfin CPLB initialization
+ *
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/module.h>
+
+#include <asm/blackfin.h>
+#include <asm/cplbinit.h>
+
+u_long icplb_table[MAX_CPLBS+1];
+u_long dcplb_table[MAX_CPLBS+1];
+
+#ifdef CONFIG_CPLB_SWITCH_TAB_L1
+u_long ipdt_table[MAX_SWITCH_I_CPLBS+1]__attribute__((l1_data));
+u_long dpdt_table[MAX_SWITCH_D_CPLBS+1]__attribute__((l1_data));
+
+#ifdef CONFIG_CPLB_INFO
+u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS]__attribute__((l1_data));
+u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS]__attribute__((l1_data));
+#endif /* CONFIG_CPLB_INFO */
+
+#else
+
+u_long ipdt_table[MAX_SWITCH_I_CPLBS+1];
+u_long dpdt_table[MAX_SWITCH_D_CPLBS+1];
+
+#ifdef CONFIG_CPLB_INFO
+u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS];
+u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS];
+#endif /* CONFIG_CPLB_INFO */
+
+#endif /*CONFIG_CPLB_SWITCH_TAB_L1*/
+
+struct s_cplb {
+ struct cplb_tab init_i;
+ struct cplb_tab init_d;
+ struct cplb_tab switch_i;
+ struct cplb_tab switch_d;
+};
+
+#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
+static struct cplb_desc cplb_data[] = {
+ {
+ .start = 0,
+ .end = SIZE_1K,
+ .psize = SIZE_1K,
+ .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+ .i_conf = SDRAM_OOPS,
+ .d_conf = SDRAM_OOPS,
+#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
+ .valid = 1,
+#else
+ .valid = 0,
+#endif
+ .name = "ZERO Pointer Saveguard",
+ },
+ {
+ .start = L1_CODE_START,
+ .end = L1_CODE_START + L1_CODE_LENGTH,
+ .psize = SIZE_4M,
+ .attr = INITIAL_T | SWITCH_T | I_CPLB,
+ .i_conf = L1_IMEMORY,
+ .d_conf = 0,
+ .valid = 1,
+ .name = "L1 I-Memory",
+ },
+ {
+ .start = L1_DATA_A_START,
+ .end = L1_DATA_B_START + L1_DATA_B_LENGTH,
+ .psize = SIZE_4M,
+ .attr = INITIAL_T | SWITCH_T | D_CPLB,
+ .i_conf = 0,
+ .d_conf = L1_DMEMORY,
+#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
+ .valid = 1,
+#else
+ .valid = 0,
+#endif
+ .name = "L1 D-Memory",
+ },
+ {
+ .start = 0,
+ .end = 0, /* dynamic */
+ .psize = 0,
+ .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
+ .i_conf = SDRAM_IGENERIC,
+ .d_conf = SDRAM_DGENERIC,
+ .valid = 1,
+ .name = "SDRAM Kernel",
+ },
+ {
+ .start = 0, /* dynamic */
+ .end = 0, /* dynamic */
+ .psize = 0,
+ .attr = INITIAL_T | SWITCH_T | D_CPLB,
+ .i_conf = SDRAM_IGENERIC,
+ .d_conf = SDRAM_DNON_CHBL,
+ .valid = 1,
+ .name = "SDRAM RAM MTD",
+ },
+ {
+ .start = 0, /* dynamic */
+ .end = 0, /* dynamic */
+ .psize = SIZE_1M,
+ .attr = INITIAL_T | SWITCH_T | D_CPLB,
+ .d_conf = SDRAM_DNON_CHBL,
+ .valid = 1,
+ .name = "SDRAM Uncached DMA ZONE",
+ },
+ {
+ .start = 0, /* dynamic */
+ .end = 0, /* dynamic */
+ .psize = 0,
+ .attr = SWITCH_T | D_CPLB,
+ .i_conf = 0, /* dynamic */
+ .d_conf = 0, /* dynamic */
+ .valid = 1,
+ .name = "SDRAM Reserved Memory",
+ },
+ {
+ .start = ASYNC_BANK0_BASE,
+ .end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
+ .psize = 0,
+ .attr = SWITCH_T | D_CPLB,
+ .d_conf = SDRAM_EBIU,
+ .valid = 1,
+ .name = "ASYNC Memory",
+ },
+ {
+#if defined(CONFIG_BF561)
+ .start = L2_SRAM,
+ .end = L2_SRAM_END,
+ .psize = SIZE_1M,
+ .attr = SWITCH_T | D_CPLB,
+ .i_conf = L2_MEMORY,
+ .d_conf = L2_MEMORY,
+ .valid = 1,
+#else
+ .valid = 0,
+#endif
+ .name = "L2 Memory",
+ }
+};
+
+static u16 __init lock_kernel_check(u32 start, u32 end)
+{
+ if ((start <= (u32) _stext && end >= (u32) _end)
+ || (start >= (u32) _stext && end <= (u32) _end))
+ return IN_KERNEL;
+ return 0;
+}
+
+static unsigned short __init
+fill_cplbtab(struct cplb_tab *table,
+ unsigned long start, unsigned long end,
+ unsigned long block_size, unsigned long cplb_data)
+{
+ int i;
+
+ switch (block_size) {
+ case SIZE_4M:
+ i = 3;
+ break;
+ case SIZE_1M:
+ i = 2;
+ break;
+ case SIZE_4K:
+ i = 1;
+ break;
+ case SIZE_1K:
+ default:
+ i = 0;
+ break;
+ }
+
+ cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
+
+ while ((start < end) && (table->pos < table->size)) {
+
+ table->tab[table->pos++] = start;
+
+ if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
+ table->tab[table->pos++] =
+ cplb_data | CPLB_LOCK | CPLB_DIRTY;
+ else
+ table->tab[table->pos++] = cplb_data;
+
+ start += block_size;
+ }
+ return 0;
+}
+
+static unsigned short __init
+close_cplbtab(struct cplb_tab *table)
+{
+
+ while (table->pos < table->size) {
+
+ table->tab[table->pos++] = 0;
+ table->tab[table->pos++] = 0; /* !CPLB_VALID */
+ }
+ return 0;
+}
+
+/* helper function */
+static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+{
+ if (cplb_data[i].psize) {
+ fill_cplbtab(t,
+ cplb_data[i].start,
+ cplb_data[i].end,
+ cplb_data[i].psize,
+ cplb_data[i].i_conf);
+ } else {
+#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
+ if (i == SDRAM_KERN) {
+ fill_cplbtab(t,
+ cplb_data[i].start,
+ cplb_data[i].end,
+ SIZE_4M,
+ cplb_data[i].i_conf);
+ } else
+#endif
+ {
+ fill_cplbtab(t,
+ cplb_data[i].start,
+ a_start,
+ SIZE_1M,
+ cplb_data[i].i_conf);
+ fill_cplbtab(t,
+ a_start,
+ a_end,
+ SIZE_4M,
+ cplb_data[i].i_conf);
+ fill_cplbtab(t, a_end,
+ cplb_data[i].end,
+ SIZE_1M,
+ cplb_data[i].i_conf);
+ }
+ }
+}
+
+static void __fill_data_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_end)
+{
+ if (cplb_data[i].psize) {
+ fill_cplbtab(t,
+ cplb_data[i].start,
+ cplb_data[i].end,
+ cplb_data[i].psize,
+ cplb_data[i].d_conf);
+ } else {
+ fill_cplbtab(t,
+ cplb_data[i].start,
+ a_start, SIZE_1M,
+ cplb_data[i].d_conf);
+ fill_cplbtab(t, a_start,
+ a_end, SIZE_4M,
+ cplb_data[i].d_conf);
+ fill_cplbtab(t, a_end,
+ cplb_data[i].end,
+ SIZE_1M,
+ cplb_data[i].d_conf);
+ }
+}
+
+void __init generate_cpl_tables(void)
+{
+
+ u16 i, j, process;
+ u32 a_start, a_end, as, ae, as_1m;
+
+ struct cplb_tab *t_i = NULL;
+ struct cplb_tab *t_d = NULL;
+ struct s_cplb cplb;
+
+ cplb.init_i.size = MAX_CPLBS;
+ cplb.init_d.size = MAX_CPLBS;
+ cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
+ cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
+
+ cplb.init_i.pos = 0;
+ cplb.init_d.pos = 0;
+ cplb.switch_i.pos = 0;
+ cplb.switch_d.pos = 0;
+
+ cplb.init_i.tab = icplb_table;
+ cplb.init_d.tab = dcplb_table;
+ cplb.switch_i.tab = ipdt_table;
+ cplb.switch_d.tab = dpdt_table;
+
+ cplb_data[SDRAM_KERN].end = memory_end;
+
+#ifdef CONFIG_MTD_UCLINUX
+ cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
+ cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
+ cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
+# if defined(CONFIG_ROMFS_FS)
+ cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
+
+ /*
+ * The ROMFS_FS size is often not multiple of 1MB.
+ * This can cause multiple CPLB sets covering the same memory area.
+ * This will then cause multiple CPLB hit exceptions.
+ * Workaround: We ensure a contiguous memory area by extending the kernel
+ * memory section over the mtd section.
+ * For ROMFS_FS memory must be covered with ICPLBs anyways.
+ * So there is no difference between kernel and mtd memory setup.
+ */
+
+ cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
+ cplb_data[SDRAM_RAM_MTD].valid = 0;
+
+# endif
+#else
+ cplb_data[SDRAM_RAM_MTD].valid = 0;
+#endif
+
+ cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
+ cplb_data[SDRAM_DMAZ].end = _ramend;
+
+ cplb_data[RES_MEM].start = _ramend;
+ cplb_data[RES_MEM].end = physical_mem_end;
+
+ if (reserved_mem_dcache_on)
+ cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
+ else
+ cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
+
+ if (reserved_mem_icache_on)
+ cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
+ else
+ cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
+
+ for (i = ZERO_P; i <= L2_MEM; i++) {
+ if (!cplb_data[i].valid)
+ continue;
+
+ as_1m = cplb_data[i].start % SIZE_1M;
+
+ /* We need to make sure all sections are properly 1M aligned
+ * However between Kernel Memory and the Kernel mtd section, depending on the
+ * rootfs size, there can be overlapping memory areas.
+ */
+
+ if (as_1m && i != L1I_MEM && i != L1D_MEM) {
+#ifdef CONFIG_MTD_UCLINUX
+ if (i == SDRAM_RAM_MTD) {
+ if ((cplb_data[SDRAM_KERN].end + 1) > cplb_data[SDRAM_RAM_MTD].start)
+ cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M)) + SIZE_1M;
+ else
+ cplb_data[SDRAM_RAM_MTD].start = (cplb_data[i].start & (-2*SIZE_1M));
+ } else
+#endif
+ printk(KERN_WARNING "Unaligned Start of %s at 0x%X\n",
+ cplb_data[i].name, cplb_data[i].start);
+ }
+
+ as = cplb_data[i].start % SIZE_4M;
+ ae = cplb_data[i].end % SIZE_4M;
+
+ if (as)
+ a_start = cplb_data[i].start + (SIZE_4M - (as));
+ else
+ a_start = cplb_data[i].start;
+
+ a_end = cplb_data[i].end - ae;
+
+ for (j = INITIAL_T; j <= SWITCH_T; j++) {
+
+ switch (j) {
+ case INITIAL_T:
+ if (cplb_data[i].attr & INITIAL_T) {
+ t_i = &cplb.init_i;
+ t_d = &cplb.init_d;
+ process = 1;
+ } else
+ process = 0;
+ break;
+ case SWITCH_T:
+ if (cplb_data[i].attr & SWITCH_T) {
+ t_i = &cplb.switch_i;
+ t_d = &cplb.switch_d;
+ process = 1;
+ } else
+ process = 0;
+ break;
+ default:
+ process = 0;
+ break;
+ }
+
+ if (!process)
+ continue;
+ if (cplb_data[i].attr & I_CPLB)
+ __fill_code_cplbtab(t_i, i, a_start, a_end);
+
+ if (cplb_data[i].attr & D_CPLB)
+ __fill_data_cplbtab(t_d, i, a_start, a_end);
+ }
+ }
+
+/* close tables */
+
+ close_cplbtab(&cplb.init_i);
+ close_cplbtab(&cplb.init_d);
+
+ cplb.init_i.tab[cplb.init_i.pos] = -1;
+ cplb.init_d.tab[cplb.init_d.pos] = -1;
+ cplb.switch_i.tab[cplb.switch_i.pos] = -1;
+ cplb.switch_d.tab[cplb.switch_d.pos] = -1;
+
+}
+
+#endif
+
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
index 539eb24e062f..ea48d5b13f11 100644
--- a/arch/blackfin/kernel/dma-mapping.c
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -34,8 +34,8 @@
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/io.h>
#include <asm/cacheflush.h>
-#include <asm/io.h>
#include <asm/bfin-global.h>
static spinlock_t dma_page_lock;
@@ -159,10 +159,13 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
BUG_ON(direction == DMA_NONE);
- for (i = 0; i < nents; i++)
- invalidate_dcache_range(sg_dma_address(&sg[i]),
- sg_dma_address(&sg[i]) +
- sg_dma_len(&sg[i]));
+ for (i = 0; i < nents; i++, sg++) {
+ sg->dma_address = page_address(sg->page) + sg->offset;
+
+ invalidate_dcache_range(sg_dma_address(sg),
+ sg_dma_address(sg) +
+ sg_dma_len(sg));
+ }
return nents;
}
diff --git a/arch/blackfin/kernel/dualcore_test.c b/arch/blackfin/kernel/dualcore_test.c
index 8b89c99f9dfa..0fcba74840b7 100644
--- a/arch/blackfin/kernel/dualcore_test.c
+++ b/arch/blackfin/kernel/dualcore_test.c
@@ -30,19 +30,19 @@
#include <linux/init.h>
#include <linux/module.h>
-static int *testarg = (int*)0xfeb00000;
+static int *testarg = (int *)0xfeb00000;
static int test_init(void)
{
*testarg = 1;
- printk("Dual core test module inserted: set testarg = [%d]\n @ [%p]\n",
+ printk(KERN_INFO "Dual core test module inserted: set testarg = [%d]\n @ [%p]\n",
*testarg, testarg);
return 0;
}
static void test_exit(void)
{
- printk("Dual core test module removed: testarg = [%d]\n", *testarg);
+ printk(KERN_INFO "Dual core test module removed: testarg = [%d]\n", *testarg);
}
module_init(test_init);
diff --git a/arch/blackfin/kernel/fixed_code.S b/arch/blackfin/kernel/fixed_code.S
new file mode 100644
index 000000000000..d8b1ebc70996
--- /dev/null
+++ b/arch/blackfin/kernel/fixed_code.S
@@ -0,0 +1,132 @@
+/*
+ * This file contains sequences of code that will be copied to a
+ * fixed location, defined in <asm/atomic_seq.h>. The interrupt
+ * handlers ensure that these sequences appear to be atomic when
+ * executed from userspace.
+ * These are aligned to 16 bytes, so that we have some space to replace
+ * these sequences with something else (e.g. kernel traps if we ever do
+ * BF561 SMP).
+ */
+#include <linux/linkage.h>
+#include <linux/unistd.h>
+#include <asm/entry.h>
+
+.text
+ENTRY(_fixed_code_start)
+
+.align 16
+ENTRY(_sigreturn_stub)
+ P0 = __NR_rt_sigreturn;
+ EXCPT 0;
+ /* Speculative execution paranoia. */
+0: JUMP.S 0b;
+ENDPROC (_sigreturn_stub)
+
+.align 16
+ /*
+ * Atomic swap, 8 bit.
+ * Inputs: P0: memory address to use
+ * R1: value to store
+ * Output: R0: old contents of the memory address, zero extended.
+ */
+ENTRY(_atomic_xchg32)
+ R0 = [P0];
+ [P0] = R1;
+ rts;
+ENDPROC (_atomic_xchg32)
+
+.align 16
+ /*
+ * Compare and swap, 32 bit.
+ * Inputs: P0: memory address to use
+ * R1: compare value
+ * R2: new value to store
+ * The new value is stored if the contents of the memory
+ * address is equal to the compare value.
+ * Output: R0: old contents of the memory address.
+ */
+ENTRY(_atomic_cas32)
+ R0 = [P0];
+ CC = R0 == R1;
+ IF !CC JUMP 1f;
+ [P0] = R2;
+1:
+ rts;
+ENDPROC (_atomic_cas32)
+
+.align 16
+ /*
+ * Atomic add, 32 bit.
+ * Inputs: P0: memory address to use
+ * R0: value to add
+ * Outputs: R0: new contents of the memory address.
+ * R1: previous contents of the memory address.
+ */
+ENTRY(_atomic_add32)
+ R1 = [P0];
+ R0 = R1 + R0;
+ [P0] = R0;
+ rts;
+ENDPROC (_atomic_add32)
+
+.align 16
+ /*
+ * Atomic sub, 32 bit.
+ * Inputs: P0: memory address to use
+ * R0: value to subtract
+ * Outputs: R0: new contents of the memory address.
+ * R1: previous contents of the memory address.
+ */
+ENTRY(_atomic_sub32)
+ R1 = [P0];
+ R0 = R1 - R0;
+ [P0] = R0;
+ rts;
+ENDPROC (_atomic_sub32)
+
+.align 16
+ /*
+ * Atomic ior, 32 bit.
+ * Inputs: P0: memory address to use
+ * R0: value to ior
+ * Outputs: R0: new contents of the memory address.
+ * R1: previous contents of the memory address.
+ */
+ENTRY(_atomic_ior32)
+ R1 = [P0];
+ R0 = R1 | R0;
+ [P0] = R0;
+ rts;
+ENDPROC (_atomic_ior32)
+
+.align 16
+ /*
+ * Atomic ior, 32 bit.
+ * Inputs: P0: memory address to use
+ * R0: value to ior
+ * Outputs: R0: new contents of the memory address.
+ * R1: previous contents of the memory address.
+ */
+ENTRY(_atomic_and32)
+ R1 = [P0];
+ R0 = R1 & R0;
+ [P0] = R0;
+ rts;
+ENDPROC (_atomic_ior32)
+
+.align 16
+ /*
+ * Atomic ior, 32 bit.
+ * Inputs: P0: memory address to use
+ * R0: value to ior
+ * Outputs: R0: new contents of the memory address.
+ * R1: previous contents of the memory address.
+ */
+ENTRY(_atomic_xor32)
+ R1 = [P0];
+ R0 = R1 ^ R0;
+ [P0] = R0;
+ rts;
+ENDPROC (_atomic_ior32)
+
+ENTRY(_fixed_code_end)
diff --git a/arch/blackfin/kernel/flat.c b/arch/blackfin/kernel/flat.c
index a92587b628b5..d188b2430536 100644
--- a/arch/blackfin/kernel/flat.c
+++ b/arch/blackfin/kernel/flat.c
@@ -36,24 +36,22 @@ unsigned long bfin_get_addr_from_rp(unsigned long *ptr,
unsigned long val;
switch (type) {
- case FLAT_BFIN_RELOC_TYPE_16_BIT:
- case FLAT_BFIN_RELOC_TYPE_16H_BIT:
- usptr = (unsigned short *)ptr;
- pr_debug("*usptr = %x", get_unaligned(usptr));
- val = get_unaligned(usptr);
- val += *persistent;
- break;
+ case FLAT_BFIN_RELOC_TYPE_16_BIT:
+ case FLAT_BFIN_RELOC_TYPE_16H_BIT:
+ usptr = (unsigned short *)ptr;
+ pr_debug("*usptr = %x", get_unaligned(usptr));
+ val = get_unaligned(usptr);
+ val += *persistent;
+ break;
- case FLAT_BFIN_RELOC_TYPE_32_BIT:
- pr_debug("*ptr = %lx", get_unaligned(ptr));
- val = get_unaligned(ptr);
- break;
+ case FLAT_BFIN_RELOC_TYPE_32_BIT:
+ pr_debug("*ptr = %lx", get_unaligned(ptr));
+ val = get_unaligned(ptr);
+ break;
- default:
- pr_debug("BINFMT_FLAT: Unknown relocation type %x\n",
- type);
-
- return 0;
+ default:
+ pr_debug("BINFMT_FLAT: Unknown relocation type %x\n", type);
+ return 0;
}
/*
@@ -81,21 +79,20 @@ void bfin_put_addr_at_rp(unsigned long *ptr, unsigned long addr,
int type = (relval >> 26) & 7;
switch (type) {
- case FLAT_BFIN_RELOC_TYPE_16_BIT:
- put_unaligned(addr, usptr);
- pr_debug("new value %x at %p", get_unaligned(usptr),
- usptr);
- break;
+ case FLAT_BFIN_RELOC_TYPE_16_BIT:
+ put_unaligned(addr, usptr);
+ pr_debug("new value %x at %p", get_unaligned(usptr), usptr);
+ break;
- case FLAT_BFIN_RELOC_TYPE_16H_BIT:
- put_unaligned(addr >> 16, usptr);
- pr_debug("new value %x", get_unaligned(usptr));
- break;
+ case FLAT_BFIN_RELOC_TYPE_16H_BIT:
+ put_unaligned(addr >> 16, usptr);
+ pr_debug("new value %x", get_unaligned(usptr));
+ break;
- case FLAT_BFIN_RELOC_TYPE_32_BIT:
- put_unaligned(addr, ptr);
- pr_debug("new ptr =%lx", get_unaligned(ptr));
- break;
+ case FLAT_BFIN_RELOC_TYPE_32_BIT:
+ put_unaligned(addr, ptr);
+ pr_debug("new ptr =%lx", get_unaligned(ptr));
+ break;
}
}
EXPORT_SYMBOL(bfin_put_addr_at_rp);
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
index 80996a1a94ca..1fc001c7abda 100644
--- a/arch/blackfin/kernel/irqchip.c
+++ b/arch/blackfin/kernel/irqchip.c
@@ -82,7 +82,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_printf(p, ", %s", action->name);
seq_putc(p, '\n');
- unlock:
+ unlock:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
} else if (i == NR_IRQS) {
seq_printf(p, "Err: %10lu\n", irq_err_count);
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
new file mode 100644
index 000000000000..a9c15515bfd7
--- /dev/null
+++ b/arch/blackfin/kernel/kgdb.c
@@ -0,0 +1,421 @@
+/*
+ * File: arch/blackfin/kernel/kgdb.c
+ * Based on:
+ * Author: Sonic Zhang
+ *
+ * Created:
+ * Description:
+ *
+ * Rev: $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
+ *
+ * Modified:
+ * Copyright 2005-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/ptrace.h> /* for linux pt_regs struct */
+#include <linux/kgdb.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/debugger.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+#include <asm/blackfin.h>
+
+/* Put the error code here just in case the user cares. */
+int gdb_bf533errcode;
+/* Likewise, the vector number here (since GDB only gets the signal
+ number through the usual means, and that's not very specific). */
+int gdb_bf533vector = -1;
+
+#if KGDB_MAX_NO_CPUS != 8
+#error change the definition of slavecpulocks
+#endif
+
+void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ gdb_regs[BFIN_R0] = regs->r0;
+ gdb_regs[BFIN_R1] = regs->r1;
+ gdb_regs[BFIN_R2] = regs->r2;
+ gdb_regs[BFIN_R3] = regs->r3;
+ gdb_regs[BFIN_R4] = regs->r4;
+ gdb_regs[BFIN_R5] = regs->r5;
+ gdb_regs[BFIN_R6] = regs->r6;
+ gdb_regs[BFIN_R7] = regs->r7;
+ gdb_regs[BFIN_P0] = regs->p0;
+ gdb_regs[BFIN_P1] = regs->p1;
+ gdb_regs[BFIN_P2] = regs->p2;
+ gdb_regs[BFIN_P3] = regs->p3;
+ gdb_regs[BFIN_P4] = regs->p4;
+ gdb_regs[BFIN_P5] = regs->p5;
+ gdb_regs[BFIN_SP] = regs->reserved;
+ gdb_regs[BFIN_FP] = regs->fp;
+ gdb_regs[BFIN_I0] = regs->i0;
+ gdb_regs[BFIN_I1] = regs->i1;
+ gdb_regs[BFIN_I2] = regs->i2;
+ gdb_regs[BFIN_I3] = regs->i3;
+ gdb_regs[BFIN_M0] = regs->m0;
+ gdb_regs[BFIN_M1] = regs->m1;
+ gdb_regs[BFIN_M2] = regs->m2;
+ gdb_regs[BFIN_M3] = regs->m3;
+ gdb_regs[BFIN_B0] = regs->b0;
+ gdb_regs[BFIN_B1] = regs->b1;
+ gdb_regs[BFIN_B2] = regs->b2;
+ gdb_regs[BFIN_B3] = regs->b3;
+ gdb_regs[BFIN_L0] = regs->l0;
+ gdb_regs[BFIN_L1] = regs->l1;
+ gdb_regs[BFIN_L2] = regs->l2;
+ gdb_regs[BFIN_L3] = regs->l3;
+ gdb_regs[BFIN_A0_DOT_X] = regs->a0x;
+ gdb_regs[BFIN_A0_DOT_W] = regs->a0w;
+ gdb_regs[BFIN_A1_DOT_X] = regs->a1x;
+ gdb_regs[BFIN_A1_DOT_W] = regs->a1w;
+ gdb_regs[BFIN_ASTAT] = regs->astat;
+ gdb_regs[BFIN_RETS] = regs->rets;
+ gdb_regs[BFIN_LC0] = regs->lc0;
+ gdb_regs[BFIN_LT0] = regs->lt0;
+ gdb_regs[BFIN_LB0] = regs->lb0;
+ gdb_regs[BFIN_LC1] = regs->lc1;
+ gdb_regs[BFIN_LT1] = regs->lt1;
+ gdb_regs[BFIN_LB1] = regs->lb1;
+ gdb_regs[BFIN_CYCLES] = 0;
+ gdb_regs[BFIN_CYCLES2] = 0;
+ gdb_regs[BFIN_USP] = regs->usp;
+ gdb_regs[BFIN_SEQSTAT] = regs->seqstat;
+ gdb_regs[BFIN_SYSCFG] = regs->syscfg;
+ gdb_regs[BFIN_RETI] = regs->pc;
+ gdb_regs[BFIN_RETX] = regs->retx;
+ gdb_regs[BFIN_RETN] = regs->retn;
+ gdb_regs[BFIN_RETE] = regs->rete;
+ gdb_regs[BFIN_PC] = regs->pc;
+ gdb_regs[BFIN_CC] = 0;
+ gdb_regs[BFIN_EXTRA1] = 0;
+ gdb_regs[BFIN_EXTRA2] = 0;
+ gdb_regs[BFIN_EXTRA3] = 0;
+ gdb_regs[BFIN_IPEND] = regs->ipend;
+}
+
+/*
+ * Extracts ebp, esp and eip values understandable by gdb from the values
+ * saved by switch_to.
+ * thread.esp points to ebp. flags and ebp are pushed in switch_to hence esp
+ * prior to entering switch_to is 8 greater then the value that is saved.
+ * If switch_to changes, change following code appropriately.
+ */
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+ gdb_regs[BFIN_SP] = p->thread.ksp;
+ gdb_regs[BFIN_PC] = p->thread.pc;
+ gdb_regs[BFIN_SEQSTAT] = p->thread.seqstat;
+}
+
+void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ regs->r0 = gdb_regs[BFIN_R0];
+ regs->r1 = gdb_regs[BFIN_R1];
+ regs->r2 = gdb_regs[BFIN_R2];
+ regs->r3 = gdb_regs[BFIN_R3];
+ regs->r4 = gdb_regs[BFIN_R4];
+ regs->r5 = gdb_regs[BFIN_R5];
+ regs->r6 = gdb_regs[BFIN_R6];
+ regs->r7 = gdb_regs[BFIN_R7];
+ regs->p0 = gdb_regs[BFIN_P0];
+ regs->p1 = gdb_regs[BFIN_P1];
+ regs->p2 = gdb_regs[BFIN_P2];
+ regs->p3 = gdb_regs[BFIN_P3];
+ regs->p4 = gdb_regs[BFIN_P4];
+ regs->p5 = gdb_regs[BFIN_P5];
+ regs->fp = gdb_regs[BFIN_FP];
+ regs->i0 = gdb_regs[BFIN_I0];
+ regs->i1 = gdb_regs[BFIN_I1];
+ regs->i2 = gdb_regs[BFIN_I2];
+ regs->i3 = gdb_regs[BFIN_I3];
+ regs->m0 = gdb_regs[BFIN_M0];
+ regs->m1 = gdb_regs[BFIN_M1];
+ regs->m2 = gdb_regs[BFIN_M2];
+ regs->m3 = gdb_regs[BFIN_M3];
+ regs->b0 = gdb_regs[BFIN_B0];
+ regs->b1 = gdb_regs[BFIN_B1];
+ regs->b2 = gdb_regs[BFIN_B2];
+ regs->b3 = gdb_regs[BFIN_B3];
+ regs->l0 = gdb_regs[BFIN_L0];
+ regs->l1 = gdb_regs[BFIN_L1];
+ regs->l2 = gdb_regs[BFIN_L2];
+ regs->l3 = gdb_regs[BFIN_L3];
+ regs->a0x = gdb_regs[BFIN_A0_DOT_X];
+ regs->a0w = gdb_regs[BFIN_A0_DOT_W];
+ regs->a1x = gdb_regs[BFIN_A1_DOT_X];
+ regs->a1w = gdb_regs[BFIN_A1_DOT_W];
+ regs->rets = gdb_regs[BFIN_RETS];
+ regs->lc0 = gdb_regs[BFIN_LC0];
+ regs->lt0 = gdb_regs[BFIN_LT0];
+ regs->lb0 = gdb_regs[BFIN_LB0];
+ regs->lc1 = gdb_regs[BFIN_LC1];
+ regs->lt1 = gdb_regs[BFIN_LT1];
+ regs->lb1 = gdb_regs[BFIN_LB1];
+ regs->usp = gdb_regs[BFIN_USP];
+ regs->syscfg = gdb_regs[BFIN_SYSCFG];
+ regs->retx = gdb_regs[BFIN_PC];
+ regs->retn = gdb_regs[BFIN_RETN];
+ regs->rete = gdb_regs[BFIN_RETE];
+ regs->pc = gdb_regs[BFIN_PC];
+
+#if 0 /* can't change these */
+ regs->astat = gdb_regs[BFIN_ASTAT];
+ regs->seqstat = gdb_regs[BFIN_SEQSTAT];
+ regs->ipend = gdb_regs[BFIN_IPEND];
+#endif
+}
+
+struct hw_breakpoint {
+ unsigned int occupied:1;
+ unsigned int skip:1;
+ unsigned int enabled:1;
+ unsigned int type:1;
+ unsigned int dataacc:2;
+ unsigned short count;
+ unsigned int addr;
+} breakinfo[HW_BREAKPOINT_NUM];
+
+int kgdb_arch_init(void)
+{
+ kgdb_remove_all_hw_break();
+ return 0;
+}
+
+int kgdb_set_hw_break(unsigned long addr)
+{
+ int breakno;
+ for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
+ if (!breakinfo[breakno].occupied) {
+ breakinfo[breakno].occupied = 1;
+ breakinfo[breakno].enabled = 1;
+ breakinfo[breakno].type = 1;
+ breakinfo[breakno].addr = addr;
+ return 0;
+ }
+
+ return -ENOSPC;
+}
+
+int kgdb_remove_hw_break(unsigned long addr)
+{
+ int breakno;
+ for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++)
+ if (breakinfo[breakno].addr == addr)
+ memset(&(breakinfo[breakno]), 0, sizeof(struct hw_breakpoint));
+
+ return 0;
+}
+
+void kgdb_remove_all_hw_break(void)
+{
+ memset(breakinfo, 0, sizeof(struct hw_breakpoint)*8);
+}
+
+/*
+void kgdb_show_info(void)
+{
+ printk(KERN_DEBUG "hwd: wpia0=0x%x, wpiacnt0=%d, wpiactl=0x%x, wpstat=0x%x\n",
+ bfin_read_WPIA0(), bfin_read_WPIACNT0(),
+ bfin_read_WPIACTL(), bfin_read_WPSTAT());
+}
+*/
+
+void kgdb_correct_hw_break(void)
+{
+ int breakno;
+ int correctit;
+ uint32_t wpdactl = bfin_read_WPDACTL();
+
+ correctit = 0;
+ for (breakno = 0; breakno < HW_BREAKPOINT_NUM; breakno++) {
+ if (breakinfo[breakno].type == 1) {
+ switch (breakno) {
+ case 0:
+ if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN0)) {
+ correctit = 1;
+ wpdactl &= ~(WPIREN01|EMUSW0);
+ wpdactl |= WPIAEN0|WPICNTEN0;
+ bfin_write_WPIA0(breakinfo[breakno].addr);
+ bfin_write_WPIACNT0(breakinfo[breakno].skip);
+ } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN0)) {
+ correctit = 1;
+ wpdactl &= ~WPIAEN0;
+ }
+ break;
+
+ case 1:
+ if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN1)) {
+ correctit = 1;
+ wpdactl &= ~(WPIREN01|EMUSW1);
+ wpdactl |= WPIAEN1|WPICNTEN1;
+ bfin_write_WPIA1(breakinfo[breakno].addr);
+ bfin_write_WPIACNT1(breakinfo[breakno].skip);
+ } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN1)) {
+ correctit = 1;
+ wpdactl &= ~WPIAEN1;
+ }
+ break;
+
+ case 2:
+ if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN2)) {
+ correctit = 1;
+ wpdactl &= ~(WPIREN23|EMUSW2);
+ wpdactl |= WPIAEN2|WPICNTEN2;
+ bfin_write_WPIA2(breakinfo[breakno].addr);
+ bfin_write_WPIACNT2(breakinfo[breakno].skip);
+ } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN2)) {
+ correctit = 1;
+ wpdactl &= ~WPIAEN2;
+ }
+ break;
+
+ case 3:
+ if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN3)) {
+ correctit = 1;
+ wpdactl &= ~(WPIREN23|EMUSW3);
+ wpdactl |= WPIAEN3|WPICNTEN3;
+ bfin_write_WPIA3(breakinfo[breakno].addr);
+ bfin_write_WPIACNT3(breakinfo[breakno].skip);
+ } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN3)) {
+ correctit = 1;
+ wpdactl &= ~WPIAEN3;
+ }
+ break;
+ case 4:
+ if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN4)) {
+ correctit = 1;
+ wpdactl &= ~(WPIREN45|EMUSW4);
+ wpdactl |= WPIAEN4|WPICNTEN4;
+ bfin_write_WPIA4(breakinfo[breakno].addr);
+ bfin_write_WPIACNT4(breakinfo[breakno].skip);
+ } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN4)) {
+ correctit = 1;
+ wpdactl &= ~WPIAEN4;
+ }
+ break;
+ case 5:
+ if (breakinfo[breakno].enabled && !(wpdactl & WPIAEN5)) {
+ correctit = 1;
+ wpdactl &= ~(WPIREN45|EMUSW5);
+ wpdactl |= WPIAEN5|WPICNTEN5;
+ bfin_write_WPIA5(breakinfo[breakno].addr);
+ bfin_write_WPIACNT5(breakinfo[breakno].skip);
+ } else if (!breakinfo[breakno].enabled && (wpdactl & WPIAEN5)) {
+ correctit = 1;
+ wpdactl &= ~WPIAEN5;
+ }
+ break;
+ }
+ }
+ }
+ if (correctit) {
+ wpdactl &= ~WPAND;
+ wpdactl |= WPPWR;
+ /*printk("correct_hw_break: wpdactl=0x%x\n", wpdactl);*/
+ bfin_write_WPDACTL(wpdactl);
+ CSYNC();
+ /*kgdb_show_info();*/
+ }
+}
+
+void kgdb_disable_hw_debug(struct pt_regs *regs)
+{
+ /* Disable hardware debugging while we are in kgdb */
+ bfin_write_WPIACTL(bfin_read_WPIACTL() & ~0x1);
+ CSYNC();
+}
+
+void kgdb_post_master_code(struct pt_regs *regs, int eVector, int err_code)
+{
+ /* Master processor is completely in the debugger */
+ gdb_bf533vector = eVector;
+ gdb_bf533errcode = err_code;
+}
+
+int kgdb_arch_handle_exception(int exceptionVector, int signo,
+ int err_code, char *remcom_in_buffer,
+ char *remcom_out_buffer,
+ struct pt_regs *linux_regs)
+{
+ long addr;
+ long breakno;
+ char *ptr;
+ int newPC;
+ int wp_status;
+
+ switch (remcom_in_buffer[0]) {
+ case 'c':
+ case 's':
+ if (kgdb_contthread && kgdb_contthread != current) {
+ strcpy(remcom_out_buffer, "E00");
+ break;
+ }
+
+ kgdb_contthread = NULL;
+
+ /* try to read optional parameter, pc unchanged if no parm */
+ ptr = &remcom_in_buffer[1];
+ if (kgdb_hex2long(&ptr, &addr)) {
+ linux_regs->retx = addr;
+ }
+ newPC = linux_regs->retx;
+
+ /* clear the trace bit */
+ linux_regs->syscfg &= 0xfffffffe;
+
+ /* set the trace bit if we're stepping */
+ if (remcom_in_buffer[0] == 's') {
+ linux_regs->syscfg |= 0x1;
+ debugger_step = 1;
+ }
+
+ wp_status = bfin_read_WPSTAT();
+ CSYNC();
+
+ if (exceptionVector == VEC_WATCH) {
+ for (breakno = 0; breakno < 6; ++breakno) {
+ if (wp_status & (1 << breakno)) {
+ breakinfo->skip = 1;
+ break;
+ }
+ }
+ }
+ kgdb_correct_hw_break();
+
+ bfin_write_WPSTAT(0);
+
+ return 0;
+ } /* switch */
+ return -1; /* this means that we do not want to exit from the handler */
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+ .gdb_bpt_instr = {0xa1},
+ .flags = KGDB_HW_BREAKPOINT,
+};
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
index 372f756f1ad9..8b9fe29d03f4 100644
--- a/arch/blackfin/kernel/module.c
+++ b/arch/blackfin/kernel/module.c
@@ -165,8 +165,8 @@ module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
for (s = sechdrs; s < sechdrs_end; ++s) {
if ((strcmp(".l1.text", secstrings + s->sh_name) == 0) ||
- ((strcmp(".text", secstrings + s->sh_name)==0) &&
- (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
+ ((strcmp(".text", secstrings + s->sh_name) == 0) &&
+ (hdr->e_flags & FLG_CODE_IN_L1) && (s->sh_size > 0))) {
mod->arch.text_l1 = s;
dest = l1_inst_sram_alloc(s->sh_size);
if (dest == NULL) {
@@ -179,9 +179,9 @@ module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
s->sh_flags &= ~SHF_ALLOC;
s->sh_addr = (unsigned long)dest;
}
- if ((strcmp(".l1.data", secstrings + s->sh_name) == 0)||
- ((strcmp(".data", secstrings + s->sh_name)==0) &&
- (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
+ if ((strcmp(".l1.data", secstrings + s->sh_name) == 0) ||
+ ((strcmp(".data", secstrings + s->sh_name) == 0) &&
+ (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
mod->arch.data_a_l1 = s;
dest = l1_data_sram_alloc(s->sh_size);
if (dest == NULL) {
@@ -195,8 +195,8 @@ module_frob_arch_sections(Elf_Ehdr * hdr, Elf_Shdr * sechdrs,
s->sh_addr = (unsigned long)dest;
}
if (strcmp(".l1.bss", secstrings + s->sh_name) == 0 ||
- ((strcmp(".bss", secstrings + s->sh_name)==0) &&
- (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
+ ((strcmp(".bss", secstrings + s->sh_name) == 0) &&
+ (hdr->e_flags & FLG_DATA_IN_L1) && (s->sh_size > 0))) {
mod->arch.bss_a_l1 = s;
dest = l1_data_sram_alloc(s->sh_size);
if (dest == NULL) {
@@ -326,7 +326,7 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
pr_debug("before %x after %x\n", *location16,
(value & 0xffff));
tmp = (value & 0xffff);
- if((unsigned long)location16 >= L1_CODE_START) {
+ if ((unsigned long)location16 >= L1_CODE_START) {
dma_memcpy(location16, &tmp, 2);
} else
*location16 = tmp;
@@ -335,7 +335,7 @@ apply_relocate_add(Elf_Shdr * sechdrs, const char *strtab,
pr_debug("before %x after %x\n", *location16,
((value >> 16) & 0xffff));
tmp = ((value >> 16) & 0xffff);
- if((unsigned long)location16 >= L1_CODE_START) {
+ if ((unsigned long)location16 >= L1_CODE_START) {
dma_memcpy(location16, &tmp, 2);
} else
*location16 = tmp;
@@ -404,8 +404,8 @@ module_finalize(const Elf_Ehdr * hdr,
continue;
if ((sechdrs[i].sh_type == SHT_RELA) &&
- ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0)||
- ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
+ ((strcmp(".rela.l1.text", secstrings + sechdrs[i].sh_name) == 0) ||
+ ((strcmp(".rela.text", secstrings + sechdrs[i].sh_name) == 0) &&
(hdr->e_flags & FLG_CODE_IN_L1)))) {
apply_relocate_add((Elf_Shdr *) sechdrs, strtab,
symindex, i, mod);
@@ -417,13 +417,13 @@ module_finalize(const Elf_Ehdr * hdr,
void module_arch_cleanup(struct module *mod)
{
if ((mod->arch.text_l1) && (mod->arch.text_l1->sh_addr))
- l1_inst_sram_free((void*)mod->arch.text_l1->sh_addr);
+ l1_inst_sram_free((void *)mod->arch.text_l1->sh_addr);
if ((mod->arch.data_a_l1) && (mod->arch.data_a_l1->sh_addr))
- l1_data_sram_free((void*)mod->arch.data_a_l1->sh_addr);
+ l1_data_sram_free((void *)mod->arch.data_a_l1->sh_addr);
if ((mod->arch.bss_a_l1) && (mod->arch.bss_a_l1->sh_addr))
- l1_data_sram_free((void*)mod->arch.bss_a_l1->sh_addr);
+ l1_data_sram_free((void *)mod->arch.bss_a_l1->sh_addr);
if ((mod->arch.data_b_l1) && (mod->arch.data_b_l1->sh_addr))
- l1_data_B_sram_free((void*)mod->arch.data_b_l1->sh_addr);
+ l1_data_B_sram_free((void *)mod->arch.data_b_l1->sh_addr);
if ((mod->arch.bss_b_l1) && (mod->arch.bss_b_l1->sh_addr))
- l1_data_B_sram_free((void*)mod->arch.bss_b_l1->sh_addr);
+ l1_data_B_sram_free((void *)mod->arch.bss_b_l1->sh_addr);
}
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 3eff7439d8d3..5a51dd6ab280 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -32,9 +32,10 @@
#include <linux/unistd.h>
#include <linux/user.h>
#include <linux/a.out.h>
+#include <linux/uaccess.h>
#include <asm/blackfin.h>
-#include <asm/uaccess.h>
+#include <asm/fixed_code.h>
#define LED_ON 0
#define LED_OFF 1
@@ -173,8 +174,8 @@ void show_regs(struct pt_regs *regs)
printk(KERN_NOTICE "R4: %08lx R5: %08lx R6: %08lx R7: %08lx\n",
regs->r4, regs->r5, regs->r6, regs->r7);
- if (!(regs->ipend))
- printk("USP: %08lx\n", rdusp());
+ if (!regs->ipend)
+ printk(KERN_NOTICE "USP: %08lx\n", rdusp());
}
/* Fill in the fpu structure for a core dump. */
@@ -322,7 +323,7 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp)
goto out;
error = do_execve(filename, argv, envp, regs);
putname(filename);
- out:
+ out:
unlock_kernel();
return error;
}
@@ -350,13 +351,77 @@ unsigned long get_wchan(struct task_struct *p)
return 0;
}
+void finish_atomic_sections (struct pt_regs *regs)
+{
+ if (regs->pc < ATOMIC_SEQS_START || regs->pc >= ATOMIC_SEQS_END)
+ return;
+
+ switch (regs->pc) {
+ case ATOMIC_XCHG32 + 2:
+ put_user(regs->r1, (int *)regs->p0);
+ regs->pc += 2;
+ break;
+
+ case ATOMIC_CAS32 + 2:
+ case ATOMIC_CAS32 + 4:
+ if (regs->r0 == regs->r1)
+ put_user(regs->r2, (int *)regs->p0);
+ regs->pc = ATOMIC_CAS32 + 8;
+ break;
+ case ATOMIC_CAS32 + 6:
+ put_user(regs->r2, (int *)regs->p0);
+ regs->pc += 2;
+ break;
+
+ case ATOMIC_ADD32 + 2:
+ regs->r0 = regs->r1 + regs->r0;
+ /* fall through */
+ case ATOMIC_ADD32 + 4:
+ put_user(regs->r0, (int *)regs->p0);
+ regs->pc = ATOMIC_ADD32 + 6;
+ break;
+
+ case ATOMIC_SUB32 + 2:
+ regs->r0 = regs->r1 - regs->r0;
+ /* fall through */
+ case ATOMIC_SUB32 + 4:
+ put_user(regs->r0, (int *)regs->p0);
+ regs->pc = ATOMIC_SUB32 + 6;
+ break;
+
+ case ATOMIC_IOR32 + 2:
+ regs->r0 = regs->r1 | regs->r0;
+ /* fall through */
+ case ATOMIC_IOR32 + 4:
+ put_user(regs->r0, (int *)regs->p0);
+ regs->pc = ATOMIC_IOR32 + 6;
+ break;
+
+ case ATOMIC_AND32 + 2:
+ regs->r0 = regs->r1 & regs->r0;
+ /* fall through */
+ case ATOMIC_AND32 + 4:
+ put_user(regs->r0, (int *)regs->p0);
+ regs->pc = ATOMIC_AND32 + 6;
+ break;
+
+ case ATOMIC_XOR32 + 2:
+ regs->r0 = regs->r1 ^ regs->r0;
+ /* fall through */
+ case ATOMIC_XOR32 + 4:
+ put_user(regs->r0, (int *)regs->p0);
+ regs->pc = ATOMIC_XOR32 + 6;
+ break;
+ }
+}
+
#if defined(CONFIG_ACCESS_CHECK)
int _access_ok(unsigned long addr, unsigned long size)
{
if (addr > (addr + size))
return 0;
- if (segment_eq(get_fs(),KERNEL_DS))
+ if (segment_eq(get_fs(), KERNEL_DS))
return 1;
#ifdef CONFIG_MTD_UCLINUX
if (addr >= memory_start && (addr + size) <= memory_end)
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index e718bb4a1ef0..ed800c7456dd 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -36,8 +36,8 @@
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/signal.h>
+#include <linux/uaccess.h>
-#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -122,7 +122,7 @@ static inline long get_reg(struct task_struct *task, int regno)
static inline int
put_reg(struct task_struct *task, int regno, unsigned long data)
{
- char * reg_ptr;
+ char *reg_ptr;
struct pt_regs *regs =
(struct pt_regs *)((unsigned long)task_stack_page(task) +
@@ -146,7 +146,7 @@ put_reg(struct task_struct *task, int regno, unsigned long data)
break;
default:
if (regno <= 216)
- *(long *)(reg_ptr + regno) = data;
+ *(long *)(reg_ptr + regno) = data;
}
return 0;
}
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 83060f98d15d..f59dcee7bae3 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -42,6 +42,7 @@
#include <asm/cacheflush.h>
#include <asm/blackfin.h>
#include <asm/cplbinit.h>
+#include <asm/fixed_code.h>
u16 _bfin_swrst;
@@ -63,10 +64,6 @@ EXPORT_SYMBOL(mtd_size);
char __initdata command_line[COMMAND_LINE_SIZE];
-#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
-static void generate_cpl_tables(void);
-#endif
-
void __init bf53x_cache_init(void)
{
#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
@@ -197,6 +194,17 @@ void __init setup_arch(char **cmdline_p)
/* this give a chance to get printk() working before crash. */
#endif
+ printk(KERN_INFO "Hardware Trace ");
+ if (bfin_read_TBUFCTL() & 0x1 )
+ printk("Active ");
+ else
+ printk("Off ");
+ if (bfin_read_TBUFCTL() & 0x2)
+ printk("and Enabled\n");
+ else
+ printk("and Disabled\n");
+
+
#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
/* we need to initialize the Flashrom device here since we might
* do things with flash early on in the boot
@@ -354,15 +362,15 @@ void __init setup_arch(char **cmdline_p)
, _stext, _etext,
__start_rodata, __end_rodata,
_sdata, _edata,
- (void*)&init_thread_union, (void*)((int)(&init_thread_union) + 0x2000),
+ (void *)&init_thread_union, (void *)((int)(&init_thread_union) + 0x2000),
__init_begin, __init_end,
__bss_start, __bss_stop,
- (void*)_ramstart, (void*)memory_end
+ (void *)_ramstart, (void *)memory_end
#ifdef CONFIG_MTD_UCLINUX
- , (void*)memory_mtd_start, (void*)(memory_mtd_start + mtd_size)
+ , (void *)memory_mtd_start, (void *)(memory_mtd_start + mtd_size)
#endif
#if DMA_UNCACHED_REGION > 0
- , (void*)(_ramend - DMA_UNCACHED_REGION), (void*)(_ramend)
+ , (void *)(_ramend - DMA_UNCACHED_REGION), (void *)(_ramend)
#endif
);
@@ -388,11 +396,11 @@ void __init setup_arch(char **cmdline_p)
/* check the size of the l1 area */
l1_length = _etext_l1 - _stext_l1;
if (l1_length > L1_CODE_LENGTH)
- panic("L1 memory overflow\n");
+ panic("L1 code memory overflow\n");
l1_length = _ebss_l1 - _sdata_l1;
if (l1_length > L1_DATA_A_LENGTH)
- panic("L1 memory overflow\n");
+ panic("L1 data memory overflow\n");
#ifdef BF561_FAMILY
_bfin_swrst = bfin_read_SICA_SWRST();
@@ -400,10 +408,28 @@ void __init setup_arch(char **cmdline_p)
_bfin_swrst = bfin_read_SWRST();
#endif
- bf53x_cache_init();
+ /* Copy atomic sequences to their fixed location, and sanity check that
+ these locations are the ones that we advertise to userspace. */
+ memcpy((void *)FIXED_CODE_START, &fixed_code_start,
+ FIXED_CODE_END - FIXED_CODE_START);
+ BUG_ON((char *)&sigreturn_stub - (char *)&fixed_code_start
+ != SIGRETURN_STUB - FIXED_CODE_START);
+ BUG_ON((char *)&atomic_xchg32 - (char *)&fixed_code_start
+ != ATOMIC_XCHG32 - FIXED_CODE_START);
+ BUG_ON((char *)&atomic_cas32 - (char *)&fixed_code_start
+ != ATOMIC_CAS32 - FIXED_CODE_START);
+ BUG_ON((char *)&atomic_add32 - (char *)&fixed_code_start
+ != ATOMIC_ADD32 - FIXED_CODE_START);
+ BUG_ON((char *)&atomic_sub32 - (char *)&fixed_code_start
+ != ATOMIC_SUB32 - FIXED_CODE_START);
+ BUG_ON((char *)&atomic_ior32 - (char *)&fixed_code_start
+ != ATOMIC_IOR32 - FIXED_CODE_START);
+ BUG_ON((char *)&atomic_and32 - (char *)&fixed_code_start
+ != ATOMIC_AND32 - FIXED_CODE_START);
+ BUG_ON((char *)&atomic_xor32 - (char *)&fixed_code_start
+ != ATOMIC_XOR32 - FIXED_CODE_START);
- printk(KERN_INFO "Hardware Trace Enabled\n");
- bfin_write_TBUFCTL(0x03);
+ bf53x_cache_init();
}
static int __init topology_init(void)
@@ -421,286 +447,6 @@ static int __init topology_init(void)
subsys_initcall(topology_init);
-#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
-static u16 __init lock_kernel_check(u32 start, u32 end)
-{
- if ((start <= (u32) _stext && end >= (u32) _end)
- || (start >= (u32) _stext && end <= (u32) _end))
- return IN_KERNEL;
- return 0;
-}
-
-static unsigned short __init
-fill_cplbtab(struct cplb_tab *table,
- unsigned long start, unsigned long end,
- unsigned long block_size, unsigned long cplb_data)
-{
- int i;
-
- switch (block_size) {
- case SIZE_4M:
- i = 3;
- break;
- case SIZE_1M:
- i = 2;
- break;
- case SIZE_4K:
- i = 1;
- break;
- case SIZE_1K:
- default:
- i = 0;
- break;
- }
-
- cplb_data = (cplb_data & ~(3 << 16)) | (i << 16);
-
- while ((start < end) && (table->pos < table->size)) {
-
- table->tab[table->pos++] = start;
-
- if (lock_kernel_check(start, start + block_size) == IN_KERNEL)
- table->tab[table->pos++] =
- cplb_data | CPLB_LOCK | CPLB_DIRTY;
- else
- table->tab[table->pos++] = cplb_data;
-
- start += block_size;
- }
- return 0;
-}
-
-static unsigned short __init
-close_cplbtab(struct cplb_tab *table)
-{
-
- while (table->pos < table->size) {
-
- table->tab[table->pos++] = 0;
- table->tab[table->pos++] = 0; /* !CPLB_VALID */
- }
- return 0;
-}
-
-/* helper function */
-static void __fill_code_cplbtab(struct cplb_tab *t, int i,
- u32 a_start, u32 a_end)
-{
- if (cplb_data[i].psize) {
- fill_cplbtab(t,
- cplb_data[i].start,
- cplb_data[i].end,
- cplb_data[i].psize,
- cplb_data[i].i_conf);
- } else {
-#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263))
- if (i == SDRAM_KERN) {
- fill_cplbtab(t,
- cplb_data[i].start,
- cplb_data[i].end,
- SIZE_4M,
- cplb_data[i].i_conf);
- } else {
-#endif
- fill_cplbtab(t,
- cplb_data[i].start,
- a_start,
- SIZE_1M,
- cplb_data[i].i_conf);
- fill_cplbtab(t,
- a_start,
- a_end,
- SIZE_4M,
- cplb_data[i].i_conf);
- fill_cplbtab(t, a_end,
- cplb_data[i].end,
- SIZE_1M,
- cplb_data[i].i_conf);
- }
- }
-}
-
-static void __fill_data_cplbtab(struct cplb_tab *t, int i,
- u32 a_start, u32 a_end)
-{
- if (cplb_data[i].psize) {
- fill_cplbtab(t,
- cplb_data[i].start,
- cplb_data[i].end,
- cplb_data[i].psize,
- cplb_data[i].d_conf);
- } else {
- fill_cplbtab(t,
- cplb_data[i].start,
- a_start, SIZE_1M,
- cplb_data[i].d_conf);
- fill_cplbtab(t, a_start,
- a_end, SIZE_4M,
- cplb_data[i].d_conf);
- fill_cplbtab(t, a_end,
- cplb_data[i].end,
- SIZE_1M,
- cplb_data[i].d_conf);
- }
-}
-static void __init generate_cpl_tables(void)
-{
-
- u16 i, j, process;
- u32 a_start, a_end, as, ae, as_1m;
-
- struct cplb_tab *t_i = NULL;
- struct cplb_tab *t_d = NULL;
- struct s_cplb cplb;
-
- cplb.init_i.size = MAX_CPLBS;
- cplb.init_d.size = MAX_CPLBS;
- cplb.switch_i.size = MAX_SWITCH_I_CPLBS;
- cplb.switch_d.size = MAX_SWITCH_D_CPLBS;
-
- cplb.init_i.pos = 0;
- cplb.init_d.pos = 0;
- cplb.switch_i.pos = 0;
- cplb.switch_d.pos = 0;
-
- cplb.init_i.tab = icplb_table;
- cplb.init_d.tab = dcplb_table;
- cplb.switch_i.tab = ipdt_table;
- cplb.switch_d.tab = dpdt_table;
-
- cplb_data[SDRAM_KERN].end = memory_end;
-
-#ifdef CONFIG_MTD_UCLINUX
- cplb_data[SDRAM_RAM_MTD].start = memory_mtd_start;
- cplb_data[SDRAM_RAM_MTD].end = memory_mtd_start + mtd_size;
- cplb_data[SDRAM_RAM_MTD].valid = mtd_size > 0;
-# if defined(CONFIG_ROMFS_FS)
- cplb_data[SDRAM_RAM_MTD].attr |= I_CPLB;
-
- /*
- * The ROMFS_FS size is often not multiple of 1MB.
- * This can cause multiple CPLB sets covering the same memory area.
- * This will then cause multiple CPLB hit exceptions.
- * Workaround: We ensure a contiguous memory area by extending the kernel
- * memory section over the mtd section.
- * For ROMFS_FS memory must be covered with ICPLBs anyways.
- * So there is no difference between kernel and mtd memory setup.
- */
-
- cplb_data[SDRAM_KERN].end = memory_mtd_start + mtd_size;;
- cplb_data[SDRAM_RAM_MTD].valid = 0;
-
-# endif
-#else
- cplb_data[SDRAM_RAM_MTD].valid = 0;
-#endif
-
- cplb_data[SDRAM_DMAZ].start = _ramend - DMA_UNCACHED_REGION;
- cplb_data[SDRAM_DMAZ].end = _ramend;
-
- cplb_data[RES_MEM].start = _ramend;
- cplb_data[RES_MEM].end = physical_mem_end;
-
- if (reserved_mem_dcache_on)
- cplb_data[RES_MEM].d_conf = SDRAM_DGENERIC;
- else
- cplb_data[RES_MEM].d_conf = SDRAM_DNON_CHBL;
-
- if (reserved_mem_icache_on)
- cplb_data[RES_MEM].i_conf = SDRAM_IGENERIC;
- else
- cplb_data[RES_MEM].i_conf = SDRAM_INON_CHBL;
-
- for (i = ZERO_P; i <= L2_MEM; i++) {
- if (!cplb_data[i].valid)
- continue;
-
- as_1m = cplb_data[i].start % SIZE_1M;
-
- /*
- * We need to make sure all sections are properly 1M aligned
- * However between Kernel Memory and the Kernel mtd section,
- * depending on the rootfs size, there can be overlapping
- * memory areas.
- */
-
- if (as_1m && i != L1I_MEM && i != L1D_MEM) {
-#ifdef CONFIG_MTD_UCLINUX
- if (i == SDRAM_RAM_MTD) {
- if ((cplb_data[SDRAM_KERN].end + 1) >
- cplb_data[SDRAM_RAM_MTD].start)
- cplb_data[SDRAM_RAM_MTD].start =
- (cplb_data[i].start &
- (-2*SIZE_1M)) + SIZE_1M;
- else
- cplb_data[SDRAM_RAM_MTD].start =
- (cplb_data[i].start &
- (-2*SIZE_1M));
- } else
-#endif
- printk(KERN_WARNING
- "Unaligned Start of %s at 0x%X\n",
- cplb_data[i].name, cplb_data[i].start);
- }
-
- as = cplb_data[i].start % SIZE_4M;
- ae = cplb_data[i].end % SIZE_4M;
-
- if (as)
- a_start = cplb_data[i].start + (SIZE_4M - (as));
- else
- a_start = cplb_data[i].start;
-
- a_end = cplb_data[i].end - ae;
-
- for (j = INITIAL_T; j <= SWITCH_T; j++) {
-
- switch (j) {
- case INITIAL_T:
- if (cplb_data[i].attr & INITIAL_T) {
- t_i = &cplb.init_i;
- t_d = &cplb.init_d;
- process = 1;
- } else
- process = 0;
- break;
- case SWITCH_T:
- if (cplb_data[i].attr & SWITCH_T) {
- t_i = &cplb.switch_i;
- t_d = &cplb.switch_d;
- process = 1;
- } else
- process = 0;
- break;
- default:
- process = 0;
- break;
- }
-
- if (!process)
- continue;
- if (cplb_data[i].attr & I_CPLB)
- __fill_code_cplbtab(t_i, i, a_start, a_end);
-
- if (cplb_data[i].attr & D_CPLB)
- __fill_data_cplbtab(t_d, i, a_start, a_end);
- }
- }
-
-/* close tables */
-
- close_cplbtab(&cplb.init_i);
- close_cplbtab(&cplb.init_d);
-
- cplb.init_i.tab[cplb.init_i.pos] = -1;
- cplb.init_d.tab[cplb.init_d.pos] = -1;
- cplb.switch_i.tab[cplb.switch_i.pos] = -1;
- cplb.switch_d.tab[cplb.switch_d.pos] = -1;
-
-}
-
-#endif
-
static u_long get_vco(void)
{
u_long msel;
@@ -730,7 +476,6 @@ u_long get_cclk(void)
return get_vco() / ssel;
return get_vco() >> csel;
}
-
EXPORT_SYMBOL(get_cclk);
/* Get the System clock */
@@ -749,7 +494,6 @@ u_long get_sclk(void)
return get_vco() / ssel;
}
-
EXPORT_SYMBOL(get_sclk);
/*
@@ -804,23 +548,23 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "D-CACHE:\tOFF\n");
- switch(bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
- case ACACHE_BSRAM:
- seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
- dcache_size = 16;
- dsup_banks = 1;
- break;
- case ACACHE_BCACHE:
- seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
- dcache_size = 32;
- dsup_banks = 2;
- break;
- case ASRAM_BSRAM:
- seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
- dcache_size = 0;
- dsup_banks = 0;
- break;
- default:
+ switch (bfin_read_DMEM_CONTROL() & (1 << DMC0_P | 1 << DMC1_P)) {
+ case ACACHE_BSRAM:
+ seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tSRAM\n");
+ dcache_size = 16;
+ dsup_banks = 1;
+ break;
+ case ACACHE_BCACHE:
+ seq_printf(m, "DBANK-A:\tCACHE\n" "DBANK-B:\tCACHE\n");
+ dcache_size = 32;
+ dsup_banks = 2;
+ break;
+ case ASRAM_BSRAM:
+ seq_printf(m, "DBANK-A:\tSRAM\n" "DBANK-B:\tSRAM\n");
+ dcache_size = 0;
+ dsup_banks = 0;
+ break;
+ default:
break;
}
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index 316e65c3439d..5564c9588aa8 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -34,8 +34,8 @@
#include <linux/personality.h>
#include <linux/binfmts.h>
#include <linux/freezer.h>
+#include <linux/uaccess.h>
-#include <asm/uaccess.h>
#include <asm/cacheflush.h>
#include <asm/ucontext.h>
@@ -124,7 +124,7 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused)
return r0;
- badframe:
+ badframe:
force_sig(SIGSEGV, current);
return 0;
}
@@ -239,7 +239,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info,
return 0;
- give_sigsegv:
+ give_sigsegv:
if (sig == SIGSEGV)
ka->sa.sa_handler = SIG_DFL;
force_sig(SIGSEGV, current);
@@ -263,7 +263,7 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler)
}
/* fallthrough */
case -ERESTARTNOINTR:
- do_restart:
+ do_restart:
regs->p0 = regs->orig_p0;
regs->r0 = regs->orig_r0;
regs->pc -= 2;
@@ -341,7 +341,7 @@ asmlinkage void do_signal(struct pt_regs *regs)
return;
}
-no_signal:
+ no_signal:
/* Did we come from a system call? */
if (regs->orig_p0 >= 0)
/* Restart the system call - no handlers present */
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
index f436e6743f5a..f5e1ae3d1705 100644
--- a/arch/blackfin/kernel/sys_bfin.c
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -37,12 +37,12 @@
#include <linux/syscalls.h>
#include <linux/mman.h>
#include <linux/file.h>
+#include <linux/uaccess.h>
+#include <linux/ipc.h>
+#include <linux/unistd.h>
#include <asm/cacheflush.h>
-#include <asm/uaccess.h>
-#include <asm/ipc.h>
#include <asm/dma.h>
-#include <asm/unistd.h>
/*
* sys_pipe() is the normal C calling standard for creating
@@ -83,7 +83,7 @@ do_mmap2(unsigned long addr, unsigned long len,
if (file)
fput(file);
- out:
+ out:
return error;
}
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index f578176b6d92..beef057bd1dc 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -87,7 +87,7 @@ void __init init_leds(void)
static inline void do_leds(void)
{
static unsigned int count = 50;
- static int flag = 0;
+ static int flag;
unsigned short tmp = 0;
if (--count == 0) {
@@ -200,7 +200,7 @@ irqreturn_t timer_interrupt(int irq, void *dummy)__attribute__((l1_text));
irqreturn_t timer_interrupt(int irq, void *dummy)
{
/* last time the cmos clock got updated */
- static long last_rtc_update = 0;
+ static long last_rtc_update;
write_seqlock(&xtime_lock);
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 56058b0b6d4a..3909f5b35536 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -27,15 +27,15 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
#include <asm/traps.h>
#include <asm/cacheflush.h>
#include <asm/blackfin.h>
-#include <asm/uaccess.h>
#include <asm/irq_handler.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
+#include <asm/trace.h>
#ifdef CONFIG_KGDB
# include <linux/debugger.h>
@@ -76,7 +76,7 @@ static int printk_address(unsigned long address)
if (!modname)
modname = delim = "";
return printk("<0x%p> { %s%s%s%s + 0x%lx }",
- (void*)address, delim, modname, delim, symname,
+ (void *)address, delim, modname, delim, symname,
(unsigned long)offset);
}
@@ -119,7 +119,7 @@ static int printk_address(unsigned long address)
write_unlock_irq(&tasklist_lock);
return printk("<0x%p> [ %s + 0x%lx ]",
- (void*)address, name, offset);
+ (void *)address, name, offset);
}
vml = vml->next;
@@ -128,19 +128,9 @@ static int printk_address(unsigned long address)
write_unlock_irq(&tasklist_lock);
/* we were unable to find this address anywhere */
- return printk("[<0x%p>]", (void*)address);
+ return printk("[<0x%p>]", (void *)address);
}
-#define trace_buffer_save(x) \
- do { \
- (x) = bfin_read_TBUFCTL(); \
- bfin_write_TBUFCTL((x) & ~TBUFEN); \
- } while (0)
-#define trace_buffer_restore(x) \
- do { \
- bfin_write_TBUFCTL((x)); \
- } while (0)
-
asmlinkage void trap_c(struct pt_regs *fp)
{
int j, sig = 0;
@@ -203,15 +193,14 @@ asmlinkage void trap_c(struct pt_regs *fp)
#else
/* 0x02 - User Defined, Caught by default */
#endif
- /* 0x03 - Atomic test and set */
+ /* 0x03 - User Defined, userspace stack overflow */
case VEC_EXCPT03:
info.si_code = SEGV_STACKFLOW;
sig = SIGSEGV;
printk(KERN_EMERG EXC_0x03);
CHK_DEBUGGER_TRAP();
break;
- /* 0x04 - spinlock - handled by _ex_spinlock,
- getting here is an error */
+ /* 0x04 - User Defined, Caught by default */
/* 0x05 - User Defined, Caught by default */
/* 0x06 - User Defined, Caught by default */
/* 0x07 - User Defined, Caught by default */
@@ -547,29 +536,28 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
printk(KERN_EMERG "TEXT = 0x%p-0x%p DATA = 0x%p-0x%p\n"
KERN_EMERG "BSS = 0x%p-0x%p USER-STACK = 0x%p\n"
KERN_EMERG "\n",
- (void*)current->mm->start_code,
- (void*)current->mm->end_code,
- (void*)current->mm->start_data,
- (void*)current->mm->end_data,
- (void*)current->mm->end_data,
- (void*)current->mm->brk,
- (void*)current->mm->start_stack);
+ (void *)current->mm->start_code,
+ (void *)current->mm->end_code,
+ (void *)current->mm->start_data,
+ (void *)current->mm->end_data,
+ (void *)current->mm->end_data,
+ (void *)current->mm->brk,
+ (void *)current->mm->start_stack);
}
printk(KERN_EMERG "return address: [0x%p]; contents of:", retaddr);
- if (retaddr != 0 && retaddr <= (void*)physical_mem_end
+ if (retaddr != 0 && retaddr <= (void *)physical_mem_end
#if L1_CODE_LENGTH != 0
/* FIXME: Copy the code out of L1 Instruction SRAM through dma
memcpy. */
- && !(retaddr >= (void*)L1_CODE_START
- && retaddr < (void*)(L1_CODE_START + L1_CODE_LENGTH))
+ && !(retaddr >= (void *)L1_CODE_START
+ && retaddr < (void *)(L1_CODE_START + L1_CODE_LENGTH))
#endif
) {
int i = ((unsigned int)retaddr & 0xFFFFFFF0) - 32;
unsigned short x = 0;
- for (; i < ((unsigned int)retaddr & 0xFFFFFFF0 ) + 32 ;
- i += 2) {
- if ( !(i & 0xF) )
+ for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) {
+ if (!(i & 0xF))
printk(KERN_EMERG "\n" KERN_EMERG
"0x%08x: ", i);
@@ -588,7 +576,7 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr)
" The rest of this error"
" is meanless\n");
#endif
- if ( i == (unsigned int)retaddr )
+ if (i == (unsigned int)retaddr)
printk("[%04x]", x);
else
printk(" %04x ", x);
@@ -681,8 +669,8 @@ void panic_cplb_error(int cplb_panic, struct pt_regs *fp)
break;
}
- printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void*)bfin_read_DCPLB_FAULT_ADDR());
- printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void*)bfin_read_ICPLB_FAULT_ADDR());
+ printk(KERN_EMERG "DCPLB_FAULT_ADDR=%p\n", (void *)bfin_read_DCPLB_FAULT_ADDR());
+ printk(KERN_EMERG "ICPLB_FAULT_ADDR=%p\n", (void *)bfin_read_ICPLB_FAULT_ADDR());
dump_bfin_regs(fp, (void *)fp->retx);
dump_stack();
panic("Unrecoverable event\n");
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index 1ef1e36b3957..d06f860f4790 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -31,6 +31,7 @@
#include <asm-generic/vmlinux.lds.h>
#include <asm/mem_map.h>
+#include <asm/page.h>
OUTPUT_FORMAT("elf32-bfin")
ENTRY(__start)
@@ -63,8 +64,8 @@ SECTIONS
.data :
{
+ . = ALIGN(PAGE_SIZE);
__sdata = .;
- . = ALIGN(0x2000);
*(.data.init_task)
DATA_DATA
CONSTRUCTORS
@@ -72,14 +73,14 @@ SECTIONS
. = ALIGN(32);
*(.data.cacheline_aligned)
- . = ALIGN(0x2000);
+ . = ALIGN(PAGE_SIZE);
__edata = .;
}
+ . = ALIGN(PAGE_SIZE);
___init_begin = .;
.init :
{
- . = ALIGN(4096);
__sinittext = .;
*(.init.text)
__einittext = .;
@@ -152,9 +153,10 @@ SECTIONS
__ebss_b_l1 = .;
}
- ___init_end = LOADADDR(.data_b_l1) + SIZEOF(.data_b_l1);
+ . = LOADADDR(.data_b_l1) + SIZEOF(.data_b_l1);
+ ___init_end = ALIGN(PAGE_SIZE);
- .bss LOADADDR(.data_b_l1) + SIZEOF(.data_b_l1) :
+ .bss ___init_end :
{
. = ALIGN(4);
___bss_start = .;
diff --git a/arch/blackfin/lib/strcmp.c b/arch/blackfin/lib/strcmp.c
index 2ad47c4254ba..4eeefd86907f 100644
--- a/arch/blackfin/lib/strcmp.c
+++ b/arch/blackfin/lib/strcmp.c
@@ -6,6 +6,5 @@
int strcmp(const char *dest, const char *src)
{
- return __inline_strcmp(dest, src);
+ return __inline_strcmp(dest, src);
}
-
diff --git a/arch/blackfin/lib/strcpy.c b/arch/blackfin/lib/strcpy.c
index 4dc835a8a19b..534589db7256 100644
--- a/arch/blackfin/lib/strcpy.c
+++ b/arch/blackfin/lib/strcpy.c
@@ -6,6 +6,5 @@
char *strcpy(char *dest, const char *src)
{
- return __inline_strcpy(dest, src);
+ return __inline_strcpy(dest, src);
}
-
diff --git a/arch/blackfin/lib/strncmp.c b/arch/blackfin/lib/strncmp.c
index 947bcfe3f3bb..d791f120bff7 100644
--- a/arch/blackfin/lib/strncmp.c
+++ b/arch/blackfin/lib/strncmp.c
@@ -6,6 +6,5 @@
int strncmp(const char *cs, const char *ct, size_t count)
{
- return __inline_strncmp(cs, ct, count);
+ return __inline_strncmp(cs, ct, count);
}
-
diff --git a/arch/blackfin/lib/strncpy.c b/arch/blackfin/lib/strncpy.c
index 77a9b2e95097..1fecb5c71ffb 100644
--- a/arch/blackfin/lib/strncpy.c
+++ b/arch/blackfin/lib/strncpy.c
@@ -6,6 +6,5 @@
char *strncpy(char *dest, const char *src, size_t n)
{
- return __inline_strncpy(dest, src, n);
+ return __inline_strncpy(dest, src, n);
}
-
diff --git a/arch/blackfin/mach-bf533/Makefile b/arch/blackfin/mach-bf533/Makefile
index 76d2c2b8579a..8cce1736360d 100644
--- a/arch/blackfin/mach-bf533/Makefile
+++ b/arch/blackfin/mach-bf533/Makefile
@@ -4,6 +4,6 @@
extra-y := head.o
-obj-y := ints-priority.o
+obj-y := ints-priority.o dma.o
-obj-$(CONFIG_CPU_FREQ_BF533) += cpu.o
+obj-$(CONFIG_CPU_FREQ) += cpu.o
diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c
index edd31ce4f8d2..4545f363e641 100644
--- a/arch/blackfin/mach-bf533/boards/cm_bf533.c
+++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c
@@ -34,7 +34,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb_isp1362.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <asm/bfin5xx_spi.h>
/*
@@ -51,11 +51,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
@@ -98,7 +98,7 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
.platform_data = &bfin_spi_flash_data,
.controller_data = &spi_flash_chip_info,
.mode = SPI_MODE_3,
- },{
+ }, {
.modalias = "bfin_spi_adc", /* Name of spi_driver for this device */
.max_speed_hz = 6250000, /* max spi clock (SCK) speed in HZ */
.bus_num = 1, /* Framework bus number */
@@ -145,7 +145,7 @@ static struct resource smc91x_resources[] = {
.start = 0x20200300,
.end = 0x20200300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF0,
.end = IRQ_PF0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -194,11 +194,11 @@ static struct resource isp1362_hcd_resources[] = {
.start = 0x20308000,
.end = 0x20308000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20308004,
.end = 0x20308004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF4,
.end = IRQ_PF4,
.flags = IORESOURCE_IRQ,
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
index 0b522d95160d..0000b8f1239c 100644
--- a/arch/blackfin/mach-bf533/boards/ezkit.c
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -35,7 +35,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb_isp1362.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <asm/bfin5xx_spi.h>
/*
@@ -61,7 +61,7 @@ static struct resource smc91x_resources[] = {
.start = 0x20310300,
.end = 0x20310300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF9,
.end = IRQ_PF9,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -85,11 +85,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
diff --git a/arch/blackfin/mach-bf533/boards/generic_board.c b/arch/blackfin/mach-bf533/boards/generic_board.c
index c0f43ccfbfb5..9bc1f0d0ab50 100644
--- a/arch/blackfin/mach-bf533/boards/generic_board.c
+++ b/arch/blackfin/mach-bf533/boards/generic_board.c
@@ -30,7 +30,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
/*
* Name the Board for the /proc/cpuinfo
@@ -53,11 +53,11 @@ static struct resource smc91x_resources[] = {
.start = 0x20300300,
.end = 0x20300300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PROG_INTB,
.end = IRQ_PROG_INTB,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- },{
+ }, {
/*
* denotes the flag pin and is used directly if
* CONFIG_IRQCHIP_DEMUX_GPIO is defined.
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index 9a472fe15833..a9143c4cbdcd 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -37,7 +37,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb_isp1362.h>
#endif
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <asm/bfin5xx_spi.h>
/*
@@ -62,7 +62,7 @@ static struct resource smc91x_resources[] = {
.start = 0x20300300,
.end = 0x20300300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF7,
.end = IRQ_PF7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -83,7 +83,7 @@ static struct resource net2272_bfin_resources[] = {
.start = 0x20300000,
.end = 0x20300000 + 0x100,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF10,
.end = IRQ_PF10,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -108,11 +108,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
@@ -229,19 +229,19 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
#if defined(CONFIG_PBX)
{
- .modalias = "fxs-spi",
- .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1,
- .chip_select = 3,
- .controller_data= &spi_si3xxx_chip_info,
+ .modalias = "fxs-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 3,
+ .controller_data = &spi_si3xxx_chip_info,
.mode = SPI_MODE_3,
},
{
- .modalias = "fxo-spi",
- .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1,
- .chip_select = 2,
- .controller_data= &spi_si3xxx_chip_info,
+ .modalias = "fxo-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 2,
+ .controller_data = &spi_si3xxx_chip_info,
.mode = SPI_MODE_3,
},
#endif
diff --git a/arch/blackfin/mach-bf533/cpu.c b/arch/blackfin/mach-bf533/cpu.c
index 99547c4c290e..6fd9cfd0a31b 100644
--- a/arch/blackfin/mach-bf533/cpu.c
+++ b/arch/blackfin/mach-bf533/cpu.c
@@ -79,8 +79,7 @@ static int bf533_target(struct cpufreq_policy *policy,
int i;
struct cpufreq_freqs freqs;
- if (cpufreq_frequency_table_target
- (policy, bf533_freq_table, target_freq, relation, &index))
+ if (cpufreq_frequency_table_target(policy, bf533_freq_table, target_freq, relation, &index))
return -EINVAL;
cclk_mhz = bf533_freq_table[index].frequency;
vco_mhz = bf533_freq_table[index].index;
diff --git a/arch/blackfin/mach-bf533/dma.c b/arch/blackfin/mach-bf533/dma.c
new file mode 100644
index 000000000000..6c909cf4f7bf
--- /dev/null
+++ b/arch/blackfin/mach-bf533/dma.c
@@ -0,0 +1,95 @@
+/*
+ * File: arch/blackfin/mach-bf533/dma.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+
+struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+ (struct dma_register *) DMA0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA7_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
+};
+
+int channel2irq(unsigned int channel)
+{
+ int ret_irq = -1;
+
+ switch (channel) {
+ case CH_PPI:
+ ret_irq = IRQ_PPI;
+ break;
+
+ case CH_SPORT0_RX:
+ ret_irq = IRQ_SPORT0_RX;
+ break;
+
+ case CH_SPORT0_TX:
+ ret_irq = IRQ_SPORT0_TX;
+ break;
+
+ case CH_SPORT1_RX:
+ ret_irq = IRQ_SPORT1_RX;
+ break;
+
+ case CH_SPORT1_TX:
+ ret_irq = IRQ_SPORT1_TX;
+ break;
+
+ case CH_SPI:
+ ret_irq = IRQ_SPI;
+ break;
+
+ case CH_UART_RX:
+ ret_irq = IRQ_UART_RX;
+ break;
+
+ case CH_UART_TX:
+ ret_irq = IRQ_UART_TX;
+ break;
+
+ case CH_MEM_STREAM0_SRC:
+ case CH_MEM_STREAM0_DEST:
+ ret_irq = IRQ_MEM_DMA0;
+ break;
+
+ case CH_MEM_STREAM1_SRC:
+ case CH_MEM_STREAM1_DEST:
+ ret_irq = IRQ_MEM_DMA1;
+ break;
+ }
+ return ret_irq;
+}
diff --git a/arch/blackfin/mach-bf533/head.S b/arch/blackfin/mach-bf533/head.S
index 7e2aa8d0f44f..7dd0e9c3a936 100644
--- a/arch/blackfin/mach-bf533/head.S
+++ b/arch/blackfin/mach-bf533/head.S
@@ -30,6 +30,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/blackfin.h>
+#include <asm/trace.h>
#if CONFIG_BFIN_KERNEL_CLOCK
#include <asm/mach/mem_init.h>
#endif
@@ -96,6 +97,10 @@ ENTRY(__start)
M2 = r0;
M3 = r0;
+ trace_buffer_start(p0,r0);
+ P0 = R1;
+ R0 = R1;
+
#if CONFIG_DEBUG_KERNEL_START
/*
diff --git a/arch/blackfin/mach-bf533/ints-priority.c b/arch/blackfin/mach-bf533/ints-priority.c
index a3e1789167be..7d79e0f9503d 100644
--- a/arch/blackfin/mach-bf533/ints-priority.c
+++ b/arch/blackfin/mach-bf533/ints-priority.c
@@ -28,8 +28,8 @@
*/
#include <linux/module.h>
+#include <linux/irq.h>
#include <asm/blackfin.h>
-#include <asm/irq.h>
void program_IAR(void)
{
diff --git a/arch/blackfin/mach-bf537/Makefile b/arch/blackfin/mach-bf537/Makefile
index f32d44215bb7..7e7c9c8ac5b2 100644
--- a/arch/blackfin/mach-bf537/Makefile
+++ b/arch/blackfin/mach-bf537/Makefile
@@ -4,6 +4,6 @@
extra-y := head.o
-obj-y := ints-priority.o
+obj-y := ints-priority.o dma.o
obj-$(CONFIG_CPU_FREQ) += cpu.o
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537.c b/arch/blackfin/mach-bf537/boards/cm_bf537.c
index 6a60618a78ec..a8f947b72754 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537.c
@@ -35,7 +35,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb_isp1362.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <asm/bfin5xx_spi.h>
/*
@@ -53,11 +53,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
@@ -202,7 +202,7 @@ static struct resource smc91x_resources[] = {
.start = 0x20200300,
.end = 0x20200300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF14,
.end = IRQ_PF14,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -223,11 +223,11 @@ static struct resource isp1362_hcd_resources[] = {
.start = 0x20308000,
.end = 0x20308000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20308004,
.end = 0x20308004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PG15,
.end = IRQ_PG15,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -262,7 +262,7 @@ static struct resource net2272_bfin_resources[] = {
.start = 0x20200000,
.end = 0x20200000 + 0x100,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF7,
.end = IRQ_PF7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -283,7 +283,7 @@ static struct resource bfin_uart_resources[] = {
.start = 0xFFC00400,
.end = 0xFFC004FF,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0xFFC02000,
.end = 0xFFC020FF,
.flags = IORESOURCE_MEM,
diff --git a/arch/blackfin/mach-bf537/boards/eth_mac.c b/arch/blackfin/mach-bf537/boards/eth_mac.c
index e129a08d63de..a725cc8a9290 100644
--- a/arch/blackfin/mach-bf537/boards/eth_mac.c
+++ b/arch/blackfin/mach-bf537/boards/eth_mac.c
@@ -20,8 +20,7 @@
#include <linux/module.h>
#include <asm/blackfin.h>
-#if defined(CONFIG_GENERIC_BOARD) \
- || defined(CONFIG_BFIN537_STAMP)
+#if defined(CONFIG_GENERIC_BOARD) || defined(CONFIG_BFIN537_STAMP)
/*
* Currently the MAC address is saved in Flash by U-Boot
@@ -43,7 +42,7 @@ void get_bf537_ether_addr(char *addr)
*/
void get_bf537_ether_addr(char *addr)
{
- printk(KERN_WARNING "%s: No valid Ethernet MAC address found\n",__FILE__);
+ printk(KERN_WARNING "%s: No valid Ethernet MAC address found\n", __FILE__);
}
#endif
diff --git a/arch/blackfin/mach-bf537/boards/generic_board.c b/arch/blackfin/mach-bf537/boards/generic_board.c
index fd57e7439e0f..648d984e98d6 100644
--- a/arch/blackfin/mach-bf537/boards/generic_board.c
+++ b/arch/blackfin/mach-bf537/boards/generic_board.c
@@ -35,9 +35,9 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb_isp1362.h>
-#include <asm/irq.h>
-#include <asm/bfin5xx_spi.h>
+#include <linux/irq.h>
#include <linux/usb_sl811.h>
+#include <asm/bfin5xx_spi.h>
/*
* Name the Board for the /proc/cpuinfo
@@ -54,19 +54,19 @@ static struct resource bfin_pcmcia_cf_resources[] = {
.start = 0x20310000, /* IO PORT */
.end = 0x20312000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20311000, /* Attribute Memory */
.end = 0x20311FFF,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PROG_INTA,
.end = IRQ_PROG_INTA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },{
+ }, {
.start = IRQ_PF4,
.end = IRQ_PF4,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },{
+ }, {
.start = 6, /* Card Detect PF6 */
.end = 6,
.flags = IORESOURCE_IRQ,
@@ -95,11 +95,11 @@ static struct resource smc91x_resources[] = {
.start = 0x20300300,
.end = 0x20300300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PROG_INTB,
.end = IRQ_PROG_INTB,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- },{
+ }, {
/*
* denotes the flag pin and is used directly if
* CONFIG_IRQCHIP_DEMUX_GPIO is defined.
@@ -123,15 +123,15 @@ static struct resource sl811_hcd_resources[] = {
.start = 0x20340000,
.end = 0x20340000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20340004,
.end = 0x20340004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PROG_INTA,
.end = IRQ_PROG_INTA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- },{
+ }, {
.start = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
.end = IRQ_PF0 + CONFIG_USB_SL811_BFIN_GPIO,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -179,15 +179,15 @@ static struct resource isp1362_hcd_resources[] = {
.start = 0x20360000,
.end = 0x20360000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20360004,
.end = 0x20360004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PROG_INTA,
.end = IRQ_PROG_INTA,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- },{
+ }, {
.start = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
.end = IRQ_PF0 + CONFIG_USB_ISP1362_BFIN_GPIO,
.flags = IORESOURCE_IRQ,
@@ -228,7 +228,7 @@ static struct resource net2272_bfin_resources[] = {
.start = 0x20300000,
.end = 0x20300000 + 0x100,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF7,
.end = IRQ_PF7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -253,11 +253,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
@@ -375,7 +375,7 @@ static struct resource bfin_uart_resources[] = {
.start = 0xFFC00400,
.end = 0xFFC004FF,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0xFFC02000,
.end = 0xFFC020FF,
.flags = IORESOURCE_MEM,
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index 8aaf76dfce80..8806f1230f2d 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -37,7 +37,7 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb_isp1362.h>
#endif
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <asm/bfin5xx_spi.h>
#include <linux/usb_sl811.h>
@@ -58,15 +58,15 @@ static struct resource bfin_pcmcia_cf_resources[] = {
.start = 0x20310000, /* IO PORT */
.end = 0x20312000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20311000, /* Attribute Memory */
.end = 0x20311FFF,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF4,
.end = IRQ_PF4,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },{
+ }, {
.start = 6, /* Card Detect PF6 */
.end = 6,
.flags = IORESOURCE_IRQ,
@@ -95,7 +95,7 @@ static struct resource smc91x_resources[] = {
.start = 0x20300300,
.end = 0x20300300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF7,
.end = IRQ_PF7,
@@ -116,11 +116,11 @@ static struct resource sl811_hcd_resources[] = {
.start = 0x20340000,
.end = 0x20340000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20340004,
.end = 0x20340004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = CONFIG_USB_SL811_BFIN_IRQ,
.end = CONFIG_USB_SL811_BFIN_IRQ,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -167,11 +167,11 @@ static struct resource isp1362_hcd_resources[] = {
.start = 0x20360000,
.end = 0x20360000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20360004,
.end = 0x20360004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
.end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -212,7 +212,7 @@ static struct resource net2272_bfin_resources[] = {
.start = 0x20300000,
.end = 0x20300000 + 0x100,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF7,
.end = IRQ_PF7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -238,11 +238,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
@@ -294,16 +294,6 @@ static struct bfin5xx_spi_chip spi_mmc_chip_info = {
};
#endif
-#if defined(CONFIG_PBX)
-static struct bfin5xx_spi_chip spi_si3xxx_chip_info = {
- .ctl_reg = 0x4, /* send zero */
- .enable_dma = 0,
- .bits_per_word = 8,
- .cs_change_per_word = 1,
-};
-#endif
-
-
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
.cs_change_per_word = 1,
@@ -392,24 +382,6 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
.mode = SPI_MODE_3,
},
#endif
-#if defined(CONFIG_PBX)
- {
- .modalias = "fxs-spi",
- .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1,
- .chip_select = 3,
- .controller_data= &spi_si3xxx_chip_info,
- .mode = SPI_MODE_3,
- },
- {
- .modalias = "fxo-spi",
- .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1,
- .chip_select = 2,
- .controller_data= &spi_si3xxx_chip_info,
- .mode = SPI_MODE_3,
- },
-#endif
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
{
.modalias = "ad7877",
@@ -451,7 +423,7 @@ static struct resource bfin_uart_resources[] = {
.start = 0xFFC00400,
.end = 0xFFC004FF,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0xFFC02000,
.end = 0xFFC020FF,
.flags = IORESOURCE_MEM,
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 3a29b4d15f25..9c43d7756510 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -37,12 +37,10 @@
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb_isp1362.h>
#endif
-#include <asm/irq.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <asm/bfin5xx_spi.h>
#include <linux/usb_sl811.h>
-
+#include <asm/bfin5xx_spi.h>
#include <linux/spi/ad7877.h>
/*
@@ -85,7 +83,7 @@ static struct platform_device *bfin_isp1761_devices[] = {
int __init bfin_isp1761_init(void)
{
- unsigned int num_devices=ARRAY_SIZE(bfin_isp1761_devices);
+ unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices);
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
@@ -107,15 +105,15 @@ static struct resource bfin_pcmcia_cf_resources[] = {
.start = 0x20310000, /* IO PORT */
.end = 0x20312000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20311000, /* Attribute Memory */
.end = 0x20311FFF,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF4,
.end = IRQ_PF4,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },{
+ }, {
.start = 6, /* Card Detect PF6 */
.end = 6,
.flags = IORESOURCE_IRQ,
@@ -144,7 +142,7 @@ static struct resource smc91x_resources[] = {
.start = 0x20300300,
.end = 0x20300300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF7,
.end = IRQ_PF7,
@@ -159,17 +157,39 @@ static struct platform_device smc91x_device = {
};
#endif
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+static struct resource dm9000_resources[] = {
+ [0] = {
+ .start = 0x203FB800,
+ .end = 0x203FB800 + 8,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_PF9,
+ .end = IRQ_PF9,
+ .flags = (IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE),
+ },
+};
+
+static struct platform_device dm9000_device = {
+ .name = "dm9000",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(dm9000_resources),
+ .resource = dm9000_resources,
+};
+#endif
+
#if defined(CONFIG_USB_SL811_HCD) || defined(CONFIG_USB_SL811_HCD_MODULE)
static struct resource sl811_hcd_resources[] = {
{
.start = 0x20340000,
.end = 0x20340000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20340004,
.end = 0x20340004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = CONFIG_USB_SL811_BFIN_IRQ,
.end = CONFIG_USB_SL811_BFIN_IRQ,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -216,11 +236,11 @@ static struct resource isp1362_hcd_resources[] = {
.start = 0x20360000,
.end = 0x20360000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x20360004,
.end = 0x20360004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
.end = CONFIG_USB_ISP1362_BFIN_GPIO_IRQ,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -261,7 +281,7 @@ static struct resource net2272_bfin_resources[] = {
.start = 0x20300000,
.end = 0x20300000 + 0x100,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF7,
.end = IRQ_PF7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -287,11 +307,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
@@ -361,7 +381,6 @@ static struct bfin5xx_spi_chip ad5304_chip_info = {
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
-// .cs_change_per_word = 1,
.enable_dma = 0,
.bits_per_word = 16,
};
@@ -449,19 +468,19 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
#endif
#if defined(CONFIG_PBX)
{
- .modalias = "fxs-spi",
- .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1,
- .chip_select = 3,
- .controller_data= &spi_si3xxx_chip_info,
+ .modalias = "fxs-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 3,
+ .controller_data = &spi_si3xxx_chip_info,
.mode = SPI_MODE_3,
},
{
- .modalias = "fxo-spi",
- .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
- .bus_num = 1,
- .chip_select = 2,
- .controller_data= &spi_si3xxx_chip_info,
+ .modalias = "fxo-spi",
+ .max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
+ .bus_num = 1,
+ .chip_select = 2,
+ .controller_data = &spi_si3xxx_chip_info,
.mode = SPI_MODE_3,
},
#endif
@@ -516,7 +535,7 @@ static struct resource bfin_uart_resources[] = {
.start = 0xFFC00400,
.end = 0xFFC004FF,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0xFFC02000,
.end = 0xFFC020FF,
.flags = IORESOURCE_MEM,
@@ -571,6 +590,10 @@ static struct platform_device *stamp_devices[] __initdata = {
&smc91x_device,
#endif
+#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
+ &dm9000_device,
+#endif
+
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
&bfin_mac_device,
#endif
diff --git a/arch/blackfin/mach-bf537/dma.c b/arch/blackfin/mach-bf537/dma.c
new file mode 100644
index 000000000000..706cb97b0265
--- /dev/null
+++ b/arch/blackfin/mach-bf537/dma.c
@@ -0,0 +1,115 @@
+/*
+ * File: arch/blackfin/mach-bf537/dma.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+
+struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+ (struct dma_register *) DMA0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA7_NEXT_DESC_PTR,
+ (struct dma_register *) DMA8_NEXT_DESC_PTR,
+ (struct dma_register *) DMA9_NEXT_DESC_PTR,
+ (struct dma_register *) DMA10_NEXT_DESC_PTR,
+ (struct dma_register *) DMA11_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
+};
+
+int channel2irq(unsigned int channel)
+{
+ int ret_irq = -1;
+
+ switch (channel) {
+ case CH_PPI:
+ ret_irq = IRQ_PPI;
+ break;
+
+ case CH_EMAC_RX:
+ ret_irq = IRQ_MAC_RX;
+ break;
+
+ case CH_EMAC_TX:
+ ret_irq = IRQ_MAC_TX;
+ break;
+
+ case CH_UART1_RX:
+ ret_irq = IRQ_UART1_RX;
+ break;
+
+ case CH_UART1_TX:
+ ret_irq = IRQ_UART1_TX;
+ break;
+
+ case CH_SPORT0_RX:
+ ret_irq = IRQ_SPORT0_RX;
+ break;
+
+ case CH_SPORT0_TX:
+ ret_irq = IRQ_SPORT0_TX;
+ break;
+
+ case CH_SPORT1_RX:
+ ret_irq = IRQ_SPORT1_RX;
+ break;
+
+ case CH_SPORT1_TX:
+ ret_irq = IRQ_SPORT1_TX;
+ break;
+
+ case CH_SPI:
+ ret_irq = IRQ_SPI;
+ break;
+
+ case CH_UART_RX:
+ ret_irq = IRQ_UART_RX;
+ break;
+
+ case CH_UART_TX:
+ ret_irq = IRQ_UART_TX;
+ break;
+
+ case CH_MEM_STREAM0_SRC:
+ case CH_MEM_STREAM0_DEST:
+ ret_irq = IRQ_MEM_DMA0;
+ break;
+
+ case CH_MEM_STREAM1_SRC:
+ case CH_MEM_STREAM1_DEST:
+ ret_irq = IRQ_MEM_DMA1;
+ break;
+ }
+ return ret_irq;
+}
diff --git a/arch/blackfin/mach-bf537/head.S b/arch/blackfin/mach-bf537/head.S
index 7d902bbd860f..429c8a1019da 100644
--- a/arch/blackfin/mach-bf537/head.S
+++ b/arch/blackfin/mach-bf537/head.S
@@ -30,6 +30,8 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/blackfin.h>
+#include <asm/trace.h>
+
#if CONFIG_BFIN_KERNEL_CLOCK
#include <asm/mach/mem_init.h>
#endif
@@ -93,6 +95,10 @@ ENTRY(__start)
M2 = r0;
M3 = r0;
+ trace_buffer_start(p0,r0);
+ P0 = R1;
+ R0 = R1;
+
/* Turn off the icache */
p0.l = (IMEM_CONTROL & 0xFFFF);
p0.h = (IMEM_CONTROL >> 16);
diff --git a/arch/blackfin/mach-bf537/ints-priority.c b/arch/blackfin/mach-bf537/ints-priority.c
index 2dbf3df465d1..a8b915f202ec 100644
--- a/arch/blackfin/mach-bf537/ints-priority.c
+++ b/arch/blackfin/mach-bf537/ints-priority.c
@@ -28,8 +28,8 @@
*/
#include <linux/module.h>
+#include <linux/irq.h>
#include <asm/blackfin.h>
-#include <asm/irq.h>
void program_IAR(void)
{
diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig
new file mode 100644
index 000000000000..e78b03d56c7c
--- /dev/null
+++ b/arch/blackfin/mach-bf548/Kconfig
@@ -0,0 +1,316 @@
+if (BF54x)
+
+menu "BF548 Specific Configuration"
+
+comment "Interrupt Priority Assignment"
+menu "Priority"
+
+config IRQ_PLL_WAKEUP
+ int "IRQ_PLL_WAKEUP"
+ default 7
+config IRQ_DMAC0_ERR
+ int "IRQ_DMAC0_ERR"
+ default 7
+config IRQ_EPPI0_ERR
+ int "IRQ_EPPI0_ERR"
+ default 7
+config IRQ_SPORT0_ERR
+ int "IRQ_SPORT0_ERR"
+ default 7
+config IRQ_SPORT1_ERR
+ int "IRQ_SPORT1_ERR"
+ default 7
+config IRQ_SPI0_ERR
+ int "IRQ_SPI0_ERR"
+ default 7
+config IRQ_UART0_ERR
+ int "IRQ_UART0_ERR"
+ default 7
+config IRQ_RTC
+ int "IRQ_RTC"
+ default 8
+config IRQ_EPPI0
+ int "IRQ_EPPI0"
+ default 8
+config IRQ_SPORT0_RX
+ int "IRQ_SPORT0_RX"
+ default 9
+config IRQ_SPORT0_TX
+ int "IRQ_SPORT0_TX"
+ default 9
+config IRQ_SPORT1_RX
+ int "IRQ_SPORT1_RX"
+ default 9
+config IRQ_SPORT1_TX
+ int "IRQ_SPORT1_TX"
+ default 9
+config IRQ_SPI0
+ int "IRQ_SPI0"
+ default 10
+config IRQ_UART0_RX
+ int "IRQ_UART0_RX"
+ default 10
+config IRQ_UART0_TX
+ int "IRQ_UART0_TX"
+ default 10
+config IRQ_TIMER8
+ int "IRQ_TIMER8"
+ default 11
+config IRQ_TIMER9
+ int "IRQ_TIMER9"
+ default 11
+config IRQ_TIMER10
+ int "IRQ_TIMER10"
+ default 11
+config IRQ_PINT0
+ int "IRQ_PINT0"
+ default 12
+config IRQ_PINT1
+ int "IRQ_PINT0"
+ default 12
+config IRQ_MDMAS0
+ int "IRQ_MDMAS0"
+ default 13
+config IRQ_MDMAS1
+ int "IRQ_DMDMAS1"
+ default 13
+config IRQ_WATCHDOG
+ int "IRQ_WATCHDOG"
+ default 13
+config IRQ_DMAC1_ERR
+ int "IRQ_DMAC1_ERR"
+ default 7
+config IRQ_SPORT2_ERR
+ int "IRQ_SPORT2_ERR"
+ default 7
+config IRQ_SPORT3_ERR
+ int "IRQ_SPORT3_ERR"
+ default 7
+config IRQ_MXVR_DATA
+ int "IRQ MXVR Data"
+ default 7
+config IRQ_SPI1_ERR
+ int "IRQ_SPI1_ERR"
+ default 7
+config IRQ_SPI2_ERR
+ int "IRQ_SPI2_ERR"
+ default 7
+config IRQ_UART1_ERR
+ int "IRQ_UART1_ERR"
+ default 7
+config IRQ_UART2_ERR
+ int "IRQ_UART2_ERR"
+ default 7
+config IRQ_CAN0_ERR
+ int "IRQ_CAN0_ERR"
+ default 7
+config IRQ_SPORT2_RX
+ int "IRQ_SPORT2_RX"
+ default 9
+config IRQ_SPORT2_TX
+ int "IRQ_SPORT2_TX"
+ default 9
+config IRQ_SPORT3_RX
+ int "IRQ_SPORT3_RX"
+ default 9
+config IRQ_SPORT3_TX
+ int "IRQ_SPORT3_TX"
+ default 9
+config IRQ_EPPI1
+ int "IRQ_EPPI1"
+ default 9
+config IRQ_EPPI2
+ int "IRQ_EPPI2"
+ default 9
+config IRQ_SPI1
+ int "IRQ_SPI1"
+ default 10
+config IRQ_SPI2
+ int "IRQ_SPI2"
+ default 10
+config IRQ_UART1_RX
+ int "IRQ_UART1_RX"
+ default 10
+config IRQ_UART1_TX
+ int "IRQ_UART1_TX"
+ default 10
+config IRQ_ATAPI_RX
+ int "IRQ_ATAPI_RX"
+ default 10
+config IRQ_ATAPI_TX
+ int "IRQ_ATAPI_TX"
+ default 10
+config IRQ_TWI0
+ int "IRQ_TWI0"
+ default 11
+config IRQ_TWI1
+ int "IRQ_TWI1"
+ default 11
+config IRQ_CAN0_RX
+ int "IRQ_CAN_RX"
+ default 11
+config IRQ_CAN0_TX
+ int "IRQ_CAN_TX"
+ default 11
+config IRQ_MDMAS2
+ int "IRQ_MDMAS2"
+ default 13
+config IRQ_MDMAS3
+ int "IRQ_DMMAS3"
+ default 13
+config IRQ_MXVR_ERR
+ int "IRQ_MXVR_ERR"
+ default 11
+config IRQ_MXVR_MSG
+ int "IRQ_MXVR_MSG"
+ default 11
+config IRQ_MXVR_PKT
+ int "IRQ_MXVR_PKT"
+ default 11
+config IRQ_EPPI1_ERR
+ int "IRQ_EPPI1_ERR"
+ default 7
+config IRQ_EPPI2_ERR
+ int "IRQ_EPPI2_ERR"
+ default 7
+config IRQ_UART3_ERR
+ int "IRQ_UART3_ERR"
+ default 7
+config IRQ_HOST_ERR
+ int "IRQ_HOST_ERR"
+ default 7
+config IRQ_PIXC_ERR
+ int "IRQ_PIXC_ERR"
+ default 7
+config IRQ_NFC_ERR
+ int "IRQ_NFC_ERR"
+ default 7
+config IRQ_ATAPI_ERR
+ int "IRQ_ATAPI_ERR"
+ default 7
+config IRQ_CAN1_ERR
+ int "IRQ_CAN1_ERR"
+ default 7
+config IRQ_HS_DMA_ERR
+ int "IRQ Handshake DMA Status"
+ default 7
+config IRQ_PIXC_IN0
+ int "IRQ PIXC IN0"
+ default 8
+config IRQ_PIXC_IN1
+ int "IRQ PIXC IN1"
+ default 8
+config IRQ_PIXC_OUT
+ int "IRQ PIXC OUT"
+ default 8
+config IRQ_SDH
+ int "IRQ SDH"
+ default 8
+config IRQ_CNT
+ int "IRQ CNT"
+ default 8
+config IRQ_KEY
+ int "IRQ KEY"
+ default 8
+config IRQ_CAN1_RX
+ int "IRQ CAN1 RX"
+ default 11
+config IRQ_CAN1_TX
+ int "IRQ_CAN1_TX"
+ default 11
+config IRQ_SDH_MASK0
+ int "IRQ_SDH_MASK0"
+ default 11
+config IRQ_SDH_MASK1
+ int "IRQ_SDH_MASK1"
+ default 11
+config IRQ_USB_INT0
+ int "IRQ USB INT0"
+ default 11
+config IRQ_USB_INT1
+ int "IRQ USB INT1"
+ default 11
+config IRQ_USB_INT2
+ int "IRQ USB INT2"
+ default 11
+config IRQ_USB_DMA
+ int "IRQ USB DMA"
+ default 11
+config IRQ_OTPSEC
+ int "IRQ OPTSEC"
+ default 11
+config IRQ_TIMER0
+ int "IRQ_TIMER0"
+ default 11
+config IRQ_TIMER1
+ int "IRQ_TIMER1"
+ default 11
+config IRQ_TIMER2
+ int "IRQ_TIMER2"
+ default 11
+config IRQ_TIMER3
+ int "IRQ_TIMER3"
+ default 11
+config IRQ_TIMER4
+ int "IRQ_TIMER4"
+ default 11
+config IRQ_TIMER5
+ int "IRQ_TIMER5"
+ default 11
+config IRQ_TIMER6
+ int "IRQ_TIMER6"
+ default 11
+config IRQ_TIMER7
+ int "IRQ_TIMER7"
+ default 11
+config IRQ_PINT2
+ int "IRQ_PIN2"
+ default 11
+config IRQ_PINT3
+ int "IRQ_PIN3"
+ default 11
+
+ help
+ Enter the priority numbers between 7-13 ONLY. Others are Reserved.
+ This applies to all the above. It is not recommended to assign the
+ highest priority number 7 to UART or any other device.
+
+endmenu
+
+comment "Pin Interrupt to Port Assignment"
+menu "Assignment"
+
+config PINTx_REASSIGN
+ bool "Reprogram PINT Assignment"
+ default n
+ help
+ The interrupt assignment registers controls the pin-to-interrupt
+ assignment in a byte-wide manner. Each option allows you to select
+ a set of pins (High/Low Byte) of an specific Port being mapped
+ to one of the four PIN Interrupts IRQ_PINTx.
+
+ You shouldn't change any of these unless you know exactly what you're doing.
+ Please consult the Blackfin BF54x Processor Hardware Reference Manual.
+
+config PINT0_ASSIGN
+ hex "PINT0_ASSIGN"
+ depends on PINTx_REASSIGN
+ default 0x00000101
+config PINT1_ASSIGN
+ hex "PINT1_ASSIGN"
+ depends on PINTx_REASSIGN
+ default 0x01010000
+config PINT2_ASSIGN
+ hex "PINT2_ASSIGN"
+ depends on PINTx_REASSIGN
+ default 0x00000101
+config PINT3_ASSIGN
+ hex "PINT3_ASSIGN"
+ depends on PINTx_REASSIGN
+ default 0x02020303
+
+endmenu
+
+endmenu
+
+endif
diff --git a/arch/blackfin/mach-bf548/Makefile b/arch/blackfin/mach-bf548/Makefile
new file mode 100644
index 000000000000..060ad78ebf1d
--- /dev/null
+++ b/arch/blackfin/mach-bf548/Makefile
@@ -0,0 +1,9 @@
+#
+# arch/blackfin/mach-bf537/Makefile
+#
+
+extra-y := head.o
+
+obj-y := ints-priority.o dma.o gpio.o
+
+obj-$(CONFIG_CPU_FREQ) += cpu.o
diff --git a/arch/blackfin/mach-bf548/boards/Makefile b/arch/blackfin/mach-bf548/boards/Makefile
new file mode 100644
index 000000000000..486e07c99a51
--- /dev/null
+++ b/arch/blackfin/mach-bf548/boards/Makefile
@@ -0,0 +1,5 @@
+#
+# arch/blackfin/mach-bf548/boards/Makefile
+#
+
+obj-$(CONFIG_BFIN548_EZKIT) += ezkit.o led.o
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
new file mode 100644
index 000000000000..96ad95fab1a8
--- /dev/null
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -0,0 +1,114 @@
+/*
+ * File: arch/blackfin/mach-bf548/boards/ezkit.c
+ * Based on: arch/blackfin/mach-bf537/boards/ezkit.c
+ * Author: Aidan Williams <aidan@nicta.com.au>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2005 National ICT Australia (NICTA)
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/flash.h>
+#include <linux/irq.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/bfin5xx_spi.h>
+
+/*
+ * Name the Board for the /proc/cpuinfo
+ */
+char *bfin_board_name = "ADSP-BF548-EZKIT";
+
+/*
+ * Driver needs to know address, irq and flag pin.
+ */
+
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+static struct platform_device rtc_device = {
+ .name = "rtc-bfin",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+static struct resource bfin_uart_resources[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+ {
+ .start = 0xFFC02000,
+ .end = 0xFFC020FF,
+ .flags = IORESOURCE_MEM,
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+ {
+ .start = 0xFFC02100,
+ .end = 0xFFC021FF,
+ .flags = IORESOURCE_MEM,
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART3
+ {
+ .start = 0xFFC03100,
+ .end = 0xFFC031FF,
+ },
+#endif
+};
+
+static struct platform_device bfin_uart_device = {
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
+};
+#endif
+
+static struct platform_device *ezkit_devices[] __initdata = {
+#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
+ &rtc_device,
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
+ &bfin_uart_device,
+#endif
+};
+
+static int __init stamp_init(void)
+{
+ printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
+ platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
+ return 0;
+}
+
+arch_initcall(stamp_init);
diff --git a/arch/blackfin/mach-bf548/boards/led.S b/arch/blackfin/mach-bf548/boards/led.S
new file mode 100644
index 000000000000..f47daf3770d0
--- /dev/null
+++ b/arch/blackfin/mach-bf548/boards/led.S
@@ -0,0 +1,172 @@
+/****************************************************
+ * LED1 ---- PG6 LED2 ---- PG7 *
+ * LED3 ---- PG8 LED4 ---- PG9 *
+ * LED5 ---- PG10 LED6 ---- PG11 *
+ ****************************************************/
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+
+/* All functions in this file save the registers they uses.
+ So there is no need to save any registers before calling them. */
+
+ .text;
+
+/* Initialize LEDs. */
+
+ENTRY(_led_init)
+ LINK 0;
+ [--SP] = P0;
+ [--SP] = R0;
+ [--SP] = R1;
+ [--SP] = R2;
+ R1 = (PG6|PG7|PG8|PG9|PG10|PG11)(Z);
+ R2 = ~R1;
+
+ P0.H = hi(PORTG_FER);
+ P0.L = lo(PORTG_FER);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 & R2;
+ W[P0] = R0.L;
+ SSYNC;
+
+ P0.H = hi(PORTG_DIR_SET);
+ P0.L = lo(PORTG_DIR_SET);
+ W[P0] = R1.L;
+ SSYNC;
+
+ P0.H = hi(PORTG_INEN);
+ P0.L = lo(PORTG_INEN);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 & R2;
+ W[P0] = R0.L;
+ SSYNC;
+
+ R2 = [SP++];
+ R1 = [SP++];
+ R0 = [SP++];
+ P0 = [SP++];
+ RTS;
+ .size _led_init, .-_led_init
+
+/* Set one LED on. Leave other LEDs unchanged.
+ It expects the LED number passed through R0. */
+
+ENTRY(_led_on)
+ LINK 0;
+ [--SP] = P0;
+ [--SP] = R1;
+ CALL _led_init;
+ R1 = 1;
+ R0 += 5;
+ R1 <<= R0;
+ P0.H = hi(PORTG_SET);
+ P0.L = lo(PORTG_SET);
+ W[P0] = R1.L;
+ SSYNC;
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_on, .-_led_on
+
+/* Set one LED off. Leave other LEDs unchanged. */
+
+ENTRY(_led_off)
+ LINK 0;
+ [--SP] = P0;
+ [--SP] = R1;
+ CALL _led_init;
+ R1 = 1;
+ R0 += 5;
+ R1 <<= R0;
+ P0.H = hi(PORTG_CLEAR);
+ P0.L = lo(PORTG_CLEAR);
+ W[P0] = R1.L;
+ SSYNC;
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_off, .-_led_off
+
+/* Toggle one LED. Leave other LEDs unchanged. */
+
+ENTRY(_led_toggle)
+ LINK 0;
+ [--SP] = P0;
+ [--SP] = R1;
+ CALL _led_init;
+ R1 = 1;
+ R0 += 5;
+ R1 <<= R0;
+ P0.H = hi(PORTG);
+ P0.L = lo(PORTG);
+ R0 = W[P0](Z);
+ SSYNC;
+ R0 = R0 ^ R1;
+ W[P0] = R0.L;
+ SSYNC;
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_toggle, .-_led_toggle
+
+/* Display the number using LEDs in binary format. */
+
+ENTRY(_led_disp_num)
+ LINK 0;
+ [--SP] = P0;
+ [--SP] = R1;
+ [--SP] = R2;
+ CALL _led_init;
+ R1 = 0x3f(X);
+ R0 = R0 & R1;
+ R2 = 6(X);
+ R0 <<= R2;
+ R1 <<= R2;
+ P0.H = hi(PORTG);
+ P0.L = lo(PORTG);
+ R2 = W[P0](Z);
+ SSYNC;
+ R1 = ~R1;
+ R2 = R2 & R1;
+ R2 = R2 | R0;
+ W[P0] = R2.L;
+ SSYNC;
+ R2 = [SP++];
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_disp_num, .-_led_disp_num
+
+/* Toggle the number using LEDs in binary format. */
+
+ENTRY(_led_toggle_num)
+ LINK 0;
+ [--SP] = P0;
+ [--SP] = R1;
+ [--SP] = R2;
+ CALL _led_init;
+ R1 = 0x3f(X);
+ R0 = R0 & R1;
+ R1 = 6(X);
+ R0 <<= R1;
+ P0.H = hi(PORTG);
+ P0.L = lo(PORTG);
+ R1 = W[P0](Z);
+ SSYNC;
+ R1 = R1 ^ R0;
+ W[P0] = R1.L;
+ SSYNC;
+ R2 = [SP++];
+ R1 = [SP++];
+ P0 = [SP++];
+ UNLINK;
+ RTS;
+ .size _led_toggle_num, .-_led_toggle_num
+
diff --git a/arch/blackfin/mach-bf548/cpu.c b/arch/blackfin/mach-bf548/cpu.c
new file mode 100644
index 000000000000..4298a3ccfbfc
--- /dev/null
+++ b/arch/blackfin/mach-bf548/cpu.c
@@ -0,0 +1,159 @@
+/*
+ * File: arch/blackfin/mach-bf548/cpu.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: clock scaling for the bf54x
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <asm/dpmc.h>
+#include <linux/fs.h>
+#include <asm/bfin-global.h>
+
+/* CONFIG_CLKIN_HZ=25000000 */
+#define VCO5 (CONFIG_CLKIN_HZ*45)
+#define VCO4 (CONFIG_CLKIN_HZ*36)
+#define VCO3 (CONFIG_CLKIN_HZ*27)
+#define VCO2 (CONFIG_CLKIN_HZ*18)
+#define VCO1 (CONFIG_CLKIN_HZ*9)
+#define VCO(x) VCO##x
+
+#define MFREQ(x) {VCO(x),VCO(x)/4},{VCO(x),VCO(x)/2},{VCO(x),VCO(x)}
+/* frequency */
+static struct cpufreq_frequency_table bf548_freq_table[] = {
+ MFREQ(1),
+ MFREQ(3),
+ {VCO4, VCO4 / 2}, {VCO4, VCO4},
+ MFREQ(5),
+ {0, CPUFREQ_TABLE_END},
+};
+
+/*
+ * dpmc_fops->ioctl()
+ * static int dpmc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+ */
+static int bf548_getfreq(unsigned int cpu)
+{
+ unsigned long cclk_mhz;
+
+ /* The driver only support single cpu */
+ if (cpu == 0)
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_GET_CORECLOCK, &cclk_mhz);
+ else
+ cclk_mhz = -1;
+
+ return cclk_mhz;
+}
+
+static int bf548_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ unsigned long cclk_mhz;
+ unsigned long vco_mhz;
+ unsigned long flags;
+ unsigned int index;
+ struct cpufreq_freqs freqs;
+
+ if (cpufreq_frequency_table_target(policy, bf548_freq_table, target_freq, relation, &index))
+ return -EINVAL;
+
+ cclk_mhz = bf548_freq_table[index].frequency;
+ vco_mhz = bf548_freq_table[index].index;
+
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_CHANGE_FREQUENCY, &vco_mhz);
+ freqs.old = bf548_getfreq(0);
+ freqs.new = cclk_mhz;
+ freqs.cpu = 0;
+
+ pr_debug("cclk begin change to cclk %d,vco=%d,index=%d,target=%d,oldfreq=%d\n",
+ cclk_mhz, vco_mhz, index, target_freq, freqs.old);
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ local_irq_save(flags);
+ dpmc_fops.ioctl(NULL, NULL, IOCTL_SET_CCLK, &cclk_mhz);
+ local_irq_restore(flags);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ vco_mhz = get_vco();
+ cclk_mhz = get_cclk();
+ return 0;
+}
+
+/* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on
+ * this platform, anyway.
+ */
+static int bf548_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, &bf548_freq_table);
+}
+
+static int __init __bf548_cpu_init(struct cpufreq_policy *policy)
+{
+ if (policy->cpu != 0)
+ return -EINVAL;
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ /*Now ,only support one cpu */
+ policy->cur = bf548_getfreq(0);
+ cpufreq_frequency_table_get_attr(bf548_freq_table, policy->cpu);
+ return cpufreq_frequency_table_cpuinfo(policy, bf548_freq_table);
+}
+
+static struct freq_attr *bf548_freq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver bf548_driver = {
+ .verify = bf548_verify_speed,
+ .target = bf548_target,
+ .get = bf548_getfreq,
+ .init = __bf548_cpu_init,
+ .name = "bf548",
+ .owner = THIS_MODULE,
+ .attr = bf548_freq_attr,
+};
+
+static int __init bf548_cpu_init(void)
+{
+ return cpufreq_register_driver(&bf548_driver);
+}
+
+static void __exit bf548_cpu_exit(void)
+{
+ cpufreq_unregister_driver(&bf548_driver);
+}
+
+MODULE_AUTHOR("Mickael Kang");
+MODULE_DESCRIPTION("cpufreq driver for BF548 CPU");
+MODULE_LICENSE("GPL");
+
+module_init(bf548_cpu_init);
+module_exit(bf548_cpu_exit);
diff --git a/arch/blackfin/mach-bf548/dma.c b/arch/blackfin/mach-bf548/dma.c
new file mode 100644
index 000000000000..a8184113be48
--- /dev/null
+++ b/arch/blackfin/mach-bf548/dma.c
@@ -0,0 +1,156 @@
+/*
+ * File: arch/blackfin/mach-bf561/dma.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+
+ struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+ (struct dma_register *) DMA0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA7_NEXT_DESC_PTR,
+ (struct dma_register *) DMA8_NEXT_DESC_PTR,
+ (struct dma_register *) DMA9_NEXT_DESC_PTR,
+ (struct dma_register *) DMA10_NEXT_DESC_PTR,
+ (struct dma_register *) DMA11_NEXT_DESC_PTR,
+ (struct dma_register *) DMA12_NEXT_DESC_PTR,
+ (struct dma_register *) DMA13_NEXT_DESC_PTR,
+ (struct dma_register *) DMA14_NEXT_DESC_PTR,
+ (struct dma_register *) DMA15_NEXT_DESC_PTR,
+ (struct dma_register *) DMA16_NEXT_DESC_PTR,
+ (struct dma_register *) DMA17_NEXT_DESC_PTR,
+ (struct dma_register *) DMA18_NEXT_DESC_PTR,
+ (struct dma_register *) DMA19_NEXT_DESC_PTR,
+ (struct dma_register *) DMA20_NEXT_DESC_PTR,
+ (struct dma_register *) DMA21_NEXT_DESC_PTR,
+ (struct dma_register *) DMA22_NEXT_DESC_PTR,
+ (struct dma_register *) DMA23_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D2_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S2_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_D3_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA_S3_NEXT_DESC_PTR,
+};
+
+int channel2irq(unsigned int channel)
+{
+ int ret_irq = -1;
+
+ switch (channel) {
+ case CH_SPORT0_RX:
+ ret_irq = IRQ_SPORT0_RX;
+ break;
+ case CH_SPORT0_TX:
+ ret_irq = IRQ_SPORT0_TX;
+ break;
+ case CH_SPORT1_RX:
+ ret_irq = IRQ_SPORT1_RX;
+ break;
+ case CH_SPORT1_TX:
+ ret_irq = IRQ_SPORT1_TX;
+ case CH_SPI0:
+ ret_irq = IRQ_SPI0;
+ break;
+ case CH_SPI1:
+ ret_irq = IRQ_SPI1;
+ break;
+ case CH_UART0_RX:
+ ret_irq = IRQ_UART_RX;
+ break;
+ case CH_UART0_TX:
+ ret_irq = IRQ_UART_TX;
+ break;
+ case CH_UART1_RX:
+ ret_irq = IRQ_UART_RX;
+ break;
+ case CH_UART1_TX:
+ ret_irq = IRQ_UART_TX;
+ break;
+ case CH_EPPI0:
+ ret_irq = IRQ_EPPI0;
+ break;
+ case CH_EPPI1:
+ ret_irq = IRQ_EPPI1;
+ break;
+ case CH_EPPI2:
+ ret_irq = IRQ_EPPI2;
+ break;
+ case CH_PIXC_IMAGE:
+ ret_irq = IRQ_PIXC_IN0;
+ break;
+ case CH_PIXC_OVERLAY:
+ ret_irq = IRQ_PIXC_IN1;
+ break;
+ case CH_PIXC_OUTPUT:
+ ret_irq = IRQ_PIXC_OUT;
+ break;
+ case CH_SPORT2_RX:
+ ret_irq = IRQ_SPORT2_RX;
+ break;
+ case CH_SPORT2_TX:
+ ret_irq = IRQ_SPORT2_TX;
+ break;
+ case CH_SPORT3_RX:
+ ret_irq = IRQ_SPORT3_RX;
+ break;
+ case CH_SPORT3_TX:
+ ret_irq = IRQ_SPORT3_TX;
+ break;
+ case CH_SDH:
+ ret_irq = IRQ_SDH;
+ break;
+ case CH_SPI2:
+ ret_irq = IRQ_SPI2;
+ break;
+ case CH_MEM_STREAM0_SRC:
+ case CH_MEM_STREAM0_DEST:
+ ret_irq = IRQ_MDMAS0;
+ break;
+ case CH_MEM_STREAM1_SRC:
+ case CH_MEM_STREAM1_DEST:
+ ret_irq = IRQ_MDMAS1;
+ break;
+ case CH_MEM_STREAM2_SRC:
+ case CH_MEM_STREAM2_DEST:
+ ret_irq = IRQ_MDMAS2;
+ break;
+ case CH_MEM_STREAM3_SRC:
+ case CH_MEM_STREAM3_DEST:
+ ret_irq = IRQ_MDMAS3;
+ break;
+ }
+ return ret_irq;
+}
diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c
new file mode 100644
index 000000000000..0da5f0003b8c
--- /dev/null
+++ b/arch/blackfin/mach-bf548/gpio.c
@@ -0,0 +1,323 @@
+/*
+ * File: arch/blackfin/mach-bf548/gpio.c
+ * Based on:
+ * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
+ *
+ * Created:
+ * Description: GPIO Abstraction Layer
+ *
+ * Modified:
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+#include <linux/irq.h>
+
+static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = {
+ (struct gpio_port_t *)PORTA_FER,
+ (struct gpio_port_t *)PORTB_FER,
+ (struct gpio_port_t *)PORTC_FER,
+ (struct gpio_port_t *)PORTD_FER,
+ (struct gpio_port_t *)PORTE_FER,
+ (struct gpio_port_t *)PORTF_FER,
+ (struct gpio_port_t *)PORTG_FER,
+ (struct gpio_port_t *)PORTH_FER,
+ (struct gpio_port_t *)PORTI_FER,
+ (struct gpio_port_t *)PORTJ_FER,
+};
+
+static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+inline int check_gpio(unsigned short gpio)
+{
+ if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15
+ || gpio == GPIO_PH14 || gpio == GPIO_PH15
+ || gpio == GPIO_PJ14 || gpio == GPIO_PJ15
+ || gpio > MAX_BLACKFIN_GPIOS)
+ return -EINVAL;
+ return 0;
+}
+
+inline void portmux_setup(unsigned short portno, unsigned short function)
+{
+ u32 pmux;
+
+ pmux = gpio_array[gpio_bank(portno)]->port_mux;
+
+ pmux &= ~(0x3 << (2 * gpio_sub_n(portno)));
+ pmux |= (function & 0x3) << (2 * gpio_sub_n(portno));
+
+ gpio_array[gpio_bank(portno)]->port_mux = pmux;
+
+}
+
+inline u16 get_portmux(unsigned short portno)
+{
+ u32 pmux;
+
+ pmux = gpio_array[gpio_bank(portno)]->port_mux;
+
+ return (pmux >> (2 * gpio_sub_n(portno)) & 0x3);
+
+}
+
+static void port_setup(unsigned short gpio, unsigned short usage)
+{
+ if (usage == GPIO_USAGE) {
+ if (gpio_array[gpio_bank(gpio)]->port_fer & gpio_bit(gpio))
+ printk(KERN_WARNING
+ "bfin-gpio: Possible Conflict with Peripheral "
+ "usage and GPIO %d detected!\n", gpio);
+ gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio);
+ } else
+ gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio);
+ SSYNC();
+}
+
+static int __init bfin_gpio_init(void)
+{
+ printk(KERN_INFO "Blackfin GPIO Controller\n");
+
+ return 0;
+}
+
+arch_initcall(bfin_gpio_init);
+
+int peripheral_request(unsigned short per, const char *label)
+{
+ unsigned long flags;
+ unsigned short ident = P_IDENT(per);
+
+ if (!(per & P_DEFINED))
+ return -ENODEV;
+
+ if (check_gpio(ident) < 0)
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) {
+ printk(KERN_ERR
+ "%s: Peripheral %d is already reserved as GPIO!\n",
+ __FUNCTION__, per);
+ dump_stack();
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+
+ if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) {
+
+ u16 funct = get_portmux(ident);
+
+ if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) {
+ printk(KERN_ERR
+ "%s: Peripheral %d is already reserved!\n",
+ __FUNCTION__, per);
+ dump_stack();
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+ }
+
+ reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident);
+
+ portmux_setup(ident, P_FUNCT2MUX(per));
+ port_setup(ident, PERIPHERAL_USAGE);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(peripheral_request);
+
+int peripheral_request_list(unsigned short per[], const char *label)
+{
+
+ u16 cnt;
+ int ret;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+ ret = peripheral_request(per[cnt], label);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(peripheral_request_list);
+
+void peripheral_free(unsigned short per)
+{
+ unsigned long flags;
+ unsigned short ident = P_IDENT(per);
+
+ if (!(per & P_DEFINED))
+ return;
+
+ if (check_gpio(ident) < 0)
+ return;
+
+ local_irq_save(flags);
+
+ if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) {
+ printk(KERN_ERR "bfin-gpio: Peripheral %d wasn't reserved!\n", per);
+ dump_stack();
+ local_irq_restore(flags);
+ return;
+ }
+
+ if (!(per & P_MAYSHARE)) {
+ port_setup(ident, GPIO_USAGE);
+ }
+
+ reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(peripheral_free);
+
+void peripheral_free_list(unsigned short per[])
+{
+ u16 cnt;
+
+ for (cnt = 0; per[cnt] != 0; cnt++) {
+ peripheral_free(per[cnt]);
+ }
+
+}
+EXPORT_SYMBOL(peripheral_free_list);
+
+/***********************************************************
+*
+* FUNCTIONS: Blackfin GPIO Driver
+*
+* INPUTS/OUTPUTS:
+* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS
+*
+*
+* DESCRIPTION: Blackfin GPIO Driver API
+*
+* CAUTION:
+*************************************************************
+* MODIFICATION HISTORY :
+**************************************************************/
+
+int gpio_request(unsigned short gpio, const char *label)
+{
+ unsigned long flags;
+
+ if (check_gpio(gpio) < 0)
+ return -EINVAL;
+
+ local_irq_save(flags);
+
+ if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+ printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio);
+ dump_stack();
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+
+ if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+ printk(KERN_ERR
+ "bfin-gpio: GPIO %d is already reserved as Peripheral!\n", gpio);
+ dump_stack();
+ local_irq_restore(flags);
+ return -EBUSY;
+ }
+
+ reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+
+ local_irq_restore(flags);
+
+ port_setup(gpio, GPIO_USAGE);
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_request);
+
+void gpio_free(unsigned short gpio)
+{
+ unsigned long flags;
+
+ if (check_gpio(gpio) < 0)
+ return;
+
+ local_irq_save(flags);
+
+ if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+ printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio);
+ dump_stack();
+ local_irq_restore(flags);
+ return;
+ }
+
+ reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_free);
+
+void gpio_direction_input(unsigned short gpio)
+{
+ unsigned long flags;
+
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+ local_irq_save(flags);
+ gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio);
+ gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_input);
+
+void gpio_direction_output(unsigned short gpio)
+{
+ unsigned long flags;
+
+ BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)));
+
+ local_irq_save(flags);
+ gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio);
+ gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_direction_output);
+
+void gpio_set_value(unsigned short gpio, unsigned short arg)
+{
+ if (arg)
+ gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio);
+ else
+ gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio);
+
+}
+EXPORT_SYMBOL(gpio_set_value);
+
+unsigned short gpio_get_value(unsigned short gpio)
+{
+ return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio)));
+}
+EXPORT_SYMBOL(gpio_get_value);
diff --git a/arch/blackfin/mach-bf548/head.S b/arch/blackfin/mach-bf548/head.S
new file mode 100644
index 000000000000..06751ae8b857
--- /dev/null
+++ b/arch/blackfin/mach-bf548/head.S
@@ -0,0 +1,512 @@
+/*
+ * File: arch/blackfin/mach-bf548/head.S
+ * Based on: arch/blackfin/mach-bf537/head.S
+ * Author: Jeff Dionne <jeff@uclinux.org> COPYRIGHT 1998 D. Jeff Dionne
+ *
+ * Created: 1998
+ * Description: Startup code for Blackfin BF548
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/linkage.h>
+#include <asm/blackfin.h>
+#include <asm/trace.h>
+#if CONFIG_BFIN_KERNEL_CLOCK
+#include <asm/mach/mem_init.h>
+#endif
+
+.global __rambase
+.global __ramstart
+.global __ramend
+.extern ___bss_stop
+.extern ___bss_start
+.extern _bf53x_relocate_l1_mem
+
+#define INITIAL_STACK 0xFFB01000
+
+.text
+
+ENTRY(__start)
+ENTRY(__stext)
+ /* R0: argument of command line string, passed from uboot, save it */
+ R7 = R0;
+ /* Set the SYSCFG register */
+ R0 = 0x36;
+ SYSCFG = R0; /*Enable Cycle Counter and Nesting Of Interrupts(3rd Bit)*/
+ R0 = 0;
+
+ /* Clear Out All the data and pointer Registers*/
+ R1 = R0;
+ R2 = R0;
+ R3 = R0;
+ R4 = R0;
+ R5 = R0;
+ R6 = R0;
+
+ P0 = R0;
+ P1 = R0;
+ P2 = R0;
+ P3 = R0;
+ P4 = R0;
+ P5 = R0;
+
+ LC0 = r0;
+ LC1 = r0;
+ L0 = r0;
+ L1 = r0;
+ L2 = r0;
+ L3 = r0;
+
+ /* Clear Out All the DAG Registers*/
+ B0 = r0;
+ B1 = r0;
+ B2 = r0;
+ B3 = r0;
+
+ I0 = r0;
+ I1 = r0;
+ I2 = r0;
+ I3 = r0;
+
+ M0 = r0;
+ M1 = r0;
+ M2 = r0;
+ M3 = r0;
+
+ trace_buffer_start(p0,r0);
+ P0 = R1;
+ R0 = R1;
+
+ /* Turn off the icache */
+ p0.l = (IMEM_CONTROL & 0xFFFF);
+ p0.h = (IMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENICPLB;
+ R0 = R0 & R1;
+ [p0] = R0;
+ SSYNC;
+
+ /* Turn off the dcache */
+ p0.l = (DMEM_CONTROL & 0xFFFF);
+ p0.h = (DMEM_CONTROL >> 16);
+ R1 = [p0];
+ R0 = ~ENDCPLB;
+ R0 = R0 & R1;
+ [p0] = R0;
+ SSYNC;
+
+ /* Initialize stack pointer */
+ SP.L = LO(INITIAL_STACK);
+ SP.H = HI(INITIAL_STACK);
+ FP = SP;
+ USP = SP;
+
+ /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */
+ call _bf53x_relocate_l1_mem;
+#if CONFIG_BFIN_KERNEL_CLOCK
+ call _start_dma_code;
+#endif
+ /* Code for initializing Async memory banks */
+
+ p2.h = hi(EBIU_AMBCTL1);
+ p2.l = lo(EBIU_AMBCTL1);
+ r0.h = hi(AMBCTL1VAL);
+ r0.l = lo(AMBCTL1VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMBCTL0);
+ p2.l = lo(EBIU_AMBCTL0);
+ r0.h = hi(AMBCTL0VAL);
+ r0.l = lo(AMBCTL0VAL);
+ [p2] = r0;
+ ssync;
+
+ p2.h = hi(EBIU_AMGCTL);
+ p2.l = lo(EBIU_AMGCTL);
+ r0 = AMGCTLVAL;
+ w[p2] = r0;
+ ssync;
+
+ /* This section keeps the processor in supervisor mode
+ * during kernel boot. Switches to user mode at end of boot.
+ * See page 3-9 of Hardware Reference manual for documentation.
+ */
+
+ /* EVT15 = _real_start */
+
+ p0.l = lo(EVT15);
+ p0.h = hi(EVT15);
+ p1.l = _real_start;
+ p1.h = _real_start;
+ [p0] = p1;
+ csync;
+
+ p0.l = lo(IMASK);
+ p0.h = hi(IMASK);
+ p1.l = IMASK_IVG15;
+ p1.h = 0x0;
+ [p0] = p1;
+ csync;
+
+ raise 15;
+ p0.l = .LWAIT_HERE;
+ p0.h = .LWAIT_HERE;
+ reti = p0;
+#if defined (ANOMALY_05000281)
+ nop;
+ nop;
+ nop;
+#endif
+ rti;
+
+.LWAIT_HERE:
+ jump .LWAIT_HERE;
+
+ENTRY(_real_start)
+ [ -- sp ] = reti;
+ p0.l = lo(WDOG_CTL);
+ p0.h = hi(WDOG_CTL);
+ r0 = 0xAD6(z);
+ w[p0] = r0; /* watchdog off for now */
+ ssync;
+
+ /* Code update for BSS size == 0
+ * Zero out the bss region.
+ */
+
+ p1.l = ___bss_start;
+ p1.h = ___bss_start;
+ p2.l = ___bss_stop;
+ p2.h = ___bss_stop;
+ r0 = 0;
+ p2 -= p1;
+ lsetup (.L_clear_bss, .L_clear_bss ) lc0 = p2;
+.L_clear_bss:
+ B[p1++] = r0;
+
+ /* In case there is a NULL pointer reference
+ * Zero out region before stext
+ */
+
+ p1.l = 0x0;
+ p1.h = 0x0;
+ r0.l = __stext;
+ r0.h = __stext;
+ r0 = r0 >> 1;
+ p2 = r0;
+ r0 = 0;
+ lsetup (.L_clear_zero, .L_clear_zero ) lc0 = p2;
+.L_clear_zero:
+ W[p1++] = r0;
+
+ /* pass the uboot arguments to the global value command line */
+ R0 = R7;
+ call _cmdline_init;
+
+ p1.l = __rambase;
+ p1.h = __rambase;
+ r0.l = __sdata;
+ r0.h = __sdata;
+ [p1] = r0;
+
+ p1.l = __ramstart;
+ p1.h = __ramstart;
+ p3.l = ___bss_stop;
+ p3.h = ___bss_stop;
+
+ r1 = p3;
+ [p1] = r1;
+
+
+ /*
+ * load the current thread pointer and stack
+ */
+ r1.l = _init_thread_union;
+ r1.h = _init_thread_union;
+
+ r2.l = 0x2000;
+ r2.h = 0x0000;
+ r1 = r1 + r2;
+ sp = r1;
+ usp = sp;
+ fp = sp;
+ call _start_kernel;
+.L_exit:
+ jump.s .L_exit;
+
+.section .l1.text
+#if CONFIG_BFIN_KERNEL_CLOCK
+ENTRY(_start_dma_code)
+
+ /* Enable PHY CLK buffer output */
+ p0.h = hi(VR_CTL);
+ p0.l = lo(VR_CTL);
+ r0.l = w[p0];
+ bitset(r0, 14);
+ w[p0] = r0.l;
+ ssync;
+
+ p0.h = hi(SIC_IWR);
+ p0.l = lo(SIC_IWR);
+ r0.l = 0x1;
+ r0.h = 0x0;
+ [p0] = r0;
+ SSYNC;
+
+ /*
+ * Set PLL_CTL
+ * - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
+ * - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
+ * - [7] = output delay (add 200ps of delay to mem signals)
+ * - [6] = input delay (add 200ps of input delay to mem signals)
+ * - [5] = PDWN : 1=All Clocks off
+ * - [3] = STOPCK : 1=Core Clock off
+ * - [1] = PLL_OFF : 1=Disable Power to PLL
+ * - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
+ * all other bits set to zero
+ */
+
+ p0.h = hi(PLL_LOCKCNT);
+ p0.l = lo(PLL_LOCKCNT);
+ r0 = 0x300(Z);
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITSET (R0, 24);
+ [P2] = R0;
+ SSYNC;
+
+ r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
+ r0 = r0 << 9; /* Shift it over, */
+ r1 = CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
+ r0 = r1 | r0;
+ r1 = PLL_BYPASS; /* Bypass the PLL? */
+ r1 = r1 << 8; /* Shift it over */
+ r0 = r1 | r0; /* add them all together */
+
+ p0.h = hi(PLL_CTL);
+ p0.l = lo(PLL_CTL); /* Load the address */
+ cli r2; /* Disable interrupts */
+ ssync;
+ w[p0] = r0.l; /* Set the value */
+ idle; /* Wait for the PLL to stablize */
+ sti r2; /* Enable interrupts */
+
+.Lcheck_again:
+ p0.h = hi(PLL_STAT);
+ p0.l = lo(PLL_STAT);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,5);
+ if ! CC jump .Lcheck_again;
+
+ /* Configure SCLK & CCLK Dividers */
+ r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
+ p0.h = hi(PLL_DIV);
+ p0.l = lo(PLL_DIV);
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = lo(EBIU_SDRRC);
+ p0.h = hi(EBIU_SDRRC);
+ r0 = mem_SDRRC;
+ w[p0] = r0.l;
+ ssync;
+
+ p0.l = (EBIU_SDBCTL & 0xFFFF);
+ p0.h = (EBIU_SDBCTL >> 16); /* SDRAM Memory Bank Control Register */
+ r0 = mem_SDBCTL;
+ w[p0] = r0.l;
+ ssync;
+
+ P2.H = hi(EBIU_SDGCTL);
+ P2.L = lo(EBIU_SDGCTL);
+ R0 = [P2];
+ BITCLR (R0, 24);
+ p0.h = hi(EBIU_SDSTAT);
+ p0.l = lo(EBIU_SDSTAT);
+ r2.l = w[p0];
+ cc = bittst(r2,3);
+ if !cc jump .Lskip;
+ NOP;
+ BITSET (R0, 23);
+.Lskip:
+ [P2] = R0;
+ SSYNC;
+
+ R0.L = lo(mem_SDGCTL);
+ R0.H = hi(mem_SDGCTL);
+ R1 = [p2];
+ R1 = R1 | R0;
+ [P2] = R1;
+ SSYNC;
+
+ p0.h = hi(SIC_IWR);
+ p0.l = lo(SIC_IWR);
+ r0.l = lo(IWR_ENABLE_ALL);
+ r0.h = hi(IWR_ENABLE_ALL);
+ [p0] = r0;
+ SSYNC;
+
+ RTS;
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+ENTRY(_bfin_reset)
+ /* No more interrupts to be handled*/
+ CLI R6;
+ SSYNC;
+
+#if defined(CONFIG_MTD_M25P80)
+/*
+ * The following code fix the SPI flash reboot issue,
+ * /CS signal of the chip which is using PF10 return to GPIO mode
+ */
+ p0.h = hi(PORTF_FER);
+ p0.l = lo(PORTF_FER);
+ r0.l = 0x0000;
+ w[p0] = r0.l;
+ SSYNC;
+
+/* /CS return to high */
+ p0.h = hi(PORTFIO);
+ p0.l = lo(PORTFIO);
+ r0.l = 0xFFFF;
+ w[p0] = r0.l;
+ SSYNC;
+
+/* Delay some time, This is necessary */
+ r1.h = 0;
+ r1.l = 0x400;
+ p1 = r1;
+ lsetup (_delay_lab1,_delay_lab1_end ) lc1 = p1;
+_delay_lab1:
+ r0.h = 0;
+ r0.l = 0x8000;
+ p0 = r0;
+ lsetup (_delay_lab0,_delay_lab0_end ) lc0 = p0;
+_delay_lab0:
+ nop;
+_delay_lab0_end:
+ nop;
+_delay_lab1_end:
+ nop;
+#endif
+
+ /* Clear the bits 13-15 in SWRST if they werent cleared */
+ p0.h = hi(SWRST);
+ p0.l = lo(SWRST);
+ csync;
+ r0.l = w[p0];
+
+ /* Clear the IMASK register */
+ p0.h = hi(IMASK);
+ p0.l = lo(IMASK);
+ r0 = 0x0;
+ [p0] = r0;
+
+ /* Clear the ILAT register */
+ p0.h = hi(ILAT);
+ p0.l = lo(ILAT);
+ r0 = [p0];
+ [p0] = r0;
+ SSYNC;
+
+ /* Disable the WDOG TIMER */
+ p0.h = hi(WDOG_CTL);
+ p0.l = lo(WDOG_CTL);
+ r0.l = 0xAD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Clear the sticky bit incase it is already set */
+ p0.h = hi(WDOG_CTL);
+ p0.l = lo(WDOG_CTL);
+ r0.l = 0x8AD6;
+ w[p0] = r0.l;
+ SSYNC;
+
+ /* Program the count value */
+ R0.l = 0x100;
+ R0.h = 0x0;
+ P0.h = hi(WDOG_CNT);
+ P0.l = lo(WDOG_CNT);
+ [P0] = R0;
+ SSYNC;
+
+ /* Program WDOG_STAT if necessary */
+ P0.h = hi(WDOG_CTL);
+ P0.l = lo(WDOG_CTL);
+ R0 = W[P0](Z);
+ CC = BITTST(R0,1);
+ if !CC JUMP .LWRITESTAT;
+ CC = BITTST(R0,2);
+ if !CC JUMP .LWRITESTAT;
+ JUMP .LSKIP_WRITE;
+
+.LWRITESTAT:
+ /* When watch dog timer is enabled,
+ * a write to STAT will load the contents of CNT to STAT
+ */
+ R0 = 0x0000(z);
+ P0.h = hi(WDOG_STAT);
+ P0.l = lo(WDOG_STAT)
+ [P0] = R0;
+ SSYNC;
+
+.LSKIP_WRITE:
+ /* Enable the reset event */
+ P0.h = hi(WDOG_CTL);
+ P0.l = lo(WDOG_CTL);
+ R0 = W[P0](Z);
+ BITCLR(R0,1);
+ BITCLR(R0,2);
+ W[P0] = R0.L;
+ SSYNC;
+ NOP;
+
+ /* Enable the wdog counter */
+ R0 = W[P0](Z);
+ BITCLR(R0,4);
+ W[P0] = R0.L;
+ SSYNC;
+
+ IDLE;
+
+ RTS;
+
+.data
+
+/*
+ * Set up the usable of RAM stuff. Size of RAM is determined then
+ * an initial stack set up at the end.
+ */
+
+.align 4
+__rambase:
+.long 0
+__ramstart:
+.long 0
+__ramend:
+.long 0
diff --git a/arch/blackfin/mach-bf548/ints-priority.c b/arch/blackfin/mach-bf548/ints-priority.c
new file mode 100644
index 000000000000..cb0ebac53c79
--- /dev/null
+++ b/arch/blackfin/mach-bf548/ints-priority.c
@@ -0,0 +1,137 @@
+/*
+ * File: arch/blackfin/mach-bf537/ints-priority.c
+ * Based on: arch/blackfin/mach-bf533/ints-priority.c
+ * Author: Michael Hennerich
+ *
+ * Created:
+ * Description: Set up the interupt priorities
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <asm/blackfin.h>
+
+void program_IAR(void)
+{
+ /* Program the IAR0 Register with the configured priority */
+ bfin_write_SIC_IAR0(((CONFIG_IRQ_PLL_WAKEUP - 7) << IRQ_PLL_WAKEUP_POS) |
+ ((CONFIG_IRQ_DMAC0_ERR - 7) << IRQ_DMAC0_ERR_POS) |
+ ((CONFIG_IRQ_EPPI0_ERR - 7) << IRQ_EPPI0_ERR_POS) |
+ ((CONFIG_IRQ_SPORT0_ERR - 7) << IRQ_SPORT0_ERR_POS) |
+ ((CONFIG_IRQ_SPORT1_ERR - 7) << IRQ_SPORT1_ERR_POS) |
+ ((CONFIG_IRQ_SPI0_ERR - 7) << IRQ_SPI0_ERR_POS) |
+ ((CONFIG_IRQ_UART0_ERR - 7) << IRQ_UART0_ERR_POS) |
+ ((CONFIG_IRQ_RTC - 7) << IRQ_RTC_POS));
+
+ bfin_write_SIC_IAR1(((CONFIG_IRQ_EPPI0 - 7) << IRQ_EPPI0_POS) |
+ ((CONFIG_IRQ_SPORT0_RX - 7) << IRQ_SPORT0_RX_POS) |
+ ((CONFIG_IRQ_SPORT0_TX - 7) << IRQ_SPORT0_TX_POS) |
+ ((CONFIG_IRQ_SPORT1_RX - 7) << IRQ_SPORT1_RX_POS) |
+ ((CONFIG_IRQ_SPORT1_TX - 7) << IRQ_SPORT1_TX_POS) |
+ ((CONFIG_IRQ_SPI0 - 7) << IRQ_SPI0_POS) |
+ ((CONFIG_IRQ_UART0_RX - 7) << IRQ_UART0_RX_POS) |
+ ((CONFIG_IRQ_UART0_TX - 7) << IRQ_UART0_TX_POS));
+
+ bfin_write_SIC_IAR2(((CONFIG_IRQ_TIMER8 - 7) << IRQ_TIMER8_POS) |
+ ((CONFIG_IRQ_TIMER9 - 7) << IRQ_TIMER9_POS) |
+ ((CONFIG_IRQ_PINT0 - 7) << IRQ_PINT0_POS) |
+ ((CONFIG_IRQ_PINT1 - 7) << IRQ_PINT1_POS) |
+ ((CONFIG_IRQ_MDMAS0 - 7) << IRQ_MDMAS0_POS) |
+ ((CONFIG_IRQ_MDMAS1 - 7) << IRQ_MDMAS1_POS) |
+ ((CONFIG_IRQ_WATCHDOG - 7) << IRQ_WATCHDOG_POS));
+
+ bfin_write_SIC_IAR3(((CONFIG_IRQ_DMAC1_ERR - 7) << IRQ_DMAC1_ERR_POS) |
+ ((CONFIG_IRQ_SPORT2_ERR - 7) << IRQ_SPORT2_ERR_POS) |
+ ((CONFIG_IRQ_SPORT3_ERR - 7) << IRQ_SPORT3_ERR_POS) |
+ ((CONFIG_IRQ_MXVR_DATA - 7) << IRQ_MXVR_DATA_POS) |
+ ((CONFIG_IRQ_SPI1_ERR - 7) << IRQ_SPI1_ERR_POS) |
+ ((CONFIG_IRQ_SPI2_ERR - 7) << IRQ_SPI2_ERR_POS) |
+ ((CONFIG_IRQ_UART1_ERR - 7) << IRQ_UART1_ERR_POS) |
+ ((CONFIG_IRQ_UART2_ERR - 7) << IRQ_UART2_ERR_POS));
+
+ bfin_write_SIC_IAR4(((CONFIG_IRQ_CAN0_ERR - 7) << IRQ_CAN0_ERR_POS) |
+ ((CONFIG_IRQ_SPORT2_RX - 7) << IRQ_SPORT2_RX_POS) |
+ ((CONFIG_IRQ_SPORT2_TX - 7) << IRQ_SPORT2_TX_POS) |
+ ((CONFIG_IRQ_SPORT3_RX - 7) << IRQ_SPORT3_RX_POS) |
+ ((CONFIG_IRQ_SPORT3_TX - 7) << IRQ_SPORT3_TX_POS) |
+ ((CONFIG_IRQ_EPPI1 - 7) << IRQ_EPPI1_POS) |
+ ((CONFIG_IRQ_EPPI2 - 7) << IRQ_EPPI2_POS) |
+ ((CONFIG_IRQ_SPI1 - 7) << IRQ_SPI1_POS));
+
+ bfin_write_SIC_IAR5(((CONFIG_IRQ_SPI2 - 7) << IRQ_SPI2_POS) |
+ ((CONFIG_IRQ_UART1_RX - 7) << IRQ_UART1_RX_POS) |
+ ((CONFIG_IRQ_UART1_TX - 7) << IRQ_UART1_TX_POS) |
+ ((CONFIG_IRQ_ATAPI_RX - 7) << IRQ_ATAPI_RX_POS) |
+ ((CONFIG_IRQ_ATAPI_TX - 7) << IRQ_ATAPI_TX_POS) |
+ ((CONFIG_IRQ_TWI0 - 7) << IRQ_TWI0_POS) |
+ ((CONFIG_IRQ_TWI1 - 7) << IRQ_TWI1_POS) |
+ ((CONFIG_IRQ_CAN0_RX - 7) << IRQ_CAN0_RX_POS));
+
+ bfin_write_SIC_IAR6(((CONFIG_IRQ_CAN0_TX - 7) << IRQ_CAN0_TX_POS) |
+ ((CONFIG_IRQ_MDMAS2 - 7) << IRQ_MDMAS2_POS) |
+ ((CONFIG_IRQ_MDMAS3 - 7) << IRQ_MDMAS3_POS) |
+ ((CONFIG_IRQ_MXVR_ERR - 7) << IRQ_MXVR_ERR_POS) |
+ ((CONFIG_IRQ_MXVR_MSG - 7) << IRQ_MXVR_MSG_POS) |
+ ((CONFIG_IRQ_MXVR_PKT - 7) << IRQ_MXVR_PKT_POS) |
+ ((CONFIG_IRQ_EPPI1_ERR - 7) << IRQ_EPPI1_ERR_POS) |
+ ((CONFIG_IRQ_EPPI2_ERR - 7) << IRQ_EPPI2_ERR_POS));
+
+ bfin_write_SIC_IAR7(((CONFIG_IRQ_UART3_ERR - 7) << IRQ_UART3_ERR_POS) |
+ ((CONFIG_IRQ_HOST_ERR - 7) << IRQ_HOST_ERR_POS) |
+ ((CONFIG_IRQ_PIXC_ERR - 7) << IRQ_PIXC_ERR_POS) |
+ ((CONFIG_IRQ_NFC_ERR - 7) << IRQ_NFC_ERR_POS) |
+ ((CONFIG_IRQ_ATAPI_ERR - 7) << IRQ_ATAPI_ERR_POS) |
+ ((CONFIG_IRQ_CAN1_ERR - 7) << IRQ_CAN1_ERR_POS) |
+ ((CONFIG_IRQ_HS_DMA_ERR - 7) << IRQ_HS_DMA_ERR_POS));
+
+ bfin_write_SIC_IAR8(((CONFIG_IRQ_PIXC_IN0 - 7) << IRQ_PIXC_IN1_POS) |
+ ((CONFIG_IRQ_PIXC_IN1 - 7) << IRQ_PIXC_IN1_POS) |
+ ((CONFIG_IRQ_PIXC_OUT - 7) << IRQ_PIXC_OUT_POS) |
+ ((CONFIG_IRQ_SDH - 7) << IRQ_SDH_POS) |
+ ((CONFIG_IRQ_CNT - 7) << IRQ_CNT_POS) |
+ ((CONFIG_IRQ_KEY - 7) << IRQ_KEY_POS) |
+ ((CONFIG_IRQ_CAN1_RX - 7) << IRQ_CAN1_RX_POS) |
+ ((CONFIG_IRQ_CAN1_TX - 7) << IRQ_CAN1_TX_POS));
+
+ bfin_write_SIC_IAR9(((CONFIG_IRQ_SDH_MASK0 - 7) << IRQ_SDH_MASK0_POS) |
+ ((CONFIG_IRQ_SDH_MASK1 - 7) << IRQ_SDH_MASK1_POS) |
+ ((CONFIG_IRQ_USB_INT0 - 7) << IRQ_USB_INT0_POS) |
+ ((CONFIG_IRQ_USB_INT1 - 7) << IRQ_USB_INT1_POS) |
+ ((CONFIG_IRQ_USB_INT2 - 7) << IRQ_USB_INT2_POS) |
+ ((CONFIG_IRQ_USB_DMA - 7) << IRQ_USB_DMA_POS) |
+ ((CONFIG_IRQ_OTPSEC - 7) << IRQ_OTPSEC_POS));
+
+ bfin_write_SIC_IAR10(((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) |
+ ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS));
+
+ bfin_write_SIC_IAR11(((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) |
+ ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) |
+ ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS) |
+ ((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) |
+ ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) |
+ ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) |
+ ((CONFIG_IRQ_PINT2 - 7) << IRQ_PINT2_POS) |
+ ((CONFIG_IRQ_PINT3 - 7) << IRQ_PINT3_POS));
+
+ SSYNC();
+}
diff --git a/arch/blackfin/mach-bf561/Makefile b/arch/blackfin/mach-bf561/Makefile
index 57f475a55161..f39235a55783 100644
--- a/arch/blackfin/mach-bf561/Makefile
+++ b/arch/blackfin/mach-bf561/Makefile
@@ -4,6 +4,6 @@
extra-y := head.o
-obj-y := ints-priority.o
+obj-y := ints-priority.o dma.o
obj-$(CONFIG_BF561_COREB) += coreb.o
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
index 3dc5c042048c..5b2b544529a1 100644
--- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -34,7 +34,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#include <linux/usb_isp1362.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
#include <asm/bfin5xx_spi.h>
/*
@@ -52,11 +52,11 @@ static struct mtd_partition bfin_spi_flash_partitions[] = {
.size = 0x00020000,
.offset = 0,
.mask_flags = MTD_CAP_ROM
- },{
+ }, {
.name = "kernel",
.size = 0xe0000,
.offset = 0x20000
- },{
+ }, {
.name = "file system",
.size = 0x700000,
.offset = 0x00100000,
@@ -186,7 +186,7 @@ static struct resource smc91x_resources[] = {
.start = 0x28000300,
.end = 0x28000300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF0,
.end = IRQ_PF0,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -206,11 +206,11 @@ static struct resource isp1362_hcd_resources[] = {
.start = 0x24008000,
.end = 0x24008000,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = 0x24008004,
.end = 0x24008004,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF47,
.end = IRQ_PF47,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
@@ -241,25 +241,25 @@ static struct platform_device isp1362_hcd_device = {
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
static struct resource bfin_uart_resources[] = {
- {
- .start = 0xFFC00400,
- .end = 0xFFC004FF,
- .flags = IORESOURCE_MEM,
- },
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
};
static struct platform_device bfin_uart_device = {
- .name = "bfin-uart",
- .id = 1,
- .num_resources = ARRAY_SIZE(bfin_uart_resources),
- .resource = bfin_uart_resources,
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
};
#endif
static struct platform_device *cm_bf561_devices[] __initdata = {
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
- &bfin_uart_device,
+ &bfin_uart_device,
#endif
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index 9720b5c307ab..724191da20a2 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -30,10 +30,9 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <asm/irq.h>
-#include <asm/bfin5xx_spi.h>
-#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/bfin5xx_spi.h>
/*
* Name the Board for the /proc/cpuinfo
@@ -45,13 +44,13 @@ char *bfin_board_name = "ADDS-BF561-EZKIT";
#if defined(CONFIG_USB_ISP1760_HCD) || defined(CONFIG_USB_ISP1760_HCD_MODULE)
static struct resource bfin_isp1761_resources[] = {
- [0] = {
+ {
.name = "isp1761-regs",
.start = ISP1761_BASE + 0x00000000,
.end = ISP1761_BASE + 0x000fffff,
.flags = IORESOURCE_MEM,
},
- [1] = {
+ {
.start = ISP1761_IRQ,
.end = ISP1761_IRQ,
.flags = IORESOURCE_IRQ,
@@ -71,7 +70,7 @@ static struct platform_device *bfin_isp1761_devices[] = {
int __init bfin_isp1761_init(void)
{
- unsigned int num_devices=ARRAY_SIZE(bfin_isp1761_devices);
+ unsigned int num_devices = ARRAY_SIZE(bfin_isp1761_devices);
printk(KERN_INFO "%s(): registering device resources\n", __FUNCTION__);
set_irq_type(ISP1761_IRQ, IRQF_TRIGGER_FALLING);
@@ -98,7 +97,7 @@ static struct resource smc91x_resources[] = {
.start = 0x2C010300,
.end = 0x2C010300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PF9,
.end = IRQ_PF9,
@@ -116,18 +115,18 @@ static struct platform_device smc91x_device = {
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
static struct resource bfin_uart_resources[] = {
- {
- .start = 0xFFC00400,
- .end = 0xFFC004FF,
- .flags = IORESOURCE_MEM,
- },
+ {
+ .start = 0xFFC00400,
+ .end = 0xFFC004FF,
+ .flags = IORESOURCE_MEM,
+ },
};
static struct platform_device bfin_uart_device = {
- .name = "bfin-uart",
- .id = 1,
- .num_resources = ARRAY_SIZE(bfin_uart_resources),
- .resource = bfin_uart_resources,
+ .name = "bfin-uart",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bfin_uart_resources),
+ .resource = bfin_uart_resources,
};
#endif
@@ -176,7 +175,7 @@ static struct platform_device *ezkit_devices[] __initdata = {
&spi_bfin_master_device,
#endif
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
- &bfin_uart_device,
+ &bfin_uart_device,
#endif
};
diff --git a/arch/blackfin/mach-bf561/boards/generic_board.c b/arch/blackfin/mach-bf561/boards/generic_board.c
index 585ecdd2f6a5..4dfea5da674c 100644
--- a/arch/blackfin/mach-bf561/boards/generic_board.c
+++ b/arch/blackfin/mach-bf561/boards/generic_board.c
@@ -30,7 +30,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
char *bfin_board_name = "UNKNOWN BOARD";
@@ -43,11 +43,11 @@ static struct resource smc91x_resources[] = {
.start = 0x2C010300,
.end = 0x2C010300 + 16,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PROG_INTB,
.end = IRQ_PROG_INTB,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
- },{
+ }, {
/*
* denotes the flag pin and is used directly if
* CONFIG_IRQCHIP_DEMUX_GPIO is defined.
diff --git a/arch/blackfin/mach-bf561/boards/tepla.c b/arch/blackfin/mach-bf561/boards/tepla.c
index db308c7ccabb..c442eb23db5e 100644
--- a/arch/blackfin/mach-bf561/boards/tepla.c
+++ b/arch/blackfin/mach-bf561/boards/tepla.c
@@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/platform_device.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
char *bfin_board_name = "Tepla-BF561";
@@ -26,11 +26,11 @@ static struct resource smc91x_resources[] = {
.start = 0x2C000300,
.end = 0x2C000320,
.flags = IORESOURCE_MEM,
- },{
+ }, {
.start = IRQ_PROG_INTB,
.end = IRQ_PROG_INTB,
.flags = IORESOURCE_IRQ|IORESOURCE_IRQ_HIGHLEVEL,
- },{
+ }, {
/*
* denotes the flag pin and is used directly if
* CONFIG_IRQCHIP_DEMUX_GPIO is defined.
diff --git a/arch/blackfin/mach-bf561/coreb.c b/arch/blackfin/mach-bf561/coreb.c
index b28582fe083c..5d1d21b4c2a7 100644
--- a/arch/blackfin/mach-bf561/coreb.c
+++ b/arch/blackfin/mach-bf561/coreb.c
@@ -32,8 +32,8 @@
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/uaccess.h>
#include <asm/dma.h>
-#include <asm/uaccess.h>
#define MODULE_VER "v0.1"
@@ -202,7 +202,7 @@ static int coreb_open(struct inode *inode, struct file *file)
spin_unlock_irq(&coreb_lock);
return 0;
- out_busy:
+ out_busy:
spin_unlock_irq(&coreb_lock);
return -EBUSY;
}
@@ -365,19 +365,19 @@ int __init bf561_coreb_init(void)
printk(KERN_INFO "BF561 Core B driver %s initialized.\n", MODULE_VER);
return 0;
- release_dma_src:
+ release_dma_src:
free_dma(CH_MEM_STREAM2_SRC);
- release_dma_dest:
+ release_dma_dest:
free_dma(CH_MEM_STREAM2_DEST);
- release_data_a_sram:
+ release_data_a_sram:
release_mem_region(0xff400000, 0x8000);
- release_data_b_sram:
+ release_data_b_sram:
release_mem_region(0xff500000, 0x8000);
- release_instruction_b_sram:
+ release_instruction_b_sram:
release_mem_region(0xff610000, 0x4000);
- release_instruction_a_sram:
+ release_instruction_a_sram:
release_mem_region(0xff600000, 0x4000);
- exit:
+ exit:
return -ENOMEM;
}
diff --git a/arch/blackfin/mach-bf561/dma.c b/arch/blackfin/mach-bf561/dma.c
new file mode 100644
index 000000000000..89c65bb0bed3
--- /dev/null
+++ b/arch/blackfin/mach-bf561/dma.c
@@ -0,0 +1,131 @@
+/*
+ * File: arch/blackfin/mach-bf561/dma.c
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: This file contains the simple DMA Implementation for Blackfin
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <asm/blackfin.h>
+#include <asm/dma.h>
+
+struct dma_register *base_addr[MAX_BLACKFIN_DMA_CHANNEL] = {
+ (struct dma_register *) DMA1_0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_7_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_8_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_9_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_10_NEXT_DESC_PTR,
+ (struct dma_register *) DMA1_11_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_0_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_1_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_2_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_3_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_4_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_5_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_6_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_7_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_8_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_9_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_10_NEXT_DESC_PTR,
+ (struct dma_register *) DMA2_11_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA1_S1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_D0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_S0_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_D1_NEXT_DESC_PTR,
+ (struct dma_register *) MDMA2_S1_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_D0_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_S0_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_D1_NEXT_DESC_PTR,
+ (struct dma_register *) IMDMA_S1_NEXT_DESC_PTR,
+};
+
+int channel2irq(unsigned int channel)
+{
+ int ret_irq = -1;
+
+ switch (channel) {
+ case CH_PPI0:
+ ret_irq = IRQ_PPI0;
+ break;
+ case CH_PPI1:
+ ret_irq = IRQ_PPI1;
+ break;
+ case CH_SPORT0_RX:
+ ret_irq = IRQ_SPORT0_RX;
+ break;
+ case CH_SPORT0_TX:
+ ret_irq = IRQ_SPORT0_TX;
+ break;
+ case CH_SPORT1_RX:
+ ret_irq = IRQ_SPORT1_RX;
+ break;
+ case CH_SPORT1_TX:
+ ret_irq = IRQ_SPORT1_TX;
+ break;
+ case CH_SPI:
+ ret_irq = IRQ_SPI;
+ break;
+ case CH_UART_RX:
+ ret_irq = IRQ_UART_RX;
+ break;
+ case CH_UART_TX:
+ ret_irq = IRQ_UART_TX;
+ break;
+
+ case CH_MEM_STREAM0_SRC:
+ case CH_MEM_STREAM0_DEST:
+ ret_irq = IRQ_MEM_DMA0;
+ break;
+ case CH_MEM_STREAM1_SRC:
+ case CH_MEM_STREAM1_DEST:
+ ret_irq = IRQ_MEM_DMA1;
+ break;
+ case CH_MEM_STREAM2_SRC:
+ case CH_MEM_STREAM2_DEST:
+ ret_irq = IRQ_MEM_DMA2;
+ break;
+ case CH_MEM_STREAM3_SRC:
+ case CH_MEM_STREAM3_DEST:
+ ret_irq = IRQ_MEM_DMA3;
+ break;
+
+ case CH_IMEM_STREAM0_SRC:
+ case CH_IMEM_STREAM0_DEST:
+ ret_irq = IRQ_IMEM_DMA0;
+ break;
+ case CH_IMEM_STREAM1_SRC:
+ case CH_IMEM_STREAM1_DEST:
+ ret_irq = IRQ_IMEM_DMA1;
+ break;
+ }
+ return ret_irq;
+}
diff --git a/arch/blackfin/mach-bf561/head.S b/arch/blackfin/mach-bf561/head.S
index 31cbc75c85cf..2f08bcb2dded 100644
--- a/arch/blackfin/mach-bf561/head.S
+++ b/arch/blackfin/mach-bf561/head.S
@@ -30,6 +30,8 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/blackfin.h>
+#include <asm/trace.h>
+
#if CONFIG_BFIN_KERNEL_CLOCK
#include <asm/mach/mem_init.h>
#endif
@@ -93,6 +95,10 @@ ENTRY(__start)
M2 = r0;
M3 = r0;
+ trace_buffer_start(p0,r0);
+ P0 = R1;
+ R0 = R1;
+
/* Turn off the icache */
p0.l = (IMEM_CONTROL & 0xFFFF);
p0.h = (IMEM_CONTROL >> 16);
diff --git a/arch/blackfin/mach-bf561/ints-priority.c b/arch/blackfin/mach-bf561/ints-priority.c
index 86e3b0ee93f4..09b541b0f7c2 100644
--- a/arch/blackfin/mach-bf561/ints-priority.c
+++ b/arch/blackfin/mach-bf561/ints-priority.c
@@ -28,8 +28,8 @@
*/
#include <linux/module.h>
+#include <linux/irq.h>
#include <asm/blackfin.h>
-#include <asm/irq.h>
void program_IAR(void)
{
diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile
index d3a49073d196..0279ede70392 100644
--- a/arch/blackfin/mach-common/Makefile
+++ b/arch/blackfin/mach-common/Makefile
@@ -4,9 +4,9 @@
obj-y := \
cache.o cacheinit.o cplbhdlr.o cplbmgr.o entry.o \
- interrupt.o lock.o dpmc.o irqpanic.o
+ interrupt.o lock.o irqpanic.o
obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
obj-$(CONFIG_BFIN_SINGLE_CORE) += ints-priority-sc.o
obj-$(CONFIG_BFIN_DUAL_CORE) += ints-priority-dc.o
-obj-$(CONFIG_PM) += pm.o
+obj-$(CONFIG_PM) += pm.o dpmc.o
diff --git a/arch/blackfin/mach-common/cacheinit.S b/arch/blackfin/mach-common/cacheinit.S
index 7924a90d9658..9d475623b724 100644
--- a/arch/blackfin/mach-common/cacheinit.S
+++ b/arch/blackfin/mach-common/cacheinit.S
@@ -38,104 +38,37 @@
.text
+#ifdef ANOMALY_05000125
#if defined(CONFIG_BLKFIN_CACHE)
-ENTRY(_bfin_icache_init)
+ENTRY(_bfin_write_IMEM_CONTROL)
- /* Initialize Instruction CPLBS */
-
- I0.L = (ICPLB_ADDR0 & 0xFFFF);
- I0.H = (ICPLB_ADDR0 >> 16);
-
- I1.L = (ICPLB_DATA0 & 0xFFFF);
- I1.H = (ICPLB_DATA0 >> 16);
-
- I2.L = _icplb_table;
- I2.H = _icplb_table;
-
- r1 = -1; /* end point comparison */
- r3 = 15; /* max counter */
-
-/* read entries from table */
-
-.Lread_iaddr:
- R0 = [I2++];
- CC = R0 == R1;
- IF CC JUMP .Lidone;
- [I0++] = R0;
-
-.Lread_idata:
- R2 = [I2++];
- [I1++] = R2;
- R3 = R3 + R1;
- CC = R3 == R1;
- IF !CC JUMP .Lread_iaddr;
-
-.Lidone:
/* Enable Instruction Cache */
P0.l = (IMEM_CONTROL & 0xFFFF);
P0.h = (IMEM_CONTROL >> 16);
- R1 = [P0];
- R0 = (IMC | ENICPLB);
- R0 = R0 | R1;
/* Anomaly 05000125 */
- CLI R2;
+ CLI R1;
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
.align 8;
[P0] = R0;
SSYNC;
- STI R2;
+ STI R1;
RTS;
-ENDPROC(_bfin_icache_init)
+ENDPROC(_bfin_write_IMEM_CONTROL)
#endif
#if defined(CONFIG_BLKFIN_DCACHE)
-ENTRY(_bfin_dcache_init)
-
- /* Initialize Data CPLBS */
-
- I0.L = (DCPLB_ADDR0 & 0xFFFF);
- I0.H = (DCPLB_ADDR0 >> 16);
-
- I1.L = (DCPLB_DATA0 & 0xFFFF);
- I1.H = (DCPLB_DATA0 >> 16);
-
- I2.L = _dcplb_table;
- I2.H = _dcplb_table;
-
- R1 = -1; /* end point comparison */
- R3 = 15; /* max counter */
-
- /* read entries from table */
-.Lread_daddr:
- R0 = [I2++];
- cc = R0 == R1;
- IF CC JUMP .Lddone;
- [I0++] = R0;
-
-.Lread_ddata:
- R2 = [I2++];
- [I1++] = R2;
- R3 = R3 + R1;
- CC = R3 == R1;
- IF !CC JUMP .Lread_daddr;
-.Lddone:
- P0.L = (DMEM_CONTROL & 0xFFFF);
- P0.H = (DMEM_CONTROL >> 16);
- R1 = [P0];
-
- R0 = DMEM_CNTR;
-
- R0 = R0 | R1;
- /* Anomaly 05000125 */
- CLI R2;
+ENTRY(_bfin_write_DMEM_CONTROL)
+ CLI R1;
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
.align 8;
[P0] = R0;
SSYNC;
- STI R2;
+ STI R1;
RTS;
-ENDPROC(_bfin_dcache_init)
+ENDPROC(_bfin_write_DMEM_CONTROL)
+#endif
+
#endif
diff --git a/arch/blackfin/mach-common/cplbinfo.c b/arch/blackfin/mach-common/cplbinfo.c
index caa9623e6bd6..785ca9816971 100644
--- a/arch/blackfin/mach-common/cplbinfo.c
+++ b/arch/blackfin/mach-common/cplbinfo.c
@@ -31,11 +31,10 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
#include <asm/current.h>
-#include <asm/uaccess.h>
#include <asm/system.h>
-
#include <asm/cplb.h>
#include <asm/blackfin.h>
@@ -92,8 +91,7 @@ static char *cplb_print_entry(char *buf, int type)
} else
buf += sprintf(buf, "Data CPLB entry:\n");
- buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\
-\tiCount\toCount\n");
+ buf += sprintf(buf, "Address\t\tData\tSize\tValid\tLocked\tSwapin\n\tiCount\toCount\n");
while (*p_addr != 0xffffffff) {
entry = cplb_find_entry(cplb_addr, cplb_data, *p_addr, *p_data);
@@ -144,8 +142,7 @@ static int cplbinfo_proc_output(char *buf)
p = buf;
- p += sprintf(p,
- "------------------ CPLB Information ------------------\n\n");
+ p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
if (bfin_read_IMEM_CONTROL() & ENICPLB)
p = cplb_print_entry(p, CPLB_I);
@@ -191,9 +188,9 @@ static int __init cplbinfo_init(void)
{
struct proc_dir_entry *entry;
- if ((entry = create_proc_entry("cplbinfo", 0, NULL)) == NULL) {
+ entry = create_proc_entry("cplbinfo", 0, NULL);
+ if (!entry)
return -ENOMEM;
- }
entry->read_proc = cplbinfo_read_proc;
entry->write_proc = cplbinfo_write_proc;
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 40045b1386ad..d61bba98fb54 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -49,34 +49,15 @@
#include <linux/linkage.h>
+#include <linux/unistd.h>
#include <asm/blackfin.h>
-#include <asm/unistd.h>
#include <asm/errno.h>
#include <asm/thread_info.h> /* TIF_NEED_RESCHED */
#include <asm/asm-offsets.h>
+#include <asm/trace.h>
#include <asm/mach-common/context.S>
-#ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
- /*
- * TODO: this should be proper save/restore, but for now
- * we'll just cheat and use 0x1/0x13
- */
-# define DEBUG_START_HWTRACE \
- P5.l = LO(TBUFCTL); \
- P5.h = HI(TBUFCTL); \
- R7 = 0x13; \
- [P5] = R7;
-# define DEBUG_STOP_HWTRACE \
- P5.l = LO(TBUFCTL); \
- P5.h = HI(TBUFCTL); \
- R7 = 0x01; \
- [P5] = R7;
-#else
-# define DEBUG_START_HWTRACE
-# define DEBUG_STOP_HWTRACE
-#endif
-
#ifdef CONFIG_EXCPT_IRQ_SYSC_L1
.section .l1.text
#else
@@ -110,25 +91,14 @@ ENTRY(_ex_icplb)
ASTAT = [sp++];
SAVE_ALL_SYS
call __cplb_hdr;
- DEBUG_START_HWTRACE
+ DEBUG_START_HWTRACE(p5, r7)
RESTORE_ALL_SYS
SP = RETN;
rtx;
ENDPROC(_ex_icplb)
-ENTRY(_ex_spinlock)
- /* Transform this into a syscall - twiddle the syscall vector. */
- p5.l = lo(EVT15);
- p5.h = hi(EVT15);
- r7.l = _spinlock_bh;
- r7.h = _spinlock_bh;
- [p5] = r7;
- csync;
- /* Fall through. */
-ENDPROC(_ex_spinlock)
-
ENTRY(_ex_syscall)
- DEBUG_START_HWTRACE
+ DEBUG_START_HWTRACE(p5, r7)
(R7:6,P5:4) = [sp++];
ASTAT = [sp++];
raise 15; /* invoked by TRAP #0, for sys call */
@@ -136,26 +106,6 @@ ENTRY(_ex_syscall)
rtx
ENDPROC(_ex_syscall)
-ENTRY(_spinlock_bh)
- SAVE_ALL_SYS
- /* To end up here, vector 15 was changed - so we have to change it
- * back.
- */
- p0.l = lo(EVT15);
- p0.h = hi(EVT15);
- p1.l = _evt_system_call;
- p1.h = _evt_system_call;
- [p0] = p1;
- csync;
- r0 = [sp + PT_R0];
- sp += -12;
- call _sys_bfin_spinlock;
- sp += 12;
- [SP + PT_R0] = R0;
- RESTORE_ALL_SYS
- rti;
-ENDPROC(_spinlock_bh)
-
ENTRY(_ex_soft_bp)
r7 = retx;
r7 += -2;
@@ -186,7 +136,7 @@ ENTRY(_ex_single_step)
if !cc jump _ex_trap_c;
_return_from_exception:
- DEBUG_START_HWTRACE
+ DEBUG_START_HWTRACE(p5, r7)
#ifdef ANOMALY_05000257
R7=LC0;
LC0=R7;
@@ -208,7 +158,7 @@ ENTRY(_handle_bad_cplb)
* need to make a CPLB exception look like a normal exception
*/
- DEBUG_START_HWTRACE
+ DEBUG_START_HWTRACE(p5, r7)
RESTORE_ALL_SYS
[--sp] = ASTAT;
[--sp] = (R7:6, P5:4);
@@ -251,7 +201,7 @@ ENTRY(_ex_trap_c)
R6 = SEQSTAT;
[P5] = R6;
- DEBUG_START_HWTRACE
+ DEBUG_START_HWTRACE(p5, r7)
(R7:6,P5:4) = [sp++];
ASTAT = [sp++];
SP = RETN;
@@ -335,7 +285,7 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/
/* Try to deal with syscalls quickly. */
[--sp] = ASTAT;
[--sp] = (R7:6, P5:4);
- DEBUG_STOP_HWTRACE
+ DEBUG_STOP_HWTRACE(p5, r7)
r7 = SEQSTAT; /* reason code is in bit 5:0 */
r6.l = lo(SEQSTAT_EXCAUSE);
r6.h = hi(SEQSTAT_EXCAUSE);
@@ -741,6 +691,10 @@ _schedule_and_signal_from_int:
r0 = [p0];
sti r0;
+ r0 = sp;
+ sp += -12;
+ call _finish_atomic_sections;
+ sp += 12;
jump.s .Lresume_userspace;
_schedule_and_signal:
@@ -790,14 +744,14 @@ ENDPROC(_init_exception_buff)
ALIGN
_extable:
/* entry for each EXCAUSE[5:0]
- * This table bmust be in sync with the table in ./kernel/traps.c
+ * This table must be in sync with the table in ./kernel/traps.c
* EXCPT instruction can provide 4 bits of EXCAUSE, allowing 16 to be user defined
*/
.long _ex_syscall; /* 0x00 - User Defined - Linux Syscall */
.long _ex_soft_bp /* 0x01 - User Defined - Software breakpoint */
.long _ex_trap_c /* 0x02 - User Defined */
- .long _ex_trap_c /* 0x03 - User Defined - Atomic test and set service */
- .long _ex_spinlock /* 0x04 - User Defined */
+ .long _ex_trap_c /* 0x03 - User Defined - userspace stack overflow */
+ .long _ex_trap_c /* 0x04 - User Defined */
.long _ex_trap_c /* 0x05 - User Defined */
.long _ex_trap_c /* 0x06 - User Defined */
.long _ex_trap_c /* 0x07 - User Defined */
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index 8be548e061bf..203e20709163 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -34,6 +34,7 @@
#include <linux/linkage.h>
#include <asm/entry.h>
#include <asm/asm-offsets.h>
+#include <asm/trace.h>
#include <asm/mach-common/context.S>
@@ -170,10 +171,9 @@ ENTRY(_evt_ivhw)
r7.l = W[p5];
1:
#endif
- p0.l = lo(TBUFCTL);
- p0.h = hi(TBUFCTL);
- r0 = 1;
- [p0] = r0;
+
+ trace_buffer_stop(p0, r0);
+
r0 = IRQ_HWERR;
r1 = sp;
diff --git a/arch/blackfin/mach-common/ints-priority-dc.c b/arch/blackfin/mach-common/ints-priority-dc.c
index 80943bbd37c2..6b9fd03ce835 100644
--- a/arch/blackfin/mach-common/ints-priority-dc.c
+++ b/arch/blackfin/mach-common/ints-priority-dc.c
@@ -183,7 +183,7 @@ static void bf561_gpio_ack_irq(unsigned int irq)
{
u16 gpionr = irq - IRQ_PF0;
- if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+ if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
set_gpio_data(gpionr, 0);
SSYNC();
}
@@ -193,7 +193,7 @@ static void bf561_gpio_mask_ack_irq(unsigned int irq)
{
u16 gpionr = irq - IRQ_PF0;
- if(gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
+ if (gpio_edge_triggered[gpio_bank(gpionr)] & gpio_bit(gpionr)) {
set_gpio_data(gpionr, 0);
SSYNC();
}
@@ -222,7 +222,7 @@ static unsigned int bf561_gpio_irq_startup(unsigned int irq)
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
ret = gpio_request(gpionr, NULL);
- if(ret)
+ if (ret)
return ret;
}
@@ -262,7 +262,7 @@ static int bf561_gpio_irq_type(unsigned int irq, unsigned int type)
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
ret = gpio_request(gpionr, NULL);
- if(ret)
+ if (ret)
return ret;
}
@@ -371,6 +371,9 @@ int __init init_arch_irq(void)
bfin_write_SICA_IMASK1(SIC_UNMASK_ALL);
SSYNC();
+ bfin_write_SICA_IWR0(IWR_ENABLE_ALL);
+ bfin_write_SICA_IWR1(IWR_ENABLE_ALL);
+
local_irq_disable();
init_exception_buff();
@@ -393,7 +396,7 @@ int __init init_arch_irq(void)
bfin_write_EVT15(evt_system_call);
CSYNC();
- for (irq = 0; irq < SYS_IRQS; irq++) {
+ for (irq = 0; irq <= SYS_IRQS; irq++) {
if (irq <= IRQ_CORETMR)
set_irq_chip(irq, &bf561_core_irqchip);
else
diff --git a/arch/blackfin/mach-common/ints-priority-sc.c b/arch/blackfin/mach-common/ints-priority-sc.c
index 2cfc7d5aec5c..28a878c3577a 100644
--- a/arch/blackfin/mach-common/ints-priority-sc.c
+++ b/arch/blackfin/mach-common/ints-priority-sc.c
@@ -13,7 +13,7 @@
* 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
* 2003 Metrowerks/Motorola
* 2003 Bas Vermeulen <bas@buyways.nl>
- * Copyright 2004-2006 Analog Devices Inc.
+ * Copyright 2004-2007 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
@@ -65,9 +65,9 @@ atomic_t num_spurious;
struct ivgx {
/* irq number for request_irq, available in mach-bf533/irq.h */
- int irqno;
+ unsigned int irqno;
/* corresponding bit in the SIC_ISR register */
- int isrflag;
+ unsigned int isrflag;
} ivg_table[NR_PERI_INTS];
struct ivg_slice {
@@ -88,17 +88,16 @@ static void __init search_IAR(void)
for (ivg = 0; ivg <= IVG13 - IVG7; ivg++) {
int irqn;
- ivg7_13[ivg].istop = ivg7_13[ivg].ifirst =
- &ivg_table[irq_pos];
+ ivg7_13[ivg].istop = ivg7_13[ivg].ifirst = &ivg_table[irq_pos];
for (irqn = 0; irqn < NR_PERI_INTS; irqn++) {
int iar_shift = (irqn & 7) * 4;
if (ivg ==
(0xf &
- bfin_read32((unsigned long *) SIC_IAR0 +
+ bfin_read32((unsigned long *)SIC_IAR0 +
(irqn >> 3)) >> iar_shift)) {
ivg_table[irq_pos].irqno = IVG7 + irqn;
- ivg_table[irq_pos].isrflag = 1 << irqn;
+ ivg_table[irq_pos].isrflag = 1 << (irqn % 32);
ivg7_13[ivg].istop++;
irq_pos++;
}
@@ -141,15 +140,31 @@ static void bfin_core_unmask_irq(unsigned int irq)
static void bfin_internal_mask_irq(unsigned int irq)
{
+#ifndef CONFIG_BF54x
bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
~(1 << (irq - (IRQ_CORETMR + 1))));
+#else
+ unsigned mask_bank, mask_bit;
+ mask_bank = (irq - (IRQ_CORETMR + 1)) / 32;
+ mask_bit = (irq - (IRQ_CORETMR + 1)) % 32;
+ bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
+ ~(1 << mask_bit));
+#endif
SSYNC();
}
static void bfin_internal_unmask_irq(unsigned int irq)
{
+#ifndef CONFIG_BF54x
bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
(1 << (irq - (IRQ_CORETMR + 1))));
+#else
+ unsigned mask_bank, mask_bit;
+ mask_bank = (irq - (IRQ_CORETMR + 1)) / 32;
+ mask_bit = (irq - (IRQ_CORETMR + 1)) % 32;
+ bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) |
+ (1 << mask_bit));
+#endif
SSYNC();
}
@@ -206,7 +221,7 @@ static struct irq_chip bfin_generic_error_irqchip = {
};
static void bfin_demux_error_irq(unsigned int int_err_irq,
- struct irq_desc *intb_desc)
+ struct irq_desc *intb_desc)
{
int irq = 0;
@@ -270,8 +285,8 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
}
pr_debug("IRQ %d:"
- " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
- irq);
+ " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
+ irq);
}
} else
printk(KERN_ERR
@@ -279,11 +294,10 @@ static void bfin_demux_error_irq(unsigned int int_err_irq,
" INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
__FUNCTION__, __FILE__, __LINE__);
-
}
#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
-#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#if defined(CONFIG_IRQCHIP_DEMUX_GPIO) && !defined(CONFIG_BF54x)
static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
static unsigned short gpio_edge_triggered[gpio_bank(MAX_BLACKFIN_GPIOS)];
@@ -361,8 +375,7 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
}
if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
- IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
- {
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
ret = gpio_request(gpionr, NULL);
if (ret)
@@ -407,7 +420,6 @@ static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
return 0;
}
-
static struct irq_chip bfin_gpio_irqchip = {
.ack = bfin_gpio_ack_irq,
.mask = bfin_gpio_mask_irq,
@@ -419,20 +431,20 @@ static struct irq_chip bfin_gpio_irqchip = {
};
static void bfin_demux_gpio_irq(unsigned int intb_irq,
- struct irq_desc *intb_desc)
+ struct irq_desc *intb_desc)
{
u16 i;
+ struct irq_desc *desc;
- for (i = 0; i < MAX_BLACKFIN_GPIOS; i+=16) {
+ for (i = 0; i < MAX_BLACKFIN_GPIOS; i += 16) {
int irq = IRQ_PF0 + i;
int flag_d = get_gpiop_data(i);
int mask =
- flag_d & (gpio_enabled[gpio_bank(i)] &
- get_gpiop_maska(i));
+ flag_d & (gpio_enabled[gpio_bank(i)] & get_gpiop_maska(i));
while (mask) {
if (mask & 1) {
- struct irq_desc *desc = irq_desc + irq;
+ desc = irq_desc + irq;
desc->handle_irq(irq, desc);
}
irq++;
@@ -441,6 +453,264 @@ static void bfin_demux_gpio_irq(unsigned int intb_irq,
}
}
+#else /* CONFIG_IRQCHIP_DEMUX_GPIO */
+
+#define NR_PINT_SYS_IRQS 4
+#define NR_PINT_BITS 32
+#define NR_PINTS 160
+#define IRQ_NOT_AVAIL 0xFF
+
+#define PINT_2_BANK(x) ((x) >> 5)
+#define PINT_2_BIT(x) ((x) & 0x1F)
+#define PINT_BIT(x) (1 << (PINT_2_BIT(x)))
+
+static unsigned char irq2pint_lut[NR_PINTS];
+static unsigned char pint2irq_lut[NR_PINT_SYS_IRQS * NR_PINT_BITS];
+
+struct pin_int_t {
+ unsigned int mask_set;
+ unsigned int mask_clear;
+ unsigned int request;
+ unsigned int assign;
+ unsigned int edge_set;
+ unsigned int edge_clear;
+ unsigned int invert_set;
+ unsigned int invert_clear;
+ unsigned int pinstate;
+ unsigned int latch;
+};
+
+static struct pin_int_t *pint[NR_PINT_SYS_IRQS] = {
+ (struct pin_int_t *)PINT0_MASK_SET,
+ (struct pin_int_t *)PINT1_MASK_SET,
+ (struct pin_int_t *)PINT2_MASK_SET,
+ (struct pin_int_t *)PINT3_MASK_SET,
+};
+
+unsigned short get_irq_base(u8 bank, u8 bmap)
+{
+
+ u16 irq_base;
+
+ if (bank < 2) { /*PA-PB */
+ irq_base = IRQ_PA0 + bmap * 16;
+ } else { /*PC-PJ */
+ irq_base = IRQ_PC0 + bmap * 16;
+ }
+
+ return irq_base;
+
+}
+
+ /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
+void init_pint_lut(void)
+{
+ u16 bank, bit, irq_base, bit_pos;
+ u32 pint_assign;
+ u8 bmap;
+
+ memset(irq2pint_lut, IRQ_NOT_AVAIL, sizeof(irq2pint_lut));
+
+ for (bank = 0; bank < NR_PINT_SYS_IRQS; bank++) {
+
+ pint_assign = pint[bank]->assign;
+
+ for (bit = 0; bit < NR_PINT_BITS; bit++) {
+
+ bmap = (pint_assign >> ((bit / 8) * 8)) & 0xFF;
+
+ irq_base = get_irq_base(bank, bmap);
+
+ irq_base += (bit % 8) + ((bit / 8) & 1 ? 8 : 0);
+ bit_pos = bit + bank * NR_PINT_BITS;
+
+ pint2irq_lut[bit_pos] = irq_base - SYS_IRQS;
+ irq2pint_lut[irq_base - SYS_IRQS] = bit_pos;
+
+ }
+
+ }
+
+}
+
+static unsigned short gpio_enabled[gpio_bank(MAX_BLACKFIN_GPIOS)];
+
+static void bfin_gpio_ack_irq(unsigned int irq)
+{
+ u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+
+ pint[PINT_2_BANK(pint_val)]->request = PINT_BIT(pint_val);
+ SSYNC();
+}
+
+static void bfin_gpio_mask_ack_irq(unsigned int irq)
+{
+ u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 pintbit = PINT_BIT(pint_val);
+ u8 bank = PINT_2_BANK(pint_val);
+
+ pint[bank]->request = pintbit;
+ pint[bank]->mask_clear = pintbit;
+ SSYNC();
+}
+
+static void bfin_gpio_mask_irq(unsigned int irq)
+{
+ u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+
+ pint[PINT_2_BANK(pint_val)]->mask_clear = PINT_BIT(pint_val);
+ SSYNC();
+}
+
+static void bfin_gpio_unmask_irq(unsigned int irq)
+{
+ u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 pintbit = PINT_BIT(pint_val);
+ u8 bank = PINT_2_BANK(pint_val);
+
+ pint[bank]->request = pintbit;
+ pint[bank]->mask_set = pintbit;
+ SSYNC();
+}
+
+static unsigned int bfin_gpio_irq_startup(unsigned int irq)
+{
+ unsigned int ret;
+ u16 gpionr = irq - IRQ_PA0;
+ u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+
+ if (pint_val == IRQ_NOT_AVAIL)
+ return -ENODEV;
+
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+ ret = gpio_request(gpionr, NULL);
+ if (ret)
+ return ret;
+ }
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ bfin_gpio_unmask_irq(irq);
+
+ return ret;
+}
+
+static void bfin_gpio_irq_shutdown(unsigned int irq)
+{
+ bfin_gpio_mask_irq(irq);
+ gpio_free(irq - IRQ_PA0);
+ gpio_enabled[gpio_bank(irq - IRQ_PA0)] &= ~gpio_bit(irq - IRQ_PA0);
+}
+
+static int bfin_gpio_irq_type(unsigned int irq, unsigned int type)
+{
+
+ unsigned int ret;
+ u16 gpionr = irq - IRQ_PA0;
+ u8 pint_val = irq2pint_lut[irq - SYS_IRQS];
+ u32 pintbit = PINT_BIT(pint_val);
+ u8 bank = PINT_2_BANK(pint_val);
+
+ if (pint_val == IRQ_NOT_AVAIL)
+ return -ENODEV;
+
+ if (type == IRQ_TYPE_PROBE) {
+ /* only probe unenabled GPIO interrupt lines */
+ if (gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))
+ return 0;
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
+ IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+ if (!(gpio_enabled[gpio_bank(gpionr)] & gpio_bit(gpionr))) {
+ ret = gpio_request(gpionr, NULL);
+ if (ret)
+ return ret;
+ }
+
+ gpio_enabled[gpio_bank(gpionr)] |= gpio_bit(gpionr);
+ } else {
+ gpio_enabled[gpio_bank(gpionr)] &= ~gpio_bit(gpionr);
+ return 0;
+ }
+
+ gpio_direction_input(gpionr);
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+ pint[bank]->edge_set = pintbit;
+ } else {
+ pint[bank]->edge_clear = pintbit;
+ }
+
+ if ((type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW)))
+ pint[bank]->invert_set = pintbit; /* low or falling edge denoted by one */
+ else
+ pint[bank]->invert_set = pintbit; /* high or rising edge denoted by zero */
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ pint[bank]->invert_set = pintbit;
+ else
+ pint[bank]->invert_set = pintbit;
+
+ SSYNC();
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
+ set_irq_handler(irq, handle_edge_irq);
+ else
+ set_irq_handler(irq, handle_level_irq);
+
+ return 0;
+}
+
+static struct irq_chip bfin_gpio_irqchip = {
+ .ack = bfin_gpio_ack_irq,
+ .mask = bfin_gpio_mask_irq,
+ .mask_ack = bfin_gpio_mask_ack_irq,
+ .unmask = bfin_gpio_unmask_irq,
+ .set_type = bfin_gpio_irq_type,
+ .startup = bfin_gpio_irq_startup,
+ .shutdown = bfin_gpio_irq_shutdown
+};
+
+static void bfin_demux_gpio_irq(unsigned int intb_irq,
+ struct irq_desc *intb_desc)
+{
+ u8 bank, pint_val;
+ u32 request, irq;
+ struct irq_desc *desc;
+
+ switch (intb_irq) {
+ case IRQ_PINT0:
+ bank = 0;
+ break;
+ case IRQ_PINT2:
+ bank = 2;
+ break;
+ case IRQ_PINT3:
+ bank = 3;
+ break;
+ case IRQ_PINT1:
+ bank = 1;
+ break;
+ default:
+ return;
+ }
+
+ pint_val = bank * NR_PINT_BITS;
+
+ request = pint[bank]->request;
+
+ while (request) {
+ if (request & 1) {
+ irq = pint2irq_lut[pint_val] + SYS_IRQS;
+ desc = irq_desc + irq;
+ desc->handle_irq(irq, desc);
+ }
+ pint_val++;
+ request >>= 1;
+ }
+
+}
#endif /* CONFIG_IRQCHIP_DEMUX_GPIO */
/*
@@ -452,7 +722,18 @@ int __init init_arch_irq(void)
int irq;
unsigned long ilat = 0;
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
+#ifdef CONFIG_BF54x
+ bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
+ bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
+ bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
+ bfin_write_SIC_IWR0(IWR_ENABLE_ALL);
+ bfin_write_SIC_IWR1(IWR_ENABLE_ALL);
+ bfin_write_SIC_IWR2(IWR_ENABLE_ALL);
+#else
bfin_write_SIC_IMASK(SIC_UNMASK_ALL);
+ bfin_write_SIC_IWR(IWR_ENABLE_ALL);
+#endif
+
SSYNC();
local_irq_disable();
@@ -475,7 +756,18 @@ int __init init_arch_irq(void)
bfin_write_EVT15(evt_system_call);
CSYNC();
- for (irq = 0; irq < SYS_IRQS; irq++) {
+#if defined(CONFIG_IRQCHIP_DEMUX_GPIO) && defined(CONFIG_BF54x)
+#ifdef CONFIG_PINTx_REASSIGN
+ pint[0]->assign = CONFIG_PINT0_ASSIGN;
+ pint[1]->assign = CONFIG_PINT1_ASSIGN;
+ pint[2]->assign = CONFIG_PINT2_ASSIGN;
+ pint[3]->assign = CONFIG_PINT3_ASSIGN;
+#endif
+ /* Whenever PINTx_ASSIGN is altered init_pint_lut() must be executed! */
+ init_pint_lut();
+#endif
+
+ for (irq = 0; irq <= SYS_IRQS; irq++) {
if (irq <= IRQ_CORETMR)
set_irq_chip(irq, &bfin_core_irqchip);
else
@@ -484,20 +776,42 @@ int __init init_arch_irq(void)
if (irq != IRQ_GENERIC_ERROR) {
#endif
+ switch (irq) {
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
- if ((irq != IRQ_PROG_INTA) /*PORT F & G MASK_A Interrupt*/
-# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
- && (irq != IRQ_MAC_RX) /*PORT H MASK_A Interrupt*/
-# endif
- ) {
+#ifndef CONFIG_BF54x
+ case IRQ_PROG_INTA:
+ set_irq_chained_handler(irq,
+ bfin_demux_gpio_irq);
+ break;
+#if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
+ case IRQ_MAC_RX:
+ set_irq_chained_handler(irq,
+ bfin_demux_gpio_irq);
+ break;
#endif
- set_irq_handler(irq, handle_simple_irq);
-#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
- } else {
+#else
+ case IRQ_PINT0:
set_irq_chained_handler(irq,
bfin_demux_gpio_irq);
- }
+ break;
+ case IRQ_PINT1:
+ set_irq_chained_handler(irq,
+ bfin_demux_gpio_irq);
+ break;
+ case IRQ_PINT2:
+ set_irq_chained_handler(irq,
+ bfin_demux_gpio_irq);
+ break;
+ case IRQ_PINT3:
+ set_irq_chained_handler(irq,
+ bfin_demux_gpio_irq);
+ break;
+#endif /*CONFIG_BF54x */
#endif
+ default:
+ set_irq_handler(irq, handle_simple_irq);
+ break;
+ }
#ifdef BF537_GENERIC_ERROR_INT_DEMUX
} else {
@@ -513,7 +827,11 @@ int __init init_arch_irq(void)
#endif
#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#ifndef CONFIG_BF54x
for (irq = IRQ_PF0; irq < NR_IRQS; irq++) {
+#else
+ for (irq = IRQ_PA0; irq < NR_IRQS; irq++) {
+#endif
set_irq_chip(irq, &bfin_gpio_irqchip);
/* if configured as edge, then will be changed to do_edge_IRQ */
set_irq_handler(irq, handle_level_irq);
@@ -526,8 +844,7 @@ int __init init_arch_irq(void)
bfin_write_ILAT(ilat);
CSYNC();
- printk(KERN_INFO
- "Configuring Blackfin Priority Driven Interrupts\n");
+ printk(KERN_INFO "Configuring Blackfin Priority Driven Interrupts\n");
/* IMASK=xxx is equivalent to STI xx or irq_flags=xx,
* local_irq_enable()
*/
@@ -538,14 +855,13 @@ int __init init_arch_irq(void)
/* Enable interrupts IVG7-15 */
irq_flags = irq_flags | IMASK_IVG15 |
IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 |
- IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 |
- IMASK_IVGHW;
+ IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW;
return 0;
}
#ifdef CONFIG_DO_IRQ_L1
-void do_irq(int vec, struct pt_regs *fp)__attribute__((l1_text));
+void do_irq(int vec, struct pt_regs *fp) __attribute__((l1_text));
#endif
void do_irq(int vec, struct pt_regs *fp)
@@ -555,9 +871,25 @@ void do_irq(int vec, struct pt_regs *fp)
} else {
struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
- unsigned long sic_status;
+#ifdef CONFIG_BF54x
+ unsigned long sic_status[3];
SSYNC();
+ sic_status[0] = bfin_read_SIC_ISR(0) & bfin_read_SIC_IMASK(0);
+ sic_status[1] = bfin_read_SIC_ISR(1) & bfin_read_SIC_IMASK(1);
+ sic_status[2] = bfin_read_SIC_ISR(2) & bfin_read_SIC_IMASK(2);
+
+ for (;; ivg++) {
+ if (ivg >= ivg_stop) {
+ atomic_inc(&num_spurious);
+ return;
+ }
+ if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
+ break;
+ }
+#else
+ unsigned long sic_status;
+ SSYNC();
sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
for (;; ivg++) {
@@ -567,6 +899,7 @@ void do_irq(int vec, struct pt_regs *fp)
} else if (sic_status & ivg->isrflag)
break;
}
+#endif
vec = ivg->irqno;
}
asm_do_IRQ(vec, fp);
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
index 150ef5d088dc..1772d8d2c1a7 100644
--- a/arch/blackfin/mach-common/pm.c
+++ b/arch/blackfin/mach-common/pm.c
@@ -35,10 +35,10 @@
#include <linux/pm.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
+#include <linux/io.h>
+#include <linux/irq.h>
-#include <asm/io.h>
#include <asm/dpmc.h>
-#include <asm/irq.h>
#include <asm/gpio.h>
#ifdef CONFIG_PM_WAKEUP_GPIO_POLAR_H
diff --git a/arch/blackfin/mm/blackfin_sram.c b/arch/blackfin/mm/blackfin_sram.c
index 68107924639e..b99ea883cd22 100644
--- a/arch/blackfin/mm/blackfin_sram.c
+++ b/arch/blackfin/mm/blackfin_sram.c
@@ -87,7 +87,7 @@ void __init l1sram_init(void)
L1_SCRATCH_LENGTH >> 10);
memset(&l1_ssram, 0x00, sizeof(l1_ssram));
- l1_ssram[0].paddr = (void*)L1_SCRATCH_START;
+ l1_ssram[0].paddr = (void *)L1_SCRATCH_START;
l1_ssram[0].size = L1_SCRATCH_LENGTH;
l1_ssram[0].flag = SRAM_SLT_FREE;
@@ -126,7 +126,7 @@ void __init l1_inst_sram_init(void)
{
#if L1_CODE_LENGTH != 0
memset(&l1_inst_sram, 0x00, sizeof(l1_inst_sram));
- l1_inst_sram[0].paddr = (void*)L1_CODE_START + (_etext_l1 - _stext_l1);
+ l1_inst_sram[0].paddr = (void *)L1_CODE_START + (_etext_l1 - _stext_l1);
l1_inst_sram[0].size = L1_CODE_LENGTH - (_etext_l1 - _stext_l1);
l1_inst_sram[0].flag = SRAM_SLT_FREE;
@@ -521,10 +521,9 @@ void *sram_alloc_with_lsl(size_t size, unsigned long flags)
struct sram_list_struct *lsl = NULL;
struct mm_struct *mm = current->mm;
- lsl = kmalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
+ lsl = kzalloc(sizeof(struct sram_list_struct), GFP_KERNEL);
if (!lsl)
return NULL;
- memset(lsl, 0, sizeof(*lsl));
if (flags & L1_INST_SRAM)
addr = l1_inst_sram_alloc(size);
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index 570356dbe028..68459cc052a1 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -29,8 +29,8 @@
#include <linux/swap.h>
#include <linux/bootmem.h>
+#include <linux/uaccess.h>
#include <asm/bfin-global.h>
-#include <asm/uaccess.h>
#include <asm/l1layout.h>
#include "blackfin_sram.h"
@@ -168,42 +168,31 @@ void __init mem_init(void)
}
}
-#ifdef CONFIG_BLK_DEV_INITRD
-void __init free_initrd_mem(unsigned long start, unsigned long end)
+static __init void free_init_pages(const char *what, unsigned long begin, unsigned long end)
{
- int pages = 0;
- for (; start < end; start += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
+ unsigned long addr;
+ /* next to check that the page we free is not a partial page */
+ for (addr = begin; addr + PAGE_SIZE <= end; addr += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(addr));
+ init_page_count(virt_to_page(addr));
+ free_page(addr);
totalram_pages++;
- pages++;
}
- printk(KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
+ printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init free_initrd_mem(unsigned long start, unsigned long end)
+{
+ free_init_pages("initrd memory", start, end);
}
#endif
void __init free_initmem(void)
{
#ifdef CONFIG_RAMKERNEL
- unsigned long addr;
- /*
- * the following code should be cool even if these sections
- * are not page aligned.
- */
- addr = PAGE_ALIGN((unsigned long)(__init_begin));
- /* next to check that the page we free is not a partial page */
- for (; addr + PAGE_SIZE < (unsigned long)(__init_end);
- addr += PAGE_SIZE) {
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk(KERN_NOTICE
- "Freeing unused kernel memory: %ldk freed (0x%x - 0x%x)\n",
- (addr - PAGE_ALIGN((long)__init_begin)) >> 10,
- (int)(PAGE_ALIGN((unsigned long)(__init_begin))),
- (int)(addr - PAGE_SIZE));
+ free_init_pages("unused kernel memory",
+ (unsigned long)(&__init_begin),
+ (unsigned long)(&__init_end));
#endif
}
diff --git a/arch/blackfin/oprofile/common.c b/arch/blackfin/oprofile/common.c
index 009a1700c854..cb8b8d5af34f 100644
--- a/arch/blackfin/oprofile/common.c
+++ b/arch/blackfin/oprofile/common.c
@@ -33,12 +33,12 @@
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/mutex.h>
+#include <linux/ptrace.h>
+#include <linux/irq.h>
+#include <linux/io.h>
-#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/blackfin.h>
-#include <asm/irq.h>
-#include <asm/io.h>
#include "op_blackfin.h"
diff --git a/arch/blackfin/oprofile/op_model_bf533.c b/arch/blackfin/oprofile/op_model_bf533.c
index b7a20a006b49..872dffe33623 100644
--- a/arch/blackfin/oprofile/op_model_bf533.c
+++ b/arch/blackfin/oprofile/op_model_bf533.c
@@ -32,12 +32,12 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
-#include <asm/ptrace.h>
+#include <linux/ptrace.h>
+#include <linux/irq.h>
+#include <linux/io.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/blackfin.h>
-#include <asm/irq.h>
-#include <asm/io.h>
#include "op_blackfin.h"
diff --git a/arch/blackfin/oprofile/timer_int.c b/arch/blackfin/oprofile/timer_int.c
index 8fba16c846c9..6c6f8606af4c 100644
--- a/arch/blackfin/oprofile/timer_int.c
+++ b/arch/blackfin/oprofile/timer_int.c
@@ -31,8 +31,7 @@
#include <linux/smp.h>
#include <linux/irq.h>
#include <linux/oprofile.h>
-
-#include <asm/ptrace.h>
+#include <linux/ptrace.h>
static void enable_sys_timer0()
{
diff --git a/arch/cris/arch-v10/defconfig b/arch/cris/arch-v10/defconfig
index 2a3411eaace9..710c20ba2be7 100644
--- a/arch/cris/arch-v10/defconfig
+++ b/arch/cris/arch-v10/defconfig
@@ -429,7 +429,6 @@ CONFIG_NET_ETHERNET=y
# CONFIG_BFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c
index d47cfbf98d6e..1de0026bb94e 100644
--- a/arch/cris/arch-v10/drivers/pcf8563.c
+++ b/arch/cris/arch-v10/drivers/pcf8563.c
@@ -180,9 +180,7 @@ err:
void __exit
pcf8563_exit(void)
{
- if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
- printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME);
- }
+ unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME);
}
/*
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c
index fd2129a04586..f4f9db698b44 100644
--- a/arch/cris/arch-v10/kernel/ptrace.c
+++ b/arch/cris/arch-v10/kernel/ptrace.c
@@ -83,19 +83,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* Read word at location address. */
case PTRACE_PEEKTEXT:
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
-
- if (copied != sizeof(tmp))
- break;
-
- ret = put_user(tmp,datap);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* Read the word at location address in the USER area. */
case PTRACE_PEEKUSR: {
@@ -113,12 +103,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Write the word at location address. */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = 0;
-
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
-
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
/* Write the word at location address in the USER area. */
diff --git a/arch/cris/arch-v10/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S
index 4b348b38cf33..9859d49d088b 100644
--- a/arch/cris/arch-v10/vmlinux.lds.S
+++ b/arch/cris/arch-v10/vmlinux.lds.S
@@ -44,7 +44,7 @@ SECTIONS
___data_start = . ;
__Sdata = . ;
.data : { /* Data */
- *(.data)
+ DATA_DATA
}
__edata = . ; /* End of data section */
_edata = . ;
diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c
index 1a071f17446d..e8914d401696 100644
--- a/arch/cris/arch-v32/drivers/cryptocop.c
+++ b/arch/cris/arch-v32/drivers/cryptocop.c
@@ -267,10 +267,10 @@ static void print_user_dma_lists(struct cryptocop_dma_list_operation *dma_op);
const struct file_operations cryptocop_fops = {
- owner: THIS_MODULE,
- open: cryptocop_open,
- release: cryptocop_release,
- ioctl: cryptocop_ioctl
+ .owner = THIS_MODULE,
+ .open = cryptocop_open,
+ .release = cryptocop_release,
+ .ioctl = cryptocop_ioctl
};
diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c
index 5d6c52737df3..e12f6cc6f4a2 100644
--- a/arch/cris/arch-v32/drivers/i2c.c
+++ b/arch/cris/arch-v32/drivers/i2c.c
@@ -574,10 +574,10 @@ i2c_ioctl(struct inode *inode, struct file *file,
}
static const struct file_operations i2c_fops = {
- owner: THIS_MODULE,
- ioctl: i2c_ioctl,
- open: i2c_open,
- release: i2c_release,
+ .owner = THIS_MODULE,
+ .ioctl = i2c_ioctl,
+ .open = i2c_open,
+ .release = i2c_release,
};
int __init
diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c
index 24b919b3821a..da479a14f836 100644
--- a/arch/cris/arch-v32/drivers/pcf8563.c
+++ b/arch/cris/arch-v32/drivers/pcf8563.c
@@ -51,10 +51,10 @@ int pcf8563_open(struct inode *, struct file *);
int pcf8563_release(struct inode *, struct file *);
static const struct file_operations pcf8563_fops = {
- owner: THIS_MODULE,
- ioctl: pcf8563_ioctl,
- open: pcf8563_open,
- release: pcf8563_release,
+ .owner = THIS_MODULE,
+ .ioctl = pcf8563_ioctl,
+ .open = pcf8563_open,
+ .release = pcf8563_release,
};
unsigned char
@@ -193,9 +193,7 @@ err:
void __exit
pcf8563_exit(void)
{
- if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) {
- printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME);
- }
+ unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME);
}
/*
diff --git a/arch/cris/arch-v32/drivers/pci/dma.c b/arch/cris/arch-v32/drivers/pci/dma.c
index 832fc63504d4..66f9500fbc02 100644
--- a/arch/cris/arch-v32/drivers/pci/dma.c
+++ b/arch/cris/arch-v32/drivers/pci/dma.c
@@ -91,14 +91,12 @@ int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
if (!mem_base)
goto out;
- dev->dma_mem = kmalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
+ dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
if (!dev->dma_mem)
goto out;
- memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
- dev->dma_mem->bitmap = kmalloc(bitmap_size, GFP_KERNEL);
+ dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
if (!dev->dma_mem->bitmap)
goto free1_out;
- memset(dev->dma_mem->bitmap, 0, bitmap_size);
dev->dma_mem->virt_base = mem_base;
dev->dma_mem->device_base = device_addr;
diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c
index d4d57b741334..38ece0cd47cb 100644
--- a/arch/cris/arch-v32/kernel/ptrace.c
+++ b/arch/cris/arch-v32/kernel/ptrace.c
@@ -146,12 +146,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* Write the word at location address. */
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = 0;
-
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
-
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
/* Write the word at location address in the USER area. */
diff --git a/arch/cris/arch-v32/vmlinux.lds.S b/arch/cris/arch-v32/vmlinux.lds.S
index dfa25e1542b9..b076c134c0bb 100644
--- a/arch/cris/arch-v32/vmlinux.lds.S
+++ b/arch/cris/arch-v32/vmlinux.lds.S
@@ -49,7 +49,7 @@ SECTIONS
___data_start = . ;
__Sdata = . ;
.data : { /* Data */
- *(.data)
+ DATA_DATA
}
__edata = . ; /* End of data section. */
_edata = . ;
@@ -91,10 +91,7 @@ SECTIONS
}
SECURITY_INIT
- . = ALIGN (8192);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(8192)
#ifdef CONFIG_BLK_DEV_INITRD
.init.ramfs : {
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c
index c73e91f1299a..8672ab7d7978 100644
--- a/arch/cris/mm/fault.c
+++ b/arch/cris/mm/fault.c
@@ -179,6 +179,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
struct mm_struct *mm;
struct vm_area_struct * vma;
siginfo_t info;
+ int fault;
D(printk("Page fault for %lX on %X at %lX, prot %d write %d\n",
address, smp_processor_id(), instruction_pointer(regs),
@@ -283,18 +284,18 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
* the fault.
*/
- switch (handle_mm_fault(mm, vma, address, writeaccess & 1)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- default:
- goto out_of_memory;
+ fault = handle_mm_fault(mm, vma, address, writeaccess & 1);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
up_read(&mm->mmap_sem);
return;
diff --git a/arch/frv/Makefile b/arch/frv/Makefile
index 038e3a8457e0..9bf7345c5cc9 100644
--- a/arch/frv/Makefile
+++ b/arch/frv/Makefile
@@ -88,7 +88,7 @@ ASFLAGS += -mno-fdpic
# make sure the .S files get compiled with debug info
# and disable optimisations that are unhelpful whilst debugging
ifdef CONFIG_DEBUG_INFO
-CFLAGS += -O1
+#CFLAGS += -O1
AFLAGS += -Wa,--gdwarf2
ASFLAGS += -Wa,--gdwarf2
endif
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 43dc08ec7511..275673c192aa 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -1492,6 +1492,10 @@ sys_call_table:
.long sys_move_pages
.long sys_getcpu
.long sys_epoll_pwait
+ .long sys_utimensat /* 320 */
+ .long sys_signalfd
+ .long sys_timerfd
+ .long sys_eventfd
syscall_table_size = (. - sys_call_table)
diff --git a/arch/frv/kernel/gdb-stub.c b/arch/frv/kernel/gdb-stub.c
index 1e7a101cbf4c..e89cad1192a9 100644
--- a/arch/frv/kernel/gdb-stub.c
+++ b/arch/frv/kernel/gdb-stub.c
@@ -647,17 +647,11 @@ void debug_to_serial(const char *p, int n)
}
#endif
-#ifdef CONFIG_GDBSTUB_CONSOLE
-
-static kdev_t gdbstub_console_dev(struct console *con)
-{
- return MKDEV(1,3); /* /dev/null */
-}
+#ifdef CONFIG_GDB_CONSOLE
static struct console gdbstub_console = {
.name = "gdb",
.write = gdbstub_console_write, /* in break.S */
- .device = gdbstub_console_dev,
.flags = CON_PRINTBUFFER,
.index = -1,
};
@@ -2021,7 +2015,7 @@ void __init gdbstub_init(void)
ptr = mem2hex(gdbstub_banner, ptr, sizeof(gdbstub_banner) - 1, 0);
gdbstub_send_packet(output_buffer);
#endif
-#if defined(CONFIG_GDBSTUB_CONSOLE) && defined(CONFIG_GDBSTUB_IMMEDIATE)
+#if defined(CONFIG_GDB_CONSOLE) && defined(CONFIG_GDBSTUB_IMMEDIATE)
register_console(&gdbstub_console);
#endif
@@ -2031,7 +2025,7 @@ void __init gdbstub_init(void)
/*
* register the console at a more appropriate time
*/
-#if defined (CONFIG_GDBSTUB_CONSOLE) && !defined(CONFIG_GDBSTUB_IMMEDIATE)
+#if defined (CONFIG_GDB_CONSOLE) && !defined(CONFIG_GDBSTUB_IMMEDIATE)
static int __init gdbstub_postinit(void)
{
printk("registering console\n");
diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c
index ce88fb95ee59..709e9bdc6126 100644
--- a/arch/frv/kernel/ptrace.c
+++ b/arch/frv/kernel/ptrace.c
@@ -112,20 +112,12 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- int copied;
-
+ case PTRACE_PEEKDATA:
ret = -EIO;
if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
break;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (copied != sizeof(tmp))
- break;
-
- ret = put_user(tmp,(unsigned long *) data);
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -176,9 +168,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = -EIO;
if (is_user_addr_valid(child, addr, sizeof(tmp)) < 0)
break;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data))
- break;
- ret = 0;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index aa3c795d5354..a74c08786b21 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -29,6 +29,7 @@
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
#include <asm/setup.h>
#include <asm/irq.h>
@@ -60,10 +61,6 @@ static void __init setup_linux_memory(void);
static void __init setup_uclinux_memory(void);
#endif
-#ifdef CONFIG_CONSOLE
-extern struct consw *conswitchp;
-#endif
-
#ifdef CONFIG_MB93090_MB00
static char __initdata mb93090_banner[] = "FJ/RH FR-V Linux";
static char __initdata mb93090_version[] = UTS_RELEASE;
@@ -795,13 +792,6 @@ void __init setup_arch(char **cmdline_p)
#endif
#endif
-#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
- /* we need to initialize the Flashrom device here since we might
- * do things with flash early on in the boot
- */
- flash_probe();
-#endif
-
/* deal with the command line - RedBoot may have passed one to the kernel */
memcpy(command_line, boot_command_line, sizeof(command_line));
*cmdline_p = &command_line[0];
@@ -837,11 +827,6 @@ void __init setup_arch(char **cmdline_p)
#endif
#endif
-#ifdef CONFIG_BLK_DEV_BLKMEM
- ROOT_DEV = MKDEV(BLKMEM_MAJOR,0);
-#endif
- /*rom_length = (unsigned long)&_flashend - (unsigned long)&_romvec;*/
-
#ifdef CONFIG_MMU
setup_linux_memory();
#else
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index 481dc1374640..3b71e0c86399 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -57,10 +57,7 @@ SECTIONS
__alt_instructions_end = .;
.altinstr_replacement : { *(.altinstr_replacement) }
- . = ALIGN(4096);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(4096)
#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(4096);
diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c
index 3f12296c3688..6798fa0257b1 100644
--- a/arch/frv/mm/fault.c
+++ b/arch/frv/mm/fault.c
@@ -40,6 +40,7 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
pud_t *pue;
pte_t *pte;
int write;
+ int fault;
#if 0
const char *atxc[16] = {
@@ -162,18 +163,18 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- switch (handle_mm_fault(mm, vma, ear0, write)) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- default:
- goto out_of_memory;
+ fault = handle_mm_fault(mm, vma, ear0, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
return;
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 618dbad696f6..e35f74e6e505 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -68,6 +68,9 @@ config TIME_LOW_RES
config NO_IOPORT
def_bool y
+config NO_DMA
+ def_bool y
+
config ISA
bool
default y
diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile
index b2d896a7e598..53b5c1edf596 100644
--- a/arch/h8300/Makefile
+++ b/arch/h8300/Makefile
@@ -61,10 +61,11 @@ archmrproper:
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
-vmlinux.srec vmlinux.bin: vmlinux
+vmlinux.srec vmlinux.bin zImage: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
define archhelp
- echo 'vmlinux.bin - Create raw binary'
- echo 'vmlinux.srec - Create srec binary'
+ @echo 'vmlinux.bin - Create raw binary'
+ @echo 'vmlinux.srec - Create srec binary'
+ @echo 'zImage - Compressed kernel image'
endef
diff --git a/arch/h8300/boot/compressed/Makefile b/arch/h8300/boot/compressed/Makefile
index 71aac82a8ae0..d6189e057ed3 100644
--- a/arch/h8300/boot/compressed/Makefile
+++ b/arch/h8300/boot/compressed/Makefile
@@ -15,10 +15,10 @@ OBJECTS = $(obj)/head.o $(obj)/misc.o
# in order to suppress error message.
#
CONFIG_MEMORY_START ?= 0x00400000
-CONFIG_BOOT_LINK_OFFSET ?= 0x00400000
+CONFIG_BOOT_LINK_OFFSET ?= 0x00140000
IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
-LDFLAGS_vmlinux := -T $(obj)/vmlinux.lds
+LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -estartup $(obj)/vmlinux.lds
$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
$(call if_changed,ld)
diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S
index b8e90d12d19e..985a81a2435a 100644
--- a/arch/h8300/boot/compressed/head.S
+++ b/arch/h8300/boot/compressed/head.S
@@ -4,7 +4,7 @@
* Copyright (C) 2006 Yoshinori Sato
*/
-.h8300h
+ .h8300h
#include <linux/linkage.h>
#define SRAM_START 0xff4000
diff --git a/arch/h8300/boot/compressed/vmlinux.lds b/arch/h8300/boot/compressed/vmlinux.lds
new file mode 100644
index 000000000000..65e2a0d1ae39
--- /dev/null
+++ b/arch/h8300/boot/compressed/vmlinux.lds
@@ -0,0 +1,32 @@
+SECTIONS
+{
+ .text :
+ {
+ __stext = . ;
+ __text = .;
+ *(.text.startup)
+ *(.text)
+ __etext = . ;
+ }
+
+ .rodata :
+ {
+ *(.rodata)
+ }
+ .data :
+
+ {
+ __sdata = . ;
+ ___data_start = . ;
+ *(.data.*)
+ }
+ .bss :
+ {
+ . = ALIGN(0x4) ;
+ __sbss = . ;
+ *(.bss*)
+ . = ALIGN(0x4) ;
+ __ebss = . ;
+ __end = . ;
+ }
+}
diff --git a/arch/h8300/boot/compressed/vmlinux.scr b/arch/h8300/boot/compressed/vmlinux.scr
new file mode 100644
index 000000000000..a0f6962736e9
--- /dev/null
+++ b/arch/h8300/boot/compressed/vmlinux.scr
@@ -0,0 +1,9 @@
+SECTIONS
+{
+ .data : {
+ _input_len = .;
+ LONG(_input_data_end - _input_data) _input_data = .;
+ *(.data)
+ _input_data_end = .;
+ }
+}
diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile
index ccc1a7fbf94b..874f6aefee65 100644
--- a/arch/h8300/kernel/Makefile
+++ b/arch/h8300/kernel/Makefile
@@ -6,6 +6,7 @@ extra-y := vmlinux.lds
obj-y := process.o traps.o ptrace.o irq.o \
sys_h8300.o time.o semaphore.o signal.o \
- setup.o gpio.o init_task.o syscalls.o
+ setup.o gpio.o init_task.o syscalls.o \
+ entry.o
obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o
diff --git a/arch/h8300/platform/h8s/entry.S b/arch/h8300/kernel/entry.S
index f3d6b8e8f959..ca7431690300 100644
--- a/arch/h8300/platform/h8s/entry.S
+++ b/arch/h8300/kernel/entry.S
@@ -1,11 +1,10 @@
/* -*- mode: asm -*-
*
- * linux/arch/h8300/platform/h8s/entry.S
+ * linux/arch/h8300/platform/h8300h/entry.S
*
* Yoshinori Sato <ysato@users.sourceforge.jp>
+ * David McCullough <davidm@snapgear.com>
*
- * fairly heavy changes to fix syscall args and signal processing
- * by David McCullough <davidm@snapgear.com>
*/
/*
@@ -23,13 +22,66 @@
#include <asm/thread_info.h>
#include <asm/errno.h>
+#if defined(CONFIG_CPU_H8300H)
+#define USERRET 8
+INTERRUPTS = 64
+ .h8300h
+ .macro SHLL2 reg
+ shll.l \reg
+ shll.l \reg
+ .endm
+ .macro SHLR2 reg
+ shlr.l \reg
+ shlr.l \reg
+ .endm
+ .macro SAVEREGS
+ mov.l er0,@-sp
+ mov.l er1,@-sp
+ mov.l er2,@-sp
+ mov.l er3,@-sp
+ .endm
+ .macro RESTOREREGS
+ mov.l @sp+,er3
+ mov.l @sp+,er2
+ .endm
+ .macro SAVEEXR
+ .endm
+ .macro RESTOREEXR
+ .endm
+#endif
+#if defined(CONFIG_CPU_H8S)
+#define USERRET 10
+#define USEREXR 8
+INTERRUPTS = 128
.h8300s
+ .macro SHLL2 reg
+ shll.l #2,\reg
+ .endm
+ .macro SHLR2 reg
+ shlr.l #2,\reg
+ .endm
+ .macro SAVEREGS
+ stm.l er0-er3,@-sp
+ .endm
+ .macro RESTOREREGS
+ ldm.l @sp+,er2-er3
+ .endm
+ .macro SAVEEXR
+ mov.w @(USEREXR:16,er0),r1
+ mov.w r1,@(LEXR-LER3:16,sp) /* copy EXR */
+ .endm
+ .macro RESTOREEXR
+ mov.w @(LEXR-LER1:16,sp),r1 /* restore EXR */
+ mov.b r1l,r1h
+ mov.w r1,@(USEREXR:16,er0)
+ .endm
+#endif
+
/* CPU context save/restore macros. */
-
+
.macro SAVE_ALL
mov.l er0,@-sp
-
stc ccr,r0l /* check kernel mode */
btst #4,r0l
bne 5f
@@ -39,42 +91,38 @@
mov.l @sp,er0 /* restore saved er0 */
orc #0x10,ccr /* switch kernel stack */
mov.l @SYMBOL_NAME(sw_ksp),sp
- sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
- stm.l er0-er3,@-sp
- mov.l @SYMBOL_NAME(sw_usp),er0
- mov.l @(10:16,er0),er1 /* copy the RET addr */
- mov.l er1,@(LRET-LER3:16,sp)
- mov.w @(8:16,er0),r1
- mov.w r1,@(LEXR-LER3:16,sp) /* copy EXR */
+ sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
+ SAVEREGS
+ mov.l @SYMBOL_NAME(sw_usp),er0
+ mov.l @(USERRET:16,er0),er1 /* copy the RET addr */
+ mov.l er1,@(LRET-LER3:16,sp)
+ SAVEEXR
- mov.w e1,r1 /* e1 highbyte = ccr */
- and #0xef,r1h /* mask mode? flag */
- sub.w r0,r0
- mov.b r1h,r0l
- mov.w r0,@(LCCR-LER3:16,sp) /* copy ccr */
mov.l @(LORIG-LER3:16,sp),er0
mov.l er0,@(LER0-LER3:16,sp) /* copy ER0 */
+ mov.w e1,r1 /* e1 highbyte = ccr */
+ and #0xef,r1h /* mask mode? flag */
bra 6f
5:
/* kernel mode */
mov.l @sp,er0 /* restore saved er0 */
subs #2,sp /* set dummy ccr */
- stm.l er0-er3,@-sp
+ SAVEREGS
mov.w @(LRET-LER3:16,sp),r1 /* copy old ccr */
+6:
mov.b r1h,r1l
mov.b #0,r1h
- mov.w r1,@(LCCR-LER3:16,sp)
-6:
+ mov.w r1,@(LCCR-LER3:16,sp) /* set ccr */
mov.l er6,@-sp /* syscall arg #6 */
mov.l er5,@-sp /* syscall arg #5 */
mov.l er4,@-sp /* syscall arg #4 */
- .endm
+ .endm /* r1 = ccr */
.macro RESTORE_ALL
mov.l @sp+,er4
mov.l @sp+,er5
mov.l @sp+,er6
- ldm.l @sp+,er2-er3
+ RESTOREREGS
mov.w @(LCCR-LER1:16,sp),r0 /* check kernel mode */
btst #4,r0l
bne 7f
@@ -83,18 +131,16 @@
mov.l @SYMBOL_NAME(sw_usp),er0
mov.l @(LER0-LER1:16,sp),er1 /* restore ER0 */
mov.l er1,@er0
- mov.w @(LEXR-LER1:16,sp),r1 /* restore EXR */
- mov.b r1l,r1h
- mov.w r1,@(8:16,er0)
+ RESTOREEXR
mov.w @(LCCR-LER1:16,sp),r1 /* restore the RET addr */
mov.b r1l,r1h
mov.b @(LRET+1-LER1:16,sp),r1l
mov.w r1,e1
mov.w @(LRET+2-LER1:16,sp),r1
- mov.l er1,@(10:16,er0)
+ mov.l er1,@(USERRET:16,er0)
mov.l @sp+,er1
- add.l #(LRET-LER1),sp /* remove LORIG - LRET */
+ add.l #(LRET-LER1),sp /* remove LORIG - LRET */
mov.l sp,@SYMBOL_NAME(sw_ksp)
andc #0xef,ccr /* switch to user mode */
mov.l er0,sp
@@ -108,7 +154,7 @@
adds #4,sp /* remove the sw created LVEC */
rte
.endm
-
+
.globl SYMBOL_NAME(system_call)
.globl SYMBOL_NAME(ret_from_exception)
.globl SYMBOL_NAME(ret_from_fork)
@@ -116,16 +162,25 @@
.globl SYMBOL_NAME(interrupt_redirect_table)
.globl SYMBOL_NAME(sw_ksp),SYMBOL_NAME(sw_usp)
.globl SYMBOL_NAME(resume)
-.globl SYMBOL_NAME(trace_break)
.globl SYMBOL_NAME(interrupt_entry)
-
-INTERRUPTS = 128
+.globl SYMBOL_NAME(trace_break)
+
#if defined(CONFIG_ROMKERNEL)
.section .int_redirect,"ax"
SYMBOL_NAME_LABEL(interrupt_redirect_table)
+#if defined(CONFIG_CPU_H8300H)
.rept 7
.long 0
.endr
+#endif
+#if defined(CONFIG_CPU_H8S)
+ .rept 5
+ .long 0
+ .endr
+ jmp @SYMBOL_NAME(trace_break)
+ .long 0
+#endif
+
jsr @SYMBOL_NAME(interrupt_entry) /* NMI */
jmp @SYMBOL_NAME(system_call) /* TRAPA #0 (System call) */
.long 0
@@ -141,20 +196,20 @@ SYMBOL_NAME_LABEL(interrupt_redirect_table)
SYMBOL_NAME_LABEL(interrupt_redirect_table)
.space 4
#endif
-
+
.section .text
.align 2
SYMBOL_NAME_LABEL(interrupt_entry)
SAVE_ALL
- mov.w @(LCCR,sp),r0
- btst #4,r0l
+ mov.l sp,er0
+ add.l #LVEC,er0
+ btst #4,r1l
bne 1f
+ /* user LVEC */
mov.l @SYMBOL_NAME(sw_usp),er0
- mov.l @(4:16,er0),er0
- bra 2f
+ adds #4,er0
1:
- mov.l @(LVEC:16,sp),er0
-2:
+ mov.l @er0,er0 /* LVEC address */
#if defined(CONFIG_ROMKERNEL)
sub.l #SYMBOL_NAME(interrupt_redirect_table),er0
#endif
@@ -162,69 +217,62 @@ SYMBOL_NAME_LABEL(interrupt_entry)
mov.l @SYMBOL_NAME(interrupt_redirect_table),er1
sub.l er1,er0
#endif
- shlr.l #2,er0
+ SHLR2 er0
dec.l #1,er0
mov.l sp,er1
subs #4,er1 /* adjust ret_pc */
- jsr @SYMBOL_NAME(process_int)
- mov.l @SYMBOL_NAME(irq_stat)+CPUSTAT_SOFTIRQ_PENDING,er0
- beq 1f
- jsr @SYMBOL_NAME(do_softirq)
-1:
- jmp @SYMBOL_NAME(ret_from_exception)
+ jsr @SYMBOL_NAME(do_IRQ)
+ jmp @SYMBOL_NAME(ret_from_interrupt)
SYMBOL_NAME_LABEL(system_call)
subs #4,sp /* dummy LVEC */
SAVE_ALL
+ andc #0x7f,ccr
mov.l er0,er4
- mov.l #-ENOSYS,er0
- mov.l er0,@(LER0:16,sp)
/* save top of frame */
mov.l sp,er0
jsr @SYMBOL_NAME(set_esp0)
- cmp.l #NR_syscalls,er4
- bcc SYMBOL_NAME(ret_from_exception):16
- shll.l #2,er4
- mov.l #SYMBOL_NAME(sys_call_table),er0
- add.l er4,er0
- mov.l @er0,er0
- mov.l er0,er4
- beq SYMBOL_NAME(ret_from_exception):16
mov.l sp,er2
and.w #0xe000,r2
- mov.b @((TASK_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
+ mov.b @((TI_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
btst #(TIF_SYSCALL_TRACE & 7),r2l
+ beq 1f
+ jsr @SYMBOL_NAME(do_syscall_trace)
+1:
+ cmp.l #NR_syscalls,er4
+ bcc badsys
+ SHLL2 er4
+ mov.l #SYMBOL_NAME(sys_call_table),er0
+ add.l er4,er0
+ mov.l @er0,er4
+ beq SYMBOL_NAME(ret_from_exception):16
mov.l @(LER1:16,sp),er0
mov.l @(LER2:16,sp),er1
mov.l @(LER3:16,sp),er2
- andc #0x7f,ccr
jsr @er4
- mov.l er0,@(LER0:16,sp) /* save the return value */
+ mov.l er0,@(LER0:16,sp) /* save the return value */
+ mov.l sp,er2
+ and.w #0xe000,r2
+ mov.b @((TI_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
+ btst #(TIF_SYSCALL_TRACE & 7),r2l
+ beq 2f
+ jsr @SYMBOL_NAME(do_syscall_trace)
+2:
#if defined(CONFIG_SYSCALL_PRINT)
jsr @SYMBOL_NAME(syscall_print)
#endif
- bra SYMBOL_NAME(ret_from_exception):8
-1:
- jsr SYMBOL_NAME(syscall_trace)
- mov.l @(LER1:16,sp),er0
- mov.l @(LER2:16,sp),er1
- mov.l @(LER3:16,sp),er2
- jsr @er4
- mov.l er0,@(LER0:16,sp) /* save the return value */
- jsr @SYMBOL_NAME(syscall_trace)
- bra SYMBOL_NAME(ret_from_exception):8
+ orc #0x80,ccr
+ bra resume_userspace
-SYMBOL_NAME_LABEL(ret_from_fork)
- mov.l er2,er0
- jsr @SYMBOL_NAME(schedule_tail)
- bra SYMBOL_NAME(ret_from_exception):8
+badsys:
+ mov.l #-ENOSYS,er0
+ mov.l er0,@(LER0:16,sp)
+ bra resume_userspace
-SYMBOL_NAME_LABEL(reschedule)
- /* save top of frame */
- mov.l sp,er0
- jsr @SYMBOL_NAME(set_esp0)
- jsr @SYMBOL_NAME(schedule)
+#if !defined(CONFIG_PREEMPT)
+#define resume_kernel restore_all
+#endif
SYMBOL_NAME_LABEL(ret_from_exception)
#if defined(CONFIG_PREEMPT)
@@ -232,58 +280,68 @@ SYMBOL_NAME_LABEL(ret_from_exception)
#endif
SYMBOL_NAME_LABEL(ret_from_interrupt)
mov.b @(LCCR+1:16,sp),r0l
- btst #4,r0l /* check if returning to kernel */
- bne done:8 /* if so, skip resched, signals */
+ btst #4,r0l
+ bne resume_kernel:8 /* return from kernel */
+resume_userspace:
andc #0x7f,ccr
mov.l sp,er4
- and.w #0xe000,r4
+ and.w #0xe000,r4 /* er4 <- current thread info */
mov.l @(TI_FLAGS:16,er4),er1
and.l #_TIF_WORK_MASK,er1
- beq done:8
-1:
- mov.l @(TI_FLAGS:16,er4),er1
+ beq restore_all:8
+work_pending:
btst #TIF_NEED_RESCHED,r1l
- bne SYMBOL_NAME(reschedule):16
+ bne work_resched:8
+ /* work notifysig */
mov.l sp,er0
- subs #4,er0 /* adjust retpc */
- mov.l er2,er1
- jsr @SYMBOL_NAME(do_signal)
+ subs #4,er0 /* er0: pt_regs */
+ jsr @SYMBOL_NAME(do_notify_resume)
+ bra restore_all:8
+work_resched:
+ mov.l sp,er0
+ jsr @SYMBOL_NAME(set_esp0)
+ jsr @SYMBOL_NAME(schedule)
+ bra resume_userspace:8
+restore_all:
+ RESTORE_ALL /* Does RTE */
+
#if defined(CONFIG_PREEMPT)
- bra done:8 /* userspace thoru */
-3:
- btst #4,r0l
- beq done:8 /* userspace thoru */
-4:
- mov.l @(TI_PRE_COUNT:16,er4),er1
- bne done:8
- mov.l @(TI_FLAGS:16,er4),er1
- btst #TIF_NEED_RESCHED,r1l
- beq done:8
- mov.b r0l,r0l
- bpl done:8 /* interrupt off (exception path?) */
- mov.l #PREEMPT_ACTIVE,er1
- mov.l er1,@(TI_PRE_COUNT:16,er4)
+resume_kernel:
+ mov.l @(TI_PRE_COUNT:16,er4),er0
+ bne restore_all:8
+need_resched:
+ mov.l @(TI_FLAGS:16,er4),er0
+ btst #TIF_NEED_RESCHED,r0l
+ beq restore_all:8
+ mov.b @(LCCR+1:16,sp),r0l /* Interrupt Enabled? */
+ bmi restore_all:8
+ mov.l #PREEMPT_ACTIVE,er0
+ mov.l er0,@(TI_PRE_COUNT:16,er4)
andc #0x7f,ccr
+ mov.l sp,er0
+ jsr @SYMBOL_NAME(set_esp0)
jsr @SYMBOL_NAME(schedule)
- sub.l er1,er1
- mov.l er1,@(TI_PRE_COUNT:16,er4)
orc #0x80,ccr
- bra 4b:8
+ bra need_resched:8
#endif
-done:
- RESTORE_ALL /* Does RTE */
+
+SYMBOL_NAME_LABEL(ret_from_fork)
+ mov.l er2,er0
+ jsr @SYMBOL_NAME(schedule_tail)
+ jmp @SYMBOL_NAME(ret_from_exception)
SYMBOL_NAME_LABEL(resume)
/*
- * er0 = prev
- * er1 = next
- * return last in er2
+ * Beware - when entering resume, offset of tss is in d1,
+ * prev (the current task) is in a0, next (the new task)
+ * is in a1 and d2.b is non-zero if the mm structure is
+ * shared between the tasks, so don't change these
+ * registers until their contents are no longer needed.
*/
/* save sr */
sub.w r3,r3
stc ccr,r3l
- stc exr,r3h
mov.w r3,@(THREAD_CCR+2:16,er0)
/* disable interrupts */
@@ -291,41 +349,45 @@ SYMBOL_NAME_LABEL(resume)
mov.l @SYMBOL_NAME(sw_usp),er3
mov.l er3,@(THREAD_USP:16,er0)
mov.l sp,@(THREAD_KSP:16,er0)
-
+
/* Skip address space switching if they are the same. */
/* FIXME: what did we hack out of here, this does nothing! */
mov.l @(THREAD_USP:16,er1),er0
mov.l er0,@SYMBOL_NAME(sw_usp)
mov.l @(THREAD_KSP:16,er1),sp
-
+
/* restore status register */
mov.w @(THREAD_CCR+2:16,er1),r3
ldc r3l,ccr
- ldc r3h,exr
-
rts
SYMBOL_NAME_LABEL(trace_break)
- subs #4,sp /* dummy LVEC */
+ subs #4,sp
SAVE_ALL
sub.l er1,er1
dec.l #1,er1
- mov.l er1,@(LORIG,sp)
+ mov.l er1,@(LORIG,sp)
mov.l sp,er0
jsr @SYMBOL_NAME(set_esp0)
mov.l @SYMBOL_NAME(sw_usp),er0
mov.l @er0,er1
+ mov.w @(-2:16,er1),r2
+ cmp.w #0x5730,r2
+ beq 1f
subs #2,er1
- mov.l er1,@er0
+ mov.l er1,@er0
+1:
and.w #0xff,e1
mov.l er1,er0
jsr @SYMBOL_NAME(trace_trap)
- jmp @SYMBOL_NAME(ret_from_exception)
+ jmp @SYMBOL_NAME(ret_from_exception)
.section .bss
SYMBOL_NAME_LABEL(sw_ksp)
- .space 4
+ .space 4
SYMBOL_NAME_LABEL(sw_usp)
- .space 4
+ .space 4
+
+ .end
diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c
deleted file mode 100644
index 3e4f479271c9..000000000000
--- a/arch/h8300/kernel/ints.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * linux/arch/h8300/kernel/ints.c
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- * Based on linux/arch/$(ARCH)/platform/$(PLATFORM)/ints.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.
- *
- * Copyright 1996 Roman Zippel
- * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <linux/bootmem.h>
-#include <linux/hardirq.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-#include <asm/io.h>
-#include <asm/setup.h>
-#include <asm/errno.h>
-
-/*
- * This structure has only 4 elements for speed reasons
- */
-typedef struct irq_handler {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
- int flags;
- int count;
- void *dev_id;
- const char *devname;
-} irq_handler_t;
-
-static irq_handler_t *irq_list[NR_IRQS];
-static int use_kmalloc;
-
-extern unsigned long *interrupt_redirect_table;
-extern const int h8300_saved_vectors[];
-extern const unsigned long h8300_trap_table[];
-int h8300_enable_irq_pin(unsigned int irq);
-void h8300_disable_irq_pin(unsigned int irq);
-
-#define CPU_VECTOR ((unsigned long *)0x000000)
-#define ADDR_MASK (0xffffff)
-
-#if defined(CONFIG_RAMKERNEL)
-static unsigned long __init *get_vector_address(void)
-{
- unsigned long *rom_vector = CPU_VECTOR;
- unsigned long base,tmp;
- int vec_no;
-
- base = rom_vector[EXT_IRQ0] & ADDR_MASK;
-
- /* check romvector format */
- for (vec_no = EXT_IRQ1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) {
- if ((base+(vec_no - EXT_IRQ0)*4) != (rom_vector[vec_no] & ADDR_MASK))
- return NULL;
- }
-
- /* ramvector base address */
- base -= EXT_IRQ0*4;
-
- /* writerble check */
- tmp = ~(*(volatile unsigned long *)base);
- (*(volatile unsigned long *)base) = tmp;
- if ((*(volatile unsigned long *)base) != tmp)
- return NULL;
- return (unsigned long *)base;
-}
-#endif
-
-void __init init_IRQ(void)
-{
-#if defined(CONFIG_RAMKERNEL)
- int i;
- unsigned long *ramvec,*ramvec_p;
- const unsigned long *trap_entry;
- const int *saved_vector;
-
- ramvec = get_vector_address();
- if (ramvec == NULL)
- panic("interrupt vector serup failed.");
- else
- printk(KERN_INFO "virtual vector at 0x%08lx\n",(unsigned long)ramvec);
-
- /* create redirect table */
- ramvec_p = ramvec;
- trap_entry = h8300_trap_table;
- saved_vector = h8300_saved_vectors;
- for ( i = 0; i < NR_IRQS; i++) {
- if (i == *saved_vector) {
- ramvec_p++;
- saved_vector++;
- } else {
- if ( i < NR_TRAPS ) {
- if (*trap_entry)
- *ramvec_p = VECTOR(*trap_entry);
- ramvec_p++;
- trap_entry++;
- } else
- *ramvec_p++ = REDIRECT(interrupt_entry);
- }
- }
- interrupt_redirect_table = ramvec;
-#ifdef DUMP_VECTOR
- ramvec_p = ramvec;
- for (i = 0; i < NR_IRQS; i++) {
- if ((i % 8) == 0)
- printk(KERN_DEBUG "\n%p: ",ramvec_p);
- printk(KERN_DEBUG "%p ",*ramvec_p);
- ramvec_p++;
- }
- printk(KERN_DEBUG "\n");
-#endif
-#endif
-}
-
-int request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, const char *devname, void *dev_id)
-{
- irq_handler_t *irq_handle;
- if (irq < 0 || irq >= NR_IRQS) {
- printk(KERN_ERR "Incorrect IRQ %d from %s\n", irq, devname);
- return -EINVAL;
- }
-
- if (irq_list[irq] || (h8300_enable_irq_pin(irq) == -EBUSY))
- return -EBUSY;
-
- if (use_kmalloc)
- irq_handle = kmalloc(sizeof(irq_handler_t), GFP_ATOMIC);
- else {
- /* use bootmem allocater */
- irq_handle = (irq_handler_t *)alloc_bootmem(sizeof(irq_handler_t));
- irq_handle = (irq_handler_t *)((unsigned long)irq_handle | 0x80000000);
- }
-
- if (irq_handle == NULL)
- return -ENOMEM;
-
- irq_handle->handler = handler;
- irq_handle->flags = flags;
- irq_handle->count = 0;
- irq_handle->dev_id = dev_id;
- irq_handle->devname = devname;
- irq_list[irq] = irq_handle;
-
- if (irq_handle->flags & IRQF_SAMPLE_RANDOM)
- rand_initialize_irq(irq);
-
- enable_irq(irq);
- return 0;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- if (irq >= NR_IRQS)
- return;
-
- if (!irq_list[irq] || irq_list[irq]->dev_id != dev_id)
- printk(KERN_WARNING "Removing probably wrong IRQ %d from %s\n",
- irq, irq_list[irq]->devname);
- disable_irq(irq);
- h8300_disable_irq_pin(irq);
- if (((unsigned long)irq_list[irq] & 0x80000000) == 0) {
- kfree(irq_list[irq]);
- irq_list[irq] = NULL;
- }
-}
-
-EXPORT_SYMBOL(free_irq);
-
-/*
- * Do we need these probe functions on the m68k?
- */
-unsigned long probe_irq_on (void)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off (unsigned long irqs)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-void enable_irq(unsigned int irq)
-{
- if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS))
- IER_REGS |= 1 << (irq - EXT_IRQ0);
-}
-
-void disable_irq(unsigned int irq)
-{
- if (irq >= EXT_IRQ0 && irq <= (EXT_IRQ0 + EXT_IRQS))
- IER_REGS &= ~(1 << (irq - EXT_IRQ0));
-}
-
-asmlinkage void process_int(int irq, struct pt_regs *fp)
-{
- irq_enter();
- h8300_clear_isr(irq);
- if (irq >= NR_TRAPS && irq < NR_IRQS) {
- if (irq_list[irq]) {
- irq_list[irq]->handler(irq, irq_list[irq]->dev_id, fp);
- irq_list[irq]->count++;
- if (irq_list[irq]->flags & IRQF_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- }
- } else {
- BUG();
- }
- irq_exit();
-}
-
-int show_interrupts(struct seq_file *p, void *v)
-{
- int i = *(loff_t *) v;
-
- if ((i < NR_IRQS) && (irq_list[i]!=NULL)) {
- seq_printf(p, "%3d: %10u ",i,irq_list[i]->count);
- seq_printf(p, "%s\n", irq_list[i]->devname);
- }
-
- return 0;
-}
-
-void init_irq_proc(void)
-{
-}
-
-static int __init enable_kmalloc(void)
-{
- use_kmalloc = 1;
- return 0;
-}
-core_initcall(enable_kmalloc);
diff --git a/arch/h8300/kernel/ptrace.c b/arch/h8300/kernel/ptrace.c
index 8f2411db7eaf..d32bbf02fc48 100644
--- a/arch/h8300/kernel/ptrace.c
+++ b/arch/h8300/kernel/ptrace.c
@@ -111,10 +111,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
@@ -219,7 +216,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
return ret;
}
-asmlinkage void syscall_trace(void)
+asmlinkage void do_syscall_trace(void)
{
if (!test_thread_flag(TIF_SYSCALL_TRACE))
return;
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index 02955604d760..62ea12d339b9 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -547,3 +547,9 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
}
return 0;
}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
+{
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ do_signal(regs, NULL);
+}
diff --git a/arch/h8300/platform/h8300h/Makefile b/arch/h8300/platform/h8300h/Makefile
index b24ea08aa0a7..c5096369ea50 100644
--- a/arch/h8300/platform/h8300h/Makefile
+++ b/arch/h8300/platform/h8300h/Makefile
@@ -4,4 +4,4 @@
# Reuse any files we can from the H8/300H
#
-obj-y := entry.o irq_pin.o ptrace_h8300h.o
+obj-y := irq_pin.o ptrace_h8300h.o
diff --git a/arch/h8300/platform/h8300h/entry.S b/arch/h8300/platform/h8300h/entry.S
deleted file mode 100644
index f86ac3b5d4de..000000000000
--- a/arch/h8300/platform/h8300h/entry.S
+++ /dev/null
@@ -1,332 +0,0 @@
-/* -*- mode: asm -*-
- *
- * linux/arch/h8300/platform/h8300h/entry.S
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- * David McCullough <davidm@snapgear.com>
- *
- */
-
-/*
- * entry.S
- * include exception/interrupt gateway
- * system call entry
- */
-
-#include <linux/sys.h>
-#include <asm/unistd.h>
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/linkage.h>
-#include <asm/asm-offsets.h>
-#include <asm/thread_info.h>
-#include <asm/errno.h>
-
- .h8300h
-
-/* CPU context save/restore macros. */
-
- .macro SAVE_ALL
- mov.l er0,@-sp
-
- stc ccr,r0l /* check kernel mode */
- btst #4,r0l
- bne 5f
-
- mov.l sp,@SYMBOL_NAME(sw_usp) /* user mode */
- mov.l @sp,er0
- orc #0x10,ccr
- mov.l @SYMBOL_NAME(sw_ksp),sp
- sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
- mov.l er0,@-sp
- mov.l er1,@-sp
- mov.l @SYMBOL_NAME(sw_usp),er0
- mov.l @(8:16,er0),er1 /* copy the RET addr */
- mov.l er1,@(LRET-LER1:16,sp)
-
- mov.w e1,r1 /* e1 highbyte = ccr */
- and #0xef,r1h /* mask mode? flag */
- sub.w r0,r0
- mov.b r1h,r0l
- mov.w r0,@(LCCR-LER1:16,sp) /* copy ccr */
- mov.l @(LORIG-LER1:16,sp),er0
- mov.l er0,@(LER0-LER1:16,sp) /* copy ER0 */
- bra 6f
-5:
- mov.l @sp,er0 /* kernel mode */
- subs #2,sp /* dummy ccr */
- mov.l er0,@-sp
- mov.l er1,@-sp
- mov.w @(LRET-LER1:16,sp),r1 /* copy old ccr */
- mov.b r1h,r1l
- mov.b #0,r1h
- mov.w r1,@(LCCR-LER1:16,sp) /* set ccr */
-6:
- mov.l er2,@-sp
- mov.l er3,@-sp
- mov.l er6,@-sp /* syscall arg #6 */
- mov.l er5,@-sp /* syscall arg #5 */
- mov.l er4,@-sp /* syscall arg #4 */
- .endm
-
- .macro RESTORE_ALL
- mov.l @sp+,er4
- mov.l @sp+,er5
- mov.l @sp+,er6
- mov.l @sp+,er3
- mov.l @sp+,er2
- mov.w @(LCCR-LER1:16,sp),r0 /* check kernel mode */
- btst #4,r0l
- bne 7f
-
- orc #0x80,ccr
- mov.l @SYMBOL_NAME(sw_usp),er0
- mov.l @(LER0-LER1:16,sp),er1 /* restore ER0 */
- mov.l er1,@er0
- mov.w @(LCCR-LER1:16,sp),r1 /* restore the RET addr */
- mov.b r1l,r1h
- mov.b @(LRET+1-LER1:16,sp),r1l
- mov.w r1,e1
- mov.w @(LRET+2-LER1:16,sp),r1
- mov.l er1,@(8:16,er0)
-
- mov.l @sp+,er1
- add.l #(LRET-LER1),sp /* remove LORIG - LRET */
- mov.l sp,@SYMBOL_NAME(sw_ksp)
- mov.l er0,sp
- bra 8f
-7:
- mov.l @sp+,er1
- adds #4,sp
- adds #2,sp
-8:
- mov.l @sp+,er0
- adds #4,sp /* remove the sw created LVEC */
- rte
- .endm
-
-.globl SYMBOL_NAME(system_call)
-.globl SYMBOL_NAME(ret_from_exception)
-.globl SYMBOL_NAME(ret_from_fork)
-.globl SYMBOL_NAME(ret_from_interrupt)
-.globl SYMBOL_NAME(interrupt_redirect_table)
-.globl SYMBOL_NAME(sw_ksp),SYMBOL_NAME(sw_usp)
-.globl SYMBOL_NAME(resume)
-.globl SYMBOL_NAME(interrupt_redirect_table)
-.globl SYMBOL_NAME(interrupt_entry)
-.globl SYMBOL_NAME(system_call)
-.globl SYMBOL_NAME(trace_break)
-
-#if defined(CONFIG_ROMKERNEL)
-INTERRUPTS = 64
- .section .int_redirect,"ax"
-SYMBOL_NAME_LABEL(interrupt_redirect_table)
- .rept 7
- .long 0
- .endr
- jsr @SYMBOL_NAME(interrupt_entry) /* NMI */
- jmp @SYMBOL_NAME(system_call) /* TRAPA #0 (System call) */
- .long 0
- .long 0
- jmp @SYMBOL_NAME(trace_break) /* TRAPA #3 (breakpoint) */
- .rept INTERRUPTS-12
- jsr @SYMBOL_NAME(interrupt_entry)
- .endr
-#endif
-#if defined(CONFIG_RAMKERNEL)
-.globl SYMBOL_NAME(interrupt_redirect_table)
- .section .bss
-SYMBOL_NAME_LABEL(interrupt_redirect_table)
- .space 4
-#endif
-
- .section .text
- .align 2
-SYMBOL_NAME_LABEL(interrupt_entry)
- SAVE_ALL
- mov.w @(LCCR,sp),r0
- btst #4,r0l
- bne 1f
- mov.l @SYMBOL_NAME(sw_usp),er0
- mov.l @(4:16,er0),er0
- bra 2f
-1:
- mov.l @(LVEC,sp),er0
-2:
-#if defined(CONFIG_ROMKERNEL)
- sub.l #SYMBOL_NAME(interrupt_redirect_table),er0
-#endif
-#if defined(CONFIG_RAMKERNEL)
- mov.l @SYMBOL_NAME(interrupt_redirect_table),er1
- sub.l er1,er0
-#endif
- shlr.l er0
- shlr.l er0
- dec.l #1,er0
- mov.l sp,er1
- subs #4,er1 /* adjust ret_pc */
- jsr @SYMBOL_NAME(do_IRQ)
- mov.l @SYMBOL_NAME(irq_stat)+CPUSTAT_SOFTIRQ_PENDING,er0
- beq 1f
- jsr @SYMBOL_NAME(do_softirq)
-1:
- jmp @SYMBOL_NAME(ret_from_interrupt)
-
-SYMBOL_NAME_LABEL(system_call)
- subs #4,sp /* dummy LVEC */
- SAVE_ALL
- mov.w @(LCCR:16,sp),r1
- bset #4,r1l
- ldc r1l,ccr
- mov.l er0,er4
- mov.l #-ENOSYS,er0
- mov.l er0,@(LER0:16,sp)
-
- /* save top of frame */
- mov.l sp,er0
- jsr @SYMBOL_NAME(set_esp0)
- cmp.l #NR_syscalls,er4
- bcc SYMBOL_NAME(ret_from_exception):16
- shll.l er4
- shll.l er4
- mov.l #SYMBOL_NAME(sys_call_table),er0
- add.l er4,er0
- mov.l @er0,er4
- beq SYMBOL_NAME(ret_from_exception):16
- mov.l sp,er2
- and.w #0xe000,r2
- mov.b @((TASK_FLAGS+3-(TIF_SYSCALL_TRACE >> 3)):16,er2),r2l
- btst #(TIF_SYSCALL_TRACE & 7),r2l
- bne 1f
- mov.l @(LER1:16,sp),er0
- mov.l @(LER2:16,sp),er1
- mov.l @(LER3:16,sp),er2
- jsr @er4
- mov.l er0,@(LER0:16,sp) /* save the return value */
-#if defined(CONFIG_SYSCALL_PRINT)
- jsr @SYMBOL_NAME(syscall_print)
-#endif
- bra SYMBOL_NAME(ret_from_exception):8
-1:
- jsr SYMBOL_NAME(syscall_trace)
- mov.l @(LER1:16,sp),er0
- mov.l @(LER2:16,sp),er1
- mov.l @(LER3:16,sp),er2
- jsr @er4
- mov.l er0,@(LER0:16,sp) /* save the return value */
- jsr @SYMBOL_NAME(syscall_trace)
- bra SYMBOL_NAME(ret_from_exception):8
-
-SYMBOL_NAME_LABEL(ret_from_fork)
- mov.l er2,er0
- jsr @SYMBOL_NAME(schedule_tail)
- bra SYMBOL_NAME(ret_from_exception):8
-
-SYMBOL_NAME_LABEL(reschedule)
- /* save top of frame */
- mov.l sp,er0
- jsr @SYMBOL_NAME(set_esp0)
- jsr @SYMBOL_NAME(schedule)
-
-SYMBOL_NAME_LABEL(ret_from_exception)
-#if defined(CONFIG_PREEMPT)
- orc #0x80,ccr
-#endif
-SYMBOL_NAME_LABEL(ret_from_interrupt)
- mov.b @(LCCR+1:16,sp),r0l
- btst #4,r0l /* check if returning to kernel */
- bne done:8 /* if so, skip resched, signals */
- andc #0x7f,ccr
- mov.l sp,er4
- and.w #0xe000,r4
- mov.l @(TI_FLAGS:16,er4),er1
- and.l #_TIF_WORK_MASK,er1
- beq done:8
-1:
- mov.l @(TI_FLAGS:16,er4),er1
- btst #TIF_NEED_RESCHED,r1l
- bne SYMBOL_NAME(reschedule):16
- mov.l sp,er0
- subs #4,er0 /* adjust retpc */
- mov.l er2,er1
- jsr @SYMBOL_NAME(do_signal)
-#if defined(CONFIG_PREEMPT)
- bra done:8 /* userspace thoru */
-3:
- btst #4,r0l
- beq done:8 /* userspace thoru */
-4:
- mov.l @(TI_PRE_COUNT:16,er4),er1
- bne done:8
- mov.l @(TI_FLAGS:16,er4),er1
- btst #TIF_NEED_RESCHED,r1l
- beq done:8
- mov.b r0l,r0l
- bpl done:8 /* interrupt off (exception path?) */
- mov.l #PREEMPT_ACTIVE,er1
- mov.l er1,@(TI_PRE_COUNT:16,er4)
- andc #0x7f,ccr
- jsr @SYMBOL_NAME(schedule)
- sub.l er1,er1
- mov.l er1,@(TI_PRE_COUNT:16,er4)
- orc #0x80,ccr
- bra 4b:8
-#endif
-done:
- RESTORE_ALL /* Does RTE */
-
-SYMBOL_NAME_LABEL(resume)
- /*
- * Beware - when entering resume, offset of tss is in d1,
- * prev (the current task) is in a0, next (the new task)
- * is in a1 and d2.b is non-zero if the mm structure is
- * shared between the tasks, so don't change these
- * registers until their contents are no longer needed.
- */
-
- /* save sr */
- sub.w r3,r3
- stc ccr,r3l
- mov.w r3,@(THREAD_CCR+2:16,er0)
-
- /* disable interrupts */
- orc #0x80,ccr
- mov.l @SYMBOL_NAME(sw_usp),er3
- mov.l er3,@(THREAD_USP:16,er0)
- mov.l sp,@(THREAD_KSP:16,er0)
-
- /* Skip address space switching if they are the same. */
- /* FIXME: what did we hack out of here, this does nothing! */
-
- mov.l @(THREAD_USP:16,er1),er0
- mov.l er0,@SYMBOL_NAME(sw_usp)
- mov.l @(THREAD_KSP:16,er1),sp
-
- /* restore status register */
- mov.w @(THREAD_CCR+2:16,er1),r3
-
- ldc r3l,ccr
- rts
-
-SYMBOL_NAME_LABEL(trace_break)
- subs #4,sp
- SAVE_ALL
- sub.l er1,er1
- dec.l #1,er1
- mov.l er1,@(LORIG,sp)
- mov.l sp,er0
- jsr @SYMBOL_NAME(set_esp0)
- mov.l @SYMBOL_NAME(sw_usp),er0
- mov.l @er0,er1
- subs #2,er1
- mov.l er1,@er0
- and.w #0xff,e1
- mov.l er1,er0
- jsr @SYMBOL_NAME(trace_trap)
- jmp @SYMBOL_NAME(ret_from_exception)
-
- .section .bss
-SYMBOL_NAME_LABEL(sw_ksp)
- .space 4
-SYMBOL_NAME_LABEL(sw_usp)
- .space 4
diff --git a/arch/h8300/platform/h8s/Makefile b/arch/h8300/platform/h8s/Makefile
index 0847b15d4256..bf1241883766 100644
--- a/arch/h8300/platform/h8s/Makefile
+++ b/arch/h8300/platform/h8s/Makefile
@@ -4,4 +4,4 @@
# Reuse any files we can from the H8S
#
-obj-y := entry.o ints_h8s.o ptrace_h8s.o
+obj-y := ints_h8s.o ptrace_h8s.o
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index b1b2b30b1b8e..abb582bc218f 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -18,6 +18,10 @@ config GENERIC_TIME
bool
default y
+config GENERIC_CMOS_UPDATE
+ bool
+ default y
+
config CLOCKSOURCE_WATCHDOG
bool
default y
@@ -222,6 +226,8 @@ config PARAVIRT
However, when run without a hypervisor the kernel is
theoretically slower. If in doubt, say N.
+source "arch/i386/xen/Kconfig"
+
config VMI
bool "VMI Paravirt-ops support"
depends on PARAVIRT
@@ -542,6 +548,7 @@ config HIGHMEM4G
config HIGHMEM64G
bool "64GB"
depends on !M386 && !M486
+ select X86_PAE
help
Select this if you have a 32-bit processor and more than 4
gigabytes of physical RAM.
@@ -571,12 +578,12 @@ choice
config VMSPLIT_3G
bool "3G/1G user/kernel split"
config VMSPLIT_3G_OPT
- depends on !HIGHMEM
+ depends on !X86_PAE
bool "3G/1G user/kernel split (for full 1G low memory)"
config VMSPLIT_2G
bool "2G/2G user/kernel split"
config VMSPLIT_2G_OPT
- depends on !HIGHMEM
+ depends on !X86_PAE
bool "2G/2G user/kernel split (for full 2G low memory)"
config VMSPLIT_1G
bool "1G/3G user/kernel split"
@@ -596,10 +603,15 @@ config HIGHMEM
default y
config X86_PAE
- bool
- depends on HIGHMEM64G
- default y
+ bool "PAE (Physical Address Extension) Support"
+ default n
+ depends on !HIGHMEM4G
select RESOURCES_64BIT
+ help
+ PAE is required for NX support, and furthermore enables
+ larger swapspace support for non-overcommit purposes. It
+ has the cost of more pagetable lookup overhead, and also
+ consumes more pagetable space per process.
# Common NUMA Features
config NUMA
@@ -815,6 +827,7 @@ config CRASH_DUMP
config PHYSICAL_START
hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP)
+ default "0x1000000" if X86_NUMAQ
default "0x100000"
help
This gives the physical address where the kernel is loaded.
@@ -1212,21 +1225,26 @@ source "drivers/Kconfig"
source "fs/Kconfig"
-menu "Instrumentation Support"
+menuconfig INSTRUMENTATION
+ bool "Instrumentation Support"
depends on EXPERIMENTAL
+ default y
+
+if INSTRUMENTATION
source "arch/i386/oprofile/Kconfig"
config KPROBES
- bool "Kprobes (EXPERIMENTAL)"
- depends on KALLSYMS && EXPERIMENTAL && MODULES
+ bool "Kprobes"
+ depends on KALLSYMS && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
a probepoint and specifies the callback. Kprobes is useful
for kernel debugging, non-intrusive instrumentation and testing.
If in doubt, say "N".
-endmenu
+
+endif # INSTRUMENTATION
source "arch/i386/Kconfig.debug"
diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
index 5c95ceb7f122..11a24d54f27b 100644
--- a/arch/i386/Kconfig.cpu
+++ b/arch/i386/Kconfig.cpu
@@ -297,11 +297,6 @@ config X86_POPAD_OK
depends on !M386
default y
-config X86_CMPXCHG64
- bool
- depends on X86_PAE
- default y
-
config X86_ALIGNMENT_16
bool
depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
@@ -344,8 +339,8 @@ config X86_CMOV
depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7)
default y
-config X86_MINIMUM_CPU_MODEL
+config X86_MINIMUM_CPU_FAMILY
int
- default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP
- default "0"
+ default "4" if X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK
+ default "3"
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index bd28f9f9b4b7..01f0ff0daaf4 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -93,6 +93,9 @@ mflags-$(CONFIG_X86_ES7000) := -Iinclude/asm-i386/mach-es7000
mcore-$(CONFIG_X86_ES7000) := mach-default
core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/
+# Xen paravirtualization support
+core-$(CONFIG_XEN) += arch/i386/xen/
+
# default subarch .h files
mflags-y += -Iinclude/asm-i386/mach-default
@@ -108,6 +111,7 @@ drivers-$(CONFIG_PCI) += arch/i386/pci/
# must be linked after kernel/
drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/
drivers-$(CONFIG_PM) += arch/i386/power/
+drivers-$(CONFIG_FB) += arch/i386/video/
CFLAGS += $(mflags-y)
AFLAGS += $(mflags-y)
diff --git a/arch/i386/boot/.gitignore b/arch/i386/boot/.gitignore
index 495f20c085de..18465143cfa2 100644
--- a/arch/i386/boot/.gitignore
+++ b/arch/i386/boot/.gitignore
@@ -1,3 +1,5 @@
bootsect
bzImage
setup
+setup.bin
+setup.elf
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index bfbc32098a4a..93386a4e40b4 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -25,27 +25,56 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
#RAMDISK := -DRAMDISK=512
-targets := vmlinux.bin bootsect bootsect.o \
- setup setup.o zImage bzImage
+targets := vmlinux.bin setup.bin setup.elf zImage bzImage
subdir- := compressed
+setup-y += a20.o apm.o cmdline.o copy.o cpu.o cpucheck.o edd.o
+setup-y += header.o main.o mca.o memory.o pm.o pmjump.o
+setup-y += printf.o string.o tty.o video.o version.o voyager.o
+
+# The link order of the video-*.o modules can matter. In particular,
+# video-vga.o *must* be listed first, followed by video-vesa.o.
+# Hardware-specific drivers should follow in the order they should be
+# probed, and video-bios.o should typically be last.
+setup-y += video-vga.o
+setup-y += video-vesa.o
+setup-y += video-bios.o
+targets += $(setup-y)
hostprogs-y := tools/build
HOSTCFLAGS_build.o := $(LINUXINCLUDE)
# ---------------------------------------------------------------------------
+# How to compile the 16-bit code. Note we always compile for -march=i386,
+# that way we can complain to the user if the CPU is insufficient.
+cflags-i386 :=
+cflags-x86_64 := -m32
+CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D__KERNEL__ \
+ $(cflags-$(ARCH)) \
+ -Wall -Wstrict-prototypes \
+ -march=i386 -mregparm=3 \
+ -include $(srctree)/$(src)/code16gcc.h \
+ -fno-strict-aliasing -fomit-frame-pointer \
+ $(call cc-option, -ffreestanding) \
+ $(call cc-option, -fno-toplevel-reorder,\
+ $(call cc-option, -fno-unit-at-a-time)) \
+ $(call cc-option, -fno-stack-protector) \
+ $(call cc-option, -mpreferred-stack-boundary=2)
+AFLAGS := $(CFLAGS) -D__ASSEMBLY__
+
$(obj)/zImage: IMAGE_OFFSET := 0x1000
$(obj)/zImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK)
$(obj)/bzImage: IMAGE_OFFSET := 0x100000
+$(obj)/bzImage: EXTRA_CFLAGS := -D__BIG_KERNEL__
$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
$(obj)/bzImage: BUILDFLAGS := -b
quiet_cmd_image = BUILD $@
-cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
+cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/setup.bin \
$(obj)/vmlinux.bin $(ROOT_DEV) > $@
-$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
+$(obj)/zImage $(obj)/bzImage: $(obj)/setup.bin \
$(obj)/vmlinux.bin $(obj)/tools/build FORCE
$(call if_changed,image)
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
@@ -53,12 +82,17 @@ $(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
-LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
-LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext
+SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
-$(obj)/setup $(obj)/bootsect: %: %.o FORCE
+LDFLAGS_setup.elf := -T
+$(obj)/setup.elf: $(src)/setup.ld $(SETUP_OBJS) FORCE
$(call if_changed,ld)
+OBJCOPYFLAGS_setup.bin := -O binary
+
+$(obj)/setup.bin: $(obj)/setup.elf FORCE
+ $(call if_changed,objcopy)
+
$(obj)/compressed/vmlinux: FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
diff --git a/arch/i386/boot/a20.c b/arch/i386/boot/a20.c
new file mode 100644
index 000000000000..31348d054fca
--- /dev/null
+++ b/arch/i386/boot/a20.c
@@ -0,0 +1,161 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/a20.c
+ *
+ * Enable A20 gate (return -1 on failure)
+ */
+
+#include "boot.h"
+
+#define MAX_8042_LOOPS 100000
+
+static int empty_8042(void)
+{
+ u8 status;
+ int loops = MAX_8042_LOOPS;
+
+ while (loops--) {
+ io_delay();
+
+ status = inb(0x64);
+ if (status & 1) {
+ /* Read and discard input data */
+ io_delay();
+ (void)inb(0x60);
+ } else if (!(status & 2)) {
+ /* Buffers empty, finished! */
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/* Returns nonzero if the A20 line is enabled. The memory address
+ used as a test is the int $0x80 vector, which should be safe. */
+
+#define A20_TEST_ADDR (4*0x80)
+#define A20_TEST_SHORT 32
+#define A20_TEST_LONG 2097152 /* 2^21 */
+
+static int a20_test(int loops)
+{
+ int ok = 0;
+ int saved, ctr;
+
+ set_fs(0x0000);
+ set_gs(0xffff);
+
+ saved = ctr = rdfs32(A20_TEST_ADDR);
+
+ while (loops--) {
+ wrfs32(++ctr, A20_TEST_ADDR);
+ io_delay(); /* Serialize and make delay constant */
+ ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr;
+ if (ok)
+ break;
+ }
+
+ wrfs32(saved, A20_TEST_ADDR);
+ return ok;
+}
+
+/* Quick test to see if A20 is already enabled */
+static int a20_test_short(void)
+{
+ return a20_test(A20_TEST_SHORT);
+}
+
+/* Longer test that actually waits for A20 to come on line; this
+ is useful when dealing with the KBC or other slow external circuitry. */
+static int a20_test_long(void)
+{
+ return a20_test(A20_TEST_LONG);
+}
+
+static void enable_a20_bios(void)
+{
+ asm volatile("pushfl; int $0x15; popfl"
+ : : "a" ((u16)0x2401));
+}
+
+static void enable_a20_kbc(void)
+{
+ empty_8042();
+
+ outb(0xd1, 0x64); /* Command write */
+ empty_8042();
+
+ outb(0xdf, 0x60); /* A20 on */
+ empty_8042();
+}
+
+static void enable_a20_fast(void)
+{
+ u8 port_a;
+
+ port_a = inb(0x92); /* Configuration port A */
+ port_a |= 0x02; /* Enable A20 */
+ port_a &= ~0x01; /* Do not reset machine */
+ outb(port_a, 0x92);
+}
+
+/*
+ * Actual routine to enable A20; return 0 on ok, -1 on failure
+ */
+
+#define A20_ENABLE_LOOPS 255 /* Number of times to try */
+
+int enable_a20(void)
+{
+ int loops = A20_ENABLE_LOOPS;
+
+#if defined(CONFIG_X86_ELAN)
+ /* Elan croaks if we try to touch the KBC */
+ enable_a20_fast();
+ while (!a20_test_long())
+ ;
+ return 0;
+#elif defined(CONFIG_X86_VOYAGER)
+ /* On Voyager, a20_test() is unsafe? */
+ enable_a20_kbc();
+ return 0;
+#else
+ while (loops--) {
+ /* First, check to see if A20 is already enabled
+ (legacy free, etc.) */
+ if (a20_test_short())
+ return 0;
+
+ /* Next, try the BIOS (INT 0x15, AX=0x2401) */
+ enable_a20_bios();
+ if (a20_test_short())
+ return 0;
+
+ /* Try enabling A20 through the keyboard controller */
+ empty_8042();
+ if (a20_test_short())
+ return 0; /* BIOS worked, but with delayed reaction */
+
+ enable_a20_kbc();
+ if (a20_test_long())
+ return 0;
+
+ /* Finally, try enabling the "fast A20 gate" */
+ enable_a20_fast();
+ if (a20_test_long())
+ return 0;
+ }
+
+ return -1;
+#endif
+}
diff --git a/arch/i386/boot/apm.c b/arch/i386/boot/apm.c
new file mode 100644
index 000000000000..a34087c370c0
--- /dev/null
+++ b/arch/i386/boot/apm.c
@@ -0,0 +1,97 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * Original APM BIOS checking by Stephen Rothwell, May 1994
+ * (sfr@canb.auug.org.au)
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/apm.c
+ *
+ * Get APM BIOS information
+ */
+
+#include "boot.h"
+
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+
+int query_apm_bios(void)
+{
+ u16 ax, bx, cx, dx, di;
+ u32 ebx, esi;
+ u8 err;
+
+ /* APM BIOS installation check */
+ ax = 0x5300;
+ bx = cx = 0;
+ asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
+ : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
+ : : "esi", "edi");
+
+ if (err)
+ return -1; /* No APM BIOS */
+
+ if (bx != 0x504d) /* "PM" signature */
+ return -1;
+
+ if (cx & 0x02) /* 32 bits supported? */
+ return -1;
+
+ /* Disconnect first, just in case */
+ ax = 0x5304;
+ asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
+ : "+a" (ax)
+ : : "ebx", "ecx", "edx", "esi", "edi");
+
+ /* Paranoia */
+ ebx = esi = 0;
+ cx = dx = di = 0;
+
+ /* 32-bit connect */
+ asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %6"
+ : "=a" (ax), "+b" (ebx), "+c" (cx), "+d" (dx),
+ "+S" (esi), "+D" (di), "=m" (err)
+ : "a" (0x5303));
+
+ boot_params.apm_bios_info.cseg = ax;
+ boot_params.apm_bios_info.offset = ebx;
+ boot_params.apm_bios_info.cseg_16 = cx;
+ boot_params.apm_bios_info.dseg = dx;
+ boot_params.apm_bios_info.cseg_len = (u16)esi;
+ boot_params.apm_bios_info.cseg_16_len = esi >> 16;
+ boot_params.apm_bios_info.dseg_len = di;
+
+ if (err)
+ return -1;
+
+ /* Redo the installation check as the 32-bit connect;
+ some BIOSes return different flags this way... */
+
+ ax = 0x5300;
+ bx = cx = 0;
+ asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp ; setc %0"
+ : "=d" (err), "+a" (ax), "+b" (bx), "+c" (cx)
+ : : "esi", "edi");
+
+ if (err || bx != 0x504d) {
+ /* Failure with 32-bit connect, try to disconect and ignore */
+ ax = 0x5304;
+ bx = 0;
+ asm volatile("pushl %%ebp ; int $0x15 ; popl %%ebp"
+ : "+a" (ax), "+b" (bx)
+ : : "ecx", "edx", "esi", "edi");
+ return -1;
+ }
+
+ boot_params.apm_bios_info.version = ax;
+ boot_params.apm_bios_info.flags = cx;
+ return 0;
+}
+
+#endif
diff --git a/arch/i386/boot/bitops.h b/arch/i386/boot/bitops.h
new file mode 100644
index 000000000000..8dcc8dc7db88
--- /dev/null
+++ b/arch/i386/boot/bitops.h
@@ -0,0 +1,45 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/bitops.h
+ *
+ * Very simple bitops for the boot code.
+ */
+
+#ifndef BOOT_BITOPS_H
+#define BOOT_BITOPS_H
+#define _LINUX_BITOPS_H /* Inhibit inclusion of <linux/bitops.h> */
+
+static inline int constant_test_bit(int nr, const void *addr)
+{
+ const u32 *p = (const u32 *)addr;
+ return ((1UL << (nr & 31)) & (p[nr >> 5])) != 0;
+}
+static inline int variable_test_bit(int nr, const void *addr)
+{
+ u8 v;
+ const u32 *p = (const u32 *)addr;
+
+ asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr));
+ return v;
+}
+
+#define test_bit(nr,addr) \
+(__builtin_constant_p(nr) ? \
+ constant_test_bit((nr),(addr)) : \
+ variable_test_bit((nr),(addr)))
+
+static inline void set_bit(int nr, void *addr)
+{
+ asm("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr));
+}
+
+#endif /* BOOT_BITOPS_H */
diff --git a/arch/i386/boot/boot.h b/arch/i386/boot/boot.h
new file mode 100644
index 000000000000..dec70c9b6050
--- /dev/null
+++ b/arch/i386/boot/boot.h
@@ -0,0 +1,296 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/boot.h
+ *
+ * Header file for the real-mode kernel code
+ */
+
+#ifndef BOOT_BOOT_H
+#define BOOT_BOOT_H
+
+#ifndef __ASSEMBLY__
+
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/edd.h>
+#include <asm/boot.h>
+#include <asm/bootparam.h>
+
+/* Useful macros */
+#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
+
+extern struct setup_header hdr;
+extern struct boot_params boot_params;
+
+/* Basic port I/O */
+static inline void outb(u8 v, u16 port)
+{
+ asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
+}
+static inline u8 inb(u16 port)
+{
+ u8 v;
+ asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
+ return v;
+}
+
+static inline void outw(u16 v, u16 port)
+{
+ asm volatile("outw %0,%1" : : "a" (v), "dN" (port));
+}
+static inline u16 inw(u16 port)
+{
+ u16 v;
+ asm volatile("inw %1,%0" : "=a" (v) : "dN" (port));
+ return v;
+}
+
+static inline void outl(u32 v, u16 port)
+{
+ asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
+}
+static inline u32 inl(u32 port)
+{
+ u32 v;
+ asm volatile("inl %1,%0" : "=a" (v) : "dN" (port));
+ return v;
+}
+
+static inline void io_delay(void)
+{
+ const u16 DELAY_PORT = 0x80;
+ asm volatile("outb %%al,%0" : : "dN" (DELAY_PORT));
+}
+
+/* These functions are used to reference data in other segments. */
+
+static inline u16 ds(void)
+{
+ u16 seg;
+ asm("movw %%ds,%0" : "=rm" (seg));
+ return seg;
+}
+
+static inline void set_fs(u16 seg)
+{
+ asm volatile("movw %0,%%fs" : : "rm" (seg));
+}
+static inline u16 fs(void)
+{
+ u16 seg;
+ asm("movw %%fs,%0" : "=rm" (seg));
+ return seg;
+}
+
+static inline void set_gs(u16 seg)
+{
+ asm volatile("movw %0,%%gs" : : "rm" (seg));
+}
+static inline u16 gs(void)
+{
+ u16 seg;
+ asm("movw %%gs,%0" : "=rm" (seg));
+ return seg;
+}
+
+typedef unsigned int addr_t;
+
+static inline u8 rdfs8(addr_t addr)
+{
+ u8 v;
+ asm("movb %%fs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
+ return v;
+}
+static inline u16 rdfs16(addr_t addr)
+{
+ u16 v;
+ asm("movw %%fs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
+ return v;
+}
+static inline u32 rdfs32(addr_t addr)
+{
+ u32 v;
+ asm("movl %%fs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
+ return v;
+}
+
+static inline void wrfs8(u8 v, addr_t addr)
+{
+ asm volatile("movb %1,%%fs:%0" : "+m" (*(u8 *)addr) : "r" (v));
+}
+static inline void wrfs16(u16 v, addr_t addr)
+{
+ asm volatile("movw %1,%%fs:%0" : "+m" (*(u16 *)addr) : "r" (v));
+}
+static inline void wrfs32(u32 v, addr_t addr)
+{
+ asm volatile("movl %1,%%fs:%0" : "+m" (*(u32 *)addr) : "r" (v));
+}
+
+static inline u8 rdgs8(addr_t addr)
+{
+ u8 v;
+ asm("movb %%gs:%1,%0" : "=r" (v) : "m" (*(u8 *)addr));
+ return v;
+}
+static inline u16 rdgs16(addr_t addr)
+{
+ u16 v;
+ asm("movw %%gs:%1,%0" : "=r" (v) : "m" (*(u16 *)addr));
+ return v;
+}
+static inline u32 rdgs32(addr_t addr)
+{
+ u32 v;
+ asm("movl %%gs:%1,%0" : "=r" (v) : "m" (*(u32 *)addr));
+ return v;
+}
+
+static inline void wrgs8(u8 v, addr_t addr)
+{
+ asm volatile("movb %1,%%gs:%0" : "+m" (*(u8 *)addr) : "r" (v));
+}
+static inline void wrgs16(u16 v, addr_t addr)
+{
+ asm volatile("movw %1,%%gs:%0" : "+m" (*(u16 *)addr) : "r" (v));
+}
+static inline void wrgs32(u32 v, addr_t addr)
+{
+ asm volatile("movl %1,%%gs:%0" : "+m" (*(u32 *)addr) : "r" (v));
+}
+
+/* Note: these only return true/false, not a signed return value! */
+static inline int memcmp(const void *s1, const void *s2, size_t len)
+{
+ u8 diff;
+ asm("repe; cmpsb; setnz %0"
+ : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+ return diff;
+}
+
+static inline int memcmp_fs(const void *s1, addr_t s2, size_t len)
+{
+ u8 diff;
+ asm("fs; repe; cmpsb; setnz %0"
+ : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+ return diff;
+}
+static inline int memcmp_gs(const void *s1, addr_t s2, size_t len)
+{
+ u8 diff;
+ asm("gs; repe; cmpsb; setnz %0"
+ : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len));
+ return diff;
+}
+
+static inline int isdigit(int ch)
+{
+ return (ch >= '0') && (ch <= '9');
+}
+
+/* Heap -- available for dynamic lists. */
+#define STACK_SIZE 512 /* Minimum number of bytes for stack */
+
+extern char _end[];
+extern char *HEAP;
+extern char *heap_end;
+#define RESET_HEAP() ((void *)( HEAP = _end ))
+static inline char *__get_heap(size_t s, size_t a, size_t n)
+{
+ char *tmp;
+
+ HEAP = (char *)(((size_t)HEAP+(a-1)) & ~(a-1));
+ tmp = HEAP;
+ HEAP += s*n;
+ return tmp;
+}
+#define GET_HEAP(type, n) \
+ ((type *)__get_heap(sizeof(type),__alignof__(type),(n)))
+
+static inline int heap_free(void)
+{
+ return heap_end-HEAP;
+}
+
+/* copy.S */
+
+void copy_to_fs(addr_t dst, void *src, size_t len);
+void *copy_from_fs(void *dst, addr_t src, size_t len);
+void copy_to_gs(addr_t dst, void *src, size_t len);
+void *copy_from_gs(void *dst, addr_t src, size_t len);
+void *memcpy(void *dst, void *src, size_t len);
+void *memset(void *dst, int c, size_t len);
+
+#define memcpy(d,s,l) __builtin_memcpy(d,s,l)
+#define memset(d,c,l) __builtin_memset(d,c,l)
+
+/* a20.c */
+int enable_a20(void);
+
+/* apm.c */
+int query_apm_bios(void);
+
+/* cmdline.c */
+int cmdline_find_option(const char *option, char *buffer, int bufsize);
+
+/* cpu.c, cpucheck.c */
+int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr);
+int validate_cpu(void);
+
+/* edd.c */
+void query_edd(void);
+
+/* header.S */
+void __attribute__((noreturn)) die(void);
+
+/* mca.c */
+int query_mca(void);
+
+/* memory.c */
+int detect_memory(void);
+
+/* pm.c */
+void __attribute__((noreturn)) go_to_protected_mode(void);
+
+/* pmjump.S */
+void __attribute__((noreturn))
+ protected_mode_jump(u32 entrypoint, u32 bootparams);
+
+/* printf.c */
+int sprintf(char *buf, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list args);
+int printf(const char *fmt, ...);
+
+/* string.c */
+int strcmp(const char *str1, const char *str2);
+size_t strnlen(const char *s, size_t maxlen);
+unsigned int atou(const char *s);
+
+/* tty.c */
+void puts(const char *);
+void putchar(int);
+int getchar(void);
+void kbd_flush(void);
+int getchar_timeout(void);
+
+/* video.c */
+void set_video(void);
+
+/* video-vesa.c */
+void vesa_store_edid(void);
+
+/* voyager.c */
+int query_voyager(void);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* BOOT_BOOT_H */
diff --git a/arch/i386/boot/bootsect.S b/arch/i386/boot/bootsect.S
deleted file mode 100644
index 011b7a4993d4..000000000000
--- a/arch/i386/boot/bootsect.S
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
- *
- * modified by Drew Eckhardt
- * modified by Bruce Evans (bde)
- * modified by Chris Noe (May 1999) (as86 -> gas)
- * gutted by H. Peter Anvin (Jan 2003)
- *
- * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
- * addresses must be multiplied by 16 to obtain their respective linear
- * addresses. To avoid confusion, linear addresses are written using leading
- * hex while segment addresses are written as segment:offset.
- *
- */
-
-#include <asm/boot.h>
-
-SETUPSECTS = 4 /* default nr of setup-sectors */
-BOOTSEG = 0x07C0 /* original address of boot-sector */
-INITSEG = DEF_INITSEG /* we move boot here - out of the way */
-SETUPSEG = DEF_SETUPSEG /* setup starts here */
-SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
-SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
- /* to be loaded */
-ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
-SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
-
-#ifndef SVGA_MODE
-#define SVGA_MODE ASK_VGA
-#endif
-
-#ifndef RAMDISK
-#define RAMDISK 0
-#endif
-
-#ifndef ROOT_RDONLY
-#define ROOT_RDONLY 1
-#endif
-
-.code16
-.text
-
-.global _start
-_start:
-
- # Normalize the start address
- jmpl $BOOTSEG, $start2
-
-start2:
- movw %cs, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw $0x7c00, %sp
- sti
- cld
-
- movw $bugger_off_msg, %si
-
-msg_loop:
- lodsb
- andb %al, %al
- jz die
- movb $0xe, %ah
- movw $7, %bx
- int $0x10
- jmp msg_loop
-
-die:
- # Allow the user to press a key, then reboot
- xorw %ax, %ax
- int $0x16
- int $0x19
-
- # int 0x19 should never return. In case it does anyway,
- # invoke the BIOS reset code...
- ljmp $0xf000,$0xfff0
-
-
-bugger_off_msg:
- .ascii "Direct booting from floppy is no longer supported.\r\n"
- .ascii "Please use a boot loader program instead.\r\n"
- .ascii "\n"
- .ascii "Remove disk and press any key to reboot . . .\r\n"
- .byte 0
-
-
- # Kernel attributes; used by setup
-
- .org 497
-setup_sects: .byte SETUPSECTS
-root_flags: .word ROOT_RDONLY
-syssize: .word SYSSIZE
-swap_dev: .word SWAP_DEV
-ram_size: .word RAMDISK
-vid_mode: .word SVGA_MODE
-root_dev: .word ROOT_DEV
-boot_flag: .word 0xAA55
diff --git a/arch/i386/boot/cmdline.c b/arch/i386/boot/cmdline.c
new file mode 100644
index 000000000000..34bb778c4357
--- /dev/null
+++ b/arch/i386/boot/cmdline.c
@@ -0,0 +1,97 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/cmdline.c
+ *
+ * Simple command-line parser for early boot.
+ */
+
+#include "boot.h"
+
+static inline int myisspace(u8 c)
+{
+ return c <= ' '; /* Close enough approximation */
+}
+
+/*
+ * Find a non-boolean option, that is, "option=argument". In accordance
+ * with standard Linux practice, if this option is repeated, this returns
+ * the last instance on the command line.
+ *
+ * Returns the length of the argument (regardless of if it was
+ * truncated to fit in the buffer), or -1 on not found.
+ */
+int cmdline_find_option(const char *option, char *buffer, int bufsize)
+{
+ u32 cmdline_ptr = boot_params.hdr.cmd_line_ptr;
+ addr_t cptr;
+ char c;
+ int len = -1;
+ const char *opptr = NULL;
+ char *bufptr = buffer;
+ enum {
+ st_wordstart, /* Start of word/after whitespace */
+ st_wordcmp, /* Comparing this word */
+ st_wordskip, /* Miscompare, skip */
+ st_bufcpy /* Copying this to buffer */
+ } state = st_wordstart;
+
+ if (!cmdline_ptr || cmdline_ptr >= 0x100000)
+ return -1; /* No command line, or inaccessible */
+
+ cptr = cmdline_ptr & 0xf;
+ set_fs(cmdline_ptr >> 4);
+
+ while (cptr < 0x10000 && (c = rdfs8(cptr++))) {
+ switch (state) {
+ case st_wordstart:
+ if (myisspace(c))
+ break;
+
+ /* else */
+ state = st_wordcmp;
+ opptr = option;
+ /* fall through */
+
+ case st_wordcmp:
+ if (c == '=' && !*opptr) {
+ len = 0;
+ bufptr = buffer;
+ state = st_bufcpy;
+ } else if (myisspace(c)) {
+ state = st_wordstart;
+ } else if (c != *opptr++) {
+ state = st_wordskip;
+ }
+ break;
+
+ case st_wordskip:
+ if (myisspace(c))
+ state = st_wordstart;
+ break;
+
+ case st_bufcpy:
+ if (myisspace(c)) {
+ state = st_wordstart;
+ } else {
+ if (len < bufsize-1)
+ *bufptr++ = c;
+ len++;
+ }
+ break;
+ }
+ }
+
+ if (bufsize)
+ *bufptr = '\0';
+
+ return len;
+}
diff --git a/arch/i386/boot/code16gcc.h b/arch/i386/boot/code16gcc.h
new file mode 100644
index 000000000000..3bd848093b9d
--- /dev/null
+++ b/arch/i386/boot/code16gcc.h
@@ -0,0 +1,15 @@
+/*
+ * code16gcc.h
+ *
+ * This file is -include'd when compiling 16-bit C code.
+ * Note: this asm() needs to be emitted before gcc omits any code.
+ * Depending on gcc version, this requires -fno-unit-at-a-time or
+ * -fno-toplevel-reorder.
+ *
+ * Hopefully gcc will eventually have a real -m16 option so we can
+ * drop this hack long term.
+ */
+
+#ifndef __ASSEMBLY__
+asm(".code16gcc");
+#endif
diff --git a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
index a661217f33ec..189fa1dbefcc 100644
--- a/arch/i386/boot/compressed/Makefile
+++ b/arch/i386/boot/compressed/Makefile
@@ -9,9 +9,14 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o \
EXTRA_AFLAGS := -traditional
LDFLAGS_vmlinux := -T
-CFLAGS_misc.o += -fPIC
hostprogs-y := relocs
+CFLAGS := -m32 -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
+ -fno-strict-aliasing -fPIC \
+ $(call cc-option,-ffreestanding) \
+ $(call cc-option,-fno-stack-protector)
+LDFLAGS := -m elf_i386
+
$(obj)/vmlinux: $(src)/vmlinux.lds $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
$(call if_changed,ld)
@:
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
index 3517a32aaf41..f35ea2237522 100644
--- a/arch/i386/boot/compressed/head.S
+++ b/arch/i386/boot/compressed/head.S
@@ -45,10 +45,10 @@ startup_32:
* at and where we were actually loaded at. This can only be done
* with a short local call on x86. Nothing else will tell us what
* address we are running at. The reserved chunk of the real-mode
- * data at 0x34-0x3f are used as the stack for this calculation.
- * Only 4 bytes are needed.
+ * data at 0x1e4 (defined as a scratch field) are used as the stack
+ * for this calculation. Only 4 bytes are needed.
*/
- leal 0x40(%esi), %esp
+ leal (0x1e4+4)(%esi), %esp
call 1f
1: popl %ebp
subl $1b, %ebp
diff --git a/arch/i386/boot/compressed/relocs.c b/arch/i386/boot/compressed/relocs.c
index ce4fda261aaf..2d77ee728f92 100644
--- a/arch/i386/boot/compressed/relocs.c
+++ b/arch/i386/boot/compressed/relocs.c
@@ -31,6 +31,9 @@ static const char* safe_abs_relocs[] = {
"__kernel_rt_sigreturn",
"__kernel_sigreturn",
"SYSENTER_RETURN",
+ "VDSO_NOTE_MASK",
+ "xen_irq_disable_direct_reloc",
+ "xen_save_fl_direct_reloc",
};
static int is_safe_abs_reloc(const char* sym_name)
diff --git a/arch/i386/boot/copy.S b/arch/i386/boot/copy.S
new file mode 100644
index 000000000000..ef127e56a3cf
--- /dev/null
+++ b/arch/i386/boot/copy.S
@@ -0,0 +1,101 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/copy.S
+ *
+ * Memory copy routines
+ */
+
+ .code16gcc
+ .text
+
+ .globl memcpy
+ .type memcpy, @function
+memcpy:
+ pushw %si
+ pushw %di
+ movw %ax, %di
+ movw %dx, %si
+ pushw %cx
+ shrw $2, %cx
+ rep; movsl
+ popw %cx
+ andw $3, %cx
+ rep; movsb
+ popw %di
+ popw %si
+ ret
+ .size memcpy, .-memcpy
+
+ .globl memset
+ .type memset, @function
+memset:
+ pushw %di
+ movw %ax, %di
+ movzbl %dl, %eax
+ imull $0x01010101,%eax
+ pushw %cx
+ shrw $2, %cx
+ rep; stosl
+ popw %cx
+ andw $3, %cx
+ rep; stosb
+ popw %di
+ ret
+ .size memset, .-memset
+
+ .globl copy_from_fs
+ .type copy_from_fs, @function
+copy_from_fs:
+ pushw %ds
+ pushw %fs
+ popw %ds
+ call memcpy
+ popw %ds
+ ret
+ .size copy_from_fs, .-copy_from_fs
+
+ .globl copy_to_fs
+ .type copy_to_fs, @function
+copy_to_fs:
+ pushw %es
+ pushw %fs
+ popw %es
+ call memcpy
+ popw %es
+ ret
+ .size copy_to_fs, .-copy_to_fs
+
+#if 0 /* Not currently used, but can be enabled as needed */
+
+ .globl copy_from_gs
+ .type copy_from_gs, @function
+copy_from_gs:
+ pushw %ds
+ pushw %gs
+ popw %ds
+ call memcpy
+ popw %ds
+ ret
+ .size copy_from_gs, .-copy_from_gs
+ .globl copy_to_gs
+
+ .type copy_to_gs, @function
+copy_to_gs:
+ pushw %es
+ pushw %gs
+ popw %es
+ call memcpy
+ popw %es
+ ret
+ .size copy_to_gs, .-copy_to_gs
+
+#endif
diff --git a/arch/i386/boot/cpu.c b/arch/i386/boot/cpu.c
new file mode 100644
index 000000000000..2a5c32da5852
--- /dev/null
+++ b/arch/i386/boot/cpu.c
@@ -0,0 +1,69 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/cpu.c
+ *
+ * Check for obligatory CPU features and abort if the features are not
+ * present.
+ */
+
+#include "boot.h"
+#include "bitops.h"
+#include <asm/cpufeature.h>
+
+static char *cpu_name(int level)
+{
+ static char buf[6];
+
+ if (level == 64) {
+ return "x86-64";
+ } else {
+ sprintf(buf, "i%d86", level);
+ return buf;
+ }
+}
+
+int validate_cpu(void)
+{
+ u32 *err_flags;
+ int cpu_level, req_level;
+
+ check_cpu(&cpu_level, &req_level, &err_flags);
+
+ if (cpu_level < req_level) {
+ printf("This kernel requires an %s CPU, ",
+ cpu_name(req_level));
+ printf("but only detected an %s CPU.\n",
+ cpu_name(cpu_level));
+ return -1;
+ }
+
+ if (err_flags) {
+ int i, j;
+ puts("This kernel requires the following features "
+ "not present on the CPU:\n");
+
+ for (i = 0; i < NCAPINTS; i++) {
+ u32 e = err_flags[i];
+
+ for (j = 0; j < 32; j++) {
+ if (e & 1)
+ printf("%d:%d ", i, j);
+
+ e >>= 1;
+ }
+ }
+ putchar('\n');
+ return -1;
+ } else {
+ return 0;
+ }
+}
diff --git a/arch/i386/boot/cpucheck.c b/arch/i386/boot/cpucheck.c
new file mode 100644
index 000000000000..991e8ceae1de
--- /dev/null
+++ b/arch/i386/boot/cpucheck.c
@@ -0,0 +1,267 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/cpucheck.c
+ *
+ * Check for obligatory CPU features and abort if the features are not
+ * present. This code should be compilable as 16-, 32- or 64-bit
+ * code, so be very careful with types and inline assembly.
+ *
+ * This code should not contain any messages; that requires an
+ * additional wrapper.
+ *
+ * As written, this code is not safe for inclusion into the kernel
+ * proper (after FPU initialization, in particular).
+ */
+
+#ifdef _SETUP
+# include "boot.h"
+# include "bitops.h"
+#endif
+#include <linux/types.h>
+#include <asm/cpufeature.h>
+#include <asm/processor-flags.h>
+#include <asm/required-features.h>
+#include <asm/msr-index.h>
+
+struct cpu_features {
+ int level; /* Family, or 64 for x86-64 */
+ int model;
+ u32 flags[NCAPINTS];
+};
+
+static struct cpu_features cpu;
+static u32 cpu_vendor[3];
+static u32 err_flags[NCAPINTS];
+
+#ifdef CONFIG_X86_64
+static const int req_level = 64;
+#elif defined(CONFIG_X86_MINIMUM_CPU_FAMILY)
+static const int req_level = CONFIG_X86_MINIMUM_CPU_FAMILY;
+#else
+static const int req_level = 3;
+#endif
+
+static const u32 req_flags[NCAPINTS] =
+{
+ REQUIRED_MASK0,
+ REQUIRED_MASK1,
+ REQUIRED_MASK2,
+ REQUIRED_MASK3,
+ REQUIRED_MASK4,
+ REQUIRED_MASK5,
+ REQUIRED_MASK6,
+ REQUIRED_MASK7,
+};
+
+#define A32(a,b,c,d) (((d) << 24)+((c) << 16)+((b) << 8)+(a))
+
+static int is_amd(void)
+{
+ return cpu_vendor[0] == A32('A','u','t','h') &&
+ cpu_vendor[1] == A32('e','n','t','i') &&
+ cpu_vendor[2] == A32('c','A','M','D');
+}
+
+static int is_centaur(void)
+{
+ return cpu_vendor[0] == A32('C','e','n','t') &&
+ cpu_vendor[1] == A32('a','u','r','H') &&
+ cpu_vendor[2] == A32('a','u','l','s');
+}
+
+static int is_transmeta(void)
+{
+ return cpu_vendor[0] == A32('G','e','n','u') &&
+ cpu_vendor[1] == A32('i','n','e','T') &&
+ cpu_vendor[2] == A32('M','x','8','6');
+}
+
+static int has_fpu(void)
+{
+ u16 fcw = -1, fsw = -1;
+ u32 cr0;
+
+ asm("movl %%cr0,%0" : "=r" (cr0));
+ if (cr0 & (X86_CR0_EM|X86_CR0_TS)) {
+ cr0 &= ~(X86_CR0_EM|X86_CR0_TS);
+ asm volatile("movl %0,%%cr0" : : "r" (cr0));
+ }
+
+ asm("fninit ; fnstsw %0 ; fnstcw %1" : "+m" (fsw), "+m" (fcw));
+
+ return fsw == 0 && (fcw & 0x103f) == 0x003f;
+}
+
+static int has_eflag(u32 mask)
+{
+ u32 f0, f1;
+
+ asm("pushfl ; "
+ "pushfl ; "
+ "popl %0 ; "
+ "movl %0,%1 ; "
+ "xorl %2,%1 ; "
+ "pushl %1 ; "
+ "popfl ; "
+ "pushfl ; "
+ "popl %1 ; "
+ "popfl"
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (mask));
+
+ return !!((f0^f1) & mask);
+}
+
+static void get_flags(void)
+{
+ u32 max_intel_level, max_amd_level;
+ u32 tfms;
+
+ if (has_fpu())
+ set_bit(X86_FEATURE_FPU, cpu.flags);
+
+ if (has_eflag(X86_EFLAGS_ID)) {
+ asm("cpuid"
+ : "=a" (max_intel_level),
+ "=b" (cpu_vendor[0]),
+ "=d" (cpu_vendor[1]),
+ "=c" (cpu_vendor[2])
+ : "a" (0));
+
+ if (max_intel_level >= 0x00000001 &&
+ max_intel_level <= 0x0000ffff) {
+ asm("cpuid"
+ : "=a" (tfms),
+ "=c" (cpu.flags[4]),
+ "=d" (cpu.flags[0])
+ : "a" (0x00000001)
+ : "ebx");
+ cpu.level = (tfms >> 8) & 15;
+ cpu.model = (tfms >> 4) & 15;
+ if (cpu.level >= 6)
+ cpu.model += ((tfms >> 16) & 0xf) << 4;
+ }
+
+ asm("cpuid"
+ : "=a" (max_amd_level)
+ : "a" (0x80000000)
+ : "ebx", "ecx", "edx");
+
+ if (max_amd_level >= 0x80000001 &&
+ max_amd_level <= 0x8000ffff) {
+ u32 eax = 0x80000001;
+ asm("cpuid"
+ : "+a" (eax),
+ "=c" (cpu.flags[6]),
+ "=d" (cpu.flags[1])
+ : : "ebx");
+ }
+ }
+}
+
+/* Returns a bitmask of which words we have error bits in */
+static int check_flags(void)
+{
+ u32 err;
+ int i;
+
+ err = 0;
+ for (i = 0; i < NCAPINTS; i++) {
+ err_flags[i] = req_flags[i] & ~cpu.flags[i];
+ if (err_flags[i])
+ err |= 1 << i;
+ }
+
+ return err;
+}
+
+/*
+ * Returns -1 on error.
+ *
+ * *cpu_level is set to the current CPU level; *req_level to the required
+ * level. x86-64 is considered level 64 for this purpose.
+ *
+ * *err_flags_ptr is set to the flags error array if there are flags missing.
+ */
+int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr)
+{
+ int err;
+
+ memset(&cpu.flags, 0, sizeof cpu.flags);
+ cpu.level = 3;
+
+ if (has_eflag(X86_EFLAGS_AC))
+ cpu.level = 4;
+
+ get_flags();
+ err = check_flags();
+
+ if (test_bit(X86_FEATURE_LM, cpu.flags))
+ cpu.level = 64;
+
+ if (err == 0x01 &&
+ !(err_flags[0] &
+ ~((1 << X86_FEATURE_XMM)|(1 << X86_FEATURE_XMM2))) &&
+ is_amd()) {
+ /* If this is an AMD and we're only missing SSE+SSE2, try to
+ turn them on */
+
+ u32 ecx = MSR_K7_HWCR;
+ u32 eax, edx;
+
+ asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
+ eax &= ~(1 << 15);
+ asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
+
+ get_flags(); /* Make sure it really did something */
+ err = check_flags();
+ } else if (err == 0x01 &&
+ !(err_flags[0] & ~(1 << X86_FEATURE_CX8)) &&
+ is_centaur() && cpu.model >= 6) {
+ /* If this is a VIA C3, we might have to enable CX8
+ explicitly */
+
+ u32 ecx = MSR_VIA_FCR;
+ u32 eax, edx;
+
+ asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
+ eax |= (1<<1)|(1<<7);
+ asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
+
+ set_bit(X86_FEATURE_CX8, cpu.flags);
+ err = check_flags();
+ } else if (err == 0x01 && is_transmeta()) {
+ /* Transmeta might have masked feature bits in word 0 */
+
+ u32 ecx = 0x80860004;
+ u32 eax, edx;
+ u32 level = 1;
+
+ asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx));
+ asm("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx));
+ asm("cpuid"
+ : "+a" (level), "=d" (cpu.flags[0])
+ : : "ecx", "ebx");
+ asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx));
+
+ err = check_flags();
+ }
+
+ if (err_flags_ptr)
+ *err_flags_ptr = err ? err_flags : NULL;
+ if (cpu_level_ptr)
+ *cpu_level_ptr = cpu.level;
+ if (req_level_ptr)
+ *req_level_ptr = req_level;
+
+ return (cpu.level < req_level || err) ? -1 : 0;
+}
diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S
deleted file mode 100644
index 34321368011a..000000000000
--- a/arch/i386/boot/edd.S
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * BIOS Enhanced Disk Drive support
- * Copyright (C) 2002, 2003, 2004 Dell, Inc.
- * by Matt Domsch <Matt_Domsch@dell.com> October 2002
- * conformant to T13 Committee www.t13.org
- * projects 1572D, 1484D, 1386D, 1226DT
- * disk signature read by Matt Domsch <Matt_Domsch@dell.com>
- * and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
- * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net>
- * March 2004
- * Command line option parsing, Matt Domsch, November 2004
- */
-
-#include <linux/edd.h>
-#include <asm/setup.h>
-
-#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
-
-# It is assumed that %ds == INITSEG here
-
- movb $0, (EDD_MBR_SIG_NR_BUF)
- movb $0, (EDDNR)
-
-# Check the command line for options:
-# edd=of disables EDD completely (edd=off)
-# edd=sk skips the MBR test (edd=skipmbr)
-# edd=on re-enables EDD (edd=on)
-
- pushl %esi
- movw $edd_mbr_sig_start, %di # Default to edd=on
-
- movl %cs:(cmd_line_ptr), %esi
- andl %esi, %esi
- jz old_cl # Old boot protocol?
-
-# Convert to a real-mode pointer in fs:si
- movl %esi, %eax
- shrl $4, %eax
- movw %ax, %fs
- andw $0xf, %si
- jmp have_cl_pointer
-
-# Old-style boot protocol?
-old_cl:
- push %ds # aka INITSEG
- pop %fs
-
- cmpw $0xa33f, (0x20)
- jne done_cl # No command line at all?
- movw (0x22), %si # Pointer relative to INITSEG
-
-# fs:si has the pointer to the command line now
-have_cl_pointer:
-
-# Loop through kernel command line one byte at a time. Just in
-# case the loader is buggy and failed to null-terminate the command line
-# terminate if we get close enough to the end of the segment that we
-# cannot fit "edd=XX"...
-cl_atspace:
- cmpw $-5, %si # Watch for segment wraparound
- jae done_cl
- movl %fs:(%si), %eax
- andb %al, %al # End of line?
- jz done_cl
- cmpl $EDD_CL_EQUALS, %eax
- jz found_edd_equals
- cmpb $0x20, %al # <= space consider whitespace
- ja cl_skipword
- incw %si
- jmp cl_atspace
-
-cl_skipword:
- cmpw $-5, %si # Watch for segment wraparound
- jae done_cl
- movb %fs:(%si), %al # End of string?
- andb %al, %al
- jz done_cl
- cmpb $0x20, %al
- jbe cl_atspace
- incw %si
- jmp cl_skipword
-
-found_edd_equals:
-# only looking at first two characters after equals
-# late overrides early on the command line, so keep going after finding something
- movw %fs:4(%si), %ax
- cmpw $EDD_CL_OFF, %ax # edd=of
- je do_edd_off
- cmpw $EDD_CL_SKIP, %ax # edd=sk
- je do_edd_skipmbr
- cmpw $EDD_CL_ON, %ax # edd=on
- je do_edd_on
- jmp cl_skipword
-do_edd_skipmbr:
- movw $edd_start, %di
- jmp cl_skipword
-do_edd_off:
- movw $edd_done, %di
- jmp cl_skipword
-do_edd_on:
- movw $edd_mbr_sig_start, %di
- jmp cl_skipword
-
-done_cl:
- popl %esi
- jmpw *%di
-
-# Read the first sector of each BIOS disk device and store the 4-byte signature
-edd_mbr_sig_start:
- movb $0x80, %dl # from device 80
- movw $EDD_MBR_SIG_BUF, %bx # store buffer ptr in bx
-edd_mbr_sig_read:
- movl $0xFFFFFFFF, %eax
- movl %eax, (%bx) # assume failure
- pushw %bx
- movb $READ_SECTORS, %ah
- movb $1, %al # read 1 sector
- movb $0, %dh # at head 0
- movw $1, %cx # cylinder 0, sector 0
- pushw %es
- pushw %ds
- popw %es
- movw $EDDBUF, %bx # disk's data goes into EDDBUF
- pushw %dx # work around buggy BIOSes
- stc # work around buggy BIOSes
- int $0x13
- sti # work around buggy BIOSes
- popw %dx
- popw %es
- popw %bx
- jc edd_mbr_sig_done # on failure, we're done.
- cmpb $0, %ah # some BIOSes do not set CF
- jne edd_mbr_sig_done # on failure, we're done.
- movl (EDDBUF+EDD_MBR_SIG_OFFSET), %eax # read sig out of the MBR
- movl %eax, (%bx) # store success
- incb (EDD_MBR_SIG_NR_BUF) # note that we stored something
- incb %dl # increment to next device
- addw $4, %bx # increment sig buffer ptr
- cmpb $EDD_MBR_SIG_MAX, (EDD_MBR_SIG_NR_BUF) # Out of space?
- jb edd_mbr_sig_read # keep looping
-edd_mbr_sig_done:
-
-# Do the BIOS Enhanced Disk Drive calls
-# This consists of two calls:
-# int 13h ah=41h "Check Extensions Present"
-# int 13h ah=48h "Get Device Parameters"
-# int 13h ah=08h "Legacy Get Device Parameters"
-#
-# A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use
-# in the boot_params at EDDBUF. The first four bytes of which are
-# used to store the device number, interface support map and version
-# results from fn41. The next four bytes are used to store the legacy
-# cylinders, heads, and sectors from fn08. The following 74 bytes are used to
-# store the results from fn48. Starting from device 80h, fn41, then fn48
-# are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE).
-# Then the pointer is incremented to store the data for the next call.
-# This repeats until either a device doesn't exist, or until EDDMAXNR
-# devices have been stored.
-# The one tricky part is that ds:si always points EDDEXTSIZE bytes into
-# the structure, and the fn41 and fn08 results are stored at offsets
-# from there. This removes the need to increment the pointer for
-# every store, and leaves it ready for the fn48 call.
-# A second one-byte buffer, EDDNR, in the boot_params stores
-# the number of BIOS devices which exist, up to EDDMAXNR.
-# In setup.c, copy_edd() stores both boot_params buffers away
-# for later use, as they would get overwritten otherwise.
-# This code is sensitive to the size of the structs in edd.h
-edd_start:
- # %ds points to the bootsector
- # result buffer for fn48
- movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results
- # kept just before that
- movb $0x80, %dl # BIOS device 0x80
-
-edd_check_ext:
- movb $CHECKEXTENSIONSPRESENT, %ah # Function 41
- movw $EDDMAGIC1, %bx # magic
- int $0x13 # make the call
- jc edd_done # no more BIOS devices
-
- cmpw $EDDMAGIC2, %bx # is magic right?
- jne edd_next # nope, next...
-
- movb %dl, %ds:-8(%si) # store device number
- movb %ah, %ds:-7(%si) # store version
- movw %cx, %ds:-6(%si) # store extensions
- incb (EDDNR) # note that we stored something
-
-edd_get_device_params:
- movw $EDDPARMSIZE, %ds:(%si) # put size
- movw $0x0, %ds:2(%si) # work around buggy BIOSes
- movb $GETDEVICEPARAMETERS, %ah # Function 48
- int $0x13 # make the call
- # Don't check for fail return
- # it doesn't matter.
-edd_get_legacy_chs:
- xorw %ax, %ax
- movw %ax, %ds:-4(%si)
- movw %ax, %ds:-2(%si)
- # Ralf Brown's Interrupt List says to set ES:DI to
- # 0000h:0000h "to guard against BIOS bugs"
- pushw %es
- movw %ax, %es
- movw %ax, %di
- pushw %dx # legacy call clobbers %dl
- movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08
- int $0x13 # make the call
- jc edd_legacy_done # failed
- movb %cl, %al # Low 6 bits are max
- andb $0x3F, %al # sector number
- movb %al, %ds:-1(%si) # Record max sect
- movb %dh, %ds:-2(%si) # Record max head number
- movb %ch, %al # Low 8 bits of max cyl
- shr $6, %cl
- movb %cl, %ah # High 2 bits of max cyl
- movw %ax, %ds:-4(%si)
-
-edd_legacy_done:
- popw %dx
- popw %es
- movw %si, %ax # increment si
- addw $EDDPARMSIZE+EDDEXTSIZE, %ax
- movw %ax, %si
-
-edd_next:
- incb %dl # increment to next device
- cmpb $EDDMAXNR, (EDDNR) # Out of space?
- jb edd_check_ext # keep looping
-
-edd_done:
-#endif
diff --git a/arch/i386/boot/edd.c b/arch/i386/boot/edd.c
new file mode 100644
index 000000000000..25a282494f4c
--- /dev/null
+++ b/arch/i386/boot/edd.c
@@ -0,0 +1,196 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/edd.c
+ *
+ * Get EDD BIOS disk information
+ */
+
+#include "boot.h"
+#include <linux/edd.h>
+
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+
+struct edd_dapa {
+ u8 pkt_size;
+ u8 rsvd;
+ u16 sector_cnt;
+ u16 buf_off, buf_seg;
+ u64 lba;
+ u64 buf_lin_addr;
+};
+
+/*
+ * Read the MBR (first sector) from a specific device.
+ */
+static int read_mbr(u8 devno, void *buf)
+{
+ struct edd_dapa dapa;
+ u16 ax, bx, cx, dx, si;
+
+ memset(&dapa, 0, sizeof dapa);
+ dapa.pkt_size = sizeof(dapa);
+ dapa.sector_cnt = 1;
+ dapa.buf_off = (size_t)buf;
+ dapa.buf_seg = ds();
+ /* dapa.lba = 0; */
+
+ ax = 0x4200; /* Extended Read */
+ si = (size_t)&dapa;
+ dx = devno;
+ asm("pushfl; stc; int $0x13; setc %%al; popfl"
+ : "+a" (ax), "+S" (si), "+d" (dx)
+ : "m" (dapa)
+ : "ebx", "ecx", "edi", "memory");
+
+ if (!(u8)ax)
+ return 0; /* OK */
+
+ ax = 0x0201; /* Legacy Read, one sector */
+ cx = 0x0001; /* Sector 0-0-1 */
+ dx = devno;
+ bx = (size_t)buf;
+ asm("pushfl; stc; int $0x13; setc %%al; popfl"
+ : "+a" (ax), "+c" (cx), "+d" (dx), "+b" (bx)
+ : : "esi", "edi", "memory");
+
+ return -(u8)ax; /* 0 or -1 */
+}
+
+static u32 read_mbr_sig(u8 devno, struct edd_info *ei)
+{
+ int sector_size;
+ char *mbrbuf_ptr, *mbrbuf_end;
+ u32 mbrsig;
+ u32 buf_base, mbr_base;
+ extern char _end[];
+ static char mbr_buf[1024];
+
+ sector_size = ei->params.bytes_per_sector;
+ if (!sector_size)
+ sector_size = 512; /* Best available guess */
+
+ buf_base = (ds() << 4) + (u32)&_end;
+ mbr_base = (buf_base+sector_size-1) & ~(sector_size-1);
+ mbrbuf_ptr = mbr_buf + (mbr_base-buf_base);
+ mbrbuf_end = mbrbuf_ptr + sector_size;
+
+ if (!(boot_params.hdr.loadflags & CAN_USE_HEAP))
+ return 0;
+ if (mbrbuf_end > (char *)(size_t)boot_params.hdr.heap_end_ptr)
+ return 0;
+
+ if (read_mbr(devno, mbrbuf_ptr))
+ return 0;
+
+ mbrsig = *(u32 *)&mbrbuf_ptr[EDD_MBR_SIG_OFFSET];
+ return mbrsig;
+}
+
+static int get_edd_info(u8 devno, struct edd_info *ei)
+{
+ u16 ax, bx, cx, dx, di;
+
+ memset(ei, 0, sizeof *ei);
+
+ /* Check Extensions Present */
+
+ ax = 0x4100;
+ bx = EDDMAGIC1;
+ dx = devno;
+ asm("pushfl; stc; int $0x13; setc %%al; popfl"
+ : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx)
+ : : "esi", "edi");
+
+ if ((u8)ax)
+ return -1; /* No extended information */
+
+ if (bx != EDDMAGIC2)
+ return -1;
+
+ ei->device = devno;
+ ei->version = ax >> 8; /* EDD version number */
+ ei->interface_support = cx; /* EDD functionality subsets */
+
+ /* Extended Get Device Parameters */
+
+ ei->params.length = sizeof(ei->params);
+ ax = 0x4800;
+ dx = devno;
+ asm("pushfl; int $0x13; popfl"
+ : "+a" (ax), "+d" (dx)
+ : "S" (&ei->params)
+ : "ebx", "ecx", "edi");
+
+ /* Get legacy CHS parameters */
+
+ /* Ralf Brown recommends setting ES:DI to 0:0 */
+ ax = 0x0800;
+ dx = devno;
+ di = 0;
+ asm("pushw %%es; "
+ "movw %%di,%%es; "
+ "pushfl; stc; int $0x13; setc %%al; popfl; "
+ "popw %%es"
+ : "+a" (ax), "=b" (bx), "=c" (cx), "+d" (dx), "+D" (di)
+ : : "esi");
+
+ if ((u8)ax == 0) {
+ ei->legacy_max_cylinder = (cx >> 8) + ((cx & 0xc0) << 2);
+ ei->legacy_max_head = dx >> 8;
+ ei->legacy_sectors_per_track = cx & 0x3f;
+ }
+
+ return 0;
+}
+
+void query_edd(void)
+{
+ char eddarg[8];
+ int do_mbr = 1;
+ int do_edd = 1;
+ int devno;
+ struct edd_info ei, *edp;
+
+ if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) {
+ if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip"))
+ do_mbr = 0;
+ else if (!strcmp(eddarg, "off"))
+ do_edd = 0;
+ }
+
+ edp = (struct edd_info *)boot_params.eddbuf;
+
+ if (!do_edd)
+ return;
+
+ for (devno = 0x80; devno < 0x80+EDD_MBR_SIG_MAX; devno++) {
+ /*
+ * Scan the BIOS-supported hard disks and query EDD
+ * information...
+ */
+ get_edd_info(devno, &ei);
+
+ if (boot_params.eddbuf_entries < EDDMAXNR) {
+ memcpy(edp, &ei, sizeof ei);
+ edp++;
+ boot_params.eddbuf_entries++;
+ }
+
+ if (do_mbr) {
+ u32 mbr_sig;
+ mbr_sig = read_mbr_sig(devno, &ei);
+ boot_params.edd_mbr_sig_buffer[devno-0x80] = mbr_sig;
+ }
+ }
+}
+
+#endif
diff --git a/arch/i386/boot/header.S b/arch/i386/boot/header.S
new file mode 100644
index 000000000000..6b9923fb6eae
--- /dev/null
+++ b/arch/i386/boot/header.S
@@ -0,0 +1,283 @@
+/*
+ * header.S
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Based on bootsect.S and setup.S
+ * modified by more people than can be counted
+ *
+ * Rewritten as a common file by H. Peter Anvin (Apr 2007)
+ *
+ * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
+ * addresses must be multiplied by 16 to obtain their respective linear
+ * addresses. To avoid confusion, linear addresses are written using leading
+ * hex while segment addresses are written as segment:offset.
+ *
+ */
+
+#include <asm/segment.h>
+#include <linux/utsrelease.h>
+#include <asm/boot.h>
+#include <asm/e820.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include "boot.h"
+
+SETUPSECTS = 4 /* default nr of setup-sectors */
+BOOTSEG = 0x07C0 /* original address of boot-sector */
+SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
+SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
+ /* to be loaded */
+ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
+SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
+
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
+
+#ifndef RAMDISK
+#define RAMDISK 0
+#endif
+
+#ifndef ROOT_RDONLY
+#define ROOT_RDONLY 1
+#endif
+
+ .code16
+ .section ".bstext", "ax"
+
+ .global bootsect_start
+bootsect_start:
+
+ # Normalize the start address
+ ljmp $BOOTSEG, $start2
+
+start2:
+ movw %cs, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ xorw %sp, %sp
+ sti
+ cld
+
+ movw $bugger_off_msg, %si
+
+msg_loop:
+ lodsb
+ andb %al, %al
+ jz bs_die
+ movb $0xe, %ah
+ movw $7, %bx
+ int $0x10
+ jmp msg_loop
+
+bs_die:
+ # Allow the user to press a key, then reboot
+ xorw %ax, %ax
+ int $0x16
+ int $0x19
+
+ # int 0x19 should never return. In case it does anyway,
+ # invoke the BIOS reset code...
+ ljmp $0xf000,$0xfff0
+
+ .section ".bsdata", "a"
+bugger_off_msg:
+ .ascii "Direct booting from floppy is no longer supported.\r\n"
+ .ascii "Please use a boot loader program instead.\r\n"
+ .ascii "\n"
+ .ascii "Remove disk and press any key to reboot . . .\r\n"
+ .byte 0
+
+
+ # Kernel attributes; used by setup. This is part 1 of the
+ # header, from the old boot sector.
+
+ .section ".header", "a"
+ .globl hdr
+hdr:
+setup_sects: .byte SETUPSECTS
+root_flags: .word ROOT_RDONLY
+syssize: .long SYSSIZE
+ram_size: .word RAMDISK
+vid_mode: .word SVGA_MODE
+root_dev: .word ROOT_DEV
+boot_flag: .word 0xAA55
+
+ # offset 512, entry point
+
+ .globl _start
+_start:
+ # Explicitly enter this as bytes, or the assembler
+ # tries to generate a 3-byte jump here, which causes
+ # everything else to push off to the wrong offset.
+ .byte 0xeb # short (2-byte) jump
+ .byte start_of_setup-1f
+1:
+
+ # Part 2 of the header, from the old setup.S
+
+ .ascii "HdrS" # header signature
+ .word 0x0206 # header version number (>= 0x0105)
+ # or else old loadlin-1.5 will fail)
+ .globl realmode_swtch
+realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
+start_sys_seg: .word SYSSEG
+ .word kernel_version-512 # pointing to kernel version string
+ # above section of header is compatible
+ # with loadlin-1.5 (header v1.5). Don't
+ # change it.
+
+type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
+ # Bootlin, SYSLX, bootsect...)
+ # See Documentation/i386/boot.txt for
+ # assigned ids
+
+# flags, unused bits must be zero (RFU) bit within loadflags
+loadflags:
+LOADED_HIGH = 1 # If set, the kernel is loaded high
+CAN_USE_HEAP = 0x80 # If set, the loader also has set
+ # heap_end_ptr to tell how much
+ # space behind setup.S can be used for
+ # heap purposes.
+ # Only the loader knows what is free
+#ifndef __BIG_KERNEL__
+ .byte 0
+#else
+ .byte LOADED_HIGH
+#endif
+
+setup_move_size: .word 0x8000 # size to move, when setup is not
+ # loaded at 0x90000. We will move setup
+ # to 0x90000 then just before jumping
+ # into the kernel. However, only the
+ # loader knows how much data behind
+ # us also needs to be loaded.
+
+code32_start: # here loaders can put a different
+ # start address for 32-bit code.
+#ifndef __BIG_KERNEL__
+ .long 0x1000 # 0x1000 = default for zImage
+#else
+ .long 0x100000 # 0x100000 = default for big kernel
+#endif
+
+ramdisk_image: .long 0 # address of loaded ramdisk image
+ # Here the loader puts the 32-bit
+ # address where it loaded the image.
+ # This only will be read by the kernel.
+
+ramdisk_size: .long 0 # its size in bytes
+
+bootsect_kludge:
+ .long 0 # obsolete
+
+heap_end_ptr: .word _end+1024 # (Header version 0x0201 or later)
+ # space from here (exclusive) down to
+ # end of setup code can be used by setup
+ # for local heap purposes.
+
+pad1: .word 0
+cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
+ # If nonzero, a 32-bit pointer
+ # to the kernel command line.
+ # The command line should be
+ # located between the start of
+ # setup and the end of low
+ # memory (0xa0000), or it may
+ # get overwritten before it
+ # gets read. If this field is
+ # used, there is no longer
+ # anything magical about the
+ # 0x90000 segment; the setup
+ # can be located anywhere in
+ # low memory 0x10000 or higher.
+
+ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
+ # (Header version 0x0203 or later)
+ # The highest safe address for
+ # the contents of an initrd
+
+kernel_alignment: .long CONFIG_PHYSICAL_ALIGN #physical addr alignment
+ #required for protected mode
+ #kernel
+#ifdef CONFIG_RELOCATABLE
+relocatable_kernel: .byte 1
+#else
+relocatable_kernel: .byte 0
+#endif
+pad2: .byte 0
+pad3: .word 0
+
+cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
+ #added with boot protocol
+ #version 2.06
+
+# End of setup header #####################################################
+
+ .section ".inittext", "ax"
+start_of_setup:
+#ifdef SAFE_RESET_DISK_CONTROLLER
+# Reset the disk controller.
+ movw $0x0000, %ax # Reset disk controller
+ movb $0x80, %dl # All disks
+ int $0x13
+#endif
+
+# We will have entired with %cs = %ds+0x20, normalize %cs so
+# it is on par with the other segments.
+ pushw %ds
+ pushw $setup2
+ lretw
+
+setup2:
+# Force %es = %ds
+ movw %ds, %ax
+ movw %ax, %es
+ cld
+
+# Stack paranoia: align the stack and make sure it is good
+# for both 16- and 32-bit references. In particular, if we
+# were meant to have been using the full 16-bit segment, the
+# caller might have set %sp to zero, which breaks %esp-based
+# references.
+ andw $~3, %sp # dword align (might as well...)
+ jnz 1f
+ movw $0xfffc, %sp # Make sure we're not zero
+1: movzwl %sp, %esp # Clear upper half of %esp
+ sti
+
+# Check signature at end of setup
+ cmpl $0x5a5aaa55, setup_sig
+ jne setup_bad
+
+# Zero the bss
+ movw $__bss_start, %di
+ movw $_end+3, %cx
+ xorl %eax, %eax
+ subw %di, %cx
+ shrw $2, %cx
+ rep; stosl
+
+# Jump to C code (should not return)
+ calll main
+
+# Setup corrupt somehow...
+setup_bad:
+ movl $setup_corrupt, %eax
+ calll puts
+ # Fall through...
+
+ .globl die
+ .type die, @function
+die:
+ hlt
+ jmp die
+
+ .size die, .-due
+
+ .section ".initdata", "a"
+setup_corrupt:
+ .byte 7
+ .string "No setup signature found..."
diff --git a/arch/i386/boot/main.c b/arch/i386/boot/main.c
new file mode 100644
index 000000000000..7f01f96c4fb8
--- /dev/null
+++ b/arch/i386/boot/main.c
@@ -0,0 +1,161 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/main.c
+ *
+ * Main module for the real-mode kernel code
+ */
+
+#include "boot.h"
+
+struct boot_params boot_params __attribute__((aligned(16)));
+
+char *HEAP = _end;
+char *heap_end = _end; /* Default end of heap = no heap */
+
+/*
+ * Copy the header into the boot parameter block. Since this
+ * screws up the old-style command line protocol, adjust by
+ * filling in the new-style command line pointer instead.
+ */
+#define OLD_CL_MAGIC 0xA33F
+#define OLD_CL_ADDRESS 0x20
+
+static void copy_boot_params(void)
+{
+ struct old_cmdline {
+ u16 cl_magic;
+ u16 cl_offset;
+ };
+ const struct old_cmdline * const oldcmd =
+ (const struct old_cmdline *)OLD_CL_ADDRESS;
+
+ BUILD_BUG_ON(sizeof boot_params != 4096);
+ memcpy(&boot_params.hdr, &hdr, sizeof hdr);
+
+ if (!boot_params.hdr.cmd_line_ptr &&
+ oldcmd->cl_magic == OLD_CL_MAGIC) {
+ /* Old-style command line protocol. */
+ u16 cmdline_seg;
+
+ /* Figure out if the command line falls in the region
+ of memory that an old kernel would have copied up
+ to 0x90000... */
+ if (oldcmd->cl_offset < boot_params.hdr.setup_move_size)
+ cmdline_seg = ds();
+ else
+ cmdline_seg = 0x9000;
+
+ boot_params.hdr.cmd_line_ptr =
+ (cmdline_seg << 4) + oldcmd->cl_offset;
+ }
+}
+
+/*
+ * Set the keyboard repeat rate to maximum. Unclear why this
+ * is done here; this might be possible to kill off as stale code.
+ */
+static void keyboard_set_repeat(void)
+{
+ u16 ax = 0x0305;
+ u16 bx = 0;
+ asm volatile("int $0x16"
+ : "+a" (ax), "+b" (bx)
+ : : "ecx", "edx", "esi", "edi");
+}
+
+/*
+ * Get Intel SpeedStep IST information.
+ */
+static void query_speedstep_ist(void)
+{
+ asm("int $0x15"
+ : "=a" (boot_params.speedstep_info[0]),
+ "=b" (boot_params.speedstep_info[1]),
+ "=c" (boot_params.speedstep_info[2]),
+ "=d" (boot_params.speedstep_info[3])
+ : "a" (0x0000e980), /* IST Support */
+ "d" (0x47534943)); /* Request value */
+}
+
+/*
+ * Tell the BIOS what CPU mode we intend to run in.
+ */
+static void set_bios_mode(void)
+{
+#ifdef CONFIG_X86_64
+ u32 eax, ebx;
+
+ eax = 0xec00;
+ ebx = 2;
+ asm volatile("int $0x15"
+ : "+a" (eax), "+b" (ebx)
+ : : "ecx", "edx", "esi", "edi");
+#endif
+}
+
+void main(void)
+{
+ /* First, copy the boot header into the "zeropage" */
+ copy_boot_params();
+
+ /* End of heap check */
+ if (boot_params.hdr.loadflags & CAN_USE_HEAP) {
+ heap_end = (char *)(boot_params.hdr.heap_end_ptr
+ +0x200-STACK_SIZE);
+ } else {
+ /* Boot protocol 2.00 only, no heap available */
+ puts("WARNING: Ancient bootloader, some functionality "
+ "may be limited!\n");
+ }
+
+ /* Make sure we have all the proper CPU support */
+ if (validate_cpu()) {
+ puts("Unable to boot - please use a kernel appropriate "
+ "for your CPU.\n");
+ die();
+ }
+
+ /* Tell the BIOS what CPU mode we intend to run in. */
+ set_bios_mode();
+
+ /* Detect memory layout */
+ detect_memory();
+
+ /* Set keyboard repeat rate (why?) */
+ keyboard_set_repeat();
+
+ /* Set the video mode */
+ set_video();
+
+ /* Query MCA information */
+ query_mca();
+
+ /* Voyager */
+#ifdef CONFIG_X86_VOYAGER
+ query_voyager();
+#endif
+
+ /* Query SpeedStep IST information */
+ query_speedstep_ist();
+
+ /* Query APM information */
+#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
+ query_apm_bios();
+#endif
+
+ /* Query EDD information */
+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
+ query_edd();
+#endif
+ /* Do the last things and invoke protected mode */
+ go_to_protected_mode();
+}
diff --git a/arch/i386/boot/mca.c b/arch/i386/boot/mca.c
new file mode 100644
index 000000000000..68222f2d4b67
--- /dev/null
+++ b/arch/i386/boot/mca.c
@@ -0,0 +1,43 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/mca.c
+ *
+ * Get the MCA system description table
+ */
+
+#include "boot.h"
+
+int query_mca(void)
+{
+ u8 err;
+ u16 es, bx, len;
+
+ asm("pushw %%es ; "
+ "int $0x15 ; "
+ "setc %0 ; "
+ "movw %%es, %1 ; "
+ "popw %%es"
+ : "=acd" (err), "=acdSD" (es), "=b" (bx)
+ : "a" (0xc000));
+
+ if (err)
+ return -1; /* No MCA present */
+
+ set_fs(es);
+ len = rdfs16(bx);
+
+ if (len > sizeof(boot_params.sys_desc_table))
+ len = sizeof(boot_params.sys_desc_table);
+
+ copy_from_fs(&boot_params.sys_desc_table, bx, len);
+ return 0;
+}
diff --git a/arch/i386/boot/memory.c b/arch/i386/boot/memory.c
new file mode 100644
index 000000000000..1a2e62db8bed
--- /dev/null
+++ b/arch/i386/boot/memory.c
@@ -0,0 +1,99 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/memory.c
+ *
+ * Memory detection code
+ */
+
+#include "boot.h"
+
+#define SMAP 0x534d4150 /* ASCII "SMAP" */
+
+static int detect_memory_e820(void)
+{
+ u32 next = 0;
+ u32 size, id;
+ u8 err;
+ struct e820entry *desc = boot_params.e820_map;
+
+ do {
+ size = sizeof(struct e820entry);
+ id = SMAP;
+ asm("int $0x15; setc %0"
+ : "=am" (err), "+b" (next), "+d" (id), "+c" (size),
+ "=m" (*desc)
+ : "D" (desc), "a" (0xe820));
+
+ if (err || id != SMAP)
+ break;
+
+ boot_params.e820_entries++;
+ desc++;
+ } while (next && boot_params.e820_entries < E820MAX);
+
+ return boot_params.e820_entries;
+}
+
+static int detect_memory_e801(void)
+{
+ u16 ax, bx, cx, dx;
+ u8 err;
+
+ bx = cx = dx = 0;
+ ax = 0xe801;
+ asm("stc; int $0x15; setc %0"
+ : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx));
+
+ if (err)
+ return -1;
+
+ /* Do we really need to do this? */
+ if (cx || dx) {
+ ax = cx;
+ bx = dx;
+ }
+
+ if (ax > 15*1024)
+ return -1; /* Bogus! */
+
+ /* This ignores memory above 16MB if we have a memory hole
+ there. If someone actually finds a machine with a memory
+ hole at 16MB and no support for 0E820h they should probably
+ generate a fake e820 map. */
+ boot_params.alt_mem_k = (ax == 15*1024) ? (dx << 6)+ax : ax;
+
+ return 0;
+}
+
+static int detect_memory_88(void)
+{
+ u16 ax;
+ u8 err;
+
+ ax = 0x8800;
+ asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax));
+
+ boot_params.screen_info.ext_mem_k = ax;
+
+ return -err;
+}
+
+int detect_memory(void)
+{
+ if (detect_memory_e820() > 0)
+ return 0;
+
+ if (!detect_memory_e801())
+ return 0;
+
+ return detect_memory_88();
+}
diff --git a/arch/i386/boot/pm.c b/arch/i386/boot/pm.c
new file mode 100644
index 000000000000..1df025c73261
--- /dev/null
+++ b/arch/i386/boot/pm.c
@@ -0,0 +1,170 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/pm.c
+ *
+ * Prepare the machine for transition to protected mode.
+ */
+
+#include "boot.h"
+#include <asm/segment.h>
+
+/*
+ * Invoke the realmode switch hook if present; otherwise
+ * disable all interrupts.
+ */
+static void realmode_switch_hook(void)
+{
+ if (boot_params.hdr.realmode_swtch) {
+ asm volatile("lcallw *%0"
+ : : "m" (boot_params.hdr.realmode_swtch)
+ : "eax", "ebx", "ecx", "edx");
+ } else {
+ asm volatile("cli");
+ outb(0x80, 0x70); /* Disable NMI */
+ io_delay();
+ }
+}
+
+/*
+ * A zImage kernel is loaded at 0x10000 but wants to run at 0x1000.
+ * A bzImage kernel is loaded and runs at 0x100000.
+ */
+static void move_kernel_around(void)
+{
+ /* Note: rely on the compile-time option here rather than
+ the LOADED_HIGH flag. The Qemu kernel loader unconditionally
+ sets the loadflags to zero. */
+#ifndef __BIG_KERNEL__
+ u16 dst_seg, src_seg;
+ u32 syssize;
+
+ dst_seg = 0x1000 >> 4;
+ src_seg = 0x10000 >> 4;
+ syssize = boot_params.hdr.syssize; /* Size in 16-byte paragraphs */
+
+ while (syssize) {
+ int paras = (syssize >= 0x1000) ? 0x1000 : syssize;
+ int dwords = paras << 2;
+
+ asm volatile("pushw %%es ; "
+ "pushw %%ds ; "
+ "movw %1,%%es ; "
+ "movw %2,%%ds ; "
+ "xorw %%di,%%di ; "
+ "xorw %%si,%%si ; "
+ "rep;movsl ; "
+ "popw %%ds ; "
+ "popw %%es"
+ : "+c" (dwords)
+ : "r" (dst_seg), "r" (src_seg)
+ : "esi", "edi");
+
+ syssize -= paras;
+ dst_seg += paras;
+ src_seg += paras;
+ }
+#endif
+}
+
+/*
+ * Disable all interrupts at the legacy PIC.
+ */
+static void mask_all_interrupts(void)
+{
+ outb(0xff, 0xa1); /* Mask all interrupts on the seconday PIC */
+ io_delay();
+ outb(0xfb, 0x21); /* Mask all but cascade on the primary PIC */
+ io_delay();
+}
+
+/*
+ * Reset IGNNE# if asserted in the FPU.
+ */
+static void reset_coprocessor(void)
+{
+ outb(0, 0xf0);
+ io_delay();
+ outb(0, 0xf1);
+ io_delay();
+}
+
+/*
+ * Set up the GDT
+ */
+#define GDT_ENTRY(flags,base,limit) \
+ (((u64)(base & 0xff000000) << 32) | \
+ ((u64)flags << 40) | \
+ ((u64)(limit & 0x00ff0000) << 32) | \
+ ((u64)(base & 0x00ffff00) << 16) | \
+ ((u64)(limit & 0x0000ffff)))
+
+struct gdt_ptr {
+ u16 len;
+ u32 ptr;
+} __attribute__((packed));
+
+static void setup_gdt(void)
+{
+ /* There are machines which are known to not boot with the GDT
+ being 8-byte unaligned. Intel recommends 16 byte alignment. */
+ static const u64 boot_gdt[] __attribute__((aligned(16))) = {
+ /* CS: code, read/execute, 4 GB, base 0 */
+ [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff),
+ /* DS: data, read/write, 4 GB, base 0 */
+ [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff),
+ };
+ struct gdt_ptr gdt;
+
+ gdt.len = sizeof(boot_gdt)-1;
+ gdt.ptr = (u32)&boot_gdt + (ds() << 4);
+
+ asm volatile("lgdtl %0" : : "m" (gdt));
+}
+
+/*
+ * Set up the IDT
+ */
+static void setup_idt(void)
+{
+ static const struct gdt_ptr null_idt = {0, 0};
+ asm volatile("lidtl %0" : : "m" (null_idt));
+}
+
+/*
+ * Actual invocation sequence
+ */
+void go_to_protected_mode(void)
+{
+ /* Hook before leaving real mode, also disables interrupts */
+ realmode_switch_hook();
+
+ /* Move the kernel/setup to their final resting places */
+ move_kernel_around();
+
+ /* Enable the A20 gate */
+ if (enable_a20()) {
+ puts("A20 gate not responding, unable to boot...\n");
+ die();
+ }
+
+ /* Reset coprocessor (IGNNE#) */
+ reset_coprocessor();
+
+ /* Mask all interrupts in the PIC */
+ mask_all_interrupts();
+
+ /* Actual transition to protected mode... */
+ setup_idt();
+ setup_gdt();
+ protected_mode_jump(boot_params.hdr.code32_start,
+ (u32)&boot_params + (ds() << 4));
+}
diff --git a/arch/i386/boot/pmjump.S b/arch/i386/boot/pmjump.S
new file mode 100644
index 000000000000..2e559233725a
--- /dev/null
+++ b/arch/i386/boot/pmjump.S
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/pmjump.S
+ *
+ * The actual transition into protected mode
+ */
+
+#include <asm/boot.h>
+#include <asm/segment.h>
+
+ .text
+
+ .globl protected_mode_jump
+ .type protected_mode_jump, @function
+
+ .code16
+
+/*
+ * void protected_mode_jump(u32 entrypoint, u32 bootparams);
+ */
+protected_mode_jump:
+ xorl %ebx, %ebx # Flag to indicate this is a boot
+ movl %edx, %esi # Pointer to boot_params table
+ movl %eax, 2f # Patch ljmpl instruction
+ jmp 1f # Short jump to flush instruction q.
+
+1:
+ movw $__BOOT_DS, %cx
+
+ movl %cr0, %edx
+ orb $1, %dl # Protected mode (PE) bit
+ movl %edx, %cr0
+
+ movw %cx, %ds
+ movw %cx, %es
+ movw %cx, %fs
+ movw %cx, %gs
+ movw %cx, %ss
+
+ # Jump to the 32-bit entrypoint
+ .byte 0x66, 0xea # ljmpl opcode
+2: .long 0 # offset
+ .word __BOOT_CS # segment
+
+ .size protected_mode_jump, .-protected_mode_jump
diff --git a/arch/i386/boot/printf.c b/arch/i386/boot/printf.c
new file mode 100644
index 000000000000..1a09f9309d3c
--- /dev/null
+++ b/arch/i386/boot/printf.c
@@ -0,0 +1,307 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/printf.c
+ *
+ * Oh, it's a waste of space, but oh-so-yummy for debugging. This
+ * version of printf() does not include 64-bit support. "Live with
+ * it."
+ *
+ */
+
+#include "boot.h"
+
+static int skip_atoi(const char **s)
+{
+ int i = 0;
+
+ while (isdigit(**s))
+ i = i * 10 + *((*s)++) - '0';
+ return i;
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static char *number(char *str, long num, int base, int size, int precision,
+ int type)
+{
+ char c, sign, tmp[66];
+ const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+ int i;
+
+ if (type & LARGE)
+ digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if (type & LEFT)
+ type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN) {
+ if (num < 0) {
+ sign = '-';
+ num = -num;
+ size--;
+ } else if (type & PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++] = '0';
+ else
+ while (num != 0)
+ tmp[i++] = digits[do_div(num, base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type & (ZEROPAD + LEFT)))
+ while (size-- > 0)
+ *str++ = ' ';
+ if (sign)
+ *str++ = sign;
+ if (type & SPECIAL) {
+ if (base == 8)
+ *str++ = '0';
+ else if (base == 16) {
+ *str++ = '0';
+ *str++ = digits[33];
+ }
+ }
+ if (!(type & LEFT))
+ while (size-- > 0)
+ *str++ = c;
+ while (i < precision--)
+ *str++ = '0';
+ while (i-- > 0)
+ *str++ = tmp[i];
+ while (size-- > 0)
+ *str++ = ' ';
+ return str;
+}
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ int len;
+ unsigned long num;
+ int i, base;
+ char *str;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+
+ for (str = buf; *fmt; ++fmt) {
+ if (*fmt != '%') {
+ *str++ = *fmt;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+ repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-':
+ flags |= LEFT;
+ goto repeat;
+ case '+':
+ flags |= PLUS;
+ goto repeat;
+ case ' ':
+ flags |= SPACE;
+ goto repeat;
+ case '#':
+ flags |= SPECIAL;
+ goto repeat;
+ case '0':
+ flags |= ZEROPAD;
+ goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (isdigit(*fmt))
+ precision = skip_atoi(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ qualifier = *fmt;
+ ++fmt;
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT))
+ while (--field_width > 0)
+ *str++ = ' ';
+ *str++ = (unsigned char)va_arg(args, int);
+ while (--field_width > 0)
+ *str++ = ' ';
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ *str++ = ' ';
+ for (i = 0; i < len; ++i)
+ *str++ = *s++;
+ while (len < field_width--)
+ *str++ = ' ';
+ continue;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 2 * sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ str = number(str,
+ (unsigned long)va_arg(args, void *), 16,
+ field_width, precision, flags);
+ continue;
+
+ case 'n':
+ if (qualifier == 'l') {
+ long *ip = va_arg(args, long *);
+ *ip = (str - buf);
+ } else {
+ int *ip = va_arg(args, int *);
+ *ip = (str - buf);
+ }
+ continue;
+
+ case '%':
+ *str++ = '%';
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ *str++ = '%';
+ if (*fmt)
+ *str++ = *fmt;
+ else
+ --fmt;
+ continue;
+ }
+ if (qualifier == 'l')
+ num = va_arg(args, unsigned long);
+ else if (qualifier == 'h') {
+ num = (unsigned short)va_arg(args, int);
+ if (flags & SIGN)
+ num = (short)num;
+ } else if (flags & SIGN)
+ num = va_arg(args, int);
+ else
+ num = va_arg(args, unsigned int);
+ str = number(str, num, base, field_width, precision, flags);
+ }
+ *str = '\0';
+ return str - buf;
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsprintf(buf, fmt, args);
+ va_end(args);
+ return i;
+}
+
+int printf(const char *fmt, ...)
+{
+ char printf_buf[1024];
+ va_list args;
+ int printed;
+
+ va_start(args, fmt);
+ printed = vsprintf(printf_buf, fmt, args);
+ va_end(args);
+
+ puts(printf_buf);
+
+ return printed;
+}
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
deleted file mode 100644
index 6dbcc95b2120..000000000000
--- a/arch/i386/boot/setup.S
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * setup.S Copyright (C) 1991, 1992 Linus Torvalds
- *
- * setup.s is responsible for getting the system data from the BIOS,
- * and putting them into the appropriate places in system memory.
- * both setup.s and system has been loaded by the bootblock.
- *
- * This code asks the bios for memory/disk/other parameters, and
- * puts them in a "safe" place: 0x90000-0x901FF, ie where the
- * boot-block used to be. It is then up to the protected mode
- * system to read them from there before the area is overwritten
- * for buffer-blocks.
- *
- * Move PS/2 aux init code to psaux.c
- * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
- *
- * some changes and additional features by Christoph Niemann,
- * March 1993/June 1994 (Christoph.Niemann@linux.org)
- *
- * add APM BIOS checking by Stephen Rothwell, May 1994
- * (sfr@canb.auug.org.au)
- *
- * High load stuff, initrd support and position independency
- * by Hans Lermen & Werner Almesberger, February 1996
- * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
- *
- * Video handling moved to video.S by Martin Mares, March 1996
- * <mj@k332.feld.cvut.cz>
- *
- * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
- * parsons) to avoid loadlin confusion, July 1997
- *
- * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
- * <stiker@northlink.com>
- *
- * Fix to work around buggy BIOSes which don't use carry bit correctly
- * and/or report extended memory in CX/DX for e801h memory size detection
- * call. As a result the kernel got wrong figures. The int15/e801h docs
- * from Ralf Brown interrupt list seem to indicate AX/BX should be used
- * anyway. So to avoid breaking many machines (presumably there was a reason
- * to orginally use CX/DX instead of AX/BX), we do a kludge to see
- * if CX/DX have been changed in the e801 call and if so use AX/BX .
- * Michael Miller, April 2001 <michaelm@mjmm.org>
- *
- * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes
- * by Robert Schwebel, December 2001 <robert@schwebel.de>
- */
-
-#include <asm/segment.h>
-#include <linux/utsrelease.h>
-#include <linux/compile.h>
-#include <asm/boot.h>
-#include <asm/e820.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-
-/* Signature words to ensure LILO loaded us right */
-#define SIG1 0xAA55
-#define SIG2 0x5A5A
-
-INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
-SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
-SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
- # ... and the former contents of CS
-
-DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
-
-.code16
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-start:
- jmp trampoline
-
-# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
-
- .ascii "HdrS" # header signature
- .word 0x0206 # header version number (>= 0x0105)
- # or else old loadlin-1.5 will fail)
-realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
-start_sys_seg: .word SYSSEG
- .word kernel_version # pointing to kernel version string
- # above section of header is compatible
- # with loadlin-1.5 (header v1.5). Don't
- # change it.
-
-type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
- # Bootlin, SYSLX, bootsect...)
- # See Documentation/i386/boot.txt for
- # assigned ids
-
-# flags, unused bits must be zero (RFU) bit within loadflags
-loadflags:
-LOADED_HIGH = 1 # If set, the kernel is loaded high
-CAN_USE_HEAP = 0x80 # If set, the loader also has set
- # heap_end_ptr to tell how much
- # space behind setup.S can be used for
- # heap purposes.
- # Only the loader knows what is free
-#ifndef __BIG_KERNEL__
- .byte 0
-#else
- .byte LOADED_HIGH
-#endif
-
-setup_move_size: .word 0x8000 # size to move, when setup is not
- # loaded at 0x90000. We will move setup
- # to 0x90000 then just before jumping
- # into the kernel. However, only the
- # loader knows how much data behind
- # us also needs to be loaded.
-
-code32_start: # here loaders can put a different
- # start address for 32-bit code.
-#ifndef __BIG_KERNEL__
- .long 0x1000 # 0x1000 = default for zImage
-#else
- .long 0x100000 # 0x100000 = default for big kernel
-#endif
-
-ramdisk_image: .long 0 # address of loaded ramdisk image
- # Here the loader puts the 32-bit
- # address where it loaded the image.
- # This only will be read by the kernel.
-
-ramdisk_size: .long 0 # its size in bytes
-
-bootsect_kludge:
- .long 0 # obsolete
-
-heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
- # space from here (exclusive) down to
- # end of setup code can be used by setup
- # for local heap purposes.
-
-pad1: .word 0
-cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
- # If nonzero, a 32-bit pointer
- # to the kernel command line.
- # The command line should be
- # located between the start of
- # setup and the end of low
- # memory (0xa0000), or it may
- # get overwritten before it
- # gets read. If this field is
- # used, there is no longer
- # anything magical about the
- # 0x90000 segment; the setup
- # can be located anywhere in
- # low memory 0x10000 or higher.
-
-ramdisk_max: .long (-__PAGE_OFFSET-(512 << 20)-1) & 0x7fffffff
- # (Header version 0x0203 or later)
- # The highest safe address for
- # the contents of an initrd
-
-kernel_alignment: .long CONFIG_PHYSICAL_ALIGN #physical addr alignment
- #required for protected mode
- #kernel
-#ifdef CONFIG_RELOCATABLE
-relocatable_kernel: .byte 1
-#else
-relocatable_kernel: .byte 0
-#endif
-pad2: .byte 0
-pad3: .word 0
-
-cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
- #added with boot protocol
- #version 2.06
-
-trampoline: call start_of_setup
- .align 16
- # The offset at this point is 0x240
- .space (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff)
-# End of setup header #####################################################
-
-start_of_setup:
-# Bootlin depends on this being done early
- movw $0x01500, %ax
- movb $0x81, %dl
- int $0x13
-
-#ifdef SAFE_RESET_DISK_CONTROLLER
-# Reset the disk controller.
- movw $0x0000, %ax
- movb $0x80, %dl
- int $0x13
-#endif
-
-# Set %ds = %cs, we know that SETUPSEG = %cs at this point
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-# Check signature at end of setup
- cmpw $SIG1, setup_sig1
- jne bad_sig
-
- cmpw $SIG2, setup_sig2
- jne bad_sig
-
- jmp good_sig1
-
-# Routine to print asciiz string at ds:si
-prtstr:
- lodsb
- andb %al, %al
- jz fin
-
- call prtchr
- jmp prtstr
-
-fin: ret
-
-# Space printing
-prtsp2: call prtspc # Print double space
-prtspc: movb $0x20, %al # Print single space (note: fall-thru)
-
-# Part of above routine, this one just prints ascii al
-prtchr: pushw %ax
- pushw %cx
- movw $7,%bx
- movw $0x01, %cx
- movb $0x0e, %ah
- int $0x10
- popw %cx
- popw %ax
- ret
-
-beep: movb $0x07, %al
- jmp prtchr
-
-no_sig_mess: .string "No setup signature found ..."
-
-good_sig1:
- jmp good_sig
-
-# We now have to find the rest of the setup code/data
-bad_sig:
- movw %cs, %ax # SETUPSEG
- subw $DELTA_INITSEG, %ax # INITSEG
- movw %ax, %ds
- xorb %bh, %bh
- movb (497), %bl # get setup sect from bootsect
- subw $4, %bx # LILO loads 4 sectors of setup
- shlw $8, %bx # convert to words (1sect=2^8 words)
- movw %bx, %cx
- shrw $3, %bx # convert to segment
- addw $SYSSEG, %bx
- movw %bx, %cs:start_sys_seg
-# Move rest of setup code/data to here
- movw $2048, %di # four sectors loaded by LILO
- subw %si, %si
- pushw %cs
- popw %es
- movw $SYSSEG, %ax
- movw %ax, %ds
- rep
- movsw
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
- cmpw $SIG1, setup_sig1
- jne no_sig
-
- cmpw $SIG2, setup_sig2
- jne no_sig
-
- jmp good_sig
-
-no_sig:
- lea no_sig_mess, %si
- call prtstr
-
-no_sig_loop:
- hlt
- jmp no_sig_loop
-
-good_sig:
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %ds
-# Check if an old loader tries to load a big-kernel
- testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
- jz loader_ok # No, no danger for old loaders.
-
- cmpb $0, %cs:type_of_loader # Do we have a loader that
- # can deal with us?
- jnz loader_ok # Yes, continue.
-
- pushw %cs # No, we have an old loader,
- popw %ds # die.
- lea loader_panic_mess, %si
- call prtstr
-
- jmp no_sig_loop
-
-loader_panic_mess: .string "Wrong loader, giving up..."
-
-# check minimum cpuid
-# we do this here because it is the last place we can actually
-# show a user visible error message. Later the video modus
-# might be already messed up.
-loader_ok:
- call verify_cpu
- testl %eax,%eax
- jz cpu_ok
- movw %cs,%ax # aka SETUPSEG
- movw %ax,%ds
- lea cpu_panic_mess,%si
- call prtstr
-1: jmp 1b
-
-cpu_panic_mess:
- .asciz "PANIC: CPU too old for this kernel."
-
-#include "../kernel/verify_cpu.S"
-
-cpu_ok:
-# Get memory size (extended mem, kB)
-
- xorl %eax, %eax
- movl %eax, (0x1e0)
-#ifndef STANDARD_MEMORY_BIOS_CALL
- movb %al, (E820NR)
-# Try three different memory detection schemes. First, try
-# e820h, which lets us assemble a memory map, then try e801h,
-# which returns a 32-bit memory size, and finally 88h, which
-# returns 0-64m
-
-# method E820H:
-# the memory map from hell. e820h returns memory classified into
-# a whole bunch of different types, and allows memory holes and
-# everything. We scan through this memory map and build a list
-# of the first 32 memory areas, which we return at [E820MAP].
-# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
-
-#define SMAP 0x534d4150
-
-meme820:
- xorl %ebx, %ebx # continuation counter
- movw $E820MAP, %di # point into the whitelist
- # so we can have the bios
- # directly write into it.
-
-jmpe820:
- movl $0x0000e820, %eax # e820, upper word zeroed
- movl $SMAP, %edx # ascii 'SMAP'
- movl $20, %ecx # size of the e820rec
- pushw %ds # data record.
- popw %es
- int $0x15 # make the call
- jc bail820 # fall to e801 if it fails
-
- cmpl $SMAP, %eax # check the return is `SMAP'
- jne bail820 # fall to e801 if it fails
-
-# cmpl $1, 16(%di) # is this usable memory?
-# jne again820
-
- # If this is usable memory, we save it by simply advancing %di by
- # sizeof(e820rec).
- #
-good820:
- movb (E820NR), %al # up to 128 entries
- cmpb $E820MAX, %al
- jae bail820
-
- incb (E820NR)
- movw %di, %ax
- addw $20, %ax
- movw %ax, %di
-again820:
- cmpl $0, %ebx # check to see if
- jne jmpe820 # %ebx is set to EOF
-bail820:
-
-
-# method E801H:
-# memory size is in 1k chunksizes, to avoid confusing loadlin.
-# we store the 0xe801 memory size in a completely different place,
-# because it will most likely be longer than 16 bits.
-# (use 1e0 because that's what Larry Augustine uses in his
-# alternative new memory detection scheme, and it's sensible
-# to write everything into the same place.)
-
-meme801:
- stc # fix to work around buggy
- xorw %cx,%cx # BIOSes which don't clear/set
- xorw %dx,%dx # carry on pass/error of
- # e801h memory size call
- # or merely pass cx,dx though
- # without changing them.
- movw $0xe801, %ax
- int $0x15
- jc mem88
-
- cmpw $0x0, %cx # Kludge to handle BIOSes
- jne e801usecxdx # which report their extended
- cmpw $0x0, %dx # memory in AX/BX rather than
- jne e801usecxdx # CX/DX. The spec I have read
- movw %ax, %cx # seems to indicate AX/BX
- movw %bx, %dx # are more reasonable anyway...
-
-e801usecxdx:
- andl $0xffff, %edx # clear sign extend
- shll $6, %edx # and go from 64k to 1k chunks
- movl %edx, (0x1e0) # store extended memory size
- andl $0xffff, %ecx # clear sign extend
- addl %ecx, (0x1e0) # and add lower memory into
- # total size.
-
-# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
-# 64mb, depending on the bios) in ax.
-mem88:
-
-#endif
- movb $0x88, %ah
- int $0x15
- movw %ax, (2)
-
-# Set the keyboard repeat rate to the max
- movw $0x0305, %ax
- xorw %bx, %bx
- int $0x16
-
-# Check for video adapter and its parameters and allow the
-# user to browse video modes.
- call video # NOTE: we need %ds pointing
- # to bootsector
-
-# Get hd0 data...
- xorw %ax, %ax
- movw %ax, %ds
- ldsw (4 * 0x41), %si
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- pushw %ax
- movw %ax, %es
- movw $0x0080, %di
- movw $0x10, %cx
- pushw %cx
- cld
- rep
- movsb
-# Get hd1 data...
- xorw %ax, %ax
- movw %ax, %ds
- ldsw (4 * 0x46), %si
- popw %cx
- popw %es
- movw $0x0090, %di
- rep
- movsb
-# Check that there IS a hd1 :-)
- movw $0x01500, %ax
- movb $0x81, %dl
- int $0x13
- jc no_disk1
-
- cmpb $3, %ah
- je is_disk1
-
-no_disk1:
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %es
- movw $0x0090, %di
- movw $0x10, %cx
- xorw %ax, %ax
- cld
- rep
- stosb
-is_disk1:
-# check for Micro Channel (MCA) bus
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %ds
- xorw %ax, %ax
- movw %ax, (0xa0) # set table length to 0
- movb $0xc0, %ah
- stc
- int $0x15 # moves feature table to es:bx
- jc no_mca
-
- pushw %ds
- movw %es, %ax
- movw %ax, %ds
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %es
- movw %bx, %si
- movw $0xa0, %di
- movw (%si), %cx
- addw $2, %cx # table length is a short
- cmpw $0x10, %cx
- jc sysdesc_ok
-
- movw $0x10, %cx # we keep only first 16 bytes
-sysdesc_ok:
- rep
- movsb
- popw %ds
-no_mca:
-#ifdef CONFIG_X86_VOYAGER
- movb $0xff, 0x40 # flag on config found
- movb $0xc0, %al
- mov $0xff, %ah
- int $0x15 # put voyager config info at es:di
- jc no_voyager
- movw $0x40, %si # place voyager info in apm table
- cld
- movw $7, %cx
-voyager_rep:
- movb %es:(%di), %al
- movb %al,(%si)
- incw %di
- incw %si
- decw %cx
- jnz voyager_rep
-no_voyager:
-#endif
-# Check for PS/2 pointing device
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %ds
- movb $0, (0x1ff) # default is no pointing device
- int $0x11 # int 0x11: equipment list
- testb $0x04, %al # check if mouse installed
- jz no_psmouse
-
- movb $0xAA, (0x1ff) # device present
-no_psmouse:
-
-#if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)
- movl $0x0000E980, %eax # IST Support
- movl $0x47534943, %edx # Request value
- int $0x15
-
- movl %eax, (96)
- movl %ebx, (100)
- movl %ecx, (104)
- movl %edx, (108)
-#endif
-
-#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
-# Then check for an APM BIOS...
- # %ds points to the bootsector
- movw $0, 0x40 # version = 0 means no APM BIOS
- movw $0x05300, %ax # APM BIOS installation check
- xorw %bx, %bx
- int $0x15
- jc done_apm_bios # Nope, no APM BIOS
-
- cmpw $0x0504d, %bx # Check for "PM" signature
- jne done_apm_bios # No signature, no APM BIOS
-
- andw $0x02, %cx # Is 32 bit supported?
- je done_apm_bios # No 32-bit, no (good) APM BIOS
-
- movw $0x05304, %ax # Disconnect first just in case
- xorw %bx, %bx
- int $0x15 # ignore return code
- movw $0x05303, %ax # 32 bit connect
- xorl %ebx, %ebx
- xorw %cx, %cx # paranoia :-)
- xorw %dx, %dx # ...
- xorl %esi, %esi # ...
- xorw %di, %di # ...
- int $0x15
- jc no_32_apm_bios # Ack, error.
-
- movw %ax, (66) # BIOS code segment
- movl %ebx, (68) # BIOS entry point offset
- movw %cx, (72) # BIOS 16 bit code segment
- movw %dx, (74) # BIOS data segment
- movl %esi, (78) # BIOS code segment lengths
- movw %di, (82) # BIOS data segment length
-# Redo the installation check as the 32 bit connect
-# modifies the flags returned on some BIOSs
- movw $0x05300, %ax # APM BIOS installation check
- xorw %bx, %bx
- xorw %cx, %cx # paranoia
- int $0x15
- jc apm_disconnect # error -> shouldn't happen
-
- cmpw $0x0504d, %bx # check for "PM" signature
- jne apm_disconnect # no sig -> shouldn't happen
-
- movw %ax, (64) # record the APM BIOS version
- movw %cx, (76) # and flags
- jmp done_apm_bios
-
-apm_disconnect: # Tidy up
- movw $0x05304, %ax # Disconnect
- xorw %bx, %bx
- int $0x15 # ignore return code
-
- jmp done_apm_bios
-
-no_32_apm_bios:
- andw $0xfffd, (76) # remove 32 bit support bit
-done_apm_bios:
-#endif
-
-#include "edd.S"
-
-# Now we want to move to protected mode ...
- cmpw $0, %cs:realmode_swtch
- jz rmodeswtch_normal
-
- lcall *%cs:realmode_swtch
-
- jmp rmodeswtch_end
-
-rmodeswtch_normal:
- pushw %cs
- call default_switch
-
-rmodeswtch_end:
-# Now we move the system to its rightful place ... but we check if we have a
-# big-kernel. In that case we *must* not move it ...
- testb $LOADED_HIGH, %cs:loadflags
- jz do_move0 # .. then we have a normal low
- # loaded zImage
- # .. or else we have a high
- # loaded bzImage
- jmp end_move # ... and we skip moving
-
-do_move0:
- movw $0x100, %ax # start of destination segment
- movw %cs, %bp # aka SETUPSEG
- subw $DELTA_INITSEG, %bp # aka INITSEG
- movw %cs:start_sys_seg, %bx # start of source segment
- cld
-do_move:
- movw %ax, %es # destination segment
- incb %ah # instead of add ax,#0x100
- movw %bx, %ds # source segment
- addw $0x100, %bx
- subw %di, %di
- subw %si, %si
- movw $0x800, %cx
- rep
- movsw
- cmpw %bp, %bx # assume start_sys_seg > 0x200,
- # so we will perhaps read one
- # page more than needed, but
- # never overwrite INITSEG
- # because destination is a
- # minimum one page below source
- jb do_move
-
-end_move:
-# then we load the segment descriptors
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-
-# Check whether we need to be downward compatible with version <=201
- cmpl $0, cmd_line_ptr
- jne end_move_self # loader uses version >=202 features
- cmpb $0x20, type_of_loader
- je end_move_self # bootsect loader, we know of it
-
-# Boot loader doesnt support boot protocol version 2.02.
-# If we have our code not at 0x90000, we need to move it there now.
-# We also then need to move the params behind it (commandline)
-# Because we would overwrite the code on the current IP, we move
-# it in two steps, jumping high after the first one.
- movw %cs, %ax
- cmpw $SETUPSEG, %ax
- je end_move_self
-
- cli # make sure we really have
- # interrupts disabled !
- # because after this the stack
- # should not be used
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ss, %dx
- cmpw %ax, %dx
- jb move_self_1
-
- addw $INITSEG, %dx
- subw %ax, %dx # this will go into %ss after
- # the move
-move_self_1:
- movw %ax, %ds
- movw $INITSEG, %ax # real INITSEG
- movw %ax, %es
- movw %cs:setup_move_size, %cx
- std # we have to move up, so we use
- # direction down because the
- # areas may overlap
- movw %cx, %di
- decw %di
- movw %di, %si
- subw $move_self_here+0x200, %cx
- rep
- movsb
- ljmp $SETUPSEG, $move_self_here
-
-move_self_here:
- movw $move_self_here+0x200, %cx
- rep
- movsb
- movw $SETUPSEG, %ax
- movw %ax, %ds
- movw %dx, %ss
-end_move_self: # now we are at the right place
-
-#
-# Enable A20. This is at the very best an annoying procedure.
-# A20 code ported from SYSLINUX 1.52-1.63 by H. Peter Anvin.
-# AMD Elan bug fix by Robert Schwebel.
-#
-
-#if defined(CONFIG_X86_ELAN)
- movb $0x02, %al # alternate A20 gate
- outb %al, $0x92 # this works on SC410/SC520
-a20_elan_wait:
- call a20_test
- jz a20_elan_wait
- jmp a20_done
-#endif
-
-
-A20_TEST_LOOPS = 32 # Iterations per wait
-A20_ENABLE_LOOPS = 255 # Total loops to try
-
-
-#ifndef CONFIG_X86_VOYAGER
-a20_try_loop:
-
- # First, see if we are on a system with no A20 gate.
-a20_none:
- call a20_test
- jnz a20_done
-
- # Next, try the BIOS (INT 0x15, AX=0x2401)
-a20_bios:
- movw $0x2401, %ax
- pushfl # Be paranoid about flags
- int $0x15
- popfl
-
- call a20_test
- jnz a20_done
-
- # Try enabling A20 through the keyboard controller
-#endif /* CONFIG_X86_VOYAGER */
-a20_kbc:
- call empty_8042
-
-#ifndef CONFIG_X86_VOYAGER
- call a20_test # Just in case the BIOS worked
- jnz a20_done # but had a delayed reaction.
-#endif
-
- movb $0xD1, %al # command write
- outb %al, $0x64
- call empty_8042
-
- movb $0xDF, %al # A20 on
- outb %al, $0x60
- call empty_8042
-
-#ifndef CONFIG_X86_VOYAGER
- # Wait until a20 really *is* enabled; it can take a fair amount of
- # time on certain systems; Toshiba Tecras are known to have this
- # problem.
-a20_kbc_wait:
- xorw %cx, %cx
-a20_kbc_wait_loop:
- call a20_test
- jnz a20_done
- loop a20_kbc_wait_loop
-
- # Final attempt: use "configuration port A"
-a20_fast:
- inb $0x92, %al # Configuration Port A
- orb $0x02, %al # "fast A20" version
- andb $0xFE, %al # don't accidentally reset
- outb %al, $0x92
-
- # Wait for configuration port A to take effect
-a20_fast_wait:
- xorw %cx, %cx
-a20_fast_wait_loop:
- call a20_test
- jnz a20_done
- loop a20_fast_wait_loop
-
- # A20 is still not responding. Try frobbing it again.
- #
- decb (a20_tries)
- jnz a20_try_loop
-
- movw $a20_err_msg, %si
- call prtstr
-
-a20_die:
- hlt
- jmp a20_die
-
-a20_tries:
- .byte A20_ENABLE_LOOPS
-
-a20_err_msg:
- .ascii "linux: fatal error: A20 gate not responding!"
- .byte 13, 10, 0
-
- # If we get here, all is good
-a20_done:
-
-#endif /* CONFIG_X86_VOYAGER */
-# set up gdt and idt and 32bit start address
- lidt idt_48 # load idt with 0,0
- xorl %eax, %eax # Compute gdt_base
- movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
- shll $4, %eax
- addl %eax, code32
- addl $gdt, %eax
- movl %eax, (gdt_48+2)
- lgdt gdt_48 # load gdt with whatever is
- # appropriate
-
-# make sure any possible coprocessor is properly reset..
- xorw %ax, %ax
- outb %al, $0xf0
- call delay
-
- outb %al, $0xf1
- call delay
-
-# well, that went ok, I hope. Now we mask all interrupts - the rest
-# is done in init_IRQ().
- movb $0xFF, %al # mask all interrupts for now
- outb %al, $0xA1
- call delay
-
- movb $0xFB, %al # mask all irq's but irq2 which
- outb %al, $0x21 # is cascaded
-
-# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
-# need no steenking BIOS anyway (except for the initial loading :-).
-# The BIOS-routine wants lots of unnecessary data, and it's less
-# "interesting" anyway. This is how REAL programmers do it.
-#
-# Well, now's the time to actually move into protected mode. To make
-# things as simple as possible, we do no register set-up or anything,
-# we let the gnu-compiled 32-bit programs do that. We just jump to
-# absolute address 0x1000 (or the loader supplied one),
-# in 32-bit protected mode.
-#
-# Note that the short jump isn't strictly needed, although there are
-# reasons why it might be a good idea. It won't hurt in any case.
- movw $1, %ax # protected mode (PE) bit
- lmsw %ax # This is it!
- jmp flush_instr
-
-flush_instr:
- xorw %bx, %bx # Flag to indicate a boot
- xorl %esi, %esi # Pointer to real-mode code
- movw %cs, %si
- subw $DELTA_INITSEG, %si
- shll $4, %esi # Convert to 32-bit pointer
-
-# jump to startup_32 in arch/i386/boot/compressed/head.S
-#
-# NOTE: For high loaded big kernels we need a
-# jmpi 0x100000,__BOOT_CS
-#
-# but we yet haven't reloaded the CS register, so the default size
-# of the target offset still is 16 bit.
-# However, using an operand prefix (0x66), the CPU will properly
-# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
-# Manual, Mixing 16-bit and 32-bit code, page 16-6)
-
- .byte 0x66, 0xea # prefix + jmpi-opcode
-code32: .long startup_32 # will be set to %cs+startup_32
- .word __BOOT_CS
-.code32
-startup_32:
- movl $(__BOOT_DS), %eax
- movl %eax, %ds
- movl %eax, %es
- movl %eax, %fs
- movl %eax, %gs
- movl %eax, %ss
-
- xorl %eax, %eax
-1: incl %eax # check that A20 really IS enabled
- movl %eax, 0x00000000 # loop forever if it isn't
- cmpl %eax, 0x00100000
- je 1b
-
- # Jump to the 32bit entry point
- jmpl *(code32_start - start + (DELTA_INITSEG << 4))(%esi)
-.code16
-
-# Here's a bunch of information about your current kernel..
-kernel_version: .ascii UTS_RELEASE
- .ascii " ("
- .ascii LINUX_COMPILE_BY
- .ascii "@"
- .ascii LINUX_COMPILE_HOST
- .ascii ") "
- .ascii UTS_VERSION
- .byte 0
-
-# This is the default real mode switch routine.
-# to be called just before protected mode transition
-default_switch:
- cli # no interrupts allowed !
- movb $0x80, %al # disable NMI for bootup
- # sequence
- outb %al, $0x70
- lret
-
-
-#ifndef CONFIG_X86_VOYAGER
-# This routine tests whether or not A20 is enabled. If so, it
-# exits with zf = 0.
-#
-# The memory address used, 0x200, is the int $0x80 vector, which
-# should be safe.
-
-A20_TEST_ADDR = 4*0x80
-
-a20_test:
- pushw %cx
- pushw %ax
- xorw %cx, %cx
- movw %cx, %fs # Low memory
- decw %cx
- movw %cx, %gs # High memory area
- movw $A20_TEST_LOOPS, %cx
- movw %fs:(A20_TEST_ADDR), %ax
- pushw %ax
-a20_test_wait:
- incw %ax
- movw %ax, %fs:(A20_TEST_ADDR)
- call delay # Serialize and make delay constant
- cmpw %gs:(A20_TEST_ADDR+0x10), %ax
- loope a20_test_wait
-
- popw %fs:(A20_TEST_ADDR)
- popw %ax
- popw %cx
- ret
-
-#endif /* CONFIG_X86_VOYAGER */
-
-# This routine checks that the keyboard command queue is empty
-# (after emptying the output buffers)
-#
-# Some machines have delusions that the keyboard buffer is always full
-# with no keyboard attached...
-#
-# If there is no keyboard controller, we will usually get 0xff
-# to all the reads. With each IO taking a microsecond and
-# a timeout of 100,000 iterations, this can take about half a
-# second ("delay" == outb to port 0x80). That should be ok,
-# and should also be plenty of time for a real keyboard controller
-# to empty.
-#
-
-empty_8042:
- pushl %ecx
- movl $100000, %ecx
-
-empty_8042_loop:
- decl %ecx
- jz empty_8042_end_loop
-
- call delay
-
- inb $0x64, %al # 8042 status port
- testb $1, %al # output buffer?
- jz no_output
-
- call delay
- inb $0x60, %al # read it
- jmp empty_8042_loop
-
-no_output:
- testb $2, %al # is input buffer full?
- jnz empty_8042_loop # yes - loop
-empty_8042_end_loop:
- popl %ecx
- ret
-
-# Read the cmos clock. Return the seconds in al
-gettime:
- pushw %cx
- movb $0x02, %ah
- int $0x1a
- movb %dh, %al # %dh contains the seconds
- andb $0x0f, %al
- movb %dh, %ah
- movb $0x04, %cl
- shrb %cl, %ah
- aad
- popw %cx
- ret
-
-# Delay is needed after doing I/O
-delay:
- outb %al,$0x80
- ret
-
-# Descriptor tables
-#
-# NOTE: The intel manual says gdt should be sixteen bytes aligned for
-# efficiency reasons. However, there are machines which are known not
-# to boot with misaligned GDTs, so alter this at your peril! If you alter
-# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two
-# empty GDT entries (one for NULL and one reserved).
-#
-# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is
-# true for the Voyager Quad CPU card which will not boot without
-# This directive. 16 byte aligment is recommended by intel.
-#
- .align 16
-gdt:
- .fill GDT_ENTRY_BOOT_CS,8,0
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9A00 # code read/exec
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9200 # data read/write
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-gdt_end:
- .align 4
-
- .word 0 # alignment byte
-idt_48:
- .word 0 # idt limit = 0
- .word 0, 0 # idt base = 0L
-
- .word 0 # alignment byte
-gdt_48:
- .word gdt_end - gdt - 1 # gdt limit
- .word 0, 0 # gdt base (filled in later)
-
-# Include video setup & detection code
-
-#include "video.S"
-
-# Setup signature -- must be last
-setup_sig1: .word SIG1
-setup_sig2: .word SIG2
-
-# After this point, there is some free space which is used by the video mode
-# handling code to store the temporary mode table (not used by the kernel).
-
-modelist:
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
diff --git a/arch/i386/boot/setup.ld b/arch/i386/boot/setup.ld
new file mode 100644
index 000000000000..df9234b3a5e0
--- /dev/null
+++ b/arch/i386/boot/setup.ld
@@ -0,0 +1,54 @@
+/*
+ * setup.ld
+ *
+ * Linker script for the i386 setup code
+ */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0;
+ .bstext : { *(.bstext) }
+ .bsdata : { *(.bsdata) }
+
+ . = 497;
+ .header : { *(.header) }
+ .inittext : { *(.inittext) }
+ .initdata : { *(.initdata) }
+ .text : { *(.text*) }
+
+ . = ALIGN(16);
+ .rodata : { *(.rodata*) }
+
+ .videocards : {
+ video_cards = .;
+ *(.videocards)
+ video_cards_end = .;
+ }
+
+ . = ALIGN(16);
+ .data : { *(.data*) }
+
+ .signature : {
+ setup_sig = .;
+ LONG(0x5a5aaa55)
+ }
+
+
+ . = ALIGN(16);
+ .bss :
+ {
+ __bss_start = .;
+ *(.bss)
+ __bss_end = .;
+ }
+ . = ALIGN(16);
+ _end = .;
+
+ /DISCARD/ : { *(.note*) }
+
+ . = ASSERT(_end <= 0x8000, "Setup too big!");
+ . = ASSERT(hdr == 0x1f1, "The setup header has the wrong offset!");
+}
diff --git a/arch/i386/boot/string.c b/arch/i386/boot/string.c
new file mode 100644
index 000000000000..481a22097781
--- /dev/null
+++ b/arch/i386/boot/string.c
@@ -0,0 +1,52 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/string.c
+ *
+ * Very basic string functions
+ */
+
+#include "boot.h"
+
+int strcmp(const char *str1, const char *str2)
+{
+ const unsigned char *s1 = (const unsigned char *)str1;
+ const unsigned char *s2 = (const unsigned char *)str2;
+ int delta = 0;
+
+ while (*s1 || *s2) {
+ delta = *s2 - *s1;
+ if (delta)
+ return delta;
+ s1++;
+ s2++;
+ }
+ return 0;
+}
+
+size_t strnlen(const char *s, size_t maxlen)
+{
+ const char *es = s;
+ while (*es && maxlen) {
+ es++;
+ maxlen--;
+ }
+
+ return (es - s);
+}
+
+unsigned int atou(const char *s)
+{
+ unsigned int i = 0;
+ while (isdigit(*s))
+ i = i * 10 + (*s++ - '0');
+ return i;
+}
diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c
index 05798419a6a9..b4248740ff0d 100644
--- a/arch/i386/boot/tools/build.c
+++ b/arch/i386/boot/tools/build.c
@@ -1,13 +1,12 @@
/*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1997 Martin Mares
+ * Copyright (C) 2007 H. Peter Anvin
*/
/*
- * This file builds a disk-image from three different files:
+ * This file builds a disk-image from two different files:
*
- * - bootsect: compatibility mbr which prints an error message if
- * someone tries to boot the kernel directly.
* - setup: 8086 machine code, sets up system parm
* - system: 80386 code for actual system
*
@@ -21,6 +20,7 @@
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
* Cross compiling fixes by Gertjan van Wingerde, July 1996
* Rewritten by Martin Mares, April 1997
+ * Substantially overhauled by H. Peter Anvin, April 2007
*/
#include <stdio.h>
@@ -32,23 +32,25 @@
#include <sys/sysmacros.h>
#include <unistd.h>
#include <fcntl.h>
+#include <sys/mman.h>
#include <asm/boot.h>
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long u32;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long u32;
#define DEFAULT_MAJOR_ROOT 0
#define DEFAULT_MINOR_ROOT 0
-/* Minimal number of setup sectors (see also bootsect.S) */
-#define SETUP_SECTS 4
+/* Minimal number of setup sectors */
+#define SETUP_SECT_MIN 5
+#define SETUP_SECT_MAX 64
-byte buf[1024];
-int fd;
+/* This must be large enough to hold the entire setup */
+u8 buf[SETUP_SECT_MAX*512];
int is_big_kernel;
-void die(const char * str, ...)
+static void die(const char * str, ...)
{
va_list args;
va_start(args, str);
@@ -57,15 +59,9 @@ void die(const char * str, ...)
exit(1);
}
-void file_open(const char *name)
+static void usage(void)
{
- if ((fd = open(name, O_RDONLY, 0)) < 0)
- die("Unable to open `%s': %m", name);
-}
-
-void usage(void)
-{
- die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
+ die("Usage: build [-b] setup system [rootdev] [> image]");
}
int main(int argc, char ** argv)
@@ -73,27 +69,30 @@ int main(int argc, char ** argv)
unsigned int i, sz, setup_sectors;
int c;
u32 sys_size;
- byte major_root, minor_root;
+ u8 major_root, minor_root;
struct stat sb;
+ FILE *file;
+ int fd;
+ void *kernel;
if (argc > 2 && !strcmp(argv[1], "-b"))
{
is_big_kernel = 1;
argc--, argv++;
}
- if ((argc < 4) || (argc > 5))
+ if ((argc < 3) || (argc > 4))
usage();
- if (argc > 4) {
- if (!strcmp(argv[4], "CURRENT")) {
+ if (argc > 3) {
+ if (!strcmp(argv[3], "CURRENT")) {
if (stat("/", &sb)) {
perror("/");
die("Couldn't stat /");
}
major_root = major(sb.st_dev);
minor_root = minor(sb.st_dev);
- } else if (strcmp(argv[4], "FLOPPY")) {
- if (stat(argv[4], &sb)) {
- perror(argv[4]);
+ } else if (strcmp(argv[3], "FLOPPY")) {
+ if (stat(argv[3], &sb)) {
+ perror(argv[3]);
die("Couldn't stat root device.");
}
major_root = major(sb.st_rdev);
@@ -108,79 +107,62 @@ int main(int argc, char ** argv)
}
fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
- file_open(argv[1]);
- i = read(fd, buf, sizeof(buf));
- fprintf(stderr,"Boot sector %d bytes.\n",i);
- if (i != 512)
- die("Boot block must be exactly 512 bytes");
+ /* Copy the setup code */
+ file = fopen(argv[1], "r");
+ if (!file)
+ die("Unable to open `%s': %m", argv[1]);
+ c = fread(buf, 1, sizeof(buf), file);
+ if (ferror(file))
+ die("read-error on `setup'");
+ if (c < 1024)
+ die("The setup must be at least 1024 bytes");
if (buf[510] != 0x55 || buf[511] != 0xaa)
die("Boot block hasn't got boot flag (0xAA55)");
+ fclose(file);
+
+ /* Pad unused space with zeros */
+ setup_sectors = (c + 511) / 512;
+ if (setup_sectors < SETUP_SECT_MIN)
+ setup_sectors = SETUP_SECT_MIN;
+ i = setup_sectors*512;
+ memset(buf+c, 0, i-c);
+
+ /* Set the default root device */
buf[508] = minor_root;
buf[509] = major_root;
- if (write(1, buf, 512) != 512)
- die("Write call failed");
- close (fd);
-
- file_open(argv[2]); /* Copy the setup code */
- for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
- if (write(1, buf, c) != c)
- die("Write call failed");
- if (c != 0)
- die("read-error on `setup'");
- close (fd);
-
- setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */
- /* for compatibility with ancient versions of LILO. */
- if (setup_sectors < SETUP_SECTS)
- setup_sectors = SETUP_SECTS;
- fprintf(stderr, "Setup is %d bytes.\n", i);
- memset(buf, 0, sizeof(buf));
- while (i < setup_sectors * 512) {
- c = setup_sectors * 512 - i;
- if (c > sizeof(buf))
- c = sizeof(buf);
- if (write(1, buf, c) != c)
- die("Write call failed");
- i += c;
- }
- file_open(argv[3]);
- if (fstat (fd, &sb))
- die("Unable to stat `%s': %m", argv[3]);
+ fprintf(stderr, "Setup is %d bytes (padded to %d bytes).\n", c, i);
+
+ /* Open and stat the kernel file */
+ fd = open(argv[2], O_RDONLY);
+ if (fd < 0)
+ die("Unable to open `%s': %m", argv[2]);
+ if (fstat(fd, &sb))
+ die("Unable to stat `%s': %m", argv[2]);
sz = sb.st_size;
- fprintf (stderr, "System is %d kB\n", sz/1024);
+ fprintf (stderr, "System is %d kB\n", (sz+1023)/1024);
+ kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
+ if (kernel == MAP_FAILED)
+ die("Unable to mmap '%s': %m", argv[2]);
sys_size = (sz + 15) / 16;
if (!is_big_kernel && sys_size > DEF_SYSSIZE)
die("System is too big. Try using bzImage or modules.");
- while (sz > 0) {
- int l, n;
-
- l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
- if ((n=read(fd, buf, l)) != l) {
- if (n < 0)
- die("Error reading %s: %m", argv[3]);
- else
- die("%s: Unexpected EOF", argv[3]);
- }
- if (write(1, buf, l) != l)
- die("Write failed");
- sz -= l;
- }
+
+ /* Patch the setup code with the appropriate size parameters */
+ buf[0x1f1] = setup_sectors-1;
+ buf[0x1f4] = sys_size;
+ buf[0x1f5] = sys_size >> 8;
+ buf[0x1f6] = sys_size >> 16;
+ buf[0x1f7] = sys_size >> 24;
+
+ if (fwrite(buf, 1, i, stdout) != i)
+ die("Writing setup failed");
+
+ /* Copy the kernel code */
+ if (fwrite(kernel, 1, sz, stdout) != sz)
+ die("Writing kernel failed");
close(fd);
- if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */
- die("Output: seek failed");
- buf[0] = setup_sectors;
- if (write(1, buf, 1) != 1)
- die("Write of setup sector count failed");
- if (lseek(1, 500, SEEK_SET) != 500)
- die("Output: seek failed");
- buf[0] = (sys_size & 0xff);
- buf[1] = ((sys_size >> 8) & 0xff);
- buf[2] = ((sys_size >> 16) & 0xff);
- buf[3] = ((sys_size >> 24) & 0xff);
- if (write(1, buf, 4) != 4)
- die("Write of image length failed");
-
- return 0; /* Everything is OK */
+ /* Everything is OK */
+ return 0;
}
diff --git a/arch/i386/boot/tty.c b/arch/i386/boot/tty.c
new file mode 100644
index 000000000000..9c668aad3515
--- /dev/null
+++ b/arch/i386/boot/tty.c
@@ -0,0 +1,112 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/tty.c
+ *
+ * Very simple screen I/O
+ * XXX: Probably should add very simple serial I/O?
+ */
+
+#include "boot.h"
+
+/*
+ * These functions are in .inittext so they can be used to signal
+ * error during initialization.
+ */
+
+void __attribute__((section(".inittext"))) putchar(int ch)
+{
+ unsigned char c = ch;
+
+ if (c == '\n')
+ putchar('\r'); /* \n -> \r\n */
+
+ /* int $0x10 is known to have bugs involving touching registers
+ it shouldn't. Be extra conservative... */
+ asm volatile("pushal; pushw %%ds; int $0x10; popw %%ds; popal"
+ : : "b" (0x0007), "c" (0x0001), "a" (0x0e00|ch));
+}
+
+void __attribute__((section(".inittext"))) puts(const char *str)
+{
+ int n = 0;
+ while (*str) {
+ putchar(*str++);
+ n++;
+ }
+}
+
+/*
+ * Read the CMOS clock through the BIOS, and return the
+ * seconds in BCD.
+ */
+
+static u8 gettime(void)
+{
+ u16 ax = 0x0200;
+ u16 cx, dx;
+
+ asm("int $0x1a"
+ : "+a" (ax), "=c" (cx), "=d" (dx)
+ : : "ebx", "esi", "edi");
+
+ return dx >> 8;
+}
+
+/*
+ * Read from the keyboard
+ */
+int getchar(void)
+{
+ u16 ax = 0;
+ asm("int $0x16" : "+a" (ax));
+
+ return ax & 0xff;
+}
+
+static int kbd_pending(void)
+{
+ u8 pending;
+ asm("int $0x16; setnz %0"
+ : "=rm" (pending)
+ : "a" (0x0100));
+ return pending;
+}
+
+void kbd_flush(void)
+{
+ for (;;) {
+ if (!kbd_pending())
+ break;
+ getchar();
+ }
+}
+
+int getchar_timeout(void)
+{
+ int cnt = 30;
+ int t0, t1;
+
+ t0 = gettime();
+
+ while (cnt) {
+ if (kbd_pending())
+ return getchar();
+
+ t1 = gettime();
+ if (t0 != t1) {
+ cnt--;
+ t0 = t1;
+ }
+ }
+
+ return 0; /* Timeout! */
+}
diff --git a/arch/i386/boot/version.c b/arch/i386/boot/version.c
new file mode 100644
index 000000000000..c61462f7d9a7
--- /dev/null
+++ b/arch/i386/boot/version.c
@@ -0,0 +1,23 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/version.c
+ *
+ * Kernel version string
+ */
+
+#include "boot.h"
+#include <linux/utsrelease.h>
+#include <linux/compile.h>
+
+const char kernel_version[] =
+ UTS_RELEASE " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ") "
+ UTS_VERSION;
diff --git a/arch/i386/boot/vesa.h b/arch/i386/boot/vesa.h
new file mode 100644
index 000000000000..ff5b73cd406f
--- /dev/null
+++ b/arch/i386/boot/vesa.h
@@ -0,0 +1,79 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1999-2007 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef BOOT_VESA_H
+#define BOOT_VESA_H
+
+typedef struct {
+ u16 off, seg;
+} far_ptr;
+
+/* VESA General Information table */
+struct vesa_general_info {
+ u32 signature; /* 0 Magic number = "VESA" */
+ u16 version; /* 4 */
+ far_ptr vendor_string; /* 6 */
+ u32 capabilities; /* 10 */
+ far_ptr video_mode_ptr; /* 14 */
+ u16 total_memory; /* 18 */
+
+ u16 oem_software_rev; /* 20 */
+ far_ptr oem_vendor_name_ptr; /* 22 */
+ far_ptr oem_product_name_ptr; /* 26 */
+ far_ptr oem_product_rev_ptr; /* 30 */
+
+ u8 reserved[222]; /* 34 */
+ u8 oem_data[256]; /* 256 */
+} __attribute__ ((packed));
+
+#define VESA_MAGIC ('V' + ('E' << 8) + ('S' << 16) + ('A' << 24))
+#define VBE2_MAGIC ('V' + ('B' << 8) + ('E' << 16) + ('2' << 24))
+
+struct vesa_mode_info {
+ u16 mode_attr; /* 0 */
+ u8 win_attr[2]; /* 2 */
+ u16 win_grain; /* 4 */
+ u16 win_size; /* 6 */
+ u16 win_seg[2]; /* 8 */
+ far_ptr win_scheme; /* 12 */
+ u16 logical_scan; /* 16 */
+
+ u16 h_res; /* 18 */
+ u16 v_res; /* 20 */
+ u8 char_width; /* 22 */
+ u8 char_height; /* 23 */
+ u8 memory_planes; /* 24 */
+ u8 bpp; /* 25 */
+ u8 banks; /* 26 */
+ u8 memory_layout; /* 27 */
+ u8 bank_size; /* 28 */
+ u8 image_planes; /* 29 */
+ u8 page_function; /* 30 */
+
+ u8 rmask; /* 31 */
+ u8 rpos; /* 32 */
+ u8 gmask; /* 33 */
+ u8 gpos; /* 34 */
+ u8 bmask; /* 35 */
+ u8 bpos; /* 36 */
+ u8 resv_mask; /* 37 */
+ u8 resv_pos; /* 38 */
+ u8 dcm_info; /* 39 */
+
+ u32 lfb_ptr; /* 40 Linear frame buffer address */
+ u32 offscreen_ptr; /* 44 Offscreen memory address */
+ u16 offscreen_size; /* 48 */
+
+ u8 reserved[206]; /* 50 */
+} __attribute__ ((packed));
+
+#endif /* LIB_SYS_VESA_H */
diff --git a/arch/i386/boot/video-bios.c b/arch/i386/boot/video-bios.c
new file mode 100644
index 000000000000..afea46c500cc
--- /dev/null
+++ b/arch/i386/boot/video-bios.c
@@ -0,0 +1,125 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video-bios.c
+ *
+ * Standard video BIOS modes
+ *
+ * We have two options for this; silent and scanned.
+ */
+
+#include "boot.h"
+#include "video.h"
+
+__videocard video_bios;
+
+/* Set a conventional BIOS mode */
+static int set_bios_mode(u8 mode);
+
+static int bios_set_mode(struct mode_info *mi)
+{
+ return set_bios_mode(mi->mode - VIDEO_FIRST_BIOS);
+}
+
+static int set_bios_mode(u8 mode)
+{
+ u16 ax;
+ u8 new_mode;
+
+ ax = mode; /* AH=0x00 Set Video Mode */
+ asm volatile(INT10
+ : "+a" (ax)
+ : : "ebx", "ecx", "edx", "esi", "edi");
+
+ ax = 0x0f00; /* Get Current Video Mode */
+ asm volatile(INT10
+ : "+a" (ax)
+ : : "ebx", "ecx", "edx", "esi", "edi");
+
+ do_restore = 1; /* Assume video contents was lost */
+ new_mode = ax & 0x7f; /* Not all BIOSes are clean with the top bit */
+
+ if (new_mode == mode)
+ return 0; /* Mode change OK */
+
+ if (new_mode != boot_params.screen_info.orig_video_mode) {
+ /* Mode setting failed, but we didn't end up where we
+ started. That's bad. Try to revert to the original
+ video mode. */
+ ax = boot_params.screen_info.orig_video_mode;
+ asm volatile(INT10
+ : "+a" (ax)
+ : : "ebx", "ecx", "edx", "esi", "edi");
+ }
+ return -1;
+}
+
+static int bios_probe(void)
+{
+ u8 mode;
+ u8 saved_mode = boot_params.screen_info.orig_video_mode;
+ u16 crtc;
+ struct mode_info *mi;
+ int nmodes = 0;
+
+ if (adapter != ADAPTER_EGA && adapter != ADAPTER_VGA)
+ return 0;
+
+ set_fs(0);
+ crtc = vga_crtc();
+
+ video_bios.modes = GET_HEAP(struct mode_info, 0);
+
+ for (mode = 0x14; mode <= 0x7f; mode++) {
+ if (heap_free() < sizeof(struct mode_info))
+ break;
+
+ if (mode_defined(VIDEO_FIRST_BIOS+mode))
+ continue;
+
+ if (set_bios_mode(mode))
+ continue;
+
+ /* Try to verify that it's a text mode. */
+
+ /* Attribute Controller: make graphics controller disabled */
+ if (in_idx(0x3c0, 0x10) & 0x01)
+ continue;
+
+ /* Graphics Controller: verify Alpha addressing enabled */
+ if (in_idx(0x3ce, 0x06) & 0x01)
+ continue;
+
+ /* CRTC cursor location low should be zero(?) */
+ if (in_idx(crtc, 0x0f))
+ continue;
+
+ mi = GET_HEAP(struct mode_info, 1);
+ mi->mode = VIDEO_FIRST_BIOS+mode;
+ mi->x = rdfs16(0x44a);
+ mi->y = rdfs8(0x484)+1;
+ nmodes++;
+ }
+
+ set_bios_mode(saved_mode);
+
+ return nmodes;
+}
+
+__videocard video_bios =
+{
+ .card_name = "BIOS (scanned)",
+ .probe = bios_probe,
+ .set_mode = bios_set_mode,
+ .unsafe = 1,
+ .xmode_first = VIDEO_FIRST_BIOS,
+ .xmode_n = 0x80,
+};
diff --git a/arch/i386/boot/video-vesa.c b/arch/i386/boot/video-vesa.c
new file mode 100644
index 000000000000..e6aa9eb8d93a
--- /dev/null
+++ b/arch/i386/boot/video-vesa.c
@@ -0,0 +1,284 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video-vesa.c
+ *
+ * VESA text modes
+ */
+
+#include "boot.h"
+#include "video.h"
+#include "vesa.h"
+
+/* VESA information */
+static struct vesa_general_info vginfo;
+static struct vesa_mode_info vminfo;
+
+__videocard video_vesa;
+
+static void vesa_store_mode_params_graphics(void);
+
+static int vesa_probe(void)
+{
+#if defined(CONFIG_VIDEO_VESA) || defined(CONFIG_FIRMWARE_EDID)
+ u16 ax;
+ u16 mode;
+ addr_t mode_ptr;
+ struct mode_info *mi;
+ int nmodes = 0;
+
+ video_vesa.modes = GET_HEAP(struct mode_info, 0);
+
+ vginfo.signature = VBE2_MAGIC;
+
+ /* Optimistically assume a VESA BIOS is register-clean... */
+ ax = 0x4f00;
+ asm("int $0x10" : "+a" (ax), "=m" (vginfo) : "D" (&vginfo));
+
+ if (ax != 0x004f ||
+ vginfo.signature != VESA_MAGIC ||
+ vginfo.version < 0x0102)
+ return 0; /* Not present */
+#endif /* CONFIG_VIDEO_VESA || CONFIG_FIRMWARE_EDID */
+#ifdef CONFIG_VIDEO_VESA
+ set_fs(vginfo.video_mode_ptr.seg);
+ mode_ptr = vginfo.video_mode_ptr.off;
+
+ while ((mode = rdfs16(mode_ptr)) != 0xffff) {
+ mode_ptr += 2;
+
+ if (heap_free() < sizeof(struct mode_info))
+ break; /* Heap full, can't save mode info */
+
+ if (mode & ~0x1ff)
+ continue;
+
+ memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
+
+ ax = 0x4f01;
+ asm("int $0x10"
+ : "+a" (ax), "=m" (vminfo)
+ : "c" (mode), "D" (&vminfo));
+
+ if (ax != 0x004f)
+ continue;
+
+ if ((vminfo.mode_attr & 0x15) == 0x05) {
+ /* Text Mode, TTY BIOS supported,
+ supported by hardware */
+ mi = GET_HEAP(struct mode_info, 1);
+ mi->mode = mode + VIDEO_FIRST_VESA;
+ mi->x = vminfo.h_res;
+ mi->y = vminfo.v_res;
+ nmodes++;
+ } else if ((vminfo.mode_attr & 0x99) == 0x99) {
+#ifdef CONFIG_FB
+ /* Graphics mode, color, linear frame buffer
+ supported -- register the mode but hide from
+ the menu. Only do this if framebuffer is
+ configured, however, otherwise the user will
+ be left without a screen. */
+ mi = GET_HEAP(struct mode_info, 1);
+ mi->mode = mode + VIDEO_FIRST_VESA;
+ mi->x = mi->y = 0;
+ nmodes++;
+#endif
+ }
+ }
+
+ return nmodes;
+#else
+ return 0;
+#endif /* CONFIG_VIDEO_VESA */
+}
+
+static int vesa_set_mode(struct mode_info *mode)
+{
+ u16 ax;
+ int is_graphic;
+ u16 vesa_mode = mode->mode - VIDEO_FIRST_VESA;
+
+ memset(&vminfo, 0, sizeof vminfo); /* Just in case... */
+
+ ax = 0x4f01;
+ asm("int $0x10"
+ : "+a" (ax), "=m" (vminfo)
+ : "c" (vesa_mode), "D" (&vminfo));
+
+ if (ax != 0x004f)
+ return -1;
+
+ if ((vminfo.mode_attr & 0x15) == 0x05) {
+ /* It's a supported text mode */
+ is_graphic = 0;
+ } else if ((vminfo.mode_attr & 0x99) == 0x99) {
+ /* It's a graphics mode with linear frame buffer */
+ is_graphic = 1;
+ vesa_mode |= 0x4000; /* Request linear frame buffer */
+ } else {
+ return -1; /* Invalid mode */
+ }
+
+
+ ax = 0x4f02;
+ asm volatile("int $0x10"
+ : "+a" (ax)
+ : "b" (vesa_mode), "D" (0));
+
+ if (ax != 0x004f)
+ return -1;
+
+ graphic_mode = is_graphic;
+ if (!is_graphic) {
+ /* Text mode */
+ force_x = mode->x;
+ force_y = mode->y;
+ do_restore = 1;
+ } else {
+ /* Graphics mode */
+ vesa_store_mode_params_graphics();
+ }
+
+ return 0;
+}
+
+
+/* Switch DAC to 8-bit mode */
+static void vesa_dac_set_8bits(void)
+{
+ u8 dac_size = 6;
+
+ /* If possible, switch the DAC to 8-bit mode */
+ if (vginfo.capabilities & 1) {
+ u16 ax, bx;
+
+ ax = 0x4f08;
+ bx = 0x0800;
+ asm volatile(INT10
+ : "+a" (ax), "+b" (bx)
+ : : "ecx", "edx", "esi", "edi");
+
+ if (ax == 0x004f)
+ dac_size = bx >> 8;
+ }
+
+ /* Set the color sizes to the DAC size, and offsets to 0 */
+ boot_params.screen_info.red_size = dac_size;
+ boot_params.screen_info.green_size = dac_size;
+ boot_params.screen_info.blue_size = dac_size;
+ boot_params.screen_info.rsvd_size = dac_size;
+
+ boot_params.screen_info.red_pos = 0;
+ boot_params.screen_info.green_pos = 0;
+ boot_params.screen_info.blue_pos = 0;
+ boot_params.screen_info.rsvd_pos = 0;
+}
+
+/* Save the VESA protected mode info */
+static void vesa_store_pm_info(void)
+{
+ u16 ax, bx, di, es;
+
+ ax = 0x4f0a;
+ bx = di = 0;
+ asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es"
+ : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di)
+ : : "ecx", "esi");
+
+ if (ax != 0x004f)
+ return;
+
+ boot_params.screen_info.vesapm_seg = es;
+ boot_params.screen_info.vesapm_off = di;
+}
+
+/*
+ * Save video mode parameters for graphics mode
+ */
+static void vesa_store_mode_params_graphics(void)
+{
+ /* Tell the kernel we're in VESA graphics mode */
+ boot_params.screen_info.orig_video_isVGA = 0x23;
+
+ /* Mode parameters */
+ boot_params.screen_info.vesa_attributes = vminfo.mode_attr;
+ boot_params.screen_info.lfb_linelength = vminfo.logical_scan;
+ boot_params.screen_info.lfb_width = vminfo.h_res;
+ boot_params.screen_info.lfb_height = vminfo.v_res;
+ boot_params.screen_info.lfb_depth = vminfo.bpp;
+ boot_params.screen_info.pages = vminfo.image_planes;
+ boot_params.screen_info.lfb_base = vminfo.lfb_ptr;
+ memcpy(&boot_params.screen_info.red_size,
+ &vminfo.rmask, 8);
+
+ /* General parameters */
+ boot_params.screen_info.lfb_size = vginfo.total_memory;
+
+ if (vminfo.bpp <= 8)
+ vesa_dac_set_8bits();
+
+ vesa_store_pm_info();
+}
+
+/*
+ * Save EDID information for the kernel; this is invoked, separately,
+ * after mode-setting.
+ */
+void vesa_store_edid(void)
+{
+#ifdef CONFIG_FIRMWARE_EDID
+ u16 ax, bx, cx, dx, di;
+
+ /* Apparently used as a nonsense token... */
+ memset(&boot_params.edid_info, 0x13, sizeof boot_params.edid_info);
+
+ if (vginfo.version < 0x0200)
+ return; /* EDID requires VBE 2.0+ */
+
+ ax = 0x4f15; /* VBE DDC */
+ bx = 0x0000; /* Report DDC capabilities */
+ cx = 0; /* Controller 0 */
+ di = 0; /* ES:DI must be 0 by spec */
+
+ /* Note: The VBE DDC spec is different from the main VESA spec;
+ we genuinely have to assume all registers are destroyed here. */
+
+ asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es"
+ : "+a" (ax), "+b" (bx)
+ : "c" (cx), "D" (di)
+ : "esi");
+
+ if (ax != 0x004f)
+ return; /* No EDID */
+
+ /* BH = time in seconds to transfer EDD information */
+ /* BL = DDC level supported */
+
+ ax = 0x4f15; /* VBE DDC */
+ bx = 0x0001; /* Read EDID */
+ cx = 0; /* Controller 0 */
+ dx = 0; /* EDID block number */
+ di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */
+ asm(INT10
+ : "+a" (ax), "+b" (bx), "+d" (dx)
+ : "c" (cx), "D" (di)
+ : "esi");
+#endif /* CONFIG_FIRMWARE_EDID */
+}
+
+__videocard video_vesa =
+{
+ .card_name = "VESA",
+ .probe = vesa_probe,
+ .set_mode = vesa_set_mode,
+ .xmode_first = VIDEO_FIRST_VESA,
+ .xmode_n = 0x200,
+};
diff --git a/arch/i386/boot/video-vga.c b/arch/i386/boot/video-vga.c
new file mode 100644
index 000000000000..700d09a9c9b3
--- /dev/null
+++ b/arch/i386/boot/video-vga.c
@@ -0,0 +1,260 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video-vga.c
+ *
+ * Common all-VGA modes
+ */
+
+#include "boot.h"
+#include "video.h"
+
+static struct mode_info vga_modes[] = {
+ { VIDEO_80x25, 80, 25 },
+ { VIDEO_8POINT, 80, 50 },
+ { VIDEO_80x43, 80, 43 },
+ { VIDEO_80x28, 80, 28 },
+ { VIDEO_80x30, 80, 30 },
+ { VIDEO_80x34, 80, 34 },
+ { VIDEO_80x60, 80, 60 },
+};
+
+static struct mode_info ega_modes[] = {
+ { VIDEO_80x25, 80, 25 },
+ { VIDEO_8POINT, 80, 43 },
+};
+
+static struct mode_info cga_modes[] = {
+ { VIDEO_80x25, 80, 25 },
+};
+
+__videocard video_vga;
+
+/* Set basic 80x25 mode */
+static u8 vga_set_basic_mode(void)
+{
+ u16 ax;
+ u8 rows;
+ u8 mode;
+
+#ifdef CONFIG_VIDEO_400_HACK
+ if (adapter >= ADAPTER_VGA) {
+ asm(INT10
+ : : "a" (0x1202), "b" (0x0030)
+ : "ecx", "edx", "esi", "edi");
+ }
+#endif
+
+ ax = 0x0f00;
+ asm(INT10
+ : "+a" (ax)
+ : : "ebx", "ecx", "edx", "esi", "edi");
+
+ mode = (u8)ax;
+
+ set_fs(0);
+ rows = rdfs8(0x484); /* rows minus one */
+
+#ifndef CONFIG_VIDEO_400_HACK
+ if ((ax == 0x5003 || ax == 0x5007) &&
+ (rows == 0 || rows == 24))
+ return mode;
+#endif
+
+ if (mode != 3 && mode != 7)
+ mode = 3;
+
+ /* Set the mode */
+ asm volatile(INT10
+ : : "a" (mode)
+ : "ebx", "ecx", "edx", "esi", "edi");
+ do_restore = 1;
+ return mode;
+}
+
+static void vga_set_8font(void)
+{
+ /* Set 8x8 font - 80x43 on EGA, 80x50 on VGA */
+
+ /* Set 8x8 font */
+ asm volatile(INT10 : : "a" (0x1112), "b" (0));
+
+ /* Use alternate print screen */
+ asm volatile(INT10 : : "a" (0x1200), "b" (0x20));
+
+ /* Turn off cursor emulation */
+ asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
+
+ /* Cursor is scan lines 6-7 */
+ asm volatile(INT10 : : "a" (0x0100), "c" (0x0607));
+}
+
+static void vga_set_14font(void)
+{
+ /* Set 9x14 font - 80x28 on VGA */
+
+ /* Set 9x14 font */
+ asm volatile(INT10 : : "a" (0x1111), "b" (0));
+
+ /* Turn off cursor emulation */
+ asm volatile(INT10 : : "a" (0x1201), "b" (0x34));
+
+ /* Cursor is scan lines 11-12 */
+ asm volatile(INT10 : : "a" (0x0100), "c" (0x0b0c));
+}
+
+static void vga_set_80x43(void)
+{
+ /* Set 80x43 mode on VGA (not EGA) */
+
+ /* Set 350 scans */
+ asm volatile(INT10 : : "a" (0x1201), "b" (0x30));
+
+ /* Reset video mode */
+ asm volatile(INT10 : : "a" (0x0003));
+
+ vga_set_8font();
+}
+
+/* I/O address of the VGA CRTC */
+u16 vga_crtc(void)
+{
+ return (inb(0x3cc) & 1) ? 0x3d4 : 0x3b4;
+}
+
+static void vga_set_480_scanlines(int end)
+{
+ u16 crtc;
+ u8 csel;
+
+ crtc = vga_crtc();
+
+ out_idx(0x0c, crtc, 0x11); /* Vertical sync end, unlock CR0-7 */
+ out_idx(0x0b, crtc, 0x06); /* Vertical total */
+ out_idx(0x3e, crtc, 0x07); /* Vertical overflow */
+ out_idx(0xea, crtc, 0x10); /* Vertical sync start */
+ out_idx(end, crtc, 0x12); /* Vertical display end */
+ out_idx(0xe7, crtc, 0x15); /* Vertical blank start */
+ out_idx(0x04, crtc, 0x16); /* Vertical blank end */
+ csel = inb(0x3cc);
+ csel &= 0x0d;
+ csel |= 0xe2;
+ outb(csel, 0x3cc);
+}
+
+static void vga_set_80x30(void)
+{
+ vga_set_480_scanlines(0xdf);
+}
+
+static void vga_set_80x34(void)
+{
+ vga_set_14font();
+ vga_set_480_scanlines(0xdb);
+}
+
+static void vga_set_80x60(void)
+{
+ vga_set_8font();
+ vga_set_480_scanlines(0xdf);
+}
+
+static int vga_set_mode(struct mode_info *mode)
+{
+ /* Set the basic mode */
+ vga_set_basic_mode();
+
+ /* Override a possibly broken BIOS */
+ force_x = mode->x;
+ force_y = mode->y;
+
+ switch (mode->mode) {
+ case VIDEO_80x25:
+ break;
+ case VIDEO_8POINT:
+ vga_set_8font();
+ break;
+ case VIDEO_80x43:
+ vga_set_80x43();
+ break;
+ case VIDEO_80x28:
+ vga_set_14font();
+ break;
+ case VIDEO_80x30:
+ vga_set_80x30();
+ break;
+ case VIDEO_80x34:
+ vga_set_80x34();
+ break;
+ case VIDEO_80x60:
+ vga_set_80x60();
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Note: this probe includes basic information required by all
+ * systems. It should be executed first, by making sure
+ * video-vga.c is listed first in the Makefile.
+ */
+static int vga_probe(void)
+{
+ static const char *card_name[] = {
+ "CGA/MDA/HGC", "EGA", "VGA"
+ };
+ static struct mode_info *mode_lists[] = {
+ cga_modes,
+ ega_modes,
+ vga_modes,
+ };
+ static int mode_count[] = {
+ sizeof(cga_modes)/sizeof(struct mode_info),
+ sizeof(ega_modes)/sizeof(struct mode_info),
+ sizeof(vga_modes)/sizeof(struct mode_info),
+ };
+ u8 vga_flag;
+
+ asm(INT10
+ : "=b" (boot_params.screen_info.orig_video_ega_bx)
+ : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */
+ : "ecx", "edx", "esi", "edi");
+
+ /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */
+ if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) {
+ /* EGA/VGA */
+ asm(INT10
+ : "=a" (vga_flag)
+ : "a" (0x1a00)
+ : "ebx", "ecx", "edx", "esi", "edi");
+
+ if (vga_flag == 0x1a) {
+ adapter = ADAPTER_VGA;
+ boot_params.screen_info.orig_video_isVGA = 1;
+ } else {
+ adapter = ADAPTER_EGA;
+ }
+ } else {
+ adapter = ADAPTER_CGA;
+ }
+
+ video_vga.modes = mode_lists[adapter];
+ video_vga.card_name = card_name[adapter];
+ return mode_count[adapter];
+}
+
+__videocard video_vga =
+{
+ .card_name = "VGA",
+ .probe = vga_probe,
+ .set_mode = vga_set_mode,
+};
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
deleted file mode 100644
index 8143c9516cb4..000000000000
--- a/arch/i386/boot/video.S
+++ /dev/null
@@ -1,2043 +0,0 @@
-/* video.S
- *
- * Display adapter & video mode setup, version 2.13 (14-May-99)
- *
- * Copyright (C) 1995 -- 1998 Martin Mares <mj@ucw.cz>
- * Based on the original setup.S code (C) Linus Torvalds and Mats Anderson
- *
- * Rewritten to use GNU 'as' by Chris Noe <stiker@northlink.com> May 1999
- *
- * For further information, look at Documentation/svga.txt.
- *
- */
-
-/* Enable autodetection of SVGA adapters and modes. */
-#undef CONFIG_VIDEO_SVGA
-
-/* Enable autodetection of VESA modes */
-#define CONFIG_VIDEO_VESA
-
-/* Enable compacting of mode table */
-#define CONFIG_VIDEO_COMPACT
-
-/* Retain screen contents when switching modes */
-#define CONFIG_VIDEO_RETAIN
-
-/* Enable local mode list */
-#undef CONFIG_VIDEO_LOCAL
-
-/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
-#undef CONFIG_VIDEO_400_HACK
-
-/* Hack that lets you force specific BIOS mode ID and specific dimensions */
-#undef CONFIG_VIDEO_GFX_HACK
-#define VIDEO_GFX_BIOS_AX 0x4f02 /* 800x600 on ThinkPad */
-#define VIDEO_GFX_BIOS_BX 0x0102
-#define VIDEO_GFX_DUMMY_RESOLUTION 0x6425 /* 100x37 */
-
-/* This code uses an extended set of video mode numbers. These include:
- * Aliases for standard modes
- * NORMAL_VGA (-1)
- * EXTENDED_VGA (-2)
- * ASK_VGA (-3)
- * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
- * of compatibility when extending the table. These are between 0x00 and 0xff.
- */
-#define VIDEO_FIRST_MENU 0x0000
-
-/* Standard BIOS video modes (BIOS number + 0x0100) */
-#define VIDEO_FIRST_BIOS 0x0100
-
-/* VESA BIOS video modes (VESA number + 0x0200) */
-#define VIDEO_FIRST_VESA 0x0200
-
-/* Video7 special modes (BIOS number + 0x0900) */
-#define VIDEO_FIRST_V7 0x0900
-
-/* Special video modes */
-#define VIDEO_FIRST_SPECIAL 0x0f00
-#define VIDEO_80x25 0x0f00
-#define VIDEO_8POINT 0x0f01
-#define VIDEO_80x43 0x0f02
-#define VIDEO_80x28 0x0f03
-#define VIDEO_CURRENT_MODE 0x0f04
-#define VIDEO_80x30 0x0f05
-#define VIDEO_80x34 0x0f06
-#define VIDEO_80x60 0x0f07
-#define VIDEO_GFX_HACK 0x0f08
-#define VIDEO_LAST_SPECIAL 0x0f09
-
-/* Video modes given by resolution */
-#define VIDEO_FIRST_RESOLUTION 0x1000
-
-/* The "recalculate timings" flag */
-#define VIDEO_RECALC 0x8000
-
-/* Positions of various video parameters passed to the kernel */
-/* (see also include/linux/tty.h) */
-#define PARAM_CURSOR_POS 0x00
-#define PARAM_VIDEO_PAGE 0x04
-#define PARAM_VIDEO_MODE 0x06
-#define PARAM_VIDEO_COLS 0x07
-#define PARAM_VIDEO_EGA_BX 0x0a
-#define PARAM_VIDEO_LINES 0x0e
-#define PARAM_HAVE_VGA 0x0f
-#define PARAM_FONT_POINTS 0x10
-
-#define PARAM_LFB_WIDTH 0x12
-#define PARAM_LFB_HEIGHT 0x14
-#define PARAM_LFB_DEPTH 0x16
-#define PARAM_LFB_BASE 0x18
-#define PARAM_LFB_SIZE 0x1c
-#define PARAM_LFB_LINELENGTH 0x24
-#define PARAM_LFB_COLORS 0x26
-#define PARAM_VESAPM_SEG 0x2e
-#define PARAM_VESAPM_OFF 0x30
-#define PARAM_LFB_PAGES 0x32
-#define PARAM_VESA_ATTRIB 0x34
-#define PARAM_CAPABILITIES 0x36
-
-/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
-#ifdef CONFIG_VIDEO_RETAIN
-#define DO_STORE call store_screen
-#else
-#define DO_STORE
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# This is the main entry point called by setup.S
-# %ds *must* be pointing to the bootsector
-video: pushw %ds # We use different segments
- pushw %ds # FS contains original DS
- popw %fs
- pushw %cs # DS is equal to CS
- popw %ds
- pushw %cs # ES is equal to CS
- popw %es
- xorw %ax, %ax
- movw %ax, %gs # GS is zero
- cld
- call basic_detect # Basic adapter type testing (EGA/VGA/MDA/CGA)
-#ifdef CONFIG_VIDEO_SELECT
- movw %fs:(0x01fa), %ax # User selected video mode
- cmpw $ASK_VGA, %ax # Bring up the menu
- jz vid2
-
- call mode_set # Set the mode
- jc vid1
-
- leaw badmdt, %si # Invalid mode ID
- call prtstr
-vid2: call mode_menu
-vid1:
-#ifdef CONFIG_VIDEO_RETAIN
- call restore_screen # Restore screen contents
-#endif /* CONFIG_VIDEO_RETAIN */
- call store_edid
-#endif /* CONFIG_VIDEO_SELECT */
- call mode_params # Store mode parameters
- popw %ds # Restore original DS
- ret
-
-# Detect if we have CGA, MDA, EGA or VGA and pass it to the kernel.
-basic_detect:
- movb $0, %fs:(PARAM_HAVE_VGA)
- movb $0x12, %ah # Check EGA/VGA
- movb $0x10, %bl
- int $0x10
- movw %bx, %fs:(PARAM_VIDEO_EGA_BX) # Identifies EGA to the kernel
- cmpb $0x10, %bl # No, it's a CGA/MDA/HGA card.
- je basret
-
- incb adapter
- movw $0x1a00, %ax # Check EGA or VGA?
- int $0x10
- cmpb $0x1a, %al # 1a means VGA...
- jne basret # anything else is EGA.
-
- incb %fs:(PARAM_HAVE_VGA) # We've detected a VGA
- incb adapter
-basret: ret
-
-# Store the video mode parameters for later usage by the kernel.
-# This is done by asking the BIOS except for the rows/columns
-# parameters in the default 80x25 mode -- these are set directly,
-# because some very obscure BIOSes supply insane values.
-mode_params:
-#ifdef CONFIG_VIDEO_SELECT
- cmpb $0, graphic_mode
- jnz mopar_gr
-#endif
- movb $0x03, %ah # Read cursor position
- xorb %bh, %bh
- int $0x10
- movw %dx, %fs:(PARAM_CURSOR_POS)
- movb $0x0f, %ah # Read page/mode/width
- int $0x10
- movw %bx, %fs:(PARAM_VIDEO_PAGE)
- movw %ax, %fs:(PARAM_VIDEO_MODE) # Video mode and screen width
- cmpb $0x7, %al # MDA/HGA => segment differs
- jnz mopar0
-
- movw $0xb000, video_segment
-mopar0: movw %gs:(0x485), %ax # Font size
- movw %ax, %fs:(PARAM_FONT_POINTS) # (valid only on EGA/VGA)
- movw force_size, %ax # Forced size?
- orw %ax, %ax
- jz mopar1
-
- movb %ah, %fs:(PARAM_VIDEO_COLS)
- movb %al, %fs:(PARAM_VIDEO_LINES)
- ret
-
-mopar1: movb $25, %al
- cmpb $0, adapter # If we are on CGA/MDA/HGA, the
- jz mopar2 # screen must have 25 lines.
-
- movb %gs:(0x484), %al # On EGA/VGA, use the EGA+ BIOS
- incb %al # location of max lines.
-mopar2: movb %al, %fs:(PARAM_VIDEO_LINES)
- ret
-
-#ifdef CONFIG_VIDEO_SELECT
-# Fetching of VESA frame buffer parameters
-mopar_gr:
- leaw modelist+1024, %di
- movb $0x23, %fs:(PARAM_HAVE_VGA)
- movw 16(%di), %ax
- movw %ax, %fs:(PARAM_LFB_LINELENGTH)
- movw 18(%di), %ax
- movw %ax, %fs:(PARAM_LFB_WIDTH)
- movw 20(%di), %ax
- movw %ax, %fs:(PARAM_LFB_HEIGHT)
- movb 25(%di), %al
- movb $0, %ah
- movw %ax, %fs:(PARAM_LFB_DEPTH)
- movb 29(%di), %al
- movb $0, %ah
- movw %ax, %fs:(PARAM_LFB_PAGES)
- movl 40(%di), %eax
- movl %eax, %fs:(PARAM_LFB_BASE)
- movl 31(%di), %eax
- movl %eax, %fs:(PARAM_LFB_COLORS)
- movl 35(%di), %eax
- movl %eax, %fs:(PARAM_LFB_COLORS+4)
- movw 0(%di), %ax
- movw %ax, %fs:(PARAM_VESA_ATTRIB)
-
-# get video mem size
- leaw modelist+1024, %di
- movw $0x4f00, %ax
- int $0x10
- xorl %eax, %eax
- movw 18(%di), %ax
- movl %eax, %fs:(PARAM_LFB_SIZE)
-
-# store mode capabilities
- movl 10(%di), %eax
- movl %eax, %fs:(PARAM_CAPABILITIES)
-
-# switching the DAC to 8-bit is for <= 8 bpp only
- movw %fs:(PARAM_LFB_DEPTH), %ax
- cmpw $8, %ax
- jg dac_done
-
-# get DAC switching capability
- xorl %eax, %eax
- movb 10(%di), %al
- testb $1, %al
- jz dac_set
-
-# attempt to switch DAC to 8-bit
- movw $0x4f08, %ax
- movw $0x0800, %bx
- int $0x10
- cmpw $0x004f, %ax
- jne dac_set
- movb %bh, dac_size # store actual DAC size
-
-dac_set:
-# set color size to DAC size
- movb dac_size, %al
- movb %al, %fs:(PARAM_LFB_COLORS+0)
- movb %al, %fs:(PARAM_LFB_COLORS+2)
- movb %al, %fs:(PARAM_LFB_COLORS+4)
- movb %al, %fs:(PARAM_LFB_COLORS+6)
-
-# set color offsets to 0
- movb $0, %fs:(PARAM_LFB_COLORS+1)
- movb $0, %fs:(PARAM_LFB_COLORS+3)
- movb $0, %fs:(PARAM_LFB_COLORS+5)
- movb $0, %fs:(PARAM_LFB_COLORS+7)
-
-dac_done:
-# get protected mode interface informations
- movw $0x4f0a, %ax
- xorw %bx, %bx
- xorw %di, %di
- int $0x10
- cmp $0x004f, %ax
- jnz no_pm
-
- movw %es, %fs:(PARAM_VESAPM_SEG)
- movw %di, %fs:(PARAM_VESAPM_OFF)
-no_pm: ret
-
-# The video mode menu
-mode_menu:
- leaw keymsg, %si # "Return/Space/Timeout" message
- call prtstr
- call flush
-nokey: call getkt
-
- cmpb $0x0d, %al # ENTER ?
- je listm # yes - manual mode selection
-
- cmpb $0x20, %al # SPACE ?
- je defmd1 # no - repeat
-
- call beep
- jmp nokey
-
-defmd1: ret # No mode chosen? Default 80x25
-
-listm: call mode_table # List mode table
-listm0: leaw name_bann, %si # Print adapter name
- call prtstr
- movw card_name, %si
- orw %si, %si
- jnz an2
-
- movb adapter, %al
- leaw old_name, %si
- orb %al, %al
- jz an1
-
- leaw ega_name, %si
- decb %al
- jz an1
-
- leaw vga_name, %si
- jmp an1
-
-an2: call prtstr
- leaw svga_name, %si
-an1: call prtstr
- leaw listhdr, %si # Table header
- call prtstr
- movb $0x30, %dl # DL holds mode number
- leaw modelist, %si
-lm1: cmpw $ASK_VGA, (%si) # End?
- jz lm2
-
- movb %dl, %al # Menu selection number
- call prtchr
- call prtsp2
- lodsw
- call prthw # Mode ID
- call prtsp2
- movb 0x1(%si), %al
- call prtdec # Rows
- movb $0x78, %al # the letter 'x'
- call prtchr
- lodsw
- call prtdec # Columns
- movb $0x0d, %al # New line
- call prtchr
- movb $0x0a, %al
- call prtchr
- incb %dl # Next character
- cmpb $0x3a, %dl
- jnz lm1
-
- movb $0x61, %dl
- jmp lm1
-
-lm2: leaw prompt, %si # Mode prompt
- call prtstr
- leaw edit_buf, %di # Editor buffer
-lm3: call getkey
- cmpb $0x0d, %al # Enter?
- jz lment
-
- cmpb $0x08, %al # Backspace?
- jz lmbs
-
- cmpb $0x20, %al # Printable?
- jc lm3
-
- cmpw $edit_buf+4, %di # Enough space?
- jz lm3
-
- stosb
- call prtchr
- jmp lm3
-
-lmbs: cmpw $edit_buf, %di # Backspace
- jz lm3
-
- decw %di
- movb $0x08, %al
- call prtchr
- call prtspc
- movb $0x08, %al
- call prtchr
- jmp lm3
-
-lment: movb $0, (%di)
- leaw crlft, %si
- call prtstr
- leaw edit_buf, %si
- cmpb $0, (%si) # Empty string = default mode
- jz lmdef
-
- cmpb $0, 1(%si) # One character = menu selection
- jz mnusel
-
- cmpw $0x6373, (%si) # "scan" => mode scanning
- jnz lmhx
-
- cmpw $0x6e61, 2(%si)
- jz lmscan
-
-lmhx: xorw %bx, %bx # Else => mode ID in hex
-lmhex: lodsb
- orb %al, %al
- jz lmuse1
-
- subb $0x30, %al
- jc lmbad
-
- cmpb $10, %al
- jc lmhx1
-
- subb $7, %al
- andb $0xdf, %al
- cmpb $10, %al
- jc lmbad
-
- cmpb $16, %al
- jnc lmbad
-
-lmhx1: shlw $4, %bx
- orb %al, %bl
- jmp lmhex
-
-lmuse1: movw %bx, %ax
- jmp lmuse
-
-mnusel: lodsb # Menu selection
- xorb %ah, %ah
- subb $0x30, %al
- jc lmbad
-
- cmpb $10, %al
- jc lmuse
-
- cmpb $0x61-0x30, %al
- jc lmbad
-
- subb $0x61-0x30-10, %al
- cmpb $36, %al
- jnc lmbad
-
-lmuse: call mode_set
- jc lmdef
-
-lmbad: leaw unknt, %si
- call prtstr
- jmp lm2
-lmscan: cmpb $0, adapter # Scanning only on EGA/VGA
- jz lmbad
-
- movw $0, mt_end # Scanning of modes is
- movb $1, scanning # done as new autodetection.
- call mode_table
- jmp listm0
-lmdef: ret
-
-# Additional parts of mode_set... (relative jumps, you know)
-setv7: # Video7 extended modes
- DO_STORE
- subb $VIDEO_FIRST_V7>>8, %bh
- movw $0x6f05, %ax
- int $0x10
- stc
- ret
-
-_setrec: jmp setrec # Ugly...
-_set_80x25: jmp set_80x25
-
-# Aliases for backward compatibility.
-setalias:
- movw $VIDEO_80x25, %ax
- incw %bx
- jz mode_set
-
- movb $VIDEO_8POINT-VIDEO_FIRST_SPECIAL, %al
- incw %bx
- jnz setbad # Fall-through!
-
-# Setting of user mode (AX=mode ID) => CF=success
-mode_set:
- movw %ax, %fs:(0x01fa) # Store mode for use in acpi_wakeup.S
- movw %ax, %bx
- cmpb $0xff, %ah
- jz setalias
-
- testb $VIDEO_RECALC>>8, %ah
- jnz _setrec
-
- cmpb $VIDEO_FIRST_RESOLUTION>>8, %ah
- jnc setres
-
- cmpb $VIDEO_FIRST_SPECIAL>>8, %ah
- jz setspc
-
- cmpb $VIDEO_FIRST_V7>>8, %ah
- jz setv7
-
- cmpb $VIDEO_FIRST_VESA>>8, %ah
- jnc check_vesa
-
- orb %ah, %ah
- jz setmenu
-
- decb %ah
- jz setbios
-
-setbad: clc
- movb $0, do_restore # The screen needn't be restored
- ret
-
-setvesa:
- DO_STORE
- subb $VIDEO_FIRST_VESA>>8, %bh
- movw $0x4f02, %ax # VESA BIOS mode set call
- int $0x10
- cmpw $0x004f, %ax # AL=4f if implemented
- jnz setbad # AH=0 if OK
-
- stc
- ret
-
-setbios:
- DO_STORE
- int $0x10 # Standard BIOS mode set call
- pushw %bx
- movb $0x0f, %ah # Check if really set
- int $0x10
- popw %bx
- cmpb %bl, %al
- jnz setbad
-
- stc
- ret
-
-setspc: xorb %bh, %bh # Set special mode
- cmpb $VIDEO_LAST_SPECIAL-VIDEO_FIRST_SPECIAL, %bl
- jnc setbad
-
- addw %bx, %bx
- jmp *spec_inits(%bx)
-
-setmenu:
- orb %al, %al # 80x25 is an exception
- jz _set_80x25
-
- pushw %bx # Set mode chosen from menu
- call mode_table # Build the mode table
- popw %ax
- shlw $2, %ax
- addw %ax, %si
- cmpw %di, %si
- jnc setbad
-
- movw (%si), %ax # Fetch mode ID
-_m_s: jmp mode_set
-
-setres: pushw %bx # Set mode chosen by resolution
- call mode_table
- popw %bx
- xchgb %bl, %bh
-setr1: lodsw
- cmpw $ASK_VGA, %ax # End of the list?
- jz setbad
-
- lodsw
- cmpw %bx, %ax
- jnz setr1
-
- movw -4(%si), %ax # Fetch mode ID
- jmp _m_s
-
-check_vesa:
-#ifdef CONFIG_FIRMWARE_EDID
- leaw modelist+1024, %di
- movw $0x4f00, %ax
- int $0x10
- cmpw $0x004f, %ax
- jnz setbad
-
- movw 4(%di), %ax
- movw %ax, vbe_version
-#endif
- leaw modelist+1024, %di
- subb $VIDEO_FIRST_VESA>>8, %bh
- movw %bx, %cx # Get mode information structure
- movw $0x4f01, %ax
- int $0x10
- addb $VIDEO_FIRST_VESA>>8, %bh
- cmpw $0x004f, %ax
- jnz setbad
-
- movb (%di), %al # Check capabilities.
- andb $0x19, %al
- cmpb $0x09, %al
- jz setvesa # This is a text mode
-
- movb (%di), %al # Check capabilities.
- andb $0x99, %al
- cmpb $0x99, %al
- jnz _setbad # Doh! No linear frame buffer.
-
- subb $VIDEO_FIRST_VESA>>8, %bh
- orw $0x4000, %bx # Use linear frame buffer
- movw $0x4f02, %ax # VESA BIOS mode set call
- int $0x10
- cmpw $0x004f, %ax # AL=4f if implemented
- jnz _setbad # AH=0 if OK
-
- movb $1, graphic_mode # flag graphic mode
- movb $0, do_restore # no screen restore
- stc
- ret
-
-_setbad: jmp setbad # Ugly...
-
-# Recalculate vertical display end registers -- this fixes various
-# inconsistencies of extended modes on many adapters. Called when
-# the VIDEO_RECALC flag is set in the mode ID.
-
-setrec: subb $VIDEO_RECALC>>8, %ah # Set the base mode
- call mode_set
- jnc rct3
-
- movw %gs:(0x485), %ax # Font size in pixels
- movb %gs:(0x484), %bl # Number of rows
- incb %bl
- mulb %bl # Number of visible
- decw %ax # scan lines - 1
- movw $0x3d4, %dx
- movw %ax, %bx
- movb $0x12, %al # Lower 8 bits
- movb %bl, %ah
- outw %ax, %dx
- movb $0x07, %al # Bits 8 and 9 in the overflow register
- call inidx
- xchgb %al, %ah
- andb $0xbd, %ah
- shrb %bh
- jnc rct1
- orb $0x02, %ah
-rct1: shrb %bh
- jnc rct2
- orb $0x40, %ah
-rct2: movb $0x07, %al
- outw %ax, %dx
- stc
-rct3: ret
-
-# Table of routines for setting of the special modes.
-spec_inits:
- .word set_80x25
- .word set_8pixel
- .word set_80x43
- .word set_80x28
- .word set_current
- .word set_80x30
- .word set_80x34
- .word set_80x60
- .word set_gfx
-
-# Set the 80x25 mode. If already set, do nothing.
-set_80x25:
- movw $0x5019, force_size # Override possibly broken BIOS
-use_80x25:
-#ifdef CONFIG_VIDEO_400_HACK
- movw $0x1202, %ax # Force 400 scan lines
- movb $0x30, %bl
- int $0x10
-#else
- movb $0x0f, %ah # Get current mode ID
- int $0x10
- cmpw $0x5007, %ax # Mode 7 (80x25 mono) is the only one available
- jz st80 # on CGA/MDA/HGA and is also available on EGAM
-
- cmpw $0x5003, %ax # Unknown mode, force 80x25 color
- jnz force3
-
-st80: cmpb $0, adapter # CGA/MDA/HGA => mode 3/7 is always 80x25
- jz set80
-
- movb %gs:(0x0484), %al # This is EGA+ -- beware of 80x50 etc.
- orb %al, %al # Some buggy BIOS'es set 0 rows
- jz set80
-
- cmpb $24, %al # It's hopefully correct
- jz set80
-#endif /* CONFIG_VIDEO_400_HACK */
-force3: DO_STORE
- movw $0x0003, %ax # Forced set
- int $0x10
-set80: stc
- ret
-
-# Set the 80x50/80x43 8-pixel mode. Simple BIOS calls.
-set_8pixel:
- DO_STORE
- call use_80x25 # The base is 80x25
-set_8pt:
- movw $0x1112, %ax # Use 8x8 font
- xorb %bl, %bl
- int $0x10
- movw $0x1200, %ax # Use alternate print screen
- movb $0x20, %bl
- int $0x10
- movw $0x1201, %ax # Turn off cursor emulation
- movb $0x34, %bl
- int $0x10
- movb $0x01, %ah # Define cursor scan lines 6-7
- movw $0x0607, %cx
- int $0x10
-set_current:
- stc
- ret
-
-# Set the 80x28 mode. This mode works on all VGA's, because it's a standard
-# 80x25 mode with 14-point fonts instead of 16-point.
-set_80x28:
- DO_STORE
- call use_80x25 # The base is 80x25
-set14: movw $0x1111, %ax # Use 9x14 font
- xorb %bl, %bl
- int $0x10
- movb $0x01, %ah # Define cursor scan lines 11-12
- movw $0x0b0c, %cx
- int $0x10
- stc
- ret
-
-# Set the 80x43 mode. This mode is works on all VGA's.
-# It's a 350-scanline mode with 8-pixel font.
-set_80x43:
- DO_STORE
- movw $0x1201, %ax # Set 350 scans
- movb $0x30, %bl
- int $0x10
- movw $0x0003, %ax # Reset video mode
- int $0x10
- jmp set_8pt # Use 8-pixel font
-
-# Set the 80x30 mode (all VGA's). 480 scanlines, 16-pixel font.
-set_80x30:
- call use_80x25 # Start with real 80x25
- DO_STORE
- movw $0x3cc, %dx # Get CRTC port
- inb %dx, %al
- movb $0xd4, %dl
- rorb %al # Mono or color?
- jc set48a
-
- movb $0xb4, %dl
-set48a: movw $0x0c11, %ax # Vertical sync end (also unlocks CR0-7)
- call outidx
- movw $0x0b06, %ax # Vertical total
- call outidx
- movw $0x3e07, %ax # (Vertical) overflow
- call outidx
- movw $0xea10, %ax # Vertical sync start
- call outidx
- movw $0xdf12, %ax # Vertical display end
- call outidx
- movw $0xe715, %ax # Vertical blank start
- call outidx
- movw $0x0416, %ax # Vertical blank end
- call outidx
- pushw %dx
- movb $0xcc, %dl # Misc output register (read)
- inb %dx, %al
- movb $0xc2, %dl # (write)
- andb $0x0d, %al # Preserve clock select bits and color bit
- orb $0xe2, %al # Set correct sync polarity
- outb %al, %dx
- popw %dx
- movw $0x501e, force_size
- stc # That's all.
- ret
-
-# Set the 80x34 mode (all VGA's). 480 scans, 14-pixel font.
-set_80x34:
- call set_80x30 # Set 480 scans
- call set14 # And 14-pt font
- movw $0xdb12, %ax # VGA vertical display end
- movw $0x5022, force_size
-setvde: call outidx
- stc
- ret
-
-# Set the 80x60 mode (all VGA's). 480 scans, 8-pixel font.
-set_80x60:
- call set_80x30 # Set 480 scans
- call set_8pt # And 8-pt font
- movw $0xdf12, %ax # VGA vertical display end
- movw $0x503c, force_size
- jmp setvde
-
-# Special hack for ThinkPad graphics
-set_gfx:
-#ifdef CONFIG_VIDEO_GFX_HACK
- movw $VIDEO_GFX_BIOS_AX, %ax
- movw $VIDEO_GFX_BIOS_BX, %bx
- int $0x10
- movw $VIDEO_GFX_DUMMY_RESOLUTION, force_size
- stc
-#endif
- ret
-
-#ifdef CONFIG_VIDEO_RETAIN
-
-# Store screen contents to temporary buffer.
-store_screen:
- cmpb $0, do_restore # Already stored?
- jnz stsr
-
- testb $CAN_USE_HEAP, loadflags # Have we space for storing?
- jz stsr
-
- pushw %ax
- pushw %bx
- pushw force_size # Don't force specific size
- movw $0, force_size
- call mode_params # Obtain params of current mode
- popw force_size
- movb %fs:(PARAM_VIDEO_LINES), %ah
- movb %fs:(PARAM_VIDEO_COLS), %al
- movw %ax, %bx # BX=dimensions
- mulb %ah
- movw %ax, %cx # CX=number of characters
- addw %ax, %ax # Calculate image size
- addw $modelist+1024+4, %ax
- cmpw heap_end_ptr, %ax
- jnc sts1 # Unfortunately, out of memory
-
- movw %fs:(PARAM_CURSOR_POS), %ax # Store mode params
- leaw modelist+1024, %di
- stosw
- movw %bx, %ax
- stosw
- pushw %ds # Store the screen
- movw video_segment, %ds
- xorw %si, %si
- rep
- movsw
- popw %ds
- incb do_restore # Screen will be restored later
-sts1: popw %bx
- popw %ax
-stsr: ret
-
-# Restore screen contents from temporary buffer.
-restore_screen:
- cmpb $0, do_restore # Has the screen been stored?
- jz res1
-
- call mode_params # Get parameters of current mode
- movb %fs:(PARAM_VIDEO_LINES), %cl
- movb %fs:(PARAM_VIDEO_COLS), %ch
- leaw modelist+1024, %si # Screen buffer
- lodsw # Set cursor position
- movw %ax, %dx
- cmpb %cl, %dh
- jc res2
-
- movb %cl, %dh
- decb %dh
-res2: cmpb %ch, %dl
- jc res3
-
- movb %ch, %dl
- decb %dl
-res3: movb $0x02, %ah
- movb $0x00, %bh
- int $0x10
- lodsw # Display size
- movb %ah, %dl # DL=number of lines
- movb $0, %ah # BX=phys. length of orig. line
- movw %ax, %bx
- cmpb %cl, %dl # Too many?
- jc res4
-
- pushw %ax
- movb %dl, %al
- subb %cl, %al
- mulb %bl
- addw %ax, %si
- addw %ax, %si
- popw %ax
- movb %cl, %dl
-res4: cmpb %ch, %al # Too wide?
- jc res5
-
- movb %ch, %al # AX=width of src. line
-res5: movb $0, %cl
- xchgb %ch, %cl
- movw %cx, %bp # BP=width of dest. line
- pushw %es
- movw video_segment, %es
- xorw %di, %di # Move the data
- addw %bx, %bx # Convert BX and BP to _bytes_
- addw %bp, %bp
-res6: pushw %si
- pushw %di
- movw %ax, %cx
- rep
- movsw
- popw %di
- popw %si
- addw %bp, %di
- addw %bx, %si
- decb %dl
- jnz res6
-
- popw %es # Done
-res1: ret
-#endif /* CONFIG_VIDEO_RETAIN */
-
-# Write to indexed VGA register (AL=index, AH=data, DX=index reg. port)
-outidx: outb %al, %dx
- pushw %ax
- movb %ah, %al
- incw %dx
- outb %al, %dx
- decw %dx
- popw %ax
- ret
-
-# Build the table of video modes (stored after the setup.S code at the
-# `modelist' label. Each video mode record looks like:
-# .word MODE-ID (our special mode ID (see above))
-# .byte rows (number of rows)
-# .byte columns (number of columns)
-# Returns address of the end of the table in DI, the end is marked
-# with a ASK_VGA ID.
-mode_table:
- movw mt_end, %di # Already filled?
- orw %di, %di
- jnz mtab1x
-
- leaw modelist, %di # Store standard modes:
- movl $VIDEO_80x25 + 0x50190000, %eax # The 80x25 mode (ALL)
- stosl
- movb adapter, %al # CGA/MDA/HGA -- no more modes
- orb %al, %al
- jz mtabe
-
- decb %al
- jnz mtabv
-
- movl $VIDEO_8POINT + 0x502b0000, %eax # The 80x43 EGA mode
- stosl
- jmp mtabe
-
-mtab1x: jmp mtab1
-
-mtabv: leaw vga_modes, %si # All modes for std VGA
- movw $vga_modes_end-vga_modes, %cx
- rep # I'm unable to use movsw as I don't know how to store a half
- movsb # of the expression above to cx without using explicit shr.
-
- cmpb $0, scanning # Mode scan requested?
- jz mscan1
-
- call mode_scan
-mscan1:
-
-#ifdef CONFIG_VIDEO_LOCAL
- call local_modes
-#endif /* CONFIG_VIDEO_LOCAL */
-
-#ifdef CONFIG_VIDEO_VESA
- call vesa_modes # Detect VESA VGA modes
-#endif /* CONFIG_VIDEO_VESA */
-
-#ifdef CONFIG_VIDEO_SVGA
- cmpb $0, scanning # Bypass when scanning
- jnz mscan2
-
- call svga_modes # Detect SVGA cards & modes
-mscan2:
-#endif /* CONFIG_VIDEO_SVGA */
-
-mtabe:
-
-#ifdef CONFIG_VIDEO_COMPACT
- leaw modelist, %si
- movw %di, %dx
- movw %si, %di
-cmt1: cmpw %dx, %si # Scan all modes
- jz cmt2
-
- leaw modelist, %bx # Find in previous entries
- movw 2(%si), %cx
-cmt3: cmpw %bx, %si
- jz cmt4
-
- cmpw 2(%bx), %cx # Found => don't copy this entry
- jz cmt5
-
- addw $4, %bx
- jmp cmt3
-
-cmt4: movsl # Copy entry
- jmp cmt1
-
-cmt5: addw $4, %si # Skip entry
- jmp cmt1
-
-cmt2:
-#endif /* CONFIG_VIDEO_COMPACT */
-
- movw $ASK_VGA, (%di) # End marker
- movw %di, mt_end
-mtab1: leaw modelist, %si # SI=mode list, DI=list end
-ret0: ret
-
-# Modes usable on all standard VGAs
-vga_modes:
- .word VIDEO_8POINT
- .word 0x5032 # 80x50
- .word VIDEO_80x43
- .word 0x502b # 80x43
- .word VIDEO_80x28
- .word 0x501c # 80x28
- .word VIDEO_80x30
- .word 0x501e # 80x30
- .word VIDEO_80x34
- .word 0x5022 # 80x34
- .word VIDEO_80x60
- .word 0x503c # 80x60
-#ifdef CONFIG_VIDEO_GFX_HACK
- .word VIDEO_GFX_HACK
- .word VIDEO_GFX_DUMMY_RESOLUTION
-#endif
-
-vga_modes_end:
-# Detect VESA modes.
-
-#ifdef CONFIG_VIDEO_VESA
-vesa_modes:
- cmpb $2, adapter # VGA only
- jnz ret0
-
- movw %di, %bp # BP=original mode table end
- addw $0x200, %di # Buffer space
- movw $0x4f00, %ax # VESA Get card info call
- int $0x10
- movw %bp, %di
- cmpw $0x004f, %ax # Successful?
- jnz ret0
-
- cmpw $0x4556, 0x200(%di)
- jnz ret0
-
- cmpw $0x4153, 0x202(%di)
- jnz ret0
-
- movw $vesa_name, card_name # Set name to "VESA VGA"
- pushw %gs
- lgsw 0x20e(%di), %si # GS:SI=mode list
- movw $128, %cx # Iteration limit
-vesa1:
-# gas version 2.9.1, using BFD version 2.9.1.0.23 buggers the next inst.
-# XXX: lodsw %gs:(%si), %ax # Get next mode in the list
- gs; lodsw
- cmpw $0xffff, %ax # End of the table?
- jz vesar
-
- cmpw $0x0080, %ax # Check validity of mode ID
- jc vesa2
-
- orb %ah, %ah # Valid IDs: 0x0000-0x007f/0x0100-0x07ff
- jz vesan # Certain BIOSes report 0x80-0xff!
-
- cmpw $0x0800, %ax
- jnc vesae
-
-vesa2: pushw %cx
- movw %ax, %cx # Get mode information structure
- movw $0x4f01, %ax
- int $0x10
- movw %cx, %bx # BX=mode number
- addb $VIDEO_FIRST_VESA>>8, %bh
- popw %cx
- cmpw $0x004f, %ax
- jnz vesan # Don't report errors (buggy BIOSES)
-
- movb (%di), %al # Check capabilities. We require
- andb $0x19, %al # a color text mode.
- cmpb $0x09, %al
- jnz vesan
-
- cmpw $0xb800, 8(%di) # Standard video memory address required
- jnz vesan
-
- testb $2, (%di) # Mode characteristics supplied?
- movw %bx, (%di) # Store mode number
- jz vesa3
-
- xorw %dx, %dx
- movw 0x12(%di), %bx # Width
- orb %bh, %bh
- jnz vesan
-
- movb %bl, 0x3(%di)
- movw 0x14(%di), %ax # Height
- orb %ah, %ah
- jnz vesan
-
- movb %al, 2(%di)
- mulb %bl
- cmpw $8193, %ax # Small enough for Linux console driver?
- jnc vesan
-
- jmp vesaok
-
-vesa3: subw $0x8108, %bx # This mode has no detailed info specified,
- jc vesan # so it must be a standard VESA mode.
-
- cmpw $5, %bx
- jnc vesan
-
- movw vesa_text_mode_table(%bx), %ax
- movw %ax, 2(%di)
-vesaok: addw $4, %di # The mode is valid. Store it.
-vesan: loop vesa1 # Next mode. Limit exceeded => error
-vesae: leaw vesaer, %si
- call prtstr
- movw %bp, %di # Discard already found modes.
-vesar: popw %gs
- ret
-
-# Dimensions of standard VESA text modes
-vesa_text_mode_table:
- .byte 60, 80 # 0108
- .byte 25, 132 # 0109
- .byte 43, 132 # 010A
- .byte 50, 132 # 010B
- .byte 60, 132 # 010C
-#endif /* CONFIG_VIDEO_VESA */
-
-# Scan for video modes. A bit dirty, but should work.
-mode_scan:
- movw $0x0100, %cx # Start with mode 0
-scm1: movb $0, %ah # Test the mode
- movb %cl, %al
- int $0x10
- movb $0x0f, %ah
- int $0x10
- cmpb %cl, %al
- jnz scm2 # Mode not set
-
- movw $0x3c0, %dx # Test if it's a text mode
- movb $0x10, %al # Mode bits
- call inidx
- andb $0x03, %al
- jnz scm2
-
- movb $0xce, %dl # Another set of mode bits
- movb $0x06, %al
- call inidx
- shrb %al
- jc scm2
-
- movb $0xd4, %dl # Cursor location
- movb $0x0f, %al
- call inidx
- orb %al, %al
- jnz scm2
-
- movw %cx, %ax # Ok, store the mode
- stosw
- movb %gs:(0x484), %al # Number of rows
- incb %al
- stosb
- movw %gs:(0x44a), %ax # Number of columns
- stosb
-scm2: incb %cl
- jns scm1
-
- movw $0x0003, %ax # Return back to mode 3
- int $0x10
- ret
-
-tstidx: outw %ax, %dx # OUT DX,AX and inidx
-inidx: outb %al, %dx # Read from indexed VGA register
- incw %dx # AL=index, DX=index reg port -> AL=data
- inb %dx, %al
- decw %dx
- ret
-
-# Try to detect type of SVGA card and supply (usually approximate) video
-# mode table for it.
-
-#ifdef CONFIG_VIDEO_SVGA
-svga_modes:
- leaw svga_table, %si # Test all known SVGA adapters
-dosvga: lodsw
- movw %ax, %bp # Default mode table
- orw %ax, %ax
- jz didsv1
-
- lodsw # Pointer to test routine
- pushw %si
- pushw %di
- pushw %es
- movw $0xc000, %bx
- movw %bx, %es
- call *%ax # Call test routine
- popw %es
- popw %di
- popw %si
- orw %bp, %bp
- jz dosvga
-
- movw %bp, %si # Found, copy the modes
- movb svga_prefix, %ah
-cpsvga: lodsb
- orb %al, %al
- jz didsv
-
- stosw
- movsw
- jmp cpsvga
-
-didsv: movw %si, card_name # Store pointer to card name
-didsv1: ret
-
-# Table of all known SVGA cards. For each card, we store a pointer to
-# a table of video modes supported by the card and a pointer to a routine
-# used for testing of presence of the card. The video mode table is always
-# followed by the name of the card or the chipset.
-svga_table:
- .word ati_md, ati_test
- .word oak_md, oak_test
- .word paradise_md, paradise_test
- .word realtek_md, realtek_test
- .word s3_md, s3_test
- .word chips_md, chips_test
- .word video7_md, video7_test
- .word cirrus5_md, cirrus5_test
- .word cirrus6_md, cirrus6_test
- .word cirrus1_md, cirrus1_test
- .word ahead_md, ahead_test
- .word everex_md, everex_test
- .word genoa_md, genoa_test
- .word trident_md, trident_test
- .word tseng_md, tseng_test
- .word 0
-
-# Test routines and mode tables:
-
-# S3 - The test algorithm was taken from the SuperProbe package
-# for XFree86 1.2.1. Report bugs to Christoph.Niemann@linux.org
-s3_test:
- movw $0x0f35, %cx # we store some constants in cl/ch
- movw $0x03d4, %dx
- movb $0x38, %al
- call inidx
- movb %al, %bh # store current CRT-register 0x38
- movw $0x0038, %ax
- call outidx # disable writing to special regs
- movb %cl, %al # check whether we can write special reg 0x35
- call inidx
- movb %al, %bl # save the current value of CRT reg 0x35
- andb $0xf0, %al # clear bits 0-3
- movb %al, %ah
- movb %cl, %al # and write it to CRT reg 0x35
- call outidx
- call inidx # now read it back
- andb %ch, %al # clear the upper 4 bits
- jz s3_2 # the first test failed. But we have a
-
- movb %bl, %ah # second chance
- movb %cl, %al
- call outidx
- jmp s3_1 # do the other tests
-
-s3_2: movw %cx, %ax # load ah with 0xf and al with 0x35
- orb %bl, %ah # set the upper 4 bits of ah with the orig value
- call outidx # write ...
- call inidx # ... and reread
- andb %cl, %al # turn off the upper 4 bits
- pushw %ax
- movb %bl, %ah # restore old value in register 0x35
- movb %cl, %al
- call outidx
- popw %ax
- cmpb %ch, %al # setting lower 4 bits was successful => bad
- je no_s3 # writing is allowed => this is not an S3
-
-s3_1: movw $0x4838, %ax # allow writing to special regs by putting
- call outidx # magic number into CRT-register 0x38
- movb %cl, %al # check whether we can write special reg 0x35
- call inidx
- movb %al, %bl
- andb $0xf0, %al
- movb %al, %ah
- movb %cl, %al
- call outidx
- call inidx
- andb %ch, %al
- jnz no_s3 # no, we can't write => no S3
-
- movw %cx, %ax
- orb %bl, %ah
- call outidx
- call inidx
- andb %ch, %al
- pushw %ax
- movb %bl, %ah # restore old value in register 0x35
- movb %cl, %al
- call outidx
- popw %ax
- cmpb %ch, %al
- jne no_s31 # writing not possible => no S3
- movb $0x30, %al
- call inidx # now get the S3 id ...
- leaw idS3, %di
- movw $0x10, %cx
- repne
- scasb
- je no_s31
-
- movb %bh, %ah
- movb $0x38, %al
- jmp s3rest
-
-no_s3: movb $0x35, %al # restore CRT register 0x35
- movb %bl, %ah
- call outidx
-no_s31: xorw %bp, %bp # Detection failed
-s3rest: movb %bh, %ah
- movb $0x38, %al # restore old value of CRT register 0x38
- jmp outidx
-
-idS3: .byte 0x81, 0x82, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95
- .byte 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xb0
-
-s3_md: .byte 0x54, 0x2b, 0x84
- .byte 0x55, 0x19, 0x84
- .byte 0
- .ascii "S3"
- .byte 0
-
-# ATI cards.
-ati_test:
- leaw idati, %si
- movw $0x31, %di
- movw $0x09, %cx
- repe
- cmpsb
- je atiok
-
- xorw %bp, %bp
-atiok: ret
-
-idati: .ascii "761295520"
-
-ati_md: .byte 0x23, 0x19, 0x84
- .byte 0x33, 0x2c, 0x84
- .byte 0x22, 0x1e, 0x64
- .byte 0x21, 0x19, 0x64
- .byte 0x58, 0x21, 0x50
- .byte 0x5b, 0x1e, 0x50
- .byte 0
- .ascii "ATI"
- .byte 0
-
-# AHEAD
-ahead_test:
- movw $0x200f, %ax
- movw $0x3ce, %dx
- outw %ax, %dx
- incw %dx
- inb %dx, %al
- cmpb $0x20, %al
- je isahed
-
- cmpb $0x21, %al
- je isahed
-
- xorw %bp, %bp
-isahed: ret
-
-ahead_md:
- .byte 0x22, 0x2c, 0x84
- .byte 0x23, 0x19, 0x84
- .byte 0x24, 0x1c, 0x84
- .byte 0x2f, 0x32, 0xa0
- .byte 0x32, 0x22, 0x50
- .byte 0x34, 0x42, 0x50
- .byte 0
- .ascii "Ahead"
- .byte 0
-
-# Chips & Tech.
-chips_test:
- movw $0x3c3, %dx
- inb %dx, %al
- orb $0x10, %al
- outb %al, %dx
- movw $0x104, %dx
- inb %dx, %al
- movb %al, %bl
- movw $0x3c3, %dx
- inb %dx, %al
- andb $0xef, %al
- outb %al, %dx
- cmpb $0xa5, %bl
- je cantok
-
- xorw %bp, %bp
-cantok: ret
-
-chips_md:
- .byte 0x60, 0x19, 0x84
- .byte 0x61, 0x32, 0x84
- .byte 0
- .ascii "Chips & Technologies"
- .byte 0
-
-# Cirrus Logic 5X0
-cirrus1_test:
- movw $0x3d4, %dx
- movb $0x0c, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bl
- xorb %al, %al
- outb %al, %dx
- decw %dx
- movb $0x1f, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bh
- xorb %ah, %ah
- shlb $4, %al
- movw %ax, %cx
- movb %bh, %al
- shrb $4, %al
- addw %ax, %cx
- shlw $8, %cx
- addw $6, %cx
- movw %cx, %ax
- movw $0x3c4, %dx
- outw %ax, %dx
- incw %dx
- inb %dx, %al
- andb %al, %al
- jnz nocirr
-
- movb %bh, %al
- outb %al, %dx
- inb %dx, %al
- cmpb $0x01, %al
- je iscirr
-
-nocirr: xorw %bp, %bp
-iscirr: movw $0x3d4, %dx
- movb %bl, %al
- xorb %ah, %ah
- shlw $8, %ax
- addw $0x0c, %ax
- outw %ax, %dx
- ret
-
-cirrus1_md:
- .byte 0x1f, 0x19, 0x84
- .byte 0x20, 0x2c, 0x84
- .byte 0x22, 0x1e, 0x84
- .byte 0x31, 0x25, 0x64
- .byte 0
- .ascii "Cirrus Logic 5X0"
- .byte 0
-
-# Cirrus Logic 54XX
-cirrus5_test:
- movw $0x3c4, %dx
- movb $6, %al
- call inidx
- movb %al, %bl # BL=backup
- movw $6, %ax
- call tstidx
- cmpb $0x0f, %al
- jne c5fail
-
- movw $0x1206, %ax
- call tstidx
- cmpb $0x12, %al
- jne c5fail
-
- movb $0x1e, %al
- call inidx
- movb %al, %bh
- movb %bh, %ah
- andb $0xc0, %ah
- movb $0x1e, %al
- call tstidx
- andb $0x3f, %al
- jne c5xx
-
- movb $0x1e, %al
- movb %bh, %ah
- orb $0x3f, %ah
- call tstidx
- xorb $0x3f, %al
- andb $0x3f, %al
-c5xx: pushf
- movb $0x1e, %al
- movb %bh, %ah
- outw %ax, %dx
- popf
- je c5done
-
-c5fail: xorw %bp, %bp
-c5done: movb $6, %al
- movb %bl, %ah
- outw %ax, %dx
- ret
-
-cirrus5_md:
- .byte 0x14, 0x19, 0x84
- .byte 0x54, 0x2b, 0x84
- .byte 0
- .ascii "Cirrus Logic 54XX"
- .byte 0
-
-# Cirrus Logic 64XX -- no known extra modes, but must be identified, because
-# it's misidentified by the Ahead test.
-cirrus6_test:
- movw $0x3ce, %dx
- movb $0x0a, %al
- call inidx
- movb %al, %bl # BL=backup
- movw $0xce0a, %ax
- call tstidx
- orb %al, %al
- jne c2fail
-
- movw $0xec0a, %ax
- call tstidx
- cmpb $0x01, %al
- jne c2fail
-
- movb $0xaa, %al
- call inidx # 4X, 5X, 7X and 8X are valid 64XX chip ID's.
- shrb $4, %al
- subb $4, %al
- jz c6done
-
- decb %al
- jz c6done
-
- subb $2, %al
- jz c6done
-
- decb %al
- jz c6done
-
-c2fail: xorw %bp, %bp
-c6done: movb $0x0a, %al
- movb %bl, %ah
- outw %ax, %dx
- ret
-
-cirrus6_md:
- .byte 0
- .ascii "Cirrus Logic 64XX"
- .byte 0
-
-# Everex / Trident
-everex_test:
- movw $0x7000, %ax
- xorw %bx, %bx
- int $0x10
- cmpb $0x70, %al
- jne noevrx
-
- shrw $4, %dx
- cmpw $0x678, %dx
- je evtrid
-
- cmpw $0x236, %dx
- jne evrxok
-
-evtrid: leaw trident_md, %bp
-evrxok: ret
-
-noevrx: xorw %bp, %bp
- ret
-
-everex_md:
- .byte 0x03, 0x22, 0x50
- .byte 0x04, 0x3c, 0x50
- .byte 0x07, 0x2b, 0x64
- .byte 0x08, 0x4b, 0x64
- .byte 0x0a, 0x19, 0x84
- .byte 0x0b, 0x2c, 0x84
- .byte 0x16, 0x1e, 0x50
- .byte 0x18, 0x1b, 0x64
- .byte 0x21, 0x40, 0xa0
- .byte 0x40, 0x1e, 0x84
- .byte 0
- .ascii "Everex/Trident"
- .byte 0
-
-# Genoa.
-genoa_test:
- leaw idgenoa, %si # Check Genoa 'clues'
- xorw %ax, %ax
- movb %es:(0x37), %al
- movw %ax, %di
- movw $0x04, %cx
- decw %si
- decw %di
-l1: incw %si
- incw %di
- movb (%si), %al
- testb %al, %al
- jz l2
-
- cmpb %es:(%di), %al
-l2: loope l1
- orw %cx, %cx
- je isgen
-
- xorw %bp, %bp
-isgen: ret
-
-idgenoa: .byte 0x77, 0x00, 0x99, 0x66
-
-genoa_md:
- .byte 0x58, 0x20, 0x50
- .byte 0x5a, 0x2a, 0x64
- .byte 0x60, 0x19, 0x84
- .byte 0x61, 0x1d, 0x84
- .byte 0x62, 0x20, 0x84
- .byte 0x63, 0x2c, 0x84
- .byte 0x64, 0x3c, 0x84
- .byte 0x6b, 0x4f, 0x64
- .byte 0x72, 0x3c, 0x50
- .byte 0x74, 0x42, 0x50
- .byte 0x78, 0x4b, 0x64
- .byte 0
- .ascii "Genoa"
- .byte 0
-
-# OAK
-oak_test:
- leaw idoakvga, %si
- movw $0x08, %di
- movw $0x08, %cx
- repe
- cmpsb
- je isoak
-
- xorw %bp, %bp
-isoak: ret
-
-idoakvga: .ascii "OAK VGA "
-
-oak_md: .byte 0x4e, 0x3c, 0x50
- .byte 0x4f, 0x3c, 0x84
- .byte 0x50, 0x19, 0x84
- .byte 0x51, 0x2b, 0x84
- .byte 0
- .ascii "OAK"
- .byte 0
-
-# WD Paradise.
-paradise_test:
- leaw idparadise, %si
- movw $0x7d, %di
- movw $0x04, %cx
- repe
- cmpsb
- je ispara
-
- xorw %bp, %bp
-ispara: ret
-
-idparadise: .ascii "VGA="
-
-paradise_md:
- .byte 0x41, 0x22, 0x50
- .byte 0x47, 0x1c, 0x84
- .byte 0x55, 0x19, 0x84
- .byte 0x54, 0x2c, 0x84
- .byte 0
- .ascii "Paradise"
- .byte 0
-
-# Trident.
-trident_test:
- movw $0x3c4, %dx
- movb $0x0e, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- xchgb %al, %ah
- xorb %al, %al
- outb %al, %dx
- inb %dx, %al
- xchgb %ah, %al
- movb %al, %bl # Strange thing ... in the book this wasn't
- andb $0x02, %bl # necessary but it worked on my card which
- jz setb2 # is a trident. Without it the screen goes
- # blurred ...
- andb $0xfd, %al
- jmp clrb2
-
-setb2: orb $0x02, %al
-clrb2: outb %al, %dx
- andb $0x0f, %ah
- cmpb $0x02, %ah
- je istrid
-
- xorw %bp, %bp
-istrid: ret
-
-trident_md:
- .byte 0x50, 0x1e, 0x50
- .byte 0x51, 0x2b, 0x50
- .byte 0x52, 0x3c, 0x50
- .byte 0x57, 0x19, 0x84
- .byte 0x58, 0x1e, 0x84
- .byte 0x59, 0x2b, 0x84
- .byte 0x5a, 0x3c, 0x84
- .byte 0
- .ascii "Trident"
- .byte 0
-
-# Tseng.
-tseng_test:
- movw $0x3cd, %dx
- inb %dx, %al # Could things be this simple ! :-)
- movb %al, %bl
- movb $0x55, %al
- outb %al, %dx
- inb %dx, %al
- movb %al, %ah
- movb %bl, %al
- outb %al, %dx
- cmpb $0x55, %ah
- je istsen
-
-isnot: xorw %bp, %bp
-istsen: ret
-
-tseng_md:
- .byte 0x26, 0x3c, 0x50
- .byte 0x2a, 0x28, 0x64
- .byte 0x23, 0x19, 0x84
- .byte 0x24, 0x1c, 0x84
- .byte 0x22, 0x2c, 0x84
- .byte 0x21, 0x3c, 0x84
- .byte 0
- .ascii "Tseng"
- .byte 0
-
-# Video7.
-video7_test:
- movw $0x3cc, %dx
- inb %dx, %al
- movw $0x3b4, %dx
- andb $0x01, %al
- jz even7
-
- movw $0x3d4, %dx
-even7: movb $0x0c, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bl
- movb $0x55, %al
- outb %al, %dx
- inb %dx, %al
- decw %dx
- movb $0x1f, %al
- outb %al, %dx
- incw %dx
- inb %dx, %al
- movb %al, %bh
- decw %dx
- movb $0x0c, %al
- outb %al, %dx
- incw %dx
- movb %bl, %al
- outb %al, %dx
- movb $0x55, %al
- xorb $0xea, %al
- cmpb %bh, %al
- jne isnot
-
- movb $VIDEO_FIRST_V7>>8, svga_prefix # Use special mode switching
- ret
-
-video7_md:
- .byte 0x40, 0x2b, 0x50
- .byte 0x43, 0x3c, 0x50
- .byte 0x44, 0x3c, 0x64
- .byte 0x41, 0x19, 0x84
- .byte 0x42, 0x2c, 0x84
- .byte 0x45, 0x1c, 0x84
- .byte 0
- .ascii "Video 7"
- .byte 0
-
-# Realtek VGA
-realtek_test:
- leaw idrtvga, %si
- movw $0x45, %di
- movw $0x0b, %cx
- repe
- cmpsb
- je isrt
-
- xorw %bp, %bp
-isrt: ret
-
-idrtvga: .ascii "REALTEK VGA"
-
-realtek_md:
- .byte 0x1a, 0x3c, 0x50
- .byte 0x1b, 0x19, 0x84
- .byte 0x1c, 0x1e, 0x84
- .byte 0x1d, 0x2b, 0x84
- .byte 0x1e, 0x3c, 0x84
- .byte 0
- .ascii "REALTEK"
- .byte 0
-
-#endif /* CONFIG_VIDEO_SVGA */
-
-# User-defined local mode table (VGA only)
-#ifdef CONFIG_VIDEO_LOCAL
-local_modes:
- leaw local_mode_table, %si
-locm1: lodsw
- orw %ax, %ax
- jz locm2
-
- stosw
- movsw
- jmp locm1
-
-locm2: ret
-
-# This is the table of local video modes which can be supplied manually
-# by the user. Each entry consists of mode ID (word) and dimensions
-# (byte for column count and another byte for row count). These modes
-# are placed before all SVGA and VESA modes and override them if table
-# compacting is enabled. The table must end with a zero word followed
-# by NUL-terminated video adapter name.
-local_mode_table:
- .word 0x0100 # Example: 40x25
- .byte 25,40
- .word 0
- .ascii "Local"
- .byte 0
-#endif /* CONFIG_VIDEO_LOCAL */
-
-# Read a key and return the ASCII code in al, scan code in ah
-getkey: xorb %ah, %ah
- int $0x16
- ret
-
-# Read a key with a timeout of 30 seconds.
-# The hardware clock is used to get the time.
-getkt: call gettime
- addb $30, %al # Wait 30 seconds
- cmpb $60, %al
- jl lminute
-
- subb $60, %al
-lminute:
- movb %al, %cl
-again: movb $0x01, %ah
- int $0x16
- jnz getkey # key pressed, so get it
-
- call gettime
- cmpb %cl, %al
- jne again
-
- movb $0x20, %al # timeout, return `space'
- ret
-
-# Flush the keyboard buffer
-flush: movb $0x01, %ah
- int $0x16
- jz empty
-
- xorb %ah, %ah
- int $0x16
- jmp flush
-
-empty: ret
-
-# Print hexadecimal number.
-prthw: pushw %ax
- movb %ah, %al
- call prthb
- popw %ax
-prthb: pushw %ax
- shrb $4, %al
- call prthn
- popw %ax
- andb $0x0f, %al
-prthn: cmpb $0x0a, %al
- jc prth1
-
- addb $0x07, %al
-prth1: addb $0x30, %al
- jmp prtchr
-
-# Print decimal number in al
-prtdec: pushw %ax
- pushw %cx
- xorb %ah, %ah
- movb $0x0a, %cl
- idivb %cl
- cmpb $0x09, %al
- jbe lt100
-
- call prtdec
- jmp skip10
-
-lt100: addb $0x30, %al
- call prtchr
-skip10: movb %ah, %al
- addb $0x30, %al
- call prtchr
- popw %cx
- popw %ax
- ret
-
-store_edid:
-#ifdef CONFIG_FIRMWARE_EDID
- pushw %es # just save all registers
- pushw %ax
- pushw %bx
- pushw %cx
- pushw %dx
- pushw %di
-
- pushw %fs
- popw %es
-
- movl $0x13131313, %eax # memset block with 0x13
- movw $32, %cx
- movw $0x140, %di
- cld
- rep
- stosl
-
- cmpw $0x0200, vbe_version # only do EDID on >= VBE2.0
- jl no_edid
-
- pushw %es # save ES
- xorw %di, %di # Report Capability
- pushw %di
- popw %es # ES:DI must be 0:0
- movw $0x4f15, %ax
- xorw %bx, %bx
- xorw %cx, %cx
- int $0x10
- popw %es # restore ES
-
- cmpb $0x00, %ah # call successful
- jne no_edid
-
- cmpb $0x4f, %al # function supported
- jne no_edid
-
- movw $0x4f15, %ax # do VBE/DDC
- movw $0x01, %bx
- movw $0x00, %cx
- movw $0x00, %dx
- movw $0x140, %di
- int $0x10
-
-no_edid:
- popw %di # restore all registers
- popw %dx
- popw %cx
- popw %bx
- popw %ax
- popw %es
-#endif
- ret
-
-# VIDEO_SELECT-only variables
-mt_end: .word 0 # End of video mode table if built
-edit_buf: .space 6 # Line editor buffer
-card_name: .word 0 # Pointer to adapter name
-scanning: .byte 0 # Performing mode scan
-do_restore: .byte 0 # Screen contents altered during mode change
-svga_prefix: .byte VIDEO_FIRST_BIOS>>8 # Default prefix for BIOS modes
-graphic_mode: .byte 0 # Graphic mode with a linear frame buffer
-dac_size: .byte 6 # DAC bit depth
-vbe_version: .word 0 # VBE bios version
-
-# Status messages
-keymsg: .ascii "Press <RETURN> to see video modes available, "
- .ascii "<SPACE> to continue or wait 30 secs"
- .byte 0x0d, 0x0a, 0
-
-listhdr: .byte 0x0d, 0x0a
- .ascii "Mode: COLSxROWS:"
-
-crlft: .byte 0x0d, 0x0a, 0
-
-prompt: .byte 0x0d, 0x0a
- .asciz "Enter mode number or `scan': "
-
-unknt: .asciz "Unknown mode ID. Try again."
-
-badmdt: .ascii "You passed an undefined mode number."
- .byte 0x0d, 0x0a, 0
-
-vesaer: .ascii "Error: Scanning of VESA modes failed. Please "
- .ascii "report to <mj@ucw.cz>."
- .byte 0x0d, 0x0a, 0
-
-old_name: .asciz "CGA/MDA/HGA"
-
-ega_name: .asciz "EGA"
-
-svga_name: .ascii " "
-
-vga_name: .asciz "VGA"
-
-vesa_name: .asciz "VESA"
-
-name_bann: .asciz "Video adapter: "
-#endif /* CONFIG_VIDEO_SELECT */
-
-# Other variables:
-adapter: .byte 0 # Video adapter: 0=CGA/MDA/HGA,1=EGA,2=VGA
-video_segment: .word 0xb800 # Video memory segment
-force_size: .word 0 # Use this size instead of the one in BIOS vars
diff --git a/arch/i386/boot/video.c b/arch/i386/boot/video.c
new file mode 100644
index 000000000000..958130ef0042
--- /dev/null
+++ b/arch/i386/boot/video.c
@@ -0,0 +1,461 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video.c
+ *
+ * Select video mode
+ */
+
+#include "boot.h"
+#include "video.h"
+#include "vesa.h"
+
+/*
+ * Mode list variables
+ */
+static struct card_info cards[]; /* List of cards to probe for */
+
+/*
+ * Common variables
+ */
+int adapter; /* 0=CGA/MDA/HGC, 1=EGA, 2=VGA+ */
+u16 video_segment;
+int force_x, force_y; /* Don't query the BIOS for cols/rows */
+
+int do_restore = 0; /* Screen contents changed during mode flip */
+int graphic_mode; /* Graphic mode with linear frame buffer */
+
+static void store_cursor_position(void)
+{
+ u16 curpos;
+ u16 ax, bx;
+
+ ax = 0x0300;
+ bx = 0;
+ asm(INT10
+ : "=d" (curpos), "+a" (ax), "+b" (bx)
+ : : "ecx", "esi", "edi");
+
+ boot_params.screen_info.orig_x = curpos;
+ boot_params.screen_info.orig_y = curpos >> 8;
+}
+
+static void store_video_mode(void)
+{
+ u16 ax, page;
+
+ /* N.B.: the saving of the video page here is a bit silly,
+ since we pretty much assume page 0 everywhere. */
+ ax = 0x0f00;
+ asm(INT10
+ : "+a" (ax), "=b" (page)
+ : : "ecx", "edx", "esi", "edi");
+
+ /* Not all BIOSes are clean with respect to the top bit */
+ boot_params.screen_info.orig_video_mode = ax & 0x7f;
+ boot_params.screen_info.orig_video_page = page;
+}
+
+/*
+ * Store the video mode parameters for later usage by the kernel.
+ * This is done by asking the BIOS except for the rows/columns
+ * parameters in the default 80x25 mode -- these are set directly,
+ * because some very obscure BIOSes supply insane values.
+ */
+static void store_mode_params(void)
+{
+ u16 font_size;
+ int x, y;
+
+ /* For graphics mode, it is up to the mode-setting driver
+ (currently only video-vesa.c) to store the parameters */
+ if (graphic_mode)
+ return;
+
+ store_cursor_position();
+ store_video_mode();
+
+ if (boot_params.screen_info.orig_video_mode == 0x07) {
+ /* MDA, HGC, or VGA in monochrome mode */
+ video_segment = 0xb000;
+ } else {
+ /* CGA, EGA, VGA and so forth */
+ video_segment = 0xb800;
+ }
+
+ set_fs(0);
+ font_size = rdfs16(0x485); /* Font size, BIOS area */
+ boot_params.screen_info.orig_video_points = font_size;
+
+ x = rdfs16(0x44a);
+ y = (adapter == ADAPTER_CGA) ? 25 : rdfs8(0x484)+1;
+
+ if (force_x)
+ x = force_x;
+ if (force_y)
+ y = force_y;
+
+ boot_params.screen_info.orig_video_cols = x;
+ boot_params.screen_info.orig_video_lines = y;
+}
+
+/* Probe the video drivers and have them generate their mode lists. */
+static void probe_cards(int unsafe)
+{
+ struct card_info *card;
+ static u8 probed[2];
+
+ if (probed[unsafe])
+ return;
+
+ probed[unsafe] = 1;
+
+ for (card = video_cards; card < video_cards_end; card++) {
+ if (card->unsafe == unsafe) {
+ if (card->probe)
+ card->nmodes = card->probe();
+ else
+ card->nmodes = 0;
+ }
+ }
+}
+
+/* Test if a mode is defined */
+int mode_defined(u16 mode)
+{
+ struct card_info *card;
+ struct mode_info *mi;
+ int i;
+
+ for (card = video_cards; card < video_cards_end; card++) {
+ mi = card->modes;
+ for (i = 0; i < card->nmodes; i++, mi++) {
+ if (mi->mode == mode)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Set mode (without recalc) */
+static int raw_set_mode(u16 mode)
+{
+ int nmode, i;
+ struct card_info *card;
+ struct mode_info *mi;
+
+ /* Drop the recalc bit if set */
+ mode &= ~VIDEO_RECALC;
+
+ /* Scan for mode based on fixed ID, position, or resolution */
+ nmode = 0;
+ for (card = video_cards; card < video_cards_end; card++) {
+ mi = card->modes;
+ for (i = 0; i < card->nmodes; i++, mi++) {
+ int visible = mi->x || mi->y;
+
+ if ((mode == nmode && visible) ||
+ mode == mi->mode ||
+ mode == (mi->y << 8)+mi->x)
+ return card->set_mode(mi);
+
+ if (visible)
+ nmode++;
+ }
+ }
+
+ /* Nothing found? Is it an "exceptional" (unprobed) mode? */
+ for (card = video_cards; card < video_cards_end; card++) {
+ if (mode >= card->xmode_first &&
+ mode < card->xmode_first+card->xmode_n) {
+ struct mode_info mix;
+ mix.mode = mode;
+ mix.x = mix.y = 0;
+ return card->set_mode(&mix);
+ }
+ }
+
+ /* Otherwise, failure... */
+ return -1;
+}
+
+/*
+ * Recalculate the vertical video cutoff (hack!)
+ */
+static void vga_recalc_vertical(void)
+{
+ unsigned int font_size, rows;
+ u16 crtc;
+ u8 pt, ov;
+
+ set_fs(0);
+ font_size = rdfs8(0x485); /* BIOS: font size (pixels) */
+ rows = force_y ? force_y : rdfs8(0x484)+1; /* Text rows */
+
+ rows *= font_size; /* Visible scan lines */
+ rows--; /* ... minus one */
+
+ crtc = vga_crtc();
+
+ pt = in_idx(crtc, 0x11);
+ pt &= ~0x80; /* Unlock CR0-7 */
+ out_idx(pt, crtc, 0x11);
+
+ out_idx((u8)rows, crtc, 0x12); /* Lower height register */
+
+ ov = in_idx(crtc, 0x07); /* Overflow register */
+ ov &= 0xbd;
+ ov |= (rows >> (8-1)) & 0x02;
+ ov |= (rows >> (9-6)) & 0x40;
+ out_idx(ov, crtc, 0x07);
+}
+
+/* Set mode (with recalc if specified) */
+static int set_mode(u16 mode)
+{
+ int rv;
+
+ /* Very special mode numbers... */
+ if (mode == VIDEO_CURRENT_MODE)
+ return 0; /* Nothing to do... */
+ else if (mode == NORMAL_VGA)
+ mode = VIDEO_80x25;
+ else if (mode == EXTENDED_VGA)
+ mode = VIDEO_8POINT;
+
+ rv = raw_set_mode(mode);
+ if (rv)
+ return rv;
+
+ if (mode & VIDEO_RECALC)
+ vga_recalc_vertical();
+
+ return 0;
+}
+
+static unsigned int get_entry(void)
+{
+ char entry_buf[4];
+ int i, len = 0;
+ int key;
+ unsigned int v;
+
+ do {
+ key = getchar();
+
+ if (key == '\b') {
+ if (len > 0) {
+ puts("\b \b");
+ len--;
+ }
+ } else if ((key >= '0' && key <= '9') ||
+ (key >= 'A' && key <= 'Z') ||
+ (key >= 'a' && key <= 'z')) {
+ if (len < sizeof entry_buf) {
+ entry_buf[len++] = key;
+ putchar(key);
+ }
+ }
+ } while (key != '\r');
+ putchar('\n');
+
+ if (len == 0)
+ return VIDEO_CURRENT_MODE; /* Default */
+
+ v = 0;
+ for (i = 0; i < len; i++) {
+ v <<= 4;
+ key = entry_buf[i] | 0x20;
+ v += (key > '9') ? key-'a'+10 : key-'0';
+ }
+
+ return v;
+}
+
+static void display_menu(void)
+{
+ struct card_info *card;
+ struct mode_info *mi;
+ char ch;
+ int i;
+
+ puts("Mode: COLSxROWS:\n");
+
+ ch = '0';
+ for (card = video_cards; card < video_cards_end; card++) {
+ mi = card->modes;
+ for (i = 0; i < card->nmodes; i++, mi++) {
+ int visible = mi->x && mi->y;
+ u16 mode_id = mi->mode ? mi->mode :
+ (mi->y << 8)+mi->x;
+
+ if (!visible)
+ continue; /* Hidden mode */
+
+ printf("%c %04X %3dx%-3d %s\n",
+ ch, mode_id, mi->x, mi->y, card->card_name);
+
+ if (ch == '9')
+ ch = 'a';
+ else if (ch == 'z' || ch == ' ')
+ ch = ' '; /* Out of keys... */
+ else
+ ch++;
+ }
+ }
+}
+
+#define H(x) ((x)-'a'+10)
+#define SCAN ((H('s')<<12)+(H('c')<<8)+(H('a')<<4)+H('n'))
+
+static unsigned int mode_menu(void)
+{
+ int key;
+ unsigned int sel;
+
+ puts("Press <ENTER> to see video modes available, "
+ "<SPACE> to continue, or wait 30 sec\n");
+
+ kbd_flush();
+ while (1) {
+ key = getchar_timeout();
+ if (key == ' ' || key == 0)
+ return VIDEO_CURRENT_MODE; /* Default */
+ if (key == '\r')
+ break;
+ putchar('\a'); /* Beep! */
+ }
+
+
+ for (;;) {
+ display_menu();
+
+ puts("Enter a video mode or \"scan\" to scan for "
+ "additional modes: ");
+ sel = get_entry();
+ if (sel != SCAN)
+ return sel;
+
+ probe_cards(1);
+ }
+}
+
+#ifdef CONFIG_VIDEO_RETAIN
+/* Save screen content to the heap */
+struct saved_screen {
+ int x, y;
+ int curx, cury;
+ u16 *data;
+} saved;
+
+static void save_screen(void)
+{
+ /* Should be called after store_mode_params() */
+ saved.x = boot_params.screen_info.orig_video_cols;
+ saved.y = boot_params.screen_info.orig_video_lines;
+ saved.curx = boot_params.screen_info.orig_x;
+ saved.cury = boot_params.screen_info.orig_y;
+
+ if (heap_free() < saved.x*saved.y*sizeof(u16)+512)
+ return; /* Not enough heap to save the screen */
+
+ saved.data = GET_HEAP(u16, saved.x*saved.y);
+
+ set_fs(video_segment);
+ copy_from_fs(saved.data, 0, saved.x*saved.y*sizeof(u16));
+}
+
+static void restore_screen(void)
+{
+ /* Should be called after store_mode_params() */
+ int xs = boot_params.screen_info.orig_video_cols;
+ int ys = boot_params.screen_info.orig_video_lines;
+ int y;
+ addr_t dst = 0;
+ u16 *src = saved.data;
+ u16 ax, bx, dx;
+
+ if (graphic_mode)
+ return; /* Can't restore onto a graphic mode */
+
+ if (!src)
+ return; /* No saved screen contents */
+
+ /* Restore screen contents */
+
+ set_fs(video_segment);
+ for (y = 0; y < ys; y++) {
+ int npad;
+
+ if (y < saved.y) {
+ int copy = (xs < saved.x) ? xs : saved.x;
+ copy_to_fs(dst, src, copy*sizeof(u16));
+ dst += copy*sizeof(u16);
+ src += saved.x;
+ npad = (xs < saved.x) ? 0 : xs-saved.x;
+ } else {
+ npad = xs;
+ }
+
+ /* Writes "npad" blank characters to
+ video_segment:dst and advances dst */
+ asm volatile("pushw %%es ; "
+ "movw %2,%%es ; "
+ "shrw %%cx ; "
+ "jnc 1f ; "
+ "stosw \n\t"
+ "1: rep;stosl ; "
+ "popw %%es"
+ : "+D" (dst), "+c" (npad)
+ : "bdS" (video_segment),
+ "a" (0x07200720));
+ }
+
+ /* Restore cursor position */
+ ax = 0x0200; /* Set cursor position */
+ bx = 0; /* Page number (<< 8) */
+ dx = (saved.cury << 8)+saved.curx;
+ asm volatile(INT10
+ : "+a" (ax), "+b" (bx), "+d" (dx)
+ : : "ecx", "esi", "edi");
+}
+#else
+#define save_screen() ((void)0)
+#define restore_screen() ((void)0)
+#endif
+
+void set_video(void)
+{
+ u16 mode = boot_params.hdr.vid_mode;
+
+ RESET_HEAP();
+
+ store_mode_params();
+ save_screen();
+ probe_cards(0);
+
+ for (;;) {
+ if (mode == ASK_VGA)
+ mode = mode_menu();
+
+ if (!set_mode(mode))
+ break;
+
+ printf("Undefined video mode number: %x\n", mode);
+ mode = ASK_VGA;
+ }
+ vesa_store_edid();
+ store_mode_params();
+
+ if (do_restore)
+ restore_screen();
+}
diff --git a/arch/i386/boot/video.h b/arch/i386/boot/video.h
new file mode 100644
index 000000000000..b92447d51213
--- /dev/null
+++ b/arch/i386/boot/video.h
@@ -0,0 +1,152 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/video.h
+ *
+ * Header file for the real-mode video probing code
+ */
+
+#ifndef BOOT_VIDEO_H
+#define BOOT_VIDEO_H
+
+#include <linux/types.h>
+
+/* Enable autodetection of SVGA adapters and modes. */
+#undef CONFIG_VIDEO_SVGA
+
+/* Enable autodetection of VESA modes */
+#define CONFIG_VIDEO_VESA
+
+/* Retain screen contents when switching modes */
+#define CONFIG_VIDEO_RETAIN
+
+/* Force 400 scan lines for standard modes (hack to fix bad BIOS behaviour */
+#undef CONFIG_VIDEO_400_HACK
+
+/* This code uses an extended set of video mode numbers. These include:
+ * Aliases for standard modes
+ * NORMAL_VGA (-1)
+ * EXTENDED_VGA (-2)
+ * ASK_VGA (-3)
+ * Video modes numbered by menu position -- NOT RECOMMENDED because of lack
+ * of compatibility when extending the table. These are between 0x00 and 0xff.
+ */
+#define VIDEO_FIRST_MENU 0x0000
+
+/* Standard BIOS video modes (BIOS number + 0x0100) */
+#define VIDEO_FIRST_BIOS 0x0100
+
+/* VESA BIOS video modes (VESA number + 0x0200) */
+#define VIDEO_FIRST_VESA 0x0200
+
+/* Video7 special modes (BIOS number + 0x0900) */
+#define VIDEO_FIRST_V7 0x0900
+
+/* Special video modes */
+#define VIDEO_FIRST_SPECIAL 0x0f00
+#define VIDEO_80x25 0x0f00
+#define VIDEO_8POINT 0x0f01
+#define VIDEO_80x43 0x0f02
+#define VIDEO_80x28 0x0f03
+#define VIDEO_CURRENT_MODE 0x0f04
+#define VIDEO_80x30 0x0f05
+#define VIDEO_80x34 0x0f06
+#define VIDEO_80x60 0x0f07
+#define VIDEO_GFX_HACK 0x0f08
+#define VIDEO_LAST_SPECIAL 0x0f09
+
+/* Video modes given by resolution */
+#define VIDEO_FIRST_RESOLUTION 0x1000
+
+/* The "recalculate timings" flag */
+#define VIDEO_RECALC 0x8000
+
+/* Define DO_STORE according to CONFIG_VIDEO_RETAIN */
+#ifdef CONFIG_VIDEO_RETAIN
+void store_screen(void);
+#define DO_STORE() store_screen()
+#else
+#define DO_STORE() ((void)0)
+#endif /* CONFIG_VIDEO_RETAIN */
+
+/*
+ * Mode table structures
+ */
+
+struct mode_info {
+ u16 mode; /* Mode number (vga= style) */
+ u8 x, y; /* Width, height */
+};
+
+struct card_info {
+ const char *card_name;
+ int (*set_mode)(struct mode_info *mode);
+ int (*probe)(void);
+ struct mode_info *modes;
+ int nmodes; /* Number of probed modes so far */
+ int unsafe; /* Probing is unsafe, only do after "scan" */
+ u16 xmode_first; /* Unprobed modes to try to call anyway */
+ u16 xmode_n; /* Size of unprobed mode range */
+};
+
+#define __videocard struct card_info __attribute__((section(".videocards")))
+extern struct card_info video_cards[], video_cards_end[];
+
+int mode_defined(u16 mode); /* video.c */
+
+/* Basic video information */
+#define ADAPTER_CGA 0 /* CGA/MDA/HGC */
+#define ADAPTER_EGA 1
+#define ADAPTER_VGA 2
+
+extern int adapter;
+extern u16 video_segment;
+extern int force_x, force_y; /* Don't query the BIOS for cols/rows */
+extern int do_restore; /* Restore screen contents */
+extern int graphic_mode; /* Graphics mode with linear frame buffer */
+
+/*
+ * int $0x10 is notorious for touching registers it shouldn't.
+ * gcc doesn't like %ebp being clobbered, so define it as a push/pop
+ * sequence here.
+ *
+ * A number of systems, including the original PC can clobber %bp in
+ * certain circumstances, like when scrolling. There exists at least
+ * one Trident video card which could clobber DS under a set of
+ * circumstances that we are unlikely to encounter (scrolling when
+ * using an extended graphics mode of more than 800x600 pixels), but
+ * it's cheap insurance to deal with that here.
+ */
+#define INT10 "pushl %%ebp; pushw %%ds; int $0x10; popw %%ds; popl %%ebp"
+
+/* Accessing VGA indexed registers */
+static inline u8 in_idx(u16 port, u8 index)
+{
+ outb(index, port);
+ return inb(port+1);
+}
+
+static inline void out_idx(u8 v, u16 port, u8 index)
+{
+ outw(index+(v << 8), port);
+}
+
+/* Writes a value to an indexed port and then reads the port again */
+static inline u8 tst_idx(u8 v, u16 port, u8 index)
+{
+ out_idx(port, index, v);
+ return in_idx(port, index);
+}
+
+/* Get the I/O port of the VGA CRTC */
+u16 vga_crtc(void); /* video-vga.c */
+
+#endif /* BOOT_VIDEO_H */
diff --git a/arch/i386/boot/voyager.c b/arch/i386/boot/voyager.c
new file mode 100644
index 000000000000..61c8fe0453be
--- /dev/null
+++ b/arch/i386/boot/voyager.c
@@ -0,0 +1,46 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2007 rPath, Inc. - All Rights Reserved
+ *
+ * This file is part of the Linux kernel, and is made available under
+ * the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * arch/i386/boot/voyager.c
+ *
+ * Get the Voyager config information
+ */
+
+#include "boot.h"
+
+#ifdef CONFIG_X86_VOYAGER
+
+int query_voyager(void)
+{
+ u8 err;
+ u16 es, di;
+ /* Abuse the apm_bios_info area for this */
+ u8 *data_ptr = (u8 *)&boot_params.apm_bios_info;
+
+ data_ptr[0] = 0xff; /* Flag on config not found(?) */
+
+ asm("pushw %%es ; "
+ "int $0x15 ; "
+ "setc %0 ; "
+ "movw %%es, %1 ; "
+ "popw %%es"
+ : "=q" (err), "=r" (es), "=D" (di)
+ : "a" (0xffc0));
+
+ if (err)
+ return -1; /* Not Voyager */
+
+ set_fs(es);
+ copy_from_fs(data_ptr, di, 7); /* Table is 7 bytes apparently */
+ return 0;
+}
+
+#endif /* CONFIG_X86_VOYAGER */
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 1a3a2217b7c2..54ee1764fdae 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc2
-# Mon May 21 13:23:44 2007
+# Linux kernel version: 2.6.22-git14
+# Fri Jul 20 09:53:15 2007
#
CONFIG_X86_32=y
CONFIG_GENERIC_TIME=y
@@ -37,19 +37,18 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=18
# CONFIG_CPUSETS is not set
CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
+CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -73,16 +72,13 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -90,14 +86,11 @@ CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -166,7 +159,6 @@ CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
-CONFIG_X86_CMPXCHG64=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_INTEL_USERCOPY=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
@@ -202,6 +194,7 @@ CONFIG_X86_CPUID=y
# CONFIG_EDD is not set
# CONFIG_DELL_RBU is not set
# CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
# CONFIG_NOHIGHMEM is not set
CONFIG_HIGHMEM4G=y
# CONFIG_HIGHMEM64G is not set
@@ -218,7 +211,9 @@ CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
# CONFIG_HIGHPTE is not set
# CONFIG_MATH_EMULATION is not set
CONFIG_MTRR=y
@@ -245,7 +240,6 @@ CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_PM=y
CONFIG_PM_LEGACY=y
# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
#
# ACPI (Advanced Configuration and Power Interface) Support
@@ -285,7 +279,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
#
# CPUFreq processor drivers
@@ -326,7 +320,7 @@ CONFIG_PCI_MMCONFIG=y
CONFIG_ARCH_SUPPORTS_MSI=y
CONFIG_PCI_MSI=y
# CONFIG_PCI_DEBUG is not set
-CONFIG_HT_IRQ=y
+# CONFIG_HT_IRQ is not set
CONFIG_ISA_DMA_API=y
# CONFIG_ISA is not set
# CONFIG_MCA is not set
@@ -382,7 +376,7 @@ CONFIG_IP_PNP_DHCP=y
CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -401,27 +395,15 @@ CONFIG_IPV6=y
# CONFIG_INET6_TUNNEL is not set
CONFIG_INET6_XFRM_MODE_TRANSPORT=y
CONFIG_INET6_XFRM_MODE_TUNNEL=y
-CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_BEET is not set
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
CONFIG_IPV6_SIT=y
# CONFIG_IPV6_TUNNEL is not set
# CONFIG_IPV6_MULTIPLE_TABLES 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
@@ -458,6 +440,7 @@ CONFIG_IPV6_SIT=y
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -472,21 +455,9 @@ CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
CONFIG_PNP=y
# CONFIG_PNP_DEBUG is not set
@@ -494,10 +465,7 @@ CONFIG_PNP=y
# Protocols
#
CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
@@ -515,17 +483,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
# CONFIG_IBM_ASM is not set
# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
# CONFIG_SONY_LAPTOP is not set
# CONFIG_THINKPAD_ACPI is not set
-# CONFIG_BLINK is not set
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y
@@ -597,6 +562,7 @@ CONFIG_BLK_DEV_IDEDMA=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
# CONFIG_SCSI_PROC_FS is not set
@@ -607,8 +573,9 @@ CONFIG_SCSI_NETLINK=y
CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
# CONFIG_CHR_DEV_SCH is not set
#
@@ -668,6 +635,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
# CONFIG_SCSI_QLA_ISCSI is not set
@@ -676,14 +644,73 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SRP is not set
-# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_ACPI=y
+CONFIG_SATA_AHCI=y
+CONFIG_SATA_SVW=y
+CONFIG_ATA_PIIX=y
+# CONFIG_SATA_MV is not set
+CONFIG_SATA_NV=y
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+CONFIG_SATA_VIA=y
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CS5535 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+# CONFIG_DM_SNAPSHOT is not set
+# CONFIG_DM_MIRROR is not set
+# CONFIG_DM_ZERO is not set
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
#
# Fusion MPT device support
@@ -724,42 +751,27 @@ CONFIG_IEEE1394_OHCI1394=y
# CONFIG_IEEE1394_ETH1394 is not set
# CONFIG_IEEE1394_DV1394 is not set
CONFIG_IEEE1394_RAWIO=y
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-# CONFIG_MACINTOSH_DRIVERS is not set
-
-#
-# Network device support
-#
+CONFIG_MACINTOSH_DRIVERS=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
CONFIG_NETDEVICES=y
+CONFIG_NETDEVICES_MULTIQUEUE=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=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_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
CONFIG_NET_TULIP=y
# CONFIG_DE2104X is not set
CONFIG_TULIP=y
@@ -810,7 +822,6 @@ CONFIG_R8169=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
CONFIG_SKY2=y
-# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=y
CONFIG_BNX2=y
@@ -824,10 +835,6 @@ CONFIG_NETDEV_10000=y
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_MLX4_CORE is not set
-
-#
-# Token Ring devices
-#
# CONFIG_TR is not set
#
@@ -856,15 +863,7 @@ CONFIG_NETCONSOLE=y
CONFIG_NETPOLL=y
# CONFIG_NETPOLL_TRAP is not set
CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -872,6 +871,7 @@ CONFIG_NET_POLL_CONTROLLER=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -937,6 +937,7 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_FIX_EARLYCON_MEM=y
CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_PNP=y
CONFIG_SERIAL_8250_NR_UARTS=4
@@ -952,10 +953,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=y
@@ -989,11 +986,7 @@ CONFIG_MAX_RAW_DEVS=256
CONFIG_HPET=y
# CONFIG_HPET_RTC_IRQ is not set
CONFIG_HPET_MMAP=y
-CONFIG_HANGCHECK_TIMER=y
-
-#
-# TPM devices
-#
+# CONFIG_HANGCHECK_TIMER is not set
# CONFIG_TCG_TPM is not set
# CONFIG_TELCLOCK is not set
CONFIG_DEVPORT=y
@@ -1004,11 +997,8 @@ CONFIG_DEVPORT=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
#
@@ -1042,7 +1032,7 @@ CONFIG_DAB=y
CONFIG_VGA_CONSOLE=y
CONFIG_VGACON_SOFT_SCROLLBACK=y
CONFIG_VGACON_SOFT_SCROLLBACK_SIZE=128
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_VIDEO_SELECT=y
CONFIG_DUMMY_CONSOLE=y
#
@@ -1059,15 +1049,11 @@ CONFIG_SOUND=y
# Open Sound System
#
CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE is not set
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
# CONFIG_SOUND_OSS is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
@@ -1078,10 +1064,7 @@ CONFIG_USB_HID=y
# CONFIG_USB_HIDINPUT_POWERBOOK is not set
# CONFIG_HID_FF is not set
# CONFIG_USB_HIDDEV is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1095,6 +1078,7 @@ CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
# CONFIG_USB_OTG is not set
#
@@ -1104,7 +1088,6 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1112,6 +1095,7 @@ CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
#
# USB Device Class drivers
@@ -1202,15 +1186,7 @@ CONFIG_USB_MON=y
#
# LED Triggers
#
-
-#
-# InfiniBand support
-#
# CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
# CONFIG_EDAC is not set
#
@@ -1230,11 +1206,13 @@ CONFIG_USB_MON=y
#
# DMA Devices
#
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
#
-# Virtualization
+# Userspace I/O
#
-# CONFIG_KVM is not set
+# CONFIG_UIO is not set
#
# File systems
@@ -1272,6 +1250,7 @@ CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
CONFIG_AUTOFS4_FS=y
# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
#
# CD-ROM/DVD Filesystems
@@ -1299,7 +1278,7 @@ CONFIG_PROC_KCORE=y
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
@@ -1349,7 +1328,6 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -1405,10 +1383,7 @@ CONFIG_NLS_UTF8=y
# Distributed Lock Manager
#
# CONFIG_DLM is not set
-
-#
-# Instrumentation Support
-#
+CONFIG_INSTRUMENTATION=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
CONFIG_KPROBES=y
@@ -1418,7 +1393,7 @@ CONFIG_KPROBES=y
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_UNUSED_SYMBOLS=y
# CONFIG_DEBUG_FS is not set
@@ -1426,15 +1401,17 @@ CONFIG_UNUSED_SYMBOLS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1444,7 +1421,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_FRAME_POINTER is not set
-# CONFIG_UNWIND_INFO is not set
# CONFIG_FORCED_INLINING is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_LKDTM is not set
@@ -1463,10 +1439,6 @@ CONFIG_DOUBLEFAULT=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
# CONFIG_CRYPTO is not set
#
@@ -1477,6 +1449,7 @@ CONFIG_BITREVERSE=y
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_PLIST=y
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 06da59f6f837..dbe5e87e0d66 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_VM86) += vm86.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_HPET_TIMER) += hpet.o
obj-$(CONFIG_K8_NB) += k8.o
+obj-$(CONFIG_MGEODE_LX) += geode.o
obj-$(CONFIG_VMI) += vmi.o vmiclock.o
obj-$(CONFIG_PARAVIRT) += paravirt.o
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index a574cd2c8b61..cacdd883bf2b 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -618,6 +618,8 @@ static int __init acpi_parse_sbf(struct acpi_table_header *table)
#ifdef CONFIG_HPET_TIMER
#include <asm/hpet.h>
+static struct __initdata resource *hpet_res;
+
static int __init acpi_parse_hpet(struct acpi_table_header *table)
{
struct acpi_table_hpet *hpet_tbl;
@@ -638,8 +640,42 @@ static int __init acpi_parse_hpet(struct acpi_table_header *table)
printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
hpet_tbl->id, hpet_address);
+ /*
+ * Allocate and initialize the HPET firmware resource for adding into
+ * the resource tree during the lateinit timeframe.
+ */
+#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",
+ hpet_tbl->sequence);
+
+ hpet_res->start = hpet_address;
+ hpet_res->end = hpet_address + (1 * 1024) - 1;
+
return 0;
}
+
+/*
+ * hpet_insert_resource inserts the HPET resources used into the resource
+ * tree.
+ */
+static __init int hpet_insert_resource(void)
+{
+ if (!hpet_res)
+ return 1;
+
+ return insert_resource(&iomem_resource, hpet_res);
+}
+
+late_initcall(hpet_insert_resource);
+
#else
#define acpi_parse_hpet NULL
#endif
@@ -950,14 +986,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
},
{
.callback = force_acpi_ht,
- .ident = "DELL GX240",
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
- DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
- },
- },
- {
- .callback = force_acpi_ht,
.ident = "HP VISUALIZE NT Workstation",
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c
index 4ee83577bf61..c42b5ab49deb 100644
--- a/arch/i386/kernel/acpi/sleep.c
+++ b/arch/i386/kernel/acpi/sleep.c
@@ -14,7 +14,7 @@
/* address in low memory of the wakeup routine. */
unsigned long acpi_wakeup_address = 0;
-unsigned long acpi_video_flags;
+unsigned long acpi_realmode_flags;
extern char wakeup_start, wakeup_end;
extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long));
@@ -68,9 +68,11 @@ static int __init acpi_sleep_setup(char *str)
{
while ((str != NULL) && (*str != '\0')) {
if (strncmp(str, "s3_bios", 7) == 0)
- acpi_video_flags = 1;
+ acpi_realmode_flags |= 1;
if (strncmp(str, "s3_mode", 7) == 0)
- acpi_video_flags |= 2;
+ acpi_realmode_flags |= 2;
+ if (strncmp(str, "s3_beep", 7) == 0)
+ acpi_realmode_flags |= 4;
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
@@ -80,9 +82,11 @@ static int __init acpi_sleep_setup(char *str)
__setup("acpi_sleep=", acpi_sleep_setup);
+/* Ouch, we want to delete this. We already have better version in userspace, in
+ s2ram from suspend.sf.net project */
static __init int reset_videomode_after_s3(struct dmi_system_id *d)
{
- acpi_video_flags |= 2;
+ acpi_realmode_flags |= 2;
return 0;
}
diff --git a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S
index a2295a34b2c7..ed0a0f2c1597 100644
--- a/arch/i386/kernel/acpi/wakeup.S
+++ b/arch/i386/kernel/acpi/wakeup.S
@@ -13,6 +13,21 @@
# cs = 0x1234, eip = 0x05
#
+#define BEEP \
+ inb $97, %al; \
+ outb %al, $0x80; \
+ movb $3, %al; \
+ outb %al, $97; \
+ outb %al, $0x80; \
+ movb $-74, %al; \
+ outb %al, $67; \
+ outb %al, $0x80; \
+ movb $-119, %al; \
+ outb %al, $66; \
+ outb %al, $0x80; \
+ movb $15, %al; \
+ outb %al, $66;
+
ALIGN
.align 4096
ENTRY(wakeup_start)
@@ -31,6 +46,11 @@ wakeup_code:
movw %cs, %ax
movw %ax, %ds # Make ds:0 point to wakeup_start
movw %ax, %ss
+
+ testl $4, realmode_flags - wakeup_code
+ jz 1f
+ BEEP
+1:
mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board
movw $0x0e00 + 'S', %fs:(0x12)
@@ -41,7 +61,7 @@ wakeup_code:
cmpl $0x12345678, %eax
jne bogus_real_magic
- testl $1, video_flags - wakeup_code
+ testl $1, realmode_flags - wakeup_code
jz 1f
lcall $0xc000,$3
movw %cs, %ax
@@ -49,7 +69,7 @@ wakeup_code:
movw %ax, %ss
1:
- testl $2, video_flags - wakeup_code
+ testl $2, realmode_flags - wakeup_code
jz 1f
mov video_mode - wakeup_code, %ax
call mode_set
@@ -88,7 +108,11 @@ wakeup_code:
cmpl $0x12345678, %eax
jne bogus_real_magic
- ljmpl $__KERNEL_CS,$wakeup_pmode_return
+ testl $8, realmode_flags - wakeup_code
+ jz 1f
+ BEEP
+1:
+ ljmpl $__KERNEL_CS, $wakeup_pmode_return
real_save_gdt: .word 0
.long 0
@@ -97,7 +121,8 @@ real_save_cr3: .long 0
real_save_cr4: .long 0
real_magic: .long 0
video_mode: .long 0
-video_flags: .long 0
+realmode_flags: .long 0
+beep_flags: .long 0
real_efer_save_restore: .long 0
real_save_efer_edx: .long 0
real_save_efer_eax: .long 0
@@ -260,8 +285,8 @@ ENTRY(acpi_copy_wakeup_routine)
movl saved_videomode, %edx
movl %edx, video_mode - wakeup_start (%eax)
- movl acpi_video_flags, %edx
- movl %edx, video_flags - wakeup_start (%eax)
+ movl acpi_realmode_flags, %edx
+ movl %edx, realmode_flags - wakeup_start (%eax)
movl $0x12345678, real_magic - wakeup_start (%eax)
movl $0x12345678, saved_magic
popl %ebx
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index d8cda14fff8b..c3750c2c4113 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -2,12 +2,17 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/kprobes.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
#include <asm/alternative.h>
#include <asm/sections.h>
+#include <asm/pgtable.h>
+#include <asm/mce.h>
+#include <asm/nmi.h>
-static int noreplace_smp = 0;
-static int smp_alt_once = 0;
-static int debug_alternative = 0;
+#ifdef CONFIG_HOTPLUG_CPU
+static int smp_alt_once;
static int __init bootonly(char *str)
{
@@ -15,6 +20,11 @@ static int __init bootonly(char *str)
return 1;
}
__setup("smp-alt-boot", bootonly);
+#else
+#define smp_alt_once 1
+#endif
+
+static int debug_alternative;
static int __init debug_alt(char *str)
{
@@ -23,6 +33,8 @@ static int __init debug_alt(char *str)
}
__setup("debug-alternative", debug_alt);
+static int noreplace_smp;
+
static int __init setup_noreplace_smp(char *str)
{
noreplace_smp = 1;
@@ -144,7 +156,7 @@ static void nop_out(void *insns, unsigned int len)
unsigned int noplen = len;
if (noplen > ASM_NOP_MAX)
noplen = ASM_NOP_MAX;
- memcpy(insns, noptable[noplen], noplen);
+ text_poke(insns, noptable[noplen], noplen);
insns += noplen;
len -= noplen;
}
@@ -196,7 +208,7 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end)
continue;
if (*ptr > text_end)
continue;
- **ptr = 0xf0; /* lock prefix */
+ text_poke(*ptr, ((unsigned char []){0xf0}), 1); /* add lock prefix */
};
}
@@ -354,10 +366,6 @@ void apply_paravirt(struct paravirt_patch_site *start,
/* Pad the rest with nops */
nop_out(p->instr + used, p->len - used);
}
-
- /* Sync to be conservative, in case we patched following
- * instructions */
- sync_core();
}
extern struct paravirt_patch_site __start_parainstructions[],
__stop_parainstructions[];
@@ -367,6 +375,14 @@ void __init alternative_instructions(void)
{
unsigned long flags;
+ /* The patching is not fully atomic, so try to avoid local interruptions
+ that might execute the to be patched code.
+ Other CPUs are not running. */
+ stop_nmi();
+#ifdef CONFIG_MCE
+ stop_mce();
+#endif
+
local_irq_save(flags);
apply_alternatives(__alt_instructions, __alt_instructions_end);
@@ -376,8 +392,6 @@ void __init alternative_instructions(void)
#ifdef CONFIG_HOTPLUG_CPU
if (num_possible_cpus() < 2)
smp_alt_once = 1;
-#else
- smp_alt_once = 1;
#endif
#ifdef CONFIG_SMP
@@ -401,4 +415,37 @@ void __init alternative_instructions(void)
#endif
apply_paravirt(__parainstructions, __parainstructions_end);
local_irq_restore(flags);
+
+ restart_nmi();
+#ifdef CONFIG_MCE
+ restart_mce();
+#endif
+}
+
+/*
+ * Warning:
+ * When you use this code to patch more than one byte of an instruction
+ * you need to make sure that other CPUs cannot execute this code in parallel.
+ * Also no thread must be currently preempted in the middle of these instructions.
+ * And on the local CPU you need to be protected again NMI or MCE handlers
+ * seeing an inconsistent instruction while you patch.
+ */
+void __kprobes text_poke(void *oaddr, unsigned char *opcode, int len)
+{
+ u8 *addr = oaddr;
+ if (!pte_write(*lookup_address((unsigned long)addr))) {
+ struct page *p[2] = { virt_to_page(addr), virt_to_page(addr+PAGE_SIZE) };
+ addr = vmap(p, 2, VM_MAP, PAGE_KERNEL);
+ if (!addr)
+ return;
+ addr += ((unsigned long)oaddr) % PAGE_SIZE;
+ }
+ memcpy(addr, opcode, len);
+ sync_core();
+ /* Not strictly needed, but can speed CPU recovery up. Ignore cross cacheline
+ case. */
+ if (cpu_has_clflush)
+ asm("clflush (%0) " :: "r" (oaddr) : "memory");
+ if (addr != oaddr)
+ vunmap(addr);
}
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 67824f3bb974..bfc6cb7df7e7 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -263,6 +263,9 @@ static void lapic_timer_setup(enum clock_event_mode mode,
v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
apic_write_around(APIC_LVTT, v);
break;
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
+ break;
}
local_irq_restore(flags);
@@ -315,7 +318,7 @@ static void __devinit setup_APIC_timer(void)
#define LAPIC_CAL_LOOPS (HZ/10)
-static __initdata volatile int lapic_cal_loops = -1;
+static __initdata int lapic_cal_loops = -1;
static __initdata long lapic_cal_t1, lapic_cal_t2;
static __initdata unsigned long long lapic_cal_tsc1, lapic_cal_tsc2;
static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
@@ -485,7 +488,7 @@ void __init setup_boot_APIC_clock(void)
/* Let the interrupts run */
local_irq_enable();
- while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
+ while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
cpu_relax();
local_irq_disable();
@@ -521,6 +524,9 @@ void __init setup_boot_APIC_clock(void)
*/
if (nmi_watchdog != NMI_IO_APIC)
lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+ else
+ printk(KERN_WARNING "APIC timer registered as dummy,"
+ " due to nmi_watchdog=1!\n");
}
/* Setup the lapic or request the broadcast */
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 4112afe712b9..47001d50a083 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -222,6 +222,7 @@
#include <linux/capability.h>
#include <linux/device.h>
#include <linux/kernel.h>
+#include <linux/freezer.h>
#include <linux/smp.h>
#include <linux/dmi.h>
#include <linux/suspend.h>
@@ -2311,7 +2312,6 @@ static int __init apm_init(void)
remove_proc_entry("apm", NULL);
return err;
}
- kapmd_task->flags |= PF_NOFREEZE;
wake_up_process(kapmd_task);
if (num_online_cpus() > 1 && !smp ) {
diff --git a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
index 27a776c9044d..7288ac88d746 100644
--- a/arch/i386/kernel/asm-offsets.c
+++ b/arch/i386/kernel/asm-offsets.c
@@ -17,6 +17,13 @@
#include <asm/thread_info.h>
#include <asm/elf.h>
+#include <xen/interface/xen.h>
+
+#ifdef CONFIG_LGUEST_GUEST
+#include <linux/lguest.h>
+#include "../../../drivers/lguest/lg.h"
+#endif
+
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -59,6 +66,7 @@ void foo(void)
OFFSET(TI_addr_limit, thread_info, addr_limit);
OFFSET(TI_restart_block, thread_info, restart_block);
OFFSET(TI_sysenter_return, thread_info, sysenter_return);
+ OFFSET(TI_cpu, thread_info, cpu);
BLANK();
OFFSET(GDS_size, Xgt_desc_struct, size);
@@ -115,4 +123,25 @@ void foo(void)
OFFSET(PARAVIRT_iret, paravirt_ops, iret);
OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0);
#endif
+
+#ifdef CONFIG_XEN
+ BLANK();
+ OFFSET(XEN_vcpu_info_mask, vcpu_info, evtchn_upcall_mask);
+ OFFSET(XEN_vcpu_info_pending, vcpu_info, evtchn_upcall_pending);
+#endif
+
+#ifdef CONFIG_LGUEST_GUEST
+ BLANK();
+ OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled);
+ OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc);
+ OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc);
+ OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3);
+ OFFSET(LGUEST_PAGES_host_sp, lguest_pages, state.host_sp);
+ OFFSET(LGUEST_PAGES_guest_gdt_desc, lguest_pages,state.guest_gdt_desc);
+ OFFSET(LGUEST_PAGES_guest_idt_desc, lguest_pages,state.guest_idt_desc);
+ OFFSET(LGUEST_PAGES_guest_gdt, lguest_pages, state.guest_gdt);
+ OFFSET(LGUEST_PAGES_regs_trapnum, lguest_pages, regs.trapnum);
+ OFFSET(LGUEST_PAGES_regs_errcode, lguest_pages, regs.errcode);
+ OFFSET(LGUEST_PAGES_regs, lguest_pages, regs);
+#endif
}
diff --git a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
index 74f27a463db0..778396c78d65 100644
--- a/arch/i386/kernel/cpu/Makefile
+++ b/arch/i386/kernel/cpu/Makefile
@@ -8,8 +8,7 @@ obj-y += amd.o
obj-y += cyrix.o
obj-y += centaur.o
obj-y += transmeta.o
-obj-y += intel.o intel_cacheinfo.o
-obj-y += rise.o
+obj-y += intel.o intel_cacheinfo.o addon_cpuid_features.o
obj-y += nexgen.o
obj-y += umc.o
diff --git a/arch/i386/kernel/cpu/addon_cpuid_features.c b/arch/i386/kernel/cpu/addon_cpuid_features.c
new file mode 100644
index 000000000000..3e91d3ee26ec
--- /dev/null
+++ b/arch/i386/kernel/cpu/addon_cpuid_features.c
@@ -0,0 +1,50 @@
+
+/*
+ * Routines to indentify additional cpu features that are scattered in
+ * cpuid space.
+ */
+
+#include <linux/cpu.h>
+
+#include <asm/processor.h>
+
+struct cpuid_bit {
+ u16 feature;
+ u8 reg;
+ u8 bit;
+ u32 level;
+};
+
+enum cpuid_regs {
+ CR_EAX = 0,
+ CR_ECX,
+ CR_EDX,
+ CR_EBX
+};
+
+void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
+{
+ u32 max_level;
+ u32 regs[4];
+ const struct cpuid_bit *cb;
+
+ static const struct cpuid_bit cpuid_bits[] = {
+ { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 },
+ { 0, 0, 0, 0 }
+ };
+
+ for (cb = cpuid_bits; cb->feature; cb++) {
+
+ /* Verify that the level is valid */
+ max_level = cpuid_eax(cb->level & 0xffff0000);
+ if (max_level < cb->level ||
+ max_level > (cb->level | 0xffff))
+ continue;
+
+ cpuid(cb->level, &regs[CR_EAX], &regs[CR_EBX],
+ &regs[CR_ECX], &regs[CR_EDX]);
+
+ if (regs[cb->reg] & (1 << cb->bit))
+ set_bit(cb->feature, c->x86_capability);
+ }
+}
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 6f47eeeb93ea..c7ba455d5ac7 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -231,6 +231,9 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
switch (c->x86) {
case 15:
+ /* Use K8 tuning for Fam10h and Fam11h */
+ case 0x10:
+ case 0x11:
set_bit(X86_FEATURE_K8, c->x86_capability);
break;
case 6:
@@ -272,8 +275,12 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
}
#endif
- if (cpuid_eax(0x80000000) >= 0x80000006)
- num_cache_leaves = 3;
+ if (cpuid_eax(0x80000000) >= 0x80000006) {
+ if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000))
+ num_cache_leaves = 4;
+ else
+ num_cache_leaves = 3;
+ }
if (amd_apic_timer_broken())
set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 794d593c47eb..d506201d397c 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -353,6 +353,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
if ( xlvl >= 0x80000004 )
get_model_name(c); /* Default name */
}
+
+ init_scattered_cpuid_features(c);
}
early_intel_workaround(c);
@@ -604,7 +606,6 @@ extern int nsc_init_cpu(void);
extern int amd_init_cpu(void);
extern int centaur_init_cpu(void);
extern int transmeta_init_cpu(void);
-extern int rise_init_cpu(void);
extern int nexgen_init_cpu(void);
extern int umc_init_cpu(void);
@@ -616,7 +617,6 @@ void __init early_cpu_init(void)
amd_init_cpu();
centaur_init_cpu();
transmeta_init_cpu();
- rise_init_cpu();
nexgen_init_cpu();
umc_init_cpu();
early_cpu_detect();
diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig
index e912aae9473c..094118ba00da 100644
--- a/arch/i386/kernel/cpu/cpufreq/Kconfig
+++ b/arch/i386/kernel/cpu/cpufreq/Kconfig
@@ -90,10 +90,17 @@ config X86_POWERNOW_K8
If in doubt, say N.
config X86_POWERNOW_K8_ACPI
- bool
- depends on X86_POWERNOW_K8 && ACPI_PROCESSOR
- depends on !(X86_POWERNOW_K8 = y && ACPI_PROCESSOR = m)
+ bool "ACPI Support"
+ select ACPI_PROCESSOR
+ depends on X86_POWERNOW_K8
default y
+ help
+ This provides access to the K8s Processor Performance States via ACPI.
+ This driver is probably required for CPUFreq to work with multi-socket and
+ SMP systems. It is not required on at least some single-socket yet
+ multi-core systems, even if SMP is enabled.
+
+ It is safe to say Y here.
config X86_GX_SUSPMOD
tristate "Cyrix MediaGX/NatSemi Geode Suspend Modulation"
@@ -109,7 +116,7 @@ config X86_GX_SUSPMOD
config X86_SPEEDSTEP_CENTRINO
tristate "Intel Enhanced SpeedStep"
select CPU_FREQ_TABLE
- select X86_SPEEDSTEP_CENTRINO_TABLE if (!X86_SPEEDSTEP_CENTRINO_ACPI)
+ select X86_SPEEDSTEP_CENTRINO_TABLE
help
This adds the CPUFreq driver for Enhanced SpeedStep enabled
mobile CPUs. This means Intel Pentium M (Centrino) CPUs. However,
@@ -121,20 +128,6 @@ config X86_SPEEDSTEP_CENTRINO
If in doubt, say N.
-config X86_SPEEDSTEP_CENTRINO_ACPI
- bool "Use ACPI tables to decode valid frequency/voltage (deprecated)"
- depends on X86_SPEEDSTEP_CENTRINO && ACPI_PROCESSOR
- depends on !(X86_SPEEDSTEP_CENTRINO = y && ACPI_PROCESSOR = m)
- help
- This is deprecated and this functionality is now merged into
- acpi_cpufreq (X86_ACPI_CPUFREQ). Use that driver instead of
- speedstep_centrino.
- Use primarily the information provided in the BIOS ACPI tables
- to determine valid CPU frequency and voltage pairings. It is
- required for the driver to work on non-Banias CPUs.
-
- If in doubt, say Y.
-
config X86_SPEEDSTEP_CENTRINO_TABLE
bool "Built-in tables for Banias CPUs"
depends on X86_SPEEDSTEP_CENTRINO
@@ -230,7 +223,7 @@ comment "shared options"
config X86_ACPI_CPUFREQ_PROC_INTF
bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on PROC_FS
- depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K7_ACPI || X86_POWERNOW_K8_ACPI
+ depends on X86_ACPI_CPUFREQ || X86_POWERNOW_K7_ACPI || X86_POWERNOW_K8_ACPI
help
This enables the deprecated /proc/acpi/processor/../performance
interface. While it is helpful for debugging, the generic,
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index 10baa3501ed3..6f846bee2103 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -167,11 +167,13 @@ static void do_drv_read(struct drv_cmd *cmd)
static void do_drv_write(struct drv_cmd *cmd)
{
- u32 h = 0;
+ u32 lo, hi;
switch (cmd->type) {
case SYSTEM_INTEL_MSR_CAPABLE:
- wrmsr(cmd->addr.msr.reg, cmd->val, h);
+ rdmsr(cmd->addr.msr.reg, lo, hi);
+ lo = (lo & ~INTEL_MSR_RANGE) | (cmd->val & INTEL_MSR_RANGE);
+ wrmsr(cmd->addr.msr.reg, lo, hi);
break;
case SYSTEM_IO_CAPABLE:
acpi_os_write_port((acpi_io_address)cmd->addr.io.port,
@@ -372,7 +374,6 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
struct cpufreq_freqs freqs;
cpumask_t online_policy_cpus;
struct drv_cmd cmd;
- unsigned int msr;
unsigned int next_state = 0; /* Index into freq_table */
unsigned int next_perf_state = 0; /* Index into perf table */
unsigned int i;
@@ -417,11 +418,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
case SYSTEM_INTEL_MSR_CAPABLE:
cmd.type = SYSTEM_INTEL_MSR_CAPABLE;
cmd.addr.msr.reg = MSR_IA32_PERF_CTL;
- msr =
- (u32) perf->states[next_perf_state].
- control & INTEL_MSR_RANGE;
- cmd.val = get_cur_val(online_policy_cpus);
- cmd.val = (cmd.val & ~INTEL_MSR_RANGE) | msr;
+ cmd.val = (u32) perf->states[next_perf_state].control;
break;
case SYSTEM_IO_CAPABLE:
cmd.type = SYSTEM_IO_CAPABLE;
@@ -668,8 +665,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
data->max_freq = perf->states[0].core_frequency * 1000;
/* table init */
for (i=0; i<perf->state_count; i++) {
- if (i>0 && perf->states[i].core_frequency ==
- perf->states[i-1].core_frequency)
+ if (i>0 && perf->states[i].core_frequency >=
+ data->freq_table[valid_states-1].frequency / 1000)
continue;
data->freq_table[valid_states].index = i;
diff --git a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c
index 0d49d73d1b71..66acd5039918 100644
--- a/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c
+++ b/arch/i386/kernel/cpu/cpufreq/cpufreq-nforce2.c
@@ -391,8 +391,6 @@ static struct cpufreq_driver nforce2_driver = {
*/
static unsigned int nforce2_detect_chipset(void)
{
- u8 revision;
-
nforce2_chipset_dev = pci_get_subsys(PCI_VENDOR_ID_NVIDIA,
PCI_DEVICE_ID_NVIDIA_NFORCE2,
PCI_ANY_ID, PCI_ANY_ID, NULL);
@@ -400,10 +398,8 @@ static unsigned int nforce2_detect_chipset(void)
if (nforce2_chipset_dev == NULL)
return -ENODEV;
- pci_read_config_byte(nforce2_chipset_dev, PCI_REVISION_ID, &revision);
-
printk(KERN_INFO "cpufreq: Detected nForce2 chipset revision %X\n",
- revision);
+ nforce2_chipset_dev->revision);
printk(KERN_INFO
"cpufreq: FSB changing is maybe unstable and can lead to crashes and data loss.\n");
diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
index 6667e9cceb9f..461dabc4e495 100644
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
@@ -79,7 +79,7 @@
#include <linux/smp.h>
#include <linux/cpufreq.h>
#include <linux/pci.h>
-#include <asm/processor.h>
+#include <asm/processor-cyrix.h>
#include <asm/errno.h>
/* PCI config registers, all at F0 */
@@ -115,7 +115,6 @@ struct gxfreq_params {
u8 pci_suscfg;
u8 pci_pmer1;
u8 pci_pmer2;
- u8 pci_rev;
struct pci_dev *cs55x0;
};
@@ -276,7 +275,7 @@ static void gx_set_cpuspeed(unsigned int khz)
pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */
pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1);
- if (gx_params->pci_rev < 0x10) { /* CS5530(rev 1.2, 1.3) */
+ if (gx_params->cs55x0->revision < 0x10) { /* CS5530(rev 1.2, 1.3) */
suscfg = gx_params->pci_suscfg | SUSMOD;
} else { /* CS5530A,B.. */
suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE;
@@ -471,7 +470,6 @@ static int __init cpufreq_gx_init(void)
pci_read_config_byte(params->cs55x0, PCI_PMER2, &(params->pci_pmer2));
pci_read_config_byte(params->cs55x0, PCI_MODON, &(params->on_duration));
pci_read_config_byte(params->cs55x0, PCI_MODOFF, &(params->off_duration));
- pci_read_config_byte(params->cs55x0, PCI_REVISION_ID, &params->pci_rev);
if ((ret = cpufreq_register_driver(&gx_suspmod_driver))) {
kfree(params);
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index a3df9c039bd4..ef8f0bc3fc71 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -29,6 +29,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/delay.h>
#include <asm/msr.h>
#include <asm/timex.h>
@@ -55,7 +56,6 @@
/* Flags */
#define USE_ACPI_C3 (1 << 1)
#define USE_NORTHBRIDGE (1 << 2)
-#define USE_VT8235 (1 << 3)
static int cpu_model;
static unsigned int numscales=16;
@@ -63,22 +63,19 @@ static unsigned int fsb;
static const struct mV_pos *vrm_mV_table;
static const unsigned char *mV_vrm_table;
-struct f_msr {
- u8 vrm;
- u8 pos;
-};
-static struct f_msr f_msr_table[32];
static unsigned int highest_speed, lowest_speed; /* kHz */
static unsigned int minmult, maxmult;
static int can_scale_voltage;
static struct acpi_processor *pr = NULL;
static struct acpi_processor_cx *cx = NULL;
+static u32 acpi_regs_addr;
static u8 longhaul_flags;
-static u8 longhaul_pos;
+static unsigned int longhaul_index;
/* Module parameters */
static int scale_voltage;
+static int disable_acpi_c3;
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "longhaul", msg)
@@ -144,7 +141,7 @@ static void do_longhaul1(unsigned int clock_ratio_index)
rdmsrl(MSR_VIA_BCR2, bcr2.val);
/* Enable software clock multiplier */
bcr2.bits.ESOFTBF = 1;
- bcr2.bits.CLOCKMUL = clock_ratio_index;
+ bcr2.bits.CLOCKMUL = clock_ratio_index & 0xff;
/* Sync to timer tick */
safe_halt();
@@ -163,14 +160,12 @@ static void do_longhaul1(unsigned int clock_ratio_index)
/* For processor with Longhaul MSR */
-static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
+static void do_powersaver(int cx_address, unsigned int clock_ratio_index,
+ unsigned int dir)
{
union msr_longhaul longhaul;
- u8 dest_pos;
u32 t;
- dest_pos = f_msr_table[clock_ratio_index].pos;
-
rdmsrl(MSR_VIA_LONGHAUL, longhaul.val);
/* Setup new frequency */
longhaul.bits.RevisionKey = longhaul.bits.RevisionID;
@@ -178,11 +173,11 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
longhaul.bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4;
/* Setup new voltage */
if (can_scale_voltage)
- longhaul.bits.SoftVID = f_msr_table[clock_ratio_index].vrm;
+ longhaul.bits.SoftVID = (clock_ratio_index >> 8) & 0x1f;
/* Sync to timer tick */
safe_halt();
/* Raise voltage if necessary */
- if (can_scale_voltage && longhaul_pos < dest_pos) {
+ if (can_scale_voltage && dir) {
longhaul.bits.EnableSoftVID = 1;
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
/* Change voltage */
@@ -199,7 +194,6 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
}
longhaul.bits.EnableSoftVID = 0;
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
- longhaul_pos = dest_pos;
}
/* Change frequency on next halt or sleep */
@@ -220,7 +214,7 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
/* Reduce voltage if necessary */
- if (can_scale_voltage && longhaul_pos > dest_pos) {
+ if (can_scale_voltage && !dir) {
longhaul.bits.EnableSoftVID = 1;
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
/* Change voltage */
@@ -237,7 +231,6 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
}
longhaul.bits.EnableSoftVID = 0;
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
- longhaul_pos = dest_pos;
}
}
@@ -248,25 +241,28 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
* Sets a new clock ratio.
*/
-static void longhaul_setstate(unsigned int clock_ratio_index)
+static void longhaul_setstate(unsigned int table_index)
{
+ unsigned int clock_ratio_index;
int speed, mult;
struct cpufreq_freqs freqs;
- static unsigned int old_ratio=-1;
unsigned long flags;
unsigned int pic1_mask, pic2_mask;
+ u16 bm_status = 0;
+ u32 bm_timeout = 1000;
+ unsigned int dir = 0;
- if (old_ratio == clock_ratio_index)
- return;
- old_ratio = clock_ratio_index;
-
- mult = clock_ratio[clock_ratio_index];
+ clock_ratio_index = longhaul_table[table_index].index;
+ /* Safety precautions */
+ mult = clock_ratio[clock_ratio_index & 0x1f];
if (mult == -1)
return;
-
speed = calc_speed(mult);
if ((speed > highest_speed) || (speed < lowest_speed))
return;
+ /* Voltage transition before frequency transition? */
+ if (can_scale_voltage && longhaul_index < table_index)
+ dir = 1;
freqs.old = calc_speed(longhaul_get_cpu_mult());
freqs.new = speed;
@@ -285,11 +281,24 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
outb(0xFF,0xA1); /* Overkill */
outb(0xFE,0x21); /* TMR0 only */
+ /* Wait while PCI bus is busy. */
+ if (acpi_regs_addr && (longhaul_flags & USE_NORTHBRIDGE
+ || ((pr != NULL) && pr->flags.bm_control))) {
+ bm_status = inw(acpi_regs_addr);
+ bm_status &= 1 << 4;
+ while (bm_status && bm_timeout) {
+ outw(1 << 4, acpi_regs_addr);
+ bm_timeout--;
+ bm_status = inw(acpi_regs_addr);
+ bm_status &= 1 << 4;
+ }
+ }
+
if (longhaul_flags & USE_NORTHBRIDGE) {
/* Disable AGP and PCI arbiters */
outb(3, 0x22);
} else if ((pr != NULL) && pr->flags.bm_control) {
- /* Disable bus master arbitration */
+ /* Disable bus master arbitration */
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
switch (longhaul_version) {
@@ -314,9 +323,9 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
if (longhaul_flags & USE_ACPI_C3) {
/* Don't allow wakeup */
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
- do_powersaver(cx->address, clock_ratio_index);
+ do_powersaver(cx->address, clock_ratio_index, dir);
} else {
- do_powersaver(0, clock_ratio_index);
+ do_powersaver(0, clock_ratio_index, dir);
}
break;
}
@@ -336,6 +345,9 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
freqs.new = calc_speed(longhaul_get_cpu_mult());
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ if (!bm_timeout)
+ printk(KERN_INFO PFX "Warning: Timeout while waiting for idle PCI bus.\n");
}
/*
@@ -369,7 +381,8 @@ static int guess_fsb(int mult)
static int __init longhaul_get_ranges(void)
{
- unsigned int j, k = 0;
+ unsigned int i, j, k = 0;
+ unsigned int ratio;
int mult;
/* Get current frequency */
@@ -423,8 +436,7 @@ static int __init longhaul_get_ranges(void)
if(!longhaul_table)
return -ENOMEM;
- for (j=0; j < numscales; j++) {
- unsigned int ratio;
+ for (j = 0; j < numscales; j++) {
ratio = clock_ratio[j];
if (ratio == -1)
continue;
@@ -434,13 +446,41 @@ static int __init longhaul_get_ranges(void)
longhaul_table[k].index = j;
k++;
}
+ if (k <= 1) {
+ kfree(longhaul_table);
+ return -ENODEV;
+ }
+ /* Sort */
+ for (j = 0; j < k - 1; j++) {
+ unsigned int min_f, min_i;
+ min_f = longhaul_table[j].frequency;
+ min_i = j;
+ for (i = j + 1; i < k; i++) {
+ if (longhaul_table[i].frequency < min_f) {
+ min_f = longhaul_table[i].frequency;
+ min_i = i;
+ }
+ }
+ if (min_i != j) {
+ unsigned int temp;
+ temp = longhaul_table[j].frequency;
+ longhaul_table[j].frequency = longhaul_table[min_i].frequency;
+ longhaul_table[min_i].frequency = temp;
+ temp = longhaul_table[j].index;
+ longhaul_table[j].index = longhaul_table[min_i].index;
+ longhaul_table[min_i].index = temp;
+ }
+ }
longhaul_table[k].frequency = CPUFREQ_TABLE_END;
- if (!k) {
- kfree (longhaul_table);
- return -EINVAL;
- }
+ /* Find index we are running on */
+ for (j = 0; j < k; j++) {
+ if (clock_ratio[longhaul_table[j].index & 0x1f] == mult) {
+ longhaul_index = j;
+ break;
+ }
+ }
return 0;
}
@@ -448,7 +488,7 @@ static int __init longhaul_get_ranges(void)
static void __init longhaul_setup_voltagescaling(void)
{
union msr_longhaul longhaul;
- struct mV_pos minvid, maxvid;
+ struct mV_pos minvid, maxvid, vid;
unsigned int j, speed, pos, kHz_step, numvscales;
int min_vid_speed;
@@ -459,11 +499,11 @@ static void __init longhaul_setup_voltagescaling(void)
}
if (!longhaul.bits.VRMRev) {
- printk (KERN_INFO PFX "VRM 8.5\n");
+ printk(KERN_INFO PFX "VRM 8.5\n");
vrm_mV_table = &vrm85_mV[0];
mV_vrm_table = &mV_vrm85[0];
} else {
- printk (KERN_INFO PFX "Mobile VRM\n");
+ printk(KERN_INFO PFX "Mobile VRM\n");
if (cpu_model < CPU_NEHEMIAH)
return;
vrm_mV_table = &mobilevrm_mV[0];
@@ -523,7 +563,6 @@ static void __init longhaul_setup_voltagescaling(void)
/* Calculate kHz for one voltage step */
kHz_step = (highest_speed - min_vid_speed) / numvscales;
-
j = 0;
while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
speed = longhaul_table[j].frequency;
@@ -531,15 +570,14 @@ static void __init longhaul_setup_voltagescaling(void)
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
else
pos = minvid.pos;
- f_msr_table[longhaul_table[j].index].vrm = mV_vrm_table[pos];
- f_msr_table[longhaul_table[j].index].pos = pos;
+ longhaul_table[j].index |= mV_vrm_table[pos] << 8;
+ vid = vrm_mV_table[mV_vrm_table[pos]];
+ printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n", speed, j, vid.mV);
j++;
}
- longhaul_pos = maxvid.pos;
can_scale_voltage = 1;
- printk(KERN_INFO PFX "Voltage scaling enabled. "
- "Use of \"conservative\" governor is highly recommended.\n");
+ printk(KERN_INFO PFX "Voltage scaling enabled.\n");
}
@@ -553,15 +591,44 @@ static int longhaul_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation)
{
unsigned int table_index = 0;
- unsigned int new_clock_ratio = 0;
+ unsigned int i;
+ unsigned int dir = 0;
+ u8 vid, current_vid;
if (cpufreq_frequency_table_target(policy, longhaul_table, target_freq, relation, &table_index))
return -EINVAL;
- new_clock_ratio = longhaul_table[table_index].index & 0xFF;
-
- longhaul_setstate(new_clock_ratio);
+ /* Don't set same frequency again */
+ if (longhaul_index == table_index)
+ return 0;
+ if (!can_scale_voltage)
+ longhaul_setstate(table_index);
+ else {
+ /* On test system voltage transitions exceeding single
+ * step up or down were turning motherboard off. Both
+ * "ondemand" and "userspace" are unsafe. C7 is doing
+ * this in hardware, C3 is old and we need to do this
+ * in software. */
+ i = longhaul_index;
+ current_vid = (longhaul_table[longhaul_index].index >> 8) & 0x1f;
+ if (table_index > longhaul_index)
+ dir = 1;
+ while (i != table_index) {
+ vid = (longhaul_table[i].index >> 8) & 0x1f;
+ if (vid != current_vid) {
+ longhaul_setstate(i);
+ current_vid = vid;
+ msleep(200);
+ }
+ if (dir)
+ i++;
+ else
+ i--;
+ }
+ longhaul_setstate(table_index);
+ }
+ longhaul_index = table_index;
return 0;
}
@@ -590,11 +657,10 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
static int enable_arbiter_disable(void)
{
struct pci_dev *dev;
- int status;
+ int status = 1;
int reg;
u8 pci_cmd;
- status = 1;
/* Find PLE133 host bridge */
reg = 0x78;
dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0,
@@ -627,13 +693,17 @@ static int enable_arbiter_disable(void)
return 0;
}
-static int longhaul_setup_vt8235(void)
+static int longhaul_setup_southbridge(void)
{
struct pci_dev *dev;
u8 pci_cmd;
/* Find VT8235 southbridge */
dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL);
+ if (dev == NULL)
+ /* Find VT8237 southbridge */
+ dev = pci_get_device(PCI_VENDOR_ID_VIA,
+ PCI_DEVICE_ID_VIA_8237, NULL);
if (dev != NULL) {
/* Set transition time to max */
pci_read_config_byte(dev, 0xec, &pci_cmd);
@@ -645,6 +715,14 @@ static int longhaul_setup_vt8235(void)
pci_read_config_byte(dev, 0xe5, &pci_cmd);
pci_cmd |= 1 << 7;
pci_write_config_byte(dev, 0xe5, pci_cmd);
+ /* Get address of ACPI registers block*/
+ pci_read_config_byte(dev, 0x81, &pci_cmd);
+ if (pci_cmd & 1 << 7) {
+ pci_read_config_dword(dev, 0x88, &acpi_regs_addr);
+ acpi_regs_addr &= 0xff00;
+ printk(KERN_INFO PFX "ACPI I/O at 0x%x\n", acpi_regs_addr);
+ }
+
pci_dev_put(dev);
return 1;
}
@@ -657,7 +735,6 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
char *cpuname=NULL;
int ret;
u32 lo, hi;
- int vt8235_present;
/* Check what we have on this motherboard */
switch (c->x86_model) {
@@ -755,7 +832,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
};
/* Doesn't hurt */
- vt8235_present = longhaul_setup_vt8235();
+ longhaul_setup_southbridge();
/* Find ACPI data for processor */
acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
@@ -765,35 +842,29 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
/* Check ACPI support for C3 state */
if (pr != NULL && longhaul_version == TYPE_POWERSAVER) {
cx = &pr->power.states[ACPI_STATE_C3];
- if (cx->address > 0 && cx->latency <= 1000) {
+ if (cx->address > 0 && cx->latency <= 1000)
longhaul_flags |= USE_ACPI_C3;
- goto print_support_type;
- }
}
+ /* Disable if it isn't working */
+ if (disable_acpi_c3)
+ longhaul_flags &= ~USE_ACPI_C3;
/* Check if northbridge is friendly */
- if (enable_arbiter_disable()) {
+ if (enable_arbiter_disable())
longhaul_flags |= USE_NORTHBRIDGE;
- goto print_support_type;
- }
- /* Use VT8235 southbridge if present */
- if (longhaul_version == TYPE_POWERSAVER && vt8235_present) {
- longhaul_flags |= USE_VT8235;
- goto print_support_type;
- }
+
/* Check ACPI support for bus master arbiter disable */
- if ((pr == NULL) || !(pr->flags.bm_control)) {
+ if (!(longhaul_flags & USE_ACPI_C3
+ || longhaul_flags & USE_NORTHBRIDGE)
+ && ((pr == NULL) || !(pr->flags.bm_control))) {
printk(KERN_ERR PFX
"No ACPI support. Unsupported northbridge.\n");
return -ENODEV;
}
-print_support_type:
if (longhaul_flags & USE_NORTHBRIDGE)
- printk (KERN_INFO PFX "Using northbridge support.\n");
- else if (longhaul_flags & USE_VT8235)
- printk (KERN_INFO PFX "Using VT8235 support.\n");
- else
- printk (KERN_INFO PFX "Using ACPI support.\n");
+ printk(KERN_INFO PFX "Using northbridge support.\n");
+ if (longhaul_flags & USE_ACPI_C3)
+ printk(KERN_INFO PFX "Using ACPI support.\n");
ret = longhaul_get_ranges();
if (ret != 0)
@@ -885,6 +956,9 @@ static void __exit longhaul_exit(void)
kfree(longhaul_table);
}
+module_param (disable_acpi_c3, int, 0644);
+MODULE_PARM_DESC(disable_acpi_c3, "Don't use ACPI C3 support");
+
module_param (scale_voltage, int, 0644);
MODULE_PARM_DESC(scale_voltage, "Scale voltage of processor");
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.h b/arch/i386/kernel/cpu/cpufreq/longhaul.h
index 102548f12842..4fcc320997df 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.h
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.h
@@ -180,7 +180,7 @@ static const int __initdata ezrat_clock_ratio[32] = {
-1, /* 0000 -> RESERVED (10.0x) */
110, /* 0001 -> 11.0x */
- 120, /* 0010 -> 12.0x */
+ -1, /* 0010 -> 12.0x */
-1, /* 0011 -> RESERVED (9.0x)*/
105, /* 0100 -> 10.5x */
115, /* 0101 -> 11.5x */
@@ -237,7 +237,7 @@ static const int __initdata ezrat_eblcr[32] = {
static const int __initdata nehemiah_clock_ratio[32] = {
100, /* 0000 -> 10.0x */
- 160, /* 0001 -> 16.0x */
+ -1, /* 0001 -> 16.0x */
40, /* 0010 -> 4.0x */
90, /* 0011 -> 9.0x */
95, /* 0100 -> 9.5x */
@@ -252,10 +252,10 @@ static const int __initdata nehemiah_clock_ratio[32] = {
75, /* 1101 -> 7.5x */
85, /* 1110 -> 8.5x */
120, /* 1111 -> 12.0x */
- 100, /* 0000 -> 10.0x */
+ -1, /* 0000 -> 10.0x */
110, /* 0001 -> 11.0x */
- 120, /* 0010 -> 12.0x */
- 90, /* 0011 -> 9.0x */
+ -1, /* 0010 -> 12.0x */
+ -1, /* 0011 -> 9.0x */
105, /* 0100 -> 10.5x */
115, /* 0101 -> 11.5x */
125, /* 0110 -> 12.5x */
@@ -267,7 +267,7 @@ static const int __initdata nehemiah_clock_ratio[32] = {
145, /* 1100 -> 14.5x */
155, /* 1101 -> 15.5x */
-1, /* 1110 -> RESERVED (13.0x) */
- 120, /* 1111 -> 12.0x */
+ -1, /* 1111 -> 12.0x */
};
static const int __initdata nehemiah_eblcr[32] = {
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
index 4ade55c5f333..34ed53a06730 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
@@ -599,14 +599,17 @@ static void print_basics(struct powernow_k8_data *data)
for (j = 0; j < data->numps; j++) {
if (data->powernow_table[j].frequency != CPUFREQ_ENTRY_INVALID) {
if (cpu_family == CPU_HW_PSTATE) {
- printk(KERN_INFO PFX " %d : fid 0x%x gid 0x%x (%d MHz)\n", j, (data->powernow_table[j].index & 0xff00) >> 8,
- (data->powernow_table[j].index & 0xff0000) >> 16,
- data->powernow_table[j].frequency/1000);
+ printk(KERN_INFO PFX " %d : fid 0x%x did 0x%x (%d MHz)\n",
+ j,
+ (data->powernow_table[j].index & 0xff00) >> 8,
+ (data->powernow_table[j].index & 0xff0000) >> 16,
+ data->powernow_table[j].frequency/1000);
} else {
- printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x\n", j,
- data->powernow_table[j].index & 0xff,
- data->powernow_table[j].frequency/1000,
- data->powernow_table[j].index >> 8);
+ printk(KERN_INFO PFX " %d : fid 0x%x (%d MHz), vid 0x%x\n",
+ j,
+ data->powernow_table[j].index & 0xff,
+ data->powernow_table[j].frequency/1000,
+ data->powernow_table[j].index >> 8);
}
}
}
@@ -1086,7 +1089,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi
if (cpu_family == CPU_HW_PSTATE)
dprintk("targ: curr fid 0x%x, did 0x%x\n",
- data->currfid, data->currvid);
+ data->currfid, data->currdid);
else {
dprintk("targ: curr fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid);
@@ -1322,16 +1325,22 @@ static struct cpufreq_driver cpufreq_amd64_driver = {
static int __cpuinit powernowk8_init(void)
{
unsigned int i, supported_cpus = 0;
+ unsigned int booted_cores = 1;
for_each_online_cpu(i) {
if (check_supported_cpu(i))
supported_cpus++;
}
+#ifdef CONFIG_SMP
+ booted_cores = cpu_data[0].booted_cores;
+#endif
+
if (supported_cpus == num_online_cpus()) {
printk(KERN_INFO PFX "Found %d %s "
- "processors (" VERSION ")\n", supported_cpus,
- boot_cpu_data.x86_model_id);
+ "processors (%d cpu cores) (" VERSION ")\n",
+ supported_cpus/booted_cores,
+ boot_cpu_data.x86_model_id, supported_cpus);
return cpufreq_register_driver(&cpufreq_amd64_driver);
}
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index 35489fd68852..6c5dc2c85aeb 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -21,12 +21,6 @@
#include <linux/delay.h>
#include <linux/compiler.h>
-#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
-#include <linux/acpi.h>
-#include <linux/dmi.h>
-#include <acpi/processor.h>
-#endif
-
#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpufeature.h>
@@ -257,9 +251,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
/* Matched a non-match */
dprintk("no table support for CPU model \"%s\"\n",
cpu->x86_model_id);
-#ifndef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
- dprintk("try compiling with CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI enabled\n");
-#endif
+ dprintk("try using the acpi-cpufreq driver\n");
return -ENOENT;
}
@@ -346,213 +338,6 @@ static unsigned int get_cur_freq(unsigned int cpu)
}
-#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
-
-static struct acpi_processor_performance *acpi_perf_data[NR_CPUS];
-
-/*
- * centrino_cpu_early_init_acpi - Do the preregistering with ACPI P-States
- * library
- *
- * Before doing the actual init, we need to do _PSD related setup whenever
- * supported by the BIOS. These are handled by this early_init routine.
- */
-static int centrino_cpu_early_init_acpi(void)
-{
- unsigned int i, j;
- struct acpi_processor_performance *data;
-
- for_each_possible_cpu(i) {
- data = kzalloc(sizeof(struct acpi_processor_performance),
- GFP_KERNEL);
- if (!data) {
- for_each_possible_cpu(j) {
- kfree(acpi_perf_data[j]);
- acpi_perf_data[j] = NULL;
- }
- return (-ENOMEM);
- }
- acpi_perf_data[i] = data;
- }
-
- acpi_processor_preregister_performance(acpi_perf_data);
- return 0;
-}
-
-
-#ifdef CONFIG_SMP
-/*
- * Some BIOSes do SW_ANY coordination internally, either set it up in hw
- * or do it in BIOS firmware and won't inform about it to OS. If not
- * detected, this has a side effect of making CPU run at a different speed
- * than OS intended it to run at. Detect it and handle it cleanly.
- */
-static int bios_with_sw_any_bug;
-static int sw_any_bug_found(struct dmi_system_id *d)
-{
- bios_with_sw_any_bug = 1;
- return 0;
-}
-
-static struct dmi_system_id sw_any_bug_dmi_table[] = {
- {
- .callback = sw_any_bug_found,
- .ident = "Supermicro Server X6DLP",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
- DMI_MATCH(DMI_BIOS_VERSION, "080010"),
- DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"),
- },
- },
- { }
-};
-#endif
-
-/*
- * centrino_cpu_init_acpi - register with ACPI P-States library
- *
- * Register with the ACPI P-States library (part of drivers/acpi/processor.c)
- * in order to determine correct frequency and voltage pairings by reading
- * the _PSS of the ACPI DSDT or SSDT tables.
- */
-static int centrino_cpu_init_acpi(struct cpufreq_policy *policy)
-{
- unsigned long cur_freq;
- int result = 0, i;
- unsigned int cpu = policy->cpu;
- struct acpi_processor_performance *p;
-
- p = acpi_perf_data[cpu];
-
- /* register with ACPI core */
- if (acpi_processor_register_performance(p, cpu)) {
- dprintk(PFX "obtaining ACPI data failed\n");
- return -EIO;
- }
-
- policy->shared_type = p->shared_type;
- /*
- * Will let policy->cpus know about dependency only when software
- * coordination is required.
- */
- if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL ||
- policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
- policy->cpus = p->shared_cpu_map;
- }
-
-#ifdef CONFIG_SMP
- dmi_check_system(sw_any_bug_dmi_table);
- if (bios_with_sw_any_bug && cpus_weight(policy->cpus) == 1) {
- policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
- policy->cpus = cpu_core_map[cpu];
- }
-#endif
-
- /* verify the acpi_data */
- if (p->state_count <= 1) {
- dprintk("No P-States\n");
- result = -ENODEV;
- goto err_unreg;
- }
-
- if ((p->control_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
- (p->status_register.space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
- dprintk("Invalid control/status registers (%x - %x)\n",
- p->control_register.space_id, p->status_register.space_id);
- result = -EIO;
- goto err_unreg;
- }
-
- for (i=0; i<p->state_count; i++) {
- if ((p->states[i].control & INTEL_MSR_RANGE) !=
- (p->states[i].status & INTEL_MSR_RANGE)) {
- dprintk("Different MSR bits in control (%llu) and status (%llu)\n",
- p->states[i].control, p->states[i].status);
- result = -EINVAL;
- goto err_unreg;
- }
-
- if (!p->states[i].core_frequency) {
- dprintk("Zero core frequency for state %u\n", i);
- result = -EINVAL;
- goto err_unreg;
- }
-
- if (p->states[i].core_frequency > p->states[0].core_frequency) {
- dprintk("P%u has larger frequency (%llu) than P0 (%llu), skipping\n", i,
- p->states[i].core_frequency, p->states[0].core_frequency);
- p->states[i].core_frequency = 0;
- continue;
- }
- }
-
- centrino_model[cpu] = kzalloc(sizeof(struct cpu_model), GFP_KERNEL);
- if (!centrino_model[cpu]) {
- result = -ENOMEM;
- goto err_unreg;
- }
-
- centrino_model[cpu]->model_name=NULL;
- centrino_model[cpu]->max_freq = p->states[0].core_frequency * 1000;
- centrino_model[cpu]->op_points = kmalloc(sizeof(struct cpufreq_frequency_table) *
- (p->state_count + 1), GFP_KERNEL);
- if (!centrino_model[cpu]->op_points) {
- result = -ENOMEM;
- goto err_kfree;
- }
-
- for (i=0; i<p->state_count; i++) {
- centrino_model[cpu]->op_points[i].index = p->states[i].control & INTEL_MSR_RANGE;
- centrino_model[cpu]->op_points[i].frequency = p->states[i].core_frequency * 1000;
- dprintk("adding state %i with frequency %u and control value %04x\n",
- i, centrino_model[cpu]->op_points[i].frequency, centrino_model[cpu]->op_points[i].index);
- }
- centrino_model[cpu]->op_points[p->state_count].frequency = CPUFREQ_TABLE_END;
-
- cur_freq = get_cur_freq(cpu);
-
- for (i=0; i<p->state_count; i++) {
- if (!p->states[i].core_frequency) {
- dprintk("skipping state %u\n", i);
- centrino_model[cpu]->op_points[i].frequency = CPUFREQ_ENTRY_INVALID;
- continue;
- }
-
- if (extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0) !=
- (centrino_model[cpu]->op_points[i].frequency)) {
- dprintk("Invalid encoded frequency (%u vs. %u)\n",
- extract_clock(centrino_model[cpu]->op_points[i].index, cpu, 0),
- centrino_model[cpu]->op_points[i].frequency);
- result = -EINVAL;
- goto err_kfree_all;
- }
-
- if (cur_freq == centrino_model[cpu]->op_points[i].frequency)
- p->state = i;
- }
-
- /* notify BIOS that we exist */
- acpi_processor_notify_smm(THIS_MODULE);
- printk("speedstep-centrino with X86_SPEEDSTEP_CENTRINO_ACPI "
- "config is deprecated.\n "
- "Use X86_ACPI_CPUFREQ (acpi-cpufreq) instead.\n" );
-
- return 0;
-
- err_kfree_all:
- kfree(centrino_model[cpu]->op_points);
- err_kfree:
- kfree(centrino_model[cpu]);
- err_unreg:
- acpi_processor_unregister_performance(p, cpu);
- dprintk(PFX "invalid ACPI data\n");
- return (result);
-}
-#else
-static inline int centrino_cpu_init_acpi(struct cpufreq_policy *policy) { return -ENODEV; }
-static inline int centrino_cpu_early_init_acpi(void) { return 0; }
-#endif
-
static int centrino_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *cpu = &cpu_data[policy->cpu];
@@ -568,27 +353,25 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
if (cpu_has(cpu, X86_FEATURE_CONSTANT_TSC))
centrino_driver.flags |= CPUFREQ_CONST_LOOPS;
- if (centrino_cpu_init_acpi(policy)) {
- if (policy->cpu != 0)
- return -ENODEV;
+ if (policy->cpu != 0)
+ return -ENODEV;
- for (i = 0; i < N_IDS; i++)
- if (centrino_verify_cpu_id(cpu, &cpu_ids[i]))
- break;
+ for (i = 0; i < N_IDS; i++)
+ if (centrino_verify_cpu_id(cpu, &cpu_ids[i]))
+ break;
- if (i != N_IDS)
- centrino_cpu[policy->cpu] = &cpu_ids[i];
+ if (i != N_IDS)
+ centrino_cpu[policy->cpu] = &cpu_ids[i];
- if (!centrino_cpu[policy->cpu]) {
- dprintk("found unsupported CPU with "
- "Enhanced SpeedStep: send /proc/cpuinfo to "
- MAINTAINER "\n");
- return -ENODEV;
- }
+ if (!centrino_cpu[policy->cpu]) {
+ dprintk("found unsupported CPU with "
+ "Enhanced SpeedStep: send /proc/cpuinfo to "
+ MAINTAINER "\n");
+ return -ENODEV;
+ }
- if (centrino_cpu_init_table(policy)) {
- return -ENODEV;
- }
+ if (centrino_cpu_init_table(policy)) {
+ return -ENODEV;
}
/* Check to see if Enhanced SpeedStep is enabled, and try to
@@ -634,20 +417,6 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy)
cpufreq_frequency_table_put_attr(cpu);
-#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
- if (!centrino_model[cpu]->model_name) {
- static struct acpi_processor_performance *p;
-
- if (acpi_perf_data[cpu]) {
- p = acpi_perf_data[cpu];
- dprintk("unregistering and freeing ACPI data\n");
- acpi_processor_unregister_performance(p, cpu);
- kfree(centrino_model[cpu]->op_points);
- kfree(centrino_model[cpu]);
- }
- }
-#endif
-
centrino_model[cpu] = NULL;
return 0;
@@ -849,25 +618,12 @@ static int __init centrino_init(void)
if (!cpu_has(cpu, X86_FEATURE_EST))
return -ENODEV;
- centrino_cpu_early_init_acpi();
-
return cpufreq_register_driver(&centrino_driver);
}
static void __exit centrino_exit(void)
{
-#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
- unsigned int j;
-#endif
-
cpufreq_unregister_driver(&centrino_driver);
-
-#ifdef CONFIG_X86_SPEEDSTEP_CENTRINO_ACPI
- for_each_possible_cpu(j) {
- kfree(acpi_perf_data[j]);
- acpi_perf_data[j] = NULL;
- }
-#endif
}
MODULE_AUTHOR ("Jeremy Fitzhardinge <jeremy@goop.org>");
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
index 698f980eb443..a5b2346faf1f 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-ich.c
@@ -205,7 +205,6 @@ static unsigned int speedstep_detect_chipset (void)
* host brige. Abort on these systems.
*/
static struct pci_dev *hostbridge;
- u8 rev = 0;
hostbridge = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82815_MC,
@@ -216,8 +215,7 @@ static unsigned int speedstep_detect_chipset (void)
if (!hostbridge)
return 2; /* 2-M */
- pci_read_config_byte(hostbridge, PCI_REVISION_ID, &rev);
- if (rev < 5) {
+ if (hostbridge->revision < 5) {
dprintk("hostbridge does not support speedstep\n");
speedstep_chipset_dev = NULL;
pci_dev_put(hostbridge);
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index e88d2fba156b..122d2d75aa9f 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -4,7 +4,7 @@
#include <linux/pci.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/processor.h>
+#include <asm/processor-cyrix.h>
#include <asm/timer.h>
#include <asm/pci-direct.h>
#include <asm/tsc.h>
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index e5be819492ef..d5a456d27d82 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -4,7 +4,7 @@
* Changes:
* Venkatesh Pallipadi : Adding cache identification through cpuid(4)
* Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
- * Andi Kleen : CPUID4 emulation on AMD.
+ * Andi Kleen / Andreas Herrmann : CPUID4 emulation on AMD.
*/
#include <linux/init.h>
@@ -135,7 +135,7 @@ unsigned short num_cache_leaves;
/* AMD doesn't have CPUID4. Emulate it here to report the same
information to the user. This makes some assumptions about the machine:
- No L3, L2 not shared, no SMT etc. that is currently true on AMD CPUs.
+ L2 not shared, no SMT etc. that is currently true on AMD CPUs.
In theory the TLBs could be reported as fake type (they are in "dummy").
Maybe later */
@@ -159,13 +159,26 @@ union l2_cache {
unsigned val;
};
+union l3_cache {
+ struct {
+ unsigned line_size : 8;
+ unsigned lines_per_tag : 4;
+ unsigned assoc : 4;
+ unsigned res : 2;
+ unsigned size_encoded : 14;
+ };
+ unsigned val;
+};
+
static const unsigned short assocs[] = {
[1] = 1, [2] = 2, [4] = 4, [6] = 8,
- [8] = 16,
+ [8] = 16, [0xa] = 32, [0xb] = 48,
+ [0xc] = 64,
[0xf] = 0xffff // ??
- };
-static const unsigned char levels[] = { 1, 1, 2 };
-static const unsigned char types[] = { 1, 2, 3 };
+};
+
+static const unsigned char levels[] = { 1, 1, 2, 3 };
+static const unsigned char types[] = { 1, 2, 3, 3 };
static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
union _cpuid4_leaf_ebx *ebx,
@@ -175,37 +188,58 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
unsigned line_size, lines_per_tag, assoc, size_in_kb;
union l1_cache l1i, l1d;
union l2_cache l2;
+ union l3_cache l3;
+ union l1_cache *l1 = &l1d;
eax->full = 0;
ebx->full = 0;
ecx->full = 0;
cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
- cpuid(0x80000006, &dummy, &dummy, &l2.val, &dummy);
-
- if (leaf > 2 || !l1d.val || !l1i.val || !l2.val)
- return;
-
- eax->split.is_self_initializing = 1;
- eax->split.type = types[leaf];
- eax->split.level = levels[leaf];
- eax->split.num_threads_sharing = 0;
- eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
-
- if (leaf <= 1) {
- union l1_cache *l1 = leaf == 0 ? &l1d : &l1i;
+ cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
+
+ switch (leaf) {
+ case 1:
+ l1 = &l1i;
+ case 0:
+ if (!l1->val)
+ return;
assoc = l1->assoc;
line_size = l1->line_size;
lines_per_tag = l1->lines_per_tag;
size_in_kb = l1->size_in_kb;
- } else {
+ break;
+ case 2:
+ if (!l2.val)
+ return;
assoc = l2.assoc;
line_size = l2.line_size;
lines_per_tag = l2.lines_per_tag;
/* cpu_data has errata corrections for K7 applied */
size_in_kb = current_cpu_data.x86_cache_size;
+ break;
+ case 3:
+ if (!l3.val)
+ return;
+ assoc = l3.assoc;
+ line_size = l3.line_size;
+ lines_per_tag = l3.lines_per_tag;
+ size_in_kb = l3.size_encoded * 512;
+ break;
+ default:
+ return;
}
+ eax->split.is_self_initializing = 1;
+ eax->split.type = types[leaf];
+ eax->split.level = levels[leaf];
+ if (leaf == 3)
+ eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
+ else
+ eax->split.num_threads_sharing = 0;
+ eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
+
+
if (assoc == 0xf)
eax->split.is_fully_associative = 1;
ebx->split.coherency_line_size = line_size - 1;
@@ -239,8 +273,7 @@ static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_le
return 0;
}
-/* will only be called once; __init is safe here */
-static int __init find_num_cache_leaves(void)
+static int __cpuinit find_num_cache_leaves(void)
{
unsigned int eax, ebx, ecx, edx;
union _cpuid4_leaf_eax cache_eax;
@@ -710,7 +743,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
return retval;
}
-static void __cpuexit cache_remove_dev(struct sys_device * sys_dev)
+static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
{
unsigned int cpu = sys_dev->id;
unsigned long i;
diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
index 56cd485b127c..34c781eddee4 100644
--- a/arch/i386/kernel/cpu/mcheck/mce.c
+++ b/arch/i386/kernel/cpu/mcheck/mce.c
@@ -60,6 +60,20 @@ void mcheck_init(struct cpuinfo_x86 *c)
}
}
+static unsigned long old_cr4 __initdata;
+
+void __init stop_mce(void)
+{
+ old_cr4 = read_cr4();
+ clear_in_cr4(X86_CR4_MCE);
+}
+
+void __init restart_mce(void)
+{
+ if (old_cr4 & X86_CR4_MCE)
+ set_in_cr4(X86_CR4_MCE);
+}
+
static int __init mcheck_disable(char *str)
{
mce_disabled = 1;
diff --git a/arch/i386/kernel/cpu/mcheck/non-fatal.c b/arch/i386/kernel/cpu/mcheck/non-fatal.c
index 6b5d3518a1c0..bf39409b3838 100644
--- a/arch/i386/kernel/cpu/mcheck/non-fatal.c
+++ b/arch/i386/kernel/cpu/mcheck/non-fatal.c
@@ -57,7 +57,7 @@ static DECLARE_DELAYED_WORK(mce_work, mce_work_fn);
static void mce_work_fn(struct work_struct *work)
{
on_each_cpu(mce_checkregs, NULL, 1, 1);
- schedule_delayed_work(&mce_work, MCE_RATE);
+ schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
}
static int __init init_nonfatal_mce_checker(void)
@@ -82,7 +82,7 @@ static int __init init_nonfatal_mce_checker(void)
/*
* Check for non-fatal errors every MCE_RATE s
*/
- schedule_delayed_work(&mce_work, MCE_RATE);
+ schedule_delayed_work(&mce_work, round_jiffies_relative(MCE_RATE));
printk(KERN_INFO "Machine check exception polling timer started.\n");
return 0;
}
diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c
index 7ba7c3abd3a4..1203dc5ab87a 100644
--- a/arch/i386/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c
@@ -134,19 +134,21 @@ static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
int err;
sys_dev = get_cpu_sysdev(cpu);
- mutex_lock(&therm_cpu_lock);
switch (action) {
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
+ mutex_lock(&therm_cpu_lock);
err = thermal_throttle_add_dev(sys_dev);
+ mutex_unlock(&therm_cpu_lock);
WARN_ON(err);
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
+ mutex_lock(&therm_cpu_lock);
thermal_throttle_remove_dev(sys_dev);
+ mutex_unlock(&therm_cpu_lock);
break;
}
- mutex_unlock(&therm_cpu_lock);
return NOTIFY_OK;
}
diff --git a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c
index 1001f1e0fe6d..2287d4863a8a 100644
--- a/arch/i386/kernel/cpu/mtrr/cyrix.c
+++ b/arch/i386/kernel/cpu/mtrr/cyrix.c
@@ -3,6 +3,7 @@
#include <asm/mtrr.h>
#include <asm/msr.h>
#include <asm/io.h>
+#include <asm/processor-cyrix.h>
#include "mtrr.h"
int arr3_protected;
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index f6e46943e6ef..56f64e34829f 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -79,7 +79,7 @@ static void print_fixed(unsigned base, unsigned step, const mtrr_type*types)
}
/* Grab all of the MTRR state for this CPU into *state */
-void get_mtrr_state(void)
+void __init get_mtrr_state(void)
{
unsigned int i;
struct mtrr_var_range *vrs;
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 75dc6d5214bc..c48b6fea5ab4 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -643,7 +643,7 @@ static struct sysdev_driver mtrr_sysdev_driver = {
* initialized (i.e. before smp_init()).
*
*/
-__init void mtrr_bp_init(void)
+void __init mtrr_bp_init(void)
{
init_ifs();
diff --git a/arch/i386/kernel/cpu/mtrr/state.c b/arch/i386/kernel/cpu/mtrr/state.c
index 7b39a2f954d9..c9014ca4a575 100644
--- a/arch/i386/kernel/cpu/mtrr/state.c
+++ b/arch/i386/kernel/cpu/mtrr/state.c
@@ -3,6 +3,7 @@
#include <asm/io.h>
#include <asm/mtrr.h>
#include <asm/msr.h>
+#include <asm-i386/processor-cyrix.h>
#include "mtrr.h"
diff --git a/arch/i386/kernel/cpu/perfctr-watchdog.c b/arch/i386/kernel/cpu/perfctr-watchdog.c
index 4d26d514c56f..4be488e73bee 100644
--- a/arch/i386/kernel/cpu/perfctr-watchdog.c
+++ b/arch/i386/kernel/cpu/perfctr-watchdog.c
@@ -325,7 +325,7 @@ static struct wd_ops k7_wd_ops = {
.stop = single_msr_stop_watchdog,
.perfctr = MSR_K7_PERFCTR0,
.evntsel = MSR_K7_EVNTSEL0,
- .checkbit = 1ULL<<63,
+ .checkbit = 1ULL<<47,
};
/* Intel Model 6 (PPro+,P2,P3,P-M,Core1) */
@@ -346,7 +346,9 @@ static int setup_p6_watchdog(unsigned nmi_hz)
perfctr_msr = MSR_P6_PERFCTR0;
evntsel_msr = MSR_P6_EVNTSEL0;
- wrmsrl(perfctr_msr, 0UL);
+ /* KVM doesn't implement this MSR */
+ if (wrmsr_safe(perfctr_msr, 0, 0) < 0)
+ return 0;
evntsel = P6_EVNTSEL_INT
| P6_EVNTSEL_OS
@@ -599,8 +601,8 @@ static struct wd_ops intel_arch_wd_ops = {
.setup = setup_intel_arch_watchdog,
.rearm = p6_rearm,
.stop = single_msr_stop_watchdog,
- .perfctr = MSR_ARCH_PERFMON_PERFCTR0,
- .evntsel = MSR_ARCH_PERFMON_EVENTSEL0,
+ .perfctr = MSR_ARCH_PERFMON_PERFCTR1,
+ .evntsel = MSR_ARCH_PERFMON_EVENTSEL1,
};
static void probe_nmi_watchdog(void)
diff --git a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
index 89d91e6cc972..1e31b6caffb1 100644
--- a/arch/i386/kernel/cpu/proc.c
+++ b/arch/i386/kernel/cpu/proc.c
@@ -29,7 +29,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
- NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", "3dnowext", "3dnow",
+ NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm",
+ "3dnowext", "3dnow",
/* Transmeta-defined */
"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
@@ -40,8 +41,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
/* Other (Linux-defined) */
"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
NULL, NULL, NULL, NULL,
- "constant_tsc", "up", NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "constant_tsc", "up", NULL, "arch_perfmon",
+ "pebs", "bts", NULL, "sync_rdtsc",
+ "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Intel-defined (#2) */
@@ -57,9 +59,16 @@ static int show_cpuinfo(struct seq_file *m, void *v)
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* AMD-defined (#2) */
- "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8legacy", "abm",
- "sse4a", "misalignsse",
- "3dnowprefetch", "osvw", "ibs", NULL, NULL, NULL, NULL, NULL,
+ "lahf_lm", "cmp_legacy", "svm", "extapic", "cr8_legacy",
+ "altmovcr8", "abm", "sse4a",
+ "misalignsse", "3dnowprefetch",
+ "osvw", "ibs", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Auxiliary (Linux-defined) */
+ "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
diff --git a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
deleted file mode 100644
index 50076f22e90f..000000000000
--- a/arch/i386/kernel/cpu/rise.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-#include <asm/processor.h>
-
-#include "cpu.h"
-
-static void __cpuinit init_rise(struct cpuinfo_x86 *c)
-{
- printk("CPU: Rise iDragon");
- if (c->x86_model > 2)
- printk(" II");
- printk("\n");
-
- /* Unhide possibly hidden capability flags
- The mp6 iDragon family don't have MSRs.
- We switch on extra features with this cpuid weirdness: */
- __asm__ (
- "movl $0x6363452a, %%eax\n\t"
- "movl $0x3231206c, %%ecx\n\t"
- "movl $0x2a32313a, %%edx\n\t"
- "cpuid\n\t"
- "movl $0x63634523, %%eax\n\t"
- "movl $0x32315f6c, %%ecx\n\t"
- "movl $0x2333313a, %%edx\n\t"
- "cpuid\n\t" : : : "eax", "ebx", "ecx", "edx"
- );
- set_bit(X86_FEATURE_CX8, c->x86_capability);
-}
-
-static struct cpu_dev rise_cpu_dev __cpuinitdata = {
- .c_vendor = "Rise",
- .c_ident = { "RiseRiseRise" },
- .c_models = {
- { .vendor = X86_VENDOR_RISE, .family = 5, .model_names =
- {
- [0] = "iDragon",
- [2] = "iDragon",
- [8] = "iDragon II",
- [9] = "iDragon II"
- }
- },
- },
- .c_init = init_rise,
-};
-
-int __init rise_init_cpu(void)
-{
- cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev;
- return 0;
-}
-
diff --git a/arch/i386/kernel/e820.c b/arch/i386/kernel/e820.c
index 9645bb51f76a..e60cddbc4cfb 100644
--- a/arch/i386/kernel/e820.c
+++ b/arch/i386/kernel/e820.c
@@ -10,6 +10,7 @@
#include <linux/efi.h>
#include <linux/pfn.h>
#include <linux/uaccess.h>
+#include <linux/suspend.h>
#include <asm/pgtable.h>
#include <asm/page.h>
@@ -320,6 +321,37 @@ static int __init request_standard_resources(void)
subsys_initcall(request_standard_resources);
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+/**
+ * e820_mark_nosave_regions - Find the ranges of physical addresses that do not
+ * correspond to e820 RAM areas and mark the corresponding pages as nosave for
+ * hibernation.
+ *
+ * This function requires the e820 map to be sorted and without any
+ * overlapping entries and assumes the first e820 area to be RAM.
+ */
+void __init e820_mark_nosave_regions(void)
+{
+ int i;
+ unsigned long pfn;
+
+ pfn = PFN_DOWN(e820.map[0].addr + e820.map[0].size);
+ for (i = 1; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+
+ if (pfn < PFN_UP(ei->addr))
+ register_nosave_region(pfn, PFN_UP(ei->addr));
+
+ pfn = PFN_DOWN(ei->addr + ei->size);
+ if (ei->type != E820_RAM)
+ register_nosave_region(PFN_UP(ei->addr), pfn);
+
+ if (pfn >= max_low_pfn)
+ break;
+ }
+}
+#endif
+
void __init add_memory_region(unsigned long long start,
unsigned long long size, int type)
{
@@ -734,7 +766,7 @@ void __init print_memory_map(char *who)
case E820_NVS:
printk("(ACPI NVS)\n");
break;
- default: printk("type %lu\n", e820.map[i].type);
+ default: printk("type %u\n", e820.map[i].type);
break;
}
}
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index a1808022ea19..2452c6fbe992 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -278,7 +278,7 @@ void efi_memmap_walk(efi_freemem_callback_t callback, void *arg)
struct range {
unsigned long start;
unsigned long end;
- } prev, curr;
+ } uninitialized_var(prev), curr;
efi_memory_desc_t *md;
unsigned long start, end;
void *p;
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index 3c3c220488c9..a714d6b43506 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -409,8 +409,6 @@ restore_nocheck_notrace:
1: INTERRUPT_RETURN
.section .fixup,"ax"
iret_exc:
- TRACE_IRQS_ON
- ENABLE_INTERRUPTS(CLBR_NONE)
pushl $0 # no error code
pushl $do_iret_error
jmp error_code
@@ -1023,6 +1021,91 @@ ENTRY(kernel_thread_helper)
CFI_ENDPROC
ENDPROC(kernel_thread_helper)
+#ifdef CONFIG_XEN
+ENTRY(xen_hypervisor_callback)
+ CFI_STARTPROC
+ pushl $0
+ CFI_ADJUST_CFA_OFFSET 4
+ SAVE_ALL
+ TRACE_IRQS_OFF
+
+ /* Check to see if we got the event in the critical
+ region in xen_iret_direct, after we've reenabled
+ events and checked for pending events. This simulates
+ iret instruction's behaviour where it delivers a
+ pending interrupt when enabling interrupts. */
+ movl PT_EIP(%esp),%eax
+ cmpl $xen_iret_start_crit,%eax
+ jb 1f
+ cmpl $xen_iret_end_crit,%eax
+ jae 1f
+
+ call xen_iret_crit_fixup
+
+1: mov %esp, %eax
+ call xen_evtchn_do_upcall
+ jmp ret_from_intr
+ CFI_ENDPROC
+ENDPROC(xen_hypervisor_callback)
+
+# Hypervisor uses this for application faults while it executes.
+# We get here for two reasons:
+# 1. Fault while reloading DS, ES, FS or GS
+# 2. Fault while executing IRET
+# Category 1 we fix up by reattempting the load, and zeroing the segment
+# register if the load fails.
+# Category 2 we fix up by jumping to do_iret_error. We cannot use the
+# normal Linux return path in this case because if we use the IRET hypercall
+# to pop the stack frame we end up in an infinite loop of failsafe callbacks.
+# We distinguish between categories by maintaining a status value in EAX.
+ENTRY(xen_failsafe_callback)
+ CFI_STARTPROC
+ pushl %eax
+ CFI_ADJUST_CFA_OFFSET 4
+ movl $1,%eax
+1: mov 4(%esp),%ds
+2: mov 8(%esp),%es
+3: mov 12(%esp),%fs
+4: mov 16(%esp),%gs
+ testl %eax,%eax
+ popl %eax
+ CFI_ADJUST_CFA_OFFSET -4
+ lea 16(%esp),%esp
+ CFI_ADJUST_CFA_OFFSET -16
+ jz 5f
+ addl $16,%esp
+ jmp iret_exc # EAX != 0 => Category 2 (Bad IRET)
+5: pushl $0 # EAX == 0 => Category 1 (Bad segment)
+ CFI_ADJUST_CFA_OFFSET 4
+ SAVE_ALL
+ jmp ret_from_exception
+ CFI_ENDPROC
+
+.section .fixup,"ax"
+6: xorl %eax,%eax
+ movl %eax,4(%esp)
+ jmp 1b
+7: xorl %eax,%eax
+ movl %eax,8(%esp)
+ jmp 2b
+8: xorl %eax,%eax
+ movl %eax,12(%esp)
+ jmp 3b
+9: xorl %eax,%eax
+ movl %eax,16(%esp)
+ jmp 4b
+.previous
+.section __ex_table,"a"
+ .align 4
+ .long 1b,6b
+ .long 2b,7b
+ .long 3b,8b
+ .long 4b,9b
+.previous
+ENDPROC(xen_failsafe_callback)
+
+#endif /* CONFIG_XEN */
+
.section .rodata,"a"
#include "syscall_table.S"
diff --git a/arch/i386/kernel/geode.c b/arch/i386/kernel/geode.c
new file mode 100644
index 000000000000..41e8aec4c61d
--- /dev/null
+++ b/arch/i386/kernel/geode.c
@@ -0,0 +1,155 @@
+/*
+ * AMD Geode southbridge support code
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <asm/msr.h>
+#include <asm/geode.h>
+
+static struct {
+ char *name;
+ u32 msr;
+ int size;
+ u32 base;
+} lbars[] = {
+ { "geode-pms", MSR_LBAR_PMS, LBAR_PMS_SIZE, 0 },
+ { "geode-acpi", MSR_LBAR_ACPI, LBAR_ACPI_SIZE, 0 },
+ { "geode-gpio", MSR_LBAR_GPIO, LBAR_GPIO_SIZE, 0 },
+ { "geode-mfgpt", MSR_LBAR_MFGPT, LBAR_MFGPT_SIZE, 0 }
+};
+
+static void __init init_lbars(void)
+{
+ u32 lo, hi;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lbars); i++) {
+ rdmsr(lbars[i].msr, lo, hi);
+ if (hi & 0x01)
+ lbars[i].base = lo & 0x0000ffff;
+
+ if (lbars[i].base == 0)
+ printk(KERN_ERR "geode: Couldn't initialize '%s'\n",
+ lbars[i].name);
+ }
+}
+
+int geode_get_dev_base(unsigned int dev)
+{
+ BUG_ON(dev >= ARRAY_SIZE(lbars));
+ return lbars[dev].base;
+}
+EXPORT_SYMBOL_GPL(geode_get_dev_base);
+
+/* === GPIO API === */
+
+void geode_gpio_set(unsigned int gpio, unsigned int reg)
+{
+ u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+ if (!base)
+ return;
+
+ if (gpio < 16)
+ outl(1 << gpio, base + reg);
+ else
+ outl(1 << (gpio - 16), base + 0x80 + reg);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_set);
+
+void geode_gpio_clear(unsigned int gpio, unsigned int reg)
+{
+ u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+ if (!base)
+ return;
+
+ if (gpio < 16)
+ outl(1 << (gpio + 16), base + reg);
+ else
+ outl(1 << gpio, base + 0x80 + reg);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_clear);
+
+int geode_gpio_isset(unsigned int gpio, unsigned int reg)
+{
+ u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+
+ if (!base)
+ return 0;
+
+ if (gpio < 16)
+ return (inl(base + reg) & (1 << gpio)) ? 1 : 0;
+ else
+ return (inl(base + 0x80 + reg) & (1 << (gpio - 16))) ? 1 : 0;
+}
+EXPORT_SYMBOL_GPL(geode_gpio_isset);
+
+void geode_gpio_set_irq(unsigned int group, unsigned int irq)
+{
+ u32 lo, hi;
+
+ if (group > 7 || irq > 15)
+ return;
+
+ rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+
+ lo &= ~(0xF << (group * 4));
+ lo |= (irq & 0xF) << (group * 4);
+
+ wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_set_irq);
+
+void geode_gpio_setup_event(unsigned int gpio, int pair, int pme)
+{
+ u32 base = geode_get_dev_base(GEODE_DEV_GPIO);
+ u32 offset, shift, val;
+
+ if (gpio >= 24)
+ offset = GPIO_MAP_W;
+ else if (gpio >= 16)
+ offset = GPIO_MAP_Z;
+ else if (gpio >= 8)
+ offset = GPIO_MAP_Y;
+ else
+ offset = GPIO_MAP_X;
+
+ shift = (gpio % 8) * 4;
+
+ val = inl(base + offset);
+
+ /* Clear whatever was there before */
+ val &= ~(0xF << shift);
+
+ /* And set the new value */
+
+ val |= ((pair & 7) << shift);
+
+ /* Set the PME bit if this is a PME event */
+
+ if (pme)
+ val |= (1 << (shift + 3));
+
+ outl(val, base + offset);
+}
+EXPORT_SYMBOL_GPL(geode_gpio_setup_event);
+
+static int __init geode_southbridge_init(void)
+{
+ if (!is_geode())
+ return -ENODEV;
+
+ init_lbars();
+ return 0;
+}
+
+postcore_initcall(geode_southbridge_init);
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index f74dfc419b56..7c52b222207e 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -168,6 +168,12 @@ page_pde_offset = (__PAGE_OFFSET >> 20);
.section .init.text,"ax",@progbits
#endif
+ /* Do an early initialization of the fixmap area */
+ movl $(swapper_pg_dir - __PAGE_OFFSET), %edx
+ movl $(swapper_pg_pmd - __PAGE_OFFSET), %eax
+ addl $0x007, %eax /* 0x007 = PRESENT+RW+USER */
+ movl %eax, 4092(%edx)
+
#ifdef CONFIG_SMP
ENTRY(startup_32_smp)
cld
@@ -504,9 +510,12 @@ ENTRY(_stext)
/*
* BSS section
*/
-.section ".bss.page_aligned","w"
+.section ".bss.page_aligned","wa"
+ .align PAGE_SIZE_asm
ENTRY(swapper_pg_dir)
.fill 1024,4,0
+ENTRY(swapper_pg_pmd)
+ .fill 1024,4,0
ENTRY(empty_zero_page)
.fill 4096,1,0
@@ -530,6 +539,8 @@ fault_msg:
.ascii "Int %d: CR2 %p err %p EIP %p CS %p flags %p\n"
.asciz "Stack: %p %p %p %p %p %p %p %p\n"
+#include "../xen/xen-head.S"
+
/*
* The IDT and GDT 'descriptors' are a strange 48-bit object
* only used by the lidt and lgdt instructions. They are not
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
index 17d73459fc5f..533d4932bc79 100644
--- a/arch/i386/kernel/hpet.c
+++ b/arch/i386/kernel/hpet.c
@@ -5,6 +5,7 @@
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/pm.h>
+#include <linux/delay.h>
#include <asm/hpet.h>
#include <asm/io.h>
@@ -187,6 +188,10 @@ static void hpet_set_mode(enum clock_event_mode mode,
cfg &= ~HPET_TN_ENABLE;
hpet_writel(cfg, HPET_T0_CFG);
break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ hpet_enable_int();
+ break;
}
}
@@ -217,6 +222,7 @@ static struct clocksource clocksource_hpet = {
.mask = HPET_MASK,
.shift = HPET_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .resume = hpet_start_counter,
};
/*
@@ -226,7 +232,8 @@ int __init hpet_enable(void)
{
unsigned long id;
uint64_t hpet_freq;
- u64 tmp;
+ u64 tmp, start, now;
+ cycle_t t1;
if (!is_hpet_capable())
return 0;
@@ -273,6 +280,27 @@ int __init hpet_enable(void)
/* Start the counter */
hpet_start_counter();
+ /* Verify whether hpet counter works */
+ t1 = read_hpet();
+ rdtscll(start);
+
+ /*
+ * We don't know the TSC frequency yet, but waiting for
+ * 200000 TSC cycles is safe:
+ * 4 GHz == 50us
+ * 1 GHz == 200us
+ */
+ do {
+ rep_nop();
+ rdtscll(now);
+ } while ((now - start) < 200000UL);
+
+ if (t1 == read_hpet()) {
+ printk(KERN_WARNING
+ "HPET counter not counting. HPET disabled\n");
+ goto out_nohpet;
+ }
+
/* Initialize and register HPET clocksource
*
* hpet period is in femto seconds per cycle
@@ -291,7 +319,6 @@ int __init hpet_enable(void)
clocksource_register(&clocksource_hpet);
-
if (id & HPET_ID_LEGSUP) {
hpet_enable_int();
hpet_reserve_platform_timers(id);
@@ -299,7 +326,7 @@ int __init hpet_enable(void)
* Start hpet with the boot cpu mask and make it
* global after the IO_APIC has been initialized.
*/
- hpet_clockevent.cpumask =cpumask_of_cpu(0);
+ hpet_clockevent.cpumask = cpumask_of_cpu(smp_processor_id());
clockevents_register_device(&hpet_clockevent);
global_clock_event = &hpet_clockevent;
return 1;
@@ -524,68 +551,3 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
#endif
-
-
-/*
- * Suspend/resume part
- */
-
-#ifdef CONFIG_PM
-
-static int hpet_suspend(struct sys_device *sys_device, pm_message_t state)
-{
- unsigned long cfg = hpet_readl(HPET_CFG);
-
- cfg &= ~(HPET_CFG_ENABLE|HPET_CFG_LEGACY);
- hpet_writel(cfg, HPET_CFG);
-
- return 0;
-}
-
-static int hpet_resume(struct sys_device *sys_device)
-{
- unsigned int id;
-
- hpet_start_counter();
-
- id = hpet_readl(HPET_ID);
-
- if (id & HPET_ID_LEGSUP)
- hpet_enable_int();
-
- return 0;
-}
-
-static struct sysdev_class hpet_class = {
- set_kset_name("hpet"),
- .suspend = hpet_suspend,
- .resume = hpet_resume,
-};
-
-static struct sys_device hpet_device = {
- .id = 0,
- .cls = &hpet_class,
-};
-
-
-static __init int hpet_register_sysfs(void)
-{
- int err;
-
- if (!is_hpet_capable())
- return 0;
-
- err = sysdev_class_register(&hpet_class);
-
- if (!err) {
- err = sysdev_register(&hpet_device);
- if (err)
- sysdev_class_unregister(&hpet_class);
- }
-
- return err;
-}
-
-device_initcall(hpet_register_sysfs);
-
-#endif
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
index f8a3c4054c70..6d839f2f1b1a 100644
--- a/arch/i386/kernel/i8253.c
+++ b/arch/i386/kernel/i8253.c
@@ -3,18 +3,17 @@
*
*/
#include <linux/clockchips.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/jiffies.h>
-#include <linux/sysdev.h>
#include <linux/module.h>
-#include <linux/init.h>
+#include <linux/spinlock.h>
#include <asm/smp.h>
#include <asm/delay.h>
#include <asm/i8253.h>
#include <asm/io.h>
-
-#include "io_ports.h"
+#include <asm/timer.h>
DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
@@ -41,26 +40,27 @@ static void init_pit_timer(enum clock_event_mode mode,
case CLOCK_EVT_MODE_PERIODIC:
/* binary, mode 2, LSB/MSB, ch 0 */
outb_p(0x34, PIT_MODE);
- udelay(10);
outb_p(LATCH & 0xff , PIT_CH0); /* LSB */
- udelay(10);
outb(LATCH >> 8 , PIT_CH0); /* MSB */
break;
- /*
- * Avoid unnecessary state transitions, as it confuses
- * Geode / Cyrix based boxen.
- */
case CLOCK_EVT_MODE_SHUTDOWN:
- if (evt->mode == CLOCK_EVT_MODE_UNUSED)
- break;
case CLOCK_EVT_MODE_UNUSED:
- if (evt->mode == CLOCK_EVT_MODE_SHUTDOWN)
- break;
+ if (evt->mode == CLOCK_EVT_MODE_PERIODIC ||
+ evt->mode == CLOCK_EVT_MODE_ONESHOT) {
+ outb_p(0x30, PIT_MODE);
+ outb_p(0, PIT_CH0);
+ outb_p(0, PIT_CH0);
+ }
+ break;
+
case CLOCK_EVT_MODE_ONESHOT:
/* One shot setup */
outb_p(0x38, PIT_MODE);
- udelay(10);
+ break;
+
+ case CLOCK_EVT_MODE_RESUME:
+ /* Nothing to do here */
break;
}
spin_unlock_irqrestore(&i8253_lock, flags);
diff --git a/arch/i386/kernel/init_task.c b/arch/i386/kernel/init_task.c
index cff95d10a4d8..d26fc063a760 100644
--- a/arch/i386/kernel/init_task.c
+++ b/arch/i386/kernel/init_task.c
@@ -42,5 +42,5 @@ EXPORT_SYMBOL(init_task);
* per-CPU TSS segments. Threads are completely 'soft' on Linux,
* no more per-task TSS's.
*/
-DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 7f8b7af2b95f..893df8280756 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -353,14 +353,6 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
# include <linux/slab.h> /* kmalloc() */
# include <linux/timer.h> /* time_after() */
-#ifdef CONFIG_BALANCED_IRQ_DEBUG
-# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0)
-# define Dprintk(x...) do { TDprintk(x); } while (0)
-# else
-# define TDprintk(x...)
-# define Dprintk(x...)
-# endif
-
#define IRQBALANCE_CHECK_ARCH -999
#define MAX_BALANCED_IRQ_INTERVAL (5*HZ)
#define MIN_BALANCED_IRQ_INTERVAL (HZ/2)
@@ -443,7 +435,7 @@ static inline void balance_irq(int cpu, int irq)
static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
{
int i, j;
- Dprintk("Rotating IRQs among CPUs.\n");
+
for_each_online_cpu(i) {
for (j = 0; j < NR_IRQS; j++) {
if (!irq_desc[j].action)
@@ -560,19 +552,11 @@ tryanothercpu:
max_loaded = tmp_loaded; /* processor */
imbalance = (max_cpu_irq - min_cpu_irq) / 2;
- Dprintk("max_loaded cpu = %d\n", max_loaded);
- Dprintk("min_loaded cpu = %d\n", min_loaded);
- Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq);
- Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq);
- Dprintk("load imbalance = %lu\n", imbalance);
-
/* if imbalance is less than approx 10% of max load, then
* observe diminishing returns action. - quit
*/
- if (imbalance < (max_cpu_irq >> 3)) {
- Dprintk("Imbalance too trivial\n");
+ if (imbalance < (max_cpu_irq >> 3))
goto not_worth_the_effort;
- }
tryanotherirq:
/* if we select an IRQ to move that can't go where we want, then
@@ -629,9 +613,6 @@ tryanotherirq:
cpus_and(tmp, target_cpu_mask, allowed_mask);
if (!cpus_empty(tmp)) {
-
- Dprintk("irq = %d moved to cpu = %d\n",
- selected_irq, min_loaded);
/* mark for change destination */
set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
@@ -651,7 +632,6 @@ not_worth_the_effort:
*/
balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL,
balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);
- Dprintk("IRQ worth rotating not found\n");
return;
}
@@ -667,6 +647,7 @@ static int balanced_irq(void *unused)
set_pending_irq(i, cpumask_of_cpu(0));
}
+ set_freezable();
for ( ; ; ) {
time_remaining = schedule_timeout_interruptible(time_remaining);
try_to_freeze();
@@ -1901,7 +1882,7 @@ __setup("no_timer_check", notimercheck);
* - if this function detects that timer IRQs are defunct, then we fall
* back to ISA timer IRQs
*/
-int __init timer_irq_works(void)
+static int __init timer_irq_works(void)
{
unsigned long t1 = jiffies;
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index d2daf672f4a2..dd2b97fc00b2 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -21,7 +21,7 @@
#include <asm/apic.h>
#include <asm/uaccess.h>
-DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
+DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
EXPORT_PER_CPU_SYMBOL(irq_stat);
DEFINE_PER_CPU(struct pt_regs *, irq_regs);
@@ -149,15 +149,11 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
#ifdef CONFIG_4KSTACKS
-/*
- * These should really be __section__(".bss.page_aligned") as well, but
- * gcc's 3.0 and earlier don't handle that correctly.
- */
static char softirq_stack[NR_CPUS * THREAD_SIZE]
- __attribute__((__aligned__(THREAD_SIZE)));
+ __attribute__((__section__(".bss.page_aligned")));
static char hardirq_stack[NR_CPUS * THREAD_SIZE]
- __attribute__((__aligned__(THREAD_SIZE)));
+ __attribute__((__section__(".bss.page_aligned")));
/*
* allocate per-cpu stacks for hardirq and for softirq processing
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index dde828a333c3..448a50b1324c 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -35,6 +35,7 @@
#include <asm/cacheflush.h>
#include <asm/desc.h>
#include <asm/uaccess.h>
+#include <asm/alternative.h>
void jprobe_return_end(void);
@@ -169,16 +170,12 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
- *p->addr = BREAKPOINT_INSTRUCTION;
- flush_icache_range((unsigned long) p->addr,
- (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+ text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- *p->addr = p->opcode;
- flush_icache_range((unsigned long) p->addr,
- (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+ text_poke(p->addr, &p->opcode, 1);
}
void __kprobes arch_remove_kprobe(struct kprobe *p)
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index fba121f7973f..99beac7f96ce 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -295,7 +295,7 @@ static unsigned int
last_irq_sums [NR_CPUS],
alert_counter [NR_CPUS];
-void touch_nmi_watchdog (void)
+void touch_nmi_watchdog(void)
{
if (nmi_watchdog > 0) {
unsigned cpu;
@@ -304,8 +304,10 @@ void touch_nmi_watchdog (void)
* Just reset the alert counters, (other CPUs might be
* spinning on locks we hold):
*/
- for_each_present_cpu (cpu)
- alert_counter[cpu] = 0;
+ for_each_present_cpu(cpu) {
+ if (alert_counter[cpu])
+ alert_counter[cpu] = 0;
+ }
}
/*
@@ -351,7 +353,7 @@ __kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
* Take the local apic timer and PIT/HPET into account. We don't
* know which one is active, when we have highres/dyntick on
*/
- sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_irqs(0);
+ sum = per_cpu(irq_stat, cpu).apic_timer_irqs + kstat_cpu(cpu).irqs[0];
/* if the none of the timers isn't firing, this cpu isn't doing much */
if (!touched && last_irq_sums[cpu] == sum) {
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c
index faab09abca5e..ea962c0667d5 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -124,20 +124,28 @@ unsigned paravirt_patch_ignore(unsigned len)
return len;
}
+struct branch {
+ unsigned char opcode;
+ u32 delta;
+} __attribute__((packed));
+
unsigned paravirt_patch_call(void *target, u16 tgt_clobbers,
void *site, u16 site_clobbers,
unsigned len)
{
unsigned char *call = site;
unsigned long delta = (unsigned long)target - (unsigned long)(call+5);
+ struct branch b;
if (tgt_clobbers & ~site_clobbers)
return len; /* target would clobber too much for this site */
if (len < 5)
return len; /* call too long for patch site */
- *call++ = 0xe8; /* call */
- *(unsigned long *)call = delta;
+ b.opcode = 0xe8; /* call */
+ b.delta = delta;
+ BUILD_BUG_ON(sizeof(b) != 5);
+ text_poke(call, (unsigned char *)&b, 5);
return 5;
}
@@ -146,12 +154,14 @@ unsigned paravirt_patch_jmp(void *target, void *site, unsigned len)
{
unsigned char *jmp = site;
unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5);
+ struct branch b;
if (len < 5)
return len; /* call too long for patch site */
- *jmp++ = 0xe9; /* jmp */
- *(unsigned long *)jmp = delta;
+ b.opcode = 0xe9; /* jmp */
+ b.delta = delta;
+ text_poke(jmp, (unsigned char *)&b, 5);
return 5;
}
@@ -228,6 +238,41 @@ static int __init print_banner(void)
}
core_initcall(print_banner);
+static struct resource reserve_ioports = {
+ .start = 0,
+ .end = IO_SPACE_LIMIT,
+ .name = "paravirt-ioport",
+ .flags = IORESOURCE_IO | IORESOURCE_BUSY,
+};
+
+static struct resource reserve_iomem = {
+ .start = 0,
+ .end = -1,
+ .name = "paravirt-iomem",
+ .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
+};
+
+/*
+ * Reserve the whole legacy IO space to prevent any legacy drivers
+ * from wasting time probing for their hardware. This is a fairly
+ * brute-force approach to disabling all non-virtual drivers.
+ *
+ * Note that this must be called very early to have any effect.
+ */
+int paravirt_disable_iospace(void)
+{
+ int ret;
+
+ ret = request_resource(&ioport_resource, &reserve_ioports);
+ if (ret == 0) {
+ ret = request_resource(&iomem_resource, &reserve_iomem);
+ if (ret)
+ release_resource(&reserve_ioports);
+ }
+
+ return ret;
+}
+
struct paravirt_ops paravirt_ops = {
.name = "bare hardware",
.paravirt_enabled = 0,
@@ -267,7 +312,7 @@ struct paravirt_ops paravirt_ops = {
.write_msr = native_write_msr_safe,
.read_tsc = native_read_tsc,
.read_pmc = native_read_pmc,
- .get_scheduled_cycles = native_read_tsc,
+ .sched_clock = native_sched_clock,
.get_cpu_khz = native_calculate_cpu_khz,
.load_tr_desc = native_load_tr_desc,
.set_ldt = native_set_ldt,
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 06dfa65ad180..84664710b784 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -300,6 +300,7 @@ early_param("idle", idle_setup);
void show_regs(struct pt_regs * regs)
{
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L;
+ unsigned long d0, d1, d2, d3, d6, d7;
printk("\n");
printk("Pid: %d, comm: %20s\n", current->pid, current->comm);
@@ -324,6 +325,17 @@ void show_regs(struct pt_regs * regs)
cr3 = read_cr3();
cr4 = read_cr4_safe();
printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
+
+ get_debugreg(d0, 0);
+ get_debugreg(d1, 1);
+ get_debugreg(d2, 2);
+ get_debugreg(d3, 3);
+ printk("DR0: %08lx DR1: %08lx DR2: %08lx DR3: %08lx\n",
+ d0, d1, d2, d3);
+ get_debugreg(d6, 6);
+ get_debugreg(d7, 7);
+ printk("DR6: %08lx DR7: %08lx\n", d6, d7);
+
show_trace(NULL, regs, &regs->esp);
}
@@ -538,8 +550,31 @@ int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
return 1;
}
-static noinline void __switch_to_xtra(struct task_struct *next_p,
- struct tss_struct *tss)
+#ifdef CONFIG_SECCOMP
+void hard_disable_TSC(void)
+{
+ write_cr4(read_cr4() | X86_CR4_TSD);
+}
+void disable_TSC(void)
+{
+ preempt_disable();
+ if (!test_and_set_thread_flag(TIF_NOTSC))
+ /*
+ * Must flip the CPU state synchronously with
+ * TIF_NOTSC in the current running context.
+ */
+ hard_disable_TSC();
+ preempt_enable();
+}
+void hard_enable_TSC(void)
+{
+ write_cr4(read_cr4() & ~X86_CR4_TSD);
+}
+#endif /* CONFIG_SECCOMP */
+
+static noinline void
+__switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p,
+ struct tss_struct *tss)
{
struct thread_struct *next;
@@ -555,6 +590,17 @@ static noinline void __switch_to_xtra(struct task_struct *next_p,
set_debugreg(next->debugreg[7], 7);
}
+#ifdef CONFIG_SECCOMP
+ if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^
+ test_tsk_thread_flag(next_p, TIF_NOTSC)) {
+ /* prev and next are different */
+ if (test_tsk_thread_flag(next_p, TIF_NOTSC))
+ hard_disable_TSC();
+ else
+ hard_enable_TSC();
+ }
+#endif
+
if (!test_tsk_thread_flag(next_p, TIF_IO_BITMAP)) {
/*
* Disable the bitmap via an invalid offset. We still cache
@@ -586,33 +632,6 @@ static noinline void __switch_to_xtra(struct task_struct *next_p,
}
/*
- * This function selects if the context switch from prev to next
- * has to tweak the TSC disable bit in the cr4.
- */
-static inline void disable_tsc(struct task_struct *prev_p,
- struct task_struct *next_p)
-{
- struct thread_info *prev, *next;
-
- /*
- * gcc should eliminate the ->thread_info dereference if
- * has_secure_computing returns 0 at compile time (SECCOMP=n).
- */
- prev = task_thread_info(prev_p);
- next = task_thread_info(next_p);
-
- if (has_secure_computing(prev) || has_secure_computing(next)) {
- /* slow path here */
- if (has_secure_computing(prev) &&
- !has_secure_computing(next)) {
- write_cr4(read_cr4() & ~X86_CR4_TSD);
- } else if (!has_secure_computing(prev) &&
- has_secure_computing(next))
- write_cr4(read_cr4() | X86_CR4_TSD);
- }
-}
-
-/*
* switch_to(x,yn) should switch tasks from x to y.
*
* We fsave/fwait so that an exception goes off at the right time
@@ -689,11 +708,9 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
/*
* Now maybe handle debug registers and/or IO bitmaps
*/
- if (unlikely((task_thread_info(next_p)->flags & _TIF_WORK_CTXSW)
- || test_tsk_thread_flag(prev_p, TIF_IO_BITMAP)))
- __switch_to_xtra(next_p, tss);
-
- disable_tsc(prev_p, next_p);
+ if (unlikely(task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV ||
+ task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT))
+ __switch_to_xtra(prev_p, next_p, tss);
/*
* Leave lazy mode, flushing any hypercalls made here.
diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
index 0c0ceec5de00..0c8f00e69c4d 100644
--- a/arch/i386/kernel/ptrace.c
+++ b/arch/i386/kernel/ptrace.c
@@ -164,14 +164,22 @@ static unsigned long convert_eip_to_linear(struct task_struct *child, struct pt_
u32 *desc;
unsigned long base;
- down(&child->mm->context.sem);
- desc = child->mm->context.ldt + (seg & ~7);
- base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+ seg &= ~7UL;
- /* 16-bit code segment? */
- if (!((desc[1] >> 22) & 1))
- addr &= 0xffff;
- addr += base;
+ down(&child->mm->context.sem);
+ if (unlikely((seg >> 3) >= child->mm->context.size))
+ addr = -1L; /* bogus selector, access would fault */
+ else {
+ desc = child->mm->context.ldt + seg;
+ base = ((desc[0] >> 16) |
+ ((desc[1] & 0xff) << 16) |
+ (desc[1] & 0xff000000));
+
+ /* 16-bit code segment? */
+ if (!((desc[1] >> 22) & 1))
+ addr &= 0xffff;
+ addr += base;
+ }
up(&child->mm->context.sem);
}
return addr;
@@ -358,17 +366,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp, datap);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -395,10 +395,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index 5513f8d5b5be..0d796248866c 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -113,6 +113,15 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
},
},
+ { /* Handle problems with rebooting on Dell Optiplex 745's SFF*/
+ .callback = set_bios_reboot,
+ .ident = "Dell OptiPlex 745",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
+ DMI_MATCH(DMI_BOARD_NAME, "0WF810"),
+ },
+ },
{ /* Handle problems with rebooting on Dell 2400's */
.callback = set_bios_reboot,
.ident = "Dell PowerEdge 2400",
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 698c24fe482e..d474cd639bcb 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -102,19 +102,10 @@ static unsigned int highmem_pages = -1;
/*
* Setup options
*/
-struct drive_info_struct { char dummy[32]; } drive_info;
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_HD) || \
- defined(CONFIG_BLK_DEV_IDE_MODULE) || defined(CONFIG_BLK_DEV_HD_MODULE)
-EXPORT_SYMBOL(drive_info);
-#endif
struct screen_info screen_info;
EXPORT_SYMBOL(screen_info);
struct apm_info apm_info;
EXPORT_SYMBOL(apm_info);
-struct sys_desc_table_struct {
- unsigned short length;
- unsigned char table[0];
-};
struct edid_info edid_info;
EXPORT_SYMBOL_GPL(edid_info);
struct ist_info ist_info;
@@ -134,7 +125,7 @@ unsigned long saved_videomode;
static char __initdata command_line[COMMAND_LINE_SIZE];
-unsigned char __initdata boot_params[PARAM_SIZE];
+struct boot_params __initdata boot_params;
#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
struct edd edd;
@@ -282,18 +273,18 @@ unsigned long __init find_max_low_pfn(void)
printk(KERN_WARNING "Warning only %ldMB will be used.\n",
MAXMEM>>20);
if (max_pfn > MAX_NONPAE_PFN)
- printk(KERN_WARNING "Use a PAE enabled kernel.\n");
+ printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
else
printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
max_pfn = MAXMEM_PFN;
#else /* !CONFIG_HIGHMEM */
-#ifndef CONFIG_X86_PAE
+#ifndef CONFIG_HIGHMEM64G
if (max_pfn > MAX_NONPAE_PFN) {
max_pfn = MAX_NONPAE_PFN;
printk(KERN_WARNING "Warning only 4GB will be used.\n");
- printk(KERN_WARNING "Use a PAE enabled kernel.\n");
+ printk(KERN_WARNING "Use a HIGHMEM64G enabled kernel.\n");
}
-#endif /* !CONFIG_X86_PAE */
+#endif /* !CONFIG_HIGHMEM64G */
#endif /* !CONFIG_HIGHMEM */
} else {
if (highmem_pages == -1)
@@ -475,7 +466,7 @@ void __init setup_bootmem_allocator(void)
*
* This should all compile down to nothing when NUMA is off.
*/
-void __init remapped_pgdat_init(void)
+static void __init remapped_pgdat_init(void)
{
int nid;
@@ -528,7 +519,6 @@ void __init setup_arch(char **cmdline_p)
#endif
ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
- drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
edid_info = EDID_INFO;
apm_info.bios = APM_BIOS_INFO;
@@ -611,6 +601,8 @@ void __init setup_arch(char **cmdline_p)
* NOTE: at this point the bootmem allocator is fully available.
*/
+ paravirt_post_allocator_init();
+
dmi_scan_machine();
#ifdef CONFIG_X86_GENERICARCH
@@ -648,6 +640,7 @@ void __init setup_arch(char **cmdline_p)
#endif
e820_register_memory();
+ e820_mark_nosave_regions();
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index d574e38f0f77..f5dd85656c18 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -199,6 +199,13 @@ asmlinkage int sys_sigreturn(unsigned long __unused)
return eax;
badframe:
+ if (show_unhandled_signals && printk_ratelimit())
+ printk("%s%s[%d] bad frame in sigreturn frame:%p eip:%lx"
+ " esp:%lx oeax:%lx\n",
+ current->pid > 1 ? KERN_INFO : KERN_EMERG,
+ current->comm, current->pid, frame, regs->eip,
+ regs->esp, regs->orig_eax);
+
force_sig(SIGSEGV, current);
return 0;
}
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 6299c080f6e2..2d35d8502029 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -22,6 +22,7 @@
#include <asm/mtrr.h>
#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
#include <mach_apic.h>
/*
@@ -249,13 +250,13 @@ static unsigned long flush_va;
static DEFINE_SPINLOCK(tlbstate_lock);
/*
- * We cannot call mmdrop() because we are in interrupt context,
+ * We cannot call mmdrop() because we are in interrupt context,
* instead update mm->cpu_vm_mask.
*
* We need to reload %cr3 since the page tables may be going
* away from under us..
*/
-static inline void leave_mm (unsigned long cpu)
+void leave_mm(unsigned long cpu)
{
if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
BUG();
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 0b2954534b8e..e4f61d1c6248 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -148,7 +148,7 @@ void __init smp_alloc_memory(void)
* a given CPU
*/
-static void __cpuinit smp_store_cpu_info(int id)
+void __cpuinit smp_store_cpu_info(int id)
{
struct cpuinfo_x86 *c = cpu_data + id;
@@ -308,8 +308,7 @@ cpumask_t cpu_coregroup_map(int cpu)
/* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map;
-static inline void
-set_cpu_sibling_map(int cpu)
+void __cpuinit set_cpu_sibling_map(int cpu)
{
int i;
struct cpuinfo_x86 *c = cpu_data;
@@ -1144,8 +1143,7 @@ void __init native_smp_prepare_boot_cpu(void)
}
#ifdef CONFIG_HOTPLUG_CPU
-static void
-remove_siblinginfo(int cpu)
+void remove_siblinginfo(int cpu)
{
int sibling;
struct cpuinfo_x86 *c = cpu_data;
diff --git a/arch/i386/kernel/smpcommon.c b/arch/i386/kernel/smpcommon.c
index 1868ae18eb4d..bbfe85a0f699 100644
--- a/arch/i386/kernel/smpcommon.c
+++ b/arch/i386/kernel/smpcommon.c
@@ -47,7 +47,7 @@ int smp_call_function(void (*func) (void *info), void *info, int nonatomic,
EXPORT_SYMBOL(smp_call_function);
/**
- * smp_call_function_single - Run a function on another CPU
+ * smp_call_function_single - Run a function on a specific CPU
* @cpu: The target CPU. Cannot be the calling CPU.
* @func: The function to run. This must be fast and non-blocking.
* @info: An arbitrary pointer to pass to the function.
@@ -66,9 +66,11 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
int ret;
int me = get_cpu();
if (cpu == me) {
- WARN_ON(1);
+ local_irq_disable();
+ func(info);
+ local_irq_enable();
put_cpu();
- return -EBUSY;
+ return 0;
}
ret = smp_call_function_mask(cpumask_of_cpu(cpu), func, info, wait);
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index bf6adce52267..8344c70adf61 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -323,3 +323,4 @@ ENTRY(sys_call_table)
.long sys_signalfd
.long sys_timerfd
.long sys_eventfd
+ .long sys_fallocate
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
index ff4ee6f3326b..6deb159d08e0 100644
--- a/arch/i386/kernel/sysenter.c
+++ b/arch/i386/kernel/sysenter.c
@@ -336,7 +336,9 @@ struct vm_area_struct *get_gate_vma(struct task_struct *tsk)
int in_gate_area(struct task_struct *task, unsigned long addr)
{
- return 0;
+ const struct vm_area_struct *vma = get_gate_vma(task);
+
+ return vma && addr >= vma->vm_start && addr < vma->vm_end;
}
int in_gate_area_no_task(unsigned long addr)
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index a665df61f08c..19a6c678d02e 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -207,55 +207,9 @@ unsigned long read_persistent_clock(void)
return retval;
}
-static void sync_cmos_clock(unsigned long dummy);
-
-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-int no_sync_cmos_clock;
-
-static void sync_cmos_clock(unsigned long dummy)
-{
- struct timeval now, next;
- int fail = 1;
-
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- * This code is run on a timer. If the clock is set, that timer
- * may not expire at the correct time. Thus, we adjust...
- */
- if (!ntp_synced())
- /*
- * Not synced, exit, do not restart a timer (if one is
- * running, let it run out).
- */
- return;
-
- do_gettimeofday(&now);
- if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
- now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
- fail = set_rtc_mmss(now.tv_sec);
-
- next.tv_usec = USEC_AFTER - now.tv_usec;
- if (next.tv_usec <= 0)
- next.tv_usec += USEC_PER_SEC;
-
- if (!fail)
- next.tv_sec = 659;
- else
- next.tv_sec = 0;
-
- if (next.tv_usec >= USEC_PER_SEC) {
- next.tv_sec++;
- next.tv_usec -= USEC_PER_SEC;
- }
- mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
-}
-
-void notify_arch_cmos_timer(void)
+int update_persistent_clock(struct timespec now)
{
- if (!no_sync_cmos_clock)
- mod_timer(&sync_cmos_timer, jiffies + 1);
+ return set_rtc_mmss(now.tv_sec);
}
extern void (*late_time_init)(void);
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 90da0575fcff..cfffe3dd9e83 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -41,6 +41,10 @@
#include <linux/mca.h>
#endif
+#if defined(CONFIG_EDAC)
+#include <linux/edac.h>
+#endif
+
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -148,7 +152,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
if (!stack) {
unsigned long dummy;
stack = &dummy;
- if (task && task != current)
+ if (task != current)
stack = (unsigned long *)task->thread.esp;
}
@@ -207,6 +211,7 @@ static void print_trace_address(void *data, unsigned long addr)
{
printk("%s [<%08lx>] ", (char *)data, addr);
print_symbol("%s\n", addr);
+ touch_nmi_watchdog();
}
static struct stacktrace_ops print_trace_ops = {
@@ -390,7 +395,7 @@ void die(const char * str, struct pt_regs * regs, long err)
unsigned long esp;
unsigned short ss;
- report_bug(regs->eip);
+ report_bug(regs->eip, regs);
printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
#ifdef CONFIG_PREEMPT
@@ -433,6 +438,7 @@ void die(const char * str, struct pt_regs * regs, long err)
bust_spinlocks(0);
die.lock_owner = -1;
+ add_taint(TAINT_DIE);
spin_unlock_irqrestore(&die.lock, flags);
if (!regs)
@@ -517,10 +523,12 @@ fastcall void do_##name(struct pt_regs * regs, long error_code) \
do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \
}
-#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
+#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \
fastcall void do_##name(struct pt_regs * regs, long error_code) \
{ \
siginfo_t info; \
+ if (irq) \
+ local_irq_enable(); \
info.si_signo = signr; \
info.si_errno = 0; \
info.si_code = sicode; \
@@ -560,13 +568,13 @@ DO_VM86_ERROR( 3, SIGTRAP, "int3", int3)
#endif
DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow)
DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds)
-DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip)
+DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0)
DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun)
DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS)
DO_ERROR(11, SIGBUS, "segment not present", segment_not_present)
DO_ERROR(12, SIGBUS, "stack segment", stack_segment)
-DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0)
-DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0)
+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)
fastcall void __kprobes do_general_protection(struct pt_regs * regs,
long error_code)
@@ -610,6 +618,13 @@ fastcall void __kprobes do_general_protection(struct pt_regs * regs,
current->thread.error_code = error_code;
current->thread.trap_no = 13;
+ if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
+ printk_ratelimit())
+ printk(KERN_INFO
+ "%s[%d] general protection eip:%lx esp:%lx error:%lx\n",
+ current->comm, current->pid,
+ regs->eip, regs->esp, error_code);
+
force_sig(SIGSEGV, current);
return;
@@ -635,6 +650,14 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
"CPU %d.\n", reason, smp_processor_id());
printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
+
+#if defined(CONFIG_EDAC)
+ if(edac_handler_set()) {
+ edac_atomic_assert_error();
+ return;
+ }
+#endif
+
if (panic_on_unrecovered_nmi)
panic("NMI: Not continuing");
@@ -752,6 +775,8 @@ static __kprobes void default_do_nmi(struct pt_regs * regs)
reassert_nmi();
}
+static int ignore_nmis;
+
fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
{
int cpu;
@@ -762,11 +787,24 @@ fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
++nmi_count(cpu);
- default_do_nmi(regs);
+ if (!ignore_nmis)
+ default_do_nmi(regs);
nmi_exit();
}
+void stop_nmi(void)
+{
+ acpi_nmi_disable();
+ ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+ ignore_nmis--;
+ acpi_nmi_enable();
+}
+
#ifdef CONFIG_KPROBES
fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
{
@@ -1053,6 +1091,7 @@ asmlinkage void math_state_restore(void)
thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */
tsk->fpu_counter++;
}
+EXPORT_SYMBOL_GPL(math_state_restore);
#ifndef CONFIG_MATH_EMULATION
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index ea63a30ca3e8..debd7dbb4158 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -27,6 +27,7 @@ static int tsc_enabled;
* an extra value to store the TSC freq
*/
unsigned int tsc_khz;
+EXPORT_SYMBOL_GPL(tsc_khz);
int tsc_disable;
@@ -58,10 +59,11 @@ __setup("notsc", tsc_setup);
*/
static int tsc_unstable;
-static inline int check_tsc_unstable(void)
+int check_tsc_unstable(void)
{
return tsc_unstable;
}
+EXPORT_SYMBOL_GPL(check_tsc_unstable);
/* Accellerators for sched_clock()
* convert from cycles(64bits) => nanoseconds (64bits)
@@ -84,7 +86,7 @@ static inline int check_tsc_unstable(void)
*
* -johnstul@us.ibm.com "math is hard, lets go shopping!"
*/
-static unsigned long cyc2ns_scale __read_mostly;
+unsigned long cyc2ns_scale __read_mostly;
#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
@@ -93,15 +95,10 @@ static inline void set_cyc2ns_scale(unsigned long cpu_khz)
cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
}
-static inline unsigned long long cycles_2_ns(unsigned long long cyc)
-{
- return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
-
/*
* Scheduler clock - returns current time in nanosec units.
*/
-unsigned long long sched_clock(void)
+unsigned long long native_sched_clock(void)
{
unsigned long long this_offset;
@@ -118,12 +115,24 @@ unsigned long long sched_clock(void)
return (jiffies_64 - INITIAL_JIFFIES) * (1000000000 / HZ);
/* read the Time Stamp Counter: */
- get_scheduled_cycles(this_offset);
+ rdtscll(this_offset);
/* return the value in ns */
return cycles_2_ns(this_offset);
}
+/* We need to define a real function for sched_clock, to override the
+ weak default version */
+#ifdef CONFIG_PARAVIRT
+unsigned long long sched_clock(void)
+{
+ return paravirt_sched_clock();
+}
+#else
+unsigned long long sched_clock(void)
+ __attribute__((alias("native_sched_clock")));
+#endif
+
unsigned long native_calculate_cpu_khz(void)
{
unsigned long long start, end;
diff --git a/arch/i386/kernel/verify_cpu.S b/arch/i386/kernel/verify_cpu.S
deleted file mode 100644
index f1d1eacf4ab0..000000000000
--- a/arch/i386/kernel/verify_cpu.S
+++ /dev/null
@@ -1,94 +0,0 @@
-/* Check if CPU has some minimum CPUID bits
- This runs in 16bit mode so that the caller can still use the BIOS
- to output errors on the screen */
-#include <asm/cpufeature.h>
-#include <asm/msr.h>
-
-verify_cpu:
- pushfl # Save caller passed flags
- pushl $0 # Kill any dangerous flags
- popfl
-
-#if CONFIG_X86_MINIMUM_CPU_MODEL >= 4
- pushfl
- pop %eax
- orl $(1<<18),%eax # try setting AC
- push %eax
- popfl
- pushfl
- popl %eax
- testl $(1<<18),%eax
- jz bad
-#endif
-#if REQUIRED_MASK1 != 0
- pushfl # standard way to check for cpuid
- popl %eax
- movl %eax,%ebx
- xorl $0x200000,%eax
- pushl %eax
- popfl
- pushfl
- popl %eax
- cmpl %eax,%ebx
- pushfl # standard way to check for cpuid
- popl %eax
- movl %eax,%ebx
- xorl $0x200000,%eax
- pushl %eax
- popfl
- pushfl
- popl %eax
- cmpl %eax,%ebx
- jz bad # REQUIRED_MASK1 != 0 requires CPUID
-
- movl $0x0,%eax # See if cpuid 1 is implemented
- cpuid
- cmpl $0x1,%eax
- jb bad # no cpuid 1
-
-#if REQUIRED_MASK1 & NEED_CMPXCHG64
- /* Some VIA C3s need magic MSRs to enable CX64. Do this here */
- cmpl $0x746e6543,%ebx # Cent
- jne 1f
- cmpl $0x48727561,%edx # aurH
- jne 1f
- cmpl $0x736c7561,%ecx # auls
- jne 1f
- movl $1,%eax # check model
- cpuid
- movl %eax,%ebx
- shr $8,%ebx
- andl $0xf,%ebx
- cmp $6,%ebx # check family == 6
- jne 1f
- shr $4,%eax
- andl $0xf,%eax
- cmpl $6,%eax # check model >= 6
- jb 1f
- # assume models >= 6 all support this MSR
- movl $MSR_VIA_FCR,%ecx
- rdmsr
- orl $((1<<1)|(1<<7)),%eax # enable CMPXCHG64 and PGE
- wrmsr
-1:
-#endif
- movl $0x1,%eax # Does the cpu have what it takes
- cpuid
-
-#if CONFIG_X86_MINIMUM_CPU_MODEL > 4
-#error add proper model checking here
-#endif
-
- andl $REQUIRED_MASK1,%edx
- xorl $REQUIRED_MASK1,%edx
- jnz bad
-#endif /* REQUIRED_MASK1 */
-
- popfl
- xor %eax,%eax
- ret
-
-bad:
- popfl
- movl $1,%eax
- ret
diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c
index c12720d7cbc5..72042bb7ec94 100644
--- a/arch/i386/kernel/vmi.c
+++ b/arch/i386/kernel/vmi.c
@@ -362,7 +362,7 @@ static void *vmi_kmap_atomic_pte(struct page *page, enum km_type type)
}
#endif
-static void vmi_allocate_pt(u32 pfn)
+static void vmi_allocate_pt(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);
@@ -891,7 +891,7 @@ static inline int __init activate_vmi(void)
paravirt_ops.setup_boot_clock = vmi_time_bsp_init;
paravirt_ops.setup_secondary_clock = vmi_time_ap_init;
#endif
- paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles;
+ paravirt_ops.sched_clock = vmi_sched_clock;
paravirt_ops.get_cpu_khz = vmi_cpu_khz;
/* We have true wallclock functions; disable CMOS clock sync */
diff --git a/arch/i386/kernel/vmiclock.c b/arch/i386/kernel/vmiclock.c
index 26a37f8a8762..b1b5ab08b26e 100644
--- a/arch/i386/kernel/vmiclock.c
+++ b/arch/i386/kernel/vmiclock.c
@@ -32,6 +32,7 @@
#include <asm/apicdef.h>
#include <asm/apic.h>
#include <asm/timer.h>
+#include <asm/i8253.h>
#include <irq_vectors.h>
#include "io_ports.h"
@@ -64,10 +65,10 @@ int vmi_set_wallclock(unsigned long now)
return 0;
}
-/* paravirt_ops.get_scheduled_cycles = vmi_get_sched_cycles */
-unsigned long long vmi_get_sched_cycles(void)
+/* paravirt_ops.sched_clock = vmi_sched_clock */
+unsigned long long vmi_sched_clock(void)
{
- return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE);
+ return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
}
/* paravirt_ops.get_cpu_khz = vmi_cpu_khz */
@@ -142,6 +143,7 @@ static void vmi_timer_set_mode(enum clock_event_mode mode,
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_RESUME:
break;
case CLOCK_EVT_MODE_PERIODIC:
cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index aa87b06c7c82..7d72cce00529 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -60,7 +60,9 @@ SECTIONS
__stop___ex_table = .;
}
- BUG_TABLE
+ NOTES :text :note
+
+ BUG_TABLE :text
. = ALIGN(4);
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
@@ -88,6 +90,7 @@ SECTIONS
. = ALIGN(4096);
.data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+ *(.data.page_aligned)
*(.data.idt)
}
@@ -180,6 +183,7 @@ SECTIONS
.data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
__per_cpu_start = .;
*(.data.percpu)
+ *(.data.percpu.shared_aligned)
__per_cpu_end = .;
}
. = ALIGN(4096);
@@ -206,6 +210,4 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
-
- NOTES
}
diff --git a/arch/i386/kernel/vsyscall-note.S b/arch/i386/kernel/vsyscall-note.S
index d4b5be4f3d5f..07c0daf78237 100644
--- a/arch/i386/kernel/vsyscall-note.S
+++ b/arch/i386/kernel/vsyscall-note.S
@@ -3,23 +3,43 @@
* Here we can supply some information useful to userland.
*/
-#include <linux/uts.h>
#include <linux/version.h>
+#include <linux/elfnote.h>
-#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
- .section name, flags; \
- .balign 4; \
- .long 1f - 0f; /* name length */ \
- .long 3f - 2f; /* data length */ \
- .long type; /* note type */ \
-0: .asciz vendor; /* vendor name */ \
-1: .balign 4; \
-2:
+/* Ideally this would use UTS_NAME, but using a quoted string here
+ doesn't work. Remember to change this when changing the
+ kernel's name. */
+ELFNOTE_START(Linux, 0, "a")
+ .long LINUX_VERSION_CODE
+ELFNOTE_END
-#define ASM_ELF_NOTE_END \
-3: .balign 4; /* pad out section */ \
- .previous
+#ifdef CONFIG_XEN
+/*
+ * Add a special note telling glibc's dynamic linker a fake hardware
+ * flavor that it will use to choose the search path for libraries in the
+ * same way it uses real hardware capabilities like "mmx".
+ * We supply "nosegneg" as the fake capability, to indicate that we
+ * do not like negative offsets in instructions using segment overrides,
+ * since we implement those inefficiently. This makes it possible to
+ * install libraries optimized to avoid those access patterns in someplace
+ * like /lib/i686/tls/nosegneg. Note that an /etc/ld.so.conf.d/file
+ * corresponding to the bits here is needed to make ldconfig work right.
+ * It should contain:
+ * hwcap 1 nosegneg
+ * to match the mapping of bit to name that we give here.
+ *
+ * At runtime, the fake hardware feature will be considered to be present
+ * if its bit is set in the mask word. So, we start with the mask 0, and
+ * at boot time we set VDSO_NOTE_NONEGSEG_BIT if running under Xen.
+ */
- ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
- .long LINUX_VERSION_CODE
- ASM_ELF_NOTE_END
+#include "../xen/vdso.h" /* Defines VDSO_NOTE_NONEGSEG_BIT. */
+
+ .globl VDSO_NOTE_MASK
+ELFNOTE_START(GNU, 2, "a")
+ .long 1 /* ncaps */
+VDSO_NOTE_MASK:
+ .long 0 /* mask */
+ .byte VDSO_NOTE_NONEGSEG_BIT; .asciz "nosegneg" /* bit, name */
+ELFNOTE_END
+#endif
diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile
index 22d8ac5815f0..4d105fdfe817 100644
--- a/arch/i386/lib/Makefile
+++ b/arch/i386/lib/Makefile
@@ -4,7 +4,7 @@
lib-y = checksum.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \
- bitops.o semaphore.o
+ bitops.o semaphore.o string.o
lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
diff --git a/arch/i386/lib/string.c b/arch/i386/lib/string.c
new file mode 100644
index 000000000000..2c773fefa3dd
--- /dev/null
+++ b/arch/i386/lib/string.c
@@ -0,0 +1,257 @@
+/*
+ * Most of the string-functions are rather heavily hand-optimized,
+ * see especially strsep,strstr,str[c]spn. They should work, but are not
+ * very easy to understand. Everything is done entirely within the register
+ * set, making the functions fast and clean. String instructions have been
+ * used through-out, making for "slightly" unclear code :-)
+ *
+ * AK: On P4 and K7 using non string instruction implementations might be faster
+ * for large memory blocks. But most of them are unlikely to be used on large
+ * strings.
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+
+#ifdef __HAVE_ARCH_STRCPY
+char *strcpy(char * dest,const char *src)
+{
+ int d0, d1, d2;
+ asm volatile( "1:\tlodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b"
+ : "=&S" (d0), "=&D" (d1), "=&a" (d2)
+ :"0" (src),"1" (dest) : "memory");
+ return dest;
+}
+EXPORT_SYMBOL(strcpy);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCPY
+char *strncpy(char * dest,const char *src,size_t count)
+{
+ int d0, d1, d2, d3;
+ asm volatile( "1:\tdecl %2\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "rep\n\t"
+ "stosb\n"
+ "2:"
+ : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
+ :"0" (src),"1" (dest),"2" (count) : "memory");
+ return dest;
+}
+EXPORT_SYMBOL(strncpy);
+#endif
+
+#ifdef __HAVE_ARCH_STRCAT
+char *strcat(char * dest,const char * src)
+{
+ int d0, d1, d2, d3;
+ asm volatile( "repne\n\t"
+ "scasb\n\t"
+ "decl %1\n"
+ "1:\tlodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b"
+ : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+ : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu): "memory");
+ return dest;
+}
+EXPORT_SYMBOL(strcat);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCAT
+char *strncat(char * dest,const char * src,size_t count)
+{
+ int d0, d1, d2, d3;
+ asm volatile( "repne\n\t"
+ "scasb\n\t"
+ "decl %1\n\t"
+ "movl %8,%3\n"
+ "1:\tdecl %3\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "stosb\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n"
+ "2:\txorl %2,%2\n\t"
+ "stosb"
+ : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
+ : "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
+ : "memory");
+ return dest;
+}
+EXPORT_SYMBOL(strncat);
+#endif
+
+#ifdef __HAVE_ARCH_STRCMP
+int strcmp(const char * cs,const char * ct)
+{
+ int d0, d1;
+ int res;
+ asm volatile( "1:\tlodsb\n\t"
+ "scasb\n\t"
+ "jne 2f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "xorl %%eax,%%eax\n\t"
+ "jmp 3f\n"
+ "2:\tsbbl %%eax,%%eax\n\t"
+ "orb $1,%%al\n"
+ "3:"
+ :"=a" (res), "=&S" (d0), "=&D" (d1)
+ :"1" (cs),"2" (ct)
+ :"memory");
+ return res;
+}
+EXPORT_SYMBOL(strcmp);
+#endif
+
+#ifdef __HAVE_ARCH_STRNCMP
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+ int res;
+ int d0, d1, d2;
+ asm volatile( "1:\tdecl %3\n\t"
+ "js 2f\n\t"
+ "lodsb\n\t"
+ "scasb\n\t"
+ "jne 3f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n"
+ "2:\txorl %%eax,%%eax\n\t"
+ "jmp 4f\n"
+ "3:\tsbbl %%eax,%%eax\n\t"
+ "orb $1,%%al\n"
+ "4:"
+ :"=a" (res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+ :"1" (cs),"2" (ct),"3" (count)
+ :"memory");
+ return res;
+}
+EXPORT_SYMBOL(strncmp);
+#endif
+
+#ifdef __HAVE_ARCH_STRCHR
+char *strchr(const char * s, int c)
+{
+ int d0;
+ char * res;
+ asm volatile( "movb %%al,%%ah\n"
+ "1:\tlodsb\n\t"
+ "cmpb %%ah,%%al\n\t"
+ "je 2f\n\t"
+ "testb %%al,%%al\n\t"
+ "jne 1b\n\t"
+ "movl $1,%1\n"
+ "2:\tmovl %1,%0\n\t"
+ "decl %0"
+ :"=a" (res), "=&S" (d0)
+ :"1" (s),"0" (c)
+ :"memory");
+ return res;
+}
+EXPORT_SYMBOL(strchr);
+#endif
+
+#ifdef __HAVE_ARCH_STRRCHR
+char *strrchr(const char * s, int c)
+{
+ int d0, d1;
+ char * res;
+ asm volatile( "movb %%al,%%ah\n"
+ "1:\tlodsb\n\t"
+ "cmpb %%ah,%%al\n\t"
+ "jne 2f\n\t"
+ "leal -1(%%esi),%0\n"
+ "2:\ttestb %%al,%%al\n\t"
+ "jne 1b"
+ :"=g" (res), "=&S" (d0), "=&a" (d1)
+ :"0" (0),"1" (s),"2" (c)
+ :"memory");
+ return res;
+}
+EXPORT_SYMBOL(strrchr);
+#endif
+
+#ifdef __HAVE_ARCH_STRLEN
+size_t strlen(const char * s)
+{
+ int d0;
+ int res;
+ asm volatile( "repne\n\t"
+ "scasb\n\t"
+ "notl %0\n\t"
+ "decl %0"
+ :"=c" (res), "=&D" (d0)
+ :"1" (s),"a" (0), "0" (0xffffffffu)
+ :"memory");
+ return res;
+}
+EXPORT_SYMBOL(strlen);
+#endif
+
+#ifdef __HAVE_ARCH_MEMCHR
+void *memchr(const void *cs,int c,size_t count)
+{
+ int d0;
+ void *res;
+ if (!count)
+ return NULL;
+ asm volatile( "repne\n\t"
+ "scasb\n\t"
+ "je 1f\n\t"
+ "movl $1,%0\n"
+ "1:\tdecl %0"
+ :"=D" (res), "=&c" (d0)
+ :"a" (c),"0" (cs),"1" (count)
+ :"memory");
+ return res;
+}
+EXPORT_SYMBOL(memchr);
+#endif
+
+#ifdef __HAVE_ARCH_MEMSCAN
+void *memscan(void * addr, int c, size_t size)
+{
+ if (!size)
+ return addr;
+ asm volatile("repnz; scasb\n\t"
+ "jnz 1f\n\t"
+ "dec %%edi\n"
+ "1:"
+ : "=D" (addr), "=c" (size)
+ : "0" (addr), "1" (size), "a" (c)
+ : "memory");
+ return addr;
+}
+EXPORT_SYMBOL(memscan);
+#endif
+
+#ifdef __HAVE_ARCH_STRNLEN
+size_t strnlen(const char *s, size_t count)
+{
+ int d0;
+ int res;
+ asm volatile( "movl %2,%0\n\t"
+ "jmp 2f\n"
+ "1:\tcmpb $0,(%0)\n\t"
+ "je 3f\n\t"
+ "incl %0\n"
+ "2:\tdecl %1\n\t"
+ "cmpl $-1,%1\n\t"
+ "jne 1b\n"
+ "3:\tsubl %2,%0"
+ :"=a" (res), "=&d" (d0)
+ :"c" (s),"1" (count)
+ :"memory");
+ return res;
+}
+EXPORT_SYMBOL(strnlen);
+#endif
diff --git a/arch/i386/mach-generic/es7000.c b/arch/i386/mach-generic/es7000.c
index b47f951c0ec2..4742626f08c4 100644
--- a/arch/i386/mach-generic/es7000.c
+++ b/arch/i386/mach-generic/es7000.c
@@ -66,4 +66,4 @@ static int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
}
#endif
-struct genapic apic_es7000 = APIC_INIT("es7000", probe_es7000);
+struct genapic __initdata_refok apic_es7000 = APIC_INIT("es7000", probe_es7000);
diff --git a/arch/i386/mach-visws/traps.c b/arch/i386/mach-visws/traps.c
index 5199bd03254a..843b67acf43b 100644
--- a/arch/i386/mach-visws/traps.c
+++ b/arch/i386/mach-visws/traps.c
@@ -23,13 +23,13 @@ static __init void lithium_init(void)
set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
- (li_pcia_read16(PCI_DEVICE_ID) != PCI_VENDOR_ID_SGI_LITHIUM)) {
+ (li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
panic("This machine is not SGI Visual Workstation 320/540");
}
if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
- (li_pcib_read16(PCI_DEVICE_ID) != PCI_VENDOR_ID_SGI_LITHIUM)) {
+ (li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
panic("This machine is not SGI Visual Workstation 320/540");
}
diff --git a/arch/i386/mach-voyager/voyager_thread.c b/arch/i386/mach-voyager/voyager_thread.c
index b4b24e0e45e1..f9d595338159 100644
--- a/arch/i386/mach-voyager/voyager_thread.c
+++ b/arch/i386/mach-voyager/voyager_thread.c
@@ -52,7 +52,7 @@ execute(const char *string)
NULL,
};
- if ((ret = call_usermodehelper(argv[0], argv, envp, 1)) != 0) {
+ if ((ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC)) != 0) {
printk(KERN_ERR "Voyager failed to run \"%s\": %i\n",
string, ret);
}
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 1ecb3e43b523..01ffdd4964f0 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -283,6 +283,8 @@ static inline int vmalloc_fault(unsigned long address)
return 0;
}
+int show_unhandled_signals = 1;
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -303,6 +305,7 @@ fastcall void __kprobes do_page_fault(struct pt_regs *regs,
struct vm_area_struct * vma;
unsigned long address;
int write, si_code;
+ int fault;
/* get the address */
address = read_cr2();
@@ -422,20 +425,18 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- switch (handle_mm_fault(mm, vma, address, write)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
+ fault = handle_mm_fault(mm, vma, address, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
goto out_of_memory;
- default:
- BUG();
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
/*
* Did it hit the DOS screen memory VA from vm86 mode?
@@ -470,6 +471,14 @@ bad_area_nosemaphore:
if (is_prefetch(regs, address, error_code))
return;
+ if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+ printk_ratelimit()) {
+ printk("%s%s[%d]: segfault at %08lx eip %08lx "
+ "esp %08lx error %lx\n",
+ tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
+ tsk->comm, tsk->pid, address, regs->eip,
+ regs->esp, error_code);
+ }
tsk->thread.cr2 = address;
/* Kernel addresses are always protection faults */
tsk->thread.error_code = error_code | (address >= TASK_SIZE);
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 7135946d3663..c3b9905af2d5 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -87,7 +87,7 @@ static pte_t * __init one_page_table_init(pmd_t *pmd)
if (!(pmd_val(*pmd) & _PAGE_PRESENT)) {
pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
- paravirt_alloc_pt(__pa(page_table) >> PAGE_SHIFT);
+ paravirt_alloc_pt(&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));
}
@@ -471,8 +471,13 @@ void zap_low_mappings (void)
flush_tlb_all();
}
+int nx_enabled = 0;
+
+#ifdef CONFIG_X86_PAE
+
static int disable_nx __initdata = 0;
u64 __supported_pte_mask __read_mostly = ~_PAGE_NX;
+EXPORT_SYMBOL_GPL(__supported_pte_mask);
/*
* noexec = on|off
@@ -499,9 +504,6 @@ static int __init noexec_setup(char *str)
}
early_param("noexec", noexec_setup);
-int nx_enabled = 0;
-#ifdef CONFIG_X86_PAE
-
static void __init set_nx(void)
{
unsigned int v[4], l, h;
@@ -751,8 +753,7 @@ void __init pgtable_cache_init(void)
PTRS_PER_PMD*sizeof(pmd_t),
PTRS_PER_PMD*sizeof(pmd_t),
SLAB_PANIC,
- pmd_ctor,
- NULL);
+ pmd_ctor);
if (!SHARED_KERNEL_PMD) {
/* If we're in PAE mode and have a non-shared
kernel pmd, then the pgd size must be a
@@ -799,17 +800,9 @@ void mark_rodata_ro(void)
unsigned long start = PFN_ALIGN(_text);
unsigned long size = PFN_ALIGN(_etext) - start;
-#ifndef CONFIG_KPROBES
-#ifdef CONFIG_HOTPLUG_CPU
- /* It must still be possible to apply SMP alternatives. */
- if (num_possible_cpus() <= 1)
-#endif
- {
- change_page_attr(virt_to_page(start),
- size >> PAGE_SHIFT, PAGE_KERNEL_RX);
- printk("Write protecting the kernel text: %luk\n", size >> 10);
- }
-#endif
+ change_page_attr(virt_to_page(start),
+ size >> PAGE_SHIFT, PAGE_KERNEL_RX);
+ printk("Write protecting the kernel text: %luk\n", size >> 10);
start += size;
size = (unsigned long)__end_rodata - start;
change_page_attr(virt_to_page(start),
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
index fff08ae7b5ed..0b278315d737 100644
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -196,7 +196,7 @@ void iounmap(volatile void __iomem *addr)
/* Reset the direct mapping. Can block */
if ((p->flags >> 20) && p->phys_addr < virt_to_phys(high_memory) - 1) {
change_page_attr(virt_to_page(__va(p->phys_addr)),
- p->size >> PAGE_SHIFT,
+ get_vm_area_size(p) >> PAGE_SHIFT,
PAGE_KERNEL);
global_flush_tlb();
}
diff --git a/arch/i386/mm/pageattr.c b/arch/i386/mm/pageattr.c
index 2eb14a73be9c..8927222b3ab2 100644
--- a/arch/i386/mm/pageattr.c
+++ b/arch/i386/mm/pageattr.c
@@ -60,7 +60,7 @@ static struct page *split_large_page(unsigned long address, pgprot_t prot,
address = __pa(address);
addr = address & LARGE_PAGE_MASK;
pbase = (pte_t *)page_address(base);
- paravirt_alloc_pt(page_to_pfn(base));
+ paravirt_alloc_pt(&init_mm, page_to_pfn(base));
for (i = 0; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE) {
set_pte(&pbase[i], pfn_pte(addr >> PAGE_SHIFT,
addr == address ? prot : ref_prot));
@@ -82,7 +82,7 @@ static void flush_kernel_map(void *arg)
struct page *p;
/* High level code is not ready for clflush yet */
- if (0 && cpu_has_clflush) {
+ if (cpu_has_clflush) {
list_for_each_entry (p, lh, lru)
cache_flush_page(p);
} else if (boot_cpu_data.x86_model >= 4)
@@ -136,6 +136,12 @@ static inline void revert_page(struct page *kpte_page, unsigned long address)
ref_prot));
}
+static inline void save_page(struct page *kpte_page)
+{
+ if (!test_and_set_bit(PG_arch_1, &kpte_page->flags))
+ list_add(&kpte_page->lru, &df_list);
+}
+
static int
__change_page_attr(struct page *page, pgprot_t prot)
{
@@ -150,6 +156,9 @@ __change_page_attr(struct page *page, pgprot_t prot)
if (!kpte)
return -EINVAL;
kpte_page = virt_to_page(kpte);
+ BUG_ON(PageLRU(kpte_page));
+ BUG_ON(PageCompound(kpte_page));
+
if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) {
if (!pte_huge(*kpte)) {
set_pte_atomic(kpte, mk_pte(page, prot));
@@ -179,11 +188,11 @@ __change_page_attr(struct page *page, pgprot_t prot)
* time (not via split_large_page) and in turn we must not
* replace it with a largepage.
*/
+
+ save_page(kpte_page);
if (!PageReserved(kpte_page)) {
if (cpu_has_pse && (page_private(kpte_page) == 0)) {
- ClearPagePrivate(kpte_page);
paravirt_release_pt(page_to_pfn(kpte_page));
- list_add(&kpte_page->lru, &df_list);
revert_page(kpte_page, address);
}
}
@@ -236,6 +245,11 @@ void global_flush_tlb(void)
spin_unlock_irq(&cpa_lock);
flush_map(&l);
list_for_each_entry_safe(pg, next, &l, lru) {
+ list_del(&pg->lru);
+ clear_bit(PG_arch_1, &pg->flags);
+ if (PageReserved(pg) || !cpu_has_pse || page_private(pg) != 0)
+ continue;
+ ClearPagePrivate(pg);
__free_page(pg);
}
}
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
index 8d7c0864cc04..01437c46baae 100644
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -235,7 +235,7 @@ static inline void pgd_list_del(pgd_t *pgd)
#if (PTRS_PER_PMD == 1)
/* Non-PAE pgd constructor */
-void pgd_ctor(void *pgd)
+static void pgd_ctor(void *pgd)
{
unsigned long flags;
@@ -257,7 +257,7 @@ void pgd_ctor(void *pgd)
}
#else /* PTRS_PER_PMD > 1 */
/* PAE pgd constructor */
-void pgd_ctor(void *pgd)
+static void pgd_ctor(void *pgd)
{
/* PAE, kernel PMD may be shared */
@@ -276,7 +276,7 @@ void pgd_ctor(void *pgd)
}
#endif /* PTRS_PER_PMD */
-void pgd_dtor(void *pgd)
+static void pgd_dtor(void *pgd)
{
unsigned long flags; /* can be called from interrupt context */
diff --git a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
index b33aea845f58..bc8a44bddaa7 100644
--- a/arch/i386/pci/acpi.c
+++ b/arch/i386/pci/acpi.c
@@ -8,20 +8,42 @@
struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
{
struct pci_bus *bus;
+ struct pci_sysdata *sd;
+ int pxm;
+
+ /* Allocate per-root-bus (not per bus) arch-specific data.
+ * TODO: leak; this memory is never freed.
+ * It's arguable whether it's worth the trouble to care.
+ */
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+ return NULL;
+ }
if (domain != 0) {
printk(KERN_WARNING "PCI: Multiple domains not supported\n");
+ kfree(sd);
return NULL;
}
- bus = pcibios_scan_root(busnum);
+ sd->node = -1;
+
+ pxm = acpi_get_pxm(device->handle);
+#ifdef CONFIG_ACPI_NUMA
+ if (pxm >= 0)
+ sd->node = pxm_to_node(pxm);
+#endif
+
+ bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+ if (!bus)
+ kfree(sd);
+
#ifdef CONFIG_ACPI_NUMA
if (bus != NULL) {
- int pxm = acpi_get_pxm(device->handle);
if (pxm >= 0) {
- bus->sysdata = (void *)(unsigned long)pxm_to_node(pxm);
- printk("bus %d -> pxm %d -> node %ld\n",
- busnum, pxm, (long)(bus->sysdata));
+ printk("bus %d -> pxm %d -> node %d\n",
+ busnum, pxm, sd->node);
}
}
#endif
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index 3f78d4d8ecf3..85503deeda46 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -293,6 +293,7 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
struct pci_bus *bus = NULL;
+ struct pci_sysdata *sd;
dmi_check_system(pciprobe_dmi_table);
@@ -303,9 +304,19 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
}
}
+ /* Allocate per-root-bus (not per bus) arch-specific data.
+ * TODO: leak; this memory is never freed.
+ * It's arguable whether it's worth the trouble to care.
+ */
+ sd = kzalloc(sizeof(*sd), GFP_KERNEL);
+ if (!sd) {
+ printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum);
+ return NULL;
+ }
+
printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
- return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
+ return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
}
extern u8 pci_cache_line_size;
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index b95b42950ed4..e7306dbf6c42 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -118,12 +118,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, pci
static void pci_fixup_via_northbridge_bug(struct pci_dev *d)
{
u8 v;
- u8 revision;
int where = 0x55;
int mask = 0x1f; /* clear bits 5, 6, 7 by default */
- pci_read_config_byte(d, PCI_REVISION_ID, &revision);
-
if (d->device == PCI_DEVICE_ID_VIA_8367_0) {
/* fix pci bus latency issues resulted by NB bios error
it appears on bug free^Wreduced kt266x's bios forces
@@ -133,8 +130,8 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d)
where = 0x95; /* the memory write queue timer register is
different for the KT266x's: 0x95 not 0x55 */
} else if (d->device == PCI_DEVICE_ID_VIA_8363_0 &&
- (revision == VIA_8363_KL133_REVISION_ID ||
- revision == VIA_8363_KM133_REVISION_ID)) {
+ (d->revision == VIA_8363_KL133_REVISION_ID ||
+ d->revision == VIA_8363_KM133_REVISION_ID)) {
mask = 0x3f; /* clear only bits 6 and 7; clearing bit 5
causes screen corruption on the KL133/KM133 */
}
@@ -142,7 +139,7 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d)
pci_read_config_byte(d, where, &v);
if (v & ~mask) {
printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \
- d->device, revision, where, v, mask, v & mask);
+ d->device, d->revision, where, v, mask, v & mask);
v &= mask;
pci_write_config_byte(d, where, v);
}
diff --git a/arch/i386/pci/mmconfig-shared.c b/arch/i386/pci/mmconfig-shared.c
index c7cabeed4d7b..4df637e34f81 100644
--- a/arch/i386/pci/mmconfig-shared.c
+++ b/arch/i386/pci/mmconfig-shared.c
@@ -24,6 +24,9 @@
DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
+/* Indicate if the mmcfg resources have been placed into the resource table. */
+static int __initdata pci_mmcfg_resources_inserted;
+
/* K8 systems have some devices (typically in the builtin northbridge)
that are only accessible using type1
Normally this can be expressed in the MCFG by not listing them
@@ -170,7 +173,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
return name != NULL;
}
-static void __init pci_mmcfg_insert_resources(void)
+static void __init pci_mmcfg_insert_resources(unsigned long resource_flags)
{
#define PCI_MMCFG_RESOURCE_NAME_LEN 19
int i;
@@ -194,10 +197,13 @@ static void __init pci_mmcfg_insert_resources(void)
cfg->pci_segment);
res->start = cfg->address;
res->end = res->start + (num_buses << 20) - 1;
- res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+ res->flags = IORESOURCE_MEM | resource_flags;
insert_resource(&iomem_resource, res);
names += PCI_MMCFG_RESOURCE_NAME_LEN;
}
+
+ /* Mark that the resources have been inserted. */
+ pci_mmcfg_resources_inserted = 1;
}
static void __init pci_mmcfg_reject_broken(int type)
@@ -267,7 +273,43 @@ void __init pci_mmcfg_init(int type)
if (type == 1)
unreachable_devices();
if (known_bridge)
- pci_mmcfg_insert_resources();
+ pci_mmcfg_insert_resources(IORESOURCE_BUSY);
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
+ } else {
+ /*
+ * Signal not to attempt to insert mmcfg resources because
+ * the architecture mmcfg setup could not initialize.
+ */
+ pci_mmcfg_resources_inserted = 1;
}
}
+
+static int __init pci_mmcfg_late_insert_resources(void)
+{
+ /*
+ * If resources are already inserted or we are not using MMCONFIG,
+ * don't insert the resources.
+ */
+ if ((pci_mmcfg_resources_inserted == 1) ||
+ (pci_probe & PCI_PROBE_MMCONF) == 0 ||
+ (pci_mmcfg_config_num == 0) ||
+ (pci_mmcfg_config == NULL) ||
+ (pci_mmcfg_config[0].address == 0))
+ return 1;
+
+ /*
+ * Attempt to insert the mmcfg resources but not with the busy flag
+ * marked so it won't cause request errors when __request_region is
+ * called.
+ */
+ pci_mmcfg_insert_resources(0);
+
+ return 0;
+}
+
+/*
+ * Perform MMCONFIG resource insertion after PCI initialization to allow for
+ * misprogrammed MCFG tables that state larger sizes but actually conflict
+ * with other system resources.
+ */
+late_initcall(pci_mmcfg_late_insert_resources);
diff --git a/arch/i386/video/Makefile b/arch/i386/video/Makefile
new file mode 100644
index 000000000000..2c447c94adcc
--- /dev/null
+++ b/arch/i386/video/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FB) += fbdev.o
diff --git a/arch/i386/video/fbdev.c b/arch/i386/video/fbdev.c
new file mode 100644
index 000000000000..48fb38d7d2c0
--- /dev/null
+++ b/arch/i386/video/fbdev.c
@@ -0,0 +1,32 @@
+/*
+ * arch/i386/video/fbdev.c - i386 Framebuffer
+ *
+ * Copyright (C) 2007 Antonino Daplas <adaplas@gmail.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+#include <linux/fb.h>
+#include <linux/pci.h>
+
+int fb_is_primary_device(struct fb_info *info)
+{
+ struct device *device = info->device;
+ struct pci_dev *pci_dev = NULL;
+ struct resource *res = NULL;
+ int retval = 0;
+
+ if (device)
+ pci_dev = to_pci_dev(device);
+
+ if (pci_dev)
+ res = &pci_dev->resource[PCI_ROM_RESOURCE];
+
+ if (res && res->flags & IORESOURCE_ROM_SHADOW)
+ retval = 1;
+
+ return retval;
+}
+EXPORT_SYMBOL(fb_is_primary_device);
diff --git a/arch/i386/xen/Kconfig b/arch/i386/xen/Kconfig
new file mode 100644
index 000000000000..9df99e1885a4
--- /dev/null
+++ b/arch/i386/xen/Kconfig
@@ -0,0 +1,11 @@
+#
+# This Kconfig describes xen options
+#
+
+config XEN
+ bool "Enable support for Xen hypervisor"
+ depends on PARAVIRT && X86_CMPXCHG && X86_TSC && !NEED_MULTIPLE_NODES
+ help
+ This is the Linux Xen port. Enabling this will allow the
+ kernel to boot in a paravirtualized environment under the
+ Xen hypervisor.
diff --git a/arch/i386/xen/Makefile b/arch/i386/xen/Makefile
new file mode 100644
index 000000000000..343df246bd3e
--- /dev/null
+++ b/arch/i386/xen/Makefile
@@ -0,0 +1,4 @@
+obj-y := enlighten.o setup.o features.o multicalls.o mmu.o \
+ events.o time.o manage.o xen-asm.o
+
+obj-$(CONFIG_SMP) += smp.o
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c
new file mode 100644
index 000000000000..9a8c1181c001
--- /dev/null
+++ b/arch/i386/xen/enlighten.c
@@ -0,0 +1,1144 @@
+/*
+ * Core of Xen paravirt_ops implementation.
+ *
+ * This file contains the xen_paravirt_ops structure itself, and the
+ * implementations for:
+ * - privileged instructions
+ * - interrupt flags
+ * - segment operations
+ * - booting and setup
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/preempt.h>
+#include <linux/hardirq.h>
+#include <linux/percpu.h>
+#include <linux/delay.h>
+#include <linux/start_kernel.h>
+#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/page-flags.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/physdev.h>
+#include <xen/interface/vcpu.h>
+#include <xen/interface/sched.h>
+#include <xen/features.h>
+#include <xen/page.h>
+
+#include <asm/paravirt.h>
+#include <asm/page.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/fixmap.h>
+#include <asm/processor.h>
+#include <asm/setup.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/reboot.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+#include "multicalls.h"
+
+EXPORT_SYMBOL_GPL(hypercall_page);
+
+DEFINE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu);
+DEFINE_PER_CPU(struct vcpu_info, xen_vcpu_info);
+DEFINE_PER_CPU(unsigned long, xen_cr3);
+
+struct start_info *xen_start_info;
+EXPORT_SYMBOL_GPL(xen_start_info);
+
+static /* __initdata */ struct shared_info dummy_shared_info;
+
+/*
+ * Point at some empty memory to start with. We map the real shared_info
+ * page as soon as fixmap is up and running.
+ */
+struct shared_info *HYPERVISOR_shared_info = (void *)&dummy_shared_info;
+
+/*
+ * Flag to determine whether vcpu info placement is available on all
+ * VCPUs. We assume it is to start with, and then set it to zero on
+ * the first failure. This is because it can succeed on some VCPUs
+ * and not others, since it can involve hypervisor memory allocation,
+ * or because the guest failed to guarantee all the appropriate
+ * constraints on all VCPUs (ie buffer can't cross a page boundary).
+ *
+ * Note that any particular CPU may be using a placed vcpu structure,
+ * but we can only optimise if the all are.
+ *
+ * 0: not available, 1: available
+ */
+static int have_vcpu_info_placement = 1;
+
+static void __init xen_vcpu_setup(int cpu)
+{
+ struct vcpu_register_vcpu_info info;
+ int err;
+ struct vcpu_info *vcpup;
+
+ per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu];
+
+ if (!have_vcpu_info_placement)
+ return; /* already tested, not available */
+
+ vcpup = &per_cpu(xen_vcpu_info, cpu);
+
+ info.mfn = virt_to_mfn(vcpup);
+ info.offset = offset_in_page(vcpup);
+
+ printk(KERN_DEBUG "trying to map vcpu_info %d at %p, mfn %x, offset %d\n",
+ cpu, vcpup, info.mfn, info.offset);
+
+ /* Check to see if the hypervisor will put the vcpu_info
+ structure where we want it, which allows direct access via
+ a percpu-variable. */
+ err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, cpu, &info);
+
+ if (err) {
+ printk(KERN_DEBUG "register_vcpu_info failed: err=%d\n", err);
+ have_vcpu_info_placement = 0;
+ } else {
+ /* This cpu is using the registered vcpu info, even if
+ later ones fail to. */
+ per_cpu(xen_vcpu, cpu) = vcpup;
+
+ printk(KERN_DEBUG "cpu %d using vcpu_info at %p\n",
+ cpu, vcpup);
+ }
+}
+
+static void __init xen_banner(void)
+{
+ printk(KERN_INFO "Booting paravirtualized kernel on %s\n",
+ paravirt_ops.name);
+ printk(KERN_INFO "Hypervisor signature: %s\n", xen_start_info->magic);
+}
+
+static void xen_cpuid(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+ unsigned maskedx = ~0;
+
+ /*
+ * Mask out inconvenient features, to try and disable as many
+ * unsupported kernel subsystems as possible.
+ */
+ if (*eax == 1)
+ maskedx = ~((1 << X86_FEATURE_APIC) | /* disable APIC */
+ (1 << X86_FEATURE_ACPI) | /* disable ACPI */
+ (1 << X86_FEATURE_ACC)); /* thermal monitoring */
+
+ asm(XEN_EMULATE_PREFIX "cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (*eax), "2" (*ecx));
+ *edx &= maskedx;
+}
+
+static void xen_set_debugreg(int reg, unsigned long val)
+{
+ HYPERVISOR_set_debugreg(reg, val);
+}
+
+static unsigned long xen_get_debugreg(int reg)
+{
+ return HYPERVISOR_get_debugreg(reg);
+}
+
+static unsigned long xen_save_fl(void)
+{
+ struct vcpu_info *vcpu;
+ unsigned long flags;
+
+ vcpu = x86_read_percpu(xen_vcpu);
+
+ /* flag has opposite sense of mask */
+ flags = !vcpu->evtchn_upcall_mask;
+
+ /* convert to IF type flag
+ -0 -> 0x00000000
+ -1 -> 0xffffffff
+ */
+ return (-flags) & X86_EFLAGS_IF;
+}
+
+static void xen_restore_fl(unsigned long flags)
+{
+ struct vcpu_info *vcpu;
+
+ /* convert from IF type flag */
+ flags = !(flags & X86_EFLAGS_IF);
+
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = flags;
+ preempt_enable_no_resched();
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ if (flags == 0) {
+ preempt_check_resched();
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ force_evtchn_callback();
+ }
+}
+
+static void xen_irq_disable(void)
+{
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ x86_read_percpu(xen_vcpu)->evtchn_upcall_mask = 1;
+ preempt_enable_no_resched();
+}
+
+static void xen_irq_enable(void)
+{
+ struct vcpu_info *vcpu;
+
+ /* There's a one instruction preempt window here. We need to
+ make sure we're don't switch CPUs between getting the vcpu
+ pointer and updating the mask. */
+ preempt_disable();
+ vcpu = x86_read_percpu(xen_vcpu);
+ vcpu->evtchn_upcall_mask = 0;
+ preempt_enable_no_resched();
+
+ /* Doesn't matter if we get preempted here, because any
+ pending event will get dealt with anyway. */
+
+ barrier(); /* unmask then check (avoid races) */
+ if (unlikely(vcpu->evtchn_upcall_pending))
+ force_evtchn_callback();
+}
+
+static void xen_safe_halt(void)
+{
+ /* Blocking includes an implicit local_irq_enable(). */
+ if (HYPERVISOR_sched_op(SCHEDOP_block, 0) != 0)
+ BUG();
+}
+
+static void xen_halt(void)
+{
+ if (irqs_disabled())
+ HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
+ else
+ xen_safe_halt();
+}
+
+static void xen_set_lazy_mode(enum paravirt_lazy_mode mode)
+{
+ BUG_ON(preemptible());
+
+ switch (mode) {
+ case PARAVIRT_LAZY_NONE:
+ BUG_ON(x86_read_percpu(xen_lazy_mode) == PARAVIRT_LAZY_NONE);
+ break;
+
+ case PARAVIRT_LAZY_MMU:
+ case PARAVIRT_LAZY_CPU:
+ BUG_ON(x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE);
+ break;
+
+ case PARAVIRT_LAZY_FLUSH:
+ /* flush if necessary, but don't change state */
+ if (x86_read_percpu(xen_lazy_mode) != PARAVIRT_LAZY_NONE)
+ xen_mc_flush();
+ return;
+ }
+
+ xen_mc_flush();
+ x86_write_percpu(xen_lazy_mode, mode);
+}
+
+static unsigned long xen_store_tr(void)
+{
+ return 0;
+}
+
+static void xen_set_ldt(const void *addr, unsigned entries)
+{
+ unsigned long linear_addr = (unsigned long)addr;
+ struct mmuext_op *op;
+ struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_SET_LDT;
+ if (linear_addr) {
+ /* ldt my be vmalloced, use arbitrary_virt_to_machine */
+ xmaddr_t maddr;
+ maddr = arbitrary_virt_to_machine((unsigned long)addr);
+ linear_addr = (unsigned long)maddr.maddr;
+ }
+ op->arg1.linear_addr = linear_addr;
+ op->arg2.nr_ents = entries;
+
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_load_gdt(const struct Xgt_desc_struct *dtr)
+{
+ unsigned long *frames;
+ unsigned long va = dtr->address;
+ unsigned int size = dtr->size + 1;
+ unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ int f;
+ struct multicall_space mcs;
+
+ /* A GDT can be up to 64k in size, which corresponds to 8192
+ 8-byte entries, or 16 4k pages.. */
+
+ BUG_ON(size > 65536);
+ BUG_ON(va & ~PAGE_MASK);
+
+ mcs = xen_mc_entry(sizeof(*frames) * pages);
+ frames = mcs.args;
+
+ for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) {
+ frames[f] = virt_to_mfn(va);
+ make_lowmem_page_readonly((void *)va);
+ }
+
+ MULTI_set_gdt(mcs.mc, frames, size / sizeof(struct desc_struct));
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void load_TLS_descriptor(struct thread_struct *t,
+ unsigned int cpu, unsigned int i)
+{
+ struct desc_struct *gdt = get_cpu_gdt_table(cpu);
+ xmaddr_t maddr = virt_to_machine(&gdt[GDT_ENTRY_TLS_MIN+i]);
+ struct multicall_space mc = __xen_mc_entry(0);
+
+ MULTI_update_descriptor(mc.mc, maddr.maddr, t->tls_array[i]);
+}
+
+static void xen_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+ xen_mc_batch();
+
+ load_TLS_descriptor(t, cpu, 0);
+ load_TLS_descriptor(t, cpu, 1);
+ load_TLS_descriptor(t, cpu, 2);
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+
+ /*
+ * XXX sleazy hack: If we're being called in a lazy-cpu zone,
+ * it means we're in a context switch, and %gs has just been
+ * saved. This means we can zero it out to prevent faults on
+ * exit from the hypervisor if the next process has no %gs.
+ * Either way, it has been saved, and the new value will get
+ * loaded properly. This will go away as soon as Xen has been
+ * modified to not save/restore %gs for normal hypercalls.
+ */
+ if (xen_get_lazy_mode() == PARAVIRT_LAZY_CPU)
+ loadsegment(gs, 0);
+}
+
+static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum,
+ u32 low, u32 high)
+{
+ unsigned long lp = (unsigned long)&dt[entrynum];
+ xmaddr_t mach_lp = virt_to_machine(lp);
+ u64 entry = (u64)high << 32 | low;
+
+ preempt_disable();
+
+ xen_mc_flush();
+ if (HYPERVISOR_update_descriptor(mach_lp.maddr, entry))
+ BUG();
+
+ preempt_enable();
+}
+
+static int cvt_gate_to_trap(int vector, u32 low, u32 high,
+ struct trap_info *info)
+{
+ u8 type, dpl;
+
+ type = (high >> 8) & 0x1f;
+ dpl = (high >> 13) & 3;
+
+ if (type != 0xf && type != 0xe)
+ return 0;
+
+ info->vector = vector;
+ info->address = (high & 0xffff0000) | (low & 0x0000ffff);
+ info->cs = low >> 16;
+ info->flags = dpl;
+ /* interrupt gates clear IF */
+ if (type == 0xe)
+ info->flags |= 4;
+
+ return 1;
+}
+
+/* Locations of each CPU's IDT */
+static DEFINE_PER_CPU(struct Xgt_desc_struct, idt_desc);
+
+/* Set an IDT entry. If the entry is part of the current IDT, then
+ also update Xen. */
+static void xen_write_idt_entry(struct desc_struct *dt, int entrynum,
+ u32 low, u32 high)
+{
+ unsigned long p = (unsigned long)&dt[entrynum];
+ unsigned long start, end;
+
+ preempt_disable();
+
+ start = __get_cpu_var(idt_desc).address;
+ end = start + __get_cpu_var(idt_desc).size + 1;
+
+ xen_mc_flush();
+
+ write_dt_entry(dt, entrynum, low, high);
+
+ if (p >= start && (p + 8) <= end) {
+ struct trap_info info[2];
+
+ info[1].address = 0;
+
+ if (cvt_gate_to_trap(entrynum, low, high, &info[0]))
+ if (HYPERVISOR_set_trap_table(info))
+ BUG();
+ }
+
+ preempt_enable();
+}
+
+static void xen_convert_trap_info(const struct Xgt_desc_struct *desc,
+ struct trap_info *traps)
+{
+ unsigned in, out, count;
+
+ count = (desc->size+1) / 8;
+ BUG_ON(count > 256);
+
+ for (in = out = 0; in < count; in++) {
+ const u32 *entry = (u32 *)(desc->address + in * 8);
+
+ if (cvt_gate_to_trap(in, entry[0], entry[1], &traps[out]))
+ out++;
+ }
+ traps[out].address = 0;
+}
+
+void xen_copy_trap_info(struct trap_info *traps)
+{
+ const struct Xgt_desc_struct *desc = &__get_cpu_var(idt_desc);
+
+ xen_convert_trap_info(desc, traps);
+}
+
+/* Load a new IDT into Xen. In principle this can be per-CPU, so we
+ hold a spinlock to protect the static traps[] array (static because
+ it avoids allocation, and saves stack space). */
+static void xen_load_idt(const struct Xgt_desc_struct *desc)
+{
+ static DEFINE_SPINLOCK(lock);
+ static struct trap_info traps[257];
+
+ spin_lock(&lock);
+
+ __get_cpu_var(idt_desc) = *desc;
+
+ xen_convert_trap_info(desc, traps);
+
+ xen_mc_flush();
+ if (HYPERVISOR_set_trap_table(traps))
+ BUG();
+
+ spin_unlock(&lock);
+}
+
+/* Write a GDT descriptor entry. Ignore LDT descriptors, since
+ they're handled differently. */
+static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
+ u32 low, u32 high)
+{
+ preempt_disable();
+
+ switch ((high >> 8) & 0xff) {
+ case DESCTYPE_LDT:
+ case DESCTYPE_TSS:
+ /* ignore */
+ break;
+
+ default: {
+ xmaddr_t maddr = virt_to_machine(&dt[entry]);
+ u64 desc = (u64)high << 32 | low;
+
+ xen_mc_flush();
+ if (HYPERVISOR_update_descriptor(maddr.maddr, desc))
+ BUG();
+ }
+
+ }
+
+ preempt_enable();
+}
+
+static void xen_load_esp0(struct tss_struct *tss,
+ struct thread_struct *thread)
+{
+ struct multicall_space mcs = xen_mc_entry(0);
+ MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->esp0);
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+}
+
+static void xen_set_iopl_mask(unsigned mask)
+{
+ struct physdev_set_iopl set_iopl;
+
+ /* Force the change at ring 0. */
+ set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3;
+ HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+}
+
+static void xen_io_delay(void)
+{
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static unsigned long xen_apic_read(unsigned long reg)
+{
+ return 0;
+}
+
+static void xen_apic_write(unsigned long reg, unsigned long val)
+{
+ /* Warn to see if there's any stray references */
+ WARN_ON(1);
+}
+#endif
+
+static void xen_flush_tlb(void)
+{
+ struct mmuext_op *op;
+ struct multicall_space 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);
+}
+
+static void xen_flush_tlb_single(unsigned long addr)
+{
+ struct mmuext_op *op;
+ struct multicall_space 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);
+}
+
+static void xen_flush_tlb_others(const cpumask_t *cpus, struct mm_struct *mm,
+ unsigned long va)
+{
+ struct {
+ struct mmuext_op op;
+ cpumask_t mask;
+ } *args;
+ cpumask_t cpumask = *cpus;
+ struct multicall_space mcs;
+
+ /*
+ * A couple of (to be removed) sanity checks:
+ *
+ * - current CPU must not be in mask
+ * - mask must exist :)
+ */
+ BUG_ON(cpus_empty(cpumask));
+ BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+ BUG_ON(!mm);
+
+ /* If a CPU which we ran on has gone down, OK. */
+ cpus_and(cpumask, cpumask, cpu_online_map);
+ if (cpus_empty(cpumask))
+ return;
+
+ mcs = xen_mc_entry(sizeof(*args));
+ args = mcs.args;
+ args->mask = cpumask;
+ args->op.arg2.vcpumask = &args->mask;
+
+ if (va == TLB_FLUSH_ALL) {
+ args->op.cmd = MMUEXT_TLB_FLUSH_MULTI;
+ } else {
+ args->op.cmd = MMUEXT_INVLPG_MULTI;
+ args->op.arg1.linear_addr = va;
+ }
+
+ MULTI_mmuext_op(mcs.mc, &args->op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+}
+
+static void xen_write_cr2(unsigned long cr2)
+{
+ x86_read_percpu(xen_vcpu)->arch.cr2 = cr2;
+}
+
+static unsigned long xen_read_cr2(void)
+{
+ return x86_read_percpu(xen_vcpu)->arch.cr2;
+}
+
+static unsigned long xen_read_cr2_direct(void)
+{
+ return x86_read_percpu(xen_vcpu_info.arch.cr2);
+}
+
+static void xen_write_cr4(unsigned long cr4)
+{
+ /* never allow TSC to be disabled */
+ native_write_cr4(cr4 & ~X86_CR4_TSD);
+}
+
+static unsigned long xen_read_cr3(void)
+{
+ return x86_read_percpu(xen_cr3);
+}
+
+static void xen_write_cr3(unsigned long cr3)
+{
+ BUG_ON(preemptible());
+
+ if (cr3 == x86_read_percpu(xen_cr3)) {
+ /* just a simple tlb flush */
+ xen_flush_tlb();
+ return;
+ }
+
+ x86_write_percpu(xen_cr3, cr3);
+
+
+ {
+ struct mmuext_op *op;
+ struct multicall_space mcs = xen_mc_entry(sizeof(*op));
+ unsigned long mfn = pfn_to_mfn(PFN_DOWN(cr3));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_NEW_BASEPTR;
+ op->arg1.mfn = mfn;
+
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_CPU);
+ }
+}
+
+/* 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)
+{
+ BUG_ON(mem_map); /* should only be used early */
+ make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+}
+
+/* This needs to make sure the new pte page is pinned iff its being
+ attached to a pinned pagetable. */
+static void xen_alloc_pt(struct mm_struct *mm, u32 pfn)
+{
+ struct page *page = pfn_to_page(pfn);
+
+ if (PagePinned(virt_to_page(mm->pgd))) {
+ SetPagePinned(page);
+
+ if (!PageHighMem(page))
+ make_lowmem_page_readonly(__va(PFN_PHYS(pfn)));
+ else
+ /* make sure there are no stray mappings of
+ this page */
+ kmap_flush_unused();
+ }
+}
+
+/* This should never happen until we're OK to use struct page */
+static void xen_release_pt(u32 pfn)
+{
+ struct page *page = pfn_to_page(pfn);
+
+ if (PagePinned(page)) {
+ if (!PageHighMem(page))
+ make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
+ }
+}
+
+#ifdef CONFIG_HIGHPTE
+static void *xen_kmap_atomic_pte(struct page *page, enum km_type type)
+{
+ pgprot_t prot = PAGE_KERNEL;
+
+ if (PagePinned(page))
+ prot = PAGE_KERNEL_RO;
+
+ if (0 && PageHighMem(page))
+ printk("mapping highpte %lx type %d prot %s\n",
+ page_to_pfn(page), type,
+ (unsigned long)pgprot_val(prot) & _PAGE_RW ? "WRITE" : "READ");
+
+ return kmap_atomic_prot(page, type, prot);
+}
+#endif
+
+static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+{
+ /* If there's an existing pte, then don't allow _PAGE_RW to be set */
+ if (pte_val_ma(*ptep) & _PAGE_PRESENT)
+ pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
+ pte_val_ma(pte));
+
+ return pte;
+}
+
+/* Init-time set_pte while constructing initial pagetables, which
+ doesn't allow RO pagetable pages to be remapped RW */
+static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
+{
+ pte = mask_rw_pte(ptep, pte);
+
+ xen_set_pte(ptep, pte);
+}
+
+static __init void xen_pagetable_setup_start(pgd_t *base)
+{
+ pgd_t *xen_pgd = (pgd_t *)xen_start_info->pt_base;
+
+ /* special set_pte for pagetable initialization */
+ paravirt_ops.set_pte = xen_set_pte_init;
+
+ init_mm.pgd = base;
+ /*
+ * copy top-level of Xen-supplied pagetable into place. For
+ * !PAE we can use this as-is, but for PAE it is a stand-in
+ * while we copy the pmd pages.
+ */
+ memcpy(base, xen_pgd, PTRS_PER_PGD * sizeof(pgd_t));
+
+ if (PTRS_PER_PMD > 1) {
+ int i;
+ /*
+ * For PAE, need to allocate new pmds, rather than
+ * share Xen's, since Xen doesn't like pmd's being
+ * shared between address spaces.
+ */
+ for (i = 0; i < PTRS_PER_PGD; i++) {
+ if (pgd_val_ma(xen_pgd[i]) & _PAGE_PRESENT) {
+ pmd_t *pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+
+ memcpy(pmd, (void *)pgd_page_vaddr(xen_pgd[i]),
+ PAGE_SIZE);
+
+ make_lowmem_page_readonly(pmd);
+
+ set_pgd(&base[i], __pgd(1 + __pa(pmd)));
+ } else
+ pgd_clear(&base[i]);
+ }
+ }
+
+ /* make sure zero_page is mapped RO so we can use it in pagetables */
+ make_lowmem_page_readonly(empty_zero_page);
+ make_lowmem_page_readonly(base);
+ /*
+ * Switch to new pagetable. This is done before
+ * pagetable_init has done anything so that the new pages
+ * added to the table can be prepared properly for Xen.
+ */
+ xen_write_cr3(__pa(base));
+}
+
+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) */
+ paravirt_ops.alloc_pt = xen_alloc_pt;
+ paravirt_ops.set_pte = xen_set_pte;
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /*
+ * Create a mapping for the shared info page.
+ * Should be set_fixmap(), but shared_info is a machine
+ * address with no corresponding pseudo-phys address.
+ */
+ set_pte_mfn(fix_to_virt(FIX_PARAVIRT_BOOTMAP),
+ PFN_DOWN(xen_start_info->shared_info),
+ PAGE_KERNEL);
+
+ HYPERVISOR_shared_info =
+ (struct shared_info *)fix_to_virt(FIX_PARAVIRT_BOOTMAP);
+
+ } else
+ HYPERVISOR_shared_info =
+ (struct shared_info *)__va(xen_start_info->shared_info);
+
+ /* Actually pin the pagetable down, but we can't set PG_pinned
+ yet because the page structures don't exist yet. */
+ {
+ struct mmuext_op op;
+#ifdef CONFIG_X86_PAE
+ op.cmd = MMUEXT_PIN_L3_TABLE;
+#else
+ op.cmd = MMUEXT_PIN_L3_TABLE;
+#endif
+ op.arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(base)));
+ if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
+ BUG();
+ }
+}
+
+/* This is called once we have the cpu_possible_map */
+void __init xen_setup_vcpu_info_placement(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ xen_vcpu_setup(cpu);
+
+ /* xen_vcpu_setup managed to place the vcpu_info within the
+ percpu area for all cpus, so make use of it */
+ if (have_vcpu_info_placement) {
+ printk(KERN_INFO "Xen: using vcpu_info placement\n");
+
+ paravirt_ops.save_fl = xen_save_fl_direct;
+ paravirt_ops.restore_fl = xen_restore_fl_direct;
+ paravirt_ops.irq_disable = xen_irq_disable_direct;
+ paravirt_ops.irq_enable = xen_irq_enable_direct;
+ paravirt_ops.read_cr2 = xen_read_cr2_direct;
+ paravirt_ops.iret = xen_iret_direct;
+ }
+}
+
+static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len)
+{
+ char *start, *end, *reloc;
+ unsigned ret;
+
+ start = end = reloc = NULL;
+
+#define SITE(x) \
+ case PARAVIRT_PATCH(x): \
+ if (have_vcpu_info_placement) { \
+ start = (char *)xen_##x##_direct; \
+ end = xen_##x##_direct_end; \
+ reloc = xen_##x##_direct_reloc; \
+ } \
+ goto patch_site
+
+ switch (type) {
+ SITE(irq_enable);
+ SITE(irq_disable);
+ SITE(save_fl);
+ SITE(restore_fl);
+#undef SITE
+
+ patch_site:
+ if (start == NULL || (end-start) > len)
+ goto default_patch;
+
+ ret = paravirt_patch_insns(insns, len, start, end);
+
+ /* Note: because reloc is assigned from something that
+ appears to be an array, gcc assumes it's non-null,
+ but doesn't know its relationship with start and
+ end. */
+ if (reloc > start && reloc < end) {
+ int reloc_off = reloc - start;
+ long *relocp = (long *)(insns + reloc_off);
+ long delta = start - (char *)insns;
+
+ *relocp += delta;
+ }
+ break;
+
+ default_patch:
+ default:
+ ret = paravirt_patch_default(type, clobbers, insns, len);
+ break;
+ }
+
+ return ret;
+}
+
+static const struct paravirt_ops xen_paravirt_ops __initdata = {
+ .paravirt_enabled = 1,
+ .shared_kernel_pmd = 0,
+
+ .name = "Xen",
+ .banner = xen_banner,
+
+ .patch = xen_patch,
+
+ .memory_setup = xen_memory_setup,
+ .arch_setup = xen_arch_setup,
+ .init_IRQ = xen_init_IRQ,
+ .post_allocator_init = xen_mark_init_mm_pinned,
+
+ .time_init = xen_time_init,
+ .set_wallclock = xen_set_wallclock,
+ .get_wallclock = xen_get_wallclock,
+ .get_cpu_khz = xen_cpu_khz,
+ .sched_clock = xen_sched_clock,
+
+ .cpuid = xen_cpuid,
+
+ .set_debugreg = xen_set_debugreg,
+ .get_debugreg = xen_get_debugreg,
+
+ .clts = native_clts,
+
+ .read_cr0 = native_read_cr0,
+ .write_cr0 = native_write_cr0,
+
+ .read_cr2 = xen_read_cr2,
+ .write_cr2 = xen_write_cr2,
+
+ .read_cr3 = xen_read_cr3,
+ .write_cr3 = xen_write_cr3,
+
+ .read_cr4 = native_read_cr4,
+ .read_cr4_safe = native_read_cr4_safe,
+ .write_cr4 = xen_write_cr4,
+
+ .save_fl = xen_save_fl,
+ .restore_fl = xen_restore_fl,
+ .irq_disable = xen_irq_disable,
+ .irq_enable = xen_irq_enable,
+ .safe_halt = xen_safe_halt,
+ .halt = xen_halt,
+ .wbinvd = native_wbinvd,
+
+ .read_msr = native_read_msr_safe,
+ .write_msr = native_write_msr_safe,
+ .read_tsc = native_read_tsc,
+ .read_pmc = native_read_pmc,
+
+ .iret = (void *)&hypercall_page[__HYPERVISOR_iret],
+ .irq_enable_sysexit = NULL, /* never called */
+
+ .load_tr_desc = paravirt_nop,
+ .set_ldt = xen_set_ldt,
+ .load_gdt = xen_load_gdt,
+ .load_idt = xen_load_idt,
+ .load_tls = xen_load_tls,
+
+ .store_gdt = native_store_gdt,
+ .store_idt = native_store_idt,
+ .store_tr = xen_store_tr,
+
+ .write_ldt_entry = xen_write_ldt_entry,
+ .write_gdt_entry = xen_write_gdt_entry,
+ .write_idt_entry = xen_write_idt_entry,
+ .load_esp0 = xen_load_esp0,
+
+ .set_iopl_mask = xen_set_iopl_mask,
+ .io_delay = xen_io_delay,
+
+#ifdef CONFIG_X86_LOCAL_APIC
+ .apic_write = xen_apic_write,
+ .apic_write_atomic = xen_apic_write,
+ .apic_read = xen_apic_read,
+ .setup_boot_clock = paravirt_nop,
+ .setup_secondary_clock = paravirt_nop,
+ .startup_ipi_hook = paravirt_nop,
+#endif
+
+ .flush_tlb_user = xen_flush_tlb,
+ .flush_tlb_kernel = xen_flush_tlb,
+ .flush_tlb_single = xen_flush_tlb_single,
+ .flush_tlb_others = xen_flush_tlb_others,
+
+ .pte_update = paravirt_nop,
+ .pte_update_defer = paravirt_nop,
+
+ .pagetable_setup_start = xen_pagetable_setup_start,
+ .pagetable_setup_done = xen_pagetable_setup_done,
+
+ .alloc_pt = xen_alloc_pt_init,
+ .release_pt = xen_release_pt,
+ .alloc_pd = paravirt_nop,
+ .alloc_pd_clone = paravirt_nop,
+ .release_pd = paravirt_nop,
+
+#ifdef CONFIG_HIGHPTE
+ .kmap_atomic_pte = xen_kmap_atomic_pte,
+#endif
+
+ .set_pte = NULL, /* see xen_pagetable_setup_* */
+ .set_pte_at = xen_set_pte_at,
+ .set_pmd = xen_set_pmd,
+
+ .pte_val = xen_pte_val,
+ .pgd_val = xen_pgd_val,
+
+ .make_pte = xen_make_pte,
+ .make_pgd = xen_make_pgd,
+
+#ifdef CONFIG_X86_PAE
+ .set_pte_atomic = xen_set_pte_atomic,
+ .set_pte_present = xen_set_pte_at,
+ .set_pud = xen_set_pud,
+ .pte_clear = xen_pte_clear,
+ .pmd_clear = xen_pmd_clear,
+
+ .make_pmd = xen_make_pmd,
+ .pmd_val = xen_pmd_val,
+#endif /* PAE */
+
+ .activate_mm = xen_activate_mm,
+ .dup_mmap = xen_dup_mmap,
+ .exit_mmap = xen_exit_mmap,
+
+ .set_lazy_mode = xen_set_lazy_mode,
+};
+
+#ifdef CONFIG_SMP
+static const struct smp_ops xen_smp_ops __initdata = {
+ .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
+ .smp_prepare_cpus = xen_smp_prepare_cpus,
+ .cpu_up = xen_cpu_up,
+ .smp_cpus_done = xen_smp_cpus_done,
+
+ .smp_send_stop = xen_smp_send_stop,
+ .smp_send_reschedule = xen_smp_send_reschedule,
+ .smp_call_function_mask = xen_smp_call_function_mask,
+};
+#endif /* CONFIG_SMP */
+
+static void xen_reboot(int reason)
+{
+#ifdef CONFIG_SMP
+ smp_send_stop();
+#endif
+
+ if (HYPERVISOR_sched_op(SCHEDOP_shutdown, reason))
+ BUG();
+}
+
+static void xen_restart(char *msg)
+{
+ xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_emergency_restart(void)
+{
+ xen_reboot(SHUTDOWN_reboot);
+}
+
+static void xen_machine_halt(void)
+{
+ xen_reboot(SHUTDOWN_poweroff);
+}
+
+static void xen_crash_shutdown(struct pt_regs *regs)
+{
+ xen_reboot(SHUTDOWN_crash);
+}
+
+static const struct machine_ops __initdata xen_machine_ops = {
+ .restart = xen_restart,
+ .halt = xen_machine_halt,
+ .power_off = xen_machine_halt,
+ .shutdown = xen_machine_halt,
+ .crash_shutdown = xen_crash_shutdown,
+ .emergency_restart = xen_emergency_restart,
+};
+
+
+/* First C function to be called on Xen boot */
+asmlinkage void __init xen_start_kernel(void)
+{
+ pgd_t *pgd;
+
+ if (!xen_start_info)
+ return;
+
+ BUG_ON(memcmp(xen_start_info->magic, "xen-3.0", 7) != 0);
+
+ /* Install Xen paravirt ops */
+ paravirt_ops = xen_paravirt_ops;
+ machine_ops = xen_machine_ops;
+
+#ifdef CONFIG_SMP
+ smp_ops = xen_smp_ops;
+#endif
+
+ xen_setup_features();
+
+ /* Get mfn list */
+ if (!xen_feature(XENFEAT_auto_translated_physmap))
+ phys_to_machine_mapping = (unsigned long *)xen_start_info->mfn_list;
+
+ pgd = (pgd_t *)xen_start_info->pt_base;
+
+ init_pg_tables_end = __pa(pgd) + xen_start_info->nr_pt_frames*PAGE_SIZE;
+
+ init_mm.pgd = pgd; /* use the Xen pagetables to start */
+
+ /* keep using Xen gdt for now; no urgent need to change it */
+
+ x86_write_percpu(xen_cr3, __pa(pgd));
+
+#ifdef CONFIG_SMP
+ /* Don't do the full vcpu_info placement stuff until we have a
+ possible map. */
+ per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
+#else
+ /* May as well do it now, since there's no good time to call
+ it later on UP. */
+ xen_setup_vcpu_info_placement();
+#endif
+
+ paravirt_ops.kernel_rpl = 1;
+ if (xen_feature(XENFEAT_supervisor_mode_kernel))
+ paravirt_ops.kernel_rpl = 0;
+
+ /* set the limit of our address space */
+ reserve_top_address(-HYPERVISOR_VIRT_START + 2 * PAGE_SIZE);
+
+ /* set up basic CPUID stuff */
+ cpu_detect(&new_cpu_data);
+ new_cpu_data.hard_math = 1;
+ new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+ /* Poke various useful things into boot_params */
+ LOADER_TYPE = (9 << 4) | 0;
+ INITRD_START = xen_start_info->mod_start ? __pa(xen_start_info->mod_start) : 0;
+ INITRD_SIZE = xen_start_info->mod_len;
+
+ /* Start the world */
+ start_kernel();
+}
diff --git a/arch/i386/xen/events.c b/arch/i386/xen/events.c
new file mode 100644
index 000000000000..da1b173547a1
--- /dev/null
+++ b/arch/i386/xen/events.c
@@ -0,0 +1,591 @@
+/*
+ * Xen event channels
+ *
+ * Xen models interrupts with abstract event channels. Because each
+ * domain gets 1024 event channels, but NR_IRQ is not that large, we
+ * must dynamically map irqs<->event channels. The event channels
+ * interface with the rest of the kernel by defining a xen interrupt
+ * chip. When an event is recieved, it is mapped to an irq and sent
+ * through the normal interrupt processing path.
+ *
+ * There are four kinds of events which can be mapped to an event
+ * channel:
+ *
+ * 1. Inter-domain notifications. This includes all the virtual
+ * device events, since they're driven by front-ends in another domain
+ * (typically dom0).
+ * 2. VIRQs, typically used for timers. These are per-cpu events.
+ * 3. IPIs.
+ * 4. Hardware interrupts. Not supported at present.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+#include <asm/sync_bitops.h>
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#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.
+ */
+static DEFINE_SPINLOCK(irq_mapping_update_lock);
+
+/* IRQ <-> VIRQ mapping. */
+static DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
+
+/* IRQ <-> IPI mapping */
+static DEFINE_PER_CPU(int, ipi_to_irq[XEN_NR_IPIS]) = {[0 ... XEN_NR_IPIS-1] = -1};
+
+/* Packed IRQ information: binding type, sub-type index, and event channel. */
+struct packed_irq
+{
+ unsigned short evtchn;
+ unsigned char index;
+ unsigned char type;
+};
+
+static struct packed_irq irq_info[NR_IRQS];
+
+/* Binding types. */
+enum {
+ IRQT_UNBOUND,
+ IRQT_PIRQ,
+ IRQT_VIRQ,
+ IRQT_IPI,
+ IRQT_EVTCHN
+};
+
+/* Convenient shorthand for packed representation of an unbound IRQ. */
+#define IRQ_UNBOUND mk_irq_info(IRQT_UNBOUND, 0, 0)
+
+static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
+ [0 ... NR_EVENT_CHANNELS-1] = -1
+};
+static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
+static u8 cpu_evtchn[NR_EVENT_CHANNELS];
+
+/* Reference counts for bindings to IRQs. */
+static int irq_bindcount[NR_IRQS];
+
+/* Xen will never allocate port zero for any purpose. */
+#define VALID_EVTCHN(chn) ((chn) != 0)
+
+/*
+ * Force a proper event-channel callback from Xen after clearing the
+ * callback mask. We do this in a very simple manner, by making a call
+ * down into Xen. The pending flag will be checked by Xen on return.
+ */
+void force_evtchn_callback(void)
+{
+ (void)HYPERVISOR_xen_version(0, NULL);
+}
+EXPORT_SYMBOL_GPL(force_evtchn_callback);
+
+static struct irq_chip xen_dynamic_chip;
+
+/* Constructor for packed IRQ information. */
+static inline struct packed_irq mk_irq_info(u32 type, u32 index, u32 evtchn)
+{
+ return (struct packed_irq) { evtchn, index, type };
+}
+
+/*
+ * Accessors for packed IRQ information.
+ */
+static inline unsigned int evtchn_from_irq(int irq)
+{
+ return irq_info[irq].evtchn;
+}
+
+static inline unsigned int index_from_irq(int irq)
+{
+ return irq_info[irq].index;
+}
+
+static inline unsigned int type_from_irq(int irq)
+{
+ return irq_info[irq].type;
+}
+
+static inline unsigned long active_evtchns(unsigned int cpu,
+ struct shared_info *sh,
+ unsigned int idx)
+{
+ return (sh->evtchn_pending[idx] &
+ cpu_evtchn_mask[cpu][idx] &
+ ~sh->evtchn_mask[idx]);
+}
+
+static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
+{
+ int irq = evtchn_to_irq[chn];
+
+ BUG_ON(irq == -1);
+#ifdef CONFIG_SMP
+ irq_desc[irq].affinity = cpumask_of_cpu(cpu);
+#endif
+
+ __clear_bit(chn, cpu_evtchn_mask[cpu_evtchn[chn]]);
+ __set_bit(chn, cpu_evtchn_mask[cpu]);
+
+ cpu_evtchn[chn] = cpu;
+}
+
+static void init_evtchn_cpu_bindings(void)
+{
+#ifdef CONFIG_SMP
+ int i;
+ /* By default all event channels notify CPU#0. */
+ for (i = 0; i < NR_IRQS; i++)
+ irq_desc[i].affinity = cpumask_of_cpu(0);
+#endif
+
+ memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
+ memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
+}
+
+static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
+{
+ return cpu_evtchn[evtchn];
+}
+
+static inline void clear_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_clear_bit(port, &s->evtchn_pending[0]);
+}
+
+static inline void set_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_set_bit(port, &s->evtchn_pending[0]);
+}
+
+
+/**
+ * notify_remote_via_irq - send event to remote end of event channel via irq
+ * @irq: irq of event channel to send event to
+ *
+ * Unlike notify_remote_via_evtchn(), this is safe to use across
+ * save/restore. Notifications on a broken connection are silently
+ * dropped.
+ */
+void notify_remote_via_irq(int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ notify_remote_via_evtchn(evtchn);
+}
+EXPORT_SYMBOL_GPL(notify_remote_via_irq);
+
+static void mask_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ sync_set_bit(port, &s->evtchn_mask[0]);
+}
+
+static void unmask_evtchn(int port)
+{
+ struct shared_info *s = HYPERVISOR_shared_info;
+ unsigned int cpu = get_cpu();
+
+ BUG_ON(!irqs_disabled());
+
+ /* Slow path (hypercall) if this is a non-local port. */
+ if (unlikely(cpu != cpu_from_evtchn(port))) {
+ struct evtchn_unmask unmask = { .port = port };
+ (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
+ } else {
+ struct vcpu_info *vcpu_info = __get_cpu_var(xen_vcpu);
+
+ sync_clear_bit(port, &s->evtchn_mask[0]);
+
+ /*
+ * The following is basically the equivalent of
+ * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
+ * the interrupt edge' if the channel is masked.
+ */
+ if (sync_test_bit(port, &s->evtchn_pending[0]) &&
+ !sync_test_and_set_bit(port / BITS_PER_LONG,
+ &vcpu_info->evtchn_pending_sel))
+ vcpu_info->evtchn_upcall_pending = 1;
+ }
+
+ put_cpu();
+}
+
+static int find_unbound_irq(void)
+{
+ int irq;
+
+ /* Only allocate from dynirq range */
+ for (irq = 0; irq < NR_IRQS; irq++)
+ if (irq_bindcount[irq] == 0)
+ break;
+
+ if (irq == NR_IRQS)
+ panic("No available IRQ to bind to: increase NR_IRQS!\n");
+
+ return irq;
+}
+
+int bind_evtchn_to_irq(unsigned int evtchn)
+{
+ int irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = evtchn_to_irq[evtchn];
+
+ if (irq == -1) {
+ irq = find_unbound_irq();
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "event");
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn);
+ }
+
+ irq_bindcount[irq]++;
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irq);
+
+static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
+{
+ struct evtchn_bind_ipi bind_ipi;
+ int evtchn, irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = per_cpu(ipi_to_irq, cpu)[ipi];
+ if (irq == -1) {
+ irq = find_unbound_irq();
+ if (irq < 0)
+ goto out;
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "ipi");
+
+ bind_ipi.vcpu = cpu;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
+ &bind_ipi) != 0)
+ BUG();
+ evtchn = bind_ipi.port;
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
+
+ per_cpu(ipi_to_irq, cpu)[ipi] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+ }
+
+ irq_bindcount[irq]++;
+
+ out:
+ spin_unlock(&irq_mapping_update_lock);
+ return irq;
+}
+
+
+static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
+{
+ struct evtchn_bind_virq bind_virq;
+ int evtchn, irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ irq = per_cpu(virq_to_irq, cpu)[virq];
+
+ if (irq == -1) {
+ bind_virq.virq = virq;
+ bind_virq.vcpu = cpu;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+ &bind_virq) != 0)
+ BUG();
+ evtchn = bind_virq.port;
+
+ irq = find_unbound_irq();
+
+ dynamic_irq_init(irq);
+ set_irq_chip_and_handler_name(irq, &xen_dynamic_chip,
+ handle_level_irq, "virq");
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
+
+ per_cpu(virq_to_irq, cpu)[virq] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+ }
+
+ irq_bindcount[irq]++;
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+
+static void unbind_from_irq(unsigned int irq)
+{
+ struct evtchn_close close;
+ int evtchn = evtchn_from_irq(irq);
+
+ spin_lock(&irq_mapping_update_lock);
+
+ if (VALID_EVTCHN(evtchn) && (--irq_bindcount[irq] == 0)) {
+ close.port = evtchn;
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
+ BUG();
+
+ switch (type_from_irq(irq)) {
+ case IRQT_VIRQ:
+ per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
+ [index_from_irq(irq)] = -1;
+ break;
+ default:
+ break;
+ }
+
+ /* Closed ports are implicitly re-bound to VCPU0. */
+ bind_evtchn_to_cpu(evtchn, 0);
+
+ evtchn_to_irq[evtchn] = -1;
+ irq_info[irq] = IRQ_UNBOUND;
+
+ dynamic_irq_init(irq);
+ }
+
+ spin_unlock(&irq_mapping_update_lock);
+}
+
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+ irqreturn_t (*handler)(int, void *),
+ unsigned long irqflags,
+ const char *devname, void *dev_id)
+{
+ unsigned int irq;
+ int retval;
+
+ irq = bind_evtchn_to_irq(evtchn);
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_evtchn_to_irqhandler);
+
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+ irqreturn_t (*handler)(int, void *),
+ unsigned long irqflags, const char *devname, void *dev_id)
+{
+ unsigned int irq;
+ int retval;
+
+ irq = bind_virq_to_irq(virq, cpu);
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
+
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+ unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id)
+{
+ int irq, retval;
+
+ irq = bind_ipi_to_irq(ipi, cpu);
+ if (irq < 0)
+ return irq;
+
+ retval = request_irq(irq, handler, irqflags, devname, dev_id);
+ if (retval != 0) {
+ unbind_from_irq(irq);
+ return retval;
+ }
+
+ return irq;
+}
+
+void unbind_from_irqhandler(unsigned int irq, void *dev_id)
+{
+ free_irq(irq, dev_id);
+ unbind_from_irq(irq);
+}
+EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector)
+{
+ int irq = per_cpu(ipi_to_irq, cpu)[vector];
+ BUG_ON(irq < 0);
+ notify_remote_via_irq(irq);
+}
+
+
+/*
+ * Search the CPUs pending events bitmasks. For each one found, map
+ * the event number to an irq, and feed it into do_IRQ() for
+ * handling.
+ *
+ * Xen uses a two-level bitmap to speed searching. The first level is
+ * a bitset of words which contain pending event bits. The second
+ * level is a bitset of pending events themselves.
+ */
+fastcall 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;
+
+ vcpu_info->evtchn_upcall_pending = 0;
+
+ /* 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);
+
+ 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) {
+ regs->orig_eax = ~irq;
+ do_IRQ(regs);
+ }
+ }
+ }
+
+ put_cpu();
+}
+
+/* Rebind an evtchn so that it gets delivered to a specific cpu */
+static void rebind_irq_to_cpu(unsigned irq, unsigned tcpu)
+{
+ struct evtchn_bind_vcpu bind_vcpu;
+ int evtchn = evtchn_from_irq(irq);
+
+ if (!VALID_EVTCHN(evtchn))
+ return;
+
+ /* Send future instances of this interrupt to other vcpu. */
+ bind_vcpu.port = evtchn;
+ bind_vcpu.vcpu = tcpu;
+
+ /*
+ * If this fails, it usually just indicates that we're dealing with a
+ * virq or IPI channel, which don't actually need to be rebound. Ignore
+ * it, but don't do the xenlinux-level rebind in that case.
+ */
+ if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0)
+ bind_evtchn_to_cpu(evtchn, tcpu);
+}
+
+
+static void set_affinity_irq(unsigned irq, cpumask_t dest)
+{
+ unsigned tcpu = first_cpu(dest);
+ rebind_irq_to_cpu(irq, tcpu);
+}
+
+static void enable_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ unmask_evtchn(evtchn);
+}
+
+static void disable_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ mask_evtchn(evtchn);
+}
+
+static void ack_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+
+ move_native_irq(irq);
+
+ if (VALID_EVTCHN(evtchn))
+ clear_evtchn(evtchn);
+}
+
+static int retrigger_dynirq(unsigned int irq)
+{
+ int evtchn = evtchn_from_irq(irq);
+ int ret = 0;
+
+ if (VALID_EVTCHN(evtchn)) {
+ set_evtchn(evtchn);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+static struct irq_chip xen_dynamic_chip __read_mostly = {
+ .name = "xen-dyn",
+ .mask = disable_dynirq,
+ .unmask = enable_dynirq,
+ .ack = ack_dynirq,
+ .set_affinity = set_affinity_irq,
+ .retrigger = retrigger_dynirq,
+};
+
+void __init xen_init_IRQ(void)
+{
+ int i;
+
+ init_evtchn_cpu_bindings();
+
+ /* No event channels are 'live' right now. */
+ for (i = 0; i < NR_EVENT_CHANNELS; i++)
+ mask_evtchn(i);
+
+ /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
+ for (i = 0; i < NR_IRQS; i++)
+ irq_bindcount[i] = 0;
+
+ irq_ctx_init(smp_processor_id());
+}
diff --git a/arch/i386/xen/features.c b/arch/i386/xen/features.c
new file mode 100644
index 000000000000..0707714e40d6
--- /dev/null
+++ b/arch/i386/xen/features.c
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * features.c
+ *
+ * Xen feature flags.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
+ */
+#include <linux/types.h>
+#include <linux/cache.h>
+#include <linux/module.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/features.h>
+
+u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
+EXPORT_SYMBOL_GPL(xen_features);
+
+void xen_setup_features(void)
+{
+ struct xen_feature_info fi;
+ int i, j;
+
+ for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
+ fi.submap_idx = i;
+ if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
+ break;
+ for (j = 0; j < 32; j++)
+ xen_features[i * 32 + j] = !!(fi.submap & 1<<j);
+ }
+}
diff --git a/arch/i386/xen/manage.c b/arch/i386/xen/manage.c
new file mode 100644
index 000000000000..aa7af9e6abc0
--- /dev/null
+++ b/arch/i386/xen/manage.c
@@ -0,0 +1,143 @@
+/*
+ * Handle extern requests for shutdown, reboot and sysrq
+ */
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+
+#include <xen/xenbus.h>
+
+#define SHUTDOWN_INVALID -1
+#define SHUTDOWN_POWEROFF 0
+#define SHUTDOWN_SUSPEND 2
+/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
+ * report a crash, not be instructed to crash!
+ * HALT is the same as POWEROFF, as far as we're concerned. The tools use
+ * the distinction when we return the reason code to them.
+ */
+#define SHUTDOWN_HALT 4
+
+/* Ignore multiple shutdown requests. */
+static int shutting_down = SHUTDOWN_INVALID;
+
+static void shutdown_handler(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ char *str;
+ struct xenbus_transaction xbt;
+ int err;
+
+ if (shutting_down != SHUTDOWN_INVALID)
+ return;
+
+ again:
+ err = xenbus_transaction_start(&xbt);
+ if (err)
+ return;
+
+ str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
+ /* Ignore read errors and empty reads. */
+ if (XENBUS_IS_ERR_READ(str)) {
+ xenbus_transaction_end(xbt, 1);
+ return;
+ }
+
+ xenbus_write(xbt, "control", "shutdown", "");
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN) {
+ kfree(str);
+ goto again;
+ }
+
+ if (strcmp(str, "poweroff") == 0 ||
+ strcmp(str, "halt") == 0)
+ orderly_poweroff(false);
+ else if (strcmp(str, "reboot") == 0)
+ ctrl_alt_del();
+ else {
+ printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
+ shutting_down = SHUTDOWN_INVALID;
+ }
+
+ kfree(str);
+}
+
+static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
+ unsigned int len)
+{
+ char sysrq_key = '\0';
+ struct xenbus_transaction xbt;
+ int err;
+
+ again:
+ err = xenbus_transaction_start(&xbt);
+ if (err)
+ return;
+ if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
+ printk(KERN_ERR "Unable to read sysrq code in "
+ "control/sysrq\n");
+ xenbus_transaction_end(xbt, 1);
+ return;
+ }
+
+ if (sysrq_key != '\0')
+ xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN)
+ goto again;
+
+ if (sysrq_key != '\0')
+ handle_sysrq(sysrq_key, NULL);
+}
+
+static struct xenbus_watch shutdown_watch = {
+ .node = "control/shutdown",
+ .callback = shutdown_handler
+};
+
+static struct xenbus_watch sysrq_watch = {
+ .node = "control/sysrq",
+ .callback = sysrq_handler
+};
+
+static int setup_shutdown_watcher(void)
+{
+ int err;
+
+ err = register_xenbus_watch(&shutdown_watch);
+ if (err) {
+ printk(KERN_ERR "Failed to set shutdown watcher\n");
+ return err;
+ }
+
+ err = register_xenbus_watch(&sysrq_watch);
+ if (err) {
+ printk(KERN_ERR "Failed to set sysrq watcher\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int shutdown_event(struct notifier_block *notifier,
+ unsigned long event,
+ void *data)
+{
+ setup_shutdown_watcher();
+ return NOTIFY_DONE;
+}
+
+static int __init setup_shutdown_event(void)
+{
+ static struct notifier_block xenstore_notifier = {
+ .notifier_call = shutdown_event
+ };
+ register_xenstore_notifier(&xenstore_notifier);
+
+ return 0;
+}
+
+subsys_initcall(setup_shutdown_event);
diff --git a/arch/i386/xen/mmu.c b/arch/i386/xen/mmu.c
new file mode 100644
index 000000000000..4ae038aa6c24
--- /dev/null
+++ b/arch/i386/xen/mmu.c
@@ -0,0 +1,564 @@
+/*
+ * Xen mmu operations
+ *
+ * This file contains the various mmu fetch and update operations.
+ * The most important job they must perform is the mapping between the
+ * domain's pfn and the overall machine mfns.
+ *
+ * Xen allows guests to directly update the pagetable, in a controlled
+ * fashion. In other words, the guest modifies the same pagetable
+ * that the CPU actually uses, which eliminates the overhead of having
+ * a separate shadow pagetable.
+ *
+ * In order to allow this, it falls on the guest domain to map its
+ * notion of a "physical" pfn - which is just a domain-local linear
+ * address - into a real "machine address" which the CPU's MMU can
+ * use.
+ *
+ * A pgd_t/pmd_t/pte_t will typically contain an mfn, and so can be
+ * inserted directly into the pagetable. When creating a new
+ * pte/pmd/pgd, it converts the passed pfn into an mfn. Conversely,
+ * when reading the content back with __(pgd|pmd|pte)_val, it converts
+ * the mfn back into a pfn.
+ *
+ * The other constraint is that all pages which make up a pagetable
+ * must be mapped read-only in the guest. This prevents uncontrolled
+ * guest updates to the pagetable. Xen strictly enforces this, and
+ * will disallow any pagetable update which will end up mapping a
+ * pagetable page RW, and will disallow using any writable page as a
+ * pagetable.
+ *
+ * Naively, when loading %cr3 with the base of a new pagetable, Xen
+ * would need to validate the whole pagetable before going on.
+ * Naturally, this is quite slow. The solution is to "pin" a
+ * pagetable, which enforces all the constraints on the pagetable even
+ * when it is not actively in use. This menas that Xen can be assured
+ * that it is still valid when you do load it into %cr3, and doesn't
+ * need to revalidate it.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/sched.h>
+#include <linux/highmem.h>
+#include <linux/bug.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/paravirt.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/page.h>
+#include <xen/interface/xen.h>
+
+#include "multicalls.h"
+#include "mmu.h"
+
+xmaddr_t arbitrary_virt_to_machine(unsigned long address)
+{
+ pte_t *pte = lookup_address(address);
+ unsigned offset = address & PAGE_MASK;
+
+ BUG_ON(pte == NULL);
+
+ return XMADDR((pte_mfn(*pte) << PAGE_SHIFT) + offset);
+}
+
+void make_lowmem_page_readonly(void *vaddr)
+{
+ pte_t *pte, ptev;
+ unsigned long address = (unsigned long)vaddr;
+
+ pte = lookup_address(address);
+ BUG_ON(pte == NULL);
+
+ ptev = pte_wrprotect(*pte);
+
+ if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+ BUG();
+}
+
+void make_lowmem_page_readwrite(void *vaddr)
+{
+ pte_t *pte, ptev;
+ unsigned long address = (unsigned long)vaddr;
+
+ pte = lookup_address(address);
+ BUG_ON(pte == NULL);
+
+ ptev = pte_mkwrite(*pte);
+
+ if (HYPERVISOR_update_va_mapping(address, ptev, 0))
+ BUG();
+}
+
+
+void xen_set_pmd(pmd_t *ptr, pmd_t val)
+{
+ struct multicall_space mcs;
+ struct mmu_update *u;
+
+ preempt_disable();
+
+ mcs = xen_mc_entry(sizeof(*u));
+ u = mcs.args;
+ u->ptr = virt_to_machine(ptr).maddr;
+ u->val = pmd_val_ma(val);
+ MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+ preempt_enable();
+}
+
+/*
+ * Associate a virtual page frame with a given physical page frame
+ * and protection flags for that frame.
+ */
+void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = swapper_pg_dir + pgd_index(vaddr);
+ if (pgd_none(*pgd)) {
+ BUG();
+ return;
+ }
+ pud = pud_offset(pgd, vaddr);
+ if (pud_none(*pud)) {
+ BUG();
+ return;
+ }
+ pmd = pmd_offset(pud, vaddr);
+ if (pmd_none(*pmd)) {
+ BUG();
+ return;
+ }
+ pte = pte_offset_kernel(pmd, vaddr);
+ /* <mfn,flags> stored as-is, to permit clearing entries */
+ xen_set_pte(pte, mfn_pte(mfn, flags));
+
+ /*
+ * It's enough to flush this one mapping.
+ * (PGE mappings get flushed as well)
+ */
+ __flush_tlb_one(vaddr);
+}
+
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ if (mm == current->mm || mm == &init_mm) {
+ if (xen_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
+ struct multicall_space mcs;
+ mcs = xen_mc_entry(0);
+
+ MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+ return;
+ } else
+ if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
+ return;
+ }
+ xen_set_pte(ptep, pteval);
+}
+
+#ifdef CONFIG_X86_PAE
+void xen_set_pud(pud_t *ptr, pud_t val)
+{
+ struct multicall_space mcs;
+ struct mmu_update *u;
+
+ preempt_disable();
+
+ mcs = xen_mc_entry(sizeof(*u));
+ u = mcs.args;
+ u->ptr = virt_to_machine(ptr).maddr;
+ u->val = pud_val_ma(val);
+ MULTI_mmu_update(mcs.mc, u, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
+
+ preempt_enable();
+}
+
+void xen_set_pte(pte_t *ptep, pte_t pte)
+{
+ ptep->pte_high = pte.pte_high;
+ smp_wmb();
+ ptep->pte_low = pte.pte_low;
+}
+
+void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
+{
+ set_64bit((u64 *)ptep, pte_val_ma(pte));
+}
+
+void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+ ptep->pte_low = 0;
+ smp_wmb(); /* make sure low gets written first */
+ ptep->pte_high = 0;
+}
+
+void xen_pmd_clear(pmd_t *pmdp)
+{
+ xen_set_pmd(pmdp, __pmd(0));
+}
+
+unsigned long long xen_pte_val(pte_t pte)
+{
+ 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 & 1)
+ pte = phys_to_machine(XPADDR(pte)).maddr;
+
+ return (pte_t){ pte, pte >> 32 };
+}
+
+pmd_t xen_make_pmd(unsigned long long pmd)
+{
+ if (pmd & 1)
+ 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 };
+}
+#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;
+
+ 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 */
+
+
+
+/*
+ (Yet another) pagetable walker. This one is intended for pinning a
+ pagetable. This means that it walks a pagetable and calls the
+ callback function on each page it finds making up the page table,
+ at every level. It walks the entire pagetable, but it only bothers
+ pinning pte pages which are below pte_limit. In the normal case
+ this will be TASK_SIZE, but at boot we need to pin up to
+ FIXADDR_TOP. But the important bit is that we don't pin beyond
+ there, because then we start getting into Xen's ptes.
+*/
+static int pgd_walk(pgd_t *pgd_base, int (*func)(struct page *, unsigned),
+ unsigned long limit)
+{
+ pgd_t *pgd = pgd_base;
+ int flush = 0;
+ unsigned long addr = 0;
+ unsigned long pgd_next;
+
+ BUG_ON(limit > FIXADDR_TOP);
+
+ if (xen_feature(XENFEAT_auto_translated_physmap))
+ return 0;
+
+ for (; addr != FIXADDR_TOP; pgd++, addr = pgd_next) {
+ pud_t *pud;
+ unsigned long pud_limit, pud_next;
+
+ pgd_next = pud_limit = pgd_addr_end(addr, FIXADDR_TOP);
+
+ if (!pgd_val(*pgd))
+ continue;
+
+ pud = pud_offset(pgd, 0);
+
+ if (PTRS_PER_PUD > 1) /* not folded */
+ flush |= (*func)(virt_to_page(pud), 0);
+
+ for (; addr != pud_limit; pud++, addr = pud_next) {
+ pmd_t *pmd;
+ unsigned long pmd_limit;
+
+ pud_next = pud_addr_end(addr, pud_limit);
+
+ if (pud_next < limit)
+ pmd_limit = pud_next;
+ else
+ pmd_limit = limit;
+
+ if (pud_none(*pud))
+ continue;
+
+ pmd = pmd_offset(pud, 0);
+
+ if (PTRS_PER_PMD > 1) /* not folded */
+ flush |= (*func)(virt_to_page(pmd), 0);
+
+ for (; addr != pmd_limit; pmd++) {
+ addr += (PAGE_SIZE * PTRS_PER_PTE);
+ if ((pmd_limit-1) < (addr-1)) {
+ addr = pmd_limit;
+ break;
+ }
+
+ if (pmd_none(*pmd))
+ continue;
+
+ flush |= (*func)(pmd_page(*pmd), 0);
+ }
+ }
+ }
+
+ flush |= (*func)(virt_to_page(pgd_base), UVMF_TLB_FLUSH);
+
+ return flush;
+}
+
+static int pin_page(struct page *page, unsigned flags)
+{
+ unsigned pgfl = test_and_set_bit(PG_pinned, &page->flags);
+ int flush;
+
+ if (pgfl)
+ flush = 0; /* already pinned */
+ else if (PageHighMem(page))
+ /* kmaps need flushing if we found an unpinned
+ highpage */
+ flush = 1;
+ else {
+ void *pt = lowmem_page_address(page);
+ unsigned long pfn = page_to_pfn(page);
+ struct multicall_space mcs = __xen_mc_entry(0);
+
+ flush = 0;
+
+ MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+ pfn_pte(pfn, PAGE_KERNEL_RO),
+ flags);
+ }
+
+ return flush;
+}
+
+/* This is called just after a mm has been created, but it has not
+ been used yet. We need to make sure that its pagetable is all
+ read-only, and can be pinned. */
+void xen_pgd_pin(pgd_t *pgd)
+{
+ struct multicall_space mcs;
+ struct mmuext_op *op;
+
+ xen_mc_batch();
+
+ if (pgd_walk(pgd, pin_page, TASK_SIZE)) {
+ /* re-enable interrupts for kmap_flush_unused */
+ xen_mc_issue(0);
+ kmap_flush_unused();
+ xen_mc_batch();
+ }
+
+ mcs = __xen_mc_entry(sizeof(*op));
+ op = mcs.args;
+
+#ifdef CONFIG_X86_PAE
+ op->cmd = MMUEXT_PIN_L3_TABLE;
+#else
+ op->cmd = MMUEXT_PIN_L2_TABLE;
+#endif
+ op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ xen_mc_issue(0);
+}
+
+/* The init_mm pagetable is really pinned as soon as its created, but
+ that's before we have page structures to store the bits. So do all
+ the book-keeping now. */
+static __init int mark_pinned(struct page *page, unsigned flags)
+{
+ SetPagePinned(page);
+ return 0;
+}
+
+void __init xen_mark_init_mm_pinned(void)
+{
+ pgd_walk(init_mm.pgd, mark_pinned, FIXADDR_TOP);
+}
+
+static int unpin_page(struct page *page, unsigned flags)
+{
+ unsigned pgfl = test_and_clear_bit(PG_pinned, &page->flags);
+
+ if (pgfl && !PageHighMem(page)) {
+ void *pt = lowmem_page_address(page);
+ unsigned long pfn = page_to_pfn(page);
+ struct multicall_space mcs = __xen_mc_entry(0);
+
+ MULTI_update_va_mapping(mcs.mc, (unsigned long)pt,
+ pfn_pte(pfn, PAGE_KERNEL),
+ flags);
+ }
+
+ return 0; /* never need to flush on unpin */
+}
+
+/* Release a pagetables pages back as normal RW */
+static void xen_pgd_unpin(pgd_t *pgd)
+{
+ struct mmuext_op *op;
+ struct multicall_space mcs;
+
+ xen_mc_batch();
+
+ mcs = __xen_mc_entry(sizeof(*op));
+
+ op = mcs.args;
+ op->cmd = MMUEXT_UNPIN_TABLE;
+ op->arg1.mfn = pfn_to_mfn(PFN_DOWN(__pa(pgd)));
+
+ MULTI_mmuext_op(mcs.mc, op, 1, NULL, DOMID_SELF);
+
+ pgd_walk(pgd, unpin_page, TASK_SIZE);
+
+ xen_mc_issue(0);
+}
+
+void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+ spin_lock(&next->page_table_lock);
+ xen_pgd_pin(next->pgd);
+ spin_unlock(&next->page_table_lock);
+}
+
+void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+ spin_lock(&mm->page_table_lock);
+ xen_pgd_pin(mm->pgd);
+ spin_unlock(&mm->page_table_lock);
+}
+
+
+#ifdef CONFIG_SMP
+/* Another cpu may still have their %cr3 pointing at the pagetable, so
+ we need to repoint it somewhere else before we can unpin it. */
+static void drop_other_mm_ref(void *info)
+{
+ struct mm_struct *mm = info;
+
+ if (__get_cpu_var(cpu_tlbstate).active_mm == mm)
+ leave_mm(smp_processor_id());
+}
+
+static void drop_mm_ref(struct mm_struct *mm)
+{
+ if (current->active_mm == mm) {
+ if (current->mm == mm)
+ load_cr3(swapper_pg_dir);
+ else
+ leave_mm(smp_processor_id());
+ }
+
+ if (!cpus_empty(mm->cpu_vm_mask))
+ xen_smp_call_function_mask(mm->cpu_vm_mask, drop_other_mm_ref,
+ mm, 1);
+}
+#else
+static void drop_mm_ref(struct mm_struct *mm)
+{
+ if (current->active_mm == mm)
+ load_cr3(swapper_pg_dir);
+}
+#endif
+
+/*
+ * While a process runs, Xen pins its pagetables, which means that the
+ * hypervisor forces it to be read-only, and it controls all updates
+ * to it. This means that all pagetable updates have to go via the
+ * hypervisor, which is moderately expensive.
+ *
+ * Since we're pulling the pagetable down, we switch to use init_mm,
+ * unpin old process pagetable and mark it all read-write, which
+ * allows further operations on it to be simple memory accesses.
+ *
+ * The only subtle point is that another CPU may be still using the
+ * pagetable because of lazy tlb flushing. This means we need need to
+ * switch all CPUs off this pagetable before we can unpin it.
+ */
+void xen_exit_mmap(struct mm_struct *mm)
+{
+ get_cpu(); /* make sure we don't move around */
+ drop_mm_ref(mm);
+ put_cpu();
+
+ spin_lock(&mm->page_table_lock);
+ xen_pgd_unpin(mm->pgd);
+ spin_unlock(&mm->page_table_lock);
+}
diff --git a/arch/i386/xen/mmu.h b/arch/i386/xen/mmu.h
new file mode 100644
index 000000000000..c9ff27f3ac3a
--- /dev/null
+++ b/arch/i386/xen/mmu.h
@@ -0,0 +1,60 @@
+#ifndef _XEN_MMU_H
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+/*
+ * Page-directory addresses above 4GB do not fit into architectural %cr3.
+ * When accessing %cr3, or equivalent field in vcpu_guest_context, guests
+ * must use the following accessor macros to pack/unpack valid MFNs.
+ *
+ * Note that Xen is using the fact that the pagetable base is always
+ * page-aligned, and putting the 12 MSB of the address into the 12 LSB
+ * of cr3.
+ */
+#define xen_pfn_to_cr3(pfn) (((unsigned)(pfn) << 12) | ((unsigned)(pfn) >> 20))
+#define xen_cr3_to_pfn(cr3) (((unsigned)(cr3) >> 12) | ((unsigned)(cr3) << 20))
+
+
+void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
+
+void xen_set_pte(pte_t *ptep, pte_t pteval);
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval);
+void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
+
+void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
+void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
+void xen_exit_mmap(struct mm_struct *mm);
+
+void xen_pgd_pin(pgd_t *pgd);
+//void xen_pgd_unpin(pgd_t *pgd);
+
+#ifdef CONFIG_X86_PAE
+unsigned long long xen_pte_val(pte_t);
+unsigned long long xen_pmd_val(pmd_t);
+unsigned long long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long long);
+pmd_t xen_make_pmd(unsigned long long);
+pgd_t xen_make_pgd(unsigned long long);
+
+void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval);
+void xen_set_pte_atomic(pte_t *ptep, pte_t pte);
+void xen_set_pud(pud_t *ptr, pud_t val);
+void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
+void xen_pmd_clear(pmd_t *pmdp);
+
+
+#else
+unsigned long xen_pte_val(pte_t);
+unsigned long xen_pmd_val(pmd_t);
+unsigned long xen_pgd_val(pgd_t);
+
+pte_t xen_make_pte(unsigned long);
+pmd_t xen_make_pmd(unsigned long);
+pgd_t xen_make_pgd(unsigned long);
+#endif
+
+#endif /* _XEN_MMU_H */
diff --git a/arch/i386/xen/multicalls.c b/arch/i386/xen/multicalls.c
new file mode 100644
index 000000000000..c837e8e463db
--- /dev/null
+++ b/arch/i386/xen/multicalls.c
@@ -0,0 +1,90 @@
+/*
+ * Xen hypercall batching.
+ *
+ * Xen allows multiple hypercalls to be issued at once, using the
+ * multicall interface. This allows the cost of trapping into the
+ * hypervisor to be amortized over several calls.
+ *
+ * This file implements a simple interface for multicalls. There's a
+ * per-cpu buffer of outstanding multicalls. When you want to queue a
+ * multicall for issuing, you can allocate a multicall slot for the
+ * call and its arguments, along with storage for space which is
+ * pointed to by the arguments (for passing pointers to structures,
+ * etc). When the multicall is actually issued, all the space for the
+ * commands and allocated memory is freed for reuse.
+ *
+ * Multicalls are flushed whenever any of the buffers get full, or
+ * when explicitly requested. There's no way to get per-multicall
+ * return results back. It will BUG if any of the multicalls fail.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/percpu.h>
+#include <linux/hardirq.h>
+
+#include <asm/xen/hypercall.h>
+
+#include "multicalls.h"
+
+#define MC_BATCH 32
+#define MC_ARGS (MC_BATCH * 16 / sizeof(u64))
+
+struct mc_buffer {
+ struct multicall_entry entries[MC_BATCH];
+ u64 args[MC_ARGS];
+ unsigned mcidx, argidx;
+};
+
+static DEFINE_PER_CPU(struct mc_buffer, mc_buffer);
+DEFINE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+void xen_mc_flush(void)
+{
+ struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+ int ret = 0;
+ unsigned long flags;
+
+ BUG_ON(preemptible());
+
+ /* Disable interrupts in case someone comes in and queues
+ something in the middle */
+ local_irq_save(flags);
+
+ if (b->mcidx) {
+ int i;
+
+ if (HYPERVISOR_multicall(b->entries, b->mcidx) != 0)
+ BUG();
+ for (i = 0; i < b->mcidx; i++)
+ if (b->entries[i].result < 0)
+ ret++;
+ b->mcidx = 0;
+ b->argidx = 0;
+ } else
+ BUG_ON(b->argidx != 0);
+
+ local_irq_restore(flags);
+
+ BUG_ON(ret);
+}
+
+struct multicall_space __xen_mc_entry(size_t args)
+{
+ struct mc_buffer *b = &__get_cpu_var(mc_buffer);
+ struct multicall_space ret;
+ unsigned argspace = (args + sizeof(u64) - 1) / sizeof(u64);
+
+ BUG_ON(preemptible());
+ BUG_ON(argspace > MC_ARGS);
+
+ if (b->mcidx == MC_BATCH ||
+ (b->argidx + argspace) > MC_ARGS)
+ xen_mc_flush();
+
+ ret.mc = &b->entries[b->mcidx];
+ b->mcidx++;
+ ret.args = &b->args[b->argidx];
+ b->argidx += argspace;
+
+ return ret;
+}
diff --git a/arch/i386/xen/multicalls.h b/arch/i386/xen/multicalls.h
new file mode 100644
index 000000000000..e6f7530b156c
--- /dev/null
+++ b/arch/i386/xen/multicalls.h
@@ -0,0 +1,45 @@
+#ifndef _XEN_MULTICALLS_H
+#define _XEN_MULTICALLS_H
+
+#include "xen-ops.h"
+
+/* Multicalls */
+struct multicall_space
+{
+ struct multicall_entry *mc;
+ void *args;
+};
+
+/* Allocate room for a multicall and its args */
+struct multicall_space __xen_mc_entry(size_t args);
+
+DECLARE_PER_CPU(unsigned long, xen_mc_irq_flags);
+
+/* Call to start a batch of multiple __xen_mc_entry()s. Must be
+ paired with xen_mc_issue() */
+static inline void xen_mc_batch(void)
+{
+ /* need to disable interrupts until this entry is complete */
+ local_irq_save(__get_cpu_var(xen_mc_irq_flags));
+}
+
+static inline struct multicall_space xen_mc_entry(size_t args)
+{
+ xen_mc_batch();
+ return __xen_mc_entry(args);
+}
+
+/* Flush all pending multicalls */
+void xen_mc_flush(void);
+
+/* Issue a multicall if we're not in a lazy mode */
+static inline void xen_mc_issue(unsigned mode)
+{
+ if ((xen_get_lazy_mode() & mode) == 0)
+ xen_mc_flush();
+
+ /* restore flags saved in xen_mc_batch */
+ local_irq_restore(x86_read_percpu(xen_mc_irq_flags));
+}
+
+#endif /* _XEN_MULTICALLS_H */
diff --git a/arch/i386/xen/setup.c b/arch/i386/xen/setup.c
new file mode 100644
index 000000000000..f84e77226646
--- /dev/null
+++ b/arch/i386/xen/setup.c
@@ -0,0 +1,111 @@
+/*
+ * Machine specific setup for xen
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/pm.h>
+
+#include <asm/elf.h>
+#include <asm/e820.h>
+#include <asm/setup.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/interface/physdev.h>
+#include <xen/features.h>
+
+#include "xen-ops.h"
+#include "vdso.h"
+
+/* These are code, but not functions. Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+extern const char xen_failsafe_callback[];
+
+unsigned long *phys_to_machine_mapping;
+EXPORT_SYMBOL(phys_to_machine_mapping);
+
+/**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ **/
+
+char * __init xen_memory_setup(void)
+{
+ unsigned long max_pfn = xen_start_info->nr_pages;
+
+ e820.nr_map = 0;
+ add_memory_region(0, PFN_PHYS(max_pfn), E820_RAM);
+
+ return "Xen";
+}
+
+static void xen_idle(void)
+{
+ local_irq_disable();
+
+ if (need_resched())
+ local_irq_enable();
+ else {
+ current_thread_info()->status &= ~TS_POLLING;
+ smp_mb__after_clear_bit();
+ safe_halt();
+ current_thread_info()->status |= TS_POLLING;
+ }
+}
+
+/*
+ * Set the bit indicating "nosegneg" library variants should be used.
+ */
+static void fiddle_vdso(void)
+{
+ extern u32 VDSO_NOTE_MASK; /* See ../kernel/vsyscall-note.S. */
+ extern char vsyscall_int80_start;
+ u32 *mask = (u32 *) ((unsigned long) &VDSO_NOTE_MASK - VDSO_PRELINK +
+ &vsyscall_int80_start);
+ *mask |= 1 << VDSO_NOTE_NONEGSEG_BIT;
+}
+
+void __init xen_arch_setup(void)
+{
+ struct physdev_set_iopl set_iopl;
+ int rc;
+
+ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
+ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap))
+ HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_pae_extended_cr3);
+
+ HYPERVISOR_set_callbacks(__KERNEL_CS, (unsigned long)xen_hypervisor_callback,
+ __KERNEL_CS, (unsigned long)xen_failsafe_callback);
+
+ set_iopl.iopl = 1;
+ rc = HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
+ if (rc != 0)
+ printk(KERN_INFO "physdev_op failed %d\n", rc);
+
+#ifdef CONFIG_ACPI
+ if (!(xen_start_info->flags & SIF_INITDOMAIN)) {
+ printk(KERN_INFO "ACPI in unprivileged domain disabled\n");
+ disable_acpi();
+ }
+#endif
+
+ memcpy(boot_command_line, xen_start_info->cmd_line,
+ MAX_GUEST_CMDLINE > COMMAND_LINE_SIZE ?
+ COMMAND_LINE_SIZE : MAX_GUEST_CMDLINE);
+
+ pm_idle = xen_idle;
+
+#ifdef CONFIG_SMP
+ /* fill cpus_possible with all available cpus */
+ xen_fill_possible_map();
+#endif
+
+ paravirt_disable_iospace();
+
+ fiddle_vdso();
+}
diff --git a/arch/i386/xen/smp.c b/arch/i386/xen/smp.c
new file mode 100644
index 000000000000..557b8e24706a
--- /dev/null
+++ b/arch/i386/xen/smp.c
@@ -0,0 +1,404 @@
+/*
+ * Xen SMP support
+ *
+ * This file implements the Xen versions of smp_ops. SMP under Xen is
+ * very straightforward. Bringing a CPU up is simply a matter of
+ * loading its initial context and setting it running.
+ *
+ * IPIs are handled through the Xen event mechanism.
+ *
+ * Because virtual CPUs can be scheduled onto any real CPU, there's no
+ * useful topology information for the kernel to make use of. As a
+ * result, all CPUs are treated as if they're single-core and
+ * single-threaded.
+ *
+ * This does not handle HOTPLUG_CPU yet.
+ */
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/smp.h>
+
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/cpu.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include <asm/xen/interface.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/page.h>
+#include <xen/events.h>
+
+#include "xen-ops.h"
+#include "mmu.h"
+
+static cpumask_t cpu_initialized_map;
+static DEFINE_PER_CPU(int, resched_irq);
+static DEFINE_PER_CPU(int, callfunc_irq);
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static DEFINE_SPINLOCK(call_lock);
+
+struct call_data_struct {
+ void (*func) (void *info);
+ void *info;
+ atomic_t started;
+ atomic_t finished;
+ int wait;
+};
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
+
+static struct call_data_struct *call_data;
+
+/*
+ * Reschedule call back. Nothing to do,
+ * all the work is done automatically when
+ * we return from the interrupt.
+ */
+static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
+{
+ return IRQ_HANDLED;
+}
+
+static __cpuinit void cpu_bringup_and_idle(void)
+{
+ int cpu = smp_processor_id();
+
+ cpu_init();
+
+ preempt_disable();
+ per_cpu(cpu_state, cpu) = CPU_ONLINE;
+
+ xen_setup_cpu_clockevents();
+
+ /* We can take interrupts now: we're officially "up". */
+ local_irq_enable();
+
+ wmb(); /* make sure everything is out */
+ cpu_idle();
+}
+
+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;
+
+ resched_name = kasprintf(GFP_KERNEL, "resched%d", cpu);
+ rc = bind_ipi_to_irqhandler(XEN_RESCHEDULE_VECTOR,
+ cpu,
+ xen_reschedule_interrupt,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ resched_name,
+ NULL);
+ if (rc < 0)
+ goto fail;
+ per_cpu(resched_irq, cpu) = rc;
+
+ callfunc_name = kasprintf(GFP_KERNEL, "callfunc%d", cpu);
+ rc = bind_ipi_to_irqhandler(XEN_CALL_FUNCTION_VECTOR,
+ cpu,
+ xen_call_function_interrupt,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ callfunc_name,
+ NULL);
+ if (rc < 0)
+ goto fail;
+ per_cpu(callfunc_irq, cpu) = rc;
+
+ return 0;
+
+ fail:
+ if (per_cpu(resched_irq, cpu) >= 0)
+ 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);
+ return rc;
+}
+
+void __init xen_fill_possible_map(void)
+{
+ int i, rc;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
+ if (rc >= 0)
+ cpu_set(i, cpu_possible_map);
+ }
+}
+
+void __init xen_smp_prepare_boot_cpu(void)
+{
+ int cpu;
+
+ BUG_ON(smp_processor_id() != 0);
+ native_smp_prepare_boot_cpu();
+
+ /* We've switched to the "real" per-cpu gdt, so make sure the
+ old memory can be recycled */
+ make_lowmem_page_readwrite(&per_cpu__gdt_page);
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ }
+
+ xen_setup_vcpu_info_placement();
+}
+
+void __init xen_smp_prepare_cpus(unsigned int max_cpus)
+{
+ unsigned cpu;
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ }
+
+ smp_store_cpu_info(0);
+ set_cpu_sibling_map(0);
+
+ if (xen_smp_intr_init(0))
+ BUG();
+
+ cpu_initialized_map = cpumask_of_cpu(0);
+
+ /* 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--)
+ continue;
+ cpu_clear(cpu, cpu_possible_map);
+ }
+
+ for_each_possible_cpu (cpu) {
+ struct task_struct *idle;
+
+ if (cpu == 0)
+ continue;
+
+ idle = fork_idle(cpu);
+ if (IS_ERR(idle))
+ panic("failed fork for CPU %d", cpu);
+
+ cpu_set(cpu, cpu_present_map);
+ }
+
+ //init_xenbus_allowed_cpumask();
+}
+
+static __cpuinit int
+cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
+{
+ struct vcpu_guest_context *ctxt;
+ struct gdt_page *gdt = &per_cpu(gdt_page, cpu);
+
+ if (cpu_test_and_set(cpu, cpu_initialized_map))
+ return 0;
+
+ ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
+ if (ctxt == NULL)
+ return -ENOMEM;
+
+ ctxt->flags = VGCF_IN_KERNEL;
+ ctxt->user_regs.ds = __USER_DS;
+ ctxt->user_regs.es = __USER_DS;
+ ctxt->user_regs.fs = __KERNEL_PERCPU;
+ ctxt->user_regs.gs = 0;
+ ctxt->user_regs.ss = __KERNEL_DS;
+ ctxt->user_regs.eip = (unsigned long)cpu_bringup_and_idle;
+ ctxt->user_regs.eflags = 0x1000; /* IOPL_RING1 */
+
+ memset(&ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
+
+ xen_copy_trap_info(ctxt->trap_ctxt);
+
+ ctxt->ldt_ents = 0;
+
+ BUG_ON((unsigned long)gdt->gdt & ~PAGE_MASK);
+ make_lowmem_page_readonly(gdt->gdt);
+
+ ctxt->gdt_frames[0] = virt_to_mfn(gdt->gdt);
+ ctxt->gdt_ents = ARRAY_SIZE(gdt->gdt);
+
+ ctxt->user_regs.cs = __KERNEL_CS;
+ ctxt->user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
+
+ ctxt->kernel_ss = __KERNEL_DS;
+ ctxt->kernel_sp = idle->thread.esp0;
+
+ ctxt->event_callback_cs = __KERNEL_CS;
+ ctxt->event_callback_eip = (unsigned long)xen_hypervisor_callback;
+ ctxt->failsafe_callback_cs = __KERNEL_CS;
+ ctxt->failsafe_callback_eip = (unsigned long)xen_failsafe_callback;
+
+ per_cpu(xen_cr3, cpu) = __pa(swapper_pg_dir);
+ ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt))
+ BUG();
+
+ kfree(ctxt);
+ return 0;
+}
+
+int __cpuinit xen_cpu_up(unsigned int cpu)
+{
+ struct task_struct *idle = idle_task(cpu);
+ int rc;
+
+#if 0
+ rc = cpu_up_check(cpu);
+ if (rc)
+ return rc;
+#endif
+
+ init_gdt(cpu);
+ per_cpu(current_task, cpu) = idle;
+ irq_ctx_init(cpu);
+ xen_setup_timer(cpu);
+
+ /* make sure interrupts start blocked */
+ per_cpu(xen_vcpu, cpu)->evtchn_upcall_mask = 1;
+
+ rc = cpu_initialize_context(cpu, idle);
+ if (rc)
+ return rc;
+
+ if (num_online_cpus() == 1)
+ alternatives_smp_switch(1);
+
+ rc = xen_smp_intr_init(cpu);
+ if (rc)
+ return rc;
+
+ smp_store_cpu_info(cpu);
+ set_cpu_sibling_map(cpu);
+ /* This must be done before setting cpu_online_map */
+ wmb();
+
+ cpu_set(cpu, cpu_online_map);
+
+ rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
+ BUG_ON(rc);
+
+ return 0;
+}
+
+void xen_smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+static void stop_self(void *v)
+{
+ int cpu = smp_processor_id();
+
+ /* make sure we're not pinning something down */
+ load_cr3(swapper_pg_dir);
+ /* should set up a minimal gdt */
+
+ HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL);
+ BUG();
+}
+
+void xen_smp_send_stop(void)
+{
+ smp_call_function(stop_self, NULL, 0, 0);
+}
+
+void xen_smp_send_reschedule(int cpu)
+{
+ xen_send_IPI_one(cpu, XEN_RESCHEDULE_VECTOR);
+}
+
+
+static void xen_send_IPI_mask(cpumask_t mask, enum ipi_vector vector)
+{
+ unsigned cpu;
+
+ cpus_and(mask, mask, cpu_online_map);
+
+ for_each_cpu_mask(cpu, mask)
+ xen_send_IPI_one(cpu, vector);
+}
+
+static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id)
+{
+ void (*func) (void *info) = call_data->func;
+ void *info = call_data->info;
+ int wait = call_data->wait;
+
+ /*
+ * Notify initiating CPU that I've grabbed the data and am
+ * about to execute the function
+ */
+ mb();
+ atomic_inc(&call_data->started);
+ /*
+ * At this point the info structure may be out of scope unless wait==1
+ */
+ irq_enter();
+ (*func)(info);
+ irq_exit();
+
+ if (wait) {
+ mb(); /* commit everything before setting finished */
+ atomic_inc(&call_data->finished);
+ }
+
+ return IRQ_HANDLED;
+}
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+ void *info, int wait)
+{
+ struct call_data_struct data;
+ int cpus;
+
+ /* Holding any lock stops cpus from going down. */
+ spin_lock(&call_lock);
+
+ cpu_clear(smp_processor_id(), mask);
+
+ cpus = cpus_weight(mask);
+ if (!cpus) {
+ spin_unlock(&call_lock);
+ return 0;
+ }
+
+ /* Can deadlock when called with interrupts disabled */
+ WARN_ON(irqs_disabled());
+
+ data.func = func;
+ data.info = info;
+ atomic_set(&data.started, 0);
+ data.wait = wait;
+ if (wait)
+ atomic_set(&data.finished, 0);
+
+ call_data = &data;
+ mb(); /* write everything before IPI */
+
+ /* Send a message to other CPUs and wait for them to respond */
+ xen_send_IPI_mask(mask, XEN_CALL_FUNCTION_VECTOR);
+
+ /* Make sure other vcpus get a chance to run.
+ XXX too severe? Maybe we should check the other CPU's states? */
+ HYPERVISOR_sched_op(SCHEDOP_yield, 0);
+
+ /* Wait for response */
+ while (atomic_read(&data.started) != cpus ||
+ (wait && atomic_read(&data.finished) != cpus))
+ cpu_relax();
+
+ spin_unlock(&call_lock);
+
+ return 0;
+}
diff --git a/arch/i386/xen/time.c b/arch/i386/xen/time.c
new file mode 100644
index 000000000000..dfd6db69ead5
--- /dev/null
+++ b/arch/i386/xen/time.c
@@ -0,0 +1,593 @@
+/*
+ * Xen time implementation.
+ *
+ * This is implemented in terms of a clocksource driver which uses
+ * the hypervisor clock as a nanosecond timebase, and a clockevent
+ * driver which uses the hypervisor's timer mechanism.
+ *
+ * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+
+#include "xen-ops.h"
+
+#define XEN_SHIFT 22
+
+/* Xen may fire a timer up to this many ns early */
+#define TIMER_SLOP 100000
+#define NS_PER_TICK (1000000000LL / HZ)
+
+static cycle_t xen_clocksource_read(void);
+
+/* These are perodically updated in shared_info, and then copied here. */
+struct shadow_time_info {
+ u64 tsc_timestamp; /* TSC at last update of time vals. */
+ u64 system_timestamp; /* Time, in nanosecs, since boot. */
+ u32 tsc_to_nsec_mul;
+ int tsc_shift;
+ u32 version;
+};
+
+static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
+
+/* runstate info updated by Xen */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
+
+/* snapshots of runstate info */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate_snapshot);
+
+/* unused ns of stolen and blocked time */
+static DEFINE_PER_CPU(u64, residual_stolen);
+static DEFINE_PER_CPU(u64, residual_blocked);
+
+/* return an consistent snapshot of 64-bit time/counter value */
+static u64 get64(const u64 *p)
+{
+ u64 ret;
+
+ if (BITS_PER_LONG < 64) {
+ u32 *p32 = (u32 *)p;
+ u32 h, l;
+
+ /*
+ * Read high then low, and then make sure high is
+ * still the same; this will only loop if low wraps
+ * and carries into high.
+ * XXX some clean way to make this endian-proof?
+ */
+ do {
+ h = p32[1];
+ barrier();
+ l = p32[0];
+ barrier();
+ } while (p32[1] != h);
+
+ ret = (((u64)h) << 32) | l;
+ } else
+ ret = *p;
+
+ return ret;
+}
+
+/*
+ * Runstate accounting
+ */
+static void get_runstate_snapshot(struct vcpu_runstate_info *res)
+{
+ u64 state_time;
+ struct vcpu_runstate_info *state;
+
+ BUG_ON(preemptible());
+
+ state = &__get_cpu_var(runstate);
+
+ /*
+ * The runstate info is always updated by the hypervisor on
+ * the current CPU, so there's no need to use anything
+ * stronger than a compiler barrier when fetching it.
+ */
+ do {
+ state_time = get64(&state->state_entry_time);
+ barrier();
+ *res = *state;
+ barrier();
+ } while (get64(&state->state_entry_time) != state_time);
+}
+
+static void setup_runstate_info(int cpu)
+{
+ struct vcpu_register_runstate_memory_area area;
+
+ area.addr.v = &per_cpu(runstate, cpu);
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
+ cpu, &area))
+ BUG();
+}
+
+static void do_stolen_accounting(void)
+{
+ struct vcpu_runstate_info state;
+ struct vcpu_runstate_info *snap;
+ s64 blocked, runnable, offline, stolen;
+ cputime_t ticks;
+
+ get_runstate_snapshot(&state);
+
+ WARN_ON(state.state != RUNSTATE_running);
+
+ snap = &__get_cpu_var(runstate_snapshot);
+
+ /* work out how much time the VCPU has not been runn*ing* */
+ blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
+ runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
+ offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
+
+ *snap = state;
+
+ /* Add the appropriate number of ticks of stolen time,
+ including any left-overs from last time. Passing NULL to
+ account_steal_time accounts the time as stolen. */
+ stolen = runnable + offline + __get_cpu_var(residual_stolen);
+
+ if (stolen < 0)
+ stolen = 0;
+
+ ticks = 0;
+ while (stolen >= NS_PER_TICK) {
+ ticks++;
+ stolen -= NS_PER_TICK;
+ }
+ __get_cpu_var(residual_stolen) = stolen;
+ account_steal_time(NULL, ticks);
+
+ /* Add the appropriate number of ticks of blocked time,
+ including any left-overs from last time. Passing idle to
+ account_steal_time accounts the time as idle/wait. */
+ blocked += __get_cpu_var(residual_blocked);
+
+ if (blocked < 0)
+ blocked = 0;
+
+ ticks = 0;
+ while (blocked >= NS_PER_TICK) {
+ ticks++;
+ blocked -= NS_PER_TICK;
+ }
+ __get_cpu_var(residual_blocked) = blocked;
+ account_steal_time(idle_task(smp_processor_id()), ticks);
+}
+
+/*
+ * Xen sched_clock implementation. Returns the number of unstolen
+ * nanoseconds, which is nanoseconds the VCPU spent in RUNNING+BLOCKED
+ * states.
+ */
+unsigned long long xen_sched_clock(void)
+{
+ struct vcpu_runstate_info state;
+ cycle_t now;
+ u64 ret;
+ s64 offset;
+
+ /*
+ * Ideally sched_clock should be called on a per-cpu basis
+ * anyway, so preempt should already be disabled, but that's
+ * not current practice at the moment.
+ */
+ preempt_disable();
+
+ now = xen_clocksource_read();
+
+ get_runstate_snapshot(&state);
+
+ WARN_ON(state.state != RUNSTATE_running);
+
+ offset = now - state.state_entry_time;
+ if (offset < 0)
+ offset = 0;
+
+ ret = state.time[RUNSTATE_blocked] +
+ state.time[RUNSTATE_running] +
+ offset;
+
+ preempt_enable();
+
+ return ret;
+}
+
+
+/* Get the CPU speed from Xen */
+unsigned long xen_cpu_khz(void)
+{
+ u64 cpu_khz = 1000000ULL << 32;
+ const struct vcpu_time_info *info =
+ &HYPERVISOR_shared_info->vcpu_info[0].time;
+
+ do_div(cpu_khz, info->tsc_to_system_mul);
+ if (info->tsc_shift < 0)
+ cpu_khz <<= -info->tsc_shift;
+ else
+ cpu_khz >>= info->tsc_shift;
+
+ return cpu_khz;
+}
+
+/*
+ * Reads a consistent set of time-base values from Xen, into a shadow data
+ * area.
+ */
+static unsigned get_time_values_from_xen(void)
+{
+ struct vcpu_time_info *src;
+ struct shadow_time_info *dst;
+
+ /* src is shared memory with the hypervisor, so we need to
+ make sure we get a consistent snapshot, even in the face of
+ being preempted. */
+ src = &__get_cpu_var(xen_vcpu)->time;
+ dst = &__get_cpu_var(shadow_time);
+
+ do {
+ dst->version = src->version;
+ rmb(); /* fetch version before data */
+ dst->tsc_timestamp = src->tsc_timestamp;
+ dst->system_timestamp = src->system_time;
+ dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
+ dst->tsc_shift = src->tsc_shift;
+ rmb(); /* test version after fetching data */
+ } while ((src->version & 1) | (dst->version ^ src->version));
+
+ return dst->version;
+}
+
+/*
+ * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
+ * yielding a 64-bit result.
+ */
+static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
+{
+ u64 product;
+#ifdef __i386__
+ u32 tmp1, tmp2;
+#endif
+
+ if (shift < 0)
+ delta >>= -shift;
+ else
+ delta <<= shift;
+
+#ifdef __i386__
+ __asm__ (
+ "mul %5 ; "
+ "mov %4,%%eax ; "
+ "mov %%edx,%4 ; "
+ "mul %5 ; "
+ "xor %5,%5 ; "
+ "add %4,%%eax ; "
+ "adc %5,%%edx ; "
+ : "=A" (product), "=r" (tmp1), "=r" (tmp2)
+ : "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
+#elif __x86_64__
+ __asm__ (
+ "mul %%rdx ; shrd $32,%%rdx,%%rax"
+ : "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
+#else
+#error implement me!
+#endif
+
+ return product;
+}
+
+static u64 get_nsec_offset(struct shadow_time_info *shadow)
+{
+ u64 now, delta;
+ now = native_read_tsc();
+ delta = now - shadow->tsc_timestamp;
+ return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
+}
+
+static cycle_t xen_clocksource_read(void)
+{
+ struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
+ cycle_t ret;
+ unsigned version;
+
+ do {
+ version = get_time_values_from_xen();
+ barrier();
+ ret = shadow->system_timestamp + get_nsec_offset(shadow);
+ barrier();
+ } while (version != __get_cpu_var(xen_vcpu)->time.version);
+
+ put_cpu_var(shadow_time);
+
+ return ret;
+}
+
+static void xen_read_wallclock(struct timespec *ts)
+{
+ const struct shared_info *s = HYPERVISOR_shared_info;
+ u32 version;
+ u64 delta;
+ struct timespec now;
+
+ /* get wallclock at system boot */
+ do {
+ version = s->wc_version;
+ rmb(); /* fetch version before time */
+ now.tv_sec = s->wc_sec;
+ now.tv_nsec = s->wc_nsec;
+ rmb(); /* fetch time before checking version */
+ } while ((s->wc_version & 1) | (version ^ s->wc_version));
+
+ delta = xen_clocksource_read(); /* time since system boot */
+ delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;
+
+ now.tv_nsec = do_div(delta, NSEC_PER_SEC);
+ now.tv_sec = delta;
+
+ set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
+}
+
+unsigned long xen_get_wallclock(void)
+{
+ struct timespec ts;
+
+ xen_read_wallclock(&ts);
+
+ return ts.tv_sec;
+}
+
+int xen_set_wallclock(unsigned long now)
+{
+ /* do nothing for domU */
+ return -1;
+}
+
+static struct clocksource xen_clocksource __read_mostly = {
+ .name = "xen",
+ .rating = 400,
+ .read = xen_clocksource_read,
+ .mask = ~0,
+ .mult = 1<<XEN_SHIFT, /* time directly in nanoseconds */
+ .shift = XEN_SHIFT,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ Xen clockevent implementation
+
+ Xen has two clockevent implementations:
+
+ The old timer_op one works with all released versions of Xen prior
+ to version 3.0.4. This version of the hypervisor provides a
+ single-shot timer with nanosecond resolution. However, sharing the
+ same event channel is a 100Hz tick which is delivered while the
+ vcpu is running. We don't care about or use this tick, but it will
+ cause the core time code to think the timer fired too soon, and
+ will end up resetting it each time. It could be filtered, but
+ doing so has complications when the ktime clocksource is not yet
+ the xen clocksource (ie, at boot time).
+
+ The new vcpu_op-based timer interface allows the tick timer period
+ to be changed or turned off. The tick timer is not useful as a
+ periodic timer because events are only delivered to running vcpus.
+ The one-shot timer can report when a timeout is in the past, so
+ set_next_event is capable of returning -ETIME when appropriate.
+ This interface is used when available.
+*/
+
+
+/*
+ Get a hypervisor absolute time. In theory we could maintain an
+ offset between the kernel's time and the hypervisor's time, and
+ apply that to a kernel's absolute timeout. Unfortunately the
+ hypervisor and kernel times can drift even if the kernel is using
+ the Xen clocksource, because ntp can warp the kernel's clocksource.
+*/
+static s64 get_abs_timeout(unsigned long delta)
+{
+ return xen_clocksource_read() + delta;
+}
+
+static void xen_timerop_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* unsupported */
+ WARN_ON(1);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ HYPERVISOR_set_timer_op(0); /* cancel timeout */
+ break;
+ }
+}
+
+static int xen_timerop_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ if (HYPERVISOR_set_timer_op(get_abs_timeout(delta)) < 0)
+ BUG();
+
+ /* We may have missed the deadline, but there's no real way of
+ knowing for sure. If the event was in the past, then we'll
+ get an immediate interrupt. */
+
+ return 0;
+}
+
+static const struct clock_event_device xen_timerop_clockevent = {
+ .name = "xen",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+
+ .max_delta_ns = 0xffffffff,
+ .min_delta_ns = TIMER_SLOP,
+
+ .mult = 1,
+ .shift = 0,
+ .rating = 500,
+
+ .set_mode = xen_timerop_set_mode,
+ .set_next_event = xen_timerop_set_next_event,
+};
+
+
+
+static void xen_vcpuop_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ int cpu = smp_processor_id();
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ WARN_ON(1); /* unsupported */
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+ BUG();
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, cpu, NULL) ||
+ HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+ BUG();
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static int xen_vcpuop_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ int cpu = smp_processor_id();
+ struct vcpu_set_singleshot_timer single;
+ int ret;
+
+ WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ single.timeout_abs_ns = get_abs_timeout(delta);
+ single.flags = VCPU_SSHOTTMR_future;
+
+ ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
+
+ BUG_ON(ret != 0 && ret != -ETIME);
+
+ return ret;
+}
+
+static const struct clock_event_device xen_vcpuop_clockevent = {
+ .name = "xen",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+
+ .max_delta_ns = 0xffffffff,
+ .min_delta_ns = TIMER_SLOP,
+
+ .mult = 1,
+ .shift = 0,
+ .rating = 500,
+
+ .set_mode = xen_vcpuop_set_mode,
+ .set_next_event = xen_vcpuop_set_next_event,
+};
+
+static const struct clock_event_device *xen_clockevent =
+ &xen_timerop_clockevent;
+static DEFINE_PER_CPU(struct clock_event_device, xen_clock_events);
+
+static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &__get_cpu_var(xen_clock_events);
+ irqreturn_t ret;
+
+ ret = IRQ_NONE;
+ if (evt->event_handler) {
+ evt->event_handler(evt);
+ ret = IRQ_HANDLED;
+ }
+
+ do_stolen_accounting();
+
+ return ret;
+}
+
+void xen_setup_timer(int cpu)
+{
+ const char *name;
+ struct clock_event_device *evt;
+ int irq;
+
+ printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
+
+ name = kasprintf(GFP_KERNEL, "timer%d", cpu);
+ if (!name)
+ name = "<timer kasprintf failed>";
+
+ irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
+ IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+ name, NULL);
+
+ evt = &per_cpu(xen_clock_events, cpu);
+ memcpy(evt, xen_clockevent, sizeof(*evt));
+
+ evt->cpumask = cpumask_of_cpu(cpu);
+ evt->irq = irq;
+
+ setup_runstate_info(cpu);
+}
+
+void xen_setup_cpu_clockevents(void)
+{
+ BUG_ON(preemptible());
+
+ clockevents_register_device(&__get_cpu_var(xen_clock_events));
+}
+
+__init void xen_time_init(void)
+{
+ int cpu = smp_processor_id();
+
+ get_time_values_from_xen();
+
+ clocksource_register(&xen_clocksource);
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
+ /* Successfully turned off 100Hz tick, so we have the
+ vcpuop-based timer interface */
+ printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
+ xen_clockevent = &xen_vcpuop_clockevent;
+ }
+
+ /* Set initial system time with full resolution */
+ xen_read_wallclock(&xtime);
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+
+ tsc_disable = 0;
+
+ xen_setup_timer(cpu);
+ xen_setup_cpu_clockevents();
+}
diff --git a/arch/i386/xen/vdso.h b/arch/i386/xen/vdso.h
new file mode 100644
index 000000000000..861fedfe5230
--- /dev/null
+++ b/arch/i386/xen/vdso.h
@@ -0,0 +1,4 @@
+/* Bit used for the pseudo-hwcap for non-negative segments. We use
+ bit 1 to avoid bugs in some versions of glibc when bit 0 is
+ used; the choice is otherwise arbitrary. */
+#define VDSO_NOTE_NONEGSEG_BIT 1
diff --git a/arch/i386/xen/xen-asm.S b/arch/i386/xen/xen-asm.S
new file mode 100644
index 000000000000..1a43b60c0c62
--- /dev/null
+++ b/arch/i386/xen/xen-asm.S
@@ -0,0 +1,291 @@
+/*
+ Asm versions of Xen pv-ops, suitable for either direct use or inlining.
+ The inline versions are the same as the direct-use versions, with the
+ pre- and post-amble chopped off.
+
+ This code is encoded for size rather than absolute efficiency,
+ with a view to being able to inline as much as possible.
+
+ We only bother with direct forms (ie, vcpu in pda) of the operations
+ here; the indirect forms are better handled in C, since they're
+ generally too large to inline anyway.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/percpu.h>
+#include <asm/processor-flags.h>
+#include <asm/segment.h>
+
+#include <xen/interface/xen.h>
+
+#define RELOC(x, v) .globl x##_reloc; x##_reloc=v
+#define ENDPATCH(x) .globl x##_end; x##_end=.
+
+/* Pseudo-flag used for virtual NMI, which we don't implement yet */
+#define XEN_EFLAGS_NMI 0x80000000
+
+/*
+ Enable events. This clears the event mask and tests the pending
+ event status with one and operation. If there are pending
+ events, then enter the hypervisor to get them handled.
+ */
+ENTRY(xen_irq_enable_direct)
+ /* Clear mask and test pending */
+ andw $0x00ff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+ /* Preempt here doesn't matter because that will deal with
+ any pending interrupts. The pending check may end up being
+ run on the wrong CPU, but that doesn't hurt. */
+ jz 1f
+2: call check_events
+1:
+ENDPATCH(xen_irq_enable_direct)
+ ret
+ ENDPROC(xen_irq_enable_direct)
+ RELOC(xen_irq_enable_direct, 2b+1)
+
+
+/*
+ Disabling events is simply a matter of making the event mask
+ non-zero.
+ */
+ENTRY(xen_irq_disable_direct)
+ movb $1, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ENDPATCH(xen_irq_disable_direct)
+ ret
+ ENDPROC(xen_irq_disable_direct)
+ RELOC(xen_irq_disable_direct, 0)
+
+/*
+ (xen_)save_fl is used to get the current interrupt enable status.
+ Callers expect the status to be in X86_EFLAGS_IF, and other bits
+ may be set in the return value. We take advantage of this by
+ making sure that X86_EFLAGS_IF has the right value (and other bits
+ in that byte are 0), but other bits in the return value are
+ undefined. We need to toggle the state of the bit, because
+ Xen and x86 use opposite senses (mask vs enable).
+ */
+ENTRY(xen_save_fl_direct)
+ testb $0xff, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ setz %ah
+ addb %ah,%ah
+ENDPATCH(xen_save_fl_direct)
+ ret
+ ENDPROC(xen_save_fl_direct)
+ RELOC(xen_save_fl_direct, 0)
+
+
+/*
+ In principle the caller should be passing us a value return
+ from xen_save_fl_direct, but for robustness sake we test only
+ the X86_EFLAGS_IF flag rather than the whole byte. After
+ setting the interrupt mask state, it checks for unmasked
+ pending events and enters the hypervisor to get them delivered
+ if so.
+ */
+ENTRY(xen_restore_fl_direct)
+ testb $X86_EFLAGS_IF>>8, %ah
+ setz PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_mask
+ /* Preempt here doesn't matter because that will deal with
+ any pending interrupts. The pending check may end up being
+ run on the wrong CPU, but that doesn't hurt. */
+
+ /* check for unmasked and pending */
+ cmpw $0x0001, PER_CPU_VAR(xen_vcpu_info)+XEN_vcpu_info_pending
+ jz 1f
+2: call check_events
+1:
+ENDPATCH(xen_restore_fl_direct)
+ ret
+ ENDPROC(xen_restore_fl_direct)
+ RELOC(xen_restore_fl_direct, 2b+1)
+
+/*
+ This is run where a normal iret would be run, with the same stack setup:
+ 8: eflags
+ 4: cs
+ esp-> 0: eip
+
+ This attempts to make sure that any pending events are dealt
+ with on return to usermode, but there is a small window in
+ which an event can happen just before entering usermode. If
+ the nested interrupt ends up setting one of the TIF_WORK_MASK
+ pending work flags, they will not be tested again before
+ returning to usermode. This means that a process can end up
+ with pending work, which will be unprocessed until the process
+ enters and leaves the kernel again, which could be an
+ unbounded amount of time. This means that a pending signal or
+ reschedule event could be indefinitely delayed.
+
+ The fix is to notice a nested interrupt in the critical
+ window, and if one occurs, then fold the nested interrupt into
+ the current interrupt stack frame, and re-process it
+ iteratively rather than recursively. This means that it will
+ exit via the normal path, and all pending work will be dealt
+ with appropriately.
+
+ Because the nested interrupt handler needs to deal with the
+ current stack state in whatever form its in, we keep things
+ simple by only using a single register which is pushed/popped
+ on the stack.
+
+ Non-direct iret could be done in the same way, but it would
+ require an annoying amount of code duplication. We'll assume
+ that direct mode will be the common case once the hypervisor
+ support becomes commonplace.
+ */
+ENTRY(xen_iret_direct)
+ /* test eflags for special cases */
+ testl $(X86_EFLAGS_VM | XEN_EFLAGS_NMI), 8(%esp)
+ jnz hyper_iret
+
+ push %eax
+ ESP_OFFSET=4 # bytes pushed onto stack
+
+ /* Store vcpu_info pointer for easy access. Do it this
+ way to avoid having to reload %fs */
+#ifdef CONFIG_SMP
+ GET_THREAD_INFO(%eax)
+ movl TI_cpu(%eax),%eax
+ movl __per_cpu_offset(,%eax,4),%eax
+ lea per_cpu__xen_vcpu_info(%eax),%eax
+#else
+ movl $per_cpu__xen_vcpu_info, %eax
+#endif
+
+ /* check IF state we're restoring */
+ testb $X86_EFLAGS_IF>>8, 8+1+ESP_OFFSET(%esp)
+
+ /* Maybe enable events. Once this happens we could get a
+ recursive event, so the critical region starts immediately
+ afterwards. However, if that happens we don't end up
+ resuming the code, so we don't have to be worried about
+ being preempted to another CPU. */
+ setz XEN_vcpu_info_mask(%eax)
+xen_iret_start_crit:
+
+ /* check for unmasked and pending */
+ cmpw $0x0001, XEN_vcpu_info_pending(%eax)
+
+ /* If there's something pending, mask events again so we
+ can jump back into xen_hypervisor_callback */
+ sete XEN_vcpu_info_mask(%eax)
+
+ popl %eax
+
+ /* From this point on the registers are restored and the stack
+ updated, so we don't need to worry about it if we're preempted */
+iret_restore_end:
+
+ /* Jump to hypervisor_callback after fixing up the stack.
+ Events are masked, so jumping out of the critical
+ region is OK. */
+ je xen_hypervisor_callback
+
+ iret
+xen_iret_end_crit:
+
+hyper_iret:
+ /* put this out of line since its very rarely used */
+ jmp hypercall_page + __HYPERVISOR_iret * 32
+
+ .globl xen_iret_start_crit, xen_iret_end_crit
+
+/*
+ This is called by xen_hypervisor_callback in entry.S when it sees
+ that the EIP at the time of interrupt was between xen_iret_start_crit
+ and xen_iret_end_crit. We're passed the EIP in %eax so we can do
+ a more refined determination of what to do.
+
+ The stack format at this point is:
+ ----------------
+ ss : (ss/esp may be present if we came from usermode)
+ esp :
+ eflags } outer exception info
+ cs }
+ eip }
+ ---------------- <- edi (copy dest)
+ eax : outer eax if it hasn't been restored
+ ----------------
+ eflags } nested exception info
+ cs } (no ss/esp because we're nested
+ eip } from the same ring)
+ orig_eax }<- esi (copy src)
+ - - - - - - - -
+ fs }
+ es }
+ ds } SAVE_ALL state
+ eax }
+ : :
+ ebx }
+ ----------------
+ return addr <- esp
+ ----------------
+
+ In order to deliver the nested exception properly, we need to shift
+ everything from the return addr up to the error code so it
+ sits just under the outer exception info. This means that when we
+ handle the exception, we do it in the context of the outer exception
+ rather than starting a new one.
+
+ The only caveat is that if the outer eax hasn't been
+ restored yet (ie, it's still on stack), we need to insert
+ its value into the SAVE_ALL state before going on, since
+ 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.
+ 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?
+ Definitely. Easy to avoid? Yes. The Intel documents
+ explicitly say that the reported EIP for a bad jump is the
+ jump instruction itself, not the destination, but some virtual
+ environments get this wrong.
+ */
+ movl PT_CS+4(%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
+
+ /* 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)
+
+ 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 */
+ rep movsl
+ cld
+
+ lea 4(%edi),%esp /* point esp to new frame */
+2: ret
+
+
+/*
+ Force an event check by making a hypercall,
+ but preserve regs before making the call.
+ */
+check_events:
+ push %eax
+ push %ecx
+ push %edx
+ call force_evtchn_callback
+ pop %edx
+ pop %ecx
+ pop %eax
+ ret
diff --git a/arch/i386/xen/xen-head.S b/arch/i386/xen/xen-head.S
new file mode 100644
index 000000000000..bc71f3bc4014
--- /dev/null
+++ b/arch/i386/xen/xen-head.S
@@ -0,0 +1,38 @@
+/* Xen-specific pieces of head.S, intended to be included in the right
+ place in head.S */
+
+#ifdef CONFIG_XEN
+
+#include <linux/elfnote.h>
+#include <asm/boot.h>
+#include <xen/interface/elfnote.h>
+
+ .section .init.text
+ENTRY(startup_xen)
+ movl %esi,xen_start_info
+ cld
+ movl $(init_thread_union+THREAD_SIZE),%esp
+ jmp xen_start_kernel
+
+.pushsection ".bss.page_aligned"
+ .align PAGE_SIZE_asm
+ENTRY(hypercall_page)
+ .skip 0x1000
+.popsection
+
+ .section .text
+ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_OS, .asciz "linux")
+ ELFNOTE(Xen, XEN_ELFNOTE_GUEST_VERSION, .asciz "2.6")
+ ELFNOTE(Xen, XEN_ELFNOTE_XEN_VERSION, .asciz "xen-3.0")
+ ELFNOTE(Xen, XEN_ELFNOTE_VIRT_BASE, .long __PAGE_OFFSET)
+ ELFNOTE(Xen, XEN_ELFNOTE_ENTRY, .long startup_xen)
+ ELFNOTE(Xen, XEN_ELFNOTE_HYPERCALL_PAGE, .long hypercall_page)
+ ELFNOTE(Xen, XEN_ELFNOTE_FEATURES, .asciz "!writable_page_tables|pae_pgdir_above_4gb")
+#ifdef CONFIG_X86_PAE
+ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "yes")
+#else
+ ELFNOTE(Xen, XEN_ELFNOTE_PAE_MODE, .asciz "no")
+#endif
+ ELFNOTE(Xen, XEN_ELFNOTE_LOADER, .asciz "generic")
+
+#endif /*CONFIG_XEN */
diff --git a/arch/i386/xen/xen-ops.h b/arch/i386/xen/xen-ops.h
new file mode 100644
index 000000000000..b9aaea45f07f
--- /dev/null
+++ b/arch/i386/xen/xen-ops.h
@@ -0,0 +1,71 @@
+#ifndef XEN_OPS_H
+#define XEN_OPS_H
+
+#include <linux/init.h>
+
+/* These are code, but not functions. Defined in entry.S */
+extern const char xen_hypervisor_callback[];
+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);
+
+extern struct start_info *xen_start_info;
+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_setup_timer(int cpu);
+void xen_setup_cpu_clockevents(void);
+unsigned long xen_cpu_khz(void);
+void __init xen_time_init(void);
+unsigned long xen_get_wallclock(void);
+int xen_set_wallclock(unsigned long time);
+unsigned long long xen_sched_clock(void);
+
+void xen_mark_init_mm_pinned(void);
+
+DECLARE_PER_CPU(enum paravirt_lazy_mode, xen_lazy_mode);
+
+static inline unsigned xen_get_lazy_mode(void)
+{
+ return x86_read_percpu(xen_lazy_mode);
+}
+
+void __init xen_fill_possible_map(void);
+
+void __init xen_setup_vcpu_info_placement(void);
+void xen_smp_prepare_boot_cpu(void);
+void xen_smp_prepare_cpus(unsigned int max_cpus);
+int xen_cpu_up(unsigned int cpu);
+void xen_smp_cpus_done(unsigned int max_cpus);
+
+void xen_smp_send_stop(void);
+void xen_smp_send_reschedule(int cpu);
+int xen_smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+ int wait);
+int xen_smp_call_function_single(int cpu, void (*func) (void *info), void *info,
+ int nonatomic, int wait);
+
+int xen_smp_call_function_mask(cpumask_t mask, void (*func)(void *),
+ void *info, int wait);
+
+
+/* Declare an asm function, along with symbols needed to make it
+ inlineable */
+#define DECL_ASM(ret, name, ...) \
+ ret name(__VA_ARGS__); \
+ extern char name##_end[]; \
+ extern char name##_reloc[] \
+
+DECL_ASM(void, xen_irq_enable_direct, void);
+DECL_ASM(void, xen_irq_disable_direct, void);
+DECL_ASM(unsigned long, xen_save_fl_direct, void);
+DECL_ASM(void, xen_restore_fl_direct, unsigned long);
+
+void xen_iret_direct(void);
+#endif /* XEN_OPS_H */
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index de1bff659969..36c7b9682aa6 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -62,7 +62,11 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
-config TIME_INTERPOLATION
+config GENERIC_TIME
+ bool
+ default y
+
+config GENERIC_TIME_VSYSCALL
bool
default y
@@ -520,8 +524,10 @@ config PCI
here unless you are using a simulator without PCI support.
config PCI_DOMAINS
- bool
- default PCI
+ def_bool PCI
+
+config PCI_SYSCALL
+ def_bool PCI
source "drivers/pci/pcie/Kconfig"
@@ -580,8 +586,8 @@ menu "Instrumentation Support"
source "arch/ia64/oprofile/Kconfig"
config KPROBES
- bool "Kprobes (EXPERIMENTAL)"
- depends on KALLSYMS && EXPERIMENTAL && MODULES
+ bool "Kprobes"
+ depends on KALLSYMS && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig
index 90e9c2e61bf4..9eb48c0927b0 100644
--- a/arch/ia64/configs/bigsur_defconfig
+++ b/arch/ia64/configs/bigsur_defconfig
@@ -85,7 +85,7 @@ CONFIG_MMU=y
CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig
index 0d29aa2066b3..3a9ed951db08 100644
--- a/arch/ia64/configs/gensparse_defconfig
+++ b/arch/ia64/configs/gensparse_defconfig
@@ -86,7 +86,7 @@ CONFIG_MMU=y
CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/sim_defconfig b/arch/ia64/configs/sim_defconfig
index d9146c31ea13..c420d9f3df98 100644
--- a/arch/ia64/configs/sim_defconfig
+++ b/arch/ia64/configs/sim_defconfig
@@ -86,7 +86,7 @@ CONFIG_MMU=y
CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
index 64e951de4e57..4c9ffc47bc7a 100644
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -93,7 +93,7 @@ CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
CONFIG_DMI=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index a1446931b401..3dbb3987df27 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar 8 11:07:09 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:54:47 2007
#
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -19,15 +19,15 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=20
# CONFIG_CPUSETS is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
@@ -46,18 +46,19 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@ CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -91,6 +89,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_IA64=y
CONFIG_64BIT=y
CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
CONFIG_DMI=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@ CONFIG_IA64_DIG=y
CONFIG_MCKINLEY=y
# CONFIG_IA64_PAGE_SIZE_4KB is not set
# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
CONFIG_PGTABLE_3=y
# CONFIG_PGTABLE_4 is not set
# CONFIG_HZ_100 is not set
@@ -145,6 +144,9 @@ CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -152,11 +154,11 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_VIRTUAL_MEM_MAP=y
CONFIG_HOLES_IN_ZONE=y
-CONFIG_IA32_SUPPORT=y
-CONFIG_COMPAT=y
+# CONFIG_IA32_SUPPORT is not set
CONFIG_IA64_MCA_RECOVERY=y
CONFIG_PERFMON=y
CONFIG_IA64_PALINFO=y
+# CONFIG_IA64_MC_ERR_INJECT is not set
# CONFIG_IA64_ESI is not set
CONFIG_KEXEC=y
# CONFIG_CRASH_DUMP is not set
@@ -166,6 +168,7 @@ CONFIG_KEXEC=y
#
CONFIG_EFI_VARS=y
CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
@@ -175,7 +178,6 @@ CONFIG_BINFMT_MISC=m
CONFIG_PM=y
CONFIG_PM_LEGACY=y
# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
#
# ACPI (Advanced Configuration and Power Interface) Support
@@ -205,13 +207,11 @@ CONFIG_ACPI_CONTAINER=m
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
# CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
CONFIG_HOTPLUG_PCI=m
# CONFIG_HOTPLUG_PCI_FAKE is not set
CONFIG_HOTPLUG_PCI_ACPI=m
@@ -232,7 +232,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -270,20 +269,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -309,7 +296,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -324,25 +321,9 @@ CONFIG_FW_LOADER=m
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
CONFIG_PNP=y
# CONFIG_PNP_DEBUG is not set
@@ -350,10 +331,7 @@ CONFIG_PNP=y
# Protocols
#
CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -370,16 +348,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
CONFIG_IDE=y
CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
@@ -396,6 +369,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
CONFIG_BLK_DEV_IDESCSI=m
# CONFIG_BLK_DEV_IDEACPI is not set
# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
#
# IDE chipset support/bugfixes
@@ -404,12 +378,12 @@ CONFIG_BLK_DEV_IDESCSI=m
# CONFIG_BLK_DEV_IDEPNP is not set
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_IDEPCI_PCIBUS_ORDER=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -438,7 +412,6 @@ CONFIG_BLK_DEV_PIIX=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -446,6 +419,7 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -468,6 +442,7 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -514,15 +489,7 @@ CONFIG_SCSI_QLOGIC_1280=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
@@ -539,6 +506,7 @@ CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m
# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
#
# Fusion MPT device support
@@ -553,46 +521,25 @@ CONFIG_FUSION_CTL=y
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=m
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
CONFIG_NET_TULIP=y
# CONFIG_DE2104X is not set
CONFIG_TULIP=m
@@ -623,10 +570,7 @@ CONFIG_E100=m
# CONFIG_SUNDANCE is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
CONFIG_E1000=y
@@ -639,36 +583,36 @@ CONFIG_E1000=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=y
# CONFIG_BNX2 is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
-# Wan interfaces
+# USB Network Adapters
#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -678,18 +622,9 @@ CONFIG_TIGON3=y
# CONFIG_SHAPER is not set
CONFIG_NETCONSOLE=y
CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
# CONFIG_NETPOLL_TRAP is not set
CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -697,6 +632,7 @@ CONFIG_NET_POLL_CONTROLLER=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -722,9 +658,17 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -790,19 +734,10 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
CONFIG_AGP=m
@@ -821,15 +756,8 @@ CONFIG_HPET=y
# CONFIG_HPET_RTC_IRQ is not set
CONFIG_HPET_MMAP=y
# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -837,21 +765,17 @@ CONFIG_HPET_MMAP=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -863,17 +787,20 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
# CONFIG_USB_DABUSB is not set
#
# Graphics support
#
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
# CONFIG_FB is not set
#
@@ -887,16 +814,18 @@ CONFIG_DUMMY_CONSOLE=y
# Sound
#
# CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
#
-# USB support
+# USB Input Devices
#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -907,8 +836,10 @@ CONFIG_USB=y
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
# CONFIG_USB_OTG is not set
#
@@ -918,7 +849,6 @@ CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=m
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -926,6 +856,7 @@ CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
#
# USB Device Class drivers
@@ -955,41 +886,10 @@ CONFIG_USB_STORAGE=m
# CONFIG_USB_LIBUSUAL is not set
#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
-#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
# CONFIG_USB_MON is not set
#
@@ -1033,10 +933,6 @@ CONFIG_USB_HID=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -1051,17 +947,9 @@ CONFIG_USB_HID=y
#
# 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
@@ -1080,12 +968,9 @@ CONFIG_USB_HID=y
#
#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
#
+# CONFIG_UIO is not set
# CONFIG_MSPEC is not set
#
@@ -1200,7 +1085,8 @@ CONFIG_EXPORTFS=m
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=m
CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
CONFIG_SMB_FS=m
CONFIG_SMB_NLS_DEFAULT=y
@@ -1214,7 +1100,6 @@ CONFIG_CIFS=m
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -1236,6 +1121,7 @@ CONFIG_SGI_PARTITION=y
# CONFIG_SUN_PARTITION is not set
# CONFIG_KARMA_PARTITION is not set
CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
#
# Native Language Support
@@ -1292,11 +1178,14 @@ CONFIG_NLS_UTF8=m
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_PENDING_IRQ=y
@@ -1319,8 +1208,8 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_SLAB is not set
@@ -1343,17 +1232,12 @@ CONFIG_IA64_GRANULE_16MB=y
# CONFIG_DISABLE_VHPT is not set
# CONFIG_IA64_DEBUG_CMPXCHG is not set
# CONFIG_IA64_DEBUG_IRQ is not set
-CONFIG_SYSVIPC_COMPAT=y
#
# Security options
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=m
@@ -1373,6 +1257,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
@@ -1390,7 +1275,4 @@ CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
index 1c7955c16358..4a060fc39934 100644
--- a/arch/ia64/configs/zx1_defconfig
+++ b/arch/ia64/configs/zx1_defconfig
@@ -96,7 +96,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
CONFIG_DMI=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 90bd9601cdde..03172dc8c403 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Thu Mar 8 11:01:03 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 13:55:32 2007
#
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -19,15 +19,15 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=20
# CONFIG_CPUSETS is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
@@ -46,18 +46,19 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -65,12 +66,9 @@ CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -91,6 +89,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_IA64=y
CONFIG_64BIT=y
CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_SWIOTLB=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
@@ -98,7 +97,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_TIME_INTERPOLATION=y
+CONFIG_GENERIC_TIME=y
CONFIG_DMI=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
@@ -114,8 +113,8 @@ CONFIG_IA64_GENERIC=y
CONFIG_MCKINLEY=y
# CONFIG_IA64_PAGE_SIZE_4KB is not set
# CONFIG_IA64_PAGE_SIZE_8KB is not set
-CONFIG_IA64_PAGE_SIZE_16KB=y
-# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_IA64_PAGE_SIZE_16KB is not set
+CONFIG_IA64_PAGE_SIZE_64KB=y
CONFIG_PGTABLE_3=y
# CONFIG_PGTABLE_4 is not set
# CONFIG_HZ_100 is not set
@@ -147,6 +146,9 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -164,7 +166,7 @@ CONFIG_COMPAT=y
CONFIG_IA64_MCA_RECOVERY=y
CONFIG_PERFMON=y
CONFIG_IA64_PALINFO=y
-# CONFIG_MC_ERR_INJECT is not set
+# CONFIG_IA64_MC_ERR_INJECT is not set
CONFIG_SGI_SN=y
# CONFIG_IA64_ESI is not set
@@ -180,6 +182,7 @@ CONFIG_CRASH_DUMP=y
#
CONFIG_EFI_VARS=y
CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
@@ -189,7 +192,6 @@ CONFIG_BINFMT_MISC=m
CONFIG_PM=y
CONFIG_PM_LEGACY=y
# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
#
# ACPI (Advanced Configuration and Power Interface) Support
@@ -220,13 +222,11 @@ CONFIG_ACPI_CONTAINER=m
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
# CONFIG_PCI_MSI is not set
# CONFIG_PCI_DEBUG is not set
-
-#
-# PCI Hotplug Support
-#
CONFIG_HOTPLUG_PCI=m
# CONFIG_HOTPLUG_PCI_FAKE is not set
CONFIG_HOTPLUG_PCI_ACPI=m
@@ -248,7 +248,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -286,20 +285,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -325,7 +312,17 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -340,25 +337,9 @@ CONFIG_FW_LOADER=m
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
CONFIG_PNP=y
# CONFIG_PNP_DEBUG is not set
@@ -366,10 +347,7 @@ CONFIG_PNP=y
# Protocols
#
CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -386,16 +364,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
CONFIG_SGI_IOC4=y
# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
CONFIG_IDE=y
CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
@@ -412,6 +385,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
CONFIG_BLK_DEV_IDESCSI=m
# CONFIG_BLK_DEV_IDEACPI is not set
# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
#
# IDE chipset support/bugfixes
@@ -420,12 +394,12 @@ CONFIG_BLK_DEV_IDESCSI=m
# CONFIG_BLK_DEV_IDEPNP is not set
CONFIG_BLK_DEV_IDEPCI=y
CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
# CONFIG_BLK_DEV_OFFBOARD is not set
CONFIG_BLK_DEV_GENERIC=y
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -455,7 +429,6 @@ CONFIG_BLK_DEV_SGIIOC4=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -463,6 +436,7 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -485,6 +459,7 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -492,7 +467,7 @@ CONFIG_CHR_DEV_SG=m
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=y
# CONFIG_SCSI_SAS_LIBSAS is not set
#
@@ -531,15 +506,7 @@ CONFIG_SCSI_QLOGIC_1280=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
@@ -557,6 +524,8 @@ CONFIG_DM_MIRROR=m
CONFIG_DM_ZERO=m
CONFIG_DM_MULTIPATH=m
# CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
+# CONFIG_DM_DELAY is not set
#
# Fusion MPT device support
@@ -564,53 +533,32 @@ CONFIG_DM_MULTIPATH=m
CONFIG_FUSION=y
CONFIG_FUSION_SPI=y
CONFIG_FUSION_FC=m
-# CONFIG_FUSION_SAS is not set
+CONFIG_FUSION_SAS=y
CONFIG_FUSION_MAX_SGE=128
# CONFIG_FUSION_CTL is not set
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=m
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
-
-#
-# Tulip family network device support
-#
CONFIG_NET_TULIP=y
# CONFIG_DE2104X is not set
CONFIG_TULIP=m
@@ -641,10 +589,7 @@ CONFIG_E100=m
# CONFIG_SUNDANCE is not set
# CONFIG_VIA_RHINE is not set
# CONFIG_SC92031 is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
CONFIG_E1000=y
@@ -657,36 +602,36 @@ CONFIG_E1000=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=y
# CONFIG_BNX2 is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
-# Wan interfaces
+# USB Network Adapters
#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_USBNET is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -696,18 +641,9 @@ CONFIG_TIGON3=y
# CONFIG_SHAPER is not set
CONFIG_NETCONSOLE=y
CONFIG_NETPOLL=y
-# CONFIG_NETPOLL_RX is not set
# CONFIG_NETPOLL_TRAP is not set
CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -715,6 +651,7 @@ CONFIG_NET_POLL_CONTROLLER=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -740,9 +677,17 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -814,19 +759,10 @@ CONFIG_SERIAL_SGI_IOC4=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
CONFIG_EFI_RTC=y
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
CONFIG_AGP=m
@@ -848,15 +784,8 @@ CONFIG_HPET=y
CONFIG_HPET_MMAP=y
# CONFIG_HANGCHECK_TIMER is not set
CONFIG_MMTIMER=y
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -864,21 +793,17 @@ CONFIG_MMTIMER=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -890,17 +815,20 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
# CONFIG_USB_DABUSB is not set
#
# Graphics support
#
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
# CONFIG_FB is not set
#
@@ -1014,9 +942,10 @@ CONFIG_SND_FM801=m
# USB devices
#
# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
#
-# SoC audio support
+# System on Chip audio support
#
# CONFIG_SND_SOC is not set
@@ -1025,16 +954,24 @@ CONFIG_SND_FM801=m
#
# CONFIG_SOUND_PRIME is not set
CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
#
-# HID Devices
+# USB Input Devices
#
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
#
-# USB support
+# USB HID Boot Protocol drivers
#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1045,8 +982,10 @@ CONFIG_USB=m
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
# CONFIG_USB_OTG is not set
#
@@ -1056,7 +995,6 @@ CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=m
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1064,6 +1002,7 @@ CONFIG_USB_OHCI_HCD=m
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=m
# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
#
# USB Device Class drivers
@@ -1093,47 +1032,10 @@ CONFIG_USB_STORAGE=m
# CONFIG_USB_LIBUSUAL is not set
#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
-# CONFIG_USB_AIPTEK is not set
-# CONFIG_USB_WACOM is not set
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
-#
# USB Imaging devices
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
-
-#
-# USB Network Adapters
-#
-# CONFIG_USB_CATC is not set
-# CONFIG_USB_KAWETH is not set
-# CONFIG_USB_PEGASUS is not set
-# CONFIG_USB_RTL8150 is not set
-# CONFIG_USB_USBNET_MII is not set
-# CONFIG_USB_USBNET is not set
CONFIG_USB_MON=y
#
@@ -1177,10 +1079,6 @@ CONFIG_USB_MON=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -1195,10 +1093,6 @@ CONFIG_USB_MON=y
#
# LED Triggers
#
-
-#
-# InfiniBand support
-#
CONFIG_INFINIBAND=m
# CONFIG_INFINIBAND_USER_MAD is not set
# CONFIG_INFINIBAND_USER_ACCESS is not set
@@ -1206,6 +1100,7 @@ CONFIG_INFINIBAND_ADDR_TRANS=y
CONFIG_INFINIBAND_MTHCA=m
CONFIG_INFINIBAND_MTHCA_DEBUG=y
# CONFIG_INFINIBAND_AMSO1100 is not set
+# CONFIG_MLX4_INFINIBAND is not set
CONFIG_INFINIBAND_IPOIB=m
# CONFIG_INFINIBAND_IPOIB_CM is not set
CONFIG_INFINIBAND_IPOIB_DEBUG=y
@@ -1214,10 +1109,6 @@ CONFIG_INFINIBAND_IPOIB_DEBUG=y
# CONFIG_INFINIBAND_ISER is not set
#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
# Real Time Clock
#
# CONFIG_RTC_CLASS is not set
@@ -1236,12 +1127,9 @@ CONFIG_INFINIBAND_IPOIB_DEBUG=y
#
#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
#
+# CONFIG_UIO is not set
# CONFIG_MSPEC is not set
#
@@ -1357,7 +1245,8 @@ CONFIG_EXPORTFS=m
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=m
CONFIG_SUNRPC_GSS=m
-CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
CONFIG_SMB_FS=m
CONFIG_SMB_NLS_DEFAULT=y
@@ -1371,7 +1260,6 @@ CONFIG_CIFS=m
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -1393,6 +1281,7 @@ CONFIG_SGI_PARTITION=y
# CONFIG_SUN_PARTITION is not set
# CONFIG_KARMA_PARTITION is not set
CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
#
# Native Language Support
@@ -1449,11 +1338,14 @@ CONFIG_NLS_UTF8=m
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_PENDING_IRQ=y
@@ -1483,8 +1375,8 @@ CONFIG_MAGIC_SYSRQ=y
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=20
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_SLAB is not set
@@ -1514,10 +1406,6 @@ CONFIG_SYSVIPC_COMPAT=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=m
@@ -1537,6 +1425,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
@@ -1554,7 +1443,4 @@ CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_CAMELLIA is not set
# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index c1dca226b479..cd4adf52f174 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -34,6 +34,7 @@
#include <linux/efi.h>
#include <linux/nodemask.h>
#include <linux/bitops.h> /* hweight64() */
+#include <linux/crash_dump.h>
#include <asm/delay.h> /* ia64_get_itc() */
#include <asm/io.h>
@@ -43,6 +44,8 @@
#include <asm/acpi-ext.h>
+extern int swiotlb_late_init_with_default_size (size_t size);
+
#define PFX "IOC: "
/*
@@ -2026,11 +2029,24 @@ sba_init(void)
if (!ia64_platform_is("hpzx1") && !ia64_platform_is("hpzx1_swiotlb"))
return 0;
+#if defined(CONFIG_IA64_GENERIC) && defined(CONFIG_CRASH_DUMP)
+ /* If we are booting a kdump kernel, the sba_iommu will
+ * cause devices that were not shutdown properly to MCA
+ * as soon as they are turned back on. Our only option for
+ * a successful kdump kernel boot is to use the swiotlb.
+ */
+ if (elfcorehdr_addr < ELFCORE_ADDR_MAX) {
+ if (swiotlb_late_init_with_default_size(64 * (1<<20)) != 0)
+ panic("Unable to initialize software I/O TLB:"
+ " Try machvec=dig boot option");
+ machvec_init("dig");
+ return 0;
+ }
+#endif
+
acpi_bus_register_driver(&acpi_sba_ioc_driver);
if (!ioc_list) {
#ifdef CONFIG_IA64_GENERIC
- extern int swiotlb_late_init_with_default_size (size_t size);
-
/*
* If we didn't find something sba_iommu can claim, we
* need to setup the swiotlb and switch to the dig machvec.
diff --git a/arch/ia64/hp/sim/boot/fw-emu.c b/arch/ia64/hp/sim/boot/fw-emu.c
index 300acd913d9c..1189d035d316 100644
--- a/arch/ia64/hp/sim/boot/fw-emu.c
+++ b/arch/ia64/hp/sim/boot/fw-emu.c
@@ -329,11 +329,6 @@ sys_fw_init (const char *args, int arglen)
strcpy(sal_systab->product_id, "HP-simulator");
#endif
-#ifdef CONFIG_IA64_SDV
- strcpy(sal_systab->oem_id, "Intel");
- strcpy(sal_systab->product_id, "SDV");
-#endif
-
/* fill in an entry point: */
sal_ed->type = SAL_DESC_ENTRY_POINT;
sal_ed->pal_proc = __pa(pal_desc[0]);
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 324ea7565e2c..ef252df50e1e 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -36,10 +36,6 @@
#include <asm/hw_irq.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_KDB
-# include <linux/kdb.h>
-#endif
-
#undef SIMSERIAL_DEBUG /* define this to get some debug information */
#define KEYBOARD_INTR 3 /* must match with simulator! */
diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
index c05bda662364..1cfab326fb7e 100644
--- a/arch/ia64/ia32/binfmt_elf32.c
+++ b/arch/ia64/ia32/binfmt_elf32.c
@@ -195,62 +195,27 @@ ia64_elf32_init (struct pt_regs *regs)
ia32_load_state(current);
}
+/*
+ * Undo the override of setup_arg_pages() without this ia32_setup_arg_pages()
+ * will suffer infinite self recursion.
+ */
+#undef setup_arg_pages
+
int
ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack)
{
- unsigned long stack_base;
- struct vm_area_struct *mpnt;
- struct mm_struct *mm = current->mm;
- int i, ret;
-
- stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE;
- mm->arg_start = bprm->p + stack_base;
-
- bprm->p += stack_base;
- if (bprm->loader)
- bprm->loader += stack_base;
- bprm->exec += stack_base;
-
- mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
- if (!mpnt)
- return -ENOMEM;
-
- down_write(&current->mm->mmap_sem);
- {
- mpnt->vm_mm = current->mm;
- mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
- mpnt->vm_end = IA32_STACK_TOP;
- if (executable_stack == EXSTACK_ENABLE_X)
- mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
- else if (executable_stack == EXSTACK_DISABLE_X)
- mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
- else
- mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC)?
- PAGE_COPY_EXEC: PAGE_COPY;
- if ((ret = insert_vm_struct(current->mm, mpnt))) {
- up_write(&current->mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, mpnt);
- return ret;
- }
- current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt);
+ int ret;
+
+ ret = setup_arg_pages(bprm, IA32_STACK_TOP, executable_stack);
+ if (!ret) {
+ /*
+ * Can't do it in ia64_elf32_init(). Needs to be done before
+ * calls to elf32_map()
+ */
+ current->thread.ppl = ia32_init_pp_list();
}
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page *page = bprm->page[i];
- if (page) {
- bprm->page[i] = NULL;
- install_arg_page(mpnt, page, stack_base);
- }
- stack_base += PAGE_SIZE;
- }
- up_write(&current->mm->mmap_sem);
-
- /* Can't do it in ia64_elf32_init(). Needs to be done before calls to
- elf32_map() */
- current->thread.ppl = ia32_init_pp_list();
-
- return 0;
+ return ret;
}
static void
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index 99b665e2b1d5..06efd1f9b800 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -304,7 +304,7 @@ ia32_syscall_table:
data8 sys_ni_syscall /* init_module */
data8 sys_ni_syscall /* delete_module */
data8 sys_ni_syscall /* get_kernel_syms */ /* 130 */
- data8 sys_quotactl
+ data8 sys32_quotactl
data8 sys_getpgid
data8 sys_fchdir
data8 sys_ni_syscall /* sys_bdflush */
diff --git a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c
index beea7a0b9dc6..e13a1a1db4b5 100644
--- a/arch/ia64/ia32/ia32_support.c
+++ b/arch/ia64/ia32/ia32_support.c
@@ -253,7 +253,7 @@ ia32_init (void)
partial_page_cachep = kmem_cache_create("partial_page_cache",
sizeof(struct partial_page),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
}
#endif
return 0;
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index 2236fabbb3c6..0aebc6f79e95 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -7,6 +7,7 @@
#define ASM_OFFSETS_C 1
#include <linux/sched.h>
+#include <linux/clocksource.h>
#include <asm-ia64/processor.h>
#include <asm-ia64/ptrace.h>
@@ -15,6 +16,7 @@
#include <asm-ia64/mca.h>
#include "../kernel/sigframe.h"
+#include "../kernel/fsyscall_gtod_data.h"
#define DEFINE(sym, val) \
asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -256,17 +258,24 @@ void foo(void)
BLANK();
/* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
- DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr));
- DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source));
- DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift));
- DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc));
- DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset));
- DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle));
- DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter));
- DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter));
- DEFINE(IA64_TIME_INTERPOLATOR_MASK_OFFSET, offsetof (struct time_interpolator, mask));
- DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU);
- DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64);
- DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32);
- DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec));
+ DEFINE(IA64_GTOD_LOCK_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, lock));
+ DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, wall_time));
+ DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, monotonic_time));
+ DEFINE(IA64_CLKSRC_MASK_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_mask));
+ DEFINE(IA64_CLKSRC_MULT_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_mult));
+ DEFINE(IA64_CLKSRC_SHIFT_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_shift));
+ DEFINE(IA64_CLKSRC_MMIO_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_fsys_mmio));
+ DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET,
+ offsetof (struct fsyscall_gtod_data_t, clk_cycle_last));
+ DEFINE(IA64_ITC_JITTER_OFFSET,
+ offsetof (struct itc_jitter_data_t, itc_jitter));
+ DEFINE(IA64_ITC_LASTCYCLE_OFFSET,
+ offsetof (struct itc_jitter_data_t, itc_lastcycle));
}
diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c
index e00b21514f7c..2fd96d9062a1 100644
--- a/arch/ia64/kernel/cyclone.c
+++ b/arch/ia64/kernel/cyclone.c
@@ -3,6 +3,7 @@
#include <linux/time.h>
#include <linux/errno.h>
#include <linux/timex.h>
+#include <linux/clocksource.h>
#include <asm/io.h>
/* IBM Summit (EXA) Cyclone counter code*/
@@ -18,13 +19,21 @@ void __init cyclone_setup(void)
use_cyclone = 1;
}
+static void __iomem *cyclone_mc;
-struct time_interpolator cyclone_interpolator = {
- .source = TIME_SOURCE_MMIO64,
- .shift = 16,
- .frequency = CYCLONE_TIMER_FREQ,
- .drift = -100,
- .mask = (1LL << 40) - 1
+static cycle_t read_cyclone(void)
+{
+ return (cycle_t)readq((void __iomem *)cyclone_mc);
+}
+
+static struct clocksource clocksource_cyclone = {
+ .name = "cyclone",
+ .rating = 300,
+ .read = read_cyclone,
+ .mask = (1LL << 40) - 1,
+ .mult = 0, /*to be caluclated*/
+ .shift = 16,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
int __init init_cyclone_clock(void)
@@ -44,13 +53,15 @@ int __init init_cyclone_clock(void)
offset = (CYCLONE_CBAR_ADDR);
reg = (u64*)ioremap_nocache(offset, sizeof(u64));
if(!reg){
- printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+ printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+ " register.\n");
use_cyclone = 0;
return -ENODEV;
}
base = readq(reg);
if(!base){
- printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+ printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
+ " value.\n");
use_cyclone = 0;
return -ENODEV;
}
@@ -60,7 +71,8 @@ int __init init_cyclone_clock(void)
offset = (base + CYCLONE_PMCC_OFFSET);
reg = (u64*)ioremap_nocache(offset, sizeof(u64));
if(!reg){
- printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+ printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
+ " register.\n");
use_cyclone = 0;
return -ENODEV;
}
@@ -71,7 +83,8 @@ int __init init_cyclone_clock(void)
offset = (base + CYCLONE_MPCS_OFFSET);
reg = (u64*)ioremap_nocache(offset, sizeof(u64));
if(!reg){
- printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+ printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
+ " register.\n");
use_cyclone = 0;
return -ENODEV;
}
@@ -82,7 +95,8 @@ int __init init_cyclone_clock(void)
offset = (base + CYCLONE_MPMC_OFFSET);
cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
if(!cyclone_timer){
- printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+ printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
+ " register.\n");
use_cyclone = 0;
return -ENODEV;
}
@@ -93,7 +107,8 @@ int __init init_cyclone_clock(void)
int stall = 100;
while(stall--) barrier();
if(readl(cyclone_timer) == old){
- printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+ printk(KERN_ERR "Summit chipset: Counter not counting!"
+ " DISABLED\n");
iounmap(cyclone_timer);
cyclone_timer = 0;
use_cyclone = 0;
@@ -101,8 +116,11 @@ int __init init_cyclone_clock(void)
}
}
/* initialize last tick */
- cyclone_interpolator.addr = cyclone_timer;
- register_time_interpolator(&cyclone_interpolator);
+ cyclone_mc = cyclone_timer;
+ clocksource_cyclone.fsys_mmio = cyclone_timer;
+ clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
+ clocksource_cyclone.shift);
+ clocksource_register(&clocksource_cyclone);
return 0;
}
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
index 75ec3478d8a2..73ca86d03810 100644
--- a/arch/ia64/kernel/efi.c
+++ b/arch/ia64/kernel/efi.c
@@ -28,6 +28,7 @@
#include <linux/time.h>
#include <linux/efi.h>
#include <linux/kexec.h>
+#include <linux/mm.h>
#include <asm/io.h>
#include <asm/kregs.h>
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 95f517515235..c36f43c94600 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1581,7 +1581,7 @@ sys_call_table:
data8 sys_sync_file_range // 1300
data8 sys_tee
data8 sys_vmsplice
- data8 sys_ni_syscall // reserved for move_pages
+ data8 sys_fallocate
data8 sys_getcpu
data8 sys_epoll_pwait // 1305
data8 sys_utimensat
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index 8589e84a27c6..44841971f077 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -147,12 +147,11 @@ ENTRY(fsys_set_tid_address)
FSYS_RETURN
END(fsys_set_tid_address)
-/*
- * Ensure that the time interpolator structure is compatible with the asm code
- */
-#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \
- || IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4
-#error fsys_gettimeofday incompatible with changes to struct time_interpolator
+#if IA64_GTOD_LOCK_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t
+#endif
+#if IA64_ITC_JITTER_OFFSET !=0
+#error fsys_gettimeofday incompatible with changes to struct itc_jitter_data_t
#endif
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
@@ -179,124 +178,124 @@ ENTRY(fsys_gettimeofday)
// r11 = preserved: saved ar.pfs
// r12 = preserved: memory stack
// r13 = preserved: thread pointer
- // r14 = address of mask / mask
+ // r14 = address of mask / mask value
// r15 = preserved: system call number
// r16 = preserved: current task pointer
- // r17 = wall to monotonic use
- // r18 = time_interpolator->offset
- // r19 = address of wall_to_monotonic
- // r20 = pointer to struct time_interpolator / pointer to time_interpolator->address
- // r21 = shift factor
- // r22 = address of time interpolator->last_counter
- // r23 = address of time_interpolator->last_cycle
- // r24 = adress of time_interpolator->offset
- // r25 = last_cycle value
- // r26 = last_counter value
- // r27 = pointer to xtime
+ // r17 = (not used)
+ // r18 = (not used)
+ // r19 = address of itc_lastcycle
+ // r20 = struct fsyscall_gtod_data (= address of gtod_lock.sequence)
+ // r21 = address of mmio_ptr
+ // r22 = address of wall_time or monotonic_time
+ // r23 = address of shift / value
+ // r24 = address mult factor / cycle_last value
+ // r25 = itc_lastcycle value
+ // r26 = address clocksource cycle_last
+ // r27 = (not used)
// r28 = sequence number at the beginning of critcal section
- // r29 = address of seqlock
+ // r29 = address of itc_jitter
// r30 = time processing flags / memory address
// r31 = pointer to result
// Predicates
// p6,p7 short term use
// p8 = timesource ar.itc
// p9 = timesource mmio64
- // p10 = timesource mmio32
+ // p10 = timesource mmio32 - not used
// p11 = timesource not to be handled by asm code
- // p12 = memory time source ( = p9 | p10)
- // p13 = do cmpxchg with time_interpolator_last_cycle
+ // p12 = memory time source ( = p9 | p10) - not used
+ // p13 = do cmpxchg with itc_lastcycle
// p14 = Divide by 1000
// p15 = Add monotonic
//
- // Note that instructions are optimized for McKinley. McKinley can process two
- // bundles simultaneously and therefore we continuously try to feed the CPU
- // two bundles and then a stop.
- tnat.nz p6,p0 = r31 // branch deferred since it does not fit into bundle structure
+ // Note that instructions are optimized for McKinley. McKinley can
+ // process two bundles simultaneously and therefore we continuously
+ // try to feed the CPU two bundles and then a stop.
+ //
+ // Additional note that code has changed a lot. Optimization is TBD.
+ // Comments begin with "?" are maybe outdated.
+ tnat.nz p6,p0 = r31 // ? branch deferred to fit later bundle
mov pr = r30,0xc000 // Set predicates according to function
add r2 = TI_FLAGS+IA64_TASK_SIZE,r16
- movl r20 = time_interpolator
+ movl r20 = fsyscall_gtod_data // load fsyscall gettimeofday data address
;;
- ld8 r20 = [r20] // get pointer to time_interpolator structure
- movl r29 = xtime_lock
+ movl r29 = itc_jitter_data // itc_jitter
+ add r22 = IA64_GTOD_WALL_TIME_OFFSET,r20 // wall_time
ld4 r2 = [r2] // process work pending flags
- movl r27 = xtime
- ;; // only one bundle here
- ld8 r21 = [r20] // first quad with control information
+ ;;
+(p15) add r22 = IA64_GTOD_MONO_TIME_OFFSET,r20 // monotonic_time
+ add r21 = IA64_CLKSRC_MMIO_OFFSET,r20
+ add r19 = IA64_ITC_LASTCYCLE_OFFSET,r29
and r2 = TIF_ALLWORK_MASK,r2
-(p6) br.cond.spnt.few .fail_einval // deferred branch
+(p6) br.cond.spnt.few .fail_einval // ? deferred branch
;;
- add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20
- extr r3 = r21,32,32 // time_interpolator->nsec_per_cyc
- extr r8 = r21,0,16 // time_interpolator->source
+ add r26 = IA64_CLKSRC_CYCLE_LAST_OFFSET,r20 // clksrc_cycle_last
cmp.ne p6, p0 = 0, r2 // Fallback if work is scheduled
(p6) br.cond.spnt.many fsys_fallback_syscall
;;
- cmp.eq p8,p12 = 0,r8 // Check for cpu timer
- cmp.eq p9,p0 = 1,r8 // MMIO64 ?
- extr r2 = r21,24,8 // time_interpolator->jitter
- cmp.eq p10,p0 = 2,r8 // MMIO32 ?
- cmp.ltu p11,p0 = 2,r8 // function or other clock
-(p11) br.cond.spnt.many fsys_fallback_syscall
+ // Begin critical section
+.time_redo:
+ ld4.acq r28 = [r20] // gtod_lock.sequence, Must take first
;;
- setf.sig f7 = r3 // Setup for scaling of counter
-(p15) movl r19 = wall_to_monotonic
-(p12) ld8 r30 = [r10]
- cmp.ne p13,p0 = r2,r0 // need jitter compensation?
- extr r21 = r21,16,8 // shift factor
+ and r28 = ~1,r28 // And make sequence even to force retry if odd
;;
-.time_redo:
- .pred.rel.mutex p8,p9,p10
- ld4.acq r28 = [r29] // xtime_lock.sequence. Must come first for locking purposes
+ ld8 r30 = [r21] // clocksource->mmio_ptr
+ add r24 = IA64_CLKSRC_MULT_OFFSET,r20
+ ld4 r2 = [r29] // itc_jitter value
+ add r23 = IA64_CLKSRC_SHIFT_OFFSET,r20
+ add r14 = IA64_CLKSRC_MASK_OFFSET,r20
+ ;;
+ ld4 r3 = [r24] // clocksource mult value
+ ld8 r14 = [r14] // clocksource mask value
+ cmp.eq p8,p9 = 0,r30 // use cpu timer if no mmio_ptr
+ ;;
+ setf.sig f7 = r3 // Setup for mult scaling of counter
+(p8) cmp.ne p13,p0 = r2,r0 // need itc_jitter compensation, set p13
+ ld4 r23 = [r23] // clocksource shift value
+ ld8 r24 = [r26] // get clksrc_cycle_last value
+(p9) cmp.eq p13,p0 = 0,r30 // if mmio_ptr, clear p13 jitter control
+ ;;
+ .pred.rel.mutex p8,p9
(p8) mov r2 = ar.itc // CPU_TIMER. 36 clocks latency!!!
- add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20
-(p9) ld8 r2 = [r30] // readq(ti->address). Could also have latency issues..
-(p10) ld4 r2 = [r30] // readw(ti->address)
-(p13) add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20
- ;; // could be removed by moving the last add upward
- ld8 r26 = [r22] // time_interpolator->last_counter
-(p13) ld8 r25 = [r23] // time interpolator->last_cycle
- add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20
-(p15) ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET
- ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET
- add r14 = IA64_TIME_INTERPOLATOR_MASK_OFFSET, r20
- ;;
- ld8 r18 = [r24] // time_interpolator->offset
- ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET // xtime.tv_nsec
-(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
- ;;
- ld8 r14 = [r14] // time_interpolator->mask
-(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
- sub r10 = r2,r26 // current_counter - last_counter
- ;;
-(p6) sub r10 = r25,r26 // time we got was less than last_cycle
+(p9) ld8 r2 = [r30] // MMIO_TIMER. Could also have latency issues..
+(p13) ld8 r25 = [r19] // get itc_lastcycle value
+ ;; // ? could be removed by moving the last add upward
+ ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET // tv_sec
+ ;;
+ ld8 r8 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET // tv_nsec
+(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
+ ;;
+(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
+ sub r10 = r2,r24 // current_cycle - last_cycle
+ ;;
+(p6) sub r10 = r25,r24 // time we got was less than last_cycle
(p7) mov ar.ccv = r25 // more than last_cycle. Prep for cmpxchg
;;
+(p7) cmpxchg8.rel r3 = [r19],r2,ar.ccv
+ ;;
+(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful
+ ;;
+(p7) sub r10 = r3,r24 // then use new last_cycle instead
+ ;;
and r10 = r10,r14 // Apply mask
;;
setf.sig f8 = r10
nop.i 123
;;
-(p7) cmpxchg8.rel r3 = [r23],r2,ar.ccv
-EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare time
+ // fault check takes 5 cycles and we have spare time
+EX(.fail_efault, probe.w.fault r31, 3)
xmpy.l f8 = f8,f7 // nsec_per_cyc*(counter-last_counter)
-(p15) add r9 = r9,r17 // Add wall to monotonic.secs to result secs
;;
-(p15) ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET
-(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful redo
- // simulate tbit.nz.or p7,p0 = r28,0
- and r28 = ~1,r28 // Make sequence even to force retry if odd
+ // ? simulate tbit.nz.or p7,p0 = r28,0
getf.sig r2 = f8
mf
- add r8 = r8,r18 // Add time interpolator offset
;;
- ld4 r10 = [r29] // xtime_lock.sequence
-(p15) add r8 = r8, r17 // Add monotonic.nsecs to nsecs
- shr.u r2 = r2,r21
- ;; // overloaded 3 bundles!
- // End critical section.
+ ld4 r10 = [r20] // gtod_lock.sequence
+ shr.u r2 = r2,r23 // shift by factor
+ ;; // ? overloaded 3 bundles!
add r8 = r8,r2 // Add xtime.nsecs
- cmp4.ne.or p7,p0 = r28,r10
-(p7) br.cond.dpnt.few .time_redo // sequence number changed ?
+ cmp4.ne p7,p0 = r28,r10
+(p7) br.cond.dpnt.few .time_redo // sequence number changed, redo
+ // End critical section.
// Now r8=tv->tv_nsec and r9=tv->tv_sec
mov r10 = r0
movl r2 = 1000000000
@@ -306,19 +305,19 @@ EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare
.time_normalize:
mov r21 = r8
cmp.ge p6,p0 = r8,r2
-(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting some time
+(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting time
;;
(p14) setf.sig f8 = r20
(p6) sub r8 = r8,r2
-(p6) add r9 = 1,r9 // two nops before the branch.
-(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod
+(p6) add r9 = 1,r9 // two nops before the branch.
+(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod
(p6) br.cond.dpnt.few .time_normalize
;;
// Divided by 8 though shift. Now divide by 125
// The compiler was able to do that with a multiply
// and a shift and we do the same
-EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
-(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it...
+EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
+(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it
;;
mov r8 = r0
(p14) getf.sig r2 = f8
diff --git a/arch/ia64/kernel/fsyscall_gtod_data.h b/arch/ia64/kernel/fsyscall_gtod_data.h
new file mode 100644
index 000000000000..490dab55fba3
--- /dev/null
+++ b/arch/ia64/kernel/fsyscall_gtod_data.h
@@ -0,0 +1,23 @@
+/*
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ * Contributed by Peter Keilty <peter.keilty@hp.com>
+ *
+ * fsyscall gettimeofday data
+ */
+
+struct fsyscall_gtod_data_t {
+ seqlock_t lock;
+ struct timespec wall_time;
+ struct timespec monotonic_time;
+ cycle_t clk_mask;
+ u32 clk_mult;
+ u32 clk_shift;
+ void *clk_fsys_mmio;
+ cycle_t clk_cycle_last;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
+struct itc_jitter_data_t {
+ int itc_jitter;
+ cycle_t itc_lastcycle;
+} __attribute__ ((aligned (L1_CACHE_BYTES)));
+
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index 3274850cf272..74b1ccce4e84 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -30,6 +30,7 @@
.previous
#define BRL_COND_FSYS_BUBBLE_DOWN(pr) \
[1:](pr)brl.cond.sptk 0; \
+ ;; \
.xdata4 ".data.patch.brl_fsys_bubble_down", 1b-.
GLOBAL_ENTRY(__kernel_syscall_via_break)
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 37f46527d233..91e6dc1e7baf 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -118,15 +118,25 @@ static DEFINE_SPINLOCK(iosapic_lock);
* vector.
*/
-struct iosapic_rte_info {
- struct list_head rte_list; /* node in list of RTEs sharing the
- * same vector */
+#define NO_REF_RTE 0
+
+static struct iosapic {
char __iomem *addr; /* base address of IOSAPIC */
- unsigned int gsi_base; /* first GSI assigned to this
- * IOSAPIC */
+ unsigned int gsi_base; /* GSI base */
+ unsigned short num_rte; /* # of RTEs on this IOSAPIC */
+ int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
+#ifdef CONFIG_NUMA
+ unsigned short node; /* numa node association via pxm */
+#endif
+ spinlock_t lock; /* lock for indirect reg access */
+} iosapic_lists[NR_IOSAPICS];
+
+struct iosapic_rte_info {
+ struct list_head rte_list; /* RTEs sharing the same vector */
char rte_index; /* IOSAPIC RTE index */
int refcnt; /* reference counter */
unsigned int flags; /* flags */
+ struct iosapic *iosapic;
} ____cacheline_aligned;
static struct iosapic_intr_info {
@@ -140,24 +150,23 @@ static struct iosapic_intr_info {
unsigned char polarity: 1; /* interrupt polarity
* (see iosapic.h) */
unsigned char trigger : 1; /* trigger mode (see iosapic.h) */
-} iosapic_intr_info[IA64_NUM_VECTORS];
-
-static struct iosapic {
- char __iomem *addr; /* base address of IOSAPIC */
- unsigned int gsi_base; /* first GSI assigned to this
- * IOSAPIC */
- unsigned short num_rte; /* # of RTEs on this IOSAPIC */
- int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
-#ifdef CONFIG_NUMA
- unsigned short node; /* numa node association via pxm */
-#endif
-} iosapic_lists[NR_IOSAPICS];
+} iosapic_intr_info[NR_IRQS];
static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
static int iosapic_kmalloc_ok;
static LIST_HEAD(free_rte_list);
+static inline void
+iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&iosapic->lock, flags);
+ __iosapic_write(iosapic->addr, reg, val);
+ spin_unlock_irqrestore(&iosapic->lock, flags);
+}
+
/*
* Find an IOSAPIC associated with a GSI
*/
@@ -175,17 +184,18 @@ find_iosapic (unsigned int gsi)
return -1;
}
-static inline int
-_gsi_to_vector (unsigned int gsi)
+static inline int __gsi_to_irq(unsigned int gsi)
{
+ int irq;
struct iosapic_intr_info *info;
struct iosapic_rte_info *rte;
- for (info = iosapic_intr_info; info <
- iosapic_intr_info + IA64_NUM_VECTORS; ++info)
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ info = &iosapic_intr_info[irq];
list_for_each_entry(rte, &info->rtes, rte_list)
- if (rte->gsi_base + rte->rte_index == gsi)
- return info - iosapic_intr_info;
+ if (rte->iosapic->gsi_base + rte->rte_index == gsi)
+ return irq;
+ }
return -1;
}
@@ -196,7 +206,10 @@ _gsi_to_vector (unsigned int gsi)
inline int
gsi_to_vector (unsigned int gsi)
{
- return _gsi_to_vector(gsi);
+ int irq = __gsi_to_irq(gsi);
+ if (check_irq_used(irq) < 0)
+ return -1;
+ return irq_to_vector(irq);
}
int
@@ -204,66 +217,48 @@ gsi_to_irq (unsigned int gsi)
{
unsigned long flags;
int irq;
- /*
- * XXX fix me: this assumes an identity mapping between IA-64 vector
- * and Linux irq numbers...
- */
+
spin_lock_irqsave(&iosapic_lock, flags);
- {
- irq = _gsi_to_vector(gsi);
- }
+ irq = __gsi_to_irq(gsi);
spin_unlock_irqrestore(&iosapic_lock, flags);
-
return irq;
}
-static struct iosapic_rte_info *gsi_vector_to_rte(unsigned int gsi,
- unsigned int vec)
+static struct iosapic_rte_info *find_rte(unsigned int irq, unsigned int gsi)
{
struct iosapic_rte_info *rte;
- list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
- if (rte->gsi_base + rte->rte_index == gsi)
+ list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+ if (rte->iosapic->gsi_base + rte->rte_index == gsi)
return rte;
return NULL;
}
static void
-set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
+set_rte (unsigned int gsi, unsigned int irq, unsigned int dest, int mask)
{
unsigned long pol, trigger, dmode;
u32 low32, high32;
- char __iomem *addr;
int rte_index;
char redir;
struct iosapic_rte_info *rte;
+ ia64_vector vector = irq_to_vector(irq);
DBG(KERN_DEBUG"IOSAPIC: routing vector %d to 0x%x\n", vector, dest);
- rte = gsi_vector_to_rte(gsi, vector);
+ rte = find_rte(irq, gsi);
if (!rte)
return; /* not an IOSAPIC interrupt */
rte_index = rte->rte_index;
- addr = rte->addr;
- pol = iosapic_intr_info[vector].polarity;
- trigger = iosapic_intr_info[vector].trigger;
- dmode = iosapic_intr_info[vector].dmode;
+ pol = iosapic_intr_info[irq].polarity;
+ trigger = iosapic_intr_info[irq].trigger;
+ dmode = iosapic_intr_info[irq].dmode;
redir = (dmode == IOSAPIC_LOWEST_PRIORITY) ? 1 : 0;
#ifdef CONFIG_SMP
- {
- unsigned int irq;
-
- for (irq = 0; irq < NR_IRQS; ++irq)
- if (irq_to_vector(irq) == vector) {
- set_irq_affinity_info(irq,
- (int)(dest & 0xffff),
- redir);
- break;
- }
- }
+ set_irq_affinity_info(irq, (int)(dest & 0xffff), redir);
#endif
low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
@@ -275,10 +270,10 @@ set_rte (unsigned int gsi, unsigned int vector, unsigned int dest, int mask)
/* dest contains both id and eid */
high32 = (dest << IOSAPIC_DEST_SHIFT);
- iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index), high32);
- iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
- iosapic_intr_info[vector].low32 = low32;
- iosapic_intr_info[vector].dest = dest;
+ iosapic_write(rte->iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+ iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
+ iosapic_intr_info[irq].low32 = low32;
+ iosapic_intr_info[irq].dest = dest;
}
static void
@@ -294,15 +289,18 @@ kexec_disable_iosapic(void)
{
struct iosapic_intr_info *info;
struct iosapic_rte_info *rte;
- u8 vec = 0;
- for (info = iosapic_intr_info; info <
- iosapic_intr_info + IA64_NUM_VECTORS; ++info, ++vec) {
+ ia64_vector vec;
+ int irq;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ info = &iosapic_intr_info[irq];
+ vec = irq_to_vector(irq);
list_for_each_entry(rte, &info->rtes,
rte_list) {
- iosapic_write(rte->addr,
+ iosapic_write(rte->iosapic,
IOSAPIC_RTE_LOW(rte->rte_index),
IOSAPIC_MASK|vec);
- iosapic_eoi(rte->addr, vec);
+ iosapic_eoi(rte->iosapic->addr, vec);
}
}
}
@@ -311,54 +309,36 @@ kexec_disable_iosapic(void)
static void
mask_irq (unsigned int irq)
{
- unsigned long flags;
- char __iomem *addr;
u32 low32;
int rte_index;
- ia64_vector vec = irq_to_vector(irq);
struct iosapic_rte_info *rte;
- if (list_empty(&iosapic_intr_info[vec].rtes))
+ if (list_empty(&iosapic_intr_info[irq].rtes))
return; /* not an IOSAPIC interrupt! */
- spin_lock_irqsave(&iosapic_lock, flags);
- {
- /* set only the mask bit */
- low32 = iosapic_intr_info[vec].low32 |= IOSAPIC_MASK;
- list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
- rte_list) {
- addr = rte->addr;
- rte_index = rte->rte_index;
- iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
- }
+ /* set only the mask bit */
+ low32 = iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+ list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+ rte_index = rte->rte_index;
+ iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
}
- spin_unlock_irqrestore(&iosapic_lock, flags);
}
static void
unmask_irq (unsigned int irq)
{
- unsigned long flags;
- char __iomem *addr;
u32 low32;
int rte_index;
- ia64_vector vec = irq_to_vector(irq);
struct iosapic_rte_info *rte;
- if (list_empty(&iosapic_intr_info[vec].rtes))
+ if (list_empty(&iosapic_intr_info[irq].rtes))
return; /* not an IOSAPIC interrupt! */
- spin_lock_irqsave(&iosapic_lock, flags);
- {
- low32 = iosapic_intr_info[vec].low32 &= ~IOSAPIC_MASK;
- list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
- rte_list) {
- addr = rte->addr;
- rte_index = rte->rte_index;
- iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
- }
+ low32 = iosapic_intr_info[irq].low32 &= ~IOSAPIC_MASK;
+ list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+ rte_index = rte->rte_index;
+ iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
}
- spin_unlock_irqrestore(&iosapic_lock, flags);
}
@@ -366,23 +346,24 @@ static void
iosapic_set_affinity (unsigned int irq, cpumask_t mask)
{
#ifdef CONFIG_SMP
- unsigned long flags;
u32 high32, low32;
int dest, rte_index;
- char __iomem *addr;
int redir = (irq & IA64_IRQ_REDIRECTED) ? 1 : 0;
- ia64_vector vec;
struct iosapic_rte_info *rte;
+ struct iosapic *iosapic;
irq &= (~IA64_IRQ_REDIRECTED);
- vec = irq_to_vector(irq);
+ cpus_and(mask, mask, cpu_online_map);
if (cpus_empty(mask))
return;
+ if (reassign_irq_vector(irq, first_cpu(mask)))
+ return;
+
dest = cpu_physical_id(first_cpu(mask));
- if (list_empty(&iosapic_intr_info[vec].rtes))
+ if (list_empty(&iosapic_intr_info[irq].rtes))
return; /* not an IOSAPIC interrupt */
set_irq_affinity_info(irq, dest, redir);
@@ -390,31 +371,24 @@ iosapic_set_affinity (unsigned int irq, cpumask_t mask)
/* dest contains both id and eid */
high32 = dest << IOSAPIC_DEST_SHIFT;
- spin_lock_irqsave(&iosapic_lock, flags);
- {
- low32 = iosapic_intr_info[vec].low32 &
- ~(7 << IOSAPIC_DELIVERY_SHIFT);
-
- if (redir)
- /* change delivery mode to lowest priority */
- low32 |= (IOSAPIC_LOWEST_PRIORITY <<
- IOSAPIC_DELIVERY_SHIFT);
- else
- /* change delivery mode to fixed */
- low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
-
- iosapic_intr_info[vec].low32 = low32;
- iosapic_intr_info[vec].dest = dest;
- list_for_each_entry(rte, &iosapic_intr_info[vec].rtes,
- rte_list) {
- addr = rte->addr;
- rte_index = rte->rte_index;
- iosapic_write(addr, IOSAPIC_RTE_HIGH(rte_index),
- high32);
- iosapic_write(addr, IOSAPIC_RTE_LOW(rte_index), low32);
- }
+ low32 = iosapic_intr_info[irq].low32 & ~(7 << IOSAPIC_DELIVERY_SHIFT);
+ if (redir)
+ /* change delivery mode to lowest priority */
+ low32 |= (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT);
+ else
+ /* change delivery mode to fixed */
+ low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT);
+ low32 &= IOSAPIC_VECTOR_MASK;
+ low32 |= irq_to_vector(irq);
+
+ iosapic_intr_info[irq].low32 = low32;
+ iosapic_intr_info[irq].dest = dest;
+ list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list) {
+ iosapic = rte->iosapic;
+ rte_index = rte->rte_index;
+ iosapic_write(iosapic, IOSAPIC_RTE_HIGH(rte_index), high32);
+ iosapic_write(iosapic, IOSAPIC_RTE_LOW(rte_index), low32);
}
- spin_unlock_irqrestore(&iosapic_lock, flags);
#endif
}
@@ -434,10 +408,20 @@ iosapic_end_level_irq (unsigned int irq)
{
ia64_vector vec = irq_to_vector(irq);
struct iosapic_rte_info *rte;
+ int do_unmask_irq = 0;
- move_native_irq(irq);
- list_for_each_entry(rte, &iosapic_intr_info[vec].rtes, rte_list)
- iosapic_eoi(rte->addr, vec);
+ if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+ do_unmask_irq = 1;
+ mask_irq(irq);
+ }
+
+ list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
+ iosapic_eoi(rte->iosapic->addr, vec);
+
+ if (unlikely(do_unmask_irq)) {
+ move_masked_irq(irq);
+ unmask_irq(irq);
+ }
}
#define iosapic_shutdown_level_irq mask_irq
@@ -519,13 +503,12 @@ iosapic_version (char __iomem *addr)
* unsigned int reserved2 : 8;
* }
*/
- return iosapic_read(addr, IOSAPIC_VERSION);
+ return __iosapic_read(addr, IOSAPIC_VERSION);
}
-static int iosapic_find_sharable_vector (unsigned long trigger,
- unsigned long pol)
+static int iosapic_find_sharable_irq(unsigned long trigger, unsigned long pol)
{
- int i, vector = -1, min_count = -1;
+ int i, irq = -ENOSPC, min_count = -1;
struct iosapic_intr_info *info;
/*
@@ -533,21 +516,21 @@ static int iosapic_find_sharable_vector (unsigned long trigger,
* supported yet
*/
if (trigger == IOSAPIC_EDGE)
- return -1;
+ return -EINVAL;
- for (i = IA64_FIRST_DEVICE_VECTOR; i <= IA64_LAST_DEVICE_VECTOR; i++) {
+ for (i = 0; i <= NR_IRQS; i++) {
info = &iosapic_intr_info[i];
if (info->trigger == trigger && info->polarity == pol &&
- (info->dmode == IOSAPIC_FIXED || info->dmode ==
- IOSAPIC_LOWEST_PRIORITY)) {
+ (info->dmode == IOSAPIC_FIXED ||
+ info->dmode == IOSAPIC_LOWEST_PRIORITY) &&
+ can_request_irq(i, IRQF_SHARED)) {
if (min_count == -1 || info->count < min_count) {
- vector = i;
+ irq = i;
min_count = info->count;
}
}
}
-
- return vector;
+ return irq;
}
/*
@@ -555,25 +538,25 @@ static int iosapic_find_sharable_vector (unsigned long trigger,
* assign a new vector for the other and make the vector available
*/
static void __init
-iosapic_reassign_vector (int vector)
+iosapic_reassign_vector (int irq)
{
- int new_vector;
+ int new_irq;
- if (!list_empty(&iosapic_intr_info[vector].rtes)) {
- new_vector = assign_irq_vector(AUTO_ASSIGN);
- if (new_vector < 0)
+ if (!list_empty(&iosapic_intr_info[irq].rtes)) {
+ new_irq = create_irq();
+ if (new_irq < 0)
panic("%s: out of interrupt vectors!\n", __FUNCTION__);
printk(KERN_INFO "Reassigning vector %d to %d\n",
- vector, new_vector);
- memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
+ irq_to_vector(irq), irq_to_vector(new_irq));
+ memcpy(&iosapic_intr_info[new_irq], &iosapic_intr_info[irq],
sizeof(struct iosapic_intr_info));
- INIT_LIST_HEAD(&iosapic_intr_info[new_vector].rtes);
- list_move(iosapic_intr_info[vector].rtes.next,
- &iosapic_intr_info[new_vector].rtes);
- memset(&iosapic_intr_info[vector], 0,
+ INIT_LIST_HEAD(&iosapic_intr_info[new_irq].rtes);
+ list_move(iosapic_intr_info[irq].rtes.next,
+ &iosapic_intr_info[new_irq].rtes);
+ memset(&iosapic_intr_info[irq], 0,
sizeof(struct iosapic_intr_info));
- iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
- INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+ iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
+ INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
}
}
@@ -610,29 +593,18 @@ static struct iosapic_rte_info *iosapic_alloc_rte (void)
return rte;
}
-static void iosapic_free_rte (struct iosapic_rte_info *rte)
+static inline int irq_is_shared (int irq)
{
- if (rte->flags & RTE_PREALLOCATED)
- list_add_tail(&rte->rte_list, &free_rte_list);
- else
- kfree(rte);
-}
-
-static inline int vector_is_shared (int vector)
-{
- return (iosapic_intr_info[vector].count > 1);
+ return (iosapic_intr_info[irq].count > 1);
}
static int
-register_intr (unsigned int gsi, int vector, unsigned char delivery,
+register_intr (unsigned int gsi, int irq, unsigned char delivery,
unsigned long polarity, unsigned long trigger)
{
irq_desc_t *idesc;
struct hw_interrupt_type *irq_type;
- int rte_index;
int index;
- unsigned long gsi_base;
- void __iomem *iosapic_address;
struct iosapic_rte_info *rte;
index = find_iosapic(gsi);
@@ -642,10 +614,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
return -ENODEV;
}
- iosapic_address = iosapic_lists[index].addr;
- gsi_base = iosapic_lists[index].gsi_base;
-
- rte = gsi_vector_to_rte(gsi, vector);
+ rte = find_rte(irq, gsi);
if (!rte) {
rte = iosapic_alloc_rte();
if (!rte) {
@@ -654,40 +623,42 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
return -ENOMEM;
}
- rte_index = gsi - gsi_base;
- rte->rte_index = rte_index;
- rte->addr = iosapic_address;
- rte->gsi_base = gsi_base;
+ rte->iosapic = &iosapic_lists[index];
+ rte->rte_index = gsi - rte->iosapic->gsi_base;
rte->refcnt++;
- list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
- iosapic_intr_info[vector].count++;
+ list_add_tail(&rte->rte_list, &iosapic_intr_info[irq].rtes);
+ iosapic_intr_info[irq].count++;
iosapic_lists[index].rtes_inuse++;
}
- else if (vector_is_shared(vector)) {
- struct iosapic_intr_info *info = &iosapic_intr_info[vector];
- if (info->trigger != trigger || info->polarity != polarity) {
+ else if (rte->refcnt == NO_REF_RTE) {
+ struct iosapic_intr_info *info = &iosapic_intr_info[irq];
+ if (info->count > 0 &&
+ (info->trigger != trigger || info->polarity != polarity)){
printk (KERN_WARNING
"%s: cannot override the interrupt\n",
__FUNCTION__);
return -EINVAL;
}
+ rte->refcnt++;
+ iosapic_intr_info[irq].count++;
+ iosapic_lists[index].rtes_inuse++;
}
- iosapic_intr_info[vector].polarity = polarity;
- iosapic_intr_info[vector].dmode = delivery;
- iosapic_intr_info[vector].trigger = trigger;
+ iosapic_intr_info[irq].polarity = polarity;
+ iosapic_intr_info[irq].dmode = delivery;
+ iosapic_intr_info[irq].trigger = trigger;
if (trigger == IOSAPIC_EDGE)
irq_type = &irq_type_iosapic_edge;
else
irq_type = &irq_type_iosapic_level;
- idesc = irq_desc + vector;
+ idesc = irq_desc + irq;
if (idesc->chip != irq_type) {
if (idesc->chip != &no_irq_type)
printk(KERN_WARNING
"%s: changing vector %d from %s to %s\n",
- __FUNCTION__, vector,
+ __FUNCTION__, irq_to_vector(irq),
idesc->chip->name, irq_type->name);
idesc->chip = irq_type;
}
@@ -695,18 +666,19 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
}
static unsigned int
-get_target_cpu (unsigned int gsi, int vector)
+get_target_cpu (unsigned int gsi, int irq)
{
#ifdef CONFIG_SMP
static int cpu = -1;
extern int cpe_vector;
+ cpumask_t domain = irq_to_domain(irq);
/*
* In case of vector shared by multiple RTEs, all RTEs that
* share the vector need to use the same destination CPU.
*/
- if (!list_empty(&iosapic_intr_info[vector].rtes))
- return iosapic_intr_info[vector].dest;
+ if (!list_empty(&iosapic_intr_info[irq].rtes))
+ return iosapic_intr_info[irq].dest;
/*
* If the platform supports redirection via XTP, let it
@@ -723,7 +695,7 @@ get_target_cpu (unsigned int gsi, int vector)
return cpu_physical_id(smp_processor_id());
#ifdef CONFIG_ACPI
- if (cpe_vector > 0 && vector == IA64_CPEP_VECTOR)
+ if (cpe_vector > 0 && irq_to_vector(irq) == IA64_CPEP_VECTOR)
return get_cpei_target_cpu();
#endif
@@ -738,7 +710,7 @@ get_target_cpu (unsigned int gsi, int vector)
goto skip_numa_setup;
cpu_mask = node_to_cpumask(iosapic_lists[iosapic_index].node);
-
+ cpus_and(cpu_mask, cpu_mask, domain);
for_each_cpu_mask(numa_cpu, cpu_mask) {
if (!cpu_online(numa_cpu))
cpu_clear(numa_cpu, cpu_mask);
@@ -749,8 +721,8 @@ get_target_cpu (unsigned int gsi, int vector)
if (!num_cpus)
goto skip_numa_setup;
- /* Use vector assignment to distribute across cpus in node */
- cpu_index = vector % num_cpus;
+ /* Use irq assignment to distribute across cpus in node */
+ cpu_index = irq % num_cpus;
for (numa_cpu = first_cpu(cpu_mask) ; i < cpu_index ; i++)
numa_cpu = next_cpu(numa_cpu, cpu_mask);
@@ -768,7 +740,7 @@ skip_numa_setup:
do {
if (++cpu >= NR_CPUS)
cpu = 0;
- } while (!cpu_online(cpu));
+ } while (!cpu_online(cpu) || !cpu_isset(cpu, domain));
return cpu_physical_id(cpu);
#else /* CONFIG_SMP */
@@ -785,84 +757,72 @@ int
iosapic_register_intr (unsigned int gsi,
unsigned long polarity, unsigned long trigger)
{
- int vector, mask = 1, err;
+ int irq, mask = 1, err;
unsigned int dest;
unsigned long flags;
struct iosapic_rte_info *rte;
u32 low32;
-again:
+
/*
* If this GSI has already been registered (i.e., it's a
* shared interrupt, or we lost a race to register it),
* don't touch the RTE.
*/
spin_lock_irqsave(&iosapic_lock, flags);
- {
- vector = gsi_to_vector(gsi);
- if (vector > 0) {
- rte = gsi_vector_to_rte(gsi, vector);
+ irq = __gsi_to_irq(gsi);
+ if (irq > 0) {
+ rte = find_rte(irq, gsi);
+ if(iosapic_intr_info[irq].count == 0) {
+ assign_irq_vector(irq);
+ dynamic_irq_init(irq);
+ } else if (rte->refcnt != NO_REF_RTE) {
rte->refcnt++;
- spin_unlock_irqrestore(&iosapic_lock, flags);
- return vector;
+ goto unlock_iosapic_lock;
}
- }
- spin_unlock_irqrestore(&iosapic_lock, flags);
+ } else
+ irq = create_irq();
/* If vector is running out, we try to find a sharable vector */
- vector = assign_irq_vector(AUTO_ASSIGN);
- if (vector < 0) {
- vector = iosapic_find_sharable_vector(trigger, polarity);
- if (vector < 0)
- return -ENOSPC;
+ if (irq < 0) {
+ irq = iosapic_find_sharable_irq(trigger, polarity);
+ if (irq < 0)
+ goto unlock_iosapic_lock;
}
- spin_lock_irqsave(&irq_desc[vector].lock, flags);
- spin_lock(&iosapic_lock);
- {
- if (gsi_to_vector(gsi) > 0) {
- if (list_empty(&iosapic_intr_info[vector].rtes))
- free_irq_vector(vector);
- spin_unlock(&iosapic_lock);
- spin_unlock_irqrestore(&irq_desc[vector].lock,
- flags);
- goto again;
- }
-
- dest = get_target_cpu(gsi, vector);
- err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
- polarity, trigger);
- if (err < 0) {
- spin_unlock(&iosapic_lock);
- spin_unlock_irqrestore(&irq_desc[vector].lock,
- flags);
- return err;
- }
-
- /*
- * If the vector is shared and already unmasked for
- * other interrupt sources, don't mask it.
- */
- low32 = iosapic_intr_info[vector].low32;
- if (vector_is_shared(vector) && !(low32 & IOSAPIC_MASK))
- mask = 0;
- set_rte(gsi, vector, dest, mask);
+ spin_lock(&irq_desc[irq].lock);
+ dest = get_target_cpu(gsi, irq);
+ err = register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY,
+ polarity, trigger);
+ if (err < 0) {
+ irq = err;
+ goto unlock_all;
}
- spin_unlock(&iosapic_lock);
- spin_unlock_irqrestore(&irq_desc[vector].lock, flags);
+
+ /*
+ * If the vector is shared and already unmasked for other
+ * interrupt sources, don't mask it.
+ */
+ low32 = iosapic_intr_info[irq].low32;
+ if (irq_is_shared(irq) && !(low32 & IOSAPIC_MASK))
+ mask = 0;
+ set_rte(gsi, irq, dest, mask);
printk(KERN_INFO "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d\n",
gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
- cpu_logical_id(dest), dest, vector);
-
- return vector;
+ cpu_logical_id(dest), dest, irq_to_vector(irq));
+ unlock_all:
+ spin_unlock(&irq_desc[irq].lock);
+ unlock_iosapic_lock:
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+ return irq;
}
void
iosapic_unregister_intr (unsigned int gsi)
{
unsigned long flags;
- int irq, vector, index;
+ int irq, index;
irq_desc_t *idesc;
u32 low32;
unsigned long trigger, polarity;
@@ -881,78 +841,56 @@ iosapic_unregister_intr (unsigned int gsi)
WARN_ON(1);
return;
}
- vector = irq_to_vector(irq);
- idesc = irq_desc + irq;
- spin_lock_irqsave(&idesc->lock, flags);
- spin_lock(&iosapic_lock);
- {
- if ((rte = gsi_vector_to_rte(gsi, vector)) == NULL) {
- printk(KERN_ERR
- "iosapic_unregister_intr(%u) unbalanced\n",
- gsi);
- WARN_ON(1);
- goto out;
- }
+ spin_lock_irqsave(&iosapic_lock, flags);
+ if ((rte = find_rte(irq, gsi)) == NULL) {
+ printk(KERN_ERR "iosapic_unregister_intr(%u) unbalanced\n",
+ gsi);
+ WARN_ON(1);
+ goto out;
+ }
- if (--rte->refcnt > 0)
- goto out;
+ if (--rte->refcnt > 0)
+ goto out;
- /* Mask the interrupt */
- low32 = iosapic_intr_info[vector].low32 | IOSAPIC_MASK;
- iosapic_write(rte->addr, IOSAPIC_RTE_LOW(rte->rte_index),
- low32);
+ idesc = irq_desc + irq;
+ rte->refcnt = NO_REF_RTE;
- /* Remove the rte entry from the list */
- list_del(&rte->rte_list);
- iosapic_intr_info[vector].count--;
- iosapic_free_rte(rte);
- index = find_iosapic(gsi);
- iosapic_lists[index].rtes_inuse--;
- WARN_ON(iosapic_lists[index].rtes_inuse < 0);
-
- trigger = iosapic_intr_info[vector].trigger;
- polarity = iosapic_intr_info[vector].polarity;
- dest = iosapic_intr_info[vector].dest;
- printk(KERN_INFO
- "GSI %u (%s, %s) -> CPU %d (0x%04x)"
- " vector %d unregistered\n",
- gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
- (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
- cpu_logical_id(dest), dest, vector);
+ /* Mask the interrupt */
+ low32 = iosapic_intr_info[irq].low32 | IOSAPIC_MASK;
+ iosapic_write(rte->iosapic, IOSAPIC_RTE_LOW(rte->rte_index), low32);
- if (list_empty(&iosapic_intr_info[vector].rtes)) {
- /* Sanity check */
- BUG_ON(iosapic_intr_info[vector].count);
+ iosapic_intr_info[irq].count--;
+ index = find_iosapic(gsi);
+ iosapic_lists[index].rtes_inuse--;
+ WARN_ON(iosapic_lists[index].rtes_inuse < 0);
- /* Clear the interrupt controller descriptor */
- idesc->chip = &no_irq_type;
+ trigger = iosapic_intr_info[irq].trigger;
+ polarity = iosapic_intr_info[irq].polarity;
+ dest = iosapic_intr_info[irq].dest;
+ printk(KERN_INFO
+ "GSI %u (%s, %s) -> CPU %d (0x%04x) vector %d unregistered\n",
+ gsi, (trigger == IOSAPIC_EDGE ? "edge" : "level"),
+ (polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
+ cpu_logical_id(dest), dest, irq_to_vector(irq));
+ if (iosapic_intr_info[irq].count == 0) {
#ifdef CONFIG_SMP
- /* Clear affinity */
- cpus_setall(idesc->affinity);
+ /* Clear affinity */
+ cpus_setall(idesc->affinity);
#endif
-
- /* Clear the interrupt information */
- memset(&iosapic_intr_info[vector], 0,
- sizeof(struct iosapic_intr_info));
- iosapic_intr_info[vector].low32 |= IOSAPIC_MASK;
- INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
-
- if (idesc->action) {
- printk(KERN_ERR
- "interrupt handlers still exist on"
- "IRQ %u\n", irq);
- WARN_ON(1);
- }
-
- /* Free the interrupt vector */
- free_irq_vector(vector);
- }
+ /* Clear the interrupt information */
+ iosapic_intr_info[irq].dest = 0;
+ iosapic_intr_info[irq].dmode = 0;
+ iosapic_intr_info[irq].polarity = 0;
+ iosapic_intr_info[irq].trigger = 0;
+ iosapic_intr_info[irq].low32 |= IOSAPIC_MASK;
+
+ /* Destroy and reserve IRQ */
+ destroy_and_reserve_irq(irq);
}
out:
- spin_unlock(&iosapic_lock);
- spin_unlock_irqrestore(&idesc->lock, flags);
+ spin_unlock_irqrestore(&iosapic_lock, flags);
}
/*
@@ -965,27 +903,30 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
{
static const char * const name[] = {"unknown", "PMI", "INIT", "CPEI"};
unsigned char delivery;
- int vector, mask = 0;
+ int irq, vector, mask = 0;
unsigned int dest = ((id << 8) | eid) & 0xffff;
switch (int_type) {
case ACPI_INTERRUPT_PMI:
- vector = iosapic_vector;
+ irq = vector = iosapic_vector;
+ bind_irq_vector(irq, vector, CPU_MASK_ALL);
/*
* since PMI vector is alloc'd by FW(ACPI) not by kernel,
* we need to make sure the vector is available
*/
- iosapic_reassign_vector(vector);
+ iosapic_reassign_vector(irq);
delivery = IOSAPIC_PMI;
break;
case ACPI_INTERRUPT_INIT:
- vector = assign_irq_vector(AUTO_ASSIGN);
- if (vector < 0)
+ irq = create_irq();
+ if (irq < 0)
panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+ vector = irq_to_vector(irq);
delivery = IOSAPIC_INIT;
break;
case ACPI_INTERRUPT_CPEI:
- vector = IA64_CPE_VECTOR;
+ irq = vector = IA64_CPE_VECTOR;
+ BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
delivery = IOSAPIC_LOWEST_PRIORITY;
mask = 1;
break;
@@ -995,7 +936,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
return -1;
}
- register_intr(gsi, vector, delivery, polarity, trigger);
+ register_intr(gsi, irq, delivery, polarity, trigger);
printk(KERN_INFO
"PLATFORM int %s (0x%x): GSI %u (%s, %s) -> CPU %d (0x%04x)"
@@ -1005,7 +946,7 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
(polarity == IOSAPIC_POL_HIGH ? "high" : "low"),
cpu_logical_id(dest), dest, vector);
- set_rte(gsi, vector, dest, mask);
+ set_rte(gsi, irq, dest, mask);
return vector;
}
@@ -1017,30 +958,32 @@ iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
unsigned long polarity,
unsigned long trigger)
{
- int vector;
+ int vector, irq;
unsigned int dest = cpu_physical_id(smp_processor_id());
- vector = isa_irq_to_vector(isa_irq);
-
- register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
+ irq = vector = isa_irq_to_vector(isa_irq);
+ BUG_ON(bind_irq_vector(irq, vector, CPU_MASK_ALL));
+ register_intr(gsi, irq, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
DBG("ISA: IRQ %u -> GSI %u (%s,%s) -> CPU %d (0x%04x) vector %d\n",
isa_irq, gsi, trigger == IOSAPIC_EDGE ? "edge" : "level",
polarity == IOSAPIC_POL_HIGH ? "high" : "low",
cpu_logical_id(dest), dest, vector);
- set_rte(gsi, vector, dest, 1);
+ set_rte(gsi, irq, dest, 1);
}
void __init
iosapic_system_init (int system_pcat_compat)
{
- int vector;
+ int irq;
- for (vector = 0; vector < IA64_NUM_VECTORS; ++vector) {
- iosapic_intr_info[vector].low32 = IOSAPIC_MASK;
+ for (irq = 0; irq < NR_IRQS; ++irq) {
+ iosapic_intr_info[irq].low32 = IOSAPIC_MASK;
/* mark as unused */
- INIT_LIST_HEAD(&iosapic_intr_info[vector].rtes);
+ INIT_LIST_HEAD(&iosapic_intr_info[irq].rtes);
+
+ iosapic_intr_info[irq].count = 0;
}
pcat_compat = system_pcat_compat;
@@ -1108,31 +1051,35 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
- {
- addr = ioremap(phys_addr, 0);
- ver = iosapic_version(addr);
+ index = find_iosapic(gsi_base);
+ if (index >= 0) {
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+ return -EBUSY;
+ }
- if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
- iounmap(addr);
- spin_unlock_irqrestore(&iosapic_lock, flags);
- return err;
- }
+ addr = ioremap(phys_addr, 0);
+ ver = iosapic_version(addr);
+ if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
+ iounmap(addr);
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+ return err;
+ }
- /*
- * The MAX_REDIR register holds the highest input pin
- * number (starting from 0).
- * We add 1 so that we can use it for number of pins (= RTEs)
- */
- num_rte = ((ver >> 16) & 0xff) + 1;
+ /*
+ * The MAX_REDIR register holds the highest input pin number
+ * (starting from 0). We add 1 so that we can use it for
+ * number of pins (= RTEs)
+ */
+ num_rte = ((ver >> 16) & 0xff) + 1;
- index = iosapic_alloc();
- iosapic_lists[index].addr = addr;
- iosapic_lists[index].gsi_base = gsi_base;
- iosapic_lists[index].num_rte = num_rte;
+ index = iosapic_alloc();
+ iosapic_lists[index].addr = addr;
+ iosapic_lists[index].gsi_base = gsi_base;
+ iosapic_lists[index].num_rte = num_rte;
#ifdef CONFIG_NUMA
- iosapic_lists[index].node = MAX_NUMNODES;
+ iosapic_lists[index].node = MAX_NUMNODES;
#endif
- }
+ spin_lock_init(&iosapic_lists[index].lock);
spin_unlock_irqrestore(&iosapic_lock, flags);
if ((gsi_base == 0) && pcat_compat) {
@@ -1157,25 +1104,22 @@ iosapic_remove (unsigned int gsi_base)
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
- {
- index = find_iosapic(gsi_base);
- if (index < 0) {
- printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
- __FUNCTION__, gsi_base);
- goto out;
- }
-
- if (iosapic_lists[index].rtes_inuse) {
- err = -EBUSY;
- printk(KERN_WARNING
- "%s: IOSAPIC for GSI base %u is busy\n",
- __FUNCTION__, gsi_base);
- goto out;
- }
+ index = find_iosapic(gsi_base);
+ if (index < 0) {
+ printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
+ __FUNCTION__, gsi_base);
+ goto out;
+ }
- iounmap(iosapic_lists[index].addr);
- iosapic_free(index);
+ if (iosapic_lists[index].rtes_inuse) {
+ err = -EBUSY;
+ printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+ __FUNCTION__, gsi_base);
+ goto out;
}
+
+ iounmap(iosapic_lists[index].addr);
+ iosapic_free(index);
out:
spin_unlock_irqrestore(&iosapic_lock, flags);
return err;
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 407b45870489..cc3ee4ef37af 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -35,7 +35,7 @@ void ack_bad_irq(unsigned int irq)
#ifdef CONFIG_IA64_GENERIC
unsigned int __ia64_local_vector_to_irq (ia64_vector vec)
{
- return (unsigned int) vec;
+ return __get_cpu_var(vector_irq)[vec];
}
#endif
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index bc47049f060f..91797c111162 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -46,6 +46,12 @@
#define IRQ_DEBUG 0
+#define IRQ_VECTOR_UNASSIGNED (0)
+
+#define IRQ_UNUSED (0)
+#define IRQ_USED (1)
+#define IRQ_RSVD (2)
+
/* These can be overridden in platform_irq_init */
int ia64_first_device_vector = IA64_DEF_FIRST_DEVICE_VECTOR;
int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
@@ -54,6 +60,8 @@ int ia64_last_device_vector = IA64_DEF_LAST_DEVICE_VECTOR;
void __iomem *ipi_base_addr = ((void __iomem *)
(__IA64_UNCACHED_OFFSET | IA64_IPI_DEFAULT_BASE_ADDR));
+static cpumask_t vector_allocation_domain(int cpu);
+
/*
* Legacy IRQ to IA-64 vector translation table.
*/
@@ -64,46 +72,269 @@ __u8 isa_irq_to_vector_map[16] = {
};
EXPORT_SYMBOL(isa_irq_to_vector_map);
-static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_MAX_DEVICE_VECTORS)];
+DEFINE_SPINLOCK(vector_lock);
+
+struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
+ [0 ... NR_IRQS - 1] = {
+ .vector = IRQ_VECTOR_UNASSIGNED,
+ .domain = CPU_MASK_NONE
+ }
+};
+
+DEFINE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq) = {
+ [0 ... IA64_NUM_VECTORS - 1] = IA64_SPURIOUS_INT_VECTOR
+};
+
+static cpumask_t vector_table[IA64_MAX_DEVICE_VECTORS] = {
+ [0 ... IA64_MAX_DEVICE_VECTORS - 1] = CPU_MASK_NONE
+};
+
+static int irq_status[NR_IRQS] = {
+ [0 ... NR_IRQS -1] = IRQ_UNUSED
+};
+
+int check_irq_used(int irq)
+{
+ if (irq_status[irq] == IRQ_USED)
+ return 1;
+
+ return -1;
+}
+
+static void reserve_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ irq_status[irq] = IRQ_RSVD;
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+static inline int find_unassigned_irq(void)
+{
+ int irq;
+
+ for (irq = IA64_FIRST_DEVICE_VECTOR; irq < NR_IRQS; irq++)
+ if (irq_status[irq] == IRQ_UNUSED)
+ return irq;
+ return -ENOSPC;
+}
+
+static inline int find_unassigned_vector(cpumask_t domain)
+{
+ cpumask_t mask;
+ int pos;
+
+ cpus_and(mask, domain, cpu_online_map);
+ if (cpus_empty(mask))
+ return -EINVAL;
+
+ for (pos = 0; pos < IA64_NUM_DEVICE_VECTORS; pos++) {
+ cpus_and(mask, domain, vector_table[pos]);
+ if (!cpus_empty(mask))
+ continue;
+ return IA64_FIRST_DEVICE_VECTOR + pos;
+ }
+ return -ENOSPC;
+}
+
+static int __bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+ cpumask_t mask;
+ int cpu, pos;
+ struct irq_cfg *cfg = &irq_cfg[irq];
+
+ cpus_and(mask, domain, cpu_online_map);
+ if (cpus_empty(mask))
+ return -EINVAL;
+ if ((cfg->vector == vector) && cpus_equal(cfg->domain, domain))
+ return 0;
+ if (cfg->vector != IRQ_VECTOR_UNASSIGNED)
+ return -EBUSY;
+ for_each_cpu_mask(cpu, mask)
+ per_cpu(vector_irq, cpu)[vector] = irq;
+ cfg->vector = vector;
+ cfg->domain = domain;
+ irq_status[irq] = IRQ_USED;
+ pos = vector - IA64_FIRST_DEVICE_VECTOR;
+ cpus_or(vector_table[pos], vector_table[pos], domain);
+ return 0;
+}
+
+int bind_irq_vector(int irq, int vector, cpumask_t domain)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ ret = __bind_irq_vector(irq, vector, domain);
+ spin_unlock_irqrestore(&vector_lock, flags);
+ return ret;
+}
+
+static void __clear_irq_vector(int irq)
+{
+ int vector, cpu, pos;
+ cpumask_t mask;
+ cpumask_t domain;
+ struct irq_cfg *cfg = &irq_cfg[irq];
+
+ BUG_ON((unsigned)irq >= NR_IRQS);
+ BUG_ON(cfg->vector == IRQ_VECTOR_UNASSIGNED);
+ vector = cfg->vector;
+ domain = cfg->domain;
+ cpus_and(mask, cfg->domain, cpu_online_map);
+ for_each_cpu_mask(cpu, mask)
+ per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+ cfg->vector = IRQ_VECTOR_UNASSIGNED;
+ cfg->domain = CPU_MASK_NONE;
+ irq_status[irq] = IRQ_UNUSED;
+ pos = vector - IA64_FIRST_DEVICE_VECTOR;
+ cpus_andnot(vector_table[pos], vector_table[pos], domain);
+}
+
+static void clear_irq_vector(int irq)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ __clear_irq_vector(irq);
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
int
assign_irq_vector (int irq)
{
- int pos, vector;
- again:
- pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
- vector = IA64_FIRST_DEVICE_VECTOR + pos;
- if (vector > IA64_LAST_DEVICE_VECTOR)
- return -ENOSPC;
- if (test_and_set_bit(pos, ia64_vector_mask))
- goto again;
+ unsigned long flags;
+ int vector, cpu;
+ cpumask_t domain;
+
+ vector = -ENOSPC;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ if (irq < 0) {
+ goto out;
+ }
+ for_each_online_cpu(cpu) {
+ domain = vector_allocation_domain(cpu);
+ vector = find_unassigned_vector(domain);
+ if (vector >= 0)
+ break;
+ }
+ if (vector < 0)
+ goto out;
+ BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+ spin_unlock_irqrestore(&vector_lock, flags);
return vector;
}
void
free_irq_vector (int vector)
{
- int pos;
-
- if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR)
+ if (vector < IA64_FIRST_DEVICE_VECTOR ||
+ vector > IA64_LAST_DEVICE_VECTOR)
return;
-
- pos = vector - IA64_FIRST_DEVICE_VECTOR;
- if (!test_and_clear_bit(pos, ia64_vector_mask))
- printk(KERN_WARNING "%s: double free!\n", __FUNCTION__);
+ clear_irq_vector(vector);
}
int
reserve_irq_vector (int vector)
{
- int pos;
-
if (vector < IA64_FIRST_DEVICE_VECTOR ||
vector > IA64_LAST_DEVICE_VECTOR)
return -EINVAL;
+ return !!bind_irq_vector(vector, vector, CPU_MASK_ALL);
+}
- pos = vector - IA64_FIRST_DEVICE_VECTOR;
- return test_and_set_bit(pos, ia64_vector_mask);
+/*
+ * Initialize vector_irq on a new cpu. This function must be called
+ * with vector_lock held.
+ */
+void __setup_vector_irq(int cpu)
+{
+ int irq, vector;
+
+ /* Clear vector_irq */
+ for (vector = 0; vector < IA64_NUM_VECTORS; ++vector)
+ per_cpu(vector_irq, cpu)[vector] = IA64_SPURIOUS_INT_VECTOR;
+ /* Mark the inuse vectors */
+ for (irq = 0; irq < NR_IRQS; ++irq) {
+ if (!cpu_isset(cpu, irq_cfg[irq].domain))
+ continue;
+ vector = irq_to_vector(irq);
+ per_cpu(vector_irq, cpu)[vector] = irq;
+ }
+}
+
+#if defined(CONFIG_SMP) && (defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_DIG))
+static enum vector_domain_type {
+ VECTOR_DOMAIN_NONE,
+ VECTOR_DOMAIN_PERCPU
+} vector_domain_type = VECTOR_DOMAIN_NONE;
+
+static cpumask_t vector_allocation_domain(int cpu)
+{
+ if (vector_domain_type == VECTOR_DOMAIN_PERCPU)
+ return cpumask_of_cpu(cpu);
+ return CPU_MASK_ALL;
+}
+
+static int __init parse_vector_domain(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+ if (!strcmp(arg, "percpu")) {
+ vector_domain_type = VECTOR_DOMAIN_PERCPU;
+ no_int_routing = 1;
+ }
+ return 1;
+}
+early_param("vector", parse_vector_domain);
+#else
+static cpumask_t vector_allocation_domain(int cpu)
+{
+ return CPU_MASK_ALL;
+}
+#endif
+
+
+void destroy_and_reserve_irq(unsigned int irq)
+{
+ dynamic_irq_cleanup(irq);
+
+ clear_irq_vector(irq);
+ reserve_irq(irq);
+}
+
+static int __reassign_irq_vector(int irq, int cpu)
+{
+ struct irq_cfg *cfg = &irq_cfg[irq];
+ int vector;
+ cpumask_t domain;
+
+ if (cfg->vector == IRQ_VECTOR_UNASSIGNED || !cpu_online(cpu))
+ return -EINVAL;
+ if (cpu_isset(cpu, cfg->domain))
+ return 0;
+ domain = vector_allocation_domain(cpu);
+ vector = find_unassigned_vector(domain);
+ if (vector < 0)
+ return -ENOSPC;
+ __clear_irq_vector(irq);
+ BUG_ON(__bind_irq_vector(irq, vector, domain));
+ return 0;
+}
+
+int reassign_irq_vector(int irq, int cpu)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ ret = __reassign_irq_vector(irq, cpu);
+ spin_unlock_irqrestore(&vector_lock, flags);
+ return ret;
}
/*
@@ -111,18 +342,35 @@ reserve_irq_vector (int vector)
*/
int create_irq(void)
{
- int vector = assign_irq_vector(AUTO_ASSIGN);
-
- if (vector >= 0)
- dynamic_irq_init(vector);
-
- return vector;
+ unsigned long flags;
+ int irq, vector, cpu;
+ cpumask_t domain;
+
+ irq = vector = -ENOSPC;
+ spin_lock_irqsave(&vector_lock, flags);
+ for_each_online_cpu(cpu) {
+ domain = vector_allocation_domain(cpu);
+ vector = find_unassigned_vector(domain);
+ if (vector >= 0)
+ break;
+ }
+ if (vector < 0)
+ goto out;
+ irq = find_unassigned_irq();
+ if (irq < 0)
+ goto out;
+ BUG_ON(__bind_irq_vector(irq, vector, domain));
+ out:
+ spin_unlock_irqrestore(&vector_lock, flags);
+ if (irq >= 0)
+ dynamic_irq_init(irq);
+ return irq;
}
void destroy_irq(unsigned int irq)
{
dynamic_irq_cleanup(irq);
- free_irq_vector(irq);
+ clear_irq_vector(irq);
}
#ifdef CONFIG_SMP
@@ -301,14 +549,13 @@ register_percpu_irq (ia64_vector vec, struct irqaction *action)
irq_desc_t *desc;
unsigned int irq;
- for (irq = 0; irq < NR_IRQS; ++irq)
- if (irq_to_vector(irq) == vec) {
- desc = irq_desc + irq;
- desc->status |= IRQ_PER_CPU;
- desc->chip = &irq_type_ia64_lsapic;
- if (action)
- setup_irq(irq, action);
- }
+ irq = vec;
+ BUG_ON(bind_irq_vector(irq, vec, CPU_MASK_ALL));
+ desc = irq_desc + irq;
+ desc->status |= IRQ_PER_CPU;
+ desc->chip = &irq_type_ia64_lsapic;
+ if (action)
+ setup_irq(irq, action);
}
void __init
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 5bc46f151344..5dc98b5abcfb 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -936,10 +936,15 @@ static void ia64_get_bsp_cfm(struct unw_frame_info *info, void *arg)
return;
}
+unsigned long arch_deref_entry_point(void *entry)
+{
+ return ((struct fnptr *)entry)->ip;
+}
+
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
- unsigned long addr = ((struct fnptr *)(jp->entry))->ip;
+ unsigned long addr = arch_deref_entry_point(jp->entry);
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
struct param_bsp_cfm pa;
int bytes;
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 1ead5ea6c5ce..4b5daa3cc0fe 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -57,6 +57,9 @@
*
* 2006-09-15 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
* Add printing support for MCA/INIT.
+ *
+ * 2007-04-27 Russ Anderson <rja@sgi.com>
+ * Support multiple cpus going through OS_MCA in the same event.
*/
#include <linux/types.h>
#include <linux/init.h>
@@ -96,7 +99,6 @@
#endif
/* Used by mca_asm.S */
-u32 ia64_mca_serialize;
DEFINE_PER_CPU(u64, ia64_mca_data); /* == __per_cpu_mca[smp_processor_id()] */
DEFINE_PER_CPU(u64, ia64_mca_per_cpu_pte); /* PTE to map per-CPU area */
DEFINE_PER_CPU(u64, ia64_mca_pal_pte); /* PTE to map PAL code */
@@ -963,11 +965,12 @@ ia64_mca_modify_original_stack(struct pt_regs *regs,
goto no_mod;
}
+ if (r13 != sos->prev_IA64_KR_CURRENT) {
+ msg = "inconsistent previous current and r13";
+ goto no_mod;
+ }
+
if (!mca_recover_range(ms->pmsa_iip)) {
- if (r13 != sos->prev_IA64_KR_CURRENT) {
- msg = "inconsistent previous current and r13";
- goto no_mod;
- }
if ((r12 - r13) >= KERNEL_STACK_SIZE) {
msg = "inconsistent r12 and r13";
goto no_mod;
@@ -1187,6 +1190,13 @@ all_in:
* further MCA logging is enabled by clearing logs.
* Monarch also has the duty of sending wakeup-IPIs to pull the
* slave processors out of rendezvous spinloop.
+ *
+ * If multiple processors call into OS_MCA, the first will become
+ * the monarch. Subsequent cpus will be recorded in the mca_cpu
+ * bitmask. After the first monarch has processed its MCA, it
+ * will wake up the next cpu in the mca_cpu bitmask and then go
+ * into the rendezvous loop. When all processors have serviced
+ * their MCA, the last monarch frees up the rest of the processors.
*/
void
ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
@@ -1196,16 +1206,32 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
struct task_struct *previous_current;
struct ia64_mca_notify_die nd =
{ .sos = sos, .monarch_cpu = &monarch_cpu };
+ static atomic_t mca_count;
+ static cpumask_t mca_cpu;
+ if (atomic_add_return(1, &mca_count) == 1) {
+ monarch_cpu = cpu;
+ sos->monarch = 1;
+ } else {
+ cpu_set(cpu, mca_cpu);
+ sos->monarch = 0;
+ }
mprintk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d "
"monarch=%ld\n", sos->proc_state_param, cpu, sos->monarch);
previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA");
- monarch_cpu = cpu;
+
if (notify_die(DIE_MCA_MONARCH_ENTER, "MCA", regs, (long)&nd, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
- ia64_wait_for_slaves(cpu, "MCA");
+ if (sos->monarch) {
+ ia64_wait_for_slaves(cpu, "MCA");
+ } else {
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
+ while (cpu_isset(cpu, mca_cpu))
+ cpu_relax(); /* spin until monarch wakes us */
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+ }
/* Wakeup all the processors which are spinning in the rendezvous loop.
* They will leave SAL, then spin in the OS with interrupts disabled
@@ -1244,6 +1270,26 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
+
+ if (atomic_dec_return(&mca_count) > 0) {
+ int i;
+
+ /* wake up the next monarch cpu,
+ * and put this cpu in the rendez loop.
+ */
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA;
+ for_each_online_cpu(i) {
+ if (cpu_isset(i, mca_cpu)) {
+ monarch_cpu = i;
+ cpu_clear(i, mca_cpu); /* wake next cpu */
+ while (monarch_cpu != -1)
+ cpu_relax(); /* spin until last cpu leaves */
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+ set_curr_task(cpu, previous_current);
+ return;
+ }
+ }
+ }
set_curr_task(cpu, previous_current);
monarch_cpu = -1;
}
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index 8c9c26aa6ae0..0f5965fcdf85 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -133,14 +133,6 @@ ia64_do_tlb_purge:
//StartMain////////////////////////////////////////////////////////////////////
ia64_os_mca_dispatch:
- // Serialize all MCA processing
- mov r3=1;;
- LOAD_PHYSICAL(p0,r2,ia64_mca_serialize);;
-ia64_os_mca_spin:
- xchg4 r4=[r2],r3;;
- cmp.ne p6,p0=r4,r0
-(p6) br ia64_os_mca_spin
-
mov r3=IA64_MCA_CPU_MCA_STACK_OFFSET // use the MCA stack
LOAD_PHYSICAL(p0,r2,1f) // return address
mov r19=1 // All MCA events are treated as monarch (for now)
@@ -291,10 +283,6 @@ END(ia64_os_mca_virtual_begin)
mov b0=r12 // SAL_CHECK return address
- // release lock
- LOAD_PHYSICAL(p0,r3,ia64_mca_serialize);;
- st4.rel [r3]=r0
-
br b0
//EndMain//////////////////////////////////////////////////////////////////////
diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S
index f2d4900751ba..3bccb06c8d21 100644
--- a/arch/ia64/kernel/mca_drv_asm.S
+++ b/arch/ia64/kernel/mca_drv_asm.S
@@ -40,7 +40,11 @@ GLOBAL_ENTRY(mca_handler_bhhook)
mov b6=loc1
;;
mov loc1=rp
- ssm psr.i | psr.ic
+ ssm psr.ic
+ ;;
+ srlz.i
+ ;;
+ ssm psr.i
br.call.sptk.many rp=b6 // does not return ...
;;
mov ar.pfs=loc0
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index c81080df70df..2fdbd5c3f213 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -13,6 +13,7 @@
#define MSI_DATA_VECTOR_SHIFT 0
#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
+#define MSI_DATA_VECTOR_MASK 0xffffff00
#define MSI_DATA_DELIVERY_SHIFT 8
#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
@@ -50,17 +51,29 @@ static struct irq_chip ia64_msi_chip;
static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
{
struct msi_msg msg;
- u32 addr;
+ u32 addr, data;
+ int cpu = first_cpu(cpu_mask);
+
+ if (!cpu_online(cpu))
+ return;
+
+ if (reassign_irq_vector(irq, cpu))
+ return;
read_msi_msg(irq, &msg);
addr = msg.address_lo;
addr &= MSI_ADDR_DESTID_MASK;
- addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+ addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(cpu));
msg.address_lo = addr;
+ data = msg.data;
+ data &= MSI_DATA_VECTOR_MASK;
+ data |= MSI_DATA_VECTOR(irq_to_vector(irq));
+ msg.data = data;
+
write_msi_msg(irq, &msg);
- irq_desc[irq].affinity = cpu_mask;
+ irq_desc[irq].affinity = cpumask_of_cpu(cpu);
}
#endif /* CONFIG_SMP */
@@ -69,13 +82,15 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
struct msi_msg msg;
unsigned long dest_phys_id;
int irq, vector;
+ cpumask_t mask;
irq = create_irq();
if (irq < 0)
return irq;
set_irq_msi(irq, desc);
- dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+ cpus_and(mask, irq_to_domain(irq), cpu_online_map);
+ dest_phys_id = cpu_physical_id(first_cpu(mask));
vector = irq_to_vector(irq);
msg.address_hi = 0;
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index af73b8dfde28..fa40cba43350 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -513,7 +513,8 @@ copy_thread (int nr, unsigned long clone_flags,
static void
do_copy_task_regs (struct task_struct *task, struct unw_frame_info *info, void *arg)
{
- unsigned long mask, sp, nat_bits = 0, ip, ar_rnat, urbs_end, cfm;
+ unsigned long mask, sp, nat_bits = 0, ar_rnat, urbs_end, cfm;
+ unsigned long uninitialized_var(ip); /* GCC be quiet */
elf_greg_t *dst = arg;
struct pt_regs *pt;
char nat;
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 188fb73c6845..cf06fe799041 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -390,10 +390,6 @@ early_console_setup (char *cmdline)
if (!efi_setup_pcdp_console(cmdline))
earlycons++;
#endif
-#ifdef CONFIG_SERIAL_8250_CONSOLE
- if (!early_serial_console_init(cmdline))
- earlycons++;
-#endif
return (earlycons) ? 0 : -1;
}
@@ -984,15 +980,6 @@ cpu_init (void)
pm_idle = default_idle;
}
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- */
-void sched_cacheflush(void)
-{
- ia64_sal_cache_flush(3);
-}
-
void __init
check_bugs (void)
{
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index b3a47f986e1e..9f72838db26e 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -82,7 +82,7 @@ static volatile struct call_data_struct *call_data;
#define IPI_KDUMP_CPU_STOP 3
/* This needs to be cacheline aligned because it is written to by *other* CPUs. */
-static DEFINE_PER_CPU(u64, ipi_operation) ____cacheline_aligned;
+static DEFINE_PER_CPU_SHARED_ALIGNED(u64, ipi_operation);
extern void cpu_halt (void);
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 3c9d8e6089cf..9f5c90b594b9 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -395,9 +395,13 @@ smp_callin (void)
fix_b0_for_bsp();
lock_ipi_calllock();
+ spin_lock(&vector_lock);
+ /* Setup the per cpu irq handling data structures */
+ __setup_vector_irq(cpuid);
cpu_set(cpuid, cpu_online_map);
unlock_ipi_calllock();
per_cpu(cpu_state, cpuid) = CPU_ONLINE;
+ spin_unlock(&vector_lock);
smp_setup_percpu_timer();
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 3486fe7d6e65..627785c48ea9 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/efi.h>
#include <linux/timex.h>
+#include <linux/clocksource.h>
#include <asm/machvec.h>
#include <asm/delay.h>
@@ -28,6 +29,16 @@
#include <asm/sections.h>
#include <asm/system.h>
+#include "fsyscall_gtod_data.h"
+
+static cycle_t itc_get_cycles(void);
+
+struct fsyscall_gtod_data_t fsyscall_gtod_data = {
+ .lock = SEQLOCK_UNLOCKED,
+};
+
+struct itc_jitter_data_t itc_jitter_data;
+
volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
#ifdef CONFIG_IA64_DEBUG_IRQ
@@ -37,11 +48,16 @@ EXPORT_SYMBOL(last_cli_ip);
#endif
-static struct time_interpolator itc_interpolator = {
- .shift = 16,
- .mask = 0xffffffffffffffffLL,
- .source = TIME_SOURCE_CPU
+static struct clocksource clocksource_itc = {
+ .name = "itc",
+ .rating = 350,
+ .read = itc_get_cycles,
+ .mask = 0xffffffffffffffff,
+ .mult = 0, /*to be caluclated*/
+ .shift = 16,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
+static struct clocksource *itc_clocksource;
static irqreturn_t
timer_interrupt (int irq, void *dev_id)
@@ -210,8 +226,6 @@ ia64_init_itm (void)
+ itc_freq/2)/itc_freq;
if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
- itc_interpolator.frequency = local_cpu_data->itc_freq;
- itc_interpolator.drift = itc_drift;
#ifdef CONFIG_SMP
/* On IA64 in an SMP configuration ITCs are never accurately synchronized.
* Jitter compensation requires a cmpxchg which may limit
@@ -223,15 +237,50 @@ ia64_init_itm (void)
* even going backward) if the ITC offsets between the individual CPUs
* are too large.
*/
- if (!nojitter) itc_interpolator.jitter = 1;
+ if (!nojitter)
+ itc_jitter_data.itc_jitter = 1;
#endif
- register_time_interpolator(&itc_interpolator);
}
/* Setup the CPU local timer tick */
ia64_cpu_local_tick();
+
+ if (!itc_clocksource) {
+ /* Sort out mult/shift values: */
+ clocksource_itc.mult =
+ clocksource_hz2mult(local_cpu_data->itc_freq,
+ clocksource_itc.shift);
+ clocksource_register(&clocksource_itc);
+ itc_clocksource = &clocksource_itc;
+ }
}
+static cycle_t itc_get_cycles()
+{
+ u64 lcycle, now, ret;
+
+ if (!itc_jitter_data.itc_jitter)
+ return get_cycles();
+
+ lcycle = itc_jitter_data.itc_lastcycle;
+ now = get_cycles();
+ if (lcycle && time_after(lcycle, now))
+ return lcycle;
+
+ /*
+ * Keep track of the last timer value returned.
+ * In an SMP environment, you could lose out in contention of
+ * cmpxchg. If so, your cmpxchg returns new value which the
+ * winner of contention updated to. Use the new value instead.
+ */
+ ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, now);
+ if (unlikely(ret != lcycle))
+ return ret;
+
+ return now;
+}
+
+
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED | IRQF_IRQPOLL,
@@ -307,3 +356,34 @@ ia64_setup_printk_clock(void)
if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
ia64_printk_clock = ia64_itc_printk_clock;
}
+
+void update_vsyscall(struct timespec *wall, struct clocksource *c)
+{
+ unsigned long flags;
+
+ write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
+
+ /* copy fsyscall clock data */
+ fsyscall_gtod_data.clk_mask = c->mask;
+ fsyscall_gtod_data.clk_mult = c->mult;
+ fsyscall_gtod_data.clk_shift = c->shift;
+ fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
+ fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
+
+ /* copy kernel time structures */
+ fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
+ fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
+ fsyscall_gtod_data.monotonic_time.tv_sec = wall_to_monotonic.tv_sec
+ + wall->tv_sec;
+ fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
+ + wall->tv_nsec;
+
+ /* normalize */
+ while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
+ fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
+ fsyscall_gtod_data.monotonic_time.tv_sec++;
+ }
+
+ write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
+}
+
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index 15ad85da15a9..3aeaf15e468b 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -69,6 +69,7 @@ die (const char *str, struct pt_regs *regs, long err)
bust_spinlocks(0);
die.lock_owner = -1;
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die.lock);
if (panic_on_oops)
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 5a65965c8b53..860f251d2fc2 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -206,6 +206,7 @@ SECTIONS
{
__per_cpu_start = .;
*(.data.percpu)
+ *(.data.percpu.shared_aligned)
__per_cpu_end = .;
}
. = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits
diff --git a/arch/ia64/lib/checksum.c b/arch/ia64/lib/checksum.c
index 4411d9baeb21..9fc955026f86 100644
--- a/arch/ia64/lib/checksum.c
+++ b/arch/ia64/lib/checksum.c
@@ -60,6 +60,7 @@ csum_tcpudp_nofold (__be32 saddr, __be32 daddr, unsigned short len,
result = (result & 0xffffffff) + (result >> 32);
return (__force __wsum)result;
}
+EXPORT_SYMBOL(csum_tcpudp_nofold);
extern unsigned long do_csum (const unsigned char *, long);
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index b87f785c2416..73ccb6010c05 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -80,6 +80,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
struct mm_struct *mm = current->mm;
struct siginfo si;
unsigned long mask;
+ int fault;
/* mmap_sem is performance critical.... */
prefetchw(&mm->mmap_sem);
@@ -147,26 +148,25 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
* sure we exit gracefully rather than endlessly redo the
* fault.
*/
- switch (handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0)) {
- case VM_FAULT_MINOR:
- ++current->min_flt;
- break;
- case VM_FAULT_MAJOR:
- ++current->maj_flt;
- break;
- case VM_FAULT_SIGBUS:
+ fault = handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
/*
* We ran out of memory, or some other thing happened
* to us that made us unable to handle the page fault
* gracefully.
*/
- signal = SIGBUS;
- goto bad_area;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ if (fault & VM_FAULT_OOM) {
+ goto out_of_memory;
+ } else if (fault & VM_FAULT_SIGBUS) {
+ signal = SIGBUS;
+ goto bad_area;
+ }
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
return;
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index fa4e6d4810f3..1682fc639038 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -175,7 +175,7 @@ EXPORT_SYMBOL(flush_tlb_range);
void __devinit
ia64_tlb_init (void)
{
- ia64_ptce_info_t ptce_info;
+ ia64_ptce_info_t uninitialized_var(ptce_info); /* GCC be quiet */
unsigned long tr_pgbits;
long status;
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 73696b4a2eed..07d0e92742c8 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -591,6 +591,9 @@ int
pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
+ unsigned long size = vma->vm_end - vma->vm_start;
+ pgprot_t prot;
+
/*
* I/O space cannot be accessed via normal processor loads and
* stores on this platform.
@@ -604,15 +607,24 @@ pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
*/
return -EINVAL;
+ if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
+ return -EINVAL;
+
+ prot = phys_mem_access_prot(NULL, vma->vm_pgoff, size,
+ vma->vm_page_prot);
+
/*
- * Leave vm_pgoff as-is, the PCI space address is the physical
- * address on this platform.
+ * If the user requested WC, the kernel uses UC or WC for this region,
+ * and the chipset supports WC, we can use WC. Otherwise, we have to
+ * use the same attribute the kernel uses.
*/
- if (write_combine && efi_range_is_wc(vma->vm_start,
- vma->vm_end - vma->vm_start))
+ if (write_combine &&
+ ((pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_UC ||
+ (pgprot_val(prot) & _PAGE_MA_MASK) == _PAGE_MA_WC) &&
+ efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_page_prot = prot;
if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c
index c6216f454ffb..3c7178f5dce8 100644
--- a/arch/ia64/sn/kernel/io_acpi_init.c
+++ b/arch/ia64/sn/kernel/io_acpi_init.c
@@ -418,7 +418,7 @@ sn_acpi_slot_fixup(struct pci_dev *dev)
void __iomem *addr;
struct pcidev_info *pcidev_info = NULL;
struct sn_irq_info *sn_irq_info = NULL;
- size_t size;
+ size_t image_size, size;
if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) {
panic("%s: Failure obtaining pcidev_info for %s\n",
@@ -428,17 +428,16 @@ sn_acpi_slot_fixup(struct pci_dev *dev)
if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
/*
* A valid ROM image exists and has been shadowed by the
- * PROM. Setup the pci_dev ROM resource to point to
- * the shadowed copy.
+ * PROM. Setup the pci_dev ROM resource with the address
+ * of the shadowed copy, and the actual length of the ROM image.
*/
- size = dev->resource[PCI_ROM_RESOURCE].end -
- dev->resource[PCI_ROM_RESOURCE].start;
- addr =
- ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE],
- size);
+ size = pci_resource_len(dev, PCI_ROM_RESOURCE);
+ addr = ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE],
+ size);
+ image_size = pci_get_rom_size(addr, size);
dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr;
dev->resource[PCI_ROM_RESOURCE].end =
- (unsigned long) addr + size;
+ (unsigned long) addr + image_size - 1;
dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY;
}
sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 6b10e5d28488..906b93674b76 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -259,9 +259,23 @@ sn_io_slot_fixup(struct pci_dev *dev)
insert_resource(&ioport_resource, &dev->resource[idx]);
else
insert_resource(&iomem_resource, &dev->resource[idx]);
- /* If ROM, mark as shadowed in PROM */
- if (idx == PCI_ROM_RESOURCE)
- dev->resource[idx].flags |= IORESOURCE_ROM_BIOS_COPY;
+ /*
+ * If ROM, set the actual ROM image size, and mark as
+ * shadowed in PROM.
+ */
+ if (idx == PCI_ROM_RESOURCE) {
+ size_t image_size;
+ void __iomem *rom;
+
+ rom = ioremap(pci_resource_start(dev, PCI_ROM_RESOURCE),
+ size + 1);
+ image_size = pci_get_rom_size(rom, size + 1);
+ dev->resource[PCI_ROM_RESOURCE].end =
+ dev->resource[PCI_ROM_RESOURCE].start +
+ image_size - 1;
+ dev->resource[PCI_ROM_RESOURCE].flags |=
+ IORESOURCE_ROM_BIOS_COPY;
+ }
}
/* Create a pci_window in the pci_controller struct for
* each device resource.
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index 6da9854751cd..df8d5bed6119 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -750,9 +750,10 @@ sn_hwperf_ioctl(struct inode *in, struct file *fp, u32 op, u64 arg)
goto error;
} else
if ((r = sn_hwperf_enum_objects(&nobj, &objs)) == 0) {
+ int cpuobj_index = 0;
+
memset(p, 0, a.sz);
for (i = 0; i < nobj; i++) {
- int cpuobj_index = 0;
if (!SN_HWPERF_IS_NODE(objs + i))
continue;
node = sn_hwperf_obj_to_cnode(objs + i);
diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c
index 56a88b6df4b4..19e25d2b64fc 100644
--- a/arch/ia64/sn/kernel/sn2/timer.c
+++ b/arch/ia64/sn/kernel/sn2/timer.c
@@ -11,6 +11,7 @@
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/interrupt.h>
+#include <linux/clocksource.h>
#include <asm/hw_irq.h>
#include <asm/system.h>
@@ -22,11 +23,21 @@
extern unsigned long sn_rtc_cycles_per_second;
-static struct time_interpolator sn2_interpolator = {
- .drift = -1,
- .shift = 10,
- .mask = (1LL << 55) - 1,
- .source = TIME_SOURCE_MMIO64
+static void __iomem *sn2_mc;
+
+static cycle_t read_sn2(void)
+{
+ return (cycle_t)readq(sn2_mc);
+}
+
+static struct clocksource clocksource_sn2 = {
+ .name = "sn2_rtc",
+ .rating = 300,
+ .read = read_sn2,
+ .mask = (1LL << 55) - 1,
+ .mult = 0,
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
/*
@@ -47,9 +58,11 @@ ia64_sn_udelay (unsigned long usecs)
void __init sn_timer_init(void)
{
- sn2_interpolator.frequency = sn_rtc_cycles_per_second;
- sn2_interpolator.addr = RTC_COUNTER_ADDR;
- register_time_interpolator(&sn2_interpolator);
+ sn2_mc = RTC_COUNTER_ADDR;
+ clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
+ clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
+ clocksource_sn2.shift);
+ clocksource_register(&clocksource_sn2);
ia64_udelay = &ia64_sn_udelay;
}
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index 493380b2c05f..5a289e4de838 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -369,7 +369,7 @@ static void tio_corelet_reset(nasid_t nasid, int corelet)
static int is_fpga_tio(int nasid, int *bt)
{
- u16 ioboard_type;
+ u16 uninitialized_var(ioboard_type); /* GCC be quiet */
s64 rc;
rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard_type);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index b42bfcae6f91..42485ad50ceb 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -80,7 +80,7 @@ static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus)
{
s64 rc;
- u16 ioboard;
+ u16 uninitialized_var(ioboard); /* GCC be quiet */
nasid_t nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base);
rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard);
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index c3bb8a755b00..8ccf3e47bff8 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -31,6 +31,9 @@ config GENERIC_IRQ_PROBE
config NO_IOPORT
def_bool y
+config NO_DMA
+ def_bool y
+
source "init/Kconfig"
diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c
index 5f02b3144875..57a92ef31a90 100644
--- a/arch/m32r/kernel/ptrace.c
+++ b/arch/m32r/kernel/ptrace.c
@@ -595,7 +595,6 @@ void ptrace_disable(struct task_struct *child)
static int
do_ptrace(long request, struct task_struct *child, long addr, long data)
{
- unsigned long tmp;
int ret;
switch (request) {
@@ -604,11 +603,7 @@ do_ptrace(long request, struct task_struct *child, long addr, long data)
*/
case PTRACE_PEEKTEXT:
case PTRACE_PEEKDATA:
- ret = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (ret == sizeof(tmp))
- ret = put_user(tmp,(unsigned long __user *) data);
- else
- ret = -EIO;
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
/*
@@ -624,15 +619,9 @@ do_ptrace(long request, struct task_struct *child, long addr, long data)
*/
case PTRACE_POKETEXT:
case PTRACE_POKEDATA:
- ret = access_process_vm(child, addr, &data, sizeof(data), 1);
- if (ret == sizeof(data)) {
- ret = 0;
- if (request == PTRACE_POKETEXT) {
- invalidate_cache();
- }
- } else {
- ret = -EIO;
- }
+ ret = generic_ptrace_pokedata(child, addr, data);
+ if (ret == 0 && request == PTRACE_POKETEXT)
+ invalidate_cache();
break;
/*
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 4e2d5b9f0a9a..942a8c7a4417 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -110,10 +110,7 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(4096);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(4096)
. = ALIGN(4096);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/m32r/m32104ut/defconfig.m32104ut b/arch/m32r/m32104ut/defconfig.m32104ut
index 7b68fe8d921e..1f88f493a9e2 100644
--- a/arch/m32r/m32104ut/defconfig.m32104ut
+++ b/arch/m32r/m32104ut/defconfig.m32104ut
@@ -699,7 +699,6 @@ CONFIG_I2C_ALGOPCF=m
# I2C Hardware Bus support
#
CONFIG_I2C_ELEKTOR=m
-CONFIG_I2C_ISA=m
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index f3935ba24946..676a1c443d28 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -80,6 +80,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
struct vm_area_struct * vma;
unsigned long page, addr;
int write;
+ int fault;
siginfo_t info;
/*
@@ -195,20 +196,18 @@ survive:
*/
addr = (address & PAGE_MASK);
set_thread_fault_code(error_code);
- switch (handle_mm_fault(mm, vma, addr, write)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
+ fault = handle_mm_fault(mm, vma, addr, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
goto out_of_memory;
- default:
- BUG();
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
set_thread_fault_code(0);
up_read(&mm->mmap_sem);
return;
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index a86e2e9a639f..20a9c08e59c3 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -37,6 +37,10 @@ config TIME_LOW_RES
bool
default y
+config GENERIC_IOMAP
+ bool
+ default y
+
config ARCH_MAY_HAVE_PC_FDC
bool
depends on Q40 || (BROKEN && SUN3X)
@@ -45,6 +49,9 @@ config ARCH_MAY_HAVE_PC_FDC
config NO_IOPORT
def_bool y
+config NO_DMA
+ def_bool SUN3
+
mainmenu "Linux/68k Kernel Configuration"
source "init/Kconfig"
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index cb8e7609df4c..78df98f2029a 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -148,8 +148,8 @@ void dn_serial_print (const char *str)
}
}
-void config_apollo(void) {
-
+void __init config_apollo(void)
+{
int i;
dn_setup_model();
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index 13bd41bed28e..5d47f3aa3810 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -37,7 +37,7 @@ static struct irq_controller apollo_irq_controller = {
};
-void dn_init_IRQ(void)
+void __init dn_init_IRQ(void)
{
m68k_setup_user_interrupt(VEC_USER + 96, 16, dn_process_int);
m68k_setup_irq_controller(&apollo_irq_controller, IRQ_APOLLO, 16);
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index 1c29603b16b3..2b5f64726a2e 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -13,6 +13,7 @@
* enhanced by Bjoern Brauel and Roman Hodek
*/
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
@@ -42,6 +43,9 @@ void (*atari_mouse_interrupt_hook) (char *);
void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
/* Hook for mouse inputdev driver */
void (*atari_input_mouse_interrupt_hook) (char *);
+EXPORT_SYMBOL(atari_mouse_interrupt_hook);
+EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
+EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
/* variables for IKBD self test: */
@@ -429,6 +433,7 @@ void ikbd_mouse_rel_pos(void)
ikbd_write(cmd, 1);
}
+EXPORT_SYMBOL(ikbd_mouse_rel_pos);
/* Set absolute mouse position reporting */
void ikbd_mouse_abs_pos(int xmax, int ymax)
@@ -453,6 +458,7 @@ void ikbd_mouse_thresh(int x, int y)
ikbd_write(cmd, 3);
}
+EXPORT_SYMBOL(ikbd_mouse_thresh);
/* Set mouse scale */
void ikbd_mouse_scale(int x, int y)
@@ -495,6 +501,7 @@ void ikbd_mouse_y0_top(void)
ikbd_write(cmd, 1);
}
+EXPORT_SYMBOL(ikbd_mouse_y0_top);
/* Resume */
void ikbd_resume(void)
@@ -511,6 +518,7 @@ void ikbd_mouse_disable(void)
ikbd_write(cmd, 1);
}
+EXPORT_SYMBOL(ikbd_mouse_disable);
/* Pause output */
void ikbd_pause(void)
@@ -696,7 +704,6 @@ int __init atari_keyb_init(void)
return 0;
}
-
int atari_kbdrate(struct kbd_repeat *k)
{
if (k->delay > 0) {
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 896ae3d3d919..9433a88a33c4 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -97,7 +97,7 @@ static int bvme6000_get_hardware_list(char *buffer)
* This function is called during kernel startup to initialize
* the bvme6000 IRQ handling routines.
*/
-static void bvme6000_init_IRQ(void)
+static void __init bvme6000_init_IRQ(void)
{
m68k_setup_user_interrupt(VEC_USER, 192, NULL);
}
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index 05741f233567..faa6764f1d13 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -577,7 +577,7 @@ func_define putn,1
#endif
.endm
-.text
+.section ".text.head","ax"
ENTRY(_stext)
/*
* Version numbers of the bootinfo interface
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index 60d4d75f5798..2b412454cb41 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -326,6 +326,10 @@ void disable_irq(unsigned int irq)
EXPORT_SYMBOL(disable_irq);
+void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq")));
+
+EXPORT_SYMBOL(disable_irq_nosync);
+
int m68k_irq_startup(unsigned int irq)
{
if (irq <= IRQ_AUTO_7)
diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c
index cdba9fd6d82f..2cf0690b7882 100644
--- a/arch/m68k/kernel/ptrace.c
+++ b/arch/m68k/kernel/ptrace.c
@@ -128,10 +128,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:
- i = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (i != sizeof(tmp))
- goto out_eio;
- ret = put_user(tmp, (unsigned long *)data);
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
/* read the word at location addr in the USER area. */
@@ -160,8 +157,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- if (access_process_vm(child, addr, &data, sizeof(data), 1) != sizeof(data))
- goto out_eio;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index 215c7bd43924..7e6d5fb75390 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -58,6 +58,7 @@ extern int end;
extern unsigned long availmem;
int m68k_num_memory;
+EXPORT_SYMBOL(m68k_num_memory);
int m68k_realnum_memory;
EXPORT_SYMBOL(m68k_realnum_memory);
unsigned long m68k_memoffset;
diff --git a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S
index 4b5f050204e8..aad01592dbbc 100644
--- a/arch/m68k/kernel/sun3-head.S
+++ b/arch/m68k/kernel/sun3-head.S
@@ -29,7 +29,7 @@ kernel_pmd_table: .skip 0x2000
.globl kernel_pg_dir
.equ kernel_pg_dir,kernel_pmd_table
- .section .head
+ .section .text.head
ENTRY(_stext)
ENTRY(_start)
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 4c065f9ceffc..7db41594d7b6 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -72,7 +72,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy)
return IRQ_HANDLED;
}
-void time_init(void)
+void __init time_init(void)
{
struct rtc_time time;
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index a27a4fa33296..4e2752a0e89b 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -1170,6 +1170,7 @@ void die_if_kernel (char *str, struct pt_regs *fp, int nr)
console_verbose();
printk("%s: %08x\n",str,nr);
show_registers(fp);
+ add_taint(TAINT_DIE);
do_exit(SIGSEGV);
}
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 40f02b128f22..c42245775a4d 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -11,6 +11,7 @@ SECTIONS
. = 0x1000;
_text = .; /* Text and read-only data */
.text : {
+ *(.text.head)
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index f06425b6d206..4adffefb5c48 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -11,7 +11,7 @@ SECTIONS
. = 0xE002000;
_text = .; /* Text and read-only data */
.text : {
- *(.head)
+ *(.text.head)
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
index cf6bb51945a2..6216f12a756b 100644
--- a/arch/m68k/lib/checksum.c
+++ b/arch/m68k/lib/checksum.c
@@ -422,3 +422,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
);
return(sum);
}
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 5fd413246f89..8547dbc5e8d7 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -49,6 +49,7 @@ struct mac_booter_data mac_bi_data;
int mac_bisize = sizeof mac_bi_data;
struct mac_hw_present mac_hw_present;
+EXPORT_SYMBOL(mac_hw_present);
/* New m68k bootinfo stuff and videobase */
@@ -84,7 +85,7 @@ extern void nubus_sweep_video(void);
static void mac_get_model(char *str);
-static void mac_sched_init(irq_handler_t vector)
+static void __init mac_sched_init(irq_handler_t vector)
{
via_init_clock(vector);
}
@@ -769,7 +770,7 @@ static struct mac_model mac_data_table[] = {
}
};
-void mac_identify(void)
+void __init mac_identify(void)
{
struct mac_model *m;
@@ -846,7 +847,7 @@ void mac_identify(void)
baboon_init();
}
-void mac_report_hardware(void)
+void __init mac_report_hardware(void)
{
printk(KERN_INFO "Apple Macintosh %s\n", macintosh_config->name);
}
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 0fc72d8f786e..ecddac4a02b9 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -114,6 +114,7 @@
*
*/
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -224,7 +225,7 @@ static struct irq_controller mac_irq_controller = {
.disable = mac_disable_irq,
};
-void mac_init_IRQ(void)
+void __init mac_init_IRQ(void)
{
#ifdef DEBUG_MACINTS
printk("mac_init_IRQ(): Setting things up...\n");
@@ -391,6 +392,7 @@ int mac_irq_pending(unsigned int irq)
}
return 0;
}
+EXPORT_SYMBOL(mac_irq_pending);
static int num_debug[8];
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index 2adbeb16e1b8..578b48f47b9e 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -159,18 +159,17 @@ good_area:
#ifdef DEBUG
printk("handle_mm_fault returns %d\n",fault);
#endif
- switch (fault) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto bus_err;
- default:
- goto out_of_memory;
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto bus_err;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
return 0;
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index f1de19e1dde6..f42caa79e4e8 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -44,7 +44,7 @@ pg_data_t *pg_data_table[65];
EXPORT_SYMBOL(pg_data_table);
#endif
-void m68k_setup_node(int node)
+void __init m68k_setup_node(int node)
{
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
struct mem_info *info = m68k_memory + node;
diff --git a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c
index 1af24cb5bfe1..3dc41158c05e 100644
--- a/arch/m68k/mm/sun3kmap.c
+++ b/arch/m68k/mm/sun3kmap.c
@@ -105,6 +105,7 @@ void __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
return (void __iomem *)ret;
}
+EXPORT_SYMBOL(sun3_ioremap);
void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache)
@@ -157,3 +158,4 @@ int sun3_map_test(unsigned long addr, char *val)
return ret;
}
+EXPORT_SYMBOL(sun3_map_test);
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 4a7df9c3f85a..92fe50714112 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -89,7 +89,7 @@ static int mvme147_get_hardware_list(char *buffer)
* the mvme147 IRQ handling routines.
*/
-void mvme147_init_IRQ(void)
+void __init mvme147_init_IRQ(void)
{
m68k_setup_user_interrupt(VEC_USER, 192, NULL);
}
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index c829ebb6b1af..daa785161401 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -119,7 +119,7 @@ static int mvme16x_get_hardware_list(char *buffer)
* that the base vectors for the VMEChip2 and PCCChip2 are valid.
*/
-static void mvme16x_init_IRQ (void)
+static void __init mvme16x_init_IRQ (void)
{
m68k_setup_user_interrupt(VEC_USER, 192, NULL);
}
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 2fb25ae46a8a..ad3ed1fb8879 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -79,7 +79,7 @@ static struct irq_controller q40_irq_controller = {
static int disabled;
-void q40_init_IRQ(void)
+void __init q40_init_IRQ(void)
{
m68k_setup_irq_controller(&q40_irq_controller, 1, Q40_IRQ_MAX);
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index 50df34bf80e3..cf93481adb1d 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -97,7 +97,7 @@ static struct irq_controller sun3_irq_controller = {
.disable = sun3_disable_irq,
};
-void sun3_init_IRQ(void)
+void __init sun3_init_IRQ(void)
{
*sun3_intreg = 1;
diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c
index 48f8eb7b1565..a7b7e818d627 100644
--- a/arch/m68k/sun3x/prom.c
+++ b/arch/m68k/sun3x/prom.c
@@ -92,7 +92,7 @@ static struct console sun3x_debug = {
.index = -1,
};
-void sun3x_prom_init(void)
+void __init sun3x_prom_init(void)
{
/* Read the vector table */
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index adc64a2bafbb..1175ceff8b2a 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -45,6 +45,10 @@ config GENERIC_HWEIGHT
bool
default y
+config GENERIC_HARDIRQS
+ bool
+ default y
+
config GENERIC_CALIBRATE_DELAY
bool
default y
diff --git a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile
index 1c6cd1ab571e..1524b39ad63f 100644
--- a/arch/m68knommu/kernel/Makefile
+++ b/arch/m68knommu/kernel/Makefile
@@ -4,8 +4,8 @@
extra-y := vmlinux.lds
-obj-y += dma.o entry.o init_task.o m68k_ksyms.o process.o ptrace.o semaphore.o \
- setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
+obj-y += dma.o entry.o init_task.o irq.o m68k_ksyms.o process.o ptrace.o \
+ semaphore.o setup.o signal.o syscalltable.o sys_m68k.o time.o traps.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_COMEMPCI) += comempci.o
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index 7cd183d346ef..d97b89bae53c 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -15,7 +15,6 @@
#include <linux/hardirq.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
-#include <asm/irqnode.h>
#include <asm/thread_info.h>
#define DEFINE(sym, val) \
@@ -72,10 +71,6 @@ int main(void)
#else
/* bitfields are a bit difficult */
DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
- /* offsets into the irq_handler struct */
- DEFINE(IRQ_HANDLER, offsetof(struct irq_node, handler));
- DEFINE(IRQ_DEVID, offsetof(struct irq_node, dev_id));
- DEFINE(IRQ_NEXT, offsetof(struct irq_node, next));
#endif
/* offsets into the kernel_stat struct */
diff --git a/arch/m68knommu/kernel/irq.c b/arch/m68knommu/kernel/irq.c
new file mode 100644
index 000000000000..bba1bb48a21f
--- /dev/null
+++ b/arch/m68knommu/kernel/irq.c
@@ -0,0 +1,82 @@
+/*
+ * irq.c
+ *
+ * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
+{
+ struct pt_regs *oldregs = set_irq_regs(regs);
+
+ irq_enter();
+ __do_IRQ(irq);
+ irq_exit();
+
+ set_irq_regs(oldregs);
+}
+
+void ack_bad_irq(unsigned int irq)
+{
+ printk(KERN_ERR "IRQ: unexpected irq=%d\n", irq);
+}
+
+static struct irq_chip m_irq_chip = {
+ .name = "M68K-INTC",
+ .enable = enable_vector,
+ .disable = disable_vector,
+ .ack = ack_vector,
+};
+
+void __init init_IRQ(void)
+{
+ int irq;
+
+ init_vectors();
+
+ for (irq = 0; (irq < NR_IRQS); irq++) {
+ irq_desc[irq].status = IRQ_DISABLED;
+ irq_desc[irq].action = NULL;
+ irq_desc[irq].depth = 1;
+ irq_desc[irq].chip = &m_irq_chip;
+ }
+}
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+ struct irqaction *ap;
+ int irq = *((loff_t *) v);
+
+ if (irq == 0)
+ seq_puts(p, " CPU0\n");
+
+ if (irq < NR_IRQS) {
+ ap = irq_desc[irq].action;
+ if (ap) {
+ seq_printf(p, "%3d: ", irq);
+ seq_printf(p, "%10u ", kstat_irqs(irq));
+ seq_printf(p, "%14s ", irq_desc[irq].chip->name);
+
+ seq_printf(p, "%s", ap->name);
+ for (ap = ap->next; ap; ap = ap->next)
+ seq_printf(p, ", %s", ap->name);
+ seq_putc(p, '\n');
+ }
+ }
+
+ return 0;
+}
+
diff --git a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c
index 25327c9eadd7..f795062aba1e 100644
--- a/arch/m68knommu/kernel/m68k_ksyms.c
+++ b/arch/m68knommu/kernel/m68k_ksyms.c
@@ -81,8 +81,6 @@ EXPORT_SYMBOL(__mulsi3);
EXPORT_SYMBOL(__udivsi3);
EXPORT_SYMBOL(__umodsi3);
-EXPORT_SYMBOL(is_in_rom);
-
#ifdef CONFIG_COLDFIRE
extern unsigned int *dma_device_address;
extern unsigned long dma_base_addr, _ramend;
diff --git a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c
index 941955dc3b7c..846f97534685 100644
--- a/arch/m68knommu/kernel/process.c
+++ b/arch/m68knommu/kernel/process.c
@@ -377,7 +377,7 @@ unsigned long get_wchan(struct task_struct *p)
fp = ((struct switch_stack *)p->thread.ksp)->a6;
do {
if (fp < stack_page+sizeof(struct thread_info) ||
- fp >= 8184+stack_page)
+ fp >= THREAD_SIZE-8+stack_page)
return 0;
pc = ((unsigned long *)fp)[1];
if (!in_sched_functions(pc))
diff --git a/arch/m68knommu/kernel/ptrace.c b/arch/m68knommu/kernel/ptrace.c
index f54b6a3dfecb..ef70ca070ce2 100644
--- a/arch/m68knommu/kernel/ptrace.c
+++ b/arch/m68knommu/kernel/ptrace.c
@@ -106,17 +106,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long *) data);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -159,10 +151,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index 8133b1047353..2203f694f26b 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -1,8 +1,8 @@
/*
* linux/arch/m68knommu/kernel/setup.c
*
- * Copyright (C) 1999-2004 Greg Ungerer (gerg@snapgear.com)
- * Copyright (C) 1998,1999 D. Jeff Dionne <jeff@lineo.ca>
+ * Copyright (C) 1999-2007 Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 1998,1999 D. Jeff Dionne <jeff@uClinux.org>
* Copyleft ()) 2000 James D. Schettine {james@telos-systems.com}
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
* Copyright (C) 1995 Hamish Macdonald
@@ -20,17 +20,13 @@
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/fs.h>
#include <linux/fb.h>
#include <linux/module.h>
#include <linux/console.h>
-#include <linux/genhd.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/major.h>
#include <linux/bootmem.h>
#include <linux/seq_file.h>
-#include <linux/root_dev.h>
#include <linux/init.h>
#include <asm/setup.h>
@@ -46,34 +42,19 @@ EXPORT_SYMBOL(memory_end);
char __initdata command_line[COMMAND_LINE_SIZE];
-/* setup some dummy routines */
-static void dummy_waitbut(void)
-{
-}
+void (*mach_trap_init)(void);
-void (*mach_sched_init) (irq_handler_t handler);
-void (*mach_tick)( void );
-/* machine dependent keyboard functions */
-int (*mach_keyb_init) (void);
-int (*mach_kbdrate) (struct kbd_repeat *);
-void (*mach_kbd_leds) (unsigned int);
-/* machine dependent irq functions */
-void (*mach_init_IRQ) (void);
-irq_handler_t mach_default_handler;
-int (*mach_get_irq_list) (struct seq_file *, void *);
-void (*mach_process_int) (int irq, struct pt_regs *fp);
-void (*mach_trap_init) (void);
/* machine dependent timer functions */
-unsigned long (*mach_gettimeoffset) (void);
-void (*mach_gettod) (int*, int*, int*, int*, int*, int*);
-int (*mach_hwclk) (int, struct rtc_time*);
-int (*mach_set_clock_mmss) (unsigned long);
-void (*mach_mksound)( unsigned int count, unsigned int ticks );
-void (*mach_reset)( void );
-void (*waitbut)(void) = dummy_waitbut;
-void (*mach_debug_init)(void);
-void (*mach_halt)( void );
-void (*mach_power_off)( void );
+void (*mach_sched_init)(irq_handler_t handler);
+void (*mach_tick)(void);
+void (*mach_gettod)(int*, int*, int*, int*, int*, int*);
+int (*mach_set_clock_mmss)(unsigned long);
+unsigned long (*mach_gettimeoffset)(void);
+
+/* machine dependent reboot functions */
+void (*mach_reset)(void);
+void (*mach_halt)(void);
+void (*mach_power_off)(void);
#ifdef CONFIG_M68000
@@ -134,13 +115,6 @@ void (*mach_power_off)( void );
#define CPU "UNKNOWN"
#endif
-/* (es) */
-/* note: why is this defined here? the must be a better place to put this */
-#if defined( CONFIG_TELOS) || defined( CONFIG_UCDIMM ) || defined( CONFIG_UCSIMM ) || defined(CONFIG_DRAGEN2) || (defined( CONFIG_PILOT ) && defined( CONFIG_M68328 ))
-#define CAT_ROMARRAY
-#endif
-/* (/es) */
-
extern int _stext, _etext, _sdata, _edata, _sbss, _ebss, _end;
extern int _ramstart, _ramend;
@@ -148,15 +122,8 @@ void setup_arch(char **cmdline_p)
{
int bootmap_size;
-#if defined(CAT_ROMARRAY) && defined(DEBUG)
- extern int __data_rom_start;
- extern int __data_start;
- int *romarray = (int *)((int) &__data_rom_start +
- (int)&_edata - (int)&__data_start);
-#endif
-
memory_start = PAGE_ALIGN(_ramstart);
- memory_end = _ramend; /* by now the stack is part of the init task */
+ memory_end = _ramend;
init_mm.start_code = (unsigned long) &_stext;
init_mm.end_code = (unsigned long) &_etext;
@@ -220,11 +187,7 @@ void setup_arch(char **cmdline_p)
(int) &_sbss, (int) &_ebss);
printk(KERN_DEBUG "KERNEL -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x "
"STACK=0x%06x-0x%06x\n",
-#ifdef CAT_ROMARRAY
- (int) romarray, ((int) romarray) + romarray[2],
-#else
(int) &_ebss, (int) memory_start,
-#endif
(int) memory_start, (int) memory_end,
(int) memory_end, (int) _ramend);
#endif
@@ -268,32 +231,33 @@ void setup_arch(char **cmdline_p)
/*
* Get CPU information for use by the procfs.
*/
-
static int show_cpuinfo(struct seq_file *m, void *v)
{
- char *cpu, *mmu, *fpu;
- u_long clockfreq;
+ char *cpu, *mmu, *fpu;
+ u_long clockfreq;
- cpu = CPU;
- mmu = "none";
- fpu = "none";
+ cpu = CPU;
+ mmu = "none";
+ fpu = "none";
#ifdef CONFIG_COLDFIRE
- clockfreq = (loops_per_jiffy*HZ)*3;
+ clockfreq = (loops_per_jiffy * HZ) * 3;
#else
- clockfreq = (loops_per_jiffy*HZ)*16;
-#endif
-
- seq_printf(m, "CPU:\t\t%s\n"
- "MMU:\t\t%s\n"
- "FPU:\t\t%s\n"
- "Clocking:\t%lu.%1luMHz\n"
- "BogoMips:\t%lu.%02lu\n"
- "Calibration:\t%lu loops\n",
- cpu, mmu, fpu,
- clockfreq/1000000,(clockfreq/100000)%10,
- (loops_per_jiffy*HZ)/500000,((loops_per_jiffy*HZ)/5000)%100,
- (loops_per_jiffy*HZ));
+ clockfreq = (loops_per_jiffy * HZ) * 16;
+#endif
+
+ seq_printf(m, "CPU:\t\t%s\n"
+ "MMU:\t\t%s\n"
+ "FPU:\t\t%s\n"
+ "Clocking:\t%lu.%1luMHz\n"
+ "BogoMips:\t%lu.%02lu\n"
+ "Calibration:\t%lu loops\n",
+ cpu, mmu, fpu,
+ clockfreq / 1000000,
+ (clockfreq / 100000) % 10,
+ (loops_per_jiffy * HZ) / 500000,
+ ((loops_per_jiffy * HZ) / 5000) % 100,
+ (loops_per_jiffy * HZ));
return 0;
}
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index bed5f47bf568..437a061d8b94 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -62,8 +62,6 @@ static char const * const vec_names[] = {
void __init trap_init(void)
{
- if (mach_trap_init)
- mach_trap_init();
}
void die_if_kernel(char *str, struct pt_regs *fp, int nr)
@@ -82,7 +80,8 @@ void die_if_kernel(char *str, struct pt_regs *fp, int nr)
printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n",
current->comm, current->pid, PAGE_SIZE+(unsigned long)current);
- show_stack(NULL, (unsigned long *)fp);
+ show_stack(NULL, (unsigned long *)(fp + 1));
+ add_taint(TAINT_DIE);
do_exit(SIGSEGV);
}
diff --git a/arch/m68knommu/mm/memory.c b/arch/m68knommu/mm/memory.c
index 411e45248e5c..f93b88b51f9f 100644
--- a/arch/m68knommu/mm/memory.c
+++ b/arch/m68knommu/mm/memory.c
@@ -17,90 +17,14 @@
#include <linux/types.h>
#include <linux/slab.h>
-#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
-#include <asm/traps.h>
-#include <asm/io.h>
/*
- * cache_clear() semantics: Clear any cache entries for the area in question,
- * without writing back dirty entries first. This is useful if the data will
- * be overwritten anyway, e.g. by DMA to memory. The range is defined by a
- * _physical_ address.
- */
-
-void cache_clear (unsigned long paddr, int len)
-{
-}
-
-
-/*
- * Define cache invalidate functions. The ColdFire 5407 is really
- * the only processor that needs to do some work here. Anything
- * that has separate data and instruction caches will be a problem.
- */
-#ifdef CONFIG_M5407
-
-static __inline__ void cache_invalidate_lines(unsigned long paddr, int len)
-{
- unsigned long sset, eset;
-
- sset = (paddr & 0x00000ff0);
- eset = ((paddr + len) & 0x0000ff0) + 0x10;
-
- __asm__ __volatile__ (
- "nop\n\t"
- "clrl %%d0\n\t"
- "1:\n\t"
- "movel %0,%%a0\n\t"
- "addl %%d0,%%a0\n\t"
- "2:\n\t"
- ".word 0xf4e8\n\t"
- "addl #0x10,%%a0\n\t"
- "cmpl %1,%%a0\n\t"
- "blt 2b\n\t"
- "addql #1,%%d0\n\t"
- "cmpil #4,%%d0\n\t"
- "bne 1b"
- : : "a" (sset), "a" (eset) : "d0", "a0" );
-}
-
-#else
-#define cache_invalidate_lines(a,b)
-#endif
-
-
-/*
- * cache_push() semantics: Write back any dirty cache data in the given area,
- * and invalidate the range in the instruction cache. It needs not (but may)
- * invalidate those entries also in the data cache. The range is defined by a
- * _physical_ address.
- */
-
-void cache_push (unsigned long paddr, int len)
-{
- cache_invalidate_lines(paddr, len);
-}
-
-
-/*
- * cache_push_v() semantics: Write back any dirty cache data in the given
- * area, and invalidate those entries at least in the instruction cache. This
- * is intended to be used after data has been written that can be executed as
- * code later. The range is defined by a _user_mode_ _virtual_ address (or,
- * more exactly, the space is defined by the %sfc/%dfc register.)
- */
-
-void cache_push_v (unsigned long vaddr, int len)
-{
- cache_invalidate_lines(vaddr, len);
-}
-
-/* Map some physical address range into the kernel address space. The
- * code is copied and adapted from map_chunk().
+ * Map some physical address range into the kernel address space.
+ * The code is copied and adapted from map_chunk().
*/
unsigned long kernel_map(unsigned long paddr, unsigned long size,
@@ -109,23 +33,3 @@ unsigned long kernel_map(unsigned long paddr, unsigned long size,
return paddr;
}
-
-int is_in_rom(unsigned long addr)
-{
- extern unsigned long _ramstart, _ramend;
-
- /*
- * What we are really trying to do is determine if addr is
- * in an allocated kernel memory region. If not then assume
- * we cannot free it or otherwise de-allocate it. Ideally
- * we could restrict this to really being in a ROM or flash,
- * but that would need to be done on a board by board basis,
- * not globally.
- */
- if ((addr < _ramstart) || (addr >= _ramend))
- return(1);
-
- /* Default case, not in ROM */
- return(0);
-}
-
diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile
index 2fd37dcc309b..719a313494bc 100644
--- a/arch/m68knommu/platform/5307/Makefile
+++ b/arch/m68knommu/platform/5307/Makefile
@@ -16,7 +16,7 @@ ifdef CONFIG_FULLDEBUG
AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1
endif
-obj-$(CONFIG_COLDFIRE) += entry.o vectors.o ints.o
+obj-$(CONFIG_COLDFIRE) += entry.o vectors.o
obj-$(CONFIG_M5206) += timers.o
obj-$(CONFIG_M5206e) += timers.o
obj-$(CONFIG_M520x) += pit.o
diff --git a/arch/m68knommu/platform/5307/entry.S b/arch/m68knommu/platform/5307/entry.S
index f0dba84d9101..c358aebe0af3 100644
--- a/arch/m68knommu/platform/5307/entry.S
+++ b/arch/m68knommu/platform/5307/entry.S
@@ -1,7 +1,7 @@
/*
* linux/arch/m68knommu/platform/5307/entry.S
*
- * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
* Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
* Kenneth Albanowski <kjahds@kjahds.com>,
* Copyright (C) 2000 Lineo Inc. (www.lineo.com)
@@ -155,34 +155,21 @@ Lsignal_return:
/*
* This is the generic interrupt handler (for all hardware interrupt
- * sources). It figures out the vector number and calls the appropriate
- * interrupt service routine directly.
+ * sources). Calls upto high level code to do all the work.
*/
ENTRY(inthandler)
SAVE_ALL
moveq #-1,%d0
movel %d0,%sp@(PT_ORIG_D0)
- addql #1,local_irq_count
movew %sp@(PT_FORMATVEC),%d0 /* put exception # in d0 */
andl #0x03fc,%d0 /* mask out vector only */
- leal per_cpu__kstat+STAT_IRQ,%a0
- addql #1,%a0@(%d0)
-
+ movel %sp,%sp@- /* push regs arg */
lsrl #2,%d0 /* calculate real vector # */
- movel %d0,%d1 /* calculate array offset */
- lsll #4,%d1
- lea irq_list,%a0
- addl %d1,%a0 /* pointer to array struct */
-
- movel %sp,%sp@- /* push regs arg onto stack */
- movel %a0@(8),%sp@- /* push devid arg */
- movel %d0,%sp@- /* push vector # on stack */
-
- movel %a0@,%a0 /* get function to call */
- jbsr %a0@ /* call vector handler */
- lea %sp@(12),%sp /* pop parameters off stack */
+ movel %d0,%sp@- /* push vector number */
+ jbsr do_IRQ /* call high level irq handler */
+ lea %sp@(8),%sp /* pop args off stack */
bra ret_from_interrupt /* this was fallthrough */
@@ -198,24 +185,15 @@ ENTRY(fasthandler)
movew %sp@(PT_FORMATVEC),%d0
andl #0x03fc,%d0 /* mask out vector only */
- leal per_cpu__kstat+STAT_IRQ,%a0
- addql #1,%a0@(%d0)
-
- movel %sp,%sp@- /* push regs arg onto stack */
- clrl %sp@- /* push devid arg */
+ movel %sp,%sp@- /* push regs arg */
lsrl #2,%d0 /* calculate real vector # */
- movel %d0,%sp@- /* push vector # on stack */
-
- lsll #4,%d0 /* adjust for array offset */
- lea irq_list,%a0
- movel %a0@(%d0),%a0 /* get function to call */
- jbsr %a0@ /* call vector handler */
- lea %sp@(12),%sp /* pop parameters off stack */
+ movel %d0,%sp@- /* push vector number */
+ jbsr do_IRQ /* call high level irq handler */
+ lea %sp@(8),%sp /* pop args off stack */
RESTORE_LOCAL
ENTRY(ret_from_interrupt)
- subql #1,local_irq_count
jeq 2f
1:
RESTORE_ALL
diff --git a/arch/m68knommu/platform/5307/ints.c b/arch/m68knommu/platform/5307/ints.c
deleted file mode 100644
index 751633038c4b..000000000000
--- a/arch/m68knommu/platform/5307/ints.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/ints.c -- General interrupt handling code
- *
- * Copyright (C) 1999-2002 Greg Ungerer (gerg@snapgear.com)
- * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
- * Kenneth Albanowski <kjahds@kjahds.com>,
- * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
- *
- * Based on:
- *
- * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/irqnode.h>
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/machdep.h>
-
-/*
- * This table stores the address info for each vector handler.
- */
-struct irq_entry irq_list[SYS_IRQS];
-
-#define NUM_IRQ_NODES 16
-static irq_node_t nodes[NUM_IRQ_NODES];
-
-/* The number of spurious interrupts */
-volatile unsigned int num_spurious;
-
-unsigned int local_irq_count[NR_CPUS];
-
-static irqreturn_t default_irq_handler(int irq, void *ptr)
-{
-#if 1
- printk(KERN_INFO "%s(%d): default irq handler vec=%d [0x%x]\n",
- __FILE__, __LINE__, irq, irq);
-#endif
- return(IRQ_HANDLED);
-}
-
-/*
- * void init_IRQ(void)
- *
- * Parameters: None
- *
- * Returns: Nothing
- *
- * This function should be called during kernel startup to initialize
- * the IRQ handling routines.
- */
-
-void __init init_IRQ(void)
-{
- int i;
-
- for (i = 0; i < SYS_IRQS; i++) {
- if (mach_default_handler)
- irq_list[i].handler = mach_default_handler;
- else
- irq_list[i].handler = default_irq_handler;
- irq_list[i].flags = IRQ_FLG_STD;
- irq_list[i].dev_id = NULL;
- irq_list[i].devname = NULL;
- }
-
- for (i = 0; i < NUM_IRQ_NODES; i++)
- nodes[i].handler = NULL;
-
- if (mach_init_IRQ)
- mach_init_IRQ();
-}
-
-irq_node_t *new_irq_node(void)
-{
- irq_node_t *node;
- short i;
-
- for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--)
- if (!node->handler)
- return node;
-
- printk(KERN_INFO "new_irq_node: out of nodes\n");
- return NULL;
-}
-
-int request_irq(
- unsigned int irq,
- irq_handler_t handler,
- unsigned long flags,
- const char *devname,
- void *dev_id)
-{
- if (irq < 0 || irq >= NR_IRQS) {
- printk(KERN_WARNING "%s: Incorrect IRQ %d from %s\n", __FUNCTION__,
- irq, devname);
- return -ENXIO;
- }
-
- if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
- if (irq_list[irq].flags & IRQ_FLG_LOCK) {
- printk(KERN_WARNING "%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, irq_list[irq].devname);
- return -EBUSY;
- }
- if (flags & IRQ_FLG_REPLACE) {
- printk(KERN_WARNING "%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, irq_list[irq].devname);
- return -EBUSY;
- }
- }
-
- if (flags & IRQ_FLG_FAST) {
- extern asmlinkage void fasthandler(void);
- extern void set_evector(int vecnum, void (*handler)(void));
- set_evector(irq, fasthandler);
- }
-
- irq_list[irq].handler = handler;
- irq_list[irq].flags = flags;
- irq_list[irq].dev_id = dev_id;
- irq_list[irq].devname = devname;
- return 0;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- if (irq >= NR_IRQS) {
- printk(KERN_WARNING "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (irq_list[irq].dev_id != dev_id)
- printk(KERN_WARNING "%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_list[irq].devname);
-
- if (irq_list[irq].flags & IRQ_FLG_FAST) {
- extern asmlinkage void inthandler(void);
- extern void set_evector(int vecnum, void (*handler)(void));
- set_evector(irq, inthandler);
- }
-
- if (mach_default_handler)
- irq_list[irq].handler = mach_default_handler;
- else
- irq_list[irq].handler = default_irq_handler;
- irq_list[irq].flags = IRQ_FLG_STD;
- irq_list[irq].dev_id = NULL;
- irq_list[irq].devname = NULL;
-}
-
-EXPORT_SYMBOL(free_irq);
-
-
-int sys_request_irq(unsigned int irq, irq_handler_t handler,
- unsigned long flags, const char *devname, void *dev_id)
-{
- if (irq > IRQ7) {
- printk(KERN_WARNING "%s: Incorrect IRQ %d from %s\n",
- __FUNCTION__, irq, devname);
- return -ENXIO;
- }
-
-#if 0
- if (!(irq_list[irq].flags & IRQ_FLG_STD)) {
- if (irq_list[irq].flags & IRQ_FLG_LOCK) {
- printk(KERN_WARNING "%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, irq_list[irq].devname);
- return -EBUSY;
- }
- if (!(flags & IRQ_FLG_REPLACE)) {
- printk(KERN_WARNING "%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, irq_list[irq].devname);
- return -EBUSY;
- }
- }
-#endif
-
- irq_list[irq].handler = handler;
- irq_list[irq].flags = flags;
- irq_list[irq].dev_id = dev_id;
- irq_list[irq].devname = devname;
- return 0;
-}
-
-void sys_free_irq(unsigned int irq, void *dev_id)
-{
- if (irq > IRQ7) {
- printk(KERN_WARNING "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (irq_list[irq].dev_id != dev_id)
- printk(KERN_WARNING "%s: Removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, irq_list[irq].devname);
-
- irq_list[irq].handler = mach_default_handler;
- irq_list[irq].flags = 0;
- irq_list[irq].dev_id = NULL;
- irq_list[irq].devname = NULL;
-}
-
-/*
- * Do we need these probe functions on the m68k?
- *
- * ... may be useful with ISA devices
- */
-unsigned long probe_irq_on (void)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off (unsigned long irqs)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(probe_irq_off);
-
-asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
-{
- if (vec >= VEC_INT1 && vec <= VEC_INT7) {
- vec -= VEC_SPUR;
- kstat_cpu(0).irqs[vec]++;
- irq_list[vec].handler(vec, irq_list[vec].dev_id);
- } else {
- if (mach_process_int)
- mach_process_int(vec, fp);
- else
- panic("Can't process interrupt vector %ld\n", vec);
- return;
- }
-}
-
-
-int show_interrupts(struct seq_file *p, void *v)
-{
- int i = *(loff_t *) v;
-
- if (i < NR_IRQS) {
- if (! (irq_list[i].flags & IRQ_FLG_STD)) {
- seq_printf(p, "%3d: %10u ", i,
- (i ? kstat_cpu(0).irqs[i] : num_spurious));
- if (irq_list[i].flags & IRQ_FLG_LOCK)
- seq_printf(p, "L ");
- else
- seq_printf(p, " ");
- seq_printf(p, "%s\n", irq_list[i].devname);
- }
- }
-
- if (i == NR_IRQS && mach_get_irq_list)
- mach_get_irq_list(p, v);
- return 0;
-}
-
-void init_irq_proc(void)
-{
- /* Insert /proc/irq driver here */
-}
-
diff --git a/arch/m68knommu/platform/5307/vectors.c b/arch/m68knommu/platform/5307/vectors.c
index 2a8b0d044ce5..6cf894620234 100644
--- a/arch/m68knommu/platform/5307/vectors.c
+++ b/arch/m68knommu/platform/5307/vectors.c
@@ -3,23 +3,17 @@
/*
* linux/arch/m68knommu/platform/5307/vectors.c
*
- * Copyright (C) 1999-2003, Greg Ungerer <gerg@snapgear.com>
+ * Copyright (C) 1999-2007, Greg Ungerer <gerg@snapgear.com>
*/
/***************************************************************************/
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/param.h>
#include <linux/init.h>
-#include <linux/unistd.h>
-#include <linux/delay.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
+#include <linux/irq.h>
#include <asm/traps.h>
#include <asm/machdep.h>
#include <asm/coldfire.h>
-#include <asm/mcftimer.h>
#include <asm/mcfsim.h>
#include <asm/mcfdma.h>
#include <asm/mcfwdebug.h>
@@ -56,7 +50,7 @@ asmlinkage void trap(void);
asmlinkage void system_call(void);
asmlinkage void inthandler(void);
-void __init coldfire_trap_init(void)
+void __init init_vectors(void)
{
int i;
@@ -86,6 +80,23 @@ void __init coldfire_trap_init(void)
/***************************************************************************/
+void enable_vector(unsigned int irq)
+{
+ /* Currently no action on ColdFire */
+}
+
+void disable_vector(unsigned int irq)
+{
+ /* Currently no action on ColdFire */
+}
+
+void ack_vector(unsigned int irq)
+{
+ /* Currently no action on ColdFire */
+}
+
+/***************************************************************************/
+
void coldfire_reset(void)
{
HARD_RESET_NOW();
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
index f97862715450..b1aef72f3baf 100644
--- a/arch/m68knommu/platform/68328/entry.S
+++ b/arch/m68knommu/platform/68328/entry.S
@@ -133,7 +133,6 @@ Lreturn:
*/
inthandler1:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -145,7 +144,6 @@ inthandler1:
inthandler2:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -157,7 +155,6 @@ inthandler2:
inthandler3:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -169,7 +166,6 @@ inthandler3:
inthandler4:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -181,7 +177,6 @@ inthandler4:
inthandler5:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -193,7 +188,6 @@ inthandler5:
inthandler6:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -205,7 +199,6 @@ inthandler6:
inthandler7:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -217,7 +210,6 @@ inthandler7:
inthandler:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and #0x3ff, %d0
@@ -228,7 +220,6 @@ inthandler:
bra ret_from_interrupt
ret_from_interrupt:
- subql #1,local_irq_count
jeq 1f
2:
RESTORE_ALL
@@ -238,7 +229,6 @@ ret_from_interrupt:
jhi 2b
/* check if we need to do software interrupts */
- movel local_irq_count,%d0
jeq ret_from_exception
pea ret_from_exception
diff --git a/arch/m68knommu/platform/68328/ints.c b/arch/m68knommu/platform/68328/ints.c
index 3de6e337554e..72e56d554f4f 100644
--- a/arch/m68knommu/platform/68328/ints.c
+++ b/arch/m68knommu/platform/68328/ints.c
@@ -9,21 +9,14 @@
* Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
*/
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/irqnode.h>
+#include <linux/irq.h>
#include <asm/traps.h>
#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/setup.h>
#if defined(CONFIG_M68328)
#include <asm/MC68328.h>
@@ -79,16 +72,12 @@ extern e_vector *_ramvec;
/* The number of spurious interrupts */
volatile unsigned int num_spurious;
-unsigned int local_irq_count[NR_CPUS];
-
-/* irq node variables for the 32 (potential) on chip sources */
-static irq_node_t int_irq_list[NR_IRQS];
/*
* This function should be called during kernel startup to initialize
- * the IRQ handling routines.
+ * the machine vector table.
*/
-void init_IRQ(void)
+void __init init_vectors(void)
{
int i;
@@ -108,96 +97,10 @@ void init_IRQ(void)
IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
- /* initialize handlers */
- for (i = 0; i < NR_IRQS; i++) {
- int_irq_list[i].handler = bad_interrupt;
- int_irq_list[i].flags = IRQ_FLG_STD;
- int_irq_list[i].dev_id = NULL;
- int_irq_list[i].devname = NULL;
- }
-
/* turn off all interrupts */
IMR = ~0;
}
-int request_irq(
- unsigned int irq,
- irq_handler_t handler,
- unsigned long flags,
- const char *devname,
- void *dev_id)
-{
- if (irq >= NR_IRQS) {
- printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- }
-
- if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) {
- if (int_irq_list[irq].flags & IRQ_FLG_LOCK) {
- printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, int_irq_list[irq].devname);
- return -EBUSY;
- }
- if (flags & IRQ_FLG_REPLACE) {
- printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, int_irq_list[irq].devname);
- return -EBUSY;
- }
- }
-
- int_irq_list[irq].handler = handler;
- int_irq_list[irq].flags = flags;
- int_irq_list[irq].dev_id = dev_id;
- int_irq_list[irq].devname = devname;
-
- IMR &= ~(1<<irq);
-
- return 0;
-}
-
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
-{
- if (irq >= NR_IRQS) {
- printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (int_irq_list[irq].dev_id != dev_id)
- printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, int_irq_list[irq].devname);
-
- int_irq_list[irq].handler = bad_interrupt;
- int_irq_list[irq].flags = IRQ_FLG_STD;
- int_irq_list[irq].dev_id = NULL;
- int_irq_list[irq].devname = NULL;
-
- IMR |= 1<<irq;
-}
-
-EXPORT_SYMBOL(free_irq);
-
-int show_interrupts(struct seq_file *p, void *v)
-{
- int i = *(loff_t *) v;
-
- if (i < NR_IRQS) {
- if (int_irq_list[i].devname) {
- seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]);
- if (int_irq_list[i].flags & IRQ_FLG_LOCK)
- seq_printf(p, "L ");
- else
- seq_printf(p, " ");
- seq_printf(p, "%s\n", int_irq_list[i].devname);
- }
- }
- if (i == NR_IRQS)
- seq_printf(p, " : %10u spurious\n", num_spurious);
-
- return 0;
-}
-
/* The 68k family did not have a good way to determine the source
* of interrupts until later in the family. The EC000 core does
* not provide the vector number on the stack, we vector everything
@@ -255,14 +158,23 @@ void process_int(int vec, struct pt_regs *fp)
irq++;
}
- kstat_cpu(0).irqs[irq]++;
-
- if (int_irq_list[irq].handler) {
- int_irq_list[irq].handler(irq, int_irq_list[irq].dev_id, fp);
- } else {
- printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the IMR...\n", irq);
- IMR |= mask;
- }
+ do_IRQ(irq, fp);
pend &= ~mask;
}
}
+
+void enable_vector(unsigned int irq)
+{
+ IMR &= ~(1<<irq);
+}
+
+void disable_vector(unsigned int irq)
+{
+ IMR |= (1<<irq);
+}
+
+void ack_vector(unsigned int irq)
+{
+ /* Nothing needed */
+}
+
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S
index f1af8977f294..55dfefe38642 100644
--- a/arch/m68knommu/platform/68360/entry.S
+++ b/arch/m68knommu/platform/68360/entry.S
@@ -120,23 +120,21 @@ Lreturn:
RESTORE_ALL
/*
- * This is the main interrupt handler, responsible for calling process_int()
+ * This is the main interrupt handler, responsible for calling do_IRQ()
*/
inthandler:
SAVE_ALL
- addql #1,local_irq_count /* put exception # in d0*/
movew %sp@(PT_VECTOR), %d0
and.l #0x3ff, %d0
lsr.l #0x02, %d0
movel %sp,%sp@-
movel %d0,%sp@- /* put vector # on stack*/
- jbsr process_int /* process the IRQ*/
+ jbsr do_IRQ /* process the IRQ*/
3: addql #8,%sp /* pop parameters off stack*/
bra ret_from_interrupt
ret_from_interrupt:
- subql #1,local_irq_count
jeq 1f
2:
RESTORE_ALL
diff --git a/arch/m68knommu/platform/68360/ints.c b/arch/m68knommu/platform/68360/ints.c
index 4df3c146eb74..c36781157e09 100644
--- a/arch/m68knommu/platform/68360/ints.c
+++ b/arch/m68knommu/platform/68360/ints.c
@@ -10,20 +10,13 @@
* Copyright (c) 1999 D. Jeff Dionne <jeff@uclinux.org>
*/
-#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/irqnode.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/traps.h>
-#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/setup.h>
#include <asm/m68360.h>
/* from quicc/commproc.c: */
@@ -36,26 +29,19 @@ extern void cpm_interrupt_init(void);
asmlinkage void system_call(void);
asmlinkage void buserr(void);
asmlinkage void trap(void);
-asmlinkage irqreturn_t bad_interrupt(void);
-asmlinkage irqreturn_t inthandler(void);
+asmlinkage void bad_interrupt(void);
+asmlinkage void inthandler(void);
extern void *_ramvec[];
/* The number of spurious interrupts */
volatile unsigned int num_spurious;
-unsigned int local_irq_count[NR_CPUS];
-
-/* irq node variables for the 32 (potential) on chip sources */
-static irq_node_t int_irq_list[INTERNAL_IRQS];
-
-static short int_irq_ablecount[INTERNAL_IRQS];
/*
* This function should be called during kernel startup to initialize
- * IRQ handling routines.
+ * the vector table.
*/
-
-void init_IRQ(void)
+void init_vectors(void)
{
int i;
int vba = (CPM_VECTOR_BASE<<4);
@@ -79,7 +65,6 @@ void init_IRQ(void)
_ramvec[32] = system_call;
_ramvec[33] = trap;
-
cpm_interrupt_init();
/* set up CICR for vector base address and irq level */
@@ -124,212 +109,20 @@ void init_IRQ(void)
/* turn off all CPM interrupts */
pquicc->intr_cimr = 0x00000000;
-
- /* initialize handlers */
- for (i = 0; i < INTERNAL_IRQS; i++) {
- int_irq_list[i].handler = NULL;
- int_irq_list[i].flags = IRQ_FLG_STD;
- int_irq_list[i].dev_id = NULL;
- int_irq_list[i].devname = NULL;
- }
-}
-
-#if 0
-void M68360_insert_irq(irq_node_t **list, irq_node_t *node)
-{
- unsigned long flags;
- irq_node_t *cur;
-
- if (!node->dev_id)
- printk(KERN_INFO "%s: Warning: dev_id of %s is zero\n",
- __FUNCTION__, node->devname);
-
- local_irq_save(flags);
-
- cur = *list;
-
- while (cur) {
- list = &cur->next;
- cur = cur->next;
- }
-
- node->next = cur;
- *list = node;
-
- local_irq_restore(flags);
}
-void M68360_delete_irq(irq_node_t **list, void *dev_id)
+void enable_vector(unsigned int irq)
{
- unsigned long flags;
- irq_node_t *node;
-
- local_irq_save(flags);
-
- for (node = *list; node; list = &node->next, node = *list) {
- if (node->dev_id == dev_id) {
- *list = node->next;
- /* Mark it as free. */
- node->handler = NULL;
- local_irq_restore(flags);
- return;
- }
- }
- local_irq_restore(flags);
- printk (KERN_INFO "%s: tried to remove invalid irq\n", __FUNCTION__);
+ pquicc->intr_cimr |= (1 << irq);
}
-#endif
-int request_irq(
- unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags,
- const char *devname,
- void *dev_id)
+void disable_vector(unsigned int irq)
{
- int mask = (1<<irq);
-
- irq += (CPM_VECTOR_BASE<<4);
-
- if (irq >= INTERNAL_IRQS) {
- printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
- return -ENXIO;
- }
-
- if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) {
- if (int_irq_list[irq].flags & IRQ_FLG_LOCK) {
- printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n",
- __FUNCTION__, irq, int_irq_list[irq].devname);
- return -EBUSY;
- }
- if (flags & IRQ_FLG_REPLACE) {
- printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n",
- __FUNCTION__, devname, irq, int_irq_list[irq].devname);
- return -EBUSY;
- }
- }
- int_irq_list[irq].handler = handler;
- int_irq_list[irq].flags = flags;
- int_irq_list[irq].dev_id = dev_id;
- int_irq_list[irq].devname = devname;
-
- /* enable in the CIMR */
- if (!int_irq_ablecount[irq])
- pquicc->intr_cimr |= mask;
- /* *(volatile unsigned long *)0xfffff304 &= ~(1<<irq); */
-
- return 0;
+ pquicc->intr_cimr &= ~(1 << irq);
}
-EXPORT_SYMBOL(request_irq);
-
-void free_irq(unsigned int irq, void *dev_id)
+void ack_vector(unsigned int irq)
{
- if (irq >= INTERNAL_IRQS) {
- printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (int_irq_list[irq].dev_id != dev_id)
- printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n",
- __FUNCTION__, irq, int_irq_list[irq].devname);
- int_irq_list[irq].handler = NULL;
- int_irq_list[irq].flags = IRQ_FLG_STD;
- int_irq_list[irq].dev_id = NULL;
- int_irq_list[irq].devname = NULL;
-
- *(volatile unsigned long *)0xfffff304 |= 1<<irq;
+ pquicc->intr_cisr = (1 << irq);
}
-EXPORT_SYMBOL(free_irq);
-
-#if 0
-/*
- * Enable/disable a particular machine specific interrupt source.
- * Note that this may affect other interrupts in case of a shared interrupt.
- * This function should only be called for a _very_ short time to change some
- * internal data, that may not be changed by the interrupt at the same time.
- * int_(enable|disable)_irq calls may also be nested.
- */
-void M68360_enable_irq(unsigned int irq)
-{
- if (irq >= INTERNAL_IRQS) {
- printk(KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (--int_irq_ablecount[irq])
- return;
-
- /* enable the interrupt */
- *(volatile unsigned long *)0xfffff304 &= ~(1<<irq);
-}
-
-void M68360_disable_irq(unsigned int irq)
-{
- if (irq >= INTERNAL_IRQS) {
- printk(KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
- return;
- }
-
- if (int_irq_ablecount[irq]++)
- return;
-
- /* disable the interrupt */
- *(volatile unsigned long *)0xfffff304 |= 1<<irq;
-}
-#endif
-
-int show_interrupts(struct seq_file *p, void *v)
-{
- int i = *(loff_t *) v;
-
- if (i < NR_IRQS) {
- if (int_irq_list[i].devname) {
- seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]);
- if (int_irq_list[i].flags & IRQ_FLG_LOCK)
- seq_printf(p, "L ");
- else
- seq_printf(p, " ");
- seq_printf(p, "%s\n", int_irq_list[i].devname);
- }
- }
- if (i == NR_IRQS)
- seq_printf(p, " : %10u spurious\n", num_spurious);
-
- return 0;
-}
-
-/* The 68k family did not have a good way to determine the source
- * of interrupts until later in the family. The EC000 core does
- * not provide the vector number on the stack, we vector everything
- * into one vector and look in the blasted mask register...
- * This code is designed to be fast, almost constant time, not clean!
- */
-void process_int(int vec, struct pt_regs *fp)
-{
- int irq;
- int mask;
-
- /* unsigned long pend = *(volatile unsigned long *)0xfffff30c; */
-
- /* irq = vec + (CPM_VECTOR_BASE<<4); */
- irq = vec;
-
- /* unsigned long pend = *(volatile unsigned long *)pquicc->intr_cipr; */
-
- /* Bugger all that weirdness. For the moment, I seem to know where I came from;
- * vec is passed from a specific ISR, so I'll use it. */
-
- if (int_irq_list[irq].handler) {
- int_irq_list[irq].handler(irq , int_irq_list[irq].dev_id, fp);
- kstat_cpu(0).irqs[irq]++;
- pquicc->intr_cisr = (1 << vec); /* indicate that irq has been serviced */
- } else {
- printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the CIMR...\n", irq);
- /* *(volatile unsigned long *)0xfffff304 |= mask; */
- pquicc->intr_cimr &= ~(1 << vec);
- num_spurious += 1;
- }
- return(IRQ_HANDLED);
-}
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index a00fabe2e4e0..1e3aeccd7322 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -117,9 +117,9 @@ config MACH_JAZZ
select ARC32
select ARCH_MAY_HAVE_PC_FDC
select GENERIC_ISA_DMA
- select I8253
select I8259
select ISA
+ select PCSPEAKER
select SYS_HAS_CPU_R4X00
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
@@ -347,9 +347,9 @@ config QEMU
select DMA_COHERENT
select GENERIC_ISA_DMA
select HAVE_STD_PC_SERIAL_PORT
- select I8253
select I8259
select ISA
+ select PCSPEAKER
select SWAP_IO_SPACE
select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
@@ -562,9 +562,9 @@ config SNI_RM
select HW_HAS_EISA
select HW_HAS_PCI
select IRQ_CPU
- select I8253
select I8259
select ISA
+ select PCSPEAKER
select SWAP_IO_SPACE if CPU_BIG_ENDIAN
select SYS_HAS_CPU_R4X00
select SYS_HAS_CPU_R5000
@@ -1190,8 +1190,19 @@ config SYS_HAS_CPU_RM9000
config SYS_HAS_CPU_SB1
bool
+#
+# CPU may reorder R->R, R->W, W->R, W->W
+# Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
+#
config WEAK_ORDERING
bool
+
+#
+# CPU may reorder reads and writes beyond LL/SC
+# CPU may reorder R->LL, R->LL, W->LL, W->LL, R->SC, R->SC, W->SC, W->SC
+#
+config WEAK_REORDERING_BEYOND_LLSC
+ bool
endmenu
#
@@ -1404,6 +1415,19 @@ config MIPS_MT_SMTC_INSTANT_REPLAY
it off), but ensures that IPIs are handled promptly even under
heavy I/O interrupt load.
+config MIPS_MT_SMTC_IM_BACKSTOP
+ bool "Use per-TC register bits as backstop for inhibited IM bits"
+ depends on MIPS_MT_SMTC
+ default y
+ help
+ To support multiple TC microthreads acting as "CPUs" within
+ a VPE, VPE-wide interrupt mask bits must be specially manipulated
+ during interrupt handling. To support legacy drivers and interrupt
+ controller management code, SMTC has a "backstop" to track and
+ if necessary restore the interrupt mask. This has some performance
+ impact on interrupt service overhead. Disable it only if you know
+ what you are doing.
+
config MIPS_VPE_LOADER_TOM
bool "Load VPE program into memory hidden from linux"
depends on MIPS_VPE_LOADER
@@ -1851,7 +1875,7 @@ config MMU
bool
default y
-config I8253
+config PCSPEAKER
bool
source "drivers/pcmcia/Kconfig"
diff --git a/arch/mips/au1000/common/setup.c b/arch/mips/au1000/common/setup.c
index 13fe187f35d6..a95b37773196 100644
--- a/arch/mips/au1000/common/setup.c
+++ b/arch/mips/au1000/common/setup.c
@@ -100,18 +100,9 @@ void __init plat_mem_setup(void)
argptr = prom_getcmdline();
/* default panel */
/*strcat(argptr, " video=au1100fb:panel:Sharp_320x240_16");*/
-#ifdef CONFIG_MIPS_HYDROGEN3
- strcat(argptr, " video=au1100fb:panel:Hydrogen_3_NEC_panel_320x240,nohwcursor");
-#endif
}
#endif
-#ifdef CONFIG_FB_XPERT98
- if ((argptr = strstr(argptr, "video=")) == NULL) {
- argptr = prom_getcmdline();
- strcat(argptr, " video=atyfb:1024x768-8@70");
- }
-#endif
#if defined(CONFIG_SOUND_AU1X00) && !defined(CONFIG_SOC_AU1000)
/* au1000 does not support vra, au1500 and au1100 do */
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index fa1c62f05515..8fc29982d700 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -203,11 +203,7 @@ wakeup_counter0_set(int ticks)
/* I haven't found anyone that doesn't use a 12 MHz source clock,
* but just in case.....
*/
-#ifdef CONFIG_AU1000_SRC_CLK
-#define AU1000_SRC_CLK CONFIG_AU1000_SRC_CLK
-#else
#define AU1000_SRC_CLK 12000000
-#endif
/*
* We read the real processor speed from the PLL. This is important
@@ -247,33 +243,8 @@ unsigned long cal_r4koff(void)
au_writel (0, SYS_TOYWRITE);
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S);
-#if defined(CONFIG_AU1000_USE32K)
- {
- unsigned long start, end, count;
-
- start = au_readl(SYS_RTCREAD);
- start += 2;
- /* wait for the beginning of a new tick
- */
- while (au_readl(SYS_RTCREAD) < start);
-
- /* Start r4k counter.
- */
- write_c0_count(0);
-
- /* Wait 0.5 seconds.
- */
- end = start + (32768 / trim_divide)/2;
-
- while (end > au_readl(SYS_RTCREAD));
-
- count = read_c0_count();
- cpu_speed = count * 2;
- }
-#else
cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) *
AU1000_SRC_CLK;
-#endif
}
else {
/* The 32KHz oscillator isn't running, so assume there
diff --git a/arch/mips/au1000/pb1200/board_setup.c b/arch/mips/au1000/pb1200/board_setup.c
index 043302b7fe58..eea2092bde8d 100644
--- a/arch/mips/au1000/pb1200/board_setup.c
+++ b/arch/mips/au1000/pb1200/board_setup.c
@@ -131,14 +131,7 @@ void __init board_setup(void)
/* The Pb1200 development board uses external MUX for PSC0 to
support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI
*/
-#if defined(CONFIG_AU1XXX_PSC_SPI) && defined(CONFIG_I2C_AU1550)
- #error I2C and SPI are mutually exclusive. Both are physically connected to PSC0.\
- Refer to Pb1200/Db1200 documentation.
-#elif defined( CONFIG_AU1XXX_PSC_SPI )
- bcsr->resets |= BCSR_RESETS_PCS0MUX;
- /*Hard Coding Value to enable Temp Sensors [bit 14] Value for SOC Au1200. Pls refer documentation*/
- bcsr->resets =0x900f;
-#elif defined( CONFIG_I2C_AU1550 )
+#ifdef CONFIG_I2C_AU1550
bcsr->resets &= (~BCSR_RESETS_PCS0MUX);
#endif
au_sync();
diff --git a/arch/mips/basler/excite/excite_setup.c b/arch/mips/basler/excite/excite_setup.c
index 2f0e4c08eb04..56003188f17c 100644
--- a/arch/mips/basler/excite/excite_setup.c
+++ b/arch/mips/basler/excite/excite_setup.c
@@ -26,6 +26,7 @@
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
+#include <linux/serial_8250.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <asm/bootinfo.h>
diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig
index dd04eece9fd3..8a0b4ac5283d 100644
--- a/arch/mips/configs/jazz_defconfig
+++ b/arch/mips/configs/jazz_defconfig
@@ -241,7 +241,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
CONFIG_ISA=y
CONFIG_MMU=y
-CONFIG_I8253=y
+CONFIG_PCSPEAKER=y
#
# PCCARD (PCMCIA/CardBus) support
diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig
index 6cca105832ca..703de002e372 100644
--- a/arch/mips/configs/qemu_defconfig
+++ b/arch/mips/configs/qemu_defconfig
@@ -221,7 +221,7 @@ CONFIG_DEFAULT_IOSCHED="noop"
#
CONFIG_ISA=y
CONFIG_MMU=y
-CONFIG_I8253=y
+CONFIG_PCSPEAKER=y
#
# PCCARD (PCMCIA/CardBus) support
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index 1a67a85aabbb..a5dc5cb97aae 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -251,7 +251,7 @@ CONFIG_PCI=y
CONFIG_ISA=y
# CONFIG_EISA is not set
CONFIG_MMU=y
-CONFIG_I8253=y
+CONFIG_PCSPEAKER=y
#
# PCCARD (PCMCIA/CardBus) support
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig
index f1cdb12f7925..f342d8c887b8 100644
--- a/arch/mips/configs/yosemite_defconfig
+++ b/arch/mips/configs/yosemite_defconfig
@@ -592,8 +592,6 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
# CONFIG_RTC is not set
-CONFIG_GEN_RTC=y
-CONFIG_GEN_RTC_X=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/gt64120/wrppmc/setup.c
index ea965529e5e0..ed58c13b6032 100644
--- a/arch/mips/gt64120/wrppmc/setup.c
+++ b/arch/mips/gt64120/wrppmc/setup.c
@@ -14,6 +14,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/pm.h>
#include <asm/io.h>
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 961594cb5214..5c8085b6d7ab 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -63,7 +63,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_64BIT) += cpu-bugs64.o
-obj-$(CONFIG_I8253) += i8253.o
+obj-$(CONFIG_PCSPEAKER) += pcspeaker.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c
index 76fd3f22c766..6b5df8bfab85 100644
--- a/arch/mips/kernel/branch.c
+++ b/arch/mips/kernel/branch.c
@@ -22,7 +22,8 @@
*/
int __compute_return_epc(struct pt_regs *regs)
{
- unsigned int *addr, bit, fcr31, dspcontrol;
+ unsigned int __user *addr;
+ unsigned int bit, fcr31, dspcontrol;
long epc;
union mips_instruction insn;
@@ -33,7 +34,7 @@ int __compute_return_epc(struct pt_regs *regs)
/*
* Read the instruction
*/
- addr = (unsigned int *) epc;
+ addr = (unsigned int __user *) epc;
if (__get_user(insn.word, addr)) {
force_sig(SIGSEGV, current);
return -EFAULT;
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index c6b8b074a81a..06448a9656dc 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -75,6 +75,27 @@ static void r4k_wait_irqoff(void)
local_irq_enable();
}
+/*
+ * The RM7000 variant has to handle erratum 38. The workaround is to not
+ * have any pending stores when the WAIT instruction is executed.
+ */
+static void rm7k_wait_irqoff(void)
+{
+ local_irq_disable();
+ if (!need_resched())
+ __asm__(
+ " .set push \n"
+ " .set mips3 \n"
+ " .set noat \n"
+ " mfc0 $1, $12 \n"
+ " sync \n"
+ " mtc0 $1, $12 # stalls until W stage \n"
+ " wait \n"
+ " mtc0 $1, $12 # stalls until W stage \n"
+ " .set pop \n");
+ local_irq_enable();
+}
+
/* The Au1xxx wait is available only if using 32khz counter or
* external timer source, but specifically not CP0 Counter. */
int allow_au1k_wait;
@@ -132,7 +153,6 @@ static inline void check_wait(void)
case CPU_R4700:
case CPU_R5000:
case CPU_NEVADA:
- case CPU_RM7000:
case CPU_4KC:
case CPU_4KEC:
case CPU_4KSC:
@@ -142,6 +162,10 @@ static inline void check_wait(void)
cpu_wait = r4k_wait;
break;
+ case CPU_RM7000:
+ cpu_wait = rm7k_wait_irqoff;
+ break;
+
case CPU_24K:
case CPU_34K:
cpu_wait = r4k_wait;
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 686249c5c328..e29598ae939d 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -84,6 +84,7 @@ FEXPORT(restore_all) # restore full frame
LONG_S sp, TI_REGS($28)
jal deferred_smtc_ipi
LONG_S s0, TI_REGS($28)
+#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
/* Re-arm any temporarily masked interrupts not explicitly "acked" */
mfc0 v0, CP0_TCSTATUS
ori v1, v0, TCSTATUS_IXMT
@@ -110,6 +111,7 @@ FEXPORT(restore_all) # restore full frame
_ehb
xor t0, t0, t3
mtc0 t0, CP0_TCCONTEXT
+#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
#endif /* CONFIG_MIPS_MT_SMTC */
.set noat
RESTORE_TEMP
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 297bd56c2347..c0f19d638b98 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -243,9 +243,11 @@ NESTED(except_vec_vi_handler, 0, sp)
*/
mfc0 t1, CP0_STATUS
and t0, a0, t1
+#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
mfc0 t2, CP0_TCCONTEXT
or t0, t0, t2
mtc0 t0, CP0_TCCONTEXT
+#endif /* CONFIG_MIPS_MT_SMTC_IM_BACKSTOP */
xor t1, t1, t0
mtc0 t1, CP0_STATUS
_ehb
diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/pcspeaker.c
index 475df6904219..475df6904219 100644
--- a/arch/mips/kernel/i8253.c
+++ b/arch/mips/kernel/pcspeaker.c
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 8f4cf27c7157..bd05f5a927ea 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -25,7 +25,9 @@
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/kallsyms.h>
+#include <linux/random.h>
+#include <asm/asm.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
#include <asm/dsp.h>
@@ -460,3 +462,15 @@ unsigned long get_wchan(struct task_struct *task)
out:
return pc;
}
+
+/*
+ * Don't forget that the stack pointer must be aligned on a 8 bytes
+ * boundary for 32-bits ABI and 16 bytes for 64-bits ABI.
+ */
+unsigned long arch_align_stack(unsigned long sp)
+{
+ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
+ sp -= get_random_int() & ~PAGE_MASK;
+
+ return sp & ALMASK;
+}
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index b5a7b46bbc49..893e7bccf226 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -174,17 +174,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long __user *) data);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* Read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -313,11 +305,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1)
- == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: {
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 06729596812f..d9bfae53c43f 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -85,12 +85,7 @@
move $28, a2
cpu_restore_nonscratch a1
-#if (_THREAD_SIZE - 32) < 0x10000
- PTR_ADDIU t0, $28, _THREAD_SIZE - 32
-#else
- PTR_LI t0, _THREAD_SIZE - 32
- PTR_ADDU t0, $28
-#endif
+ PTR_ADDU t0, $28, _THREAD_SIZE - 32
set_saved_sp t0, t1, t2
#ifdef CONFIG_MIPS_MT_SMTC
/* Read-modify-writes of Status must be atomic on a VPE */
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 80ea4fa95bd9..ce277cb34dd0 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -131,7 +131,7 @@ static void show_stacktrace(struct task_struct *task, struct pt_regs *regs)
const int field = 2 * sizeof(unsigned long);
long stackdata;
int i;
- unsigned long *sp = (unsigned long *)regs->regs[29];
+ unsigned long __user *sp = (unsigned long __user *)regs->regs[29];
printk("Stack :");
i = 0;
@@ -187,7 +187,7 @@ void dump_stack(void)
EXPORT_SYMBOL(dump_stack);
-void show_code(unsigned int *pc)
+static void show_code(unsigned int __user *pc)
{
long i;
@@ -305,7 +305,7 @@ void show_registers(struct pt_regs *regs)
printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
current->comm, current->pid, current_thread_info(), current);
show_stacktrace(current, regs);
- show_code((unsigned int *) regs->cp0_epc);
+ show_code((unsigned int __user *) regs->cp0_epc);
printk("\n");
}
@@ -326,6 +326,7 @@ void __noreturn die(const char * str, struct pt_regs * regs)
#endif /* CONFIG_MIPS_MT_SMTC */
printk("%s[#%d]:\n", str, ++die_counter);
show_registers(regs);
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
@@ -373,7 +374,7 @@ asmlinkage void do_be(struct pt_regs *regs)
action = MIPS_BE_FIXUP;
if (board_be_handler)
- action = board_be_handler(regs, fixup != 0);
+ action = board_be_handler(regs, fixup != NULL);
switch (action) {
case MIPS_BE_DISCARD:
@@ -865,7 +866,7 @@ asmlinkage void do_mcheck(struct pt_regs *regs)
dump_tlb_all();
}
- show_code((unsigned int *) regs->cp0_epc);
+ show_code((unsigned int __user *) regs->cp0_epc);
/*
* Some chips may have other causes of machine check (e.g. SB1
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 9b9992cd562a..bc9bae2a73f4 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -119,10 +119,7 @@ SECTIONS
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
#endif
- . = ALIGN(_PAGE_SIZE);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(_PAGE_SIZE)
. = ALIGN(_PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c
index 1a4db7dc77cb..465ff0ec85b9 100644
--- a/arch/mips/lib/dump_tlb.c
+++ b/arch/mips/lib/dump_tlb.c
@@ -10,6 +10,7 @@
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/tlbdebug.h>
static inline const char *msk2str(unsigned int mask)
{
diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c
index 52f87795ecc3..9cee907975ae 100644
--- a/arch/mips/lib/r3k_dump_tlb.c
+++ b/arch/mips/lib/r3k_dump_tlb.c
@@ -11,6 +11,7 @@
#include <asm/mipsregs.h>
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/tlbdebug.h>
extern int r3k_have_wired_reg; /* defined in tlb-r3k.c */
diff --git a/arch/mips/lib/uncached.c b/arch/mips/lib/uncached.c
index 2388f7f3ffde..58d14f4d9349 100644
--- a/arch/mips/lib/uncached.c
+++ b/arch/mips/lib/uncached.c
@@ -12,6 +12,7 @@
#include <asm/addrspace.h>
#include <asm/bug.h>
+#include <asm/cacheflush.h>
#ifndef CKSEG2
#define CKSEG2 CKSSEG
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index d7f05b0abe17..17419e11ecad 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -205,7 +205,7 @@ static int isBranchInstr(mips_instruction * i)
static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
{
mips_instruction ir;
- void * emulpc, *contpc;
+ unsigned long emulpc, contpc;
unsigned int cond;
if (get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) {
@@ -230,7 +230,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
* Linux MIPS branch emulator operates on context, updating the
* cp0_epc.
*/
- emulpc = (void *) (xcp->cp0_epc + 4); /* Snapshot emulation target */
+ emulpc = xcp->cp0_epc + 4; /* Snapshot emulation target */
if (__compute_return_epc(xcp)) {
#ifdef CP1DBG
@@ -244,12 +244,12 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
return SIGBUS;
}
/* __compute_return_epc() will have updated cp0_epc */
- contpc = (void *) xcp->cp0_epc;
+ contpc = xcp->cp0_epc;
/* In order not to confuse ptrace() et al, tweak context */
- xcp->cp0_epc = (unsigned long) emulpc - 4;
+ xcp->cp0_epc = emulpc - 4;
} else {
- emulpc = (void *) xcp->cp0_epc;
- contpc = (void *) (xcp->cp0_epc + 4);
+ emulpc = xcp->cp0_epc;
+ contpc = xcp->cp0_epc + 4;
}
emul:
@@ -427,8 +427,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
* instruction
*/
xcp->cp0_epc += 4;
- contpc = (void *)
- (xcp->cp0_epc +
+ contpc = (xcp->cp0_epc +
(MIPSInst_SIMM(ir) << 2));
if (get_user(ir,
@@ -462,7 +461,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
* Single step the non-cp1
* instruction in the dslot
*/
- return mips_dsemul(xcp, ir, (unsigned long) contpc);
+ return mips_dsemul(xcp, ir, contpc);
}
else {
/* branch not taken */
@@ -521,7 +520,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
}
/* we did it !! */
- xcp->cp0_epc = (unsigned long) contpc;
+ xcp->cp0_epc = contpc;
xcp->cp0_cause &= ~CAUSEF_BD;
return 0;
diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c
index ea6ba7248489..653e325849e4 100644
--- a/arch/mips/math-emu/dsemul.c
+++ b/arch/mips/math-emu/dsemul.c
@@ -54,8 +54,7 @@ struct emuframe {
int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
{
extern asmlinkage void handle_dsemulret(void);
- mips_instruction *dsemul_insns;
- struct emuframe *fr;
+ struct emuframe __user *fr;
int err;
if (ir == 0) { /* a nop is easy */
@@ -87,8 +86,8 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
*/
/* Ensure that the two instructions are in the same cache line */
- dsemul_insns = (mips_instruction *) ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7);
- fr = (struct emuframe *) dsemul_insns;
+ fr = (struct emuframe __user *)
+ ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7);
/* Verify that the stack pointer is not competely insane */
if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe))))
@@ -113,12 +112,13 @@ int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
int do_dsemulret(struct pt_regs *xcp)
{
- struct emuframe *fr;
+ struct emuframe __user *fr;
unsigned long epc;
u32 insn, cookie;
int err = 0;
- fr = (struct emuframe *) (xcp->cp0_epc - sizeof(mips_instruction));
+ fr = (struct emuframe __user *)
+ (xcp->cp0_epc - sizeof(mips_instruction));
/*
* If we can't even access the area, something is very wrong, but we'll
diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
index 1cc6ebbedfdd..c68358a476dd 100644
--- a/arch/mips/mips-boards/atlas/atlas_setup.c
+++ b/arch/mips/mips-boards/atlas/atlas_setup.c
@@ -22,6 +22,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
diff --git a/arch/mips/mips-boards/sead/sead_setup.c b/arch/mips/mips-boards/sead/sead_setup.c
index bb801409d39b..5f70eaf01fab 100644
--- a/arch/mips/mips-boards/sead/sead_setup.c
+++ b/arch/mips/mips-boards/sead/sead_setup.c
@@ -23,6 +23,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
diff --git a/arch/mips/mipssim/sim_int.c b/arch/mips/mipssim/sim_int.c
index d86b37235cf6..5cbc3509ab52 100644
--- a/arch/mips/mipssim/sim_int.c
+++ b/arch/mips/mipssim/sim_int.c
@@ -77,7 +77,7 @@ asmlinkage void plat_irq_dispatch(void)
irq = irq_ffs(pending);
if (irq > 0)
- do_IRQ(MIPSCPU_INT_BASE + irq);
+ do_IRQ(MIPS_CPU_IRQ_BASE + irq);
else
spurious_interrupt();
}
diff --git a/arch/mips/mipssim/sim_setup.c b/arch/mips/mipssim/sim_setup.c
index 3643582bdade..17819b594105 100644
--- a/arch/mips/mipssim/sim_setup.c
+++ b/arch/mips/mipssim/sim_setup.c
@@ -26,6 +26,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/cpu.h>
#include <asm/bootinfo.h>
@@ -84,7 +85,7 @@ static void __init serial_init(void)
/* hardware int 4 - the serial int, is CPU int 6
but poll for now */
s.irq = 0;
- s.uartclk = BASE_BAUD * 16;
+ s.uartclk = 1843200;
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
s.iotype = UPIO_PORT;
s.regshift = 0;
diff --git a/arch/mips/mipssim/sim_time.c b/arch/mips/mipssim/sim_time.c
index 874a18e8ac24..a0f5a5dca1b2 100644
--- a/arch/mips/mipssim/sim_time.c
+++ b/arch/mips/mipssim/sim_time.c
@@ -5,7 +5,6 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/mc146818rtc.h>
-#include <linux/mipsregs.h>
#include <linux/smp.h>
#include <linux/timex.h>
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 7ebea331edb8..521771b373de 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -39,6 +39,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
struct mm_struct *mm = tsk->mm;
const int field = sizeof(unsigned long) * 2;
siginfo_t info;
+ int fault;
#if 0
printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(),
@@ -102,20 +103,18 @@ survive:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- switch (handle_mm_fault(mm, vma, address, write)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ fault = handle_mm_fault(mm, vma, address, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
up_read(&mm->mmap_sem);
return;
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index f26ede001a0b..c58bd3d036f4 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -2,7 +2,7 @@
# Makefile for the PCI specific kernel interface routines under Linux.
#
-obj-y += pci.o pci-dac.o
+obj-y += pci.o
#
# PCI bus host bridge specific code
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
index 7fc475f7eae5..76b4f0ffb1e5 100644
--- a/arch/mips/pci/fixup-cobalt.c
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -58,8 +58,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1,
static void qube_raq_galileo_fixup(struct pci_dev *dev)
{
- unsigned short galileo_id;
-
if (dev->devfn != PCI_DEVFN(0, 0))
return;
@@ -84,16 +82,14 @@ static void qube_raq_galileo_fixup(struct pci_dev *dev)
* Therefore we must set the disconnect/retry cycle values to
* something sensible when using the new Galileo.
*/
- pci_read_config_word(dev, PCI_REVISION_ID, &galileo_id);
- galileo_id &= 0xff; /* mask off class info */
- printk(KERN_INFO "Galileo: revision %u\n", galileo_id);
+ printk(KERN_INFO "Galileo: revision %u\n", dev->revision);
#if 0
- if (galileo_id >= 0x10) {
+ if (dev->revision >= 0x10) {
/* New Galileo, assumes PCI stop line to VIA is connected. */
GT_WRITE(GT_PCI0_TOR_OFS, 0x4020);
- } else if (galileo_id == 0x1 || galileo_id == 0x2)
+ } else if (dev->revision == 0x1 || dev->revision == 0x2)
#endif
{
signed int timeo;
diff --git a/arch/mips/pci/pci-dac.c b/arch/mips/pci/pci-dac.c
deleted file mode 100644
index 0f0ea1b7d4dd..000000000000
--- a/arch/mips/pci/pci-dac.c
+++ /dev/null
@@ -1,79 +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) 2000 Ani Joshi <ajoshi@unixbox.com>
- * Copyright (C) 2000, 2001, 06 Ralf Baechle <ralf@linux-mips.org>
- * swiped from i386, and cloned for MIPS by Geert, polished by Ralf.
- */
-
-#include <linux/types.h>
-#include <linux/dma-mapping.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/string.h>
-
-#include <asm/cache.h>
-#include <asm/io.h>
-
-#include <dma-coherence.h>
-
-#include <linux/pci.h>
-
-dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
- struct page *page, unsigned long offset, int direction)
-{
- struct device *dev = &pdev->dev;
-
- BUG_ON(direction == DMA_NONE);
-
- if (!plat_device_is_coherent(dev)) {
- unsigned long addr;
-
- addr = (unsigned long) page_address(page) + offset;
- dma_cache_wback_inv(addr, PAGE_SIZE);
- }
-
- return plat_map_dma_mem_page(dev, page) + offset;
-}
-
-EXPORT_SYMBOL(pci_dac_page_to_dma);
-
-struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
- dma64_addr_t dma_addr)
-{
- return pfn_to_page(plat_dma_addr_to_phys(dma_addr) >> PAGE_SHIFT);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_page);
-
-unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
- dma64_addr_t dma_addr)
-{
- return dma_addr & ~PAGE_MASK;
-}
-
-EXPORT_SYMBOL(pci_dac_dma_to_offset);
-
-void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
- dma64_addr_t dma_addr, size_t len, int direction)
-{
- BUG_ON(direction == PCI_DMA_NONE);
-
- if (!plat_device_is_coherent(&pdev->dev))
- dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu);
-
-void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
- dma64_addr_t dma_addr, size_t len, int direction)
-{
- BUG_ON(direction == PCI_DMA_NONE);
-
- if (!plat_device_is_coherent(&pdev->dev))
- dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len);
-}
-
-EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device);
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index 8108231f2e20..99d8f4fd3ff4 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -269,7 +269,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
}
for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
- struct pci_dev *dev = pci_dev_b(ln);
+ dev = pci_dev_b(ln);
if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
pcibios_fixup_device_resources(dev, bus);
diff --git a/arch/mips/pmc-sierra/msp71xx/msp_serial.c b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
index c41b53faa8f6..e25bac537d77 100644
--- a/arch/mips/pmc-sierra/msp71xx/msp_serial.c
+++ b/arch/mips/pmc-sierra/msp71xx/msp_serial.c
@@ -32,6 +32,7 @@
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/serial.h>
+#include <linux/serial_8250.h>
#include <msp_prom.h>
#include <msp_int.h>
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
index 6a6e15e40009..f7f93ae24c34 100644
--- a/arch/mips/pmc-sierra/yosemite/setup.c
+++ b/arch/mips/pmc-sierra/yosemite/setup.c
@@ -39,6 +39,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/time.h>
#include <asm/bootinfo.h>
diff --git a/arch/mips/sibyte/bcm1480/setup.c b/arch/mips/sibyte/bcm1480/setup.c
index bdaac34ae708..89f29233cae1 100644
--- a/arch/mips/sibyte/bcm1480/setup.c
+++ b/arch/mips/sibyte/bcm1480/setup.c
@@ -31,6 +31,7 @@
unsigned int sb1_pass;
unsigned int soc_pass;
unsigned int soc_type;
+EXPORT_SYMBOL(soc_type);
unsigned int periph_rev;
unsigned int zbbus_mhz;
diff --git a/arch/mips/sibyte/sb1250/setup.c b/arch/mips/sibyte/sb1250/setup.c
index f4a6169aa0a4..2d5c6d8b41f2 100644
--- a/arch/mips/sibyte/sb1250/setup.c
+++ b/arch/mips/sibyte/sb1250/setup.c
@@ -31,6 +31,7 @@
unsigned int sb1_pass;
unsigned int soc_pass;
unsigned int soc_type;
+EXPORT_SYMBOL(soc_type);
unsigned int periph_rev;
unsigned int zbbus_mhz;
EXPORT_SYMBOL(zbbus_mhz);
diff --git a/arch/mips/sibyte/swarm/time.c b/arch/mips/sibyte/swarm/time.c
deleted file mode 100644
index 97c73c793c35..000000000000
--- a/arch/mips/sibyte/swarm/time.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2000, 2001 Broadcom 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- * Time routines for the swarm board. We pass all the hard stuff
- * through to the sb1250 handling code. Only thing we really keep
- * track of here is what time of day we think it is. And we don't
- * really even do a good job of that...
- */
-
-
-#include <linux/bcd.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <asm/addrspace.h>
-#include <asm/io.h>
-
-#include <asm/sibyte/sb1250.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_smbus.h>
-
-static unsigned long long sec_bias = 0;
-static unsigned int usec_bias = 0;
-
-/* Xicor 1241 definitions */
-
-/*
- * Register bits
- */
-
-#define X1241REG_SR_BAT 0x80 /* currently on battery power */
-#define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */
-#define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */
-#define X1241REG_SR_RTCF 0x01 /* clock failed */
-#define X1241REG_BL_BP2 0x80 /* block protect 2 */
-#define X1241REG_BL_BP1 0x40 /* block protect 1 */
-#define X1241REG_BL_BP0 0x20 /* block protect 0 */
-#define X1241REG_BL_WD1 0x10
-#define X1241REG_BL_WD0 0x08
-#define X1241REG_HR_MIL 0x80 /* military time format */
-
-/*
- * Register numbers
- */
-
-#define X1241REG_BL 0x10 /* block protect bits */
-#define X1241REG_INT 0x11 /* */
-#define X1241REG_SC 0x30 /* Seconds */
-#define X1241REG_MN 0x31 /* Minutes */
-#define X1241REG_HR 0x32 /* Hours */
-#define X1241REG_DT 0x33 /* Day of month */
-#define X1241REG_MO 0x34 /* Month */
-#define X1241REG_YR 0x35 /* Year */
-#define X1241REG_DW 0x36 /* Day of Week */
-#define X1241REG_Y2K 0x37 /* Year 2K */
-#define X1241REG_SR 0x3F /* Status register */
-
-#define X1241_CCR_ADDRESS 0x6F
-
-#define SMB_CSR(reg) (IOADDR(A_SMB_REGISTER(1, reg)))
-
-static int xicor_read(uint8_t addr)
-{
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- __raw_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD));
- __raw_writeq(addr & 0xff, SMB_CSR(R_SMB_DATA));
- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE,
- SMB_CSR(R_SMB_START));
-
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE,
- SMB_CSR(R_SMB_START));
-
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
- /* Clear error bit by writing a 1 */
- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
- return -1;
- }
-
- return (__raw_readq(SMB_CSR(R_SMB_DATA)) & 0xff);
-}
-
-static int xicor_write(uint8_t addr, int b)
-{
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- __raw_writeq(addr, SMB_CSR(R_SMB_CMD));
- __raw_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA));
- __raw_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE,
- SMB_CSR(R_SMB_START));
-
- while (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- if (__raw_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) {
- /* Clear error bit by writing a 1 */
- __raw_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS));
- return -1;
- } else {
- return 0;
- }
-}
-
-/*
- * In order to set the CMOS clock precisely, set_rtc_mmss has to be
- * called 500 ms after the second nowtime has started, because when
- * nowtime is written into the registers of the CMOS clock, it will
- * jump to the next second precisely 500 ms later. Check the Motorola
- * MC146818A or Dallas DS12887 data sheet for details.
- *
- * BUG: This routine does not handle hour overflow properly; it just
- * sets the minutes. Usually you'll only notice that after reboot!
- */
-int set_rtc_mmss(unsigned long nowtime)
-{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
-
- cmos_minutes = xicor_read(X1241REG_MN);
- cmos_minutes = BCD2BIN(cmos_minutes);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- /* unlock writes to the CCR */
- xicor_write(X1241REG_SR, X1241REG_SR_WEL);
- xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL);
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- real_seconds = BIN2BCD(real_seconds);
- real_minutes = BIN2BCD(real_minutes);
- xicor_write(X1241REG_SC, real_seconds);
- xicor_write(X1241REG_MN, real_minutes);
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
- retval = -1;
- }
-
- xicor_write(X1241REG_SR, 0);
-
- printk("set_rtc_mmss: %02d:%02d\n", real_minutes, real_seconds);
-
- return retval;
-}
-
-static unsigned long __init get_swarm_time(void)
-{
- unsigned int year, mon, day, hour, min, sec, y2k;
-
- sec = xicor_read(X1241REG_SC);
- min = xicor_read(X1241REG_MN);
- hour = xicor_read(X1241REG_HR);
-
- if (hour & X1241REG_HR_MIL) {
- hour &= 0x3f;
- } else {
- if (hour & 0x20)
- hour = (hour & 0xf) + 0x12;
- }
-
- sec = BCD2BIN(sec);
- min = BCD2BIN(min);
- hour = BCD2BIN(hour);
-
- day = xicor_read(X1241REG_DT);
- mon = xicor_read(X1241REG_MO);
- year = xicor_read(X1241REG_YR);
- y2k = xicor_read(X1241REG_Y2K);
-
- day = BCD2BIN(day);
- mon = BCD2BIN(mon);
- year = BCD2BIN(year);
- y2k = BCD2BIN(y2k);
-
- year += (y2k * 100);
-
- return mktime(year, mon, day, hour, min, sec);
-}
-
-/*
- * Bring up the timer at 100 Hz.
- */
-void __init swarm_time_init(void)
-{
- unsigned int flags;
- int status;
-
- /* Set up the scd general purpose timer 0 to cpu 0 */
- sb1250_time_init();
-
- /* Establish communication with the Xicor 1241 RTC */
- /* XXXKW how do I share the SMBus with the I2C subsystem? */
-
- __raw_writeq(K_SMB_FREQ_400KHZ, SMB_CSR(R_SMB_FREQ));
- __raw_writeq(0, SMB_CSR(R_SMB_CONTROL));
-
- if ((status = xicor_read(X1241REG_SR_RTCF)) < 0) {
- printk("x1241: couldn't detect on SWARM SMBus 1\n");
- } else {
- if (status & X1241REG_SR_RTCF)
- printk("x1241: battery failed -- time is probably wrong\n");
- write_seqlock_irqsave(&xtime_lock, flags);
- xtime.tv_sec = get_swarm_time();
- xtime.tv_nsec = 0;
- write_sequnlock_irqrestore(&xtime_lock, flags);
- }
-}
diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c
index 6850a29defcd..acc9ba76c1a9 100644
--- a/arch/mips/sni/a20r.c
+++ b/arch/mips/sni/a20r.c
@@ -87,8 +87,8 @@ static struct platform_device snirm_82596_pdev = {
static struct resource snirm_53c710_rsrc[] = {
{
- .start = 0xb9000000,
- .end = 0xb90fffff,
+ .start = 0x19000000,
+ .end = 0x190fffff,
.flags = IORESOURCE_MEM
},
{
@@ -106,8 +106,8 @@ static struct platform_device snirm_53c710_pdev = {
static struct resource sc26xx_rsrc[] = {
{
- .start = 0xbc070000,
- .end = 0xbc0700ff,
+ .start = 0x1c070000,
+ .end = 0x1c0700ff,
.flags = IORESOURCE_MEM
},
{
diff --git a/arch/mips/sni/rm200.c b/arch/mips/sni/rm200.c
index 4bfda020fdc7..28a11d8605ce 100644
--- a/arch/mips/sni/rm200.c
+++ b/arch/mips/sni/rm200.c
@@ -88,8 +88,8 @@ static struct platform_device snirm_82596_rm200_pdev = {
static struct resource snirm_53c710_rm200_rsrc[] = {
{
- .start = 0xb9000000,
- .end = 0xb90fffff,
+ .start = 0x19000000,
+ .end = 0x190fffff,
.flags = IORESOURCE_MEM
},
{
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
index a0c11efeaeeb..40c7c3eeafaf 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
@@ -138,7 +138,6 @@ extern void toshiba_rbtx4927_irq_setup(void);
char *prom_getcmdline(void);
#ifdef CONFIG_PCI
-#define CONFIG_TX4927BUG_WORKAROUND
#undef TX4927_SUPPORT_COMMAND_IO
#undef TX4927_SUPPORT_PCI_66
int tx4927_cpu_clock = 100000000; /* 100MHz */
@@ -669,15 +668,7 @@ void tx4927_pci_setup(void)
/* PCI->GB mappings (MEM 16MB) -not used */
tx4927_pcicptr->p2gm1plbase = 0xffffffff;
-#ifdef CONFIG_TX4927BUG_WORKAROUND
- /*
- * TX4927-PCIC-BUG: P2GM1PUBASE must be 0
- * if P2GM0PUBASE was 0.
- */
- tx4927_pcicptr->p2gm1pubase = 0;
-#else
tx4927_pcicptr->p2gm1pubase = 0xffffffff;
-#endif
tx4927_pcicptr->p2gmgbase[1] = 0;
/* PCI->GB mappings (MEM 1MB) -not used */
@@ -910,16 +901,6 @@ void __init toshiba_rbtx4927_setup(void)
if (tx4927_ccfg_toeon)
tx4927_ccfgptr->ccfg |= TX4927_CCFG_TOE;
- /* SDRAMC fixup */
-#ifdef CONFIG_TX4927BUG_WORKAROUND
- /*
- * TX4927-BUG: INF 01-01-18/ BUG 01-01-22
- * G-bus timeout error detection is incorrect
- */
- if (tx4927_ccfg_toeon)
- tx4927_sdramcptr->tr |= 0x02000000; /* RCD:3tck */
-#endif
-
tx4927_pci_setup();
if (tx4927_using_backplane == 1)
printk("backplane board IS installed\n");
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
index f842783acd86..d0d84ec8d63d 100644
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -2,4 +2,4 @@
# Makefile for common code of the NEC VR4100 series.
#
-obj-y += bcu.o cmu.o icu.o init.o irq.o pmu.o type.o
+obj-y += bcu.o cmu.o giu.o icu.o init.o irq.o pmu.o rtc.o siu.o type.o
diff --git a/arch/mips/vr41xx/common/giu.c b/arch/mips/vr41xx/common/giu.c
new file mode 100644
index 000000000000..d21f6f2d22a3
--- /dev/null
+++ b/arch/mips/vr41xx/common/giu.c
@@ -0,0 +1,122 @@
+/*
+ * NEC VR4100 series GIU platform device.
+ *
+ * Copyright (C) 2007 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/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/cpu.h>
+#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/irq.h>
+
+static struct resource giu_50pins_pullupdown_resource[] __initdata = {
+ {
+ .start = 0x0b000100,
+ .end = 0x0b00011f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x0b0002e0,
+ .end = 0x0b0002e3,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = GIUINT_IRQ,
+ .end = GIUINT_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource giu_36pins_resource[] __initdata = {
+ {
+ .start = 0x0f000140,
+ .end = 0x0f00015f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = GIUINT_IRQ,
+ .end = GIUINT_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource giu_48pins_resource[] __initdata = {
+ {
+ .start = 0x0f000140,
+ .end = 0x0f000167,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = GIUINT_IRQ,
+ .end = GIUINT_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int __init vr41xx_giu_add(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ unsigned int num;
+ int retval;
+
+ pdev = platform_device_alloc("GIU", -1);
+ if (!pdev)
+ return -ENOMEM;
+
+ switch (current_cpu_data.cputype) {
+ case CPU_VR4111:
+ case CPU_VR4121:
+ pdev->id = GPIO_50PINS_PULLUPDOWN;
+ res = giu_50pins_pullupdown_resource;
+ num = ARRAY_SIZE(giu_50pins_pullupdown_resource);
+ break;
+ case CPU_VR4122:
+ case CPU_VR4131:
+ pdev->id = GPIO_36PINS;
+ res = giu_36pins_resource;
+ num = ARRAY_SIZE(giu_36pins_resource);
+ break;
+ case CPU_VR4133:
+ pdev->id = GPIO_48PINS_EDGE_SELECT;
+ res = giu_48pins_resource;
+ num = ARRAY_SIZE(giu_48pins_resource);
+ break;
+ default:
+ retval = -ENODEV;
+ goto err_free_device;
+ }
+
+ retval = platform_device_add_resources(pdev, res, num);
+ if (retval)
+ goto err_free_device;
+
+ retval = platform_device_add(pdev);
+ if (retval)
+ goto err_free_device;
+
+ return 0;
+
+err_free_device:
+ platform_device_put(pdev);
+
+ return retval;
+}
+device_initcall(vr41xx_giu_add);
diff --git a/arch/mips/vr41xx/common/rtc.c b/arch/mips/vr41xx/common/rtc.c
new file mode 100644
index 000000000000..cce605b3d688
--- /dev/null
+++ b/arch/mips/vr41xx/common/rtc.c
@@ -0,0 +1,117 @@
+/*
+ * NEC VR4100 series RTC platform device.
+ *
+ * Copyright (C) 2007 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/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+#include <asm/cpu.h>
+#include <asm/vr41xx/irq.h>
+
+static struct resource rtc_type1_resource[] __initdata = {
+ {
+ .start = 0x0b0000c0,
+ .end = 0x0b0000df,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x0b0001c0,
+ .end = 0x0b0001df,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = ELAPSEDTIME_IRQ,
+ .end = ELAPSEDTIME_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = RTCLONG1_IRQ,
+ .end = RTCLONG1_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource rtc_type2_resource[] __initdata = {
+ {
+ .start = 0x0f000100,
+ .end = 0x0f00011f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x0f000120,
+ .end = 0x0f00013f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = ELAPSEDTIME_IRQ,
+ .end = ELAPSEDTIME_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = RTCLONG1_IRQ,
+ .end = RTCLONG1_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int __init vr41xx_rtc_add(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ unsigned int num;
+ int retval;
+
+ pdev = platform_device_alloc("RTC", -1);
+ if (!pdev)
+ return -ENOMEM;
+
+ switch (current_cpu_data.cputype) {
+ case CPU_VR4111:
+ case CPU_VR4121:
+ res = rtc_type1_resource;
+ num = ARRAY_SIZE(rtc_type1_resource);
+ break;
+ case CPU_VR4122:
+ case CPU_VR4131:
+ case CPU_VR4133:
+ res = rtc_type2_resource;
+ num = ARRAY_SIZE(rtc_type2_resource);
+ break;
+ default:
+ retval = -ENODEV;
+ goto err_free_device;
+ }
+
+ retval = platform_device_add_resources(pdev, res, num);
+ if (retval)
+ goto err_free_device;
+
+ retval = platform_device_add(pdev);
+ if (retval)
+ goto err_free_device;
+
+ return 0;
+
+err_free_device:
+ platform_device_put(pdev);
+
+ return retval;
+}
+device_initcall(vr41xx_rtc_add);
diff --git a/arch/mips/vr41xx/common/siu.c b/arch/mips/vr41xx/common/siu.c
new file mode 100644
index 000000000000..a1e774142163
--- /dev/null
+++ b/arch/mips/vr41xx/common/siu.c
@@ -0,0 +1,120 @@
+/*
+ * NEC VR4100 series SIU platform device.
+ *
+ * Copyright (C) 2007 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/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+
+#include <asm/cpu.h>
+#include <asm/vr41xx/siu.h>
+
+static unsigned int siu_type1_ports[SIU_PORTS_MAX] __initdata = {
+ PORT_VR41XX_SIU,
+ PORT_UNKNOWN,
+};
+
+static struct resource siu_type1_resource[] __initdata = {
+ {
+ .start = 0x0c000000,
+ .end = 0x0c00000a,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_IRQ,
+ .end = SIU_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static unsigned int siu_type2_ports[SIU_PORTS_MAX] __initdata = {
+ PORT_VR41XX_SIU,
+ PORT_VR41XX_DSIU,
+};
+
+static struct resource siu_type2_resource[] __initdata = {
+ {
+ .start = 0x0f000800,
+ .end = 0x0f00080a,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = 0x0f000820,
+ .end = 0x0f000829,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = SIU_IRQ,
+ .end = SIU_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = DSIU_IRQ,
+ .end = DSIU_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static int __init vr41xx_siu_add(void)
+{
+ struct platform_device *pdev;
+ struct resource *res;
+ unsigned int num;
+ int retval;
+
+ pdev = platform_device_alloc("SIU", -1);
+ if (!pdev)
+ return -ENOMEM;
+
+ switch (current_cpu_data.cputype) {
+ case CPU_VR4111:
+ case CPU_VR4121:
+ pdev->dev.platform_data = siu_type1_ports;
+ res = siu_type1_resource;
+ num = ARRAY_SIZE(siu_type1_resource);
+ break;
+ case CPU_VR4122:
+ case CPU_VR4131:
+ case CPU_VR4133:
+ pdev->dev.platform_data = siu_type2_ports;
+ res = siu_type2_resource;
+ num = ARRAY_SIZE(siu_type2_resource);
+ break;
+ default:
+ retval = -ENODEV;
+ goto err_free_device;
+ }
+
+ retval = platform_device_add_resources(pdev, res, num);
+ if (retval)
+ goto err_free_device;
+
+ retval = platform_device_add(pdev);
+ if (retval)
+ goto err_free_device;
+
+ return 0;
+
+err_free_device:
+ platform_device_put(pdev);
+
+ return retval;
+}
+device_initcall(vr41xx_siu_add);
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 8a0db376e91e..26ec774c5027 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -87,10 +87,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA: {
- int copied;
-
#ifdef CONFIG_64BIT
if (__is_compat_task(child)) {
+ int copied;
unsigned int tmp;
addr &= 0xffffffffL;
@@ -105,15 +104,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
}
else
#endif
- {
- unsigned long tmp;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- goto out_tsk;
- ret = put_user(tmp,(unsigned long *) data);
- }
+ ret = generic_ptrace_peekdata(child, addr, data);
goto out_tsk;
}
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index c3ec9f1ec0f3..bbf029a184ac 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -264,6 +264,7 @@ KERN_CRIT " || ||\n");
show_regs(regs);
dump_stack();
+ add_taint(TAINT_DIE);
if (in_interrupt())
panic("Fatal exception in interrupt");
@@ -302,7 +303,7 @@ static void handle_break(struct pt_regs *regs)
if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) {
/* check if a BUG() or WARN() trapped here. */
enum bug_trap_type tt;
- tt = report_bug(regs->iaoq[0] & ~3);
+ tt = report_bug(regs->iaoq[0] & ~3, regs);
if (tt == BUG_TRAP_TYPE_WARN) {
regs->iaoq[0] += 4;
regs->iaoq[1] += 4;
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
index 322167737de7..cf780cb3b916 100644
--- a/arch/parisc/kernel/unwind.c
+++ b/arch/parisc/kernel/unwind.c
@@ -242,7 +242,7 @@ static void unwind_frame_regs(struct unwind_frame_info *info)
#ifdef CONFIG_KALLSYMS
/* Handle some frequent special cases.... */
{
- char symname[KSYM_NAME_LEN+1];
+ char symname[KSYM_NAME_LEN];
char *modname;
kallsyms_lookup(info->ip, NULL, NULL, &modname,
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 4d96ba4b9849..d4e6a93c8d9a 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -181,10 +181,9 @@ SECTIONS
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
#endif
- . = ALIGN(ASM_PAGE_SIZE);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+
+ PERCPU(ASM_PAGE_SIZE)
+
. = ALIGN(ASM_PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
index f6f67554c623..7899ab87785a 100644
--- a/arch/parisc/mm/fault.c
+++ b/arch/parisc/mm/fault.c
@@ -147,6 +147,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
struct mm_struct *mm = tsk->mm;
const struct exception_table_entry *fix;
unsigned long acc_type;
+ int fault;
if (in_atomic() || !mm)
goto no_context;
@@ -173,23 +174,23 @@ good_area:
* fault.
*/
- switch (handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) != 0)) {
- case VM_FAULT_MINOR:
- ++current->min_flt;
- break;
- case VM_FAULT_MAJOR:
- ++current->maj_flt;
- break;
- case VM_FAULT_SIGBUS:
+ fault = handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) != 0);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
/*
* We hit a shared mapping outside of the file, or some
* other thing happened to us that made us unable to
* handle the page fault gracefully.
*/
- goto bad_area;
- default:
- goto out_of_memory;
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto bad_area;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
return;
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 5eaeafd30bdf..853c282da22e 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -4,17 +4,7 @@
mainmenu "Linux/PowerPC Kernel Configuration"
-config PPC64
- bool "64-bit kernel"
- default n
- help
- This option selects whether a 32-bit or a 64-bit kernel
- will be built.
-
-config PPC_PM_NEEDS_RTC_LIB
- bool
- select RTC_LIB
- default y if PM
+source "arch/powerpc/platforms/Kconfig.cputype"
config PPC32
bool
@@ -66,6 +56,9 @@ config GENERIC_FIND_NEXT_BIT
bool
default y
+config ARCH_NO_VIRT_TO_BUS
+ def_bool PPC64
+
config PPC
bool
default y
@@ -99,6 +92,9 @@ config ARCH_MAY_HAVE_PC_FDC
config PPC_OF
def_bool y
+config OF
+ def_bool y
+
config PPC_UDBG_16550
bool
default n
@@ -132,123 +128,6 @@ config PPC64_SWSUSP
depends on PPC64 && (BROKEN || (PPC_PMAC64 && EXPERIMENTAL))
default y
-menu "Processor support"
-choice
- prompt "Processor Type"
- depends on PPC32
- default 6xx
-
-config CLASSIC32
- bool "52xx/6xx/7xx/74xx"
- select PPC_FPU
- select 6xx
- help
- There are four families of PowerPC chips supported. The more common
- types (601, 603, 604, 740, 750, 7400), the Motorola embedded
- versions (821, 823, 850, 855, 860, 52xx, 82xx, 83xx), the AMCC
- embedded versions (403 and 405) and the high end 64 bit Power
- processors (POWER 3, POWER4, and IBM PPC970 also known as G5).
-
- This option is the catch-all for 6xx types, including some of the
- embedded versions. Unless there is see an option for the specific
- chip family you are using, you want this option.
-
- You do not want this if you are building a kernel for a 64 bit
- IBM RS/6000 or an Apple G5, choose 6xx.
-
- If unsure, select this option
-
- Note that the kernel runs in 32-bit mode even on 64-bit chips.
-
-config PPC_82xx
- bool "Freescale 82xx"
- select 6xx
- select PPC_FPU
-
-config PPC_83xx
- bool "Freescale 83xx"
- select 6xx
- select FSL_SOC
- select 83xx
- select PPC_FPU
- select WANT_DEVICE_TREE
-
-config PPC_85xx
- bool "Freescale 85xx"
- select E500
- select FSL_SOC
- select 85xx
- select WANT_DEVICE_TREE
-
-config PPC_86xx
- bool "Freescale 86xx"
- select 6xx
- select FSL_SOC
- select FSL_PCIE
- select PPC_FPU
- select ALTIVEC
- help
- The Freescale E600 SoCs have 74xx cores.
-
-config PPC_8xx
- bool "Freescale 8xx"
- select FSL_SOC
- select 8xx
-
-config 40x
- bool "AMCC 40x"
- select PPC_DCR_NATIVE
-
-config 44x
- bool "AMCC 44x"
- select PPC_DCR_NATIVE
- select WANT_DEVICE_TREE
-
-config E200
- bool "Freescale e200"
-
-endchoice
-
-config POWER4_ONLY
- bool "Optimize for POWER4"
- depends on PPC64
- default n
- ---help---
- Cause the compiler to optimize for POWER4/POWER5/PPC970 processors.
- The resulting binary will not work on POWER3 or RS64 processors
- when compiled with binutils 2.15 or later.
-
-config POWER3
- bool
- depends on PPC64
- default y if !POWER4_ONLY
-
-config POWER4
- depends on PPC64
- def_bool y
-
-config 6xx
- bool
-
-# this is temp to handle compat with arch=ppc
-config 8xx
- bool
-
-# this is temp to handle compat with arch=ppc
-config 83xx
- bool
-
-# this is temp to handle compat with arch=ppc
-config 85xx
- bool
-
-config E500
- bool
-
-config PPC_FPU
- bool
- default y if PPC64
-
config PPC_DCR_NATIVE
bool
default n
@@ -267,134 +146,6 @@ config PPC_OF_PLATFORM_PCI
depends on PPC64 # not supported on 32 bits yet
default n
-config 4xx
- bool
- depends on 40x || 44x
- default y
-
-config BOOKE
- bool
- depends on E200 || E500 || 44x
- default y
-
-config FSL_BOOKE
- bool
- depends on E200 || E500
- default y
-
-config PTE_64BIT
- bool
- depends on 44x || E500
- default y if 44x
- default y if E500 && PHYS_64BIT
-
-config PHYS_64BIT
- bool 'Large physical address support' if E500
- depends on 44x || E500
- select RESOURCES_64BIT
- default y if 44x
- ---help---
- This option enables kernel support for larger than 32-bit physical
- addresses. This features is not be available on all e500 cores.
-
- If in doubt, say N here.
-
-config ALTIVEC
- bool "AltiVec Support"
- depends on CLASSIC32 || POWER4
- ---help---
- This option enables kernel support for the Altivec extensions to the
- PowerPC processor. The kernel currently supports saving and restoring
- altivec registers, and turning on the 'altivec enable' bit so user
- processes can execute altivec instructions.
-
- This option is only usefully if you have a processor that supports
- altivec (G4, otherwise known as 74xx series), but does not have
- any affect on a non-altivec cpu (it does, however add code to the
- kernel).
-
- If in doubt, say Y here.
-
-config SPE
- bool "SPE Support"
- depends on E200 || E500
- default y
- ---help---
- This option enables kernel support for the Signal Processing
- Extensions (SPE) to the PowerPC processor. The kernel currently
- supports saving and restoring SPE registers, and turning on the
- 'spe enable' bit so user processes can execute SPE instructions.
-
- This option is only useful if you have a processor that supports
- SPE (e500, otherwise known as 85xx series), but does not have any
- effect on a non-spe cpu (it does, however add code to the kernel).
-
- If in doubt, say Y here.
-
-config PPC_STD_MMU
- bool
- depends on 6xx || POWER3 || POWER4 || PPC64
- default y
-
-config PPC_STD_MMU_32
- def_bool y
- depends on PPC_STD_MMU && PPC32
-
-config PPC_MM_SLICES
- bool
- default y if HUGETLB_PAGE
- default n
-
-config VIRT_CPU_ACCOUNTING
- bool "Deterministic task and CPU time accounting"
- depends on PPC64
- default y
- help
- Select this option to enable more accurate task and CPU time
- accounting. This is done by reading a CPU counter on each
- kernel entry and exit and on transitions within the kernel
- between system, softirq and hardirq state, so there is a
- small performance impact. This also enables accounting of
- stolen time on logically-partitioned systems running on
- IBM POWER5-based machines.
-
- If in doubt, say Y here.
-
-config SMP
- depends on PPC_STD_MMU
- bool "Symmetric multi-processing support"
- ---help---
- This enables support for systems with more than one CPU. If you have
- a system with only one CPU, say N. If you have a system with more
- than one CPU, say Y. Note that the kernel does not currently
- support SMP machines with 603/603e/603ev or PPC750 ("G3") processors
- since they have inadequate hardware support for multiprocessor
- operation.
-
- If you say N here, the kernel will run on single and multiprocessor
- machines, but will use only one CPU of a multiprocessor machine. If
- you say Y here, the kernel will run on single-processor machines.
- On a single-processor machine, the kernel will run faster if you say
- N here.
-
- If you don't know what to do here, say N.
-
-config NR_CPUS
- int "Maximum number of CPUs (2-128)"
- range 2 128
- depends on SMP
- default "32" if PPC64
- default "4"
-
-config NOT_COHERENT_CACHE
- bool
- depends on 4xx || 8xx || E200
- default y
-
-config CONFIG_CHECK_CACHE_COHERENCY
- bool
-endmenu
-
source "init/Kconfig"
source "arch/powerpc/platforms/Kconfig"
@@ -674,10 +425,6 @@ config SBUS
config FSL_SOC
bool
-config FSL_PCIE
- bool
- depends on PPC_86xx
-
# Yes MCA RS/6000s exist but Linux-PPC does not currently support any
config MCA
bool
@@ -685,10 +432,10 @@ config MCA
config PCI
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
- || MPC7448HPC2 || PPC_PS3 || PPC_HOLLY
- default y if !40x && !CPM2 && !8xx && !APUS && !PPC_83xx \
+ || PPC_PS3
+ default y if !40x && !CPM2 && !8xx && !PPC_83xx \
&& !PPC_85xx && !PPC_86xx
- default PCI_PERMEDIA if !4xx && !CPM2 && !8xx && APUS
+ default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
default PCI_QSPAN if !4xx && !CPM2 && 8xx
select ARCH_SUPPORTS_MSI
help
@@ -698,8 +445,10 @@ config PCI
infrastructure code to support PCI bus devices.
config PCI_DOMAINS
- bool
- default PCI
+ def_bool PCI
+
+config PCI_SYSCALL
+ def_bool PCI
config PCI_QSPAN
bool "QSpan PCI"
@@ -894,8 +643,8 @@ menu "Instrumentation Support"
source "arch/powerpc/oprofile/Kconfig"
config KPROBES
- bool "Kprobes (EXPERIMENTAL)"
- depends on !BOOKE && !4xx && KALLSYMS && EXPERIMENTAL && MODULES
+ bool "Kprobes"
+ depends on !BOOKE && !4xx && KALLSYMS && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index fbafd965dcd2..6c1e36c33faa 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -148,7 +148,7 @@ all: $(KBUILD_IMAGE)
CPPFLAGS_vmlinux.lds := -Upowerpc
-BOOT_TARGETS = zImage zImage.initrd zImage.dts zImage.dts_initrd uImage
+BOOT_TARGETS = zImage zImage.initrd uImage
PHONY += $(BOOT_TARGETS)
@@ -201,6 +201,14 @@ checkbin:
false; \
fi ; \
fi
+ @if test "$(call cc-fullversion)" = "040200" \
+ && test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \
+ echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \
+ echo 'kernel with modules enabled.' ; \
+ echo -n '*** Please use a different GCC version or ' ; \
+ echo 'disable kernel modules' ; \
+ false ; \
+ fi
@if ! /bin/echo dssall | $(AS) -many -o $(TOUT) >/dev/null 2>&1 ; then \
echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build ' ; \
echo 'correctly with old versions of binutils.' ; \
diff --git a/arch/powerpc/boot/44x.c b/arch/powerpc/boot/44x.c
index d51377d9024f..9f64e840bef6 100644
--- a/arch/powerpc/boot/44x.c
+++ b/arch/powerpc/boot/44x.c
@@ -38,3 +38,48 @@ void ibm44x_fixup_memsize(void)
dt_fixup_memory(0, memsize);
}
+
+#define SPRN_DBCR0 0x134
+#define DBCR0_RST_SYSTEM 0x30000000
+
+void ibm44x_dbcr_reset(void)
+{
+ unsigned long tmp;
+
+ asm volatile (
+ "mfspr %0,%1\n"
+ "oris %0,%0,%2@h\n"
+ "mtspr %1,%0"
+ : "=&r"(tmp) : "i"(SPRN_DBCR0), "i"(DBCR0_RST_SYSTEM)
+ );
+
+}
+
+/* Read 4xx EBC bus bridge registers to get mappings of the peripheral
+ * banks into the OPB address space */
+void ibm4xx_fixup_ebc_ranges(const char *ebc)
+{
+ void *devp;
+ u32 bxcr;
+ u32 ranges[EBC_NUM_BANKS*4];
+ u32 *p = ranges;
+ int i;
+
+ for (i = 0; i < EBC_NUM_BANKS; i++) {
+ mtdcr(DCRN_EBC0_CFGADDR, EBC_BXCR(i));
+ bxcr = mfdcr(DCRN_EBC0_CFGDATA);
+
+ if ((bxcr & EBC_BXCR_BU) != EBC_BXCR_BU_OFF) {
+ *p++ = i;
+ *p++ = 0;
+ *p++ = bxcr & EBC_BXCR_BAS;
+ *p++ = EBC_BXCR_BANK_SIZE(bxcr);
+ }
+ }
+
+ devp = finddevice(ebc);
+ if (! devp)
+ fatal("Couldn't locate EBC node %s\n\r", ebc);
+
+ setprop(devp, "ranges", ranges, (p - ranges) * sizeof(u32));
+}
diff --git a/arch/powerpc/boot/44x.h b/arch/powerpc/boot/44x.h
index 7b129ad043e1..577982c9a3cd 100644
--- a/arch/powerpc/boot/44x.h
+++ b/arch/powerpc/boot/44x.h
@@ -11,6 +11,9 @@
#define _PPC_BOOT_44X_H_
void ibm44x_fixup_memsize(void);
+void ibm4xx_fixup_ebc_ranges(const char *ebc);
+
+void ibm44x_dbcr_reset(void);
void ebony_init(void *mac0, void *mac1);
#endif /* _PPC_BOOT_44X_H_ */
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index ff2701949ee1..61a6f34ca5ed 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -43,10 +43,11 @@ $(addprefix $(obj)/,$(zlib) gunzip_util.o main.o): \
src-wlib := string.S crt0.S stdio.c main.c flatdevtree.c flatdevtree_misc.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
- gunzip_util.c elf_util.c $(zlib) devtree.c \
- 44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c
+ gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
+ 44x.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c
src-plat := of.c cuboot-83xx.c cuboot-85xx.c holly.c \
- cuboot-ebony.c treeboot-ebony.c prpmc2800.c
+ cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
+ ps3-head.S ps3-hvcall.S ps3.c
src-boot := $(src-wlib) $(src-plat) empty.c
src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -75,11 +76,11 @@ $(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
$(obj)/empty.c:
@touch $@
-$(obj)/zImage.lds $(obj)/zImage.coff.lds: $(obj)/%: $(srctree)/$(src)/%.S
+$(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds: $(obj)/%: $(srctree)/$(src)/%.S
@cp $< $@
clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
- empty.c zImage.coff.lds zImage.lds
+ empty.c zImage zImage.coff.lds zImage.ps3.lds zImage.lds
quiet_cmd_bootcc = BOOTCC $@
cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
@@ -102,7 +103,7 @@ hostprogs-y := addnote addRamDisk hack-coff mktree
targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
- $(obj)/zImage.lds $(obj)/zImage.coff.lds
+ $(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds
wrapper :=$(srctree)/$(src)/wrapper
wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree) \
@@ -132,7 +133,7 @@ image-$(CONFIG_PPC_CELLEB) += zImage.pseries
image-$(CONFIG_PPC_CHRP) += zImage.chrp
image-$(CONFIG_PPC_EFIKA) += zImage.chrp
image-$(CONFIG_PPC_PMAC) += zImage.pmac
-image-$(CONFIG_PPC_HOLLY) += zImage.holly-elf
+image-$(CONFIG_PPC_HOLLY) += zImage.holly
image-$(CONFIG_PPC_PRPMC2800) += zImage.prpmc2800
image-$(CONFIG_PPC_ISERIES) += zImage.iseries
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
@@ -157,55 +158,43 @@ targets += $(image-y) $(initrd-y)
$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
-dts- := $(patsubst zImage%, zImage.dts%, $(image-n) $(image-))
-dts-y := $(patsubst zImage%, zImage.dts%, $(image-y))
-dts-y := $(filter-out $(image-y), $(dts-y))
-targets += $(image-y) $(dts-y)
-
-dts_initrd- := $(patsubst zImage%, zImage.dts_initrd%, $(image-n) $(image-))
-dts_initrd-y := $(patsubst zImage%, zImage.dts_initrd%, $(image-y))
-dts_initrd-y := $(filter-out $(image-y), $(dts_initrd-y))
-targets += $(image-y) $(dts_initrd-y)
-
-$(addprefix $(obj)/, $(dts_initrd-y)): $(obj)/ramdisk.image.gz
+# If CONFIG_WANT_DEVICE_TREE is set and CONFIG_DEVICE_TREE isn't an
+# empty string, define 'dts' to be path to the dts
+# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them
+ifeq ($(CONFIG_WANT_DEVICE_TREE),y)
+ifneq ($(CONFIG_DEVICE_TREE),"")
+dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
+ ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%)
+endif
+endif
# Don't put the ramdisk on the pattern rule; when its missing make will try
# the pattern rule with less dependencies that also matches (even with the
# hard dependency listed).
-$(obj)/zImage.dts_initrd.%: vmlinux $(wrapperbits) $(dts) $(obj)/ramdisk.image.gz
+$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(dts)
$(call if_changed,wrap,$*,$(dts),,$(obj)/ramdisk.image.gz)
-$(obj)/zImage.dts.%: vmlinux $(wrapperbits) $(dts)
+$(obj)/zImage.%: vmlinux $(wrapperbits) $(dts)
$(call if_changed,wrap,$*,$(dts))
-$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
- $(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
-
-$(obj)/zImage.%: vmlinux $(wrapperbits)
- $(call if_changed,wrap,$*)
-
-$(obj)/zImage.iseries: vmlinux
+# This cannot be in the root of $(src) as the zImage rule always adds a $(obj)
+# prefix
+$(obj)/vmlinux.strip: vmlinux
$(STRIP) -s -R .comment $< -o $@
-$(obj)/zImage.ps3: vmlinux
+$(obj)/zImage.iseries: vmlinux
$(STRIP) -s -R .comment $< -o $@
-$(obj)/zImage.initrd.ps3: vmlinux
- @echo " WARNING zImage.initrd.ps3 not supported (yet)"
-
-$(obj)/zImage.holly-elf: vmlinux $(wrapperbits)
- $(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,)
+$(obj)/zImage.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts
+ $(STRIP) -s -R .comment $< -o vmlinux.strip
+ $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,)
-$(obj)/zImage.initrd.holly-elf: vmlinux $(wrapperbits) $(obj)/ramdisk.image.gz
- $(call if_changed,wrap,holly,$(obj)/dts/holly.dts,,$(obj)/ramdisk.image.gz)
+$(obj)/zImage.initrd.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts $(obj)/ramdisk.image.gz
+ $(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,$(obj)/ramdisk.image.gz)
$(obj)/uImage: vmlinux $(wrapperbits)
$(call if_changed,wrap,uboot)
-# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them
-dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
- ,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%)
-
$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits)
$(call if_changed,wrap,cuboot-$*,$(dts))
@@ -215,22 +204,22 @@ $(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits)
$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits)
$(call if_changed,wrap,treeboot-$*,$(dts))
+# If there isn't a platform selected then just strip the vmlinux.
+ifeq (,$(image-y))
+image-y := vmlinux.strip
+endif
+
$(obj)/zImage: $(addprefix $(obj)/, $(image-y))
@rm -f $@; ln $< $@
$(obj)/zImage.initrd: $(addprefix $(obj)/, $(initrd-y))
@rm -f $@; ln $< $@
-$(obj)/zImage.dts: $(addprefix $(obj)/, $(dts-y))
- @rm -f $@; ln $< $@
-$(obj)/zImage.dts_initrd: $(addprefix $(obj)/, $(dts_initrd-y))
- @rm -f $@; ln $< $@
-
install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y))
sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $<
# anything not in $(targets)
-clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* \
- treeImage.* zImage.dts zImage.dts_initrd
+clean-files += $(image-) $(initrd-) zImage zImage.initrd cuImage.* treeImage.* \
+ otheros.bld
# clean up files cached by wrapper
clean-kernel := vmlinux.strip vmlinux.bin
diff --git a/arch/powerpc/boot/cuboot-83xx.c b/arch/powerpc/boot/cuboot-83xx.c
index 9af554eea54b..296025d8b295 100644
--- a/arch/powerpc/boot/cuboot-83xx.c
+++ b/arch/powerpc/boot/cuboot-83xx.c
@@ -12,12 +12,12 @@
#include "ops.h"
#include "stdio.h"
+#include "cuboot.h"
#define TARGET_83xx
#include "ppcboot.h"
static bd_t bd;
-extern char _end[];
extern char _dtb_start[], _dtb_end[];
static void platform_fixups(void)
@@ -52,16 +52,7 @@ static void platform_fixups(void)
void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
- unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
- unsigned long avail_ram = end_of_ram - (unsigned long)_end;
-
- memcpy(&bd, (bd_t *)r3, sizeof(bd));
- loader_info.initrd_addr = r4;
- loader_info.initrd_size = r4 ? r5 - r4 : 0;
- loader_info.cmdline = (char *)r6;
- loader_info.cmdline_len = r7 - r6;
-
- simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+ CUBOOT_INIT();
ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
serial_console_init();
platform_ops.fixups = platform_fixups;
diff --git a/arch/powerpc/boot/cuboot-85xx.c b/arch/powerpc/boot/cuboot-85xx.c
index e2560317f278..10f0f697c935 100644
--- a/arch/powerpc/boot/cuboot-85xx.c
+++ b/arch/powerpc/boot/cuboot-85xx.c
@@ -12,12 +12,12 @@
#include "ops.h"
#include "stdio.h"
+#include "cuboot.h"
#define TARGET_85xx
#include "ppcboot.h"
static bd_t bd;
-extern char _end[];
extern char _dtb_start[], _dtb_end[];
static void platform_fixups(void)
@@ -53,16 +53,7 @@ static void platform_fixups(void)
void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
- unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
- unsigned long avail_ram = end_of_ram - (unsigned long)_end;
-
- memcpy(&bd, (bd_t *)r3, sizeof(bd));
- loader_info.initrd_addr = r4;
- loader_info.initrd_size = r4 ? r5 - r4 : 0;
- loader_info.cmdline = (char *)r6;
- loader_info.cmdline_len = r7 - r6;
-
- simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+ CUBOOT_INIT();
ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
serial_console_init();
platform_ops.fixups = platform_fixups;
diff --git a/arch/powerpc/boot/cuboot-ebony.c b/arch/powerpc/boot/cuboot-ebony.c
index 4464c5f67acb..c5f37ce172ea 100644
--- a/arch/powerpc/boot/cuboot-ebony.c
+++ b/arch/powerpc/boot/cuboot-ebony.c
@@ -15,28 +15,16 @@
#include "ops.h"
#include "stdio.h"
#include "44x.h"
+#include "cuboot.h"
#define TARGET_44x
#include "ppcboot.h"
static bd_t bd;
-extern char _end[];
-
-BSS_STACK(4096);
void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7)
{
- unsigned long end_of_ram = bd.bi_memstart + bd.bi_memsize;
- unsigned long avail_ram = end_of_ram - (unsigned long)_end;
-
- memcpy(&bd, (bd_t *)r3, sizeof(bd));
- loader_info.initrd_addr = r4;
- loader_info.initrd_size = r4 ? r5 : 0;
- loader_info.cmdline = (char *)r6;
- loader_info.cmdline_len = r7 - r6;
-
- simple_alloc_init(_end, avail_ram, 32, 64);
-
+ CUBOOT_INIT();
ebony_init(&bd.bi_enetaddr, &bd.bi_enet1addr);
}
diff --git a/arch/powerpc/boot/cuboot.c b/arch/powerpc/boot/cuboot.c
new file mode 100644
index 000000000000..65795468ad6f
--- /dev/null
+++ b/arch/powerpc/boot/cuboot.c
@@ -0,0 +1,35 @@
+/*
+ * Compatibility for old (not device tree aware) U-Boot versions
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ * Consolidated using macros by David Gibson <david@gibson.dropbear.id.au>
+ *
+ * Copyright 2007 David Gibson, IBM Corporation.
+ * Copyright (c) 2007 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 version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+
+#include "ppcboot.h"
+
+extern char _end[];
+extern char _dtb_start[], _dtb_end[];
+
+void cuboot_init(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ unsigned long end_of_ram)
+{
+ unsigned long avail_ram = end_of_ram - (unsigned long)_end;
+
+ loader_info.initrd_addr = r4;
+ loader_info.initrd_size = r4 ? r5 - r4 : 0;
+ loader_info.cmdline = (char *)r6;
+ loader_info.cmdline_len = r7 - r6;
+
+ simple_alloc_init(_end, avail_ram - 1024*1024, 32, 64);
+}
diff --git a/arch/powerpc/boot/cuboot.h b/arch/powerpc/boot/cuboot.h
new file mode 100644
index 000000000000..cd2aa7f348f3
--- /dev/null
+++ b/arch/powerpc/boot/cuboot.h
@@ -0,0 +1,14 @@
+#ifndef _PPC_BOOT_CUBOOT_H_
+#define _PPC_BOOT_CUBOOT_H_
+
+void cuboot_init(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ unsigned long end_of_ram);
+
+#define CUBOOT_INIT() \
+ do { \
+ memcpy(&bd, (bd_t *)r3, sizeof(bd)); \
+ cuboot_init(r4, r5, r6, r7, bd.bi_memstart + bd.bi_memsize); \
+ } while (0)
+
+#endif /* _PPC_BOOT_CUBOOT_H_ */
diff --git a/arch/powerpc/boot/dcr.h b/arch/powerpc/boot/dcr.h
index 877bc97b1e97..14b44aa96fea 100644
--- a/arch/powerpc/boot/dcr.h
+++ b/arch/powerpc/boot/dcr.h
@@ -26,6 +26,43 @@ static const unsigned long sdram_bxcr[] = { SDRAM0_B0CR, SDRAM0_B1CR, SDRAM0_B2C
#define SDRAM_CONFIG_BANK_SIZE(reg) \
(0x00400000 << ((reg & SDRAM_CONFIG_SIZE_MASK) >> 17))
+/* 440GP External Bus Controller (EBC) */
+#define DCRN_EBC0_CFGADDR 0x012
+#define DCRN_EBC0_CFGDATA 0x013
+#define EBC_NUM_BANKS 8
+#define EBC_B0CR 0x00
+#define EBC_B1CR 0x01
+#define EBC_B2CR 0x02
+#define EBC_B3CR 0x03
+#define EBC_B4CR 0x04
+#define EBC_B5CR 0x05
+#define EBC_B6CR 0x06
+#define EBC_B7CR 0x07
+#define EBC_BXCR(n) (n)
+#define EBC_BXCR_BAS 0xfff00000
+#define EBC_BXCR_BS 0x000e0000
+#define EBC_BXCR_BANK_SIZE(reg) \
+ (0x100000 << (((reg) & EBC_BXCR_BS) >> 17))
+#define EBC_BXCR_BU 0x00018000
+#define EBC_BXCR_BU_OFF 0x00000000
+#define EBC_BXCR_BU_RO 0x00008000
+#define EBC_BXCR_BU_WO 0x00010000
+#define EBC_BXCR_BU_RW 0x00018000
+#define EBC_BXCR_BW 0x00006000
+#define EBC_B0AP 0x10
+#define EBC_B1AP 0x11
+#define EBC_B2AP 0x12
+#define EBC_B3AP 0x13
+#define EBC_B4AP 0x14
+#define EBC_B5AP 0x15
+#define EBC_B6AP 0x16
+#define EBC_B7AP 0x17
+#define EBC_BXAP(n) (0x10+(n))
+#define EBC_BEAR 0x20
+#define EBC_BESR 0x21
+#define EBC_CFG 0x23
+#define EBC_CID 0x24
+
/* 440GP Clock, PM, chip control */
#define DCRN_CPC0_SR 0x0b0
#define DCRN_CPC0_ER 0x0b1
diff --git a/arch/powerpc/boot/dts/ebony.dts b/arch/powerpc/boot/dts/ebony.dts
index 0ec02f4726b5..c5f99613fc7b 100644
--- a/arch/powerpc/boot/dts/ebony.dts
+++ b/arch/powerpc/boot/dts/ebony.dts
@@ -31,8 +31,8 @@
reg = <0>;
clock-frequency = <0>; // Filled in by zImage
timebase-frequency = <0>; // Filled in by zImage
- i-cache-line-size = <32>;
- d-cache-line-size = <32>;
+ i-cache-line-size = <20>;
+ d-cache-line-size = <20>;
i-cache-size = <8000>; /* 32 kB */
d-cache-size = <8000>; /* 32 kB */
dcr-controller;
@@ -135,11 +135,9 @@
#address-cells = <2>;
#size-cells = <1>;
clock-frequency = <0>; // Filled in by zImage
- ranges = <0 00000000 fff00000 100000
- 1 00000000 48000000 100000
- 2 00000000 ff800000 400000
- 3 00000000 48200000 100000
- 7 00000000 48300000 100000>;
+ // ranges property is supplied by zImage
+ // based on firmware's configuration of the
+ // EBC bridge
interrupts = <5 4>;
interrupt-parent = <&UIC1>;
diff --git a/arch/powerpc/boot/dts/holly.dts b/arch/powerpc/boot/dts/holly.dts
index 254499b107f4..80a4fab8ee37 100644
--- a/arch/powerpc/boot/dts/holly.dts
+++ b/arch/powerpc/boot/dts/holly.dts
@@ -46,7 +46,7 @@
tsi109@c0000000 {
device_type = "tsi-bridge";
- compatible = "tsi-bridge";
+ compatible = "tsi109-bridge", "tsi108-bridge";
#address-cells = <1>;
#size-cells = <1>;
ranges = <00000000 c0000000 00010000>;
@@ -54,52 +54,55 @@
i2c@7000 {
device_type = "i2c";
- compatible = "tsi-i2c";
- interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ compatible = "tsi109-i2c", "tsi108-i2c";
+ interrupt-parent = <&MPIC>;
interrupts = <e 2>;
reg = <7000 400>;
};
- mdio@6000 {
+ MDIO: mdio@6000 {
device_type = "mdio";
- compatible = "tsi-ethernet";
+ compatible = "tsi109-mdio", "tsi108-mdio";
+ reg = <6000 50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
- PHY1: ethernet-phy@6000 {
- device_type = "ethernet-phy";
- compatible = "bcm54xx";
- reg = <6000 50>;
- phy-id = <1>;
+ PHY1: ethernet-phy@1 {
+ compatible = "bcm5461a";
+ reg = <1>;
+ txc-rxc-delay-disable;
};
- PHY2: ethernet-phy@6400 {
- device_type = "ethernet-phy";
- compatible = "bcm54xx";
- reg = <6000 50>;
- phy-id = <2>;
+ PHY2: ethernet-phy@2 {
+ compatible = "bcm5461a";
+ reg = <2>;
+ txc-rxc-delay-disable;
};
};
ethernet@6200 {
device_type = "network";
- compatible = "tsi-ethernet";
+ compatible = "tsi109-ethernet", "tsi108-ethernet";
#address-cells = <1>;
#size-cells = <0>;
reg = <6000 200>;
local-mac-address = [ 00 00 00 00 00 00 ];
- interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupt-parent = <&MPIC>;
interrupts = <10 2>;
+ mdio-handle = <&MDIO>;
phy-handle = <&PHY1>;
};
ethernet@6600 {
device_type = "network";
- compatible = "tsi-ethernet";
+ compatible = "tsi109-ethernet", "tsi108-ethernet";
#address-cells = <1>;
#size-cells = <0>;
reg = <6400 200>;
local-mac-address = [ 00 00 00 00 00 00 ];
- interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupt-parent = <&MPIC>;
interrupts = <11 2>;
+ mdio-handle = <&MDIO>;
phy-handle = <&PHY2>;
};
@@ -110,7 +113,7 @@
virtual-reg = <c0007808>;
clock-frequency = <3F9C6000>;
current-speed = <1c200>;
- interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupt-parent = <&MPIC>;
interrupts = <c 2>;
};
@@ -121,7 +124,7 @@
virtual-reg = <c0007c08>;
clock-frequency = <3F9C6000>;
current-speed = <1c200>;
- interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupt-parent = <&MPIC>;
interrupts = <d 2>;
};
@@ -136,7 +139,7 @@
pci@1000 {
device_type = "pci";
- compatible = "tsi109";
+ compatible = "tsi109-pci", "tsi108-pci";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
@@ -150,7 +153,7 @@
ranges = <02000000 0 40000000 40000000 0 10000000
01000000 0 00000000 7e000000 0 00010000>;
clock-frequency = <7f28154>;
- interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupt-parent = <&MPIC>;
interrupts = <17 2>;
interrupt-map-mask = <f800 0 0 7>;
/*----------------------------------------------------+
@@ -186,13 +189,12 @@
#address-cells = <0>;
#interrupt-cells = <2>;
interrupts = <17 2>;
- interrupt-parent = < &/tsi109@c0000000/pic@7400 >;
+ interrupt-parent = <&MPIC>;
};
};
};
chosen {
linux,stdout-path = "/tsi109@c0000000/serial@7808";
- bootargs = "console=ttyS0,115200";
};
};
diff --git a/arch/powerpc/boot/dts/mpc7448hpc2.dts b/arch/powerpc/boot/dts/mpc7448hpc2.dts
index 765c306ecf80..0e3d314a7158 100644
--- a/arch/powerpc/boot/dts/mpc7448hpc2.dts
+++ b/arch/powerpc/boot/dts/mpc7448hpc2.dts
@@ -45,7 +45,7 @@
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
- device_type = "tsi-bridge";
+ device_type = "tsi108-bridge";
ranges = <00000000 c0000000 00010000>;
reg = <c0000000 00010000>;
bus-frequency = <0>;
@@ -55,27 +55,26 @@
interrupts = <E 0>;
reg = <7000 400>;
device_type = "i2c";
- compatible = "tsi-i2c";
+ compatible = "tsi108-i2c";
};
- mdio@6000 {
+ MDIO: mdio@6000 {
device_type = "mdio";
- compatible = "tsi-ethernet";
+ compatible = "tsi108-mdio";
+ reg = <6000 50>;
+ #address-cells = <1>;
+ #size-cells = <0>;
- phy8: ethernet-phy@6000 {
+ phy8: ethernet-phy@8 {
interrupt-parent = <&mpic>;
interrupts = <2 1>;
- reg = <6000 50>;
- phy-id = <8>;
- device_type = "ethernet-phy";
+ reg = <8>;
};
- phy9: ethernet-phy@6400 {
+ phy9: ethernet-phy@9 {
interrupt-parent = <&mpic>;
interrupts = <2 1>;
- reg = <6000 50>;
- phy-id = <9>;
- device_type = "ethernet-phy";
+ reg = <9>;
};
};
@@ -83,12 +82,12 @@
ethernet@6200 {
#size-cells = <0>;
device_type = "network";
- model = "TSI-ETH";
- compatible = "tsi-ethernet";
+ compatible = "tsi108-ethernet";
reg = <6000 200>;
address = [ 00 06 D2 00 00 01 ];
interrupts = <10 2>;
interrupt-parent = <&mpic>;
+ mdio-handle = <&MDIO>;
phy-handle = <&phy8>;
};
@@ -96,12 +95,12 @@
#address-cells = <1>;
#size-cells = <0>;
device_type = "network";
- model = "TSI-ETH";
- compatible = "tsi-ethernet";
+ compatible = "tsi108-ethernet";
reg = <6400 200>;
address = [ 00 06 D2 00 00 02 ];
interrupts = <11 2>;
interrupt-parent = <&mpic>;
+ mdio-handle = <&MDIO>;
phy-handle = <&phy9>;
};
@@ -135,7 +134,7 @@
big-endian;
};
pci@1000 {
- compatible = "tsi10x";
+ compatible = "tsi108-pci";
device_type = "pci";
#interrupt-cells = <1>;
#size-cells = <2>;
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
index 423eedcf634f..1934b800278e 100644
--- a/arch/powerpc/boot/dts/mpc8272ads.dts
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -14,12 +14,10 @@
compatible = "MPC8260ADS";
#address-cells = <1>;
#size-cells = <1>;
- linux,phandle = <100>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
- linux,phandle = <200>;
PowerPC,8272@0 {
device_type = "cpu";
@@ -32,12 +30,10 @@
bus-frequency = <0>;
clock-frequency = <0>;
32-bit;
- linux,phandle = <201>;
};
};
- interrupt-controller@f8200000 {
- linux,phandle = <f8200000>;
+ pci_pic: interrupt-controller@f8200000 {
#address-cells = <0>;
#interrupt-cells = <2>;
interrupt-controller;
@@ -47,15 +43,13 @@
};
memory {
device_type = "memory";
- linux,phandle = <300>;
reg = <00000000 4000000 f4500000 00000020>;
};
chosen {
name = "chosen";
linux,platform = <0>;
- interrupt-controller = <10c00>;
- linux,phandle = <400>;
+ interrupt-controller = <&Cpm_pic>;
};
soc8272@f0000000 {
@@ -70,20 +64,17 @@
device_type = "mdio";
compatible = "fs_enet";
reg = <0 0>;
- linux,phandle = <24520>;
#address-cells = <1>;
#size-cells = <0>;
- ethernet-phy@0 {
- linux,phandle = <2452000>;
- interrupt-parent = <10c00>;
+ phy0:ethernet-phy@0 {
+ interrupt-parent = <&Cpm_pic>;
interrupts = <17 4>;
reg = <0>;
bitbang = [ 12 12 13 02 02 01 ];
device_type = "ethernet-phy";
};
- ethernet-phy@1 {
- linux,phandle = <2452001>;
- interrupt-parent = <10c00>;
+ phy1:ethernet-phy@1 {
+ interrupt-parent = <&Cpm_pic>;
interrupts = <17 4>;
bitbang = [ 12 12 13 02 02 01 ];
reg = <3>;
@@ -101,8 +92,8 @@
reg = <11300 20 8400 100 11380 30>;
mac-address = [ 00 11 2F 99 43 54 ];
interrupts = <20 2>;
- interrupt-parent = <10c00>;
- phy-handle = <2452000>;
+ interrupt-parent = <&Cpm_pic>;
+ phy-handle = <&Phy0>;
rx-clock = <13>;
tx-clock = <12>;
};
@@ -115,14 +106,13 @@
reg = <11320 20 8500 100 113b0 30>;
mac-address = [ 00 11 2F 99 44 54 ];
interrupts = <21 2>;
- interrupt-parent = <10c00>;
- phy-handle = <2452001>;
+ interrupt-parent = <&Cpm_pic>;
+ phy-handle = <&Phy1>;
rx-clock = <17>;
tx-clock = <18>;
};
cpm@f0000000 {
- linux,phandle = <f0000000>;
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
@@ -142,7 +132,7 @@
reg = <11a00 20 8000 100>;
current-speed = <1c200>;
interrupts = <28 2>;
- interrupt-parent = <10c00>;
+ interrupt-parent = <&Cpm_pic>;
clock-setup = <0 00ffffff>;
rx-clock = <1>;
tx-clock = <1>;
@@ -156,15 +146,14 @@
reg = <11a60 20 8300 100>;
current-speed = <1c200>;
interrupts = <2b 2>;
- interrupt-parent = <10c00>;
+ interrupt-parent = <&Cpm_pic>;
clock-setup = <1b ffffff00>;
rx-clock = <4>;
tx-clock = <4>;
};
};
- interrupt-controller@10c00 {
- linux,phandle = <10c00>;
+ cpm_pic:interrupt-controller@10c00 {
#address-cells = <0>;
#interrupt-cells = <2>;
interrupt-controller;
@@ -174,7 +163,6 @@
compatible = "CPM2";
};
pci@0500 {
- linux,phandle = <0500>;
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
@@ -202,7 +190,7 @@
c000 0 0 2 f8200000 43 8
c000 0 0 3 f8200000 40 8
c000 0 0 4 f8200000 41 8>;
- interrupt-parent = <10c00>;
+ interrupt-parent = <&Cpm_pic>;
interrupts = <14 8>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 40000000
@@ -216,7 +204,7 @@
compatible = "talitos";
reg = <30000 10000>;
interrupts = <b 2>;
- interrupt-parent = <10c00>;
+ interrupt-parent = <&Cpm_pic>;
num-channels = <4>;
channel-fifo-len = <18>;
exec-units-mask = <0000007e>;
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 112dd5198fe2..4fc0c4d34aa8 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -272,7 +272,13 @@
reg = <2200 200>;
interrupts = <22>;
interrupt-parent = < &qeic >;
- mac-address = [ 00 04 9f 00 23 23 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <19>;
tx-clock = <1a>;
phy-handle = < &phy3 >;
@@ -287,7 +293,13 @@
reg = <3000 200>;
interrupts = <23>;
interrupt-parent = < &qeic >;
- mac-address = [ 00 11 22 33 44 55 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <17>;
tx-clock = <18>;
phy-handle = < &phy4 >;
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
index be4c35784e49..447c03ffabbc 100644
--- a/arch/powerpc/boot/dts/mpc832x_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -231,7 +231,13 @@
reg = <3000 200>;
interrupts = <21>;
interrupt-parent = <&qeic>;
- mac-address = [ 00 04 9f ef 03 02 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <20>;
tx-clock = <13>;
phy-handle = <&phy00>;
@@ -246,7 +252,13 @@
reg = <2200 200>;
interrupts = <22>;
interrupt-parent = <&qeic>;
- mac-address = [ 00 04 9f ef 03 01 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <19>;
tx-clock = <1a>;
phy-handle = <&phy04>;
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index db0d00303275..ae9bca575453 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -131,6 +131,11 @@
model = "TSEC";
compatible = "gianfar";
reg = <24000 1000>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
address = [ 00 00 00 00 00 00 ];
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <20 8 21 8 22 8>;
@@ -145,6 +150,11 @@
model = "TSEC";
compatible = "gianfar";
reg = <25000 1000>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
address = [ 00 00 00 00 00 00 ];
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <23 8 24 8 25 8>;
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index df773fafe9d1..310e877826b4 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -136,6 +136,11 @@
model = "TSEC";
compatible = "gianfar";
reg = <24000 1000>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
address = [ 00 00 00 00 00 00 ];
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <20 8 21 8 22 8>;
@@ -150,6 +155,11 @@
model = "TSEC";
compatible = "gianfar";
reg = <25000 1000>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
address = [ 00 00 00 00 00 00 ];
local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <23 8 24 8 25 8>;
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index 38c8594df3a4..1e914f31dd92 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -301,7 +301,13 @@
reg = <2000 200>;
interrupts = <20>;
interrupt-parent = < &qeic >;
- mac-address = [ 00 04 9f 00 23 23 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <0>;
tx-clock = <19>;
phy-handle = < &phy0 >;
@@ -317,7 +323,13 @@
reg = <3000 200>;
interrupts = <21>;
interrupt-parent = < &qeic >;
- mac-address = [ 00 11 22 33 44 55 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <0>;
tx-clock = <14>;
phy-handle = < &phy1 >;
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts
index d91e81c009f5..364a969f5c2f 100644
--- a/arch/powerpc/boot/dts/mpc8540ads.dts
+++ b/arch/powerpc/boot/dts/mpc8540ads.dts
@@ -52,7 +52,7 @@
compatible = "fsl,8540-memory-controller";
reg = <2000 1000>;
interrupt-parent = <&mpic>;
- interrupts = <2 2>;
+ interrupts = <12 2>;
};
l2-cache-controller@20000 {
@@ -61,14 +61,14 @@
cache-line-size = <20>; // 32 bytes
cache-size = <40000>; // L2, 256K
interrupt-parent = <&mpic>;
- interrupts = <0 2>;
+ interrupts = <10 2>;
};
i2c@3000 {
device_type = "i2c";
compatible = "fsl-i2c";
reg = <3000 100>;
- interrupts = <1b 2>;
+ interrupts = <2b 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
@@ -81,19 +81,19 @@
reg = <24520 20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <35 1>;
+ interrupts = <5 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <35 1>;
+ interrupts = <5 1>;
reg = <1>;
device_type = "ethernet-phy";
};
phy3: ethernet-phy@3 {
interrupt-parent = <&mpic>;
- interrupts = <37 1>;
+ interrupts = <7 1>;
reg = <3>;
device_type = "ethernet-phy";
};
@@ -106,9 +106,14 @@
model = "TSEC";
compatible = "gianfar";
reg = <24000 1000>;
- address = [ 00 E0 0C 00 73 00 ];
- local-mac-address = [ 00 E0 0C 00 73 00 ];
- interrupts = <d 2 e 2 12 2>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
};
@@ -120,9 +125,14 @@
model = "TSEC";
compatible = "gianfar";
reg = <25000 1000>;
- address = [ 00 E0 0C 00 73 01 ];
- local-mac-address = [ 00 E0 0C 00 73 01 ];
- interrupts = <13 2 14 2 18 2>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <23 2 24 2 28 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
};
@@ -134,9 +144,14 @@
model = "FEC";
compatible = "gianfar";
reg = <26000 1000>;
- address = [ 00 E0 0C 00 73 02 ];
- local-mac-address = [ 00 E0 0C 00 73 02 ];
- interrupts = <19 2>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <29 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy3>;
};
@@ -146,7 +161,7 @@
compatible = "ns16550";
reg = <4500 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -155,7 +170,7 @@
compatible = "ns16550";
reg = <4600 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
pci@8000 {
@@ -163,78 +178,78 @@
interrupt-map = <
/* IDSEL 0x02 */
- 1000 0 0 1 &mpic 31 1
- 1000 0 0 2 &mpic 32 1
- 1000 0 0 3 &mpic 33 1
- 1000 0 0 4 &mpic 34 1
+ 1000 0 0 1 &mpic 1 1
+ 1000 0 0 2 &mpic 2 1
+ 1000 0 0 3 &mpic 3 1
+ 1000 0 0 4 &mpic 4 1
/* IDSEL 0x03 */
- 1800 0 0 1 &mpic 34 1
- 1800 0 0 2 &mpic 31 1
- 1800 0 0 3 &mpic 32 1
- 1800 0 0 4 &mpic 33 1
+ 1800 0 0 1 &mpic 4 1
+ 1800 0 0 2 &mpic 1 1
+ 1800 0 0 3 &mpic 2 1
+ 1800 0 0 4 &mpic 3 1
/* IDSEL 0x04 */
- 2000 0 0 1 &mpic 33 1
- 2000 0 0 2 &mpic 34 1
- 2000 0 0 3 &mpic 31 1
- 2000 0 0 4 &mpic 32 1
+ 2000 0 0 1 &mpic 3 1
+ 2000 0 0 2 &mpic 4 1
+ 2000 0 0 3 &mpic 1 1
+ 2000 0 0 4 &mpic 2 1
/* IDSEL 0x05 */
- 2800 0 0 1 &mpic 32 1
- 2800 0 0 2 &mpic 33 1
- 2800 0 0 3 &mpic 34 1
- 2800 0 0 4 &mpic 31 1
+ 2800 0 0 1 &mpic 2 1
+ 2800 0 0 2 &mpic 3 1
+ 2800 0 0 3 &mpic 4 1
+ 2800 0 0 4 &mpic 1 1
/* IDSEL 0x0c */
- 6000 0 0 1 &mpic 31 1
- 6000 0 0 2 &mpic 32 1
- 6000 0 0 3 &mpic 33 1
- 6000 0 0 4 &mpic 34 1
+ 6000 0 0 1 &mpic 1 1
+ 6000 0 0 2 &mpic 2 1
+ 6000 0 0 3 &mpic 3 1
+ 6000 0 0 4 &mpic 4 1
/* IDSEL 0x0d */
- 6800 0 0 1 &mpic 34 1
- 6800 0 0 2 &mpic 31 1
- 6800 0 0 3 &mpic 32 1
- 6800 0 0 4 &mpic 33 1
+ 6800 0 0 1 &mpic 4 1
+ 6800 0 0 2 &mpic 1 1
+ 6800 0 0 3 &mpic 2 1
+ 6800 0 0 4 &mpic 3 1
/* IDSEL 0x0e */
- 7000 0 0 1 &mpic 33 1
- 7000 0 0 2 &mpic 34 1
- 7000 0 0 3 &mpic 31 1
- 7000 0 0 4 &mpic 32 1
+ 7000 0 0 1 &mpic 3 1
+ 7000 0 0 2 &mpic 4 1
+ 7000 0 0 3 &mpic 1 1
+ 7000 0 0 4 &mpic 2 1
/* IDSEL 0x0f */
- 7800 0 0 1 &mpic 32 1
- 7800 0 0 2 &mpic 33 1
- 7800 0 0 3 &mpic 34 1
- 7800 0 0 4 &mpic 31 1
+ 7800 0 0 1 &mpic 2 1
+ 7800 0 0 2 &mpic 3 1
+ 7800 0 0 3 &mpic 4 1
+ 7800 0 0 4 &mpic 1 1
/* IDSEL 0x12 */
- 9000 0 0 1 &mpic 31 1
- 9000 0 0 2 &mpic 32 1
- 9000 0 0 3 &mpic 33 1
- 9000 0 0 4 &mpic 34 1
+ 9000 0 0 1 &mpic 1 1
+ 9000 0 0 2 &mpic 2 1
+ 9000 0 0 3 &mpic 3 1
+ 9000 0 0 4 &mpic 4 1
/* IDSEL 0x13 */
- 9800 0 0 1 &mpic 34 1
- 9800 0 0 2 &mpic 31 1
- 9800 0 0 3 &mpic 32 1
- 9800 0 0 4 &mpic 33 1
+ 9800 0 0 1 &mpic 4 1
+ 9800 0 0 2 &mpic 1 1
+ 9800 0 0 3 &mpic 2 1
+ 9800 0 0 4 &mpic 3 1
/* IDSEL 0x14 */
- a000 0 0 1 &mpic 33 1
- a000 0 0 2 &mpic 34 1
- a000 0 0 3 &mpic 31 1
- a000 0 0 4 &mpic 32 1
+ a000 0 0 1 &mpic 3 1
+ a000 0 0 2 &mpic 4 1
+ a000 0 0 3 &mpic 1 1
+ a000 0 0 4 &mpic 2 1
/* IDSEL 0x15 */
- a800 0 0 1 &mpic 32 1
- a800 0 0 2 &mpic 33 1
- a800 0 0 3 &mpic 34 1
- a800 0 0 4 &mpic 31 1>;
+ a800 0 0 1 &mpic 2 1
+ a800 0 0 2 &mpic 3 1
+ a800 0 0 3 &mpic 4 1
+ a800 0 0 4 &mpic 1 1>;
interrupt-parent = <&mpic>;
- interrupts = <08 2>;
+ interrupts = <18 2>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e2000000 0 00100000>;
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts
index 4f2c3af2e052..070206fffe88 100644
--- a/arch/powerpc/boot/dts/mpc8541cds.dts
+++ b/arch/powerpc/boot/dts/mpc8541cds.dts
@@ -52,7 +52,7 @@
compatible = "fsl,8541-memory-controller";
reg = <2000 1000>;
interrupt-parent = <&mpic>;
- interrupts = <2 2>;
+ interrupts = <12 2>;
};
l2-cache-controller@20000 {
@@ -61,14 +61,14 @@
cache-line-size = <20>; // 32 bytes
cache-size = <40000>; // L2, 256K
interrupt-parent = <&mpic>;
- interrupts = <0 2>;
+ interrupts = <10 2>;
};
i2c@3000 {
device_type = "i2c";
compatible = "fsl-i2c";
reg = <3000 100>;
- interrupts = <1b 2>;
+ interrupts = <2b 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
@@ -81,13 +81,13 @@
reg = <24520 20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <1>;
device_type = "ethernet-phy";
};
@@ -100,8 +100,8 @@
model = "TSEC";
compatible = "gianfar";
reg = <24000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 00 ];
- interrupts = <d 2 e 2 12 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
};
@@ -113,8 +113,8 @@
model = "TSEC";
compatible = "gianfar";
reg = <25000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 01 ];
- interrupts = <13 2 14 2 18 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <23 2 24 2 28 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
};
@@ -124,7 +124,7 @@
compatible = "ns16550";
reg = <4500 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -133,7 +133,7 @@
compatible = "ns16550";
reg = <4600 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -142,49 +142,49 @@
interrupt-map = <
/* IDSEL 0x10 */
- 08000 0 0 1 &mpic 30 1
- 08000 0 0 2 &mpic 31 1
- 08000 0 0 3 &mpic 32 1
- 08000 0 0 4 &mpic 33 1
+ 08000 0 0 1 &mpic 0 1
+ 08000 0 0 2 &mpic 1 1
+ 08000 0 0 3 &mpic 2 1
+ 08000 0 0 4 &mpic 3 1
/* IDSEL 0x11 */
- 08800 0 0 1 &mpic 30 1
- 08800 0 0 2 &mpic 31 1
- 08800 0 0 3 &mpic 32 1
- 08800 0 0 4 &mpic 33 1
+ 08800 0 0 1 &mpic 0 1
+ 08800 0 0 2 &mpic 1 1
+ 08800 0 0 3 &mpic 2 1
+ 08800 0 0 4 &mpic 3 1
/* IDSEL 0x12 (Slot 1) */
- 09000 0 0 1 &mpic 30 1
- 09000 0 0 2 &mpic 31 1
- 09000 0 0 3 &mpic 32 1
- 09000 0 0 4 &mpic 33 1
+ 09000 0 0 1 &mpic 0 1
+ 09000 0 0 2 &mpic 1 1
+ 09000 0 0 3 &mpic 2 1
+ 09000 0 0 4 &mpic 3 1
/* IDSEL 0x13 (Slot 2) */
- 09800 0 0 1 &mpic 31 1
- 09800 0 0 2 &mpic 32 1
- 09800 0 0 3 &mpic 33 1
- 09800 0 0 4 &mpic 30 1
+ 09800 0 0 1 &mpic 1 1
+ 09800 0 0 2 &mpic 2 1
+ 09800 0 0 3 &mpic 3 1
+ 09800 0 0 4 &mpic 0 1
/* IDSEL 0x14 (Slot 3) */
- 0a000 0 0 1 &mpic 32 1
- 0a000 0 0 2 &mpic 33 1
- 0a000 0 0 3 &mpic 30 1
- 0a000 0 0 4 &mpic 31 1
+ 0a000 0 0 1 &mpic 2 1
+ 0a000 0 0 2 &mpic 3 1
+ 0a000 0 0 3 &mpic 0 1
+ 0a000 0 0 4 &mpic 1 1
/* IDSEL 0x15 (Slot 4) */
- 0a800 0 0 1 &mpic 33 1
- 0a800 0 0 2 &mpic 30 1
- 0a800 0 0 3 &mpic 31 1
- 0a800 0 0 4 &mpic 32 1
+ 0a800 0 0 1 &mpic 3 1
+ 0a800 0 0 2 &mpic 0 1
+ 0a800 0 0 3 &mpic 1 1
+ 0a800 0 0 4 &mpic 2 1
/* Bus 1 (Tundra Bridge) */
/* IDSEL 0x12 (ISA bridge) */
- 19000 0 0 1 &mpic 30 1
- 19000 0 0 2 &mpic 31 1
- 19000 0 0 3 &mpic 32 1
- 19000 0 0 4 &mpic 33 1>;
+ 19000 0 0 1 &mpic 0 1
+ 19000 0 0 2 &mpic 1 1
+ 19000 0 0 3 &mpic 2 1
+ 19000 0 0 4 &mpic 3 1>;
interrupt-parent = <&mpic>;
- interrupts = <08 2>;
+ interrupts = <18 2>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e2000000 0 00100000>;
@@ -216,12 +216,12 @@
interrupt-map = <
/* IDSEL 0x15 */
- a800 0 0 1 &mpic 3b 1
- a800 0 0 2 &mpic 3b 1
- a800 0 0 3 &mpic 3b 1
- a800 0 0 4 &mpic 3b 1>;
+ a800 0 0 1 &mpic b 1
+ a800 0 0 2 &mpic b 1
+ a800 0 0 3 &mpic b 1
+ a800 0 0 4 &mpic b 1>;
interrupt-parent = <&mpic>;
- interrupts = <09 2>;
+ interrupts = <19 2>;
bus-range = <0 0>;
ranges = <02000000 0 a0000000 a0000000 0 20000000
01000000 0 00000000 e3000000 0 00100000>;
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts
index 3033599e74e8..828592592460 100644
--- a/arch/powerpc/boot/dts/mpc8544ds.dts
+++ b/arch/powerpc/boot/dts/mpc8544ds.dts
@@ -52,7 +52,7 @@
compatible = "fsl,8544-memory-controller";
reg = <2000 1000>;
interrupt-parent = <&mpic>;
- interrupts = <2 2>;
+ interrupts = <12 2>;
};
l2-cache-controller@20000 {
@@ -61,14 +61,14 @@
cache-line-size = <20>; // 32 bytes
cache-size = <40000>; // L2, 256K
interrupt-parent = <&mpic>;
- interrupts = <0 2>;
+ interrupts = <10 2>;
};
i2c@3000 {
device_type = "i2c";
compatible = "fsl-i2c";
reg = <3000 100>;
- interrupts = <1b 2>;
+ interrupts = <2b 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
@@ -81,13 +81,13 @@
reg = <24520 20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <3a 1>;
+ interrupts = <a 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <3a 1>;
+ interrupts = <a 1>;
reg = <1>;
device_type = "ethernet-phy";
};
@@ -101,7 +101,7 @@
compatible = "gianfar";
reg = <24000 1000>;
local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <d 2 e 2 12 2>;
+ interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
};
@@ -114,7 +114,7 @@
compatible = "gianfar";
reg = <26000 1000>;
local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <f 2 10 2 11 2>;
+ interrupts = <1f 2 20 2 21 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
};
@@ -124,7 +124,7 @@
compatible = "ns16550";
reg = <4500 100>;
clock-frequency = <0>;
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -133,7 +133,7 @@
compatible = "ns16550";
reg = <4600 100>;
clock-frequency = <0>;
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index ad96381033c0..9d0b84b66cd4 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -52,7 +52,7 @@
compatible = "fsl,8548-memory-controller";
reg = <2000 1000>;
interrupt-parent = <&mpic>;
- interrupts = <2 2>;
+ interrupts = <12 2>;
};
l2-cache-controller@20000 {
@@ -61,14 +61,14 @@
cache-line-size = <20>; // 32 bytes
cache-size = <80000>; // L2, 512K
interrupt-parent = <&mpic>;
- interrupts = <0 2>;
+ interrupts = <10 2>;
};
i2c@3000 {
device_type = "i2c";
compatible = "fsl-i2c";
reg = <3000 100>;
- interrupts = <1b 2>;
+ interrupts = <2b 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
@@ -81,25 +81,25 @@
reg = <24520 20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <1>;
device_type = "ethernet-phy";
};
phy2: ethernet-phy@2 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <2>;
device_type = "ethernet-phy";
};
phy3: ethernet-phy@3 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <3>;
device_type = "ethernet-phy";
};
@@ -112,8 +112,8 @@
model = "eTSEC";
compatible = "gianfar";
reg = <24000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 00 ];
- interrupts = <d 2 e 2 12 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
};
@@ -125,8 +125,8 @@
model = "eTSEC";
compatible = "gianfar";
reg = <25000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 01 ];
- interrupts = <13 2 14 2 18 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <23 2 24 2 28 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
};
@@ -139,8 +139,8 @@
model = "eTSEC";
compatible = "gianfar";
reg = <26000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 02 ];
- interrupts = <f 2 10 2 11 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <1f 2 20 2 21 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy2>;
};
@@ -152,8 +152,8 @@
model = "eTSEC";
compatible = "gianfar";
reg = <27000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 03 ];
- interrupts = <15 2 16 2 17 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <25 2 26 2 27 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy3>;
};
@@ -164,7 +164,7 @@
compatible = "ns16550";
reg = <4500 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -173,58 +173,64 @@
compatible = "ns16550";
reg = <4600 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
+ global-utilities@e0000 { //global utilities reg
+ compatible = "fsl,mpc8548-guts";
+ reg = <e0000 1000>;
+ fsl,has-rstcr;
+ };
+
pci1: pci@8000 {
interrupt-map-mask = <1f800 0 0 7>;
interrupt-map = <
/* IDSEL 0x10 */
- 08000 0 0 1 &mpic 30 1
- 08000 0 0 2 &mpic 31 1
- 08000 0 0 3 &mpic 32 1
- 08000 0 0 4 &mpic 33 1
+ 08000 0 0 1 &mpic 0 1
+ 08000 0 0 2 &mpic 1 1
+ 08000 0 0 3 &mpic 2 1
+ 08000 0 0 4 &mpic 3 1
/* IDSEL 0x11 */
- 08800 0 0 1 &mpic 30 1
- 08800 0 0 2 &mpic 31 1
- 08800 0 0 3 &mpic 32 1
- 08800 0 0 4 &mpic 33 1
+ 08800 0 0 1 &mpic 0 1
+ 08800 0 0 2 &mpic 1 1
+ 08800 0 0 3 &mpic 2 1
+ 08800 0 0 4 &mpic 3 1
/* IDSEL 0x12 (Slot 1) */
- 09000 0 0 1 &mpic 30 1
- 09000 0 0 2 &mpic 31 1
- 09000 0 0 3 &mpic 32 1
- 09000 0 0 4 &mpic 33 1
+ 09000 0 0 1 &mpic 0 1
+ 09000 0 0 2 &mpic 1 1
+ 09000 0 0 3 &mpic 2 1
+ 09000 0 0 4 &mpic 3 1
/* IDSEL 0x13 (Slot 2) */
- 09800 0 0 1 &mpic 31 1
- 09800 0 0 2 &mpic 32 1
- 09800 0 0 3 &mpic 33 1
- 09800 0 0 4 &mpic 30 1
+ 09800 0 0 1 &mpic 1 1
+ 09800 0 0 2 &mpic 2 1
+ 09800 0 0 3 &mpic 3 1
+ 09800 0 0 4 &mpic 0 1
/* IDSEL 0x14 (Slot 3) */
- 0a000 0 0 1 &mpic 32 1
- 0a000 0 0 2 &mpic 33 1
- 0a000 0 0 3 &mpic 30 1
- 0a000 0 0 4 &mpic 31 1
+ 0a000 0 0 1 &mpic 2 1
+ 0a000 0 0 2 &mpic 3 1
+ 0a000 0 0 3 &mpic 0 1
+ 0a000 0 0 4 &mpic 1 1
/* IDSEL 0x15 (Slot 4) */
- 0a800 0 0 1 &mpic 33 1
- 0a800 0 0 2 &mpic 30 1
- 0a800 0 0 3 &mpic 31 1
- 0a800 0 0 4 &mpic 32 1
+ 0a800 0 0 1 &mpic 3 1
+ 0a800 0 0 2 &mpic 0 1
+ 0a800 0 0 3 &mpic 1 1
+ 0a800 0 0 4 &mpic 2 1
/* Bus 1 (Tundra Bridge) */
/* IDSEL 0x12 (ISA bridge) */
- 19000 0 0 1 &mpic 30 1
- 19000 0 0 2 &mpic 31 1
- 19000 0 0 3 &mpic 32 1
- 19000 0 0 4 &mpic 33 1>;
+ 19000 0 0 1 &mpic 0 1
+ 19000 0 0 2 &mpic 1 1
+ 19000 0 0 3 &mpic 2 1
+ 19000 0 0 4 &mpic 3 1>;
interrupt-parent = <&mpic>;
- interrupts = <08 2>;
+ interrupts = <18 2>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e2000000 0 00100000>;
@@ -256,12 +262,12 @@
interrupt-map = <
/* IDSEL 0x15 */
- a800 0 0 1 &mpic 3b 1
- a800 0 0 2 &mpic 3b 1
- a800 0 0 3 &mpic 3b 1
- a800 0 0 4 &mpic 3b 1>;
+ a800 0 0 1 &mpic b 1
+ a800 0 0 2 &mpic b 1
+ a800 0 0 3 &mpic b 1
+ a800 0 0 4 &mpic b 1>;
interrupt-parent = <&mpic>;
- interrupts = <09 2>;
+ interrupts = <19 2>;
bus-range = <0 0>;
ranges = <02000000 0 a0000000 a0000000 0 20000000
01000000 0 00000000 e3000000 0 00100000>;
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts
index 951ed92f1154..17e45d9a382a 100644
--- a/arch/powerpc/boot/dts/mpc8555cds.dts
+++ b/arch/powerpc/boot/dts/mpc8555cds.dts
@@ -52,7 +52,7 @@
compatible = "fsl,8555-memory-controller";
reg = <2000 1000>;
interrupt-parent = <&mpic>;
- interrupts = <2 2>;
+ interrupts = <12 2>;
};
l2-cache-controller@20000 {
@@ -61,14 +61,14 @@
cache-line-size = <20>; // 32 bytes
cache-size = <40000>; // L2, 256K
interrupt-parent = <&mpic>;
- interrupts = <0 2>;
+ interrupts = <10 2>;
};
i2c@3000 {
device_type = "i2c";
compatible = "fsl-i2c";
reg = <3000 100>;
- interrupts = <1b 2>;
+ interrupts = <2b 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
@@ -81,13 +81,13 @@
reg = <24520 20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <35 0>;
+ interrupts = <5 1>;
reg = <1>;
device_type = "ethernet-phy";
};
@@ -100,8 +100,8 @@
model = "TSEC";
compatible = "gianfar";
reg = <24000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 00 ];
- interrupts = <0d 2 0e 2 12 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
};
@@ -113,8 +113,8 @@
model = "TSEC";
compatible = "gianfar";
reg = <25000 1000>;
- local-mac-address = [ 00 E0 0C 00 73 01 ];
- interrupts = <13 2 14 2 18 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <23 2 24 2 28 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
};
@@ -124,7 +124,7 @@
compatible = "ns16550";
reg = <4500 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -133,7 +133,7 @@
compatible = "ns16550";
reg = <4600 100>; // reg base, size
clock-frequency = <0>; // should we fill in in uboot?
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -142,49 +142,49 @@
interrupt-map = <
/* IDSEL 0x10 */
- 08000 0 0 1 &mpic 30 1
- 08000 0 0 2 &mpic 31 1
- 08000 0 0 3 &mpic 32 1
- 08000 0 0 4 &mpic 33 1
+ 08000 0 0 1 &mpic 0 1
+ 08000 0 0 2 &mpic 1 1
+ 08000 0 0 3 &mpic 2 1
+ 08000 0 0 4 &mpic 3 1
/* IDSEL 0x11 */
- 08800 0 0 1 &mpic 30 1
- 08800 0 0 2 &mpic 31 1
- 08800 0 0 3 &mpic 32 1
- 08800 0 0 4 &mpic 33 1
+ 08800 0 0 1 &mpic 0 1
+ 08800 0 0 2 &mpic 1 1
+ 08800 0 0 3 &mpic 2 1
+ 08800 0 0 4 &mpic 3 1
/* IDSEL 0x12 (Slot 1) */
- 09000 0 0 1 &mpic 30 1
- 09000 0 0 2 &mpic 31 1
- 09000 0 0 3 &mpic 32 1
- 09000 0 0 4 &mpic 33 1
+ 09000 0 0 1 &mpic 0 1
+ 09000 0 0 2 &mpic 1 1
+ 09000 0 0 3 &mpic 2 1
+ 09000 0 0 4 &mpic 3 1
/* IDSEL 0x13 (Slot 2) */
- 09800 0 0 1 &mpic 31 1
- 09800 0 0 2 &mpic 32 1
- 09800 0 0 3 &mpic 33 1
- 09800 0 0 4 &mpic 30 1
+ 09800 0 0 1 &mpic 1 1
+ 09800 0 0 2 &mpic 2 1
+ 09800 0 0 3 &mpic 3 1
+ 09800 0 0 4 &mpic 0 1
/* IDSEL 0x14 (Slot 3) */
- 0a000 0 0 1 &mpic 32 1
- 0a000 0 0 2 &mpic 33 1
- 0a000 0 0 3 &mpic 30 1
- 0a000 0 0 4 &mpic 31 1
+ 0a000 0 0 1 &mpic 2 1
+ 0a000 0 0 2 &mpic 3 1
+ 0a000 0 0 3 &mpic 0 1
+ 0a000 0 0 4 &mpic 1 1
/* IDSEL 0x15 (Slot 4) */
- 0a800 0 0 1 &mpic 33 1
- 0a800 0 0 2 &mpic 30 1
- 0a800 0 0 3 &mpic 31 1
- 0a800 0 0 4 &mpic 32 1
+ 0a800 0 0 1 &mpic 3 1
+ 0a800 0 0 2 &mpic 0 1
+ 0a800 0 0 3 &mpic 1 1
+ 0a800 0 0 4 &mpic 2 1
/* Bus 1 (Tundra Bridge) */
/* IDSEL 0x12 (ISA bridge) */
- 19000 0 0 1 &mpic 30 1
- 19000 0 0 2 &mpic 31 1
- 19000 0 0 3 &mpic 32 1
- 19000 0 0 4 &mpic 33 1>;
+ 19000 0 0 1 &mpic 0 1
+ 19000 0 0 2 &mpic 1 1
+ 19000 0 0 3 &mpic 2 1
+ 19000 0 0 4 &mpic 3 1>;
interrupt-parent = <&mpic>;
- interrupts = <08 2>;
+ interrupts = <18 2>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e2000000 0 00100000>;
@@ -216,12 +216,12 @@
interrupt-map = <
/* IDSEL 0x15 */
- a800 0 0 1 &mpic 3b 1
- a800 0 0 2 &mpic 3b 1
- a800 0 0 3 &mpic 3b 1
- a800 0 0 4 &mpic 3b 1>;
+ a800 0 0 1 &mpic b 1
+ a800 0 0 2 &mpic b 1
+ a800 0 0 3 &mpic b 1
+ a800 0 0 4 &mpic b 1>;
interrupt-parent = <&mpic>;
- interrupts = <09 2>;
+ interrupts = <19 2>;
bus-range = <0 0>;
ranges = <02000000 0 a0000000 a0000000 0 20000000
01000000 0 00000000 e3000000 0 00100000>;
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
index 80682152b0cf..21ccaaa27993 100644
--- a/arch/powerpc/boot/dts/mpc8560ads.dts
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -52,7 +52,7 @@
compatible = "fsl,8540-memory-controller";
reg = <2000 1000>;
interrupt-parent = <&mpic>;
- interrupts = <2 2>;
+ interrupts = <12 2>;
};
l2-cache-controller@20000 {
@@ -61,7 +61,7 @@
cache-line-size = <20>; // 32 bytes
cache-size = <40000>; // L2, 256K
interrupt-parent = <&mpic>;
- interrupts = <0 2>;
+ interrupts = <10 2>;
};
mdio@24520 {
@@ -72,25 +72,25 @@
#size-cells = <0>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <35 1>;
+ interrupts = <5 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <35 1>;
+ interrupts = <5 1>;
reg = <1>;
device_type = "ethernet-phy";
};
phy2: ethernet-phy@2 {
interrupt-parent = <&mpic>;
- interrupts = <37 1>;
+ interrupts = <7 1>;
reg = <2>;
device_type = "ethernet-phy";
};
phy3: ethernet-phy@3 {
interrupt-parent = <&mpic>;
- interrupts = <37 1>;
+ interrupts = <7 1>;
reg = <3>;
device_type = "ethernet-phy";
};
@@ -101,8 +101,14 @@
model = "TSEC";
compatible = "gianfar";
reg = <24000 1000>;
- address = [ 00 00 0C 00 00 FD ];
- interrupts = <d 2 e 2 12 2>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
};
@@ -114,8 +120,14 @@
model = "TSEC";
compatible = "gianfar";
reg = <25000 1000>;
- address = [ 00 00 0C 00 01 FD ];
- interrupts = <13 2 14 2 18 2>;
+ /*
+ * address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <23 2 24 2 28 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
};
@@ -132,79 +144,79 @@
interrupt-map = <
/* IDSEL 0x2 */
- 1000 0 0 1 &mpic 31 1
- 1000 0 0 2 &mpic 32 1
- 1000 0 0 3 &mpic 33 1
- 1000 0 0 4 &mpic 34 1
+ 1000 0 0 1 &mpic 1 1
+ 1000 0 0 2 &mpic 2 1
+ 1000 0 0 3 &mpic 3 1
+ 1000 0 0 4 &mpic 4 1
/* IDSEL 0x3 */
- 1800 0 0 1 &mpic 34 1
- 1800 0 0 2 &mpic 31 1
- 1800 0 0 3 &mpic 32 1
- 1800 0 0 4 &mpic 33 1
+ 1800 0 0 1 &mpic 4 1
+ 1800 0 0 2 &mpic 1 1
+ 1800 0 0 3 &mpic 2 1
+ 1800 0 0 4 &mpic 3 1
/* IDSEL 0x4 */
- 2000 0 0 1 &mpic 33 1
- 2000 0 0 2 &mpic 34 1
- 2000 0 0 3 &mpic 31 1
- 2000 0 0 4 &mpic 32 1
+ 2000 0 0 1 &mpic 3 1
+ 2000 0 0 2 &mpic 4 1
+ 2000 0 0 3 &mpic 1 1
+ 2000 0 0 4 &mpic 2 1
/* IDSEL 0x5 */
- 2800 0 0 1 &mpic 32 1
- 2800 0 0 2 &mpic 33 1
- 2800 0 0 3 &mpic 34 1
- 2800 0 0 4 &mpic 31 1
+ 2800 0 0 1 &mpic 2 1
+ 2800 0 0 2 &mpic 3 1
+ 2800 0 0 3 &mpic 4 1
+ 2800 0 0 4 &mpic 1 1
/* IDSEL 12 */
- 6000 0 0 1 &mpic 31 1
- 6000 0 0 2 &mpic 32 1
- 6000 0 0 3 &mpic 33 1
- 6000 0 0 4 &mpic 34 1
+ 6000 0 0 1 &mpic 1 1
+ 6000 0 0 2 &mpic 2 1
+ 6000 0 0 3 &mpic 3 1
+ 6000 0 0 4 &mpic 4 1
/* IDSEL 13 */
- 6800 0 0 1 &mpic 34 1
- 6800 0 0 2 &mpic 31 1
- 6800 0 0 3 &mpic 32 1
- 6800 0 0 4 &mpic 33 1
+ 6800 0 0 1 &mpic 4 1
+ 6800 0 0 2 &mpic 1 1
+ 6800 0 0 3 &mpic 2 1
+ 6800 0 0 4 &mpic 3 1
/* IDSEL 14*/
- 7000 0 0 1 &mpic 33 1
- 7000 0 0 2 &mpic 34 1
- 7000 0 0 3 &mpic 31 1
- 7000 0 0 4 &mpic 32 1
+ 7000 0 0 1 &mpic 3 1
+ 7000 0 0 2 &mpic 4 1
+ 7000 0 0 3 &mpic 1 1
+ 7000 0 0 4 &mpic 2 1
/* IDSEL 15 */
- 7800 0 0 1 &mpic 32 1
- 7800 0 0 2 &mpic 33 1
- 7800 0 0 3 &mpic 34 1
- 7800 0 0 4 &mpic 31 1
+ 7800 0 0 1 &mpic 2 1
+ 7800 0 0 2 &mpic 3 1
+ 7800 0 0 3 &mpic 4 1
+ 7800 0 0 4 &mpic 1 1
/* IDSEL 18 */
- 9000 0 0 1 &mpic 31 1
- 9000 0 0 2 &mpic 32 1
- 9000 0 0 3 &mpic 33 1
- 9000 0 0 4 &mpic 34 1
+ 9000 0 0 1 &mpic 1 1
+ 9000 0 0 2 &mpic 2 1
+ 9000 0 0 3 &mpic 3 1
+ 9000 0 0 4 &mpic 4 1
/* IDSEL 19 */
- 9800 0 0 1 &mpic 34 1
- 9800 0 0 2 &mpic 31 1
- 9800 0 0 3 &mpic 32 1
- 9800 0 0 4 &mpic 33 1
+ 9800 0 0 1 &mpic 4 1
+ 9800 0 0 2 &mpic 1 1
+ 9800 0 0 3 &mpic 2 1
+ 9800 0 0 4 &mpic 3 1
/* IDSEL 20 */
- a000 0 0 1 &mpic 33 1
- a000 0 0 2 &mpic 34 1
- a000 0 0 3 &mpic 31 1
- a000 0 0 4 &mpic 32 1
+ a000 0 0 1 &mpic 3 1
+ a000 0 0 2 &mpic 4 1
+ a000 0 0 3 &mpic 1 1
+ a000 0 0 4 &mpic 2 1
/* IDSEL 21 */
- a800 0 0 1 &mpic 32 1
- a800 0 0 2 &mpic 33 1
- a800 0 0 3 &mpic 34 1
- a800 0 0 4 &mpic 31 1>;
+ a800 0 0 1 &mpic 2 1
+ a800 0 0 2 &mpic 3 1
+ a800 0 0 3 &mpic 4 1
+ a800 0 0 4 &mpic 1 1>;
interrupt-parent = <&mpic>;
- interrupts = <8 0>;
+ interrupts = <18 2>;
bus-range = <0 0>;
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e2000000 0 01000000>;
@@ -234,7 +246,7 @@
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
- interrupts = <1e 0>;
+ interrupts = <2e 2>;
interrupt-parent = <&mpic>;
reg = <90c00 80>;
built-in;
@@ -275,7 +287,13 @@
model = "FCC";
device-id = <2>;
reg = <91320 20 88500 100 913a0 30>;
- mac-address = [ 00 00 0C 00 02 FD ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
clock-setup = <ff00ffff 250000>;
rx-clock = <15>;
tx-clock = <16>;
@@ -290,7 +308,13 @@
model = "FCC";
device-id = <3>;
reg = <91340 20 88600 100 913d0 30>;
- mac-address = [ 00 00 0C 00 03 FD ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
clock-setup = <ffff00ff 3700>;
rx-clock = <17>;
tx-clock = <18>;
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts
index a123ec9456bc..6bb18f2807a8 100644
--- a/arch/powerpc/boot/dts/mpc8568mds.dts
+++ b/arch/powerpc/boot/dts/mpc8568mds.dts
@@ -61,7 +61,7 @@
compatible = "fsl,8568-memory-controller";
reg = <2000 1000>;
interrupt-parent = <&mpic>;
- interrupts = <2 2>;
+ interrupts = <12 2>;
};
l2-cache-controller@20000 {
@@ -70,14 +70,14 @@
cache-line-size = <20>; // 32 bytes
cache-size = <80000>; // L2, 512K
interrupt-parent = <&mpic>;
- interrupts = <0 2>;
+ interrupts = <10 2>;
};
i2c@3000 {
device_type = "i2c";
compatible = "fsl-i2c";
reg = <3000 100>;
- interrupts = <1b 2>;
+ interrupts = <2b 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
@@ -86,7 +86,7 @@
device_type = "i2c";
compatible = "fsl-i2c";
reg = <3100 100>;
- interrupts = <1b 2>;
+ interrupts = <2b 2>;
interrupt-parent = <&mpic>;
dfsrr;
};
@@ -99,25 +99,25 @@
reg = <24520 20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <31 1>;
+ interrupts = <1 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <32 1>;
+ interrupts = <2 1>;
reg = <1>;
device_type = "ethernet-phy";
};
phy2: ethernet-phy@2 {
interrupt-parent = <&mpic>;
- interrupts = <31 1>;
+ interrupts = <1 1>;
reg = <2>;
device_type = "ethernet-phy";
};
phy3: ethernet-phy@3 {
interrupt-parent = <&mpic>;
- interrupts = <32 1>;
+ interrupts = <2 1>;
reg = <3>;
device_type = "ethernet-phy";
};
@@ -130,8 +130,14 @@
model = "eTSEC";
compatible = "gianfar";
reg = <24000 1000>;
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <d 2 e 2 12 2>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy2>;
};
@@ -143,8 +149,14 @@
model = "eTSEC";
compatible = "gianfar";
reg = <25000 1000>;
- mac-address = [ 00 00 00 00 00 00];
- interrupts = <13 2 14 2 18 2>;
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <23 2 24 2 28 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy3>;
};
@@ -154,7 +166,7 @@
compatible = "ns16550";
reg = <4500 100>;
clock-frequency = <0>;
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -163,7 +175,7 @@
compatible = "ns16550";
reg = <4600 100>;
clock-frequency = <0>;
- interrupts = <1a 2>;
+ interrupts = <2a 2>;
interrupt-parent = <&mpic>;
};
@@ -172,7 +184,7 @@
model = "SEC2";
compatible = "talitos";
reg = <30000 f000>;
- interrupts = <1d 2>;
+ interrupts = <2d 2>;
interrupt-parent = <&mpic>;
num-channels = <4>;
channel-fifo-len = <18>;
@@ -300,7 +312,13 @@
reg = <2000 200>;
interrupts = <20>;
interrupt-parent = <&qeic>;
- mac-address = [ 00 04 9f 00 23 23 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <0>;
tx-clock = <19>;
phy-handle = <&qe_phy0>;
@@ -316,7 +334,13 @@
reg = <3000 200>;
interrupts = <21>;
interrupt-parent = <&qeic>;
- mac-address = [ 00 11 22 33 44 55 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
rx-clock = <0>;
tx-clock = <14>;
phy-handle = <&qe_phy1>;
@@ -335,25 +359,25 @@
* gianfar's MDIO bus */
qe_phy0: ethernet-phy@00 {
interrupt-parent = <&mpic>;
- interrupts = <31 1>;
+ interrupts = <1 1>;
reg = <0>;
device_type = "ethernet-phy";
};
qe_phy1: ethernet-phy@01 {
interrupt-parent = <&mpic>;
- interrupts = <32 1>;
+ interrupts = <2 1>;
reg = <1>;
device_type = "ethernet-phy";
};
qe_phy2: ethernet-phy@02 {
interrupt-parent = <&mpic>;
- interrupts = <31 1>;
+ interrupts = <1 1>;
reg = <2>;
device_type = "ethernet-phy";
};
qe_phy3: ethernet-phy@03 {
interrupt-parent = <&mpic>;
- interrupts = <32 1>;
+ interrupts = <2 1>;
reg = <3>;
device_type = "ethernet-phy";
};
@@ -367,7 +391,7 @@
reg = <80 80>;
built-in;
big-endian;
- interrupts = <1e 2 1e 2>; //high:30 low:30
+ interrupts = <2e 2 2e 2>; //high:30 low:30
interrupt-parent = <&mpic>;
};
diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
index 260b264c869e..6a78a2b37c08 100644
--- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts
+++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts
@@ -56,8 +56,12 @@
#size-cells = <1>;
#interrupt-cells = <2>;
device_type = "soc";
- ranges = <0 f8000000 00100000>;
- reg = <f8000000 00100000>; // CCSRBAR 1M
+ ranges = <00001000 f8001000 000ff000
+ 80000000 80000000 20000000
+ e2000000 e2000000 00100000
+ a0000000 a0000000 20000000
+ e3000000 e3000000 00100000>;
+ reg = <f8000000 00001000>; // CCSRBAR
bus-frequency = <0>;
i2c@3000 {
@@ -86,25 +90,25 @@
reg = <24520 20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <4a 1>;
+ interrupts = <a 1>;
reg = <0>;
device_type = "ethernet-phy";
};
phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <4a 1>;
+ interrupts = <a 1>;
reg = <1>;
device_type = "ethernet-phy";
};
phy2: ethernet-phy@2 {
interrupt-parent = <&mpic>;
- interrupts = <4a 1>;
+ interrupts = <a 1>;
reg = <2>;
device_type = "ethernet-phy";
};
phy3: ethernet-phy@3 {
interrupt-parent = <&mpic>;
- interrupts = <4a 1>;
+ interrupts = <a 1>;
reg = <3>;
device_type = "ethernet-phy";
};
@@ -117,10 +121,17 @@
model = "TSEC";
compatible = "gianfar";
reg = <24000 1000>;
- mac-address = [ 00 E0 0C 00 73 00 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <1d 2 1e 2 22 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
+ phy-connection-type = "rgmii-id";
};
ethernet@25000 {
@@ -130,10 +141,17 @@
model = "TSEC";
compatible = "gianfar";
reg = <25000 1000>;
- mac-address = [ 00 E0 0C 00 73 01 ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <23 2 24 2 28 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
+ phy-connection-type = "rgmii-id";
};
ethernet@26000 {
@@ -143,10 +161,17 @@
model = "TSEC";
compatible = "gianfar";
reg = <26000 1000>;
- mac-address = [ 00 E0 0C 00 02 FD ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <1F 2 20 2 21 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy2>;
+ phy-connection-type = "rgmii-id";
};
ethernet@27000 {
@@ -156,10 +181,17 @@
model = "TSEC";
compatible = "gianfar";
reg = <27000 1000>;
- mac-address = [ 00 E0 0C 00 03 FD ];
+ /*
+ * mac-address is deprecated and will be removed
+ * in 2.6.25. Only recent versions of
+ * U-Boot support local-mac-address, however.
+ */
+ mac-address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
interrupts = <25 2 26 2 27 2>;
interrupt-parent = <&mpic>;
phy-handle = <&phy3>;
+ phy-connection-type = "rgmii-id";
};
serial@4500 {
device_type = "serial";
@@ -186,7 +218,7 @@
#size-cells = <2>;
#address-cells = <3>;
reg = <8000 1000>;
- bus-range = <0 fe>;
+ bus-range = <0 ff>;
ranges = <02000000 0 80000000 80000000 0 20000000
01000000 0 00000000 e2000000 0 00100000>;
clock-frequency = <1fca055>;
@@ -285,17 +317,84 @@
f800 0 0 3 &i8259 0 0
f800 0 0 4 &i8259 0 0
>;
- i8259: i8259@4d0 {
- clock-frequency = <0>;
- interrupt-controller;
- device_type = "interrupt-controller";
- #address-cells = <0>;
- #interrupt-cells = <2>;
- built-in;
- compatible = "chrp,iic";
- big-endian;
- interrupts = <49 2>;
- interrupt-parent = <&mpic>;
+ uli1575@0 {
+ reg = <0 0 0 0 0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ ranges = <02000000 0 80000000
+ 02000000 0 80000000
+ 0 20000000
+ 01000000 0 00000000
+ 01000000 0 00000000
+ 0 00100000>;
+
+ pci_bridge@0 {
+ reg = <0 0 0 0 0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ ranges = <02000000 0 80000000
+ 02000000 0 80000000
+ 0 20000000
+ 01000000 0 00000000
+ 01000000 0 00000000
+ 0 00100000>;
+
+ isa@1e {
+ device_type = "isa";
+ #interrupt-cells = <2>;
+ #size-cells = <1>;
+ #address-cells = <2>;
+ reg = <f000 0 0 0 0>;
+ ranges = <1 0 01000000 0 0
+ 00001000>;
+ interrupt-parent = <&i8259>;
+
+ i8259: interrupt-controller@20 {
+ reg = <1 20 2
+ 1 a0 2
+ 1 4d0 2>;
+ clock-frequency = <0>;
+ interrupt-controller;
+ device_type = "interrupt-controller";
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ built-in;
+ compatible = "chrp,iic";
+ interrupts = <9 2>;
+ interrupt-parent =
+ <&mpic>;
+ };
+
+ i8042@60 {
+ #size-cells = <0>;
+ #address-cells = <1>;
+ reg = <1 60 1 1 64 1>;
+ interrupts = <1 3 c 3>;
+ interrupt-parent =
+ <&i8259>;
+
+ keyboard@0 {
+ reg = <0>;
+ compatible = "pnpPNP,303";
+ };
+
+ mouse@1 {
+ reg = <1>;
+ compatible = "pnpPNP,f03";
+ };
+ };
+
+ rtc@70 {
+ compatible =
+ "pnpPNP,b00";
+ reg = <1 70 2>;
+ };
+
+ gpio@400 {
+ reg = <1 400 80>;
+ };
+ };
+ };
};
};
@@ -316,10 +415,10 @@
interrupt-map-mask = <f800 0 0 7>;
interrupt-map = <
/* IDSEL 0x0 */
- 0000 0 0 1 &mpic 44 1
- 0000 0 0 2 &mpic 45 1
- 0000 0 0 3 &mpic 46 1
- 0000 0 0 4 &mpic 47 1
+ 0000 0 0 1 &mpic 4 1
+ 0000 0 0 2 &mpic 5 1
+ 0000 0 0 3 &mpic 6 1
+ 0000 0 0 4 &mpic 7 1
>;
};
diff --git a/arch/powerpc/boot/dts/mpc866ads.dts b/arch/powerpc/boot/dts/mpc866ads.dts
index c0d06fd12927..e5e7726ddb03 100644
--- a/arch/powerpc/boot/dts/mpc866ads.dts
+++ b/arch/powerpc/boot/dts/mpc866ads.dts
@@ -15,12 +15,10 @@
compatible = "mpc8xx";
#address-cells = <1>;
#size-cells = <1>;
- linux,phandle = <100>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
- linux,phandle = <200>;
PowerPC,866@0 {
device_type = "cpu";
@@ -34,14 +32,12 @@
clock-frequency = <0>;
32-bit;
interrupts = <f 2>; // decrementer interrupt
- interrupt-parent = <ff000000>;
- linux,phandle = <201>;
+ interrupt-parent = <&Mpc8xx_pic>;
};
};
memory {
device_type = "memory";
- linux,phandle = <300>;
reg = <00000000 800000>;
};
@@ -57,11 +53,9 @@
device_type = "mdio";
compatible = "fs_enet";
reg = <e80 8>;
- linux,phandle = <e80>;
#address-cells = <1>;
#size-cells = <0>;
- ethernet-phy@f {
- linux,phandle = <e800f>;
+ phy: ethernet-phy@f {
reg = <f>;
device_type = "ethernet-phy";
};
@@ -75,12 +69,11 @@
reg = <e00 188>;
mac-address = [ 00 00 0C 00 01 FD ];
interrupts = <3 1>;
- interrupt-parent = <ff000000>;
- phy-handle = <e800f>;
+ interrupt-parent = <&Mpc8xx_pic>;
+ phy-handle = <&Phy>;
};
- pic@ff000000 {
- linux,phandle = <ff000000>;
+ mpc8xx_pic: pic@ff000000 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
@@ -91,7 +84,6 @@
};
cpm@ff000000 {
- linux,phandle = <ff000000>;
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
@@ -102,15 +94,14 @@
command-proc = <9c0>;
brg-frequency = <0>;
interrupts = <0 2>; // cpm error interrupt
- interrupt-parent = <930>;
+ interrupt-parent = <&Cpm_pic>;
- pic@930 {
- linux,phandle = <930>;
+ cpm_pic: pic@930 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
interrupts = <5 2 0 2>;
- interrupt-parent = <ff000000>;
+ interrupt-parent = <&Mpc8xx_pic>;
reg = <930 20>;
built-in;
device_type = "cpm-pic";
@@ -128,7 +119,7 @@
tx-clock = <1>;
current-speed = <0>;
interrupts = <4 3>;
- interrupt-parent = <930>;
+ interrupt-parent = <&Cpm_pic>;
};
smc@a90 {
@@ -142,7 +133,7 @@
tx-clock = <2>;
current-speed = <0>;
interrupts = <3 3>;
- interrupt-parent = <930>;
+ interrupt-parent = <&Cpm_pic>;
};
scc@a00 {
@@ -153,7 +144,7 @@
reg = <a00 18 3c00 80>;
mac-address = [ 00 00 0C 00 03 FD ];
interrupts = <1e 3>;
- interrupt-parent = <930>;
+ interrupt-parent = <&Cpm_pic>;
};
};
};
diff --git a/arch/powerpc/boot/dts/mpc885ads.dts b/arch/powerpc/boot/dts/mpc885ads.dts
index 110bf6170603..dc7ab9c80611 100644
--- a/arch/powerpc/boot/dts/mpc885ads.dts
+++ b/arch/powerpc/boot/dts/mpc885ads.dts
@@ -15,12 +15,10 @@
compatible = "mpc8xx";
#address-cells = <1>;
#size-cells = <1>;
- linux,phandle = <100>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
- linux,phandle = <200>;
PowerPC,885@0 {
device_type = "cpu";
@@ -34,14 +32,12 @@
clock-frequency = <0>;
32-bit;
interrupts = <f 2>; // decrementer interrupt
- interrupt-parent = <ff000000>;
- linux,phandle = <201>;
+ interrupt-parent = <&Mpc8xx_pic>;
};
};
memory {
device_type = "memory";
- linux,phandle = <300>;
reg = <00000000 800000>;
};
@@ -57,21 +53,17 @@
device_type = "mdio";
compatible = "fs_enet";
reg = <e80 8>;
- linux,phandle = <e80>;
#address-cells = <1>;
#size-cells = <0>;
- ethernet-phy@0 {
- linux,phandle = <e8000>;
+ Phy0: ethernet-phy@0 {
reg = <0>;
device_type = "ethernet-phy";
};
- ethernet-phy@1 {
- linux,phandle = <e8001>;
+ Phy1: ethernet-phy@1 {
reg = <1>;
device_type = "ethernet-phy";
};
- ethernet-phy@2 {
- linux,phandle = <e8002>;
+ Phy2: ethernet-phy@2 {
reg = <2>;
device_type = "ethernet-phy";
};
@@ -85,8 +77,8 @@
reg = <e00 188>;
mac-address = [ 00 00 0C 00 01 FD ];
interrupts = <3 1>;
- interrupt-parent = <ff000000>;
- phy-handle = <e8000>;
+ interrupt-parent = <&Mpc8xx_pic>;
+ phy-handle = <&Phy1>;
};
fec@1e00 {
@@ -97,12 +89,11 @@
reg = <1e00 188>;
mac-address = [ 00 00 0C 00 02 FD ];
interrupts = <7 1>;
- interrupt-parent = <ff000000>;
- phy-handle = <e8001>;
+ interrupt-parent = <&Mpc8xx_pic>;
+ phy-handle = <&Phy2>;
};
- pic@ff000000 {
- linux,phandle = <ff000000>;
+ Mpc8xx_pic: pic@ff000000 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
@@ -112,8 +103,18 @@
compatible = "CPM";
};
+ pcmcia@0080 {
+ #address-cells = <3>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ compatible = "fsl,pq-pcmcia";
+ device_type = "pcmcia";
+ reg = <80 80>;
+ interrupt-parent = <&Mpc8xx_pic>;
+ interrupts = <d 1>;
+ };
+
cpm@ff000000 {
- linux,phandle = <ff000000>;
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
@@ -124,15 +125,14 @@
command-proc = <9c0>;
brg-frequency = <0>;
interrupts = <0 2>; // cpm error interrupt
- interrupt-parent = <930>;
+ interrupt-parent = <&Cpm_pic>;
- pic@930 {
- linux,phandle = <930>;
+ Cpm_pic: pic@930 {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <2>;
interrupts = <5 2 0 2>;
- interrupt-parent = <ff000000>;
+ interrupt-parent = <&Mpc8xx_pic>;
reg = <930 20>;
built-in;
device_type = "cpm-pic";
@@ -150,7 +150,7 @@
tx-clock = <1>;
current-speed = <0>;
interrupts = <4 3>;
- interrupt-parent = <930>;
+ interrupt-parent = <&Cpm_pic>;
};
smc@a90 {
@@ -164,7 +164,7 @@
tx-clock = <2>;
current-speed = <0>;
interrupts = <3 3>;
- interrupt-parent = <930>;
+ interrupt-parent = <&Cpm_pic>;
};
scc@a40 {
@@ -175,8 +175,8 @@
reg = <a40 18 3e00 80>;
mac-address = [ 00 00 0C 00 03 FD ];
interrupts = <1c 3>;
- interrupt-parent = <930>;
- phy-handle = <e8002>;
+ interrupt-parent = <&Cpm_pic>;
+ phy-handle = <&Phy2>;
};
};
};
diff --git a/arch/powerpc/boot/dts/prpmc2800.dts b/arch/powerpc/boot/dts/prpmc2800.dts
index 568965a022b9..699d0df574d5 100644
--- a/arch/powerpc/boot/dts/prpmc2800.dts
+++ b/arch/powerpc/boot/dts/prpmc2800.dts
@@ -309,7 +309,7 @@
};
chosen {
- bootargs = "ip=on console=ttyMM0";
+ bootargs = "ip=on";
linux,stdout-path = "/mv64x60@f1000000/mpsc@8000";
};
};
diff --git a/arch/powerpc/boot/dts/ps3.dts b/arch/powerpc/boot/dts/ps3.dts
new file mode 100644
index 000000000000..379ded282d5e
--- /dev/null
+++ b/arch/powerpc/boot/dts/ps3.dts
@@ -0,0 +1,68 @@
+/*
+ * PS3 Game Console device tree.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/ {
+ model = "SonyPS3";
+ compatible = "sony,ps3";
+ #size-cells = <2>;
+ #address-cells = <2>;
+
+ chosen {
+ };
+
+ /*
+ * We'll get the size of the bootmem block from lv1 after startup,
+ * so we'll put a null entry here.
+ */
+
+ memory {
+ device_type = "memory";
+ reg = <0 0 0 0>;
+ };
+
+ /*
+ * The boot cpu is always zero for PS3.
+ *
+ * dtc expects a clock-frequency and timebase-frequency entries, so
+ * we'll put a null entries here. These will be initialized after
+ * startup with data from lv1.
+ *
+ * Seems the only way currently to indicate a processor has multiple
+ * threads is with an ibm,ppc-interrupt-server#s entry. We'll put one
+ * here so we can bring up both of ours. See smp_setup_cpu_maps().
+ */
+
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ cpu@0 {
+ device_type = "cpu";
+ reg = <0>;
+ ibm,ppc-interrupt-server#s = <0 1>;
+ clock-frequency = <0>;
+ timebase-frequency = <0>;
+ i-cache-size = <8000>;
+ d-cache-size = <8000>;
+ i-cache-line-size = <80>;
+ d-cache-line-size = <80>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/ebony.c b/arch/powerpc/boot/ebony.c
index b1251ee7a102..75daedafd0a4 100644
--- a/arch/powerpc/boot/ebony.c
+++ b/arch/powerpc/boot/ebony.c
@@ -100,28 +100,13 @@ static void ebony_fixups(void)
ibm440gp_fixup_clocks(sysclk, 6 * 1843200);
ibm44x_fixup_memsize();
dt_fixup_mac_addresses(ebony_mac0, ebony_mac1);
-}
-
-#define SPRN_DBCR0 0x134
-#define DBCR0_RST_SYSTEM 0x30000000
-
-static void ebony_exit(void)
-{
- unsigned long tmp;
-
- asm volatile (
- "mfspr %0,%1\n"
- "oris %0,%0,%2@h\n"
- "mtspr %1,%0"
- : "=&r"(tmp) : "i"(SPRN_DBCR0), "i"(DBCR0_RST_SYSTEM)
- );
-
+ ibm4xx_fixup_ebc_ranges("/plb/opb/ebc");
}
void ebony_init(void *mac0, void *mac1)
{
platform_ops.fixups = ebony_fixups;
- platform_ops.exit = ebony_exit;
+ platform_ops.exit = ibm44x_dbcr_reset;
ebony_mac0 = mac0;
ebony_mac1 = mac1;
ft_init(_dtb_start, _dtb_end - _dtb_start, 32);
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index 56b56a8d4b23..416dc3857bfe 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -36,8 +36,6 @@ struct addr_range {
unsigned long size;
};
-typedef void (*kernel_entry_t)(unsigned long, unsigned long, void *);
-
#undef DEBUG
static struct addr_range prep_kernel(void)
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
index d16ee3e3f868..385e08b83b7e 100644
--- a/arch/powerpc/boot/of.c
+++ b/arch/powerpc/boot/of.c
@@ -15,8 +15,7 @@
#include "page.h"
#include "ops.h"
-typedef void *ihandle;
-typedef void *phandle;
+#include "of.h"
extern char _end[];
@@ -25,154 +24,10 @@ extern char _end[];
#define RAM_END (512<<20) /* Fixme: use OF */
#define ONE_MB 0x100000
-int (*prom) (void *);
static unsigned long claim_base;
-static int call_prom(const char *service, int nargs, int nret, ...)
-{
- int i;
- struct prom_args {
- const char *service;
- int nargs;
- int nret;
- unsigned int args[12];
- } args;
- va_list list;
-
- args.service = service;
- args.nargs = nargs;
- args.nret = nret;
-
- va_start(list, nret);
- for (i = 0; i < nargs; i++)
- args.args[i] = va_arg(list, unsigned int);
- va_end(list);
-
- for (i = 0; i < nret; i++)
- args.args[nargs+i] = 0;
-
- if (prom(&args) < 0)
- return -1;
-
- return (nret > 0)? args.args[nargs]: 0;
-}
-
-static int call_prom_ret(const char *service, int nargs, int nret,
- unsigned int *rets, ...)
-{
- int i;
- struct prom_args {
- const char *service;
- int nargs;
- int nret;
- unsigned int args[12];
- } args;
- va_list list;
-
- args.service = service;
- args.nargs = nargs;
- args.nret = nret;
-
- va_start(list, rets);
- for (i = 0; i < nargs; i++)
- args.args[i] = va_arg(list, unsigned int);
- va_end(list);
-
- for (i = 0; i < nret; i++)
- args.args[nargs+i] = 0;
-
- if (prom(&args) < 0)
- return -1;
-
- if (rets != (void *) 0)
- for (i = 1; i < nret; ++i)
- rets[i-1] = args.args[nargs+i];
-
- return (nret > 0)? args.args[nargs]: 0;
-}
-
-/*
- * Older OF's require that when claiming a specific range of addresses,
- * we claim the physical space in the /memory node and the virtual
- * space in the chosen mmu node, and then do a map operation to
- * map virtual to physical.
- */
-static int need_map = -1;
-static ihandle chosen_mmu;
-static phandle memory;
-
-/* returns true if s2 is a prefix of s1 */
-static int string_match(const char *s1, const char *s2)
-{
- for (; *s2; ++s2)
- if (*s1++ != *s2)
- return 0;
- return 1;
-}
-
-static int check_of_version(void)
-{
- phandle oprom, chosen;
- char version[64];
-
- oprom = finddevice("/openprom");
- if (oprom == (phandle) -1)
- return 0;
- if (getprop(oprom, "model", version, sizeof(version)) <= 0)
- return 0;
- version[sizeof(version)-1] = 0;
- printf("OF version = '%s'\r\n", version);
- if (!string_match(version, "Open Firmware, 1.")
- && !string_match(version, "FirmWorks,3."))
- return 0;
- chosen = finddevice("/chosen");
- if (chosen == (phandle) -1) {
- chosen = finddevice("/chosen@0");
- if (chosen == (phandle) -1) {
- printf("no chosen\n");
- return 0;
- }
- }
- if (getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
- printf("no mmu\n");
- return 0;
- }
- memory = (ihandle) call_prom("open", 1, 1, "/memory");
- if (memory == (ihandle) -1) {
- memory = (ihandle) call_prom("open", 1, 1, "/memory@0");
- if (memory == (ihandle) -1) {
- printf("no memory node\n");
- return 0;
- }
- }
- printf("old OF detected\r\n");
- return 1;
-}
-
-static void *claim(unsigned long virt, unsigned long size, unsigned long align)
-{
- int ret;
- unsigned int result;
-
- if (need_map < 0)
- need_map = check_of_version();
- if (align || !need_map)
- return (void *) call_prom("claim", 3, 1, virt, size, align);
-
- ret = call_prom_ret("call-method", 5, 2, &result, "claim", memory,
- align, size, virt);
- if (ret != 0 || result == -1)
- return (void *) -1;
- ret = call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
- align, size, virt);
- /* 0x12 == coherent + read/write */
- ret = call_prom("call-method", 6, 1, "map", chosen_mmu,
- 0x12, size, virt, virt);
- return (void *) virt;
-}
-
static void *of_try_claim(unsigned long size)
{
unsigned long addr = 0;
@@ -184,7 +39,7 @@ static void *of_try_claim(unsigned long size)
#ifdef DEBUG
printf(" trying: 0x%08lx\n\r", claim_base);
#endif
- addr = (unsigned long)claim(claim_base, size, 0);
+ addr = (unsigned long)of_claim(claim_base, size, 0);
if ((void *)addr != (void *)-1)
break;
}
@@ -208,64 +63,6 @@ static void of_image_hdr(const void *hdr)
}
}
-static void *of_vmlinux_alloc(unsigned long size)
-{
- void *p = malloc(size);
-
- if (!p)
- fatal("Can't allocate memory for kernel image!\n\r");
-
- return p;
-}
-
-static void of_exit(void)
-{
- call_prom("exit", 0, 0);
-}
-
-/*
- * OF device tree routines
- */
-static void *of_finddevice(const char *name)
-{
- return (phandle) call_prom("finddevice", 1, 1, name);
-}
-
-static int of_getprop(const void *phandle, const char *name, void *buf,
- const int buflen)
-{
- return call_prom("getprop", 4, 1, phandle, name, buf, buflen);
-}
-
-static int of_setprop(const void *phandle, const char *name, const void *buf,
- const int buflen)
-{
- return call_prom("setprop", 4, 1, phandle, name, buf, buflen);
-}
-
-/*
- * OF console routines
- */
-static void *of_stdout_handle;
-
-static int of_console_open(void)
-{
- void *devp;
-
- if (((devp = finddevice("/chosen")) != NULL)
- && (getprop(devp, "stdout", &of_stdout_handle,
- sizeof(of_stdout_handle))
- == sizeof(of_stdout_handle)))
- return 0;
-
- return -1;
-}
-
-static void of_console_write(char *buf, int len)
-{
- call_prom("write", 3, 1, of_stdout_handle, buf, len);
-}
-
void platform_init(unsigned long a1, unsigned long a2, void *promptr)
{
platform_ops.image_hdr = of_image_hdr;
@@ -277,10 +74,9 @@ void platform_init(unsigned long a1, unsigned long a2, void *promptr)
dt_ops.getprop = of_getprop;
dt_ops.setprop = of_setprop;
- console_ops.open = of_console_open;
- console_ops.write = of_console_write;
+ of_console_init();
- prom = (int (*)(void *))promptr;
+ of_init(promptr);
loader_info.promptr = promptr;
if (a1 && a2 && a2 != 0xdeadbeef) {
loader_info.initrd_addr = a1;
diff --git a/arch/powerpc/boot/of.h b/arch/powerpc/boot/of.h
new file mode 100644
index 000000000000..e4c68f7391c5
--- /dev/null
+++ b/arch/powerpc/boot/of.h
@@ -0,0 +1,21 @@
+#ifndef _PPC_BOOT_OF_H_
+#define _PPC_BOOT_OF_H_
+
+typedef void *phandle;
+typedef void *ihandle;
+
+void of_init(void *promptr);
+int of_call_prom(const char *service, int nargs, int nret, ...);
+void *of_claim(unsigned long virt, unsigned long size, unsigned long align);
+void *of_vmlinux_alloc(unsigned long size);
+void of_exit(void);
+void *of_finddevice(const char *name);
+int of_getprop(const void *phandle, const char *name, void *buf,
+ const int buflen);
+int of_setprop(const void *phandle, const char *name, const void *buf,
+ const int buflen);
+
+/* Console functions */
+void of_console_init(void);
+
+#endif /* _PPC_BOOT_OF_H_ */
diff --git a/arch/powerpc/boot/ofconsole.c b/arch/powerpc/boot/ofconsole.c
new file mode 100644
index 000000000000..ce0e02424453
--- /dev/null
+++ b/arch/powerpc/boot/ofconsole.c
@@ -0,0 +1,45 @@
+/*
+ * OF console routines
+ *
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+
+#include "of.h"
+
+static void *of_stdout_handle;
+
+static int of_console_open(void)
+{
+ void *devp;
+
+ if (((devp = of_finddevice("/chosen")) != NULL)
+ && (of_getprop(devp, "stdout", &of_stdout_handle,
+ sizeof(of_stdout_handle))
+ == sizeof(of_stdout_handle)))
+ return 0;
+
+ return -1;
+}
+
+static void of_console_write(const char *buf, int len)
+{
+ of_call_prom("write", 3, 1, of_stdout_handle, buf, len);
+}
+
+void of_console_init(void)
+{
+ console_ops.open = of_console_open;
+ console_ops.write = of_console_write;
+}
diff --git a/arch/powerpc/boot/oflib.c b/arch/powerpc/boot/oflib.c
new file mode 100644
index 000000000000..95b8fd69a403
--- /dev/null
+++ b/arch/powerpc/boot/oflib.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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 <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+
+#include "of.h"
+
+static int (*prom) (void *);
+
+void of_init(void *promptr)
+{
+ prom = (int (*)(void *))promptr;
+}
+
+int of_call_prom(const char *service, int nargs, int nret, ...)
+{
+ int i;
+ struct prom_args {
+ const char *service;
+ int nargs;
+ int nret;
+ unsigned int args[12];
+ } args;
+ va_list list;
+
+ args.service = service;
+ args.nargs = nargs;
+ args.nret = nret;
+
+ va_start(list, nret);
+ for (i = 0; i < nargs; i++)
+ args.args[i] = va_arg(list, unsigned int);
+ va_end(list);
+
+ for (i = 0; i < nret; i++)
+ args.args[nargs+i] = 0;
+
+ if (prom(&args) < 0)
+ return -1;
+
+ return (nret > 0)? args.args[nargs]: 0;
+}
+
+static int of_call_prom_ret(const char *service, int nargs, int nret,
+ unsigned int *rets, ...)
+{
+ int i;
+ struct prom_args {
+ const char *service;
+ int nargs;
+ int nret;
+ unsigned int args[12];
+ } args;
+ va_list list;
+
+ args.service = service;
+ args.nargs = nargs;
+ args.nret = nret;
+
+ va_start(list, rets);
+ for (i = 0; i < nargs; i++)
+ args.args[i] = va_arg(list, unsigned int);
+ va_end(list);
+
+ for (i = 0; i < nret; i++)
+ args.args[nargs+i] = 0;
+
+ if (prom(&args) < 0)
+ return -1;
+
+ if (rets != (void *) 0)
+ for (i = 1; i < nret; ++i)
+ rets[i-1] = args.args[nargs+i];
+
+ return (nret > 0)? args.args[nargs]: 0;
+}
+
+/* returns true if s2 is a prefix of s1 */
+static int string_match(const char *s1, const char *s2)
+{
+ for (; *s2; ++s2)
+ if (*s1++ != *s2)
+ return 0;
+ return 1;
+}
+
+/*
+ * Older OF's require that when claiming a specific range of addresses,
+ * we claim the physical space in the /memory node and the virtual
+ * space in the chosen mmu node, and then do a map operation to
+ * map virtual to physical.
+ */
+static int need_map = -1;
+static ihandle chosen_mmu;
+static phandle memory;
+
+static int check_of_version(void)
+{
+ phandle oprom, chosen;
+ char version[64];
+
+ oprom = of_finddevice("/openprom");
+ if (oprom == (phandle) -1)
+ return 0;
+ if (of_getprop(oprom, "model", version, sizeof(version)) <= 0)
+ return 0;
+ version[sizeof(version)-1] = 0;
+ printf("OF version = '%s'\r\n", version);
+ if (!string_match(version, "Open Firmware, 1.")
+ && !string_match(version, "FirmWorks,3."))
+ return 0;
+ chosen = of_finddevice("/chosen");
+ if (chosen == (phandle) -1) {
+ chosen = of_finddevice("/chosen@0");
+ if (chosen == (phandle) -1) {
+ printf("no chosen\n");
+ return 0;
+ }
+ }
+ if (of_getprop(chosen, "mmu", &chosen_mmu, sizeof(chosen_mmu)) <= 0) {
+ printf("no mmu\n");
+ return 0;
+ }
+ memory = (ihandle) of_call_prom("open", 1, 1, "/memory");
+ if (memory == (ihandle) -1) {
+ memory = (ihandle) of_call_prom("open", 1, 1, "/memory@0");
+ if (memory == (ihandle) -1) {
+ printf("no memory node\n");
+ return 0;
+ }
+ }
+ printf("old OF detected\r\n");
+ return 1;
+}
+
+void *of_claim(unsigned long virt, unsigned long size, unsigned long align)
+{
+ int ret;
+ unsigned int result;
+
+ if (need_map < 0)
+ need_map = check_of_version();
+ if (align || !need_map)
+ return (void *) of_call_prom("claim", 3, 1, virt, size, align);
+
+ ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", memory,
+ align, size, virt);
+ if (ret != 0 || result == -1)
+ return (void *) -1;
+ ret = of_call_prom_ret("call-method", 5, 2, &result, "claim", chosen_mmu,
+ align, size, virt);
+ /* 0x12 == coherent + read/write */
+ ret = of_call_prom("call-method", 6, 1, "map", chosen_mmu,
+ 0x12, size, virt, virt);
+ return (void *) virt;
+}
+
+void *of_vmlinux_alloc(unsigned long size)
+{
+ void *p = malloc(size);
+
+ if (!p)
+ fatal("Can't allocate memory for kernel image!\n\r");
+
+ return p;
+}
+
+void of_exit(void)
+{
+ of_call_prom("exit", 0, 0);
+}
+
+/*
+ * OF device tree routines
+ */
+void *of_finddevice(const char *name)
+{
+ return (phandle) of_call_prom("finddevice", 1, 1, name);
+}
+
+int of_getprop(const void *phandle, const char *name, void *buf,
+ const int buflen)
+{
+ return of_call_prom("getprop", 4, 1, phandle, name, buf, buflen);
+}
+
+int of_setprop(const void *phandle, const char *name, const void *buf,
+ const int buflen)
+{
+ return of_call_prom("setprop", 4, 1, phandle, name, buf, buflen);
+}
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index 959124f3f9af..86077066cd7c 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -19,6 +19,8 @@
#define MAX_PATH_LEN 256
#define MAX_PROP_LEN 256 /* What should this be? */
+typedef void (*kernel_entry_t)(unsigned long r3, unsigned long r4, void *r5);
+
/* Platform specific operations */
struct platform_ops {
void (*fixups)(void);
@@ -51,7 +53,7 @@ extern struct dt_ops dt_ops;
/* Console operations */
struct console_ops {
int (*open)(void);
- void (*write)(char *buf, int len);
+ void (*write)(const char *buf, int len);
void (*edit_cmdline)(char *buf, int len);
void (*close)(void);
void *data;
diff --git a/arch/powerpc/boot/ps3-head.S b/arch/powerpc/boot/ps3-head.S
new file mode 100644
index 000000000000..a55c2735f759
--- /dev/null
+++ b/arch/powerpc/boot/ps3-head.S
@@ -0,0 +1,82 @@
+/*
+ * PS3 bootwrapper entry.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ppc_asm.h"
+
+ .machine "ppc64"
+
+ .text
+
+/*
+ * __system_reset_overlay - The PS3 first stage entry.
+ *
+ * The bootwraper build script copies the 0x100 bytes at symbol
+ * __system_reset_overlay to offset 0x100 of the rom image.
+ *
+ * The PS3 has a single processor with two threads.
+ */
+
+ .globl __system_reset_overlay
+__system_reset_overlay:
+
+ /* Switch to 32-bit mode. */
+
+ mfmsr r9
+ clrldi r9,r9,1
+ mtmsrd r9
+ nop
+
+ /* Get thread number in r3 and branch. */
+
+ mfspr r3, 0x88
+ cntlzw. r3, r3
+ li r4, 0
+ li r5, 0
+ beq 1f
+
+ /* Secondary goes to __secondary_hold in kernel. */
+
+ li r4, 0x60
+ mtctr r4
+ bctr
+
+ /* Primary delays then goes to _zimage_start in wrapper. */
+1:
+ or 31, 31, 31 /* db16cyc */
+ or 31, 31, 31 /* db16cyc */
+
+ lis r4, _zimage_start@ha
+ addi r4, r4, _zimage_start@l
+ mtctr r4
+ bctr
+
+/*
+ * __system_reset_kernel - Place holder for the kernel reset vector.
+ *
+ * The bootwrapper build script copies 0x100 bytes from offset 0x100
+ * of the rom image to the symbol __system_reset_kernel. At runtime
+ * the bootwrapper program copies the 0x100 bytes at __system_reset_kernel
+ * to ram address 0x100. This symbol must occupy 0x100 bytes.
+ */
+
+ .globl __system_reset_kernel
+__system_reset_kernel:
+
+ . = __system_reset_kernel + 0x100
diff --git a/arch/powerpc/boot/ps3-hvcall.S b/arch/powerpc/boot/ps3-hvcall.S
new file mode 100644
index 000000000000..585965f7e6a8
--- /dev/null
+++ b/arch/powerpc/boot/ps3-hvcall.S
@@ -0,0 +1,186 @@
+/*
+ * PS3 bootwrapper hvcalls.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ppc_asm.h"
+
+ .machine "ppc64"
+
+/*
+ * The PS3 hypervisor uses a 64 bit "C" language calling convention.
+ * The routines here marshal arguments between the 32 bit wrapper
+ * program and the 64 bit hvcalls.
+ *
+ * wrapper lv1
+ * 32-bit (h,l) 64-bit
+ *
+ * 1: r3,r4 <-> r3
+ * 2: r5,r6 <-> r4
+ * 3: r7,r8 <-> r5
+ * 4: r9,r10 <-> r6
+ * 5: 8(r1),12(r1) <-> r7
+ * 6: 16(r1),20(r1) <-> r8
+ * 7: 24(r1),28(r1) <-> r9
+ * 8: 32(r1),36(r1) <-> r10
+ *
+ */
+
+.macro GLOBAL name
+ .section ".text"
+ .balign 4
+ .globl \name
+\name:
+.endm
+
+.macro NO_SUPPORT name
+ GLOBAL \name
+ b ps3_no_support
+.endm
+
+.macro HVCALL num
+ li r11, \num
+ .long 0x44000022
+ extsw r3, r3
+.endm
+
+.macro SAVE_LR offset=4
+ mflr r0
+ stw r0, \offset(r1)
+.endm
+
+.macro LOAD_LR offset=4
+ lwz r0, \offset(r1)
+ mtlr r0
+.endm
+
+.macro LOAD_64_REG target,high,low
+ sldi r11, \high, 32
+ or \target, r11, \low
+.endm
+
+.macro LOAD_64_STACK target,offset
+ ld \target, \offset(r1)
+.endm
+
+.macro LOAD_R3
+ LOAD_64_REG r3,r3,r4
+.endm
+
+.macro LOAD_R4
+ LOAD_64_REG r4,r5,r6
+.endm
+
+.macro LOAD_R5
+ LOAD_64_REG r5,r7,r8
+.endm
+
+.macro LOAD_R6
+ LOAD_64_REG r6,r9,r10
+.endm
+
+.macro LOAD_R7
+ LOAD_64_STACK r7,8
+.endm
+
+.macro LOAD_R8
+ LOAD_64_STACK r8,16
+.endm
+
+.macro LOAD_R9
+ LOAD_64_STACK r9,24
+.endm
+
+.macro LOAD_R10
+ LOAD_64_STACK r10,32
+.endm
+
+.macro LOAD_REGS_0
+ stwu 1,-16(1)
+ stw 3, 8(1)
+.endm
+
+.macro LOAD_REGS_5
+ LOAD_R3
+ LOAD_R4
+ LOAD_R5
+ LOAD_R6
+ LOAD_R7
+.endm
+
+.macro LOAD_REGS_6
+ LOAD_REGS_5
+ LOAD_R8
+.endm
+
+.macro LOAD_REGS_8
+ LOAD_REGS_6
+ LOAD_R9
+ LOAD_R10
+.endm
+
+.macro STORE_REGS_0_1
+ lwz r11, 8(r1)
+ std r4, 0(r11)
+ mr r4, r3
+ li r3, 0
+ addi r1,r1,16
+.endm
+
+.macro STORE_REGS_5_2
+ lwz r11, 16(r1)
+ std r4, 0(r11)
+ lwz r11, 24(r1)
+ std r5, 0(r11)
+.endm
+
+.macro STORE_REGS_6_1
+ lwz r11, 24(r1)
+ std r4, 0(r11)
+.endm
+
+GLOBAL lv1_get_logical_ppe_id
+ SAVE_LR
+ LOAD_REGS_0
+ HVCALL 69
+ STORE_REGS_0_1
+ LOAD_LR
+ blr
+
+GLOBAL lv1_get_logical_partition_id
+ SAVE_LR
+ LOAD_REGS_0
+ HVCALL 74
+ STORE_REGS_0_1
+ LOAD_LR
+ blr
+
+GLOBAL lv1_get_repository_node_value
+ SAVE_LR
+ LOAD_REGS_5
+ HVCALL 91
+ STORE_REGS_5_2
+ LOAD_LR
+ blr
+
+GLOBAL lv1_panic
+ SAVE_LR
+ LOAD_REGS_8
+ HVCALL 255
+ LOAD_LR
+ blr
diff --git a/arch/powerpc/boot/ps3.c b/arch/powerpc/boot/ps3.c
new file mode 100644
index 000000000000..893d59339c26
--- /dev/null
+++ b/arch/powerpc/boot/ps3.c
@@ -0,0 +1,161 @@
+/*
+ * PS3 bootwrapper support.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "string.h"
+#include "stdio.h"
+#include "page.h"
+#include "ops.h"
+
+extern s64 lv1_panic(u64 in_1);
+extern s64 lv1_get_logical_partition_id(u64 *out_1);
+extern s64 lv1_get_logical_ppe_id(u64 *out_1);
+extern s64 lv1_get_repository_node_value(u64 in_1, u64 in_2, u64 in_3,
+ u64 in_4, u64 in_5, u64 *out_1, u64 *out_2);
+
+#ifdef DEBUG
+#define DBG(fmt...) printf(fmt)
+#else
+static inline int __attribute__ ((format (printf, 1, 2))) DBG(
+ const char *fmt, ...) {return 0;}
+#endif
+
+BSS_STACK(4096);
+
+/* A buffer that may be edited by tools operating on a zImage binary so as to
+ * edit the command line passed to vmlinux (by setting /chosen/bootargs).
+ * The buffer is put in it's own section so that tools may locate it easier.
+ */
+static char cmdline[COMMAND_LINE_SIZE]
+ __attribute__((__section__("__builtin_cmdline")));
+
+static void prep_cmdline(void *chosen)
+{
+ if (cmdline[0] == '\0')
+ getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
+ else
+ setprop_str(chosen, "bootargs", cmdline);
+
+ printf("cmdline: '%s'\n", cmdline);
+}
+
+static void ps3_console_write(const char *buf, int len)
+{
+}
+
+static void ps3_exit(void)
+{
+ printf("ps3_exit\n");
+
+ /* lv1_panic will shutdown the lpar. */
+
+ lv1_panic(0); /* zero = do not reboot */
+ while (1);
+}
+
+static int ps3_repository_read_rm_size(u64 *rm_size)
+{
+ s64 result;
+ u64 lpar_id;
+ u64 ppe_id;
+ u64 v2;
+
+ result = lv1_get_logical_partition_id(&lpar_id);
+
+ if (result)
+ return -1;
+
+ result = lv1_get_logical_ppe_id(&ppe_id);
+
+ if (result)
+ return -1;
+
+ /*
+ * n1: 0000000062690000 : ....bi..
+ * n2: 7075000000000000 : pu......
+ * n3: 0000000000000001 : ........
+ * n4: 726d5f73697a6500 : rm_size.
+ */
+
+ result = lv1_get_repository_node_value(lpar_id, 0x0000000062690000ULL,
+ 0x7075000000000000ULL, ppe_id, 0x726d5f73697a6500ULL, rm_size,
+ &v2);
+
+ printf("%s:%d: ppe_id %lu \n", __func__, __LINE__,
+ (unsigned long)ppe_id);
+ printf("%s:%d: lpar_id %lu \n", __func__, __LINE__,
+ (unsigned long)lpar_id);
+ printf("%s:%d: rm_size %llxh \n", __func__, __LINE__, *rm_size);
+
+ return result ? -1 : 0;
+}
+
+void ps3_copy_vectors(void)
+{
+ extern char __system_reset_kernel[];
+
+ memcpy((void *)0x100, __system_reset_kernel, 0x100);
+ flush_cache((void *)0x100, 0x100);
+}
+
+void platform_init(void)
+{
+ extern char _end[];
+ extern char _dtb_start[];
+ extern char _initrd_start[];
+ extern char _initrd_end[];
+ const u32 heapsize = 0x1000000 - (u32)_end; /* 16MiB */
+ void *chosen;
+ unsigned long ft_addr;
+ u64 rm_size;
+
+ console_ops.write = ps3_console_write;
+ platform_ops.exit = ps3_exit;
+
+ printf("\n-- PS3 bootwrapper --\n");
+
+ simple_alloc_init(_end, heapsize, 32, 64);
+ ft_init(_dtb_start, 0, 4);
+
+ chosen = finddevice("/chosen");
+
+ ps3_repository_read_rm_size(&rm_size);
+ dt_fixup_memory(0, rm_size);
+
+ if (_initrd_end > _initrd_start) {
+ setprop_val(chosen, "linux,initrd-start", (u32)(_initrd_start));
+ setprop_val(chosen, "linux,initrd-end", (u32)(_initrd_end));
+ }
+
+ prep_cmdline(chosen);
+
+ ft_addr = dt_ops.finalize();
+
+ ps3_copy_vectors();
+
+ printf(" flat tree at 0x%lx\n\r", ft_addr);
+
+ ((kernel_entry_t)0)(ft_addr, 0, NULL);
+
+ ps3_exit();
+}
diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c
index 7fd32330a9a5..eaa0d3ae3518 100644
--- a/arch/powerpc/boot/serial.c
+++ b/arch/powerpc/boot/serial.c
@@ -27,7 +27,7 @@ static int serial_open(void)
return scdp->open();
}
-static void serial_write(char *buf, int len)
+static void serial_write(const char *buf, int len)
{
struct serial_console_data *scdp = console_ops.data;
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c
index 0a9feeb98342..5b57800bbc67 100644
--- a/arch/powerpc/boot/stdio.c
+++ b/arch/powerpc/boot/stdio.c
@@ -190,7 +190,11 @@ int vsprintf(char *buf, const char *fmt, va_list args)
/* get the conversion qualifier */
qualifier = -1;
- if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt =='Z') {
+ if (*fmt == 'l' && *(fmt + 1) == 'l') {
+ qualifier = 'q';
+ fmt += 2;
+ } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
+ || *fmt == 'Z') {
qualifier = *fmt;
++fmt;
}
@@ -281,6 +285,10 @@ int vsprintf(char *buf, const char *fmt, va_list args)
num = va_arg(args, unsigned long);
if (flags & SIGN)
num = (signed long) num;
+ } else if (qualifier == 'q') {
+ num = va_arg(args, unsigned long long);
+ if (flags & SIGN)
+ num = (signed long long) num;
} else if (qualifier == 'Z') {
num = va_arg(args, size_t);
} else if (qualifier == 'h') {
diff --git a/arch/powerpc/boot/types.h b/arch/powerpc/boot/types.h
index 79d26e708677..31393d17a9c1 100644
--- a/arch/powerpc/boot/types.h
+++ b/arch/powerpc/boot/types.h
@@ -7,6 +7,10 @@ typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
+typedef signed char s8;
+typedef short s16;
+typedef int s32;
+typedef long long s64;
#define min(x,y) ({ \
typeof(x) _x = (x); \
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index da77adc73078..65f685479175 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -144,6 +144,15 @@ miboot|uboot)
cuboot*)
gzip=
;;
+ps3)
+ platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
+ lds=$object/zImage.ps3.lds
+ gzip=
+ ext=bin
+ objflags="-O binary --set-section-flags=.bss=contents,alloc,load,data"
+ ksection=.kernel:vmlinux.bin
+ isection=.kernel:initrd
+ ;;
esac
vmz="$tmpdir/`basename \"$kernel\"`.$ext"
@@ -239,4 +248,50 @@ treeboot*)
fi
exit 0
;;
+ps3)
+ # The ps3's loader supports loading gzipped binary images from flash
+ # rom to addr zero. The loader enters the image at addr 0x100. A
+ # bootwrapper overlay is use to arrange for the kernel to be loaded
+ # to addr zero and to have a suitable bootwrapper entry at 0x100.
+ # To construct the rom image, 0x100 bytes from offset 0x100 in the
+ # kernel is copied to the bootwrapper symbol __system_reset_kernel.
+ # The 0x100 bytes at the bootwrapper symbol __system_reset_overlay is
+ # then copied to offset 0x100. At runtime the bootwrapper program
+ # copies the 0x100 bytes at __system_reset_kernel to addr 0x100.
+
+ system_reset_overlay=0x`${CROSS}nm "$ofile" \
+ | grep ' __system_reset_overlay$' \
+ | cut -d' ' -f1`
+ system_reset_overlay=`printf "%d" $system_reset_overlay`
+ system_reset_kernel=0x`${CROSS}nm "$ofile" \
+ | grep ' __system_reset_kernel$' \
+ | cut -d' ' -f1`
+ system_reset_kernel=`printf "%d" $system_reset_kernel`
+ overlay_dest="256"
+ overlay_size="256"
+
+ rm -f "$object/otheros.bld"
+
+ ${CROSS}objcopy -O binary "$ofile" "$ofile.bin"
+
+ msg=$(dd if="$ofile.bin" of="$ofile.bin" conv=notrunc \
+ skip=$overlay_dest seek=$system_reset_kernel \
+ count=$overlay_size bs=1 2>&1)
+
+ if [ $? -ne "0" ]; then
+ echo $msg
+ exit 1
+ fi
+
+ msg=$(dd if="$ofile.bin" of="$ofile.bin" conv=notrunc \
+ skip=$system_reset_overlay seek=$overlay_dest \
+ count=$overlay_size bs=1 2>&1)
+
+ if [ $? -ne "0" ]; then
+ echo $msg
+ exit 2
+ fi
+
+ gzip --force -9 --stdout "$ofile.bin" > "$object/otheros.bld"
+ ;;
esac
diff --git a/arch/powerpc/boot/zImage.ps3.lds.S b/arch/powerpc/boot/zImage.ps3.lds.S
new file mode 100644
index 000000000000..aaa469c1e60d
--- /dev/null
+++ b/arch/powerpc/boot/zImage.ps3.lds.S
@@ -0,0 +1,50 @@
+OUTPUT_ARCH(powerpc:common)
+ENTRY(_zimage_start)
+EXTERN(_zimage_start)
+SECTIONS
+{
+ _vmlinux_start = .;
+ .kernel:vmlinux.bin : { *(.kernel:vmlinux.bin) }
+ _vmlinux_end = .;
+
+ . = ALIGN(4096);
+ _dtb_start = .;
+ .kernel:dtb : { *(.kernel:dtb) }
+ _dtb_end = .;
+
+ . = ALIGN(4096);
+ _initrd_start = .;
+ .kernel:initrd : { *(.kernel:initrd) }
+ _initrd_end = .;
+
+ _start = .;
+ .text :
+ {
+ *(.text)
+ *(.fixup)
+ }
+ _etext = .;
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.rodata*)
+ *(.data*)
+ *(.sdata*)
+ __got2_start = .;
+ *(.got2)
+ __got2_end = .;
+ }
+
+ . = ALIGN(4096);
+ _edata = .;
+
+ . = ALIGN(4096);
+ __bss_start = .;
+ .bss :
+ {
+ *(.sbss)
+ *(.bss)
+ }
+ . = ALIGN(4096);
+ _end = . ;
+}
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index 74f83f4a4e5e..d9ac24e8de16 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1455,7 +1455,8 @@ CONFIG_HAS_DMA=y
# Instrumentation Support
#
CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+CONFIG_OPROFILE=m
+CONFIG_OPROFILE_CELL=y
# CONFIG_KPROBES is not set
#
diff --git a/arch/powerpc/configs/holly_defconfig b/arch/powerpc/configs/holly_defconfig
index 32781849ad4c..04b94f884aae 100644
--- a/arch/powerpc/configs/holly_defconfig
+++ b/arch/powerpc/configs/holly_defconfig
@@ -190,10 +190,12 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=1
CONFIG_PROC_DEVICETREE=y
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200"
# CONFIG_PM is not set
# CONFIG_SECCOMP is not set
-# CONFIG_WANT_DEVICE_TREE is not set
+CONFIG_WANT_DEVICE_TREE=y
+CONFIG_DEVICE_TREE="holly.dts"
CONFIG_ISA_DMA_API=y
#
diff --git a/arch/powerpc/configs/prpmc2800_defconfig b/arch/powerpc/configs/prpmc2800_defconfig
index fb504a714625..858f865f2d59 100644
--- a/arch/powerpc/configs/prpmc2800_defconfig
+++ b/arch/powerpc/configs/prpmc2800_defconfig
@@ -48,7 +48,7 @@ CONFIG_PPC_STD_MMU_32=y
# CONFIG_PPC_MM_SLICES is not set
# CONFIG_SMP is not set
CONFIG_NOT_COHERENT_CACHE=y
-CONFIG_CONFIG_CHECK_CACHE_COHERENCY=y
+CONFIG_CHECK_CACHE_COHERENCY=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index 956d1df61e0f..d0b43df44426 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -156,7 +156,11 @@ CONFIG_PS3_HTAB_SIZE=20
CONFIG_PS3_USE_LPAR_ADDR=y
CONFIG_PS3_VUART=y
CONFIG_PS3_PS3AV=y
-CONFIG_PS3_SYS_MANAGER=y
+CONFIG_PS3_SYS_MANAGER=m
+CONFIG_PS3_STORAGE=y
+CONFIG_PS3_DISK=y
+CONFIG_PS3_ROM=y
+CONFIG_PS3_FLASH=y
CONFIG_PPC_CELL=y
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_IBM_CELL_BLADE is not set
@@ -335,7 +339,7 @@ CONFIG_BT=m
CONFIG_BT_L2CAP=m
CONFIG_BT_SCO=m
CONFIG_BT_RFCOMM=m
-# CONFIG_BT_RFCOMM_TTY is not set
+CONFIG_BT_RFCOMM_TTY=y
# CONFIG_BT_BNEP is not set
CONFIG_BT_HIDP=m
@@ -344,7 +348,9 @@ CONFIG_BT_HIDP=m
#
CONFIG_BT_HCIUSB=m
CONFIG_BT_HCIUSB_SCO=y
-# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
# CONFIG_BT_HCIBCM203X is not set
# CONFIG_BT_HCIBPA10X is not set
# CONFIG_BT_HCIBFUSB is not set
@@ -435,7 +441,7 @@ CONFIG_CHR_DEV_SG=m
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
-# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
@@ -479,6 +485,7 @@ CONFIG_NETDEVICES=y
CONFIG_MII=m
CONFIG_NETDEV_1000=y
CONFIG_NETDEV_10000=y
+CONFIG_GELIC_NET=y
#
# Wireless LAN
@@ -546,7 +553,27 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_JOYSTICK=y
+# CONFIG_JOYSTICK_ANALOG is not set
+# CONFIG_JOYSTICK_A3D is not set
+# CONFIG_JOYSTICK_ADI is not set
+# CONFIG_JOYSTICK_COBRA is not set
+# CONFIG_JOYSTICK_GF2K is not set
+# CONFIG_JOYSTICK_GRIP is not set
+# CONFIG_JOYSTICK_GRIP_MP is not set
+# CONFIG_JOYSTICK_GUILLEMOT is not set
+# CONFIG_JOYSTICK_INTERACT is not set
+# CONFIG_JOYSTICK_SIDEWINDER is not set
+# CONFIG_JOYSTICK_TMDC is not set
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDJOY is not set
+# CONFIG_JOYSTICK_JOYDUMP is not set
+# CONFIG_JOYSTICK_XPAD is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -563,7 +590,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -1086,7 +1113,7 @@ CONFIG_HAS_DMA=y
#
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
@@ -1116,16 +1143,7 @@ CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUGGER is not set
CONFIG_IRQSTACKS=y
# CONFIG_BOOTX_TEXT is not set
-CONFIG_PPC_EARLY_DEBUG=y
-# CONFIG_PPC_EARLY_DEBUG_LPAR is not set
-# CONFIG_PPC_EARLY_DEBUG_G5 is not set
-# CONFIG_PPC_EARLY_DEBUG_RTAS_PANEL is not set
-# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
-# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
-# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
-# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set
-# CONFIG_PPC_EARLY_DEBUG_BEAT is not set
-# CONFIG_PPC_EARLY_DEBUG_44x is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
#
# Security options
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 3e779f07f21b..42c42ecad00c 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -12,7 +12,8 @@ endif
obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
irq.o align.o signal_32.o pmc.o vdso.o \
- init_task.o process.o systbl.o idle.o
+ init_task.o process.o systbl.o idle.o \
+ signal.o
obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
signal_64.o ptrace32.o \
@@ -65,9 +66,9 @@ obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o
module-$(CONFIG_PPC64) += module_64.o
obj-$(CONFIG_MODULES) += $(module-y)
-pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o
+pci64-$(CONFIG_PPC64) += pci_64.o pci_dn.o isa-bridge.o
pci32-$(CONFIG_PPC32) := pci_32.o
-obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y)
+obj-$(CONFIG_PCI) += $(pci64-y) $(pci32-y) pci-common.o
obj-$(CONFIG_PCI_MSI) += msi.o
kexec-$(CONFIG_PPC64) := machine_kexec_64.o
kexec-$(CONFIG_PPC32) := machine_kexec_32.o
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index b2b5d664d328..b1f8000952f3 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -294,6 +294,21 @@ static struct cpu_spec cpu_specs[] = {
.oprofile_mmcra_sipr = MMCRA_SIPR,
.platform = "power5",
},
+ { /* Power5++ */
+ .pvr_mask = 0xffffff00,
+ .pvr_value = 0x003b0300,
+ .cpu_name = "POWER5+ (gs)",
+ .cpu_features = CPU_FTRS_POWER5,
+ .cpu_user_features = COMMON_USER_POWER5_PLUS,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .num_pmcs = 6,
+ .oprofile_cpu_type = "ppc64/power5++",
+ .oprofile_type = PPC_OPROFILE_POWER4,
+ .oprofile_mmcra_sihv = MMCRA_SIHV,
+ .oprofile_mmcra_sipr = MMCRA_SIPR,
+ .platform = "power5+",
+ },
{ /* Power5 GS */
.pvr_mask = 0xffff0000,
.pvr_value = 0x003b0000,
@@ -1178,8 +1193,8 @@ static struct cpu_spec cpu_specs[] = {
.platform = "ppc440",
},
{ /* 440SP Rev. A */
- .pvr_mask = 0xff000fff,
- .pvr_value = 0x53000891,
+ .pvr_mask = 0xfff00fff,
+ .pvr_value = 0x53200891,
.cpu_name = "440SP Rev. A",
.cpu_features = CPU_FTRS_44X,
.cpu_user_features = COMMON_USER_BOOKE,
@@ -1188,9 +1203,19 @@ static struct cpu_spec cpu_specs[] = {
.platform = "ppc440",
},
{ /* 440SPe Rev. A */
- .pvr_mask = 0xff000fff,
- .pvr_value = 0x53000890,
- .cpu_name = "440SPe Rev. A",
+ .pvr_mask = 0xfff00fff,
+ .pvr_value = 0x53400890,
+ .cpu_name = "440SPe Rev. A",
+ .cpu_features = CPU_FTRS_44X,
+ .cpu_user_features = COMMON_USER_BOOKE,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .platform = "ppc440",
+ },
+ { /* 440SPe Rev. B */
+ .pvr_mask = 0xfff00fff,
+ .pvr_value = 0x53400891,
+ .cpu_name = "440SPe Rev. B",
.cpu_features = CPU_FTRS_44X,
.cpu_user_features = COMMON_USER_BOOKE,
.icache_bsize = 32,
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index d3f2080d2eee..37658ea417fa 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -219,6 +219,72 @@ void crash_kexec_secondary(struct pt_regs *regs)
cpus_in_sr = CPU_MASK_NONE;
}
#endif
+#ifdef CONFIG_SPU_BASE
+
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
+
+struct crash_spu_info {
+ struct spu *spu;
+ u32 saved_spu_runcntl_RW;
+ u32 saved_spu_status_R;
+ u32 saved_spu_npc_RW;
+ u64 saved_mfc_sr1_RW;
+ u64 saved_mfc_dar;
+ u64 saved_mfc_dsisr;
+};
+
+#define CRASH_NUM_SPUS 16 /* Enough for current hardware */
+static struct crash_spu_info crash_spu_info[CRASH_NUM_SPUS];
+
+static void crash_kexec_stop_spus(void)
+{
+ struct spu *spu;
+ int i;
+ u64 tmp;
+
+ for (i = 0; i < CRASH_NUM_SPUS; i++) {
+ if (!crash_spu_info[i].spu)
+ continue;
+
+ spu = crash_spu_info[i].spu;
+
+ crash_spu_info[i].saved_spu_runcntl_RW =
+ in_be32(&spu->problem->spu_runcntl_RW);
+ crash_spu_info[i].saved_spu_status_R =
+ in_be32(&spu->problem->spu_status_R);
+ crash_spu_info[i].saved_spu_npc_RW =
+ in_be32(&spu->problem->spu_npc_RW);
+
+ crash_spu_info[i].saved_mfc_dar = spu_mfc_dar_get(spu);
+ crash_spu_info[i].saved_mfc_dsisr = spu_mfc_dsisr_get(spu);
+ tmp = spu_mfc_sr1_get(spu);
+ crash_spu_info[i].saved_mfc_sr1_RW = tmp;
+
+ tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+ spu_mfc_sr1_set(spu, tmp);
+
+ __delay(200);
+ }
+}
+
+void crash_register_spus(struct list_head *list)
+{
+ struct spu *spu;
+
+ list_for_each_entry(spu, list, full_list) {
+ if (WARN_ON(spu->number >= CRASH_NUM_SPUS))
+ continue;
+
+ crash_spu_info[spu->number].spu = spu;
+ }
+}
+
+#else
+static inline void crash_kexec_stop_spus(void)
+{
+}
+#endif /* CONFIG_SPU_BASE */
void default_machine_crash_shutdown(struct pt_regs *regs)
{
@@ -254,6 +320,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
crash_save_cpu(regs, crashing_cpu);
crash_kexec_prepare_cpus(crashing_cpu);
cpu_set(crashing_cpu, cpus_in_crash);
+ crash_kexec_stop_spus();
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(1, 0);
}
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index c897203198b1..7d73a13450b0 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -9,7 +9,6 @@
* rewritten by Paul Mackerras.
* Copyright (C) 1996 Paul Mackerras.
* MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net).
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* This file contains the low-level support and setup for the
* PowerPC platform, including trap and interrupt dispatch.
@@ -32,10 +31,6 @@
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
-#ifdef CONFIG_APUS
-#include <asm/amigappc.h>
-#endif
-
/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */
#define LOAD_BAT(n, reg, RA, RB) \
/* see the comment for clear_bats() -- Cort */ \
@@ -92,11 +87,6 @@ _start:
* r4: virtual address of boot_infos_t
* r5: 0
*
- * APUS
- * r3: 'APUS'
- * r4: physical address of memory base
- * Linux/m68k style BootInfo structure at &_end.
- *
* PREP
* This is jumped to on prep systems right after the kernel is relocated
* to its proper place in memory by the boot loader. The expected layout
@@ -150,14 +140,6 @@ __start:
*/
bl early_init
-#ifdef CONFIG_APUS
-/* On APUS the __va/__pa constants need to be set to the correct
- * values before continuing.
- */
- mr r4,r30
- bl fix_mem_constants
-#endif /* CONFIG_APUS */
-
/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
* the physical address we are running at, returned by early_init()
*/
@@ -167,7 +149,7 @@ __after_mmu_off:
bl flush_tlbs
bl initial_bats
-#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+#if defined(CONFIG_BOOTX_TEXT)
bl setup_disp_bat
#endif
@@ -183,7 +165,6 @@ __after_mmu_off:
#endif /* CONFIG_6xx */
-#ifndef CONFIG_APUS
/*
* We need to run with _start at physical address 0.
* On CHRP, we are loaded at 0x10000 since OF on CHRP uses
@@ -196,7 +177,6 @@ __after_mmu_off:
addis r4,r3,KERNELBASE@h /* current address of _start */
cmpwi 0,r4,0 /* are we already running at 0? */
bne relocate_kernel
-#endif /* CONFIG_APUS */
/*
* we now have the 1st 16M of ram mapped with the bats.
* prep needs the mmu to be turned on here, but pmac already has it on.
@@ -881,85 +861,6 @@ _GLOBAL(copy_and_flush)
addi r6,r6,4
blr
-#ifdef CONFIG_APUS
-/*
- * On APUS the physical base address of the kernel is not known at compile
- * time, which means the __pa/__va constants used are incorrect. In the
- * __init section is recorded the virtual addresses of instructions using
- * these constants, so all that has to be done is fix these before
- * continuing the kernel boot.
- *
- * r4 = The physical address of the kernel base.
- */
-fix_mem_constants:
- mr r10,r4
- addis r10,r10,-KERNELBASE@h /* virt_to_phys constant */
- neg r11,r10 /* phys_to_virt constant */
-
- lis r12,__vtop_table_begin@h
- ori r12,r12,__vtop_table_begin@l
- add r12,r12,r10 /* table begin phys address */
- lis r13,__vtop_table_end@h
- ori r13,r13,__vtop_table_end@l
- add r13,r13,r10 /* table end phys address */
- subi r12,r12,4
- subi r13,r13,4
-1: lwzu r14,4(r12) /* virt address of instruction */
- add r14,r14,r10 /* phys address of instruction */
- lwz r15,0(r14) /* instruction, now insert top */
- rlwimi r15,r10,16,16,31 /* half of vp const in low half */
- stw r15,0(r14) /* of instruction and restore. */
- dcbst r0,r14 /* write it to memory */
- sync
- icbi r0,r14 /* flush the icache line */
- cmpw r12,r13
- bne 1b
- sync /* additional sync needed on g4 */
- isync
-
-/*
- * Map the memory where the exception handlers will
- * be copied to when hash constants have been patched.
- */
-#ifdef CONFIG_APUS_FAST_EXCEPT
- lis r8,0xfff0
-#else
- lis r8,0
-#endif
- ori r8,r8,0x2 /* 128KB, supervisor */
- mtspr SPRN_DBAT3U,r8
- mtspr SPRN_DBAT3L,r8
-
- lis r12,__ptov_table_begin@h
- ori r12,r12,__ptov_table_begin@l
- add r12,r12,r10 /* table begin phys address */
- lis r13,__ptov_table_end@h
- ori r13,r13,__ptov_table_end@l
- add r13,r13,r10 /* table end phys address */
- subi r12,r12,4
- subi r13,r13,4
-1: lwzu r14,4(r12) /* virt address of instruction */
- add r14,r14,r10 /* phys address of instruction */
- lwz r15,0(r14) /* instruction, now insert top */
- rlwimi r15,r11,16,16,31 /* half of pv const in low half*/
- stw r15,0(r14) /* of instruction and restore. */
- dcbst r0,r14 /* write it to memory */
- sync
- icbi r0,r14 /* flush the icache line */
- cmpw r12,r13
- bne 1b
-
- sync /* additional sync needed on g4 */
- isync /* No speculative loading until now */
- blr
-
-/***********************************************************************
- * Please note that on APUS the exception handlers are located at the
- * physical address 0xfff0000. For this reason, the exception handlers
- * cannot use relative branches to access the code below.
- ***********************************************************************/
-#endif /* CONFIG_APUS */
-
#ifdef CONFIG_SMP
#ifdef CONFIG_GEMINI
.globl __secondary_start_gemini
@@ -1135,19 +1036,6 @@ start_here:
bl __save_cpu_setup
bl MMU_init
-#ifdef CONFIG_APUS
- /* Copy exception code to exception vector base on APUS. */
- lis r4,KERNELBASE@h
-#ifdef CONFIG_APUS_FAST_EXCEPT
- lis r3,0xfff0 /* Copy to 0xfff00000 */
-#else
- lis r3,0 /* Copy to 0x00000000 */
-#endif
- li r5,0x4000 /* # bytes of memory to copy */
- li r6,0
- bl copy_and_flush /* copy the first 0x4000 bytes */
-#endif /* CONFIG_APUS */
-
/*
* Go back to running unmapped so we can load up new values
* for SDR1 (hash table pointer) and the segment registers
@@ -1324,11 +1212,7 @@ initial_bats:
#else
ori r8,r8,2 /* R/W access */
#endif /* CONFIG_SMP */
-#ifdef CONFIG_APUS
- ori r11,r11,BL_8M<<2|0x2 /* set up 8MB BAT registers for 604 */
-#else
ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */
-#endif /* CONFIG_APUS */
mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */
mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */
@@ -1338,7 +1222,7 @@ initial_bats:
blr
-#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT)
+#ifdef CONFIG_BOOTX_TEXT
setup_disp_bat:
/*
* setup the display bat prepared for us in prom.c
@@ -1362,7 +1246,7 @@ setup_disp_bat:
1: mtspr SPRN_IBAT3L,r8
mtspr SPRN_IBAT3U,r11
blr
-#endif /* !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) */
+#endif /* CONFIG_BOOTX_TEXT */
#ifdef CONFIG_8260
/* Jump into the system reset for the rom.
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 1111fcec7673..8cdd48ea4391 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -103,8 +103,8 @@ __secondary_hold_acknowledge:
. = 0x60
/*
- * The following code is used on pSeries to hold secondary processors
- * in a spin loop after they have been freed from OpenFirmware, but
+ * The following code is used to hold secondary processors
+ * in a spin loop after they have entered the kernel, but
* before the bulk of the kernel has been relocated. This code
* is relocated to physical address 0x60 before prom_init is run.
* All of it must fit below the first exception vector at 0x100.
diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c
index 34ae11494ddc..e31aca9208eb 100644
--- a/arch/powerpc/kernel/io.c
+++ b/arch/powerpc/kernel/io.c
@@ -35,7 +35,7 @@ void _insb(const volatile u8 __iomem *port, void *buf, long count)
asm volatile("sync");
do {
tmp = *port;
- asm volatile("eieio");
+ eieio();
*tbuf++ = tmp;
} while (--count != 0);
asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
@@ -66,7 +66,7 @@ void _insw_ns(const volatile u16 __iomem *port, void *buf, long count)
asm volatile("sync");
do {
tmp = *port;
- asm volatile("eieio");
+ eieio();
*tbuf++ = tmp;
} while (--count != 0);
asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
@@ -97,7 +97,7 @@ void _insl_ns(const volatile u32 __iomem *port, void *buf, long count)
asm volatile("sync");
do {
tmp = *port;
- asm volatile("eieio");
+ eieio();
*tbuf++ = tmp;
} while (--count != 0);
asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
@@ -155,21 +155,21 @@ void _memcpy_fromio(void *dest, const volatile void __iomem *src,
__asm__ __volatile__ ("sync" : : : "memory");
while(n && (!IO_CHECK_ALIGN(vsrc, 4) || !IO_CHECK_ALIGN(dest, 4))) {
*((u8 *)dest) = *((volatile u8 *)vsrc);
- __asm__ __volatile__ ("eieio" : : : "memory");
+ eieio();
vsrc++;
dest++;
n--;
}
while(n > 4) {
*((u32 *)dest) = *((volatile u32 *)vsrc);
- __asm__ __volatile__ ("eieio" : : : "memory");
+ eieio();
vsrc += 4;
dest += 4;
n -= 4;
}
while(n) {
*((u8 *)dest) = *((volatile u8 *)vsrc);
- __asm__ __volatile__ ("eieio" : : : "memory");
+ eieio();
vsrc++;
dest++;
n--;
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index c2b84c64db20..2fc87862146c 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -7,7 +7,6 @@
* Copyright (C) 1996-2001 Cort Dougan
* Adapted for Power Macintosh by Paul Mackerras
* Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -337,7 +336,8 @@ void do_IRQ(struct pt_regs *regs)
void __init init_IRQ(void)
{
- ppc_md.init_IRQ();
+ if (ppc_md.init_IRQ)
+ ppc_md.init_IRQ();
#ifdef CONFIG_PPC64
irq_ctx_init();
#endif
@@ -597,6 +597,49 @@ static void irq_radix_rdunlock(unsigned long flags)
local_irq_restore(flags);
}
+static int irq_setup_virq(struct irq_host *host, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ /* Clear IRQ_NOREQUEST flag */
+ get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;
+
+ /* map it */
+ smp_wmb();
+ irq_map[virq].hwirq = hwirq;
+ smp_mb();
+
+ if (host->ops->map(host, virq, hwirq)) {
+ pr_debug("irq: -> mapping failed, freeing\n");
+ irq_free_virt(virq, 1);
+ return -1;
+ }
+
+ return 0;
+}
+
+unsigned int irq_create_direct_mapping(struct irq_host *host)
+{
+ unsigned int virq;
+
+ if (host == NULL)
+ host = irq_default_host;
+
+ BUG_ON(host == NULL);
+ WARN_ON(host->revmap_type != IRQ_HOST_MAP_NOMAP);
+
+ virq = irq_alloc_virt(host, 1, 0);
+ if (virq == NO_IRQ) {
+ pr_debug("irq: create_direct virq allocation failed\n");
+ return NO_IRQ;
+ }
+
+ pr_debug("irq: create_direct obtained virq %d\n", virq);
+
+ if (irq_setup_virq(host, virq, virq))
+ return NO_IRQ;
+
+ return virq;
+}
unsigned int irq_create_mapping(struct irq_host *host,
irq_hw_number_t hwirq)
@@ -645,18 +688,9 @@ unsigned int irq_create_mapping(struct irq_host *host,
}
pr_debug("irq: -> obtained virq %d\n", virq);
- /* Clear IRQ_NOREQUEST flag */
- get_irq_desc(virq)->status &= ~IRQ_NOREQUEST;
-
- /* map it */
- smp_wmb();
- irq_map[virq].hwirq = hwirq;
- smp_mb();
- if (host->ops->map(host, virq, hwirq)) {
- pr_debug("irq: -> mapping failed, freeing\n");
- irq_free_virt(virq, 1);
+ if (irq_setup_virq(host, virq, hwirq))
return NO_IRQ;
- }
+
return virq;
}
EXPORT_SYMBOL_GPL(irq_create_mapping);
diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c
new file mode 100644
index 000000000000..f0f49d1be3d5
--- /dev/null
+++ b/arch/powerpc/kernel/isa-bridge.c
@@ -0,0 +1,271 @@
+/*
+ * Routines for tracking a legacy ISA bridge
+ *
+ * Copyrigh 2007 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ *
+ * Some bits and pieces moved over from pci_64.c
+ *
+ * Copyrigh 2003 Anton Blanchard <anton@au.ibm.com>, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
+
+unsigned long isa_io_base; /* NULL if no ISA bus */
+EXPORT_SYMBOL(isa_io_base);
+
+/* Cached ISA bridge dev. */
+static struct device_node *isa_bridge_devnode;
+struct pci_dev *isa_bridge_pcidev;
+EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
+
+#define ISA_SPACE_MASK 0x1
+#define ISA_SPACE_IO 0x1
+
+static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
+ unsigned long phb_io_base_phys)
+{
+ /* We should get some saner parsing here and remove these structs */
+ struct pci_address {
+ u32 a_hi;
+ u32 a_mid;
+ u32 a_lo;
+ };
+
+ struct isa_address {
+ u32 a_hi;
+ u32 a_lo;
+ };
+
+ struct isa_range {
+ struct isa_address isa_addr;
+ struct pci_address pci_addr;
+ unsigned int size;
+ };
+
+ const struct isa_range *range;
+ unsigned long pci_addr;
+ unsigned int isa_addr;
+ unsigned int size;
+ int rlen = 0;
+
+ range = of_get_property(isa_node, "ranges", &rlen);
+ if (range == NULL || (rlen < sizeof(struct isa_range)))
+ goto inval_range;
+
+ /* From "ISA Binding to 1275"
+ * The ranges property is laid out as an array of elements,
+ * each of which comprises:
+ * cells 0 - 1: an ISA address
+ * cells 2 - 4: a PCI address
+ * (size depending on dev->n_addr_cells)
+ * cell 5: the size of the range
+ */
+ if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO) {
+ range++;
+ rlen -= sizeof(struct isa_range);
+ if (rlen < sizeof(struct isa_range))
+ goto inval_range;
+ }
+ if ((range->isa_addr.a_hi && ISA_SPACE_MASK) != ISA_SPACE_IO)
+ goto inval_range;
+
+ isa_addr = range->isa_addr.a_lo;
+ pci_addr = (unsigned long) range->pci_addr.a_mid << 32 |
+ range->pci_addr.a_lo;
+
+ /* Assume these are both zero. Note: We could fix that and
+ * do a proper parsing instead ... oh well, that will do for
+ * now as nobody uses fancy mappings for ISA bridges
+ */
+ if ((pci_addr != 0) || (isa_addr != 0)) {
+ printk(KERN_ERR "unexpected isa to pci mapping: %s\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /* Align size and make sure it's cropped to 64K */
+ size = PAGE_ALIGN(range->size);
+ if (size > 0x10000)
+ size = 0x10000;
+
+ printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+ "mapping 64k\n");
+
+ __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
+ size, _PAGE_NO_CACHE|_PAGE_GUARDED);
+ return;
+
+inval_range:
+ printk(KERN_ERR "no ISA IO ranges or unexpected isa range,"
+ "mapping 64k\n");
+ __ioremap_at(phb_io_base_phys, (void *)ISA_IO_BASE,
+ 0x10000, _PAGE_NO_CACHE|_PAGE_GUARDED);
+}
+
+
+/**
+ * isa_bridge_find_early - Find and map the ISA IO space early before
+ * main PCI discovery. This is optionally called by
+ * the arch code when adding PCI PHBs to get early
+ * access to ISA IO ports
+ */
+void __init isa_bridge_find_early(struct pci_controller *hose)
+{
+ struct device_node *np, *parent = NULL, *tmp;
+
+ /* If we already have an ISA bridge, bail off */
+ if (isa_bridge_devnode != NULL)
+ return;
+
+ /* For each "isa" node in the system. Note : we do a search by
+ * type and not by name. It might be better to do by name but that's
+ * what the code used to do and I don't want to break too much at
+ * once. We can look into changing that separately
+ */
+ for_each_node_by_type(np, "isa") {
+ /* Look for our hose being a parent */
+ for (parent = of_get_parent(np); parent;) {
+ if (parent == hose->arch_data) {
+ of_node_put(parent);
+ break;
+ }
+ tmp = parent;
+ parent = of_get_parent(parent);
+ of_node_put(tmp);
+ }
+ if (parent != NULL)
+ break;
+ }
+ if (np == NULL)
+ return;
+ isa_bridge_devnode = np;
+
+ /* Now parse the "ranges" property and setup the ISA mapping */
+ pci_process_ISA_OF_ranges(np, hose->io_base_phys);
+
+ /* Set the global ISA io base to indicate we have an ISA bridge */
+ isa_io_base = ISA_IO_BASE;
+
+ pr_debug("ISA bridge (early) is %s\n", np->full_name);
+}
+
+/**
+ * isa_bridge_find_late - Find and map the ISA IO space upon discovery of
+ * a new ISA bridge
+ */
+static void __devinit isa_bridge_find_late(struct pci_dev *pdev,
+ struct device_node *devnode)
+{
+ struct pci_controller *hose = pci_bus_to_host(pdev->bus);
+
+ /* Store ISA device node and PCI device */
+ isa_bridge_devnode = of_node_get(devnode);
+ isa_bridge_pcidev = pdev;
+
+ /* Now parse the "ranges" property and setup the ISA mapping */
+ pci_process_ISA_OF_ranges(devnode, hose->io_base_phys);
+
+ /* Set the global ISA io base to indicate we have an ISA bridge */
+ isa_io_base = ISA_IO_BASE;
+
+ pr_debug("ISA bridge (late) is %s on %s\n",
+ devnode->full_name, pci_name(pdev));
+}
+
+/**
+ * isa_bridge_remove - Remove/unmap an ISA bridge
+ */
+static void isa_bridge_remove(void)
+{
+ pr_debug("ISA bridge removed !\n");
+
+ /* Clear the global ISA io base to indicate that we have no more
+ * ISA bridge. Note that drivers don't quite handle that, though
+ * we should probably do something about it. But do we ever really
+ * have ISA bridges being removed on machines using legacy devices ?
+ */
+ isa_io_base = ISA_IO_BASE;
+
+ /* Clear references to the bridge */
+ of_node_put(isa_bridge_devnode);
+ isa_bridge_devnode = NULL;
+ isa_bridge_pcidev = NULL;
+
+ /* Unmap the ISA area */
+ __iounmap_at((void *)ISA_IO_BASE, 0x10000);
+}
+
+/**
+ * isa_bridge_notify - Get notified of PCI devices addition/removal
+ */
+static int __devinit isa_bridge_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct device_node *devnode = pci_device_to_OF_node(pdev);
+
+ switch(action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ /* Check if we have an early ISA device, without PCI dev */
+ if (isa_bridge_devnode && isa_bridge_devnode == devnode &&
+ !isa_bridge_pcidev) {
+ pr_debug("ISA bridge PCI attached: %s\n",
+ pci_name(pdev));
+ isa_bridge_pcidev = pdev;
+ }
+
+ /* Check if we have no ISA device, and this happens to be one,
+ * register it as such if it has an OF device
+ */
+ if (!isa_bridge_devnode && devnode && devnode->type &&
+ !strcmp(devnode->type, "isa"))
+ isa_bridge_find_late(pdev, devnode);
+
+ return 0;
+ case BUS_NOTIFY_DEL_DEVICE:
+ /* Check if this our existing ISA device */
+ if (pdev == isa_bridge_pcidev ||
+ (devnode && devnode == isa_bridge_devnode))
+ isa_bridge_remove();
+ return 0;
+ }
+ return 0;
+}
+
+static struct notifier_block isa_bridge_notifier = {
+ .notifier_call = isa_bridge_notify
+};
+
+/**
+ * isa_bridge_init - register to be notified of ISA bridge addition/removal
+ *
+ */
+static int __init isa_bridge_init(void)
+{
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+ bus_register_notifier(&pci_bus_type, &isa_bridge_notifier);
+ return 0;
+}
+arch_initcall(isa_bridge_init);
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 0c96611f02f4..440f5a87271f 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -492,6 +492,13 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
return ret;
}
+#ifdef CONFIG_PPC64
+unsigned long arch_deref_entry_point(void *entry)
+{
+ return (unsigned long)(((func_descr_t *)entry)->entry);
+}
+#endif
+
int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of(p, struct jprobe, kp);
@@ -500,11 +507,9 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs));
/* setup return addr to the jprobe handler routine */
+ regs->nip = arch_deref_entry_point(jp->entry);
#ifdef CONFIG_PPC64
- regs->nip = (unsigned long)(((func_descr_t *)jp->entry)->entry);
regs->gpr[2] = (unsigned long)(((func_descr_t *)jp->entry)->toc);
-#else
- regs->nip = (unsigned long)jp->entry;
#endif
return 1;
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index c492cee90e0f..6444eaa30a2f 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -248,7 +248,7 @@ static void parse_system_parameter_string(struct seq_file *m)
} else {
int splpar_strlen;
int idx, w_idx;
- char *workbuffer = kmalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
+ char *workbuffer = kzalloc(SPLPAR_MAXLENGTH, GFP_KERNEL);
if (!workbuffer) {
printk(KERN_ERR "%s %s kmalloc failure at line %d \n",
__FILE__, __FUNCTION__, __LINE__);
@@ -261,7 +261,6 @@ static void parse_system_parameter_string(struct seq_file *m)
splpar_strlen = local_buffer[0] * 256 + local_buffer[1];
local_buffer += 2; /* step over strlen value */
- memset(workbuffer, 0, SPLPAR_MAXLENGTH);
w_idx = 0;
idx = 0;
while ((*local_buffer) && (idx < splpar_strlen)) {
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 98decf8ebff4..e708ab7ca9e8 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -392,7 +392,7 @@ BEGIN_FTR_SECTION
mtspr SPRN_L1CSR0,r3
isync
blr
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
mfspr r3,SPRN_L1CSR1
ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
mtspr SPRN_L1CSR1,r3
@@ -419,7 +419,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
_GLOBAL(__flush_icache_range)
BEGIN_FTR_SECTION
blr /* for 601, do nothing */
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
li r5,L1_CACHE_BYTES-1
andc r3,r3,r5
subf r4,r3,r4
@@ -514,8 +514,8 @@ _GLOBAL(invalidate_dcache_range)
*/
_GLOBAL(__flush_dcache_icache)
BEGIN_FTR_SECTION
- blr /* for 601, do nothing */
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+ blr
+END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
rlwinm r3,r3,0,0,19 /* Get page base address */
li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */
mtctr r4
@@ -543,7 +543,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
_GLOBAL(__flush_dcache_icache_phys)
BEGIN_FTR_SECTION
blr /* for 601, do nothing */
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
mfmsr r10
rlwinm r0,r10,0,28,26 /* clear DR */
mtmsr r0
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 519861da0423..bbb3ba54c51c 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -646,6 +646,19 @@ _GLOBAL(kexec_sequence)
/* turn off mmu */
bl real_mode
+ /* copy 0x100 bytes starting at start to 0 */
+ li r3,0
+ mr r4,r30 /* start, aka phys mem offset */
+ li r5,0x100
+ li r6,0
+ bl .copy_and_flush /* (dest, src, copy limit, start offset) */
+1: /* assume normal blr return */
+
+ /* release other cpus to the new kernel secondary start at 0x60 */
+ mflr r5
+ li r6,1
+ stw r6,kexec_flag-1b(5)
+
/* clear out hardware hash page table and tlb */
ld r5,0(r27) /* deref function descriptor */
mtctr r5
@@ -676,19 +689,6 @@ _GLOBAL(kexec_sequence)
* are the boot cpu ?????
* other device tree differences (prop sizes, va vs pa, etc)...
*/
-
- /* copy 0x100 bytes starting at start to 0 */
- li r3,0
- mr r4,r30
- li r5,0x100
- li r6,0
- bl .copy_and_flush /* (dest, src, copy limit, start offset) */
-1: /* assume normal blr return */
-
- /* release other cpus to the new kernel secondary start at 0x60 */
- mflr r5
- li r6,1
- stw r6,kexec_flag-1b(5)
mr r3,r25 # my phys cpu
mr r4,r30 # start, aka phys mem offset
mtlr 4
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index a464d67248df..89b911e83c04 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -1,5 +1,6 @@
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
@@ -8,118 +9,6 @@
#include <asm/errno.h>
#include <asm/of_device.h>
-/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- * @ids: array of of device match structures to search in
- * @node: the of device structure to match against
- *
- * Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
- const struct device_node *node)
-{
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
- int match = 1;
- if (matches->name[0])
- match &= node->name
- && !strcmp(matches->name, node->name);
- if (matches->type[0])
- match &= node->type
- && !strcmp(matches->type, node->type);
- if (matches->compatible[0])
- match &= of_device_is_compatible(node,
- matches->compatible);
- if (match)
- return matches;
- matches++;
- }
- return NULL;
-}
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
- const struct of_device *dev)
-{
- if (!dev->node)
- return NULL;
- return of_match_node(matches, dev->node);
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
- struct device *tmp;
-
- if (!dev)
- return NULL;
- tmp = get_device(&dev->dev);
- if (tmp)
- return to_of_device(tmp);
- else
- return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
- if (dev)
- put_device(&dev->dev);
-}
-
-static ssize_t dev_show_devspec(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
- return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
- of_node_put(ofdev->node);
- kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
- int rc;
-
- BUG_ON(ofdev->node == NULL);
-
- rc = device_register(&ofdev->dev);
- if (rc)
- return rc;
-
- return device_create_file(&ofdev->dev, &dev_attr_devspec);
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
- device_remove_file(&ofdev->dev, &dev_attr_devspec);
-
- device_unregister(&ofdev->dev);
-}
-
-
ssize_t of_device_get_modalias(struct of_device *ofdev,
char *str, ssize_t len)
{
@@ -229,14 +118,5 @@ int of_device_uevent(struct device *dev,
return 0;
}
-
-
-EXPORT_SYMBOL(of_match_node);
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
-EXPORT_SYMBOL(of_release_dev);
EXPORT_SYMBOL(of_device_uevent);
EXPORT_SYMBOL(of_device_get_modalias);
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c
index d454f61c9c7c..f70e787d556f 100644
--- a/arch/powerpc/kernel/of_platform.c
+++ b/arch/powerpc/kernel/of_platform.c
@@ -55,94 +55,14 @@ static struct of_device_id of_default_bus_ids[] = {
static atomic_t bus_no_reg_magic;
-/*
- *
- * OF platform device type definition & base infrastructure
- *
- */
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * of_drv = to_of_platform_driver(drv);
- const struct of_device_id * matches = of_drv->match_table;
-
- if (!matches)
- return 0;
-
- return of_match_device(matches, of_dev) != NULL;
-}
-
-static int of_platform_device_probe(struct device *dev)
-{
- int error = -ENODEV;
- struct of_platform_driver *drv;
- struct of_device *of_dev;
- const struct of_device_id *match;
-
- drv = to_of_platform_driver(dev->driver);
- of_dev = to_of_device(dev);
-
- if (!drv->probe)
- return error;
-
- of_dev_get(of_dev);
-
- match = of_match_device(drv->match_table, of_dev);
- if (match)
- error = drv->probe(of_dev, match);
- if (error)
- of_dev_put(of_dev);
-
- return error;
-}
-
-static int of_platform_device_remove(struct device *dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
- if (dev->driver && drv->remove)
- drv->remove(of_dev);
- return 0;
-}
-
-static int of_platform_device_suspend(struct device *dev, pm_message_t state)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->suspend)
- error = drv->suspend(of_dev, state);
- return error;
-}
-
-static int of_platform_device_resume(struct device * dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->resume)
- error = drv->resume(of_dev);
- return error;
-}
-
struct bus_type of_platform_bus_type = {
- .name = "of_platform",
- .match = of_platform_bus_match,
.uevent = of_device_uevent,
- .probe = of_platform_device_probe,
- .remove = of_platform_device_remove,
- .suspend = of_platform_device_suspend,
- .resume = of_platform_device_resume,
};
EXPORT_SYMBOL(of_platform_bus_type);
static int __init of_bus_driver_init(void)
{
- return bus_register(&of_platform_bus_type);
+ return of_bus_type_init(&of_platform_bus_type, "of_platform");
}
postcore_initcall(of_bus_driver_init);
@@ -222,10 +142,9 @@ struct of_device* of_platform_device_create(struct device_node *np,
{
struct of_device *dev;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->node = of_node_get(np);
dev->dma_mask = 0xffffffffUL;
@@ -427,14 +346,6 @@ static int __devinit of_pci_phb_probe(struct of_device *dev,
/* Process "ranges" property */
pci_process_bridge_OF_ranges(phb, dev->node, 0);
- /* Setup IO space. We use the non-dynamic version of that code here,
- * which doesn't quite support unplugging. Next kernel release will
- * have a better fix for this.
- * Note also that we don't do ISA, this will also be fixed with a
- * more massive rework.
- */
- pci_setup_phb_io(phb, pci_io_base == 0);
-
/* Init pci_dn data structures */
pci_devs_phb_init_dynamic(phb);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
new file mode 100644
index 000000000000..fe7d1255e11e
--- /dev/null
+++ b/arch/powerpc/kernel/pci-common.c
@@ -0,0 +1,457 @@
+/*
+ * Contains common pci routines for ALL ppc platform
+ * (based on pci_32.c and pci_64.c)
+ *
+ * Port for PPC64 David Engebretsen, IBM Corp.
+ * Contains common pci routines for ppc64 platform, pSeries and iSeries brands.
+ *
+ * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Rework, based on alpha PCI code.
+ *
+ * Common pmac/prep/chrp pci routines. -- Cort
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/syscalls.h>
+#include <linux/irq.h>
+#include <linux/vmalloc.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/byteorder.h>
+#include <asm/machdep.h>
+#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
+
+#ifdef DEBUG
+#include <asm/udbg.h>
+#define DBG(fmt...) printk(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+static DEFINE_SPINLOCK(hose_spinlock);
+
+/* XXX kill that some day ... */
+int global_phb_number; /* Global phb counter */
+
+extern struct list_head hose_list;
+
+/*
+ * pci_controller(phb) initialized common variables.
+ */
+static void __devinit pci_setup_pci_controller(struct pci_controller *hose)
+{
+ memset(hose, 0, sizeof(struct pci_controller));
+
+ spin_lock(&hose_spinlock);
+ hose->global_number = global_phb_number++;
+ list_add_tail(&hose->list_node, &hose_list);
+ spin_unlock(&hose_spinlock);
+}
+
+struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
+{
+ struct pci_controller *phb;
+
+ if (mem_init_done)
+ phb = kmalloc(sizeof(struct pci_controller), GFP_KERNEL);
+ else
+ phb = alloc_bootmem(sizeof (struct pci_controller));
+ if (phb == NULL)
+ return NULL;
+ pci_setup_pci_controller(phb);
+ phb->arch_data = dev;
+ phb->is_dynamic = mem_init_done;
+#ifdef CONFIG_PPC64
+ if (dev) {
+ int nid = of_node_to_nid(dev);
+
+ if (nid < 0 || !node_online(nid))
+ nid = -1;
+
+ PHB_SET_NODE(phb, nid);
+ }
+#endif
+ return phb;
+}
+
+void pcibios_free_controller(struct pci_controller *phb)
+{
+ spin_lock(&hose_spinlock);
+ list_del(&phb->list_node);
+ spin_unlock(&hose_spinlock);
+
+ if (phb->is_dynamic)
+ kfree(phb);
+}
+
+/*
+ * Return the domain number for this bus.
+ */
+int pci_domain_nr(struct pci_bus *bus)
+{
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+ else {
+ struct pci_controller *hose = pci_bus_to_host(bus);
+
+ return hose->global_number;
+ }
+}
+
+EXPORT_SYMBOL(pci_domain_nr);
+
+#ifdef CONFIG_PPC_OF
+
+/* This routine is meant to be used early during boot, when the
+ * PCI bus numbers have not yet been assigned, and you need to
+ * issue PCI config cycles to an OF device.
+ * It could also be used to "fix" RTAS config cycles if you want
+ * to set pci_assign_all_buses to 1 and still use RTAS for PCI
+ * config cycles.
+ */
+struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
+{
+ if (!have_of)
+ return NULL;
+ while(node) {
+ struct pci_controller *hose, *tmp;
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
+ if (hose->arch_data == node)
+ return hose;
+ node = node->parent;
+ }
+ return NULL;
+}
+
+static ssize_t pci_show_devspec(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev;
+ struct device_node *np;
+
+ pdev = to_pci_dev (dev);
+ np = pci_device_to_OF_node(pdev);
+ if (np == NULL || np->full_name == NULL)
+ return 0;
+ return sprintf(buf, "%s", np->full_name);
+}
+static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
+#endif /* CONFIG_PPC_OF */
+
+/* Add sysfs properties */
+int pcibios_add_platform_entries(struct pci_dev *pdev)
+{
+#ifdef CONFIG_PPC_OF
+ return device_create_file(&pdev->dev, &dev_attr_devspec);
+#else
+ return 0;
+#endif /* CONFIG_PPC_OF */
+
+}
+
+char __devinit *pcibios_setup(char *str)
+{
+ return str;
+}
+
+/*
+ * Reads the interrupt pin to determine if interrupt is use by card.
+ * If the interrupt is used, then gets the interrupt line from the
+ * openfirmware and sets it in the pci_dev and pci_config line.
+ */
+int pci_read_irq_line(struct pci_dev *pci_dev)
+{
+ struct of_irq oirq;
+ unsigned int virq;
+
+ DBG("Try to map irq for %s...\n", pci_name(pci_dev));
+
+#ifdef DEBUG
+ memset(&oirq, 0xff, sizeof(oirq));
+#endif
+ /* Try to get a mapping from the device-tree */
+ if (of_irq_map_pci(pci_dev, &oirq)) {
+ u8 line, pin;
+
+ /* If that fails, lets fallback to what is in the config
+ * space and map that through the default controller. We
+ * also set the type to level low since that's what PCI
+ * interrupts are. If your platform does differently, then
+ * either provide a proper interrupt tree or don't use this
+ * function.
+ */
+ if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
+ return -1;
+ if (pin == 0)
+ return -1;
+ if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
+ line == 0xff) {
+ return -1;
+ }
+ DBG(" -> no map ! Using irq line %d from PCI config\n", line);
+
+ virq = irq_create_mapping(NULL, line);
+ if (virq != NO_IRQ)
+ set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
+ } else {
+ DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
+ oirq.size, oirq.specifier[0], oirq.specifier[1],
+ oirq.controller->full_name);
+
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+ }
+ if(virq == NO_IRQ) {
+ DBG(" -> failed to map !\n");
+ return -1;
+ }
+
+ DBG(" -> mapped to linux irq %d\n", virq);
+
+ pci_dev->irq = virq;
+
+ return 0;
+}
+EXPORT_SYMBOL(pci_read_irq_line);
+
+/*
+ * Platform support for /proc/bus/pci/X/Y mmap()s,
+ * modelled on the sparc64 implementation by Dave Miller.
+ * -- paulus.
+ */
+
+/*
+ * Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
+ *
+ * Basically, the user finds the base address for his device which he wishes
+ * to mmap. They read the 32-bit value from the config space base register,
+ * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
+ * offset parameter of mmap on /proc/bus/pci/XXX for that device.
+ *
+ * Returns negative error code on failure, zero on success.
+ */
+static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
+ resource_size_t *offset,
+ enum pci_mmap_state mmap_state)
+{
+ struct pci_controller *hose = pci_bus_to_host(dev->bus);
+ unsigned long io_offset = 0;
+ int i, res_bit;
+
+ if (hose == 0)
+ return NULL; /* should never happen */
+
+ /* If memory, add on the PCI bridge address offset */
+ if (mmap_state == pci_mmap_mem) {
+#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
+ *offset += hose->pci_mem_offset;
+#endif
+ res_bit = IORESOURCE_MEM;
+ } else {
+ io_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+ *offset += io_offset;
+ res_bit = IORESOURCE_IO;
+ }
+
+ /*
+ * Check that the offset requested corresponds to one of the
+ * resources of the device.
+ */
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+ struct resource *rp = &dev->resource[i];
+ int flags = rp->flags;
+
+ /* treat ROM as memory (should be already) */
+ if (i == PCI_ROM_RESOURCE)
+ flags |= IORESOURCE_MEM;
+
+ /* Active and same type? */
+ if ((flags & res_bit) == 0)
+ continue;
+
+ /* In the range of this resource? */
+ if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
+ continue;
+
+ /* found it! construct the final physical address */
+ if (mmap_state == pci_mmap_io)
+ *offset += hose->io_base_phys - io_offset;
+ return rp;
+ }
+
+ return NULL;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
+ pgprot_t protection,
+ enum pci_mmap_state mmap_state,
+ int write_combine)
+{
+ unsigned long prot = pgprot_val(protection);
+
+ /* Write combine is always 0 on non-memory space mappings. On
+ * memory space, if the user didn't pass 1, we check for a
+ * "prefetchable" resource. This is a bit hackish, but we use
+ * this to workaround the inability of /sysfs to provide a write
+ * combine bit
+ */
+ if (mmap_state != pci_mmap_mem)
+ write_combine = 0;
+ else if (write_combine == 0) {
+ if (rp->flags & IORESOURCE_PREFETCH)
+ write_combine = 1;
+ }
+
+ /* XXX would be nice to have a way to ask for write-through */
+ prot |= _PAGE_NO_CACHE;
+ if (write_combine)
+ prot &= ~_PAGE_GUARDED;
+ else
+ prot |= _PAGE_GUARDED;
+
+ return __pgprot(prot);
+}
+
+/*
+ * This one is used by /dev/mem and fbdev who have no clue about the
+ * PCI device, it tries to find the PCI device first and calls the
+ * above routine
+ */
+pgprot_t pci_phys_mem_access_prot(struct file *file,
+ unsigned long pfn,
+ unsigned long size,
+ pgprot_t protection)
+{
+ struct pci_dev *pdev = NULL;
+ struct resource *found = NULL;
+ unsigned long prot = pgprot_val(protection);
+ unsigned long offset = pfn << PAGE_SHIFT;
+ int i;
+
+ if (page_is_ram(pfn))
+ return __pgprot(prot);
+
+ prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+
+ for_each_pci_dev(pdev) {
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+ struct resource *rp = &pdev->resource[i];
+ int flags = rp->flags;
+
+ /* Active and same type? */
+ if ((flags & IORESOURCE_MEM) == 0)
+ continue;
+ /* In the range of this resource? */
+ if (offset < (rp->start & PAGE_MASK) ||
+ offset > rp->end)
+ continue;
+ found = rp;
+ break;
+ }
+ if (found)
+ break;
+ }
+ if (found) {
+ if (found->flags & IORESOURCE_PREFETCH)
+ prot &= ~_PAGE_GUARDED;
+ pci_dev_put(pdev);
+ }
+
+ DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
+
+ return __pgprot(prot);
+}
+
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture. The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
+{
+ resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
+ struct resource *rp;
+ int ret;
+
+ rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
+ if (rp == NULL)
+ return -EINVAL;
+
+ vma->vm_pgoff = offset >> PAGE_SHIFT;
+ vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
+ vma->vm_page_prot,
+ mmap_state, write_combine);
+
+ ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+ return ret;
+}
+
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+ const struct resource *rsrc,
+ resource_size_t *start, resource_size_t *end)
+{
+ struct pci_controller *hose = pci_bus_to_host(dev->bus);
+ resource_size_t offset = 0;
+
+ if (hose == NULL)
+ return;
+
+ if (rsrc->flags & IORESOURCE_IO)
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+
+ /* We pass a fully fixed up address to userland for MMIO instead of
+ * a BAR value because X is lame and expects to be able to use that
+ * to pass to /dev/mem !
+ *
+ * That means that we'll have potentially 64 bits values where some
+ * userland apps only expect 32 (like X itself since it thinks only
+ * Sparc has 64 bits MMIO) but if we don't do that, we break it on
+ * 32 bits CHRPs :-(
+ *
+ * Hopefully, the sysfs insterface is immune to that gunk. Once X
+ * has been fixed (and the fix spread enough), we can re-enable the
+ * 2 lines below and pass down a BAR value to userland. In that case
+ * we'll also have to re-enable the matching code in
+ * __pci_mmap_make_offset().
+ *
+ * BenH.
+ */
+#if 0
+ else if (rsrc->flags & IORESOURCE_MEM)
+ offset = hose->pci_mem_offset;
+#endif
+
+ *start = rsrc->start - offset;
+ *end = rsrc->end - offset;
+}
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index e66064b5093a..0adf077f3f3a 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -55,8 +55,7 @@ static u8* pci_to_OF_bus_map;
*/
int pci_assign_all_buses;
-struct pci_controller* hose_head;
-struct pci_controller** hose_tail = &hose_head;
+LIST_HEAD(hose_list);
static int pci_bus_count;
@@ -573,58 +572,6 @@ pcibios_assign_resources(void)
}
}
-
-int
-pcibios_enable_resources(struct pci_dev *dev, int mask)
-{
- u16 cmd, old_cmd;
- int idx;
- struct resource *r;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- old_cmd = cmd;
- for (idx=0; idx<6; idx++) {
- /* Only set up the requested stuff */
- if (!(mask & (1<<idx)))
- continue;
-
- r = &dev->resource[idx];
- if (r->flags & IORESOURCE_UNSET) {
- printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev));
- return -EINVAL;
- }
- if (r->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (r->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- if (dev->resource[PCI_ROM_RESOURCE].start)
- cmd |= PCI_COMMAND_MEMORY;
- if (cmd != old_cmd) {
- printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
-}
-
-static int next_controller_index;
-
-struct pci_controller * __init
-pcibios_alloc_controller(void)
-{
- struct pci_controller *hose;
-
- hose = (struct pci_controller *)alloc_bootmem(sizeof(*hose));
- memset(hose, 0, sizeof(struct pci_controller));
-
- *hose_tail = hose;
- hose_tail = &hose->next;
-
- hose->index = next_controller_index++;
-
- return hose;
-}
-
#ifdef CONFIG_PPC_OF
/*
* Functions below are used on OpenFirmware machines.
@@ -670,7 +617,7 @@ void
pcibios_make_OF_bus_map(void)
{
int i;
- struct pci_controller* hose;
+ struct pci_controller *hose, *tmp;
struct property *map_prop;
struct device_node *dn;
@@ -687,7 +634,7 @@ pcibios_make_OF_bus_map(void)
pci_to_OF_bus_map[i] = 0xff;
/* For each hose, we begin searching bridges */
- for(hose=hose_head; hose; hose=hose->next) {
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
struct device_node* node;
node = (struct device_node *)hose->arch_data;
if (!node)
@@ -765,7 +712,7 @@ static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus)
/* Are we a root bus ? */
if (bus->self == NULL || bus->parent == NULL) {
- struct pci_controller *hose = pci_bus_to_hose(bus->number);
+ struct pci_controller *hose = pci_bus_to_host(bus);
if (hose == NULL)
return NULL;
return of_node_get(hose->arch_data);
@@ -818,27 +765,6 @@ pci_device_to_OF_node(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_device_to_OF_node);
-/* This routine is meant to be used early during boot, when the
- * PCI bus numbers have not yet been assigned, and you need to
- * issue PCI config cycles to an OF device.
- * It could also be used to "fix" RTAS config cycles if you want
- * to set pci_assign_all_buses to 1 and still use RTAS for PCI
- * config cycles.
- */
-struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
-{
- if (!have_of)
- return NULL;
- while(node) {
- struct pci_controller* hose;
- for (hose=hose_head;hose;hose=hose->next)
- if (hose->arch_data == node)
- return hose;
- node=node->parent;
- }
- return NULL;
-}
-
static int
find_OF_pci_device_filter(struct device_node* node, void* data)
{
@@ -1027,34 +953,12 @@ pci_create_OF_bus_map(void)
}
}
-static ssize_t pci_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pci_dev *pdev;
- struct device_node *np;
-
- pdev = to_pci_dev (dev);
- np = pci_device_to_OF_node(pdev);
- if (np == NULL || np->full_name == NULL)
- return 0;
- return sprintf(buf, "%s", np->full_name);
-}
-static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
-
#else /* CONFIG_PPC_OF */
void pcibios_make_OF_bus_map(void)
{
}
#endif /* CONFIG_PPC_OF */
-/* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
-{
-#ifdef CONFIG_PPC_OF
- device_create_file(&pdev->dev, &dev_attr_devspec);
-#endif /* CONFIG_PPC_OF */
-}
-
-
#ifdef CONFIG_PPC_PMAC
/*
* This set of routines checks for PCI<->PCI bridges that have closed
@@ -1269,14 +1173,14 @@ pcibios_fixup_p2p_bridges(void)
static int __init
pcibios_init(void)
{
- struct pci_controller *hose;
+ struct pci_controller *hose, *tmp;
struct pci_bus *bus;
- int next_busno;
+ int next_busno = 0;
printk(KERN_INFO "PCI: Probing PCI hardware\n");
/* Scan all of the recorded PCI controllers. */
- for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
if (pci_assign_all_buses)
hose->first_busno = next_busno;
hose->last_busno = 0xff;
@@ -1319,12 +1223,6 @@ pcibios_init(void)
subsys_initcall(pcibios_init);
-unsigned long resource_fixup(struct pci_dev * dev, struct resource * res,
- unsigned long start, unsigned long size)
-{
- return start;
-}
-
void __init pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_controller *hose = (struct pci_controller *) bus->sysdata;
@@ -1342,7 +1240,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
if (!res->flags) {
if (io_offset)
printk(KERN_ERR "I/O resource not set for host"
- " bridge %d\n", hose->index);
+ " bridge %d\n", hose->global_number);
res->start = 0;
res->end = IO_SPACE_LIMIT;
res->flags = IORESOURCE_IO;
@@ -1356,7 +1254,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
if (i > 0)
continue;
printk(KERN_ERR "Memory resource not set for "
- "host bridge %d\n", hose->index);
+ "host bridge %d\n", hose->global_number);
res->start = hose->pci_mem_offset;
res->end = ~0U;
res->flags = IORESOURCE_MEM;
@@ -1370,7 +1268,7 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
for (i = 0; i < 4; ++i) {
if ((res = bus->resource[i]) == NULL)
continue;
- if (!res->flags)
+ if (!res->flags || bus->self->transparent)
continue;
if (io_offset && (res->flags & IORESOURCE_IO)) {
res->start += io_offset;
@@ -1395,11 +1293,6 @@ void __init pcibios_fixup_bus(struct pci_bus *bus)
}
}
-char __init *pcibios_setup(char *str)
-{
- return str;
-}
-
/* the next one is stolen from the alpha port... */
void __init
pcibios_update_irq(struct pci_dev *dev, int irq)
@@ -1408,64 +1301,6 @@ pcibios_update_irq(struct pci_dev *dev, int irq)
/* XXX FIXME - update OF device tree node interrupt property */
}
-#ifdef CONFIG_PPC_MERGE
-/* XXX This is a copy of the ppc64 version. This is temporary until we start
- * merging the 2 PCI layers
- */
-/*
- * Reads the interrupt pin to determine if interrupt is use by card.
- * If the interrupt is used, then gets the interrupt line from the
- * openfirmware and sets it in the pci_dev and pci_config line.
- */
-int pci_read_irq_line(struct pci_dev *pci_dev)
-{
- struct of_irq oirq;
- unsigned int virq;
-
- DBG("Try to map irq for %s...\n", pci_name(pci_dev));
-
- /* Try to get a mapping from the device-tree */
- if (of_irq_map_pci(pci_dev, &oirq)) {
- u8 line, pin;
-
- /* If that fails, lets fallback to what is in the config
- * space and map that through the default controller. We
- * also set the type to level low since that's what PCI
- * interrupts are. If your platform does differently, then
- * either provide a proper interrupt tree or don't use this
- * function.
- */
- if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
- return -1;
- if (pin == 0)
- return -1;
- if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
- line == 0xff) {
- return -1;
- }
- DBG(" -> no map ! Using irq line %d from PCI config\n", line);
-
- virq = irq_create_mapping(NULL, line);
- if (virq != NO_IRQ)
- set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
- } else {
- DBG(" -> got one, spec %d cells (0x%08x...) on %s\n",
- oirq.size, oirq.specifier[0], oirq.controller->full_name);
-
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
- }
- if(virq == NO_IRQ) {
- DBG(" -> failed to map !\n");
- return -1;
- }
- pci_dev->irq = virq;
-
- return 0;
-}
-EXPORT_SYMBOL(pci_read_irq_line);
-#endif /* CONFIG_PPC_MERGE */
-
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
u16 cmd, old_cmd;
@@ -1497,281 +1332,17 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return 0;
}
-struct pci_controller*
+static struct pci_controller*
pci_bus_to_hose(int bus)
{
- struct pci_controller* hose = hose_head;
+ struct pci_controller *hose, *tmp;
- for (; hose; hose = hose->next)
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
if (bus >= hose->first_busno && bus <= hose->last_busno)
return hose;
return NULL;
}
-void __iomem *
-pci_bus_io_base(unsigned int bus)
-{
- struct pci_controller *hose;
-
- hose = pci_bus_to_hose(bus);
- if (!hose)
- return NULL;
- return hose->io_base_virt;
-}
-
-unsigned long
-pci_bus_io_base_phys(unsigned int bus)
-{
- struct pci_controller *hose;
-
- hose = pci_bus_to_hose(bus);
- if (!hose)
- return 0;
- return hose->io_base_phys;
-}
-
-unsigned long
-pci_bus_mem_base_phys(unsigned int bus)
-{
- struct pci_controller *hose;
-
- hose = pci_bus_to_hose(bus);
- if (!hose)
- return 0;
- return hose->pci_mem_offset;
-}
-
-unsigned long
-pci_resource_to_bus(struct pci_dev *pdev, struct resource *res)
-{
- /* Hack alert again ! See comments in chrp_pci.c
- */
- struct pci_controller* hose =
- (struct pci_controller *)pdev->sysdata;
- if (hose && res->flags & IORESOURCE_MEM)
- return res->start - hose->pci_mem_offset;
- /* We may want to do something with IOs here... */
- return res->start;
-}
-
-
-static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
- resource_size_t *offset,
- enum pci_mmap_state mmap_state)
-{
- struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
- unsigned long io_offset = 0;
- int i, res_bit;
-
- if (hose == 0)
- return NULL; /* should never happen */
-
- /* If memory, add on the PCI bridge address offset */
- if (mmap_state == pci_mmap_mem) {
-#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
- *offset += hose->pci_mem_offset;
-#endif
- res_bit = IORESOURCE_MEM;
- } else {
- io_offset = hose->io_base_virt - (void __iomem *)_IO_BASE;
- *offset += io_offset;
- res_bit = IORESOURCE_IO;
- }
-
- /*
- * Check that the offset requested corresponds to one of the
- * resources of the device.
- */
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *rp = &dev->resource[i];
- int flags = rp->flags;
-
- /* treat ROM as memory (should be already) */
- if (i == PCI_ROM_RESOURCE)
- flags |= IORESOURCE_MEM;
-
- /* Active and same type? */
- if ((flags & res_bit) == 0)
- continue;
-
- /* In the range of this resource? */
- if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
- continue;
-
- /* found it! construct the final physical address */
- if (mmap_state == pci_mmap_io)
- *offset += hose->io_base_phys - io_offset;
- return rp;
- }
-
- return NULL;
-}
-
-/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
- pgprot_t protection,
- enum pci_mmap_state mmap_state,
- int write_combine)
-{
- unsigned long prot = pgprot_val(protection);
-
- /* Write combine is always 0 on non-memory space mappings. On
- * memory space, if the user didn't pass 1, we check for a
- * "prefetchable" resource. This is a bit hackish, but we use
- * this to workaround the inability of /sysfs to provide a write
- * combine bit
- */
- if (mmap_state != pci_mmap_mem)
- write_combine = 0;
- else if (write_combine == 0) {
- if (rp->flags & IORESOURCE_PREFETCH)
- write_combine = 1;
- }
-
- /* XXX would be nice to have a way to ask for write-through */
- prot |= _PAGE_NO_CACHE;
- if (write_combine)
- prot &= ~_PAGE_GUARDED;
- else
- prot |= _PAGE_GUARDED;
-
- return __pgprot(prot);
-}
-
-/*
- * This one is used by /dev/mem and fbdev who have no clue about the
- * PCI device, it tries to find the PCI device first and calls the
- * above routine
- */
-pgprot_t pci_phys_mem_access_prot(struct file *file,
- unsigned long pfn,
- unsigned long size,
- pgprot_t protection)
-{
- struct pci_dev *pdev = NULL;
- struct resource *found = NULL;
- unsigned long prot = pgprot_val(protection);
- unsigned long offset = pfn << PAGE_SHIFT;
- int i;
-
- if (page_is_ram(pfn))
- return __pgprot(prot);
-
- prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
-
- for_each_pci_dev(pdev) {
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *rp = &pdev->resource[i];
- int flags = rp->flags;
-
- /* Active and same type? */
- if ((flags & IORESOURCE_MEM) == 0)
- continue;
- /* In the range of this resource? */
- if (offset < (rp->start & PAGE_MASK) ||
- offset > rp->end)
- continue;
- found = rp;
- break;
- }
- if (found)
- break;
- }
- if (found) {
- if (found->flags & IORESOURCE_PREFETCH)
- prot &= ~_PAGE_GUARDED;
- pci_dev_put(pdev);
- }
-
- DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
-
- return __pgprot(prot);
-}
-
-
-/*
- * Perform the actual remap of the pages for a PCI device mapping, as
- * appropriate for this architecture. The region in the process to map
- * is described by vm_start and vm_end members of VMA, the base physical
- * address is found in vm_pgoff.
- * The pci device structure is provided so that architectures may make mapping
- * decisions on a per-device or per-bus basis.
- *
- * Returns a negative error code on failure, zero on success.
- */
-int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state,
- int write_combine)
-{
- resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
- struct resource *rp;
- int ret;
-
- rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
- if (rp == NULL)
- return -EINVAL;
-
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
- vma->vm_page_prot,
- mmap_state, write_combine);
-
- ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot);
-
- return ret;
-}
-
-/* Obsolete functions. Should be removed once the symbios driver
- * is fixed
- */
-unsigned long
-phys_to_bus(unsigned long pa)
-{
- struct pci_controller *hose;
- int i;
-
- for (hose = hose_head; hose; hose = hose->next) {
- for (i = 0; i < 3; ++i) {
- if (pa >= hose->mem_resources[i].start
- && pa <= hose->mem_resources[i].end) {
- /*
- * XXX the hose->pci_mem_offset really
- * only applies to mem_resources[0].
- * We need a way to store an offset for
- * the others. -- paulus
- */
- if (i == 0)
- pa -= hose->pci_mem_offset;
- return pa;
- }
- }
- }
- /* hmmm, didn't find it */
- return 0;
-}
-
-unsigned long
-pci_phys_to_bus(unsigned long pa, int busnr)
-{
- struct pci_controller* hose = pci_bus_to_hose(busnr);
- if (!hose)
- return pa;
- return pa - hose->pci_mem_offset;
-}
-
-unsigned long
-pci_bus_to_phys(unsigned int ba, int busnr)
-{
- struct pci_controller* hose = pci_bus_to_hose(busnr);
- if (!hose)
- return ba;
- return ba + hose->pci_mem_offset;
-}
-
/* Provide information on locations of various I/O regions in physical
* memory. Do this on a per-card basis so that we choose the right
* root bridge.
@@ -1814,62 +1385,11 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
return result;
}
-void pci_resource_to_user(const struct pci_dev *dev, int bar,
- const struct resource *rsrc,
- resource_size_t *start, resource_size_t *end)
-{
- struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
- resource_size_t offset = 0;
-
- if (hose == NULL)
- return;
-
- if (rsrc->flags & IORESOURCE_IO)
- offset = (unsigned long)hose->io_base_virt - _IO_BASE;
-
- /* We pass a fully fixed up address to userland for MMIO instead of
- * a BAR value because X is lame and expects to be able to use that
- * to pass to /dev/mem !
- *
- * That means that we'll have potentially 64 bits values where some
- * userland apps only expect 32 (like X itself since it thinks only
- * Sparc has 64 bits MMIO) but if we don't do that, we break it on
- * 32 bits CHRPs :-(
- *
- * Hopefully, the sysfs insterface is immune to that gunk. Once X
- * has been fixed (and the fix spread enough), we can re-enable the
- * 2 lines below and pass down a BAR value to userland. In that case
- * we'll also have to re-enable the matching code in
- * __pci_mmap_make_offset().
- *
- * BenH.
- */
-#if 0
- else if (rsrc->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-#endif
-
- *start = rsrc->start - offset;
- *end = rsrc->end - offset;
-}
-
-void __init pci_init_resource(struct resource *res, resource_size_t start,
- resource_size_t end, int flags, char *name)
-{
- res->start = start;
- res->end = end;
- res->flags = flags;
- res->name = name;
- res->parent = NULL;
- res->sibling = NULL;
- res->child = NULL;
-}
-
unsigned long pci_address_to_pio(phys_addr_t address)
{
- struct pci_controller* hose = hose_head;
+ struct pci_controller *hose, *tmp;
- for (; hose; hose = hose->next) {
+ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
unsigned int size = hose->io_resource.end -
hose->io_resource.start + 1;
if (address >= hose->io_base_phys &&
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 249cca27a9b8..a97e23ac1976 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -22,6 +22,7 @@
#include <linux/list.h>
#include <linux/syscalls.h>
#include <linux/irq.h>
+#include <linux/vmalloc.h>
#include <asm/processor.h>
#include <asm/io.h>
@@ -41,35 +42,23 @@
unsigned long pci_probe_only = 1;
int pci_assign_all_buses = 0;
-static int pci_initial_scan_done;
static void fixup_resource(struct resource *res, struct pci_dev *dev);
static void do_bus_setup(struct pci_bus *bus);
-static void phbs_remap_io(void);
/* pci_io_base -- the base address from which io bars are offsets.
* This is the lowest I/O base address (so bar values are always positive),
* and it *must* be the start of ISA space if an ISA bus exists because
- * ISA drivers use hard coded offsets. If no ISA bus exists a dummy
- * page is mapped and isa_io_limit prevents access to it.
+ * ISA drivers use hard coded offsets. If no ISA bus exists nothing
+ * is mapped on the first 64K of IO space
*/
-unsigned long isa_io_base; /* NULL if no ISA bus */
-EXPORT_SYMBOL(isa_io_base);
-unsigned long pci_io_base;
+unsigned long pci_io_base = ISA_IO_BASE;
EXPORT_SYMBOL(pci_io_base);
-void iSeries_pcibios_init(void);
-
LIST_HEAD(hose_list);
static struct dma_mapping_ops *pci_dma_ops;
-int global_phb_number; /* Global phb counter */
-
-/* Cached ISA bridge dev. */
-struct pci_dev *ppc64_isabridge_dev = NULL;
-EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
-
void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
{
pci_dma_ops = dma_ops;
@@ -100,7 +89,7 @@ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region
return;
if (res->flags & IORESOURCE_IO)
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
if (res->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
@@ -119,7 +108,7 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
return;
if (res->flags & IORESOURCE_IO)
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
if (res->flags & IORESOURCE_MEM)
offset = hose->pci_mem_offset;
@@ -156,7 +145,7 @@ void pcibios_align_resource(void *data, struct resource *res,
if (res->flags & IORESOURCE_IO) {
unsigned long offset = (unsigned long)hose->io_base_virt -
- pci_io_base;
+ _IO_BASE;
/* Make sure we start at our min on all hoses */
if (start - offset < PCIBIOS_MIN_IO)
start = PCIBIOS_MIN_IO + offset;
@@ -180,55 +169,6 @@ void pcibios_align_resource(void *data, struct resource *res,
res->start = start;
}
-static DEFINE_SPINLOCK(hose_spinlock);
-
-/*
- * pci_controller(phb) initialized common variables.
- */
-static void __devinit pci_setup_pci_controller(struct pci_controller *hose)
-{
- memset(hose, 0, sizeof(struct pci_controller));
-
- spin_lock(&hose_spinlock);
- hose->global_number = global_phb_number++;
- list_add_tail(&hose->list_node, &hose_list);
- spin_unlock(&hose_spinlock);
-}
-
-struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
-{
- struct pci_controller *phb;
-
- if (mem_init_done)
- phb = kmalloc(sizeof(struct pci_controller), GFP_KERNEL);
- else
- phb = alloc_bootmem(sizeof (struct pci_controller));
- if (phb == NULL)
- return NULL;
- pci_setup_pci_controller(phb);
- phb->arch_data = dev;
- phb->is_dynamic = mem_init_done;
- if (dev) {
- int nid = of_node_to_nid(dev);
-
- if (nid < 0 || !node_online(nid))
- nid = -1;
-
- PHB_SET_NODE(phb, nid);
- }
- return phb;
-}
-
-void pcibios_free_controller(struct pci_controller *phb)
-{
- spin_lock(&hose_spinlock);
- list_del(&phb->list_node);
- spin_unlock(&hose_spinlock);
-
- if (phb->is_dynamic)
- kfree(phb);
-}
-
void __devinit pcibios_claim_one_bus(struct pci_bus *b)
{
struct pci_dev *dev;
@@ -291,7 +231,6 @@ static unsigned int pci_parse_of_flags(u32 addr0)
return flags;
}
-#define GET_64BIT(prop, i) ((((u64) (prop)[(i)]) << 32) | (prop)[(i)+1])
static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
{
@@ -310,8 +249,8 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
flags = pci_parse_of_flags(addrs[0]);
if (!flags)
continue;
- base = GET_64BIT(addrs, 1);
- size = GET_64BIT(addrs, 3);
+ base = of_read_number(&addrs[1], 2);
+ size = of_read_number(&addrs[3], 2);
if (!size)
continue;
i = addrs[0] & 0xff;
@@ -367,8 +306,10 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
dev->class = get_int_prop(node, "class-code", 0);
+ dev->revision = get_int_prop(node, "revision-id", 0);
DBG(" class: 0x%x\n", dev->class);
+ DBG(" revision: 0x%x\n", dev->revision);
dev->current_state = 4; /* unknown power state */
dev->error_state = pci_channel_io_normal;
@@ -477,7 +418,7 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
i = 1;
for (; len >= 32; len -= 32, ranges += 8) {
flags = pci_parse_of_flags(ranges[0]);
- size = GET_64BIT(ranges, 6);
+ size = of_read_number(&ranges[6], 2);
if (flags == 0 || size == 0)
continue;
if (flags & IORESOURCE_IO) {
@@ -496,7 +437,7 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
res = bus->resource[i];
++i;
}
- res->start = GET_64BIT(ranges, 1);
+ res->start = of_read_number(&ranges[1], 2);
res->end = res->start + size - 1;
res->flags = flags;
fixup_resource(res, dev);
@@ -535,10 +476,16 @@ void __devinit scan_phb(struct pci_controller *hose)
bus->secondary = hose->first_busno;
hose->bus = bus;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ pcibios_map_io_space(bus);
+
bus->resource[0] = res = &hose->io_resource;
- if (res->flags && request_resource(&ioport_resource, res))
+ if (res->flags && request_resource(&ioport_resource, res)) {
printk(KERN_ERR "Failed to request PCI IO region "
"on PCI domain %04x\n", hose->global_number);
+ DBG("res->start = 0x%016lx, res->end = 0x%016lx\n",
+ res->start, res->end);
+ }
for (i = 0; i < 3; ++i) {
res = &hose->mem_resources[i];
@@ -596,17 +543,6 @@ static int __init pcibios_init(void)
if (ppc_md.pcibios_fixup)
ppc_md.pcibios_fixup();
- /* Cache the location of the ISA bridge (if we have one) */
- ppc64_isabridge_dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
- if (ppc64_isabridge_dev != NULL)
- printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
-
- if (!firmware_has_feature(FW_FEATURE_ISERIES))
- /* map in PCI I/O space */
- phbs_remap_io();
-
- pci_initial_scan_done = 1;
-
printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");
return 0;
@@ -614,11 +550,6 @@ static int __init pcibios_init(void)
subsys_initcall(pcibios_init);
-char __init *pcibios_setup(char *str)
-{
- return str;
-}
-
int pcibios_enable_device(struct pci_dev *dev, int mask)
{
u16 cmd, oldcmd;
@@ -649,22 +580,6 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
return 0;
}
-/*
- * Return the domain number for this bus.
- */
-int pci_domain_nr(struct pci_bus *bus)
-{
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- return 0;
- else {
- struct pci_controller *hose = pci_bus_to_host(bus);
-
- return hose->global_number;
- }
-}
-
-EXPORT_SYMBOL(pci_domain_nr);
-
/* Decide whether to display the domain number in /proc */
int pci_proc_domain(struct pci_bus *bus)
{
@@ -676,281 +591,6 @@ int pci_proc_domain(struct pci_bus *bus)
}
}
-/*
- * Platform support for /proc/bus/pci/X/Y mmap()s,
- * modelled on the sparc64 implementation by Dave Miller.
- * -- paulus.
- */
-
-/*
- * Adjust vm_pgoff of VMA such that it is the physical page offset
- * corresponding to the 32-bit pci bus offset for DEV requested by the user.
- *
- * Basically, the user finds the base address for his device which he wishes
- * to mmap. They read the 32-bit value from the config space base register,
- * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
- * offset parameter of mmap on /proc/bus/pci/XXX for that device.
- *
- * Returns negative error code on failure, zero on success.
- */
-static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
- resource_size_t *offset,
- enum pci_mmap_state mmap_state)
-{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned long io_offset = 0;
- int i, res_bit;
-
- if (hose == 0)
- return NULL; /* should never happen */
-
- /* If memory, add on the PCI bridge address offset */
- if (mmap_state == pci_mmap_mem) {
-#if 0 /* See comment in pci_resource_to_user() for why this is disabled */
- *offset += hose->pci_mem_offset;
-#endif
- res_bit = IORESOURCE_MEM;
- } else {
- io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
- *offset += io_offset;
- res_bit = IORESOURCE_IO;
- }
-
- /*
- * Check that the offset requested corresponds to one of the
- * resources of the device.
- */
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *rp = &dev->resource[i];
- int flags = rp->flags;
-
- /* treat ROM as memory (should be already) */
- if (i == PCI_ROM_RESOURCE)
- flags |= IORESOURCE_MEM;
-
- /* Active and same type? */
- if ((flags & res_bit) == 0)
- continue;
-
- /* In the range of this resource? */
- if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end)
- continue;
-
- /* found it! construct the final physical address */
- if (mmap_state == pci_mmap_io)
- *offset += hose->io_base_phys - io_offset;
- return rp;
- }
-
- return NULL;
-}
-
-/*
- * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp,
- pgprot_t protection,
- enum pci_mmap_state mmap_state,
- int write_combine)
-{
- unsigned long prot = pgprot_val(protection);
-
- /* Write combine is always 0 on non-memory space mappings. On
- * memory space, if the user didn't pass 1, we check for a
- * "prefetchable" resource. This is a bit hackish, but we use
- * this to workaround the inability of /sysfs to provide a write
- * combine bit
- */
- if (mmap_state != pci_mmap_mem)
- write_combine = 0;
- else if (write_combine == 0) {
- if (rp->flags & IORESOURCE_PREFETCH)
- write_combine = 1;
- }
-
- /* XXX would be nice to have a way to ask for write-through */
- prot |= _PAGE_NO_CACHE;
- if (write_combine)
- prot &= ~_PAGE_GUARDED;
- else
- prot |= _PAGE_GUARDED;
-
- return __pgprot(prot);
-}
-
-/*
- * This one is used by /dev/mem and fbdev who have no clue about the
- * PCI device, it tries to find the PCI device first and calls the
- * above routine
- */
-pgprot_t pci_phys_mem_access_prot(struct file *file,
- unsigned long pfn,
- unsigned long size,
- pgprot_t protection)
-{
- struct pci_dev *pdev = NULL;
- struct resource *found = NULL;
- unsigned long prot = pgprot_val(protection);
- unsigned long offset = pfn << PAGE_SHIFT;
- int i;
-
- if (page_is_ram(pfn))
- return __pgprot(prot);
-
- prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
-
- for_each_pci_dev(pdev) {
- for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
- struct resource *rp = &pdev->resource[i];
- int flags = rp->flags;
-
- /* Active and same type? */
- if ((flags & IORESOURCE_MEM) == 0)
- continue;
- /* In the range of this resource? */
- if (offset < (rp->start & PAGE_MASK) ||
- offset > rp->end)
- continue;
- found = rp;
- break;
- }
- if (found)
- break;
- }
- if (found) {
- if (found->flags & IORESOURCE_PREFETCH)
- prot &= ~_PAGE_GUARDED;
- pci_dev_put(pdev);
- }
-
- DBG("non-PCI map for %lx, prot: %lx\n", offset, prot);
-
- return __pgprot(prot);
-}
-
-
-/*
- * Perform the actual remap of the pages for a PCI device mapping, as
- * appropriate for this architecture. The region in the process to map
- * is described by vm_start and vm_end members of VMA, the base physical
- * address is found in vm_pgoff.
- * The pci device structure is provided so that architectures may make mapping
- * decisions on a per-device or per-bus basis.
- *
- * Returns a negative error code on failure, zero on success.
- */
-int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
- enum pci_mmap_state mmap_state, int write_combine)
-{
- resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
- struct resource *rp;
- int ret;
-
- rp = __pci_mmap_make_offset(dev, &offset, mmap_state);
- if (rp == NULL)
- return -EINVAL;
-
- vma->vm_pgoff = offset >> PAGE_SHIFT;
- vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp,
- vma->vm_page_prot,
- mmap_state, write_combine);
-
- ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
- vma->vm_end - vma->vm_start, vma->vm_page_prot);
-
- return ret;
-}
-
-static ssize_t pci_show_devspec(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct pci_dev *pdev;
- struct device_node *np;
-
- pdev = to_pci_dev (dev);
- np = pci_device_to_OF_node(pdev);
- if (np == NULL || np->full_name == NULL)
- return 0;
- return sprintf(buf, "%s", np->full_name);
-}
-static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
-
-void pcibios_add_platform_entries(struct pci_dev *pdev)
-{
- device_create_file(&pdev->dev, &dev_attr_devspec);
-}
-
-#define ISA_SPACE_MASK 0x1
-#define ISA_SPACE_IO 0x1
-
-static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
- unsigned long phb_io_base_phys,
- void __iomem * phb_io_base_virt)
-{
- /* Remove these asap */
-
- struct pci_address {
- u32 a_hi;
- u32 a_mid;
- u32 a_lo;
- };
-
- struct isa_address {
- u32 a_hi;
- u32 a_lo;
- };
-
- struct isa_range {
- struct isa_address isa_addr;
- struct pci_address pci_addr;
- unsigned int size;
- };
-
- const struct isa_range *range;
- unsigned long pci_addr;
- unsigned int isa_addr;
- unsigned int size;
- int rlen = 0;
-
- range = of_get_property(isa_node, "ranges", &rlen);
- if (range == NULL || (rlen < sizeof(struct isa_range))) {
- printk(KERN_ERR "no ISA ranges or unexpected isa range size,"
- "mapping 64k\n");
- __ioremap_explicit(phb_io_base_phys,
- (unsigned long)phb_io_base_virt,
- 0x10000, _PAGE_NO_CACHE | _PAGE_GUARDED);
- return;
- }
-
- /* From "ISA Binding to 1275"
- * The ranges property is laid out as an array of elements,
- * each of which comprises:
- * cells 0 - 1: an ISA address
- * cells 2 - 4: a PCI address
- * (size depending on dev->n_addr_cells)
- * cell 5: the size of the range
- */
- if ((range->isa_addr.a_hi && ISA_SPACE_MASK) == ISA_SPACE_IO) {
- isa_addr = range->isa_addr.a_lo;
- pci_addr = (unsigned long) range->pci_addr.a_mid << 32 |
- range->pci_addr.a_lo;
-
- /* Assume these are both zero */
- if ((pci_addr != 0) || (isa_addr != 0)) {
- printk(KERN_ERR "unexpected isa to pci mapping: %s\n",
- __FUNCTION__);
- return;
- }
-
- size = PAGE_ALIGN(range->size);
-
- __ioremap_explicit(phb_io_base_phys,
- (unsigned long) phb_io_base_virt,
- size, _PAGE_NO_CACHE | _PAGE_GUARDED);
- }
-}
-
void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int prim)
{
@@ -1045,155 +685,122 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
}
}
-void __devinit pci_setup_phb_io(struct pci_controller *hose, int primary)
+#ifdef CONFIG_HOTPLUG
+
+int pcibios_unmap_io_space(struct pci_bus *bus)
{
- unsigned long size = hose->pci_io_size;
- unsigned long io_virt_offset;
- struct resource *res;
- struct device_node *isa_dn;
+ struct pci_controller *hose;
- if (size == 0)
- return;
+ WARN_ON(bus == NULL);
- hose->io_base_virt = reserve_phb_iospace(size);
- DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
- hose->global_number, hose->io_base_phys,
- (unsigned long) hose->io_base_virt);
-
- if (primary) {
- pci_io_base = (unsigned long)hose->io_base_virt;
- isa_dn = of_find_node_by_type(NULL, "isa");
- if (isa_dn) {
- isa_io_base = pci_io_base;
- pci_process_ISA_OF_ranges(isa_dn, hose->io_base_phys,
- hose->io_base_virt);
- of_node_put(isa_dn);
- }
- }
+ /* If this is not a PHB, we only flush the hash table over
+ * the area mapped by this bridge. We don't play with the PTE
+ * mappings since we might have to deal with sub-page alignemnts
+ * so flushing the hash table is the only sane way to make sure
+ * that no hash entries are covering that removed bridge area
+ * while still allowing other busses overlapping those pages
+ */
+ if (bus->self) {
+ struct resource *res = bus->resource[0];
- io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base;
- res = &hose->io_resource;
- res->start += io_virt_offset;
- res->end += io_virt_offset;
+ DBG("IO unmapping for PCI-PCI bridge %s\n",
+ pci_name(bus->self));
- /* If this is called after the initial PCI scan, then we need to
- * proceed to IO mappings now
- */
- if (pci_initial_scan_done)
- __ioremap_explicit(hose->io_base_phys,
- (unsigned long)hose->io_base_virt,
- hose->pci_io_size,
- _PAGE_NO_CACHE | _PAGE_GUARDED);
-}
+ __flush_hash_table_range(&init_mm, res->start + _IO_BASE,
+ res->end - res->start + 1);
+ return 0;
+ }
-void __devinit pci_setup_phb_io_dynamic(struct pci_controller *hose,
- int primary)
-{
- unsigned long size = hose->pci_io_size;
- unsigned long io_virt_offset;
- struct resource *res;
+ /* Get the host bridge */
+ hose = pci_bus_to_host(bus);
- if (size == 0)
- return;
+ /* Check if we have IOs allocated */
+ if (hose->io_base_alloc == 0)
+ return 0;
- hose->io_base_virt = __ioremap(hose->io_base_phys, size,
- _PAGE_NO_CACHE | _PAGE_GUARDED);
- DBG("phb%d io_base_phys 0x%lx io_base_virt 0x%lx\n",
- hose->global_number, hose->io_base_phys,
- (unsigned long) hose->io_base_virt);
+ DBG("IO unmapping for PHB %s\n",
+ ((struct device_node *)hose->arch_data)->full_name);
+ DBG(" alloc=0x%p\n", hose->io_base_alloc);
- if (primary)
- pci_io_base = (unsigned long)hose->io_base_virt;
+ /* This is a PHB, we fully unmap the IO area */
+ vunmap(hose->io_base_alloc);
- io_virt_offset = (unsigned long)hose->io_base_virt - pci_io_base;
- res = &hose->io_resource;
- res->start += io_virt_offset;
- res->end += io_virt_offset;
+ return 0;
}
+EXPORT_SYMBOL_GPL(pcibios_unmap_io_space);
+#endif /* CONFIG_HOTPLUG */
-static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys,
- unsigned long *start_virt, unsigned long *size)
+int __devinit pcibios_map_io_space(struct pci_bus *bus)
{
- struct pci_controller *hose = pci_bus_to_host(bus);
- struct resource *res;
-
- if (bus->self)
- res = bus->resource[0];
- else
- /* Root Bus */
- res = &hose->io_resource;
-
- if (res->end == 0 && res->start == 0)
- return 1;
+ struct vm_struct *area;
+ unsigned long phys_page;
+ unsigned long size_page;
+ unsigned long io_virt_offset;
+ struct pci_controller *hose;
- *start_virt = pci_io_base + res->start;
- *start_phys = *start_virt + hose->io_base_phys
- - (unsigned long) hose->io_base_virt;
+ WARN_ON(bus == NULL);
- if (res->end > res->start)
- *size = res->end - res->start + 1;
- else {
- printk("%s(): unexpected region 0x%lx->0x%lx\n",
- __FUNCTION__, res->start, res->end);
- return 1;
+ /* If this not a PHB, nothing to do, page tables still exist and
+ * thus HPTEs will be faulted in when needed
+ */
+ if (bus->self) {
+ DBG("IO mapping for PCI-PCI bridge %s\n",
+ pci_name(bus->self));
+ DBG(" virt=0x%016lx...0x%016lx\n",
+ bus->resource[0]->start + _IO_BASE,
+ bus->resource[0]->end + _IO_BASE);
+ return 0;
}
- return 0;
-}
-
-int unmap_bus_range(struct pci_bus *bus)
-{
- unsigned long start_phys;
- unsigned long start_virt;
- unsigned long size;
+ /* Get the host bridge */
+ hose = pci_bus_to_host(bus);
+ phys_page = _ALIGN_DOWN(hose->io_base_phys, PAGE_SIZE);
+ size_page = _ALIGN_UP(hose->pci_io_size, PAGE_SIZE);
- if (!bus) {
- printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
- return 1;
- }
-
- if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
- return 1;
- if (__iounmap_explicit((void __iomem *) start_virt, size))
- return 1;
-
- return 0;
-}
-EXPORT_SYMBOL(unmap_bus_range);
+ /* Make sure IO area address is clear */
+ hose->io_base_alloc = NULL;
-int remap_bus_range(struct pci_bus *bus)
-{
- unsigned long start_phys;
- unsigned long start_virt;
- unsigned long size;
+ /* If there's no IO to map on that bus, get away too */
+ if (hose->pci_io_size == 0 || hose->io_base_phys == 0)
+ return 0;
- if (!bus) {
- printk(KERN_ERR "%s() expected bus\n", __FUNCTION__);
- return 1;
- }
-
-
- if (get_bus_io_range(bus, &start_phys, &start_virt, &size))
- return 1;
- if (start_phys == 0)
- return 1;
- printk(KERN_DEBUG "mapping IO %lx -> %lx, size: %lx\n", start_phys, start_virt, size);
- if (__ioremap_explicit(start_phys, start_virt, size,
- _PAGE_NO_CACHE | _PAGE_GUARDED))
- return 1;
+ /* Let's allocate some IO space for that guy. We don't pass
+ * VM_IOREMAP because we don't care about alignment tricks that
+ * the core does in that case. Maybe we should due to stupid card
+ * with incomplete address decoding but I'd rather not deal with
+ * those outside of the reserved 64K legacy region.
+ */
+ area = __get_vm_area(size_page, 0, PHB_IO_BASE, PHB_IO_END);
+ if (area == NULL)
+ return -ENOMEM;
+ hose->io_base_alloc = area->addr;
+ hose->io_base_virt = (void __iomem *)(area->addr +
+ hose->io_base_phys - phys_page);
+
+ DBG("IO mapping for PHB %s\n",
+ ((struct device_node *)hose->arch_data)->full_name);
+ DBG(" phys=0x%016lx, virt=0x%p (alloc=0x%p)\n",
+ hose->io_base_phys, hose->io_base_virt, hose->io_base_alloc);
+ DBG(" size=0x%016lx (alloc=0x%016lx)\n",
+ hose->pci_io_size, size_page);
+
+ /* Establish the mapping */
+ if (__ioremap_at(phys_page, area->addr, size_page,
+ _PAGE_NO_CACHE | _PAGE_GUARDED) == NULL)
+ return -ENOMEM;
+
+ /* Fixup hose IO resource */
+ io_virt_offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+ hose->io_resource.start += io_virt_offset;
+ hose->io_resource.end += io_virt_offset;
+
+ DBG(" hose->io_resource=0x%016lx...0x%016lx\n",
+ hose->io_resource.start, hose->io_resource.end);
return 0;
}
-EXPORT_SYMBOL(remap_bus_range);
-
-static void phbs_remap_io(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
- remap_bus_range(hose->bus);
-}
+EXPORT_SYMBOL_GPL(pcibios_map_io_space);
static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
{
@@ -1201,8 +808,7 @@ static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
unsigned long offset;
if (res->flags & IORESOURCE_IO) {
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
-
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
res->start += offset;
res->end += offset;
} else if (res->flags & IORESOURCE_MEM) {
@@ -1217,9 +823,20 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,
/* Update device resources. */
int i;
- for (i = 0; i < PCI_NUM_RESOURCES; i++)
- if (dev->resource[i].flags)
- fixup_resource(&dev->resource[i], dev);
+ DBG("%s: Fixup resources:\n", pci_name(dev));
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ struct resource *res = &dev->resource[i];
+ if (!res->flags)
+ continue;
+
+ DBG(" 0x%02x < %08lx:0x%016lx...0x%016lx\n",
+ i, res->flags, res->start, res->end);
+
+ fixup_resource(res, dev);
+
+ DBG(" > %08lx:0x%016lx...0x%016lx\n",
+ res->flags, res->start, res->end);
+ }
}
EXPORT_SYMBOL(pcibios_fixup_device_resources);
@@ -1289,119 +906,6 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL(pcibios_fixup_bus);
-/*
- * Reads the interrupt pin to determine if interrupt is use by card.
- * If the interrupt is used, then gets the interrupt line from the
- * openfirmware and sets it in the pci_dev and pci_config line.
- */
-int pci_read_irq_line(struct pci_dev *pci_dev)
-{
- struct of_irq oirq;
- unsigned int virq;
-
- DBG("Try to map irq for %s...\n", pci_name(pci_dev));
-
-#ifdef DEBUG
- memset(&oirq, 0xff, sizeof(oirq));
-#endif
- /* Try to get a mapping from the device-tree */
- if (of_irq_map_pci(pci_dev, &oirq)) {
- u8 line, pin;
-
- /* If that fails, lets fallback to what is in the config
- * space and map that through the default controller. We
- * also set the type to level low since that's what PCI
- * interrupts are. If your platform does differently, then
- * either provide a proper interrupt tree or don't use this
- * function.
- */
- if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_PIN, &pin))
- return -1;
- if (pin == 0)
- return -1;
- if (pci_read_config_byte(pci_dev, PCI_INTERRUPT_LINE, &line) ||
- line == 0xff) {
- return -1;
- }
- DBG(" -> no map ! Using irq line %d from PCI config\n", line);
-
- virq = irq_create_mapping(NULL, line);
- if (virq != NO_IRQ)
- set_irq_type(virq, IRQ_TYPE_LEVEL_LOW);
- } else {
- DBG(" -> got one, spec %d cells (0x%08x 0x%08x...) on %s\n",
- oirq.size, oirq.specifier[0], oirq.specifier[1],
- oirq.controller->full_name);
-
- virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
- oirq.size);
- }
- if(virq == NO_IRQ) {
- DBG(" -> failed to map !\n");
- return -1;
- }
-
- DBG(" -> mapped to linux irq %d\n", virq);
-
- pci_dev->irq = virq;
-
- return 0;
-}
-EXPORT_SYMBOL(pci_read_irq_line);
-
-void pci_resource_to_user(const struct pci_dev *dev, int bar,
- const struct resource *rsrc,
- resource_size_t *start, resource_size_t *end)
-{
- struct pci_controller *hose = pci_bus_to_host(dev->bus);
- resource_size_t offset = 0;
-
- if (hose == NULL)
- return;
-
- if (rsrc->flags & IORESOURCE_IO)
- offset = (unsigned long)hose->io_base_virt - pci_io_base;
-
- /* We pass a fully fixed up address to userland for MMIO instead of
- * a BAR value because X is lame and expects to be able to use that
- * to pass to /dev/mem !
- *
- * That means that we'll have potentially 64 bits values where some
- * userland apps only expect 32 (like X itself since it thinks only
- * Sparc has 64 bits MMIO) but if we don't do that, we break it on
- * 32 bits CHRPs :-(
- *
- * Hopefully, the sysfs insterface is immune to that gunk. Once X
- * has been fixed (and the fix spread enough), we can re-enable the
- * 2 lines below and pass down a BAR value to userland. In that case
- * we'll also have to re-enable the matching code in
- * __pci_mmap_make_offset().
- *
- * BenH.
- */
-#if 0
- else if (rsrc->flags & IORESOURCE_MEM)
- offset = hose->pci_mem_offset;
-#endif
-
- *start = rsrc->start - offset;
- *end = rsrc->end - offset;
-}
-
-struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node)
-{
- if (!have_of)
- return NULL;
- while(node) {
- struct pci_controller *hose, *tmp;
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node)
- if (hose->arch_data == node)
- return hose;
- node = node->parent;
- }
- return NULL;
-}
-
unsigned long pci_address_to_pio(phys_addr_t address)
{
struct pci_controller *hose, *tmp;
@@ -1410,7 +914,7 @@ unsigned long pci_address_to_pio(phys_addr_t address)
if (address >= hose->io_base_phys &&
address < (hose->io_base_phys + hose->pci_io_size)) {
unsigned long base =
- (unsigned long)hose->io_base_virt - pci_io_base;
+ (unsigned long)hose->io_base_virt - _IO_BASE;
return base + (address - hose->io_base_phys);
}
}
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index c96fa9bd35a4..a20f1951a5ce 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -67,7 +67,6 @@ EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
EXPORT_SYMBOL(DMA_MODE_READ);
EXPORT_SYMBOL(DMA_MODE_WRITE);
-EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(transfer_to_handler);
EXPORT_SYMBOL(do_IRQ);
EXPORT_SYMBOL(machine_check_exception);
@@ -106,10 +105,6 @@ EXPORT_SYMBOL(isa_mem_base);
EXPORT_SYMBOL(pci_dram_offset);
EXPORT_SYMBOL(pci_alloc_consistent);
EXPORT_SYMBOL(pci_free_consistent);
-EXPORT_SYMBOL(pci_bus_io_base);
-EXPORT_SYMBOL(pci_bus_io_base_phys);
-EXPORT_SYMBOL(pci_bus_mem_base_phys);
-EXPORT_SYMBOL(pci_bus_to_hose);
#endif /* CONFIG_PCI */
EXPORT_SYMBOL(start_thread);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 6e2f03566b0d..84f000a45e36 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -219,22 +219,26 @@ void discard_lazy_cpu_state(void)
}
#endif /* CONFIG_SMP */
-#ifdef CONFIG_PPC_MERGE /* XXX for now */
int set_dabr(unsigned long dabr)
{
+#ifdef CONFIG_PPC_MERGE /* XXX for now */
if (ppc_md.set_dabr)
return ppc_md.set_dabr(dabr);
+#endif
+ /* XXX should we have a CPU_FTR_HAS_DABR ? */
+#if defined(CONFIG_PPC64) || defined(CONFIG_6xx)
mtspr(SPRN_DABR, dabr);
+#endif
return 0;
}
-#endif
#ifdef CONFIG_PPC64
DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
-static DEFINE_PER_CPU(unsigned long, current_dabr);
#endif
+static DEFINE_PER_CPU(unsigned long, current_dabr);
+
struct task_struct *__switch_to(struct task_struct *prev,
struct task_struct *new)
{
@@ -299,12 +303,10 @@ struct task_struct *__switch_to(struct task_struct *prev,
#endif /* CONFIG_SMP */
-#ifdef CONFIG_PPC64 /* for now */
if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) {
set_dabr(new->thread.dabr);
__get_cpu_var(current_dabr) = new->thread.dabr;
}
-#endif /* CONFIG_PPC64 */
new_thread = &new->thread;
old_thread = &current->thread;
@@ -473,12 +475,10 @@ void flush_thread(void)
discard_lazy_cpu_state();
-#ifdef CONFIG_PPC64 /* for now */
if (current->thread.dabr) {
current->thread.dabr = 0;
set_dabr(0);
}
-#endif
}
void
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index af42ddab3ab4..a38197b12d3e 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -52,6 +52,7 @@
#include <asm/pSeries_reconfig.h>
#include <asm/pci-bridge.h>
#include <asm/kexec.h>
+#include <asm/system.h>
#ifdef DEBUG
#define DBG(fmt...) printk(KERN_ERR fmt)
@@ -77,12 +78,9 @@ static struct boot_param_header *initial_boot_params __initdata;
struct boot_param_header *initial_boot_params;
#endif
-static struct device_node *allnodes = NULL;
+extern struct device_node *allnodes; /* temporary while merging */
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
+extern rwlock_t devtree_lock; /* temporary while merging */
/* export that to outside world */
struct device_node *of_chosen;
@@ -1005,7 +1003,7 @@ static void __init early_reserve_mem(void)
void __init early_init_devtree(void *params)
{
- DBG(" -> early_init_devtree()\n");
+ DBG(" -> early_init_devtree(%p)\n", params);
/* Setup flat device-tree pointer */
initial_boot_params = params;
@@ -1055,62 +1053,6 @@ void __init early_init_devtree(void *params)
DBG(" <- early_init_devtree()\n");
}
-#undef printk
-
-int of_n_addr_cells(struct device_node* np)
-{
- const int *ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#address-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #address-cells property for the root node, default to 1 */
- return 1;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node* np)
-{
- const int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#size-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #size-cells property for the root node, default to 1 */
- return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
-/** Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
- */
-int of_device_is_compatible(const struct device_node *device,
- const char *compat)
-{
- const char* cp;
- int cplen, l;
-
- cp = of_get_property(device, "compatible", &cplen);
- if (cp == NULL)
- return 0;
- while (cplen > 0) {
- if (strncasecmp(cp, compat, strlen(compat)) == 0)
- return 1;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
/**
* Indicates whether the root node has a given value in its
@@ -1142,119 +1084,6 @@ EXPORT_SYMBOL(machine_is_compatible);
*******/
/**
- * of_find_node_by_name - Find a node by its "name" property
- * @from: The node to start searching from or NULL, the node
- * you pass will not be searched, only the next one
- * will; typically, you pass what the previous call
- * returned. of_node_put() will be called on it
- * @name: The name string to match against
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name)
-{
- struct device_node *np;
-
- read_lock(&devtree_lock);
- np = from ? from->allnext : allnodes;
- for (; np != NULL; np = np->allnext)
- if (np->name != NULL && strcasecmp(np->name, name) == 0
- && of_node_get(np))
- break;
- of_node_put(from);
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-/**
- * of_find_node_by_type - Find a node by its "device_type" property
- * @from: The node to start searching from, or NULL to start searching
- * the entire device tree. The node you pass will not be
- * searched, only the next one will; typically, you pass
- * what the previous call returned. of_node_put() will be
- * called on from for you.
- * @type: The type string to match against
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_type(struct device_node *from,
- const char *type)
-{
- struct device_node *np;
-
- read_lock(&devtree_lock);
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext)
- if (np->type != 0 && strcasecmp(np->type, type) == 0
- && of_node_get(np))
- break;
- of_node_put(from);
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-/**
- * of_find_compatible_node - Find a node based on type and one of the
- * tokens in its "compatible" property
- * @from: The node to start searching from or NULL, the node
- * you pass will not be searched, only the next one
- * will; typically, you pass what the previous call
- * returned. of_node_put() will be called on it
- * @type: The type string to match "device_type" or NULL to ignore
- * @compatible: The string to match to one of the tokens in the device
- * "compatible" list.
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_compatible_node(struct device_node *from,
- const char *type, const char *compatible)
-{
- struct device_node *np;
-
- read_lock(&devtree_lock);
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext) {
- if (type != NULL
- && !(np->type != 0 && strcasecmp(np->type, type) == 0))
- continue;
- if (of_device_is_compatible(np, compatible) && of_node_get(np))
- break;
- }
- of_node_put(from);
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-/**
- * of_find_node_by_path - Find a node matching a full OF path
- * @path: The full path to match
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_find_node_by_path(const char *path)
-{
- struct device_node *np = allnodes;
-
- read_lock(&devtree_lock);
- for (; np != 0; np = np->allnext) {
- if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0
- && of_node_get(np))
- break;
- }
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
-
-/**
* of_find_node_by_phandle - Find a node given a phandle
* @handle: phandle of the node to find
*
@@ -1299,51 +1128,6 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
EXPORT_SYMBOL(of_find_all_nodes);
/**
- * of_get_parent - Get a node's parent if any
- * @node: Node to get parent
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_get_parent(const struct device_node *node)
-{
- struct device_node *np;
-
- if (!node)
- return NULL;
-
- read_lock(&devtree_lock);
- np = of_node_get(node->parent);
- read_unlock(&devtree_lock);
- return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-/**
- * of_get_next_child - Iterate a node childs
- * @node: parent node
- * @prev: previous child of the parent node, or NULL to get first
- *
- * Returns a node pointer with refcount incremented, use
- * of_node_put() on it when done.
- */
-struct device_node *of_get_next_child(const struct device_node *node,
- struct device_node *prev)
-{
- struct device_node *next;
-
- read_lock(&devtree_lock);
- next = prev ? prev->sibling : node->child;
- for (; next != 0; next = next->sibling)
- if (of_node_get(next))
- break;
- of_node_put(prev);
- read_unlock(&devtree_lock);
- return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-/**
* of_node_get - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to
* simplify writing of callers
@@ -1375,8 +1159,17 @@ static void of_node_release(struct kref *kref)
struct device_node *node = kref_to_device_node(kref);
struct property *prop = node->properties;
- if (!OF_IS_DYNAMIC(node))
+ /* We should never be releasing nodes that haven't been detached. */
+ if (!of_node_check_flag(node, OF_DETACHED)) {
+ printk("WARNING: Bad of_node_put() on %s\n", node->full_name);
+ dump_stack();
+ kref_init(&node->kref);
+ return;
+ }
+
+ if (!of_node_check_flag(node, OF_DYNAMIC))
return;
+
while (prop) {
struct property *next = prop->next;
kfree(prop->name);
@@ -1425,13 +1218,15 @@ void of_attach_node(struct device_node *np)
* a reference to the node. The memory associated with the node
* is not freed until its refcount goes to zero.
*/
-void of_detach_node(const struct device_node *np)
+void of_detach_node(struct device_node *np)
{
struct device_node *parent;
write_lock(&devtree_lock);
parent = np->parent;
+ if (!parent)
+ goto out_unlock;
if (allnodes == np)
allnodes = np->allnext;
@@ -1455,6 +1250,9 @@ void of_detach_node(const struct device_node *np)
prevsib->sibling = np->sibling;
}
+ of_node_set_flag(np, OF_DETACHED);
+
+out_unlock:
write_unlock(&devtree_lock);
}
@@ -1530,37 +1328,6 @@ static int __init prom_reconfig_setup(void)
__initcall(prom_reconfig_setup);
#endif
-struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp)
-{
- struct property *pp;
-
- read_lock(&devtree_lock);
- for (pp = np->properties; pp != 0; pp = pp->next)
- if (strcmp(pp->name, name) == 0) {
- if (lenp != 0)
- *lenp = pp->length;
- break;
- }
- read_unlock(&devtree_lock);
-
- return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
- int *lenp)
-{
- struct property *pp = of_find_property(np,name,lenp);
- return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
/*
* Add a property to a node
*/
@@ -1716,22 +1483,18 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread)
}
EXPORT_SYMBOL(of_get_cpu_node);
-#ifdef DEBUG
+#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
static struct debugfs_blob_wrapper flat_dt_blob;
static int __init export_flat_device_tree(void)
{
struct dentry *d;
- d = debugfs_create_dir("powerpc", NULL);
- if (!d)
- return 1;
-
flat_dt_blob.data = initial_boot_params;
flat_dt_blob.size = initial_boot_params->totalsize;
d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
- d, &flat_dt_blob);
+ powerpc_debugfs_root, &flat_dt_blob);
if (!d)
return 1;
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index d6047c441034..a1d582e38627 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -635,6 +635,7 @@ static void __init early_cmdline_parse(void)
/* ibm,dynamic-reconfiguration-memory property supported */
#define OV5_DRCONF_MEMORY 0x20
#define OV5_LARGE_PAGES 0x10 /* large pages supported */
+#define OV5_DONATE_DEDICATE_CPU 0x02 /* donate dedicated CPU support */
/* PCIe/MSI support. Without MSI full PCIe is not supported */
#ifdef CONFIG_PCI_MSI
#define OV5_MSI 0x01 /* PCIe/MSI support */
@@ -685,7 +686,8 @@ static unsigned char ibm_architecture_vec[] = {
/* option vector 5: PAPR/OF options */
3 - 2, /* length */
0, /* don't ignore, don't halt */
- OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY | OV5_MSI,
+ OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
+ OV5_DONATE_DEDICATE_CPU | OV5_MSI,
};
/* Old method - ELF header with PT_NOTE sections */
diff --git a/arch/powerpc/kernel/ptrace-common.h b/arch/powerpc/kernel/ptrace-common.h
deleted file mode 100644
index 8797ae737a7b..000000000000
--- a/arch/powerpc/kernel/ptrace-common.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2002 Stephen Rothwell, IBM Coproration
- * Extracted from ptrace.c and ptrace32.c
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file README.legal in the main directory of
- * this archive for more details.
- */
-
-#ifndef _PPC64_PTRACE_COMMON_H
-#define _PPC64_PTRACE_COMMON_H
-
-#include <asm/system.h>
-
-/*
- * Set of msr bits that gdb can change on behalf of a process.
- */
-#define MSR_DEBUGCHANGE (MSR_FE0 | MSR_SE | MSR_BE | MSR_FE1)
-
-/*
- * Get contents of register REGNO in task TASK.
- */
-static inline unsigned long get_reg(struct task_struct *task, int regno)
-{
- unsigned long tmp = 0;
-
- /*
- * Put the correct FP bits in, they might be wrong as a result
- * of our lazy FP restore.
- */
- if (regno == PT_MSR) {
- tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
- tmp |= task->thread.fpexc_mode;
- } else if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long))) {
- tmp = ((unsigned long *)task->thread.regs)[regno];
- }
-
- return tmp;
-}
-
-/*
- * Write contents of register REGNO in task TASK.
- */
-static inline int put_reg(struct task_struct *task, int regno,
- unsigned long data)
-{
- if (regno < PT_SOFTE) {
- if (regno == PT_MSR)
- data = (data & MSR_DEBUGCHANGE)
- | (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
- ((unsigned long *)task->thread.regs)[regno] = data;
- return 0;
- }
- return -EIO;
-}
-
-static inline void set_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
- if (regs != NULL)
- regs->msr |= MSR_SE;
- set_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-
-static inline void clear_single_step(struct task_struct *task)
-{
- struct pt_regs *regs = task->thread.regs;
- if (regs != NULL)
- regs->msr &= ~MSR_SE;
- clear_tsk_thread_flag(task, TIF_SINGLESTEP);
-}
-
-#ifdef CONFIG_ALTIVEC
-/*
- * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
- * The transfer totals 34 quadword. Quadwords 0-31 contain the
- * corresponding vector registers. Quadword 32 contains the vscr as the
- * last word (offset 12) within that quadword. Quadword 33 contains the
- * vrsave as the first word (offset 0) within the quadword.
- *
- * This definition of the VMX state is compatible with the current PPC32
- * ptrace interface. This allows signal handling and ptrace to use the
- * same structures. This also simplifies the implementation of a bi-arch
- * (combined (32- and 64-bit) gdb.
- */
-
-/*
- * Get contents of AltiVec register state in task TASK
- */
-static inline int get_vrregs(unsigned long __user *data,
- struct task_struct *task)
-{
- unsigned long regsize;
-
- /* copy AltiVec registers VR[0] .. VR[31] */
- regsize = 32 * sizeof(vector128);
- if (copy_to_user(data, task->thread.vr, regsize))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VSCR */
- regsize = 1 * sizeof(vector128);
- if (copy_to_user(data, &task->thread.vscr, regsize))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VRSAVE */
- if (put_user(task->thread.vrsave, (u32 __user *)data))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Write contents of AltiVec register state into task TASK.
- */
-static inline int set_vrregs(struct task_struct *task,
- unsigned long __user *data)
-{
- unsigned long regsize;
-
- /* copy AltiVec registers VR[0] .. VR[31] */
- regsize = 32 * sizeof(vector128);
- if (copy_from_user(task->thread.vr, data, regsize))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VSCR */
- regsize = 1 * sizeof(vector128);
- if (copy_from_user(&task->thread.vscr, data, regsize))
- return -EFAULT;
- data += (regsize / sizeof(unsigned long));
-
- /* copy VRSAVE */
- if (get_user(task->thread.vrsave, (u32 __user *)data))
- return -EFAULT;
-
- return 0;
-}
-#endif
-
-static inline int ptrace_set_debugreg(struct task_struct *task,
- unsigned long addr, unsigned long data)
-{
- /* We only support one DABR and no IABRS at the moment */
- if (addr > 0)
- return -EINVAL;
-
- /* The bottom 3 bits are flags */
- if ((data & ~0x7UL) >= TASK_SIZE)
- return -EIO;
-
- /* Ensure translation is on */
- if (data && !(data & DABR_TRANSLATION))
- return -EIO;
-
- task->thread.dabr = data;
- return 0;
-}
-
-#endif /* _PPC64_PTRACE_COMMON_H */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index bf76562167c3..8a177bd9eab4 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -35,11 +35,11 @@
#include <asm/pgtable.h>
#include <asm/system.h>
-#ifdef CONFIG_PPC64
-#include "ptrace-common.h"
-#endif
+/*
+ * does not yet catch signals sent when the child dies.
+ * in exit.c or in signal.c.
+ */
-#ifdef CONFIG_PPC32
/*
* Set of msr bits that gdb can change on behalf of a process.
*/
@@ -48,65 +48,117 @@
#else
#define MSR_DEBUGCHANGE (MSR_SE | MSR_BE)
#endif
-#endif /* CONFIG_PPC32 */
/*
- * does not yet catch signals sent when the child dies.
- * in exit.c or in signal.c.
+ * Max register writeable via put_reg
*/
-
#ifdef CONFIG_PPC32
+#define PT_MAX_PUT_REG PT_MQ
+#else
+#define PT_MAX_PUT_REG PT_CCR
+#endif
+
/*
* Get contents of register REGNO in task TASK.
*/
-static inline unsigned long get_reg(struct task_struct *task, int regno)
+unsigned long ptrace_get_reg(struct task_struct *task, int regno)
{
- if (regno < sizeof(struct pt_regs) / sizeof(unsigned long)
- && task->thread.regs != NULL)
+ unsigned long tmp = 0;
+
+ if (task->thread.regs == NULL)
+ return -EIO;
+
+ if (regno == PT_MSR) {
+ tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
+ return tmp | task->thread.fpexc_mode;
+ }
+
+ if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
return ((unsigned long *)task->thread.regs)[regno];
- return (0);
+
+ return -EIO;
}
/*
* Write contents of register REGNO in task TASK.
*/
-static inline int put_reg(struct task_struct *task, int regno,
- unsigned long data)
+int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
{
- if (regno <= PT_MQ && task->thread.regs != NULL) {
+ if (task->thread.regs == NULL)
+ return -EIO;
+
+ if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
if (regno == PT_MSR)
data = (data & MSR_DEBUGCHANGE)
| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
+ /* We prevent mucking around with the reserved area of trap
+ * which are used internally by the kernel
+ */
+ if (regno == PT_TRAP)
+ data &= 0xfff0;
((unsigned long *)task->thread.regs)[regno] = data;
return 0;
}
return -EIO;
}
+
+static int get_fpregs(void __user *data, struct task_struct *task,
+ int has_fpscr)
+{
+ unsigned int count = has_fpscr ? 33 : 32;
+
+ if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_fpregs(void __user *data, struct task_struct *task,
+ int has_fpscr)
+{
+ unsigned int count = has_fpscr ? 33 : 32;
+
+ if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
+ return -EFAULT;
+ return 0;
+}
+
+
#ifdef CONFIG_ALTIVEC
/*
+ * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go.
+ * The transfer totals 34 quadword. Quadwords 0-31 contain the
+ * corresponding vector registers. Quadword 32 contains the vscr as the
+ * last word (offset 12) within that quadword. Quadword 33 contains the
+ * vrsave as the first word (offset 0) within the quadword.
+ *
+ * This definition of the VMX state is compatible with the current PPC32
+ * ptrace interface. This allows signal handling and ptrace to use the
+ * same structures. This also simplifies the implementation of a bi-arch
+ * (combined (32- and 64-bit) gdb.
+ */
+
+/*
* Get contents of AltiVec register state in task TASK
*/
-static inline int get_vrregs(unsigned long __user *data, struct task_struct *task)
+static int get_vrregs(unsigned long __user *data, struct task_struct *task)
{
- int i, j;
-
- if (!access_ok(VERIFY_WRITE, data, 133 * sizeof(unsigned long)))
- return -EFAULT;
+ unsigned long regsize;
/* copy AltiVec registers VR[0] .. VR[31] */
- for (i = 0; i < 32; i++)
- for (j = 0; j < 4; j++, data++)
- if (__put_user(task->thread.vr[i].u[j], data))
- return -EFAULT;
+ regsize = 32 * sizeof(vector128);
+ if (copy_to_user(data, task->thread.vr, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
/* copy VSCR */
- for (i = 0; i < 4; i++, data++)
- if (__put_user(task->thread.vscr.u[i], data))
- return -EFAULT;
+ regsize = 1 * sizeof(vector128);
+ if (copy_to_user(data, &task->thread.vscr, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
- /* copy VRSAVE */
- if (__put_user(task->thread.vrsave, data))
+ /* copy VRSAVE */
+ if (put_user(task->thread.vrsave, (u32 __user *)data))
return -EFAULT;
return 0;
@@ -115,31 +167,29 @@ static inline int get_vrregs(unsigned long __user *data, struct task_struct *tas
/*
* Write contents of AltiVec register state into task TASK.
*/
-static inline int set_vrregs(struct task_struct *task, unsigned long __user *data)
+static int set_vrregs(struct task_struct *task, unsigned long __user *data)
{
- int i, j;
-
- if (!access_ok(VERIFY_READ, data, 133 * sizeof(unsigned long)))
- return -EFAULT;
+ unsigned long regsize;
/* copy AltiVec registers VR[0] .. VR[31] */
- for (i = 0; i < 32; i++)
- for (j = 0; j < 4; j++, data++)
- if (__get_user(task->thread.vr[i].u[j], data))
- return -EFAULT;
+ regsize = 32 * sizeof(vector128);
+ if (copy_from_user(task->thread.vr, data, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
/* copy VSCR */
- for (i = 0; i < 4; i++, data++)
- if (__get_user(task->thread.vscr.u[i], data))
- return -EFAULT;
+ regsize = 1 * sizeof(vector128);
+ if (copy_from_user(&task->thread.vscr, data, regsize))
+ return -EFAULT;
+ data += (regsize / sizeof(unsigned long));
/* copy VRSAVE */
- if (__get_user(task->thread.vrsave, data))
+ if (get_user(task->thread.vrsave, (u32 __user *)data))
return -EFAULT;
return 0;
}
-#endif
+#endif /* CONFIG_ALTIVEC */
#ifdef CONFIG_SPE
@@ -156,7 +206,7 @@ static inline int set_vrregs(struct task_struct *task, unsigned long __user *dat
/*
* Get contents of SPE register state in task TASK.
*/
-static inline int get_evrregs(unsigned long *data, struct task_struct *task)
+static int get_evrregs(unsigned long *data, struct task_struct *task)
{
int i;
@@ -182,7 +232,7 @@ static inline int get_evrregs(unsigned long *data, struct task_struct *task)
/*
* Write contents of SPE register state into task TASK.
*/
-static inline int set_evrregs(struct task_struct *task, unsigned long *data)
+static int set_evrregs(struct task_struct *task, unsigned long *data)
{
int i;
@@ -205,8 +255,8 @@ static inline int set_evrregs(struct task_struct *task, unsigned long *data)
}
#endif /* CONFIG_SPE */
-static inline void
-set_single_step(struct task_struct *task)
+
+static void set_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
@@ -221,8 +271,7 @@ set_single_step(struct task_struct *task)
set_tsk_thread_flag(task, TIF_SINGLESTEP);
}
-static inline void
-clear_single_step(struct task_struct *task)
+static void clear_single_step(struct task_struct *task)
{
struct pt_regs *regs = task->thread.regs;
@@ -236,7 +285,25 @@ clear_single_step(struct task_struct *task)
}
clear_tsk_thread_flag(task, TIF_SINGLESTEP);
}
-#endif /* CONFIG_PPC32 */
+
+static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr,
+ unsigned long data)
+{
+ /* We only support one DABR and no IABRS at the moment */
+ if (addr > 0)
+ return -EINVAL;
+
+ /* The bottom 3 bits are flags */
+ if ((data & ~0x7UL) >= TASK_SIZE)
+ return -EIO;
+
+ /* Ensure translation is on */
+ if (data && !(data & DABR_TRANSLATION))
+ return -EIO;
+
+ task->thread.dabr = data;
+ return 0;
+}
/*
* Called by kernel/ptrace.c when detaching..
@@ -249,6 +316,62 @@ void ptrace_disable(struct task_struct *child)
clear_single_step(child);
}
+/*
+ * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
+ * we mark them as obsolete now, they will be removed in a future version
+ */
+static long arch_ptrace_old(struct task_struct *child, long request, long addr,
+ long data)
+{
+ int ret = -EPERM;
+
+ switch(request) {
+ case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned long __user *tmp = (unsigned long __user *)addr;
+
+ for (i = 0; i < 32; i++) {
+ ret = put_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned long __user *tmp = (unsigned long __user *)addr;
+
+ for (i = 0; i < 32; i++) {
+ ret = get_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
+ flush_fp_to_thread(child);
+ ret = get_fpregs((void __user *)addr, child, 0);
+ break;
+ }
+
+ case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
+ flush_fp_to_thread(child);
+ ret = set_fpregs((void __user *)addr, child, 0);
+ break;
+ }
+
+ }
+ return ret;
+}
+
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
int ret = -EPERM;
@@ -256,17 +379,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long __user *) data);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -284,11 +399,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#endif
break;
-#ifdef CONFIG_PPC32
CHECK_FULL_REGS(child->thread.regs);
-#endif
if (index < PT_FPR0) {
- tmp = get_reg(child, (int) index);
+ tmp = ptrace_get_reg(child, (int) index);
} else {
flush_fp_to_thread(child);
tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0];
@@ -300,11 +413,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* If I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1)
- == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
/* write the word at location addr in the USER area */
@@ -323,13 +432,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
#endif
break;
-#ifdef CONFIG_PPC32
CHECK_FULL_REGS(child->thread.regs);
-#endif
- if (index == PT_ORIG_R3)
- break;
if (index < PT_FPR0) {
- ret = put_reg(child, index, data);
+ ret = ptrace_put_reg(child, index, data);
} else {
flush_fp_to_thread(child);
((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data;
@@ -384,7 +489,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
}
-#ifdef CONFIG_PPC64
case PTRACE_GET_DEBUGREG: {
ret = -EINVAL;
/* We only support one DABR and no IABRS at the moment */
@@ -398,73 +502,61 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_SET_DEBUGREG:
ret = ptrace_set_debugreg(child, addr, data);
break;
-#endif
case PTRACE_DETACH:
ret = ptrace_detach(child, data);
break;
- case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+#ifdef CONFIG_PPC64
+ case PTRACE_GETREGS64:
+#endif
+ case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
+ int ui;
+ if (!access_ok(VERIFY_WRITE, (void __user *)data,
+ sizeof(struct pt_regs))) {
+ ret = -EIO;
+ break;
+ }
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret |= __put_user(ptrace_get_reg(child, ui),
+ (unsigned long __user *) data);
+ data += sizeof(long);
}
break;
}
- case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
+#ifdef CONFIG_PPC64
+ case PTRACE_SETREGS64:
+#endif
+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+ unsigned long tmp;
+ int ui;
+ if (!access_ok(VERIFY_READ, (void __user *)data,
+ sizeof(struct pt_regs))) {
+ ret = -EIO;
+ break;
+ }
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret = __get_user(tmp, (unsigned long __user *) data);
if (ret)
break;
- reg++;
- tmp++;
+ ptrace_put_reg(child, ui, tmp);
+ data += sizeof(long);
}
break;
}
- case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
+ case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
+ ret = get_fpregs((void __user *)data, child, 1);
break;
}
- case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned long __user *tmp = (unsigned long __user *)addr;
-
+ case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
- }
+ ret = set_fpregs((void __user *)data, child, 1);
break;
}
@@ -499,11 +591,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
break;
#endif
+ /* Old reverse args ptrace callss */
+ case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
+ case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
+ case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
+ case PPC_PTRACE_SETFPREGS: /* Get FPRs 0 - 31. */
+ ret = arch_ptrace_old(child, request, addr, data);
+ break;
+
default:
ret = ptrace_request(child, request, addr, data);
break;
}
-
return ret;
}
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c
index 9b9a230349bc..9e6baeac0fb1 100644
--- a/arch/powerpc/kernel/ptrace32.c
+++ b/arch/powerpc/kernel/ptrace32.c
@@ -33,13 +33,55 @@
#include <asm/pgtable.h>
#include <asm/system.h>
-#include "ptrace-common.h"
-
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
*/
+/*
+ * Here are the old "legacy" powerpc specific getregs/setregs ptrace calls,
+ * we mark them as obsolete now, they will be removed in a future version
+ */
+static long compat_ptrace_old(struct task_struct *child, long request,
+ long addr, long data)
+{
+ int ret = -EPERM;
+
+ switch(request) {
+ case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned int __user *tmp = (unsigned int __user *)addr;
+
+ for (i = 0; i < 32; i++) {
+ ret = put_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
+ int i;
+ unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
+ unsigned int __user *tmp = (unsigned int __user *)addr;
+
+ for (i = 0; i < 32; i++) {
+ ret = get_user(*reg, tmp);
+ if (ret)
+ break;
+ reg++;
+ tmp++;
+ }
+ break;
+ }
+
+ }
+ return ret;
+}
+
long compat_sys_ptrace(int request, int pid, unsigned long addr,
unsigned long data)
{
@@ -123,7 +165,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
break;
if (index < PT_FPR0) {
- tmp = get_reg(child, index);
+ tmp = ptrace_get_reg(child, index);
} else {
flush_fp_to_thread(child);
/*
@@ -162,7 +204,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
else
part = 0; /* want the 1st half of the register (left-most). */
- /* Validate the input - check to see if address is on the wrong boundary or beyond the end of the user area */
+ /* Validate the input - check to see if address is on the wrong boundary
+ * or beyond the end of the user area
+ */
if ((addr & 3) || numReg > PT_FPSCR)
break;
@@ -170,7 +214,7 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
flush_fp_to_thread(child);
tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0];
} else { /* register within PT_REGS struct */
- tmp = get_reg(child, numReg);
+ tmp = ptrace_get_reg(child, numReg);
}
reg32bits = ((u32*)&tmp)[part];
ret = put_user(reg32bits, (u32 __user *)data);
@@ -226,10 +270,8 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
if ((addr & 3) || (index > PT_FPSCR32))
break;
- if (index == PT_ORIG_R3)
- break;
if (index < PT_FPR0) {
- ret = put_reg(child, index, data);
+ ret = ptrace_put_reg(child, index, data);
} else {
flush_fp_to_thread(child);
/*
@@ -258,70 +300,25 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
/* Determine which register the user wants */
index = (u64)addr >> 2;
numReg = index / 2;
+
/*
* Validate the input - check to see if address is on the
* wrong boundary or beyond the end of the user area
*/
if ((addr & 3) || (numReg > PT_FPSCR))
break;
- /* Insure it is a register we let them change */
- if ((numReg == PT_ORIG_R3)
- || ((numReg > PT_CCR) && (numReg < PT_FPR0)))
- break;
- if (numReg >= PT_FPR0) {
+ if (numReg < PT_FPR0) {
+ unsigned long freg = ptrace_get_reg(child, numReg);
+ if (index % 2)
+ freg = (freg & ~0xfffffffful) | (data & 0xfffffffful);
+ else
+ freg = (freg & 0xfffffffful) | (data << 32);
+ ret = ptrace_put_reg(child, numReg, freg);
+ } else {
flush_fp_to_thread(child);
+ ((unsigned int *)child->thread.regs)[index] = data;
+ ret = 0;
}
- if (numReg == PT_MSR)
- data = (data & MSR_DEBUGCHANGE)
- | (child->thread.regs->msr & ~MSR_DEBUGCHANGE);
- ((u32*)child->thread.regs)[index] = data;
- ret = 0;
- break;
- }
-
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL)
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- else
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- clear_single_step(child);
- wake_up_process(child);
- ret = 0;
- break;
- }
-
- /*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL: {
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- clear_single_step(child);
- wake_up_process(child);
- break;
- }
-
- case PTRACE_SINGLESTEP: { /* set the trap flag. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- set_single_step(child);
- child->exit_code = data;
- /* give it a chance to run. */
- wake_up_process(child);
- ret = 0;
break;
}
@@ -334,95 +331,67 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
break;
}
- case PTRACE_SET_DEBUGREG:
- ret = ptrace_set_debugreg(child, addr, data);
- break;
-
- case PTRACE_DETACH:
- ret = ptrace_detach(child, data);
+ case PTRACE_GETEVENTMSG:
+ ret = put_user(child->ptrace_message, (unsigned int __user *) data);
break;
- case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+ case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
+ int ui;
+ if (!access_ok(VERIFY_WRITE, (void __user *)data,
+ PT_REGS_COUNT * sizeof(int))) {
+ ret = -EIO;
+ break;
}
- break;
- }
-
- case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret |= __put_user(ptrace_get_reg(child, ui),
+ (unsigned int __user *) data);
+ data += sizeof(int);
}
break;
}
- case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = put_user(*reg, tmp);
- if (ret)
- break;
- reg++;
- tmp++;
+ case PTRACE_SETREGS: { /* Set all gp regs in the child. */
+ unsigned long tmp;
+ int ui;
+ if (!access_ok(VERIFY_READ, (void __user *)data,
+ PT_REGS_COUNT * sizeof(int))) {
+ ret = -EIO;
+ break;
}
- break;
- }
-
- case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
- int i;
- unsigned long *reg = &((unsigned long *)child->thread.fpr)[0];
- unsigned int __user *tmp = (unsigned int __user *)addr;
-
- flush_fp_to_thread(child);
-
- for (i = 0; i < 32; i++) {
- ret = get_user(*reg, tmp);
+ ret = 0;
+ for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
+ ret = __get_user(tmp, (unsigned int __user *) data);
if (ret)
break;
- reg++;
- tmp++;
+ ptrace_put_reg(child, ui, tmp);
+ data += sizeof(int);
}
break;
}
- case PTRACE_GETEVENTMSG:
- ret = put_user(child->ptrace_message, (unsigned int __user *) data);
- break;
-
-#ifdef CONFIG_ALTIVEC
+ case PTRACE_GETFPREGS:
+ case PTRACE_SETFPREGS:
case PTRACE_GETVRREGS:
- /* Get the child altivec register state. */
- flush_altivec_to_thread(child);
- ret = get_vrregs((unsigned long __user *)data, child);
+ case PTRACE_SETVRREGS:
+ case PTRACE_GETREGS64:
+ case PTRACE_SETREGS64:
+ case PPC_PTRACE_GETFPREGS:
+ case PPC_PTRACE_SETFPREGS:
+ case PTRACE_KILL:
+ case PTRACE_SINGLESTEP:
+ case PTRACE_DETACH:
+ case PTRACE_SET_DEBUGREG:
+ case PTRACE_SYSCALL:
+ case PTRACE_CONT:
+ ret = arch_ptrace(child, request, addr, data);
break;
- case PTRACE_SETVRREGS:
- /* Set the child altivec register state. */
- flush_altivec_to_thread(child);
- ret = set_vrregs(child, (unsigned long __user *)data);
+ /* Old reverse args ptrace callss */
+ case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
+ case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
+ ret = compat_ptrace_old(child, request, addr, data);
break;
-#endif
default:
ret = ptrace_request(child, request, addr, data);
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index f72118c0844f..62b7bf2f3eab 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -804,7 +804,7 @@ int __init rtas_flash_init(void)
flash_block_cache = kmem_cache_create("rtas_flash_cache",
RTAS_BLK_SIZE, RTAS_BLK_SIZE, 0,
- rtas_block_ctor, NULL);
+ rtas_block_ctor);
if (!flash_block_cache) {
printk(KERN_ERR "%s: failed to create block cache\n",
__FUNCTION__);
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c
index f2286822be09..a5de6211b97a 100644
--- a/arch/powerpc/kernel/rtas_pci.c
+++ b/arch/powerpc/kernel/rtas_pci.c
@@ -278,10 +278,8 @@ void __init find_and_init_phbs(void)
{
struct device_node *node;
struct pci_controller *phb;
- unsigned int index;
struct device_node *root = of_find_node_by_path("/");
- index = 0;
for (node = of_get_next_child(root, NULL);
node != NULL;
node = of_get_next_child(root, node)) {
@@ -295,8 +293,7 @@ void __init find_and_init_phbs(void)
continue;
rtas_setup_phb(phb);
pci_process_bridge_OF_ranges(phb, node, 0);
- pci_setup_phb_io(phb, index == 0);
- index++;
+ isa_bridge_find_early(phb);
}
of_node_put(root);
@@ -335,7 +332,7 @@ int pcibios_remove_root_bus(struct pci_controller *phb)
return 1;
}
- rc = unmap_bus_range(b);
+ rc = pcibios_unmap_io_space(b);
if (rc) {
printk(KERN_ERR "%s: failed to unmap IO on bus %s\n",
__FUNCTION__, b->name);
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index ed07a198f8d6..4924c48cb1ff 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -32,6 +32,7 @@
#include <linux/unistd.h>
#include <linux/serial.h>
#include <linux/serial_8250.h>
+#include <linux/debugfs.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/processor.h>
@@ -486,6 +487,14 @@ int check_legacy_ioport(unsigned long base_port)
switch(base_port) {
case I8042_DATA_REG:
+ if (!(np = of_find_compatible_node(NULL, NULL, "pnpPNP,303")))
+ np = of_find_compatible_node(NULL, NULL, "pnpPNP,f03");
+ if (np) {
+ parent = of_get_parent(np);
+ of_node_put(np);
+ np = parent;
+ break;
+ }
np = of_find_node_by_type(NULL, "8042");
break;
case FDC_BASE: /* FDC1 */
@@ -571,3 +580,15 @@ static int __init check_cache_coherency(void)
late_initcall(check_cache_coherency);
#endif /* CONFIG_CHECK_CACHE_COHERENCY */
+
+#ifdef CONFIG_DEBUG_FS
+struct dentry *powerpc_debugfs_root;
+
+static int powerpc_debugfs_init(void)
+{
+ powerpc_debugfs_root = debugfs_create_dir("powerpc", NULL);
+
+ return powerpc_debugfs_root == NULL;
+}
+arch_initcall(powerpc_debugfs_init);
+#endif
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 35f8f443c14f..7ec6ba56d83d 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -262,13 +262,11 @@ void __init setup_arch(char **cmdline_p)
* Systems with OF can look in the properties on the cpu node(s)
* for a possibly more accurate value.
*/
- if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) {
- dcache_bsize = cur_cpu_spec->dcache_bsize;
- icache_bsize = cur_cpu_spec->icache_bsize;
- ucache_bsize = 0;
- } else
- ucache_bsize = dcache_bsize = icache_bsize
- = cur_cpu_spec->dcache_bsize;
+ dcache_bsize = cur_cpu_spec->dcache_bsize;
+ icache_bsize = cur_cpu_spec->icache_bsize;
+ ucache_bsize = 0;
+ if (cpu_has_feature(CPU_FTR_UNIFIED_ID_CACHE))
+ ucache_bsize = icache_bsize = dcache_bsize;
/* reboot on panic */
panic_timeout = 180;
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
new file mode 100644
index 000000000000..c434d6c4e4e6
--- /dev/null
+++ b/arch/powerpc/kernel/signal.c
@@ -0,0 +1,180 @@
+/*
+ * Common signal handling code for both 32 and 64 bits
+ *
+ * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
+ * Extracted from signal_32.c and signal_64.c
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+#include "signal.h"
+
+/*
+ * Allocate space for the signal frame
+ */
+void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ size_t frame_size)
+{
+ unsigned long oldsp, newsp;
+
+ /* Default to using normal stack */
+ oldsp = regs->gpr[1];
+
+ /* Check for alt stack */
+ if ((ka->sa.sa_flags & SA_ONSTACK) &&
+ current->sas_ss_size && !on_sig_stack(oldsp))
+ oldsp = (current->sas_ss_sp + current->sas_ss_size);
+
+ /* Get aligned frame */
+ newsp = (oldsp - frame_size) & ~0xFUL;
+
+ /* Check access */
+ if (!access_ok(VERIFY_WRITE, (void __user *)newsp, oldsp - newsp))
+ return NULL;
+
+ return (void __user *)newsp;
+}
+
+
+/*
+ * Restore the user process's signal mask
+ */
+void restore_sigmask(sigset_t *set)
+{
+ sigdelsetmask(set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = *set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+}
+
+static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka,
+ int has_handler)
+{
+ unsigned long ret = regs->gpr[3];
+ int restart = 1;
+
+ /* syscall ? */
+ if (TRAP(regs) != 0x0C00)
+ return;
+
+ /* error signalled ? */
+ if (!(regs->ccr & 0x10000000))
+ return;
+
+ switch (ret) {
+ case ERESTART_RESTARTBLOCK:
+ case ERESTARTNOHAND:
+ /* ERESTARTNOHAND means that the syscall should only be
+ * restarted if there was no handler for the signal, and since
+ * we only get here if there is a handler, we dont restart.
+ */
+ restart = !has_handler;
+ break;
+ case ERESTARTSYS:
+ /* ERESTARTSYS means to restart the syscall if there is no
+ * handler or the handler was registered with SA_RESTART
+ */
+ restart = !has_handler || (ka->sa.sa_flags & SA_RESTART) != 0;
+ break;
+ case ERESTARTNOINTR:
+ /* ERESTARTNOINTR means that the syscall should be
+ * called again after the signal handler returns.
+ */
+ break;
+ default:
+ return;
+ }
+ if (restart) {
+ if (ret == ERESTART_RESTARTBLOCK)
+ regs->gpr[0] = __NR_restart_syscall;
+ else
+ regs->gpr[3] = regs->orig_gpr3;
+ regs->nip -= 4;
+ regs->result = 0;
+ } else {
+ regs->result = -EINTR;
+ regs->gpr[3] = EINTR;
+ regs->ccr |= 0x10000000;
+ }
+}
+
+int do_signal(sigset_t *oldset, struct pt_regs *regs)
+{
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
+ int ret;
+ int is32 = is_32bit_task();
+
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else if (!oldset)
+ oldset = &current->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+ /* Is there any syscall restart business here ? */
+ check_syscall_restart(regs, &ka, signr > 0);
+
+ if (signr <= 0) {
+ /* No signal to deliver -- put the saved sigmask back */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+ return 0; /* no signals delivered */
+ }
+
+ /*
+ * Reenable the DABR before delivering the signal to
+ * user space. The DABR will have been cleared if it
+ * triggered inside the kernel.
+ */
+ if (current->thread.dabr)
+ set_dabr(current->thread.dabr);
+
+ if (is32) {
+ if (ka.sa.sa_flags & SA_SIGINFO)
+ ret = handle_rt_signal32(signr, &ka, &info, oldset,
+ regs);
+ else
+ ret = handle_signal32(signr, &ka, &info, oldset,
+ regs);
+ } else {
+ ret = handle_rt_signal64(signr, &ka, &info, oldset, regs);
+ }
+
+ if (ret) {
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked, &current->blocked,
+ &ka.sa.sa_mask);
+ if (!(ka.sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked, signr);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ /*
+ * A signal was successfully delivered; the saved sigmask is in
+ * its frame, and we can clear the TIF_RESTORE_SIGMASK flag.
+ */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
+
+ return ret;
+}
+
+long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+ unsigned long r5, unsigned long r6, unsigned long r7,
+ unsigned long r8, struct pt_regs *regs)
+{
+ return do_sigaltstack(uss, uoss, regs->gpr[1]);
+}
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h
new file mode 100644
index 000000000000..77efb3d5465a
--- /dev/null
+++ b/arch/powerpc/kernel/signal.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2007 Benjamin Herrenschmidt, IBM Coproration
+ * Extracted from signal_32.c and signal_64.c
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file README.legal in the main directory of
+ * this archive for more details.
+ */
+
+#ifndef _POWERPC_ARCH_SIGNAL_H
+#define _POWERPC_ARCH_SIGNAL_H
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
+ size_t frame_size);
+extern void restore_sigmask(sigset_t *set);
+
+extern int handle_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset,
+ struct pt_regs *regs);
+
+extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset,
+ struct pt_regs *regs);
+
+
+#ifdef CONFIG_PPC64
+
+static inline int is_32bit_task(void)
+{
+ return test_thread_flag(TIF_32BIT);
+}
+
+extern int handle_rt_signal64(int signr, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *set,
+ struct pt_regs *regs);
+
+#else /* CONFIG_PPC64 */
+
+static inline int is_32bit_task(void)
+{
+ return 1;
+}
+
+static inline int handle_rt_signal64(int signr, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *set,
+ struct pt_regs *regs)
+{
+ return -EFAULT;
+}
+
+#endif /* !defined(CONFIG_PPC64) */
+
+#endif /* _POWERPC_ARCH_SIGNAL_H */
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index dd1dca5bfa81..590057e9e987 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -51,12 +51,11 @@
#include <asm/pgtable.h>
#endif
-#undef DEBUG_SIG
+#include "signal.h"
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+#undef DEBUG_SIG
#ifdef CONFIG_PPC64
-#define do_signal do_signal32
#define sys_sigsuspend compat_sys_sigsuspend
#define sys_rt_sigsuspend compat_sys_rt_sigsuspend
#define sys_rt_sigreturn compat_sys_rt_sigreturn
@@ -231,8 +230,6 @@ static inline int restore_general_regs(struct pt_regs *regs,
#endif /* CONFIG_PPC64 */
-int do_signal(sigset_t *oldset, struct pt_regs *regs);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -251,14 +248,6 @@ long sys_sigsuspend(old_sigset_t mask)
return -ERESTARTNOHAND;
}
-#ifdef CONFIG_PPC32
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, int r5,
- int r6, int r7, int r8, struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->gpr[1]);
-}
-#endif
-
long sys_sigaction(int sig, struct old_sigaction __user *act,
struct old_sigaction __user *oact)
{
@@ -293,14 +282,17 @@ long sys_sigaction(int sig, struct old_sigaction __user *act,
/*
* When we have signals to deliver, we set up on the
* user stack, going down from the original stack pointer:
- * a sigregs struct
+ * an ABI gap of 56 words
+ * an mcontext struct
* a sigcontext struct
* a gap of __SIGNAL_FRAMESIZE bytes
*
- * Each of these things must be a multiple of 16 bytes in size.
+ * Each of these things must be a multiple of 16 bytes in size. The following
+ * structure represent all of this except the __SIGNAL_FRAMESIZE gap
*
*/
-struct sigregs {
+struct sigframe {
+ struct sigcontext sctx; /* the sigcontext */
struct mcontext mctx; /* all the register values */
/*
* Programs using the rs6000/xcoff abi can save up to 19 gp
@@ -703,44 +695,22 @@ int compat_sys_sigaltstack(u32 __new, u32 __old, int r5,
}
#endif /* CONFIG_PPC64 */
-
-/*
- * Restore the user process's signal mask
- */
-#ifdef CONFIG_PPC64
-extern void restore_sigmask(sigset_t *set);
-#else /* CONFIG_PPC64 */
-static void restore_sigmask(sigset_t *set)
-{
- sigdelsetmask(set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = *set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-}
-#endif
-
/*
* Set up a signal frame for a "real-time" signal handler
* (one which gets siginfo).
*/
-static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
+int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
siginfo_t *info, sigset_t *oldset,
- struct pt_regs *regs, unsigned long newsp)
+ struct pt_regs *regs)
{
struct rt_sigframe __user *rt_sf;
struct mcontext __user *frame;
- unsigned long origsp = newsp;
+ unsigned long newsp = 0;
/* Set up Signal Frame */
/* Put a Real Time Context onto stack */
- newsp -= sizeof(*rt_sf);
- rt_sf = (struct rt_sigframe __user *)newsp;
-
- /* create a stack frame for the caller of the handler */
- newsp -= __SIGNAL_FRAMESIZE + 16;
-
- if (!access_ok(VERIFY_WRITE, (void __user *)newsp, origsp - newsp))
+ rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf));
+ if (unlikely(rt_sf == NULL))
goto badframe;
/* Put the siginfo & fill in most of the ucontext */
@@ -770,8 +740,12 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka,
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+ /* create a stack frame for the caller of the handler */
+ newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
+
+ /* Fill registers for signal handler */
regs->gpr[1] = newsp;
regs->gpr[3] = sig;
regs->gpr[4] = (unsigned long) &rt_sf->info;
@@ -1015,27 +989,18 @@ int sys_debug_setcontext(struct ucontext __user *ctx,
/*
* OK, we're invoking a handler
*/
-static int handle_signal(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, sigset_t *oldset, struct pt_regs *regs,
- unsigned long newsp)
+int handle_signal32(unsigned long sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
{
struct sigcontext __user *sc;
- struct sigregs __user *frame;
- unsigned long origsp = newsp;
+ struct sigframe __user *frame;
+ unsigned long newsp = 0;
/* Set up Signal Frame */
- newsp -= sizeof(struct sigregs);
- frame = (struct sigregs __user *) newsp;
-
- /* Put a sigcontext on the stack */
- newsp -= sizeof(*sc);
- sc = (struct sigcontext __user *) newsp;
-
- /* create a stack frame for the caller of the handler */
- newsp -= __SIGNAL_FRAMESIZE;
-
- if (!access_ok(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+ if (unlikely(frame == NULL))
goto badframe;
+ sc = (struct sigcontext __user *) &frame->sctx;
#if _NSIG != 64
#error "Please adjust handle_signal()"
@@ -1047,7 +1012,7 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
#else
|| __put_user(oldset->sig[1], &sc->_unused[3])
#endif
- || __put_user(to_user_ptr(frame), &sc->regs)
+ || __put_user(to_user_ptr(&frame->mctx), &sc->regs)
|| __put_user(sig, &sc->signal))
goto badframe;
@@ -1063,8 +1028,11 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka,
current->thread.fpscr.val = 0; /* turn off all fp exceptions */
+ /* create a stack frame for the caller of the handler */
+ newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
if (put_user(regs->gpr[1], (u32 __user *)newsp))
goto badframe;
+
regs->gpr[1] = newsp;
regs->gpr[3] = sig;
regs->gpr[4] = (unsigned long) sc;
@@ -1126,106 +1094,3 @@ badframe:
force_sig(SIGSEGV, current);
return 0;
}
-
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
-{
- siginfo_t info;
- struct k_sigaction ka;
- unsigned int newsp;
- int signr, ret;
-
-#ifdef CONFIG_PPC32
- if (try_to_freeze()) {
- signr = 0;
- if (!signal_pending(current))
- goto no_signal;
- }
-#endif
-
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- oldset = &current->saved_sigmask;
- else if (!oldset)
- oldset = &current->blocked;
-
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-#ifdef CONFIG_PPC32
-no_signal:
-#endif
- if (TRAP(regs) == 0x0C00 /* System Call! */
- && regs->ccr & 0x10000000 /* error signalled */
- && ((ret = regs->gpr[3]) == ERESTARTSYS
- || ret == ERESTARTNOHAND || ret == ERESTARTNOINTR
- || ret == ERESTART_RESTARTBLOCK)) {
-
- if (signr > 0
- && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK
- || (ret == ERESTARTSYS
- && !(ka.sa.sa_flags & SA_RESTART)))) {
- /* make the system call return an EINTR error */
- regs->result = -EINTR;
- regs->gpr[3] = EINTR;
- /* note that the cr0.SO bit is already set */
- } else {
- regs->nip -= 4; /* Back up & retry system call */
- regs->result = 0;
- regs->trap = 0;
- if (ret == ERESTART_RESTARTBLOCK)
- regs->gpr[0] = __NR_restart_syscall;
- else
- regs->gpr[3] = regs->orig_gpr3;
- }
- }
-
- if (signr == 0) {
- /* No signal to deliver -- put the saved sigmask back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
- }
- return 0; /* no signals delivered */
- }
-
- if ((ka.sa.sa_flags & SA_ONSTACK) && current->sas_ss_size
- && !on_sig_stack(regs->gpr[1]))
- newsp = current->sas_ss_sp + current->sas_ss_size;
- else
- newsp = regs->gpr[1];
- newsp &= ~0xfUL;
-
-#ifdef CONFIG_PPC64
- /*
- * Reenable the DABR before delivering the signal to
- * user space. The DABR will have been cleared if it
- * triggered inside the kernel.
- */
- if (current->thread.dabr)
- set_dabr(current->thread.dabr);
-#endif
-
- /* Whee! Actually deliver the signal. */
- if (ka.sa.sa_flags & SA_SIGINFO)
- ret = handle_rt_signal(signr, &ka, &info, oldset, regs, newsp);
- else
- ret = handle_signal(signr, &ka, &info, oldset, regs, newsp);
-
- if (ret) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked,
- &ka.sa.sa_mask);
- if (!(ka.sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, signr);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- /* A signal was successfully delivered; the saved sigmask is in
- its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- }
-
- return ret;
-}
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index b27e26852fdb..de895e6d8c62 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -34,9 +34,9 @@
#include <asm/syscalls.h>
#include <asm/vdso.h>
-#define DEBUG_SIG 0
+#include "signal.h"
-#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+#define DEBUG_SIG 0
#define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
#define FP_REGS_SIZE sizeof(elf_fpregset_t)
@@ -64,14 +64,6 @@ struct rt_sigframe {
char abigap[288];
} __attribute__ ((aligned (16)));
-long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5,
- unsigned long r6, unsigned long r7, unsigned long r8,
- struct pt_regs *regs)
-{
- return do_sigaltstack(uss, uoss, regs->gpr[1]);
-}
-
-
/*
* Set up the sigcontext for the signal frame.
*/
@@ -208,25 +200,6 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig,
}
/*
- * Allocate space for the signal frame
- */
-static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
- size_t frame_size)
-{
- unsigned long newsp;
-
- /* Default to using normal stack */
- newsp = regs->gpr[1];
-
- if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) {
- if (! on_sig_stack(regs->gpr[1]))
- newsp = (current->sas_ss_sp + current->sas_ss_size);
- }
-
- return (void __user *)((newsp - frame_size) & -16ul);
-}
-
-/*
* Setup the trampoline code on the stack
*/
static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp)
@@ -253,19 +226,6 @@ static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp)
}
/*
- * Restore the user process's signal mask (also used by signal32.c)
- */
-void restore_sigmask(sigset_t *set)
-{
- sigdelsetmask(set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = *set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-}
-
-
-/*
* Handle {get,set,swap}_context operations
*/
int sys_swapcontext(struct ucontext __user *old_ctx,
@@ -359,7 +319,7 @@ badframe:
return 0;
}
-static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
/* Handler is *really* a pointer to the function descriptor for
@@ -373,8 +333,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
long err = 0;
frame = get_sigframe(ka, regs, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ if (unlikely(frame == NULL))
goto badframe;
err |= __put_user(&frame->info, &frame->pinfo);
@@ -411,7 +370,7 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
funct_desc_ptr = (func_descr_t __user *) ka->sa.sa_handler;
/* Allocate a dummy caller frame for the signal handler. */
- newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+ newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
err |= put_user(regs->gpr[1], (unsigned long __user *)newsp);
/* Set up "regs" so we "return" to the signal handler. */
@@ -442,134 +401,3 @@ badframe:
force_sigsegv(signr, current);
return 0;
}
-
-
-/*
- * OK, we're invoking a handler
- */
-static int handle_signal(unsigned long sig, struct k_sigaction *ka,
- siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
-{
- int ret;
-
- /* Set up Signal Frame */
- ret = setup_rt_frame(sig, ka, info, oldset, regs);
-
- if (ret) {
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- }
-
- return ret;
-}
-
-static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
-{
- switch ((int)regs->result) {
- case -ERESTART_RESTARTBLOCK:
- case -ERESTARTNOHAND:
- /* ERESTARTNOHAND means that the syscall should only be
- * restarted if there was no handler for the signal, and since
- * we only get here if there is a handler, we dont restart.
- */
- regs->result = -EINTR;
- regs->gpr[3] = EINTR;
- regs->ccr |= 0x10000000;
- break;
- case -ERESTARTSYS:
- /* ERESTARTSYS means to restart the syscall if there is no
- * handler or the handler was registered with SA_RESTART
- */
- if (!(ka->sa.sa_flags & SA_RESTART)) {
- regs->result = -EINTR;
- regs->gpr[3] = EINTR;
- regs->ccr |= 0x10000000;
- break;
- }
- /* fallthrough */
- case -ERESTARTNOINTR:
- /* ERESTARTNOINTR means that the syscall should be
- * called again after the signal handler returns.
- */
- regs->gpr[3] = regs->orig_gpr3;
- regs->nip -= 4;
- regs->result = 0;
- break;
- }
-}
-
-/*
- * Note that 'init' is a special process: it doesn't get signals it doesn't
- * want to handle. Thus you cannot kill init even with a SIGKILL even by
- * mistake.
- */
-int do_signal(sigset_t *oldset, struct pt_regs *regs)
-{
- siginfo_t info;
- int signr;
- struct k_sigaction ka;
-
- /*
- * If the current thread is 32 bit - invoke the
- * 32 bit signal handling code
- */
- if (test_thread_flag(TIF_32BIT))
- return do_signal32(oldset, regs);
-
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- oldset = &current->saved_sigmask;
- else if (!oldset)
- oldset = &current->blocked;
-
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- if (signr > 0) {
- int ret;
-
- /* Whee! Actually deliver the signal. */
- if (TRAP(regs) == 0x0C00)
- syscall_restart(regs, &ka);
-
- /*
- * Reenable the DABR before delivering the signal to
- * user space. The DABR will have been cleared if it
- * triggered inside the kernel.
- */
- if (current->thread.dabr)
- set_dabr(current->thread.dabr);
-
- ret = handle_signal(signr, &ka, &info, oldset, regs);
-
- /* If a signal was successfully delivered, the saved sigmask is in
- its frame, and we can clear the TIF_RESTORE_SIGMASK flag */
- if (ret && test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
-
- return ret;
- }
-
- if (TRAP(regs) == 0x0C00) { /* System Call! */
- if ((int)regs->result == -ERESTARTNOHAND ||
- (int)regs->result == -ERESTARTSYS ||
- (int)regs->result == -ERESTARTNOINTR) {
- regs->gpr[3] = regs->orig_gpr3;
- regs->nip -= 4; /* Back up & retry system call */
- regs->result = 0;
- } else if ((int)regs->result == -ERESTART_RESTARTBLOCK) {
- regs->gpr[0] = __NR_restart_syscall;
- regs->nip -= 4;
- regs->result = 0;
- }
- }
- /* No signal to deliver -- put the saved sigmask back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
- sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(do_signal);
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index d577b71db375..087c92f2a3eb 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -284,7 +284,7 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int
int wait)
{
cpumask_t map = CPU_MASK_NONE;
- int ret = -EBUSY;
+ int ret = 0;
if (!cpu_online(cpu))
return -EINVAL;
@@ -292,6 +292,11 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int
cpu_set(cpu, map);
if (cpu != get_cpu())
ret = smp_call_function_map(func,info,nonatomic,wait,map);
+ else {
+ local_irq_disable();
+ func(info);
+ local_irq_enable();
+ }
put_cpu();
return ret;
}
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index b42cbf1e2d7d..bd85b5fd08c8 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -773,6 +773,13 @@ asmlinkage int compat_sys_truncate64(const char __user * path, u32 reg4,
return sys_truncate(path, (high << 32) | low);
}
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+ u32 lenhi, u32 lenlo)
+{
+ return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+ ((loff_t)lenhi << 32) | lenlo);
+}
+
asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long high,
unsigned long low)
{
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 68991c2d4a1b..55d29ed4b7a0 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -442,12 +442,14 @@ int sysfs_add_device_to_node(struct sys_device *dev, int nid)
return sysfs_create_link(&node->sysdev.kobj, &dev->kobj,
kobject_name(&dev->kobj));
}
+EXPORT_SYMBOL_GPL(sysfs_add_device_to_node);
void sysfs_remove_device_from_node(struct sys_device *dev, int nid)
{
struct node *node = &node_devices[nid];
sysfs_remove_link(&node->sysdev.kobj, kobject_name(&dev->kobj));
}
+EXPORT_SYMBOL_GPL(sysfs_remove_device_from_node);
#else
static void register_nodes(void)
@@ -457,9 +459,6 @@ static void register_nodes(void)
#endif
-EXPORT_SYMBOL_GPL(sysfs_add_device_to_node);
-EXPORT_SYMBOL_GPL(sysfs_remove_device_from_node);
-
/* Only valid if CPU is present. */
static ssize_t show_physical_id(struct sys_device *dev, char *buf)
{
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 2c8564d54e4d..727a6699f2f4 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -77,9 +77,8 @@
/* keep track of when we need to update the rtc */
time_t last_rtc_update;
#ifdef CONFIG_PPC_ISERIES
-unsigned long iSeries_recal_titan = 0;
-unsigned long iSeries_recal_tb = 0;
-static unsigned long first_settimeofday = 1;
+static unsigned long __initdata iSeries_recal_titan;
+static signed long __initdata iSeries_recal_tb;
#endif
/* The decrementer counts down by 128 every 128ns on a 601. */
@@ -113,8 +112,9 @@ u64 ticklen_to_xs; /* 0.64 fraction */
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL_GPL(rtc_lock);
-u64 tb_to_ns_scale;
-unsigned tb_to_ns_shift;
+static u64 tb_to_ns_scale __read_mostly;
+static unsigned tb_to_ns_shift __read_mostly;
+static unsigned long boot_tb __read_mostly;
struct gettimeofday_struct do_gtod;
@@ -122,6 +122,7 @@ extern struct timezone sys_tz;
static long timezone_offset;
unsigned long ppc_proc_freq;
+EXPORT_SYMBOL(ppc_proc_freq);
unsigned long ppc_tb_freq;
static u64 tb_last_jiffy __cacheline_aligned_in_smp;
@@ -214,7 +215,6 @@ static void account_process_time(struct pt_regs *regs)
run_posix_cpu_timers(current);
}
-#ifdef CONFIG_PPC_SPLPAR
/*
* Stuff for accounting stolen time.
*/
@@ -222,19 +222,28 @@ struct cpu_purr_data {
int initialized; /* thread is running */
u64 tb; /* last TB value read */
u64 purr; /* last PURR value read */
- spinlock_t lock;
};
+/*
+ * Each entry in the cpu_purr_data array is manipulated only by its
+ * "owner" cpu -- usually in the timer interrupt but also occasionally
+ * in process context for cpu online. As long as cpus do not touch
+ * each others' cpu_purr_data, disabling local interrupts is
+ * sufficient to serialize accesses.
+ */
static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data);
static void snapshot_tb_and_purr(void *data)
{
+ unsigned long flags;
struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
+ local_irq_save(flags);
p->tb = mftb();
p->purr = mfspr(SPRN_PURR);
wmb();
p->initialized = 1;
+ local_irq_restore(flags);
}
/*
@@ -242,15 +251,14 @@ static void snapshot_tb_and_purr(void *data)
*/
void snapshot_timebases(void)
{
- int cpu;
-
if (!cpu_has_feature(CPU_FTR_PURR))
return;
- for_each_possible_cpu(cpu)
- spin_lock_init(&per_cpu(cpu_purr_data, cpu).lock);
on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1);
}
+/*
+ * Must be called with interrupts disabled.
+ */
void calculate_steal_time(void)
{
u64 tb, purr;
@@ -262,7 +270,6 @@ void calculate_steal_time(void)
pme = &per_cpu(cpu_purr_data, smp_processor_id());
if (!pme->initialized)
return; /* this can happen in early boot */
- spin_lock(&pme->lock);
tb = mftb();
purr = mfspr(SPRN_PURR);
stolen = (tb - pme->tb) - (purr - pme->purr);
@@ -270,9 +277,9 @@ void calculate_steal_time(void)
account_steal_time(current, stolen);
pme->tb = tb;
pme->purr = purr;
- spin_unlock(&pme->lock);
}
+#ifdef CONFIG_PPC_SPLPAR
/*
* Must be called before the cpu is added to the online map when
* a cpu is being brought up at runtime.
@@ -284,12 +291,12 @@ static void snapshot_purr(void)
if (!cpu_has_feature(CPU_FTR_PURR))
return;
+ local_irq_save(flags);
pme = &per_cpu(cpu_purr_data, smp_processor_id());
- spin_lock_irqsave(&pme->lock, flags);
pme->tb = mftb();
pme->purr = mfspr(SPRN_PURR);
pme->initialized = 1;
- spin_unlock_irqrestore(&pme->lock, flags);
+ local_irq_restore(flags);
}
#endif /* CONFIG_PPC_SPLPAR */
@@ -550,10 +557,15 @@ EXPORT_SYMBOL(profile_pc);
* returned by the service processor for the timebase frequency.
*/
-static void iSeries_tb_recal(void)
+static int __init iSeries_tb_recal(void)
{
struct div_result divres;
unsigned long titan, tb;
+
+ /* Make sure we only run on iSeries */
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -ENODEV;
+
tb = get_tb();
titan = HvCallXm_loadTod();
if ( iSeries_recal_titan ) {
@@ -594,8 +606,18 @@ static void iSeries_tb_recal(void)
}
iSeries_recal_titan = titan;
iSeries_recal_tb = tb;
+
+ return 0;
}
-#endif
+late_initcall(iSeries_tb_recal);
+
+/* Called from platform early init */
+void __init iSeries_time_init_early(void)
+{
+ iSeries_recal_tb = get_tb();
+ iSeries_recal_titan = HvCallXm_loadTod();
+}
+#endif /* CONFIG_PPC_ISERIES */
/*
* For iSeries shared processors, we have to let the hypervisor
@@ -735,7 +757,7 @@ unsigned long long sched_clock(void)
{
if (__USE_RTC())
return get_rtc();
- return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift;
+ return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift;
}
int do_settimeofday(struct timespec *tv)
@@ -759,12 +781,6 @@ int do_settimeofday(struct timespec *tv)
* to the RTC again, or write to the RTC but then they don't call
* settimeofday to perform this operation.
*/
-#ifdef CONFIG_PPC_ISERIES
- if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) {
- iSeries_tb_recal();
- first_settimeofday = 0;
- }
-#endif
/* Make userspace gettimeofday spin until we're done. */
++vdso_data->tb_update_count;
@@ -960,6 +976,8 @@ void __init time_init(void)
}
tb_to_ns_scale = scale;
tb_to_ns_shift = shift;
+ /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */
+ boot_tb = get_tb();
tm = get_boot_time();
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index bf6445ac9f1c..2bb1cb911783 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -149,6 +149,7 @@ int die(const char *str, struct pt_regs *regs, long err)
bust_spinlocks(0);
die.lock_owner = -1;
+ add_taint(TAINT_DIE);
spin_unlock_irqrestore(&die.lock, flags);
if (kexec_should_crash(current) ||
@@ -777,7 +778,7 @@ void __kprobes program_check_exception(struct pt_regs *regs)
return;
if (!(regs->msr & MSR_PR) && /* not user-mode */
- report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
+ report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
}
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index 4245579edb4e..cef01e4e8989 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -670,7 +670,7 @@ static int __init vdso_init(void)
/*
* Fill up the "systemcfg" stuff for backward compatiblity
*/
- strcpy(vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
+ strcpy((char *)vdso_data->eye_catcher, "SYSTEMCFG:PPC64");
vdso_data->version.major = SYSTEMCFG_MAJOR;
vdso_data->version.minor = SYSTEMCFG_MINOR;
vdso_data->processor = mfspr(SPRN_PVR);
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 21c39ff2dc39..0c458556399f 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -7,6 +7,7 @@
#define PROVIDE32(x) PROVIDE(x)
#endif
#include <asm-generic/vmlinux.lds.h>
+#include <asm/cache.h>
ENTRY(_stext)
@@ -62,6 +63,8 @@ SECTIONS
__stop___ex_table = .;
}
+ NOTES
+
BUG_TABLE
/*
@@ -143,6 +146,7 @@ SECTIONS
.data.percpu : {
__per_cpu_start = .;
*(.data.percpu)
+ *(.data.percpu.shared_aligned)
__per_cpu_end = .;
}
@@ -173,7 +177,9 @@ SECTIONS
}
#else
.data : {
- *(.data .data.rel* .toc1)
+ DATA_DATA
+ *(.data.rel*)
+ *(.toc1)
*(.branch_lt)
}
@@ -211,6 +217,11 @@ SECTIONS
*(.data.cacheline_aligned)
}
+ . = ALIGN(L1_CACHE_BYTES);
+ .data.read_mostly : {
+ *(.data.read_mostly)
+ }
+
. = ALIGN(PAGE_SIZE);
__data_nosave : {
__nosave_begin = .;
diff --git a/arch/powerpc/mm/44x_mmu.c b/arch/powerpc/mm/44x_mmu.c
index ca4dcb07a939..c3df50476539 100644
--- a/arch/powerpc/mm/44x_mmu.c
+++ b/arch/powerpc/mm/44x_mmu.c
@@ -12,7 +12,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
diff --git a/arch/powerpc/mm/4xx_mmu.c b/arch/powerpc/mm/4xx_mmu.c
index 838e09db71d9..7ff2609b64d1 100644
--- a/arch/powerpc/mm/4xx_mmu.c
+++ b/arch/powerpc/mm/4xx_mmu.c
@@ -9,7 +9,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 4f839c6a9768..7e4d27ad3dee 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -11,8 +11,7 @@ obj-$(CONFIG_PPC32) += init_32.o pgtable_32.o mmu_context_32.o
hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC64) += init_64.o pgtable_64.o mmu_context_64.o \
hash_utils_64.o hash_low_64.o tlb_64.o \
- slb_low.o slb.o stab.o mmap.o imalloc.o \
- $(hash-y)
+ slb_low.o slb.o stab.o mmap.o $(hash-y)
obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o hash_low_32.o tlb_32.o
obj-$(CONFIG_40x) += 4xx_mmu.o
obj-$(CONFIG_44x) += 44x_mmu.o
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 115b25f50bf8..ab3546c5ac3a 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -145,7 +145,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
struct mm_struct *mm = current->mm;
siginfo_t info;
int code = SEGV_MAPERR;
- int is_write = 0;
+ int is_write = 0, ret;
int trap = TRAP(regs);
int is_exec = trap == 0x400;
@@ -283,7 +283,13 @@ good_area:
/* protection fault */
if (error_code & DSISR_PROTFAULT)
goto bad_area;
- if (!(vma->vm_flags & VM_EXEC))
+ /*
+ * Allow execution from readable areas if the MMU does not
+ * provide separate controls over reading and executing.
+ */
+ if (!(vma->vm_flags & VM_EXEC) &&
+ (cpu_has_feature(CPU_FTR_NOEXECUTE) ||
+ !(vma->vm_flags & (VM_READ | VM_WRITE))))
goto bad_area;
#else
pte_t *ptep;
@@ -330,22 +336,18 @@ good_area:
* the fault.
*/
survive:
- switch (handle_mm_fault(mm, vma, address, is_write)) {
-
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ ret = handle_mm_fault(mm, vma, address, is_write);
+ if (unlikely(ret & VM_FAULT_ERROR)) {
+ if (ret & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (ret & VM_FAULT_SIGBUS)
+ goto do_sigbus;
BUG();
}
-
+ if (ret & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
return 0;
@@ -380,7 +382,7 @@ out_of_memory:
}
printk("VM: killing process %s\n", current->comm);
if (user_mode(regs))
- do_exit(SIGKILL);
+ do_group_exit(SIGKILL);
return SIGKILL;
do_sigbus:
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index 123da03ab118..afab247d472f 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -14,7 +14,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 4a20d890e2f4..6ba9b47e55af 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -104,7 +104,7 @@ static inline void tlbie(unsigned long va, int psize, int local)
spin_unlock(&native_tlbie_lock);
}
-static inline void native_lock_hpte(hpte_t *hptep)
+static inline void native_lock_hpte(struct hash_pte *hptep)
{
unsigned long *word = &hptep->v;
@@ -116,7 +116,7 @@ static inline void native_lock_hpte(hpte_t *hptep)
}
}
-static inline void native_unlock_hpte(hpte_t *hptep)
+static inline void native_unlock_hpte(struct hash_pte *hptep)
{
unsigned long *word = &hptep->v;
@@ -128,7 +128,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va,
unsigned long pa, unsigned long rflags,
unsigned long vflags, int psize)
{
- hpte_t *hptep = htab_address + hpte_group;
+ struct hash_pte *hptep = htab_address + hpte_group;
unsigned long hpte_v, hpte_r;
int i;
@@ -163,7 +163,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va,
hptep->r = hpte_r;
/* Guarantee the second dword is visible before the valid bit */
- __asm__ __volatile__ ("eieio" : : : "memory");
+ eieio();
/*
* Now set the first dword including the valid bit
* NOTE: this also unlocks the hpte
@@ -177,7 +177,7 @@ static long native_hpte_insert(unsigned long hpte_group, unsigned long va,
static long native_hpte_remove(unsigned long hpte_group)
{
- hpte_t *hptep;
+ struct hash_pte *hptep;
int i;
int slot_offset;
unsigned long hpte_v;
@@ -217,7 +217,7 @@ static long native_hpte_remove(unsigned long hpte_group)
static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
unsigned long va, int psize, int local)
{
- hpte_t *hptep = htab_address + slot;
+ struct hash_pte *hptep = htab_address + slot;
unsigned long hpte_v, want_v;
int ret = 0;
@@ -233,15 +233,14 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
/* Even if we miss, we need to invalidate the TLB */
if (!HPTE_V_COMPARE(hpte_v, want_v) || !(hpte_v & HPTE_V_VALID)) {
DBG_LOW(" -> miss\n");
- native_unlock_hpte(hptep);
ret = -1;
} else {
DBG_LOW(" -> hit\n");
/* Update the HPTE */
hptep->r = (hptep->r & ~(HPTE_R_PP | HPTE_R_N)) |
(newpp & (HPTE_R_PP | HPTE_R_N | HPTE_R_C));
- native_unlock_hpte(hptep);
}
+ native_unlock_hpte(hptep);
/* Ensure it is out of the tlb too. */
tlbie(va, psize, local);
@@ -251,7 +250,7 @@ static long native_hpte_updatepp(unsigned long slot, unsigned long newpp,
static long native_hpte_find(unsigned long va, int psize)
{
- hpte_t *hptep;
+ struct hash_pte *hptep;
unsigned long hash;
unsigned long i, j;
long slot;
@@ -294,7 +293,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
{
unsigned long vsid, va;
long slot;
- hpte_t *hptep;
+ struct hash_pte *hptep;
vsid = get_kernel_vsid(ea);
va = (vsid << 28) | (ea & 0x0fffffff);
@@ -315,7 +314,7 @@ static void native_hpte_updateboltedpp(unsigned long newpp, unsigned long ea,
static void native_hpte_invalidate(unsigned long slot, unsigned long va,
int psize, int local)
{
- hpte_t *hptep = htab_address + slot;
+ struct hash_pte *hptep = htab_address + slot;
unsigned long hpte_v;
unsigned long want_v;
unsigned long flags;
@@ -345,7 +344,7 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va,
#define LP_BITS 8
#define LP_MASK(i) ((0xFF >> (i)) << LP_SHIFT)
-static void hpte_decode(hpte_t *hpte, unsigned long slot,
+static void hpte_decode(struct hash_pte *hpte, unsigned long slot,
int *psize, unsigned long *va)
{
unsigned long hpte_r = hpte->r;
@@ -415,7 +414,7 @@ static void hpte_decode(hpte_t *hpte, unsigned long slot,
static void native_hpte_clear(void)
{
unsigned long slot, slots, flags;
- hpte_t *hptep = htab_address;
+ struct hash_pte *hptep = htab_address;
unsigned long hpte_v, va;
unsigned long pteg_count;
int psize;
@@ -462,7 +461,7 @@ static void native_hpte_clear(void)
static void native_flush_hash_range(unsigned long number, int local)
{
unsigned long va, hash, index, hidx, shift, slot;
- hpte_t *hptep;
+ struct hash_pte *hptep;
unsigned long hpte_v;
unsigned long want_v;
unsigned long flags;
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 4f2f4534a9d8..bc7b0cedae5e 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -87,7 +87,7 @@ extern unsigned long dart_tablebase;
static unsigned long _SDR1;
struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
-hpte_t *htab_address;
+struct hash_pte *htab_address;
unsigned long htab_size_bytes;
unsigned long htab_hash_mask;
int mmu_linear_psize = MMU_PAGE_4K;
@@ -609,7 +609,7 @@ static void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
mm->context.sllp = SLB_VSID_USER | mmu_psize_defs[MMU_PAGE_4K].sllp;
#endif /* CONFIG_PPC_MM_SLICES */
-#ifdef CONFIG_SPE_BASE
+#ifdef CONFIG_SPU_BASE
spu_flush_all_slbs(mm);
#endif
}
@@ -744,7 +744,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap)
"to 4kB pages because of "
"non-cacheable mapping\n");
psize = mmu_vmalloc_psize = MMU_PAGE_4K;
-#ifdef CONFIG_SPE_BASE
+#ifdef CONFIG_SPU_BASE
spu_flush_all_slbs(mm);
#endif
}
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 92a1b16fb7e3..4835f73af304 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -542,7 +542,7 @@ static int __init hugetlbpage_init(void)
HUGEPTE_TABLE_SIZE,
HUGEPTE_TABLE_SIZE,
0,
- zero_ctor, NULL);
+ zero_ctor);
if (! huge_pgtable_cache)
panic("hugetlbpage_init(): could not create hugepte cache\n");
diff --git a/arch/powerpc/mm/imalloc.c b/arch/powerpc/mm/imalloc.c
deleted file mode 100644
index c831815c31f0..000000000000
--- a/arch/powerpc/mm/imalloc.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * c 2001 PPC 64 Team, IBM Corp
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <linux/mutex.h>
-#include <asm/cacheflush.h>
-
-#include "mmu_decl.h"
-
-static DEFINE_MUTEX(imlist_mutex);
-struct vm_struct * imlist = NULL;
-
-static int get_free_im_addr(unsigned long size, unsigned long *im_addr)
-{
- unsigned long addr;
- struct vm_struct **p, *tmp;
-
- addr = ioremap_bot;
- for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
- if (size + addr < (unsigned long) tmp->addr)
- break;
- if ((unsigned long)tmp->addr >= ioremap_bot)
- addr = tmp->size + (unsigned long) tmp->addr;
- if (addr >= IMALLOC_END-size)
- return 1;
- }
- *im_addr = addr;
-
- return 0;
-}
-
-/* Return whether the region described by v_addr and size is a subset
- * of the region described by parent
- */
-static inline int im_region_is_subset(unsigned long v_addr, unsigned long size,
- struct vm_struct *parent)
-{
- return (int) (v_addr >= (unsigned long) parent->addr &&
- v_addr < (unsigned long) parent->addr + parent->size &&
- size < parent->size);
-}
-
-/* Return whether the region described by v_addr and size is a superset
- * of the region described by child
- */
-static int im_region_is_superset(unsigned long v_addr, unsigned long size,
- struct vm_struct *child)
-{
- struct vm_struct parent;
-
- parent.addr = (void *) v_addr;
- parent.size = size;
-
- return im_region_is_subset((unsigned long) child->addr, child->size,
- &parent);
-}
-
-/* Return whether the region described by v_addr and size overlaps
- * the region described by vm. Overlapping regions meet the
- * following conditions:
- * 1) The regions share some part of the address space
- * 2) The regions aren't identical
- * 3) Neither region is a subset of the other
- */
-static int im_region_overlaps(unsigned long v_addr, unsigned long size,
- struct vm_struct *vm)
-{
- if (im_region_is_superset(v_addr, size, vm))
- return 0;
-
- return (v_addr + size > (unsigned long) vm->addr + vm->size &&
- v_addr < (unsigned long) vm->addr + vm->size) ||
- (v_addr < (unsigned long) vm->addr &&
- v_addr + size > (unsigned long) vm->addr);
-}
-
-/* Determine imalloc status of region described by v_addr and size.
- * Can return one of the following:
- * IM_REGION_UNUSED - Entire region is unallocated in imalloc space.
- * IM_REGION_SUBSET - Region is a subset of a region that is already
- * allocated in imalloc space.
- * vm will be assigned to a ptr to the parent region.
- * IM_REGION_EXISTS - Exact region already allocated in imalloc space.
- * vm will be assigned to a ptr to the existing imlist
- * member.
- * IM_REGION_OVERLAPS - Region overlaps an allocated region in imalloc space.
- * IM_REGION_SUPERSET - Region is a superset of a region that is already
- * allocated in imalloc space.
- */
-static int im_region_status(unsigned long v_addr, unsigned long size,
- struct vm_struct **vm)
-{
- struct vm_struct *tmp;
-
- for (tmp = imlist; tmp; tmp = tmp->next)
- if (v_addr < (unsigned long) tmp->addr + tmp->size)
- break;
-
- *vm = NULL;
- if (tmp) {
- if (im_region_overlaps(v_addr, size, tmp))
- return IM_REGION_OVERLAP;
-
- *vm = tmp;
- if (im_region_is_subset(v_addr, size, tmp)) {
- /* Return with tmp pointing to superset */
- return IM_REGION_SUBSET;
- }
- if (im_region_is_superset(v_addr, size, tmp)) {
- /* Return with tmp pointing to first subset */
- return IM_REGION_SUPERSET;
- }
- else if (v_addr == (unsigned long) tmp->addr &&
- size == tmp->size) {
- /* Return with tmp pointing to exact region */
- return IM_REGION_EXISTS;
- }
- }
-
- return IM_REGION_UNUSED;
-}
-
-static struct vm_struct * split_im_region(unsigned long v_addr,
- unsigned long size, struct vm_struct *parent)
-{
- struct vm_struct *vm1 = NULL;
- struct vm_struct *vm2 = NULL;
- struct vm_struct *new_vm = NULL;
-
- vm1 = kmalloc(sizeof(*vm1), GFP_KERNEL);
- if (vm1 == NULL) {
- printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
- return NULL;
- }
-
- if (v_addr == (unsigned long) parent->addr) {
- /* Use existing parent vm_struct to represent child, allocate
- * new one for the remainder of parent range
- */
- vm1->size = parent->size - size;
- vm1->addr = (void *) (v_addr + size);
- vm1->next = parent->next;
-
- parent->size = size;
- parent->next = vm1;
- new_vm = parent;
- } else if (v_addr + size == (unsigned long) parent->addr +
- parent->size) {
- /* Allocate new vm_struct to represent child, use existing
- * parent one for remainder of parent range
- */
- vm1->size = size;
- vm1->addr = (void *) v_addr;
- vm1->next = parent->next;
- new_vm = vm1;
-
- parent->size -= size;
- parent->next = vm1;
- } else {
- /* Allocate two new vm_structs for the new child and
- * uppermost remainder, and use existing parent one for the
- * lower remainder of parent range
- */
- vm2 = kmalloc(sizeof(*vm2), GFP_KERNEL);
- if (vm2 == NULL) {
- printk(KERN_ERR "%s() out of memory\n", __FUNCTION__);
- kfree(vm1);
- return NULL;
- }
-
- vm1->size = size;
- vm1->addr = (void *) v_addr;
- vm1->next = vm2;
- new_vm = vm1;
-
- vm2->size = ((unsigned long) parent->addr + parent->size) -
- (v_addr + size);
- vm2->addr = (void *) v_addr + size;
- vm2->next = parent->next;
-
- parent->size = v_addr - (unsigned long) parent->addr;
- parent->next = vm1;
- }
-
- return new_vm;
-}
-
-static struct vm_struct * __add_new_im_area(unsigned long req_addr,
- unsigned long size)
-{
- struct vm_struct **p, *tmp, *area;
-
- for (p = &imlist; (tmp = *p) ; p = &tmp->next) {
- if (req_addr + size <= (unsigned long)tmp->addr)
- break;
- }
-
- area = kmalloc(sizeof(*area), GFP_KERNEL);
- if (!area)
- return NULL;
- area->flags = 0;
- area->addr = (void *)req_addr;
- area->size = size;
- area->next = *p;
- *p = area;
-
- return area;
-}
-
-static struct vm_struct * __im_get_area(unsigned long req_addr,
- unsigned long size,
- int criteria)
-{
- struct vm_struct *tmp;
- int status;
-
- status = im_region_status(req_addr, size, &tmp);
- if ((criteria & status) == 0) {
- return NULL;
- }
-
- switch (status) {
- case IM_REGION_UNUSED:
- tmp = __add_new_im_area(req_addr, size);
- break;
- case IM_REGION_SUBSET:
- tmp = split_im_region(req_addr, size, tmp);
- break;
- case IM_REGION_EXISTS:
- /* Return requested region */
- break;
- case IM_REGION_SUPERSET:
- /* Return first existing subset of requested region */
- break;
- default:
- printk(KERN_ERR "%s() unexpected imalloc region status\n",
- __FUNCTION__);
- tmp = NULL;
- }
-
- return tmp;
-}
-
-struct vm_struct * im_get_free_area(unsigned long size)
-{
- struct vm_struct *area;
- unsigned long addr;
-
- mutex_lock(&imlist_mutex);
- if (get_free_im_addr(size, &addr)) {
- printk(KERN_ERR "%s() cannot obtain addr for size 0x%lx\n",
- __FUNCTION__, size);
- area = NULL;
- goto next_im_done;
- }
-
- area = __im_get_area(addr, size, IM_REGION_UNUSED);
- if (area == NULL) {
- printk(KERN_ERR
- "%s() cannot obtain area for addr 0x%lx size 0x%lx\n",
- __FUNCTION__, addr, size);
- }
-next_im_done:
- mutex_unlock(&imlist_mutex);
- return area;
-}
-
-struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
- int criteria)
-{
- struct vm_struct *area;
-
- mutex_lock(&imlist_mutex);
- area = __im_get_area(v_addr, size, criteria);
- mutex_unlock(&imlist_mutex);
- return area;
-}
-
-void im_free(void * addr)
-{
- struct vm_struct **p, *tmp;
-
- if (!addr)
- return;
- if ((unsigned long) addr & ~PAGE_MASK) {
- printk(KERN_ERR "Trying to %s bad address (%p)\n", __FUNCTION__, addr);
- return;
- }
- mutex_lock(&imlist_mutex);
- for (p = &imlist ; (tmp = *p) ; p = &tmp->next) {
- if (tmp->addr == addr) {
- *p = tmp->next;
- unmap_vm_area(tmp);
- kfree(tmp);
- mutex_unlock(&imlist_mutex);
- return;
- }
- }
- mutex_unlock(&imlist_mutex);
- printk(KERN_ERR "Trying to %s nonexistent area (%p)\n", __FUNCTION__,
- addr);
-}
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 5fce6ccecb8d..e1f5ded851f6 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -5,7 +5,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
* PPC44x/36-bit changes by Matt Porter (mporter@mvista.com)
*
* Derived from "arch/i386/mm/init.c"
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 7312a265545f..9f27bb56a61d 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -5,7 +5,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -179,7 +178,6 @@ void pgtable_cache_init(void)
pgtable_cache[i] = kmem_cache_create(name,
size, size,
SLAB_PANIC,
- zero_ctor,
- NULL);
+ zero_ctor);
}
}
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 0266a94d83b6..f0e7eedb1ba3 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -5,7 +5,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
* PPC44x/36-bit changes by Matt Porter (mporter@mvista.com)
*
* Derived from "arch/i386/mm/init.c"
@@ -129,8 +128,6 @@ int __devinit arch_add_memory(int nid, u64 start, u64 size)
zone = pgdata->node_zones;
return __add_pages(zone, start_pfn, nr_pages);
-
- return 0;
}
/*
diff --git a/arch/powerpc/mm/mmu_context_32.c b/arch/powerpc/mm/mmu_context_32.c
index 792086b01000..cc32ba41d900 100644
--- a/arch/powerpc/mm/mmu_context_32.c
+++ b/arch/powerpc/mm/mmu_context_32.c
@@ -11,7 +11,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h
index 2558c34eedaa..c94a64fd3c01 100644
--- a/arch/powerpc/mm/mmu_decl.h
+++ b/arch/powerpc/mm/mmu_decl.h
@@ -8,7 +8,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -40,8 +39,8 @@ extern int __map_without_bats;
extern unsigned long ioremap_base;
extern unsigned int rtas_data, rtas_size;
-struct _PTE;
-extern struct _PTE *Hash, *Hash_end;
+struct hash_pte;
+extern struct hash_pte *Hash, *Hash_end;
extern unsigned long Hash_size, Hash_mask;
extern unsigned int num_tlbcam_entries;
@@ -90,16 +89,4 @@ static inline void flush_HPTE(unsigned context, unsigned long va,
else
_tlbie(va);
}
-#else /* CONFIG_PPC64 */
-/* imalloc region types */
-#define IM_REGION_UNUSED 0x1
-#define IM_REGION_SUBSET 0x2
-#define IM_REGION_EXISTS 0x4
-#define IM_REGION_OVERLAP 0x8
-#define IM_REGION_SUPERSET 0x10
-
-extern struct vm_struct * im_get_free_area(unsigned long size);
-extern struct vm_struct * im_get_area(unsigned long v_addr, unsigned long size,
- int region_type);
-extern void im_free(void *addr);
#endif
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index f6ae1a57d652..64488723162a 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -8,7 +8,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -37,7 +36,6 @@
unsigned long ioremap_base;
unsigned long ioremap_bot;
EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */
-int io_bat_index;
#if defined(CONFIG_6xx) || defined(CONFIG_POWER3)
#define HAVE_BATS 1
@@ -300,51 +298,6 @@ void __init mapin_ram(void)
}
}
-/* is x a power of 4? */
-#define is_power_of_4(x) is_power_of_2(x) && (ffs(x) & 1)
-
-/*
- * Set up a mapping for a block of I/O.
- * virt, phys, size must all be page-aligned.
- * This should only be called before ioremap is called.
- */
-void __init io_block_mapping(unsigned long virt, phys_addr_t phys,
- unsigned int size, int flags)
-{
- int i;
-
- if (virt > KERNELBASE && virt < ioremap_bot)
- ioremap_bot = ioremap_base = virt;
-
-#ifdef HAVE_BATS
- /*
- * Use a BAT for this if possible...
- */
- if (io_bat_index < 2 && is_power_of_2(size)
- && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
- setbat(io_bat_index, virt, phys, size, flags);
- ++io_bat_index;
- return;
- }
-#endif /* HAVE_BATS */
-
-#ifdef HAVE_TLBCAM
- /*
- * Use a CAM for this if possible...
- */
- if (tlbcam_index < num_tlbcam_entries && is_power_of_4(size)
- && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
- settlbcam(tlbcam_index, virt, phys, size, flags, 0);
- ++tlbcam_index;
- return;
- }
-#endif /* HAVE_TLBCAM */
-
- /* No BATs available, put it in the page tables. */
- for (i = 0; i < size; i += PAGE_SIZE)
- map_page(virt + i, phys + i, flags);
-}
-
/* Scan the real Linux page tables and return a PTE pointer for
* a virtual address in a context.
* Returns true (1) if PTE was found, zero otherwise. The pointer to
@@ -379,82 +332,6 @@ get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
return(retval);
}
-/* Find physical address for this virtual address. Normally used by
- * I/O functions, but anyone can call it.
- */
-unsigned long iopa(unsigned long addr)
-{
- unsigned long pa;
-
- /* I don't know why this won't work on PMacs or CHRP. It
- * appears there is some bug, or there is some implicit
- * mapping done not properly represented by BATs or in page
- * tables.......I am actively working on resolving this, but
- * can't hold up other stuff. -- Dan
- */
- pte_t *pte;
- struct mm_struct *mm;
-
- /* Check the BATs */
- pa = v_mapped_by_bats(addr);
- if (pa)
- return pa;
-
- /* Allow mapping of user addresses (within the thread)
- * for DMA if necessary.
- */
- if (addr < TASK_SIZE)
- mm = current->mm;
- else
- mm = &init_mm;
-
- pa = 0;
- if (get_pteptr(mm, addr, &pte, NULL)) {
- pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
- pte_unmap(pte);
- }
-
- return(pa);
-}
-
-/* This is will find the virtual address for a physical one....
- * Swiped from APUS, could be dangerous :-).
- * This is only a placeholder until I really find a way to make this
- * work. -- Dan
- */
-unsigned long
-mm_ptov (unsigned long paddr)
-{
- unsigned long ret;
-#if 0
- if (paddr < 16*1024*1024)
- ret = ZTWO_VADDR(paddr);
- else {
- int i;
-
- for (i = 0; i < kmap_chunk_count;){
- unsigned long phys = kmap_chunks[i++];
- unsigned long size = kmap_chunks[i++];
- unsigned long virt = kmap_chunks[i++];
- if (paddr >= phys
- && paddr < (phys + size)){
- ret = virt + paddr - phys;
- goto exit;
- }
- }
-
- ret = (unsigned long) __va(paddr);
- }
-exit:
-#ifdef DEBUGPV
- printk ("PTOV(%lx)=%lx\n", paddr, ret);
-#endif
-#else
- ret = (unsigned long)paddr + KERNELBASE;
-#endif
- return ret;
-}
-
#ifdef CONFIG_DEBUG_PAGEALLOC
static int __change_page_attr(struct page *page, pgprot_t prot)
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index ad6e135bf212..3dfd10db931a 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -7,7 +7,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@samba.org)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -34,41 +33,27 @@
#include <linux/stddef.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/idr.h>
-#include <linux/nodemask.h>
-#include <linux/module.h>
#include <asm/pgalloc.h>
#include <asm/page.h>
#include <asm/prom.h>
-#include <asm/lmb.h>
-#include <asm/rtas.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/mmu.h>
-#include <asm/uaccess.h>
#include <asm/smp.h>
#include <asm/machdep.h>
#include <asm/tlb.h>
-#include <asm/eeh.h>
#include <asm/processor.h>
-#include <asm/mmzone.h>
#include <asm/cputable.h>
#include <asm/sections.h>
#include <asm/system.h>
-#include <asm/iommu.h>
#include <asm/abs_addr.h>
-#include <asm/vdso.h>
#include <asm/firmware.h>
#include "mmu_decl.h"
-unsigned long ioremap_bot = IMALLOC_BASE;
-static unsigned long phbs_io_bot = PHBS_IO_BASE;
+unsigned long ioremap_bot = IOREMAP_BASE;
/*
* map_io_page currently only called by __ioremap
@@ -102,8 +87,8 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
* entry in the hardware page table.
*
*/
- if (htab_bolt_mapping(ea, ea + PAGE_SIZE, pa, flags,
- mmu_io_psize)) {
+ if (htab_bolt_mapping(ea, (unsigned long)ea + PAGE_SIZE,
+ pa, flags, mmu_io_psize)) {
printk(KERN_ERR "Failed to do bolted mapping IO "
"memory at %016lx !\n", pa);
return -ENOMEM;
@@ -113,8 +98,11 @@ static int map_io_page(unsigned long ea, unsigned long pa, int flags)
}
-static void __iomem * __ioremap_com(phys_addr_t addr, unsigned long pa,
- unsigned long ea, unsigned long size,
+/**
+ * __ioremap_at - Low level function to establish the page tables
+ * for an IO mapping
+ */
+void __iomem * __ioremap_at(phys_addr_t pa, void *ea, unsigned long size,
unsigned long flags)
{
unsigned long i;
@@ -122,17 +110,35 @@ static void __iomem * __ioremap_com(phys_addr_t addr, unsigned long pa,
if ((flags & _PAGE_PRESENT) == 0)
flags |= pgprot_val(PAGE_KERNEL);
+ WARN_ON(pa & ~PAGE_MASK);
+ WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
+ WARN_ON(size & ~PAGE_MASK);
+
for (i = 0; i < size; i += PAGE_SIZE)
- if (map_io_page(ea+i, pa+i, flags))
+ if (map_io_page((unsigned long)ea+i, pa+i, flags))
return NULL;
- return (void __iomem *) (ea + (addr & ~PAGE_MASK));
+ return (void __iomem *)ea;
+}
+
+/**
+ * __iounmap_from - Low level function to tear down the page tables
+ * for an IO mapping. This is used for mappings that
+ * are manipulated manually, like partial unmapping of
+ * PCI IOs or ISA space.
+ */
+void __iounmap_at(void *ea, unsigned long size)
+{
+ WARN_ON(((unsigned long)ea) & ~PAGE_MASK);
+ WARN_ON(size & ~PAGE_MASK);
+
+ unmap_kernel_range((unsigned long)ea, size);
}
void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
unsigned long flags)
{
- unsigned long pa, ea;
+ phys_addr_t paligned;
void __iomem *ret;
/*
@@ -144,27 +150,30 @@ void __iomem * __ioremap(phys_addr_t addr, unsigned long size,
* IMALLOC_END
*
*/
- pa = addr & PAGE_MASK;
- size = PAGE_ALIGN(addr + size) - pa;
+ paligned = addr & PAGE_MASK;
+ size = PAGE_ALIGN(addr + size) - paligned;
- if ((size == 0) || (pa == 0))
+ if ((size == 0) || (paligned == 0))
return NULL;
if (mem_init_done) {
struct vm_struct *area;
- area = im_get_free_area(size);
+
+ area = __get_vm_area(size, VM_IOREMAP,
+ ioremap_bot, IOREMAP_END);
if (area == NULL)
return NULL;
- ea = (unsigned long)(area->addr);
- ret = __ioremap_com(addr, pa, ea, size, flags);
+ ret = __ioremap_at(paligned, area->addr, size, flags);
if (!ret)
- im_free(area->addr);
+ vunmap(area->addr);
} else {
- ea = ioremap_bot;
- ret = __ioremap_com(addr, pa, ea, size, flags);
+ ret = __ioremap_at(paligned, (void *)ioremap_bot, size, flags);
if (ret)
ioremap_bot += size;
}
+
+ if (ret)
+ ret += addr & ~PAGE_MASK;
return ret;
}
@@ -187,62 +196,9 @@ void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size,
}
-#define IS_PAGE_ALIGNED(_val) ((_val) == ((_val) & PAGE_MASK))
-
-int __ioremap_explicit(phys_addr_t pa, unsigned long ea,
- unsigned long size, unsigned long flags)
-{
- struct vm_struct *area;
- void __iomem *ret;
-
- /* For now, require page-aligned values for pa, ea, and size */
- if (!IS_PAGE_ALIGNED(pa) || !IS_PAGE_ALIGNED(ea) ||
- !IS_PAGE_ALIGNED(size)) {
- printk(KERN_ERR "unaligned value in %s\n", __FUNCTION__);
- return 1;
- }
-
- if (!mem_init_done) {
- /* Two things to consider in this case:
- * 1) No records will be kept (imalloc, etc) that the region
- * has been remapped
- * 2) It won't be easy to iounmap() the region later (because
- * of 1)
- */
- ;
- } else {
- area = im_get_area(ea, size,
- IM_REGION_UNUSED|IM_REGION_SUBSET|IM_REGION_EXISTS);
- if (area == NULL) {
- /* Expected when PHB-dlpar is in play */
- return 1;
- }
- if (ea != (unsigned long) area->addr) {
- printk(KERN_ERR "unexpected addr return from "
- "im_get_area\n");
- return 1;
- }
- }
-
- ret = __ioremap_com(pa, pa, ea, size, flags);
- if (ret == NULL) {
- printk(KERN_ERR "ioremap_explicit() allocation failure !\n");
- return 1;
- }
- if (ret != (void *) ea) {
- printk(KERN_ERR "__ioremap_com() returned unexpected addr\n");
- return 1;
- }
-
- return 0;
-}
-
/*
* Unmap an IO region and remove it from imalloc'd list.
* Access to IO memory should be serialized by driver.
- * This code is modeled after vmalloc code - unmap_vm_area()
- *
- * XXX what about calls before mem_init_done (ie python_countermeasures())
*/
void __iounmap(volatile void __iomem *token)
{
@@ -251,9 +207,14 @@ void __iounmap(volatile void __iomem *token)
if (!mem_init_done)
return;
- addr = (void *) ((unsigned long __force) token & PAGE_MASK);
-
- im_free(addr);
+ addr = (void *) ((unsigned long __force)
+ PCI_FIX_ADDR(token) & PAGE_MASK);
+ if ((unsigned long)addr < ioremap_bot) {
+ printk(KERN_WARNING "Attempt to iounmap early bolted mapping"
+ " at 0x%p\n", addr);
+ return;
+ }
+ vunmap(addr);
}
void iounmap(volatile void __iomem *token)
@@ -264,77 +225,8 @@ void iounmap(volatile void __iomem *token)
__iounmap(token);
}
-static int iounmap_subset_regions(unsigned long addr, unsigned long size)
-{
- struct vm_struct *area;
-
- /* Check whether subsets of this region exist */
- area = im_get_area(addr, size, IM_REGION_SUPERSET);
- if (area == NULL)
- return 1;
-
- while (area) {
- iounmap((void __iomem *) area->addr);
- area = im_get_area(addr, size,
- IM_REGION_SUPERSET);
- }
-
- return 0;
-}
-
-int __iounmap_explicit(volatile void __iomem *start, unsigned long size)
-{
- struct vm_struct *area;
- unsigned long addr;
- int rc;
-
- addr = (unsigned long __force) start & PAGE_MASK;
-
- /* Verify that the region either exists or is a subset of an existing
- * region. In the latter case, split the parent region to create
- * the exact region
- */
- area = im_get_area(addr, size,
- IM_REGION_EXISTS | IM_REGION_SUBSET);
- if (area == NULL) {
- /* Determine whether subset regions exist. If so, unmap */
- rc = iounmap_subset_regions(addr, size);
- if (rc) {
- printk(KERN_ERR
- "%s() cannot unmap nonexistent range 0x%lx\n",
- __FUNCTION__, addr);
- return 1;
- }
- } else {
- iounmap((void __iomem *) area->addr);
- }
- /*
- * FIXME! This can't be right:
- iounmap(area->addr);
- * Maybe it should be "iounmap(area);"
- */
- return 0;
-}
-
EXPORT_SYMBOL(ioremap);
EXPORT_SYMBOL(ioremap_flags);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap);
EXPORT_SYMBOL(__iounmap);
-
-static DEFINE_SPINLOCK(phb_io_lock);
-
-void __iomem * reserve_phb_iospace(unsigned long size)
-{
- void __iomem *virt_addr;
-
- if (phbs_io_bot >= IMALLOC_BASE)
- panic("reserve_phb_iospace(): phb io space overflow\n");
-
- spin_lock(&phb_io_lock);
- virt_addr = (void __iomem *) phbs_io_bot;
- phbs_io_bot += size;
- spin_unlock(&phb_io_lock);
-
- return virt_addr;
-}
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index ec1421a20aaa..5c45d474cfcc 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -11,7 +11,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -35,12 +34,12 @@
#include "mmu_decl.h"
-PTE *Hash, *Hash_end;
+struct hash_pte *Hash, *Hash_end;
unsigned long Hash_size, Hash_mask;
unsigned long _SDR1;
union ubat { /* BAT register values to be loaded */
- BAT bat;
+ struct ppc_bat bat;
u32 word[2];
} BATS[8][2]; /* 8 pairs of IBAT, DBAT */
@@ -245,7 +244,7 @@ void __init MMU_init_hw(void)
cacheable_memzero(Hash, Hash_size);
_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
- Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+ Hash_end = (struct hash_pte *) ((unsigned long)Hash + Hash_size);
printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
total_memory >> 20, Hash_size >> 10, Hash);
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 132c6bc66ce1..28492bbdee8e 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -55,7 +55,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
for (entry = 0; entry < 8; entry++, ste++) {
if (!(ste->esid_data & STE_ESID_V)) {
ste->vsid_data = vsid_data;
- asm volatile("eieio":::"memory");
+ eieio();
ste->esid_data = esid_data;
return (global_entry | entry);
}
@@ -101,7 +101,7 @@ static int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
asm volatile("sync" : : : "memory"); /* Order update */
castout_ste->vsid_data = vsid_data;
- asm volatile("eieio" : : : "memory"); /* Order update */
+ eieio(); /* Order update */
castout_ste->esid_data = esid_data;
asm volatile("slbie %0" : : "r" (old_esid << SID_SHIFT));
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c
index 6a69417cbc0e..eb4b512d65fa 100644
--- a/arch/powerpc/mm/tlb_32.c
+++ b/arch/powerpc/mm/tlb_32.c
@@ -11,7 +11,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -27,6 +26,8 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/highmem.h>
+#include <linux/pagemap.h>
+
#include <asm/tlbflush.h>
#include <asm/tlb.h>
diff --git a/arch/powerpc/mm/tlb_64.c b/arch/powerpc/mm/tlb_64.c
index 2bfc4d7e1aa2..cbd34fc813ee 100644
--- a/arch/powerpc/mm/tlb_64.c
+++ b/arch/powerpc/mm/tlb_64.c
@@ -8,7 +8,6 @@
* Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
* and Cort Dougan (PReP) (cort@cs.nmt.edu)
* Copyright (C) 1996 Paul Mackerras
- * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
*
* Derived from "arch/i386/mm/init.c"
* Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
@@ -239,3 +238,59 @@ void pte_free_finish(void)
pte_free_submit(*batchp);
*batchp = NULL;
}
+
+/**
+ * __flush_hash_table_range - Flush all HPTEs for a given address range
+ * from the hash table (and the TLB). But keeps
+ * the linux PTEs intact.
+ *
+ * @mm : mm_struct of the target address space (generally init_mm)
+ * @start : starting address
+ * @end : ending address (not included in the flush)
+ *
+ * This function is mostly to be used by some IO hotplug code in order
+ * to remove all hash entries from a given address range used to map IO
+ * space on a removed PCI-PCI bidge without tearing down the full mapping
+ * since 64K pages may overlap with other bridges when using 64K pages
+ * with 4K HW pages on IO space.
+ *
+ * Because of that usage pattern, it's only available with CONFIG_HOTPLUG
+ * and is implemented for small size rather than speed.
+ */
+#ifdef CONFIG_HOTPLUG
+
+void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ unsigned long flags;
+
+ start = _ALIGN_DOWN(start, PAGE_SIZE);
+ end = _ALIGN_UP(end, PAGE_SIZE);
+
+ BUG_ON(!mm->pgd);
+
+ /* Note: Normally, we should only ever use a batch within a
+ * PTE locked section. This violates the rule, but will work
+ * since we don't actually modify the PTEs, we just flush the
+ * hash while leaving the PTEs intact (including their reference
+ * to being hashed). This is not the most performance oriented
+ * way to do things but is fine for our needs here.
+ */
+ local_irq_save(flags);
+ arch_enter_lazy_mmu_mode();
+ for (; start < end; start += PAGE_SIZE) {
+ pte_t *ptep = find_linux_pte(mm->pgd, start);
+ unsigned long pte;
+
+ if (ptep == NULL)
+ continue;
+ pte = pte_val(*ptep);
+ if (!(pte & _PAGE_HASHPTE))
+ continue;
+ hpte_need_flush(mm, start, ptep, pte, 0);
+ }
+ arch_leave_lazy_mmu_mode();
+ local_irq_restore(flags);
+}
+
+#endif /* CONFIG_HOTPLUG */
diff --git a/arch/powerpc/oprofile/Kconfig b/arch/powerpc/oprofile/Kconfig
index eb2dece76a54..7089e79689b9 100644
--- a/arch/powerpc/oprofile/Kconfig
+++ b/arch/powerpc/oprofile/Kconfig
@@ -15,3 +15,10 @@ config OPROFILE
If unsure, say N.
+config OPROFILE_CELL
+ bool "OProfile for Cell Broadband Engine"
+ depends on (SPU_FS = y && OPROFILE = m) || (SPU_FS = y && OPROFILE = y) || (SPU_FS = m && OPROFILE = m)
+ default y
+ help
+ Profiling of Cell BE SPUs requires special support enabled
+ by this option.
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 4b5f9528218c..c5f64c3bd668 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -11,7 +11,9 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
timer_int.o )
oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
-oprofile-$(CONFIG_PPC_CELL_NATIVE) += op_model_cell.o
+oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
+ cell/spu_profiler.o cell/vma_map.o \
+ cell/spu_task_sync.o
oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
oprofile-$(CONFIG_6xx) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/cell/pr_util.h b/arch/powerpc/oprofile/cell/pr_util.h
new file mode 100644
index 000000000000..e5704f00c8b4
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/pr_util.h
@@ -0,0 +1,97 @@
+ /*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef PR_UTIL_H
+#define PR_UTIL_H
+
+#include <linux/cpumask.h>
+#include <linux/oprofile.h>
+#include <asm/cell-pmu.h>
+#include <asm/spu.h>
+
+#include "../../platforms/cell/cbe_regs.h"
+
+/* Defines used for sync_start */
+#define SKIP_GENERIC_SYNC 0
+#define SYNC_START_ERROR -1
+#define DO_GENERIC_SYNC 1
+
+struct spu_overlay_info { /* map of sections within an SPU overlay */
+ unsigned int vma; /* SPU virtual memory address from elf */
+ unsigned int size; /* size of section from elf */
+ unsigned int offset; /* offset of section into elf file */
+ unsigned int buf;
+};
+
+struct vma_to_fileoffset_map { /* map of sections within an SPU program */
+ struct vma_to_fileoffset_map *next; /* list pointer */
+ unsigned int vma; /* SPU virtual memory address from elf */
+ unsigned int size; /* size of section from elf */
+ unsigned int offset; /* offset of section into elf file */
+ unsigned int guard_ptr;
+ unsigned int guard_val;
+ /*
+ * The guard pointer is an entry in the _ovly_buf_table,
+ * computed using ovly.buf as the index into the table. Since
+ * ovly.buf values begin at '1' to reference the first (or 0th)
+ * entry in the _ovly_buf_table, the computation subtracts 1
+ * from ovly.buf.
+ * The guard value is stored in the _ovly_buf_table entry and
+ * is an index (starting at 1) back to the _ovly_table entry
+ * that is pointing at this _ovly_buf_table entry. So, for
+ * example, for an overlay scenario with one overlay segment
+ * and two overlay sections:
+ * - Section 1 points to the first entry of the
+ * _ovly_buf_table, which contains a guard value
+ * of '1', referencing the first (index=0) entry of
+ * _ovly_table.
+ * - Section 2 points to the second entry of the
+ * _ovly_buf_table, which contains a guard value
+ * of '2', referencing the second (index=1) entry of
+ * _ovly_table.
+ */
+
+};
+
+/* The three functions below are for maintaining and accessing
+ * the vma-to-fileoffset map.
+ */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *spu,
+ u64 objectid);
+unsigned int vma_map_lookup(struct vma_to_fileoffset_map *map,
+ unsigned int vma, const struct spu *aSpu,
+ int *grd_val);
+void vma_map_free(struct vma_to_fileoffset_map *map);
+
+/*
+ * Entry point for SPU profiling.
+ * cycles_reset is the SPU_CYCLES count value specified by the user.
+ */
+int start_spu_profiling(unsigned int cycles_reset);
+
+void stop_spu_profiling(void);
+
+
+/* add the necessary profiling hooks */
+int spu_sync_start(void);
+
+/* remove the hooks */
+int spu_sync_stop(void);
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+ int num_samples);
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset);
+
+#endif /* PR_UTIL_H */
diff --git a/arch/powerpc/oprofile/cell/spu_profiler.c b/arch/powerpc/oprofile/cell/spu_profiler.c
new file mode 100644
index 000000000000..380d7e217531
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/spu_profiler.c
@@ -0,0 +1,221 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Authors: Maynard Johnson <maynardj@us.ibm.com>
+ * Carl Love <carll@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/hrtimer.h>
+#include <linux/smp.h>
+#include <linux/slab.h>
+#include <asm/cell-pmu.h>
+#include "pr_util.h"
+
+#define TRACE_ARRAY_SIZE 1024
+#define SCALE_SHIFT 14
+
+static u32 *samples;
+
+static int spu_prof_running;
+static unsigned int profiling_interval;
+
+#define NUM_SPU_BITS_TRBUF 16
+#define SPUS_PER_TB_ENTRY 4
+#define SPUS_PER_NODE 8
+
+#define SPU_PC_MASK 0xFFFF
+
+static DEFINE_SPINLOCK(sample_array_lock);
+unsigned long sample_array_lock_flags;
+
+void set_spu_profiling_frequency(unsigned int freq_khz, unsigned int cycles_reset)
+{
+ unsigned long ns_per_cyc;
+
+ if (!freq_khz)
+ freq_khz = ppc_proc_freq/1000;
+
+ /* To calculate a timeout in nanoseconds, the basic
+ * formula is ns = cycles_reset * (NSEC_PER_SEC / cpu frequency).
+ * To avoid floating point math, we use the scale math
+ * technique as described in linux/jiffies.h. We use
+ * a scale factor of SCALE_SHIFT, which provides 4 decimal places
+ * of precision. This is close enough for the purpose at hand.
+ *
+ * The value of the timeout should be small enough that the hw
+ * trace buffer will not get more then about 1/3 full for the
+ * maximum user specified (the LFSR value) hw sampling frequency.
+ * This is to ensure the trace buffer will never fill even if the
+ * kernel thread scheduling varies under a heavy system load.
+ */
+
+ ns_per_cyc = (USEC_PER_SEC << SCALE_SHIFT)/freq_khz;
+ profiling_interval = (ns_per_cyc * cycles_reset) >> SCALE_SHIFT;
+
+}
+
+/*
+ * Extract SPU PC from trace buffer entry
+ */
+static void spu_pc_extract(int cpu, int entry)
+{
+ /* the trace buffer is 128 bits */
+ u64 trace_buffer[2];
+ u64 spu_mask;
+ int spu;
+
+ spu_mask = SPU_PC_MASK;
+
+ /* Each SPU PC is 16 bits; hence, four spus in each of
+ * the two 64-bit buffer entries that make up the
+ * 128-bit trace_buffer entry. Process two 64-bit values
+ * simultaneously.
+ * trace[0] SPU PC contents are: 0 1 2 3
+ * trace[1] SPU PC contents are: 4 5 6 7
+ */
+
+ cbe_read_trace_buffer(cpu, trace_buffer);
+
+ for (spu = SPUS_PER_TB_ENTRY-1; spu >= 0; spu--) {
+ /* spu PC trace entry is upper 16 bits of the
+ * 18 bit SPU program counter
+ */
+ samples[spu * TRACE_ARRAY_SIZE + entry]
+ = (spu_mask & trace_buffer[0]) << 2;
+ samples[(spu + SPUS_PER_TB_ENTRY) * TRACE_ARRAY_SIZE + entry]
+ = (spu_mask & trace_buffer[1]) << 2;
+
+ trace_buffer[0] = trace_buffer[0] >> NUM_SPU_BITS_TRBUF;
+ trace_buffer[1] = trace_buffer[1] >> NUM_SPU_BITS_TRBUF;
+ }
+}
+
+static int cell_spu_pc_collection(int cpu)
+{
+ u32 trace_addr;
+ int entry;
+
+ /* process the collected SPU PC for the node */
+
+ entry = 0;
+
+ trace_addr = cbe_read_pm(cpu, trace_address);
+ while (!(trace_addr & CBE_PM_TRACE_BUF_EMPTY)) {
+ /* there is data in the trace buffer to process */
+ spu_pc_extract(cpu, entry);
+
+ entry++;
+
+ if (entry >= TRACE_ARRAY_SIZE)
+ /* spu_samples is full */
+ break;
+
+ trace_addr = cbe_read_pm(cpu, trace_address);
+ }
+
+ return entry;
+}
+
+
+static enum hrtimer_restart profile_spus(struct hrtimer *timer)
+{
+ ktime_t kt;
+ int cpu, node, k, num_samples, spu_num;
+
+ if (!spu_prof_running)
+ goto stop;
+
+ for_each_online_cpu(cpu) {
+ if (cbe_get_hw_thread_id(cpu))
+ continue;
+
+ node = cbe_cpu_to_node(cpu);
+
+ /* There should only be one kernel thread at a time processing
+ * the samples. In the very unlikely case that the processing
+ * is taking a very long time and multiple kernel threads are
+ * started to process the samples. Make sure only one kernel
+ * thread is working on the samples array at a time. The
+ * sample array must be loaded and then processed for a given
+ * cpu. The sample array is not per cpu.
+ */
+ spin_lock_irqsave(&sample_array_lock,
+ sample_array_lock_flags);
+ num_samples = cell_spu_pc_collection(cpu);
+
+ if (num_samples == 0) {
+ spin_unlock_irqrestore(&sample_array_lock,
+ sample_array_lock_flags);
+ continue;
+ }
+
+ for (k = 0; k < SPUS_PER_NODE; k++) {
+ spu_num = k + (node * SPUS_PER_NODE);
+ spu_sync_buffer(spu_num,
+ samples + (k * TRACE_ARRAY_SIZE),
+ num_samples);
+ }
+
+ spin_unlock_irqrestore(&sample_array_lock,
+ sample_array_lock_flags);
+
+ }
+ smp_wmb(); /* insure spu event buffer updates are written */
+ /* don't want events intermingled... */
+
+ kt = ktime_set(0, profiling_interval);
+ if (!spu_prof_running)
+ goto stop;
+ hrtimer_forward(timer, timer->base->get_time(), kt);
+ return HRTIMER_RESTART;
+
+ stop:
+ printk(KERN_INFO "SPU_PROF: spu-prof timer ending\n");
+ return HRTIMER_NORESTART;
+}
+
+static struct hrtimer timer;
+/*
+ * Entry point for SPU profiling.
+ * NOTE: SPU profiling is done system-wide, not per-CPU.
+ *
+ * cycles_reset is the count value specified by the user when
+ * setting up OProfile to count SPU_CYCLES.
+ */
+int start_spu_profiling(unsigned int cycles_reset)
+{
+ ktime_t kt;
+
+ pr_debug("timer resolution: %lu\n", TICK_NSEC);
+ kt = ktime_set(0, profiling_interval);
+ hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ timer.expires = kt;
+ timer.function = profile_spus;
+
+ /* Allocate arrays for collecting SPU PC samples */
+ samples = kzalloc(SPUS_PER_NODE *
+ TRACE_ARRAY_SIZE * sizeof(u32), GFP_KERNEL);
+
+ if (!samples)
+ return -ENOMEM;
+
+ spu_prof_running = 1;
+ hrtimer_start(&timer, kt, HRTIMER_MODE_REL);
+
+ return 0;
+}
+
+void stop_spu_profiling(void)
+{
+ spu_prof_running = 0;
+ hrtimer_cancel(&timer);
+ kfree(samples);
+ pr_debug("SPU_PROF: stop_spu_profiling issued\n");
+}
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c
new file mode 100644
index 000000000000..133665754a75
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/spu_task_sync.c
@@ -0,0 +1,484 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The purpose of this file is to handle SPU event task switching
+ * and to record SPU context information into the OProfile
+ * event buffer.
+ *
+ * Additionally, the spu_sync_buffer function is provided as a helper
+ * for recoding actual SPU program counter samples to the event buffer.
+ */
+#include <linux/dcookies.h>
+#include <linux/kref.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/numa.h>
+#include <linux/oprofile.h>
+#include <linux/spinlock.h>
+#include "pr_util.h"
+
+#define RELEASE_ALL 9999
+
+static DEFINE_SPINLOCK(buffer_lock);
+static DEFINE_SPINLOCK(cache_lock);
+static int num_spu_nodes;
+int spu_prof_num_nodes;
+int last_guard_val[MAX_NUMNODES * 8];
+
+/* Container for caching information about an active SPU task. */
+struct cached_info {
+ struct vma_to_fileoffset_map *map;
+ struct spu *the_spu; /* needed to access pointer to local_store */
+ struct kref cache_ref;
+};
+
+static struct cached_info *spu_info[MAX_NUMNODES * 8];
+
+static void destroy_cached_info(struct kref *kref)
+{
+ struct cached_info *info;
+
+ info = container_of(kref, struct cached_info, cache_ref);
+ vma_map_free(info->map);
+ kfree(info);
+ module_put(THIS_MODULE);
+}
+
+/* Return the cached_info for the passed SPU number.
+ * ATTENTION: Callers are responsible for obtaining the
+ * cache_lock if needed prior to invoking this function.
+ */
+static struct cached_info *get_cached_info(struct spu *the_spu, int spu_num)
+{
+ struct kref *ref;
+ struct cached_info *ret_info;
+
+ if (spu_num >= num_spu_nodes) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Invalid index %d into spu info cache\n",
+ __FUNCTION__, __LINE__, spu_num);
+ ret_info = NULL;
+ goto out;
+ }
+ if (!spu_info[spu_num] && the_spu) {
+ ref = spu_get_profile_private_kref(the_spu->ctx);
+ if (ref) {
+ spu_info[spu_num] = container_of(ref, struct cached_info, cache_ref);
+ kref_get(&spu_info[spu_num]->cache_ref);
+ }
+ }
+
+ ret_info = spu_info[spu_num];
+ out:
+ return ret_info;
+}
+
+
+/* Looks for cached info for the passed spu. If not found, the
+ * cached info is created for the passed spu.
+ * Returns 0 for success; otherwise, -1 for error.
+ */
+static int
+prepare_cached_spu_info(struct spu *spu, unsigned long objectId)
+{
+ unsigned long flags;
+ struct vma_to_fileoffset_map *new_map;
+ int retval = 0;
+ struct cached_info *info;
+
+ /* We won't bother getting cache_lock here since
+ * don't do anything with the cached_info that's returned.
+ */
+ info = get_cached_info(spu, spu->number);
+
+ if (info) {
+ pr_debug("Found cached SPU info.\n");
+ goto out;
+ }
+
+ /* Create cached_info and set spu_info[spu->number] to point to it.
+ * spu->number is a system-wide value, not a per-node value.
+ */
+ info = kzalloc(sizeof(struct cached_info), GFP_KERNEL);
+ if (!info) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: create vma_map failed\n",
+ __FUNCTION__, __LINE__);
+ retval = -ENOMEM;
+ goto err_alloc;
+ }
+ new_map = create_vma_map(spu, objectId);
+ if (!new_map) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: create vma_map failed\n",
+ __FUNCTION__, __LINE__);
+ retval = -ENOMEM;
+ goto err_alloc;
+ }
+
+ pr_debug("Created vma_map\n");
+ info->map = new_map;
+ info->the_spu = spu;
+ kref_init(&info->cache_ref);
+ spin_lock_irqsave(&cache_lock, flags);
+ spu_info[spu->number] = info;
+ /* Increment count before passing off ref to SPUFS. */
+ kref_get(&info->cache_ref);
+
+ /* We increment the module refcount here since SPUFS is
+ * responsible for the final destruction of the cached_info,
+ * and it must be able to access the destroy_cached_info()
+ * function defined in the OProfile module. We decrement
+ * the module refcount in destroy_cached_info.
+ */
+ try_module_get(THIS_MODULE);
+ spu_set_profile_private_kref(spu->ctx, &info->cache_ref,
+ destroy_cached_info);
+ spin_unlock_irqrestore(&cache_lock, flags);
+ goto out;
+
+err_alloc:
+ kfree(info);
+out:
+ return retval;
+}
+
+/*
+ * NOTE: The caller is responsible for locking the
+ * cache_lock prior to calling this function.
+ */
+static int release_cached_info(int spu_index)
+{
+ int index, end;
+
+ if (spu_index == RELEASE_ALL) {
+ end = num_spu_nodes;
+ index = 0;
+ } else {
+ if (spu_index >= num_spu_nodes) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: "
+ "Invalid index %d into spu info cache\n",
+ __FUNCTION__, __LINE__, spu_index);
+ goto out;
+ }
+ end = spu_index + 1;
+ index = spu_index;
+ }
+ for (; index < end; index++) {
+ if (spu_info[index]) {
+ kref_put(&spu_info[index]->cache_ref,
+ destroy_cached_info);
+ spu_info[index] = NULL;
+ }
+ }
+
+out:
+ return 0;
+}
+
+/* The source code for fast_get_dcookie was "borrowed"
+ * from drivers/oprofile/buffer_sync.c.
+ */
+
+/* Optimisation. We can manage without taking the dcookie sem
+ * because we cannot reach this code without at least one
+ * dcookie user still being registered (namely, the reader
+ * of the event buffer).
+ */
+static inline unsigned long fast_get_dcookie(struct dentry *dentry,
+ struct vfsmount *vfsmnt)
+{
+ unsigned long cookie;
+
+ if (dentry->d_cookie)
+ return (unsigned long)dentry;
+ get_dcookie(dentry, vfsmnt, &cookie);
+ return cookie;
+}
+
+/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+ * which corresponds loosely to "application name". Also, determine
+ * the offset for the SPU ELF object. If computed offset is
+ * non-zero, it implies an embedded SPU object; otherwise, it's a
+ * separate SPU binary, in which case we retrieve it's dcookie.
+ * For the embedded case, we must determine if SPU ELF is embedded
+ * in the executable application or another file (i.e., shared lib).
+ * If embedded in a shared lib, we must get the dcookie and return
+ * that to the caller.
+ */
+static unsigned long
+get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
+ unsigned long *spu_bin_dcookie,
+ unsigned long spu_ref)
+{
+ unsigned long app_cookie = 0;
+ unsigned int my_offset = 0;
+ struct file *app = NULL;
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = spu->mm;
+
+ if (!mm)
+ goto out;
+
+ down_read(&mm->mmap_sem);
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (!vma->vm_file)
+ continue;
+ if (!(vma->vm_flags & VM_EXECUTABLE))
+ continue;
+ app_cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ pr_debug("got dcookie for %s\n",
+ vma->vm_file->f_dentry->d_name.name);
+ app = vma->vm_file;
+ break;
+ }
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (vma->vm_start > spu_ref || vma->vm_end <= spu_ref)
+ continue;
+ my_offset = spu_ref - vma->vm_start;
+ if (!vma->vm_file)
+ goto fail_no_image_cookie;
+
+ pr_debug("Found spu ELF at %X(object-id:%lx) for file %s\n",
+ my_offset, spu_ref,
+ vma->vm_file->f_dentry->d_name.name);
+ *offsetp = my_offset;
+ break;
+ }
+
+ *spu_bin_dcookie = fast_get_dcookie(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name);
+
+ up_read(&mm->mmap_sem);
+
+out:
+ return app_cookie;
+
+fail_no_image_cookie:
+ up_read(&mm->mmap_sem);
+
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Cannot find dcookie for SPU binary\n",
+ __FUNCTION__, __LINE__);
+ goto out;
+}
+
+
+
+/* This function finds or creates cached context information for the
+ * passed SPU and records SPU context information into the OProfile
+ * event buffer.
+ */
+static int process_context_switch(struct spu *spu, unsigned long objectId)
+{
+ unsigned long flags;
+ int retval;
+ unsigned int offset = 0;
+ unsigned long spu_cookie = 0, app_dcookie;
+
+ retval = prepare_cached_spu_info(spu, objectId);
+ if (retval)
+ goto out;
+
+ /* Get dcookie first because a mutex_lock is taken in that
+ * code path, so interrupts must not be disabled.
+ */
+ app_dcookie = get_exec_dcookie_and_offset(spu, &offset, &spu_cookie, objectId);
+ if (!app_dcookie || !spu_cookie) {
+ retval = -ENOENT;
+ goto out;
+ }
+
+ /* Record context info in event buffer */
+ spin_lock_irqsave(&buffer_lock, flags);
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(SPU_CTX_SWITCH_CODE);
+ add_event_entry(spu->number);
+ add_event_entry(spu->pid);
+ add_event_entry(spu->tgid);
+ add_event_entry(app_dcookie);
+ add_event_entry(spu_cookie);
+ add_event_entry(offset);
+ spin_unlock_irqrestore(&buffer_lock, flags);
+ smp_wmb(); /* insure spu event buffer updates are written */
+ /* don't want entries intermingled... */
+out:
+ return retval;
+}
+
+/*
+ * This function is invoked on either a bind_context or unbind_context.
+ * If called for an unbind_context, the val arg is 0; otherwise,
+ * it is the object-id value for the spu context.
+ * The data arg is of type 'struct spu *'.
+ */
+static int spu_active_notify(struct notifier_block *self, unsigned long val,
+ void *data)
+{
+ int retval;
+ unsigned long flags;
+ struct spu *the_spu = data;
+
+ pr_debug("SPU event notification arrived\n");
+ if (!val) {
+ spin_lock_irqsave(&cache_lock, flags);
+ retval = release_cached_info(the_spu->number);
+ spin_unlock_irqrestore(&cache_lock, flags);
+ } else {
+ retval = process_context_switch(the_spu, val);
+ }
+ return retval;
+}
+
+static struct notifier_block spu_active = {
+ .notifier_call = spu_active_notify,
+};
+
+static int number_of_online_nodes(void)
+{
+ u32 cpu; u32 tmp;
+ int nodes = 0;
+ for_each_online_cpu(cpu) {
+ tmp = cbe_cpu_to_node(cpu) + 1;
+ if (tmp > nodes)
+ nodes++;
+ }
+ return nodes;
+}
+
+/* The main purpose of this function is to synchronize
+ * OProfile with SPUFS by registering to be notified of
+ * SPU task switches.
+ *
+ * NOTE: When profiling SPUs, we must ensure that only
+ * spu_sync_start is invoked and not the generic sync_start
+ * in drivers/oprofile/oprof.c. A return value of
+ * SKIP_GENERIC_SYNC or SYNC_START_ERROR will
+ * accomplish this.
+ */
+int spu_sync_start(void)
+{
+ int k;
+ int ret = SKIP_GENERIC_SYNC;
+ int register_ret;
+ unsigned long flags = 0;
+
+ spu_prof_num_nodes = number_of_online_nodes();
+ num_spu_nodes = spu_prof_num_nodes * 8;
+
+ spin_lock_irqsave(&buffer_lock, flags);
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(SPU_PROFILING_CODE);
+ add_event_entry(num_spu_nodes);
+ spin_unlock_irqrestore(&buffer_lock, flags);
+
+ /* Register for SPU events */
+ register_ret = spu_switch_event_register(&spu_active);
+ if (register_ret) {
+ ret = SYNC_START_ERROR;
+ goto out;
+ }
+
+ for (k = 0; k < (MAX_NUMNODES * 8); k++)
+ last_guard_val[k] = 0;
+ pr_debug("spu_sync_start -- running.\n");
+out:
+ return ret;
+}
+
+/* Record SPU program counter samples to the oprofile event buffer. */
+void spu_sync_buffer(int spu_num, unsigned int *samples,
+ int num_samples)
+{
+ unsigned long long file_offset;
+ unsigned long flags;
+ int i;
+ struct vma_to_fileoffset_map *map;
+ struct spu *the_spu;
+ unsigned long long spu_num_ll = spu_num;
+ unsigned long long spu_num_shifted = spu_num_ll << 32;
+ struct cached_info *c_info;
+
+ /* We need to obtain the cache_lock here because it's
+ * possible that after getting the cached_info, the SPU job
+ * corresponding to this cached_info may end, thus resulting
+ * in the destruction of the cached_info.
+ */
+ spin_lock_irqsave(&cache_lock, flags);
+ c_info = get_cached_info(NULL, spu_num);
+ if (!c_info) {
+ /* This legitimately happens when the SPU task ends before all
+ * samples are recorded.
+ * No big deal -- so we just drop a few samples.
+ */
+ pr_debug("SPU_PROF: No cached SPU contex "
+ "for SPU #%d. Dropping samples.\n", spu_num);
+ goto out;
+ }
+
+ map = c_info->map;
+ the_spu = c_info->the_spu;
+ spin_lock(&buffer_lock);
+ for (i = 0; i < num_samples; i++) {
+ unsigned int sample = *(samples+i);
+ int grd_val = 0;
+ file_offset = 0;
+ if (sample == 0)
+ continue;
+ file_offset = vma_map_lookup( map, sample, the_spu, &grd_val);
+
+ /* If overlays are used by this SPU application, the guard
+ * value is non-zero, indicating which overlay section is in
+ * use. We need to discard samples taken during the time
+ * period which an overlay occurs (i.e., guard value changes).
+ */
+ if (grd_val && grd_val != last_guard_val[spu_num]) {
+ last_guard_val[spu_num] = grd_val;
+ /* Drop the rest of the samples. */
+ break;
+ }
+
+ add_event_entry(file_offset | spu_num_shifted);
+ }
+ spin_unlock(&buffer_lock);
+out:
+ spin_unlock_irqrestore(&cache_lock, flags);
+}
+
+
+int spu_sync_stop(void)
+{
+ unsigned long flags = 0;
+ int ret = spu_switch_event_unregister(&spu_active);
+ if (ret) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: spu_switch_event_unregister returned %d\n",
+ __FUNCTION__, __LINE__, ret);
+ goto out;
+ }
+
+ spin_lock_irqsave(&cache_lock, flags);
+ ret = release_cached_info(RELEASE_ALL);
+ spin_unlock_irqrestore(&cache_lock, flags);
+out:
+ pr_debug("spu_sync_stop -- done.\n");
+ return ret;
+}
+
+
diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c
new file mode 100644
index 000000000000..76ec1d16aef7
--- /dev/null
+++ b/arch/powerpc/oprofile/cell/vma_map.c
@@ -0,0 +1,287 @@
+/*
+ * Cell Broadband Engine OProfile Support
+ *
+ * (C) Copyright IBM Corporation 2006
+ *
+ * Author: Maynard Johnson <maynardj@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/* The code in this source file is responsible for generating
+ * vma-to-fileOffset maps for both overlay and non-overlay SPU
+ * applications.
+ */
+
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/elf.h>
+#include "pr_util.h"
+
+
+void vma_map_free(struct vma_to_fileoffset_map *map)
+{
+ while (map) {
+ struct vma_to_fileoffset_map *next = map->next;
+ kfree(map);
+ map = next;
+ }
+}
+
+unsigned int
+vma_map_lookup(struct vma_to_fileoffset_map *map, unsigned int vma,
+ const struct spu *aSpu, int *grd_val)
+{
+ /*
+ * Default the offset to the physical address + a flag value.
+ * Addresses of dynamically generated code can't be found in the vma
+ * map. For those addresses the flagged value will be sent on to
+ * the user space tools so they can be reported rather than just
+ * thrown away.
+ */
+ u32 offset = 0x10000000 + vma;
+ u32 ovly_grd;
+
+ for (; map; map = map->next) {
+ if (vma < map->vma || vma >= map->vma + map->size)
+ continue;
+
+ if (map->guard_ptr) {
+ ovly_grd = *(u32 *)(aSpu->local_store + map->guard_ptr);
+ if (ovly_grd != map->guard_val)
+ continue;
+ *grd_val = ovly_grd;
+ }
+ offset = vma - map->vma + map->offset;
+ break;
+ }
+
+ return offset;
+}
+
+static struct vma_to_fileoffset_map *
+vma_map_add(struct vma_to_fileoffset_map *map, unsigned int vma,
+ unsigned int size, unsigned int offset, unsigned int guard_ptr,
+ unsigned int guard_val)
+{
+ struct vma_to_fileoffset_map *new =
+ kzalloc(sizeof(struct vma_to_fileoffset_map), GFP_KERNEL);
+ if (!new) {
+ printk(KERN_ERR "SPU_PROF: %s, line %d: malloc failed\n",
+ __FUNCTION__, __LINE__);
+ vma_map_free(map);
+ return NULL;
+ }
+
+ new->next = map;
+ new->vma = vma;
+ new->size = size;
+ new->offset = offset;
+ new->guard_ptr = guard_ptr;
+ new->guard_val = guard_val;
+
+ return new;
+}
+
+
+/* Parse SPE ELF header and generate a list of vma_maps.
+ * A pointer to the first vma_map in the generated list
+ * of vma_maps is returned. */
+struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
+ unsigned long spu_elf_start)
+{
+ static const unsigned char expected[EI_PAD] = {
+ [EI_MAG0] = ELFMAG0,
+ [EI_MAG1] = ELFMAG1,
+ [EI_MAG2] = ELFMAG2,
+ [EI_MAG3] = ELFMAG3,
+ [EI_CLASS] = ELFCLASS32,
+ [EI_DATA] = ELFDATA2MSB,
+ [EI_VERSION] = EV_CURRENT,
+ [EI_OSABI] = ELFOSABI_NONE
+ };
+
+ int grd_val;
+ struct vma_to_fileoffset_map *map = NULL;
+ struct spu_overlay_info ovly;
+ unsigned int overlay_tbl_offset = -1;
+ unsigned long phdr_start, shdr_start;
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+ Elf32_Shdr shdr, shdr_str;
+ Elf32_Sym sym;
+ int i, j;
+ char name[32];
+
+ unsigned int ovly_table_sym = 0;
+ unsigned int ovly_buf_table_sym = 0;
+ unsigned int ovly_table_end_sym = 0;
+ unsigned int ovly_buf_table_end_sym = 0;
+ unsigned long ovly_table;
+ unsigned int n_ovlys;
+
+ /* Get and validate ELF header. */
+
+ if (copy_from_user(&ehdr, (void *) spu_elf_start, sizeof (ehdr)))
+ goto fail;
+
+ if (memcmp(ehdr.e_ident, expected, EI_PAD) != 0) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Unexpected e_ident parsing SPU ELF\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ if (ehdr.e_machine != EM_SPU) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Unexpected e_machine parsing SPU ELF\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ if (ehdr.e_type != ET_EXEC) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Unexpected e_type parsing SPU ELF\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ phdr_start = spu_elf_start + ehdr.e_phoff;
+ shdr_start = spu_elf_start + ehdr.e_shoff;
+
+ /* Traverse program headers. */
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (copy_from_user(&phdr,
+ (void *) (phdr_start + i * sizeof(phdr)),
+ sizeof(phdr)))
+ goto fail;
+
+ if (phdr.p_type != PT_LOAD)
+ continue;
+ if (phdr.p_flags & (1 << 27))
+ continue;
+
+ map = vma_map_add(map, phdr.p_vaddr, phdr.p_memsz,
+ phdr.p_offset, 0, 0);
+ if (!map)
+ goto fail;
+ }
+
+ pr_debug("SPU_PROF: Created non-overlay maps\n");
+ /* Traverse section table and search for overlay-related symbols. */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ if (copy_from_user(&shdr,
+ (void *) (shdr_start + i * sizeof(shdr)),
+ sizeof(shdr)))
+ goto fail;
+
+ if (shdr.sh_type != SHT_SYMTAB)
+ continue;
+ if (shdr.sh_entsize != sizeof (sym))
+ continue;
+
+ if (copy_from_user(&shdr_str,
+ (void *) (shdr_start + shdr.sh_link *
+ sizeof(shdr)),
+ sizeof(shdr)))
+ goto fail;
+
+ if (shdr_str.sh_type != SHT_STRTAB)
+ goto fail;;
+
+ for (j = 0; j < shdr.sh_size / sizeof (sym); j++) {
+ if (copy_from_user(&sym, (void *) (spu_elf_start +
+ shdr.sh_offset + j *
+ sizeof (sym)),
+ sizeof (sym)))
+ goto fail;
+
+ if (copy_from_user(name, (void *)
+ (spu_elf_start + shdr_str.sh_offset +
+ sym.st_name),
+ 20))
+ goto fail;
+
+ if (memcmp(name, "_ovly_table", 12) == 0)
+ ovly_table_sym = sym.st_value;
+ if (memcmp(name, "_ovly_buf_table", 16) == 0)
+ ovly_buf_table_sym = sym.st_value;
+ if (memcmp(name, "_ovly_table_end", 16) == 0)
+ ovly_table_end_sym = sym.st_value;
+ if (memcmp(name, "_ovly_buf_table_end", 20) == 0)
+ ovly_buf_table_end_sym = sym.st_value;
+ }
+ }
+
+ /* If we don't have overlays, we're done. */
+ if (ovly_table_sym == 0 || ovly_buf_table_sym == 0
+ || ovly_table_end_sym == 0 || ovly_buf_table_end_sym == 0) {
+ pr_debug("SPU_PROF: No overlay table found\n");
+ goto out;
+ } else {
+ pr_debug("SPU_PROF: Overlay table found\n");
+ }
+
+ /* The _ovly_table symbol represents a table with one entry
+ * per overlay section. The _ovly_buf_table symbol represents
+ * a table with one entry per overlay region.
+ * The struct spu_overlay_info gives the structure of the _ovly_table
+ * entries. The structure of _ovly_table_buf is simply one
+ * u32 word per entry.
+ */
+ overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
+ aSpu, &grd_val);
+ if (overlay_tbl_offset < 0) {
+ printk(KERN_ERR "SPU_PROF: "
+ "%s, line %d: Error finding SPU overlay table\n",
+ __FUNCTION__, __LINE__);
+ goto fail;
+ }
+ ovly_table = spu_elf_start + overlay_tbl_offset;
+
+ n_ovlys = (ovly_table_end_sym -
+ ovly_table_sym) / sizeof (ovly);
+
+ /* Traverse overlay table. */
+ for (i = 0; i < n_ovlys; i++) {
+ if (copy_from_user(&ovly, (void *)
+ (ovly_table + i * sizeof (ovly)),
+ sizeof (ovly)))
+ goto fail;
+
+ /* The ovly.vma/size/offset arguments are analogous to the same
+ * arguments used above for non-overlay maps. The final two
+ * args are referred to as the guard pointer and the guard
+ * value.
+ * The guard pointer is an entry in the _ovly_buf_table,
+ * computed using ovly.buf as the index into the table. Since
+ * ovly.buf values begin at '1' to reference the first (or 0th)
+ * entry in the _ovly_buf_table, the computation subtracts 1
+ * from ovly.buf.
+ * The guard value is stored in the _ovly_buf_table entry and
+ * is an index (starting at 1) back to the _ovly_table entry
+ * that is pointing at this _ovly_buf_table entry. So, for
+ * example, for an overlay scenario with one overlay segment
+ * and two overlay sections:
+ * - Section 1 points to the first entry of the
+ * _ovly_buf_table, which contains a guard value
+ * of '1', referencing the first (index=0) entry of
+ * _ovly_table.
+ * - Section 2 points to the second entry of the
+ * _ovly_buf_table, which contains a guard value
+ * of '2', referencing the second (index=1) entry of
+ * _ovly_table.
+ */
+ map = vma_map_add(map, ovly.vma, ovly.size, ovly.offset,
+ ovly_buf_table_sym + (ovly.buf-1) * 4, i+1);
+ if (!map)
+ goto fail;
+ }
+ goto out;
+
+ fail:
+ map = NULL;
+ out:
+ return map;
+}
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index 1a7ef7e246d2..a28cce1d6c24 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -29,6 +29,8 @@ static struct op_powerpc_model *model;
static struct op_counter_config ctr[OP_MAX_COUNTER];
static struct op_system_config sys;
+static int op_per_cpu_rc;
+
static void op_handle_interrupt(struct pt_regs *regs)
{
model->handle_interrupt(regs, ctr);
@@ -36,25 +38,41 @@ static void op_handle_interrupt(struct pt_regs *regs)
static void op_powerpc_cpu_setup(void *dummy)
{
- model->cpu_setup(ctr);
+ int ret;
+
+ ret = model->cpu_setup(ctr);
+
+ if (ret != 0)
+ op_per_cpu_rc = ret;
}
static int op_powerpc_setup(void)
{
int err;
+ op_per_cpu_rc = 0;
+
/* Grab the hardware */
err = reserve_pmc_hardware(op_handle_interrupt);
if (err)
return err;
/* Pre-compute the values to stuff in the hardware registers. */
- model->reg_setup(ctr, &sys, model->num_counters);
+ op_per_cpu_rc = model->reg_setup(ctr, &sys, model->num_counters);
- /* Configure the registers on all cpus. */
+ if (op_per_cpu_rc)
+ goto out;
+
+ /* Configure the registers on all cpus. If an error occurs on one
+ * of the cpus, op_per_cpu_rc will be set to the error */
on_each_cpu(op_powerpc_cpu_setup, NULL, 0, 1);
- return 0;
+out: if (op_per_cpu_rc) {
+ /* error on setup release the performance counter hardware */
+ release_pmc_hardware();
+ }
+
+ return op_per_cpu_rc;
}
static void op_powerpc_shutdown(void)
@@ -64,16 +82,29 @@ static void op_powerpc_shutdown(void)
static void op_powerpc_cpu_start(void *dummy)
{
- model->start(ctr);
+ /* If any of the cpus have return an error, set the
+ * global flag to the error so it can be returned
+ * to the generic OProfile caller.
+ */
+ int ret;
+
+ ret = model->start(ctr);
+ if (ret != 0)
+ op_per_cpu_rc = ret;
}
static int op_powerpc_start(void)
{
+ op_per_cpu_rc = 0;
+
if (model->global_start)
- model->global_start(ctr);
- if (model->start)
+ return model->global_start(ctr);
+ if (model->start) {
on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
- return 0;
+ return op_per_cpu_rc;
+ }
+ return -EIO; /* No start function is defined for this
+ power architecture */
}
static inline void op_powerpc_cpu_stop(void *dummy)
@@ -147,11 +178,13 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
switch (cur_cpu_spec->oprofile_type) {
#ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_CELL_NATIVE
+#ifdef CONFIG_OPROFILE_CELL
case PPC_OPROFILE_CELL:
if (firmware_has_feature(FW_FEATURE_LPAR))
return -ENODEV;
model = &op_model_cell;
+ ops->sync_start = model->sync_start;
+ ops->sync_stop = model->sync_stop;
break;
#endif
case PPC_OPROFILE_RS64:
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index 5d1bbaf35ccb..cc599eb8768b 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -81,7 +81,7 @@ static void pmc_stop_ctrs(void)
/* Configures the counters on this CPU based on the global
* settings */
-static void fsl7450_cpu_setup(struct op_counter_config *ctr)
+static int fsl7450_cpu_setup(struct op_counter_config *ctr)
{
/* freeze all counters */
pmc_stop_ctrs();
@@ -89,12 +89,14 @@ static void fsl7450_cpu_setup(struct op_counter_config *ctr)
mtspr(SPRN_MMCR0, mmcr0_val);
mtspr(SPRN_MMCR1, mmcr1_val);
mtspr(SPRN_MMCR2, mmcr2_val);
+
+ return 0;
}
#define NUM_CTRS 6
/* Configures the global settings for the countes on all CPUs. */
-static void fsl7450_reg_setup(struct op_counter_config *ctr,
+static int fsl7450_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -126,10 +128,12 @@ static void fsl7450_reg_setup(struct op_counter_config *ctr,
| mmcr1_event6(ctr[5].event);
mmcr2_val = 0;
+
+ return 0;
}
/* Sets the counters on this CPU to the chosen values, and starts them */
-static void fsl7450_start(struct op_counter_config *ctr)
+static int fsl7450_start(struct op_counter_config *ctr)
{
int i;
@@ -148,6 +152,8 @@ static void fsl7450_start(struct op_counter_config *ctr)
pmc_start_ctrs();
oprofile_running = 1;
+
+ return 0;
}
/* Stop the counters on this CPU */
@@ -193,7 +199,7 @@ static void fsl7450_handle_interrupt(struct pt_regs *regs,
/* The freeze bit was set by the interrupt. */
/* Clear the freeze bit, and reenable the interrupt.
* The counters won't actually start until the rfi clears
- * the PMM bit */
+ * the PM/M bit */
pmc_start_ctrs();
}
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index c29293befba9..d928b54f3a0f 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -5,8 +5,8 @@
*
* Author: David Erb (djerb@us.ibm.com)
* Modifications:
- * Carl Love <carll@us.ibm.com>
- * Maynard Johnson <maynardj@us.ibm.com>
+ * Carl Love <carll@us.ibm.com>
+ * Maynard Johnson <maynardj@us.ibm.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -38,12 +38,25 @@
#include "../platforms/cell/interrupt.h"
#include "../platforms/cell/cbe_regs.h"
+#include "cell/pr_util.h"
+
+static void cell_global_stop_spu(void);
+
+/*
+ * spu_cycle_reset is the number of cycles between samples.
+ * This variable is used for SPU profiling and should ONLY be set
+ * at the beginning of cell_reg_setup; otherwise, it's read-only.
+ */
+static unsigned int spu_cycle_reset;
+
+#define NUM_SPUS_PER_NODE 8
+#define SPU_CYCLES_EVENT_NUM 2 /* event number for SPU_CYCLES */
#define PPU_CYCLES_EVENT_NUM 1 /* event number for CYCLES */
-#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying
- * PPU_CYCLES event
- */
-#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */
+#define PPU_CYCLES_GRP_NUM 1 /* special group number for identifying
+ * PPU_CYCLES event
+ */
+#define CBE_COUNT_ALL_CYCLES 0x42800000 /* PPU cycle event specifier */
#define NUM_THREADS 2 /* number of physical threads in
* physical processor
@@ -51,6 +64,7 @@
#define NUM_TRACE_BUS_WORDS 4
#define NUM_INPUT_BUS_WORDS 2
+#define MAX_SPU_COUNT 0xFFFFFF /* maximum 24 bit LFSR value */
struct pmc_cntrl_data {
unsigned long vcntr;
@@ -62,11 +76,10 @@ struct pmc_cntrl_data {
/*
* ibm,cbe-perftools rtas parameters
*/
-
struct pm_signal {
u16 cpu; /* Processor to modify */
- u16 sub_unit; /* hw subunit this applies to (if applicable) */
- short int signal_group; /* Signal Group to Enable/Disable */
+ u16 sub_unit; /* hw subunit this applies to (if applicable)*/
+ short int signal_group; /* Signal Group to Enable/Disable */
u8 bus_word; /* Enable/Disable on this Trace/Trigger/Event
* Bus Word(s) (bitmask)
*/
@@ -112,21 +125,42 @@ static DEFINE_PER_CPU(unsigned long[NR_PHYS_CTRS], pmc_values);
static struct pmc_cntrl_data pmc_cntrl[NUM_THREADS][NR_PHYS_CTRS];
-/* Interpetation of hdw_thread:
+/*
+ * The CELL profiling code makes rtas calls to setup the debug bus to
+ * route the performance signals. Additionally, SPU profiling requires
+ * a second rtas call to setup the hardware to capture the SPU PCs.
+ * The EIO error value is returned if the token lookups or the rtas
+ * call fail. The EIO error number is the best choice of the existing
+ * error numbers. The probability of rtas related error is very low. But
+ * by returning EIO and printing additional information to dmsg the user
+ * will know that OProfile did not start and dmesg will tell them why.
+ * OProfile does not support returning errors on Stop. Not a huge issue
+ * since failure to reset the debug bus or stop the SPU PC collection is
+ * not a fatel issue. Chances are if the Stop failed, Start doesn't work
+ * either.
+ */
+
+/*
+ * Interpetation of hdw_thread:
* 0 - even virtual cpus 0, 2, 4,...
* 1 - odd virtual cpus 1, 3, 5, ...
+ *
+ * FIXME: this is strictly wrong, we need to clean this up in a number
+ * of places. It works for now. -arnd
*/
static u32 hdw_thread;
static u32 virt_cntr_inter_mask;
static struct timer_list timer_virt_cntr;
-/* pm_signal needs to be global since it is initialized in
+/*
+ * pm_signal needs to be global since it is initialized in
* cell_reg_setup at the time when the necessary information
* is available.
*/
static struct pm_signal pm_signal[NR_PHYS_CTRS];
-static int pm_rtas_token;
+static int pm_rtas_token; /* token for debug bus setup call */
+static int spu_rtas_token; /* token for SPU cycle profiling */
static u32 reset_value[NR_PHYS_CTRS];
static int num_counters;
@@ -147,8 +181,8 @@ rtas_ibm_cbe_perftools(int subfunc, int passthru,
{
u64 paddr = __pa(address);
- return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc, passthru,
- paddr >> 32, paddr & 0xffffffff, length);
+ return rtas_call(pm_rtas_token, 5, 1, NULL, subfunc,
+ passthru, paddr >> 32, paddr & 0xffffffff, length);
}
static void pm_rtas_reset_signals(u32 node)
@@ -156,12 +190,13 @@ static void pm_rtas_reset_signals(u32 node)
int ret;
struct pm_signal pm_signal_local;
- /* The debug bus is being set to the passthru disable state.
- * However, the FW still expects atleast one legal signal routing
- * entry or it will return an error on the arguments. If we don't
- * supply a valid entry, we must ignore all return values. Ignoring
- * all return values means we might miss an error we should be
- * concerned about.
+ /*
+ * The debug bus is being set to the passthru disable state.
+ * However, the FW still expects atleast one legal signal routing
+ * entry or it will return an error on the arguments. If we don't
+ * supply a valid entry, we must ignore all return values. Ignoring
+ * all return values means we might miss an error we should be
+ * concerned about.
*/
/* fw expects physical cpu #. */
@@ -175,18 +210,24 @@ static void pm_rtas_reset_signals(u32 node)
&pm_signal_local,
sizeof(struct pm_signal));
- if (ret)
+ if (unlikely(ret))
+ /*
+ * Not a fatal error. For Oprofile stop, the oprofile
+ * functions do not support returning an error for
+ * failure to stop OProfile.
+ */
printk(KERN_WARNING "%s: rtas returned: %d\n",
__FUNCTION__, ret);
}
-static void pm_rtas_activate_signals(u32 node, u32 count)
+static int pm_rtas_activate_signals(u32 node, u32 count)
{
int ret;
int i, j;
struct pm_signal pm_signal_local[NR_PHYS_CTRS];
- /* There is no debug setup required for the cycles event.
+ /*
+ * There is no debug setup required for the cycles event.
* Note that only events in the same group can be used.
* Otherwise, there will be conflicts in correctly routing
* the signals on the debug bus. It is the responsiblity
@@ -213,10 +254,14 @@ static void pm_rtas_activate_signals(u32 node, u32 count)
pm_signal_local,
i * sizeof(struct pm_signal));
- if (ret)
+ if (unlikely(ret)) {
printk(KERN_WARNING "%s: rtas returned: %d\n",
__FUNCTION__, ret);
+ return -EIO;
+ }
}
+
+ return 0;
}
/*
@@ -260,11 +305,12 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)
pm_regs.pm07_cntrl[ctr] |= PM07_CTR_POLARITY(polarity);
pm_regs.pm07_cntrl[ctr] |= PM07_CTR_INPUT_CONTROL(input_control);
- /* Some of the islands signal selection is based on 64 bit words.
+ /*
+ * Some of the islands signal selection is based on 64 bit words.
* The debug bus words are 32 bits, the input words to the performance
* counters are defined as 32 bits. Need to convert the 64 bit island
* specification to the appropriate 32 input bit and bus word for the
- * performance counter event selection. See the CELL Performance
+ * performance counter event selection. See the CELL Performance
* monitoring signals manual and the Perf cntr hardware descriptions
* for the details.
*/
@@ -298,6 +344,7 @@ static void set_pm_event(u32 ctr, int event, u32 unit_mask)
input_bus[j] = i;
pm_regs.group_control |=
(i << (31 - i));
+
break;
}
}
@@ -309,7 +356,8 @@ out:
static void write_pm_cntrl(int cpu)
{
- /* Oprofile will use 32 bit counters, set bits 7:10 to 0
+ /*
+ * Oprofile will use 32 bit counters, set bits 7:10 to 0
* pmregs.pm_cntrl is a global
*/
@@ -326,7 +374,8 @@ static void write_pm_cntrl(int cpu)
if (pm_regs.pm_cntrl.freeze == 1)
val |= CBE_PM_FREEZE_ALL_CTRS;
- /* Routine set_count_mode must be called previously to set
+ /*
+ * Routine set_count_mode must be called previously to set
* the count mode based on the user selection of user and kernel.
*/
val |= CBE_PM_COUNT_MODE_SET(pm_regs.pm_cntrl.count_mode);
@@ -336,7 +385,8 @@ static void write_pm_cntrl(int cpu)
static inline void
set_count_mode(u32 kernel, u32 user)
{
- /* The user must specify user and kernel if they want them. If
+ /*
+ * The user must specify user and kernel if they want them. If
* neither is specified, OProfile will count in hypervisor mode.
* pm_regs.pm_cntrl is a global
*/
@@ -364,7 +414,7 @@ static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl)
/*
* Oprofile is expected to collect data on all CPUs simultaneously.
- * However, there is one set of performance counters per node. There are
+ * However, there is one set of performance counters per node. There are
* two hardware threads or virtual CPUs on each node. Hence, OProfile must
* multiplex in time the performance counter collection on the two virtual
* CPUs. The multiplexing of the performance counters is done by this
@@ -377,19 +427,19 @@ static inline void enable_ctr(u32 cpu, u32 ctr, u32 * pm07_cntrl)
* pair of per-cpu arrays is used for storing the previous and next
* pmc values for a given node.
* NOTE: We use the per-cpu variable to improve cache performance.
+ *
+ * This routine will alternate loading the virtual counters for
+ * virtual CPUs
*/
static void cell_virtual_cntr(unsigned long data)
{
- /* This routine will alternate loading the virtual counters for
- * virtual CPUs
- */
int i, prev_hdw_thread, next_hdw_thread;
u32 cpu;
unsigned long flags;
- /* Make sure that the interrupt_hander and
- * the virt counter are not both playing with
- * the counters on the same node.
+ /*
+ * Make sure that the interrupt_hander and the virt counter are
+ * not both playing with the counters on the same node.
*/
spin_lock_irqsave(&virt_cntr_lock, flags);
@@ -400,22 +450,25 @@ static void cell_virtual_cntr(unsigned long data)
hdw_thread = 1 ^ hdw_thread;
next_hdw_thread = hdw_thread;
- for (i = 0; i < num_counters; i++)
- /* There are some per thread events. Must do the
+ /*
+ * There are some per thread events. Must do the
* set event, for the thread that is being started
*/
+ for (i = 0; i < num_counters; i++)
set_pm_event(i,
pmc_cntrl[next_hdw_thread][i].evnts,
pmc_cntrl[next_hdw_thread][i].masks);
- /* The following is done only once per each node, but
+ /*
+ * The following is done only once per each node, but
* we need cpu #, not node #, to pass to the cbe_xxx functions.
*/
for_each_online_cpu(cpu) {
if (cbe_get_hw_thread_id(cpu))
continue;
- /* stop counters, save counter values, restore counts
+ /*
+ * stop counters, save counter values, restore counts
* for previous thread
*/
cbe_disable_pm(cpu);
@@ -428,7 +481,7 @@ static void cell_virtual_cntr(unsigned long data)
== 0xFFFFFFFF)
/* If the cntr value is 0xffffffff, we must
* reset that to 0xfffffff0 when the current
- * thread is restarted. This will generate a
+ * thread is restarted. This will generate a
* new interrupt and make sure that we never
* restore the counters to the max value. If
* the counters were restored to the max value,
@@ -444,13 +497,15 @@ static void cell_virtual_cntr(unsigned long data)
next_hdw_thread)[i]);
}
- /* Switch to the other thread. Change the interrupt
+ /*
+ * Switch to the other thread. Change the interrupt
* and control regs to be scheduled on the CPU
* corresponding to the thread to execute.
*/
for (i = 0; i < num_counters; i++) {
if (pmc_cntrl[next_hdw_thread][i].enabled) {
- /* There are some per thread events.
+ /*
+ * There are some per thread events.
* Must do the set event, enable_cntr
* for each cpu.
*/
@@ -482,17 +537,42 @@ static void start_virt_cntrs(void)
}
/* This function is called once for all cpus combined */
-static void
-cell_reg_setup(struct op_counter_config *ctr,
- struct op_system_config *sys, int num_ctrs)
+static int cell_reg_setup(struct op_counter_config *ctr,
+ struct op_system_config *sys, int num_ctrs)
{
int i, j, cpu;
+ spu_cycle_reset = 0;
+
+ if (ctr[0].event == SPU_CYCLES_EVENT_NUM) {
+ spu_cycle_reset = ctr[0].count;
+
+ /*
+ * Each node will need to make the rtas call to start
+ * and stop SPU profiling. Get the token once and store it.
+ */
+ spu_rtas_token = rtas_token("ibm,cbe-spu-perftools");
+
+ if (unlikely(spu_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+ printk(KERN_ERR
+ "%s: rtas token ibm,cbe-spu-perftools unknown\n",
+ __FUNCTION__);
+ return -EIO;
+ }
+ }
pm_rtas_token = rtas_token("ibm,cbe-perftools");
- if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
+
+ /*
+ * For all events excetp PPU CYCLEs, each node will need to make
+ * the rtas cbe-perftools call to setup and reset the debug bus.
+ * Make the token lookup call once and store it in the global
+ * variable pm_rtas_token.
+ */
+ if (unlikely(pm_rtas_token == RTAS_UNKNOWN_SERVICE)) {
+ printk(KERN_ERR
+ "%s: rtas token ibm,cbe-perftools unknown\n",
__FUNCTION__);
- goto out;
+ return -EIO;
}
num_counters = num_ctrs;
@@ -520,7 +600,8 @@ cell_reg_setup(struct op_counter_config *ctr,
per_cpu(pmc_values, j)[i] = 0;
}
- /* Setup the thread 1 events, map the thread 0 event to the
+ /*
+ * Setup the thread 1 events, map the thread 0 event to the
* equivalent thread 1 event.
*/
for (i = 0; i < num_ctrs; ++i) {
@@ -544,9 +625,10 @@ cell_reg_setup(struct op_counter_config *ctr,
for (i = 0; i < NUM_INPUT_BUS_WORDS; i++)
input_bus[i] = 0xff;
- /* Our counters count up, and "count" refers to
+ /*
+ * Our counters count up, and "count" refers to
* how much before the next interrupt, and we interrupt
- * on overflow. So we calculate the starting value
+ * on overflow. So we calculate the starting value
* which will give us "count" until overflow.
* Then we set the events on the enabled counters.
*/
@@ -569,28 +651,27 @@ cell_reg_setup(struct op_counter_config *ctr,
for (i = 0; i < num_counters; ++i) {
per_cpu(pmc_values, cpu)[i] = reset_value[i];
}
-out:
- ;
+
+ return 0;
}
+
+
/* This function is called once for each cpu */
-static void cell_cpu_setup(struct op_counter_config *cntr)
+static int cell_cpu_setup(struct op_counter_config *cntr)
{
u32 cpu = smp_processor_id();
u32 num_enabled = 0;
int i;
+ if (spu_cycle_reset)
+ return 0;
+
/* There is one performance monitor per processor chip (i.e. node),
* so we only need to perform this function once per node.
*/
if (cbe_get_hw_thread_id(cpu))
- goto out;
-
- if (pm_rtas_token == RTAS_UNKNOWN_SERVICE) {
- printk(KERN_WARNING "%s: RTAS_UNKNOWN_SERVICE\n",
- __FUNCTION__);
- goto out;
- }
+ return 0;
/* Stop all counters */
cbe_disable_pm(cpu);
@@ -609,16 +690,286 @@ static void cell_cpu_setup(struct op_counter_config *cntr)
}
}
- pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+ /*
+ * The pm_rtas_activate_signals will return -EIO if the FW
+ * call failed.
+ */
+ return pm_rtas_activate_signals(cbe_cpu_to_node(cpu), num_enabled);
+}
+
+#define ENTRIES 303
+#define MAXLFSR 0xFFFFFF
+
+/* precomputed table of 24 bit LFSR values */
+static int initial_lfsr[] = {
+ 8221349, 12579195, 5379618, 10097839, 7512963, 7519310, 3955098, 10753424,
+ 15507573, 7458917, 285419, 2641121, 9780088, 3915503, 6668768, 1548716,
+ 4885000, 8774424, 9650099, 2044357, 2304411, 9326253, 10332526, 4421547,
+ 3440748, 10179459, 13332843, 10375561, 1313462, 8375100, 5198480, 6071392,
+ 9341783, 1526887, 3985002, 1439429, 13923762, 7010104, 11969769, 4547026,
+ 2040072, 4025602, 3437678, 7939992, 11444177, 4496094, 9803157, 10745556,
+ 3671780, 4257846, 5662259, 13196905, 3237343, 12077182, 16222879, 7587769,
+ 14706824, 2184640, 12591135, 10420257, 7406075, 3648978, 11042541, 15906893,
+ 11914928, 4732944, 10695697, 12928164, 11980531, 4430912, 11939291, 2917017,
+ 6119256, 4172004, 9373765, 8410071, 14788383, 5047459, 5474428, 1737756,
+ 15967514, 13351758, 6691285, 8034329, 2856544, 14394753, 11310160, 12149558,
+ 7487528, 7542781, 15668898, 12525138, 12790975, 3707933, 9106617, 1965401,
+ 16219109, 12801644, 2443203, 4909502, 8762329, 3120803, 6360315, 9309720,
+ 15164599, 10844842, 4456529, 6667610, 14924259, 884312, 6234963, 3326042,
+ 15973422, 13919464, 5272099, 6414643, 3909029, 2764324, 5237926, 4774955,
+ 10445906, 4955302, 5203726, 10798229, 11443419, 2303395, 333836, 9646934,
+ 3464726, 4159182, 568492, 995747, 10318756, 13299332, 4836017, 8237783,
+ 3878992, 2581665, 11394667, 5672745, 14412947, 3159169, 9094251, 16467278,
+ 8671392, 15230076, 4843545, 7009238, 15504095, 1494895, 9627886, 14485051,
+ 8304291, 252817, 12421642, 16085736, 4774072, 2456177, 4160695, 15409741,
+ 4902868, 5793091, 13162925, 16039714, 782255, 11347835, 14884586, 366972,
+ 16308990, 11913488, 13390465, 2958444, 10340278, 1177858, 1319431, 10426302,
+ 2868597, 126119, 5784857, 5245324, 10903900, 16436004, 3389013, 1742384,
+ 14674502, 10279218, 8536112, 10364279, 6877778, 14051163, 1025130, 6072469,
+ 1988305, 8354440, 8216060, 16342977, 13112639, 3976679, 5913576, 8816697,
+ 6879995, 14043764, 3339515, 9364420, 15808858, 12261651, 2141560, 5636398,
+ 10345425, 10414756, 781725, 6155650, 4746914, 5078683, 7469001, 6799140,
+ 10156444, 9667150, 10116470, 4133858, 2121972, 1124204, 1003577, 1611214,
+ 14304602, 16221850, 13878465, 13577744, 3629235, 8772583, 10881308, 2410386,
+ 7300044, 5378855, 9301235, 12755149, 4977682, 8083074, 10327581, 6395087,
+ 9155434, 15501696, 7514362, 14520507, 15808945, 3244584, 4741962, 9658130,
+ 14336147, 8654727, 7969093, 15759799, 14029445, 5038459, 9894848, 8659300,
+ 13699287, 8834306, 10712885, 14753895, 10410465, 3373251, 309501, 9561475,
+ 5526688, 14647426, 14209836, 5339224, 207299, 14069911, 8722990, 2290950,
+ 3258216, 12505185, 6007317, 9218111, 14661019, 10537428, 11731949, 9027003,
+ 6641507, 9490160, 200241, 9720425, 16277895, 10816638, 1554761, 10431375,
+ 7467528, 6790302, 3429078, 14633753, 14428997, 11463204, 3576212, 2003426,
+ 6123687, 820520, 9992513, 15784513, 5778891, 6428165, 8388607
+};
+
+/*
+ * The hardware uses an LFSR counting sequence to determine when to capture
+ * the SPU PCs. An LFSR sequence is like a puesdo random number sequence
+ * where each number occurs once in the sequence but the sequence is not in
+ * numerical order. The SPU PC capture is done when the LFSR sequence reaches
+ * the last value in the sequence. Hence the user specified value N
+ * corresponds to the LFSR number that is N from the end of the sequence.
+ *
+ * To avoid the time to compute the LFSR, a lookup table is used. The 24 bit
+ * LFSR sequence is broken into four ranges. The spacing of the precomputed
+ * values is adjusted in each range so the error between the user specifed
+ * number (N) of events between samples and the actual number of events based
+ * on the precomputed value will be les then about 6.2%. Note, if the user
+ * specifies N < 2^16, the LFSR value that is 2^16 from the end will be used.
+ * This is to prevent the loss of samples because the trace buffer is full.
+ *
+ * User specified N Step between Index in
+ * precomputed values precomputed
+ * table
+ * 0 to 2^16-1 ---- 0
+ * 2^16 to 2^16+2^19-1 2^12 1 to 128
+ * 2^16+2^19 to 2^16+2^19+2^22-1 2^15 129 to 256
+ * 2^16+2^19+2^22 to 2^24-1 2^18 257 to 302
+ *
+ *
+ * For example, the LFSR values in the second range are computed for 2^16,
+ * 2^16+2^12, ... , 2^19-2^16, 2^19 and stored in the table at indicies
+ * 1, 2,..., 127, 128.
+ *
+ * The 24 bit LFSR value for the nth number in the sequence can be
+ * calculated using the following code:
+ *
+ * #define size 24
+ * int calculate_lfsr(int n)
+ * {
+ * int i;
+ * unsigned int newlfsr0;
+ * unsigned int lfsr = 0xFFFFFF;
+ * unsigned int howmany = n;
+ *
+ * for (i = 2; i < howmany + 2; i++) {
+ * newlfsr0 = (((lfsr >> (size - 1 - 0)) & 1) ^
+ * ((lfsr >> (size - 1 - 1)) & 1) ^
+ * (((lfsr >> (size - 1 - 6)) & 1) ^
+ * ((lfsr >> (size - 1 - 23)) & 1)));
+ *
+ * lfsr >>= 1;
+ * lfsr = lfsr | (newlfsr0 << (size - 1));
+ * }
+ * return lfsr;
+ * }
+ */
+
+#define V2_16 (0x1 << 16)
+#define V2_19 (0x1 << 19)
+#define V2_22 (0x1 << 22)
+
+static int calculate_lfsr(int n)
+{
+ /*
+ * The ranges and steps are in powers of 2 so the calculations
+ * can be done using shifts rather then divide.
+ */
+ int index;
+
+ if ((n >> 16) == 0)
+ index = 0;
+ else if (((n - V2_16) >> 19) == 0)
+ index = ((n - V2_16) >> 12) + 1;
+ else if (((n - V2_16 - V2_19) >> 22) == 0)
+ index = ((n - V2_16 - V2_19) >> 15 ) + 1 + 128;
+ else if (((n - V2_16 - V2_19 - V2_22) >> 24) == 0)
+ index = ((n - V2_16 - V2_19 - V2_22) >> 18 ) + 1 + 256;
+ else
+ index = ENTRIES-1;
+
+ /* make sure index is valid */
+ if ((index > ENTRIES) || (index < 0))
+ index = ENTRIES-1;
+
+ return initial_lfsr[index];
+}
+
+static int pm_rtas_activate_spu_profiling(u32 node)
+{
+ int ret, i;
+ struct pm_signal pm_signal_local[NR_PHYS_CTRS];
+
+ /*
+ * Set up the rtas call to configure the debug bus to
+ * route the SPU PCs. Setup the pm_signal for each SPU
+ */
+ for (i = 0; i < NUM_SPUS_PER_NODE; i++) {
+ pm_signal_local[i].cpu = node;
+ pm_signal_local[i].signal_group = 41;
+ /* spu i on word (i/2) */
+ pm_signal_local[i].bus_word = 1 << i / 2;
+ /* spu i */
+ pm_signal_local[i].sub_unit = i;
+ pm_signal_local[i].bit = 63;
+ }
+
+ ret = rtas_ibm_cbe_perftools(SUBFUNC_ACTIVATE,
+ PASSTHRU_ENABLE, pm_signal_local,
+ (NUM_SPUS_PER_NODE
+ * sizeof(struct pm_signal)));
+
+ if (unlikely(ret)) {
+ printk(KERN_WARNING "%s: rtas returned: %d\n",
+ __FUNCTION__, ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_CPU_FREQ
+static int
+oprof_cpufreq_notify(struct notifier_block *nb, unsigned long val, void *data)
+{
+ int ret = 0;
+ struct cpufreq_freqs *frq = data;
+ if ((val == CPUFREQ_PRECHANGE && frq->old < frq->new) ||
+ (val == CPUFREQ_POSTCHANGE && frq->old > frq->new) ||
+ (val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE))
+ set_spu_profiling_frequency(frq->new, spu_cycle_reset);
+ return ret;
+}
+
+static struct notifier_block cpu_freq_notifier_block = {
+ .notifier_call = oprof_cpufreq_notify
+};
+#endif
+
+static int cell_global_start_spu(struct op_counter_config *ctr)
+{
+ int subfunc;
+ unsigned int lfsr_value;
+ int cpu;
+ int ret;
+ int rtas_error;
+ unsigned int cpu_khzfreq = 0;
+
+ /* The SPU profiling uses time-based profiling based on
+ * cpu frequency, so if configured with the CPU_FREQ
+ * option, we should detect frequency changes and react
+ * accordingly.
+ */
+#ifdef CONFIG_CPU_FREQ
+ ret = cpufreq_register_notifier(&cpu_freq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ if (ret < 0)
+ /* this is not a fatal error */
+ printk(KERN_ERR "CPU freq change registration failed: %d\n",
+ ret);
+
+ else
+ cpu_khzfreq = cpufreq_quick_get(smp_processor_id());
+#endif
+
+ set_spu_profiling_frequency(cpu_khzfreq, spu_cycle_reset);
+
+ for_each_online_cpu(cpu) {
+ if (cbe_get_hw_thread_id(cpu))
+ continue;
+
+ /*
+ * Setup SPU cycle-based profiling.
+ * Set perf_mon_control bit 0 to a zero before
+ * enabling spu collection hardware.
+ */
+ cbe_write_pm(cpu, pm_control, 0);
+
+ if (spu_cycle_reset > MAX_SPU_COUNT)
+ /* use largest possible value */
+ lfsr_value = calculate_lfsr(MAX_SPU_COUNT-1);
+ else
+ lfsr_value = calculate_lfsr(spu_cycle_reset);
+
+ /* must use a non zero value. Zero disables data collection. */
+ if (lfsr_value == 0)
+ lfsr_value = calculate_lfsr(1);
+
+ lfsr_value = lfsr_value << 8; /* shift lfsr to correct
+ * register location
+ */
+
+ /* debug bus setup */
+ ret = pm_rtas_activate_spu_profiling(cbe_cpu_to_node(cpu));
+
+ if (unlikely(ret)) {
+ rtas_error = ret;
+ goto out;
+ }
+
+
+ subfunc = 2; /* 2 - activate SPU tracing, 3 - deactivate */
+
+ /* start profiling */
+ ret = rtas_call(spu_rtas_token, 3, 1, NULL, subfunc,
+ cbe_cpu_to_node(cpu), lfsr_value);
+
+ if (unlikely(ret != 0)) {
+ printk(KERN_ERR
+ "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+ __FUNCTION__, ret);
+ rtas_error = -EIO;
+ goto out;
+ }
+ }
+
+ rtas_error = start_spu_profiling(spu_cycle_reset);
+ if (rtas_error)
+ goto out_stop;
+
+ oprofile_running = 1;
+ return 0;
+
+out_stop:
+ cell_global_stop_spu(); /* clean up the PMU/debug bus */
out:
- ;
+ return rtas_error;
}
-static void cell_global_start(struct op_counter_config *ctr)
+static int cell_global_start_ppu(struct op_counter_config *ctr)
{
- u32 cpu;
+ u32 cpu, i;
u32 interrupt_mask = 0;
- u32 i;
/* This routine gets called once for the system.
* There is one performance monitor per node, so we
@@ -651,19 +1002,79 @@ static void cell_global_start(struct op_counter_config *ctr)
oprofile_running = 1;
smp_wmb();
- /* NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
- * executed which manipulates the PMU. We start the "virtual counter"
+ /*
+ * NOTE: start_virt_cntrs will result in cell_virtual_cntr() being
+ * executed which manipulates the PMU. We start the "virtual counter"
* here so that we do not need to synchronize access to the PMU in
* the above for-loop.
*/
start_virt_cntrs();
+
+ return 0;
}
-static void cell_global_stop(void)
+static int cell_global_start(struct op_counter_config *ctr)
+{
+ if (spu_cycle_reset)
+ return cell_global_start_spu(ctr);
+ else
+ return cell_global_start_ppu(ctr);
+}
+
+/*
+ * Note the generic OProfile stop calls do not support returning
+ * an error on stop. Hence, will not return an error if the FW
+ * calls fail on stop. Failure to reset the debug bus is not an issue.
+ * Failure to disable the SPU profiling is not an issue. The FW calls
+ * to enable the performance counters and debug bus will work even if
+ * the hardware was not cleanly reset.
+ */
+static void cell_global_stop_spu(void)
+{
+ int subfunc, rtn_value;
+ unsigned int lfsr_value;
+ int cpu;
+
+ oprofile_running = 0;
+
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_unregister_notifier(&cpu_freq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+#endif
+
+ for_each_online_cpu(cpu) {
+ if (cbe_get_hw_thread_id(cpu))
+ continue;
+
+ subfunc = 3; /*
+ * 2 - activate SPU tracing,
+ * 3 - deactivate
+ */
+ lfsr_value = 0x8f100000;
+
+ rtn_value = rtas_call(spu_rtas_token, 3, 1, NULL,
+ subfunc, cbe_cpu_to_node(cpu),
+ lfsr_value);
+
+ if (unlikely(rtn_value != 0)) {
+ printk(KERN_ERR
+ "%s: rtas call ibm,cbe-spu-perftools failed, return = %d\n",
+ __FUNCTION__, rtn_value);
+ }
+
+ /* Deactivate the signals */
+ pm_rtas_reset_signals(cbe_cpu_to_node(cpu));
+ }
+
+ stop_spu_profiling();
+}
+
+static void cell_global_stop_ppu(void)
{
int cpu;
- /* This routine will be called once for the system.
+ /*
+ * This routine will be called once for the system.
* There is one performance monitor per node, so we
* only need to perform this function once per node.
*/
@@ -687,8 +1098,16 @@ static void cell_global_stop(void)
}
}
-static void
-cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
+static void cell_global_stop(void)
+{
+ if (spu_cycle_reset)
+ cell_global_stop_spu();
+ else
+ cell_global_stop_ppu();
+}
+
+static void cell_handle_interrupt(struct pt_regs *regs,
+ struct op_counter_config *ctr)
{
u32 cpu;
u64 pc;
@@ -699,13 +1118,15 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
cpu = smp_processor_id();
- /* Need to make sure the interrupt handler and the virt counter
+ /*
+ * Need to make sure the interrupt handler and the virt counter
* routine are not running at the same time. See the
* cell_virtual_cntr() routine for additional comments.
*/
spin_lock_irqsave(&virt_cntr_lock, flags);
- /* Need to disable and reenable the performance counters
+ /*
+ * Need to disable and reenable the performance counters
* to get the desired behavior from the hardware. This
* is hardware specific.
*/
@@ -714,7 +1135,8 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
interrupt_mask = cbe_get_and_clear_pm_interrupts(cpu);
- /* If the interrupt mask has been cleared, then the virt cntr
+ /*
+ * If the interrupt mask has been cleared, then the virt cntr
* has cleared the interrupt. When the thread that generated
* the interrupt is restored, the data count will be restored to
* 0xffffff0 to cause the interrupt to be regenerated.
@@ -732,18 +1154,20 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
}
}
- /* The counters were frozen by the interrupt.
+ /*
+ * The counters were frozen by the interrupt.
* Reenable the interrupt and restart the counters.
* If there was a race between the interrupt handler and
- * the virtual counter routine. The virutal counter
+ * the virtual counter routine. The virutal counter
* routine may have cleared the interrupts. Hence must
* use the virt_cntr_inter_mask to re-enable the interrupts.
*/
cbe_enable_pm_interrupts(cpu, hdw_thread,
virt_cntr_inter_mask);
- /* The writes to the various performance counters only writes
- * to a latch. The new values (interrupt setting bits, reset
+ /*
+ * The writes to the various performance counters only writes
+ * to a latch. The new values (interrupt setting bits, reset
* counter value etc.) are not copied to the actual registers
* until the performance monitor is enabled. In order to get
* this to work as desired, the permormance monitor needs to
@@ -755,10 +1179,33 @@ cell_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr)
spin_unlock_irqrestore(&virt_cntr_lock, flags);
}
+/*
+ * This function is called from the generic OProfile
+ * driver. When profiling PPUs, we need to do the
+ * generic sync start; otherwise, do spu_sync_start.
+ */
+static int cell_sync_start(void)
+{
+ if (spu_cycle_reset)
+ return spu_sync_start();
+ else
+ return DO_GENERIC_SYNC;
+}
+
+static int cell_sync_stop(void)
+{
+ if (spu_cycle_reset)
+ return spu_sync_stop();
+ else
+ return 1;
+}
+
struct op_powerpc_model op_model_cell = {
.reg_setup = cell_reg_setup,
.cpu_setup = cell_cpu_setup,
.global_start = cell_global_start,
.global_stop = cell_global_stop,
+ .sync_start = cell_sync_start,
+ .sync_stop = cell_sync_stop,
.handle_interrupt = cell_handle_interrupt,
};
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 2267eb8c661b..183a28bb1812 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -244,7 +244,7 @@ static void dump_pmcs(void)
mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
}
-static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
+static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
{
int i;
@@ -258,9 +258,11 @@ static void fsl_booke_cpu_setup(struct op_counter_config *ctr)
set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
}
+
+ return 0;
}
-static void fsl_booke_reg_setup(struct op_counter_config *ctr,
+static int fsl_booke_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -276,9 +278,10 @@ static void fsl_booke_reg_setup(struct op_counter_config *ctr,
for (i = 0; i < num_counters; ++i)
reset_value[i] = 0x80000000UL - ctr[i].count;
+ return 0;
}
-static void fsl_booke_start(struct op_counter_config *ctr)
+static int fsl_booke_start(struct op_counter_config *ctr)
{
int i;
@@ -308,6 +311,8 @@ static void fsl_booke_start(struct op_counter_config *ctr)
pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
mfpmr(PMRN_PMGC0));
+
+ return 0;
}
static void fsl_booke_stop(void)
diff --git a/arch/powerpc/oprofile/op_model_pa6t.c b/arch/powerpc/oprofile/op_model_pa6t.c
index e8a56b0adadc..c40de461fd4e 100644
--- a/arch/powerpc/oprofile/op_model_pa6t.c
+++ b/arch/powerpc/oprofile/op_model_pa6t.c
@@ -89,7 +89,7 @@ static inline void ctr_write(unsigned int i, u64 val)
/* precompute the values to stuff in the hardware registers */
-static void pa6t_reg_setup(struct op_counter_config *ctr,
+static int pa6t_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -135,10 +135,12 @@ static void pa6t_reg_setup(struct op_counter_config *ctr,
pr_debug("reset_value for pmc%u inited to 0x%lx\n",
pmc, reset_value[pmc]);
}
+
+ return 0;
}
/* configure registers on this cpu */
-static void pa6t_cpu_setup(struct op_counter_config *ctr)
+static int pa6t_cpu_setup(struct op_counter_config *ctr)
{
u64 mmcr0 = mmcr0_val;
u64 mmcr1 = mmcr1_val;
@@ -154,9 +156,11 @@ static void pa6t_cpu_setup(struct op_counter_config *ctr)
mfspr(SPRN_PA6T_MMCR0));
pr_debug("setup on cpu %d, mmcr1 %016lx\n", smp_processor_id(),
mfspr(SPRN_PA6T_MMCR1));
+
+ return 0;
}
-static void pa6t_start(struct op_counter_config *ctr)
+static int pa6t_start(struct op_counter_config *ctr)
{
int i;
@@ -174,6 +178,8 @@ static void pa6t_start(struct op_counter_config *ctr)
oprofile_running = 1;
pr_debug("start on cpu %d, mmcr0 %lx\n", smp_processor_id(), mmcr0);
+
+ return 0;
}
static void pa6t_stop(void)
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index fe597a154d4f..cddc250a6a5c 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Added mmcra[slot] support:
+ * Copyright (C) 2006-2007 Will Schmidt <willschm@us.ibm.com>, IBM
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,7 +32,7 @@ static u32 mmcr0_val;
static u64 mmcr1_val;
static u64 mmcra_val;
-static void power4_reg_setup(struct op_counter_config *ctr,
+static int power4_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -58,6 +60,8 @@ static void power4_reg_setup(struct op_counter_config *ctr,
mmcr0_val &= ~MMCR0_PROBLEM_DISABLE;
else
mmcr0_val |= MMCR0_PROBLEM_DISABLE;
+
+ return 0;
}
extern void ppc64_enable_pmcs(void);
@@ -82,7 +86,7 @@ static inline int mmcra_must_set_sample(void)
return 0;
}
-static void power4_cpu_setup(struct op_counter_config *ctr)
+static int power4_cpu_setup(struct op_counter_config *ctr)
{
unsigned int mmcr0 = mmcr0_val;
unsigned long mmcra = mmcra_val;
@@ -109,9 +113,11 @@ static void power4_cpu_setup(struct op_counter_config *ctr)
mfspr(SPRN_MMCR1));
dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
mfspr(SPRN_MMCRA));
+
+ return 0;
}
-static void power4_start(struct op_counter_config *ctr)
+static int power4_start(struct op_counter_config *ctr)
{
int i;
unsigned int mmcr0;
@@ -146,6 +152,7 @@ static void power4_start(struct op_counter_config *ctr)
oprofile_running = 1;
dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+ return 0;
}
static void power4_stop(void)
@@ -181,11 +188,17 @@ static void __attribute_used__ kernel_unknown_bucket(void)
* On GQ and newer the MMCRA stores the HV and PR bits at the time
* the SIAR was sampled. We use that to work out if the SIAR was sampled in
* the hypervisor, our exception vectors or RTAS.
+ * If the MMCRA_SAMPLE_ENABLE bit is set, we can use the MMCRA[slot] bits
+ * to more accurately identify the address of the sampled instruction. The
+ * mmcra[slot] bits represent the slot number of a sampled instruction
+ * within an instruction group. The slot will contain a value between 1
+ * and 5 if MMCRA_SAMPLE_ENABLE is set, otherwise 0.
*/
static unsigned long get_pc(struct pt_regs *regs)
{
unsigned long pc = mfspr(SPRN_SIAR);
unsigned long mmcra;
+ unsigned long slot;
/* Cant do much about it */
if (!cur_cpu_spec->oprofile_mmcra_sihv)
@@ -193,6 +206,12 @@ static unsigned long get_pc(struct pt_regs *regs)
mmcra = mfspr(SPRN_MMCRA);
+ if (mmcra & MMCRA_SAMPLE_ENABLE) {
+ slot = ((mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT);
+ if (slot > 1)
+ pc += 4 * (slot - 1);
+ }
+
/* Were we in the hypervisor? */
if (firmware_has_feature(FW_FEATURE_LPAR) &&
(mmcra & cur_cpu_spec->oprofile_mmcra_sihv))
diff --git a/arch/powerpc/oprofile/op_model_rs64.c b/arch/powerpc/oprofile/op_model_rs64.c
index c731acbfb2a5..a20afe45d936 100644
--- a/arch/powerpc/oprofile/op_model_rs64.c
+++ b/arch/powerpc/oprofile/op_model_rs64.c
@@ -88,7 +88,7 @@ static unsigned long reset_value[OP_MAX_COUNTER];
static int num_counters;
-static void rs64_reg_setup(struct op_counter_config *ctr,
+static int rs64_reg_setup(struct op_counter_config *ctr,
struct op_system_config *sys,
int num_ctrs)
{
@@ -100,9 +100,10 @@ static void rs64_reg_setup(struct op_counter_config *ctr,
reset_value[i] = 0x80000000UL - ctr[i].count;
/* XXX setup user and kernel profiling */
+ return 0;
}
-static void rs64_cpu_setup(struct op_counter_config *ctr)
+static int rs64_cpu_setup(struct op_counter_config *ctr)
{
unsigned int mmcr0;
@@ -125,9 +126,11 @@ static void rs64_cpu_setup(struct op_counter_config *ctr)
mfspr(SPRN_MMCR0));
dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
mfspr(SPRN_MMCR1));
+
+ return 0;
}
-static void rs64_start(struct op_counter_config *ctr)
+static int rs64_start(struct op_counter_config *ctr)
{
int i;
unsigned int mmcr0;
@@ -155,6 +158,7 @@ static void rs64_start(struct op_counter_config *ctr)
mtspr(SPRN_MMCR0, mmcr0);
dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
+ return 0;
}
static void rs64_stop(void)
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c
index f591a9fc19b9..4be6e7a17b66 100644
--- a/arch/powerpc/platforms/52xx/efika.c
+++ b/arch/powerpc/platforms/52xx/efika.c
@@ -54,7 +54,7 @@ static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
struct pci_controller *hose = bus->sysdata;
unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
| (((bus->number - hose->first_busno) & 0xff) << 16)
- | (hose->index << 24);
+ | (hose->global_number << 24);
int ret = -1;
int rval;
@@ -69,7 +69,7 @@ static int rtas_write_config(struct pci_bus *bus, unsigned int devfn,
struct pci_controller *hose = bus->sysdata;
unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
| (((bus->number - hose->first_busno) & 0xff) << 16)
- | (hose->index << 24);
+ | (hose->global_number << 24);
int rval;
rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
@@ -83,7 +83,7 @@ static struct pci_ops rtas_pci_ops = {
};
-void __init efika_pcisetup(void)
+static void __init efika_pcisetup(void)
{
const int *bus_range;
int len;
@@ -128,7 +128,7 @@ void __init efika_pcisetup(void)
printk(" controlled by %s\n", pcictrl->full_name);
printk("\n");
- hose = pcibios_alloc_controller();
+ hose = pcibios_alloc_controller(of_node_get(pcictrl));
if (!hose) {
printk(KERN_WARNING EFIKA_PLATFORM_NAME
": Can't allocate PCI controller structure for %s\n",
@@ -136,7 +136,6 @@ void __init efika_pcisetup(void)
return;
}
- hose->arch_data = of_node_get(pcictrl);
hose->first_busno = bus_range[0];
hose->last_busno = bus_range[1];
hose->ops = &rtas_pci_ops;
@@ -145,7 +144,7 @@ void __init efika_pcisetup(void)
}
#else
-void __init efika_pcisetup(void)
+static void __init efika_pcisetup(void)
{}
#endif
@@ -252,6 +251,8 @@ define_machine(efika)
.progress = rtas_progress,
.get_boot_time = rtas_get_boot_time,
.calibrate_decr = generic_calibrate_decr,
+#ifdef CONFIG_PCI
.phys_mem_access_prot = pci_phys_mem_access_prot,
+#endif
};
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index 1cfc00dfb99a..5c46e898fd45 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -156,7 +156,7 @@ static void __init lite5200_setup_arch(void)
}
-void lite5200_show_cpuinfo(struct seq_file *m)
+static void lite5200_show_cpuinfo(struct seq_file *m)
{
struct device_node* np = of_find_all_nodes(NULL);
const char *model = NULL;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index 34d34a26d305..4c6c82a684b1 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -112,18 +112,18 @@ mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
u32 value;
if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfn))
+ if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
out_be32(hose->cfg_addr,
(1 << 31) |
- ((bus->number - hose->bus_offset) << 16) |
+ (bus->number << 16) |
(devfn << 8) |
(offset & 0xfc));
mb();
#if defined(CONFIG_PPC_MPC5200_BUGFIX)
- if (bus->number != hose->bus_offset) {
+ if (bus->number) {
/* workaround for the bug 435 of the MPC5200 (L25R);
* Don't do 32 bits config access during type-1 cycles */
switch (len) {
@@ -169,18 +169,18 @@ mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
u32 value, mask;
if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfn))
+ if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
out_be32(hose->cfg_addr,
(1 << 31) |
- ((bus->number - hose->bus_offset) << 16) |
+ (bus->number << 16) |
(devfn << 8) |
(offset & 0xfc));
mb();
#if defined(CONFIG_PPC_MPC5200_BUGFIX)
- if (bus->number != hose->bus_offset) {
+ if (bus->number) {
/* workaround for the bug 435 of the MPC5200 (L25R);
* Don't do 32 bits config access during type-1 cycles */
switch (len) {
@@ -385,17 +385,13 @@ mpc52xx_add_bridge(struct device_node *node)
* tree are needed to configure the 52xx PCI controller. Rather
* than parse the tree here, let pci_process_bridge_OF_ranges()
* do it for us and extract the values after the fact */
- hose = pcibios_alloc_controller();
+ hose = pcibios_alloc_controller(node);
if (!hose)
return -ENOMEM;
- hose->arch_data = node;
- hose->set_cfg_type = 1;
-
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
- hose->bus_offset = 0;
hose->ops = &mpc52xx_pci_ops;
pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
index fd40044d16cd..ee2e7639c63e 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c
@@ -9,8 +9,8 @@
/* these are defined in mpc52xx_sleep.S, and only used here */
-extern void mpc52xx_deep_sleep(void *sram, void *sdram_regs,
- struct mpc52xx_cdm *, struct mpc52xx_intr *);
+extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs,
+ struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*);
extern void mpc52xx_ds_sram(void);
extern const long mpc52xx_ds_sram_size;
extern void mpc52xx_ds_cached(void);
@@ -21,7 +21,7 @@ static void __iomem *sdram;
static struct mpc52xx_cdm __iomem *cdm;
static struct mpc52xx_intr __iomem *intr;
static struct mpc52xx_gpio_wkup __iomem *gpiow;
-static void *sram;
+static void __iomem *sram;
static int sram_size;
struct mpc52xx_suspend mpc52xx_suspend;
@@ -100,7 +100,7 @@ int mpc52xx_pm_enter(suspend_state_t state)
u32 clk_enables;
u32 msr, hid0;
u32 intr_main_mask;
- void __iomem * irq_0x500 = (void *)CONFIG_KERNEL_START + 0x500;
+ void __iomem * irq_0x500 = (void __iomem *)CONFIG_KERNEL_START + 0x500;
unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
char saved_0x500[mpc52xx_ds_cached_size];
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
index de7fce9cb6eb..89fde43895c5 100644
--- a/arch/powerpc/platforms/82xx/Kconfig
+++ b/arch/powerpc/platforms/82xx/Kconfig
@@ -1,5 +1,5 @@
choice
- prompt "Machine Type"
+ prompt "82xx Board Type"
depends on PPC_82xx
default MPC82xx_ADS
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index 47cb09f08052..da20832b27f1 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -49,7 +49,7 @@
#include <linux/fs_enet_pd.h>
#include <sysdev/fsl_soc.h>
-#include <../sysdev/cpm2_pic.h>
+#include <sysdev/cpm2_pic.h>
#include "pq2ads.h"
@@ -507,7 +507,8 @@ void m82xx_pci_init_irq(void)
return;
}
-static int m82xx_pci_exclude_device(u_char bus, u_char devfn)
+static int m82xx_pci_exclude_device(struct pci_controller *hose,
+ u_char bus, u_char devfn)
{
if (bus == 0 && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -515,7 +516,7 @@ static int m82xx_pci_exclude_device(u_char bus, u_char devfn)
return PCIBIOS_SUCCESSFUL;
}
-void __init add_bridge(struct device_node *np)
+static void __init mpc82xx_add_bridge(struct device_node *np)
{
int len;
struct pci_controller *hose;
@@ -542,19 +543,13 @@ void __init add_bridge(struct device_node *np)
pci_assign_all_buses = 1;
- hose = pcibios_alloc_controller();
+ hose = pcibios_alloc_controller(np);
if (!hose)
return;
- hose->arch_data = np;
- hose->set_cfg_type = 1;
-
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
- hose->bus_offset = 0;
-
- hose->set_cfg_type = 1;
setup_indirect_pci(hose,
r.start + offsetof(pci_cpm2_t, pci_cfg_addr),
@@ -584,7 +579,7 @@ static void __init mpc82xx_ads_setup_arch(void)
#ifdef CONFIG_PCI
ppc_md.pci_exclude_device = m82xx_pci_exclude_device;
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc82xx_add_bridge(np);
of_node_put(np);
#endif
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 19cafdf6df93..ec305f18abd8 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -1,5 +1,5 @@
choice
- prompt "Machine Type"
+ prompt "83xx Board Type"
depends on PPC_83xx
default MPC834x_MDS
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 31a91b53f528..5a98f885779f 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the PowerPC 83xx linux kernel.
#
-obj-y := misc.o
+obj-y := misc.o usb.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o
obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o
diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
index 96970ac887ee..3edfe170a03b 100644
--- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
@@ -28,11 +28,6 @@
#define DBG(fmt...)
#endif
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
/* ************************************************************************
*
* Setup the architecture
@@ -49,10 +44,11 @@ static void __init mpc8313_rdb_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc83xx_add_bridge(np);
ppc_md.pci_exclude_device = mpc83xx_exclude_device;
#endif
+ mpc831x_usb_cfg();
}
void __init mpc8313_rdb_init_IRQ(void)
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index 94843ed52a93..b39cb52c6fb9 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -49,11 +49,6 @@
#define DBG(fmt...)
#endif
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
static u8 *bcsr_regs = NULL;
/* ************************************************************************
@@ -80,7 +75,7 @@ static void __init mpc832x_sys_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc83xx_add_bridge(np);
ppc_md.pci_exclude_device = mpc83xx_exclude_device;
#endif
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index 3db68b73fc32..b2b28a44738c 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -32,11 +32,6 @@
#define DBG(fmt...)
#endif
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
/* ************************************************************************
*
* Setup the architecture
@@ -53,7 +48,7 @@ static void __init mpc832x_rdb_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc83xx_add_bridge(np);
ppc_md.pci_exclude_device = mpc83xx_exclude_device;
#endif
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 40a01947d684..47ba5446f63c 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -38,11 +38,6 @@
#include "mpc83xx.h"
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
/* ************************************************************************
*
* Setup the architecture
@@ -59,10 +54,12 @@ static void __init mpc834x_itx_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc83xx_add_bridge(np);
ppc_md.pci_exclude_device = mpc83xx_exclude_device;
#endif
+
+ mpc834x_usb_cfg();
}
static void __init mpc834x_itx_init_IRQ(void)
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c
index 10394b2d7e7a..4c9ff9cadfe4 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c
@@ -38,61 +38,17 @@
#include "mpc83xx.h"
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
#define BCSR5_INT_USB 0x02
-/* Note: This is only for PB, not for PB+PIB
- * On PB only port0 is connected using ULPI */
-static int mpc834x_usb_cfg(void)
+static int mpc834xemds_usb_cfg(void)
{
- unsigned long sccr, sicrl;
- void __iomem *immap;
+ struct device_node *np;
void __iomem *bcsr_regs = NULL;
u8 bcsr5;
- struct device_node *np = NULL;
- int port0_is_dr = 0;
-
- if ((np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr")) != NULL)
- port0_is_dr = 1;
- if ((np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph")) != NULL){
- if (port0_is_dr) {
- printk(KERN_WARNING
- "There is only one USB port on PB board! \n");
- return -1;
- } else if (!port0_is_dr)
- /* No usb port enabled */
- return -1;
- }
-
- immap = ioremap(get_immrbase(), 0x1000);
- if (!immap)
- return -1;
-
- /* Configure clock */
- sccr = in_be32(immap + MPC83XX_SCCR_OFFS);
- if (port0_is_dr)
- sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
- else
- sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */
- out_be32(immap + MPC83XX_SCCR_OFFS, sccr);
-
- /* Configure Pin */
- sicrl = in_be32(immap + MPC83XX_SICRL_OFFS);
- /* set port0 only */
- if (port0_is_dr)
- sicrl |= MPC83XX_SICRL_USB0;
- else
- sicrl &= ~(MPC83XX_SICRL_USB0);
- out_be32(immap + MPC83XX_SICRL_OFFS, sicrl);
-
- iounmap(immap);
+ mpc834x_usb_cfg();
/* Map BCSR area */
np = of_find_node_by_name(NULL, "bcsr");
- if (np != 0) {
+ if (np) {
struct resource res;
of_address_to_resource(np, 0, &res);
@@ -129,12 +85,12 @@ static void __init mpc834x_mds_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc83xx_add_bridge(np);
ppc_md.pci_exclude_device = mpc83xx_exclude_device;
#endif
- mpc834x_usb_cfg();
+ mpc834xemds_usb_cfg();
}
static void __init mpc834x_mds_init_IRQ(void)
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c
index bceeff8bbfd2..0e615fd65c1f 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c
@@ -55,11 +55,6 @@
#define DBG(fmt...)
#endif
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
static u8 *bcsr_regs = NULL;
/* ************************************************************************
@@ -86,7 +81,7 @@ static void __init mpc836x_mds_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc83xx_add_bridge(np);
ppc_md.pci_exclude_device = mpc83xx_exclude_device;
#endif
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h
index 9cd03b59c8f4..589ee55730f3 100644
--- a/arch/powerpc/platforms/83xx/mpc83xx.h
+++ b/arch/powerpc/platforms/83xx/mpc83xx.h
@@ -3,9 +3,11 @@
#include <linux/init.h>
#include <linux/device.h>
+#include <asm/pci-bridge.h>
/* System Clock Control Register */
#define MPC83XX_SCCR_OFFS 0xA08
+#define MPC83XX_SCCR_USB_MASK 0x00f00000
#define MPC83XX_SCCR_USB_MPHCM_11 0x00c00000
#define MPC83XX_SCCR_USB_MPHCM_01 0x00400000
#define MPC83XX_SCCR_USB_MPHCM_10 0x00800000
@@ -15,21 +17,43 @@
/* system i/o configuration register low */
#define MPC83XX_SICRL_OFFS 0x114
-#define MPC83XX_SICRL_USB0 0x40000000
-#define MPC83XX_SICRL_USB1 0x20000000
+#define MPC834X_SICRL_USB_MASK 0x60000000
+#define MPC834X_SICRL_USB0 0x40000000
+#define MPC834X_SICRL_USB1 0x20000000
+#define MPC831X_SICRL_USB_MASK 0x00000c00
+#define MPC831X_SICRL_USB_ULPI 0x00000800
/* system i/o configuration register high */
#define MPC83XX_SICRH_OFFS 0x118
-#define MPC83XX_SICRH_USB_UTMI 0x00020000
+#define MPC834X_SICRH_USB_UTMI 0x00020000
+#define MPC831X_SICRH_USB_MASK 0x000000e0
+#define MPC831X_SICRH_USB_ULPI 0x000000a0
+
+/* USB Control Register */
+#define FSL_USB2_CONTROL_OFFS 0x500
+#define CONTROL_UTMI_PHY_EN 0x00000200
+#define CONTROL_REFSEL_48MHZ 0x00000080
+#define CONTROL_PHY_CLK_SEL_ULPI 0x00000400
+#define CONTROL_OTG_PORT 0x00000020
+
+/* USB PORTSC Registers */
+#define FSL_USB2_PORTSC1_OFFS 0x184
+#define FSL_USB2_PORTSC2_OFFS 0x188
+#define PORTSCX_PTW_16BIT 0x10000000
+#define PORTSCX_PTS_UTMI 0x00000000
+#define PORTSCX_PTS_ULPI 0x80000000
/*
* Declaration for the various functions exported by the
* mpc83xx_* files. Mostly for use by mpc83xx_setup
*/
-extern int add_bridge(struct device_node *dev);
-extern int mpc83xx_exclude_device(u_char bus, u_char devfn);
+extern int mpc83xx_add_bridge(struct device_node *dev);
+extern int mpc83xx_exclude_device(struct pci_controller *hose,
+ u_char bus, u_char devfn);
extern void mpc83xx_restart(char *cmd);
extern long mpc83xx_time_init(void);
+extern int mpc834x_usb_cfg(void);
+extern int mpc831x_usb_cfg(void);
#endif /* __MPC83XX_H__ */
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c
index 774457d09e94..c0e2b89154e5 100644
--- a/arch/powerpc/platforms/83xx/pci.c
+++ b/arch/powerpc/platforms/83xx/pci.c
@@ -33,19 +33,14 @@
#define DBG(x...)
#endif
-int mpc83xx_pci2_busno;
-
-int mpc83xx_exclude_device(u_char bus, u_char devfn)
+int mpc83xx_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
{
- if (bus == 0 && PCI_SLOT(devfn) == 0)
+ if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
- if (mpc83xx_pci2_busno)
- if (bus == (mpc83xx_pci2_busno) && PCI_SLOT(devfn) == 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
return PCIBIOS_SUCCESSFUL;
}
-int __init add_bridge(struct device_node *dev)
+int __init mpc83xx_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
@@ -66,11 +61,10 @@ int __init add_bridge(struct device_node *dev)
" bus 0\n", dev->full_name);
}
- hose = pcibios_alloc_controller();
+ pci_assign_all_buses = 1;
+ hose = pcibios_alloc_controller(dev);
if (!hose)
return -ENOMEM;
- hose->arch_data = dev;
- hose->set_cfg_type = 1;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
@@ -86,8 +80,6 @@ int __init add_bridge(struct device_node *dev)
if ((rsrc.start & 0xfffff) == 0x8600) {
setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384);
primary = 0;
- hose->bus_offset = hose->first_busno;
- mpc83xx_pci2_busno = hose->first_busno;
}
printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. "
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c
new file mode 100644
index 000000000000..e7fdf013cd39
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/usb.c
@@ -0,0 +1,181 @@
+/*
+ * Freescale 83xx USB SOC setup code
+ *
+ * Copyright (C) 2007 Freescale Semiconductor, Inc.
+ * Author: Li Yang
+ *
+ * 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc83xx.h"
+
+
+#ifdef CONFIG_MPC834x
+int mpc834x_usb_cfg(void)
+{
+ unsigned long sccr, sicrl, sicrh;
+ void __iomem *immap;
+ struct device_node *np = NULL;
+ int port0_is_dr = 0, port1_is_dr = 0;
+ const void *prop, *dr_mode;
+
+ immap = ioremap(get_immrbase(), 0x1000);
+ if (!immap)
+ return -ENOMEM;
+
+ /* Read registers */
+ /* Note: DR and MPH must use the same clock setting in SCCR */
+ sccr = in_be32(immap + MPC83XX_SCCR_OFFS) & ~MPC83XX_SCCR_USB_MASK;
+ sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK;
+ sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI;
+
+ np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr");
+ if (np) {
+ sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
+
+ prop = of_get_property(np, "phy_type", NULL);
+ if (prop && (!strcmp(prop, "utmi") ||
+ !strcmp(prop, "utmi_wide"))) {
+ sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
+ sicrh |= MPC834X_SICRH_USB_UTMI;
+ port1_is_dr = 1;
+ } else if (prop && !strcmp(prop, "serial")) {
+ dr_mode = of_get_property(np, "dr_mode", NULL);
+ if (dr_mode && !strcmp(dr_mode, "otg")) {
+ sicrl |= MPC834X_SICRL_USB0 | MPC834X_SICRL_USB1;
+ port1_is_dr = 1;
+ } else {
+ sicrl |= MPC834X_SICRL_USB0;
+ }
+ } else if (prop && !strcmp(prop, "ulpi")) {
+ sicrl |= MPC834X_SICRL_USB0;
+ } else {
+ printk(KERN_WARNING "834x USB PHY type not supported\n");
+ }
+ port0_is_dr = 1;
+ of_node_put(np);
+ }
+ np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph");
+ if (np) {
+ sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */
+
+ prop = of_get_property(np, "port0", NULL);
+ if (prop) {
+ if (port0_is_dr)
+ printk(KERN_WARNING
+ "834x USB port0 can't be used by both DR and MPH!\n");
+ sicrl |= MPC834X_SICRL_USB0;
+ }
+ prop = of_get_property(np, "port1", NULL);
+ if (prop) {
+ if (port1_is_dr)
+ printk(KERN_WARNING
+ "834x USB port1 can't be used by both DR and MPH!\n");
+ sicrl |= MPC834X_SICRL_USB1;
+ }
+ of_node_put(np);
+ }
+
+ /* Write back */
+ out_be32(immap + MPC83XX_SCCR_OFFS, sccr);
+ out_be32(immap + MPC83XX_SICRL_OFFS, sicrl);
+ out_be32(immap + MPC83XX_SICRH_OFFS, sicrh);
+
+ iounmap(immap);
+ return 0;
+}
+#endif /* CONFIG_MPC834x */
+
+#ifdef CONFIG_PPC_MPC831x
+int mpc831x_usb_cfg(void)
+{
+ u32 temp;
+ void __iomem *immap, *usb_regs;
+ struct device_node *np = NULL;
+ const void *prop;
+ struct resource res;
+ int ret = 0;
+#ifdef CONFIG_USB_OTG
+ const void *dr_mode;
+#endif
+
+ np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr");
+ if (!np)
+ return -ENODEV;
+ prop = of_get_property(np, "phy_type", NULL);
+
+ /* Map IMMR space for pin and clock settings */
+ immap = ioremap(get_immrbase(), 0x1000);
+ if (!immap) {
+ of_node_put(np);
+ return -ENOMEM;
+ }
+
+ /* Configure clock */
+ temp = in_be32(immap + MPC83XX_SCCR_OFFS);
+ temp &= ~MPC83XX_SCCR_USB_MASK;
+ temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
+ out_be32(immap + MPC83XX_SCCR_OFFS, temp);
+
+ /* Configure pin mux for ULPI. There is no pin mux for UTMI */
+ if (!strcmp(prop, "ulpi")) {
+ temp = in_be32(immap + MPC83XX_SICRL_OFFS);
+ temp &= ~MPC831X_SICRL_USB_MASK;
+ temp |= MPC831X_SICRL_USB_ULPI;
+ out_be32(immap + MPC83XX_SICRL_OFFS, temp);
+
+ temp = in_be32(immap + MPC83XX_SICRH_OFFS);
+ temp &= ~MPC831X_SICRH_USB_MASK;
+ temp |= MPC831X_SICRH_USB_ULPI;
+ out_be32(immap + MPC83XX_SICRH_OFFS, temp);
+ }
+
+ iounmap(immap);
+
+ /* Map USB SOC space */
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ of_node_put(np);
+ return ret;
+ }
+ usb_regs = ioremap(res.start, res.end - res.start + 1);
+
+ /* Using on-chip PHY */
+ if (!strcmp(prop, "utmi_wide") ||
+ !strcmp(prop, "utmi")) {
+ /* Set UTMI_PHY_EN, REFSEL to 48MHZ */
+ out_be32(usb_regs + FSL_USB2_CONTROL_OFFS,
+ CONTROL_UTMI_PHY_EN | CONTROL_REFSEL_48MHZ);
+ /* Using external UPLI PHY */
+ } else if (!strcmp(prop, "ulpi")) {
+ /* Set PHY_CLK_SEL to ULPI */
+ temp = CONTROL_PHY_CLK_SEL_ULPI;
+#ifdef CONFIG_USB_OTG
+ /* Set OTG_PORT */
+ dr_mode = of_get_property(np, "dr_mode", NULL);
+ if (dr_mode && !strcmp(dr_mode, "otg"))
+ temp |= CONTROL_OTG_PORT;
+#endif /* CONFIG_USB_OTG */
+ out_be32(usb_regs + FSL_USB2_CONTROL_OFFS, temp);
+ } else {
+ printk(KERN_WARNING "831x USB PHY type not supported\n");
+ ret = -EINVAL;
+ }
+
+ iounmap(usb_regs);
+ of_node_put(np);
+ return ret;
+}
+#endif /* CONFIG_PPC_MPC831x */
diff --git a/arch/powerpc/platforms/85xx/misc.c b/arch/powerpc/platforms/85xx/misc.c
index 3e62fcb04c1c..4fe376e9c3b6 100644
--- a/arch/powerpc/platforms/85xx/misc.c
+++ b/arch/powerpc/platforms/85xx/misc.c
@@ -13,11 +13,43 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+
+static __be32 __iomem *rstcr;
extern void abort(void);
+static int __init mpc85xx_rstcr(void)
+{
+ struct device_node *np;
+ np = of_find_node_by_name(NULL, "global-utilities");
+ if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) {
+ const u32 *prop = of_get_property(np, "reg", NULL);
+ if (prop) {
+ /* map reset control register
+ * 0xE00B0 is offset of reset control register
+ */
+ rstcr = ioremap(get_immrbase() + *prop + 0xB0, 0xff);
+ if (!rstcr)
+ printk (KERN_EMERG "Error: reset control "
+ "register not mapped!\n");
+ }
+ } else
+ printk (KERN_INFO "rstcr compatible register does not exist!\n");
+ if (np)
+ of_node_put(np);
+ return 0;
+}
+
+arch_initcall(mpc85xx_rstcr);
+
void mpc85xx_restart(char *cmd)
{
local_irq_disable();
+ if (rstcr)
+ /* set reset control register */
+ out_be32(rstcr, 0x2); /* HRESET_REQ */
abort();
}
diff --git a/arch/powerpc/platforms/85xx/mpc8544_ds.c b/arch/powerpc/platforms/85xx/mpc8544_ds.c
index bec84ffe708e..6fb90aab879f 100644
--- a/arch/powerpc/platforms/85xx/mpc8544_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc8544_ds.c
@@ -61,24 +61,11 @@ void __init mpc8544_ds_pic_init(void)
return;
}
- /* Alloc mpic structure and per isu has 16 INT entries. */
mpic = mpic_alloc(np, r.start,
MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
- 16, 64, " OPENPIC ");
+ 0, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
- /*
- * 48 Internal Interrupts
- */
- mpic_assign_isu(mpic, 0, r.start + 0x10200);
- mpic_assign_isu(mpic, 1, r.start + 0x10400);
- mpic_assign_isu(mpic, 2, r.start + 0x10600);
-
- /*
- * 16 External interrupts
- */
- mpic_assign_isu(mpic, 3, r.start + 0x10000);
-
mpic_init(mpic);
#ifdef CONFIG_PPC_I8259
diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h
index 83415db33378..7286ffac2c1d 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx.h
+++ b/arch/powerpc/platforms/85xx/mpc85xx.h
@@ -15,4 +15,4 @@
*/
extern void mpc85xx_restart(char *);
-extern int add_bridge(struct device_node *dev);
+extern int mpc85xx_add_bridge(struct device_node *dev);
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index 5d27621f0927..7235f702394c 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -38,13 +38,9 @@
#include <asm/fs_pd.h>
#endif
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
#ifdef CONFIG_PCI
-static int mpc85xx_exclude_device(u_char bus, u_char devfn)
+static int mpc85xx_exclude_device(struct pci_controller *hose,
+ u_char bus, u_char devfn)
{
if (bus == 0 && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -91,30 +87,10 @@ static void __init mpc85xx_ads_pic_init(void)
mpic = mpic_alloc(np, r.start,
MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
- 4, 0, " OpenPIC ");
+ 0, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
of_node_put(np);
- mpic_assign_isu(mpic, 0, r.start + 0x10200);
- mpic_assign_isu(mpic, 1, r.start + 0x10280);
- mpic_assign_isu(mpic, 2, r.start + 0x10300);
- mpic_assign_isu(mpic, 3, r.start + 0x10380);
- mpic_assign_isu(mpic, 4, r.start + 0x10400);
- mpic_assign_isu(mpic, 5, r.start + 0x10480);
- mpic_assign_isu(mpic, 6, r.start + 0x10500);
- mpic_assign_isu(mpic, 7, r.start + 0x10580);
-
- /* Unused on this platform (leave room for 8548) */
- mpic_assign_isu(mpic, 8, r.start + 0x10600);
- mpic_assign_isu(mpic, 9, r.start + 0x10680);
- mpic_assign_isu(mpic, 10, r.start + 0x10700);
- mpic_assign_isu(mpic, 11, r.start + 0x10780);
-
- /* External Interrupts */
- mpic_assign_isu(mpic, 12, r.start + 0x10000);
- mpic_assign_isu(mpic, 13, r.start + 0x10080);
- mpic_assign_isu(mpic, 14, r.start + 0x10100);
-
mpic_init(mpic);
#ifdef CONFIG_CPM2
@@ -241,7 +217,7 @@ static void __init mpc85xx_ads_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc85xx_add_bridge(np);
ppc_md.pci_exclude_device = mpc85xx_exclude_device;
#endif
}
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 1490eb3ce0d3..50c8d6458362 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -47,11 +47,6 @@
#include <sysdev/fsl_soc.h>
#include "mpc85xx.h"
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
static int cds_pci_slot = 2;
static volatile u8 *cadmus;
@@ -60,15 +55,11 @@ static volatile u8 *cadmus;
#define ARCADIA_HOST_BRIDGE_IDSEL 17
#define ARCADIA_2ND_BRIDGE_IDSEL 3
-extern int mpc85xx_pci2_busno;
-
-static int mpc85xx_exclude_device(u_char bus, u_char devfn)
+static int mpc85xx_exclude_device(struct pci_controller *hose,
+ u_char bus, u_char devfn)
{
- if (bus == 0 && PCI_SLOT(devfn) == 0)
+ if ((bus == hose->first_busno) && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
- if (mpc85xx_pci2_busno)
- if (bus == (mpc85xx_pci2_busno) && PCI_SLOT(devfn) == 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
/* We explicitly do not go past the Tundra 320 Bridge */
if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL))
return PCIBIOS_DEVICE_NOT_FOUND;
@@ -78,52 +69,44 @@ static int mpc85xx_exclude_device(u_char bus, u_char devfn)
return PCIBIOS_SUCCESSFUL;
}
-static void __init mpc85xx_cds_pcibios_fixup(void)
+static void __init mpc85xx_cds_pci_irq_fixup(struct pci_dev *dev)
{
- struct pci_dev *dev;
- u_char c;
-
- if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_82C586_1, NULL))) {
+ u_char c;
+ if (dev->vendor == PCI_VENDOR_ID_VIA) {
+ switch (dev->device) {
+ case PCI_DEVICE_ID_VIA_82C586_1:
+ /*
+ * U-Boot does not set the enable bits
+ * for the IDE device. Force them on here.
+ */
+ pci_read_config_byte(dev, 0x40, &c);
+ c |= 0x03; /* IDE: Chip Enable Bits */
+ pci_write_config_byte(dev, 0x40, c);
+
+ /*
+ * Since only primary interface works, force the
+ * IDE function to standard primary IDE interrupt
+ * w/ 8259 offset
+ */
+ dev->irq = 14;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ break;
/*
- * U-Boot does not set the enable bits
- * for the IDE device. Force them on here.
+ * Force legacy USB interrupt routing
*/
- pci_read_config_byte(dev, 0x40, &c);
- c |= 0x03; /* IDE: Chip Enable Bits */
- pci_write_config_byte(dev, 0x40, c);
-
- /*
- * Since only primary interface works, force the
- * IDE function to standard primary IDE interrupt
- * w/ 8259 offset
+ case PCI_DEVICE_ID_VIA_82C586_2:
+ /* There are two USB controllers.
+ * Identify them by functon number
*/
- dev->irq = 14;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- pci_dev_put(dev);
- }
-
- /*
- * Force legacy USB interrupt routing
- */
- if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_82C586_2, NULL))) {
- dev->irq = 10;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10);
- pci_dev_put(dev);
- }
-
- if ((dev = pci_get_device(PCI_VENDOR_ID_VIA,
- PCI_DEVICE_ID_VIA_82C586_2, dev))) {
- dev->irq = 11;
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
- pci_dev_put(dev);
+ if (PCI_FUNC(dev->devfn))
+ dev->irq = 11;
+ else
+ dev->irq = 10;
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+ default:
+ break;
+ }
}
-
- /* Now map all the PCI irqs */
- dev = NULL;
- for_each_pci_dev(dev)
- pci_read_irq_line(dev);
}
#ifdef CONFIG_PPC_I8259
@@ -165,33 +148,12 @@ static void __init mpc85xx_cds_pic_init(void)
mpic = mpic_alloc(np, r.start,
MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
- 4, 0, " OpenPIC ");
+ 0, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
/* Return the mpic node */
of_node_put(np);
- mpic_assign_isu(mpic, 0, r.start + 0x10200);
- mpic_assign_isu(mpic, 1, r.start + 0x10280);
- mpic_assign_isu(mpic, 2, r.start + 0x10300);
- mpic_assign_isu(mpic, 3, r.start + 0x10380);
- mpic_assign_isu(mpic, 4, r.start + 0x10400);
- mpic_assign_isu(mpic, 5, r.start + 0x10480);
- mpic_assign_isu(mpic, 6, r.start + 0x10500);
- mpic_assign_isu(mpic, 7, r.start + 0x10580);
-
- /* Used only for 8548 so far, but no harm in
- * allocating them for everyone */
- mpic_assign_isu(mpic, 8, r.start + 0x10600);
- mpic_assign_isu(mpic, 9, r.start + 0x10680);
- mpic_assign_isu(mpic, 10, r.start + 0x10700);
- mpic_assign_isu(mpic, 11, r.start + 0x10780);
-
- /* External Interrupts */
- mpic_assign_isu(mpic, 12, r.start + 0x10000);
- mpic_assign_isu(mpic, 13, r.start + 0x10080);
- mpic_assign_isu(mpic, 14, r.start + 0x10100);
-
mpic_init(mpic);
#ifdef CONFIG_PPC_I8259
@@ -257,9 +219,9 @@ static void __init mpc85xx_cds_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ mpc85xx_add_bridge(np);
- ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup;
+ ppc_md.pci_irq_fixup = mpc85xx_cds_pci_irq_fixup;
ppc_md.pci_exclude_device = mpc85xx_exclude_device;
#endif
}
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index e3dddbfe66ff..004b80bd0b84 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -59,11 +59,6 @@
#define DBG(fmt...)
#endif
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-#endif
-
/* ************************************************************************
*
* Setup the architecture
@@ -100,7 +95,7 @@ static void __init mpc85xx_mds_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) {
- add_bridge(np);
+ mpc85xx_add_bridge(np);
}
of_node_put(np);
#endif
@@ -181,29 +176,10 @@ static void __init mpc85xx_mds_pic_init(void)
mpic = mpic_alloc(np, r.start,
MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
- 4, 0, " OpenPIC ");
+ 0, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
of_node_put(np);
- /* Internal Interrupts */
- mpic_assign_isu(mpic, 0, r.start + 0x10200);
- mpic_assign_isu(mpic, 1, r.start + 0x10280);
- mpic_assign_isu(mpic, 2, r.start + 0x10300);
- mpic_assign_isu(mpic, 3, r.start + 0x10380);
- mpic_assign_isu(mpic, 4, r.start + 0x10400);
- mpic_assign_isu(mpic, 5, r.start + 0x10480);
- mpic_assign_isu(mpic, 6, r.start + 0x10500);
- mpic_assign_isu(mpic, 7, r.start + 0x10580);
- mpic_assign_isu(mpic, 8, r.start + 0x10600);
- mpic_assign_isu(mpic, 9, r.start + 0x10680);
- mpic_assign_isu(mpic, 10, r.start + 0x10700);
- mpic_assign_isu(mpic, 11, r.start + 0x10780);
-
- /* External Interrupts */
- mpic_assign_isu(mpic, 12, r.start + 0x10000);
- mpic_assign_isu(mpic, 13, r.start + 0x10080);
- mpic_assign_isu(mpic, 14, r.start + 0x10100);
-
mpic_init(mpic);
#ifdef CONFIG_QUICC_ENGINE
diff --git a/arch/powerpc/platforms/85xx/pci.c b/arch/powerpc/platforms/85xx/pci.c
index 48f17e23d771..8118417b7364 100644
--- a/arch/powerpc/platforms/85xx/pci.c
+++ b/arch/powerpc/platforms/85xx/pci.c
@@ -33,10 +33,8 @@
#define DBG(x...)
#endif
-int mpc85xx_pci2_busno = 0;
-
#ifdef CONFIG_PCI
-int __init add_bridge(struct device_node *dev)
+int __init mpc85xx_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
@@ -57,11 +55,10 @@ int __init add_bridge(struct device_node *dev)
" bus 0\n", dev->full_name);
}
- hose = pcibios_alloc_controller();
+ pci_assign_all_buses = 1;
+ hose = pcibios_alloc_controller(dev);
if (!hose)
return -ENOMEM;
- hose->arch_data = dev;
- hose->set_cfg_type = 1;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
@@ -74,8 +71,6 @@ int __init add_bridge(struct device_node *dev)
if ((rsrc.start & 0xfffff) == 0x9000) {
setup_indirect_pci(hose, immr + 0x9000, immr + 0x9004);
primary = 0;
- hose->bus_offset = hose->first_busno;
- mpc85xx_pci2_busno = hose->first_busno;
}
printk(KERN_INFO "Found MPC85xx PCI host bridge at 0x%016llx. "
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index d1bcff500464..0faebfdc1596 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -1,5 +1,5 @@
choice
- prompt "Machine Type"
+ prompt "86xx Board Type"
depends on PPC_86xx
default MPC8641_HPCN
diff --git a/arch/powerpc/platforms/86xx/mpc86xx.h b/arch/powerpc/platforms/86xx/mpc86xx.h
index 2834462590b8..23f7ed2a7f88 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx.h
+++ b/arch/powerpc/platforms/86xx/mpc86xx.h
@@ -15,15 +15,10 @@
* mpc86xx_* files. Mostly for use by mpc86xx_setup().
*/
-extern int add_bridge(struct device_node *dev);
+extern int mpc86xx_add_bridge(struct device_node *dev);
-extern int mpc86xx_exclude_device(u_char bus, u_char devfn);
-
-extern void setup_indirect_pcie(struct pci_controller *hose,
- u32 cfg_addr, u32 cfg_data);
-extern void setup_indirect_pcie_nomap(struct pci_controller *hose,
- void __iomem *cfg_addr,
- void __iomem *cfg_data);
+extern int mpc86xx_exclude_device(struct pci_controller *hose,
+ u_char bus, u_char devfn);
extern void __init mpc86xx_smp_init(void);
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index 1051702c8d4f..5b01ec7c13dc 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -44,13 +44,6 @@
#define DBG(fmt...) do { } while(0)
#endif
-#ifndef CONFIG_PCI
-unsigned long isa_io_base = 0;
-unsigned long isa_mem_base = 0;
-unsigned long pci_dram_offset = 0;
-#endif
-
-
#ifdef CONFIG_PCI
static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
@@ -81,22 +74,9 @@ mpc86xx_hpcn_init_irq(void)
/* Alloc mpic structure and per isu has 16 INT entries. */
mpic1 = mpic_alloc(np, res.start,
MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
- 16, NR_IRQS - 4,
- " MPIC ");
+ 0, 256, " MPIC ");
BUG_ON(mpic1 == NULL);
- mpic_assign_isu(mpic1, 0, res.start + 0x10000);
-
- /* 48 Internal Interrupts */
- mpic_assign_isu(mpic1, 1, res.start + 0x10200);
- mpic_assign_isu(mpic1, 2, res.start + 0x10400);
- mpic_assign_isu(mpic1, 3, res.start + 0x10600);
-
- /* 16 External interrupts
- * Moving them from [0 - 15] to [64 - 79]
- */
- mpic_assign_isu(mpic1, 4, res.start + 0x10000);
-
mpic_init(mpic1);
#ifdef CONFIG_PCI
@@ -319,6 +299,7 @@ static void __devinit quirk_uli5229(struct pci_dev *dev)
{
unsigned short temp;
pci_write_config_word(dev, 0x04, 0x0405);
+ dev->class &= ~0x5;
pci_read_config_word(dev, 0x4a, &temp);
temp |= 0x1000;
pci_write_config_word(dev, 0x4a, temp);
@@ -364,9 +345,7 @@ mpc86xx_hpcn_setup_arch(void)
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
-
- ppc_md.pci_exclude_device = mpc86xx_exclude_device;
+ mpc86xx_add_bridge(np);
#endif
printk("MPC86xx HPCN board from Freescale Semiconductor\n");
diff --git a/arch/powerpc/platforms/86xx/pci.c b/arch/powerpc/platforms/86xx/pci.c
index 8235c562661f..73cd5b05a84e 100644
--- a/arch/powerpc/platforms/86xx/pci.c
+++ b/arch/powerpc/platforms/86xx/pci.c
@@ -122,7 +122,6 @@ static void __init
mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
{
u16 cmd;
- unsigned int temps;
DBG("PCIE host controller register offset 0x%08x, size 0x%08x.\n",
pcie_offset, pcie_size);
@@ -133,22 +132,49 @@ mpc86xx_setup_pcie(struct pci_controller *hose, u32 pcie_offset, u32 pcie_size)
early_write_config_word(hose, 0, 0, PCI_COMMAND, cmd);
early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
-
- /* PCIE Bus, Fix the MPC8641D host bridge's location to bus 0xFF. */
- early_read_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, &temps);
- temps = (temps & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16);
- early_write_config_dword(hose, 0, 0, PCI_PRIMARY_BUS, temps);
}
-int mpc86xx_exclude_device(u_char bus, u_char devfn)
+static void __devinit quirk_fsl_pcie_transparent(struct pci_dev *dev)
{
- if (bus == 0 && PCI_SLOT(devfn) == 0)
- return PCIBIOS_DEVICE_NOT_FOUND;
+ struct resource *res;
+ int i, res_idx = PCI_BRIDGE_RESOURCES;
+ struct pci_controller *hose;
- return PCIBIOS_SUCCESSFUL;
+ /*
+ * Make the bridge be transparent.
+ */
+ dev->transparent = 1;
+
+ hose = pci_bus_to_host(dev->bus);
+ if (!hose) {
+ printk(KERN_ERR "Can't find hose for bus %d\n",
+ dev->bus->number);
+ return;
+ }
+
+ if (hose->io_resource.flags) {
+ res = &dev->resource[res_idx++];
+ res->start = hose->io_resource.start;
+ res->end = hose->io_resource.end;
+ res->flags = hose->io_resource.flags;
+ }
+
+ for (i = 0; i < 3; i++) {
+ res = &dev->resource[res_idx + i];
+ res->start = hose->mem_resources[i].start;
+ res->end = hose->mem_resources[i].end;
+ res->flags = hose->mem_resources[i].flags;
+ }
}
-int __init add_bridge(struct device_node *dev)
+
+DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7010, quirk_fsl_pcie_transparent);
+DECLARE_PCI_FIXUP_EARLY(0x1957, 0x7011, quirk_fsl_pcie_transparent);
+
+#define PCIE_LTSSM 0x404 /* PCIe Link Training and Status */
+#define PCIE_LTSSM_L0 0x16 /* L0 state */
+
+int __init mpc86xx_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
@@ -156,6 +182,7 @@ int __init add_bridge(struct device_node *dev)
const int *bus_range;
int has_address = 0;
int primary = 0;
+ u16 val;
DBG("Adding PCIE host bridge %s\n", dev->full_name);
@@ -168,17 +195,23 @@ int __init add_bridge(struct device_node *dev)
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
- hose = pcibios_alloc_controller();
+ pci_assign_all_buses = 1;
+ hose = pcibios_alloc_controller(dev);
if (!hose)
return -ENOMEM;
- hose->arch_data = dev;
- hose->set_cfg_type = 1;
- /* last_busno = 0xfe cause by MPC8641 PCIE bug */
+ hose->indirect_type = PPC_INDIRECT_TYPE_EXT_REG |
+ PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS;
+
hose->first_busno = bus_range ? bus_range[0] : 0x0;
- hose->last_busno = bus_range ? bus_range[1] : 0xfe;
+ hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+ setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4);
- setup_indirect_pcie(hose, rsrc.start, rsrc.start + 0x4);
+ /* Probe the hose link training status */
+ early_read_config_word(hose, 0, 0, PCIE_LTSSM, &val);
+ if (val < PCIE_LTSSM_L0)
+ return -ENXIO;
/* Setup the PCIE host controller. */
mpc86xx_setup_pcie(hose, rsrc.start, rsrc.end - rsrc.start + 1);
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 0901dbada350..f1693550c70c 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -32,6 +32,7 @@
#include <linux/root_dev.h>
#include <linux/time.h>
#include <linux/rtc.h>
+#include <linux/fsl_devices.h>
#include <asm/mmu.h>
#include <asm/reg.h>
@@ -49,6 +50,10 @@
#include "sysdev/mpc8xx_pic.h"
+#ifdef CONFIG_PCMCIA_M8XX
+struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
+#endif
+
void m8xx_calibrate_decr(void);
extern void m8xx_wdt_handler_install(bd_t *bp);
extern int cpm_pic_init(void);
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
index c36e475d93dc..5a808d611ae3 100644
--- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -22,6 +22,7 @@
#include <linux/fs_enet_pd.h>
#include <linux/fs_uart_pd.h>
+#include <linux/fsl_devices.h>
#include <linux/mii.h>
#include <asm/delay.h>
@@ -39,7 +40,7 @@
#include <asm/prom.h>
extern void cpm_reset(void);
-extern void mpc8xx_show_cpuinfo(struct seq_file*);
+extern void mpc8xx_show_cpuinfo(struct seq_file *);
extern void mpc8xx_restart(char *cmd);
extern void mpc8xx_calibrate_decr(void);
extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
@@ -47,9 +48,73 @@ extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
extern void m8xx_pic_init(void);
extern unsigned int mpc8xx_get_irq(void);
-static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
-static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
-static void init_scc3_ioports(struct fs_platform_info* ptr);
+static void init_smc1_uart_ioports(struct fs_uart_platform_info *fpi);
+static void init_smc2_uart_ioports(struct fs_uart_platform_info *fpi);
+static void init_scc3_ioports(struct fs_platform_info *ptr);
+
+#ifdef CONFIG_PCMCIA_M8XX
+static void pcmcia_hw_setup(int slot, int enable)
+{
+ unsigned *bcsr_io;
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+ if (enable)
+ clrbits32(bcsr_io, BCSR1_PCCEN);
+ else
+ setbits32(bcsr_io, BCSR1_PCCEN);
+
+ iounmap(bcsr_io);
+}
+
+static int pcmcia_set_voltage(int slot, int vcc, int vpp)
+{
+ u32 reg = 0;
+ unsigned *bcsr_io;
+
+ bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+
+ switch (vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= BCSR1_PCCVCC0;
+ break;
+ case 50:
+ reg |= BCSR1_PCCVCC1;
+ break;
+ default:
+ return 1;
+ }
+
+ switch (vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if (vcc == vpp)
+ reg |= BCSR1_PCCVPP1;
+ else
+ return 1;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= BCSR1_PCCVPP0;
+ else
+ return 1;
+ default:
+ return 1;
+ }
+
+ /* first, turn off all power */
+ clrbits32(bcsr_io, 0x00610000);
+
+ /* enable new powersettings */
+ setbits32(bcsr_io, reg);
+
+ iounmap(bcsr_io);
+ return 0;
+}
+#endif
void __init mpc885ads_board_setup(void)
{
@@ -62,7 +127,7 @@ void __init mpc885ads_board_setup(void)
#endif
bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
- cp = (cpm8xx_t *)immr_map(im_cpm);
+ cp = (cpm8xx_t *) immr_map(im_cpm);
if (bcsr_io == NULL) {
printk(KERN_CRIT "Could not remap BCSR\n");
@@ -75,13 +140,13 @@ void __init mpc885ads_board_setup(void)
out_8(&(cp->cp_smc[0].smc_smcm), tmpval8);
clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); /* brg1 */
#else
- setbits32(bcsr_io,BCSR1_RS232EN_1);
+ setbits32(bcsr_io, BCSR1_RS232EN_1);
out_be16(&cp->cp_smc[0].smc_smcmr, 0);
out_8(&cp->cp_smc[0].smc_smce, 0);
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
- clrbits32(bcsr_io,BCSR1_RS232EN_2);
+ clrbits32(bcsr_io, BCSR1_RS232EN_2);
clrbits32(&cp->cp_simode, 0xe0000000 >> 1);
setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */
tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX);
@@ -90,7 +155,7 @@ void __init mpc885ads_board_setup(void)
init_smc2_uart_ioports(0);
#else
- setbits32(bcsr_io,BCSR1_RS232EN_2);
+ setbits32(bcsr_io, BCSR1_RS232EN_2);
out_be16(&cp->cp_smc[1].smc_smcmr, 0);
out_8(&cp->cp_smc[1].smc_smce, 0);
#endif
@@ -99,29 +164,34 @@ void __init mpc885ads_board_setup(void)
#ifdef CONFIG_FS_ENET
/* use MDC for MII (common) */
- io_port = (iop8xx_t*)immr_map(im_ioport);
+ io_port = (iop8xx_t *) immr_map(im_ioport);
setbits16(&io_port->iop_pdpar, 0x0080);
clrbits16(&io_port->iop_pddir, 0x0080);
bcsr_io = ioremap(BCSR5, sizeof(unsigned long));
- clrbits32(bcsr_io,BCSR5_MII1_EN);
- clrbits32(bcsr_io,BCSR5_MII1_RST);
+ clrbits32(bcsr_io, BCSR5_MII1_EN);
+ clrbits32(bcsr_io, BCSR5_MII1_RST);
#ifndef CONFIG_FC_ENET_HAS_SCC
- clrbits32(bcsr_io,BCSR5_MII2_EN);
- clrbits32(bcsr_io,BCSR5_MII2_RST);
+ clrbits32(bcsr_io, BCSR5_MII2_EN);
+ clrbits32(bcsr_io, BCSR5_MII2_RST);
#endif
iounmap(bcsr_io);
immr_unmap(io_port);
#endif
-}
+#ifdef CONFIG_PCMCIA_M8XX
+ /*Set up board specific hook-ups */
+ m8xx_pcmcia_ops.hw_ctrl = pcmcia_hw_setup;
+ m8xx_pcmcia_ops.voltage_set = pcmcia_set_voltage;
+#endif
+}
-static void init_fec1_ioports(struct fs_platform_info* ptr)
+static void init_fec1_ioports(struct fs_platform_info *ptr)
{
- cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
- iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+ cpm8xx_t *cp = (cpm8xx_t *) immr_map(im_cpm);
+ iop8xx_t *io_port = (iop8xx_t *) immr_map(im_ioport);
/* configure FEC1 pins */
setbits16(&io_port->iop_papar, 0xf830);
@@ -143,11 +213,10 @@ static void init_fec1_ioports(struct fs_platform_info* ptr)
immr_unmap(cp);
}
-
-static void init_fec2_ioports(struct fs_platform_info* ptr)
+static void init_fec2_ioports(struct fs_platform_info *ptr)
{
- cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
- iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
+ cpm8xx_t *cp = (cpm8xx_t *) immr_map(im_cpm);
+ iop8xx_t *io_port = (iop8xx_t *) immr_map(im_ioport);
/* configure FEC2 pins */
setbits32(&cp->cp_pepar, 0x0003fffc);
@@ -177,15 +246,15 @@ void init_fec_ioports(struct fs_platform_info *fpi)
}
}
-static void init_scc3_ioports(struct fs_platform_info* fpi)
+static void init_scc3_ioports(struct fs_platform_info *fpi)
{
unsigned *bcsr_io;
iop8xx_t *io_port;
cpm8xx_t *cp;
bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
- io_port = (iop8xx_t *)immr_map(im_ioport);
- cp = (cpm8xx_t *)immr_map(im_cpm);
+ io_port = (iop8xx_t *) immr_map(im_ioport);
+ cp = (cpm8xx_t *) immr_map(im_cpm);
if (bcsr_io == NULL) {
printk(KERN_CRIT "Could not remap BCSR\n");
@@ -194,9 +263,9 @@ static void init_scc3_ioports(struct fs_platform_info* fpi)
/* Enable the PHY.
*/
- clrbits32(bcsr_io+4, BCSR4_ETH10_RST);
+ clrbits32(bcsr_io + 4, BCSR4_ETH10_RST);
udelay(1000);
- setbits32(bcsr_io+4, BCSR4_ETH10_RST);
+ setbits32(bcsr_io + 4, BCSR4_ETH10_RST);
/* Configure port A pins for Txd and Rxd.
*/
setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD);
@@ -212,8 +281,7 @@ static void init_scc3_ioports(struct fs_platform_info* fpi)
*/
setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
clrbits32(&cp->cp_pepar, PE_ENET_TENA);
- clrbits32(&cp->cp_pedir,
- PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
+ clrbits32(&cp->cp_pedir, PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
setbits32(&cp->cp_peso, PE_ENET_TENA);
@@ -237,7 +305,7 @@ static void init_scc3_ioports(struct fs_platform_info* fpi)
clrbits32(&cp->cp_pedir, PE_ENET_TENA);
setbits32(&cp->cp_peso, PE_ENET_TENA);
- setbits32(bcsr_io+4, BCSR1_ETHEN);
+ setbits32(bcsr_io + 4, BCSR1_ETHEN);
iounmap(bcsr_io);
immr_unmap(io_port);
immr_unmap(cp);
@@ -257,50 +325,48 @@ void init_scc_ioports(struct fs_platform_info *fpi)
}
}
-
-
-static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr)
+static void init_smc1_uart_ioports(struct fs_uart_platform_info *ptr)
{
- unsigned *bcsr_io;
+ unsigned *bcsr_io;
cpm8xx_t *cp;
- cp = (cpm8xx_t *)immr_map(im_cpm);
+ cp = (cpm8xx_t *) immr_map(im_cpm);
setbits32(&cp->cp_pepar, 0x000000c0);
clrbits32(&cp->cp_pedir, 0x000000c0);
clrbits32(&cp->cp_peso, 0x00000040);
setbits32(&cp->cp_peso, 0x00000080);
immr_unmap(cp);
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+ 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);
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR1\n");
+ return;
+ }
+ clrbits32(bcsr_io, BCSR1_RS232EN_1);
+ iounmap(bcsr_io);
}
-static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi)
+static void init_smc2_uart_ioports(struct fs_uart_platform_info *fpi)
{
- unsigned *bcsr_io;
+ unsigned *bcsr_io;
cpm8xx_t *cp;
- cp = (cpm8xx_t *)immr_map(im_cpm);
+ cp = (cpm8xx_t *) immr_map(im_cpm);
setbits32(&cp->cp_pepar, 0x00000c00);
clrbits32(&cp->cp_pedir, 0x00000c00);
clrbits32(&cp->cp_peso, 0x00000400);
setbits32(&cp->cp_peso, 0x00000800);
immr_unmap(cp);
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
+ 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);
+ if (bcsr_io == NULL) {
+ printk(KERN_CRIT "Could not remap BCSR1\n");
+ return;
+ }
+ clrbits32(bcsr_io, BCSR1_RS232EN_2);
+ iounmap(bcsr_io);
}
void init_smc_ioports(struct fs_uart_platform_info *data)
@@ -373,15 +439,11 @@ static int __init mpc885ads_probe(void)
return 1;
}
-define_machine(mpc885_ads) {
- .name = "MPC885 ADS",
- .probe = mpc885ads_probe,
- .setup_arch = mpc885ads_setup_arch,
- .init_IRQ = m8xx_pic_init,
- .show_cpuinfo = mpc8xx_show_cpuinfo,
- .get_irq = mpc8xx_get_irq,
- .restart = mpc8xx_restart,
- .calibrate_decr = mpc8xx_calibrate_decr,
- .set_rtc_time = mpc8xx_set_rtc_time,
- .get_rtc_time = mpc8xx_get_rtc_time,
-};
+define_machine(mpc885_ads)
+{
+.name = "MPC885 ADS",.probe = mpc885ads_probe,.setup_arch =
+ mpc885ads_setup_arch,.init_IRQ =
+ m8xx_pic_init,.show_cpuinfo = mpc8xx_show_cpuinfo,.get_irq =
+ mpc8xx_get_irq,.restart = mpc8xx_restart,.calibrate_decr =
+ mpc8xx_calibrate_decr,.set_rtc_time =
+ mpc8xx_set_rtc_time,.get_rtc_time = mpc8xx_get_rtc_time,};
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 361acfa2894c..932538a93c2b 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -2,7 +2,7 @@ menu "Platform support"
choice
prompt "Machine type"
- depends on PPC64 || CLASSIC32
+ depends on PPC64 || 6xx
default PPC_MULTIPLATFORM
config PPC_MULTIPLATFORM
@@ -16,15 +16,30 @@ config EMBEDDED6xx
bool "Embedded 6xx/7xx/7xxx-based board"
depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
-config APUS
- bool "Amiga-APUS"
- depends on PPC32 && BROKEN
+config PPC_82xx
+ bool "Freescale 82xx"
+ depends on 6xx
+
+config PPC_83xx
+ bool "Freescale 83xx"
+ depends on 6xx
+ select FSL_SOC
+ select 83xx
+ select WANT_DEVICE_TREE
+
+config PPC_86xx
+ bool "Freescale 86xx"
+ depends on 6xx
+ select FSL_SOC
+ select ALTIVEC
help
- Select APUS if configuring for a PowerUP Amiga.
- More information is available at:
- <http://linux-apus.sourceforge.net/>.
+ The Freescale E600 SoCs have 74xx cores.
endchoice
+config CLASSIC32
+ def_bool y
+ depends on 6xx && PPC_MULTIPLATFORM
+
source "arch/powerpc/platforms/pseries/Kconfig"
source "arch/powerpc/platforms/iseries/Kconfig"
source "arch/powerpc/platforms/chrp/Kconfig"
@@ -257,4 +272,14 @@ config CPM2
you wish to build a kernel for a machine with a CPM2 coprocessor
on it (826x, 827x, 8560).
+config AXON_RAM
+ tristate "Axon DDR2 memory device driver"
+ depends on PPC_IBM_CELL_BLADE
+ default m
+ help
+ It registers one block device per Axon's DDR2 memory bank found
+ on a system. Block devices are called axonram?, their major and
+ minor numbers are available in /proc/devices, /proc/partitions or
+ in /sys/block/axonram?/dev.
+
endmenu
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
new file mode 100644
index 000000000000..e4b2aee53a73
--- /dev/null
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -0,0 +1,221 @@
+config PPC64
+ bool "64-bit kernel"
+ default n
+ help
+ This option selects whether a 32-bit or a 64-bit kernel
+ will be built.
+
+menu "Processor support"
+choice
+ prompt "Processor Type"
+ depends on PPC32
+ default 6xx
+ help
+ There are five families of 32 bit PowerPC chips supported.
+ The most common ones are the desktop and server CPUs (601, 603,
+ 604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
+ embedded 52xx/82xx/83xx/86xx counterparts.
+ The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
+ (85xx) each form a family of their own that is not compatible
+ with the others.
+
+ If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
+
+config 6xx
+ bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
+ select PPC_FPU
+
+config PPC_85xx
+ bool "Freescale 85xx"
+ select E500
+ select FSL_SOC
+ select 85xx
+ select WANT_DEVICE_TREE
+
+config PPC_8xx
+ bool "Freescale 8xx"
+ select FSL_SOC
+ select 8xx
+
+config 40x
+ bool "AMCC 40x"
+ select PPC_DCR_NATIVE
+
+config 44x
+ bool "AMCC 44x"
+ select PPC_DCR_NATIVE
+ select WANT_DEVICE_TREE
+
+config E200
+ bool "Freescale e200"
+
+endchoice
+
+config POWER4_ONLY
+ bool "Optimize for POWER4"
+ depends on PPC64
+ default n
+ ---help---
+ Cause the compiler to optimize for POWER4/POWER5/PPC970 processors.
+ The resulting binary will not work on POWER3 or RS64 processors
+ when compiled with binutils 2.15 or later.
+
+config POWER3
+ bool
+ depends on PPC64
+ default y if !POWER4_ONLY
+
+config POWER4
+ depends on PPC64
+ def_bool y
+
+config 6xx
+ bool
+
+# this is temp to handle compat with arch=ppc
+config 8xx
+ bool
+
+# this is temp to handle compat with arch=ppc
+config 83xx
+ bool
+
+# this is temp to handle compat with arch=ppc
+config 85xx
+ bool
+
+config E500
+ bool
+
+config PPC_FPU
+ bool
+ default y if PPC64
+
+config 4xx
+ bool
+ depends on 40x || 44x
+ default y
+
+config BOOKE
+ bool
+ depends on E200 || E500 || 44x
+ default y
+
+config FSL_BOOKE
+ bool
+ depends on E200 || E500
+ default y
+
+config PTE_64BIT
+ bool
+ depends on 44x || E500
+ default y if 44x
+ default y if E500 && PHYS_64BIT
+
+config PHYS_64BIT
+ bool 'Large physical address support' if E500
+ depends on 44x || E500
+ select RESOURCES_64BIT
+ default y if 44x
+ ---help---
+ This option enables kernel support for larger than 32-bit physical
+ addresses. This features is not be available on all e500 cores.
+
+ If in doubt, say N here.
+
+config ALTIVEC
+ bool "AltiVec Support"
+ depends on CLASSIC32 || POWER4
+ ---help---
+ This option enables kernel support for the Altivec extensions to the
+ PowerPC processor. The kernel currently supports saving and restoring
+ altivec registers, and turning on the 'altivec enable' bit so user
+ processes can execute altivec instructions.
+
+ This option is only usefully if you have a processor that supports
+ altivec (G4, otherwise known as 74xx series), but does not have
+ any affect on a non-altivec cpu (it does, however add code to the
+ kernel).
+
+ If in doubt, say Y here.
+
+config SPE
+ bool "SPE Support"
+ depends on E200 || E500
+ default y
+ ---help---
+ This option enables kernel support for the Signal Processing
+ Extensions (SPE) to the PowerPC processor. The kernel currently
+ supports saving and restoring SPE registers, and turning on the
+ 'spe enable' bit so user processes can execute SPE instructions.
+
+ This option is only useful if you have a processor that supports
+ SPE (e500, otherwise known as 85xx series), but does not have any
+ effect on a non-spe cpu (it does, however add code to the kernel).
+
+ If in doubt, say Y here.
+
+config PPC_STD_MMU
+ bool
+ depends on 6xx || POWER3 || POWER4 || PPC64
+ default y
+
+config PPC_STD_MMU_32
+ def_bool y
+ depends on PPC_STD_MMU && PPC32
+
+config PPC_MM_SLICES
+ bool
+ default y if HUGETLB_PAGE
+ default n
+
+config VIRT_CPU_ACCOUNTING
+ bool "Deterministic task and CPU time accounting"
+ depends on PPC64
+ default y
+ help
+ Select this option to enable more accurate task and CPU time
+ accounting. This is done by reading a CPU counter on each
+ kernel entry and exit and on transitions within the kernel
+ between system, softirq and hardirq state, so there is a
+ small performance impact. This also enables accounting of
+ stolen time on logically-partitioned systems running on
+ IBM POWER5-based machines.
+
+ If in doubt, say Y here.
+
+config SMP
+ depends on PPC_STD_MMU
+ bool "Symmetric multi-processing support"
+ ---help---
+ This enables support for systems with more than one CPU. If you have
+ a system with only one CPU, say N. If you have a system with more
+ than one CPU, say Y. Note that the kernel does not currently
+ support SMP machines with 603/603e/603ev or PPC750 ("G3") processors
+ since they have inadequate hardware support for multiprocessor
+ operation.
+
+ If you say N here, the kernel will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor machine. If
+ you say Y here, the kernel will run on single-processor machines.
+ On a single-processor machine, the kernel will run faster if you say
+ N here.
+
+ If you don't know what to do here, say N.
+
+config NR_CPUS
+ int "Maximum number of CPUs (2-128)"
+ range 2 128
+ depends on SMP
+ default "32" if PPC64
+ default "4"
+
+config NOT_COHERENT_CACHE
+ bool
+ depends on 4xx || 8xx || E200
+ default y
+
+config CHECK_CACHE_COHERENCY
+ bool
+
+endmenu
diff --git a/arch/powerpc/platforms/apus/Kconfig b/arch/powerpc/platforms/apus/Kconfig
deleted file mode 100644
index 6bde3bffed86..000000000000
--- a/arch/powerpc/platforms/apus/Kconfig
+++ /dev/null
@@ -1,130 +0,0 @@
-
-config AMIGA
- bool
- depends on APUS
- default y
- help
- This option enables support for the Amiga series of computers.
-
-config ZORRO
- bool
- depends on APUS
- default y
- help
- This enables support for the Zorro bus in the Amiga. If you have
- expansion cards in your Amiga that conform to the Amiga
- AutoConfig(tm) specification, say Y, otherwise N. Note that even
- expansion cards that do not fit in the Zorro slots but fit in e.g.
- the CPU slot may fall in this category, so you have to say Y to let
- Linux use these.
-
-config ABSTRACT_CONSOLE
- bool
- depends on APUS
- default y
-
-config APUS_FAST_EXCEPT
- bool
- depends on APUS
- default y
-
-config AMIGA_PCMCIA
- bool "Amiga 1200/600 PCMCIA support"
- depends on APUS && EXPERIMENTAL
- help
- Include support in the kernel for pcmcia on Amiga 1200 and Amiga
- 600. If you intend to use pcmcia cards say Y; otherwise say N.
-
-config AMIGA_BUILTIN_SERIAL
- tristate "Amiga builtin serial support"
- depends on APUS
- help
- If you want to use your Amiga's built-in serial port in Linux,
- answer Y.
-
- To compile this driver as a module, choose M here.
-
-config GVPIOEXT
- tristate "GVP IO-Extender support"
- depends on APUS
- help
- If you want to use a GVP IO-Extender serial card in Linux, say Y.
- Otherwise, say N.
-
-config GVPIOEXT_LP
- tristate "GVP IO-Extender parallel printer support"
- depends on GVPIOEXT
- help
- Say Y to enable driving a printer from the parallel port on your
- GVP IO-Extender card, N otherwise.
-
-config GVPIOEXT_PLIP
- tristate "GVP IO-Extender PLIP support"
- depends on GVPIOEXT
- help
- Say Y to enable doing IP over the parallel port on your GVP
- IO-Extender card, N otherwise.
-
-config MULTIFACE_III_TTY
- tristate "Multiface Card III serial support"
- depends on APUS
- help
- If you want to use a Multiface III card's serial port in Linux,
- answer Y.
-
- To compile this driver as a module, choose M here.
-
-config A2232
- tristate "Commodore A2232 serial support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && APUS
- ---help---
- This option supports the 2232 7-port serial card shipped with the
- Amiga 2000 and other Zorro-bus machines, dating from 1989. At
- a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip
- each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The
- ports were connected with 8 pin DIN connectors on the card bracket,
- for which 8 pin to DB25 adapters were supplied. The card also had
- jumpers internally to toggle various pinning configurations.
-
- This driver can be built as a module; but then "generic_serial"
- will also be built as a module. This has to be loaded before
- "ser_a2232". If you want to do this, answer M here.
-
-config WHIPPET_SERIAL
- tristate "Hisoft Whippet PCMCIA serial support"
- depends on AMIGA_PCMCIA
- help
- HiSoft has a web page at <http://www.hisoft.co.uk/>, but there
- is no listing for the Whippet in their Amiga section.
-
-config APNE
- tristate "PCMCIA NE2000 support"
- depends on AMIGA_PCMCIA
- help
- If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise,
- say N.
-
- To compile this driver as a module, choose M here: the
- module will be called apne.
-
-config SERIAL_CONSOLE
- bool "Support for serial port console"
- depends on APUS && (AMIGA_BUILTIN_SERIAL=y || GVPIOEXT=y || MULTIFACE_III_TTY=y)
-
-config HEARTBEAT
- bool "Use power LED as a heartbeat"
- depends on APUS
- help
- Use the power-on LED on your machine as a load meter. The exact
- behavior is platform-dependent, but normally the flash frequency is
- a hyperbolic function of the 5-minute load average.
-
-config PROC_HARDWARE
- bool "/proc/hardware support"
- depends on APUS
-
-source "drivers/zorro/Kconfig"
-
-config PCI_PERMEDIA
- bool "PCI for Permedia2"
- depends on !4xx && !8xx && APUS
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 9b2b386ccf48..ac8032034fb8 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -73,4 +73,14 @@ config CBE_CPUFREQ
For details, take a look at <file:Documentation/cpu-freq/>.
If you don't have such processor, say N
+config CBE_CPUFREQ_PMI
+ tristate "CBE frequency scaling using PMI interface"
+ depends on CBE_CPUFREQ && PPC_PMI && EXPERIMENTAL
+ default n
+ help
+ Select this, if you want to use the PMI interface
+ to switch frequencies. Using PMI, the
+ processor will not only be able to run at lower speed,
+ but also at lower core voltage.
+
endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 869af89df6ff..f88a7c76f296 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -4,7 +4,9 @@ obj-$(CONFIG_PPC_CELL_NATIVE) += interrupt.o iommu.o setup.o \
obj-$(CONFIG_CBE_RAS) += ras.o
obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
-obj-$(CONFIG_CBE_CPUFREQ) += cbe_cpufreq.o
+obj-$(CONFIG_CBE_CPUFREQ_PMI) += cbe_cpufreq_pmi.o
+obj-$(CONFIG_CBE_CPUFREQ) += cbe-cpufreq.o
+cbe-cpufreq-y += cbe_cpufreq_pervasive.o cbe_cpufreq.o
ifeq ($(CONFIG_SMP),y)
obj-$(CONFIG_PPC_CELL_NATIVE) += smp.o
@@ -23,3 +25,5 @@ obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
$(spu-priv1-y) \
$(spu-manage-y) \
spufs/
+
+obj-$(CONFIG_PCI_MSI) += axon_msi.o
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
new file mode 100644
index 000000000000..4c9ab5b70bae
--- /dev/null
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2007, Michael Ellerman, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/reboot.h>
+
+#include <asm/dcr.h>
+#include <asm/machdep.h>
+#include <asm/prom.h>
+
+
+/*
+ * MSIC registers, specified as offsets from dcr_base
+ */
+#define MSIC_CTRL_REG 0x0
+
+/* Base Address registers specify FIFO location in BE memory */
+#define MSIC_BASE_ADDR_HI_REG 0x3
+#define MSIC_BASE_ADDR_LO_REG 0x4
+
+/* Hold the read/write offsets into the FIFO */
+#define MSIC_READ_OFFSET_REG 0x5
+#define MSIC_WRITE_OFFSET_REG 0x6
+
+
+/* MSIC control register flags */
+#define MSIC_CTRL_ENABLE 0x0001
+#define MSIC_CTRL_FIFO_FULL_ENABLE 0x0002
+#define MSIC_CTRL_IRQ_ENABLE 0x0008
+#define MSIC_CTRL_FULL_STOP_ENABLE 0x0010
+
+/*
+ * The MSIC can be configured to use a FIFO of 32KB, 64KB, 128KB or 256KB.
+ * Currently we're using a 64KB FIFO size.
+ */
+#define MSIC_FIFO_SIZE_SHIFT 16
+#define MSIC_FIFO_SIZE_BYTES (1 << MSIC_FIFO_SIZE_SHIFT)
+
+/*
+ * To configure the FIFO size as (1 << n) bytes, we write (n - 15) into bits
+ * 8-9 of the MSIC control reg.
+ */
+#define MSIC_CTRL_FIFO_SIZE (((MSIC_FIFO_SIZE_SHIFT - 15) << 8) & 0x300)
+
+/*
+ * We need to mask the read/write offsets to make sure they stay within
+ * the bounds of the FIFO. Also they should always be 16-byte aligned.
+ */
+#define MSIC_FIFO_SIZE_MASK ((MSIC_FIFO_SIZE_BYTES - 1) & ~0xFu)
+
+/* Each entry in the FIFO is 16 bytes, the first 4 bytes hold the irq # */
+#define MSIC_FIFO_ENTRY_SIZE 0x10
+
+
+struct axon_msic {
+ struct device_node *dn;
+ struct irq_host *irq_host;
+ __le32 *fifo;
+ dcr_host_t dcr_host;
+ struct list_head list;
+ u32 read_offset;
+ u32 dcr_base;
+};
+
+static LIST_HEAD(axon_msic_list);
+
+static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
+{
+ pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
+
+ dcr_write(msic->dcr_host, msic->dcr_base + dcr_n, val);
+}
+
+static u32 msic_dcr_read(struct axon_msic *msic, unsigned int dcr_n)
+{
+ return dcr_read(msic->dcr_host, msic->dcr_base + dcr_n);
+}
+
+static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct axon_msic *msic = get_irq_data(irq);
+ u32 write_offset, msi;
+ int idx;
+
+ write_offset = msic_dcr_read(msic, MSIC_WRITE_OFFSET_REG);
+ pr_debug("axon_msi: original write_offset 0x%x\n", write_offset);
+
+ /* write_offset doesn't wrap properly, so we have to mask it */
+ write_offset &= MSIC_FIFO_SIZE_MASK;
+
+ while (msic->read_offset != write_offset) {
+ idx = msic->read_offset / sizeof(__le32);
+ msi = le32_to_cpu(msic->fifo[idx]);
+ msi &= 0xFFFF;
+
+ pr_debug("axon_msi: woff %x roff %x msi %x\n",
+ write_offset, msic->read_offset, msi);
+
+ msic->read_offset += MSIC_FIFO_ENTRY_SIZE;
+ msic->read_offset &= MSIC_FIFO_SIZE_MASK;
+
+ if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host)
+ generic_handle_irq(msi);
+ else
+ pr_debug("axon_msi: invalid irq 0x%x!\n", msi);
+ }
+
+ desc->chip->eoi(irq);
+}
+
+static struct axon_msic *find_msi_translator(struct pci_dev *dev)
+{
+ struct irq_host *irq_host;
+ struct device_node *dn, *tmp;
+ const phandle *ph;
+ struct axon_msic *msic = NULL;
+
+ dn = pci_device_to_OF_node(dev);
+ if (!dn) {
+ dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+ return NULL;
+ }
+
+ for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+ ph = of_get_property(dn, "msi-translator", NULL);
+ if (ph)
+ break;
+ }
+
+ if (!ph) {
+ dev_dbg(&dev->dev,
+ "axon_msi: no msi-translator property found\n");
+ goto out_error;
+ }
+
+ tmp = dn;
+ dn = of_find_node_by_phandle(*ph);
+ if (!dn) {
+ dev_dbg(&dev->dev,
+ "axon_msi: msi-translator doesn't point to a node\n");
+ goto out_error;
+ }
+
+ irq_host = irq_find_host(dn);
+ if (!irq_host) {
+ dev_dbg(&dev->dev, "axon_msi: no irq_host found for node %s\n",
+ dn->full_name);
+ goto out_error;
+ }
+
+ msic = irq_host->host_data;
+
+out_error:
+ of_node_put(dn);
+ of_node_put(tmp);
+
+ return msic;
+}
+
+static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
+{
+ if (!find_msi_translator(dev))
+ return -ENODEV;
+
+ return 0;
+}
+
+static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
+{
+ struct device_node *dn, *tmp;
+ struct msi_desc *entry;
+ int len;
+ const u32 *prop;
+
+ dn = pci_device_to_OF_node(dev);
+ if (!dn) {
+ dev_dbg(&dev->dev, "axon_msi: no pci_dn found\n");
+ return -ENODEV;
+ }
+
+ entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
+
+ for (; dn; tmp = of_get_parent(dn), of_node_put(dn), dn = tmp) {
+ if (entry->msi_attrib.is_64) {
+ prop = of_get_property(dn, "msi-address-64", &len);
+ if (prop)
+ break;
+ }
+
+ prop = of_get_property(dn, "msi-address-32", &len);
+ if (prop)
+ break;
+ }
+
+ if (!prop) {
+ dev_dbg(&dev->dev,
+ "axon_msi: no msi-address-(32|64) properties found\n");
+ return -ENOENT;
+ }
+
+ switch (len) {
+ case 8:
+ msg->address_hi = prop[0];
+ msg->address_lo = prop[1];
+ break;
+ case 4:
+ msg->address_hi = 0;
+ msg->address_lo = prop[0];
+ break;
+ default:
+ dev_dbg(&dev->dev,
+ "axon_msi: malformed msi-address-(32|64) property\n");
+ of_node_put(dn);
+ return -EINVAL;
+ }
+
+ of_node_put(dn);
+
+ return 0;
+}
+
+static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ unsigned int virq, rc;
+ struct msi_desc *entry;
+ struct msi_msg msg;
+ struct axon_msic *msic;
+
+ msic = find_msi_translator(dev);
+ if (!msic)
+ return -ENODEV;
+
+ rc = setup_msi_msg_address(dev, &msg);
+ if (rc)
+ return rc;
+
+ /* We rely on being able to stash a virq in a u16 */
+ BUILD_BUG_ON(NR_IRQS > 65536);
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ virq = irq_create_direct_mapping(msic->irq_host);
+ if (virq == NO_IRQ) {
+ dev_warn(&dev->dev,
+ "axon_msi: virq allocation failed!\n");
+ return -1;
+ }
+ dev_dbg(&dev->dev, "axon_msi: allocated virq 0x%x\n", virq);
+
+ set_irq_msi(virq, entry);
+ msg.data = virq;
+ write_msi_msg(virq, &msg);
+ }
+
+ return 0;
+}
+
+static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+
+ dev_dbg(&dev->dev, "axon_msi: tearing down msi irqs\n");
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (entry->irq == NO_IRQ)
+ continue;
+
+ set_irq_msi(entry->irq, NULL);
+ irq_dispose_mapping(entry->irq);
+ }
+}
+
+static struct irq_chip msic_irq_chip = {
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .shutdown = unmask_msi_irq,
+ .typename = "AXON-MSI",
+};
+
+static int msic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ set_irq_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq);
+
+ return 0;
+}
+
+static int msic_host_match(struct irq_host *host, struct device_node *dn)
+{
+ struct axon_msic *msic = host->host_data;
+
+ return msic->dn == dn;
+}
+
+static struct irq_host_ops msic_host_ops = {
+ .match = msic_host_match,
+ .map = msic_host_map,
+};
+
+static int axon_msi_notify_reboot(struct notifier_block *nb,
+ unsigned long code, void *data)
+{
+ struct axon_msic *msic;
+ u32 tmp;
+
+ list_for_each_entry(msic, &axon_msic_list, list) {
+ pr_debug("axon_msi: disabling %s\n", msic->dn->full_name);
+ tmp = msic_dcr_read(msic, MSIC_CTRL_REG);
+ tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
+ msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
+ }
+
+ return 0;
+}
+
+static struct notifier_block axon_msi_reboot_notifier = {
+ .notifier_call = axon_msi_notify_reboot
+};
+
+static int axon_msi_setup_one(struct device_node *dn)
+{
+ struct page *page;
+ struct axon_msic *msic;
+ unsigned int virq;
+ int dcr_len;
+
+ pr_debug("axon_msi: setting up dn %s\n", dn->full_name);
+
+ msic = kzalloc(sizeof(struct axon_msic), GFP_KERNEL);
+ if (!msic) {
+ printk(KERN_ERR "axon_msi: couldn't allocate msic for %s\n",
+ dn->full_name);
+ goto out;
+ }
+
+ msic->dcr_base = dcr_resource_start(dn, 0);
+ dcr_len = dcr_resource_len(dn, 0);
+
+ if (msic->dcr_base == 0 || dcr_len == 0) {
+ printk(KERN_ERR
+ "axon_msi: couldn't parse dcr properties on %s\n",
+ dn->full_name);
+ goto out;
+ }
+
+ msic->dcr_host = dcr_map(dn, msic->dcr_base, dcr_len);
+ if (!DCR_MAP_OK(msic->dcr_host)) {
+ printk(KERN_ERR "axon_msi: dcr_map failed for %s\n",
+ dn->full_name);
+ goto out_free_msic;
+ }
+
+ page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
+ get_order(MSIC_FIFO_SIZE_BYTES));
+ if (!page) {
+ printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
+ dn->full_name);
+ goto out_free_msic;
+ }
+
+ msic->fifo = page_address(page);
+
+ msic->irq_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, NR_IRQS,
+ &msic_host_ops, 0);
+ if (!msic->irq_host) {
+ printk(KERN_ERR "axon_msi: couldn't allocate irq_host for %s\n",
+ dn->full_name);
+ goto out_free_fifo;
+ }
+
+ msic->irq_host->host_data = msic;
+
+ virq = irq_of_parse_and_map(dn, 0);
+ if (virq == NO_IRQ) {
+ printk(KERN_ERR "axon_msi: irq parse and map failed for %s\n",
+ dn->full_name);
+ goto out_free_host;
+ }
+
+ msic->dn = of_node_get(dn);
+
+ set_irq_data(virq, msic);
+ set_irq_chained_handler(virq, axon_msi_cascade);
+ pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
+
+ /* Enable the MSIC hardware */
+ msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
+ msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
+ (u64)msic->fifo & 0xFFFFFFFF);
+ msic_dcr_write(msic, MSIC_CTRL_REG,
+ MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
+ MSIC_CTRL_FIFO_SIZE);
+
+ list_add(&msic->list, &axon_msic_list);
+
+ printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
+
+ return 0;
+
+out_free_host:
+ kfree(msic->irq_host);
+out_free_fifo:
+ __free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
+out_free_msic:
+ kfree(msic);
+out:
+
+ return -1;
+}
+
+static int axon_msi_init(void)
+{
+ struct device_node *dn;
+ int found = 0;
+
+ pr_debug("axon_msi: initialising ...\n");
+
+ for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
+ if (axon_msi_setup_one(dn) == 0)
+ found++;
+ }
+
+ if (found) {
+ ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
+ ppc_md.msi_check_device = axon_msi_check_device;
+
+ register_reboot_notifier(&axon_msi_reboot_notifier);
+
+ pr_debug("axon_msi: registered callbacks!\n");
+ }
+
+ return 0;
+}
+arch_initcall(axon_msi_init);
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index ab511d5b65a4..0b6e8ee85ab1 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -1,7 +1,7 @@
/*
* cpufreq driver for the cell processor
*
- * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
*
* Author: Christian Krafft <krafft@de.ibm.com>
*
@@ -21,18 +21,11 @@
*/
#include <linux/cpufreq.h>
-#include <linux/timer.h>
-
-#include <asm/hw_irq.h>
-#include <asm/io.h>
#include <asm/machdep.h>
-#include <asm/processor.h>
-#include <asm/prom.h>
-#include <asm/time.h>
-#include <asm/pmi.h>
#include <asm/of_platform.h>
-
+#include <asm/prom.h>
#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
static DEFINE_MUTEX(cbe_switch_mutex);
@@ -50,159 +43,24 @@ static struct cpufreq_frequency_table cbe_freqs[] = {
{0, CPUFREQ_TABLE_END},
};
-/* to write to MIC register */
-static u64 MIC_Slow_Fast_Timer_table[] = {
- [0 ... 7] = 0x007fc00000000000ull,
-};
-
-/* more values for the MIC */
-static u64 MIC_Slow_Next_Timer_table[] = {
- 0x0000240000000000ull,
- 0x0000268000000000ull,
- 0x000029C000000000ull,
- 0x00002D0000000000ull,
- 0x0000300000000000ull,
- 0x0000334000000000ull,
- 0x000039C000000000ull,
- 0x00003FC000000000ull,
-};
-
-static unsigned int pmi_frequency_limit = 0;
/*
* hardware specific functions
*/
-static struct of_device *pmi_dev;
-
-#ifdef CONFIG_PPC_PMI
-static int set_pmode_pmi(int cpu, unsigned int pmode)
-{
- int ret;
- pmi_message_t pmi_msg;
-#ifdef DEBUG
- u64 time;
-#endif
-
- pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
- pmi_msg.data1 = cbe_cpu_to_node(cpu);
- pmi_msg.data2 = pmode;
-
-#ifdef DEBUG
- time = (u64) get_cycles();
-#endif
-
- pmi_send_message(pmi_dev, pmi_msg);
- ret = pmi_msg.data2;
-
- pr_debug("PMI returned slow mode %d\n", ret);
-
-#ifdef DEBUG
- time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
- time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
- pr_debug("had to wait %lu ns for a transition\n", time);
-#endif
- return ret;
-}
-#endif
-
-static int get_pmode(int cpu)
+static int set_pmode(unsigned int cpu, unsigned int slow_mode)
{
- int ret;
- struct cbe_pmd_regs __iomem *pmd_regs;
-
- pmd_regs = cbe_get_cpu_pmd_regs(cpu);
- ret = in_be64(&pmd_regs->pmsr) & 0x07;
-
- return ret;
-}
-
-static int set_pmode_reg(int cpu, unsigned int pmode)
-{
- struct cbe_pmd_regs __iomem *pmd_regs;
- struct cbe_mic_tm_regs __iomem *mic_tm_regs;
- u64 flags;
- u64 value;
-
- local_irq_save(flags);
-
- mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
- pmd_regs = cbe_get_cpu_pmd_regs(cpu);
-
- pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr);
- pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0);
-
- out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
- out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
-
- out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
- out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
-
- value = in_be64(&pmd_regs->pmcr);
- /* set bits to zero */
- value &= 0xFFFFFFFFFFFFFFF8ull;
- /* set bits to next pmode */
- value |= pmode;
-
- out_be64(&pmd_regs->pmcr, value);
-
- /* wait until new pmode appears in status register */
- value = in_be64(&pmd_regs->pmsr) & 0x07;
- while(value != pmode) {
- cpu_relax();
- value = in_be64(&pmd_regs->pmsr) & 0x07;
- }
-
- local_irq_restore(flags);
-
- return 0;
-}
+ int rc;
-static int set_pmode(int cpu, unsigned int slow_mode) {
-#ifdef CONFIG_PPC_PMI
- if (pmi_dev)
- return set_pmode_pmi(cpu, slow_mode);
+ if (cbe_cpufreq_has_pmi)
+ rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
else
-#endif
- return set_pmode_reg(cpu, slow_mode);
-}
-
-static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
-{
- u8 cpu;
- u8 cbe_pmode_new;
-
- BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+ rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
- cpu = cbe_node_to_cpu(pmi_msg.data1);
- cbe_pmode_new = pmi_msg.data2;
+ pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
- pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency;
-
- pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit);
-}
-
-static int pmi_notifier(struct notifier_block *nb,
- unsigned long event, void *data)
-{
- struct cpufreq_policy *policy = data;
-
- if (event != CPUFREQ_INCOMPATIBLE)
- return 0;
-
- cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit);
- return 0;
+ return rc;
}
-static struct notifier_block pmi_notifier_block = {
- .notifier_call = pmi_notifier,
-};
-
-static struct pmi_handler cbe_pmi_handler = {
- .type = PMI_TYPE_FREQ_CHANGE,
- .handle_pmi_message = cbe_cpufreq_handle_pmi,
-};
-
-
/*
* cpufreq functions
*/
@@ -221,8 +79,19 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("init cpufreq on CPU %d\n", policy->cpu);
+ /*
+ * Let's check we can actually get to the CELL regs
+ */
+ if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
+ !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
+ pr_info("invalid CBE regs pointers for cpufreq\n");
+ return -EINVAL;
+ }
+
max_freqp = of_get_property(cpu, "clock-frequency", NULL);
+ of_node_put(cpu);
+
if (!max_freqp)
return -EINVAL;
@@ -239,10 +108,12 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
}
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- /* if DEBUG is enabled set_pmode() measures the correct latency of a transition */
+
+ /* if DEBUG is enabled set_pmode() measures the latency
+ * of a transition */
policy->cpuinfo.transition_latency = 25000;
- cur_pmode = get_pmode(policy->cpu);
+ cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
pr_debug("current pmode is at %d\n",cur_pmode);
policy->cur = cbe_freqs[cur_pmode].frequency;
@@ -253,21 +124,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu);
- if (pmi_dev) {
- /* frequency might get limited later, initialize limit with max_freq */
- pmi_frequency_limit = max_freq;
- cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
- }
-
- /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */
+ /* this ensures that policy->cpuinfo_min
+ * and policy->cpuinfo_max are set correctly */
return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs);
}
static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
- if (pmi_dev)
- cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
-
cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
@@ -277,13 +140,13 @@ static int cbe_cpufreq_verify(struct cpufreq_policy *policy)
return cpufreq_frequency_table_verify(policy, cbe_freqs);
}
-
-static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq,
- unsigned int relation)
+static int cbe_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
int rc;
struct cpufreq_freqs freqs;
- int cbe_pmode_new;
+ unsigned int cbe_pmode_new;
cpufreq_frequency_table_target(policy,
cbe_freqs,
@@ -298,12 +161,14 @@ static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target
mutex_lock(&cbe_switch_mutex);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n",
+ pr_debug("setting frequency for cpu %d to %d kHz, " \
+ "1/%d of max frequency\n",
policy->cpu,
cbe_freqs[cbe_pmode_new].frequency,
cbe_freqs[cbe_pmode_new].index);
rc = set_pmode(policy->cpu, cbe_pmode_new);
+
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
mutex_unlock(&cbe_switch_mutex);
@@ -326,28 +191,14 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
static int __init cbe_cpufreq_init(void)
{
-#ifdef CONFIG_PPC_PMI
- struct device_node *np;
-#endif
if (!machine_is(cell))
return -ENODEV;
-#ifdef CONFIG_PPC_PMI
- np = of_find_node_by_type(NULL, "ibm,pmi");
-
- pmi_dev = of_find_device_by_node(np);
- if (pmi_dev)
- pmi_register_handler(pmi_dev, &cbe_pmi_handler);
-#endif
return cpufreq_register_driver(&cbe_cpufreq_driver);
}
static void __exit cbe_cpufreq_exit(void)
{
-#ifdef CONFIG_PPC_PMI
- if (pmi_dev)
- pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
-#endif
cpufreq_unregister_driver(&cbe_cpufreq_driver);
}
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.h b/arch/powerpc/platforms/cell/cbe_cpufreq.h
new file mode 100644
index 000000000000..c1d86bfa92ff
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.h
@@ -0,0 +1,24 @@
+/*
+ * cbe_cpufreq.h
+ *
+ * This file contains the definitions used by the cbe_cpufreq driver.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/types.h>
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode);
+int cbe_cpufreq_get_pmode(int cpu);
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode);
+
+#if defined(CONFIG_CBE_CPUFREQ_PMI) || defined(CONFIG_CBE_CPUFREQ_PMI_MODULE)
+extern bool cbe_cpufreq_has_pmi;
+#else
+#define cbe_cpufreq_has_pmi (0)
+#endif
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
new file mode 100644
index 000000000000..163263b3e1cd
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pervasive.c
@@ -0,0 +1,115 @@
+/*
+ * pervasive backend for the cbe_cpufreq driver
+ *
+ * This driver makes use of the pervasive unit to
+ * engage the desired frequency.
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <asm/machdep.h>
+#include <asm/hw_irq.h>
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+/* to write to MIC register */
+static u64 MIC_Slow_Fast_Timer_table[] = {
+ [0 ... 7] = 0x007fc00000000000ull,
+};
+
+/* more values for the MIC */
+static u64 MIC_Slow_Next_Timer_table[] = {
+ 0x0000240000000000ull,
+ 0x0000268000000000ull,
+ 0x000029C000000000ull,
+ 0x00002D0000000000ull,
+ 0x0000300000000000ull,
+ 0x0000334000000000ull,
+ 0x000039C000000000ull,
+ 0x00003FC000000000ull,
+};
+
+
+int cbe_cpufreq_set_pmode(int cpu, unsigned int pmode)
+{
+ struct cbe_pmd_regs __iomem *pmd_regs;
+ struct cbe_mic_tm_regs __iomem *mic_tm_regs;
+ u64 flags;
+ u64 value;
+#ifdef DEBUG
+ long time;
+#endif
+
+ local_irq_save(flags);
+
+ mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu);
+ pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+
+#ifdef DEBUG
+ time = jiffies;
+#endif
+
+ out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]);
+ out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]);
+
+ out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]);
+ out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]);
+
+ value = in_be64(&pmd_regs->pmcr);
+ /* set bits to zero */
+ value &= 0xFFFFFFFFFFFFFFF8ull;
+ /* set bits to next pmode */
+ value |= pmode;
+
+ out_be64(&pmd_regs->pmcr, value);
+
+#ifdef DEBUG
+ /* wait until new pmode appears in status register */
+ value = in_be64(&pmd_regs->pmsr) & 0x07;
+ while (value != pmode) {
+ cpu_relax();
+ value = in_be64(&pmd_regs->pmsr) & 0x07;
+ }
+
+ time = jiffies - time;
+ time = jiffies_to_msecs(time);
+ pr_debug("had to wait %lu ms for a transition using " \
+ "pervasive unit\n", time);
+#endif
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+
+int cbe_cpufreq_get_pmode(int cpu)
+{
+ int ret;
+ struct cbe_pmd_regs __iomem *pmd_regs;
+
+ pmd_regs = cbe_get_cpu_pmd_regs(cpu);
+ ret = in_be64(&pmd_regs->pmsr) & 0x07;
+
+ return ret;
+}
+
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
new file mode 100644
index 000000000000..fc6f38982ff4
--- /dev/null
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c
@@ -0,0 +1,148 @@
+/*
+ * pmi backend for the cbe_cpufreq driver
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
+ *
+ * Author: Christian Krafft <krafft@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <asm/of_platform.h>
+#include <asm/processor.h>
+#include <asm/prom.h>
+#include <asm/pmi.h>
+
+#ifdef DEBUG
+#include <asm/time.h>
+#endif
+
+#include "cbe_regs.h"
+#include "cbe_cpufreq.h"
+
+static u8 pmi_slow_mode_limit[MAX_CBE];
+
+bool cbe_cpufreq_has_pmi = false;
+EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);
+
+/*
+ * hardware specific functions
+ */
+
+int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)
+{
+ int ret;
+ pmi_message_t pmi_msg;
+#ifdef DEBUG
+ long time;
+#endif
+ pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
+ pmi_msg.data1 = cbe_cpu_to_node(cpu);
+ pmi_msg.data2 = pmode;
+
+#ifdef DEBUG
+ time = jiffies;
+#endif
+ pmi_send_message(pmi_msg);
+
+#ifdef DEBUG
+ time = jiffies - time;
+ time = jiffies_to_msecs(time);
+ pr_debug("had to wait %lu ms for a transition using " \
+ "PMI\n", time);
+#endif
+ ret = pmi_msg.data2;
+ pr_debug("PMI returned slow mode %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);
+
+
+static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)
+{
+ u8 node, slow_mode;
+
+ BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
+
+ node = pmi_msg.data1;
+ slow_mode = pmi_msg.data2;
+
+ pmi_slow_mode_limit[node] = slow_mode;
+
+ pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);
+}
+
+static int pmi_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct cpufreq_policy *policy = data;
+ struct cpufreq_frequency_table *cbe_freqs;
+ u8 node;
+
+ cbe_freqs = cpufreq_frequency_get_table(policy->cpu);
+ node = cbe_cpu_to_node(policy->cpu);
+
+ pr_debug("got notified, event=%lu, node=%u\n", event, node);
+
+ if (pmi_slow_mode_limit[node] != 0) {
+ pr_debug("limiting node %d to slow mode %d\n",
+ node, pmi_slow_mode_limit[node]);
+
+ cpufreq_verify_within_limits(policy, 0,
+
+ cbe_freqs[pmi_slow_mode_limit[node]].frequency);
+ }
+
+ return 0;
+}
+
+static struct notifier_block pmi_notifier_block = {
+ .notifier_call = pmi_notifier,
+};
+
+static struct pmi_handler cbe_pmi_handler = {
+ .type = PMI_TYPE_FREQ_CHANGE,
+ .handle_pmi_message = cbe_cpufreq_handle_pmi,
+};
+
+
+
+static int __init cbe_cpufreq_pmi_init(void)
+{
+ cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0;
+
+ if (!cbe_cpufreq_has_pmi)
+ return -ENODEV;
+
+ cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+
+ return 0;
+}
+
+static void __exit cbe_cpufreq_pmi_exit(void)
+{
+ cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+ pmi_unregister_handler(&cbe_pmi_handler);
+}
+
+module_init(cbe_cpufreq_pmi_init);
+module_exit(cbe_cpufreq_pmi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 12c9674b4b1f..c8f7f0007422 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -174,6 +174,13 @@ static struct device_node *cbe_get_be_node(int cpu_id)
cpu_handle = of_get_property(np, "cpus", &len);
+ /*
+ * the CAB SLOF tree is non compliant, so we just assume
+ * there is only one node
+ */
+ if (WARN_ON_ONCE(!cpu_handle))
+ return np;
+
for (i=0; i<len; i++)
if (of_find_node_by_phandle(cpu_handle[i]) == of_get_cpu_node(cpu_id, NULL))
return np;
diff --git a/arch/powerpc/platforms/cell/cbe_thermal.c b/arch/powerpc/platforms/cell/cbe_thermal.c
index f370f0fa6f4c..e4132f8f51b3 100644
--- a/arch/powerpc/platforms/cell/cbe_thermal.c
+++ b/arch/powerpc/platforms/cell/cbe_thermal.c
@@ -292,7 +292,7 @@ static struct attribute_group ppe_attribute_group = {
/*
* initialize throttling with default values
*/
-static void __init init_default_values(void)
+static int __init init_default_values(void)
{
int cpu;
struct cbe_pmd_regs __iomem *pmd_regs;
@@ -339,25 +339,40 @@ static void __init init_default_values(void)
for_each_possible_cpu (cpu) {
pr_debug("processing cpu %d\n", cpu);
sysdev = get_cpu_sysdev(cpu);
+
+ if (!sysdev) {
+ pr_info("invalid sysdev pointer for cbe_thermal\n");
+ return -EINVAL;
+ }
+
pmd_regs = cbe_get_cpu_pmd_regs(sysdev->id);
+ if (!pmd_regs) {
+ pr_info("invalid CBE regs pointer for cbe_thermal\n");
+ return -EINVAL;
+ }
+
out_be64(&pmd_regs->tm_str2, str2);
out_be64(&pmd_regs->tm_str1.val, str1.val);
out_be64(&pmd_regs->tm_tpr.val, tpr.val);
out_be64(&pmd_regs->tm_cr1.val, cr1.val);
out_be64(&pmd_regs->tm_cr2, cr2);
}
+
+ return 0;
}
static int __init thermal_init(void)
{
- init_default_values();
+ int rc = init_default_values();
- spu_add_sysdev_attr_group(&spu_attribute_group);
- cpu_add_sysdev_attr_group(&ppe_attribute_group);
+ if (rc == 0) {
+ spu_add_sysdev_attr_group(&spu_attribute_group);
+ cpu_add_sysdev_attr_group(&ppe_attribute_group);
+ }
- return 0;
+ return rc;
}
module_init(thermal_init);
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c
index 7fb92f23f380..9d7c2ef940a8 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/platforms/cell/io-workarounds.c
@@ -102,7 +102,7 @@ static void spider_io_flush(const volatile void __iomem *addr)
vaddr = (unsigned long)PCI_FIX_ADDR(addr);
/* Check if it's in allowed range for PIO */
- if (vaddr < PHBS_IO_BASE || vaddr >= IMALLOC_BASE)
+ if (vaddr < PHB_IO_BASE || vaddr > PHB_IO_END)
return;
/* Try to find a PTE. If not, clear the paddr, we'll do
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index a7f5a7653c62..90124228b8f4 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -31,21 +31,41 @@
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/mutex.h>
+#include <linux/linux_logo.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/xmon.h>
+#include <asm/prom.h>
+#include "spu_priv1_mmio.h"
const struct spu_management_ops *spu_management_ops;
EXPORT_SYMBOL_GPL(spu_management_ops);
const struct spu_priv1_ops *spu_priv1_ops;
+EXPORT_SYMBOL_GPL(spu_priv1_ops);
-static struct list_head spu_list[MAX_NUMNODES];
-static LIST_HEAD(spu_full_list);
-static DEFINE_MUTEX(spu_mutex);
-static DEFINE_SPINLOCK(spu_list_lock);
+struct cbe_spu_info cbe_spu_info[MAX_NUMNODES];
+EXPORT_SYMBOL_GPL(cbe_spu_info);
-EXPORT_SYMBOL_GPL(spu_priv1_ops);
+/*
+ * Protects cbe_spu_info and spu->number.
+ */
+static DEFINE_SPINLOCK(spu_lock);
+
+/*
+ * List of all spus in the system.
+ *
+ * This list is iterated by callers from irq context and callers that
+ * want to sleep. Thus modifications need to be done with both
+ * spu_full_list_lock and spu_full_list_mutex held, while iterating
+ * through it requires either of these locks.
+ *
+ * In addition spu_full_list_lock protects all assignmens to
+ * spu->mm.
+ */
+static LIST_HEAD(spu_full_list);
+static DEFINE_SPINLOCK(spu_full_list_lock);
+static DEFINE_MUTEX(spu_full_list_mutex);
void spu_invalidate_slbs(struct spu *spu)
{
@@ -64,12 +84,12 @@ void spu_flush_all_slbs(struct mm_struct *mm)
struct spu *spu;
unsigned long flags;
- spin_lock_irqsave(&spu_list_lock, flags);
+ spin_lock_irqsave(&spu_full_list_lock, flags);
list_for_each_entry(spu, &spu_full_list, full_list) {
if (spu->mm == mm)
spu_invalidate_slbs(spu);
}
- spin_unlock_irqrestore(&spu_list_lock, flags);
+ spin_unlock_irqrestore(&spu_full_list_lock, flags);
}
/* The hack below stinks... try to do something better one of
@@ -87,9 +107,9 @@ void spu_associate_mm(struct spu *spu, struct mm_struct *mm)
{
unsigned long flags;
- spin_lock_irqsave(&spu_list_lock, flags);
+ spin_lock_irqsave(&spu_full_list_lock, flags);
spu->mm = mm;
- spin_unlock_irqrestore(&spu_list_lock, flags);
+ spin_unlock_irqrestore(&spu_full_list_lock, flags);
if (mm)
mm_needs_global_tlbie(mm);
}
@@ -183,7 +203,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
spu->slb_replace = 0;
spu_restart_dma(spu);
-
+ spu->stats.slb_flt++;
return 0;
}
@@ -332,6 +352,7 @@ spu_irq_class_2(int irq, void *data)
if (stat & 0x10) /* SPU mailbox threshold */
spu->wbox_callback(spu);
+ spu->stats.class2_intr++;
return stat ? IRQ_HANDLED : IRQ_NONE;
}
@@ -388,7 +409,7 @@ static void spu_free_irqs(struct spu *spu)
free_irq(spu->irqs[2], spu);
}
-static void spu_init_channels(struct spu *spu)
+void spu_init_channels(struct spu *spu)
{
static const struct {
unsigned channel;
@@ -421,60 +442,31 @@ static void spu_init_channels(struct spu *spu)
out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count);
}
}
+EXPORT_SYMBOL_GPL(spu_init_channels);
-struct spu *spu_alloc_node(int node)
+static int spu_shutdown(struct sys_device *sysdev)
{
- struct spu *spu = NULL;
-
- mutex_lock(&spu_mutex);
- if (!list_empty(&spu_list[node])) {
- spu = list_entry(spu_list[node].next, struct spu, list);
- list_del_init(&spu->list);
- pr_debug("Got SPU %d %d\n", spu->number, spu->node);
- }
- mutex_unlock(&spu_mutex);
-
- if (spu)
- spu_init_channels(spu);
- return spu;
-}
-EXPORT_SYMBOL_GPL(spu_alloc_node);
-
-struct spu *spu_alloc(void)
-{
- struct spu *spu = NULL;
- int node;
-
- for (node = 0; node < MAX_NUMNODES; node++) {
- spu = spu_alloc_node(node);
- if (spu)
- break;
- }
-
- return spu;
-}
+ struct spu *spu = container_of(sysdev, struct spu, sysdev);
-void spu_free(struct spu *spu)
-{
- mutex_lock(&spu_mutex);
- list_add_tail(&spu->list, &spu_list[spu->node]);
- mutex_unlock(&spu_mutex);
+ spu_free_irqs(spu);
+ spu_destroy_spu(spu);
+ return 0;
}
-EXPORT_SYMBOL_GPL(spu_free);
struct sysdev_class spu_sysdev_class = {
- set_kset_name("spu")
+ set_kset_name("spu"),
+ .shutdown = spu_shutdown,
};
int spu_add_sysdev_attr(struct sysdev_attribute *attr)
{
struct spu *spu;
- mutex_lock(&spu_mutex);
+ mutex_lock(&spu_full_list_mutex);
list_for_each_entry(spu, &spu_full_list, full_list)
sysdev_create_file(&spu->sysdev, attr);
+ mutex_unlock(&spu_full_list_mutex);
- mutex_unlock(&spu_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
@@ -482,12 +474,12 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);
int spu_add_sysdev_attr_group(struct attribute_group *attrs)
{
struct spu *spu;
- mutex_lock(&spu_mutex);
+ mutex_lock(&spu_full_list_mutex);
list_for_each_entry(spu, &spu_full_list, full_list)
sysfs_create_group(&spu->sysdev.kobj, attrs);
+ mutex_unlock(&spu_full_list_mutex);
- mutex_unlock(&spu_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
@@ -496,24 +488,22 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);
void spu_remove_sysdev_attr(struct sysdev_attribute *attr)
{
struct spu *spu;
- mutex_lock(&spu_mutex);
+ mutex_lock(&spu_full_list_mutex);
list_for_each_entry(spu, &spu_full_list, full_list)
sysdev_remove_file(&spu->sysdev, attr);
-
- mutex_unlock(&spu_mutex);
+ mutex_unlock(&spu_full_list_mutex);
}
EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);
void spu_remove_sysdev_attr_group(struct attribute_group *attrs)
{
struct spu *spu;
- mutex_lock(&spu_mutex);
+ mutex_lock(&spu_full_list_mutex);
list_for_each_entry(spu, &spu_full_list, full_list)
sysfs_remove_group(&spu->sysdev.kobj, attrs);
-
- mutex_unlock(&spu_mutex);
+ mutex_unlock(&spu_full_list_mutex);
}
EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);
@@ -541,16 +531,19 @@ static int __init create_spu(void *data)
int ret;
static int number;
unsigned long flags;
+ struct timespec ts;
ret = -ENOMEM;
spu = kzalloc(sizeof (*spu), GFP_KERNEL);
if (!spu)
goto out;
+ spu->alloc_state = SPU_FREE;
+
spin_lock_init(&spu->register_lock);
- mutex_lock(&spu_mutex);
+ spin_lock(&spu_lock);
spu->number = number++;
- mutex_unlock(&spu_mutex);
+ spin_unlock(&spu_lock);
ret = spu_create_spu(spu, data);
@@ -567,12 +560,22 @@ static int __init create_spu(void *data)
if (ret)
goto out_free_irqs;
- mutex_lock(&spu_mutex);
- spin_lock_irqsave(&spu_list_lock, flags);
- list_add(&spu->list, &spu_list[spu->node]);
+ mutex_lock(&cbe_spu_info[spu->node].list_mutex);
+ list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus);
+ cbe_spu_info[spu->node].n_spus++;
+ mutex_unlock(&cbe_spu_info[spu->node].list_mutex);
+
+ mutex_lock(&spu_full_list_mutex);
+ spin_lock_irqsave(&spu_full_list_lock, flags);
list_add(&spu->full_list, &spu_full_list);
- spin_unlock_irqrestore(&spu_list_lock, flags);
- mutex_unlock(&spu_mutex);
+ spin_unlock_irqrestore(&spu_full_list_lock, flags);
+ mutex_unlock(&spu_full_list_mutex);
+
+ spu->stats.util_state = SPU_UTIL_IDLE_LOADED;
+ ktime_get_ts(&ts);
+ spu->stats.tstamp = timespec_to_ns(&ts);
+
+ INIT_LIST_HEAD(&spu->aff_list);
goto out;
@@ -586,12 +589,193 @@ out:
return ret;
}
+static const char *spu_state_names[] = {
+ "user", "system", "iowait", "idle"
+};
+
+static unsigned long long spu_acct_time(struct spu *spu,
+ enum spu_utilization_state state)
+{
+ struct timespec ts;
+ unsigned long long time = spu->stats.times[state];
+
+ /*
+ * If the spu is idle or the context is stopped, utilization
+ * statistics are not updated. Apply the time delta from the
+ * last recorded state of the spu.
+ */
+ if (spu->stats.util_state == state) {
+ ktime_get_ts(&ts);
+ time += timespec_to_ns(&ts) - spu->stats.tstamp;
+ }
+
+ return time / NSEC_PER_MSEC;
+}
+
+
+static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf)
+{
+ struct spu *spu = container_of(sysdev, struct spu, sysdev);
+
+ return sprintf(buf, "%s %llu %llu %llu %llu "
+ "%llu %llu %llu %llu %llu %llu %llu %llu\n",
+ spu_state_names[spu->stats.util_state],
+ spu_acct_time(spu, SPU_UTIL_USER),
+ spu_acct_time(spu, SPU_UTIL_SYSTEM),
+ spu_acct_time(spu, SPU_UTIL_IOWAIT),
+ spu_acct_time(spu, SPU_UTIL_IDLE_LOADED),
+ spu->stats.vol_ctx_switch,
+ spu->stats.invol_ctx_switch,
+ spu->stats.slb_flt,
+ spu->stats.hash_flt,
+ spu->stats.min_flt,
+ spu->stats.maj_flt,
+ spu->stats.class2_intr,
+ spu->stats.libassist);
+}
+
+static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);
+
+/* Hardcoded affinity idxs for QS20 */
+#define SPES_PER_BE 8
+static int QS20_reg_idxs[SPES_PER_BE] = { 0, 2, 4, 6, 7, 5, 3, 1 };
+static int QS20_reg_memory[SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 };
+
+static struct spu *spu_lookup_reg(int node, u32 reg)
+{
+ struct spu *spu;
+
+ list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+ if (*(u32 *)get_property(spu_devnode(spu), "reg", NULL) == reg)
+ return spu;
+ }
+ return NULL;
+}
+
+static void init_aff_QS20_harcoded(void)
+{
+ int node, i;
+ struct spu *last_spu, *spu;
+ u32 reg;
+
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ last_spu = NULL;
+ for (i = 0; i < SPES_PER_BE; i++) {
+ reg = QS20_reg_idxs[i];
+ spu = spu_lookup_reg(node, reg);
+ if (!spu)
+ continue;
+ spu->has_mem_affinity = QS20_reg_memory[reg];
+ if (last_spu)
+ list_add_tail(&spu->aff_list,
+ &last_spu->aff_list);
+ last_spu = spu;
+ }
+ }
+}
+
+static int of_has_vicinity(void)
+{
+ struct spu* spu;
+
+ spu = list_entry(cbe_spu_info[0].spus.next, struct spu, cbe_list);
+ return of_find_property(spu_devnode(spu), "vicinity", NULL) != NULL;
+}
+
+static struct spu *aff_devnode_spu(int cbe, struct device_node *dn)
+{
+ struct spu *spu;
+
+ list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list)
+ if (spu_devnode(spu) == dn)
+ return spu;
+ return NULL;
+}
+
+static struct spu *
+aff_node_next_to(int cbe, struct device_node *target, struct device_node *avoid)
+{
+ struct spu *spu;
+ const phandle *vic_handles;
+ int lenp, i;
+
+ list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) {
+ if (spu_devnode(spu) == avoid)
+ continue;
+ vic_handles = get_property(spu_devnode(spu), "vicinity", &lenp);
+ for (i=0; i < (lenp / sizeof(phandle)); i++) {
+ if (vic_handles[i] == target->linux_phandle)
+ return spu;
+ }
+ }
+ return NULL;
+}
+
+static void init_aff_fw_vicinity_node(int cbe)
+{
+ struct spu *spu, *last_spu;
+ struct device_node *vic_dn, *last_spu_dn;
+ phandle avoid_ph;
+ const phandle *vic_handles;
+ const char *name;
+ int lenp, i, added, mem_aff;
+
+ last_spu = list_entry(cbe_spu_info[cbe].spus.next, struct spu, cbe_list);
+ avoid_ph = 0;
+ for (added = 1; added < cbe_spu_info[cbe].n_spus; added++) {
+ last_spu_dn = spu_devnode(last_spu);
+ vic_handles = get_property(last_spu_dn, "vicinity", &lenp);
+
+ for (i = 0; i < (lenp / sizeof(phandle)); i++) {
+ if (vic_handles[i] == avoid_ph)
+ continue;
+
+ vic_dn = of_find_node_by_phandle(vic_handles[i]);
+ if (!vic_dn)
+ continue;
+
+ name = get_property(vic_dn, "name", NULL);
+ if (strcmp(name, "spe") == 0) {
+ spu = aff_devnode_spu(cbe, vic_dn);
+ avoid_ph = last_spu_dn->linux_phandle;
+ }
+ else {
+ mem_aff = strcmp(name, "mic-tm") == 0;
+ spu = aff_node_next_to(cbe, vic_dn, last_spu_dn);
+ if (!spu)
+ continue;
+ if (mem_aff) {
+ last_spu->has_mem_affinity = 1;
+ spu->has_mem_affinity = 1;
+ }
+ avoid_ph = vic_dn->linux_phandle;
+ }
+ list_add_tail(&spu->aff_list, &last_spu->aff_list);
+ last_spu = spu;
+ break;
+ }
+ }
+}
+
+static void init_aff_fw_vicinity(void)
+{
+ int cbe;
+
+ /* sets has_mem_affinity for each spu, as long as the
+ * spu->aff_list list, linking each spu to its neighbors
+ */
+ for (cbe = 0; cbe < MAX_NUMNODES; cbe++)
+ init_aff_fw_vicinity_node(cbe);
+}
+
static int __init init_spu_base(void)
{
int i, ret = 0;
- for (i = 0; i < MAX_NUMNODES; i++)
- INIT_LIST_HEAD(&spu_list[i]);
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ mutex_init(&cbe_spu_info[i].list_mutex);
+ INIT_LIST_HEAD(&cbe_spu_info[i].spus);
+ }
if (!spu_management_ops)
goto out;
@@ -603,20 +787,43 @@ static int __init init_spu_base(void)
ret = spu_enumerate_spus(create_spu);
- if (ret) {
+ if (ret < 0) {
printk(KERN_WARNING "%s: Error initializing spus\n",
__FUNCTION__);
goto out_unregister_sysdev_class;
}
+ if (ret > 0) {
+ /*
+ * We cannot put the forward declaration in
+ * <linux/linux_logo.h> because of conflicting session type
+ * conflicts for const and __initdata with different compiler
+ * versions
+ */
+ extern const struct linux_logo logo_spe_clut224;
+
+ fb_append_extra_logo(&logo_spe_clut224, ret);
+ }
+
+ mutex_lock(&spu_full_list_mutex);
xmon_register_spus(&spu_full_list);
+ crash_register_spus(&spu_full_list);
+ mutex_unlock(&spu_full_list_mutex);
+ spu_add_sysdev_attr(&attr_stat);
+
+ if (of_has_vicinity()) {
+ init_aff_fw_vicinity();
+ } else {
+ long root = of_get_flat_dt_root();
+ if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
+ init_aff_QS20_harcoded();
+ }
return 0;
out_unregister_sysdev_class:
sysdev_class_unregister(&spu_sysdev_class);
out:
-
return ret;
}
module_init(init_spu_base);
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
index 1d4562ae463d..75ed50fcc3db 100644
--- a/arch/powerpc/platforms/cell/spu_manage.c
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -279,6 +279,7 @@ static int __init of_enumerate_spus(int (*fn)(void *data))
{
int ret;
struct device_node *node;
+ unsigned int n = 0;
ret = -ENODEV;
for (node = of_find_node_by_type(NULL, "spe");
@@ -289,8 +290,9 @@ static int __init of_enumerate_spus(int (*fn)(void *data))
__FUNCTION__, node->name);
break;
}
+ n++;
}
- return ret;
+ return ret ? ret : n;
}
static int __init of_create_spu(struct spu *spu, void *data)
diff --git a/arch/powerpc/platforms/cell/spu_syscalls.c b/arch/powerpc/platforms/cell/spu_syscalls.c
index 261b507a901a..dd2c6688c8aa 100644
--- a/arch/powerpc/platforms/cell/spu_syscalls.c
+++ b/arch/powerpc/platforms/cell/spu_syscalls.c
@@ -34,14 +34,27 @@ struct spufs_calls spufs_calls = {
* this file is not used and the syscalls directly enter the fs code */
asmlinkage long sys_spu_create(const char __user *name,
- unsigned int flags, mode_t mode)
+ unsigned int flags, mode_t mode, int neighbor_fd)
{
long ret;
struct module *owner = spufs_calls.owner;
+ struct file *neighbor;
+ int fput_needed;
ret = -ENOSYS;
if (owner && try_module_get(owner)) {
- ret = spufs_calls.create_thread(name, flags, mode);
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ neighbor = fget_light(neighbor_fd, &fput_needed);
+ if (neighbor) {
+ ret = spufs_calls.create_thread(name, flags,
+ mode, neighbor);
+ fput_light(neighbor, fput_needed);
+ }
+ }
+ else {
+ ret = spufs_calls.create_thread(name, flags,
+ mode, NULL);
+ }
module_put(owner);
}
return ret;
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
index d32db9ffc6eb..07a0e815abf5 100644
--- a/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -320,6 +320,12 @@ static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
/* FIXME: what are the side-effects of this? */
prob->dma_querymask_RW = mask;
prob->dma_querytype_RW = mode;
+ /* In the current implementation, the SPU context is always
+ * acquired in runnable state when new bits are added to the
+ * mask (tagwait), so it's sufficient just to mask
+ * dma_tagstatus_R with the 'mask' parameter here.
+ */
+ ctx->csa.prob.dma_tagstatus_R &= mask;
out:
spin_unlock(&ctx->csa.register_lock);
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 7c51cb54bca1..6694f86d7000 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -22,11 +22,16 @@
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/slab.h>
+#include <asm/atomic.h>
#include <asm/spu.h>
#include <asm/spu_csa.h>
#include "spufs.h"
+
+atomic_t nr_spu_contexts = ATOMIC_INIT(0);
+
struct spu_context *alloc_spu_context(struct spu_gang *gang)
{
struct spu_context *ctx;
@@ -51,12 +56,14 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
ctx->ops = &spu_backing_ops;
ctx->owner = get_task_mm(current);
INIT_LIST_HEAD(&ctx->rq);
+ INIT_LIST_HEAD(&ctx->aff_list);
if (gang)
spu_gang_add_ctx(gang, ctx);
- ctx->rt_priority = current->rt_priority;
- ctx->policy = current->policy;
- ctx->prio = current->prio;
- INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick);
+ ctx->cpus_allowed = current->cpus_allowed;
+ spu_set_timeslice(ctx);
+ ctx->stats.util_state = SPU_UTIL_IDLE_LOADED;
+
+ atomic_inc(&nr_spu_contexts);
goto out;
out_free:
kfree(ctx);
@@ -75,7 +82,10 @@ void destroy_spu_context(struct kref *kref)
spu_fini_csa(&ctx->csa);
if (ctx->gang)
spu_gang_remove_ctx(ctx->gang, ctx);
+ if (ctx->prof_priv_kref)
+ kref_put(ctx->prof_priv_kref, ctx->prof_priv_release);
BUG_ON(!list_empty(&ctx->rq));
+ atomic_dec(&nr_spu_contexts);
kfree(ctx);
}
@@ -159,6 +169,39 @@ int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags)
void spu_acquire_saved(struct spu_context *ctx)
{
spu_acquire(ctx);
- if (ctx->state != SPU_STATE_SAVED)
+ if (ctx->state != SPU_STATE_SAVED) {
+ set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags);
spu_deactivate(ctx);
+ }
+}
+
+/**
+ * spu_release_saved - unlock spu context and return it to the runqueue
+ * @ctx: context to unlock
+ */
+void spu_release_saved(struct spu_context *ctx)
+{
+ BUG_ON(ctx->state != SPU_STATE_SAVED);
+
+ if (test_and_clear_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags))
+ spu_activate(ctx, 0);
+
+ spu_release(ctx);
+}
+
+void spu_set_profile_private_kref(struct spu_context *ctx,
+ struct kref *prof_info_kref,
+ void ( * prof_info_release) (struct kref *kref))
+{
+ ctx->prof_priv_kref = prof_info_kref;
+ ctx->prof_priv_release = prof_info_release;
}
+EXPORT_SYMBOL_GPL(spu_set_profile_private_kref);
+
+void *spu_get_profile_private_kref(struct spu_context *ctx)
+{
+ return ctx->prof_priv_kref;
+}
+EXPORT_SYMBOL_GPL(spu_get_profile_private_kref);
+
+
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 5d9ad5a0307b..5e31799b1e3f 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -226,7 +226,7 @@ static void spufs_arch_write_notes(struct file *file)
spu_acquire_saved(ctx_info->ctx);
for (j = 0; j < spufs_coredump_num_notes; j++)
spufs_arch_write_note(ctx_info, j, file);
- spu_release(ctx_info->ctx);
+ spu_release_saved(ctx_info->ctx);
list_del(&ctx_info->list);
kfree(ctx_info);
}
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c
index 0f75c07e29d8..917eab4be486 100644
--- a/arch/powerpc/platforms/cell/spufs/fault.c
+++ b/arch/powerpc/platforms/cell/spufs/fault.c
@@ -33,7 +33,8 @@
* function. Currently, there are a few corner cases that we haven't had
* to handle fortunately.
*/
-static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, unsigned long dsisr)
+static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
+ unsigned long dsisr, unsigned *flt)
{
struct vm_area_struct *vma;
unsigned long is_write;
@@ -73,22 +74,21 @@ good_area:
goto bad_area;
}
ret = 0;
- switch (handle_mm_fault(mm, vma, ea, is_write)) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- ret = -EFAULT;
- goto bad_area;
- case VM_FAULT_OOM:
- ret = -ENOMEM;
- goto bad_area;
- default:
+ *flt = handle_mm_fault(mm, vma, ea, is_write);
+ if (unlikely(*flt & VM_FAULT_ERROR)) {
+ if (*flt & VM_FAULT_OOM) {
+ ret = -ENOMEM;
+ goto bad_area;
+ } else if (*flt & VM_FAULT_SIGBUS) {
+ ret = -EFAULT;
+ goto bad_area;
+ }
BUG();
}
+ if (*flt & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
return ret;
@@ -153,6 +153,7 @@ int spufs_handle_class1(struct spu_context *ctx)
{
u64 ea, dsisr, access;
unsigned long flags;
+ unsigned flt = 0;
int ret;
/*
@@ -178,9 +179,15 @@ int spufs_handle_class1(struct spu_context *ctx)
if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)))
return 0;
+ spuctx_switch_state(ctx, SPU_UTIL_IOWAIT);
+
pr_debug("ctx %p: ea %016lx, dsisr %016lx state %d\n", ctx, ea,
dsisr, ctx->state);
+ ctx->stats.hash_flt++;
+ if (ctx->state == SPU_STATE_RUNNABLE)
+ ctx->spu->stats.hash_flt++;
+
/* we must not hold the lock when entering spu_handle_mm_fault */
spu_release(ctx);
@@ -192,7 +199,7 @@ int spufs_handle_class1(struct spu_context *ctx)
/* hashing failed, so try the actual fault handler */
if (ret)
- ret = spu_handle_mm_fault(current->mm, ea, dsisr);
+ ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt);
spu_acquire(ctx);
/*
@@ -201,11 +208,23 @@ int spufs_handle_class1(struct spu_context *ctx)
* In case of unhandled error report the problem to user space.
*/
if (!ret) {
+ if (flt & VM_FAULT_MAJOR)
+ ctx->stats.maj_flt++;
+ else
+ ctx->stats.min_flt++;
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ if (flt & VM_FAULT_MAJOR)
+ ctx->spu->stats.maj_flt++;
+ else
+ ctx->spu->stats.min_flt++;
+ }
+
if (ctx->spu)
ctx->ops->restart_dma(ctx);
} else
spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE);
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
return ret;
}
EXPORT_SYMBOL_GPL(spufs_handle_class1);
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index b1e7e2f8a2e9..4100ddc52f02 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -28,6 +28,7 @@
#include <linux/pagemap.h>
#include <linux/poll.h>
#include <linux/ptrace.h>
+#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/semaphore.h>
@@ -39,6 +40,7 @@
#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
+
static int
spufs_mem_open(struct inode *inode, struct file *file)
{
@@ -216,12 +218,12 @@ unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr,
#endif /* CONFIG_SPU_FS_64K_LS */
static const struct file_operations spufs_mem_fops = {
- .open = spufs_mem_open,
- .release = spufs_mem_release,
- .read = spufs_mem_read,
- .write = spufs_mem_write,
- .llseek = generic_file_llseek,
- .mmap = spufs_mem_mmap,
+ .open = spufs_mem_open,
+ .release = spufs_mem_release,
+ .read = spufs_mem_read,
+ .write = spufs_mem_write,
+ .llseek = generic_file_llseek,
+ .mmap = spufs_mem_mmap,
#ifdef CONFIG_SPU_FS_64K_LS
.get_unmapped_area = spufs_get_unmapped_area,
#endif
@@ -368,7 +370,7 @@ spufs_regs_read(struct file *file, char __user *buffer,
spu_acquire_saved(ctx);
ret = __spufs_regs_read(ctx, buffer, size, pos);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -390,7 +392,7 @@ spufs_regs_write(struct file *file, const char __user *buffer,
ret = copy_from_user(lscsa->gprs + *pos - size,
buffer, size) ? -EFAULT : size;
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -419,7 +421,7 @@ spufs_fpcr_read(struct file *file, char __user * buffer,
spu_acquire_saved(ctx);
ret = __spufs_fpcr_read(ctx, buffer, size, pos);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -441,7 +443,7 @@ spufs_fpcr_write(struct file *file, const char __user * buffer,
ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
buffer, size) ? -EFAULT : size;
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -866,7 +868,7 @@ static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
spu_acquire_saved(ctx);
ret = __spufs_signal1_read(ctx, buf, len, pos);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -932,6 +934,13 @@ static const struct file_operations spufs_signal1_fops = {
.mmap = spufs_signal1_mmap,
};
+static const struct file_operations spufs_signal1_nosched_fops = {
+ .open = spufs_signal1_open,
+ .release = spufs_signal1_release,
+ .write = spufs_signal1_write,
+ .mmap = spufs_signal1_mmap,
+};
+
static int spufs_signal2_open(struct inode *inode, struct file *file)
{
struct spufs_inode_info *i = SPUFS_I(inode);
@@ -990,7 +999,7 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
spu_acquire_saved(ctx);
ret = __spufs_signal2_read(ctx, buf, len, pos);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -1060,6 +1069,13 @@ static const struct file_operations spufs_signal2_fops = {
.mmap = spufs_signal2_mmap,
};
+static const struct file_operations spufs_signal2_nosched_fops = {
+ .open = spufs_signal2_open,
+ .release = spufs_signal2_release,
+ .write = spufs_signal2_write,
+ .mmap = spufs_signal2_mmap,
+};
+
static void spufs_signal1_type_set(void *data, u64 val)
{
struct spu_context *ctx = data;
@@ -1497,14 +1513,15 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
if (status)
ret = status;
}
- spu_release(ctx);
if (ret)
- goto out;
+ goto out_unlock;
ctx->tagwait |= 1 << cmd.tag;
ret = size;
+out_unlock:
+ spu_release(ctx);
out:
return ret;
}
@@ -1515,14 +1532,14 @@ static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
u32 free_elements, tagstatus;
unsigned int mask;
+ poll_wait(file, &ctx->mfc_wq, wait);
+
spu_acquire(ctx);
ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
free_elements = ctx->ops->get_mfc_free_elements(ctx);
tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
spu_release(ctx);
- poll_wait(file, &ctx->mfc_wq, wait);
-
mask = 0;
if (free_elements & 0xffff)
mask |= POLLOUT | POLLWRNORM;
@@ -1609,7 +1626,7 @@ static void spufs_decr_set(void *data, u64 val)
struct spu_lscsa *lscsa = ctx->csa.lscsa;
spu_acquire_saved(ctx);
lscsa->decr.slot[0] = (u32) val;
- spu_release(ctx);
+ spu_release_saved(ctx);
}
static u64 __spufs_decr_get(void *data)
@@ -1625,7 +1642,7 @@ static u64 spufs_decr_get(void *data)
u64 ret;
spu_acquire_saved(ctx);
ret = __spufs_decr_get(data);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
@@ -1634,17 +1651,21 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
static void spufs_decr_status_set(void *data, u64 val)
{
struct spu_context *ctx = data;
- struct spu_lscsa *lscsa = ctx->csa.lscsa;
spu_acquire_saved(ctx);
- lscsa->decr_status.slot[0] = (u32) val;
- spu_release(ctx);
+ if (val)
+ ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
+ else
+ ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
+ spu_release_saved(ctx);
}
static u64 __spufs_decr_status_get(void *data)
{
struct spu_context *ctx = data;
- struct spu_lscsa *lscsa = ctx->csa.lscsa;
- return lscsa->decr_status.slot[0];
+ if (ctx->csa.priv2.mfc_control_RW & MFC_CNTL_DECREMENTER_RUNNING)
+ return SPU_DECR_STATUS_RUNNING;
+ else
+ return 0;
}
static u64 spufs_decr_status_get(void *data)
@@ -1653,7 +1674,7 @@ static u64 spufs_decr_status_get(void *data)
u64 ret;
spu_acquire_saved(ctx);
ret = __spufs_decr_status_get(data);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
@@ -1665,7 +1686,7 @@ static void spufs_event_mask_set(void *data, u64 val)
struct spu_lscsa *lscsa = ctx->csa.lscsa;
spu_acquire_saved(ctx);
lscsa->event_mask.slot[0] = (u32) val;
- spu_release(ctx);
+ spu_release_saved(ctx);
}
static u64 __spufs_event_mask_get(void *data)
@@ -1681,7 +1702,7 @@ static u64 spufs_event_mask_get(void *data)
u64 ret;
spu_acquire_saved(ctx);
ret = __spufs_event_mask_get(data);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
@@ -1705,7 +1726,7 @@ static u64 spufs_event_status_get(void *data)
spu_acquire_saved(ctx);
ret = __spufs_event_status_get(data);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
@@ -1717,7 +1738,7 @@ static void spufs_srr0_set(void *data, u64 val)
struct spu_lscsa *lscsa = ctx->csa.lscsa;
spu_acquire_saved(ctx);
lscsa->srr0.slot[0] = (u32) val;
- spu_release(ctx);
+ spu_release_saved(ctx);
}
static u64 spufs_srr0_get(void *data)
@@ -1727,7 +1748,7 @@ static u64 spufs_srr0_get(void *data)
u64 ret;
spu_acquire_saved(ctx);
ret = lscsa->srr0.slot[0];
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
@@ -1783,7 +1804,7 @@ static u64 spufs_lslr_get(void *data)
spu_acquire_saved(ctx);
ret = __spufs_lslr_get(data);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -1797,6 +1818,29 @@ static int spufs_info_open(struct inode *inode, struct file *file)
return 0;
}
+static int spufs_caps_show(struct seq_file *s, void *private)
+{
+ struct spu_context *ctx = s->private;
+
+ if (!(ctx->flags & SPU_CREATE_NOSCHED))
+ seq_puts(s, "sched\n");
+ if (!(ctx->flags & SPU_CREATE_ISOLATE))
+ seq_puts(s, "step\n");
+ return 0;
+}
+
+static int spufs_caps_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, spufs_caps_show, SPUFS_I(inode)->i_ctx);
+}
+
+static const struct file_operations spufs_caps_fops = {
+ .open = spufs_caps_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,
char __user *buf, size_t len, loff_t *pos)
{
@@ -1824,7 +1868,7 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
spin_lock(&ctx->csa.register_lock);
ret = __spufs_mbox_info_read(ctx, buf, len, pos);
spin_unlock(&ctx->csa.register_lock);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -1862,7 +1906,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
spin_lock(&ctx->csa.register_lock);
ret = __spufs_ibox_info_read(ctx, buf, len, pos);
spin_unlock(&ctx->csa.register_lock);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -1903,7 +1947,7 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
spin_lock(&ctx->csa.register_lock);
ret = __spufs_wbox_info_read(ctx, buf, len, pos);
spin_unlock(&ctx->csa.register_lock);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -1953,7 +1997,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
spin_lock(&ctx->csa.register_lock);
ret = __spufs_dma_info_read(ctx, buf, len, pos);
spin_unlock(&ctx->csa.register_lock);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -2004,7 +2048,7 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
spin_lock(&ctx->csa.register_lock);
ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
spin_unlock(&ctx->csa.register_lock);
- spu_release(ctx);
+ spu_release_saved(ctx);
return ret;
}
@@ -2014,7 +2058,117 @@ static const struct file_operations spufs_proxydma_info_fops = {
.read = spufs_proxydma_info_read,
};
+static int spufs_show_tid(struct seq_file *s, void *private)
+{
+ struct spu_context *ctx = s->private;
+
+ seq_printf(s, "%d\n", ctx->tid);
+ return 0;
+}
+
+static int spufs_tid_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, spufs_show_tid, SPUFS_I(inode)->i_ctx);
+}
+
+static const struct file_operations spufs_tid_fops = {
+ .open = spufs_tid_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const char *ctx_state_names[] = {
+ "user", "system", "iowait", "loaded"
+};
+
+static unsigned long long spufs_acct_time(struct spu_context *ctx,
+ enum spu_utilization_state state)
+{
+ struct timespec ts;
+ unsigned long long time = ctx->stats.times[state];
+
+ /*
+ * In general, utilization statistics are updated by the controlling
+ * thread as the spu context moves through various well defined
+ * state transitions, but if the context is lazily loaded its
+ * utilization statistics are not updated as the controlling thread
+ * is not tightly coupled with the execution of the spu context. We
+ * calculate and apply the time delta from the last recorded state
+ * of the spu context.
+ */
+ if (ctx->spu && ctx->stats.util_state == state) {
+ ktime_get_ts(&ts);
+ time += timespec_to_ns(&ts) - ctx->stats.tstamp;
+ }
+
+ return time / NSEC_PER_MSEC;
+}
+
+static unsigned long long spufs_slb_flts(struct spu_context *ctx)
+{
+ unsigned long long slb_flts = ctx->stats.slb_flt;
+
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ slb_flts += (ctx->spu->stats.slb_flt -
+ ctx->stats.slb_flt_base);
+ }
+
+ return slb_flts;
+}
+
+static unsigned long long spufs_class2_intrs(struct spu_context *ctx)
+{
+ unsigned long long class2_intrs = ctx->stats.class2_intr;
+
+ if (ctx->state == SPU_STATE_RUNNABLE) {
+ class2_intrs += (ctx->spu->stats.class2_intr -
+ ctx->stats.class2_intr_base);
+ }
+
+ return class2_intrs;
+}
+
+
+static int spufs_show_stat(struct seq_file *s, void *private)
+{
+ struct spu_context *ctx = s->private;
+
+ spu_acquire(ctx);
+ seq_printf(s, "%s %llu %llu %llu %llu "
+ "%llu %llu %llu %llu %llu %llu %llu %llu\n",
+ ctx_state_names[ctx->stats.util_state],
+ spufs_acct_time(ctx, SPU_UTIL_USER),
+ spufs_acct_time(ctx, SPU_UTIL_SYSTEM),
+ spufs_acct_time(ctx, SPU_UTIL_IOWAIT),
+ spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED),
+ ctx->stats.vol_ctx_switch,
+ ctx->stats.invol_ctx_switch,
+ spufs_slb_flts(ctx),
+ ctx->stats.hash_flt,
+ ctx->stats.min_flt,
+ ctx->stats.maj_flt,
+ spufs_class2_intrs(ctx),
+ ctx->stats.libassist);
+ spu_release(ctx);
+ return 0;
+}
+
+static int spufs_stat_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx);
+}
+
+static const struct file_operations spufs_stat_fops = {
+ .open = spufs_stat_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
struct tree_descr spufs_dir_contents[] = {
+ { "capabilities", &spufs_caps_fops, 0444, },
{ "mem", &spufs_mem_fops, 0666, },
{ "regs", &spufs_regs_fops, 0666, },
{ "mbox", &spufs_mbox_fops, 0444, },
@@ -2023,8 +2177,8 @@ struct tree_descr spufs_dir_contents[] = {
{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
- { "signal1", &spufs_signal1_fops, 0666, },
- { "signal2", &spufs_signal2_fops, 0666, },
+ { "signal1", &spufs_signal1_nosched_fops, 0222, },
+ { "signal2", &spufs_signal2_nosched_fops, 0222, },
{ "signal1_type", &spufs_signal1_type, 0666, },
{ "signal2_type", &spufs_signal2_type, 0666, },
{ "cntl", &spufs_cntl_fops, 0666, },
@@ -2046,10 +2200,13 @@ struct tree_descr spufs_dir_contents[] = {
{ "wbox_info", &spufs_wbox_info_fops, 0444, },
{ "dma_info", &spufs_dma_info_fops, 0444, },
{ "proxydma_info", &spufs_proxydma_info_fops, 0444, },
+ { "tid", &spufs_tid_fops, 0444, },
+ { "stat", &spufs_stat_fops, 0444, },
{},
};
struct tree_descr spufs_dir_nosched_contents[] = {
+ { "capabilities", &spufs_caps_fops, 0444, },
{ "mem", &spufs_mem_fops, 0666, },
{ "mbox", &spufs_mbox_fops, 0444, },
{ "ibox", &spufs_ibox_fops, 0444, },
@@ -2057,8 +2214,8 @@ struct tree_descr spufs_dir_nosched_contents[] = {
{ "mbox_stat", &spufs_mbox_stat_fops, 0444, },
{ "ibox_stat", &spufs_ibox_stat_fops, 0444, },
{ "wbox_stat", &spufs_wbox_stat_fops, 0444, },
- { "signal1", &spufs_signal1_fops, 0666, },
- { "signal2", &spufs_signal2_fops, 0666, },
+ { "signal1", &spufs_signal1_nosched_fops, 0222, },
+ { "signal2", &spufs_signal2_nosched_fops, 0222, },
{ "signal1_type", &spufs_signal1_type, 0666, },
{ "signal2_type", &spufs_signal2_type, 0666, },
{ "mss", &spufs_mss_fops, 0666, },
@@ -2068,6 +2225,8 @@ struct tree_descr spufs_dir_nosched_contents[] = {
{ "psmap", &spufs_psmap_fops, 0666, },
{ "phys-id", &spufs_id_ops, 0666, },
{ "object-id", &spufs_object_id_ops, 0666, },
+ { "tid", &spufs_tid_fops, 0444, },
+ { "stat", &spufs_stat_fops, 0444, },
{},
};
diff --git a/arch/powerpc/platforms/cell/spufs/gang.c b/arch/powerpc/platforms/cell/spufs/gang.c
index 212ea78f9051..71a443253021 100644
--- a/arch/powerpc/platforms/cell/spufs/gang.c
+++ b/arch/powerpc/platforms/cell/spufs/gang.c
@@ -35,7 +35,9 @@ struct spu_gang *alloc_spu_gang(void)
kref_init(&gang->kref);
mutex_init(&gang->mutex);
+ mutex_init(&gang->aff_mutex);
INIT_LIST_HEAD(&gang->list);
+ INIT_LIST_HEAD(&gang->aff_list_head);
out:
return gang;
@@ -73,6 +75,10 @@ void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx)
{
mutex_lock(&gang->mutex);
WARN_ON(ctx->gang != gang);
+ if (!list_empty(&ctx->aff_list)) {
+ list_del_init(&ctx->aff_list);
+ gang->aff_flags &= ~AFF_OFFSETS_SET;
+ }
list_del_init(&ctx->gang_list);
gang->contexts--;
mutex_unlock(&gang->mutex);
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 9807206e0219..b3d0dd118dd0 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -232,10 +232,6 @@ static int spufs_dir_close(struct inode *inode, struct file *file)
return dcache_dir_close(inode, file);
}
-const struct inode_operations spufs_dir_inode_operations = {
- .lookup = simple_lookup,
-};
-
const struct file_operations spufs_context_fops = {
.open = dcache_dir_open,
.release = spufs_dir_close,
@@ -269,7 +265,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
goto out_iput;
ctx->flags = flags;
- inode->i_op = &spufs_dir_inode_operations;
+ inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
if (flags & SPU_CREATE_NOSCHED)
ret = spufs_fill_dir(dentry, spufs_dir_nosched_contents,
@@ -320,11 +316,107 @@ out:
return ret;
}
-static int spufs_create_context(struct inode *inode,
- struct dentry *dentry,
- struct vfsmount *mnt, int flags, int mode)
+static struct spu_context *
+spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
+ struct file *filp)
+{
+ struct spu_context *tmp, *neighbor;
+ int count, node;
+ int aff_supp;
+
+ aff_supp = !list_empty(&(list_entry(cbe_spu_info[0].spus.next,
+ struct spu, cbe_list))->aff_list);
+
+ if (!aff_supp)
+ return ERR_PTR(-EINVAL);
+
+ if (flags & SPU_CREATE_GANG)
+ return ERR_PTR(-EINVAL);
+
+ if (flags & SPU_CREATE_AFFINITY_MEM &&
+ gang->aff_ref_ctx &&
+ gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM)
+ return ERR_PTR(-EEXIST);
+
+ if (gang->aff_flags & AFF_MERGED)
+ return ERR_PTR(-EBUSY);
+
+ neighbor = NULL;
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ if (!filp || filp->f_op != &spufs_context_fops)
+ return ERR_PTR(-EINVAL);
+
+ neighbor = get_spu_context(
+ SPUFS_I(filp->f_dentry->d_inode)->i_ctx);
+
+ if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
+ !list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
+ !list_entry(neighbor->aff_list.next, struct spu_context,
+ aff_list)->aff_head)
+ return ERR_PTR(-EEXIST);
+
+ if (gang != neighbor->gang)
+ return ERR_PTR(-EINVAL);
+
+ count = 1;
+ list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+ count++;
+ if (list_empty(&neighbor->aff_list))
+ count++;
+
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ if ((cbe_spu_info[node].n_spus - atomic_read(
+ &cbe_spu_info[node].reserved_spus)) >= count)
+ break;
+ }
+
+ if (node == MAX_NUMNODES)
+ return ERR_PTR(-EEXIST);
+ }
+
+ return neighbor;
+}
+
+static void
+spufs_set_affinity(unsigned int flags, struct spu_context *ctx,
+ struct spu_context *neighbor)
+{
+ if (flags & SPU_CREATE_AFFINITY_MEM)
+ ctx->gang->aff_ref_ctx = ctx;
+
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ if (list_empty(&neighbor->aff_list)) {
+ list_add_tail(&neighbor->aff_list,
+ &ctx->gang->aff_list_head);
+ neighbor->aff_head = 1;
+ }
+
+ if (list_is_last(&neighbor->aff_list, &ctx->gang->aff_list_head)
+ || list_entry(neighbor->aff_list.next, struct spu_context,
+ aff_list)->aff_head) {
+ list_add(&ctx->aff_list, &neighbor->aff_list);
+ } else {
+ list_add_tail(&ctx->aff_list, &neighbor->aff_list);
+ if (neighbor->aff_head) {
+ neighbor->aff_head = 0;
+ ctx->aff_head = 1;
+ }
+ }
+
+ if (!ctx->gang->aff_ref_ctx)
+ ctx->gang->aff_ref_ctx = ctx;
+ }
+}
+
+static int
+spufs_create_context(struct inode *inode, struct dentry *dentry,
+ struct vfsmount *mnt, int flags, int mode,
+ struct file *aff_filp)
{
int ret;
+ int affinity;
+ struct spu_gang *gang;
+ struct spu_context *neighbor;
ret = -EPERM;
if ((flags & SPU_CREATE_NOSCHED) &&
@@ -340,9 +432,29 @@ static int spufs_create_context(struct inode *inode,
if ((flags & SPU_CREATE_ISOLATE) && !isolated_loader)
goto out_unlock;
+ gang = NULL;
+ neighbor = NULL;
+ affinity = flags & (SPU_CREATE_AFFINITY_MEM | SPU_CREATE_AFFINITY_SPU);
+ if (affinity) {
+ gang = SPUFS_I(inode)->i_gang;
+ ret = -EINVAL;
+ if (!gang)
+ goto out_unlock;
+ mutex_lock(&gang->aff_mutex);
+ neighbor = spufs_assert_affinity(flags, gang, aff_filp);
+ if (IS_ERR(neighbor)) {
+ ret = PTR_ERR(neighbor);
+ goto out_aff_unlock;
+ }
+ }
+
ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
if (ret)
- goto out_unlock;
+ goto out_aff_unlock;
+
+ if (affinity)
+ spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
+ neighbor);
/*
* get references for dget and mntget, will be released
@@ -356,6 +468,9 @@ static int spufs_create_context(struct inode *inode,
goto out;
}
+out_aff_unlock:
+ if (affinity)
+ mutex_unlock(&gang->aff_mutex);
out_unlock:
mutex_unlock(&inode->i_mutex);
out:
@@ -386,7 +501,7 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode)
if (!gang)
goto out_iput;
- inode->i_op = &spufs_dir_inode_operations;
+ inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
d_instantiate(dentry, inode);
@@ -454,7 +569,8 @@ out:
static struct file_system_type spufs_type;
-long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
+long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode,
+ struct file *filp)
{
struct dentry *dentry;
int ret;
@@ -491,7 +607,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
dentry, nd->mnt, mode);
else
return spufs_create_context(nd->dentry->d_inode,
- dentry, nd->mnt, flags, mode);
+ dentry, nd->mnt, flags, mode, filp);
out_dput:
dput(dentry);
@@ -593,7 +709,7 @@ spufs_create_root(struct super_block *sb, void *data)
if (!inode)
goto out;
- inode->i_op = &spufs_dir_inode_operations;
+ inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
SPUFS_I(inode)->i_ctx = NULL;
@@ -658,7 +774,7 @@ static int __init spufs_init(void)
ret = -ENOMEM;
spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
sizeof(struct spufs_inode_info), 0,
- SLAB_HWCACHE_ALIGN, spufs_init_once, NULL);
+ SLAB_HWCACHE_ALIGN, spufs_init_once);
if (!spufs_inode_cache)
goto out;
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 57626600b1a4..0b50fa5cb39d 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -18,18 +18,21 @@ void spufs_stop_callback(struct spu *spu)
wake_up_all(&ctx->stop_wq);
}
-static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
+static inline int spu_stopped(struct spu_context *ctx, u32 *stat)
{
struct spu *spu;
u64 pte_fault;
*stat = ctx->ops->status_read(ctx);
- if (ctx->state != SPU_STATE_RUNNABLE)
- return 1;
+
spu = ctx->spu;
+ if (ctx->state != SPU_STATE_RUNNABLE ||
+ test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags))
+ return 1;
pte_fault = spu->dsisr &
(MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
- return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+ return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ?
+ 1 : 0;
}
static int spu_setup_isolated(struct spu_context *ctx)
@@ -123,8 +126,10 @@ out:
return ret;
}
-static int spu_run_init(struct spu_context *ctx, u32 * npc)
+static int spu_run_init(struct spu_context *ctx, u32 *npc)
{
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
if (ctx->flags & SPU_CREATE_ISOLATE) {
unsigned long runcntl;
@@ -142,22 +147,28 @@ static int spu_run_init(struct spu_context *ctx, u32 * npc)
runcntl = SPU_RUNCNTL_RUNNABLE;
ctx->ops->runcntl_write(ctx, runcntl);
} else {
- spu_start_tick(ctx);
+ unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL;
ctx->ops->npc_write(ctx, *npc);
+ if (test_thread_flag(TIF_SINGLESTEP))
+ mode = SPU_PRIVCNTL_MODE_SINGLE_STEP;
+ out_be64(&ctx->spu->priv2->spu_privcntl_RW, mode);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
}
+ spuctx_switch_state(ctx, SPU_UTIL_USER);
+
return 0;
}
-static int spu_run_fini(struct spu_context *ctx, u32 * npc,
- u32 * status)
+static int spu_run_fini(struct spu_context *ctx, u32 *npc,
+ u32 *status)
{
int ret = 0;
- spu_stop_tick(ctx);
*status = ctx->ops->status_read(ctx);
*npc = ctx->ops->npc_read(ctx);
+
+ spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
spu_release(ctx);
if (signal_pending(current))
@@ -286,10 +297,10 @@ static inline int spu_process_events(struct spu_context *ctx)
return ret;
}
-long spufs_run_spu(struct file *file, struct spu_context *ctx,
- u32 *npc, u32 *event)
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
{
int ret;
+ struct spu *spu;
u32 status;
if (mutex_lock_interruptible(&ctx->run_mutex))
@@ -298,9 +309,22 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
ctx->ops->master_start(ctx);
ctx->event_return = 0;
- ret = spu_acquire_runnable(ctx, 0);
- if (ret)
- return ret;
+ spu_acquire(ctx);
+ if (ctx->state == SPU_STATE_SAVED) {
+ __spu_update_sched_info(ctx);
+
+ ret = spu_activate(ctx, 0);
+ if (ret) {
+ spu_release(ctx);
+ goto out;
+ }
+ } else {
+ /*
+ * We have to update the scheduling priority under active_mutex
+ * to protect against find_victim().
+ */
+ spu_update_sched_info(ctx);
+ }
ret = spu_run_init(ctx, npc);
if (ret) {
@@ -312,6 +336,17 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
if (unlikely(ret))
break;
+ spu = ctx->spu;
+ if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE,
+ &ctx->sched_flags))) {
+ if (!(status & SPU_STATUS_STOPPED_BY_STOP)) {
+ spu_switch_notify(spu, ctx);
+ continue;
+ }
+ }
+
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
(status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
ret = spu_process_callback(ctx);
@@ -325,16 +360,21 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
ret = spu_reacquire_runnable(ctx, npc, &status);
- if (ret) {
- spu_stop_tick(ctx);
+ if (ret)
goto out2;
- }
continue;
}
ret = spu_process_events(ctx);
} while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
- SPU_STATUS_STOPPED_BY_HALT)));
+ SPU_STATUS_STOPPED_BY_HALT |
+ SPU_STATUS_SINGLE_STEP)));
+
+ if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
+ (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) &&
+ (ctx->state == SPU_STATE_RUNNABLE))
+ ctx->stats.libassist++;
+
ctx->ops->master_stop(ctx);
ret = spu_run_fini(ctx, npc, &status);
@@ -344,10 +384,15 @@ out2:
if ((ret == 0) ||
((ret == -ERESTARTSYS) &&
((status & SPU_STATUS_STOPPED_BY_HALT) ||
+ (status & SPU_STATUS_SINGLE_STEP) ||
((status & SPU_STATUS_STOPPED_BY_STOP) &&
(status >> SPU_STOP_STATUS_SHIFT != 0x2104)))))
ret = status;
+ /* Note: we don't need to force_sig SIGTRAP on single-step
+ * since we have TIF_SINGLESTEP set, thus the kernel will do
+ * it upon return from the syscall anyawy
+ */
if ((status & SPU_STATUS_STOPPED_BY_STOP)
&& (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
force_sig(SIGTRAP, current);
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 3b831e07f1ed..227968b4779d 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -35,6 +35,10 @@
#include <linux/numa.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/pid_namespace.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
@@ -43,97 +47,175 @@
#include <asm/spu_priv1.h>
#include "spufs.h"
-#define SPU_TIMESLICE (HZ)
-
struct spu_prio_array {
DECLARE_BITMAP(bitmap, MAX_PRIO);
struct list_head runq[MAX_PRIO];
spinlock_t runq_lock;
- struct list_head active_list[MAX_NUMNODES];
- struct mutex active_mutex[MAX_NUMNODES];
+ int nr_waiting;
};
+static unsigned long spu_avenrun[3];
static struct spu_prio_array *spu_prio;
-static struct workqueue_struct *spu_sched_wq;
+static struct task_struct *spusched_task;
+static struct timer_list spusched_timer;
-static inline int node_allowed(int node)
-{
- cpumask_t mask;
+/*
+ * Priority of a normal, non-rt, non-niced'd process (aka nice level 0).
+ */
+#define NORMAL_PRIO 120
- if (!nr_cpus_node(node))
- return 0;
- mask = node_to_cpumask(node);
- if (!cpus_intersects(mask, current->cpus_allowed))
- return 0;
- return 1;
+/*
+ * Frequency of the spu scheduler tick. By default we do one SPU scheduler
+ * tick for every 10 CPU scheduler ticks.
+ */
+#define SPUSCHED_TICK (10)
+
+/*
+ * These are the 'tuning knobs' of the scheduler:
+ *
+ * Minimum timeslice is 5 msecs (or 1 spu scheduler tick, whichever is
+ * larger), default timeslice is 100 msecs, maximum timeslice is 800 msecs.
+ */
+#define MIN_SPU_TIMESLICE max(5 * HZ / (1000 * SPUSCHED_TICK), 1)
+#define DEF_SPU_TIMESLICE (100 * HZ / (1000 * SPUSCHED_TICK))
+
+#define MAX_USER_PRIO (MAX_PRIO - MAX_RT_PRIO)
+#define SCALE_PRIO(x, prio) \
+ max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_SPU_TIMESLICE)
+
+/*
+ * scale user-nice values [ -20 ... 0 ... 19 ] to time slice values:
+ * [800ms ... 100ms ... 5ms]
+ *
+ * The higher a thread's priority, the bigger timeslices
+ * it gets during one round of execution. But even the lowest
+ * priority thread gets MIN_TIMESLICE worth of execution time.
+ */
+void spu_set_timeslice(struct spu_context *ctx)
+{
+ if (ctx->prio < NORMAL_PRIO)
+ ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE * 4, ctx->prio);
+ else
+ ctx->time_slice = SCALE_PRIO(DEF_SPU_TIMESLICE, ctx->prio);
}
-void spu_start_tick(struct spu_context *ctx)
+/*
+ * Update scheduling information from the owning thread.
+ */
+void __spu_update_sched_info(struct spu_context *ctx)
{
- if (ctx->policy == SCHED_RR) {
- /*
- * Make sure the exiting bit is cleared.
- */
- clear_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
- mb();
- queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE);
- }
+ /*
+ * 32-Bit assignment are atomic on powerpc, and we don't care about
+ * memory ordering here because retriving the controlling thread is
+ * per defintion racy.
+ */
+ ctx->tid = current->pid;
+
+ /*
+ * We do our own priority calculations, so we normally want
+ * ->static_prio to start with. Unfortunately thies field
+ * contains junk for threads with a realtime scheduling
+ * policy so we have to look at ->prio in this case.
+ */
+ if (rt_prio(current->prio))
+ ctx->prio = current->prio;
+ else
+ ctx->prio = current->static_prio;
+ ctx->policy = current->policy;
+
+ /*
+ * A lot of places that don't hold list_mutex poke into
+ * cpus_allowed, including grab_runnable_context which
+ * already holds the runq_lock. So abuse runq_lock
+ * to protect this field aswell.
+ */
+ spin_lock(&spu_prio->runq_lock);
+ ctx->cpus_allowed = current->cpus_allowed;
+ spin_unlock(&spu_prio->runq_lock);
}
-void spu_stop_tick(struct spu_context *ctx)
+void spu_update_sched_info(struct spu_context *ctx)
{
- if (ctx->policy == SCHED_RR) {
- /*
- * While the work can be rearming normally setting this flag
- * makes sure it does not rearm itself anymore.
- */
- set_bit(SPU_SCHED_EXITING, &ctx->sched_flags);
- mb();
- cancel_delayed_work(&ctx->sched_work);
- }
+ int node = ctx->spu->node;
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ __spu_update_sched_info(ctx);
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
}
-/**
- * spu_add_to_active_list - add spu to active list
- * @spu: spu to add to the active list
- */
-static void spu_add_to_active_list(struct spu *spu)
+static int __node_allowed(struct spu_context *ctx, int node)
{
- mutex_lock(&spu_prio->active_mutex[spu->node]);
- list_add_tail(&spu->list, &spu_prio->active_list[spu->node]);
- mutex_unlock(&spu_prio->active_mutex[spu->node]);
+ if (nr_cpus_node(node)) {
+ cpumask_t mask = node_to_cpumask(node);
+
+ if (cpus_intersects(mask, ctx->cpus_allowed))
+ return 1;
+ }
+
+ return 0;
}
-/**
- * spu_remove_from_active_list - remove spu from active list
- * @spu: spu to remove from the active list
- */
-static void spu_remove_from_active_list(struct spu *spu)
+static int node_allowed(struct spu_context *ctx, int node)
{
- int node = spu->node;
+ int rval;
- mutex_lock(&spu_prio->active_mutex[node]);
- list_del_init(&spu->list);
- mutex_unlock(&spu_prio->active_mutex[node]);
+ spin_lock(&spu_prio->runq_lock);
+ rval = __node_allowed(ctx, node);
+ spin_unlock(&spu_prio->runq_lock);
+
+ return rval;
}
static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
-static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
{
blocking_notifier_call_chain(&spu_switch_notifier,
ctx ? ctx->object_id : 0, spu);
}
+static void notify_spus_active(void)
+{
+ int node;
+
+ /*
+ * Wake up the active spu_contexts.
+ *
+ * When the awakened processes see their "notify_active" flag is set,
+ * they will call spu_switch_notify();
+ */
+ for_each_online_node(node) {
+ struct spu *spu;
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+ if (spu->alloc_state != SPU_FREE) {
+ struct spu_context *ctx = spu->ctx;
+ set_bit(SPU_SCHED_NOTIFY_ACTIVE,
+ &ctx->sched_flags);
+ mb();
+ wake_up_all(&ctx->stop_wq);
+ }
+ }
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+ }
+}
+
int spu_switch_event_register(struct notifier_block * n)
{
- return blocking_notifier_chain_register(&spu_switch_notifier, n);
+ int ret;
+ ret = blocking_notifier_chain_register(&spu_switch_notifier, n);
+ if (!ret)
+ notify_spus_active();
+ return ret;
}
+EXPORT_SYMBOL_GPL(spu_switch_event_register);
int spu_switch_event_unregister(struct notifier_block * n)
{
return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
}
+EXPORT_SYMBOL_GPL(spu_switch_event_unregister);
/**
* spu_bind_context - bind spu context to physical spu
@@ -144,11 +226,22 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
{
pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
spu->number, spu->node);
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
+
+ if (ctx->flags & SPU_CREATE_NOSCHED)
+ atomic_inc(&cbe_spu_info[spu->node].reserved_spus);
+ if (!list_empty(&ctx->aff_list))
+ atomic_inc(&ctx->gang->aff_sched_count);
+
+ ctx->stats.slb_flt_base = spu->stats.slb_flt;
+ ctx->stats.class2_intr_base = spu->stats.class2_intr;
+
spu->ctx = ctx;
spu->flags = 0;
ctx->spu = spu;
ctx->ops = &spu_hw_ops;
spu->pid = current->pid;
+ spu->tgid = current->tgid;
spu_associate_mm(spu, ctx->owner);
spu->ibox_callback = spufs_ibox_callback;
spu->wbox_callback = spufs_wbox_callback;
@@ -161,8 +254,154 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
spu->timestamp = jiffies;
spu_cpu_affinity_set(spu, raw_smp_processor_id());
spu_switch_notify(spu, ctx);
- spu_add_to_active_list(spu);
ctx->state = SPU_STATE_RUNNABLE;
+
+ spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+}
+
+/*
+ * Must be used with the list_mutex held.
+ */
+static inline int sched_spu(struct spu *spu)
+{
+ BUG_ON(!mutex_is_locked(&cbe_spu_info[spu->node].list_mutex));
+
+ return (!spu->ctx || !(spu->ctx->flags & SPU_CREATE_NOSCHED));
+}
+
+static void aff_merge_remaining_ctxs(struct spu_gang *gang)
+{
+ struct spu_context *ctx;
+
+ list_for_each_entry(ctx, &gang->aff_list_head, aff_list) {
+ if (list_empty(&ctx->aff_list))
+ list_add(&ctx->aff_list, &gang->aff_list_head);
+ }
+ gang->aff_flags |= AFF_MERGED;
+}
+
+static void aff_set_offsets(struct spu_gang *gang)
+{
+ struct spu_context *ctx;
+ int offset;
+
+ offset = -1;
+ list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+ aff_list) {
+ if (&ctx->aff_list == &gang->aff_list_head)
+ break;
+ ctx->aff_offset = offset--;
+ }
+
+ offset = 0;
+ list_for_each_entry(ctx, gang->aff_ref_ctx->aff_list.prev, aff_list) {
+ if (&ctx->aff_list == &gang->aff_list_head)
+ break;
+ ctx->aff_offset = offset++;
+ }
+
+ gang->aff_flags |= AFF_OFFSETS_SET;
+}
+
+static struct spu *aff_ref_location(struct spu_context *ctx, int mem_aff,
+ int group_size, int lowest_offset)
+{
+ struct spu *spu;
+ int node, n;
+
+ /*
+ * TODO: A better algorithm could be used to find a good spu to be
+ * used as reference location for the ctxs chain.
+ */
+ node = cpu_to_node(raw_smp_processor_id());
+ for (n = 0; n < MAX_NUMNODES; n++, node++) {
+ node = (node < MAX_NUMNODES) ? node : 0;
+ if (!node_allowed(ctx, node))
+ continue;
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+ if ((!mem_aff || spu->has_mem_affinity) &&
+ sched_spu(spu)) {
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+ return spu;
+ }
+ }
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+ }
+ return NULL;
+}
+
+static void aff_set_ref_point_location(struct spu_gang *gang)
+{
+ int mem_aff, gs, lowest_offset;
+ struct spu_context *ctx;
+ struct spu *tmp;
+
+ mem_aff = gang->aff_ref_ctx->flags & SPU_CREATE_AFFINITY_MEM;
+ lowest_offset = 0;
+ gs = 0;
+
+ list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
+ gs++;
+
+ list_for_each_entry_reverse(ctx, &gang->aff_ref_ctx->aff_list,
+ aff_list) {
+ if (&ctx->aff_list == &gang->aff_list_head)
+ break;
+ lowest_offset = ctx->aff_offset;
+ }
+
+ gang->aff_ref_spu = aff_ref_location(ctx, mem_aff, gs, lowest_offset);
+}
+
+static struct spu *ctx_location(struct spu *ref, int offset, int node)
+{
+ struct spu *spu;
+
+ spu = NULL;
+ if (offset >= 0) {
+ list_for_each_entry(spu, ref->aff_list.prev, aff_list) {
+ BUG_ON(spu->node != node);
+ if (offset == 0)
+ break;
+ if (sched_spu(spu))
+ offset--;
+ }
+ } else {
+ list_for_each_entry_reverse(spu, ref->aff_list.next, aff_list) {
+ BUG_ON(spu->node != node);
+ if (offset == 0)
+ break;
+ if (sched_spu(spu))
+ offset++;
+ }
+ }
+
+ return spu;
+}
+
+/*
+ * affinity_check is called each time a context is going to be scheduled.
+ * It returns the spu ptr on which the context must run.
+ */
+static int has_affinity(struct spu_context *ctx)
+{
+ struct spu_gang *gang = ctx->gang;
+
+ if (list_empty(&ctx->aff_list))
+ return 0;
+
+ mutex_lock(&gang->aff_mutex);
+ if (!gang->aff_ref_spu) {
+ if (!(gang->aff_flags & AFF_MERGED))
+ aff_merge_remaining_ctxs(gang);
+ if (!(gang->aff_flags & AFF_OFFSETS_SET))
+ aff_set_offsets(gang);
+ aff_set_ref_point_location(gang);
+ }
+ mutex_unlock(&gang->aff_mutex);
+
+ return gang->aff_ref_spu != NULL;
}
/**
@@ -174,8 +413,13 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
{
pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
spu->pid, spu->number, spu->node);
+ spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
- spu_remove_from_active_list(spu);
+ if (spu->ctx->flags & SPU_CREATE_NOSCHED)
+ atomic_dec(&cbe_spu_info[spu->node].reserved_spus);
+ if (!list_empty(&ctx->aff_list))
+ if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
+ ctx->gang->aff_ref_spu = NULL;
spu_switch_notify(spu, NULL);
spu_unmap_mappings(ctx);
spu_save(&ctx->csa, spu);
@@ -188,10 +432,19 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
spu->dma_callback = NULL;
spu_associate_mm(spu, NULL);
spu->pid = 0;
+ spu->tgid = 0;
ctx->ops = &spu_backing_ops;
- ctx->spu = NULL;
spu->flags = 0;
spu->ctx = NULL;
+
+ ctx->stats.slb_flt +=
+ (spu->stats.slb_flt - ctx->stats.slb_flt_base);
+ ctx->stats.class2_intr +=
+ (spu->stats.class2_intr - ctx->stats.class2_intr_base);
+
+ /* This maps the underlying spu state to idle */
+ spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED);
+ ctx->spu = NULL;
}
/**
@@ -200,20 +453,39 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
*/
static void __spu_add_to_rq(struct spu_context *ctx)
{
- int prio = ctx->prio;
-
- list_add_tail(&ctx->rq, &spu_prio->runq[prio]);
- set_bit(prio, spu_prio->bitmap);
+ /*
+ * Unfortunately this code path can be called from multiple threads
+ * on behalf of a single context due to the way the problem state
+ * mmap support works.
+ *
+ * Fortunately we need to wake up all these threads at the same time
+ * and can simply skip the runqueue addition for every but the first
+ * thread getting into this codepath.
+ *
+ * It's still quite hacky, and long-term we should proxy all other
+ * threads through the owner thread so that spu_run is in control
+ * of all the scheduling activity for a given context.
+ */
+ if (list_empty(&ctx->rq)) {
+ list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]);
+ set_bit(ctx->prio, spu_prio->bitmap);
+ if (!spu_prio->nr_waiting++)
+ __mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK);
+ }
}
static void __spu_del_from_rq(struct spu_context *ctx)
{
int prio = ctx->prio;
- if (!list_empty(&ctx->rq))
+ if (!list_empty(&ctx->rq)) {
+ if (!--spu_prio->nr_waiting)
+ del_timer(&spusched_timer);
list_del_init(&ctx->rq);
- if (list_empty(&spu_prio->runq[prio]))
- clear_bit(prio, spu_prio->bitmap);
+
+ if (list_empty(&spu_prio->runq[prio]))
+ clear_bit(prio, spu_prio->bitmap);
+ }
}
static void spu_prio_wait(struct spu_context *ctx)
@@ -238,18 +510,41 @@ static void spu_prio_wait(struct spu_context *ctx)
static struct spu *spu_get_idle(struct spu_context *ctx)
{
- struct spu *spu = NULL;
- int node = cpu_to_node(raw_smp_processor_id());
- int n;
+ struct spu *spu;
+ int node, n;
+ if (has_affinity(ctx)) {
+ node = ctx->gang->aff_ref_spu->node;
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ spu = ctx_location(ctx->gang->aff_ref_spu, ctx->aff_offset, node);
+ if (spu && spu->alloc_state == SPU_FREE)
+ goto found;
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+ return NULL;
+ }
+
+ node = cpu_to_node(raw_smp_processor_id());
for (n = 0; n < MAX_NUMNODES; n++, node++) {
node = (node < MAX_NUMNODES) ? node : 0;
- if (!node_allowed(node))
+ if (!node_allowed(ctx, node))
continue;
- spu = spu_alloc_node(node);
- if (spu)
- break;
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
+ if (spu->alloc_state == SPU_FREE)
+ goto found;
+ }
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
}
+
+ return NULL;
+
+ found:
+ spu->alloc_state = SPU_USED;
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+ pr_debug("Got SPU %d %d\n", spu->number, spu->node);
+ spu_init_channels(spu);
return spu;
}
@@ -276,18 +571,18 @@ static struct spu *find_victim(struct spu_context *ctx)
node = cpu_to_node(raw_smp_processor_id());
for (n = 0; n < MAX_NUMNODES; n++, node++) {
node = (node < MAX_NUMNODES) ? node : 0;
- if (!node_allowed(node))
+ if (!node_allowed(ctx, node))
continue;
- mutex_lock(&spu_prio->active_mutex[node]);
- list_for_each_entry(spu, &spu_prio->active_list[node], list) {
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
struct spu_context *tmp = spu->ctx;
- if (tmp->rt_priority < ctx->rt_priority &&
- (!victim || tmp->rt_priority < victim->rt_priority))
+ if (tmp->prio > ctx->prio &&
+ (!victim || tmp->prio > victim->prio))
victim = spu->ctx;
}
- mutex_unlock(&spu_prio->active_mutex[node]);
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
if (victim) {
/*
@@ -312,7 +607,14 @@ static struct spu *find_victim(struct spu_context *ctx)
victim = NULL;
goto restart;
}
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ cbe_spu_info[node].nr_active--;
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+
spu_unbind_context(spu, victim);
+ victim->stats.invol_ctx_switch++;
+ spu->stats.invol_ctx_switch++;
mutex_unlock(&victim->state_mutex);
/*
* We need to break out of the wait loop in spu_run
@@ -338,22 +640,32 @@ static struct spu *find_victim(struct spu_context *ctx)
*/
int spu_activate(struct spu_context *ctx, unsigned long flags)
{
-
- if (ctx->spu)
- return 0;
-
do {
struct spu *spu;
+ /*
+ * If there are multiple threads waiting for a single context
+ * only one actually binds the context while the others will
+ * only be able to acquire the state_mutex once the context
+ * already is in runnable state.
+ */
+ if (ctx->spu)
+ return 0;
+
spu = spu_get_idle(ctx);
/*
* If this is a realtime thread we try to get it running by
* preempting a lower priority thread.
*/
- if (!spu && ctx->rt_priority)
+ if (!spu && rt_prio(ctx->prio))
spu = find_victim(ctx);
if (spu) {
+ int node = spu->node;
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
spu_bind_context(spu, ctx);
+ cbe_spu_info[node].nr_active++;
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
return 0;
}
@@ -369,23 +681,28 @@ int spu_activate(struct spu_context *ctx, unsigned long flags)
* Remove the highest priority context on the runqueue and return it
* to the caller. Returns %NULL if no runnable context was found.
*/
-static struct spu_context *grab_runnable_context(int prio)
+static struct spu_context *grab_runnable_context(int prio, int node)
{
- struct spu_context *ctx = NULL;
+ struct spu_context *ctx;
int best;
spin_lock(&spu_prio->runq_lock);
- best = sched_find_first_bit(spu_prio->bitmap);
- if (best < prio) {
+ best = find_first_bit(spu_prio->bitmap, prio);
+ while (best < prio) {
struct list_head *rq = &spu_prio->runq[best];
- BUG_ON(list_empty(rq));
-
- ctx = list_entry(rq->next, struct spu_context, rq);
- __spu_del_from_rq(ctx);
+ list_for_each_entry(ctx, rq, rq) {
+ /* XXX(hch): check for affinity here aswell */
+ if (__node_allowed(ctx, node)) {
+ __spu_del_from_rq(ctx);
+ goto found;
+ }
+ }
+ best++;
}
+ ctx = NULL;
+ found:
spin_unlock(&spu_prio->runq_lock);
-
return ctx;
}
@@ -395,10 +712,19 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
struct spu_context *new = NULL;
if (spu) {
- new = grab_runnable_context(max_prio);
+ new = grab_runnable_context(max_prio, spu->node);
if (new || force) {
+ int node = spu->node;
+
+ mutex_lock(&cbe_spu_info[node].list_mutex);
spu_unbind_context(spu, ctx);
- spu_free(spu);
+ spu->alloc_state = SPU_FREE;
+ cbe_spu_info[node].nr_active--;
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+
+ ctx->stats.vol_ctx_switch++;
+ spu->stats.vol_ctx_switch++;
+
if (new)
wake_up(&new->stop_wq);
}
@@ -421,7 +747,7 @@ void spu_deactivate(struct spu_context *ctx)
}
/**
- * spu_yield - yield a physical spu if others are waiting
+ * spu_yield - yield a physical spu if others are waiting
* @ctx: spu context to yield
*
* Check if there is a higher priority context waiting and if yes
@@ -437,78 +763,217 @@ void spu_yield(struct spu_context *ctx)
}
}
-void spu_sched_tick(struct work_struct *work)
+static noinline void spusched_tick(struct spu_context *ctx)
{
- struct spu_context *ctx =
- container_of(work, struct spu_context, sched_work.work);
- int preempted;
+ if (ctx->flags & SPU_CREATE_NOSCHED)
+ return;
+ if (ctx->policy == SCHED_FIFO)
+ return;
- /*
- * If this context is being stopped avoid rescheduling from the
- * scheduler tick because we would block on the state_mutex.
- * The caller will yield the spu later on anyway.
- */
- if (test_bit(SPU_SCHED_EXITING, &ctx->sched_flags))
+ if (--ctx->time_slice)
return;
- mutex_lock(&ctx->state_mutex);
- preempted = __spu_deactivate(ctx, 0, ctx->prio + 1);
- mutex_unlock(&ctx->state_mutex);
+ /*
+ * Unfortunately list_mutex ranks outside of state_mutex, so
+ * we have to trylock here. If we fail give the context another
+ * tick and try again.
+ */
+ if (mutex_trylock(&ctx->state_mutex)) {
+ struct spu *spu = ctx->spu;
+ struct spu_context *new;
- if (preempted) {
- /*
- * We need to break out of the wait loop in spu_run manually
- * to ensure this context gets put on the runqueue again
- * ASAP.
- */
- wake_up(&ctx->stop_wq);
+ new = grab_runnable_context(ctx->prio + 1, spu->node);
+ if (new) {
+ spu_unbind_context(spu, ctx);
+ ctx->stats.invol_ctx_switch++;
+ spu->stats.invol_ctx_switch++;
+ spu->alloc_state = SPU_FREE;
+ cbe_spu_info[spu->node].nr_active--;
+ wake_up(&new->stop_wq);
+ /*
+ * We need to break out of the wait loop in
+ * spu_run manually to ensure this context
+ * gets put on the runqueue again ASAP.
+ */
+ wake_up(&ctx->stop_wq);
+ }
+ spu_set_timeslice(ctx);
+ mutex_unlock(&ctx->state_mutex);
} else {
- spu_start_tick(ctx);
+ ctx->time_slice++;
}
}
-int __init spu_sched_init(void)
+/**
+ * count_active_contexts - count nr of active tasks
+ *
+ * Return the number of tasks currently running or waiting to run.
+ *
+ * Note that we don't take runq_lock / list_mutex here. Reading
+ * a single 32bit value is atomic on powerpc, and we don't care
+ * about memory ordering issues here.
+ */
+static unsigned long count_active_contexts(void)
{
- int i;
+ int nr_active = 0, node;
- spu_sched_wq = create_singlethread_workqueue("spusched");
- if (!spu_sched_wq)
- return 1;
+ for (node = 0; node < MAX_NUMNODES; node++)
+ nr_active += cbe_spu_info[node].nr_active;
+ nr_active += spu_prio->nr_waiting;
- spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL);
- if (!spu_prio) {
- printk(KERN_WARNING "%s: Unable to allocate priority queue.\n",
- __FUNCTION__);
- destroy_workqueue(spu_sched_wq);
- return 1;
+ return nr_active;
+}
+
+/**
+ * spu_calc_load - given tick count, update the avenrun load estimates.
+ * @tick: tick count
+ *
+ * No locking against reading these values from userspace, as for
+ * the CPU loadavg code.
+ */
+static void spu_calc_load(unsigned long ticks)
+{
+ unsigned long active_tasks; /* fixed-point */
+ static int count = LOAD_FREQ;
+
+ count -= ticks;
+
+ if (unlikely(count < 0)) {
+ active_tasks = count_active_contexts() * FIXED_1;
+ do {
+ CALC_LOAD(spu_avenrun[0], EXP_1, active_tasks);
+ CALC_LOAD(spu_avenrun[1], EXP_5, active_tasks);
+ CALC_LOAD(spu_avenrun[2], EXP_15, active_tasks);
+ count += LOAD_FREQ;
+ } while (count < 0);
+ }
+}
+
+static void spusched_wake(unsigned long data)
+{
+ mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK);
+ wake_up_process(spusched_task);
+ spu_calc_load(SPUSCHED_TICK);
+}
+
+static int spusched_thread(void *unused)
+{
+ struct spu *spu;
+ int node;
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+ if (spu->ctx)
+ spusched_tick(spu->ctx);
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
+ }
}
+
+ return 0;
+}
+
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+
+static int show_spu_loadavg(struct seq_file *s, void *private)
+{
+ int a, b, c;
+
+ a = spu_avenrun[0] + (FIXED_1/200);
+ b = spu_avenrun[1] + (FIXED_1/200);
+ c = spu_avenrun[2] + (FIXED_1/200);
+
+ /*
+ * Note that last_pid doesn't really make much sense for the
+ * SPU loadavg (it even seems very odd on the CPU side..),
+ * but we include it here to have a 100% compatible interface.
+ */
+ seq_printf(s, "%d.%02d %d.%02d %d.%02d %ld/%d %d\n",
+ LOAD_INT(a), LOAD_FRAC(a),
+ LOAD_INT(b), LOAD_FRAC(b),
+ LOAD_INT(c), LOAD_FRAC(c),
+ count_active_contexts(),
+ atomic_read(&nr_spu_contexts),
+ current->nsproxy->pid_ns->last_pid);
+ return 0;
+}
+
+static int spu_loadavg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, show_spu_loadavg, NULL);
+}
+
+static const struct file_operations spu_loadavg_fops = {
+ .open = spu_loadavg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+int __init spu_sched_init(void)
+{
+ struct proc_dir_entry *entry;
+ int err = -ENOMEM, i;
+
+ spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL);
+ if (!spu_prio)
+ goto out;
+
for (i = 0; i < MAX_PRIO; i++) {
INIT_LIST_HEAD(&spu_prio->runq[i]);
__clear_bit(i, spu_prio->bitmap);
}
- __set_bit(MAX_PRIO, spu_prio->bitmap);
for (i = 0; i < MAX_NUMNODES; i++) {
- mutex_init(&spu_prio->active_mutex[i]);
- INIT_LIST_HEAD(&spu_prio->active_list[i]);
+ mutex_init(&cbe_spu_info[i].list_mutex);
+ INIT_LIST_HEAD(&cbe_spu_info[i].spus);
}
spin_lock_init(&spu_prio->runq_lock);
+
+ setup_timer(&spusched_timer, spusched_wake, 0);
+
+ spusched_task = kthread_run(spusched_thread, NULL, "spusched");
+ if (IS_ERR(spusched_task)) {
+ err = PTR_ERR(spusched_task);
+ goto out_free_spu_prio;
+ }
+
+ entry = create_proc_entry("spu_loadavg", 0, NULL);
+ if (!entry)
+ goto out_stop_kthread;
+ entry->proc_fops = &spu_loadavg_fops;
+
+ pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n",
+ SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE);
return 0;
+
+ out_stop_kthread:
+ kthread_stop(spusched_task);
+ out_free_spu_prio:
+ kfree(spu_prio);
+ out:
+ return err;
}
-void __exit spu_sched_exit(void)
+void spu_sched_exit(void)
{
- struct spu *spu, *tmp;
+ struct spu *spu;
int node;
+ remove_proc_entry("spu_loadavg", NULL);
+
+ del_timer_sync(&spusched_timer);
+ kthread_stop(spusched_task);
+
for (node = 0; node < MAX_NUMNODES; node++) {
- mutex_lock(&spu_prio->active_mutex[node]);
- list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node],
- list) {
- list_del_init(&spu->list);
- spu_free(spu);
- }
- mutex_unlock(&spu_prio->active_mutex[node]);
+ mutex_lock(&cbe_spu_info[node].list_mutex);
+ list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list)
+ if (spu->alloc_state != SPU_FREE)
+ spu->alloc_state = SPU_FREE;
+ mutex_unlock(&cbe_spu_info[node].list_mutex);
}
kfree(spu_prio);
- destroy_workqueue(spu_sched_wq);
}
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore.c b/arch/powerpc/platforms/cell/spufs/spu_restore.c
index 0bf723dcd677..21a9c952d88b 100644
--- a/arch/powerpc/platforms/cell/spufs/spu_restore.c
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore.c
@@ -84,13 +84,13 @@ static inline void restore_decr(void)
unsigned int decr_running;
unsigned int decr;
- /* Restore, Step 6:
+ /* Restore, Step 6(moved):
* If the LSCSA "decrementer running" flag is set
* then write the SPU_WrDec channel with the
* decrementer value from LSCSA.
*/
offset = LSCSA_QW_OFFSET(decr_status);
- decr_running = regs_spill[offset].slot[0];
+ decr_running = regs_spill[offset].slot[0] & SPU_DECR_STATUS_RUNNING;
if (decr_running) {
offset = LSCSA_QW_OFFSET(decr);
decr = regs_spill[offset].slot[0];
@@ -296,7 +296,7 @@ static inline void restore_complete(void)
* This code deviates from the documented sequence in the
* following aspects:
*
- * 1. The EA for LSCSA is passed from PPE in the
+ * 1. The EA for LSCSA is passed from PPE in the
* signal notification channels.
* 2. The register spill area is pulled by SPU
* into LS, rather than pushed by PPE.
@@ -318,10 +318,10 @@ int main()
build_dma_list(lscsa_ea); /* Step 3. */
restore_upper_240kb(lscsa_ea); /* Step 4. */
/* Step 5: done by 'exit'. */
- restore_decr(); /* Step 6. */
enqueue_putllc(lscsa_ea); /* Step 7. */
set_tag_update(); /* Step 8. */
read_tag_status(); /* Step 9. */
+ restore_decr(); /* moved Step 6. */
read_llar_status(); /* Step 10. */
write_ppu_mb(); /* Step 11. */
write_ppuint_mb(); /* Step 12. */
diff --git a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
index 15183d209b58..f383b027e8bf 100644
--- a/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
+++ b/arch/powerpc/platforms/cell/spufs/spu_restore_dump.h_shipped
@@ -10,7 +10,7 @@ static unsigned int spu_restore_code[] __attribute__((__aligned__(128))) = {
0x24fd8081,
0x1cd80081,
0x33001180,
-0x42030003,
+0x42034003,
0x33800284,
0x1c010204,
0x40200000,
@@ -24,22 +24,22 @@ static unsigned int spu_restore_code[] __attribute__((__aligned__(128))) = {
0x23fffd84,
0x1c100183,
0x217ffa85,
-0x3080a000,
-0x3080a201,
-0x3080a402,
-0x3080a603,
-0x3080a804,
-0x3080aa05,
-0x3080ac06,
-0x3080ae07,
-0x3080b008,
-0x3080b209,
-0x3080b40a,
-0x3080b60b,
-0x3080b80c,
-0x3080ba0d,
-0x3080bc0e,
-0x3080be0f,
+0x3080b000,
+0x3080b201,
+0x3080b402,
+0x3080b603,
+0x3080b804,
+0x3080ba05,
+0x3080bc06,
+0x3080be07,
+0x3080c008,
+0x3080c209,
+0x3080c40a,
+0x3080c60b,
+0x3080c80c,
+0x3080ca0d,
+0x3080cc0e,
+0x3080ce0f,
0x00003ffc,
0x00000000,
0x00000000,
@@ -48,19 +48,18 @@ static unsigned int spu_restore_code[] __attribute__((__aligned__(128))) = {
0x3ec00083,
0xb0a14103,
0x01a00204,
-0x3ec10082,
-0x4202800e,
-0x04000703,
-0xb0a14202,
-0x21a00803,
-0x3fbf028d,
-0x3f20068d,
-0x3fbe0682,
+0x3ec10083,
+0x4202c002,
+0xb0a14203,
+0x21a00802,
+0x3fbf028a,
+0x3f20050a,
+0x3fbe0502,
0x3fe30102,
0x21a00882,
-0x3f82028f,
-0x3fe3078f,
-0x3fbf0784,
+0x3f82028b,
+0x3fe3058b,
+0x3fbf0584,
0x3f200204,
0x3fbe0204,
0x3fe30204,
@@ -75,252 +74,285 @@ static unsigned int spu_restore_code[] __attribute__((__aligned__(128))) = {
0x21a00083,
0x40800082,
0x21a00b02,
-0x10002818,
-0x42a00002,
-0x32800007,
-0x4207000c,
-0x18008208,
-0x40a0000b,
-0x4080020a,
-0x40800709,
-0x00200000,
-0x42070002,
-0x3ac30384,
+0x10002612,
+0x42a00003,
+0x42074006,
+0x1800c204,
+0x40a00008,
+0x40800789,
+0x1c010305,
+0x34000302,
0x1cffc489,
-0x00200000,
-0x18008383,
-0x38830382,
-0x4cffc486,
-0x3ac28185,
-0xb0408584,
-0x28830382,
-0x1c020387,
-0x38828182,
-0xb0408405,
-0x1802c408,
-0x28828182,
-0x217ff886,
-0x04000583,
-0x21a00803,
-0x3fbe0682,
-0x3fe30102,
-0x04000106,
-0x21a00886,
-0x04000603,
-0x21a00903,
-0x40803c02,
-0x21a00982,
-0x40800003,
-0x04000184,
-0x21a00a04,
+0x3ec00303,
+0x3ec00287,
+0xb0408403,
+0x24000302,
+0x34000282,
+0x1c020306,
+0xb0408207,
+0x18020204,
+0x24000282,
+0x217ffa09,
+0x04000402,
+0x21a00802,
+0x3fbe0504,
+0x3fe30204,
+0x21a00884,
+0x42074002,
+0x21a00902,
+0x40803c03,
+0x21a00983,
+0x04000485,
+0x21a00a05,
0x40802202,
0x21a00a82,
-0x42028005,
-0x34208702,
-0x21002282,
-0x21a00804,
-0x21a00886,
-0x3fbf0782,
+0x21a00805,
+0x21a00884,
+0x3fbf0582,
0x3f200102,
0x3fbe0102,
0x3fe30102,
0x21a00902,
0x40804003,
0x21a00983,
-0x21a00a04,
+0x21a00a05,
0x40805a02,
0x21a00a82,
0x40800083,
0x21a00b83,
0x01a00c02,
-0x01a00d83,
-0x3420c282,
+0x30809c03,
+0x34000182,
+0x14004102,
+0x21002082,
+0x01a00d82,
+0x3080a003,
+0x34000182,
0x21a00e02,
-0x34210283,
-0x21a00f03,
-0x34200284,
-0x77400200,
-0x3421c282,
+0x3080a203,
+0x34000182,
+0x21a00f02,
+0x3080a403,
+0x34000182,
+0x77400100,
+0x3080a603,
+0x34000182,
0x21a00702,
-0x34218283,
-0x21a00083,
-0x34214282,
+0x3080a803,
+0x34000182,
+0x21a00082,
+0x3080aa03,
+0x34000182,
0x21a00b02,
-0x4200480c,
-0x00200000,
-0x1c010286,
-0x34220284,
-0x34220302,
-0x0f608203,
-0x5c024204,
-0x3b81810b,
-0x42013c02,
-0x00200000,
-0x18008185,
-0x38808183,
-0x3b814182,
-0x21004e84,
+0x4020007f,
+0x3080ae02,
+0x42004805,
+0x3080ac04,
+0x34000103,
+0x34000202,
+0x1cffc183,
+0x3b810106,
+0x0f608184,
+0x42013802,
+0x5c020183,
+0x38810102,
+0x3b810102,
+0x21000e83,
0x4020007f,
0x35000100,
-0x000004e0,
-0x000002a0,
-0x000002e8,
-0x00000428,
+0x00000470,
+0x000002f8,
+0x00000430,
0x00000360,
-0x000002e8,
-0x000004a0,
-0x00000468,
+0x000002f8,
0x000003c8,
+0x000004a8,
+0x00000298,
0x00000360,
+0x00200000,
0x409ffe02,
0x30801203,
-0x40800204,
-0x3ec40085,
-0x10009c09,
-0x3ac10606,
-0xb060c105,
-0x4020007f,
-0x4020007f,
+0x40800208,
+0x3ec40084,
+0x40800407,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
0x20801203,
-0x38810602,
-0xb0408586,
-0x28810602,
-0x32004180,
-0x34204702,
+0x38820282,
+0x41004003,
+0xb0408189,
+0x28820282,
+0x3881c282,
+0xb0408304,
+0x2881c282,
+0x00400000,
+0x40800003,
+0x35000000,
+0x30809e03,
+0x34000182,
0x21a00382,
0x4020007f,
-0x327fdc80,
+0x327fde00,
0x409ffe02,
0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
-0x00200000,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800206,
+0x3ec40084,
+0x40800407,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
0x20801203,
+0x38818282,
0x41004003,
-0x38810602,
-0x4020007f,
-0xb0408188,
-0x4020007f,
-0x28810602,
-0x41201002,
-0x38814603,
-0x10009c09,
-0xb060c109,
-0x4020007f,
-0x28814603,
+0xb040818a,
+0x10005b0b,
+0x41201003,
+0x28818282,
+0x3881c282,
+0xb0408184,
0x41193f83,
-0x38818602,
0x60ffc003,
-0xb040818a,
-0x28818602,
-0x32003080,
+0x2881c282,
+0x38820282,
+0xb0408189,
+0x28820282,
+0x327fef80,
0x409ffe02,
0x30801203,
-0x40800204,
-0x3ec40087,
-0x41201008,
-0x10009c14,
-0x40800405,
-0x3ac10609,
-0x40800606,
-0x3ac1460a,
-0xb060c107,
-0x3ac1860b,
+0x40800207,
+0x3ec40086,
+0x4120100b,
+0x10005b14,
+0x40800404,
+0x3ac1c289,
+0x40800608,
+0xb060c106,
+0x3ac10286,
+0x3ac2028a,
0x20801203,
-0x38810602,
-0xb0408409,
-0x28810602,
-0x38814603,
-0xb060c40a,
-0x4020007f,
-0x28814603,
+0x3881c282,
0x41193f83,
-0x38818602,
0x60ffc003,
-0xb040818b,
-0x28818602,
-0x32002380,
-0x409ffe02,
-0x30801204,
-0x40800205,
-0x3ec40083,
-0x40800406,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x41004002,
-0x20801204,
-0x4020007f,
-0x38814603,
-0x10009c0b,
-0xb060c107,
-0x4020007f,
-0x4020007f,
-0x28814603,
-0x38818602,
-0x4020007f,
+0xb0408589,
+0x2881c282,
+0x38810282,
+0xb0408586,
+0x28810282,
+0x38820282,
+0xb040818a,
+0x28820282,
0x4020007f,
-0xb0408588,
-0x28818602,
+0x327fe280,
+0x409ffe02,
+0x30801203,
+0x40800207,
+0x3ec40084,
+0x40800408,
+0x10005b14,
+0x40800609,
+0x3ac1c28a,
+0x3ac2028b,
+0xb060c104,
+0x3ac24284,
+0x20801203,
+0x41201003,
+0x3881c282,
+0xb040830a,
+0x2881c282,
+0x38820282,
+0xb040818b,
+0x41193f83,
+0x60ffc003,
+0x28820282,
+0x38824282,
+0xb0408184,
+0x28824282,
0x4020007f,
-0x32001780,
+0x327fd580,
0x409ffe02,
-0x1000640e,
-0x40800204,
+0x1000658e,
+0x40800206,
0x30801203,
-0x40800405,
-0x3ec40087,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800407,
+0x3ec40084,
+0x40800608,
+0x3ac1828a,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
0x20801203,
0x413d8003,
-0x38810602,
+0x38818282,
0x4020007f,
-0x327fd780,
-0x409ffe02,
-0x10007f0c,
-0x40800205,
-0x30801204,
-0x40800406,
-0x3ec40083,
-0x3ac14607,
-0x3ac18608,
-0xb0810103,
-0x413d8002,
-0x20801204,
-0x38814603,
+0x327fd800,
+0x409ffe03,
+0x30801202,
+0x40800207,
+0x3ec40084,
+0x10005b09,
+0x3ac1c288,
+0xb0408184,
0x4020007f,
-0x327feb80,
+0x4020007f,
+0x20801202,
+0x3881c282,
+0xb0408308,
+0x2881c282,
+0x327fc680,
0x409ffe02,
+0x1000588b,
+0x40800208,
0x30801203,
-0x40800204,
-0x3ec40087,
-0x40800405,
-0x1000650a,
-0x40800606,
-0x3ac10608,
-0x3ac14609,
-0x3ac1860a,
-0xb060c107,
+0x40800407,
+0x3ec40084,
+0x3ac20289,
+0xb060c104,
+0x3ac1c284,
0x20801203,
-0x38810602,
-0xb0408588,
-0x4020007f,
-0x327fc980,
-0x00400000,
-0x40800003,
-0x4020007f,
-0x35000000,
+0x413d8003,
+0x38820282,
+0x327fbd80,
+0x00200000,
+0x00000da0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000d90,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000db0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dc0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000d80,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000df0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000de0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000dd0,
+0x00000000,
+0x00000000,
+0x00000000,
+0x00000e04,
+0x00000000,
+0x00000000,
0x00000000,
+0x00000e00,
0x00000000,
0x00000000,
0x00000000,
diff --git a/arch/powerpc/platforms/cell/spufs/spu_save.c b/arch/powerpc/platforms/cell/spufs/spu_save.c
index 196033b8a579..ae95cc1701e9 100644
--- a/arch/powerpc/platforms/cell/spufs/spu_save.c
+++ b/arch/powerpc/platforms/cell/spufs/spu_save.c
@@ -44,7 +44,7 @@ static inline void save_event_mask(void)
* Read the SPU_RdEventMsk channel and save to the LSCSA.
*/
offset = LSCSA_QW_OFFSET(event_mask);
- regs_spill[offset].slot[0] = spu_readch(SPU_RdEventStatMask);
+ regs_spill[offset].slot[0] = spu_readch(SPU_RdEventMask);
}
static inline void save_tag_mask(void)
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 47617e8014a5..8b20c0c1556f 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -26,6 +26,7 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
+#include <linux/cpumask.h>
#include <asm/spu.h>
#include <asm/spu_csa.h>
@@ -39,9 +40,13 @@ enum {
struct spu_context_ops;
struct spu_gang;
+enum {
+ SPU_SCHED_WAS_ACTIVE, /* was active upon spu_acquire_saved() */
+};
+
/* ctx->sched_flags */
enum {
- SPU_SCHED_EXITING = 0,
+ SPU_SCHED_NOTIFY_ACTIVE,
};
struct spu_context {
@@ -80,14 +85,41 @@ struct spu_context {
struct list_head gang_list;
struct spu_gang *gang;
+ struct kref *prof_priv_kref;
+ void ( * prof_priv_release) (struct kref *kref);
+
+ /* owner thread */
+ pid_t tid;
/* scheduler fields */
- struct list_head rq;
- struct delayed_work sched_work;
+ struct list_head rq;
+ unsigned int time_slice;
unsigned long sched_flags;
- unsigned long rt_priority;
+ cpumask_t cpus_allowed;
int policy;
int prio;
+
+ /* statistics */
+ struct {
+ /* updates protected by ctx->state_mutex */
+ enum spu_utilization_state util_state;
+ unsigned long long tstamp; /* time of last state switch */
+ unsigned long long times[SPU_UTIL_MAX];
+ unsigned long long vol_ctx_switch;
+ unsigned long long invol_ctx_switch;
+ unsigned long long min_flt;
+ unsigned long long maj_flt;
+ unsigned long long hash_flt;
+ unsigned long long slb_flt;
+ unsigned long long slb_flt_base; /* # at last ctx switch */
+ unsigned long long class2_intr;
+ unsigned long long class2_intr_base; /* # at last ctx switch */
+ unsigned long long libassist;
+ } stats;
+
+ struct list_head aff_list;
+ int aff_head;
+ int aff_offset;
};
struct spu_gang {
@@ -95,8 +127,19 @@ struct spu_gang {
struct mutex mutex;
struct kref kref;
int contexts;
+
+ struct spu_context *aff_ref_ctx;
+ struct list_head aff_list_head;
+ struct mutex aff_mutex;
+ int aff_flags;
+ struct spu *aff_ref_spu;
+ atomic_t aff_sched_count;
};
+/* Flag bits for spu_gang aff_flags */
+#define AFF_OFFSETS_SET 1
+#define AFF_MERGED 2
+
struct mfc_dma_command {
int32_t pad; /* reserved */
uint32_t lsa; /* local storage address */
@@ -160,10 +203,9 @@ extern struct tree_descr spufs_dir_contents[];
extern struct tree_descr spufs_dir_nosched_contents[];
/* system call implementation */
-long spufs_run_spu(struct file *file,
- struct spu_context *ctx, u32 *npc, u32 *status);
-long spufs_create(struct nameidata *nd,
- unsigned int flags, mode_t mode);
+long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *status);
+long spufs_create(struct nameidata *nd, unsigned int flags,
+ mode_t mode, struct file *filp);
extern const struct file_operations spufs_context_fops;
/* gang management */
@@ -176,7 +218,11 @@ void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
/* fault handling */
int spufs_handle_class1(struct spu_context *ctx);
+/* affinity */
+struct spu *affinity_check(struct spu_context *ctx);
+
/* context management */
+extern atomic_t nr_spu_contexts;
static inline void spu_acquire(struct spu_context *ctx)
{
mutex_lock(&ctx->state_mutex);
@@ -196,21 +242,23 @@ void spu_unmap_mappings(struct spu_context *ctx);
void spu_forget(struct spu_context *ctx);
int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags);
void spu_acquire_saved(struct spu_context *ctx);
+void spu_release_saved(struct spu_context *ctx);
int spu_activate(struct spu_context *ctx, unsigned long flags);
void spu_deactivate(struct spu_context *ctx);
void spu_yield(struct spu_context *ctx);
-void spu_start_tick(struct spu_context *ctx);
-void spu_stop_tick(struct spu_context *ctx);
-void spu_sched_tick(struct work_struct *work);
+void spu_switch_notify(struct spu *spu, struct spu_context *ctx);
+void spu_set_timeslice(struct spu_context *ctx);
+void spu_update_sched_info(struct spu_context *ctx);
+void __spu_update_sched_info(struct spu_context *ctx);
int __init spu_sched_init(void);
-void __exit spu_sched_exit(void);
+void spu_sched_exit(void);
extern char *isolated_loader;
/*
* spufs_wait
- * Same as wait_event_interruptible(), except that here
+ * Same as wait_event_interruptible(), except that here
* we need to call spu_release(ctx) before sleeping, and
* then spu_acquire(ctx) when awoken.
*/
@@ -256,4 +304,41 @@ struct spufs_coredump_reader {
extern struct spufs_coredump_reader spufs_coredump_read[];
extern int spufs_coredump_num_notes;
+/*
+ * This function is a little bit too large for an inline, but
+ * as fault.c is built into the kernel we can't move it out of
+ * line.
+ */
+static inline void spuctx_switch_state(struct spu_context *ctx,
+ enum spu_utilization_state new_state)
+{
+ unsigned long long curtime;
+ signed long long delta;
+ struct timespec ts;
+ struct spu *spu;
+ enum spu_utilization_state old_state;
+
+ ktime_get_ts(&ts);
+ curtime = timespec_to_ns(&ts);
+ delta = curtime - ctx->stats.tstamp;
+
+ WARN_ON(!mutex_is_locked(&ctx->state_mutex));
+ WARN_ON(delta < 0);
+
+ spu = ctx->spu;
+ old_state = ctx->stats.util_state;
+ ctx->stats.util_state = new_state;
+ ctx->stats.tstamp = curtime;
+
+ /*
+ * Update the physical SPU utilization statistics.
+ */
+ if (spu) {
+ ctx->stats.times[old_state] += delta;
+ spu->stats.times[old_state] += delta;
+ spu->stats.util_state = new_state;
+ spu->stats.tstamp = curtime;
+ }
+}
+
#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 71a0b41adb8c..27ffdae98e5a 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -70,7 +70,7 @@
}
#endif /* debug */
-#define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c))
+#define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c))
static inline void acquire_spu_lock(struct spu *spu)
{
@@ -180,7 +180,7 @@ static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
case MFC_CNTL_SUSPEND_COMPLETE:
if (csa) {
csa->priv2.mfc_control_RW =
- in_be64(&priv2->mfc_control_RW) |
+ MFC_CNTL_SUSPEND_MASK |
MFC_CNTL_SUSPEND_DMA_QUEUE;
}
break;
@@ -190,9 +190,7 @@ static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
MFC_CNTL_SUSPEND_COMPLETE);
if (csa) {
- csa->priv2.mfc_control_RW =
- in_be64(&priv2->mfc_control_RW) &
- ~MFC_CNTL_SUSPEND_DMA_QUEUE;
+ csa->priv2.mfc_control_RW = 0;
}
break;
}
@@ -251,16 +249,8 @@ static inline void save_mfc_decr(struct spu_state *csa, struct spu *spu)
* Read MFC_CNTL[Ds]. Update saved copy of
* CSA.MFC_CNTL[Ds].
*/
- if (in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING) {
- csa->priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING;
- csa->suspend_time = get_cycles();
- out_be64(&priv2->spu_chnlcntptr_RW, 7ULL);
- eieio();
- csa->spu_chnldata_RW[7] = in_be64(&priv2->spu_chnldata_RW);
- eieio();
- } else {
- csa->priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING;
- }
+ csa->priv2.mfc_control_RW |=
+ in_be64(&priv2->mfc_control_RW) & MFC_CNTL_DECREMENTER_RUNNING;
}
static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
@@ -271,7 +261,8 @@ static inline void halt_mfc_decr(struct spu_state *csa, struct spu *spu)
* Write MFC_CNTL[Dh] set to a '1' to halt
* the decrementer.
*/
- out_be64(&priv2->mfc_control_RW, MFC_CNTL_DECREMENTER_HALTED);
+ out_be64(&priv2->mfc_control_RW,
+ MFC_CNTL_DECREMENTER_HALTED | MFC_CNTL_SUSPEND_MASK);
eieio();
}
@@ -387,6 +378,19 @@ static inline void save_ppu_querytype(struct spu_state *csa, struct spu *spu)
csa->prob.dma_querytype_RW = in_be32(&prob->dma_querytype_RW);
}
+static inline void save_ppu_tagstatus(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_problem __iomem *prob = spu->problem;
+
+ /* Save the Prxy_TagStatus register in the CSA.
+ *
+ * It is unnecessary to restore dma_tagstatus_R, however,
+ * dma_tagstatus_R in the CSA is accessed via backing_ops, so
+ * we must save it.
+ */
+ csa->prob.dma_tagstatus_R = in_be32(&prob->dma_tagstatus_R);
+}
+
static inline void save_mfc_csr_tsq(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
@@ -602,7 +606,7 @@ static inline void save_ppuint_mb(struct spu_state *csa, struct spu *spu)
static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
int i;
/* Save, Step 42:
@@ -613,7 +617,7 @@ static inline void save_ch_part1(struct spu_state *csa, struct spu *spu)
csa->spu_chnldata_RW[1] = in_be64(&priv2->spu_chnldata_RW);
/* Save the following CH: [0,3,4,24,25,27] */
- for (i = 0; i < 7; i++) {
+ for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
idx = ch_indices[i];
out_be64(&priv2->spu_chnlcntptr_RW, idx);
eieio();
@@ -970,13 +974,13 @@ static inline void terminate_spu_app(struct spu_state *csa, struct spu *spu)
*/
}
-static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+static inline void suspend_mfc_and_halt_decr(struct spu_state *csa,
+ struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
/* Restore, Step 7:
- * Restore, Step 47.
- * Write MFC_Cntl[Dh,Sc]='1','1' to suspend
+ * Write MFC_Cntl[Dh,Sc,Sm]='1','1','0' to suspend
* the queue and halt the decrementer.
*/
out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE |
@@ -1077,7 +1081,7 @@ static inline void clear_spu_status(struct spu_state *csa, struct spu *spu)
static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- u64 ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ u64 ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
u64 idx;
int i;
@@ -1089,7 +1093,7 @@ static inline void reset_ch_part1(struct spu_state *csa, struct spu *spu)
out_be64(&priv2->spu_chnldata_RW, 0UL);
/* Reset the following CH: [0,3,4,24,25,27] */
- for (i = 0; i < 7; i++) {
+ for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
idx = ch_indices[i];
out_be64(&priv2->spu_chnlcntptr_RW, idx);
eieio();
@@ -1276,7 +1280,15 @@ static inline void setup_decr(struct spu_state *csa, struct spu *spu)
cycles_t resume_time = get_cycles();
cycles_t delta_time = resume_time - csa->suspend_time;
+ csa->lscsa->decr_status.slot[0] = SPU_DECR_STATUS_RUNNING;
+ if (csa->lscsa->decr.slot[0] < delta_time) {
+ csa->lscsa->decr_status.slot[0] |=
+ SPU_DECR_STATUS_WRAPPED;
+ }
+
csa->lscsa->decr.slot[0] -= delta_time;
+ } else {
+ csa->lscsa->decr_status.slot[0] = 0;
}
}
@@ -1385,6 +1397,18 @@ static inline void restore_ls_16kb(struct spu_state *csa, struct spu *spu)
send_mfc_dma(spu, addr, ls_offset, size, tag, rclass, cmd);
}
+static inline void suspend_mfc(struct spu_state *csa, struct spu *spu)
+{
+ struct spu_priv2 __iomem *priv2 = spu->priv2;
+
+ /* Restore, Step 47.
+ * Write MFC_Cntl[Sc,Sm]='1','0' to suspend
+ * the queue.
+ */
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE);
+ eieio();
+}
+
static inline void clear_interrupts(struct spu_state *csa, struct spu *spu)
{
/* Restore, Step 49:
@@ -1535,10 +1559,10 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
* "wrapped" flag is set, OR in a '1' to
* CSA.SPU_Event_Status[Tm].
*/
- if (csa->lscsa->decr_status.slot[0] == 1) {
+ if (csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) {
csa->spu_chnldata_RW[0] |= 0x20;
}
- if ((csa->lscsa->decr_status.slot[0] == 1) &&
+ if ((csa->lscsa->decr_status.slot[0] & SPU_DECR_STATUS_WRAPPED) &&
(csa->spu_chnlcnt_RW[0] == 0 &&
((csa->spu_chnldata_RW[2] & 0x20) == 0x0) &&
((csa->spu_chnldata_RW[0] & 0x20) != 0x1))) {
@@ -1549,18 +1573,13 @@ static inline void restore_decr_wrapped(struct spu_state *csa, struct spu *spu)
static inline void restore_ch_part1(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- u64 idx, ch_indices[7] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
+ u64 idx, ch_indices[] = { 0UL, 3UL, 4UL, 24UL, 25UL, 27UL };
int i;
/* Restore, Step 59:
+ * Restore the following CH: [0,3,4,24,25,27]
*/
-
- /* Restore CH 1 without count */
- out_be64(&priv2->spu_chnlcntptr_RW, 1);
- out_be64(&priv2->spu_chnldata_RW, csa->spu_chnldata_RW[1]);
-
- /* Restore the following CH: [0,3,4,24,25,27] */
- for (i = 0; i < 7; i++) {
+ for (i = 0; i < ARRAY_SIZE(ch_indices); i++) {
idx = ch_indices[i];
out_be64(&priv2->spu_chnlcntptr_RW, idx);
eieio();
@@ -1812,6 +1831,7 @@ static void save_csa(struct spu_state *prev, struct spu *spu)
save_mfc_queues(prev, spu); /* Step 19. */
save_ppu_querymask(prev, spu); /* Step 20. */
save_ppu_querytype(prev, spu); /* Step 21. */
+ save_ppu_tagstatus(prev, spu); /* NEW. */
save_mfc_csr_tsq(prev, spu); /* Step 22. */
save_mfc_csr_cmd(prev, spu); /* Step 23. */
save_mfc_csr_ato(prev, spu); /* Step 24. */
@@ -1918,7 +1938,7 @@ static void harvest(struct spu_state *prev, struct spu *spu)
set_switch_pending(prev, spu); /* Step 5. */
stop_spu_isolate(spu); /* NEW. */
remove_other_spu_access(prev, spu); /* Step 6. */
- suspend_mfc(prev, spu); /* Step 7. */
+ suspend_mfc_and_halt_decr(prev, spu); /* Step 7. */
wait_suspend_mfc_complete(prev, spu); /* Step 8. */
if (!suspend_spe(prev, spu)) /* Step 9. */
clear_spu_status(prev, spu); /* Step 10. */
@@ -1930,7 +1950,7 @@ static void harvest(struct spu_state *prev, struct spu *spu)
reset_spu_privcntl(prev, spu); /* Step 16. */
reset_spu_lslr(prev, spu); /* Step 17. */
setup_mfc_sr1(prev, spu); /* Step 18. */
- spu_invalidate_slbs(spu); /* Step 19. */
+ spu_invalidate_slbs(spu); /* Step 19. */
reset_ch_part1(prev, spu); /* Step 20. */
reset_ch_part2(prev, spu); /* Step 21. */
enable_interrupts(prev, spu); /* Step 22. */
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index 8e37bdf4dfda..43f0fb88abbc 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -47,7 +47,7 @@ static long do_spu_run(struct file *filp,
goto out;
i = SPUFS_I(filp->f_path.dentry->d_inode);
- ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
+ ret = spufs_run_spu(i->i_ctx, &npc, &status);
if (put_user(npc, unpc))
ret = -EFAULT;
@@ -76,8 +76,8 @@ asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus)
}
#endif
-asmlinkage long sys_spu_create(const char __user *pathname,
- unsigned int flags, mode_t mode)
+asmlinkage long do_spu_create(const char __user *pathname, unsigned int flags,
+ mode_t mode, struct file *neighbor)
{
char *tmp;
int ret;
@@ -90,7 +90,7 @@ asmlinkage long sys_spu_create(const char __user *pathname,
ret = path_lookup(tmp, LOOKUP_PARENT|
LOOKUP_OPEN|LOOKUP_CREATE, &nd);
if (!ret) {
- ret = spufs_create(&nd, flags, mode);
+ ret = spufs_create(&nd, flags, mode, neighbor);
path_release(&nd);
}
putname(tmp);
@@ -99,8 +99,32 @@ asmlinkage long sys_spu_create(const char __user *pathname,
return ret;
}
+#ifndef MODULE
+asmlinkage long sys_spu_create(const char __user *pathname, unsigned int flags,
+ mode_t mode, int neighbor_fd)
+{
+ int fput_needed;
+ struct file *neighbor;
+ long ret;
+
+ if (flags & SPU_CREATE_AFFINITY_SPU) {
+ ret = -EBADF;
+ neighbor = fget_light(neighbor_fd, &fput_needed);
+ if (neighbor) {
+ ret = do_spu_create(pathname, flags, mode, neighbor);
+ fput_light(neighbor, fput_needed);
+ }
+ }
+ else {
+ ret = do_spu_create(pathname, flags, mode, NULL);
+ }
+
+ return ret;
+}
+#endif
+
struct spufs_calls spufs_calls = {
- .create_thread = sys_spu_create,
+ .create_thread = do_spu_create,
.spu_run = do_spu_run,
.owner = THIS_MODULE,
};
diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig
index d2c690531963..22b4b4e3b6f0 100644
--- a/arch/powerpc/platforms/chrp/Kconfig
+++ b/arch/powerpc/platforms/chrp/Kconfig
@@ -8,4 +8,5 @@ config PPC_CHRP
select PPC_MPC106
select PPC_UDBG_16550
select PPC_NATIVE
+ select PCI
default y
diff --git a/arch/powerpc/platforms/chrp/Makefile b/arch/powerpc/platforms/chrp/Makefile
index 902feb1ac431..4b3bfadc70fa 100644
--- a/arch/powerpc/platforms/chrp/Makefile
+++ b/arch/powerpc/platforms/chrp/Makefile
@@ -1,4 +1,3 @@
-obj-y += setup.o time.o pegasos_eth.o
-obj-$(CONFIG_PCI) += pci.o
+obj-y += setup.o time.o pegasos_eth.o pci.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_NVRAM) += nvram.o
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
index d32fedc991d3..3690624e49d4 100644
--- a/arch/powerpc/platforms/chrp/pci.c
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -99,7 +99,7 @@ int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
struct pci_controller *hose = bus->sysdata;
unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
| (((bus->number - hose->first_busno) & 0xff) << 16)
- | (hose->index << 24);
+ | (hose->global_number << 24);
int ret = -1;
int rval;
@@ -114,7 +114,7 @@ int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
struct pci_controller *hose = bus->sysdata;
unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8)
| (((bus->number - hose->first_busno) & 0xff) << 16)
- | (hose->index << 24);
+ | (hose->global_number << 24);
int rval;
rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL,
@@ -254,13 +254,12 @@ chrp_find_bridges(void)
printk(" at %llx", (unsigned long long)r.start);
printk("\n");
- hose = pcibios_alloc_controller();
+ hose = pcibios_alloc_controller(dev);
if (!hose) {
printk("Can't allocate PCI controller structure for %s\n",
dev->full_name);
continue;
}
- hose->arch_data = dev;
hose->first_busno = bus_range[0];
hose->last_busno = bus_range[1];
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index f2d26268ca6f..2d12f77e46bc 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -28,6 +28,7 @@ config PPC_HOLLY
bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)"
select TSI108_BRIDGE
select PPC_UDBG_16550
+ select WANT_DEVICE_TREE
help
Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval
Board with TSI108/9 bridge (Hickory/Holly)
@@ -44,6 +45,7 @@ endchoice
config TSI108_BRIDGE
bool
depends on MPC7448HPC2 || PPC_HOLLY
+ select PCI
select MPIC
select MPIC_WEIRD
default y
@@ -57,7 +59,7 @@ config MPC10X_BRIDGE
config MV64X60
bool
select PPC_INDIRECT_PCI
- select CONFIG_CHECK_CACHE_COHERENCY
+ select CHECK_CACHE_COHERENCY
config MPC10X_OPENPIC
bool
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c
index 3a0b4a01401c..6292e36dc577 100644
--- a/arch/powerpc/platforms/embedded6xx/holly.c
+++ b/arch/powerpc/platforms/embedded6xx/holly.c
@@ -45,7 +45,7 @@
#define HOLLY_PCI_CFG_PHYS 0x7c000000
-int holly_exclude_device(u_char bus, u_char devfn)
+int holly_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
{
if (bus == 0 && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c
index b412f006a9c5..f4d0a7a603f5 100644
--- a/arch/powerpc/platforms/embedded6xx/linkstation.c
+++ b/arch/powerpc/platforms/embedded6xx/linkstation.c
@@ -54,8 +54,9 @@ static struct mtd_partition linkstation_physmap_partitions[] = {
},
};
-static int __init add_bridge(struct device_node *dev)
+static int __init linkstation_add_bridge(struct device_node *dev)
{
+#ifdef CONFIG_PCI
int len;
struct pci_controller *hose;
const int *bus_range;
@@ -67,18 +68,17 @@ static int __init add_bridge(struct device_node *dev)
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
- hose = pcibios_alloc_controller();
+ hose = pcibios_alloc_controller(dev);
if (hose == NULL)
return -ENOMEM;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
- hose->arch_data = dev;
setup_indirect_pci(hose, 0xfec00000, 0xfee00000);
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges(hose, dev, 1);
-
+#endif
return 0;
}
@@ -92,7 +92,7 @@ static void __init linkstation_setup_arch(void)
/* Lookup PCI host bridges */
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
- add_bridge(np);
+ linkstation_add_bridge(np);
printk(KERN_INFO "BUFFALO Network Attached Storage Series\n");
printk(KERN_INFO "(C) 2002-2005 BUFFALO INC.\n");
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index 4542e0c837c0..1e3cc69487b5 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -54,15 +54,10 @@
#define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000
-#ifndef CONFIG_PCI
-isa_io_base = MPC7448_HPC2_ISA_IO_BASE;
-isa_mem_base = MPC7448_HPC2_ISA_MEM_BASE;
-pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET;
-#endif
-
extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
-int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
+int mpc7448_hpc2_exclude_device(struct pci_controller *hose,
+ u_char bus, u_char devfn)
{
if (bus == 0 && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h
index a543a5242e34..f7e0e0c7f8d8 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.h
@@ -18,9 +18,4 @@
#include <asm/ppcboot.h>
-/* Base Addresses for the PCI bus
- */
-#define MPC7448_HPC2_PCI_MEM_OFFSET (0x00000000)
-#define MPC7448_HPC2_ISA_IO_BASE (0x00000000)
-#define MPC7448_HPC2_ISA_MEM_BASE (0x00000000)
#endif /* __PPC_PLATFORMS_MPC7448_HPC2_H */
diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h
index a843b0f87b72..8d95fe4b554e 100644
--- a/arch/powerpc/platforms/iseries/call_hpt.h
+++ b/arch/powerpc/platforms/iseries/call_hpt.h
@@ -76,24 +76,25 @@ static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson,
return compressedStatus;
}
-static inline u64 HvCallHpt_findValid(hpte_t *hpte, u64 vpn)
+static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn)
{
return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0);
}
-static inline u64 HvCallHpt_findNextValid(hpte_t *hpte, u32 hpteIndex,
+static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex,
u8 bitson, u8 bitsoff)
{
return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex,
bitson, bitsoff);
}
-static inline void HvCallHpt_get(hpte_t *hpte, u32 hpteIndex)
+static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex)
{
HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0);
}
-static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, hpte_t *hpte)
+static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit,
+ struct hash_pte *hpte)
{
HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r);
}
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c
index ed44dfceaa45..b4e2c7a038e1 100644
--- a/arch/powerpc/platforms/iseries/htab.c
+++ b/arch/powerpc/platforms/iseries/htab.c
@@ -44,7 +44,7 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
unsigned long vflags, int psize)
{
long slot;
- hpte_t lhpte;
+ struct hash_pte lhpte;
int secondary = 0;
BUG_ON(psize != MMU_PAGE_4K);
@@ -99,7 +99,7 @@ long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
static unsigned long iSeries_hpte_getword0(unsigned long slot)
{
- hpte_t hpte;
+ struct hash_pte hpte;
HvCallHpt_get(&hpte, slot);
return hpte.v;
@@ -144,7 +144,7 @@ static long iSeries_hpte_remove(unsigned long hpte_group)
static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
unsigned long va, int psize, int local)
{
- hpte_t hpte;
+ struct hash_pte hpte;
unsigned long want_v;
iSeries_hlock(slot);
@@ -176,7 +176,7 @@ static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
*/
static long iSeries_hpte_find(unsigned long vpn)
{
- hpte_t hpte;
+ struct hash_pte hpte;
long slot;
/*
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 9c974227155e..da87162000f0 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -742,6 +742,11 @@ void __init iSeries_pcibios_init(void)
/* Install IO hooks */
ppc_pci_io = iseries_pci_io;
+ /* iSeries has no IO space in the common sense, it needs to set
+ * the IO base to 0
+ */
+ pci_io_base = 0;
+
if (root == NULL) {
printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
"of device tree\n");
@@ -763,7 +768,7 @@ void __init iSeries_pcibios_init(void)
if (phb == NULL)
continue;
- phb->pci_mem_offset = phb->local_number = bus;
+ phb->pci_mem_offset = bus;
phb->first_busno = bus;
phb->last_busno = bus;
phb->ops = &iSeries_pci_ops;
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 7f5dcee814d4..13a8b1908ded 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -79,8 +79,6 @@ extern void iSeries_pci_final_fixup(void);
static void iSeries_pci_final_fixup(void) { }
#endif
-extern unsigned long iSeries_recal_tb;
-extern unsigned long iSeries_recal_titan;
struct MemoryBlock {
unsigned long absStart;
@@ -292,8 +290,8 @@ static void __init iSeries_init_early(void)
{
DBG(" -> iSeries_init_early()\n");
- iSeries_recal_tb = get_tb();
- iSeries_recal_titan = HvCallXm_loadTod();
+ /* Snapshot the timebase, for use in later recalibration */
+ iSeries_time_init_early();
/*
* Initialize the DMA/TCE management
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 7aaa5bbc9363..fceaae40fe70 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -444,7 +444,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
u3_ht = hose;
}
-static int __init add_bridge(struct device_node *dev)
+static int __init maple_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
@@ -519,23 +519,6 @@ void __devinit maple_pci_irq_fixup(struct pci_dev *dev)
DBG(" <- maple_pci_irq_fixup\n");
}
-static void __init maple_fixup_phb_resources(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
-
- hose->io_resource.start += offset;
- hose->io_resource.end += offset;
-
- printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n",
- hose->global_number,
- (unsigned long long)hose->io_resource.start,
- (unsigned long long)hose->io_resource.end);
- }
-}
-
void __init maple_pci_init(void)
{
struct device_node *np, *root;
@@ -558,7 +541,7 @@ void __init maple_pci_init(void)
continue;
if ((of_device_is_compatible(np, "u4-pcie") ||
of_device_is_compatible(np, "u3-agp")) &&
- add_bridge(np) == 0)
+ maple_add_bridge(np) == 0)
of_node_get(np);
if (of_device_is_compatible(np, "u3-ht")) {
@@ -570,27 +553,9 @@ void __init maple_pci_init(void)
/* Now setup the HyperTransport host if we found any
*/
- if (ht && add_bridge(ht) != 0)
+ if (ht && maple_add_bridge(ht) != 0)
of_node_put(ht);
- /*
- * We need to call pci_setup_phb_io for the HT bridge first
- * so it gets the I/O port numbers starting at 0, and we
- * need to call it for the AGP bridge after that so it gets
- * small positive I/O port numbers.
- */
- if (u3_ht)
- pci_setup_phb_io(u3_ht, 1);
- if (u3_agp)
- pci_setup_phb_io(u3_agp, 0);
- if (u4_pcie)
- pci_setup_phb_io(u4_pcie, 0);
-
- /* Fixup the IO resources on our host bridges as the common code
- * does it only for childs of the host bridges
- */
- maple_fixup_phb_resources();
-
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
index 7c5076e38ea1..95cd90fd81c7 100644
--- a/arch/powerpc/platforms/pasemi/Kconfig
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -25,4 +25,13 @@ config PPC_PASEMI_MDIO
help
Driver for MDIO via GPIO on PWRficient platforms
+config ELECTRA_IDE
+ tristate "Electra IDE driver"
+ default y
+ depends on PPC_PASEMI && ATA
+ select PATA_PLATFORM
+ help
+ This includes driver support for the Electra on-board IDE
+ interface.
+
endmenu
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index 2cd2a4f26a48..f47fcac7e581 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1,3 +1,4 @@
obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o
obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o
+obj-$(CONFIG_ELECTRA_IDE) += electra_ide.o
obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o
diff --git a/arch/powerpc/platforms/pasemi/electra_ide.c b/arch/powerpc/platforms/pasemi/electra_ide.c
new file mode 100644
index 000000000000..12fb0c949263
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/electra_ide.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/platform_device.h>
+
+#include <asm/prom.h>
+#include <asm/system.h>
+
+/* The electra IDE interface is incredibly simple: Just a device on the localbus
+ * with interrupts hooked up to one of the GPIOs. The device tree contains the
+ * address window and interrupt mappings already, and the pata_platform driver handles
+ * the rest. We just need to hook the two up.
+ */
+
+#define MAX_IFS 4 /* really, we have only one */
+
+static struct platform_device *pdevs[MAX_IFS];
+
+static int __devinit electra_ide_init(void)
+{
+ struct device_node *np;
+ struct resource r[3];
+ int ret = 0;
+ int i;
+
+ np = of_find_compatible_node(NULL, "ide", "electra-ide");
+ i = 0;
+
+ while (np && i < MAX_IFS) {
+ memset(r, 0, sizeof(r));
+
+ /* pata_platform wants two address ranges: one for the base registers,
+ * another for the control (altstatus). It's located at offset 0x3f6 in
+ * the window, but the device tree only has one large register window
+ * that covers both ranges. So we need to split it up by hand here:
+ */
+
+ ret = of_address_to_resource(np, 0, &r[0]);
+ if (ret)
+ goto out;
+ ret = of_address_to_resource(np, 0, &r[1]);
+ if (ret)
+ goto out;
+
+ r[1].start += 0x3f6;
+ r[0].end = r[1].start-1;
+
+ r[2].start = irq_of_parse_and_map(np, 0);
+ r[2].end = irq_of_parse_and_map(np, 0);
+ r[2].flags = IORESOURCE_IRQ;
+
+ pr_debug("registering platform device at 0x%lx/0x%lx, irq is %ld\n",
+ r[0].start, r[1].start, r[2].start);
+ pdevs[i] = platform_device_register_simple("pata_platform", i, r, 3);
+ if (IS_ERR(pdevs[i])) {
+ ret = PTR_ERR(pdevs[i]);
+ pdevs[i] = NULL;
+ goto out;
+ }
+ np = of_find_compatible_node(np, "ide", "electra-ide");
+ }
+out:
+ return ret;
+}
+module_init(electra_ide_init);
+
+static void __devexit electra_ide_exit(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_IFS; i++)
+ if (pdevs[i])
+ platform_device_unregister(pdevs[i]);
+}
+module_exit(electra_ide_exit);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi Electra IDE driver");
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index bbc6dfcfaa91..ab1f5f62bcd8 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -132,7 +132,7 @@ static void __init setup_pa_pxp(struct pci_controller *hose)
hose->cfg_data = ioremap(0xe0000000, 0x10000000);
}
-static int __init add_bridge(struct device_node *dev)
+static int __init pas_add_bridge(struct device_node *dev)
{
struct pci_controller *hose;
@@ -150,29 +150,11 @@ static int __init add_bridge(struct device_node *dev)
printk(KERN_INFO "Found PA-PXP PCI host bridge.\n");
/* Interpret the "ranges" property */
- /* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges(hose, dev, 1);
- pci_setup_phb_io(hose, 1);
return 0;
}
-
-static void __init pas_fixup_phb_resources(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
- hose->io_resource.start += offset;
- hose->io_resource.end += offset;
- printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
- hose->global_number,
- hose->io_resource.start, hose->io_resource.end);
- }
-}
-
-
void __init pas_pci_init(void)
{
struct device_node *np, *root;
@@ -185,13 +167,11 @@ void __init pas_pci_init(void)
}
for (np = NULL; (np = of_get_next_child(root, np)) != NULL;)
- if (np->name && !strcmp(np->name, "pxp") && !add_bridge(np))
+ if (np->name && !strcmp(np->name, "pxp") && !pas_add_bridge(np))
of_node_get(np);
of_node_put(root);
- pas_fixup_phb_resources();
-
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index c5a3f61f8d85..ffe6528048b5 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -239,7 +239,7 @@ static int __init pas_probe(void)
return 1;
}
-define_machine(pas) {
+define_machine(pasemi) {
.name = "PA Semi PA6T-1682M",
.probe = pas_probe,
.setup_arch = pas_setup_arch,
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig
index 5b7afe50039a..055990ca8ce6 100644
--- a/arch/powerpc/platforms/powermac/Kconfig
+++ b/arch/powerpc/platforms/powermac/Kconfig
@@ -2,6 +2,7 @@ config PPC_PMAC
bool "Apple PowerMac based machines"
depends on PPC_MULTIPLATFORM
select MPIC
+ select PCI
select PPC_INDIRECT_PCI if PPC32
select PPC_MPC106 if PPC32
select PPC_NATIVE
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 3f507ab9c5e5..efdf5eb81ecc 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -42,6 +42,7 @@
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/timer.h>
+#include <linux/mutex.h>
#include <asm/keylargo.h>
#include <asm/uninorth.h>
#include <asm/io.h>
@@ -84,7 +85,7 @@ struct pmac_i2c_bus
void *hostdata;
int channel; /* some hosts have multiple */
int mode; /* current mode */
- struct semaphore sem;
+ struct mutex mutex;
int opened;
int polled; /* open mode */
struct platform_device *platform_dev;
@@ -104,7 +105,7 @@ static LIST_HEAD(pmac_i2c_busses);
struct pmac_i2c_host_kw
{
- struct semaphore mutex; /* Access mutex for use by
+ struct mutex mutex; /* Access mutex for use by
* i2c-keywest */
void __iomem *base; /* register base address */
int bsteps; /* register stepping */
@@ -375,14 +376,14 @@ static void kw_i2c_timeout(unsigned long data)
static int kw_i2c_open(struct pmac_i2c_bus *bus)
{
struct pmac_i2c_host_kw *host = bus->hostdata;
- down(&host->mutex);
+ mutex_lock(&host->mutex);
return 0;
}
static void kw_i2c_close(struct pmac_i2c_bus *bus)
{
struct pmac_i2c_host_kw *host = bus->hostdata;
- up(&host->mutex);
+ mutex_unlock(&host->mutex);
}
static int kw_i2c_xfer(struct pmac_i2c_bus *bus, u8 addrdir, int subsize,
@@ -498,7 +499,7 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
kfree(host);
return NULL;
}
- init_MUTEX(&host->mutex);
+ mutex_init(&host->mutex);
init_completion(&host->complete);
spin_lock_init(&host->lock);
init_timer(&host->timeout_timer);
@@ -571,7 +572,7 @@ static void __init kw_i2c_add(struct pmac_i2c_host_kw *host,
bus->open = kw_i2c_open;
bus->close = kw_i2c_close;
bus->xfer = kw_i2c_xfer;
- init_MUTEX(&bus->sem);
+ mutex_init(&bus->mutex);
if (controller == busnode)
bus->flags = pmac_i2c_multibus;
list_add(&bus->link, &pmac_i2c_busses);
@@ -798,7 +799,7 @@ static void __init pmu_i2c_probe(void)
bus->mode = pmac_i2c_mode_std;
bus->hostdata = bus + 1;
bus->xfer = pmu_i2c_xfer;
- init_MUTEX(&bus->sem);
+ mutex_init(&bus->mutex);
bus->flags = pmac_i2c_multibus;
list_add(&bus->link, &pmac_i2c_busses);
@@ -921,7 +922,7 @@ static void __init smu_i2c_probe(void)
bus->mode = pmac_i2c_mode_std;
bus->hostdata = bus + 1;
bus->xfer = smu_i2c_xfer;
- init_MUTEX(&bus->sem);
+ mutex_init(&bus->mutex);
bus->flags = 0;
list_add(&bus->link, &pmac_i2c_busses);
@@ -1093,13 +1094,13 @@ int pmac_i2c_open(struct pmac_i2c_bus *bus, int polled)
{
int rc;
- down(&bus->sem);
+ mutex_lock(&bus->mutex);
bus->polled = polled || pmac_i2c_force_poll;
bus->opened = 1;
bus->mode = pmac_i2c_mode_std;
if (bus->open && (rc = bus->open(bus)) != 0) {
bus->opened = 0;
- up(&bus->sem);
+ mutex_unlock(&bus->mutex);
return rc;
}
return 0;
@@ -1112,7 +1113,7 @@ void pmac_i2c_close(struct pmac_i2c_bus *bus)
if (bus->close)
bus->close(bus);
bus->opened = 0;
- up(&bus->sem);
+ mutex_unlock(&bus->mutex);
}
EXPORT_SYMBOL_GPL(pmac_i2c_close);
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index c4af9e21ac93..92586db19754 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -35,8 +35,6 @@
#define DBG(x...)
#endif
-static int add_bridge(struct device_node *dev);
-
/* XXX Could be per-controller, but I don't think we risk anything by
* assuming we won't have both UniNorth and Bandit */
static int has_uninorth;
@@ -897,7 +895,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
* "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
* if we have one or more bandit or chaos bridges, we don't have a MPC106.
*/
-static int __init add_bridge(struct device_node *dev)
+static int __init pmac_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
@@ -918,15 +916,9 @@ static int __init add_bridge(struct device_node *dev)
" bus 0\n", dev->full_name);
}
- /* XXX Different prototypes, to be merged */
-#ifdef CONFIG_PPC64
hose = pcibios_alloc_controller(dev);
-#else
- hose = pcibios_alloc_controller();
-#endif
if (!hose)
return -ENOMEM;
- hose->arch_data = dev;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
@@ -1006,19 +998,6 @@ void __devinit pmac_pci_irq_fixup(struct pci_dev *dev)
#endif /* CONFIG_PPC32 */
}
-#ifdef CONFIG_PPC64
-static void __init pmac_fixup_phb_resources(void)
-{
- struct pci_controller *hose, *tmp;
-
- list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
- printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
- hose->global_number,
- hose->io_resource.start, hose->io_resource.end);
- }
-}
-#endif
-
void __init pmac_pci_init(void)
{
struct device_node *np, *root;
@@ -1036,7 +1015,7 @@ void __init pmac_pci_init(void)
if (strcmp(np->name, "bandit") == 0
|| strcmp(np->name, "chaos") == 0
|| strcmp(np->name, "pci") == 0) {
- if (add_bridge(np) == 0)
+ if (pmac_add_bridge(np) == 0)
of_node_get(np);
}
if (strcmp(np->name, "ht") == 0) {
@@ -1050,28 +1029,9 @@ void __init pmac_pci_init(void)
/* Probe HT last as it relies on the agp resources to be already
* setup
*/
- if (ht && add_bridge(ht) != 0)
+ if (ht && pmac_add_bridge(ht) != 0)
of_node_put(ht);
- /*
- * We need to call pci_setup_phb_io for the HT bridge first
- * so it gets the I/O port numbers starting at 0, and we
- * need to call it for the AGP bridge after that so it gets
- * small positive I/O port numbers.
- */
- if (u3_ht)
- pci_setup_phb_io(u3_ht, 1);
- if (u3_agp)
- pci_setup_phb_io(u3_agp, 0);
- if (u4_pcie)
- pci_setup_phb_io(u4_pcie, 0);
-
- /*
- * On ppc64, fixup the IO resources on our host bridges as
- * the common code does it only for children of the host bridges
- */
- pmac_fixup_phb_resources();
-
/* Setup the linkage between OF nodes and PHBs */
pci_devs_phb_init();
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig
index 40f0008af4d1..d4fc74f7bb15 100644
--- a/arch/powerpc/platforms/ps3/Kconfig
+++ b/arch/powerpc/platforms/ps3/Kconfig
@@ -7,6 +7,7 @@ config PPC_PS3
select USB_OHCI_BIG_ENDIAN_MMIO
select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_MMIO
+ select MEMORY_HOTPLUG
help
This option enables support for the Sony PS3 game console
and other platforms using the PS3 hypervisor.
@@ -73,18 +74,12 @@ config PS3_USE_LPAR_ADDR
config PS3_VUART
depends on PPC_PS3
- bool "PS3 Virtual UART support" if PS3_ADVANCED
- default y
- help
- Include support for the PS3 Virtual UART.
-
- This support is required for several system services
- including the System Manager and AV Settings. In
- general, all users will say Y.
+ tristate
config PS3_PS3AV
+ depends on PPC_PS3
tristate "PS3 AV settings driver" if PS3_ADVANCED
- depends on PS3_VUART
+ select PS3_VUART
default y
help
Include support for the PS3 AV Settings driver.
@@ -93,13 +88,54 @@ config PS3_PS3AV
general, all users will say Y or M.
config PS3_SYS_MANAGER
- bool "PS3 System Manager driver" if PS3_ADVANCED
- depends on PS3_VUART
- default y
+ depends on PPC_PS3
+ tristate "PS3 System Manager driver" if PS3_ADVANCED
+ select PS3_VUART
+ default m
help
Include support for the PS3 System Manager.
This support is required for system control. In
- general, all users will say Y.
+ general, all users will say Y or M.
+
+config PS3_STORAGE
+ depends on PPC_PS3
+ tristate
+
+config PS3_DISK
+ tristate "PS3 Disk Storage Driver"
+ depends on PPC_PS3 && BLOCK
+ select PS3_STORAGE
+ help
+ Include support for the PS3 Disk Storage.
+
+ This support is required to access the PS3 hard disk.
+ In general, all users will say Y or M.
+
+config PS3_ROM
+ tristate "PS3 BD/DVD/CD-ROM Storage Driver"
+ depends on PPC_PS3 && SCSI
+ select PS3_STORAGE
+ help
+ Include support for the PS3 ROM Storage.
+
+ This support is required to access the PS3 BD/DVD/CD-ROM drive.
+ In general, all users will say Y or M.
+ Also make sure to say Y or M to "SCSI CDROM support" later.
+
+config PS3_FLASH
+ tristate "PS3 FLASH ROM Storage Driver"
+ depends on PPC_PS3
+ select PS3_STORAGE
+ help
+ Include support for the PS3 FLASH ROM Storage.
+
+ This support is required to access the PS3 FLASH ROM, which
+ contains the boot loader and some boot options.
+ In general, all users will say Y or M.
+
+ As this driver needs a fixed buffer of 256 KiB of memory, it can
+ be disabled on the kernel command line using "ps3flash=off", to
+ not allocate this fixed buffer.
endmenu
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile
index a0048fcf0866..ac1bdf844eca 100644
--- a/arch/powerpc/platforms/ps3/Makefile
+++ b/arch/powerpc/platforms/ps3/Makefile
@@ -4,3 +4,4 @@ obj-y += system-bus.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SPU_BASE) += spu.o
+obj-y += device-init.o
diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c
new file mode 100644
index 000000000000..825ebb2cbc2a
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/device-init.c
@@ -0,0 +1,785 @@
+/*
+ * PS3 device registration routines.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/init.h>
+
+#include <asm/firmware.h>
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+#include "platform.h"
+
+/**
+ * ps3_setup_gelic_device - Setup and register a gelic device instance.
+ *
+ * Allocates memory for a struct ps3_system_bus_device instance, initialises the
+ * structure members, and registers the device instance with the system bus.
+ */
+
+static int __init ps3_setup_gelic_device(
+ const struct ps3_repository_device *repo)
+{
+ int result;
+ struct layout {
+ struct ps3_system_bus_device dev;
+ struct ps3_dma_region d_region;
+ } *p;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB);
+ BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_GELIC);
+
+ p = kzalloc(sizeof(struct layout), GFP_KERNEL);
+
+ if (!p) {
+ result = -ENOMEM;
+ goto fail_malloc;
+ }
+
+ p->dev.match_id = PS3_MATCH_ID_GELIC;
+ p->dev.dev_type = PS3_DEVICE_TYPE_SB;
+ p->dev.bus_id = repo->bus_id;
+ p->dev.dev_id = repo->dev_id;
+ p->dev.d_region = &p->d_region;
+
+ result = ps3_repository_find_interrupt(repo,
+ PS3_INTERRUPT_TYPE_EVENT_PORT, &p->dev.interrupt_id);
+
+ if (result) {
+ pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
+ __func__, __LINE__);
+ goto fail_find_interrupt;
+ }
+
+ BUG_ON(p->dev.interrupt_id != 0);
+
+ result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K,
+ PS3_DMA_OTHER, NULL, 0);
+
+ if (result) {
+ pr_debug("%s:%d ps3_dma_region_init failed\n",
+ __func__, __LINE__);
+ goto fail_dma_init;
+ }
+
+ result = ps3_system_bus_device_register(&p->dev);
+
+ if (result) {
+ pr_debug("%s:%d ps3_system_bus_device_register failed\n",
+ __func__, __LINE__);
+ goto fail_device_register;
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+
+fail_device_register:
+fail_dma_init:
+fail_find_interrupt:
+ kfree(p);
+fail_malloc:
+ pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__);
+ return result;
+}
+
+static int __init_refok ps3_setup_uhc_device(
+ const struct ps3_repository_device *repo, enum ps3_match_id match_id,
+ enum ps3_interrupt_type interrupt_type, enum ps3_reg_type reg_type)
+{
+ int result;
+ struct layout {
+ struct ps3_system_bus_device dev;
+ struct ps3_dma_region d_region;
+ struct ps3_mmio_region m_region;
+ } *p;
+ u64 bus_addr;
+ u64 len;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ BUG_ON(repo->bus_type != PS3_BUS_TYPE_SB);
+ BUG_ON(repo->dev_type != PS3_DEV_TYPE_SB_USB);
+
+ p = kzalloc(sizeof(struct layout), GFP_KERNEL);
+
+ if (!p) {
+ result = -ENOMEM;
+ goto fail_malloc;
+ }
+
+ p->dev.match_id = match_id;
+ p->dev.dev_type = PS3_DEVICE_TYPE_SB;
+ p->dev.bus_id = repo->bus_id;
+ p->dev.dev_id = repo->dev_id;
+ p->dev.d_region = &p->d_region;
+ p->dev.m_region = &p->m_region;
+
+ result = ps3_repository_find_interrupt(repo,
+ interrupt_type, &p->dev.interrupt_id);
+
+ if (result) {
+ pr_debug("%s:%d ps3_repository_find_interrupt failed\n",
+ __func__, __LINE__);
+ goto fail_find_interrupt;
+ }
+
+ result = ps3_repository_find_reg(repo, reg_type,
+ &bus_addr, &len);
+
+ if (result) {
+ pr_debug("%s:%d ps3_repository_find_reg failed\n",
+ __func__, __LINE__);
+ goto fail_find_reg;
+ }
+
+ result = ps3_dma_region_init(&p->dev, p->dev.d_region, PS3_DMA_64K,
+ PS3_DMA_INTERNAL, NULL, 0);
+
+ if (result) {
+ pr_debug("%s:%d ps3_dma_region_init failed\n",
+ __func__, __LINE__);
+ goto fail_dma_init;
+ }
+
+ result = ps3_mmio_region_init(&p->dev, p->dev.m_region, bus_addr, len,
+ PS3_MMIO_4K);
+
+ if (result) {
+ pr_debug("%s:%d ps3_mmio_region_init failed\n",
+ __func__, __LINE__);
+ goto fail_mmio_init;
+ }
+
+ result = ps3_system_bus_device_register(&p->dev);
+
+ if (result) {
+ pr_debug("%s:%d ps3_system_bus_device_register failed\n",
+ __func__, __LINE__);
+ goto fail_device_register;
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+
+fail_device_register:
+fail_mmio_init:
+fail_dma_init:
+fail_find_reg:
+fail_find_interrupt:
+ kfree(p);
+fail_malloc:
+ pr_debug(" <- %s:%d: fail.\n", __func__, __LINE__);
+ return result;
+}
+
+static int __init ps3_setup_ehci_device(
+ const struct ps3_repository_device *repo)
+{
+ return ps3_setup_uhc_device(repo, PS3_MATCH_ID_EHCI,
+ PS3_INTERRUPT_TYPE_SB_EHCI, PS3_REG_TYPE_SB_EHCI);
+}
+
+static int __init ps3_setup_ohci_device(
+ const struct ps3_repository_device *repo)
+{
+ return ps3_setup_uhc_device(repo, PS3_MATCH_ID_OHCI,
+ PS3_INTERRUPT_TYPE_SB_OHCI, PS3_REG_TYPE_SB_OHCI);
+}
+
+static int __init ps3_setup_vuart_device(enum ps3_match_id match_id,
+ unsigned int port_number)
+{
+ int result;
+ struct layout {
+ struct ps3_system_bus_device dev;
+ } *p;
+
+ pr_debug(" -> %s:%d: match_id %u, port %u\n", __func__, __LINE__,
+ match_id, port_number);
+
+ p = kzalloc(sizeof(struct layout), GFP_KERNEL);
+
+ if (!p)
+ return -ENOMEM;
+
+ p->dev.match_id = match_id;
+ p->dev.dev_type = PS3_DEVICE_TYPE_VUART;
+ p->dev.port_number = port_number;
+
+ result = ps3_system_bus_device_register(&p->dev);
+
+ if (result)
+ pr_debug("%s:%d ps3_system_bus_device_register failed\n",
+ __func__, __LINE__);
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+static int ps3stor_wait_for_completion(u64 dev_id, u64 tag,
+ unsigned int timeout)
+{
+ int result = -1;
+ unsigned int retries = 0;
+ u64 status;
+
+ for (retries = 0; retries < timeout; retries++) {
+ result = lv1_storage_check_async_status(dev_id, tag, &status);
+ if (!result)
+ break;
+
+ msleep(1);
+ }
+
+ if (result)
+ pr_debug("%s:%u: check_async_status: %s, status %lx\n",
+ __func__, __LINE__, ps3_result(result), status);
+
+ return result;
+}
+
+/**
+ * ps3_storage_wait_for_device - Wait for a storage device to become ready.
+ * @repo: The repository device to wait for.
+ *
+ * Uses the hypervisor's storage device notification mechanism to wait until
+ * a storage device is ready. The device notification mechanism uses a
+ * psuedo device (id = -1) to asynchronously notify the guest when storage
+ * devices become ready. The notification device has a block size of 512
+ * bytes.
+ */
+
+static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo)
+{
+ int result;
+ const u64 notification_dev_id = (u64)-1LL;
+ const unsigned int timeout = HZ;
+ u64 lpar;
+ u64 tag;
+ struct {
+ u64 operation_code; /* must be zero */
+ u64 event_mask; /* 1 = device ready */
+ } *notify_cmd;
+ struct {
+ u64 event_type; /* notify_device_ready */
+ u64 bus_id;
+ u64 dev_id;
+ u64 dev_type;
+ u64 dev_port;
+ } *notify_event;
+ enum {
+ notify_device_ready = 1
+ };
+
+ pr_debug(" -> %s:%u: bus_id %u, dev_id %u, dev_type %u\n", __func__,
+ __LINE__, repo->bus_id, repo->dev_id, repo->dev_type);
+
+ notify_cmd = kzalloc(512, GFP_KERNEL);
+ notify_event = (void *)notify_cmd;
+ if (!notify_cmd)
+ return -ENOMEM;
+
+ lpar = ps3_mm_phys_to_lpar(__pa(notify_cmd));
+
+ result = lv1_open_device(repo->bus_id, notification_dev_id, 0);
+ if (result) {
+ printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__,
+ __LINE__, ps3_result(result));
+ result = -ENODEV;
+ goto fail_free;
+ }
+
+ /* Setup and write the request for device notification. */
+
+ notify_cmd->operation_code = 0; /* must be zero */
+ notify_cmd->event_mask = 0x01; /* device ready */
+
+ result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar,
+ &tag);
+ if (result) {
+ printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__,
+ ps3_result(result));
+ result = -ENODEV;
+ goto fail_close;
+ }
+
+ /* Wait for the write completion */
+
+ result = ps3stor_wait_for_completion(notification_dev_id, tag,
+ timeout);
+ if (result) {
+ printk(KERN_ERR "%s:%u: write not completed %s\n", __func__,
+ __LINE__, ps3_result(result));
+ result = -ENODEV;
+ goto fail_close;
+ }
+
+ /* Loop here processing the requested notification events. */
+
+ result = -ENODEV;
+ while (1) {
+ memset(notify_event, 0, sizeof(*notify_event));
+
+ result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0,
+ lpar, &tag);
+ if (result) {
+ printk(KERN_ERR "%s:%u: write failed %s\n", __func__,
+ __LINE__, ps3_result(result));
+ break;
+ }
+
+ result = ps3stor_wait_for_completion(notification_dev_id, tag,
+ timeout);
+ if (result) {
+ printk(KERN_ERR "%s:%u: read not completed %s\n",
+ __func__, __LINE__, ps3_result(result));
+ break;
+ }
+
+ if (notify_event->event_type != notify_device_ready ||
+ notify_event->bus_id != repo->bus_id) {
+ pr_debug("%s:%u: bad notify_event: event %lu, "
+ "dev_id %lu, dev_type %lu\n",
+ __func__, __LINE__, notify_event->event_type,
+ notify_event->dev_id, notify_event->dev_type);
+ break;
+ }
+
+ if (notify_event->dev_id == repo->dev_id &&
+ notify_event->dev_type == repo->dev_type) {
+ pr_debug("%s:%u: device ready: dev_id %u\n", __func__,
+ __LINE__, repo->dev_id);
+ result = 0;
+ break;
+ }
+
+ if (notify_event->dev_id == repo->dev_id &&
+ notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) {
+ pr_debug("%s:%u: no access: dev_id %u\n", __func__,
+ __LINE__, repo->dev_id);
+ break;
+ }
+ }
+
+fail_close:
+ lv1_close_device(repo->bus_id, notification_dev_id);
+fail_free:
+ kfree(notify_cmd);
+ pr_debug(" <- %s:%u\n", __func__, __LINE__);
+ return result;
+}
+
+static int ps3_setup_storage_dev(const struct ps3_repository_device *repo,
+ enum ps3_match_id match_id)
+{
+ int result;
+ struct ps3_storage_device *p;
+ u64 port, blk_size, num_blocks;
+ unsigned int num_regions, i;
+
+ pr_debug(" -> %s:%u: match_id %u\n", __func__, __LINE__, match_id);
+
+ result = ps3_repository_read_stor_dev_info(repo->bus_index,
+ repo->dev_index, &port,
+ &blk_size, &num_blocks,
+ &num_regions);
+ if (result) {
+ printk(KERN_ERR "%s:%u: _read_stor_dev_info failed %d\n",
+ __func__, __LINE__, result);
+ return -ENODEV;
+ }
+
+ pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu "
+ "num_regions %u\n", __func__, __LINE__, repo->bus_index,
+ repo->dev_index, port, blk_size, num_blocks, num_regions);
+
+ p = kzalloc(sizeof(struct ps3_storage_device) +
+ num_regions * sizeof(struct ps3_storage_region),
+ GFP_KERNEL);
+ if (!p) {
+ result = -ENOMEM;
+ goto fail_malloc;
+ }
+
+ p->sbd.match_id = match_id;
+ p->sbd.dev_type = PS3_DEVICE_TYPE_SB;
+ p->sbd.bus_id = repo->bus_id;
+ p->sbd.dev_id = repo->dev_id;
+ p->sbd.d_region = &p->dma_region;
+ p->blk_size = blk_size;
+ p->num_regions = num_regions;
+
+ result = ps3_repository_find_interrupt(repo,
+ PS3_INTERRUPT_TYPE_EVENT_PORT,
+ &p->sbd.interrupt_id);
+ if (result) {
+ printk(KERN_ERR "%s:%u: find_interrupt failed %d\n", __func__,
+ __LINE__, result);
+ result = -ENODEV;
+ goto fail_find_interrupt;
+ }
+
+ /* FIXME: Arrange to only do this on a 'cold' boot */
+
+ result = ps3_storage_wait_for_device(repo);
+ if (result) {
+ printk(KERN_ERR "%s:%u: storage_notification failed %d\n",
+ __func__, __LINE__, result);
+ result = -ENODEV;
+ goto fail_probe_notification;
+ }
+
+ for (i = 0; i < num_regions; i++) {
+ unsigned int id;
+ u64 start, size;
+
+ result = ps3_repository_read_stor_dev_region(repo->bus_index,
+ repo->dev_index,
+ i, &id, &start,
+ &size);
+ if (result) {
+ printk(KERN_ERR
+ "%s:%u: read_stor_dev_region failed %d\n",
+ __func__, __LINE__, result);
+ result = -ENODEV;
+ goto fail_read_region;
+ }
+ pr_debug("%s:%u: region %u: id %u start %lu size %lu\n",
+ __func__, __LINE__, i, id, start, size);
+
+ p->regions[i].id = id;
+ p->regions[i].start = start;
+ p->regions[i].size = size;
+ }
+
+ result = ps3_system_bus_device_register(&p->sbd);
+ if (result) {
+ pr_debug("%s:%u ps3_system_bus_device_register failed\n",
+ __func__, __LINE__);
+ goto fail_device_register;
+ }
+
+ pr_debug(" <- %s:%u\n", __func__, __LINE__);
+ return 0;
+
+fail_device_register:
+fail_read_region:
+fail_probe_notification:
+fail_find_interrupt:
+ kfree(p);
+fail_malloc:
+ pr_debug(" <- %s:%u: fail.\n", __func__, __LINE__);
+ return result;
+}
+
+static int __init ps3_register_vuart_devices(void)
+{
+ int result;
+ unsigned int port_number;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ result = ps3_repository_read_vuart_av_port(&port_number);
+ if (result)
+ port_number = 0; /* av default */
+
+ result = ps3_setup_vuart_device(PS3_MATCH_ID_AV_SETTINGS, port_number);
+ WARN_ON(result);
+
+ result = ps3_repository_read_vuart_sysmgr_port(&port_number);
+ if (result)
+ port_number = 2; /* sysmgr default */
+
+ result = ps3_setup_vuart_device(PS3_MATCH_ID_SYSTEM_MANAGER,
+ port_number);
+ WARN_ON(result);
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+static int __init ps3_register_sound_devices(void)
+{
+ int result;
+ struct layout {
+ struct ps3_system_bus_device dev;
+ struct ps3_dma_region d_region;
+ struct ps3_mmio_region m_region;
+ } *p;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ p->dev.match_id = PS3_MATCH_ID_SOUND;
+ p->dev.dev_type = PS3_DEVICE_TYPE_IOC0;
+ p->dev.d_region = &p->d_region;
+ p->dev.m_region = &p->m_region;
+
+ result = ps3_system_bus_device_register(&p->dev);
+
+ if (result)
+ pr_debug("%s:%d ps3_system_bus_device_register failed\n",
+ __func__, __LINE__);
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+static int __init ps3_register_graphics_devices(void)
+{
+ int result;
+ struct layout {
+ struct ps3_system_bus_device dev;
+ } *p;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ p = kzalloc(sizeof(struct layout), GFP_KERNEL);
+
+ if (!p)
+ return -ENOMEM;
+
+ p->dev.match_id = PS3_MATCH_ID_GRAPHICS;
+ p->dev.dev_type = PS3_DEVICE_TYPE_IOC0;
+
+ result = ps3_system_bus_device_register(&p->dev);
+
+ if (result)
+ pr_debug("%s:%d ps3_system_bus_device_register failed\n",
+ __func__, __LINE__);
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+/**
+ * ps3_register_repository_device - Register a device from the repositiory info.
+ *
+ */
+
+static int ps3_register_repository_device(
+ const struct ps3_repository_device *repo)
+{
+ int result;
+
+ switch (repo->dev_type) {
+ case PS3_DEV_TYPE_SB_GELIC:
+ result = ps3_setup_gelic_device(repo);
+ if (result) {
+ pr_debug("%s:%d ps3_setup_gelic_device failed\n",
+ __func__, __LINE__);
+ }
+ break;
+ case PS3_DEV_TYPE_SB_USB:
+
+ /* Each USB device has both an EHCI and an OHCI HC */
+
+ result = ps3_setup_ehci_device(repo);
+
+ if (result) {
+ pr_debug("%s:%d ps3_setup_ehci_device failed\n",
+ __func__, __LINE__);
+ }
+
+ result = ps3_setup_ohci_device(repo);
+
+ if (result) {
+ pr_debug("%s:%d ps3_setup_ohci_device failed\n",
+ __func__, __LINE__);
+ }
+ break;
+ case PS3_DEV_TYPE_STOR_DISK:
+ result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK);
+
+ /* Some devices are not accessable from the Other OS lpar. */
+ if (result == -ENODEV) {
+ result = 0;
+ pr_debug("%s:%u: not accessable\n", __func__,
+ __LINE__);
+ }
+
+ if (result)
+ pr_debug("%s:%u ps3_setup_storage_dev failed\n",
+ __func__, __LINE__);
+ break;
+
+ case PS3_DEV_TYPE_STOR_ROM:
+ result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_ROM);
+ if (result)
+ pr_debug("%s:%u ps3_setup_storage_dev failed\n",
+ __func__, __LINE__);
+ break;
+
+ case PS3_DEV_TYPE_STOR_FLASH:
+ result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_FLASH);
+ if (result)
+ pr_debug("%s:%u ps3_setup_storage_dev failed\n",
+ __func__, __LINE__);
+ break;
+
+ default:
+ result = 0;
+ pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__,
+ repo->dev_type);
+ }
+
+ return result;
+}
+
+/**
+ * ps3_probe_thread - Background repository probing at system startup.
+ *
+ * This implementation only supports background probing on a single bus.
+ */
+
+static int ps3_probe_thread(void *data)
+{
+ struct ps3_repository_device *repo = data;
+ int result;
+ unsigned int ms = 250;
+
+ pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__);
+
+ do {
+ try_to_freeze();
+
+ pr_debug("%s:%u: probing...\n", __func__, __LINE__);
+
+ do {
+ result = ps3_repository_find_device(repo);
+
+ if (result == -ENODEV)
+ pr_debug("%s:%u: nothing new\n", __func__,
+ __LINE__);
+ else if (result)
+ pr_debug("%s:%u: find device error.\n",
+ __func__, __LINE__);
+ else {
+ pr_debug("%s:%u: found device\n", __func__,
+ __LINE__);
+ ps3_register_repository_device(repo);
+ ps3_repository_bump_device(repo);
+ ms = 250;
+ }
+ } while (!result);
+
+ pr_debug("%s:%u: ms %u\n", __func__, __LINE__, ms);
+
+ if ( ms > 60000)
+ break;
+
+ msleep_interruptible(ms);
+
+ /* An exponential backoff. */
+ ms <<= 1;
+
+ } while (!kthread_should_stop());
+
+ pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__);
+
+ return 0;
+}
+
+/**
+ * ps3_start_probe_thread - Starts the background probe thread.
+ *
+ */
+
+static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type)
+{
+ int result;
+ struct task_struct *task;
+ static struct ps3_repository_device repo; /* must be static */
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ memset(&repo, 0, sizeof(repo));
+
+ repo.bus_type = bus_type;
+
+ result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index);
+
+ if (result) {
+ printk(KERN_ERR "%s: Cannot find bus (%d)\n", __func__, result);
+ return -ENODEV;
+ }
+
+ result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id);
+
+ if (result) {
+ printk(KERN_ERR "%s: read_bus_id failed %d\n", __func__,
+ result);
+ return -ENODEV;
+ }
+
+ task = kthread_run(ps3_probe_thread, &repo, "ps3-probe-%u", bus_type);
+
+ if (IS_ERR(task)) {
+ result = PTR_ERR(task);
+ printk(KERN_ERR "%s: kthread_run failed %d\n", __func__,
+ result);
+ return result;
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return 0;
+}
+
+/**
+ * ps3_register_devices - Probe the system and register devices found.
+ *
+ * A device_initcall() routine.
+ */
+
+static int __init ps3_register_devices(void)
+{
+ int result;
+
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return -ENODEV;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ /* ps3_repository_dump_bus_info(); */
+
+ result = ps3_start_probe_thread(PS3_BUS_TYPE_STORAGE);
+
+ ps3_register_vuart_devices();
+
+ ps3_register_graphics_devices();
+
+ ps3_repository_find_devices(PS3_BUS_TYPE_SB,
+ ps3_register_repository_device);
+
+ ps3_register_sound_devices();
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return 0;
+}
+
+device_initcall(ps3_register_devices);
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index a1409e450c70..5d2e176a1b18 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -29,12 +29,12 @@
#include "platform.h"
#if defined(DEBUG)
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG udbg_printf
#else
-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
+#define DBG pr_debug
#endif
-static hpte_t *htab;
+static struct hash_pte *htab;
static unsigned long htab_addr;
static unsigned char *bolttab;
static unsigned char *inusetab;
@@ -44,8 +44,8 @@ static DEFINE_SPINLOCK(ps3_bolttab_lock);
#define debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g) \
_debug_dump_hpte(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__)
static void _debug_dump_hpte(unsigned long pa, unsigned long va,
- unsigned long group, unsigned long bitmap, hpte_t lhpte, int psize,
- unsigned long slot, const char* func, int line)
+ unsigned long group, unsigned long bitmap, struct hash_pte lhpte,
+ int psize, unsigned long slot, const char* func, int line)
{
DBG("%s:%d: pa = %lxh\n", func, line, pa);
DBG("%s:%d: lpar = %lxh\n", func, line,
@@ -63,7 +63,7 @@ static long ps3_hpte_insert(unsigned long hpte_group, unsigned long va,
unsigned long pa, unsigned long rflags, unsigned long vflags, int psize)
{
unsigned long slot;
- hpte_t lhpte;
+ struct hash_pte lhpte;
int secondary = 0;
unsigned long result;
unsigned long bitmap;
@@ -234,10 +234,17 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va,
static void ps3_hpte_clear(void)
{
- /* Make sure to clean up the frame buffer device first */
- ps3fb_cleanup();
+ int result;
- lv1_unmap_htab(htab_addr);
+ DBG(" -> %s:%d\n", __func__, __LINE__);
+
+ result = lv1_unmap_htab(htab_addr);
+ BUG_ON(result);
+
+ ps3_mm_shutdown();
+ ps3_mm_vas_destroy();
+
+ DBG(" <- %s:%d\n", __func__, __LINE__);
}
void __init ps3_hpte_init(unsigned long htab_size)
@@ -255,7 +262,7 @@ void __init ps3_hpte_init(unsigned long htab_size)
ppc64_pft_size = __ilog2(htab_size);
- bitmap_size = htab_size / sizeof(hpte_t) / 8;
+ bitmap_size = htab_size / sizeof(struct hash_pte) / 8;
bolttab = __va(lmb_alloc(bitmap_size, 1));
inusetab = __va(lmb_alloc(bitmap_size, 1));
@@ -273,8 +280,8 @@ void __init ps3_map_htab(void)
result = lv1_map_htab(0, &htab_addr);
- htab = (hpte_t *)__ioremap(htab_addr, htab_size,
- pgprot_val(PAGE_READONLY_X));
+ htab = (__force struct hash_pte *)ioremap_flags(htab_addr, htab_size,
+ pgprot_val(PAGE_READONLY_X));
DBG("%s:%d: lpar %016lxh, virt %016lxh\n", __func__, __LINE__,
htab_addr, (unsigned long)htab);
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index ec9030dbb5f1..67e32ec9b37e 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -30,9 +30,9 @@
#include "platform.h"
#if defined(DEBUG)
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG udbg_printf
#else
-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
+#define DBG pr_debug
#endif
/**
@@ -78,19 +78,85 @@ struct ps3_bmp {
/**
* struct ps3_private - a per cpu data structure
* @bmp: ps3_bmp structure
- * @node: HV logical_ppe_id
- * @cpu: HV thread_id
+ * @ppe_id: HV logical_ppe_id
+ * @thread_id: HV thread_id
*/
struct ps3_private {
struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
- u64 node;
- unsigned int cpu;
+ u64 ppe_id;
+ u64 thread_id;
};
static DEFINE_PER_CPU(struct ps3_private, ps3_private);
/**
+ * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp.
+ * @virq: The assigned Linux virq.
+ *
+ * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
+ */
+
+static void ps3_chip_mask(unsigned int virq)
+{
+ struct ps3_private *pd = get_irq_chip_data(virq);
+ unsigned long flags;
+
+ pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__,
+ pd->thread_id, virq);
+
+ local_irq_save(flags);
+ clear_bit(63 - virq, &pd->bmp.mask);
+ lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
+ local_irq_restore(flags);
+}
+
+/**
+ * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp.
+ * @virq: The assigned Linux virq.
+ *
+ * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask().
+ */
+
+static void ps3_chip_unmask(unsigned int virq)
+{
+ struct ps3_private *pd = get_irq_chip_data(virq);
+ unsigned long flags;
+
+ pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__,
+ pd->thread_id, virq);
+
+ local_irq_save(flags);
+ set_bit(63 - virq, &pd->bmp.mask);
+ lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
+ local_irq_restore(flags);
+}
+
+/**
+ * ps3_chip_eoi - HV end-of-interrupt.
+ * @virq: The assigned Linux virq.
+ *
+ * Calls lv1_end_of_interrupt_ext().
+ */
+
+static void ps3_chip_eoi(unsigned int virq)
+{
+ const struct ps3_private *pd = get_irq_chip_data(virq);
+ lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq);
+}
+
+/**
+ * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip.
+ */
+
+static struct irq_chip ps3_irq_chip = {
+ .typename = "ps3",
+ .mask = ps3_chip_mask,
+ .unmask = ps3_chip_unmask,
+ .eoi = ps3_chip_eoi,
+};
+
+/**
* ps3_virq_setup - virq related setup.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
@@ -134,6 +200,8 @@ int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
goto fail_set;
}
+ ps3_chip_mask(*virq);
+
return result;
fail_set:
@@ -153,8 +221,8 @@ int ps3_virq_destroy(unsigned int virq)
{
const struct ps3_private *pd = get_irq_chip_data(virq);
- pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
- pd->node, pd->cpu, virq);
+ pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__,
+ __LINE__, pd->ppe_id, pd->thread_id, virq);
set_irq_chip_data(virq, NULL);
irq_dispose_mapping(virq);
@@ -190,7 +258,8 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
/* Binds outlet to cpu + virq. */
- result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
+ result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq,
+ outlet, 0);
if (result) {
pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
@@ -222,10 +291,12 @@ int ps3_irq_plug_destroy(unsigned int virq)
int result;
const struct ps3_private *pd = get_irq_chip_data(virq);
- pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
- pd->node, pd->cpu, virq);
+ pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__,
+ __LINE__, pd->ppe_id, pd->thread_id, virq);
+
+ ps3_chip_mask(virq);
- result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
+ result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);
if (result)
pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
@@ -282,7 +353,9 @@ int ps3_event_receive_port_destroy(unsigned int virq)
{
int result;
- pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq);
+ pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq);
+
+ ps3_chip_mask(virq);
result = lv1_destruct_event_receive_port(virq_to_hw(virq));
@@ -290,17 +363,14 @@ int ps3_event_receive_port_destroy(unsigned int virq)
pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
__func__, __LINE__, ps3_result(result));
- /* lv1_destruct_event_receive_port() destroys the IRQ plug,
- * so don't call ps3_irq_plug_destroy() here.
+ /*
+ * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu()
+ * calls from interrupt context (smp_call_function) when kexecing.
*/
- result = ps3_virq_destroy(virq);
- BUG_ON(result);
-
pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
}
-EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy);
int ps3_send_event_locally(unsigned int virq)
{
@@ -311,17 +381,15 @@ int ps3_send_event_locally(unsigned int virq)
* ps3_sb_event_receive_port_setup - Setup a system bus event receive port.
* @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
* serviced on.
- * @did: The HV device identifier read from the system repository.
- * @interrupt_id: The device interrupt id read from the system repository.
+ * @dev: The system bus device instance.
* @virq: The assigned Linux virq.
*
* An event irq represents a virtual device interrupt. The interrupt_id
* coresponds to the software interrupt number.
*/
-int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
- const struct ps3_device_id *did, unsigned int interrupt_id,
- unsigned int *virq)
+int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
+ enum ps3_cpu_binding cpu, unsigned int *virq)
{
/* this should go in system-bus.c */
@@ -332,8 +400,8 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
if (result)
return result;
- result = lv1_connect_interrupt_event_receive_port(did->bus_id,
- did->dev_id, virq_to_hw(*virq), interrupt_id);
+ result = lv1_connect_interrupt_event_receive_port(dev->bus_id,
+ dev->dev_id, virq_to_hw(*virq), dev->interrupt_id);
if (result) {
pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
@@ -345,24 +413,24 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
}
pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
- interrupt_id, *virq);
+ dev->interrupt_id, *virq);
return 0;
}
EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
-int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
- unsigned int interrupt_id, unsigned int virq)
+int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
+ unsigned int virq)
{
/* this should go in system-bus.c */
int result;
pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
- interrupt_id, virq);
+ dev->interrupt_id, virq);
- result = lv1_disconnect_interrupt_event_receive_port(did->bus_id,
- did->dev_id, virq_to_hw(virq), interrupt_id);
+ result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id,
+ dev->dev_id, virq_to_hw(virq), dev->interrupt_id);
if (result)
pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port"
@@ -372,6 +440,14 @@ int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
result = ps3_event_receive_port_destroy(virq);
BUG_ON(result);
+ /*
+ * ps3_event_receive_port_destroy() destroys the IRQ plug,
+ * so don't call ps3_irq_plug_destroy() here.
+ */
+
+ result = ps3_virq_destroy(virq);
+ BUG_ON(result);
+
pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -412,16 +488,24 @@ EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
int ps3_io_irq_destroy(unsigned int virq)
{
int result;
+ unsigned long outlet = virq_to_hw(virq);
- result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
+ ps3_chip_mask(virq);
- if (result)
- pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
- __func__, __LINE__, ps3_result(result));
+ /*
+ * lv1_destruct_io_irq_outlet() will destroy the IRQ plug,
+ * so call ps3_irq_plug_destroy() first.
+ */
result = ps3_irq_plug_destroy(virq);
BUG_ON(result);
+ result = lv1_destruct_io_irq_outlet(outlet);
+
+ if (result)
+ pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
return result;
}
EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
@@ -461,11 +545,13 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
return result;
}
+EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup);
int ps3_vuart_irq_destroy(unsigned int virq)
{
int result;
+ ps3_chip_mask(virq);
result = lv1_deconfigure_virtual_uart_irq();
if (result) {
@@ -479,6 +565,7 @@ int ps3_vuart_irq_destroy(unsigned int virq)
return result;
}
+EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy);
/**
* ps3_spe_irq_setup - Setup an spe virq.
@@ -514,9 +601,14 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
int ps3_spe_irq_destroy(unsigned int virq)
{
- int result = ps3_irq_plug_destroy(virq);
+ int result;
+
+ ps3_chip_mask(virq);
+
+ result = ps3_irq_plug_destroy(virq);
BUG_ON(result);
- return 0;
+
+ return result;
}
@@ -533,7 +625,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
*p & 0xffff);
}
-static void __attribute__ ((unused)) _dump_256_bmp(const char *header,
+static void __maybe_unused _dump_256_bmp(const char *header,
const u64 *p, unsigned cpu, const char* func, int line)
{
pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
@@ -546,86 +638,25 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
unsigned long flags;
spin_lock_irqsave(&pd->bmp.lock, flags);
- _dump_64_bmp("stat", &pd->bmp.status, pd->cpu, func, line);
- _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line);
+ _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line);
+ _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
spin_unlock_irqrestore(&pd->bmp.lock, flags);
}
#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
-static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
+static void __maybe_unused _dump_mask(struct ps3_private *pd,
const char* func, int line)
{
unsigned long flags;
spin_lock_irqsave(&pd->bmp.lock, flags);
- _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line);
+ _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
spin_unlock_irqrestore(&pd->bmp.lock, flags);
}
#else
static void dump_bmp(struct ps3_private* pd) {};
#endif /* defined(DEBUG) */
-static void ps3_chip_mask(unsigned int virq)
-{
- struct ps3_private *pd = get_irq_chip_data(virq);
- u64 bit = 0x8000000000000000UL >> virq;
- u64 *p = &pd->bmp.mask;
- u64 old;
- unsigned long flags;
-
- pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
-
- local_irq_save(flags);
- asm volatile(
- "1: ldarx %0,0,%3\n"
- "andc %0,%0,%2\n"
- "stdcx. %0,0,%3\n"
- "bne- 1b"
- : "=&r" (old), "+m" (*p)
- : "r" (bit), "r" (p)
- : "cc" );
-
- lv1_did_update_interrupt_mask(pd->node, pd->cpu);
- local_irq_restore(flags);
-}
-
-static void ps3_chip_unmask(unsigned int virq)
-{
- struct ps3_private *pd = get_irq_chip_data(virq);
- u64 bit = 0x8000000000000000UL >> virq;
- u64 *p = &pd->bmp.mask;
- u64 old;
- unsigned long flags;
-
- pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
-
- local_irq_save(flags);
- asm volatile(
- "1: ldarx %0,0,%3\n"
- "or %0,%0,%2\n"
- "stdcx. %0,0,%3\n"
- "bne- 1b"
- : "=&r" (old), "+m" (*p)
- : "r" (bit), "r" (p)
- : "cc" );
-
- lv1_did_update_interrupt_mask(pd->node, pd->cpu);
- local_irq_restore(flags);
-}
-
-static void ps3_chip_eoi(unsigned int virq)
-{
- const struct ps3_private *pd = get_irq_chip_data(virq);
- lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
-}
-
-static struct irq_chip irq_chip = {
- .typename = "ps3",
- .mask = ps3_chip_mask,
- .unmask = ps3_chip_unmask,
- .eoi = ps3_chip_eoi,
-};
-
static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
{
set_irq_chip_data(virq, NULL);
@@ -637,7 +668,7 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq,
pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
virq);
- set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
+ set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq);
return 0;
}
@@ -657,7 +688,7 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
cpu, virq, pd->bmp.ipi_debug_brk_mask);
}
-unsigned int ps3_get_irq(void)
+static unsigned int ps3_get_irq(void)
{
struct ps3_private *pd = &__get_cpu_var(ps3_private);
u64 x = (pd->bmp.status & pd->bmp.mask);
@@ -672,8 +703,8 @@ unsigned int ps3_get_irq(void)
plug &= 0x3f;
if (unlikely(plug) == NO_IRQ) {
- pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
- pd->cpu);
+ pr_debug("%s:%d: no plug found: thread_id %lu\n", __func__,
+ __LINE__, pd->thread_id);
dump_bmp(&per_cpu(ps3_private, 0));
dump_bmp(&per_cpu(ps3_private, 1));
return NO_IRQ;
@@ -703,16 +734,16 @@ void __init ps3_init_IRQ(void)
for_each_possible_cpu(cpu) {
struct ps3_private *pd = &per_cpu(ps3_private, cpu);
- lv1_get_logical_ppe_id(&pd->node);
- pd->cpu = get_hard_smp_processor_id(cpu);
+ lv1_get_logical_ppe_id(&pd->ppe_id);
+ pd->thread_id = get_hard_smp_processor_id(cpu);
spin_lock_init(&pd->bmp.lock);
- pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__,
- __LINE__, pd->node, pd->cpu,
+ pr_debug("%s:%d: ppe_id %lu, thread_id %lu, bmp %lxh\n",
+ __func__, __LINE__, pd->ppe_id, pd->thread_id,
ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
- result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu,
- ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
+ result = lv1_configure_irq_state_bitmap(pd->ppe_id,
+ pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
if (result)
pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
@@ -722,3 +753,16 @@ void __init ps3_init_IRQ(void)
ppc_md.get_irq = ps3_get_irq;
}
+
+void ps3_shutdown_IRQ(int cpu)
+{
+ int result;
+ u64 ppe_id;
+ u64 thread_id = get_hard_smp_processor_id(cpu);
+
+ lv1_get_logical_ppe_id(&ppe_id);
+ result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0);
+
+ DBG("%s:%d: lv1_configure_irq_state_bitmap (%lu:%lu/%d) %s\n", __func__,
+ __LINE__, ppe_id, thread_id, cpu, ps3_result(result));
+}
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index f8a3e206c584..7bb3e1620974 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -30,9 +30,9 @@
#include "platform.h"
#if defined(DEBUG)
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG udbg_printf
#else
-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
+#define DBG pr_debug
#endif
enum {
@@ -115,7 +115,8 @@ struct map {
};
#define debug_dump_map(x) _debug_dump_map(x, __func__, __LINE__)
-static void _debug_dump_map(const struct map* m, const char* func, int line)
+static void __maybe_unused _debug_dump_map(const struct map *m,
+ const char *func, int line)
{
DBG("%s:%d: map.total = %lxh\n", func, line, m->total);
DBG("%s:%d: map.rm.size = %lxh\n", func, line, m->rm.size);
@@ -212,9 +213,15 @@ fail:
void ps3_mm_vas_destroy(void)
{
+ int result;
+
+ DBG("%s:%d: map.vas_id = %lu\n", __func__, __LINE__, map.vas_id);
+
if (map.vas_id) {
- lv1_select_virtual_address_space(0);
- lv1_destruct_virtual_address_space(map.vas_id);
+ result = lv1_select_virtual_address_space(0);
+ BUG_ON(result);
+ result = lv1_destruct_virtual_address_space(map.vas_id);
+ BUG_ON(result);
map.vas_id = 0;
}
}
@@ -232,7 +239,7 @@ void ps3_mm_vas_destroy(void)
* @size is rounded down to a multiple of the vas large page size.
*/
-int ps3_mm_region_create(struct mem_region *r, unsigned long size)
+static int ps3_mm_region_create(struct mem_region *r, unsigned long size)
{
int result;
unsigned long muid;
@@ -273,10 +280,14 @@ zero_region:
* @r: pointer to struct mem_region
*/
-void ps3_mm_region_destroy(struct mem_region *r)
+static void ps3_mm_region_destroy(struct mem_region *r)
{
+ int result;
+
+ DBG("%s:%d: r->base = %lxh\n", __func__, __LINE__, r->base);
if (r->base) {
- lv1_release_memory(r->base);
+ result = lv1_release_memory(r->base);
+ BUG_ON(result);
r->size = r->base = r->offset = 0;
map.total = map.rm.size;
}
@@ -329,31 +340,34 @@ core_initcall(ps3_mm_add_memory);
/*============================================================================*/
/**
- * dma_lpar_to_bus - Translate an lpar address to ioc mapped bus address.
+ * dma_sb_lpar_to_bus - Translate an lpar address to ioc mapped bus address.
* @r: pointer to dma region structure
* @lpar_addr: HV lpar address
*/
-static unsigned long dma_lpar_to_bus(struct ps3_dma_region *r,
+static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r,
unsigned long lpar_addr)
{
- BUG_ON(lpar_addr >= map.r1.base + map.r1.size);
- return r->bus_addr + (lpar_addr <= map.rm.size ? lpar_addr
- : lpar_addr - map.r1.offset);
+ if (lpar_addr >= map.rm.size)
+ lpar_addr -= map.r1.offset;
+ BUG_ON(lpar_addr < r->offset);
+ BUG_ON(lpar_addr >= r->offset + r->len);
+ return r->bus_addr + lpar_addr - r->offset;
}
#define dma_dump_region(_a) _dma_dump_region(_a, __func__, __LINE__)
-static void _dma_dump_region(const struct ps3_dma_region *r, const char* func,
- int line)
+static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r,
+ const char *func, int line)
{
- DBG("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
- r->did.dev_id);
+ DBG("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id,
+ r->dev->dev_id);
DBG("%s:%d: page_size %u\n", func, line, r->page_size);
DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
DBG("%s:%d: len %lxh\n", func, line, r->len);
+ DBG("%s:%d: offset %lxh\n", func, line, r->offset);
}
-/**
+ /**
* dma_chunk - A chunk of dma pages mapped by the io controller.
* @region - The dma region that owns this chunk.
* @lpar_addr: Starting lpar address of the area to map.
@@ -381,10 +395,11 @@ static void _dma_dump_chunk (const struct dma_chunk* c, const char* func,
int line)
{
DBG("%s:%d: r.dev %u:%u\n", func, line,
- c->region->did.bus_id, c->region->did.dev_id);
+ c->region->dev->bus_id, c->region->dev->dev_id);
DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr);
DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size);
DBG("%s:%d: r.len %lxh\n", func, line, c->region->len);
+ DBG("%s:%d: r.offset %lxh\n", func, line, c->region->offset);
DBG("%s:%d: c.lpar_addr %lxh\n", func, line, c->lpar_addr);
DBG("%s:%d: c.bus_addr %lxh\n", func, line, c->bus_addr);
DBG("%s:%d: c.len %lxh\n", func, line, c->len);
@@ -395,39 +410,68 @@ static struct dma_chunk * dma_find_chunk(struct ps3_dma_region *r,
{
struct dma_chunk *c;
unsigned long aligned_bus = _ALIGN_DOWN(bus_addr, 1 << r->page_size);
- unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len+bus_addr-aligned_bus,
+ 1 << r->page_size);
list_for_each_entry(c, &r->chunk_list.head, link) {
/* intersection */
- if (aligned_bus >= c->bus_addr
- && aligned_bus < c->bus_addr + c->len
- && aligned_bus + aligned_len <= c->bus_addr + c->len) {
+ if (aligned_bus >= c->bus_addr &&
+ aligned_bus + aligned_len <= c->bus_addr + c->len)
return c;
- }
+
/* below */
- if (aligned_bus + aligned_len <= c->bus_addr) {
+ if (aligned_bus + aligned_len <= c->bus_addr)
continue;
- }
+
/* above */
- if (aligned_bus >= c->bus_addr + c->len) {
+ if (aligned_bus >= c->bus_addr + c->len)
continue;
- }
/* we don't handle the multi-chunk case for now */
-
dma_dump_chunk(c);
BUG();
}
return NULL;
}
-static int dma_free_chunk(struct dma_chunk *c)
+static struct dma_chunk *dma_find_chunk_lpar(struct ps3_dma_region *r,
+ unsigned long lpar_addr, unsigned long len)
+{
+ struct dma_chunk *c;
+ unsigned long aligned_lpar = _ALIGN_DOWN(lpar_addr, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + lpar_addr - aligned_lpar,
+ 1 << r->page_size);
+
+ list_for_each_entry(c, &r->chunk_list.head, link) {
+ /* intersection */
+ if (c->lpar_addr <= aligned_lpar &&
+ aligned_lpar < c->lpar_addr + c->len) {
+ if (aligned_lpar + aligned_len <= c->lpar_addr + c->len)
+ return c;
+ else {
+ dma_dump_chunk(c);
+ BUG();
+ }
+ }
+ /* below */
+ if (aligned_lpar + aligned_len <= c->lpar_addr) {
+ continue;
+ }
+ /* above */
+ if (c->lpar_addr + c->len <= aligned_lpar) {
+ continue;
+ }
+ }
+ return NULL;
+}
+
+static int dma_sb_free_chunk(struct dma_chunk *c)
{
int result = 0;
if (c->bus_addr) {
- result = lv1_unmap_device_dma_region(c->region->did.bus_id,
- c->region->did.dev_id, c->bus_addr, c->len);
+ result = lv1_unmap_device_dma_region(c->region->dev->bus_id,
+ c->region->dev->dev_id, c->bus_addr, c->len);
BUG_ON(result);
}
@@ -435,8 +479,39 @@ static int dma_free_chunk(struct dma_chunk *c)
return result;
}
+static int dma_ioc0_free_chunk(struct dma_chunk *c)
+{
+ int result = 0;
+ int iopage;
+ unsigned long offset;
+ struct ps3_dma_region *r = c->region;
+
+ DBG("%s:start\n", __func__);
+ for (iopage = 0; iopage < (c->len >> r->page_size); iopage++) {
+ offset = (1 << r->page_size) * iopage;
+ /* put INVALID entry */
+ result = lv1_put_iopte(0,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid,
+ 0);
+ DBG("%s: bus=%#lx, lpar=%#lx, ioid=%d\n", __func__,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid);
+
+ if (result) {
+ DBG("%s:%d: lv1_put_iopte failed: %s\n", __func__,
+ __LINE__, ps3_result(result));
+ }
+ }
+ kfree(c);
+ DBG("%s:end\n", __func__);
+ return result;
+}
+
/**
- * dma_map_pages - Maps dma pages into the io controller bus address space.
+ * dma_sb_map_pages - Maps dma pages into the io controller bus address space.
* @r: Pointer to a struct ps3_dma_region.
* @phys_addr: Starting physical address of the area to map.
* @len: Length in bytes of the area to map.
@@ -446,8 +521,8 @@ static int dma_free_chunk(struct dma_chunk *c)
* make the HV call to add the pages into the io controller address space.
*/
-static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
- unsigned long len, struct dma_chunk **c_out)
+static int dma_sb_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
+ unsigned long len, struct dma_chunk **c_out, u64 iopte_flag)
{
int result;
struct dma_chunk *c;
@@ -461,13 +536,13 @@ static int dma_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
c->region = r;
c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
- c->bus_addr = dma_lpar_to_bus(r, c->lpar_addr);
+ c->bus_addr = dma_sb_lpar_to_bus(r, c->lpar_addr);
c->len = len;
- result = lv1_map_device_dma_region(c->region->did.bus_id,
- c->region->did.dev_id, c->lpar_addr, c->bus_addr, c->len,
- 0xf800000000000000UL);
-
+ BUG_ON(iopte_flag != 0xf800000000000000UL);
+ result = lv1_map_device_dma_region(c->region->dev->bus_id,
+ c->region->dev->dev_id, c->lpar_addr,
+ c->bus_addr, c->len, iopte_flag);
if (result) {
DBG("%s:%d: lv1_map_device_dma_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
@@ -487,26 +562,120 @@ fail_alloc:
return result;
}
+static int dma_ioc0_map_pages(struct ps3_dma_region *r, unsigned long phys_addr,
+ unsigned long len, struct dma_chunk **c_out,
+ u64 iopte_flag)
+{
+ int result;
+ struct dma_chunk *c, *last;
+ int iopage, pages;
+ unsigned long offset;
+
+ DBG(KERN_ERR "%s: phy=%#lx, lpar%#lx, len=%#lx\n", __func__,
+ phys_addr, ps3_mm_phys_to_lpar(phys_addr), len);
+ c = kzalloc(sizeof(struct dma_chunk), GFP_ATOMIC);
+
+ if (!c) {
+ result = -ENOMEM;
+ goto fail_alloc;
+ }
+
+ c->region = r;
+ c->len = len;
+ c->lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
+ /* allocate IO address */
+ if (list_empty(&r->chunk_list.head)) {
+ /* first one */
+ c->bus_addr = r->bus_addr;
+ } else {
+ /* derive from last bus addr*/
+ last = list_entry(r->chunk_list.head.next,
+ struct dma_chunk, link);
+ c->bus_addr = last->bus_addr + last->len;
+ DBG("%s: last bus=%#lx, len=%#lx\n", __func__,
+ last->bus_addr, last->len);
+ }
+
+ /* FIXME: check whether length exceeds region size */
+
+ /* build ioptes for the area */
+ pages = len >> r->page_size;
+ DBG("%s: pgsize=%#x len=%#lx pages=%#x iopteflag=%#lx\n", __func__,
+ r->page_size, r->len, pages, iopte_flag);
+ for (iopage = 0; iopage < pages; iopage++) {
+ offset = (1 << r->page_size) * iopage;
+ result = lv1_put_iopte(0,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid,
+ iopte_flag);
+ if (result) {
+ printk(KERN_WARNING "%s:%d: lv1_map_device_dma_region "
+ "failed: %s\n", __func__, __LINE__,
+ ps3_result(result));
+ goto fail_map;
+ }
+ DBG("%s: pg=%d bus=%#lx, lpar=%#lx, ioid=%#x\n", __func__,
+ iopage, c->bus_addr + offset, c->lpar_addr + offset,
+ r->ioid);
+ }
+
+ /* be sure that last allocated one is inserted at head */
+ list_add(&c->link, &r->chunk_list.head);
+
+ *c_out = c;
+ DBG("%s: end\n", __func__);
+ return 0;
+
+fail_map:
+ for (iopage--; 0 <= iopage; iopage--) {
+ lv1_put_iopte(0,
+ c->bus_addr + offset,
+ c->lpar_addr + offset,
+ r->ioid,
+ 0);
+ }
+ kfree(c);
+fail_alloc:
+ *c_out = NULL;
+ return result;
+}
+
/**
- * dma_region_create - Create a device dma region.
+ * dma_sb_region_create - Create a device dma region.
* @r: Pointer to a struct ps3_dma_region.
*
* This is the lowest level dma region create routine, and is the one that
* will make the HV call to create the region.
*/
-static int dma_region_create(struct ps3_dma_region* r)
+static int dma_sb_region_create(struct ps3_dma_region *r)
{
int result;
- r->len = _ALIGN_UP(map.total, 1 << r->page_size);
+ pr_info(" -> %s:%d:\n", __func__, __LINE__);
+
+ BUG_ON(!r);
+
+ if (!r->dev->bus_id) {
+ pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__,
+ r->dev->bus_id, r->dev->dev_id);
+ return 0;
+ }
+
+ DBG("%s:%u: len = 0x%lx, page_size = %u, offset = 0x%lx\n", __func__,
+ __LINE__, r->len, r->page_size, r->offset);
+
+ BUG_ON(!r->len);
+ BUG_ON(!r->page_size);
+ BUG_ON(!r->region_ops);
+
INIT_LIST_HEAD(&r->chunk_list.head);
spin_lock_init(&r->chunk_list.lock);
- result = lv1_allocate_device_dma_region(r->did.bus_id, r->did.dev_id,
- r->len, r->page_size, r->region_type, &r->bus_addr);
-
- dma_dump_region(r);
+ result = lv1_allocate_device_dma_region(r->dev->bus_id, r->dev->dev_id,
+ roundup_pow_of_two(r->len), r->page_size, r->region_type,
+ &r->bus_addr);
if (result) {
DBG("%s:%d: lv1_allocate_device_dma_region failed: %s\n",
@@ -517,6 +686,27 @@ static int dma_region_create(struct ps3_dma_region* r)
return result;
}
+static int dma_ioc0_region_create(struct ps3_dma_region *r)
+{
+ int result;
+
+ INIT_LIST_HEAD(&r->chunk_list.head);
+ spin_lock_init(&r->chunk_list.lock);
+
+ result = lv1_allocate_io_segment(0,
+ r->len,
+ r->page_size,
+ &r->bus_addr);
+ if (result) {
+ DBG("%s:%d: lv1_allocate_io_segment failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ r->len = r->bus_addr = 0;
+ }
+ DBG("%s: len=%#lx, pg=%d, bus=%#lx\n", __func__,
+ r->len, r->page_size, r->bus_addr);
+ return result;
+}
+
/**
* dma_region_free - Free a device dma region.
* @r: Pointer to a struct ps3_dma_region.
@@ -525,31 +715,62 @@ static int dma_region_create(struct ps3_dma_region* r)
* will make the HV call to free the region.
*/
-static int dma_region_free(struct ps3_dma_region* r)
+static int dma_sb_region_free(struct ps3_dma_region *r)
{
int result;
struct dma_chunk *c;
struct dma_chunk *tmp;
+ BUG_ON(!r);
+
+ if (!r->dev->bus_id) {
+ pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__,
+ r->dev->bus_id, r->dev->dev_id);
+ return 0;
+ }
+
list_for_each_entry_safe(c, tmp, &r->chunk_list.head, link) {
list_del(&c->link);
- dma_free_chunk(c);
+ dma_sb_free_chunk(c);
}
- result = lv1_free_device_dma_region(r->did.bus_id, r->did.dev_id,
+ result = lv1_free_device_dma_region(r->dev->bus_id, r->dev->dev_id,
r->bus_addr);
if (result)
DBG("%s:%d: lv1_free_device_dma_region failed: %s\n",
__func__, __LINE__, ps3_result(result));
- r->len = r->bus_addr = 0;
+ r->bus_addr = 0;
+
+ return result;
+}
+
+static int dma_ioc0_region_free(struct ps3_dma_region *r)
+{
+ int result;
+ struct dma_chunk *c, *n;
+
+ DBG("%s: start\n", __func__);
+ list_for_each_entry_safe(c, n, &r->chunk_list.head, link) {
+ list_del(&c->link);
+ dma_ioc0_free_chunk(c);
+ }
+
+ result = lv1_release_io_segment(0, r->bus_addr);
+
+ if (result)
+ DBG("%s:%d: lv1_free_device_dma_region failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+
+ r->bus_addr = 0;
+ DBG("%s: end\n", __func__);
return result;
}
/**
- * dma_map_area - Map an area of memory into a device dma region.
+ * dma_sb_map_area - Map an area of memory into a device dma region.
* @r: Pointer to a struct ps3_dma_region.
* @virt_addr: Starting virtual address of the area to map.
* @len: Length in bytes of the area to map.
@@ -559,16 +780,19 @@ static int dma_region_free(struct ps3_dma_region* r)
* This is the common dma mapping routine.
*/
-static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
- unsigned long len, unsigned long *bus_addr)
+static int dma_sb_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
{
int result;
unsigned long flags;
struct dma_chunk *c;
unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
: virt_addr;
-
- *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
+ unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys,
+ 1 << r->page_size);
+ *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
if (!USE_DYNAMIC_DMA) {
unsigned long lpar_addr = ps3_mm_phys_to_lpar(phys_addr);
@@ -588,17 +812,18 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
c = dma_find_chunk(r, *bus_addr, len);
if (c) {
+ DBG("%s:%d: reusing mapped chunk", __func__, __LINE__);
+ dma_dump_chunk(c);
c->usage_count++;
spin_unlock_irqrestore(&r->chunk_list.lock, flags);
return 0;
}
- result = dma_map_pages(r, _ALIGN_DOWN(phys_addr, 1 << r->page_size),
- _ALIGN_UP(len, 1 << r->page_size), &c);
+ result = dma_sb_map_pages(r, aligned_phys, aligned_len, &c, iopte_flag);
if (result) {
*bus_addr = 0;
- DBG("%s:%d: dma_map_pages failed (%d)\n",
+ DBG("%s:%d: dma_sb_map_pages failed (%d)\n",
__func__, __LINE__, result);
spin_unlock_irqrestore(&r->chunk_list.lock, flags);
return result;
@@ -610,8 +835,57 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
return result;
}
+static int dma_ioc0_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
+{
+ int result;
+ unsigned long flags;
+ struct dma_chunk *c;
+ unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
+ : virt_addr;
+ unsigned long aligned_phys = _ALIGN_DOWN(phys_addr, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + phys_addr - aligned_phys,
+ 1 << r->page_size);
+
+ DBG(KERN_ERR "%s: vaddr=%#lx, len=%#lx\n", __func__,
+ virt_addr, len);
+ DBG(KERN_ERR "%s: ph=%#lx a_ph=%#lx a_l=%#lx\n", __func__,
+ phys_addr, aligned_phys, aligned_len);
+
+ spin_lock_irqsave(&r->chunk_list.lock, flags);
+ c = dma_find_chunk_lpar(r, ps3_mm_phys_to_lpar(phys_addr), len);
+
+ if (c) {
+ /* FIXME */
+ BUG();
+ *bus_addr = c->bus_addr + phys_addr - aligned_phys;
+ c->usage_count++;
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ return 0;
+ }
+
+ result = dma_ioc0_map_pages(r, aligned_phys, aligned_len, &c,
+ iopte_flag);
+
+ if (result) {
+ *bus_addr = 0;
+ DBG("%s:%d: dma_ioc0_map_pages failed (%d)\n",
+ __func__, __LINE__, result);
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ return result;
+ }
+ *bus_addr = c->bus_addr + phys_addr - aligned_phys;
+ DBG("%s: va=%#lx pa=%#lx a_pa=%#lx bus=%#lx\n", __func__,
+ virt_addr, phys_addr, aligned_phys, *bus_addr);
+ c->usage_count = 1;
+
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ return result;
+}
+
/**
- * dma_unmap_area - Unmap an area of memory from a device dma region.
+ * dma_sb_unmap_area - Unmap an area of memory from a device dma region.
* @r: Pointer to a struct ps3_dma_region.
* @bus_addr: The starting ioc bus address of the area to unmap.
* @len: Length in bytes of the area to unmap.
@@ -619,7 +893,7 @@ static int dma_map_area(struct ps3_dma_region *r, unsigned long virt_addr,
* This is the common dma unmap routine.
*/
-int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
+static int dma_sb_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
unsigned long len)
{
unsigned long flags;
@@ -631,7 +905,8 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
if (!c) {
unsigned long aligned_bus = _ALIGN_DOWN(bus_addr,
1 << r->page_size);
- unsigned long aligned_len = _ALIGN_UP(len, 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + bus_addr
+ - aligned_bus, 1 << r->page_size);
DBG("%s:%d: not found: bus_addr %lxh\n",
__func__, __LINE__, bus_addr);
DBG("%s:%d: not found: len %lxh\n",
@@ -647,94 +922,166 @@ int dma_unmap_area(struct ps3_dma_region *r, unsigned long bus_addr,
if (!c->usage_count) {
list_del(&c->link);
- dma_free_chunk(c);
+ dma_sb_free_chunk(c);
}
spin_unlock_irqrestore(&r->chunk_list.lock, flags);
return 0;
}
+static int dma_ioc0_unmap_area(struct ps3_dma_region *r,
+ unsigned long bus_addr, unsigned long len)
+{
+ unsigned long flags;
+ struct dma_chunk *c;
+
+ DBG("%s: start a=%#lx l=%#lx\n", __func__, bus_addr, len);
+ spin_lock_irqsave(&r->chunk_list.lock, flags);
+ c = dma_find_chunk(r, bus_addr, len);
+
+ if (!c) {
+ unsigned long aligned_bus = _ALIGN_DOWN(bus_addr,
+ 1 << r->page_size);
+ unsigned long aligned_len = _ALIGN_UP(len + bus_addr
+ - aligned_bus,
+ 1 << r->page_size);
+ DBG("%s:%d: not found: bus_addr %lxh\n",
+ __func__, __LINE__, bus_addr);
+ DBG("%s:%d: not found: len %lxh\n",
+ __func__, __LINE__, len);
+ DBG("%s:%d: not found: aligned_bus %lxh\n",
+ __func__, __LINE__, aligned_bus);
+ DBG("%s:%d: not found: aligned_len %lxh\n",
+ __func__, __LINE__, aligned_len);
+ BUG();
+ }
+
+ c->usage_count--;
+
+ if (!c->usage_count) {
+ list_del(&c->link);
+ dma_ioc0_free_chunk(c);
+ }
+
+ spin_unlock_irqrestore(&r->chunk_list.lock, flags);
+ DBG("%s: end\n", __func__);
+ return 0;
+}
+
/**
- * dma_region_create_linear - Setup a linear dma maping for a device.
+ * dma_sb_region_create_linear - Setup a linear dma mapping for a device.
* @r: Pointer to a struct ps3_dma_region.
*
* This routine creates an HV dma region for the device and maps all available
* ram into the io controller bus address space.
*/
-static int dma_region_create_linear(struct ps3_dma_region *r)
+static int dma_sb_region_create_linear(struct ps3_dma_region *r)
{
int result;
- unsigned long tmp;
-
- /* force 16M dma pages for linear mapping */
-
- if (r->page_size != PS3_DMA_16M) {
- pr_info("%s:%d: forcing 16M pages for linear map\n",
- __func__, __LINE__);
- r->page_size = PS3_DMA_16M;
+ unsigned long virt_addr, len, tmp;
+
+ if (r->len > 16*1024*1024) { /* FIXME: need proper fix */
+ /* force 16M dma pages for linear mapping */
+ if (r->page_size != PS3_DMA_16M) {
+ pr_info("%s:%d: forcing 16M pages for linear map\n",
+ __func__, __LINE__);
+ r->page_size = PS3_DMA_16M;
+ r->len = _ALIGN_UP(r->len, 1 << r->page_size);
+ }
}
- result = dma_region_create(r);
+ result = dma_sb_region_create(r);
BUG_ON(result);
- result = dma_map_area(r, map.rm.base, map.rm.size, &tmp);
- BUG_ON(result);
-
- if (USE_LPAR_ADDR)
- result = dma_map_area(r, map.r1.base, map.r1.size,
- &tmp);
- else
- result = dma_map_area(r, map.rm.size, map.r1.size,
- &tmp);
+ if (r->offset < map.rm.size) {
+ /* Map (part of) 1st RAM chunk */
+ virt_addr = map.rm.base + r->offset;
+ len = map.rm.size - r->offset;
+ if (len > r->len)
+ len = r->len;
+ result = dma_sb_map_area(r, virt_addr, len, &tmp,
+ IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+ BUG_ON(result);
+ }
- BUG_ON(result);
+ if (r->offset + r->len > map.rm.size) {
+ /* Map (part of) 2nd RAM chunk */
+ virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size;
+ len = r->len;
+ if (r->offset >= map.rm.size)
+ virt_addr += r->offset - map.rm.size;
+ else
+ len -= map.rm.size - r->offset;
+ result = dma_sb_map_area(r, virt_addr, len, &tmp,
+ IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
+ BUG_ON(result);
+ }
return result;
}
/**
- * dma_region_free_linear - Free a linear dma mapping for a device.
+ * dma_sb_region_free_linear - Free a linear dma mapping for a device.
* @r: Pointer to a struct ps3_dma_region.
*
* This routine will unmap all mapped areas and free the HV dma region.
*/
-static int dma_region_free_linear(struct ps3_dma_region *r)
+static int dma_sb_region_free_linear(struct ps3_dma_region *r)
{
int result;
+ unsigned long bus_addr, len, lpar_addr;
+
+ if (r->offset < map.rm.size) {
+ /* Unmap (part of) 1st RAM chunk */
+ lpar_addr = map.rm.base + r->offset;
+ len = map.rm.size - r->offset;
+ if (len > r->len)
+ len = r->len;
+ bus_addr = dma_sb_lpar_to_bus(r, lpar_addr);
+ result = dma_sb_unmap_area(r, bus_addr, len);
+ BUG_ON(result);
+ }
- result = dma_unmap_area(r, dma_lpar_to_bus(r, 0), map.rm.size);
- BUG_ON(result);
-
- result = dma_unmap_area(r, dma_lpar_to_bus(r, map.r1.base),
- map.r1.size);
- BUG_ON(result);
+ if (r->offset + r->len > map.rm.size) {
+ /* Unmap (part of) 2nd RAM chunk */
+ lpar_addr = map.r1.base;
+ len = r->len;
+ if (r->offset >= map.rm.size)
+ lpar_addr += r->offset - map.rm.size;
+ else
+ len -= map.rm.size - r->offset;
+ bus_addr = dma_sb_lpar_to_bus(r, lpar_addr);
+ result = dma_sb_unmap_area(r, bus_addr, len);
+ BUG_ON(result);
+ }
- result = dma_region_free(r);
+ result = dma_sb_region_free(r);
BUG_ON(result);
return result;
}
/**
- * dma_map_area_linear - Map an area of memory into a device dma region.
+ * dma_sb_map_area_linear - Map an area of memory into a device dma region.
* @r: Pointer to a struct ps3_dma_region.
* @virt_addr: Starting virtual address of the area to map.
* @len: Length in bytes of the area to map.
* @bus_addr: A pointer to return the starting ioc bus address of the area to
* map.
*
- * This routine just returns the coresponding bus address. Actual mapping
+ * This routine just returns the corresponding bus address. Actual mapping
* occurs in dma_region_create_linear().
*/
-static int dma_map_area_linear(struct ps3_dma_region *r,
- unsigned long virt_addr, unsigned long len, unsigned long *bus_addr)
+static int dma_sb_map_area_linear(struct ps3_dma_region *r,
+ unsigned long virt_addr, unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
{
unsigned long phys_addr = is_kernel_addr(virt_addr) ? __pa(virt_addr)
: virt_addr;
- *bus_addr = dma_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
+ *bus_addr = dma_sb_lpar_to_bus(r, ps3_mm_phys_to_lpar(phys_addr));
return 0;
}
@@ -744,42 +1091,98 @@ static int dma_map_area_linear(struct ps3_dma_region *r,
* @bus_addr: The starting ioc bus address of the area to unmap.
* @len: Length in bytes of the area to unmap.
*
- * This routine does nothing. Unmapping occurs in dma_region_free_linear().
+ * This routine does nothing. Unmapping occurs in dma_sb_region_free_linear().
*/
-static int dma_unmap_area_linear(struct ps3_dma_region *r,
+static int dma_sb_unmap_area_linear(struct ps3_dma_region *r,
unsigned long bus_addr, unsigned long len)
{
return 0;
+};
+
+static const struct ps3_dma_region_ops ps3_dma_sb_region_ops = {
+ .create = dma_sb_region_create,
+ .free = dma_sb_region_free,
+ .map = dma_sb_map_area,
+ .unmap = dma_sb_unmap_area
+};
+
+static const struct ps3_dma_region_ops ps3_dma_sb_region_linear_ops = {
+ .create = dma_sb_region_create_linear,
+ .free = dma_sb_region_free_linear,
+ .map = dma_sb_map_area_linear,
+ .unmap = dma_sb_unmap_area_linear
+};
+
+static const struct ps3_dma_region_ops ps3_dma_ioc0_region_ops = {
+ .create = dma_ioc0_region_create,
+ .free = dma_ioc0_region_free,
+ .map = dma_ioc0_map_area,
+ .unmap = dma_ioc0_unmap_area
+};
+
+int ps3_dma_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_dma_region *r, enum ps3_dma_page_size page_size,
+ enum ps3_dma_region_type region_type, void *addr, unsigned long len)
+{
+ unsigned long lpar_addr;
+
+ lpar_addr = addr ? ps3_mm_phys_to_lpar(__pa(addr)) : 0;
+
+ r->dev = dev;
+ r->page_size = page_size;
+ r->region_type = region_type;
+ r->offset = lpar_addr;
+ if (r->offset >= map.rm.size)
+ r->offset -= map.r1.offset;
+ r->len = len ? len : _ALIGN_UP(map.total, 1 << r->page_size);
+
+ switch (dev->dev_type) {
+ case PS3_DEVICE_TYPE_SB:
+ r->region_ops = (USE_DYNAMIC_DMA)
+ ? &ps3_dma_sb_region_ops
+ : &ps3_dma_sb_region_linear_ops;
+ break;
+ case PS3_DEVICE_TYPE_IOC0:
+ r->region_ops = &ps3_dma_ioc0_region_ops;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+ return 0;
}
+EXPORT_SYMBOL(ps3_dma_region_init);
int ps3_dma_region_create(struct ps3_dma_region *r)
{
- return (USE_DYNAMIC_DMA)
- ? dma_region_create(r)
- : dma_region_create_linear(r);
+ BUG_ON(!r);
+ BUG_ON(!r->region_ops);
+ BUG_ON(!r->region_ops->create);
+ return r->region_ops->create(r);
}
+EXPORT_SYMBOL(ps3_dma_region_create);
int ps3_dma_region_free(struct ps3_dma_region *r)
{
- return (USE_DYNAMIC_DMA)
- ? dma_region_free(r)
- : dma_region_free_linear(r);
+ BUG_ON(!r);
+ BUG_ON(!r->region_ops);
+ BUG_ON(!r->region_ops->free);
+ return r->region_ops->free(r);
}
+EXPORT_SYMBOL(ps3_dma_region_free);
int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr,
- unsigned long len, unsigned long *bus_addr)
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_flag)
{
- return (USE_DYNAMIC_DMA)
- ? dma_map_area(r, virt_addr, len, bus_addr)
- : dma_map_area_linear(r, virt_addr, len, bus_addr);
+ return r->region_ops->map(r, virt_addr, len, bus_addr, iopte_flag);
}
int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr,
unsigned long len)
{
- return (USE_DYNAMIC_DMA) ? dma_unmap_area(r, bus_addr, len)
- : dma_unmap_area_linear(r, bus_addr, len);
+ return r->region_ops->unmap(r, bus_addr, len);
}
/*============================================================================*/
@@ -810,12 +1213,13 @@ void __init ps3_mm_init(void)
BUG_ON(map.rm.base);
BUG_ON(!map.rm.size);
- lmb_add(map.rm.base, map.rm.size);
- lmb_analyze();
/* arrange to do this in ps3_mm_add_memory */
ps3_mm_region_create(&map.r1, map.total - map.rm.size);
+ /* correct map.total for the real total amount of memory we use */
+ map.total = map.rm.size + map.r1.size;
+
DBG(" <- %s:%d\n", __func__, __LINE__);
}
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index 5c3da08bc0c4..b70e474014f0 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -133,7 +133,7 @@ struct saved_params {
} static saved_params;
#define dump_header(_a) _dump_header(_a, __func__, __LINE__)
-static void _dump_header(const struct os_area_header __iomem *h, const char* func,
+static void _dump_header(const struct os_area_header *h, const char *func,
int line)
{
pr_debug("%s:%d: h.magic_num: '%s'\n", func, line,
@@ -151,7 +151,7 @@ static void _dump_header(const struct os_area_header __iomem *h, const char* fun
}
#define dump_params(_a) _dump_params(_a, __func__, __LINE__)
-static void _dump_params(const struct os_area_params __iomem *p, const char* func,
+static void _dump_params(const struct os_area_params *p, const char *func,
int line)
{
pr_debug("%s:%d: p.boot_flag: %u\n", func, line, p->boot_flag);
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index ca04f03305c7..87d52060fec0 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -41,6 +41,7 @@ void ps3_mm_shutdown(void);
/* irq */
void ps3_init_IRQ(void);
+void ps3_shutdown_IRQ(int cpu);
void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq);
/* smp */
@@ -82,6 +83,7 @@ enum ps3_dev_type {
PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */
PS3_DEV_TYPE_SB_GPIO = 6,
PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */
+ PS3_DEV_TYPE_NOACCESS = 255,
};
int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
@@ -129,24 +131,28 @@ int ps3_repository_read_dev_reg(unsigned int bus_index,
/* repository bus enumerators */
struct ps3_repository_device {
+ enum ps3_bus_type bus_type;
unsigned int bus_index;
+ unsigned int bus_id;
+ enum ps3_dev_type dev_type;
unsigned int dev_index;
- struct ps3_device_id did;
+ unsigned int dev_id;
};
-int ps3_repository_find_device(enum ps3_bus_type bus_type,
- enum ps3_dev_type dev_type,
- const struct ps3_repository_device *start_dev,
- struct ps3_repository_device *dev);
-static inline int ps3_repository_find_first_device(
- enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
- struct ps3_repository_device *dev)
+static inline struct ps3_repository_device *ps3_repository_bump_device(
+ struct ps3_repository_device *repo)
{
- return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
+ repo->dev_index++;
+ return repo;
}
-int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+int ps3_repository_find_device(struct ps3_repository_device *repo);
+int ps3_repository_find_devices(enum ps3_bus_type bus_type,
+ int (*callback)(const struct ps3_repository_device *repo));
+int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,
+ unsigned int *bus_index);
+int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,
enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
-int ps3_repository_find_reg(const struct ps3_repository_device *dev,
+int ps3_repository_find_reg(const struct ps3_repository_device *repo,
enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len);
/* repository block device info */
@@ -216,4 +222,19 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
int ps3_repository_read_spu_resource_id(unsigned int res_index,
enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
+/* repository vuart info */
+
+int ps3_repository_read_vuart_av_port(unsigned int *port);
+int ps3_repository_read_vuart_sysmgr_port(unsigned int *port);
+
+/* Page table entries */
+#define IOPTE_PP_W 0x8000000000000000ul /* protection: write */
+#define IOPTE_PP_R 0x4000000000000000ul /* protection: read */
+#define IOPTE_M 0x2000000000000000ul /* coherency required */
+#define IOPTE_SO_R 0x1000000000000000ul /* ordering: writes */
+#define IOPTE_SO_RW 0x1800000000000000ul /* ordering: r & w */
+#define IOPTE_RPN_Mask 0x07fffffffffff000ul /* RPN */
+#define IOPTE_H 0x0000000000000800ul /* cache hint */
+#define IOPTE_IOID_Mask 0x00000000000007fful /* ioid */
+
#endif
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index ae586a0e5d3f..8cc37cfea0f2 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -138,7 +138,7 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
pr_debug("%s:%d: lv1_get_repository_node_value failed: %s\n",
__func__, __LINE__, ps3_result(result));
dump_node_name(lpar_id, n1, n2, n3, n4);
- return result;
+ return -ENOENT;
}
dump_node(lpar_id, n1, n2, n3, n4, v1, v2);
@@ -155,7 +155,7 @@ static int read_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4,
pr_debug("%s:%d: warning: discarding non-zero v2: %016lx\n",
__func__, __LINE__, v2);
- return result;
+ return 0;
}
int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
@@ -314,324 +314,140 @@ int ps3_repository_read_dev_reg(unsigned int bus_index,
reg_index, bus_addr, len);
}
-#if defined(DEBUG)
-int ps3_repository_dump_resource_info(unsigned int bus_index,
- unsigned int dev_index)
-{
- int result = 0;
- unsigned int res_index;
- pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
- bus_index, dev_index);
- for (res_index = 0; res_index < 10; res_index++) {
- enum ps3_interrupt_type intr_type;
- unsigned int interrupt_id;
+int ps3_repository_find_device(struct ps3_repository_device *repo)
+{
+ int result;
+ struct ps3_repository_device tmp = *repo;
+ unsigned int num_dev;
- result = ps3_repository_read_dev_intr(bus_index, dev_index,
- res_index, &intr_type, &interrupt_id);
+ BUG_ON(repo->bus_index > 10);
+ BUG_ON(repo->dev_index > 10);
- if (result) {
- if (result != LV1_NO_ENTRY)
- pr_debug("%s:%d ps3_repository_read_dev_intr"
- " (%u:%u) failed\n", __func__, __LINE__,
- bus_index, dev_index);
- break;
- }
+ result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev);
- pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",
- __func__, __LINE__, bus_index, dev_index, intr_type,
- interrupt_id);
+ if (result) {
+ pr_debug("%s:%d read_bus_num_dev failed\n", __func__, __LINE__);
+ return result;
}
- for (res_index = 0; res_index < 10; res_index++) {
- enum ps3_reg_type reg_type;
- u64 bus_addr;
- u64 len;
-
- result = ps3_repository_read_dev_reg(bus_index, dev_index,
- res_index, &reg_type, &bus_addr, &len);
+ pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %u, num_dev %u\n",
+ __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id,
+ num_dev);
- if (result) {
- if (result != LV1_NO_ENTRY)
- pr_debug("%s:%d ps3_repository_read_dev_reg"
- " (%u:%u) failed\n", __func__, __LINE__,
- bus_index, dev_index);
- break;
- }
-
- pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n",
- __func__, __LINE__, bus_index, dev_index, reg_type,
- bus_addr, len);
+ if (tmp.dev_index >= num_dev) {
+ pr_debug("%s:%d: no device found\n", __func__, __LINE__);
+ return -ENODEV;
}
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
- return result;
-}
-
-static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index)
-{
- int result = 0;
- unsigned int num_regions, region_index;
- u64 port, blk_size, num_blocks;
-
- pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
- bus_index, dev_index);
+ result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index,
+ &tmp.dev_type);
- result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port,
- &blk_size, &num_blocks, &num_regions);
if (result) {
- pr_debug("%s:%d ps3_repository_read_stor_dev_info"
- " (%u:%u) failed\n", __func__, __LINE__,
- bus_index, dev_index);
- goto out;
+ pr_debug("%s:%d read_dev_type failed\n", __func__, __LINE__);
+ return result;
}
- pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks "
- "%lu, num_regions %u\n",
- __func__, __LINE__, bus_index, dev_index, port,
- blk_size, num_blocks, num_regions);
-
- for (region_index = 0; region_index < num_regions; region_index++) {
- unsigned int region_id;
- u64 region_start, region_size;
-
- result = ps3_repository_read_stor_dev_region(bus_index,
- dev_index, region_index, &region_id, &region_start,
- &region_size);
- if (result) {
- pr_debug("%s:%d ps3_repository_read_stor_dev_region"
- " (%u:%u) failed\n", __func__, __LINE__,
- bus_index, dev_index);
- break;
- }
+ result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index,
+ &tmp.dev_id);
- pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
- __func__, __LINE__, bus_index, dev_index, region_id,
- region_start, region_size);
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__,
+ __LINE__);
+ return result;
}
-out:
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
- return result;
-}
-
-static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type,
- unsigned int num_dev)
-{
- int result = 0;
- unsigned int dev_index;
-
- pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, bus_index);
-
- for (dev_index = 0; dev_index < num_dev; dev_index++) {
- enum ps3_dev_type dev_type;
- unsigned int dev_id;
-
- result = ps3_repository_read_dev_type(bus_index, dev_index,
- &dev_type);
-
- if (result) {
- pr_debug("%s:%d ps3_repository_read_dev_type"
- " (%u:%u) failed\n", __func__, __LINE__,
- bus_index, dev_index);
- break;
- }
-
- result = ps3_repository_read_dev_id(bus_index, dev_index,
- &dev_id);
-
- if (result) {
- pr_debug("%s:%d ps3_repository_read_dev_id"
- " (%u:%u) failed\n", __func__, __LINE__,
- bus_index, dev_index);
- continue;
- }
+ pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %u\n",
+ __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id);
- pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__,
- __LINE__, bus_index, dev_index, dev_type, dev_id);
-
- ps3_repository_dump_resource_info(bus_index, dev_index);
-
- if (bus_type == PS3_BUS_TYPE_STORAGE)
- dump_stor_dev_info(bus_index, dev_index);
- }
-
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
- return result;
+ *repo = tmp;
+ return 0;
}
-int ps3_repository_dump_bus_info(void)
+int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type,
+ int (*callback)(const struct ps3_repository_device *repo))
{
int result = 0;
- unsigned int bus_index;
+ struct ps3_repository_device repo;
- pr_debug(" -> %s:%d\n", __func__, __LINE__);
+ pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type);
- for (bus_index = 0; bus_index < 10; bus_index++) {
- enum ps3_bus_type bus_type;
- unsigned int bus_id;
- unsigned int num_dev;
+ for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) {
- result = ps3_repository_read_bus_type(bus_index, &bus_type);
+ result = ps3_repository_read_bus_type(repo.bus_index,
+ &repo.bus_type);
if (result) {
pr_debug("%s:%d read_bus_type(%u) failed\n",
- __func__, __LINE__, bus_index);
+ __func__, __LINE__, repo.bus_index);
break;
}
- result = ps3_repository_read_bus_id(bus_index, &bus_id);
-
- if (result) {
- pr_debug("%s:%d read_bus_id(%u) failed\n",
- __func__, __LINE__, bus_index);
+ if (repo.bus_type != bus_type) {
+ pr_debug("%s:%d: skip, bus_type %u\n", __func__,
+ __LINE__, repo.bus_type);
continue;
}
- if (bus_index != bus_id)
- pr_debug("%s:%d bus_index != bus_id\n",
- __func__, __LINE__);
-
- result = ps3_repository_read_bus_num_dev(bus_index, &num_dev);
+ result = ps3_repository_read_bus_id(repo.bus_index,
+ &repo.bus_id);
if (result) {
- pr_debug("%s:%d read_bus_num_dev(%u) failed\n",
- __func__, __LINE__, bus_index);
+ pr_debug("%s:%d read_bus_id(%u) failed\n",
+ __func__, __LINE__, repo.bus_index);
continue;
}
- pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n",
- __func__, __LINE__, bus_index, bus_type, bus_id,
- num_dev);
+ for (repo.dev_index = 0; ; repo.dev_index++) {
+ result = ps3_repository_find_device(&repo);
- dump_device_info(bus_index, bus_type, num_dev);
- }
+ if (result == -ENODEV) {
+ result = 0;
+ break;
+ } else if (result)
+ break;
- pr_debug(" <- %s:%d\n", __func__, __LINE__);
- return result;
-}
-#endif /* defined(DEBUG) */
-
-static int find_device(unsigned int bus_index, unsigned int num_dev,
- unsigned int start_dev_index, enum ps3_dev_type dev_type,
- struct ps3_repository_device *dev)
-{
- int result = 0;
- unsigned int dev_index;
+ result = callback(&repo);
- pr_debug("%s:%d: find dev_type %u\n", __func__, __LINE__, dev_type);
-
- dev->dev_index = UINT_MAX;
-
- for (dev_index = start_dev_index; dev_index < num_dev; dev_index++) {
- enum ps3_dev_type x;
-
- result = ps3_repository_read_dev_type(bus_index, dev_index,
- &x);
-
- if (result) {
- pr_debug("%s:%d read_dev_type failed\n",
- __func__, __LINE__);
- return result;
+ if (result) {
+ pr_debug("%s:%d: abort at callback\n", __func__,
+ __LINE__);
+ break;
+ }
}
-
- if (x == dev_type)
- break;
- }
-
- if (dev_index == num_dev)
- return -1;
-
- pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
- __func__, __LINE__, dev_type, dev_index);
-
- result = ps3_repository_read_dev_id(bus_index, dev_index,
- &dev->did.dev_id);
-
- if (result) {
- pr_debug("%s:%d read_dev_id failed\n",
- __func__, __LINE__);
- return result;
+ break;
}
- dev->dev_index = dev_index;
-
- pr_debug("%s:%d found: dev_id %u\n", __func__, __LINE__,
- dev->did.dev_id);
-
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
}
-int ps3_repository_find_device (enum ps3_bus_type bus_type,
- enum ps3_dev_type dev_type,
- const struct ps3_repository_device *start_dev,
- struct ps3_repository_device *dev)
+int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from,
+ unsigned int *bus_index)
{
- int result = 0;
- unsigned int bus_index;
- unsigned int num_dev;
-
- pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__,
- bus_type, dev_type);
-
- BUG_ON(start_dev && start_dev->bus_index > 10);
-
- for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10;
- bus_index++) {
- enum ps3_bus_type x;
-
- result = ps3_repository_read_bus_type(bus_index, &x);
+ unsigned int i;
+ enum ps3_bus_type type;
+ int error;
- if (result) {
+ for (i = from; i < 10; i++) {
+ error = ps3_repository_read_bus_type(i, &type);
+ if (error) {
pr_debug("%s:%d read_bus_type failed\n",
__func__, __LINE__);
- dev->bus_index = UINT_MAX;
- return result;
+ *bus_index = UINT_MAX;
+ return error;
+ }
+ if (type == bus_type) {
+ *bus_index = i;
+ return 0;
}
- if (x == bus_type)
- break;
- }
-
- if (bus_index >= 10)
- return -ENODEV;
-
- pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
- __func__, __LINE__, bus_type, bus_index);
-
- result = ps3_repository_read_bus_num_dev(bus_index, &num_dev);
-
- if (result) {
- pr_debug("%s:%d read_bus_num_dev failed\n",
- __func__, __LINE__);
- return result;
- }
-
- result = find_device(bus_index, num_dev, start_dev
- ? start_dev->dev_index + 1 : 0, dev_type, dev);
-
- if (result) {
- pr_debug("%s:%d get_did failed\n", __func__, __LINE__);
- return result;
- }
-
- result = ps3_repository_read_bus_id(bus_index, &dev->did.bus_id);
-
- if (result) {
- pr_debug("%s:%d read_bus_id failed\n",
- __func__, __LINE__);
- return result;
}
-
- dev->bus_index = bus_index;
-
- pr_debug("%s:%d found: bus_id %u, dev_id %u\n",
- __func__, __LINE__, dev->did.bus_id, dev->did.dev_id);
-
- return result;
+ *bus_index = UINT_MAX;
+ return -ENODEV;
}
-int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
+int ps3_repository_find_interrupt(const struct ps3_repository_device *repo,
enum ps3_interrupt_type intr_type, unsigned int *interrupt_id)
{
int result = 0;
@@ -645,8 +461,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
enum ps3_interrupt_type t;
unsigned int id;
- result = ps3_repository_read_dev_intr(dev->bus_index,
- dev->dev_index, res_index, &t, &id);
+ result = ps3_repository_read_dev_intr(repo->bus_index,
+ repo->dev_index, res_index, &t, &id);
if (result) {
pr_debug("%s:%d read_dev_intr failed\n",
@@ -669,7 +485,7 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
return result;
}
-int ps3_repository_find_reg(const struct ps3_repository_device *dev,
+int ps3_repository_find_reg(const struct ps3_repository_device *repo,
enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
{
int result = 0;
@@ -684,8 +500,8 @@ int ps3_repository_find_reg(const struct ps3_repository_device *dev,
u64 a;
u64 l;
- result = ps3_repository_read_dev_reg(dev->bus_index,
- dev->dev_index, res_index, &t, &a, &l);
+ result = ps3_repository_read_dev_reg(repo->bus_index,
+ repo->dev_index, res_index, &t, &a, &l);
if (result) {
pr_debug("%s:%d read_dev_reg failed\n",
@@ -965,6 +781,36 @@ int ps3_repository_read_boot_dat_size(unsigned int *size)
return result;
}
+int ps3_repository_read_vuart_av_port(unsigned int *port)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("vir_uart", 0),
+ make_field("port", 0),
+ make_field("avset", 0),
+ &v1, 0);
+ *port = v1;
+ return result;
+}
+
+int ps3_repository_read_vuart_sysmgr_port(unsigned int *port)
+{
+ int result;
+ u64 v1;
+
+ result = read_node(PS3_LPAR_ID_CURRENT,
+ make_first_field("bi", 0),
+ make_field("vir_uart", 0),
+ make_field("port", 0),
+ make_field("sysmgr", 0),
+ &v1, 0);
+ *port = v1;
+ return result;
+}
+
/**
* ps3_repository_read_boot_dat_info - Get address and size of cell_ext_os_area.
* address: lpar address of cell_ext_os_area
@@ -1026,3 +872,205 @@ int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq)
return result ? result
: ps3_repository_read_tb_freq(node_id, tb_freq);
}
+
+#if defined(DEBUG)
+
+int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo)
+{
+ int result = 0;
+ unsigned int res_index;
+
+ pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+
+ for (res_index = 0; res_index < 10; res_index++) {
+ enum ps3_interrupt_type intr_type;
+ unsigned int interrupt_id;
+
+ result = ps3_repository_read_dev_intr(repo->bus_index,
+ repo->dev_index, res_index, &intr_type, &interrupt_id);
+
+ if (result) {
+ if (result != LV1_NO_ENTRY)
+ pr_debug("%s:%d ps3_repository_read_dev_intr"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+ break;
+ }
+
+ pr_debug("%s:%d (%u:%u) intr_type %u, interrupt_id %u\n",
+ __func__, __LINE__, repo->bus_index, repo->dev_index,
+ intr_type, interrupt_id);
+ }
+
+ for (res_index = 0; res_index < 10; res_index++) {
+ enum ps3_reg_type reg_type;
+ u64 bus_addr;
+ u64 len;
+
+ result = ps3_repository_read_dev_reg(repo->bus_index,
+ repo->dev_index, res_index, &reg_type, &bus_addr, &len);
+
+ if (result) {
+ if (result != LV1_NO_ENTRY)
+ pr_debug("%s:%d ps3_repository_read_dev_reg"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+ break;
+ }
+
+ pr_debug("%s:%d (%u:%u) reg_type %u, bus_addr %lxh, len %lxh\n",
+ __func__, __LINE__, repo->bus_index, repo->dev_index,
+ reg_type, bus_addr, len);
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+static int dump_stor_dev_info(struct ps3_repository_device *repo)
+{
+ int result = 0;
+ unsigned int num_regions, region_index;
+ u64 port, blk_size, num_blocks;
+
+ pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+
+ result = ps3_repository_read_stor_dev_info(repo->bus_index,
+ repo->dev_index, &port, &blk_size, &num_blocks, &num_regions);
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_stor_dev_info"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+ goto out;
+ }
+
+ pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks "
+ "%lu, num_regions %u\n",
+ __func__, __LINE__, repo->bus_index, repo->dev_index, port,
+ blk_size, num_blocks, num_regions);
+
+ for (region_index = 0; region_index < num_regions; region_index++) {
+ unsigned int region_id;
+ u64 region_start, region_size;
+
+ result = ps3_repository_read_stor_dev_region(repo->bus_index,
+ repo->dev_index, region_index, &region_id,
+ &region_start, &region_size);
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_stor_dev_region"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+ break;
+ }
+
+ pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
+ __func__, __LINE__, repo->bus_index, repo->dev_index,
+ region_id, region_start, region_size);
+ }
+
+out:
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+static int dump_device_info(struct ps3_repository_device *repo,
+ unsigned int num_dev)
+{
+ int result = 0;
+
+ pr_debug(" -> %s:%d: bus_%u\n", __func__, __LINE__, repo->bus_index);
+
+ for (repo->dev_index = 0; repo->dev_index < num_dev;
+ repo->dev_index++) {
+
+ result = ps3_repository_read_dev_type(repo->bus_index,
+ repo->dev_index, &repo->dev_type);
+
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_dev_type"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+ break;
+ }
+
+ result = ps3_repository_read_dev_id(repo->bus_index,
+ repo->dev_index, &repo->dev_id);
+
+ if (result) {
+ pr_debug("%s:%d ps3_repository_read_dev_id"
+ " (%u:%u) failed\n", __func__, __LINE__,
+ repo->bus_index, repo->dev_index);
+ continue;
+ }
+
+ pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__,
+ __LINE__, repo->bus_index, repo->dev_index,
+ repo->dev_type, repo->dev_id);
+
+ ps3_repository_dump_resource_info(repo);
+
+ if (repo->bus_type == PS3_BUS_TYPE_STORAGE)
+ dump_stor_dev_info(repo);
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+int ps3_repository_dump_bus_info(void)
+{
+ int result = 0;
+ struct ps3_repository_device repo;
+
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ memset(&repo, 0, sizeof(repo));
+
+ for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) {
+ unsigned int num_dev;
+
+ result = ps3_repository_read_bus_type(repo.bus_index,
+ &repo.bus_type);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_type(%u) failed\n",
+ __func__, __LINE__, repo.bus_index);
+ break;
+ }
+
+ result = ps3_repository_read_bus_id(repo.bus_index,
+ &repo.bus_id);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_id(%u) failed\n",
+ __func__, __LINE__, repo.bus_index);
+ continue;
+ }
+
+ if (repo.bus_index != repo.bus_id)
+ pr_debug("%s:%d bus_index != bus_id\n",
+ __func__, __LINE__);
+
+ result = ps3_repository_read_bus_num_dev(repo.bus_index,
+ &num_dev);
+
+ if (result) {
+ pr_debug("%s:%d read_bus_num_dev(%u) failed\n",
+ __func__, __LINE__, repo.bus_index);
+ continue;
+ }
+
+ pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n",
+ __func__, __LINE__, repo.bus_index, repo.bus_type,
+ repo.bus_id, num_dev);
+
+ dump_device_info(&repo, num_dev);
+ }
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return result;
+}
+
+#endif /* defined(DEBUG) */
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index 935396766621..aa05288de64e 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -37,27 +37,35 @@
#include "platform.h"
#if defined(DEBUG)
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG udbg_printf
#else
-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
+#define DBG pr_debug
#endif
#if !defined(CONFIG_SMP)
static void smp_send_stop(void) {}
#endif
-int ps3_get_firmware_version(union ps3_firmware_version *v)
+static union ps3_firmware_version ps3_firmware_version;
+
+void ps3_get_firmware_version(union ps3_firmware_version *v)
{
- int result = lv1_get_version_info(&v->raw);
+ *v = ps3_firmware_version;
+}
+EXPORT_SYMBOL_GPL(ps3_get_firmware_version);
- if (result) {
- v->raw = 0;
- return -1;
- }
+int ps3_compare_firmware_version(u16 major, u16 minor, u16 rev)
+{
+ union ps3_firmware_version x;
+
+ x.pad = 0;
+ x.major = major;
+ x.minor = minor;
+ x.rev = rev;
- return result;
+ return (ps3_firmware_version.raw - x.raw);
}
-EXPORT_SYMBOL_GPL(ps3_get_firmware_version);
+EXPORT_SYMBOL_GPL(ps3_compare_firmware_version);
static void ps3_power_save(void)
{
@@ -99,7 +107,8 @@ static void ps3_panic(char *str)
while(1);
}
-#ifdef CONFIG_FB_PS3
+#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE) || \
+ defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
static void prealloc(struct ps3_prealloc *p)
{
if (!p->size)
@@ -115,12 +124,15 @@ static void prealloc(struct ps3_prealloc *p)
printk(KERN_INFO "%s: %lu bytes at %p\n", p->name, p->size,
p->address);
}
+#endif
+#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE)
struct ps3_prealloc ps3fb_videomemory = {
- .name = "ps3fb videomemory",
- .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024,
- .align = 1024*1024 /* the GPU requires 1 MiB alignment */
+ .name = "ps3fb videomemory",
+ .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024,
+ .align = 1024*1024 /* the GPU requires 1 MiB alignment */
};
+EXPORT_SYMBOL_GPL(ps3fb_videomemory);
#define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory)
static int __init early_parse_ps3fb(char *p)
@@ -137,6 +149,30 @@ early_param("ps3fb", early_parse_ps3fb);
#define prealloc_ps3fb_videomemory() do { } while (0)
#endif
+#if defined(CONFIG_PS3_FLASH) || defined(CONFIG_PS3_FLASH_MODULE)
+struct ps3_prealloc ps3flash_bounce_buffer = {
+ .name = "ps3flash bounce buffer",
+ .size = 256*1024,
+ .align = 256*1024
+};
+EXPORT_SYMBOL_GPL(ps3flash_bounce_buffer);
+#define prealloc_ps3flash_bounce_buffer() prealloc(&ps3flash_bounce_buffer)
+
+static int __init early_parse_ps3flash(char *p)
+{
+ if (!p)
+ return 1;
+
+ if (!strcmp(p, "off"))
+ ps3flash_bounce_buffer.size = 0;
+
+ return 0;
+}
+early_param("ps3flash", early_parse_ps3flash);
+#else
+#define prealloc_ps3flash_bounce_buffer() do { } while (0)
+#endif
+
static int ps3_set_dabr(u64 dabr)
{
enum {DABR_USER = 1, DABR_KERNEL = 2,};
@@ -146,13 +182,13 @@ static int ps3_set_dabr(u64 dabr)
static void __init ps3_setup_arch(void)
{
- union ps3_firmware_version v;
DBG(" -> %s:%d\n", __func__, __LINE__);
- ps3_get_firmware_version(&v);
- printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor,
- v.rev);
+ lv1_get_version_info(&ps3_firmware_version.raw);
+ printk(KERN_INFO "PS3 firmware version %u.%u.%u\n",
+ ps3_firmware_version.major, ps3_firmware_version.minor,
+ ps3_firmware_version.rev);
ps3_spu_set_platform();
ps3_map_htab();
@@ -166,6 +202,8 @@ static void __init ps3_setup_arch(void)
#endif
prealloc_ps3fb_videomemory();
+ prealloc_ps3flash_bounce_buffer();
+
ppc_md.power_save = ps3_power_save;
DBG(" <- %s:%d\n", __func__, __LINE__);
@@ -184,7 +222,7 @@ static int __init ps3_probe(void)
DBG(" -> %s:%d\n", __func__, __LINE__);
dt_root = of_get_flat_dt_root();
- if (!of_flat_dt_is_compatible(dt_root, "PS3"))
+ if (!of_flat_dt_is_compatible(dt_root, "sony,ps3"))
return 0;
powerpc_firmware_features |= FW_FEATURE_PS3_POSSIBLE;
@@ -201,31 +239,12 @@ static int __init ps3_probe(void)
#if defined(CONFIG_KEXEC)
static void ps3_kexec_cpu_down(int crash_shutdown, int secondary)
{
- DBG(" -> %s:%d\n", __func__, __LINE__);
-
- if (secondary) {
- int cpu;
- for_each_online_cpu(cpu)
- if (cpu)
- ps3_smp_cleanup_cpu(cpu);
- } else
- ps3_smp_cleanup_cpu(0);
-
- DBG(" <- %s:%d\n", __func__, __LINE__);
-}
-
-static void ps3_machine_kexec(struct kimage *image)
-{
- unsigned long ppe_id;
-
- DBG(" -> %s:%d\n", __func__, __LINE__);
+ int cpu = smp_processor_id();
- lv1_get_logical_ppe_id(&ppe_id);
- lv1_configure_irq_state_bitmap(ppe_id, 0, 0);
- ps3_mm_shutdown();
- ps3_mm_vas_destroy();
+ DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
- default_machine_kexec(image);
+ ps3_smp_cleanup_cpu(cpu);
+ ps3_shutdown_IRQ(cpu);
DBG(" <- %s:%d\n", __func__, __LINE__);
}
@@ -247,7 +266,7 @@ define_machine(ps3) {
.power_off = ps3_power_off,
#if defined(CONFIG_KEXEC)
.kexec_cpu_down = ps3_kexec_cpu_down,
- .machine_kexec = ps3_machine_kexec,
+ .machine_kexec = default_machine_kexec,
.machine_kexec_prepare = default_machine_kexec_prepare,
.machine_crash_shutdown = default_machine_crash_shutdown,
#endif
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 53416ec5198b..f0b12f212363 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -27,9 +27,9 @@
#include "platform.h"
#if defined(DEBUG)
-#define DBG(fmt...) udbg_printf(fmt)
+#define DBG udbg_printf
#else
-#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
+#define DBG pr_debug
#endif
static irqreturn_t ipi_function_handler(int irq, void *msg)
@@ -39,11 +39,11 @@ static irqreturn_t ipi_function_handler(int irq, void *msg)
}
/**
- * virqs - a per cpu array of virqs for ipi use
+ * ps3_ipi_virqs - a per cpu array of virqs for ipi use
*/
#define MSG_COUNT 4
-static DEFINE_PER_CPU(unsigned int, virqs[MSG_COUNT]);
+static DEFINE_PER_CPU(unsigned int, ps3_ipi_virqs[MSG_COUNT]);
static const char *names[MSG_COUNT] = {
"ipi call",
@@ -62,7 +62,7 @@ static void do_message_pass(int target, int msg)
return;
}
- virq = per_cpu(virqs, target)[msg];
+ virq = per_cpu(ps3_ipi_virqs, target)[msg];
result = ps3_send_event_locally(virq);
if (result)
@@ -94,13 +94,13 @@ static int ps3_smp_probe(void)
static void __init ps3_smp_setup_cpu(int cpu)
{
int result;
- unsigned int *virqs = per_cpu(virqs, cpu);
+ unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
int i;
DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
/*
- * Check assumptions on virqs[] indexing. If this
+ * Check assumptions on ps3_ipi_virqs[] indexing. If this
* check fails, then a different mapping of PPC_MSG_
* to index needs to be setup.
*/
@@ -132,13 +132,13 @@ static void __init ps3_smp_setup_cpu(int cpu)
void ps3_smp_cleanup_cpu(int cpu)
{
- unsigned int *virqs = per_cpu(virqs, cpu);
+ unsigned int *virqs = per_cpu(ps3_ipi_virqs, cpu);
int i;
DBG(" -> %s:%d: (%d)\n", __func__, __LINE__, cpu);
for (i = 0; i < MSG_COUNT; i++) {
- free_irq(virqs[i], (void*)(long)i);
+ /* Can't call free_irq from interrupt context. */
ps3_event_receive_port_destroy(virqs[i]);
virqs[i] = NO_IRQ;
}
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 651437cb2c18..502d80ed982b 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -182,15 +182,18 @@ static int __init setup_areas(struct spu *spu)
{
struct table {char* name; unsigned long addr; unsigned long size;};
- spu_pdata(spu)->shadow = __ioremap(
- spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow),
- pgprot_val(PAGE_READONLY) | _PAGE_NO_CACHE | _PAGE_GUARDED);
+ spu_pdata(spu)->shadow = ioremap_flags(spu_pdata(spu)->shadow_addr,
+ sizeof(struct spe_shadow),
+ pgprot_val(PAGE_READONLY) |
+ _PAGE_NO_CACHE);
if (!spu_pdata(spu)->shadow) {
pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__);
goto fail_ioremap;
}
- spu->local_store = ioremap(spu->local_store_phys, LS_SIZE);
+ spu->local_store = (__force void *)ioremap_flags(spu->local_store_phys,
+ LS_SIZE, _PAGE_NO_CACHE);
+
if (!spu->local_store) {
pr_debug("%s:%d: ioremap local_store failed\n",
__func__, __LINE__);
@@ -199,6 +202,7 @@ static int __init setup_areas(struct spu *spu)
spu->problem = ioremap(spu->problem_phys,
sizeof(struct spu_problem));
+
if (!spu->problem) {
pr_debug("%s:%d: ioremap problem failed\n", __func__, __LINE__);
goto fail_ioremap;
@@ -206,6 +210,7 @@ static int __init setup_areas(struct spu *spu)
spu->priv2 = ioremap(spu_pdata(spu)->priv2_addr,
sizeof(struct spu_priv2));
+
if (!spu->priv2) {
pr_debug("%s:%d: ioremap priv2 failed\n", __func__, __LINE__);
goto fail_ioremap;
@@ -400,11 +405,13 @@ static int __init ps3_enumerate_spus(int (*fn)(void *data))
}
}
- if (result)
+ if (result) {
printk(KERN_WARNING "%s:%d: Error initializing spus\n",
__func__, __LINE__);
+ return result;
+ }
- return result;
+ return num_resource_id;
}
const struct spu_management_ops spu_management_ps3_ops = {
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index 6bda51027cc6..4bb634a17e43 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -30,22 +30,228 @@
#include "platform.h"
+static struct device ps3_system_bus = {
+ .bus_id = "ps3_system",
+};
+
+/* FIXME: need device usage counters! */
+struct {
+ struct mutex mutex;
+ int sb_11; /* usb 0 */
+ int sb_12; /* usb 0 */
+ int gpu;
+} static usage_hack;
+
+static int ps3_is_device(struct ps3_system_bus_device *dev,
+ unsigned int bus_id, unsigned int dev_id)
+{
+ return dev->bus_id == bus_id && dev->dev_id == dev_id;
+}
+
+static int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ BUG_ON(!dev->bus_id);
+ mutex_lock(&usage_hack.mutex);
+
+ if (ps3_is_device(dev, 1, 1)) {
+ usage_hack.sb_11++;
+ if (usage_hack.sb_11 > 1) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ if (ps3_is_device(dev, 1, 2)) {
+ usage_hack.sb_12++;
+ if (usage_hack.sb_12 > 1) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ result = lv1_open_device(dev->bus_id, dev->dev_id, 0);
+
+ if (result) {
+ pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__,
+ __LINE__, ps3_result(result));
+ result = -EPERM;
+ }
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+static int ps3_close_hv_device_sb(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ BUG_ON(!dev->bus_id);
+ mutex_lock(&usage_hack.mutex);
+
+ if (ps3_is_device(dev, 1, 1)) {
+ usage_hack.sb_11--;
+ if (usage_hack.sb_11) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ if (ps3_is_device(dev, 1, 2)) {
+ usage_hack.sb_12--;
+ if (usage_hack.sb_12) {
+ result = 0;
+ goto done;
+ }
+ }
+
+ result = lv1_close_device(dev->bus_id, dev->dev_id);
+ BUG_ON(result);
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+static int ps3_open_hv_device_gpu(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ mutex_lock(&usage_hack.mutex);
+
+ usage_hack.gpu++;
+ if (usage_hack.gpu > 1) {
+ result = 0;
+ goto done;
+ }
+
+ result = lv1_gpu_open(0);
+
+ if (result) {
+ pr_debug("%s:%d: lv1_gpu_open failed: %s\n", __func__,
+ __LINE__, ps3_result(result));
+ result = -EPERM;
+ }
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+static int ps3_close_hv_device_gpu(struct ps3_system_bus_device *dev)
+{
+ int result;
+
+ mutex_lock(&usage_hack.mutex);
+
+ usage_hack.gpu--;
+ if (usage_hack.gpu) {
+ result = 0;
+ goto done;
+ }
+
+ result = lv1_gpu_close();
+ BUG_ON(result);
+
+done:
+ mutex_unlock(&usage_hack.mutex);
+ return result;
+}
+
+int ps3_open_hv_device(struct ps3_system_bus_device *dev)
+{
+ BUG_ON(!dev);
+ pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id);
+
+ switch (dev->match_id) {
+ case PS3_MATCH_ID_EHCI:
+ case PS3_MATCH_ID_OHCI:
+ case PS3_MATCH_ID_GELIC:
+ case PS3_MATCH_ID_STOR_DISK:
+ case PS3_MATCH_ID_STOR_ROM:
+ case PS3_MATCH_ID_STOR_FLASH:
+ return ps3_open_hv_device_sb(dev);
+
+ case PS3_MATCH_ID_SOUND:
+ case PS3_MATCH_ID_GRAPHICS:
+ return ps3_open_hv_device_gpu(dev);
+
+ case PS3_MATCH_ID_AV_SETTINGS:
+ case PS3_MATCH_ID_SYSTEM_MANAGER:
+ pr_debug("%s:%d: unsupported match_id: %u\n", __func__,
+ __LINE__, dev->match_id);
+ pr_debug("%s:%d: bus_id: %u\n", __func__,
+ __LINE__, dev->bus_id);
+ BUG();
+ return -EINVAL;
+
+ default:
+ break;
+ }
+
+ pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__,
+ dev->match_id);
+ BUG();
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(ps3_open_hv_device);
+
+int ps3_close_hv_device(struct ps3_system_bus_device *dev)
+{
+ BUG_ON(!dev);
+ pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id);
+
+ switch (dev->match_id) {
+ case PS3_MATCH_ID_EHCI:
+ case PS3_MATCH_ID_OHCI:
+ case PS3_MATCH_ID_GELIC:
+ case PS3_MATCH_ID_STOR_DISK:
+ case PS3_MATCH_ID_STOR_ROM:
+ case PS3_MATCH_ID_STOR_FLASH:
+ return ps3_close_hv_device_sb(dev);
+
+ case PS3_MATCH_ID_SOUND:
+ case PS3_MATCH_ID_GRAPHICS:
+ return ps3_close_hv_device_gpu(dev);
+
+ case PS3_MATCH_ID_AV_SETTINGS:
+ case PS3_MATCH_ID_SYSTEM_MANAGER:
+ pr_debug("%s:%d: unsupported match_id: %u\n", __func__,
+ __LINE__, dev->match_id);
+ pr_debug("%s:%d: bus_id: %u\n", __func__,
+ __LINE__, dev->bus_id);
+ BUG();
+ return -EINVAL;
+
+ default:
+ break;
+ }
+
+ pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__,
+ dev->match_id);
+ BUG();
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(ps3_close_hv_device);
+
#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
static void _dump_mmio_region(const struct ps3_mmio_region* r,
const char* func, int line)
{
- pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
- r->did.dev_id);
+ pr_debug("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id,
+ r->dev->dev_id);
pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
pr_debug("%s:%d: len %lxh\n", func, line, r->len);
pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
}
-int ps3_mmio_region_create(struct ps3_mmio_region *r)
+static int ps3_sb_mmio_region_create(struct ps3_mmio_region *r)
{
int result;
- result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
+ result = lv1_map_device_mmio_region(r->dev->bus_id, r->dev->dev_id,
r->bus_addr, r->len, r->page_size, &r->lpar_addr);
if (result) {
@@ -57,13 +263,26 @@ int ps3_mmio_region_create(struct ps3_mmio_region *r)
dump_mmio_region(r);
return result;
}
+
+static int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r)
+{
+ /* device specific; do nothing currently */
+ return 0;
+}
+
+int ps3_mmio_region_create(struct ps3_mmio_region *r)
+{
+ return r->mmio_ops->create(r);
+}
EXPORT_SYMBOL_GPL(ps3_mmio_region_create);
-int ps3_free_mmio_region(struct ps3_mmio_region *r)
+static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r)
{
int result;
- result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
+ dump_mmio_region(r);
+;
+ result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id,
r->lpar_addr);
if (result)
@@ -73,14 +292,60 @@ int ps3_free_mmio_region(struct ps3_mmio_region *r)
r->lpar_addr = 0;
return result;
}
+
+static int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r)
+{
+ /* device specific; do nothing currently */
+ return 0;
+}
+
+
+int ps3_free_mmio_region(struct ps3_mmio_region *r)
+{
+ return r->mmio_ops->free(r);
+}
+
EXPORT_SYMBOL_GPL(ps3_free_mmio_region);
+static const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = {
+ .create = ps3_sb_mmio_region_create,
+ .free = ps3_sb_free_mmio_region
+};
+
+static const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = {
+ .create = ps3_ioc0_mmio_region_create,
+ .free = ps3_ioc0_free_mmio_region
+};
+
+int ps3_mmio_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len,
+ enum ps3_mmio_page_size page_size)
+{
+ r->dev = dev;
+ r->bus_addr = bus_addr;
+ r->len = len;
+ r->page_size = page_size;
+ switch (dev->dev_type) {
+ case PS3_DEVICE_TYPE_SB:
+ r->mmio_ops = &ps3_mmio_sb_region_ops;
+ break;
+ case PS3_DEVICE_TYPE_IOC0:
+ r->mmio_ops = &ps3_mmio_ioc0_region_ops;
+ break;
+ default:
+ BUG();
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3_mmio_region_init);
+
static int ps3_system_bus_match(struct device *_dev,
struct device_driver *_drv)
{
int result;
- struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_driver *drv = ps3_drv_to_system_bus_drv(_drv);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
result = dev->match_id == drv->match_id;
@@ -92,32 +357,14 @@ static int ps3_system_bus_match(struct device *_dev,
static int ps3_system_bus_probe(struct device *_dev)
{
- int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
-
- result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
-
- if (result) {
- pr_debug("%s:%d: lv1_open_device failed (%d)\n",
- __func__, __LINE__, result);
- result = -EACCES;
- goto clean_none;
- }
-
- if (dev->d_region->did.bus_id) {
- result = ps3_dma_region_create(dev->d_region);
+ int result = 0;
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ struct ps3_system_bus_driver *drv;
- if (result) {
- pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
- __func__, __LINE__, result);
- BUG_ON("check region type");
- result = -EINVAL;
- goto clean_device;
- }
- }
+ BUG_ON(!dev);
+ pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
+ drv = ps3_system_bus_dev_to_system_bus_drv(dev);
BUG_ON(!drv);
if (drv->probe)
@@ -126,56 +373,127 @@ static int ps3_system_bus_probe(struct device *_dev)
pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
dev->core.bus_id);
- if (result) {
- pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
- goto clean_dma;
- }
-
- return result;
-
-clean_dma:
- ps3_dma_region_free(dev->d_region);
-clean_device:
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
-clean_none:
+ pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
return result;
}
static int ps3_system_bus_remove(struct device *_dev)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
- struct ps3_system_bus_driver *drv =
- to_ps3_system_bus_driver(_dev->driver);
+ int result = 0;
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ struct ps3_system_bus_driver *drv;
+
+ BUG_ON(!dev);
+ pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id);
+
+ drv = ps3_system_bus_dev_to_system_bus_drv(dev);
+ BUG_ON(!drv);
if (drv->remove)
- drv->remove(dev);
+ result = drv->remove(dev);
else
- pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
- dev->core.bus_id);
+ dev_dbg(&dev->core, "%s:%d %s: no remove method\n",
+ __func__, __LINE__, drv->core.name);
+
+ pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id);
+ return result;
+}
+
+static void ps3_system_bus_shutdown(struct device *_dev)
+{
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ struct ps3_system_bus_driver *drv;
+
+ BUG_ON(!dev);
+
+ dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
+ dev->match_id);
+
+ if (!dev->core.driver) {
+ dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
+ __LINE__);
+ return;
+ }
+
+ drv = ps3_system_bus_dev_to_system_bus_drv(dev);
+
+ BUG_ON(!drv);
+
+ dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__,
+ dev->core.bus_id, drv->core.name);
+
+ if (drv->shutdown)
+ drv->shutdown(dev);
+ else if (drv->remove) {
+ dev_dbg(&dev->core, "%s:%d %s: no shutdown, calling remove\n",
+ __func__, __LINE__, drv->core.name);
+ drv->remove(dev);
+ } else {
+ dev_dbg(&dev->core, "%s:%d %s: no shutdown method\n",
+ __func__, __LINE__, drv->core.name);
+ BUG();
+ }
+
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
+}
+
+static int ps3_system_bus_uevent(struct device *_dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ int i = 0, length = 0;
- ps3_dma_region_free(dev->d_region);
- ps3_free_mmio_region(dev->m_region);
- lv1_close_device(dev->did.bus_id, dev->did.dev_id);
+ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
+ &length, "MODALIAS=ps3:%d",
+ dev->match_id))
+ return -ENOMEM;
+ envp[i] = NULL;
return 0;
}
+static ssize_t modalias_show(struct device *_dev, struct device_attribute *a,
+ char *buf)
+{
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ int len = snprintf(buf, PAGE_SIZE, "ps3:%d\n", dev->match_id);
+
+ return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
+}
+
+static struct device_attribute ps3_system_bus_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
struct bus_type ps3_system_bus_type = {
.name = "ps3_system_bus",
.match = ps3_system_bus_match,
+ .uevent = ps3_system_bus_uevent,
.probe = ps3_system_bus_probe,
.remove = ps3_system_bus_remove,
+ .shutdown = ps3_system_bus_shutdown,
+ .dev_attrs = ps3_system_bus_dev_attrs,
};
-int __init ps3_system_bus_init(void)
+static int __init ps3_system_bus_init(void)
{
int result;
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
return -ENODEV;
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ mutex_init(&usage_hack.mutex);
+
+ result = device_register(&ps3_system_bus);
+ BUG_ON(result);
+
result = bus_register(&ps3_system_bus_type);
BUG_ON(result);
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
return result;
}
@@ -185,16 +503,13 @@ core_initcall(ps3_system_bus_init);
* Returns the virtual address of the buffer and sets dma_handle
* to the dma address (mapping) of the first page.
*/
-
static void * ps3_alloc_coherent(struct device *_dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
+ dma_addr_t *dma_handle, gfp_t flag)
{
int result;
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
unsigned long virt_addr;
- BUG_ON(!dev->d_region->bus_addr);
-
flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
flag |= __GFP_ZERO;
@@ -205,7 +520,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size,
goto clean_none;
}
- result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
+ result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle,
+ IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -226,7 +542,7 @@ clean_none:
static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
dma_addr_t dma_handle)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
ps3_dma_unmap(dev->d_region, dma_handle, size);
free_pages((unsigned long)vaddr, get_order(size));
@@ -239,15 +555,16 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
* byte within the page as vaddr.
*/
-static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
+static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
int result;
unsigned long bus_addr;
result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
- &bus_addr);
+ &bus_addr,
+ IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -257,10 +574,44 @@ static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
return bus_addr;
}
+static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
+ int result;
+ unsigned long bus_addr;
+ u64 iopte_flag;
+
+ iopte_flag = IOPTE_M;
+ switch (direction) {
+ case DMA_BIDIRECTIONAL:
+ iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW;
+ break;
+ case DMA_TO_DEVICE:
+ iopte_flag |= IOPTE_PP_R | IOPTE_SO_R;
+ break;
+ case DMA_FROM_DEVICE:
+ iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW;
+ break;
+ default:
+ /* not happned */
+ BUG();
+ };
+ result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
+ &bus_addr, iopte_flag);
+
+ if (result) {
+ pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
+ __func__, __LINE__, result);
+ }
+ return bus_addr;
+}
+
static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
size_t size, enum dma_data_direction direction)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
int result;
result = ps3_dma_unmap(dev->d_region, dma_addr, size);
@@ -271,20 +622,20 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
}
}
-static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
+static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction)
{
#if defined(CONFIG_PS3_DYNAMIC_DMA)
BUG_ON("do");
return -EPERM;
#else
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
int i;
for (i = 0; i < nents; i++, sg++) {
int result = ps3_dma_map(dev->d_region,
page_to_phys(sg->page) + sg->offset, sg->length,
- &sg->dma_address);
+ &sg->dma_address, 0);
if (result) {
pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
@@ -299,7 +650,15 @@ static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
#endif
}
-static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
+static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg,
+ int nents,
+ enum dma_data_direction direction)
+{
+ BUG();
+ return 0;
+}
+
+static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction)
{
#if defined(CONFIG_PS3_DYNAMIC_DMA)
@@ -307,18 +666,34 @@ static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
#endif
}
+static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction)
+{
+ BUG();
+}
+
static int ps3_dma_supported(struct device *_dev, u64 mask)
{
return mask >= DMA_32BIT_MASK;
}
-static struct dma_mapping_ops ps3_dma_ops = {
+static struct dma_mapping_ops ps3_sb_dma_ops = {
.alloc_coherent = ps3_alloc_coherent,
.free_coherent = ps3_free_coherent,
- .map_single = ps3_map_single,
+ .map_single = ps3_sb_map_single,
.unmap_single = ps3_unmap_single,
- .map_sg = ps3_map_sg,
- .unmap_sg = ps3_unmap_sg,
+ .map_sg = ps3_sb_map_sg,
+ .unmap_sg = ps3_sb_unmap_sg,
+ .dma_supported = ps3_dma_supported
+};
+
+static struct dma_mapping_ops ps3_ioc0_dma_ops = {
+ .alloc_coherent = ps3_alloc_coherent,
+ .free_coherent = ps3_free_coherent,
+ .map_single = ps3_ioc0_map_single,
+ .unmap_single = ps3_unmap_single,
+ .map_sg = ps3_ioc0_map_sg,
+ .unmap_sg = ps3_ioc0_unmap_sg,
.dma_supported = ps3_dma_supported
};
@@ -328,7 +703,7 @@ static struct dma_mapping_ops ps3_dma_ops = {
static void ps3_system_bus_release_device(struct device *_dev)
{
- struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
+ struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev);
kfree(dev);
}
@@ -343,19 +718,38 @@ static void ps3_system_bus_release_device(struct device *_dev)
int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
{
int result;
- static unsigned int dev_count = 1;
+ static unsigned int dev_ioc0_count;
+ static unsigned int dev_sb_count;
+ static unsigned int dev_vuart_count;
- dev->core.parent = NULL;
+ if (!dev->core.parent)
+ dev->core.parent = &ps3_system_bus;
dev->core.bus = &ps3_system_bus_type;
dev->core.release = ps3_system_bus_release_device;
+ switch (dev->dev_type) {
+ case PS3_DEVICE_TYPE_IOC0:
+ dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops;
+ snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
+ "ioc0_%02x", ++dev_ioc0_count);
+ break;
+ case PS3_DEVICE_TYPE_SB:
+ dev->core.archdata.dma_ops = &ps3_sb_dma_ops;
+ snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
+ "sb_%02x", ++dev_sb_count);
+
+ break;
+ case PS3_DEVICE_TYPE_VUART:
+ snprintf(dev->core.bus_id, sizeof(dev->core.bus_id),
+ "vuart_%02x", ++dev_vuart_count);
+ break;
+ default:
+ BUG();
+ };
+
dev->core.archdata.of_node = NULL;
- dev->core.archdata.dma_ops = &ps3_dma_ops;
dev->core.archdata.numa_node = 0;
- snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
- dev_count++);
-
pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
result = device_register(&dev->core);
@@ -368,9 +762,15 @@ int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
{
int result;
+ pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
+
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return -ENODEV;
+
drv->core.bus = &ps3_system_bus_type;
result = driver_register(&drv->core);
+ pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
return result;
}
@@ -378,7 +778,9 @@ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
{
+ pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name);
driver_unregister(&drv->core);
+ pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name);
}
EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
diff --git a/arch/powerpc/platforms/ps3/time.c b/arch/powerpc/platforms/ps3/time.c
index 1bae8b19b363..802a9ccacb5e 100644
--- a/arch/powerpc/platforms/ps3/time.c
+++ b/arch/powerpc/platforms/ps3/time.c
@@ -39,7 +39,7 @@ static void _dump_tm(const struct rtc_time *tm, const char* func, int line)
}
#define dump_time(_a) _dump_time(_a, __func__, __LINE__)
-static void __attribute__ ((unused)) _dump_time(int time, const char* func,
+static void __maybe_unused _dump_time(int time, const char *func,
int line)
{
struct rtc_time tm;
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index ae1fc92dc1c9..992ba6753cf2 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -8,7 +8,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
-obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o
+obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o
obj-$(CONFIG_KEXEC) += kexec.o
obj-$(CONFIG_PCI) += pci.o pci_dlpar.o
obj-$(CONFIG_PCI_MSI) += msi.o
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 5f3e6d8659fe..b8770395013d 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1,6 +1,8 @@
/*
* eeh.c
- * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation
+ * Copyright IBM Corporation 2001, 2005, 2006
+ * Copyright Dave Engebretsen & Todd Inglett 2001
+ * Copyright Linas Vepstas 2005, 2006
*
* 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
@@ -15,6 +17,8 @@
* 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
+ *
+ * Please address comments and feedback to Linas Vepstas <linas@austin.ibm.com>
*/
#include <linux/delay.h>
@@ -117,7 +121,6 @@ static unsigned long no_cfg_addr;
static unsigned long ignored_check;
static unsigned long total_mmio_ffs;
static unsigned long false_positives;
-static unsigned long ignored_failures;
static unsigned long slot_resets;
#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE)
@@ -505,6 +508,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n",
ret, dn->full_name);
false_positives++;
+ pdn->eeh_false_positives ++;
rc = 0;
goto dn_unlock;
}
@@ -513,6 +517,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
* they are empty when they don't have children. */
if ((rets[0] == 5) && (dn->child == NULL)) {
false_positives++;
+ pdn->eeh_false_positives ++;
rc = 0;
goto dn_unlock;
}
@@ -522,6 +527,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n",
ret, dn->full_name);
false_positives++;
+ pdn->eeh_false_positives ++;
rc = 0;
goto dn_unlock;
}
@@ -529,6 +535,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev)
/* If not the kind of error we know about, punt. */
if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) {
false_positives++;
+ pdn->eeh_false_positives ++;
rc = 0;
goto dn_unlock;
}
@@ -921,6 +928,7 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
pdn->eeh_mode = 0;
pdn->eeh_check_count = 0;
pdn->eeh_freeze_count = 0;
+ pdn->eeh_false_positives = 0;
if (status && strcmp(status, "ok") != 0)
return NULL; /* ignore devices with bad status */
@@ -1139,7 +1147,8 @@ static void eeh_add_device_late(struct pci_dev *dev)
pdn = PCI_DN(dn);
pdn->pcidev = dev;
- pci_addr_cache_insert_device (dev);
+ pci_addr_cache_insert_device(dev);
+ eeh_sysfs_add_device(dev);
}
void eeh_add_device_tree_late(struct pci_bus *bus)
@@ -1178,6 +1187,7 @@ static void eeh_remove_device(struct pci_dev *dev)
printk(KERN_DEBUG "EEH: remove device %s\n", pci_name(dev));
#endif
pci_addr_cache_remove_device(dev);
+ eeh_sysfs_remove_device(dev);
dn = pci_device_to_OF_node(dev);
if (PCI_DN(dn)->pcidev) {
@@ -1214,11 +1224,10 @@ static int proc_eeh_show(struct seq_file *m, void *v)
"check not wanted=%ld\n"
"eeh_total_mmio_ffs=%ld\n"
"eeh_false_positives=%ld\n"
- "eeh_ignored_failures=%ld\n"
"eeh_slot_resets=%ld\n",
no_device, no_dn, no_cfg_addr,
ignored_check, total_mmio_ffs,
- false_positives, ignored_failures,
+ false_positives,
slot_resets);
}
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c
index f2bae04424f8..e49c815eae23 100644
--- a/arch/powerpc/platforms/pseries/eeh_cache.c
+++ b/arch/powerpc/platforms/pseries/eeh_cache.c
@@ -2,7 +2,8 @@
* eeh_cache.c
* PCI address cache; allows the lookup of PCI devices based on I/O address
*
- * Copyright (C) 2004 Linas Vepstas <linas@austin.ibm.com> IBM Corporation
+ * Copyright IBM Corporation 2004
+ * Copyright Linas Vepstas <linas@austin.ibm.com> 2004
*
* 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
@@ -295,6 +296,8 @@ void __init pci_addr_cache_build(void)
continue;
pci_dev_get (dev); /* matching put is in eeh_remove_device() */
PCI_DN(dn)->pcidev = dev;
+
+ eeh_sysfs_add_device(dev);
}
#ifdef DEBUG
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 161a5844ab6c..15e015ef6865 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -1,6 +1,7 @@
/*
* PCI Error Recovery Driver for RPA-compliant PPC64 platform.
- * Copyright (C) 2004, 2005 Linas Vepstas <linas@linas.org>
+ * Copyright IBM Corp. 2004 2005
+ * Copyright Linas Vepstas <linas@linas.org> 2004, 2005
*
* All rights reserved.
*
@@ -19,8 +20,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <linas@us.ibm.com>
- *
+ * Send comments and feedback to Linas Vepstas <linas@austin.ibm.com>
*/
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c
new file mode 100644
index 000000000000..15e13b568904
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c
@@ -0,0 +1,87 @@
+/*
+ * Sysfs entries for PCI Error Recovery for PAPR-compliant platform.
+ * Copyright IBM Corporation 2007
+ * Copyright Linas Vepstas <linas@austin.ibm.com> 2007
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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.
+ *
+ * Send comments and feedback to Linas Vepstas <linas@austin.ibm.com>
+ */
+#include <linux/pci.h>
+#include <asm/ppc-pci.h>
+#include <asm/pci-bridge.h>
+#include <linux/kobject.h>
+
+/**
+ * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic
+ * @_name: name of file in sysfs directory
+ * @_memb: name of member in struct pci_dn to access
+ * @_format: printf format for display
+ *
+ * All of the attributes look very similar, so just
+ * auto-gen a cut-n-paste routine to display them.
+ */
+#define EEH_SHOW_ATTR(_name,_memb,_format) \
+static ssize_t eeh_show_##_name(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct pci_dev *pdev = to_pci_dev(dev); \
+ struct device_node *dn = pci_device_to_OF_node(pdev); \
+ struct pci_dn *pdn; \
+ \
+ if (!dn || PCI_DN(dn) == NULL) \
+ return 0; \
+ \
+ pdn = PCI_DN(dn); \
+ return sprintf(buf, _format "\n", pdn->_memb); \
+} \
+static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL);
+
+
+EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x");
+EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x");
+EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x");
+EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d");
+EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d");
+EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d");
+
+void eeh_sysfs_add_device(struct pci_dev *pdev)
+{
+ int rc=0;
+
+ rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
+ rc += device_create_file(&pdev->dev, &dev_attr_eeh_config_addr);
+ rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
+ rc += device_create_file(&pdev->dev, &dev_attr_eeh_check_count);
+ rc += device_create_file(&pdev->dev, &dev_attr_eeh_false_positives);
+ rc += device_create_file(&pdev->dev, &dev_attr_eeh_freeze_count);
+
+ if (rc)
+ printk(KERN_WARNING "EEH: Unable to create sysfs entries\n");
+}
+
+void eeh_sysfs_remove_device(struct pci_dev *pdev)
+{
+ device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
+ device_remove_file(&pdev->dev, &dev_attr_eeh_config_addr);
+ device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
+ device_remove_file(&pdev->dev, &dev_attr_eeh_check_count);
+ device_remove_file(&pdev->dev, &dev_attr_eeh_false_positives);
+ device_remove_file(&pdev->dev, &dev_attr_eeh_freeze_count);
+}
+
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 29bf83bfb1f0..8b18a1c40092 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -66,24 +66,13 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
* device-tree/ibm,hypertas-functions. Ultimately this functionality may
* be moved into prom.c prom_init().
*/
-void __init fw_feature_init(void)
+void __init fw_feature_init(const char *hypertas, unsigned long len)
{
- struct device_node *dn;
- const char *hypertas, *s;
- int len, i;
+ const char *s;
+ int i;
DBG(" -> fw_feature_init()\n");
- dn = of_find_node_by_path("/rtas");
- if (dn == NULL) {
- printk(KERN_ERR "WARNING! Cannot find RTAS in device-tree!\n");
- goto out;
- }
-
- hypertas = of_get_property(dn, "ibm,hypertas-functions", &len);
- if (hypertas == NULL)
- goto out;
-
for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) {
/* check value against table of strings */
@@ -98,7 +87,5 @@ void __init fw_feature_init(void)
}
}
-out:
- of_node_put(dn);
DBG(" <- fw_feature_init()\n");
}
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 362dfbc260a6..8cc6eeeaae2f 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -373,12 +373,23 @@ static void pSeries_lpar_hptab_clear(void)
{
unsigned long size_bytes = 1UL << ppc64_pft_size;
unsigned long hpte_count = size_bytes >> 4;
- unsigned long dummy1, dummy2;
+ unsigned long dummy1, dummy2, dword0;
+ long lpar_rc;
int i;
/* TODO: Use bulk call */
- for (i = 0; i < hpte_count; i++)
- plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2);
+ for (i = 0; i < hpte_count; i++) {
+ /* dont remove HPTEs with VRMA mappings */
+ lpar_rc = plpar_pte_remove_raw(H_ANDCOND, i, HPTE_V_1TB_SEG,
+ &dummy1, &dummy2);
+ if (lpar_rc == H_NOT_FOUND) {
+ lpar_rc = plpar_pte_read_raw(0, i, &dword0, &dummy1);
+ if (!lpar_rc && ((dword0 & HPTE_V_VRMA_MASK)
+ != HPTE_V_VRMA_MASK))
+ /* Can be hpte for 1TB Seg. So remove it */
+ plpar_pte_remove_raw(0, i, 0, &dummy1, &dummy2);
+ }
+ }
}
/*
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index ffaf6c5c517b..47f0e0857f0e 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -110,8 +110,6 @@ pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus)
}
}
}
-
- eeh_add_device_tree_late(bus);
}
EXPORT_SYMBOL_GPL(pcibios_fixup_new_pci_devices);
@@ -139,6 +137,8 @@ pcibios_pci_config_bridge(struct pci_dev *dev)
/* Make the discovered devices available */
pci_bus_add_devices(child_bus);
+
+ eeh_add_device_tree_late(child_bus);
return 0;
}
@@ -171,6 +171,7 @@ pcibios_add_pci_devices(struct pci_bus * bus)
if (!list_empty(&bus->devices)) {
pcibios_fixup_new_pci_devices(bus, 0);
pci_bus_add_devices(bus);
+ eeh_add_device_tree_late(bus);
}
} else if (mode == PCI_PROBE_NORMAL) {
/* use legacy probe */
@@ -179,6 +180,7 @@ pcibios_add_pci_devices(struct pci_bus * bus)
if (num) {
pcibios_fixup_new_pci_devices(bus, 1);
pci_bus_add_devices(bus);
+ eeh_add_device_tree_late(bus);
}
list_for_each_entry(dev, &bus->devices, bus_list)
@@ -200,8 +202,6 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
rtas_setup_phb(phb);
pci_process_bridge_OF_ranges(phb, dn, 0);
- pci_setup_phb_io_dynamic(phb, primary);
-
pci_devs_phb_init_dynamic(phb);
if (dn->child)
@@ -210,6 +210,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
scan_phb(phb);
pcibios_fixup_new_pci_devices(phb->bus, 0);
pci_bus_add_devices(phb->bus);
+ eeh_add_device_tree_late(phb->bus);
return phb;
}
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index 2e4d10c9eea8..d003c80fa31d 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -108,6 +108,21 @@ static inline long plpar_pte_read(unsigned long flags, unsigned long ptex,
return rc;
}
+/* plpar_pte_read_raw can be called in real mode. It calls plpar_hcall_raw */
+static inline long plpar_pte_read_raw(unsigned long flags, unsigned long ptex,
+ unsigned long *old_pteh_ret, unsigned long *old_ptel_ret)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+ rc = plpar_hcall_raw(H_READ, retbuf, flags, ptex);
+
+ *old_pteh_ret = retbuf[0];
+ *old_ptel_ret = retbuf[1];
+
+ return rc;
+}
+
static inline long plpar_pte_protect(unsigned long flags, unsigned long ptex,
unsigned long avpn)
{
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 2729d559fd91..61136d019554 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -10,7 +10,7 @@
#ifndef _PSERIES_PSERIES_H
#define _PSERIES_PSERIES_H
-extern void __init fw_feature_init(void);
+extern void __init fw_feature_init(const char *hypertas, unsigned long len);
struct pt_regs;
@@ -33,6 +33,8 @@ static inline void setup_kexec_cpu_down_xics(void) { }
static inline void setup_kexec_cpu_down_mpic(void) { }
#endif
+extern void pSeries_final_fixup(void);
+
/* Poweron flag used for enabling auto ups restart */
extern unsigned long rtas_poweron_auto;
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 5aa97aff3391..c02f8742c54d 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -123,7 +123,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
strcpy(np->full_name, path);
np->properties = proplist;
- OF_MARK_DYNAMIC(np);
+ of_node_set_flag(np, OF_DYNAMIC);
kref_init(&np->kref);
np->parent = derive_parent(path);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 470db6efaeb6..f0b7146a110f 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -176,7 +176,7 @@ static void __init pseries_mpic_init_IRQ(void)
return;
cascade_irq = irq_of_parse_and_map(cascade, 0);
- if (cascade == NO_IRQ) {
+ if (cascade_irq == NO_IRQ) {
printk(KERN_ERR "mpic: failed to map cascade interrupt");
return;
}
@@ -320,8 +320,6 @@ static void __init pSeries_init_early(void)
{
DBG(" -> pSeries_init_early()\n");
- fw_feature_init();
-
if (firmware_has_feature(FW_FEATURE_LPAR))
find_udbg_vterm();
@@ -343,14 +341,21 @@ static int __init pSeries_probe_hypertas(unsigned long node,
const char *uname, int depth,
void *data)
{
+ const char *hypertas;
+ unsigned long len;
+
if (depth != 1 ||
(strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0))
- return 0;
+ return 0;
+
+ hypertas = of_get_flat_dt_prop(node, "ibm,hypertas-functions", &len);
+ if (!hypertas)
+ return 1;
- if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
- powerpc_firmware_features |= FW_FEATURE_LPAR;
+ powerpc_firmware_features |= FW_FEATURE_LPAR;
+ fw_feature_init(hypertas, len);
- return 1;
+ return 1;
}
static int __init pSeries_probe(void)
@@ -399,6 +404,7 @@ static void pseries_dedicated_idle_sleep(void)
* a good time to find other work to dispatch.
*/
get_lppaca()->idle = 1;
+ get_lppaca()->donate_dedicated_cpu = 1;
/*
* We come in with interrupts disabled, and need_resched()
@@ -431,6 +437,7 @@ static void pseries_dedicated_idle_sleep(void)
out:
HMT_medium();
+ get_lppaca()->donate_dedicated_cpu = 0;
get_lppaca()->idle = 0;
}
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index f1df942072bb..5bd90a7eb763 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -156,9 +156,9 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
#ifdef CONFIG_SMP
-static int get_irq_server(unsigned int virq)
+static int get_irq_server(unsigned int virq, unsigned int strict_check)
{
- unsigned int server;
+ int server;
/* For the moment only implement delivery to all cpus or one cpu */
cpumask_t cpumask = irq_desc[virq].affinity;
cpumask_t tmp = CPU_MASK_NONE;
@@ -166,22 +166,25 @@ static int get_irq_server(unsigned int virq)
if (!distribute_irqs)
return default_server;
- if (cpus_equal(cpumask, CPU_MASK_ALL)) {
- server = default_distrib_server;
- } else {
+ if (!cpus_equal(cpumask, CPU_MASK_ALL)) {
cpus_and(tmp, cpu_online_map, cpumask);
- if (cpus_empty(tmp))
- server = default_distrib_server;
- else
- server = get_hard_smp_processor_id(first_cpu(tmp));
+ server = first_cpu(tmp);
+
+ if (server < NR_CPUS)
+ return get_hard_smp_processor_id(server);
+
+ if (strict_check)
+ return -1;
}
- return server;
+ if (cpus_equal(cpu_online_map, cpu_present_map))
+ return default_distrib_server;
+ return default_server;
}
#else
-static int get_irq_server(unsigned int virq)
+static int get_irq_server(unsigned int virq, unsigned int strict_check)
{
return default_server;
}
@@ -192,7 +195,7 @@ static void xics_unmask_irq(unsigned int virq)
{
unsigned int irq;
int call_status;
- unsigned int server;
+ int server;
pr_debug("xics: unmask virq %d\n", virq);
@@ -201,7 +204,7 @@ static void xics_unmask_irq(unsigned int virq)
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
return;
- server = get_irq_server(virq);
+ server = get_irq_server(virq, 0);
call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
DEFAULT_PRIORITY);
@@ -398,8 +401,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
unsigned int irq;
int status;
int xics_status[2];
- unsigned long newmask;
- cpumask_t tmp = CPU_MASK_NONE;
+ int irq_server;
irq = (unsigned int)irq_map[virq].hwirq;
if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
@@ -413,18 +415,21 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
return;
}
- /* For the moment only implement delivery to all cpus or one cpu */
- if (cpus_equal(cpumask, CPU_MASK_ALL)) {
- newmask = default_distrib_server;
- } else {
- cpus_and(tmp, cpu_online_map, cpumask);
- if (cpus_empty(tmp))
- return;
- newmask = get_hard_smp_processor_id(first_cpu(tmp));
+ /*
+ * For the moment only implement delivery to all cpus or one cpu.
+ * Get current irq_server for the given irq
+ */
+ irq_server = get_irq_server(irq, 1);
+ if (irq_server == -1) {
+ char cpulist[128];
+ cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
+ printk(KERN_WARNING "xics_set_affinity: No online cpus in "
+ "the mask %s for irq %d\n", cpulist, virq);
+ return;
}
status = rtas_call(ibm_set_xive, 3, 1, NULL,
- irq, newmask, xics_status[1]);
+ irq, irq_server, xics_status[1]);
if (status) {
printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index c3ce0bd12c0b..484eb4e0e9db 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -5,7 +5,6 @@ endif
mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
-obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_MPC106) += grackle.o
obj-$(CONFIG_PPC_DCR) += dcr.o
obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o
@@ -13,16 +12,20 @@ obj-$(CONFIG_PPC_PMI) += pmi.o
obj-$(CONFIG_U3_DART) += dart_iommu.o
obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
-obj-$(CONFIG_FSL_PCIE) += fsl_pcie.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
mv64x60-$(CONFIG_PCI) += mv64x60_pci.o
obj-$(CONFIG_MV64X60) += $(mv64x60-y) mv64x60_pic.o mv64x60_dev.o
+obj-$(CONFIG_RTC_DRV_CMOS) += rtc_cmos_setup.o
+obj-$(CONFIG_AXON_RAM) += axonram.o
# contains only the suspend handler for time
+ifeq ($(CONFIG_RTC_CLASS),)
obj-$(CONFIG_PM) += timer.o
+endif
ifeq ($(CONFIG_PPC_MERGE),y)
+obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPC_I8259) += i8259.o
obj-$(CONFIG_PPC_83xx) += ipic.o
obj-$(CONFIG_4xx) += uic.o
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
new file mode 100644
index 000000000000..2326d5dc5752
--- /dev/null
+++ b/arch/powerpc/sysdev/axonram.c
@@ -0,0 +1,381 @@
+/*
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2006
+ *
+ * Author: Maxim Shchetynin <maxim@de.ibm.com>
+ *
+ * Axon DDR2 device driver.
+ * It registers one block device per Axon's DDR2 memory bank found on a system.
+ * Block devices are called axonram?, their major and minor numbers are
+ * available in /proc/devices, /proc/partitions or in /sys/block/axonram?/dev.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+
+#define AXON_RAM_MODULE_NAME "axonram"
+#define AXON_RAM_DEVICE_NAME "axonram"
+#define AXON_RAM_MINORS_PER_DISK 16
+#define AXON_RAM_BLOCK_SHIFT PAGE_SHIFT
+#define AXON_RAM_BLOCK_SIZE 1 << AXON_RAM_BLOCK_SHIFT
+#define AXON_RAM_SECTOR_SHIFT 9
+#define AXON_RAM_SECTOR_SIZE 1 << AXON_RAM_SECTOR_SHIFT
+#define AXON_RAM_IRQ_FLAGS IRQF_SHARED | IRQF_TRIGGER_RISING
+
+struct axon_ram_bank {
+ struct of_device *device;
+ struct gendisk *disk;
+ unsigned int irq_correctable;
+ unsigned int irq_uncorrectable;
+ unsigned long ph_addr;
+ unsigned long io_addr;
+ unsigned long size;
+ unsigned long ecc_counter;
+};
+
+static ssize_t
+axon_ram_sysfs_ecc(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct of_device *device = to_of_device(dev);
+ struct axon_ram_bank *bank = device->dev.platform_data;
+
+ BUG_ON(!bank);
+
+ return sprintf(buf, "%ld\n", bank->ecc_counter);
+}
+
+static DEVICE_ATTR(ecc, S_IRUGO, axon_ram_sysfs_ecc, NULL);
+
+/**
+ * axon_ram_irq_handler - interrupt handler for Axon RAM ECC
+ * @irq: interrupt ID
+ * @dev: pointer to of_device
+ */
+static irqreturn_t
+axon_ram_irq_handler(int irq, void *dev)
+{
+ struct of_device *device = dev;
+ struct axon_ram_bank *bank = device->dev.platform_data;
+
+ BUG_ON(!bank);
+
+ if (irq == bank->irq_correctable) {
+ dev_err(&device->dev, "Correctable memory error occured\n");
+ bank->ecc_counter++;
+ return IRQ_HANDLED;
+ } else if (irq == bank->irq_uncorrectable) {
+ dev_err(&device->dev, "Uncorrectable memory error occured\n");
+ panic("Critical ECC error on %s", device->node->full_name);
+ }
+
+ return IRQ_NONE;
+}
+
+/**
+ * axon_ram_make_request - make_request() method for block device
+ * @queue, @bio: see blk_queue_make_request()
+ */
+static int
+axon_ram_make_request(struct request_queue *queue, struct bio *bio)
+{
+ struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data;
+ unsigned long phys_mem, phys_end;
+ void *user_mem;
+ struct bio_vec *vec;
+ unsigned int transfered;
+ unsigned short idx;
+ int rc = 0;
+
+ phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT);
+ phys_end = bank->io_addr + bank->size;
+ transfered = 0;
+ bio_for_each_segment(vec, bio, idx) {
+ if (unlikely(phys_mem + vec->bv_len > phys_end)) {
+ bio_io_error(bio, bio->bi_size);
+ rc = -ERANGE;
+ break;
+ }
+
+ user_mem = page_address(vec->bv_page) + vec->bv_offset;
+ if (bio_data_dir(bio) == READ)
+ memcpy(user_mem, (void *) phys_mem, vec->bv_len);
+ else
+ memcpy((void *) phys_mem, user_mem, vec->bv_len);
+
+ phys_mem += vec->bv_len;
+ transfered += vec->bv_len;
+ }
+ bio_endio(bio, transfered, 0);
+
+ return rc;
+}
+
+/**
+ * axon_ram_direct_access - direct_access() method for block device
+ * @device, @sector, @data: see block_device_operations method
+ */
+static int
+axon_ram_direct_access(struct block_device *device, sector_t sector,
+ unsigned long *data)
+{
+ struct axon_ram_bank *bank = device->bd_disk->private_data;
+ loff_t offset;
+
+ offset = sector << AXON_RAM_SECTOR_SHIFT;
+ if (offset >= bank->size) {
+ dev_err(&bank->device->dev, "Access outside of address space\n");
+ return -ERANGE;
+ }
+
+ *data = bank->ph_addr + offset;
+
+ return 0;
+}
+
+static struct block_device_operations axon_ram_devops = {
+ .owner = THIS_MODULE,
+ .direct_access = axon_ram_direct_access
+};
+
+/**
+ * axon_ram_probe - probe() method for platform driver
+ * @device, @device_id: see of_platform_driver method
+ */
+static int
+axon_ram_probe(struct of_device *device, const struct of_device_id *device_id)
+{
+ static int axon_ram_bank_id = -1;
+ struct axon_ram_bank *bank;
+ struct resource resource;
+ int rc = 0;
+
+ axon_ram_bank_id++;
+
+ dev_info(&device->dev, "Found memory controller on %s\n",
+ device->node->full_name);
+
+ bank = kzalloc(sizeof(struct axon_ram_bank), GFP_KERNEL);
+ if (bank == NULL) {
+ dev_err(&device->dev, "Out of memory\n");
+ rc = -ENOMEM;
+ goto failed;
+ }
+
+ device->dev.platform_data = bank;
+
+ bank->device = device;
+
+ if (of_address_to_resource(device->node, 0, &resource) != 0) {
+ dev_err(&device->dev, "Cannot access device tree\n");
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ bank->size = resource.end - resource.start + 1;
+
+ if (bank->size == 0) {
+ dev_err(&device->dev, "No DDR2 memory found for %s%d\n",
+ AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+ rc = -ENODEV;
+ goto failed;
+ }
+
+ dev_info(&device->dev, "Register DDR2 memory device %s%d with %luMB\n",
+ AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20);
+
+ bank->ph_addr = resource.start;
+ bank->io_addr = (unsigned long) ioremap_flags(
+ bank->ph_addr, bank->size, _PAGE_NO_CACHE);
+ if (bank->io_addr == 0) {
+ dev_err(&device->dev, "ioremap() failed\n");
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ bank->disk = alloc_disk(AXON_RAM_MINORS_PER_DISK);
+ if (bank->disk == NULL) {
+ dev_err(&device->dev, "Cannot register disk\n");
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ bank->disk->first_minor = 0;
+ bank->disk->fops = &axon_ram_devops;
+ bank->disk->private_data = bank;
+ bank->disk->driverfs_dev = &device->dev;
+
+ sprintf(bank->disk->disk_name, "%s%d",
+ AXON_RAM_DEVICE_NAME, axon_ram_bank_id);
+ bank->disk->major = register_blkdev(0, bank->disk->disk_name);
+ if (bank->disk->major < 0) {
+ dev_err(&device->dev, "Cannot register block device\n");
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ bank->disk->queue = blk_alloc_queue(GFP_KERNEL);
+ if (bank->disk->queue == NULL) {
+ dev_err(&device->dev, "Cannot register disk queue\n");
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ set_capacity(bank->disk, bank->size >> AXON_RAM_SECTOR_SHIFT);
+ blk_queue_make_request(bank->disk->queue, axon_ram_make_request);
+ blk_queue_hardsect_size(bank->disk->queue, AXON_RAM_SECTOR_SIZE);
+ add_disk(bank->disk);
+
+ bank->irq_correctable = irq_of_parse_and_map(device->node, 0);
+ bank->irq_uncorrectable = irq_of_parse_and_map(device->node, 1);
+ if ((bank->irq_correctable <= 0) || (bank->irq_uncorrectable <= 0)) {
+ dev_err(&device->dev, "Cannot access ECC interrupt ID\n");
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ rc = request_irq(bank->irq_correctable, axon_ram_irq_handler,
+ AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+ if (rc != 0) {
+ dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+ bank->irq_correctable = bank->irq_uncorrectable = 0;
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ rc = request_irq(bank->irq_uncorrectable, axon_ram_irq_handler,
+ AXON_RAM_IRQ_FLAGS, bank->disk->disk_name, device);
+ if (rc != 0) {
+ dev_err(&device->dev, "Cannot register ECC interrupt handler\n");
+ bank->irq_uncorrectable = 0;
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ rc = device_create_file(&device->dev, &dev_attr_ecc);
+ if (rc != 0) {
+ dev_err(&device->dev, "Cannot create sysfs file\n");
+ rc = -EFAULT;
+ goto failed;
+ }
+
+ return 0;
+
+failed:
+ if (bank != NULL) {
+ if (bank->irq_uncorrectable > 0)
+ free_irq(bank->irq_uncorrectable, device);
+ if (bank->irq_correctable > 0)
+ free_irq(bank->irq_correctable, device);
+ if (bank->disk != NULL) {
+ if (bank->disk->queue != NULL)
+ blk_cleanup_queue(bank->disk->queue);
+ if (bank->disk->major > 0)
+ unregister_blkdev(bank->disk->major,
+ bank->disk->disk_name);
+ del_gendisk(bank->disk);
+ }
+ device->dev.platform_data = NULL;
+ if (bank->io_addr != 0)
+ iounmap((void __iomem *) bank->io_addr);
+ kfree(bank);
+ }
+
+ return rc;
+}
+
+/**
+ * axon_ram_remove - remove() method for platform driver
+ * @device: see of_platform_driver method
+ */
+static int
+axon_ram_remove(struct of_device *device)
+{
+ struct axon_ram_bank *bank = device->dev.platform_data;
+
+ BUG_ON(!bank || !bank->disk);
+
+ device_remove_file(&device->dev, &dev_attr_ecc);
+ free_irq(bank->irq_uncorrectable, device);
+ free_irq(bank->irq_correctable, device);
+ blk_cleanup_queue(bank->disk->queue);
+ unregister_blkdev(bank->disk->major, bank->disk->disk_name);
+ del_gendisk(bank->disk);
+ iounmap((void __iomem *) bank->io_addr);
+ kfree(bank);
+
+ return 0;
+}
+
+static struct of_device_id axon_ram_device_id[] = {
+ {
+ .type = "dma-memory"
+ },
+ {}
+};
+
+static struct of_platform_driver axon_ram_driver = {
+ .owner = THIS_MODULE,
+ .name = AXON_RAM_MODULE_NAME,
+ .match_table = axon_ram_device_id,
+ .probe = axon_ram_probe,
+ .remove = axon_ram_remove
+};
+
+/**
+ * axon_ram_init
+ */
+static int __init
+axon_ram_init(void)
+{
+ return of_register_platform_driver(&axon_ram_driver);
+}
+
+/**
+ * axon_ram_exit
+ */
+static void __exit
+axon_ram_exit(void)
+{
+ of_unregister_platform_driver(&axon_ram_driver);
+}
+
+module_init(axon_ram_init);
+module_exit(axon_ram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Shchetynin <maxim@de.ibm.com>");
+MODULE_DESCRIPTION("Axon DDR2 RAM device driver for IBM Cell BE");
diff --git a/arch/powerpc/sysdev/fsl_pcie.c b/arch/powerpc/sysdev/fsl_pcie.c
deleted file mode 100644
index 041c07e8b665..000000000000
--- a/arch/powerpc/sysdev/fsl_pcie.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Support for indirect PCI bridges.
- *
- * Copyright (C) 1998 Gabriel Paubert.
- *
- * 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.
- *
- * "Temporary" MPC8548 Errata file -
- * The standard indirect_pci code should work with future silicon versions.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-
-#define PCI_CFG_OUT out_be32
-
-/* ERRATA PCI-Ex 14 PCIE Controller timeout */
-#define PCIE_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff)
-
-
-static int
-indirect_read_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
- int len, u32 *val)
-{
- struct pci_controller *hose = bus->sysdata;
- volatile void __iomem *cfg_data;
- u32 temp;
-
- if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfn))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- /* Possible artifact of CDCpp50937 needs further investigation */
- if (devfn != 0x0 && bus->number == 0xff)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- PCIE_FIX;
- if (bus->number == 0xff) {
- PCI_CFG_OUT(hose->cfg_addr,
- (0x80000000 | ((offset & 0xf00) << 16) |
- ((bus->number - hose->bus_offset) << 16)
- | (devfn << 8) | ((offset & 0xfc) )));
- } else {
- PCI_CFG_OUT(hose->cfg_addr,
- (0x80000001 | ((offset & 0xf00) << 16) |
- ((bus->number - hose->bus_offset) << 16)
- | (devfn << 8) | ((offset & 0xfc) )));
- }
-
- /*
- * Note: the caller has already checked that offset is
- * suitably aligned and that len is 1, 2 or 4.
- */
- /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
- cfg_data = hose->cfg_data;
- PCIE_FIX;
- temp = in_le32(cfg_data);
- switch (len) {
- case 1:
- *val = (temp >> (((offset & 3))*8)) & 0xff;
- break;
- case 2:
- *val = (temp >> (((offset & 3))*8)) & 0xffff;
- break;
- default:
- *val = temp;
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-indirect_write_config_pcie(struct pci_bus *bus, unsigned int devfn, int offset,
- int len, u32 val)
-{
- struct pci_controller *hose = bus->sysdata;
- volatile void __iomem *cfg_data;
- u32 temp;
-
- if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfn))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- /* Possible artifact of CDCpp50937 needs further investigation */
- if (devfn != 0x0 && bus->number == 0xff)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- PCIE_FIX;
- if (bus->number == 0xff) {
- PCI_CFG_OUT(hose->cfg_addr,
- (0x80000000 | ((offset & 0xf00) << 16) |
- ((bus->number - hose->bus_offset) << 16)
- | (devfn << 8) | ((offset & 0xfc) )));
- } else {
- PCI_CFG_OUT(hose->cfg_addr,
- (0x80000001 | ((offset & 0xf00) << 16) |
- ((bus->number - hose->bus_offset) << 16)
- | (devfn << 8) | ((offset & 0xfc) )));
- }
-
- /*
- * Note: the caller has already checked that offset is
- * suitably aligned and that len is 1, 2 or 4.
- */
- /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */
- cfg_data = hose->cfg_data;
- switch (len) {
- case 1:
- PCIE_FIX;
- temp = in_le32(cfg_data);
- temp = (temp & ~(0xff << ((offset & 3) * 8))) |
- (val << ((offset & 3) * 8));
- PCIE_FIX;
- out_le32(cfg_data, temp);
- break;
- case 2:
- PCIE_FIX;
- temp = in_le32(cfg_data);
- temp = (temp & ~(0xffff << ((offset & 3) * 8)));
- temp |= (val << ((offset & 3) * 8)) ;
- PCIE_FIX;
- out_le32(cfg_data, temp);
- break;
- default:
- PCIE_FIX;
- out_le32(cfg_data, val);
- break;
- }
- PCIE_FIX;
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops indirect_pcie_ops = {
- indirect_read_config_pcie,
- indirect_write_config_pcie
-};
-
-void __init
-setup_indirect_pcie_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
- void __iomem * cfg_data)
-{
- hose->cfg_addr = cfg_addr;
- hose->cfg_data = cfg_data;
- hose->ops = &indirect_pcie_ops;
-}
-
-void __init
-setup_indirect_pcie(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
-{
- unsigned long base = cfg_addr & PAGE_MASK;
- void __iomem *mbase, *addr, *data;
-
- mbase = ioremap(base, PAGE_SIZE);
- addr = mbase + (cfg_addr & ~PAGE_MASK);
- if ((cfg_data & PAGE_MASK) != base)
- mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
- data = mbase + (cfg_data & ~PAGE_MASK);
- setup_indirect_pcie_nomap(hose, addr, data);
-}
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index cad175724359..3289fab01e92 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -197,6 +197,7 @@ static int __init gfar_of_init(void)
struct gianfar_platform_data gfar_data;
const unsigned int *id;
const char *model;
+ const char *ctype;
const void *mac_addr;
const phandle *ph;
int n_res = 2;
@@ -254,6 +255,14 @@ static int __init gfar_of_init(void)
FSL_GIANFAR_DEV_HAS_VLAN |
FSL_GIANFAR_DEV_HAS_EXTENDED_HASH;
+ ctype = of_get_property(np, "phy-connection-type", NULL);
+
+ /* We only care about rgmii-id. The rest are autodetected */
+ if (ctype && !strcmp(ctype, "rgmii-id"))
+ gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID;
+ else
+ gfar_data.interface = PHY_INTERFACE_MODE_MII;
+
ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
@@ -1028,6 +1037,19 @@ err:
arch_initcall(fs_enet_of_init);
+static int __init fsl_pcmcia_of_init(void)
+{
+ struct device_node *np = NULL;
+ /*
+ * Register all the devices which type is "pcmcia"
+ */
+ while ((np = of_find_compatible_node(np,
+ "pcmcia", "fsl,pq-pcmcia")) != NULL)
+ of_platform_device_create(np, "m8xx-pcmcia", NULL);
+ return 0;
+}
+
+arch_initcall(fsl_pcmcia_of_init);
static const char *smc_regs = "regs";
static const char *smc_pram = "pram";
diff --git a/arch/powerpc/sysdev/indirect_pci.c b/arch/powerpc/sysdev/indirect_pci.c
index e71488469704..c7e6e859b393 100644
--- a/arch/powerpc/sysdev/indirect_pci.c
+++ b/arch/powerpc/sysdev/indirect_pci.c
@@ -33,18 +33,27 @@ indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
struct pci_controller *hose = bus->sysdata;
volatile void __iomem *cfg_data;
u8 cfg_type = 0;
+ u32 bus_no, reg;
if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfn))
+ if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
- if (hose->set_cfg_type)
+ if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
if (bus->number != hose->first_busno)
cfg_type = 1;
- PCI_CFG_OUT(hose->cfg_addr,
- (0x80000000 | ((bus->number - hose->bus_offset) << 16)
- | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+ bus_no = (bus->number == hose->first_busno) ?
+ hose->self_busno : bus->number;
+
+ if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
+ reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+ else
+ reg = offset & 0xfc;
+
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000000 | (bus_no << 16)
+ | (devfn << 8) | reg | cfg_type));
/*
* Note: the caller has already checked that offset is
@@ -72,18 +81,33 @@ indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
struct pci_controller *hose = bus->sysdata;
volatile void __iomem *cfg_data;
u8 cfg_type = 0;
+ u32 bus_no, reg;
if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfn))
+ if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
- if (hose->set_cfg_type)
+ if (hose->indirect_type & PPC_INDIRECT_TYPE_SET_CFG_TYPE)
if (bus->number != hose->first_busno)
cfg_type = 1;
- PCI_CFG_OUT(hose->cfg_addr,
- (0x80000000 | ((bus->number - hose->bus_offset) << 16)
- | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+ bus_no = (bus->number == hose->first_busno) ?
+ hose->self_busno : bus->number;
+
+ if (hose->indirect_type & PPC_INDIRECT_TYPE_EXT_REG)
+ reg = ((offset & 0xf00) << 16) | (offset & 0xfc);
+ else
+ reg = offset & 0xfc;
+
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000000 | (bus_no << 16)
+ | (devfn << 8) | reg | cfg_type));
+
+ /* surpress setting of PCI_PRIMARY_BUS */
+ if (hose->indirect_type & PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS)
+ if ((offset == PCI_PRIMARY_BUS) &&
+ (bus->number == hose->first_busno))
+ val &= 0xffffff00;
/*
* Note: the caller has already checked that offset is
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.h b/arch/powerpc/sysdev/mpc8xx_pic.h
index afa2ee6717c1..9fe00eebdc8b 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.h
+++ b/arch/powerpc/sysdev/mpc8xx_pic.h
@@ -4,9 +4,16 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
-extern struct hw_interrupt_type mpc8xx_pic;
-
int mpc8xx_pic_init(void);
unsigned int mpc8xx_get_irq(void);
+/*
+ * Some internal interrupt registers use an 8-bit mask for the interrupt
+ * level instead of a number.
+ */
+static inline uint mk_int_int_mask(uint mask)
+{
+ return (1 << (7 - (mask/2)));
+}
+
#endif /* _PPC_KERNEL_PPC8xx_H */
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 75aad38179f0..74c64c0d3b71 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -877,6 +877,8 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
if (hw == mpic->spurious_vec)
return -EINVAL;
+ if (mpic->protected && test_bit(hw, mpic->protected))
+ return -EINVAL;
#ifdef CONFIG_SMP
else if (hw >= mpic->ipi_vecs[0]) {
@@ -1034,6 +1036,25 @@ struct mpic * __init mpic_alloc(struct device_node *node,
if (node && of_get_property(node, "big-endian", NULL) != NULL)
mpic->flags |= MPIC_BIG_ENDIAN;
+ /* Look for protected sources */
+ if (node) {
+ unsigned int psize, bits, mapsize;
+ const u32 *psrc =
+ of_get_property(node, "protected-sources", &psize);
+ if (psrc) {
+ psize /= 4;
+ bits = intvec_top + 1;
+ mapsize = BITS_TO_LONGS(bits) * sizeof(unsigned long);
+ mpic->protected = alloc_bootmem(mapsize);
+ BUG_ON(mpic->protected == NULL);
+ memset(mpic->protected, 0, mapsize);
+ for (i = 0; i < psize; i++) {
+ if (psrc[i] > intvec_top)
+ continue;
+ __set_bit(psrc[i], mpic->protected);
+ }
+ }
+ }
#ifdef CONFIG_MPIC_WEIRD
mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)];
@@ -1213,6 +1234,9 @@ void __init mpic_init(struct mpic *mpic)
u32 vecpri = MPIC_VECPRI_MASK | i |
(8 << MPIC_VECPRI_PRIORITY_SHIFT);
+ /* check if protected */
+ if (mpic->protected && test_bit(i, mpic->protected))
+ continue;
/* init hw */
mpic_irq_write(i, MPIC_INFO(IRQ_VECTOR_PRI), vecpri);
mpic_irq_write(i, MPIC_INFO(IRQ_DESTINATION),
@@ -1407,6 +1431,14 @@ unsigned int mpic_get_one_irq(struct mpic *mpic)
mpic_eoi(mpic);
return NO_IRQ;
}
+ if (unlikely(mpic->protected && test_bit(src, mpic->protected))) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING "%s: Got protected source %d !\n",
+ mpic->name, (int)src);
+ mpic_eoi(mpic);
+ return NO_IRQ;
+ }
+
return irq_linear_revmap(mpic->irqhost, src);
}
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c
index 4b0a9c88eeb3..b618fa60aef3 100644
--- a/arch/powerpc/sysdev/mv64x60_dev.c
+++ b/arch/powerpc/sysdev/mv64x60_dev.c
@@ -12,6 +12,7 @@
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/console.h>
#include <linux/mv643xx.h>
#include <linux/platform_device.h>
@@ -420,3 +421,30 @@ error:
return err;
}
arch_initcall(mv64x60_device_setup);
+
+static int __init mv64x60_add_mpsc_console(void)
+{
+ struct device_node *np = NULL;
+ const char *prop;
+
+ prop = of_get_property(of_chosen, "linux,stdout-path", NULL);
+ if (prop == NULL)
+ goto not_mpsc;
+
+ np = of_find_node_by_path(prop);
+ if (!np)
+ goto not_mpsc;
+
+ if (!of_device_is_compatible(np, "marvell,mpsc"))
+ goto not_mpsc;
+
+ prop = of_get_property(np, "block-index", NULL);
+ if (!prop)
+ goto not_mpsc;
+
+ add_preferred_console("ttyMM", *(int *)prop, NULL);
+
+not_mpsc:
+ return 0;
+}
+console_initcall(mv64x60_add_mpsc_console);
diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c
index b5aef4cbc8d2..45db86c2363c 100644
--- a/arch/powerpc/sysdev/mv64x60_pci.c
+++ b/arch/powerpc/sysdev/mv64x60_pci.c
@@ -137,18 +137,15 @@ static int __init mv64x60_add_bridge(struct device_node *dev)
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
- hose = pcibios_alloc_controller();
+ hose = pcibios_alloc_controller(dev);
if (!hose)
return -ENOMEM;
- hose->arch_data = dev;
- hose->set_cfg_type = 1;
-
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
setup_indirect_pci(hose, rsrc.start, rsrc.start + 4);
- hose->bus_offset = hose->first_busno;
+ hose->self_busno = hose->first_busno;
printk(KERN_INFO "Found MV64x60 PCI host bridge at 0x%016llx. "
"Firmware bus number: %d->%d\n",
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c
index 85a7c99c1003..2f91b55b7754 100644
--- a/arch/powerpc/sysdev/pmi.c
+++ b/arch/powerpc/sysdev/pmi.c
@@ -48,15 +48,13 @@ struct pmi_data {
struct work_struct work;
};
+static struct pmi_data *data;
static int pmi_irq_handler(int irq, void *dev_id)
{
- struct pmi_data *data;
u8 type;
int rc;
- data = dev_id;
-
spin_lock(&data->pmi_spinlock);
type = ioread8(data->pmi_reg + PMI_READ_TYPE);
@@ -111,16 +109,13 @@ MODULE_DEVICE_TABLE(of, pmi_match);
static void pmi_notify_handlers(struct work_struct *work)
{
- struct pmi_data *data;
struct pmi_handler *handler;
- data = container_of(work, struct pmi_data, work);
-
spin_lock(&data->handler_spinlock);
list_for_each_entry(handler, &data->handler, node) {
pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler);
if (handler->type == data->msg.type)
- handler->handle_pmi_message(data->dev, data->msg);
+ handler->handle_pmi_message(data->msg);
}
spin_unlock(&data->handler_spinlock);
}
@@ -129,9 +124,14 @@ static int pmi_of_probe(struct of_device *dev,
const struct of_device_id *match)
{
struct device_node *np = dev->node;
- struct pmi_data *data;
int rc;
+ if (data) {
+ printk(KERN_ERR "pmi: driver has already been initialized.\n");
+ rc = -EBUSY;
+ goto out;
+ }
+
data = kzalloc(sizeof(struct pmi_data), GFP_KERNEL);
if (!data) {
printk(KERN_ERR "pmi: could not allocate memory.\n");
@@ -154,7 +154,6 @@ static int pmi_of_probe(struct of_device *dev,
INIT_WORK(&data->work, pmi_notify_handlers);
- dev->dev.driver_data = data;
data->dev = dev;
data->irq = irq_of_parse_and_map(np, 0);
@@ -164,7 +163,7 @@ static int pmi_of_probe(struct of_device *dev,
goto error_cleanup_iomap;
}
- rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", data);
+ rc = request_irq(data->irq, pmi_irq_handler, 0, "pmi", NULL);
if (rc) {
printk(KERN_ERR "pmi: can't request IRQ %d: returned %d\n",
data->irq, rc);
@@ -187,12 +186,9 @@ out:
static int pmi_of_remove(struct of_device *dev)
{
- struct pmi_data *data;
struct pmi_handler *handler, *tmp;
- data = dev->dev.driver_data;
-
- free_irq(data->irq, data);
+ free_irq(data->irq, NULL);
iounmap(data->pmi_reg);
spin_lock(&data->handler_spinlock);
@@ -202,7 +198,8 @@ static int pmi_of_remove(struct of_device *dev)
spin_unlock(&data->handler_spinlock);
- kfree(dev->dev.driver_data);
+ kfree(data);
+ data = NULL;
return 0;
}
@@ -226,13 +223,13 @@ static void __exit pmi_module_exit(void)
}
module_exit(pmi_module_exit);
-void pmi_send_message(struct of_device *device, pmi_message_t msg)
+int pmi_send_message(pmi_message_t msg)
{
- struct pmi_data *data;
unsigned long flags;
DECLARE_COMPLETION_ONSTACK(completion);
- data = device->dev.driver_data;
+ if (!data)
+ return -ENODEV;
mutex_lock(&data->msg_mutex);
@@ -256,30 +253,26 @@ void pmi_send_message(struct of_device *device, pmi_message_t msg)
data->completion = NULL;
mutex_unlock(&data->msg_mutex);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(pmi_send_message);
-void pmi_register_handler(struct of_device *device,
- struct pmi_handler *handler)
+int pmi_register_handler(struct pmi_handler *handler)
{
- struct pmi_data *data;
- data = device->dev.driver_data;
-
if (!data)
- return;
+ return -ENODEV;
spin_lock(&data->handler_spinlock);
list_add_tail(&handler->node, &data->handler);
spin_unlock(&data->handler_spinlock);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(pmi_register_handler);
-void pmi_unregister_handler(struct of_device *device,
- struct pmi_handler *handler)
+void pmi_unregister_handler(struct pmi_handler *handler)
{
- struct pmi_data *data;
- data = device->dev.driver_data;
-
if (!data)
return;
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
index ac12a44d516f..f970e5415ac0 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc.c
@@ -18,6 +18,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/stddef.h>
+#include <linux/module.h>
#include <asm/irq.h>
#include <asm/io.h>
@@ -40,6 +41,7 @@ int ucc_set_qe_mux_mii_mng(int ucc_num)
return 0;
}
+EXPORT_SYMBOL(ucc_set_qe_mux_mii_mng);
int ucc_set_type(int ucc_num, struct ucc_common *regs,
enum ucc_speed_type speed)
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
index 9143236853fc..3df202e8d332 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -19,6 +19,7 @@
#include <linux/stddef.h>
#include <linux/interrupt.h>
#include <linux/err.h>
+#include <linux/module.h>
#include <asm/io.h>
#include <asm/immap_qe.h>
@@ -70,6 +71,7 @@ void ucc_fast_dump_regs(struct ucc_fast_private * uccf)
printk(KERN_INFO "guemr : addr - 0x%08x, val - 0x%02x",
(u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr);
}
+EXPORT_SYMBOL(ucc_fast_dump_regs);
u32 ucc_fast_get_qe_cr_subblock(int uccf_num)
{
@@ -85,11 +87,13 @@ u32 ucc_fast_get_qe_cr_subblock(int uccf_num)
default: return QE_CR_SUBBLOCK_INVALID;
}
}
+EXPORT_SYMBOL(ucc_fast_get_qe_cr_subblock);
void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf)
{
out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
}
+EXPORT_SYMBOL(ucc_fast_transmit_on_demand);
void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode)
{
@@ -110,6 +114,7 @@ void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode)
}
out_be32(&uf_regs->gumr, gumr);
}
+EXPORT_SYMBOL(ucc_fast_enable);
void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode)
{
@@ -130,6 +135,7 @@ void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode)
}
out_be32(&uf_regs->gumr, gumr);
}
+EXPORT_SYMBOL(ucc_fast_disable);
int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret)
{
@@ -341,6 +347,7 @@ int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** ucc
*uccf_ret = uccf;
return 0;
}
+EXPORT_SYMBOL(ucc_fast_init);
void ucc_fast_free(struct ucc_fast_private * uccf)
{
@@ -355,3 +362,4 @@ void ucc_fast_free(struct ucc_fast_private * uccf)
kfree(uccf);
}
+EXPORT_SYMBOL(ucc_fast_free);
diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c
new file mode 100644
index 000000000000..e276048b8c5f
--- /dev/null
+++ b/arch/powerpc/sysdev/rtc_cmos_setup.c
@@ -0,0 +1,49 @@
+/*
+ * Setup code for PC-style Real-Time Clock.
+ *
+ * Author: Wade Farnsworth <wfarnsworth@mvista.com>
+ *
+ * 2007 (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.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/prom.h>
+
+static int __init add_rtc(void)
+{
+ struct device_node *np;
+ struct platform_device *pd;
+ struct resource res;
+ int ret;
+
+ np = of_find_compatible_node(NULL, NULL, "pnpPNP,b00");
+ if (!np)
+ return -ENODEV;
+
+ ret = of_address_to_resource(np, 0, &res);
+ of_node_put(np);
+ if (ret)
+ return ret;
+
+ /*
+ * RTC_PORT(x) is hardcoded in asm/mc146818rtc.h. Verify that the
+ * address provided by the device node matches.
+ */
+ if (res.start != RTC_PORT(0))
+ return -EINVAL;
+
+ pd = platform_device_register_simple("rtc_cmos", -1,
+ &res, 1);
+ if (IS_ERR(pd))
+ return PTR_ERR(pd);
+
+ return 0;
+}
+fs_initcall(add_rtc);
diff --git a/arch/powerpc/sysdev/timer.c b/arch/powerpc/sysdev/timer.c
index 4a01748b4217..e81e7ec2e799 100644
--- a/arch/powerpc/sysdev/timer.c
+++ b/arch/powerpc/sysdev/timer.c
@@ -24,7 +24,12 @@ static int timer_resume(struct sys_device *dev)
/* get current RTC time and convert to seconds */
get_rtc_time(&cur_rtc_tm);
- rtc_tm_to_time(&cur_rtc_tm, &cur_rtc_time);
+ cur_rtc_time = mktime(cur_rtc_tm.tm_year + 1900,
+ cur_rtc_tm.tm_mon + 1,
+ cur_rtc_tm.tm_mday,
+ cur_rtc_tm.tm_hour,
+ cur_rtc_tm.tm_min,
+ cur_rtc_tm.tm_sec);
diff = cur_rtc_time - suspend_rtc_time;
@@ -44,7 +49,12 @@ static int timer_suspend(struct sys_device *dev, pm_message_t state)
WARN_ON(!ppc_md.get_rtc_time);
get_rtc_time(&suspend_rtc_tm);
- rtc_tm_to_time(&suspend_rtc_tm, &suspend_rtc_time);
+ suspend_rtc_time = mktime(suspend_rtc_tm.tm_year + 1900,
+ suspend_rtc_tm.tm_mon + 1,
+ suspend_rtc_tm.tm_mday,
+ suspend_rtc_tm.tm_hour,
+ suspend_rtc_tm.tm_min,
+ suspend_rtc_tm.tm_sec);
return 0;
}
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index 7d3b09b7d544..a113d800cbf0 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -72,12 +72,11 @@ static int __init tsi108_eth_of_init(void)
int ret;
for (np = NULL, i = 0;
- (np = of_find_compatible_node(np, "network", "tsi-ethernet")) != NULL;
+ (np = of_find_compatible_node(np, "network", "tsi108-ethernet")) != NULL;
i++) {
struct resource r[2];
- struct device_node *phy;
+ struct device_node *phy, *mdio;
hw_info tsi_eth_data;
- const unsigned int *id;
const unsigned int *phy_id;
const void *mac_addr;
const phandle *ph;
@@ -111,6 +110,13 @@ static int __init tsi108_eth_of_init(void)
if (mac_addr)
memcpy(tsi_eth_data.mac_addr, mac_addr, 6);
+ ph = of_get_property(np, "mdio-handle", NULL);
+ mdio = of_find_node_by_phandle(*ph);
+ ret = of_address_to_resource(mdio, 0, &res);
+ of_node_put(mdio);
+ if (ret)
+ goto unreg;
+
ph = of_get_property(np, "phy-handle", NULL);
phy = of_find_node_by_phandle(*ph);
@@ -119,20 +125,25 @@ static int __init tsi108_eth_of_init(void)
goto unreg;
}
- id = of_get_property(phy, "reg", NULL);
- phy_id = of_get_property(phy, "phy-id", NULL);
- ret = of_address_to_resource(phy, 0, &res);
- if (ret) {
- of_node_put(phy);
- goto unreg;
- }
+ phy_id = of_get_property(phy, "reg", NULL);
+
tsi_eth_data.regs = r[0].start;
tsi_eth_data.phyregs = res.start;
tsi_eth_data.phy = *phy_id;
tsi_eth_data.irq_num = irq_of_parse_and_map(np, 0);
- if (of_device_is_compatible(phy, "bcm54xx"))
+
+ /* Some boards with the TSI108 bridge (e.g. Holly)
+ * have a miswiring of the ethernet PHYs which
+ * requires a workaround. The special
+ * "txc-rxc-delay-disable" property enables this
+ * workaround. FIXME: Need to port the tsi108_eth
+ * driver itself to phylib and use a non-misleading
+ * name for the workaround flag - it's not actually to
+ * do with the model of PHY in use */
+ if (of_get_property(phy, "txc-rxc-delay-disable", NULL))
tsi_eth_data.phy_type = TSI108_PHY_BCM54XX;
of_node_put(phy);
+
ret =
platform_device_add_data(tsi_eth_dev, &tsi_eth_data,
sizeof(hw_info));
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index 2153163fa593..90db8a720fed 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -64,9 +64,10 @@ tsi108_direct_write_config(struct pci_bus *bus, unsigned int devfunc,
int offset, int len, u32 val)
{
volatile unsigned char *cfg_addr;
+ struct pci_controller *hose = bus->sysdata;
if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfunc))
+ if (ppc_md.pci_exclude_device(hose, bus->number, devfunc))
return PCIBIOS_DEVICE_NOT_FOUND;
cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
@@ -149,10 +150,11 @@ tsi108_direct_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
int len, u32 * val)
{
volatile unsigned char *cfg_addr;
+ struct pci_controller *hose = bus->sysdata;
u32 temp;
if (ppc_md.pci_exclude_device)
- if (ppc_md.pci_exclude_device(bus->number, devfn))
+ if (ppc_md.pci_exclude_device(hose, bus->number, devfn))
return PCIBIOS_DEVICE_NOT_FOUND;
cfg_addr = (unsigned char *)(tsi_mk_config_addr(bus->number,
@@ -219,14 +221,12 @@ int __init tsi108_setup_pci(struct device_node *dev, u32 cfg_phys, int primary)
" bus 0\n", dev->full_name);
}
- hose = pcibios_alloc_controller();
+ hose = pcibios_alloc_controller(dev);
if (!hose) {
printk("PCI Host bridge init failed\n");
return -ENOMEM;
}
- hose->arch_data = dev;
- hose->set_cfg_type = 1;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
diff --git a/arch/powerpc/xmon/nonstdio.c b/arch/powerpc/xmon/nonstdio.c
index 78765833f4c0..bfac84fbe780 100644
--- a/arch/powerpc/xmon/nonstdio.c
+++ b/arch/powerpc/xmon/nonstdio.c
@@ -132,3 +132,8 @@ void xmon_printf(const char *format, ...)
va_end(args);
xmon_write(xmon_outbuf, n);
}
+
+void xmon_puts(const char *str)
+{
+ xmon_write(str, strlen(str));
+}
diff --git a/arch/powerpc/xmon/nonstdio.h b/arch/powerpc/xmon/nonstdio.h
index 47cebbd2b1b1..23dd95f4599c 100644
--- a/arch/powerpc/xmon/nonstdio.h
+++ b/arch/powerpc/xmon/nonstdio.h
@@ -5,10 +5,11 @@
extern int xmon_putchar(int c);
extern int xmon_getchar(void);
+extern void xmon_puts(const char *);
extern char *xmon_gets(char *, int);
extern void xmon_printf(const char *, ...);
extern void xmon_map_scc(void);
extern int xmon_expect(const char *str, unsigned long timeout);
-extern int xmon_write(void *ptr, int nb);
+extern int xmon_write(const void *ptr, int nb);
extern int xmon_readchar(void);
extern int xmon_read_poll(void);
diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c
index 712552c4f242..8864de2af382 100644
--- a/arch/powerpc/xmon/start.c
+++ b/arch/powerpc/xmon/start.c
@@ -14,7 +14,7 @@ void xmon_map_scc(void)
{
}
-int xmon_write(void *ptr, int nb)
+int xmon_write(const void *ptr, int nb)
{
return udbg_write(ptr, nb);
}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 28fdf4f50c27..121b04d165d1 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -833,7 +833,7 @@ cmds(struct pt_regs *excp)
mdelay(2000);
return cmd;
case '?':
- printf(help_string);
+ xmon_puts(help_string);
break;
case 'b':
bpt_cmds();
@@ -2634,7 +2634,7 @@ static int __init setup_xmon_sysrq(void)
__initcall(setup_xmon_sysrq);
#endif /* CONFIG_MAGIC_SYSRQ */
-int __initdata xmon_early, xmon_off;
+static int __initdata xmon_early, xmon_off;
static int __init early_parse_xmon(char *p)
{
diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
index 4c0a7d732f69..615b6583d9b0 100644
--- a/arch/ppc/8260_io/enet.c
+++ b/arch/ppc/8260_io/enet.c
@@ -477,9 +477,9 @@ for (;;) {
}
else {
skb_put(skb,pkt_len-4); /* Make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *)__va(bdp->cbd_bufaddr),
- pkt_len-4, 0);
+ pkt_len-4);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
}
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index cab395da25da..6f3ed6a72e0b 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -734,9 +734,9 @@ for (;;) {
}
else {
skb_put(skb,pkt_len); /* Make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *)__va(bdp->cbd_bufaddr),
- pkt_len, 0);
+ pkt_len);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
}
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index e58288e14369..703d47eee436 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -506,9 +506,9 @@ for (;;) {
}
else {
skb_put(skb,pkt_len-4); /* Make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
cep->rx_vaddr[bdp - cep->rx_bd_base],
- pkt_len-4, 0);
+ pkt_len-4);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
}
diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c
index d38335d2d710..0288279be9aa 100644
--- a/arch/ppc/8xx_io/fec.c
+++ b/arch/ppc/8xx_io/fec.c
@@ -725,7 +725,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
fep->stats.rx_dropped++;
} else {
skb_put(skb,pkt_len-4); /* Make room */
- eth_copy_and_sum(skb, data, pkt_len-4, 0);
+ skb_copy_to_linear_data(skb, data, pkt_len-4);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
}
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index ccce2a4a1522..6bdeeb70b157 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -1237,8 +1237,10 @@ config PCI
infrastructure code to support PCI bus devices.
config PCI_DOMAINS
- bool
- default PCI
+ def_bool PCI
+
+config PCI_SYSCALL
+ def_bool PCI
config MPC83xx_PCI2
bool "Support for 2nd PCI host controller"
diff --git a/arch/ppc/configs/ev64260_defconfig b/arch/ppc/configs/ev64260_defconfig
index 84cc142a67bb..587e9a3b9491 100644
--- a/arch/ppc/configs/ev64260_defconfig
+++ b/arch/ppc/configs/ev64260_defconfig
@@ -531,7 +531,6 @@ CONFIG_I2C_CHARDEV=m
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PIIX4 is not set
diff --git a/arch/ppc/configs/mpc8540_ads_defconfig b/arch/ppc/configs/mpc8540_ads_defconfig
index c5c86025e261..bf676ebd99ab 100644
--- a/arch/ppc/configs/mpc8540_ads_defconfig
+++ b/arch/ppc/configs/mpc8540_ads_defconfig
@@ -452,7 +452,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/mpc8548_cds_defconfig b/arch/ppc/configs/mpc8548_cds_defconfig
index abe034f24b83..f36fc5db540b 100644
--- a/arch/ppc/configs/mpc8548_cds_defconfig
+++ b/arch/ppc/configs/mpc8548_cds_defconfig
@@ -413,7 +413,6 @@ CONFIG_I2C_CHARDEV=y
#
# I2C Hardware Bus support
#
-# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PCA_ISA is not set
diff --git a/arch/ppc/configs/mpc8555_cds_defconfig b/arch/ppc/configs/mpc8555_cds_defconfig
index 15abebf46b96..4f1e320acfbe 100644
--- a/arch/ppc/configs/mpc8555_cds_defconfig
+++ b/arch/ppc/configs/mpc8555_cds_defconfig
@@ -518,7 +518,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/mpc8560_ads_defconfig b/arch/ppc/configs/mpc8560_ads_defconfig
index f834fb541ad5..f12d48fcbba7 100644
--- a/arch/ppc/configs/mpc8560_ads_defconfig
+++ b/arch/ppc/configs/mpc8560_ads_defconfig
@@ -489,7 +489,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/radstone_ppc7d_defconfig b/arch/ppc/configs/radstone_ppc7d_defconfig
index ca4d1fd0ca05..9f64532f2a81 100644
--- a/arch/ppc/configs/radstone_ppc7d_defconfig
+++ b/arch/ppc/configs/radstone_ppc7d_defconfig
@@ -710,7 +710,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_MPC is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
diff --git a/arch/ppc/configs/stx_gp3_defconfig b/arch/ppc/configs/stx_gp3_defconfig
index 3fedc43e44ad..70d6f842aa9b 100644
--- a/arch/ppc/configs/stx_gp3_defconfig
+++ b/arch/ppc/configs/stx_gp3_defconfig
@@ -661,7 +661,6 @@ CONFIG_I2C_ALGOBIT=m
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_MPC is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT is not set
diff --git a/arch/ppc/configs/sycamore_defconfig b/arch/ppc/configs/sycamore_defconfig
index 758114cfea5c..6996cca18f3e 100644
--- a/arch/ppc/configs/sycamore_defconfig
+++ b/arch/ppc/configs/sycamore_defconfig
@@ -461,7 +461,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
# CONFIG_I2C_IBM_IIC is not set
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_PIIX4 is not set
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index d319f9ba2379..0da55368655c 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -328,7 +328,7 @@ BEGIN_FTR_SECTION
mtspr SPRN_L1CSR0,r3
isync
blr
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
mfspr r3,SPRN_L1CSR1
ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
mtspr SPRN_L1CSR1,r3
@@ -355,7 +355,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
_GLOBAL(__flush_icache_range)
BEGIN_FTR_SECTION
blr /* for 601, do nothing */
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
li r5,L1_CACHE_BYTES-1
andc r3,r3,r5
subf r4,r3,r4
@@ -472,7 +472,7 @@ _GLOBAL(flush_dcache_all)
_GLOBAL(__flush_dcache_icache)
BEGIN_FTR_SECTION
blr /* for 601, do nothing */
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
rlwinm r3,r3,0,0,19 /* Get page base address */
li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */
mtctr r4
@@ -500,7 +500,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
_GLOBAL(__flush_dcache_icache_phys)
BEGIN_FTR_SECTION
blr /* for 601, do nothing */
-END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
+END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
mfmsr r10
rlwinm r0,r10,0,28,26 /* clear DR */
mtmsr r0
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 5e723c4c2571..c2ec13bea006 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -633,12 +633,6 @@ void pcibios_make_OF_bus_map(void)
{
}
-/* Add sysfs properties */
-void pcibios_add_platform_entries(struct pci_dev *pdev)
-{
-}
-
-
static int __init
pcibios_init(void)
{
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index a4165209ac7c..63f0a987139b 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -64,7 +64,6 @@ extern unsigned long mm_ptov (unsigned long paddr);
EXPORT_SYMBOL(clear_pages);
EXPORT_SYMBOL(clear_user_page);
-EXPORT_SYMBOL(do_signal);
EXPORT_SYMBOL(transfer_to_handler);
EXPORT_SYMBOL(do_IRQ);
EXPORT_SYMBOL(machine_check_exception);
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index c79704f5409c..967c1ef59a6b 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -526,7 +526,7 @@ void __init setup_arch(char **cmdline_p)
* Systems with OF can look in the properties on the cpu node(s)
* for a possibly more accurate value.
*/
- if (cpu_has_feature(CPU_FTR_SPLIT_ID_CACHE)) {
+ if (! cpu_has_feature(CPU_FTR_UNIFIED_ID_CACHE)) {
dcache_bsize = cur_cpu_spec->dcache_bsize;
icache_bsize = cur_cpu_spec->icache_bsize;
ucache_bsize = 0;
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index aea100be52c8..3f3b292eb773 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -92,6 +92,7 @@ int die(const char * str, struct pt_regs * fp, long err)
if (nl)
printk("\n");
show_regs(fp);
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
/* do_exit() should take care of panic'ing from an interrupt
* context so we don't handle it here
@@ -619,7 +620,7 @@ void program_check_exception(struct pt_regs *regs)
return;
if (!(regs->msr & MSR_PR) && /* not user-mode */
- report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
+ report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
regs->nip += 4;
return;
}
diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S
index 19db8746ff14..c0aac3ff9e91 100644
--- a/arch/ppc/kernel/vmlinux.lds.S
+++ b/arch/ppc/kernel/vmlinux.lds.S
@@ -130,10 +130,7 @@ SECTIONS
__ftr_fixup : { *(__ftr_fixup) }
__stop___ftr_fixup = .;
- . = ALIGN(4096);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(4096)
#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(4096);
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 465f451f3bc3..b98244e277fb 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -96,6 +96,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
struct mm_struct *mm = current->mm;
siginfo_t info;
int code = SEGV_MAPERR;
+ int fault;
#if defined(CONFIG_4xx) || defined (CONFIG_BOOKE)
int is_write = error_code & ESR_DST;
#else
@@ -249,20 +250,18 @@ good_area:
* the fault.
*/
survive:
- switch (handle_mm_fault(mm, vma, address, is_write)) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ fault = handle_mm_fault(mm, vma, address, is_write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
/*
diff --git a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c
index fa29740a28f5..4ff260bc9dd1 100644
--- a/arch/ppc/mm/tlb.c
+++ b/arch/ppc/mm/tlb.c
@@ -27,6 +27,7 @@
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/highmem.h>
+#include <linux/pagemap.h>
#include <asm/tlbflush.h>
#include <asm/tlb.h>
diff --git a/arch/ppc/platforms/4xx/bamboo.c b/arch/ppc/platforms/4xx/bamboo.c
index 349660b84a02..017623c9bc4b 100644
--- a/arch/ppc/platforms/4xx/bamboo.c
+++ b/arch/ppc/platforms/4xx/bamboo.c
@@ -29,6 +29,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/ethtool.h>
#include <asm/system.h>
diff --git a/arch/ppc/platforms/4xx/bubinga.c b/arch/ppc/platforms/4xx/bubinga.c
index 1a7f075b754f..cd696be55aca 100644
--- a/arch/ppc/platforms/4xx/bubinga.c
+++ b/arch/ppc/platforms/4xx/bubinga.c
@@ -21,6 +21,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/system.h>
#include <asm/pci-bridge.h>
diff --git a/arch/ppc/platforms/4xx/cpci405.c b/arch/ppc/platforms/4xx/cpci405.c
index 8474b05b795a..2e7e25dd84cb 100644
--- a/arch/ppc/platforms/4xx/cpci405.c
+++ b/arch/ppc/platforms/4xx/cpci405.c
@@ -23,6 +23,7 @@
#include <asm/todc.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/ocp.h>
#include <asm/ibm_ocp_pci.h>
#include <platforms/4xx/ibm405gp.h>
diff --git a/arch/ppc/platforms/4xx/ebony.c b/arch/ppc/platforms/4xx/ebony.c
index f0f9cc8480ca..05d7184d7e14 100644
--- a/arch/ppc/platforms/4xx/ebony.c
+++ b/arch/ppc/platforms/4xx/ebony.c
@@ -32,6 +32,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/system.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/platforms/4xx/luan.c b/arch/ppc/platforms/4xx/luan.c
index 61706ef37112..4b169610f154 100644
--- a/arch/ppc/platforms/4xx/luan.c
+++ b/arch/ppc/platforms/4xx/luan.c
@@ -30,6 +30,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/system.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/platforms/4xx/ocotea.c b/arch/ppc/platforms/4xx/ocotea.c
index 5e994e146ba8..fd0f971881d6 100644
--- a/arch/ppc/platforms/4xx/ocotea.c
+++ b/arch/ppc/platforms/4xx/ocotea.c
@@ -30,6 +30,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/system.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/platforms/4xx/taishan.c b/arch/ppc/platforms/4xx/taishan.c
index 5d9af8ddb155..888c492b4a45 100644
--- a/arch/ppc/platforms/4xx/taishan.c
+++ b/arch/ppc/platforms/4xx/taishan.c
@@ -30,6 +30,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/platform_device.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
diff --git a/arch/ppc/platforms/4xx/yucca.c b/arch/ppc/platforms/4xx/yucca.c
index 346787df0ddb..a83b0baea011 100644
--- a/arch/ppc/platforms/4xx/yucca.c
+++ b/arch/ppc/platforms/4xx/yucca.c
@@ -31,6 +31,7 @@
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/system.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
index 1d10ab98f66d..3d7addbdecfd 100644
--- a/arch/ppc/platforms/85xx/sbc8560.c
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -26,6 +26,7 @@
#include <linux/serial.h>
#include <linux/tty.h> /* for linux/serial_core.h */
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/initrd.h>
#include <linux/module.h>
#include <linux/fsl_devices.h>
diff --git a/arch/ppc/platforms/chestnut.c b/arch/ppc/platforms/chestnut.c
index a764ae71cbcb..248684f50dd9 100644
--- a/arch/ppc/platforms/chestnut.c
+++ b/arch/ppc/platforms/chestnut.c
@@ -25,6 +25,7 @@
#include <linux/ide.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/mtd/physmap.h>
#include <asm/system.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/platforms/ev64260.c b/arch/ppc/platforms/ev64260.c
index 4957a7bcde22..976270d537c1 100644
--- a/arch/ppc/platforms/ev64260.c
+++ b/arch/ppc/platforms/ev64260.c
@@ -35,6 +35,7 @@
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#else
#include <linux/mv643xx.h>
#endif
diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
index 6f21110a9747..3c56654bfc6f 100644
--- a/arch/ppc/platforms/prep_setup.c
+++ b/arch/ppc/platforms/prep_setup.c
@@ -69,9 +69,6 @@
TODC_ALLOC();
-unsigned char ucBoardRev;
-unsigned char ucBoardRevMaj, ucBoardRevMin;
-
extern unsigned char prep_nvram_read_val(int addr);
extern void prep_nvram_write_val(int addr,
unsigned char val);
diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c
index b55860734a72..44d4398a36ff 100644
--- a/arch/ppc/platforms/radstone_ppc7d.c
+++ b/arch/ppc/platforms/radstone_ppc7d.c
@@ -35,6 +35,7 @@
#include <linux/serial.h>
#include <linux/tty.h> /* for linux/serial_core.h */
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/mv643xx.h>
#include <linux/netdevice.h>
#include <linux/platform_device.h>
diff --git a/arch/ppc/platforms/spruce.c b/arch/ppc/platforms/spruce.c
index 3c7842784876..f4de50ba292e 100644
--- a/arch/ppc/platforms/spruce.c
+++ b/arch/ppc/platforms/spruce.c
@@ -27,6 +27,7 @@
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <asm/system.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
index 95694159b226..543795be58c8 100644
--- a/arch/ppc/syslib/Makefile
+++ b/arch/ppc/syslib/Makefile
@@ -7,6 +7,7 @@ CFLAGS_btext.o += -fPIC
wdt-mpc8xx-$(CONFIG_8xx_WDT) += m8xx_wdt.o
+obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o
obj-$(CONFIG_PPC_OCP) += ocp.o
obj-$(CONFIG_IBM_OCP) += ibm_ocp.o
diff --git a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c
new file mode 100644
index 000000000000..83b323a7d029
--- /dev/null
+++ b/arch/ppc/syslib/indirect_pci.c
@@ -0,0 +1,134 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * 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/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+#ifdef CONFIG_PPC_INDIRECT_PCI_BE
+#define PCI_CFG_OUT out_be32
+#else
+#define PCI_CFG_OUT out_le32
+#endif
+
+static int
+indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 *val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ volatile void __iomem *cfg_data;
+ u8 cfg_type = 0;
+
+ if (ppc_md.pci_exclude_device)
+ if (ppc_md.pci_exclude_device(bus->number, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (hose->set_cfg_type)
+ if (bus->number != hose->first_busno)
+ cfg_type = 1;
+
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+ | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ cfg_data = hose->cfg_data + (offset & 3);
+ switch (len) {
+ case 1:
+ *val = in_8(cfg_data);
+ break;
+ case 2:
+ *val = in_le16(cfg_data);
+ break;
+ default:
+ *val = in_le32(cfg_data);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+ int len, u32 val)
+{
+ struct pci_controller *hose = bus->sysdata;
+ volatile void __iomem *cfg_data;
+ u8 cfg_type = 0;
+
+ if (ppc_md.pci_exclude_device)
+ if (ppc_md.pci_exclude_device(bus->number, devfn))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (hose->set_cfg_type)
+ if (bus->number != hose->first_busno)
+ cfg_type = 1;
+
+ PCI_CFG_OUT(hose->cfg_addr,
+ (0x80000000 | ((bus->number - hose->bus_offset) << 16)
+ | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
+
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ cfg_data = hose->cfg_data + (offset & 3);
+ switch (len) {
+ case 1:
+ out_8(cfg_data, val);
+ break;
+ case 2:
+ out_le16(cfg_data, val);
+ break;
+ default:
+ out_le32(cfg_data, val);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pci_ops =
+{
+ indirect_read_config,
+ indirect_write_config
+};
+
+void __init
+setup_indirect_pci_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
+ void __iomem * cfg_data)
+{
+ hose->cfg_addr = cfg_addr;
+ hose->cfg_data = cfg_data;
+ hose->ops = &indirect_pci_ops;
+}
+
+void __init
+setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+ unsigned long base = cfg_addr & PAGE_MASK;
+ void __iomem *mbase, *addr, *data;
+
+ mbase = ioremap(base, PAGE_SIZE);
+ addr = mbase + (cfg_addr & ~PAGE_MASK);
+ if ((cfg_data & PAGE_MASK) != base)
+ mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
+ data = mbase + (cfg_data & ~PAGE_MASK);
+ setup_indirect_pci_nomap(hose, addr, data);
+}
diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
index 8485a68cd475..d212b1c418a9 100644
--- a/arch/ppc/syslib/mv64x60.c
+++ b/arch/ppc/syslib/mv64x60.c
@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/mv643xx.h>
@@ -2359,7 +2360,7 @@ mv64460_chip_specific_init(struct mv64x60_handle *bh,
/* Export the hotswap register via sysfs for enum event monitoring */
#define VAL_LEN_MAX 11 /* 32-bit hex or dec stringified number + '\n' */
-DECLARE_MUTEX(mv64xxx_hs_lock);
+static DEFINE_MUTEX(mv64xxx_hs_lock);
static ssize_t
mv64xxx_hs_reg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
@@ -2372,14 +2373,14 @@ mv64xxx_hs_reg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
if (count < VAL_LEN_MAX)
return -EINVAL;
- if (down_interruptible(&mv64xxx_hs_lock))
+ if (mutex_lock_interruptible(&mv64xxx_hs_lock))
return -ERESTARTSYS;
save_exclude = mv64x60_pci_exclude_bridge;
mv64x60_pci_exclude_bridge = 0;
early_read_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
MV64360_PCICFG_CPCI_HOTSWAP, &v);
mv64x60_pci_exclude_bridge = save_exclude;
- up(&mv64xxx_hs_lock);
+ mutex_unlock(&mv64xxx_hs_lock);
return sprintf(buf, "0x%08x\n", v);
}
@@ -2396,14 +2397,14 @@ mv64xxx_hs_reg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
return -EINVAL;
if (sscanf(buf, "%i", &v) == 1) {
- if (down_interruptible(&mv64xxx_hs_lock))
+ if (mutex_lock_interruptible(&mv64xxx_hs_lock))
return -ERESTARTSYS;
save_exclude = mv64x60_pci_exclude_bridge;
mv64x60_pci_exclude_bridge = 0;
early_write_config_dword(&sysfs_hose_a, 0, PCI_DEVFN(0, 0),
MV64360_PCICFG_CPCI_HOTSWAP, v);
mv64x60_pci_exclude_bridge = save_exclude;
- up(&mv64xxx_hs_lock);
+ mutex_unlock(&mv64xxx_hs_lock);
}
else
count = -EINVAL;
@@ -2415,7 +2416,6 @@ static struct bin_attribute mv64xxx_hs_reg_attr = { /* Hotswap register */
.attr = {
.name = "hs_reg",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = VAL_LEN_MAX,
.read = mv64xxx_hs_reg_read,
@@ -2434,10 +2434,10 @@ mv64xxx_hs_reg_valid_show(struct device *dev, struct device_attribute *attr,
pdev = container_of(dev, struct platform_device, dev);
pdp = (struct mv64xxx_pdata *)pdev->dev.platform_data;
- if (down_interruptible(&mv64xxx_hs_lock))
+ if (mutex_lock_interruptible(&mv64xxx_hs_lock))
return -ERESTARTSYS;
v = pdp->hs_reg_valid;
- up(&mv64xxx_hs_lock);
+ mutex_unlock(&mv64xxx_hs_lock);
return sprintf(buf, "%i\n", v);
}
diff --git a/arch/ppc/syslib/virtex_devices.c b/arch/ppc/syslib/virtex_devices.c
index 16546788e23b..ace4ec08de51 100644
--- a/arch/ppc/syslib/virtex_devices.c
+++ b/arch/ppc/syslib/virtex_devices.c
@@ -71,6 +71,21 @@
}, \
}
+/*
+ * ML300/ML403 Video Device: shortcut macro for single instance
+ */
+#define XPAR_TFT(num) { \
+ .name = "xilinxfb", \
+ .id = num, \
+ .num_resources = 1, \
+ .resource = (struct resource[]) { \
+ { \
+ .start = XPAR_TFT_##num##_BASEADDR, \
+ .end = XPAR_TFT_##num##_BASEADDR+7, \
+ .flags = IORESOURCE_IO, \
+ }, \
+ }, \
+}
/* UART 8250 driver platform data table */
struct plat_serial8250_port virtex_serial_platform_data[] = {
@@ -146,20 +161,17 @@ struct platform_device virtex_platform_devices[] = {
XPAR_SYSACE(1),
#endif
- /* ML300/403 reference design framebuffer */
#if defined(XPAR_TFT_0_BASEADDR)
- {
- .name = "xilinxfb",
- .id = 0,
- .num_resources = 1,
- .resource = (struct resource[]) {
- {
- .start = XPAR_TFT_0_BASEADDR,
- .end = XPAR_TFT_0_BASEADDR+7,
- .flags = IORESOURCE_IO,
- },
- },
- },
+ XPAR_TFT(0),
+#endif
+#if defined(XPAR_TFT_1_BASEADDR)
+ XPAR_TFT(1),
+#endif
+#if defined(XPAR_TFT_2_BASEADDR)
+ XPAR_TFT(2),
+#endif
+#if defined(XPAR_TFT_3_BASEADDR)
+ XPAR_TFT(3),
#endif
};
diff --git a/arch/ppc/syslib/virtex_devices.h b/arch/ppc/syslib/virtex_devices.h
index 3d4be1412f60..9f38d92ae536 100644
--- a/arch/ppc/syslib/virtex_devices.h
+++ b/arch/ppc/syslib/virtex_devices.h
@@ -31,4 +31,11 @@ void __init virtex_early_serial_map(void);
*/
int virtex_device_fixup(struct platform_device *dev);
+/* SPI Controller IP */
+struct xspi_platform_data {
+ s16 bus_num;
+ u16 num_chipselect;
+ u32 speed_hz;
+};
+
#endif /* __ASM_VIRTEX_DEVICES_H__ */
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 68441e0e74b6..143ed8e154af 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -19,7 +19,7 @@ CFLAGS += -m31
AFLAGS += -m31
UTS_MACHINE := s390
STACK_SIZE := 8192
-CHECKFLAGS += -D__s390__
+CHECKFLAGS += -D__s390__ -msize-long
else
LDFLAGS := -m elf64_s390
MODFLAGS += -fpic -D__PIC__
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 485b60c1983c..2aae23dba4bb 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21
-# Thu May 10 15:18:19 2007
+# Linux kernel version: 2.6.22
+# Tue Jul 17 12:50:23 2007
#
CONFIG_MMU=y
CONFIG_ZONE_DMA=y
@@ -32,12 +32,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL is not set
CONFIG_IKCONFIG=y
@@ -61,20 +60,19 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
CONFIG_SLAB=y
# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
@@ -82,12 +80,9 @@ CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
+CONFIG_BLK_DEV_BSG=y
#
# IO Schedulers
@@ -151,6 +146,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
+CONFIG_VIRT_TO_BUS=y
CONFIG_HOLES_IN_ZONE=y
#
@@ -248,25 +244,13 @@ CONFIG_IPV6_SIT=y
# CONFIG_IPV6_MULTIPLE_TABLES 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=m
# CONFIG_SCTP_DBG_MSG is not set
# CONFIG_SCTP_DBG_OBJCNT is not set
# CONFIG_SCTP_HMAC_NONE is not set
# CONFIG_SCTP_HMAC_SHA1 is not set
CONFIG_SCTP_HMAC_MD5=y
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -293,6 +277,7 @@ CONFIG_NET_SCH_CBQ=m
# CONFIG_NET_SCH_HTB is not set
# CONFIG_NET_SCH_HFSC is not set
CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RR=m
CONFIG_NET_SCH_RED=m
CONFIG_NET_SCH_SFQ=m
CONFIG_NET_SCH_TEQL=m
@@ -317,10 +302,14 @@ CONFIG_CLS_U32_MARK=y
CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
# CONFIG_NET_EMATCH is not set
-# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=y
+# CONFIG_NET_ACT_GACT is not set
+# CONFIG_NET_ACT_MIRRED is not set
+# CONFIG_NET_ACT_PEDIT is not set
+# CONFIG_NET_ACT_SIMP is not set
CONFIG_NET_CLS_POLICE=y
# CONFIG_NET_CLS_IND is not set
-CONFIG_NET_ESTIMATOR=y
#
# Network testing
@@ -329,6 +318,7 @@ CONFIG_NET_ESTIMATOR=y
# CONFIG_NET_TCPPROBE is not set
# CONFIG_AF_RXRPC is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
# CONFIG_PCMCIA is not set
CONFIG_CCW=y
@@ -345,15 +335,8 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
CONFIG_SYS_HYPERVISOR=y
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=m
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -376,17 +359,15 @@ CONFIG_DASD_ECKD=y
CONFIG_DASD_FBA=y
CONFIG_DASD_DIAG=y
CONFIG_DASD_EER=y
-
-#
-# Misc devices
-#
-# CONFIG_BLINK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_DMA is not set
# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -447,40 +428,21 @@ CONFIG_DM_MIRROR=y
CONFIG_DM_ZERO=y
CONFIG_DM_MULTIPATH=y
# CONFIG_DM_MULTIPATH_EMC is not set
+# CONFIG_DM_MULTIPATH_RDAC is not set
# CONFIG_DM_DELAY is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_IFB is not set
CONFIG_DUMMY=m
CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
CONFIG_EQUALIZER=m
CONFIG_TUN=m
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
# CONFIG_TR is not set
-
-#
-# Wan interfaces
-#
# CONFIG_WAN is not set
#
@@ -511,10 +473,6 @@ CONFIG_CCWGROUP=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=m
# CONFIG_R3964 is not set
@@ -554,6 +512,8 @@ CONFIG_S390_TAPE_34XX=m
# CONFIG_VMCP is not set
# CONFIG_MONREADER is not set
CONFIG_MONWRITER=m
+CONFIG_S390_VMUR=m
+# CONFIG_POWER_SUPPLY is not set
#
# File systems
@@ -655,7 +615,6 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -712,6 +671,7 @@ CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_HEADERS_CHECK=y
CONFIG_DEBUG_KERNEL=y
+# CONFIG_SCHED_DEBUG is not set
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_SLAB is not set
@@ -740,10 +700,6 @@ CONFIG_FORCED_INLINING=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
@@ -782,10 +738,7 @@ CONFIG_CRYPTO_FCRYPT=m
# CONFIG_CRYPTO_CRC32C is not set
CONFIG_CRYPTO_CAMELLIA=m
# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
# CONFIG_CRYPTO_SHA1_S390 is not set
# CONFIG_CRYPTO_SHA256_S390 is not set
# CONFIG_CRYPTO_DES_S390 is not set
@@ -800,6 +753,7 @@ CONFIG_ZCRYPT=m
CONFIG_BITREVERSE=m
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=m
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index a057ebf108a7..d3057318f2bf 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -240,8 +240,8 @@ static const unsigned char formats[][7] = {
[INSTR_RXY_FRRD] = { 0xff, F_8,D20_20,X_12,B_16,0,0 },/* e.g. ley */
[INSTR_RX_FRRD] = { 0xff, F_8,D_20,X_12,B_16,0,0 }, /* e.g. ae */
[INSTR_RX_RRRD] = { 0xff, R_8,D_20,X_12,B_16,0,0 }, /* e.g. l */
- [INSTR_RX_URRD] = { 0x00, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc */
- [INSTR_SI_URD] = { 0x00, D_20,B_16,U8_8,0,0,0 }, /* e.g. cli */
+ [INSTR_RX_URRD] = { 0xff, U4_8,D_20,X_12,B_16,0,0 }, /* e.g. bc */
+ [INSTR_SI_URD] = { 0xff, D_20,B_16,U8_8,0,0,0 }, /* e.g. cli */
[INSTR_SIY_URD] = { 0xff, D20_20,B_16,U8_8,0,0,0 }, /* e.g. tmy */
[INSTR_SSE_RDRD] = { 0xff, D_20,B_16,D_36,B_32,0,0 }, /* e.g. mvsdk */
[INSTR_SS_L0RDRD] = { 0xff, D_20,L8_8,B_16,D_36,B_32,0 },
@@ -1190,7 +1190,8 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
else if (operand->flags & OPERAND_CR)
ptr += sprintf(ptr, "%%c%i", value);
else if (operand->flags & OPERAND_PCREL)
- ptr += sprintf(ptr, "%lx", value + addr);
+ ptr += sprintf(ptr, "%lx", (signed int) value
+ + addr);
else if (operand->flags & OPERAND_SIGNED)
ptr += sprintf(ptr, "%i", value);
else
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 82b131ddd7ff..8b8f136d9cc7 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -295,8 +295,8 @@ static ssize_t sys_ipl_device_show(struct kset *kset, char *page)
static struct subsys_attribute sys_ipl_device_attr =
__ATTR(device, S_IRUGO, sys_ipl_device_show, NULL);
-static ssize_t ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
{
unsigned int size = IPL_PARMBLOCK_SIZE;
@@ -312,14 +312,13 @@ static struct bin_attribute ipl_parameter_attr = {
.attr = {
.name = "binary_parameter",
.mode = S_IRUGO,
- .owner = THIS_MODULE,
},
.size = PAGE_SIZE,
.read = &ipl_parameter_read,
};
-static ssize_t ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
{
unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len;
void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data;
@@ -336,10 +335,9 @@ static struct bin_attribute ipl_scp_data_attr = {
.attr = {
.name = "scp_data",
.mode = S_IRUGO,
- .owner = THIS_MODULE,
},
.size = PAGE_SIZE,
- .read = &ipl_scp_data_read,
+ .read = ipl_scp_data_read,
};
/* FCP ipl device attributes */
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 2a8f0872ea8b..f4503ca27630 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -294,7 +294,6 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
static int
do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
{
- unsigned long tmp;
ptrace_area parea;
int copied, ret;
@@ -304,10 +303,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
/* Remove high order bit from address (only for 31 bit). */
addr &= PSW_ADDR_INSN;
/* read word at location addr. */
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (copied != sizeof(tmp))
- return -EIO;
- return put_user(tmp, (unsigned long __force __user *) data);
+ return generic_ptrace_peekdata(child, addr, data);
case PTRACE_PEEKUSR:
/* read the word at location addr in the USER area. */
@@ -318,10 +314,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
/* Remove high order bit from address (only for 31 bit). */
addr &= PSW_ADDR_INSN;
/* write the word at location addr. */
- copied = access_process_vm(child, addr, &data, sizeof(data),1);
- if (copied != sizeof(data))
- return -EIO;
- return 0;
+ return generic_ptrace_pokedata(child, addr, data);
case PTRACE_POKEUSR:
/* write the word at location addr in the USER area */
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index 515ff9011dd7..da6924729964 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -12,7 +12,6 @@
#include <linux/kallsyms.h>
static unsigned long save_context_stack(struct stack_trace *trace,
- unsigned int *skip,
unsigned long sp,
unsigned long low,
unsigned long high)
@@ -28,10 +27,10 @@ static unsigned long save_context_stack(struct stack_trace *trace,
sf = (struct stack_frame *)sp;
while(1) {
addr = sf->gprs[8] & PSW_ADDR_INSN;
- if (!(*skip))
+ if (!trace->skip)
trace->entries[trace->nr_entries++] = addr;
else
- (*skip)--;
+ trace->skip--;
if (trace->nr_entries >= trace->max_entries)
return sp;
low = sp;
@@ -48,10 +47,10 @@ static unsigned long save_context_stack(struct stack_trace *trace,
return sp;
regs = (struct pt_regs *)sp;
addr = regs->psw.addr & PSW_ADDR_INSN;
- if (!(*skip))
+ if (!trace->skip)
trace->entries[trace->nr_entries++] = addr;
else
- (*skip)--;
+ trace->skip--;
if (trace->nr_entries >= trace->max_entries)
return sp;
low = sp;
@@ -65,20 +64,17 @@ void save_stack_trace(struct stack_trace *trace)
unsigned long orig_sp, new_sp;
orig_sp = sp & PSW_ADDR_INSN;
-
- new_sp = save_context_stack(trace, &trace->skip, orig_sp,
- S390_lowcore.panic_stack - PAGE_SIZE,
- S390_lowcore.panic_stack);
+ new_sp = save_context_stack(trace, orig_sp,
+ S390_lowcore.panic_stack - PAGE_SIZE,
+ S390_lowcore.panic_stack);
if (new_sp != orig_sp)
return;
- new_sp = save_context_stack(trace, &trace->skip, new_sp,
- S390_lowcore.async_stack - ASYNC_SIZE,
- S390_lowcore.async_stack);
+ new_sp = save_context_stack(trace, new_sp,
+ S390_lowcore.async_stack - ASYNC_SIZE,
+ S390_lowcore.async_stack);
if (new_sp != orig_sp)
return;
-
- save_context_stack(trace, &trace->skip, new_sp,
+ save_context_stack(trace, new_sp,
S390_lowcore.thread_info,
S390_lowcore.thread_info + THREAD_SIZE);
- return;
}
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index ee9186f8fb08..8ec9def83ccb 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -262,6 +262,7 @@ void die(const char * str, struct pt_regs * regs, long err)
print_modules();
show_regs(regs);
bust_spinlocks(0);
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
panic("Fatal exception in interrupt");
@@ -319,7 +320,7 @@ static void __kprobes inline do_trap(long interruption_code, int signr,
else {
enum bug_trap_type btt;
- btt = report_bug(regs->psw.addr & PSW_ADDR_INSN);
+ btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
if (btt == BUG_TRAP_TYPE_WARN)
return;
die(str, regs, interruption_code);
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 7158a804a5e4..6ab7d4ee13a4 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -45,6 +45,8 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
+ NOTES
+
BUG_TABLE
.data : { /* Data */
@@ -107,10 +109,7 @@ SECTIONS
. = ALIGN(2);
__initramfs_end = .;
#endif
- . = ALIGN(4096);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(4096)
. = ALIGN(4096);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 63181671e3e3..60604b2819b2 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -20,6 +20,7 @@ static int __handle_fault(struct mm_struct *mm, unsigned long address,
{
struct vm_area_struct *vma;
int ret = -EFAULT;
+ int fault;
if (in_atomic())
return ret;
@@ -44,20 +45,18 @@ static int __handle_fault(struct mm_struct *mm, unsigned long address,
}
survive:
- switch (handle_mm_fault(mm, vma, address, write_access)) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto out_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ fault = handle_mm_fault(mm, vma, address, write_access);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto out_sigbus;
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
ret = 0;
out:
up_read(&mm->mmap_sem);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index d855cdbf8fb8..54055194e9af 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -307,6 +307,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write)
unsigned long address;
int space;
int si_code;
+ int fault;
if (notify_page_fault(regs, error_code))
return;
@@ -377,23 +378,22 @@ survive:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- switch (handle_mm_fault(mm, vma, address, write)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- do_sigbus(regs, error_code, address);
- return;
- case VM_FAULT_OOM:
- if (do_out_of_memory(regs, error_code, address))
- goto survive;
- return;
- default:
+ fault = handle_mm_fault(mm, vma, address, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM) {
+ if (do_out_of_memory(regs, error_code, address))
+ goto survive;
+ return;
+ } else if (fault & VM_FAULT_SIGBUS) {
+ do_sigbus(regs, error_code, address);
+ return;
+ }
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
up_read(&mm->mmap_sem);
/*
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 038179ecf6a9..f87f429e0b24 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -55,8 +55,21 @@ config GENERIC_TIME
config GENERIC_CLOCKEVENTS
def_bool n
+config SYS_SUPPORTS_PM
+ bool
+
config SYS_SUPPORTS_APM_EMULATION
bool
+ select SYS_SUPPORTS_PM
+
+config SYS_SUPPORTS_SMP
+ bool
+
+config SYS_SUPPORTS_NUMA
+ bool
+
+config SYS_SUPPORTS_PCI
+ bool
config ARCH_MAY_HAVE_PC_FDC
bool
@@ -81,24 +94,150 @@ source "init/Kconfig"
menu "System type"
-config SOLUTION_ENGINE
- bool
+source "arch/sh/mm/Kconfig"
+
+menu "Processor features"
choice
- prompt "SuperH system type"
- default SH_UNKNOWN
+ prompt "Endianess selection"
+ default CPU_LITTLE_ENDIAN
+ help
+ Some SuperH machines can be configured for either little or big
+ endian byte order. These modes require different kernels.
+
+config CPU_LITTLE_ENDIAN
+ bool "Little Endian"
+
+config CPU_BIG_ENDIAN
+ bool "Big Endian"
+
+endchoice
+
+config SH_FPU
+ bool "FPU support"
+ depends on CPU_SH4
+ default y
+ help
+ Selecting this option will enable support for SH processors that
+ have FPU units (ie, SH77xx).
+
+ This option must be set in order to enable the FPU.
+
+config SH_FPU_EMU
+ bool "FPU emulation support"
+ depends on !SH_FPU && EXPERIMENTAL
+ default n
+ help
+ Selecting this option will enable support for software FPU emulation.
+ Most SH-3 users will want to say Y here, whereas most SH-4 users will
+ want to say N.
+
+config SH_DSP
+ bool "DSP support"
+ default y if SH4AL_DSP || !CPU_SH4
+ default n
+ help
+ Selecting this option will enable support for SH processors that
+ have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
+
+ This option must be set in order to enable the DSP.
+
+config SH_ADC
+ bool "ADC support"
+ depends on CPU_SH3
+ default y
+ help
+ Selecting this option will allow the Linux kernel to use SH3 on-chip
+ ADC module.
+
+ If unsure, say N.
+
+config SH_STORE_QUEUES
+ bool "Support for Store Queues"
+ depends on CPU_SH4
+ help
+ Selecting this option will enable an in-kernel API for manipulating
+ the store queues integrated in the SH-4 processors.
+
+config SPECULATIVE_EXECUTION
+ bool "Speculative subroutine return"
+ depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
+ help
+ This enables support for a speculative instruction fetch for
+ subroutine return. There are various pitfalls associated with
+ this, as outlined in the SH7780 hardware manual.
+
+ If unsure, say N.
+
+config CPU_HAS_INTEVT
+ bool
+
+config CPU_HAS_PINT_IRQ
+ bool
+
+config CPU_HAS_MASKREG_IRQ
+ bool
+
+config CPU_HAS_INTC_IRQ
+ bool
+
+config CPU_HAS_INTC2_IRQ
+ bool
+
+config CPU_HAS_IPR_IRQ
+ bool
+
+config CPU_HAS_SR_RB
+ bool "CPU has SR.RB"
+ depends on CPU_SH3 || CPU_SH4
+ default y
+ help
+ This will enable the use of SR.RB register bank usage. Processors
+ that are lacking this bit must have another method in place for
+ accomplishing what is taken care of by the banked registers.
+
+ See <file:Documentation/sh/register-banks.txt> for further
+ information on SR.RB and register banking in the kernel in general.
+
+config CPU_HAS_PTEA
+ bool
+
+endmenu
+
+menu "Board support"
+
+config SOLUTION_ENGINE
+ bool
config SH_SOLUTION_ENGINE
bool "SolutionEngine"
select SOLUTION_ENGINE
+ select CPU_HAS_IPR_IRQ
+ depends on CPU_SUBTYPE_SH7709 || CPU_SUBTYPE_SH7750
help
Select SolutionEngine if configuring for a Hitachi SH7709
or SH7750 evaluation board.
+config SH_7206_SOLUTION_ENGINE
+ bool "SolutionEngine7206"
+ select SOLUTION_ENGINE
+ depends on CPU_SUBTYPE_SH7206
+ help
+ Select 7206 SolutionEngine if configuring for a Hitachi SH7206
+ evaluation board.
+
+config SH_7619_SOLUTION_ENGINE
+ bool "SolutionEngine7619"
+ select SOLUTION_ENGINE
+ depends on CPU_SUBTYPE_SH7619
+ help
+ Select 7619 SolutionEngine if configuring for a Hitachi SH7619
+ evaluation board.
+
config SH_7722_SOLUTION_ENGINE
bool "SolutionEngine7722"
select SOLUTION_ENGINE
- select CPU_SUBTYPE_SH7722
+ depends on CPU_SUBTYPE_SH7722
help
Select 7722 SolutionEngine if configuring for a Hitachi SH772
evaluation board.
@@ -106,7 +245,8 @@ config SH_7722_SOLUTION_ENGINE
config SH_7751_SOLUTION_ENGINE
bool "SolutionEngine7751"
select SOLUTION_ENGINE
- select CPU_SUBTYPE_SH7751
+ select CPU_HAS_IPR_IRQ
+ depends on CPU_SUBTYPE_SH7751
help
Select 7751 SolutionEngine if configuring for a Hitachi SH7751
evaluation board.
@@ -114,7 +254,9 @@ config SH_7751_SOLUTION_ENGINE
config SH_7780_SOLUTION_ENGINE
bool "SolutionEngine7780"
select SOLUTION_ENGINE
- select CPU_SUBTYPE_SH7780
+ select SYS_SUPPORTS_PCI
+ select CPU_HAS_INTC2_IRQ
+ depends on CPU_SUBTYPE_SH7780
help
Select 7780 SolutionEngine if configuring for a Renesas SH7780
evaluation board.
@@ -122,7 +264,7 @@ config SH_7780_SOLUTION_ENGINE
config SH_7300_SOLUTION_ENGINE
bool "SolutionEngine7300"
select SOLUTION_ENGINE
- select CPU_SUBTYPE_SH7300
+ depends on CPU_SUBTYPE_SH7300
help
Select 7300 SolutionEngine if configuring for a Hitachi
SH7300(SH-Mobile V) evaluation board.
@@ -130,22 +272,22 @@ config SH_7300_SOLUTION_ENGINE
config SH_7343_SOLUTION_ENGINE
bool "SolutionEngine7343"
select SOLUTION_ENGINE
- select CPU_SUBTYPE_SH7343
+ depends on CPU_SUBTYPE_SH7343
help
Select 7343 SolutionEngine if configuring for a Hitachi
SH7343 (SH-Mobile 3AS) evaluation board.
config SH_73180_SOLUTION_ENGINE
- bool "SolutionEngine73180"
+ bool "SolutionEngine73180"
select SOLUTION_ENGINE
- select CPU_SUBTYPE_SH73180
+ depends on CPU_SUBTYPE_SH73180
help
Select 73180 SolutionEngine if configuring for a Hitachi
SH73180(SH-Mobile 3) evaluation board.
config SH_7751_SYSTEMH
bool "SystemH7751R"
- select CPU_SUBTYPE_SH7751R
+ depends on CPU_SUBTYPE_SH7751R
help
Select SystemH if you are configuring for a Renesas SystemH
7751R evaluation board.
@@ -153,20 +295,17 @@ config SH_7751_SYSTEMH
config SH_HP6XX
bool "HP6XX"
select SYS_SUPPORTS_APM_EMULATION
+ select HD6446X_SERIES
+ depends on CPU_SUBTYPE_SH7709
help
Select HP6XX if configuring for a HP jornada HP6xx.
More information (hardware only) at
<http://www.hp.com/jornada/>.
-config SH_SATURN
- bool "Saturn"
- select CPU_SUBTYPE_SH7604
- help
- Select Saturn if configuring for a SEGA Saturn.
-
config SH_DREAMCAST
bool "Dreamcast"
- select CPU_SUBTYPE_SH7091
+ select SYS_SUPPORTS_PCI
+ depends on CPU_SUBTYPE_SH7091
help
Select Dreamcast if configuring for a SEGA Dreamcast.
More information at
@@ -175,6 +314,7 @@ config SH_DREAMCAST
config SH_MPC1211
bool "Interface MPC1211"
+ depends on CPU_SUBTYPE_SH7751 && BROKEN
help
CTP/PCI-SH02 is a CPU module computer that is produced
by Interface Corporation.
@@ -182,6 +322,9 @@ config SH_MPC1211
config SH_SH03
bool "Interface CTP/PCI-SH03"
+ depends on CPU_SUBTYPE_SH7751 && BROKEN
+ select CPU_HAS_IPR_IRQ
+ select SYS_SUPPORTS_PCI
help
CTP/PCI-SH03 is a CPU module computer that is produced
by Interface Corporation.
@@ -189,7 +332,9 @@ config SH_SH03
config SH_SECUREEDGE5410
bool "SecureEdge5410"
- select CPU_SUBTYPE_SH7751R
+ depends on CPU_SUBTYPE_SH7751R
+ select CPU_HAS_IPR_IRQ
+ select SYS_SUPPORTS_PCI
help
Select SecureEdge5410 if configuring for a SnapGear SH board.
This includes both the OEM SecureEdge products as well as the
@@ -197,246 +342,78 @@ config SH_SECUREEDGE5410
config SH_HS7751RVOIP
bool "HS7751RVOIP"
- select CPU_SUBTYPE_SH7751R
+ depends on CPU_SUBTYPE_SH7751R
help
Select HS7751RVOIP if configuring for a Renesas Technology
Sales VoIP board.
config SH_7710VOIPGW
bool "SH7710-VOIP-GW"
- select CPU_SUBTYPE_SH7710
+ depends on CPU_SUBTYPE_SH7710
help
Select this option to build a kernel for the SH7710 based
VOIP GW.
config SH_RTS7751R2D
bool "RTS7751R2D"
- select CPU_SUBTYPE_SH7751R
+ depends on CPU_SUBTYPE_SH7751R
+ select SYS_SUPPORTS_PCI
help
Select RTS7751R2D if configuring for a Renesas Technology
Sales SH-Graphics board.
config SH_HIGHLANDER
bool "Highlander"
+ depends on CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785
+ select SYS_SUPPORTS_PCI
config SH_EDOSK7705
bool "EDOSK7705"
- select CPU_SUBTYPE_SH7705
+ depends on CPU_SUBTYPE_SH7705
config SH_SH4202_MICRODEV
bool "SH4-202 MicroDev"
- select CPU_SUBTYPE_SH4_202
+ depends on CPU_SUBTYPE_SH4_202
help
Select SH4-202 MicroDev if configuring for a SuperH MicroDev board
with an SH4-202 CPU.
config SH_LANDISK
bool "LANDISK"
- select CPU_SUBTYPE_SH7751R
+ depends on CPU_SUBTYPE_SH7751R
+ select SYS_SUPPORTS_PCI
help
I-O DATA DEVICE, INC. "LANDISK Series" support.
config SH_TITAN
bool "TITAN"
- select CPU_SUBTYPE_SH7751R
+ depends on CPU_SUBTYPE_SH7751R
+ select CPU_HAS_IPR_IRQ
+ select SYS_SUPPORTS_PCI
help
Select Titan if you are configuring for a Nimble Microsystems
NetEngine NP51R.
config SH_SHMIN
bool "SHMIN"
- select CPU_SUBTYPE_SH7706
+ depends on CPU_SUBTYPE_SH7706
+ select CPU_HAS_IPR_IRQ
help
Select SHMIN if configuring for the SHMIN board.
-config SH_7206_SOLUTION_ENGINE
- bool "SolutionEngine7206"
- select CPU_SUBTYPE_SH7206
- help
- Select 7206 SolutionEngine if configuring for a Hitachi SH7206
- evaluation board.
-
-config SH_7619_SOLUTION_ENGINE
- bool "SolutionEngine7619"
- select CPU_SUBTYPE_SH7619
- help
- Select 7619 SolutionEngine if configuring for a Hitachi SH7619
- evaluation board.
-
config SH_LBOX_RE2
bool "L-BOX RE2"
- select CPU_SUBTYPE_SH7751R
+ depends on CPU_SUBTYPE_SH7751R
+ select SYS_SUPPORTS_PCI
help
Select L-BOX RE2 if configuring for the NTT COMWARE L-BOX RE2.
-config SH_UNKNOWN
- bool "BareCPU"
- help
- "Bare CPU" aka "unknown" means an SH-based system which is not one
- of the specific ones mentioned above, which means you need to enter
- all sorts of stuff like CONFIG_MEMORY_START because the config
- system doesn't already know what it is. You get a machine vector
- without any platform-specific code in it, so things like the RTC may
- not work.
-
- This option is for the early stages of porting to a new machine.
-
-endchoice
+endmenu
source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
source "arch/sh/boards/renesas/r7780rp/Kconfig"
-source "arch/sh/mm/Kconfig"
-
-config CF_ENABLER
- bool "Compact Flash Enabler support"
- depends on SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_SH03
- ---help---
- Compact Flash is a small, removable mass storage device introduced
- in 1994 originally as a PCMCIA device. If you say `Y' here, you
- compile in support for Compact Flash devices directly connected to
- a SuperH processor. A Compact Flash FAQ is available at
- <http://www.compactflash.org/faqs/faq.htm>.
-
- If your board has "Directly Connected" CompactFlash at area 5 or 6,
- you may want to enable this option. Then, you can use CF as
- primary IDE drive (only tested for SanDisk).
-
- If in doubt, select 'N'.
-
-choice
- prompt "Compact Flash Connection Area"
- depends on CF_ENABLER
- default CF_AREA6
-
-config CF_AREA5
- bool "Area5"
- help
- If your board has "Directly Connected" CompactFlash, You should
- select the area where your CF is connected to.
-
- - "Area5" if CompactFlash is connected to Area 5 (0x14000000)
- - "Area6" if it is connected to Area 6 (0x18000000)
-
- "Area6" will work for most boards.
-
-config CF_AREA6
- bool "Area6"
-
-endchoice
-
-config CF_BASE_ADDR
- hex
- depends on CF_ENABLER
- default "0xb8000000" if CF_AREA6
- default "0xb4000000" if CF_AREA5
-
-menu "Processor features"
-
-choice
- prompt "Endianess selection"
- default CPU_LITTLE_ENDIAN
- help
- Some SuperH machines can be configured for either little or big
- endian byte order. These modes require different kernels.
-
-config CPU_LITTLE_ENDIAN
- bool "Little Endian"
-
-config CPU_BIG_ENDIAN
- bool "Big Endian"
-
-endchoice
-
-config SH_FPU
- bool "FPU support"
- depends on !CPU_SH3
- default y
- help
- Selecting this option will enable support for SH processors that
- have FPU units (ie, SH77xx).
-
- This option must be set in order to enable the FPU.
-
-config SH_FPU_EMU
- bool "FPU emulation support"
- depends on !SH_FPU && EXPERIMENTAL
- default n
- help
- Selecting this option will enable support for software FPU emulation.
- Most SH-3 users will want to say Y here, whereas most SH-4 users will
- want to say N.
-
-config SH_DSP
- bool "DSP support"
- default y if SH4AL_DSP || !CPU_SH4
- default n
- help
- Selecting this option will enable support for SH processors that
- have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
-
- This option must be set in order to enable the DSP.
-
-config SH_ADC
- bool "ADC support"
- depends on CPU_SH3
- default y
- help
- Selecting this option will allow the Linux kernel to use SH3 on-chip
- ADC module.
-
- If unsure, say N.
-
-config SH_STORE_QUEUES
- bool "Support for Store Queues"
- depends on CPU_SH4
- help
- Selecting this option will enable an in-kernel API for manipulating
- the store queues integrated in the SH-4 processors.
-
-config SPECULATIVE_EXECUTION
- bool "Speculative subroutine return"
- depends on CPU_SUBTYPE_SH7780 && EXPERIMENTAL
- help
- This enables support for a speculative instruction fetch for
- subroutine return. There are various pitfalls associated with
- this, as outlined in the SH7780 hardware manual.
-
- If unsure, say N.
-
-config CPU_HAS_INTEVT
- bool
-
-config CPU_HAS_PINT_IRQ
- bool
-
-config CPU_HAS_MASKREG_IRQ
- bool
-
-config CPU_HAS_INTC2_IRQ
- bool
-
-config CPU_HAS_IPR_IRQ
- bool
-
-config CPU_HAS_SR_RB
- bool "CPU has SR.RB"
- depends on CPU_SH3 || CPU_SH4
- default y
- help
- This will enable the use of SR.RB register bank usage. Processors
- that are lacking this bit must have another method in place for
- accomplishing what is taken care of by the banked registers.
-
- See <file:Documentation/sh/register-banks.txt> for further
- information on SR.RB and register banking in the kernel in general.
-
-config CPU_HAS_PTEA
- bool
-
-endmenu
-
menu "Timer and clock configuration"
config SH_TMU
@@ -473,13 +450,13 @@ config SH_PCLK_FREQ
int "Peripheral clock frequency (in Hz)"
default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
default "31250000" if CPU_SUBTYPE_SH7619
+ default "32000000" if CPU_SUBTYPE_SH7722
default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705 || \
CPU_SUBTYPE_SH7206
- default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780 || \
- CPU_SUBTYPE_SH7785
- default "60000000" if CPU_SUBTYPE_SH7751
+ default "60000000" if CPU_SUBTYPE_SH7751 || CPU_SUBTYPE_SH7751R
default "66000000" if CPU_SUBTYPE_SH4_202
+ default "50000000"
help
This option is used to specify the peripheral clock frequency.
This is necessary for determining the reference clock value on
@@ -487,8 +464,10 @@ config SH_PCLK_FREQ
config SH_CLK_MD
int "CPU Mode Pin Setting"
- default 0
depends on CPU_SUBTYPE_SH7619 || CPU_SUBTYPE_SH7206
+ default 6 if CPU_SUBTYPE_SH7206
+ default 5 if CPU_SUBTYPE_SH7619
+ default 0
help
MD2 - MD0 pin setting.
@@ -560,6 +539,7 @@ config CRASH_DUMP
config SMP
bool "Symmetric multi-processing support"
+ depends on SYS_SUPPORTS_SMP
---help---
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If
@@ -584,6 +564,7 @@ config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32
depends on SMP
+ default "4" if CPU_SHX3
default "2"
help
This allows you to specify the maximum number of CPUs which this
@@ -623,6 +604,7 @@ config BOOT_LINK_OFFSET
config UBC_WAKEUP
bool "Wakeup UBC on startup"
+ depends on CPU_SH4
help
Selecting this option will wakeup the User Break Controller (UBC) on
startup. Although the UBC is left in an awake state when the processor
@@ -651,8 +633,8 @@ menu "Bus options"
# we're not using PCMCIA, so we make it dependent on
# PCMCIA outright. -- PFM.
config ISA
- bool
- default y if PCMCIA
+ def_bool y
+ depends on PCMCIA && HD6446X_SERIES
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
@@ -690,6 +672,49 @@ config SUPERHYWAY
tristate "SuperHyway Bus support"
depends on CPU_SUBTYPE_SH4_202
+config CF_ENABLER
+ bool "Compact Flash Enabler support"
+ depends on SOLUTION_ENGINE || SH_SH03
+ ---help---
+ Compact Flash is a small, removable mass storage device introduced
+ in 1994 originally as a PCMCIA device. If you say `Y' here, you
+ compile in support for Compact Flash devices directly connected to
+ a SuperH processor. A Compact Flash FAQ is available at
+ <http://www.compactflash.org/faqs/faq.htm>.
+
+ If your board has "Directly Connected" CompactFlash at area 5 or 6,
+ you may want to enable this option. Then, you can use CF as
+ primary IDE drive (only tested for SanDisk).
+
+ If in doubt, select 'N'.
+
+choice
+ prompt "Compact Flash Connection Area"
+ depends on CF_ENABLER
+ default CF_AREA6
+
+config CF_AREA5
+ bool "Area5"
+ help
+ If your board has "Directly Connected" CompactFlash, You should
+ select the area where your CF is connected to.
+
+ - "Area5" if CompactFlash is connected to Area 5 (0x14000000)
+ - "Area6" if it is connected to Area 6 (0x18000000)
+
+ "Area6" will work for most boards.
+
+config CF_AREA6
+ bool "Area6"
+
+endchoice
+
+config CF_BASE_ADDR
+ hex
+ depends on CF_ENABLER
+ default "0xb8000000" if CF_AREA6
+ default "0xb4000000" if CF_AREA5
+
source "arch/sh/drivers/pci/Kconfig"
source "drivers/pci/Kconfig"
@@ -707,7 +732,7 @@ source "fs/Kconfig.binfmt"
endmenu
menu "Power management options (EXPERIMENTAL)"
-depends on EXPERIMENTAL
+depends on EXPERIMENTAL && SYS_SUPPORTS_PM
source kernel/power/Kconfig
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index b56307294b67..52f6a99c8ecc 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -52,6 +52,10 @@ config EARLY_PRINTK
select both the EARLY_SCIF_CONSOLE and SH_STANDARD_BIOS, using
the kernel command line option to toggle back and forth.
+config DEBUG_BOOTMEM
+ depends on DEBUG_KERNEL
+ bool "Debug BOOTMEM initialization"
+
config DEBUG_STACKOVERFLOW
bool "Check for stack overflows"
depends on DEBUG_KERNEL
@@ -82,6 +86,7 @@ config SH_KGDB
bool "Include KGDB kernel debugger"
select FRAME_POINTER
select DEBUG_INFO
+ depends on CPU_SH3 || CPU_SH4
help
Include in-kernel hooks for kgdb, the Linux kernel source level
debugger. See <http://kgdb.sourceforge.net/> for more information.
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index 883b03b040c4..0016609d1eba 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -34,20 +34,20 @@ isa-y := $(isa-y)-nofpu
endif
endif
-cflags-$(CONFIG_CPU_SH2) := -m2
-cflags-$(CONFIG_CPU_SH2A) := -m2a $(call cc-option,-m2a-nofpu,)
-cflags-$(CONFIG_CPU_SH3) := -m3
-cflags-$(CONFIG_CPU_SH4) := -m4 \
+cflags-$(CONFIG_CPU_SH2) := $(call cc-option,-m2,)
+cflags-$(CONFIG_CPU_SH2A) += $(call cc-option,-m2a,) \
+ $(call cc-option,-m2a-nofpu,)
+cflags-$(CONFIG_CPU_SH3) := $(call cc-option,-m3,)
+cflags-$(CONFIG_CPU_SH4) := $(call cc-option,-m4,) \
$(call cc-option,-mno-implicit-fp,-m4-nofpu)
-cflags-$(CONFIG_CPU_SH4A) := $(call cc-option,-m4a,) $(call cc-option,-m4a-nofpu,)
+cflags-$(CONFIG_CPU_SH4A) += $(call cc-option,-m4a,) \
+ $(call cc-option,-m4a-nofpu,)
cflags-$(CONFIG_CPU_BIG_ENDIAN) += -mb
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += -ml
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),) -ffreestanding
-cflags-$(CONFIG_SH_DSP) += -Wa,-dsp
-
cflags-$(CONFIG_MORE_COMPILE_OPTIONS) += \
$(shell echo $(CONFIG_COMPILE_OPTIONS) | sed -e 's/"//g')
@@ -87,44 +87,41 @@ core-y += arch/sh/kernel/ arch/sh/mm/
core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/
# Boards
-machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x
-machdir-$(CONFIG_SH_7722_SOLUTION_ENGINE) := se/7722
-machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751
-machdir-$(CONFIG_SH_7780_SOLUTION_ENGINE) := se/7780
-machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se/7300
-machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) := se/7343
-machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se/73180
-machdir-$(CONFIG_SH_HP6XX) := hp6xx
-machdir-$(CONFIG_SH_SATURN) := saturn
-machdir-$(CONFIG_SH_DREAMCAST) := dreamcast
-machdir-$(CONFIG_SH_MPC1211) := mpc1211
-machdir-$(CONFIG_SH_SH03) := sh03
-machdir-$(CONFIG_SH_SECUREEDGE5410) := snapgear
-machdir-$(CONFIG_SH_HS7751RVOIP) := renesas/hs7751rvoip
-machdir-$(CONFIG_SH_RTS7751R2D) := renesas/rts7751r2d
-machdir-$(CONFIG_SH_7751_SYSTEMH) := renesas/systemh
-machdir-$(CONFIG_SH_EDOSK7705) := renesas/edosk7705
-machdir-$(CONFIG_SH_HIGHLANDER) := renesas/r7780rp
-machdir-$(CONFIG_SH_7710VOIPGW) := renesas/sh7710voipgw
-machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev
-machdir-$(CONFIG_SH_LANDISK) := landisk
-machdir-$(CONFIG_SH_TITAN) := titan
-machdir-$(CONFIG_SH_SHMIN) := shmin
-machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) := se/7206
-machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) := se/7619
-machdir-$(CONFIG_SH_LBOX_RE2) := lboxre2
-machdir-$(CONFIG_SH_UNKNOWN) := unknown
-
-incdir-y := $(notdir $(machdir-y))
-incdir-$(CONFIG_SH_HP6XX) := hp6xx
+machdir-$(CONFIG_SH_SOLUTION_ENGINE) += se/770x
+machdir-$(CONFIG_SH_7722_SOLUTION_ENGINE) += se/7722
+machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) += se/7751
+machdir-$(CONFIG_SH_7780_SOLUTION_ENGINE) += se/7780
+machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) += se/7300
+machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) += se/7343
+machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) += se/73180
+machdir-$(CONFIG_SH_HP6XX) += hp6xx
+machdir-$(CONFIG_SH_DREAMCAST) += dreamcast
+machdir-$(CONFIG_SH_MPC1211) += mpc1211
+machdir-$(CONFIG_SH_SH03) += sh03
+machdir-$(CONFIG_SH_SECUREEDGE5410) += snapgear
+machdir-$(CONFIG_SH_HS7751RVOIP) += renesas/hs7751rvoip
+machdir-$(CONFIG_SH_RTS7751R2D) += renesas/rts7751r2d
+machdir-$(CONFIG_SH_7751_SYSTEMH) += renesas/systemh
+machdir-$(CONFIG_SH_EDOSK7705) += renesas/edosk7705
+machdir-$(CONFIG_SH_HIGHLANDER) += renesas/r7780rp
+machdir-$(CONFIG_SH_7710VOIPGW) += renesas/sh7710voipgw
+machdir-$(CONFIG_SH_SH4202_MICRODEV) += superh/microdev
+machdir-$(CONFIG_SH_LANDISK) += landisk
+machdir-$(CONFIG_SH_TITAN) += titan
+machdir-$(CONFIG_SH_SHMIN) += shmin
+machdir-$(CONFIG_SH_7206_SOLUTION_ENGINE) += se/7206
+machdir-$(CONFIG_SH_7619_SOLUTION_ENGINE) += se/7619
+machdir-$(CONFIG_SH_LBOX_RE2) += lboxre2
+
+incdir-y := $(notdir $(machdir-y))
ifneq ($(machdir-y),)
-core-y += arch/sh/boards/$(machdir-y)/
+core-y += $(addprefix arch/sh/boards/, \
+ $(filter-out ., $(patsubst %,%/,$(machdir-y))))
endif
# Companion chips
-core-$(CONFIG_HD64461) += arch/sh/cchips/hd6446x/hd64461/
-core-$(CONFIG_HD64465) += arch/sh/cchips/hd6446x/hd64465/
+core-$(CONFIG_HD6446X_SERIES) += arch/sh/cchips/hd6446x/
core-$(CONFIG_VOYAGERGX) += arch/sh/cchips/voyagergx/
cpuincdir-$(CONFIG_CPU_SH2) := cpu-sh2
@@ -157,19 +154,31 @@ include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) \
# Most boards have their own mach directories. For the ones that
# don't, just reference the parent directory so the semantics are
# kept roughly the same.
+#
+# When multiple boards are compiled in at the same time, preference
+# for the mach link is given to whichever has a directory for its
+# headers. However, this is only a workaround until platforms that
+# can live in the same kernel image back away from relying on the
+# mach link.
include/asm-sh/.mach: $(wildcard include/config/sh/*.h) \
include/config/auto.conf FORCE
- @echo -n ' SYMLINK include/asm-sh/mach -> '
$(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
- $(Q)if [ -d $(incdir-prefix)$(incdir-y) ]; then \
- echo -e 'include/asm-sh/$(incdir-y)'; \
- ln -fsn $(incdir-prefix)$(incdir-y) \
+ $(Q)rm -f include/asm-sh/mach
+ $(Q)for i in $(incdir-y); do \
+ if [ -d $(incdir-prefix)$$i ]; then \
+ echo -n ' SYMLINK include/asm-sh/mach -> '; \
+ echo -e "include/asm-sh/$$i"; \
+ ln -fsn $(incdir-prefix)$$i \
include/asm-sh/mach; \
else \
- echo -e 'include/asm-sh'; \
- ln -fsn $(incdir-prefix) include/asm-sh/mach; \
- fi
+ if [ ! -d include/asm-sh/mach ]; then \
+ echo -n ' SYMLINK include/asm-sh/mach -> '; \
+ echo -e 'include/asm-sh'; \
+ ln -fsn $(incdir-prefix) include/asm-sh/mach; \
+ fi; \
+ fi; \
+ done
@touch $@
archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools
@@ -188,7 +197,9 @@ compressed: zImage
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
-CLEAN_FILES += include/asm-sh/machtypes.h
+CLEAN_FILES += include/asm-sh/machtypes.h \
+ include/asm-sh/cpu include/asm-sh/.cpu \
+ include/asm-sh/mach include/asm-sh/.mach
define archhelp
@echo '* zImage - Compressed kernel image'
diff --git a/arch/sh/boards/dreamcast/setup.c b/arch/sh/boards/dreamcast/setup.c
index f13017eeeb27..8799df6e866a 100644
--- a/arch/sh/boards/dreamcast/setup.c
+++ b/arch/sh/boards/dreamcast/setup.c
@@ -60,7 +60,7 @@ static void __init dreamcast_setup(char **cmdline_p)
#endif
}
-struct sh_machine_vector mv_dreamcast __initmv = {
+static struct sh_machine_vector mv_dreamcast __initmv = {
.mv_name = "Sega Dreamcast",
.mv_setup = dreamcast_setup,
.mv_irq_demux = systemasic_irq_demux,
@@ -70,4 +70,3 @@ struct sh_machine_vector mv_dreamcast __initmv = {
.mv_consistent_free = dreamcast_consistent_free,
#endif
};
-ALIAS_MV(dreamcast)
diff --git a/arch/sh/boards/hp6xx/mach.c b/arch/sh/boards/hp6xx/mach.c
deleted file mode 100644
index 08dbba910f74..000000000000
--- a/arch/sh/boards/hp6xx/mach.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * linux/arch/sh/boards/hp6xx/mach.c
- *
- * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the HP680
- */
-#include <asm/machvec.h>
-#include <asm/hd64461.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-struct sh_machine_vector mv_hp6xx __initmv = {
- .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
-
- .mv_inb = hd64461_inb,
- .mv_inw = hd64461_inw,
- .mv_inl = hd64461_inl,
- .mv_outb = hd64461_outb,
- .mv_outw = hd64461_outw,
- .mv_outl = hd64461_outl,
-
- .mv_inb_p = hd64461_inb_p,
- .mv_inw_p = hd64461_inw,
- .mv_inl_p = hd64461_inl,
- .mv_outb_p = hd64461_outb_p,
- .mv_outw_p = hd64461_outw,
- .mv_outl_p = hd64461_outl,
-
- .mv_insb = hd64461_insb,
- .mv_insw = hd64461_insw,
- .mv_insl = hd64461_insl,
- .mv_outsb = hd64461_outsb,
- .mv_outsw = hd64461_outsw,
- .mv_outsl = hd64461_outsl,
-
- .mv_readw = hd64461_readw,
- .mv_writew = hd64461_writew,
-
- .mv_irq_demux = hd64461_irq_demux,
-};
-
-ALIAS_MV(hp6xx)
diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c
index 6aeee85c9785..7ae708930bac 100644
--- a/arch/sh/boards/hp6xx/setup.c
+++ b/arch/sh/boards/hp6xx/setup.c
@@ -98,10 +98,9 @@ static void __init hp6xx_setup(char **cmdline_p)
}
device_initcall(hp6xx_devices_setup);
-struct sh_machine_vector mv_hp6xx __initmv = {
+static struct sh_machine_vector mv_hp6xx __initmv = {
.mv_name = "hp6xx",
.mv_setup = hp6xx_setup,
.mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
.mv_irq_demux = hd64461_irq_demux,
};
-ALIAS_MV(hp6xx)
diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c
index f953c7427769..eda71763ecc5 100644
--- a/arch/sh/boards/landisk/setup.c
+++ b/arch/sh/boards/landisk/setup.c
@@ -97,10 +97,9 @@ static void __init landisk_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_landisk __initmv = {
+static struct sh_machine_vector mv_landisk __initmv = {
.mv_name = "LANDISK",
.mv_nr_irqs = 72,
.mv_setup = landisk_setup,
.mv_init_irq = init_landisk_IRQ,
};
-ALIAS_MV(landisk)
diff --git a/arch/sh/boards/lboxre2/setup.c b/arch/sh/boards/lboxre2/setup.c
index 4e20f7c63bf3..9c830fdc411b 100644
--- a/arch/sh/boards/lboxre2/setup.c
+++ b/arch/sh/boards/lboxre2/setup.c
@@ -77,9 +77,8 @@ device_initcall(lboxre2_devices_setup);
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_lboxre2 __initmv = {
+static struct sh_machine_vector mv_lboxre2 __initmv = {
.mv_name = "L-BOX RE2",
.mv_nr_irqs = 72,
.mv_init_irq = init_lboxre2_IRQ,
};
-ALIAS_MV(lboxre2)
diff --git a/arch/sh/boards/mpc1211/pci.c b/arch/sh/boards/mpc1211/pci.c
index 4ed1a95c6d56..23849f70f133 100644
--- a/arch/sh/boards/mpc1211/pci.c
+++ b/arch/sh/boards/mpc1211/pci.c
@@ -187,7 +187,7 @@ char * __devinit pcibios_setup(char *str)
* are examined.
*/
-void __init pcibios_fixup_bus(struct pci_bus *b)
+void __devinit pcibios_fixup_bus(struct pci_bus *b)
{
pci_read_bridge_bases(b);
}
diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c
index 1a0604b23ce0..8ce03e00b0ae 100644
--- a/arch/sh/boards/mpc1211/setup.c
+++ b/arch/sh/boards/mpc1211/setup.c
@@ -338,11 +338,10 @@ static void __init mpc1211_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_mpc1211 __initmv = {
+static struct sh_machine_vector mv_mpc1211 __initmv = {
.mv_name = "Interface MPC-1211(CTP/PCI/MPC-SH02)",
.mv_setup = mpc1211_setup,
.mv_nr_irqs = 48,
.mv_irq_demux = mpc1211_irq_demux,
.mv_init_irq = init_mpc1211_IRQ,
};
-ALIAS_MV(mpc1211)
diff --git a/arch/sh/boards/renesas/edosk7705/setup.c b/arch/sh/boards/renesas/edosk7705/setup.c
index ec5be0107719..f076c45308dd 100644
--- a/arch/sh/boards/renesas/edosk7705/setup.c
+++ b/arch/sh/boards/renesas/edosk7705/setup.c
@@ -21,7 +21,7 @@ static void __init sh_edosk7705_init_irq(void)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_edosk7705 __initmv = {
+static struct sh_machine_vector mv_edosk7705 __initmv = {
.mv_name = "EDOSK7705",
.mv_nr_irqs = 80,
@@ -41,4 +41,3 @@ struct sh_machine_vector mv_edosk7705 __initmv = {
.mv_isa_port2addr = sh_edosk7705_isa_port2addr,
.mv_init_irq = sh_edosk7705_init_irq,
};
-ALIAS_MV(edosk7705)
diff --git a/arch/sh/boards/renesas/hs7751rvoip/setup.c b/arch/sh/boards/renesas/hs7751rvoip/setup.c
index f7d0e304d899..fa5fa3920222 100644
--- a/arch/sh/boards/renesas/hs7751rvoip/setup.c
+++ b/arch/sh/boards/renesas/hs7751rvoip/setup.c
@@ -89,7 +89,7 @@ static void __init hs7751rvoip_setup(char **cmdline_p)
printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
}
-struct sh_machine_vector mv_hs7751rvoip __initmv = {
+static struct sh_machine_vector mv_hs7751rvoip __initmv = {
.mv_name = "HS7751RVoIP",
.mv_setup = hs7751rvoip_setup,
.mv_nr_irqs = 72,
@@ -118,4 +118,3 @@ struct sh_machine_vector mv_hs7751rvoip __initmv = {
.mv_init_irq = hs7751rvoip_init_irq,
.mv_ioport_map = hs7751rvoip_ioport_map,
};
-ALIAS_MV(hs7751rvoip)
diff --git a/arch/sh/boards/renesas/r7780rp/Kconfig b/arch/sh/boards/renesas/r7780rp/Kconfig
index 9fb11641fe13..fc8f28e04ba3 100644
--- a/arch/sh/boards/renesas/r7780rp/Kconfig
+++ b/arch/sh/boards/renesas/r7780rp/Kconfig
@@ -6,18 +6,18 @@ choice
config SH_R7780RP
bool "R7780RP-1 board support"
- select CPU_SUBTYPE_SH7780
+ depends on CPU_SUBTYPE_SH7780
config SH_R7780MP
bool "R7780MP board support"
- select CPU_SUBTYPE_SH7780
+ depends on CPU_SUBTYPE_SH7780
help
Selecting this option will enable support for the mass-production
version of the R7780RP. If in doubt, say Y.
config SH_R7785RP
bool "R7785RP board support"
- select CPU_SUBTYPE_SH7785
+ depends on CPU_SUBTYPE_SH7785
endchoice
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index 0727ef92f2b3..adb529d01bae 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -21,6 +21,58 @@
#include <asm/clock.h>
#include <asm/io.h>
+static struct resource r8a66597_usb_host_resources[] = {
+ [0] = {
+ .name = "r8a66597_hcd",
+ .start = 0xA4200000,
+ .end = 0xA42000FF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "r8a66597_hcd",
+ .start = 11, /* irq number */
+ .end = 11,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device r8a66597_usb_host_device = {
+ .name = "r8a66597_hcd",
+ .id = -1,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(r8a66597_usb_host_resources),
+ .resource = r8a66597_usb_host_resources,
+};
+
+static struct resource m66592_usb_peripheral_resources[] = {
+ [0] = {
+ .name = "m66592_udc",
+ .start = 0xb0000000,
+ .end = 0xb00000FF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "m66592_udc",
+ .start = 9, /* irq number */
+ .end = 9,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device m66592_usb_peripheral_device = {
+ .name = "m66592_udc",
+ .id = -1,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(m66592_usb_peripheral_resources),
+ .resource = m66592_usb_peripheral_resources,
+};
+
static struct resource cf_ide_resources[] = {
[0] = {
.start = PA_AREA5_IO + 0x1000,
@@ -81,6 +133,8 @@ static struct platform_device heartbeat_device = {
};
static struct platform_device *r7780rp_devices[] __initdata = {
+ &r8a66597_usb_host_device,
+ &m66592_usb_peripheral_device,
&cf_ide_device,
&heartbeat_device,
};
@@ -166,10 +220,9 @@ static void __init highlander_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_highlander __initmv = {
+static struct sh_machine_vector mv_highlander __initmv = {
.mv_name = "Highlander",
.mv_nr_irqs = 109,
.mv_setup = highlander_setup,
.mv_init_irq = highlander_init_irq,
};
-ALIAS_MV(highlander)
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
index 593f26a85e9c..e165d85c03b5 100644
--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
+++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
@@ -86,7 +86,8 @@ static struct plat_serial8250_port uart_platform_data[] = {
.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
.regshift = 2,
.uartclk = (9600 * 16),
- }
+ },
+ { 0 },
};
static struct platform_device uart_device = {
@@ -176,7 +177,7 @@ static void __init rts7751r2d_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_rts7751r2d __initmv = {
+static struct sh_machine_vector mv_rts7751r2d __initmv = {
.mv_name = "RTS7751R2D",
.mv_setup = rts7751r2d_setup,
.mv_nr_irqs = 72,
@@ -189,4 +190,3 @@ struct sh_machine_vector mv_rts7751r2d __initmv = {
.mv_consistent_free = voyagergx_consistent_free,
#endif
};
-ALIAS_MV(rts7751r2d)
diff --git a/arch/sh/boards/renesas/sh7710voipgw/setup.c b/arch/sh/boards/renesas/sh7710voipgw/setup.c
index 180810b12107..2dce8bd97f90 100644
--- a/arch/sh/boards/renesas/sh7710voipgw/setup.c
+++ b/arch/sh/boards/renesas/sh7710voipgw/setup.c
@@ -88,9 +88,8 @@ static void __init sh7710voipgw_init_irq(void)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_sh7710voipgw __initmv = {
+static struct sh_machine_vector mv_sh7710voipgw __initmv = {
.mv_name = "SH7710 VoIP Gateway",
.mv_nr_irqs = 104,
.mv_init_irq = sh7710voipgw_init_irq,
};
-ALIAS_MV(sh7710voipgw)
diff --git a/arch/sh/boards/renesas/systemh/setup.c b/arch/sh/boards/renesas/systemh/setup.c
index 936117659b74..ee78af842778 100644
--- a/arch/sh/boards/renesas/systemh/setup.c
+++ b/arch/sh/boards/renesas/systemh/setup.c
@@ -28,7 +28,7 @@ static void __init sh7751systemh_init_irq(void)
make_systemh_irq(0xb); /* Ethernet interrupt */
}
-struct sh_machine_vector mv_7751systemh __initmv = {
+static struct sh_machine_vector mv_7751systemh __initmv = {
.mv_name = "7751 SystemH",
.mv_nr_irqs = 72,
@@ -55,4 +55,3 @@ struct sh_machine_vector mv_7751systemh __initmv = {
.mv_init_irq = sh7751systemh_init_irq,
};
-ALIAS_MV(7751systemh)
diff --git a/arch/sh/boards/saturn/Makefile b/arch/sh/boards/saturn/Makefile
deleted file mode 100644
index 75a3042e252e..000000000000
--- a/arch/sh/boards/saturn/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the Sega Saturn specific parts of the kernel
-#
-
-obj-y := setup.o io.o irq.o
-
-obj-$(CONFIG_SMP) += smp.o
-
diff --git a/arch/sh/boards/saturn/io.c b/arch/sh/boards/saturn/io.c
deleted file mode 100644
index c6e4f7f2e686..000000000000
--- a/arch/sh/boards/saturn/io.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * arch/sh/boards/saturn/io.c
- *
- * I/O routines for the Sega Saturn.
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#include <asm/saturn/io.h>
-#include <asm/machvec.h>
-
-unsigned long saturn_isa_port2addr(unsigned long offset)
-{
- return offset;
-}
-
-void *saturn_ioremap(unsigned long offset, unsigned long size)
-{
- return (void *)offset;
-}
-
-void saturn_iounmap(void *addr)
-{
-}
-
diff --git a/arch/sh/boards/saturn/irq.c b/arch/sh/boards/saturn/irq.c
deleted file mode 100644
index 15d1d3f0f787..000000000000
--- a/arch/sh/boards/saturn/irq.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * arch/sh/boards/saturn/irq.c
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-
-/*
- * Interrupts map out as follows:
- *
- * Vector Name Mask
- *
- * 64 VBLANKIN 0x0001
- * 65 VBLANKOUT 0x0002
- * 66 HBLANKIN 0x0004
- * 67 TIMER0 0x0008
- * 68 TIMER1 0x0010
- * 69 DSPEND 0x0020
- * 70 SOUNDREQUEST 0x0040
- * 71 SYSTEMMANAGER 0x0080
- * 72 PAD 0x0100
- * 73 LEVEL2DMAEND 0x0200
- * 74 LEVEL1DMAEND 0x0400
- * 75 LEVEL0DMAEND 0x0800
- * 76 DMAILLEGAL 0x1000
- * 77 SRITEDRAWEND 0x2000
- * 78 ABUS 0x8000
- *
- */
-#define SATURN_IRQ_MIN 64 /* VBLANKIN */
-#define SATURN_IRQ_MAX 78 /* ABUS */
-
-#define SATURN_IRQ_MASK 0xbfff
-
-static inline u32 saturn_irq_mask(unsigned int irq_nr)
-{
- u32 mask;
-
- mask = (1 << (irq_nr - SATURN_IRQ_MIN));
- mask <<= (irq_nr == SATURN_IRQ_MAX);
- mask &= SATURN_IRQ_MASK;
-
- return mask;
-}
-
-static inline void mask_saturn_irq(unsigned int irq_nr)
-{
- u32 mask;
-
- mask = ctrl_inl(SATURN_IMR);
- mask |= saturn_irq_mask(irq_nr);
- ctrl_outl(mask, SATURN_IMR);
-}
-
-static inline void unmask_saturn_irq(unsigned int irq_nr)
-{
- u32 mask;
-
- mask = ctrl_inl(SATURN_IMR);
- mask &= ~saturn_irq_mask(irq_nr);
- ctrl_outl(mask, SATURN_IMR);
-}
-
-static void disable_saturn_irq(unsigned int irq_nr)
-{
- mask_saturn_irq(irq_nr);
-}
-
-static void enable_saturn_irq(unsigned int irq_nr)
-{
- unmask_saturn_irq(irq_nr);
-}
-
-static void mask_and_ack_saturn_irq(unsigned int irq_nr)
-{
- mask_saturn_irq(irq_nr);
-}
-
-static void end_saturn_irq(unsigned int irq_nr)
-{
- if (!(irq_desc[irq_nr].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
- unmask_saturn_irq(irq_nr);
-}
-
-static unsigned int startup_saturn_irq(unsigned int irq_nr)
-{
- unmask_saturn_irq(irq_nr);
-
- return 0;
-}
-
-static void shutdown_saturn_irq(unsigned int irq_nr)
-{
- mask_saturn_irq(irq_nr);
-}
-
-static struct hw_interrupt_type saturn_int = {
- .typename = "Saturn",
- .enable = enable_saturn_irq,
- .disable = disable_saturn_irq,
- .ack = mask_and_ack_saturn_irq,
- .end = end_saturn_irq,
- .startup = startup_saturn_irq,
- .shutdown = shutdown_saturn_irq,
-};
-
-int saturn_irq_demux(int irq_nr)
-{
- /* FIXME */
- return irq_nr;
-}
-
diff --git a/arch/sh/boards/saturn/setup.c b/arch/sh/boards/saturn/setup.c
deleted file mode 100644
index a3a37c9aad2e..000000000000
--- a/arch/sh/boards/saturn/setup.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/sh/boards/saturn/setup.c
- *
- * Hardware support for the Sega Saturn.
- *
- * Copyright (c) 2002 Paul Mundt
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/machvec.h>
-#include <asm/mach/io.h>
-
-extern int saturn_irq_demux(int irq_nr);
-
-/*
- * The Machine Vector
- */
-struct sh_machine_vector mv_saturn __initmv = {
- .mv_name = "Sega Saturn",
- .mv_nr_irqs = 80, /* Fix this later */
-
- .mv_isa_port2addr = saturn_isa_port2addr,
- .mv_irq_demux = saturn_irq_demux,
-
- .mv_ioremap = saturn_ioremap,
- .mv_iounmap = saturn_iounmap,
-};
-ALIAS_MV(saturn)
diff --git a/arch/sh/boards/saturn/smp.c b/arch/sh/boards/saturn/smp.c
deleted file mode 100644
index 76460918c9cd..000000000000
--- a/arch/sh/boards/saturn/smp.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * arch/sh/boards/saturn/smp.c
- *
- * SMP support for the Sega Saturn.
- *
- * Copyright (c) 2002 Paul Mundt
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/saturn/smpc.h>
-
-extern void start_secondary(void);
-
-void __smp_send_ipi(unsigned int cpu, unsigned int action)
-{
- /* Nothing here yet .. */
-}
-
-unsigned int __smp_probe_cpus(void)
-{
- /*
- * This is just a straightforward master/slave configuration,
- * and probing isn't really supported..
- */
- return 2;
-}
-
-/*
- * We're only allowed to do byte-access to SMPC registers. In
- * addition to which, we treat them as write-only, since
- * reading from them will return undefined data.
- */
-static inline void smpc_slave_stop(unsigned int cpu)
-{
- smpc_barrier();
- ctrl_outb(1, SMPC_STATUS);
-
- ctrl_outb(SMPC_CMD_SSHOFF, SMPC_COMMAND);
- smpc_barrier();
-}
-
-static inline void smpc_slave_start(unsigned int cpu)
-{
- ctrl_outb(1, SMPC_STATUS);
- ctrl_outb(SMPC_CMD_SSHON, SMPC_COMMAND);
-
- smpc_barrier();
-}
-
-void __smp_slave_init(unsigned int cpu)
-{
- register unsigned long vbr;
- void **entry;
-
- __asm__ __volatile__ ("stc vbr, %0\n\t" : "=r" (vbr));
- entry = (void **)(vbr + 0x310 + 0x94);
-
- smpc_slave_stop(cpu);
-
- *(void **)entry = (void *)start_secondary;
-
- smpc_slave_start(cpu);
-}
-
diff --git a/arch/sh/boards/se/7206/setup.c b/arch/sh/boards/se/7206/setup.c
index ca714879f559..a074b62505ef 100644
--- a/arch/sh/boards/se/7206/setup.c
+++ b/arch/sh/boards/se/7206/setup.c
@@ -70,7 +70,7 @@ __initcall(se7206_devices_setup);
* The Machine Vector
*/
-struct sh_machine_vector mv_se __initmv = {
+static struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
.mv_nr_irqs = 256,
.mv_inb = se7206_inb,
@@ -96,4 +96,3 @@ struct sh_machine_vector mv_se __initmv = {
.mv_init_irq = init_se7206_IRQ,
};
-ALIAS_MV(se)
diff --git a/arch/sh/boards/se/7300/setup.c b/arch/sh/boards/se/7300/setup.c
index f1960956bad0..eb469f5b6e97 100644
--- a/arch/sh/boards/se/7300/setup.c
+++ b/arch/sh/boards/se/7300/setup.c
@@ -46,7 +46,7 @@ __initcall(se7300_devices_setup);
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_7300se __initmv = {
+static struct sh_machine_vector mv_7300se __initmv = {
.mv_name = "SolutionEngine 7300",
.mv_nr_irqs = 109,
.mv_inb = sh7300se_inb,
@@ -72,4 +72,3 @@ struct sh_machine_vector mv_7300se __initmv = {
.mv_init_irq = init_7300se_IRQ,
};
-ALIAS_MV(7300se)
diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c
index e143017c8975..1deee8556642 100644
--- a/arch/sh/boards/se/73180/setup.c
+++ b/arch/sh/boards/se/73180/setup.c
@@ -46,7 +46,7 @@ __initcall(se73180_devices_setup);
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_73180se __initmv = {
+static struct sh_machine_vector mv_73180se __initmv = {
.mv_name = "SolutionEngine 73180",
.mv_nr_irqs = 108,
.mv_inb = sh73180se_inb,
@@ -73,4 +73,3 @@ struct sh_machine_vector mv_73180se __initmv = {
.mv_init_irq = init_73180se_IRQ,
.mv_irq_demux = shmse_irq_demux,
};
-ALIAS_MV(73180se)
diff --git a/arch/sh/boards/se/7343/setup.c b/arch/sh/boards/se/7343/setup.c
index 3fdb16f2cef1..8fec155e2ff7 100644
--- a/arch/sh/boards/se/7343/setup.c
+++ b/arch/sh/boards/se/7343/setup.c
@@ -64,7 +64,7 @@ static void __init sh7343se_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_7343se __initmv = {
+static struct sh_machine_vector mv_7343se __initmv = {
.mv_name = "SolutionEngine 7343",
.mv_setup = sh7343se_setup,
.mv_nr_irqs = 108,
@@ -92,4 +92,3 @@ struct sh_machine_vector mv_7343se __initmv = {
.mv_init_irq = init_7343se_IRQ,
.mv_irq_demux = shmse_irq_demux,
};
-ALIAS_MV(7343se)
diff --git a/arch/sh/boards/se/7619/setup.c b/arch/sh/boards/se/7619/setup.c
index 52d2c4d5d2fa..1d0ef7faa10d 100644
--- a/arch/sh/boards/se/7619/setup.c
+++ b/arch/sh/boards/se/7619/setup.c
@@ -15,8 +15,7 @@
* The Machine Vector
*/
-struct sh_machine_vector mv_se __initmv = {
+static struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
.mv_nr_irqs = 108,
};
-ALIAS_MV(se)
diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c
index c8eccff77a04..cdb0807928a5 100644
--- a/arch/sh/boards/se/770x/irq.c
+++ b/arch/sh/boards/se/770x/irq.c
@@ -15,46 +15,7 @@
#include <asm/io.h>
#include <asm/se.h>
-/*
- * If the problem of make_ipr_irq is solved,
- * this code will become unnecessary. :-)
- */
-static void se770x_disable_ipr_irq(unsigned int irq)
-{
- struct ipr_data *p = get_irq_chip_data(irq);
-
- ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr);
-}
-
-static void se770x_enable_ipr_irq(unsigned int irq)
-{
- struct ipr_data *p = get_irq_chip_data(irq);
-
- ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr);
-}
-
-static struct irq_chip se770x_irq_chip = {
- .name = "MS770xSE-FPGA",
- .mask = se770x_disable_ipr_irq,
- .unmask = se770x_enable_ipr_irq,
- .mask_ack = se770x_disable_ipr_irq,
-};
-
-void make_se770x_irq(struct ipr_data *table, unsigned int nr_irqs)
-{
- int i;
-
- for (i = 0; i < nr_irqs; i++) {
- unsigned int irq = table[i].irq;
- disable_irq_nosync(irq);
- set_irq_chip_and_handler_name(irq, &se770x_irq_chip,
- handle_level_irq, "level");
- set_irq_chip_data(irq, &table[i]);
- se770x_enable_ipr_irq(irq);
- }
-}
-
-static struct ipr_data se770x_ipr_map[] = {
+static struct ipr_data ipr_irq_table[] = {
/*
* Super I/O (Just mimic PC):
* 1: keyboard
@@ -68,46 +29,67 @@ static struct ipr_data se770x_ipr_map[] = {
*/
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
/* This is default value */
- { 13, 0, 8, 0x0f-13 ,BCR_ILCRA},
- { 5 , 0, 4, 0x0f- 5 ,BCR_ILCRA},
- { 10, 0, 0, 0x0f-10, BCR_ILCRB},
- { 7 , 0, 4, 0x0f- 7, BCR_ILCRC},
- { 3 , 0, 0, 0x0f- 3, BCR_ILCRC},
- { 1 , 0, 12, 0x0f- 1, BCR_ILCRD},
- { 12, 0, 4, 0x0f-12, BCR_ILCRD}, /* LAN */
- { 2 , 0, 8, 0x0f- 2, BCR_ILCRE}, /* PCIRQ2 */
- { 6 , 0, 4, 0x0f- 6, BCR_ILCRE}, /* PCIRQ1 */
- { 14, 0, 0, 0x0f-14, BCR_ILCRE}, /* PCIRQ0 */
- { 0 , 0, 12, 0x0f , BCR_ILCRF},
- { 4 , 0, 4, 0x0f- 4, BCR_ILCRF},
- { 8 , 0, 12, 0x0f- 8, BCR_ILCRG},
- { 9 , 0, 8, 0x0f- 9, BCR_ILCRG},
- { 11, 0, 4, 0x0f-11, BCR_ILCRG},
+ { 13, 0, 8, 0x0f-13, },
+ { 5 , 0, 4, 0x0f- 5, },
+ { 10, 1, 0, 0x0f-10, },
+ { 7 , 2, 4, 0x0f- 7, },
+ { 3 , 2, 0, 0x0f- 3, },
+ { 1 , 3, 12, 0x0f- 1, },
+ { 12, 3, 4, 0x0f-12, }, /* LAN */
+ { 2 , 4, 8, 0x0f- 2, }, /* PCIRQ2 */
+ { 6 , 4, 4, 0x0f- 6, }, /* PCIRQ1 */
+ { 14, 4, 0, 0x0f-14, }, /* PCIRQ0 */
+ { 0 , 5, 12, 0x0f , },
+ { 4 , 5, 4, 0x0f- 4, },
+ { 8 , 6, 12, 0x0f- 8, },
+ { 9 , 6, 8, 0x0f- 9, },
+ { 11, 6, 4, 0x0f-11, },
#else
- { 14, 0, 8, 0x0f-14 ,BCR_ILCRA},
- { 12, 0, 4, 0x0f-12 ,BCR_ILCRA},
- { 8, 0, 4, 0x0f- 8 ,BCR_ILCRB},
- { 6, 0, 12, 0x0f- 6 ,BCR_ILCRC},
- { 5, 0, 8, 0x0f- 5 ,BCR_ILCRC},
- { 4, 0, 4, 0x0f- 4 ,BCR_ILCRC},
- { 3, 0, 0, 0x0f- 3 ,BCR_ILCRC},
- { 1, 0, 12, 0x0f- 1 ,BCR_ILCRD},
+ { 14, 0, 8, 0x0f-14, },
+ { 12, 0, 4, 0x0f-12, },
+ { 8, 1, 4, 0x0f- 8, },
+ { 6, 2, 12, 0x0f- 6, },
+ { 5, 2, 8, 0x0f- 5, },
+ { 4, 2, 4, 0x0f- 4, },
+ { 3, 2, 0, 0x0f- 3, },
+ { 1, 3, 12, 0x0f- 1, },
#if defined(CONFIG_STNIC)
/* ST NIC */
- { 10, 0, 4, 0x0f-10 ,BCR_ILCRD}, /* LAN */
+ { 10, 3, 4, 0x0f-10, }, /* LAN */
#endif
/* MRSHPC IRQs setting */
- { 0, 0, 12, 0x0f- 0 ,BCR_ILCRE}, /* PCIRQ3 */
- { 11, 0, 8, 0x0f-11 ,BCR_ILCRE}, /* PCIRQ2 */
- { 9, 0, 4, 0x0f- 9 ,BCR_ILCRE}, /* PCIRQ1 */
- { 7, 0, 0, 0x0f- 7 ,BCR_ILCRE}, /* PCIRQ0 */
+ { 0, 4, 12, 0x0f- 0, }, /* PCIRQ3 */
+ { 11, 4, 8, 0x0f-11, }, /* PCIRQ2 */
+ { 9, 4, 4, 0x0f- 9, }, /* PCIRQ1 */
+ { 7, 4, 0, 0x0f- 7, }, /* PCIRQ0 */
/* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
/* NOTE: #2 and #13 are not used on PC */
- { 13, 0, 4, 0x0f-13 ,BCR_ILCRG}, /* SLOTIRQ2 */
- { 2, 0, 0, 0x0f- 2 ,BCR_ILCRG}, /* SLOTIRQ1 */
+ { 13, 6, 4, 0x0f-13, }, /* SLOTIRQ2 */
+ { 2, 6, 0, 0x0f- 2, }, /* SLOTIRQ1 */
#endif
};
+static unsigned long ipr_offsets[] = {
+ BCR_ILCRA,
+ BCR_ILCRB,
+ BCR_ILCRC,
+ BCR_ILCRD,
+ BCR_ILCRE,
+ BCR_ILCRF,
+ BCR_ILCRG,
+};
+
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+ .chip = {
+ .name = "IPR-se770x",
+ },
+};
+
/*
* Initialize IRQ setting
*/
@@ -122,5 +104,5 @@ void __init init_se_IRQ(void)
ctrl_outw(0, BCR_ILCRF);
ctrl_outw(0, BCR_ILCRG);
- make_se770x_irq(se770x_ipr_map, ARRAY_SIZE(se770x_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c
index 17a2631de3ba..2962da148f3f 100644
--- a/arch/sh/boards/se/770x/setup.c
+++ b/arch/sh/boards/se/770x/setup.c
@@ -122,7 +122,7 @@ device_initcall(se_devices_setup);
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_se __initmv = {
+static struct sh_machine_vector mv_se __initmv = {
.mv_name = "SolutionEngine",
.mv_setup = smsc_setup,
#if defined(CONFIG_CPU_SH4)
@@ -160,4 +160,3 @@ struct sh_machine_vector mv_se __initmv = {
.mv_init_irq = init_se_IRQ,
};
-ALIAS_MV(se)
diff --git a/arch/sh/boards/se/7722/irq.c b/arch/sh/boards/se/7722/irq.c
index 099e5deb77f8..0b03f3f610b8 100644
--- a/arch/sh/boards/se/7722/irq.c
+++ b/arch/sh/boards/se/7722/irq.c
@@ -16,86 +16,61 @@
#include <asm/io.h>
#include <asm/se7722.h>
-#define INTC_INTMSK0 0xFFD00044
-#define INTC_INTMSKCLR0 0xFFD00064
-
static void disable_se7722_irq(unsigned int irq)
{
- struct ipr_data *p = get_irq_chip_data(irq);
- ctrl_outw( ctrl_inw( p->addr ) | p->priority , p->addr );
+ unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+ ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
}
static void enable_se7722_irq(unsigned int irq)
{
- struct ipr_data *p = get_irq_chip_data(irq);
- ctrl_outw( ctrl_inw( p->addr ) & ~p->priority , p->addr );
+ unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
+ ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
}
static struct irq_chip se7722_irq_chip __read_mostly = {
- .name = "SE7722",
+ .name = "SE7722-FPGA",
.mask = disable_se7722_irq,
.unmask = enable_se7722_irq,
.mask_ack = disable_se7722_irq,
};
-static struct ipr_data ipr_irq_table[] = {
- /* irq ,idx,sft, priority , addr */
- { MRSHPC_IRQ0 , 0 , 0 , MRSHPC_BIT0 , IRQ01_MASK } ,
- { MRSHPC_IRQ1 , 0 , 0 , MRSHPC_BIT1 , IRQ01_MASK } ,
- { MRSHPC_IRQ2 , 0 , 0 , MRSHPC_BIT2 , IRQ01_MASK } ,
- { MRSHPC_IRQ3 , 0 , 0 , MRSHPC_BIT3 , IRQ01_MASK } ,
- { SMC_IRQ , 0 , 0 , SMC_BIT , IRQ01_MASK } ,
- { EXT_IRQ , 0 , 0 , EXT_BIT , IRQ01_MASK } ,
-};
-
-int se7722_irq_demux(int irq)
+static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
{
+ unsigned short intv = ctrl_inw(IRQ01_STS);
+ struct irq_desc *ext_desc;
+ unsigned int ext_irq = SE7722_FPGA_IRQ_BASE;
- if ((irq == IRQ0_IRQ)||(irq == IRQ1_IRQ)) {
- volatile unsigned short intv =
- *(volatile unsigned short *)IRQ01_STS;
- if (irq == IRQ0_IRQ){
- if(intv & SMC_BIT ) {
- return SMC_IRQ;
- } else if(intv & USB_BIT) {
- return USB_IRQ;
- } else {
- printk("intv =%04x\n", intv);
- return SMC_IRQ;
- }
- } else if(irq == IRQ1_IRQ){
- if(intv & MRSHPC_BIT0) {
- return MRSHPC_IRQ0;
- } else if(intv & MRSHPC_BIT1) {
- return MRSHPC_IRQ1;
- } else if(intv & MRSHPC_BIT2) {
- return MRSHPC_IRQ2;
- } else if(intv & MRSHPC_BIT3) {
- return MRSHPC_IRQ3;
- } else {
- printk("BIT_EXTENTION =%04x\n", intv);
- return EXT_IRQ;
- }
+ intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
+
+ while (intv) {
+ if (intv & 1) {
+ ext_desc = irq_desc + ext_irq;
+ handle_level_irq(ext_irq, ext_desc);
}
+ intv >>= 1;
+ ext_irq++;
}
- return irq;
-
}
+
/*
* Initialize IRQ setting
*/
void __init init_se7722_IRQ(void)
{
- int i = 0;
+ int i;
+
+ ctrl_outw(0, IRQ01_MASK); /* disable all irqs */
ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */
- ctrl_outl((3 << ((7 - 0) * 4))|(3 << ((7 - 1) * 4)), INTC_INTPRI0); /* irq0 pri=3,irq1,pri=3 */
- ctrl_outw((2 << ((7 - 0) * 2))|(2 << ((7 - 1) * 2)), INTC_ICR1); /* irq0,1 low-level irq */
- for (i = 0; i < ARRAY_SIZE(ipr_irq_table); i++) {
- disable_irq_nosync(ipr_irq_table[i].irq);
- set_irq_chip_and_handler_name( ipr_irq_table[i].irq, &se7722_irq_chip,
- handle_level_irq, "level");
- set_irq_chip_data( ipr_irq_table[i].irq, &ipr_irq_table[i] );
- disable_se7722_irq(ipr_irq_table[i].irq);
- }
+ for (i = 0; i < SE7722_FPGA_IRQ_NR; i++)
+ set_irq_chip_and_handler_name(SE7722_FPGA_IRQ_BASE + i,
+ &se7722_irq_chip,
+ handle_level_irq, "level");
+
+ set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux);
+ set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
+
+ set_irq_chained_handler(IRQ1_IRQ, se7722_irq_demux);
+ set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
}
diff --git a/arch/sh/boards/se/7722/setup.c b/arch/sh/boards/se/7722/setup.c
index 636ca6c987e0..495fc7e2b60f 100644
--- a/arch/sh/boards/se/7722/setup.c
+++ b/arch/sh/boards/se/7722/setup.c
@@ -77,6 +77,7 @@ static struct resource cf_ide_resources[] = {
},
[2] = {
.start = MRSHPC_IRQ0,
+ .end = MRSHPC_IRQ0,
.flags = IORESOURCE_IRQ,
},
};
@@ -137,12 +138,9 @@ static void __init se7722_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_se7722 __initmv = {
+static struct sh_machine_vector mv_se7722 __initmv = {
.mv_name = "Solution Engine 7722" ,
.mv_setup = se7722_setup ,
- .mv_nr_irqs = 109 ,
+ .mv_nr_irqs = SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_NR,
.mv_init_irq = init_se7722_IRQ,
- .mv_irq_demux = se7722_irq_demux,
-
};
-ALIAS_MV(se7722)
diff --git a/arch/sh/boards/se/7751/irq.c b/arch/sh/boards/se/7751/irq.c
index e4c63a48296c..c3d12590e5db 100644
--- a/arch/sh/boards/se/7751/irq.c
+++ b/arch/sh/boards/se/7751/irq.c
@@ -14,44 +14,31 @@
#include <asm/irq.h>
#include <asm/se7751.h>
-static struct ipr_data se7751_ipr_map[] = {
- /* Leave old Solution Engine code in for reference. */
-#if defined(CONFIG_SH_SOLUTION_ENGINE)
- /*
- * Super I/O (Just mimic PC):
- * 1: keyboard
- * 3: serial 0
- * 4: serial 1
- * 5: printer
- * 6: floppy
- * 8: rtc
- * 12: mouse
- * 14: ide0
- */
- { 14, BCR_ILCRA, 2, 0x0f-14 },
- { 12, BCR_ILCRA, 1, 0x0f-12 },
- { 8, BCR_ILCRB, 1, 0x0f- 8 },
- { 6, BCR_ILCRC, 3, 0x0f- 6 },
- { 5, BCR_ILCRC, 2, 0x0f- 5 },
- { 4, BCR_ILCRC, 1, 0x0f- 4 },
- { 3, BCR_ILCRC, 0, 0x0f- 3 },
- { 1, BCR_ILCRD, 3, 0x0f- 1 },
+static struct ipr_data ipr_irq_table[] = {
+ { 13, 3, 3, 2 },
+ /* Add additional entries here as drivers are added and tested. */
+};
- { 10, BCR_ILCRD, 1, 0x0f-10 }, /* LAN */
+static unsigned long ipr_offsets[] = {
+ BCR_ILCRA,
+ BCR_ILCRB,
+ BCR_ILCRC,
+ BCR_ILCRD,
+ BCR_ILCRE,
+ BCR_ILCRF,
+ BCR_ILCRG,
+};
- { 0, BCR_ILCRE, 3, 0x0f- 0 }, /* PCIRQ3 */
- { 11, BCR_ILCRE, 2, 0x0f-11 }, /* PCIRQ2 */
- { 9, BCR_ILCRE, 1, 0x0f- 9 }, /* PCIRQ1 */
- { 7, BCR_ILCRE, 0, 0x0f- 7 }, /* PCIRQ0 */
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
- /* #2, #13 are allocated for SLOT IRQ #1 and #2 (for now) */
- /* NOTE: #2 and #13 are not used on PC */
- { 13, BCR_ILCRG, 1, 0x0f-13 }, /* SLOTIRQ2 */
- { 2, BCR_ILCRG, 0, 0x0f- 2 }, /* SLOTIRQ1 */
-#elif defined(CONFIG_SH_7751_SOLUTION_ENGINE)
- { 13, BCR_ILCRD, 3, 2 },
- /* Add additional entries here as drivers are added and tested. */
-#endif
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-se7751",
+ },
};
/*
@@ -59,5 +46,5 @@ static struct ipr_data se7751_ipr_map[] = {
*/
void __init init_7751se_IRQ(void)
{
- make_ipr_irq(se7751_ipr_map, ARRAY_SIZE(se7751_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
index 52c7bfa57c2c..7873d07e40c1 100644
--- a/arch/sh/boards/se/7751/setup.c
+++ b/arch/sh/boards/se/7751/setup.c
@@ -48,7 +48,7 @@ __initcall(se7751_devices_setup);
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_7751se __initmv = {
+static struct sh_machine_vector mv_7751se __initmv = {
.mv_name = "7751 SolutionEngine",
.mv_nr_irqs = 72,
@@ -71,4 +71,3 @@ struct sh_machine_vector mv_7751se __initmv = {
.mv_init_irq = init_7751se_IRQ,
};
-ALIAS_MV(7751se)
diff --git a/arch/sh/boards/se/7780/irq.c b/arch/sh/boards/se/7780/irq.c
index 3d0625c2d07b..874914746009 100644
--- a/arch/sh/boards/se/7780/irq.c
+++ b/arch/sh/boards/se/7780/irq.c
@@ -16,28 +16,6 @@
#include <asm/io.h>
#include <asm/se7780.h>
-#define INTC_INTMSK0 0xFFD00044
-#define INTC_INTMSKCLR0 0xFFD00064
-
-static void disable_se7780_irq(unsigned int irq)
-{
- struct intc2_data *p = get_irq_chip_data(irq);
- ctrl_outl(1 << p->msk_shift, INTC_INTMSK0 + p->msk_offset);
-}
-
-static void enable_se7780_irq(unsigned int irq)
-{
- struct intc2_data *p = get_irq_chip_data(irq);
- ctrl_outl(1 << p->msk_shift, INTC_INTMSKCLR0 + p->msk_offset);
-}
-
-static struct irq_chip se7780_irq_chip __read_mostly = {
- .name = "SE7780",
- .mask = disable_se7780_irq,
- .unmask = enable_se7780_irq,
- .mask_ack = disable_se7780_irq,
-};
-
static struct intc2_data intc2_irq_table[] = {
{ 2, 0, 31, 0, 31, 3 }, /* daughter board EXTINT1 */
{ 4, 0, 30, 0, 30, 3 }, /* daughter board EXTINT2 */
@@ -51,13 +29,24 @@ static struct intc2_data intc2_irq_table[] = {
{ 0 , 0, 24, 0, 24, 3 }, /* SM501 */
};
+static struct intc2_desc intc2_irq_desc __read_mostly = {
+ .prio_base = 0, /* N/A */
+ .msk_base = 0xffd00044,
+ .mskclr_base = 0xffd00064,
+
+ .intc2_data = intc2_irq_table,
+ .nr_irqs = ARRAY_SIZE(intc2_irq_table),
+
+ .chip = {
+ .name = "INTC2-se7780",
+ },
+};
+
/*
* Initialize IRQ setting
*/
void __init init_se7780_IRQ(void)
{
- int i ;
-
/* enable all interrupt at FPGA */
ctrl_outw(0, FPGA_INTMSK1);
/* mask SM501 interrupt */
@@ -79,11 +68,5 @@ void __init init_se7780_IRQ(void)
/* FPGA + 0x0A */
ctrl_outw((IRQPIN_PCCPW << IRQPOS_PCCPW), FPGA_INTSEL3);
- for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++) {
- disable_irq_nosync(intc2_irq_table[i].irq);
- set_irq_chip_and_handler_name( intc2_irq_table[i].irq, &se7780_irq_chip,
- handle_level_irq, "level");
- set_irq_chip_data( intc2_irq_table[i].irq, &intc2_irq_table[i] );
- disable_se7780_irq(intc2_irq_table[i].irq);
- }
+ register_intc2_controller(&intc2_irq_desc);
}
diff --git a/arch/sh/boards/se/7780/setup.c b/arch/sh/boards/se/7780/setup.c
index df7d08a24c9f..723f2fd4d55b 100644
--- a/arch/sh/boards/se/7780/setup.c
+++ b/arch/sh/boards/se/7780/setup.c
@@ -113,10 +113,9 @@ static void __init se7780_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_se7780 __initmv = {
+static struct sh_machine_vector mv_se7780 __initmv = {
.mv_name = "Solution Engine 7780" ,
.mv_setup = se7780_setup ,
.mv_nr_irqs = 111 ,
.mv_init_irq = init_se7780_IRQ,
};
-ALIAS_MV(se7780)
diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c
index c069c444b4ec..9c031a8c0a1c 100644
--- a/arch/sh/boards/sh03/setup.c
+++ b/arch/sh/boards/sh03/setup.c
@@ -15,17 +15,33 @@
#include <asm/sh03/sh03.h>
#include <asm/addrspace.h>
-static struct ipr_data sh03_ipr_map[] = {
- { IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY },
- { IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY },
- { IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY },
- { IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY },
+static struct ipr_data ipr_irq_table[] = {
+ { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY },
+ { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY },
+ { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY },
+ { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY },
+};
+
+static unsigned long ipr_offsets[] = {
+ INTC_IPRD,
+};
+
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-sh03",
+ },
};
static void __init init_sh03_IRQ(void)
{
ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
- make_ipr_irq(sh03_ipr_map, ARRAY_SIZE(sh03_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
extern void *cf_io_base;
@@ -74,11 +90,10 @@ static int __init sh03_devices_setup(void)
}
__initcall(sh03_devices_setup);
-struct sh_machine_vector mv_sh03 __initmv = {
+static struct sh_machine_vector mv_sh03 __initmv = {
.mv_name = "Interface (CTP/PCI-SH03)",
.mv_setup = sh03_setup,
.mv_nr_irqs = 48,
.mv_ioport_map = sh03_ioport_map,
.mv_init_irq = init_sh03_IRQ,
};
-ALIAS_MV(sh03)
diff --git a/arch/sh/boards/shmin/setup.c b/arch/sh/boards/shmin/setup.c
index 4a9df4a6b034..dfd124509f42 100644
--- a/arch/sh/boards/shmin/setup.c
+++ b/arch/sh/boards/shmin/setup.c
@@ -6,28 +6,44 @@
* SHMIN Support.
*/
#include <linux/init.h>
+#include <linux/irq.h>
#include <asm/machvec.h>
#include <asm/shmin.h>
#include <asm/clock.h>
-#include <asm/irq.h>
#include <asm/io.h>
#define PFC_PHCR 0xa400010eUL
#define INTC_ICR1 0xa4000010UL
#define INTC_IPRC 0xa4000016UL
-static struct ipr_data shmin_ipr_map[] = {
- { .irq=32, .addr=INTC_IPRC, .shift= 0, .priority=0 },
- { .irq=33, .addr=INTC_IPRC, .shift= 4, .priority=0 },
- { .irq=34, .addr=INTC_IPRC, .shift= 8, .priority=8 },
- { .irq=35, .addr=INTC_IPRC, .shift=12, .priority=0 },
+static struct ipr_data ipr_irq_table[] = {
+ { 32, 0, 0, 0 },
+ { 33, 0, 4, 0 },
+ { 34, 0, 8, 8 },
+ { 35, 0, 12, 0 },
+};
+
+static unsigned long ipr_offsets[] = {
+ INTC_IPRC,
+};
+
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-shmin",
+ },
};
static void __init init_shmin_irq(void)
{
ctrl_outw(0x2a00, PFC_PHCR); // IRQ0-3=IRQ
ctrl_outw(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active.
- make_ipr_irq(shmin_ipr_map, ARRAY_SIZE(shmin_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size)
@@ -43,9 +59,8 @@ static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size)
}
-struct sh_machine_vector mv_shmin __initmv = {
+static struct sh_machine_vector mv_shmin __initmv = {
.mv_name = "SHMIN",
.mv_init_irq = init_shmin_irq,
.mv_ioport_map = shmin_ioport_map,
};
-ALIAS_MV(shmin)
diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c
index 650fb3645947..84271d85a8dd 100644
--- a/arch/sh/boards/snapgear/setup.c
+++ b/arch/sh/boards/snapgear/setup.c
@@ -68,11 +68,27 @@ module_init(eraseconfig_init);
* IRL3 = crypto
*/
-static struct ipr_data snapgear_ipr_map[] = {
- make_ipr_irq(IRL0_IRQ, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY);
- make_ipr_irq(IRL1_IRQ, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY);
- make_ipr_irq(IRL2_IRQ, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY);
- make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
+static struct ipr_data ipr_irq_table[] = {
+ { IRL0_IRQ, 0, IRL0_IPR_POS, IRL0_PRIORITY },
+ { IRL1_IRQ, 0, IRL1_IPR_POS, IRL1_PRIORITY },
+ { IRL2_IRQ, 0, IRL2_IPR_POS, IRL2_PRIORITY },
+ { IRL3_IRQ, 0, IRL3_IPR_POS, IRL3_PRIORITY },
+};
+
+static unsigned long ipr_offsets[] = {
+ INTC_IPRD,
+};
+
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-snapgear",
+ },
};
static void __init init_snapgear_IRQ(void)
@@ -82,7 +98,7 @@ static void __init init_snapgear_IRQ(void)
printk("Setup SnapGear IRQ/IPR ...\n");
- make_ipr_irq(snapgear_ipr_map, ARRAY_SIZE(snapgear_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
/*
@@ -96,7 +112,7 @@ static void __init snapgear_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_snapgear __initmv = {
+static struct sh_machine_vector mv_snapgear __initmv = {
.mv_name = "SnapGear SecureEdge5410",
.mv_setup = snapgear_setup,
.mv_nr_irqs = 72,
@@ -117,4 +133,3 @@ struct sh_machine_vector mv_snapgear __initmv = {
.mv_init_irq = init_snapgear_IRQ,
};
-ALIAS_MV(snapgear)
diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c
index 6396cea1c896..fc8cd06d66cf 100644
--- a/arch/sh/boards/superh/microdev/setup.c
+++ b/arch/sh/boards/superh/microdev/setup.c
@@ -371,7 +371,7 @@ static void __init microdev_setup(char **cmdline_p)
/*
* The Machine Vector
*/
-struct sh_machine_vector mv_sh4202_microdev __initmv = {
+static struct sh_machine_vector mv_sh4202_microdev __initmv = {
.mv_name = "SH4-202 MicroDev",
.mv_setup = microdev_setup,
.mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */
@@ -403,4 +403,3 @@ struct sh_machine_vector mv_sh4202_microdev __initmv = {
.mv_heartbeat = microdev_heartbeat,
#endif
};
-ALIAS_MV(sh4202_microdev)
diff --git a/arch/sh/boards/titan/setup.c b/arch/sh/boards/titan/setup.c
index 6bcd939bfaed..606d25a4b870 100644
--- a/arch/sh/boards/titan/setup.c
+++ b/arch/sh/boards/titan/setup.c
@@ -12,7 +12,7 @@
#include <asm/titan.h>
#include <asm/io.h>
-static struct ipr_data titan_ipr_map[] = {
+static struct ipr_data ipr_irq_table[] = {
/* IRQ, IPR idx, shift, prio */
{ TITAN_IRQ_WAN, 3, 12, 8 }, /* eth0 (WAN) */
{ TITAN_IRQ_LAN, 3, 8, 8 }, /* eth1 (LAN) */
@@ -20,15 +20,33 @@ static struct ipr_data titan_ipr_map[] = {
{ TITAN_IRQ_USB, 3, 0, 8 }, /* mPCI B (bottom), USB */
};
+static unsigned long ipr_offsets[] = { /* stolen from setup-sh7750.c */
+ 0xffd00004UL, /* 0: IPRA */
+ 0xffd00008UL, /* 1: IPRB */
+ 0xffd0000cUL, /* 2: IPRC */
+ 0xffd00010UL, /* 3: IPRD */
+};
+
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-titan",
+ },
+};
static void __init init_titan_irq(void)
{
/* enable individual interrupt mode for externals */
ipr_irq_enable_irlm();
/* register ipr irqs */
- make_ipr_irq(titan_ipr_map, ARRAY_SIZE(titan_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
-struct sh_machine_vector mv_titan __initmv = {
+static struct sh_machine_vector mv_titan __initmv = {
.mv_name = "Titan",
.mv_inb = titan_inb,
@@ -52,4 +70,3 @@ struct sh_machine_vector mv_titan __initmv = {
.mv_init_irq = init_titan_irq,
};
-ALIAS_MV(titan)
diff --git a/arch/sh/boards/unknown/Makefile b/arch/sh/boards/unknown/Makefile
deleted file mode 100644
index 7d18f408b0c5..000000000000
--- a/arch/sh/boards/unknown/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for unknown SH boards
-#
-
-obj-y := setup.o
-
diff --git a/arch/sh/boards/unknown/setup.c b/arch/sh/boards/unknown/setup.c
deleted file mode 100644
index bee4612de59b..000000000000
--- a/arch/sh/boards/unknown/setup.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * linux/arch/sh/boards/unknown/setup.c
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Setup code for an unknown machine (internal peripherals only)
- *
- * This is the simplest of all boards, and serves only as a quick and dirty
- * method to start debugging a new board during bring-up until proper board
- * setup code is written.
- */
-#include <linux/init.h>
-#include <asm/machvec.h>
-
-struct sh_machine_vector mv_unknown __initmv = {
- .mv_name = "Unknown",
-};
-ALIAS_MV(unknown)
diff --git a/arch/sh/cchips/Kconfig b/arch/sh/cchips/Kconfig
index 0582ca8346b6..2e516e9a6ede 100644
--- a/arch/sh/cchips/Kconfig
+++ b/arch/sh/cchips/Kconfig
@@ -13,10 +13,8 @@ config VOYAGERGX
are additional GPIO bits that can be used to interface to
external as well.
-# A board must have defined HD6446X_SERIES in order to see these
config HD6446X_SERIES
- bool "HD6446x support"
- default n
+ bool
choice
prompt "HD6446x options"
@@ -25,7 +23,6 @@ choice
config HD64461
bool "Hitachi HD64461 companion chip support"
- depends on CPU_SUBTYPE_SH7709
---help---
The Hitachi HD64461 provides an interface for
the SH7709 CPU, supporting a LCD controller,
@@ -40,7 +37,6 @@ config HD64461
config HD64465
bool "Hitachi HD64465 companion chip support"
- depends on CPU_SUBTYPE_SH7750
---help---
The Hitachi HD64465 provides an interface for
the SH7750 CPU, supporting a LCD controller,
diff --git a/arch/sh/cchips/hd6446x/Makefile b/arch/sh/cchips/hd6446x/Makefile
new file mode 100644
index 000000000000..a106dd9db986
--- /dev/null
+++ b/arch/sh/cchips/hd6446x/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_HD64461) += hd64461.o
+obj-$(CONFIG_HD64465) += hd64465/
diff --git a/arch/sh/cchips/hd6446x/hd64461/setup.c b/arch/sh/cchips/hd6446x/hd64461.c
index 4d49b5cbcc13..97f6512aa1b7 100644
--- a/arch/sh/cchips/hd6446x/hd64461/setup.c
+++ b/arch/sh/cchips/hd6446x/hd64461.c
@@ -1,5 +1,4 @@
/*
- * $Id: setup.c,v 1.5 2004/03/16 00:07:50 lethal Exp $
* Copyright (C) 2000 YAEGASHI Takeshi
* Hitachi HD64461 companion chip support
*/
diff --git a/arch/sh/cchips/hd6446x/hd64461/Makefile b/arch/sh/cchips/hd6446x/hd64461/Makefile
deleted file mode 100644
index bff4b92e388c..000000000000
--- a/arch/sh/cchips/hd6446x/hd64461/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the HD64461
-#
-
-obj-y := setup.o io.o
-
diff --git a/arch/sh/cchips/hd6446x/hd64461/io.c b/arch/sh/cchips/hd6446x/hd64461/io.c
deleted file mode 100644
index 7909a1b7b512..000000000000
--- a/arch/sh/cchips/hd6446x/hd64461/io.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2000 YAEGASHI Takeshi
- * Typical I/O routines for HD64461 system.
- */
-
-#include <asm/io.h>
-#include <asm/hd64461.h>
-
-#define MEM_BASE (CONFIG_HD64461_IOBASE - HD64461_STBCR)
-
-static __inline__ unsigned long PORT2ADDR(unsigned long port)
-{
- /* 16550A: HD64461 internal */
- if (0x3f8<=port && port<=0x3ff)
- return CONFIG_HD64461_IOBASE + 0x8000 + ((port-0x3f8)<<1);
- if (0x2f8<=port && port<=0x2ff)
- return CONFIG_HD64461_IOBASE + 0x7000 + ((port-0x2f8)<<1);
-
-#ifdef CONFIG_HD64461_ENABLER
- /* NE2000: HD64461 PCMCIA channel 0 (I/O) */
- if (0x300<=port && port<=0x31f)
- return 0xba000000 + port;
-
- /* ide0: HD64461 PCMCIA channel 1 (memory) */
- /* On HP690, CF in slot 1 is configured as a memory card
- device. See CF+ and CompactFlash Specification for the
- detail of CF's memory mapped addressing. */
- if (0x1f0<=port && port<=0x1f7) return 0xb5000000 + port;
- if (port == 0x3f6) return 0xb50001fe;
- if (port == 0x3f7) return 0xb50001ff;
-
- /* ide1 */
- if (0x170<=port && port<=0x177) return 0xba000000 + port;
- if (port == 0x376) return 0xba000376;
- if (port == 0x377) return 0xba000377;
-#endif
-
- /* ??? */
- if (port < 0xf000) return 0xa0000000 + port;
- /* PCMCIA channel 0, I/O (0xba000000) */
- if (port < 0x10000) return 0xba000000 + port - 0xf000;
-
- /* HD64461 internal devices (0xb0000000) */
- if (port < 0x20000) return CONFIG_HD64461_IOBASE + port - 0x10000;
-
- /* PCMCIA channel 0, I/O (0xba000000) */
- if (port < 0x30000) return 0xba000000 + port - 0x20000;
-
- /* PCMCIA channel 1, memory (0xb5000000) */
- if (port < 0x40000) return 0xb5000000 + port - 0x30000;
-
- /* Whole physical address space (0xa0000000) */
- return 0xa0000000 + (port & 0x1fffffff);
-}
-
-unsigned char hd64461_inb(unsigned long port)
-{
- return *(volatile unsigned char*)PORT2ADDR(port);
-}
-
-unsigned char hd64461_inb_p(unsigned long port)
-{
- unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
- ctrl_delay();
- return v;
-}
-
-unsigned short hd64461_inw(unsigned long port)
-{
- return *(volatile unsigned short*)PORT2ADDR(port);
-}
-
-unsigned int hd64461_inl(unsigned long port)
-{
- return *(volatile unsigned long*)PORT2ADDR(port);
-}
-
-void hd64461_outb(unsigned char b, unsigned long port)
-{
- *(volatile unsigned char*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outb_p(unsigned char b, unsigned long port)
-{
- *(volatile unsigned char*)PORT2ADDR(port) = b;
- ctrl_delay();
-}
-
-void hd64461_outw(unsigned short b, unsigned long port)
-{
- *(volatile unsigned short*)PORT2ADDR(port) = b;
-}
-
-void hd64461_outl(unsigned int b, unsigned long port)
-{
- *(volatile unsigned long*)PORT2ADDR(port) = b;
-}
-
-void hd64461_insb(unsigned long port, void *buffer, unsigned long count)
-{
- volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
- unsigned char *buf=buffer;
- while(count--) *buf++=*addr;
-}
-
-void hd64461_insw(unsigned long port, void *buffer, unsigned long count)
-{
- volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
- unsigned short *buf=buffer;
- while(count--) *buf++=*addr;
-}
-
-void hd64461_insl(unsigned long port, void *buffer, unsigned long count)
-{
- volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
- unsigned long *buf=buffer;
- while(count--) *buf++=*addr;
-}
-
-void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count)
-{
- volatile unsigned char* addr=(volatile unsigned char*)PORT2ADDR(port);
- const unsigned char *buf=buffer;
- while(count--) *addr=*buf++;
-}
-
-void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count)
-{
- volatile unsigned short* addr=(volatile unsigned short*)PORT2ADDR(port);
- const unsigned short *buf=buffer;
- while(count--) *addr=*buf++;
-}
-
-void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count)
-{
- volatile unsigned long* addr=(volatile unsigned long*)PORT2ADDR(port);
- const unsigned long *buf=buffer;
- while(count--) *addr=*buf++;
-}
-
-unsigned short hd64461_readw(void __iomem *addr)
-{
- return ctrl_inw(MEM_BASE+(unsigned long __force)addr);
-}
-
-void hd64461_writew(unsigned short b, void __iomem *addr)
-{
- ctrl_outw(b, MEM_BASE+(unsigned long __force)addr);
-}
-
diff --git a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
index 8b6b5a779de8..3fdd270eecf7 100644
--- a/arch/sh/configs/dreamcast_defconfig
+++ b/arch/sh/configs/dreamcast_defconfig
@@ -1,15 +1,23 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Tue Oct 3 10:51:55 2006
+# Linux kernel version: 2.6.22-rc4
+# Sat Jul 7 03:47:45 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PCI=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -28,6 +36,7 @@ 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=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
@@ -35,8 +44,10 @@ CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -50,14 +61,19 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
#
# Loadable module support
@@ -93,44 +109,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# System type
#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-CONFIG_SH_DREAMCAST=y
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
CONFIG_CPU_SH4=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-
-#
-# SH-3 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
@@ -138,79 +119,93 @@ CONFIG_CPU_SH4=y
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
-CONFIG_CPU_SUBTYPE_SH7750=y
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
CONFIG_CPU_SUBTYPE_SH7091=y
-CONFIG_CPU_SUBTYPE_SH7750R=y
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
# CONFIG_CPU_SUBTYPE_SH7750S is not set
# CONFIG_CPU_SUBTYPE_SH7751 is not set
# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x01000000
CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
#
# Processor features
#
CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_SH_FPU=y
# CONFIG_SH_DSP is not set
CONFIG_SH_STORE_QUEUES=y
CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_IPR_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
+CONFIG_CPU_HAS_PTEA=y
#
-# Timer support
+# Board support
+#
+CONFIG_SH_DREAMCAST=y
+
+#
+# Timer and clock configuration
#
CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
CONFIG_SH_PCLK_FREQ=49876504
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
#
# CPU Frequency scaling
@@ -232,6 +227,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
#
# DMA support
#
+CONFIG_SH_DMA_API=y
CONFIG_SH_DMA=y
CONFIG_NR_ONCHIP_DMA_CHANNELS=4
CONFIG_NR_DMA_CHANNELS_BOOL=y
@@ -240,17 +236,23 @@ CONFIG_NR_DMA_CHANNELS=9
#
# Companion Chips
#
-# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+# CONFIG_PUSH_SWITCH is not set
#
# Kernel features
#
# 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_KEXEC is not set
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
@@ -269,33 +271,23 @@ CONFIG_CMDLINE="console=ttySC1,115200 panic=3"
# Bus options
#
CONFIG_PCI=y
-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
+CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
-# CONFIG_PCI_MULTITHREAD_PROBE is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
#
# PCCARD (PCMCIA/CardBus) support
#
# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
# Networking
#
CONFIG_NET=y
@@ -303,13 +295,13 @@ 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 is not set
@@ -327,30 +319,20 @@ CONFIG_IP_FIB_HASH=y
# 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
@@ -376,7 +358,16 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
#
# Device Drivers
@@ -394,10 +385,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -408,6 +395,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -421,13 +409,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
#
-# ATA/ATAPI/MFM/RLL support
+# Misc devices
#
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_BLINK is not set
# CONFIG_IDE is not set
#
@@ -436,10 +427,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# 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
#
@@ -455,6 +442,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
#
@@ -470,15 +458,7 @@ CONFIG_NETDEVICES=y
# 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 is not set
#
@@ -521,47 +501,16 @@ CONFIG_8139TOO=y
# CONFIG_SUNDANCE is not set
# CONFIG_TLAN is not set
# CONFIG_VIA_RHINE is not set
-
-#
-# 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_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-# CONFIG_QLA3XXX is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-# CONFIG_MYRI10GE is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_SC92031 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
+# Wireless LAN
#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -604,17 +553,19 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_KEYBOARD_SUNKBD is not set
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_PS2 is not set
# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -660,10 +611,6 @@ CONFIG_LEGACY_PTY_COUNT=256
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -680,14 +627,8 @@ CONFIG_SH_WDT=y
# CONFIG_PCIPCWATCHDOG is not set
# CONFIG_WDTPCI is not set
CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -695,11 +636,7 @@ CONFIG_HW_RANDOM=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -711,44 +648,51 @@ CONFIG_HW_RANDOM=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
+# CONFIG_HWMON 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_VT1211 is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Misc devices
+# Multifunction device drivers
#
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Graphics support
+# Display device support
#
-CONFIG_FIRMWARE_EDID=y
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
# CONFIG_FB_CYBER2000 is not set
@@ -763,13 +707,17 @@ CONFIG_FB_PVR2=y
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
# CONFIG_FB_SAVAGE is not set
# CONFIG_FB_SIS is not set
# CONFIG_FB_NEOMAGIC is not set
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -789,10 +737,6 @@ CONFIG_FONT_8x16=y
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
# CONFIG_FONT_10x18 is not set
-
-#
-# Logo configuration
-#
CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
@@ -800,7 +744,6 @@ CONFIG_LOGO=y
# CONFIG_LOGO_SUPERH_MONO is not set
# CONFIG_LOGO_SUPERH_VGA16 is not set
CONFIG_LOGO_SUPERH_CLUT224=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -808,6 +751,12 @@ CONFIG_LOGO_SUPERH_CLUT224=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -823,10 +772,6 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -874,10 +819,12 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -957,6 +904,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
CONFIG_PROFILING=y
@@ -965,17 +917,18 @@ CONFIG_PROFILING=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# 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_DEBUG_FS is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
-# CONFIG_KGDB is not set
+# CONFIG_SH_KGDB is not set
#
# Security options
@@ -991,8 +944,13 @@ CONFIG_LOG_BUF_SHIFT=14
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
index e7f8ddb0ada4..07310fa03250 100644
--- a/arch/sh/configs/landisk_defconfig
+++ b/arch/sh/configs/landisk_defconfig
@@ -217,7 +217,7 @@ CONFIG_SH_FPU=y
# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
diff --git a/arch/sh/configs/lboxre2_defconfig b/arch/sh/configs/lboxre2_defconfig
index be86414dcc87..fa09d68d057a 100644
--- a/arch/sh/configs/lboxre2_defconfig
+++ b/arch/sh/configs/lboxre2_defconfig
@@ -222,7 +222,7 @@ CONFIG_SH_FPU=y
# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
diff --git a/arch/sh/configs/r7780mp_defconfig b/arch/sh/configs/r7780mp_defconfig
new file mode 100644
index 000000000000..ac4de4973b60
--- /dev/null
+++ b/arch/sh/configs/r7780mp_defconfig
@@ -0,0 +1,1223 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22-rc4
+# Mon Jun 11 10:24:57 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=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=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+CONFIG_ANON_INODES=y
+# CONFIG_EPOLL is not set
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# 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 is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+CONFIG_CPU_SUBTYPE_SH7780=y
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+# CONFIG_32BIT is not set
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB 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=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_SPECULATIVE_EXECUTION=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Board support
+#
+# CONFIG_SH_7780_SOLUTION_ENGINE is not set
+CONFIG_SH_HIGHLANDER=y
+# CONFIG_SH_R7780RP is not set
+CONFIG_SH_R7780MP=y
+# CONFIG_SH_R7785RP is not set
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=28
+CONFIG_SH_PCLK_FREQ=32000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Additional SuperH Device Drivers
+#
+# CONFIG_HEARTBEAT is not set
+CONFIG_PUSH_SWITCH=y
+
+#
+# Kernel features
+#
+# 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_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/sda1"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE 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_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
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+# 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_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 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=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# Misc devices
+#
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_BLINK is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+# CONFIG_PCNET32_NAPI is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+# CONFIG_VIA_RHINE_NAPI is not set
+# CONFIG_SC92031 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=m
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=y
+# CONFIG_R8169_NAPI is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# 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_NET_FC 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=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# 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=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW 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_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# 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
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_OSS_OBSOLETE is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN 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
+# 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_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# 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=y
+# 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=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# 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_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=m
+
+#
+# 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 is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+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 is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=m
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_FRAME_POINTER is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+# CONFIG_SH_KGDB 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_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_HMAC=y
+# 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=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD 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
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig
index 48c6a2194c98..12cc01910cf8 100644
--- a/arch/sh/configs/r7780rp_defconfig
+++ b/arch/sh/configs/r7780rp_defconfig
@@ -241,7 +241,7 @@ CONFIG_SH_FPU=y
CONFIG_SH_STORE_QUEUES=y
CONFIG_SPECULATIVE_EXECUTION=y
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
#
diff --git a/arch/sh/configs/r7785rp_defconfig b/arch/sh/configs/r7785rp_defconfig
index 0f5ec649daf8..5c29338532da 100644
--- a/arch/sh/configs/r7785rp_defconfig
+++ b/arch/sh/configs/r7785rp_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc3
-# Mon Mar 12 14:26:33 2007
+# Linux kernel version: 2.6.22-rc4
+# Thu Jul 12 12:33:15 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -11,7 +11,9 @@ CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_PCI=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
@@ -43,6 +45,7 @@ CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_SYSFS_DEPRECATED is not set
# CONFIG_RELAY is not set
# CONFIG_BLK_DEV_INITRD is not set
@@ -60,13 +63,18 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
+CONFIG_ANON_INODES=y
# CONFIG_EPOLL is not set
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
#
# Loadable module support
@@ -102,55 +110,11 @@ CONFIG_DEFAULT_IOSCHED="noop"
#
# System type
#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-CONFIG_SH_HIGHLANDER=y
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_7206_SOLUTION_ENGINE is not set
-# CONFIG_SH_7619_SOLUTION_ENGINE is not set
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_R7780MP is not set
-CONFIG_SH_R7785RP=y
-
-#
-# Processor selection
-#
CONFIG_CPU_SH4=y
CONFIG_CPU_SH4A=y
CONFIG_CPU_SHX2=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
# CONFIG_CPU_SUBTYPE_SH7619 is not set
-
-#
-# SH-2A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7206 is not set
-
-#
-# SH-3 Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
@@ -158,10 +122,7 @@ CONFIG_CPU_SHX2=y
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -170,23 +131,12 @@ CONFIG_CPU_SHX2=y
# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
CONFIG_CPU_SUBTYPE_SH7785=y
-
-#
-# SH4AL-DSP Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SHX3 is not set
# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
# CONFIG_CPU_SUBTYPE_SH7722 is not set
@@ -194,6 +144,7 @@ CONFIG_CPU_SUBTYPE_SH7785=y
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x08000000
@@ -201,6 +152,12 @@ CONFIG_MEMORY_SIZE=0x08000000
CONFIG_32BIT=y
# CONFIG_X2TLB is not set
CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -215,17 +172,17 @@ CONFIG_FLATMEM_MANUAL=y
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
#
# Processor features
@@ -241,12 +198,22 @@ CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
#
+# Board support
+#
+CONFIG_SH_HIGHLANDER=y
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_R7780MP is not set
+CONFIG_SH_R7785RP=y
+
+#
# Timer and clock configuration
#
CONFIG_SH_TMU=y
CONFIG_SH_TIMER_IRQ=28
-CONFIG_NO_IDLE_HZ=y
CONFIG_SH_PCLK_FREQ=50000000
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
#
# CPU Frequency scaling
@@ -261,7 +228,6 @@ CONFIG_SH_PCLK_FREQ=50000000
#
# Companion Chips
#
-# CONFIG_HD6446X_SERIES is not set
#
# Additional SuperH Device Drivers
@@ -278,7 +244,7 @@ CONFIG_HZ_250=y
# CONFIG_HZ_1000 is not set
CONFIG_HZ=250
CONFIG_KEXEC=y
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
@@ -300,31 +266,22 @@ CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
#
# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
# Networking
#
CONFIG_NET=y
@@ -332,7 +289,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -377,20 +333,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
CONFIG_BRIDGE=m
@@ -417,8 +361,16 @@ CONFIG_LLC=m
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
CONFIG_WIRELESS_EXT=y
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
#
# Device Drivers
@@ -438,10 +390,6 @@ CONFIG_FW_LOADER=m
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -475,12 +423,10 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# Misc devices
#
+# CONFIG_PHANTOM is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+# CONFIG_BLINK is not set
# CONFIG_IDE is not set
#
@@ -509,6 +455,7 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -554,10 +501,6 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
# CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
# CONFIG_SATA_AHCI is not set
@@ -580,6 +523,7 @@ CONFIG_SATA_SIL=y
# CONFIG_PATA_AMD is not set
# CONFIG_PATA_ARTOP is not set
# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
# CONFIG_PATA_CMD64X is not set
# CONFIG_PATA_CS5520 is not set
# CONFIG_PATA_CS5530 is not set
@@ -629,6 +573,7 @@ CONFIG_PATA_PLATFORM=y
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
#
@@ -644,15 +589,7 @@ CONFIG_NETDEVICES=y
# 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 is not set
#
@@ -673,10 +610,7 @@ CONFIG_MII=y
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
# CONFIG_NET_PCI is not set
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
# CONFIG_E1000 is not set
@@ -689,55 +623,26 @@ CONFIG_R8169=y
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-# CONFIG_NET_WIRELESS_RTNETLINK is not set
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_IPW2100 is not set
-# CONFIG_IPW2200 is not set
-# CONFIG_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
-#
-# CONFIG_PRISM54 is not set
-# CONFIG_HOSTAP is not set
-CONFIG_NET_WIRELESS=y
-
-#
-# Wan interfaces
+# Wireless LAN
#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
@@ -789,6 +694,7 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -831,14 +737,8 @@ CONFIG_LEGACY_PTY_COUNT=256
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_DRM is not set
@@ -848,10 +748,7 @@ CONFIG_HW_RANDOM=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -864,16 +761,15 @@ CONFIG_HW_RANDOM=y
# 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_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -885,22 +781,30 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_DAB is not set
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Graphics support
+# Display device support
#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
# CONFIG_FB_CFB_FILLRECT is not set
# CONFIG_FB_CFB_COPYAREA is not set
# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
@@ -908,7 +812,7 @@ CONFIG_FB=y
# CONFIG_FB_TILEBLITTING is not set
#
-# Frambuffer hardware drivers
+# Frame buffer hardware drivers
#
# CONFIG_FB_CIRRUS is not set
# CONFIG_FB_PM2 is not set
@@ -930,12 +834,11 @@ CONFIG_FB=y
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
# CONFIG_FB_VIRTUAL is not set
-
-#
-# Logo configuration
-#
# CONFIG_LOGO is not set
#
@@ -952,13 +855,10 @@ CONFIG_SOUND=m
# Open Sound System
#
CONFIG_SOUND_PRIME=m
-# CONFIG_OBSOLETE_OSS is not set
-# CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_ICH is not set
+# CONFIG_OSS_OBSOLETE is not set
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
#
# HID Devices
@@ -982,10 +882,6 @@ CONFIG_USB_ARCH_HAS_EHCI=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -1026,18 +922,30 @@ CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
#
-# RTC drivers
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
#
# CONFIG_RTC_DRV_DS1553 is not set
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_M48T86 is not set
-CONFIG_RTC_DRV_SH=y
-# CONFIG_RTC_DRV_TEST is not set
# CONFIG_RTC_DRV_V3020 is not set
#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
# DMA Engine support
#
# CONFIG_DMA_ENGINE is not set
@@ -1051,14 +959,6 @@ CONFIG_RTC_DRV_SH=y
#
#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
-#
-
-#
# File systems
#
CONFIG_EXT2_FS=y
@@ -1157,6 +1057,7 @@ CONFIG_EXPORTFS=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -1239,7 +1140,6 @@ CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DETECT_SOFTLOCKUP is not set
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
@@ -1266,6 +1166,7 @@ CONFIG_FORCED_INLINING=y
CONFIG_SH_STANDARD_BIOS=y
# CONFIG_EARLY_SCIF_CONSOLE is not set
CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
CONFIG_DEBUG_STACKOVERFLOW=y
CONFIG_DEBUG_STACK_USAGE=y
# CONFIG_4KSTACKS is not set
@@ -1300,6 +1201,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_BLOWFISH is not set
@@ -1328,7 +1230,9 @@ CONFIG_CRYPTO_DES=y
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig
index a59bb78bd071..f1e979b1e495 100644
--- a/arch/sh/configs/rts7751r2d_defconfig
+++ b/arch/sh/configs/rts7751r2d_defconfig
@@ -155,7 +155,7 @@ CONFIG_CPU_SH4=y
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
# CONFIG_CPU_SUBTYPE_SH7750S is not set
-CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
CONFIG_CPU_SUBTYPE_SH7751R=y
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
@@ -218,7 +218,7 @@ CONFIG_SH_FPU=y
# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
@@ -280,7 +280,7 @@ CONFIG_ZERO_PAGE_OFFSET=0x00010000
CONFIG_BOOT_LINK_OFFSET=0x00800000
# CONFIG_UBC_WAKEUP is not set
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1"
+CONFIG_CMDLINE="console=tty0 console=ttySC0,115200 root=/dev/sda1 earlyprintk=bios"
#
# Bus options
@@ -1323,7 +1323,7 @@ CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_SH_STANDARD_BIOS=y
CONFIG_EARLY_SCIF_CONSOLE=y
CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000
CONFIG_EARLY_PRINTK=y
diff --git a/arch/sh/configs/se7206_defconfig b/arch/sh/configs/se7206_defconfig
index 87ab9080fd1d..f2f2a3c9c32d 100644
--- a/arch/sh/configs/se7206_defconfig
+++ b/arch/sh/configs/se7206_defconfig
@@ -1,18 +1,22 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19
-# Wed Dec 6 14:40:15 2006
+# Linux kernel version: 2.6.22-rc4
+# Fri Jun 15 19:37:46 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -34,8 +38,10 @@ CONFIG_LOCALVERSION=""
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -48,12 +54,17 @@ CONFIG_BUG=y
# CONFIG_ELF_CORE is not set
# CONFIG_BASE_FULL is not set
# CONFIG_FUTEX is not set
+CONFIG_ANON_INODES=y
# CONFIG_EPOLL is not set
-CONFIG_SLAB=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_TINY_SHMEM=y
CONFIG_BASE_SMALL=1
-# CONFIG_SLOB is not set
#
# Loadable module support
@@ -83,53 +94,10 @@ CONFIG_DEFAULT_IOSCHED="noop"
#
# System type
#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-CONFIG_SH_7206_SOLUTION_ENGINE=y
-# CONFIG_SH_7619_SOLUTION_ENGINE is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
CONFIG_CPU_SH2=y
CONFIG_CPU_SH2A=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
# CONFIG_CPU_SUBTYPE_SH7619 is not set
-
-#
-# SH-2A Processor Support
-#
CONFIG_CPU_SUBTYPE_SH7206=y
-
-#
-# SH-3 Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
@@ -137,10 +105,7 @@ CONFIG_CPU_SUBTYPE_SH7206=y
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -149,32 +114,28 @@ CONFIG_CPU_SUBTYPE_SH7206=y
# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
# CONFIG_CPU_SUBTYPE_SH7785 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_PAGE_OFFSET=0x00000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -184,35 +145,42 @@ CONFIG_FLATMEM_MANUAL=y
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
#
# Processor features
#
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_CPU_BIG_ENDIAN=y
-# CONFIG_SH_FPU is not set
# CONFIG_SH_FPU_EMU is not set
# CONFIG_SH_DSP is not set
+CONFIG_CPU_HAS_IPR_IRQ=y
+
+#
+# Board support
+#
+CONFIG_SOLUTION_ENGINE=y
+CONFIG_SH_7206_SOLUTION_ENGINE=y
#
-# Timer support
+# Timer and clock configuration
#
CONFIG_SH_CMT=y
# CONFIG_SH_MTU2 is not set
CONFIG_SH_TIMER_IRQ=140
-# CONFIG_NO_IDLE_HZ is not set
CONFIG_SH_PCLK_FREQ=33333333
CONFIG_SH_CLK_MD=6
+# CONFIG_TICK_ONESHOT is not set
#
# CPU Frequency scaling
@@ -227,11 +195,11 @@ CONFIG_SH_CLK_MD=6
#
# Companion Chips
#
-# CONFIG_HD6446X_SERIES is not set
#
# Additional SuperH Device Drivers
#
+# CONFIG_HEARTBEAT is not set
# CONFIG_PUSH_SWITCH is not set
#
@@ -239,10 +207,11 @@ CONFIG_SH_CLK_MD=6
#
CONFIG_HZ_100=y
# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
# CONFIG_KEXEC is not set
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
@@ -252,23 +221,18 @@ CONFIG_PREEMPT_NONE=y
#
CONFIG_ZERO_PAGE_OFFSET=0x00001000
CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_UBC_WAKEUP is not set
# CONFIG_CMDLINE_BOOL is not set
#
# Bus options
#
-# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
#
# PCCARD (PCMCIA/CardBus) support
#
#
-# PCI Hotplug Support
-#
-
-#
# Executable file formats
#
CONFIG_BINFMT_FLAT=y
@@ -277,11 +241,6 @@ CONFIG_BINFMT_ZFLAT=y
# CONFIG_BINFMT_MISC is not set
#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
# Networking
#
CONFIG_NET=y
@@ -289,7 +248,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
# CONFIG_PACKET is not set
# CONFIG_UNIX is not set
# CONFIG_NET_KEY is not set
@@ -314,25 +272,14 @@ CONFIG_IP_FIB_HASH=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
@@ -358,7 +305,16 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
#
# Device Drivers
@@ -375,10 +331,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
@@ -393,6 +345,7 @@ CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
@@ -424,7 +377,6 @@ CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
@@ -452,16 +404,13 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
#
-# OneNAND Flash Device Drivers
+# UBI - Unsorted block images
#
-# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_UBI is not set
#
# Parallel port support
@@ -471,6 +420,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -479,18 +429,13 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
#
# Misc devices
#
-# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+# CONFIG_BLINK is not set
# CONFIG_IDE is not set
#
@@ -499,10 +444,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
# 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
#
@@ -511,19 +452,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=4
# CONFIG_MD is not set
#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
# Network device support
#
CONFIG_NETDEVICES=y
@@ -531,10 +459,6 @@ CONFIG_NETDEVICES=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# PHY device support
-#
# CONFIG_PHYLIB is not set
#
@@ -544,27 +468,14 @@ CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_STNIC is not set
CONFIG_SMC91X=y
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
+# Wireless LAN
#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
@@ -604,6 +515,7 @@ CONFIG_INPUT=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -639,29 +551,15 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM 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_RAW_DRIVER is not set
#
# TPM devices
#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
# CONFIG_I2C is not set
#
@@ -674,27 +572,30 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
#
-# Hardware Monitoring support
+# Multifunction device drivers
#
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Graphics support
+# Display device support
#
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
# CONFIG_FB is not set
#
@@ -703,6 +604,12 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
# USB support
#
# CONFIG_USB_ARCH_HAS_HCD is not set
@@ -717,10 +624,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -802,7 +705,6 @@ CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
# CONFIG_SYSFS is not set
# CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
@@ -816,7 +718,6 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
@@ -849,6 +750,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -861,14 +767,11 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS 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_UNWIND_INFO is not set
-# CONFIG_HEADERS_CHECK is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
-# CONFIG_KGDB is not set
#
# Security options
@@ -883,8 +786,13 @@ CONFIG_LOG_BUF_SHIFT=14
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/se7619_defconfig b/arch/sh/configs/se7619_defconfig
index 20ac7f4c53fb..3a3c3c1f507d 100644
--- a/arch/sh/configs/se7619_defconfig
+++ b/arch/sh/configs/se7619_defconfig
@@ -1,18 +1,22 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.19
-# Wed Dec 6 16:35:36 2006
+# Linux kernel version: 2.6.22-rc4
+# Fri Jun 15 19:43:06 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
# CONFIG_GENERIC_TIME is not set
+# CONFIG_GENERIC_CLOCKEVENTS is not set
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -31,8 +35,10 @@ CONFIG_LOCALVERSION=""
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_UTS_NS is not set
# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
-CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -45,12 +51,17 @@ CONFIG_BUG=y
# CONFIG_ELF_CORE is not set
# CONFIG_BASE_FULL is not set
# CONFIG_FUTEX is not set
+CONFIG_ANON_INODES=y
# CONFIG_EPOLL is not set
-CONFIG_SLAB=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_TINY_SHMEM=y
CONFIG_BASE_SMALL=1
-# CONFIG_SLOB is not set
#
# Loadable module support
@@ -80,52 +91,9 @@ CONFIG_DEFAULT_IOSCHED="noop"
#
# System type
#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_R7780RP is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_7206_SOLUTION_ENGINE is not set
-CONFIG_SH_7619_SOLUTION_ENGINE=y
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
CONFIG_CPU_SH2=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
CONFIG_CPU_SUBTYPE_SH7619=y
-
-#
-# SH-2A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7206 is not set
-
-#
-# SH-3 Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
@@ -133,10 +101,7 @@ CONFIG_CPU_SUBTYPE_SH7619=y
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
-
-#
-# SH-4 Processor Support
-#
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -145,32 +110,28 @@ CONFIG_CPU_SUBTYPE_SH7619=y
# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
# CONFIG_CPU_SUBTYPE_SH7785 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_PAGE_OFFSET=0x00000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -180,34 +141,41 @@ CONFIG_FLATMEM_MANUAL=y
# CONFIG_SPARSEMEM_MANUAL is not set
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_STATIC=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
CONFIG_SH_WRITETHROUGH=y
-# CONFIG_SH_OCRAM is not set
#
# Processor features
#
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_CPU_BIG_ENDIAN=y
-# CONFIG_SH_FPU is not set
# CONFIG_SH_FPU_EMU is not set
# CONFIG_SH_DSP is not set
+CONFIG_CPU_HAS_IPR_IRQ=y
+
+#
+# Board support
+#
+CONFIG_SOLUTION_ENGINE=y
+CONFIG_SH_7619_SOLUTION_ENGINE=y
#
-# Timer support
+# Timer and clock configuration
#
CONFIG_SH_CMT=y
CONFIG_SH_TIMER_IRQ=86
-# CONFIG_NO_IDLE_HZ is not set
CONFIG_SH_PCLK_FREQ=31250000
CONFIG_SH_CLK_MD=5
+# CONFIG_TICK_ONESHOT is not set
#
# CPU Frequency scaling
@@ -222,11 +190,11 @@ CONFIG_SH_CLK_MD=5
#
# Companion Chips
#
-# CONFIG_HD6446X_SERIES is not set
#
# Additional SuperH Device Drivers
#
+# CONFIG_HEARTBEAT is not set
# CONFIG_PUSH_SWITCH is not set
#
@@ -234,10 +202,11 @@ CONFIG_SH_CLK_MD=5
#
CONFIG_HZ_100=y
# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
# CONFIG_KEXEC is not set
-# CONFIG_SMP is not set
+# CONFIG_CRASH_DUMP is not set
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
@@ -247,23 +216,18 @@ CONFIG_PREEMPT_NONE=y
#
CONFIG_ZERO_PAGE_OFFSET=0x00001000
CONFIG_BOOT_LINK_OFFSET=0x00800000
-# CONFIG_UBC_WAKEUP is not set
# CONFIG_CMDLINE_BOOL is not set
#
# Bus options
#
-# CONFIG_PCI is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
#
# PCCARD (PCMCIA/CardBus) support
#
#
-# PCI Hotplug Support
-#
-
-#
# Executable file formats
#
CONFIG_BINFMT_FLAT=y
@@ -272,11 +236,6 @@ CONFIG_BINFMT_ZFLAT=y
# CONFIG_BINFMT_MISC is not set
#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
# Networking
#
# CONFIG_NET is not set
@@ -295,10 +254,6 @@ CONFIG_BINFMT_ZFLAT=y
#
# Connector - unified userspace <-> kernelspace linker
#
-
-#
-# Memory Technology Devices (MTD)
-#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
CONFIG_MTD_CONCAT=y
@@ -313,6 +268,7 @@ CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
@@ -344,7 +300,6 @@ CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
@@ -372,16 +327,13 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MTD_DOC2000 is not set
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
#
-# OneNAND Flash Device Drivers
+# UBI - Unsorted block images
#
-# CONFIG_MTD_ONENAND is not set
+# CONFIG_MTD_UBI is not set
#
# Parallel port support
@@ -391,6 +343,7 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -398,17 +351,12 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
# Misc devices
#
-# CONFIG_TIFM_CORE is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+# CONFIG_BLINK is not set
# CONFIG_IDE is not set
#
@@ -417,10 +365,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# 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
#
@@ -429,19 +373,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MD is not set
#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
# ISDN subsystem
#
@@ -471,6 +402,7 @@ CONFIG_INPUT=y
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -506,29 +438,15 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM 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_RAW_DRIVER is not set
#
# TPM devices
#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
# CONFIG_I2C is not set
#
@@ -541,26 +459,29 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
#
-# Hardware Monitoring support
+# Multifunction device drivers
#
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_DAB=y
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Graphics support
+# Display device support
#
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
# CONFIG_FB is not set
#
@@ -569,6 +490,12 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SOUND is not set
#
+# HID Devices
+#
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
# USB support
#
# CONFIG_USB_ARCH_HAS_HCD is not set
@@ -583,10 +510,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -668,7 +591,6 @@ CONFIG_PROC_FS=y
CONFIG_PROC_SYSCTL=y
# CONFIG_SYSFS is not set
# CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
@@ -682,7 +604,6 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
@@ -715,14 +636,11 @@ CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS 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_UNWIND_INFO is not set
-# CONFIG_HEADERS_CHECK is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
-# CONFIG_KGDB is not set
#
# Security options
@@ -737,8 +655,13 @@ CONFIG_LOG_BUF_SHIFT=14
#
# Library routines
#
+CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/se7722_defconfig b/arch/sh/configs/se7722_defconfig
index ca4c663dfa37..8e6a6baf5d27 100644
--- a/arch/sh/configs/se7722_defconfig
+++ b/arch/sh/configs/se7722_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc7
-# Fri Apr 27 16:30:30 2007
+# Linux kernel version: 2.6.22-rc4
+# Wed Jun 20 18:08:04 2007
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
@@ -11,7 +11,9 @@ CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-# CONFIG_GENERIC_TIME is not set
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_SYS_SUPPORTS_NUMA=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_LOCKDEP_SUPPORT=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
@@ -43,6 +45,7 @@ CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
# CONFIG_SYSFS_DEPRECATED is not set
# CONFIG_RELAY is not set
CONFIG_BLK_DEV_INITRD=y
@@ -60,14 +63,20 @@ CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
#
# Loadable module support
@@ -103,57 +112,12 @@ CONFIG_DEFAULT_IOSCHED="noop"
#
# System type
#
-CONFIG_SOLUTION_ENGINE=y
-# CONFIG_SH_SOLUTION_ENGINE is not set
-CONFIG_SH_7722_SOLUTION_ENGINE=y
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7780_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_7343_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_7710VOIPGW is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_HIGHLANDER is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_LANDISK is not set
-# CONFIG_SH_TITAN is not set
-# CONFIG_SH_SHMIN is not set
-# CONFIG_SH_7206_SOLUTION_ENGINE is not set
-# CONFIG_SH_7619_SOLUTION_ENGINE is not set
-# CONFIG_SH_LBOX_RE2 is not set
-# CONFIG_SH_UNKNOWN is not set
-
-#
-# Processor selection
-#
CONFIG_CPU_SH4=y
CONFIG_CPU_SH4A=y
CONFIG_CPU_SH4AL_DSP=y
CONFIG_CPU_SHX2=y
-
-#
-# SH-2 Processor Support
-#
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
# CONFIG_CPU_SUBTYPE_SH7619 is not set
-
-#
-# SH-2A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7206 is not set
-
-#
-# SH-3 Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
# CONFIG_CPU_SUBTYPE_SH7706 is not set
@@ -162,10 +126,6 @@ CONFIG_CPU_SHX2=y
# CONFIG_CPU_SUBTYPE_SH7709 is not set
# CONFIG_CPU_SUBTYPE_SH7710 is not set
# CONFIG_CPU_SUBTYPE_SH7712 is not set
-
-#
-# SH-4 Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
# CONFIG_CPU_SUBTYPE_SH7091 is not set
# CONFIG_CPU_SUBTYPE_SH7750R is not set
@@ -174,23 +134,11 @@ CONFIG_CPU_SHX2=y
# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-
-#
-# ST40 Processor Support
-#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-
-#
-# SH-4A Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
# CONFIG_CPU_SUBTYPE_SH7785 is not set
-
-#
-# SH4AL-DSP Processor Support
-#
# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7343 is not set
CONFIG_CPU_SUBTYPE_SH7722=y
@@ -198,15 +146,21 @@ CONFIG_CPU_SUBTYPE_SH7722=y
#
# Memory management options
#
+CONFIG_QUICKLIST=y
CONFIG_MMU=y
CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
-# CONFIG_32BIT is not set
# CONFIG_X2TLB is not set
CONFIG_VSYSCALL=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=1
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=2
CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
@@ -216,26 +170,25 @@ CONFIG_HUGETLB_PAGE_SIZE_64K=y
# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
# CONFIG_HUGETLB_PAGE_SIZE_64MB is not set
CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_STATIC=y
+# CONFIG_MEMORY_HOTPLUG is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-CONFIG_CF_ENABLER=y
-# CONFIG_CF_AREA5 is not set
-CONFIG_CF_AREA6=y
-CONFIG_CF_BASE_ADDR=0xb8000000
#
# Processor features
@@ -247,17 +200,25 @@ CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SH_DSP=y
CONFIG_SH_STORE_QUEUES=y
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
#
+# Board support
+#
+CONFIG_SOLUTION_ENGINE=y
+CONFIG_SH_7722_SOLUTION_ENGINE=y
+
+#
# Timer and clock configuration
#
CONFIG_SH_TMU=y
CONFIG_SH_TIMER_IRQ=16
-CONFIG_NO_IDLE_HZ=y
CONFIG_SH_PCLK_FREQ=33333333
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
#
# CPU Frequency scaling
@@ -272,7 +233,6 @@ CONFIG_SH_PCLK_FREQ=33333333
#
# Companion Chips
#
-# CONFIG_HD6446X_SERIES is not set
#
# Additional SuperH Device Drivers
@@ -290,7 +250,6 @@ CONFIG_HZ_250=y
CONFIG_HZ=250
CONFIG_KEXEC=y
# CONFIG_CRASH_DUMP is not set
-# CONFIG_SMP is not set
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
@@ -307,7 +266,11 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000
#
# Bus options
#
-# CONFIG_PCI is not set
+CONFIG_CF_ENABLER=y
+# CONFIG_CF_AREA5 is not set
+CONFIG_CF_AREA6=y
+CONFIG_CF_BASE_ADDR=0xb8000000
+# CONFIG_ARCH_SUPPORTS_MSI is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -315,22 +278,12 @@ CONFIG_BOOT_LINK_OFFSET=0x00800000
# CONFIG_PCCARD is not set
#
-# PCI Hotplug Support
-#
-
-#
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
#
-# Power management options (EXPERIMENTAL)
-#
-# CONFIG_PM is not set
-
-#
# Networking
#
CONFIG_NET=y
@@ -338,7 +291,6 @@ CONFIG_NET=y
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
@@ -375,20 +327,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -414,7 +354,16 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
#
# Device Drivers
@@ -432,10 +381,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -464,10 +409,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# Misc devices
#
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+# CONFIG_BLINK is not set
# CONFIG_IDE is not set
#
@@ -496,6 +438,7 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_CONSTANTS is not set
# CONFIG_SCSI_LOGGING is not set
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -511,10 +454,6 @@ CONFIG_BLK_DEV_SD=y
#
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_DEBUG is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
CONFIG_PATA_PLATFORM=y
@@ -525,19 +464,6 @@ CONFIG_PATA_PLATFORM=y
# CONFIG_MD is not set
#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
# Network device support
#
CONFIG_NETDEVICES=y
@@ -545,10 +471,6 @@ CONFIG_NETDEVICES=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# PHY device support
-#
# CONFIG_PHYLIB is not set
#
@@ -558,27 +480,14 @@ CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_STNIC is not set
CONFIG_SMC91X=y
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
+# Wireless LAN
#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
@@ -627,6 +536,7 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
@@ -655,7 +565,7 @@ CONFIG_SERIO_LIBPS2=y
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_NR_UARTS=3
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
@@ -667,14 +577,8 @@ CONFIG_LEGACY_PTY_COUNT=256
# IPMI
#
# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
@@ -682,10 +586,6 @@ CONFIG_HW_RANDOM=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
# CONFIG_I2C is not set
#
@@ -698,16 +598,15 @@ CONFIG_HW_RANDOM=y
# 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_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83627HF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -719,16 +618,19 @@ CONFIG_HWMON=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
#
-# Digital Video Broadcasting Devices
+# Graphics support
#
-# CONFIG_DVB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Graphics support
+# Display device support
#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
# CONFIG_FB is not set
#
@@ -757,10 +659,6 @@ CONFIG_HID=y
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -800,18 +698,30 @@ CONFIG_RTC_INTF_SYSFS=y
CONFIG_RTC_INTF_PROC=y
CONFIG_RTC_INTF_DEV=y
# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
#
-# RTC drivers
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
#
# CONFIG_RTC_DRV_DS1553 is not set
# CONFIG_RTC_DRV_DS1742 is not set
# CONFIG_RTC_DRV_M48T86 is not set
-CONFIG_RTC_DRV_SH=y
-# CONFIG_RTC_DRV_TEST is not set
# CONFIG_RTC_DRV_V3020 is not set
#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
# DMA Engine support
#
# CONFIG_DMA_ENGINE is not set
@@ -825,14 +735,6 @@ CONFIG_RTC_DRV_SH=y
#
#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
-#
-
-#
# File systems
#
CONFIG_EXT2_FS=y
@@ -937,23 +839,24 @@ CONFIG_MSDOS_PARTITION=y
#
# Profiling support
#
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
#
# Kernel hacking
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_MUST_CHECK is not set
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
+CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_SH_STANDARD_BIOS=y
# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_EARLY_PRINTK is not set
# CONFIG_SH_KGDB is not set
#
@@ -973,8 +876,10 @@ CONFIG_LOG_BUF_SHIFT=14
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig
index 4e6e77fa4ce7..c60b6fd4fc42 100644
--- a/arch/sh/configs/se7750_defconfig
+++ b/arch/sh/configs/se7750_defconfig
@@ -226,7 +226,7 @@ CONFIG_SH_FPU=y
# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
CONFIG_CPU_HAS_INTEVT=y
-CONFIG_CPU_HAS_IPR_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
CONFIG_CPU_HAS_PTEA=y
diff --git a/arch/sh/configs/se7780_defconfig b/arch/sh/configs/se7780_defconfig
index 538661e98793..f68743dc3931 100644
--- a/arch/sh/configs/se7780_defconfig
+++ b/arch/sh/configs/se7780_defconfig
@@ -218,6 +218,7 @@ CONFIG_SH_FPU=y
# CONFIG_SH_STORE_QUEUES is not set
CONFIG_CPU_HAS_INTEVT=y
CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_INTC_IRQ=y
CONFIG_CPU_HAS_SR_RB=y
#
diff --git a/arch/sh/configs/shx3_defconfig b/arch/sh/configs/shx3_defconfig
new file mode 100644
index 000000000000..219bad558b10
--- /dev/null
+++ b/arch/sh/configs/shx3_defconfig
@@ -0,0 +1,756 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.22-rc4
+# Wed Jun 20 14:09:27 2007
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=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_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_UTS_NS is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# 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 is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SHX3=y
+# CONFIG_CPU_SUBTYPE_SH7619 is not set
+# CONFIG_CPU_SUBTYPE_SH7206 is not set
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+# CONFIG_CPU_SUBTYPE_SH7712 is not set
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+# CONFIG_CPU_SUBTYPE_SH7785 is not set
+CONFIG_CPU_SUBTYPE_SHX3=y
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+# CONFIG_CPU_SUBTYPE_SH7722 is not set
+
+#
+# Memory management options
+#
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_VSYSCALL=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_MAX_ACTIVE_REGIONS=1
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_256K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64MB 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=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=2
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+# CONFIG_SH_FPU is not set
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Board support
+#
+
+#
+# Timer and clock configuration
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_TIMER_IRQ=16
+CONFIG_SH_PCLK_FREQ=50000000
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+
+#
+# Additional SuperH Device Drivers
+#
+CONFIG_HEARTBEAT=y
+# CONFIG_PUSH_SWITCH is not set
+
+#
+# Kernel features
+#
+# 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_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,115200 ip=192.168.1.2:::255.255.255.0 root=/dev/nfs nfsroot=192.168.1.1:/exports/devel/rfs/mobiler noaliencache earlyprintk=bios ignore_loglevel"
+
+#
+# Bus options
+#
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Networking
+#
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# 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_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# Misc devices
+#
+# CONFIG_BLINK is not set
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_PATA_PLATFORM=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# ISDN subsystem
+#
+
+#
+# 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=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# 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=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW 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_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# 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
+# CONFIG_HWMON is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+# CONFIG_HID is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SH=y
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# 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 is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_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_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+# CONFIG_OPROFILE is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+CONFIG_DEBUG_PREEMPT=y
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+# CONFIG_PROVE_LOCKING is not set
+CONFIG_LOCKDEP=y
+CONFIG_DEBUG_LOCKDEP=y
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+CONFIG_EARLY_PRINTK=y
+# CONFIG_DEBUG_BOOTMEM is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_STACK_USAGE=y
+# CONFIG_4KSTACKS is not set
+# CONFIG_SH_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index 99935f9daf4b..ee711431e504 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -5,12 +5,13 @@ config SH_DMA_API
config SH_DMA
bool "SuperH on-chip DMA controller (DMAC) support"
+ depends on CPU_SH3 || CPU_SH4
select SH_DMA_API
default n
config NR_ONCHIP_DMA_CHANNELS
+ int
depends on SH_DMA
- int "Number of on-chip DMAC channels"
default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
default "12" if CPU_SUBTYPE_SH7780
default "4"
@@ -36,23 +37,6 @@ config NR_DMA_CHANNELS
support. Setting this to a higher value allows for cascading DMACs
with additional channels.
-config DMA_PAGE_OPS
- bool "Use DMAC for page copy/clear"
- depends on SH_DMA && BROKEN
- help
- Selecting this option will use a dual-address mode configured channel
- in the SH DMAC for copy_page()/clear_page(). Primarily a performance
- hack.
-
-config DMA_PAGE_OPS_CHANNEL
- depends on DMA_PAGE_OPS
- int "DMA channel for sh memory-manager page copy/clear"
- default "3"
- help
- This allows the specification of the dual address dma channel,
- in case channel 3 is unavailable. On the SH4, channels 1,2, and 3
- are dual-address capable.
-
config SH_DMABRG
bool "SH7760 DMABRG support"
depends on CPU_SUBTYPE_SH7760
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c
index 23dd6080422f..10c1828c9ff5 100644
--- a/arch/sh/drivers/heartbeat.c
+++ b/arch/sh/drivers/heartbeat.c
@@ -78,7 +78,7 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
hd->bit_pos[i] = i;
}
- hd->base = (void __iomem *)res->start;
+ hd->base = (void __iomem *)(unsigned long)res->start;
setup_timer(&hd->timer, heartbeat_timer, (unsigned long)hd);
platform_set_drvdata(pdev, hd);
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig
index 6d1cbbe6745c..fbc6f2c8649f 100644
--- a/arch/sh/drivers/pci/Kconfig
+++ b/arch/sh/drivers/pci/Kconfig
@@ -1,5 +1,6 @@
config PCI
bool "PCI support"
+ depends on SYS_SUPPORTS_PCI
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
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 0e9b532b9fbc..2f65ac72f48a 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_PCI_AUTO) += pci-auto.o
obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += pci-st40.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += pci-sh7751.o ops-sh4.o
obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o
obj-$(CONFIG_CPU_SUBTYPE_SH7785) += pci-sh7780.o ops-sh4.o
diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
index 54232f13e406..710a3b0306e5 100644
--- a/arch/sh/drivers/pci/ops-sh4.c
+++ b/arch/sh/drivers/pci/ops-sh4.c
@@ -153,7 +153,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
{
if (!strcmp(str, "off")) {
pci_probe = 0;
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
index 543417ff8314..1502a14386b6 100644
--- a/arch/sh/drivers/pci/pci-st40.c
+++ b/arch/sh/drivers/pci/pci-st40.c
@@ -328,7 +328,7 @@ int __init st40pci_init(unsigned memStart, unsigned memSize)
return 1;
}
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
{
return str;
}
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index d439336d2e18..ccaba368ac9b 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -71,7 +71,7 @@ subsys_initcall(pcibios_init);
* Called after each bus is probed, but before its children
* are examined.
*/
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
pci_read_bridge_bases(bus);
}
diff --git a/arch/sh/drivers/push-switch.c b/arch/sh/drivers/push-switch.c
index b3d20c0e021f..725be6de589b 100644
--- a/arch/sh/drivers/push-switch.c
+++ b/arch/sh/drivers/push-switch.c
@@ -138,4 +138,4 @@ module_exit(switch_exit);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR("Paul Mundt");
-MODULE_LICENSE("GPLv2");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 9104b6257644..1f141a8ba17c 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -4,10 +4,9 @@
extra-y := head.o init_task.o vmlinux.lds
-obj-y := process.o signal.o traps.o irq.o \
- ptrace.o setup.o time.o sys_sh.o semaphore.o \
- io.o io_generic.o sh_ksyms.o syscalls.o \
- debugtraps.o
+obj-y := debugtraps.o io.o io_generic.o irq.o machvec.o process.o ptrace.o \
+ semaphore.o setup.o signal.o sys_sh.o syscalls.o \
+ time.o topology.o traps.o
obj-y += cpu/ timers/
obj-$(CONFIG_VSYSCALL) += vsyscall/
@@ -17,7 +16,7 @@ obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
obj-$(CONFIG_SH_KGDB) += kgdb_stub.o kgdb_jmp.o
obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
-obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_MODULES) += sh_ksyms.o module.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
index ebc73b85094a..1c3b99642e1c 100644
--- a/arch/sh/kernel/cf-enabler.c
+++ b/arch/sh/kernel/cf-enabler.c
@@ -75,11 +75,7 @@ static int __init cf_init_default(void)
#if defined(CONFIG_CPU_SH4)
allocate_cf_area();
#endif
-#if defined(CONFIG_SH_UNKNOWN)
- /* This should be done in each board's init_xxx_irq. */
- make_imask_irq(14);
- disable_irq(14);
-#endif
+
return 0;
}
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 63251549e9a8..92807ffa8e20 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -229,6 +229,22 @@ void clk_recalc_rate(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_recalc_rate);
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (likely(clk->ops && clk->ops->round_rate)) {
+ unsigned long flags, rounded;
+
+ spin_lock_irqsave(&clock_lock, flags);
+ rounded = clk->ops->round_rate(clk, rate);
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ return rounded;
+ }
+
+ return clk_get_rate(clk);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
/*
* Returns a clock. Note that we first try to use device id on the bus
* and clock name. If this fails, we try to use clock name only.
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 6451ad630174..9172e97dc26a 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -21,8 +21,7 @@
#include <asm/cacheflush.h>
#include <asm/cache.h>
#include <asm/io.h>
-
-extern void detect_cpu_and_cache_system(void);
+#include <asm/ubc.h>
/*
* Generic wrapper for command line arguments to disable on-chip
@@ -152,15 +151,6 @@ static void __init cache_init(void)
flags |= CCR_CACHE_CB;
#endif
-#ifdef CONFIG_SH_OCRAM
- /* Turn on OCRAM -- halve the OC */
- flags |= CCR_CACHE_ORA;
- current_cpu_data.dcache.sets >>= 1;
-
- current_cpu_data.dcache.way_size = current_cpu_data.dcache.sets *
- current_cpu_data.dcache.linesz;
-#endif
-
ctrl_outl(flags, CCR);
back_to_P1();
}
@@ -269,7 +259,6 @@ asmlinkage void __init sh_cpu_init(void)
}
#endif
-#ifdef CONFIG_UBC_WAKEUP
/*
* Some brain-damaged loaders decided it would be a good idea to put
* the UBC to sleep. This causes some issues when it comes to things
@@ -277,7 +266,5 @@ asmlinkage void __init sh_cpu_init(void)
* we wake it up and hope that all is well.
*/
ubc_wakeup();
-#endif
-
speculative_execution_init();
}
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index 1c23308cfc25..9ddb446ac930 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -6,4 +6,5 @@ obj-y += imask.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
+obj-$(CONFIG_CPU_HAS_INTC_IRQ) += intc.o
obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc.c b/arch/sh/kernel/cpu/irq/intc.c
new file mode 100644
index 000000000000..9345a7130e9e
--- /dev/null
+++ b/arch/sh/kernel/cpu/irq/intc.c
@@ -0,0 +1,405 @@
+/*
+ * Shared interrupt handling code for IPR and INTC2 types of IRQs.
+ *
+ * Copyright (C) 2007 Magnus Damm
+ *
+ * Based on intc2.c and ipr.c
+ *
+ * Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2005, 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#define _INTC_MK(fn, idx, bit, value) \
+ ((fn) << 24 | ((value) << 16) | ((idx) << 8) | (bit))
+#define _INTC_FN(h) (h >> 24)
+#define _INTC_VALUE(h) ((h >> 16) & 0xff)
+#define _INTC_IDX(h) ((h >> 8) & 0xff)
+#define _INTC_BIT(h) (h & 0xff)
+
+#define _INTC_PTR(desc, member, data) \
+ (desc->member + _INTC_IDX(data))
+
+static inline struct intc_desc *get_intc_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+ return (void *)((char *)chip - offsetof(struct intc_desc, chip));
+}
+
+static inline unsigned int set_field(unsigned int value,
+ unsigned int field_value,
+ unsigned int width,
+ unsigned int shift)
+{
+ value &= ~(((1 << width) - 1) << shift);
+ value |= field_value << shift;
+ return value;
+}
+
+static inline unsigned int set_prio_field(struct intc_desc *desc,
+ unsigned int value,
+ unsigned int priority,
+ unsigned int data)
+{
+ unsigned int width = _INTC_PTR(desc, prio_regs, data)->field_width;
+
+ return set_field(value, priority, width, _INTC_BIT(data));
+}
+
+static void disable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+ unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+ ctrl_outw(set_prio_field(desc, ctrl_inw(addr), 0, data), addr);
+}
+
+static void enable_prio_16(struct intc_desc *desc, unsigned int data)
+{
+ unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+ unsigned int prio = _INTC_VALUE(data);
+
+ ctrl_outw(set_prio_field(desc, ctrl_inw(addr), prio, data), addr);
+}
+
+static void disable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+ unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+
+ ctrl_outl(set_prio_field(desc, ctrl_inl(addr), 0, data), addr);
+}
+
+static void enable_prio_32(struct intc_desc *desc, unsigned int data)
+{
+ unsigned long addr = _INTC_PTR(desc, prio_regs, data)->reg;
+ unsigned int prio = _INTC_VALUE(data);
+
+ ctrl_outl(set_prio_field(desc, ctrl_inl(addr), prio, data), addr);
+}
+
+static void disable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+ ctrl_outb(1 << _INTC_BIT(data),
+ _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_8(struct intc_desc *desc, unsigned int data)
+{
+ ctrl_outb(1 << _INTC_BIT(data),
+ _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+static void disable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+ ctrl_outl(1 << _INTC_BIT(data),
+ _INTC_PTR(desc, mask_regs, data)->set_reg);
+}
+
+static void enable_mask_32(struct intc_desc *desc, unsigned int data)
+{
+ ctrl_outl(1 << _INTC_BIT(data),
+ _INTC_PTR(desc, mask_regs, data)->clr_reg);
+}
+
+enum { REG_FN_ERROR=0,
+ REG_FN_MASK_8, REG_FN_MASK_32,
+ REG_FN_PRIO_16, REG_FN_PRIO_32 };
+
+static struct {
+ void (*enable)(struct intc_desc *, unsigned int);
+ void (*disable)(struct intc_desc *, unsigned int);
+} intc_reg_fns[] = {
+ [REG_FN_MASK_8] = { enable_mask_8, disable_mask_8 },
+ [REG_FN_MASK_32] = { enable_mask_32, disable_mask_32 },
+ [REG_FN_PRIO_16] = { enable_prio_16, disable_prio_16 },
+ [REG_FN_PRIO_32] = { enable_prio_32, disable_prio_32 },
+};
+
+static void intc_enable(unsigned int irq)
+{
+ struct intc_desc *desc = get_intc_desc(irq);
+ unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+ intc_reg_fns[_INTC_FN(data)].enable(desc, data);
+}
+
+static void intc_disable(unsigned int irq)
+{
+ struct intc_desc *desc = get_intc_desc(irq);
+ unsigned int data = (unsigned int) get_irq_chip_data(irq);
+
+ intc_reg_fns[_INTC_FN(data)].disable(desc, data);
+}
+
+static void set_sense_16(struct intc_desc *desc, unsigned int data)
+{
+ unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+ unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+ unsigned int bit = _INTC_BIT(data);
+ unsigned int value = _INTC_VALUE(data);
+
+ ctrl_outw(set_field(ctrl_inw(addr), value, width, bit), addr);
+}
+
+static void set_sense_32(struct intc_desc *desc, unsigned int data)
+{
+ unsigned long addr = _INTC_PTR(desc, sense_regs, data)->reg;
+ unsigned int width = _INTC_PTR(desc, sense_regs, data)->field_width;
+ unsigned int bit = _INTC_BIT(data);
+ unsigned int value = _INTC_VALUE(data);
+
+ ctrl_outl(set_field(ctrl_inl(addr), value, width, bit), addr);
+}
+
+#define VALID(x) (x | 0x80)
+
+static unsigned char intc_irq_sense_table[IRQ_TYPE_SENSE_MASK + 1] = {
+ [IRQ_TYPE_EDGE_FALLING] = VALID(0),
+ [IRQ_TYPE_EDGE_RISING] = VALID(1),
+ [IRQ_TYPE_LEVEL_LOW] = VALID(2),
+ [IRQ_TYPE_LEVEL_HIGH] = VALID(3),
+};
+
+static int intc_set_sense(unsigned int irq, unsigned int type)
+{
+ struct intc_desc *desc = get_intc_desc(irq);
+ unsigned char value = intc_irq_sense_table[type & IRQ_TYPE_SENSE_MASK];
+ unsigned int i, j, data, bit;
+ intc_enum enum_id = 0;
+
+ for (i = 0; i < desc->nr_vectors; i++) {
+ struct intc_vect *vect = desc->vectors + i;
+
+ if (evt2irq(vect->vect) != irq)
+ continue;
+
+ enum_id = vect->enum_id;
+ break;
+ }
+
+ if (!enum_id || !value)
+ return -EINVAL;
+
+ value ^= VALID(0);
+
+ for (i = 0; i < desc->nr_sense_regs; i++) {
+ struct intc_sense_reg *sr = desc->sense_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(sr->enum_ids); j++) {
+ if (sr->enum_ids[j] != enum_id)
+ continue;
+
+ bit = sr->reg_width - ((j + 1) * sr->field_width);
+ data = _INTC_MK(0, i, bit, value);
+
+ switch(sr->reg_width) {
+ case 16:
+ set_sense_16(desc, data);
+ break;
+ case 32:
+ set_sense_32(desc, data);
+ break;
+ }
+
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static unsigned int __init intc_find_mask_handler(unsigned int width)
+{
+ switch (width) {
+ case 8:
+ return REG_FN_MASK_8;
+ case 32:
+ return REG_FN_MASK_32;
+ }
+
+ BUG();
+ return REG_FN_ERROR;
+}
+
+static unsigned int __init intc_find_prio_handler(unsigned int width)
+{
+ switch (width) {
+ case 16:
+ return REG_FN_PRIO_16;
+ case 32:
+ return REG_FN_PRIO_32;
+ }
+
+ BUG();
+ return REG_FN_ERROR;
+}
+
+static intc_enum __init intc_grp_id(struct intc_desc *desc, intc_enum enum_id)
+{
+ struct intc_group *g = desc->groups;
+ unsigned int i, j;
+
+ for (i = 0; g && enum_id && i < desc->nr_groups; i++) {
+ g = desc->groups + i;
+
+ for (j = 0; g->enum_ids[j]; j++) {
+ if (g->enum_ids[j] != enum_id)
+ continue;
+
+ return g->enum_id;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int __init intc_prio_value(struct intc_desc *desc,
+ intc_enum enum_id, int do_grps)
+{
+ struct intc_prio *p = desc->priorities;
+ unsigned int i;
+
+ for (i = 0; p && enum_id && i < desc->nr_priorities; i++) {
+ p = desc->priorities + i;
+
+ if (p->enum_id != enum_id)
+ continue;
+
+ return p->priority;
+ }
+
+ if (do_grps)
+ return intc_prio_value(desc, intc_grp_id(desc, enum_id), 0);
+
+ /* default to the lowest priority possible if no priority is set
+ * - this needs to be at least 2 for 5-bit priorities on 7780
+ */
+
+ return 2;
+}
+
+static unsigned int __init intc_mask_data(struct intc_desc *desc,
+ intc_enum enum_id, int do_grps)
+{
+ struct intc_mask_reg *mr = desc->mask_regs;
+ unsigned int i, j, fn;
+
+ for (i = 0; mr && enum_id && i < desc->nr_mask_regs; i++) {
+ mr = desc->mask_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(mr->enum_ids); j++) {
+ if (mr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = intc_find_mask_handler(mr->reg_width);
+ if (fn == REG_FN_ERROR)
+ return 0;
+
+ return _INTC_MK(fn, i, (mr->reg_width - 1) - j, 0);
+ }
+ }
+
+ if (do_grps)
+ return intc_mask_data(desc, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+static unsigned int __init intc_prio_data(struct intc_desc *desc,
+ intc_enum enum_id, int do_grps)
+{
+ struct intc_prio_reg *pr = desc->prio_regs;
+ unsigned int i, j, fn, bit, prio;
+
+ for (i = 0; pr && enum_id && i < desc->nr_prio_regs; i++) {
+ pr = desc->prio_regs + i;
+
+ for (j = 0; j < ARRAY_SIZE(pr->enum_ids); j++) {
+ if (pr->enum_ids[j] != enum_id)
+ continue;
+
+ fn = intc_find_prio_handler(pr->reg_width);
+ if (fn == REG_FN_ERROR)
+ return 0;
+
+ prio = intc_prio_value(desc, enum_id, 1);
+ bit = pr->reg_width - ((j + 1) * pr->field_width);
+
+ BUG_ON(bit < 0);
+
+ return _INTC_MK(fn, i, bit, prio);
+ }
+ }
+
+ if (do_grps)
+ return intc_prio_data(desc, intc_grp_id(desc, enum_id), 0);
+
+ return 0;
+}
+
+static void __init intc_register_irq(struct intc_desc *desc, intc_enum enum_id,
+ unsigned int irq)
+{
+ unsigned int data[2], primary;
+
+ /* Prefer single interrupt source bitmap over other combinations:
+ * 1. bitmap, single interrupt source
+ * 2. priority, single interrupt source
+ * 3. bitmap, multiple interrupt sources (groups)
+ * 4. priority, multiple interrupt sources (groups)
+ */
+
+ data[0] = intc_mask_data(desc, enum_id, 0);
+ data[1] = intc_prio_data(desc, enum_id, 0);
+
+ primary = 0;
+ if (!data[0] && data[1])
+ primary = 1;
+
+ data[0] = data[0] ? data[0] : intc_mask_data(desc, enum_id, 1);
+ data[1] = data[1] ? data[1] : intc_prio_data(desc, enum_id, 1);
+
+ if (!data[primary])
+ primary ^= 1;
+
+ BUG_ON(!data[primary]); /* must have primary masking method */
+
+ disable_irq_nosync(irq);
+ set_irq_chip_and_handler_name(irq, &desc->chip,
+ handle_level_irq, "level");
+ set_irq_chip_data(irq, (void *)data[primary]);
+
+ /* enable secondary masking method if present */
+ if (data[!primary])
+ intc_reg_fns[_INTC_FN(data[!primary])].enable(desc,
+ data[!primary]);
+
+ /* irq should be disabled by default */
+ desc->chip.mask(irq);
+}
+
+void __init register_intc_controller(struct intc_desc *desc)
+{
+ unsigned int i;
+
+ desc->chip.mask = intc_disable;
+ desc->chip.unmask = intc_enable;
+ desc->chip.mask_ack = intc_disable;
+ desc->chip.set_type = intc_set_sense;
+
+ for (i = 0; i < desc->nr_vectors; i++) {
+ struct intc_vect *vect = desc->vectors + i;
+
+ intc_register_irq(desc, vect->enum_id, evt2irq(vect->vect));
+ }
+}
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index d8e22f4ff0f0..cc5221390e09 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -13,36 +13,31 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <asm/smp.h>
-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
-#define INTC2_BASE 0xfe080000
-#define INTC2_INTMSK (INTC2_BASE + 0x40)
-#define INTC2_INTMSKCLR (INTC2_BASE + 0x60)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785)
-#define INTC2_BASE 0xffd40000
-#define INTC2_INTMSK (INTC2_BASE + 0x38)
-#define INTC2_INTMSKCLR (INTC2_BASE + 0x3c)
-#endif
+static inline struct intc2_desc *get_intc2_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+ return (void *)((char *)chip - offsetof(struct intc2_desc, chip));
+}
static void disable_intc2_irq(unsigned int irq)
{
struct intc2_data *p = get_irq_chip_data(irq);
- ctrl_outl(1 << p->msk_shift, INTC2_INTMSK + p->msk_offset);
+ struct intc2_desc *d = get_intc2_desc(irq);
+
+ ctrl_outl(1 << p->msk_shift, d->msk_base + p->msk_offset +
+ (hard_smp_processor_id() * 4));
}
static void enable_intc2_irq(unsigned int irq)
{
struct intc2_data *p = get_irq_chip_data(irq);
- ctrl_outl(1 << p->msk_shift, INTC2_INTMSKCLR + p->msk_offset);
-}
+ struct intc2_desc *d = get_intc2_desc(irq);
-static struct irq_chip intc2_irq_chip = {
- .name = "INTC2",
- .mask = disable_intc2_irq,
- .unmask = enable_intc2_irq,
- .mask_ack = disable_intc2_irq,
-};
+ ctrl_outl(1 << p->msk_shift, d->mskclr_base + p->msk_offset +
+ (hard_smp_processor_id() * 4));
+}
/*
* Setup an INTC2 style interrupt.
@@ -56,30 +51,36 @@ static struct irq_chip intc2_irq_chip = {
*
* in the intc2_data table.
*/
-void make_intc2_irq(struct intc2_data *table, unsigned int nr_irqs)
+void register_intc2_controller(struct intc2_desc *desc)
{
int i;
- for (i = 0; i < nr_irqs; i++) {
+ desc->chip.mask = disable_intc2_irq;
+ desc->chip.unmask = enable_intc2_irq;
+ desc->chip.mask_ack = disable_intc2_irq;
+
+ for (i = 0; i < desc->nr_irqs; i++) {
unsigned long ipr, flags;
- struct intc2_data *p = table + i;
+ struct intc2_data *p = desc->intc2_data + i;
disable_irq_nosync(p->irq);
- /* Set the priority level */
- local_irq_save(flags);
+ if (desc->prio_base) {
+ /* Set the priority level */
+ local_irq_save(flags);
- ipr = ctrl_inl(INTC2_BASE + p->ipr_offset);
- ipr &= ~(0xf << p->ipr_shift);
- ipr |= p->priority << p->ipr_shift;
- ctrl_outl(ipr, INTC2_BASE + p->ipr_offset);
+ ipr = ctrl_inl(desc->prio_base + p->ipr_offset);
+ ipr &= ~(0xf << p->ipr_shift);
+ ipr |= p->priority << p->ipr_shift;
+ ctrl_outl(ipr, desc->prio_base + p->ipr_offset);
- local_irq_restore(flags);
+ local_irq_restore(flags);
+ }
- set_irq_chip_and_handler_name(p->irq, &intc2_irq_chip,
+ set_irq_chip_and_handler_name(p->irq, &desc->chip,
handle_level_irq, "level");
set_irq_chip_data(p->irq, p);
- enable_intc2_irq(p->irq);
+ disable_intc2_irq(p->irq);
}
}
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 210280b6fddf..98e84f40c713 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -22,58 +22,57 @@
#include <linux/io.h>
#include <linux/interrupt.h>
+static inline struct ipr_desc *get_ipr_desc(unsigned int irq)
+{
+ struct irq_chip *chip = get_irq_chip(irq);
+ return (void *)((char *)chip - offsetof(struct ipr_desc, chip));
+}
+
static void disable_ipr_irq(unsigned int irq)
{
struct ipr_data *p = get_irq_chip_data(irq);
+ unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
/* Set the priority in IPR to 0 */
- ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr);
+ ctrl_outw(ctrl_inw(addr) & (0xffff ^ (0xf << p->shift)), addr);
}
static void enable_ipr_irq(unsigned int irq)
{
struct ipr_data *p = get_irq_chip_data(irq);
+ unsigned long addr = get_ipr_desc(irq)->ipr_offsets[p->ipr_idx];
/* Set priority in IPR back to original value */
- ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr);
+ ctrl_outw(ctrl_inw(addr) | (p->priority << p->shift), addr);
}
-static struct irq_chip ipr_irq_chip = {
- .name = "IPR",
- .mask = disable_ipr_irq,
- .unmask = enable_ipr_irq,
- .mask_ack = disable_ipr_irq,
-};
-
-unsigned int map_ipridx_to_addr(int idx) __attribute__ ((weak));
-unsigned int map_ipridx_to_addr(int idx)
-{
- return 0;
-}
+/*
+ * The shift value is now the number of bits to shift, not the number of
+ * bits/4. This is to make it easier to read the value directly from the
+ * datasheets. The IPR address is calculated using the ipr_offset table.
+ */
-void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs)
+void register_ipr_controller(struct ipr_desc *desc)
{
int i;
- for (i = 0; i < nr_irqs; i++) {
- unsigned int irq = table[i].irq;
+ desc->chip.mask = disable_ipr_irq;
+ desc->chip.unmask = enable_ipr_irq;
+ desc->chip.mask_ack = disable_ipr_irq;
- if (!irq)
- irq = table[i].irq = i;
+ for (i = 0; i < desc->nr_irqs; i++) {
+ struct ipr_data *p = desc->ipr_data + i;
- /* could the IPR index be mapped, if not we ignore this */
- if (!table[i].addr) {
- table[i].addr = map_ipridx_to_addr(table[i].ipr_idx);
- if (!table[i].addr)
- continue;
- }
+ BUG_ON(p->ipr_idx >= desc->nr_offsets);
+ BUG_ON(!desc->ipr_offsets[p->ipr_idx]);
- disable_irq_nosync(irq);
- set_irq_chip_and_handler_name(irq, &ipr_irq_chip,
+ disable_irq_nosync(p->irq);
+ set_irq_chip_and_handler_name(p->irq, &desc->chip,
handle_level_irq, "level");
- set_irq_chip_data(irq, &table[i]);
- enable_ipr_irq(irq);
+ set_irq_chip_data(p->irq, p);
+ disable_ipr_irq(p->irq);
}
}
-EXPORT_SYMBOL(make_ipr_irq);
+
+EXPORT_SYMBOL(register_ipr_controller);
#if !defined(CONFIG_CPU_HAS_PINT_IRQ)
int ipr_irq_demux(int irq)
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S
index c16dc8fec489..ee8f1fe84b08 100644
--- a/arch/sh/kernel/cpu/sh2/entry.S
+++ b/arch/sh/kernel/cpu/sh2/entry.S
@@ -311,6 +311,7 @@ restore_all:
rte
nop
+ .align 2
#ifdef CONFIG_TRACE_IRQFLAGS
1: .long trace_hardirqs_off
#endif
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c
index 108e81b682ed..abbf17427e52 100644
--- a/arch/sh/kernel/cpu/sh2/probe.c
+++ b/arch/sh/kernel/cpu/sh2/probe.c
@@ -9,23 +9,14 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-
-
#include <linux/init.h>
+#include <linux/smp.h>
#include <asm/processor.h>
#include <asm/cache.h>
int __init detect_cpu_and_cache_system(void)
{
-#if defined(CONFIG_CPU_SUBTYPE_SH7604)
- current_cpu_data.type = CPU_SH7604;
- current_cpu_data.dcache.ways = 4;
- current_cpu_data.dcache.way_incr = (1<<10);
- current_cpu_data.dcache.sets = 64;
- current_cpu_data.dcache.entry_shift = 4;
- current_cpu_data.dcache.linesz = L1_CACHE_BYTES;
- current_cpu_data.dcache.flags = 0;
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+#if defined(CONFIG_CPU_SUBTYPE_SH7619)
current_cpu_data.type = CPU_SH7619;
current_cpu_data.dcache.ways = 4;
current_cpu_data.dcache.way_incr = (1<<12);
diff --git a/arch/sh/kernel/cpu/sh2/setup-sh7619.c b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
index f83ff8a68f35..a979b981e6a3 100644
--- a/arch/sh/kernel/cpu/sh2/setup-sh7619.c
+++ b/arch/sh/kernel/cpu/sh2/setup-sh7619.c
@@ -52,7 +52,7 @@ static int __init sh7619_devices_setup(void)
}
__initcall(sh7619_devices_setup);
-static struct ipr_data sh7619_ipr_map[] = {
+static struct ipr_data ipr_irq_table[] = {
{ 86, 0, 4, 2 }, /* CMI0 */
{ 88, 1, 12, 3 }, /* SCIF0_ERI */
{ 89, 1, 12, 3 }, /* SCIF0_RXI */
@@ -68,7 +68,7 @@ static struct ipr_data sh7619_ipr_map[] = {
{ 99, 1, 4, 3 }, /* SCIF2_TXI */
};
-static unsigned int ipr_offsets[] = {
+static unsigned long ipr_offsets[] = {
0xf8080000, /* IPRC */
0xf8080002, /* IPRD */
0xf8080004, /* IPRE */
@@ -76,15 +76,19 @@ static unsigned int ipr_offsets[] = {
0xf8080008, /* IPRG */
};
-/* given the IPR index return the address of the IPR register */
-unsigned int map_ipridx_to_addr(int idx)
-{
- if (unlikely(idx >= ARRAY_SIZE(ipr_offsets)))
- return 0;
- return ipr_offsets[idx];
-}
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-sh7619",
+ },
+};
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
{
- make_ipr_irq(sh7619_ipr_map, ARRAY_SIZE(sh7619_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
index 4ed9110632bc..deab16500167 100644
--- a/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
+++ b/arch/sh/kernel/cpu/sh2a/setup-sh7206.c
@@ -57,7 +57,7 @@ static int __init sh7206_devices_setup(void)
}
__initcall(sh7206_devices_setup);
-static struct ipr_data sh7206_ipr_map[] = {
+static struct ipr_data ipr_irq_table[] = {
{ 140, 7, 12, 2 }, /* CMI0 */
{ 164, 8, 4, 2 }, /* MTU2_TGI1A */
{ 240, 13, 12, 3 }, /* SCIF0_BRI */
@@ -78,7 +78,7 @@ static struct ipr_data sh7206_ipr_map[] = {
{ 255, 13, 0, 3 }, /* SCIF3_TXI */
};
-static unsigned int ipr_offsets[] = {
+static unsigned long ipr_offsets[] = {
0xfffe0818, /* IPR01 */
0xfffe081a, /* IPR02 */
0, /* unused */
@@ -95,15 +95,19 @@ static unsigned int ipr_offsets[] = {
0xfffe0c10, /* IPR14 */
};
-/* given the IPR index return the address of the IPR register */
-unsigned int map_ipridx_to_addr(int idx)
-{
- if (unlikely(idx >= ARRAY_SIZE(ipr_offsets)))
- return 0;
- return ipr_offsets[idx];
-}
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-sh7206",
+ },
+};
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
{
- make_ipr_irq(sh7206_ipr_map, ARRAY_SIZE(sh7206_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index b0b59d4a33ca..d8e122971c3e 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -340,8 +340,27 @@ ENTRY(vbr_base)
general_exception:
mov.l 1f, k2
mov.l 2f, k3
+#ifdef CONFIG_CPU_SUBTYPE_SHX3
+ mov.l @k2, k2
+
+ ! Is EXPEVT larger than 0x800?
+ mov #0x8, k0
+ shll8 k0
+ cmp/hs k0, k2
+ bf 0f
+
+ ! then add 0x580 (k2 is 0xd80 or 0xda0)
+ mov #0x58, k0
+ shll2 k0
+ shll2 k0
+ add k0, k2
+0:
+ bra handle_exception
+ nop
+#else
bra handle_exception
mov.l @k2, k2
+#endif
.align 2
1: .long EXPEVT
2: .long ret_from_exception
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
index 1983fb7ad6ea..ebd9d06d8bdd 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7705.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -48,7 +48,7 @@ static int __init sh7705_devices_setup(void)
}
__initcall(sh7705_devices_setup);
-static struct ipr_data sh7705_ipr_map[] = {
+static struct ipr_data ipr_irq_table[] = {
/* IRQ, IPR-idx, shift, priority */
{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
{ 17, 0, 8, 2 }, /* TMU1 TUNI */
@@ -70,25 +70,29 @@ static struct ipr_data sh7705_ipr_map[] = {
};
static unsigned long ipr_offsets[] = {
- 0xFFFFFEE2 /* 0: IPRA */
-, 0xFFFFFEE4 /* 1: IPRB */
-, 0xA4000016 /* 2: IPRC */
-, 0xA4000018 /* 3: IPRD */
-, 0xA400001A /* 4: IPRE */
-, 0xA4080000 /* 5: IPRF */
-, 0xA4080002 /* 6: IPRG */
-, 0xA4080004 /* 7: IPRH */
+ 0xFFFFFEE2, /* 0: IPRA */
+ 0xFFFFFEE4, /* 1: IPRB */
+ 0xA4000016, /* 2: IPRC */
+ 0xA4000018, /* 3: IPRD */
+ 0xA400001A, /* 4: IPRE */
+ 0xA4080000, /* 5: IPRF */
+ 0xA4080002, /* 6: IPRG */
+ 0xA4080004, /* 7: IPRH */
};
-/* given the IPR index return the address of the IPR register */
-unsigned int map_ipridx_to_addr(int idx)
-{
- if (idx >= ARRAY_SIZE(ipr_offsets))
- return 0;
- return ipr_offsets[idx];
-}
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-sh7705",
+ },
+};
-void __init init_IRQ_ipr()
+void __init plat_irq_setup(void)
{
- make_ipr_irq(sh7705_ipr_map, ARRAY_SIZE(sh7705_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
index c7d7c35fc834..086f8e2545af 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7709.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -12,6 +12,26 @@
#include <linux/serial.h>
#include <asm/sci.h>
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xfffffec0,
+ .end = 0xfffffec0 + 0x1e,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ .start = 20,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xfffffe80,
@@ -41,8 +61,16 @@ static struct platform_device sci_device = {
},
};
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
static struct platform_device *sh7709_devices[] __initdata = {
&sci_device,
+ &rtc_device,
};
static int __init sh7709_devices_setup(void)
@@ -52,32 +80,66 @@ static int __init sh7709_devices_setup(void)
}
__initcall(sh7709_devices_setup);
-#define IPRx(A,N) .addr=A, .shift=N
-#define IPRA(N) IPRx(0xfffffee2UL,N)
-#define IPRB(N) IPRx(0xfffffee4UL,N)
-#define IPRC(N) IPRx(0xa4000016UL,N)
-#define IPRD(N) IPRx(0xa4000018UL,N)
-#define IPRE(N) IPRx(0xa400001aUL,N)
-
-static struct ipr_data sh7709_ipr_map[] = {
- [16] = { IPRA(12), 2 }, /* TMU TUNI0 */
- [17] = { IPRA(8), 4 }, /* TMU TUNI1 */
- [18 ... 19] = { IPRA(4), 1 }, /* TMU TUNI1 */
- [20 ... 22] = { IPRA(0), 2 }, /* RTC CUI */
- [23 ... 26] = { IPRB(4), 3 }, /* SCI */
- [27] = { IPRB(12), 2 }, /* WDT ITI */
- [32] = { IPRC(0), 1 }, /* IRQ 0 */
- [33] = { IPRC(4), 1 }, /* IRQ 1 */
- [34] = { IPRC(8), 1 }, /* IRQ 2 APM */
- [35] = { IPRC(12), 1 }, /* IRQ 3 TOUCHSCREEN */
- [36] = { IPRD(0), 1 }, /* IRQ 4 */
- [37] = { IPRD(4), 1 }, /* IRQ 5 */
- [48 ... 51] = { IPRE(12), 7 }, /* DMA */
- [52 ... 55] = { IPRE(8), 3 }, /* IRDA */
- [56 ... 59] = { IPRE(4), 3 }, /* SCIF */
+static struct ipr_data ipr_irq_table[] = {
+ { 16, 0, 12, 2 }, /* TMU TUNI0 */
+ { 17, 0, 8, 4 }, /* TMU TUNI1 */
+ { 18, 0, 4, 1 }, /* TMU TUNI1 */
+ { 19, 0, 4, 1 }, /* TMU TUNI1 */
+ { 20, 0, 0, 2 }, /* RTC CUI */
+ { 21, 0, 0, 2 }, /* RTC CUI */
+ { 22, 0, 0, 2 }, /* RTC CUI */
+
+ { 23, 1, 4, 3 }, /* SCI */
+ { 24, 1, 4, 3 }, /* SCI */
+ { 25, 1, 4, 3 }, /* SCI */
+ { 26, 1, 4, 3 }, /* SCI */
+ { 27, 1, 12, 3 }, /* WDT ITI */
+
+ { 32, 2, 0, 1 }, /* IRQ 0 */
+ { 33, 2, 4, 1 }, /* IRQ 1 */
+ { 34, 2, 8, 1 }, /* IRQ 2 APM */
+ { 35, 2, 12, 1 }, /* IRQ 3 TOUCHSCREEN */
+
+ { 36, 3, 0, 1 }, /* IRQ 4 */
+ { 37, 3, 4, 1 }, /* IRQ 5 */
+
+ { 48, 4, 12, 7 }, /* DMA */
+ { 49, 4, 12, 7 }, /* DMA */
+ { 50, 4, 12, 7 }, /* DMA */
+ { 51, 4, 12, 7 }, /* DMA */
+
+ { 52, 4, 8, 3 }, /* IRDA */
+ { 53, 4, 8, 3 }, /* IRDA */
+ { 54, 4, 8, 3 }, /* IRDA */
+ { 55, 4, 8, 3 }, /* IRDA */
+
+ { 56, 4, 4, 3 }, /* SCIF */
+ { 57, 4, 4, 3 }, /* SCIF */
+ { 58, 4, 4, 3 }, /* SCIF */
+ { 59, 4, 4, 3 }, /* SCIF */
+};
+
+static unsigned long ipr_offsets[] = {
+ 0xfffffee2, /* 0: IPRA */
+ 0xfffffee4, /* 1: IPRB */
+ 0xa4000016, /* 2: IPRC */
+ 0xa4000018, /* 3: IPRD */
+ 0xa400001a, /* 4: IPRE */
+};
+
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-sh7709",
+ },
};
-void __init init_IRQ_ipr()
+void __init plat_irq_setup(void)
{
- make_ipr_irq(sh7709_ipr_map, ARRAY_SIZE(sh7709_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
index 51760a7e7f1c..132284893373 100644
--- a/arch/sh/kernel/cpu/sh3/setup-sh7710.c
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -49,7 +49,7 @@ static int __init sh7710_devices_setup(void)
}
__initcall(sh7710_devices_setup);
-static struct ipr_data sh7710_ipr_map[] = {
+static struct ipr_data ipr_irq_table[] = {
/* IRQ, IPR-idx, shift, priority */
{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
{ 17, 0, 8, 2 }, /* TMU1 TUNI */
@@ -78,26 +78,30 @@ static struct ipr_data sh7710_ipr_map[] = {
};
static unsigned long ipr_offsets[] = {
- 0xA414FEE2 /* 0: IPRA */
-, 0xA414FEE4 /* 1: IPRB */
-, 0xA4140016 /* 2: IPRC */
-, 0xA4140018 /* 3: IPRD */
-, 0xA414001A /* 4: IPRE */
-, 0xA4080000 /* 5: IPRF */
-, 0xA4080002 /* 6: IPRG */
-, 0xA4080004 /* 7: IPRH */
-, 0xA4080006 /* 8: IPRI */
+ 0xA414FEE2, /* 0: IPRA */
+ 0xA414FEE4, /* 1: IPRB */
+ 0xA4140016, /* 2: IPRC */
+ 0xA4140018, /* 3: IPRD */
+ 0xA414001A, /* 4: IPRE */
+ 0xA4080000, /* 5: IPRF */
+ 0xA4080002, /* 6: IPRG */
+ 0xA4080004, /* 7: IPRH */
+ 0xA4080006, /* 8: IPRI */
};
-/* given the IPR index return the address of the IPR register */
-unsigned int map_ipridx_to_addr(int idx)
-{
- if (idx >= ARRAY_SIZE(ipr_offsets))
- return 0;
- return ipr_offsets[idx];
-}
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
+
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-sh7710",
+ },
+};
-void __init init_IRQ_ipr()
+void __init plat_irq_setup(void)
{
- make_ipr_irq(sh7710_ipr_map, ARRAY_SIZE(sh7710_ipr_map));
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 8add10bd8268..dadd6bffc128 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -10,7 +10,11 @@ obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7750S) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7091) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751R) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o
obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index fab2eb07196b..66c3f75647b2 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -141,6 +141,14 @@ int __init detect_cpu_and_cache_system(void)
current_cpu_data.flags |= CPU_HAS_LLSC;
}
break;
+ case 0x4000: /* 1st cut */
+ case 0x4001: /* 2nd cut */
+ current_cpu_data.type = CPU_SHX3;
+ current_cpu_data.icache.ways = 4;
+ current_cpu_data.dcache.ways = 4;
+ current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ CPU_HAS_LLSC;
+ break;
case 0x8000:
current_cpu_data.type = CPU_ST40RA;
current_cpu_data.flags |= CPU_HAS_FPU;
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
index 03b14cf78ddf..f2286de22bd5 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7750.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -82,72 +82,213 @@ static int __init sh7750_devices_setup(void)
}
__initcall(sh7750_devices_setup);
-static struct ipr_data sh7750_ipr_map[] = {
- /* IRQ, IPR-idx, shift, priority */
- { 16, 0, 12, 2 }, /* TMU0 TUNI*/
- { 17, 0, 12, 2 }, /* TMU1 TUNI */
- { 18, 0, 4, 2 }, /* TMU2 TUNI */
- { 19, 0, 4, 2 }, /* TMU2 TIPCI */
- { 27, 1, 12, 2 }, /* WDT ITI */
- { 20, 0, 0, 2 }, /* RTC ATI (alarm) */
- { 21, 0, 0, 2 }, /* RTC PRI (period) */
- { 22, 0, 0, 2 }, /* RTC CUI (carry) */
- { 23, 1, 4, 3 }, /* SCI ERI */
- { 24, 1, 4, 3 }, /* SCI RXI */
- { 25, 1, 4, 3 }, /* SCI TXI */
- { 40, 2, 4, 3 }, /* SCIF ERI */
- { 41, 2, 4, 3 }, /* SCIF RXI */
- { 42, 2, 4, 3 }, /* SCIF BRI */
- { 43, 2, 4, 3 }, /* SCIF TXI */
- { 34, 2, 8, 7 }, /* DMAC DMTE0 */
- { 35, 2, 8, 7 }, /* DMAC DMTE1 */
- { 36, 2, 8, 7 }, /* DMAC DMTE2 */
- { 37, 2, 8, 7 }, /* DMAC DMTE3 */
- { 38, 2, 8, 7 }, /* DMAC DMAE */
-};
-
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
-static struct ipr_data sh7751_ipr_map[] = {
- { 44, 2, 8, 7 }, /* DMAC DMTE4 */
- { 45, 2, 8, 7 }, /* DMAC DMTE5 */
- { 46, 2, 8, 7 }, /* DMAC DMTE6 */
- { 47, 2, 8, 7 }, /* DMAC DMTE7 */
- /* The following use INTC_INPRI00 for masking, which is a 32-bit
- register, not a 16-bit register like the IPRx registers, so it
- would need special support */
- /*{ 72, INTPRI00, 8, ? },*/ /* TMU3 TUNI */
- /*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */
+enum {
+ UNUSED = 0,
+
+ /* interrupt sources */
+ IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
+ HUDI, GPIOI,
+ DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
+ DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
+ DMAC_DMAE,
+ PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+ PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
+ TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
+ RTC_ATI, RTC_PRI, RTC_CUI,
+ SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
+ SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
+ WDT,
+ REF_RCMI, REF_ROVI,
+
+ /* interrupt groups */
+ DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
+};
+
+static struct intc_vect vectors[] = {
+ INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
+ INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+ INTC_VECT(RTC_CUI, 0x4c0),
+ INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
+ INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
+ INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
+ INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
+ INTC_VECT(WDT, 0x560),
+ INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
+};
+
+static struct intc_group groups[] = {
+ INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
+ INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
+ INTC_GROUP(REF, REF_RCMI, REF_ROVI),
+};
+
+static struct intc_prio priorities[] = {
+ INTC_PRIO(SCIF, 3),
+ INTC_PRIO(SCI1, 3),
+ INTC_PRIO(DMAC, 7),
+};
+
+static struct intc_prio_reg prio_registers[] = {
+ { 0xffd00004, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
+ { 0xffd00008, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
+ { 0xffd0000c, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
+ { 0xffd00010, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
+ { 0xfe080000, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0,
+ TMU4, TMU3,
+ PCIC1, PCIC0_PCISERR } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7750", vectors, groups,
+ priorities, NULL, prio_registers, NULL);
+
+/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7091)
+static struct intc_vect vectors_dma4[] = {
+ INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+ INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+ INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma4[] = {
+ INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+ DMAC_DMTE3, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma4, "sh7750_dma4",
+ vectors_dma4, groups_dma4,
+ priorities, NULL, prio_registers, NULL);
+#endif
+
+/* SH7750R and SH7751R both have 8-channel DMA controllers */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_dma8[] = {
+ INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
+ INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
+ INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
+ INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
+ INTC_VECT(DMAC_DMAE, 0x6c0),
+};
+
+static struct intc_group groups_dma8[] = {
+ INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
+ DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
+ DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
+};
+
+static DECLARE_INTC_DESC(intc_desc_dma8, "sh7750_dma8",
+ vectors_dma8, groups_dma8,
+ priorities, NULL, prio_registers, NULL);
+#endif
+
+/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_tmu34[] = {
+ INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+ { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, TMU4, TMU3,
+ PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+ PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
+ PCIC1_PCIDMA3, PCIC0_PCISERR } },
};
+
+static DECLARE_INTC_DESC(intc_desc_tmu34, "sh7750_tmu34",
+ vectors_tmu34, NULL, priorities,
+ mask_registers, prio_registers, NULL);
#endif
-static unsigned long ipr_offsets[] = {
- 0xffd00004UL, /* 0: IPRA */
- 0xffd00008UL, /* 1: IPRB */
- 0xffd0000cUL, /* 2: IPRC */
- 0xffd00010UL, /* 3: IPRD */
+/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
+static struct intc_vect vectors_irlm[] = {
+ INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
+ INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
+};
+
+static DECLARE_INTC_DESC(intc_desc_irlm, "sh7750_irlm", vectors_irlm, NULL,
+ priorities, NULL, prio_registers, NULL);
+
+/* SH7751 and SH7751R both have PCI */
+#if defined(CONFIG_CPU_SUBTYPE_SH7751) || defined(CONFIG_CPU_SUBTYPE_SH7751R)
+static struct intc_vect vectors_pci[] = {
+ INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
+ INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
+ INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
+ INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
};
-/* given the IPR index return the address of the IPR register */
-unsigned int map_ipridx_to_addr(int idx)
+static struct intc_group groups_pci[] = {
+ INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
+ PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
+};
+
+static DECLARE_INTC_DESC(intc_desc_pci, "sh7750_pci", vectors_pci, groups_pci,
+ priorities, mask_registers, prio_registers, NULL);
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7091)
+void __init plat_irq_setup(void)
{
- if (idx >= ARRAY_SIZE(ipr_offsets))
- return 0;
- return ipr_offsets[idx];
+ /*
+ * same vectors for SH7750, SH7750S and SH7091 except for IRLM,
+ * see below..
+ */
+ register_intc_controller(&intc_desc);
+ register_intc_controller(&intc_desc_dma4);
}
+#endif
-#define INTC_ICR 0xffd00000UL
-#define INTC_ICR_IRLM (1<<7)
+#if defined(CONFIG_CPU_SUBTYPE_SH7750R)
+void __init plat_irq_setup(void)
+{
+ register_intc_controller(&intc_desc);
+ register_intc_controller(&intc_desc_dma8);
+ register_intc_controller(&intc_desc_tmu34);
+}
+#endif
-/* enable individual interrupt mode for external interupts */
-void ipr_irq_enable_irlm(void)
+#if defined(CONFIG_CPU_SUBTYPE_SH7751)
+void __init plat_irq_setup(void)
{
- ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+ register_intc_controller(&intc_desc);
+ register_intc_controller(&intc_desc_dma4);
+ register_intc_controller(&intc_desc_tmu34);
+ register_intc_controller(&intc_desc_pci);
}
+#endif
-void __init init_IRQ_ipr()
+#if defined(CONFIG_CPU_SUBTYPE_SH7751R)
+void __init plat_irq_setup(void)
{
- make_ipr_irq(sh7750_ipr_map, ARRAY_SIZE(sh7750_ipr_map));
-#ifdef CONFIG_CPU_SUBTYPE_SH7751
- make_ipr_irq(sh7751_ipr_map, ARRAY_SIZE(sh7751_ipr_map));
+ register_intc_controller(&intc_desc);
+ register_intc_controller(&intc_desc_dma8);
+ register_intc_controller(&intc_desc_tmu34);
+ register_intc_controller(&intc_desc_pci);
+}
#endif
+
+#define INTC_ICR 0xffd00000UL
+#define INTC_ICR_IRLM (1<<7)
+
+/* enable individual interrupt mode for external interupts */
+void __init ipr_irq_enable_irlm(void)
+{
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7091)
+ BUG(); /* impossible to mask interrupts on SH7750 and SH7091 */
+#endif
+ register_intc_controller(&intc_desc_irlm);
+
+ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
}
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
index b7c702821e6f..47fa27056253 100644
--- a/arch/sh/kernel/cpu/sh4/setup-sh7760.c
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -96,7 +96,20 @@ static struct intc2_data intc2_irq_table[] = {
{109,12, 0, 4, 0, 3}, /* CMTI */
};
-static struct ipr_data sh7760_ipr_map[] = {
+static struct intc2_desc intc2_irq_desc __read_mostly = {
+ .prio_base = 0xfe080000,
+ .msk_base = 0xfe080040,
+ .mskclr_base = 0xfe080060,
+
+ .intc2_data = intc2_irq_table,
+ .nr_irqs = ARRAY_SIZE(intc2_irq_table),
+
+ .chip = {
+ .name = "INTC2-sh7760",
+ },
+};
+
+static struct ipr_data ipr_irq_table[] = {
/* IRQ, IPR-idx, shift, priority */
{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
{ 17, 0, 8, 2 }, /* TMU1 TUNI */
@@ -133,20 +146,20 @@ static unsigned long ipr_offsets[] = {
0xffd00010UL, /* 3: IPRD */
};
-/* given the IPR index return the address of the IPR register */
-unsigned int map_ipridx_to_addr(int idx)
-{
- if (idx >= ARRAY_SIZE(ipr_offsets))
- return 0;
- return ipr_offsets[idx];
-}
+static struct ipr_desc ipr_irq_desc = {
+ .ipr_offsets = ipr_offsets,
+ .nr_offsets = ARRAY_SIZE(ipr_offsets),
-void __init init_IRQ_intc2(void)
-{
- make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
-}
+ .ipr_data = ipr_irq_table,
+ .nr_irqs = ARRAY_SIZE(ipr_irq_table),
+
+ .chip = {
+ .name = "IPR-sh7760",
+ },
+};
-void __init init_IRQ_ipr(void)
+void __init plat_irq_setup(void)
{
- make_ipr_irq(sh7760_ipr_map, ARRAY_SIZE(sh7760_ipr_map));
+ register_intc2_controller(&intc2_irq_desc);
+ register_ipr_controller(&ipr_irq_desc);
}
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index d7fff752e569..b98d6c3e6f36 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -371,8 +371,7 @@ static int __init sq_api_init(void)
printk(KERN_NOTICE "sq: Registering store queue API.\n");
sq_cache = kmem_cache_create("store_queue_cache",
- sizeof(struct sq_mapping), 0, 0,
- NULL, NULL);
+ sizeof(struct sq_mapping), 0, 0, NULL);
if (unlikely(!sq_cache))
return ret;
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile
index ab7422f8f820..400623286487 100644
--- a/arch/sh/kernel/cpu/sh4a/Makefile
+++ b/arch/sh/kernel/cpu/sh4a/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
+obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
@@ -17,5 +18,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
+clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
obj-y += $(clock-y)
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
index 51b386d454de..a0fd8bb21f7c 100644
--- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c
@@ -387,9 +387,24 @@ out_err:
return err;
}
+static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk->parent->rate;
+ int div;
+
+ /* look for multiplier/divisor pair */
+ div = sh7722_find_divisors(parent_rate, rate);
+ if (div < 0)
+ return clk->rate;
+
+ /* calculate new value of clock rate */
+ return parent_rate * 2 / div;
+}
+
static struct clk_ops sh7722_frqcr_clk_ops = {
.recalc = sh7722_frqcr_recalc,
.set_rate = sh7722_frqcr_set_rate,
+ .round_rate = sh7722_frqcr_round_rate,
};
/*
diff --git a/arch/sh/kernel/cpu/sh4a/clock-shx3.c b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
new file mode 100644
index 000000000000..c630b29e06a8
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/clock-shx3.c
@@ -0,0 +1,135 @@
+/*
+ * arch/sh/kernel/cpu/sh4/clock-shx3.c
+ *
+ * SH-X3 support for the clock framework
+ *
+ * Copyright (C) 2006-2007 Renesas Technology Corp.
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ * Copyright (C) 2006-2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int ifc_divisors[] = { 1, 2, 4 ,6 };
+static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 };
+static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 };
+static int cfc_divisors[] = { 1, 1, 4, 6 };
+
+#define IFC_POS 28
+#define IFC_MSK 0x0003
+#define BFC_MSK 0x000f
+#define PFC_MSK 0x000f
+#define CFC_MSK 0x0003
+#define BFC_POS 16
+#define PFC_POS 0
+#define CFC_POS 20
+
+static void master_clk_init(struct clk *clk)
+{
+ clk->rate *= pfc_divisors[(ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK];
+}
+
+static struct clk_ops shx3_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK);
+ clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops shx3_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> BFC_POS) & BFC_MSK);
+ clk->rate = clk->parent->rate / bfc_divisors[idx];
+}
+
+static struct clk_ops shx3_bus_clk_ops = {
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> IFC_POS) & IFC_MSK);
+ clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops shx3_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *shx3_clk_ops[] = {
+ &shx3_master_clk_ops,
+ &shx3_module_clk_ops,
+ &shx3_bus_clk_ops,
+ &shx3_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(shx3_clk_ops))
+ *ops = shx3_clk_ops[idx];
+}
+
+static void shyway_clk_recalc(struct clk *clk)
+{
+ int idx = ((ctrl_inl(FRQCR) >> CFC_POS) & CFC_MSK);
+ clk->rate = clk->parent->rate / cfc_divisors[idx];
+}
+
+static struct clk_ops shx3_shyway_clk_ops = {
+ .recalc = shyway_clk_recalc,
+};
+
+static struct clk shx3_shyway_clk = {
+ .name = "shyway_clk",
+ .flags = CLK_ALWAYS_ENABLED,
+ .ops = &shx3_shyway_clk_ops,
+};
+
+/*
+ * Additional SHx3-specific on-chip clocks that aren't already part of the
+ * clock framework
+ */
+static struct clk *shx3_onchip_clocks[] = {
+ &shx3_shyway_clk,
+};
+
+static int __init shx3_clk_init(void)
+{
+ struct clk *clk = clk_get(NULL, "master_clk");
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
+ struct clk *clkp = shx3_onchip_clocks[i];
+
+ clkp->parent = clk;
+ clk_register(clkp);
+ clk_enable(clkp);
+ }
+
+ /*
+ * Now that we have the rest of the clocks registered, we need to
+ * force the parent clock to propagate so that these clocks will
+ * automatically figure out their rate. We cheat by handing the
+ * parent clock its current rate and forcing child propagation.
+ */
+ clk_set_rate(clk, clk_get_rate(clk));
+
+ clk_put(clk);
+
+ return 0;
+}
+arch_initcall(shx3_clk_init);
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
index 1143fbf65faf..25b913e07e2c 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c
@@ -1,7 +1,7 @@
/*
* SH7722 Setup
*
- * Copyright (C) 2006 Paul Mundt
+ * Copyright (C) 2006 - 2007 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
@@ -10,6 +10,8 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/serial.h>
+#include <linux/mm.h>
+#include <asm/mmzone.h>
#include <asm/sci.h>
static struct plat_sci_port sci_platform_data[] = {
@@ -17,8 +19,21 @@ static struct plat_sci_port sci_platform_data[] = {
.mapbase = 0xffe00000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 80, 81, 83, 82 },
- }, {
+ .irqs = { 80, 80, 80, 80 },
+ },
+ {
+ .mapbase = 0xffe10000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 81, 81, 81, 81 },
+ },
+ {
+ .mapbase = 0xffe20000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 82, 82, 82, 82 },
+ },
+ {
.flags = 0,
}
};
@@ -42,39 +57,149 @@ static int __init sh7722_devices_setup(void)
}
__initcall(sh7722_devices_setup);
-static struct ipr_data sh7722_ipr_map[] = {
- /* IRQ, IPR-idx, shift, prio */
- { 16, 0, 12, 2 }, /* TMU0 */
- { 17, 0, 8, 2 }, /* TMU1 */
- { 80, 6, 12, 3 }, /* SCIF ERI */
- { 81, 6, 12, 3 }, /* SCIF RXI */
- { 82, 6, 12, 3 }, /* SCIF BRI */
- { 83, 6, 12, 3 }, /* SCIF TXI */
+enum {
+ UNUSED=0,
+
+ /* interrupt sources */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ HUDI,
+ SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI,
+ RTC_ATI, RTC_PRI, RTC_CUI,
+ DMAC0, DMAC1, DMAC2, DMAC3,
+ VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU,
+ VPU, TPU,
+ USB_USBI0, USB_USBI1,
+ DMAC4, DMAC5, DMAC_DADERR,
+ KEYSC,
+ SCIF0, SCIF1, SCIF2, SIOF0, SIOF1, SIO,
+ FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
+ I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI,
+ SDHI0, SDHI1, SDHI2, SDHI3,
+ CMT, TSIF, SIU, TWODG,
+ TMU0, TMU1, TMU2,
+ IRDA, JPU, LCDC,
+
+ /* interrupt groups */
+
+ SIM, RTC, DMAC0123, VIOVOU, USB, DMAC45, FLCTL, I2C, SDHI,
+};
+
+static struct intc_vect vectors[] = {
+ INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620),
+ INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660),
+ INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0),
+ INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0),
+ INTC_VECT(SIM_ERI, 0x700), INTC_VECT(SIM_RXI, 0x720),
+ INTC_VECT(SIM_TXI, 0x740), INTC_VECT(SIM_TEI, 0x760),
+ INTC_VECT(RTC_ATI, 0x780), INTC_VECT(RTC_PRI, 0x7a0),
+ INTC_VECT(RTC_CUI, 0x7c0),
+ INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820),
+ INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860),
+ INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0),
+ INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0),
+ INTC_VECT(VPU, 0x980), INTC_VECT(TPU, 0x9a0),
+ INTC_VECT(USB_USBI0, 0xa20), INTC_VECT(USB_USBI1, 0xa40),
+ INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0),
+ INTC_VECT(DMAC_DADERR, 0xbc0), INTC_VECT(KEYSC, 0xbe0),
+ INTC_VECT(SCIF0, 0xc00), INTC_VECT(SCIF1, 0xc20),
+ INTC_VECT(SCIF2, 0xc40), INTC_VECT(SIOF0, 0xc80),
+ INTC_VECT(SIOF1, 0xca0), INTC_VECT(SIO, 0xd00),
+ INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0),
+ INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0),
+ INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20),
+ INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60),
+ INTC_VECT(SDHI0, 0xe80), INTC_VECT(SDHI1, 0xea0),
+ INTC_VECT(SDHI2, 0xec0), INTC_VECT(SDHI3, 0xee0),
+ INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20),
+ INTC_VECT(SIU, 0xf80), INTC_VECT(TWODG, 0xfa0),
+ INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
+ INTC_VECT(TMU2, 0x440), INTC_VECT(IRDA, 0x480),
+ INTC_VECT(JPU, 0x560), INTC_VECT(LCDC, 0x580),
+};
+
+static struct intc_group groups[] = {
+ INTC_GROUP(SIM, SIM_ERI, SIM_RXI, SIM_TXI, SIM_TEI),
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3),
+ INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU),
+ INTC_GROUP(USB, USB_USBI0, USB_USBI1),
+ INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR),
+ INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI,
+ FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
+ INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI),
+ INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3),
+};
+
+static struct intc_prio priorities[] = {
+ INTC_PRIO(SCIF0, 3),
+ INTC_PRIO(SCIF1, 3),
+ INTC_PRIO(SCIF2, 3),
+ INTC_PRIO(TMU0, 2),
+ INTC_PRIO(TMU1, 2),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+ { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */
+ { } },
+ { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */
+ { VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } },
+ { 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */
+ { 0, 0, 0, VPU, } },
+ { 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */
+ { SIM_TEI, SIM_TXI, SIM_RXI, SIM_ERI, 0, 0, 0, IRDA } },
+ { 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */
+ { 0, TMU2, TMU1, TMU0, JPU, 0, 0, LCDC } },
+ { 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */
+ { KEYSC, DMAC_DADERR, DMAC5, DMAC4, 0, SCIF2, SCIF1, SCIF0 } },
+ { 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */
+ { 0, 0, 0, SIO, 0, 0, SIOF1, SIOF0 } },
+ { 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */
+ { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI,
+ FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } },
+ { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */
+ { SDHI3, SDHI2, SDHI1, SDHI0, 0, 0, TWODG, SIU } },
+ { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */
+ { 0, 0, 0, CMT, 0, USB_USBI1, USB_USBI0, } },
+ { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */
+ { } },
+ { 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */
+ { 0, RTC_CUI, RTC_PRI, RTC_ATI, 0, TPU, 0, TSIF } },
+ { 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-static unsigned long ipr_offsets[] = {
- 0xa4080000, /* 0: IPRA */
- 0xa4080004, /* 1: IPRB */
- 0xa4080008, /* 2: IPRC */
- 0xa408000c, /* 3: IPRD */
- 0xa4080010, /* 4: IPRE */
- 0xa4080014, /* 5: IPRF */
- 0xa4080018, /* 6: IPRG */
- 0xa408001c, /* 7: IPRH */
- 0xa4080020, /* 8: IPRI */
- 0xa4080024, /* 9: IPRJ */
- 0xa4080028, /* 10: IPRK */
- 0xa408002c, /* 11: IPRL */
+static struct intc_prio_reg prio_registers[] = {
+ { 0xa4080000, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, IRDA } },
+ { 0xa4080004, 16, 4, /* IPRB */ { JPU, LCDC, SIM } },
+ { 0xa4080008, 16, 4, /* IPRC */ { } },
+ { 0xa408000c, 16, 4, /* IPRD */ { } },
+ { 0xa4080010, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, 0, VPU } },
+ { 0xa4080014, 16, 4, /* IPRF */ { KEYSC, DMAC45, USB, CMT } },
+ { 0xa4080018, 16, 4, /* IPRG */ { SCIF0, SCIF1, SCIF2 } },
+ { 0xa408001c, 16, 4, /* IPRH */ { SIOF0, SIOF1, FLCTL, I2C } },
+ { 0xa4080020, 16, 4, /* IPRI */ { SIO, 0, TSIF, RTC } },
+ { 0xa4080024, 16, 4, /* IPRJ */ { 0, 0, SIU } },
+ { 0xa4080028, 16, 4, /* IPRK */ { 0, 0, 0, SDHI } },
+ { 0xa408002c, 16, 4, /* IPRL */ { TWODG, 0, TPU } },
+ { 0xa4140010, 32, 4, /* INTPRI00 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
};
-unsigned int map_ipridx_to_addr(int idx)
+static struct intc_sense_reg sense_registers[] = {
+ { 0xa414001c, 16, 2, /* ICR1 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7722", vectors, groups, priorities,
+ mask_registers, prio_registers, sense_registers);
+
+void __init plat_irq_setup(void)
{
- if (unlikely(idx >= ARRAY_SIZE(ipr_offsets)))
- return 0;
- return ipr_offsets[idx];
+ register_intc_controller(&intc_desc);
}
-void __init init_IRQ_ipr(void)
+void __init plat_mem_setup(void)
{
- make_ipr_irq(sh7722_ipr_map, ARRAY_SIZE(sh7722_ipr_map));
+ /* Register the URAM space as Node 1 */
+ setup_bootmem_node(1, 0x055f0000, 0x05610000);
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
index 9aeaa2ddaa28..a4127ec15203 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7780.c
@@ -30,7 +30,7 @@ static struct resource rtc_resources[] = {
},
[3] = {
/* Alarm IRQ */
- .start = 23,
+ .start = 20,
.flags = IORESOURCE_IRQ,
},
};
@@ -78,31 +78,205 @@ static int __init sh7780_devices_setup(void)
}
__initcall(sh7780_devices_setup);
-static struct intc2_data intc2_irq_table[] = {
- { 28, 0, 24, 0, 0, 2 }, /* TMU0 */
+enum {
+ UNUSED = 0,
- { 21, 1, 0, 0, 2, 2 },
- { 22, 1, 1, 0, 2, 2 },
- { 23, 1, 2, 0, 2, 2 },
+ /* interrupt sources */
- { 40, 8, 24, 0, 3, 3 }, /* SCIF0 ERI */
- { 41, 8, 24, 0, 3, 3 }, /* SCIF0 RXI */
- { 42, 8, 24, 0, 3, 3 }, /* SCIF0 BRI */
- { 43, 8, 24, 0, 3, 3 }, /* SCIF0 TXI */
+ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL,
- { 76, 8, 16, 0, 4, 3 }, /* SCIF1 ERI */
- { 77, 8, 16, 0, 4, 3 }, /* SCIF1 RXI */
- { 78, 8, 16, 0, 4, 3 }, /* SCIF1 BRI */
- { 79, 8, 16, 0, 4, 3 }, /* SCIF1 TXI */
+ IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7,
+ RTC_ATI, RTC_PRI, RTC_CUI,
+ WDT,
+ TMU0, TMU1, TMU2, TMU2_TICPI,
+ HUDI,
+ DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, DMAC0_DMINT3, DMAC0_DMAE,
+ SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI,
+ DMAC0_DMINT4, DMAC0_DMINT5, DMAC1_DMINT6, DMAC1_DMINT7,
+ CMT, HAC,
+ PCISERR, PCIINTA, PCIINTB, PCIINTC, PCIINTD,
+ PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0,
+ SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI,
+ SIOF, HSPI,
+ MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY,
+ DMAC1_DMINT8, DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11,
+ TMU3, TMU4, TMU5,
+ SSI,
+ FLCTL_FLSTE, FLCTL_FLEND, FLCTL_FLTRQ0, FLCTL_FLTRQ1,
+ GPIOI0, GPIOI1, GPIOI2, GPIOI3,
- { 64, 0x10, 8, 0, 14, 2 }, /* PCIC0 */
- { 65, 0x10, 0, 0, 15, 2 }, /* PCIC1 */
- { 66, 0x14, 24, 0, 16, 2 }, /* PCIC2 */
- { 67, 0x14, 16, 0, 17, 2 }, /* PCIC3 */
- { 68, 0x14, 8, 0, 18, 2 }, /* PCIC4 */
+ /* interrupt groups */
+
+ RTC, TMU012, DMAC0, SCIF0, DMAC45, DMAC1,
+ PCIC5, SCIF1, MMCIF, TMU345, FLCTL, GPIO,
+};
+
+static struct intc_vect vectors[] = {
+ INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
+ INTC_VECT(RTC_CUI, 0x4c0),
+ INTC_VECT(WDT, 0x560),
+ INTC_VECT(TMU0, 0x580), INTC_VECT(TMU1, 0x5a0),
+ INTC_VECT(TMU2, 0x5c0), INTC_VECT(TMU2_TICPI, 0x5e0),
+ INTC_VECT(HUDI, 0x600),
+ INTC_VECT(DMAC0_DMINT0, 0x640), INTC_VECT(DMAC0_DMINT1, 0x660),
+ INTC_VECT(DMAC0_DMINT2, 0x680), INTC_VECT(DMAC0_DMINT3, 0x6a0),
+ INTC_VECT(DMAC0_DMAE, 0x6c0),
+ INTC_VECT(SCIF0_ERI, 0x700), INTC_VECT(SCIF0_RXI, 0x720),
+ INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
+ INTC_VECT(DMAC0_DMINT4, 0x780), INTC_VECT(DMAC0_DMINT5, 0x7a0),
+ INTC_VECT(DMAC1_DMINT6, 0x7c0), INTC_VECT(DMAC1_DMINT7, 0x7e0),
+ INTC_VECT(CMT, 0x900), INTC_VECT(HAC, 0x980),
+ INTC_VECT(PCISERR, 0xa00), INTC_VECT(PCIINTA, 0xa20),
+ INTC_VECT(PCIINTB, 0xa40), INTC_VECT(PCIINTC, 0xa60),
+ INTC_VECT(PCIINTD, 0xa80), INTC_VECT(PCIERR, 0xaa0),
+ INTC_VECT(PCIPWD3, 0xac0), INTC_VECT(PCIPWD2, 0xae0),
+ INTC_VECT(PCIPWD1, 0xb00), INTC_VECT(PCIPWD0, 0xb20),
+ INTC_VECT(SCIF1_ERI, 0xb80), INTC_VECT(SCIF1_RXI, 0xba0),
+ INTC_VECT(SCIF1_BRI, 0xbc0), INTC_VECT(SCIF1_TXI, 0xbe0),
+ INTC_VECT(SIOF, 0xc00), INTC_VECT(HSPI, 0xc80),
+ INTC_VECT(MMCIF_FSTAT, 0xd00), INTC_VECT(MMCIF_TRAN, 0xd20),
+ INTC_VECT(MMCIF_ERR, 0xd40), INTC_VECT(MMCIF_FRDY, 0xd60),
+ INTC_VECT(DMAC1_DMINT8, 0xd80), INTC_VECT(DMAC1_DMINT9, 0xda0),
+ INTC_VECT(DMAC1_DMINT10, 0xdc0), INTC_VECT(DMAC1_DMINT11, 0xde0),
+ INTC_VECT(TMU3, 0xe00), INTC_VECT(TMU4, 0xe20),
+ INTC_VECT(TMU5, 0xe40),
+ INTC_VECT(SSI, 0xe80),
+ INTC_VECT(FLCTL_FLSTE, 0xf00), INTC_VECT(FLCTL_FLEND, 0xf20),
+ INTC_VECT(FLCTL_FLTRQ0, 0xf40), INTC_VECT(FLCTL_FLTRQ1, 0xf60),
+ INTC_VECT(GPIOI0, 0xf80), INTC_VECT(GPIOI1, 0xfa0),
+ INTC_VECT(GPIOI2, 0xfc0), INTC_VECT(GPIOI3, 0xfe0),
+};
+
+static struct intc_group groups[] = {
+ INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
+ INTC_GROUP(TMU012, TMU0, TMU1, TMU2, TMU2_TICPI),
+ INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
+ DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
+ INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
+ INTC_GROUP(DMAC1, DMAC1_DMINT6, DMAC1_DMINT7, DMAC1_DMINT8,
+ DMAC1_DMINT9, DMAC1_DMINT10, DMAC1_DMINT11),
+ INTC_GROUP(PCIC5, PCIERR, PCIPWD3, PCIPWD2, PCIPWD1, PCIPWD0),
+ INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
+ INTC_GROUP(MMCIF, MMCIF_FSTAT, MMCIF_TRAN, MMCIF_ERR, MMCIF_FRDY),
+ INTC_GROUP(TMU345, TMU3, TMU4, TMU5),
+ INTC_GROUP(FLCTL, FLCTL_FLSTE, FLCTL_FLEND,
+ FLCTL_FLTRQ0, FLCTL_FLTRQ1),
+ INTC_GROUP(GPIO, GPIOI0, GPIOI1, GPIOI2, GPIOI3),
+};
+
+static struct intc_prio priorities[] = {
+ INTC_PRIO(SCIF0, 3),
+ INTC_PRIO(SCIF1, 3),
+};
+
+static struct intc_mask_reg mask_registers[] = {
+ { 0xffd40038, 0xffd4003c, 32, /* INT2MSKR / INT2MSKCR */
+ { 0, 0, 0, 0, 0, 0, GPIO, FLCTL,
+ SSI, MMCIF, HSPI, SIOF, PCIC5, PCIINTD, PCIINTC, PCIINTB,
+ PCIINTA, PCISERR, HAC, CMT, 0, 0, DMAC1, DMAC0,
+ HUDI, 0, WDT, SCIF1, SCIF0, RTC, TMU345, TMU012 } },
};
-void __init init_IRQ_intc2(void)
+static struct intc_prio_reg prio_registers[] = {
+ { 0xffd40000, 32, 8, /* INT2PRI0 */ { TMU0, TMU1, TMU2, TMU2_TICPI } },
+ { 0xffd40004, 32, 8, /* INT2PRI1 */ { TMU3, TMU4, TMU5, RTC } },
+ { 0xffd40008, 32, 8, /* INT2PRI2 */ { SCIF0, SCIF1, WDT } },
+ { 0xffd4000c, 32, 8, /* INT2PRI3 */ { HUDI, DMAC0, DMAC1 } },
+ { 0xffd40010, 32, 8, /* INT2PRI4 */ { CMT, HAC, PCISERR, PCIINTA, } },
+ { 0xffd40014, 32, 8, /* INT2PRI5 */ { PCIINTB, PCIINTC,
+ PCIINTD, PCIC5 } },
+ { 0xffd40018, 32, 8, /* INT2PRI6 */ { SIOF, HSPI, MMCIF, SSI } },
+ { 0xffd4001c, 32, 8, /* INT2PRI7 */ { FLCTL, GPIO } },
+};
+
+static DECLARE_INTC_DESC(intc_desc, "sh7780", vectors, groups, priorities,
+ mask_registers, prio_registers, NULL);
+
+/* Support for external interrupt pins in IRQ mode */
+
+static struct intc_vect irq_vectors[] = {
+ INTC_VECT(IRQ0, 0x240), INTC_VECT(IRQ1, 0x280),
+ INTC_VECT(IRQ2, 0x2c0), INTC_VECT(IRQ3, 0x300),
+ INTC_VECT(IRQ4, 0x340), INTC_VECT(IRQ5, 0x380),
+ INTC_VECT(IRQ6, 0x3c0), INTC_VECT(IRQ7, 0x200),
+};
+
+static struct intc_mask_reg irq_mask_registers[] = {
+ { 0xffd00044, 0xffd00064, 32, /* INTMSK0 / INTMSKCLR0 */
+ { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_prio_reg irq_prio_registers[] = {
+ { 0xffd00010, 32, 4, /* INTPRI */ { IRQ0, IRQ1, IRQ2, IRQ3,
+ IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static struct intc_sense_reg irq_sense_registers[] = {
+ { 0xffd0001c, 32, 2, /* ICR1 */ { IRQ0, IRQ1, IRQ2, IRQ3,
+ IRQ4, IRQ5, IRQ6, IRQ7 } },
+};
+
+static DECLARE_INTC_DESC(intc_irq_desc, "sh7780-irq", irq_vectors,
+ NULL, NULL, irq_mask_registers, irq_prio_registers,
+ irq_sense_registers);
+
+/* External interrupt pins in IRL mode */
+
+static struct intc_vect irl_vectors[] = {
+ INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
+ INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
+ INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
+ INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
+ INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
+ INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
+ INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
+ INTC_VECT(IRL_HHHL, 0x3c0),
+};
+
+static struct intc_mask_reg irl3210_mask_registers[] = {
+ { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+ { IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static struct intc_mask_reg irl7654_mask_registers[] = {
+ { 0xffd00080, 0xffd00084, 32, /* INTMSK2 / INTMSKCLR2 */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
+ IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
+ IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
+ IRL_HHLL, IRL_HHLH, IRL_HHHL, } },
+};
+
+static DECLARE_INTC_DESC(intc_irl7654_desc, "sh7780-irl7654", irl_vectors,
+ NULL, NULL, irl7654_mask_registers, NULL, NULL);
+
+static DECLARE_INTC_DESC(intc_irl3210_desc, "sh7780-irl3210", irl_vectors,
+ NULL, NULL, irl3210_mask_registers, NULL, NULL);
+
+void __init plat_irq_setup(void)
{
- make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
+ register_intc_controller(&intc_desc);
+}
+
+void __init plat_irq_setup_pins(int mode)
+{
+ switch (mode) {
+ case IRQ_MODE_IRQ:
+ register_intc_controller(&intc_irq_desc);
+ break;
+ case IRQ_MODE_IRL7654:
+ register_intc_controller(&intc_irl7654_desc);
+ break;
+ case IRQ_MODE_IRL3210:
+ register_intc_controller(&intc_irl3210_desc);
+ break;
+ default:
+ BUG();
+ }
}
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
index 07b0de82cfe6..cf047562e43f 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7785.c
@@ -97,7 +97,21 @@ static struct intc2_data intc2_irq_table[] = {
{ 60, 12, 16, 0, 7, 3 }, /* SCIF5 ERI, RXI, BRI, TXI */
};
-void __init init_IRQ_intc2(void)
+static struct intc2_desc intc2_irq_desc __read_mostly = {
+ .prio_base = 0xffd40000,
+ .msk_base = 0xffd40038,
+ .mskclr_base = 0xffd4003c,
+
+ .intc2_data = intc2_irq_table,
+ .nr_irqs = ARRAY_SIZE(intc2_irq_table),
+
+ .chip = {
+ .name = "INTC2-sh7785",
+ },
+};
+
+void __init plat_irq_setup(void)
{
- make_intc2_irq(intc2_irq_table, ARRAY_SIZE(intc2_irq_table));
+ register_intc2_controller(&intc2_irq_desc);
}
+
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
new file mode 100644
index 000000000000..704c064f70dc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -0,0 +1,85 @@
+/*
+ * SH-X3 Setup
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffc30000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .mapbase = 0xffc40000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 44, 45, 47, 46 },
+ }, {
+ .mapbase = 0xffc50000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 48, 49, 51, 50 },
+ }, {
+ .mapbase = 0xffc60000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 52, 53, 55, 54 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *shx3_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init shx3_devices_setup(void)
+{
+ return platform_add_devices(shx3_devices,
+ ARRAY_SIZE(shx3_devices));
+}
+__initcall(shx3_devices_setup);
+
+static struct intc2_data intc2_irq_table[] = {
+ { 16, 0, 0, 0, 1, 2 }, /* TMU0 */
+ { 40, 4, 0, 0x20, 0, 3 }, /* SCIF0 ERI */
+ { 41, 4, 0, 0x20, 1, 3 }, /* SCIF0 RXI */
+ { 42, 4, 0, 0x20, 2, 3 }, /* SCIF0 BRI */
+ { 43, 4, 0, 0x20, 3, 3 }, /* SCIF0 TXI */
+};
+
+static struct intc2_desc intc2_irq_desc __read_mostly = {
+ .prio_base = 0xfe410000,
+ .msk_base = 0xfe410820,
+ .mskclr_base = 0xfe410850,
+
+ .intc2_data = intc2_irq_table,
+ .nr_irqs = ARRAY_SIZE(intc2_irq_table),
+
+ .chip = {
+ .name = "INTC2-SHX3",
+ },
+};
+
+void __init plat_irq_setup(void)
+{
+ register_intc2_controller(&intc2_irq_desc);
+}
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c
index 47abf6e49dfb..e61890217c50 100644
--- a/arch/sh/kernel/cpufreq.c
+++ b/arch/sh/kernel/cpufreq.c
@@ -3,89 +3,46 @@
*
* cpufreq driver for the SuperH processors.
*
- * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
+ * Copyright (C) 2002 - 2007 Paul Mundt
* Copyright (C) 2002 M. R. Brown
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
+ *
+ * Copyright (C) 2004-2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*/
#include <linux/types.h>
#include <linux/cpufreq.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <linux/sched.h> /* set_cpus_allowed() */
+#include <linux/clk.h>
-#include <asm/processor.h>
-#include <asm/watchdog.h>
-#include <asm/freq.h>
-#include <asm/io.h>
-
-/*
- * For SuperH, each policy change requires that we change the IFC, BFC, and
- * PFC at the same time. Here we define sane values that won't trash the
- * system.
- *
- * Note the max set is computed at runtime, we use the divisors that we booted
- * with to setup our maximum operating frequencies.
- */
-struct clock_set {
- unsigned int ifc;
- unsigned int bfc;
- unsigned int pfc;
-} clock_sets[] = {
-#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH2)
- { 0, 0, 0 }, /* not implemented yet */
-#elif defined(CONFIG_CPU_SH4)
- { 4, 8, 8 }, /* min - IFC: 1/4, BFC: 1/8, PFC: 1/8 */
- { 1, 2, 2 }, /* max - IFC: 1, BFC: 1/2, PFC: 1/2 */
-#endif
-};
-
-#define MIN_CLOCK_SET 0
-#define MAX_CLOCK_SET (ARRAY_SIZE(clock_sets) - 1)
-
-/*
- * For the time being, we only support two frequencies, which in turn are
- * aimed at the POWERSAVE and PERFORMANCE policies, which in turn are derived
- * directly from the respective min/max clock sets. Technically we could
- * support a wider range of frequencies, but these vary far too much for each
- * CPU subtype (and we'd have to construct a frequency table for each subtype).
- *
- * Maybe something to implement in the future..
- */
-#define SH_FREQ_MAX 0
-#define SH_FREQ_MIN 1
-
-static struct cpufreq_frequency_table sh_freqs[] = {
- { SH_FREQ_MAX, 0 },
- { SH_FREQ_MIN, 0 },
- { 0, CPUFREQ_TABLE_END },
-};
+static struct clk *cpuclk;
-static void sh_cpufreq_update_clocks(unsigned int set)
+static unsigned int sh_cpufreq_get(unsigned int cpu)
{
- current_cpu_data.cpu_clock = current_cpu_data.master_clock / clock_sets[set].ifc;
- current_cpu_data.bus_clock = current_cpu_data.master_clock / clock_sets[set].bfc;
- current_cpu_data.module_clock = current_cpu_data.master_clock / clock_sets[set].pfc;
- current_cpu_data.loops_per_jiffy = loops_per_jiffy;
+ return (clk_get_rate(cpuclk) + 500) / 1000;
}
-/* XXX: This needs to be split out per CPU and CPU subtype. */
/*
* Here we notify other drivers of the proposed change and the final change.
*/
-static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
+static int sh_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
{
- unsigned short frqcr = ctrl_inw(FRQCR);
+ unsigned int cpu = policy->cpu;
cpumask_t cpus_allowed;
struct cpufreq_freqs freqs;
+ long freq;
if (!cpu_online(cpu))
return -ENODEV;
@@ -95,125 +52,109 @@ static int sh_cpufreq_setstate(unsigned int cpu, unsigned int set)
BUG_ON(smp_processor_id() != cpu);
- freqs.cpu = cpu;
- freqs.old = current_cpu_data.cpu_clock / 1000;
- freqs.new = (current_cpu_data.master_clock / clock_sets[set].ifc) / 1000;
+ /* Convert target_freq from kHz to Hz */
+ freq = clk_round_rate(cpuclk, target_freq * 1000);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-#if defined(CONFIG_CPU_SH3)
- frqcr |= (newstate & 0x4000) << 14;
- frqcr |= (newstate & 0x000c) << 2;
-#elif defined(CONFIG_CPU_SH4)
- /*
- * FRQCR.PLL2EN is 1, we need to allow the PLL to stabilize by
- * initializing the WDT.
- */
- if (frqcr & (1 << 9)) {
- __u8 csr;
-
- /*
- * Set the overflow period to the highest available,
- * in this case a 1/4096 division ratio yields a 5.25ms
- * overflow period. See asm-sh/watchdog.h for more
- * information and a range of other divisors.
- */
- csr = sh_wdt_read_csr();
- csr |= WTCSR_CKS_4096;
- sh_wdt_write_csr(csr);
-
- sh_wdt_write_cnt(0);
- }
- frqcr &= 0x0e00; /* Clear ifc, bfc, pfc */
- frqcr |= get_ifc_value(clock_sets[set].ifc) << 6;
- frqcr |= get_bfc_value(clock_sets[set].bfc) << 3;
- frqcr |= get_pfc_value(clock_sets[set].pfc);
-#endif
- ctrl_outw(frqcr, FRQCR);
- sh_cpufreq_update_clocks(set);
+ if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
+ return -EINVAL;
+
+ pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+ freqs.cpu = cpu;
+ freqs.old = sh_cpufreq_get(cpu);
+ freqs.new = (freq + 500) / 1000;
+ freqs.flags = 0;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
set_cpus_allowed(current, cpus_allowed);
+ clk_set_rate(cpuclk, freq);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ pr_debug("cpufreq: set frequency %lu Hz\n", freq);
+
return 0;
}
static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
- unsigned int min_freq, max_freq;
- unsigned int ifc, bfc, pfc;
+ printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n");
if (!cpu_online(policy->cpu))
return -ENODEV;
- /* Update our maximum clock set */
- get_current_frequency_divisors(&ifc, &bfc, &pfc);
- clock_sets[MAX_CLOCK_SET].ifc = ifc;
- clock_sets[MAX_CLOCK_SET].bfc = bfc;
- clock_sets[MAX_CLOCK_SET].pfc = pfc;
-
- /* Convert from Hz to kHz */
- max_freq = current_cpu_data.cpu_clock / 1000;
- min_freq = (current_cpu_data.master_clock / clock_sets[MIN_CLOCK_SET].ifc) / 1000;
-
- sh_freqs[SH_FREQ_MAX].frequency = max_freq;
- sh_freqs[SH_FREQ_MIN].frequency = min_freq;
+ cpuclk = clk_get(NULL, "cpu_clk");
+ if (IS_ERR(cpuclk)) {
+ printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
+ return PTR_ERR(cpuclk);
+ }
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000;
+ policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
- policy->cur = max_freq;
- return cpufreq_frequency_table_cpuinfo(policy, &sh_freqs[0]);
-}
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ policy->cur = sh_cpufreq_get(policy->cpu);
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
-static int sh_cpufreq_verify(struct cpufreq_policy *policy)
-{
- return cpufreq_frequency_table_verify(policy, &sh_freqs[0]);
-}
-static int sh_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
-{
- unsigned int set, idx = 0;
+ /*
+ * Catch the cases where the clock framework hasn't been wired up
+ * properly to support scaling.
+ */
+ if (unlikely(policy->min == policy->max)) {
+ printk(KERN_ERR "cpufreq: clock framework rate rounding "
+ "not supported on this CPU.\n");
- if (cpufreq_frequency_table_target(policy, &sh_freqs[0], target_freq, relation, &idx))
+ clk_put(cpuclk);
return -EINVAL;
+ }
- set = (idx == SH_FREQ_MIN) ? MIN_CLOCK_SET : MAX_CLOCK_SET;
+ printk(KERN_INFO "cpufreq: Frequencies - Minimum %u.%03u MHz, "
+ "Maximum %u.%03u MHz.\n",
+ policy->min / 1000, policy->min % 1000,
+ policy->max / 1000, policy->max % 1000);
- sh_cpufreq_setstate(policy->cpu, set);
+ return 0;
+}
+static int sh_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ return 0;
+}
+
+static int sh_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ clk_put(cpuclk);
return 0;
}
static struct cpufreq_driver sh_cpufreq_driver = {
.owner = THIS_MODULE,
- .name = "SH cpufreq",
+ .name = "sh",
.init = sh_cpufreq_cpu_init,
.verify = sh_cpufreq_verify,
.target = sh_cpufreq_target,
+ .get = sh_cpufreq_get,
+ .exit = sh_cpufreq_exit,
};
-static int __init sh_cpufreq_init(void)
+static int __init sh_cpufreq_module_init(void)
{
- if (!current_cpu_data.cpu_clock)
- return -EINVAL;
- if (cpufreq_register_driver(&sh_cpufreq_driver))
- return -EINVAL;
-
- return 0;
+ return cpufreq_register_driver(&sh_cpufreq_driver);
}
-static void __exit sh_cpufreq_exit(void)
+static void __exit sh_cpufreq_module_exit(void)
{
cpufreq_unregister_driver(&sh_cpufreq_driver);
}
-module_init(sh_cpufreq_init);
-module_exit(sh_cpufreq_exit);
+module_init(sh_cpufreq_module_init);
+module_exit(sh_cpufreq_module_exit);
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
MODULE_DESCRIPTION("cpufreq driver for SuperH");
MODULE_LICENSE("GPL");
-
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 71a3ad7d283e..0bccc0ca5a0f 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -36,7 +36,8 @@ ENTRY(empty_zero_page)
1:
.skip PAGE_SIZE - empty_zero_page - 1b
- .text
+ .section .text.head, "ax"
+
/*
* Condition at the entry of _stext:
*
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 27b923c45b3d..03404987528d 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -158,15 +158,11 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
}
#ifdef CONFIG_4KSTACKS
-/*
- * These should really be __section__(".bss.page_aligned") as well, but
- * gcc's 3.0 and earlier don't handle that correctly.
- */
static char softirq_stack[NR_CPUS * THREAD_SIZE]
- __attribute__((__aligned__(THREAD_SIZE)));
+ __attribute__((__section__(".bss.page_aligned")));
static char hardirq_stack[NR_CPUS * THREAD_SIZE]
- __attribute__((__aligned__(THREAD_SIZE)));
+ __attribute__((__section__(".bss.page_aligned")));
/*
* allocate per-cpu stacks for hardirq and for softirq processing
@@ -257,14 +253,7 @@ void __init init_IRQ(void)
#ifdef CONFIG_CPU_HAS_PINT_IRQ
init_IRQ_pint();
#endif
-
-#ifdef CONFIG_CPU_HAS_INTC2_IRQ
- init_IRQ_intc2();
-#endif
-
-#ifdef CONFIG_CPU_HAS_IPR_IRQ
- init_IRQ_ipr();
-#endif
+ plat_irq_setup();
/* Perform the machine specific initialisation */
if (sh_mv.mv_init_irq)
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c
new file mode 100644
index 000000000000..23c5948f0124
--- /dev/null
+++ b/arch/sh/kernel/machvec.c
@@ -0,0 +1,130 @@
+/*
+ * arch/sh/kernel/machvec.c
+ *
+ * The SuperH machine vector setup handlers, yanked from setup.c
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2002 - 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <asm/machvec.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define MV_NAME_SIZE 32
+
+#define for_each_mv(mv) \
+ for ((mv) = (struct sh_machine_vector *)&__machvec_start; \
+ (mv) && (unsigned long)(mv) < (unsigned long)&__machvec_end; \
+ (mv)++)
+
+static struct sh_machine_vector * __init get_mv_byname(const char *name)
+{
+ struct sh_machine_vector *mv;
+
+ for_each_mv(mv)
+ if (strcasecmp(name, mv->mv_name) == 0)
+ return mv;
+
+ return NULL;
+}
+
+static unsigned int __initdata machvec_selected;
+
+static int __init early_parse_mv(char *from)
+{
+ char mv_name[MV_NAME_SIZE] = "";
+ char *mv_end;
+ char *mv_comma;
+ int mv_len;
+ struct sh_machine_vector *mvp;
+
+ mv_end = strchr(from, ' ');
+ if (mv_end == NULL)
+ mv_end = from + strlen(from);
+
+ mv_comma = strchr(from, ',');
+ mv_len = mv_end - from;
+ if (mv_len > (MV_NAME_SIZE-1))
+ mv_len = MV_NAME_SIZE-1;
+ memcpy(mv_name, from, mv_len);
+ mv_name[mv_len] = '\0';
+ from = mv_end;
+
+ machvec_selected = 1;
+
+ /* Boot with the generic vector */
+ if (strcmp(mv_name, "generic") == 0)
+ return 0;
+
+ mvp = get_mv_byname(mv_name);
+ if (unlikely(!mvp)) {
+ printk("Available vectors:\n\n\t'%s', ", sh_mv.mv_name);
+ for_each_mv(mvp)
+ printk("'%s', ", mvp->mv_name);
+ printk("\n\n");
+ panic("Failed to select machvec '%s' -- halting.\n",
+ mv_name);
+ } else
+ sh_mv = *mvp;
+
+ return 0;
+}
+early_param("sh_mv", early_parse_mv);
+
+void __init sh_mv_setup(void)
+{
+ /*
+ * Only overload the machvec if one hasn't been selected on
+ * the command line with sh_mv=
+ */
+ if (!machvec_selected) {
+ unsigned long machvec_size;
+
+ machvec_size = ((unsigned long)&__machvec_end -
+ (unsigned long)&__machvec_start);
+
+ /*
+ * If the machvec hasn't been preselected, use the first
+ * vector (usually the only one) from .machvec.init.
+ */
+ if (machvec_size >= sizeof(struct sh_machine_vector))
+ sh_mv = *(struct sh_machine_vector *)&__machvec_start;
+ }
+
+ printk(KERN_NOTICE "Booting machvec: %s\n", get_system_type());
+
+ /*
+ * Manually walk the vec, fill in anything that the board hasn't yet
+ * by hand, wrapping to the generic implementation.
+ */
+#define mv_set(elem) do { \
+ if (!sh_mv.mv_##elem) \
+ sh_mv.mv_##elem = generic_##elem; \
+} while (0)
+
+ mv_set(inb); mv_set(inw); mv_set(inl);
+ mv_set(outb); mv_set(outw); mv_set(outl);
+
+ mv_set(inb_p); mv_set(inw_p); mv_set(inl_p);
+ mv_set(outb_p); mv_set(outw_p); mv_set(outl_p);
+
+ mv_set(insb); mv_set(insw); mv_set(insl);
+ mv_set(outsb); mv_set(outsw); mv_set(outsl);
+
+ mv_set(readb); mv_set(readw); mv_set(readl);
+ mv_set(writeb); mv_set(writew); mv_set(writel);
+
+ mv_set(ioport_map);
+ mv_set(ioport_unmap);
+ mv_set(irq_demux);
+
+ if (!sh_mv.mv_nr_irqs)
+ sh_mv.mv_nr_irqs = NR_IRQS;
+}
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index a11e2aa73cbc..6334a4c54c7c 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -17,6 +17,7 @@
#include <linux/kexec.h>
#include <linux/kdebug.h>
#include <linux/tick.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/pgalloc.h>
@@ -319,9 +320,7 @@ static void ubc_set_tracing(int asid, unsigned long pc)
ctrl_outl(pc, UBC_BARA);
#ifdef CONFIG_MMU
- /* We don't have any ASID settings for the SH-2! */
- if (current_cpu_data.type != CPU_SH7604)
- ctrl_outb(asid, UBC_BASRA);
+ ctrl_outb(asid, UBC_BASRA);
#endif
ctrl_outl(0, UBC_BAMRA);
@@ -405,8 +404,8 @@ asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs __regs)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
#ifdef CONFIG_MMU
+ struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
#else
/* fork almost works, enough to trick you into looking elsewhere :-( */
@@ -449,23 +448,20 @@ asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
/*
* sys_execve() executes a new program.
*/
-asmlinkage int sys_execve(char *ufilename, char **uargv,
- char **uenvp, unsigned long r7,
+asmlinkage int sys_execve(char __user *ufilename, char __user * __user *uargv,
+ char __user * __user *uenvp, unsigned long r7,
struct pt_regs __regs)
{
struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
int error;
char *filename;
- filename = getname((char __user *)ufilename);
+ filename = getname(ufilename);
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
- error = do_execve(filename,
- (char __user * __user *)uargv,
- (char __user * __user *)uenvp,
- regs);
+ error = do_execve(filename, uargv, uenvp, regs);
if (error == 0) {
task_lock(current);
current->ptrace &= ~PT_DTRACE;
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
index 3fb5fc0b550d..891d1d46c902 100644
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace.c
@@ -91,17 +91,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long *) data);
- break;
- }
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -128,17 +119,14 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
tmp = !!tsk_used_math(child);
else
tmp = 0;
- ret = put_user(tmp, (unsigned long *)data);
+ ret = put_user(tmp, (unsigned long __user *)data);
break;
}
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
@@ -196,7 +184,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_SINGLESTEP: { /* set the trap flag. */
long pc;
- struct pt_regs *dummy = NULL;
+ struct pt_regs *regs = NULL;
ret = -EIO;
if (!valid_signal(data))
@@ -207,7 +195,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
child->ptrace |= PT_DTRACE;
}
- pc = get_stack_long(child, (long)&dummy->pc);
+ pc = get_stack_long(child, (long)&regs->pc);
/* Next scheduling will set up UBC */
if (child->thread.ubc_pc == 0)
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index c27729135935..c14a3e95d0b1 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -21,8 +21,10 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/kexec.h>
+#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <asm/page.h>
#include <asm/sections.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -41,20 +43,19 @@ extern void * __rd_start, * __rd_end;
* The bigger value means no problem.
*/
struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, };
+
+/*
+ * The machine vector. First entry in .machvec.init, or clobbered by
+ * sh_mv= on the command line, prior to .machvec.init teardown.
+ */
+struct sh_machine_vector sh_mv = { .mv_name = "generic", };
+
#ifdef CONFIG_VT
struct screen_info screen_info;
#endif
-#if defined(CONFIG_SH_UNKNOWN)
-struct sh_machine_vector sh_mv;
-#endif
-
extern int root_mountflags;
-#define MV_NAME_SIZE 32
-
-static struct sh_machine_vector* __init get_mv_byname(const char* name);
-
/*
* This is set up by the setup-routine at boot-time
*/
@@ -78,133 +79,23 @@ static char __initdata command_line[COMMAND_LINE_SIZE] = { 0, };
static struct resource code_resource = { .name = "Kernel code", };
static struct resource data_resource = { .name = "Kernel data", };
-unsigned long memory_start, memory_end;
+unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
-static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
- struct sh_machine_vector** mvp,
- unsigned long *mv_io_base)
-{
- char c = ' ', *to = command_line, *from = COMMAND_LINE;
- int len = 0;
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
- /* Save unparsed command line copy for /proc/cmdline */
- memcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
- boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
-
- memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
- memory_end = memory_start + __MEMORY_SIZE;
-
- for (;;) {
- /*
- * "mem=XXX[kKmM]" defines a size of memory.
- */
- if (c == ' ' && !memcmp(from, "mem=", 4)) {
- if (to != command_line)
- to--;
- {
- unsigned long mem_size;
-
- mem_size = memparse(from+4, &from);
- memory_end = memory_start + mem_size;
- }
- }
-
- if (c == ' ' && !memcmp(from, "sh_mv=", 6)) {
- char* mv_end;
- char* mv_comma;
- int mv_len;
- if (to != command_line)
- to--;
- from += 6;
- mv_end = strchr(from, ' ');
- if (mv_end == NULL)
- mv_end = from + strlen(from);
-
- mv_comma = strchr(from, ',');
- if ((mv_comma != NULL) && (mv_comma < mv_end)) {
- int ints[3];
- get_options(mv_comma+1, ARRAY_SIZE(ints), ints);
- *mv_io_base = ints[1];
- mv_len = mv_comma - from;
- } else {
- mv_len = mv_end - from;
- }
- if (mv_len > (MV_NAME_SIZE-1))
- mv_len = MV_NAME_SIZE-1;
- memcpy(mv_name, from, mv_len);
- mv_name[mv_len] = '\0';
- from = mv_end;
-
- *mvp = get_mv_byname(mv_name);
- }
-
- c = *(from++);
- if (!c)
- break;
- if (COMMAND_LINE_SIZE <= ++len)
- break;
- *(to++) = c;
- }
- *to = '\0';
- *cmdline_p = command_line;
-}
-
-static int __init sh_mv_setup(char **cmdline_p)
+static int __init early_parse_mem(char *p)
{
-#ifdef CONFIG_SH_UNKNOWN
- extern struct sh_machine_vector mv_unknown;
-#endif
- struct sh_machine_vector *mv = NULL;
- char mv_name[MV_NAME_SIZE] = "";
- unsigned long mv_io_base = 0;
-
- parse_cmdline(cmdline_p, mv_name, &mv, &mv_io_base);
-
-#ifdef CONFIG_SH_UNKNOWN
- if (mv == NULL) {
- mv = &mv_unknown;
- if (*mv_name != '\0') {
- printk("Warning: Unsupported machine %s, using unknown\n",
- mv_name);
- }
- }
- sh_mv = *mv;
-#endif
-
- /*
- * Manually walk the vec, fill in anything that the board hasn't yet
- * by hand, wrapping to the generic implementation.
- */
-#define mv_set(elem) do { \
- if (!sh_mv.mv_##elem) \
- sh_mv.mv_##elem = generic_##elem; \
-} while (0)
-
- mv_set(inb); mv_set(inw); mv_set(inl);
- mv_set(outb); mv_set(outw); mv_set(outl);
-
- mv_set(inb_p); mv_set(inw_p); mv_set(inl_p);
- mv_set(outb_p); mv_set(outw_p); mv_set(outl_p);
-
- mv_set(insb); mv_set(insw); mv_set(insl);
- mv_set(outsb); mv_set(outsw); mv_set(outsl);
-
- mv_set(readb); mv_set(readw); mv_set(readl);
- mv_set(writeb); mv_set(writew); mv_set(writel);
+ unsigned long size;
- mv_set(ioport_map);
- mv_set(ioport_unmap);
- mv_set(irq_demux);
-
-#ifdef CONFIG_SH_UNKNOWN
- __set_io_port_base(mv_io_base);
-#endif
-
- if (!sh_mv.mv_nr_irqs)
- sh_mv.mv_nr_irqs = NR_IRQS;
+ memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
+ size = memparse(p, &p);
+ memory_end = memory_start + size;
return 0;
}
+early_param("mem", early_parse_mem);
/*
* Register fully available low RAM pages with the bootmem allocator.
@@ -230,7 +121,7 @@ static void __init register_bootmem_low_pages(void)
free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(pages));
}
-void __init setup_bootmem_allocator(unsigned long start_pfn)
+void __init setup_bootmem_allocator(unsigned long free_pfn)
{
unsigned long bootmap_size;
@@ -239,9 +130,10 @@ void __init setup_bootmem_allocator(unsigned long start_pfn)
* bootstrap step all allocations (until the page allocator
* is intact) must be done via bootmem_alloc().
*/
- bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn,
+ bootmap_size = init_bootmem_node(NODE_DATA(0), free_pfn,
min_low_pfn, max_low_pfn);
+ add_active_range(0, min_low_pfn, max_low_pfn);
register_bootmem_low_pages();
node_set_online(0);
@@ -254,7 +146,7 @@ void __init setup_bootmem_allocator(unsigned long start_pfn)
* an invalid RAM area.
*/
reserve_bootmem(__MEMORY_START+PAGE_SIZE,
- (PFN_PHYS(start_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
+ (PFN_PHYS(free_pfn)+bootmap_size+PAGE_SIZE-1)-__MEMORY_START);
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
@@ -262,6 +154,8 @@ void __init setup_bootmem_allocator(unsigned long start_pfn)
*/
reserve_bootmem(__MEMORY_START, PAGE_SIZE);
+ sparse_memory_present_with_active_regions(0);
+
#ifdef CONFIG_BLK_DEV_INITRD
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
if (&__rd_start != &__rd_end) {
@@ -315,10 +209,6 @@ void __init setup_arch(char **cmdline_p)
{
enable_mmu();
-#ifdef CONFIG_CMDLINE_BOOL
- strcpy(COMMAND_LINE, CONFIG_CMDLINE);
-#endif
-
ROOT_DEV = old_decode_dev(ORIG_ROOT_DEV);
#ifdef CONFIG_BLK_DEV_RAM
@@ -339,9 +229,22 @@ void __init setup_arch(char **cmdline_p)
data_resource.start = virt_to_phys(_etext);
data_resource.end = virt_to_phys(_edata)-1;
+ memory_start = (unsigned long)PAGE_OFFSET+__MEMORY_START;
+ memory_end = memory_start + __MEMORY_SIZE;
+
+#ifdef CONFIG_CMDLINE_BOOL
+ strlcpy(command_line, CONFIG_CMDLINE, sizeof(command_line));
+#else
+ strlcpy(command_line, COMMAND_LINE, sizeof(command_line));
+#endif
+
+ /* Save unparsed command line copy for /proc/cmdline */
+ memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
+ *cmdline_p = command_line;
+
parse_early_param();
- sh_mv_setup(cmdline_p);
+ sh_mv_setup();
/*
* Find the highest page frame number we have available
@@ -355,8 +258,9 @@ void __init setup_arch(char **cmdline_p)
min_low_pfn = __MEMORY_START >> PAGE_SHIFT;
nodes_clear(node_online_map);
+
+ /* Setup bootmem with available RAM */
setup_memory();
- paging_init();
sparse_init();
#ifdef CONFIG_DUMMY_CONSOLE
@@ -366,46 +270,13 @@ void __init setup_arch(char **cmdline_p)
/* Perform the machine specific initialisation */
if (likely(sh_mv.mv_setup))
sh_mv.mv_setup(cmdline_p);
-}
-
-struct sh_machine_vector* __init get_mv_byname(const char* name)
-{
- extern long __machvec_start, __machvec_end;
- struct sh_machine_vector *all_vecs =
- (struct sh_machine_vector *)&__machvec_start;
-
- int i, n = ((unsigned long)&__machvec_end
- - (unsigned long)&__machvec_start)/
- sizeof(struct sh_machine_vector);
-
- for (i = 0; i < n; ++i) {
- struct sh_machine_vector *mv = &all_vecs[i];
- if (mv == NULL)
- continue;
- if (strcasecmp(name, get_system_type()) == 0) {
- return mv;
- }
- }
- return NULL;
-}
-
-static struct cpu cpu[NR_CPUS];
-
-static int __init topology_init(void)
-{
- int cpu_id;
- for_each_possible_cpu(cpu_id)
- register_cpu(&cpu[cpu_id], cpu_id);
-
- return 0;
+ paging_init();
}
-subsys_initcall(topology_init);
-
static const char *cpu_name[] = {
[CPU_SH7206] = "SH7206", [CPU_SH7619] = "SH7619",
- [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300",
+ [CPU_SH7300] = "SH7300",
[CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
[CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
[CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
@@ -419,7 +290,7 @@ static const char *cpu_name[] = {
[CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
[CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
[CPU_SH7785] = "SH7785", [CPU_SH7722] = "SH7722",
- [CPU_SH_NONE] = "Unknown"
+ [CPU_SHX3] = "SH-X3", [CPU_SH_NONE] = "Unknown"
};
const char *get_cpu_subtype(struct sh_cpuinfo *c)
diff --git a/arch/sh/kernel/sh_bios.c b/arch/sh/kernel/sh_bios.c
index 5b53e10bb9cd..d1bcac4fa269 100644
--- a/arch/sh/kernel/sh_bios.c
+++ b/arch/sh/kernel/sh_bios.c
@@ -5,7 +5,7 @@
* Copyright (C) 2000 Greg Banks, Mitch Davis
*
*/
-
+#include <linux/module.h>
#include <asm/sh_bios.h>
#define BIOS_CALL_CONSOLE_WRITE 0
@@ -63,6 +63,7 @@ void sh_bios_gdb_detach(void)
{
sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
}
+EXPORT_SYMBOL(sh_bios_gdb_detach);
void sh_bios_get_node_addr (unsigned char *node_addr)
{
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index c1cfcb9f047c..37aef0a85197 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -63,10 +63,43 @@ EXPORT_SYMBOL(__const_udelay);
/* These symbols are generated by the compiler itself */
DECLARE_EXPORT(__udivsi3);
DECLARE_EXPORT(__sdivsi3);
+DECLARE_EXPORT(__ashrsi3);
+DECLARE_EXPORT(__ashlsi3);
DECLARE_EXPORT(__ashrdi3);
DECLARE_EXPORT(__ashldi3);
+DECLARE_EXPORT(__ashiftrt_r4_6);
+DECLARE_EXPORT(__ashiftrt_r4_7);
+DECLARE_EXPORT(__ashiftrt_r4_8);
+DECLARE_EXPORT(__ashiftrt_r4_9);
+DECLARE_EXPORT(__ashiftrt_r4_10);
+DECLARE_EXPORT(__ashiftrt_r4_11);
+DECLARE_EXPORT(__ashiftrt_r4_12);
+DECLARE_EXPORT(__ashiftrt_r4_13);
+DECLARE_EXPORT(__ashiftrt_r4_14);
+DECLARE_EXPORT(__ashiftrt_r4_15);
+DECLARE_EXPORT(__ashiftrt_r4_20);
+DECLARE_EXPORT(__ashiftrt_r4_21);
+DECLARE_EXPORT(__ashiftrt_r4_22);
+DECLARE_EXPORT(__ashiftrt_r4_23);
+DECLARE_EXPORT(__ashiftrt_r4_24);
+DECLARE_EXPORT(__ashiftrt_r4_27);
+DECLARE_EXPORT(__ashiftrt_r4_30);
+DECLARE_EXPORT(__lshrsi3);
DECLARE_EXPORT(__lshrdi3);
+DECLARE_EXPORT(__movstrSI8);
+DECLARE_EXPORT(__movstrSI12);
DECLARE_EXPORT(__movstrSI16);
+DECLARE_EXPORT(__movstrSI20);
+DECLARE_EXPORT(__movstrSI24);
+DECLARE_EXPORT(__movstrSI28);
+DECLARE_EXPORT(__movstrSI32);
+DECLARE_EXPORT(__movstrSI36);
+DECLARE_EXPORT(__movstrSI40);
+DECLARE_EXPORT(__movstrSI44);
+DECLARE_EXPORT(__movstrSI48);
+DECLARE_EXPORT(__movstrSI52);
+DECLARE_EXPORT(__movstrSI56);
+DECLARE_EXPORT(__movstrSI60);
#if __GNUC__ == 4
DECLARE_EXPORT(__movmem);
#else
@@ -78,6 +111,16 @@ DECLARE_EXPORT(__movstr);
DECLARE_EXPORT(__movmem_i4_even);
DECLARE_EXPORT(__movmem_i4_odd);
DECLARE_EXPORT(__movmemSI12_i4);
+
+#if (__GNUC_MINOR__ == 2 || defined(__GNUC_STM_RELEASE__))
+/*
+ * GCC 4.2 emits these for division, as do GCC 4.1.x versions of the ST
+ * compiler which include backported patches.
+ */
+DECLARE_EXPORT(__sdivsi3_i4i);
+DECLARE_EXPORT(__udiv_qrnnd_16);
+DECLARE_EXPORT(__udivsi3_i4i);
+#endif
#else /* GCC 3.x */
DECLARE_EXPORT(__movstr_i4_even);
DECLARE_EXPORT(__movstr_i4_odd);
@@ -105,7 +148,9 @@ EXPORT_SYMBOL(synchronize_irq);
#endif
EXPORT_SYMBOL(csum_partial);
+EXPORT_SYMBOL(csum_partial_copy_generic);
#ifdef CONFIG_IPV6
EXPORT_SYMBOL(csum_ipv6_magic);
#endif
EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(__clear_user);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index e323e299878b..706d81ccd101 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -23,6 +23,7 @@
#include <linux/personality.h>
#include <linux/binfmts.h>
#include <linux/freezer.h>
+#include <linux/io.h>
#include <asm/system.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>
@@ -261,7 +262,7 @@ asmlinkage int sys_rt_sigreturn(unsigned long r4, unsigned long r5,
goto badframe;
/* It is more difficult to avoid calling this function than to
call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs->regs[15]);
+ do_sigaltstack((const stack_t __user *)&st, NULL, (unsigned long)frame);
return r0;
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index 7db1c2dc5992..91fb7024e06f 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -308,9 +308,9 @@ ENTRY(sys_call_table)
.long sys_utimes
.long sys_fadvise64_64_wrapper
.long sys_ni_syscall /* Reserved for vserver */
- .long sys_ni_syscall /* Reserved for mbind */
- .long sys_ni_syscall /* 275 - get_mempolicy */
- .long sys_ni_syscall /* set_mempolicy */
+ .long sys_mbind
+ .long sys_get_mempolicy /* 275 */
+ .long sys_set_mempolicy
.long sys_mq_open
.long sys_mq_unlink
.long sys_mq_timedsend
@@ -358,3 +358,4 @@ ENTRY(sys_call_table)
.long sys_signalfd
.long sys_timerfd
.long sys_eventfd
+ .long sys_fallocate
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index 2d997e2a5b6c..7aca37d79766 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -30,7 +30,7 @@
static int tmu_timer_start(void)
{
- ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
+ ctrl_outb(ctrl_inb(TMU_012_TSTR) | 0x3, TMU_012_TSTR);
return 0;
}
@@ -52,7 +52,7 @@ static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
static int tmu_timer_stop(void)
{
- ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
+ ctrl_outb(ctrl_inb(TMU_012_TSTR) & ~0x3, TMU_012_TSTR);
return 0;
}
@@ -80,6 +80,7 @@ static void tmu_set_mode(enum clock_event_mode mode,
break;
case CLOCK_EVT_MODE_UNUSED:
case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
break;
}
}
@@ -174,7 +175,8 @@ static int tmu_timer_init(void)
#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
!defined(CONFIG_CPU_SUBTYPE_SH7760) && \
- !defined(CONFIG_CPU_SUBTYPE_SH7785)
+ !defined(CONFIG_CPU_SUBTYPE_SH7785) && \
+ !defined(CONFIG_CPU_SUBTYPE_SHX3)
ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
#endif
diff --git a/arch/sh/kernel/topology.c b/arch/sh/kernel/topology.c
new file mode 100644
index 000000000000..9b5844a1bdaa
--- /dev/null
+++ b/arch/sh/kernel/topology.c
@@ -0,0 +1,49 @@
+/*
+ * arch/sh/kernel/topology.c
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/node.h>
+#include <linux/nodemask.h>
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+
+static int __init topology_init(void)
+{
+ int i, ret;
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+ for_each_online_node(i)
+ register_one_node(i);
+#endif
+
+ for_each_present_cpu(i) {
+ ret = register_cpu(&per_cpu(cpu_devices, i), i);
+ if (unlikely(ret))
+ printk(KERN_WARNING "%s: register_cpu %d failed (%d)\n",
+ __FUNCTION__, i, ret);
+ }
+
+#if defined(CONFIG_NUMA) && !defined(CONFIG_SMP)
+ /*
+ * In the UP case, make sure the CPU association is still
+ * registered under each node. Without this, sysfs fails
+ * to make the connection between nodes other than node0
+ * and cpu0.
+ */
+ for_each_online_node(i)
+ if (i != numa_node_id())
+ register_cpu_under_node(raw_smp_processor_id(), i);
+#endif
+
+ return 0;
+}
+subsys_initcall(topology_init);
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 8f18930d5bf8..502d43e4785c 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -103,6 +103,7 @@ void die(const char * str, struct pt_regs * regs, long err)
(unsigned long)task_stack_page(current));
bust_spinlocks(0);
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
if (kexec_should_crash(current))
@@ -584,7 +585,7 @@ uspace_segv:
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = si_code;
- info.si_addr = (void *) address;
+ info.si_addr = (void __user *)address;
force_sig_info(SIGBUS, &info, current);
} else {
if (regs->pc & 1)
@@ -617,7 +618,7 @@ uspace_segv:
*/
int is_dsp_inst(struct pt_regs *regs)
{
- unsigned short inst;
+ unsigned short inst = 0;
/*
* Safe guard if DSP mode is already enabled or we're lacking
@@ -645,7 +646,6 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs __regs)
{
- struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
siginfo_t info;
switch (r4) {
@@ -874,7 +874,7 @@ void __init trap_init(void)
void handle_BUG(struct pt_regs *regs)
{
enum bug_trap_type tt;
- tt = report_bug(regs->pc);
+ tt = report_bug(regs->pc, regs);
if (tt == BUG_TRAP_TYPE_WARN) {
regs->pc += 2;
return;
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 4c5b57e9c3c1..9cb95af7b090 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -22,6 +22,7 @@ SECTIONS
*(.empty_zero_page)
} = 0
.text : {
+ *(.text.head)
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
@@ -60,10 +61,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
__nosave_end = .;
- . = ALIGN(PAGE_SIZE);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(PAGE_SIZE)
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
_edata = .; /* End of data section */
@@ -97,18 +95,20 @@ SECTIONS
__initramfs_end = .;
#endif
+ . = ALIGN(4);
__machvec_start = .;
- .init.machvec : { *(.init.machvec) }
+ .machvec.init : { *(.machvec.init) }
__machvec_end = .;
- . = ALIGN(PAGE_SIZE);
- __init_end = .;
-
- . = ALIGN(4);
- __bss_start = .; /* BSS */
- .bss : { *(.bss) }
- . = ALIGN(4);
- _end = . ;
+ . = ALIGN(PAGE_SIZE);
+ .bss : {
+ __init_end = .;
+ __bss_start = .; /* BSS */
+ *(.bss.page_aligned)
+ *(.bss)
+ . = ALIGN(4);
+ _end = . ;
+ }
/* When something in the kernel is NOT compiled as a module, the
* module cleanup code and data are put into these segments. Both
diff --git a/arch/sh/lib/div64-generic.c b/arch/sh/lib/div64-generic.c
index c02473afd581..4bef3b5d964a 100644
--- a/arch/sh/lib/div64-generic.c
+++ b/arch/sh/lib/div64-generic.c
@@ -4,16 +4,15 @@
#include <linux/types.h>
-extern u64 __xdiv64_32(u64 n, u32 d);
+extern uint64_t __xdiv64_32(u64 n, u32 d);
-u64 __div64_32(u64 *xp, u32 y)
+uint32_t __div64_32(u64 *xp, u32 y)
{
- u64 rem;
- u64 q = __xdiv64_32(*xp, y);
+ uint32_t rem;
+ uint64_t q = __xdiv64_32(*xp, y);
rem = *xp - q * y;
*xp = q;
return rem;
}
-
diff --git a/arch/sh/lib/div64.S b/arch/sh/lib/div64.S
index eefc275d64a7..5ee7334ea64f 100644
--- a/arch/sh/lib/div64.S
+++ b/arch/sh/lib/div64.S
@@ -1,12 +1,12 @@
/*
- * unsigned long long __xdiv64_32(unsigned long long n, unsigned long d);
+ * unsigned long __xdiv64_32(unsigned long long n, unsigned long d);
*/
#include <linux/linkage.h>
.text
ENTRY(__xdiv64_32)
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
mov r4, r0
mov r5, r1
#else
@@ -34,7 +34,7 @@ ENTRY(__xdiv64_32)
rotcl r0
div1 r6, r1
.endr
-#ifdef __LITTLE_ENDIAN__
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
mov r2, r1
rts
rotcl r0
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
index a38e1eed9e77..ac2d7abd2567 100644
--- a/arch/sh/math-emu/math.c
+++ b/arch/sh/math-emu/math.c
@@ -507,6 +507,7 @@ static int ieee_fpe_handler(struct pt_regs *regs)
unsigned short insn = *(unsigned short *)regs->pc;
unsigned short finsn;
unsigned long nextpc;
+ siginfo_t info;
int nib[4] = {
(insn >> 12) & 0xf,
(insn >> 8) & 0xf,
@@ -559,9 +560,11 @@ static int ieee_fpe_handler(struct pt_regs *regs)
~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
set_tsk_thread_flag(tsk, TIF_USEDFPU);
} else {
- tsk->thread.trap_no = 11;
- tsk->thread.error_code = 0;
- force_sig(SIGFPE, tsk);
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = FPE_FLTINV;
+ info.si_addr = (void __user *)regs->pc;
+ force_sig_info(SIGFPE, &info, tsk);
}
regs->pc = nextpc;
@@ -576,14 +579,17 @@ asmlinkage void do_fpu_error(unsigned long r4, unsigned long r5,
struct pt_regs regs)
{
struct task_struct *tsk = current;
+ siginfo_t info;
if (ieee_fpe_handler (&regs))
return;
regs.pc += 2;
- tsk->thread.trap_no = 11;
- tsk->thread.error_code = 0;
- force_sig(SIGFPE, tsk);
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = FPE_FLTINV;
+ info.si_addr = (void __user *)regs.pc;
+ force_sig_info(SIGFPE, &info, tsk);
}
/**
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 253346d7b316..70da1c8d407e 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -1,5 +1,3 @@
-menu "Processor selection"
-
#
# Processor families
#
@@ -38,27 +36,31 @@ config CPU_SUBTYPE_ST40
config CPU_SHX2
bool
+config CPU_SHX3
+ bool
+
+choice
+ prompt "Processor sub-type selection"
+
#
# Processor subtypes
#
-comment "SH-2 Processor Support"
-
-config CPU_SUBTYPE_SH7604
- bool "Support SH7604 processor"
- select CPU_SH2
+# SH-2 Processor Support
config CPU_SUBTYPE_SH7619
bool "Support SH7619 processor"
select CPU_SH2
+ select CPU_HAS_IPR_IRQ
-comment "SH-2A Processor Support"
+# SH-2A Processor Support
config CPU_SUBTYPE_SH7206
bool "Support SH7206 processor"
select CPU_SH2A
+ select CPU_HAS_IPR_IRQ
-comment "SH-3 Processor Support"
+# SH-3 Processor Support
config CPU_SUBTYPE_SH7300
bool "Support SH7300 processor"
@@ -113,19 +115,19 @@ config CPU_SUBTYPE_SH7712
help
Select SH7712 if you have a SH3-DSP SH7712 CPU.
-comment "SH-4 Processor Support"
+# SH-4 Processor Support
config CPU_SUBTYPE_SH7750
bool "Support SH7750 processor"
select CPU_SH4
- select CPU_HAS_IPR_IRQ
+ select CPU_HAS_INTC_IRQ
help
Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
config CPU_SUBTYPE_SH7091
bool "Support SH7091 processor"
select CPU_SH4
- select CPU_SUBTYPE_SH7750
+ select CPU_HAS_INTC_IRQ
help
Select SH7091 if you have an SH-4 based Sega device (such as
the Dreamcast, Naomi, and Naomi 2).
@@ -133,19 +135,17 @@ config CPU_SUBTYPE_SH7091
config CPU_SUBTYPE_SH7750R
bool "Support SH7750R processor"
select CPU_SH4
- select CPU_SUBTYPE_SH7750
- select CPU_HAS_IPR_IRQ
+ select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7750S
bool "Support SH7750S processor"
select CPU_SH4
- select CPU_SUBTYPE_SH7750
- select CPU_HAS_IPR_IRQ
+ select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7751
bool "Support SH7751 processor"
select CPU_SH4
- select CPU_HAS_IPR_IRQ
+ select CPU_HAS_INTC_IRQ
help
Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
or if you have a HD6417751R CPU.
@@ -153,8 +153,7 @@ config CPU_SUBTYPE_SH7751
config CPU_SUBTYPE_SH7751R
bool "Support SH7751R processor"
select CPU_SH4
- select CPU_SUBTYPE_SH7751
- select CPU_HAS_IPR_IRQ
+ select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7760
bool "Support SH7760 processor"
@@ -166,7 +165,7 @@ config CPU_SUBTYPE_SH4_202
bool "Support SH4-202 processor"
select CPU_SH4
-comment "ST40 Processor Support"
+# ST40 Processor Support
config CPU_SUBTYPE_ST40STB1
bool "Support ST40STB1/ST40RA processors"
@@ -181,7 +180,7 @@ config CPU_SUBTYPE_ST40GX1
help
Select ST40GX1 if you have a ST40GX1 CPU.
-comment "SH-4A Processor Support"
+# SH-4A Processor Support
config CPU_SUBTYPE_SH7770
bool "Support SH7770 processor"
@@ -190,7 +189,7 @@ config CPU_SUBTYPE_SH7770
config CPU_SUBTYPE_SH7780
bool "Support SH7780 processor"
select CPU_SH4A
- select CPU_HAS_INTC2_IRQ
+ select CPU_HAS_INTC_IRQ
config CPU_SUBTYPE_SH7785
bool "Support SH7785 processor"
@@ -198,7 +197,13 @@ config CPU_SUBTYPE_SH7785
select CPU_SHX2
select CPU_HAS_INTC2_IRQ
-comment "SH4AL-DSP Processor Support"
+config CPU_SUBTYPE_SHX3
+ bool "Support SH-X3 processor"
+ select CPU_SH4A
+ select CPU_SHX3
+ select CPU_HAS_INTC2_IRQ
+
+# SH4AL-DSP Processor Support
config CPU_SUBTYPE_SH73180
bool "Support SH73180 processor"
@@ -212,9 +217,11 @@ config CPU_SUBTYPE_SH7722
bool "Support SH7722 processor"
select CPU_SH4AL_DSP
select CPU_SHX2
- select CPU_HAS_IPR_IRQ
+ select CPU_HAS_INTC_IRQ
+ select ARCH_SPARSEMEM_ENABLE
+ select SYS_SUPPORTS_NUMA
-endmenu
+endchoice
menu "Memory management options"
@@ -266,7 +273,7 @@ config MEMORY_SIZE
config 32BIT
bool "Support 32-bit physical addressing through PMB"
- depends on CPU_SH4A && MMU && (!X2TLB || BROKEN)
+ depends on MMU && (CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785)
default y
help
If you say Y here, physical addressing will be extended to
@@ -295,6 +302,17 @@ config VSYSCALL
For systems with an MMU that can afford to give up a page,
(the default value) say Y.
+config NUMA
+ bool "Non Uniform Memory Access (NUMA) Support"
+ depends on MMU && SYS_SUPPORTS_NUMA && EXPERIMENTAL
+ default n
+ help
+ Some SH systems have many various memories scattered around
+ the address space, each with varying latencies. This enables
+ support for these blocks by binding them to nodes and allowing
+ memory policies to be used for prioritizing and controlling
+ allocation behaviour.
+
config NODES_SHIFT
int
default "1"
@@ -302,14 +320,34 @@ config NODES_SHIFT
config ARCH_FLATMEM_ENABLE
def_bool y
+ depends on !NUMA
+
+config ARCH_SPARSEMEM_ENABLE
+ def_bool y
+ select SPARSEMEM_STATIC
+
+config ARCH_SPARSEMEM_DEFAULT
+ def_bool y
config MAX_ACTIVE_REGIONS
int
+ default "2" if (CPU_SUBTYPE_SH7722 && SPARSEMEM)
default "1"
config ARCH_POPULATES_NODE_MAP
def_bool y
+config ARCH_SELECT_MEMORY_MODEL
+ def_bool y
+
+config ARCH_ENABLE_MEMORY_HOTPLUG
+ def_bool y
+ depends on SPARSEMEM
+
+config ARCH_MEMORY_PROBE
+ def_bool y
+ depends on MEMORY_HOTPLUG
+
choice
prompt "Kernel page size"
default PAGE_SIZE_4KB
@@ -394,15 +432,4 @@ config SH_WRITETHROUGH
If unsure, say N.
-config SH_OCRAM
- bool "Operand Cache RAM (OCRAM) support"
- help
- Selecting this option will automatically tear down the number of
- sets in the dcache by half, which in turn exposes a memory range.
-
- The addresses for the OC RAM base will vary according to the
- processor version. Consult vendor documentation for specifics.
-
- If unsure, say N.
-
endmenu
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 3ffd7f68c0a2..d677d7f3afc1 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -8,9 +8,6 @@ obj-$(CONFIG_CPU_SH2) += cache-sh2.o
obj-$(CONFIG_CPU_SH3) += cache-sh3.o
obj-$(CONFIG_CPU_SH4) += cache-sh4.o
-obj-$(CONFIG_DMA_PAGE_OPS) += pg-dma.o
-obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
-
mmu-y := fault-nommu.o tlb-nommu.o pg-nommu.o
mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \
ioremap.o
@@ -27,5 +24,7 @@ obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o
obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
endif
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
obj-$(CONFIG_32BIT) += pmb.o
+obj-$(CONFIG_NUMA) += numa.o
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index c878faa4ae46..964c6767dc73 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -32,8 +32,8 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
struct task_struct *tsk;
struct mm_struct *mm;
struct vm_area_struct * vma;
- unsigned long page;
int si_code;
+ int fault;
siginfo_t info;
trace_hardirqs_on();
@@ -125,20 +125,18 @@ good_area:
* the fault.
*/
survive:
- switch (handle_mm_fault(mm, vma, address, writeaccess)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
+ fault = handle_mm_fault(mm, vma, address, writeaccess);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
goto out_of_memory;
- default:
- BUG();
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
up_read(&mm->mmap_sem);
return;
@@ -170,24 +168,38 @@ no_context:
* terminate things with extreme prejudice.
*
*/
- if (address < PAGE_SIZE)
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- else
- printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n", address);
- printk(KERN_ALERT "pc = %08lx\n", regs->pc);
- page = (unsigned long)get_TTB();
- if (page) {
- page = ((unsigned long *) page)[address >> PGDIR_SHIFT];
- printk(KERN_ALERT "*pde = %08lx\n", page);
- if (page & _PAGE_PRESENT) {
- page &= PAGE_MASK;
- address &= 0x003ff000;
- page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
- printk(KERN_ALERT "*pte = %08lx\n", page);
+
+ bust_spinlocks(1);
+
+ if (oops_may_print()) {
+ __typeof__(pte_val(__pte(0))) page;
+
+ if (address < PAGE_SIZE)
+ printk(KERN_ALERT "Unable to handle kernel NULL "
+ "pointer dereference");
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging "
+ "request");
+ printk(" at virtual address %08lx\n", address);
+ printk(KERN_ALERT "pc = %08lx\n", regs->pc);
+ page = (unsigned long)get_TTB();
+ if (page) {
+ page = ((__typeof__(page) *) __va(page))[address >>
+ PGDIR_SHIFT];
+ printk(KERN_ALERT "*pde = %08lx\n", page);
+ if (page & _PAGE_PRESENT) {
+ page &= PAGE_MASK;
+ address &= 0x003ff000;
+ page = ((__typeof__(page) *)
+ __va(page))[address >>
+ PAGE_SHIFT];
+ printk(KERN_ALERT "*pte = %08lx\n", page);
+ }
}
}
+
die("Oops", regs, writeaccess);
+ bust_spinlocks(0);
do_exit(SIGKILL);
/*
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index e0e644ff3204..82b68c789a5f 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -18,6 +18,7 @@
#include <asm/mmu_context.h>
#include <asm/tlb.h>
#include <asm/cacheflush.h>
+#include <asm/sections.h>
#include <asm/cache.h>
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -36,14 +37,11 @@ void show_mem(void)
show_free_areas();
for_each_online_pgdat(pgdat) {
- struct page *page, *end;
- unsigned long flags;
+ unsigned long flags, i;
pgdat_resize_lock(pgdat, &flags);
- page = pgdat->node_mem_map;
- end = page + pgdat->node_spanned_pages;
-
- do {
+ for (i = 0; i < pgdat->node_spanned_pages; i++) {
+ struct page *page = pgdat_page_nr(pgdat, i);
total++;
if (PageReserved(page))
reserved++;
@@ -55,9 +53,7 @@ void show_mem(void)
free++;
else
shared += page_count(page) - 1;
- page++;
- } while (page < end);
-
+ }
pgdat_resize_unlock(pgdat, &flags);
}
@@ -137,16 +133,12 @@ void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
}
#endif /* CONFIG_MMU */
-/* References to section boundaries */
-
-extern char _text, _etext, _edata, __bss_start, _end;
-extern char __init_begin, __init_end;
-
/*
* paging_init() sets up the page tables
*/
void __init paging_init(void)
{
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
int nid;
/* We don't need to map the kernel through the TLB, as
@@ -158,43 +150,39 @@ void __init paging_init(void)
* check for a null value. */
set_TTB(swapper_pg_dir);
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
- unsigned long max_zone_pfns[MAX_NR_ZONES];
unsigned long low, start_pfn;
- memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-
start_pfn = pgdat->bdata->node_boot_start >> PAGE_SHIFT;
low = pgdat->bdata->node_low_pfn;
- max_zone_pfns[ZONE_NORMAL] = low;
- add_active_range(nid, start_pfn, low);
+ if (max_zone_pfns[ZONE_NORMAL] < low)
+ max_zone_pfns[ZONE_NORMAL] = low;
printk("Node %u: start_pfn = 0x%lx, low = 0x%lx\n",
nid, start_pfn, low);
-
- free_area_init_nodes(max_zone_pfns);
-
- printk("Node %u: mem_map starts at %p\n",
- pgdat->node_id, pgdat->node_mem_map);
}
+
+ free_area_init_nodes(max_zone_pfns);
}
static struct kcore_list kcore_mem, kcore_vmalloc;
void __init mem_init(void)
{
- int codesize, reservedpages, datasize, initsize;
+ int codesize, datasize, initsize;
int nid;
- reservedpages = 0;
+ num_physpages = 0;
+ high_memory = NULL;
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
unsigned long node_pages = 0;
void *node_high_memory;
- int i;
num_physpages += pgdat->node_present_pages;
@@ -203,13 +191,9 @@ void __init mem_init(void)
totalram_pages += node_pages;
- for (i = 0; i < node_pages; i++)
- if (PageReserved(pgdat->node_mem_map + i))
- reservedpages++;
-
- node_high_memory = (void *)((pgdat->node_start_pfn +
- pgdat->node_spanned_pages) <<
- PAGE_SHIFT);
+ node_high_memory = (void *)__va((pgdat->node_start_pfn +
+ pgdat->node_spanned_pages) <<
+ PAGE_SHIFT);
if (node_high_memory > high_memory)
high_memory = node_high_memory;
}
@@ -239,11 +223,10 @@ void __init mem_init(void)
VMALLOC_END - VMALLOC_START);
printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
- "%dk reserved, %dk data, %dk init)\n",
+ "%dk data, %dk init)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
- totalram_pages << (PAGE_SHIFT-10),
+ num_physpages << (PAGE_SHIFT-10),
codesize >> 10,
- reservedpages << (PAGE_SHIFT-10),
datasize >> 10,
initsize >> 10);
@@ -264,7 +247,9 @@ void free_initmem(void)
free_page(addr);
totalram_pages++;
}
- printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10);
+ printk("Freeing unused kernel memory: %ldk freed\n",
+ ((unsigned long)&__init_end -
+ (unsigned long)&__init_begin) >> 10);
}
#ifdef CONFIG_BLK_DEV_INITRD
@@ -277,6 +262,50 @@ void free_initrd_mem(unsigned long start, unsigned long end)
free_page(p);
totalram_pages++;
}
- printk ("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+ printk("Freeing initrd memory: %ldk freed\n", (end - start) >> 10);
+}
+#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;
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+ int ret;
+
+ pgdat = NODE_DATA(nid);
+
+ /* We only have ZONE_NORMAL, so this is easy.. */
+ ret = __add_pages(pgdat->node_zones + ZONE_NORMAL, start_pfn, nr_pages);
+ if (unlikely(ret))
+ printk("%s: Failed, __add_pages() == %d\n", __FUNCTION__, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(arch_add_memory);
+
+int remove_memory(u64 start, u64 size)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(remove_memory);
+
+#ifdef CONFIG_NUMA
+int memory_add_physaddr_to_nid(u64 addr)
+{
+ /* Node 0 for now.. */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+#endif
#endif
diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c
new file mode 100644
index 000000000000..8aff065dd307
--- /dev/null
+++ b/arch/sh/mm/numa.c
@@ -0,0 +1,92 @@
+/*
+ * arch/sh/mm/numa.c - Multiple node support for SH machines
+ *
+ * Copyright (C) 2007 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/module.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/numa.h>
+#include <linux/pfn.h>
+#include <asm/sections.h>
+
+static bootmem_data_t plat_node_bdata[MAX_NUMNODES];
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
+EXPORT_SYMBOL_GPL(node_data);
+
+/*
+ * On SH machines the conventional approach is to stash system RAM
+ * in node 0, and other memory blocks in to node 1 and up, ordered by
+ * latency. Each node's pgdat is node-local at the beginning of the node,
+ * immediately followed by the node mem map.
+ */
+void __init setup_memory(void)
+{
+ unsigned long free_pfn = PFN_UP(__pa(_end));
+
+ /*
+ * Node 0 sets up its pgdat at the first available pfn,
+ * and bumps it up before setting up the bootmem allocator.
+ */
+ NODE_DATA(0) = pfn_to_kaddr(free_pfn);
+ memset(NODE_DATA(0), 0, sizeof(struct pglist_data));
+ free_pfn += PFN_UP(sizeof(struct pglist_data));
+ NODE_DATA(0)->bdata = &plat_node_bdata[0];
+
+ /* Set up node 0 */
+ setup_bootmem_allocator(free_pfn);
+
+ /* Give the platforms a chance to hook up their nodes */
+ plat_mem_setup();
+}
+
+void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
+{
+ unsigned long bootmap_pages, bootmap_start, bootmap_size;
+ unsigned long start_pfn, free_pfn, end_pfn;
+
+ /* Don't allow bogus node assignment */
+ BUG_ON(nid > MAX_NUMNODES || nid == 0);
+
+ /*
+ * The free pfn starts at the beginning of the range, and is
+ * advanced as necessary for pgdat and node map allocations.
+ */
+ free_pfn = start_pfn = start >> PAGE_SHIFT;
+ end_pfn = end >> PAGE_SHIFT;
+
+ add_active_range(nid, start_pfn, end_pfn);
+
+ /* Node-local pgdat */
+ NODE_DATA(nid) = pfn_to_kaddr(free_pfn);
+ free_pfn += PFN_UP(sizeof(struct pglist_data));
+ memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
+
+ NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
+ NODE_DATA(nid)->node_start_pfn = start_pfn;
+ NODE_DATA(nid)->node_spanned_pages = end_pfn - start_pfn;
+
+ /* Node-local bootmap */
+ bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
+ bootmap_start = (unsigned long)pfn_to_kaddr(free_pfn);
+ bootmap_size = init_bootmem_node(NODE_DATA(nid), free_pfn, start_pfn,
+ end_pfn);
+
+ free_bootmem_with_active_regions(nid, end_pfn);
+
+ /* Reserve the pgdat and bootmap space with the bootmem allocator */
+ reserve_bootmem_node(NODE_DATA(nid), start_pfn << PAGE_SHIFT,
+ sizeof(struct pglist_data));
+ reserve_bootmem_node(NODE_DATA(nid), free_pfn << PAGE_SHIFT,
+ bootmap_pages << PAGE_SHIFT);
+
+ /* It's up */
+ node_set_online(nid);
+
+ /* Kick sparsemem */
+ sparse_memory_present_with_active_regions(nid);
+}
diff --git a/arch/sh/mm/pg-dma.c b/arch/sh/mm/pg-dma.c
deleted file mode 100644
index bb23679369d6..000000000000
--- a/arch/sh/mm/pg-dma.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * arch/sh/mm/pg-dma.c
- *
- * Fast clear_page()/copy_page() implementation using the SH DMAC
- *
- * Copyright (C) 2003 Paul Mundt
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/semaphore.h>
-#include <asm/mmu_context.h>
-#include <asm/addrspace.h>
-#include <asm/atomic.h>
-#include <asm/page.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-
-/* Channel to use for page ops, must be dual-address mode capable. */
-static int dma_channel = CONFIG_DMA_PAGE_OPS_CHANNEL;
-
-static void copy_page_dma(void *to, void *from)
-{
- /*
- * This doesn't seem to get triggered until further along in the
- * boot process, at which point the DMAC is already initialized.
- * Fix this in the same fashion as clear_page_dma() in the event
- * that this crashes due to the DMAC not being initialized.
- */
-
- flush_icache_range((unsigned long)from, PAGE_SIZE);
- dma_write_page(dma_channel, (unsigned long)from, (unsigned long)to);
- dma_wait_for_completion(dma_channel);
-}
-
-static void clear_page_dma(void *to)
-{
- /*
- * We get invoked quite early on, if the DMAC hasn't been initialized
- * yet, fall back on the slow manual implementation.
- */
- if (dma_info[dma_channel].chan != dma_channel) {
- clear_page_slow(to);
- return;
- }
-
- dma_write_page(dma_channel, (unsigned long)empty_zero_page,
- (unsigned long)to);
-
- /*
- * FIXME: Something is a bit racy here, if we poll the counter right
- * away, we seem to lock. flushing the page from the dcache doesn't
- * seem to make a difference one way or the other, though either a full
- * icache or dcache flush does.
- *
- * The location of this is important as well, and must happen prior to
- * the completion loop but after the transfer was initiated.
- *
- * Oddly enough, this doesn't appear to be an issue for copy_page()..
- */
- flush_icache_range((unsigned long)to, PAGE_SIZE);
-
- dma_wait_for_completion(dma_channel);
-}
-
-static int __init pg_dma_init(void)
-{
- int ret;
-
- ret = request_dma(dma_channel, "page ops");
- if (ret != 0)
- return ret;
-
- copy_page = copy_page_dma;
- clear_page = clear_page_dma;
-
- return ret;
-}
-
-static void __exit pg_dma_exit(void)
-{
- free_dma(dma_channel);
-}
-
-module_init(pg_dma_init);
-module_exit(pg_dma_exit);
-
-MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
-MODULE_DESCRIPTION("Optimized page copy/clear routines using a dual-address mode capable DMAC channel");
-MODULE_LICENSE("GPL");
-
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
index b6a5a338145b..a08a4a958add 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -310,7 +310,7 @@ static int __init pmb_init(void)
BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0,
- SLAB_PANIC, pmb_cache_ctor, NULL);
+ SLAB_PANIC, pmb_cache_ctor);
jump_to_P2();
diff --git a/arch/sh/tools/Makefile b/arch/sh/tools/Makefile
index 3c370a113291..567516b58acc 100644
--- a/arch/sh/tools/Makefile
+++ b/arch/sh/tools/Makefile
@@ -12,4 +12,5 @@
include/asm-sh/machtypes.h: $(src)/gen-mach-types $(src)/mach-types
@echo ' Generating $@'
+ $(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
$(Q)$(AWK) -f $^ > $@ || { rm -f $@; /bin/false; }
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index fb40f188aff9..4b5e9305092e 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -18,7 +18,6 @@ SE SH_SOLUTION_ENGINE
HP6XX SH_HP6XX
HD64461 HD64461
HD64465 HD64465
-SATURN SH_SATURN
DREAMCAST SH_DREAMCAST
MPC1211 SH_MPC1211
SNAPGEAR SH_SECUREEDGE5410
@@ -34,3 +33,4 @@ R7785RP SH_R7785RP
TITAN SH_TITAN
SHMIN SH_SHMIN
7710VOIPGW SH_7710VOIPGW
+LBOXRE2 SH_LBOX_RE2
diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
index ed035084b053..784434143343 100644
--- a/arch/sh64/configs/cayman_defconfig
+++ b/arch/sh64/configs/cayman_defconfig
@@ -1,11 +1,12 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc1
-# Mon May 14 08:43:31 2007
+# Linux kernel version: 2.6.22
+# Fri Jul 20 12:28:34 2007
#
CONFIG_SUPERH=y
CONFIG_SUPERH64=y
CONFIG_MMU=y
+CONFIG_QUICKLIST=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
@@ -32,7 +33,7 @@ CONFIG_SWAP=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=14
@@ -66,19 +67,12 @@ CONFIG_SLAB=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
# CONFIG_MODULES is not set
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -156,6 +150,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
@@ -175,7 +171,6 @@ CONFIG_SH_PCIDMA_NONCOHERENT=y
# Executable file formats
#
CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
#
@@ -225,20 +220,8 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
# CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -274,6 +257,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -288,26 +272,10 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -323,18 +291,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
# CONFIG_IDE is not set
#
@@ -342,6 +303,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
@@ -410,13 +372,8 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SRP is not set
# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
# CONFIG_MD is not set
#
@@ -432,30 +389,16 @@ CONFIG_SCSI_SYM53C8XX_MMIO=y
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
# CONFIG_STNIC is not set
@@ -464,10 +407,6 @@ CONFIG_NET_ETHERNET=y
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
-
-#
-# Tulip family network device support
-#
CONFIG_NET_TULIP=y
# CONFIG_DE2104X is not set
CONFIG_TULIP=y
@@ -510,7 +449,6 @@ CONFIG_NETDEV_1000=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
@@ -524,11 +462,6 @@ CONFIG_NETDEV_10000=y
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_MLX4_CORE is not set
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
# CONFIG_TR is not set
#
@@ -546,15 +479,7 @@ CONFIG_MLX4_DEBUG=y
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -562,6 +487,7 @@ CONFIG_MLX4_DEBUG=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -638,10 +564,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
CONFIG_WATCHDOG=y
# CONFIG_WATCHDOG_NOWAYOUT is not set
@@ -658,15 +580,10 @@ CONFIG_WATCHDOG=y
# CONFIG_PCIPCWATCHDOG is not set
# CONFIG_WDTPCI is not set
CONFIG_HW_RANDOM=y
-# CONFIG_GEN_RTC is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
# CONFIG_I2C is not set
@@ -676,20 +593,24 @@ CONFIG_DEVPORT=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -739,7 +660,6 @@ CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
-# CONFIG_FB_EPSON1355 is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
@@ -765,6 +685,7 @@ CONFIG_FB_KYRO=y
#
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
# CONFIG_FONT_8x8 is not set
@@ -789,16 +710,10 @@ CONFIG_LOGO_SUPERH_CLUT224=y
# Sound
#
# CONFIG_SOUND is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -826,17 +741,9 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
# LED Triggers
#
-
-#
-# InfiniBand support
-#
# CONFIG_INFINIBAND is not set
#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
# Real Time Clock
#
# CONFIG_RTC_CLASS is not set
@@ -855,6 +762,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y
#
#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -950,7 +862,6 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -1001,6 +912,7 @@ CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
CONFIG_SCHEDSTATS=y
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_SLAB is not set
@@ -1017,7 +929,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_LIST is not set
CONFIG_FRAME_POINTER=y
CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_EARLY_PRINTK is not set
# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
@@ -1033,10 +944,6 @@ CONFIG_SH64_SR_WATCH=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
# CONFIG_CRYPTO is not set
#
@@ -1047,6 +954,7 @@ CONFIG_BITREVERSE=y
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
CONFIG_HAS_IOMEM=y
diff --git a/arch/sh64/kernel/head.S b/arch/sh64/kernel/head.S
index f3740ddbc471..186406d3ad9c 100644
--- a/arch/sh64/kernel/head.S
+++ b/arch/sh64/kernel/head.S
@@ -124,7 +124,7 @@ empty_bad_pte_table:
fpu_in_use: .quad 0
- .section .text, "ax"
+ .section .text.head, "ax"
.balign L1_CACHE_BYTES
/*
* Condition at the entry of __stext:
diff --git a/arch/sh64/kernel/pci_sh5.c b/arch/sh64/kernel/pci_sh5.c
index 3334f99b5835..388bb711f1b0 100644
--- a/arch/sh64/kernel/pci_sh5.c
+++ b/arch/sh64/kernel/pci_sh5.c
@@ -48,7 +48,7 @@ static void __init pci_fixup_ide_bases(struct pci_dev *d)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
-char * __init pcibios_setup(char *str)
+char * __devinit pcibios_setup(char *str)
{
return str;
}
@@ -497,7 +497,7 @@ static int __init pcibios_init(void)
subsys_initcall(pcibios_init);
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+void __devinit pcibios_fixup_bus(struct pci_bus *bus)
{
struct pci_dev *dev = bus->self;
int i;
diff --git a/arch/sh64/kernel/ptrace.c b/arch/sh64/kernel/ptrace.c
index 4e95e18b46d9..df06c6477468 100644
--- a/arch/sh64/kernel/ptrace.c
+++ b/arch/sh64/kernel/ptrace.c
@@ -129,17 +129,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long *) data);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -166,10 +158,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR:
diff --git a/arch/sh64/kernel/syscalls.S b/arch/sh64/kernel/syscalls.S
index a5c680d29384..abb94c05d07a 100644
--- a/arch/sh64/kernel/syscalls.S
+++ b/arch/sh64/kernel/syscalls.S
@@ -378,3 +378,4 @@ sys_call_table:
.long sys_signalfd
.long sys_timerfd /* 350 */
.long sys_eventfd
+ .long sys_fallocate
diff --git a/arch/sh64/kernel/vmlinux.lds.S b/arch/sh64/kernel/vmlinux.lds.S
index 02aea86c5907..267b4f9af2e1 100644
--- a/arch/sh64/kernel/vmlinux.lds.S
+++ b/arch/sh64/kernel/vmlinux.lds.S
@@ -54,6 +54,7 @@ SECTIONS
} = 0
.text : C_PHYS(.text) {
+ *(.text.head)
TEXT_TEXT
*(.text64)
*(.text..SHmedia32)
@@ -87,7 +88,10 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
__per_cpu_start = .;
- .data.percpu : C_PHYS(.data.percpu) { *(.data.percpu) }
+ .data.percpu : C_PHYS(.data.percpu) {
+ *(.data.percpu)
+ *(.data.percpu.shared_aligned)
+ }
__per_cpu_end = . ;
.data.cacheline_aligned : C_PHYS(.data.cacheline_aligned) { *(.data.cacheline_aligned) }
diff --git a/arch/sh64/lib/c-checksum.c b/arch/sh64/lib/c-checksum.c
index 4b2676380deb..bd5501760240 100644
--- a/arch/sh64/lib/c-checksum.c
+++ b/arch/sh64/lib/c-checksum.c
@@ -213,3 +213,4 @@ __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
return (__wsum)result;
}
+EXPORT_SYMBOL(csum_tcpudp_nofold);
diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c
index 3cd93ba5d826..0d069d82141f 100644
--- a/arch/sh64/mm/fault.c
+++ b/arch/sh64/mm/fault.c
@@ -127,6 +127,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
struct vm_area_struct * vma;
const struct exception_table_entry *fixup;
pte_t *pte;
+ int fault;
#if defined(CONFIG_SH64_PROC_TLB)
++calls_to_do_slow_page_fault;
@@ -221,18 +222,19 @@ good_area:
* the fault.
*/
survive:
- switch (handle_mm_fault(mm, vma, address, writeaccess)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- default:
- goto out_of_memory;
+ fault = handle_mm_fault(mm, vma, address, writeaccess);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+
/* If we get here, the page fault has been handled. Do the TLB refill
now from the newly-setup PTE, to avoid having to fault again right
away on the same instruction. */
diff --git a/arch/sh64/mm/ioremap.c b/arch/sh64/mm/ioremap.c
index ff26c02511aa..990857756d44 100644
--- a/arch/sh64/mm/ioremap.c
+++ b/arch/sh64/mm/ioremap.c
@@ -242,7 +242,7 @@ static void shmedia_free_io(struct resource *res)
release_resource(res);
}
-static void *sh64_get_page(void)
+static __init_refok void *sh64_get_page(void)
{
extern int after_bootmem;
void *page;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index fbcc00c6c06e..9d327ec59759 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -21,6 +21,12 @@ config GENERIC_ISA_DMA
bool
default y
+config ARCH_NO_VIRT_TO_BUS
+ def_bool y
+
+config OF
+ def_bool y
+
source "init/Kconfig"
menu "General machine setup"
@@ -210,10 +216,16 @@ config PCI
CP-1200, JavaEngine-1, Corona, Red October, and Serengeti SGSC.
All of these platforms are extremely obscure, so say N if unsure.
+config PCI_SYSCALL
+ def_bool PCI
+
source "drivers/pci/Kconfig"
endif
+config NO_DMA
+ def_bool !PCI
+
config SUN_OPENPROMFS
tristate "Openprom tree appears in /proc/openprom"
help
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
index 7bb86b9cdaa3..ac352eb6dff3 100644
--- a/arch/sparc/kernel/ebus.c
+++ b/arch/sparc/kernel/ebus.c
@@ -148,6 +148,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
{
const struct linux_prom_registers *regs;
struct linux_ebus_child *child;
+ struct dev_archdata *sd;
const int *irqs;
int i, n, len;
unsigned long baseaddr;
@@ -234,6 +235,10 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
}
}
+ sd = &dev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &dev->ofdev;
+
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 831f540251f8..eac38388f5fd 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -1749,8 +1749,8 @@ fpload:
__ndelay:
save %sp, -STACKFRAME_SZ, %sp
mov %i0, %o0
- call .umul
- mov 0x1ad, %o1 ! 2**32 / (1 000 000 000 / HZ)
+ call .umul ! round multiplier up so large ns ok
+ mov 0x1ae, %o1 ! 2**32 / (1 000 000 000 / HZ)
call .umul
mov %i1, %o1 ! udelay_val
ba delay_continue
@@ -1760,11 +1760,17 @@ __ndelay:
__udelay:
save %sp, -STACKFRAME_SZ, %sp
mov %i0, %o0
- sethi %hi(0x10c6), %o1
+ sethi %hi(0x10c7), %o1 ! round multiplier up so large us ok
call .umul
- or %o1, %lo(0x10c6), %o1 ! 2**32 / 1 000 000
+ or %o1, %lo(0x10c7), %o1 ! 2**32 / 1 000 000
call .umul
mov %i1, %o1 ! udelay_val
+ sethi %hi(0x028f4b62), %l0 ! Add in rounding constant * 2**32,
+ or %g0, %lo(0x028f4b62), %l0
+ addcc %o0, %l0, %o0 ! 2**32 * 0.009 999
+ bcs,a 3f
+ add %o1, 0x01, %o1
+3:
call .umul
mov HZ, %o0 ! >>32 earlier for wider range
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index f257a67bcf93..75b2240ad0f9 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -47,6 +47,8 @@
#include <asm/cacheflush.h>
#include <asm/irq_regs.h>
+#include "irq.h"
+
#ifdef CONFIG_SMP
#define SMP_NOP2 "nop; nop;\n\t"
#define SMP_NOP3 "nop; nop; nop;\n\t"
@@ -268,7 +270,7 @@ void free_irq(unsigned int irq, void *dev_id)
kfree(action);
if (!sparc_irq[cpu_irq].action)
- disable_irq(irq);
+ __disable_irq(irq);
out_unlock:
spin_unlock_irqrestore(&irq_action_lock, flags);
@@ -464,7 +466,7 @@ int request_fast_irq(unsigned int irq,
sparc_irq[cpu_irq].action = action;
- enable_irq(irq);
+ __enable_irq(irq);
ret = 0;
out_unlock:
@@ -544,7 +546,7 @@ int request_irq(unsigned int irq,
*actionp = action;
- enable_irq(irq);
+ __enable_irq(irq);
ret = 0;
out_unlock:
@@ -555,6 +557,25 @@ out:
EXPORT_SYMBOL(request_irq);
+void disable_irq_nosync(unsigned int irq)
+{
+ return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq_nosync);
+
+void disable_irq(unsigned int irq)
+{
+ return __disable_irq(irq);
+}
+EXPORT_SYMBOL(disable_irq);
+
+void enable_irq(unsigned int irq)
+{
+ return __enable_irq(irq);
+}
+
+EXPORT_SYMBOL(enable_irq);
+
/* We really don't need these at all on the Sparc. We only have
* stubs here because they are exported to modules.
*/
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
new file mode 100644
index 000000000000..32ef3ebd0a88
--- /dev/null
+++ b/arch/sparc/kernel/irq.h
@@ -0,0 +1,68 @@
+#include <asm/btfixup.h>
+
+/* Dave Redman (djhr@tadpole.co.uk)
+ * changed these to function pointers.. it saves cycles and will allow
+ * the irq dependencies to be split into different files at a later date
+ * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
+ * Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Changed these to btfixup entities... It saves cycles :)
+ */
+
+BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
+BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
+BTFIXUPDEF_CALL(void, clear_clock_irq, void)
+BTFIXUPDEF_CALL(void, clear_profile_irq, int)
+BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
+
+static inline void __disable_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(disable_irq)(irq);
+}
+
+static inline void __enable_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(enable_irq)(irq);
+}
+
+static inline void disable_pil_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(disable_pil_irq)(irq);
+}
+
+static inline void enable_pil_irq(unsigned int irq)
+{
+ BTFIXUP_CALL(enable_pil_irq)(irq);
+}
+
+static inline void clear_clock_irq(void)
+{
+ BTFIXUP_CALL(clear_clock_irq)();
+}
+
+static inline void clear_profile_irq(int irq)
+{
+ BTFIXUP_CALL(clear_profile_irq)(irq);
+}
+
+static inline void load_profile_irq(int cpu, int limit)
+{
+ BTFIXUP_CALL(load_profile_irq)(cpu, limit);
+}
+
+extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
+
+extern void claim_ticker14(irq_handler_t irq_handler,
+ int irq,
+ unsigned int timeout);
+
+#ifdef CONFIG_SMP
+BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
+BTFIXUPDEF_CALL(void, set_irq_udt, int)
+
+#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
+#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
+#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
+#endif
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index fd7f8cb668a3..36383f73d685 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -1,132 +1,13 @@
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
- const struct of_device *dev)
-{
- if (!dev->node)
- return NULL;
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
- int match = 1;
- if (matches->name[0])
- match &= dev->node->name
- && !strcmp(matches->name, dev->node->name);
- if (matches->type[0])
- match &= dev->node->type
- && !strcmp(matches->type, dev->node->type);
- if (matches->compatible[0])
- match &= of_device_is_compatible(dev->node,
- matches->compatible);
- if (match)
- return matches;
- matches++;
- }
- return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * of_drv = to_of_platform_driver(drv);
- const struct of_device_id * matches = of_drv->match_table;
-
- if (!matches)
- return 0;
-
- return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
- struct device *tmp;
-
- if (!dev)
- return NULL;
- tmp = get_device(&dev->dev);
- if (tmp)
- return to_of_device(tmp);
- else
- return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
- if (dev)
- put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
- int error = -ENODEV;
- struct of_platform_driver *drv;
- struct of_device *of_dev;
- const struct of_device_id *match;
-
- drv = to_of_platform_driver(dev->driver);
- of_dev = to_of_device(dev);
-
- if (!drv->probe)
- return error;
-
- of_dev_get(of_dev);
-
- match = of_match_device(drv->match_table, of_dev);
- if (match)
- error = drv->probe(of_dev, match);
- if (error)
- of_dev_put(of_dev);
-
- return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
- if (dev->driver && drv->remove)
- drv->remove(of_dev);
- return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->suspend)
- error = drv->suspend(of_dev, state);
- return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->resume)
- error = drv->resume(of_dev);
- return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
static int node_match(struct device *dev, void *data)
{
@@ -138,7 +19,7 @@ static int node_match(struct device *dev, void *data)
struct of_device *of_find_device_by_node(struct device_node *dp)
{
- struct device *dev = bus_find_device(&of_bus_type, NULL,
+ struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
dp, node_match);
if (dev)
@@ -149,38 +30,17 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
EXPORT_SYMBOL(of_find_device_by_node);
#ifdef CONFIG_PCI
-struct bus_type ebus_bus_type = {
- .name = "ebus",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type ebus_bus_type;
EXPORT_SYMBOL(ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
- .name = "sbus",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type sbus_bus_type;
EXPORT_SYMBOL(sbus_bus_type);
#endif
-struct bus_type of_bus_type = {
- .name = "of",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
static inline u64 of_read_addr(const u32 *cell, int size)
{
@@ -560,11 +420,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
{
struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
const struct linux_prom_irqs *intr;
+ struct dev_archdata *sd;
int len, i;
if (!op)
return NULL;
+ sd = &op->dev.archdata;
+ sd->prom_node = dp;
+ sd->op = op;
+
op->node = dp;
op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -646,7 +511,7 @@ build_resources:
build_device_resources(op, parent);
op->dev.parent = parent;
- op->dev.bus = &of_bus_type;
+ op->dev.bus = &of_platform_bus_type;
if (!parent)
strcpy(op->dev.bus_id, "root");
else
@@ -690,14 +555,14 @@ static int __init of_bus_driver_init(void)
{
int err;
- err = bus_register(&of_bus_type);
+ err = of_bus_type_init(&of_platform_bus_type, "of");
#ifdef CONFIG_PCI
if (!err)
- err = bus_register(&ebus_bus_type);
+ err = of_bus_type_init(&ebus_bus_type, "ebus");
#endif
#ifdef CONFIG_SBUS
if (!err)
- err = bus_register(&sbus_bus_type);
+ err = of_bus_type_init(&sbus_bus_type, "sbus");
#endif
if (!err)
@@ -735,56 +600,6 @@ void of_unregister_driver(struct of_platform_driver *drv)
driver_unregister(&drv->driver);
}
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
- return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
-
- kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
- int rc;
-
- BUG_ON(ofdev->node == NULL);
-
- rc = device_register(&ofdev->dev);
- if (rc)
- return rc;
-
- rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
- if (rc)
- device_unregister(&ofdev->dev);
-
- return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
- device_remove_file(&ofdev->dev, &dev_attr_devspec);
- device_unregister(&ofdev->dev);
-}
-
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
struct device *parent,
@@ -810,12 +625,6 @@ struct of_device* of_platform_device_create(struct device_node *np,
return dev;
}
-EXPORT_SYMBOL(of_match_device);
EXPORT_SYMBOL(of_register_driver);
EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 791771196905..f2eae457fc9a 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -36,6 +36,7 @@
#include <asm/uaccess.h>
#include <asm/irq_regs.h>
+#include "irq.h"
/*
* I studied different documents and many live PROMs both from 2.30
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index 8c37f8f5adb7..33f7a3ddb104 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -39,6 +39,7 @@
#include <asm/processor.h>
#include <asm/psr.h>
#include <asm/elf.h>
+#include <asm/prom.h>
#include <asm/unistd.h>
/*
@@ -150,7 +151,7 @@ void machine_halt(void)
local_irq_enable();
mdelay(8);
local_irq_disable();
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (1);
prom_halt();
panic("Halt failed!");
@@ -166,7 +167,7 @@ void machine_restart(char * cmd)
p = strchr (reboot_command, '\n');
if (p) *p = 0;
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (1);
if (cmd)
prom_reboot(cmd);
@@ -179,7 +180,8 @@ void machine_restart(char * cmd)
void machine_power_off(void)
{
#ifdef CONFIG_SUN_AUXIO
- if (auxio_power_register && (!serial_console || scons_pwroff))
+ if (auxio_power_register &&
+ (strcmp(of_console_device->type, "serial") || scons_pwroff))
*auxio_power_register |= AUXIO_POWER_OFF;
#endif
machine_halt();
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index eed140b3c739..e3a537650db1 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -25,73 +25,9 @@
#include <asm/prom.h>
#include <asm/oplib.h>
-static struct device_node *allnodes;
+extern struct device_node *allnodes; /* temporary while merging */
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
- const char *compat)
-{
- const char* cp;
- int cplen, l;
-
- cp = of_get_property(device, "compatible", &cplen);
- if (cp == NULL)
- return 0;
- while (cplen > 0) {
- if (strncmp(cp, compat, strlen(compat)) == 0)
- return 1;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
- struct device_node *np;
-
- if (!node)
- return NULL;
-
- np = node->parent;
-
- return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
- struct device_node *prev)
-{
- struct device_node *next;
-
- next = prev ? prev->sibling : node->child;
- for (; next != 0; next = next->sibling) {
- break;
- }
-
- return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
- struct device_node *np = allnodes;
-
- for (; np != 0; np = np->allnext) {
- if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
- break;
- }
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock; /* temporary while merging */
struct device_node *of_find_node_by_phandle(phandle handle)
{
@@ -105,81 +41,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
}
EXPORT_SYMBOL(of_find_node_by_phandle);
-struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != NULL; np = np->allnext)
- if (np->name != NULL && strcmp(np->name, name) == 0)
- break;
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
- const char *type)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext)
- if (np->type != 0 && strcmp(np->type, type) == 0)
- break;
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
- const char *type, const char *compatible)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext) {
- if (type != NULL
- && !(np->type != 0 && strcmp(np->type, type) == 0))
- continue;
- if (of_device_is_compatible(np, compatible))
- break;
- }
-
- return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp)
-{
- struct property *pp;
-
- for (pp = np->properties; pp != 0; pp = pp->next) {
- if (strcasecmp(pp->name, name) == 0) {
- if (lenp != 0)
- *lenp = pp->length;
- break;
- }
- }
- return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
- int *lenp)
-{
- struct property *pp = of_find_property(np,name,lenp);
- return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
int of_getintprop_default(struct device_node *np, const char *name, int def)
{
struct property *prop;
@@ -193,36 +54,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
}
EXPORT_SYMBOL(of_getintprop_default);
-int of_n_addr_cells(struct device_node *np)
-{
- const int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#address-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #address-cells property for the root node, default to 2 */
- return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
- const int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#size-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #size-cells property for the root node, default to 1 */
- return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
int of_set_property(struct device_node *dp, const char *name, void *val, int len)
{
struct property **prevp;
@@ -566,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
return dp;
}
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+extern void restore_current(void);
+
+static void __init of_console_init(void)
+{
+ char *msg = "OF stdout device is: %s\n";
+ struct device_node *dp;
+ unsigned long flags;
+ const char *type;
+ phandle node;
+ int skip, fd;
+
+ of_console_path = prom_early_alloc(256);
+
+ switch (prom_vers) {
+ case PROM_V0:
+ case PROM_SUN4:
+ skip = 0;
+ switch (*romvec->pv_stdout) {
+ case PROMDEV_SCREEN:
+ type = "display";
+ break;
+
+ case PROMDEV_TTYB:
+ skip = 1;
+ /* FALLTHRU */
+
+ case PROMDEV_TTYA:
+ type = "serial";
+ break;
+
+ default:
+ prom_printf("Invalid PROM_V0 stdout value %u\n",
+ *romvec->pv_stdout);
+ prom_halt();
+ }
+
+ for_each_node_by_type(dp, type) {
+ if (!skip--)
+ break;
+ }
+ if (!dp) {
+ prom_printf("Cannot find PROM_V0 console node.\n");
+ prom_halt();
+ }
+ of_console_device = dp;
+
+ strcpy(of_console_path, dp->full_name);
+ if (!strcmp(type, "serial")) {
+ strcat(of_console_path,
+ (skip ? ":b" : ":a"));
+ }
+ break;
+
+ default:
+ case PROM_V2:
+ case PROM_V3:
+ fd = *romvec->pv_v2bootargs.fd_stdout;
+
+ spin_lock_irqsave(&prom_lock, flags);
+ node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
+ restore_current();
+ spin_unlock_irqrestore(&prom_lock, flags);
+
+ if (!node) {
+ prom_printf("Cannot resolve stdout node from "
+ "instance %08x.\n", fd);
+ prom_halt();
+ }
+ dp = of_find_node_by_phandle(node);
+ type = of_get_property(dp, "device_type", NULL);
+
+ if (!type) {
+ prom_printf("Console stdout lacks "
+ "device_type property.\n");
+ prom_halt();
+ }
+
+ if (strcmp(type, "display") && strcmp(type, "serial")) {
+ prom_printf("Console device_type is neither display "
+ "nor serial.\n");
+ prom_halt();
+ }
+
+ of_console_device = dp;
+
+ if (prom_vers == PROM_V2) {
+ strcpy(of_console_path, dp->full_name);
+ switch (*romvec->pv_stdout) {
+ case PROMDEV_TTYA:
+ strcat(of_console_path, ":a");
+ break;
+ case PROMDEV_TTYB:
+ strcat(of_console_path, ":b");
+ break;
+ }
+ } else {
+ const char *path;
+
+ dp = of_find_node_by_path("/");
+ path = of_get_property(dp, "stdout-path", NULL);
+ if (!path) {
+ prom_printf("No stdout-path in root node.\n");
+ prom_halt();
+ }
+ strcpy(of_console_path, path);
+ }
+ break;
+ }
+
+ of_console_options = strrchr(of_console_path, ':');
+ if (of_console_options) {
+ of_console_options++;
+ if (*of_console_options == '\0')
+ of_console_options = NULL;
+ }
+
+ prom_printf(msg, of_console_path);
+ printk(msg, of_console_path);
+}
+
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
@@ -578,6 +538,8 @@ void __init prom_build_devicetree(void)
allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node),
&nextp);
+ of_console_init();
+
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 64c0ed98820a..f8228383895a 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -146,31 +146,6 @@ static void __init process_switch(char c)
}
}
-static void __init process_console(char *commands)
-{
- serial_console = 0;
- commands += 8;
- /* Linux-style serial */
- if (!strncmp(commands, "ttyS", 4))
- serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
- else if (!strncmp(commands, "tty", 3)) {
- char c = *(commands + 3);
- /* Solaris-style serial */
- if (c == 'a' || c == 'b')
- serial_console = c - 'a' + 1;
- /* else Linux-style fbcon, not serial */
- }
-#if defined(CONFIG_PROM_CONSOLE)
- if (!strncmp(commands, "prom", 4)) {
- char *p;
-
- for (p = commands - 8; *p && *p != ' '; p++)
- *p = ' ';
- conswitchp = &prom_con;
- }
-#endif
-}
-
static void __init boot_flags_init(char *commands)
{
while (*commands) {
@@ -187,9 +162,7 @@ static void __init boot_flags_init(char *commands)
process_switch(*commands++);
continue;
}
- if (!strncmp(commands, "console=", 8)) {
- process_console(commands);
- } else if (!strncmp(commands, "mem=", 4)) {
+ if (!strncmp(commands, "mem=", 4)) {
/*
* "mem=XXX[kKmM] overrides the PROM-reported
* memory size.
@@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p)
smp_setup_cpu_possible_map();
}
-static int __init set_preferred_console(void)
-{
- int idev, odev;
-
- /* The user has requested a console so this is already set up. */
- if (serial_console >= 0)
- return -EBUSY;
-
- idev = prom_query_input_device();
- odev = prom_query_output_device();
- if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
- serial_console = 0;
- } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
- serial_console = 1;
- } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
- serial_console = 2;
- } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
- prom_printf("MrCoffee ttya\n");
- serial_console = 1;
- } else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
- serial_console = 0;
- prom_printf("MrCoffee keyboard\n");
- } else {
- prom_printf("Confusing console (idev %d, odev %d)\n",
- idev, odev);
- serial_console = 1;
- }
-
- if (serial_console)
- return add_preferred_console("ttyS", serial_console - 1, NULL);
-
- return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
extern char *sparc_cpu_type;
extern char *sparc_fpu_type;
@@ -461,7 +399,6 @@ void sun_do_break(void)
prom_cmdline();
}
-int serial_console = -1;
int stop_a_enabled = 1;
static int __init topology_init(void)
diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
index 4fea3ac7bff0..6724ab90f82b 100644
--- a/arch/sparc/kernel/smp.c
+++ b/arch/sparc/kernel/smp.c
@@ -33,6 +33,8 @@
#include <asm/tlbflush.h>
#include <asm/cpudata.h>
+#include "irq.h"
+
int smp_num_cpus = 1;
volatile unsigned long cpu_callin_map[NR_CPUS] __initdata = {0,};
unsigned char boot_cpu_id = 0;
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index d8e008a04e2b..55bac516dfe2 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -154,8 +154,6 @@ EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32));
#else
EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id));
#endif
-EXPORT_SYMBOL(BTFIXUP_CALL(enable_irq));
-EXPORT_SYMBOL(BTFIXUP_CALL(disable_irq));
EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea));
EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea));
EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl));
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 009e891a4329..c6ac9fc52563 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include "irq.h"
#include <asm/ptrace.h>
#include <asm/processor.h>
@@ -40,6 +41,20 @@ static struct resource sun4c_timer_eb = { "sun4c_timer" };
static struct resource sun4c_intr_eb = { "sun4c_intr" };
#endif
+/*
+ * Bit field defines for the interrupt registers on various
+ * Sparc machines.
+ */
+
+/* The sun4c interrupt register. */
+#define SUN4C_INT_ENABLE 0x01 /* Allow interrupts. */
+#define SUN4C_INT_E14 0x80 /* Enable level 14 IRQ. */
+#define SUN4C_INT_E10 0x20 /* Enable level 10 IRQ. */
+#define SUN4C_INT_E8 0x10 /* Enable level 8 IRQ. */
+#define SUN4C_INT_E6 0x08 /* Enable level 6 IRQ. */
+#define SUN4C_INT_E4 0x04 /* Enable level 4 IRQ. */
+#define SUN4C_INT_E1 0x02 /* Enable level 1 IRQ. */
+
/* Pointer to the interrupt enable byte
*
* Dave Redman (djhr@tadpole.co.uk)
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 396797e20c39..e0efab2a6bef 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -39,6 +39,8 @@
#include <asm/cacheflush.h>
#include <asm/irq_regs.h>
+#include "irq.h"
+
/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
/* #define DISTRIBUTE_IRQS */
@@ -188,7 +190,7 @@ void sun4d_free_irq(unsigned int irq, void *dev_id)
kfree(action);
if (!(*actionp))
- disable_irq(irq);
+ __disable_irq(irq);
out_unlock:
spin_unlock_irqrestore(&irq_action_lock, flags);
@@ -346,7 +348,7 @@ int sun4d_request_irq(unsigned int irq,
else
*actionp = action;
- enable_irq(irq);
+ __enable_irq(irq);
ret = 0;
out_unlock:
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 098c94f1a322..89a6de95070c 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -36,6 +36,7 @@
#include <asm/cacheflush.h>
#include <asm/cpudata.h>
+#include "irq.h"
#define IRQ_CROSS_CALL 15
extern ctxd_t *srmmu_ctx_table_phys;
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 91a803ea88be..b92d6d2d5b04 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -38,11 +38,85 @@
#include <asm/sbus.h>
#include <asm/cacheflush.h>
+#include "irq.h"
+
+/* On the sun4m, just like the timers, we have both per-cpu and master
+ * interrupt registers.
+ */
+
+/* These registers are used for sending/receiving irqs from/to
+ * different cpu's.
+ */
+struct sun4m_intreg_percpu {
+ unsigned int tbt; /* Interrupts still pending for this cpu. */
+
+ /* These next two registers are WRITE-ONLY and are only
+ * "on bit" sensitive, "off bits" written have NO affect.
+ */
+ unsigned int clear; /* Clear this cpus irqs here. */
+ unsigned int set; /* Set this cpus irqs here. */
+ unsigned char space[PAGE_SIZE - 12];
+};
+
+/*
+ * djhr
+ * Actually the clear and set fields in this struct are misleading..
+ * according to the SLAVIO manual (and the same applies for the SEC)
+ * the clear field clears bits in the mask which will ENABLE that IRQ
+ * the set field sets bits in the mask to DISABLE the IRQ.
+ *
+ * Also the undirected_xx address in the SLAVIO is defined as
+ * RESERVED and write only..
+ *
+ * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
+ * sun4m machines, for MP the layout makes more sense.
+ */
+struct sun4m_intregs {
+ struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
+ unsigned int tbt; /* IRQ's that are still pending. */
+ unsigned int irqs; /* Master IRQ bits. */
+
+ /* Again, like the above, two these registers are WRITE-ONLY. */
+ unsigned int clear; /* Clear master IRQ's by setting bits here. */
+ unsigned int set; /* Set master IRQ's by setting bits here. */
+
+ /* This register is both READ and WRITE. */
+ unsigned int undirected_target; /* Which cpu gets undirected irqs. */
+};
+
static unsigned long dummy;
struct sun4m_intregs *sun4m_interrupts;
unsigned long *irq_rcvreg = &dummy;
+/* Dave Redman (djhr@tadpole.co.uk)
+ * The sun4m interrupt registers.
+ */
+#define SUN4M_INT_ENABLE 0x80000000
+#define SUN4M_INT_E14 0x00000080
+#define SUN4M_INT_E10 0x00080000
+
+#define SUN4M_HARD_INT(x) (0x000000001 << (x))
+#define SUN4M_SOFT_INT(x) (0x000010000 << (x))
+
+#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
+#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
+#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
+#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
+#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
+#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
+#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
+#define SUN4M_INT_REALTIME 0x00080000 /* system timer */
+#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */
+#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */
+#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */
+#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
+#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
+#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
+
+#define SUN4M_INT_SBUS(x) (1 << (x+7))
+#define SUN4M_INT_VME(x) (1 << (x))
+
/* These tables only apply for interrupts greater than 15..
*
* any intr value below 0x10 is considered to be a soft-int
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 63ed19bfd028..730eb5796f8e 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -31,6 +31,8 @@
#include <asm/oplib.h>
#include <asm/cpudata.h>
+#include "irq.h"
+
#define IRQ_RESCHEDULE 13
#define IRQ_STOP_CPU 14
#define IRQ_CROSS_CALL 15
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 90b52d4dab9a..55722840859c 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.103 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
*
* Based upon preliminary work which is:
*
@@ -80,7 +79,7 @@ sys_call_table:
/*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
/*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
/*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
#ifdef CONFIG_SUNOS_EMUL
/* Now the SunOS syscall table. */
@@ -198,6 +197,6 @@ sunos_sys_table:
.long sunos_nosys, sunos_nosys, sunos_nosys
.long sunos_nosys
/*310*/ .long sunos_nosys, sunos_nosys, sunos_nosys
- .long sunos_nosys
+ .long sunos_nosys, sunos_nosys
#endif
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index f1a7bd19e04f..707bfda86570 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -25,6 +25,8 @@
#include <asm/irq.h>
#include <asm/io.h>
+#include "irq.h"
+
extern unsigned long lvl14_save[5];
static unsigned long *linux_lvl14 = NULL;
static unsigned long obp_lvl14[4];
@@ -62,7 +64,7 @@ void claim_ticker14(irq_handler_t handler,
/* first we copy the obp handler instructions
*/
- disable_irq(irq_nr);
+ __disable_irq(irq_nr);
if (!handler)
return;
@@ -79,6 +81,6 @@ void claim_ticker14(irq_handler_t handler,
NULL)) {
install_linux_ticker();
load_profile_irq(cpu, timeout);
- enable_irq(irq_nr);
+ __enable_irq(irq_nr);
}
}
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 7b4612da74a6..6a2513321620 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -44,6 +44,8 @@
#include <asm/of_device.h>
#include <asm/irq_regs.h>
+#include "irq.h"
+
DEFINE_SPINLOCK(rtc_lock);
enum sparc_clock_type sp_clock_typ;
DEFINE_SPINLOCK(mostek_lock);
@@ -354,7 +356,7 @@ static struct of_platform_driver clock_driver = {
/* Probe for the mostek real time clock chip. */
static int __init clock_init(void)
{
- return of_register_driver(&clock_driver, &of_bus_type);
+ return of_register_driver(&clock_driver, &of_platform_bus_type);
}
/* Must be after subsys_initcall() so that busses are probed. Must
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
index dc9ffea2a4f7..3bc3bff51e08 100644
--- a/arch/sparc/kernel/traps.c
+++ b/arch/sparc/kernel/traps.c
@@ -101,6 +101,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
printk("%s(%d): %s [#%d]\n", current->comm, current->pid, str, ++die_counter);
show_regs(regs);
+ add_taint(TAINT_DIE);
__SAVE; __SAVE; __SAVE; __SAVE;
__SAVE; __SAVE; __SAVE; __SAVE;
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index f75a1b822789..47583887abc6 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -65,10 +65,7 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(4096);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(4096)
. = ALIGN(4096);
__init_end = .;
. = ALIGN(32);
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
index c3483365db4b..50747fe44356 100644
--- a/arch/sparc/mm/fault.c
+++ b/arch/sparc/mm/fault.c
@@ -226,6 +226,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long g2;
siginfo_t info;
int from_user = !(regs->psr & PSR_PS);
+ int fault;
if(text_fault)
address = regs->pc;
@@ -289,19 +290,18 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- switch (handle_mm_fault(mm, vma, address, write)) {
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- case VM_FAULT_MAJOR:
+ fault = handle_mm_fault(mm, vma, address, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
current->maj_flt++;
- break;
- case VM_FAULT_MINOR:
- default:
+ else
current->min_flt++;
- break;
- }
up_read(&mm->mmap_sem);
return;
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
index a532922e2e35..a1bef07755a9 100644
--- a/arch/sparc/mm/init.c
+++ b/arch/sparc/mm/init.c
@@ -308,6 +308,9 @@ extern void sun4c_paging_init(void);
extern void srmmu_paging_init(void);
extern void device_scan(void);
+pgprot_t PAGE_SHARED __read_mostly;
+EXPORT_SYMBOL(PAGE_SHARED);
+
void __init paging_init(void)
{
switch(sparc_cpu_model) {
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index e5eaa8072ae0..17b485f2825c 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -160,9 +160,6 @@ static inline int srmmu_pte_none(pte_t pte)
static inline int srmmu_pte_present(pte_t pte)
{ return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); }
-static inline int srmmu_pte_read(pte_t pte)
-{ return !(pte_val(pte) & SRMMU_NOREAD); }
-
static inline void srmmu_pte_clear(pte_t *ptep)
{ srmmu_set_pte(ptep, __pte(0)); }
@@ -2157,7 +2154,7 @@ void __init ld_mmu_srmmu(void)
BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD);
BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE));
- BTFIXUPSET_INT(page_shared, pgprot_val(SRMMU_PAGE_SHARED));
+ PAGE_SHARED = pgprot_val(SRMMU_PAGE_SHARED);
BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY));
BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY));
BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL));
@@ -2181,7 +2178,6 @@ void __init ld_mmu_srmmu(void)
BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0);
- BTFIXUPSET_CALL(pte_read, srmmu_pte_read, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pmd_bad, srmmu_pmd_bad, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pmd_present, srmmu_pmd_present, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
index 436021ceb2e7..a57a366e339a 100644
--- a/arch/sparc/mm/sun4c.c
+++ b/arch/sparc/mm/sun4c.c
@@ -1748,11 +1748,6 @@ static int sun4c_pte_present(pte_t pte)
}
static void sun4c_pte_clear(pte_t *ptep) { *ptep = __pte(0); }
-static int sun4c_pte_read(pte_t pte)
-{
- return (pte_val(pte) & _SUN4C_PAGE_READ);
-}
-
static int sun4c_pmd_bad(pmd_t pmd)
{
return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) ||
@@ -2160,7 +2155,7 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE);
BTFIXUPSET_INT(page_none, pgprot_val(SUN4C_PAGE_NONE));
- BTFIXUPSET_INT(page_shared, pgprot_val(SUN4C_PAGE_SHARED));
+ PAGE_SHARED = pgprot_val(SUN4C_PAGE_SHARED);
BTFIXUPSET_INT(page_copy, pgprot_val(SUN4C_PAGE_COPY));
BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY));
BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL));
@@ -2212,7 +2207,6 @@ void __init ld_mmu_sun4c(void)
BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0);
- BTFIXUPSET_CALL(pte_read, sun4c_pte_read, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pmd_bad, sun4c_pmd_bad, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pmd_present, sun4c_pmd_present, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c
index 4e6e41d3291d..8d1cfb0d5068 100644
--- a/arch/sparc/prom/console.c
+++ b/arch/sparc/prom/console.c
@@ -102,119 +102,3 @@ prom_putchar(char c)
while(prom_nbputchar(c) == -1) ;
return;
}
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
- unsigned long flags;
- int st_p;
- char propb[64];
- char *p;
- int propl;
-
- switch(prom_vers) {
- case PROM_V0:
- case PROM_V2:
- case PROM_SUN4:
- default:
- switch(*romvec->pv_stdin) {
- case PROMDEV_KBD: return PROMDEV_IKBD;
- case PROMDEV_TTYA: return PROMDEV_ITTYA;
- case PROMDEV_TTYB: return PROMDEV_ITTYB;
- default:
- return PROMDEV_I_UNK;
- };
- case PROM_V3:
- spin_lock_irqsave(&prom_lock, flags);
- st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
- restore_current();
- spin_unlock_irqrestore(&prom_lock, flags);
- if(prom_node_has_property(st_p, "keyboard"))
- return PROMDEV_IKBD;
- if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
- if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
- return PROMDEV_IKBD;
- }
- if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
- if(strncmp(propb, "serial", sizeof("serial")))
- return PROMDEV_I_UNK;
- }
- propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
- if(propl > 2) {
- p = propb;
- while(*p) p++; p -= 2;
- if(p[0] == ':') {
- if(p[1] == 'a')
- return PROMDEV_ITTYA;
- else if(p[1] == 'b')
- return PROMDEV_ITTYB;
- }
- }
- return PROMDEV_I_UNK;
- }
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
- unsigned long flags;
- int st_p;
- char propb[64];
- char *p;
- int propl;
-
- switch(prom_vers) {
- case PROM_V0:
- case PROM_SUN4:
- switch(*romvec->pv_stdin) {
- case PROMDEV_SCREEN: return PROMDEV_OSCREEN;
- case PROMDEV_TTYA: return PROMDEV_OTTYA;
- case PROMDEV_TTYB: return PROMDEV_OTTYB;
- };
- break;
- case PROM_V2:
- case PROM_V3:
- spin_lock_irqsave(&prom_lock, flags);
- st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
- restore_current();
- spin_unlock_irqrestore(&prom_lock, flags);
- propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
- if (propl == sizeof("display") &&
- strncmp("display", propb, sizeof("display")) == 0)
- {
- return PROMDEV_OSCREEN;
- }
- if(prom_vers == PROM_V3) {
- if(propl >= 0 &&
- strncmp("serial", propb, sizeof("serial")) != 0)
- return PROMDEV_O_UNK;
- propl = prom_getproperty(prom_root_node, "stdout-path",
- propb, sizeof(propb));
- if(propl == CON_SIZE_JMC &&
- strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
- return PROMDEV_OTTYA;
- if(propl > 2) {
- p = propb;
- while(*p) p++; p-= 2;
- if(p[0]==':') {
- if(p[1] == 'a')
- return PROMDEV_OTTYA;
- else if(p[1] == 'b')
- return PROMDEV_OTTYB;
- }
- }
- } else {
- switch(*romvec->pv_stdin) {
- case PROMDEV_TTYA: return PROMDEV_OTTYA;
- case PROMDEV_TTYB: return PROMDEV_OTTYB;
- };
- }
- break;
- default:
- ;
- };
- return PROMDEV_O_UNK;
-}
diff --git a/arch/sparc/prom/misc.c b/arch/sparc/prom/misc.c
index 1942c7c05cb1..37cff5f54704 100644
--- a/arch/sparc/prom/misc.c
+++ b/arch/sparc/prom/misc.c
@@ -58,7 +58,7 @@ prom_cmdline(void)
extern void install_linux_ticker(void);
unsigned long flags;
- if(!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (1);
spin_lock_irqsave(&prom_lock, flags);
install_obp_ticker();
@@ -69,7 +69,7 @@ prom_cmdline(void)
#ifdef CONFIG_SUN_AUXIO
set_auxio(AUXIO_LED, 0);
#endif
- if(!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (0);
}
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 89a1b469b93d..33dabf588bdd 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -23,6 +23,10 @@ config GENERIC_TIME
bool
default y
+config GENERIC_CMOS_UPDATE
+ bool
+ default y
+
config GENERIC_CLOCKEVENTS
bool
default y
@@ -62,6 +66,12 @@ config AUDIT_ARCH
bool
default y
+config ARCH_NO_VIRT_TO_BUS
+ def_bool y
+
+config OF
+ def_bool y
+
choice
prompt "Kernel page size"
default SPARC64_PAGE_SIZE_8KB
@@ -108,6 +118,15 @@ config SECCOMP
source kernel/Kconfig.hz
+config HOTPLUG_CPU
+ bool "Support for hot-pluggable CPUs"
+ depends on SMP
+ select HOTPLUG
+ ---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.
+
source "init/Kconfig"
config SYSVIPC_COMPAT
@@ -305,6 +324,12 @@ config SUN_IO
bool
default y
+config SUN_LDOMS
+ bool "Sun Logical Domains support"
+ help
+ Say Y here is you want to support virtual devices via
+ Logical Domains.
+
config PCI
bool "PCI support"
select ARCH_SUPPORTS_MSI
@@ -320,8 +345,10 @@ config PCI
doesn't.
config PCI_DOMAINS
- bool
- default PCI
+ def_bool PCI
+
+config PCI_SYSCALL
+ def_bool PCI
source "drivers/pci/Kconfig"
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 65840a62bb9c..10e301970a44 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.22-rc1
-# Mon May 14 04:17:48 2007
+# Linux kernel version: 2.6.22
+# Thu Jul 19 21:30:37 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -16,6 +16,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_AUDIT_ARCH=y
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
CONFIG_SPARC64_PAGE_SIZE_8KB=y
# CONFIG_SPARC64_PAGE_SIZE_64KB is not set
# CONFIG_SPARC64_PAGE_SIZE_512KB is not set
@@ -42,12 +43,11 @@ CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_LOG_BUF_SHIFT=18
@@ -82,22 +82,15 @@ CONFIG_SLUB=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BLK_DEV_BSG=y
#
# IO Schedulers
@@ -160,8 +153,10 @@ CONFIG_SBUS=y
CONFIG_SBUSCHAR=y
CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
+# CONFIG_SUN_LDOMS is not set
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
CONFIG_ARCH_SUPPORTS_MSI=y
CONFIG_PCI_MSI=y
# CONFIG_PCI_DEBUG is not set
@@ -246,10 +241,6 @@ CONFIG_IPV6_TUNNEL=m
# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
CONFIG_IP_DCCP=m
CONFIG_INET_DCCP_DIAG=m
CONFIG_IP_DCCP_ACKVEC=y
@@ -269,15 +260,7 @@ CONFIG_IP_DCCP_CCID3_RTO=100
#
# CONFIG_IP_DCCP_DEBUG is not set
# CONFIG_NET_DCCPPROBE 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
@@ -314,6 +297,7 @@ CONFIG_NET_TCPPROBE=m
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -328,28 +312,11 @@ CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
CONFIG_CONNECTOR=m
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
# CONFIG_BLK_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
@@ -364,18 +331,11 @@ CONFIG_CDROM_PKTCDVD=m
CONFIG_CDROM_PKTCDVD_BUFFERS=8
CONFIG_CDROM_PKTCDVD_WCACHE=y
CONFIG_ATA_OVER_ETH=m
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
-# CONFIG_BLINK is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y
@@ -440,6 +400,7 @@ CONFIG_BLK_DEV_IDEDMA=y
#
CONFIG_RAID_ATTRS=m
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
@@ -505,14 +466,9 @@ CONFIG_ISCSI_TCP=m
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SUNESP is not set
# CONFIG_SCSI_SRP is not set
# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
@@ -545,30 +501,16 @@ CONFIG_DM_ZERO=m
#
# CONFIG_FIREWIRE is not set
# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-
-#
-# Network device support
-#
CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=m
# CONFIG_SUNLANCE is not set
@@ -578,10 +520,6 @@ CONFIG_MII=m
# CONFIG_SUNGEM is not set
CONFIG_CASSINI=m
# 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=y
@@ -617,7 +555,6 @@ CONFIG_E1000_NAPI=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=m
CONFIG_BNX2=m
@@ -631,11 +568,6 @@ CONFIG_NETDEV_10000=y
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_MLX4_CORE is not set
-CONFIG_MLX4_DEBUG=y
-
-#
-# Token Ring devices
-#
# CONFIG_TR is not set
#
@@ -665,6 +597,7 @@ CONFIG_PPP_DEFLATE=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_MPPE=m
CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
# CONFIG_SLIP is not set
CONFIG_SLHC=m
# CONFIG_NET_FC is not set
@@ -672,15 +605,7 @@ CONFIG_SLHC=m
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -688,6 +613,7 @@ CONFIG_SLHC=m
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -733,7 +659,6 @@ CONFIG_INPUT_SPARCSPKR=y
# CONFIG_INPUT_POWERMATE is not set
# CONFIG_INPUT_YEALINK is not set
# CONFIG_INPUT_UINPUT is not set
-# CONFIG_INPUT_POLLDEV is not set
#
# Hardware I/O ports
@@ -773,10 +698,6 @@ CONFIG_SERIAL_CORE_CONSOLE=y
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
@@ -785,10 +706,6 @@ CONFIG_RTC=y
# CONFIG_APPLICOM is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
CONFIG_DEVPORT=y
CONFIG_I2C=y
@@ -822,6 +739,7 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
# CONFIG_I2C_STUB is not set
# CONFIG_I2C_TINY_USB is not set
# CONFIG_I2C_VIA is not set
@@ -833,11 +751,13 @@ CONFIG_I2C_ALGOBIT=y
#
# CONFIG_SENSORS_DS1337 is not set
# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_DS1682 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -848,14 +768,12 @@ CONFIG_I2C_ALGOBIT=y
#
# CONFIG_SPI is not set
# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ABITUGURU3 is not set
# CONFIG_SENSORS_AD7418 is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
@@ -882,11 +800,13 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_MAX6650 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_PC87427 is not set
# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -949,6 +869,8 @@ CONFIG_FB_TILEBLITTING=y
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_SBUS is not set
+# CONFIG_FB_XVR500 is not set
+# CONFIG_FB_XVR2500 is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
@@ -970,9 +892,6 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_ARK is not set
# CONFIG_FB_PM3 is not set
-# CONFIG_FB_XVR500 is not set
-# CONFIG_FB_XVR2500 is not set
-# CONFIG_FB_PCI is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -981,6 +900,7 @@ CONFIG_FB_RADEON_I2C=y
# CONFIG_PROM_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
# CONFIG_FONT_8x8 is not set
@@ -1118,10 +1038,7 @@ CONFIG_SND_SUN_CS4231=m
#
# CONFIG_SOUND_PRIME is not set
CONFIG_AC97_BUS=m
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
@@ -1132,10 +1049,7 @@ CONFIG_USB_HID=y
# CONFIG_USB_HIDINPUT_POWERBOOK is not set
# CONFIG_HID_FF is not set
CONFIG_USB_HIDDEV=y
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1157,7 +1071,6 @@ CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1165,6 +1078,7 @@ CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=m
# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
#
# USB Device Class drivers
@@ -1256,17 +1170,9 @@ CONFIG_USB_STORAGE=m
#
# 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
@@ -1285,6 +1191,11 @@ CONFIG_USB_STORAGE=m
#
#
+# Userspace I/O
+#
+# CONFIG_UIO is not set
+
+#
# Misc Linux/SPARC drivers
#
CONFIG_SUN_OPENPROMIO=m
@@ -1387,7 +1298,6 @@ CONFIG_RAMFS=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -1465,14 +1375,17 @@ CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
CONFIG_SCHEDSTATS=y
# CONFIG_TIMER_STATS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1496,10 +1409,10 @@ CONFIG_FORCED_INLINING=y
CONFIG_KEYS=y
# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
@@ -1539,10 +1452,7 @@ CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_TEST=m
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
#
# Library routines
@@ -1552,6 +1462,7 @@ CONFIG_CRC_CCITT=m
CONFIG_CRC16=m
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index f964bf28d21a..b66876bf410c 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
-obj-$(CONFIG_SMP) += smp.o trampoline.o
+obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o
@@ -26,6 +26,7 @@ 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-y += $(obj-yy)
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 826118ee53d5..7b379761e9f8 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -155,7 +155,7 @@ static struct of_platform_driver auxio_driver = {
static int __init auxio_init(void)
{
- return of_register_driver(&auxio_driver, &of_bus_type);
+ return of_register_driver(&auxio_driver, &of_platform_bus_type);
}
/* Must be after subsys_initcall() so that busses are probed. Must
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
new file mode 100644
index 000000000000..9f472a79d37e
--- /dev/null
+++ b/arch/sparc64/kernel/ds.c
@@ -0,0 +1,1246 @@
+/* ds.c: Domain Services driver for Logical Domains
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/reboot.h>
+#include <linux/cpu.h>
+
+#include <asm/ldc.h>
+#include <asm/vio.h>
+#include <asm/mdesc.h>
+#include <asm/head.h>
+#include <asm/irq.h>
+
+#define DRV_MODULE_NAME "ds"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.0"
+#define DRV_MODULE_RELDATE "Jul 11, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun LDOM domain services driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+struct ds_msg_tag {
+ __u32 type;
+#define DS_INIT_REQ 0x00
+#define DS_INIT_ACK 0x01
+#define DS_INIT_NACK 0x02
+#define DS_REG_REQ 0x03
+#define DS_REG_ACK 0x04
+#define DS_REG_NACK 0x05
+#define DS_UNREG_REQ 0x06
+#define DS_UNREG_ACK 0x07
+#define DS_UNREG_NACK 0x08
+#define DS_DATA 0x09
+#define DS_NACK 0x0a
+
+ __u32 len;
+};
+
+/* Result codes */
+#define DS_OK 0x00
+#define DS_REG_VER_NACK 0x01
+#define DS_REG_DUP 0x02
+#define DS_INV_HDL 0x03
+#define DS_TYPE_UNKNOWN 0x04
+
+struct ds_version {
+ __u16 major;
+ __u16 minor;
+};
+
+struct ds_ver_req {
+ struct ds_msg_tag tag;
+ struct ds_version ver;
+};
+
+struct ds_ver_ack {
+ struct ds_msg_tag tag;
+ __u16 minor;
+};
+
+struct ds_ver_nack {
+ struct ds_msg_tag tag;
+ __u16 major;
+};
+
+struct ds_reg_req {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u16 major;
+ __u16 minor;
+ char svc_id[0];
+};
+
+struct ds_reg_ack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u16 minor;
+};
+
+struct ds_reg_nack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u16 major;
+};
+
+struct ds_unreg_req {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_unreg_ack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_unreg_nack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_data {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_data_nack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u64 result;
+};
+
+struct ds_info;
+struct ds_cap_state {
+ __u64 handle;
+
+ void (*data)(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+
+ const char *service_id;
+
+ u8 state;
+#define CAP_STATE_UNKNOWN 0x00
+#define CAP_STATE_REG_SENT 0x01
+#define CAP_STATE_REGISTERED 0x02
+};
+
+static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
+ void *buf, int len);
+static void domain_shutdown_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+static void domain_panic_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+#ifdef CONFIG_HOTPLUG_CPU
+static void dr_cpu_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+#endif
+static void ds_pri_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+static void ds_var_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+
+struct ds_cap_state ds_states_template[] = {
+ {
+ .service_id = "md-update",
+ .data = md_update_data,
+ },
+ {
+ .service_id = "domain-shutdown",
+ .data = domain_shutdown_data,
+ },
+ {
+ .service_id = "domain-panic",
+ .data = domain_panic_data,
+ },
+#ifdef CONFIG_HOTPLUG_CPU
+ {
+ .service_id = "dr-cpu",
+ .data = dr_cpu_data,
+ },
+#endif
+ {
+ .service_id = "pri",
+ .data = ds_pri_data,
+ },
+ {
+ .service_id = "var-config",
+ .data = ds_var_data,
+ },
+ {
+ .service_id = "var-config-backup",
+ .data = ds_var_data,
+ },
+};
+
+static DEFINE_SPINLOCK(ds_lock);
+
+struct ds_info {
+ struct ldc_channel *lp;
+ u8 hs_state;
+#define DS_HS_START 0x01
+#define DS_HS_DONE 0x02
+
+ u64 id;
+
+ void *rcv_buf;
+ int rcv_buf_len;
+
+ struct ds_cap_state *ds_states;
+ int num_ds_states;
+
+ struct ds_info *next;
+};
+
+static struct ds_info *ds_info_list;
+
+static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
+{
+ unsigned int index = handle >> 32;
+
+ if (index >= dp->num_ds_states)
+ return NULL;
+ return &dp->ds_states[index];
+}
+
+static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
+ const char *name)
+{
+ int i;
+
+ for (i = 0; i < dp->num_ds_states; i++) {
+ if (strcmp(dp->ds_states[i].service_id, name))
+ continue;
+
+ return &dp->ds_states[i];
+ }
+ return NULL;
+}
+
+static int __ds_send(struct ldc_channel *lp, void *data, int len)
+{
+ int err, limit = 1000;
+
+ err = -EINVAL;
+ while (limit-- > 0) {
+ err = ldc_write(lp, data, len);
+ if (!err || (err != -EAGAIN))
+ break;
+ udelay(1);
+ }
+
+ return err;
+}
+
+static int ds_send(struct ldc_channel *lp, void *data, int len)
+{
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&ds_lock, flags);
+ err = __ds_send(lp, data, len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ return err;
+}
+
+struct ds_md_update_req {
+ __u64 req_num;
+};
+
+struct ds_md_update_res {
+ __u64 req_num;
+ __u32 result;
+};
+
+static void md_update_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_data *dpkt = buf;
+ struct ds_md_update_req *rp;
+ struct {
+ struct ds_data data;
+ struct ds_md_update_res res;
+ } pkt;
+
+ rp = (struct ds_md_update_req *) (dpkt + 1);
+
+ printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
+
+ mdesc_update();
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
+ pkt.data.handle = cp->handle;
+ pkt.res.req_num = rp->req_num;
+ pkt.res.result = DS_OK;
+
+ ds_send(lp, &pkt, sizeof(pkt));
+}
+
+struct ds_shutdown_req {
+ __u64 req_num;
+ __u32 ms_delay;
+};
+
+struct ds_shutdown_res {
+ __u64 req_num;
+ __u32 result;
+ char reason[1];
+};
+
+static void domain_shutdown_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_data *dpkt = buf;
+ struct ds_shutdown_req *rp;
+ struct {
+ struct ds_data data;
+ struct ds_shutdown_res res;
+ } pkt;
+
+ rp = (struct ds_shutdown_req *) (dpkt + 1);
+
+ printk(KERN_ALERT "ds-%lu: Shutdown request from "
+ "LDOM manager received.\n", dp->id);
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
+ pkt.data.handle = cp->handle;
+ pkt.res.req_num = rp->req_num;
+ pkt.res.result = DS_OK;
+ pkt.res.reason[0] = 0;
+
+ ds_send(lp, &pkt, sizeof(pkt));
+
+ orderly_poweroff(true);
+}
+
+struct ds_panic_req {
+ __u64 req_num;
+};
+
+struct ds_panic_res {
+ __u64 req_num;
+ __u32 result;
+ char reason[1];
+};
+
+static void domain_panic_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_data *dpkt = buf;
+ struct ds_panic_req *rp;
+ struct {
+ struct ds_data data;
+ struct ds_panic_res res;
+ } pkt;
+
+ rp = (struct ds_panic_req *) (dpkt + 1);
+
+ printk(KERN_ALERT "ds-%lu: Panic request from "
+ "LDOM manager received.\n", dp->id);
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
+ pkt.data.handle = cp->handle;
+ pkt.res.req_num = rp->req_num;
+ pkt.res.result = DS_OK;
+ pkt.res.reason[0] = 0;
+
+ ds_send(lp, &pkt, sizeof(pkt));
+
+ panic("PANIC requested by LDOM manager.");
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+struct dr_cpu_tag {
+ __u64 req_num;
+ __u32 type;
+#define DR_CPU_CONFIGURE 0x43
+#define DR_CPU_UNCONFIGURE 0x55
+#define DR_CPU_FORCE_UNCONFIGURE 0x46
+#define DR_CPU_STATUS 0x53
+
+/* Responses */
+#define DR_CPU_OK 0x6f
+#define DR_CPU_ERROR 0x65
+
+ __u32 num_records;
+};
+
+struct dr_cpu_resp_entry {
+ __u32 cpu;
+ __u32 result;
+#define DR_CPU_RES_OK 0x00
+#define DR_CPU_RES_FAILURE 0x01
+#define DR_CPU_RES_BLOCKED 0x02
+#define DR_CPU_RES_CPU_NOT_RESPONDING 0x03
+#define DR_CPU_RES_NOT_IN_MD 0x04
+
+ __u32 stat;
+#define DR_CPU_STAT_NOT_PRESENT 0x00
+#define DR_CPU_STAT_UNCONFIGURED 0x01
+#define DR_CPU_STAT_CONFIGURED 0x02
+
+ __u32 str_off;
+};
+
+static void __dr_cpu_send_error(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ struct ds_data *data)
+{
+ struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
+ struct {
+ struct ds_data data;
+ struct dr_cpu_tag tag;
+ } pkt;
+ int msg_len;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.handle = cp->handle;
+ pkt.tag.req_num = tag->req_num;
+ pkt.tag.type = DR_CPU_ERROR;
+ pkt.tag.num_records = 0;
+
+ msg_len = (sizeof(struct ds_data) +
+ sizeof(struct dr_cpu_tag));
+
+ pkt.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
+
+ __ds_send(dp->lp, &pkt, msg_len);
+}
+
+static void dr_cpu_send_error(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ struct ds_data *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __dr_cpu_send_error(dp, cp, data);
+ spin_unlock_irqrestore(&ds_lock, flags);
+}
+
+#define CPU_SENTINEL 0xffffffff
+
+static void purge_dups(u32 *list, u32 num_ents)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_ents; i++) {
+ u32 cpu = list[i];
+ unsigned int j;
+
+ if (cpu == CPU_SENTINEL)
+ continue;
+
+ for (j = i + 1; j < num_ents; j++) {
+ if (list[j] == cpu)
+ list[j] = CPU_SENTINEL;
+ }
+ }
+}
+
+static int dr_cpu_size_response(int ncpus)
+{
+ return (sizeof(struct ds_data) +
+ sizeof(struct dr_cpu_tag) +
+ (sizeof(struct dr_cpu_resp_entry) * ncpus));
+}
+
+static void dr_cpu_init_response(struct ds_data *resp, u64 req_num,
+ u64 handle, int resp_len, int ncpus,
+ cpumask_t *mask, u32 default_stat)
+{
+ struct dr_cpu_resp_entry *ent;
+ struct dr_cpu_tag *tag;
+ int i, cpu;
+
+ tag = (struct dr_cpu_tag *) (resp + 1);
+ ent = (struct dr_cpu_resp_entry *) (tag + 1);
+
+ resp->tag.type = DS_DATA;
+ resp->tag.len = resp_len - sizeof(struct ds_msg_tag);
+ resp->handle = handle;
+ tag->req_num = req_num;
+ tag->type = DR_CPU_OK;
+ tag->num_records = ncpus;
+
+ i = 0;
+ for_each_cpu_mask(cpu, *mask) {
+ ent[i].cpu = cpu;
+ ent[i].result = DR_CPU_RES_OK;
+ ent[i].stat = default_stat;
+ i++;
+ }
+ BUG_ON(i != ncpus);
+}
+
+static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
+ u32 res, u32 stat)
+{
+ struct dr_cpu_resp_entry *ent;
+ struct dr_cpu_tag *tag;
+ int i;
+
+ tag = (struct dr_cpu_tag *) (resp + 1);
+ ent = (struct dr_cpu_resp_entry *) (tag + 1);
+
+ for (i = 0; i < ncpus; i++) {
+ if (ent[i].cpu != cpu)
+ continue;
+ ent[i].result = res;
+ ent[i].stat = stat;
+ break;
+ }
+}
+
+static int dr_cpu_configure(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ u64 req_num,
+ cpumask_t *mask)
+{
+ struct ds_data *resp;
+ int resp_len, ncpus, cpu;
+ unsigned long flags;
+
+ ncpus = cpus_weight(*mask);
+ resp_len = dr_cpu_size_response(ncpus);
+ resp = kzalloc(resp_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ dr_cpu_init_response(resp, req_num, cp->handle,
+ resp_len, ncpus, mask,
+ DR_CPU_STAT_CONFIGURED);
+
+ mdesc_fill_in_cpu_data(*mask);
+
+ for_each_cpu_mask(cpu, *mask) {
+ int err;
+
+ printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
+ dp->id, cpu);
+ err = cpu_up(cpu);
+ if (err) {
+ __u32 res = DR_CPU_RES_FAILURE;
+ __u32 stat = DR_CPU_STAT_UNCONFIGURED;
+
+ if (!cpu_present(cpu)) {
+ /* CPU not present in MD */
+ res = DR_CPU_RES_NOT_IN_MD;
+ stat = DR_CPU_STAT_NOT_PRESENT;
+ } else if (err == -ENODEV) {
+ /* CPU did not call in successfully */
+ res = DR_CPU_RES_CPU_NOT_RESPONDING;
+ }
+
+ printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
+ dp->id, err);
+ dr_cpu_mark(resp, cpu, ncpus, res, stat);
+ }
+ }
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __ds_send(dp->lp, resp, resp_len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ kfree(resp);
+
+ /* Redistribute IRQs, taking into account the new cpus. */
+ fixup_irqs();
+
+ return 0;
+}
+
+static int dr_cpu_unconfigure(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ u64 req_num,
+ cpumask_t *mask)
+{
+ struct ds_data *resp;
+ int resp_len, ncpus, cpu;
+ unsigned long flags;
+
+ ncpus = cpus_weight(*mask);
+ resp_len = dr_cpu_size_response(ncpus);
+ resp = kzalloc(resp_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ dr_cpu_init_response(resp, req_num, cp->handle,
+ resp_len, ncpus, mask,
+ DR_CPU_STAT_UNCONFIGURED);
+
+ for_each_cpu_mask(cpu, *mask) {
+ int err;
+
+ printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
+ dp->id, cpu);
+ err = cpu_down(cpu);
+ if (err)
+ dr_cpu_mark(resp, cpu, ncpus,
+ DR_CPU_RES_FAILURE,
+ DR_CPU_STAT_CONFIGURED);
+ }
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __ds_send(dp->lp, resp, resp_len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ kfree(resp);
+
+ return 0;
+}
+
+static void dr_cpu_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ds_data *data = buf;
+ struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
+ u32 *cpu_list = (u32 *) (tag + 1);
+ u64 req_num = tag->req_num;
+ cpumask_t mask;
+ unsigned int i;
+ int err;
+
+ switch (tag->type) {
+ case DR_CPU_CONFIGURE:
+ case DR_CPU_UNCONFIGURE:
+ case DR_CPU_FORCE_UNCONFIGURE:
+ break;
+
+ default:
+ dr_cpu_send_error(dp, cp, data);
+ return;
+ }
+
+ purge_dups(cpu_list, tag->num_records);
+
+ cpus_clear(mask);
+ for (i = 0; i < tag->num_records; i++) {
+ if (cpu_list[i] == CPU_SENTINEL)
+ continue;
+
+ if (cpu_list[i] < NR_CPUS)
+ cpu_set(cpu_list[i], mask);
+ }
+
+ if (tag->type == DR_CPU_CONFIGURE)
+ err = dr_cpu_configure(dp, cp, req_num, &mask);
+ else
+ err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
+
+ if (err)
+ dr_cpu_send_error(dp, cp, data);
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+struct ds_pri_msg {
+ __u64 req_num;
+ __u64 type;
+#define DS_PRI_REQUEST 0x00
+#define DS_PRI_DATA 0x01
+#define DS_PRI_UPDATE 0x02
+};
+
+static void ds_pri_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ds_data *dpkt = buf;
+ struct ds_pri_msg *rp;
+
+ rp = (struct ds_pri_msg *) (dpkt + 1);
+
+ printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
+ dp->id, rp->req_num, rp->type, len);
+}
+
+struct ds_var_hdr {
+ __u32 type;
+#define DS_VAR_SET_REQ 0x00
+#define DS_VAR_DELETE_REQ 0x01
+#define DS_VAR_SET_RESP 0x02
+#define DS_VAR_DELETE_RESP 0x03
+};
+
+struct ds_var_set_msg {
+ struct ds_var_hdr hdr;
+ char name_and_value[0];
+};
+
+struct ds_var_delete_msg {
+ struct ds_var_hdr hdr;
+ char name[0];
+};
+
+struct ds_var_resp {
+ struct ds_var_hdr hdr;
+ __u32 result;
+#define DS_VAR_SUCCESS 0x00
+#define DS_VAR_NO_SPACE 0x01
+#define DS_VAR_INVALID_VAR 0x02
+#define DS_VAR_INVALID_VAL 0x03
+#define DS_VAR_NOT_PRESENT 0x04
+};
+
+static DEFINE_MUTEX(ds_var_mutex);
+static int ds_var_doorbell;
+static int ds_var_response;
+
+static void ds_var_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ds_data *dpkt = buf;
+ struct ds_var_resp *rp;
+
+ rp = (struct ds_var_resp *) (dpkt + 1);
+
+ if (rp->hdr.type != DS_VAR_SET_RESP &&
+ rp->hdr.type != DS_VAR_DELETE_RESP)
+ return;
+
+ ds_var_response = rp->result;
+ wmb();
+ ds_var_doorbell = 1;
+}
+
+void ldom_set_var(const char *var, const char *value)
+{
+ struct ds_cap_state *cp;
+ struct ds_info *dp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ds_lock, flags);
+ cp = NULL;
+ for (dp = ds_info_list; dp; dp = dp->next) {
+ struct ds_cap_state *tmp;
+
+ tmp = find_cap_by_string(dp, "var-config");
+ if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+ cp = tmp;
+ break;
+ }
+ }
+ if (!cp) {
+ for (dp = ds_info_list; dp; dp = dp->next) {
+ struct ds_cap_state *tmp;
+
+ tmp = find_cap_by_string(dp, "var-config-backup");
+ if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+ cp = tmp;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ if (cp) {
+ union {
+ struct {
+ struct ds_data data;
+ struct ds_var_set_msg msg;
+ } header;
+ char all[512];
+ } pkt;
+ char *base, *p;
+ int msg_len, loops;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.header.data.tag.type = DS_DATA;
+ pkt.header.data.handle = cp->handle;
+ pkt.header.msg.hdr.type = DS_VAR_SET_REQ;
+ base = p = &pkt.header.msg.name_and_value[0];
+ strcpy(p, var);
+ p += strlen(var) + 1;
+ strcpy(p, value);
+ p += strlen(value) + 1;
+
+ msg_len = (sizeof(struct ds_data) +
+ sizeof(struct ds_var_set_msg) +
+ (p - base));
+ msg_len = (msg_len + 3) & ~3;
+ pkt.header.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
+
+ mutex_lock(&ds_var_mutex);
+
+ spin_lock_irqsave(&ds_lock, flags);
+ ds_var_doorbell = 0;
+ ds_var_response = -1;
+
+ __ds_send(dp->lp, &pkt, msg_len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ loops = 1000;
+ while (ds_var_doorbell == 0) {
+ if (loops-- < 0)
+ break;
+ barrier();
+ udelay(100);
+ }
+
+ mutex_unlock(&ds_var_mutex);
+
+ if (ds_var_doorbell == 0 ||
+ ds_var_response != DS_VAR_SUCCESS)
+ printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
+ "failed, response(%d).\n",
+ dp->id, var, value,
+ ds_var_response);
+ } else {
+ printk(KERN_ERR PFX "var-config not registered so "
+ "could not set (%s) variable to (%s).\n",
+ var, value);
+ }
+}
+
+void ldom_reboot(const char *boot_command)
+{
+ /* Don't bother with any of this if the boot_command
+ * is empty.
+ */
+ if (boot_command && strlen(boot_command)) {
+ char full_boot_str[256];
+
+ strcpy(full_boot_str, "boot ");
+ strcpy(full_boot_str + strlen("boot "), boot_command);
+
+ ldom_set_var("reboot-command", full_boot_str);
+ }
+ sun4v_mach_sir();
+}
+
+void ldom_power_off(void)
+{
+ sun4v_mach_exit(0);
+}
+
+static void ds_conn_reset(struct ds_info *dp)
+{
+ printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
+ dp->id, __builtin_return_address(0));
+}
+
+static int register_services(struct ds_info *dp)
+{
+ struct ldc_channel *lp = dp->lp;
+ int i;
+
+ for (i = 0; i < dp->num_ds_states; i++) {
+ struct {
+ struct ds_reg_req req;
+ u8 id_buf[256];
+ } pbuf;
+ struct ds_cap_state *cp = &dp->ds_states[i];
+ int err, msg_len;
+ u64 new_count;
+
+ if (cp->state == CAP_STATE_REGISTERED)
+ continue;
+
+ new_count = sched_clock() & 0xffffffff;
+ cp->handle = ((u64) i << 32) | new_count;
+
+ msg_len = (sizeof(struct ds_reg_req) +
+ strlen(cp->service_id));
+
+ memset(&pbuf, 0, sizeof(pbuf));
+ pbuf.req.tag.type = DS_REG_REQ;
+ pbuf.req.tag.len = (msg_len - sizeof(struct ds_msg_tag));
+ pbuf.req.handle = cp->handle;
+ pbuf.req.major = 1;
+ pbuf.req.minor = 0;
+ strcpy(pbuf.req.svc_id, cp->service_id);
+
+ err = __ds_send(lp, &pbuf, msg_len);
+ if (err > 0)
+ cp->state = CAP_STATE_REG_SENT;
+ }
+ return 0;
+}
+
+static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
+{
+
+ if (dp->hs_state == DS_HS_START) {
+ if (pkt->type != DS_INIT_ACK)
+ goto conn_reset;
+
+ dp->hs_state = DS_HS_DONE;
+
+ return register_services(dp);
+ }
+
+ if (dp->hs_state != DS_HS_DONE)
+ goto conn_reset;
+
+ if (pkt->type == DS_REG_ACK) {
+ struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
+ struct ds_cap_state *cp = find_cap(dp, ap->handle);
+
+ if (!cp) {
+ printk(KERN_ERR "ds-%lu: REG ACK for unknown "
+ "handle %lx\n", dp->id, ap->handle);
+ return 0;
+ }
+ printk(KERN_INFO "ds-%lu: Registered %s service.\n",
+ dp->id, cp->service_id);
+ cp->state = CAP_STATE_REGISTERED;
+ } else if (pkt->type == DS_REG_NACK) {
+ struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
+ struct ds_cap_state *cp = find_cap(dp, np->handle);
+
+ if (!cp) {
+ printk(KERN_ERR "ds-%lu: REG NACK for "
+ "unknown handle %lx\n",
+ dp->id, np->handle);
+ return 0;
+ }
+ cp->state = CAP_STATE_UNKNOWN;
+ }
+
+ return 0;
+
+conn_reset:
+ ds_conn_reset(dp);
+ return -ECONNRESET;
+}
+
+static void __send_ds_nack(struct ds_info *dp, u64 handle)
+{
+ struct ds_data_nack nack = {
+ .tag = {
+ .type = DS_NACK,
+ .len = (sizeof(struct ds_data_nack) -
+ sizeof(struct ds_msg_tag)),
+ },
+ .handle = handle,
+ .result = DS_INV_HDL,
+ };
+
+ __ds_send(dp->lp, &nack, sizeof(nack));
+}
+
+static LIST_HEAD(ds_work_list);
+static DECLARE_WAIT_QUEUE_HEAD(ds_wait);
+
+struct ds_queue_entry {
+ struct list_head list;
+ struct ds_info *dp;
+ int req_len;
+ int __pad;
+ u64 req[0];
+};
+
+static void process_ds_work(void)
+{
+ struct ds_queue_entry *qp, *tmp;
+ unsigned long flags;
+ LIST_HEAD(todo);
+
+ spin_lock_irqsave(&ds_lock, flags);
+ list_splice(&ds_work_list, &todo);
+ INIT_LIST_HEAD(&ds_work_list);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ list_for_each_entry_safe(qp, tmp, &todo, list) {
+ struct ds_data *dpkt = (struct ds_data *) qp->req;
+ struct ds_info *dp = qp->dp;
+ struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
+ int req_len = qp->req_len;
+
+ if (!cp) {
+ printk(KERN_ERR "ds-%lu: Data for unknown "
+ "handle %lu\n",
+ dp->id, dpkt->handle);
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __send_ds_nack(dp, dpkt->handle);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ } else {
+ cp->data(dp, cp, dpkt, req_len);
+ }
+
+ list_del(&qp->list);
+ kfree(qp);
+ }
+}
+
+static int ds_thread(void *__unused)
+{
+ DEFINE_WAIT(wait);
+
+ while (1) {
+ prepare_to_wait(&ds_wait, &wait, TASK_INTERRUPTIBLE);
+ if (list_empty(&ds_work_list))
+ schedule();
+ finish_wait(&ds_wait, &wait);
+
+ if (kthread_should_stop())
+ break;
+
+ process_ds_work();
+ }
+
+ return 0;
+}
+
+static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
+{
+ struct ds_data *dpkt = (struct ds_data *) pkt;
+ struct ds_queue_entry *qp;
+
+ qp = kmalloc(sizeof(struct ds_queue_entry) + len, GFP_ATOMIC);
+ if (!qp) {
+ __send_ds_nack(dp, dpkt->handle);
+ } else {
+ qp->dp = dp;
+ memcpy(&qp->req, pkt, len);
+ list_add_tail(&qp->list, &ds_work_list);
+ wake_up(&ds_wait);
+ }
+ return 0;
+}
+
+static void ds_up(struct ds_info *dp)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_ver_req req;
+ int err;
+
+ req.tag.type = DS_INIT_REQ;
+ req.tag.len = sizeof(req) - sizeof(struct ds_msg_tag);
+ req.ver.major = 1;
+ req.ver.minor = 0;
+
+ err = __ds_send(lp, &req, sizeof(req));
+ if (err > 0)
+ dp->hs_state = DS_HS_START;
+}
+
+static void ds_reset(struct ds_info *dp)
+{
+ int i;
+
+ dp->hs_state = 0;
+
+ for (i = 0; i < dp->num_ds_states; i++) {
+ struct ds_cap_state *cp = &dp->ds_states[i];
+
+ cp->state = CAP_STATE_UNKNOWN;
+ }
+}
+
+static void ds_event(void *arg, int event)
+{
+ struct ds_info *dp = arg;
+ struct ldc_channel *lp = dp->lp;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&ds_lock, flags);
+
+ if (event == LDC_EVENT_UP) {
+ ds_up(dp);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
+ if (event == LDC_EVENT_RESET) {
+ ds_reset(dp);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
+ if (event != LDC_EVENT_DATA_READY) {
+ printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
+ dp->id, event);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
+ err = 0;
+ while (1) {
+ struct ds_msg_tag *tag;
+
+ err = ldc_read(lp, dp->rcv_buf, sizeof(*tag));
+
+ if (unlikely(err < 0)) {
+ if (err == -ECONNRESET)
+ ds_conn_reset(dp);
+ break;
+ }
+ if (err == 0)
+ break;
+
+ tag = dp->rcv_buf;
+ err = ldc_read(lp, tag + 1, tag->len);
+
+ if (unlikely(err < 0)) {
+ if (err == -ECONNRESET)
+ ds_conn_reset(dp);
+ break;
+ }
+ if (err < tag->len)
+ break;
+
+ if (tag->type < DS_DATA)
+ err = ds_handshake(dp, dp->rcv_buf);
+ else
+ err = ds_data(dp, dp->rcv_buf,
+ sizeof(*tag) + err);
+ if (err == -ECONNRESET)
+ break;
+ }
+
+ spin_unlock_irqrestore(&ds_lock, flags);
+}
+
+static int __devinit ds_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ static int ds_version_printed;
+ struct ldc_channel_config ds_cfg = {
+ .event = ds_event,
+ .mtu = 4096,
+ .mode = LDC_MODE_STREAM,
+ };
+ struct mdesc_handle *hp;
+ struct ldc_channel *lp;
+ struct ds_info *dp;
+ const u64 *val;
+ int err, i;
+
+ if (ds_version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ dp = kzalloc(sizeof(*dp), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!dp)
+ goto out_err;
+
+ hp = mdesc_grab();
+ val = mdesc_get_property(hp, vdev->mp, "id", NULL);
+ if (val)
+ dp->id = *val;
+ mdesc_release(hp);
+
+ dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
+ if (!dp->rcv_buf)
+ goto out_free_dp;
+
+ dp->rcv_buf_len = 4096;
+
+ dp->ds_states = kzalloc(sizeof(ds_states_template),
+ GFP_KERNEL);
+ if (!dp->ds_states)
+ goto out_free_rcv_buf;
+
+ memcpy(dp->ds_states, ds_states_template,
+ sizeof(ds_states_template));
+ dp->num_ds_states = ARRAY_SIZE(ds_states_template);
+
+ for (i = 0; i < dp->num_ds_states; i++)
+ dp->ds_states[i].handle = ((u64)i << 32);
+
+ ds_cfg.tx_irq = vdev->tx_irq;
+ ds_cfg.rx_irq = vdev->rx_irq;
+
+ lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out_free_ds_states;
+ }
+ dp->lp = lp;
+
+ err = ldc_bind(lp, "DS");
+ if (err)
+ goto out_free_ldc;
+
+ spin_lock_irq(&ds_lock);
+ dp->next = ds_info_list;
+ ds_info_list = dp;
+ spin_unlock_irq(&ds_lock);
+
+ return err;
+
+out_free_ldc:
+ ldc_free(dp->lp);
+
+out_free_ds_states:
+ kfree(dp->ds_states);
+
+out_free_rcv_buf:
+ kfree(dp->rcv_buf);
+
+out_free_dp:
+ kfree(dp);
+
+out_err:
+ return err;
+}
+
+static int ds_remove(struct vio_dev *vdev)
+{
+ return 0;
+}
+
+static struct vio_device_id ds_match[] = {
+ {
+ .type = "domain-services-port",
+ },
+ {},
+};
+
+static struct vio_driver ds_driver = {
+ .id_table = ds_match,
+ .probe = ds_probe,
+ .remove = ds_remove,
+ .driver = {
+ .name = "ds",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init ds_init(void)
+{
+ kthread_run(ds_thread, NULL, "kldomd");
+
+ return vio_register_driver(&ds_driver);
+}
+
+subsys_initcall(ds_init);
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index ad55a9bb50dd..6d2956179cde 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -362,6 +362,7 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
struct linux_ebus_child *child;
+ struct dev_archdata *sd;
struct of_device *op;
int i, len;
@@ -387,6 +388,10 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de
dev->irqs[i] = op->irqs[i];
}
+ sd = &dev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &dev->ofdev;
+
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 77259526cb15..35feacb6b8ec 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -458,7 +458,6 @@ tlb_fixup_done:
or %g6, %lo(init_thread_union), %g6
ldx [%g6 + TI_TASK], %g4
mov %sp, %l6
- mov %o4, %l7
wr %g0, ASI_P, %asi
mov 1, %g1
diff --git a/arch/sparc64/kernel/hvtramp.S b/arch/sparc64/kernel/hvtramp.S
new file mode 100644
index 000000000000..a55c252e18cc
--- /dev/null
+++ b/arch/sparc64/kernel/hvtramp.S
@@ -0,0 +1,140 @@
+/* hvtramp.S: Hypervisor start-cpu trampoline code.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <asm/thread_info.h>
+#include <asm/hypervisor.h>
+#include <asm/scratchpad.h>
+#include <asm/spitfire.h>
+#include <asm/hvtramp.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/head.h>
+#include <asm/asi.h>
+
+ .text
+ .align 8
+ .globl hv_cpu_startup, hv_cpu_startup_end
+
+ /* This code executes directly out of the hypervisor
+ * with physical addressing (va==pa). %o0 contains
+ * our client argument which for Linux points to
+ * a descriptor data structure which defines the
+ * MMU entries we need to load up.
+ *
+ * After we set things up we enable the MMU and call
+ * into the kernel.
+ *
+ * First setup basic privileged cpu state.
+ */
+hv_cpu_startup:
+ SET_GL(0)
+ wrpr %g0, 15, %pil
+ wrpr %g0, 0, %canrestore
+ wrpr %g0, 0, %otherwin
+ wrpr %g0, 6, %cansave
+ wrpr %g0, 6, %cleanwin
+ wrpr %g0, 0, %cwp
+ wrpr %g0, 0, %wstate
+ wrpr %g0, 0, %tl
+
+ sethi %hi(sparc64_ttable_tl0), %g1
+ wrpr %g1, %tba
+
+ mov %o0, %l0
+
+ lduw [%l0 + HVTRAMP_DESCR_CPU], %g1
+ mov SCRATCHPAD_CPUID, %g2
+ stxa %g1, [%g2] ASI_SCRATCHPAD
+
+ ldx [%l0 + HVTRAMP_DESCR_FAULT_INFO_VA], %g2
+ stxa %g2, [%g0] ASI_SCRATCHPAD
+
+ mov 0, %l1
+ lduw [%l0 + HVTRAMP_DESCR_NUM_MAPPINGS], %l2
+ add %l0, HVTRAMP_DESCR_MAPS, %l3
+
+1: ldx [%l3 + HVTRAMP_MAPPING_VADDR], %o0
+ clr %o1
+ ldx [%l3 + HVTRAMP_MAPPING_TTE], %o2
+ mov HV_MMU_IMMU | HV_MMU_DMMU, %o3
+ mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
+ ta HV_FAST_TRAP
+
+ brnz,pn %o0, 80f
+ nop
+
+ add %l1, 1, %l1
+ cmp %l1, %l2
+ blt,a,pt %xcc, 1b
+ add %l3, HVTRAMP_MAPPING_SIZE, %l3
+
+ ldx [%l0 + HVTRAMP_DESCR_FAULT_INFO_PA], %o0
+ mov HV_FAST_MMU_FAULT_AREA_CONF, %o5
+ ta HV_FAST_TRAP
+
+ brnz,pn %o0, 80f
+ nop
+
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+
+ ldx [%l0 + HVTRAMP_DESCR_THREAD_REG], %l6
+
+ mov 1, %o0
+ set 1f, %o1
+ mov HV_FAST_MMU_ENABLE, %o5
+ ta HV_FAST_TRAP
+
+ ba,pt %xcc, 80f
+ nop
+
+1:
+ wr %g0, 0, %fprs
+ wr %g0, ASI_P, %asi
+
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_MMU
+ membar #Sync
+
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_MMU
+ membar #Sync
+
+ mov %l6, %g6
+ ldx [%g6 + TI_TASK], %g4
+
+ mov 1, %g5
+ sllx %g5, THREAD_SHIFT, %g5
+ sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
+ mov 0, %fp
+
+ call init_irqwork_curcpu
+ nop
+ call hard_smp_processor_id
+ nop
+
+ mov %o0, %o1
+ mov 0, %o0
+ mov 0, %o2
+ call sun4v_init_mondo_queues
+ mov 1, %o3
+
+ call init_cur_cpu_trap
+ mov %g6, %o0
+
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+
+ call smp_callin
+ nop
+ call cpu_idle
+ mov 0, %o0
+ call cpu_panic
+ nop
+
+80: ba,pt %xcc, 80b
+ nop
+
+ .align 8
+hv_cpu_startup_end:
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 6b6165d36fd8..db31bf6b42db 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -87,7 +87,11 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
*/
#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)
-static unsigned int virt_to_real_irq_table[NR_IRQS];
+static struct {
+ unsigned int irq;
+ unsigned int dev_handle;
+ unsigned int dev_ino;
+} virt_to_real_irq_table[NR_IRQS];
static unsigned char virt_irq_alloc(unsigned int real_irq)
{
@@ -96,7 +100,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
BUILD_BUG_ON(NR_IRQS >= 256);
for (ent = 1; ent < NR_IRQS; ent++) {
- if (!virt_to_real_irq_table[ent])
+ if (!virt_to_real_irq_table[ent].irq)
break;
}
if (ent >= NR_IRQS) {
@@ -104,7 +108,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
return 0;
}
- virt_to_real_irq_table[ent] = real_irq;
+ virt_to_real_irq_table[ent].irq = real_irq;
return ent;
}
@@ -117,8 +121,8 @@ static void virt_irq_free(unsigned int virt_irq)
if (virt_irq >= NR_IRQS)
return;
- real_irq = virt_to_real_irq_table[virt_irq];
- virt_to_real_irq_table[virt_irq] = 0;
+ real_irq = virt_to_real_irq_table[virt_irq].irq;
+ virt_to_real_irq_table[virt_irq].irq = 0;
__bucket(real_irq)->virt_irq = 0;
}
@@ -126,7 +130,7 @@ static void virt_irq_free(unsigned int virt_irq)
static unsigned int virt_to_real_irq(unsigned char virt_irq)
{
- return virt_to_real_irq_table[virt_irq];
+ return virt_to_real_irq_table[virt_irq].irq;
}
/*
@@ -293,6 +297,11 @@ static void sun4u_irq_enable(unsigned int virt_irq)
}
}
+static void sun4u_set_affinity(unsigned int virt_irq, cpumask_t mask)
+{
+ sun4u_irq_enable(virt_irq);
+}
+
static void sun4u_irq_disable(unsigned int virt_irq)
{
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
@@ -309,6 +318,10 @@ static void sun4u_irq_disable(unsigned int virt_irq)
static void sun4u_irq_end(unsigned int virt_irq)
{
struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+ struct irq_desc *desc = irq_desc + virt_irq;
+
+ if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ return;
if (likely(data))
upa_writeq(ICLR_IDLE, data->iclr);
@@ -327,19 +340,37 @@ static void sun4v_irq_enable(unsigned int virt_irq)
err = sun4v_intr_settarget(ino, cpuid);
if (err != HV_EOK)
- printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
- ino, cpuid, err);
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_intr_setstate(%x): "
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
"err(%d)\n", ino, err);
err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
if (err != HV_EOK)
- printk("sun4v_intr_setenabled(%x): err(%d)\n",
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
ino, err);
}
}
+static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask)
+{
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+ unsigned int ino = bucket - &ivector_table[0];
+
+ if (likely(bucket)) {
+ unsigned long cpuid;
+ int err;
+
+ cpuid = irq_choose_cpu(virt_irq);
+
+ err = sun4v_intr_settarget(ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
+ }
+}
+
static void sun4v_irq_disable(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
@@ -350,7 +381,7 @@ static void sun4v_irq_disable(unsigned int virt_irq)
err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
if (err != HV_EOK)
- printk("sun4v_intr_setenabled(%x): "
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): "
"err(%d)\n", ino, err);
}
}
@@ -373,13 +404,17 @@ static void sun4v_irq_end(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
unsigned int ino = bucket - &ivector_table[0];
+ struct irq_desc *desc = irq_desc + virt_irq;
+
+ if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ return;
if (likely(bucket)) {
int err;
err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_intr_setstate(%x): "
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
"err(%d)\n", ino, err);
}
}
@@ -387,7 +422,6 @@ static void sun4v_irq_end(unsigned int virt_irq)
static void sun4v_virq_enable(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long cpuid, dev_handle, dev_ino;
@@ -395,45 +429,65 @@ static void sun4v_virq_enable(unsigned int virt_irq)
cpuid = irq_choose_cpu(virt_irq);
- dev_handle = ino & IMAP_IGN;
- dev_ino = ino & IMAP_INO;
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
if (err != HV_EOK)
- printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
"err(%d)\n",
dev_handle, dev_ino, cpuid, err);
err = sun4v_vintr_set_state(dev_handle, dev_ino,
HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_STATE_IDLE): err(%d)\n",
dev_handle, dev_ino, err);
err = sun4v_vintr_set_valid(dev_handle, dev_ino,
HV_INTR_ENABLED);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_ENABLED): err(%d)\n",
dev_handle, dev_ino, err);
}
}
+static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
+{
+ struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+
+ if (likely(bucket)) {
+ unsigned long cpuid, dev_handle, dev_ino;
+ int err;
+
+ cpuid = irq_choose_cpu(virt_irq);
+
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
+
+ err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
+ "err(%d)\n",
+ dev_handle, dev_ino, cpuid, err);
+ }
+}
+
static void sun4v_virq_disable(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long dev_handle, dev_ino;
int err;
- dev_handle = ino & IMAP_IGN;
- dev_ino = ino & IMAP_INO;
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
err = sun4v_vintr_set_valid(dev_handle, dev_ino,
HV_INTR_DISABLED);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_DISABLED): err(%d)\n",
dev_handle, dev_ino, err);
}
@@ -442,19 +496,22 @@ static void sun4v_virq_disable(unsigned int virt_irq)
static void sun4v_virq_end(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
+ struct irq_desc *desc = irq_desc + virt_irq;
+
+ if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ return;
if (likely(bucket)) {
unsigned long dev_handle, dev_ino;
int err;
- dev_handle = ino & IMAP_IGN;
- dev_ino = ino & IMAP_INO;
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
err = sun4v_vintr_set_state(dev_handle, dev_ino,
HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_STATE_IDLE): err(%d)\n",
dev_handle, dev_ino, err);
}
@@ -477,6 +534,7 @@ static struct irq_chip sun4u_irq = {
.enable = sun4u_irq_enable,
.disable = sun4u_irq_disable,
.end = sun4u_irq_end,
+ .set_affinity = sun4u_set_affinity,
};
static struct irq_chip sun4u_irq_ack = {
@@ -485,6 +543,7 @@ static struct irq_chip sun4u_irq_ack = {
.disable = sun4u_irq_disable,
.ack = run_pre_handler,
.end = sun4u_irq_end,
+ .set_affinity = sun4u_set_affinity,
};
static struct irq_chip sun4v_irq = {
@@ -492,6 +551,7 @@ static struct irq_chip sun4v_irq = {
.enable = sun4v_irq_enable,
.disable = sun4v_irq_disable,
.end = sun4v_irq_end,
+ .set_affinity = sun4v_set_affinity,
};
static struct irq_chip sun4v_irq_ack = {
@@ -500,6 +560,7 @@ static struct irq_chip sun4v_irq_ack = {
.disable = sun4v_irq_disable,
.ack = run_pre_handler,
.end = sun4v_irq_end,
+ .set_affinity = sun4v_set_affinity,
};
#ifdef CONFIG_PCI_MSI
@@ -511,6 +572,7 @@ static struct irq_chip sun4v_msi = {
.disable = sun4v_msi_disable,
.ack = run_pre_handler,
.end = sun4v_irq_end,
+ .set_affinity = sun4v_set_affinity,
};
#endif
@@ -519,6 +581,7 @@ static struct irq_chip sun4v_virq = {
.enable = sun4v_virq_enable,
.disable = sun4v_virq_disable,
.end = sun4v_virq_end,
+ .set_affinity = sun4v_virt_set_affinity,
};
static struct irq_chip sun4v_virq_ack = {
@@ -527,6 +590,7 @@ static struct irq_chip sun4v_virq_ack = {
.disable = sun4v_virq_disable,
.ack = run_pre_handler,
.end = sun4v_virq_end,
+ .set_affinity = sun4v_virt_set_affinity,
};
void irq_install_pre_handler(int virt_irq,
@@ -636,11 +700,12 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
{
unsigned long sysino, hv_err;
+ unsigned int virq;
- BUG_ON(devhandle & ~IMAP_IGN);
- BUG_ON(devino & ~IMAP_INO);
+ BUG_ON(devhandle & devino);
sysino = devhandle | devino;
+ BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
if (hv_err) {
@@ -649,7 +714,12 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
prom_halt();
}
- return sun4v_build_common(sysino, &sun4v_virq);
+ virq = sun4v_build_common(sysino, &sun4v_virq);
+
+ virt_to_real_irq_table[virq].dev_handle = devhandle;
+ virt_to_real_irq_table[virq].dev_ino = devino;
+
+ return virq;
}
#ifdef CONFIG_PCI_MSI
@@ -739,6 +809,26 @@ void handler_irq(int irq, struct pt_regs *regs)
set_irq_regs(old_regs);
}
+#ifdef CONFIG_HOTPLUG_CPU
+void fixup_irqs(void)
+{
+ unsigned int irq;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_desc[irq].lock, flags);
+ if (irq_desc[irq].action &&
+ !(irq_desc[irq].status & IRQ_PER_CPU)) {
+ if (irq_desc[irq].chip->set_affinity)
+ irq_desc[irq].chip->set_affinity(irq,
+ irq_desc[irq].affinity);
+ }
+ spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+ }
+}
+#endif
+
struct sun5_timer {
u64 count0;
u64 limit0;
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 6a6882e57ff2..1a1043fcf97d 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -79,6 +79,7 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
while (dp) {
struct sparc_isa_device *isa_dev;
+ struct dev_archdata *sd;
isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
@@ -86,6 +87,10 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
return;
}
+ sd = &isa_dev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &isa_dev->ofdev;
+
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
isa_dev->ofdev.dev.bus = &isa_bus_type;
diff --git a/arch/sparc64/kernel/ldc.c b/arch/sparc64/kernel/ldc.c
new file mode 100644
index 000000000000..85a2be0b0962
--- /dev/null
+++ b/arch/sparc64/kernel/ldc.c
@@ -0,0 +1,2373 @@
+/* ldc.c: Logical Domain Channel link-layer protocol driver.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/init.h>
+
+#include <asm/hypervisor.h>
+#include <asm/iommu.h>
+#include <asm/page.h>
+#include <asm/ldc.h>
+#include <asm/mdesc.h>
+
+#define DRV_MODULE_NAME "ldc"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.0"
+#define DRV_MODULE_RELDATE "June 25, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+#define LDC_PACKET_SIZE 64
+
+/* Packet header layout for unreliable and reliable mode frames.
+ * When in RAW mode, packets are simply straight 64-byte payloads
+ * with no headers.
+ */
+struct ldc_packet {
+ u8 type;
+#define LDC_CTRL 0x01
+#define LDC_DATA 0x02
+#define LDC_ERR 0x10
+
+ u8 stype;
+#define LDC_INFO 0x01
+#define LDC_ACK 0x02
+#define LDC_NACK 0x04
+
+ u8 ctrl;
+#define LDC_VERS 0x01 /* Link Version */
+#define LDC_RTS 0x02 /* Request To Send */
+#define LDC_RTR 0x03 /* Ready To Receive */
+#define LDC_RDX 0x04 /* Ready for Data eXchange */
+#define LDC_CTRL_MSK 0x0f
+
+ u8 env;
+#define LDC_LEN 0x3f
+#define LDC_FRAG_MASK 0xc0
+#define LDC_START 0x40
+#define LDC_STOP 0x80
+
+ u32 seqid;
+
+ union {
+ u8 u_data[LDC_PACKET_SIZE - 8];
+ struct {
+ u32 pad;
+ u32 ackid;
+ u8 r_data[LDC_PACKET_SIZE - 8 - 8];
+ } r;
+ } u;
+};
+
+struct ldc_version {
+ u16 major;
+ u16 minor;
+};
+
+/* Ordered from largest major to lowest. */
+static struct ldc_version ver_arr[] = {
+ { .major = 1, .minor = 0 },
+};
+
+#define LDC_DEFAULT_MTU (4 * LDC_PACKET_SIZE)
+#define LDC_DEFAULT_NUM_ENTRIES (PAGE_SIZE / LDC_PACKET_SIZE)
+
+struct ldc_channel;
+
+struct ldc_mode_ops {
+ int (*write)(struct ldc_channel *, const void *, unsigned int);
+ int (*read)(struct ldc_channel *, void *, unsigned int);
+};
+
+static const struct ldc_mode_ops raw_ops;
+static const struct ldc_mode_ops nonraw_ops;
+static const struct ldc_mode_ops stream_ops;
+
+int ldom_domaining_enabled;
+
+struct ldc_iommu {
+ /* Protects arena alloc/free. */
+ spinlock_t lock;
+ struct iommu_arena arena;
+ struct ldc_mtable_entry *page_table;
+};
+
+struct ldc_channel {
+ /* Protects all operations that depend upon channel state. */
+ spinlock_t lock;
+
+ unsigned long id;
+
+ u8 *mssbuf;
+ u32 mssbuf_len;
+ u32 mssbuf_off;
+
+ struct ldc_packet *tx_base;
+ unsigned long tx_head;
+ unsigned long tx_tail;
+ unsigned long tx_num_entries;
+ unsigned long tx_ra;
+
+ unsigned long tx_acked;
+
+ struct ldc_packet *rx_base;
+ unsigned long rx_head;
+ unsigned long rx_tail;
+ unsigned long rx_num_entries;
+ unsigned long rx_ra;
+
+ u32 rcv_nxt;
+ u32 snd_nxt;
+
+ unsigned long chan_state;
+
+ struct ldc_channel_config cfg;
+ void *event_arg;
+
+ const struct ldc_mode_ops *mops;
+
+ struct ldc_iommu iommu;
+
+ struct ldc_version ver;
+
+ u8 hs_state;
+#define LDC_HS_CLOSED 0x00
+#define LDC_HS_OPEN 0x01
+#define LDC_HS_GOTVERS 0x02
+#define LDC_HS_SENTRTR 0x03
+#define LDC_HS_GOTRTR 0x04
+#define LDC_HS_COMPLETE 0x10
+
+ u8 flags;
+#define LDC_FLAG_ALLOCED_QUEUES 0x01
+#define LDC_FLAG_REGISTERED_QUEUES 0x02
+#define LDC_FLAG_REGISTERED_IRQS 0x04
+#define LDC_FLAG_RESET 0x10
+
+ u8 mss;
+ u8 state;
+
+#define LDC_IRQ_NAME_MAX 32
+ char rx_irq_name[LDC_IRQ_NAME_MAX];
+ char tx_irq_name[LDC_IRQ_NAME_MAX];
+
+ struct hlist_head mh_list;
+
+ struct hlist_node list;
+};
+
+#define ldcdbg(TYPE, f, a...) \
+do { if (lp->cfg.debug & LDC_DEBUG_##TYPE) \
+ printk(KERN_INFO PFX "ID[%lu] " f, lp->id, ## a); \
+} while (0)
+
+static const char *state_to_str(u8 state)
+{
+ switch (state) {
+ case LDC_STATE_INVALID:
+ return "INVALID";
+ case LDC_STATE_INIT:
+ return "INIT";
+ case LDC_STATE_BOUND:
+ return "BOUND";
+ case LDC_STATE_READY:
+ return "READY";
+ case LDC_STATE_CONNECTED:
+ return "CONNECTED";
+ default:
+ return "<UNKNOWN>";
+ }
+}
+
+static void ldc_set_state(struct ldc_channel *lp, u8 state)
+{
+ ldcdbg(STATE, "STATE (%s) --> (%s)\n",
+ state_to_str(lp->state),
+ state_to_str(state));
+
+ lp->state = state;
+}
+
+static unsigned long __advance(unsigned long off, unsigned long num_entries)
+{
+ off += LDC_PACKET_SIZE;
+ if (off == (num_entries * LDC_PACKET_SIZE))
+ off = 0;
+
+ return off;
+}
+
+static unsigned long rx_advance(struct ldc_channel *lp, unsigned long off)
+{
+ return __advance(off, lp->rx_num_entries);
+}
+
+static unsigned long tx_advance(struct ldc_channel *lp, unsigned long off)
+{
+ return __advance(off, lp->tx_num_entries);
+}
+
+static struct ldc_packet *handshake_get_tx_packet(struct ldc_channel *lp,
+ unsigned long *new_tail)
+{
+ struct ldc_packet *p;
+ unsigned long t;
+
+ t = tx_advance(lp, lp->tx_tail);
+ if (t == lp->tx_head)
+ return NULL;
+
+ *new_tail = t;
+
+ p = lp->tx_base;
+ return p + (lp->tx_tail / LDC_PACKET_SIZE);
+}
+
+/* When we are in reliable or stream mode, have to track the next packet
+ * we haven't gotten an ACK for in the TX queue using tx_acked. We have
+ * to be careful not to stomp over the queue past that point. During
+ * the handshake, we don't have TX data packets pending in the queue
+ * and that's why handshake_get_tx_packet() need not be mindful of
+ * lp->tx_acked.
+ */
+static unsigned long head_for_data(struct ldc_channel *lp)
+{
+ if (lp->cfg.mode == LDC_MODE_STREAM)
+ return lp->tx_acked;
+ return lp->tx_head;
+}
+
+static int tx_has_space_for(struct ldc_channel *lp, unsigned int size)
+{
+ unsigned long limit, tail, new_tail, diff;
+ unsigned int mss;
+
+ limit = head_for_data(lp);
+ tail = lp->tx_tail;
+ new_tail = tx_advance(lp, tail);
+ if (new_tail == limit)
+ return 0;
+
+ if (limit > new_tail)
+ diff = limit - new_tail;
+ else
+ diff = (limit +
+ ((lp->tx_num_entries * LDC_PACKET_SIZE) - new_tail));
+ diff /= LDC_PACKET_SIZE;
+ mss = lp->mss;
+
+ if (diff * mss < size)
+ return 0;
+
+ return 1;
+}
+
+static struct ldc_packet *data_get_tx_packet(struct ldc_channel *lp,
+ unsigned long *new_tail)
+{
+ struct ldc_packet *p;
+ unsigned long h, t;
+
+ h = head_for_data(lp);
+ t = tx_advance(lp, lp->tx_tail);
+ if (t == h)
+ return NULL;
+
+ *new_tail = t;
+
+ p = lp->tx_base;
+ return p + (lp->tx_tail / LDC_PACKET_SIZE);
+}
+
+static int set_tx_tail(struct ldc_channel *lp, unsigned long tail)
+{
+ unsigned long orig_tail = lp->tx_tail;
+ int limit = 1000;
+
+ lp->tx_tail = tail;
+ while (limit-- > 0) {
+ unsigned long err;
+
+ err = sun4v_ldc_tx_set_qtail(lp->id, tail);
+ if (!err)
+ return 0;
+
+ if (err != HV_EWOULDBLOCK) {
+ lp->tx_tail = orig_tail;
+ return -EINVAL;
+ }
+ udelay(1);
+ }
+
+ lp->tx_tail = orig_tail;
+ return -EBUSY;
+}
+
+/* This just updates the head value in the hypervisor using
+ * a polling loop with a timeout. The caller takes care of
+ * upating software state representing the head change, if any.
+ */
+static int __set_rx_head(struct ldc_channel *lp, unsigned long head)
+{
+ int limit = 1000;
+
+ while (limit-- > 0) {
+ unsigned long err;
+
+ err = sun4v_ldc_rx_set_qhead(lp->id, head);
+ if (!err)
+ return 0;
+
+ if (err != HV_EWOULDBLOCK)
+ return -EINVAL;
+
+ udelay(1);
+ }
+
+ return -EBUSY;
+}
+
+static int send_tx_packet(struct ldc_channel *lp,
+ struct ldc_packet *p,
+ unsigned long new_tail)
+{
+ BUG_ON(p != (lp->tx_base + (lp->tx_tail / LDC_PACKET_SIZE)));
+
+ return set_tx_tail(lp, new_tail);
+}
+
+static struct ldc_packet *handshake_compose_ctrl(struct ldc_channel *lp,
+ u8 stype, u8 ctrl,
+ void *data, int dlen,
+ unsigned long *new_tail)
+{
+ struct ldc_packet *p = handshake_get_tx_packet(lp, new_tail);
+
+ if (p) {
+ memset(p, 0, sizeof(*p));
+ p->type = LDC_CTRL;
+ p->stype = stype;
+ p->ctrl = ctrl;
+ if (data)
+ memcpy(p->u.u_data, data, dlen);
+ }
+ return p;
+}
+
+static int start_handshake(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ struct ldc_version *ver;
+ unsigned long new_tail;
+
+ ver = &ver_arr[0];
+
+ ldcdbg(HS, "SEND VER INFO maj[%u] min[%u]\n",
+ ver->major, ver->minor);
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_VERS,
+ ver, sizeof(*ver), &new_tail);
+ if (p) {
+ int err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ lp->flags &= ~LDC_FLAG_RESET;
+ return err;
+ }
+ return -EBUSY;
+}
+
+static int send_version_nack(struct ldc_channel *lp,
+ u16 major, u16 minor)
+{
+ struct ldc_packet *p;
+ struct ldc_version ver;
+ unsigned long new_tail;
+
+ ver.major = major;
+ ver.minor = minor;
+
+ p = handshake_compose_ctrl(lp, LDC_NACK, LDC_VERS,
+ &ver, sizeof(ver), &new_tail);
+ if (p) {
+ ldcdbg(HS, "SEND VER NACK maj[%u] min[%u]\n",
+ ver.major, ver.minor);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_version_ack(struct ldc_channel *lp,
+ struct ldc_version *vp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_ACK, LDC_VERS,
+ vp, sizeof(*vp), &new_tail);
+ if (p) {
+ ldcdbg(HS, "SEND VER ACK maj[%u] min[%u]\n",
+ vp->major, vp->minor);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_rts(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_RTS, NULL, 0,
+ &new_tail);
+ if (p) {
+ p->env = lp->cfg.mode;
+ p->seqid = 0;
+ lp->rcv_nxt = 0;
+
+ ldcdbg(HS, "SEND RTS env[0x%x] seqid[0x%x]\n",
+ p->env, p->seqid);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_rtr(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_RTR, NULL, 0,
+ &new_tail);
+ if (p) {
+ p->env = lp->cfg.mode;
+ p->seqid = 0;
+
+ ldcdbg(HS, "SEND RTR env[0x%x] seqid[0x%x]\n",
+ p->env, p->seqid);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_rdx(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_RDX, NULL, 0,
+ &new_tail);
+ if (p) {
+ p->env = 0;
+ p->seqid = ++lp->snd_nxt;
+ p->u.r.ackid = lp->rcv_nxt;
+
+ ldcdbg(HS, "SEND RDX env[0x%x] seqid[0x%x] ackid[0x%x]\n",
+ p->env, p->seqid, p->u.r.ackid);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_data_nack(struct ldc_channel *lp, struct ldc_packet *data_pkt)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+ int err;
+
+ p = data_get_tx_packet(lp, &new_tail);
+ if (!p)
+ return -EBUSY;
+ memset(p, 0, sizeof(*p));
+ p->type = data_pkt->type;
+ p->stype = LDC_NACK;
+ p->ctrl = data_pkt->ctrl & LDC_CTRL_MSK;
+ p->seqid = lp->snd_nxt + 1;
+ p->u.r.ackid = lp->rcv_nxt;
+
+ ldcdbg(HS, "SEND DATA NACK type[0x%x] ctl[0x%x] seq[0x%x] ack[0x%x]\n",
+ p->type, p->ctrl, p->seqid, p->u.r.ackid);
+
+ err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ lp->snd_nxt++;
+
+ return err;
+}
+
+static int ldc_abort(struct ldc_channel *lp)
+{
+ unsigned long hv_err;
+
+ ldcdbg(STATE, "ABORT\n");
+
+ /* We report but do not act upon the hypervisor errors because
+ * there really isn't much we can do if they fail at this point.
+ */
+ hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_tx_qconf(%lx,%lx,%lx) failed, err=%lu\n",
+ lp->id, lp->tx_ra, lp->tx_num_entries, hv_err);
+
+ hv_err = sun4v_ldc_tx_get_state(lp->id,
+ &lp->tx_head,
+ &lp->tx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_tx_get_state(%lx,...) failed, err=%lu\n",
+ lp->id, hv_err);
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, lp->rx_ra, lp->rx_num_entries);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_rx_qconf(%lx,%lx,%lx) failed, err=%lu\n",
+ lp->id, lp->rx_ra, lp->rx_num_entries, hv_err);
+
+ /* Refetch the RX queue state as well, because we could be invoked
+ * here in the queue processing context.
+ */
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_rx_get_state(%lx,...) failed, err=%lu\n",
+ lp->id, hv_err);
+
+ return -ECONNRESET;
+}
+
+static struct ldc_version *find_by_major(u16 major)
+{
+ struct ldc_version *ret = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ver_arr); i++) {
+ struct ldc_version *v = &ver_arr[i];
+ if (v->major <= major) {
+ ret = v;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int process_ver_info(struct ldc_channel *lp, struct ldc_version *vp)
+{
+ struct ldc_version *vap;
+ int err;
+
+ ldcdbg(HS, "GOT VERSION INFO major[%x] minor[%x]\n",
+ vp->major, vp->minor);
+
+ if (lp->hs_state == LDC_HS_GOTVERS) {
+ lp->hs_state = LDC_HS_OPEN;
+ memset(&lp->ver, 0, sizeof(lp->ver));
+ }
+
+ vap = find_by_major(vp->major);
+ if (!vap) {
+ err = send_version_nack(lp, 0, 0);
+ } else if (vap->major != vp->major) {
+ err = send_version_nack(lp, vap->major, vap->minor);
+ } else {
+ struct ldc_version ver = *vp;
+ if (ver.minor > vap->minor)
+ ver.minor = vap->minor;
+ err = send_version_ack(lp, &ver);
+ if (!err) {
+ lp->ver = ver;
+ lp->hs_state = LDC_HS_GOTVERS;
+ }
+ }
+ if (err)
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int process_ver_ack(struct ldc_channel *lp, struct ldc_version *vp)
+{
+ ldcdbg(HS, "GOT VERSION ACK major[%x] minor[%x]\n",
+ vp->major, vp->minor);
+
+ if (lp->hs_state == LDC_HS_GOTVERS) {
+ if (lp->ver.major != vp->major ||
+ lp->ver.minor != vp->minor)
+ return ldc_abort(lp);
+ } else {
+ lp->ver = *vp;
+ lp->hs_state = LDC_HS_GOTVERS;
+ }
+ if (send_rts(lp))
+ return ldc_abort(lp);
+ return 0;
+}
+
+static int process_ver_nack(struct ldc_channel *lp, struct ldc_version *vp)
+{
+ struct ldc_version *vap;
+
+ if ((vp->major == 0 && vp->minor == 0) ||
+ !(vap = find_by_major(vp->major))) {
+ return ldc_abort(lp);
+ } else {
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_VERS,
+ vap, sizeof(*vap),
+ &new_tail);
+ if (p)
+ return send_tx_packet(lp, p, new_tail);
+ else
+ return ldc_abort(lp);
+ }
+}
+
+static int process_version(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ struct ldc_version *vp;
+
+ vp = (struct ldc_version *) p->u.u_data;
+
+ switch (p->stype) {
+ case LDC_INFO:
+ return process_ver_info(lp, vp);
+
+ case LDC_ACK:
+ return process_ver_ack(lp, vp);
+
+ case LDC_NACK:
+ return process_ver_nack(lp, vp);
+
+ default:
+ return ldc_abort(lp);
+ }
+}
+
+static int process_rts(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ ldcdbg(HS, "GOT RTS stype[%x] seqid[%x] env[%x]\n",
+ p->stype, p->seqid, p->env);
+
+ if (p->stype != LDC_INFO ||
+ lp->hs_state != LDC_HS_GOTVERS ||
+ p->env != lp->cfg.mode)
+ return ldc_abort(lp);
+
+ lp->snd_nxt = p->seqid;
+ lp->rcv_nxt = p->seqid;
+ lp->hs_state = LDC_HS_SENTRTR;
+ if (send_rtr(lp))
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int process_rtr(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ ldcdbg(HS, "GOT RTR stype[%x] seqid[%x] env[%x]\n",
+ p->stype, p->seqid, p->env);
+
+ if (p->stype != LDC_INFO ||
+ p->env != lp->cfg.mode)
+ return ldc_abort(lp);
+
+ lp->snd_nxt = p->seqid;
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+ send_rdx(lp);
+
+ return LDC_EVENT_UP;
+}
+
+static int rx_seq_ok(struct ldc_channel *lp, u32 seqid)
+{
+ return lp->rcv_nxt + 1 == seqid;
+}
+
+static int process_rdx(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ ldcdbg(HS, "GOT RDX stype[%x] seqid[%x] env[%x] ackid[%x]\n",
+ p->stype, p->seqid, p->env, p->u.r.ackid);
+
+ if (p->stype != LDC_INFO ||
+ !(rx_seq_ok(lp, p->seqid)))
+ return ldc_abort(lp);
+
+ lp->rcv_nxt = p->seqid;
+
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+
+ return LDC_EVENT_UP;
+}
+
+static int process_control_frame(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ switch (p->ctrl) {
+ case LDC_VERS:
+ return process_version(lp, p);
+
+ case LDC_RTS:
+ return process_rts(lp, p);
+
+ case LDC_RTR:
+ return process_rtr(lp, p);
+
+ case LDC_RDX:
+ return process_rdx(lp, p);
+
+ default:
+ return ldc_abort(lp);
+ }
+}
+
+static int process_error_frame(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ return ldc_abort(lp);
+}
+
+static int process_data_ack(struct ldc_channel *lp,
+ struct ldc_packet *ack)
+{
+ unsigned long head = lp->tx_acked;
+ u32 ackid = ack->u.r.ackid;
+
+ while (1) {
+ struct ldc_packet *p = lp->tx_base + (head / LDC_PACKET_SIZE);
+
+ head = tx_advance(lp, head);
+
+ if (p->seqid == ackid) {
+ lp->tx_acked = head;
+ return 0;
+ }
+ if (head == lp->tx_tail)
+ return ldc_abort(lp);
+ }
+
+ return 0;
+}
+
+static void send_events(struct ldc_channel *lp, unsigned int event_mask)
+{
+ if (event_mask & LDC_EVENT_RESET)
+ lp->cfg.event(lp->event_arg, LDC_EVENT_RESET);
+ if (event_mask & LDC_EVENT_UP)
+ lp->cfg.event(lp->event_arg, LDC_EVENT_UP);
+ if (event_mask & LDC_EVENT_DATA_READY)
+ lp->cfg.event(lp->event_arg, LDC_EVENT_DATA_READY);
+}
+
+static irqreturn_t ldc_rx(int irq, void *dev_id)
+{
+ struct ldc_channel *lp = dev_id;
+ unsigned long orig_state, hv_err, flags;
+ unsigned int event_mask;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ orig_state = lp->chan_state;
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+
+ ldcdbg(RX, "RX state[0x%02lx:0x%02lx] head[0x%04lx] tail[0x%04lx]\n",
+ orig_state, lp->chan_state, lp->rx_head, lp->rx_tail);
+
+ event_mask = 0;
+
+ if (lp->cfg.mode == LDC_MODE_RAW &&
+ lp->chan_state == LDC_CHANNEL_UP) {
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+
+ event_mask |= LDC_EVENT_UP;
+
+ orig_state = lp->chan_state;
+ }
+
+ /* If we are in reset state, flush the RX queue and ignore
+ * everything.
+ */
+ if (lp->flags & LDC_FLAG_RESET) {
+ (void) __set_rx_head(lp, lp->rx_tail);
+ goto out;
+ }
+
+ /* Once we finish the handshake, we let the ldc_read()
+ * paths do all of the control frame and state management.
+ * Just trigger the callback.
+ */
+ if (lp->hs_state == LDC_HS_COMPLETE) {
+handshake_complete:
+ if (lp->chan_state != orig_state) {
+ unsigned int event = LDC_EVENT_RESET;
+
+ if (lp->chan_state == LDC_CHANNEL_UP)
+ event = LDC_EVENT_UP;
+
+ event_mask |= event;
+ }
+ if (lp->rx_head != lp->rx_tail)
+ event_mask |= LDC_EVENT_DATA_READY;
+
+ goto out;
+ }
+
+ if (lp->chan_state != orig_state)
+ goto out;
+
+ while (lp->rx_head != lp->rx_tail) {
+ struct ldc_packet *p;
+ unsigned long new;
+ int err;
+
+ p = lp->rx_base + (lp->rx_head / LDC_PACKET_SIZE);
+
+ switch (p->type) {
+ case LDC_CTRL:
+ err = process_control_frame(lp, p);
+ if (err > 0)
+ event_mask |= err;
+ break;
+
+ case LDC_DATA:
+ event_mask |= LDC_EVENT_DATA_READY;
+ err = 0;
+ break;
+
+ case LDC_ERR:
+ err = process_error_frame(lp, p);
+ break;
+
+ default:
+ err = ldc_abort(lp);
+ break;
+ }
+
+ if (err < 0)
+ break;
+
+ new = lp->rx_head;
+ new += LDC_PACKET_SIZE;
+ if (new == (lp->rx_num_entries * LDC_PACKET_SIZE))
+ new = 0;
+ lp->rx_head = new;
+
+ err = __set_rx_head(lp, new);
+ if (err < 0) {
+ (void) ldc_abort(lp);
+ break;
+ }
+ if (lp->hs_state == LDC_HS_COMPLETE)
+ goto handshake_complete;
+ }
+
+out:
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ send_events(lp, event_mask);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ldc_tx(int irq, void *dev_id)
+{
+ struct ldc_channel *lp = dev_id;
+ unsigned long flags, hv_err, orig_state;
+ unsigned int event_mask = 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ orig_state = lp->chan_state;
+ hv_err = sun4v_ldc_tx_get_state(lp->id,
+ &lp->tx_head,
+ &lp->tx_tail,
+ &lp->chan_state);
+
+ ldcdbg(TX, " TX state[0x%02lx:0x%02lx] head[0x%04lx] tail[0x%04lx]\n",
+ orig_state, lp->chan_state, lp->tx_head, lp->tx_tail);
+
+ if (lp->cfg.mode == LDC_MODE_RAW &&
+ lp->chan_state == LDC_CHANNEL_UP) {
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+
+ event_mask |= LDC_EVENT_UP;
+ }
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ send_events(lp, event_mask);
+
+ return IRQ_HANDLED;
+}
+
+/* XXX ldc_alloc() and ldc_free() needs to run under a mutex so
+ * XXX that addition and removal from the ldc_channel_list has
+ * XXX atomicity, otherwise the __ldc_channel_exists() check is
+ * XXX totally pointless as another thread can slip into ldc_alloc()
+ * XXX and add a channel with the same ID. There also needs to be
+ * XXX a spinlock for ldc_channel_list.
+ */
+static HLIST_HEAD(ldc_channel_list);
+
+static int __ldc_channel_exists(unsigned long id)
+{
+ struct ldc_channel *lp;
+ struct hlist_node *n;
+
+ hlist_for_each_entry(lp, n, &ldc_channel_list, list) {
+ if (lp->id == id)
+ return 1;
+ }
+ return 0;
+}
+
+static int alloc_queue(const char *name, unsigned long num_entries,
+ struct ldc_packet **base, unsigned long *ra)
+{
+ unsigned long size, order;
+ void *q;
+
+ size = num_entries * LDC_PACKET_SIZE;
+ order = get_order(size);
+
+ q = (void *) __get_free_pages(GFP_KERNEL, order);
+ if (!q) {
+ printk(KERN_ERR PFX "Alloc of %s queue failed with "
+ "size=%lu order=%lu\n", name, size, order);
+ return -ENOMEM;
+ }
+
+ memset(q, 0, PAGE_SIZE << order);
+
+ *base = q;
+ *ra = __pa(q);
+
+ return 0;
+}
+
+static void free_queue(unsigned long num_entries, struct ldc_packet *q)
+{
+ unsigned long size, order;
+
+ if (!q)
+ return;
+
+ size = num_entries * LDC_PACKET_SIZE;
+ order = get_order(size);
+
+ free_pages((unsigned long)q, order);
+}
+
+/* XXX Make this configurable... XXX */
+#define LDC_IOTABLE_SIZE (8 * 1024)
+
+static int ldc_iommu_init(struct ldc_channel *lp)
+{
+ unsigned long sz, num_tsb_entries, tsbsize, order;
+ struct ldc_iommu *iommu = &lp->iommu;
+ struct ldc_mtable_entry *table;
+ unsigned long hv_err;
+ int err;
+
+ num_tsb_entries = LDC_IOTABLE_SIZE;
+ tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
+
+ spin_lock_init(&iommu->lock);
+
+ sz = num_tsb_entries / 8;
+ sz = (sz + 7UL) & ~7UL;
+ iommu->arena.map = kzalloc(sz, GFP_KERNEL);
+ if (!iommu->arena.map) {
+ printk(KERN_ERR PFX "Alloc of arena map failed, sz=%lu\n", sz);
+ return -ENOMEM;
+ }
+
+ iommu->arena.limit = num_tsb_entries;
+
+ order = get_order(tsbsize);
+
+ table = (struct ldc_mtable_entry *)
+ __get_free_pages(GFP_KERNEL, order);
+ err = -ENOMEM;
+ if (!table) {
+ printk(KERN_ERR PFX "Alloc of MTE table failed, "
+ "size=%lu order=%lu\n", tsbsize, order);
+ goto out_free_map;
+ }
+
+ memset(table, 0, PAGE_SIZE << order);
+
+ iommu->page_table = table;
+
+ hv_err = sun4v_ldc_set_map_table(lp->id, __pa(table),
+ num_tsb_entries);
+ err = -EINVAL;
+ if (hv_err)
+ goto out_free_table;
+
+ return 0;
+
+out_free_table:
+ free_pages((unsigned long) table, order);
+ iommu->page_table = NULL;
+
+out_free_map:
+ kfree(iommu->arena.map);
+ iommu->arena.map = NULL;
+
+ return err;
+}
+
+static void ldc_iommu_release(struct ldc_channel *lp)
+{
+ struct ldc_iommu *iommu = &lp->iommu;
+ unsigned long num_tsb_entries, tsbsize, order;
+
+ (void) sun4v_ldc_set_map_table(lp->id, 0, 0);
+
+ num_tsb_entries = iommu->arena.limit;
+ tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
+ order = get_order(tsbsize);
+
+ free_pages((unsigned long) iommu->page_table, order);
+ iommu->page_table = NULL;
+
+ kfree(iommu->arena.map);
+ iommu->arena.map = NULL;
+}
+
+struct ldc_channel *ldc_alloc(unsigned long id,
+ const struct ldc_channel_config *cfgp,
+ void *event_arg)
+{
+ struct ldc_channel *lp;
+ const struct ldc_mode_ops *mops;
+ unsigned long dummy1, dummy2, hv_err;
+ u8 mss, *mssbuf;
+ int err;
+
+ err = -ENODEV;
+ if (!ldom_domaining_enabled)
+ goto out_err;
+
+ err = -EINVAL;
+ if (!cfgp)
+ goto out_err;
+
+ switch (cfgp->mode) {
+ case LDC_MODE_RAW:
+ mops = &raw_ops;
+ mss = LDC_PACKET_SIZE;
+ break;
+
+ case LDC_MODE_UNRELIABLE:
+ mops = &nonraw_ops;
+ mss = LDC_PACKET_SIZE - 8;
+ break;
+
+ case LDC_MODE_STREAM:
+ mops = &stream_ops;
+ mss = LDC_PACKET_SIZE - 8 - 8;
+ break;
+
+ default:
+ goto out_err;
+ }
+
+ if (!cfgp->event || !event_arg || !cfgp->rx_irq || !cfgp->tx_irq)
+ goto out_err;
+
+ hv_err = sun4v_ldc_tx_qinfo(id, &dummy1, &dummy2);
+ err = -ENODEV;
+ if (hv_err == HV_ECHANNEL)
+ goto out_err;
+
+ err = -EEXIST;
+ if (__ldc_channel_exists(id))
+ goto out_err;
+
+ mssbuf = NULL;
+
+ lp = kzalloc(sizeof(*lp), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!lp)
+ goto out_err;
+
+ spin_lock_init(&lp->lock);
+
+ lp->id = id;
+
+ err = ldc_iommu_init(lp);
+ if (err)
+ goto out_free_ldc;
+
+ lp->mops = mops;
+ lp->mss = mss;
+
+ lp->cfg = *cfgp;
+ if (!lp->cfg.mtu)
+ lp->cfg.mtu = LDC_DEFAULT_MTU;
+
+ if (lp->cfg.mode == LDC_MODE_STREAM) {
+ mssbuf = kzalloc(lp->cfg.mtu, GFP_KERNEL);
+ if (!mssbuf) {
+ err = -ENOMEM;
+ goto out_free_iommu;
+ }
+ lp->mssbuf = mssbuf;
+ }
+
+ lp->event_arg = event_arg;
+
+ /* XXX allow setting via ldc_channel_config to override defaults
+ * XXX or use some formula based upon mtu
+ */
+ lp->tx_num_entries = LDC_DEFAULT_NUM_ENTRIES;
+ lp->rx_num_entries = LDC_DEFAULT_NUM_ENTRIES;
+
+ err = alloc_queue("TX", lp->tx_num_entries,
+ &lp->tx_base, &lp->tx_ra);
+ if (err)
+ goto out_free_mssbuf;
+
+ err = alloc_queue("RX", lp->rx_num_entries,
+ &lp->rx_base, &lp->rx_ra);
+ if (err)
+ goto out_free_txq;
+
+ lp->flags |= LDC_FLAG_ALLOCED_QUEUES;
+
+ lp->hs_state = LDC_HS_CLOSED;
+ ldc_set_state(lp, LDC_STATE_INIT);
+
+ INIT_HLIST_NODE(&lp->list);
+ hlist_add_head(&lp->list, &ldc_channel_list);
+
+ INIT_HLIST_HEAD(&lp->mh_list);
+
+ return lp;
+
+out_free_txq:
+ free_queue(lp->tx_num_entries, lp->tx_base);
+
+out_free_mssbuf:
+ if (mssbuf)
+ kfree(mssbuf);
+
+out_free_iommu:
+ ldc_iommu_release(lp);
+
+out_free_ldc:
+ kfree(lp);
+
+out_err:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(ldc_alloc);
+
+void ldc_free(struct ldc_channel *lp)
+{
+ if (lp->flags & LDC_FLAG_REGISTERED_IRQS) {
+ free_irq(lp->cfg.rx_irq, lp);
+ free_irq(lp->cfg.tx_irq, lp);
+ }
+
+ if (lp->flags & LDC_FLAG_REGISTERED_QUEUES) {
+ sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ lp->flags &= ~LDC_FLAG_REGISTERED_QUEUES;
+ }
+ if (lp->flags & LDC_FLAG_ALLOCED_QUEUES) {
+ free_queue(lp->tx_num_entries, lp->tx_base);
+ free_queue(lp->rx_num_entries, lp->rx_base);
+ lp->flags &= ~LDC_FLAG_ALLOCED_QUEUES;
+ }
+
+ hlist_del(&lp->list);
+
+ if (lp->mssbuf)
+ kfree(lp->mssbuf);
+
+ ldc_iommu_release(lp);
+
+ kfree(lp);
+}
+EXPORT_SYMBOL(ldc_free);
+
+/* Bind the channel. This registers the LDC queues with
+ * the hypervisor and puts the channel into a pseudo-listening
+ * state. This does not initiate a handshake, ldc_connect() does
+ * that.
+ */
+int ldc_bind(struct ldc_channel *lp, const char *name)
+{
+ unsigned long hv_err, flags;
+ int err = -EINVAL;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if (!name)
+ goto out_err;
+
+ if (lp->state != LDC_STATE_INIT)
+ goto out_err;
+
+ snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
+ snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
+
+ err = request_irq(lp->cfg.rx_irq, ldc_rx,
+ IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ lp->rx_irq_name, lp);
+ if (err)
+ goto out_err;
+
+ err = request_irq(lp->cfg.tx_irq, ldc_tx,
+ IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ lp->tx_irq_name, lp);
+ if (err)
+ goto out_free_rx_irq;
+
+
+ lp->flags |= LDC_FLAG_REGISTERED_IRQS;
+
+ err = -ENODEV;
+ hv_err = sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_free_tx_irq;
+
+ hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries);
+ if (hv_err)
+ goto out_free_tx_irq;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_unmap_tx;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, lp->rx_ra, lp->rx_num_entries);
+ if (hv_err)
+ goto out_unmap_tx;
+
+ lp->flags |= LDC_FLAG_REGISTERED_QUEUES;
+
+ hv_err = sun4v_ldc_tx_get_state(lp->id,
+ &lp->tx_head,
+ &lp->tx_tail,
+ &lp->chan_state);
+ err = -EBUSY;
+ if (hv_err)
+ goto out_unmap_rx;
+
+ lp->tx_acked = lp->tx_head;
+
+ lp->hs_state = LDC_HS_OPEN;
+ ldc_set_state(lp, LDC_STATE_BOUND);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return 0;
+
+out_unmap_rx:
+ lp->flags &= ~LDC_FLAG_REGISTERED_QUEUES;
+ sun4v_ldc_rx_qconf(lp->id, 0, 0);
+
+out_unmap_tx:
+ sun4v_ldc_tx_qconf(lp->id, 0, 0);
+
+out_free_tx_irq:
+ lp->flags &= ~LDC_FLAG_REGISTERED_IRQS;
+ free_irq(lp->cfg.tx_irq, lp);
+
+out_free_rx_irq:
+ free_irq(lp->cfg.rx_irq, lp);
+
+out_err:
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_bind);
+
+int ldc_connect(struct ldc_channel *lp)
+{
+ unsigned long flags;
+ int err;
+
+ if (lp->cfg.mode == LDC_MODE_RAW)
+ return -EINVAL;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if (!(lp->flags & LDC_FLAG_ALLOCED_QUEUES) ||
+ !(lp->flags & LDC_FLAG_REGISTERED_QUEUES) ||
+ lp->hs_state != LDC_HS_OPEN)
+ err = -EINVAL;
+ else
+ err = start_handshake(lp);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_connect);
+
+int ldc_disconnect(struct ldc_channel *lp)
+{
+ unsigned long hv_err, flags;
+ int err;
+
+ if (lp->cfg.mode == LDC_MODE_RAW)
+ return -EINVAL;
+
+ if (!(lp->flags & LDC_FLAG_ALLOCED_QUEUES) ||
+ !(lp->flags & LDC_FLAG_REGISTERED_QUEUES))
+ return -EINVAL;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ err = -ENODEV;
+ hv_err = sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_err;
+
+ hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries);
+ if (hv_err)
+ goto out_err;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_err;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, lp->rx_ra, lp->rx_num_entries);
+ if (hv_err)
+ goto out_err;
+
+ ldc_set_state(lp, LDC_STATE_BOUND);
+ lp->hs_state = LDC_HS_OPEN;
+ lp->flags |= LDC_FLAG_RESET;
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return 0;
+
+out_err:
+ sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ free_irq(lp->cfg.tx_irq, lp);
+ free_irq(lp->cfg.rx_irq, lp);
+ lp->flags &= ~(LDC_FLAG_REGISTERED_IRQS |
+ LDC_FLAG_REGISTERED_QUEUES);
+ ldc_set_state(lp, LDC_STATE_INIT);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_disconnect);
+
+int ldc_state(struct ldc_channel *lp)
+{
+ return lp->state;
+}
+EXPORT_SYMBOL(ldc_state);
+
+static int write_raw(struct ldc_channel *lp, const void *buf, unsigned int size)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+ int err;
+
+ if (size > LDC_PACKET_SIZE)
+ return -EMSGSIZE;
+
+ p = data_get_tx_packet(lp, &new_tail);
+ if (!p)
+ return -EAGAIN;
+
+ memcpy(p, buf, size);
+
+ err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ err = size;
+
+ return err;
+}
+
+static int read_raw(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ struct ldc_packet *p;
+ unsigned long hv_err, new;
+ int err;
+
+ if (size < LDC_PACKET_SIZE)
+ return -EINVAL;
+
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ return ldc_abort(lp);
+
+ if (lp->chan_state == LDC_CHANNEL_DOWN ||
+ lp->chan_state == LDC_CHANNEL_RESETTING)
+ return -ECONNRESET;
+
+ if (lp->rx_head == lp->rx_tail)
+ return 0;
+
+ p = lp->rx_base + (lp->rx_head / LDC_PACKET_SIZE);
+ memcpy(buf, p, LDC_PACKET_SIZE);
+
+ new = rx_advance(lp, lp->rx_head);
+ lp->rx_head = new;
+
+ err = __set_rx_head(lp, new);
+ if (err < 0)
+ err = -ECONNRESET;
+ else
+ err = LDC_PACKET_SIZE;
+
+ return err;
+}
+
+static const struct ldc_mode_ops raw_ops = {
+ .write = write_raw,
+ .read = read_raw,
+};
+
+static int write_nonraw(struct ldc_channel *lp, const void *buf,
+ unsigned int size)
+{
+ unsigned long hv_err, tail;
+ unsigned int copied;
+ u32 seq;
+ int err;
+
+ hv_err = sun4v_ldc_tx_get_state(lp->id, &lp->tx_head, &lp->tx_tail,
+ &lp->chan_state);
+ if (unlikely(hv_err))
+ return -EBUSY;
+
+ if (unlikely(lp->chan_state != LDC_CHANNEL_UP))
+ return ldc_abort(lp);
+
+ if (!tx_has_space_for(lp, size))
+ return -EAGAIN;
+
+ seq = lp->snd_nxt;
+ copied = 0;
+ tail = lp->tx_tail;
+ while (copied < size) {
+ struct ldc_packet *p = lp->tx_base + (tail / LDC_PACKET_SIZE);
+ u8 *data = ((lp->cfg.mode == LDC_MODE_UNRELIABLE) ?
+ p->u.u_data :
+ p->u.r.r_data);
+ int data_len;
+
+ p->type = LDC_DATA;
+ p->stype = LDC_INFO;
+ p->ctrl = 0;
+
+ data_len = size - copied;
+ if (data_len > lp->mss)
+ data_len = lp->mss;
+
+ BUG_ON(data_len > LDC_LEN);
+
+ p->env = (data_len |
+ (copied == 0 ? LDC_START : 0) |
+ (data_len == size - copied ? LDC_STOP : 0));
+
+ p->seqid = ++seq;
+
+ ldcdbg(DATA, "SENT DATA [%02x:%02x:%02x:%02x:%08x]\n",
+ p->type,
+ p->stype,
+ p->ctrl,
+ p->env,
+ p->seqid);
+
+ memcpy(data, buf, data_len);
+ buf += data_len;
+ copied += data_len;
+
+ tail = tx_advance(lp, tail);
+ }
+
+ err = set_tx_tail(lp, tail);
+ if (!err) {
+ lp->snd_nxt = seq;
+ err = size;
+ }
+
+ return err;
+}
+
+static int rx_bad_seq(struct ldc_channel *lp, struct ldc_packet *p,
+ struct ldc_packet *first_frag)
+{
+ int err;
+
+ if (first_frag)
+ lp->rcv_nxt = first_frag->seqid - 1;
+
+ err = send_data_nack(lp, p);
+ if (err)
+ return err;
+
+ err = __set_rx_head(lp, lp->rx_tail);
+ if (err < 0)
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int data_ack_nack(struct ldc_channel *lp, struct ldc_packet *p)
+{
+ if (p->stype & LDC_ACK) {
+ int err = process_data_ack(lp, p);
+ if (err)
+ return err;
+ }
+ if (p->stype & LDC_NACK)
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int rx_data_wait(struct ldc_channel *lp, unsigned long cur_head)
+{
+ unsigned long dummy;
+ int limit = 1000;
+
+ ldcdbg(DATA, "DATA WAIT cur_head[%lx] rx_head[%lx] rx_tail[%lx]\n",
+ cur_head, lp->rx_head, lp->rx_tail);
+ while (limit-- > 0) {
+ unsigned long hv_err;
+
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &dummy,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ return ldc_abort(lp);
+
+ if (lp->chan_state == LDC_CHANNEL_DOWN ||
+ lp->chan_state == LDC_CHANNEL_RESETTING)
+ return -ECONNRESET;
+
+ if (cur_head != lp->rx_tail) {
+ ldcdbg(DATA, "DATA WAIT DONE "
+ "head[%lx] tail[%lx] chan_state[%lx]\n",
+ dummy, lp->rx_tail, lp->chan_state);
+ return 0;
+ }
+
+ udelay(1);
+ }
+ return -EAGAIN;
+}
+
+static int rx_set_head(struct ldc_channel *lp, unsigned long head)
+{
+ int err = __set_rx_head(lp, head);
+
+ if (err < 0)
+ return ldc_abort(lp);
+
+ lp->rx_head = head;
+ return 0;
+}
+
+static void send_data_ack(struct ldc_channel *lp)
+{
+ unsigned long new_tail;
+ struct ldc_packet *p;
+
+ p = data_get_tx_packet(lp, &new_tail);
+ if (likely(p)) {
+ int err;
+
+ memset(p, 0, sizeof(*p));
+ p->type = LDC_DATA;
+ p->stype = LDC_ACK;
+ p->ctrl = 0;
+ p->seqid = lp->snd_nxt + 1;
+ p->u.r.ackid = lp->rcv_nxt;
+
+ err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ lp->snd_nxt++;
+ }
+}
+
+static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ struct ldc_packet *first_frag;
+ unsigned long hv_err, new;
+ int err, copied;
+
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ return ldc_abort(lp);
+
+ if (lp->chan_state == LDC_CHANNEL_DOWN ||
+ lp->chan_state == LDC_CHANNEL_RESETTING)
+ return -ECONNRESET;
+
+ if (lp->rx_head == lp->rx_tail)
+ return 0;
+
+ first_frag = NULL;
+ copied = err = 0;
+ new = lp->rx_head;
+ while (1) {
+ struct ldc_packet *p;
+ int pkt_len;
+
+ BUG_ON(new == lp->rx_tail);
+ p = lp->rx_base + (new / LDC_PACKET_SIZE);
+
+ ldcdbg(RX, "RX read pkt[%02x:%02x:%02x:%02x:%08x:%08x] "
+ "rcv_nxt[%08x]\n",
+ p->type,
+ p->stype,
+ p->ctrl,
+ p->env,
+ p->seqid,
+ p->u.r.ackid,
+ lp->rcv_nxt);
+
+ if (unlikely(!rx_seq_ok(lp, p->seqid))) {
+ err = rx_bad_seq(lp, p, first_frag);
+ copied = 0;
+ break;
+ }
+
+ if (p->type & LDC_CTRL) {
+ err = process_control_frame(lp, p);
+ if (err < 0)
+ break;
+ err = 0;
+ }
+
+ lp->rcv_nxt = p->seqid;
+
+ if (!(p->type & LDC_DATA)) {
+ new = rx_advance(lp, new);
+ goto no_data;
+ }
+ if (p->stype & (LDC_ACK | LDC_NACK)) {
+ err = data_ack_nack(lp, p);
+ if (err)
+ break;
+ }
+ if (!(p->stype & LDC_INFO)) {
+ new = rx_advance(lp, new);
+ err = rx_set_head(lp, new);
+ if (err)
+ break;
+ goto no_data;
+ }
+
+ pkt_len = p->env & LDC_LEN;
+
+ /* Every initial packet starts with the START bit set.
+ *
+ * Singleton packets will have both START+STOP set.
+ *
+ * Fragments will have START set in the first frame, STOP
+ * set in the last frame, and neither bit set in middle
+ * frames of the packet.
+ *
+ * Therefore if we are at the beginning of a packet and
+ * we don't see START, or we are in the middle of a fragmented
+ * packet and do see START, we are unsynchronized and should
+ * flush the RX queue.
+ */
+ if ((first_frag == NULL && !(p->env & LDC_START)) ||
+ (first_frag != NULL && (p->env & LDC_START))) {
+ if (!first_frag)
+ new = rx_advance(lp, new);
+
+ err = rx_set_head(lp, new);
+ if (err)
+ break;
+
+ if (!first_frag)
+ goto no_data;
+ }
+ if (!first_frag)
+ first_frag = p;
+
+ if (pkt_len > size - copied) {
+ /* User didn't give us a big enough buffer,
+ * what to do? This is a pretty serious error.
+ *
+ * Since we haven't updated the RX ring head to
+ * consume any of the packets, signal the error
+ * to the user and just leave the RX ring alone.
+ *
+ * This seems the best behavior because this allows
+ * a user of the LDC layer to start with a small
+ * RX buffer for ldc_read() calls and use -EMSGSIZE
+ * as a cue to enlarge it's read buffer.
+ */
+ err = -EMSGSIZE;
+ break;
+ }
+
+ /* Ok, we are gonna eat this one. */
+ new = rx_advance(lp, new);
+
+ memcpy(buf,
+ (lp->cfg.mode == LDC_MODE_UNRELIABLE ?
+ p->u.u_data : p->u.r.r_data), pkt_len);
+ buf += pkt_len;
+ copied += pkt_len;
+
+ if (p->env & LDC_STOP)
+ break;
+
+no_data:
+ if (new == lp->rx_tail) {
+ err = rx_data_wait(lp, new);
+ if (err)
+ break;
+ }
+ }
+
+ if (!err)
+ err = rx_set_head(lp, new);
+
+ if (err && first_frag)
+ lp->rcv_nxt = first_frag->seqid - 1;
+
+ if (!err) {
+ err = copied;
+ if (err > 0 && lp->cfg.mode != LDC_MODE_UNRELIABLE)
+ send_data_ack(lp);
+ }
+
+ return err;
+}
+
+static const struct ldc_mode_ops nonraw_ops = {
+ .write = write_nonraw,
+ .read = read_nonraw,
+};
+
+static int write_stream(struct ldc_channel *lp, const void *buf,
+ unsigned int size)
+{
+ if (size > lp->cfg.mtu)
+ size = lp->cfg.mtu;
+ return write_nonraw(lp, buf, size);
+}
+
+static int read_stream(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ if (!lp->mssbuf_len) {
+ int err = read_nonraw(lp, lp->mssbuf, lp->cfg.mtu);
+ if (err < 0)
+ return err;
+
+ lp->mssbuf_len = err;
+ lp->mssbuf_off = 0;
+ }
+
+ if (size > lp->mssbuf_len)
+ size = lp->mssbuf_len;
+ memcpy(buf, lp->mssbuf + lp->mssbuf_off, size);
+
+ lp->mssbuf_off += size;
+ lp->mssbuf_len -= size;
+
+ return size;
+}
+
+static const struct ldc_mode_ops stream_ops = {
+ .write = write_stream,
+ .read = read_stream,
+};
+
+int ldc_write(struct ldc_channel *lp, const void *buf, unsigned int size)
+{
+ unsigned long flags;
+ int err;
+
+ if (!buf)
+ return -EINVAL;
+
+ if (!size)
+ return 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if (lp->hs_state != LDC_HS_COMPLETE)
+ err = -ENOTCONN;
+ else
+ err = lp->mops->write(lp, buf, size);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_write);
+
+int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ unsigned long flags;
+ int err;
+
+ if (!buf)
+ return -EINVAL;
+
+ if (!size)
+ return 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if (lp->hs_state != LDC_HS_COMPLETE)
+ err = -ENOTCONN;
+ else
+ err = lp->mops->read(lp, buf, size);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_read);
+
+static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages)
+{
+ struct iommu_arena *arena = &iommu->arena;
+ unsigned long n, i, start, end, limit;
+ int pass;
+
+ limit = arena->limit;
+ start = arena->hint;
+ pass = 0;
+
+again:
+ n = find_next_zero_bit(arena->map, limit, start);
+ end = n + npages;
+ if (unlikely(end >= limit)) {
+ if (likely(pass < 1)) {
+ limit = start;
+ start = 0;
+ pass++;
+ goto again;
+ } else {
+ /* Scanned the whole thing, give up. */
+ return -1;
+ }
+ }
+
+ for (i = n; i < end; i++) {
+ if (test_bit(i, arena->map)) {
+ start = i + 1;
+ goto again;
+ }
+ }
+
+ for (i = n; i < end; i++)
+ __set_bit(i, arena->map);
+
+ arena->hint = end;
+
+ return n;
+}
+
+#define COOKIE_PGSZ_CODE 0xf000000000000000ULL
+#define COOKIE_PGSZ_CODE_SHIFT 60ULL
+
+static u64 pagesize_code(void)
+{
+ switch (PAGE_SIZE) {
+ default:
+ case (8ULL * 1024ULL):
+ return 0;
+ case (64ULL * 1024ULL):
+ return 1;
+ case (512ULL * 1024ULL):
+ return 2;
+ case (4ULL * 1024ULL * 1024ULL):
+ return 3;
+ case (32ULL * 1024ULL * 1024ULL):
+ return 4;
+ case (256ULL * 1024ULL * 1024ULL):
+ return 5;
+ }
+}
+
+static u64 make_cookie(u64 index, u64 pgsz_code, u64 page_offset)
+{
+ return ((pgsz_code << COOKIE_PGSZ_CODE_SHIFT) |
+ (index << PAGE_SHIFT) |
+ page_offset);
+}
+
+static u64 cookie_to_index(u64 cookie, unsigned long *shift)
+{
+ u64 szcode = cookie >> COOKIE_PGSZ_CODE_SHIFT;
+
+ cookie &= ~COOKIE_PGSZ_CODE;
+
+ *shift = szcode * 3;
+
+ return (cookie >> (13ULL + (szcode * 3ULL)));
+}
+
+static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu,
+ unsigned long npages)
+{
+ long entry;
+
+ entry = arena_alloc(iommu, npages);
+ if (unlikely(entry < 0))
+ return NULL;
+
+ return iommu->page_table + entry;
+}
+
+static u64 perm_to_mte(unsigned int map_perm)
+{
+ u64 mte_base;
+
+ mte_base = pagesize_code();
+
+ if (map_perm & LDC_MAP_SHADOW) {
+ if (map_perm & LDC_MAP_R)
+ mte_base |= LDC_MTE_COPY_R;
+ if (map_perm & LDC_MAP_W)
+ mte_base |= LDC_MTE_COPY_W;
+ }
+ if (map_perm & LDC_MAP_DIRECT) {
+ if (map_perm & LDC_MAP_R)
+ mte_base |= LDC_MTE_READ;
+ if (map_perm & LDC_MAP_W)
+ mte_base |= LDC_MTE_WRITE;
+ if (map_perm & LDC_MAP_X)
+ mte_base |= LDC_MTE_EXEC;
+ }
+ if (map_perm & LDC_MAP_IO) {
+ if (map_perm & LDC_MAP_R)
+ mte_base |= LDC_MTE_IOMMU_R;
+ if (map_perm & LDC_MAP_W)
+ mte_base |= LDC_MTE_IOMMU_W;
+ }
+
+ return mte_base;
+}
+
+static int pages_in_region(unsigned long base, long len)
+{
+ int count = 0;
+
+ do {
+ unsigned long new = (base + PAGE_SIZE) & PAGE_MASK;
+
+ len -= (new - base);
+ base = new;
+ count++;
+ } while (len > 0);
+
+ return count;
+}
+
+struct cookie_state {
+ struct ldc_mtable_entry *page_table;
+ struct ldc_trans_cookie *cookies;
+ u64 mte_base;
+ u64 prev_cookie;
+ u32 pte_idx;
+ u32 nc;
+};
+
+static void fill_cookies(struct cookie_state *sp, unsigned long pa,
+ unsigned long off, unsigned long len)
+{
+ do {
+ unsigned long tlen, new = pa + PAGE_SIZE;
+ u64 this_cookie;
+
+ sp->page_table[sp->pte_idx].mte = sp->mte_base | pa;
+
+ tlen = PAGE_SIZE;
+ if (off)
+ tlen = PAGE_SIZE - off;
+ if (tlen > len)
+ tlen = len;
+
+ this_cookie = make_cookie(sp->pte_idx,
+ pagesize_code(), off);
+
+ off = 0;
+
+ if (this_cookie == sp->prev_cookie) {
+ sp->cookies[sp->nc - 1].cookie_size += tlen;
+ } else {
+ sp->cookies[sp->nc].cookie_addr = this_cookie;
+ sp->cookies[sp->nc].cookie_size = tlen;
+ sp->nc++;
+ }
+ sp->prev_cookie = this_cookie + tlen;
+
+ sp->pte_idx++;
+
+ len -= tlen;
+ pa = new;
+ } while (len > 0);
+}
+
+static int sg_count_one(struct scatterlist *sg)
+{
+ unsigned long base = page_to_pfn(sg->page) << PAGE_SHIFT;
+ long len = sg->length;
+
+ if ((sg->offset | len) & (8UL - 1))
+ return -EFAULT;
+
+ return pages_in_region(base + sg->offset, len);
+}
+
+static int sg_count_pages(struct scatterlist *sg, int num_sg)
+{
+ int count;
+ int i;
+
+ count = 0;
+ for (i = 0; i < num_sg; i++) {
+ int err = sg_count_one(sg + i);
+ if (err < 0)
+ return err;
+ count += err;
+ }
+
+ return count;
+}
+
+int ldc_map_sg(struct ldc_channel *lp,
+ struct scatterlist *sg, int num_sg,
+ struct ldc_trans_cookie *cookies, int ncookies,
+ unsigned int map_perm)
+{
+ unsigned long i, npages, flags;
+ struct ldc_mtable_entry *base;
+ struct cookie_state state;
+ struct ldc_iommu *iommu;
+ int err;
+
+ if (map_perm & ~LDC_MAP_ALL)
+ return -EINVAL;
+
+ err = sg_count_pages(sg, num_sg);
+ if (err < 0)
+ return err;
+
+ npages = err;
+ if (err > ncookies)
+ return -EMSGSIZE;
+
+ iommu = &lp->iommu;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ base = alloc_npages(iommu, npages);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ if (!base)
+ return -ENOMEM;
+
+ state.page_table = iommu->page_table;
+ state.cookies = cookies;
+ state.mte_base = perm_to_mte(map_perm);
+ state.prev_cookie = ~(u64)0;
+ state.pte_idx = (base - iommu->page_table);
+ state.nc = 0;
+
+ for (i = 0; i < num_sg; i++)
+ fill_cookies(&state, page_to_pfn(sg[i].page) << PAGE_SHIFT,
+ sg[i].offset, sg[i].length);
+
+ return state.nc;
+}
+EXPORT_SYMBOL(ldc_map_sg);
+
+int ldc_map_single(struct ldc_channel *lp,
+ void *buf, unsigned int len,
+ struct ldc_trans_cookie *cookies, int ncookies,
+ unsigned int map_perm)
+{
+ unsigned long npages, pa, flags;
+ struct ldc_mtable_entry *base;
+ struct cookie_state state;
+ struct ldc_iommu *iommu;
+
+ if ((map_perm & ~LDC_MAP_ALL) || (ncookies < 1))
+ return -EINVAL;
+
+ pa = __pa(buf);
+ if ((pa | len) & (8UL - 1))
+ return -EFAULT;
+
+ npages = pages_in_region(pa, len);
+
+ iommu = &lp->iommu;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ base = alloc_npages(iommu, npages);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ if (!base)
+ return -ENOMEM;
+
+ state.page_table = iommu->page_table;
+ state.cookies = cookies;
+ state.mte_base = perm_to_mte(map_perm);
+ state.prev_cookie = ~(u64)0;
+ state.pte_idx = (base - iommu->page_table);
+ state.nc = 0;
+ fill_cookies(&state, (pa & PAGE_MASK), (pa & ~PAGE_MASK), len);
+ BUG_ON(state.nc != 1);
+
+ return state.nc;
+}
+EXPORT_SYMBOL(ldc_map_single);
+
+static void free_npages(unsigned long id, struct ldc_iommu *iommu,
+ u64 cookie, u64 size)
+{
+ struct iommu_arena *arena = &iommu->arena;
+ unsigned long i, shift, index, npages;
+ struct ldc_mtable_entry *base;
+
+ npages = PAGE_ALIGN(((cookie & ~PAGE_MASK) + size)) >> PAGE_SHIFT;
+ index = cookie_to_index(cookie, &shift);
+ base = iommu->page_table + index;
+
+ BUG_ON(index > arena->limit ||
+ (index + npages) > arena->limit);
+
+ for (i = 0; i < npages; i++) {
+ if (base->cookie)
+ sun4v_ldc_revoke(id, cookie + (i << shift),
+ base->cookie);
+ base->mte = 0;
+ __clear_bit(index + i, arena->map);
+ }
+}
+
+void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies,
+ int ncookies)
+{
+ struct ldc_iommu *iommu = &lp->iommu;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ for (i = 0; i < ncookies; i++) {
+ u64 addr = cookies[i].cookie_addr;
+ u64 size = cookies[i].cookie_size;
+
+ free_npages(lp->id, iommu, addr, size);
+ }
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+EXPORT_SYMBOL(ldc_unmap);
+
+int ldc_copy(struct ldc_channel *lp, int copy_dir,
+ void *buf, unsigned int len, unsigned long offset,
+ struct ldc_trans_cookie *cookies, int ncookies)
+{
+ unsigned int orig_len;
+ unsigned long ra;
+ int i;
+
+ if (copy_dir != LDC_COPY_IN && copy_dir != LDC_COPY_OUT) {
+ printk(KERN_ERR PFX "ldc_copy: ID[%lu] Bad copy_dir[%d]\n",
+ lp->id, copy_dir);
+ return -EINVAL;
+ }
+
+ ra = __pa(buf);
+ if ((ra | len | offset) & (8UL - 1)) {
+ printk(KERN_ERR PFX "ldc_copy: ID[%lu] Unaligned buffer "
+ "ra[%lx] len[%x] offset[%lx]\n",
+ lp->id, ra, len, offset);
+ return -EFAULT;
+ }
+
+ if (lp->hs_state != LDC_HS_COMPLETE ||
+ (lp->flags & LDC_FLAG_RESET)) {
+ printk(KERN_ERR PFX "ldc_copy: ID[%lu] Link down hs_state[%x] "
+ "flags[%x]\n", lp->id, lp->hs_state, lp->flags);
+ return -ECONNRESET;
+ }
+
+ orig_len = len;
+ for (i = 0; i < ncookies; i++) {
+ unsigned long cookie_raddr = cookies[i].cookie_addr;
+ unsigned long this_len = cookies[i].cookie_size;
+ unsigned long actual_len;
+
+ if (unlikely(offset)) {
+ unsigned long this_off = offset;
+
+ if (this_off > this_len)
+ this_off = this_len;
+
+ offset -= this_off;
+ this_len -= this_off;
+ if (!this_len)
+ continue;
+ cookie_raddr += this_off;
+ }
+
+ if (this_len > len)
+ this_len = len;
+
+ while (1) {
+ unsigned long hv_err;
+
+ hv_err = sun4v_ldc_copy(lp->id, copy_dir,
+ cookie_raddr, ra,
+ this_len, &actual_len);
+ if (unlikely(hv_err)) {
+ printk(KERN_ERR PFX "ldc_copy: ID[%lu] "
+ "HV error %lu\n",
+ lp->id, hv_err);
+ if (lp->hs_state != LDC_HS_COMPLETE ||
+ (lp->flags & LDC_FLAG_RESET))
+ return -ECONNRESET;
+ else
+ return -EFAULT;
+ }
+
+ cookie_raddr += actual_len;
+ ra += actual_len;
+ len -= actual_len;
+ if (actual_len == this_len)
+ break;
+
+ this_len -= actual_len;
+ }
+
+ if (!len)
+ break;
+ }
+
+ /* It is caller policy what to do about short copies.
+ * For example, a networking driver can declare the
+ * packet a runt and drop it.
+ */
+
+ return orig_len - len;
+}
+EXPORT_SYMBOL(ldc_copy);
+
+void *ldc_alloc_exp_dring(struct ldc_channel *lp, unsigned int len,
+ struct ldc_trans_cookie *cookies, int *ncookies,
+ unsigned int map_perm)
+{
+ void *buf;
+ int err;
+
+ if (len & (8UL - 1))
+ return ERR_PTR(-EINVAL);
+
+ buf = kzalloc(len, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ err = ldc_map_single(lp, buf, len, cookies, *ncookies, map_perm);
+ if (err < 0) {
+ kfree(buf);
+ return ERR_PTR(err);
+ }
+ *ncookies = err;
+
+ return buf;
+}
+EXPORT_SYMBOL(ldc_alloc_exp_dring);
+
+void ldc_free_exp_dring(struct ldc_channel *lp, void *buf, unsigned int len,
+ struct ldc_trans_cookie *cookies, int ncookies)
+{
+ ldc_unmap(lp, cookies, ncookies);
+ kfree(buf);
+}
+EXPORT_SYMBOL(ldc_free_exp_dring);
+
+static int __init ldc_init(void)
+{
+ unsigned long major, minor;
+ struct mdesc_handle *hp;
+ const u64 *v;
+ u64 mp;
+
+ hp = mdesc_grab();
+ if (!hp)
+ return -ENODEV;
+
+ mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "platform");
+ if (mp == MDESC_NODE_NULL)
+ return -ENODEV;
+
+ v = mdesc_get_property(hp, mp, "domaining-enabled", NULL);
+ if (!v)
+ return -ENODEV;
+
+ major = 1;
+ minor = 0;
+ if (sun4v_hvapi_register(HV_GRP_LDOM, major, &minor)) {
+ printk(KERN_INFO PFX "Could not register LDOM hvapi.\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "%s", version);
+
+ if (!*v) {
+ printk(KERN_INFO PFX "Domaining disabled.\n");
+ return -ENODEV;
+ }
+ ldom_domaining_enabled = 1;
+
+ return 0;
+}
+
+core_initcall(ldc_init);
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index f0e16045fb16..cce4d0ddf5d5 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -6,6 +6,9 @@
#include <linux/types.h>
#include <linux/bootmem.h>
#include <linux/log2.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
#include <asm/hypervisor.h>
#include <asm/mdesc.h>
@@ -29,7 +32,7 @@ struct mdesc_hdr {
u32 node_sz; /* node block size */
u32 name_sz; /* name block size */
u32 data_sz; /* data block size */
-};
+} __attribute__((aligned(16)));
struct mdesc_elem {
u8 tag;
@@ -53,306 +56,516 @@ struct mdesc_elem {
} d;
};
-static struct mdesc_hdr *main_mdesc;
-static struct mdesc_node *allnodes;
+struct mdesc_mem_ops {
+ struct mdesc_handle *(*alloc)(unsigned int mdesc_size);
+ void (*free)(struct mdesc_handle *handle);
+};
-static struct mdesc_node *allnodes_tail;
-static unsigned int unique_id;
+struct mdesc_handle {
+ struct list_head list;
+ struct mdesc_mem_ops *mops;
+ void *self_base;
+ atomic_t refcnt;
+ unsigned int handle_size;
+ struct mdesc_hdr mdesc;
+};
+
+static void mdesc_handle_init(struct mdesc_handle *hp,
+ unsigned int handle_size,
+ void *base)
+{
+ BUG_ON(((unsigned long)&hp->mdesc) & (16UL - 1));
-static struct mdesc_node **mdesc_hash;
-static unsigned int mdesc_hash_size;
+ memset(hp, 0, handle_size);
+ INIT_LIST_HEAD(&hp->list);
+ hp->self_base = base;
+ atomic_set(&hp->refcnt, 1);
+ hp->handle_size = handle_size;
+}
-static inline unsigned int node_hashfn(u64 node)
+static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size)
{
- return ((unsigned int) (node ^ (node >> 8) ^ (node >> 16)))
- & (mdesc_hash_size - 1);
+ struct mdesc_handle *hp;
+ unsigned int handle_size, alloc_size;
+
+ handle_size = (sizeof(struct mdesc_handle) -
+ sizeof(struct mdesc_hdr) +
+ mdesc_size);
+ alloc_size = PAGE_ALIGN(handle_size);
+
+ hp = __alloc_bootmem(alloc_size, PAGE_SIZE, 0UL);
+ if (hp)
+ mdesc_handle_init(hp, handle_size, hp);
+
+ return hp;
}
-static inline void hash_node(struct mdesc_node *mp)
+static void mdesc_bootmem_free(struct mdesc_handle *hp)
{
- struct mdesc_node **head = &mdesc_hash[node_hashfn(mp->node)];
+ unsigned int alloc_size, handle_size = hp->handle_size;
+ unsigned long start, end;
- mp->hash_next = *head;
- *head = mp;
+ BUG_ON(atomic_read(&hp->refcnt) != 0);
+ BUG_ON(!list_empty(&hp->list));
- if (allnodes_tail) {
- allnodes_tail->allnodes_next = mp;
- allnodes_tail = mp;
- } else {
- allnodes = allnodes_tail = mp;
+ alloc_size = PAGE_ALIGN(handle_size);
+
+ start = (unsigned long) hp;
+ end = start + alloc_size;
+
+ while (start < end) {
+ struct page *p;
+
+ p = virt_to_page(start);
+ ClearPageReserved(p);
+ __free_page(p);
+ start += PAGE_SIZE;
}
}
-static struct mdesc_node *find_node(u64 node)
+static struct mdesc_mem_ops bootmem_mdesc_ops = {
+ .alloc = mdesc_bootmem_alloc,
+ .free = mdesc_bootmem_free,
+};
+
+static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
{
- struct mdesc_node *mp = mdesc_hash[node_hashfn(node)];
+ unsigned int handle_size;
+ void *base;
- while (mp) {
- if (mp->node == node)
- return mp;
+ handle_size = (sizeof(struct mdesc_handle) -
+ sizeof(struct mdesc_hdr) +
+ mdesc_size);
- mp = mp->hash_next;
+ base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
+ if (base) {
+ struct mdesc_handle *hp;
+ unsigned long addr;
+
+ addr = (unsigned long)base;
+ addr = (addr + 15UL) & ~15UL;
+ hp = (struct mdesc_handle *) addr;
+
+ mdesc_handle_init(hp, handle_size, base);
+ return hp;
}
+
return NULL;
}
-struct property *md_find_property(const struct mdesc_node *mp,
- const char *name,
- int *lenp)
+static void mdesc_kfree(struct mdesc_handle *hp)
{
- struct property *pp;
+ BUG_ON(atomic_read(&hp->refcnt) != 0);
+ BUG_ON(!list_empty(&hp->list));
- for (pp = mp->properties; pp != 0; pp = pp->next) {
- if (strcasecmp(pp->name, name) == 0) {
- if (lenp)
- *lenp = pp->length;
- break;
- }
- }
- return pp;
+ kfree(hp->self_base);
}
-EXPORT_SYMBOL(md_find_property);
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *md_get_property(const struct mdesc_node *mp, const char *name,
- int *lenp)
+static struct mdesc_mem_ops kmalloc_mdesc_memops = {
+ .alloc = mdesc_kmalloc,
+ .free = mdesc_kfree,
+};
+
+static struct mdesc_handle *mdesc_alloc(unsigned int mdesc_size,
+ struct mdesc_mem_ops *mops)
{
- struct property *pp = md_find_property(mp, name, lenp);
- return pp ? pp->value : NULL;
+ struct mdesc_handle *hp = mops->alloc(mdesc_size);
+
+ if (hp)
+ hp->mops = mops;
+
+ return hp;
}
-EXPORT_SYMBOL(md_get_property);
-struct mdesc_node *md_find_node_by_name(struct mdesc_node *from,
- const char *name)
+static void mdesc_free(struct mdesc_handle *hp)
{
- struct mdesc_node *mp;
+ hp->mops->free(hp);
+}
- mp = from ? from->allnodes_next : allnodes;
- for (; mp != NULL; mp = mp->allnodes_next) {
- if (strcmp(mp->name, name) == 0)
- break;
+static struct mdesc_handle *cur_mdesc;
+static LIST_HEAD(mdesc_zombie_list);
+static DEFINE_SPINLOCK(mdesc_lock);
+
+struct mdesc_handle *mdesc_grab(void)
+{
+ struct mdesc_handle *hp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdesc_lock, flags);
+ hp = cur_mdesc;
+ if (hp)
+ atomic_inc(&hp->refcnt);
+ spin_unlock_irqrestore(&mdesc_lock, flags);
+
+ return hp;
+}
+EXPORT_SYMBOL(mdesc_grab);
+
+void mdesc_release(struct mdesc_handle *hp)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdesc_lock, flags);
+ if (atomic_dec_and_test(&hp->refcnt)) {
+ list_del_init(&hp->list);
+ hp->mops->free(hp);
}
- return mp;
+ spin_unlock_irqrestore(&mdesc_lock, flags);
}
-EXPORT_SYMBOL(md_find_node_by_name);
+EXPORT_SYMBOL(mdesc_release);
-static unsigned int mdesc_early_allocated;
+static DEFINE_MUTEX(mdesc_mutex);
+static struct mdesc_notifier_client *client_list;
-static void * __init mdesc_early_alloc(unsigned long size)
+void mdesc_register_notifier(struct mdesc_notifier_client *client)
{
- void *ret;
+ u64 node;
- ret = __alloc_bootmem(size, SMP_CACHE_BYTES, 0UL);
- if (ret == NULL) {
- prom_printf("MDESC: alloc of %lu bytes failed.\n", size);
- prom_halt();
+ mutex_lock(&mdesc_mutex);
+ client->next = client_list;
+ client_list = client;
+
+ mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
+ client->add(cur_mdesc, node);
+
+ mutex_unlock(&mdesc_mutex);
+}
+
+static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
+{
+ const u64 *id;
+ u64 a;
+
+ id = NULL;
+ mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+ u64 target;
+
+ target = mdesc_arc_target(hp, a);
+ id = mdesc_get_property(hp, target,
+ "cfg-handle", NULL);
+ if (id)
+ break;
}
- memset(ret, 0, size);
+ return id;
+}
- mdesc_early_allocated += size;
+/* Run 'func' on nodes which are in A but not in B. */
+static void invoke_on_missing(const char *name,
+ struct mdesc_handle *a,
+ struct mdesc_handle *b,
+ void (*func)(struct mdesc_handle *, u64))
+{
+ u64 node;
- return ret;
+ mdesc_for_each_node_by_name(a, node, name) {
+ int found = 0, is_vdc_port = 0;
+ const char *name_prop;
+ const u64 *id;
+ u64 fnode;
+
+ name_prop = mdesc_get_property(a, node, "name", NULL);
+ if (name_prop && !strcmp(name_prop, "vdc-port")) {
+ is_vdc_port = 1;
+ id = parent_cfg_handle(a, node);
+ } else
+ id = mdesc_get_property(a, node, "id", NULL);
+
+ if (!id) {
+ printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
+ (name_prop ? name_prop : name));
+ continue;
+ }
+
+ mdesc_for_each_node_by_name(b, fnode, name) {
+ const u64 *fid;
+
+ if (is_vdc_port) {
+ name_prop = mdesc_get_property(b, fnode,
+ "name", NULL);
+ if (!name_prop ||
+ strcmp(name_prop, "vdc-port"))
+ continue;
+ fid = parent_cfg_handle(b, fnode);
+ if (!fid) {
+ printk(KERN_ERR "MD: Cannot find ID "
+ "for vdc-port node.\n");
+ continue;
+ }
+ } else
+ fid = mdesc_get_property(b, fnode,
+ "id", NULL);
+
+ if (*id == *fid) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ func(a, node);
+ }
}
-static unsigned int __init count_arcs(struct mdesc_elem *ep)
+static void notify_one(struct mdesc_notifier_client *p,
+ struct mdesc_handle *old_hp,
+ struct mdesc_handle *new_hp)
{
- unsigned int ret = 0;
+ invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
+ invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
+}
- ep++;
- while (ep->tag != MD_NODE_END) {
- if (ep->tag == MD_PROP_ARC)
- ret++;
- ep++;
+static void mdesc_notify_clients(struct mdesc_handle *old_hp,
+ struct mdesc_handle *new_hp)
+{
+ struct mdesc_notifier_client *p = client_list;
+
+ while (p) {
+ notify_one(p, old_hp, new_hp);
+ p = p->next;
}
- return ret;
}
-static void __init mdesc_node_alloc(u64 node, struct mdesc_elem *ep, const char *names)
+void mdesc_update(void)
{
- unsigned int num_arcs = count_arcs(ep);
- struct mdesc_node *mp;
+ unsigned long len, real_len, status;
+ struct mdesc_handle *hp, *orig_hp;
+ unsigned long flags;
+
+ mutex_lock(&mdesc_mutex);
+
+ (void) sun4v_mach_desc(0UL, 0UL, &len);
+
+ hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
+ if (!hp) {
+ printk(KERN_ERR "MD: mdesc alloc fails\n");
+ goto out;
+ }
+
+ status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
+ if (status != HV_EOK || real_len > len) {
+ printk(KERN_ERR "MD: mdesc reread fails with %lu\n",
+ status);
+ atomic_dec(&hp->refcnt);
+ mdesc_free(hp);
+ goto out;
+ }
- mp = mdesc_early_alloc(sizeof(*mp) +
- (num_arcs * sizeof(struct mdesc_arc)));
- mp->name = names + ep->name_offset;
- mp->node = node;
- mp->unique_id = unique_id++;
- mp->num_arcs = num_arcs;
+ spin_lock_irqsave(&mdesc_lock, flags);
+ orig_hp = cur_mdesc;
+ cur_mdesc = hp;
+ spin_unlock_irqrestore(&mdesc_lock, flags);
- hash_node(mp);
+ mdesc_notify_clients(orig_hp, hp);
+
+ spin_lock_irqsave(&mdesc_lock, flags);
+ if (atomic_dec_and_test(&orig_hp->refcnt))
+ mdesc_free(orig_hp);
+ else
+ list_add(&orig_hp->list, &mdesc_zombie_list);
+ spin_unlock_irqrestore(&mdesc_lock, flags);
+
+out:
+ mutex_unlock(&mdesc_mutex);
}
-static inline struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
+static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
{
return (struct mdesc_elem *) (mdesc + 1);
}
-static inline void *name_block(struct mdesc_hdr *mdesc)
+static void *name_block(struct mdesc_hdr *mdesc)
{
return ((void *) node_block(mdesc)) + mdesc->node_sz;
}
-static inline void *data_block(struct mdesc_hdr *mdesc)
+static void *data_block(struct mdesc_hdr *mdesc)
{
return ((void *) name_block(mdesc)) + mdesc->name_sz;
}
-/* In order to avoid recursion (the graph can be very deep) we use a
- * two pass algorithm. First we allocate all the nodes and hash them.
- * Then we iterate over each node, filling in the arcs and properties.
- */
-static void __init build_all_nodes(struct mdesc_hdr *mdesc)
+u64 mdesc_node_by_name(struct mdesc_handle *hp,
+ u64 from_node, const char *name)
{
- struct mdesc_elem *start, *ep;
- struct mdesc_node *mp;
- const char *names;
- void *data;
- u64 last_node;
+ struct mdesc_elem *ep = node_block(&hp->mdesc);
+ const char *names = name_block(&hp->mdesc);
+ u64 last_node = hp->mdesc.node_sz / 16;
+ u64 ret;
+
+ if (from_node == MDESC_NODE_NULL) {
+ ret = from_node = 0;
+ } else if (from_node >= last_node) {
+ return MDESC_NODE_NULL;
+ } else {
+ ret = ep[from_node].d.val;
+ }
- start = ep = node_block(mdesc);
- last_node = mdesc->node_sz / 16;
+ while (ret < last_node) {
+ if (ep[ret].tag != MD_NODE)
+ return MDESC_NODE_NULL;
+ if (!strcmp(names + ep[ret].name_offset, name))
+ break;
+ ret = ep[ret].d.val;
+ }
+ if (ret >= last_node)
+ ret = MDESC_NODE_NULL;
+ return ret;
+}
+EXPORT_SYMBOL(mdesc_node_by_name);
- names = name_block(mdesc);
+const void *mdesc_get_property(struct mdesc_handle *hp, u64 node,
+ const char *name, int *lenp)
+{
+ const char *names = name_block(&hp->mdesc);
+ u64 last_node = hp->mdesc.node_sz / 16;
+ void *data = data_block(&hp->mdesc);
+ struct mdesc_elem *ep;
- while (1) {
- u64 node = ep - start;
+ if (node == MDESC_NODE_NULL || node >= last_node)
+ return NULL;
- if (ep->tag == MD_LIST_END)
+ ep = node_block(&hp->mdesc) + node;
+ ep++;
+ for (; ep->tag != MD_NODE_END; ep++) {
+ void *val = NULL;
+ int len = 0;
+
+ switch (ep->tag) {
+ case MD_PROP_VAL:
+ val = &ep->d.val;
+ len = 8;
break;
- if (ep->tag != MD_NODE) {
- prom_printf("MDESC: Inconsistent element list.\n");
- prom_halt();
- }
-
- mdesc_node_alloc(node, ep, names);
+ case MD_PROP_STR:
+ case MD_PROP_DATA:
+ val = data + ep->d.data.data_offset;
+ len = ep->d.data.data_len;
+ break;
- if (ep->d.val >= last_node) {
- printk("MDESC: Warning, early break out of node scan.\n");
- printk("MDESC: Next node [%lu] last_node [%lu].\n",
- node, last_node);
+ default:
break;
}
+ if (!val)
+ continue;
- ep = start + ep->d.val;
+ if (!strcmp(names + ep->name_offset, name)) {
+ if (lenp)
+ *lenp = len;
+ return val;
+ }
}
- data = data_block(mdesc);
- for (mp = allnodes; mp; mp = mp->allnodes_next) {
- struct mdesc_elem *ep = start + mp->node;
- struct property **link = &mp->properties;
- unsigned int this_arc = 0;
-
- ep++;
- while (ep->tag != MD_NODE_END) {
- switch (ep->tag) {
- case MD_PROP_ARC: {
- struct mdesc_node *target;
-
- if (this_arc >= mp->num_arcs) {
- prom_printf("MDESC: ARC overrun [%u:%u]\n",
- this_arc, mp->num_arcs);
- prom_halt();
- }
- target = find_node(ep->d.val);
- if (!target) {
- printk("MDESC: Warning, arc points to "
- "missing node, ignoring.\n");
- break;
- }
- mp->arcs[this_arc].name =
- (names + ep->name_offset);
- mp->arcs[this_arc].arc = target;
- this_arc++;
- break;
- }
+ return NULL;
+}
+EXPORT_SYMBOL(mdesc_get_property);
- case MD_PROP_VAL:
- case MD_PROP_STR:
- case MD_PROP_DATA: {
- struct property *p = mdesc_early_alloc(sizeof(*p));
-
- p->unique_id = unique_id++;
- p->name = (char *) names + ep->name_offset;
- if (ep->tag == MD_PROP_VAL) {
- p->value = &ep->d.val;
- p->length = 8;
- } else {
- p->value = data + ep->d.data.data_offset;
- p->length = ep->d.data.data_len;
- }
- *link = p;
- link = &p->next;
- break;
- }
+u64 mdesc_next_arc(struct mdesc_handle *hp, u64 from, const char *arc_type)
+{
+ struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
+ const char *names = name_block(&hp->mdesc);
+ u64 last_node = hp->mdesc.node_sz / 16;
- case MD_NOOP:
- break;
+ if (from == MDESC_NODE_NULL || from >= last_node)
+ return MDESC_NODE_NULL;
- default:
- printk("MDESC: Warning, ignoring unknown tag type %02x\n",
- ep->tag);
- }
- ep++;
- }
+ ep = base + from;
+
+ ep++;
+ for (; ep->tag != MD_NODE_END; ep++) {
+ if (ep->tag != MD_PROP_ARC)
+ continue;
+
+ if (strcmp(names + ep->name_offset, arc_type))
+ continue;
+
+ return ep - base;
}
+
+ return MDESC_NODE_NULL;
}
+EXPORT_SYMBOL(mdesc_next_arc);
-static unsigned int __init count_nodes(struct mdesc_hdr *mdesc)
+u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc)
{
- struct mdesc_elem *ep = node_block(mdesc);
- struct mdesc_elem *end;
- unsigned int cnt = 0;
+ struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
- end = ((void *)ep) + mdesc->node_sz;
- while (ep < end) {
- if (ep->tag == MD_NODE)
- cnt++;
- ep++;
- }
- return cnt;
+ ep = base + arc;
+
+ return ep->d.val;
+}
+EXPORT_SYMBOL(mdesc_arc_target);
+
+const char *mdesc_node_name(struct mdesc_handle *hp, u64 node)
+{
+ struct mdesc_elem *ep, *base = node_block(&hp->mdesc);
+ const char *names = name_block(&hp->mdesc);
+ u64 last_node = hp->mdesc.node_sz / 16;
+
+ if (node == MDESC_NODE_NULL || node >= last_node)
+ return NULL;
+
+ ep = base + node;
+ if (ep->tag != MD_NODE)
+ return NULL;
+
+ return names + ep->name_offset;
}
+EXPORT_SYMBOL(mdesc_node_name);
static void __init report_platform_properties(void)
{
- struct mdesc_node *pn = md_find_node_by_name(NULL, "platform");
+ struct mdesc_handle *hp = mdesc_grab();
+ u64 pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "platform");
const char *s;
const u64 *v;
- if (!pn) {
+ if (pn == MDESC_NODE_NULL) {
prom_printf("No platform node in machine-description.\n");
prom_halt();
}
- s = md_get_property(pn, "banner-name", NULL);
+ s = mdesc_get_property(hp, pn, "banner-name", NULL);
printk("PLATFORM: banner-name [%s]\n", s);
- s = md_get_property(pn, "name", NULL);
+ s = mdesc_get_property(hp, pn, "name", NULL);
printk("PLATFORM: name [%s]\n", s);
- v = md_get_property(pn, "hostid", NULL);
+ v = mdesc_get_property(hp, pn, "hostid", NULL);
if (v)
printk("PLATFORM: hostid [%08lx]\n", *v);
- v = md_get_property(pn, "serial#", NULL);
+ v = mdesc_get_property(hp, pn, "serial#", NULL);
if (v)
printk("PLATFORM: serial# [%08lx]\n", *v);
- v = md_get_property(pn, "stick-frequency", NULL);
+ v = mdesc_get_property(hp, pn, "stick-frequency", NULL);
printk("PLATFORM: stick-frequency [%08lx]\n", *v);
- v = md_get_property(pn, "mac-address", NULL);
+ v = mdesc_get_property(hp, pn, "mac-address", NULL);
if (v)
printk("PLATFORM: mac-address [%lx]\n", *v);
- v = md_get_property(pn, "watchdog-resolution", NULL);
+ v = mdesc_get_property(hp, pn, "watchdog-resolution", NULL);
if (v)
printk("PLATFORM: watchdog-resolution [%lu ms]\n", *v);
- v = md_get_property(pn, "watchdog-max-timeout", NULL);
+ v = mdesc_get_property(hp, pn, "watchdog-max-timeout", NULL);
if (v)
printk("PLATFORM: watchdog-max-timeout [%lu ms]\n", *v);
- v = md_get_property(pn, "max-cpus", NULL);
+ v = mdesc_get_property(hp, pn, "max-cpus", NULL);
if (v)
printk("PLATFORM: max-cpus [%lu]\n", *v);
+
+#ifdef CONFIG_SMP
+ {
+ int max_cpu, i;
+
+ if (v) {
+ max_cpu = *v;
+ if (max_cpu > NR_CPUS)
+ max_cpu = NR_CPUS;
+ } else {
+ max_cpu = NR_CPUS;
+ }
+ for (i = 0; i < max_cpu; i++)
+ cpu_set(i, cpu_possible_map);
+ }
+#endif
+
+ mdesc_release(hp);
}
static int inline find_in_proplist(const char *list, const char *match, int len)
@@ -369,15 +582,17 @@ static int inline find_in_proplist(const char *list, const char *match, int len)
return 0;
}
-static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp)
+static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
+ struct mdesc_handle *hp,
+ u64 mp)
{
- const u64 *level = md_get_property(mp, "level", NULL);
- const u64 *size = md_get_property(mp, "size", NULL);
- const u64 *line_size = md_get_property(mp, "line-size", NULL);
+ const u64 *level = mdesc_get_property(hp, mp, "level", NULL);
+ const u64 *size = mdesc_get_property(hp, mp, "size", NULL);
+ const u64 *line_size = mdesc_get_property(hp, mp, "line-size", NULL);
const char *type;
int type_len;
- type = md_get_property(mp, "type", &type_len);
+ type = mdesc_get_property(hp, mp, "type", &type_len);
switch (*level) {
case 1:
@@ -400,48 +615,45 @@ static void __init fill_in_one_cache(cpuinfo_sparc *c, struct mdesc_node *mp)
}
if (*level == 1) {
- unsigned int i;
+ u64 a;
- for (i = 0; i < mp->num_arcs; i++) {
- struct mdesc_node *t = mp->arcs[i].arc;
+ mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
+ u64 target = mdesc_arc_target(hp, a);
+ const char *name = mdesc_node_name(hp, target);
- if (strcmp(mp->arcs[i].name, "fwd"))
- continue;
-
- if (!strcmp(t->name, "cache"))
- fill_in_one_cache(c, t);
+ if (!strcmp(name, "cache"))
+ fill_in_one_cache(c, hp, target);
}
}
}
-static void __init mark_core_ids(struct mdesc_node *mp, int core_id)
+static void __devinit mark_core_ids(struct mdesc_handle *hp, u64 mp,
+ int core_id)
{
- unsigned int i;
+ u64 a;
- for (i = 0; i < mp->num_arcs; i++) {
- struct mdesc_node *t = mp->arcs[i].arc;
+ mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+ u64 t = mdesc_arc_target(hp, a);
+ const char *name;
const u64 *id;
- if (strcmp(mp->arcs[i].name, "back"))
- continue;
-
- if (!strcmp(t->name, "cpu")) {
- id = md_get_property(t, "id", NULL);
+ name = mdesc_node_name(hp, t);
+ if (!strcmp(name, "cpu")) {
+ id = mdesc_get_property(hp, t, "id", NULL);
if (*id < NR_CPUS)
cpu_data(*id).core_id = core_id;
} else {
- unsigned int j;
+ u64 j;
- for (j = 0; j < t->num_arcs; j++) {
- struct mdesc_node *n = t->arcs[j].arc;
+ mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_BACK) {
+ u64 n = mdesc_arc_target(hp, j);
+ const char *n_name;
- if (strcmp(t->arcs[j].name, "back"))
+ n_name = mdesc_node_name(hp, n);
+ if (strcmp(n_name, "cpu"))
continue;
- if (strcmp(n->name, "cpu"))
- continue;
-
- id = md_get_property(n, "id", NULL);
+ id = mdesc_get_property(hp, n, "id", NULL);
if (*id < NR_CPUS)
cpu_data(*id).core_id = core_id;
}
@@ -449,78 +661,81 @@ static void __init mark_core_ids(struct mdesc_node *mp, int core_id)
}
}
-static void __init set_core_ids(void)
+static void __devinit set_core_ids(struct mdesc_handle *hp)
{
- struct mdesc_node *mp;
int idx;
+ u64 mp;
idx = 1;
- md_for_each_node_by_name(mp, "cache") {
- const u64 *level = md_get_property(mp, "level", NULL);
+ mdesc_for_each_node_by_name(hp, mp, "cache") {
+ const u64 *level;
const char *type;
int len;
+ level = mdesc_get_property(hp, mp, "level", NULL);
if (*level != 1)
continue;
- type = md_get_property(mp, "type", &len);
+ type = mdesc_get_property(hp, mp, "type", &len);
if (!find_in_proplist(type, "instn", len))
continue;
- mark_core_ids(mp, idx);
+ mark_core_ids(hp, mp, idx);
idx++;
}
}
-static void __init mark_proc_ids(struct mdesc_node *mp, int proc_id)
+static void __devinit mark_proc_ids(struct mdesc_handle *hp, u64 mp,
+ int proc_id)
{
- int i;
+ u64 a;
- for (i = 0; i < mp->num_arcs; i++) {
- struct mdesc_node *t = mp->arcs[i].arc;
+ mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+ u64 t = mdesc_arc_target(hp, a);
+ const char *name;
const u64 *id;
- if (strcmp(mp->arcs[i].name, "back"))
+ name = mdesc_node_name(hp, t);
+ if (strcmp(name, "cpu"))
continue;
- if (strcmp(t->name, "cpu"))
- continue;
-
- id = md_get_property(t, "id", NULL);
+ id = mdesc_get_property(hp, t, "id", NULL);
if (*id < NR_CPUS)
cpu_data(*id).proc_id = proc_id;
}
}
-static void __init __set_proc_ids(const char *exec_unit_name)
+static void __devinit __set_proc_ids(struct mdesc_handle *hp,
+ const char *exec_unit_name)
{
- struct mdesc_node *mp;
int idx;
+ u64 mp;
idx = 0;
- md_for_each_node_by_name(mp, exec_unit_name) {
+ mdesc_for_each_node_by_name(hp, mp, exec_unit_name) {
const char *type;
int len;
- type = md_get_property(mp, "type", &len);
+ type = mdesc_get_property(hp, mp, "type", &len);
if (!find_in_proplist(type, "int", len) &&
!find_in_proplist(type, "integer", len))
continue;
- mark_proc_ids(mp, idx);
+ mark_proc_ids(hp, mp, idx);
idx++;
}
}
-static void __init set_proc_ids(void)
+static void __devinit set_proc_ids(struct mdesc_handle *hp)
{
- __set_proc_ids("exec_unit");
- __set_proc_ids("exec-unit");
+ __set_proc_ids(hp, "exec_unit");
+ __set_proc_ids(hp, "exec-unit");
}
-static void __init get_one_mondo_bits(const u64 *p, unsigned int *mask, unsigned char def)
+static void __devinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
+ unsigned char def)
{
u64 val;
@@ -538,35 +753,37 @@ use_default:
*mask = ((1U << def) * 64U) - 1U;
}
-static void __init get_mondo_data(struct mdesc_node *mp, struct trap_per_cpu *tb)
+static void __devinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
+ struct trap_per_cpu *tb)
{
const u64 *val;
- val = md_get_property(mp, "q-cpu-mondo-#bits", NULL);
+ val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL);
get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7);
- val = md_get_property(mp, "q-dev-mondo-#bits", NULL);
+ val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL);
get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7);
- val = md_get_property(mp, "q-resumable-#bits", NULL);
+ val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL);
get_one_mondo_bits(val, &tb->resum_qmask, 6);
- val = md_get_property(mp, "q-nonresumable-#bits", NULL);
+ val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL);
get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
}
-static void __init mdesc_fill_in_cpu_data(void)
+void __devinit mdesc_fill_in_cpu_data(cpumask_t mask)
{
- struct mdesc_node *mp;
+ struct mdesc_handle *hp = mdesc_grab();
+ u64 mp;
ncpus_probed = 0;
- md_for_each_node_by_name(mp, "cpu") {
- const u64 *id = md_get_property(mp, "id", NULL);
- const u64 *cfreq = md_get_property(mp, "clock-frequency", NULL);
+ mdesc_for_each_node_by_name(hp, mp, "cpu") {
+ const u64 *id = mdesc_get_property(hp, mp, "id", NULL);
+ const u64 *cfreq = mdesc_get_property(hp, mp, "clock-frequency", NULL);
struct trap_per_cpu *tb;
cpuinfo_sparc *c;
- unsigned int i;
int cpuid;
+ u64 a;
ncpus_probed++;
@@ -575,6 +792,8 @@ static void __init mdesc_fill_in_cpu_data(void)
#ifdef CONFIG_SMP
if (cpuid >= NR_CPUS)
continue;
+ if (!cpu_isset(cpuid, mask))
+ continue;
#else
/* On uniprocessor we only want the values for the
* real physical cpu the kernel booted onto, however
@@ -589,35 +808,30 @@ static void __init mdesc_fill_in_cpu_data(void)
c->clock_tick = *cfreq;
tb = &trap_block[cpuid];
- get_mondo_data(mp, tb);
+ get_mondo_data(hp, mp, tb);
- for (i = 0; i < mp->num_arcs; i++) {
- struct mdesc_node *t = mp->arcs[i].arc;
- unsigned int j;
+ mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
+ u64 j, t = mdesc_arc_target(hp, a);
+ const char *t_name;
- if (strcmp(mp->arcs[i].name, "fwd"))
- continue;
-
- if (!strcmp(t->name, "cache")) {
- fill_in_one_cache(c, t);
+ t_name = mdesc_node_name(hp, t);
+ if (!strcmp(t_name, "cache")) {
+ fill_in_one_cache(c, hp, t);
continue;
}
- for (j = 0; j < t->num_arcs; j++) {
- struct mdesc_node *n;
-
- n = t->arcs[j].arc;
- if (strcmp(t->arcs[j].name, "fwd"))
- continue;
+ mdesc_for_each_arc(j, hp, t, MDESC_ARC_TYPE_FWD) {
+ u64 n = mdesc_arc_target(hp, j);
+ const char *n_name;
- if (!strcmp(n->name, "cache"))
- fill_in_one_cache(c, n);
+ n_name = mdesc_node_name(hp, n);
+ if (!strcmp(n_name, "cache"))
+ fill_in_one_cache(c, hp, n);
}
}
#ifdef CONFIG_SMP
cpu_set(cpuid, cpu_present_map);
- cpu_set(cpuid, phys_cpu_present_map);
#endif
c->core_id = 0;
@@ -628,45 +842,43 @@ static void __init mdesc_fill_in_cpu_data(void)
sparc64_multi_core = 1;
#endif
- set_core_ids();
- set_proc_ids();
+ set_core_ids(hp);
+ set_proc_ids(hp);
smp_fill_in_sib_core_maps();
+
+ mdesc_release(hp);
}
void __init sun4v_mdesc_init(void)
{
+ struct mdesc_handle *hp;
unsigned long len, real_len, status;
+ cpumask_t mask;
(void) sun4v_mach_desc(0UL, 0UL, &len);
printk("MDESC: Size is %lu bytes.\n", len);
- main_mdesc = mdesc_early_alloc(len);
+ hp = mdesc_alloc(len, &bootmem_mdesc_ops);
+ if (hp == NULL) {
+ prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
+ prom_halt();
+ }
- status = sun4v_mach_desc(__pa(main_mdesc), len, &real_len);
+ status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
if (status != HV_EOK || real_len > len) {
prom_printf("sun4v_mach_desc fails, err(%lu), "
"len(%lu), real_len(%lu)\n",
status, len, real_len);
+ mdesc_free(hp);
prom_halt();
}
- len = count_nodes(main_mdesc);
- printk("MDESC: %lu nodes.\n", len);
-
- len = roundup_pow_of_two(len);
-
- mdesc_hash = mdesc_early_alloc(len * sizeof(struct mdesc_node *));
- mdesc_hash_size = len;
-
- printk("MDESC: Hash size %lu entries.\n", len);
-
- build_all_nodes(main_mdesc);
-
- printk("MDESC: Built graph with %u bytes of memory.\n",
- mdesc_early_allocated);
+ cur_mdesc = hp;
report_platform_properties();
- mdesc_fill_in_cpu_data();
+
+ cpus_setall(mask);
+ mdesc_fill_in_cpu_data(mask);
}
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 6676b93219dc..4cc77485f536 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -1,132 +1,13 @@
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
- const struct of_device *dev)
-{
- if (!dev->node)
- return NULL;
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
- int match = 1;
- if (matches->name[0])
- match &= dev->node->name
- && !strcmp(matches->name, dev->node->name);
- if (matches->type[0])
- match &= dev->node->type
- && !strcmp(matches->type, dev->node->type);
- if (matches->compatible[0])
- match &= of_device_is_compatible(dev->node,
- matches->compatible);
- if (match)
- return matches;
- matches++;
- }
- return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * of_drv = to_of_platform_driver(drv);
- const struct of_device_id * matches = of_drv->match_table;
-
- if (!matches)
- return 0;
-
- return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
- struct device *tmp;
-
- if (!dev)
- return NULL;
- tmp = get_device(&dev->dev);
- if (tmp)
- return to_of_device(tmp);
- else
- return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
- if (dev)
- put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
- int error = -ENODEV;
- struct of_platform_driver *drv;
- struct of_device *of_dev;
- const struct of_device_id *match;
-
- drv = to_of_platform_driver(dev->driver);
- of_dev = to_of_device(dev);
-
- if (!drv->probe)
- return error;
-
- of_dev_get(of_dev);
-
- match = of_match_device(drv->match_table, of_dev);
- if (match)
- error = drv->probe(of_dev, match);
- if (error)
- of_dev_put(of_dev);
-
- return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
- if (dev->driver && drv->remove)
- drv->remove(of_dev);
- return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->suspend)
- error = drv->suspend(of_dev, state);
- return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->resume)
- error = drv->resume(of_dev);
- return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
{
@@ -163,7 +44,7 @@ static int node_match(struct device *dev, void *data)
struct of_device *of_find_device_by_node(struct device_node *dp)
{
- struct device *dev = bus_find_device(&of_bus_type, NULL,
+ struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
dp, node_match);
if (dev)
@@ -174,48 +55,20 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
EXPORT_SYMBOL(of_find_device_by_node);
#ifdef CONFIG_PCI
-struct bus_type isa_bus_type = {
- .name = "isa",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type isa_bus_type;
EXPORT_SYMBOL(isa_bus_type);
-struct bus_type ebus_bus_type = {
- .name = "ebus",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type ebus_bus_type;
EXPORT_SYMBOL(ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
- .name = "sbus",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type sbus_bus_type;
EXPORT_SYMBOL(sbus_bus_type);
#endif
-struct bus_type of_bus_type = {
- .name = "of",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
static inline u64 of_read_addr(const u32 *cell, int size)
{
@@ -899,11 +752,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
{
struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
const unsigned int *irq;
+ struct dev_archdata *sd;
int len, i;
if (!op)
return NULL;
+ sd = &op->dev.archdata;
+ sd->prom_node = dp;
+ sd->op = op;
+
op->node = dp;
op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -933,7 +791,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
op->dev.parent = parent;
- op->dev.bus = &of_bus_type;
+ op->dev.bus = &of_platform_bus_type;
if (!parent)
strcpy(op->dev.bus_id, "root");
else
@@ -977,16 +835,16 @@ static int __init of_bus_driver_init(void)
{
int err;
- err = bus_register(&of_bus_type);
+ err = of_bus_type_init(&of_platform_bus_type, "of");
#ifdef CONFIG_PCI
if (!err)
- err = bus_register(&isa_bus_type);
+ err = of_bus_type_init(&isa_bus_type, "isa");
if (!err)
- err = bus_register(&ebus_bus_type);
+ err = of_bus_type_init(&ebus_bus_type, "ebus");
#endif
#ifdef CONFIG_SBUS
if (!err)
- err = bus_register(&sbus_bus_type);
+ err = of_bus_type_init(&sbus_bus_type, "sbus");
#endif
if (!err)
@@ -1020,61 +878,13 @@ int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
/* register with core */
return driver_register(&drv->driver);
}
+EXPORT_SYMBOL(of_register_driver);
void of_unregister_driver(struct of_platform_driver *drv)
{
driver_unregister(&drv->driver);
}
-
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
- return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
-
- kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
- int rc;
-
- BUG_ON(ofdev->node == NULL);
-
- rc = device_register(&ofdev->dev);
- if (rc)
- return rc;
-
- rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
- if (rc)
- device_unregister(&ofdev->dev);
-
- return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
- device_remove_file(&ofdev->dev, &dev_attr_devspec);
- device_unregister(&ofdev->dev);
-}
+EXPORT_SYMBOL(of_unregister_driver);
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
@@ -1100,13 +910,4 @@ struct of_device* of_platform_device_create(struct device_node *np,
return dev;
}
-
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_register_driver);
-EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 81f4a5ea05f7..55ad1b899bb8 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -448,6 +448,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
*/
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
dev->class = class >> 8;
+ dev->revision = class & 0xff;
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 6b3fe2c1d65e..639cf06ca372 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -1129,7 +1129,7 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
}
#endif /* !(CONFIG_PCI_MSI) */
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
+static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
@@ -1163,7 +1163,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
pci_sun4v_msi_init(pbm);
}
-void sun4v_pci_init(struct device_node *dp, char *model_name)
+void __init sun4v_pci_init(struct device_node *dp, char *model_name)
{
static int hvapi_negotiated = 0;
struct pci_controller_info *p;
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 5d6adea3967f..881a09ee4c4c 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -1,7 +1,6 @@
-/* $Id: power.c,v 1.10 2001/12/11 01:57:16 davem Exp $
- * power.c: Power management driver.
+/* power.c: Power management driver.
*
- * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -13,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/syscalls.h>
+#include <linux/reboot.h>
#include <asm/system.h>
#include <asm/auxio.h>
@@ -29,24 +29,15 @@
*/
int scons_pwroff = 1;
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
static void __iomem *power_reg;
-static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed;
-
static irqreturn_t power_handler(int irq, void *dev_id)
{
- if (button_pressed == 0) {
- button_pressed = 1;
- wake_up(&powerd_wait);
- }
+ orderly_poweroff(true);
/* FIXME: Check registers for status... */
return IRQ_HANDLED;
}
-#endif /* CONFIG_PCI */
extern void machine_halt(void);
extern void machine_alt_power_off(void);
@@ -55,20 +46,19 @@ static void (*poweroff_method)(void) = machine_alt_power_off;
void machine_power_off(void)
{
sstate_poweroff();
- if (!serial_console || scons_pwroff) {
-#ifdef CONFIG_PCI
+ if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
if (power_reg) {
/* Both register bits seem to have the
* same effect, so until I figure out
* what the difference is...
*/
writel(AUXIO_PCIO_CPWR_OFF | AUXIO_PCIO_SPWR_OFF, power_reg);
- } else
-#endif /* CONFIG_PCI */
+ } else {
if (poweroff_method != NULL) {
poweroff_method();
/* not reached */
}
+ }
}
machine_halt();
}
@@ -76,40 +66,9 @@ void machine_power_off(void)
void (*pm_power_off)(void) = machine_power_off;
EXPORT_SYMBOL(pm_power_off);
-#ifdef CONFIG_PCI
-static int powerd(void *__unused)
-{
- static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
- DECLARE_WAITQUEUE(wait, current);
-
- daemonize("powerd");
-
- add_wait_queue(&powerd_wait, &wait);
-again:
- for (;;) {
- set_task_state(current, TASK_INTERRUPTIBLE);
- if (button_pressed)
- break;
- flush_signals(current);
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&powerd_wait, &wait);
-
- /* Ok, down we go... */
- button_pressed = 0;
- if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
- printk("powerd: shutdown execution failed\n");
- add_wait_queue(&powerd_wait, &wait);
- goto again;
- }
- return 0;
-}
-
static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
- if (irq == PCI_IRQ_NONE)
+ if (irq == 0xffffffff)
return 0;
if (!of_find_property(dp, "button", NULL))
return 0;
@@ -124,23 +83,15 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
power_reg = of_ioremap(res, 0, 0x4, "power");
- printk("%s: Control reg at %lx ... ",
+ printk(KERN_INFO "%s: Control reg at %lx\n",
op->node->name, res->start);
poweroff_method = machine_halt; /* able to use the standard halt */
if (has_button_interrupt(irq, op->node)) {
- if (kernel_thread(powerd, NULL, CLONE_FS) < 0) {
- printk("Failed to start power daemon.\n");
- return 0;
- }
- printk("powerd running.\n");
-
if (request_irq(irq,
power_handler, 0, "power", NULL) < 0)
- printk("power: Error, cannot register IRQ handler.\n");
- } else {
- printk("not using powerd.\n");
+ printk(KERN_ERR "power: Cannot setup IRQ handler.\n");
}
return 0;
@@ -161,7 +112,6 @@ static struct of_platform_driver power_driver = {
void __init power_init(void)
{
- of_register_driver(&power_driver, &of_bus_type);
+ of_register_driver(&power_driver, &of_platform_bus_type);
return;
}
-#endif /* CONFIG_PCI */
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index f5f97e2c669c..fd7899ba1d70 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -29,6 +29,7 @@
#include <linux/compat.h>
#include <linux/tick.h>
#include <linux/init.h>
+#include <linux/cpu.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
@@ -49,7 +50,7 @@
/* #define VERBOSE_SHOWREGS */
-static void sparc64_yield(void)
+static void sparc64_yield(int cpu)
{
if (tlb_type != hypervisor)
return;
@@ -57,7 +58,7 @@ static void sparc64_yield(void)
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb__after_clear_bit();
- while (!need_resched()) {
+ while (!need_resched() && !cpu_is_offline(cpu)) {
unsigned long pstate;
/* Disable interrupts. */
@@ -68,7 +69,7 @@ static void sparc64_yield(void)
: "=&r" (pstate)
: "i" (PSTATE_IE));
- if (!need_resched())
+ if (!need_resched() && !cpu_is_offline(cpu))
sun4v_cpu_yield();
/* Re-enable interrupts. */
@@ -86,15 +87,25 @@ static void sparc64_yield(void)
/* The idle loop on sparc64. */
void cpu_idle(void)
{
+ int cpu = smp_processor_id();
+
set_thread_flag(TIF_POLLING_NRFLAG);
while(1) {
tick_nohz_stop_sched_tick();
- while (!need_resched())
- sparc64_yield();
+
+ while (!need_resched() && !cpu_is_offline(cpu))
+ sparc64_yield(cpu);
+
tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if (cpu_is_offline(cpu))
+ cpu_play_dead();
+#endif
+
schedule();
preempt_disable();
}
@@ -108,7 +119,7 @@ extern void (*prom_keyboard)(void);
void machine_halt(void)
{
sstate_halt();
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (1);
if (prom_keyboard)
prom_keyboard();
@@ -119,7 +130,7 @@ void machine_halt(void)
void machine_alt_power_off(void)
{
sstate_poweroff();
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette(1);
if (prom_keyboard)
prom_keyboard();
@@ -134,7 +145,7 @@ void machine_restart(char * cmd)
sstate_reboot();
p = strchr (reboot_command, '\n');
if (p) *p = 0;
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (1);
if (prom_keyboard)
prom_keyboard();
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 61036b346664..f4e0a9ad9be3 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -30,73 +30,9 @@
#include <asm/upa.h>
#include <asm/smp.h>
-static struct device_node *allnodes;
+extern struct device_node *allnodes; /* temporary while merging */
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
- const char *compat)
-{
- const char* cp;
- int cplen, l;
-
- cp = of_get_property(device, "compatible", &cplen);
- if (cp == NULL)
- return 0;
- while (cplen > 0) {
- if (strncmp(cp, compat, strlen(compat)) == 0)
- return 1;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
- struct device_node *np;
-
- if (!node)
- return NULL;
-
- np = node->parent;
-
- return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
- struct device_node *prev)
-{
- struct device_node *next;
-
- next = prev ? prev->sibling : node->child;
- for (; next != 0; next = next->sibling) {
- break;
- }
-
- return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
- struct device_node *np = allnodes;
-
- for (; np != 0; np = np->allnext) {
- if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
- break;
- }
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock; /* temporary while merging */
struct device_node *of_find_node_by_phandle(phandle handle)
{
@@ -110,81 +46,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
}
EXPORT_SYMBOL(of_find_node_by_phandle);
-struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != NULL; np = np->allnext)
- if (np->name != NULL && strcmp(np->name, name) == 0)
- break;
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
- const char *type)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext)
- if (np->type != 0 && strcmp(np->type, type) == 0)
- break;
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
- const char *type, const char *compatible)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext) {
- if (type != NULL
- && !(np->type != 0 && strcmp(np->type, type) == 0))
- continue;
- if (of_device_is_compatible(np, compatible))
- break;
- }
-
- return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp)
-{
- struct property *pp;
-
- for (pp = np->properties; pp != 0; pp = pp->next) {
- if (strcasecmp(pp->name, name) == 0) {
- if (lenp != 0)
- *lenp = pp->length;
- break;
- }
- }
- return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
- int *lenp)
-{
- struct property *pp = of_find_property(np,name,lenp);
- return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
int of_getintprop_default(struct device_node *np, const char *name, int def)
{
struct property *prop;
@@ -198,36 +59,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
}
EXPORT_SYMBOL(of_getintprop_default);
-int of_n_addr_cells(struct device_node *np)
-{
- const int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#address-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #address-cells property for the root node, default to 2 */
- return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
- const int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#size-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #size-cells property for the root node, default to 1 */
- return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
int of_set_property(struct device_node *dp, const char *name, void *val, int len)
{
struct property **prevp;
@@ -1808,13 +1639,67 @@ static void __init of_fill_in_cpu_data(void)
#ifdef CONFIG_SMP
cpu_set(cpuid, cpu_present_map);
- cpu_set(cpuid, phys_cpu_present_map);
+ cpu_set(cpuid, cpu_possible_map);
#endif
}
smp_fill_in_sib_core_maps();
}
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+static void __init of_console_init(void)
+{
+ char *msg = "OF stdout device is: %s\n";
+ struct device_node *dp;
+ const char *type;
+ phandle node;
+
+ of_console_path = prom_early_alloc(256);
+ if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
+ prom_printf("Cannot obtain path of stdout.\n");
+ prom_halt();
+ }
+ of_console_options = strrchr(of_console_path, ':');
+ if (of_console_options) {
+ of_console_options++;
+ if (*of_console_options == '\0')
+ of_console_options = NULL;
+ }
+
+ node = prom_inst2pkg(prom_stdout);
+ if (!node) {
+ prom_printf("Cannot resolve stdout node from "
+ "instance %08x.\n", prom_stdout);
+ prom_halt();
+ }
+
+ dp = of_find_node_by_phandle(node);
+ type = of_get_property(dp, "device_type", NULL);
+ if (!type) {
+ prom_printf("Console stdout lacks device_type property.\n");
+ prom_halt();
+ }
+
+ if (strcmp(type, "display") && strcmp(type, "serial")) {
+ prom_printf("Console device_type is neither display "
+ "nor serial.\n");
+ prom_halt();
+ }
+
+ of_console_device = dp;
+
+ prom_printf(msg, of_console_path);
+ printk(msg, of_console_path);
+}
+
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
@@ -1827,6 +1712,8 @@ void __init prom_build_devicetree(void)
allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node),
&nextp);
+ of_console_init();
+
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 7490cc670a53..0f5be828ee92 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -133,33 +133,6 @@ static void __init process_switch(char c)
}
}
-static void __init process_console(char *commands)
-{
- serial_console = 0;
- commands += 8;
- /* Linux-style serial */
- if (!strncmp(commands, "ttyS", 4))
- serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
- else if (!strncmp(commands, "tty", 3)) {
- char c = *(commands + 3);
- /* Solaris-style serial */
- if (c == 'a' || c == 'b') {
- serial_console = c - 'a' + 1;
- prom_printf ("Using /dev/tty%c as console.\n", c);
- }
- /* else Linux-style fbcon, not serial */
- }
-#if defined(CONFIG_PROM_CONSOLE)
- if (!strncmp(commands, "prom", 4)) {
- char *p;
-
- for (p = commands - 8; *p && *p != ' '; p++)
- *p = ' ';
- conswitchp = &prom_con;
- }
-#endif
-}
-
static void __init boot_flags_init(char *commands)
{
while (*commands) {
@@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands)
process_switch(*commands++);
continue;
}
- if (!strncmp(commands, "console=", 8)) {
- process_console(commands);
- } else if (!strncmp(commands, "mem=", 4)) {
+ if (!strncmp(commands, "mem=", 4)) {
/*
* "mem=XXX[kKmM]" overrides the PROM-reported
* memory size.
@@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p)
paging_init();
}
-static int __init set_preferred_console(void)
-{
- int idev, odev;
-
- /* The user has requested a console so this is already set up. */
- if (serial_console >= 0)
- return -EBUSY;
-
- idev = prom_query_input_device();
- odev = prom_query_output_device();
- if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
- serial_console = 0;
- } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
- serial_console = 1;
- } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
- serial_console = 2;
- } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
- serial_console = 3;
- } else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
- /* sunhv_console_init() doesn't check the serial_console
- * value anyways...
- */
- serial_console = 4;
- return add_preferred_console("ttyHV", 0, NULL);
- } else {
- prom_printf("Inconsistent console: "
- "input %d, output %d\n",
- idev, odev);
- prom_halt();
- }
-
- if (serial_console)
- return add_preferred_console("ttyS", serial_console - 1, NULL);
-
- return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
/* BUFFER is PAGE_SIZE bytes long. */
extern char *sparc_cpu_type;
@@ -442,7 +375,6 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
"D$ parity tl1\t: %u\n"
"I$ parity tl1\t: %u\n"
#ifndef CONFIG_SMP
- "Cpu0Bogo\t: %lu.%02lu\n"
"Cpu0ClkTck\t: %016lx\n"
#endif
,
@@ -457,9 +389,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
dcache_parity_tl1_occurred,
icache_parity_tl1_occurred
#ifndef CONFIG_SMP
- , cpu_data(0).udelay_val/(500000/HZ),
- (cpu_data(0).udelay_val/(5000/HZ)) % 100,
- cpu_data(0).clock_tick
+ , cpu_data(0).clock_tick
#endif
);
#ifdef CONFIG_SMP
@@ -511,5 +441,4 @@ void sun_do_break(void)
prom_cmdline();
}
-int serial_console = -1;
int stop_a_enabled = 1;
diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c
index 203e87301005..fb13775b3682 100644
--- a/arch/sparc64/kernel/signal.c
+++ b/arch/sparc64/kernel/signal.c
@@ -289,9 +289,7 @@ void do_rt_sigreturn(struct pt_regs *regs)
struct rt_signal_frame __user *sf;
unsigned long tpc, tnpc, tstate;
__siginfo_fpu_t __user *fpu_save;
- mm_segment_t old_fs;
sigset_t set;
- stack_t st;
int err;
/* Always make any pending restarted system calls return -EINTR */
@@ -327,20 +325,13 @@ void do_rt_sigreturn(struct pt_regs *regs)
err |= restore_fpu_state(regs, &sf->fpu_state);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
- err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t));
-
+ err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
+
if (err)
goto segv;
-
+
regs->tpc = tpc;
regs->tnpc = tnpc;
-
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
- set_fs(old_fs);
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 40e40f968d61..b448d33321c6 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -1,6 +1,6 @@
/* smp.c: Sparc64 SMP support.
*
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -28,6 +28,8 @@
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
#include <asm/cpudata.h>
+#include <asm/hvtramp.h>
+#include <asm/io.h>
#include <asm/irq.h>
#include <asm/irq_regs.h>
@@ -41,22 +43,26 @@
#include <asm/sections.h>
#include <asm/prom.h>
#include <asm/mdesc.h>
+#include <asm/ldc.h>
+#include <asm/hypervisor.h>
extern void calibrate_delay(void);
int sparc64_multi_core __read_mostly;
-/* Please don't make this stuff initdata!!! --DaveM */
-unsigned char boot_cpu_id;
-
+cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE;
cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
-cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = CPU_MASK_NONE };
cpumask_t cpu_core_map[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = CPU_MASK_NONE };
+
+EXPORT_SYMBOL(cpu_possible_map);
+EXPORT_SYMBOL(cpu_online_map);
+EXPORT_SYMBOL(cpu_sibling_map);
+EXPORT_SYMBOL(cpu_core_map);
+
static cpumask_t smp_commenced_mask;
-static cpumask_t cpu_callout_map;
void smp_info(struct seq_file *m)
{
@@ -73,18 +79,17 @@ void smp_bogo(struct seq_file *m)
for_each_online_cpu(i)
seq_printf(m,
- "Cpu%dBogo\t: %lu.%02lu\n"
"Cpu%dClkTck\t: %016lx\n",
- i, cpu_data(i).udelay_val / (500000/HZ),
- (cpu_data(i).udelay_val / (5000/HZ)) % 100,
i, cpu_data(i).clock_tick);
}
+static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
+
extern void setup_sparc64_timer(void);
static volatile unsigned long callin_flag = 0;
-void __init smp_callin(void)
+void __devinit smp_callin(void)
{
int cpuid = hard_smp_processor_id();
@@ -102,8 +107,6 @@ void __init smp_callin(void)
local_irq_enable();
- calibrate_delay();
- cpu_data(cpuid).udelay_val = loops_per_jiffy;
callin_flag = 1;
__asm__ __volatile__("membar #Sync\n\t"
"flush %%g6" : : : "memory");
@@ -120,7 +123,9 @@ void __init smp_callin(void)
while (!cpu_isset(cpuid, smp_commenced_mask))
rmb();
+ spin_lock(&call_lock);
cpu_set(cpuid, cpu_online_map);
+ spin_unlock(&call_lock);
/* idle thread is expected to have preempt disabled */
preempt_disable();
@@ -268,6 +273,67 @@ static void smp_synchronize_one_tick(int cpu)
spin_unlock_irqrestore(&itc_sync_lock, flags);
}
+#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
+/* XXX Put this in some common place. XXX */
+static unsigned long kimage_addr_to_ra(void *p)
+{
+ unsigned long val = (unsigned long) p;
+
+ return kern_base + (val - KERNBASE);
+}
+
+static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
+{
+ extern unsigned long sparc64_ttable_tl0;
+ extern unsigned long kern_locked_tte_data;
+ extern int bigkernel;
+ struct hvtramp_descr *hdesc;
+ unsigned long trampoline_ra;
+ struct trap_per_cpu *tb;
+ u64 tte_vaddr, tte_data;
+ unsigned long hv_err;
+
+ hdesc = kzalloc(sizeof(*hdesc), GFP_KERNEL);
+ if (!hdesc) {
+ printk(KERN_ERR "ldom_startcpu_cpuid: Cannot allocate "
+ "hvtramp_descr.\n");
+ return;
+ }
+
+ hdesc->cpu = cpu;
+ hdesc->num_mappings = (bigkernel ? 2 : 1);
+
+ tb = &trap_block[cpu];
+ tb->hdesc = hdesc;
+
+ hdesc->fault_info_va = (unsigned long) &tb->fault_info;
+ hdesc->fault_info_pa = kimage_addr_to_ra(&tb->fault_info);
+
+ hdesc->thread_reg = thread_reg;
+
+ tte_vaddr = (unsigned long) KERNBASE;
+ tte_data = kern_locked_tte_data;
+
+ hdesc->maps[0].vaddr = tte_vaddr;
+ hdesc->maps[0].tte = tte_data;
+ if (bigkernel) {
+ tte_vaddr += 0x400000;
+ tte_data += 0x400000;
+ hdesc->maps[1].vaddr = tte_vaddr;
+ hdesc->maps[1].tte = tte_data;
+ }
+
+ trampoline_ra = kimage_addr_to_ra(hv_cpu_startup);
+
+ hv_err = sun4v_cpu_start(cpu, trampoline_ra,
+ kimage_addr_to_ra(&sparc64_ttable_tl0),
+ __pa(hdesc));
+ if (hv_err)
+ printk(KERN_ERR "ldom_startcpu_cpuid: sun4v_cpu_start() "
+ "gives error %lu\n", hv_err);
+}
+#endif
+
extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load);
extern unsigned long sparc64_cpu_startup;
@@ -280,6 +346,7 @@ static struct thread_info *cpu_new_thread = NULL;
static int __devinit smp_boot_one_cpu(unsigned int cpu)
{
+ struct trap_per_cpu *tb = &trap_block[cpu];
unsigned long entry =
(unsigned long)(&sparc64_cpu_startup);
unsigned long cookie =
@@ -290,20 +357,25 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
p = fork_idle(cpu);
callin_flag = 0;
cpu_new_thread = task_thread_info(p);
- cpu_set(cpu, cpu_callout_map);
if (tlb_type == hypervisor) {
/* Alloc the mondo queues, cpu will load them. */
sun4v_init_mondo_queues(0, cpu, 1, 0);
- prom_startcpu_cpuid(cpu, entry, cookie);
+#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
+ if (ldom_domaining_enabled)
+ ldom_startcpu_cpuid(cpu,
+ (unsigned long) cpu_new_thread);
+ else
+#endif
+ prom_startcpu_cpuid(cpu, entry, cookie);
} else {
struct device_node *dp = of_find_node_by_cpuid(cpu);
prom_startcpu(dp->node, entry, cookie);
}
- for (timeout = 0; timeout < 5000000; timeout++) {
+ for (timeout = 0; timeout < 50000; timeout++) {
if (callin_flag)
break;
udelay(100);
@@ -313,11 +385,15 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
ret = 0;
} else {
printk("Processor %d is stuck.\n", cpu);
- cpu_clear(cpu, cpu_callout_map);
ret = -ENODEV;
}
cpu_new_thread = NULL;
+ if (tb->hdesc) {
+ kfree(tb->hdesc);
+ tb->hdesc = NULL;
+ }
+
return ret;
}
@@ -720,7 +796,6 @@ struct call_data_struct {
int wait;
};
-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock);
static struct call_data_struct *call_data;
extern unsigned long xcall_call_function;
@@ -1152,34 +1227,14 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
preempt_enable();
}
-void __init smp_tick_init(void)
-{
- boot_cpu_id = hard_smp_processor_id();
-}
-
/* /proc/profile writes can call this, don't __init it please. */
int setup_profiling_timer(unsigned int multiplier)
{
return -EINVAL;
}
-/* Constrain the number of cpus to max_cpus. */
void __init smp_prepare_cpus(unsigned int max_cpus)
{
- int i;
-
- if (num_possible_cpus() > max_cpus) {
- for_each_possible_cpu(i) {
- if (i != boot_cpu_id) {
- cpu_clear(i, phys_cpu_present_map);
- cpu_clear(i, cpu_present_map);
- if (num_possible_cpus() <= max_cpus)
- break;
- }
- }
- }
-
- cpu_data(boot_cpu_id).udelay_val = loops_per_jiffy;
}
void __devinit smp_prepare_boot_cpu(void)
@@ -1190,30 +1245,32 @@ void __devinit smp_fill_in_sib_core_maps(void)
{
unsigned int i;
- for_each_possible_cpu(i) {
+ for_each_present_cpu(i) {
unsigned int j;
+ cpus_clear(cpu_core_map[i]);
if (cpu_data(i).core_id == 0) {
cpu_set(i, cpu_core_map[i]);
continue;
}
- for_each_possible_cpu(j) {
+ for_each_present_cpu(j) {
if (cpu_data(i).core_id ==
cpu_data(j).core_id)
cpu_set(j, cpu_core_map[i]);
}
}
- for_each_possible_cpu(i) {
+ for_each_present_cpu(i) {
unsigned int j;
+ cpus_clear(cpu_sibling_map[i]);
if (cpu_data(i).proc_id == -1) {
cpu_set(i, cpu_sibling_map[i]);
continue;
}
- for_each_possible_cpu(j) {
+ for_each_present_cpu(j) {
if (cpu_data(i).proc_id ==
cpu_data(j).proc_id)
cpu_set(j, cpu_sibling_map[i]);
@@ -1242,18 +1299,112 @@ int __cpuinit __cpu_up(unsigned int cpu)
return ret;
}
-void __init smp_cpus_done(unsigned int max_cpus)
+#ifdef CONFIG_HOTPLUG_CPU
+void cpu_play_dead(void)
+{
+ int cpu = smp_processor_id();
+ unsigned long pstate;
+
+ idle_task_exit();
+
+ if (tlb_type == hypervisor) {
+ struct trap_per_cpu *tb = &trap_block[cpu];
+
+ sun4v_cpu_qconf(HV_CPU_QUEUE_CPU_MONDO,
+ tb->cpu_mondo_pa, 0);
+ sun4v_cpu_qconf(HV_CPU_QUEUE_DEVICE_MONDO,
+ tb->dev_mondo_pa, 0);
+ sun4v_cpu_qconf(HV_CPU_QUEUE_RES_ERROR,
+ tb->resum_mondo_pa, 0);
+ sun4v_cpu_qconf(HV_CPU_QUEUE_NONRES_ERROR,
+ tb->nonresum_mondo_pa, 0);
+ }
+
+ cpu_clear(cpu, smp_commenced_mask);
+ membar_safe("#Sync");
+
+ local_irq_disable();
+
+ __asm__ __volatile__(
+ "rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate"
+ : "=r" (pstate)
+ : "i" (PSTATE_IE));
+
+ while (1)
+ barrier();
+}
+
+int __cpu_disable(void)
{
- unsigned long bogosum = 0;
+ int cpu = smp_processor_id();
+ cpuinfo_sparc *c;
int i;
- for_each_online_cpu(i)
- bogosum += cpu_data(i).udelay_val;
- printk("Total of %ld processors activated "
- "(%lu.%02lu BogoMIPS).\n",
- (long) num_online_cpus(),
- bogosum/(500000/HZ),
- (bogosum/(5000/HZ))%100);
+ for_each_cpu_mask(i, cpu_core_map[cpu])
+ cpu_clear(cpu, cpu_core_map[i]);
+ cpus_clear(cpu_core_map[cpu]);
+
+ for_each_cpu_mask(i, cpu_sibling_map[cpu])
+ cpu_clear(cpu, cpu_sibling_map[i]);
+ cpus_clear(cpu_sibling_map[cpu]);
+
+ c = &cpu_data(cpu);
+
+ c->core_id = 0;
+ c->proc_id = -1;
+
+ spin_lock(&call_lock);
+ cpu_clear(cpu, cpu_online_map);
+ spin_unlock(&call_lock);
+
+ smp_wmb();
+
+ /* Make sure no interrupts point to this cpu. */
+ fixup_irqs();
+
+ local_irq_enable();
+ mdelay(1);
+ local_irq_disable();
+
+ return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ smp_rmb();
+ if (!cpu_isset(cpu, smp_commenced_mask))
+ break;
+ msleep(100);
+ }
+ if (cpu_isset(cpu, smp_commenced_mask)) {
+ printk(KERN_ERR "CPU %u didn't die...\n", cpu);
+ } else {
+#if defined(CONFIG_SUN_LDOMS)
+ unsigned long hv_err;
+ int limit = 100;
+
+ do {
+ hv_err = sun4v_cpu_stop(cpu);
+ if (hv_err == HV_EOK) {
+ cpu_clear(cpu, cpu_present_map);
+ break;
+ }
+ } while (--limit > 0);
+ if (limit <= 0) {
+ printk(KERN_ERR "sun4v_cpu_stop() fails err=%lu\n",
+ hv_err);
+ }
+#endif
+ }
+}
+#endif
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
}
void smp_send_reschedule(int cpu)
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 6fa761612899..d270c2f0be0f 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -1,7 +1,6 @@
-/* $Id: sparc64_ksyms.c,v 1.121 2002/02/09 19:49:31 davem Exp $
- * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
+/* arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
*
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz)
*/
@@ -28,7 +27,6 @@
#include <net/compat.h>
#include <asm/oplib.h>
-#include <asm/delay.h>
#include <asm/system.h>
#include <asm/auxio.h>
#include <asm/pgtable.h>
@@ -124,10 +122,6 @@ EXPORT_SYMBOL(__write_lock);
EXPORT_SYMBOL(__write_unlock);
EXPORT_SYMBOL(__write_trylock);
-/* CPU online map and active count. */
-EXPORT_SYMBOL(cpu_online_map);
-EXPORT_SYMBOL(phys_cpu_present_map);
-
EXPORT_SYMBOL(smp_call_function);
#endif /* CONFIG_SMP */
@@ -286,6 +280,7 @@ EXPORT_SYMBOL(sys_getgid);
EXPORT_SYMBOL(svr4_getcontext);
EXPORT_SYMBOL(svr4_setcontext);
EXPORT_SYMBOL(compat_sys_ioctl);
+EXPORT_SYMBOL(sys_ioctl);
EXPORT_SYMBOL(sparc32_open);
#endif
@@ -330,19 +325,12 @@ EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(strncmp);
-/* Delay routines. */
-EXPORT_SYMBOL(__udelay);
-EXPORT_SYMBOL(__ndelay);
-EXPORT_SYMBOL(__const_udelay);
-EXPORT_SYMBOL(__delay);
-
void VISenter(void);
/* RAID code needs this */
EXPORT_SYMBOL(VISenter);
/* for input/keybdev */
EXPORT_SYMBOL(sun_do_break);
-EXPORT_SYMBOL(serial_console);
EXPORT_SYMBOL(stop_a_enabled);
#ifdef CONFIG_DEBUG_BUGVERBOSE
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index abd83129b2e7..e8dce90d05d4 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,8 +1,7 @@
-/* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
- * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
+/* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
*
* These routines maintain argument size conversion between 32bit and 64bit
* environment.
@@ -1028,3 +1027,10 @@ long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_lo
(nb_high << 32) | nb_low,
flags);
}
+
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+ u32 lenhi, u32 lenlo)
+{
+ return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+ ((loff_t)lenhi << 32) | lenlo);
+}
diff --git a/arch/sparc64/kernel/sysfs.c b/arch/sparc64/kernel/sysfs.c
index cdb1477af89f..52816c7be0b9 100644
--- a/arch/sparc64/kernel/sysfs.c
+++ b/arch/sparc64/kernel/sysfs.c
@@ -193,7 +193,6 @@ static ssize_t show_##NAME(struct sys_device *dev, char *buf) \
}
SHOW_CPUDATA_ULONG_NAME(clock_tick, clock_tick);
-SHOW_CPUDATA_ULONG_NAME(udelay_val, udelay_val);
SHOW_CPUDATA_UINT_NAME(l1_dcache_size, dcache_size);
SHOW_CPUDATA_UINT_NAME(l1_dcache_line_size, dcache_line_size);
SHOW_CPUDATA_UINT_NAME(l1_icache_size, icache_size);
@@ -203,7 +202,6 @@ SHOW_CPUDATA_UINT_NAME(l2_cache_line_size, ecache_line_size);
static struct sysdev_attribute cpu_core_attrs[] = {
_SYSDEV_ATTR(clock_tick, 0444, show_clock_tick, NULL),
- _SYSDEV_ATTR(udelay_val, 0444, show_udelay_val, NULL),
_SYSDEV_ATTR(l1_dcache_size, 0444, show_l1_dcache_size, NULL),
_SYSDEV_ATTR(l1_dcache_line_size, 0444, show_l1_dcache_line_size, NULL),
_SYSDEV_ATTR(l1_icache_size, 0444, show_l1_icache_size, NULL),
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 8765e32155a0..06d10907d8ce 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.81 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
- * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1996, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*
* Based upon preliminary work which is:
@@ -81,7 +80,7 @@ sys_call_table32:
.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
.word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd
+/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
#endif /* CONFIG_COMPAT */
@@ -153,7 +152,7 @@ sys_call_table:
.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
.word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -272,6 +271,6 @@ sunos_sys_table:
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys
/*310*/ .word sunos_nosys, sunos_nosys, sunos_nosys
- .word sunos_nosys
+ .word sunos_nosys, sunos_nosys
#endif
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index a31a0439244f..49063ca2efcd 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -403,58 +403,9 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = {
static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
-#define TICK_SIZE (tick_nsec / 1000)
-
-#define USEC_AFTER 500000
-#define USEC_BEFORE 500000
-
-static void sync_cmos_clock(unsigned long dummy);
-
-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-
-static void sync_cmos_clock(unsigned long dummy)
+int update_persistent_clock(struct timespec now)
{
- struct timeval now, next;
- int fail = 1;
-
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- * This code is run on a timer. If the clock is set, that timer
- * may not expire at the correct time. Thus, we adjust...
- */
- if (!ntp_synced())
- /*
- * Not synced, exit, do not restart a timer (if one is
- * running, let it run out).
- */
- return;
-
- do_gettimeofday(&now);
- if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
- now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
- fail = set_rtc_mmss(now.tv_sec);
-
- next.tv_usec = USEC_AFTER - now.tv_usec;
- if (next.tv_usec <= 0)
- next.tv_usec += USEC_PER_SEC;
-
- if (!fail)
- next.tv_sec = 659;
- else
- next.tv_sec = 0;
-
- if (next.tv_usec >= USEC_PER_SEC) {
- next.tv_sec++;
- next.tv_usec -= USEC_PER_SEC;
- }
- mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
-}
-
-void notify_arch_cmos_timer(void)
-{
- mod_timer(&sync_cmos_timer, jiffies + 1);
+ return set_rtc_mmss(now.tv_sec);
}
/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
@@ -835,7 +786,7 @@ static int __init clock_init(void)
return 0;
}
- return of_register_driver(&clock_driver, &of_bus_type);
+ return of_register_driver(&clock_driver, &of_platform_bus_type);
}
/* Must be after subsys_initcall() so that busses are probed. Must
@@ -849,9 +800,6 @@ static unsigned long sparc64_init_timers(void)
{
struct device_node *dp;
unsigned long clock;
-#ifdef CONFIG_SMP
- extern void smp_tick_init(void);
-#endif
dp = of_find_node_by_path("/");
if (tlb_type == spitfire) {
@@ -874,10 +822,6 @@ static unsigned long sparc64_init_timers(void)
clock = of_getintprop_default(dp, "stick-frequency", 0);
}
-#ifdef CONFIG_SMP
- smp_tick_init();
-#endif
-
return clock;
}
@@ -938,6 +882,7 @@ static void sparc64_timer_setup(enum clock_event_mode mode,
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_RESUME:
break;
case CLOCK_EVT_MODE_SHUTDOWN:
@@ -1038,10 +983,31 @@ static void __init setup_clockevent_multiplier(unsigned long hz)
sparc64_clockevent.mult = mult;
}
+static unsigned long tb_ticks_per_usec __read_mostly;
+
+void __delay(unsigned long loops)
+{
+ unsigned long bclock, now;
+
+ bclock = tick_ops->get_tick();
+ do {
+ now = tick_ops->get_tick();
+ } while ((now-bclock) < loops);
+}
+EXPORT_SYMBOL(__delay);
+
+void udelay(unsigned long usecs)
+{
+ __delay(tb_ticks_per_usec * usecs);
+}
+EXPORT_SYMBOL(udelay);
+
void __init time_init(void)
{
unsigned long clock = sparc64_init_timers();
+ tb_ticks_per_usec = clock / USEC_PER_SEC;
+
timer_ticks_per_nsec_quotient =
clocksource_hz2mult(clock, SPARC64_NSEC_PER_CYC_SHIFT);
@@ -1420,6 +1386,78 @@ static int bq4802_set_rtc_time(struct rtc_time *time)
return 0;
}
+
+static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned char ctrl;
+
+ rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+ rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+ rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+ rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+ rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+ rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+ rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
+
+ ctrl = CMOS_READ(RTC_CONTROL);
+ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BCD_TO_BIN(rtc_tm->tm_sec);
+ BCD_TO_BIN(rtc_tm->tm_min);
+ BCD_TO_BIN(rtc_tm->tm_hour);
+ BCD_TO_BIN(rtc_tm->tm_mday);
+ BCD_TO_BIN(rtc_tm->tm_mon);
+ BCD_TO_BIN(rtc_tm->tm_year);
+ BCD_TO_BIN(rtc_tm->tm_wday);
+ }
+
+ if (rtc_tm->tm_year <= 69)
+ rtc_tm->tm_year += 100;
+
+ rtc_tm->tm_mon--;
+}
+
+static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned char mon, day, hrs, min, sec;
+ unsigned char save_control, save_freq_select;
+ unsigned int yrs;
+
+ yrs = rtc_tm->tm_year;
+ mon = rtc_tm->tm_mon + 1;
+ day = rtc_tm->tm_mday;
+ hrs = rtc_tm->tm_hour;
+ min = rtc_tm->tm_min;
+ sec = rtc_tm->tm_sec;
+
+ if (yrs >= 100)
+ yrs -= 100;
+
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(sec);
+ BIN_TO_BCD(min);
+ BIN_TO_BCD(hrs);
+ BIN_TO_BCD(day);
+ BIN_TO_BCD(mon);
+ BIN_TO_BCD(yrs);
+ }
+
+ save_control = CMOS_READ(RTC_CONTROL);
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ CMOS_WRITE(yrs, RTC_YEAR);
+ CMOS_WRITE(mon, RTC_MONTH);
+ CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+ CMOS_WRITE(hrs, RTC_HOURS);
+ CMOS_WRITE(min, RTC_MINUTES);
+ CMOS_WRITE(sec, RTC_SECONDS);
+
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return 0;
+}
#endif /* CONFIG_PCI */
struct mini_rtc_ops {
@@ -1442,6 +1480,11 @@ static struct mini_rtc_ops bq4802_rtc_ops = {
.get_rtc_time = bq4802_get_rtc_time,
.set_rtc_time = bq4802_set_rtc_time,
};
+
+static struct mini_rtc_ops cmos_rtc_ops = {
+ .get_rtc_time = cmos_get_rtc_time,
+ .set_rtc_time = cmos_set_rtc_time,
+};
#endif /* CONFIG_PCI */
static struct mini_rtc_ops *mini_rtc_ops;
@@ -1569,6 +1612,8 @@ static int __init rtc_mini_init(void)
#ifdef CONFIG_PCI
else if (bq4802_regs)
mini_rtc_ops = &bq4802_rtc_ops;
+ else if (ds1287_regs)
+ mini_rtc_ops = &cmos_rtc_ops;
#endif /* CONFIG_PCI */
else
return -ENODEV;
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 00a9e3286c83..6ef2d299fb10 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -2225,6 +2225,7 @@ void die_if_kernel(char *str, struct pt_regs *regs)
notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV);
__asm__ __volatile__("flushw");
__show_regs(regs);
+ add_taint(TAINT_DIE);
if (regs->tstate & TSTATE_PRIV) {
struct reg_window *rw = (struct reg_window *)
(regs->u_regs[UREG_FP] + STACK_BIAS);
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
new file mode 100644
index 000000000000..3685daf5157f
--- /dev/null
+++ b/arch/sparc64/kernel/vio.c
@@ -0,0 +1,443 @@
+/* vio.c: Virtual I/O channel devices probing infrastructure.
+ *
+ * Copyright (c) 2003-2005 IBM Corp.
+ * Dave Engebretsen engebret@us.ibm.com
+ * Santiago Leon santil@us.ibm.com
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ * Stephen Rothwell
+ *
+ * Adapted to sparc64 by David S. Miller davem@davemloft.net
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+
+#include <asm/mdesc.h>
+#include <asm/vio.h>
+
+static inline int find_in_proplist(const char *list, const char *match,
+ int len)
+{
+ while (len > 0) {
+ int l;
+
+ if (!strcmp(list, match))
+ return 1;
+ l = strlen(list) + 1;
+ list += l;
+ len -= l;
+ }
+ return 0;
+}
+
+static const struct vio_device_id *vio_match_device(
+ const struct vio_device_id *matches,
+ const struct vio_dev *dev)
+{
+ const char *type, *compat;
+ int len;
+
+ type = dev->type;
+ compat = dev->compat;
+ len = dev->compat_len;
+
+ while (matches->type[0] || matches->compat[0]) {
+ int match = 1;
+ if (matches->type[0])
+ match &= !strcmp(matches->type, type);
+
+ if (matches->compat[0]) {
+ match &= len &&
+ find_in_proplist(compat, matches->compat, len);
+ }
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+
+static int vio_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct vio_dev *vio_dev = to_vio_dev(dev);
+ struct vio_driver *vio_drv = to_vio_driver(drv);
+ const struct vio_device_id *matches = vio_drv->id_table;
+
+ if (!matches)
+ return 0;
+
+ return vio_match_device(matches, vio_dev) != NULL;
+}
+
+static int vio_device_probe(struct device *dev)
+{
+ struct vio_dev *vdev = to_vio_dev(dev);
+ struct vio_driver *drv = to_vio_driver(dev->driver);
+ const struct vio_device_id *id;
+ int error = -ENODEV;
+
+ if (drv->probe) {
+ id = vio_match_device(drv->id_table, vdev);
+ if (id)
+ error = drv->probe(vdev, id);
+ }
+
+ return error;
+}
+
+static int vio_device_remove(struct device *dev)
+{
+ struct vio_dev *vdev = to_vio_dev(dev);
+ struct vio_driver *drv = to_vio_driver(dev->driver);
+
+ if (drv->remove)
+ return drv->remove(vdev);
+
+ return 1;
+}
+
+static ssize_t devspec_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vio_dev *vdev = to_vio_dev(dev);
+ const char *str = "none";
+
+ if (!strcmp(vdev->type, "vnet-port"))
+ str = "vnet";
+ else if (!strcmp(vdev->type, "vdc-port"))
+ str = "vdisk";
+
+ return sprintf(buf, "%s\n", str);
+}
+
+static ssize_t type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vio_dev *vdev = to_vio_dev(dev);
+ return sprintf(buf, "%s\n", vdev->type);
+}
+
+static struct device_attribute vio_dev_attrs[] = {
+ __ATTR_RO(devspec),
+ __ATTR_RO(type),
+ __ATTR_NULL
+};
+
+static struct bus_type vio_bus_type = {
+ .name = "vio",
+ .dev_attrs = vio_dev_attrs,
+ .match = vio_bus_match,
+ .probe = vio_device_probe,
+ .remove = vio_device_remove,
+};
+
+int vio_register_driver(struct vio_driver *viodrv)
+{
+ viodrv->driver.bus = &vio_bus_type;
+
+ return driver_register(&viodrv->driver);
+}
+EXPORT_SYMBOL(vio_register_driver);
+
+void vio_unregister_driver(struct vio_driver *viodrv)
+{
+ driver_unregister(&viodrv->driver);
+}
+EXPORT_SYMBOL(vio_unregister_driver);
+
+static void __devinit vio_dev_release(struct device *dev)
+{
+ kfree(to_vio_dev(dev));
+}
+
+static ssize_t
+show_pciobppath_attr(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vio_dev *vdev;
+ struct device_node *dp;
+
+ vdev = to_vio_dev(dev);
+ dp = vdev->dp;
+
+ return snprintf (buf, PAGE_SIZE, "%s\n", dp->full_name);
+}
+
+static DEVICE_ATTR(obppath, S_IRUSR | S_IRGRP | S_IROTH,
+ show_pciobppath_attr, NULL);
+
+struct device_node *cdev_node;
+
+static struct vio_dev *root_vdev;
+static u64 cdev_cfg_handle;
+
+static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
+ struct vio_dev *vdev)
+{
+ u64 a;
+
+ mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
+ const u64 *chan_id;
+ const u64 *irq;
+ u64 target;
+
+ target = mdesc_arc_target(hp, a);
+
+ irq = mdesc_get_property(hp, target, "tx-ino", NULL);
+ if (irq)
+ vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
+
+ irq = mdesc_get_property(hp, target, "rx-ino", NULL);
+ if (irq)
+ vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
+
+ chan_id = mdesc_get_property(hp, target, "id", NULL);
+ if (chan_id)
+ vdev->channel_id = *chan_id;
+ }
+}
+
+static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
+ struct device *parent)
+{
+ const char *type, *compat, *bus_id_name;
+ struct device_node *dp;
+ struct vio_dev *vdev;
+ int err, tlen, clen;
+ const u64 *id, *cfg_handle;
+ u64 a;
+
+ type = mdesc_get_property(hp, mp, "device-type", &tlen);
+ if (!type) {
+ type = mdesc_get_property(hp, mp, "name", &tlen);
+ if (!type) {
+ type = mdesc_node_name(hp, mp);
+ tlen = strlen(type) + 1;
+ }
+ }
+ if (tlen > VIO_MAX_TYPE_LEN) {
+ printk(KERN_ERR "VIO: Type string [%s] is too long.\n",
+ type);
+ return NULL;
+ }
+
+ id = mdesc_get_property(hp, mp, "id", NULL);
+
+ cfg_handle = NULL;
+ mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+ u64 target;
+
+ target = mdesc_arc_target(hp, a);
+ cfg_handle = mdesc_get_property(hp, target,
+ "cfg-handle", NULL);
+ if (cfg_handle)
+ break;
+ }
+
+ bus_id_name = type;
+ if (!strcmp(type, "domain-services-port"))
+ bus_id_name = "ds";
+
+ if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
+ printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
+ bus_id_name);
+ return NULL;
+ }
+
+ compat = mdesc_get_property(hp, mp, "device-type", &clen);
+ if (!compat) {
+ clen = 0;
+ } else if (clen > VIO_MAX_COMPAT_LEN) {
+ printk(KERN_ERR "VIO: Compat len %d for [%s] is too long.\n",
+ clen, type);
+ return NULL;
+ }
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev) {
+ printk(KERN_ERR "VIO: Could not allocate vio_dev\n");
+ return NULL;
+ }
+
+ vdev->mp = mp;
+ memcpy(vdev->type, type, tlen);
+ if (compat)
+ memcpy(vdev->compat, compat, clen);
+ else
+ memset(vdev->compat, 0, sizeof(vdev->compat));
+ vdev->compat_len = clen;
+
+ vdev->channel_id = ~0UL;
+ vdev->tx_irq = ~0;
+ vdev->rx_irq = ~0;
+
+ vio_fill_channel_info(hp, mp, vdev);
+
+ if (!id) {
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
+ bus_id_name);
+ vdev->dev_no = ~(u64)0;
+ } else if (!cfg_handle) {
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
+ bus_id_name, *id);
+ vdev->dev_no = *id;
+ } else {
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu-%lu",
+ bus_id_name, *cfg_handle, *id);
+ vdev->dev_no = *cfg_handle;
+ }
+
+ vdev->dev.parent = parent;
+ vdev->dev.bus = &vio_bus_type;
+ vdev->dev.release = vio_dev_release;
+
+ if (parent == NULL) {
+ dp = cdev_node;
+ } else if (to_vio_dev(parent) == root_vdev) {
+ dp = of_get_next_child(cdev_node, NULL);
+ while (dp) {
+ if (!strcmp(dp->type, type))
+ break;
+
+ dp = of_get_next_child(cdev_node, dp);
+ }
+ } else {
+ dp = to_vio_dev(parent)->dp;
+ }
+ vdev->dp = dp;
+
+ printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
+
+ err = device_register(&vdev->dev);
+ if (err) {
+ printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
+ vdev->dev.bus_id, err);
+ kfree(vdev);
+ return NULL;
+ }
+ if (vdev->dp)
+ err = sysfs_create_file(&vdev->dev.kobj,
+ &dev_attr_obppath.attr);
+
+ return vdev;
+}
+
+static void vio_add(struct mdesc_handle *hp, u64 node)
+{
+ (void) vio_create_one(hp, node, &root_vdev->dev);
+}
+
+static int vio_md_node_match(struct device *dev, void *arg)
+{
+ struct vio_dev *vdev = to_vio_dev(dev);
+
+ if (vdev->mp == (u64) arg)
+ return 1;
+
+ return 0;
+}
+
+static void vio_remove(struct mdesc_handle *hp, u64 node)
+{
+ struct device *dev;
+
+ dev = device_find_child(&root_vdev->dev, (void *) node,
+ vio_md_node_match);
+ if (dev) {
+ printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
+
+ device_unregister(dev);
+ }
+}
+
+static struct mdesc_notifier_client vio_device_notifier = {
+ .add = vio_add,
+ .remove = vio_remove,
+ .node_name = "virtual-device-port",
+};
+
+static struct mdesc_notifier_client vio_ds_notifier = {
+ .add = vio_add,
+ .remove = vio_remove,
+ .node_name = "domain-services-port",
+};
+
+const char *channel_devices_node = "channel-devices";
+const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
+const char *cfg_handle_prop = "cfg-handle";
+
+static int __init vio_init(void)
+{
+ struct mdesc_handle *hp;
+ const char *compat;
+ const u64 *cfg_handle;
+ int err, len;
+ u64 root;
+
+ err = bus_register(&vio_bus_type);
+ if (err) {
+ printk(KERN_ERR "VIO: Could not register bus type err=%d\n",
+ err);
+ return err;
+ }
+
+ hp = mdesc_grab();
+ if (!hp)
+ return 0;
+
+ root = mdesc_node_by_name(hp, MDESC_NODE_NULL, channel_devices_node);
+ if (root == MDESC_NODE_NULL) {
+ printk(KERN_INFO "VIO: No channel-devices MDESC node.\n");
+ mdesc_release(hp);
+ return 0;
+ }
+
+ cdev_node = of_find_node_by_name(NULL, "channel-devices");
+ err = -ENODEV;
+ if (!cdev_node) {
+ printk(KERN_INFO "VIO: No channel-devices OBP node.\n");
+ goto out_release;
+ }
+
+ compat = mdesc_get_property(hp, root, "compatible", &len);
+ if (!compat) {
+ printk(KERN_ERR "VIO: Channel devices lacks compatible "
+ "property\n");
+ goto out_release;
+ }
+ if (!find_in_proplist(compat, channel_devices_compat, len)) {
+ printk(KERN_ERR "VIO: Channel devices node lacks (%s) "
+ "compat entry.\n", channel_devices_compat);
+ goto out_release;
+ }
+
+ cfg_handle = mdesc_get_property(hp, root, cfg_handle_prop, NULL);
+ if (!cfg_handle) {
+ printk(KERN_ERR "VIO: Channel devices lacks %s property\n",
+ cfg_handle_prop);
+ goto out_release;
+ }
+
+ cdev_cfg_handle = *cfg_handle;
+
+ root_vdev = vio_create_one(hp, root, NULL);
+ err = -ENODEV;
+ if (!root_vdev) {
+ printk(KERN_ERR "VIO: Coult not create root device.\n");
+ goto out_release;
+ }
+
+ mdesc_register_notifier(&vio_device_notifier);
+ mdesc_register_notifier(&vio_ds_notifier);
+
+ mdesc_release(hp);
+
+ return err;
+
+out_release:
+ mdesc_release(hp);
+ return err;
+}
+
+postcore_initcall(vio_init);
diff --git a/arch/sparc64/kernel/viohs.c b/arch/sparc64/kernel/viohs.c
new file mode 100644
index 000000000000..09126fc338ba
--- /dev/null
+++ b/arch/sparc64/kernel/viohs.c
@@ -0,0 +1,822 @@
+/* viohs.c: LDOM Virtual I/O handshake helper layer.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include <asm/ldc.h>
+#include <asm/vio.h>
+
+int vio_ldc_send(struct vio_driver_state *vio, void *data, int len)
+{
+ int err, limit = 1000;
+
+ err = -EINVAL;
+ while (limit-- > 0) {
+ err = ldc_write(vio->lp, data, len);
+ if (!err || (err != -EAGAIN))
+ break;
+ udelay(1);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL(vio_ldc_send);
+
+static int send_ctrl(struct vio_driver_state *vio,
+ struct vio_msg_tag *tag, int len)
+{
+ tag->sid = vio_send_sid(vio);
+ return vio_ldc_send(vio, tag, len);
+}
+
+static void init_tag(struct vio_msg_tag *tag, u8 type, u8 stype, u16 stype_env)
+{
+ tag->type = type;
+ tag->stype = stype;
+ tag->stype_env = stype_env;
+}
+
+static int send_version(struct vio_driver_state *vio, u16 major, u16 minor)
+{
+ struct vio_ver_info pkt;
+
+ vio->_local_sid = (u32) sched_clock();
+
+ memset(&pkt, 0, sizeof(pkt));
+ init_tag(&pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_VER_INFO);
+ pkt.major = major;
+ pkt.minor = minor;
+ pkt.dev_class = vio->dev_class;
+
+ viodbg(HS, "SEND VERSION INFO maj[%u] min[%u] devclass[%u]\n",
+ major, minor, vio->dev_class);
+
+ return send_ctrl(vio, &pkt.tag, sizeof(pkt));
+}
+
+static int start_handshake(struct vio_driver_state *vio)
+{
+ int err;
+
+ viodbg(HS, "START HANDSHAKE\n");
+
+ vio->hs_state = VIO_HS_INVALID;
+
+ err = send_version(vio,
+ vio->ver_table[0].major,
+ vio->ver_table[0].minor);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void flush_rx_dring(struct vio_driver_state *vio)
+{
+ struct vio_dring_state *dr;
+ u64 ident;
+
+ BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
+
+ dr = &vio->drings[VIO_DRIVER_RX_RING];
+ ident = dr->ident;
+
+ BUG_ON(!vio->desc_buf);
+ kfree(vio->desc_buf);
+ vio->desc_buf = NULL;
+
+ memset(dr, 0, sizeof(*dr));
+ dr->ident = ident;
+}
+
+void vio_link_state_change(struct vio_driver_state *vio, int event)
+{
+ if (event == LDC_EVENT_UP) {
+ vio->hs_state = VIO_HS_INVALID;
+
+ switch (vio->dev_class) {
+ case VDEV_NETWORK:
+ case VDEV_NETWORK_SWITCH:
+ vio->dr_state = (VIO_DR_STATE_TXREQ |
+ VIO_DR_STATE_RXREQ);
+ break;
+
+ case VDEV_DISK:
+ vio->dr_state = VIO_DR_STATE_TXREQ;
+ break;
+ case VDEV_DISK_SERVER:
+ vio->dr_state = VIO_DR_STATE_RXREQ;
+ break;
+ }
+ start_handshake(vio);
+ } else if (event == LDC_EVENT_RESET) {
+ vio->hs_state = VIO_HS_INVALID;
+
+ if (vio->dr_state & VIO_DR_STATE_RXREG)
+ flush_rx_dring(vio);
+
+ vio->dr_state = 0x00;
+ memset(&vio->ver, 0, sizeof(vio->ver));
+
+ ldc_disconnect(vio->lp);
+ }
+}
+EXPORT_SYMBOL(vio_link_state_change);
+
+static int handshake_failure(struct vio_driver_state *vio)
+{
+ struct vio_dring_state *dr;
+
+ /* XXX Put policy here... Perhaps start a timer to fire
+ * XXX in 100 ms, which will bring the link up and retry
+ * XXX the handshake.
+ */
+
+ viodbg(HS, "HANDSHAKE FAILURE\n");
+
+ vio->dr_state &= ~(VIO_DR_STATE_TXREG |
+ VIO_DR_STATE_RXREG);
+
+ dr = &vio->drings[VIO_DRIVER_RX_RING];
+ memset(dr, 0, sizeof(*dr));
+
+ kfree(vio->desc_buf);
+ vio->desc_buf = NULL;
+ vio->desc_buf_len = 0;
+
+ vio->hs_state = VIO_HS_INVALID;
+
+ return -ECONNRESET;
+}
+
+static int process_unknown(struct vio_driver_state *vio, void *arg)
+{
+ struct vio_msg_tag *pkt = arg;
+
+ viodbg(HS, "UNKNOWN CONTROL [%02x:%02x:%04x:%08x]\n",
+ pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
+
+ printk(KERN_ERR "vio: ID[%lu] Resetting connection.\n",
+ vio->vdev->channel_id);
+
+ ldc_disconnect(vio->lp);
+
+ return -ECONNRESET;
+}
+
+static int send_dreg(struct vio_driver_state *vio)
+{
+ struct vio_dring_state *dr = &vio->drings[VIO_DRIVER_TX_RING];
+ union {
+ struct vio_dring_register pkt;
+ char all[sizeof(struct vio_dring_register) +
+ (sizeof(struct ldc_trans_cookie) *
+ dr->ncookies)];
+ } u;
+ int i;
+
+ memset(&u, 0, sizeof(u));
+ init_tag(&u.pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_DRING_REG);
+ u.pkt.dring_ident = 0;
+ u.pkt.num_descr = dr->num_entries;
+ u.pkt.descr_size = dr->entry_size;
+ u.pkt.options = VIO_TX_DRING;
+ u.pkt.num_cookies = dr->ncookies;
+
+ viodbg(HS, "SEND DRING_REG INFO ndesc[%u] dsz[%u] opt[0x%x] "
+ "ncookies[%u]\n",
+ u.pkt.num_descr, u.pkt.descr_size, u.pkt.options,
+ u.pkt.num_cookies);
+
+ for (i = 0; i < dr->ncookies; i++) {
+ u.pkt.cookies[i] = dr->cookies[i];
+
+ viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n",
+ i,
+ (unsigned long long) u.pkt.cookies[i].cookie_addr,
+ (unsigned long long) u.pkt.cookies[i].cookie_size);
+ }
+
+ return send_ctrl(vio, &u.pkt.tag, sizeof(u));
+}
+
+static int send_rdx(struct vio_driver_state *vio)
+{
+ struct vio_rdx pkt;
+
+ memset(&pkt, 0, sizeof(pkt));
+
+ init_tag(&pkt.tag, VIO_TYPE_CTRL, VIO_SUBTYPE_INFO, VIO_RDX);
+
+ viodbg(HS, "SEND RDX INFO\n");
+
+ return send_ctrl(vio, &pkt.tag, sizeof(pkt));
+}
+
+static int send_attr(struct vio_driver_state *vio)
+{
+ return vio->ops->send_attr(vio);
+}
+
+static struct vio_version *find_by_major(struct vio_driver_state *vio,
+ u16 major)
+{
+ struct vio_version *ret = NULL;
+ int i;
+
+ for (i = 0; i < vio->ver_table_entries; i++) {
+ struct vio_version *v = &vio->ver_table[i];
+ if (v->major <= major) {
+ ret = v;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int process_ver_info(struct vio_driver_state *vio,
+ struct vio_ver_info *pkt)
+{
+ struct vio_version *vap;
+ int err;
+
+ viodbg(HS, "GOT VERSION INFO maj[%u] min[%u] devclass[%u]\n",
+ pkt->major, pkt->minor, pkt->dev_class);
+
+ if (vio->hs_state != VIO_HS_INVALID) {
+ /* XXX Perhaps invoke start_handshake? XXX */
+ memset(&vio->ver, 0, sizeof(vio->ver));
+ vio->hs_state = VIO_HS_INVALID;
+ }
+
+ vap = find_by_major(vio, pkt->major);
+
+ vio->_peer_sid = pkt->tag.sid;
+
+ if (!vap) {
+ pkt->tag.stype = VIO_SUBTYPE_NACK;
+ pkt->major = 0;
+ pkt->minor = 0;
+ viodbg(HS, "SEND VERSION NACK maj[0] min[0]\n");
+ err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
+ } else if (vap->major != pkt->major) {
+ pkt->tag.stype = VIO_SUBTYPE_NACK;
+ pkt->major = vap->major;
+ pkt->minor = vap->minor;
+ viodbg(HS, "SEND VERSION NACK maj[%u] min[%u]\n",
+ pkt->major, pkt->minor);
+ err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
+ } else {
+ struct vio_version ver = {
+ .major = pkt->major,
+ .minor = pkt->minor,
+ };
+ if (ver.minor > vap->minor)
+ ver.minor = vap->minor;
+ pkt->minor = ver.minor;
+ pkt->tag.stype = VIO_SUBTYPE_ACK;
+ viodbg(HS, "SEND VERSION ACK maj[%u] min[%u]\n",
+ pkt->major, pkt->minor);
+ err = send_ctrl(vio, &pkt->tag, sizeof(*pkt));
+ if (err > 0) {
+ vio->ver = ver;
+ vio->hs_state = VIO_HS_GOTVERS;
+ }
+ }
+ if (err < 0)
+ return handshake_failure(vio);
+
+ return 0;
+}
+
+static int process_ver_ack(struct vio_driver_state *vio,
+ struct vio_ver_info *pkt)
+{
+ viodbg(HS, "GOT VERSION ACK maj[%u] min[%u] devclass[%u]\n",
+ pkt->major, pkt->minor, pkt->dev_class);
+
+ if (vio->hs_state & VIO_HS_GOTVERS) {
+ if (vio->ver.major != pkt->major ||
+ vio->ver.minor != pkt->minor) {
+ pkt->tag.stype = VIO_SUBTYPE_NACK;
+ (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt));
+ return handshake_failure(vio);
+ }
+ } else {
+ vio->ver.major = pkt->major;
+ vio->ver.minor = pkt->minor;
+ vio->hs_state = VIO_HS_GOTVERS;
+ }
+
+ switch (vio->dev_class) {
+ case VDEV_NETWORK:
+ case VDEV_DISK:
+ if (send_attr(vio) < 0)
+ return handshake_failure(vio);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int process_ver_nack(struct vio_driver_state *vio,
+ struct vio_ver_info *pkt)
+{
+ struct vio_version *nver;
+
+ viodbg(HS, "GOT VERSION NACK maj[%u] min[%u] devclass[%u]\n",
+ pkt->major, pkt->minor, pkt->dev_class);
+
+ if ((pkt->major == 0 && pkt->minor == 0) ||
+ !(nver = find_by_major(vio, pkt->major)))
+ return handshake_failure(vio);
+
+ if (send_version(vio, nver->major, nver->minor) < 0)
+ return handshake_failure(vio);
+
+ return 0;
+}
+
+static int process_ver(struct vio_driver_state *vio, struct vio_ver_info *pkt)
+{
+ switch (pkt->tag.stype) {
+ case VIO_SUBTYPE_INFO:
+ return process_ver_info(vio, pkt);
+
+ case VIO_SUBTYPE_ACK:
+ return process_ver_ack(vio, pkt);
+
+ case VIO_SUBTYPE_NACK:
+ return process_ver_nack(vio, pkt);
+
+ default:
+ return handshake_failure(vio);
+ };
+}
+
+static int process_attr(struct vio_driver_state *vio, void *pkt)
+{
+ int err;
+
+ if (!(vio->hs_state & VIO_HS_GOTVERS))
+ return handshake_failure(vio);
+
+ err = vio->ops->handle_attr(vio, pkt);
+ if (err < 0) {
+ return handshake_failure(vio);
+ } else {
+ vio->hs_state |= VIO_HS_GOT_ATTR;
+
+ if ((vio->dr_state & VIO_DR_STATE_TXREQ) &&
+ !(vio->hs_state & VIO_HS_SENT_DREG)) {
+ if (send_dreg(vio) < 0)
+ return handshake_failure(vio);
+
+ vio->hs_state |= VIO_HS_SENT_DREG;
+ }
+ }
+ return 0;
+}
+
+static int all_drings_registered(struct vio_driver_state *vio)
+{
+ int need_rx, need_tx;
+
+ need_rx = (vio->dr_state & VIO_DR_STATE_RXREQ);
+ need_tx = (vio->dr_state & VIO_DR_STATE_TXREQ);
+
+ if (need_rx &&
+ !(vio->dr_state & VIO_DR_STATE_RXREG))
+ return 0;
+
+ if (need_tx &&
+ !(vio->dr_state & VIO_DR_STATE_TXREG))
+ return 0;
+
+ return 1;
+}
+
+static int process_dreg_info(struct vio_driver_state *vio,
+ struct vio_dring_register *pkt)
+{
+ struct vio_dring_state *dr;
+ int i, len;
+
+ viodbg(HS, "GOT DRING_REG INFO ident[%llx] "
+ "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
+ (unsigned long long) pkt->dring_ident,
+ pkt->num_descr, pkt->descr_size, pkt->options,
+ pkt->num_cookies);
+
+ if (!(vio->dr_state & VIO_DR_STATE_RXREQ))
+ goto send_nack;
+
+ if (vio->dr_state & VIO_DR_STATE_RXREG)
+ goto send_nack;
+
+ BUG_ON(vio->desc_buf);
+
+ vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
+ if (!vio->desc_buf)
+ goto send_nack;
+
+ vio->desc_buf_len = pkt->descr_size;
+
+ dr = &vio->drings[VIO_DRIVER_RX_RING];
+
+ dr->num_entries = pkt->num_descr;
+ dr->entry_size = pkt->descr_size;
+ dr->ncookies = pkt->num_cookies;
+ for (i = 0; i < dr->ncookies; i++) {
+ dr->cookies[i] = pkt->cookies[i];
+
+ viodbg(HS, "DRING COOKIE(%d) [%016llx:%016llx]\n",
+ i,
+ (unsigned long long)
+ pkt->cookies[i].cookie_addr,
+ (unsigned long long)
+ pkt->cookies[i].cookie_size);
+ }
+
+ pkt->tag.stype = VIO_SUBTYPE_ACK;
+ pkt->dring_ident = ++dr->ident;
+
+ viodbg(HS, "SEND DRING_REG ACK ident[%llx]\n",
+ (unsigned long long) pkt->dring_ident);
+
+ len = (sizeof(*pkt) +
+ (dr->ncookies * sizeof(struct ldc_trans_cookie)));
+ if (send_ctrl(vio, &pkt->tag, len) < 0)
+ goto send_nack;
+
+ vio->dr_state |= VIO_DR_STATE_RXREG;
+
+ return 0;
+
+send_nack:
+ pkt->tag.stype = VIO_SUBTYPE_NACK;
+ viodbg(HS, "SEND DRING_REG NACK\n");
+ (void) send_ctrl(vio, &pkt->tag, sizeof(*pkt));
+
+ return handshake_failure(vio);
+}
+
+static int process_dreg_ack(struct vio_driver_state *vio,
+ struct vio_dring_register *pkt)
+{
+ struct vio_dring_state *dr;
+
+ viodbg(HS, "GOT DRING_REG ACK ident[%llx] "
+ "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
+ (unsigned long long) pkt->dring_ident,
+ pkt->num_descr, pkt->descr_size, pkt->options,
+ pkt->num_cookies);
+
+ dr = &vio->drings[VIO_DRIVER_TX_RING];
+
+ if (!(vio->dr_state & VIO_DR_STATE_TXREQ))
+ return handshake_failure(vio);
+
+ dr->ident = pkt->dring_ident;
+ vio->dr_state |= VIO_DR_STATE_TXREG;
+
+ if (all_drings_registered(vio)) {
+ if (send_rdx(vio) < 0)
+ return handshake_failure(vio);
+ vio->hs_state = VIO_HS_SENT_RDX;
+ }
+ return 0;
+}
+
+static int process_dreg_nack(struct vio_driver_state *vio,
+ struct vio_dring_register *pkt)
+{
+ viodbg(HS, "GOT DRING_REG NACK ident[%llx] "
+ "ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
+ (unsigned long long) pkt->dring_ident,
+ pkt->num_descr, pkt->descr_size, pkt->options,
+ pkt->num_cookies);
+
+ return handshake_failure(vio);
+}
+
+static int process_dreg(struct vio_driver_state *vio,
+ struct vio_dring_register *pkt)
+{
+ if (!(vio->hs_state & VIO_HS_GOTVERS))
+ return handshake_failure(vio);
+
+ switch (pkt->tag.stype) {
+ case VIO_SUBTYPE_INFO:
+ return process_dreg_info(vio, pkt);
+
+ case VIO_SUBTYPE_ACK:
+ return process_dreg_ack(vio, pkt);
+
+ case VIO_SUBTYPE_NACK:
+ return process_dreg_nack(vio, pkt);
+
+ default:
+ return handshake_failure(vio);
+ }
+}
+
+static int process_dunreg(struct vio_driver_state *vio,
+ struct vio_dring_unregister *pkt)
+{
+ struct vio_dring_state *dr = &vio->drings[VIO_DRIVER_RX_RING];
+
+ viodbg(HS, "GOT DRING_UNREG\n");
+
+ if (pkt->dring_ident != dr->ident)
+ return 0;
+
+ vio->dr_state &= ~VIO_DR_STATE_RXREG;
+
+ memset(dr, 0, sizeof(*dr));
+
+ kfree(vio->desc_buf);
+ vio->desc_buf = NULL;
+ vio->desc_buf_len = 0;
+
+ return 0;
+}
+
+static int process_rdx_info(struct vio_driver_state *vio, struct vio_rdx *pkt)
+{
+ viodbg(HS, "GOT RDX INFO\n");
+
+ pkt->tag.stype = VIO_SUBTYPE_ACK;
+ viodbg(HS, "SEND RDX ACK\n");
+ if (send_ctrl(vio, &pkt->tag, sizeof(*pkt)) < 0)
+ return handshake_failure(vio);
+
+ vio->hs_state |= VIO_HS_SENT_RDX_ACK;
+ return 0;
+}
+
+static int process_rdx_ack(struct vio_driver_state *vio, struct vio_rdx *pkt)
+{
+ viodbg(HS, "GOT RDX ACK\n");
+
+ if (!(vio->hs_state & VIO_HS_SENT_RDX))
+ return handshake_failure(vio);
+
+ vio->hs_state |= VIO_HS_GOT_RDX_ACK;
+ return 0;
+}
+
+static int process_rdx_nack(struct vio_driver_state *vio, struct vio_rdx *pkt)
+{
+ viodbg(HS, "GOT RDX NACK\n");
+
+ return handshake_failure(vio);
+}
+
+static int process_rdx(struct vio_driver_state *vio, struct vio_rdx *pkt)
+{
+ if (!all_drings_registered(vio))
+ handshake_failure(vio);
+
+ switch (pkt->tag.stype) {
+ case VIO_SUBTYPE_INFO:
+ return process_rdx_info(vio, pkt);
+
+ case VIO_SUBTYPE_ACK:
+ return process_rdx_ack(vio, pkt);
+
+ case VIO_SUBTYPE_NACK:
+ return process_rdx_nack(vio, pkt);
+
+ default:
+ return handshake_failure(vio);
+ }
+}
+
+int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt)
+{
+ struct vio_msg_tag *tag = pkt;
+ u8 prev_state = vio->hs_state;
+ int err;
+
+ switch (tag->stype_env) {
+ case VIO_VER_INFO:
+ err = process_ver(vio, pkt);
+ break;
+
+ case VIO_ATTR_INFO:
+ err = process_attr(vio, pkt);
+ break;
+
+ case VIO_DRING_REG:
+ err = process_dreg(vio, pkt);
+ break;
+
+ case VIO_DRING_UNREG:
+ err = process_dunreg(vio, pkt);
+ break;
+
+ case VIO_RDX:
+ err = process_rdx(vio, pkt);
+ break;
+
+ default:
+ err = process_unknown(vio, pkt);
+ break;
+ }
+ if (!err &&
+ vio->hs_state != prev_state &&
+ (vio->hs_state & VIO_HS_COMPLETE))
+ vio->ops->handshake_complete(vio);
+
+ return err;
+}
+EXPORT_SYMBOL(vio_control_pkt_engine);
+
+void vio_conn_reset(struct vio_driver_state *vio)
+{
+}
+EXPORT_SYMBOL(vio_conn_reset);
+
+/* The issue is that the Solaris virtual disk server just mirrors the
+ * SID values it gets from the client peer. So we work around that
+ * here in vio_{validate,send}_sid() so that the drivers don't need
+ * to be aware of this crap.
+ */
+int vio_validate_sid(struct vio_driver_state *vio, struct vio_msg_tag *tp)
+{
+ u32 sid;
+
+ /* Always let VERSION+INFO packets through unchecked, they
+ * define the new SID.
+ */
+ if (tp->type == VIO_TYPE_CTRL &&
+ tp->stype == VIO_SUBTYPE_INFO &&
+ tp->stype_env == VIO_VER_INFO)
+ return 0;
+
+ /* Ok, now figure out which SID to use. */
+ switch (vio->dev_class) {
+ case VDEV_NETWORK:
+ case VDEV_NETWORK_SWITCH:
+ case VDEV_DISK_SERVER:
+ default:
+ sid = vio->_peer_sid;
+ break;
+
+ case VDEV_DISK:
+ sid = vio->_local_sid;
+ break;
+ }
+
+ if (sid == tp->sid)
+ return 0;
+ viodbg(DATA, "BAD SID tag->sid[%08x] peer_sid[%08x] local_sid[%08x]\n",
+ tp->sid, vio->_peer_sid, vio->_local_sid);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(vio_validate_sid);
+
+u32 vio_send_sid(struct vio_driver_state *vio)
+{
+ switch (vio->dev_class) {
+ case VDEV_NETWORK:
+ case VDEV_NETWORK_SWITCH:
+ case VDEV_DISK:
+ default:
+ return vio->_local_sid;
+
+ case VDEV_DISK_SERVER:
+ return vio->_peer_sid;
+ }
+}
+EXPORT_SYMBOL(vio_send_sid);
+
+extern int vio_ldc_alloc(struct vio_driver_state *vio,
+ struct ldc_channel_config *base_cfg,
+ void *event_arg)
+{
+ struct ldc_channel_config cfg = *base_cfg;
+ struct ldc_channel *lp;
+
+ cfg.tx_irq = vio->vdev->tx_irq;
+ cfg.rx_irq = vio->vdev->rx_irq;
+
+ lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg);
+ if (IS_ERR(lp))
+ return PTR_ERR(lp);
+
+ vio->lp = lp;
+
+ return 0;
+}
+EXPORT_SYMBOL(vio_ldc_alloc);
+
+void vio_ldc_free(struct vio_driver_state *vio)
+{
+ ldc_free(vio->lp);
+ vio->lp = NULL;
+
+ kfree(vio->desc_buf);
+ vio->desc_buf = NULL;
+ vio->desc_buf_len = 0;
+}
+EXPORT_SYMBOL(vio_ldc_free);
+
+void vio_port_up(struct vio_driver_state *vio)
+{
+ unsigned long flags;
+ int err, state;
+
+ spin_lock_irqsave(&vio->lock, flags);
+
+ state = ldc_state(vio->lp);
+
+ err = 0;
+ if (state == LDC_STATE_INIT) {
+ err = ldc_bind(vio->lp, vio->name);
+ if (err)
+ printk(KERN_WARNING "%s: Port %lu bind failed, "
+ "err=%d\n",
+ vio->name, vio->vdev->channel_id, err);
+ }
+
+ if (!err) {
+ err = ldc_connect(vio->lp);
+ if (err)
+ printk(KERN_WARNING "%s: Port %lu connect failed, "
+ "err=%d\n",
+ vio->name, vio->vdev->channel_id, err);
+ }
+ if (err) {
+ unsigned long expires = jiffies + HZ;
+
+ expires = round_jiffies(expires);
+ mod_timer(&vio->timer, expires);
+ }
+
+ spin_unlock_irqrestore(&vio->lock, flags);
+}
+EXPORT_SYMBOL(vio_port_up);
+
+static void vio_port_timer(unsigned long _arg)
+{
+ struct vio_driver_state *vio = (struct vio_driver_state *) _arg;
+
+ vio_port_up(vio);
+}
+
+int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
+ u8 dev_class, struct vio_version *ver_table,
+ int ver_table_size, struct vio_driver_ops *ops,
+ char *name)
+{
+ switch (dev_class) {
+ case VDEV_NETWORK:
+ case VDEV_NETWORK_SWITCH:
+ case VDEV_DISK:
+ case VDEV_DISK_SERVER:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (!ops->send_attr ||
+ !ops->handle_attr ||
+ !ops->handshake_complete)
+ return -EINVAL;
+
+ if (!ver_table || ver_table_size < 0)
+ return -EINVAL;
+
+ if (!name)
+ return -EINVAL;
+
+ spin_lock_init(&vio->lock);
+
+ vio->name = name;
+
+ vio->dev_class = dev_class;
+ vio->vdev = vdev;
+
+ vio->ver_table = ver_table;
+ vio->ver_table_entries = ver_table_size;
+
+ vio->ops = ops;
+
+ setup_timer(&vio->timer, vio_port_timer, (unsigned long) vio);
+
+ return 0;
+}
+EXPORT_SYMBOL(vio_driver_init);
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 3ad10f3027e4..481861764deb 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -90,10 +90,8 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(PAGE_SIZE);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(PAGE_SIZE)
+
. = ALIGN(PAGE_SIZE);
__init_end = .;
__bss_start = .;
diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile
index 4a725d8985f1..c4a6d6e7d03c 100644
--- a/arch/sparc64/lib/Makefile
+++ b/arch/sparc64/lib/Makefile
@@ -14,6 +14,6 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \
NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o NGpatch.o \
NGpage.o NGbzero.o \
copy_in_user.o user_fixup.o memmove.o \
- mcount.o ipcsum.o rwsem.o xor.o delay.o
+ mcount.o ipcsum.o rwsem.o xor.o
obj-y += iomap.o
diff --git a/arch/sparc64/lib/delay.c b/arch/sparc64/lib/delay.c
deleted file mode 100644
index fb27e54a03ee..000000000000
--- a/arch/sparc64/lib/delay.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* delay.c: Delay loops for sparc64
- *
- * Copyright (C) 2004, 2006 David S. Miller <davem@davemloft.net>
- *
- * Based heavily upon x86 variant which is:
- * Copyright (C) 1993 Linus Torvalds
- * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- */
-
-#include <linux/delay.h>
-#include <asm/timer.h>
-
-void __delay(unsigned long loops)
-{
- unsigned long bclock, now;
-
- bclock = tick_ops->get_tick();
- do {
- now = tick_ops->get_tick();
- } while ((now-bclock) < loops);
-}
-
-/* We used to multiply by HZ after shifting down by 32 bits
- * but that runs into problems for higher values of HZ and
- * slow cpus.
- */
-void __const_udelay(unsigned long n)
-{
- n *= 4;
-
- n *= (cpu_data(raw_smp_processor_id()).udelay_val * (HZ/4));
- n >>= 32;
-
- __delay(n + 1);
-}
-
-void __udelay(unsigned long n)
-{
- __const_udelay(n * 0x10c7UL);
-}
-
-
-void __ndelay(unsigned long n)
-{
- __const_udelay(n * 0x5UL);
-}
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index b582024d2199..17123e9ecf78 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -278,7 +278,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned int insn = 0;
- int si_code, fault_code;
+ int si_code, fault_code, fault;
unsigned long address, mm_rss;
fault_code = get_thread_fault_code();
@@ -415,20 +415,18 @@ good_area:
goto bad_area;
}
- switch (handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE))) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ fault = handle_mm_fault(mm, vma, address, (fault_code & FAULT_CODE_WRITE));
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c
index 8eb8a7c76ec9..7ff0a02f5813 100644
--- a/arch/sparc64/mm/tsb.c
+++ b/arch/sparc64/mm/tsb.c
@@ -262,8 +262,7 @@ void __init pgtable_cache_init(void)
tsb_caches[i] = kmem_cache_create(name,
size, size,
- 0,
- NULL, NULL);
+ 0, NULL);
if (!tsb_caches[i]) {
prom_printf("Could not create %s cache\n", name);
prom_halt();
diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c
index 7c25c54cefdc..3fafa9a8b50b 100644
--- a/arch/sparc64/prom/console.c
+++ b/arch/sparc64/prom/console.c
@@ -73,88 +73,3 @@ prom_puts(const char *s, int len)
P1275_INOUT(3,1),
prom_stdout, s, P1275_SIZE(len));
}
-
-/* Query for input device type */
-enum prom_input_device
-prom_query_input_device(void)
-{
- int st_p;
- char propb[64];
-
- st_p = prom_inst2pkg(prom_stdin);
- if(prom_node_has_property(st_p, "keyboard"))
- return PROMDEV_IKBD;
- prom_getproperty(st_p, "device_type", propb, sizeof(propb));
- if(strncmp(propb, "serial", 6))
- return PROMDEV_I_UNK;
- /* FIXME: Is there any better way how to find out? */
- memset(propb, 0, sizeof(propb));
- st_p = prom_finddevice ("/options");
- prom_getproperty(st_p, "input-device", propb, sizeof(propb));
-
- /*
- * If we get here with propb == 'keyboard', we are on ttya, as
- * the PROM defaulted to this due to 'no input device'.
- */
- if (!strncmp(propb, "keyboard", 8))
- return PROMDEV_ITTYA;
-
- if (!strncmp (propb, "rsc", 3))
- return PROMDEV_IRSC;
-
- if (!strncmp (propb, "virtual-console", 3))
- return PROMDEV_IVCONS;
-
- if (strncmp (propb, "tty", 3) || !propb[3])
- return PROMDEV_I_UNK;
-
- switch (propb[3]) {
- case 'a': return PROMDEV_ITTYA;
- case 'b': return PROMDEV_ITTYB;
- default: return PROMDEV_I_UNK;
- }
-}
-
-/* Query for output device type */
-
-enum prom_output_device
-prom_query_output_device(void)
-{
- int st_p;
- char propb[64];
- int propl;
-
- st_p = prom_inst2pkg(prom_stdout);
- propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
- if (propl >= 0 && propl == sizeof("display") &&
- strncmp("display", propb, sizeof("display")) == 0)
- return PROMDEV_OSCREEN;
- if(strncmp("serial", propb, 6))
- return PROMDEV_O_UNK;
- /* FIXME: Is there any better way how to find out? */
- memset(propb, 0, sizeof(propb));
- st_p = prom_finddevice ("/options");
- prom_getproperty(st_p, "output-device", propb, sizeof(propb));
-
- /*
- * If we get here with propb == 'screen', we are on ttya, as
- * the PROM defaulted to this due to 'no input device'.
- */
- if (!strncmp(propb, "screen", 6))
- return PROMDEV_OTTYA;
-
- if (!strncmp (propb, "rsc", 3))
- return PROMDEV_ORSC;
-
- if (!strncmp (propb, "virtual-console", 3))
- return PROMDEV_OVCONS;
-
- if (strncmp (propb, "tty", 3) || !propb[3])
- return PROMDEV_O_UNK;
-
- switch (propb[3]) {
- case 'a': return PROMDEV_OTTYA;
- case 'b': return PROMDEV_OTTYB;
- default: return PROMDEV_O_UNK;
- }
-}
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index f3e0c14e9eef..68c83ad04ad9 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -14,6 +14,7 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/system.h>
+#include <asm/ldc.h>
int prom_service_exists(const char *service_name)
{
@@ -37,6 +38,10 @@ void prom_sun4v_guest_soft_state(void)
/* Reset and reboot the machine with the command 'bcommand'. */
void prom_reboot(const char *bcommand)
{
+#ifdef CONFIG_SUN_LDOMS
+ if (ldom_domaining_enabled)
+ ldom_reboot(bcommand);
+#endif
p1275_cmd("boot", P1275_ARG(0, P1275_ARG_IN_STRING) |
P1275_INOUT(1, 0), bcommand);
}
@@ -67,7 +72,7 @@ void prom_cmdline(void)
local_irq_save(flags);
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette(1);
#ifdef CONFIG_SMP
@@ -80,7 +85,7 @@ void prom_cmdline(void)
smp_release();
#endif
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette(0);
local_irq_restore(flags);
@@ -91,6 +96,10 @@ void prom_cmdline(void)
*/
void prom_halt(void)
{
+#ifdef CONFIG_SUN_LDOMS
+ if (ldom_domaining_enabled)
+ ldom_power_off();
+#endif
again:
p1275_cmd("exit", P1275_INOUT(0, 0));
goto again; /* PROM is out to get me -DaveM */
@@ -98,6 +107,10 @@ again:
void prom_halt_power_off(void)
{
+#ifdef CONFIG_SUN_LDOMS
+ if (ldom_domaining_enabled)
+ ldom_power_off();
+#endif
p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0));
/* if nothing else helps, we just halt */
diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c
index 2b32c489860c..7fcccc0e19cf 100644
--- a/arch/sparc64/prom/p1275.c
+++ b/arch/sparc64/prom/p1275.c
@@ -16,6 +16,7 @@
#include <asm/system.h>
#include <asm/spitfire.h>
#include <asm/pstate.h>
+#include <asm/ldc.h>
struct {
long prom_callback; /* 0x00 */
diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c
index 500f05e2cfcb..b2c5b12c9818 100644
--- a/arch/sparc64/prom/tree.c
+++ b/arch/sparc64/prom/tree.c
@@ -13,6 +13,7 @@
#include <asm/openprom.h>
#include <asm/oplib.h>
+#include <asm/ldc.h>
/* Return the child of node 'node' or zero if no this node has no
* direct descendent.
@@ -261,9 +262,17 @@ int prom_node_has_property(int node, const char *prop)
int
prom_setprop(int node, const char *pname, char *value, int size)
{
- if(size == 0) return 0;
- if((pname == 0) || (value == 0)) return 0;
+ if (size == 0)
+ return 0;
+ if ((pname == 0) || (value == 0))
+ return 0;
+#ifdef CONFIG_SUN_LDOMS
+ if (ldom_domaining_enabled) {
+ ldom_set_var(pname, value);
+ return 0;
+ }
+#endif
return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)|
P1275_ARG(2,P1275_ARG_IN_BUF)|
P1275_INOUT(4, 1),
@@ -295,3 +304,11 @@ prom_pathtoinode(const char *path)
if (node == -1) return 0;
return node;
}
+
+int prom_ihandle2path(int handle, char *buffer, int bufsize)
+{
+ return p1275_cmd("instance-to-path",
+ P1275_ARG(1,P1275_ARG_OUT_BUF)|
+ P1275_INOUT(3, 1),
+ handle, buffer, P1275_SIZE(bufsize));
+}
diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
index e94f6e5d9455..7736411f244f 100644
--- a/arch/sparc64/solaris/socksys.c
+++ b/arch/sparc64/solaris/socksys.c
@@ -199,6 +199,5 @@ int __init init_socksys(void)
void __exit cleanup_socksys(void)
{
- if (unregister_chrdev(30, "socksys"))
- printk ("Couldn't unregister socksys character device\n");
+ unregister_chrdev(30, "socksys");
}
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
index 09c1aca6339f..c86f5eb29fd5 100644
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -47,4 +47,13 @@ config GCOV
If you're involved in UML kernel development and want to use gcov,
say Y. If you're unsure, say N.
+config DEBUG_STACK_USAGE
+ bool "Stack utilization instrumentation"
+ default N
+ help
+ Track the maximum kernel stack usage - this will look at each
+ kernel stack at process exit and log it if it's the deepest
+ stack seen so far.
+
+ This option will slow down process creation and destruction somewhat.
endmenu
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 5d5ed726faa0..989224f21346 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -146,7 +146,7 @@ define cmd_vmlinux__
-Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
-Wl,--start-group $(vmlinux-main) -Wl,--end-group \
-lutil \
- $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) \
+ $(filter-out $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) vmlinux.o \
FORCE ,$^) ; rm -f linux
endef
diff --git a/arch/um/config.release b/arch/um/config.release
deleted file mode 100644
index fc68bcb9294e..000000000000
--- a/arch/um/config.release
+++ /dev/null
@@ -1,333 +0,0 @@
-#
-# Automatically generated make config: don't edit
-#
-CONFIG_USERMODE=y
-# CONFIG_ISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_PCI is not set
-CONFIG_UID16=y
-CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-
-#
-# General Setup
-#
-CONFIG_STDIO_CONSOLE=y
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_SYSCTL=y
-CONFIG_BINFMT_AOUT=y
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
-CONFIG_SSL=y
-CONFIG_HOSTFS=y
-CONFIG_MCONSOLE=y
-CONFIG_MAGIC_SYSRQ=y
-# CONFIG_HOST_2G_2G is not set
-# CONFIG_UML_SMP is not set
-# CONFIG_SMP is not set
-CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
-CONFIG_CON_CHAN="xterm"
-CONFIG_SSL_CHAN="pty"
-CONFIG_NEST_LEVEL=0
-CONFIG_KERNEL_HALF_GIGS=1
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_KMOD=y
-
-#
-# Devices
-#
-CONFIG_BLK_DEV_UBD=y
-# CONFIG_BLK_DEV_UBD_SYNC is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_MMAPPER is not set
-CONFIG_UML_SOUND=y
-CONFIG_SOUND=y
-CONFIG_HOSTAUDIO=y
-# CONFIG_UML_WATCHDOG is not set
-# CONFIG_TTY_LOG is not set
-CONFIG_FD_CHAN=y
-# CONFIG_NULL_CHAN is not set
-CONFIG_PORT_CHAN=y
-CONFIG_PTY_CHAN=y
-CONFIG_TTY_CHAN=y
-CONFIG_XTERM_CHAN=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_FILTER is not set
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
-# CONFIG_KHTTPD is not set
-# CONFIG_ATM is not set
-# CONFIG_VLAN_8021Q is not set
-
-#
-#
-#
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_LLC is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_HW_FLOWCONTROL is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network device support
-#
-CONFIG_UML_NET=y
-CONFIG_UML_NET_ETHERTAP=y
-CONFIG_UML_NET_TUNTAP=y
-CONFIG_UML_NET_SLIP=y
-CONFIG_UML_NET_DAEMON=y
-CONFIG_UML_NET_MCAST=y
-CONFIG_NETDEVICES=y
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-CONFIG_DUMMY=y
-CONFIG_BONDING=m
-CONFIG_EQUALIZER=m
-CONFIG_TUN=y
-# CONFIG_ETHERTAP is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-CONFIG_PLIP=m
-CONFIG_PPP=m
-CONFIG_PPP_MULTILINK=y
-# CONFIG_PPP_FILTER is not set
-# CONFIG_PPP_ASYNC is not set
-CONFIG_PPP_SYNC_TTY=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPPOE=m
-CONFIG_SLIP=m
-CONFIG_SLIP_COMPRESSED=y
-CONFIG_SLIP_SMART=y
-# CONFIG_SLIP_MODE_SLIP6 is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-# CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
-CONFIG_SHAPER=m
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# File systems
-#
-CONFIG_QUOTA=y
-CONFIG_AUTOFS_FS=m
-CONFIG_AUTOFS4_FS=m
-CONFIG_REISERFS_FS=m
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-CONFIG_ADFS_FS=m
-# CONFIG_ADFS_FS_RW is not set
-CONFIG_AFFS_FS=m
-CONFIG_HFS_FS=m
-CONFIG_BFS_FS=m
-CONFIG_EXT3_FS=y
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FAT_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_UMSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_EFS_FS=m
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-CONFIG_CRAMFS=m
-CONFIG_TMPFS=y
-CONFIG_RAMFS=m
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-CONFIG_MINIX_FS=m
-CONFIG_VXFS_FS=m
-# CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_RW is not set
-CONFIG_HPFS_FS=m
-CONFIG_PROC_FS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-CONFIG_QNX4FS_FS=m
-# CONFIG_QNX4FS_RW is not set
-CONFIG_ROMFS_FS=m
-CONFIG_EXT2_FS=y
-CONFIG_SYSV_FS=m
-CONFIG_UDF_FS=m
-CONFIG_UFS_FS=m
-# CONFIG_UFS_FS_WRITE is not set
-
-#
-# Network File Systems
-#
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_ROOT_NFS is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-# CONFIG_ZISOFS_FS is not set
-CONFIG_ZLIB_FS_INFLATE=m
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
-CONFIG_NLS=y
-
-#
-# Native Language Support
-#
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_SLAB is not set
-# CONFIG_DEBUG_INFO is not set
-# CONFIG_PT_PROXY is not set
-# CONFIG_GPROF is not set
-# CONFIG_GCOV is not set
diff --git a/arch/um/defconfig b/arch/um/defconfig
index a54d0efecae1..1e0f677c2f46 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -52,7 +52,6 @@ CONFIG_X86_WP_WORKS_OK=y
CONFIG_X86_INVLPG=y
CONFIG_X86_BSWAP=y
CONFIG_X86_POPAD_OK=y
-CONFIG_X86_CMPXCHG64=y
CONFIG_X86_GOOD_APIC=y
CONFIG_X86_USE_PPRO_CHECKSUM=y
CONFIG_X86_TSC=y
@@ -189,7 +188,7 @@ CONFIG_XTERM_CHAN=y
# CONFIG_NOCONFIG_CHAN is not set
CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
CONFIG_CON_CHAN="xterm"
-CONFIG_SSL_CHAN="pty"
+CONFIG_SSL_CHAN="pts"
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -527,3 +526,4 @@ CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_GPROF is not set
# CONFIG_GCOV is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 3aa351611763..368d3e97dfd9 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -203,22 +203,37 @@ void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
}
}
-void enable_chan(struct line *line)
+int enable_chan(struct line *line)
{
struct list_head *ele;
struct chan *chan;
+ int err;
list_for_each(ele, &line->chan_list){
chan = list_entry(ele, struct chan, list);
- if(open_one_chan(chan))
+ err = open_one_chan(chan);
+ if (err) {
+ if (chan->primary)
+ goto out_close;
+
continue;
+ }
if(chan->enabled)
continue;
- line_setup_irq(chan->fd, chan->input, chan->output, line,
- chan);
+ err = line_setup_irq(chan->fd, chan->input, chan->output, line,
+ chan);
+ if (err)
+ goto out_close;
+
chan->enabled = 1;
}
+
+ return 0;
+
+ out_close:
+ close_chan(&line->chan_list, 0);
+ return err;
}
/* Items are added in IRQ context, when free_irq can't be called, and
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c
index 13f0bf852b2a..4d438f36ea2e 100644
--- a/arch/um/drivers/chan_user.c
+++ b/arch/um/drivers/chan_user.c
@@ -51,19 +51,21 @@ error:
/*
* UML SIGWINCH handling
*
- * The point of this is to handle SIGWINCH on consoles which have host ttys and
- * relay them inside UML to whatever might be running on the console and cares
- * about the window size (since SIGWINCH notifies about terminal size changes).
+ * The point of this is to handle SIGWINCH on consoles which have host
+ * ttys and relay them inside UML to whatever might be running on the
+ * console and cares about the window size (since SIGWINCH notifies
+ * about terminal size changes).
*
- * So, we have a separate thread for each host tty attached to a UML device
- * (side-issue - I'm annoyed that one thread can't have multiple controlling
- * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons
- * that doesn't make any sense).
+ * So, we have a separate thread for each host tty attached to a UML
+ * device (side-issue - I'm annoyed that one thread can't have
+ * multiple controlling ttys for the purpose of handling SIGWINCH, but
+ * I imagine there are other reasons that doesn't make any sense).
*
- * SIGWINCH can't be received synchronously, so you have to set up to receive it
- * as a signal. That being the case, if you are going to wait for it, it is
- * convenient to sit in sigsuspend() and wait for the signal to bounce you out of
- * it (see below for how we make sure to exit only on SIGWINCH).
+ * SIGWINCH can't be received synchronously, so you have to set up to
+ * receive it as a signal. That being the case, if you are going to
+ * wait for it, it is convenient to sit in sigsuspend() and wait for
+ * the signal to bounce you out of it (see below for how we make sure
+ * to exit only on SIGWINCH).
*/
static void winch_handler(int sig)
@@ -112,7 +114,8 @@ static int winch_thread(void *arg)
err = os_new_tty_pgrp(pty_fd, os_getpid());
if(err < 0){
- printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
+ printk("winch_thread : new_tty_pgrp failed on fd %d, "
+ "err = %d\n", pty_fd, -err);
exit(1);
}
@@ -126,8 +129,9 @@ static int winch_thread(void *arg)
"err = %d\n", -count);
while(1){
- /* This will be interrupted by SIGWINCH only, since other signals
- * are blocked.*/
+ /* This will be interrupted by SIGWINCH only, since
+ * other signals are blocked.
+ */
sigsuspend(&sigs);
count = os_write_file(pipe_fd, &c, sizeof(c));
@@ -137,10 +141,10 @@ static int winch_thread(void *arg)
}
}
-static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
+static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out,
+ unsigned long *stack_out)
{
struct winch_data data;
- unsigned long stack;
int fds[2], n, err;
char c;
@@ -153,9 +157,11 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
data = ((struct winch_data) { .pty_fd = fd,
.pipe_fd = fds[1] } );
/* CLONE_FILES so this thread doesn't hold open files which are open
- * now, but later closed. This is a problem with /dev/net/tun.
+ * now, but later closed in a different thread. This is a
+ * problem with /dev/net/tun, which if held open by this
+ * thread, prevents the TUN/TAP device from being reused.
*/
- err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0);
+ err = run_helper_thread(winch_thread, &data, CLONE_FILES, stack_out);
if(err < 0){
printk("fork of winch_thread failed - errno = %d\n", -err);
goto out_close;
@@ -170,7 +176,13 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
err = -EINVAL;
goto out_close;
}
- return err ;
+
+ if (os_set_fd_block(*fd_out, 0)) {
+ printk("winch_tramp: failed to set thread_fd non-blocking.\n");
+ goto out_close;
+ }
+
+ return err;
out_close:
os_close_file(fds[1]);
@@ -181,25 +193,25 @@ static int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
void register_winch(int fd, struct tty_struct *tty)
{
- int pid, thread, thread_fd = -1;
- int count;
+ unsigned long stack;
+ int pid, thread, count, thread_fd = -1;
char c = 1;
if(!isatty(fd))
return;
pid = tcgetpgrp(fd);
- if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
- tty) && (pid == -1)){
- thread = winch_tramp(fd, tty, &thread_fd);
- if(thread > 0){
- register_winch_irq(thread_fd, fd, thread, tty);
-
- count = os_write_file(thread_fd, &c, sizeof(c));
- if(count != sizeof(c))
- printk("register_winch : failed to write "
- "synchronization byte, err = %d\n",
- -count);
- }
+ if (!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, tty) &&
+ (pid == -1)) {
+ thread = winch_tramp(fd, tty, &thread_fd, &stack);
+ if (thread < 0)
+ return;
+
+ register_winch_irq(thread_fd, fd, thread, tty, stack);
+
+ count = os_write_file(thread_fd, &c, sizeof(c));
+ if(count != sizeof(c))
+ printk("register_winch : failed to write "
+ "synchronization byte, err = %d\n", -count);
}
}
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
index 15453845d2ba..ca8c9e11a39b 100644
--- a/arch/um/drivers/cow_sys.h
+++ b/arch/um/drivers/cow_sys.h
@@ -8,7 +8,7 @@
static inline void *cow_malloc(int size)
{
- return um_kmalloc(size);
+ return kmalloc(size, UM_GFP_KERNEL);
}
static inline void cow_free(void *ptr)
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index b869e3899683..8d2008f06682 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -35,7 +35,7 @@ static struct sockaddr_un *new_addr(void *name, int len)
{
struct sockaddr_un *sun;
- sun = um_kmalloc(sizeof(struct sockaddr_un));
+ sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
if(sun == NULL){
printk("new_addr: allocation of sockaddr_un failed\n");
return NULL;
@@ -83,7 +83,7 @@ static int connect_to_switch(struct daemon_data *pri)
goto out_close;
}
- sun = um_kmalloc(sizeof(struct sockaddr_un));
+ sun = kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
if(sun == NULL){
printk("new_addr: allocation of sockaddr_un failed\n");
err = -ENOMEM;
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index 7f083ec47a4f..39c01ffd45c9 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -37,7 +37,7 @@ static void *fd_init(char *str, int device, const struct chan_opts *opts)
printk("fd_init : couldn't parse file descriptor '%s'\n", str);
return(NULL);
}
- data = um_kmalloc(sizeof(*data));
+ data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
if(data == NULL) return(NULL);
*data = ((struct fd_chan) { .fd = n,
.raw = opts->raw });
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c
index 5eeecf8917c3..1171790f742c 100644
--- a/arch/um/drivers/harddog_user.c
+++ b/arch/um/drivers/harddog_user.c
@@ -68,7 +68,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
args = pid_args;
}
- pid = run_helper(pre_exec, &data, args, NULL);
+ pid = run_helper(pre_exec, &data, args);
os_close_file(out_fds[0]);
os_close_file(in_fds[1]);
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 4bd40bb43ec2..3e0b68e297f2 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -454,7 +454,10 @@ int line_open(struct line *lines, struct tty_struct *tty)
tty->driver_data = line;
line->tty = tty;
- enable_chan(line);
+ err = enable_chan(line);
+ if (err)
+ return err;
+
INIT_DELAYED_WORK(&line->task, line_timer_cb);
if(!line->sigio){
@@ -746,8 +749,24 @@ struct winch {
int tty_fd;
int pid;
struct tty_struct *tty;
+ unsigned long stack;
};
+static void free_winch(struct winch *winch, int free_irq_ok)
+{
+ list_del(&winch->list);
+
+ if (winch->pid != -1)
+ os_kill_process(winch->pid, 1);
+ if (winch->fd != -1)
+ os_close_file(winch->fd);
+ if (winch->stack != 0)
+ free_stack(winch->stack, 0);
+ if (free_irq_ok)
+ free_irq(WINCH_IRQ, winch);
+ kfree(winch);
+}
+
static irqreturn_t winch_interrupt(int irq, void *data)
{
struct winch *winch = data;
@@ -764,12 +783,13 @@ static irqreturn_t winch_interrupt(int irq, void *data)
"errno = %d\n", -err);
printk("fd %d is losing SIGWINCH support\n",
winch->tty_fd);
+ free_winch(winch, 0);
return IRQ_HANDLED;
}
goto out;
}
}
- tty = winch->tty;
+ tty = winch->tty;
if (tty != NULL) {
line = tty->driver_data;
chan_window_size(&line->chan_list, &tty->winsize.ws_row,
@@ -782,43 +802,44 @@ static irqreturn_t winch_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
+void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty,
+ unsigned long stack)
{
struct winch *winch;
winch = kmalloc(sizeof(*winch), GFP_KERNEL);
if (winch == NULL) {
printk("register_winch_irq - kmalloc failed\n");
- return;
+ goto cleanup;
}
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
.fd = fd,
.tty_fd = tty_fd,
.pid = pid,
- .tty = tty });
+ .tty = tty,
+ .stack = stack });
+
+ if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
+ IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ "winch", winch) < 0) {
+ printk("register_winch_irq - failed to register IRQ\n");
+ goto out_free;
+ }
spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers);
spin_unlock(&winch_handler_lock);
- if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
- IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
- "winch", winch) < 0)
- printk("register_winch_irq - failed to register IRQ\n");
-}
-
-static void free_winch(struct winch *winch)
-{
- list_del(&winch->list);
-
- if(winch->pid != -1)
- os_kill_process(winch->pid, 1);
- if(winch->fd != -1)
- os_close_file(winch->fd);
+ return;
- free_irq(WINCH_IRQ, winch);
+ out_free:
kfree(winch);
+ cleanup:
+ os_kill_process(pid, 1);
+ os_close_file(fd);
+ if (stack != 0)
+ free_stack(stack, 0);
}
static void unregister_winch(struct tty_struct *tty)
@@ -831,7 +852,7 @@ static void unregister_winch(struct tty_struct *tty)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){
- free_winch(winch);
+ free_winch(winch, 1);
break;
}
}
@@ -847,7 +868,7 @@ static void winch_cleanup(void)
list_for_each_safe(ele, next, &winch_handlers){
winch = list_entry(ele, struct winch, list);
- free_winch(winch);
+ free_winch(winch, 1);
}
spin_unlock(&winch_handler_lock);
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index d319db16d4ec..236a3dfc297d 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -30,7 +30,7 @@ static struct sockaddr_in *new_addr(char *addr, unsigned short port)
{
struct sockaddr_in *sin;
- sin = um_kmalloc(sizeof(struct sockaddr_in));
+ sin = kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
if(sin == NULL){
printk("new_addr: allocation of sockaddr_in failed\n");
return NULL;
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index 62e5ad63181a..f31e71546e52 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -86,8 +86,9 @@ int mconsole_get_request(int fd, struct mc_request *req)
int len;
req->originlen = sizeof(req->origin);
- req->len = recvfrom(fd, &req->request, sizeof(req->request), 0,
- (struct sockaddr *) req->origin, &req->originlen);
+ req->len = recvfrom(fd, &req->request, sizeof(req->request),
+ MSG_DONTWAIT, (struct sockaddr *) req->origin,
+ &req->originlen);
if (req->len < 0)
return 0;
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index 3503cff867c3..da946e3e1bf2 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -187,7 +187,7 @@ static int change_tramp(char **argv, char *output, int output_len)
}
pe_data.close_me = fds[0];
pe_data.stdout = fds[1];
- pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
+ pid = run_helper(change_pre_exec, &pe_data, argv);
if (pid > 0) /* Avoid hang as we won't get data in failure case. */
read_output(fds[0], output, output_len);
@@ -217,7 +217,7 @@ static void change(char *dev, char *what, unsigned char *addr,
netmask[2], netmask[3]);
output_len = UM_KERN_PAGE_SIZE;
- output = um_kmalloc(output_len);
+ output = kmalloc(output_len, UM_GFP_KERNEL);
if(output == NULL)
printk("change : failed to allocate output buffer\n");
diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
index 483aa15222a4..1316456e2a28 100644
--- a/arch/um/drivers/pcap_user.c
+++ b/arch/um/drivers/pcap_user.c
@@ -53,7 +53,7 @@ static int pcap_open(void *data)
return -EIO;
}
- pri->compiled = um_kmalloc(sizeof(struct bpf_program));
+ pri->compiled = kmalloc(sizeof(struct bpf_program), UM_GFP_KERNEL);
if(pri->compiled == NULL){
printk(UM_KERN_ERR "pcap_open : kmalloc failed\n");
return -ENOMEM;
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index 3f6357d24bee..c799b00012c7 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -50,7 +50,7 @@ static void *port_init(char *str, int device, const struct chan_opts *opts)
if(kern_data == NULL)
return NULL;
- data = um_kmalloc(sizeof(*data));
+ data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
if(data == NULL)
goto err;
@@ -188,7 +188,7 @@ int port_connection(int fd, int *socket, int *pid_out)
{ .sock_fd = new,
.pipe_fd = socket[1] });
- err = run_helper(port_pre_exec, &data, argv, NULL);
+ err = run_helper(port_pre_exec, &data, argv);
if(err < 0)
goto out_shutdown;
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index df4976c9eef2..1e3fd619a837 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -7,12 +7,14 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <fcntl.h>
#include <errno.h>
#include <termios.h>
+#include <sys/stat.h>
#include "chan_user.h"
-#include "user.h"
-#include "kern_util.h"
#include "os.h"
+#include "user.h"
+#include "kern_constants.h"
#include "um_malloc.h"
struct pty_chan {
@@ -27,12 +29,14 @@ static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
{
struct pty_chan *data;
- data = um_kmalloc(sizeof(*data));
- if(data == NULL) return(NULL);
+ data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
+ if (data == NULL)
+ return NULL;
+
*data = ((struct pty_chan) { .announce = opts->announce,
.dev = device,
.raw = opts->raw });
- return(data);
+ return data;
}
static int pts_open(int input, int output, int primary, void *d,
@@ -43,31 +47,35 @@ static int pts_open(int input, int output, int primary, void *d,
int fd, err;
fd = get_pty();
- if(fd < 0){
+ if (fd < 0) {
err = -errno;
- printk("open_pts : Failed to open pts\n");
+ printk(UM_KERN_ERR "open_pts : Failed to open pts\n");
return err;
}
- if(data->raw){
+
+ if (data->raw) {
CATCH_EINTR(err = tcgetattr(fd, &data->tt));
- if(err)
- return(err);
+ if (err)
+ return err;
err = raw(fd);
- if(err)
- return(err);
+ if (err)
+ return err;
}
dev = ptsname(fd);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
+
if (data->announce)
(*data->announce)(dev, data->dev);
- return(fd);
+
+ return fd;
}
static int getmaster(char *line)
{
+ struct stat buf;
char *pty, *bank, *cp;
int master, err;
@@ -75,24 +83,29 @@ static int getmaster(char *line)
for (bank = "pqrs"; *bank; bank++) {
line[strlen("/dev/pty")] = *bank;
*pty = '0';
- if (os_stat_file(line, NULL) < 0)
+ /* Did we hit the end ? */
+ if ((stat(line, &buf) < 0) && (errno == ENOENT))
break;
+
for (cp = "0123456789abcdef"; *cp; cp++) {
*pty = *cp;
- master = os_open_file(line, of_rdwr(OPENFLAGS()), 0);
+ master = open(line, O_RDWR);
if (master >= 0) {
char *tp = &line[strlen("/dev/")];
/* verify slave side is usable */
*tp = 't';
- err = os_access(line, OS_ACC_RW_OK);
+ err = access(line, R_OK | W_OK);
*tp = 'p';
- if(err == 0) return(master);
- (void) os_close_file(master);
+ if(!err)
+ return master;
+ close(master);
}
}
}
- return(-1);
+
+ printk(UM_KERN_ERR "getmaster - no usable host pty devices\n");
+ return -ENOENT;
}
static int pty_open(int input, int output, int primary, void *d,
@@ -103,20 +116,22 @@ static int pty_open(int input, int output, int primary, void *d,
char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
fd = getmaster(dev);
- if(fd < 0)
- return(-errno);
+ if (fd < 0)
+ return fd;
if(data->raw){
err = raw(fd);
- if(err)
- return(err);
+ if (err)
+ return err;
}
- if(data->announce) (*data->announce)(dev, data->dev);
+ if (data->announce)
+ (*data->announce)(dev, data->dev);
sprintf(data->dev_name, "%s", dev);
*dev_out = data->dev_name;
- return(fd);
+
+ return fd;
}
const struct chan_ops pty_ops = {
@@ -144,14 +159,3 @@ const struct chan_ops pts_ops = {
.free = generic_free,
.winch = 0,
};
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 78f0e515da8f..c0b73c28cff0 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -85,13 +85,13 @@ static int slip_tramp(char **argv, int fd)
pe_data.stdin = fd;
pe_data.stdout = fds[1];
pe_data.close_me = fds[0];
- err = run_helper(slip_pre_exec, &pe_data, argv, NULL);
+ err = run_helper(slip_pre_exec, &pe_data, argv);
if(err < 0)
goto out_close;
pid = err;
output_len = UM_KERN_PAGE_SIZE;
- output = um_kmalloc(output_len);
+ output = kmalloc(output_len, UM_GFP_KERNEL);
if(output == NULL){
printk("slip_tramp : failed to allocate output buffer\n");
os_kill_process(pid, 1);
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
index 39f889fe9949..0e462f64f227 100644
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -42,7 +42,7 @@ static int slirp_tramp(char **argv, int fd)
pe_data.stdin = fd;
pe_data.stdout = fd;
- pid = run_helper(slirp_pre_exec, &pe_data, argv, NULL);
+ pid = run_helper(slirp_pre_exec, &pe_data, argv);
return(pid);
}
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index fd09ad9e9c0a..875d60d0c6a2 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -42,8 +42,6 @@ static struct chan_opts opts = {
.announce = ssl_announce,
.xterm_title = "Serial Line #%d",
.raw = 1,
- .tramp_stack = 0,
- .in_kernel = 1,
};
static int ssl_config(char *str, char **error_out);
@@ -99,7 +97,13 @@ static int ssl_remove(int n, char **error_out)
static int ssl_open(struct tty_struct *tty, struct file *filp)
{
- return line_open(serial_lines, tty);
+ int err = line_open(serial_lines, tty);
+
+ if (err)
+ printk(KERN_ERR "Failed to open serial line %d, err = %d\n",
+ tty->index, err);
+
+ return err;
}
#if 0
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 2bb4193ac1aa..656036e90b19 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -46,8 +46,6 @@ static struct chan_opts opts = {
.announce = stdio_announce,
.xterm_title = "Virtual Console #%d",
.raw = 1,
- .tramp_stack = 0,
- .in_kernel = 1,
};
static int con_config(char *str, char **error_out);
@@ -101,7 +99,12 @@ static int con_remove(int n, char **error_out)
static int con_open(struct tty_struct *tty, struct file *filp)
{
- return line_open(vts, tty);
+ int err = line_open(vts, tty);
+ if (err)
+ printk(KERN_ERR "Failed to open console %d, err = %d\n",
+ tty->index, err);
+
+ return err;
}
/* Set in an initcall, checked in an exitcall */
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index c07d0d562780..a9f87e19c5bf 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -29,7 +29,7 @@ static void *tty_chan_init(char *str, int device, const struct chan_opts *opts)
}
str++;
- data = um_kmalloc(sizeof(*data));
+ data = kmalloc(sizeof(*data), UM_GFP_KERNEL);
if(data == NULL)
return NULL;
*data = ((struct tty_chan) { .dev = str,
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 2e09f162c42f..fc27f6c72b41 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -712,6 +712,8 @@ static int ubd_add(int n, char **error_out)
ubd_dev->queue->queuedata = ubd_dev;
blk_queue_max_hw_segments(ubd_dev->queue, MAX_SG);
+ if(ubd_dev->cow.file != NULL)
+ blk_queue_max_sectors(ubd_dev->queue, 8 * sizeof(long));
err = ubd_disk_register(MAJOR_NR, ubd_dev->size, n, &ubd_gendisk[n]);
if(err){
*error_out = "Failed to register device";
@@ -1083,7 +1085,7 @@ static void do_ubd_request(request_queue_t *q)
{
struct io_thread_req *io_req;
struct request *req;
- int n;
+ int n, last_sectors;
while(1){
struct ubd *dev = q->queuedata;
@@ -1099,9 +1101,11 @@ static void do_ubd_request(request_queue_t *q)
}
req = dev->request;
+ last_sectors = 0;
while(dev->start_sg < dev->end_sg){
struct scatterlist *sg = &dev->sg[dev->start_sg];
+ req->sector += last_sectors;
io_req = kmalloc(sizeof(struct io_thread_req),
GFP_ATOMIC);
if(io_req == NULL){
@@ -1113,6 +1117,7 @@ static void do_ubd_request(request_queue_t *q)
(unsigned long long) req->sector << 9,
sg->offset, sg->length, sg->page);
+ last_sectors = sg->length >> 9;
n = os_write_file(thread_fd, &io_req,
sizeof(struct io_thread_req *));
if(n != sizeof(struct io_thread_req *)){
@@ -1124,7 +1129,6 @@ static void do_ubd_request(request_queue_t *q)
return;
}
- req->sector += sg->length >> 9;
dev->start_sg++;
}
dev->end_sg = 0;
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c
index 4707b3f14c2f..41d254bd38df 100644
--- a/arch/um/drivers/ubd_user.c
+++ b/arch/um/drivers/ubd_user.c
@@ -43,6 +43,12 @@ int start_io_thread(unsigned long sp, int *fd_out)
kernel_fd = fds[0];
*fd_out = fds[1];
+ err = os_set_fd_block(*fd_out, 0);
+ if (err) {
+ printk("start_io_thread - failed to set nonblocking I/O.\n");
+ goto out_close;
+ }
+
pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD,
NULL);
if(pid < 0){
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index 571c2b3325d5..fd817e541543 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -1,22 +1,20 @@
/*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include <stdio.h>
#include <stdlib.h>
+#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <termios.h>
-#include <signal.h>
-#include <sched.h>
-#include <sys/socket.h>
-#include "kern_util.h"
#include "chan_user.h"
-#include "user.h"
#include "os.h"
+#include "init.h"
+#include "user.h"
#include "xterm.h"
+#include "kern_constants.h"
struct xterm_chan {
int pid;
@@ -25,25 +23,21 @@ struct xterm_chan {
int device;
int raw;
struct termios tt;
- unsigned long stack;
- int direct_rcv;
};
-/* Not static because it's called directly by the tt mode gdb code */
-void *xterm_init(char *str, int device, const struct chan_opts *opts)
+static void *xterm_init(char *str, int device, const struct chan_opts *opts)
{
struct xterm_chan *data;
data = malloc(sizeof(*data));
- if(data == NULL) return(NULL);
- *data = ((struct xterm_chan) { .pid = -1,
+ if (data == NULL)
+ return NULL;
+ *data = ((struct xterm_chan) { .pid = -1,
.helper_pid = -1,
- .device = device,
+ .device = device,
.title = opts->xterm_title,
- .raw = opts->raw,
- .stack = opts->tramp_stack,
- .direct_rcv = !opts->in_kernel } );
- return(data);
+ .raw = opts->raw } );
+ return data;
}
/* Only changed by xterm_setup, which is a setup */
@@ -57,16 +51,22 @@ static int __init xterm_setup(char *line, int *add)
terminal_emulator = line;
line = strchr(line, ',');
- if(line == NULL) return(0);
+ if (line == NULL)
+ return 0;
+
*line++ = '\0';
- if(*line) title_switch = line;
+ if (*line)
+ title_switch = line;
line = strchr(line, ',');
- if(line == NULL) return(0);
+ if (line == NULL)
+ return 0;
+
*line++ = '\0';
- if(*line) exec_switch = line;
+ if (*line)
+ exec_switch = line;
- return(0);
+ return 0;
}
__uml_setup("xterm=", xterm_setup,
@@ -82,107 +82,128 @@ __uml_setup("xterm=", xterm_setup,
" are 'xterm=gnome-terminal,-t,-x'.\n\n"
);
-/* XXX This badly needs some cleaning up in the error paths
- * Not static because it's called directly by the tt mode gdb code
- */
-int xterm_open(int input, int output, int primary, void *d,
+static int xterm_open(int input, int output, int primary, void *d,
char **dev_out)
{
struct xterm_chan *data = d;
- unsigned long stack;
int pid, fd, new, err;
char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
- char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
+ char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
"/usr/lib/uml/port-helper", "-uml-socket",
file, NULL };
- if(os_access(argv[4], OS_ACC_X_OK) < 0)
+ if (access(argv[4], X_OK) < 0)
argv[4] = "port-helper";
/* Check that DISPLAY is set, this doesn't guarantee the xterm
* will work but w/o it we can be pretty sure it won't. */
- if (!getenv("DISPLAY")) {
- printk("xterm_open: $DISPLAY not set.\n");
+ if (getenv("DISPLAY") == NULL) {
+ printk(UM_KERN_ERR "xterm_open: $DISPLAY not set.\n");
return -ENODEV;
}
+ /*
+ * This business of getting a descriptor to a temp file,
+ * deleting the file and closing the descriptor is just to get
+ * a known-unused name for the Unix socket that we really
+ * want.
+ */
fd = mkstemp(file);
- if(fd < 0){
+ if (fd < 0) {
err = -errno;
- printk("xterm_open : mkstemp failed, errno = %d\n", errno);
+ printk(UM_KERN_ERR "xterm_open : mkstemp failed, errno = %d\n",
+ errno);
return err;
}
- if(unlink(file)){
+ if (unlink(file)) {
err = -errno;
- printk("xterm_open : unlink failed, errno = %d\n", errno);
+ printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n",
+ errno);
return err;
}
- os_close_file(fd);
+ close(fd);
fd = os_create_unix_socket(file, sizeof(file), 1);
- if(fd < 0){
- printk("xterm_open : create_unix_socket failed, errno = %d\n",
- -fd);
- return(fd);
+ if (fd < 0) {
+ printk(UM_KERN_ERR "xterm_open : create_unix_socket failed, "
+ "errno = %d\n", -fd);
+ return fd;
}
sprintf(title, data->title, data->device);
- stack = data->stack;
- pid = run_helper(NULL, NULL, argv, &stack);
- if(pid < 0){
- printk("xterm_open : run_helper failed, errno = %d\n", -pid);
- return(pid);
+ pid = run_helper(NULL, NULL, argv);
+ if (pid < 0) {
+ err = pid;
+ printk(UM_KERN_ERR "xterm_open : run_helper failed, "
+ "errno = %d\n", -err);
+ goto out_close1;
}
- if (data->direct_rcv) {
- new = os_rcv_fd(fd, &data->helper_pid);
- } else {
- err = os_set_fd_block(fd, 0);
- if(err < 0){
- printk("xterm_open : failed to set descriptor "
- "non-blocking, err = %d\n", -err);
- return(err);
- }
- new = xterm_fd(fd, &data->helper_pid);
+ err = os_set_fd_block(fd, 0);
+ if (err < 0) {
+ printk(UM_KERN_ERR "xterm_open : failed to set descriptor "
+ "non-blocking, err = %d\n", -err);
+ goto out_kill;
}
- if(new < 0){
- printk("xterm_open : os_rcv_fd failed, err = %d\n", -new);
- goto out;
+
+ new = xterm_fd(fd, &data->helper_pid);
+ if (new < 0) {
+ err = new;
+ printk(UM_KERN_ERR "xterm_open : os_rcv_fd failed, err = %d\n",
+ -err);
+ goto out_kill;
+ }
+
+ err = os_set_fd_block(new, 0);
+ if (err) {
+ printk(UM_KERN_ERR "xterm_open : failed to set xterm "
+ "descriptor non-blocking, err = %d\n", -err);
+ goto out_close2;
}
CATCH_EINTR(err = tcgetattr(new, &data->tt));
- if(err){
+ if (err) {
new = err;
- goto out;
+ goto out_close2;
}
- if(data->raw){
+ if (data->raw) {
err = raw(new);
- if(err){
+ if (err) {
new = err;
- goto out;
+ goto out_close2;
}
}
+ unlink(file);
data->pid = pid;
*dev_out = NULL;
- out:
- unlink(file);
- return(new);
+
+ return new;
+
+ out_close2:
+ close(new);
+ out_kill:
+ os_kill_process(pid, 1);
+ out_close1:
+ close(fd);
+
+ return err;
}
-/* Not static because it's called directly by the tt mode gdb code */
-void xterm_close(int fd, void *d)
+static void xterm_close(int fd, void *d)
{
struct xterm_chan *data = d;
- if(data->pid != -1)
+ if (data->pid != -1)
os_kill_process(data->pid, 1);
data->pid = -1;
- if(data->helper_pid != -1)
+
+ if (data->helper_pid != -1)
os_kill_process(data->helper_pid, 0);
data->helper_pid = -1;
+
os_close_file(fd);
}
@@ -203,14 +224,3 @@ const struct chan_ops xterm_ops = {
.free = xterm_free,
.winch = 1,
};
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index a4ce7058e10e..b646bccef37a 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -1,18 +1,14 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
-#include "linux/errno.h"
-#include "linux/slab.h"
-#include "linux/signal.h"
-#include "linux/interrupt.h"
-#include "asm/irq.h"
-#include "irq_user.h"
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/irqreturn.h>
+#include <asm/irq.h>
#include "irq_kern.h"
-#include "kern_util.h"
#include "os.h"
-#include "xterm.h"
struct xterm_wait {
struct completion ready;
@@ -27,12 +23,13 @@ static irqreturn_t xterm_interrupt(int irq, void *data)
int fd;
fd = os_rcv_fd(xterm->fd, &xterm->pid);
- if(fd == -EAGAIN)
- return(IRQ_NONE);
+ if (fd == -EAGAIN)
+ return IRQ_NONE;
xterm->new_fd = fd;
complete(&xterm->ready);
- return(IRQ_HANDLED);
+
+ return IRQ_HANDLED;
}
int xterm_fd(int socket, int *pid_out)
@@ -41,22 +38,21 @@ int xterm_fd(int socket, int *pid_out)
int err, ret;
data = kmalloc(sizeof(*data), GFP_KERNEL);
- if(data == NULL){
+ if (data == NULL) {
printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n");
- return(-ENOMEM);
+ return -ENOMEM;
}
/* This is a locked semaphore... */
- *data = ((struct xterm_wait)
- { .fd = socket,
- .pid = -1,
- .new_fd = -1 });
+ *data = ((struct xterm_wait) { .fd = socket,
+ .pid = -1,
+ .new_fd = -1 });
init_completion(&data->ready);
- err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
+ err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
"xterm", data);
- if (err){
+ if (err) {
printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
"err = %d\n", err);
ret = err;
@@ -76,16 +72,5 @@ int xterm_fd(int socket, int *pid_out)
out:
kfree(data);
- return(ret);
+ return ret;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
index c4b41bb1035f..624b5100a3cd 100644
--- a/arch/um/include/chan_kern.h
+++ b/arch/um/include/chan_kern.h
@@ -40,7 +40,7 @@ extern int console_open_chan(struct line *line, struct console *co);
extern void deactivate_chan(struct list_head *chans, int irq);
extern void reactivate_chan(struct list_head *chans, int irq);
extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
-extern void enable_chan(struct line *line);
+extern int enable_chan(struct line *line);
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,
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
index 38f16d812e7c..5a2263e05bb2 100644
--- a/arch/um/include/chan_user.h
+++ b/arch/um/include/chan_user.h
@@ -12,8 +12,6 @@ struct chan_opts {
void (*const announce)(char *dev_name, int dev);
char *xterm_title;
const int raw;
- const unsigned long tramp_stack;
- const int in_kernel;
};
enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
@@ -44,7 +42,8 @@ extern void generic_free(void *data);
struct tty_struct;
extern void register_winch(int fd, struct tty_struct *tty);
-extern void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty);
+extern void register_winch_irq(int fd, int tty_fd, int pid,
+ struct tty_struct *tty, unsigned long stack);
#define __channel_help(fn, prefix) \
__uml_help(fn, prefix "[0-9]*=<channel description>\n" \
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 7376ee44e330..6eee343e53eb 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -27,6 +27,9 @@ DEFINE(UM_ELFCLASS64, ELFCLASS64);
DEFINE(UM_NR_CPUS, NR_CPUS);
+DEFINE(UM_GFP_KERNEL, GFP_KERNEL);
+DEFINE(UM_GFP_ATOMIC, GFP_ATOMIC);
+
/* For crypto assembler code. */
DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 4d9fb26387d5..930b261ea483 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -239,11 +239,9 @@ extern unsigned long __do_user_copy(void *to, const void *from, int n,
/* execvp.c */
extern int execvp_noalloc(char *buf, const char *file, char *const argv[]);
/* helper.c */
-extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
- unsigned long *stack_out);
+extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv);
extern int run_helper_thread(int (*proc)(void *), void *arg,
- unsigned int flags, unsigned long *stack_out,
- int stack_order);
+ unsigned int flags, unsigned long *stack_out);
extern int helper_wait(int pid);
diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h
index e6d7c5aa3f4e..0ad17cb83d96 100644
--- a/arch/um/include/um_malloc.h
+++ b/arch/um/include/um_malloc.h
@@ -6,11 +6,17 @@
#ifndef __UM_MALLOC_H__
#define __UM_MALLOC_H__
-extern void *um_kmalloc(int size);
-extern void *um_kmalloc_atomic(int size);
+#include "kern_constants.h"
+
+extern void *__kmalloc(int size, int flags);
+static inline void *kmalloc(int size, int flags)
+{
+ return __kmalloc(size, flags);
+}
+
extern void kfree(const void *ptr);
-extern void *um_vmalloc(int size);
+extern void *vmalloc(unsigned long size);
extern void vfree(void *ptr);
#endif /* __UM_MALLOC_H__ */
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index dba04d88b432..9870febdbead 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -30,7 +30,6 @@
#include "irq_kern.h"
#include "os.h"
#include "sigio.h"
-#include "um_malloc.h"
#include "misc_constants.h"
#include "as-layout.h"
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 8d2c5496532b..bfa52f206bb6 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -46,7 +46,6 @@
#include "mode.h"
#include "mode_kern.h"
#include "choose-mode.h"
-#include "um_malloc.h"
/* This is a per-cpu array. A processor only modifies its entry and it only
* cares about its entry, so it's OK if another processor is modifying its
@@ -262,21 +261,6 @@ void dump_thread(struct pt_regs *regs, struct user *u)
{
}
-void *um_kmalloc(int size)
-{
- return kmalloc(size, GFP_KERNEL);
-}
-
-void *um_kmalloc_atomic(int size)
-{
- return kmalloc(size, GFP_ATOMIC);
-}
-
-void *um_vmalloc(int size)
-{
- return vmalloc(size);
-}
-
int __cant_sleep(void) {
return in_atomic() || irqs_disabled() || in_interrupt();
/* Is in_interrupt() really needed? */
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
index 627742d89434..6916c8888dba 100644
--- a/arch/um/kernel/ptrace.c
+++ b/arch/um/kernel/ptrace.c
@@ -52,17 +52,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- ret = -EIO;
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp, p);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR:
@@ -72,11 +64,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = -EIO;
- if (access_process_vm(child, addr, &data, sizeof(data),
- 1) != sizeof(data))
- break;
- ret = 0;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index abab90c3803f..3850d53f79fd 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -76,23 +76,24 @@ good_area:
goto out;
do {
+ int fault;
survive:
- switch (handle_mm_fault(mm, vma, address, is_write)){
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- err = -EACCES;
- goto out;
- case VM_FAULT_OOM:
- err = -ENOMEM;
- goto out_of_memory;
- default:
+ fault = handle_mm_fault(mm, vma, address, is_write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM) {
+ err = -ENOMEM;
+ goto out_of_memory;
+ } else if (fault & VM_FAULT_SIGBUS) {
+ err = -EACCES;
+ goto out;
+ }
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
+
pgd = pgd_offset(mm, address);
pud = pud_offset(pgd, address);
pmd = pmd_offset(pud, address);
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c
index 9bf944f6a1db..b126df4ea168 100644
--- a/arch/um/os-Linux/aio.c
+++ b/arch/um/os-Linux/aio.c
@@ -177,6 +177,7 @@ static int do_not_aio(struct aio_thread_req *req)
static int aio_req_fd_r = -1;
static int aio_req_fd_w = -1;
static int aio_pid = -1;
+static unsigned long aio_stack;
static int not_aio_thread(void *arg)
{
@@ -212,7 +213,6 @@ static int not_aio_thread(void *arg)
static int init_aio_24(void)
{
- unsigned long stack;
int fds[2], err;
err = os_pipe(fds, 1, 1);
@@ -227,7 +227,7 @@ static int init_aio_24(void)
goto out_close_pipe;
err = run_helper_thread(not_aio_thread, NULL,
- CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ CLONE_FILES | CLONE_VM | SIGCHLD, &aio_stack);
if(err < 0)
goto out_close_pipe;
@@ -252,7 +252,6 @@ out:
#define DEFAULT_24_AIO 0
static int init_aio_26(void)
{
- unsigned long stack;
int err;
if(io_setup(256, &ctx)){
@@ -263,7 +262,7 @@ static int init_aio_26(void)
}
err = run_helper_thread(aio_thread, NULL,
- CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0);
+ CLONE_FILES | CLONE_VM | SIGCHLD, &aio_stack);
if(err < 0)
return err;
@@ -365,8 +364,10 @@ __initcall(init_aio);
static void exit_aio(void)
{
- if(aio_pid != -1)
+ if (aio_pid != -1) {
os_kill_process(aio_pid, 1);
+ free_stack(aio_stack, 0);
+ }
}
__uml_exitcall(exit_aio);
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index acba30161287..61d3953c7ac9 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -54,7 +54,7 @@ static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
return;
}
- output = um_kmalloc(UM_KERN_PAGE_SIZE);
+ output = kmalloc(UM_KERN_PAGE_SIZE, UM_GFP_KERNEL);
if(output == NULL)
printk("etap_change : Failed to allocate output buffer\n");
read_output(fd, output, UM_KERN_PAGE_SIZE);
@@ -117,7 +117,7 @@ static int etap_tramp(char *dev, char *gate, int control_me,
pe_data.control_remote = control_remote;
pe_data.control_me = control_me;
pe_data.data_me = data_me;
- pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
+ pid = run_helper(etap_pre_exec, &pe_data, args);
if(pid < 0)
err = pid;
@@ -166,7 +166,7 @@ static int etap_open(void *data)
err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
control_fds[1], data_fds[0], data_fds[1]);
output_len = UM_KERN_PAGE_SIZE;
- output = um_kmalloc(output_len);
+ output = kmalloc(output_len, UM_GFP_KERNEL);
read_output(control_fds[0], output, output_len);
if(output == NULL)
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
index 11a9779dc9f1..f848b4ea9343 100644
--- a/arch/um/os-Linux/drivers/tuntap_user.c
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -83,7 +83,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
data.stdout = remote;
data.close_me = me;
- pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
+ pid = run_helper(tuntap_pre_exec, &data, argv);
if(pid < 0)
return -pid;
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index 97bed16bf4c7..d81af7b8587a 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -44,17 +44,13 @@ static int helper_child(void *arg)
/* Returns either the pid of the child process we run or -E* on failure.
* XXX The alloc_stack here breaks if this is called in the tracing thread, so
* we need to receive a preallocated stack (a local buffer is ok). */
-int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
- unsigned long *stack_out)
+int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv)
{
struct helper_data data;
unsigned long stack, sp;
int pid, fds[2], ret, n;
- if ((stack_out != NULL) && (*stack_out != 0))
- stack = *stack_out;
- else
- stack = alloc_stack(0, __cant_sleep());
+ stack = alloc_stack(0, __cant_sleep());
if (stack == 0)
return -ENOMEM;
@@ -76,8 +72,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
data.pre_data = pre_data;
data.argv = argv;
data.fd = fds[1];
- data.buf = __cant_sleep() ? um_kmalloc_atomic(PATH_MAX) :
- um_kmalloc(PATH_MAX);
+ data.buf = __cant_sleep() ? kmalloc(PATH_MAX, UM_GFP_ATOMIC) :
+ kmalloc(PATH_MAX, UM_GFP_KERNEL);
pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
if (pid < 0) {
ret = -errno;
@@ -113,22 +109,21 @@ out_close:
close(fds[1]);
close(fds[0]);
out_free:
- if ((stack_out == NULL) || (*stack_out == 0))
- free_stack(stack, 0);
+ free_stack(stack, 0);
return ret;
}
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
- unsigned long *stack_out, int stack_order)
+ unsigned long *stack_out)
{
unsigned long stack, sp;
int pid, status, err;
- stack = alloc_stack(stack_order, __cant_sleep());
+ stack = alloc_stack(0, __cant_sleep());
if (stack == 0)
return -ENOMEM;
- sp = stack + (UM_KERN_PAGE_SIZE << stack_order) - sizeof(void *);
+ sp = stack + UM_KERN_PAGE_SIZE - sizeof(void *);
pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
if (pid < 0) {
err = -errno;
@@ -147,7 +142,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
printk("run_helper_thread - thread returned status "
"0x%x\n", status);
- free_stack(stack, stack_order);
+ free_stack(stack, 0);
} else
*stack_out = stack;
return pid;
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index fb510d40480c..e85f4995a011 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -235,8 +235,8 @@ void *__wrap_malloc(int size)
return __real_malloc(size);
else if(size <= UM_KERN_PAGE_SIZE)
/* finding contiguous pages can be hard*/
- ret = um_kmalloc(size);
- else ret = um_vmalloc(size);
+ ret = kmalloc(size, UM_GFP_KERNEL);
+ else ret = vmalloc(size);
/* glibc people insist that if malloc fails, errno should be
* set by malloc as well. So we do.
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index 8d4e0c6b8c92..dc03e9cccb63 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -26,6 +26,7 @@
* exitcall.
*/
static int write_sigio_pid = -1;
+static unsigned long write_sigio_stack;
/* These arrays are initialized before the sigio thread is started, and
* the descriptors closed after it is killed. So, it can't see them change.
@@ -104,7 +105,7 @@ static int need_poll(struct pollfds *polls, int n)
if(n <= polls->size)
return 0;
- new = um_kmalloc_atomic(n * sizeof(struct pollfd));
+ new = kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC);
if(new == NULL){
printk("need_poll : failed to allocate new pollfds\n");
return -ENOMEM;
@@ -144,8 +145,10 @@ static void update_thread(void)
return;
fail:
/* Critical section start */
- if(write_sigio_pid != -1)
+ if (write_sigio_pid != -1) {
os_kill_process(write_sigio_pid, 1);
+ free_stack(write_sigio_stack, 0);
+ }
write_sigio_pid = -1;
close(sigio_private[0]);
close(sigio_private[1]);
@@ -230,7 +233,7 @@ static struct pollfd *setup_initial_poll(int fd)
{
struct pollfd *p;
- p = um_kmalloc(sizeof(struct pollfd));
+ p = kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL);
if (p == NULL) {
printk("setup_initial_poll : failed to allocate poll\n");
return NULL;
@@ -243,7 +246,6 @@ static struct pollfd *setup_initial_poll(int fd)
static void write_sigio_workaround(void)
{
- unsigned long stack;
struct pollfd *p;
int err;
int l_write_sigio_fds[2];
@@ -293,7 +295,8 @@ static void write_sigio_workaround(void)
memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private));
write_sigio_pid = run_helper_thread(write_sigio_thread, NULL,
- CLONE_FILES | CLONE_VM, &stack, 0);
+ CLONE_FILES | CLONE_VM,
+ &write_sigio_stack);
if (write_sigio_pid < 0)
goto out_clear;
@@ -356,10 +359,12 @@ out:
static void sigio_cleanup(void)
{
- if(write_sigio_pid != -1){
- os_kill_process(write_sigio_pid, 1);
- write_sigio_pid = -1;
- }
+ if (write_sigio_pid == -1)
+ return;
+
+ os_kill_process(write_sigio_pid, 1);
+ free_stack(write_sigio_stack, 0);
+ write_sigio_pid = -1;
}
__uml_exitcall(sigio_cleanup);
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 46c00cc429bc..ba9af8d62055 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -41,7 +41,7 @@ int is_skas_winch(int pid, int fd, void *data)
if(pid != os_getpgrp())
return(0);
- register_winch_irq(-1, fd, -1, data);
+ register_winch_irq(-1, fd, -1, data, 0);
return(1);
}
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
index 3f33165ada68..419b2d5ff6de 100644
--- a/arch/um/os-Linux/user_syms.c
+++ b/arch/um/os-Linux/user_syms.c
@@ -5,7 +5,8 @@
* so I *must* declare good prototypes for them and then EXPORT them.
* The kernel code uses the macro defined by include/linux/string.h,
* so I undef macros; the userspace code does not include that and I
- * add an EXPORT for the glibc one.*/
+ * add an EXPORT for the glibc one.
+ */
#undef strlen
#undef strstr
@@ -61,12 +62,18 @@ EXPORT_SYMBOL_PROTO(dup2);
EXPORT_SYMBOL_PROTO(__xstat);
EXPORT_SYMBOL_PROTO(__lxstat);
EXPORT_SYMBOL_PROTO(__lxstat64);
+EXPORT_SYMBOL_PROTO(__fxstat64);
EXPORT_SYMBOL_PROTO(lseek);
EXPORT_SYMBOL_PROTO(lseek64);
EXPORT_SYMBOL_PROTO(chown);
+EXPORT_SYMBOL_PROTO(fchown);
EXPORT_SYMBOL_PROTO(truncate);
+EXPORT_SYMBOL_PROTO(ftruncate64);
EXPORT_SYMBOL_PROTO(utime);
+EXPORT_SYMBOL_PROTO(utimes);
+EXPORT_SYMBOL_PROTO(futimes);
EXPORT_SYMBOL_PROTO(chmod);
+EXPORT_SYMBOL_PROTO(fchmod);
EXPORT_SYMBOL_PROTO(rename);
EXPORT_SYMBOL_PROTO(__xmknod);
@@ -102,14 +109,3 @@ EXPORT_SYMBOL(__stack_smash_handler);
extern long __guard __attribute__((weak));
EXPORT_SYMBOL(__guard);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c
index a9b09343097d..a458ac941b25 100644
--- a/arch/v850/kernel/ptrace.c
+++ b/arch/v850/kernel/ptrace.c
@@ -117,24 +117,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int rval;
switch (request) {
- unsigned long val, copied;
+ unsigned long val;
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:
- copied = access_process_vm(child, addr, &val, sizeof(val), 0);
- rval = -EIO;
- if (copied != sizeof(val))
- break;
- rval = put_user(val, (unsigned long *)data);
+ rval = generic_ptrace_peekdata(child, addr, data);
goto out;
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- rval = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1)
- == sizeof(data))
- break;
- rval = -EIO;
+ rval = generic_ptrace_pokedata(child, addr, data);
goto out;
/* Read/write the word at location ADDR in the registers. */
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index 5ce94430c019..45f82ae6d389 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -32,6 +32,10 @@ config GENERIC_TIME_VSYSCALL
bool
default y
+config GENERIC_CMOS_UPDATE
+ bool
+ default y
+
config ZONE_DMA32
bool
default y
@@ -56,6 +60,14 @@ config ZONE_DMA
bool
default y
+config QUICKLIST
+ bool
+ default y
+
+config NR_QUICK
+ int
+ default 2
+
config ISA
bool
@@ -427,6 +439,10 @@ config NR_CPUS
This is purely to save memory - each supported CPU requires
memory in the static kernel configuration.
+config PHYSICAL_ALIGN
+ hex
+ default "0x200000"
+
config HOTPLUG_CPU
bool "Support for suspend on SMP and hot-pluggable CPUs (EXPERIMENTAL)"
depends on SMP && HOTPLUG && EXPERIMENTAL
@@ -770,8 +786,8 @@ menu "Instrumentation Support"
source "arch/x86_64/oprofile/Kconfig"
config KPROBES
- bool "Kprobes (EXPERIMENTAL)"
- depends on KALLSYMS && EXPERIMENTAL && MODULES
+ bool "Kprobes"
+ depends on KALLSYMS && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 29617ae3926d..128561d3e876 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -76,7 +76,8 @@ head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kern
libs-y += arch/x86_64/lib/
core-y += arch/x86_64/kernel/ \
arch/x86_64/mm/ \
- arch/x86_64/crypto/
+ arch/x86_64/crypto/ \
+ arch/x86_64/vdso/
core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/
drivers-$(CONFIG_PCI) += arch/x86_64/pci/
drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/
diff --git a/arch/x86_64/boot/.gitignore b/arch/x86_64/boot/.gitignore
index 495f20c085de..18465143cfa2 100644
--- a/arch/x86_64/boot/.gitignore
+++ b/arch/x86_64/boot/.gitignore
@@ -1,3 +1,5 @@
bootsect
bzImage
setup
+setup.bin
+setup.elf
diff --git a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
index ee6f6505f95f..67096389de1f 100644
--- a/arch/x86_64/boot/Makefile
+++ b/arch/x86_64/boot/Makefile
@@ -1,135 +1,9 @@
#
# arch/x86_64/boot/Makefile
#
-# This file is subject to the terms and conditions of the GNU General Public
-# License. See the file "COPYING" in the main directory of this archive
-# for more details.
-#
-# Copyright (C) 1994 by Linus Torvalds
-#
-
-# ROOT_DEV specifies the default root-device when making the image.
-# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
-# the default of FLOPPY is used by 'build'.
-
-ROOT_DEV := CURRENT
-
-# If you want to preset the SVGA mode, uncomment the next line and
-# set SVGA_MODE to whatever number you want.
-# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode.
-# The number is the same as you would ordinarily press at bootup.
-
-SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
-
-# If you want the RAM disk device, define this to be the size in blocks.
-
-#RAMDISK := -DRAMDISK=512
-
-targets := vmlinux.bin bootsect bootsect.o \
- setup setup.o bzImage mtools.conf
-
-EXTRA_CFLAGS := -m32
-
-hostprogs-y := tools/build
-HOST_EXTRACFLAGS += $(LINUXINCLUDE)
-subdir- := compressed/ #Let make clean descend in compressed/
-# ---------------------------------------------------------------------------
-
-$(obj)/bzImage: IMAGE_OFFSET := 0x100000
-$(obj)/bzImage: EXTRA_AFLAGS := $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__
-$(obj)/bzImage: BUILDFLAGS := -b
-
-quiet_cmd_image = BUILD $@
-cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \
- $(obj)/vmlinux.bin $(ROOT_DEV) > $@
-
-$(obj)/bzImage: $(obj)/bootsect $(obj)/setup \
- $(obj)/vmlinux.bin $(obj)/tools/build FORCE
- $(call if_changed,image)
- @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
-
-$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
- $(call if_changed,objcopy)
-
-LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary
-LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext
-
-$(obj)/setup $(obj)/bootsect: %: %.o FORCE
- $(call if_changed,ld)
-
-$(obj)/compressed/vmlinux: FORCE
- $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
-
-# Set this if you want to pass append arguments to the zdisk/fdimage/isoimage kernel
-FDARGS =
-# Set this if you want an initrd included with the zdisk/fdimage/isoimage kernel
-FDINITRD =
-
-image_cmdline = default linux $(FDARGS) $(if $(FDINITRD),initrd=initrd.img,)
-
-$(obj)/mtools.conf: $(src)/mtools.conf.in
- sed -e 's|@OBJ@|$(obj)|g' < $< > $@
-
-# This requires write access to /dev/fd0
-zdisk: $(BOOTIMAGE) $(obj)/mtools.conf
- MTOOLSRC=$(obj)/mtools.conf mformat a: ; sync
- syslinux /dev/fd0 ; sync
- echo '$(image_cmdline)' | \
- MTOOLSRC=$(obj)/mtools.conf mcopy - a:syslinux.cfg
- if [ -f '$(FDINITRD)' ] ; then \
- MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' a:initrd.img ; \
- fi
- MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) a:linux ; sync
-
-# These require being root or having syslinux 2.02 or higher installed
-fdimage fdimage144: $(BOOTIMAGE) $(obj)/mtools.conf
- dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=1440
- MTOOLSRC=$(obj)/mtools.conf mformat v: ; sync
- syslinux $(obj)/fdimage ; sync
- echo '$(image_cmdline)' | \
- MTOOLSRC=$(obj)/mtools.conf mcopy - v:syslinux.cfg
- if [ -f '$(FDINITRD)' ] ; then \
- MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' v:initrd.img ; \
- fi
- MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) v:linux ; sync
-
-fdimage288: $(BOOTIMAGE) $(obj)/mtools.conf
- dd if=/dev/zero of=$(obj)/fdimage bs=1024 count=2880
- MTOOLSRC=$(obj)/mtools.conf mformat w: ; sync
- syslinux $(obj)/fdimage ; sync
- echo '$(image_cmdline)' | \
- MTOOLSRC=$(obj)/mtools.conf mcopy - w:syslinux.cfg
- if [ -f '$(FDINITRD)' ] ; then \
- MTOOLSRC=$(obj)/mtools.conf mcopy '$(FDINITRD)' w:initrd.img ; \
- fi
- MTOOLSRC=$(obj)/mtools.conf mcopy $(BOOTIMAGE) w:linux ; sync
-
-isoimage: $(BOOTIMAGE)
- -rm -rf $(obj)/isoimage
- mkdir $(obj)/isoimage
- for i in lib lib64 share end ; do \
- if [ -f /usr/$$i/syslinux/isolinux.bin ] ; then \
- cp /usr/$$i/syslinux/isolinux.bin $(obj)/isoimage ; \
- break ; \
- fi ; \
- if [ $$i = end ] ; then exit 1 ; fi ; \
- done
- cp $(BOOTIMAGE) $(obj)/isoimage/linux
- echo '$(image_cmdline)' > $(obj)/isoimage/isolinux.cfg
- if [ -f '$(FDINITRD)' ] ; then \
- cp '$(FDINITRD)' $(obj)/isoimage/initrd.img ; \
- fi
- mkisofs -J -r -o $(obj)/image.iso -b isolinux.bin -c boot.cat \
- -no-emul-boot -boot-load-size 4 -boot-info-table \
- $(obj)/isoimage
- rm -rf $(obj)/isoimage
-
-zlilo: $(BOOTIMAGE)
- if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
- if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
- cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
- cp System.map $(INSTALL_PATH)/
- if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
+# The actual boot code is shared with i386 including the Makefile.
+# So tell kbuild that we fetch the code from i386 and include the
+# Makefile from i386 too.
-install:
- sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
+src := arch/i386/boot
+include $(src)/Makefile
diff --git a/arch/x86_64/boot/bootsect.S b/arch/x86_64/boot/bootsect.S
deleted file mode 100644
index 011b7a4993d4..000000000000
--- a/arch/x86_64/boot/bootsect.S
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds
- *
- * modified by Drew Eckhardt
- * modified by Bruce Evans (bde)
- * modified by Chris Noe (May 1999) (as86 -> gas)
- * gutted by H. Peter Anvin (Jan 2003)
- *
- * BIG FAT NOTE: We're in real mode using 64k segments. Therefore segment
- * addresses must be multiplied by 16 to obtain their respective linear
- * addresses. To avoid confusion, linear addresses are written using leading
- * hex while segment addresses are written as segment:offset.
- *
- */
-
-#include <asm/boot.h>
-
-SETUPSECTS = 4 /* default nr of setup-sectors */
-BOOTSEG = 0x07C0 /* original address of boot-sector */
-INITSEG = DEF_INITSEG /* we move boot here - out of the way */
-SETUPSEG = DEF_SETUPSEG /* setup starts here */
-SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */
-SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */
- /* to be loaded */
-ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */
-SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */
-
-#ifndef SVGA_MODE
-#define SVGA_MODE ASK_VGA
-#endif
-
-#ifndef RAMDISK
-#define RAMDISK 0
-#endif
-
-#ifndef ROOT_RDONLY
-#define ROOT_RDONLY 1
-#endif
-
-.code16
-.text
-
-.global _start
-_start:
-
- # Normalize the start address
- jmpl $BOOTSEG, $start2
-
-start2:
- movw %cs, %ax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %ss
- movw $0x7c00, %sp
- sti
- cld
-
- movw $bugger_off_msg, %si
-
-msg_loop:
- lodsb
- andb %al, %al
- jz die
- movb $0xe, %ah
- movw $7, %bx
- int $0x10
- jmp msg_loop
-
-die:
- # Allow the user to press a key, then reboot
- xorw %ax, %ax
- int $0x16
- int $0x19
-
- # int 0x19 should never return. In case it does anyway,
- # invoke the BIOS reset code...
- ljmp $0xf000,$0xfff0
-
-
-bugger_off_msg:
- .ascii "Direct booting from floppy is no longer supported.\r\n"
- .ascii "Please use a boot loader program instead.\r\n"
- .ascii "\n"
- .ascii "Remove disk and press any key to reboot . . .\r\n"
- .byte 0
-
-
- # Kernel attributes; used by setup
-
- .org 497
-setup_sects: .byte SETUPSECTS
-root_flags: .word ROOT_RDONLY
-syssize: .word SYSSIZE
-swap_dev: .word SWAP_DEV
-ram_size: .word RAMDISK
-vid_mode: .word SVGA_MODE
-root_dev: .word ROOT_DEV
-boot_flag: .word 0xAA55
diff --git a/arch/x86_64/boot/compressed/Makefile b/arch/x86_64/boot/compressed/Makefile
index 705a3e33d7e1..877c0bdbbc67 100644
--- a/arch/x86_64/boot/compressed/Makefile
+++ b/arch/x86_64/boot/compressed/Makefile
@@ -3,15 +3,14 @@
#
# create a compressed vmlinux image from the original vmlinux
#
-# Note all the files here are compiled/linked as 32bit executables.
-#
targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
-EXTRA_AFLAGS := -traditional
-# cannot use EXTRA_CFLAGS because base CFLAGS contains -mkernel which conflicts with
-# -m32
-CFLAGS := -m64 -D__KERNEL__ -Iinclude -O2 -fno-strict-aliasing -fPIC -mcmodel=small -fno-builtin
+CFLAGS := -m64 -D__KERNEL__ $(LINUXINCLUDE) -O2 \
+ -fno-strict-aliasing -fPIC -mcmodel=small \
+ $(call cc-option, -ffreestanding) \
+ $(call cc-option, -fno-stack-protector)
+AFLAGS := $(CFLAGS) -D__ASSEMBLY__
LDFLAGS := -m elf_x86_64
LDFLAGS_vmlinux := -T
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S
index f9d5692a0106..1312bfaff306 100644
--- a/arch/x86_64/boot/compressed/head.S
+++ b/arch/x86_64/boot/compressed/head.S
@@ -46,10 +46,10 @@ startup_32:
* at and where we were actually loaded at. This can only be done
* with a short local call on x86. Nothing else will tell us what
* address we are running at. The reserved chunk of the real-mode
- * data at 0x34-0x3f are used as the stack for this calculation.
- * Only 4 bytes are needed.
+ * data at 0x1e4 (defined as a scratch field) are used as the stack
+ * for this calculation. Only 4 bytes are needed.
*/
- leal 0x40(%esi), %esp
+ leal (0x1e4+4)(%esi), %esp
call 1f
1: popl %ebp
subl $1b, %ebp
diff --git a/arch/x86_64/boot/install.sh b/arch/x86_64/boot/install.sh
deleted file mode 100644
index baaa2369bdb8..000000000000
--- a/arch/x86_64/boot/install.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-. $srctree/arch/i386/boot/install.sh
diff --git a/arch/x86_64/boot/mtools.conf.in b/arch/x86_64/boot/mtools.conf.in
deleted file mode 100644
index efd6d2490c1d..000000000000
--- a/arch/x86_64/boot/mtools.conf.in
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# mtools configuration file for "make (b)zdisk"
-#
-
-# Actual floppy drive
-drive a:
- file="/dev/fd0"
-
-# 1.44 MB floppy disk image
-drive v:
- file="@OBJ@/fdimage" cylinders=80 heads=2 sectors=18 filter
-
-# 2.88 MB floppy disk image (mostly for virtual uses)
-drive w:
- file="@OBJ@/fdimage" cylinders=80 heads=2 sectors=36 filter
-
-
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
deleted file mode 100644
index e9e33f949697..000000000000
--- a/arch/x86_64/boot/setup.S
+++ /dev/null
@@ -1,826 +0,0 @@
-/*
- * setup.S Copyright (C) 1991, 1992 Linus Torvalds
- *
- * setup.s is responsible for getting the system data from the BIOS,
- * and putting them into the appropriate places in system memory.
- * both setup.s and system has been loaded by the bootblock.
- *
- * This code asks the bios for memory/disk/other parameters, and
- * puts them in a "safe" place: 0x90000-0x901FF, ie where the
- * boot-block used to be. It is then up to the protected mode
- * system to read them from there before the area is overwritten
- * for buffer-blocks.
- *
- * Move PS/2 aux init code to psaux.c
- * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92
- *
- * some changes and additional features by Christoph Niemann,
- * March 1993/June 1994 (Christoph.Niemann@linux.org)
- *
- * add APM BIOS checking by Stephen Rothwell, May 1994
- * (sfr@canb.auug.org.au)
- *
- * High load stuff, initrd support and position independency
- * by Hans Lermen & Werner Almesberger, February 1996
- * <lermen@elserv.ffm.fgan.de>, <almesber@lrc.epfl.ch>
- *
- * Video handling moved to video.S by Martin Mares, March 1996
- * <mj@k332.feld.cvut.cz>
- *
- * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david
- * parsons) to avoid loadlin confusion, July 1997
- *
- * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
- * <stiker@northlink.com>
- *
- * Fix to work around buggy BIOSes which don't use carry bit correctly
- * and/or report extended memory in CX/DX for e801h memory size detection
- * call. As a result the kernel got wrong figures. The int15/e801h docs
- * from Ralf Brown interrupt list seem to indicate AX/BX should be used
- * anyway. So to avoid breaking many machines (presumably there was a reason
- * to orginally use CX/DX instead of AX/BX), we do a kludge to see
- * if CX/DX have been changed in the e801 call and if so use AX/BX .
- * Michael Miller, April 2001 <michaelm@mjmm.org>
- *
- * Added long mode checking and SSE force. March 2003, Andi Kleen.
- */
-
-#include <asm/segment.h>
-#include <linux/utsrelease.h>
-#include <linux/compile.h>
-#include <asm/boot.h>
-#include <asm/e820.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-
-/* Signature words to ensure LILO loaded us right */
-#define SIG1 0xAA55
-#define SIG2 0x5A5A
-
-INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way
-SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536).
-SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment
- # ... and the former contents of CS
-
-DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020
-
-.code16
-.globl begtext, begdata, begbss, endtext, enddata, endbss
-
-.text
-begtext:
-.data
-begdata:
-.bss
-begbss:
-.text
-
-start:
- jmp trampoline
-
-# This is the setup header, and it must start at %cs:2 (old 0x9020:2)
-
- .ascii "HdrS" # header signature
- .word 0x0206 # header version number (>= 0x0105)
- # or else old loadlin-1.5 will fail)
-realmode_swtch: .word 0, 0 # default_switch, SETUPSEG
-start_sys_seg: .word SYSSEG
- .word kernel_version # pointing to kernel version string
- # above section of header is compatible
- # with loadlin-1.5 (header v1.5). Don't
- # change it.
-
-type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin,
- # Bootlin, SYSLX, bootsect...)
- # See Documentation/i386/boot.txt for
- # assigned ids
-
-# flags, unused bits must be zero (RFU) bit within loadflags
-loadflags:
-LOADED_HIGH = 1 # If set, the kernel is loaded high
-CAN_USE_HEAP = 0x80 # If set, the loader also has set
- # heap_end_ptr to tell how much
- # space behind setup.S can be used for
- # heap purposes.
- # Only the loader knows what is free
-#ifndef __BIG_KERNEL__
- .byte 0
-#else
- .byte LOADED_HIGH
-#endif
-
-setup_move_size: .word 0x8000 # size to move, when setup is not
- # loaded at 0x90000. We will move setup
- # to 0x90000 then just before jumping
- # into the kernel. However, only the
- # loader knows how much data behind
- # us also needs to be loaded.
-
-code32_start: # here loaders can put a different
- # start address for 32-bit code.
-#ifndef __BIG_KERNEL__
- .long 0x1000 # 0x1000 = default for zImage
-#else
- .long 0x100000 # 0x100000 = default for big kernel
-#endif
-
-ramdisk_image: .long 0 # address of loaded ramdisk image
- # Here the loader puts the 32-bit
- # address where it loaded the image.
- # This only will be read by the kernel.
-
-ramdisk_size: .long 0 # its size in bytes
-
-bootsect_kludge:
- .long 0 # obsolete
-
-heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later)
- # space from here (exclusive) down to
- # end of setup code can be used by setup
- # for local heap purposes.
-
-pad1: .word 0
-cmd_line_ptr: .long 0 # (Header version 0x0202 or later)
- # If nonzero, a 32-bit pointer
- # to the kernel command line.
- # The command line should be
- # located between the start of
- # setup and the end of low
- # memory (0xa0000), or it may
- # get overwritten before it
- # gets read. If this field is
- # used, there is no longer
- # anything magical about the
- # 0x90000 segment; the setup
- # can be located anywhere in
- # low memory 0x10000 or higher.
-
-ramdisk_max: .long 0xffffffff
-kernel_alignment: .long 0x200000 # physical addr alignment required for
- # protected mode relocatable kernel
-#ifdef CONFIG_RELOCATABLE
-relocatable_kernel: .byte 1
-#else
-relocatable_kernel: .byte 0
-#endif
-pad2: .byte 0
-pad3: .word 0
-
-cmdline_size: .long COMMAND_LINE_SIZE-1 #length of the command line,
- #added with boot protocol
- #version 2.06
-
-trampoline: call start_of_setup
- .align 16
- # The offset at this point is 0x240
- .space (0xeff-0x240+1) # E820 & EDD space (ending at 0xeff)
-# End of setup header #####################################################
-
-start_of_setup:
-# Bootlin depends on this being done early
- movw $0x01500, %ax
- movb $0x81, %dl
- int $0x13
-
-#ifdef SAFE_RESET_DISK_CONTROLLER
-# Reset the disk controller.
- movw $0x0000, %ax
- movb $0x80, %dl
- int $0x13
-#endif
-
-# Set %ds = %cs, we know that SETUPSEG = %cs at this point
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-# Check signature at end of setup
- cmpw $SIG1, setup_sig1
- jne bad_sig
-
- cmpw $SIG2, setup_sig2
- jne bad_sig
-
- jmp good_sig1
-
-# Routine to print asciiz string at ds:si
-prtstr:
- lodsb
- andb %al, %al
- jz fin
-
- call prtchr
- jmp prtstr
-
-fin: ret
-
-# Space printing
-prtsp2: call prtspc # Print double space
-prtspc: movb $0x20, %al # Print single space (note: fall-thru)
-
-prtchr:
- pushw %ax
- pushw %cx
- movw $0007,%bx
- movw $0x01, %cx
- movb $0x0e, %ah
- int $0x10
- popw %cx
- popw %ax
- ret
-
-beep: movb $0x07, %al
- jmp prtchr
-
-no_sig_mess: .string "No setup signature found ..."
-
-good_sig1:
- jmp good_sig
-
-# We now have to find the rest of the setup code/data
-bad_sig:
- movw %cs, %ax # SETUPSEG
- subw $DELTA_INITSEG, %ax # INITSEG
- movw %ax, %ds
- xorb %bh, %bh
- movb (497), %bl # get setup sect from bootsect
- subw $4, %bx # LILO loads 4 sectors of setup
- shlw $8, %bx # convert to words (1sect=2^8 words)
- movw %bx, %cx
- shrw $3, %bx # convert to segment
- addw $SYSSEG, %bx
- movw %bx, %cs:start_sys_seg
-# Move rest of setup code/data to here
- movw $2048, %di # four sectors loaded by LILO
- subw %si, %si
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %es
- movw $SYSSEG, %ax
- movw %ax, %ds
- rep
- movsw
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
- cmpw $SIG1, setup_sig1
- jne no_sig
-
- cmpw $SIG2, setup_sig2
- jne no_sig
-
- jmp good_sig
-
-no_sig:
- lea no_sig_mess, %si
- call prtstr
-
-no_sig_loop:
- jmp no_sig_loop
-
-good_sig:
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %ds
-# Check if an old loader tries to load a big-kernel
- testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel?
- jz loader_ok # No, no danger for old loaders.
-
- cmpb $0, %cs:type_of_loader # Do we have a loader that
- # can deal with us?
- jnz loader_ok # Yes, continue.
-
- pushw %cs # No, we have an old loader,
- popw %ds # die.
- lea loader_panic_mess, %si
- call prtstr
-
- jmp no_sig_loop
-
-loader_panic_mess: .string "Wrong loader, giving up..."
-
-loader_ok:
- /* check for long mode. */
- /* we have to do this before the VESA setup, otherwise the user
- can't see the error message. */
-
- pushw %ds
- movw %cs,%ax
- movw %ax,%ds
-
- call verify_cpu
- testl %eax,%eax
- jz sse_ok
-
-no_longmode:
- call beep
- lea long_mode_panic,%si
- call prtstr
-no_longmode_loop:
- jmp no_longmode_loop
-long_mode_panic:
- .string "Your CPU does not support long mode. Use a 32bit distribution."
- .byte 0
-
-#include "../kernel/verify_cpu.S"
-sse_ok:
- popw %ds
-
-# tell BIOS we want to go to long mode
- movl $0xec00,%eax # declare target operating mode
- movl $2,%ebx # long mode
- int $0x15
-
-# Get memory size (extended mem, kB)
-
- xorl %eax, %eax
- movl %eax, (0x1e0)
-#ifndef STANDARD_MEMORY_BIOS_CALL
- movb %al, (E820NR)
-# Try three different memory detection schemes. First, try
-# e820h, which lets us assemble a memory map, then try e801h,
-# which returns a 32-bit memory size, and finally 88h, which
-# returns 0-64m
-
-# method E820H:
-# the memory map from hell. e820h returns memory classified into
-# a whole bunch of different types, and allows memory holes and
-# everything. We scan through this memory map and build a list
-# of the first 32 memory areas, which we return at [E820MAP].
-# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
-
-#define SMAP 0x534d4150
-
-meme820:
- xorl %ebx, %ebx # continuation counter
- movw $E820MAP, %di # point into the whitelist
- # so we can have the bios
- # directly write into it.
-
-jmpe820:
- movl $0x0000e820, %eax # e820, upper word zeroed
- movl $SMAP, %edx # ascii 'SMAP'
- movl $20, %ecx # size of the e820rec
- pushw %ds # data record.
- popw %es
- int $0x15 # make the call
- jc bail820 # fall to e801 if it fails
-
- cmpl $SMAP, %eax # check the return is `SMAP'
- jne bail820 # fall to e801 if it fails
-
-# cmpl $1, 16(%di) # is this usable memory?
-# jne again820
-
- # If this is usable memory, we save it by simply advancing %di by
- # sizeof(e820rec).
- #
-good820:
- movb (E820NR), %al # up to 128 entries
- cmpb $E820MAX, %al
- jae bail820
-
- incb (E820NR)
- movw %di, %ax
- addw $20, %ax
- movw %ax, %di
-again820:
- cmpl $0, %ebx # check to see if
- jne jmpe820 # %ebx is set to EOF
-bail820:
-
-
-# method E801H:
-# memory size is in 1k chunksizes, to avoid confusing loadlin.
-# we store the 0xe801 memory size in a completely different place,
-# because it will most likely be longer than 16 bits.
-# (use 1e0 because that's what Larry Augustine uses in his
-# alternative new memory detection scheme, and it's sensible
-# to write everything into the same place.)
-
-meme801:
- stc # fix to work around buggy
- xorw %cx,%cx # BIOSes which don't clear/set
- xorw %dx,%dx # carry on pass/error of
- # e801h memory size call
- # or merely pass cx,dx though
- # without changing them.
- movw $0xe801, %ax
- int $0x15
- jc mem88
-
- cmpw $0x0, %cx # Kludge to handle BIOSes
- jne e801usecxdx # which report their extended
- cmpw $0x0, %dx # memory in AX/BX rather than
- jne e801usecxdx # CX/DX. The spec I have read
- movw %ax, %cx # seems to indicate AX/BX
- movw %bx, %dx # are more reasonable anyway...
-
-e801usecxdx:
- andl $0xffff, %edx # clear sign extend
- shll $6, %edx # and go from 64k to 1k chunks
- movl %edx, (0x1e0) # store extended memory size
- andl $0xffff, %ecx # clear sign extend
- addl %ecx, (0x1e0) # and add lower memory into
- # total size.
-
-# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
-# 64mb, depending on the bios) in ax.
-mem88:
-
-#endif
- movb $0x88, %ah
- int $0x15
- movw %ax, (2)
-
-# Set the keyboard repeat rate to the max
- movw $0x0305, %ax
- xorw %bx, %bx
- int $0x16
-
-# Check for video adapter and its parameters and allow the
-# user to browse video modes.
- call video # NOTE: we need %ds pointing
- # to bootsector
-
-# Get hd0 data...
- xorw %ax, %ax
- movw %ax, %ds
- ldsw (4 * 0x41), %si
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- pushw %ax
- movw %ax, %es
- movw $0x0080, %di
- movw $0x10, %cx
- pushw %cx
- cld
- rep
- movsb
-# Get hd1 data...
- xorw %ax, %ax
- movw %ax, %ds
- ldsw (4 * 0x46), %si
- popw %cx
- popw %es
- movw $0x0090, %di
- rep
- movsb
-# Check that there IS a hd1 :-)
- movw $0x01500, %ax
- movb $0x81, %dl
- int $0x13
- jc no_disk1
-
- cmpb $3, %ah
- je is_disk1
-
-no_disk1:
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %es
- movw $0x0090, %di
- movw $0x10, %cx
- xorw %ax, %ax
- cld
- rep
- stosb
-is_disk1:
-
-# Check for PS/2 pointing device
- movw %cs, %ax # aka SETUPSEG
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ax, %ds
- movb $0, (0x1ff) # default is no pointing device
- int $0x11 # int 0x11: equipment list
- testb $0x04, %al # check if mouse installed
- jz no_psmouse
-
- movb $0xAA, (0x1ff) # device present
-no_psmouse:
-
-#include "../../i386/boot/edd.S"
-
-# Now we want to move to protected mode ...
- cmpw $0, %cs:realmode_swtch
- jz rmodeswtch_normal
-
- lcall *%cs:realmode_swtch
-
- jmp rmodeswtch_end
-
-rmodeswtch_normal:
- pushw %cs
- call default_switch
-
-rmodeswtch_end:
-# we get the code32 start address and modify the below 'jmpi'
-# (loader may have changed it)
- movl %cs:code32_start, %eax
- movl %eax, %cs:code32
-
-# Now we move the system to its rightful place ... but we check if we have a
-# big-kernel. In that case we *must* not move it ...
- testb $LOADED_HIGH, %cs:loadflags
- jz do_move0 # .. then we have a normal low
- # loaded zImage
- # .. or else we have a high
- # loaded bzImage
- jmp end_move # ... and we skip moving
-
-do_move0:
- movw $0x100, %ax # start of destination segment
- movw %cs, %bp # aka SETUPSEG
- subw $DELTA_INITSEG, %bp # aka INITSEG
- movw %cs:start_sys_seg, %bx # start of source segment
- cld
-do_move:
- movw %ax, %es # destination segment
- incb %ah # instead of add ax,#0x100
- movw %bx, %ds # source segment
- addw $0x100, %bx
- subw %di, %di
- subw %si, %si
- movw $0x800, %cx
- rep
- movsw
- cmpw %bp, %bx # assume start_sys_seg > 0x200,
- # so we will perhaps read one
- # page more than needed, but
- # never overwrite INITSEG
- # because destination is a
- # minimum one page below source
- jb do_move
-
-end_move:
-# then we load the segment descriptors
- movw %cs, %ax # aka SETUPSEG
- movw %ax, %ds
-
-# Check whether we need to be downward compatible with version <=201
- cmpl $0, cmd_line_ptr
- jne end_move_self # loader uses version >=202 features
- cmpb $0x20, type_of_loader
- je end_move_self # bootsect loader, we know of it
-
-# Boot loader doesnt support boot protocol version 2.02.
-# If we have our code not at 0x90000, we need to move it there now.
-# We also then need to move the params behind it (commandline)
-# Because we would overwrite the code on the current IP, we move
-# it in two steps, jumping high after the first one.
- movw %cs, %ax
- cmpw $SETUPSEG, %ax
- je end_move_self
-
- cli # make sure we really have
- # interrupts disabled !
- # because after this the stack
- # should not be used
- subw $DELTA_INITSEG, %ax # aka INITSEG
- movw %ss, %dx
- cmpw %ax, %dx
- jb move_self_1
-
- addw $INITSEG, %dx
- subw %ax, %dx # this will go into %ss after
- # the move
-move_self_1:
- movw %ax, %ds
- movw $INITSEG, %ax # real INITSEG
- movw %ax, %es
- movw %cs:setup_move_size, %cx
- std # we have to move up, so we use
- # direction down because the
- # areas may overlap
- movw %cx, %di
- decw %di
- movw %di, %si
- subw $move_self_here+0x200, %cx
- rep
- movsb
- ljmp $SETUPSEG, $move_self_here
-
-move_self_here:
- movw $move_self_here+0x200, %cx
- rep
- movsb
- movw $SETUPSEG, %ax
- movw %ax, %ds
- movw %dx, %ss
-end_move_self: # now we are at the right place
- lidt idt_48 # load idt with 0,0
- xorl %eax, %eax # Compute gdt_base
- movw %ds, %ax # (Convert %ds:gdt to a linear ptr)
- shll $4, %eax
- addl $gdt, %eax
- movl %eax, (gdt_48+2)
- lgdt gdt_48 # load gdt with whatever is
- # appropriate
-
-# that was painless, now we enable a20
- call empty_8042
-
- movb $0xD1, %al # command write
- outb %al, $0x64
- call empty_8042
-
- movb $0xDF, %al # A20 on
- outb %al, $0x60
- call empty_8042
-
-#
-# You must preserve the other bits here. Otherwise embarrasing things
-# like laptops powering off on boot happen. Corrected version by Kira
-# Brown from Linux 2.2
-#
- inb $0x92, %al #
- orb $02, %al # "fast A20" version
- outb %al, $0x92 # some chips have only this
-
-# wait until a20 really *is* enabled; it can take a fair amount of
-# time on certain systems; Toshiba Tecras are known to have this
-# problem. The memory location used here (0x200) is the int 0x80
-# vector, which should be safe to use.
-
- xorw %ax, %ax # segment 0x0000
- movw %ax, %fs
- decw %ax # segment 0xffff (HMA)
- movw %ax, %gs
-a20_wait:
- incw %ax # unused memory location <0xfff0
- movw %ax, %fs:(0x200) # we use the "int 0x80" vector
- cmpw %gs:(0x210), %ax # and its corresponding HMA addr
- je a20_wait # loop until no longer aliased
-
-# make sure any possible coprocessor is properly reset..
- xorw %ax, %ax
- outb %al, $0xf0
- call delay
-
- outb %al, $0xf1
- call delay
-
-# well, that went ok, I hope. Now we mask all interrupts - the rest
-# is done in init_IRQ().
- movb $0xFF, %al # mask all interrupts for now
- outb %al, $0xA1
- call delay
-
- movb $0xFB, %al # mask all irq's but irq2 which
- outb %al, $0x21 # is cascaded
-
-# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't
-# need no steenking BIOS anyway (except for the initial loading :-).
-# The BIOS-routine wants lots of unnecessary data, and it's less
-# "interesting" anyway. This is how REAL programmers do it.
-#
-# Well, now's the time to actually move into protected mode. To make
-# things as simple as possible, we do no register set-up or anything,
-# we let the gnu-compiled 32-bit programs do that. We just jump to
-# absolute address 0x1000 (or the loader supplied one),
-# in 32-bit protected mode.
-#
-# Note that the short jump isn't strictly needed, although there are
-# reasons why it might be a good idea. It won't hurt in any case.
- movw $1, %ax # protected mode (PE) bit
- lmsw %ax # This is it!
- jmp flush_instr
-
-flush_instr:
- xorw %bx, %bx # Flag to indicate a boot
- xorl %esi, %esi # Pointer to real-mode code
- movw %cs, %si
- subw $DELTA_INITSEG, %si
- shll $4, %esi # Convert to 32-bit pointer
-# NOTE: For high loaded big kernels we need a
-# jmpi 0x100000,__KERNEL_CS
-#
-# but we yet haven't reloaded the CS register, so the default size
-# of the target offset still is 16 bit.
-# However, using an operand prefix (0x66), the CPU will properly
-# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
-# Manual, Mixing 16-bit and 32-bit code, page 16-6)
-
- .byte 0x66, 0xea # prefix + jmpi-opcode
-code32: .long 0x1000 # will be set to 0x100000
- # for big kernels
- .word __KERNEL_CS
-
-# Here's a bunch of information about your current kernel..
-kernel_version: .ascii UTS_RELEASE
- .ascii " ("
- .ascii LINUX_COMPILE_BY
- .ascii "@"
- .ascii LINUX_COMPILE_HOST
- .ascii ") "
- .ascii UTS_VERSION
- .byte 0
-
-# This is the default real mode switch routine.
-# to be called just before protected mode transition
-default_switch:
- cli # no interrupts allowed !
- movb $0x80, %al # disable NMI for bootup
- # sequence
- outb %al, $0x70
- lret
-
-
-# This routine checks that the keyboard command queue is empty
-# (after emptying the output buffers)
-#
-# Some machines have delusions that the keyboard buffer is always full
-# with no keyboard attached...
-#
-# If there is no keyboard controller, we will usually get 0xff
-# to all the reads. With each IO taking a microsecond and
-# a timeout of 100,000 iterations, this can take about half a
-# second ("delay" == outb to port 0x80). That should be ok,
-# and should also be plenty of time for a real keyboard controller
-# to empty.
-#
-
-empty_8042:
- pushl %ecx
- movl $100000, %ecx
-
-empty_8042_loop:
- decl %ecx
- jz empty_8042_end_loop
-
- call delay
-
- inb $0x64, %al # 8042 status port
- testb $1, %al # output buffer?
- jz no_output
-
- call delay
- inb $0x60, %al # read it
- jmp empty_8042_loop
-
-no_output:
- testb $2, %al # is input buffer full?
- jnz empty_8042_loop # yes - loop
-empty_8042_end_loop:
- popl %ecx
- ret
-
-# Read the cmos clock. Return the seconds in al
-gettime:
- pushw %cx
- movb $0x02, %ah
- int $0x1a
- movb %dh, %al # %dh contains the seconds
- andb $0x0f, %al
- movb %dh, %ah
- movb $0x04, %cl
- shrb %cl, %ah
- aad
- popw %cx
- ret
-
-# Delay is needed after doing I/O
-delay:
- outb %al,$0x80
- ret
-
-# Descriptor tables
-gdt:
- .word 0, 0, 0, 0 # dummy
-
- .word 0, 0, 0, 0 # unused
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9A00 # code read/exec
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-
- .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
- .word 0 # base address = 0
- .word 0x9200 # data read/write
- .word 0x00CF # granularity = 4096, 386
- # (+5th nibble of limit)
-gdt_end:
-idt_48:
- .word 0 # idt limit = 0
- .word 0, 0 # idt base = 0L
-gdt_48:
- .word gdt_end-gdt-1 # gdt limit
- .word 0, 0 # gdt base (filled in later)
-
-# Include video setup & detection code
-
-#include "../../i386/boot/video.S"
-
-# Setup signature -- must be last
-setup_sig1: .word SIG1
-setup_sig2: .word SIG2
-
-# After this point, there is some free space which is used by the video mode
-# handling code to store the temporary mode table (not used by the kernel).
-
-modelist:
-
-.text
-endtext:
-.data
-enddata:
-.bss
-endbss:
diff --git a/arch/x86_64/boot/tools/build.c b/arch/x86_64/boot/tools/build.c
deleted file mode 100644
index eae86691709a..000000000000
--- a/arch/x86_64/boot/tools/build.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (C) 1991, 1992 Linus Torvalds
- * Copyright (C) 1997 Martin Mares
- */
-
-/*
- * This file builds a disk-image from three different files:
- *
- * - bootsect: compatibility mbr which prints an error message if
- * someone tries to boot the kernel directly.
- * - setup: 8086 machine code, sets up system parm
- * - system: 80386 code for actual system
- *
- * It does some checking that all files are of the correct type, and
- * just writes the result to stdout, removing headers and padding to
- * the right amount. It also writes some system data to stderr.
- */
-
-/*
- * Changes by tytso to allow root device specification
- * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
- * Cross compiling fixes by Gertjan van Wingerde, July 1996
- * Rewritten by Martin Mares, April 1997
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/sysmacros.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <asm/boot.h>
-
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long u32;
-
-#define DEFAULT_MAJOR_ROOT 0
-#define DEFAULT_MINOR_ROOT 0
-
-/* Minimal number of setup sectors (see also bootsect.S) */
-#define SETUP_SECTS 4
-
-byte buf[1024];
-int fd;
-int is_big_kernel;
-
-void die(const char * str, ...)
-{
- va_list args;
- va_start(args, str);
- vfprintf(stderr, str, args);
- fputc('\n', stderr);
- exit(1);
-}
-
-void file_open(const char *name)
-{
- if ((fd = open(name, O_RDONLY, 0)) < 0)
- die("Unable to open `%s': %m", name);
-}
-
-void usage(void)
-{
- die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
-}
-
-int main(int argc, char ** argv)
-{
- unsigned int i, c, sz, setup_sectors;
- u32 sys_size;
- byte major_root, minor_root;
- struct stat sb;
-
- if (argc > 2 && !strcmp(argv[1], "-b"))
- {
- is_big_kernel = 1;
- argc--, argv++;
- }
- if ((argc < 4) || (argc > 5))
- usage();
- if (argc > 4) {
- if (!strcmp(argv[4], "CURRENT")) {
- if (stat("/", &sb)) {
- perror("/");
- die("Couldn't stat /");
- }
- major_root = major(sb.st_dev);
- minor_root = minor(sb.st_dev);
- } else if (strcmp(argv[4], "FLOPPY")) {
- if (stat(argv[4], &sb)) {
- perror(argv[4]);
- die("Couldn't stat root device.");
- }
- major_root = major(sb.st_rdev);
- minor_root = minor(sb.st_rdev);
- } else {
- major_root = 0;
- minor_root = 0;
- }
- } else {
- major_root = DEFAULT_MAJOR_ROOT;
- minor_root = DEFAULT_MINOR_ROOT;
- }
- fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
-
- file_open(argv[1]);
- i = read(fd, buf, sizeof(buf));
- fprintf(stderr,"Boot sector %d bytes.\n",i);
- if (i != 512)
- die("Boot block must be exactly 512 bytes");
- if (buf[510] != 0x55 || buf[511] != 0xaa)
- die("Boot block hasn't got boot flag (0xAA55)");
- buf[508] = minor_root;
- buf[509] = major_root;
- if (write(1, buf, 512) != 512)
- die("Write call failed");
- close (fd);
-
- file_open(argv[2]); /* Copy the setup code */
- for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c )
- if (write(1, buf, c) != c)
- die("Write call failed");
- if (c != 0)
- die("read-error on `setup'");
- close (fd);
-
- setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */
- /* for compatibility with ancient versions of LILO. */
- if (setup_sectors < SETUP_SECTS)
- setup_sectors = SETUP_SECTS;
- fprintf(stderr, "Setup is %d bytes.\n", i);
- memset(buf, 0, sizeof(buf));
- while (i < setup_sectors * 512) {
- c = setup_sectors * 512 - i;
- if (c > sizeof(buf))
- c = sizeof(buf);
- if (write(1, buf, c) != c)
- die("Write call failed");
- i += c;
- }
-
- file_open(argv[3]);
- if (fstat (fd, &sb))
- die("Unable to stat `%s': %m", argv[3]);
- sz = sb.st_size;
- fprintf (stderr, "System is %d kB\n", sz/1024);
- sys_size = (sz + 15) / 16;
- if (!is_big_kernel && sys_size > DEF_SYSSIZE)
- die("System is too big. Try using bzImage or modules.");
- while (sz > 0) {
- int l, n;
-
- l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
- if ((n=read(fd, buf, l)) != l) {
- if (n < 0)
- die("Error reading %s: %m", argv[3]);
- else
- die("%s: Unexpected EOF", argv[3]);
- }
- if (write(1, buf, l) != l)
- die("Write failed");
- sz -= l;
- }
- close(fd);
-
- if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */
- die("Output: seek failed");
- buf[0] = setup_sectors;
- if (write(1, buf, 1) != 1)
- die("Write of setup sector count failed");
- if (lseek(1, 500, SEEK_SET) != 500)
- die("Output: seek failed");
- buf[0] = (sys_size & 0xff);
- buf[1] = ((sys_size >> 8) & 0xff);
- buf[2] = ((sys_size >> 16) & 0xff);
- buf[3] = ((sys_size >> 24) & 0xff);
- if (write(1, buf, 4) != 4)
- die("Write of image length failed");
-
- return 0; /* Everything is OK */
-}
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 40178e5c3104..b7c4cd04bfc3 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,19 +1,22 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.22-rc2
-# Mon May 21 13:23:40 2007
+# Linux kernel version: 2.6.22-git14
+# Fri Jul 20 09:53:15 2007
#
CONFIG_X86_64=y
CONFIG_64BIT=y
CONFIG_X86=y
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CMOS_UPDATE=y
CONFIG_ZONE_DMA32=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_SEMAPHORE_SLEEPERS=y
CONFIG_MMU=y
CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
+CONFIG_NR_QUICK=2
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
@@ -44,19 +47,18 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
CONFIG_SYSVIPC_SYSCTL=y
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=18
# CONFIG_CPUSETS is not set
CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
+CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -86,10 +88,6 @@ CONFIG_SLAB=y
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -97,12 +95,9 @@ CONFIG_MODULE_FORCE_UNLOAD=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
CONFIG_STOP_MACHINE=y
-
-#
-# Block layer
-#
CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
#
# IO Schedulers
@@ -165,9 +160,12 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
CONFIG_OUT_OF_LINE_PFN_TO_PAGE=y
CONFIG_NR_CPUS=32
+CONFIG_PHYSICAL_ALIGN=0x200000
CONFIG_HOTPLUG_CPU=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_HPET_TIMER=y
@@ -180,7 +178,7 @@ CONFIG_X86_MCE_INTEL=y
CONFIG_X86_MCE_AMD=y
# CONFIG_KEXEC is not set
# CONFIG_CRASH_DUMP is not set
-CONFIG_RELOCATABLE=y
+# CONFIG_RELOCATABLE is not set
CONFIG_PHYSICAL_START=0x200000
CONFIG_SECCOMP=y
# CONFIG_CC_STACKPROTECTOR is not set
@@ -201,7 +199,6 @@ CONFIG_GENERIC_PENDING_IRQ=y
CONFIG_PM=y
# CONFIG_PM_LEGACY is not set
# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
CONFIG_SOFTWARE_SUSPEND=y
CONFIG_PM_STD_PARTITION=""
CONFIG_SUSPEND_SMP=y
@@ -248,7 +245,7 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
#
# CPUFreq processor drivers
@@ -351,20 +348,8 @@ CONFIG_IPV6_SIT=y
# CONFIG_IPV6_MULTIPLE_TABLES 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
@@ -401,6 +386,7 @@ CONFIG_IPV6_SIT=y
# CONFIG_MAC80211 is not set
# CONFIG_IEEE80211 is not set
# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
#
# Device Drivers
@@ -415,21 +401,9 @@ CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
CONFIG_PNP=y
# CONFIG_PNP_DEBUG is not set
@@ -437,10 +411,7 @@ CONFIG_PNP=y
# Protocols
#
CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
CONFIG_BLK_DEV_FD=y
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
@@ -458,17 +429,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
# CONFIG_IBM_ASM is not set
# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
# CONFIG_SONY_LAPTOP is not set
# CONFIG_THINKPAD_ACPI is not set
-# CONFIG_BLINK is not set
CONFIG_IDE=y
CONFIG_BLK_DEV_IDE=y
@@ -539,6 +507,7 @@ CONFIG_BLK_DEV_IDEDMA=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
# CONFIG_SCSI_TGT is not set
CONFIG_SCSI_NETLINK=y
# CONFIG_SCSI_PROC_FS is not set
@@ -590,11 +559,9 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_AIC79XX_REG_PRETTY_PRINT is not set
# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_ARCMSR is not set
-CONFIG_MEGARAID_NEWGEN=y
-CONFIG_MEGARAID_MM=y
-CONFIG_MEGARAID_MAILBOX=y
+# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
-CONFIG_MEGARAID_SAS=y
+# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -614,7 +581,6 @@ CONFIG_MEGARAID_SAS=y
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SRP is not set
CONFIG_ATA=y
# CONFIG_ATA_NONSTANDARD is not set
@@ -671,10 +637,6 @@ CONFIG_SATA_VIA=y
# CONFIG_PATA_SIS is not set
# CONFIG_PATA_VIA is not set
# CONFIG_PATA_WINBOND is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
CONFIG_MD=y
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_DM=y
@@ -692,7 +654,7 @@ CONFIG_BLK_DEV_DM=y
CONFIG_FUSION=y
CONFIG_FUSION_SPI=y
# CONFIG_FUSION_FC is not set
-CONFIG_FUSION_SAS=y
+# CONFIG_FUSION_SAS is not set
CONFIG_FUSION_MAX_SGE=128
# CONFIG_FUSION_CTL is not set
@@ -710,7 +672,10 @@ CONFIG_IEEE1394=y
#
# Controllers
#
-# CONFIG_IEEE1394_PCILYNX is not set
+
+#
+# Texas Instruments PCILynx requires I2C
+#
CONFIG_IEEE1394_OHCI1394=y
#
@@ -722,32 +687,19 @@ CONFIG_IEEE1394_OHCI1394=y
# CONFIG_IEEE1394_ETH1394 is not set
# CONFIG_IEEE1394_DV1394 is not set
CONFIG_IEEE1394_RAWIO=y
-
-#
-# I2O device support
-#
# CONFIG_I2O is not set
-# CONFIG_MACINTOSH_DRIVERS is not set
-
-#
-# Network device support
-#
+CONFIG_MACINTOSH_DRIVERS=y
+# CONFIG_MAC_EMUMOUSEBTN is not set
CONFIG_NETDEVICES=y
+CONFIG_NETDEVICES_MULTIQUEUE=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
CONFIG_TUN=y
# CONFIG_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
@@ -756,10 +708,6 @@ CONFIG_MII=y
CONFIG_NET_VENDOR_3COM=y
CONFIG_VORTEX=y
# CONFIG_TYPHOON is not set
-
-#
-# Tulip family network device support
-#
CONFIG_NET_TULIP=y
# CONFIG_DE2104X is not set
CONFIG_TULIP=y
@@ -773,7 +721,8 @@ CONFIG_TULIP=y
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
+CONFIG_AMD8111_ETH=y
+# CONFIG_AMD8111E_NAPI is not set
# CONFIG_ADAPTEC_STARFIRE is not set
CONFIG_B44=y
CONFIG_FORCEDETH=y
@@ -808,7 +757,6 @@ CONFIG_E1000=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=y
CONFIG_BNX2=y
@@ -823,10 +771,6 @@ CONFIG_S2IO=m
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_MLX4_CORE is not set
-
-#
-# Token Ring devices
-#
# CONFIG_TR is not set
#
@@ -855,15 +799,7 @@ CONFIG_NETCONSOLE=y
CONFIG_NETPOLL=y
# CONFIG_NETPOLL_TRAP is not set
CONFIG_NET_POLL_CONTROLLER=y
-
-#
-# ISDN subsystem
-#
# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
# CONFIG_PHONE is not set
#
@@ -871,6 +807,7 @@ CONFIG_NET_POLL_CONTROLLER=y
#
CONFIG_INPUT=y
# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
#
# Userland interfaces
@@ -936,6 +873,7 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_FIX_EARLYCON_MEM=y
CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_PNP=y
CONFIG_SERIAL_8250_NR_UARTS=4
@@ -951,16 +889,11 @@ CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
# CONFIG_IPMI_HANDLER is not set
# CONFIG_WATCHDOG is not set
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_INTEL=y
CONFIG_HW_RANDOM_AMD=y
-# CONFIG_HW_RANDOM_GEODE is not set
# CONFIG_NVRAM is not set
CONFIG_RTC=y
# CONFIG_R3964 is not set
@@ -979,127 +912,19 @@ CONFIG_HPET=y
# CONFIG_HPET_RTC_IRQ is not set
CONFIG_HPET_MMAP=y
# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
# CONFIG_TCG_TPM is not set
# CONFIG_TELCLOCK is not set
CONFIG_DEVPORT=y
-CONFIG_I2C=m
-CONFIG_I2C_BOARDINFO=y
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_OCORES is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_I2C_SIMTEC is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_TINY_USB is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_SENSORS_DS1337 is not set
-# CONFIG_SENSORS_DS1374 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCA9539 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_MAX6875 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_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
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_AD7418 is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1029 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ADM9240 is not set
-# CONFIG_SENSORS_K8TEMP is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_ATXP1 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-CONFIG_SENSORS_CORETEMP=y
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_LM92 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_MAX6650 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47M192 is not set
-CONFIG_SENSORS_SMSC47B397=m
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_VT8231 is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83791D is not set
-# CONFIG_SENSORS_W83792D is not set
-# CONFIG_SENSORS_W83793 is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_SENSORS_HDAPS is not set
-# CONFIG_SENSORS_APPLESMC is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
#
# Multifunction device drivers
@@ -1149,15 +974,11 @@ CONFIG_SOUND=y
# Open Sound System
#
CONFIG_SOUND_PRIME=y
-# CONFIG_OSS_OBSOLETE is not set
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
# CONFIG_SOUND_OSS is not set
-
-#
-# HID Devices
-#
+CONFIG_HID_SUPPORT=y
CONFIG_HID=y
# CONFIG_HID_DEBUG is not set
@@ -1168,10 +989,7 @@ CONFIG_USB_HID=y
# CONFIG_USB_HIDINPUT_POWERBOOK is not set
# CONFIG_HID_FF is not set
# CONFIG_USB_HIDDEV is not set
-
-#
-# USB support
-#
+CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1185,6 +1003,7 @@ CONFIG_USB_DEVICEFS=y
# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_PERSIST is not set
# CONFIG_USB_OTG is not set
#
@@ -1194,7 +1013,6 @@ CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1202,6 +1020,7 @@ CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
#
# USB Device Class drivers
@@ -1292,15 +1111,7 @@ CONFIG_USB_MON=y
#
# LED Triggers
#
-
-#
-# InfiniBand support
-#
# CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
# CONFIG_EDAC is not set
#
@@ -1320,11 +1131,13 @@ CONFIG_USB_MON=y
#
# DMA Devices
#
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
#
-# Virtualization
+# Userspace I/O
#
-# CONFIG_KVM is not set
+# CONFIG_UIO is not set
#
# Firmware Drivers
@@ -1332,6 +1145,7 @@ CONFIG_USB_MON=y
# CONFIG_EDD is not set
# CONFIG_DELL_RBU is not set
# CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
#
# File systems
@@ -1447,7 +1261,6 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
-# CONFIG_9P_FS is not set
#
# Partition Types
@@ -1524,8 +1337,9 @@ CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_SHIRQ is not set
CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHED_DEBUG is not set
# CONFIG_SCHEDSTATS is not set
-# CONFIG_TIMER_STATS is not set
+CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
@@ -1533,6 +1347,7 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_LOCK_ALLOC is not set
# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1541,8 +1356,6 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_VM is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_FRAME_POINTER is not set
-CONFIG_UNWIND_INFO=y
-CONFIG_STACK_UNWIND=y
# CONFIG_FORCED_INLINING is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_LKDTM is not set
@@ -1557,10 +1370,6 @@ CONFIG_DEBUG_STACKOVERFLOW=y
#
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
# CONFIG_CRYPTO is not set
#
@@ -1571,6 +1380,7 @@ CONFIG_BITREVERSE=y
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_PLIST=y
diff --git a/arch/x86_64/ia32/ia32_aout.c b/arch/x86_64/ia32/ia32_aout.c
index fe83edb93c10..08781370256d 100644
--- a/arch/x86_64/ia32/ia32_aout.c
+++ b/arch/x86_64/ia32/ia32_aout.c
@@ -404,7 +404,7 @@ beyond_if:
set_brk(current->mm->start_brk, current->mm->brk);
- retval = ia32_setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
+ retval = setup_arg_pages(bprm, IA32_STACK_TOP, EXSTACK_DEFAULT);
if (retval < 0) {
/* Someone check-me: is this error path enough? */
send_sig(SIGKILL, current, 0);
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 185399baaf6d..b70f3e7cf06c 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -38,6 +38,7 @@
int sysctl_vsyscall32 = 1;
+#undef ARCH_DLINFO
#define ARCH_DLINFO do { \
if (sysctl_vsyscall32) { \
NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
@@ -232,9 +233,6 @@ do { \
#define load_elf_binary load_elf32_binary
#define ELF_PLAT_INIT(r, load_addr) elf32_init(r)
-#define setup_arg_pages(bprm, stack_top, exec_stack) \
- ia32_setup_arg_pages(bprm, stack_top, exec_stack)
-int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack);
#undef start_thread
#define start_thread(regs,new_rip,new_rsp) do { \
@@ -286,61 +284,6 @@ static void elf32_init(struct pt_regs *regs)
me->thread.es = __USER_DS;
}
-int ia32_setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top,
- int executable_stack)
-{
- unsigned long stack_base;
- struct vm_area_struct *mpnt;
- struct mm_struct *mm = current->mm;
- int i, ret;
-
- stack_base = stack_top - MAX_ARG_PAGES * PAGE_SIZE;
- mm->arg_start = bprm->p + stack_base;
-
- bprm->p += stack_base;
- if (bprm->loader)
- bprm->loader += stack_base;
- bprm->exec += stack_base;
-
- mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
- if (!mpnt)
- return -ENOMEM;
-
- down_write(&mm->mmap_sem);
- {
- mpnt->vm_mm = mm;
- mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p;
- mpnt->vm_end = stack_top;
- if (executable_stack == EXSTACK_ENABLE_X)
- mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
- else if (executable_stack == EXSTACK_DISABLE_X)
- mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
- else
- mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_page_prot = (mpnt->vm_flags & VM_EXEC) ?
- PAGE_COPY_EXEC : PAGE_COPY;
- if ((ret = insert_vm_struct(mm, mpnt))) {
- up_write(&mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, mpnt);
- return ret;
- }
- mm->stack_vm = mm->total_vm = vma_pages(mpnt);
- }
-
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page *page = bprm->page[i];
- if (page) {
- bprm->page[i] = NULL;
- install_arg_page(mpnt, page, stack_base);
- }
- stack_base += PAGE_SIZE;
- }
- up_write(&mm->mmap_sem);
-
- return 0;
-}
-EXPORT_SYMBOL(ia32_setup_arg_pages);
-
#ifdef CONFIG_SYSCTL
/* Register vsyscall32 into the ABI table */
#include <linux/sysctl.h>
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index 47565c3345d2..938278697e20 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -104,7 +104,7 @@ ENTRY(ia32_sysenter_target)
pushq %rax
CFI_ADJUST_CFA_OFFSET 8
cld
- SAVE_ARGS 0,0,0
+ SAVE_ARGS 0,0,1
/* no need to do an access_ok check here because rbp has been
32bit zero extended */
1: movl (%rbp),%r9d
@@ -294,7 +294,7 @@ ia32_badarg:
*/
ENTRY(ia32_syscall)
- CFI_STARTPROC simple
+ CFI_STARTPROC32 simple
CFI_SIGNAL_FRAME
CFI_DEF_CFA rsp,SS+8-RIP
/*CFI_REL_OFFSET ss,SS-RIP*/
@@ -330,6 +330,7 @@ ia32_sysret:
ia32_tracesys:
SAVE_REST
+ CLEAR_RREGS
movq $-ENOSYS,RAX(%rsp) /* really needed? */
movq %rsp,%rdi /* &pt_regs -> arg1 */
call syscall_trace_enter
@@ -526,7 +527,7 @@ ia32_sys_call_table:
.quad sys_init_module
.quad sys_delete_module
.quad quiet_ni_syscall /* 130 get_kernel_syms */
- .quad sys_quotactl
+ .quad sys32_quotactl
.quad sys_getpgid
.quad sys_fchdir
.quad quiet_ni_syscall /* bdflush */
@@ -719,4 +720,5 @@ ia32_sys_call_table:
.quad compat_sys_signalfd
.quad compat_sys_timerfd
.quad sys_eventfd
+ .quad sys32_fallocate
ia32_syscall_end:
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index 99a78a3cce7c..bee96d614432 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -879,3 +879,11 @@ asmlinkage long sys32_fadvise64(int fd, unsigned offset_lo, unsigned offset_hi,
return sys_fadvise64_64(fd, ((u64)offset_hi << 32) | offset_lo,
len, advice);
}
+
+asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
+ unsigned offset_hi, unsigned len_lo,
+ unsigned len_hi)
+{
+ return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
+ ((u64)len_hi << 32) | len_lo);
+}
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index de1de8a2fd84..47f1dc30bf56 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_PCI) += early-quirks.o
obj-y += topology.o
obj-y += intel_cacheinfo.o
+obj-y += addon_cpuid_features.o
obj-y += pcspeaker.o
CFLAGS_vsyscall.o := $(PROFILING) -g0
@@ -55,6 +56,7 @@ cpuid-$(subst m,y,$(CONFIG_X86_CPUID)) += ../../i386/kernel/cpuid.o
topology-y += ../../i386/kernel/topology.o
microcode-$(subst m,y,$(CONFIG_MICROCODE)) += ../../i386/kernel/microcode.o
intel_cacheinfo-y += ../../i386/kernel/cpu/intel_cacheinfo.o
+addon_cpuid_features-y += ../../i386/kernel/cpu/addon_cpuid_features.o
quirks-y += ../../i386/kernel/quirks.o
i8237-y += ../../i386/kernel/i8237.o
msr-$(subst m,y,$(CONFIG_X86_MSR)) += ../../i386/kernel/msr.o
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
index 195b7034a148..4277f2b27e6d 100644
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -55,7 +55,7 @@
/* address in low memory of the wakeup routine. */
unsigned long acpi_wakeup_address = 0;
-unsigned long acpi_video_flags;
+unsigned long acpi_realmode_flags;
extern char wakeup_start, wakeup_end;
extern unsigned long acpi_copy_wakeup_routine(unsigned long);
@@ -103,9 +103,11 @@ static int __init acpi_sleep_setup(char *str)
{
while ((str != NULL) && (*str != '\0')) {
if (strncmp(str, "s3_bios", 7) == 0)
- acpi_video_flags = 1;
+ acpi_realmode_flags |= 1;
if (strncmp(str, "s3_mode", 7) == 0)
- acpi_video_flags |= 2;
+ acpi_realmode_flags |= 2;
+ if (strncmp(str, "s3_beep", 7) == 0)
+ acpi_realmode_flags |= 4;
str = strchr(str, ',');
if (str != NULL)
str += strspn(str, ", \t");
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
index 8550a6ffa275..13f1480cbec9 100644
--- a/arch/x86_64/kernel/acpi/wakeup.S
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -16,6 +16,21 @@
# cs = 0x1234, eip = 0x05
#
+#define BEEP \
+ inb $97, %al; \
+ outb %al, $0x80; \
+ movb $3, %al; \
+ outb %al, $97; \
+ outb %al, $0x80; \
+ movb $-74, %al; \
+ outb %al, $67; \
+ outb %al, $0x80; \
+ movb $-119, %al; \
+ outb %al, $66; \
+ outb %al, $0x80; \
+ movb $15, %al; \
+ outb %al, $66;
+
ALIGN
.align 16
@@ -33,6 +48,13 @@ wakeup_code:
movw %cs, %ax
movw %ax, %ds # Make ds:0 point to wakeup_start
movw %ax, %ss
+
+ # Data segment must be set up before we can see whether to beep.
+ testl $4, realmode_flags - wakeup_code
+ jz 1f
+ BEEP
+1:
+
# Private stack is needed for ASUS board
mov $(wakeup_stack - wakeup_code), %sp
@@ -48,7 +70,7 @@ wakeup_code:
testl %eax, %eax
jnz no_longmode
- testl $1, video_flags - wakeup_code
+ testl $1, realmode_flags - wakeup_code
jz 1f
lcall $0xc000,$3
movw %cs, %ax
@@ -56,7 +78,7 @@ wakeup_code:
movw %ax, %ss
1:
- testl $2, video_flags - wakeup_code
+ testl $2, realmode_flags - wakeup_code
jz 1f
mov video_mode - wakeup_code, %ax
call mode_seta
@@ -230,7 +252,7 @@ gdt_48a:
real_magic: .quad 0
video_mode: .quad 0
-video_flags: .quad 0
+realmode_flags: .quad 0
.code16
bogus_real_magic:
@@ -346,8 +368,8 @@ ENTRY(acpi_copy_wakeup_routine)
movl saved_video_mode, %edx
movl %edx, video_mode - wakeup_start (,%rdi)
- movl acpi_video_flags, %edx
- movl %edx, video_flags - wakeup_start (,%rdi)
+ movl acpi_realmode_flags, %edx
+ movl %edx, realmode_flags - wakeup_start (,%rdi)
movq $0x12345678, real_magic - wakeup_start (,%rdi)
movq $0x123456789abcdef0, %rdx
movq %rdx, saved_magic
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index a3d450d6c15b..8f681cae7bf7 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -20,7 +20,7 @@
#include <linux/ioport.h>
#include <asm/e820.h>
#include <asm/io.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
#include <asm/pci-direct.h>
#include <asm/dma.h>
#include <asm/k8.h>
@@ -214,7 +214,7 @@ void __init iommu_hole_init(void)
if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed())
return;
- printk("Checking aperture...\n");
+ printk(KERN_INFO "Checking aperture...\n");
fix = 0;
for (num = 24; num < 32; num++) {
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 1b0e07bb8728..900ff38d68de 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -92,8 +92,9 @@ unsigned int safe_apic_wait_icr_idle(void)
void enable_NMI_through_LVT0 (void * dummy)
{
unsigned int v;
-
- v = APIC_DM_NMI; /* unmask and set to NMI */
+
+ /* unmask and set to NMI */
+ v = APIC_DM_NMI;
apic_write(APIC_LVT0, v);
}
@@ -120,7 +121,7 @@ void ack_bad_irq(unsigned int irq)
* holds up an irq slot - in excessive cases (when multiple
* unexpected vectors occur) that might lock up the APIC
* completely.
- * But don't ack when the APIC is disabled. -AK
+ * But don't ack when the APIC is disabled. -AK
*/
if (!disable_apic)
ack_APIC_irq();
@@ -616,7 +617,7 @@ early_param("apic", apic_set_verbosity);
* Detect and enable local APICs on non-SMP boards.
* Original code written by Keir Fraser.
* On AMD64 we trust the BIOS - if it says no APIC it is likely
- * not correctly set up (usually the APIC timer won't work etc.)
+ * not correctly set up (usually the APIC timer won't work etc.)
*/
static int __init detect_init_APIC (void)
@@ -789,13 +790,13 @@ static void setup_APIC_timer(unsigned int clocks)
local_irq_save(flags);
/* wait for irq slice */
- if (hpet_address && hpet_use_timer) {
- int trigger = hpet_readl(HPET_T0_CMP);
- while (hpet_readl(HPET_COUNTER) >= trigger)
- /* do nothing */ ;
- while (hpet_readl(HPET_COUNTER) < trigger)
- /* do nothing */ ;
- } else {
+ if (hpet_address && hpet_use_timer) {
+ int trigger = hpet_readl(HPET_T0_CMP);
+ while (hpet_readl(HPET_COUNTER) >= trigger)
+ /* do nothing */ ;
+ while (hpet_readl(HPET_COUNTER) < trigger)
+ /* do nothing */ ;
+ } else {
int c1, c2;
outb_p(0x00, 0x43);
c2 = inb_p(0x40);
@@ -881,10 +882,10 @@ static unsigned int calibration_result;
void __init setup_boot_APIC_clock (void)
{
- if (disable_apic_timer) {
- printk(KERN_INFO "Disabling APIC timer\n");
- return;
- }
+ if (disable_apic_timer) {
+ printk(KERN_INFO "Disabling APIC timer\n");
+ return;
+ }
printk(KERN_INFO "Using local APIC timer interrupts.\n");
using_apic_timer = 1;
@@ -990,8 +991,8 @@ int setup_profiling_timer(unsigned int multiplier)
return -EINVAL;
}
-void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
- unsigned char msg_type, unsigned char mask)
+void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+ unsigned char msg_type, unsigned char mask)
{
unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
unsigned int v = (mask << 16) | (msg_type << 8) | vector;
@@ -1128,20 +1129,6 @@ asmlinkage void smp_spurious_interrupt(void)
if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
ack_APIC_irq();
-#if 0
- static unsigned long last_warning;
- static unsigned long skipped;
-
- /* see sw-dev-man vol 3, chapter 7.4.13.5 */
- if (time_before(last_warning+30*HZ,jiffies)) {
- printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
- smp_processor_id(), skipped);
- last_warning = jiffies;
- skipped = 0;
- } else {
- skipped++;
- }
-#endif
irq_exit();
}
@@ -1173,11 +1160,11 @@ asmlinkage void smp_error_interrupt(void)
7: Illegal register address
*/
printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
- smp_processor_id(), v , v1);
+ smp_processor_id(), v , v1);
irq_exit();
}
-int disable_apic;
+int disable_apic;
/*
* This initializes the IO-APIC and APIC hardware if this is
@@ -1185,11 +1172,11 @@ int disable_apic;
*/
int __init APIC_init_uniprocessor (void)
{
- if (disable_apic) {
+ if (disable_apic) {
printk(KERN_INFO "Apic disabled\n");
- return -1;
+ return -1;
}
- if (!cpu_has_apic) {
+ if (!cpu_has_apic) {
disable_apic = 1;
printk(KERN_INFO "Apic disabled by BIOS\n");
return -1;
@@ -1211,8 +1198,8 @@ int __init APIC_init_uniprocessor (void)
return 0;
}
-static __init int setup_disableapic(char *str)
-{
+static __init int setup_disableapic(char *str)
+{
disable_apic = 1;
clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
return 0;
@@ -1220,10 +1207,10 @@ static __init int setup_disableapic(char *str)
early_param("disableapic", setup_disableapic);
/* same as disableapic, for compatibility */
-static __init int setup_nolapic(char *str)
-{
+static __init int setup_nolapic(char *str)
+{
return setup_disableapic(str);
-}
+}
early_param("nolapic", setup_nolapic);
static int __init parse_lapic_timer_c2_ok(char *arg)
@@ -1233,13 +1220,13 @@ static int __init parse_lapic_timer_c2_ok(char *arg)
}
early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
-static __init int setup_noapictimer(char *str)
-{
+static __init int setup_noapictimer(char *str)
+{
if (str[0] != ' ' && str[0] != 0)
return 0;
disable_apic_timer = 1;
return 1;
-}
+}
static __init int setup_apicmaintimer(char *str)
{
@@ -1264,5 +1251,5 @@ static __init int setup_apicpmtimer(char *s)
}
__setup("apicpmtimer", setup_apicpmtimer);
-__setup("noapictimer", setup_noapictimer);
+__setup("noapictimer", setup_noapictimer);
diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig
index c0749d2479f5..a3fd51926cbd 100644
--- a/arch/x86_64/kernel/cpufreq/Kconfig
+++ b/arch/x86_64/kernel/cpufreq/Kconfig
@@ -48,10 +48,6 @@ config X86_SPEEDSTEP_CENTRINO
If in doubt, say N.
-config X86_SPEEDSTEP_CENTRINO_ACPI
- bool
- depends on X86_SPEEDSTEP_CENTRINO
-
config X86_ACPI_CPUFREQ
tristate "ACPI Processor P-States driver"
select CPU_FREQ_TABLE
@@ -73,7 +69,7 @@ comment "shared options"
config X86_ACPI_CPUFREQ_PROC_INTF
bool "/proc/acpi/processor/../performance interface (deprecated)"
depends on PROC_FS
- depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K8_ACPI
+ depends on X86_ACPI_CPUFREQ || X86_POWERNOW_K8_ACPI
help
This enables the deprecated /proc/acpi/processor/../performance
interface. While it is helpful for debugging, the generic,
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index 13c6c37610e0..0f4d5e209e9b 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -194,37 +194,6 @@ unsigned long __init e820_end_of_ram(void)
}
/*
- * Find the hole size in the range.
- */
-unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
-{
- unsigned long ram = 0;
- int i;
-
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
- unsigned long last, addr;
-
- if (ei->type != E820_RAM ||
- ei->addr+ei->size <= start ||
- ei->addr >= end)
- continue;
-
- addr = round_up(ei->addr, PAGE_SIZE);
- if (addr < start)
- addr = start;
-
- last = round_down(ei->addr + ei->size, PAGE_SIZE);
- if (last >= end)
- last = end;
-
- if (last > addr)
- ram += last - addr;
- }
- return ((end - start) - ram);
-}
-
-/*
* Mark e820 reserved areas as busy for the resource manager.
*/
void __init e820_reserve_resources(void)
@@ -289,47 +258,61 @@ void __init e820_mark_nosave_regions(void)
}
}
-/* Walk the e820 map and register active regions within a node */
-void __init
-e820_register_active_regions(int nid, unsigned long start_pfn,
- unsigned long end_pfn)
+/*
+ * Finds an active region in the address range from start_pfn to end_pfn and
+ * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
+ */
+static int __init e820_find_active_region(const struct e820entry *ei,
+ unsigned long start_pfn,
+ unsigned long end_pfn,
+ unsigned long *ei_startpfn,
+ unsigned long *ei_endpfn)
{
- int i;
- unsigned long ei_startpfn, ei_endpfn;
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
- ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
- ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE)
- >> PAGE_SHIFT;
+ *ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
+ *ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE) >> PAGE_SHIFT;
- /* Skip map entries smaller than a page */
- if (ei_startpfn >= ei_endpfn)
- continue;
+ /* Skip map entries smaller than a page */
+ if (*ei_startpfn >= *ei_endpfn)
+ return 0;
- /* Check if end_pfn_map should be updated */
- if (ei->type != E820_RAM && ei_endpfn > end_pfn_map)
- end_pfn_map = ei_endpfn;
+ /* Check if end_pfn_map should be updated */
+ if (ei->type != E820_RAM && *ei_endpfn > end_pfn_map)
+ end_pfn_map = *ei_endpfn;
- /* Skip if map is outside the node */
- if (ei->type != E820_RAM ||
- ei_endpfn <= start_pfn ||
- ei_startpfn >= end_pfn)
- continue;
+ /* Skip if map is outside the node */
+ if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
+ *ei_startpfn >= end_pfn)
+ return 0;
- /* Check for overlaps */
- if (ei_startpfn < start_pfn)
- ei_startpfn = start_pfn;
- if (ei_endpfn > end_pfn)
- ei_endpfn = end_pfn;
+ /* Check for overlaps */
+ if (*ei_startpfn < start_pfn)
+ *ei_startpfn = start_pfn;
+ if (*ei_endpfn > end_pfn)
+ *ei_endpfn = end_pfn;
- /* Obey end_user_pfn to save on memmap */
- if (ei_startpfn >= end_user_pfn)
- continue;
- if (ei_endpfn > end_user_pfn)
- ei_endpfn = end_user_pfn;
+ /* Obey end_user_pfn to save on memmap */
+ if (*ei_startpfn >= end_user_pfn)
+ return 0;
+ if (*ei_endpfn > end_user_pfn)
+ *ei_endpfn = end_user_pfn;
- add_active_range(nid, ei_startpfn, ei_endpfn);
- }
+ return 1;
+}
+
+/* Walk the e820 map and register active regions within a node */
+void __init
+e820_register_active_regions(int nid, unsigned long start_pfn,
+ unsigned long end_pfn)
+{
+ unsigned long ei_startpfn;
+ unsigned long ei_endpfn;
+ int i;
+
+ for (i = 0; i < e820.nr_map; i++)
+ if (e820_find_active_region(&e820.map[i],
+ start_pfn, end_pfn,
+ &ei_startpfn, &ei_endpfn))
+ add_active_range(nid, ei_startpfn, ei_endpfn);
}
/*
@@ -350,12 +333,35 @@ void __init add_memory_region(unsigned long start, unsigned long size, int type)
e820.nr_map++;
}
+/*
+ * Find the hole size (in bytes) in the memory range.
+ * @start: starting address of the memory range to scan
+ * @end: ending address of the memory range to scan
+ */
+unsigned long __init e820_hole_size(unsigned long start, unsigned long end)
+{
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long end_pfn = end >> PAGE_SHIFT;
+ unsigned long ei_startpfn;
+ unsigned long ei_endpfn;
+ unsigned long ram = 0;
+ int i;
+
+ for (i = 0; i < e820.nr_map; i++) {
+ if (e820_find_active_region(&e820.map[i],
+ start_pfn, end_pfn,
+ &ei_startpfn, &ei_endpfn))
+ ram += ei_endpfn - ei_startpfn;
+ }
+ return end - start - (ram << PAGE_SHIFT);
+}
+
void __init e820_print_map(char *who)
{
int i;
for (i = 0; i < e820.nr_map; i++) {
- printk(" %s: %016Lx - %016Lx ", who,
+ printk(KERN_INFO " %s: %016Lx - %016Lx ", who,
(unsigned long long) e820.map[i].addr,
(unsigned long long) (e820.map[i].addr + e820.map[i].size));
switch (e820.map[i].type) {
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index 990d9c218a5d..13aa4fd728f3 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -14,6 +14,7 @@
#include <linux/pci_ids.h>
#include <asm/pci-direct.h>
#include <asm/proto.h>
+#include <asm/iommu.h>
#include <asm/dma.h>
static void __init via_bugs(void)
diff --git a/arch/x86_64/kernel/early_printk.c b/arch/x86_64/kernel/early_printk.c
index 296d2b0c5d88..fd9aff3f3890 100644
--- a/arch/x86_64/kernel/early_printk.c
+++ b/arch/x86_64/kernel/early_printk.c
@@ -6,6 +6,7 @@
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/fcntl.h>
+#include <xen/hvc-console.h>
/* Simple VGA output */
@@ -242,6 +243,10 @@ static int __init setup_early_printk(char *buf)
simnow_init(buf + 6);
early_console = &simnow_console;
keep_early = 1;
+#ifdef CONFIG_HVC_XEN
+ } else if (!strncmp(buf, "xen", 3)) {
+ early_console = &xenboot_console;
+#endif
}
if (keep_early)
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index a67f87bf4015..830cfc6ee8cb 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -282,7 +282,7 @@ sysret_careful:
sysret_signal:
TRACE_IRQS_ON
sti
- testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+ testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
jz 1f
/* Really a signal */
@@ -375,7 +375,7 @@ int_very_careful:
jmp int_restore_rest
int_signal:
- testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx
+ testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
jz 1f
movq %rsp,%rdi # &ptregs -> arg1
xorl %esi,%esi # oldset -> arg2
@@ -599,7 +599,7 @@ retint_careful:
jmp retint_check
retint_signal:
- testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx
+ testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP|_TIF_MCE_NOTIFY),%edx
jz retint_swapgs
TRACE_IRQS_ON
sti
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 1fab487dee86..e89abcdbdde8 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -25,7 +25,7 @@
*/
.text
- .section .bootstrap.text
+ .section .text.head
.code64
.globl startup_64
startup_64:
@@ -73,7 +73,11 @@ startup_64:
addq %rbp, init_level4_pgt + (511*8)(%rip)
addq %rbp, level3_ident_pgt + 0(%rip)
+
addq %rbp, level3_kernel_pgt + (510*8)(%rip)
+ addq %rbp, level3_kernel_pgt + (511*8)(%rip)
+
+ addq %rbp, level2_fixmap_pgt + (506*8)(%rip)
/* Add an Identity mapping if I am above 1G */
leaq _text(%rip), %rdi
@@ -239,10 +243,16 @@ ENTRY(secondary_startup_64)
lretq
/* SMP bootup changes these two */
+#ifndef CONFIG_HOTPLUG_CPU
+ .pushsection .init.data
+#endif
.align 8
.globl initial_code
initial_code:
.quad x86_64_start_kernel
+#ifndef CONFIG_HOTPLUG_CPU
+ .popsection
+#endif
.globl init_rsp
init_rsp:
.quad init_thread_union+THREAD_SIZE-8
@@ -314,7 +324,16 @@ NEXT_PAGE(level3_kernel_pgt)
.fill 510,8,0
/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
.quad level2_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
- .fill 1,8,0
+ .quad level2_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
+
+NEXT_PAGE(level2_fixmap_pgt)
+ .fill 506,8,0
+ .quad level1_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE
+ /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */
+ .fill 5,8,0
+
+NEXT_PAGE(level1_fixmap_pgt)
+ .fill 512,8,0
NEXT_PAGE(level2_ident_pgt)
/* Since I easily can, map the first 1G.
diff --git a/arch/x86_64/kernel/hpet.c b/arch/x86_64/kernel/hpet.c
index b8286968662d..e2d1b912e154 100644
--- a/arch/x86_64/kernel/hpet.c
+++ b/arch/x86_64/kernel/hpet.c
@@ -133,7 +133,7 @@ struct clocksource clocksource_hpet = {
.vread = vread_hpet,
};
-int hpet_arch_init(void)
+int __init hpet_arch_init(void)
{
unsigned int id;
u64 tmp;
@@ -190,7 +190,7 @@ int hpet_reenable(void)
*/
#define TICK_COUNT 100000000
-#define TICK_MIN 5000
+#define SMI_THRESHOLD 50000
#define MAX_TRIES 5
/*
@@ -205,7 +205,7 @@ static void __init read_hpet_tsc(int *hpet, int *tsc)
tsc1 = get_cycles_sync();
hpet1 = hpet_readl(HPET_COUNTER);
tsc2 = get_cycles_sync();
- if (tsc2 - tsc1 > TICK_MIN)
+ if ((tsc2 - tsc1) < SMI_THRESHOLD)
break;
}
*hpet = hpet1;
@@ -439,7 +439,7 @@ int hpet_rtc_dropped_irq(void)
return 1;
}
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
{
struct rtc_time curr_time;
unsigned long rtc_int_flag = 0;
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 4b326655b208..948cae646099 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -444,24 +444,6 @@ void __init init_ISA_irqs (void)
}
}
-void apic_timer_interrupt(void);
-void spurious_interrupt(void);
-void error_interrupt(void);
-void reschedule_interrupt(void);
-void call_function_interrupt(void);
-void irq_move_cleanup_interrupt(void);
-void invalidate_interrupt0(void);
-void invalidate_interrupt1(void);
-void invalidate_interrupt2(void);
-void invalidate_interrupt3(void);
-void invalidate_interrupt4(void);
-void invalidate_interrupt5(void);
-void invalidate_interrupt6(void);
-void invalidate_interrupt7(void);
-void thermal_interrupt(void);
-void threshold_interrupt(void);
-void i8254_timer_resume(void);
-
static void setup_timer_hardware(void)
{
outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */
diff --git a/arch/x86_64/kernel/init_task.c b/arch/x86_64/kernel/init_task.c
index 3dc5854ba21e..4ff33d4f8551 100644
--- a/arch/x86_64/kernel/init_task.c
+++ b/arch/x86_64/kernel/init_task.c
@@ -44,7 +44,7 @@ EXPORT_SYMBOL(init_task);
* section. Since TSS's are completely CPU-local, we want them
* on exact cacheline boundaries, to eliminate cacheline ping-pong.
*/
-DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
+DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS;
/* Copies of the original ist values from the tss are only accessed during
* debugging, no special alignment required.
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 1c6c6f724573..050141c0602b 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -152,6 +152,32 @@ static inline void io_apic_modify(unsigned int apic, unsigned int value)
writel(value, &io_apic->data);
}
+static int io_apic_level_ack_pending(unsigned int irq)
+{
+ struct irq_pin_list *entry;
+ unsigned long flags;
+ int pending = 0;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ entry = irq_2_pin + irq;
+ for (;;) {
+ unsigned int reg;
+ int pin;
+
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+ reg = io_apic_read(entry->apic, 0x10 + pin*2);
+ /* Is the remote IRR bit set? */
+ pending |= (reg >> 14) & 1;
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ return pending;
+}
+
/*
* Synchronize the IO-APIC and the CPU by doing
* a dummy read from the IO-APIC
@@ -1418,9 +1444,37 @@ static void ack_apic_level(unsigned int irq)
ack_APIC_irq();
/* Now we can move and renable the irq */
- move_masked_irq(irq);
- if (unlikely(do_unmask_irq))
+ if (unlikely(do_unmask_irq)) {
+ /* Only migrate the irq if the ack has been received.
+ *
+ * On rare occasions the broadcast level triggered ack gets
+ * delayed going to ioapics, and if we reprogram the
+ * vector while Remote IRR is still set the irq will never
+ * fire again.
+ *
+ * To prevent this scenario we read the Remote IRR bit
+ * of the ioapic. This has two effects.
+ * - On any sane system the read of the ioapic will
+ * flush writes (and acks) going to the ioapic from
+ * this cpu.
+ * - We get to see if the ACK has actually been delivered.
+ *
+ * Based on failed experiments of reprogramming the
+ * ioapic entry from outside of irq context starting
+ * with masking the ioapic entry and then polling until
+ * Remote IRR was clear before reprogramming the
+ * ioapic I don't trust the Remote IRR bit to be
+ * completey accurate.
+ *
+ * However there appears to be no other way to plug
+ * this race, so if the Remote IRR bit is not
+ * accurate and is causing problems then it is a hardware bug
+ * and you can go talk to the chipset vendor about it.
+ */
+ if (!io_apic_level_ack_pending(irq))
+ move_masked_irq(irq);
unmask_IO_APIC_irq(irq);
+ }
}
static struct irq_chip ioapic_chip __read_mostly = {
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index d4a0d0ac9935..a30e004682e2 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -39,9 +39,9 @@
#include <linux/module.h>
#include <linux/kdebug.h>
-#include <asm/cacheflush.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
+#include <asm/alternative.h>
void jprobe_return_end(void);
static void __kprobes arch_copy_kprobe(struct kprobe *p);
@@ -209,16 +209,12 @@ static void __kprobes arch_copy_kprobe(struct kprobe *p)
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
- *p->addr = BREAKPOINT_INSTRUCTION;
- flush_icache_range((unsigned long) p->addr,
- (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+ text_poke(p->addr, ((unsigned char []){BREAKPOINT_INSTRUCTION}), 1);
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- *p->addr = p->opcode;
- flush_icache_range((unsigned long) p->addr,
- (unsigned long) p->addr + sizeof(kprobe_opcode_t));
+ text_poke(p->addr, &p->opcode, 1);
}
void __kprobes arch_remove_kprobe(struct kprobe *p)
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index aa1d15991794..a66d607f5b92 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -18,6 +18,8 @@
#include <linux/capability.h>
#include <linux/cpu.h>
#include <linux/percpu.h>
+#include <linux/poll.h>
+#include <linux/thread_info.h>
#include <linux/ctype.h>
#include <linux/kmod.h>
#include <linux/kdebug.h>
@@ -26,6 +28,7 @@
#include <asm/mce.h>
#include <asm/uaccess.h>
#include <asm/smp.h>
+#include <asm/idle.h>
#define MISC_MCELOG_MINOR 227
#define NR_BANKS 6
@@ -34,13 +37,17 @@ atomic_t mce_entry;
static int mce_dont_init;
-/* 0: always panic, 1: panic if deadlock possible, 2: try to avoid panic,
- 3: never panic or exit (for testing only) */
+/*
+ * Tolerant levels:
+ * 0: always panic on uncorrected errors, log corrected errors
+ * 1: panic or SIGBUS on uncorrected errors, log corrected errors
+ * 2: SIGBUS or log uncorrected errors (if possible), log corrected errors
+ * 3: never panic or SIGBUS, log all errors (for testing only)
+ */
static int tolerant = 1;
static int banks;
static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
-static unsigned long console_logged;
-static int notify_user;
+static unsigned long notify_user;
static int rip_msr;
static int mce_bootlog = 1;
static atomic_t mce_events;
@@ -48,6 +55,8 @@ static atomic_t mce_events;
static char trigger[128];
static char *trigger_argv[2] = { trigger, NULL };
+static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
+
/*
* Lockless MCE logging infrastructure.
* This avoids deadlocks on printk locks without having to break locks. Also
@@ -94,8 +103,7 @@ void mce_log(struct mce *mce)
mcelog.entry[entry].finished = 1;
wmb();
- if (!test_and_set_bit(0, &console_logged))
- notify_user = 1;
+ set_bit(0, &notify_user);
}
static void print_mce(struct mce *m)
@@ -128,6 +136,7 @@ static void print_mce(struct mce *m)
static void mce_panic(char *msg, struct mce *backup, unsigned long start)
{
int i;
+
oops_begin();
for (i = 0; i < MCE_LOG_LEN; i++) {
unsigned long tsc = mcelog.entry[i].tsc;
@@ -139,10 +148,7 @@ static void mce_panic(char *msg, struct mce *backup, unsigned long start)
}
if (backup)
print_mce(backup);
- if (tolerant >= 3)
- printk("Fake panic: %s\n", msg);
- else
- panic(msg);
+ panic(msg);
}
static int mce_available(struct cpuinfo_x86 *c)
@@ -167,17 +173,6 @@ static inline void mce_get_rip(struct mce *m, struct pt_regs *regs)
}
}
-static void do_mce_trigger(void)
-{
- static atomic_t mce_logged;
- int events = atomic_read(&mce_events);
- if (events != atomic_read(&mce_logged) && trigger[0]) {
- /* Small race window, but should be harmless. */
- atomic_set(&mce_logged, events);
- call_usermodehelper(trigger, trigger_argv, NULL, -1);
- }
-}
-
/*
* The actual machine check handler
*/
@@ -185,11 +180,19 @@ static void do_mce_trigger(void)
void do_machine_check(struct pt_regs * regs, long error_code)
{
struct mce m, panicm;
- int nowayout = (tolerant < 1);
- int kill_it = 0;
u64 mcestart = 0;
int i;
int panicm_found = 0;
+ /*
+ * If no_way_out gets set, there is no safe way to recover from this
+ * MCE. If tolerant is cranked up, we'll try anyway.
+ */
+ int no_way_out = 0;
+ /*
+ * If kill_it gets set, there might be a way to recover from this
+ * error.
+ */
+ int kill_it = 0;
atomic_inc(&mce_entry);
@@ -201,8 +204,9 @@ void do_machine_check(struct pt_regs * regs, long error_code)
memset(&m, 0, sizeof(struct mce));
m.cpu = smp_processor_id();
rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
+ /* if the restart IP is not valid, we're done for */
if (!(m.mcgstatus & MCG_STATUS_RIPV))
- kill_it = 1;
+ no_way_out = 1;
rdtscll(mcestart);
barrier();
@@ -221,10 +225,18 @@ void do_machine_check(struct pt_regs * regs, long error_code)
continue;
if (m.status & MCI_STATUS_EN) {
- /* In theory _OVER could be a nowayout too, but
- assume any overflowed errors were no fatal. */
- nowayout |= !!(m.status & MCI_STATUS_PCC);
- kill_it |= !!(m.status & MCI_STATUS_UC);
+ /* if PCC was set, there's no way out */
+ no_way_out |= !!(m.status & MCI_STATUS_PCC);
+ /*
+ * If this error was uncorrectable and there was
+ * an overflow, we're in trouble. If no overflow,
+ * we might get away with just killing a task.
+ */
+ if (m.status & MCI_STATUS_UC) {
+ if (tolerant < 1 || m.status & MCI_STATUS_OVER)
+ no_way_out = 1;
+ kill_it = 1;
+ }
}
if (m.status & MCI_STATUS_MISCV)
@@ -235,7 +247,6 @@ void do_machine_check(struct pt_regs * regs, long error_code)
mce_get_rip(&m, regs);
if (error_code >= 0)
rdtscll(m.tsc);
- wrmsrl(MSR_IA32_MC0_STATUS + i*4, 0);
if (error_code != -2)
mce_log(&m);
@@ -251,45 +262,59 @@ void do_machine_check(struct pt_regs * regs, long error_code)
}
/* Never do anything final in the polling timer */
- if (!regs) {
- /* Normal interrupt context here. Call trigger for any new
- events. */
- do_mce_trigger();
+ if (!regs)
goto out;
- }
/* If we didn't find an uncorrectable error, pick
the last one (shouldn't happen, just being safe). */
if (!panicm_found)
panicm = m;
- if (nowayout)
+
+ /*
+ * If we have decided that we just CAN'T continue, and the user
+ * has not set tolerant to an insane level, give up and die.
+ */
+ if (no_way_out && tolerant < 3)
mce_panic("Machine check", &panicm, mcestart);
- if (kill_it) {
+
+ /*
+ * If the error seems to be unrecoverable, something should be
+ * done. Try to kill as little as possible. If we can kill just
+ * one task, do that. If the user has set the tolerance very
+ * high, don't try to do anything at all.
+ */
+ if (kill_it && tolerant < 3) {
int user_space = 0;
- if (m.mcgstatus & MCG_STATUS_RIPV)
+ /*
+ * If the EIPV bit is set, it means the saved IP is the
+ * instruction which caused the MCE.
+ */
+ if (m.mcgstatus & MCG_STATUS_EIPV)
user_space = panicm.rip && (panicm.cs & 3);
-
- /* When the machine was in user space and the CPU didn't get
- confused it's normally not necessary to panic, unless you
- are paranoid (tolerant == 0)
-
- RED-PEN could be more tolerant for MCEs in idle,
- but most likely they occur at boot anyways, where
- it is best to just halt the machine. */
- if ((!user_space && (panic_on_oops || tolerant < 2)) ||
- (unsigned)current->pid <= 1)
- mce_panic("Uncorrected machine check", &panicm, mcestart);
-
- /* do_exit takes an awful lot of locks and has as
- slight risk of deadlocking. If you don't want that
- don't set tolerant >= 2 */
- if (tolerant < 3)
+
+ /*
+ * If we know that the error was in user space, send a
+ * SIGBUS. Otherwise, panic if tolerance is low.
+ *
+ * do_exit() takes an awful lot of locks and has a slight
+ * risk of deadlocking.
+ */
+ if (user_space) {
do_exit(SIGBUS);
+ } else if (panic_on_oops || tolerant < 2) {
+ mce_panic("Uncorrected machine check",
+ &panicm, mcestart);
+ }
}
+ /* notify userspace ASAP */
+ set_thread_flag(TIF_MCE_NOTIFY);
+
out:
- /* Last thing done in the machine check exception to clear state. */
+ /* the last thing we do is clear state */
+ for (i = 0; i < banks; i++)
+ wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
wrmsrl(MSR_IA32_MCG_STATUS, 0);
out2:
atomic_dec(&mce_entry);
@@ -344,37 +369,69 @@ static void mcheck_timer(struct work_struct *work)
on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
/*
- * It's ok to read stale data here for notify_user and
- * console_logged as we'll simply get the updated versions
- * on the next mcheck_timer execution and atomic operations
- * on console_logged act as synchronization for notify_user
- * writes.
+ * Alert userspace if needed. If we logged an MCE, reduce the
+ * polling interval, otherwise increase the polling interval.
*/
- if (notify_user && console_logged) {
+ if (mce_notify_user()) {
+ next_interval = max(next_interval/2, HZ/100);
+ } else {
+ next_interval = min(next_interval*2,
+ (int)round_jiffies_relative(check_interval*HZ));
+ }
+
+ schedule_delayed_work(&mcheck_work, next_interval);
+}
+
+/*
+ * This is only called from process context. This is where we do
+ * anything we need to alert userspace about new MCEs. This is called
+ * directly from the poller and also from entry.S and idle, thanks to
+ * TIF_MCE_NOTIFY.
+ */
+int mce_notify_user(void)
+{
+ clear_thread_flag(TIF_MCE_NOTIFY);
+ if (test_and_clear_bit(0, &notify_user)) {
static unsigned long last_print;
unsigned long now = jiffies;
- /* if we logged an MCE, reduce the polling interval */
- next_interval = max(next_interval/2, HZ/100);
- notify_user = 0;
- clear_bit(0, &console_logged);
+ wake_up_interruptible(&mce_wait);
+ if (trigger[0])
+ call_usermodehelper(trigger, trigger_argv, NULL,
+ UMH_NO_WAIT);
+
if (time_after_eq(now, last_print + (check_interval*HZ))) {
last_print = now;
printk(KERN_INFO "Machine check events logged\n");
}
- } else {
- next_interval = min(next_interval*2, check_interval*HZ);
+
+ return 1;
}
+ return 0;
+}
- schedule_delayed_work(&mcheck_work, next_interval);
+/* see if the idle task needs to notify userspace */
+static int
+mce_idle_callback(struct notifier_block *nfb, unsigned long action, void *junk)
+{
+ /* IDLE_END should be safe - interrupts are back on */
+ if (action == IDLE_END && test_thread_flag(TIF_MCE_NOTIFY))
+ mce_notify_user();
+
+ return NOTIFY_OK;
}
+static struct notifier_block mce_idle_notifier = {
+ .notifier_call = mce_idle_callback,
+};
static __init int periodic_mcheck_init(void)
{
next_interval = check_interval * HZ;
if (next_interval)
- schedule_delayed_work(&mcheck_work, next_interval);
+ schedule_delayed_work(&mcheck_work,
+ round_jiffies_relative(next_interval));
+ idle_notifier_register(&mce_idle_notifier);
return 0;
}
__initcall(periodic_mcheck_init);
@@ -465,6 +522,40 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
* Character device to read and clear the MCE log.
*/
+static DEFINE_SPINLOCK(mce_state_lock);
+static int open_count; /* #times opened */
+static int open_exclu; /* already open exclusive? */
+
+static int mce_open(struct inode *inode, struct file *file)
+{
+ spin_lock(&mce_state_lock);
+
+ if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
+ spin_unlock(&mce_state_lock);
+ return -EBUSY;
+ }
+
+ if (file->f_flags & O_EXCL)
+ open_exclu = 1;
+ open_count++;
+
+ spin_unlock(&mce_state_lock);
+
+ return nonseekable_open(inode, file);
+}
+
+static int mce_release(struct inode *inode, struct file *file)
+{
+ spin_lock(&mce_state_lock);
+
+ open_count--;
+ open_exclu = 0;
+
+ spin_unlock(&mce_state_lock);
+
+ return 0;
+}
+
static void collect_tscs(void *data)
{
unsigned long *cpu_tsc = (unsigned long *)data;
@@ -532,6 +623,14 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff
return err ? -EFAULT : buf - ubuf;
}
+static unsigned int mce_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &mce_wait, wait);
+ if (rcu_dereference(mcelog.next))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned long arg)
{
int __user *p = (int __user *)arg;
@@ -555,7 +654,10 @@ static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned
}
static const struct file_operations mce_chrdev_ops = {
+ .open = mce_open,
+ .release = mce_release,
.read = mce_read,
+ .poll = mce_poll,
.ioctl = mce_ioctl,
};
@@ -565,6 +667,20 @@ static struct miscdevice mce_log_device = {
&mce_chrdev_ops,
};
+static unsigned long old_cr4 __initdata;
+
+void __init stop_mce(void)
+{
+ old_cr4 = read_cr4();
+ clear_in_cr4(X86_CR4_MCE);
+}
+
+void __init restart_mce(void)
+{
+ if (old_cr4 & X86_CR4_MCE)
+ set_in_cr4(X86_CR4_MCE);
+}
+
/*
* Old style boot options parsing. Only for compatibility.
*/
@@ -620,7 +736,8 @@ static void mce_restart(void)
on_each_cpu(mce_init, NULL, 1, 1);
next_interval = check_interval * HZ;
if (next_interval)
- schedule_delayed_work(&mcheck_work, next_interval);
+ schedule_delayed_work(&mcheck_work,
+ round_jiffies_relative(next_interval));
}
static struct sysdev_class mce_sysclass = {
diff --git a/arch/x86_64/kernel/mce_amd.c b/arch/x86_64/kernel/mce_amd.c
index 03356e64f9c8..2f8a7f18b0fe 100644
--- a/arch/x86_64/kernel/mce_amd.c
+++ b/arch/x86_64/kernel/mce_amd.c
@@ -157,9 +157,9 @@ void __cpuinit mce_amd_feature_init(struct cpuinfo_x86 *c)
high |= K8_APIC_EXT_LVT_ENTRY_THRESHOLD << 20;
wrmsr(address, low, high);
- setup_APIC_extened_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
- THRESHOLD_APIC_VECTOR,
- K8_APIC_EXT_INT_MSG_FIX, 0);
+ setup_APIC_extended_lvt(K8_APIC_EXT_LVT_ENTRY_THRESHOLD,
+ THRESHOLD_APIC_VECTOR,
+ K8_APIC_EXT_INT_MSG_FIX, 0);
threshold_defaults.address = address;
threshold_restart_bank(&threshold_defaults, 0, 0);
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 61ae57eb9e4c..8bf0ca03ac8e 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -32,7 +32,6 @@
/* Have we found an MP table */
int smp_found_config;
-unsigned int __initdata maxcpus = NR_CPUS;
/*
* Various Linux-internal data structures created from the
@@ -649,6 +648,20 @@ static int mp_find_ioapic(int gsi)
return -1;
}
+static u8 uniq_ioapic_id(u8 id)
+{
+ int i;
+ DECLARE_BITMAP(used, 256);
+ bitmap_zero(used, 256);
+ for (i = 0; i < nr_ioapics; i++) {
+ struct mpc_config_ioapic *ia = &mp_ioapics[i];
+ __set_bit(ia->mpc_apicid, used);
+ }
+ if (!test_bit(id, used))
+ return id;
+ return find_first_zero_bit(used, 256);
+}
+
void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
{
int idx = 0;
@@ -656,14 +669,14 @@ void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
if (bad_ioapic(address))
return;
- idx = nr_ioapics++;
+ idx = nr_ioapics;
mp_ioapics[idx].mpc_type = MP_IOAPIC;
mp_ioapics[idx].mpc_flags = MPC_APIC_USABLE;
mp_ioapics[idx].mpc_apicaddr = address;
set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
- mp_ioapics[idx].mpc_apicid = id;
+ mp_ioapics[idx].mpc_apicid = uniq_ioapic_id(id);
mp_ioapics[idx].mpc_apicver = 0;
/*
@@ -680,6 +693,8 @@ void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
mp_ioapics[idx].mpc_apicaddr,
mp_ioapic_routing[idx].gsi_start,
mp_ioapic_routing[idx].gsi_end);
+
+ nr_ioapics++;
}
void __init
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 931c64bad5e6..cb8ee9d02f86 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -296,7 +296,7 @@ static DEFINE_PER_CPU(unsigned, last_irq_sum);
static DEFINE_PER_CPU(local_t, alert_counter);
static DEFINE_PER_CPU(int, nmi_touch);
-void touch_nmi_watchdog (void)
+void touch_nmi_watchdog(void)
{
if (nmi_watchdog > 0) {
unsigned cpu;
@@ -306,8 +306,10 @@ void touch_nmi_watchdog (void)
* do it ourselves because the alert count increase is not
* atomic.
*/
- for_each_present_cpu (cpu)
- per_cpu(nmi_touch, cpu) = 1;
+ for_each_present_cpu(cpu) {
+ if (per_cpu(nmi_touch, cpu) != 1)
+ per_cpu(nmi_touch, cpu) = 1;
+ }
}
touch_softlockup_watchdog();
@@ -382,11 +384,14 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
return rc;
}
+static unsigned ignore_nmis;
+
asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
{
nmi_enter();
add_pda(__nmi_count,1);
- default_do_nmi(regs);
+ if (!ignore_nmis)
+ default_do_nmi(regs);
nmi_exit();
}
@@ -399,6 +404,18 @@ int do_nmi_callback(struct pt_regs * regs, int cpu)
return 0;
}
+void stop_nmi(void)
+{
+ acpi_nmi_disable();
+ ignore_nmis++;
+}
+
+void restart_nmi(void)
+{
+ ignore_nmis--;
+ acpi_nmi_enable();
+}
+
#ifdef CONFIG_SYSCTL
static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index 5bd20b542c1e..ba16c968ca3f 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -1,7 +1,7 @@
/*
* Derived from arch/powerpc/kernel/iommu.c
*
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
* Copyright (C) 2006 Jon Mason <jdmason@kudzu.us>
*
* Author: Jon Mason <jdmason@kudzu.us>
@@ -35,7 +35,7 @@
#include <linux/pci_ids.h>
#include <linux/pci.h>
#include <linux/delay.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
#include <asm/calgary.h>
#include <asm/tce.h>
#include <asm/pci-direct.h>
@@ -50,13 +50,7 @@ int use_calgary __read_mostly = 0;
#endif /* CONFIG_CALGARY_DEFAULT_ENABLED */
#define PCI_DEVICE_ID_IBM_CALGARY 0x02a1
-#define PCI_VENDOR_DEVICE_ID_CALGARY \
- (PCI_VENDOR_ID_IBM | PCI_DEVICE_ID_IBM_CALGARY << 16)
-
-/* we need these for register space address calculation */
-#define START_ADDRESS 0xfe000000
-#define CHASSIS_BASE 0
-#define ONE_BASED_CHASSIS_NUM 1
+#define PCI_DEVICE_ID_IBM_CALIOC2 0x0308
/* register offsets inside the host bridge space */
#define CALGARY_CONFIG_REG 0x0108
@@ -80,6 +74,12 @@ int use_calgary __read_mostly = 0;
#define PHB_MEM_2_SIZE_LOW 0x02E0
#define PHB_DOSHOLE_OFFSET 0x08E0
+/* CalIOC2 specific */
+#define PHB_SAVIOR_L2 0x0DB0
+#define PHB_PAGE_MIG_CTRL 0x0DA8
+#define PHB_PAGE_MIG_DEBUG 0x0DA0
+#define PHB_ROOT_COMPLEX_STATUS 0x0CB0
+
/* PHB_CONFIG_RW */
#define PHB_TCE_ENABLE 0x20000000
#define PHB_SLOT_DISABLE 0x1C000000
@@ -92,7 +92,11 @@ int use_calgary __read_mostly = 0;
/* CSR (Channel/DMA Status Register) */
#define CSR_AGENT_MASK 0xffe0ffff
/* CCR (Calgary Configuration Register) */
-#define CCR_2SEC_TIMEOUT 0x000000000000000EUL
+#define CCR_2SEC_TIMEOUT 0x000000000000000EUL
+/* PMCR/PMDR (Page Migration Control/Debug Registers */
+#define PMR_SOFTSTOP 0x80000000
+#define PMR_SOFTSTOPFAULT 0x40000000
+#define PMR_HARDSTOP 0x20000000
#define MAX_NUM_OF_PHBS 8 /* how many PHBs in total? */
#define MAX_NUM_CHASSIS 8 /* max number of chassis */
@@ -155,9 +159,26 @@ struct calgary_bus_info {
void __iomem *bbar;
};
-static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calgary_tce_cache_blast(struct iommu_table *tbl);
+static void calgary_dump_error_regs(struct iommu_table *tbl);
+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev);
+static void calioc2_tce_cache_blast(struct iommu_table *tbl);
+static void calioc2_dump_error_regs(struct iommu_table *tbl);
+
+static struct cal_chipset_ops calgary_chip_ops = {
+ .handle_quirks = calgary_handle_quirks,
+ .tce_cache_blast = calgary_tce_cache_blast,
+ .dump_error_regs = calgary_dump_error_regs
+};
-static void tce_cache_blast(struct iommu_table *tbl);
+static struct cal_chipset_ops calioc2_chip_ops = {
+ .handle_quirks = calioc2_handle_quirks,
+ .tce_cache_blast = calioc2_tce_cache_blast,
+ .dump_error_regs = calioc2_dump_error_regs
+};
+
+static struct calgary_bus_info bus_info[MAX_PHB_BUS_NUM] = { { NULL, 0, 0 }, };
/* enable this to stress test the chip's TCE cache */
#ifdef CONFIG_IOMMU_DEBUG
@@ -187,6 +208,7 @@ static inline unsigned long verify_bit_range(unsigned long* bitmap,
{
return ~0UL;
}
+
#endif /* CONFIG_IOMMU_DEBUG */
static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
@@ -206,11 +228,12 @@ static inline int translate_phb(struct pci_dev* dev)
}
static void iommu_range_reserve(struct iommu_table *tbl,
- unsigned long start_addr, unsigned int npages)
+ unsigned long start_addr, unsigned int npages)
{
unsigned long index;
unsigned long end;
unsigned long badbit;
+ unsigned long flags;
index = start_addr >> PAGE_SHIFT;
@@ -222,6 +245,8 @@ static void iommu_range_reserve(struct iommu_table *tbl,
if (end > tbl->it_size) /* don't go off the table */
end = tbl->it_size;
+ spin_lock_irqsave(&tbl->it_lock, flags);
+
badbit = verify_bit_range(tbl->it_map, 0, index, end);
if (badbit != ~0UL) {
if (printk_ratelimit())
@@ -231,23 +256,29 @@ static void iommu_range_reserve(struct iommu_table *tbl,
}
set_bit_string(tbl->it_map, index, npages);
+
+ spin_unlock_irqrestore(&tbl->it_lock, flags);
}
static unsigned long iommu_range_alloc(struct iommu_table *tbl,
unsigned int npages)
{
+ unsigned long flags;
unsigned long offset;
BUG_ON(npages == 0);
+ spin_lock_irqsave(&tbl->it_lock, flags);
+
offset = find_next_zero_string(tbl->it_map, tbl->it_hint,
tbl->it_size, npages);
if (offset == ~0UL) {
- tce_cache_blast(tbl);
+ tbl->chip_ops->tce_cache_blast(tbl);
offset = find_next_zero_string(tbl->it_map, 0,
tbl->it_size, npages);
if (offset == ~0UL) {
printk(KERN_WARNING "Calgary: IOMMU full.\n");
+ spin_unlock_irqrestore(&tbl->it_lock, flags);
if (panic_on_overflow)
panic("Calgary: fix the allocator.\n");
else
@@ -259,17 +290,17 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
tbl->it_hint = offset + npages;
BUG_ON(tbl->it_hint > tbl->it_size);
+ spin_unlock_irqrestore(&tbl->it_lock, flags);
+
return offset;
}
static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
unsigned int npages, int direction)
{
- unsigned long entry, flags;
+ unsigned long entry;
dma_addr_t ret = bad_dma_address;
- spin_lock_irqsave(&tbl->it_lock, flags);
-
entry = iommu_range_alloc(tbl, npages);
if (unlikely(entry == bad_dma_address))
@@ -282,23 +313,21 @@ static dma_addr_t iommu_alloc(struct iommu_table *tbl, void *vaddr,
tce_build(tbl, entry, npages, (unsigned long)vaddr & PAGE_MASK,
direction);
- spin_unlock_irqrestore(&tbl->it_lock, flags);
-
return ret;
error:
- spin_unlock_irqrestore(&tbl->it_lock, flags);
printk(KERN_WARNING "Calgary: failed to allocate %u pages in "
"iommu %p\n", npages, tbl);
return bad_dma_address;
}
-static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
+static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
unsigned int npages)
{
unsigned long entry;
unsigned long badbit;
unsigned long badend;
+ unsigned long flags;
/* were we called with bad_dma_address? */
badend = bad_dma_address + (EMERGENCY_PAGES * PAGE_SIZE);
@@ -315,6 +344,8 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
tce_free(tbl, entry, npages);
+ spin_lock_irqsave(&tbl->it_lock, flags);
+
badbit = verify_bit_range(tbl->it_map, 1, entry, entry + npages);
if (badbit != ~0UL) {
if (printk_ratelimit())
@@ -324,23 +355,40 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
}
__clear_bit_string(tbl->it_map, entry, npages);
+
+ spin_unlock_irqrestore(&tbl->it_lock, flags);
}
-static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
- unsigned int npages)
+static inline struct iommu_table *find_iommu_table(struct device *dev)
{
- unsigned long flags;
+ struct pci_dev *pdev;
+ struct pci_bus *pbus;
+ struct iommu_table *tbl;
- spin_lock_irqsave(&tbl->it_lock, flags);
+ pdev = to_pci_dev(dev);
- __iommu_free(tbl, dma_addr, npages);
+ /* is the device behind a bridge? */
+ if (unlikely(pdev->bus->parent))
+ pbus = pdev->bus->parent;
+ else
+ pbus = pdev->bus;
- spin_unlock_irqrestore(&tbl->it_lock, flags);
+ tbl = pci_iommu(pbus);
+
+ BUG_ON(pdev->bus->parent &&
+ (tbl->it_busno != pdev->bus->parent->number));
+
+ return tbl;
}
-static void __calgary_unmap_sg(struct iommu_table *tbl,
+static void calgary_unmap_sg(struct device *dev,
struct scatterlist *sglist, int nelems, int direction)
{
+ struct iommu_table *tbl = find_iommu_table(dev);
+
+ if (!translate_phb(to_pci_dev(dev)))
+ return;
+
while (nelems--) {
unsigned int npages;
dma_addr_t dma = sglist->dma_address;
@@ -350,33 +398,17 @@ static void __calgary_unmap_sg(struct iommu_table *tbl,
break;
npages = num_dma_pages(dma, dmalen);
- __iommu_free(tbl, dma, npages);
+ iommu_free(tbl, dma, npages);
sglist++;
}
}
-void calgary_unmap_sg(struct device *dev, struct scatterlist *sglist,
- int nelems, int direction)
-{
- unsigned long flags;
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
-
- if (!translate_phb(to_pci_dev(dev)))
- return;
-
- spin_lock_irqsave(&tbl->it_lock, flags);
-
- __calgary_unmap_sg(tbl, sglist, nelems, direction);
-
- spin_unlock_irqrestore(&tbl->it_lock, flags);
-}
-
static int calgary_nontranslate_map_sg(struct device* dev,
struct scatterlist *sg, int nelems, int direction)
{
int i;
- for (i = 0; i < nelems; i++ ) {
+ for (i = 0; i < nelems; i++ ) {
struct scatterlist *s = &sg[i];
BUG_ON(!s->page);
s->dma_address = virt_to_bus(page_address(s->page) +s->offset);
@@ -385,11 +417,10 @@ static int calgary_nontranslate_map_sg(struct device* dev,
return nelems;
}
-int calgary_map_sg(struct device *dev, struct scatterlist *sg,
+static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
int nelems, int direction)
{
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
- unsigned long flags;
+ struct iommu_table *tbl = find_iommu_table(dev);
unsigned long vaddr;
unsigned int npages;
unsigned long entry;
@@ -398,8 +429,6 @@ int calgary_map_sg(struct device *dev, struct scatterlist *sg,
if (!translate_phb(to_pci_dev(dev)))
return calgary_nontranslate_map_sg(dev, sg, nelems, direction);
- spin_lock_irqsave(&tbl->it_lock, flags);
-
for (i = 0; i < nelems; i++ ) {
struct scatterlist *s = &sg[i];
BUG_ON(!s->page);
@@ -423,26 +452,23 @@ int calgary_map_sg(struct device *dev, struct scatterlist *sg,
s->dma_length = s->length;
}
- spin_unlock_irqrestore(&tbl->it_lock, flags);
-
return nelems;
error:
- __calgary_unmap_sg(tbl, sg, nelems, direction);
+ calgary_unmap_sg(dev, sg, nelems, direction);
for (i = 0; i < nelems; i++) {
sg[i].dma_address = bad_dma_address;
sg[i].dma_length = 0;
}
- spin_unlock_irqrestore(&tbl->it_lock, flags);
return 0;
}
-dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
+static dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
size_t size, int direction)
{
dma_addr_t dma_handle = bad_dma_address;
unsigned long uaddr;
unsigned int npages;
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);
uaddr = (unsigned long)vaddr;
npages = num_dma_pages(uaddr, size);
@@ -455,10 +481,10 @@ dma_addr_t calgary_map_single(struct device *dev, void *vaddr,
return dma_handle;
}
-void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
+static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
size_t size, int direction)
{
- struct iommu_table *tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);
unsigned int npages;
if (!translate_phb(to_pci_dev(dev)))
@@ -468,15 +494,13 @@ void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
iommu_free(tbl, dma_handle, npages);
}
-void* calgary_alloc_coherent(struct device *dev, size_t size,
+static void* calgary_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
{
void *ret = NULL;
dma_addr_t mapping;
unsigned int npages, order;
- struct iommu_table *tbl;
-
- tbl = to_pci_dev(dev)->bus->self->sysdata;
+ struct iommu_table *tbl = find_iommu_table(dev);
size = PAGE_ALIGN(size); /* size rounded up to full pages */
npages = size >> PAGE_SHIFT;
@@ -552,7 +576,22 @@ static inline void __iomem* calgary_reg(void __iomem *bar, unsigned long offset)
return (void __iomem*)target;
}
-static void tce_cache_blast(struct iommu_table *tbl)
+static inline int is_calioc2(unsigned short device)
+{
+ return (device == PCI_DEVICE_ID_IBM_CALIOC2);
+}
+
+static inline int is_calgary(unsigned short device)
+{
+ return (device == PCI_DEVICE_ID_IBM_CALGARY);
+}
+
+static inline int is_cal_pci_dev(unsigned short device)
+{
+ return (is_calgary(device) || is_calioc2(device));
+}
+
+static void calgary_tce_cache_blast(struct iommu_table *tbl)
{
u64 val;
u32 aer;
@@ -589,6 +628,85 @@ static void tce_cache_blast(struct iommu_table *tbl)
(void)readl(target); /* flush */
}
+static void calioc2_tce_cache_blast(struct iommu_table *tbl)
+{
+ void __iomem *bbar = tbl->bbar;
+ void __iomem *target;
+ u64 val64;
+ u32 val;
+ int i = 0;
+ int count = 1;
+ unsigned char bus = tbl->it_busno;
+
+begin:
+ printk(KERN_DEBUG "Calgary: CalIOC2 bus 0x%x entering tce cache blast "
+ "sequence - count %d\n", bus, count);
+
+ /* 1. using the Page Migration Control reg set SoftStop */
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "1a. read 0x%x [LE] from %p\n", val, target);
+ val |= PMR_SOFTSTOP;
+ printk(KERN_DEBUG "1b. writing 0x%x [LE] to %p\n", val, target);
+ writel(cpu_to_be32(val), target);
+
+ /* 2. poll split queues until all DMA activity is done */
+ printk(KERN_DEBUG "2a. starting to poll split queues\n");
+ target = calgary_reg(bbar, split_queue_offset(bus));
+ do {
+ val64 = readq(target);
+ i++;
+ } while ((val64 & 0xff) != 0xff && i < 100);
+ if (i == 100)
+ printk(KERN_WARNING "CalIOC2: PCI bus not quiesced, "
+ "continuing anyway\n");
+
+ /* 3. poll Page Migration DEBUG for SoftStopFault */
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "3. read 0x%x [LE] from %p\n", val, target);
+
+ /* 4. if SoftStopFault - goto (1) */
+ if (val & PMR_SOFTSTOPFAULT) {
+ if (++count < 100)
+ goto begin;
+ else {
+ printk(KERN_WARNING "CalIOC2: too many SoftStopFaults, "
+ "aborting TCE cache flush sequence!\n");
+ return; /* pray for the best */
+ }
+ }
+
+ /* 5. Slam into HardStop by reading PHB_PAGE_MIG_CTRL */
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ printk(KERN_DEBUG "5a. slamming into HardStop by reading %p\n", target);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "5b. read 0x%x [LE] from %p\n", val, target);
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_DEBUG);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "5c. read 0x%x [LE] from %p (debug)\n", val, target);
+
+ /* 6. invalidate TCE cache */
+ printk(KERN_DEBUG "6. invalidating TCE cache\n");
+ target = calgary_reg(bbar, tar_offset(bus));
+ writeq(tbl->tar_val, target);
+
+ /* 7. Re-read PMCR */
+ printk(KERN_DEBUG "7a. Re-reading PMCR\n");
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "7b. read 0x%x [LE] from %p\n", val, target);
+
+ /* 8. Remove HardStop */
+ printk(KERN_DEBUG "8a. removing HardStop from PMCR\n");
+ target = calgary_reg(bbar, phb_offset(bus) | PHB_PAGE_MIG_CTRL);
+ val = 0;
+ printk(KERN_DEBUG "8b. writing 0x%x [LE] to %p\n", val, target);
+ writel(cpu_to_be32(val), target);
+ val = be32_to_cpu(readl(target));
+ printk(KERN_DEBUG "8c. read 0x%x [LE] from %p\n", val, target);
+}
+
static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
u64 limit)
{
@@ -598,7 +716,7 @@ static void __init calgary_reserve_mem_region(struct pci_dev *dev, u64 start,
limit++;
numpages = ((limit - start) >> PAGE_SHIFT);
- iommu_range_reserve(dev->sysdata, start, numpages);
+ iommu_range_reserve(pci_iommu(dev->bus), start, numpages);
}
static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
@@ -606,7 +724,7 @@ static void __init calgary_reserve_peripheral_mem_1(struct pci_dev *dev)
void __iomem *target;
u64 low, high, sizelow;
u64 start, limit;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
unsigned char busnum = dev->bus->number;
void __iomem *bbar = tbl->bbar;
@@ -630,7 +748,7 @@ static void __init calgary_reserve_peripheral_mem_2(struct pci_dev *dev)
u32 val32;
u64 low, high, sizelow, sizehigh;
u64 start, limit;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
unsigned char busnum = dev->bus->number;
void __iomem *bbar = tbl->bbar;
@@ -666,14 +784,20 @@ static void __init calgary_reserve_regions(struct pci_dev *dev)
{
unsigned int npages;
u64 start;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
/* reserve EMERGENCY_PAGES from bad_dma_address and up */
iommu_range_reserve(tbl, bad_dma_address, EMERGENCY_PAGES);
/* avoid the BIOS/VGA first 640KB-1MB region */
- start = (640 * 1024);
- npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+ /* for CalIOC2 - avoid the entire first MB */
+ if (is_calgary(dev->device)) {
+ start = (640 * 1024);
+ npages = ((1024 - 640) * 1024) >> PAGE_SHIFT;
+ } else { /* calioc2 */
+ start = 0;
+ npages = (1 * 1024 * 1024) >> PAGE_SHIFT;
+ }
iommu_range_reserve(tbl, start, npages);
/* reserve the two PCI peripheral memory regions in IO space */
@@ -694,10 +818,17 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
if (ret)
return ret;
- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
tbl->it_base = (unsigned long)bus_info[dev->bus->number].tce_space;
tce_free(tbl, 0, tbl->it_size);
+ if (is_calgary(dev->device))
+ tbl->chip_ops = &calgary_chip_ops;
+ else if (is_calioc2(dev->device))
+ tbl->chip_ops = &calioc2_chip_ops;
+ else
+ BUG();
+
calgary_reserve_regions(dev);
/* set TARs for each PHB */
@@ -706,15 +837,15 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
/* zero out all TAR bits under sw control */
val64 &= ~TAR_SW_BITS;
-
- tbl = dev->sysdata;
table_phys = (u64)__pa(tbl->it_base);
+
val64 |= table_phys;
BUG_ON(specified_table_size > TCE_TABLE_SIZE_8M);
val64 |= (u64) specified_table_size;
tbl->tar_val = cpu_to_be64(val64);
+
writeq(tbl->tar_val, target);
readq(target); /* flush */
@@ -724,7 +855,7 @@ static int __init calgary_setup_tar(struct pci_dev *dev, void __iomem *bbar)
static void __init calgary_free_bus(struct pci_dev *dev)
{
u64 val64;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
void __iomem *target;
unsigned int bitmapsz;
@@ -739,16 +870,81 @@ static void __init calgary_free_bus(struct pci_dev *dev)
tbl->it_map = NULL;
kfree(tbl);
- dev->sysdata = NULL;
+
+ set_pci_iommu(dev->bus, NULL);
/* Can't free bootmem allocated memory after system is up :-( */
bus_info[dev->bus->number].tce_space = NULL;
}
+static void calgary_dump_error_regs(struct iommu_table *tbl)
+{
+ void __iomem *bbar = tbl->bbar;
+ void __iomem *target;
+ u32 csr, plssr;
+
+ target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_CSR_OFFSET);
+ csr = be32_to_cpu(readl(target));
+
+ target = calgary_reg(bbar, phb_offset(tbl->it_busno) | PHB_PLSSR_OFFSET);
+ plssr = be32_to_cpu(readl(target));
+
+ /* If no error, the agent ID in the CSR is not valid */
+ printk(KERN_EMERG "Calgary: DMA error on Calgary PHB 0x%x, "
+ "0x%08x@CSR 0x%08x@PLSSR\n", tbl->it_busno, csr, plssr);
+}
+
+static void calioc2_dump_error_regs(struct iommu_table *tbl)
+{
+ void __iomem *bbar = tbl->bbar;
+ u32 csr, csmr, plssr, mck, rcstat;
+ void __iomem *target;
+ unsigned long phboff = phb_offset(tbl->it_busno);
+ unsigned long erroff;
+ u32 errregs[7];
+ int i;
+
+ /* dump CSR */
+ target = calgary_reg(bbar, phboff | PHB_CSR_OFFSET);
+ csr = be32_to_cpu(readl(target));
+ /* dump PLSSR */
+ target = calgary_reg(bbar, phboff | PHB_PLSSR_OFFSET);
+ plssr = be32_to_cpu(readl(target));
+ /* dump CSMR */
+ target = calgary_reg(bbar, phboff | 0x290);
+ csmr = be32_to_cpu(readl(target));
+ /* dump mck */
+ target = calgary_reg(bbar, phboff | 0x800);
+ mck = be32_to_cpu(readl(target));
+
+ printk(KERN_EMERG "Calgary: DMA error on CalIOC2 PHB 0x%x\n",
+ tbl->it_busno);
+
+ printk(KERN_EMERG "Calgary: 0x%08x@CSR 0x%08x@PLSSR 0x%08x@CSMR 0x%08x@MCK\n",
+ csr, plssr, csmr, mck);
+
+ /* dump rest of error regs */
+ printk(KERN_EMERG "Calgary: ");
+ for (i = 0; i < ARRAY_SIZE(errregs); i++) {
+ /* err regs are at 0x810 - 0x870 */
+ erroff = (0x810 + (i * 0x10));
+ target = calgary_reg(bbar, phboff | erroff);
+ errregs[i] = be32_to_cpu(readl(target));
+ printk("0x%08x@0x%lx ", errregs[i], erroff);
+ }
+ printk("\n");
+
+ /* root complex status */
+ target = calgary_reg(bbar, phboff | PHB_ROOT_COMPLEX_STATUS);
+ rcstat = be32_to_cpu(readl(target));
+ printk(KERN_EMERG "Calgary: 0x%08x@0x%x\n", rcstat,
+ PHB_ROOT_COMPLEX_STATUS);
+}
+
static void calgary_watchdog(unsigned long data)
{
struct pci_dev *dev = (struct pci_dev *)data;
- struct iommu_table *tbl = dev->sysdata;
+ struct iommu_table *tbl = pci_iommu(dev->bus);
void __iomem *bbar = tbl->bbar;
u32 val32;
void __iomem *target;
@@ -758,13 +954,14 @@ static void calgary_watchdog(unsigned long data)
/* If no error, the agent ID in the CSR is not valid */
if (val32 & CSR_AGENT_MASK) {
- printk(KERN_EMERG "calgary_watchdog: DMA error on PHB %#x, "
- "CSR = %#x\n", dev->bus->number, val32);
+ tbl->chip_ops->dump_error_regs(tbl);
+
+ /* reset error */
writel(0, target);
/* Disable bus that caused the error */
target = calgary_reg(bbar, phb_offset(tbl->it_busno) |
- PHB_CONFIG_RW_OFFSET);
+ PHB_CONFIG_RW_OFFSET);
val32 = be32_to_cpu(readl(target));
val32 |= PHB_SLOT_DISABLE;
writel(cpu_to_be32(val32), target);
@@ -775,8 +972,8 @@ static void calgary_watchdog(unsigned long data)
}
}
-static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
- unsigned char busnum)
+static void __init calgary_set_split_completion_timeout(void __iomem *bbar,
+ unsigned char busnum, unsigned long timeout)
{
u64 val64;
void __iomem *target;
@@ -802,11 +999,40 @@ static void __init calgary_increase_split_completion_timeout(void __iomem *bbar,
/* zero out this PHB's timer bits */
mask = ~(0xFUL << phb_shift);
val64 &= mask;
- val64 |= (CCR_2SEC_TIMEOUT << phb_shift);
+ val64 |= (timeout << phb_shift);
writeq(cpu_to_be64(val64), target);
readq(target); /* flush */
}
+static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+{
+ unsigned char busnum = dev->bus->number;
+ void __iomem *bbar = tbl->bbar;
+ void __iomem *target;
+ u32 val;
+
+ /*
+ * CalIOC2 designers recommend setting bit 8 in 0xnDB0 to 1
+ */
+ target = calgary_reg(bbar, phb_offset(busnum) | PHB_SAVIOR_L2);
+ val = cpu_to_be32(readl(target));
+ val |= 0x00800000;
+ writel(cpu_to_be32(val), target);
+}
+
+static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+{
+ unsigned char busnum = dev->bus->number;
+
+ /*
+ * Give split completion a longer timeout on bus 1 for aic94xx
+ * http://bugzilla.kernel.org/show_bug.cgi?id=7180
+ */
+ if (is_calgary(dev->device) && (busnum == 1))
+ calgary_set_split_completion_timeout(tbl->bbar, busnum,
+ CCR_2SEC_TIMEOUT);
+}
+
static void __init calgary_enable_translation(struct pci_dev *dev)
{
u32 val32;
@@ -816,7 +1042,7 @@ static void __init calgary_enable_translation(struct pci_dev *dev)
struct iommu_table *tbl;
busnum = dev->bus->number;
- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
bbar = tbl->bbar;
/* enable TCE in PHB Config Register */
@@ -824,20 +1050,15 @@ static void __init calgary_enable_translation(struct pci_dev *dev)
val32 = be32_to_cpu(readl(target));
val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE;
- printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum);
+ printk(KERN_INFO "Calgary: enabling translation on %s PHB %#x\n",
+ (dev->device == PCI_DEVICE_ID_IBM_CALGARY) ?
+ "Calgary" : "CalIOC2", busnum);
printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this "
"bus.\n");
writel(cpu_to_be32(val32), target);
readl(target); /* flush */
- /*
- * Give split completion a longer timeout on bus 1 for aic94xx
- * http://bugzilla.kernel.org/show_bug.cgi?id=7180
- */
- if (busnum == 1)
- calgary_increase_split_completion_timeout(bbar, busnum);
-
init_timer(&tbl->watchdog_timer);
tbl->watchdog_timer.function = &calgary_watchdog;
tbl->watchdog_timer.data = (unsigned long)dev;
@@ -853,7 +1074,7 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
struct iommu_table *tbl;
busnum = dev->bus->number;
- tbl = dev->sysdata;
+ tbl = pci_iommu(dev->bus);
bbar = tbl->bbar;
/* disable TCE in PHB Config Register */
@@ -871,13 +1092,19 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
static void __init calgary_init_one_nontraslated(struct pci_dev *dev)
{
pci_dev_get(dev);
- dev->sysdata = NULL;
- dev->bus->self = dev;
+ set_pci_iommu(dev->bus, NULL);
+
+ /* is the device behind a bridge? */
+ if (dev->bus->parent)
+ dev->bus->parent->self = dev;
+ else
+ dev->bus->self = dev;
}
static int __init calgary_init_one(struct pci_dev *dev)
{
void __iomem *bbar;
+ struct iommu_table *tbl;
int ret;
BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
@@ -888,7 +1115,18 @@ static int __init calgary_init_one(struct pci_dev *dev)
goto done;
pci_dev_get(dev);
- dev->bus->self = dev;
+
+ if (dev->bus->parent) {
+ if (dev->bus->parent->self)
+ printk(KERN_WARNING "Calgary: IEEEE, dev %p has "
+ "bus->parent->self!\n", dev);
+ dev->bus->parent->self = dev;
+ } else
+ dev->bus->self = dev;
+
+ tbl = pci_iommu(dev->bus);
+ tbl->chip_ops->handle_quirks(tbl, dev);
+
calgary_enable_translation(dev);
return 0;
@@ -924,11 +1162,18 @@ static int __init calgary_locate_bbars(void)
target = calgary_reg(bbar, offset);
val = be32_to_cpu(readl(target));
+
start_bus = (u8)((val & 0x00FF0000) >> 16);
end_bus = (u8)((val & 0x0000FF00) >> 8);
- for (bus = start_bus; bus <= end_bus; bus++) {
- bus_info[bus].bbar = bbar;
- bus_info[bus].phbid = phb;
+
+ if (end_bus) {
+ for (bus = start_bus; bus <= end_bus; bus++) {
+ bus_info[bus].bbar = bbar;
+ bus_info[bus].phbid = phb;
+ }
+ } else {
+ bus_info[start_bus].bbar = bbar;
+ bus_info[start_bus].phbid = phb;
}
}
}
@@ -948,22 +1193,24 @@ static int __init calgary_init(void)
{
int ret;
struct pci_dev *dev = NULL;
+ void *tce_space;
ret = calgary_locate_bbars();
if (ret)
return ret;
do {
- dev = pci_get_device(PCI_VENDOR_ID_IBM,
- PCI_DEVICE_ID_IBM_CALGARY,
- dev);
+ dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
if (!dev)
break;
+ if (!is_cal_pci_dev(dev->device))
+ continue;
if (!translate_phb(dev)) {
calgary_init_one_nontraslated(dev);
continue;
}
- if (!bus_info[dev->bus->number].tce_space && !translate_empty_slots)
+ tce_space = bus_info[dev->bus->number].tce_space;
+ if (!tce_space && !translate_empty_slots)
continue;
ret = calgary_init_one(dev);
@@ -976,10 +1223,11 @@ static int __init calgary_init(void)
error:
do {
dev = pci_get_device_reverse(PCI_VENDOR_ID_IBM,
- PCI_DEVICE_ID_IBM_CALGARY,
- dev);
+ PCI_ANY_ID, dev);
if (!dev)
break;
+ if (!is_cal_pci_dev(dev->device))
+ continue;
if (!translate_phb(dev)) {
pci_dev_put(dev);
continue;
@@ -1057,9 +1305,29 @@ static int __init build_detail_arrays(void)
return 0;
}
-void __init detect_calgary(void)
+static int __init calgary_bus_has_devices(int bus, unsigned short pci_dev)
{
+ int dev;
u32 val;
+
+ if (pci_dev == PCI_DEVICE_ID_IBM_CALIOC2) {
+ /*
+ * FIXME: properly scan for devices accross the
+ * PCI-to-PCI bridge on every CalIOC2 port.
+ */
+ return 1;
+ }
+
+ for (dev = 1; dev < 8; dev++) {
+ val = read_pci_config(bus, dev, 0, 0);
+ if (val != 0xffffffff)
+ break;
+ }
+ return (val != 0xffffffff);
+}
+
+void __init detect_calgary(void)
+{
int bus;
void *tbl;
int calgary_found = 0;
@@ -1116,29 +1384,26 @@ void __init detect_calgary(void)
specified_table_size = determine_tce_table_size(end_pfn * PAGE_SIZE);
for (bus = 0; bus < MAX_PHB_BUS_NUM; bus++) {
- int dev;
struct calgary_bus_info *info = &bus_info[bus];
+ unsigned short pci_device;
+ u32 val;
+
+ val = read_pci_config(bus, 0, 0, 0);
+ pci_device = (val & 0xFFFF0000) >> 16;
- if (read_pci_config(bus, 0, 0, 0) != PCI_VENDOR_DEVICE_ID_CALGARY)
+ if (!is_cal_pci_dev(pci_device))
continue;
if (info->translation_disabled)
continue;
- /*
- * Scan the slots of the PCI bus to see if there is a device present.
- * The parent bus will be the zero-ith device, so start at 1.
- */
- for (dev = 1; dev < 8; dev++) {
- val = read_pci_config(bus, dev, 0, 0);
- if (val != 0xffffffff || translate_empty_slots) {
- tbl = alloc_tce_table();
- if (!tbl)
- goto cleanup;
- info->tce_space = tbl;
- calgary_found = 1;
- break;
- }
+ if (calgary_bus_has_devices(bus, pci_device) ||
+ translate_empty_slots) {
+ tbl = alloc_tce_table();
+ if (!tbl)
+ goto cleanup;
+ info->tce_space = tbl;
+ calgary_found = 1;
}
}
@@ -1249,3 +1514,66 @@ static int __init calgary_parse_options(char *p)
return 1;
}
__setup("calgary=", calgary_parse_options);
+
+static void __init calgary_fixup_one_tce_space(struct pci_dev *dev)
+{
+ struct iommu_table *tbl;
+ unsigned int npages;
+ int i;
+
+ tbl = pci_iommu(dev->bus);
+
+ for (i = 0; i < 4; i++) {
+ struct resource *r = &dev->resource[PCI_BRIDGE_RESOURCES + i];
+
+ /* Don't give out TCEs that map MEM resources */
+ if (!(r->flags & IORESOURCE_MEM))
+ continue;
+
+ /* 0-based? we reserve the whole 1st MB anyway */
+ if (!r->start)
+ continue;
+
+ /* cover the whole region */
+ npages = (r->end - r->start) >> PAGE_SHIFT;
+ npages++;
+
+ iommu_range_reserve(tbl, r->start, npages);
+ }
+}
+
+static int __init calgary_fixup_tce_spaces(void)
+{
+ struct pci_dev *dev = NULL;
+ void *tce_space;
+
+ if (no_iommu || swiotlb || !calgary_detected)
+ return -ENODEV;
+
+ printk(KERN_DEBUG "Calgary: fixing up tce spaces\n");
+
+ do {
+ dev = pci_get_device(PCI_VENDOR_ID_IBM, PCI_ANY_ID, dev);
+ if (!dev)
+ break;
+ if (!is_cal_pci_dev(dev->device))
+ continue;
+ if (!translate_phb(dev))
+ continue;
+
+ tce_space = bus_info[dev->bus->number].tce_space;
+ if (!tce_space)
+ continue;
+
+ calgary_fixup_one_tce_space(dev);
+
+ } while (1);
+
+ return 0;
+}
+
+/*
+ * We need to be call after pcibios_assign_resources (fs_initcall level)
+ * and before device_initcall.
+ */
+rootfs_initcall(calgary_fixup_tce_spaces);
diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
index 9f80aad3fe2d..05d745ede561 100644
--- a/arch/x86_64/kernel/pci-dma.c
+++ b/arch/x86_64/kernel/pci-dma.c
@@ -8,7 +8,7 @@
#include <linux/pci.h>
#include <linux/module.h>
#include <asm/io.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
#include <asm/calgary.h>
int iommu_merge __read_mostly = 0;
@@ -22,8 +22,7 @@ EXPORT_SYMBOL(bad_dma_address);
int iommu_bio_merge __read_mostly = 0;
EXPORT_SYMBOL(iommu_bio_merge);
-int iommu_sac_force __read_mostly = 0;
-EXPORT_SYMBOL(iommu_sac_force);
+static int iommu_sac_force __read_mostly = 0;
int no_iommu __read_mostly;
#ifdef CONFIG_IOMMU_DEBUG
@@ -322,6 +321,11 @@ static int __init pci_iommu_init(void)
return 0;
}
+void pci_iommu_shutdown(void)
+{
+ gart_iommu_shutdown();
+}
+
#ifdef CONFIG_PCI
/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index ae091cdc1a4d..4918c575d582 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -28,6 +28,7 @@
#include <asm/mtrr.h>
#include <asm/pgtable.h>
#include <asm/proto.h>
+#include <asm/iommu.h>
#include <asm/cacheflush.h>
#include <asm/swiotlb.h>
#include <asm/dma.h>
@@ -235,7 +236,7 @@ static dma_addr_t gart_map_simple(struct device *dev, char *buf,
}
/* Map a single area into the IOMMU */
-dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
+static dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
{
unsigned long phys_mem, bus;
@@ -253,7 +254,7 @@ dma_addr_t gart_map_single(struct device *dev, void *addr, size_t size, int dir)
/*
* Free a DMA mapping.
*/
-void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
+static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
size_t size, int direction)
{
unsigned long iommu_page;
@@ -275,7 +276,7 @@ void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
/*
* Wrapper for pci_unmap_single working with scatterlists.
*/
-void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
+static void gart_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
{
int i;
@@ -571,6 +572,26 @@ static const struct dma_mapping_ops gart_dma_ops = {
.unmap_sg = gart_unmap_sg,
};
+void gart_iommu_shutdown(void)
+{
+ struct pci_dev *dev;
+ int i;
+
+ if (no_agp && (dma_ops != &gart_dma_ops))
+ return;
+
+ for (i = 0; i < num_k8_northbridges; i++) {
+ u32 ctl;
+
+ dev = k8_northbridges[i];
+ pci_read_config_dword(dev, 0x90, &ctl);
+
+ ctl &= ~1;
+
+ pci_write_config_dword(dev, 0x90, ctl);
+ }
+}
+
void __init gart_iommu_init(void)
{
struct agp_kern_info info;
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index 6dade0c867cc..2a34c6c025a9 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -6,7 +6,7 @@
#include <linux/string.h>
#include <linux/dma-mapping.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
#include <asm/processor.h>
#include <asm/dma.h>
@@ -34,7 +34,7 @@ nommu_map_single(struct device *hwdev, void *ptr, size_t size,
return bus;
}
-void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
+static void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
int direction)
{
}
@@ -54,7 +54,7 @@ void nommu_unmap_single(struct device *dev, dma_addr_t addr,size_t size,
* Device ownership issues as mentioned above for pci_map_single are
* the same here.
*/
-int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
+static int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
int nents, int direction)
{
int i;
@@ -74,7 +74,7 @@ int nommu_map_sg(struct device *hwdev, struct scatterlist *sg,
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
-void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
+static void nommu_unmap_sg(struct device *dev, struct scatterlist *sg,
int nents, int dir)
{
}
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index 4b4569abc60c..b2f405ea7c85 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -5,7 +5,7 @@
#include <linux/module.h>
#include <linux/dma-mapping.h>
-#include <asm/proto.h>
+#include <asm/iommu.h>
#include <asm/swiotlb.h>
#include <asm/dma.h>
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 5909039f37aa..e7ac629d4c46 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -207,6 +207,7 @@ void cpu_idle (void)
if (__get_cpu_var(cpu_idle_state))
__get_cpu_var(cpu_idle_state) = 0;
+ check_pgt_cache();
rmb();
idle = pm_idle;
if (!idle)
@@ -278,7 +279,7 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
*/
if (!pm_idle) {
if (!printed) {
- printk("using mwait in idle threads.\n");
+ printk(KERN_INFO "using mwait in idle threads.\n");
printed = 1;
}
pm_idle = mwait_idle;
@@ -305,6 +306,7 @@ early_param("idle", idle_setup);
void __show_regs(struct pt_regs * regs)
{
unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
+ unsigned long d0, d1, d2, d3, d6, d7;
unsigned int fsindex,gsindex;
unsigned int ds,cs,es;
@@ -340,15 +342,24 @@ void __show_regs(struct pt_regs * regs)
rdmsrl(MSR_GS_BASE, gs);
rdmsrl(MSR_KERNEL_GS_BASE, shadowgs);
- asm("movq %%cr0, %0": "=r" (cr0));
- asm("movq %%cr2, %0": "=r" (cr2));
- asm("movq %%cr3, %0": "=r" (cr3));
- asm("movq %%cr4, %0": "=r" (cr4));
+ cr0 = read_cr0();
+ cr2 = read_cr2();
+ cr3 = read_cr3();
+ cr4 = read_cr4();
printk("FS: %016lx(%04x) GS:%016lx(%04x) knlGS:%016lx\n",
fs,fsindex,gs,gsindex,shadowgs);
printk("CS: %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0);
printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+
+ get_debugreg(d0, 0);
+ get_debugreg(d1, 1);
+ get_debugreg(d2, 2);
+ printk("DR0: %016lx DR1: %016lx DR2: %016lx\n", d0, d1, d2);
+ get_debugreg(d3, 3);
+ get_debugreg(d6, 6);
+ get_debugreg(d7, 7);
+ printk("DR3: %016lx DR6: %016lx DR7: %016lx\n", d3, d6, d7);
}
void show_regs(struct pt_regs *regs)
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index 9409117b9f19..e83cc67155ac 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -102,16 +102,25 @@ unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *r
u32 *desc;
unsigned long base;
- down(&child->mm->context.sem);
- desc = child->mm->context.ldt + (seg & ~7);
- base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
+ seg &= ~7UL;
- /* 16-bit code segment? */
- if (!((desc[1] >> 22) & 1))
- addr &= 0xffff;
- addr += base;
+ down(&child->mm->context.sem);
+ if (unlikely((seg >> 3) >= child->mm->context.size))
+ addr = -1L; /* bogus selector, access would fault */
+ else {
+ desc = child->mm->context.ldt + seg;
+ base = ((desc[0] >> 16) |
+ ((desc[1] & 0xff) << 16) |
+ (desc[1] & 0xff000000));
+
+ /* 16-bit code segment? */
+ if (!((desc[1] >> 22) & 1))
+ addr &= 0xffff;
+ addr += base;
+ }
up(&child->mm->context.sem);
}
+
return addr;
}
@@ -313,17 +322,9 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
/* when I and D space are separate, these will need to be fixed. */
case PTRACE_PEEKTEXT: /* read word at location addr. */
- case PTRACE_PEEKDATA: {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long __user *) data);
+ case PTRACE_PEEKDATA:
+ ret = generic_ptrace_peekdata(child, addr, data);
break;
- }
/* read the word at location addr in the USER area. */
case PTRACE_PEEKUSR: {
@@ -367,10 +368,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
/* when I and D space are separate, this will have to be fixed. */
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- ret = 0;
- if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index 7503068e788d..368db2b9c5ac 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -16,6 +16,7 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <asm/apic.h>
+#include <asm/iommu.h>
/*
* Power off function, if any
@@ -81,6 +82,7 @@ static inline void kb_wait(void)
void machine_shutdown(void)
{
unsigned long flags;
+
/* Stop the cpus and apics */
#ifdef CONFIG_SMP
int reboot_cpu_id;
@@ -111,6 +113,8 @@ void machine_shutdown(void)
disable_IO_APIC();
local_irq_restore(flags);
+
+ pci_iommu_shutdown();
}
void machine_emergency_restart(void)
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index eb6524f3ac29..af838f6b0b7f 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -575,6 +575,8 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
level = cpuid_eax(1);
if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
+ if (c->x86 == 0x10)
+ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
/* Enable workaround for FXSAVE leak */
if (c->x86 >= 6)
@@ -600,8 +602,14 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
if (c->extended_cpuid_level >= 0x80000008)
amd_detect_cmp(c);
- /* Fix cpuid4 emulation for more */
- num_cache_leaves = 3;
+ if (c->extended_cpuid_level >= 0x80000006 &&
+ (cpuid_edx(0x80000006) & 0xf000))
+ num_cache_leaves = 4;
+ else
+ num_cache_leaves = 3;
+
+ if (c->x86 == 0xf || c->x86 == 0x10 || c->x86 == 0x11)
+ set_bit(X86_FEATURE_K8, &c->x86_capability);
/* RDTSC can be speculated around */
clear_bit(X86_FEATURE_SYNC_RDTSC, &c->x86_capability);
@@ -846,6 +854,8 @@ void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
c->x86_capability[2] = cpuid_edx(0x80860001);
}
+ init_scattered_cpuid_features(c);
+
c->apicid = phys_pkg_id(0);
/*
@@ -931,7 +941,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
- "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
+ "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe",
/* AMD-defined */
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -947,10 +957,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Other (Linux-defined) */
- "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
- "constant_tsc", NULL, NULL,
- "up", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
+ NULL, NULL, NULL, NULL,
+ "constant_tsc", "up", NULL, "arch_perfmon",
+ "pebs", "bts", NULL, "sync_rdtsc",
+ "rep_good", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Intel-defined (#2) */
@@ -961,7 +972,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
/* VIA/Cyrix/Centaur-defined */
NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -972,6 +983,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"osvw", "ibs", NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+ /* Auxiliary (Linux-defined) */
+ "ida", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
static char *x86_power_flags[] = {
"ts", /* temperature sensor */
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index 290f5d8037cd..739175b01e06 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -26,6 +26,7 @@
#include <asm/i387.h>
#include <asm/proto.h>
#include <asm/ia32_unistd.h>
+#include <asm/mce.h>
/* #define DEBUG_SIG 1 */
@@ -472,6 +473,12 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
clear_thread_flag(TIF_SINGLESTEP);
}
+#ifdef CONFIG_X86_MCE
+ /* notify userspace of pending MCEs */
+ if (thread_info_flags & _TIF_MCE_NOTIFY)
+ mce_notify_user();
+#endif /* CONFIG_X86_MCE */
+
/* deal with pending signal delivery */
if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
do_signal(regs);
@@ -480,7 +487,7 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
{
struct task_struct *me = current;
- if (exception_trace)
+ if (show_unhandled_signals && printk_ratelimit())
printk("%s[%d] bad frame in %s frame:%p rip:%lx rsp:%lx orax:%lx\n",
me->comm,me->pid,where,frame,regs->rip,regs->rsp,regs->orig_rax);
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index 2ff468591625..673a300b5944 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -241,7 +241,7 @@ void flush_tlb_mm (struct mm_struct * mm)
}
if (!cpus_empty(cpu_mask))
flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
-
+ check_pgt_cache();
preempt_enable();
}
EXPORT_SYMBOL(flush_tlb_mm);
@@ -357,7 +357,7 @@ __smp_call_function_single(int cpu, void (*func) (void *info), void *info,
}
/*
- * smp_call_function_single - Run a function on another CPU
+ * smp_call_function_single - Run a function on a specific CPU
* @func: The function to run. This must be fast and non-blocking.
* @info: An arbitrary pointer to pass to the function.
* @nonatomic: Currently unused.
@@ -374,17 +374,21 @@ int smp_call_function_single (int cpu, void (*func) (void *info), void *info,
{
/* prevent preemption and reschedule on another processor */
int me = get_cpu();
+
+ /* Can deadlock when called with interrupts disabled */
+ WARN_ON(irqs_disabled());
+
if (cpu == me) {
+ local_irq_disable();
+ func(info);
+ local_irq_enable();
put_cpu();
return 0;
}
- /* Can deadlock when called with interrupts disabled */
- WARN_ON(irqs_disabled());
-
- spin_lock_bh(&call_lock);
+ spin_lock(&call_lock);
__smp_call_function_single(cpu, func, info, nonatomic, wait);
- spin_unlock_bh(&call_lock);
+ spin_unlock(&call_lock);
put_cpu();
return 0;
}
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c
index 6a5a98f2a75c..ea83a9f91965 100644
--- a/arch/x86_64/kernel/suspend.c
+++ b/arch/x86_64/kernel/suspend.c
@@ -55,11 +55,11 @@ void __save_processor_state(struct saved_context *ctxt)
* control registers
*/
rdmsrl(MSR_EFER, ctxt->efer);
- asm volatile ("movq %%cr0, %0" : "=r" (ctxt->cr0));
- asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
- asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
- asm volatile ("movq %%cr4, %0" : "=r" (ctxt->cr4));
- asm volatile ("movq %%cr8, %0" : "=r" (ctxt->cr8));
+ ctxt->cr0 = read_cr0();
+ ctxt->cr2 = read_cr2();
+ ctxt->cr3 = read_cr3();
+ ctxt->cr4 = read_cr4();
+ ctxt->cr8 = read_cr8();
}
void save_processor_state(void)
@@ -81,11 +81,11 @@ void __restore_processor_state(struct saved_context *ctxt)
* control registers
*/
wrmsrl(MSR_EFER, ctxt->efer);
- asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
- asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
- asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
- asm volatile ("movq %0, %%cr2" :: "r" (ctxt->cr2));
- asm volatile ("movq %0, %%cr0" :: "r" (ctxt->cr0));
+ write_cr8(ctxt->cr8);
+ write_cr4(ctxt->cr4);
+ write_cr3(ctxt->cr3);
+ write_cr2(ctxt->cr2);
+ write_cr0(ctxt->cr0);
/*
* now restore the descriptor tables to their proper values
diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c
index f61fb8e4f129..3aeae2fa2e24 100644
--- a/arch/x86_64/kernel/tce.c
+++ b/arch/x86_64/kernel/tce.c
@@ -136,9 +136,9 @@ int build_tce_table(struct pci_dev *dev, void __iomem *bbar)
struct iommu_table *tbl;
int ret;
- if (dev->sysdata) {
- printk(KERN_ERR "Calgary: dev %p has sysdata %p\n",
- dev, dev->sysdata);
+ if (pci_iommu(dev->bus)) {
+ printk(KERN_ERR "Calgary: dev %p has sysdata->iommu %p\n",
+ dev, pci_iommu(dev->bus));
BUG();
}
@@ -155,11 +155,7 @@ int build_tce_table(struct pci_dev *dev, void __iomem *bbar)
tbl->bbar = bbar;
- /*
- * NUMA is already using the bus's sysdata pointer, so we use
- * the bus's pci_dev's sysdata instead.
- */
- dev->sysdata = tbl;
+ set_pci_iommu(dev->bus, tbl);
return 0;
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 4a0895bacf51..6d48a4e826d9 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -33,6 +33,7 @@
#include <acpi/acpi_bus.h>
#endif
#include <asm/8253pit.h>
+#include <asm/i8253.h>
#include <asm/pgtable.h>
#include <asm/vsyscall.h>
#include <asm/timex.h>
@@ -44,12 +45,14 @@
#include <asm/hpet.h>
#include <asm/mpspec.h>
#include <asm/nmi.h>
+#include <asm/vgtod.h>
static char *timename = NULL;
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
DEFINE_SPINLOCK(i8253_lock);
+EXPORT_SYMBOL(i8253_lock);
volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
@@ -79,8 +82,9 @@ EXPORT_SYMBOL(profile_pc);
* sheet for details.
*/
-static void set_rtc_mmss(unsigned long nowtime)
+static int set_rtc_mmss(unsigned long nowtime)
{
+ int retval = 0;
int real_seconds, real_minutes, cmos_minutes;
unsigned char control, freq_select;
@@ -120,6 +124,7 @@ static void set_rtc_mmss(unsigned long nowtime)
if (abs(real_minutes - cmos_minutes) >= 30) {
printk(KERN_WARNING "time.c: can't update CMOS clock "
"from %d to %d\n", cmos_minutes, real_minutes);
+ retval = -1;
} else {
BIN_TO_BCD(real_seconds);
BIN_TO_BCD(real_minutes);
@@ -139,12 +144,17 @@ static void set_rtc_mmss(unsigned long nowtime)
CMOS_WRITE(freq_select, RTC_FREQ_SELECT);
spin_unlock(&rtc_lock);
+
+ return retval;
}
+int update_persistent_clock(struct timespec now)
+{
+ return set_rtc_mmss(now.tv_sec);
+}
void main_timer_handler(void)
{
- static unsigned long rtc_update = 0;
/*
* Here we are in the timer irq handler. We have irqs locally disabled (so we
* don't need spin_lock_irqsave()) but we don't know if the timer_bh is running
@@ -172,20 +182,6 @@ void main_timer_handler(void)
if (!using_apic_timer)
smp_local_timer_interrupt();
-/*
- * If we have an externally synchronized Linux clock, then update CMOS clock
- * accordingly every ~11 minutes. set_rtc_mmss() will be called in the jiffy
- * closest to exactly 500 ms before the next second. If the update fails, we
- * don't care, as it'll be updated on the next turn, and the problem (time way
- * off) isn't likely to go away much sooner anyway.
- */
-
- if (ntp_synced() && xtime.tv_sec > rtc_update &&
- abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {
- set_rtc_mmss(xtime.tv_sec);
- rtc_update = xtime.tv_sec + 660;
- }
-
write_sequnlock(&xtime_lock);
}
@@ -199,7 +195,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static unsigned long get_cmos_time(void)
+unsigned long read_persistent_clock(void)
{
unsigned int year, mon, day, hour, min, sec;
unsigned long flags;
@@ -226,7 +222,7 @@ static unsigned long get_cmos_time(void)
/*
* We know that x86-64 always uses BCD format, no need to check the
* config register.
- */
+ */
BCD_TO_BIN(sec);
BCD_TO_BIN(min);
@@ -239,11 +235,11 @@ static unsigned long get_cmos_time(void)
BCD_TO_BIN(century);
year += century * 100;
printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
- } else {
+ } else {
/*
* x86-64 systems only exists since 2002.
* This will work up to Dec 31, 2100
- */
+ */
year += 2000;
}
@@ -255,45 +251,45 @@ static unsigned long get_cmos_time(void)
#define TICK_COUNT 100000000
static unsigned int __init tsc_calibrate_cpu_khz(void)
{
- int tsc_start, tsc_now;
- int i, no_ctr_free;
- unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
- unsigned long flags;
-
- for (i = 0; i < 4; i++)
- if (avail_to_resrv_perfctr_nmi_bit(i))
- break;
- no_ctr_free = (i == 4);
- if (no_ctr_free) {
- i = 3;
- rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
- wrmsrl(MSR_K7_EVNTSEL3, 0);
- rdmsrl(MSR_K7_PERFCTR3, pmc3);
- } else {
- reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
- reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
- }
- local_irq_save(flags);
- /* start meauring cycles, incrementing from 0 */
- wrmsrl(MSR_K7_PERFCTR0 + i, 0);
- wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
- rdtscl(tsc_start);
- do {
- rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
- tsc_now = get_cycles_sync();
- } while ((tsc_now - tsc_start) < TICK_COUNT);
-
- local_irq_restore(flags);
- if (no_ctr_free) {
- wrmsrl(MSR_K7_EVNTSEL3, 0);
- wrmsrl(MSR_K7_PERFCTR3, pmc3);
- wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
- } else {
- release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
- release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
- }
-
- return pmc_now * tsc_khz / (tsc_now - tsc_start);
+ int tsc_start, tsc_now;
+ int i, no_ctr_free;
+ unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
+ unsigned long flags;
+
+ for (i = 0; i < 4; i++)
+ if (avail_to_resrv_perfctr_nmi_bit(i))
+ break;
+ no_ctr_free = (i == 4);
+ if (no_ctr_free) {
+ i = 3;
+ rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
+ wrmsrl(MSR_K7_EVNTSEL3, 0);
+ rdmsrl(MSR_K7_PERFCTR3, pmc3);
+ } else {
+ reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+ reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+ }
+ local_irq_save(flags);
+ /* start meauring cycles, incrementing from 0 */
+ wrmsrl(MSR_K7_PERFCTR0 + i, 0);
+ wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
+ rdtscl(tsc_start);
+ do {
+ rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
+ tsc_now = get_cycles_sync();
+ } while ((tsc_now - tsc_start) < TICK_COUNT);
+
+ local_irq_restore(flags);
+ if (no_ctr_free) {
+ wrmsrl(MSR_K7_EVNTSEL3, 0);
+ wrmsrl(MSR_K7_PERFCTR3, pmc3);
+ wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
+ } else {
+ release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
+ release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
+ }
+
+ return pmc_now * tsc_khz / (tsc_now - tsc_start);
}
/*
@@ -321,7 +317,7 @@ static unsigned int __init pit_calibrate_tsc(void)
end = get_cycles_sync();
spin_unlock_irqrestore(&i8253_lock, flags);
-
+
return (end - start) / 50;
}
@@ -366,25 +362,20 @@ static struct irqaction irq0 = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED | IRQF_IRQPOLL,
.mask = CPU_MASK_NONE,
- .name = "timer"
+ .name = "timer"
};
void __init time_init(void)
{
if (nohpet)
hpet_address = 0;
- xtime.tv_sec = get_cmos_time();
- xtime.tv_nsec = 0;
-
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
if (hpet_arch_init())
hpet_address = 0;
if (hpet_use_timer) {
/* set tick_nsec to use the proper rate for HPET */
- tick_nsec = TICK_NSEC_HPET;
+ tick_nsec = TICK_NSEC_HPET;
tsc_khz = hpet_calibrate_tsc();
timename = "HPET";
} else {
@@ -415,54 +406,21 @@ void __init time_init(void)
setup_irq(0, &irq0);
}
-
-static long clock_cmos_diff;
-static unsigned long sleep_start;
-
/*
* sysfs support for the timer.
*/
static int timer_suspend(struct sys_device *dev, pm_message_t state)
{
- /*
- * Estimate time zone so that set_time can update the clock
- */
- long cmos_time = get_cmos_time();
-
- clock_cmos_diff = -cmos_time;
- clock_cmos_diff += get_seconds();
- sleep_start = cmos_time;
return 0;
}
static int timer_resume(struct sys_device *dev)
{
- unsigned long flags;
- unsigned long sec;
- unsigned long ctime = get_cmos_time();
- long sleep_length = (ctime - sleep_start) * HZ;
-
- if (sleep_length < 0) {
- printk(KERN_WARNING "Time skew detected in timer resume!\n");
- /* The time after the resume must not be earlier than the time
- * before the suspend or some nasty things will happen
- */
- sleep_length = 0;
- ctime = sleep_start;
- }
if (hpet_address)
hpet_reenable();
else
i8254_timer_resume();
-
- sec = ctime + clock_cmos_diff;
- write_seqlock_irqsave(&xtime_lock,flags);
- xtime.tv_sec = sec;
- xtime.tv_nsec = 0;
- jiffies += sleep_length;
- write_sequnlock_irqrestore(&xtime_lock,flags);
- touch_softlockup_watchdog();
return 0;
}
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index aac1c0be54c6..03888420775d 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -34,6 +34,10 @@
#include <linux/bug.h>
#include <linux/kdebug.h>
+#if defined(CONFIG_EDAC)
+#include <linux/edac.h>
+#endif
+
#include <asm/system.h>
#include <asm/io.h>
#include <asm/atomic.h>
@@ -330,6 +334,7 @@ static int print_trace_stack(void *data, char *name)
static void print_trace_address(void *data, unsigned long addr)
{
+ touch_nmi_watchdog();
printk_address(addr);
}
@@ -518,6 +523,7 @@ void __kprobes __die(const char * str, struct pt_regs * regs, long err)
printk("\n");
notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV);
show_registers(regs);
+ add_taint(TAINT_DIE);
/* Executive summary in case the oops scrolled away */
printk(KERN_ALERT "RIP ");
printk_address(regs->rip);
@@ -531,7 +537,7 @@ void die(const char * str, struct pt_regs * regs, long err)
unsigned long flags = oops_begin();
if (!user_mode(regs))
- report_bug(regs->rip);
+ report_bug(regs->rip, regs);
__die(str, regs, err);
oops_end(flags);
@@ -578,7 +584,8 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
tsk->thread.error_code = error_code;
tsk->thread.trap_no = trapnr;
- if (exception_trace && unhandled_signal(tsk, signr))
+ if (show_unhandled_signals && unhandled_signal(tsk, signr) &&
+ printk_ratelimit())
printk(KERN_INFO
"%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
tsk->comm, tsk->pid, str,
@@ -682,7 +689,8 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
tsk->thread.error_code = error_code;
tsk->thread.trap_no = 13;
- if (exception_trace && unhandled_signal(tsk, SIGSEGV))
+ if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+ printk_ratelimit())
printk(KERN_INFO
"%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
tsk->comm, tsk->pid,
@@ -717,6 +725,13 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
reason);
printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
+#if defined(CONFIG_EDAC)
+ if(edac_handler_set()) {
+ edac_atomic_assert_error();
+ return;
+ }
+#endif
+
if (panic_on_unrecovered_nmi)
panic("NMI: Not continuing");
diff --git a/arch/x86_64/kernel/tsc.c b/arch/x86_64/kernel/tsc.c
index 48f9a8e6aa91..9b76b03d0600 100644
--- a/arch/x86_64/kernel/tsc.c
+++ b/arch/x86_64/kernel/tsc.c
@@ -44,7 +44,7 @@ unsigned long long sched_clock(void)
static int tsc_unstable;
-static inline int check_tsc_unstable(void)
+inline int check_tsc_unstable(void)
{
return tsc_unstable;
}
@@ -61,25 +61,9 @@ static inline int check_tsc_unstable(void)
* first tick after the change will be slightly wrong.
*/
-#include <linux/workqueue.h>
-
-static unsigned int cpufreq_delayed_issched = 0;
-static unsigned int cpufreq_init = 0;
-static struct work_struct cpufreq_delayed_get_work;
-
-static void handle_cpufreq_delayed_get(struct work_struct *v)
-{
- unsigned int cpu;
- for_each_online_cpu(cpu) {
- cpufreq_get(cpu);
- }
- cpufreq_delayed_issched = 0;
-}
-
-static unsigned int ref_freq = 0;
-static unsigned long loops_per_jiffy_ref = 0;
-
-static unsigned long tsc_khz_ref = 0;
+static unsigned int ref_freq;
+static unsigned long loops_per_jiffy_ref;
+static unsigned long tsc_khz_ref;
static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
@@ -125,10 +109,8 @@ static struct notifier_block time_cpufreq_notifier_block = {
static int __init cpufreq_tsc(void)
{
- INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get);
- if (!cpufreq_register_notifier(&time_cpufreq_notifier_block,
- CPUFREQ_TRANSITION_NOTIFIER))
- cpufreq_init = 1;
+ cpufreq_register_notifier(&time_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
return 0;
}
@@ -153,17 +135,18 @@ __cpuinit int unsynchronized_tsc(void)
#endif
/* Most intel systems have synchronized TSCs except for
multi node systems */
- if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
#ifdef CONFIG_ACPI
/* But TSC doesn't tick in C3 so don't use it there */
- if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000)
+ if (acpi_gbl_FADT.header.length > 0 &&
+ acpi_gbl_FADT.C3latency < 1000)
return 1;
#endif
- return 0;
+ return 0;
}
- /* Assume multi socket systems are not synchronized */
- return num_present_cpus() > 1;
+ /* Assume multi socket systems are not synchronized */
+ return num_present_cpus() > 1;
}
int __init notsc_setup(char *s)
diff --git a/arch/x86_64/kernel/verify_cpu.S b/arch/x86_64/kernel/verify_cpu.S
index e035f5948199..45b6f8a975a1 100644
--- a/arch/x86_64/kernel/verify_cpu.S
+++ b/arch/x86_64/kernel/verify_cpu.S
@@ -37,20 +37,6 @@ verify_cpu:
pushl $0 # Kill any dangerous flags
popfl
- /* minimum CPUID flags for x86-64 as defined by AMD */
-#define M(x) (1<<(x))
-#define M2(a,b) M(a)|M(b)
-#define M4(a,b,c,d) M(a)|M(b)|M(c)|M(d)
-
-#define SSE_MASK \
- (M2(X86_FEATURE_XMM,X86_FEATURE_XMM2))
-#define REQUIRED_MASK1 \
- (M4(X86_FEATURE_FPU,X86_FEATURE_PSE,X86_FEATURE_TSC,X86_FEATURE_MSR)|\
- M4(X86_FEATURE_PAE,X86_FEATURE_CX8,X86_FEATURE_PGE,X86_FEATURE_CMOV)|\
- M(X86_FEATURE_FXSR))
-#define REQUIRED_MASK2 \
- (M(X86_FEATURE_LM - 32))
-
pushfl # standard way to check for cpuid
popl %eax
movl %eax,%ebx
@@ -79,8 +65,8 @@ verify_cpu:
verify_cpu_noamd:
movl $0x1,%eax # Does the cpu have what it takes
cpuid
- andl $REQUIRED_MASK1,%edx
- xorl $REQUIRED_MASK1,%edx
+ andl $REQUIRED_MASK0,%edx
+ xorl $REQUIRED_MASK0,%edx
jnz verify_cpu_no_longmode
movl $0x80000000,%eax # See if extended cpuid is implemented
@@ -90,8 +76,8 @@ verify_cpu_noamd:
movl $0x80000001,%eax # Does the cpu have what it takes
cpuid
- andl $REQUIRED_MASK2,%edx
- xorl $REQUIRED_MASK2,%edx
+ andl $REQUIRED_MASK1,%edx
+ xorl $REQUIRED_MASK1,%edx
jnz verify_cpu_no_longmode
verify_cpu_sse_test:
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index dbccfda8364f..ba8ea97abd21 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -28,7 +28,7 @@ SECTIONS
_text = .; /* Text and read-only data */
.text : AT(ADDR(.text) - LOAD_OFFSET) {
/* First the code that has to be first for bootstrapping */
- *(.bootstrap.text)
+ *(.text.head)
_stext = .;
/* Then the rest */
TEXT_TEXT
@@ -48,10 +48,19 @@ SECTIONS
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
__stop___ex_table = .;
- BUG_TABLE
+ NOTES :text :note
+
+ BUG_TABLE :text
RODATA
+ . = ALIGN(4);
+ .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) {
+ __tracedata_start = .;
+ *(.tracedata)
+ __tracedata_end = .;
+ }
+
. = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */
/* Data */
.data : AT(ADDR(.data) - LOAD_OFFSET) {
@@ -91,6 +100,9 @@ SECTIONS
.vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data))
{ *(.vsyscall_gtod_data) }
vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
+ .vsyscall_clock : AT(VLOAD(.vsyscall_clock))
+ { *(.vsyscall_clock) }
+ vsyscall_clock = VVIRT(.vsyscall_clock);
.vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
@@ -131,20 +143,11 @@ SECTIONS
/* might get freed after init */
. = ALIGN(4096);
__smp_alt_begin = .;
- __smp_alt_instructions = .;
- .smp_altinstructions : AT(ADDR(.smp_altinstructions) - LOAD_OFFSET) {
- *(.smp_altinstructions)
- }
- __smp_alt_instructions_end = .;
- . = ALIGN(8);
__smp_locks = .;
.smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
*(.smp_locks)
}
__smp_locks_end = .;
- .smp_altinstr_replacement : AT(ADDR(.smp_altinstr_replacement) - LOAD_OFFSET) {
- *(.smp_altinstr_replacement)
- }
. = ALIGN(4096);
__smp_alt_end = .;
@@ -187,6 +190,12 @@ SECTIONS
.exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
.exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
+/* vdso blob that is mapped into user space */
+ vdso_start = . ;
+ .vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) }
+ . = ALIGN(4096);
+ vdso_end = .;
+
#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(4096);
__initramfs_start = .;
@@ -194,10 +203,8 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(4096);
- __per_cpu_start = .;
- .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(4096)
+
. = ALIGN(4096);
__init_end = .;
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index 57660d58d500..06c34949bfdc 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -42,6 +42,7 @@
#include <asm/segment.h>
#include <asm/desc.h>
#include <asm/topology.h>
+#include <asm/vgtod.h>
#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
#define __syscall_clobber "r11","rcx","memory"
@@ -57,26 +58,9 @@
* - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
* Try to keep this structure as small as possible to avoid cache line ping pongs
*/
-struct vsyscall_gtod_data_t {
- seqlock_t lock;
-
- /* open coded 'struct timespec' */
- time_t wall_time_sec;
- u32 wall_time_nsec;
-
- int sysctl_enabled;
- struct timezone sys_tz;
- struct { /* extract of a clocksource struct */
- cycle_t (*vread)(void);
- cycle_t cycle_last;
- cycle_t mask;
- u32 mult;
- u32 shift;
- } clock;
-};
int __vgetcpu_mode __section_vgetcpu_mode;
-struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data =
+struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
{
.lock = SEQLOCK_UNLOCKED,
.sysctl_enabled = 1,
@@ -96,6 +80,8 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
vsyscall_gtod_data.sys_tz = sys_tz;
+ vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
+ vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic;
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 635e58d443d7..327c9f2fa626 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -159,7 +159,7 @@ void dump_pagetable(unsigned long address)
pmd_t *pmd;
pte_t *pte;
- asm("movq %%cr3,%0" : "=r" (pgd));
+ pgd = (pgd_t *)read_cr3();
pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK);
pgd += pgd_index(address);
@@ -221,16 +221,6 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
return 0;
}
-int unhandled_signal(struct task_struct *tsk, int sig)
-{
- if (is_init(tsk))
- return 1;
- if (tsk->ptrace & PT_PTRACED)
- return 0;
- return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
- (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
-}
-
static noinline void pgtable_bad(unsigned long address, struct pt_regs *regs,
unsigned long error_code)
{
@@ -301,8 +291,8 @@ static int vmalloc_fault(unsigned long address)
return 0;
}
-int page_fault_trace = 0;
-int exception_trace = 1;
+static int page_fault_trace;
+int show_unhandled_signals = 1;
/*
* This routine handles page faults. It determines the address,
@@ -317,7 +307,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
struct vm_area_struct * vma;
unsigned long address;
const struct exception_table_entry *fixup;
- int write;
+ int write, fault;
unsigned long flags;
siginfo_t info;
@@ -326,7 +316,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
prefetchw(&mm->mmap_sem);
/* get the address */
- __asm__("movq %%cr2,%0":"=r" (address));
+ address = read_cr2();
info.si_code = SEGV_MAPERR;
@@ -450,19 +440,18 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- switch (handle_mm_fault(mm, vma, address, write)) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- default:
- goto out_of_memory;
+ fault = handle_mm_fault(mm, vma, address, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
}
-
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
up_read(&mm->mmap_sem);
return;
@@ -495,7 +484,8 @@ bad_area_nosemaphore:
(address >> 32))
return;
- if (exception_trace && unhandled_signal(tsk, SIGSEGV)) {
+ if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) &&
+ printk_ratelimit()) {
printk(
"%s%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n",
tsk->pid > 1 ? KERN_INFO : KERN_EMERG,
@@ -569,7 +559,7 @@ out_of_memory:
}
printk("VM: killing process %s\n", tsk->comm);
if (error_code & 4)
- do_exit(SIGKILL);
+ do_group_exit(SIGKILL);
goto no_context;
do_sigbus:
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index 9a0e98accf04..38f5d6368006 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -383,7 +383,7 @@ void __meminit init_memory_mapping(unsigned long start, unsigned long end)
}
if (!after_bootmem)
- asm volatile("movq %%cr4,%0" : "=r" (mmu_cr4_features));
+ mmu_cr4_features = read_cr4();
__flush_tlb_all();
}
@@ -600,16 +600,6 @@ void mark_rodata_ro(void)
{
unsigned long start = (unsigned long)_stext, end;
-#ifdef CONFIG_HOTPLUG_CPU
- /* It must still be possible to apply SMP alternatives. */
- if (num_possible_cpus() > 1)
- start = (unsigned long)_etext;
-#endif
-
-#ifdef CONFIG_KPROBES
- start = (unsigned long)__start_rodata;
-#endif
-
end = (unsigned long)__end_rodata;
start = (start + PAGE_SIZE - 1) & PAGE_MASK;
end &= PAGE_MASK;
@@ -697,41 +687,6 @@ int kern_addr_valid(unsigned long addr)
return pfn_valid(pte_pfn(*pte));
}
-#ifdef CONFIG_SYSCTL
-#include <linux/sysctl.h>
-
-extern int exception_trace, page_fault_trace;
-
-static ctl_table debug_table2[] = {
- {
- .ctl_name = 99,
- .procname = "exception-trace",
- .data = &exception_trace,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {}
-};
-
-static ctl_table debug_root_table2[] = {
- {
- .ctl_name = CTL_DEBUG,
- .procname = "debug",
- .mode = 0555,
- .child = debug_table2
- },
- {}
-};
-
-static __init int x8664_sysctl_init(void)
-{
- register_sysctl_table(debug_root_table2);
- return 0;
-}
-__initcall(x8664_sysctl_init);
-#endif
-
/* A pseudo VMA to allow ptrace access for the vsyscall page. This only
covers the 64bit vsyscall page now. 32bit has a real VMA now and does
not need special handling anymore. */
@@ -769,8 +724,17 @@ int in_gate_area_no_task(unsigned long addr)
return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
}
-void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
+void * __init alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
{
return __alloc_bootmem_core(pgdat->bdata, size,
SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0);
}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+ return "[vdso]";
+ if (vma == &gate_vma)
+ return "[vsyscall]";
+ return NULL;
+}
diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c
index f983c75825d0..a96006f7ae0c 100644
--- a/arch/x86_64/mm/k8topology.c
+++ b/arch/x86_64/mm/k8topology.c
@@ -44,12 +44,12 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
{
unsigned long prevbase;
struct bootnode nodes[8];
- int nodeid, i, nb;
+ int nodeid, i, j, nb;
unsigned char nodeids[8];
int found = 0;
u32 reg;
unsigned numnodes;
- unsigned dualcore = 0;
+ unsigned num_cores;
if (!early_pci_allowed())
return -1;
@@ -60,6 +60,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb);
+ num_cores = (cpuid_ecx(0x80000008) & 0xff) + 1;
+ printk(KERN_INFO "CPU has %d num_cores\n", num_cores);
+
reg = read_pci_config(0, nb, 0, 0x60);
numnodes = ((reg >> 4) & 0xF) + 1;
if (numnodes <= 1)
@@ -73,8 +76,6 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
unsigned long base,limit;
u32 nodeid;
- /* Undefined before E stepping, but hopefully 0 */
- dualcore |= ((read_pci_config(0, nb, 3, 0xe8) >> 12) & 3) == 1;
base = read_pci_config(0, nb, 1, 0x40 + i*8);
limit = read_pci_config(0, nb, 1, 0x44 + i*8);
@@ -170,8 +171,8 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
for (i = 0; i < 8; i++) {
if (nodes[i].start != nodes[i].end) {
nodeid = nodeids[i];
- apicid_to_node[nodeid << dualcore] = i;
- apicid_to_node[(nodeid << dualcore) + dualcore] = i;
+ for (j = 0; j < num_cores; j++)
+ apicid_to_node[(nodeid * num_cores) + j] = i;
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
}
}
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 51548947ad3b..6da235522269 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -273,9 +273,6 @@ void __init numa_init_array(void)
#ifdef CONFIG_NUMA_EMU
/* Numa emulation */
-#define E820_ADDR_HOLE_SIZE(start, end) \
- (e820_hole_size((start) >> PAGE_SHIFT, (end) >> PAGE_SHIFT) << \
- PAGE_SHIFT)
char *cmdline __initdata;
/*
@@ -319,7 +316,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
return -1;
if (num_nodes > MAX_NUMNODES)
num_nodes = MAX_NUMNODES;
- size = (max_addr - *addr - E820_ADDR_HOLE_SIZE(*addr, max_addr)) /
+ size = (max_addr - *addr - e820_hole_size(*addr, max_addr)) /
num_nodes;
/*
* Calculate the number of big nodes that can be allocated as a result
@@ -347,7 +344,7 @@ static int __init split_nodes_equally(struct bootnode *nodes, u64 *addr,
if (i == num_nodes + node_start - 1)
end = max_addr;
else
- while (end - *addr - E820_ADDR_HOLE_SIZE(*addr, end) <
+ while (end - *addr - e820_hole_size(*addr, end) <
size) {
end += FAKE_NODE_MIN_SIZE;
if (end > max_addr) {
@@ -476,18 +473,22 @@ out:
/*
* We need to vacate all active ranges that may have been registered by
- * SRAT.
+ * SRAT and set acpi_numa to -1 so that srat_disabled() always returns
+ * true. NUMA emulation has succeeded so we will not scan ACPI nodes.
*/
remove_all_active_ranges();
+#ifdef CONFIG_ACPI_NUMA
+ acpi_numa = -1;
+#endif
for_each_node_mask(i, node_possible_map) {
e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
nodes[i].end >> PAGE_SHIFT);
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
}
+ acpi_fake_nodes(nodes, num_nodes);
numa_init_array();
return 0;
}
-#undef E820_ADDR_HOLE_SIZE
#endif /* CONFIG_NUMA_EMU */
void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
diff --git a/arch/x86_64/mm/pageattr.c b/arch/x86_64/mm/pageattr.c
index 9148f4a4cec6..7e161c698af4 100644
--- a/arch/x86_64/mm/pageattr.c
+++ b/arch/x86_64/mm/pageattr.c
@@ -13,7 +13,7 @@
#include <asm/tlbflush.h>
#include <asm/io.h>
-static inline pte_t *lookup_address(unsigned long address)
+pte_t *lookup_address(unsigned long address)
{
pgd_t *pgd = pgd_offset_k(address);
pud_t *pud;
@@ -74,14 +74,12 @@ static void flush_kernel_map(void *arg)
struct page *pg;
/* When clflush is available always use it because it is
- much cheaper than WBINVD. Disable clflush for now because
- the high level code is not ready yet */
- if (1 || !cpu_has_clflush)
+ much cheaper than WBINVD. */
+ if (!cpu_has_clflush)
asm volatile("wbinvd" ::: "memory");
else list_for_each_entry(pg, l, lru) {
void *adr = page_address(pg);
- if (cpu_has_clflush)
- cache_flush_page(adr);
+ cache_flush_page(adr);
}
__flush_tlb_all();
}
@@ -95,7 +93,8 @@ static LIST_HEAD(deferred_pages); /* protected by init_mm.mmap_sem */
static inline void save_page(struct page *fpage)
{
- list_add(&fpage->lru, &deferred_pages);
+ if (!test_and_set_bit(PG_arch_1, &fpage->flags))
+ list_add(&fpage->lru, &deferred_pages);
}
/*
@@ -129,9 +128,12 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
pte_t *kpte;
struct page *kpte_page;
pgprot_t ref_prot2;
+
kpte = lookup_address(address);
if (!kpte) return 0;
kpte_page = virt_to_page(((unsigned long)kpte) & PAGE_MASK);
+ BUG_ON(PageLRU(kpte_page));
+ BUG_ON(PageCompound(kpte_page));
if (pgprot_val(prot) != pgprot_val(ref_prot)) {
if (!pte_huge(*kpte)) {
set_pte(kpte, pfn_pte(pfn, prot));
@@ -159,10 +161,9 @@ __change_page_attr(unsigned long address, unsigned long pfn, pgprot_t prot,
/* on x86-64 the direct mapping set at boot is not using 4k pages */
BUG_ON(PageReserved(kpte_page));
- if (page_private(kpte_page) == 0) {
- save_page(kpte_page);
+ save_page(kpte_page);
+ if (page_private(kpte_page) == 0)
revert_page(address, ref_prot);
- }
return 0;
}
@@ -234,6 +235,10 @@ void global_flush_tlb(void)
flush_map(&l);
list_for_each_entry_safe(pg, next, &l, lru) {
+ list_del(&pg->lru);
+ clear_bit(PG_arch_1, &pg->flags);
+ if (page_private(pg) != 0)
+ continue;
ClearPagePrivate(pg);
__free_page(pg);
}
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 1e76bb0a7277..acdf03e19146 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -106,9 +106,9 @@ static __init int slit_valid(struct acpi_table_slit *slit)
for (j = 0; j < d; j++) {
u8 val = slit->entry[d*i + j];
if (i == j) {
- if (val != 10)
+ if (val != LOCAL_DISTANCE)
return 0;
- } else if (val <= 10)
+ } else if (val <= LOCAL_DISTANCE)
return 0;
}
}
@@ -350,7 +350,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
/* Sanity check to catch more bad SRATs (they are amazingly common).
Make sure the PXMs cover all memory. */
-static int nodes_cover_memory(void)
+static int __init nodes_cover_memory(const struct bootnode *nodes)
{
int i;
unsigned long pxmram, e820ram;
@@ -394,6 +394,9 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
{
int i;
+ if (acpi_numa <= 0)
+ return -1;
+
/* First clean up the node list */
for (i = 0; i < MAX_NUMNODES; i++) {
cutoff_node(i, start, end);
@@ -403,10 +406,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
}
}
- if (acpi_numa <= 0)
- return -1;
-
- if (!nodes_cover_memory()) {
+ if (!nodes_cover_memory(nodes)) {
bad_srat();
return -1;
}
@@ -440,6 +440,86 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
return 0;
}
+#ifdef CONFIG_NUMA_EMU
+static int __init find_node_by_addr(unsigned long addr)
+{
+ int ret = NUMA_NO_NODE;
+ int i;
+
+ for_each_node_mask(i, nodes_parsed) {
+ /*
+ * Find the real node that this emulated node appears on. For
+ * the sake of simplicity, we only use a real node's starting
+ * address to determine which emulated node it appears on.
+ */
+ if (addr >= nodes[i].start && addr < nodes[i].end) {
+ ret = i;
+ break;
+ }
+ }
+ return i;
+}
+
+/*
+ * In NUMA emulation, we need to setup proximity domain (_PXM) to node ID
+ * mappings that respect the real ACPI topology but reflect our emulated
+ * environment. For each emulated node, we find which real node it appears on
+ * and create PXM to NID mappings for those fake nodes which mirror that
+ * locality. SLIT will now represent the correct distances between emulated
+ * nodes as a result of the real topology.
+ */
+void __init acpi_fake_nodes(const struct bootnode *fake_nodes, int num_nodes)
+{
+ int i, j;
+ int fake_node_to_pxm_map[MAX_NUMNODES] = {
+ [0 ... MAX_NUMNODES-1] = PXM_INVAL
+ };
+ unsigned char fake_apicid_to_node[MAX_LOCAL_APIC] = {
+ [0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
+ };
+
+ printk(KERN_INFO "Faking PXM affinity for fake nodes on real "
+ "topology.\n");
+ for (i = 0; i < num_nodes; i++) {
+ int nid, pxm;
+
+ nid = find_node_by_addr(fake_nodes[i].start);
+ if (nid == NUMA_NO_NODE)
+ continue;
+ pxm = node_to_pxm(nid);
+ if (pxm == PXM_INVAL)
+ continue;
+ fake_node_to_pxm_map[i] = pxm;
+ /*
+ * For each apicid_to_node mapping that exists for this real
+ * node, it must now point to the fake node ID.
+ */
+ for (j = 0; j < MAX_LOCAL_APIC; j++)
+ if (apicid_to_node[j] == nid)
+ fake_apicid_to_node[j] = i;
+ }
+ for (i = 0; i < num_nodes; i++)
+ __acpi_map_pxm_to_node(fake_node_to_pxm_map[i], i);
+ memcpy(apicid_to_node, fake_apicid_to_node, sizeof(apicid_to_node));
+
+ nodes_clear(nodes_parsed);
+ for (i = 0; i < num_nodes; i++)
+ if (fake_nodes[i].start != fake_nodes[i].end)
+ node_set(i, nodes_parsed);
+ WARN_ON(!nodes_cover_memory(fake_nodes));
+}
+
+static int null_slit_node_compare(int a, int b)
+{
+ return node_to_pxm(a) == node_to_pxm(b);
+}
+#else
+static int null_slit_node_compare(int a, int b)
+{
+ return a == b;
+}
+#endif /* CONFIG_NUMA_EMU */
+
void __init srat_reserve_add_area(int nodeid)
{
if (found_add_area && nodes_add[nodeid].end) {
@@ -464,7 +544,8 @@ int __node_distance(int a, int b)
int index;
if (!acpi_slit)
- return a == b ? 10 : 20;
+ return null_slit_node_compare(a, b) ? LOCAL_DISTANCE :
+ REMOTE_DISTANCE;
index = acpi_slit->locality_count * node_to_pxm(a);
return acpi_slit->entry[index + node_to_pxm(b)];
}
diff --git a/arch/x86_64/pci/k8-bus.c b/arch/x86_64/pci/k8-bus.c
index 3acf60ded2a0..9cc813e29706 100644
--- a/arch/x86_64/pci/k8-bus.c
+++ b/arch/x86_64/pci/k8-bus.c
@@ -59,6 +59,8 @@ fill_mp_bus_to_cpumask(void)
j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
j++) {
struct pci_bus *bus;
+ struct pci_sysdata *sd;
+
long node = NODE_ID(nid);
/* Algorithm a bit dumb, but
it shouldn't matter here */
@@ -67,7 +69,9 @@ fill_mp_bus_to_cpumask(void)
continue;
if (!node_online(node))
node = 0;
- bus->sysdata = (void *)node;
+
+ sd = bus->sysdata;
+ sd->node = node;
}
}
}
diff --git a/arch/x86_64/vdso/Makefile b/arch/x86_64/vdso/Makefile
new file mode 100644
index 000000000000..8d03de029d9b
--- /dev/null
+++ b/arch/x86_64/vdso/Makefile
@@ -0,0 +1,49 @@
+#
+# x86-64 vDSO.
+#
+
+# files to link into the vdso
+# vdso-start.o has to be first
+vobjs-y := vdso-start.o vdso-note.o vclock_gettime.o vgetcpu.o vvar.o
+
+# files to link into kernel
+obj-y := vma.o vdso.o vdso-syms.o
+
+vobjs := $(foreach F,$(vobjs-y),$(obj)/$F)
+
+$(obj)/vdso.o: $(obj)/vdso.so
+
+targets += vdso.so vdso.lds $(vobjs-y) vdso-syms.o
+
+# The DSO images are built using a special linker script.
+quiet_cmd_syscall = SYSCALL $@
+ cmd_syscall = $(CC) -m elf_x86_64 -nostdlib $(SYSCFLAGS_$(@F)) \
+ -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+export CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+vdso-flags = -fPIC -shared -Wl,-soname=linux-vdso.so.1 \
+ $(call ld-option, -Wl$(comma)--hash-style=sysv) \
+ -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+SYSCFLAGS_vdso.so = $(vdso-flags)
+
+$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so
+
+$(obj)/vdso.so: $(src)/vdso.lds $(vobjs) FORCE
+ $(call if_changed,syscall)
+
+CFL := $(PROFILING) -mcmodel=small -fPIC -g0 -O2 -fasynchronous-unwind-tables -m64
+
+$(obj)/vclock_gettime.o: CFLAGS = $(CFL)
+$(obj)/vgetcpu.o: CFLAGS = $(CFL)
+
+# We also create a special relocatable object that should mirror the symbol
+# table and layout of the linked DSO. With ld -R we can then refer to
+# these symbols in the kernel code rather than hand-coded addresses.
+extra-y += vdso-syms.o
+$(obj)/built-in.o: $(obj)/vdso-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/vdso-syms.o
+
+SYSCFLAGS_vdso-syms.o = -r -d
+$(obj)/vdso-syms.o: $(src)/vdso.lds $(vobjs) FORCE
+ $(call if_changed,syscall)
diff --git a/arch/x86_64/vdso/vclock_gettime.c b/arch/x86_64/vdso/vclock_gettime.c
new file mode 100644
index 000000000000..17f6a00de712
--- /dev/null
+++ b/arch/x86_64/vdso/vclock_gettime.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2006 Andi Kleen, SUSE Labs.
+ * Subject to the GNU Public License, v.2
+ *
+ * Fast user context implementation of clock_gettime and gettimeofday.
+ *
+ * The code should have no internal unresolved relocations.
+ * Check with readelf after changing.
+ * Also alternative() doesn't work.
+ */
+
+#include <linux/kernel.h>
+#include <linux/posix-timers.h>
+#include <linux/time.h>
+#include <linux/string.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include <asm/timex.h>
+#include <asm/hpet.h>
+#include <asm/unistd.h>
+#include <asm/io.h>
+#include <asm/vgtod.h>
+#include "vextern.h"
+
+#define gtod vdso_vsyscall_gtod_data
+
+static long vdso_fallback_gettime(long clock, struct timespec *ts)
+{
+ long ret;
+ asm("syscall" : "=a" (ret) :
+ "0" (__NR_clock_gettime),"D" (clock), "S" (ts) : "memory");
+ return ret;
+}
+
+static inline long vgetns(void)
+{
+ cycles_t (*vread)(void);
+ vread = gtod->clock.vread;
+ return ((vread() - gtod->clock.cycle_last) * gtod->clock.mult) >>
+ gtod->clock.shift;
+}
+
+static noinline int do_realtime(struct timespec *ts)
+{
+ unsigned long seq, ns;
+ do {
+ seq = read_seqbegin(&gtod->lock);
+ ts->tv_sec = gtod->wall_time_sec;
+ ts->tv_nsec = gtod->wall_time_nsec;
+ ns = vgetns();
+ } while (unlikely(read_seqretry(&gtod->lock, seq)));
+ timespec_add_ns(ts, ns);
+ return 0;
+}
+
+/* Copy of the version in kernel/time.c which we cannot directly access */
+static void vset_normalized_timespec(struct timespec *ts, long sec, long nsec)
+{
+ while (nsec >= NSEC_PER_SEC) {
+ nsec -= NSEC_PER_SEC;
+ ++sec;
+ }
+ while (nsec < 0) {
+ nsec += NSEC_PER_SEC;
+ --sec;
+ }
+ ts->tv_sec = sec;
+ ts->tv_nsec = nsec;
+}
+
+static noinline int do_monotonic(struct timespec *ts)
+{
+ unsigned long seq, ns, secs;
+ do {
+ seq = read_seqbegin(&gtod->lock);
+ secs = gtod->wall_time_sec;
+ ns = gtod->wall_time_nsec + vgetns();
+ secs += gtod->wall_to_monotonic.tv_sec;
+ ns += gtod->wall_to_monotonic.tv_nsec;
+ } while (unlikely(read_seqretry(&gtod->lock, seq)));
+ vset_normalized_timespec(ts, secs, ns);
+ return 0;
+}
+
+int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
+{
+ if (likely(gtod->sysctl_enabled && gtod->clock.vread))
+ switch (clock) {
+ case CLOCK_REALTIME:
+ return do_realtime(ts);
+ case CLOCK_MONOTONIC:
+ return do_monotonic(ts);
+ }
+ return vdso_fallback_gettime(clock, ts);
+}
+int clock_gettime(clockid_t, struct timespec *)
+ __attribute__((weak, alias("__vdso_clock_gettime")));
+
+int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ long ret;
+ if (likely(gtod->sysctl_enabled && gtod->clock.vread)) {
+ BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
+ offsetof(struct timespec, tv_nsec) ||
+ sizeof(*tv) != sizeof(struct timespec));
+ do_realtime((struct timespec *)tv);
+ tv->tv_usec /= 1000;
+ if (unlikely(tz != NULL)) {
+ /* This relies on gcc inlining the memcpy. We'll notice
+ if it ever fails to do so. */
+ memcpy(tz, &gtod->sys_tz, sizeof(struct timezone));
+ }
+ return 0;
+ }
+ asm("syscall" : "=a" (ret) :
+ "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
+ return ret;
+}
+int gettimeofday(struct timeval *, struct timezone *)
+ __attribute__((weak, alias("__vdso_gettimeofday")));
diff --git a/arch/x86_64/vdso/vdso-note.S b/arch/x86_64/vdso/vdso-note.S
new file mode 100644
index 000000000000..79a071e4357e
--- /dev/null
+++ b/arch/x86_64/vdso/vdso-note.S
@@ -0,0 +1,12 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+ .long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/x86_64/vdso/vdso-start.S b/arch/x86_64/vdso/vdso-start.S
new file mode 100644
index 000000000000..2dc2cdb84d67
--- /dev/null
+++ b/arch/x86_64/vdso/vdso-start.S
@@ -0,0 +1,2 @@
+ .globl vdso_kernel_start
+vdso_kernel_start:
diff --git a/arch/x86_64/vdso/vdso.S b/arch/x86_64/vdso/vdso.S
new file mode 100644
index 000000000000..92e80c1972a7
--- /dev/null
+++ b/arch/x86_64/vdso/vdso.S
@@ -0,0 +1,2 @@
+ .section ".vdso","a"
+ .incbin "arch/x86_64/vdso/vdso.so"
diff --git a/arch/x86_64/vdso/vdso.lds.S b/arch/x86_64/vdso/vdso.lds.S
new file mode 100644
index 000000000000..b9a60e665d08
--- /dev/null
+++ b/arch/x86_64/vdso/vdso.lds.S
@@ -0,0 +1,77 @@
+/*
+ * Linker script for vsyscall DSO. The vsyscall page is an ELF shared
+ * object prelinked to its virtual address, and with only one read-only
+ * segment (that fits in one page). This script controls its layout.
+ */
+#include <asm/asm-offsets.h>
+#include "voffset.h"
+
+#define VDSO_PRELINK 0xffffffffff700000
+
+SECTIONS
+{
+ . = VDSO_PRELINK + SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ /* This linker script is used both with -r and with -shared.
+ For the layouts to match, we need to skip more than enough
+ space for the dynamic symbol table et al. If this amount
+ is insufficient, ld -shared will barf. Just increase it here. */
+ . = VDSO_PRELINK + VDSO_TEXT_OFFSET;
+
+ .text : { *(.text) } :text
+ .text.ptr : { *(.text.ptr) } :text
+ . = VDSO_PRELINK + 0x900;
+ .data : { *(.data) } :text
+ .bss : { *(.bss) } :text
+
+ .altinstructions : { *(.altinstructions) } :text
+ .altinstr_replacement : { *(.altinstr_replacement) } :text
+
+ .note : { *(.note.*) } :text :note
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .useless : {
+ *(.got.plt) *(.got)
+ *(.gnu.linkonce.d.*)
+ *(.dynbss)
+ *(.gnu.linkonce.b.*)
+ } :text
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ LINUX_2.6 {
+ global:
+ clock_gettime;
+ __vdso_clock_gettime;
+ gettimeofday;
+ __vdso_gettimeofday;
+ getcpu;
+ __vdso_getcpu;
+ local: *;
+ };
+}
diff --git a/arch/x86_64/vdso/vextern.h b/arch/x86_64/vdso/vextern.h
new file mode 100644
index 000000000000..1683ba2ae3e8
--- /dev/null
+++ b/arch/x86_64/vdso/vextern.h
@@ -0,0 +1,16 @@
+#ifndef VEXTERN
+#include <asm/vsyscall.h>
+#define VEXTERN(x) \
+ extern typeof(x) *vdso_ ## x __attribute__((visibility("hidden")));
+#endif
+
+#define VMAGIC 0xfeedbabeabcdefabUL
+
+/* Any kernel variables used in the vDSO must be exported in the main
+ kernel's vmlinux.lds.S/vsyscall.h/proper __section and
+ put into vextern.h and be referenced as a pointer with vdso prefix.
+ The main kernel later fills in the values. */
+
+VEXTERN(jiffies)
+VEXTERN(vgetcpu_mode)
+VEXTERN(vsyscall_gtod_data)
diff --git a/arch/x86_64/vdso/vgetcpu.c b/arch/x86_64/vdso/vgetcpu.c
new file mode 100644
index 000000000000..91f6e85d0fc2
--- /dev/null
+++ b/arch/x86_64/vdso/vgetcpu.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2006 Andi Kleen, SUSE Labs.
+ * Subject to the GNU Public License, v.2
+ *
+ * Fast user context implementation of getcpu()
+ */
+
+#include <linux/kernel.h>
+#include <linux/getcpu.h>
+#include <linux/jiffies.h>
+#include <linux/time.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include "vextern.h"
+
+long __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
+{
+ unsigned int dummy, p;
+ unsigned long j = 0;
+
+ /* Fast cache - only recompute value once per jiffies and avoid
+ relatively costly rdtscp/cpuid otherwise.
+ This works because the scheduler usually keeps the process
+ on the same CPU and this syscall doesn't guarantee its
+ results anyways.
+ We do this here because otherwise user space would do it on
+ its own in a likely inferior way (no access to jiffies).
+ If you don't like it pass NULL. */
+ if (tcache && tcache->blob[0] == (j = *vdso_jiffies)) {
+ p = tcache->blob[1];
+ } else if (*vdso_vgetcpu_mode == VGETCPU_RDTSCP) {
+ /* Load per CPU data from RDTSCP */
+ rdtscp(dummy, dummy, p);
+ } else {
+ /* Load per CPU data from GDT */
+ asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
+ }
+ if (tcache) {
+ tcache->blob[0] = j;
+ tcache->blob[1] = p;
+ }
+ if (cpu)
+ *cpu = p & 0xfff;
+ if (node)
+ *node = p >> 12;
+ return 0;
+}
+
+long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
+ __attribute__((weak, alias("__vdso_getcpu")));
diff --git a/arch/x86_64/vdso/vma.c b/arch/x86_64/vdso/vma.c
new file mode 100644
index 000000000000..d4cb83a6c066
--- /dev/null
+++ b/arch/x86_64/vdso/vma.c
@@ -0,0 +1,139 @@
+/*
+ * Set up the VMAs to tell the VM about the vDSO.
+ * Copyright 2007 Andi Kleen, SUSE Labs.
+ * Subject to the GPL, v.2
+ */
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <asm/vsyscall.h>
+#include <asm/vgtod.h>
+#include <asm/proto.h>
+#include "voffset.h"
+
+int vdso_enabled = 1;
+
+#define VEXTERN(x) extern typeof(__ ## x) *vdso_ ## x;
+#include "vextern.h"
+#undef VEXTERN
+
+extern char vdso_kernel_start[], vdso_start[], vdso_end[];
+extern unsigned short vdso_sync_cpuid;
+
+struct page **vdso_pages;
+
+static inline void *var_ref(void *vbase, char *var, char *name)
+{
+ unsigned offset = var - &vdso_kernel_start[0] + VDSO_TEXT_OFFSET;
+ void *p = vbase + offset;
+ if (*(void **)p != (void *)VMAGIC) {
+ printk("VDSO: variable %s broken\n", name);
+ vdso_enabled = 0;
+ }
+ return p;
+}
+
+static int __init init_vdso_vars(void)
+{
+ int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
+ int i;
+ char *vbase;
+
+ vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL);
+ if (!vdso_pages)
+ goto oom;
+ for (i = 0; i < npages; i++) {
+ struct page *p;
+ p = alloc_page(GFP_KERNEL);
+ if (!p)
+ goto oom;
+ vdso_pages[i] = p;
+ copy_page(page_address(p), vdso_start + i*PAGE_SIZE);
+ }
+
+ vbase = vmap(vdso_pages, npages, 0, PAGE_KERNEL);
+ if (!vbase)
+ goto oom;
+
+ if (memcmp(vbase, "\177ELF", 4)) {
+ printk("VDSO: I'm broken; not ELF\n");
+ vdso_enabled = 0;
+ }
+
+#define V(x) *(typeof(x) *) var_ref(vbase, (char *)RELOC_HIDE(&x, 0), #x)
+#define VEXTERN(x) \
+ V(vdso_ ## x) = &__ ## x;
+#include "vextern.h"
+#undef VEXTERN
+ return 0;
+
+ oom:
+ printk("Cannot allocate vdso\n");
+ vdso_enabled = 0;
+ return -ENOMEM;
+}
+__initcall(init_vdso_vars);
+
+struct linux_binprm;
+
+/* Put the vdso above the (randomized) stack with another randomized offset.
+ This way there is no hole in the middle of address space.
+ To save memory make sure it is still in the same PTE as the stack top.
+ This doesn't give that many random bits */
+static unsigned long vdso_addr(unsigned long start, unsigned len)
+{
+ unsigned long addr, end;
+ unsigned offset;
+ end = (start + PMD_SIZE - 1) & PMD_MASK;
+ if (end >= TASK_SIZE64)
+ end = TASK_SIZE64;
+ end -= len;
+ /* This loses some more bits than a modulo, but is cheaper */
+ offset = get_random_int() & (PTRS_PER_PTE - 1);
+ addr = start + (offset << PAGE_SHIFT);
+ if (addr >= end)
+ addr = end;
+ return addr;
+}
+
+/* Setup a VMA at program startup for the vsyscall page.
+ Not called for compat tasks */
+int arch_setup_additional_pages(struct linux_binprm *bprm, int exstack)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long addr;
+ int ret;
+ unsigned len = round_up(vdso_end - vdso_start, PAGE_SIZE);
+
+ if (!vdso_enabled)
+ return 0;
+
+ down_write(&mm->mmap_sem);
+ addr = vdso_addr(mm->start_stack, len);
+ addr = get_unmapped_area(NULL, addr, len, 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ ret = install_special_mapping(mm, addr, len,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ vdso_pages);
+ if (ret)
+ goto up_fail;
+
+ current->mm->context.vdso = (void *)addr;
+up_fail:
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+static __init int vdso_setup(char *s)
+{
+ vdso_enabled = simple_strtoul(s, NULL, 0);
+ return 0;
+}
+__setup("vdso=", vdso_setup);
diff --git a/arch/x86_64/vdso/voffset.h b/arch/x86_64/vdso/voffset.h
new file mode 100644
index 000000000000..5304204911f2
--- /dev/null
+++ b/arch/x86_64/vdso/voffset.h
@@ -0,0 +1 @@
+#define VDSO_TEXT_OFFSET 0x500
diff --git a/arch/x86_64/vdso/vvar.c b/arch/x86_64/vdso/vvar.c
new file mode 100644
index 000000000000..6fc22219a472
--- /dev/null
+++ b/arch/x86_64/vdso/vvar.c
@@ -0,0 +1,12 @@
+/* Define pointer to external vDSO variables.
+ These are part of the vDSO. The kernel fills in the real addresses
+ at boot time. This is done because when the vdso is linked the
+ kernel isn't yet and we don't know the final addresses. */
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <asm/vsyscall.h>
+#include <asm/timex.h>
+#include <asm/vgtod.h>
+
+#define VEXTERN(x) typeof (__ ## x) *vdso_ ## x = (void *)VMAGIC;
+#include "vextern.h"
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
index 14104ff63093..06a13d9b69db 100644
--- a/arch/xtensa/kernel/ptrace.c
+++ b/arch/xtensa/kernel/ptrace.c
@@ -50,18 +50,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
switch (request) {
case PTRACE_PEEKTEXT: /* read word at location addr. */
case PTRACE_PEEKDATA:
- {
- unsigned long tmp;
- int copied;
-
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- ret = -EIO;
- if (copied != sizeof(tmp))
- break;
- ret = put_user(tmp,(unsigned long *) data);
-
+ ret = generic_ptrace_peekdata(child, addr, data);
goto out;
- }
/* Read the word at location addr in the USER area. */
@@ -138,10 +128,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_POKETEXT: /* write the word at location addr. */
case PTRACE_POKEDATA:
- if (access_process_vm(child, addr, &data, sizeof(data), 1)
- == sizeof(data))
- break;
- ret = -EIO;
+ ret = generic_ptrace_pokedata(child, addr, data);
goto out;
case PTRACE_POKEUSR:
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index 693ab268485e..c5e62f9d9f50 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -482,6 +482,7 @@ void die(const char * str, struct pt_regs * regs, long err)
if (!user_mode(regs))
show_stack(NULL, (unsigned long*)regs->areg[1]);
+ add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
if (in_interrupt())
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index b0582c3c5f8d..ac4ed52034db 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -118,7 +118,8 @@ SECTIONS
_fdata = .;
.data :
{
- *(.data) CONSTRUCTORS
+ DATA_DATA
+ CONSTRUCTORS
. = ALIGN(XCHAL_ICACHE_LINESIZE);
*(.data.cacheline_aligned)
}
@@ -190,10 +191,7 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(4096);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(4096)
/* We need this dummy segment here */
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index 3dc6f2f07bbe..16004067add3 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -41,6 +41,7 @@ void do_page_fault(struct pt_regs *regs)
siginfo_t info;
int is_write, is_exec;
+ int fault;
info.si_code = SEGV_MAPERR;
@@ -102,20 +103,18 @@ good_area:
* the fault.
*/
survive:
- switch (handle_mm_fault(mm, vma, address, is_write)) {
- case VM_FAULT_MINOR:
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- current->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- goto do_sigbus;
- case VM_FAULT_OOM:
- goto out_of_memory;
- default:
+ fault = handle_mm_fault(mm, vma, address, is_write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
BUG();
}
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
up_read(&mm->mmap_sem);
return;
diff --git a/block/Kconfig b/block/Kconfig
index 285935134bcd..ca2ef4e08497 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -51,4 +51,17 @@ config LSF
endif # BLOCK
+config BLK_DEV_BSG
+ bool "Block layer SG support v4 (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ Saying Y here will enable generic SG (SCSI generic) v4 support
+ for any block device.
+
+ Unlike SG v3 (aka block/scsi_ioctl.c drivers/scsi/sg.c), SG v4
+ can handle complicated SCSI commands: tagged variable length cdbs
+ with bidirectional data transfers and generic request/response
+ protocols (e.g. Task Management Functions and SMP in Serial
+ Attached SCSI).
+
source block/Kconfig.iosched
diff --git a/block/Makefile b/block/Makefile
index 4b84d0d5947b..959feeb253be 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_BLOCK) := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o
+obj-$(CONFIG_BLK_DEV_BSG) += bsg.o
obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
obj-$(CONFIG_IOSCHED_AS) += as-iosched.o
obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 109e91b91ffa..3e316dd72529 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -1322,10 +1322,9 @@ static void *as_init_queue(request_queue_t *q)
{
struct as_data *ad;
- ad = kmalloc_node(sizeof(*ad), GFP_KERNEL, q->node);
+ ad = kmalloc_node(sizeof(*ad), GFP_KERNEL | __GFP_ZERO, q->node);
if (!ad)
return NULL;
- memset(ad, 0, sizeof(*ad));
ad->q = q; /* Identify what queue the data belongs to */
diff --git a/block/bsg.c b/block/bsg.c
new file mode 100644
index 000000000000..b571869928a8
--- /dev/null
+++ b/block/bsg.c
@@ -0,0 +1,1080 @@
+/*
+ * bsg.c - block layer implementation of the sg v3 interface
+ *
+ * Copyright (C) 2004 Jens Axboe <axboe@suse.de> SUSE Labs
+ * Copyright (C) 2004 Peter M. Jones <pjones@redhat.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License version 2. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ *
+ */
+/*
+ * TODO
+ * - Should this get merged, block/scsi_ioctl.c will be migrated into
+ * this file. To keep maintenance down, it's easier to have them
+ * seperated right now.
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/file.h>
+#include <linux/blkdev.h>
+#include <linux/poll.h>
+#include <linux/cdev.h>
+#include <linux/percpu.h>
+#include <linux/uio.h>
+#include <linux/bsg.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/sg.h>
+
+#define BSG_DESCRIPTION "Block layer SCSI generic (bsg) driver"
+#define BSG_VERSION "0.4"
+
+struct bsg_device {
+ request_queue_t *queue;
+ spinlock_t lock;
+ struct list_head busy_list;
+ struct list_head done_list;
+ struct hlist_node dev_list;
+ atomic_t ref_count;
+ int minor;
+ int queued_cmds;
+ int done_cmds;
+ wait_queue_head_t wq_done;
+ wait_queue_head_t wq_free;
+ char name[BUS_ID_SIZE];
+ int max_queue;
+ unsigned long flags;
+};
+
+enum {
+ BSG_F_BLOCK = 1,
+ BSG_F_WRITE_PERM = 2,
+};
+
+#define BSG_DEFAULT_CMDS 64
+#define BSG_MAX_DEVS 32768
+
+#undef BSG_DEBUG
+
+#ifdef BSG_DEBUG
+#define dprintk(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ##args)
+#else
+#define dprintk(fmt, args...)
+#endif
+
+static DEFINE_MUTEX(bsg_mutex);
+static int bsg_device_nr, bsg_minor_idx;
+
+#define BSG_LIST_ARRAY_SIZE 8
+static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE];
+
+static struct class *bsg_class;
+static LIST_HEAD(bsg_class_list);
+static int bsg_major;
+
+static struct kmem_cache *bsg_cmd_cachep;
+
+/*
+ * our internal command type
+ */
+struct bsg_command {
+ struct bsg_device *bd;
+ struct list_head list;
+ struct request *rq;
+ struct bio *bio;
+ struct bio *bidi_bio;
+ int err;
+ struct sg_io_v4 hdr;
+ struct sg_io_v4 __user *uhdr;
+ char sense[SCSI_SENSE_BUFFERSIZE];
+};
+
+static void bsg_free_command(struct bsg_command *bc)
+{
+ struct bsg_device *bd = bc->bd;
+ unsigned long flags;
+
+ kmem_cache_free(bsg_cmd_cachep, bc);
+
+ spin_lock_irqsave(&bd->lock, flags);
+ bd->queued_cmds--;
+ spin_unlock_irqrestore(&bd->lock, flags);
+
+ wake_up(&bd->wq_free);
+}
+
+static struct bsg_command *bsg_alloc_command(struct bsg_device *bd)
+{
+ struct bsg_command *bc = ERR_PTR(-EINVAL);
+
+ spin_lock_irq(&bd->lock);
+
+ if (bd->queued_cmds >= bd->max_queue)
+ goto out;
+
+ bd->queued_cmds++;
+ spin_unlock_irq(&bd->lock);
+
+ bc = kmem_cache_zalloc(bsg_cmd_cachep, GFP_KERNEL);
+ if (unlikely(!bc)) {
+ spin_lock_irq(&bd->lock);
+ bd->queued_cmds--;
+ bc = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ bc->bd = bd;
+ INIT_LIST_HEAD(&bc->list);
+ dprintk("%s: returning free cmd %p\n", bd->name, bc);
+ return bc;
+out:
+ spin_unlock_irq(&bd->lock);
+ return bc;
+}
+
+static inline struct hlist_head *bsg_dev_idx_hash(int index)
+{
+ return &bsg_device_list[index & (BSG_LIST_ARRAY_SIZE - 1)];
+}
+
+static int bsg_io_schedule(struct bsg_device *bd)
+{
+ DEFINE_WAIT(wait);
+ int ret = 0;
+
+ spin_lock_irq(&bd->lock);
+
+ BUG_ON(bd->done_cmds > bd->queued_cmds);
+
+ /*
+ * -ENOSPC or -ENODATA? I'm going for -ENODATA, meaning "I have no
+ * work to do", even though we return -ENOSPC after this same test
+ * during bsg_write() -- there, it means our buffer can't have more
+ * bsg_commands added to it, thus has no space left.
+ */
+ if (bd->done_cmds == bd->queued_cmds) {
+ ret = -ENODATA;
+ goto unlock;
+ }
+
+ if (!test_bit(BSG_F_BLOCK, &bd->flags)) {
+ ret = -EAGAIN;
+ goto unlock;
+ }
+
+ prepare_to_wait(&bd->wq_done, &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock_irq(&bd->lock);
+ io_schedule();
+ finish_wait(&bd->wq_done, &wait);
+
+ return ret;
+unlock:
+ spin_unlock_irq(&bd->lock);
+ return ret;
+}
+
+static int blk_fill_sgv4_hdr_rq(request_queue_t *q, struct request *rq,
+ struct sg_io_v4 *hdr, int has_write_perm)
+{
+ memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
+
+ if (copy_from_user(rq->cmd, (void *)(unsigned long)hdr->request,
+ hdr->request_len))
+ return -EFAULT;
+
+ if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) {
+ if (blk_verify_command(rq->cmd, has_write_perm))
+ return -EPERM;
+ } else if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /*
+ * fill in request structure
+ */
+ rq->cmd_len = hdr->request_len;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+
+ rq->timeout = (hdr->timeout * HZ) / 1000;
+ if (!rq->timeout)
+ rq->timeout = q->sg_timeout;
+ if (!rq->timeout)
+ rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
+
+ return 0;
+}
+
+/*
+ * Check if sg_io_v4 from user is allowed and valid
+ */
+static int
+bsg_validate_sgv4_hdr(request_queue_t *q, struct sg_io_v4 *hdr, int *rw)
+{
+ int ret = 0;
+
+ if (hdr->guard != 'Q')
+ return -EINVAL;
+ if (hdr->request_len > BLK_MAX_CDB)
+ return -EINVAL;
+ if (hdr->dout_xfer_len > (q->max_sectors << 9) ||
+ hdr->din_xfer_len > (q->max_sectors << 9))
+ return -EIO;
+
+ switch (hdr->protocol) {
+ case BSG_PROTOCOL_SCSI:
+ switch (hdr->subprotocol) {
+ case BSG_SUB_PROTOCOL_SCSI_CMD:
+ case BSG_SUB_PROTOCOL_SCSI_TRANSPORT:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ *rw = hdr->dout_xfer_len ? WRITE : READ;
+ return ret;
+}
+
+/*
+ * map sg_io_v4 to a request.
+ */
+static struct request *
+bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr)
+{
+ request_queue_t *q = bd->queue;
+ struct request *rq, *next_rq = NULL;
+ int ret, rw;
+ unsigned int dxfer_len;
+ void *dxferp = NULL;
+
+ dprintk("map hdr %llx/%u %llx/%u\n", (unsigned long long) hdr->dout_xferp,
+ hdr->dout_xfer_len, (unsigned long long) hdr->din_xferp,
+ hdr->din_xfer_len);
+
+ ret = bsg_validate_sgv4_hdr(q, hdr, &rw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /*
+ * map scatter-gather elements seperately and string them to request
+ */
+ rq = blk_get_request(q, rw, GFP_KERNEL);
+ if (!rq)
+ return ERR_PTR(-ENOMEM);
+ ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM,
+ &bd->flags));
+ if (ret)
+ goto out;
+
+ if (rw == WRITE && hdr->din_xfer_len) {
+ if (!test_bit(QUEUE_FLAG_BIDI, &q->queue_flags)) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ next_rq = blk_get_request(q, READ, GFP_KERNEL);
+ if (!next_rq) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ rq->next_rq = next_rq;
+
+ dxferp = (void*)(unsigned long)hdr->din_xferp;
+ ret = blk_rq_map_user(q, next_rq, dxferp, hdr->din_xfer_len);
+ if (ret)
+ goto out;
+ }
+
+ if (hdr->dout_xfer_len) {
+ dxfer_len = hdr->dout_xfer_len;
+ dxferp = (void*)(unsigned long)hdr->dout_xferp;
+ } else if (hdr->din_xfer_len) {
+ dxfer_len = hdr->din_xfer_len;
+ dxferp = (void*)(unsigned long)hdr->din_xferp;
+ } else
+ dxfer_len = 0;
+
+ if (dxfer_len) {
+ ret = blk_rq_map_user(q, rq, dxferp, dxfer_len);
+ if (ret)
+ goto out;
+ }
+ return rq;
+out:
+ blk_put_request(rq);
+ if (next_rq) {
+ blk_rq_unmap_user(next_rq->bio);
+ blk_put_request(next_rq);
+ }
+ return ERR_PTR(ret);
+}
+
+/*
+ * async completion call-back from the block layer, when scsi/ide/whatever
+ * calls end_that_request_last() on a request
+ */
+static void bsg_rq_end_io(struct request *rq, int uptodate)
+{
+ struct bsg_command *bc = rq->end_io_data;
+ struct bsg_device *bd = bc->bd;
+ unsigned long flags;
+
+ dprintk("%s: finished rq %p bc %p, bio %p stat %d\n",
+ bd->name, rq, bc, bc->bio, uptodate);
+
+ bc->hdr.duration = jiffies_to_msecs(jiffies - bc->hdr.duration);
+
+ spin_lock_irqsave(&bd->lock, flags);
+ list_move_tail(&bc->list, &bd->done_list);
+ bd->done_cmds++;
+ spin_unlock_irqrestore(&bd->lock, flags);
+
+ wake_up(&bd->wq_done);
+}
+
+/*
+ * do final setup of a 'bc' and submit the matching 'rq' to the block
+ * layer for io
+ */
+static void bsg_add_command(struct bsg_device *bd, request_queue_t *q,
+ struct bsg_command *bc, struct request *rq)
+{
+ rq->sense = bc->sense;
+ rq->sense_len = 0;
+
+ /*
+ * add bc command to busy queue and submit rq for io
+ */
+ bc->rq = rq;
+ bc->bio = rq->bio;
+ if (rq->next_rq)
+ bc->bidi_bio = rq->next_rq->bio;
+ bc->hdr.duration = jiffies;
+ spin_lock_irq(&bd->lock);
+ list_add_tail(&bc->list, &bd->busy_list);
+ spin_unlock_irq(&bd->lock);
+
+ dprintk("%s: queueing rq %p, bc %p\n", bd->name, rq, bc);
+
+ rq->end_io_data = bc;
+ blk_execute_rq_nowait(q, NULL, rq, 1, bsg_rq_end_io);
+}
+
+static struct bsg_command *bsg_next_done_cmd(struct bsg_device *bd)
+{
+ struct bsg_command *bc = NULL;
+
+ spin_lock_irq(&bd->lock);
+ if (bd->done_cmds) {
+ bc = list_entry(bd->done_list.next, struct bsg_command, list);
+ list_del(&bc->list);
+ bd->done_cmds--;
+ }
+ spin_unlock_irq(&bd->lock);
+
+ return bc;
+}
+
+/*
+ * Get a finished command from the done list
+ */
+static struct bsg_command *bsg_get_done_cmd(struct bsg_device *bd)
+{
+ struct bsg_command *bc;
+ int ret;
+
+ do {
+ bc = bsg_next_done_cmd(bd);
+ if (bc)
+ break;
+
+ if (!test_bit(BSG_F_BLOCK, &bd->flags)) {
+ bc = ERR_PTR(-EAGAIN);
+ break;
+ }
+
+ ret = wait_event_interruptible(bd->wq_done, bd->done_cmds);
+ if (ret) {
+ bc = ERR_PTR(-ERESTARTSYS);
+ break;
+ }
+ } while (1);
+
+ dprintk("%s: returning done %p\n", bd->name, bc);
+
+ return bc;
+}
+
+static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
+ struct bio *bio, struct bio *bidi_bio)
+{
+ int ret = 0;
+
+ dprintk("rq %p bio %p %u\n", rq, bio, rq->errors);
+ /*
+ * fill in all the output members
+ */
+ hdr->device_status = status_byte(rq->errors);
+ hdr->transport_status = host_byte(rq->errors);
+ hdr->driver_status = driver_byte(rq->errors);
+ hdr->info = 0;
+ if (hdr->device_status || hdr->transport_status || hdr->driver_status)
+ hdr->info |= SG_INFO_CHECK;
+ hdr->din_resid = rq->data_len;
+ hdr->response_len = 0;
+
+ if (rq->sense_len && hdr->response) {
+ int len = min_t(unsigned int, hdr->max_response_len,
+ rq->sense_len);
+
+ ret = copy_to_user((void*)(unsigned long)hdr->response,
+ rq->sense, len);
+ if (!ret)
+ hdr->response_len = len;
+ else
+ ret = -EFAULT;
+ }
+
+ if (rq->next_rq) {
+ blk_rq_unmap_user(bidi_bio);
+ blk_put_request(rq->next_rq);
+ }
+
+ blk_rq_unmap_user(bio);
+ blk_put_request(rq);
+
+ return ret;
+}
+
+static int bsg_complete_all_commands(struct bsg_device *bd)
+{
+ struct bsg_command *bc;
+ int ret, tret;
+
+ dprintk("%s: entered\n", bd->name);
+
+ set_bit(BSG_F_BLOCK, &bd->flags);
+
+ /*
+ * wait for all commands to complete
+ */
+ ret = 0;
+ do {
+ ret = bsg_io_schedule(bd);
+ /*
+ * look for -ENODATA specifically -- we'll sometimes get
+ * -ERESTARTSYS when we've taken a signal, but we can't
+ * return until we're done freeing the queue, so ignore
+ * it. The signal will get handled when we're done freeing
+ * the bsg_device.
+ */
+ } while (ret != -ENODATA);
+
+ /*
+ * discard done commands
+ */
+ ret = 0;
+ do {
+ spin_lock_irq(&bd->lock);
+ if (!bd->queued_cmds) {
+ spin_unlock_irq(&bd->lock);
+ break;
+ }
+ spin_unlock_irq(&bd->lock);
+
+ bc = bsg_get_done_cmd(bd);
+ if (IS_ERR(bc))
+ break;
+
+ tret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio,
+ bc->bidi_bio);
+ if (!ret)
+ ret = tret;
+
+ bsg_free_command(bc);
+ } while (1);
+
+ return ret;
+}
+
+static int
+__bsg_read(char __user *buf, size_t count, struct bsg_device *bd,
+ const struct iovec *iov, ssize_t *bytes_read)
+{
+ struct bsg_command *bc;
+ int nr_commands, ret;
+
+ if (count % sizeof(struct sg_io_v4))
+ return -EINVAL;
+
+ ret = 0;
+ nr_commands = count / sizeof(struct sg_io_v4);
+ while (nr_commands) {
+ bc = bsg_get_done_cmd(bd);
+ if (IS_ERR(bc)) {
+ ret = PTR_ERR(bc);
+ break;
+ }
+
+ /*
+ * this is the only case where we need to copy data back
+ * after completing the request. so do that here,
+ * bsg_complete_work() cannot do that for us
+ */
+ ret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio,
+ bc->bidi_bio);
+
+ if (copy_to_user(buf, &bc->hdr, sizeof(bc->hdr)))
+ ret = -EFAULT;
+
+ bsg_free_command(bc);
+
+ if (ret)
+ break;
+
+ buf += sizeof(struct sg_io_v4);
+ *bytes_read += sizeof(struct sg_io_v4);
+ nr_commands--;
+ }
+
+ return ret;
+}
+
+static inline void bsg_set_block(struct bsg_device *bd, struct file *file)
+{
+ if (file->f_flags & O_NONBLOCK)
+ clear_bit(BSG_F_BLOCK, &bd->flags);
+ else
+ set_bit(BSG_F_BLOCK, &bd->flags);
+}
+
+static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file)
+{
+ if (file->f_mode & FMODE_WRITE)
+ set_bit(BSG_F_WRITE_PERM, &bd->flags);
+ else
+ clear_bit(BSG_F_WRITE_PERM, &bd->flags);
+}
+
+/*
+ * Check if the error is a "real" error that we should return.
+ */
+static inline int err_block_err(int ret)
+{
+ if (ret && ret != -ENOSPC && ret != -ENODATA && ret != -EAGAIN)
+ return 1;
+
+ return 0;
+}
+
+static ssize_t
+bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct bsg_device *bd = file->private_data;
+ int ret;
+ ssize_t bytes_read;
+
+ dprintk("%s: read %Zd bytes\n", bd->name, count);
+
+ bsg_set_block(bd, file);
+ bytes_read = 0;
+ ret = __bsg_read(buf, count, bd, NULL, &bytes_read);
+ *ppos = bytes_read;
+
+ if (!bytes_read || (bytes_read && err_block_err(ret)))
+ bytes_read = ret;
+
+ return bytes_read;
+}
+
+static int __bsg_write(struct bsg_device *bd, const char __user *buf,
+ size_t count, ssize_t *bytes_written)
+{
+ struct bsg_command *bc;
+ struct request *rq;
+ int ret, nr_commands;
+
+ if (count % sizeof(struct sg_io_v4))
+ return -EINVAL;
+
+ nr_commands = count / sizeof(struct sg_io_v4);
+ rq = NULL;
+ bc = NULL;
+ ret = 0;
+ while (nr_commands) {
+ request_queue_t *q = bd->queue;
+
+ bc = bsg_alloc_command(bd);
+ if (IS_ERR(bc)) {
+ ret = PTR_ERR(bc);
+ bc = NULL;
+ break;
+ }
+
+ bc->uhdr = (struct sg_io_v4 __user *) buf;
+ if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ /*
+ * get a request, fill in the blanks, and add to request queue
+ */
+ rq = bsg_map_hdr(bd, &bc->hdr);
+ if (IS_ERR(rq)) {
+ ret = PTR_ERR(rq);
+ rq = NULL;
+ break;
+ }
+
+ bsg_add_command(bd, q, bc, rq);
+ bc = NULL;
+ rq = NULL;
+ nr_commands--;
+ buf += sizeof(struct sg_io_v4);
+ *bytes_written += sizeof(struct sg_io_v4);
+ }
+
+ if (bc)
+ bsg_free_command(bc);
+
+ return ret;
+}
+
+static ssize_t
+bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct bsg_device *bd = file->private_data;
+ ssize_t bytes_written;
+ int ret;
+
+ dprintk("%s: write %Zd bytes\n", bd->name, count);
+
+ bsg_set_block(bd, file);
+ bsg_set_write_perm(bd, file);
+
+ bytes_written = 0;
+ ret = __bsg_write(bd, buf, count, &bytes_written);
+ *ppos = bytes_written;
+
+ /*
+ * return bytes written on non-fatal errors
+ */
+ if (!bytes_written || (bytes_written && err_block_err(ret)))
+ bytes_written = ret;
+
+ dprintk("%s: returning %Zd\n", bd->name, bytes_written);
+ return bytes_written;
+}
+
+static struct bsg_device *bsg_alloc_device(void)
+{
+ struct bsg_device *bd;
+
+ bd = kzalloc(sizeof(struct bsg_device), GFP_KERNEL);
+ if (unlikely(!bd))
+ return NULL;
+
+ spin_lock_init(&bd->lock);
+
+ bd->max_queue = BSG_DEFAULT_CMDS;
+
+ INIT_LIST_HEAD(&bd->busy_list);
+ INIT_LIST_HEAD(&bd->done_list);
+ INIT_HLIST_NODE(&bd->dev_list);
+
+ init_waitqueue_head(&bd->wq_free);
+ init_waitqueue_head(&bd->wq_done);
+ return bd;
+}
+
+static int bsg_put_device(struct bsg_device *bd)
+{
+ int ret = 0;
+
+ mutex_lock(&bsg_mutex);
+
+ if (!atomic_dec_and_test(&bd->ref_count))
+ goto out;
+
+ dprintk("%s: tearing down\n", bd->name);
+
+ /*
+ * close can always block
+ */
+ set_bit(BSG_F_BLOCK, &bd->flags);
+
+ /*
+ * correct error detection baddies here again. it's the responsibility
+ * of the app to properly reap commands before close() if it wants
+ * fool-proof error detection
+ */
+ ret = bsg_complete_all_commands(bd);
+
+ blk_put_queue(bd->queue);
+ hlist_del(&bd->dev_list);
+ kfree(bd);
+out:
+ mutex_unlock(&bsg_mutex);
+ return ret;
+}
+
+static struct bsg_device *bsg_add_device(struct inode *inode,
+ struct request_queue *rq,
+ struct file *file)
+{
+ struct bsg_device *bd;
+#ifdef BSG_DEBUG
+ unsigned char buf[32];
+#endif
+
+ bd = bsg_alloc_device();
+ if (!bd)
+ return ERR_PTR(-ENOMEM);
+
+ bd->queue = rq;
+ kobject_get(&rq->kobj);
+ bsg_set_block(bd, file);
+
+ atomic_set(&bd->ref_count, 1);
+ bd->minor = iminor(inode);
+ mutex_lock(&bsg_mutex);
+ hlist_add_head(&bd->dev_list, bsg_dev_idx_hash(bd->minor));
+
+ strncpy(bd->name, rq->bsg_dev.class_dev->class_id, sizeof(bd->name) - 1);
+ dprintk("bound to <%s>, max queue %d\n",
+ format_dev_t(buf, inode->i_rdev), bd->max_queue);
+
+ mutex_unlock(&bsg_mutex);
+ return bd;
+}
+
+static struct bsg_device *__bsg_get_device(int minor)
+{
+ struct bsg_device *bd = NULL;
+ struct hlist_node *entry;
+
+ mutex_lock(&bsg_mutex);
+
+ hlist_for_each(entry, bsg_dev_idx_hash(minor)) {
+ bd = hlist_entry(entry, struct bsg_device, dev_list);
+ if (bd->minor == minor) {
+ atomic_inc(&bd->ref_count);
+ break;
+ }
+
+ bd = NULL;
+ }
+
+ mutex_unlock(&bsg_mutex);
+ return bd;
+}
+
+static struct bsg_device *bsg_get_device(struct inode *inode, struct file *file)
+{
+ struct bsg_device *bd = __bsg_get_device(iminor(inode));
+ struct bsg_class_device *bcd, *__bcd;
+
+ if (bd)
+ return bd;
+
+ /*
+ * find the class device
+ */
+ bcd = NULL;
+ mutex_lock(&bsg_mutex);
+ list_for_each_entry(__bcd, &bsg_class_list, list) {
+ if (__bcd->minor == iminor(inode)) {
+ bcd = __bcd;
+ break;
+ }
+ }
+ mutex_unlock(&bsg_mutex);
+
+ if (!bcd)
+ return ERR_PTR(-ENODEV);
+
+ return bsg_add_device(inode, bcd->queue, file);
+}
+
+static int bsg_open(struct inode *inode, struct file *file)
+{
+ struct bsg_device *bd = bsg_get_device(inode, file);
+
+ if (IS_ERR(bd))
+ return PTR_ERR(bd);
+
+ file->private_data = bd;
+ return 0;
+}
+
+static int bsg_release(struct inode *inode, struct file *file)
+{
+ struct bsg_device *bd = file->private_data;
+
+ file->private_data = NULL;
+ return bsg_put_device(bd);
+}
+
+static unsigned int bsg_poll(struct file *file, poll_table *wait)
+{
+ struct bsg_device *bd = file->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(file, &bd->wq_done, wait);
+ poll_wait(file, &bd->wq_free, wait);
+
+ spin_lock_irq(&bd->lock);
+ if (!list_empty(&bd->done_list))
+ mask |= POLLIN | POLLRDNORM;
+ if (bd->queued_cmds >= bd->max_queue)
+ mask |= POLLOUT;
+ spin_unlock_irq(&bd->lock);
+
+ return mask;
+}
+
+static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct bsg_device *bd = file->private_data;
+ int __user *uarg = (int __user *) arg;
+
+ switch (cmd) {
+ /*
+ * our own ioctls
+ */
+ case SG_GET_COMMAND_Q:
+ return put_user(bd->max_queue, uarg);
+ case SG_SET_COMMAND_Q: {
+ int queue;
+
+ if (get_user(queue, uarg))
+ return -EFAULT;
+ if (queue < 1)
+ return -EINVAL;
+
+ spin_lock_irq(&bd->lock);
+ bd->max_queue = queue;
+ spin_unlock_irq(&bd->lock);
+ return 0;
+ }
+
+ /*
+ * SCSI/sg ioctls
+ */
+ case SG_GET_VERSION_NUM:
+ case SCSI_IOCTL_GET_IDLUN:
+ case SCSI_IOCTL_GET_BUS_NUMBER:
+ case SG_SET_TIMEOUT:
+ case SG_GET_TIMEOUT:
+ case SG_GET_RESERVED_SIZE:
+ case SG_SET_RESERVED_SIZE:
+ case SG_EMULATED_HOST:
+ case SCSI_IOCTL_SEND_COMMAND: {
+ void __user *uarg = (void __user *) arg;
+ return scsi_cmd_ioctl(file, bd->queue, NULL, cmd, uarg);
+ }
+ case SG_IO: {
+ struct request *rq;
+ struct bio *bio, *bidi_bio = NULL;
+ struct sg_io_v4 hdr;
+
+ if (copy_from_user(&hdr, uarg, sizeof(hdr)))
+ return -EFAULT;
+
+ rq = bsg_map_hdr(bd, &hdr);
+ if (IS_ERR(rq))
+ return PTR_ERR(rq);
+
+ bio = rq->bio;
+ if (rq->next_rq)
+ bidi_bio = rq->next_rq->bio;
+ blk_execute_rq(bd->queue, NULL, rq, 0);
+ blk_complete_sgv4_hdr_rq(rq, &hdr, bio, bidi_bio);
+
+ if (copy_to_user(uarg, &hdr, sizeof(hdr)))
+ return -EFAULT;
+
+ return 0;
+ }
+ /*
+ * block device ioctls
+ */
+ default:
+#if 0
+ return ioctl_by_bdev(bd->bdev, cmd, arg);
+#else
+ return -ENOTTY;
+#endif
+ }
+}
+
+static struct file_operations bsg_fops = {
+ .read = bsg_read,
+ .write = bsg_write,
+ .poll = bsg_poll,
+ .open = bsg_open,
+ .release = bsg_release,
+ .unlocked_ioctl = bsg_ioctl,
+ .owner = THIS_MODULE,
+};
+
+void bsg_unregister_queue(struct request_queue *q)
+{
+ struct bsg_class_device *bcd = &q->bsg_dev;
+
+ if (!bcd->class_dev)
+ return;
+
+ mutex_lock(&bsg_mutex);
+ sysfs_remove_link(&q->kobj, "bsg");
+ class_device_unregister(bcd->class_dev);
+ put_device(bcd->dev);
+ bcd->class_dev = NULL;
+ bcd->dev = NULL;
+ list_del_init(&bcd->list);
+ bsg_device_nr--;
+ mutex_unlock(&bsg_mutex);
+}
+EXPORT_SYMBOL_GPL(bsg_unregister_queue);
+
+int bsg_register_queue(struct request_queue *q, struct device *gdev,
+ const char *name)
+{
+ struct bsg_class_device *bcd, *__bcd;
+ dev_t dev;
+ int ret = -EMFILE;
+ struct class_device *class_dev = NULL;
+ const char *devname;
+
+ if (name)
+ devname = name;
+ else
+ devname = gdev->bus_id;
+
+ /*
+ * we need a proper transport to send commands, not a stacked device
+ */
+ if (!q->request_fn)
+ return 0;
+
+ bcd = &q->bsg_dev;
+ memset(bcd, 0, sizeof(*bcd));
+ INIT_LIST_HEAD(&bcd->list);
+
+ mutex_lock(&bsg_mutex);
+ if (bsg_device_nr == BSG_MAX_DEVS) {
+ printk(KERN_ERR "bsg: too many bsg devices\n");
+ goto err;
+ }
+
+retry:
+ list_for_each_entry(__bcd, &bsg_class_list, list) {
+ if (__bcd->minor == bsg_minor_idx) {
+ bsg_minor_idx++;
+ if (bsg_minor_idx == BSG_MAX_DEVS)
+ bsg_minor_idx = 0;
+ goto retry;
+ }
+ }
+
+ bcd->minor = bsg_minor_idx++;
+ if (bsg_minor_idx == BSG_MAX_DEVS)
+ bsg_minor_idx = 0;
+
+ bcd->queue = q;
+ bcd->dev = get_device(gdev);
+ dev = MKDEV(bsg_major, bcd->minor);
+ class_dev = class_device_create(bsg_class, NULL, dev, gdev, "%s",
+ devname);
+ if (IS_ERR(class_dev)) {
+ ret = PTR_ERR(class_dev);
+ goto err_put;
+ }
+ bcd->class_dev = class_dev;
+
+ if (q->kobj.sd) {
+ ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg");
+ if (ret)
+ goto err_unregister;
+ }
+
+ list_add_tail(&bcd->list, &bsg_class_list);
+ bsg_device_nr++;
+
+ mutex_unlock(&bsg_mutex);
+ return 0;
+
+err_unregister:
+ class_device_unregister(class_dev);
+err_put:
+ put_device(gdev);
+err:
+ mutex_unlock(&bsg_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(bsg_register_queue);
+
+static struct cdev bsg_cdev = {
+ .kobj = {.name = "bsg", },
+ .owner = THIS_MODULE,
+};
+
+static int __init bsg_init(void)
+{
+ int ret, i;
+ dev_t devid;
+
+ bsg_cmd_cachep = kmem_cache_create("bsg_cmd",
+ sizeof(struct bsg_command), 0, 0, NULL);
+ if (!bsg_cmd_cachep) {
+ printk(KERN_ERR "bsg: failed creating slab cache\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < BSG_LIST_ARRAY_SIZE; i++)
+ INIT_HLIST_HEAD(&bsg_device_list[i]);
+
+ bsg_class = class_create(THIS_MODULE, "bsg");
+ if (IS_ERR(bsg_class)) {
+ ret = PTR_ERR(bsg_class);
+ goto destroy_kmemcache;
+ }
+
+ ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg");
+ if (ret)
+ goto destroy_bsg_class;
+
+ bsg_major = MAJOR(devid);
+
+ cdev_init(&bsg_cdev, &bsg_fops);
+ ret = cdev_add(&bsg_cdev, MKDEV(bsg_major, 0), BSG_MAX_DEVS);
+ if (ret)
+ goto unregister_chrdev;
+
+ printk(KERN_INFO BSG_DESCRIPTION " version " BSG_VERSION
+ " loaded (major %d)\n", bsg_major);
+ return 0;
+unregister_chrdev:
+ unregister_chrdev_region(MKDEV(bsg_major, 0), BSG_MAX_DEVS);
+destroy_bsg_class:
+ class_destroy(bsg_class);
+destroy_kmemcache:
+ kmem_cache_destroy(bsg_cmd_cachep);
+ return ret;
+}
+
+MODULE_AUTHOR("Jens Axboe");
+MODULE_DESCRIPTION(BSG_DESCRIPTION);
+MODULE_LICENSE("GPL");
+
+device_initcall(bsg_init);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index e0aa4dad6742..d148ccbc36d1 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -92,7 +92,11 @@ struct cfq_data {
struct cfq_queue *active_queue;
struct cfq_io_context *active_cic;
- struct cfq_queue *async_cfqq[IOPRIO_BE_NR];
+ /*
+ * async queue for each priority case
+ */
+ struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR];
+ struct cfq_queue *async_idle_cfqq;
struct timer_list idle_class_timer;
@@ -111,9 +115,6 @@ struct cfq_data {
unsigned int cfq_slice_idle;
struct list_head cic_list;
-
- sector_t new_seek_mean;
- u64 new_seek_total;
};
/*
@@ -153,8 +154,6 @@ struct cfq_queue {
/* various state flags, see below */
unsigned int flags;
-
- sector_t last_request_pos;
};
enum cfqq_state_flags {
@@ -1251,9 +1250,9 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
{
struct cfq_io_context *cic;
- cic = kmem_cache_alloc_node(cfq_ioc_pool, gfp_mask, cfqd->queue->node);
+ cic = kmem_cache_alloc_node(cfq_ioc_pool, gfp_mask | __GFP_ZERO,
+ cfqd->queue->node);
if (cic) {
- memset(cic, 0, sizeof(*cic));
cic->last_end_request = jiffies;
INIT_LIST_HEAD(&cic->queue_list);
cic->dtor = cfq_free_io_context;
@@ -1376,17 +1375,19 @@ retry:
* free memory.
*/
spin_unlock_irq(cfqd->queue->queue_lock);
- new_cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask|__GFP_NOFAIL, cfqd->queue->node);
+ new_cfqq = kmem_cache_alloc_node(cfq_pool,
+ gfp_mask | __GFP_NOFAIL | __GFP_ZERO,
+ cfqd->queue->node);
spin_lock_irq(cfqd->queue->queue_lock);
goto retry;
} else {
- cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask, cfqd->queue->node);
+ cfqq = kmem_cache_alloc_node(cfq_pool,
+ gfp_mask | __GFP_ZERO,
+ cfqd->queue->node);
if (!cfqq)
goto out;
}
- memset(cfqq, 0, sizeof(*cfqq));
-
RB_CLEAR_NODE(&cfqq->rb_node);
INIT_LIST_HEAD(&cfqq->fifo);
@@ -1412,24 +1413,44 @@ out:
return cfqq;
}
+static struct cfq_queue **
+cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
+{
+ switch(ioprio_class) {
+ case IOPRIO_CLASS_RT:
+ return &cfqd->async_cfqq[0][ioprio];
+ case IOPRIO_CLASS_BE:
+ return &cfqd->async_cfqq[1][ioprio];
+ case IOPRIO_CLASS_IDLE:
+ return &cfqd->async_idle_cfqq;
+ default:
+ BUG();
+ }
+}
+
static struct cfq_queue *
cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
gfp_t gfp_mask)
{
const int ioprio = task_ioprio(tsk);
+ const int ioprio_class = task_ioprio_class(tsk);
+ struct cfq_queue **async_cfqq = NULL;
struct cfq_queue *cfqq = NULL;
- if (!is_sync)
- cfqq = cfqd->async_cfqq[ioprio];
+ if (!is_sync) {
+ async_cfqq = cfq_async_queue_prio(cfqd, ioprio_class, ioprio);
+ cfqq = *async_cfqq;
+ }
+
if (!cfqq)
cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask);
/*
* pin the queue now that it's allocated, scheduler exit will prune it
*/
- if (!is_sync && !cfqd->async_cfqq[ioprio]) {
+ if (!is_sync && !(*async_cfqq)) {
atomic_inc(&cfqq->ref);
- cfqd->async_cfqq[ioprio] = cfqq;
+ *async_cfqq = cfqq;
}
atomic_inc(&cfqq->ref);
@@ -1595,11 +1616,6 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
else
sdist = cic->last_request_pos - rq->sector;
- if (!cic->seek_samples) {
- cfqd->new_seek_total = (7*cic->seek_total + (u64)256*sdist) / 8;
- cfqd->new_seek_mean = cfqd->new_seek_total / 256;
- }
-
/*
* Don't allow the seek distance to get too large from the
* odd fragment, pagein, etc
@@ -1735,7 +1751,6 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
cfq_update_idle_window(cfqd, cfqq, cic);
cic->last_request_pos = rq->sector + rq->nr_sectors;
- cfqq->last_request_pos = cic->last_request_pos;
if (cfqq == cfqd->active_queue) {
/*
@@ -2040,11 +2055,24 @@ static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
blk_sync_queue(cfqd->queue);
}
+static void cfq_put_async_queues(struct cfq_data *cfqd)
+{
+ int i;
+
+ for (i = 0; i < IOPRIO_BE_NR; i++) {
+ if (cfqd->async_cfqq[0][i])
+ cfq_put_queue(cfqd->async_cfqq[0][i]);
+ if (cfqd->async_cfqq[1][i])
+ cfq_put_queue(cfqd->async_cfqq[1][i]);
+ if (cfqd->async_idle_cfqq)
+ cfq_put_queue(cfqd->async_idle_cfqq);
+ }
+}
+
static void cfq_exit_queue(elevator_t *e)
{
struct cfq_data *cfqd = e->elevator_data;
request_queue_t *q = cfqd->queue;
- int i;
cfq_shutdown_timer_wq(cfqd);
@@ -2061,12 +2089,7 @@ static void cfq_exit_queue(elevator_t *e)
__cfq_exit_single_io_context(cfqd, cic);
}
- /*
- * Put the async queues
- */
- for (i = 0; i < IOPRIO_BE_NR; i++)
- if (cfqd->async_cfqq[i])
- cfq_put_queue(cfqd->async_cfqq[i]);
+ cfq_put_async_queues(cfqd);
spin_unlock_irq(q->queue_lock);
@@ -2079,12 +2102,10 @@ static void *cfq_init_queue(request_queue_t *q)
{
struct cfq_data *cfqd;
- cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
+ cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
if (!cfqd)
return NULL;
- memset(cfqd, 0, sizeof(*cfqd));
-
cfqd->service_tree = CFQ_RB_ROOT;
INIT_LIST_HEAD(&cfqd->cic_list);
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index 6d673e938d3e..87ca02ac84cb 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -360,10 +360,9 @@ static void *deadline_init_queue(request_queue_t *q)
{
struct deadline_data *dd;
- dd = kmalloc_node(sizeof(*dd), GFP_KERNEL, q->node);
+ dd = kmalloc_node(sizeof(*dd), GFP_KERNEL | __GFP_ZERO, q->node);
if (!dd)
return NULL;
- memset(dd, 0, sizeof(*dd));
INIT_LIST_HEAD(&dd->fifo_list[READ]);
INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
diff --git a/block/elevator.c b/block/elevator.c
index 4769a25d7037..d265963d1ed3 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -177,11 +177,10 @@ static elevator_t *elevator_alloc(request_queue_t *q, struct elevator_type *e)
elevator_t *eq;
int i;
- eq = kmalloc_node(sizeof(elevator_t), GFP_KERNEL, q->node);
+ eq = kmalloc_node(sizeof(elevator_t), GFP_KERNEL | __GFP_ZERO, q->node);
if (unlikely(!eq))
goto err;
- memset(eq, 0, sizeof(*eq));
eq->ops = &e->ops;
eq->elevator_type = e;
kobject_init(&eq->kobj);
diff --git a/block/genhd.c b/block/genhd.c
index 863a8c0623ed..3af1e7a378d4 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -108,28 +108,24 @@ out:
EXPORT_SYMBOL(register_blkdev);
-/* todo: make void - error printk here */
-int unregister_blkdev(unsigned int major, const char *name)
+void unregister_blkdev(unsigned int major, const char *name)
{
struct blk_major_name **n;
struct blk_major_name *p = NULL;
int index = major_to_index(major);
- int ret = 0;
mutex_lock(&block_subsys_lock);
for (n = &major_names[index]; *n; n = &(*n)->next)
if ((*n)->major == major)
break;
- if (!*n || strcmp((*n)->name, name))
- ret = -EINVAL;
- else {
+ if (!*n || strcmp((*n)->name, name)) {
+ WARN_ON(1);
+ } else {
p = *n;
*n = p->next;
}
mutex_unlock(&block_subsys_lock);
kfree(p);
-
- return ret;
}
EXPORT_SYMBOL(unregister_blkdev);
@@ -726,21 +722,21 @@ struct gendisk *alloc_disk_node(int minors, int node_id)
{
struct gendisk *disk;
- disk = kmalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id);
+ disk = kmalloc_node(sizeof(struct gendisk),
+ GFP_KERNEL | __GFP_ZERO, node_id);
if (disk) {
- memset(disk, 0, sizeof(struct gendisk));
if (!init_disk_stats(disk)) {
kfree(disk);
return NULL;
}
if (minors > 1) {
int size = (minors - 1) * sizeof(struct hd_struct *);
- disk->part = kmalloc_node(size, GFP_KERNEL, node_id);
+ disk->part = kmalloc_node(size,
+ GFP_KERNEL | __GFP_ZERO, node_id);
if (!disk->part) {
kfree(disk);
return NULL;
}
- memset(disk->part, 0, size);
}
disk->minors = minors;
kobj_set_kset_s(disk,block_subsys);
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index ef42bb2b12b6..66056ca5e631 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -256,6 +256,7 @@ static void rq_init(request_queue_t *q, struct request *rq)
rq->end_io = NULL;
rq->end_io_data = NULL;
rq->completion_data = NULL;
+ rq->next_rq = NULL;
}
/**
@@ -1828,11 +1829,11 @@ request_queue_t *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
{
request_queue_t *q;
- q = kmem_cache_alloc_node(requestq_cachep, gfp_mask, node_id);
+ q = kmem_cache_alloc_node(requestq_cachep,
+ gfp_mask | __GFP_ZERO, node_id);
if (!q)
return NULL;
- memset(q, 0, sizeof(*q));
init_timer(&q->unplug_timer);
snprintf(q->kobj.name, KOBJ_NAME_LEN, "%s", "queue");
@@ -3697,13 +3698,13 @@ int __init blk_dev_init(void)
panic("Failed to create kblockd\n");
request_cachep = kmem_cache_create("blkdev_requests",
- sizeof(struct request), 0, SLAB_PANIC, NULL, NULL);
+ sizeof(struct request), 0, SLAB_PANIC, NULL);
requestq_cachep = kmem_cache_create("blkdev_queue",
- sizeof(request_queue_t), 0, SLAB_PANIC, NULL, NULL);
+ sizeof(request_queue_t), 0, SLAB_PANIC, NULL);
iocontext_cachep = kmem_cache_create("blkdev_ioc",
- sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
+ sizeof(struct io_context), 0, SLAB_PANIC, NULL);
for_each_possible_cpu(i)
INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index e83f1dbf7c29..d359a715bbc8 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -41,8 +41,6 @@ const unsigned char scsi_command_size[8] =
EXPORT_SYMBOL(scsi_command_size);
-#define BLK_DEFAULT_TIMEOUT (60 * HZ)
-
#include <scsi/sg.h>
static int sg_get_version(int __user *p)
@@ -114,7 +112,7 @@ static int sg_emulated_host(request_queue_t *q, int __user *p)
#define safe_for_read(cmd) [cmd] = CMD_READ_SAFE
#define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE
-static int verify_command(struct file *file, unsigned char *cmd)
+int blk_verify_command(unsigned char *cmd, int has_write_perm)
{
static unsigned char cmd_type[256] = {
@@ -193,18 +191,11 @@ static int verify_command(struct file *file, unsigned char *cmd)
safe_for_write(GPCMD_SET_STREAMING),
};
unsigned char type = cmd_type[cmd[0]];
- int has_write_perm = 0;
/* Anybody who can open the device can do a read-safe command */
if (type & CMD_READ_SAFE)
return 0;
- /*
- * file can be NULL from ioctl_by_bdev()...
- */
- if (file)
- has_write_perm = file->f_mode & FMODE_WRITE;
-
/* Write-safe commands just require a writable open.. */
if ((type & CMD_WRITE_SAFE) && has_write_perm)
return 0;
@@ -221,25 +212,93 @@ static int verify_command(struct file *file, unsigned char *cmd)
/* Otherwise fail it with an "Operation not permitted" */
return -EPERM;
}
+EXPORT_SYMBOL_GPL(blk_verify_command);
+
+static int blk_fill_sghdr_rq(request_queue_t *q, struct request *rq,
+ struct sg_io_hdr *hdr, int has_write_perm)
+{
+ memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
+
+ if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
+ return -EFAULT;
+ if (blk_verify_command(rq->cmd, has_write_perm))
+ return -EPERM;
+
+ /*
+ * fill in request structure
+ */
+ rq->cmd_len = hdr->cmd_len;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+
+ rq->timeout = (hdr->timeout * HZ) / 1000;
+ if (!rq->timeout)
+ rq->timeout = q->sg_timeout;
+ if (!rq->timeout)
+ rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
+
+ return 0;
+}
+
+/*
+ * unmap a request that was previously mapped to this sg_io_hdr. handles
+ * both sg and non-sg sg_io_hdr.
+ */
+static int blk_unmap_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr)
+{
+ blk_rq_unmap_user(rq->bio);
+ blk_put_request(rq);
+ return 0;
+}
+
+static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr,
+ struct bio *bio)
+{
+ int r, ret = 0;
+
+ /*
+ * fill in all the output members
+ */
+ hdr->status = rq->errors & 0xff;
+ hdr->masked_status = status_byte(rq->errors);
+ hdr->msg_status = msg_byte(rq->errors);
+ hdr->host_status = host_byte(rq->errors);
+ hdr->driver_status = driver_byte(rq->errors);
+ hdr->info = 0;
+ if (hdr->masked_status || hdr->host_status || hdr->driver_status)
+ hdr->info |= SG_INFO_CHECK;
+ hdr->resid = rq->data_len;
+ hdr->sb_len_wr = 0;
+
+ if (rq->sense_len && hdr->sbp) {
+ int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
+
+ if (!copy_to_user(hdr->sbp, rq->sense, len))
+ hdr->sb_len_wr = len;
+ else
+ ret = -EFAULT;
+ }
+
+ rq->bio = bio;
+ r = blk_unmap_sghdr_rq(rq, hdr);
+ if (ret)
+ r = ret;
+
+ return r;
+}
static int sg_io(struct file *file, request_queue_t *q,
struct gendisk *bd_disk, struct sg_io_hdr *hdr)
{
- unsigned long start_time, timeout;
- int writing = 0, ret = 0;
+ unsigned long start_time;
+ int writing = 0, ret = 0, has_write_perm = 0;
struct request *rq;
char sense[SCSI_SENSE_BUFFERSIZE];
- unsigned char cmd[BLK_MAX_CDB];
struct bio *bio;
if (hdr->interface_id != 'S')
return -EINVAL;
if (hdr->cmd_len > BLK_MAX_CDB)
return -EINVAL;
- if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len))
- return -EFAULT;
- if (verify_command(file, cmd))
- return -EPERM;
if (hdr->dxfer_len > (q->max_hw_sectors << 9))
return -EIO;
@@ -260,25 +319,13 @@ static int sg_io(struct file *file, request_queue_t *q,
if (!rq)
return -ENOMEM;
- /*
- * fill in request structure
- */
- rq->cmd_len = hdr->cmd_len;
- memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
- memcpy(rq->cmd, cmd, hdr->cmd_len);
-
- memset(sense, 0, sizeof(sense));
- rq->sense = sense;
- rq->sense_len = 0;
-
- rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ if (file)
+ has_write_perm = file->f_mode & FMODE_WRITE;
- timeout = msecs_to_jiffies(hdr->timeout);
- rq->timeout = (timeout < INT_MAX) ? timeout : INT_MAX;
- if (!rq->timeout)
- rq->timeout = q->sg_timeout;
- if (!rq->timeout)
- rq->timeout = BLK_DEFAULT_TIMEOUT;
+ if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) {
+ blk_put_request(rq);
+ return -EFAULT;
+ }
if (hdr->iovec_count) {
const int size = sizeof(struct sg_iovec) * hdr->iovec_count;
@@ -306,6 +353,9 @@ static int sg_io(struct file *file, request_queue_t *q,
goto out;
bio = rq->bio;
+ memset(sense, 0, sizeof(sense));
+ rq->sense = sense;
+ rq->sense_len = 0;
rq->retries = 0;
start_time = jiffies;
@@ -316,31 +366,9 @@ static int sg_io(struct file *file, request_queue_t *q,
*/
blk_execute_rq(q, bd_disk, rq, 0);
- /* write to all output members */
- hdr->status = 0xff & rq->errors;
- hdr->masked_status = status_byte(rq->errors);
- hdr->msg_status = msg_byte(rq->errors);
- hdr->host_status = host_byte(rq->errors);
- hdr->driver_status = driver_byte(rq->errors);
- hdr->info = 0;
- if (hdr->masked_status || hdr->host_status || hdr->driver_status)
- hdr->info |= SG_INFO_CHECK;
- hdr->resid = rq->data_len;
hdr->duration = ((jiffies - start_time) * 1000) / HZ;
- hdr->sb_len_wr = 0;
-
- if (rq->sense_len && hdr->sbp) {
- int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len);
-
- if (!copy_to_user(hdr->sbp, rq->sense, len))
- hdr->sb_len_wr = len;
- }
- if (blk_rq_unmap_user(bio))
- ret = -EFAULT;
-
- /* may not have succeeded, but output values written to control
- * structure (struct sg_io_hdr). */
+ return blk_complete_sghdr_rq(rq, hdr, bio);
out:
blk_put_request(rq);
return ret;
@@ -405,11 +433,10 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
bytes = max(in_len, out_len);
if (bytes) {
- buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN);
+ buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN);
if (!buffer)
return -ENOMEM;
- memset(buffer, 0, bytes);
}
rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
@@ -427,7 +454,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len))
goto error;
- err = verify_command(file, rq->cmd);
+ err = blk_verify_command(rq->cmd, file->f_mode & FMODE_WRITE);
if (err)
goto error;
@@ -454,7 +481,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
rq->retries = 1;
break;
default:
- rq->timeout = BLK_DEFAULT_TIMEOUT;
+ rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
break;
}
@@ -501,7 +528,7 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->data = NULL;
rq->data_len = 0;
- rq->timeout = BLK_DEFAULT_TIMEOUT;
+ rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = cmd;
rq->cmd[4] = data;
@@ -517,16 +544,12 @@ static inline int blk_send_start_stop(request_queue_t *q, struct gendisk *bd_dis
return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
}
-int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, void __user *arg)
+int scsi_cmd_ioctl(struct file *file, struct request_queue *q,
+ struct gendisk *bd_disk, unsigned int cmd, void __user *arg)
{
- request_queue_t *q;
int err;
- q = bd_disk->queue;
- if (!q)
- return -ENXIO;
-
- if (blk_get_queue(q))
+ if (!q || blk_get_queue(q))
return -ENXIO;
switch (cmd) {
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 4ca0ab3448d9..3d1a1e27944f 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1,10 +1,18 @@
#
-# Cryptographic API Configuration
+# Generic algorithms support
#
+config XOR_BLOCKS
+ tristate
-menu "Cryptographic options"
+#
+# async_tx api: hardware offloaded memory transfer/transform support
+#
+source "crypto/async_tx/Kconfig"
-config CRYPTO
+#
+# Cryptographic API Configuration
+#
+menuconfig CRYPTO
bool "Cryptographic API"
help
This option provides the core Cryptographic API.
@@ -463,5 +471,3 @@ config CRYPTO_TEST
source "drivers/crypto/Kconfig"
endif # if CRYPTO
-
-endmenu
diff --git a/crypto/Makefile b/crypto/Makefile
index cce46a1c9dc7..0cf17f1ea151 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -50,3 +50,9 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
+
+#
+# generic algorithms and the async_tx api
+#
+obj-$(CONFIG_XOR_BLOCKS) += xor.o
+obj-$(CONFIG_ASYNC_CORE) += async_tx/
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index 9348ddd84a56..1c166b47b4cc 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -19,16 +19,41 @@
#include <linux/module.h>
#include <linux/seq_file.h>
+static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int keylen)
+{
+ struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm);
+ unsigned long alignmask = crypto_ablkcipher_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = cipher->setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+}
+
static int setkey(struct crypto_ablkcipher *tfm, const u8 *key,
unsigned int keylen)
{
struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm);
+ unsigned long alignmask = crypto_ablkcipher_alignmask(tfm);
if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
return -EINVAL;
}
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
return cipher->setkey(tfm, key, keylen);
}
@@ -66,8 +91,10 @@ static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg)
seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize);
seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize);
seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize);
- seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen);
- seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen);
+ if (ablkcipher->queue) {
+ seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen);
+ seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen);
+ }
}
const struct crypto_type crypto_ablkcipher_type = {
diff --git a/crypto/algapi.c b/crypto/algapi.c
index f137a432061f..38aa9e994703 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -34,7 +34,7 @@ void crypto_larval_error(const char *name, u32 type, u32 mask)
if (alg) {
if (crypto_is_larval(alg)) {
struct crypto_larval *larval = (void *)alg;
- complete(&larval->completion);
+ complete_all(&larval->completion);
}
crypto_mod_put(alg);
}
@@ -164,7 +164,7 @@ static int __crypto_register_alg(struct crypto_alg *alg,
continue;
larval->adult = alg;
- complete(&larval->completion);
+ complete_all(&larval->completion);
continue;
}
diff --git a/crypto/api.c b/crypto/api.c
index 33734fd9198f..4ccc5af6c265 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -144,7 +144,7 @@ static void crypto_larval_kill(struct crypto_alg *alg)
down_write(&crypto_alg_sem);
list_del(&alg->cra_list);
up_write(&crypto_alg_sem);
- complete(&larval->completion);
+ complete_all(&larval->completion);
crypto_alg_put(alg);
}
diff --git a/crypto/async_tx/Kconfig b/crypto/async_tx/Kconfig
new file mode 100644
index 000000000000..d8fb39145986
--- /dev/null
+++ b/crypto/async_tx/Kconfig
@@ -0,0 +1,16 @@
+config ASYNC_CORE
+ tristate
+
+config ASYNC_MEMCPY
+ tristate
+ select ASYNC_CORE
+
+config ASYNC_XOR
+ tristate
+ select ASYNC_CORE
+ select XOR_BLOCKS
+
+config ASYNC_MEMSET
+ tristate
+ select ASYNC_CORE
+
diff --git a/crypto/async_tx/Makefile b/crypto/async_tx/Makefile
new file mode 100644
index 000000000000..27baa7d52fbc
--- /dev/null
+++ b/crypto/async_tx/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_ASYNC_CORE) += async_tx.o
+obj-$(CONFIG_ASYNC_MEMCPY) += async_memcpy.o
+obj-$(CONFIG_ASYNC_MEMSET) += async_memset.o
+obj-$(CONFIG_ASYNC_XOR) += async_xor.o
diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c
new file mode 100644
index 000000000000..047e533fcc5b
--- /dev/null
+++ b/crypto/async_tx/async_memcpy.c
@@ -0,0 +1,120 @@
+/*
+ * copy offload engine support
+ *
+ * Copyright © 2006, Intel Corporation.
+ *
+ * Dan Williams <dan.j.williams@intel.com>
+ *
+ * with architecture considerations by:
+ * Neil Brown <neilb@suse.de>
+ * Jeff Garzik <jeff@garzik.org>
+ *
+ * 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/highmem.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/async_tx.h>
+
+/**
+ * async_memcpy - attempt to copy memory with a dma engine.
+ * @dest: destination page
+ * @src: src page
+ * @offset: offset in pages to start transaction
+ * @len: length in bytes
+ * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK,
+ * @depend_tx: memcpy depends on the result of this transaction
+ * @cb_fn: function to call when the memcpy completes
+ * @cb_param: parameter to pass to the callback routine
+ */
+struct dma_async_tx_descriptor *
+async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
+ unsigned int src_offset, size_t len, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMCPY);
+ struct dma_device *device = chan ? chan->device : NULL;
+ int int_en = cb_fn ? 1 : 0;
+ struct dma_async_tx_descriptor *tx = device ?
+ device->device_prep_dma_memcpy(chan, len,
+ int_en) : NULL;
+
+ if (tx) { /* run the memcpy asynchronously */
+ dma_addr_t addr;
+ enum dma_data_direction dir;
+
+ pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
+
+ dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
+ DMA_NONE : DMA_FROM_DEVICE;
+
+ addr = dma_map_page(device->dev, dest, dest_offset, len, dir);
+ tx->tx_set_dest(addr, tx, 0);
+
+ dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
+ DMA_NONE : DMA_TO_DEVICE;
+
+ addr = dma_map_page(device->dev, src, src_offset, len, dir);
+ tx->tx_set_src(addr, tx, 0);
+
+ async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+ } else { /* run the memcpy synchronously */
+ void *dest_buf, *src_buf;
+ pr_debug("%s: (sync) len: %zu\n", __FUNCTION__, len);
+
+ /* wait for any prerequisite operations */
+ if (depend_tx) {
+ /* if ack is already set then we cannot be sure
+ * we are referring to the correct operation
+ */
+ BUG_ON(depend_tx->ack);
+ if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR)
+ panic("%s: DMA_ERROR waiting for depend_tx\n",
+ __FUNCTION__);
+ }
+
+ dest_buf = kmap_atomic(dest, KM_USER0) + dest_offset;
+ src_buf = kmap_atomic(src, KM_USER1) + src_offset;
+
+ memcpy(dest_buf, src_buf, len);
+
+ kunmap_atomic(dest_buf, KM_USER0);
+ kunmap_atomic(src_buf, KM_USER1);
+
+ async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
+ }
+
+ return tx;
+}
+EXPORT_SYMBOL_GPL(async_memcpy);
+
+static int __init async_memcpy_init(void)
+{
+ return 0;
+}
+
+static void __exit async_memcpy_exit(void)
+{
+ do { } while (0);
+}
+
+module_init(async_memcpy_init);
+module_exit(async_memcpy_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("asynchronous memcpy api");
+MODULE_LICENSE("GPL");
diff --git a/crypto/async_tx/async_memset.c b/crypto/async_tx/async_memset.c
new file mode 100644
index 000000000000..66ef6351202e
--- /dev/null
+++ b/crypto/async_tx/async_memset.c
@@ -0,0 +1,109 @@
+/*
+ * memory fill offload engine support
+ *
+ * Copyright © 2006, Intel Corporation.
+ *
+ * Dan Williams <dan.j.williams@intel.com>
+ *
+ * with architecture considerations by:
+ * Neil Brown <neilb@suse.de>
+ * Jeff Garzik <jeff@garzik.org>
+ *
+ * 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/async_tx.h>
+
+/**
+ * async_memset - attempt to fill memory with a dma engine.
+ * @dest: destination page
+ * @val: fill value
+ * @offset: offset in pages to start transaction
+ * @len: length in bytes
+ * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @depend_tx: memset depends on the result of this transaction
+ * @cb_fn: function to call when the memcpy completes
+ * @cb_param: parameter to pass to the callback routine
+ */
+struct dma_async_tx_descriptor *
+async_memset(struct page *dest, int val, unsigned int offset,
+ size_t len, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_MEMSET);
+ struct dma_device *device = chan ? chan->device : NULL;
+ int int_en = cb_fn ? 1 : 0;
+ struct dma_async_tx_descriptor *tx = device ?
+ device->device_prep_dma_memset(chan, val, len,
+ int_en) : NULL;
+
+ if (tx) { /* run the memset asynchronously */
+ dma_addr_t dma_addr;
+ enum dma_data_direction dir;
+
+ pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
+ dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
+ DMA_NONE : DMA_FROM_DEVICE;
+
+ dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
+ tx->tx_set_dest(dma_addr, tx, 0);
+
+ async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+ } else { /* run the memset synchronously */
+ void *dest_buf;
+ pr_debug("%s: (sync) len: %zu\n", __FUNCTION__, len);
+
+ dest_buf = (void *) (((char *) page_address(dest)) + offset);
+
+ /* wait for any prerequisite operations */
+ if (depend_tx) {
+ /* if ack is already set then we cannot be sure
+ * we are referring to the correct operation
+ */
+ BUG_ON(depend_tx->ack);
+ if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR)
+ panic("%s: DMA_ERROR waiting for depend_tx\n",
+ __FUNCTION__);
+ }
+
+ memset(dest_buf, val, len);
+
+ async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
+ }
+
+ return tx;
+}
+EXPORT_SYMBOL_GPL(async_memset);
+
+static int __init async_memset_init(void)
+{
+ return 0;
+}
+
+static void __exit async_memset_exit(void)
+{
+ do { } while (0);
+}
+
+module_init(async_memset_init);
+module_exit(async_memset_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("asynchronous memset api");
+MODULE_LICENSE("GPL");
diff --git a/crypto/async_tx/async_tx.c b/crypto/async_tx/async_tx.c
new file mode 100644
index 000000000000..035007145e78
--- /dev/null
+++ b/crypto/async_tx/async_tx.c
@@ -0,0 +1,497 @@
+/*
+ * core routines for the asynchronous memory transfer/transform api
+ *
+ * Copyright © 2006, Intel Corporation.
+ *
+ * Dan Williams <dan.j.williams@intel.com>
+ *
+ * with architecture considerations by:
+ * Neil Brown <neilb@suse.de>
+ * Jeff Garzik <jeff@garzik.org>
+ *
+ * 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/async_tx.h>
+
+#ifdef CONFIG_DMA_ENGINE
+static enum dma_state_client
+dma_channel_add_remove(struct dma_client *client,
+ struct dma_chan *chan, enum dma_state state);
+
+static struct dma_client async_tx_dma = {
+ .event_callback = dma_channel_add_remove,
+ /* .cap_mask == 0 defaults to all channels */
+};
+
+/**
+ * dma_cap_mask_all - enable iteration over all operation types
+ */
+static dma_cap_mask_t dma_cap_mask_all;
+
+/**
+ * chan_ref_percpu - tracks channel allocations per core/opertion
+ */
+struct chan_ref_percpu {
+ struct dma_chan_ref *ref;
+};
+
+static int channel_table_initialized;
+static struct chan_ref_percpu *channel_table[DMA_TX_TYPE_END];
+
+/**
+ * async_tx_lock - protect modification of async_tx_master_list and serialize
+ * rebalance operations
+ */
+static spinlock_t async_tx_lock;
+
+static struct list_head
+async_tx_master_list = LIST_HEAD_INIT(async_tx_master_list);
+
+/* async_tx_issue_pending_all - start all transactions on all channels */
+void async_tx_issue_pending_all(void)
+{
+ struct dma_chan_ref *ref;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ref, &async_tx_master_list, node)
+ ref->chan->device->device_issue_pending(ref->chan);
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(async_tx_issue_pending_all);
+
+/* dma_wait_for_async_tx - spin wait for a transcation to complete
+ * @tx: transaction to wait on
+ */
+enum dma_status
+dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
+{
+ enum dma_status status;
+ struct dma_async_tx_descriptor *iter;
+
+ if (!tx)
+ return DMA_SUCCESS;
+
+ /* poll through the dependency chain, return when tx is complete */
+ do {
+ iter = tx;
+ while (iter->cookie == -EBUSY)
+ iter = iter->parent;
+
+ status = dma_sync_wait(iter->chan, iter->cookie);
+ } while (status == DMA_IN_PROGRESS || (iter != tx));
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(dma_wait_for_async_tx);
+
+/* async_tx_run_dependencies - helper routine for dma drivers to process
+ * (start) dependent operations on their target channel
+ * @tx: transaction with dependencies
+ */
+void
+async_tx_run_dependencies(struct dma_async_tx_descriptor *tx)
+{
+ struct dma_async_tx_descriptor *dep_tx, *_dep_tx;
+ struct dma_device *dev;
+ struct dma_chan *chan;
+
+ list_for_each_entry_safe(dep_tx, _dep_tx, &tx->depend_list,
+ depend_node) {
+ chan = dep_tx->chan;
+ dev = chan->device;
+ /* we can't depend on ourselves */
+ BUG_ON(chan == tx->chan);
+ list_del(&dep_tx->depend_node);
+ tx->tx_submit(dep_tx);
+
+ /* we need to poke the engine as client code does not
+ * know about dependency submission events
+ */
+ dev->device_issue_pending(chan);
+ }
+}
+EXPORT_SYMBOL_GPL(async_tx_run_dependencies);
+
+static void
+free_dma_chan_ref(struct rcu_head *rcu)
+{
+ struct dma_chan_ref *ref;
+ ref = container_of(rcu, struct dma_chan_ref, rcu);
+ kfree(ref);
+}
+
+static void
+init_dma_chan_ref(struct dma_chan_ref *ref, struct dma_chan *chan)
+{
+ INIT_LIST_HEAD(&ref->node);
+ INIT_RCU_HEAD(&ref->rcu);
+ ref->chan = chan;
+ atomic_set(&ref->count, 0);
+}
+
+/**
+ * get_chan_ref_by_cap - returns the nth channel of the given capability
+ * defaults to returning the channel with the desired capability and the
+ * lowest reference count if the index can not be satisfied
+ * @cap: capability to match
+ * @index: nth channel desired, passing -1 has the effect of forcing the
+ * default return value
+ */
+static struct dma_chan_ref *
+get_chan_ref_by_cap(enum dma_transaction_type cap, int index)
+{
+ struct dma_chan_ref *ret_ref = NULL, *min_ref = NULL, *ref;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ref, &async_tx_master_list, node)
+ if (dma_has_cap(cap, ref->chan->device->cap_mask)) {
+ if (!min_ref)
+ min_ref = ref;
+ else if (atomic_read(&ref->count) <
+ atomic_read(&min_ref->count))
+ min_ref = ref;
+
+ if (index-- == 0) {
+ ret_ref = ref;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ if (!ret_ref)
+ ret_ref = min_ref;
+
+ if (ret_ref)
+ atomic_inc(&ret_ref->count);
+
+ return ret_ref;
+}
+
+/**
+ * async_tx_rebalance - redistribute the available channels, optimize
+ * for cpu isolation in the SMP case, and opertaion isolation in the
+ * uniprocessor case
+ */
+static void async_tx_rebalance(void)
+{
+ int cpu, cap, cpu_idx = 0;
+ unsigned long flags;
+
+ if (!channel_table_initialized)
+ return;
+
+ spin_lock_irqsave(&async_tx_lock, flags);
+
+ /* undo the last distribution */
+ for_each_dma_cap_mask(cap, dma_cap_mask_all)
+ for_each_possible_cpu(cpu) {
+ struct dma_chan_ref *ref =
+ per_cpu_ptr(channel_table[cap], cpu)->ref;
+ if (ref) {
+ atomic_set(&ref->count, 0);
+ per_cpu_ptr(channel_table[cap], cpu)->ref =
+ NULL;
+ }
+ }
+
+ for_each_dma_cap_mask(cap, dma_cap_mask_all)
+ for_each_online_cpu(cpu) {
+ struct dma_chan_ref *new;
+ if (NR_CPUS > 1)
+ new = get_chan_ref_by_cap(cap, cpu_idx++);
+ else
+ new = get_chan_ref_by_cap(cap, -1);
+
+ per_cpu_ptr(channel_table[cap], cpu)->ref = new;
+ }
+
+ spin_unlock_irqrestore(&async_tx_lock, flags);
+}
+
+static enum dma_state_client
+dma_channel_add_remove(struct dma_client *client,
+ struct dma_chan *chan, enum dma_state state)
+{
+ unsigned long found, flags;
+ struct dma_chan_ref *master_ref, *ref;
+ enum dma_state_client ack = DMA_DUP; /* default: take no action */
+
+ switch (state) {
+ case DMA_RESOURCE_AVAILABLE:
+ found = 0;
+ rcu_read_lock();
+ list_for_each_entry_rcu(ref, &async_tx_master_list, node)
+ if (ref->chan == chan) {
+ found = 1;
+ break;
+ }
+ rcu_read_unlock();
+
+ pr_debug("async_tx: dma resource available [%s]\n",
+ found ? "old" : "new");
+
+ if (!found)
+ ack = DMA_ACK;
+ else
+ break;
+
+ /* add the channel to the generic management list */
+ master_ref = kmalloc(sizeof(*master_ref), GFP_KERNEL);
+ if (master_ref) {
+ /* keep a reference until async_tx is unloaded */
+ dma_chan_get(chan);
+ init_dma_chan_ref(master_ref, chan);
+ spin_lock_irqsave(&async_tx_lock, flags);
+ list_add_tail_rcu(&master_ref->node,
+ &async_tx_master_list);
+ spin_unlock_irqrestore(&async_tx_lock,
+ flags);
+ } else {
+ printk(KERN_WARNING "async_tx: unable to create"
+ " new master entry in response to"
+ " a DMA_RESOURCE_ADDED event"
+ " (-ENOMEM)\n");
+ return 0;
+ }
+
+ async_tx_rebalance();
+ break;
+ case DMA_RESOURCE_REMOVED:
+ found = 0;
+ spin_lock_irqsave(&async_tx_lock, flags);
+ list_for_each_entry_rcu(ref, &async_tx_master_list, node)
+ if (ref->chan == chan) {
+ /* permit backing devices to go away */
+ dma_chan_put(ref->chan);
+ list_del_rcu(&ref->node);
+ call_rcu(&ref->rcu, free_dma_chan_ref);
+ found = 1;
+ break;
+ }
+ spin_unlock_irqrestore(&async_tx_lock, flags);
+
+ pr_debug("async_tx: dma resource removed [%s]\n",
+ found ? "ours" : "not ours");
+
+ if (found)
+ ack = DMA_ACK;
+ else
+ break;
+
+ async_tx_rebalance();
+ break;
+ case DMA_RESOURCE_SUSPEND:
+ case DMA_RESOURCE_RESUME:
+ printk(KERN_WARNING "async_tx: does not support dma channel"
+ " suspend/resume\n");
+ break;
+ default:
+ BUG();
+ }
+
+ return ack;
+}
+
+static int __init
+async_tx_init(void)
+{
+ enum dma_transaction_type cap;
+
+ spin_lock_init(&async_tx_lock);
+ bitmap_fill(dma_cap_mask_all.bits, DMA_TX_TYPE_END);
+
+ /* an interrupt will never be an explicit operation type.
+ * clearing this bit prevents allocation to a slot in 'channel_table'
+ */
+ clear_bit(DMA_INTERRUPT, dma_cap_mask_all.bits);
+
+ for_each_dma_cap_mask(cap, dma_cap_mask_all) {
+ channel_table[cap] = alloc_percpu(struct chan_ref_percpu);
+ if (!channel_table[cap])
+ goto err;
+ }
+
+ channel_table_initialized = 1;
+ dma_async_client_register(&async_tx_dma);
+ dma_async_client_chan_request(&async_tx_dma);
+
+ printk(KERN_INFO "async_tx: api initialized (async)\n");
+
+ return 0;
+err:
+ printk(KERN_ERR "async_tx: initialization failure\n");
+
+ while (--cap >= 0)
+ free_percpu(channel_table[cap]);
+
+ return 1;
+}
+
+static void __exit async_tx_exit(void)
+{
+ enum dma_transaction_type cap;
+
+ channel_table_initialized = 0;
+
+ for_each_dma_cap_mask(cap, dma_cap_mask_all)
+ if (channel_table[cap])
+ free_percpu(channel_table[cap]);
+
+ dma_async_client_unregister(&async_tx_dma);
+}
+
+/**
+ * async_tx_find_channel - find a channel to carry out the operation or let
+ * the transaction execute synchronously
+ * @depend_tx: transaction dependency
+ * @tx_type: transaction type
+ */
+struct dma_chan *
+async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+ enum dma_transaction_type tx_type)
+{
+ /* see if we can keep the chain on one channel */
+ if (depend_tx &&
+ dma_has_cap(tx_type, depend_tx->chan->device->cap_mask))
+ return depend_tx->chan;
+ else if (likely(channel_table_initialized)) {
+ struct dma_chan_ref *ref;
+ int cpu = get_cpu();
+ ref = per_cpu_ptr(channel_table[tx_type], cpu)->ref;
+ put_cpu();
+ return ref ? ref->chan : NULL;
+ } else
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(async_tx_find_channel);
+#else
+static int __init async_tx_init(void)
+{
+ printk(KERN_INFO "async_tx: api initialized (sync-only)\n");
+ return 0;
+}
+
+static void __exit async_tx_exit(void)
+{
+ do { } while (0);
+}
+#endif
+
+void
+async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx,
+ enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ tx->callback = cb_fn;
+ tx->callback_param = cb_param;
+
+ /* set this new tx to run after depend_tx if:
+ * 1/ a dependency exists (depend_tx is !NULL)
+ * 2/ the tx can not be submitted to the current channel
+ */
+ if (depend_tx && depend_tx->chan != chan) {
+ /* if ack is already set then we cannot be sure
+ * we are referring to the correct operation
+ */
+ BUG_ON(depend_tx->ack);
+
+ tx->parent = depend_tx;
+ spin_lock_bh(&depend_tx->lock);
+ list_add_tail(&tx->depend_node, &depend_tx->depend_list);
+ if (depend_tx->cookie == 0) {
+ struct dma_chan *dep_chan = depend_tx->chan;
+ struct dma_device *dep_dev = dep_chan->device;
+ dep_dev->device_dependency_added(dep_chan);
+ }
+ spin_unlock_bh(&depend_tx->lock);
+
+ /* schedule an interrupt to trigger the channel switch */
+ async_trigger_callback(ASYNC_TX_ACK, depend_tx, NULL, NULL);
+ } else {
+ tx->parent = NULL;
+ tx->tx_submit(tx);
+ }
+
+ if (flags & ASYNC_TX_ACK)
+ async_tx_ack(tx);
+
+ if (depend_tx && (flags & ASYNC_TX_DEP_ACK))
+ async_tx_ack(depend_tx);
+}
+EXPORT_SYMBOL_GPL(async_tx_submit);
+
+/**
+ * async_trigger_callback - schedules the callback function to be run after
+ * any dependent operations have been completed.
+ * @flags: ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @depend_tx: 'callback' requires the completion of this transaction
+ * @cb_fn: function to call after depend_tx completes
+ * @cb_param: parameter to pass to the callback routine
+ */
+struct dma_async_tx_descriptor *
+async_trigger_callback(enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ struct dma_chan *chan;
+ struct dma_device *device;
+ struct dma_async_tx_descriptor *tx;
+
+ if (depend_tx) {
+ chan = depend_tx->chan;
+ device = chan->device;
+
+ /* see if we can schedule an interrupt
+ * otherwise poll for completion
+ */
+ if (device && !dma_has_cap(DMA_INTERRUPT, device->cap_mask))
+ device = NULL;
+
+ tx = device ? device->device_prep_dma_interrupt(chan) : NULL;
+ } else
+ tx = NULL;
+
+ if (tx) {
+ pr_debug("%s: (async)\n", __FUNCTION__);
+
+ async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+ } else {
+ pr_debug("%s: (sync)\n", __FUNCTION__);
+
+ /* wait for any prerequisite operations */
+ if (depend_tx) {
+ /* if ack is already set then we cannot be sure
+ * we are referring to the correct operation
+ */
+ BUG_ON(depend_tx->ack);
+ if (dma_wait_for_async_tx(depend_tx) == DMA_ERROR)
+ panic("%s: DMA_ERROR waiting for depend_tx\n",
+ __FUNCTION__);
+ }
+
+ async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
+ }
+
+ return tx;
+}
+EXPORT_SYMBOL_GPL(async_trigger_callback);
+
+module_init(async_tx_init);
+module_exit(async_tx_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Asynchronous Bulk Memory Transactions API");
+MODULE_LICENSE("GPL");
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c
new file mode 100644
index 000000000000..2575f674dcd5
--- /dev/null
+++ b/crypto/async_tx/async_xor.c
@@ -0,0 +1,327 @@
+/*
+ * xor offload engine api
+ *
+ * Copyright © 2006, Intel Corporation.
+ *
+ * Dan Williams <dan.j.williams@intel.com>
+ *
+ * with architecture considerations by:
+ * Neil Brown <neilb@suse.de>
+ * Jeff Garzik <jeff@garzik.org>
+ *
+ * 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/raid/xor.h>
+#include <linux/async_tx.h>
+
+static void
+do_async_xor(struct dma_async_tx_descriptor *tx, struct dma_device *device,
+ struct dma_chan *chan, struct page *dest, struct page **src_list,
+ unsigned int offset, unsigned int src_cnt, size_t len,
+ enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ dma_addr_t dma_addr;
+ enum dma_data_direction dir;
+ int i;
+
+ pr_debug("%s: len: %zu\n", __FUNCTION__, len);
+
+ dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
+ DMA_NONE : DMA_FROM_DEVICE;
+
+ dma_addr = dma_map_page(device->dev, dest, offset, len, dir);
+ tx->tx_set_dest(dma_addr, tx, 0);
+
+ dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
+ DMA_NONE : DMA_TO_DEVICE;
+
+ for (i = 0; i < src_cnt; i++) {
+ dma_addr = dma_map_page(device->dev, src_list[i],
+ offset, len, dir);
+ tx->tx_set_src(dma_addr, tx, i);
+ }
+
+ async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+}
+
+static void
+do_sync_xor(struct page *dest, struct page **src_list, unsigned int offset,
+ unsigned int src_cnt, size_t len, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ void *_dest;
+ int i;
+
+ pr_debug("%s: len: %zu\n", __FUNCTION__, len);
+
+ /* reuse the 'src_list' array to convert to buffer pointers */
+ for (i = 0; i < src_cnt; i++)
+ src_list[i] = (struct page *)
+ (page_address(src_list[i]) + offset);
+
+ /* set destination address */
+ _dest = page_address(dest) + offset;
+
+ if (flags & ASYNC_TX_XOR_ZERO_DST)
+ memset(_dest, 0, len);
+
+ xor_blocks(src_cnt, len, _dest,
+ (void **) src_list);
+
+ async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
+}
+
+/**
+ * async_xor - attempt to xor a set of blocks with a dma engine.
+ * xor_blocks always uses the dest as a source so the ASYNC_TX_XOR_ZERO_DST
+ * flag must be set to not include dest data in the calculation. The
+ * assumption with dma eninges is that they only use the destination
+ * buffer as a source when it is explicity specified in the source list.
+ * @dest: destination page
+ * @src_list: array of source pages (if the dest is also a source it must be
+ * at index zero). The contents of this array may be overwritten.
+ * @offset: offset in pages to start transaction
+ * @src_cnt: number of source pages
+ * @len: length in bytes
+ * @flags: ASYNC_TX_XOR_ZERO_DST, ASYNC_TX_XOR_DROP_DEST,
+ * ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @depend_tx: xor depends on the result of this transaction.
+ * @cb_fn: function to call when the xor completes
+ * @cb_param: parameter to pass to the callback routine
+ */
+struct dma_async_tx_descriptor *
+async_xor(struct page *dest, struct page **src_list, unsigned int offset,
+ int src_cnt, size_t len, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_XOR);
+ struct dma_device *device = chan ? chan->device : NULL;
+ struct dma_async_tx_descriptor *tx = NULL;
+ dma_async_tx_callback _cb_fn;
+ void *_cb_param;
+ unsigned long local_flags;
+ int xor_src_cnt;
+ int i = 0, src_off = 0, int_en;
+
+ BUG_ON(src_cnt <= 1);
+
+ while (src_cnt) {
+ local_flags = flags;
+ if (device) { /* run the xor asynchronously */
+ xor_src_cnt = min(src_cnt, device->max_xor);
+ /* if we are submitting additional xors
+ * only set the callback on the last transaction
+ */
+ if (src_cnt > xor_src_cnt) {
+ local_flags &= ~ASYNC_TX_ACK;
+ _cb_fn = NULL;
+ _cb_param = NULL;
+ } else {
+ _cb_fn = cb_fn;
+ _cb_param = cb_param;
+ }
+
+ int_en = _cb_fn ? 1 : 0;
+
+ tx = device->device_prep_dma_xor(
+ chan, xor_src_cnt, len, int_en);
+
+ if (tx) {
+ do_async_xor(tx, device, chan, dest,
+ &src_list[src_off], offset, xor_src_cnt, len,
+ local_flags, depend_tx, _cb_fn,
+ _cb_param);
+ } else /* fall through */
+ goto xor_sync;
+ } else { /* run the xor synchronously */
+xor_sync:
+ /* in the sync case the dest is an implied source
+ * (assumes the dest is at the src_off index)
+ */
+ if (flags & ASYNC_TX_XOR_DROP_DST) {
+ src_cnt--;
+ src_off++;
+ }
+
+ /* process up to 'MAX_XOR_BLOCKS' sources */
+ xor_src_cnt = min(src_cnt, MAX_XOR_BLOCKS);
+
+ /* if we are submitting additional xors
+ * only set the callback on the last transaction
+ */
+ if (src_cnt > xor_src_cnt) {
+ local_flags &= ~ASYNC_TX_ACK;
+ _cb_fn = NULL;
+ _cb_param = NULL;
+ } else {
+ _cb_fn = cb_fn;
+ _cb_param = cb_param;
+ }
+
+ /* wait for any prerequisite operations */
+ if (depend_tx) {
+ /* if ack is already set then we cannot be sure
+ * we are referring to the correct operation
+ */
+ BUG_ON(depend_tx->ack);
+ if (dma_wait_for_async_tx(depend_tx) ==
+ DMA_ERROR)
+ panic("%s: DMA_ERROR waiting for "
+ "depend_tx\n",
+ __FUNCTION__);
+ }
+
+ do_sync_xor(dest, &src_list[src_off], offset,
+ xor_src_cnt, len, local_flags, depend_tx,
+ _cb_fn, _cb_param);
+ }
+
+ /* the previous tx is hidden from the client,
+ * so ack it
+ */
+ if (i && depend_tx)
+ async_tx_ack(depend_tx);
+
+ depend_tx = tx;
+
+ if (src_cnt > xor_src_cnt) {
+ /* drop completed sources */
+ src_cnt -= xor_src_cnt;
+ src_off += xor_src_cnt;
+
+ /* unconditionally preserve the destination */
+ flags &= ~ASYNC_TX_XOR_ZERO_DST;
+
+ /* use the intermediate result a source, but remember
+ * it's dropped, because it's implied, in the sync case
+ */
+ src_list[--src_off] = dest;
+ src_cnt++;
+ flags |= ASYNC_TX_XOR_DROP_DST;
+ } else
+ src_cnt = 0;
+ i++;
+ }
+
+ return tx;
+}
+EXPORT_SYMBOL_GPL(async_xor);
+
+static int page_is_zero(struct page *p, unsigned int offset, size_t len)
+{
+ char *a = page_address(p) + offset;
+ return ((*(u32 *) a) == 0 &&
+ memcmp(a, a + 4, len - 4) == 0);
+}
+
+/**
+ * async_xor_zero_sum - attempt a xor parity check with a dma engine.
+ * @dest: destination page used if the xor is performed synchronously
+ * @src_list: array of source pages. The dest page must be listed as a source
+ * at index zero. The contents of this array may be overwritten.
+ * @offset: offset in pages to start transaction
+ * @src_cnt: number of source pages
+ * @len: length in bytes
+ * @result: 0 if sum == 0 else non-zero
+ * @flags: ASYNC_TX_ASSUME_COHERENT, ASYNC_TX_ACK, ASYNC_TX_DEP_ACK
+ * @depend_tx: xor depends on the result of this transaction.
+ * @cb_fn: function to call when the xor completes
+ * @cb_param: parameter to pass to the callback routine
+ */
+struct dma_async_tx_descriptor *
+async_xor_zero_sum(struct page *dest, struct page **src_list,
+ unsigned int offset, int src_cnt, size_t len,
+ u32 *result, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_param)
+{
+ struct dma_chan *chan = async_tx_find_channel(depend_tx, DMA_ZERO_SUM);
+ struct dma_device *device = chan ? chan->device : NULL;
+ int int_en = cb_fn ? 1 : 0;
+ struct dma_async_tx_descriptor *tx = device ?
+ device->device_prep_dma_zero_sum(chan, src_cnt, len, result,
+ int_en) : NULL;
+ int i;
+
+ BUG_ON(src_cnt <= 1);
+
+ if (tx) {
+ dma_addr_t dma_addr;
+ enum dma_data_direction dir;
+
+ pr_debug("%s: (async) len: %zu\n", __FUNCTION__, len);
+
+ dir = (flags & ASYNC_TX_ASSUME_COHERENT) ?
+ DMA_NONE : DMA_TO_DEVICE;
+
+ for (i = 0; i < src_cnt; i++) {
+ dma_addr = dma_map_page(device->dev, src_list[i],
+ offset, len, dir);
+ tx->tx_set_src(dma_addr, tx, i);
+ }
+
+ async_tx_submit(chan, tx, flags, depend_tx, cb_fn, cb_param);
+ } else {
+ unsigned long xor_flags = flags;
+
+ pr_debug("%s: (sync) len: %zu\n", __FUNCTION__, len);
+
+ xor_flags |= ASYNC_TX_XOR_DROP_DST;
+ xor_flags &= ~ASYNC_TX_ACK;
+
+ tx = async_xor(dest, src_list, offset, src_cnt, len, xor_flags,
+ depend_tx, NULL, NULL);
+
+ if (tx) {
+ if (dma_wait_for_async_tx(tx) == DMA_ERROR)
+ panic("%s: DMA_ERROR waiting for tx\n",
+ __FUNCTION__);
+ async_tx_ack(tx);
+ }
+
+ *result = page_is_zero(dest, offset, len) ? 0 : 1;
+
+ tx = NULL;
+
+ async_tx_sync_epilog(flags, depend_tx, cb_fn, cb_param);
+ }
+
+ return tx;
+}
+EXPORT_SYMBOL_GPL(async_xor_zero_sum);
+
+static int __init async_xor_init(void)
+{
+ return 0;
+}
+
+static void __exit async_xor_exit(void)
+{
+ do { } while (0);
+}
+
+module_init(async_xor_init);
+module_exit(async_xor_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("asynchronous xor/xor-zero-sum api");
+MODULE_LICENSE("GPL");
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 8edf40c835a7..40a3dcff15bb 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -336,16 +336,41 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc,
return blkcipher_walk_next(desc, walk);
}
+static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+ struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = cipher->setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+}
+
static int setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen)
{
struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) {
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
return cipher->setkey(tfm, key, keylen);
}
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 333aab2f0277..0b2650c2014b 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -20,16 +20,43 @@
#include <linux/string.h>
#include "internal.h"
+static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+ struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = cia->cia_setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+
+}
+
static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
{
struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
-
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+
tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
- } else
- return cia->cia_setkey(tfm, key, keylen);
+ }
+
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
+ return cia->cia_setkey(tfm, key, keylen);
}
static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
diff --git a/crypto/hash.c b/crypto/hash.c
index 4ccd22deef39..4d75ca7b57b2 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -22,6 +22,42 @@ static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg, u32 type,
return alg->cra_ctxsize;
}
+static int hash_setkey_unaligned(struct crypto_hash *crt, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_hash_tfm(crt);
+ struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+ unsigned long alignmask = crypto_hash_alignmask(crt);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = alg->setkey(crt, alignbuffer, keylen);
+ memset(alignbuffer, 0, absize);
+ kfree(buffer);
+ return ret;
+}
+
+static int hash_setkey(struct crypto_hash *crt, const u8 *key,
+ unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_hash_tfm(crt);
+ struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+ unsigned long alignmask = crypto_hash_alignmask(crt);
+
+ if ((unsigned long)key & alignmask)
+ return hash_setkey_unaligned(crt, key, keylen);
+
+ return alg->setkey(crt, key, keylen);
+}
+
static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
{
struct hash_tfm *crt = &tfm->crt_hash;
@@ -34,7 +70,7 @@ static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
crt->update = alg->update;
crt->final = alg->final;
crt->digest = alg->digest;
- crt->setkey = alg->setkey;
+ crt->setkey = hash_setkey;
crt->digestsize = alg->digestsize;
return 0;
diff --git a/crypto/proc.c b/crypto/proc.c
index 102c751a124c..3d73323ff79b 100644
--- a/crypto/proc.c
+++ b/crypto/proc.c
@@ -23,24 +23,13 @@
static void *c_start(struct seq_file *m, loff_t *pos)
{
- struct list_head *v;
- loff_t n = *pos;
-
down_read(&crypto_alg_sem);
- list_for_each(v, &crypto_alg_list)
- if (!n--)
- return list_entry(v, struct crypto_alg, cra_list);
- return NULL;
+ return seq_list_start(&crypto_alg_list, *pos);
}
static void *c_next(struct seq_file *m, void *p, loff_t *pos)
{
- struct list_head *v = p;
-
- (*pos)++;
- v = v->next;
- return (v == &crypto_alg_list) ?
- NULL : list_entry(v, struct crypto_alg, cra_list);
+ return seq_list_next(p, &crypto_alg_list, pos);
}
static void c_stop(struct seq_file *m, void *p)
@@ -50,7 +39,7 @@ static void c_stop(struct seq_file *m, void *p)
static int c_show(struct seq_file *m, void *p)
{
- struct crypto_alg *alg = (struct crypto_alg *)p;
+ struct crypto_alg *alg = list_entry(p, struct crypto_alg, cra_list);
seq_printf(m, "name : %s\n", alg->cra_name);
seq_printf(m, "driver : %s\n", alg->cra_driver_name);
diff --git a/drivers/md/xor.c b/crypto/xor.c
index 324897c4be4e..b2e6db075e49 100644
--- a/drivers/md/xor.c
+++ b/crypto/xor.c
@@ -26,32 +26,32 @@
static struct xor_block_template *active_template;
void
-xor_block(unsigned int count, unsigned int bytes, void **ptr)
+xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
{
- unsigned long *p0, *p1, *p2, *p3, *p4;
+ unsigned long *p1, *p2, *p3, *p4;
- p0 = (unsigned long *) ptr[0];
- p1 = (unsigned long *) ptr[1];
- if (count == 2) {
- active_template->do_2(bytes, p0, p1);
+ p1 = (unsigned long *) srcs[0];
+ if (src_count == 1) {
+ active_template->do_2(bytes, dest, p1);
return;
}
- p2 = (unsigned long *) ptr[2];
- if (count == 3) {
- active_template->do_3(bytes, p0, p1, p2);
+ p2 = (unsigned long *) srcs[1];
+ if (src_count == 2) {
+ active_template->do_3(bytes, dest, p1, p2);
return;
}
- p3 = (unsigned long *) ptr[3];
- if (count == 4) {
- active_template->do_4(bytes, p0, p1, p2, p3);
+ p3 = (unsigned long *) srcs[2];
+ if (src_count == 3) {
+ active_template->do_4(bytes, dest, p1, p2, p3);
return;
}
- p4 = (unsigned long *) ptr[4];
- active_template->do_5(bytes, p0, p1, p2, p3, p4);
+ p4 = (unsigned long *) srcs[3];
+ active_template->do_5(bytes, dest, p1, p2, p3, p4);
}
+EXPORT_SYMBOL(xor_blocks);
/* Set of all registered templates. */
static struct xor_block_template *template_list;
@@ -78,7 +78,7 @@ do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
now = jiffies;
count = 0;
while (jiffies == now) {
- mb();
+ mb(); /* prevent loop optimzation */
tmpl->do_2(BENCH_SIZE, b1, b2);
mb();
count++;
@@ -91,26 +91,26 @@ do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2)
speed = max * (HZ * BENCH_SIZE / 1024);
tmpl->speed = speed;
- printk(" %-10s: %5d.%03d MB/sec\n", tmpl->name,
+ printk(KERN_INFO " %-10s: %5d.%03d MB/sec\n", tmpl->name,
speed / 1000, speed % 1000);
}
-static int
-calibrate_xor_block(void)
+static int __init
+calibrate_xor_blocks(void)
{
void *b1, *b2;
struct xor_block_template *f, *fastest;
b1 = (void *) __get_free_pages(GFP_KERNEL, 2);
- if (! b1) {
- printk("raid5: Yikes! No memory available.\n");
+ if (!b1) {
+ printk(KERN_WARNING "xor: Yikes! No memory available.\n");
return -ENOMEM;
}
b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE;
/*
- * If this arch/cpu has a short-circuited selection, don't loop through all
- * the possible functions, just test the best one
+ * If this arch/cpu has a short-circuited selection, don't loop through
+ * all the possible functions, just test the best one
*/
fastest = NULL;
@@ -122,11 +122,12 @@ calibrate_xor_block(void)
#define xor_speed(templ) do_xor_speed((templ), b1, b2)
if (fastest) {
- printk(KERN_INFO "raid5: automatically using best checksumming function: %s\n",
+ printk(KERN_INFO "xor: automatically using best "
+ "checksumming function: %s\n",
fastest->name);
xor_speed(fastest);
} else {
- printk(KERN_INFO "raid5: measuring checksumming speed\n");
+ printk(KERN_INFO "xor: measuring software checksum speed\n");
XOR_TRY_TEMPLATES;
fastest = template_list;
for (f = fastest; f; f = f->next)
@@ -134,7 +135,7 @@ calibrate_xor_block(void)
fastest = f;
}
- printk("raid5: using function: %s (%d.%03d MB/sec)\n",
+ printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
fastest->name, fastest->speed / 1000, fastest->speed % 1000);
#undef xor_speed
@@ -147,8 +148,8 @@ calibrate_xor_block(void)
static __exit void xor_exit(void) { }
-EXPORT_SYMBOL(xor_block);
MODULE_LICENSE("GPL");
-module_init(calibrate_xor_block);
+/* when built-in xor.o must initialize before drivers/md/md.o */
+core_initcall(calibrate_xor_blocks);
module_exit(xor_exit);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 7916f4b86d23..3e1c442deff9 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -8,6 +8,8 @@ source "drivers/connector/Kconfig"
source "drivers/mtd/Kconfig"
+source "drivers/of/Kconfig"
+
source "drivers/parport/Kconfig"
source "drivers/pnp/Kconfig"
@@ -84,4 +86,7 @@ source "drivers/auxdisplay/Kconfig"
source "drivers/kvm/Kconfig"
+source "drivers/uio/Kconfig"
+
+source "drivers/lguest/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 503d82569449..a9e4c5f922a0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -15,6 +15,8 @@ obj-$(CONFIG_ACPI) += acpi/
obj-$(CONFIG_PNP) += pnp/
obj-$(CONFIG_ARM_AMBA) += amba/
+obj-$(CONFIG_XEN) += xen/
+
# char/ comes before serial/ etc so that the VT console is the boot-time
# default.
obj-y += char/
@@ -38,6 +40,7 @@ obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_FUSION) += message/
obj-$(CONFIG_FIREWIRE) += firewire/
obj-$(CONFIG_IEEE1394) += ieee1394/
+obj-$(CONFIG_UIO) += uio/
obj-y += cdrom/
obj-y += auxdisplay/
obj-$(CONFIG_MTD) += mtd/
@@ -70,6 +73,7 @@ obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_MCA) += mca/
obj-$(CONFIG_EISA) += eisa/
+obj-$(CONFIG_LGUEST_GUEST) += lguest/
obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_NEW_LEDS) += leds/
@@ -82,3 +86,4 @@ obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
+obj-$(CONFIG_OF) += of/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 139f41f033d8..408b45168aba 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -2,16 +2,12 @@
# ACPI Configuration
#
-menu "ACPI (Advanced Configuration and Power Interface) Support"
+menuconfig ACPI
+ bool "ACPI Support (Advanced Configuration and Power Interface) Support"
depends on !X86_NUMAQ
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
- depends on PM
-
-config ACPI
- bool "ACPI Support"
- depends on IA64 || X86
depends on PCI
depends on PM
select PNP
@@ -49,7 +45,6 @@ if ACPI
config ACPI_SLEEP
bool "Sleep States"
depends on X86 && (!SMP || SUSPEND_SMP)
- depends on PM
default y
---help---
This option adds support for ACPI suspend states.
@@ -82,7 +77,6 @@ config ACPI_SLEEP_PROC_SLEEP
config ACPI_PROCFS
bool "Procfs interface (deprecated)"
- depends on ACPI
default y
---help---
The Procfs interface for ACPI is made optional for backward compatibility.
@@ -124,7 +118,7 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
- depends on X86 && BACKLIGHT_CLASS_DEVICE
+ depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -280,6 +274,14 @@ config ACPI_DEBUG
of verbosity. Saying Y enables these statements. This will increase
your kernel size by around 50K.
+config ACPI_DEBUG_FUNC_TRACE
+ bool "Additionally enable ACPI function tracing"
+ default n
+ depends on ACPI_DEBUG
+ help
+ ACPI Debug Statements slow down ACPI processing. Function trace
+ is about half of the penalty and is rarely useful.
+
config ACPI_EC
bool
default y
@@ -330,7 +332,6 @@ config ACPI_CONTAINER
config ACPI_HOTPLUG_MEMORY
tristate "Memory Hotplug"
- depends on ACPI
depends on MEMORY_HOTPLUG
default n
help
@@ -359,5 +360,3 @@ config ACPI_SBS
to today's ACPI "Control Method" battery.
endif # ACPI
-
-endmenu
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index e64c76c8b726..cad932de383d 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -43,21 +43,30 @@
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_BATTERY_HID "PNP0C0A"
#define ACPI_BATTERY_DEVICE_NAME "Battery"
-#define ACPI_BATTERY_FILE_INFO "info"
-#define ACPI_BATTERY_FILE_STATUS "state"
-#define ACPI_BATTERY_FILE_ALARM "alarm"
#define ACPI_BATTERY_NOTIFY_STATUS 0x80
#define ACPI_BATTERY_NOTIFY_INFO 0x81
#define ACPI_BATTERY_UNITS_WATTS "mW"
#define ACPI_BATTERY_UNITS_AMPS "mA"
#define _COMPONENT ACPI_BATTERY_COMPONENT
+
+#define ACPI_BATTERY_UPDATE_TIME 0
+
+#define ACPI_BATTERY_NONE_UPDATE 0
+#define ACPI_BATTERY_EASY_UPDATE 1
+#define ACPI_BATTERY_INIT_UPDATE 2
+
ACPI_MODULE_NAME("battery");
MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI Battery Driver");
MODULE_LICENSE("GPL");
+static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
+
+/* 0 - every time, > 0 - by update_time */
+module_param(update_time, uint, 0644);
+
extern struct proc_dir_entry *acpi_lock_battery_dir(void);
extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
@@ -76,7 +85,7 @@ static struct acpi_driver acpi_battery_driver = {
},
};
-struct acpi_battery_status {
+struct acpi_battery_state {
acpi_integer state;
acpi_integer present_rate;
acpi_integer remaining_capacity;
@@ -99,33 +108,111 @@ struct acpi_battery_info {
acpi_string oem_info;
};
-struct acpi_battery_flags {
- u8 present:1; /* Bay occupied? */
- u8 power_unit:1; /* 0=watts, 1=apms */
- u8 alarm:1; /* _BTP present? */
- u8 reserved:5;
+enum acpi_battery_files{
+ ACPI_BATTERY_INFO = 0,
+ ACPI_BATTERY_STATE,
+ ACPI_BATTERY_ALARM,
+ ACPI_BATTERY_NUMFILES,
};
-struct acpi_battery_trips {
- unsigned long warning;
- unsigned long low;
+struct acpi_battery_flags {
+ u8 battery_present_prev;
+ u8 alarm_present;
+ u8 init_update;
+ u8 update[ACPI_BATTERY_NUMFILES];
+ u8 power_unit;
};
struct acpi_battery {
- struct acpi_device * device;
+ struct mutex mutex;
+ struct acpi_device *device;
struct acpi_battery_flags flags;
- struct acpi_battery_trips trips;
+ struct acpi_buffer bif_data;
+ struct acpi_buffer bst_data;
unsigned long alarm;
- struct acpi_battery_info *info;
+ unsigned long update_time[ACPI_BATTERY_NUMFILES];
};
+inline int acpi_battery_present(struct acpi_battery *battery)
+{
+ return battery->device->status.battery_present;
+}
+inline char *acpi_battery_power_units(struct acpi_battery *battery)
+{
+ if (battery->flags.power_unit)
+ return ACPI_BATTERY_UNITS_AMPS;
+ else
+ return ACPI_BATTERY_UNITS_WATTS;
+}
+
+inline acpi_handle acpi_battery_handle(struct acpi_battery *battery)
+{
+ return battery->device->handle;
+}
+
/* --------------------------------------------------------------------------
Battery Management
-------------------------------------------------------------------------- */
-static int
-acpi_battery_get_info(struct acpi_battery *battery,
- struct acpi_battery_info **bif)
+static void acpi_battery_check_result(struct acpi_battery *battery, int result)
+{
+ if (!battery)
+ return;
+
+ if (result) {
+ battery->flags.init_update = 1;
+ }
+}
+
+static int acpi_battery_extract_package(struct acpi_battery *battery,
+ union acpi_object *package,
+ struct acpi_buffer *format,
+ struct acpi_buffer *data,
+ char *package_name)
+{
+ acpi_status status = AE_OK;
+ struct acpi_buffer data_null = { 0, NULL };
+
+ status = acpi_extract_package(package, format, &data_null);
+ if (status != AE_BUFFER_OVERFLOW) {
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
+ package_name));
+ return -ENODEV;
+ }
+
+ if (data_null.length != data->length) {
+ kfree(data->pointer);
+ data->pointer = kzalloc(data_null.length, GFP_KERNEL);
+ if (!data->pointer) {
+ ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
+ return -ENOMEM;
+ }
+ data->length = data_null.length;
+ }
+
+ status = acpi_extract_package(package, format, data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
+ package_name));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int acpi_battery_get_status(struct acpi_battery *battery)
+{
+ int result = 0;
+
+ result = acpi_bus_get_status(battery->device);
+ if (result) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
+ return -ENODEV;
+ }
+ return result;
+}
+
+static int acpi_battery_get_info(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = 0;
@@ -133,16 +220,20 @@ acpi_battery_get_info(struct acpi_battery *battery,
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
ACPI_BATTERY_FORMAT_BIF
};
- struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
+ struct acpi_buffer *data = NULL;
+ struct acpi_battery_info *bif = NULL;
+ battery->update_time[ACPI_BATTERY_INFO] = get_seconds();
- if (!battery || !bif)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return 0;
- /* Evalute _BIF */
+ /* Evaluate _BIF */
- status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
return -ENODEV;
@@ -150,41 +241,29 @@ acpi_battery_get_info(struct acpi_battery *battery,
package = buffer.pointer;
- /* Extract Package Data */
-
- status = acpi_extract_package(package, &format, &data);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
- result = -ENODEV;
- goto end;
- }
+ data = &battery->bif_data;
- data.pointer = kzalloc(data.length, GFP_KERNEL);
- if (!data.pointer) {
- result = -ENOMEM;
- goto end;
- }
+ /* Extract Package Data */
- status = acpi_extract_package(package, &format, &data);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
- kfree(data.pointer);
- result = -ENODEV;
+ result =
+ acpi_battery_extract_package(battery, package, &format, data,
+ "_BIF");
+ if (result)
goto end;
- }
end:
+
kfree(buffer.pointer);
- if (!result)
- (*bif) = data.pointer;
+ if (!result) {
+ bif = data->pointer;
+ battery->flags.power_unit = bif->power_unit;
+ }
return result;
}
-static int
-acpi_battery_get_status(struct acpi_battery *battery,
- struct acpi_battery_status **bst)
+static int acpi_battery_get_state(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = 0;
@@ -192,16 +271,19 @@ acpi_battery_get_status(struct acpi_battery *battery,
struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
ACPI_BATTERY_FORMAT_BST
};
- struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
+ struct acpi_buffer *data = NULL;
+ battery->update_time[ACPI_BATTERY_STATE] = get_seconds();
- if (!battery || !bst)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return 0;
- /* Evalute _BST */
+ /* Evaluate _BST */
- status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
+ &buffer);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
return -ENODEV;
@@ -209,55 +291,49 @@ acpi_battery_get_status(struct acpi_battery *battery,
package = buffer.pointer;
- /* Extract Package Data */
-
- status = acpi_extract_package(package, &format, &data);
- if (status != AE_BUFFER_OVERFLOW) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
- result = -ENODEV;
- goto end;
- }
+ data = &battery->bst_data;
- data.pointer = kzalloc(data.length, GFP_KERNEL);
- if (!data.pointer) {
- result = -ENOMEM;
- goto end;
- }
+ /* Extract Package Data */
- status = acpi_extract_package(package, &format, &data);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
- kfree(data.pointer);
- result = -ENODEV;
+ result =
+ acpi_battery_extract_package(battery, package, &format, data,
+ "_BST");
+ if (result)
goto end;
- }
end:
kfree(buffer.pointer);
- if (!result)
- (*bst) = data.pointer;
-
return result;
}
-static int
-acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
+static int acpi_battery_get_alarm(struct acpi_battery *battery)
+{
+ battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
+
+ return 0;
+}
+
+static int acpi_battery_set_alarm(struct acpi_battery *battery,
+ unsigned long alarm)
{
acpi_status status = 0;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list arg_list = { 1, &arg0 };
+ battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
- if (!battery)
- return -EINVAL;
+ if (!acpi_battery_present(battery))
+ return -ENODEV;
- if (!battery->flags.alarm)
+ if (!battery->flags.alarm_present)
return -ENODEV;
arg0.integer.value = alarm;
- status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
+ status =
+ acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+ &arg_list, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -268,65 +344,114 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
return 0;
}
-static int acpi_battery_check(struct acpi_battery *battery)
+static int acpi_battery_init_alarm(struct acpi_battery *battery)
{
int result = 0;
acpi_status status = AE_OK;
acpi_handle handle = NULL;
- struct acpi_device *device = NULL;
- struct acpi_battery_info *bif = NULL;
+ struct acpi_battery_info *bif = battery->bif_data.pointer;
+ unsigned long alarm = battery->alarm;
+ /* See if alarms are supported, and if so, set default */
- if (!battery)
- return -EINVAL;
-
- device = battery->device;
+ status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
+ if (ACPI_SUCCESS(status)) {
+ battery->flags.alarm_present = 1;
+ if (!alarm && bif) {
+ alarm = bif->design_capacity_warning;
+ }
+ result = acpi_battery_set_alarm(battery, alarm);
+ if (result)
+ goto end;
+ } else {
+ battery->flags.alarm_present = 0;
+ }
- result = acpi_bus_get_status(device);
- if (result)
- return result;
+ end:
- /* Insertion? */
+ return result;
+}
- if (!battery->flags.present && device->status.battery_present) {
+static int acpi_battery_init_update(struct acpi_battery *battery)
+{
+ int result = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
+ result = acpi_battery_get_status(battery);
+ if (result)
+ return result;
- /* Evalute _BIF to get certain static information */
+ battery->flags.battery_present_prev = acpi_battery_present(battery);
- result = acpi_battery_get_info(battery, &bif);
+ if (acpi_battery_present(battery)) {
+ result = acpi_battery_get_info(battery);
+ if (result)
+ return result;
+ result = acpi_battery_get_state(battery);
if (result)
return result;
- battery->flags.power_unit = bif->power_unit;
- battery->trips.warning = bif->design_capacity_warning;
- battery->trips.low = bif->design_capacity_low;
- kfree(bif);
+ acpi_battery_init_alarm(battery);
+ }
+
+ return result;
+}
- /* See if alarms are supported, and if so, set default */
+static int acpi_battery_update(struct acpi_battery *battery,
+ int update, int *update_result_ptr)
+{
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
+
+ if (!acpi_battery_present(battery)) {
+ update = 1;
+ }
- status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
- if (ACPI_SUCCESS(status)) {
- battery->flags.alarm = 1;
- acpi_battery_set_alarm(battery, battery->trips.warning);
+ if (battery->flags.init_update) {
+ result = acpi_battery_init_update(battery);
+ if (result)
+ goto end;
+ update_result = ACPI_BATTERY_INIT_UPDATE;
+ } else if (update) {
+ result = acpi_battery_get_status(battery);
+ if (result)
+ goto end;
+ if ((!battery->flags.battery_present_prev & acpi_battery_present(battery))
+ || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) {
+ result = acpi_battery_init_update(battery);
+ if (result)
+ goto end;
+ update_result = ACPI_BATTERY_INIT_UPDATE;
+ } else {
+ update_result = ACPI_BATTERY_EASY_UPDATE;
}
}
- /* Removal? */
+ end:
- else if (battery->flags.present && !device->status.battery_present) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
- }
+ battery->flags.init_update = (result != 0);
- battery->flags.present = device->status.battery_present;
+ *update_result_ptr = update_result;
return result;
}
-static void acpi_battery_check_present(struct acpi_battery *battery)
+static void acpi_battery_notify_update(struct acpi_battery *battery)
{
- if (!battery->flags.present) {
- acpi_battery_check(battery);
+ acpi_battery_get_status(battery);
+
+ if (battery->flags.init_update) {
+ return;
+ }
+
+ if ((!battery->flags.battery_present_prev &
+ acpi_battery_present(battery)) ||
+ (battery->flags.battery_present_prev &
+ !acpi_battery_present(battery))) {
+ battery->flags.init_update = 1;
+ } else {
+ battery->flags.update[ACPI_BATTERY_INFO] = 1;
+ battery->flags.update[ACPI_BATTERY_STATE] = 1;
+ battery->flags.update[ACPI_BATTERY_ALARM] = 1;
}
}
@@ -335,37 +460,33 @@ static void acpi_battery_check_present(struct acpi_battery *battery)
-------------------------------------------------------------------------- */
static struct proc_dir_entry *acpi_battery_dir;
-static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+
+static int acpi_battery_print_info(struct seq_file *seq, int result)
{
- int result = 0;
struct acpi_battery *battery = seq->private;
struct acpi_battery_info *bif = NULL;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (battery->flags.present)
+ if (acpi_battery_present(battery))
seq_printf(seq, "present: yes\n");
else {
seq_printf(seq, "present: no\n");
goto end;
}
- /* Battery Info (_BIF) */
-
- result = acpi_battery_get_info(battery, &bif);
- if (result || !bif) {
- seq_printf(seq, "ERROR: Unable to read battery information\n");
+ bif = battery->bif_data.pointer;
+ if (!bif) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
+ result = -ENODEV;
goto end;
}
- units =
- bif->
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+ /* Battery Units */
+
+ units = acpi_battery_power_units(battery);
if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
seq_printf(seq, "design capacity: unknown\n");
@@ -396,7 +517,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
else
seq_printf(seq, "design voltage: %d mV\n",
(u32) bif->design_voltage);
-
seq_printf(seq, "design capacity warning: %d %sh\n",
(u32) bif->design_capacity_warning, units);
seq_printf(seq, "design capacity low: %d %sh\n",
@@ -411,50 +531,40 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
seq_printf(seq, "OEM info: %s\n", bif->oem_info);
end:
- kfree(bif);
- return 0;
-}
+ if (result)
+ seq_printf(seq, "ERROR: Unable to read battery info\n");
-static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+ return result;
}
-static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+static int acpi_battery_print_state(struct seq_file *seq, int result)
{
- int result = 0;
struct acpi_battery *battery = seq->private;
- struct acpi_battery_status *bst = NULL;
+ struct acpi_battery_state *bst = NULL;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (battery->flags.present)
+ if (acpi_battery_present(battery))
seq_printf(seq, "present: yes\n");
else {
seq_printf(seq, "present: no\n");
goto end;
}
- /* Battery Units */
-
- units =
- battery->flags.
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
- /* Battery Status (_BST) */
-
- result = acpi_battery_get_status(battery, &bst);
- if (result || !bst) {
- seq_printf(seq, "ERROR: Unable to read battery status\n");
+ bst = battery->bst_data.pointer;
+ if (!bst) {
+ ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
+ result = -ENODEV;
goto end;
}
+ /* Battery Units */
+
+ units = acpi_battery_power_units(battery);
+
if (!(bst->state & 0x04))
seq_printf(seq, "capacity state: ok\n");
else
@@ -490,48 +600,43 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
(u32) bst->present_voltage);
end:
- kfree(bst);
- return 0;
-}
+ if (result) {
+ seq_printf(seq, "ERROR: Unable to read battery state\n");
+ }
-static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_battery_read_state, PDE(inode)->data);
+ return result;
}
-static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+static int acpi_battery_print_alarm(struct seq_file *seq, int result)
{
struct acpi_battery *battery = seq->private;
char *units = "?";
-
- if (!battery)
+ if (result)
goto end;
- acpi_battery_check_present(battery);
-
- if (!battery->flags.present) {
+ if (!acpi_battery_present(battery)) {
seq_printf(seq, "present: no\n");
goto end;
}
/* Battery Units */
- units =
- battery->flags.
- power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
- /* Battery Alarm */
+ units = acpi_battery_power_units(battery);
seq_printf(seq, "alarm: ");
if (!battery->alarm)
seq_printf(seq, "unsupported\n");
else
- seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
+ seq_printf(seq, "%lu %sh\n", battery->alarm, units);
end:
- return 0;
+
+ if (result)
+ seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+
+ return result;
}
static ssize_t
@@ -543,27 +648,113 @@ acpi_battery_write_alarm(struct file *file,
char alarm_string[12] = { '\0' };
struct seq_file *m = file->private_data;
struct acpi_battery *battery = m->private;
-
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
if (!battery || (count > sizeof(alarm_string) - 1))
return -EINVAL;
- acpi_battery_check_present(battery);
+ mutex_lock(&battery->mutex);
- if (!battery->flags.present)
- return -ENODEV;
+ result = acpi_battery_update(battery, 1, &update_result);
+ if (result) {
+ result = -ENODEV;
+ goto end;
+ }
+
+ if (!acpi_battery_present(battery)) {
+ result = -ENODEV;
+ goto end;
+ }
- if (copy_from_user(alarm_string, buffer, count))
- return -EFAULT;
+ if (copy_from_user(alarm_string, buffer, count)) {
+ result = -EFAULT;
+ goto end;
+ }
alarm_string[count] = '\0';
result = acpi_battery_set_alarm(battery,
simple_strtoul(alarm_string, NULL, 0));
if (result)
- return result;
+ goto end;
+
+ end:
- return count;
+ acpi_battery_check_result(battery, result);
+
+ if (!result)
+ result = count;
+
+ mutex_unlock(&battery->mutex);
+
+ return result;
+}
+
+typedef int(*print_func)(struct seq_file *seq, int result);
+typedef int(*get_func)(struct acpi_battery *battery);
+
+static struct acpi_read_mux {
+ print_func print;
+ get_func get;
+} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = {
+ {.get = acpi_battery_get_info, .print = acpi_battery_print_info},
+ {.get = acpi_battery_get_state, .print = acpi_battery_print_state},
+ {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm},
+};
+
+static int acpi_battery_read(int fid, struct seq_file *seq)
+{
+ struct acpi_battery *battery = seq->private;
+ int result = 0;
+ int update_result = ACPI_BATTERY_NONE_UPDATE;
+ int update = 0;
+
+ mutex_lock(&battery->mutex);
+
+ update = (get_seconds() - battery->update_time[fid] >= update_time);
+ update = (update | battery->flags.update[fid]);
+
+ result = acpi_battery_update(battery, update, &update_result);
+ if (result)
+ goto end;
+
+ if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+ result = acpi_read_funcs[fid].get(battery);
+ if (result)
+ goto end;
+ }
+
+ end:
+ result = acpi_read_funcs[fid].print(seq, result);
+ acpi_battery_check_result(battery, result);
+ battery->flags.update[fid] = result;
+ mutex_unlock(&battery->mutex);
+ return result;
+}
+
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+ return acpi_battery_read(ACPI_BATTERY_INFO, seq);
+}
+
+static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+{
+ return acpi_battery_read(ACPI_BATTERY_STATE, seq);
+}
+
+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+{
+ return acpi_battery_read(ACPI_BATTERY_ALARM, seq);
+}
+
+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+}
+
+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_state, PDE(inode)->data);
}
static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -571,35 +762,51 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
}
-static const struct file_operations acpi_battery_info_ops = {
+static struct battery_file {
+ struct file_operations ops;
+ mode_t mode;
+ char *name;
+} acpi_battery_file[] = {
+ {
+ .name = "info",
+ .mode = S_IRUGO,
+ .ops = {
.open = acpi_battery_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_state_ops = {
+ },
+ },
+ {
+ .name = "state",
+ .mode = S_IRUGO,
+ .ops = {
.open = acpi_battery_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_alarm_ops = {
+ },
+ },
+ {
+ .name = "alarm",
+ .mode = S_IFREG | S_IRUGO | S_IWUSR,
+ .ops = {
.open = acpi_battery_alarm_open_fs,
.read = seq_read,
.write = acpi_battery_write_alarm,
.llseek = seq_lseek,
.release = single_release,
.owner = THIS_MODULE,
+ },
+ },
};
static int acpi_battery_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
-
+ int i;
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
@@ -609,38 +816,16 @@ static int acpi_battery_add_fs(struct acpi_device *device)
acpi_device_dir(device)->owner = THIS_MODULE;
}
- /* 'info' [R] */
- entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
- if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_info_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
- /* 'status' [R] */
- entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
- S_IRUGO, acpi_device_dir(device));
- if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_state_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
- /* 'alarm' [R/W] */
- entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
- if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_alarm_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
+ for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+ entry = create_proc_entry(acpi_battery_file[i].name,
+ acpi_battery_file[i].mode, acpi_device_dir(device));
+ if (!entry)
+ return -ENODEV;
+ else {
+ entry->proc_fops = &acpi_battery_file[i].ops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
}
return 0;
@@ -648,15 +833,12 @@ static int acpi_battery_add_fs(struct acpi_device *device)
static int acpi_battery_remove_fs(struct acpi_device *device)
{
-
+ int i;
if (acpi_device_dir(device)) {
- remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
+ for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+ remove_proc_entry(acpi_battery_file[i].name,
acpi_device_dir(device));
- remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_BATTERY_FILE_INFO,
- acpi_device_dir(device));
-
+ }
remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
acpi_device_dir(device) = NULL;
}
@@ -673,7 +855,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
struct acpi_battery *battery = data;
struct acpi_device *device = NULL;
-
if (!battery)
return;
@@ -684,8 +865,10 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
case ACPI_BATTERY_NOTIFY_INFO:
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
- acpi_battery_check(battery);
- acpi_bus_generate_event(device, event, battery->flags.present);
+ device = battery->device;
+ acpi_battery_notify_update(battery);
+ acpi_bus_generate_event(device, event,
+ acpi_battery_present(battery));
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -702,7 +885,6 @@ static int acpi_battery_add(struct acpi_device *device)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
-
if (!device)
return -EINVAL;
@@ -710,15 +892,21 @@ static int acpi_battery_add(struct acpi_device *device)
if (!battery)
return -ENOMEM;
+ mutex_init(&battery->mutex);
+
+ mutex_lock(&battery->mutex);
+
battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
acpi_driver_data(device) = battery;
- result = acpi_battery_check(battery);
+ result = acpi_battery_get_status(battery);
if (result)
goto end;
+ battery->flags.init_update = 1;
+
result = acpi_battery_add_fs(device);
if (result)
goto end;
@@ -727,6 +915,7 @@ static int acpi_battery_add(struct acpi_device *device)
ACPI_ALL_NOTIFY,
acpi_battery_notify, battery);
if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
result = -ENODEV;
goto end;
}
@@ -736,11 +925,14 @@ static int acpi_battery_add(struct acpi_device *device)
device->status.battery_present ? "present" : "absent");
end:
+
if (result) {
acpi_battery_remove_fs(device);
kfree(battery);
}
+ mutex_unlock(&battery->mutex);
+
return result;
}
@@ -749,18 +941,27 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
-
if (!device || !acpi_driver_data(device))
return -EINVAL;
battery = acpi_driver_data(device);
+ mutex_lock(&battery->mutex);
+
status = acpi_remove_notify_handler(device->handle,
ACPI_ALL_NOTIFY,
acpi_battery_notify);
acpi_battery_remove_fs(device);
+ kfree(battery->bif_data.pointer);
+
+ kfree(battery->bst_data.pointer);
+
+ mutex_unlock(&battery->mutex);
+
+ mutex_destroy(&battery->mutex);
+
kfree(battery);
return 0;
@@ -775,7 +976,10 @@ static int acpi_battery_resume(struct acpi_device *device)
return -EINVAL;
battery = device->driver_data;
- return acpi_battery_check(battery);
+
+ battery->flags.init_update = 1;
+
+ return 0;
}
static int __init acpi_battery_init(void)
@@ -800,7 +1004,6 @@ static int __init acpi_battery_init(void)
static void __exit acpi_battery_exit(void)
{
-
acpi_bus_unregister_driver(&acpi_battery_driver);
acpi_unlock_battery_dir(acpi_battery_dir);
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index fb3f31b5e69f..56a5b3fffeb3 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, int id)
new_bay->pdev = pdev;
platform_set_drvdata(pdev, new_bay);
+ /*
+ * we want the bay driver to be able to send uevents
+ */
+ pdev->dev.uevent_suppress = 0;
+
if (acpi_bay_add_fs(new_bay)) {
platform_device_unregister(new_bay->pdev);
goto bay_add_err;
@@ -328,18 +333,12 @@ static void bay_notify(acpi_handle handle, u32 event, void *data)
{
struct bay *bay_dev = (struct bay *)data;
struct device *dev = &bay_dev->pdev->dev;
+ char event_string[12];
+ char *envp[] = { event_string, NULL };
bay_dprintk(handle, "Bay event");
-
- switch(event) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- case ACPI_NOTIFY_EJECT_REQUEST:
- kobject_uevent(&dev->kobj, KOBJ_CHANGE);
- break;
- default:
- printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
- }
+ sprintf(event_string, "BAY_EVENT=%d\n", event);
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
static acpi_status
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index e5084ececb6f..6b2658c96242 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -292,6 +292,10 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
if (!device)
return -EINVAL;
+ if (acpi_bus_generate_genetlink_event(device, type, data))
+ printk(KERN_WARNING PREFIX
+ "Failed to generate an ACPI event via genetlink!\n");
+
/* drop event on the floor if no one's listening */
if (!event_is_open)
return 0;
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 4546bf873aea..6192c8be66df 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -40,8 +40,15 @@ MODULE_AUTHOR("Kristen Carlson Accardi");
MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
MODULE_LICENSE("GPL");
+static int immediate_undock = 1;
+module_param(immediate_undock, bool, 0644);
+MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
+ "undock immediately when the undock button is pressed, 0 will cause"
+ " the driver to wait for userspace to write the undock sysfs file "
+ " before undocking");
+
static struct atomic_notifier_head dock_notifier_list;
-static struct platform_device dock_device;
+static struct platform_device *dock_device;
static char dock_device_name[] = "dock";
struct dock_station {
@@ -63,6 +70,7 @@ struct dock_dependent_device {
};
#define DOCK_DOCKING 0x00000001
+#define DOCK_UNDOCKING 0x00000002
#define DOCK_EVENT 3
#define UNDOCK_EVENT 2
@@ -327,12 +335,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
static void dock_event(struct dock_station *ds, u32 event, int num)
{
- struct device *dev = &dock_device.dev;
+ struct device *dev = &dock_device->dev;
+ char event_string[7];
+ char *envp[] = { event_string, NULL };
+
+ if (num == UNDOCK_EVENT)
+ sprintf(event_string, "UNDOCK");
+ else
+ sprintf(event_string, "DOCK");
+
/*
* Indicate that the status of the dock station has
* changed.
*/
- kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
}
/**
@@ -380,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock)
union acpi_object arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
- obj = name_buffer.pointer;
- printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
+ printk(KERN_INFO PREFIX "%s - %s\n",
+ (char *)name_buffer.pointer, dock ? "docking" : "undocking");
/* _DCK method has one argument */
arg_list.count = 1;
@@ -394,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock)
arg.integer.value = dock;
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
if (ACPI_FAILURE(status))
- pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
+ printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
+ (char *)name_buffer.pointer);
kfree(buffer.pointer);
kfree(name_buffer.pointer);
}
@@ -420,6 +436,16 @@ static inline void complete_dock(struct dock_station *ds)
ds->last_dock_time = jiffies;
}
+static inline void begin_undock(struct dock_station *ds)
+{
+ ds->flags |= DOCK_UNDOCKING;
+}
+
+static inline void complete_undock(struct dock_station *ds)
+{
+ ds->flags &= ~(DOCK_UNDOCKING);
+}
+
/**
* dock_in_progress - see if we are in the middle of handling a dock event
* @ds: the dock station
@@ -550,7 +576,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
printk(KERN_ERR PREFIX "Unable to undock!\n");
return -EBUSY;
}
-
+ complete_undock(ds);
return 0;
}
@@ -594,7 +620,11 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
* to the driver who wish to hotplug.
*/
case ACPI_NOTIFY_EJECT_REQUEST:
- handle_eject_request(ds, event);
+ begin_undock(ds);
+ if (immediate_undock)
+ handle_eject_request(ds, event);
+ else
+ dock_event(ds, event, UNDOCK_EVENT);
break;
default:
printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -653,6 +683,17 @@ static ssize_t show_docked(struct device *dev,
DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
/*
+ * show_flags - read method for flags file in sysfs
+ */
+static ssize_t show_flags(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
+
+}
+DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+
+/*
* write_undock - write method for "undock" file in sysfs
*/
static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
@@ -675,16 +716,15 @@ static ssize_t show_dock_uid(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned long lbuf;
- acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
- if(ACPI_FAILURE(status)) {
+ acpi_status status = acpi_evaluate_integer(dock_station->handle,
+ "_UID", NULL, &lbuf);
+ if (ACPI_FAILURE(status))
return 0;
- }
+
return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
}
DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
-
-
/**
* dock_add - add a new dock station
* @handle: the dock station handle
@@ -711,33 +751,53 @@ static int dock_add(acpi_handle handle)
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
/* initialize platform device stuff */
- dock_device.name = dock_device_name;
- ret = platform_device_register(&dock_device);
+ dock_device =
+ platform_device_register_simple(dock_device_name, 0, NULL, 0);
+ if (IS_ERR(dock_device)) {
+ kfree(dock_station);
+ dock_station = NULL;
+ return PTR_ERR(dock_device);
+ }
+
+ /* we want the dock device to send uevents */
+ dock_device->dev.uevent_suppress = 0;
+
+ ret = device_create_file(&dock_device->dev, &dev_attr_docked);
if (ret) {
- printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+ printk("Error %d adding sysfs file\n", ret);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
- ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+ ret = device_create_file(&dock_device->dev, &dev_attr_undock);
if (ret) {
printk("Error %d adding sysfs file\n", ret);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
- ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+ ret = device_create_file(&dock_device->dev, &dev_attr_uid);
if (ret) {
printk("Error %d adding sysfs file\n", ret);
- device_remove_file(&dock_device.dev, &dev_attr_docked);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
- ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+ ret = device_create_file(&dock_device->dev, &dev_attr_flags);
if (ret) {
printk("Error %d adding sysfs file\n", ret);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ device_remove_file(&dock_device->dev, &dev_attr_uid);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
@@ -750,6 +810,7 @@ static int dock_add(acpi_handle handle)
dd = alloc_dock_dependent_device(handle);
if (!dd) {
kfree(dock_station);
+ dock_station = NULL;
ret = -ENOMEM;
goto dock_add_err_unregister;
}
@@ -773,10 +834,13 @@ static int dock_add(acpi_handle handle)
dock_add_err:
kfree(dd);
dock_add_err_unregister:
- device_remove_file(&dock_device.dev, &dev_attr_docked);
- device_remove_file(&dock_device.dev, &dev_attr_undock);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ device_remove_file(&dock_device->dev, &dev_attr_uid);
+ device_remove_file(&dock_device->dev, &dev_attr_flags);
+ platform_device_unregister(dock_device);
kfree(dock_station);
+ dock_station = NULL;
return ret;
}
@@ -804,12 +868,15 @@ static int dock_remove(void)
printk(KERN_ERR "Error removing notify handler\n");
/* cleanup sysfs */
- device_remove_file(&dock_device.dev, &dev_attr_docked);
- device_remove_file(&dock_device.dev, &dev_attr_undock);
- platform_device_unregister(&dock_device);
+ device_remove_file(&dock_device->dev, &dev_attr_docked);
+ device_remove_file(&dock_device->dev, &dev_attr_undock);
+ device_remove_file(&dock_device->dev, &dev_attr_uid);
+ device_remove_file(&dock_device->dev, &dev_attr_flags);
+ platform_device_unregister(dock_device);
/* free dock station memory */
kfree(dock_station);
+ dock_station = NULL;
return 0;
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 82f496c07675..10e851021eca 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,25 +34,26 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
+#include <linux/list.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <acpi/actypes.h>
-#define _COMPONENT ACPI_EC_COMPONENT
-ACPI_MODULE_NAME("ec");
-#define ACPI_EC_COMPONENT 0x00100000
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_HID "PNP0C09"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
+
#undef PREFIX
#define PREFIX "ACPI: EC: "
+
/* EC status register */
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
+
/* EC commands */
enum ec_command {
ACPI_EC_COMMAND_READ = 0x80,
@@ -61,6 +62,7 @@ enum ec_command {
ACPI_EC_BURST_DISABLE = 0x83,
ACPI_EC_COMMAND_QUERY = 0x84,
};
+
/* EC events */
enum ec_event {
ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
@@ -94,6 +96,16 @@ static struct acpi_driver acpi_ec_driver = {
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
/* External interfaces use first EC only, so remember */
+typedef int (*acpi_ec_query_func) (void *data);
+
+struct acpi_ec_query_handler {
+ struct list_head node;
+ acpi_ec_query_func func;
+ acpi_handle handle;
+ void *data;
+ u8 query_bit;
+};
+
static struct acpi_ec {
acpi_handle handle;
unsigned long gpe;
@@ -104,6 +116,7 @@ static struct acpi_ec {
atomic_t query_pending;
atomic_t event_count;
wait_queue_head_t wait;
+ struct list_head list;
} *boot_ec, *first_ec;
/* --------------------------------------------------------------------------
@@ -245,7 +258,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
if (status) {
- printk(KERN_DEBUG PREFIX
+ printk(KERN_ERR PREFIX
"input buffer is not empty, aborting transaction\n");
goto end;
}
@@ -394,21 +407,67 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
+int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
+ acpi_handle handle, acpi_ec_query_func func,
+ void *data)
+{
+ struct acpi_ec_query_handler *handler =
+ kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
+ if (!handler)
+ return -ENOMEM;
+
+ handler->query_bit = query_bit;
+ handler->handle = handle;
+ handler->func = func;
+ handler->data = data;
+ mutex_lock(&ec->lock);
+ list_add_tail(&handler->node, &ec->list);
+ mutex_unlock(&ec->lock);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
+
+void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
+{
+ struct acpi_ec_query_handler *handler;
+ mutex_lock(&ec->lock);
+ list_for_each_entry(handler, &ec->list, node) {
+ if (query_bit == handler->query_bit) {
+ list_del(&handler->node);
+ kfree(handler);
+ break;
+ }
+ }
+ mutex_unlock(&ec->lock);
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
static void acpi_ec_gpe_query(void *ec_cxt)
{
struct acpi_ec *ec = ec_cxt;
u8 value = 0;
- char object_name[8];
+ struct acpi_ec_query_handler *handler, copy;
if (!ec || acpi_ec_query(ec, &value))
return;
-
- snprintf(object_name, 8, "_Q%2.2X", value);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
-
- acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
+ mutex_lock(&ec->lock);
+ list_for_each_entry(handler, &ec->list, node) {
+ if (value == handler->query_bit) {
+ /* have custom handler for this bit */
+ memcpy(&copy, handler, sizeof(copy));
+ mutex_unlock(&ec->lock);
+ if (copy.func) {
+ copy.func(copy.data);
+ } else if (copy.handle) {
+ acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
+ }
+ return;
+ }
+ }
+ mutex_unlock(&ec->lock);
+ printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value);
}
static u32 acpi_ec_gpe_handler(void *data)
@@ -427,8 +486,7 @@ static u32 acpi_ec_gpe_handler(void *data)
if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
atomic_set(&ec->query_pending, 1);
status =
- acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
- ec);
+ acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
}
return status == AE_OK ?
@@ -454,57 +512,35 @@ acpi_ec_space_setup(acpi_handle region_handle,
}
static acpi_status
-acpi_ec_space_handler(u32 function,
- acpi_physical_address address,
- u32 bit_width,
- acpi_integer * value,
+acpi_ec_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, acpi_integer *value,
void *handler_context, void *region_context)
{
- int result = 0;
struct acpi_ec *ec = handler_context;
- u64 temp = *value;
- acpi_integer f_v = 0;
- int i = 0;
+ int result = 0, i = 0;
+ u8 temp = 0;
if ((address > 0xFF) || !value || !handler_context)
return AE_BAD_PARAMETER;
- if (bit_width != 8 && acpi_strict) {
+ if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER;
- }
-
- next_byte:
- switch (function) {
- case ACPI_READ:
- temp = 0;
- result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
- break;
- case ACPI_WRITE:
- result = acpi_ec_write(ec, (u8) address, (u8) temp);
- break;
- default:
- result = -EINVAL;
- goto out;
- break;
- }
- bit_width -= 8;
- if (bit_width) {
- if (function == ACPI_READ)
- f_v |= temp << 8 * i;
- if (function == ACPI_WRITE)
- temp >>= 8;
- i++;
- address++;
- goto next_byte;
- }
+ if (bits != 8 && acpi_strict)
+ return AE_BAD_PARAMETER;
- if (function == ACPI_READ) {
- f_v |= temp << 8 * i;
- *value = f_v;
+ while (bits - i > 0) {
+ if (function == ACPI_READ) {
+ result = acpi_ec_read(ec, address, &temp);
+ (*value) |= ((acpi_integer)temp) << i;
+ } else {
+ temp = 0xff & ((*value) >> i);
+ result = acpi_ec_write(ec, address, temp);
+ }
+ i += 8;
+ ++address;
}
- out:
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
@@ -597,9 +633,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
static acpi_status
ec_parse_io_ports(struct acpi_resource *resource, void *context);
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
-
static struct acpi_ec *make_acpi_ec(void)
{
struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
@@ -610,13 +643,52 @@ static struct acpi_ec *make_acpi_ec(void)
atomic_set(&ec->event_count, 1);
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
+ INIT_LIST_HEAD(&ec->list);
return ec;
}
+static acpi_status
+acpi_ec_register_query_methods(acpi_handle handle, u32 level,
+ void *context, void **return_value)
+{
+ struct acpi_namespace_node *node = handle;
+ struct acpi_ec *ec = context;
+ int value = 0;
+ if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
+ acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
+ }
+ return AE_OK;
+}
+
+static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle)
+{
+ if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS,
+ ec_parse_io_ports, ec)))
+ return -EINVAL;
+
+ /* Get GPE bit assignment (EC events). */
+ /* TODO: Add support for _GPE returning a package */
+ if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe)))
+ return -EINVAL;
+
+ /* Use the global lock for all EC transactions? */
+ acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
+
+ /* Find and register all query methods */
+ acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
+ acpi_ec_register_query_methods, ec, NULL);
+
+ ec->handle = handle;
+
+ printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx",
+ ec->gpe, ec->command_addr, ec->data_addr);
+
+ return 0;
+}
+
static int acpi_ec_add(struct acpi_device *device)
{
- acpi_status status = AE_OK;
struct acpi_ec *ec = NULL;
if (!device)
@@ -629,8 +701,7 @@ static int acpi_ec_add(struct acpi_device *device)
if (!ec)
return -ENOMEM;
- status = ec_parse_device(device->handle, 0, ec, NULL);
- if (status != AE_CTRL_TERMINATE) {
+ if (ec_parse_device(ec, device->handle)) {
kfree(ec);
return -EINVAL;
}
@@ -641,6 +712,8 @@ static int acpi_ec_add(struct acpi_device *device)
/* We might have incorrect info for GL at boot time */
mutex_lock(&boot_ec->lock);
boot_ec->global_lock = ec->global_lock;
+ /* Copy handlers from new ec into boot ec */
+ list_splice(&ec->list, &boot_ec->list);
mutex_unlock(&boot_ec->lock);
kfree(ec);
ec = boot_ec;
@@ -651,22 +724,24 @@ static int acpi_ec_add(struct acpi_device *device)
acpi_driver_data(device) = ec;
acpi_ec_add_fs(device);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
- acpi_device_name(device), acpi_device_bid(device),
- (u32) ec->gpe));
-
return 0;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
{
struct acpi_ec *ec;
+ struct acpi_ec_query_handler *handler;
if (!device)
return -EINVAL;
ec = acpi_driver_data(device);
+ mutex_lock(&ec->lock);
+ list_for_each_entry(handler, &ec->list, node) {
+ list_del(&handler->node);
+ kfree(handler);
+ }
+ mutex_unlock(&ec->lock);
acpi_ec_remove_fs(device);
acpi_driver_data(device) = NULL;
if (ec == first_ec)
@@ -722,15 +797,13 @@ static int ec_install_handlers(struct acpi_ec *ec)
return -ENODEV;
}
- /* EC is fully operational, allow queries */
- atomic_set(&ec->query_pending, 0);
-
return 0;
}
static int acpi_ec_start(struct acpi_device *device)
{
struct acpi_ec *ec;
+ int ret = 0;
if (!device)
return -EINVAL;
@@ -740,14 +813,14 @@ static int acpi_ec_start(struct acpi_device *device)
if (!ec)
return -EINVAL;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
- ec->gpe, ec->command_addr, ec->data_addr));
-
/* Boot EC is already working */
- if (ec == boot_ec)
- return 0;
+ if (ec != boot_ec)
+ ret = ec_install_handlers(ec);
+
+ /* EC is fully operational, allow queries */
+ atomic_set(&ec->query_pending, 0);
- return ec_install_handlers(ec);
+ return ret;
}
static int acpi_ec_stop(struct acpi_device *device, int type)
@@ -779,34 +852,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
return 0;
}
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
-{
- acpi_status status;
-
- struct acpi_ec *ec = context;
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- ec_parse_io_ports, ec);
- if (ACPI_FAILURE(status))
- return status;
-
- /* Get GPE bit assignment (EC events). */
- /* TODO: Add support for _GPE returning a package */
- status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
- if (ACPI_FAILURE(status))
- return status;
-
- /* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
-
- ec->handle = handle;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
- ec->gpe, ec->command_addr, ec->data_addr));
-
- return AE_CTRL_TERMINATE;
-}
-
int __init acpi_ec_ecdt_probe(void)
{
int ret;
@@ -825,7 +870,7 @@ int __init acpi_ec_ecdt_probe(void)
if (ACPI_FAILURE(status))
goto error;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
+ printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address;
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 3b23562e6f92..dfa5853b17f0 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -11,6 +11,8 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <acpi/acpi_drivers.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("event");
@@ -48,7 +50,6 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
static int chars_remaining = 0;
static char *ptr;
-
if (!chars_remaining) {
memset(&event, 0, sizeof(struct acpi_bus_event));
@@ -106,23 +107,161 @@ static const struct file_operations acpi_system_event_ops = {
.poll = acpi_system_poll_event,
};
+#ifdef CONFIG_NET
+unsigned int acpi_event_seqnum;
+struct acpi_genl_event {
+ acpi_device_class device_class;
+ char bus_id[15];
+ u32 type;
+ u32 data;
+};
+
+/* attributes of acpi_genl_family */
+enum {
+ ACPI_GENL_ATTR_UNSPEC,
+ ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */
+ __ACPI_GENL_ATTR_MAX,
+};
+#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
+
+/* commands supported by the acpi_genl_family */
+enum {
+ ACPI_GENL_CMD_UNSPEC,
+ ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */
+ __ACPI_GENL_CMD_MAX,
+};
+#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
+
+#define ACPI_GENL_FAMILY_NAME "acpi_event"
+#define ACPI_GENL_VERSION 0x01
+#define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group"
+
+static struct genl_family acpi_event_genl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = ACPI_GENL_FAMILY_NAME,
+ .version = ACPI_GENL_VERSION,
+ .maxattr = ACPI_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group acpi_event_mcgrp = {
+ .name = ACPI_GENL_MCAST_GROUP_NAME,
+};
+
+int acpi_bus_generate_genetlink_event(struct acpi_device *device,
+ u8 type, int data)
+{
+ struct sk_buff *skb;
+ struct nlattr *attr;
+ struct acpi_genl_event *event;
+ void *msg_header;
+ int size;
+ int result;
+
+ /* allocate memory */
+ size = nla_total_size(sizeof(struct acpi_genl_event)) +
+ nla_total_size(0);
+
+ skb = genlmsg_new(size, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ /* add the genetlink message header */
+ msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
+ &acpi_event_genl_family, 0,
+ ACPI_GENL_CMD_EVENT);
+ if (!msg_header) {
+ nlmsg_free(skb);
+ return -ENOMEM;
+ }
+
+ /* fill the data */
+ attr =
+ nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
+ sizeof(struct acpi_genl_event));
+ if (!attr) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ event = nla_data(attr);
+ if (!event) {
+ nlmsg_free(skb);
+ return -EINVAL;
+ }
+
+ memset(event, 0, sizeof(struct acpi_genl_event));
+
+ strcpy(event->device_class, device->pnp.device_class);
+ strcpy(event->bus_id, device->dev.bus_id);
+ event->type = type;
+ event->data = data;
+
+ /* send multicast genetlink message */
+ result = genlmsg_end(skb, msg_header);
+ if (result < 0) {
+ nlmsg_free(skb);
+ return result;
+ }
+
+ result =
+ genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Failed to send a Genetlink message!\n"));
+ return 0;
+}
+
+static int acpi_event_genetlink_init(void)
+{
+ int result;
+
+ result = genl_register_family(&acpi_event_genl_family);
+ if (result)
+ return result;
+
+ result = genl_register_mc_group(&acpi_event_genl_family,
+ &acpi_event_mcgrp);
+ if (result)
+ genl_unregister_family(&acpi_event_genl_family);
+
+ return result;
+}
+
+#else
+int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type,
+ int data)
+{
+ return 0;
+}
+
+static int acpi_event_genetlink_init(void)
+{
+ return -ENODEV;
+}
+#endif
+
static int __init acpi_event_init(void)
{
struct proc_dir_entry *entry;
int error = 0;
-
if (acpi_disabled)
return 0;
+ /* create genetlink for acpi event */
+ error = acpi_event_genetlink_init();
+ if (error)
+ printk(KERN_WARNING PREFIX
+ "Failed to create genetlink family for ACPI event\n");
+
/* 'event' [R] */
entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
if (entry)
entry->proc_fops = &acpi_system_event_ops;
- else {
- error = -ENODEV;
- }
- return error;
+ else
+ return -ENODEV;
+
+ return 0;
}
-subsys_initcall(acpi_event_init);
+fs_initcall(acpi_event_init);
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 902c287b3a4f..361ebe6c4a6f 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -586,6 +586,10 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
if (gpe_xrupt->previous) {
gpe_xrupt->previous->next = gpe_xrupt->next;
+ } else {
+ /* No previous, update list head */
+
+ acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
}
if (gpe_xrupt->next) {
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 400d90fca966..23ee7bc4a705 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -284,6 +284,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
}
if (!pci_device_node) {
+ ACPI_FREE(pci_id);
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 41427a41f620..4893e256e399 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -16,7 +16,7 @@
#if ACPI_GLUE_DEBUG
#define DBG(x...) printk(PREFIX x)
#else
-#define DBG(x...)
+#define DBG(x...) do { } while(0)
#endif
static LIST_HEAD(bus_type_list);
static DECLARE_RWSEM(bus_type_sem);
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 0c9f15c54e8c..ab04d848b19d 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -36,13 +36,11 @@
ACPI_MODULE_NAME("numa");
static nodemask_t nodes_found_map = NODE_MASK_NONE;
-#define PXM_INVAL -1
-#define NID_INVAL -1
/* maps to convert between proximity domain and logical node ID */
-static int pxm_to_node_map[MAX_PXM_DOMAINS]
+static int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
= { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
-static int node_to_pxm_map[MAX_NUMNODES]
+static int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
int pxm_to_node(int pxm)
@@ -59,6 +57,12 @@ int node_to_pxm(int node)
return node_to_pxm_map[node];
}
+void __acpi_map_pxm_to_node(int pxm, int node)
+{
+ pxm_to_node_map[pxm] = node;
+ node_to_pxm_map[node] = pxm;
+}
+
int acpi_map_pxm_to_node(int pxm)
{
int node = pxm_to_node_map[pxm];
@@ -67,8 +71,7 @@ int acpi_map_pxm_to_node(int pxm)
if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
return NID_INVAL;
node = first_unset_node(nodes_found_map);
- pxm_to_node_map[pxm] = node;
- node_to_pxm_map[node] = pxm;
+ __acpi_map_pxm_to_node(pxm, node);
node_set(node, nodes_found_map);
}
@@ -83,7 +86,8 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
node_clear(node, nodes_found_map);
}
-void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
+static void __init
+acpi_table_print_srat_entry(struct acpi_subtable_header *header)
{
ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -200,7 +204,7 @@ static int __init acpi_parse_srat(struct acpi_table_header *table)
return 0;
}
-int __init
+static int __init
acpi_table_parse_srat(enum acpi_srat_type id,
acpi_table_entry_handler handler, unsigned int max_entries)
{
@@ -211,14 +215,13 @@ acpi_table_parse_srat(enum acpi_srat_type id,
int __init acpi_numa_init(void)
{
- int result;
-
/* SRAT: Static Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
- result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
- acpi_parse_processor_affinity,
- NR_CPUS);
- result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
+ acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
+ acpi_parse_processor_affinity, NR_CPUS);
+ acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+ acpi_parse_memory_affinity,
+ NR_NODE_MEMBLKS);
}
/* SLIT: System Locality Information Table */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2e7ba615d760..12c09fafce9a 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,13 +77,7 @@ static struct workqueue_struct *kacpi_notify_wq;
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
static char osi_additional_string[OSI_STRING_LENGTH_MAX];
-#define OSI_LINUX_ENABLED
-#ifdef OSI_LINUX_ENABLED
-int osi_linux = 1; /* enable _OSI(Linux) by default */
-#else
-int osi_linux; /* disable _OSI(Linux) by default */
-#endif
-
+static int osi_linux; /* disable _OSI(Linux) by default */
#ifdef CONFIG_DMI
static struct __initdata dmi_system_id acpi_osl_dmi_table[];
@@ -1098,7 +1092,7 @@ void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
acpi_status
acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
{
- *cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
+ *cache = kmem_cache_create(name, size, 0, 0, NULL);
if (*cache == NULL)
return AE_ERROR;
else
@@ -1183,17 +1177,10 @@ acpi_os_validate_interface (char *interface)
if (!strcmp("Linux", interface)) {
printk(KERN_WARNING PREFIX
"System BIOS is requesting _OSI(Linux)\n");
-#ifdef OSI_LINUX_ENABLED
- printk(KERN_WARNING PREFIX
- "Please test with \"acpi_osi=!Linux\"\n"
- "Please send dmidecode "
- "to linux-acpi@vger.kernel.org\n");
-#else
printk(KERN_WARNING PREFIX
"If \"acpi_osi=Linux\" works better,\n"
"Please send dmidecode "
"to linux-acpi@vger.kernel.org\n");
-#endif
if(osi_linux)
return AE_OK;
}
@@ -1227,36 +1214,14 @@ acpi_os_validate_address (
}
#ifdef CONFIG_DMI
-#ifdef OSI_LINUX_ENABLED
-static int dmi_osi_not_linux(struct dmi_system_id *d)
-{
- printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident);
- enable_osi_linux(0);
- return 0;
-}
-#else
static int dmi_osi_linux(struct dmi_system_id *d)
{
- printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident);
+ printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
enable_osi_linux(1);
return 0;
}
-#endif
static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-#ifdef OSI_LINUX_ENABLED
- /*
- * Boxes that need NOT _OSI(Linux)
- */
- {
- .callback = dmi_osi_not_linux,
- .ident = "Toshiba Satellite P100",
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"),
- DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"),
- },
- },
-#else
/*
* Boxes that need _OSI(Linux)
*/
@@ -1268,7 +1233,6 @@ static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
},
},
-#endif
{}
};
#endif /* CONFIG_DMI */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index acc594771379..3448edd61dc4 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -733,7 +733,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
/* query and set link->irq.active */
acpi_pci_link_get_current(link);
- printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
+ printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
acpi_device_bid(device));
for (i = 0; i < link->irq.possible_count; i++) {
if (link->irq.active == link->irq.possible[i]) {
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index f7de02a6f497..81aceb5da7c7 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -66,6 +66,7 @@
#define ACPI_PROCESSOR_FILE_LIMIT "limit"
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
+#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
@@ -84,6 +85,8 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
+extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
+
static struct acpi_driver acpi_processor_driver = {
.name = "processor",
@@ -115,7 +118,6 @@ struct acpi_processor_errata errata __read_mostly;
static int acpi_processor_errata_piix4(struct pci_dev *dev)
{
- u8 rev = 0;
u8 value1 = 0;
u8 value2 = 0;
@@ -127,9 +129,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
* Note that 'dev' references the PIIX4 ACPI Controller.
*/
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-
- switch (rev) {
+ switch (dev->revision) {
case 0:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
break;
@@ -147,7 +147,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
break;
}
- switch (rev) {
+ switch (dev->revision) {
case 0: /* PIIX4 A-step */
case 1: /* PIIX4 B-step */
@@ -699,6 +699,9 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
acpi_processor_cst_has_changed(pr);
acpi_bus_generate_event(device, event, 0);
break;
+ case ACPI_PROCESSOR_NOTIFY_THROTTLING:
+ acpi_processor_tstate_has_changed(pr);
+ acpi_bus_generate_event(device, event, 0);
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 80ffc7829916..a898991f77cb 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -475,7 +475,7 @@ static void acpi_processor_idle(void)
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C2, so notify users */
mark_tsc_unstable("possible TSC halt in C2");
#endif
@@ -490,7 +490,17 @@ static void acpi_processor_idle(void)
case ACPI_STATE_C3:
- if (pr->flags.bm_check) {
+ /*
+ * disable bus master
+ * bm_check implies we need ARB_DIS
+ * !bm_check implies we need cache flush
+ * bm_control implies whether we can do ARB_DIS
+ *
+ * That leaves a case where bm_check is set and bm_control is
+ * not set. In that case we cannot do much, we enter C3
+ * without doing anything.
+ */
+ if (pr->flags.bm_check && pr->flags.bm_control) {
if (atomic_inc_return(&c3_cpu_count) ==
num_online_cpus()) {
/*
@@ -499,7 +509,7 @@ static void acpi_processor_idle(void)
*/
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
}
- } else {
+ } else if (!pr->flags.bm_check) {
/* SMP with no shared cache... Invalidate cache */
ACPI_FLUSH_CPU_CACHE();
}
@@ -511,13 +521,13 @@ static void acpi_processor_idle(void)
acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
- if (pr->flags.bm_check) {
+ if (pr->flags.bm_check && pr->flags.bm_control) {
/* Enable bus master arbitration */
atomic_dec(&c3_cpu_count);
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
}
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
/* TSC halts in C3, so notify users */
mark_tsc_unstable("TSC halts in C3");
#endif
@@ -961,9 +971,9 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
if (pr->flags.bm_check) {
/* bus mastering control is necessary */
if (!pr->flags.bm_control) {
+ /* In this case we enter C3 without bus mastering */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 support requires bus mastering control\n"));
- return;
+ "C3 support without bus mastering control\n"));
}
} else {
/*
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index b33486009f41..3f55d1f90c11 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -44,17 +44,231 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_throttling");
+static int acpi_processor_get_throttling(struct acpi_processor *pr);
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+
+static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
+{
+ acpi_status status = 0;
+ unsigned long tpc = 0;
+
+ if (!pr)
+ return -EINVAL;
+ status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
+ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
+ return -ENODEV;
+ }
+ pr->throttling_platform_limit = (int)tpc;
+ return 0;
+}
+
+int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
+{
+ return acpi_processor_get_platform_limit(pr);
+}
+
+/* --------------------------------------------------------------------------
+ _PTC, _TSS, _TSD support
+ -------------------------------------------------------------------------- */
+static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *ptc = NULL;
+ union acpi_object obj = { 0 };
+
+ status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
+ return -ENODEV;
+ }
+
+ ptc = (union acpi_object *)buffer.pointer;
+ if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
+ || (ptc->package.count != 2)) {
+ printk(KERN_ERR PREFIX "Invalid _PTC data\n");
+ result = -EFAULT;
+ goto end;
+ }
+
+ /*
+ * control_register
+ */
+
+ obj = ptc->package.elements[0];
+
+ if ((obj.type != ACPI_TYPE_BUFFER)
+ || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+ || (obj.buffer.pointer == NULL)) {
+ printk(KERN_ERR PREFIX
+ "Invalid _PTC data (control_register)\n");
+ result = -EFAULT;
+ goto end;
+ }
+ memcpy(&pr->throttling.control_register, obj.buffer.pointer,
+ sizeof(struct acpi_ptc_register));
+
+ /*
+ * status_register
+ */
+
+ obj = ptc->package.elements[1];
+
+ if ((obj.type != ACPI_TYPE_BUFFER)
+ || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+ || (obj.buffer.pointer == NULL)) {
+ printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n");
+ result = -EFAULT;
+ goto end;
+ }
+
+ memcpy(&pr->throttling.status_register, obj.buffer.pointer,
+ sizeof(struct acpi_ptc_register));
+
+ end:
+ kfree(buffer.pointer);
+
+ return result;
+}
+static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+ struct acpi_buffer state = { 0, NULL };
+ union acpi_object *tss = NULL;
+ int i;
+
+ status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
+ return -ENODEV;
+ }
+
+ tss = buffer.pointer;
+ if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
+ printk(KERN_ERR PREFIX "Invalid _TSS data\n");
+ result = -EFAULT;
+ goto end;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
+ tss->package.count));
+
+ pr->throttling.state_count = tss->package.count;
+ pr->throttling.states_tss =
+ kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count,
+ GFP_KERNEL);
+ if (!pr->throttling.states_tss) {
+ result = -ENOMEM;
+ goto end;
+ }
+
+ for (i = 0; i < pr->throttling.state_count; i++) {
+
+ struct acpi_processor_tx_tss *tx =
+ (struct acpi_processor_tx_tss *)&(pr->throttling.
+ states_tss[i]);
+
+ state.length = sizeof(struct acpi_processor_tx_tss);
+ state.pointer = tx;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
+
+ status = acpi_extract_package(&(tss->package.elements[i]),
+ &format, &state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data"));
+ result = -EFAULT;
+ kfree(pr->throttling.states_tss);
+ goto end;
+ }
+
+ if (!tx->freqpercentage) {
+ printk(KERN_ERR PREFIX
+ "Invalid _TSS data: freq is zero\n");
+ result = -EFAULT;
+ kfree(pr->throttling.states_tss);
+ goto end;
+ }
+ }
+
+ end:
+ kfree(buffer.pointer);
+
+ return result;
+}
+static int acpi_processor_get_tsd(struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+ struct acpi_buffer state = { 0, NULL };
+ union acpi_object *tsd = NULL;
+ struct acpi_tsd_package *pdomain;
+
+ status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ return -ENODEV;
+ }
+
+ tsd = buffer.pointer;
+ if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (tsd->package.count != 1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ pdomain = &(pr->throttling.domain_info);
+
+ state.length = sizeof(struct acpi_tsd_package);
+ state.pointer = pdomain;
+
+ status = acpi_extract_package(&(tsd->package.elements[0]),
+ &format, &state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ end:
+ kfree(buffer.pointer);
+ return result;
+}
+
/* --------------------------------------------------------------------------
Throttling Control
-------------------------------------------------------------------------- */
-static int acpi_processor_get_throttling(struct acpi_processor *pr)
+static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
{
int state = 0;
u32 value = 0;
u32 duty_mask = 0;
u32 duty_value = 0;
-
if (!pr)
return -EINVAL;
@@ -94,13 +308,115 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
return 0;
}
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+static int acpi_read_throttling_status(struct acpi_processor_throttling
+ *throttling)
+{
+ int value = -1;
+ switch (throttling->status_register.space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ acpi_os_read_port((acpi_io_address) throttling->status_register.
+ address, &value,
+ (u32) throttling->status_register.bit_width *
+ 8);
+ break;
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ printk(KERN_ERR PREFIX
+ "HARDWARE addr space,NOT supported yet\n");
+ break;
+ default:
+ printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+ (u32) (throttling->status_register.space_id));
+ }
+ return value;
+}
+
+static int acpi_write_throttling_state(struct acpi_processor_throttling
+ *throttling, int value)
+{
+ int ret = -1;
+
+ switch (throttling->control_register.space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ acpi_os_write_port((acpi_io_address) throttling->
+ control_register.address, value,
+ (u32) throttling->control_register.
+ bit_width * 8);
+ ret = 0;
+ break;
+ case ACPI_ADR_SPACE_FIXED_HARDWARE:
+ printk(KERN_ERR PREFIX
+ "HARDWARE addr space,NOT supported yet\n");
+ break;
+ default:
+ printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+ (u32) (throttling->control_register.space_id));
+ }
+ return ret;
+}
+
+static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
+{
+ int i;
+
+ for (i = 0; i < pr->throttling.state_count; i++) {
+ struct acpi_processor_tx_tss *tx =
+ (struct acpi_processor_tx_tss *)&(pr->throttling.
+ states_tss[i]);
+ if (tx->control == value)
+ break;
+ }
+ if (i > pr->throttling.state_count)
+ i = -1;
+ return i;
+}
+
+static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
+{
+ int value = -1;
+ if (state >= 0 && state <= pr->throttling.state_count) {
+ struct acpi_processor_tx_tss *tx =
+ (struct acpi_processor_tx_tss *)&(pr->throttling.
+ states_tss[state]);
+ value = tx->control;
+ }
+ return value;
+}
+
+static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
+{
+ int state = 0;
+ u32 value = 0;
+
+ if (!pr)
+ return -EINVAL;
+
+ if (!pr->flags.throttling)
+ return -ENODEV;
+
+ pr->throttling.state = 0;
+ local_irq_disable();
+ value = acpi_read_throttling_status(&pr->throttling);
+ if (value >= 0) {
+ state = acpi_get_throttling_state(pr, value);
+ pr->throttling.state = state;
+ }
+ local_irq_enable();
+
+ return 0;
+}
+
+static int acpi_processor_get_throttling(struct acpi_processor *pr)
+{
+ return pr->throttling.acpi_processor_get_throttling(pr);
+}
+
+static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
+ int state)
{
u32 value = 0;
u32 duty_mask = 0;
u32 duty_value = 0;
-
if (!pr)
return -EINVAL;
@@ -113,6 +429,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
if (state == pr->throttling.state)
return 0;
+ if (state < pr->throttling_platform_limit)
+ return -EPERM;
/*
* Calculate the duty_value and duty_mask.
*/
@@ -165,12 +483,51 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
return 0;
}
+static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
+ int state)
+{
+ u32 value = 0;
+
+ if (!pr)
+ return -EINVAL;
+
+ if ((state < 0) || (state > (pr->throttling.state_count - 1)))
+ return -EINVAL;
+
+ if (!pr->flags.throttling)
+ return -ENODEV;
+
+ if (state == pr->throttling.state)
+ return 0;
+
+ if (state < pr->throttling_platform_limit)
+ return -EPERM;
+
+ local_irq_disable();
+
+ value = acpi_get_throttling_value(pr, state);
+ if (value >= 0) {
+ acpi_write_throttling_state(&pr->throttling, value);
+ pr->throttling.state = state;
+ }
+ local_irq_enable();
+
+ return 0;
+}
+
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+{
+ return pr->throttling.acpi_processor_set_throttling(pr, state);
+}
+
int acpi_processor_get_throttling_info(struct acpi_processor *pr)
{
int result = 0;
int step = 0;
int i = 0;
-
+ int no_ptc = 0;
+ int no_tss = 0;
+ int no_tsd = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -182,6 +539,21 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
return -EINVAL;
/* TBD: Support ACPI 2.0 objects */
+ no_ptc = acpi_processor_get_throttling_control(pr);
+ no_tss = acpi_processor_get_throttling_states(pr);
+ no_tsd = acpi_processor_get_tsd(pr);
+
+ if (no_ptc || no_tss) {
+ pr->throttling.acpi_processor_get_throttling =
+ &acpi_processor_get_throttling_fadt;
+ pr->throttling.acpi_processor_set_throttling =
+ &acpi_processor_set_throttling_fadt;
+ } else {
+ pr->throttling.acpi_processor_get_throttling =
+ &acpi_processor_get_throttling_ptc;
+ pr->throttling.acpi_processor_set_throttling =
+ &acpi_processor_set_throttling_ptc;
+ }
if (!pr->throttling.address) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
@@ -262,7 +634,6 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
int i = 0;
int result = 0;
-
if (!pr)
goto end;
@@ -280,15 +651,25 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
}
seq_printf(seq, "state count: %d\n"
- "active state: T%d\n",
- pr->throttling.state_count, pr->throttling.state);
+ "active state: T%d\n"
+ "state available: T%d to T%d\n",
+ pr->throttling.state_count, pr->throttling.state,
+ pr->throttling_platform_limit,
+ pr->throttling.state_count - 1);
seq_puts(seq, "states:\n");
- for (i = 0; i < pr->throttling.state_count; i++)
- seq_printf(seq, " %cT%d: %02d%%\n",
- (i == pr->throttling.state ? '*' : ' '), i,
- (pr->throttling.states[i].performance ? pr->
- throttling.states[i].performance / 10 : 0));
+ if (acpi_processor_get_throttling == acpi_processor_get_throttling_fadt)
+ for (i = 0; i < pr->throttling.state_count; i++)
+ seq_printf(seq, " %cT%d: %02d%%\n",
+ (i == pr->throttling.state ? '*' : ' '), i,
+ (pr->throttling.states[i].performance ? pr->
+ throttling.states[i].performance / 10 : 0));
+ else
+ for (i = 0; i < pr->throttling.state_count; i++)
+ seq_printf(seq, " %cT%d: %02d%%\n",
+ (i == pr->throttling.state ? '*' : ' '), i,
+ (int)pr->throttling.states_tss[i].
+ freqpercentage);
end:
return 0;
@@ -301,7 +682,7 @@ static int acpi_processor_throttling_open_fs(struct inode *inode,
PDE(inode)->data);
}
-static ssize_t acpi_processor_write_throttling(struct file * file,
+static ssize_t acpi_processor_write_throttling(struct file *file,
const char __user * buffer,
size_t count, loff_t * data)
{
@@ -310,7 +691,6 @@ static ssize_t acpi_processor_write_throttling(struct file * file,
struct acpi_processor *pr = m->private;
char state_string[12] = { '\0' };
-
if (!pr || (count > sizeof(state_string) - 1))
return -EINVAL;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index c1bae106833c..974d00ccfe84 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -127,7 +127,7 @@ static int acpi_sbs_resume(struct acpi_device *device);
static struct acpi_driver acpi_sbs_driver = {
.name = "sbs",
.class = ACPI_SBS_CLASS,
- .ids = ACPI_SBS_HID,
+ .ids = "ACPI0001,ACPI0005",
.ops = {
.add = acpi_sbs_add,
.remove = acpi_sbs_remove,
@@ -176,10 +176,8 @@ struct acpi_battery {
};
struct acpi_sbs {
- acpi_handle handle;
int base;
struct acpi_device *device;
- struct acpi_ec_smbus *smbus;
struct mutex mutex;
int sbsm_present;
int sbsm_batteries_supported;
@@ -511,7 +509,7 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
"acpi_sbs_read_word() failed"));
goto end;
}
-
+ sbs->sbsm_present = 1;
sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
end:
@@ -1630,13 +1628,12 @@ static int acpi_sbs_add(struct acpi_device *device)
{
struct acpi_sbs *sbs = NULL;
int result = 0, remove_result = 0;
- unsigned long sbs_obj;
int id;
acpi_status status = AE_OK;
unsigned long val;
status =
- acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+ acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
return -EIO;
@@ -1653,7 +1650,7 @@ static int acpi_sbs_add(struct acpi_device *device)
sbs_mutex_lock(sbs);
- sbs->base = (val & 0xff00ull) >> 8;
+ sbs->base = 0xff & (val >> 8);
sbs->device = device;
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
@@ -1665,24 +1662,10 @@ static int acpi_sbs_add(struct acpi_device *device)
ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
goto end;
}
- status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
- if (status) {
- ACPI_EXCEPTION((AE_INFO, status,
- "acpi_evaluate_integer() failed"));
- result = -EIO;
- goto end;
- }
- if (sbs_obj > 0) {
- result = acpi_sbsm_get_info(sbs);
- if (result) {
- ACPI_EXCEPTION((AE_INFO, AE_ERROR,
- "acpi_sbsm_get_info() failed"));
- goto end;
- }
- sbs->sbsm_present = 1;
- }
- if (sbs->sbsm_present == 0) {
+ acpi_sbsm_get_info(sbs);
+
+ if (!sbs->sbsm_present) {
result = acpi_battery_add(sbs, 0);
if (result) {
ACPI_EXCEPTION((AE_INFO, AE_ERROR,
@@ -1702,8 +1685,6 @@ static int acpi_sbs_add(struct acpi_device *device)
}
}
- sbs->handle = device->handle;
-
init_timer(&sbs->update_timer);
result = acpi_check_update_proc(sbs);
if (result)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index bc7e16ec8393..3279e72a94f8 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -210,17 +210,28 @@ static void acpi_hibernation_finish(void)
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+}
- if (init_8259A_after_S1) {
- printk("Broken toshiba laptop -> kicking interrupts\n");
- init_8259A(0);
- }
+static int acpi_hibernation_pre_restore(void)
+{
+ acpi_status status;
+
+ status = acpi_hw_disable_all_gpes();
+
+ return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_restore_cleanup(void)
+{
+ acpi_hw_enable_all_runtime_gpes();
}
static struct hibernation_ops acpi_hibernation_ops = {
.prepare = acpi_hibernation_prepare,
.enter = acpi_hibernation_enter,
.finish = acpi_hibernation_finish,
+ .pre_restore = acpi_hibernation_pre_restore,
+ .restore_cleanup = acpi_hibernation_restore_cleanup,
};
#endif /* CONFIG_SOFTWARE_SUSPEND */
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
index d9801eff6489..39e40d56b034 100644
--- a/drivers/acpi/sleep/poweroff.c
+++ b/drivers/acpi/sleep/poweroff.c
@@ -39,7 +39,13 @@ int acpi_sleep_prepare(u32 acpi_state)
#ifdef CONFIG_PM
-void acpi_power_off(void)
+static void acpi_power_off_prepare(void)
+{
+ /* Prepare to power off the system */
+ acpi_sleep_prepare(ACPI_STATE_S5);
+}
+
+static void acpi_power_off(void)
{
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
printk("%s called\n", __FUNCTION__);
@@ -48,30 +54,6 @@ void acpi_power_off(void)
acpi_enter_sleep_state(ACPI_STATE_S5);
}
-static int acpi_shutdown(struct sys_device *x)
-{
- switch (system_state) {
- case SYSTEM_POWER_OFF:
- /* Prepare to power off the system */
- return acpi_sleep_prepare(ACPI_STATE_S5);
- case SYSTEM_SUSPEND_DISK:
- /* Prepare to suspend the system to disk */
- return acpi_sleep_prepare(ACPI_STATE_S4);
- default:
- return 0;
- }
-}
-
-static struct sysdev_class acpi_sysclass = {
- set_kset_name("acpi"),
- .shutdown = acpi_shutdown
-};
-
-static struct sys_device device_acpi = {
- .id = 0,
- .cls = &acpi_sysclass,
-};
-
static int acpi_poweroff_init(void)
{
if (!acpi_disabled) {
@@ -81,13 +63,8 @@ static int acpi_poweroff_init(void)
status =
acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
if (ACPI_SUCCESS(status)) {
- int error;
- error = sysdev_class_register(&acpi_sysclass);
- if (!error)
- error = sysdev_register(&device_acpi);
- if (!error)
- pm_power_off = acpi_power_off;
- return error;
+ pm_power_off_prepare = acpi_power_off_prepare;
+ pm_power_off = acpi_power_off;
}
}
return 0;
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 83a8d3097904..edee2806e37b 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -39,15 +39,12 @@ ACPI_MODULE_NAME("system");
#define ACPI_SYSTEM_CLASS "system"
#define ACPI_SYSTEM_DEVICE_NAME "System"
-#define ACPI_SYSTEM_FILE_INFO "info"
-#define ACPI_SYSTEM_FILE_EVENT "event"
-#define ACPI_SYSTEM_FILE_DSDT "dsdt"
-#define ACPI_SYSTEM_FILE_FADT "fadt"
/*
* Make ACPICA version work as module param
*/
-static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
+{
int result;
result = sprintf(buffer, "%x", ACPI_CA_VERSION);
@@ -58,9 +55,126 @@ static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
/* --------------------------------------------------------------------------
+ FS Interface (/sys)
+ -------------------------------------------------------------------------- */
+static LIST_HEAD(acpi_table_attr_list);
+static struct kobject tables_kobj;
+
+struct acpi_table_attr {
+ struct bin_attribute attr;
+ char name[8];
+ int instance;
+ struct list_head node;
+};
+
+static ssize_t acpi_table_show(struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t offset, size_t count)
+{
+ struct acpi_table_attr *table_attr =
+ container_of(bin_attr, struct acpi_table_attr, attr);
+ struct acpi_table_header *table_header = NULL;
+ acpi_status status;
+ ssize_t ret_count = count;
+
+ status =
+ acpi_get_table(table_attr->name, table_attr->instance,
+ &table_header);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ if (offset >= table_header->length) {
+ ret_count = 0;
+ goto end;
+ }
+
+ if (offset + ret_count > table_header->length)
+ ret_count = table_header->length - offset;
+
+ memcpy(buf, ((char *)table_header) + offset, ret_count);
+
+ end:
+ return ret_count;
+}
+
+static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
+ struct acpi_table_header *table_header)
+{
+ struct acpi_table_header *header = NULL;
+ struct acpi_table_attr *attr = NULL;
+
+ memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE);
+
+ list_for_each_entry(attr, &acpi_table_attr_list, node) {
+ if (!memcmp(table_header->signature, attr->name,
+ ACPI_NAME_SIZE))
+ if (table_attr->instance < attr->instance)
+ table_attr->instance = attr->instance;
+ }
+ table_attr->instance++;
+
+ if (table_attr->instance > 1 || (table_attr->instance == 1 &&
+ !acpi_get_table(table_header->
+ signature, 2,
+ &header)))
+ sprintf(table_attr->name + 4, "%d", table_attr->instance);
+
+ table_attr->attr.size = 0;
+ table_attr->attr.read = acpi_table_show;
+ table_attr->attr.attr.name = table_attr->name;
+ table_attr->attr.attr.mode = 0444;
+ table_attr->attr.attr.owner = THIS_MODULE;
+
+ return;
+}
+
+static int acpi_system_sysfs_init(void)
+{
+ struct acpi_table_attr *table_attr;
+ struct acpi_table_header *table_header = NULL;
+ int table_index = 0;
+ int result;
+
+ tables_kobj.parent = &acpi_subsys.kobj;
+ kobject_set_name(&tables_kobj, "tables");
+ result = kobject_register(&tables_kobj);
+ if (result)
+ return result;
+
+ do {
+ result = acpi_get_table_by_index(table_index, &table_header);
+ if (!result) {
+ table_index++;
+ table_attr = NULL;
+ table_attr =
+ kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
+ if (!table_attr)
+ return -ENOMEM;
+
+ acpi_table_attr_init(table_attr, table_header);
+ result =
+ sysfs_create_bin_file(&tables_kobj,
+ &table_attr->attr);
+ if (result) {
+ kfree(table_attr);
+ return result;
+ } else
+ list_add_tail(&table_attr->node,
+ &acpi_table_attr_list);
+ }
+ } while (!result);
+
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_INFO "info"
+#define ACPI_SYSTEM_FILE_EVENT "event"
+#define ACPI_SYSTEM_FILE_DSDT "dsdt"
+#define ACPI_SYSTEM_FILE_FADT "fadt"
static int acpi_system_read_info(struct seq_file *seq, void *offset)
{
@@ -80,7 +194,6 @@ static const struct file_operations acpi_system_info_ops = {
.llseek = seq_lseek,
.release = single_release,
};
-#endif
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
@@ -97,13 +210,11 @@ acpi_system_read_dsdt(struct file *file,
struct acpi_table_header *dsdt = NULL;
ssize_t res;
-
status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
return -ENODEV;
- res = simple_read_from_buffer(buffer, count, ppos,
- dsdt, dsdt->length);
+ res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length);
return res;
}
@@ -123,28 +234,21 @@ acpi_system_read_fadt(struct file *file,
struct acpi_table_header *fadt = NULL;
ssize_t res;
-
status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
if (ACPI_FAILURE(status))
return -ENODEV;
- res = simple_read_from_buffer(buffer, count, ppos,
- fadt, fadt->length);
+ res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length);
return res;
}
-static int __init acpi_system_init(void)
+static int acpi_system_procfs_init(void)
{
struct proc_dir_entry *entry;
int error = 0;
char *name;
-
- if (acpi_disabled)
- return 0;
-
-#ifdef CONFIG_ACPI_PROCFS
/* 'info' [R] */
name = ACPI_SYSTEM_FILE_INFO;
entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -153,7 +257,6 @@ static int __init acpi_system_init(void)
else {
entry->proc_fops = &acpi_system_info_ops;
}
-#endif
/* 'dsdt' [R] */
name = ACPI_SYSTEM_FILE_DSDT;
@@ -177,12 +280,32 @@ static int __init acpi_system_init(void)
Error:
remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
-#ifdef CONFIG_ACPI_PROCFS
remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
-#endif
error = -EFAULT;
goto Done;
}
+#else
+static int acpi_system_procfs_init(void)
+{
+ return 0;
+}
+#endif
+
+static int __init acpi_system_init(void)
+{
+ int result = 0;
+
+ if (acpi_disabled)
+ return 0;
+
+ result = acpi_system_procfs_init();
+ if (result)
+ return result;
+
+ result = acpi_system_sysfs_init();
+
+ return result;
+}
subsys_initcall(acpi_system_init);
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 1285e91474fb..002bb33003af 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -211,14 +211,17 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
* DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
* Performs validation on some important FADT fields.
*
+ * NOTE: We create a local copy of the FADT regardless of the version.
+ *
******************************************************************************/
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
{
/*
- * Check if the FADT is larger than what we know about (ACPI 2.0 version).
- * Truncate the table, but make some noise.
+ * Check if the FADT is larger than the largest table that we expect
+ * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
+ * a warning.
*/
if (length > sizeof(struct acpi_table_fadt)) {
ACPI_WARNING((AE_INFO,
@@ -227,10 +230,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
sizeof(struct acpi_table_fadt)));
}
- /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+ /* Clear the entire local FADT */
ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
+ /* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */
+
ACPI_MEMCPY(&acpi_gbl_FADT, table,
ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
@@ -251,7 +256,7 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
* RETURN: None
*
* DESCRIPTION: Converts all versions of the FADT to a common internal format.
- * -> Expand all 32-bit addresses to 64-bit.
+ * Expand all 32-bit addresses to 64-bit.
*
* NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
* and must contain a copy of the actual FADT.
@@ -292,8 +297,23 @@ static void acpi_tb_convert_fadt(void)
}
/*
- * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
- * structures as necessary.
+ * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
+ * should be zero are indeed zero. This will workaround BIOSs that
+ * inadvertently place values in these fields.
+ *
+ * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
+ * offset 45, 55, 95, and the word located at offset 109, 110.
+ */
+ if (acpi_gbl_FADT.header.revision < 3) {
+ acpi_gbl_FADT.preferred_profile = 0;
+ acpi_gbl_FADT.pstate_control = 0;
+ acpi_gbl_FADT.cst_control = 0;
+ acpi_gbl_FADT.boot_flags = 0;
+ }
+
+ /*
+ * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X"
+ * generic address structures as necessary.
*/
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
target =
@@ -349,18 +369,6 @@ static void acpi_tb_convert_fadt(void)
acpi_gbl_FADT.xpm1a_event_block.space_id;
}
-
- /*
- * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
- * are indeed zero. This will workaround BIOSs that inadvertently placed
- * values in these fields.
- */
- if (acpi_gbl_FADT.header.revision < 3) {
- acpi_gbl_FADT.preferred_profile = 0;
- acpi_gbl_FADT.pstate_control = 0;
- acpi_gbl_FADT.cst_control = 0;
- acpi_gbl_FADT.boot_flags = 0;
- }
}
/******************************************************************************
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 88a6fc7fd271..58f1338981bc 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -40,6 +40,7 @@
#include <linux/jiffies.h>
#include <linux/kmod.h>
#include <linux/seq_file.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -59,7 +60,6 @@
#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
#define ACPI_THERMAL_NOTIFY_HOT 0xF1
#define ACPI_THERMAL_MODE_ACTIVE 0x00
-#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
#define ACPI_THERMAL_MAX_ACTIVE 10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
@@ -419,26 +419,6 @@ static int acpi_thermal_get_devices(struct acpi_thermal *tz)
return 0;
}
-static int acpi_thermal_call_usermode(char *path)
-{
- char *argv[2] = { NULL, NULL };
- char *envp[3] = { NULL, NULL, NULL };
-
-
- if (!path)
- return -EINVAL;
-
- argv[0] = path;
-
- /* minimal command environment */
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
- call_usermodehelper(argv[0], argv, envp, 0);
-
- return 0;
-}
-
static int acpi_thermal_critical(struct acpi_thermal *tz)
{
if (!tz || !tz->trips.critical.flags.valid)
@@ -456,7 +436,7 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
- acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+ orderly_poweroff(true);
return 0;
}
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 8ec6f8e48138..f112af433e36 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -62,16 +62,13 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
static char *acpi_interfaces_supported[] = {
/* Operating System Vendor Strings */
- "Windows 2000",
- "Windows 2001",
- "Windows 2001 SP0",
- "Windows 2001 SP1",
- "Windows 2001 SP2",
- "Windows 2001 SP3",
- "Windows 2001 SP4",
- "Windows 2001.1",
- "Windows 2001.1 SP1", /* Added 03/2006 */
- "Windows 2006", /* Added 03/2006 */
+ "Windows 2000", /* Windows 2000 */
+ "Windows 2001", /* Windows XP */
+ "Windows 2001 SP1", /* Windows XP SP1 */
+ "Windows 2001 SP2", /* Windows XP SP2 */
+ "Windows 2001.1", /* Windows Server 2003 */
+ "Windows 2001.1 SP1", /* Windows Server 2003 SP1 - Added 03/2006 */
+ "Windows 2006", /* Windows Vista - Added 03/2006 */
/* Feature Group Strings */
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 00d25b347255..04ea697f72bf 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -33,6 +33,7 @@
#include <linux/seq_file.h>
#include <linux/backlight.h>
+#include <linux/video_output.h>
#include <asm/uaccess.h>
#include <acpi/acpi_bus.h>
@@ -169,6 +170,7 @@ struct acpi_video_device {
struct acpi_device *dev;
struct acpi_video_device_brightness *brightness;
struct backlight_device *backlight;
+ struct output_device *output_dev;
};
/* bus */
@@ -272,13 +274,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event);
static void acpi_video_switch_brightness(struct acpi_video_device *device,
int event);
+static int acpi_video_device_get_state(struct acpi_video_device *device,
+ unsigned long *state);
+static int acpi_video_output_get(struct output_device *od);
+static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
/*backlight device sysfs support*/
static int acpi_video_get_brightness(struct backlight_device *bd)
{
unsigned long cur_level;
struct acpi_video_device *vd =
- (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ (struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_get_level_current(vd, &cur_level);
return (int) cur_level;
}
@@ -287,7 +293,7 @@ static int acpi_video_set_brightness(struct backlight_device *bd)
{
int request_level = bd->props.brightness;
struct acpi_video_device *vd =
- (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+ (struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_set_level(vd, request_level);
return 0;
}
@@ -297,6 +303,28 @@ static struct backlight_ops acpi_backlight_ops = {
.update_status = acpi_video_set_brightness,
};
+/*video output device sysfs support*/
+static int acpi_video_output_get(struct output_device *od)
+{
+ unsigned long state;
+ struct acpi_video_device *vd =
+ (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+ acpi_video_device_get_state(vd, &state);
+ return (int)state;
+}
+
+static int acpi_video_output_set(struct output_device *od)
+{
+ unsigned long state = od->request_state;
+ struct acpi_video_device *vd=
+ (struct acpi_video_device *)class_get_devdata(&od->class_dev);
+ return acpi_video_device_set_state(vd, state);
+}
+
+static struct output_properties acpi_output_properties = {
+ .set_state = acpi_video_output_set,
+ .get_status = acpi_video_output_get,
+};
/* --------------------------------------------------------------------------
Video Management
-------------------------------------------------------------------------- */
@@ -531,7 +559,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
static void acpi_video_device_find_cap(struct acpi_video_device *device)
{
- acpi_integer status;
acpi_handle h_dummy1;
int i;
u32 max_level = 0;
@@ -565,50 +592,55 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
device->cap._DSS = 1;
}
- status = acpi_video_device_lcd_query_levels(device, &obj);
-
- if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
- int count = 0;
- union acpi_object *o;
-
- br = kzalloc(sizeof(*br), GFP_KERNEL);
- if (!br) {
- printk(KERN_ERR "can't allocate memory\n");
- } else {
- br->levels = kmalloc(obj->package.count *
- sizeof *(br->levels), GFP_KERNEL);
- if (!br->levels)
- goto out;
-
- for (i = 0; i < obj->package.count; i++) {
- o = (union acpi_object *)&obj->package.
- elements[i];
- if (o->type != ACPI_TYPE_INTEGER) {
- printk(KERN_ERR PREFIX "Invalid data\n");
- continue;
- }
- br->levels[count] = (u32) o->integer.value;
- if (br->levels[count] > max_level)
- max_level = br->levels[count];
- count++;
- }
- out:
- if (count < 2) {
- kfree(br->levels);
- kfree(br);
+ if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
+
+ if (obj->package.count >= 2) {
+ int count = 0;
+ union acpi_object *o;
+
+ br = kzalloc(sizeof(*br), GFP_KERNEL);
+ if (!br) {
+ printk(KERN_ERR "can't allocate memory\n");
} else {
- br->count = count;
- device->brightness = br;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "found %d brightness levels\n",
- count));
+ br->levels = kmalloc(obj->package.count *
+ sizeof *(br->levels), GFP_KERNEL);
+ if (!br->levels)
+ goto out;
+
+ for (i = 0; i < obj->package.count; i++) {
+ o = (union acpi_object *)&obj->package.
+ elements[i];
+ if (o->type != ACPI_TYPE_INTEGER) {
+ printk(KERN_ERR PREFIX "Invalid data\n");
+ continue;
+ }
+ br->levels[count] = (u32) o->integer.value;
+
+ if (br->levels[count] > max_level)
+ max_level = br->levels[count];
+ count++;
+ }
+ out:
+ if (count < 2) {
+ kfree(br->levels);
+ kfree(br);
+ } else {
+ br->count = count;
+ device->brightness = br;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "found %d brightness levels\n",
+ count));
+ }
}
}
+
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
}
kfree(obj);
- if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+ if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
unsigned long tmp;
static int count = 0;
char *name;
@@ -626,6 +658,17 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(name);
}
+ if (device->cap._DCS && device->cap._DSS){
+ static int count = 0;
+ char *name;
+ name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+ if (!name)
+ return;
+ sprintf(name, "acpi_video%d", count++);
+ device->output_dev = video_output_register(name,
+ NULL, device, &acpi_output_properties);
+ kfree(name);
+ }
return;
}
@@ -1669,6 +1712,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
backlight_device_unregister(device->backlight);
+ video_output_unregister(device->output_dev);
return 0;
}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 4ad8675f5a16..d8046a113c37 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -309,7 +309,7 @@ config PATA_HPT3X2N
If unsure, say N.
config PATA_HPT3X3
- tristate "HPT 343/363 PATA support (Experimental)"
+ tristate "HPT 343/363 PATA support"
depends on PCI
help
This option enables support for the HPT 343/363
@@ -317,6 +317,14 @@ config PATA_HPT3X3
If unsure, say N.
+config PATA_HPT3X3_DMA
+ bool "HPT 343/363 DMA support (Experimental)"
+ depends on PATA_HPT3X3
+ help
+ This option enables DMA support for the HPT343/363
+ controllers. Enable with care as there are still some
+ problems with DMA on this chipset.
+
config PATA_ISAPNP
tristate "ISA Plug and Play PATA support (Experimental)"
depends on EXPERIMENTAL && ISAPNP
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 11e4eb9f304e..06f212ff2b4f 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -99,6 +99,7 @@ enum {
HOST_CAP_SSC = (1 << 14), /* Slumber capable */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
@@ -113,11 +114,11 @@ enum {
PORT_TFDATA = 0x20, /* taskfile data */
PORT_SIG = 0x24, /* device TF signature */
PORT_CMD_ISSUE = 0x38, /* command issue */
- PORT_SCR = 0x28, /* SATA phy register block */
PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */
PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */
PORT_SCR_ERR = 0x30, /* SATA phy register: SError */
PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
+ PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
@@ -216,8 +217,8 @@ struct ahci_port_priv {
unsigned int ncq_saw_sdb:1;
};
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static void ahci_irq_clear(struct ata_port *ap);
@@ -417,7 +418,10 @@ static const struct pci_device_id ahci_pci_tbl[] = {
/* ATI */
{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
- { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
+ { PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 IDE */
+ { PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700 AHCI */
+ { PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700 nraid5 */
+ { PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700 raid5 */
/* VIA */
{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -545,13 +549,19 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
- /* some chips lie about 64bit support */
+ /* some chips have errata preventing 64bit use */
if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
"controller can't do 64bit DMA, forcing 32bit\n");
cap &= ~HOST_CAP_64;
}
+ if ((cap & HOST_CAP_NCQ) && (pi->flags & AHCI_FLAG_NO_NCQ)) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "controller can't do NCQ, turning off CAP_NCQ\n");
+ cap &= ~HOST_CAP_NCQ;
+ }
+
/* fixup zero port_map */
if (!port_map) {
port_map = (1 << ahci_nr_ports(cap)) - 1;
@@ -625,38 +635,45 @@ static void ahci_restore_initial_config(struct ata_host *host)
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return 0xffffffffU;
- }
+ static const int offset[] = {
+ [SCR_STATUS] = PORT_SCR_STAT,
+ [SCR_CONTROL] = PORT_SCR_CTL,
+ [SCR_ERROR] = PORT_SCR_ERR,
+ [SCR_ACTIVE] = PORT_SCR_ACT,
+ [SCR_NOTIFICATION] = PORT_SCR_NTF,
+ };
+ struct ahci_host_priv *hpriv = ap->host->private_data;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ if (sc_reg < ARRAY_SIZE(offset) &&
+ (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+ return offset[sc_reg];
+ return 0;
}
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
- u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
- unsigned int sc_reg;
-
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
+
+ if (offset) {
+ *val = readl(port_mmio + offset);
+ return 0;
}
+ return -EINVAL;
+}
- writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+ void __iomem *port_mmio = ahci_port_base(ap);
+ int offset = ahci_scr_offset(ap, sc_reg);
+
+ if (offset) {
+ writel(val, port_mmio + offset);
+ return 0;
+ }
+ return -EINVAL;
}
static void ahci_start_engine(struct ata_port *ap)
@@ -948,37 +965,87 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
}
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
{
void __iomem *port_mmio = ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
+ int busy, rc;
+
+ /* do we need to kick the port? */
+ busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+ if (!busy && !force_restart)
+ return 0;
+
+ /* stop engine */
+ rc = ahci_stop_engine(ap);
+ if (rc)
+ goto out_restart;
- if (!(hpriv->cap & HOST_CAP_CLO))
- return -EOPNOTSUPP;
+ /* need to do CLO? */
+ if (!busy) {
+ rc = 0;
+ goto out_restart;
+ }
+ if (!(hpriv->cap & HOST_CAP_CLO)) {
+ rc = -EOPNOTSUPP;
+ goto out_restart;
+ }
+
+ /* perform CLO */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_CLO;
writel(tmp, port_mmio + PORT_CMD);
+ rc = 0;
tmp = ata_wait_register(port_mmio + PORT_CMD,
PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
if (tmp & PORT_CMD_CLO)
- return -EIO;
+ rc = -EIO;
- return 0;
+ /* restart engine */
+ out_restart:
+ ahci_start_engine(ap);
+ return rc;
}
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+ struct ata_taskfile *tf, int is_cmd, u16 flags,
+ unsigned long timeout_msec)
{
+ const u32 cmd_fis_len = 5; /* five dwords */
struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
- const u32 cmd_fis_len = 5; /* five dwords */
+ u8 *fis = pp->cmd_tbl;
+ u32 tmp;
+
+ /* prep the command */
+ ata_tf_to_fis(tf, pmp, is_cmd, fis);
+ ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+ /* issue & wait */
+ writel(1, port_mmio + PORT_CMD_ISSUE);
+
+ if (timeout_msec) {
+ tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+ 1, timeout_msec);
+ if (tmp & 0x1) {
+ ahci_kick_engine(ap, 1);
+ return -EBUSY;
+ }
+ } else
+ readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+
+ return 0;
+}
+
+static int ahci_do_softreset(struct ata_port *ap, unsigned int *class,
+ int pmp, unsigned long deadline)
+{
const char *reason = NULL;
+ unsigned long now, msecs;
struct ata_taskfile tf;
- u32 tmp;
- u8 *fis;
int rc;
DPRINTK("ENTER\n");
@@ -990,43 +1057,22 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
}
/* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_stop_engine(ap);
- if (rc) {
- reason = "failed to stop engine";
- goto fail_restart;
- }
-
- /* check BUSY/DRQ, perform Command List Override if necessary */
- if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
- rc = ahci_clo(ap);
-
- if (rc == -EOPNOTSUPP) {
- reason = "port busy but CLO unavailable";
- goto fail_restart;
- } else if (rc) {
- reason = "port busy but CLO failed";
- goto fail_restart;
- }
- }
-
- /* restart engine */
- ahci_start_engine(ap);
+ rc = ahci_kick_engine(ap, 1);
+ if (rc)
+ ata_port_printk(ap, KERN_WARNING,
+ "failed to reset engine (errno=%d)", rc);
ata_tf_init(ap->device, &tf);
- fis = pp->cmd_tbl;
/* issue the first D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0,
- cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+ msecs = 0;
+ now = jiffies;
+ if (time_after(now, deadline))
+ msecs = jiffies_to_msecs(deadline - now);
tf.ctl |= ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
-
- tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
- if (tmp & 0x1) {
+ if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+ AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
rc = -EIO;
reason = "1st FIS failed";
goto fail;
@@ -1036,14 +1082,8 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
msleep(1);
/* issue the second D2H Register FIS */
- ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
tf.ctl &= ~ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
-
- writel(1, port_mmio + PORT_CMD_ISSUE);
- readl(port_mmio + PORT_CMD_ISSUE); /* flush */
+ ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
/* spec mandates ">= 2ms" before checking status.
* We wait 150ms, because that was the magic delay used for
@@ -1066,13 +1106,17 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class,
DPRINTK("EXIT, class=%u\n", *class);
return 0;
- fail_restart:
- ahci_start_engine(ap);
fail:
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
}
+static int ahci_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
+ return ahci_do_softreset(ap, class, 0, deadline);
+}
+
static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
@@ -1088,7 +1132,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(ap->device, &tf);
tf.command = 0x80;
- ata_tf_to_fis(&tf, d2h_fis, 0);
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_std_hardreset(ap, class, deadline);
@@ -1106,6 +1150,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
+ u32 serror;
int rc;
DPRINTK("ENTER\n");
@@ -1116,7 +1161,8 @@ static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
deadline);
/* vt8251 needs SError cleared for the port to operate */
- ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+ ahci_scr_read(ap, SCR_ERROR, &serror);
+ ahci_scr_write(ap, SCR_ERROR, serror);
ahci_start_engine(ap);
@@ -1205,7 +1251,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc)
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
- ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1238,7 +1284,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_ehi_clear_desc(ehi);
/* AHCI needs SError cleared; otherwise, it might lock up */
- serror = ahci_scr_read(ap, SCR_ERROR);
+ ahci_scr_read(ap, SCR_ERROR, &serror);
ahci_scr_write(ap, SCR_ERROR, serror);
/* analyze @irq_stat */
@@ -1262,12 +1308,12 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
if (irq_stat & PORT_IRQ_IF_ERR) {
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", interface fatal error");
+ ata_ehi_push_desc(ehi, "interface fatal error");
}
if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
+ ata_ehi_push_desc(ehi, "%s", irq_stat & PORT_IRQ_CONNECT ?
"connection status changed" : "PHY RDY changed");
}
@@ -1276,7 +1322,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
err_mask |= AC_ERR_HSM;
action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+ ata_ehi_push_desc(ehi, "unknown FIS %08x %08x %08x %08x",
unk[0], unk[1], unk[2], unk[3]);
}
@@ -1512,11 +1558,17 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- if (qc->flags & ATA_QCFLAG_FAILED) {
- /* make DMA engine forget about the failed command */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
- }
+ /* make DMA engine forget about the failed command */
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ ahci_kick_engine(ap, 1);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+ ahci_power_up(ap);
+ ahci_start_port(ap);
+
+ return 0;
}
#ifdef CONFIG_PM
@@ -1536,14 +1588,6 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
return rc;
}
-static int ahci_port_resume(struct ata_port *ap)
-{
- ahci_power_up(ap);
- ahci_start_port(ap);
-
- return 0;
-}
-
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1734,12 +1778,13 @@ static void ahci_print_info(struct ata_host *host)
dev_printk(KERN_INFO, &pdev->dev,
"flags: "
- "%s%s%s%s%s%s"
- "%s%s%s%s%s%s%s\n"
+ "%s%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s\n"
,
cap & (1 << 31) ? "64bit " : "",
cap & (1 << 30) ? "ncq " : "",
+ cap & (1 << 29) ? "sntf " : "",
cap & (1 << 28) ? "ilck " : "",
cap & (1 << 27) ? "stag " : "",
cap & (1 << 26) ? "pm " : "",
@@ -1794,7 +1839,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
ahci_save_initial_config(pdev, &pi, hpriv);
/* prepare host */
- if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+ if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
@@ -1808,10 +1853,8 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *port_mmio = ahci_port_base(ap);
/* standard SATA port setup */
- if (hpriv->port_map & (1 << i)) {
+ if (hpriv->port_map & (1 << i))
ap->ioaddr.cmd_addr = port_mmio;
- ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
- }
/* disabled/not-implemented port */
else
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 6a3bfef58e13..d9fa329fd157 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -414,7 +414,7 @@ static const struct piix_map_db ich6m_map_db = {
*/
.map = {
/* PM PS SM SS MAP */
- { P0, P2, RV, RV }, /* 00b */
+ { P0, P2, NA, NA }, /* 00b */
{ IDE, IDE, P1, P3 }, /* 01b */
{ P0, P2, IDE, IDE }, /* 10b */
{ RV, RV, RV, RV },
@@ -928,20 +928,18 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
{
struct pci_dev *pdev = NULL;
u16 cfg;
- u8 rev;
int no_piix_dma = 0;
while((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev)) != NULL)
{
/* Look for 450NX PXB. Check for problem configurations
A PCI quirk checks bit 6 already */
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
pci_read_config_word(pdev, 0x41, &cfg);
/* Only on the original revision: IDE DMA can hang */
- if (rev == 0x00)
+ if (pdev->revision == 0x00)
no_piix_dma = 1;
/* On all revisions below 5 PXB bus lock must be disabled for IDE */
- else if (cfg & (1<<14) && rev < 5)
+ else if (cfg & (1<<14) && pdev->revision < 5)
no_piix_dma = 2;
}
if (no_piix_dma)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 5b25311ba885..6001aae0b884 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -71,6 +71,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(struct ata_device *dev);
+static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
unsigned int ata_print_id = 1;
static struct workqueue_struct *ata_wq;
@@ -110,8 +111,9 @@ MODULE_VERSION(DRV_VERSION);
/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert
- * @fis: Buffer into which data will output
* @pmp: Port multiplier port
+ * @is_cmd: This FIS is for command
+ * @fis: Buffer into which data will output
*
* Converts a standard ATA taskfile to a Serial ATA
* FIS structure (Register - Host to Device).
@@ -119,12 +121,13 @@ MODULE_VERSION(DRV_VERSION);
* LOCKING:
* Inherited from caller.
*/
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
{
- fis[0] = 0x27; /* Register - Host to Device FIS */
- fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
- bit 7 indicates Command FIS */
+ fis[0] = 0x27; /* Register - Host to Device FIS */
+ fis[1] = pmp & 0xf; /* Port multiplier number*/
+ if (is_cmd)
+ fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */
+
fis[2] = tf->command;
fis[3] = tf->feature;
@@ -1283,18 +1286,11 @@ static unsigned int ata_id_xfermask(const u16 *id)
void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data,
unsigned long delay)
{
- int rc;
-
- if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
- return;
-
PREPARE_DELAYED_WORK(&ap->port_task, fn);
ap->port_task_data = data;
- rc = queue_delayed_work(ata_wq, &ap->port_task, delay);
-
- /* rc == 0 means that another user is using port task */
- WARN_ON(rc == 0);
+ /* may fail if ata_port_flush_task() in progress */
+ queue_delayed_work(ata_wq, &ap->port_task, delay);
}
/**
@@ -1309,32 +1305,9 @@ void ata_port_queue_task(struct ata_port *ap, work_func_t fn, void *data,
*/
void ata_port_flush_task(struct ata_port *ap)
{
- unsigned long flags;
-
DPRINTK("ENTER\n");
- spin_lock_irqsave(ap->lock, flags);
- ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(ap->lock, flags);
-
- DPRINTK("flush #1\n");
- cancel_work_sync(&ap->port_task.work); /* akpm: seems unneeded */
-
- /*
- * At this point, if a task is running, it's guaranteed to see
- * the FLUSH flag; thus, it will never queue pio tasks again.
- * Cancel and flush.
- */
- if (!cancel_delayed_work(&ap->port_task)) {
- if (ata_msg_ctl(ap))
- ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
- __FUNCTION__);
- cancel_work_sync(&ap->port_task.work);
- }
-
- spin_lock_irqsave(ap->lock, flags);
- ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
- spin_unlock_irqrestore(ap->lock, flags);
+ cancel_rearming_delayed_work(&ap->port_task);
if (ata_msg_ctl(ap))
ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __FUNCTION__);
@@ -1814,7 +1787,7 @@ static void ata_dev_config_ncq(struct ata_device *dev,
desc[0] = '\0';
return;
}
- if (ata_device_blacklisted(dev) & ATA_HORKAGE_NONCQ) {
+ if (dev->horkage & ATA_HORKAGE_NONCQ) {
snprintf(desc, desc_sz, "NCQ (not used)");
return;
}
@@ -1863,6 +1836,9 @@ int ata_dev_configure(struct ata_device *dev)
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);
+ /* set horkage */
+ dev->horkage |= ata_dev_blacklisted(dev);
+
/* let ACPI work its magic */
rc = ata_acpi_on_devcfg(dev);
if (rc)
@@ -2038,7 +2014,7 @@ int ata_dev_configure(struct ata_device *dev)
dev->max_sectors = ATA_MAX_SECTORS;
}
- if (ata_device_blacklisted(dev) & ATA_HORKAGE_MAX_SEC_128)
+ if (dev->horkage & ATA_HORKAGE_MAX_SEC_128)
dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
dev->max_sectors);
@@ -2413,21 +2389,35 @@ int sata_down_spd_limit(struct ata_port *ap)
u32 sstatus, spd, mask;
int rc, highbit;
+ if (!sata_scr_valid(ap))
+ return -EOPNOTSUPP;
+
+ /* If SCR can be read, use it to determine the current SPD.
+ * If not, use cached value in ap->sata_spd.
+ */
rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
- if (rc)
- return rc;
+ if (rc == 0)
+ spd = (sstatus >> 4) & 0xf;
+ else
+ spd = ap->sata_spd;
mask = ap->sata_spd_limit;
if (mask <= 1)
return -EINVAL;
+
+ /* unconditionally mask off the highest bit */
highbit = fls(mask) - 1;
mask &= ~(1 << highbit);
- spd = (sstatus >> 4) & 0xf;
- if (spd <= 1)
- return -EINVAL;
- spd--;
- mask &= (1 << spd) - 1;
+ /* Mask off all speeds higher than or equal to the current
+ * one. Force 1.5Gbps if current SPD is not available.
+ */
+ if (spd > 1)
+ mask &= (1 << (spd - 1)) - 1;
+ else
+ mask &= 1;
+
+ /* were we already at the bottom? */
if (!mask)
return -EINVAL;
@@ -3190,9 +3180,6 @@ void ata_bus_reset(struct ata_port *ap)
if ((slave_possible) && (err != 0x81))
ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
- /* re-enable interrupts */
- ap->ops->irq_on(ap);
-
/* is double-select really necessary? */
if (ap->device[1].class != ATA_DEV_NONE)
ap->ops->dev_select(ap, 1);
@@ -3280,9 +3267,11 @@ int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
last = cur;
last_jiffies = jiffies;
- /* check deadline */
+ /* Check deadline. If debouncing failed, return
+ * -EPIPE to tell upper layer to lower link speed.
+ */
if (time_after(jiffies, deadline))
- return -EBUSY;
+ return -EPIPE;
}
}
@@ -3577,10 +3566,6 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
sata_scr_write(ap, SCR_ERROR, serror);
- /* re-enable interrupts */
- if (!ap->ops->error_handler)
- ap->ops->irq_on(ap);
-
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
ap->ops->dev_select(ap, 1);
@@ -3770,6 +3755,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "SAMSUNG CD-ROM SN-124","N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
{ "IOMEGA ZIP 250 ATAPI", NULL, ATA_HORKAGE_NODMA }, /* temporary fix */
+ { "IOMEGA ZIP 250 ATAPI Floppy",
+ NULL, ATA_HORKAGE_NODMA },
/* Weird ATAPI devices */
{ "TORiSAN DVD-ROM DRD-N216", NULL, ATA_HORKAGE_MAX_SEC_128 },
@@ -3783,7 +3770,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "FUJITSU MHT2060BH", NULL, ATA_HORKAGE_NONCQ },
/* NCQ is broken */
{ "Maxtor 6L250S0", "BANC1G10", ATA_HORKAGE_NONCQ },
+ { "Maxtor 6B200M0", "BANC1BM0", ATA_HORKAGE_NONCQ },
{ "Maxtor 6B200M0", "BANC1B10", ATA_HORKAGE_NONCQ },
+ { "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI",
+ ATA_HORKAGE_NONCQ },
/* NCQ hard hangs device under heavier load, needs hard power cycle */
{ "Maxtor 6B250S0", "BANC1B70", ATA_HORKAGE_NONCQ },
/* Blacklist entries taken from Silicon Image 3124/3132
@@ -3796,6 +3786,8 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "HTS541612J9SA00", "SBDIC7JP", ATA_HORKAGE_NONCQ, },
{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
{ "WDC WD740ADFD-00NLR1", NULL, ATA_HORKAGE_NONCQ, },
+ { "FUJITSU MHV2080BH", "00840028", ATA_HORKAGE_NONCQ, },
+ { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, },
/* Devices with NCQ limits */
@@ -3803,7 +3795,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ }
};
-unsigned long ata_device_blacklisted(const struct ata_device *dev)
+static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
{
unsigned char model_num[ATA_ID_PROD_LEN + 1];
unsigned char model_rev[ATA_ID_FW_REV_LEN + 1];
@@ -3833,7 +3825,7 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
(dev->flags & ATA_DFLAG_CDB_INTR))
return 1;
- return (ata_device_blacklisted(dev) & ATA_HORKAGE_NODMA) ? 1 : 0;
+ return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0;
}
/**
@@ -5756,10 +5748,8 @@ int sata_scr_valid(struct ata_port *ap)
*/
int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
{
- if (sata_scr_valid(ap)) {
- *val = ap->ops->scr_read(ap, reg);
- return 0;
- }
+ if (sata_scr_valid(ap))
+ return ap->ops->scr_read(ap, reg, val);
return -EOPNOTSUPP;
}
@@ -5781,10 +5771,8 @@ int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
*/
int sata_scr_write(struct ata_port *ap, int reg, u32 val)
{
- if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- return 0;
- }
+ if (sata_scr_valid(ap))
+ return ap->ops->scr_write(ap, reg, val);
return -EOPNOTSUPP;
}
@@ -5805,10 +5793,13 @@ int sata_scr_write(struct ata_port *ap, int reg, u32 val)
*/
int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
{
+ int rc;
+
if (sata_scr_valid(ap)) {
- ap->ops->scr_write(ap, reg, val);
- ap->ops->scr_read(ap, reg);
- return 0;
+ rc = ap->ops->scr_write(ap, reg, val);
+ if (rc == 0)
+ rc = ap->ops->scr_read(ap, reg, &val);
+ return rc;
}
return -EOPNOTSUPP;
}
@@ -6020,6 +6011,7 @@ void ata_dev_init(struct ata_device *dev)
/* SATA spd limit is bound to the first device */
ap->sata_spd_limit = ap->hw_sata_spd_limit;
+ ap->sata_spd = 0;
/* High bits of dev->flags are used to record warm plug
* requests which occur asynchronously. Synchronize using
@@ -6085,6 +6077,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q);
+ init_timer_deferrable(&ap->fastdrain_timer);
+ ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+ ap->fastdrain_timer.data = (unsigned long)ap;
ap->cbl = ATA_CBL_NONE;
@@ -6461,7 +6456,7 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
- ata_scsi_scan_host(ap);
+ ata_scsi_scan_host(ap, 1);
}
return 0;
@@ -6557,13 +6552,7 @@ void ata_port_detach(struct ata_port *ap)
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
-
- /* Flush hotplug task. The sequence is similar to
- * ata_port_flush_task().
- */
- cancel_work_sync(&ap->hotplug_task.work); /* akpm: why? */
- cancel_delayed_work(&ap->hotplug_task);
- cancel_work_sync(&ap->hotplug_task.work);
+ cancel_rearming_delayed_work(&ap->hotplug_task);
skip_eh:
/* remove the associated SCSI host */
@@ -6952,7 +6941,6 @@ EXPORT_SYMBOL_GPL(ata_host_resume);
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_id_to_dma_mode);
-EXPORT_SYMBOL_GPL(ata_device_blacklisted);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
EXPORT_SYMBOL_GPL(ata_pio_need_iordy);
@@ -6961,9 +6949,9 @@ EXPORT_SYMBOL_GPL(ata_timing_merge);
#ifdef CONFIG_PCI
EXPORT_SYMBOL_GPL(pci_test_config_bits);
-EXPORT_SYMBOL_GPL(ata_pci_init_native_host);
+EXPORT_SYMBOL_GPL(ata_pci_init_sff_host);
EXPORT_SYMBOL_GPL(ata_pci_init_bmdma);
-EXPORT_SYMBOL_GPL(ata_pci_prepare_native_host);
+EXPORT_SYMBOL_GPL(ata_pci_prepare_sff_host);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
#ifdef CONFIG_PM
@@ -6976,6 +6964,9 @@ EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
EXPORT_SYMBOL_GPL(ata_eng_timeout);
EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
EXPORT_SYMBOL_GPL(ata_port_abort);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 9ee0a8c08d96..ac6ceed4bb60 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -56,6 +56,7 @@ enum {
*/
enum {
ATA_EH_PRERESET_TIMEOUT = 10 * HZ,
+ ATA_EH_FASTDRAIN_INTERVAL = 3 * HZ,
};
/* The following table determines how we sequence resets. Each entry
@@ -85,6 +86,71 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
{ }
#endif /* CONFIG_PM */
+static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
+ va_list args)
+{
+ ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
+ ATA_EH_DESC_LEN - ehi->desc_len,
+ fmt, args);
+}
+
+/**
+ * __ata_ehi_push_desc - push error description without adding separator
+ * @ehi: target EHI
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to @ehi->desc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(ehi, fmt, args);
+ va_end(args);
+}
+
+/**
+ * ata_ehi_push_desc - push error description with separator
+ * @ehi: target EHI
+ * @fmt: printf format string
+ *
+ * Format string according to @fmt and append it to @ehi->desc.
+ * If @ehi->desc is not empty, ", " is added in-between.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+ va_list args;
+
+ if (ehi->desc_len)
+ __ata_ehi_push_desc(ehi, ", ");
+
+ va_start(args, fmt);
+ __ata_ehi_pushv_desc(ehi, fmt, args);
+ va_end(args);
+}
+
+/**
+ * ata_ehi_clear_desc - clean error description
+ * @ehi: target EHI
+ *
+ * Clear @ehi->desc.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+void ata_ehi_clear_desc(struct ata_eh_info *ehi)
+{
+ ehi->desc[0] = '\0';
+ ehi->desc_len = 0;
+}
+
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
{
@@ -296,6 +362,9 @@ void ata_scsi_error(struct Scsi_Host *host)
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ /* kill fast drain timer */
+ del_timer_sync(&ap->fastdrain_timer);
+
/* process port resume request */
ata_eh_handle_port_resume(ap);
@@ -511,6 +580,94 @@ void ata_eng_timeout(struct ata_port *ap)
DPRINTK("EXIT\n");
}
+static int ata_eh_nr_in_flight(struct ata_port *ap)
+{
+ unsigned int tag;
+ int nr = 0;
+
+ /* count only non-internal commands */
+ for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
+ if (ata_qc_from_tag(ap, tag))
+ nr++;
+
+ return nr;
+}
+
+void ata_eh_fastdrain_timerfn(unsigned long arg)
+{
+ struct ata_port *ap = (void *)arg;
+ unsigned long flags;
+ int cnt;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ cnt = ata_eh_nr_in_flight(ap);
+
+ /* are we done? */
+ if (!cnt)
+ goto out_unlock;
+
+ if (cnt == ap->fastdrain_cnt) {
+ unsigned int tag;
+
+ /* No progress during the last interval, tag all
+ * in-flight qcs as timed out and freeze the port.
+ */
+ for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+ if (qc)
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ }
+
+ ata_port_freeze(ap);
+ } else {
+ /* some qcs have finished, give it another chance */
+ ap->fastdrain_cnt = cnt;
+ ap->fastdrain_timer.expires =
+ jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ add_timer(&ap->fastdrain_timer);
+ }
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ * ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
+ * @ap: target ATA port
+ * @fastdrain: activate fast drain
+ *
+ * Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
+ * is non-zero and EH wasn't pending before. Fast drain ensures
+ * that EH kicks in in timely manner.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host lock)
+ */
+static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
+{
+ int cnt;
+
+ /* already scheduled? */
+ if (ap->pflags & ATA_PFLAG_EH_PENDING)
+ return;
+
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+ if (!fastdrain)
+ return;
+
+ /* do we have in-flight qcs? */
+ cnt = ata_eh_nr_in_flight(ap);
+ if (!cnt)
+ return;
+
+ /* activate fast drain */
+ ap->fastdrain_cnt = cnt;
+ ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+ add_timer(&ap->fastdrain_timer);
+}
+
/**
* ata_qc_schedule_eh - schedule qc for error handling
* @qc: command to schedule error handling for
@@ -528,7 +685,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED;
- qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_eh_set_pending(ap, 1);
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
@@ -555,7 +712,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
if (ap->pflags & ATA_PFLAG_INITIALIZING)
return;
- ap->pflags |= ATA_PFLAG_EH_PENDING;
+ ata_eh_set_pending(ap, 1);
scsi_schedule_eh(ap->scsi_host);
DPRINTK("port EH scheduled\n");
@@ -579,6 +736,9 @@ int ata_port_abort(struct ata_port *ap)
WARN_ON(!ap->ops->error_handler);
+ /* we're gonna abort all commands, no need for fast drain */
+ ata_eh_set_pending(ap, 0);
+
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
@@ -1130,7 +1290,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
/* we've got the perpetrator, condemn it */
qc = __ata_qc_from_tag(ap, tag);
memcpy(&qc->result_tf, &tf, sizeof(tf));
- qc->err_mask |= AC_ERR_DEV;
+ qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
ehc->i.err_mask &= ~AC_ERR_DEV;
}
@@ -1413,8 +1573,12 @@ static void ata_eh_autopsy(struct ata_port *ap)
if (rc == 0) {
ehc->i.serror |= serror;
ata_eh_analyze_serror(ap);
- } else if (rc != -EOPNOTSUPP)
+ } else if (rc != -EOPNOTSUPP) {
+ /* SError read failed, force hardreset and probing */
+ ata_ehi_schedule_probe(&ehc->i);
ehc->i.action |= ATA_EH_HARDRESET;
+ ehc->i.err_mask |= AC_ERR_OTHER;
+ }
/* analyze NCQ failure */
ata_eh_analyze_ncq_error(ap);
@@ -1524,14 +1688,14 @@ static void ata_eh_report(struct ata_port *ap)
ehc->i.err_mask, ap->sactive, ehc->i.serror,
ehc->i.action, frozen);
if (desc)
- ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+ ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
} else {
ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
"SAct 0x%x SErr 0x%x action 0x%x%s\n",
ehc->i.err_mask, ap->sactive, ehc->i.serror,
ehc->i.action, frozen);
if (desc)
- ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+ ata_port_printk(ap, KERN_ERR, "%s\n", desc);
}
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
@@ -1551,7 +1715,7 @@ static void ata_eh_report(struct ata_port *ap)
"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
"tag %d cdb 0x%x data %u %s\n "
"res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
- "Emask 0x%x (%s)\n",
+ "Emask 0x%x (%s)%s\n",
cmd->command, cmd->feature, cmd->nsect,
cmd->lbal, cmd->lbam, cmd->lbah,
cmd->hob_feature, cmd->hob_nsect,
@@ -1562,7 +1726,8 @@ static void ata_eh_report(struct ata_port *ap)
res->lbal, res->lbam, res->lbah,
res->hob_feature, res->hob_nsect,
res->hob_lbal, res->hob_lbam, res->hob_lbah,
- res->device, qc->err_mask, ata_err_string(qc->err_mask));
+ res->device, qc->err_mask, ata_err_string(qc->err_mask),
+ qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
}
}
@@ -1648,7 +1813,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
} else
ata_port_printk(ap, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
- return rc;
+ goto out;
}
}
@@ -1661,7 +1826,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
/* prereset told us not to reset, bang classes and return */
for (i = 0; i < ATA_MAX_DEVICES; i++)
classes[i] = ATA_DEV_NONE;
- return 0;
+ rc = 0;
+ goto out;
}
/* did prereset() screw up? if so, fix up to avoid oopsing */
@@ -1697,7 +1863,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_ERR,
"follow-up softreset required "
"but no softreset avaliable\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
@@ -1707,7 +1874,8 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
classes[0] == ATA_DEV_UNKNOWN) {
ata_port_printk(ap, KERN_ERR,
"classification failed\n");
- return -EINVAL;
+ rc = -EINVAL;
+ goto out;
}
}
@@ -1724,7 +1892,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
schedule_timeout_uninterruptible(delta);
}
- if (reset == hardreset &&
+ if (rc == -EPIPE ||
try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
sata_down_spd_limit(ap);
if (hardreset)
@@ -1733,12 +1901,18 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
}
if (rc == 0) {
+ u32 sstatus;
+
/* After the reset, the device state is PIO 0 and the
* controller state is undefined. Record the mode.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].pio_mode = XFER_PIO_0;
+ /* record current link speed */
+ if (sata_scr_read(ap, SCR_STATUS, &sstatus) == 0)
+ ap->sata_spd = (sstatus >> 4) & 0xf;
+
if (postreset)
postreset(ap, classes);
@@ -1746,7 +1920,9 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}
-
+ out:
+ /* clear hotplug flag */
+ ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
return rc;
}
@@ -1897,6 +2073,57 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
return 1;
}
+static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
+{
+ struct ata_port *ap = dev->ap;
+ struct ata_eh_context *ehc = &ap->eh_context;
+
+ ehc->tries[dev->devno]--;
+
+ switch (err) {
+ case -ENODEV:
+ /* device missing or wrong IDENTIFY data, schedule probing */
+ ehc->i.probe_mask |= (1 << dev->devno);
+ case -EINVAL:
+ /* give it just one more chance */
+ ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
+ case -EIO:
+ if (ehc->tries[dev->devno] == 1) {
+ /* This is the last chance, better to slow
+ * down than lose it.
+ */
+ sata_down_spd_limit(ap);
+ ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
+ }
+ }
+
+ if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
+ /* disable device if it has used up all its chances */
+ ata_dev_disable(dev);
+
+ /* detach if offline */
+ if (ata_port_offline(ap))
+ ata_eh_detach_dev(dev);
+
+ /* probe if requested */
+ if ((ehc->i.probe_mask & (1 << dev->devno)) &&
+ !(ehc->did_probe_mask & (1 << dev->devno))) {
+ ata_eh_detach_dev(dev);
+ ata_dev_init(dev);
+
+ ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+ ehc->did_probe_mask |= (1 << dev->devno);
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+ } else {
+ /* soft didn't work? be haaaaard */
+ if (ehc->i.flags & ATA_EHI_DID_RESET)
+ ehc->i.action |= ATA_EH_HARDRESET;
+ else
+ ehc->i.action |= ATA_EH_SOFTRESET;
+ }
+}
+
/**
* ata_eh_recover - recover host port after error
* @ap: host port to recover
@@ -1997,50 +2224,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
goto out;
dev_fail:
- ehc->tries[dev->devno]--;
-
- switch (rc) {
- case -ENODEV:
- /* device missing or wrong IDENTIFY data, schedule probing */
- ehc->i.probe_mask |= (1 << dev->devno);
- case -EINVAL:
- /* give it just one more chance */
- ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
- case -EIO:
- if (ehc->tries[dev->devno] == 1) {
- /* This is the last chance, better to slow
- * down than lose it.
- */
- sata_down_spd_limit(ap);
- ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
- }
- }
-
- if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {
- /* disable device if it has used up all its chances */
- ata_dev_disable(dev);
-
- /* detach if offline */
- if (ata_port_offline(ap))
- ata_eh_detach_dev(dev);
-
- /* probe if requested */
- if ((ehc->i.probe_mask & (1 << dev->devno)) &&
- !(ehc->did_probe_mask & (1 << dev->devno))) {
- ata_eh_detach_dev(dev);
- ata_dev_init(dev);
-
- ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
- ehc->did_probe_mask |= (1 << dev->devno);
- ehc->i.action |= ATA_EH_SOFTRESET;
- }
- } else {
- /* soft didn't work? be haaaaard */
- if (ehc->i.flags & ATA_EHI_DID_RESET)
- ehc->i.action |= ATA_EH_HARDRESET;
- else
- ehc->i.action |= ATA_EH_SOFTRESET;
- }
+ ata_eh_handle_dev_fail(dev, rc);
if (ata_port_nr_enabled(ap)) {
ata_port_printk(ap, KERN_WARNING, "failed to recover some "
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfde22da07ac..12ac0b511f79 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -2947,17 +2947,22 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
return rc;
}
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
{
+ int tries = 5;
+ struct ata_device *last_failed_dev = NULL;
+ struct ata_device *dev;
unsigned int i;
if (ap->flags & ATA_FLAG_DISABLED)
return;
+ repeat:
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
struct scsi_device *sdev;
+ dev = &ap->device[i];
+
if (!ata_dev_enabled(dev) || dev->sdev)
continue;
@@ -2967,6 +2972,45 @@ void ata_scsi_scan_host(struct ata_port *ap)
scsi_device_put(sdev);
}
}
+
+ /* If we scanned while EH was in progress or allocation
+ * failure occurred, scan would have failed silently. Check
+ * whether all devices are attached.
+ */
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ dev = &ap->device[i];
+ if (ata_dev_enabled(dev) && !dev->sdev)
+ break;
+ }
+ if (i == ATA_MAX_DEVICES)
+ return;
+
+ /* we're missing some SCSI devices */
+ if (sync) {
+ /* If caller requested synchrnous scan && we've made
+ * any progress, sleep briefly and repeat.
+ */
+ if (dev != last_failed_dev) {
+ msleep(100);
+ last_failed_dev = dev;
+ goto repeat;
+ }
+
+ /* We might be failing to detect boot device, give it
+ * a few more chances.
+ */
+ if (--tries) {
+ msleep(100);
+ goto repeat;
+ }
+
+ ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+ "failed without making any progress,\n"
+ " switching to async\n");
+ }
+
+ queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+ round_jiffies_relative(HZ));
}
/**
@@ -3093,20 +3137,7 @@ void ata_scsi_hotplug(struct work_struct *work)
}
/* scan for new ones */
- ata_scsi_scan_host(ap);
-
- /* If we scanned while EH was in progress, scan would have
- * failed silently. Requeue if there are enabled but
- * unattached devices.
- */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *dev = &ap->device[i];
- if (ata_dev_enabled(dev) && !dev->sdev) {
- queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
- round_jiffies_relative(HZ));
- break;
- }
- }
+ ata_scsi_scan_host(ap, 0);
DPRINTK("EXIT\n");
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index fa1c22c7b38f..6c289c7b1322 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1,5 +1,5 @@
/*
- * libata-bmdma.c - helper library for PCI IDE BMDMA
+ * libata-sff.c - helper library for PCI IDE BMDMA
*
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
* Please ALWAYS copy linux-ide@vger.kernel.org
@@ -211,6 +211,8 @@ void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = ioread8(ioaddr->lbal_addr);
tf->hob_lbam = ioread8(ioaddr->lbam_addr);
tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+ iowrite8(tf->ctl, ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
}
}
@@ -604,13 +606,17 @@ int ata_pci_init_bmdma(struct ata_host *host)
}
/**
- * ata_pci_init_native_host - acquire native ATA resources and init host
+ * ata_pci_init_sff_host - acquire native PCI ATA resources and init host
* @host: target ATA host
*
* Acquire native PCI ATA resources for @host and initialize the
* first two ports of @host accordingly. Ports marked dummy are
* skipped and allocation failure makes the port dummy.
*
+ * Note that native PCI resources are valid even for legacy hosts
+ * as we fix up pdev resources array early in boot, so this
+ * function can be used for both native and legacy SFF hosts.
+ *
* LOCKING:
* Inherited from calling layer (may sleep).
*
@@ -618,7 +624,7 @@ int ata_pci_init_bmdma(struct ata_host *host)
* 0 if at least one port is initialized, -ENODEV if no port is
* available.
*/
-int ata_pci_init_native_host(struct ata_host *host)
+int ata_pci_init_sff_host(struct ata_host *host)
{
struct device *gdev = host->dev;
struct pci_dev *pdev = to_pci_dev(gdev);
@@ -673,7 +679,7 @@ int ata_pci_init_native_host(struct ata_host *host)
}
/**
- * ata_pci_prepare_native_host - helper to prepare native PCI ATA host
+ * ata_pci_prepare_sff_host - helper to prepare native PCI ATA host
* @pdev: target PCI device
* @ppi: array of port_info, must be enough for two ports
* @r_host: out argument for the initialized ATA host
@@ -687,9 +693,9 @@ int ata_pci_init_native_host(struct ata_host *host)
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int ata_pci_prepare_native_host(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
- struct ata_host **r_host)
+int ata_pci_prepare_sff_host(struct pci_dev *pdev,
+ const struct ata_port_info * const * ppi,
+ struct ata_host **r_host)
{
struct ata_host *host;
int rc;
@@ -705,7 +711,7 @@ int ata_pci_prepare_native_host(struct pci_dev *pdev,
goto err_out;
}
- rc = ata_pci_init_native_host(host);
+ rc = ata_pci_init_sff_host(host);
if (rc)
goto err_out;
@@ -730,221 +736,6 @@ int ata_pci_prepare_native_host(struct pci_dev *pdev,
return rc;
}
-struct ata_legacy_devres {
- unsigned int mask;
- unsigned long cmd_port[2];
- void __iomem * cmd_addr[2];
- void __iomem * ctl_addr[2];
- unsigned int irq[2];
- void * irq_dev_id[2];
-};
-
-static void ata_legacy_free_irqs(struct ata_legacy_devres *legacy_dr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- if (!legacy_dr->irq[i])
- continue;
-
- free_irq(legacy_dr->irq[i], legacy_dr->irq_dev_id[i]);
- legacy_dr->irq[i] = 0;
- legacy_dr->irq_dev_id[i] = NULL;
- }
-}
-
-static void ata_legacy_release(struct device *gdev, void *res)
-{
- struct ata_legacy_devres *this = res;
- int i;
-
- ata_legacy_free_irqs(this);
-
- for (i = 0; i < 2; i++) {
- if (this->cmd_addr[i])
- ioport_unmap(this->cmd_addr[i]);
- if (this->ctl_addr[i])
- ioport_unmap(this->ctl_addr[i]);
- if (this->cmd_port[i])
- release_region(this->cmd_port[i], 8);
- }
-}
-
-static int ata_init_legacy_port(struct ata_port *ap,
- struct ata_legacy_devres *legacy_dr)
-{
- struct ata_host *host = ap->host;
- int port_no = ap->port_no;
- unsigned long cmd_port, ctl_port;
-
- if (port_no == 0) {
- cmd_port = ATA_PRIMARY_CMD;
- ctl_port = ATA_PRIMARY_CTL;
- } else {
- cmd_port = ATA_SECONDARY_CMD;
- ctl_port = ATA_SECONDARY_CTL;
- }
-
- /* request cmd_port */
- if (request_region(cmd_port, 8, "libata"))
- legacy_dr->cmd_port[port_no] = cmd_port;
- else {
- dev_printk(KERN_WARNING, host->dev,
- "0x%0lX IDE port busy\n", cmd_port);
- return -EBUSY;
- }
-
- /* iomap cmd and ctl ports */
- legacy_dr->cmd_addr[port_no] = ioport_map(cmd_port, 8);
- legacy_dr->ctl_addr[port_no] = ioport_map(ctl_port, 1);
- if (!legacy_dr->cmd_addr[port_no] || !legacy_dr->ctl_addr[port_no]) {
- dev_printk(KERN_WARNING, host->dev,
- "failed to map cmd/ctl ports\n");
- return -ENOMEM;
- }
-
- /* init IO addresses */
- ap->ioaddr.cmd_addr = legacy_dr->cmd_addr[port_no];
- ap->ioaddr.altstatus_addr = legacy_dr->ctl_addr[port_no];
- ap->ioaddr.ctl_addr = legacy_dr->ctl_addr[port_no];
- ata_std_ports(&ap->ioaddr);
-
- return 0;
-}
-
-/**
- * ata_init_legacy_host - acquire legacy ATA resources and init ATA host
- * @host: target ATA host
- * @was_busy: out parameter, indicates whether any port was busy
- *
- * Acquire legacy ATA resources for the first two ports of @host
- * and initialize it accordingly. Ports marked dummy are skipped
- * and resource acquistion failure makes the port dummy.
- *
- * LOCKING:
- * Inherited from calling layer (may sleep).
- *
- * RETURNS:
- * 0 if at least one port is initialized, -ENODEV if no port is
- * available.
- */
-static int ata_init_legacy_host(struct ata_host *host, int *was_busy)
-{
- struct device *gdev = host->dev;
- struct ata_legacy_devres *legacy_dr;
- int i, rc;
-
- if (!devres_open_group(gdev, NULL, GFP_KERNEL))
- return -ENOMEM;
-
- rc = -ENOMEM;
- legacy_dr = devres_alloc(ata_legacy_release, sizeof(*legacy_dr),
- GFP_KERNEL);
- if (!legacy_dr)
- goto err_out;
- devres_add(gdev, legacy_dr);
-
- for (i = 0; i < 2; i++) {
- if (ata_port_is_dummy(host->ports[i]))
- continue;
-
- rc = ata_init_legacy_port(host->ports[i], legacy_dr);
- if (rc == 0)
- legacy_dr->mask |= 1 << i;
- else {
- if (rc == -EBUSY)
- (*was_busy)++;
- host->ports[i]->ops = &ata_dummy_port_ops;
- }
- }
-
- if (!legacy_dr->mask) {
- dev_printk(KERN_ERR, gdev, "no available legacy port\n");
- return -ENODEV;
- }
-
- devres_remove_group(gdev, NULL);
- return 0;
-
- err_out:
- devres_release_group(gdev, NULL);
- return rc;
-}
-
-/**
- * ata_request_legacy_irqs - request legacy ATA IRQs
- * @host: target ATA host
- * @handler: array of IRQ handlers
- * @irq_flags: array of IRQ flags
- * @dev_id: array of IRQ dev_ids
- *
- * Request legacy IRQs for non-dummy legacy ports in @host. All
- * IRQ parameters are passed as array to allow ports to have
- * separate IRQ handlers.
- *
- * LOCKING:
- * Inherited from calling layer (may sleep).
- *
- * RETURNS:
- * 0 on success, -errno otherwise.
- */
-static int ata_request_legacy_irqs(struct ata_host *host,
- irq_handler_t const *handler,
- const unsigned int *irq_flags,
- void * const *dev_id)
-{
- struct device *gdev = host->dev;
- struct ata_legacy_devres *legacy_dr;
- int i, rc;
-
- legacy_dr = devres_find(host->dev, ata_legacy_release, NULL, NULL);
- BUG_ON(!legacy_dr);
-
- for (i = 0; i < 2; i++) {
- unsigned int irq;
-
- /* FIXME: ATA_*_IRQ() should take generic device not pci_dev */
- if (i == 0)
- irq = ATA_PRIMARY_IRQ(to_pci_dev(gdev));
- else
- irq = ATA_SECONDARY_IRQ(to_pci_dev(gdev));
-
- if (!(legacy_dr->mask & (1 << i)))
- continue;
-
- if (!handler[i]) {
- dev_printk(KERN_ERR, gdev,
- "NULL handler specified for port %d\n", i);
- rc = -EINVAL;
- goto err_out;
- }
-
- rc = request_irq(irq, handler[i], irq_flags[i], DRV_NAME,
- dev_id[i]);
- if (rc) {
- dev_printk(KERN_ERR, gdev,
- "irq %u request failed (errno=%d)\n", irq, rc);
- goto err_out;
- }
-
- /* record irq allocation in legacy_dr */
- legacy_dr->irq[i] = irq;
- legacy_dr->irq_dev_id[i] = dev_id[i];
-
- /* only used to print info */
- if (i == 0)
- host->irq = irq;
- else
- host->irq2 = irq;
- }
-
- return 0;
-
- err_out:
- ata_legacy_free_irqs(legacy_dr);
- return rc;
-}
-
/**
* ata_pci_init_one - Initialize/register PCI IDE host controller
* @pdev: Controller to be initialized
@@ -1029,35 +820,11 @@ int ata_pci_init_one(struct pci_dev *pdev,
#endif
}
- /* alloc and init host */
- host = ata_host_alloc_pinfo(dev, ppi, 2);
- if (!host) {
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to allocate ATA host\n");
- rc = -ENOMEM;
+ /* prepare host */
+ rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
+ if (rc)
goto err_out;
- }
- if (!legacy_mode) {
- rc = ata_pci_init_native_host(host);
- if (rc)
- goto err_out;
- } else {
- int was_busy = 0;
-
- rc = ata_init_legacy_host(host, &was_busy);
- if (was_busy)
- pcim_pin_device(pdev);
- if (rc)
- goto err_out;
-
- /* request respective PCI regions, may fail */
- rc = pci_request_region(pdev, 1, DRV_NAME);
- rc = pci_request_region(pdev, 3, DRV_NAME);
- }
-
- /* init BMDMA, may fail */
- ata_pci_init_bmdma(host);
pci_set_master(pdev);
/* start host and request IRQ */
@@ -1068,17 +835,28 @@ int ata_pci_init_one(struct pci_dev *pdev,
if (!legacy_mode) {
rc = devm_request_irq(dev, pdev->irq, pi->port_ops->irq_handler,
IRQF_SHARED, DRV_NAME, host);
+ if (rc)
+ goto err_out;
host->irq = pdev->irq;
} else {
- irq_handler_t handler[2] = { host->ops->irq_handler,
- host->ops->irq_handler };
- unsigned int irq_flags[2] = { IRQF_SHARED, IRQF_SHARED };
- void *dev_id[2] = { host, host };
+ if (!ata_port_is_dummy(host->ports[0])) {
+ host->irq = ATA_PRIMARY_IRQ(pdev);
+ rc = devm_request_irq(dev, host->irq,
+ pi->port_ops->irq_handler,
+ IRQF_SHARED, DRV_NAME, host);
+ if (rc)
+ goto err_out;
+ }
- rc = ata_request_legacy_irqs(host, handler, irq_flags, dev_id);
+ if (!ata_port_is_dummy(host->ports[1])) {
+ host->irq2 = ATA_SECONDARY_IRQ(pdev);
+ rc = devm_request_irq(dev, host->irq2,
+ pi->port_ops->irq_handler,
+ IRQF_SHARED, DRV_NAME, host);
+ if (rc)
+ goto err_out;
+ }
}
- if (rc)
- goto err_out;
/* register */
rc = ata_host_register(host, pi->sht);
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ba17fc5f2e99..564cd234c805 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -112,7 +112,7 @@ static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
/* libata-scsi.c */
extern int ata_scsi_add_hosts(struct ata_host *host,
struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
@@ -151,6 +151,7 @@ extern int ata_bus_probe(struct ata_port *ap);
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_eh_fastdrain_timerfn(unsigned long arg);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
/* libata-sff.c */
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 30c4276ec882..010436795d20 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -455,23 +455,21 @@ static struct ata_port_operations ali_c5_port_ops = {
static void ali_init_chipset(struct pci_dev *pdev)
{
- u8 rev, tmp;
+ u8 tmp;
struct pci_dev *north, *isa_bridge;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
-
/*
* The chipset revision selects the driver operations and
* mode data.
*/
- if (rev >= 0x20 && rev < 0xC2) {
+ if (pdev->revision >= 0x20 && pdev->revision < 0xC2) {
/* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
pci_read_config_byte(pdev, 0x4B, &tmp);
/* Clear CD-ROM DMA write bit */
tmp &= 0x7F;
pci_write_config_byte(pdev, 0x4B, tmp);
- } else if (rev >= 0xC2) {
+ } else if (pdev->revision >= 0xC2) {
/* Enable cable detection logic */
pci_read_config_byte(pdev, 0x4B, &tmp);
pci_write_config_byte(pdev, 0x4B, tmp | 0x08);
@@ -483,21 +481,21 @@ static void ali_init_chipset(struct pci_dev *pdev)
/* Configure the ALi bridge logic. For non ALi rely on BIOS.
Set the south bridge enable bit */
pci_read_config_byte(isa_bridge, 0x79, &tmp);
- if (rev == 0xC2)
+ if (pdev->revision == 0xC2)
pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04);
- else if (rev > 0xC2 && rev < 0xC5)
+ else if (pdev->revision > 0xC2 && pdev->revision < 0xC5)
pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02);
}
- if (rev >= 0x20) {
+ if (pdev->revision >= 0x20) {
/*
* CD_ROM DMA on (0x53 bit 0). Enable this even if we want
* to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
* via 0x54/55.
*/
pci_read_config_byte(pdev, 0x53, &tmp);
- if (rev <= 0x20)
+ if (pdev->revision <= 0x20)
tmp &= ~0x02;
- if (rev >= 0xc7)
+ if (pdev->revision >= 0xc7)
tmp |= 0x03;
else
tmp |= 0x01; /* CD_ROM enable for DMA */
@@ -579,25 +577,23 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
};
const struct ata_port_info *ppi[] = { NULL, NULL };
- u8 rev, tmp;
+ u8 tmp;
struct pci_dev *isa_bridge;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
-
/*
* The chipset revision selects the driver operations and
* mode data.
*/
- if (rev < 0x20) {
+ if (pdev->revision < 0x20) {
ppi[0] = &info_early;
- } else if (rev < 0xC2) {
+ } else if (pdev->revision < 0xC2) {
ppi[0] = &info_20;
- } else if (rev == 0xC2) {
+ } else if (pdev->revision == 0xC2) {
ppi[0] = &info_c2;
- } else if (rev == 0xC3) {
+ } else if (pdev->revision == 0xC3) {
ppi[0] = &info_c3;
- } else if (rev == 0xC4) {
+ } else if (pdev->revision == 0xC4) {
ppi[0] = &info_c4;
} else
ppi[0] = &info_c5;
@@ -605,7 +601,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
ali_init_chipset(pdev);
isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
- if (isa_bridge && rev >= 0x20 && rev < 0xC2) {
+ if (isa_bridge && pdev->revision >= 0x20 && pdev->revision < 0xC2) {
/* Are we paired with a UDMA capable chip */
pci_read_config_byte(isa_bridge, 0x5E, &tmp);
if ((tmp & 0x1E) == 0x12)
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index b9c44c575ce3..b09facad63e1 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -623,17 +623,15 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
const struct ata_port_info *ppi[] = { NULL, NULL };
static int printed_version;
int type = id->driver_data;
- u8 rev;
u8 fifo;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
pci_read_config_byte(pdev, 0x41, &fifo);
/* Check for AMD7409 without swdma errata and if found adjust type */
- if (type == 1 && rev > 0x7)
+ if (type == 1 && pdev->revision > 0x7)
type = 2;
/* Check for AMD7411 */
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 6bf037d82b5a..7dc76e71bd55 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -275,7 +275,7 @@ static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_devi
for (i = 0; i < 2; i++) {
static const int irq[] = { 14, 15 };
- struct ata_port *ap = host->ports[0];
+ struct ata_port *ap = host->ports[i];
if (ata_port_is_dummy(ap))
continue;
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 3fca5898642b..68f150a1e2f4 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -266,7 +266,7 @@ static int cs5530_init_chip(void)
}
pci_set_master(cs5530_0);
- pci_set_mwi(cs5530_0);
+ pci_try_set_mwi(cs5530_0);
/*
* Set PCI CacheLineSize to 16-bytes:
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index d928c9105034..be0f05efac6d 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -23,7 +23,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_hpt3x3"
-#define DRV_VERSION "0.4.3"
+#define DRV_VERSION "0.5.3"
/**
* hpt3x3_set_piomode - PIO setup
@@ -52,6 +52,7 @@ static void hpt3x3_set_piomode(struct ata_port *ap, struct ata_device *adev)
pci_write_config_dword(pdev, 0x48, r2);
}
+#if defined(CONFIG_PATA_HPT3X3_DMA)
/**
* hpt3x3_set_dmamode - DMA timing setup
* @ap: ATA interface
@@ -59,6 +60,9 @@ static void hpt3x3_set_piomode(struct ata_port *ap, struct ata_device *adev)
*
* Set up the channel for MWDMA or UDMA modes. Much the same as with
* PIO, load the mode number and then set MWDMA or UDMA flag.
+ *
+ * 0x44 : bit 0-2 master mode, 3-5 slave mode, etc
+ * 0x48 : bit 4/0 DMA/UDMA bit 5/1 for slave etc
*/
static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev)
@@ -76,13 +80,26 @@ static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev)
r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
if (adev->dma_mode >= XFER_UDMA_0)
- r2 |= 0x01 << dn; /* Ultra mode */
+ r2 |= (0x10 << dn); /* Ultra mode */
else
- r2 |= 0x10 << dn; /* MWDMA */
+ r2 |= (0x01 << dn); /* MWDMA */
pci_write_config_dword(pdev, 0x44, r1);
pci_write_config_dword(pdev, 0x48, r2);
}
+#endif /* CONFIG_PATA_HPT3X3_DMA */
+
+/**
+ * hpt3x3_atapi_dma - ATAPI DMA check
+ * @qc: Queued command
+ *
+ * Just say no - we don't do ATAPI DMA
+ */
+
+static int hpt3x3_atapi_dma(struct ata_queued_cmd *qc)
+{
+ return 1;
+}
static struct scsi_host_template hpt3x3_sht = {
.module = THIS_MODULE,
@@ -105,7 +122,9 @@ static struct scsi_host_template hpt3x3_sht = {
static struct ata_port_operations hpt3x3_port_ops = {
.port_disable = ata_port_disable,
.set_piomode = hpt3x3_set_piomode,
+#if defined(CONFIG_PATA_HPT3X3_DMA)
.set_dmamode = hpt3x3_set_dmamode,
+#endif
.mode_filter = ata_pci_default_filter,
.tf_load = ata_tf_load,
@@ -124,6 +143,7 @@ static struct ata_port_operations hpt3x3_port_ops = {
.bmdma_start = ata_bmdma_start,
.bmdma_stop = ata_bmdma_stop,
.bmdma_status = ata_bmdma_status,
+ .check_atapi_dma= hpt3x3_atapi_dma,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -158,32 +178,79 @@ static void hpt3x3_init_chipset(struct pci_dev *dev)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
}
-
/**
* hpt3x3_init_one - Initialise an HPT343/363
- * @dev: PCI device
+ * @pdev: PCI device
* @id: Entry in match table
*
- * Perform basic initialisation. The chip has a quirk that it won't
- * function unless it is at XX00. The old ATA driver touched this up
- * but we leave it for pci quirks to do properly.
+ * Perform basic initialisation. We set the device up so we access all
+ * ports via BAR4. This is neccessary to work around errata.
*/
-static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+static int hpt3x3_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
+ static int printed_version;
static const struct ata_port_info info = {
.sht = &hpt3x3_sht,
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f,
+#if defined(CONFIG_PATA_HPT3X3_DMA)
+ /* Further debug needed */
.mwdma_mask = 0x07,
.udma_mask = 0x07,
+#endif
.port_ops = &hpt3x3_port_ops
};
+ /* Register offsets of taskfiles in BAR4 area */
+ static const u8 offset_cmd[2] = { 0x20, 0x28 };
+ static const u8 offset_ctl[2] = { 0x36, 0x3E };
const struct ata_port_info *ppi[] = { &info, NULL };
-
- hpt3x3_init_chipset(dev);
- /* Now kick off ATA set up */
- return ata_pci_init_one(dev, ppi);
+ struct ata_host *host;
+ int i, rc;
+ void __iomem *base;
+
+ hpt3x3_init_chipset(pdev);
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2);
+ if (!host)
+ return -ENOMEM;
+ /* acquire resources and fill host */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ /* Everything is relative to BAR4 if we set up this way */
+ rc = pcim_iomap_regions(pdev, 1 << 4, DRV_NAME);
+ if (rc == -EBUSY)
+ pcim_pin_device(pdev);
+ if (rc)
+ return rc;
+ host->iomap = pcim_iomap_table(pdev);
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ return rc;
+
+ base = host->iomap[4]; /* Bus mastering base */
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+
+ ioaddr->cmd_addr = base + offset_cmd[i];
+ ioaddr->altstatus_addr =
+ ioaddr->ctl_addr = base + offset_ctl[i];
+ ioaddr->scr_addr = NULL;
+ ata_std_ports(ioaddr);
+ ioaddr->bmdma_addr = base + 8 * i;
+ }
+ pci_set_master(pdev);
+ return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
+ &hpt3x3_sht);
}
#ifdef CONFIG_PM
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index b67bbf6516ba..430673be1df7 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -587,8 +587,7 @@ static int it821x_port_start(struct ata_port *ap)
itdev->want[1][1] = ATA_ANY;
itdev->last_device = -1;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &conf);
- if (conf == 0x10) {
+ if (pdev->revision == 0x11) {
itdev->timing10 = 1;
/* Need to disable ATAPI DMA for this case */
if (!itdev->smart)
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 368fac7d168b..182e83c9047b 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -467,13 +467,27 @@ mpc52xx_ata_remove(struct of_device *op)
static int
mpc52xx_ata_suspend(struct of_device *op, pm_message_t state)
{
- return 0; /* FIXME : What to do here ? */
+ struct ata_host *host = dev_get_drvdata(&op->dev);
+
+ return ata_host_suspend(host, state);
}
static int
mpc52xx_ata_resume(struct of_device *op)
{
- return 0; /* FIXME : What to do here ? */
+ struct ata_host *host = dev_get_drvdata(&op->dev);
+ struct mpc52xx_ata_priv *priv = host->private_data;
+ int rv;
+
+ rv = mpc52xx_ata_hw_init(priv);
+ if (rv) {
+ printk(KERN_ERR DRV_NAME ": Error during HW init\n");
+ return rv;
+ }
+
+ ata_host_resume(host);
+
+ return 0;
}
#endif
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index a56257c98fe5..6da23feed039 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -382,6 +382,7 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 79f841bca593..a909f793ffc1 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -213,8 +213,9 @@ static int __devinit pata_platform_probe(struct platform_device *pdev)
pata_platform_setup_port(&ap->ioaddr, pp_info);
/* activate */
- return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
- pp_info->irq_flags, &pata_platform_sht);
+ return ata_host_activate(host, platform_get_irq(pdev, 0),
+ ata_interrupt, pp_info ? pp_info->irq_flags
+ : 0, &pata_platform_sht);
}
/**
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index 61502bc7bf1d..36cdbd2b0bd5 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -258,6 +258,17 @@ static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
}
+unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+ /* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
+ if (adev->class == ATA_DEV_ATAPI &&
+ (mask & (0xE0 << ATA_SHIFT_UDMA))) {
+ printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
+ mask &= ~(0xE0 << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(adev, mask);
+}
+
/**
* scc_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
@@ -352,6 +363,8 @@ static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
tf->hob_lbal = in_be32(ioaddr->lbal_addr);
tf->hob_lbam = in_be32(ioaddr->lbam_addr);
tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+ out_be32(ioaddr->ctl_addr, tf->ctl);
+ ap->last_ctl = tf->ctl;
}
}
@@ -724,22 +737,36 @@ static void scc_bmdma_stop (struct ata_queued_cmd *qc)
static u8 scc_bmdma_status (struct ata_port *ap)
{
- u8 host_stat;
void __iomem *mmio = ap->ioaddr.bmdma_addr;
-
- host_stat = in_be32(mmio + SCC_DMA_STATUS);
-
- /* Workaround for PTERADD: emulate DMA_INTR when
- * - IDE_STATUS[ERR] = 1
- * - INT_STATUS[INTRQ] = 1
- * - DMA_STATUS[IORACTA] = 1
- */
- if (!(host_stat & ATA_DMA_INTR)) {
- u32 int_status = in_be32(mmio + SCC_DMA_INTST);
- if (ata_altstatus(ap) & ATA_ERR &&
- int_status & INTSTS_INTRQ &&
- host_stat & ATA_DMA_ACTIVE)
- host_stat |= ATA_DMA_INTR;
+ u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
+ u32 int_status = in_be32(mmio + SCC_DMA_INTST);
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+ static int retry = 0;
+
+ /* return if IOS_SS is cleared */
+ if (!(in_be32(mmio + SCC_DMA_CMD) & ATA_DMA_START))
+ return host_stat;
+
+ /* errata A252,A308 workaround: Step4 */
+ if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
+ return (host_stat | ATA_DMA_INTR);
+
+ /* errata A308 workaround Step5 */
+ if (int_status & INTSTS_IOIRQS) {
+ host_stat |= ATA_DMA_INTR;
+
+ /* We don't check ATAPI DMA because it is limited to UDMA4 */
+ if ((qc->tf.protocol == ATA_PROT_DMA &&
+ qc->dev->xfer_mode > XFER_UDMA_4)) {
+ if (!(int_status & INTSTS_ACTEINT)) {
+ printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
+ ap->print_id);
+ host_stat |= ATA_DMA_ERR;
+ if (retry++)
+ ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
+ } else
+ retry = 0;
+ }
}
return host_stat;
@@ -892,10 +919,6 @@ static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
{
DPRINTK("ENTER\n");
- /* re-enable interrupts */
- if (!ap->ops->error_handler)
- ap->ops->irq_on(ap);
-
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
ap->ops->dev_select(ap, 1);
@@ -1000,7 +1023,7 @@ static const struct ata_port_operations scc_pata_ops = {
.port_disable = ata_port_disable,
.set_piomode = scc_set_piomode,
.set_dmamode = scc_set_dmamode,
- .mode_filter = ata_pci_default_filter,
+ .mode_filter = scc_mode_filter,
.tf_load = scc_tf_load,
.tf_read = scc_tf_read,
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 0231aba51ca4..89691541fe59 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -410,11 +410,8 @@ static int serverworks_fixup_osb4(struct pci_dev *pdev)
static int serverworks_fixup_csb(struct pci_dev *pdev)
{
- u8 rev;
u8 btr;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
-
/* Third Channel Test */
if (!(PCI_FUNC(pdev->devfn) & 1)) {
struct pci_dev * findev = NULL;
@@ -456,7 +453,7 @@ static int serverworks_fixup_csb(struct pci_dev *pdev)
if (!(PCI_FUNC(pdev->devfn) & 1))
btr |= 0x2;
else
- btr |= (rev >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ btr |= (pdev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
pci_write_config_byte(pdev, 0x5A, btr);
return btr;
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 2b4508206a6c..9a829a7cbc60 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -149,6 +149,9 @@ static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
return -ENOENT;
+ /* Clear the FIFO settings. We can't enable the FIFO until
+ we know we are poking at a disk */
+ pci_write_config_byte(pdev, 0x4B, 0);
return ata_std_prereset(ap, deadline);
}
@@ -928,9 +931,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (host != NULL) {
chipset = sets; /* Match found */
if (sets->device == 0x630) { /* SIS630 */
- u8 host_rev;
- pci_read_config_byte(host, PCI_REVISION_ID, &host_rev);
- if (host_rev >= 0x30) /* 630 ET */
+ if (host->revision >= 0x30) /* 630 ET */
chipset = &sis100_early;
}
break;
@@ -974,7 +975,6 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
u16 trueid;
u8 prefctl;
u8 idecfg;
- u8 sbrev;
/* Try the second unmasking technique */
pci_read_config_byte(pdev, 0x4a, &idecfg);
@@ -987,11 +987,10 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
lpc_bridge = pci_get_slot(pdev->bus, 0x10); /* Bus 0 Dev 2 Fn 0 */
if (lpc_bridge == NULL)
break;
- pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
pci_read_config_byte(pdev, 0x49, &prefctl);
pci_dev_put(lpc_bridge);
- if (sbrev == 0x10 && (prefctl & 0x80)) {
+ if (lpc_bridge->revision == 0x10 && (prefctl & 0x80)) {
chipset = &sis133_early;
break;
}
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index bde734189623..8c2813aa6cdb 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -270,7 +270,6 @@ static struct ata_port_operations sl82c105_port_ops = {
static int sl82c105_bridge_revision(struct pci_dev *pdev)
{
struct pci_dev *bridge;
- u8 rev;
/*
* The bridge should be part of the same device, but function 0.
@@ -292,10 +291,8 @@ static int sl82c105_bridge_revision(struct pci_dev *pdev)
/*
* We need to find function 0's revision, not function 1
*/
- pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
-
pci_dev_put(bridge);
- return rev;
+ return bridge->revision;
}
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index f0cadbe6aa11..f645fe22cd1e 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -506,7 +506,6 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
struct pci_dev *isa = NULL;
const struct via_isa_bridge *config;
static int printed_version;
- u8 t;
u8 enable;
u32 timing;
@@ -520,9 +519,8 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
!!(config->flags & VIA_BAD_ID),
config->id, NULL))) {
- pci_read_config_byte(isa, PCI_REVISION_ID, &t);
- if (t >= config->rev_min &&
- t <= config->rev_max)
+ if (isa->revision >= config->rev_min &&
+ isa->revision <= config->rev_max)
break;
pci_dev_put(isa);
}
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 3de183461c3c..a9c948d7604a 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -190,34 +190,34 @@ static void inic_reset_port(void __iomem *port_base)
writew(ctl, idma_ctl);
}
-static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
void __iomem *addr;
- u32 val;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
- return 0xffffffffU;
+ return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4;
- val = readl(scr_addr + scr_map[sc_reg] * 4);
+ *val = readl(scr_addr + scr_map[sc_reg] * 4);
/* this controller has stuck DIAG.N, ignore it */
if (sc_reg == SCR_ERROR)
- val &= ~SERR_PHYRDY_CHG;
- return val;
+ *val &= ~SERR_PHYRDY_CHG;
+ return 0;
}
-static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
- return;
+ return -EINVAL;
addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
+ return 0;
}
/*
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 3873b29c80d6..8ec520885b95 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -29,19 +29,12 @@
I distinctly remember a couple workarounds (one related to PCI-X)
are still needed.
- 2) Convert to LibATA new EH. Required for hotplug, NCQ, and sane
- probing/error handling in general. MUST HAVE.
-
- 3) Add hotplug support (easy, once new-EH support appears)
-
4) Add NCQ support (easy to intermediate, once new-EH support appears)
5) Investigate problems with PCI Message Signalled Interrupts (MSI).
6) Add port multiplier support (intermediate)
- 7) Test and verify 3.0 Gbps support
-
8) Develop a low-power-consumption strategy, and implement it.
9) [Experiment, low priority] See if ATAPI can be supported using
@@ -108,8 +101,6 @@ enum {
MV_SATAHC_ARBTR_REG_SZ = MV_MINOR_REG_AREA_SZ, /* arbiter */
MV_PORT_REG_SZ = MV_MINOR_REG_AREA_SZ,
- MV_USE_Q_DEPTH = ATA_DEF_QUEUE,
-
MV_MAX_Q_DEPTH = 32,
MV_MAX_Q_DEPTH_MASK = MV_MAX_Q_DEPTH - 1,
@@ -133,18 +124,22 @@ enum {
/* Host Flags */
MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
- MV_COMMON_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
- ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
- ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING),
+ MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
+ ATA_FLAG_PIO_POLLING,
MV_6XXX_FLAGS = MV_FLAG_IRQ_COALESCE,
CRQB_FLAG_READ = (1 << 0),
CRQB_TAG_SHIFT = 1,
+ CRQB_IOID_SHIFT = 6, /* CRQB Gen-II/IIE IO Id shift */
+ CRQB_HOSTQ_SHIFT = 17, /* CRQB Gen-II/IIE HostQueTag shift */
CRQB_CMD_ADDR_SHIFT = 8,
CRQB_CMD_CS = (0x2 << 11),
CRQB_CMD_LAST = (1 << 15),
CRPB_FLAG_STATUS_SHIFT = 8,
+ CRPB_IOID_SHIFT_6 = 5, /* CRPB Gen-II IO Id shift */
+ CRPB_IOID_SHIFT_7 = 7, /* CRPB Gen-IIE IO Id shift */
EPRD_FLAG_END_OF_TBL = (1 << 31),
@@ -230,31 +225,53 @@ enum {
EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
EDMA_ERR_IRQ_MASK_OFS = 0xc,
- EDMA_ERR_D_PAR = (1 << 0),
- EDMA_ERR_PRD_PAR = (1 << 1),
- EDMA_ERR_DEV = (1 << 2),
- EDMA_ERR_DEV_DCON = (1 << 3),
- EDMA_ERR_DEV_CON = (1 << 4),
- EDMA_ERR_SERR = (1 << 5),
- EDMA_ERR_SELF_DIS = (1 << 7),
- EDMA_ERR_BIST_ASYNC = (1 << 8),
- EDMA_ERR_CRBQ_PAR = (1 << 9),
- EDMA_ERR_CRPB_PAR = (1 << 10),
- EDMA_ERR_INTRL_PAR = (1 << 11),
- EDMA_ERR_IORDY = (1 << 12),
- EDMA_ERR_LNK_CTRL_RX = (0xf << 13),
+ EDMA_ERR_D_PAR = (1 << 0), /* UDMA data parity err */
+ EDMA_ERR_PRD_PAR = (1 << 1), /* UDMA PRD parity err */
+ EDMA_ERR_DEV = (1 << 2), /* device error */
+ EDMA_ERR_DEV_DCON = (1 << 3), /* device disconnect */
+ EDMA_ERR_DEV_CON = (1 << 4), /* device connected */
+ EDMA_ERR_SERR = (1 << 5), /* SError bits [WBDST] raised */
+ EDMA_ERR_SELF_DIS = (1 << 7), /* Gen II/IIE self-disable */
+ EDMA_ERR_SELF_DIS_5 = (1 << 8), /* Gen I self-disable */
+ EDMA_ERR_BIST_ASYNC = (1 << 8), /* BIST FIS or Async Notify */
+ EDMA_ERR_TRANS_IRQ_7 = (1 << 8), /* Gen IIE transprt layer irq */
+ EDMA_ERR_CRQB_PAR = (1 << 9), /* CRQB parity error */
+ EDMA_ERR_CRPB_PAR = (1 << 10), /* CRPB parity error */
+ EDMA_ERR_INTRL_PAR = (1 << 11), /* internal parity error */
+ EDMA_ERR_IORDY = (1 << 12), /* IORdy timeout */
+ EDMA_ERR_LNK_CTRL_RX = (0xf << 13), /* link ctrl rx error */
EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
- EDMA_ERR_LNK_DATA_RX = (0xf << 17),
- EDMA_ERR_LNK_CTRL_TX = (0x1f << 21),
- EDMA_ERR_LNK_DATA_TX = (0x1f << 26),
- EDMA_ERR_TRANS_PROTO = (1 << 31),
- EDMA_ERR_FATAL = (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
- EDMA_ERR_DEV_DCON | EDMA_ERR_CRBQ_PAR |
- EDMA_ERR_CRPB_PAR | EDMA_ERR_INTRL_PAR |
- EDMA_ERR_IORDY | EDMA_ERR_LNK_CTRL_RX_2 |
- EDMA_ERR_LNK_DATA_RX |
- EDMA_ERR_LNK_DATA_TX |
- EDMA_ERR_TRANS_PROTO),
+ EDMA_ERR_LNK_DATA_RX = (0xf << 17), /* link data rx error */
+ EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), /* link ctrl tx error */
+ EDMA_ERR_LNK_DATA_TX = (0x1f << 26), /* link data tx error */
+ EDMA_ERR_TRANS_PROTO = (1 << 31), /* transport protocol error */
+ EDMA_ERR_OVERRUN_5 = (1 << 5),
+ EDMA_ERR_UNDERRUN_5 = (1 << 6),
+ EDMA_EH_FREEZE = EDMA_ERR_D_PAR |
+ EDMA_ERR_PRD_PAR |
+ EDMA_ERR_DEV_DCON |
+ EDMA_ERR_DEV_CON |
+ EDMA_ERR_SERR |
+ EDMA_ERR_SELF_DIS |
+ EDMA_ERR_CRQB_PAR |
+ EDMA_ERR_CRPB_PAR |
+ EDMA_ERR_INTRL_PAR |
+ EDMA_ERR_IORDY |
+ EDMA_ERR_LNK_CTRL_RX_2 |
+ EDMA_ERR_LNK_DATA_RX |
+ EDMA_ERR_LNK_DATA_TX |
+ EDMA_ERR_TRANS_PROTO,
+ EDMA_EH_FREEZE_5 = EDMA_ERR_D_PAR |
+ EDMA_ERR_PRD_PAR |
+ EDMA_ERR_DEV_DCON |
+ EDMA_ERR_DEV_CON |
+ EDMA_ERR_OVERRUN_5 |
+ EDMA_ERR_UNDERRUN_5 |
+ EDMA_ERR_SELF_DIS_5 |
+ EDMA_ERR_CRQB_PAR |
+ EDMA_ERR_CRPB_PAR |
+ EDMA_ERR_INTRL_PAR |
+ EDMA_ERR_IORDY,
EDMA_REQ_Q_BASE_HI_OFS = 0x10,
EDMA_REQ_Q_IN_PTR_OFS = 0x14, /* also contains BASE_LO */
@@ -267,10 +284,10 @@ enum {
EDMA_RSP_Q_OUT_PTR_OFS = 0x24, /* also contains BASE_LO */
EDMA_RSP_Q_PTR_SHIFT = 3,
- EDMA_CMD_OFS = 0x28,
- EDMA_EN = (1 << 0),
- EDMA_DS = (1 << 1),
- ATA_RST = (1 << 2),
+ EDMA_CMD_OFS = 0x28, /* EDMA command register */
+ EDMA_EN = (1 << 0), /* enable EDMA */
+ EDMA_DS = (1 << 1), /* disable EDMA; self-negated */
+ ATA_RST = (1 << 2), /* reset trans/link/phy */
EDMA_IORDY_TMOUT = 0x34,
EDMA_ARB_CFG = 0x38,
@@ -282,25 +299,28 @@ enum {
MV_HP_ERRATA_60X1B2 = (1 << 3),
MV_HP_ERRATA_60X1C0 = (1 << 4),
MV_HP_ERRATA_XX42A0 = (1 << 5),
- MV_HP_50XX = (1 << 6),
- MV_HP_GEN_IIE = (1 << 7),
+ MV_HP_GEN_I = (1 << 6), /* Generation I: 50xx */
+ MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
+ MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
/* Port private flags (pp_flags) */
- MV_PP_FLAG_EDMA_EN = (1 << 0),
- MV_PP_FLAG_EDMA_DS_ACT = (1 << 1),
+ MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
+ MV_PP_FLAG_HAD_A_RESET = (1 << 2), /* 1st hard reset complete? */
};
-#define IS_50XX(hpriv) ((hpriv)->hp_flags & MV_HP_50XX)
-#define IS_60XX(hpriv) (((hpriv)->hp_flags & MV_HP_50XX) == 0)
-#define IS_GEN_I(hpriv) IS_50XX(hpriv)
-#define IS_GEN_II(hpriv) IS_60XX(hpriv)
+#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
+#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
enum {
MV_DMA_BOUNDARY = 0xffffffffU,
+ /* mask of register bits containing lower 32 bits
+ * of EDMA request queue DMA address
+ */
EDMA_REQ_Q_BASE_LO_MASK = 0xfffffc00U,
+ /* ditto, for response queue */
EDMA_RSP_Q_BASE_LO_MASK = 0xffffff00U,
};
@@ -352,6 +372,10 @@ struct mv_port_priv {
dma_addr_t crpb_dma;
struct mv_sg *sg_tbl;
dma_addr_t sg_tbl_dma;
+
+ unsigned int req_idx;
+ unsigned int resp_idx;
+
u32 pp_flags;
};
@@ -380,18 +404,19 @@ struct mv_host_priv {
};
static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static void mv_phy_reset(struct ata_port *ap);
-static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
-static void mv_eng_timeout(struct ata_port *ap);
+static void mv_error_handler(struct ata_port *ap);
+static void mv_post_int_cmd(struct ata_queued_cmd *qc);
+static void mv_eh_freeze(struct ata_port *ap);
+static void mv_eh_thaw(struct ata_port *ap);
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -415,14 +440,31 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no);
-static void mv_stop_and_reset(struct ata_port *ap);
-static struct scsi_host_template mv_sht = {
+static struct scsi_host_template mv5_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .can_queue = MV_USE_Q_DEPTH,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = MV_MAX_SG_CT,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = 1,
+ .proc_name = DRV_NAME,
+ .dma_boundary = MV_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .slave_destroy = ata_scsi_slave_destroy,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct scsi_host_template mv6_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = MV_MAX_SG_CT,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
@@ -444,19 +486,21 @@ static const struct ata_port_operations mv5_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = mv_phy_reset,
.cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
.data_xfer = ata_data_xfer,
- .eng_timeout = mv_eng_timeout,
-
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
+ .error_handler = mv_error_handler,
+ .post_internal_cmd = mv_post_int_cmd,
+ .freeze = mv_eh_freeze,
+ .thaw = mv_eh_thaw,
+
.scr_read = mv5_scr_read,
.scr_write = mv5_scr_write,
@@ -473,19 +517,21 @@ static const struct ata_port_operations mv6_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = mv_phy_reset,
.cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
.data_xfer = ata_data_xfer,
- .eng_timeout = mv_eng_timeout,
-
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
+ .error_handler = mv_error_handler,
+ .post_internal_cmd = mv_post_int_cmd,
+ .freeze = mv_eh_freeze,
+ .thaw = mv_eh_thaw,
+
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
@@ -502,19 +548,21 @@ static const struct ata_port_operations mv_iie_ops = {
.exec_command = ata_exec_command,
.dev_select = ata_std_dev_select,
- .phy_reset = mv_phy_reset,
.cable_detect = ata_cable_sata,
.qc_prep = mv_qc_prep_iie,
.qc_issue = mv_qc_issue,
.data_xfer = ata_data_xfer,
- .eng_timeout = mv_eng_timeout,
-
.irq_clear = mv_irq_clear,
.irq_on = ata_irq_on,
.irq_ack = ata_irq_ack,
+ .error_handler = mv_error_handler,
+ .post_internal_cmd = mv_post_int_cmd,
+ .freeze = mv_eh_freeze,
+ .thaw = mv_eh_thaw,
+
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
@@ -530,38 +578,38 @@ static const struct ata_port_info mv_port_info[] = {
.port_ops = &mv5_ops,
},
{ /* chip_508x */
- .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+ .flags = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv5_ops,
},
{ /* chip_5080 */
- .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+ .flags = MV_COMMON_FLAGS | MV_FLAG_DUAL_HC,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv5_ops,
},
{ /* chip_604x */
- .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv6_ops,
},
{ /* chip_608x */
- .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- MV_FLAG_DUAL_HC),
+ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ MV_FLAG_DUAL_HC,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv6_ops,
},
{ /* chip_6042 */
- .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
- .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
@@ -709,6 +757,46 @@ static void mv_irq_clear(struct ata_port *ap)
{
}
+static void mv_set_edma_ptrs(void __iomem *port_mmio,
+ struct mv_host_priv *hpriv,
+ struct mv_port_priv *pp)
+{
+ u32 index;
+
+ /*
+ * initialize request queue
+ */
+ index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << 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);
+ writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | index,
+ port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+
+ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+ writelfl((pp->crqb_dma & 0xffffffff) | index,
+ port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+ else
+ writelfl(index, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+
+ /*
+ * initialize response queue
+ */
+ index = (pp->resp_idx & MV_MAX_Q_DEPTH_MASK) << 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);
+
+ if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
+ writelfl((pp->crpb_dma & 0xffffffff) | index,
+ port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+ else
+ writelfl(index, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+
+ writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) | index,
+ port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+}
+
/**
* mv_start_dma - Enable eDMA engine
* @base: port base address
@@ -720,9 +808,15 @@ static void mv_irq_clear(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
+static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
+ struct mv_port_priv *pp)
{
- if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
+ if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
+ /* clear EDMA event indicators, if any */
+ writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ mv_set_edma_ptrs(base, hpriv, pp);
+
writelfl(EDMA_EN, base + EDMA_CMD_OFS);
pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
}
@@ -730,7 +824,7 @@ static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
}
/**
- * mv_stop_dma - Disable eDMA engine
+ * __mv_stop_dma - Disable eDMA engine
* @ap: ATA channel to manipulate
*
* Verify the local cache of the eDMA state is accurate with a
@@ -739,14 +833,14 @@ static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
* LOCKING:
* Inherited from caller.
*/
-static void mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_port_priv *pp = ap->private_data;
u32 reg;
- int i;
+ int i, err = 0;
- if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
/* Disable EDMA if active. The disable bit auto clears.
*/
writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
@@ -758,16 +852,30 @@ static void mv_stop_dma(struct ata_port *ap)
/* now properly wait for the eDMA to stop */
for (i = 1000; i > 0; i--) {
reg = readl(port_mmio + EDMA_CMD_OFS);
- if (!(EDMA_EN & reg)) {
+ if (!(reg & EDMA_EN))
break;
- }
+
udelay(100);
}
- if (EDMA_EN & reg) {
+ if (reg & EDMA_EN) {
ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
- /* FIXME: Consider doing a reset here to recover */
+ err = -EIO;
}
+
+ return err;
+}
+
+static int mv_stop_dma(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&ap->host->lock, flags);
+ rc = __mv_stop_dma(ap);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
+
+ return rc;
}
#ifdef ATA_DEBUG
@@ -866,30 +974,35 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs)
- return readl(mv_ap_base(ap) + ofs);
- else
- return (u32) ofs;
+ if (ofs != 0xffffffffU) {
+ *val = readl(mv_ap_base(ap) + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
unsigned int ofs = mv_scr_offset(sc_reg_in);
- if (0xffffffffU != ofs)
+ if (ofs != 0xffffffffU) {
writelfl(val, mv_ap_base(ap) + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
-static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
+static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
+ void __iomem *port_mmio)
{
u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
/* set up non-NCQ EDMA configuration */
- cfg &= ~(1 << 9); /* disable equeue */
+ cfg &= ~(1 << 9); /* disable eQue */
if (IS_GEN_I(hpriv)) {
cfg &= ~0x1f; /* clear queue depth */
@@ -909,7 +1022,7 @@ static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
cfg |= (1 << 18); /* enab early completion */
cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
- cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
+ cfg &= ~(EDMA_CFG_NCQ); /* clear NCQ */
}
writelfl(cfg, port_mmio + EDMA_CFG_OFS);
@@ -933,6 +1046,7 @@ static int mv_port_start(struct ata_port *ap)
void __iomem *port_mmio = mv_ap_base(ap);
void *mem;
dma_addr_t mem_dma;
+ unsigned long flags;
int rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -971,28 +1085,13 @@ static int mv_port_start(struct ata_port *ap)
pp->sg_tbl = mem;
pp->sg_tbl_dma = mem_dma;
- mv_edma_cfg(hpriv, port_mmio);
-
- writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
- writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK,
- port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
-
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl(pp->crqb_dma & 0xffffffff,
- port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
- else
- writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+ spin_lock_irqsave(&ap->host->lock, flags);
- writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+ mv_edma_cfg(ap, hpriv, port_mmio);
- if (hpriv->hp_flags & MV_HP_ERRATA_XX42A0)
- writelfl(pp->crpb_dma & 0xffffffff,
- port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
- else
- writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+ mv_set_edma_ptrs(port_mmio, hpriv, pp);
- writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK,
- port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
/* Don't turn on EDMA here...do it before DMA commands only. Else
* we'll be unable to send non-data, PIO, etc due to restricted access
@@ -1013,11 +1112,7 @@ static int mv_port_start(struct ata_port *ap)
*/
static void mv_port_stop(struct ata_port *ap)
{
- unsigned long flags;
-
- spin_lock_irqsave(&ap->host->lock, flags);
mv_stop_dma(ap);
- spin_unlock_irqrestore(&ap->host->lock, flags);
}
/**
@@ -1055,11 +1150,6 @@ static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
return n_sg;
}
-static inline unsigned mv_inc_q_index(unsigned index)
-{
- return (index + 1) & MV_MAX_Q_DEPTH_MASK;
-}
-
static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
{
u16 tmp = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
@@ -1088,7 +1178,7 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
u16 flags = 0;
unsigned in_index;
- if (ATA_PROT_DMA != qc->tf.protocol)
+ if (qc->tf.protocol != ATA_PROT_DMA)
return;
/* Fill in command request block
@@ -1097,10 +1187,10 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
flags |= CRQB_FLAG_READ;
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
+ flags |= qc->tag << CRQB_IOID_SHIFT; /* 50xx appears to ignore this*/
- /* get current queue index from hardware */
- in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ /* get current queue index from software */
+ in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
pp->crqb[in_index].sg_addr =
cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
@@ -1180,7 +1270,7 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
unsigned in_index;
u32 flags = 0;
- if (ATA_PROT_DMA != qc->tf.protocol)
+ if (qc->tf.protocol != ATA_PROT_DMA)
return;
/* Fill in Gen IIE command request block
@@ -1190,10 +1280,11 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
+ flags |= qc->tag << CRQB_IOID_SHIFT; /* "I/O Id" is -really-
+ what we use as our tag */
- /* get current queue index from hardware */
- in_index = (readl(mv_ap_base(ap) + EDMA_REQ_Q_IN_PTR_OFS)
- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ /* get current queue index from software */
+ in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
@@ -1241,83 +1332,41 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
*/
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
{
- void __iomem *port_mmio = mv_ap_base(qc->ap);
- struct mv_port_priv *pp = qc->ap->private_data;
- unsigned in_index;
- u32 in_ptr;
+ struct ata_port *ap = qc->ap;
+ void __iomem *port_mmio = mv_ap_base(ap);
+ struct mv_port_priv *pp = ap->private_data;
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ u32 in_index;
- if (ATA_PROT_DMA != qc->tf.protocol) {
+ if (qc->tf.protocol != ATA_PROT_DMA) {
/* We're about to send a non-EDMA capable command to the
* port. Turn off EDMA so there won't be problems accessing
* shadow block, etc registers.
*/
- mv_stop_dma(qc->ap);
+ __mv_stop_dma(ap);
return ata_qc_issue_prot(qc);
}
- in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
- in_index = (in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+ mv_start_dma(port_mmio, hpriv, pp);
+
+ in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
/* until we do queuing, the queue should be empty at this point */
WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
>> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
- in_index = mv_inc_q_index(in_index); /* now incr producer index */
+ pp->req_idx++;
- mv_start_dma(port_mmio, pp);
+ in_index = (pp->req_idx & MV_MAX_Q_DEPTH_MASK) << EDMA_REQ_Q_PTR_SHIFT;
/* and write the request in pointer to kick the EDMA to life */
- in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
- in_ptr |= in_index << EDMA_REQ_Q_PTR_SHIFT;
- writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+ writelfl((pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK) | in_index,
+ port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
return 0;
}
/**
- * mv_get_crpb_status - get status from most recently completed cmd
- * @ap: ATA channel to manipulate
- *
- * This routine is for use when the port is in DMA mode, when it
- * will be using the CRPB (command response block) method of
- * returning command completion information. We check indices
- * are good, grab status, and bump the response consumer index to
- * prove that we're up to date.
- *
- * LOCKING:
- * Inherited from caller.
- */
-static u8 mv_get_crpb_status(struct ata_port *ap)
-{
- void __iomem *port_mmio = mv_ap_base(ap);
- struct mv_port_priv *pp = ap->private_data;
- unsigned out_index;
- u32 out_ptr;
- u8 ata_status;
-
- out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
- out_index = (out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
-
- ata_status = le16_to_cpu(pp->crpb[out_index].flags)
- >> CRPB_FLAG_STATUS_SHIFT;
-
- /* increment our consumer index... */
- out_index = mv_inc_q_index(out_index);
-
- /* and, until we do NCQ, there should only be 1 CRPB waiting */
- WARN_ON(out_index != ((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS)
- >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
-
- /* write out our inc'd consumer index so EDMA knows we're caught up */
- out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
- out_ptr |= out_index << EDMA_RSP_Q_PTR_SHIFT;
- writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
-
- /* Return ATA status register for completed CRPB */
- return ata_status;
-}
-
-/**
* mv_err_intr - Handle error interrupts on the port
* @ap: ATA channel to manipulate
* @reset_allowed: bool: 0 == don't trigger from reset here
@@ -1331,30 +1380,188 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_err_intr(struct ata_port *ap, int reset_allowed)
+static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
{
void __iomem *port_mmio = mv_ap_base(ap);
- u32 edma_err_cause, serr = 0;
+ 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->eh_info;
- edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ ata_ehi_clear_desc(ehi);
- if (EDMA_ERR_SERR & edma_err_cause) {
+ 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, SCR_ERROR, &serr);
sata_scr_write_flush(ap, SCR_ERROR, serr);
}
- if (EDMA_ERR_SELF_DIS & edma_err_cause) {
- struct mv_port_priv *pp = ap->private_data;
- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+
+ edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ ata_ehi_push_desc(ehi, "edma_err 0x%08x", edma_err_cause);
+
+ /*
+ * 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 |
+ EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
+ EDMA_ERR_INTRL_PAR)) {
+ err_mask |= AC_ERR_ATA_BUS;
+ action |= ATA_EH_HARDRESET;
+ ata_ehi_push_desc(ehi, "parity error");
+ }
+ if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
+ "dev disconnect" : "dev connect");
+ }
+
+ if (IS_GEN_I(hpriv)) {
+ eh_freeze_mask = EDMA_EH_FREEZE_5;
+
+ if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
+ struct mv_port_priv *pp = ap->private_data;
+ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ ata_ehi_push_desc(ehi, "EDMA self-disable");
+ }
+ } else {
+ eh_freeze_mask = EDMA_EH_FREEZE;
+
+ if (edma_err_cause & EDMA_ERR_SELF_DIS) {
+ struct mv_port_priv *pp = ap->private_data;
+ pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ ata_ehi_push_desc(ehi, "EDMA self-disable");
+ }
+
+ if (edma_err_cause & EDMA_ERR_SERR) {
+ sata_scr_read(ap, SCR_ERROR, &serr);
+ sata_scr_write_flush(ap, SCR_ERROR, serr);
+ err_mask = AC_ERR_ATA_BUS;
+ action |= ATA_EH_HARDRESET;
+ }
}
- DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
- "SERR: 0x%08x\n", ap->print_id, edma_err_cause, serr);
/* Clear EDMA now that SERR cleanup done */
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- /* check for fatal here and recover if needed */
- if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
- mv_stop_and_reset(ap);
+ if (!err_mask) {
+ err_mask = AC_ERR_OTHER;
+ action |= ATA_EH_HARDRESET;
+ }
+
+ ehi->serror |= serr;
+ ehi->action |= action;
+
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
+
+ if (edma_err_cause & eh_freeze_mask)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
+}
+
+static void mv_intr_pio(struct ata_port *ap)
+{
+ 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;
+
+ /* get active ATA command */
+ qc = ata_qc_from_tag(ap, ap->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);
+}
+
+static void mv_intr_edma(struct ata_port *ap)
+{
+ 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;
+ bool work_done = false;
+
+ /* get h/w response queue pointer */
+ 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;
+ unsigned int tag;
+
+ /* get s/w response queue last-read pointer, and compare */
+ out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
+ if (in_index == out_index)
+ break;
+
+ /* 50xx: get active ATA command */
+ if (IS_GEN_I(hpriv))
+ tag = ap->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 if (IS_GEN_II(hpriv))
+ tag = (le16_to_cpu(pp->crpb[out_index].id)
+ >> CRPB_IOID_SHIFT_6) & 0x3f;
+
+ else /* IS_GEN_IIE */
+ tag = (le16_to_cpu(pp->crpb[out_index].id)
+ >> CRPB_IOID_SHIFT_7) & 0x3f;
+
+ qc = ata_qc_from_tag(ap, tag);
+
+ /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
+ * bits (WARNING: might not necessarily be associated
+ * with this command), which -should- be clear
+ * if all is well
+ */
+ status = le16_to_cpu(pp->crpb[out_index].flags);
+ if (unlikely(status & 0xff)) {
+ 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);
+ }
+
+ /* advance software response queue pointer, to
+ * indicate (after the loop completes) to hardware
+ * that we have consumed a response queue entry.
+ */
+ work_done = true;
+ pp->resp_idx++;
+ }
+
+ if (work_done)
+ writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
+ (out_index << EDMA_RSP_Q_PTR_SHIFT),
+ port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
}
/**
@@ -1377,10 +1584,8 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
{
void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
void __iomem *hc_mmio = mv_hc_base(mmio, hc);
- struct ata_queued_cmd *qc;
u32 hc_irq_cause;
- int shift, port, port0, hard_port, handled;
- unsigned int err_mask;
+ int port, port0;
if (hc == 0)
port0 = 0;
@@ -1389,79 +1594,95 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
/* 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)
- writelfl(~hc_irq_cause, 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 < port0 + MV_PORTS_PER_HC; port++) {
- u8 ata_status = 0;
struct ata_port *ap = host->ports[port];
struct mv_port_priv *pp = ap->private_data;
+ int have_err_bits, hard_port, shift;
+
+ if ((!ap) || (ap->flags & ATA_FLAG_DISABLED))
+ continue;
+
+ 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->active_tag);
+ if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
+ continue;
+
+ mv_err_intr(ap, qc);
+ continue;
+ }
hard_port = mv_hardport_from_port(port); /* range 0..3 */
- handled = 0; /* ensure ata_status is set if handled++ */
- /* Note that DEV_IRQ might happen spuriously during EDMA,
- * and should be ignored in such cases.
- * The cause of this is still under investigation.
- */
if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
- /* EDMA: check for response queue interrupt */
- if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
- ata_status = mv_get_crpb_status(ap);
- handled = 1;
- }
+ if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause)
+ mv_intr_edma(ap);
} else {
- /* PIO: check for device (drive) interrupt */
- if ((DEV_IRQ << hard_port) & hc_irq_cause) {
- ata_status = readb(ap->ioaddr.status_addr);
- handled = 1;
- /* ignore spurious intr if drive still BUSY */
- if (ata_status & ATA_BUSY) {
- ata_status = 0;
- handled = 0;
- }
- }
+ if ((DEV_IRQ << hard_port) & hc_irq_cause)
+ mv_intr_pio(ap);
}
+ }
+ VPRINTK("EXIT\n");
+}
- if (ap && (ap->flags & ATA_FLAG_DISABLED))
- continue;
+static void mv_pci_error(struct ata_host *host, void __iomem *mmio)
+{
+ struct ata_port *ap;
+ struct ata_queued_cmd *qc;
+ struct ata_eh_info *ehi;
+ unsigned int i, err_mask, printed = 0;
+ u32 err_cause;
- err_mask = ac_err_mask(ata_status);
+ err_cause = readl(mmio + PCI_IRQ_CAUSE_OFS);
- shift = port << 1; /* (port * 2) */
- if (port >= MV_PORTS_PER_HC) {
- shift++; /* skip bit 8 in the HC Main IRQ reg */
- }
- if ((PORT0_ERR << shift) & relevant) {
- mv_err_intr(ap, 1);
- err_mask |= AC_ERR_OTHER;
- handled = 1;
- }
+ dev_printk(KERN_ERR, host->dev, "PCI ERROR; PCI IRQ cause=0x%08x\n",
+ err_cause);
+
+ DPRINTK("All regs @ PCI error\n");
+ mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
- if (handled) {
+ writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
+
+ for (i = 0; i < host->n_ports; i++) {
+ ap = host->ports[i];
+ if (!ata_port_offline(ap)) {
+ ehi = &ap->eh_info;
+ ata_ehi_clear_desc(ehi);
+ if (!printed++)
+ ata_ehi_push_desc(ehi,
+ "PCI err cause 0x%08x", err_cause);
+ err_mask = AC_ERR_HOST_BUS;
+ ehi->action = ATA_EH_HARDRESET;
qc = ata_qc_from_tag(ap, ap->active_tag);
- if (qc && (qc->flags & ATA_QCFLAG_ACTIVE)) {
- VPRINTK("port %u IRQ found for qc, "
- "ata_status 0x%x\n", port,ata_status);
- /* mark qc status appropriately */
- if (!(qc->tf.flags & ATA_TFLAG_POLLING)) {
- qc->err_mask |= err_mask;
- ata_qc_complete(qc);
- }
- }
+ if (qc)
+ qc->err_mask |= err_mask;
+ else
+ ehi->err_mask |= err_mask;
+
+ ata_port_freeze(ap);
}
}
- VPRINTK("EXIT\n");
}
/**
- * mv_interrupt -
+ * mv_interrupt - Main interrupt event handler
* @irq: unused
* @dev_instance: private data; in this case the host structure
- * @regs: unused
*
* Read the read only register to determine if any host
* controllers have pending interrupts. If so, call lower level
@@ -1477,7 +1698,6 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
struct ata_host *host = dev_instance;
unsigned int hc, handled = 0, n_hcs;
void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
- struct mv_host_priv *hpriv;
u32 irq_stat;
irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
@@ -1491,34 +1711,21 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
n_hcs = mv_get_hc_count(host->ports[0]->flags);
spin_lock(&host->lock);
+ if (unlikely(irq_stat & PCI_ERR)) {
+ 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++;
- }
- }
-
- hpriv = host->private_data;
- if (IS_60XX(hpriv)) {
- /* deal with the interrupt coalescing bits */
- if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
- writelfl(0, mmio + MV_IRQ_COAL_CAUSE_LO);
- writelfl(0, mmio + MV_IRQ_COAL_CAUSE_HI);
- writelfl(0, mmio + MV_IRQ_COAL_CAUSE);
+ handled = 1;
}
}
- if (PCI_ERR & irq_stat) {
- printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
- readl(mmio + PCI_IRQ_CAUSE_OFS));
-
- DPRINTK("All regs @ PCI error\n");
- mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
-
- writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
- handled++;
- }
+out_unlock:
spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
@@ -1549,36 +1756,37 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
return ofs;
}
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
{
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
- if (ofs != 0xffffffffU)
- return readl(addr + ofs);
- else
- return (u32) ofs;
+ if (ofs != 0xffffffffU) {
+ *val = readl(addr + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
- if (ofs != 0xffffffffU)
+ if (ofs != 0xffffffffU) {
writelfl(val, addr + ofs);
+ return 0;
+ } else
+ return -EINVAL;
}
static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
{
- u8 rev_id;
int early_5080;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
-
- early_5080 = (pdev->device == 0x5080) && (rev_id == 0);
+ early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
if (!early_5080) {
u32 tmp = readl(mmio + MV_PCI_EXP_ROM_BAR_CTL);
@@ -1907,7 +2115,7 @@ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
- if (IS_60XX(hpriv)) {
+ if (IS_GEN_II(hpriv)) {
u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
ifctl |= (1 << 7); /* enable gen2i speed */
ifctl = (ifctl & 0xfff) | 0x9b1000; /* from chip spec */
@@ -1923,32 +2131,12 @@ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
hpriv->ops->phy_errata(hpriv, mmio, port_no);
- if (IS_50XX(hpriv))
+ if (IS_GEN_I(hpriv))
mdelay(1);
}
-static void mv_stop_and_reset(struct ata_port *ap)
-{
- struct mv_host_priv *hpriv = ap->host->private_data;
- void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
-
- mv_stop_dma(ap);
-
- mv_channel_reset(hpriv, mmio, ap->port_no);
-
- __mv_phy_reset(ap, 0);
-}
-
-static inline void __msleep(unsigned int msec, int can_sleep)
-{
- if (can_sleep)
- msleep(msec);
- else
- mdelay(msec);
-}
-
/**
- * __mv_phy_reset - Perform eDMA reset followed by COMRESET
+ * mv_phy_reset - Perform eDMA reset followed by COMRESET
* @ap: ATA channel to manipulate
*
* Part of this is taken from __sata_phy_reset and modified to
@@ -1958,57 +2146,65 @@ static inline void __msleep(unsigned int msec, int can_sleep)
* Inherited from caller. This is coded to safe to call at
* interrupt level, i.e. it does not sleep.
*/
-static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
+static void mv_phy_reset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
struct mv_port_priv *pp = ap->private_data;
struct mv_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = mv_ap_base(ap);
- struct ata_taskfile tf;
- struct ata_device *dev = &ap->device[0];
- unsigned long timeout;
int retry = 5;
u32 sstatus;
VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
- DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+ {
+ u32 sstatus, serror, scontrol;
+
+ mv_scr_read(ap, SCR_STATUS, &sstatus);
+ mv_scr_read(ap, SCR_ERROR, &serror);
+ mv_scr_read(ap, SCR_CONTROL, &scontrol);
+ DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", status, serror, scontrol);
+ }
+#endif
/* Issue COMRESET via SControl */
comreset_retry:
sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
- __msleep(1, can_sleep);
+ msleep(1);
sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
- __msleep(20, can_sleep);
+ msleep(20);
- timeout = jiffies + msecs_to_jiffies(200);
do {
sata_scr_read(ap, SCR_STATUS, &sstatus);
if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
break;
- __msleep(1, can_sleep);
- } while (time_before(jiffies, timeout));
+ msleep(1);
+ } while (time_before(jiffies, deadline));
/* work around errata */
- if (IS_60XX(hpriv) &&
+ if (IS_GEN_II(hpriv) &&
(sstatus != 0x0) && (sstatus != 0x113) && (sstatus != 0x123) &&
(retry-- > 0))
goto comreset_retry;
- DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
- "SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
- mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+ {
+ u32 sstatus, serror, scontrol;
- if (ata_port_online(ap)) {
- ata_port_probe(ap);
- } else {
- sata_scr_read(ap, SCR_STATUS, &sstatus);
- ata_port_printk(ap, KERN_INFO,
- "no device found (phy stat %08x)\n", sstatus);
- ata_port_disable(ap);
+ mv_scr_read(ap, SCR_STATUS, &sstatus);
+ mv_scr_read(ap, SCR_ERROR, &serror);
+ mv_scr_read(ap, SCR_CONTROL, &scontrol);
+ DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+ "SCtrl 0x%08x\n", sstatus, serror, scontrol);
+ }
+#endif
+
+ if (ata_port_offline(ap)) {
+ *class = ATA_DEV_NONE;
return;
}
@@ -2022,68 +2218,152 @@ comreset_retry:
u8 drv_stat = ata_check_status(ap);
if ((drv_stat != 0x80) && (drv_stat != 0x7f))
break;
- __msleep(500, can_sleep);
+ msleep(500);
if (retry-- <= 0)
break;
+ if (time_after(jiffies, deadline))
+ break;
}
- tf.lbah = readb(ap->ioaddr.lbah_addr);
- tf.lbam = readb(ap->ioaddr.lbam_addr);
- tf.lbal = readb(ap->ioaddr.lbal_addr);
- tf.nsect = readb(ap->ioaddr.nsect_addr);
+ /* FIXME: if we passed the deadline, the following
+ * code probably produces an invalid result
+ */
- dev->class = ata_dev_classify(&tf);
- if (!ata_dev_enabled(dev)) {
- VPRINTK("Port disabled post-sig: No device present.\n");
- ata_port_disable(ap);
- }
+ /* finally, read device signature from TF registers */
+ *class = ata_dev_try_classify(ap, 0, NULL);
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ WARN_ON(pp->pp_flags & MV_PP_FLAG_EDMA_EN);
VPRINTK("EXIT\n");
}
-static void mv_phy_reset(struct ata_port *ap)
+static int mv_prereset(struct ata_port *ap, unsigned long deadline)
{
- __mv_phy_reset(ap, 1);
+ struct mv_port_priv *pp = ap->private_data;
+ struct ata_eh_context *ehc = &ap->eh_context;
+ int rc;
+
+ rc = mv_stop_dma(ap);
+ if (rc)
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ if (!(pp->pp_flags & MV_PP_FLAG_HAD_A_RESET)) {
+ pp->pp_flags |= MV_PP_FLAG_HAD_A_RESET;
+ ehc->i.action |= ATA_EH_HARDRESET;
+ }
+
+ /* if we're about to do hardreset, nothing more to do */
+ if (ehc->i.action & ATA_EH_HARDRESET)
+ return 0;
+
+ if (ata_port_online(ap))
+ rc = ata_wait_ready(ap, deadline);
+ else
+ rc = -ENODEV;
+
+ return rc;
}
-/**
- * mv_eng_timeout - Routine called by libata when SCSI times out I/O
- * @ap: ATA channel to manipulate
- *
- * Intent is to clear all pending error conditions, reset the
- * chip/bus, fail the command, and move on.
- *
- * LOCKING:
- * This routine holds the host lock while failing the command.
- */
-static void mv_eng_timeout(struct ata_port *ap)
+static int mv_hardreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
{
+ struct mv_host_priv *hpriv = ap->host->private_data;
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
- struct ata_queued_cmd *qc;
- unsigned long flags;
- ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
- DPRINTK("All regs @ start of eng_timeout\n");
- mv_dump_all_regs(mmio, ap->port_no, to_pci_dev(ap->host->dev));
+ mv_stop_dma(ap);
- qc = ata_qc_from_tag(ap, ap->active_tag);
- printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
- mmio, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
+ mv_channel_reset(hpriv, mmio, ap->port_no);
- spin_lock_irqsave(&ap->host->lock, flags);
- mv_err_intr(ap, 0);
- mv_stop_and_reset(ap);
- spin_unlock_irqrestore(&ap->host->lock, flags);
+ mv_phy_reset(ap, class, deadline);
- WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
- if (qc->flags & ATA_QCFLAG_ACTIVE) {
- qc->err_mask |= AC_ERR_TIMEOUT;
- ata_eh_qc_complete(qc);
+ return 0;
+}
+
+static void mv_postreset(struct ata_port *ap, unsigned int *classes)
+{
+ u32 serr;
+
+ /* print link status */
+ sata_print_link_status(ap);
+
+ /* clear SError */
+ sata_scr_read(ap, SCR_ERROR, &serr);
+ sata_scr_write_flush(ap, SCR_ERROR, serr);
+
+ /* bail out if no device is present */
+ if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+ DPRINTK("EXIT, no device\n");
+ return;
+ }
+
+ /* set up device control */
+ iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
+}
+
+static void mv_error_handler(struct ata_port *ap)
+{
+ ata_do_eh(ap, mv_prereset, ata_std_softreset,
+ mv_hardreset, mv_postreset);
+}
+
+static void mv_post_int_cmd(struct ata_queued_cmd *qc)
+{
+ mv_stop_dma(qc->ap);
+}
+
+static void mv_eh_freeze(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ unsigned int hc = (ap->port_no > 3) ? 1 : 0;
+ u32 tmp, mask;
+ unsigned int shift;
+
+ /* FIXME: handle coalescing completion events properly */
+
+ shift = ap->port_no * 2;
+ if (hc > 0)
+ shift++;
+
+ mask = 0x3 << shift;
+
+ /* disable assertion of portN err, done events */
+ tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
+ writelfl(tmp & ~mask, mmio + HC_MAIN_IRQ_MASK_OFS);
+}
+
+static void mv_eh_thaw(struct ata_port *ap)
+{
+ void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
+ unsigned int hc = (ap->port_no > 3) ? 1 : 0;
+ void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+ void __iomem *port_mmio = mv_ap_base(ap);
+ u32 tmp, mask, hc_irq_cause;
+ unsigned int shift, hc_port_no = ap->port_no;
+
+ /* FIXME: handle coalescing completion events properly */
+
+ shift = ap->port_no * 2;
+ if (hc > 0) {
+ shift++;
+ hc_port_no -= 4;
}
+
+ mask = 0x3 << shift;
+
+ /* 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);
+
+ /* enable assertion of portN err, done events */
+ tmp = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
+ writelfl(tmp | mask, mmio + HC_MAIN_IRQ_MASK_OFS);
}
/**
@@ -2139,17 +2419,14 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct mv_host_priv *hpriv = host->private_data;
- u8 rev_id;
u32 hp_flags = hpriv->hp_flags;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
-
switch(board_idx) {
case chip_5080:
hpriv->ops = &mv5xxx_ops;
- hp_flags |= MV_HP_50XX;
+ hp_flags |= MV_HP_GEN_I;
- switch (rev_id) {
+ switch (pdev->revision) {
case 0x1:
hp_flags |= MV_HP_ERRATA_50XXB0;
break;
@@ -2167,9 +2444,9 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
case chip_504x:
case chip_508x:
hpriv->ops = &mv5xxx_ops;
- hp_flags |= MV_HP_50XX;
+ hp_flags |= MV_HP_GEN_I;
- switch (rev_id) {
+ switch (pdev->revision) {
case 0x0:
hp_flags |= MV_HP_ERRATA_50XXB0;
break;
@@ -2187,8 +2464,9 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
case chip_604x:
case chip_608x:
hpriv->ops = &mv6xxx_ops;
+ hp_flags |= MV_HP_GEN_II;
- switch (rev_id) {
+ switch (pdev->revision) {
case 0x7:
hp_flags |= MV_HP_ERRATA_60X1B2;
break;
@@ -2206,10 +2484,9 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
case chip_7042:
case chip_6042:
hpriv->ops = &mv6xxx_ops;
-
hp_flags |= MV_HP_GEN_IIE;
- switch (rev_id) {
+ switch (pdev->revision) {
case 0x0:
hp_flags |= MV_HP_ERRATA_XX42A0;
break;
@@ -2273,7 +2550,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
hpriv->ops->enable_leds(hpriv, mmio);
for (port = 0; port < host->n_ports; port++) {
- if (IS_60XX(hpriv)) {
+ if (IS_GEN_II(hpriv)) {
void __iomem *port_mmio = mv_port_base(mmio, port);
u32 ifctl = readl(port_mmio + SATA_INTERFACE_CTL);
@@ -2308,7 +2585,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
/* and unmask interrupt generation for host regs */
writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
- if (IS_50XX(hpriv))
+ if (IS_GEN_I(hpriv))
writelfl(~HC_MAIN_MASKED_IRQS_5, mmio + HC_MAIN_IRQ_MASK_OFS);
else
writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
@@ -2337,14 +2614,12 @@ static void mv_print_info(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct mv_host_priv *hpriv = host->private_data;
- u8 rev_id, scc;
+ u8 scc;
const char *scc_s, *gen;
/* Use this to determine the HW stepping of the chip so we know
* what errata to workaround
*/
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
-
pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
if (scc == 0)
scc_s = "SCSI";
@@ -2426,8 +2701,9 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
mv_print_info(host);
pci_set_master(pdev);
+ pci_try_set_mwi(pdev);
return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
- &mv_sht);
+ IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
}
static int __init mv_init(void)
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index b2656867c647..0b58c4df6fd2 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -236,8 +236,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap);
@@ -715,19 +715,20 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
int freeze = 0;
ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+ __ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
if (flags & NV_CPB_RESP_ATA_ERR) {
- ata_ehi_push_desc(ehi, ": ATA error");
+ ata_ehi_push_desc(ehi, "ATA error");
ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CMD_ERR) {
- ata_ehi_push_desc(ehi, ": CMD error");
+ ata_ehi_push_desc(ehi, "CMD error");
ehi->err_mask |= AC_ERR_DEV;
} else if (flags & NV_CPB_RESP_CPB_ERR) {
- ata_ehi_push_desc(ehi, ": CPB error");
+ ata_ehi_push_desc(ehi, "CPB error");
ehi->err_mask |= AC_ERR_SYSTEM;
freeze = 1;
} else {
/* notifier error, but no error in CPB flags? */
+ ata_ehi_push_desc(ehi, "unknown");
ehi->err_mask |= AC_ERR_OTHER;
freeze = 1;
}
@@ -854,20 +855,21 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
struct ata_eh_info *ehi = &ap->eh_info;
ata_ehi_clear_desc(ehi);
- ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+ __ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
if (status & NV_ADMA_STAT_TIMEOUT) {
ehi->err_mask |= AC_ERR_SYSTEM;
- ata_ehi_push_desc(ehi, ": timeout");
+ ata_ehi_push_desc(ehi, "timeout");
} else if (status & NV_ADMA_STAT_HOTPLUG) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ": hotplug");
+ ata_ehi_push_desc(ehi, "hotplug");
} else if (status & NV_ADMA_STAT_HOTUNPLUG) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ": hot unplug");
+ ata_ehi_push_desc(ehi, "hot unplug");
} else if (status & NV_ADMA_STAT_SERROR) {
/* let libata analyze SError and figure out the cause */
- ata_ehi_push_desc(ehi, ": SError");
- }
+ ata_ehi_push_desc(ehi, "SError");
+ } else
+ ata_ehi_push_desc(ehi, "unknown");
ata_port_freeze(ap);
continue;
}
@@ -1391,20 +1393,22 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
return ret;
}
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
- return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
static void nv_nf2_freeze(struct ata_port *ap)
@@ -1560,7 +1564,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
ppi[0] = &nv_port_info[type];
- rc = ata_pci_prepare_native_host(pdev, ppi, &host);
+ rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
if (rc)
return rc;
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index 2ad5872fe90c..d39ebc23c4a9 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,7 +45,7 @@
#include "sata_promise.h"
#define DRV_NAME "sata_promise"
-#define DRV_VERSION "2.08"
+#define DRV_VERSION "2.09"
enum {
PDC_MAX_PORTS = 4,
@@ -128,8 +128,8 @@ struct pdc_port_priv {
dma_addr_t pkt_dma;
};
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap);
@@ -427,19 +427,20 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
return ATA_CBL_SATA;
}
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -642,8 +643,12 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
| PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
ac_err_mask |= AC_ERR_HOST_BUS;
- if (sata_scr_valid(ap))
- ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+ if (sata_scr_valid(ap)) {
+ u32 serror;
+
+ pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+ ehi->serror |= serror;
+ }
qc->err_mask |= ac_err_mask;
@@ -716,6 +721,9 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
unsigned int i, tmp;
unsigned int handled = 0;
void __iomem *mmio_base;
+ unsigned int hotplug_offset, ata_no;
+ u32 hotplug_status;
+ int is_sataii_tx4;
VPRINTK("ENTER\n");
@@ -726,10 +734,20 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
mmio_base = host->iomap[PDC_MMIO_BAR];
+ /* read and clear hotplug flags for all ports */
+ if (host->ports[0]->flags & PDC_FLAG_GEN_II)
+ hotplug_offset = PDC2_SATA_PLUG_CSR;
+ else
+ hotplug_offset = PDC_SATA_PLUG_CSR;
+ hotplug_status = readl(mmio_base + hotplug_offset);
+ if (hotplug_status & 0xff)
+ writel(hotplug_status | 0xff, mmio_base + hotplug_offset);
+ hotplug_status &= 0xff; /* clear uninteresting bits */
+
/* reading should also clear interrupts */
mask = readl(mmio_base + PDC_INT_SEQMASK);
- if (mask == 0xffffffff) {
+ if (mask == 0xffffffff && hotplug_status == 0) {
VPRINTK("QUICK EXIT 2\n");
return IRQ_NONE;
}
@@ -737,16 +755,34 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
spin_lock(&host->lock);
mask &= 0xffff; /* only 16 tags possible */
- if (!mask) {
+ if (mask == 0 && hotplug_status == 0) {
VPRINTK("QUICK EXIT 3\n");
goto done_irq;
}
writel(mask, mmio_base + PDC_INT_SEQMASK);
+ is_sataii_tx4 = pdc_is_sataii_tx4(host->ports[0]->flags);
+
for (i = 0; i < host->n_ports; i++) {
VPRINTK("port %u\n", i);
ap = host->ports[i];
+
+ /* check for a plug or unplug event */
+ ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
+ tmp = hotplug_status & (0x11 << ata_no);
+ if (tmp && ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_eh_info *ehi = &ap->eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_hotplugged(ehi);
+ ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);
+ ata_port_freeze(ap);
+ ++handled;
+ continue;
+ }
+
+ /* check for a packet interrupt */
tmp = mask & (1 << (i + 1));
if (tmp && ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
@@ -902,9 +938,9 @@ static void pdc_host_init(struct ata_host *host)
tmp = readl(mmio + hotplug_offset);
writel(tmp | 0xff, mmio + hotplug_offset);
- /* mask plug/unplug ints */
+ /* unmask plug/unplug ints */
tmp = readl(mmio + hotplug_offset);
- writel(tmp | 0xff0000, mmio + hotplug_offset);
+ writel(tmp & ~0xff0000, mmio + hotplug_offset);
/* don't initialise TBG or SLEW on 2nd generation chips */
if (is_gen2)
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 9ab554da89bf..c8f9242e7f44 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -111,8 +111,8 @@ struct qs_port_priv {
qs_state_t state;
};
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
@@ -255,18 +255,20 @@ static void qs_eng_timeout(struct ata_port *ap)
ata_eng_timeout(ap);
}
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return ~0U;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+ return 0;
}
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+ return 0;
}
static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -337,7 +339,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
buf[28] = dflags;
/* frame information structure (FIS) */
- ata_tf_to_fis(&qc->tf, &buf[32], 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
}
static inline void qs_packet_start(struct ata_queued_cmd *qc)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 2a86dc4598d0..db6763758952 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -115,8 +115,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev);
#endif
static void sil_dev_config(struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
@@ -350,19 +350,26 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap, unsigned int sc_re
return NULL;
}
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
void __iomem *mmio = sil_scr_addr(ap, sc_reg);
- if (mmio)
- return readl(mmio);
- return 0xffffffffU;
+
+ if (mmio) {
+ *val = readl(mmio);
+ return 0;
+ }
+ return -EINVAL;
}
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
void __iomem *mmio = sil_scr_addr(ap, sc_reg);
- if (mmio)
+
+ if (mmio) {
writel(val, mmio);
+ return 0;
+ }
+ return -EINVAL;
}
static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
@@ -378,7 +385,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately.
*/
- serror = sil_scr_read(ap, SCR_ERROR);
+ sil_scr_read(ap, SCR_ERROR, &serror);
sil_scr_write(ap, SCR_ERROR, serror);
/* Trigger hotplug and accumulate SError only if the
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ac43a30ebe29..46fbbe7f121c 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -326,8 +326,8 @@ struct sil24_port_priv {
static void sil24_dev_config(struct ata_device *dev);
static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@@ -464,15 +464,15 @@ static void sil24_dev_config(struct ata_device *dev)
writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
}
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
{
- struct sil24_port_priv *pp = ap->private_data;
void __iomem *port = ap->ioaddr.cmd_addr;
- struct sil24_prb __iomem *prb = port;
+ struct sil24_prb __iomem *prb;
u8 fis[6 * 4];
- memcpy_fromio(fis, prb->fis, 6 * 4);
- ata_tf_from_fis(fis, &pp->tf);
+ prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+ memcpy_fromio(fis, prb->fis, sizeof(fis));
+ ata_tf_from_fis(fis, tf);
}
static u8 sil24_check_status(struct ata_port *ap)
@@ -488,25 +488,30 @@ static int sil24_scr_map[] = {
[SCR_ACTIVE] = 3,
};
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
- return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+ *val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+ return 0;
}
- return 0xffffffffU;
+ return -EINVAL;
}
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr;
addr = scr_addr + sil24_scr_map[sc_reg] * 4;
writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+ return 0;
}
+ return -EINVAL;
}
static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -531,15 +536,60 @@ static int sil24_init_port(struct ata_port *ap)
return 0;
}
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
- unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+ const struct ata_taskfile *tf,
+ int is_cmd, u32 ctrl,
+ unsigned long timeout_msec)
{
void __iomem *port = ap->ioaddr.cmd_addr;
struct sil24_port_priv *pp = ap->private_data;
struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
dma_addr_t paddr = pp->cmd_block_dma;
- u32 mask, irq_stat;
+ u32 irq_enabled, irq_mask, irq_stat;
+ int rc;
+
+ prb->ctrl = cpu_to_le16(ctrl);
+ ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+ /* temporarily plug completion and error interrupts */
+ irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+ writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+ writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+ writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+ irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+ irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+ 10, timeout_msec);
+
+ writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+ irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+ if (irq_stat & PORT_IRQ_COMPLETE)
+ rc = 0;
+ else {
+ /* force port into known state */
+ sil24_init_port(ap);
+
+ if (irq_stat & PORT_IRQ_ERROR)
+ rc = -EIO;
+ else
+ rc = -EBUSY;
+ }
+
+ /* restore IRQ enabled */
+ writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+ return rc;
+}
+
+static int sil24_do_softreset(struct ata_port *ap, unsigned int *class,
+ int pmp, unsigned long deadline)
+{
+ unsigned long timeout_msec = 0;
+ struct ata_taskfile tf;
const char *reason;
+ int rc;
DPRINTK("ENTER\n");
@@ -556,29 +606,22 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
}
/* do SRST */
- prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
- prb->fis[1] = 0; /* no PMP yet */
-
- writel((u32)paddr, port + PORT_CMD_ACTIVATE);
- writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
- mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
- irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
- 100, jiffies_to_msecs(deadline - jiffies));
-
- writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
- irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
- if (!(irq_stat & PORT_IRQ_COMPLETE)) {
- if (irq_stat & PORT_IRQ_ERROR)
- reason = "SRST command error";
- else
- reason = "timeout";
+ if (time_after(deadline, jiffies))
+ timeout_msec = jiffies_to_msecs(deadline - jiffies);
+
+ ata_tf_init(ap->device, &tf); /* doesn't really matter */
+ rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+ timeout_msec);
+ if (rc == -EBUSY) {
+ reason = "timeout";
+ goto err;
+ } else if (rc) {
+ reason = "SRST command error";
goto err;
}
- sil24_update_tf(ap);
- *class = ata_dev_classify(&pp->tf);
+ sil24_read_tf(ap, 0, &tf);
+ *class = ata_dev_classify(&tf);
if (*class == ATA_DEV_UNKNOWN)
*class = ATA_DEV_NONE;
@@ -592,6 +635,12 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class,
return -EIO;
}
+static int sil24_softreset(struct ata_port *ap, unsigned int *class,
+ unsigned long deadline)
+{
+ return sil24_do_softreset(ap, class, 0, deadline);
+}
+
static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
unsigned long deadline)
{
@@ -699,7 +748,7 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc)
}
prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, prb->fis, 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge);
@@ -754,6 +803,7 @@ static void sil24_thaw(struct ata_port *ap)
static void sil24_error_intr(struct ata_port *ap)
{
void __iomem *port = ap->ioaddr.cmd_addr;
+ struct sil24_port_priv *pp = ap->private_data;
struct ata_eh_info *ehi = &ap->eh_info;
int freeze = 0;
u32 irq_stat;
@@ -769,16 +819,16 @@ static void sil24_error_intr(struct ata_port *ap)
if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
ata_ehi_hotplugged(ehi);
- ata_ehi_push_desc(ehi, ", %s",
- irq_stat & PORT_IRQ_PHYRDY_CHG ?
- "PHY RDY changed" : "device exchanged");
+ ata_ehi_push_desc(ehi, "%s",
+ irq_stat & PORT_IRQ_PHYRDY_CHG ?
+ "PHY RDY changed" : "device exchanged");
freeze = 1;
}
if (irq_stat & PORT_IRQ_UNK_FIS) {
ehi->err_mask |= AC_ERR_HSM;
ehi->action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi , ", unknown FIS");
+ ata_ehi_push_desc(ehi, "unknown FIS");
freeze = 1;
}
@@ -797,18 +847,18 @@ static void sil24_error_intr(struct ata_port *ap)
if (ci && ci->desc) {
err_mask |= ci->err_mask;
action |= ci->action;
- ata_ehi_push_desc(ehi, ", %s", ci->desc);
+ ata_ehi_push_desc(ehi, "%s", ci->desc);
} else {
err_mask |= AC_ERR_OTHER;
action |= ATA_EH_SOFTRESET;
- ata_ehi_push_desc(ehi, ", unknown command error %d",
+ ata_ehi_push_desc(ehi, "unknown command error %d",
cerr);
}
/* record error info */
qc = ata_qc_from_tag(ap, ap->active_tag);
if (qc) {
- sil24_update_tf(ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
qc->err_mask |= err_mask;
} else
ehi->err_mask |= err_mask;
@@ -825,8 +875,11 @@ static void sil24_error_intr(struct ata_port *ap)
static void sil24_finish_qc(struct ata_queued_cmd *qc)
{
+ struct ata_port *ap = qc->ap;
+ struct sil24_port_priv *pp = ap->private_data;
+
if (qc->flags & ATA_QCFLAG_RESULT_TF)
- sil24_update_tf(qc->ap);
+ sil24_read_tf(ap, qc->tag, &pp->tf);
}
static inline void sil24_host_intr(struct ata_port *ap)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index fd80bcf1b236..31a2f55aae66 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -64,8 +64,8 @@ enum {
};
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
@@ -207,36 +207,37 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int sc_reg, u32 val
pci_write_config_dword(pdev, cfg_addr+0x10, val);
}
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- u32 val, val2 = 0;
u8 pmr;
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_read(ap, sc_reg);
pci_read_config_byte(pdev, SIS_PMR, &pmr);
- val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+ *val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
- val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+ *val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+
+ *val &= 0xfffffffb;
- return (val | val2) & 0xfffffffb;
+ return 0;
}
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -248,6 +249,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
}
+ return 0;
}
static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -334,7 +336,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
- rc = ata_pci_prepare_native_host(pdev, ppi, &host);
+ rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
if (rc)
return rc;
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 63fe99afd59f..92e877075037 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -103,20 +103,21 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
return 0;
}
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index aca71819f6e8..78c28512f01c 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -57,8 +57,8 @@ struct uli_priv {
};
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -164,20 +164,22 @@ static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
pci_write_config_dword(pdev, cfg_addr, val);
}
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
+ return -EINVAL;
- return uli_scr_cfg_read(ap, sc_reg);
+ *val = uli_scr_cfg_read(ap, sc_reg);
+ return 0;
}
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
- return;
+ return -EINVAL;
uli_scr_cfg_write(ap, sc_reg, val);
+ return 0;
}
static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -213,7 +215,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
host->private_data = hpriv;
/* the first two ports are standard SFF */
- rc = ata_pci_init_native_host(host);
+ rc = ata_pci_init_sff_host(host);
if (rc)
return rc;
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index a4c0832033d8..86b7bfc17324 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -72,8 +72,8 @@ enum {
};
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap);
static void vt6420_error_handler(struct ata_port *ap);
static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -249,18 +249,20 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return -EINVAL;
+ *val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+ return 0;
}
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+ return 0;
}
static void svia_noop_freeze(struct ata_port *ap)
@@ -305,18 +307,19 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
/* Resume phy. This is the old SATA resume sequence */
svia_scr_write(ap, SCR_CONTROL, 0x300);
- svia_scr_read(ap, SCR_CONTROL); /* flush */
+ svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
/* wait for phy to become ready, if necessary */
do {
msleep(200);
- if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
+ if ((sstatus & 0xf) != 1)
break;
} while (time_before(jiffies, timeout));
/* open code sata_print_link_status() */
- sstatus = svia_scr_read(ap, SCR_STATUS);
- scontrol = svia_scr_read(ap, SCR_CONTROL);
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
+ svia_scr_read(ap, SCR_CONTROL, &scontrol);
online = (sstatus & 0xf) == 0x3;
@@ -325,7 +328,7 @@ static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
online ? "up" : "down", sstatus, scontrol);
/* SStatus is read one more time */
- svia_scr_read(ap, SCR_STATUS);
+ svia_scr_read(ap, SCR_STATUS, &sstatus);
if (!online) {
/* tell EH to bail */
@@ -412,7 +415,7 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
struct ata_host *host;
int rc;
- rc = ata_pci_prepare_native_host(pdev, ppi, &host);
+ rc = ata_pci_prepare_sff_host(pdev, ppi, &host);
if (rc)
return rc;
*r_host = host;
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 1b5d81faa102..24344d0d0575 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -98,20 +98,21 @@ enum {
VSC_SATA_INT_PHY_CHANGE),
};
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
{
if (sc_reg > SCR_CONTROL)
- return 0xffffffffU;
- return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return -EINVAL;
+ *val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
- u32 val)
+static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
{
if (sc_reg > SCR_CONTROL)
- return;
+ return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+ return 0;
}
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index 5b4fab24155f..bed9f58c2d5a 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -142,7 +142,7 @@ config ATM_ENI_BURST_RX_2W
config ATM_FIRESTREAM
tristate "Fujitsu FireStream (FS50/FS155) "
- depends on PCI
+ depends on PCI && VIRT_TO_BUS
help
Driver for the Fujitsu FireStream 155 (MB86697) and
FireStream 50 (MB86695) ATM PCI chips.
@@ -152,7 +152,7 @@ config ATM_FIRESTREAM
config ATM_ZATM
tristate "ZeitNet ZN1221/ZN1225"
- depends on PCI
+ depends on PCI && VIRT_TO_BUS
help
Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM
adapters.
@@ -172,7 +172,7 @@ config ATM_ZATM_DEBUG
config ATM_NICSTAR
tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
- depends on PCI && !64BIT
+ depends on PCI && !64BIT && VIRT_TO_BUS
help
The NICStAR chipset family is used in a large number of ATM NICs for
25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
@@ -240,7 +240,7 @@ config ATM_IDT77252_USE_SUNI
config ATM_AMBASSADOR
tristate "Madge Ambassador (Collage PCI 155 Server)"
- depends on PCI
+ depends on PCI && VIRT_TO_BUS
select BITREVERSE
help
This is a driver for ATMizer based ATM card produced by Madge
@@ -265,7 +265,7 @@ config ATM_AMBASSADOR_DEBUG
config ATM_HORIZON
tristate "Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)"
- depends on PCI
+ depends on PCI && VIRT_TO_BUS
help
This is a driver for the Horizon chipset ATM adapter cards once
produced by Madge Networks Ltd. Say Y (or M to compile as a module
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 59651abfa4f8..b34b3829f6a9 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -1040,7 +1040,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
struct atm_qos * qos;
struct atm_trafprm * txtp;
struct atm_trafprm * rxtp;
- u16 tx_rate_bits;
+ u16 tx_rate_bits = -1; // hush gcc
u16 tx_vc_bits = -1; // hush gcc
u16 tx_frame_bits = -1; // hush gcc
@@ -1096,6 +1096,8 @@ static int amb_open (struct atm_vcc * atm_vcc)
r = round_up;
}
error = make_rate (pcr, r, &tx_rate_bits, NULL);
+ if (error)
+ return error;
tx_vc_bits = TX_UBR_CAPPED;
tx_frame_bits = TX_FRAME_CAPPED;
}
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 0d3a38b1cb0b..41b2204ebc6e 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1704,7 +1704,6 @@ static int __devinit eni_do_init(struct atm_dev *dev)
struct pci_dev *pci_dev;
unsigned long real_base;
void __iomem *base;
- unsigned char revision;
int error,i,last;
DPRINTK(">eni_init\n");
@@ -1715,12 +1714,6 @@ static int __devinit eni_do_init(struct atm_dev *dev)
pci_dev = eni_dev->pci_dev;
real_base = pci_resource_start(pci_dev, 0);
eni_dev->irq = pci_dev->irq;
- error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision);
- if (error) {
- printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%02x\n",
- dev->number,error);
- return -EINVAL;
- }
if ((error = pci_write_config_word(pci_dev,PCI_COMMAND,
PCI_COMMAND_MEMORY |
(eni_dev->asic ? PCI_COMMAND_PARITY | PCI_COMMAND_SERR : 0)))) {
@@ -1729,7 +1722,7 @@ static int __devinit eni_do_init(struct atm_dev *dev)
return -EIO;
}
printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%lx,irq=%d,",
- dev->number,revision,real_base,eni_dev->irq);
+ dev->number,pci_dev->revision,real_base,eni_dev->irq);
if (!(base = ioremap_nocache(real_base,MAP_MAX_SIZE))) {
printk("\n");
printk(KERN_ERR DEV_LABEL "(itf %d): can't set up page "
@@ -1745,7 +1738,8 @@ static int __devinit eni_do_init(struct atm_dev *dev)
printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
"magic - expected 0x%x, got 0x%x\n",dev->number,
ENI155_MAGIC,(unsigned) readl(&eprom->magic));
- return -EINVAL;
+ error = -EINVAL;
+ goto unmap;
}
}
eni_dev->phy = base+PHY_BASE;
@@ -1772,17 +1766,27 @@ static int __devinit eni_do_init(struct atm_dev *dev)
printk(")\n");
printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n",
dev->number,(unsigned) eni_in(MID_RES_ID_MCON));
- return -EINVAL;
+ error = -EINVAL;
+ goto unmap;
}
error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base);
- if (error) return error;
+ if (error)
+ goto unmap;
for (i = 0; i < ESI_LEN; i++)
printk("%s%02X",i ? "-" : "",dev->esi[i]);
printk(")\n");
printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number,
eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]);
- return suni_init(dev);
+
+ error = suni_init(dev);
+ if (error)
+ goto unmap;
+out:
+ return error;
+unmap:
+ iounmap(base);
+ goto out;
}
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 38b688f9f6a9..737cea49f872 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1710,7 +1710,7 @@ static int __devinit fs_init (struct fs_dev *dev)
/* This bit is documented as "RESERVED" */
if (isr & ISR_INIT_ERR) {
printk (KERN_ERR "Error initializing the FS... \n");
- return 1;
+ goto unmap;
}
if (isr & ISR_INIT) {
fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n");
@@ -1723,7 +1723,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (!to) {
printk (KERN_ERR "timeout initializing the FS... \n");
- return 1;
+ goto unmap;
}
/* XXX fix for fs155 */
@@ -1803,7 +1803,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (!dev->atm_vccs) {
printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n");
/* XXX Clean up..... */
- return 1;
+ goto unmap;
}
dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
@@ -1813,7 +1813,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (!dev->tx_inuse) {
printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n");
/* XXX Clean up..... */
- return 1;
+ goto unmap;
}
/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
/* -- RAS2 : FS50 only: Default is OK. */
@@ -1840,7 +1840,7 @@ static int __devinit fs_init (struct fs_dev *dev)
if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) {
printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
/* XXX undo all previous stuff... */
- return 1;
+ goto unmap;
}
fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev);
@@ -1890,6 +1890,9 @@ static int __devinit fs_init (struct fs_dev *dev)
func_exit ();
return 0;
+unmap:
+ iounmap(dev->base);
+ return 1;
}
static int __devinit firestream_init_one (struct pci_dev *pci_dev,
@@ -2012,6 +2015,7 @@ static void __devexit firestream_remove_one (struct pci_dev *pdev)
for (i=0;i < FS_NR_RX_QUEUES;i++)
free_queue (dev, &dev->rx_rq[i]);
+ iounmap(dev->base);
fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev);
nxtdev = dev->next;
kfree (dev);
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 3800bc0cb2ef..f8b1700f4c16 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -65,7 +65,7 @@ static char const rcsid[] =
static unsigned int vpibits = 1;
-#define CONFIG_ATM_IDT77252_SEND_IDLE 1
+#define ATM_IDT77252_SEND_IDLE 1
/*
@@ -3404,7 +3404,7 @@ init_card(struct atm_dev *dev)
conf = SAR_CFG_TX_FIFO_SIZE_9 | /* Use maximum fifo size */
SAR_CFG_RXSTQ_SIZE_8k | /* Receive Status Queue is 8k */
SAR_CFG_IDLE_CLP | /* Set CLP on idle cells */
-#ifndef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifndef ATM_IDT77252_SEND_IDLE
SAR_CFG_NO_IDLE | /* Do not send idle cells */
#endif
0;
@@ -3541,7 +3541,7 @@ init_card(struct atm_dev *dev)
printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
card->name, linkrate, card->link_pcr);
-#ifdef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifdef ATM_IDT77252_SEND_IDLE
card->utopia_pcr = card->link_pcr;
#else
card->utopia_pcr = (160000000 / 8 / 54);
@@ -3679,7 +3679,6 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
unsigned long membase, srambase;
struct idt77252_dev *card;
struct atm_dev *dev;
- ushort revision = 0;
int i, err;
@@ -3688,19 +3687,13 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
return err;
}
- if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) {
- printk("idt77252-%d: can't read PCI_REVISION_ID\n", index);
- err = -ENODEV;
- goto err_out_disable_pdev;
- }
-
card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
if (!card) {
printk("idt77252-%d: can't allocate private data\n", index);
err = -ENOMEM;
goto err_out_disable_pdev;
}
- card->revision = revision;
+ card->revision = pcidev->revision;
card->index = index;
card->pcidev = pcidev;
sprintf(card->name, "idt77252-%d", card->index);
@@ -3762,8 +3755,8 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
}
printk("%s: ABR SAR (Rev %c): MEM %08lx SRAM %08lx [%u KB]\n",
- card->name, ((revision > 1) && (revision < 25)) ?
- 'A' + revision - 1 : '?', membase, srambase,
+ card->name, ((card->revision > 1) && (card->revision < 25)) ?
+ 'A' + card->revision - 1 : '?', membase, srambase,
card->sramsize / 1024);
if (init_card(dev)) {
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index bb7ef570514c..a3b605a0ca17 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2290,7 +2290,6 @@ static int __devinit ia_init(struct atm_dev *dev)
unsigned long real_base;
void __iomem *base;
unsigned short command;
- unsigned char revision;
int error, i;
/* The device has been identified and registered. Now we read
@@ -2305,16 +2304,14 @@ static int __devinit ia_init(struct atm_dev *dev)
real_base = pci_resource_start (iadev->pci, 0);
iadev->irq = iadev->pci->irq;
- if ((error = pci_read_config_word(iadev->pci, PCI_COMMAND,&command))
- || (error = pci_read_config_byte(iadev->pci,
- PCI_REVISION_ID,&revision)))
- {
+ error = pci_read_config_word(iadev->pci, PCI_COMMAND, &command);
+ if (error) {
printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%x\n",
dev->number,error);
return -EINVAL;
}
IF_INIT(printk(DEV_LABEL "(itf %d): rev.%d,realbase=0x%lx,irq=%d\n",
- dev->number, revision, real_base, iadev->irq);)
+ dev->number, iadev->pci->revision, real_base, iadev->irq);)
/* find mapping size of board */
@@ -2353,7 +2350,7 @@ static int __devinit ia_init(struct atm_dev *dev)
return error;
}
IF_INIT(printk(DEV_LABEL " (itf %d): rev.%d,base=%p,irq=%d\n",
- dev->number, revision, base, iadev->irq);)
+ dev->number, iadev->pci->revision, base, iadev->irq);)
/* filling the iphase dev structure */
iadev->mem = iadev->pci_map_size /2;
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index 09f477d4237a..55fd1b4543fd 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -246,8 +246,8 @@ struct lanai_vcc {
};
enum lanai_type {
- lanai2 = PCI_VENDOR_ID_EF_ATM_LANAI2,
- lanaihb = PCI_VENDOR_ID_EF_ATM_LANAIHB
+ lanai2 = PCI_DEVICE_ID_EF_ATM_LANAI2,
+ lanaihb = PCI_DEVICE_ID_EF_ATM_LANAIHB
};
struct lanai_dev_stats {
@@ -293,7 +293,6 @@ struct lanai_dev {
struct atm_vcc *cbrvcc;
int number;
int board_rev;
- u8 pci_revision;
/* TODO - look at race conditions with maintence of conf1/conf2 */
/* TODO - transmit locking: should we use _irq not _irqsave? */
/* TODO - organize above in some rational fashion (see <asm/cache.h>) */
@@ -553,8 +552,8 @@ static inline void sram_write(const struct lanai_dev *lanai,
writel(val, sram_addr(lanai, offset));
}
-static int __init sram_test_word(
- const struct lanai_dev *lanai, int offset, u32 pattern)
+static int __devinit sram_test_word(const struct lanai_dev *lanai,
+ int offset, u32 pattern)
{
u32 readback;
sram_write(lanai, pattern, offset);
@@ -1969,14 +1968,6 @@ static int __devinit lanai_pci_start(struct lanai_dev *lanai)
"(itf %d): No suitable DMA available.\n", lanai->number);
return -EBUSY;
}
- /* Get the pci revision byte */
- result = pci_read_config_byte(pci, PCI_REVISION_ID,
- &lanai->pci_revision);
- if (result != PCIBIOS_SUCCESSFUL) {
- printk(KERN_ERR DEV_LABEL "(itf %d): can't read "
- "PCI_REVISION_ID: %d\n", lanai->number, result);
- return -EINVAL;
- }
result = pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &w);
if (result != PCIBIOS_SUCCESSFUL) {
printk(KERN_ERR DEV_LABEL "(itf %d): can't read "
@@ -2254,7 +2245,7 @@ static int __devinit lanai_dev_open(struct atm_dev *atmdev)
lanai_timed_poll_start(lanai);
printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d, base=0x%lx, irq=%u "
"(%02X-%02X-%02X-%02X-%02X-%02X)\n", lanai->number,
- (int) lanai->pci_revision, (unsigned long) lanai->base,
+ (int) lanai->pci->revision, (unsigned long) lanai->base,
lanai->pci->irq,
atmdev->esi[0], atmdev->esi[1], atmdev->esi[2],
atmdev->esi[3], atmdev->esi[4], atmdev->esi[5]);
@@ -2491,7 +2482,7 @@ static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page)
(unsigned int) lanai->magicno, lanai->num_vci);
if (left-- == 0)
return sprintf(page, "revision: board=%d, pci_if=%d\n",
- lanai->board_rev, (int) lanai->pci_revision);
+ lanai->board_rev, (int) lanai->pci->revision);
if (left-- == 0)
return sprintf(page, "EEPROM ESI: "
"%02X:%02X:%02X:%02X:%02X:%02X\n",
@@ -2631,14 +2622,8 @@ static int __devinit lanai_init_one(struct pci_dev *pci,
}
static struct pci_device_id lanai_pci_tbl[] = {
- {
- PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAI2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0
- },
- {
- PCI_VENDOR_ID_EF, PCI_VENDOR_ID_EF_ATM_LANAIHB,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0
- },
+ { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_LANAI2) },
+ { PCI_VDEVICE(EF, PCI_DEVICE_ID_EF_ATM_LANAIHB) },
{ 0, } /* terminal entry */
};
MODULE_DEVICE_TABLE(pci, lanai_pci_tbl);
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 480947f4e01e..842e26c45557 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -134,7 +134,7 @@ nicstar_read_eprom_status( virt_addr_t base )
/* Send read instruction */
val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
- for (i=0; i<sizeof rdsrtab/sizeof rdsrtab[0]; i++)
+ for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
{
NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
(val | rdsrtab[i]) );
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 2ad2527cf5b3..58583c6ac5be 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -915,7 +915,7 @@ static int open_tx_first(struct atm_vcc *vcc)
unsigned long flags;
u32 *loop;
unsigned short chan;
- int pcr,unlimited;
+ int unlimited;
DPRINTK("open_tx_first\n");
zatm_dev = ZATM_DEV(vcc->dev);
@@ -936,6 +936,8 @@ static int open_tx_first(struct atm_vcc *vcc)
vcc->qos.txtp.max_pcr >= ATM_OC3_PCR);
if (unlimited && zatm_dev->ubr != -1) zatm_vcc->shaper = zatm_dev->ubr;
else {
+ int uninitialized_var(pcr);
+
if (unlimited) vcc->qos.txtp.max_sdu = ATM_MAX_AAL5_PDU;
if ((zatm_vcc->shaper = alloc_shaper(vcc->dev,&pcr,
vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,unlimited))
@@ -1182,7 +1184,6 @@ static int __devinit zatm_init(struct atm_dev *dev)
struct zatm_dev *zatm_dev;
struct pci_dev *pci_dev;
unsigned short command;
- unsigned char revision;
int error,i,last;
unsigned long t0,t1,t2;
@@ -1192,8 +1193,7 @@ static int __devinit zatm_init(struct atm_dev *dev)
pci_dev = zatm_dev->pci_dev;
zatm_dev->base = pci_resource_start(pci_dev, 0);
zatm_dev->irq = pci_dev->irq;
- if ((error = pci_read_config_word(pci_dev,PCI_COMMAND,&command)) ||
- (error = pci_read_config_byte(pci_dev,PCI_REVISION_ID,&revision))) {
+ if ((error = pci_read_config_word(pci_dev,PCI_COMMAND,&command))) {
printk(KERN_ERR DEV_LABEL "(itf %d): init error 0x%02x\n",
dev->number,error);
return -EINVAL;
@@ -1206,7 +1206,7 @@ static int __devinit zatm_init(struct atm_dev *dev)
}
eprom_get_esi(dev);
printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d,base=0x%x,irq=%d,",
- dev->number,revision,zatm_dev->base,zatm_dev->irq);
+ dev->number,pci_dev->revision,zatm_dev->base,zatm_dev->irq);
/* reset uPD98401 */
zout(0,SWR);
while (!(zin(GSR) & uPD98401_INT_IND));
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index ea4fe3e48f33..de2fcce10ba5 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -5,8 +5,11 @@
# Auxiliary display drivers configuration.
#
-menu "Auxiliary Display support"
+menuconfig AUXDISPLAY
depends on PARPORT
+ bool "Auxiliary Display support"
+
+if AUXDISPLAY && PARPORT
config KS0108
tristate "KS0108 LCD Controller"
@@ -111,4 +114,5 @@ config CFAG12864B_RATE
If you compile this as a module, you can still override this
value using the module parameters.
-endmenu
+
+endif # AUXDISPLAY
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c
index 1ec0654665cf..7370d7cf5988 100644
--- a/drivers/base/attribute_container.c
+++ b/drivers/base/attribute_container.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include "base.h"
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 5512d84452f2..47eb02d9f1af 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -44,6 +44,6 @@ struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
extern char *make_class_name(const char *name, struct kobject *kobj);
-extern void devres_release_all(struct device *dev);
+extern int devres_release_all(struct device *dev);
extern struct kset devices_subsys;
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index dca734819e50..61c67526a656 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -138,12 +138,24 @@ void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
}
}
-static struct kobj_type ktype_bus = {
+static struct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
+};
+
+static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+ struct kobj_type *ktype = get_ktype(kobj);
+ if (ktype == &bus_ktype)
+ return 1;
+ return 0;
+}
+
+static struct kset_uevent_ops bus_uevent_ops = {
+ .filter = bus_uevent_filter,
};
-static decl_subsys(bus, &ktype_bus, NULL);
+static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);
#ifdef CONFIG_HOTPLUG
@@ -562,7 +574,6 @@ static int add_probe_files(struct bus_type *bus)
bus->drivers_probe_attr.attr.name = "drivers_probe";
bus->drivers_probe_attr.attr.mode = S_IWUSR;
- bus->drivers_probe_attr.attr.owner = bus->owner;
bus->drivers_probe_attr.store = store_drivers_probe;
retval = bus_create_file(bus, &bus->drivers_probe_attr);
if (retval)
@@ -570,7 +581,6 @@ static int add_probe_files(struct bus_type *bus)
bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
- bus->drivers_autoprobe_attr.attr.owner = bus->owner;
bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
@@ -610,7 +620,8 @@ int bus_add_driver(struct device_driver *drv)
if (error)
goto out_put_bus;
drv->kobj.kset = &bus->drivers;
- if ((error = kobject_register(&drv->kobj)))
+ error = kobject_register(&drv->kobj);
+ if (error)
goto out_put_bus;
if (drv->bus->drivers_autoprobe) {
@@ -760,7 +771,8 @@ static int bus_add_attrs(struct bus_type * bus)
if (bus->bus_attrs) {
for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
- if ((error = bus_create_file(bus,&bus->bus_attrs[i])))
+ error = bus_create_file(bus,&bus->bus_attrs[i]);
+ if (error)
goto Err;
}
}
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 8c506dbe3913..4d2222618b78 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -312,9 +312,6 @@ static void class_dev_release(struct kobject * kobj)
pr_debug("device class '%s': release.\n", cd->class_id);
- kfree(cd->devt_attr);
- cd->devt_attr = NULL;
-
if (cd->release)
cd->release(cd);
else if (cls->release)
@@ -547,6 +544,9 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
return print_dev_t(buf, class_dev->devt);
}
+static struct class_device_attribute class_devt_attr =
+ __ATTR(dev, S_IRUGO, show_dev, NULL);
+
static ssize_t store_uevent(struct class_device *class_dev,
const char *buf, size_t count)
{
@@ -554,6 +554,9 @@ static ssize_t store_uevent(struct class_device *class_dev,
return count;
}
+static struct class_device_attribute class_uevent_attr =
+ __ATTR(uevent, S_IWUSR, NULL, store_uevent);
+
void class_device_initialize(struct class_device *class_dev)
{
kobj_set_kset_s(class_dev, class_obj_subsys);
@@ -603,32 +606,15 @@ int class_device_add(struct class_device *class_dev)
&parent_class->subsys.kobj, "subsystem");
if (error)
goto out3;
- class_dev->uevent_attr.attr.name = "uevent";
- class_dev->uevent_attr.attr.mode = S_IWUSR;
- class_dev->uevent_attr.attr.owner = parent_class->owner;
- class_dev->uevent_attr.store = store_uevent;
- error = class_device_create_file(class_dev, &class_dev->uevent_attr);
+
+ error = class_device_create_file(class_dev, &class_uevent_attr);
if (error)
goto out3;
if (MAJOR(class_dev->devt)) {
- struct class_device_attribute *attr;
- attr = kzalloc(sizeof(*attr), GFP_KERNEL);
- if (!attr) {
- error = -ENOMEM;
- goto out4;
- }
- attr->attr.name = "dev";
- attr->attr.mode = S_IRUGO;
- attr->attr.owner = parent_class->owner;
- attr->show = show_dev;
- error = class_device_create_file(class_dev, attr);
- if (error) {
- kfree(attr);
+ error = class_device_create_file(class_dev, &class_devt_attr);
+ if (error)
goto out4;
- }
-
- class_dev->devt_attr = attr;
}
error = class_device_add_attrs(class_dev);
@@ -671,10 +657,10 @@ int class_device_add(struct class_device *class_dev)
out6:
class_device_remove_attrs(class_dev);
out5:
- if (class_dev->devt_attr)
- class_device_remove_file(class_dev, class_dev->devt_attr);
+ if (MAJOR(class_dev->devt))
+ class_device_remove_file(class_dev, &class_devt_attr);
out4:
- class_device_remove_file(class_dev, &class_dev->uevent_attr);
+ class_device_remove_file(class_dev, &class_uevent_attr);
out3:
kobject_del(&class_dev->kobj);
out2:
@@ -774,9 +760,9 @@ void class_device_del(struct class_device *class_dev)
sysfs_remove_link(&class_dev->kobj, "device");
}
sysfs_remove_link(&class_dev->kobj, "subsystem");
- class_device_remove_file(class_dev, &class_dev->uevent_attr);
- if (class_dev->devt_attr)
- class_device_remove_file(class_dev, class_dev->devt_attr);
+ class_device_remove_file(class_dev, &class_uevent_attr);
+ if (MAJOR(class_dev->devt))
+ class_device_remove_file(class_dev, &class_devt_attr);
class_device_remove_attrs(class_dev);
class_device_remove_groups(class_dev);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index dd40d78a023d..3599ab2506d2 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -24,6 +24,8 @@
#include "base.h"
#include "power/power.h"
+extern const char *kobject_actions[];
+
int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL;
@@ -303,13 +305,31 @@ out:
static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- if (memcmp(buf, "add", 3) != 0)
- dev_err(dev, "uevent: unsupported action-string; this will "
- "be ignored in a future kernel version");
+ size_t len = count;
+ enum kobject_action action;
+
+ if (len && buf[len-1] == '\n')
+ len--;
+
+ for (action = 0; action < KOBJ_MAX; action++) {
+ if (strncmp(kobject_actions[action], buf, len) != 0)
+ continue;
+ if (kobject_actions[action][len] != '\0')
+ continue;
+ kobject_uevent(&dev->kobj, action);
+ goto out;
+ }
+
+ dev_err(dev, "uevent: unsupported action-string; this will "
+ "be ignored in a future kernel version\n");
kobject_uevent(&dev->kobj, KOBJ_ADD);
+out:
return count;
}
+static struct device_attribute uevent_attr =
+ __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
+
static int device_add_attributes(struct device *dev,
struct device_attribute *attrs)
{
@@ -423,6 +443,9 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
return print_dev_t(buf, dev->devt);
}
+static struct device_attribute devt_attr =
+ __ATTR(dev, S_IRUGO, show_dev, NULL);
+
/*
* devices_subsys - structure to be registered with kobject core.
*/
@@ -637,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent)
return 0;
}
+static int device_add_class_symlinks(struct device *dev)
+{
+ int error;
+
+ if (!dev->class)
+ return 0;
+ error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
+ "subsystem");
+ if (error)
+ goto out;
+ /*
+ * If this is not a "fake" compatible device, then create the
+ * symlink from the class to the device.
+ */
+ if (dev->kobj.parent != &dev->class->subsys.kobj) {
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+ dev->bus_id);
+ if (error)
+ goto out_subsys;
+ }
+ /* only bus-device parents get a "device"-link */
+ if (dev->parent && dev->parent->bus) {
+ error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+ "device");
+ if (error)
+ goto out_busid;
+#ifdef CONFIG_SYSFS_DEPRECATED
+ {
+ char * class_name = make_class_name(dev->class->name,
+ &dev->kobj);
+ if (class_name)
+ error = sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, class_name);
+ kfree(class_name);
+ if (error)
+ goto out_device;
+ }
+#endif
+ }
+ return 0;
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+out_device:
+ if (dev->parent)
+ sysfs_remove_link(&dev->kobj, "device");
+#endif
+out_busid:
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+out_subsys:
+ sysfs_remove_link(&dev->kobj, "subsystem");
+out:
+ return error;
+}
+
+static void device_remove_class_symlinks(struct device *dev)
+{
+ if (!dev->class)
+ return;
+ if (dev->parent) {
+#ifdef CONFIG_SYSFS_DEPRECATED
+ char *class_name;
+
+ class_name = make_class_name(dev->class->name, &dev->kobj);
+ if (class_name) {
+ sysfs_remove_link(&dev->parent->kobj, class_name);
+ kfree(class_name);
+ }
+#endif
+ sysfs_remove_link(&dev->kobj, "device");
+ }
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+ sysfs_remove_link(&dev->kobj, "subsystem");
+}
+
/**
* device_add - add device to device hierarchy.
* @dev: device.
@@ -651,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent)
int device_add(struct device *dev)
{
struct device *parent = NULL;
- char *class_name = NULL;
struct class_interface *class_intf;
int error = -EINVAL;
@@ -681,63 +779,27 @@ int device_add(struct device *dev)
blocking_notifier_call_chain(&dev->bus->bus_notifier,
BUS_NOTIFY_ADD_DEVICE, dev);
- dev->uevent_attr.attr.name = "uevent";
- dev->uevent_attr.attr.mode = S_IRUGO | S_IWUSR;
- if (dev->driver)
- dev->uevent_attr.attr.owner = dev->driver->owner;
- dev->uevent_attr.store = store_uevent;
- dev->uevent_attr.show = show_uevent;
- error = device_create_file(dev, &dev->uevent_attr);
+ error = device_create_file(dev, &uevent_attr);
if (error)
goto attrError;
if (MAJOR(dev->devt)) {
- struct device_attribute *attr;
- attr = kzalloc(sizeof(*attr), GFP_KERNEL);
- if (!attr) {
- error = -ENOMEM;
- goto ueventattrError;
- }
- attr->attr.name = "dev";
- attr->attr.mode = S_IRUGO;
- if (dev->driver)
- attr->attr.owner = dev->driver->owner;
- attr->show = show_dev;
- error = device_create_file(dev, attr);
- if (error) {
- kfree(attr);
+ error = device_create_file(dev, &devt_attr);
+ if (error)
goto ueventattrError;
- }
-
- dev->devt_attr = attr;
}
- if (dev->class) {
- sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
- "subsystem");
- /* If this is not a "fake" compatible device, then create the
- * symlink from the class to the device. */
- if (dev->kobj.parent != &dev->class->subsys.kobj)
- sysfs_create_link(&dev->class->subsys.kobj,
- &dev->kobj, dev->bus_id);
- if (parent) {
- sysfs_create_link(&dev->kobj, &dev->parent->kobj,
- "device");
-#ifdef CONFIG_SYSFS_DEPRECATED
- class_name = make_class_name(dev->class->name,
- &dev->kobj);
- if (class_name)
- sysfs_create_link(&dev->parent->kobj,
- &dev->kobj, class_name);
-#endif
- }
- }
-
- if ((error = device_add_attrs(dev)))
+ error = device_add_class_symlinks(dev);
+ if (error)
+ goto SymlinkError;
+ error = device_add_attrs(dev);
+ if (error)
goto AttrsError;
- if ((error = device_pm_add(dev)))
+ error = device_pm_add(dev);
+ if (error)
goto PMError;
- if ((error = bus_add_device(dev)))
+ error = bus_add_device(dev);
+ if (error)
goto BusError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_attach_device(dev);
@@ -756,7 +818,6 @@ int device_add(struct device *dev)
up(&dev->class->sem);
}
Done:
- kfree(class_name);
put_device(dev);
return error;
BusError:
@@ -767,10 +828,10 @@ int device_add(struct device *dev)
BUS_NOTIFY_DEL_DEVICE, dev);
device_remove_attrs(dev);
AttrsError:
- if (dev->devt_attr) {
- device_remove_file(dev, dev->devt_attr);
- kfree(dev->devt_attr);
- }
+ device_remove_class_symlinks(dev);
+ SymlinkError:
+ if (MAJOR(dev->devt))
+ device_remove_file(dev, &devt_attr);
if (dev->class) {
sysfs_remove_link(&dev->kobj, "subsystem");
@@ -792,7 +853,7 @@ int device_add(struct device *dev)
}
}
ueventattrError:
- device_remove_file(dev, &dev->uevent_attr);
+ device_remove_file(dev, &uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
@@ -869,10 +930,8 @@ void device_del(struct device * dev)
if (parent)
klist_del(&dev->knode_parent);
- if (dev->devt_attr) {
- device_remove_file(dev, dev->devt_attr);
- kfree(dev->devt_attr);
- }
+ if (MAJOR(dev->devt))
+ device_remove_file(dev, &devt_attr);
if (dev->class) {
sysfs_remove_link(&dev->kobj, "subsystem");
/* If this is not a "fake" compatible device, remove the
@@ -926,7 +985,7 @@ void device_del(struct device * dev)
up(&dev->class->sem);
}
}
- device_remove_file(dev, &dev->uevent_attr);
+ device_remove_file(dev, &uevent_attr);
device_remove_attrs(dev);
bus_remove_device(dev);
@@ -1155,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name)
{
char *old_class_name = NULL;
char *new_class_name = NULL;
- char *old_symlink_name = NULL;
+ char *old_device_name = NULL;
int error;
dev = get_device(dev);
@@ -1169,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name)
old_class_name = make_class_name(dev->class->name, &dev->kobj);
#endif
- if (dev->class) {
- old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
- if (!old_symlink_name) {
- error = -ENOMEM;
- goto out_free_old_class;
- }
- strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
+ old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+ if (!old_device_name) {
+ error = -ENOMEM;
+ goto out;
}
-
+ strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
error = kobject_rename(&dev->kobj, new_name);
+ if (error) {
+ strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
+ goto out;
+ }
#ifdef CONFIG_SYSFS_DEPRECATED
if (old_class_name) {
new_class_name = make_class_name(dev->class->name, &dev->kobj);
if (new_class_name) {
- sysfs_create_link(&dev->parent->kobj, &dev->kobj,
- new_class_name);
+ error = sysfs_create_link(&dev->parent->kobj,
+ &dev->kobj, new_class_name);
+ if (error)
+ goto out;
sysfs_remove_link(&dev->parent->kobj, old_class_name);
}
}
#endif
if (dev->class) {
- sysfs_remove_link(&dev->class->subsys.kobj,
- old_symlink_name);
- sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
- dev->bus_id);
+ sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+ dev->bus_id);
+ if (error) {
+ /* Uh... how to unravel this if restoring can fail? */
+ dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
+ __FUNCTION__, error);
+ }
}
+out:
put_device(dev);
kfree(new_class_name);
- kfree(old_symlink_name);
- out_free_old_class:
kfree(old_class_name);
+ kfree(old_device_name);
return error;
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index b0088b0efecd..7ac474db88c5 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -281,24 +281,16 @@ int driver_attach(struct device_driver * drv)
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
-/**
- * device_release_driver - manually detach device from driver.
- * @dev: device.
- *
- * Manually detach device from driver.
- *
+/*
* __device_release_driver() must be called with @dev->sem held.
- * When called for a USB interface, @dev->parent->sem must be held
- * as well.
+ * When called for a USB interface, @dev->parent->sem must be held as well.
*/
-
static void __device_release_driver(struct device * dev)
{
struct device_driver * drv;
- drv = dev->driver;
+ drv = get_driver(dev->driver);
if (drv) {
- get_driver(drv);
driver_sysfs_remove(dev);
sysfs_remove_link(&dev->kobj, "driver");
klist_remove(&dev->knode_driver);
@@ -318,6 +310,13 @@ static void __device_release_driver(struct device * dev)
}
}
+/**
+ * device_release_driver - manually detach device from driver.
+ * @dev: device.
+ *
+ * Manually detach device from driver.
+ * When called for a USB interface, @dev->parent->sem must be held.
+ */
void device_release_driver(struct device * dev)
{
/*
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index e1c0730a3b99..e8beb8e5b626 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -10,6 +10,8 @@
#include <linux/device.h>
#include <linux/module.h>
+#include "base.h"
+
struct devres_node {
struct list_head entry;
dr_release_t release;
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
index 91970e9bb05e..7647abfe1890 100644
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -127,7 +127,7 @@ dma_pool_create (const char *name, struct device *dev,
} else if (allocation < size)
return NULL;
- if (!(retval = kmalloc (sizeof *retval, GFP_KERNEL)))
+ if (!(retval = kmalloc_node (sizeof *retval, GFP_KERNEL, dev_to_node(dev))))
return retval;
strlcpy (retval->name, name, sizeof retval->name);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 89a5f4a54913..53f0ee6f3016 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -175,7 +175,7 @@ static ssize_t firmware_loading_store(struct device *dev,
static DEVICE_ATTR(loading, 0644, firmware_loading_show, firmware_loading_store);
static ssize_t
-firmware_data_read(struct kobject *kobj,
+firmware_data_read(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct device *dev = to_dev(kobj);
@@ -240,7 +240,7 @@ fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
* the driver as a firmware image.
**/
static ssize_t
-firmware_data_write(struct kobject *kobj,
+firmware_data_write(struct kobject *kobj, struct bin_attribute *bin_attr,
char *buffer, loff_t offset, size_t count)
{
struct device *dev = to_dev(kobj);
@@ -271,7 +271,7 @@ out:
}
static struct bin_attribute firmware_attr_data_tmpl = {
- .attr = {.name = "data", .mode = 0644, .owner = THIS_MODULE},
+ .attr = {.name = "data", .mode = 0644},
.size = 0,
.read = firmware_data_read,
.write = firmware_data_write,
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 91f230939c1e..966a5e287415 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,10 +1,10 @@
obj-y := shutdown.o
-obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM) += main.o suspend.o resume.o sysfs.o
obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
EXTRA_CFLAGS += -DDEBUG
endif
-ifeq ($(CONFIG_PM_DEBUG),y)
+ifeq ($(CONFIG_PM_VERBOSE),y)
EXTRA_CFLAGS += -DDEBUG
endif
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 05dc8764e765..eb9f38d0aa58 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -20,64 +20,44 @@
*/
#include <linux/device.h>
+#include <linux/mutex.h>
+
#include "power.h"
LIST_HEAD(dpm_active);
LIST_HEAD(dpm_off);
LIST_HEAD(dpm_off_irq);
-DECLARE_MUTEX(dpm_sem);
-DECLARE_MUTEX(dpm_list_sem);
+DEFINE_MUTEX(dpm_mtx);
+DEFINE_MUTEX(dpm_list_mtx);
int (*platform_enable_wakeup)(struct device *dev, int is_on);
-
-/**
- * device_pm_set_parent - Specify power dependency.
- * @dev: Device who needs power.
- * @parent: Device that supplies power.
- *
- * This function is used to manually describe a power-dependency
- * relationship. It may be used to specify a transversal relationship
- * (where the power supplier is not the physical (or electrical)
- * ancestor of a specific device.
- * The effect of this is that the supplier will not be powered down
- * before the power dependent.
- */
-
-void device_pm_set_parent(struct device * dev, struct device * parent)
-{
- put_device(dev->power.pm_parent);
- dev->power.pm_parent = get_device(parent);
-}
-EXPORT_SYMBOL_GPL(device_pm_set_parent);
-
-int device_pm_add(struct device * dev)
+int device_pm_add(struct device *dev)
{
int error;
pr_debug("PM: Adding info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus",
kobject_name(&dev->kobj));
- down(&dpm_list_sem);
+ mutex_lock(&dpm_list_mtx);
list_add_tail(&dev->power.entry, &dpm_active);
- device_pm_set_parent(dev, dev->parent);
- if ((error = dpm_sysfs_add(dev)))
+ error = dpm_sysfs_add(dev);
+ if (error)
list_del(&dev->power.entry);
- up(&dpm_list_sem);
+ mutex_unlock(&dpm_list_mtx);
return error;
}
-void device_pm_remove(struct device * dev)
+void device_pm_remove(struct device *dev)
{
pr_debug("PM: Removing info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus",
kobject_name(&dev->kobj));
- down(&dpm_list_sem);
+ mutex_lock(&dpm_list_mtx);
dpm_sysfs_remove(dev);
- put_device(dev->power.pm_parent);
list_del_init(&dev->power.entry);
- up(&dpm_list_sem);
+ mutex_unlock(&dpm_list_mtx);
}
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index fb3d35a9e101..591a0dd5deee 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -14,12 +14,12 @@ extern void device_shutdown(void);
/*
* Used to synchronize global power management operations.
*/
-extern struct semaphore dpm_sem;
+extern struct mutex dpm_mtx;
/*
* Used to serialize changes to the dpm_* lists.
*/
-extern struct semaphore dpm_list_sem;
+extern struct mutex dpm_list_mtx;
/*
* The PM lists.
@@ -62,11 +62,6 @@ extern int resume_device(struct device *);
*/
extern int suspend_device(struct device *, pm_message_t);
-
-/*
- * runtime.c
- */
-
#else /* CONFIG_PM */
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index a2c64188d713..00fd84ae6e66 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -29,14 +29,6 @@ int resume_device(struct device * dev)
down(&dev->sem);
- if (dev->power.pm_parent
- && dev->power.pm_parent->power.power_state.event) {
- dev_err(dev, "PM: resume from %d, parent %s still %d\n",
- dev->power.power_state.event,
- dev->power.pm_parent->bus_id,
- dev->power.pm_parent->power.power_state.event);
- }
-
if (dev->bus && dev->bus->resume) {
dev_dbg(dev,"resuming\n");
error = dev->bus->resume(dev);
@@ -80,7 +72,7 @@ static int resume_device_early(struct device * dev)
*/
void dpm_resume(void)
{
- down(&dpm_list_sem);
+ mutex_lock(&dpm_list_mtx);
while(!list_empty(&dpm_off)) {
struct list_head * entry = dpm_off.next;
struct device * dev = to_device(entry);
@@ -88,13 +80,12 @@ void dpm_resume(void)
get_device(dev);
list_move_tail(entry, &dpm_active);
- up(&dpm_list_sem);
- if (!dev->power.prev_state.event)
- resume_device(dev);
- down(&dpm_list_sem);
+ mutex_unlock(&dpm_list_mtx);
+ resume_device(dev);
+ mutex_lock(&dpm_list_mtx);
put_device(dev);
}
- up(&dpm_list_sem);
+ mutex_unlock(&dpm_list_mtx);
}
@@ -108,9 +99,9 @@ void dpm_resume(void)
void device_resume(void)
{
might_sleep();
- down(&dpm_sem);
+ mutex_lock(&dpm_mtx);
dpm_resume();
- up(&dpm_sem);
+ mutex_unlock(&dpm_mtx);
}
EXPORT_SYMBOL_GPL(device_resume);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
deleted file mode 100644
index 96370ec1d673..000000000000
--- a/drivers/base/power/runtime.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * drivers/base/power/runtime.c - Handling dynamic device power management.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Lab
- *
- */
-
-#include <linux/device.h>
-#include "power.h"
-
-
-static void runtime_resume(struct device * dev)
-{
- dev_dbg(dev, "resuming\n");
- if (!dev->power.power_state.event)
- return;
- if (!resume_device(dev))
- dev->power.power_state = PMSG_ON;
-}
-
-
-/**
- * dpm_runtime_resume - Power one device back on.
- * @dev: Device.
- *
- * Bring one device back to the on state by first powering it
- * on, then restoring state. We only operate on devices that aren't
- * already on.
- * FIXME: We need to handle devices that are in an unknown state.
- */
-
-void dpm_runtime_resume(struct device * dev)
-{
- down(&dpm_sem);
- runtime_resume(dev);
- up(&dpm_sem);
-}
-EXPORT_SYMBOL(dpm_runtime_resume);
-
-
-/**
- * dpm_runtime_suspend - Put one device in low-power state.
- * @dev: Device.
- * @state: State to enter.
- */
-
-int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
- int error = 0;
-
- down(&dpm_sem);
- if (dev->power.power_state.event == state.event)
- goto Done;
-
- if (dev->power.power_state.event)
- runtime_resume(dev);
-
- if (!(error = suspend_device(dev, state)))
- dev->power.power_state = state;
- Done:
- up(&dpm_sem);
- return error;
-}
-EXPORT_SYMBOL(dpm_runtime_suspend);
-
-
-#if 0
-/**
- * dpm_set_power_state - Update power_state field.
- * @dev: Device.
- * @state: Power state device is in.
- *
- * This is an update mechanism for drivers to notify the core
- * what power state a device is in. Device probing code may not
- * always be able to tell, but we need accurate information to
- * work reliably.
- */
-void dpm_set_power_state(struct device * dev, pm_message_t state)
-{
- down(&dpm_sem);
- dev->power.power_state = state;
- up(&dpm_sem);
-}
-#endif /* 0 */
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index 42d2b86ba765..26df9b231737 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -40,6 +40,14 @@ static inline char *suspend_verb(u32 event)
}
+static void
+suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
+{
+ dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
+ ((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
+ ", may wakeup" : "");
+}
+
/**
* suspend_device - Save state of one device.
* @dev: Device.
@@ -55,49 +63,21 @@ int suspend_device(struct device * dev, pm_message_t state)
dev_dbg(dev, "PM: suspend %d-->%d\n",
dev->power.power_state.event, state.event);
}
- if (dev->power.pm_parent
- && dev->power.pm_parent->power.power_state.event) {
- dev_err(dev,
- "PM: suspend %d->%d, parent %s already %d\n",
- dev->power.power_state.event, state.event,
- dev->power.pm_parent->bus_id,
- dev->power.pm_parent->power.power_state.event);
- }
-
- dev->power.prev_state = dev->power.power_state;
- if (dev->class && dev->class->suspend && !dev->power.power_state.event) {
- dev_dbg(dev, "class %s%s\n",
- suspend_verb(state.event),
- ((state.event == PM_EVENT_SUSPEND)
- && device_may_wakeup(dev))
- ? ", may wakeup"
- : ""
- );
+ if (dev->class && dev->class->suspend) {
+ suspend_device_dbg(dev, state, "class ");
error = dev->class->suspend(dev, state);
suspend_report_result(dev->class->suspend, error);
}
- if (!error && dev->type && dev->type->suspend && !dev->power.power_state.event) {
- dev_dbg(dev, "%s%s\n",
- suspend_verb(state.event),
- ((state.event == PM_EVENT_SUSPEND)
- && device_may_wakeup(dev))
- ? ", may wakeup"
- : ""
- );
+ if (!error && dev->type && dev->type->suspend) {
+ suspend_device_dbg(dev, state, "type ");
error = dev->type->suspend(dev, state);
suspend_report_result(dev->type->suspend, error);
}
- if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
- dev_dbg(dev, "%s%s\n",
- suspend_verb(state.event),
- ((state.event == PM_EVENT_SUSPEND)
- && device_may_wakeup(dev))
- ? ", may wakeup"
- : ""
- );
+ if (!error && dev->bus && dev->bus->suspend) {
+ suspend_device_dbg(dev, state, "");
error = dev->bus->suspend(dev, state);
suspend_report_result(dev->bus->suspend, error);
}
@@ -108,21 +88,15 @@ int suspend_device(struct device * dev, pm_message_t state)
/*
* This is called with interrupts off, only a single CPU
- * running. We can't do down() on a semaphore (and we don't
+ * running. We can't acquire a mutex or semaphore (and we don't
* need the protection)
*/
static int suspend_device_late(struct device *dev, pm_message_t state)
{
int error = 0;
- if (dev->bus && dev->bus->suspend_late && !dev->power.power_state.event) {
- dev_dbg(dev, "LATE %s%s\n",
- suspend_verb(state.event),
- ((state.event == PM_EVENT_SUSPEND)
- && device_may_wakeup(dev))
- ? ", may wakeup"
- : ""
- );
+ if (dev->bus && dev->bus->suspend_late) {
+ suspend_device_dbg(dev, state, "LATE ");
error = dev->bus->suspend_late(dev, state);
suspend_report_result(dev->bus->suspend_late, error);
}
@@ -153,18 +127,18 @@ int device_suspend(pm_message_t state)
int error = 0;
might_sleep();
- down(&dpm_sem);
- down(&dpm_list_sem);
+ mutex_lock(&dpm_mtx);
+ mutex_lock(&dpm_list_mtx);
while (!list_empty(&dpm_active) && error == 0) {
struct list_head * entry = dpm_active.prev;
struct device * dev = to_device(entry);
get_device(dev);
- up(&dpm_list_sem);
+ mutex_unlock(&dpm_list_mtx);
error = suspend_device(dev, state);
- down(&dpm_list_sem);
+ mutex_lock(&dpm_list_mtx);
/* Check if the device got removed */
if (!list_empty(&dev->power.entry)) {
@@ -179,11 +153,11 @@ int device_suspend(pm_message_t state)
error == -EAGAIN ? " (please convert to suspend_late)" : "");
put_device(dev);
}
- up(&dpm_list_sem);
+ mutex_unlock(&dpm_list_mtx);
if (error)
dpm_resume();
- up(&dpm_sem);
+ mutex_unlock(&dpm_mtx);
return error;
}
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 2d47517dbe32..f2ed179cd695 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -7,69 +7,6 @@
#include "power.h"
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
-
-/**
- * state - Control current power state of device
- *
- * show() returns the current power state of the device. '0' indicates
- * the device is on. Other values (2) indicate the device is in some low
- * power state.
- *
- * store() sets the current power state, which is an integer valued
- * 0, 2, or 3. Devices with bus.suspend_late(), or bus.resume_early()
- * methods fail this operation; those methods couldn't be called.
- * Otherwise,
- *
- * - If the recorded dev->power.power_state.event matches the
- * target value, nothing is done.
- * - If the recorded event code is nonzero, the device is reactivated
- * by calling bus.resume() and/or class.resume().
- * - If the target value is nonzero, the device is suspended by
- * calling class.suspend() and/or bus.suspend() with event code
- * PM_EVENT_SUSPEND.
- *
- * This mechanism is DEPRECATED and should only be used for testing.
- */
-
-static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
-{
- if (dev->power.power_state.event)
- return sprintf(buf, "2\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
-{
- pm_message_t state;
- int error = -EINVAL;
-
- /* disallow incomplete suspend sequences */
- if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
- return error;
-
- state.event = PM_EVENT_SUSPEND;
- /* Older apps expected to write "3" here - confused with PCI D3 */
- if ((n == 1) && !strcmp(buf, "3"))
- error = dpm_runtime_suspend(dev, state);
-
- if ((n == 1) && !strcmp(buf, "2"))
- error = dpm_runtime_suspend(dev, state);
-
- if ((n == 1) && !strcmp(buf, "0")) {
- dpm_runtime_resume(dev);
- error = 0;
- }
-
- return error ? error : n;
-}
-
-static DEVICE_ATTR(state, 0644, state_show, state_store);
-
-
-#endif /* CONFIG_PM_SYSFS_DEPRECATED */
-
/*
* wakeup - Report/change current wakeup option for device
*
@@ -143,9 +80,6 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
static struct attribute * power_attrs[] = {
-#ifdef CONFIG_PM_SYSFS_DEPRECATED
- &dev_attr_state.attr,
-#endif
&dev_attr_wakeup.attr,
NULL,
};
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index a9ab30fefffc..2b0c601e422e 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -142,6 +142,7 @@ void set_trace_device(struct device *dev)
{
dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
}
+EXPORT_SYMBOL(set_trace_device);
/*
* We could just take the "tracedata" index into the .tracedata
@@ -162,6 +163,7 @@ void generate_resume_trace(void *tracedata, unsigned int user)
file_hash_value = hash_string(lineno, file, FILEHASH);
set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
}
+EXPORT_SYMBOL(generate_resume_trace);
extern char __tracedata_start, __tracedata_end;
static int show_file_hash(unsigned int value)
@@ -170,7 +172,8 @@ static int show_file_hash(unsigned int value)
char *tracedata;
match = 0;
- for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
+ for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
+ tracedata += 2 + sizeof(unsigned long)) {
unsigned short lineno = *(unsigned short *)tracedata;
const char *file = *(const char **)(tracedata + 2);
unsigned int hash = hash_string(lineno, file, FILEHASH);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 29f1291966c1..18febe26caa1 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -21,7 +21,7 @@
#include <linux/string.h>
#include <linux/pm.h>
#include <linux/device.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include "base.h"
@@ -155,7 +155,7 @@ EXPORT_SYMBOL_GPL(sysdev_class_unregister);
static LIST_HEAD(sysdev_drivers);
-static DECLARE_MUTEX(sysdev_drivers_lock);
+static DEFINE_MUTEX(sysdev_drivers_lock);
/**
* sysdev_driver_register - Register auxillary driver
@@ -172,7 +172,7 @@ static DECLARE_MUTEX(sysdev_drivers_lock);
int sysdev_driver_register(struct sysdev_class * cls,
struct sysdev_driver * drv)
{
- down(&sysdev_drivers_lock);
+ mutex_lock(&sysdev_drivers_lock);
if (cls && kset_get(&cls->kset)) {
list_add_tail(&drv->entry, &cls->drivers);
@@ -184,7 +184,7 @@ int sysdev_driver_register(struct sysdev_class * cls,
}
} else
list_add_tail(&drv->entry, &sysdev_drivers);
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
return 0;
}
@@ -197,7 +197,7 @@ int sysdev_driver_register(struct sysdev_class * cls,
void sysdev_driver_unregister(struct sysdev_class * cls,
struct sysdev_driver * drv)
{
- down(&sysdev_drivers_lock);
+ mutex_lock(&sysdev_drivers_lock);
list_del_init(&drv->entry);
if (cls) {
if (drv->remove) {
@@ -207,7 +207,7 @@ void sysdev_driver_unregister(struct sysdev_class * cls,
}
kset_put(&cls->kset);
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
}
EXPORT_SYMBOL_GPL(sysdev_driver_register);
@@ -246,7 +246,7 @@ int sysdev_register(struct sys_device * sysdev)
if (!error) {
struct sysdev_driver * drv;
- down(&sysdev_drivers_lock);
+ mutex_lock(&sysdev_drivers_lock);
/* Generic notification is implicit, because it's that
* code that should have called us.
*/
@@ -262,7 +262,7 @@ int sysdev_register(struct sys_device * sysdev)
if (drv->add)
drv->add(sysdev);
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
}
return error;
}
@@ -271,7 +271,7 @@ void sysdev_unregister(struct sys_device * sysdev)
{
struct sysdev_driver * drv;
- down(&sysdev_drivers_lock);
+ mutex_lock(&sysdev_drivers_lock);
list_for_each_entry(drv, &sysdev_drivers, entry) {
if (drv->remove)
drv->remove(sysdev);
@@ -281,7 +281,7 @@ void sysdev_unregister(struct sys_device * sysdev)
if (drv->remove)
drv->remove(sysdev);
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
kobject_unregister(&sysdev->kobj);
}
@@ -308,7 +308,7 @@ void sysdev_shutdown(void)
pr_debug("Shutting Down System Devices\n");
- down(&sysdev_drivers_lock);
+ mutex_lock(&sysdev_drivers_lock);
list_for_each_entry_reverse(cls, &system_subsys.list,
kset.kobj.entry) {
struct sys_device * sysdev;
@@ -337,7 +337,7 @@ void sysdev_shutdown(void)
cls->shutdown(sysdev);
}
}
- up(&sysdev_drivers_lock);
+ mutex_unlock(&sysdev_drivers_lock);
}
static void __sysdev_resume(struct sys_device *dev)
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 6e23af1ecbdb..a4a311992408 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -59,17 +59,6 @@ config AMIGA_Z2RAM
To compile this driver as a module, choose M here: the
module will be called z2ram.
-config ATARI_SLM
- tristate "Atari SLM laser printer support"
- depends on ATARI
- help
- If you have an Atari SLM laser printer, say Y to include support for
- it in the kernel. Otherwise, say N. This driver is also available as
- a module ( = code which can be inserted in and removed from the
- running kernel whenever you want). The module will be called
- acsi_slm. Be warned: the driver needs much ST-RAM and can cause
- problems due to that fact!
-
config BLK_DEV_XD
tristate "XT hard disk support"
depends on ISA && ISA_DMA_API
@@ -113,7 +102,7 @@ source "drivers/block/paride/Kconfig"
config BLK_CPQ_DA
tristate "Compaq SMART2 support"
- depends on PCI
+ depends on PCI && VIRT_TO_BUS
help
This is the driver for Compaq Smart Array controllers. Everyone
using these boards should say Y here. See the file
@@ -423,6 +412,28 @@ config ATA_OVER_ETH
This driver provides Support for ATA over Ethernet block
devices like the Coraid EtherDrive (R) Storage Blade.
+config SUNVDC
+ tristate "Sun Virtual Disk Client support"
+ depends on SUN_LDOMS
+ help
+ Support for virtual disk devices as a client under Sun
+ Logical Domains.
+
source "drivers/s390/block/Kconfig"
+config XILINX_SYSACE
+ tristate "Xilinx SystemACE support"
+ depends on 4xx
+ help
+ Include support for the Xilinx SystemACE CompactFlash interface
+
+config XEN_BLKDEV_FRONTEND
+ tristate "Xen virtual block device support"
+ depends on XEN
+ default y
+ help
+ This driver implements the front-end of the Xen virtual
+ block device driver. It communicates with a back-end driver
+ in another domain which drives the actual block device.
+
endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index e5f98acc5d52..a7a099027fca 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -8,8 +8,8 @@
obj-$(CONFIG_MAC_FLOPPY) += swim3.o
obj-$(CONFIG_BLK_DEV_FD) += floppy.o
obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o
+obj-$(CONFIG_PS3_DISK) += ps3disk.o
obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
-obj-$(CONFIG_ATARI_SLM) += acsi_slm.o
obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
obj-$(CONFIG_BLK_DEV_RAM) += rd.o
obj-$(CONFIG_BLK_DEV_LOOP) += loop.o
@@ -18,7 +18,9 @@ obj-$(CONFIG_BLK_DEV_XD) += xd.o
obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o
obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o
obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o
+obj-$(CONFIG_XILINX_SYSACE) += xsysace.o
obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o
+obj-$(CONFIG_SUNVDC) += sunvdc.o
obj-$(CONFIG_BLK_DEV_UMEM) += umem.o
obj-$(CONFIG_BLK_DEV_NBD) += nbd.o
@@ -28,3 +30,5 @@ obj-$(CONFIG_VIODASD) += viodasd.o
obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
obj-$(CONFIG_BLK_DEV_UB) += ub.o
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
+obj-$(CONFIG_LGUEST_GUEST) += lguest_blk.o
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
deleted file mode 100644
index 1d9d9b4f48cc..000000000000
--- a/drivers/block/acsi_slm.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * acsi_slm.c -- Device driver for the Atari SLM laser printer
- *
- * Copyright 1995 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
- *
- * 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.
- *
- */
-
-/*
-
-Notes:
-
-The major number for SLM printers is 28 (like ACSI), but as a character
-device, not block device. The minor number is the number of the printer (if
-you have more than one SLM; currently max. 2 (#define-constant) SLMs are
-supported). The device can be opened for reading and writing. If reading it,
-you get some status infos (MODE SENSE data). Writing mode is used for the data
-to be printed. Some ioctls allow to get the printer status and to tune printer
-modes and some internal variables.
-
-A special problem of the SLM driver is the timing and thus the buffering of
-the print data. The problem is that all the data for one page must be present
-in memory when printing starts, else --when swapping occurs-- the timing could
-not be guaranteed. There are several ways to assure this:
-
- 1) Reserve a buffer of 1196k (maximum page size) statically by
- atari_stram_alloc(). The data are collected there until they're complete,
- and then printing starts. Since the buffer is reserved, no further
- considerations about memory and swapping are needed. So this is the
- simplest method, but it needs a lot of memory for just the SLM.
-
- An striking advantage of this method is (supposed the SLM_CONT_CNT_REPROG
- method works, see there), that there are no timing problems with the DMA
- anymore.
-
- 2) The other method would be to reserve the buffer dynamically each time
- printing is required. I could think of looking at mem_map where the
- largest unallocted ST-RAM area is, taking the area, and then extending it
- by swapping out the neighbored pages, until the needed size is reached.
- This requires some mm hacking, but seems possible. The only obstacle could
- be pages that cannot be swapped out (reserved pages)...
-
- 3) Another possibility would be to leave the real data in user space and to
- work with two dribble buffers of about 32k in the driver: While the one
- buffer is DMAed to the SLM, the other can be filled with new data. But
- to keep the timing, that requires that the user data remain in memory and
- are not swapped out. Requires mm hacking, too, but maybe not so bad as
- method 2).
-
-*/
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_acsi.h>
-#include <asm/atari_stdma.h>
-#include <asm/atari_stram.h>
-#include <asm/atari_SLM.h>
-
-
-#undef DEBUG
-
-/* Define this if the page data are continuous in physical memory. That
- * requires less reprogramming of the ST-DMA */
-#define SLM_CONTINUOUS_DMA
-
-/* Use continuous reprogramming of the ST-DMA counter register. This is
- * --strictly speaking-- not allowed, Atari recommends not to look at the
- * counter register while a DMA is going on. But I don't know if that applies
- * only for reading the register, or also writing to it. Writing only works
- * fine for me... The advantage is that the timing becomes absolutely
- * uncritical: Just update each, say 200ms, the counter reg to its maximum,
- * and the DMA will work until the status byte interrupt occurs.
- */
-#define SLM_CONT_CNT_REPROG
-
-#define CMDSET_TARG_LUN(cmd,targ,lun) \
- do { \
- cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5; \
- cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5; \
- } while(0)
-
-#define START_TIMER(to) mod_timer(&slm_timer, jiffies + (to))
-#define STOP_TIMER() del_timer(&slm_timer)
-
-
-static char slmreqsense_cmd[6] = { 0x03, 0, 0, 0, 0, 0 };
-static char slmprint_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 };
-static char slminquiry_cmd[6] = { 0x12, 0, 0, 0, 0, 0x80 };
-static char slmmsense_cmd[6] = { 0x1a, 0, 0, 0, 255, 0 };
-#if 0
-static char slmmselect_cmd[6] = { 0x15, 0, 0, 0, 0, 0 };
-#endif
-
-
-#define MAX_SLM 2
-
-static struct slm {
- unsigned target; /* target number */
- unsigned lun; /* LUN in target controller */
- atomic_t wr_ok; /* set to 0 if output part busy */
- atomic_t rd_ok; /* set to 0 if status part busy */
-} slm_info[MAX_SLM];
-
-int N_SLM_Printers = 0;
-
-/* printer buffer */
-static unsigned char *SLMBuffer; /* start of buffer */
-static unsigned char *BufferP; /* current position in buffer */
-static int BufferSize; /* length of buffer for page size */
-
-typedef enum { IDLE, FILLING, PRINTING } SLMSTATE;
-static SLMSTATE SLMState;
-static int SLMBufOwner; /* SLM# currently using the buffer */
-
-/* DMA variables */
-#ifndef SLM_CONT_CNT_REPROG
-static unsigned long SLMCurAddr; /* current base addr of DMA chunk */
-static unsigned long SLMEndAddr; /* expected end addr */
-static unsigned long SLMSliceSize; /* size of one DMA chunk */
-#endif
-static int SLMError;
-
-/* wait queues */
-static DECLARE_WAIT_QUEUE_HEAD(slm_wait); /* waiting for buffer */
-static DECLARE_WAIT_QUEUE_HEAD(print_wait); /* waiting for printing finished */
-
-/* status codes */
-#define SLMSTAT_OK 0x00
-#define SLMSTAT_ORNERY 0x02
-#define SLMSTAT_TONER 0x03
-#define SLMSTAT_WARMUP 0x04
-#define SLMSTAT_PAPER 0x05
-#define SLMSTAT_DRUM 0x06
-#define SLMSTAT_INJAM 0x07
-#define SLMSTAT_THRJAM 0x08
-#define SLMSTAT_OUTJAM 0x09
-#define SLMSTAT_COVER 0x0a
-#define SLMSTAT_FUSER 0x0b
-#define SLMSTAT_IMAGER 0x0c
-#define SLMSTAT_MOTOR 0x0d
-#define SLMSTAT_VIDEO 0x0e
-#define SLMSTAT_SYSTO 0x10
-#define SLMSTAT_OPCODE 0x12
-#define SLMSTAT_DEVNUM 0x15
-#define SLMSTAT_PARAM 0x1a
-#define SLMSTAT_ACSITO 0x1b /* driver defined */
-#define SLMSTAT_NOTALL 0x1c /* driver defined */
-
-static char *SLMErrors[] = {
- /* 0x00 */ "OK and ready",
- /* 0x01 */ NULL,
- /* 0x02 */ "ornery printer",
- /* 0x03 */ "toner empty",
- /* 0x04 */ "warming up",
- /* 0x05 */ "paper empty",
- /* 0x06 */ "drum empty",
- /* 0x07 */ "input jam",
- /* 0x08 */ "through jam",
- /* 0x09 */ "output jam",
- /* 0x0a */ "cover open",
- /* 0x0b */ "fuser malfunction",
- /* 0x0c */ "imager malfunction",
- /* 0x0d */ "motor malfunction",
- /* 0x0e */ "video malfunction",
- /* 0x0f */ NULL,
- /* 0x10 */ "printer system timeout",
- /* 0x11 */ NULL,
- /* 0x12 */ "invalid operation code",
- /* 0x13 */ NULL,
- /* 0x14 */ NULL,
- /* 0x15 */ "invalid device number",
- /* 0x16 */ NULL,
- /* 0x17 */ NULL,
- /* 0x18 */ NULL,
- /* 0x19 */ NULL,
- /* 0x1a */ "invalid parameter list",
- /* 0x1b */ "ACSI timeout",
- /* 0x1c */ "not all printed"
-};
-
-#define N_ERRORS (sizeof(SLMErrors)/sizeof(*SLMErrors))
-
-/* real (driver caused) error? */
-#define IS_REAL_ERROR(x) (x > 0x10)
-
-
-static struct {
- char *name;
- int w, h;
-} StdPageSize[] = {
- { "Letter", 2400, 3180 },
- { "Legal", 2400, 4080 },
- { "A4", 2336, 3386 },
- { "B5", 2016, 2914 }
-};
-
-#define N_STD_SIZES (sizeof(StdPageSize)/sizeof(*StdPageSize))
-
-#define SLM_BUFFER_SIZE (2336*3386/8) /* A4 for now */
-#define SLM_DMA_AMOUNT 255 /* #sectors to program the DMA for */
-
-#ifdef SLM_CONTINUOUS_DMA
-# define SLM_DMA_INT_OFFSET 0 /* DMA goes until seccnt 0, no offs */
-# define SLM_DMA_END_OFFSET 32 /* 32 Byte ST-DMA FIFO */
-# define SLM_SLICE_SIZE(w) (255*512)
-#else
-# define SLM_DMA_INT_OFFSET 32 /* 32 Byte ST-DMA FIFO */
-# define SLM_DMA_END_OFFSET 32 /* 32 Byte ST-DMA FIFO */
-# define SLM_SLICE_SIZE(w) ((254*512)/(w/8)*(w/8))
-#endif
-
-/* calculate the number of jiffies to wait for 'n' bytes */
-#ifdef SLM_CONT_CNT_REPROG
-#define DMA_TIME_FOR(n) 50
-#define DMA_STARTUP_TIME 0
-#else
-#define DMA_TIME_FOR(n) (n/1400-1)
-#define DMA_STARTUP_TIME 650
-#endif
-
-/***************************** Prototypes *****************************/
-
-static char *slm_errstr( int stat );
-static int slm_getstats( char *buffer, int device );
-static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t
- *ppos );
-static void start_print( int device );
-static irqreturn_t slm_interrupt(int irc, void *data);
-static void slm_test_ready( unsigned long dummy );
-static void set_dma_addr( unsigned long paddr );
-static unsigned long get_dma_addr( void );
-static ssize_t slm_write( struct file *file, const char *buf, size_t count,
- loff_t *ppos );
-static int slm_ioctl( struct inode *inode, struct file *file, unsigned int
- cmd, unsigned long arg );
-static int slm_open( struct inode *inode, struct file *file );
-static int slm_release( struct inode *inode, struct file *file );
-static int slm_req_sense( int device );
-static int slm_mode_sense( int device, char *buffer, int abs_flag );
-#if 0
-static int slm_mode_select( int device, char *buffer, int len, int
- default_flag );
-#endif
-static int slm_get_pagesize( int device, int *w, int *h );
-
-/************************* End of Prototypes **************************/
-
-
-static DEFINE_TIMER(slm_timer, slm_test_ready, 0, 0);
-
-static const struct file_operations slm_fops = {
- .owner = THIS_MODULE,
- .read = slm_read,
- .write = slm_write,
- .ioctl = slm_ioctl,
- .open = slm_open,
- .release = slm_release,
-};
-
-
-/* ---------------------------------------------------------------------- */
-/* Status Functions */
-
-
-static char *slm_errstr( int stat )
-
-{ char *p;
- static char str[22];
-
- stat &= 0x1f;
- if (stat >= 0 && stat < N_ERRORS && (p = SLMErrors[stat]))
- return( p );
- sprintf( str, "unknown status 0x%02x", stat );
- return( str );
-}
-
-
-static int slm_getstats( char *buffer, int device )
-
-{ int len = 0, stat, i, w, h;
- unsigned char buf[256];
-
- stat = slm_mode_sense( device, buf, 0 );
- if (IS_REAL_ERROR(stat))
- return( -EIO );
-
-#define SHORTDATA(i) ((buf[i] << 8) | buf[i+1])
-#define BOOLDATA(i,mask) ((buf[i] & mask) ? "on" : "off")
-
- w = SHORTDATA( 3 );
- h = SHORTDATA( 1 );
-
- len += sprintf( buffer+len, "Status\t\t%s\n",
- slm_errstr( stat ) );
- len += sprintf( buffer+len, "Page Size\t%dx%d",
- w, h );
-
- for( i = 0; i < N_STD_SIZES; ++i ) {
- if (w == StdPageSize[i].w && h == StdPageSize[i].h)
- break;
- }
- if (i < N_STD_SIZES)
- len += sprintf( buffer+len, " (%s)", StdPageSize[i].name );
- buffer[len++] = '\n';
-
- len += sprintf( buffer+len, "Top/Left Margin\t%d/%d\n",
- SHORTDATA( 5 ), SHORTDATA( 7 ) );
- len += sprintf( buffer+len, "Manual Feed\t%s\n",
- BOOLDATA( 9, 0x01 ) );
- len += sprintf( buffer+len, "Input Select\t%d\n",
- (buf[9] >> 1) & 7 );
- len += sprintf( buffer+len, "Auto Select\t%s\n",
- BOOLDATA( 9, 0x10 ) );
- len += sprintf( buffer+len, "Prefeed Paper\t%s\n",
- BOOLDATA( 9, 0x20 ) );
- len += sprintf( buffer+len, "Thick Pixels\t%s\n",
- BOOLDATA( 9, 0x40 ) );
- len += sprintf( buffer+len, "H/V Resol.\t%d/%d dpi\n",
- SHORTDATA( 12 ), SHORTDATA( 10 ) );
- len += sprintf( buffer+len, "System Timeout\t%d\n",
- buf[14] );
- len += sprintf( buffer+len, "Scan Time\t%d\n",
- SHORTDATA( 15 ) );
- len += sprintf( buffer+len, "Page Count\t%d\n",
- SHORTDATA( 17 ) );
- len += sprintf( buffer+len, "In/Out Cap.\t%d/%d\n",
- SHORTDATA( 19 ), SHORTDATA( 21 ) );
- len += sprintf( buffer+len, "Stagger Output\t%s\n",
- BOOLDATA( 23, 0x01 ) );
- len += sprintf( buffer+len, "Output Select\t%d\n",
- (buf[23] >> 1) & 7 );
- len += sprintf( buffer+len, "Duplex Print\t%s\n",
- BOOLDATA( 23, 0x10 ) );
- len += sprintf( buffer+len, "Color Sep.\t%s\n",
- BOOLDATA( 23, 0x20 ) );
-
- return( len );
-}
-
-
-static ssize_t slm_read( struct file *file, char *buf, size_t count,
- loff_t *ppos )
-
-{
- struct inode *node = file->f_path.dentry->d_inode;
- unsigned long page;
- int length;
- int end;
-
- if (!(page = __get_free_page( GFP_KERNEL )))
- return( -ENOMEM );
-
- length = slm_getstats( (char *)page, iminor(node) );
- if (length < 0) {
- count = length;
- goto out;
- }
- if (file->f_pos >= length) {
- count = 0;
- goto out;
- }
- if (count + file->f_pos > length)
- count = length - file->f_pos;
- end = count + file->f_pos;
- if (copy_to_user(buf, (char *)page + file->f_pos, count)) {
- count = -EFAULT;
- goto out;
- }
- file->f_pos = end;
-out: free_page( page );
- return( count );
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* Printing */
-
-
-static void start_print( int device )
-
-{ struct slm *sip = &slm_info[device];
- unsigned char *cmd;
- unsigned long paddr;
- int i;
-
- stdma_lock( slm_interrupt, NULL );
-
- CMDSET_TARG_LUN( slmprint_cmd, sip->target, sip->lun );
- cmd = slmprint_cmd;
- paddr = virt_to_phys( SLMBuffer );
- dma_cache_maintenance( paddr, virt_to_phys(BufferP)-paddr, 1 );
- DISABLE_IRQ();
-
- /* Low on A1 */
- dma_wd.dma_mode_status = 0x88;
- MFPDELAY();
-
- /* send the command bytes except the last */
- for( i = 0; i < 5; ++i ) {
- DMA_LONG_WRITE( *cmd++, 0x8a );
- udelay(20);
- if (!acsi_wait_for_IRQ( HZ/2 )) {
- SLMError = 1;
- return; /* timeout */
- }
- }
- /* last command byte */
- DMA_LONG_WRITE( *cmd++, 0x82 );
- MFPDELAY();
- /* set DMA address */
- set_dma_addr( paddr );
- /* program DMA for write and select sector counter reg */
- dma_wd.dma_mode_status = 0x192;
- MFPDELAY();
- /* program for 255*512 bytes and start DMA */
- DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 );
-
-#ifndef SLM_CONT_CNT_REPROG
- SLMCurAddr = paddr;
- SLMEndAddr = paddr + SLMSliceSize + SLM_DMA_INT_OFFSET;
-#endif
- START_TIMER( DMA_STARTUP_TIME + DMA_TIME_FOR( SLMSliceSize ));
-#if !defined(SLM_CONT_CNT_REPROG) && defined(DEBUG)
- printk( "SLM: CurAddr=%#lx EndAddr=%#lx timer=%ld\n",
- SLMCurAddr, SLMEndAddr, DMA_TIME_FOR( SLMSliceSize ) );
-#endif
-
- ENABLE_IRQ();
-}
-
-
-/* Only called when an error happened or at the end of a page */
-
-static irqreturn_t slm_interrupt(int irc, void *data)
-
-{ unsigned long addr;
- int stat;
-
- STOP_TIMER();
- addr = get_dma_addr();
- stat = acsi_getstatus();
- SLMError = (stat < 0) ? SLMSTAT_ACSITO :
- (addr < virt_to_phys(BufferP)) ? SLMSTAT_NOTALL :
- stat;
-
- dma_wd.dma_mode_status = 0x80;
- MFPDELAY();
-#ifdef DEBUG
- printk( "SLM: interrupt, addr=%#lx, error=%d\n", addr, SLMError );
-#endif
-
- wake_up( &print_wait );
- stdma_release();
- ENABLE_IRQ();
- return IRQ_HANDLED;
-}
-
-
-static void slm_test_ready( unsigned long dummy )
-
-{
-#ifdef SLM_CONT_CNT_REPROG
- /* program for 255*512 bytes again */
- dma_wd.fdc_acces_seccount = SLM_DMA_AMOUNT;
- START_TIMER( DMA_TIME_FOR(0) );
-#ifdef DEBUG
- printk( "SLM: reprogramming timer for %d jiffies, addr=%#lx\n",
- DMA_TIME_FOR(0), get_dma_addr() );
-#endif
-
-#else /* !SLM_CONT_CNT_REPROG */
-
- unsigned long flags, addr;
- int d, ti;
-#ifdef DEBUG
- struct timeval start_tm, end_tm;
- int did_wait = 0;
-#endif
-
- local_irq_save(flags);
-
- addr = get_dma_addr();
- if ((d = SLMEndAddr - addr) > 0) {
- local_irq_restore(flags);
-
- /* slice not yet finished, decide whether to start another timer or to
- * busy-wait */
- ti = DMA_TIME_FOR( d );
- if (ti > 0) {
-#ifdef DEBUG
- printk( "SLM: reprogramming timer for %d jiffies, rest %d bytes\n",
- ti, d );
-#endif
- START_TIMER( ti );
- return;
- }
- /* wait for desired end address to be reached */
-#ifdef DEBUG
- do_gettimeofday( &start_tm );
- did_wait = 1;
-#endif
- local_irq_disable();
- while( get_dma_addr() < SLMEndAddr )
- barrier();
- }
-
- /* slice finished, start next one */
- SLMCurAddr += SLMSliceSize;
-
-#ifdef SLM_CONTINUOUS_DMA
- /* program for 255*512 bytes again */
- dma_wd.fdc_acces_seccount = SLM_DMA_AMOUNT;
-#else
- /* set DMA address;
- * add 2 bytes for the ones in the SLM controller FIFO! */
- set_dma_addr( SLMCurAddr + 2 );
- /* toggle DMA to write and select sector counter reg */
- dma_wd.dma_mode_status = 0x92;
- MFPDELAY();
- dma_wd.dma_mode_status = 0x192;
- MFPDELAY();
- /* program for 255*512 bytes and start DMA */
- DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 );
-#endif
-
- local_irq_restore(flags);
-
-#ifdef DEBUG
- if (did_wait) {
- int ms;
- do_gettimeofday( &end_tm );
- ms = (end_tm.tv_sec*1000000+end_tm.tv_usec) -
- (start_tm.tv_sec*1000000+start_tm.tv_usec);
- printk( "SLM: did %ld.%ld ms busy waiting for %d bytes\n",
- ms/1000, ms%1000, d );
- }
- else
- printk( "SLM: didn't wait (!)\n" );
-#endif
-
- if ((unsigned char *)PTOV( SLMCurAddr + SLMSliceSize ) >= BufferP) {
- /* will be last slice, no timer necessary */
-#ifdef DEBUG
- printk( "SLM: CurAddr=%#lx EndAddr=%#lx last slice -> no timer\n",
- SLMCurAddr, SLMEndAddr );
-#endif
- }
- else {
- /* not last slice */
- SLMEndAddr = SLMCurAddr + SLMSliceSize + SLM_DMA_INT_OFFSET;
- START_TIMER( DMA_TIME_FOR( SLMSliceSize ));
-#ifdef DEBUG
- printk( "SLM: CurAddr=%#lx EndAddr=%#lx timer=%ld\n",
- SLMCurAddr, SLMEndAddr, DMA_TIME_FOR( SLMSliceSize ) );
-#endif
- }
-#endif /* SLM_CONT_CNT_REPROG */
-}
-
-
-static void set_dma_addr( unsigned long paddr )
-
-{ unsigned long flags;
-
- local_irq_save(flags);
- dma_wd.dma_lo = (unsigned char)paddr;
- paddr >>= 8;
- MFPDELAY();
- dma_wd.dma_md = (unsigned char)paddr;
- paddr >>= 8;
- MFPDELAY();
- if (ATARIHW_PRESENT( EXTD_DMA ))
- st_dma_ext_dmahi = (unsigned short)paddr;
- else
- dma_wd.dma_hi = (unsigned char)paddr;
- MFPDELAY();
- local_irq_restore(flags);
-}
-
-
-static unsigned long get_dma_addr( void )
-
-{ unsigned long addr;
-
- addr = dma_wd.dma_lo & 0xff;
- MFPDELAY();
- addr |= (dma_wd.dma_md & 0xff) << 8;
- MFPDELAY();
- addr |= (dma_wd.dma_hi & 0xff) << 16;
- MFPDELAY();
-
- return( addr );
-}
-
-
-static ssize_t slm_write( struct file *file, const char *buf, size_t count,
- loff_t *ppos )
-
-{
- struct inode *node = file->f_path.dentry->d_inode;
- int device = iminor(node);
- int n, filled, w, h;
-
- while( SLMState == PRINTING ||
- (SLMState == FILLING && SLMBufOwner != device) ) {
- interruptible_sleep_on( &slm_wait );
- if (signal_pending(current))
- return( -ERESTARTSYS );
- }
- if (SLMState == IDLE) {
- /* first data of page: get current page size */
- if (slm_get_pagesize( device, &w, &h ))
- return( -EIO );
- BufferSize = w*h/8;
- if (BufferSize > SLM_BUFFER_SIZE)
- return( -ENOMEM );
-
- SLMState = FILLING;
- SLMBufOwner = device;
- }
-
- n = count;
- filled = BufferP - SLMBuffer;
- if (filled + n > BufferSize)
- n = BufferSize - filled;
-
- if (copy_from_user(BufferP, buf, n))
- return -EFAULT;
- BufferP += n;
- filled += n;
-
- if (filled == BufferSize) {
- /* Check the paper size again! The user may have switched it in the
- * time between starting the data and finishing them. Would end up in
- * a trashy page... */
- if (slm_get_pagesize( device, &w, &h ))
- return( -EIO );
- if (BufferSize != w*h/8) {
- printk( KERN_NOTICE "slm%d: page size changed while printing\n",
- device );
- return( -EAGAIN );
- }
-
- SLMState = PRINTING;
- /* choose a slice size that is a multiple of the line size */
-#ifndef SLM_CONT_CNT_REPROG
- SLMSliceSize = SLM_SLICE_SIZE(w);
-#endif
-
- start_print( device );
- sleep_on( &print_wait );
- if (SLMError && IS_REAL_ERROR(SLMError)) {
- printk( KERN_ERR "slm%d: %s\n", device, slm_errstr(SLMError) );
- n = -EIO;
- }
-
- SLMState = IDLE;
- BufferP = SLMBuffer;
- wake_up_interruptible( &slm_wait );
- }
-
- return( n );
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* ioctl Functions */
-
-
-static int slm_ioctl( struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg )
-
-{ int device = iminor(inode), err;
-
- /* I can think of setting:
- * - manual feed
- * - paper format
- * - copy count
- * - ...
- * but haven't implemented that yet :-)
- * BTW, has anybody better docs about the MODE SENSE/MODE SELECT data?
- */
- switch( cmd ) {
-
- case SLMIORESET: /* reset buffer, i.e. empty the buffer */
- if (!(file->f_mode & 2))
- return( -EINVAL );
- if (SLMState == PRINTING)
- return( -EBUSY );
- SLMState = IDLE;
- BufferP = SLMBuffer;
- wake_up_interruptible( &slm_wait );
- return( 0 );
-
- case SLMIOGSTAT: { /* get status */
- int stat;
- char *str;
-
- stat = slm_req_sense( device );
- if (arg) {
- str = slm_errstr( stat );
- if (put_user(stat,
- (long *)&((struct SLM_status *)arg)->stat))
- return -EFAULT;
- if (copy_to_user( ((struct SLM_status *)arg)->str, str,
- strlen(str) + 1))
- return -EFAULT;
- }
- return( stat );
- }
-
- case SLMIOGPSIZE: { /* get paper size */
- int w, h;
-
- if ((err = slm_get_pagesize( device, &w, &h ))) return( err );
-
- if (put_user(w, (long *)&((struct SLM_paper_size *)arg)->width))
- return -EFAULT;
- if (put_user(h, (long *)&((struct SLM_paper_size *)arg)->height))
- return -EFAULT;
- return( 0 );
- }
-
- case SLMIOGMFEED: /* get manual feed */
- return( -EINVAL );
-
- case SLMIOSPSIZE: /* set paper size */
- return( -EINVAL );
-
- case SLMIOSMFEED: /* set manual feed */
- return( -EINVAL );
-
- }
- return( -EINVAL );
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* Opening and Closing */
-
-
-static int slm_open( struct inode *inode, struct file *file )
-
-{ int device;
- struct slm *sip;
-
- device = iminor(inode);
- if (device >= N_SLM_Printers)
- return( -ENXIO );
- sip = &slm_info[device];
-
- if (file->f_mode & 2) {
- /* open for writing is exclusive */
- if ( !atomic_dec_and_test(&sip->wr_ok) ) {
- atomic_inc(&sip->wr_ok);
- return( -EBUSY );
- }
- }
- if (file->f_mode & 1) {
- /* open for reading is exclusive */
- if ( !atomic_dec_and_test(&sip->rd_ok) ) {
- atomic_inc(&sip->rd_ok);
- return( -EBUSY );
- }
- }
-
- return( 0 );
-}
-
-
-static int slm_release( struct inode *inode, struct file *file )
-
-{ int device;
- struct slm *sip;
-
- device = iminor(inode);
- sip = &slm_info[device];
-
- if (file->f_mode & 2)
- atomic_inc( &sip->wr_ok );
- if (file->f_mode & 1)
- atomic_inc( &sip->rd_ok );
-
- return( 0 );
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* ACSI Primitives for the SLM */
-
-
-static int slm_req_sense( int device )
-
-{ int stat, rv;
- struct slm *sip = &slm_info[device];
-
- stdma_lock( NULL, NULL );
-
- CMDSET_TARG_LUN( slmreqsense_cmd, sip->target, sip->lun );
- if (!acsicmd_nodma( slmreqsense_cmd, 0 ) ||
- (stat = acsi_getstatus()) < 0)
- rv = SLMSTAT_ACSITO;
- else
- rv = stat & 0x1f;
-
- ENABLE_IRQ();
- stdma_release();
- return( rv );
-}
-
-
-static int slm_mode_sense( int device, char *buffer, int abs_flag )
-
-{ unsigned char stat, len;
- int rv = 0;
- struct slm *sip = &slm_info[device];
-
- stdma_lock( NULL, NULL );
-
- CMDSET_TARG_LUN( slmmsense_cmd, sip->target, sip->lun );
- slmmsense_cmd[5] = abs_flag ? 0x80 : 0;
- if (!acsicmd_nodma( slmmsense_cmd, 0 )) {
- rv = SLMSTAT_ACSITO;
- goto the_end;
- }
-
- if (!acsi_extstatus( &stat, 1 )) {
- acsi_end_extstatus();
- rv = SLMSTAT_ACSITO;
- goto the_end;
- }
-
- if (!acsi_extstatus( &len, 1 )) {
- acsi_end_extstatus();
- rv = SLMSTAT_ACSITO;
- goto the_end;
- }
- buffer[0] = len;
- if (!acsi_extstatus( buffer+1, len )) {
- acsi_end_extstatus();
- rv = SLMSTAT_ACSITO;
- goto the_end;
- }
-
- acsi_end_extstatus();
- rv = stat & 0x1f;
-
- the_end:
- ENABLE_IRQ();
- stdma_release();
- return( rv );
-}
-
-
-#if 0
-/* currently unused */
-static int slm_mode_select( int device, char *buffer, int len,
- int default_flag )
-
-{ int stat, rv;
- struct slm *sip = &slm_info[device];
-
- stdma_lock( NULL, NULL );
-
- CMDSET_TARG_LUN( slmmselect_cmd, sip->target, sip->lun );
- slmmselect_cmd[5] = default_flag ? 0x80 : 0;
- if (!acsicmd_nodma( slmmselect_cmd, 0 )) {
- rv = SLMSTAT_ACSITO;
- goto the_end;
- }
-
- if (!default_flag) {
- unsigned char c = len;
- if (!acsi_extcmd( &c, 1 )) {
- rv = SLMSTAT_ACSITO;
- goto the_end;
- }
- if (!acsi_extcmd( buffer, len )) {
- rv = SLMSTAT_ACSITO;
- goto the_end;
- }
- }
-
- stat = acsi_getstatus();
- rv = (stat < 0 ? SLMSTAT_ACSITO : stat);
-
- the_end:
- ENABLE_IRQ();
- stdma_release();
- return( rv );
-}
-#endif
-
-
-static int slm_get_pagesize( int device, int *w, int *h )
-
-{ char buf[256];
- int stat;
-
- stat = slm_mode_sense( device, buf, 0 );
- ENABLE_IRQ();
- stdma_release();
-
- if (stat != SLMSTAT_OK)
- return( -EIO );
-
- *w = (buf[3] << 8) | buf[4];
- *h = (buf[1] << 8) | buf[2];
- return( 0 );
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* Initialization */
-
-
-int attach_slm( int target, int lun )
-
-{ static int did_register;
- int len;
-
- if (N_SLM_Printers >= MAX_SLM) {
- printk( KERN_WARNING "Too much SLMs\n" );
- return( 0 );
- }
-
- /* do an INQUIRY */
- udelay(100);
- CMDSET_TARG_LUN( slminquiry_cmd, target, lun );
- if (!acsicmd_nodma( slminquiry_cmd, 0 )) {
- inq_timeout:
- printk( KERN_ERR "SLM inquiry command timed out.\n" );
- inq_fail:
- acsi_end_extstatus();
- return( 0 );
- }
- /* read status and header of return data */
- if (!acsi_extstatus( SLMBuffer, 6 ))
- goto inq_timeout;
-
- if (SLMBuffer[1] != 2) { /* device type == printer? */
- printk( KERN_ERR "SLM inquiry returned device type != printer\n" );
- goto inq_fail;
- }
- len = SLMBuffer[5];
-
- /* read id string */
- if (!acsi_extstatus( SLMBuffer, len ))
- goto inq_timeout;
- acsi_end_extstatus();
- SLMBuffer[len] = 0;
-
- if (!did_register) {
- did_register = 1;
- }
-
- slm_info[N_SLM_Printers].target = target;
- slm_info[N_SLM_Printers].lun = lun;
- atomic_set(&slm_info[N_SLM_Printers].wr_ok, 1 );
- atomic_set(&slm_info[N_SLM_Printers].rd_ok, 1 );
-
- printk( KERN_INFO " Printer: %s\n", SLMBuffer );
- printk( KERN_INFO "Detected slm%d at id %d lun %d\n",
- N_SLM_Printers, target, lun );
- N_SLM_Printers++;
- return( 1 );
-}
-
-int slm_init( void )
-
-{
- int i;
- if (register_chrdev( ACSI_MAJOR, "slm", &slm_fops )) {
- printk( KERN_ERR "Unable to get major %d for ACSI SLM\n", ACSI_MAJOR );
- return -EBUSY;
- }
-
- if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, "SLM" ))) {
- printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" );
- unregister_chrdev( ACSI_MAJOR, "slm" );
- return -ENOMEM;
- }
- BufferP = SLMBuffer;
- SLMState = IDLE;
-
- return 0;
-}
-
-#ifdef MODULE
-
-/* from acsi.c */
-void acsi_attach_SLMs( int (*attach_func)( int, int ) );
-
-int init_module(void)
-{
- int err;
-
- if ((err = slm_init()))
- return( err );
- /* This calls attach_slm() for every target/lun where acsi.c detected a
- * printer */
- acsi_attach_SLMs( attach_slm );
- return( 0 );
-}
-
-void cleanup_module(void)
-{
- if (unregister_chrdev( ACSI_MAJOR, "slm" ) != 0)
- printk( KERN_ERR "acsi_slm: cleanup_module failed\n");
- atari_stram_free( SLMBuffer );
-}
-#endif
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 478489c568a4..4f598270fa31 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -257,9 +257,9 @@ aoeblk_exit(void)
int __init
aoeblk_init(void)
{
- buf_pool_cache = kmem_cache_create("aoe_bufs",
+ buf_pool_cache = kmem_cache_create("aoe_bufs",
sizeof(struct buf),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (buf_pool_cache == NULL)
return -ENOMEM;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 0fcad430474e..a2d6612b80d2 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1170,7 +1170,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
case SG_EMULATED_HOST:
case SG_IO:
case SCSI_IOCTL_SEND_COMMAND:
- return scsi_cmd_ioctl(filep, disk, cmd, argp);
+ return scsi_cmd_ioctl(filep, disk->queue, disk, cmd, argp);
/* scsi_cmd_ioctl would normally handle these, below, but */
/* they aren't a good fit for cciss, as CD-ROMs are */
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 90961a8ea895..4aca7ddfdddf 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -555,7 +555,6 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
{
struct scsi_cmnd *cmd;
ctlr_info_t *ctlr;
- u64bit addr64;
ErrorInfo_struct *ei;
ei = cp->err_info;
@@ -569,20 +568,7 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
cmd = (struct scsi_cmnd *) cp->scsi_cmd;
ctlr = hba[cp->ctlr];
- /* undo the DMA mappings */
-
- if (cmd->use_sg) {
- pci_unmap_sg(ctlr->pdev,
- cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
- }
- else if (cmd->request_bufflen) {
- addr64.val32.lower = cp->SG[0].Addr.lower;
- addr64.val32.upper = cp->SG[0].Addr.upper;
- pci_unmap_single(ctlr->pdev, (dma_addr_t) addr64.val,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
@@ -597,7 +583,7 @@ complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
SCSI_SENSE_BUFFERSIZE :
ei->SenseLen);
- cmd->resid = ei->ResidualCnt;
+ scsi_set_resid(cmd, ei->ResidualCnt);
if(ei->CommandStatus != 0)
{ /* an error has occurred */
@@ -1204,46 +1190,29 @@ cciss_scatter_gather(struct pci_dev *pdev,
CommandList_struct *cp,
struct scsi_cmnd *cmd)
{
- unsigned int use_sg, nsegs=0, len;
- struct scatterlist *scatter = (struct scatterlist *) cmd->request_buffer;
+ unsigned int len;
+ struct scatterlist *sg;
__u64 addr64;
-
- /* is it just one virtual address? */
- if (!cmd->use_sg) {
- if (cmd->request_bufflen) { /* anything to xfer? */
-
- addr64 = (__u64) pci_map_single(pdev,
- cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
-
- cp->SG[0].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Len = cmd->request_bufflen;
- nsegs=1;
- }
- } /* else, must be a list of virtual addresses.... */
- else if (cmd->use_sg <= MAXSGENTRIES) { /* not too many addrs? */
-
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
-
- for (nsegs=0; nsegs < use_sg; nsegs++) {
- addr64 = (__u64) sg_dma_address(&scatter[nsegs]);
- len = sg_dma_len(&scatter[nsegs]);
- cp->SG[nsegs].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[nsegs].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[nsegs].Len = len;
- cp->SG[nsegs].Ext = 0; // we are not chaining
+ int use_sg, i;
+
+ BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
+
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg) { /* not too many addrs? */
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ addr64 = (__u64) sg_dma_address(sg);
+ len = sg_dma_len(sg);
+ cp->SG[i].Addr.lower =
+ (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Addr.upper =
+ (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
+ cp->SG[i].Len = len;
+ cp->SG[i].Ext = 0; // we are not chaining
}
- } else BUG();
+ }
- cp->Header.SGList = (__u8) nsegs; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) nsegs; /* total sgs in this cmd list */
+ cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
return;
}
diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c
new file mode 100644
index 000000000000..1634c2dd25ec
--- /dev/null
+++ b/drivers/block/lguest_blk.c
@@ -0,0 +1,275 @@
+/* A simple block driver for lguest.
+ *
+ * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> 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 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
+ */
+//#define DEBUG
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/lguest_bus.h>
+
+static char next_block_index = 'a';
+
+struct blockdev
+{
+ spinlock_t lock;
+
+ /* The disk structure for the kernel. */
+ struct gendisk *disk;
+
+ /* The major number for this disk. */
+ int major;
+ int irq;
+
+ unsigned long phys_addr;
+ /* The mapped block page. */
+ struct lguest_block_page *lb_page;
+
+ /* We only have a single request outstanding at a time. */
+ struct lguest_dma dma;
+ struct request *req;
+};
+
+/* Jens gave me this nice helper to end all chunks of a request. */
+static void end_entire_request(struct request *req, int uptodate)
+{
+ if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+ BUG();
+ add_disk_randomness(req->rq_disk);
+ blkdev_dequeue_request(req);
+ end_that_request_last(req, uptodate);
+}
+
+static irqreturn_t lgb_irq(int irq, void *_bd)
+{
+ struct blockdev *bd = _bd;
+ unsigned long flags;
+
+ if (!bd->req) {
+ pr_debug("No work!\n");
+ return IRQ_NONE;
+ }
+
+ if (!bd->lb_page->result) {
+ pr_debug("No result!\n");
+ return IRQ_NONE;
+ }
+
+ spin_lock_irqsave(&bd->lock, flags);
+ end_entire_request(bd->req, bd->lb_page->result == 1);
+ bd->req = NULL;
+ bd->dma.used_len = 0;
+ blk_start_queue(bd->disk->queue);
+ spin_unlock_irqrestore(&bd->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
+{
+ unsigned int i = 0, idx, len = 0;
+ struct bio *bio;
+
+ rq_for_each_bio(bio, req) {
+ struct bio_vec *bvec;
+ bio_for_each_segment(bvec, bio, idx) {
+ BUG_ON(i == LGUEST_MAX_DMA_SECTIONS);
+ BUG_ON(!bvec->bv_len);
+ dma->addr[i] = page_to_phys(bvec->bv_page)
+ + bvec->bv_offset;
+ dma->len[i] = bvec->bv_len;
+ len += bvec->bv_len;
+ i++;
+ }
+ }
+ if (i < LGUEST_MAX_DMA_SECTIONS)
+ dma->len[i] = 0;
+ return len;
+}
+
+static void empty_dma(struct lguest_dma *dma)
+{
+ dma->len[0] = 0;
+}
+
+static void setup_req(struct blockdev *bd,
+ int type, struct request *req, struct lguest_dma *dma)
+{
+ bd->lb_page->type = type;
+ bd->lb_page->sector = req->sector;
+ bd->lb_page->result = 0;
+ bd->req = req;
+ bd->lb_page->bytes = req_to_dma(req, dma);
+}
+
+static void do_write(struct blockdev *bd, struct request *req)
+{
+ struct lguest_dma send;
+
+ pr_debug("lgb: WRITE sector %li\n", (long)req->sector);
+ setup_req(bd, 1, req, &send);
+
+ lguest_send_dma(bd->phys_addr, &send);
+}
+
+static void do_read(struct blockdev *bd, struct request *req)
+{
+ struct lguest_dma ping;
+
+ pr_debug("lgb: READ sector %li\n", (long)req->sector);
+ setup_req(bd, 0, req, &bd->dma);
+
+ empty_dma(&ping);
+ lguest_send_dma(bd->phys_addr, &ping);
+}
+
+static void do_lgb_request(request_queue_t *q)
+{
+ struct blockdev *bd;
+ struct request *req;
+
+again:
+ req = elv_next_request(q);
+ if (!req)
+ return;
+
+ bd = req->rq_disk->private_data;
+ /* Sometimes we get repeated requests after blk_stop_queue. */
+ if (bd->req)
+ return;
+
+ if (!blk_fs_request(req)) {
+ pr_debug("Got non-command 0x%08x\n", req->cmd_type);
+ req->errors++;
+ end_entire_request(req, 0);
+ goto again;
+ }
+
+ if (rq_data_dir(req) == WRITE)
+ do_write(bd, req);
+ else
+ do_read(bd, req);
+
+ /* Wait for interrupt to tell us it's done. */
+ blk_stop_queue(q);
+}
+
+static struct block_device_operations lguestblk_fops = {
+ .owner = THIS_MODULE,
+};
+
+static int lguestblk_probe(struct lguest_device *lgdev)
+{
+ struct blockdev *bd;
+ int err;
+ int irqflags = IRQF_SHARED;
+
+ bd = kmalloc(sizeof(*bd), GFP_KERNEL);
+ if (!bd)
+ return -ENOMEM;
+
+ spin_lock_init(&bd->lock);
+ bd->irq = lgdev_irq(lgdev);
+ bd->req = NULL;
+ bd->dma.used_len = 0;
+ bd->dma.len[0] = 0;
+ bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT);
+
+ bd->lb_page = lguest_map(bd->phys_addr, 1);
+ if (!bd->lb_page) {
+ err = -ENOMEM;
+ goto out_free_bd;
+ }
+
+ bd->major = register_blkdev(0, "lguestblk");
+ if (bd->major < 0) {
+ err = bd->major;
+ goto out_unmap;
+ }
+
+ bd->disk = alloc_disk(1);
+ if (!bd->disk) {
+ err = -ENOMEM;
+ goto out_unregister_blkdev;
+ }
+
+ bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock);
+ if (!bd->disk->queue) {
+ err = -ENOMEM;
+ goto out_put_disk;
+ }
+
+ /* We can only handle a certain number of sg entries */
+ blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS);
+ /* Buffers must not cross page boundaries */
+ blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1);
+
+ sprintf(bd->disk->disk_name, "lgb%c", next_block_index++);
+ if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+ irqflags |= IRQF_SAMPLE_RANDOM;
+ err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd);
+ if (err)
+ goto out_cleanup_queue;
+
+ err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq);
+ if (err)
+ goto out_free_irq;
+
+ bd->disk->major = bd->major;
+ bd->disk->first_minor = 0;
+ bd->disk->private_data = bd;
+ bd->disk->fops = &lguestblk_fops;
+ /* This is initialized to the disk size by the other end. */
+ set_capacity(bd->disk, bd->lb_page->num_sectors);
+ add_disk(bd->disk);
+
+ printk(KERN_INFO "%s: device %i at major %d\n",
+ bd->disk->disk_name, lgdev->index, bd->major);
+
+ lgdev->private = bd;
+ return 0;
+
+out_free_irq:
+ free_irq(bd->irq, bd);
+out_cleanup_queue:
+ blk_cleanup_queue(bd->disk->queue);
+out_put_disk:
+ put_disk(bd->disk);
+out_unregister_blkdev:
+ unregister_blkdev(bd->major, "lguestblk");
+out_unmap:
+ lguest_unmap(bd->lb_page);
+out_free_bd:
+ kfree(bd);
+ return err;
+}
+
+static struct lguest_driver lguestblk_drv = {
+ .name = "lguestblk",
+ .owner = THIS_MODULE,
+ .device_type = LGUEST_DEVICE_T_BLOCK,
+ .probe = lguestblk_probe,
+};
+
+static __init int lguestblk_init(void)
+{
+ return register_lguest_driver(&lguestblk_drv);
+}
+module_init(lguestblk_init);
+
+MODULE_DESCRIPTION("Lguest block driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 4503290da407..e425daa1eac3 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -68,6 +68,7 @@
#include <linux/loop.h>
#include <linux/compat.h>
#include <linux/suspend.h>
+#include <linux/freezer.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> /* for invalidate_bdev() */
#include <linux/completion.h>
@@ -600,13 +601,6 @@ static int loop_thread(void *data)
struct loop_device *lo = data;
struct bio *bio;
- /*
- * loop can be used in an encrypted device,
- * hence, it mustn't be stopped at all
- * because it could be indirectly used during suspension
- */
- current->flags |= PF_NOFREEZE;
-
set_user_nice(current, -20);
while (!kthread_should_stop() || lo->lo_bio) {
@@ -1574,8 +1568,7 @@ static void __exit loop_exit(void)
loop_del_one(lo);
blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
- if (unregister_blkdev(LOOP_MAJOR, "loop"))
- printk(KERN_WARNING "loop: cannot unregister blkdev\n");
+ unregister_blkdev(LOOP_MAJOR, "loop");
}
module_init(loop_init);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c575fb1d585f..c12951024090 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -122,17 +122,12 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size,
int result;
struct msghdr msg;
struct kvec iov;
- unsigned long flags;
- sigset_t oldset;
+ sigset_t blocked, oldset;
/* Allow interception of SIGKILL only
* Don't allow other signals to interrupt the transmission */
- spin_lock_irqsave(&current->sighand->siglock, flags);
- oldset = current->blocked;
- sigfillset(&current->blocked);
- sigdelsetmask(&current->blocked, sigmask(SIGKILL));
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ siginitsetinv(&blocked, sigmask(SIGKILL));
+ sigprocmask(SIG_SETMASK, &blocked, &oldset);
do {
sock->sk->sk_allocation = GFP_NOIO;
@@ -151,11 +146,9 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size,
if (signal_pending(current)) {
siginfo_t info;
- spin_lock_irqsave(&current->sighand->siglock, flags);
printk(KERN_WARNING "nbd (pid %d: %s) got signal %d\n",
- current->pid, current->comm,
- dequeue_signal(current, &current->blocked, &info));
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ current->pid, current->comm,
+ dequeue_signal_lock(current, &current->blocked, &info));
result = -EINTR;
break;
}
@@ -169,10 +162,7 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size,
buf += result;
} while (size > 0);
- spin_lock_irqsave(&current->sighand->siglock, flags);
- current->blocked = oldset;
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
return result;
}
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index f1b9dd7d47d6..31be33e4f119 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -146,8 +146,7 @@ static void pkt_kobj_release(struct kobject *kobj)
**********************************************************/
#define DEF_ATTR(_obj,_name,_mode) \
- static struct attribute _obj = { \
- .name = _name, .owner = THIS_MODULE, .mode = _mode }
+ static struct attribute _obj = { .name = _name, .mode = _mode }
/**********************************************************
/sys/class/pktcdvd/pktcdvd[0-7]/
@@ -1594,6 +1593,7 @@ static int kcdrwd(void *foobar)
long min_sleep_time, residue;
set_user_nice(current, -20);
+ set_freezable();
for (;;) {
DECLARE_WAITQUEUE(wait, current);
@@ -1653,9 +1653,6 @@ static int kcdrwd(void *foobar)
}
}
- if (signal_pending(current)) {
- flush_signals(current);
- }
if (kthread_should_stop())
break;
}
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
new file mode 100644
index 000000000000..170fb33dba97
--- /dev/null
+++ b/drivers/block/ps3disk.c
@@ -0,0 +1,630 @@
+/*
+ * PS3 Disk Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/ata.h>
+#include <linux/blkdev.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+#include <asm/firmware.h>
+
+
+#define DEVICE_NAME "ps3disk"
+
+#define BOUNCE_SIZE (64*1024)
+
+#define PS3DISK_MAX_DISKS 16
+#define PS3DISK_MINORS 16
+
+
+#define PS3DISK_NAME "ps3d%c"
+
+
+struct ps3disk_private {
+ spinlock_t lock; /* Request queue spinlock */
+ struct request_queue *queue;
+ struct gendisk *gendisk;
+ unsigned int blocking_factor;
+ struct request *req;
+ u64 raw_capacity;
+ unsigned char model[ATA_ID_PROD_LEN+1];
+};
+
+
+#define LV1_STORAGE_SEND_ATA_COMMAND (2)
+#define LV1_STORAGE_ATA_HDDOUT (0x23)
+
+struct lv1_ata_cmnd_block {
+ u16 features;
+ u16 sector_count;
+ u16 LBA_low;
+ u16 LBA_mid;
+ u16 LBA_high;
+ u8 device;
+ u8 command;
+ u32 is_ext;
+ u32 proto;
+ u32 in_out;
+ u32 size;
+ u64 buffer;
+ u32 arglen;
+};
+
+enum lv1_ata_proto {
+ NON_DATA_PROTO = 0,
+ PIO_DATA_IN_PROTO = 1,
+ PIO_DATA_OUT_PROTO = 2,
+ DMA_PROTO = 3
+};
+
+enum lv1_ata_in_out {
+ DIR_WRITE = 0, /* memory -> device */
+ DIR_READ = 1 /* device -> memory */
+};
+
+static int ps3disk_major;
+
+
+static struct block_device_operations ps3disk_fops = {
+ .owner = THIS_MODULE,
+};
+
+
+static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
+ struct request *req, int gather)
+{
+ unsigned int offset = 0;
+ struct bio *bio;
+ sector_t sector;
+ struct bio_vec *bvec;
+ unsigned int i = 0, j;
+ size_t size;
+ void *buf;
+
+ rq_for_each_bio(bio, req) {
+ sector = bio->bi_sector;
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: bio %u: %u segs %u sectors from %lu\n",
+ __func__, __LINE__, i, bio_segments(bio),
+ bio_sectors(bio), sector);
+ bio_for_each_segment(bvec, bio, j) {
+ size = bvec->bv_len;
+ buf = __bio_kmap_atomic(bio, j, KM_IRQ0);
+ if (gather)
+ memcpy(dev->bounce_buf+offset, buf, size);
+ else
+ memcpy(buf, dev->bounce_buf+offset, size);
+ offset += size;
+ flush_kernel_dcache_page(bio_iovec_idx(bio, j)->bv_page);
+ __bio_kunmap_atomic(bio, KM_IRQ0);
+ }
+ i++;
+ }
+}
+
+static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
+ struct request *req)
+{
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+ int write = rq_data_dir(req), res;
+ const char *op = write ? "write" : "read";
+ u64 start_sector, sectors;
+ unsigned int region_id = dev->regions[dev->region_idx].id;
+
+#ifdef DEBUG
+ unsigned int n = 0;
+ struct bio *bio;
+
+ rq_for_each_bio(bio, req)
+ n++;
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: %s req has %u bios for %lu sectors %lu hard sectors\n",
+ __func__, __LINE__, op, n, req->nr_sectors,
+ req->hard_nr_sectors);
+#endif
+
+ start_sector = req->sector * priv->blocking_factor;
+ sectors = req->nr_sectors * priv->blocking_factor;
+ dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+ __func__, __LINE__, op, sectors, start_sector);
+
+ if (write) {
+ ps3disk_scatter_gather(dev, req, 1);
+
+ res = lv1_storage_write(dev->sbd.dev_id, region_id,
+ start_sector, sectors, 0,
+ dev->bounce_lpar, &dev->tag);
+ } else {
+ res = lv1_storage_read(dev->sbd.dev_id, region_id,
+ start_sector, sectors, 0,
+ dev->bounce_lpar, &dev->tag);
+ }
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
+ __LINE__, op, res);
+ end_request(req, 0);
+ return 0;
+ }
+
+ priv->req = req;
+ return 1;
+}
+
+static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
+ struct request *req)
+{
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+ u64 res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
+
+ res = lv1_storage_send_device_command(dev->sbd.dev_id,
+ LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
+ 0, &dev->tag);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+ __func__, __LINE__, res);
+ end_request(req, 0);
+ return 0;
+ }
+
+ priv->req = req;
+ return 1;
+}
+
+static void ps3disk_do_request(struct ps3_storage_device *dev,
+ request_queue_t *q)
+{
+ struct request *req;
+
+ dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+ while ((req = elv_next_request(q))) {
+ if (blk_fs_request(req)) {
+ if (ps3disk_submit_request_sg(dev, req))
+ break;
+ } else if (req->cmd_type == REQ_TYPE_FLUSH) {
+ if (ps3disk_submit_flush_request(dev, req))
+ break;
+ } else {
+ blk_dump_rq_flags(req, DEVICE_NAME " bad request");
+ end_request(req, 0);
+ continue;
+ }
+ }
+}
+
+static void ps3disk_request(request_queue_t *q)
+{
+ struct ps3_storage_device *dev = q->queuedata;
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+ if (priv->req) {
+ dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
+ return;
+ }
+
+ ps3disk_do_request(dev, q);
+}
+
+static irqreturn_t ps3disk_interrupt(int irq, void *data)
+{
+ struct ps3_storage_device *dev = data;
+ struct ps3disk_private *priv;
+ struct request *req;
+ int res, read, uptodate;
+ u64 tag, status;
+ unsigned long num_sectors;
+ const char *op;
+
+ res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+ if (tag != dev->tag)
+ dev_err(&dev->sbd.core,
+ "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ __func__, __LINE__, tag, dev->tag);
+
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ __func__, __LINE__, res, status);
+ return IRQ_HANDLED;
+ }
+
+ priv = dev->sbd.core.driver_data;
+ req = priv->req;
+ if (!req) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u non-block layer request completed\n", __func__,
+ __LINE__);
+ dev->lv1_status = status;
+ complete(&dev->done);
+ return IRQ_HANDLED;
+ }
+
+ if (req->cmd_type == REQ_TYPE_FLUSH) {
+ read = 0;
+ num_sectors = req->hard_cur_sectors;
+ op = "flush";
+ } else {
+ read = !rq_data_dir(req);
+ num_sectors = req->nr_sectors;
+ op = read ? "read" : "write";
+ }
+ if (status) {
+ dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ __LINE__, op, status);
+ uptodate = 0;
+ } else {
+ dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
+ __LINE__, op);
+ uptodate = 1;
+ if (read)
+ ps3disk_scatter_gather(dev, req, 0);
+ }
+
+ spin_lock(&priv->lock);
+ if (!end_that_request_first(req, uptodate, num_sectors)) {
+ add_disk_randomness(req->rq_disk);
+ blkdev_dequeue_request(req);
+ end_that_request_last(req, uptodate);
+ }
+ priv->req = NULL;
+ ps3disk_do_request(dev, priv->queue);
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int ps3disk_sync_cache(struct ps3_storage_device *dev)
+{
+ u64 res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__);
+
+ res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+ __func__, __LINE__, res);
+ return -EIO;
+ }
+ return 0;
+}
+
+
+/* ATA helpers copied from drivers/ata/libata-core.c */
+
+static void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+ unsigned int i;
+
+ for (i = 0; i < buf_words; i++)
+ buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+ if (ata_id_has_lba(id)) {
+ if (ata_id_has_lba48(id))
+ return ata_id_u64(id, 100);
+ else
+ return ata_id_u32(id, 60);
+ } else {
+ if (ata_id_current_chs_valid(id))
+ return ata_id_u32(id, 57);
+ else
+ return id[1] * id[3] * id[6];
+ }
+}
+
+static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs,
+ unsigned int len)
+{
+ unsigned int c;
+
+ while (len > 0) {
+ c = id[ofs] >> 8;
+ *s = c;
+ s++;
+
+ c = id[ofs] & 0xff;
+ *s = c;
+ s++;
+
+ ofs++;
+ len -= 2;
+ }
+}
+
+static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
+ unsigned int len)
+{
+ unsigned char *p;
+
+ WARN_ON(!(len & 1));
+
+ ata_id_string(id, s, ofs, len - 1);
+
+ p = s + strnlen(s, len - 1);
+ while (p > s && p[-1] == ' ')
+ p--;
+ *p = '\0';
+}
+
+static int ps3disk_identify(struct ps3_storage_device *dev)
+{
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+ struct lv1_ata_cmnd_block ata_cmnd;
+ u16 *id = dev->bounce_buf;
+ u64 res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: identify disk\n", __func__, __LINE__);
+
+ memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block));
+ ata_cmnd.command = ATA_CMD_ID_ATA;
+ ata_cmnd.sector_count = 1;
+ ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2;
+ ata_cmnd.buffer = dev->bounce_lpar;
+ ata_cmnd.proto = PIO_DATA_IN_PROTO;
+ ata_cmnd.in_out = DIR_READ;
+
+ res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND,
+ ps3_mm_phys_to_lpar(__pa(&ata_cmnd)),
+ sizeof(ata_cmnd), ata_cmnd.buffer,
+ ata_cmnd.arglen);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%lx\n",
+ __func__, __LINE__, res);
+ return -EIO;
+ }
+
+ swap_buf_le16(id, ATA_ID_WORDS);
+
+ /* All we're interested in are raw capacity and model name */
+ priv->raw_capacity = ata_id_n_sectors(id);
+ ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model));
+ return 0;
+}
+
+static void ps3disk_prepare_flush(request_queue_t *q, struct request *req)
+{
+ struct ps3_storage_device *dev = q->queuedata;
+
+ dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+ memset(req->cmd, 0, sizeof(req->cmd));
+ req->cmd_type = REQ_TYPE_FLUSH;
+}
+
+static int ps3disk_issue_flush(request_queue_t *q, struct gendisk *gendisk,
+ sector_t *sector)
+{
+ struct ps3_storage_device *dev = q->queuedata;
+ struct request *req;
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+ req = blk_get_request(q, WRITE, __GFP_WAIT);
+ ps3disk_prepare_flush(q, req);
+ res = blk_execute_rq(q, gendisk, req, 0);
+ if (res)
+ dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n",
+ __func__, __LINE__, res);
+ blk_put_request(req);
+ return res;
+}
+
+
+static unsigned long ps3disk_mask;
+
+static DEFINE_MUTEX(ps3disk_mask_mutex);
+
+static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct ps3disk_private *priv;
+ int error;
+ unsigned int devidx;
+ struct request_queue *queue;
+ struct gendisk *gendisk;
+
+ if (dev->blk_size < 512) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: cannot handle block size %lu\n", __func__,
+ __LINE__, dev->blk_size);
+ return -EINVAL;
+ }
+
+ BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG);
+ mutex_lock(&ps3disk_mask_mutex);
+ devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS);
+ if (devidx >= PS3DISK_MAX_DISKS) {
+ dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__,
+ __LINE__);
+ mutex_unlock(&ps3disk_mask_mutex);
+ return -ENOSPC;
+ }
+ __set_bit(devidx, &ps3disk_mask);
+ mutex_unlock(&ps3disk_mask_mutex);
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dev->sbd.core.driver_data = priv;
+ spin_lock_init(&priv->lock);
+
+ dev->bounce_size = BOUNCE_SIZE;
+ dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+ if (!dev->bounce_buf) {
+ error = -ENOMEM;
+ goto fail_free_priv;
+ }
+
+ error = ps3stor_setup(dev, ps3disk_interrupt);
+ if (error)
+ goto fail_free_bounce;
+
+ ps3disk_identify(dev);
+
+ queue = blk_init_queue(ps3disk_request, &priv->lock);
+ if (!queue) {
+ dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
+ __func__, __LINE__);
+ error = -ENOMEM;
+ goto fail_teardown;
+ }
+
+ priv->queue = queue;
+ queue->queuedata = dev;
+
+ blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
+
+ blk_queue_max_sectors(queue, dev->bounce_size >> 9);
+ blk_queue_segment_boundary(queue, -1UL);
+ blk_queue_dma_alignment(queue, dev->blk_size-1);
+ blk_queue_hardsect_size(queue, dev->blk_size);
+
+ blk_queue_issue_flush_fn(queue, ps3disk_issue_flush);
+ blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
+ ps3disk_prepare_flush);
+
+ blk_queue_max_phys_segments(queue, -1);
+ blk_queue_max_hw_segments(queue, -1);
+ blk_queue_max_segment_size(queue, dev->bounce_size);
+
+ gendisk = alloc_disk(PS3DISK_MINORS);
+ if (!gendisk) {
+ dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
+ __LINE__);
+ error = -ENOMEM;
+ goto fail_cleanup_queue;
+ }
+
+ priv->gendisk = gendisk;
+ gendisk->major = ps3disk_major;
+ gendisk->first_minor = devidx * PS3DISK_MINORS;
+ gendisk->fops = &ps3disk_fops;
+ gendisk->queue = queue;
+ gendisk->private_data = dev;
+ gendisk->driverfs_dev = &dev->sbd.core;
+ snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
+ devidx+'a');
+ priv->blocking_factor = dev->blk_size >> 9;
+ set_capacity(gendisk,
+ dev->regions[dev->region_idx].size*priv->blocking_factor);
+
+ dev_info(&dev->sbd.core,
+ "%s is a %s (%lu MiB total, %lu MiB for OtherOS)\n",
+ gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
+ get_capacity(gendisk) >> 11);
+
+ add_disk(gendisk);
+ return 0;
+
+fail_cleanup_queue:
+ blk_cleanup_queue(queue);
+fail_teardown:
+ ps3stor_teardown(dev);
+fail_free_bounce:
+ kfree(dev->bounce_buf);
+fail_free_priv:
+ kfree(priv);
+ dev->sbd.core.driver_data = NULL;
+fail:
+ mutex_lock(&ps3disk_mask_mutex);
+ __clear_bit(devidx, &ps3disk_mask);
+ mutex_unlock(&ps3disk_mask_mutex);
+ return error;
+}
+
+static int ps3disk_remove(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+ mutex_lock(&ps3disk_mask_mutex);
+ __clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
+ &ps3disk_mask);
+ mutex_unlock(&ps3disk_mask_mutex);
+ del_gendisk(priv->gendisk);
+ blk_cleanup_queue(priv->queue);
+ put_disk(priv->gendisk);
+ dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
+ ps3disk_sync_cache(dev);
+ ps3stor_teardown(dev);
+ kfree(dev->bounce_buf);
+ kfree(priv);
+ dev->sbd.core.driver_data = NULL;
+ return 0;
+}
+
+static struct ps3_system_bus_driver ps3disk = {
+ .match_id = PS3_MATCH_ID_STOR_DISK,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3disk_probe,
+ .remove = ps3disk_remove,
+ .shutdown = ps3disk_remove,
+};
+
+
+static int __init ps3disk_init(void)
+{
+ int error;
+
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return -ENODEV;
+
+ error = register_blkdev(0, DEVICE_NAME);
+ if (error <= 0) {
+ printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
+ __LINE__, error);
+ return error;
+ }
+ ps3disk_major = error;
+
+ pr_info("%s:%u: registered block device major %d\n", __func__,
+ __LINE__, ps3disk_major);
+
+ error = ps3_system_bus_driver_register(&ps3disk);
+ if (error)
+ unregister_blkdev(ps3disk_major, DEVICE_NAME);
+
+ return error;
+}
+
+static void __exit ps3disk_exit(void)
+{
+ ps3_system_bus_driver_unregister(&ps3disk);
+ unregister_blkdev(ps3disk_major, DEVICE_NAME);
+}
+
+module_init(ps3disk_init);
+module_exit(ps3disk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 Disk Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK);
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
new file mode 100644
index 000000000000..d50b82381155
--- /dev/null
+++ b/drivers/block/sunvdc.c
@@ -0,0 +1,887 @@
+/* sunvdc.c: Sun LDOM Virtual Disk Client.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/list.h>
+
+#include <asm/vio.h>
+#include <asm/ldc.h>
+
+#define DRV_MODULE_NAME "sunvdc"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.0"
+#define DRV_MODULE_RELDATE "June 25, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun LDOM virtual disk client driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+#define VDC_TX_RING_SIZE 256
+
+#define WAITING_FOR_LINK_UP 0x01
+#define WAITING_FOR_TX_SPACE 0x02
+#define WAITING_FOR_GEN_CMD 0x04
+#define WAITING_FOR_ANY -1
+
+struct vdc_req_entry {
+ struct request *req;
+};
+
+struct vdc_port {
+ struct vio_driver_state vio;
+
+ struct gendisk *disk;
+
+ struct vdc_completion *cmp;
+
+ u64 req_id;
+ u64 seq;
+ struct vdc_req_entry rq_arr[VDC_TX_RING_SIZE];
+
+ unsigned long ring_cookies;
+
+ u64 max_xfer_size;
+ u32 vdisk_block_size;
+
+ /* The server fills these in for us in the disk attribute
+ * ACK packet.
+ */
+ u64 operations;
+ u32 vdisk_size;
+ u8 vdisk_type;
+
+ char disk_name[32];
+
+ struct vio_disk_geom geom;
+ struct vio_disk_vtoc label;
+};
+
+static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
+{
+ return container_of(vio, struct vdc_port, vio);
+}
+
+/* Ordered from largest major to lowest */
+static struct vio_version vdc_versions[] = {
+ { .major = 1, .minor = 0 },
+};
+
+#define VDCBLK_NAME "vdisk"
+static int vdc_major;
+#define PARTITION_SHIFT 3
+
+static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr)
+{
+ return vio_dring_avail(dr, VDC_TX_RING_SIZE);
+}
+
+static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ struct gendisk *disk = bdev->bd_disk;
+ struct vdc_port *port = disk->private_data;
+
+ geo->heads = (u8) port->geom.num_hd;
+ geo->sectors = (u8) port->geom.num_sec;
+ geo->cylinders = port->geom.num_cyl;
+
+ return 0;
+}
+
+static struct block_device_operations vdc_fops = {
+ .owner = THIS_MODULE,
+ .getgeo = vdc_getgeo,
+};
+
+static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for)
+{
+ if (vio->cmp &&
+ (waiting_for == -1 ||
+ vio->cmp->waiting_for == waiting_for)) {
+ vio->cmp->err = err;
+ complete(&vio->cmp->com);
+ vio->cmp = NULL;
+ }
+}
+
+static void vdc_handshake_complete(struct vio_driver_state *vio)
+{
+ vdc_finish(vio, 0, WAITING_FOR_LINK_UP);
+}
+
+static int vdc_handle_unknown(struct vdc_port *port, void *arg)
+{
+ struct vio_msg_tag *pkt = arg;
+
+ printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n",
+ pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
+ printk(KERN_ERR PFX "Resetting connection.\n");
+
+ ldc_disconnect(port->vio.lp);
+
+ return -ECONNRESET;
+}
+
+static int vdc_send_attr(struct vio_driver_state *vio)
+{
+ struct vdc_port *port = to_vdc_port(vio);
+ struct vio_disk_attr_info pkt;
+
+ memset(&pkt, 0, sizeof(pkt));
+
+ pkt.tag.type = VIO_TYPE_CTRL;
+ pkt.tag.stype = VIO_SUBTYPE_INFO;
+ pkt.tag.stype_env = VIO_ATTR_INFO;
+ pkt.tag.sid = vio_send_sid(vio);
+
+ pkt.xfer_mode = VIO_DRING_MODE;
+ pkt.vdisk_block_size = port->vdisk_block_size;
+ pkt.max_xfer_size = port->max_xfer_size;
+
+ viodbg(HS, "SEND ATTR xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
+ pkt.xfer_mode, pkt.vdisk_block_size, pkt.max_xfer_size);
+
+ return vio_ldc_send(&port->vio, &pkt, sizeof(pkt));
+}
+
+static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
+{
+ struct vdc_port *port = to_vdc_port(vio);
+ struct vio_disk_attr_info *pkt = arg;
+
+ viodbg(HS, "GOT ATTR stype[0x%x] ops[%lx] disk_size[%lu] disk_type[%x] "
+ "xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n",
+ pkt->tag.stype, pkt->operations,
+ pkt->vdisk_size, pkt->vdisk_type,
+ pkt->xfer_mode, pkt->vdisk_block_size,
+ pkt->max_xfer_size);
+
+ if (pkt->tag.stype == VIO_SUBTYPE_ACK) {
+ switch (pkt->vdisk_type) {
+ case VD_DISK_TYPE_DISK:
+ case VD_DISK_TYPE_SLICE:
+ break;
+
+ default:
+ printk(KERN_ERR PFX "%s: Bogus vdisk_type 0x%x\n",
+ vio->name, pkt->vdisk_type);
+ return -ECONNRESET;
+ }
+
+ if (pkt->vdisk_block_size > port->vdisk_block_size) {
+ printk(KERN_ERR PFX "%s: BLOCK size increased "
+ "%u --> %u\n",
+ vio->name,
+ port->vdisk_block_size, pkt->vdisk_block_size);
+ return -ECONNRESET;
+ }
+
+ port->operations = pkt->operations;
+ port->vdisk_size = pkt->vdisk_size;
+ port->vdisk_type = pkt->vdisk_type;
+ if (pkt->max_xfer_size < port->max_xfer_size)
+ port->max_xfer_size = pkt->max_xfer_size;
+ port->vdisk_block_size = pkt->vdisk_block_size;
+ return 0;
+ } else {
+ printk(KERN_ERR PFX "%s: Attribute NACK\n", vio->name);
+
+ return -ECONNRESET;
+ }
+}
+
+static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
+{
+ int err = desc->status;
+
+ vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
+}
+
+static void vdc_end_request(struct request *req, int uptodate, int num_sectors)
+{
+ if (end_that_request_first(req, uptodate, num_sectors))
+ return;
+ add_disk_randomness(req->rq_disk);
+ end_that_request_last(req, uptodate);
+}
+
+static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
+ unsigned int index)
+{
+ struct vio_disk_desc *desc = vio_dring_entry(dr, index);
+ struct vdc_req_entry *rqe = &port->rq_arr[index];
+ struct request *req;
+
+ if (unlikely(desc->hdr.state != VIO_DESC_DONE))
+ return;
+
+ ldc_unmap(port->vio.lp, desc->cookies, desc->ncookies);
+ desc->hdr.state = VIO_DESC_FREE;
+ dr->cons = (index + 1) & (VDC_TX_RING_SIZE - 1);
+
+ req = rqe->req;
+ if (req == NULL) {
+ vdc_end_special(port, desc);
+ return;
+ }
+
+ rqe->req = NULL;
+
+ vdc_end_request(req, !desc->status, desc->size >> 9);
+
+ if (blk_queue_stopped(port->disk->queue))
+ blk_start_queue(port->disk->queue);
+}
+
+static int vdc_ack(struct vdc_port *port, void *msgbuf)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct vio_dring_data *pkt = msgbuf;
+
+ if (unlikely(pkt->dring_ident != dr->ident ||
+ pkt->start_idx != pkt->end_idx ||
+ pkt->start_idx >= VDC_TX_RING_SIZE))
+ return 0;
+
+ vdc_end_one(port, dr, pkt->start_idx);
+
+ return 0;
+}
+
+static int vdc_nack(struct vdc_port *port, void *msgbuf)
+{
+ /* XXX Implement me XXX */
+ return 0;
+}
+
+static void vdc_event(void *arg, int event)
+{
+ struct vdc_port *port = arg;
+ struct vio_driver_state *vio = &port->vio;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&vio->lock, flags);
+
+ if (unlikely(event == LDC_EVENT_RESET ||
+ event == LDC_EVENT_UP)) {
+ vio_link_state_change(vio, event);
+ spin_unlock_irqrestore(&vio->lock, flags);
+ return;
+ }
+
+ if (unlikely(event != LDC_EVENT_DATA_READY)) {
+ printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+ spin_unlock_irqrestore(&vio->lock, flags);
+ return;
+ }
+
+ err = 0;
+ while (1) {
+ union {
+ struct vio_msg_tag tag;
+ u64 raw[8];
+ } msgbuf;
+
+ err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf));
+ if (unlikely(err < 0)) {
+ if (err == -ECONNRESET)
+ vio_conn_reset(vio);
+ break;
+ }
+ if (err == 0)
+ break;
+ viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n",
+ msgbuf.tag.type,
+ msgbuf.tag.stype,
+ msgbuf.tag.stype_env,
+ msgbuf.tag.sid);
+ err = vio_validate_sid(vio, &msgbuf.tag);
+ if (err < 0)
+ break;
+
+ if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) {
+ if (msgbuf.tag.stype == VIO_SUBTYPE_ACK)
+ err = vdc_ack(port, &msgbuf);
+ else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK)
+ err = vdc_nack(port, &msgbuf);
+ else
+ err = vdc_handle_unknown(port, &msgbuf);
+ } else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
+ err = vio_control_pkt_engine(vio, &msgbuf);
+ } else {
+ err = vdc_handle_unknown(port, &msgbuf);
+ }
+ if (err < 0)
+ break;
+ }
+ if (err < 0)
+ vdc_finish(&port->vio, err, WAITING_FOR_ANY);
+ spin_unlock_irqrestore(&vio->lock, flags);
+}
+
+static int __vdc_tx_trigger(struct vdc_port *port)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct vio_dring_data hdr = {
+ .tag = {
+ .type = VIO_TYPE_DATA,
+ .stype = VIO_SUBTYPE_INFO,
+ .stype_env = VIO_DRING_DATA,
+ .sid = vio_send_sid(&port->vio),
+ },
+ .dring_ident = dr->ident,
+ .start_idx = dr->prod,
+ .end_idx = dr->prod,
+ };
+ int err, delay;
+
+ hdr.seq = dr->snd_nxt;
+ delay = 1;
+ do {
+ err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr));
+ if (err > 0) {
+ dr->snd_nxt++;
+ break;
+ }
+ udelay(delay);
+ if ((delay <<= 1) > 128)
+ delay = 128;
+ } while (err == -EAGAIN);
+
+ return err;
+}
+
+static int __send_request(struct request *req)
+{
+ struct vdc_port *port = req->rq_disk->private_data;
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct scatterlist sg[port->ring_cookies];
+ struct vdc_req_entry *rqe;
+ struct vio_disk_desc *desc;
+ unsigned int map_perm;
+ int nsg, err, i;
+ u64 len;
+ u8 op;
+
+ map_perm = LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO;
+
+ if (rq_data_dir(req) == READ) {
+ map_perm |= LDC_MAP_W;
+ op = VD_OP_BREAD;
+ } else {
+ map_perm |= LDC_MAP_R;
+ op = VD_OP_BWRITE;
+ }
+
+ nsg = blk_rq_map_sg(req->q, req, sg);
+
+ len = 0;
+ for (i = 0; i < nsg; i++)
+ len += sg[i].length;
+
+ if (unlikely(vdc_tx_dring_avail(dr) < 1)) {
+ blk_stop_queue(port->disk->queue);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ desc = vio_dring_cur(dr);
+
+ err = ldc_map_sg(port->vio.lp, sg, nsg,
+ desc->cookies, port->ring_cookies,
+ map_perm);
+ if (err < 0) {
+ printk(KERN_ERR PFX "ldc_map_sg() failure, err=%d.\n", err);
+ return err;
+ }
+
+ rqe = &port->rq_arr[dr->prod];
+ rqe->req = req;
+
+ desc->hdr.ack = VIO_ACK_ENABLE;
+ desc->req_id = port->req_id;
+ desc->operation = op;
+ if (port->vdisk_type == VD_DISK_TYPE_DISK) {
+ desc->slice = 2;
+ } else {
+ desc->slice = 0;
+ }
+ desc->status = ~0;
+ desc->offset = (req->sector << 9) / port->vdisk_block_size;
+ desc->size = len;
+ desc->ncookies = err;
+
+ /* This has to be a non-SMP write barrier because we are writing
+ * to memory which is shared with the peer LDOM.
+ */
+ wmb();
+ desc->hdr.state = VIO_DESC_READY;
+
+ err = __vdc_tx_trigger(port);
+ if (err < 0) {
+ printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err);
+ } else {
+ port->req_id++;
+ dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
+ }
+out:
+
+ return err;
+}
+
+static void do_vdc_request(request_queue_t *q)
+{
+ while (1) {
+ struct request *req = elv_next_request(q);
+
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+ if (__send_request(req) < 0)
+ vdc_end_request(req, 0, req->hard_nr_sectors);
+ }
+}
+
+static int generic_request(struct vdc_port *port, u8 op, void *buf, int len)
+{
+ struct vio_dring_state *dr;
+ struct vio_completion comp;
+ struct vio_disk_desc *desc;
+ unsigned int map_perm;
+ unsigned long flags;
+ int op_len, err;
+ void *req_buf;
+
+ if (!(((u64)1 << ((u64)op - 1)) & port->operations))
+ return -EOPNOTSUPP;
+
+ switch (op) {
+ case VD_OP_BREAD:
+ case VD_OP_BWRITE:
+ default:
+ return -EINVAL;
+
+ case VD_OP_FLUSH:
+ op_len = 0;
+ map_perm = 0;
+ break;
+
+ case VD_OP_GET_WCE:
+ op_len = sizeof(u32);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_SET_WCE:
+ op_len = sizeof(u32);
+ map_perm = LDC_MAP_R;
+ break;
+
+ case VD_OP_GET_VTOC:
+ op_len = sizeof(struct vio_disk_vtoc);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_SET_VTOC:
+ op_len = sizeof(struct vio_disk_vtoc);
+ map_perm = LDC_MAP_R;
+ break;
+
+ case VD_OP_GET_DISKGEOM:
+ op_len = sizeof(struct vio_disk_geom);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_SET_DISKGEOM:
+ op_len = sizeof(struct vio_disk_geom);
+ map_perm = LDC_MAP_R;
+ break;
+
+ case VD_OP_SCSICMD:
+ op_len = 16;
+ map_perm = LDC_MAP_RW;
+ break;
+
+ case VD_OP_GET_DEVID:
+ op_len = sizeof(struct vio_disk_devid);
+ map_perm = LDC_MAP_W;
+ break;
+
+ case VD_OP_GET_EFI:
+ case VD_OP_SET_EFI:
+ return -EOPNOTSUPP;
+ break;
+ };
+
+ map_perm |= LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO;
+
+ op_len = (op_len + 7) & ~7;
+ req_buf = kzalloc(op_len, GFP_KERNEL);
+ if (!req_buf)
+ return -ENOMEM;
+
+ if (len > op_len)
+ len = op_len;
+
+ if (map_perm & LDC_MAP_R)
+ memcpy(req_buf, buf, len);
+
+ spin_lock_irqsave(&port->vio.lock, flags);
+
+ dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+
+ /* XXX If we want to use this code generically we have to
+ * XXX handle TX ring exhaustion etc.
+ */
+ desc = vio_dring_cur(dr);
+
+ err = ldc_map_single(port->vio.lp, req_buf, op_len,
+ desc->cookies, port->ring_cookies,
+ map_perm);
+ if (err < 0) {
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+ kfree(req_buf);
+ return err;
+ }
+
+ init_completion(&comp.com);
+ comp.waiting_for = WAITING_FOR_GEN_CMD;
+ port->vio.cmp = &comp;
+
+ desc->hdr.ack = VIO_ACK_ENABLE;
+ desc->req_id = port->req_id;
+ desc->operation = op;
+ desc->slice = 0;
+ desc->status = ~0;
+ desc->offset = 0;
+ desc->size = op_len;
+ desc->ncookies = err;
+
+ /* This has to be a non-SMP write barrier because we are writing
+ * to memory which is shared with the peer LDOM.
+ */
+ wmb();
+ desc->hdr.state = VIO_DESC_READY;
+
+ err = __vdc_tx_trigger(port);
+ if (err >= 0) {
+ port->req_id++;
+ dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+
+ wait_for_completion(&comp.com);
+ err = comp.err;
+ } else {
+ port->vio.cmp = NULL;
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+ }
+
+ if (map_perm & LDC_MAP_W)
+ memcpy(buf, req_buf, len);
+
+ kfree(req_buf);
+
+ return err;
+}
+
+static int __devinit vdc_alloc_tx_ring(struct vdc_port *port)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ unsigned long len, entry_size;
+ int ncookies;
+ void *dring;
+
+ entry_size = sizeof(struct vio_disk_desc) +
+ (sizeof(struct ldc_trans_cookie) * port->ring_cookies);
+ len = (VDC_TX_RING_SIZE * entry_size);
+
+ ncookies = VIO_MAX_RING_COOKIES;
+ dring = ldc_alloc_exp_dring(port->vio.lp, len,
+ dr->cookies, &ncookies,
+ (LDC_MAP_SHADOW |
+ LDC_MAP_DIRECT |
+ LDC_MAP_RW));
+ if (IS_ERR(dring))
+ return PTR_ERR(dring);
+
+ dr->base = dring;
+ dr->entry_size = entry_size;
+ dr->num_entries = VDC_TX_RING_SIZE;
+ dr->prod = dr->cons = 0;
+ dr->pending = VDC_TX_RING_SIZE;
+ dr->ncookies = ncookies;
+
+ return 0;
+}
+
+static void vdc_free_tx_ring(struct vdc_port *port)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+
+ if (dr->base) {
+ ldc_free_exp_dring(port->vio.lp, dr->base,
+ (dr->entry_size * dr->num_entries),
+ dr->cookies, dr->ncookies);
+ dr->base = NULL;
+ dr->entry_size = 0;
+ dr->num_entries = 0;
+ dr->pending = 0;
+ dr->ncookies = 0;
+ }
+}
+
+static int probe_disk(struct vdc_port *port)
+{
+ struct vio_completion comp;
+ struct request_queue *q;
+ struct gendisk *g;
+ int err;
+
+ init_completion(&comp.com);
+ comp.err = 0;
+ comp.waiting_for = WAITING_FOR_LINK_UP;
+ port->vio.cmp = &comp;
+
+ vio_port_up(&port->vio);
+
+ wait_for_completion(&comp.com);
+ if (comp.err)
+ return comp.err;
+
+ err = generic_request(port, VD_OP_GET_VTOC,
+ &port->label, sizeof(port->label));
+ if (err < 0) {
+ printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err);
+ return err;
+ }
+
+ err = generic_request(port, VD_OP_GET_DISKGEOM,
+ &port->geom, sizeof(port->geom));
+ if (err < 0) {
+ printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns "
+ "error %d\n", err);
+ return err;
+ }
+
+ port->vdisk_size = ((u64)port->geom.num_cyl *
+ (u64)port->geom.num_hd *
+ (u64)port->geom.num_sec);
+
+ q = blk_init_queue(do_vdc_request, &port->vio.lock);
+ if (!q) {
+ printk(KERN_ERR PFX "%s: Could not allocate queue.\n",
+ port->vio.name);
+ return -ENOMEM;
+ }
+ g = alloc_disk(1 << PARTITION_SHIFT);
+ if (!g) {
+ printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n",
+ port->vio.name);
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ port->disk = g;
+
+ blk_queue_max_hw_segments(q, port->ring_cookies);
+ blk_queue_max_phys_segments(q, port->ring_cookies);
+ blk_queue_max_sectors(q, port->max_xfer_size);
+ g->major = vdc_major;
+ g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
+ strcpy(g->disk_name, port->disk_name);
+
+ g->fops = &vdc_fops;
+ g->queue = q;
+ g->private_data = port;
+ g->driverfs_dev = &port->vio.vdev->dev;
+
+ set_capacity(g, port->vdisk_size);
+
+ printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n",
+ g->disk_name,
+ port->vdisk_size, (port->vdisk_size >> (20 - 9)));
+
+ add_disk(g);
+
+ return 0;
+}
+
+static struct ldc_channel_config vdc_ldc_cfg = {
+ .event = vdc_event,
+ .mtu = 64,
+ .mode = LDC_MODE_UNRELIABLE,
+};
+
+static struct vio_driver_ops vdc_vio_ops = {
+ .send_attr = vdc_send_attr,
+ .handle_attr = vdc_handle_attr,
+ .handshake_complete = vdc_handshake_complete,
+};
+
+static void print_version(void)
+{
+ static int version_printed;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
+static int __devinit vdc_port_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ struct mdesc_handle *hp;
+ struct vdc_port *port;
+ int err;
+
+ print_version();
+
+ hp = mdesc_grab();
+
+ err = -ENODEV;
+ if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+ printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+ vdev->dev_no);
+ goto err_out_release_mdesc;
+ }
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!port) {
+ printk(KERN_ERR PFX "Cannot allocate vdc_port.\n");
+ goto err_out_release_mdesc;
+ }
+
+ if (vdev->dev_no >= 26)
+ snprintf(port->disk_name, sizeof(port->disk_name),
+ VDCBLK_NAME "%c%c",
+ 'a' + ((int)vdev->dev_no / 26) - 1,
+ 'a' + ((int)vdev->dev_no % 26));
+ else
+ snprintf(port->disk_name, sizeof(port->disk_name),
+ VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
+
+ err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
+ vdc_versions, ARRAY_SIZE(vdc_versions),
+ &vdc_vio_ops, port->disk_name);
+ if (err)
+ goto err_out_free_port;
+
+ port->vdisk_block_size = 512;
+ port->max_xfer_size = ((128 * 1024) / port->vdisk_block_size);
+ port->ring_cookies = ((port->max_xfer_size *
+ port->vdisk_block_size) / PAGE_SIZE) + 2;
+
+ err = vio_ldc_alloc(&port->vio, &vdc_ldc_cfg, port);
+ if (err)
+ goto err_out_free_port;
+
+ err = vdc_alloc_tx_ring(port);
+ if (err)
+ goto err_out_free_ldc;
+
+ err = probe_disk(port);
+ if (err)
+ goto err_out_free_tx_ring;
+
+ dev_set_drvdata(&vdev->dev, port);
+
+ mdesc_release(hp);
+
+ return 0;
+
+err_out_free_tx_ring:
+ vdc_free_tx_ring(port);
+
+err_out_free_ldc:
+ vio_ldc_free(&port->vio);
+
+err_out_free_port:
+ kfree(port);
+
+err_out_release_mdesc:
+ mdesc_release(hp);
+ return err;
+}
+
+static int vdc_port_remove(struct vio_dev *vdev)
+{
+ struct vdc_port *port = dev_get_drvdata(&vdev->dev);
+
+ if (port) {
+ del_timer_sync(&port->vio.timer);
+
+ vdc_free_tx_ring(port);
+ vio_ldc_free(&port->vio);
+
+ dev_set_drvdata(&vdev->dev, NULL);
+
+ kfree(port);
+ }
+ return 0;
+}
+
+static struct vio_device_id vdc_port_match[] = {
+ {
+ .type = "vdc-port",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
+
+static struct vio_driver vdc_port_driver = {
+ .id_table = vdc_port_match,
+ .probe = vdc_port_probe,
+ .remove = vdc_port_remove,
+ .driver = {
+ .name = "vdc_port",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init vdc_init(void)
+{
+ int err;
+
+ err = register_blkdev(0, VDCBLK_NAME);
+ if (err < 0)
+ goto out_err;
+
+ vdc_major = err;
+
+ err = vio_register_driver(&vdc_port_driver);
+ if (err)
+ goto out_unregister_blkdev;
+
+ return 0;
+
+out_unregister_blkdev:
+ unregister_blkdev(vdc_major, VDCBLK_NAME);
+ vdc_major = 0;
+
+out_err:
+ return err;
+}
+
+static void __exit vdc_exit(void)
+{
+ vio_unregister_driver(&vdc_port_driver);
+ unregister_blkdev(vdc_major, VDCBLK_NAME);
+}
+
+module_init(vdc_init);
+module_exit(vdc_exit);
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 54509eb3391b..949ae93499e5 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -1608,7 +1608,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
#endif
- host = kmalloc(sizeof(*host), GFP_KERNEL);
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
if (!host) {
printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",
pci_name(pdev));
@@ -1616,7 +1616,6 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_regions;
}
- memset(host, 0, sizeof(*host));
host->pdev = pdev;
host->flags = pci_dac ? FL_DAC : 0;
spin_lock_init(&host->lock);
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 746a118a9b52..8b13d7d2cb63 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -1547,10 +1547,8 @@ static void ub_reset_enter(struct ub_dev *sc, int try)
#endif
#if 0 /* We let them stop themselves. */
- struct list_head *p;
struct ub_lun *lun;
- list_for_each(p, &sc->luns) {
- lun = list_entry(p, struct ub_lun, link);
+ list_for_each_entry(lun, &sc->luns, link) {
blk_stop_queue(lun->disk->queue);
}
#endif
@@ -1562,7 +1560,6 @@ static void ub_reset_task(struct work_struct *work)
{
struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
unsigned long flags;
- struct list_head *p;
struct ub_lun *lun;
int lkr, rc;
@@ -1608,8 +1605,7 @@ static void ub_reset_task(struct work_struct *work)
spin_lock_irqsave(sc->lock, flags);
sc->reset = 0;
tasklet_schedule(&sc->tasklet);
- list_for_each(p, &sc->luns) {
- lun = list_entry(p, struct ub_lun, link);
+ list_for_each_entry(lun, &sc->luns, link) {
blk_start_queue(lun->disk->queue);
}
wake_up(&sc->reset_wait);
@@ -1713,7 +1709,7 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp,
struct gendisk *disk = inode->i_bdev->bd_disk;
void __user *usermem = (void __user *) arg;
- return scsi_cmd_ioctl(filp, disk, cmd, usermem);
+ return scsi_cmd_ioctl(filp, disk->queue, disk, cmd, usermem);
}
/*
@@ -2348,7 +2344,6 @@ err_alloc:
static void ub_disconnect(struct usb_interface *intf)
{
struct ub_dev *sc = usb_get_intfdata(intf);
- struct list_head *p;
struct ub_lun *lun;
unsigned long flags;
@@ -2403,8 +2398,7 @@ static void ub_disconnect(struct usb_interface *intf)
/*
* Unregister the upper layer.
*/
- list_for_each (p, &sc->luns) {
- lun = list_entry(p, struct ub_lun, link);
+ list_for_each_entry(lun, &sc->luns, link) {
del_gendisk(lun->disk);
/*
* I wish I could do:
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 6f5d6203d725..dec74bd23496 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -105,12 +105,6 @@ struct cardinfo {
unsigned long csr_base;
unsigned char __iomem *csr_remap;
unsigned long csr_len;
-#ifdef CONFIG_MM_MAP_MEMORY
- unsigned long mem_base;
- unsigned char __iomem *mem_remap;
- unsigned long mem_len;
-#endif
-
unsigned int win_size; /* PCI window size */
unsigned int mm_size; /* size in kbytes */
@@ -872,10 +866,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
card->csr_base = pci_resource_start(dev, 0);
card->csr_len = pci_resource_len(dev, 0);
-#ifdef CONFIG_MM_MAP_MEMORY
- card->mem_base = pci_resource_start(dev, 1);
- card->mem_len = pci_resource_len(dev, 1);
-#endif
printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n",
card->card_number, dev->bus->number, dev->devfn);
@@ -903,27 +893,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number,
card->csr_base, card->csr_remap, card->csr_len);
-#ifdef CONFIG_MM_MAP_MEMORY
- if (!request_mem_region(card->mem_base, card->mem_len, "Micro Memory")) {
- printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number);
- ret = -ENOMEM;
-
- goto failed_req_mem;
- }
-
- if (!(card->mem_remap = ioremap(card->mem_base, cards->mem_len))) {
- printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number);
- ret = -ENOMEM;
-
- goto failed_remap_mem;
- }
-
- printk(KERN_INFO "MM%d: MEM 0x%8lx -> 0x%8lx (0x%lx)\n", card->card_number,
- card->mem_base, card->mem_remap, card->mem_len);
-#else
- printk(KERN_INFO "MM%d: MEM area not remapped (CONFIG_MM_MAP_MEMORY not set)\n",
- card->card_number);
-#endif
switch(card->dev->device) {
case 0x5415:
card->flags |= UM_FLAG_NO_BYTE_STATUS | UM_FLAG_NO_BATTREG;
@@ -1091,12 +1060,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
card->mm_pages[1].desc,
card->mm_pages[1].page_dma);
failed_magic:
-#ifdef CONFIG_MM_MAP_MEMORY
- iounmap(card->mem_remap);
- failed_remap_mem:
- release_mem_region(card->mem_base, card->mem_len);
- failed_req_mem:
-#endif
iounmap(card->csr_remap);
failed_remap_csr:
release_mem_region(card->csr_base, card->csr_len);
@@ -1116,10 +1079,6 @@ static void mm_pci_remove(struct pci_dev *dev)
tasklet_kill(&card->tasklet);
iounmap(card->csr_remap);
release_mem_region(card->csr_base, card->csr_len);
-#ifdef CONFIG_MM_MAP_MEMORY
- iounmap(card->mem_remap);
- release_mem_region(card->mem_base, card->mem_len);
-#endif
free_irq(card->irq, card);
if (card->mm_pages[0].desc)
@@ -1133,23 +1092,18 @@ static void mm_pci_remove(struct pci_dev *dev)
blk_cleanup_queue(card->queue);
}
-static const struct pci_device_id mm_pci_ids[] = { {
- .vendor = PCI_VENDOR_ID_MICRO_MEMORY,
- .device = PCI_DEVICE_ID_MICRO_MEMORY_5415CN,
- }, {
- .vendor = PCI_VENDOR_ID_MICRO_MEMORY,
- .device = PCI_DEVICE_ID_MICRO_MEMORY_5425CN,
- }, {
- .vendor = PCI_VENDOR_ID_MICRO_MEMORY,
- .device = PCI_DEVICE_ID_MICRO_MEMORY_6155,
- }, {
+static const struct pci_device_id mm_pci_ids[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_5415CN)},
+ {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_5425CN)},
+ {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_6155)},
+ {
.vendor = 0x8086,
.device = 0xB555,
.subvendor= 0x1332,
.subdevice= 0x5460,
.class = 0x050000,
.class_mask= 0,
- }, { /* end: all zeroes */ }
+ }, { /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, mm_pci_ids);
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index 68592c336011..dae39911a11d 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -252,10 +252,10 @@ static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
struct gendisk *disk = bdev->bd_disk;
struct viodasd_device *d = disk->private_data;
- geo->sectors = d->sectors ? d->sectors : 0;
+ geo->sectors = d->sectors ? d->sectors : 32;
geo->heads = d->tracks ? d->tracks : 64;
geo->cylinders = d->cylinders ? d->cylinders :
- get_capacity(disk) / (geo->cylinders * geo->heads);
+ get_capacity(disk) / (geo->sectors * geo->heads);
return 0;
}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
new file mode 100644
index 000000000000..6746c29181f8
--- /dev/null
+++ b/drivers/block/xen-blkfront.c
@@ -0,0 +1,988 @@
+/*
+ * blkfront.c
+ *
+ * XenLinux virtual block device driver.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
+ * Copyright (c) 2005, Christopher Clark
+ * Copyright (c) 2005, XenSource 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; 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/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/blkif.h>
+
+#include <asm/xen/hypervisor.h>
+
+enum blkif_state {
+ BLKIF_STATE_DISCONNECTED,
+ BLKIF_STATE_CONNECTED,
+ BLKIF_STATE_SUSPENDED,
+};
+
+struct blk_shadow {
+ struct blkif_request req;
+ unsigned long request;
+ unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+static struct block_device_operations xlvbd_block_fops;
+
+#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'. They
+ * hang in private_data off the gendisk structure. We may end up
+ * putting all kinds of interesting stuff here :-)
+ */
+struct blkfront_info
+{
+ struct xenbus_device *xbdev;
+ dev_t dev;
+ struct gendisk *gd;
+ int vdevice;
+ blkif_vdev_t handle;
+ enum blkif_state connected;
+ int ring_ref;
+ struct blkif_front_ring ring;
+ unsigned int evtchn, irq;
+ struct request_queue *rq;
+ struct work_struct work;
+ struct gnttab_free_callback callback;
+ struct blk_shadow shadow[BLK_RING_SIZE];
+ unsigned long shadow_free;
+ int feature_barrier;
+
+ /**
+ * The number of people holding this device open. We won't allow a
+ * hot-unplug unless this is 0.
+ */
+ int users;
+};
+
+static DEFINE_SPINLOCK(blkif_io_lock);
+
+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
+ (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
+#define GRANT_INVALID_REF 0
+
+#define PARTS_PER_DISK 16
+
+#define BLKIF_MAJOR(dev) ((dev)>>8)
+#define BLKIF_MINOR(dev) ((dev) & 0xff)
+
+#define DEV_NAME "xvd" /* name in /dev */
+
+/* Information about our VBDs. */
+#define MAX_VBDS 64
+static LIST_HEAD(vbds_list);
+
+static int get_id_from_freelist(struct blkfront_info *info)
+{
+ unsigned long free = info->shadow_free;
+ BUG_ON(free > BLK_RING_SIZE);
+ info->shadow_free = info->shadow[free].req.id;
+ info->shadow[free].req.id = 0x0fffffee; /* debug */
+ return free;
+}
+
+static void add_id_to_freelist(struct blkfront_info *info,
+ unsigned long id)
+{
+ info->shadow[id].req.id = info->shadow_free;
+ info->shadow[id].request = 0;
+ info->shadow_free = id;
+}
+
+static void blkif_restart_queue_callback(void *arg)
+{
+ struct blkfront_info *info = (struct blkfront_info *)arg;
+ schedule_work(&info->work);
+}
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ * virtual address in the guest os.
+ */
+static int blkif_queue_request(struct request *req)
+{
+ struct blkfront_info *info = req->rq_disk->private_data;
+ unsigned long buffer_mfn;
+ struct blkif_request *ring_req;
+ struct bio *bio;
+ struct bio_vec *bvec;
+ int idx;
+ unsigned long id;
+ unsigned int fsect, lsect;
+ int ref;
+ grant_ref_t gref_head;
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+ return 1;
+
+ if (gnttab_alloc_grant_references(
+ BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
+ gnttab_request_free_callback(
+ &info->callback,
+ blkif_restart_queue_callback,
+ info,
+ BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ return 1;
+ }
+
+ /* Fill out a communications ring structure. */
+ ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+ id = get_id_from_freelist(info);
+ info->shadow[id].request = (unsigned long)req;
+
+ ring_req->id = id;
+ ring_req->sector_number = (blkif_sector_t)req->sector;
+ ring_req->handle = info->handle;
+
+ ring_req->operation = rq_data_dir(req) ?
+ BLKIF_OP_WRITE : BLKIF_OP_READ;
+ if (blk_barrier_rq(req))
+ ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+
+ ring_req->nr_segments = 0;
+ rq_for_each_bio (bio, req) {
+ bio_for_each_segment (bvec, bio, idx) {
+ BUG_ON(ring_req->nr_segments
+ == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+ fsect = bvec->bv_offset >> 9;
+ lsect = fsect + (bvec->bv_len >> 9) - 1;
+ /* install a grant reference. */
+ ref = gnttab_claim_grant_reference(&gref_head);
+ BUG_ON(ref == -ENOSPC);
+
+ gnttab_grant_foreign_access_ref(
+ ref,
+ info->xbdev->otherend_id,
+ buffer_mfn,
+ rq_data_dir(req) );
+
+ info->shadow[id].frame[ring_req->nr_segments] =
+ mfn_to_pfn(buffer_mfn);
+
+ ring_req->seg[ring_req->nr_segments] =
+ (struct blkif_request_segment) {
+ .gref = ref,
+ .first_sect = fsect,
+ .last_sect = lsect };
+
+ ring_req->nr_segments++;
+ }
+ }
+
+ info->ring.req_prod_pvt++;
+
+ /* Keep a private copy so we can reissue requests when recovering. */
+ info->shadow[id].req = *ring_req;
+
+ gnttab_free_grant_references(gref_head);
+
+ return 0;
+}
+
+
+static inline void flush_requests(struct blkfront_info *info)
+{
+ int notify;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+
+ if (notify)
+ notify_remote_via_irq(info->irq);
+}
+
+/*
+ * do_blkif_request
+ * read a block; request is in a request queue
+ */
+static void do_blkif_request(request_queue_t *rq)
+{
+ struct blkfront_info *info = NULL;
+ struct request *req;
+ int queued;
+
+ pr_debug("Entered do_blkif_request\n");
+
+ queued = 0;
+
+ while ((req = elv_next_request(rq)) != NULL) {
+ info = req->rq_disk->private_data;
+ if (!blk_fs_request(req)) {
+ end_request(req, 0);
+ continue;
+ }
+
+ if (RING_FULL(&info->ring))
+ goto wait;
+
+ pr_debug("do_blk_req %p: cmd %p, sec %lx, "
+ "(%u/%li) buffer:%p [%s]\n",
+ req, req->cmd, (unsigned long)req->sector,
+ req->current_nr_sectors,
+ req->nr_sectors, req->buffer,
+ rq_data_dir(req) ? "write" : "read");
+
+
+ blkdev_dequeue_request(req);
+ if (blkif_queue_request(req)) {
+ blk_requeue_request(rq, req);
+wait:
+ /* Avoid pointless unplugs. */
+ blk_stop_queue(rq);
+ break;
+ }
+
+ queued++;
+ }
+
+ if (queued != 0)
+ flush_requests(info);
+}
+
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+{
+ request_queue_t *rq;
+
+ rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+ if (rq == NULL)
+ return -1;
+
+ elevator_init(rq, "noop");
+
+ /* Hard sector size and max sectors impersonate the equiv. hardware. */
+ blk_queue_hardsect_size(rq, sector_size);
+ blk_queue_max_sectors(rq, 512);
+
+ /* Each segment in a request is up to an aligned page in size. */
+ blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+ blk_queue_max_segment_size(rq, PAGE_SIZE);
+
+ /* Ensure a merged request will fit in a single I/O ring slot. */
+ blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+ blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ /* Make sure buffer addresses are sector-aligned. */
+ blk_queue_dma_alignment(rq, 511);
+
+ gd->queue = rq;
+
+ return 0;
+}
+
+
+static int xlvbd_barrier(struct blkfront_info *info)
+{
+ int err;
+
+ err = blk_queue_ordered(info->rq,
+ info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE,
+ NULL);
+
+ if (err)
+ return err;
+
+ printk(KERN_INFO "blkfront: %s: barriers %s\n",
+ info->gd->disk_name,
+ info->feature_barrier ? "enabled" : "disabled");
+ return 0;
+}
+
+
+static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
+ int vdevice, u16 vdisk_info, u16 sector_size,
+ struct blkfront_info *info)
+{
+ struct gendisk *gd;
+ int nr_minors = 1;
+ int err = -ENODEV;
+
+ BUG_ON(info->gd != NULL);
+ BUG_ON(info->rq != NULL);
+
+ if ((minor % PARTS_PER_DISK) == 0)
+ nr_minors = PARTS_PER_DISK;
+
+ gd = alloc_disk(nr_minors);
+ if (gd == NULL)
+ goto out;
+
+ if (nr_minors > 1)
+ sprintf(gd->disk_name, "%s%c", DEV_NAME,
+ 'a' + minor / PARTS_PER_DISK);
+ else
+ sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+ 'a' + minor / PARTS_PER_DISK,
+ minor % PARTS_PER_DISK);
+
+ gd->major = XENVBD_MAJOR;
+ gd->first_minor = minor;
+ gd->fops = &xlvbd_block_fops;
+ gd->private_data = info;
+ gd->driverfs_dev = &(info->xbdev->dev);
+ set_capacity(gd, capacity);
+
+ if (xlvbd_init_blk_queue(gd, sector_size)) {
+ del_gendisk(gd);
+ goto out;
+ }
+
+ info->rq = gd->queue;
+ info->gd = gd;
+
+ if (info->feature_barrier)
+ xlvbd_barrier(info);
+
+ if (vdisk_info & VDISK_READONLY)
+ set_disk_ro(gd, 1);
+
+ if (vdisk_info & VDISK_REMOVABLE)
+ gd->flags |= GENHD_FL_REMOVABLE;
+
+ if (vdisk_info & VDISK_CDROM)
+ gd->flags |= GENHD_FL_CD;
+
+ return 0;
+
+ out:
+ return err;
+}
+
+static void kick_pending_request_queues(struct blkfront_info *info)
+{
+ if (!RING_FULL(&info->ring)) {
+ /* Re-enable calldowns. */
+ blk_start_queue(info->rq);
+ /* Kick things off immediately. */
+ do_blkif_request(info->rq);
+ }
+}
+
+static void blkif_restart_queue(struct work_struct *work)
+{
+ struct blkfront_info *info = container_of(work, struct blkfront_info, work);
+
+ spin_lock_irq(&blkif_io_lock);
+ if (info->connected == BLKIF_STATE_CONNECTED)
+ kick_pending_request_queues(info);
+ spin_unlock_irq(&blkif_io_lock);
+}
+
+static void blkif_free(struct blkfront_info *info, int suspend)
+{
+ /* Prevent new requests being issued until we fix things up. */
+ spin_lock_irq(&blkif_io_lock);
+ info->connected = suspend ?
+ BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
+ /* No more blkif_request(). */
+ if (info->rq)
+ blk_stop_queue(info->rq);
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ spin_unlock_irq(&blkif_io_lock);
+
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
+ /* Free resources associated with old device channel. */
+ if (info->ring_ref != GRANT_INVALID_REF) {
+ gnttab_end_foreign_access(info->ring_ref, 0,
+ (unsigned long)info->ring.sring);
+ info->ring_ref = GRANT_INVALID_REF;
+ info->ring.sring = NULL;
+ }
+ if (info->irq)
+ unbind_from_irqhandler(info->irq, info);
+ info->evtchn = info->irq = 0;
+
+}
+
+static void blkif_completion(struct blk_shadow *s)
+{
+ int i;
+ for (i = 0; i < s->req.nr_segments; i++)
+ gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+{
+ struct request *req;
+ struct blkif_response *bret;
+ RING_IDX i, rp;
+ unsigned long flags;
+ struct blkfront_info *info = (struct blkfront_info *)dev_id;
+ int uptodate;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ again:
+ rp = info->ring.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ for (i = info->ring.rsp_cons; i != rp; i++) {
+ unsigned long id;
+ int ret;
+
+ bret = RING_GET_RESPONSE(&info->ring, i);
+ id = bret->id;
+ req = (struct request *)info->shadow[id].request;
+
+ blkif_completion(&info->shadow[id]);
+
+ add_id_to_freelist(info, id);
+
+ uptodate = (bret->status == BLKIF_RSP_OKAY);
+ switch (bret->operation) {
+ case BLKIF_OP_WRITE_BARRIER:
+ if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+ printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+ info->gd->disk_name);
+ uptodate = -EOPNOTSUPP;
+ info->feature_barrier = 0;
+ xlvbd_barrier(info);
+ }
+ /* fall through */
+ case BLKIF_OP_READ:
+ case BLKIF_OP_WRITE:
+ if (unlikely(bret->status != BLKIF_RSP_OKAY))
+ dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
+ "request: %x\n", bret->status);
+
+ ret = end_that_request_first(req, uptodate,
+ req->hard_nr_sectors);
+ BUG_ON(ret);
+ end_that_request_last(req, uptodate);
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ info->ring.rsp_cons = i;
+
+ if (i != info->ring.req_prod_pvt) {
+ int more_to_do;
+ RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+ if (more_to_do)
+ goto again;
+ } else
+ info->ring.sring->rsp_event = i + 1;
+
+ kick_pending_request_queues(info);
+
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+
+static int setup_blkring(struct xenbus_device *dev,
+ struct blkfront_info *info)
+{
+ struct blkif_sring *sring;
+ int err;
+
+ info->ring_ref = GRANT_INVALID_REF;
+
+ sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL);
+ if (!sring) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+ return -ENOMEM;
+ }
+ SHARED_RING_INIT(sring);
+ FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+ if (err < 0) {
+ free_page((unsigned long)sring);
+ info->ring.sring = NULL;
+ goto fail;
+ }
+ info->ring_ref = err;
+
+ err = xenbus_alloc_evtchn(dev, &info->evtchn);
+ if (err)
+ goto fail;
+
+ err = bind_evtchn_to_irqhandler(info->evtchn,
+ blkif_interrupt,
+ IRQF_SAMPLE_RANDOM, "blkif", info);
+ if (err <= 0) {
+ xenbus_dev_fatal(dev, err,
+ "bind_evtchn_to_irqhandler failed");
+ goto fail;
+ }
+ info->irq = err;
+
+ return 0;
+fail:
+ blkif_free(info, 0);
+ return err;
+}
+
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+ struct blkfront_info *info)
+{
+ const char *message = NULL;
+ struct xenbus_transaction xbt;
+ int err;
+
+ /* Create shared ring, alloc event channel. */
+ err = setup_blkring(dev, info);
+ if (err)
+ goto out;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ goto destroy_blkring;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename,
+ "ring-ref", "%u", info->ring_ref);
+ if (err) {
+ message = "writing ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel", "%u", info->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ goto destroy_blkring;
+ }
+
+ xenbus_switch_state(dev, XenbusStateInitialised);
+
+ return 0;
+
+ abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ if (message)
+ xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_blkring:
+ blkif_free(info, 0);
+ out:
+ return err;
+}
+
+
+/**
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures and the ring buffer for communication with the backend, and
+ * inform the backend of the appropriate details for those. Switch to
+ * Initialised state.
+ */
+static int blkfront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err, vdevice, i;
+ struct blkfront_info *info;
+
+ /* FIXME: Use dynamic device id if this is not set. */
+ err = xenbus_scanf(XBT_NIL, dev->nodename,
+ "virtual-device", "%i", &vdevice);
+ if (err != 1) {
+ xenbus_dev_fatal(dev, err, "reading virtual-device");
+ return err;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+ return -ENOMEM;
+ }
+
+ info->xbdev = dev;
+ info->vdevice = vdevice;
+ info->connected = BLKIF_STATE_DISCONNECTED;
+ INIT_WORK(&info->work, blkif_restart_queue);
+
+ for (i = 0; i < BLK_RING_SIZE; i++)
+ info->shadow[i].req.id = i+1;
+ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ /* Front end dir is a number, which is used as the id. */
+ info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
+ dev->dev.driver_data = info;
+
+ err = talk_to_backend(dev, info);
+ if (err) {
+ kfree(info);
+ dev->dev.driver_data = NULL;
+ return err;
+ }
+
+ return 0;
+}
+
+
+static int blkif_recover(struct blkfront_info *info)
+{
+ int i;
+ struct blkif_request *req;
+ struct blk_shadow *copy;
+ int j;
+
+ /* Stage 1: Make a safe copy of the shadow state. */
+ copy = kmalloc(sizeof(info->shadow), GFP_KERNEL);
+ if (!copy)
+ return -ENOMEM;
+ memcpy(copy, info->shadow, sizeof(info->shadow));
+
+ /* Stage 2: Set up free list. */
+ memset(&info->shadow, 0, sizeof(info->shadow));
+ for (i = 0; i < BLK_RING_SIZE; i++)
+ info->shadow[i].req.id = i+1;
+ info->shadow_free = info->ring.req_prod_pvt;
+ info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+ /* Stage 3: Find pending requests and requeue them. */
+ for (i = 0; i < BLK_RING_SIZE; i++) {
+ /* Not in use? */
+ if (copy[i].request == 0)
+ continue;
+
+ /* Grab a request slot and copy shadow state into it. */
+ req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+ *req = copy[i].req;
+
+ /* We get a new request id, and must reset the shadow state. */
+ req->id = get_id_from_freelist(info);
+ memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
+
+ /* Rewrite any grant references invalidated by susp/resume. */
+ for (j = 0; j < req->nr_segments; j++)
+ gnttab_grant_foreign_access_ref(
+ req->seg[j].gref,
+ info->xbdev->otherend_id,
+ pfn_to_mfn(info->shadow[req->id].frame[j]),
+ rq_data_dir(
+ (struct request *)
+ info->shadow[req->id].request));
+ info->shadow[req->id].req = *req;
+
+ info->ring.req_prod_pvt++;
+ }
+
+ kfree(copy);
+
+ xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+ spin_lock_irq(&blkif_io_lock);
+
+ /* Now safe for us to use the shared ring */
+ info->connected = BLKIF_STATE_CONNECTED;
+
+ /* Send off requeued requests */
+ flush_requests(info);
+
+ /* Kick any other new requests queued since we resumed */
+ kick_pending_request_queues(info);
+
+ spin_unlock_irq(&blkif_io_lock);
+
+ return 0;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart. We tear down our blkif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int blkfront_resume(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ int err;
+
+ dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
+
+ blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+
+ err = talk_to_backend(dev, info);
+ if (info->connected == BLKIF_STATE_SUSPENDED && !err)
+ err = blkif_recover(info);
+
+ return err;
+}
+
+
+/*
+ * Invoked when the backend is finally 'ready' (and has told produced
+ * the details about the physical device - #sectors, size, etc).
+ */
+static void blkfront_connect(struct blkfront_info *info)
+{
+ unsigned long long sectors;
+ unsigned long sector_size;
+ unsigned int binfo;
+ int err;
+
+ if ((info->connected == BLKIF_STATE_CONNECTED) ||
+ (info->connected == BLKIF_STATE_SUSPENDED) )
+ return;
+
+ dev_dbg(&info->xbdev->dev, "%s:%s.\n",
+ __func__, info->xbdev->otherend);
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "sectors", "%llu", &sectors,
+ "info", "%u", &binfo,
+ "sector-size", "%lu", &sector_size,
+ NULL);
+ if (err) {
+ xenbus_dev_fatal(info->xbdev, err,
+ "reading backend fields at %s",
+ info->xbdev->otherend);
+ return;
+ }
+
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-barrier", "%lu", &info->feature_barrier,
+ NULL);
+ if (err)
+ info->feature_barrier = 0;
+
+ err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
+ sectors, info->vdevice,
+ binfo, sector_size, info);
+ if (err) {
+ xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
+ info->xbdev->otherend);
+ return;
+ }
+
+ xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+ /* Kick pending requests. */
+ spin_lock_irq(&blkif_io_lock);
+ info->connected = BLKIF_STATE_CONNECTED;
+ kick_pending_request_queues(info);
+ spin_unlock_irq(&blkif_io_lock);
+
+ add_disk(info->gd);
+}
+
+/**
+ * Handle the change of state of the backend to Closing. We must delete our
+ * device-layer structures now, to ensure that writes are flushed through to
+ * the backend. Once is this done, we can switch to Closed in
+ * acknowledgement.
+ */
+static void blkfront_closing(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ unsigned long flags;
+
+ dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
+
+ if (info->rq == NULL)
+ goto out;
+
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ del_gendisk(info->gd);
+
+ /* No more blkif_request(). */
+ blk_stop_queue(info->rq);
+
+ /* No more gnttab callback work. */
+ gnttab_cancel_free_callback(&info->callback);
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ /* Flush gnttab callback work. Must be done with no locks held. */
+ flush_scheduled_work();
+
+ blk_cleanup_queue(info->rq);
+ info->rq = NULL;
+
+ out:
+ xenbus_frontend_closed(dev);
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+ struct block_device *bd;
+
+ dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitWait:
+ case XenbusStateInitialised:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateConnected:
+ blkfront_connect(info);
+ break;
+
+ case XenbusStateClosing:
+ bd = bdget(info->dev);
+ if (bd == NULL)
+ xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
+
+ mutex_lock(&bd->bd_mutex);
+ if (info->users > 0)
+ xenbus_dev_error(dev, -EBUSY,
+ "Device in use; refusing to close");
+ else
+ blkfront_closing(dev);
+ mutex_unlock(&bd->bd_mutex);
+ bdput(bd);
+ break;
+ }
+}
+
+static int blkfront_remove(struct xenbus_device *dev)
+{
+ struct blkfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
+
+ blkif_free(info, 0);
+
+ kfree(info);
+
+ return 0;
+}
+
+static int blkif_open(struct inode *inode, struct file *filep)
+{
+ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ info->users++;
+ return 0;
+}
+
+static int blkif_release(struct inode *inode, struct file *filep)
+{
+ struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+ info->users--;
+ if (info->users == 0) {
+ /* Check whether we have been instructed to close. We will
+ have ignored this request initially, as the device was
+ still mounted. */
+ struct xenbus_device *dev = info->xbdev;
+ enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
+
+ if (state == XenbusStateClosing)
+ blkfront_closing(dev);
+ }
+ return 0;
+}
+
+static struct block_device_operations xlvbd_block_fops =
+{
+ .owner = THIS_MODULE,
+ .open = blkif_open,
+ .release = blkif_release,
+};
+
+
+static struct xenbus_device_id blkfront_ids[] = {
+ { "vbd" },
+ { "" }
+};
+
+static struct xenbus_driver blkfront = {
+ .name = "vbd",
+ .owner = THIS_MODULE,
+ .ids = blkfront_ids,
+ .probe = blkfront_probe,
+ .remove = blkfront_remove,
+ .resume = blkfront_resume,
+ .otherend_changed = backend_changed,
+};
+
+static int __init xlblk_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
+ printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
+ XENVBD_MAJOR, DEV_NAME);
+ return -ENODEV;
+ }
+
+ return xenbus_register_frontend(&blkfront);
+}
+module_init(xlblk_init);
+
+
+static void xlblk_exit(void)
+{
+ return xenbus_unregister_driver(&blkfront);
+}
+module_exit(xlblk_exit);
+
+MODULE_DESCRIPTION("Xen virtual block device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
new file mode 100644
index 000000000000..732ec63b6e9c
--- /dev/null
+++ b/drivers/block/xsysace.c
@@ -0,0 +1,1164 @@
+/*
+ * Xilinx SystemACE device driver
+ *
+ * Copyright 2007 Secret Lab Technologies 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.
+ */
+
+/*
+ * The SystemACE chip is designed to configure FPGAs by loading an FPGA
+ * bitstream from a file on a CF card and squirting it into FPGAs connected
+ * to the SystemACE JTAG chain. It also has the advantage of providing an
+ * MPU interface which can be used to control the FPGA configuration process
+ * and to use the attached CF card for general purpose storage.
+ *
+ * This driver is a block device driver for the SystemACE.
+ *
+ * Initialization:
+ * The driver registers itself as a platform_device driver at module
+ * load time. The platform bus will take care of calling the
+ * ace_probe() method for all SystemACE instances in the system. Any
+ * number of SystemACE instances are supported. ace_probe() calls
+ * ace_setup() which initialized all data structures, reads the CF
+ * id structure and registers the device.
+ *
+ * Processing:
+ * Just about all of the heavy lifting in this driver is performed by
+ * a Finite State Machine (FSM). The driver needs to wait on a number
+ * of events; some raised by interrupts, some which need to be polled
+ * for. Describing all of the behaviour in a FSM seems to be the
+ * easiest way to keep the complexity low and make it easy to
+ * understand what the driver is doing. If the block ops or the
+ * request function need to interact with the hardware, then they
+ * simply need to flag the request and kick of FSM processing.
+ *
+ * The FSM itself is atomic-safe code which can be run from any
+ * context. The general process flow is:
+ * 1. obtain the ace->lock spinlock.
+ * 2. loop on ace_fsm_dostate() until the ace->fsm_continue flag is
+ * cleared.
+ * 3. release the lock.
+ *
+ * Individual states do not sleep in any way. If a condition needs to
+ * be waited for then the state much clear the fsm_continue flag and
+ * either schedule the FSM to be run again at a later time, or expect
+ * an interrupt to call the FSM when the desired condition is met.
+ *
+ * In normal operation, the FSM is processed at interrupt context
+ * either when the driver's tasklet is scheduled, or when an irq is
+ * raised by the hardware. The tasklet can be scheduled at any time.
+ * The request method in particular schedules the tasklet when a new
+ * request has been indicated by the block layer. Once started, the
+ * FSM proceeds as far as it can processing the request until it
+ * needs on a hardware event. At this point, it must yield execution.
+ *
+ * A state has two options when yielding execution:
+ * 1. ace_fsm_yield()
+ * - Call if need to poll for event.
+ * - clears the fsm_continue flag to exit the processing loop
+ * - reschedules the tasklet to run again as soon as possible
+ * 2. ace_fsm_yieldirq()
+ * - Call if an irq is expected from the HW
+ * - clears the fsm_continue flag to exit the processing loop
+ * - does not reschedule the tasklet so the FSM will not be processed
+ * again until an irq is received.
+ * After calling a yield function, the state must return control back
+ * to the FSM main loop.
+ *
+ * Additionally, the driver maintains a kernel timer which can process
+ * the FSM. If the FSM gets stalled, typically due to a missed
+ * interrupt, then the kernel timer will expire and the driver can
+ * continue where it left off.
+ *
+ * To Do:
+ * - Add FPGA configuration control interface.
+ * - Request major number from lanana
+ */
+
+#undef DEBUG
+
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/platform_device.h>
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("Xilinx SystemACE device driver");
+MODULE_LICENSE("GPL");
+
+/* SystemACE register definitions */
+#define ACE_BUSMODE (0x00)
+
+#define ACE_STATUS (0x04)
+#define ACE_STATUS_CFGLOCK (0x00000001)
+#define ACE_STATUS_MPULOCK (0x00000002)
+#define ACE_STATUS_CFGERROR (0x00000004) /* config controller error */
+#define ACE_STATUS_CFCERROR (0x00000008) /* CF controller error */
+#define ACE_STATUS_CFDETECT (0x00000010)
+#define ACE_STATUS_DATABUFRDY (0x00000020)
+#define ACE_STATUS_DATABUFMODE (0x00000040)
+#define ACE_STATUS_CFGDONE (0x00000080)
+#define ACE_STATUS_RDYFORCFCMD (0x00000100)
+#define ACE_STATUS_CFGMODEPIN (0x00000200)
+#define ACE_STATUS_CFGADDR_MASK (0x0000e000)
+#define ACE_STATUS_CFBSY (0x00020000)
+#define ACE_STATUS_CFRDY (0x00040000)
+#define ACE_STATUS_CFDWF (0x00080000)
+#define ACE_STATUS_CFDSC (0x00100000)
+#define ACE_STATUS_CFDRQ (0x00200000)
+#define ACE_STATUS_CFCORR (0x00400000)
+#define ACE_STATUS_CFERR (0x00800000)
+
+#define ACE_ERROR (0x08)
+#define ACE_CFGLBA (0x0c)
+#define ACE_MPULBA (0x10)
+
+#define ACE_SECCNTCMD (0x14)
+#define ACE_SECCNTCMD_RESET (0x0100)
+#define ACE_SECCNTCMD_IDENTIFY (0x0200)
+#define ACE_SECCNTCMD_READ_DATA (0x0300)
+#define ACE_SECCNTCMD_WRITE_DATA (0x0400)
+#define ACE_SECCNTCMD_ABORT (0x0600)
+
+#define ACE_VERSION (0x16)
+#define ACE_VERSION_REVISION_MASK (0x00FF)
+#define ACE_VERSION_MINOR_MASK (0x0F00)
+#define ACE_VERSION_MAJOR_MASK (0xF000)
+
+#define ACE_CTRL (0x18)
+#define ACE_CTRL_FORCELOCKREQ (0x0001)
+#define ACE_CTRL_LOCKREQ (0x0002)
+#define ACE_CTRL_FORCECFGADDR (0x0004)
+#define ACE_CTRL_FORCECFGMODE (0x0008)
+#define ACE_CTRL_CFGMODE (0x0010)
+#define ACE_CTRL_CFGSTART (0x0020)
+#define ACE_CTRL_CFGSEL (0x0040)
+#define ACE_CTRL_CFGRESET (0x0080)
+#define ACE_CTRL_DATABUFRDYIRQ (0x0100)
+#define ACE_CTRL_ERRORIRQ (0x0200)
+#define ACE_CTRL_CFGDONEIRQ (0x0400)
+#define ACE_CTRL_RESETIRQ (0x0800)
+#define ACE_CTRL_CFGPROG (0x1000)
+#define ACE_CTRL_CFGADDR_MASK (0xe000)
+
+#define ACE_FATSTAT (0x1c)
+
+#define ACE_NUM_MINORS 16
+#define ACE_SECTOR_SIZE (512)
+#define ACE_FIFO_SIZE (32)
+#define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE)
+
+struct ace_reg_ops;
+
+struct ace_device {
+ /* driver state data */
+ int id;
+ int media_change;
+ int users;
+ struct list_head list;
+
+ /* finite state machine data */
+ struct tasklet_struct fsm_tasklet;
+ uint fsm_task; /* Current activity (ACE_TASK_*) */
+ uint fsm_state; /* Current state (ACE_FSM_STATE_*) */
+ uint fsm_continue_flag; /* cleared to exit FSM mainloop */
+ uint fsm_iter_num;
+ struct timer_list stall_timer;
+
+ /* Transfer state/result, use for both id and block request */
+ struct request *req; /* request being processed */
+ void *data_ptr; /* pointer to I/O buffer */
+ int data_count; /* number of buffers remaining */
+ int data_result; /* Result of transfer; 0 := success */
+
+ int id_req_count; /* count of id requests */
+ int id_result;
+ struct completion id_completion; /* used when id req finishes */
+ int in_irq;
+
+ /* Details of hardware device */
+ unsigned long physaddr;
+ void *baseaddr;
+ int irq;
+ int bus_width; /* 0 := 8 bit; 1 := 16 bit */
+ struct ace_reg_ops *reg_ops;
+ int lock_count;
+
+ /* Block device data structures */
+ spinlock_t lock;
+ struct device *dev;
+ struct request_queue *queue;
+ struct gendisk *gd;
+
+ /* Inserted CF card parameters */
+ struct hd_driveid cf_id;
+};
+
+static int ace_major;
+
+/* ---------------------------------------------------------------------
+ * Low level register access
+ */
+
+struct ace_reg_ops {
+ u16(*in) (struct ace_device * ace, int reg);
+ void (*out) (struct ace_device * ace, int reg, u16 val);
+ void (*datain) (struct ace_device * ace);
+ void (*dataout) (struct ace_device * ace);
+};
+
+/* 8 Bit bus width */
+static u16 ace_in_8(struct ace_device *ace, int reg)
+{
+ void *r = ace->baseaddr + reg;
+ return in_8(r) | (in_8(r + 1) << 8);
+}
+
+static void ace_out_8(struct ace_device *ace, int reg, u16 val)
+{
+ void *r = ace->baseaddr + reg;
+ out_8(r, val);
+ out_8(r + 1, val >> 8);
+}
+
+static void ace_datain_8(struct ace_device *ace)
+{
+ void *r = ace->baseaddr + 0x40;
+ u8 *dst = ace->data_ptr;
+ int i = ACE_FIFO_SIZE;
+ while (i--)
+ *dst++ = in_8(r++);
+ ace->data_ptr = dst;
+}
+
+static void ace_dataout_8(struct ace_device *ace)
+{
+ void *r = ace->baseaddr + 0x40;
+ u8 *src = ace->data_ptr;
+ int i = ACE_FIFO_SIZE;
+ while (i--)
+ out_8(r++, *src++);
+ ace->data_ptr = src;
+}
+
+static struct ace_reg_ops ace_reg_8_ops = {
+ .in = ace_in_8,
+ .out = ace_out_8,
+ .datain = ace_datain_8,
+ .dataout = ace_dataout_8,
+};
+
+/* 16 bit big endian bus attachment */
+static u16 ace_in_be16(struct ace_device *ace, int reg)
+{
+ return in_be16(ace->baseaddr + reg);
+}
+
+static void ace_out_be16(struct ace_device *ace, int reg, u16 val)
+{
+ out_be16(ace->baseaddr + reg, val);
+}
+
+static void ace_datain_be16(struct ace_device *ace)
+{
+ int i = ACE_FIFO_SIZE / 2;
+ u16 *dst = ace->data_ptr;
+ while (i--)
+ *dst++ = in_le16(ace->baseaddr + 0x40);
+ ace->data_ptr = dst;
+}
+
+static void ace_dataout_be16(struct ace_device *ace)
+{
+ int i = ACE_FIFO_SIZE / 2;
+ u16 *src = ace->data_ptr;
+ while (i--)
+ out_le16(ace->baseaddr + 0x40, *src++);
+ ace->data_ptr = src;
+}
+
+/* 16 bit little endian bus attachment */
+static u16 ace_in_le16(struct ace_device *ace, int reg)
+{
+ return in_le16(ace->baseaddr + reg);
+}
+
+static void ace_out_le16(struct ace_device *ace, int reg, u16 val)
+{
+ out_le16(ace->baseaddr + reg, val);
+}
+
+static void ace_datain_le16(struct ace_device *ace)
+{
+ int i = ACE_FIFO_SIZE / 2;
+ u16 *dst = ace->data_ptr;
+ while (i--)
+ *dst++ = in_be16(ace->baseaddr + 0x40);
+ ace->data_ptr = dst;
+}
+
+static void ace_dataout_le16(struct ace_device *ace)
+{
+ int i = ACE_FIFO_SIZE / 2;
+ u16 *src = ace->data_ptr;
+ while (i--)
+ out_be16(ace->baseaddr + 0x40, *src++);
+ ace->data_ptr = src;
+}
+
+static struct ace_reg_ops ace_reg_be16_ops = {
+ .in = ace_in_be16,
+ .out = ace_out_be16,
+ .datain = ace_datain_be16,
+ .dataout = ace_dataout_be16,
+};
+
+static struct ace_reg_ops ace_reg_le16_ops = {
+ .in = ace_in_le16,
+ .out = ace_out_le16,
+ .datain = ace_datain_le16,
+ .dataout = ace_dataout_le16,
+};
+
+static inline u16 ace_in(struct ace_device *ace, int reg)
+{
+ return ace->reg_ops->in(ace, reg);
+}
+
+static inline u32 ace_in32(struct ace_device *ace, int reg)
+{
+ return ace_in(ace, reg) | (ace_in(ace, reg + 2) << 16);
+}
+
+static inline void ace_out(struct ace_device *ace, int reg, u16 val)
+{
+ ace->reg_ops->out(ace, reg, val);
+}
+
+static inline void ace_out32(struct ace_device *ace, int reg, u32 val)
+{
+ ace_out(ace, reg, val);
+ ace_out(ace, reg + 2, val >> 16);
+}
+
+/* ---------------------------------------------------------------------
+ * Debug support functions
+ */
+
+#if defined(DEBUG)
+static void ace_dump_mem(void *base, int len)
+{
+ const char *ptr = base;
+ int i, j;
+
+ for (i = 0; i < len; i += 16) {
+ printk(KERN_INFO "%.8x:", i);
+ for (j = 0; j < 16; j++) {
+ if (!(j % 4))
+ printk(" ");
+ printk("%.2x", ptr[i + j]);
+ }
+ printk(" ");
+ for (j = 0; j < 16; j++)
+ printk("%c", isprint(ptr[i + j]) ? ptr[i + j] : '.');
+ printk("\n");
+ }
+}
+#else
+static inline void ace_dump_mem(void *base, int len)
+{
+}
+#endif
+
+static void ace_dump_regs(struct ace_device *ace)
+{
+ dev_info(ace->dev, " ctrl: %.8x seccnt/cmd: %.4x ver:%.4x\n"
+ " status:%.8x mpu_lba:%.8x busmode:%4x\n"
+ " error: %.8x cfg_lba:%.8x fatstat:%.4x\n",
+ ace_in32(ace, ACE_CTRL),
+ ace_in(ace, ACE_SECCNTCMD),
+ ace_in(ace, ACE_VERSION),
+ ace_in32(ace, ACE_STATUS),
+ ace_in32(ace, ACE_MPULBA),
+ ace_in(ace, ACE_BUSMODE),
+ ace_in32(ace, ACE_ERROR),
+ ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT));
+}
+
+void ace_fix_driveid(struct hd_driveid *id)
+{
+#if defined(__BIG_ENDIAN)
+ u16 *buf = (void *)id;
+ int i;
+
+ /* All half words have wrong byte order; swap the bytes */
+ for (i = 0; i < sizeof(struct hd_driveid); i += 2, buf++)
+ *buf = le16_to_cpu(*buf);
+
+ /* Some of the data values are 32bit; swap the half words */
+ id->lba_capacity = ((id->lba_capacity >> 16) & 0x0000FFFF) |
+ ((id->lba_capacity << 16) & 0xFFFF0000);
+ id->spg = ((id->spg >> 16) & 0x0000FFFF) |
+ ((id->spg << 16) & 0xFFFF0000);
+#endif
+}
+
+/* ---------------------------------------------------------------------
+ * Finite State Machine (FSM) implementation
+ */
+
+/* FSM tasks; used to direct state transitions */
+#define ACE_TASK_IDLE 0
+#define ACE_TASK_IDENTIFY 1
+#define ACE_TASK_READ 2
+#define ACE_TASK_WRITE 3
+#define ACE_FSM_NUM_TASKS 4
+
+/* FSM state definitions */
+#define ACE_FSM_STATE_IDLE 0
+#define ACE_FSM_STATE_REQ_LOCK 1
+#define ACE_FSM_STATE_WAIT_LOCK 2
+#define ACE_FSM_STATE_WAIT_CFREADY 3
+#define ACE_FSM_STATE_IDENTIFY_PREPARE 4
+#define ACE_FSM_STATE_IDENTIFY_TRANSFER 5
+#define ACE_FSM_STATE_IDENTIFY_COMPLETE 6
+#define ACE_FSM_STATE_REQ_PREPARE 7
+#define ACE_FSM_STATE_REQ_TRANSFER 8
+#define ACE_FSM_STATE_REQ_COMPLETE 9
+#define ACE_FSM_STATE_ERROR 10
+#define ACE_FSM_NUM_STATES 11
+
+/* Set flag to exit FSM loop and reschedule tasklet */
+static inline void ace_fsm_yield(struct ace_device *ace)
+{
+ dev_dbg(ace->dev, "ace_fsm_yield()\n");
+ tasklet_schedule(&ace->fsm_tasklet);
+ ace->fsm_continue_flag = 0;
+}
+
+/* Set flag to exit FSM loop and wait for IRQ to reschedule tasklet */
+static inline void ace_fsm_yieldirq(struct ace_device *ace)
+{
+ dev_dbg(ace->dev, "ace_fsm_yieldirq()\n");
+
+ if (ace->irq == NO_IRQ)
+ /* No IRQ assigned, so need to poll */
+ tasklet_schedule(&ace->fsm_tasklet);
+ ace->fsm_continue_flag = 0;
+}
+
+/* Get the next read/write request; ending requests that we don't handle */
+struct request *ace_get_next_request(request_queue_t * q)
+{
+ struct request *req;
+
+ while ((req = elv_next_request(q)) != NULL) {
+ if (blk_fs_request(req))
+ break;
+ end_request(req, 0);
+ }
+ return req;
+}
+
+static void ace_fsm_dostate(struct ace_device *ace)
+{
+ struct request *req;
+ u32 status;
+ u16 val;
+ int count;
+ int i;
+
+#if defined(DEBUG)
+ dev_dbg(ace->dev, "fsm_state=%i, id_req_count=%i\n",
+ ace->fsm_state, ace->id_req_count);
+#endif
+
+ switch (ace->fsm_state) {
+ case ACE_FSM_STATE_IDLE:
+ /* See if there is anything to do */
+ if (ace->id_req_count || ace_get_next_request(ace->queue)) {
+ ace->fsm_iter_num++;
+ ace->fsm_state = ACE_FSM_STATE_REQ_LOCK;
+ mod_timer(&ace->stall_timer, jiffies + HZ);
+ if (!timer_pending(&ace->stall_timer))
+ add_timer(&ace->stall_timer);
+ break;
+ }
+ del_timer(&ace->stall_timer);
+ ace->fsm_continue_flag = 0;
+ break;
+
+ case ACE_FSM_STATE_REQ_LOCK:
+ if (ace_in(ace, ACE_STATUS) & ACE_STATUS_MPULOCK) {
+ /* Already have the lock, jump to next state */
+ ace->fsm_state = ACE_FSM_STATE_WAIT_CFREADY;
+ break;
+ }
+
+ /* Request the lock */
+ val = ace_in(ace, ACE_CTRL);
+ ace_out(ace, ACE_CTRL, val | ACE_CTRL_LOCKREQ);
+ ace->fsm_state = ACE_FSM_STATE_WAIT_LOCK;
+ break;
+
+ case ACE_FSM_STATE_WAIT_LOCK:
+ if (ace_in(ace, ACE_STATUS) & ACE_STATUS_MPULOCK) {
+ /* got the lock; move to next state */
+ ace->fsm_state = ACE_FSM_STATE_WAIT_CFREADY;
+ break;
+ }
+
+ /* wait a bit for the lock */
+ ace_fsm_yield(ace);
+ break;
+
+ case ACE_FSM_STATE_WAIT_CFREADY:
+ status = ace_in32(ace, ACE_STATUS);
+ if (!(status & ACE_STATUS_RDYFORCFCMD) ||
+ (status & ACE_STATUS_CFBSY)) {
+ /* CF card isn't ready; it needs to be polled */
+ ace_fsm_yield(ace);
+ break;
+ }
+
+ /* Device is ready for command; determine what to do next */
+ if (ace->id_req_count)
+ ace->fsm_state = ACE_FSM_STATE_IDENTIFY_PREPARE;
+ else
+ ace->fsm_state = ACE_FSM_STATE_REQ_PREPARE;
+ break;
+
+ case ACE_FSM_STATE_IDENTIFY_PREPARE:
+ /* Send identify command */
+ ace->fsm_task = ACE_TASK_IDENTIFY;
+ ace->data_ptr = &ace->cf_id;
+ ace->data_count = ACE_BUF_PER_SECTOR;
+ ace_out(ace, ACE_SECCNTCMD, ACE_SECCNTCMD_IDENTIFY);
+
+ /* As per datasheet, put config controller in reset */
+ val = ace_in(ace, ACE_CTRL);
+ ace_out(ace, ACE_CTRL, val | ACE_CTRL_CFGRESET);
+
+ /* irq handler takes over from this point; wait for the
+ * transfer to complete */
+ ace->fsm_state = ACE_FSM_STATE_IDENTIFY_TRANSFER;
+ ace_fsm_yieldirq(ace);
+ break;
+
+ case ACE_FSM_STATE_IDENTIFY_TRANSFER:
+ /* Check that the sysace is ready to receive data */
+ status = ace_in32(ace, ACE_STATUS);
+ if (status & ACE_STATUS_CFBSY) {
+ dev_dbg(ace->dev, "CFBSY set; t=%i iter=%i dc=%i\n",
+ ace->fsm_task, ace->fsm_iter_num,
+ ace->data_count);
+ ace_fsm_yield(ace);
+ break;
+ }
+ if (!(status & ACE_STATUS_DATABUFRDY)) {
+ ace_fsm_yield(ace);
+ break;
+ }
+
+ /* Transfer the next buffer */
+ ace->reg_ops->datain(ace);
+ ace->data_count--;
+
+ /* If there are still buffers to be transfers; jump out here */
+ if (ace->data_count != 0) {
+ ace_fsm_yieldirq(ace);
+ break;
+ }
+
+ /* transfer finished; kick state machine */
+ dev_dbg(ace->dev, "identify finished\n");
+ ace->fsm_state = ACE_FSM_STATE_IDENTIFY_COMPLETE;
+ break;
+
+ case ACE_FSM_STATE_IDENTIFY_COMPLETE:
+ ace_fix_driveid(&ace->cf_id);
+ ace_dump_mem(&ace->cf_id, 512); /* Debug: Dump out disk ID */
+
+ if (ace->data_result) {
+ /* Error occured, disable the disk */
+ ace->media_change = 1;
+ set_capacity(ace->gd, 0);
+ dev_err(ace->dev, "error fetching CF id (%i)\n",
+ ace->data_result);
+ } else {
+ ace->media_change = 0;
+
+ /* Record disk parameters */
+ set_capacity(ace->gd, ace->cf_id.lba_capacity);
+ dev_info(ace->dev, "capacity: %i sectors\n",
+ ace->cf_id.lba_capacity);
+ }
+
+ /* We're done, drop to IDLE state and notify waiters */
+ ace->fsm_state = ACE_FSM_STATE_IDLE;
+ ace->id_result = ace->data_result;
+ while (ace->id_req_count) {
+ complete(&ace->id_completion);
+ ace->id_req_count--;
+ }
+ break;
+
+ case ACE_FSM_STATE_REQ_PREPARE:
+ req = ace_get_next_request(ace->queue);
+ if (!req) {
+ ace->fsm_state = ACE_FSM_STATE_IDLE;
+ break;
+ }
+
+ /* Okay, it's a data request, set it up for transfer */
+ dev_dbg(ace->dev,
+ "request: sec=%lx hcnt=%lx, ccnt=%x, dir=%i\n",
+ req->sector, req->hard_nr_sectors,
+ req->current_nr_sectors, rq_data_dir(req));
+
+ ace->req = req;
+ ace->data_ptr = req->buffer;
+ ace->data_count = req->current_nr_sectors * ACE_BUF_PER_SECTOR;
+ ace_out32(ace, ACE_MPULBA, req->sector & 0x0FFFFFFF);
+
+ count = req->hard_nr_sectors;
+ if (rq_data_dir(req)) {
+ /* Kick off write request */
+ dev_dbg(ace->dev, "write data\n");
+ ace->fsm_task = ACE_TASK_WRITE;
+ ace_out(ace, ACE_SECCNTCMD,
+ count | ACE_SECCNTCMD_WRITE_DATA);
+ } else {
+ /* Kick off read request */
+ dev_dbg(ace->dev, "read data\n");
+ ace->fsm_task = ACE_TASK_READ;
+ ace_out(ace, ACE_SECCNTCMD,
+ count | ACE_SECCNTCMD_READ_DATA);
+ }
+
+ /* As per datasheet, put config controller in reset */
+ val = ace_in(ace, ACE_CTRL);
+ ace_out(ace, ACE_CTRL, val | ACE_CTRL_CFGRESET);
+
+ /* Move to the transfer state. The systemace will raise
+ * an interrupt once there is something to do
+ */
+ ace->fsm_state = ACE_FSM_STATE_REQ_TRANSFER;
+ if (ace->fsm_task == ACE_TASK_READ)
+ ace_fsm_yieldirq(ace); /* wait for data ready */
+ break;
+
+ case ACE_FSM_STATE_REQ_TRANSFER:
+ /* Check that the sysace is ready to receive data */
+ status = ace_in32(ace, ACE_STATUS);
+ if (status & ACE_STATUS_CFBSY) {
+ dev_dbg(ace->dev,
+ "CFBSY set; t=%i iter=%i c=%i dc=%i irq=%i\n",
+ ace->fsm_task, ace->fsm_iter_num,
+ ace->req->current_nr_sectors * 16,
+ ace->data_count, ace->in_irq);
+ ace_fsm_yield(ace); /* need to poll CFBSY bit */
+ break;
+ }
+ if (!(status & ACE_STATUS_DATABUFRDY)) {
+ dev_dbg(ace->dev,
+ "DATABUF not set; t=%i iter=%i c=%i dc=%i irq=%i\n",
+ ace->fsm_task, ace->fsm_iter_num,
+ ace->req->current_nr_sectors * 16,
+ ace->data_count, ace->in_irq);
+ ace_fsm_yieldirq(ace);
+ break;
+ }
+
+ /* Transfer the next buffer */
+ i = 16;
+ if (ace->fsm_task == ACE_TASK_WRITE)
+ ace->reg_ops->dataout(ace);
+ else
+ ace->reg_ops->datain(ace);
+ ace->data_count--;
+
+ /* If there are still buffers to be transfers; jump out here */
+ if (ace->data_count != 0) {
+ ace_fsm_yieldirq(ace);
+ break;
+ }
+
+ /* bio finished; is there another one? */
+ i = ace->req->current_nr_sectors;
+ if (end_that_request_first(ace->req, 1, i)) {
+ /* dev_dbg(ace->dev, "next block; h=%li c=%i\n",
+ * ace->req->hard_nr_sectors,
+ * ace->req->current_nr_sectors);
+ */
+ ace->data_ptr = ace->req->buffer;
+ ace->data_count = ace->req->current_nr_sectors * 16;
+ ace_fsm_yieldirq(ace);
+ break;
+ }
+
+ ace->fsm_state = ACE_FSM_STATE_REQ_COMPLETE;
+ break;
+
+ case ACE_FSM_STATE_REQ_COMPLETE:
+ /* Complete the block request */
+ blkdev_dequeue_request(ace->req);
+ end_that_request_last(ace->req, 1);
+ ace->req = NULL;
+
+ /* Finished request; go to idle state */
+ ace->fsm_state = ACE_FSM_STATE_IDLE;
+ break;
+
+ default:
+ ace->fsm_state = ACE_FSM_STATE_IDLE;
+ break;
+ }
+}
+
+static void ace_fsm_tasklet(unsigned long data)
+{
+ struct ace_device *ace = (void *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ace->lock, flags);
+
+ /* Loop over state machine until told to stop */
+ ace->fsm_continue_flag = 1;
+ while (ace->fsm_continue_flag)
+ ace_fsm_dostate(ace);
+
+ spin_unlock_irqrestore(&ace->lock, flags);
+}
+
+static void ace_stall_timer(unsigned long data)
+{
+ struct ace_device *ace = (void *)data;
+ unsigned long flags;
+
+ dev_warn(ace->dev,
+ "kicking stalled fsm; state=%i task=%i iter=%i dc=%i\n",
+ ace->fsm_state, ace->fsm_task, ace->fsm_iter_num,
+ ace->data_count);
+ spin_lock_irqsave(&ace->lock, flags);
+
+ /* Rearm the stall timer *before* entering FSM (which may then
+ * delete the timer) */
+ mod_timer(&ace->stall_timer, jiffies + HZ);
+
+ /* Loop over state machine until told to stop */
+ ace->fsm_continue_flag = 1;
+ while (ace->fsm_continue_flag)
+ ace_fsm_dostate(ace);
+
+ spin_unlock_irqrestore(&ace->lock, flags);
+}
+
+/* ---------------------------------------------------------------------
+ * Interrupt handling routines
+ */
+static int ace_interrupt_checkstate(struct ace_device *ace)
+{
+ u32 sreg = ace_in32(ace, ACE_STATUS);
+ u16 creg = ace_in(ace, ACE_CTRL);
+
+ /* Check for error occurance */
+ if ((sreg & (ACE_STATUS_CFGERROR | ACE_STATUS_CFCERROR)) &&
+ (creg & ACE_CTRL_ERRORIRQ)) {
+ dev_err(ace->dev, "transfer failure\n");
+ ace_dump_regs(ace);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static irqreturn_t ace_interrupt(int irq, void *dev_id)
+{
+ u16 creg;
+ struct ace_device *ace = dev_id;
+
+ /* be safe and get the lock */
+ spin_lock(&ace->lock);
+ ace->in_irq = 1;
+
+ /* clear the interrupt */
+ creg = ace_in(ace, ACE_CTRL);
+ ace_out(ace, ACE_CTRL, creg | ACE_CTRL_RESETIRQ);
+ ace_out(ace, ACE_CTRL, creg);
+
+ /* check for IO failures */
+ if (ace_interrupt_checkstate(ace))
+ ace->data_result = -EIO;
+
+ if (ace->fsm_task == 0) {
+ dev_err(ace->dev,
+ "spurious irq; stat=%.8x ctrl=%.8x cmd=%.4x\n",
+ ace_in32(ace, ACE_STATUS), ace_in32(ace, ACE_CTRL),
+ ace_in(ace, ACE_SECCNTCMD));
+ dev_err(ace->dev, "fsm_task=%i fsm_state=%i data_count=%i\n",
+ ace->fsm_task, ace->fsm_state, ace->data_count);
+ }
+
+ /* Loop over state machine until told to stop */
+ ace->fsm_continue_flag = 1;
+ while (ace->fsm_continue_flag)
+ ace_fsm_dostate(ace);
+
+ /* done with interrupt; drop the lock */
+ ace->in_irq = 0;
+ spin_unlock(&ace->lock);
+
+ return IRQ_HANDLED;
+}
+
+/* ---------------------------------------------------------------------
+ * Block ops
+ */
+static void ace_request(request_queue_t * q)
+{
+ struct request *req;
+ struct ace_device *ace;
+
+ req = ace_get_next_request(q);
+
+ if (req) {
+ ace = req->rq_disk->private_data;
+ tasklet_schedule(&ace->fsm_tasklet);
+ }
+}
+
+static int ace_media_changed(struct gendisk *gd)
+{
+ struct ace_device *ace = gd->private_data;
+ dev_dbg(ace->dev, "ace_media_changed(): %i\n", ace->media_change);
+
+ return ace->media_change;
+}
+
+static int ace_revalidate_disk(struct gendisk *gd)
+{
+ struct ace_device *ace = gd->private_data;
+ unsigned long flags;
+
+ dev_dbg(ace->dev, "ace_revalidate_disk()\n");
+
+ if (ace->media_change) {
+ dev_dbg(ace->dev, "requesting cf id and scheduling tasklet\n");
+
+ spin_lock_irqsave(&ace->lock, flags);
+ ace->id_req_count++;
+ spin_unlock_irqrestore(&ace->lock, flags);
+
+ tasklet_schedule(&ace->fsm_tasklet);
+ wait_for_completion(&ace->id_completion);
+ }
+
+ dev_dbg(ace->dev, "revalidate complete\n");
+ return ace->id_result;
+}
+
+static int ace_open(struct inode *inode, struct file *filp)
+{
+ struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
+ unsigned long flags;
+
+ dev_dbg(ace->dev, "ace_open() users=%i\n", ace->users + 1);
+
+ filp->private_data = ace;
+ spin_lock_irqsave(&ace->lock, flags);
+ ace->users++;
+ spin_unlock_irqrestore(&ace->lock, flags);
+
+ check_disk_change(inode->i_bdev);
+ return 0;
+}
+
+static int ace_release(struct inode *inode, struct file *filp)
+{
+ struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
+ unsigned long flags;
+ u16 val;
+
+ dev_dbg(ace->dev, "ace_release() users=%i\n", ace->users - 1);
+
+ spin_lock_irqsave(&ace->lock, flags);
+ ace->users--;
+ if (ace->users == 0) {
+ val = ace_in(ace, ACE_CTRL);
+ ace_out(ace, ACE_CTRL, val & ~ACE_CTRL_LOCKREQ);
+ }
+ spin_unlock_irqrestore(&ace->lock, flags);
+ return 0;
+}
+
+static int ace_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
+ struct hd_geometry __user *geo = (struct hd_geometry __user *)arg;
+ struct hd_geometry g;
+ dev_dbg(ace->dev, "ace_ioctl()\n");
+
+ switch (cmd) {
+ case HDIO_GETGEO:
+ g.heads = ace->cf_id.heads;
+ g.sectors = ace->cf_id.sectors;
+ g.cylinders = ace->cf_id.cyls;
+ g.start = 0;
+ return copy_to_user(geo, &g, sizeof(g)) ? -EFAULT : 0;
+
+ default:
+ return -ENOTTY;
+ }
+ return -ENOTTY;
+}
+
+static struct block_device_operations ace_fops = {
+ .owner = THIS_MODULE,
+ .open = ace_open,
+ .release = ace_release,
+ .media_changed = ace_media_changed,
+ .revalidate_disk = ace_revalidate_disk,
+ .ioctl = ace_ioctl,
+};
+
+/* --------------------------------------------------------------------
+ * SystemACE device setup/teardown code
+ */
+static int __devinit ace_setup(struct ace_device *ace)
+{
+ u16 version;
+ u16 val;
+
+ int rc;
+
+ spin_lock_init(&ace->lock);
+ init_completion(&ace->id_completion);
+
+ /*
+ * Map the device
+ */
+ ace->baseaddr = ioremap(ace->physaddr, 0x80);
+ if (!ace->baseaddr)
+ goto err_ioremap;
+
+ if (ace->irq != NO_IRQ) {
+ rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
+ if (rc) {
+ /* Failure - fall back to polled mode */
+ dev_err(ace->dev, "request_irq failed\n");
+ ace->irq = NO_IRQ;
+ }
+ }
+
+ /*
+ * Initialize the state machine tasklet and stall timer
+ */
+ tasklet_init(&ace->fsm_tasklet, ace_fsm_tasklet, (unsigned long)ace);
+ setup_timer(&ace->stall_timer, ace_stall_timer, (unsigned long)ace);
+
+ /*
+ * Initialize the request queue
+ */
+ ace->queue = blk_init_queue(ace_request, &ace->lock);
+ if (ace->queue == NULL)
+ goto err_blk_initq;
+ blk_queue_hardsect_size(ace->queue, 512);
+
+ /*
+ * Allocate and initialize GD structure
+ */
+ ace->gd = alloc_disk(ACE_NUM_MINORS);
+ if (!ace->gd)
+ goto err_alloc_disk;
+
+ ace->gd->major = ace_major;
+ ace->gd->first_minor = ace->id * ACE_NUM_MINORS;
+ ace->gd->fops = &ace_fops;
+ ace->gd->queue = ace->queue;
+ ace->gd->private_data = ace;
+ snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');
+
+ /* set bus width */
+ if (ace->bus_width == 1) {
+ /* 0x0101 should work regardless of endianess */
+ ace_out_le16(ace, ACE_BUSMODE, 0x0101);
+
+ /* read it back to determine endianess */
+ if (ace_in_le16(ace, ACE_BUSMODE) == 0x0001)
+ ace->reg_ops = &ace_reg_le16_ops;
+ else
+ ace->reg_ops = &ace_reg_be16_ops;
+ } else {
+ ace_out_8(ace, ACE_BUSMODE, 0x00);
+ ace->reg_ops = &ace_reg_8_ops;
+ }
+
+ /* Make sure version register is sane */
+ version = ace_in(ace, ACE_VERSION);
+ if ((version == 0) || (version == 0xFFFF))
+ goto err_read;
+
+ /* Put sysace in a sane state by clearing most control reg bits */
+ ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE |
+ ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);
+
+ /* Enable interrupts */
+ val = ace_in(ace, ACE_CTRL);
+ val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;
+ ace_out(ace, ACE_CTRL, val);
+
+ /* Print the identification */
+ dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i\n",
+ (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff);
+ dev_dbg(ace->dev, "physaddr 0x%lx, mapped to 0x%p, irq=%i\n",
+ ace->physaddr, ace->baseaddr, ace->irq);
+
+ ace->media_change = 1;
+ ace_revalidate_disk(ace->gd);
+
+ /* Make the sysace device 'live' */
+ add_disk(ace->gd);
+
+ return 0;
+
+ err_read:
+ put_disk(ace->gd);
+ err_alloc_disk:
+ blk_cleanup_queue(ace->queue);
+ err_blk_initq:
+ iounmap(ace->baseaddr);
+ if (ace->irq != NO_IRQ)
+ free_irq(ace->irq, ace);
+ err_ioremap:
+ printk(KERN_INFO "xsysace: error initializing device at 0x%lx\n",
+ ace->physaddr);
+ return -ENOMEM;
+}
+
+static void __devexit ace_teardown(struct ace_device *ace)
+{
+ if (ace->gd) {
+ del_gendisk(ace->gd);
+ put_disk(ace->gd);
+ }
+
+ if (ace->queue)
+ blk_cleanup_queue(ace->queue);
+
+ tasklet_kill(&ace->fsm_tasklet);
+
+ if (ace->irq != NO_IRQ)
+ free_irq(ace->irq, ace);
+
+ iounmap(ace->baseaddr);
+}
+
+/* ---------------------------------------------------------------------
+ * Platform Bus Support
+ */
+
+static int __devinit ace_probe(struct device *device)
+{
+ struct platform_device *dev = to_platform_device(device);
+ struct ace_device *ace;
+ int i;
+
+ dev_dbg(device, "ace_probe(%p)\n", device);
+
+ /*
+ * Allocate the ace device structure
+ */
+ ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL);
+ if (!ace)
+ goto err_alloc;
+
+ ace->dev = device;
+ ace->id = dev->id;
+ ace->irq = NO_IRQ;
+
+ for (i = 0; i < dev->num_resources; i++) {
+ if (dev->resource[i].flags & IORESOURCE_MEM)
+ ace->physaddr = dev->resource[i].start;
+ if (dev->resource[i].flags & IORESOURCE_IRQ)
+ ace->irq = dev->resource[i].start;
+ }
+
+ /* FIXME: Should get bus_width from the platform_device struct */
+ ace->bus_width = 1;
+
+ dev_set_drvdata(&dev->dev, ace);
+
+ /* Call the bus-independant setup code */
+ if (ace_setup(ace) != 0)
+ goto err_setup;
+
+ return 0;
+
+ err_setup:
+ dev_set_drvdata(&dev->dev, NULL);
+ kfree(ace);
+ err_alloc:
+ printk(KERN_ERR "xsysace: could not initialize device\n");
+ return -ENOMEM;
+}
+
+/*
+ * Platform bus remove() method
+ */
+static int __devexit ace_remove(struct device *device)
+{
+ struct ace_device *ace = dev_get_drvdata(device);
+
+ dev_dbg(device, "ace_remove(%p)\n", device);
+
+ if (ace) {
+ ace_teardown(ace);
+ kfree(ace);
+ }
+
+ return 0;
+}
+
+static struct device_driver ace_driver = {
+ .name = "xsysace",
+ .bus = &platform_bus_type,
+ .probe = ace_probe,
+ .remove = __devexit_p(ace_remove),
+};
+
+/* ---------------------------------------------------------------------
+ * Module init/exit routines
+ */
+static int __init ace_init(void)
+{
+ ace_major = register_blkdev(ace_major, "xsysace");
+ if (ace_major <= 0) {
+ printk(KERN_WARNING "xsysace: register_blkdev() failed\n");
+ return ace_major;
+ }
+
+ pr_debug("Registering Xilinx SystemACE driver, major=%i\n", ace_major);
+ return driver_register(&ace_driver);
+}
+
+static void __exit ace_exit(void)
+{
+ pr_debug("Unregistering Xilinx SystemACE driver\n");
+ driver_unregister(&ace_driver);
+ unregister_blkdev(ace_major, "xsysace");
+}
+
+module_init(ace_init);
+module_exit(ace_exit);
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 7cc2685ca84a..e40fa98842e5 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -44,9 +44,6 @@
extern int m68k_realnum_memory;
extern struct mem_info m68k_memory[NUM_MEMINFO];
-#define TRUE (1)
-#define FALSE (0)
-
#define Z2MINOR_COMBINED (0)
#define Z2MINOR_Z2ONLY (1)
#define Z2MINOR_CHIPONLY (2)
@@ -374,9 +371,7 @@ static void __exit z2_exit(void)
{
int i, j;
blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), 256);
- if ( unregister_blkdev( Z2RAM_MAJOR, DEVICE_NAME ) != 0 )
- printk( KERN_ERR DEVICE_NAME ": unregister of device failed\n");
-
+ unregister_blkdev(Z2RAM_MAJOR, DEVICE_NAME);
del_gendisk(z2ram_gendisk);
put_disk(z2ram_gendisk);
blk_cleanup_queue(z2_queue);
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 7e04dd69f609..59b054810ed0 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -199,7 +199,6 @@ static void hci_usb_tx_complete(struct urb *urb);
#define __pending_q(husb, type) (&husb->pending_q[type-1])
#define __completed_q(husb, type) (&husb->completed_q[type-1])
#define __transmit_q(husb, type) (&husb->transmit_q[type-1])
-#define __reassembly(husb, type) (husb->reassembly[type-1])
static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
{
@@ -429,12 +428,6 @@ static void hci_usb_unlink_urbs(struct hci_usb *husb)
kfree(urb->transfer_buffer);
_urb_free(_urb);
}
-
- /* Release reassembly buffers */
- if (husb->reassembly[i]) {
- kfree_skb(husb->reassembly[i]);
- husb->reassembly[i] = NULL;
- }
}
}
@@ -671,83 +664,6 @@ static int hci_usb_send_frame(struct sk_buff *skb)
return 0;
}
-static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
-{
- BT_DBG("%s type %d data %p count %d", husb->hdev->name, type, data, count);
-
- husb->hdev->stat.byte_rx += count;
-
- while (count) {
- struct sk_buff *skb = __reassembly(husb, type);
- struct { int expect; } *scb;
- int len = 0;
-
- if (!skb) {
- /* Start of the frame */
-
- switch (type) {
- case HCI_EVENT_PKT:
- if (count >= HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *h = data;
- len = HCI_EVENT_HDR_SIZE + h->plen;
- } else
- return -EILSEQ;
- break;
-
- case HCI_ACLDATA_PKT:
- if (count >= HCI_ACL_HDR_SIZE) {
- struct hci_acl_hdr *h = data;
- len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
- } else
- return -EILSEQ;
- break;
-#ifdef CONFIG_BT_HCIUSB_SCO
- case HCI_SCODATA_PKT:
- if (count >= HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *h = data;
- len = HCI_SCO_HDR_SIZE + h->dlen;
- } else
- return -EILSEQ;
- break;
-#endif
- }
- BT_DBG("new packet len %d", len);
-
- skb = bt_skb_alloc(len, GFP_ATOMIC);
- if (!skb) {
- BT_ERR("%s no memory for the packet", husb->hdev->name);
- return -ENOMEM;
- }
- skb->dev = (void *) husb->hdev;
- bt_cb(skb)->pkt_type = type;
-
- __reassembly(husb, type) = skb;
-
- scb = (void *) skb->cb;
- scb->expect = len;
- } else {
- /* Continuation */
- scb = (void *) skb->cb;
- len = scb->expect;
- }
-
- len = min(len, count);
-
- memcpy(skb_put(skb, len), data, len);
-
- scb->expect -= len;
- if (!scb->expect) {
- /* Complete frame */
- __reassembly(husb, type) = NULL;
- bt_cb(skb)->pkt_type = type;
- hci_recv_frame(skb);
- }
-
- count -= len; data += len;
- }
- return 0;
-}
-
static void hci_usb_rx_complete(struct urb *urb)
{
struct _urb *_urb = container_of(urb, struct _urb, urb);
@@ -776,7 +692,7 @@ static void hci_usb_rx_complete(struct urb *urb)
urb->iso_frame_desc[i].actual_length);
if (!urb->iso_frame_desc[i].status)
- __recv_frame(husb, _urb->type,
+ hci_recv_fragment(husb->hdev, _urb->type,
urb->transfer_buffer + urb->iso_frame_desc[i].offset,
urb->iso_frame_desc[i].actual_length);
}
@@ -784,7 +700,7 @@ static void hci_usb_rx_complete(struct urb *urb)
;
#endif
} else {
- err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
+ err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count);
if (err < 0) {
BT_ERR("%s corrupted packet: type %d count %d",
husb->hdev->name, _urb->type, count);
diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h
index 963fc55cdc85..56cd3a92ceca 100644
--- a/drivers/bluetooth/hci_usb.h
+++ b/drivers/bluetooth/hci_usb.h
@@ -102,9 +102,9 @@ struct hci_usb {
struct hci_dev *hdev;
unsigned long state;
-
+
struct usb_device *udev;
-
+
struct usb_host_endpoint *bulk_in_ep;
struct usb_host_endpoint *bulk_out_ep;
struct usb_host_endpoint *intr_in_ep;
@@ -116,7 +116,6 @@ struct hci_usb {
__u8 ctrl_req;
struct sk_buff_head transmit_q[4];
- struct sk_buff *reassembly[4]; /* Reassembly buffers */
rwlock_t completion_lock;
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index b71a5ccc587f..0638730a4a19 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -180,11 +180,6 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
return total;
}
-static loff_t vhci_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
static ssize_t vhci_read(struct file *file,
char __user *buf, size_t count, loff_t *pos)
{
@@ -334,7 +329,6 @@ static int vhci_fasync(int fd, struct file *file, int on)
static const struct file_operations vhci_fops = {
.owner = THIS_MODULE,
- .llseek = vhci_llseek,
.read = vhci_read,
.write = vhci_write,
.poll = vhci_poll,
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index aa5468f487ba..499019bf8f40 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2695,11 +2695,12 @@ int cdrom_ioctl(struct file * file, struct cdrom_device_info *cdi,
{
void __user *argp = (void __user *)arg;
int ret;
+ struct gendisk *disk = ip->i_bdev->bd_disk;
/*
* Try the generic SCSI command ioctl's first.
*/
- ret = scsi_cmd_ioctl(file, ip->i_bdev->bd_disk, cmd, argp);
+ ret = scsi_cmd_ioctl(file, disk->queue, disk, cmd, argp);
if (ret != -ENOTTY)
return ret;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ef683ebd367c..c8dfd18bea44 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -114,7 +114,7 @@ config COMPUTONE
config ROCKETPORT
tristate "Comtrol RocketPort support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
help
This driver supports Comtrol RocketPort and RocketModem PCI boards.
These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
@@ -157,7 +157,7 @@ config CYZ_INTR
config DIGIEPCA
tristate "Digiboard Intelligent Async Support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
---help---
This is a driver for Digi International's Xx, Xeve, and Xem series
of cards which provide multiple serial ports. You would need
@@ -185,7 +185,7 @@ config ESPSERIAL
config MOXA_INTELLIO
tristate "Moxa Intellio support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
help
Say Y here if you have a Moxa Intellio multiport serial card.
@@ -213,8 +213,6 @@ config MOXA_SMARTIO_NEW
This is upgraded (1.9.1) driver from original Moxa drivers with
changes finally resulting in PCI probing.
- Use at your own risk.
-
This driver can also be built as a module. The module will be called
mxser_new. If you want to do that, say M here.
@@ -243,7 +241,7 @@ config SYNCLINK
config SYNCLINKMP
tristate "SyncLink Multiport support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && PCI
help
Enable support for the SyncLink Multiport (2 or 4 ports)
serial adapter, running asynchronous and HDLC communications up
@@ -354,7 +352,7 @@ config STALDRV
config STALLION
tristate "Stallion EasyIO or EC8/32 support"
- depends on STALDRV && BROKEN_ON_SMP
+ depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
help
If you have an EasyIO or EasyConnection 8/32 multiport Stallion
card, then this is for you; say Y. Make sure to read
@@ -365,7 +363,7 @@ config STALLION
config ISTALLION
tristate "Stallion EC8/64, ONboard, Brumby support"
- depends on STALDRV && BROKEN_ON_SMP
+ depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI)
help
If you have an EasyConnection 8/64, ONboard, Brumby or Stallion
serial multiport card, say Y here. Make sure to read
@@ -374,53 +372,6 @@ config ISTALLION
To compile this driver as a module, choose M here: the
module will be called istallion.
-config AU1000_UART
- bool "Enable Au1000 UART Support"
- depends on SERIAL_NONSTANDARD && MIPS
- help
- If you have an Alchemy AU1000 processor (MIPS based) and you want
- to use serial ports, say Y. Otherwise, say N.
-
-config AU1000_SERIAL_CONSOLE
- bool "Enable Au1000 serial console"
- depends on AU1000_UART
- help
- If you have an Alchemy AU1000 processor (MIPS based) and you want
- to use a console on a serial port, say Y. Otherwise, say N.
-
-config SERIAL_DEC
- bool "DECstation serial support"
- depends on MACH_DECSTATION
- default y
- help
- This selects whether you want to be asked about drivers for
- DECstation serial ports.
-
- Note that the answer to this question won't directly affect the
- kernel: saying N will just cause the configurator to skip all
- the questions about DECstation serial ports.
-
-config SERIAL_DEC_CONSOLE
- bool "Support for console on a DECstation serial port"
- depends on SERIAL_DEC
- default y
- help
- If you say Y here, it will be possible to use a serial port as the
- system console (the system console is the device which receives all
- kernel messages and warnings and which allows logins in single user
- mode). Note that the firmware uses ttyS0 as the serial console on
- the Maxine and ttyS2 on the others.
-
- If unsure, say Y.
-
-config ZS
- bool "Z85C30 Serial Support"
- depends on SERIAL_DEC
- default y
- help
- Documentation on the Zilog 85C350 serial communications controller
- is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>
-
config A2232
tristate "Commodore A2232 serial support (EXPERIMENTAL)"
depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
@@ -653,6 +604,14 @@ config HVC_BEAT
help
Toshiba's Cell Reference Set Beat Console device driver
+config HVC_XEN
+ bool "Xen Hypervisor Console support"
+ depends on XEN
+ select HVC_DRIVER
+ default y
+ help
+ Xen virtual console device driver
+
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"
depends on PPC_PSERIES
@@ -767,7 +726,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+ depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -815,7 +774,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390 && !SUPERH
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH
---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
@@ -993,15 +952,14 @@ config GPIO_VR41XX
depends on CPU_VR41XX
config RAW_DRIVER
- tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)"
+ tristate "RAW driver (/dev/raw/rawN)"
depends on BLOCK
help
- The raw driver permits block devices to be bound to /dev/raw/rawN.
- Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
+ The raw driver permits block devices to be bound to /dev/raw/rawN.
+ Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
See the raw(8) manpage for more details.
- The raw driver is deprecated and will be removed soon.
- Applications should simply open the device (eg /dev/hda1)
+ Applications should preferably open the device (eg /dev/hda1)
with the O_DIRECT flag.
config MAX_RAW_DEVS
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 2f56ecc035aa..8fecaf4010b1 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -15,6 +15,7 @@ obj-y += misc.o
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \
consolemap_deftbl.o selection.o keyboard.o
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
+obj-$(CONFIG_AUDIT) += tty_audit.o
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_ESPSERIAL) += esp.o
obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o
@@ -41,12 +42,14 @@ obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
+obj-$(CONFIG_LGUEST_GUEST) += hvc_lguest.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
+obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MSPEC) += mspec.o
@@ -104,6 +107,8 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/
obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
+obj-$(CONFIG_PS3_FLASH) += ps3flash.o
+
# Files generated that shall be removed upon make clean
clean-files := consolemap_deftbl.c defkeymap.c
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index e6c534e62846..df0ddf14b85c 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -462,9 +462,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev,
* erratum 46: Setup violation on AGP SBA pins - Disable side band addressing.
* With this lot disabled, we should prevent lockups. */
if (agp_bridge->dev->device == PCI_DEVICE_ID_AMD_FE_GATE_700E) {
- u8 revision=0;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &revision);
- if (revision == 0x10 || revision == 0x11) {
+ if (pdev->revision == 0x10 || pdev->revision == 0x11) {
agp_bridge->flags = AGP_ERRATA_FASTWRITES;
agp_bridge->flags |= AGP_ERRATA_SBA;
agp_bridge->flags |= AGP_ERRATA_1X;
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 801abdd29066..d95662e96326 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -367,10 +367,8 @@ static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge)
{
char *revstring;
- u8 rev_id;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
- switch (rev_id) {
+ switch (pdev->revision) {
case 0x01: revstring="A0"; break;
case 0x02: revstring="A1"; break;
case 0x11: revstring="B0"; break;
@@ -386,7 +384,7 @@ static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data
* Work around errata.
* Chips before B2 stepping incorrectly reporting v3.5
*/
- if (rev_id < 0x13) {
+ if (pdev->revision < 0x13) {
printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n");
bridge->major_version = 3;
bridge->minor_version = 0;
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index ebdd6dd66edb..1b47c89a1b99 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -321,7 +321,7 @@ EXPORT_SYMBOL(agp_try_unsupported_boot);
static int __init agp_init(void)
{
if (!agp_off)
- printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Dave Jones\n",
+ printk(KERN_INFO "Linux agpgart interface v%d.%d\n",
AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
return 0;
}
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 4eaceabd8cea..3d468f502d2d 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -738,6 +738,7 @@ static void change_speed(struct async_struct *info,
}
/* If the quotient is zero refuse the change */
if (!quot && old_termios) {
+ /* FIXME: Will need updating for new tty in the end */
info->tty->termios->c_cflag &= ~CBAUD;
info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
baud = tty_get_baud_rate(info->tty);
@@ -783,7 +784,6 @@ static void change_speed(struct async_struct *info,
/*
* Set up parity check flag
*/
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
info->read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (I_INPCK(info->tty))
@@ -1367,11 +1367,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
- if ( (cflag == old_termios->c_cflag)
- && ( RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
-
change_speed(info, old_termios);
/* Handle transition to B0 status */
@@ -1726,12 +1721,11 @@ static int get_async_struct(int line, struct async_struct **ret_info)
*ret_info = sstate->info;
return 0;
}
- info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+ info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
if (!info) {
sstate->count--;
return -ENOMEM;
}
- memset(info, 0, sizeof(struct async_struct));
#ifdef DECLARE_WAITQUEUE
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 179c7a3b6e75..ec116df919d9 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -20,6 +20,7 @@
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/apm-emulation.h>
+#include <linux/freezer.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/list.h>
@@ -329,13 +330,8 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
/*
* Wait for the suspend/resume to complete. If there
* are pending acknowledges, we wait here for them.
- *
- * Note: we need to ensure that the PM subsystem does
- * not kick us out of the wait when it suspends the
- * threads.
*/
flags = current->flags;
- current->flags |= PF_NOFREEZE;
wait_event(apm_suspend_waitqueue,
as->suspend_state == SUSPEND_DONE);
@@ -365,13 +361,8 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
/*
* Wait for the suspend/resume to complete. If there
* are pending acknowledges, we wait here for them.
- *
- * Note: we need to ensure that the PM subsystem does
- * not kick us out of the wait when it suspends the
- * threads.
*/
flags = current->flags;
- current->flags |= PF_NOFREEZE;
wait_event_interruptible(apm_suspend_waitqueue,
as->suspend_state == SUSPEND_DONE);
@@ -598,7 +589,6 @@ static int __init apm_init(void)
kapmd_tsk = NULL;
return ret;
}
- kapmd_tsk->flags |= PF_NOFREEZE;
wake_up_process(kapmd_tsk);
#ifdef CONFIG_PROC_FS
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index ed53f541d9e8..b6f2639f903d 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -91,11 +91,6 @@ static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count
unsigned short c;
unsigned char cp;
-#if 0 /* Can't seek (pread) on this device */
- if (ppos != &file->f_pos)
- return -ESPIPE;
-#endif
-
if (!vfd_is_open)
return -ENODEV;
@@ -139,11 +134,6 @@ static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_
size_t indx = len;
int i, esc = 0;
-#if 0 /* Can't seek (pwrite) on this device */
- if (ppos != &file->f_pos)
- return -ESPIPE;
-#endif
-
if (!vfd_is_open)
return -EBUSY;
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index fd40b959afdd..4b3916f54909 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -177,6 +177,7 @@ struct uni_pagedir {
unsigned long refcount;
unsigned long sum;
unsigned char *inverse_translations[4];
+ u16 *inverse_trans_unicode;
int readonly;
};
@@ -207,6 +208,41 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int
}
}
+static void set_inverse_trans_unicode(struct vc_data *conp,
+ struct uni_pagedir *p)
+{
+ int i, j, k, glyph;
+ u16 **p1, *p2;
+ u16 *q;
+
+ if (!p) return;
+ q = p->inverse_trans_unicode;
+ if (!q) {
+ q = p->inverse_trans_unicode =
+ kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL);
+ if (!q)
+ return;
+ }
+ memset(q, 0, MAX_GLYPH * sizeof(u16));
+
+ for (i = 0; i < 32; i++) {
+ p1 = p->uni_pgdir[i];
+ if (!p1)
+ continue;
+ for (j = 0; j < 32; j++) {
+ p2 = p1[j];
+ if (!p2)
+ continue;
+ for (k = 0; k < 64; k++) {
+ glyph = p2[k];
+ if (glyph >= 0 && glyph < MAX_GLYPH
+ && q[glyph] < 32)
+ q[glyph] = (i << 11) + (j << 6) + k;
+ }
+ }
+ }
+}
+
unsigned short *set_translate(int m, struct vc_data *vc)
{
inv_translate[vc->vc_num] = m;
@@ -217,19 +253,29 @@ unsigned short *set_translate(int m, struct vc_data *vc)
* Inverse translation is impossible for several reasons:
* 1. The font<->character maps are not 1-1.
* 2. The text may have been written while a different translation map
- * was active, or using Unicode.
+ * was active.
* Still, it is now possible to a certain extent to cut and paste non-ASCII.
*/
-unsigned char inverse_translate(struct vc_data *conp, int glyph)
+u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode)
{
struct uni_pagedir *p;
+ int m;
if (glyph < 0 || glyph >= MAX_GLYPH)
return 0;
- else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) ||
- !p->inverse_translations[inv_translate[conp->vc_num]])
+ else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc))
return glyph;
- else
- return p->inverse_translations[inv_translate[conp->vc_num]][glyph];
+ else if (use_unicode) {
+ if (!p->inverse_trans_unicode)
+ return glyph;
+ else
+ return p->inverse_trans_unicode[glyph];
+ } else {
+ m = inv_translate[conp->vc_num];
+ if (!p->inverse_translations[m])
+ return glyph;
+ else
+ return p->inverse_translations[m][glyph];
+ }
}
static void update_user_maps(void)
@@ -243,6 +289,7 @@ static void update_user_maps(void)
p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc;
if (p && p != q) {
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
+ set_inverse_trans_unicode(vc_cons[i].d, p);
q = p;
}
}
@@ -353,6 +400,10 @@ static void con_release_unimap(struct uni_pagedir *p)
kfree(p->inverse_translations[i]);
p->inverse_translations[i] = NULL;
}
+ if (p->inverse_trans_unicode) {
+ kfree(p->inverse_trans_unicode);
+ p->inverse_trans_unicode = NULL;
+ }
}
void con_free_unimap(struct vc_data *vc)
@@ -511,6 +562,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
for (i = 0; i <= 3; i++)
set_inverse_transl(vc, p, i); /* Update all inverse translations */
+ set_inverse_trans_unicode(vc, p);
return err;
}
@@ -561,6 +613,7 @@ int con_set_default_unimap(struct vc_data *vc)
for (i = 0; i <= 3; i++)
set_inverse_transl(vc, p, i); /* Update all inverse translations */
+ set_inverse_trans_unicode(vc, p);
dflt = p;
return err;
}
@@ -617,6 +670,19 @@ void con_protect_unimap(struct vc_data *vc, int rdonly)
p->readonly = rdonly;
}
+/* may be called during an interrupt */
+u32 conv_8bit_to_uni(unsigned char c)
+{
+ /*
+ * Always use USER_MAP. This function is used by the keyboard,
+ * which shouldn't be affected by G0/G1 switching, etc.
+ * If the user map still contains default values, i.e. the
+ * direct-to-font mapping, then assume user is using Latin1.
+ */
+ unsigned short uni = translations[USER_MAP][c];
+ return uni == (0xf000 | c) ? c : uni;
+}
+
int
conv_uni_to_pc(struct vc_data *conp, long ucs)
{
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index ca376b92162c..9e0adfe27c12 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -646,6 +646,7 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/bitops.h>
+#include <linux/firmware.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -680,6 +681,44 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
#define STD_COM_FLAGS (0)
+/* firmware stuff */
+#define ZL_MAX_BLOCKS 16
+#define DRIVER_VERSION 0x02010203
+#define RAM_SIZE 0x80000
+
+#define Z_FPGA_LOADED(X) ((readl(&(X)->init_ctrl) & (1<<17)) != 0)
+
+enum zblock_type {
+ ZBLOCK_PRG = 0,
+ ZBLOCK_FPGA = 1
+};
+
+struct zfile_header {
+ char name[64];
+ char date[32];
+ char aux[32];
+ u32 n_config;
+ u32 config_offset;
+ u32 n_blocks;
+ u32 block_offset;
+ u32 reserved[9];
+} __attribute__ ((packed));
+
+struct zfile_config {
+ char name[64];
+ u32 mailbox;
+ u32 function;
+ u32 n_blocks;
+ u32 block_list[ZL_MAX_BLOCKS];
+} __attribute__ ((packed));
+
+struct zfile_block {
+ u32 type;
+ u32 file_offset;
+ u32 ram_offset;
+ u32 size;
+} __attribute__ ((packed));
+
static struct tty_driver *cy_serial_driver;
#ifdef CONFIG_ISA
@@ -1851,11 +1890,11 @@ static void cyz_poll(unsigned long arg)
struct cyclades_card *cinfo;
struct cyclades_port *info;
struct tty_struct *tty;
- static struct FIRM_ID *firm_id;
- static struct ZFW_CTRL *zfw_ctrl;
- static struct BOARD_CTRL *board_ctrl;
- static struct CH_CTRL *ch_ctrl;
- static struct BUF_CTRL *buf_ctrl;
+ struct FIRM_ID __iomem *firm_id;
+ struct ZFW_CTRL __iomem *zfw_ctrl;
+ struct BOARD_CTRL __iomem *board_ctrl;
+ struct CH_CTRL __iomem *ch_ctrl;
+ struct BUF_CTRL __iomem *buf_ctrl;
unsigned long expires = jiffies + HZ;
int card, port;
@@ -1999,7 +2038,6 @@ static int startup(struct cyclades_port *info)
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
- int retval;
base_addr = card->base_addr;
@@ -2371,7 +2409,6 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
- int retval;
base_addr = cinfo->base_addr;
firm_id = base_addr + ID_ADDRESS;
@@ -4127,10 +4164,6 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
#endif
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- (tty->termios->c_iflag & (IXON | IXANY)) ==
- (old_termios->c_iflag & (IXON | IXANY)))
- return;
set_line_char(info);
if ((old_termios->c_cflag & CRTSCTS) &&
@@ -4433,10 +4466,10 @@ static void cy_hangup(struct tty_struct *tty)
static int __devinit cy_init_card(struct cyclades_card *cinfo)
{
struct cyclades_port *info;
- u32 mailbox;
+ u32 uninitialized_var(mailbox);
unsigned int nports;
unsigned short chip_number;
- int index, port;
+ int uninitialized_var(index), port;
spin_lock_init(&cinfo->card_lock);
@@ -4739,17 +4772,295 @@ static int __init cy_detect_isa(void)
} /* cy_detect_isa */
#ifdef CONFIG_PCI
-static void __devinit plx_init(void __iomem * addr, __u32 initctl)
+static inline int __devinit cyc_isfwstr(const char *str, unsigned int size)
+{
+ unsigned int a;
+
+ for (a = 0; a < size && *str; a++, str++)
+ if (*str & 0x80)
+ return -EINVAL;
+
+ for (; a < size; a++, str++)
+ if (*str)
+ return -EINVAL;
+
+ return 0;
+}
+
+static inline void __devinit cyz_fpga_copy(void __iomem *fpga, u8 *data,
+ unsigned int size)
+{
+ for (; size > 0; size--) {
+ cy_writel(fpga, *data++);
+ udelay(10);
+ }
+}
+
+static void __devinit plx_init(struct pci_dev *pdev, int irq,
+ struct RUNTIME_9060 __iomem *addr)
{
/* Reset PLX */
- cy_writel(addr + initctl, readl(addr + initctl) | 0x40000000);
+ cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x40000000);
udelay(100L);
- cy_writel(addr + initctl, readl(addr + initctl) & ~0x40000000);
+ cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x40000000);
/* Reload Config. Registers from EEPROM */
- cy_writel(addr + initctl, readl(addr + initctl) | 0x20000000);
+ cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) | 0x20000000);
udelay(100L);
- cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000);
+ cy_writel(&addr->init_ctrl, readl(&addr->init_ctrl) & ~0x20000000);
+
+ /* For some yet unknown reason, once the PLX9060 reloads the EEPROM,
+ * the IRQ is lost and, thus, we have to re-write it to the PCI config.
+ * registers. This will remain here until we find a permanent fix.
+ */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+}
+
+static int __devinit __cyz_load_fw(const struct firmware *fw,
+ const char *name, const u32 mailbox, void __iomem *base,
+ void __iomem *fpga)
+{
+ void *ptr = fw->data;
+ struct zfile_header *h = ptr;
+ struct zfile_config *c, *cs;
+ struct zfile_block *b, *bs;
+ unsigned int a, tmp, len = fw->size;
+#define BAD_FW KERN_ERR "Bad firmware: "
+ if (len < sizeof(*h)) {
+ printk(BAD_FW "too short: %u<%zu\n", len, sizeof(*h));
+ return -EINVAL;
+ }
+
+ cs = ptr + h->config_offset;
+ bs = ptr + h->block_offset;
+
+ if ((void *)(cs + h->n_config) > ptr + len ||
+ (void *)(bs + h->n_blocks) > ptr + len) {
+ printk(BAD_FW "too short");
+ return -EINVAL;
+ }
+
+ if (cyc_isfwstr(h->name, sizeof(h->name)) ||
+ cyc_isfwstr(h->date, sizeof(h->date))) {
+ printk(BAD_FW "bad formatted header string\n");
+ return -EINVAL;
+ }
+
+ if (strncmp(name, h->name, sizeof(h->name))) {
+ printk(BAD_FW "bad name '%s' (expected '%s')\n", h->name, name);
+ return -EINVAL;
+ }
+
+ tmp = 0;
+ for (c = cs; c < cs + h->n_config; c++) {
+ for (a = 0; a < c->n_blocks; a++)
+ if (c->block_list[a] > h->n_blocks) {
+ printk(BAD_FW "bad block ref number in cfgs\n");
+ return -EINVAL;
+ }
+ if (c->mailbox == mailbox && c->function == 0) /* 0 is normal */
+ tmp++;
+ }
+ if (!tmp) {
+ printk(BAD_FW "nothing appropriate\n");
+ return -EINVAL;
+ }
+
+ for (b = bs; b < bs + h->n_blocks; b++)
+ if (b->file_offset + b->size > len) {
+ printk(BAD_FW "bad block data offset\n");
+ return -EINVAL;
+ }
+
+ /* everything is OK, let's seek'n'load it */
+ for (c = cs; c < cs + h->n_config; c++)
+ if (c->mailbox == mailbox && c->function == 0)
+ break;
+
+ for (a = 0; a < c->n_blocks; a++) {
+ b = &bs[c->block_list[a]];
+ if (b->type == ZBLOCK_FPGA) {
+ if (fpga != NULL)
+ cyz_fpga_copy(fpga, ptr + b->file_offset,
+ b->size);
+ } else {
+ if (base != NULL)
+ memcpy_toio(base + b->ram_offset,
+ ptr + b->file_offset, b->size);
+ }
+ }
+#undef BAD_FW
+ return 0;
+}
+
+static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
+ struct RUNTIME_9060 __iomem *ctl_addr, int irq)
+{
+ const struct firmware *fw;
+ struct FIRM_ID __iomem *fid = base_addr + ID_ADDRESS;
+ struct CUSTOM_REG __iomem *cust = base_addr;
+ struct ZFW_CTRL __iomem *pt_zfwctrl;
+ void __iomem *tmp;
+ u32 mailbox, status;
+ unsigned int i;
+ int retval;
+
+ retval = request_firmware(&fw, "cyzfirm.bin", &pdev->dev);
+ if (retval) {
+ dev_err(&pdev->dev, "can't get firmware\n");
+ goto err;
+ }
+
+ /* Check whether the firmware is already loaded and running. If
+ positive, skip this board */
+ if (Z_FPGA_LOADED(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
+ u32 cntval = readl(base_addr + 0x190);
+
+ udelay(100);
+ if (cntval != readl(base_addr + 0x190)) {
+ /* FW counter is working, FW is running */
+ dev_dbg(&pdev->dev, "Cyclades-Z FW already loaded. "
+ "Skipping board.\n");
+ retval = 0;
+ goto err_rel;
+ }
+ }
+
+ /* start boot */
+ cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) &
+ ~0x00030800UL);
+
+ mailbox = readl(&ctl_addr->mail_box_0);
+
+ if (mailbox == 0 || Z_FPGA_LOADED(ctl_addr)) {
+ /* stops CPU and set window to beginning of RAM */
+ cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
+ cy_writel(&cust->cpu_stop, 0);
+ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
+ udelay(100);
+ }
+
+ plx_init(pdev, irq, ctl_addr);
+
+ if (mailbox != 0) {
+ /* load FPGA */
+ retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, NULL,
+ base_addr);
+ if (retval)
+ goto err_rel;
+ if (!Z_FPGA_LOADED(ctl_addr)) {
+ dev_err(&pdev->dev, "fw upload successful, but fw is "
+ "not loaded\n");
+ goto err_rel;
+ }
+ }
+
+ /* stops CPU and set window to beginning of RAM */
+ cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
+ cy_writel(&cust->cpu_stop, 0);
+ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
+ udelay(100);
+
+ /* clear memory */
+ for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
+ cy_writeb(tmp, 255);
+ if (mailbox != 0) {
+ /* set window to last 512K of RAM */
+ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
+ //sleep(1);
+ for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
+ cy_writeb(tmp, 255);
+ /* set window to beginning of RAM */
+ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
+ //sleep(1);
+ }
+
+ retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
+ release_firmware(fw);
+ if (retval)
+ goto err;
+
+ /* finish boot and start boards */
+ cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
+ cy_writel(&cust->cpu_start, 0);
+ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
+ i = 0;
+ while ((status = readl(&fid->signature)) != ZFIRM_ID && i++ < 40)
+ msleep(100);
+ if (status != ZFIRM_ID) {
+ if (status == ZFIRM_HLT) {
+ dev_err(&pdev->dev, "you need an external power supply "
+ "for this number of ports. Firmware halted and "
+ "board reset.\n");
+ retval = -EIO;
+ goto err;
+ }
+ dev_warn(&pdev->dev, "fid->signature = 0x%x... Waiting "
+ "some more time\n", status);
+ while ((status = readl(&fid->signature)) != ZFIRM_ID &&
+ i++ < 200)
+ msleep(100);
+ if (status != ZFIRM_ID) {
+ dev_err(&pdev->dev, "Board not started in 20 seconds! "
+ "Giving up. (fid->signature = 0x%x)\n",
+ status);
+ dev_info(&pdev->dev, "*** Warning ***: if you are "
+ "upgrading the FW, please power cycle the "
+ "system before loading the new FW to the "
+ "Cyclades-Z.\n");
+
+ if (Z_FPGA_LOADED(ctl_addr))
+ plx_init(pdev, irq, ctl_addr);
+
+ retval = -EIO;
+ goto err;
+ }
+ dev_dbg(&pdev->dev, "Firmware started after %d seconds.\n",
+ i / 10);
+ }
+ pt_zfwctrl = base_addr + readl(&fid->zfwctrl_addr);
+
+ dev_dbg(&pdev->dev, "fid=> %p, zfwctrl_addr=> %x, npt_zfwctrl=> %p\n",
+ base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
+ base_addr + readl(&fid->zfwctrl_addr));
+
+ dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
+ readl(&pt_zfwctrl->board_ctrl.fw_version),
+ readl(&pt_zfwctrl->board_ctrl.n_channel));
+
+ if (readl(&pt_zfwctrl->board_ctrl.n_channel) == 0) {
+ dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
+ "check the connection between the Z host card and the "
+ "serial expanders.\n");
+
+ if (Z_FPGA_LOADED(ctl_addr))
+ plx_init(pdev, irq, ctl_addr);
+
+ dev_info(&pdev->dev, "Null number of ports detected. Board "
+ "reset.\n");
+ retval = 0;
+ goto err;
+ }
+
+ cy_writel(&pt_zfwctrl->board_ctrl.op_system, C_OS_LINUX);
+ cy_writel(&pt_zfwctrl->board_ctrl.dr_version, DRIVER_VERSION);
+
+ /*
+ Early firmware failed to start looking for commands.
+ This enables firmware interrupts for those commands.
+ */
+ cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
+ (1 << 17));
+ cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
+ 0x00030800UL);
+
+ plx_init(pdev, irq, ctl_addr);
+
+ return 0;
+err_rel:
+ release_firmware(fw);
+err:
+ return retval;
}
static int __devinit cy_pci_probe(struct pci_dev *pdev,
@@ -4831,16 +5142,9 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
}
/* Disable interrupts on the PLX before resetting it */
- cy_writew(addr0 + 0x68,
- readw(addr0 + 0x68) & ~0x0900);
+ cy_writew(addr0 + 0x68, readw(addr0 + 0x68) & ~0x0900);
- plx_init(addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent
- fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+ plx_init(pdev, irq, addr0);
mailbox = (u32)readl(&ctl_addr->mail_box_0);
@@ -4881,6 +5185,9 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
cy_writel(addr2 + ID_ADDRESS, 0L);
+ retval = cyz_load_fw(pdev, addr2, addr0, irq);
+ if (retval)
+ goto err_unmap;
/* This must be a Cyclades-8Zo/PCI. The extendable
version will have a different device_id and will
be allocated its maximum number of ports. */
@@ -4957,15 +5264,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
case PLX_9060:
case PLX_9080:
default: /* Old boards, use PLX_9060 */
-
- plx_init(addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent
- fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
-
+ plx_init(pdev, irq, addr0);
cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
break;
}
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c
deleted file mode 100644
index 8ea2bea2b183..000000000000
--- a/drivers/char/decserial.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * sercons.c
- * choose the right serial device at boot time
- *
- * triemer 6-SEP-1998
- * sercons.c is designed to allow the three different kinds
- * of serial devices under the decstation world to co-exist
- * in the same kernel. The idea here is to abstract
- * the pieces of the drivers that are common to this file
- * so that they do not clash at compile time and runtime.
- *
- * HK 16-SEP-1998 v0.002
- * removed the PROM console as this is not a real serial
- * device. Added support for PROM console in drivers/char/tty_io.c
- * instead. Although it may work to enable more than one
- * console device I strongly recommend to use only one.
- */
-
-#include <linux/init.h>
-#include <asm/dec/machtype.h>
-
-#ifdef CONFIG_ZS
-extern int zs_init(void);
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-#ifdef CONFIG_ZS
-extern void zs_serial_console_init(void);
-#endif
-
-#endif
-
-/* rs_init - starts up the serial interface -
- handle normal case of starting up the serial interface */
-
-#ifdef CONFIG_SERIAL
-
-int __init rs_init(void)
-{
-#ifdef CONFIG_ZS
- if (IOASIC)
- return zs_init();
-#endif
- return -ENXIO;
-}
-
-__initcall(rs_init);
-
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/* serial_console_init handles the special case of starting
- * up the console on the serial port
- */
-static int __init decserial_console_init(void)
-{
-#ifdef CONFIG_ZS
- if (IOASIC)
- zs_serial_console_init();
-#endif
- return 0;
-}
-console_initcall(decserial_console_init);
-
-#endif
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index 5b91bc04ea4e..3345641ff904 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -73,9 +73,9 @@ static void drm_ati_free_pcigart_table(void *address, int order)
free_pages((unsigned long)address, order);
}
-int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
+int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
{
- drm_sg_mem_t *entry = dev->sg;
+ struct drm_sg_mem *entry = dev->sg;
unsigned long pages;
int i;
int order;
@@ -122,9 +122,9 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
}
EXPORT_SYMBOL(drm_ati_pcigart_cleanup);
-int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
+int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
{
- drm_sg_mem_t *entry = dev->sg;
+ struct drm_sg_mem *entry = dev->sg;
void *address = NULL;
unsigned long pages;
u32 *pci_gart, page_base, bus_address = 0;
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 089198491f16..2d6f2d0bd02b 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -109,31 +109,31 @@ typedef unsigned int drm_magic_t;
* \note KW: Actually it's illegal to change either for
* backwards-compatibility reasons.
*/
-typedef struct drm_clip_rect {
+struct drm_clip_rect {
unsigned short x1;
unsigned short y1;
unsigned short x2;
unsigned short y2;
-} drm_clip_rect_t;
+};
/**
* Drawable information.
*/
-typedef struct drm_drawable_info {
+struct drm_drawable_info {
unsigned int num_rects;
- drm_clip_rect_t *rects;
-} drm_drawable_info_t;
+ struct drm_clip_rect *rects;
+};
/**
* Texture region,
*/
-typedef struct drm_tex_region {
+struct drm_tex_region {
unsigned char next;
unsigned char prev;
unsigned char in_use;
unsigned char padding;
unsigned int age;
-} drm_tex_region_t;
+};
/**
* Hardware lock.
@@ -142,17 +142,17 @@ typedef struct drm_tex_region {
* processor bus contention on a multiprocessor system, there should not be any
* other data stored in the same cache line.
*/
-typedef struct drm_hw_lock {
+struct drm_hw_lock {
__volatile__ unsigned int lock; /**< lock variable */
char padding[60]; /**< Pad to cache line */
-} drm_hw_lock_t;
+};
/**
* DRM_IOCTL_VERSION ioctl argument type.
*
* \sa drmGetVersion().
*/
-typedef struct drm_version {
+struct drm_version {
int version_major; /**< Major version */
int version_minor; /**< Minor version */
int version_patchlevel; /**< Patch level */
@@ -162,33 +162,33 @@ typedef struct drm_version {
char __user *date; /**< User-space buffer to hold date */
size_t desc_len; /**< Length of desc buffer */
char __user *desc; /**< User-space buffer to hold desc */
-} drm_version_t;
+};
/**
* DRM_IOCTL_GET_UNIQUE ioctl argument type.
*
* \sa drmGetBusid() and drmSetBusId().
*/
-typedef struct drm_unique {
+struct drm_unique {
size_t unique_len; /**< Length of unique */
char __user *unique; /**< Unique name for driver instantiation */
-} drm_unique_t;
+};
-typedef struct drm_list {
+struct drm_list {
int count; /**< Length of user-space structures */
- drm_version_t __user *version;
-} drm_list_t;
+ struct drm_version __user *version;
+};
-typedef struct drm_block {
+struct drm_block {
int unused;
-} drm_block_t;
+};
/**
* DRM_IOCTL_CONTROL ioctl argument type.
*
* \sa drmCtlInstHandler() and drmCtlUninstHandler().
*/
-typedef struct drm_control {
+struct drm_control {
enum {
DRM_ADD_COMMAND,
DRM_RM_COMMAND,
@@ -196,24 +196,24 @@ typedef struct drm_control {
DRM_UNINST_HANDLER
} func;
int irq;
-} drm_control_t;
+};
/**
* Type of memory to map.
*/
-typedef enum drm_map_type {
+enum drm_map_type {
_DRM_FRAME_BUFFER = 0, /**< WC (no caching), no core dump */
_DRM_REGISTERS = 1, /**< no caching, no core dump */
_DRM_SHM = 2, /**< shared, cached */
_DRM_AGP = 3, /**< AGP/GART */
_DRM_SCATTER_GATHER = 4, /**< Scatter/gather memory for PCI DMA */
_DRM_CONSISTENT = 5, /**< Consistent memory for PCI DMA */
-} drm_map_type_t;
+};
/**
* Memory mapping flags.
*/
-typedef enum drm_map_flags {
+enum drm_map_flags {
_DRM_RESTRICTED = 0x01, /**< Cannot be mapped to user-virtual */
_DRM_READ_ONLY = 0x02,
_DRM_LOCKED = 0x04, /**< shared, cached, locked */
@@ -221,12 +221,12 @@ typedef enum drm_map_flags {
_DRM_WRITE_COMBINING = 0x10, /**< use write-combining if available */
_DRM_CONTAINS_LOCK = 0x20, /**< SHM page that contains lock */
_DRM_REMOVABLE = 0x40 /**< Removable mapping */
-} drm_map_flags_t;
+};
-typedef struct drm_ctx_priv_map {
+struct drm_ctx_priv_map {
unsigned int ctx_id; /**< Context requesting private mapping */
void *handle; /**< Handle of map */
-} drm_ctx_priv_map_t;
+};
/**
* DRM_IOCTL_GET_MAP, DRM_IOCTL_ADD_MAP and DRM_IOCTL_RM_MAP ioctls
@@ -234,30 +234,30 @@ typedef struct drm_ctx_priv_map {
*
* \sa drmAddMap().
*/
-typedef struct drm_map {
+struct drm_map {
unsigned long offset; /**< Requested physical address (0 for SAREA)*/
unsigned long size; /**< Requested physical size (bytes) */
- drm_map_type_t type; /**< Type of memory to map */
- drm_map_flags_t flags; /**< Flags */
+ enum drm_map_type type; /**< Type of memory to map */
+ enum drm_map_flags flags; /**< Flags */
void *handle; /**< User-space: "Handle" to pass to mmap() */
/**< Kernel-space: kernel-virtual address */
int mtrr; /**< MTRR slot used */
/* Private data */
-} drm_map_t;
+};
/**
* DRM_IOCTL_GET_CLIENT ioctl argument type.
*/
-typedef struct drm_client {
+struct drm_client {
int idx; /**< Which client desired? */
int auth; /**< Is client authenticated? */
unsigned long pid; /**< Process ID */
unsigned long uid; /**< User ID */
unsigned long magic; /**< Magic */
unsigned long iocs; /**< Ioctl count */
-} drm_client_t;
+};
-typedef enum {
+enum drm_stat_type {
_DRM_STAT_LOCK,
_DRM_STAT_OPENS,
_DRM_STAT_CLOSES,
@@ -275,23 +275,23 @@ typedef enum {
_DRM_STAT_SPECIAL, /**< Special DMA (e.g., priority or polled) */
_DRM_STAT_MISSED /**< Missed DMA opportunity */
/* Add to the *END* of the list */
-} drm_stat_type_t;
+};
/**
* DRM_IOCTL_GET_STATS ioctl argument type.
*/
-typedef struct drm_stats {
+struct drm_stats {
unsigned long count;
struct {
unsigned long value;
- drm_stat_type_t type;
+ enum drm_stat_type type;
} data[15];
-} drm_stats_t;
+};
/**
* Hardware locking flags.
*/
-typedef enum drm_lock_flags {
+enum drm_lock_flags {
_DRM_LOCK_READY = 0x01, /**< Wait until hardware is ready for DMA */
_DRM_LOCK_QUIESCENT = 0x02, /**< Wait until hardware quiescent */
_DRM_LOCK_FLUSH = 0x04, /**< Flush this context's DMA queue first */
@@ -301,17 +301,17 @@ typedef enum drm_lock_flags {
full-screen DGA-like mode. */
_DRM_HALT_ALL_QUEUES = 0x10, /**< Halt all current and future queues */
_DRM_HALT_CUR_QUEUES = 0x20 /**< Halt all current queues */
-} drm_lock_flags_t;
+};
/**
* DRM_IOCTL_LOCK, DRM_IOCTL_UNLOCK and DRM_IOCTL_FINISH ioctl argument type.
*
* \sa drmGetLock() and drmUnlock().
*/
-typedef struct drm_lock {
+struct drm_lock {
int context;
- drm_lock_flags_t flags;
-} drm_lock_t;
+ enum drm_lock_flags flags;
+};
/**
* DMA flags
@@ -321,7 +321,7 @@ typedef struct drm_lock {
*
* \sa drm_dma.
*/
-typedef enum drm_dma_flags {
+enum drm_dma_flags {
/* Flags for DMA buffer dispatch */
_DRM_DMA_BLOCK = 0x01, /**<
* Block until buffer dispatched.
@@ -340,14 +340,14 @@ typedef enum drm_dma_flags {
_DRM_DMA_WAIT = 0x10, /**< Wait for free buffers */
_DRM_DMA_SMALLER_OK = 0x20, /**< Smaller-than-requested buffers OK */
_DRM_DMA_LARGER_OK = 0x40 /**< Larger-than-requested buffers OK */
-} drm_dma_flags_t;
+};
/**
* DRM_IOCTL_ADD_BUFS and DRM_IOCTL_MARK_BUFS ioctl argument type.
*
* \sa drmAddBufs().
*/
-typedef struct drm_buf_desc {
+struct drm_buf_desc {
int count; /**< Number of buffers of this size */
int size; /**< Size in bytes */
int low_mark; /**< Low water mark */
@@ -363,44 +363,44 @@ typedef struct drm_buf_desc {
* Start address of where the AGP buffers are
* in the AGP aperture
*/
-} drm_buf_desc_t;
+};
/**
* DRM_IOCTL_INFO_BUFS ioctl argument type.
*/
-typedef struct drm_buf_info {
+struct drm_buf_info {
int count; /**< Entries in list */
- drm_buf_desc_t __user *list;
-} drm_buf_info_t;
+ struct drm_buf_desc __user *list;
+};
/**
* DRM_IOCTL_FREE_BUFS ioctl argument type.
*/
-typedef struct drm_buf_free {
+struct drm_buf_free {
int count;
int __user *list;
-} drm_buf_free_t;
+};
/**
* Buffer information
*
* \sa drm_buf_map.
*/
-typedef struct drm_buf_pub {
+struct drm_buf_pub {
int idx; /**< Index into the master buffer list */
int total; /**< Buffer size */
int used; /**< Amount of buffer in use (for DMA) */
void __user *address; /**< Address of buffer */
-} drm_buf_pub_t;
+};
/**
* DRM_IOCTL_MAP_BUFS ioctl argument type.
*/
-typedef struct drm_buf_map {
+struct drm_buf_map {
int count; /**< Length of the buffer list */
void __user *virtual; /**< Mmap'd area in user-virtual */
- drm_buf_pub_t __user *list; /**< Buffer information */
-} drm_buf_map_t;
+ struct drm_buf_pub __user *list; /**< Buffer information */
+};
/**
* DRM_IOCTL_DMA ioctl argument type.
@@ -409,48 +409,48 @@ typedef struct drm_buf_map {
*
* \sa drmDMA().
*/
-typedef struct drm_dma {
+struct drm_dma {
int context; /**< Context handle */
int send_count; /**< Number of buffers to send */
int __user *send_indices; /**< List of handles to buffers */
int __user *send_sizes; /**< Lengths of data to send */
- drm_dma_flags_t flags; /**< Flags */
+ enum drm_dma_flags flags; /**< Flags */
int request_count; /**< Number of buffers requested */
int request_size; /**< Desired size for buffers */
int __user *request_indices; /**< Buffer information */
int __user *request_sizes;
int granted_count; /**< Number of buffers granted */
-} drm_dma_t;
+};
-typedef enum {
+enum drm_ctx_flags {
_DRM_CONTEXT_PRESERVED = 0x01,
_DRM_CONTEXT_2DONLY = 0x02
-} drm_ctx_flags_t;
+};
/**
* DRM_IOCTL_ADD_CTX ioctl argument type.
*
* \sa drmCreateContext() and drmDestroyContext().
*/
-typedef struct drm_ctx {
+struct drm_ctx {
drm_context_t handle;
- drm_ctx_flags_t flags;
-} drm_ctx_t;
+ enum drm_ctx_flags flags;
+};
/**
* DRM_IOCTL_RES_CTX ioctl argument type.
*/
-typedef struct drm_ctx_res {
+struct drm_ctx_res {
int count;
- drm_ctx_t __user *contexts;
-} drm_ctx_res_t;
+ struct drm_ctx __user *contexts;
+};
/**
* DRM_IOCTL_ADD_DRAW and DRM_IOCTL_RM_DRAW ioctl argument type.
*/
-typedef struct drm_draw {
+struct drm_draw {
drm_drawable_t handle;
-} drm_draw_t;
+};
/**
* DRM_IOCTL_UPDATE_DRAW ioctl argument type.
@@ -459,52 +459,52 @@ typedef enum {
DRM_DRAWABLE_CLIPRECTS,
} drm_drawable_info_type_t;
-typedef struct drm_update_draw {
+struct drm_update_draw {
drm_drawable_t handle;
unsigned int type;
unsigned int num;
unsigned long long data;
-} drm_update_draw_t;
+};
/**
* DRM_IOCTL_GET_MAGIC and DRM_IOCTL_AUTH_MAGIC ioctl argument type.
*/
-typedef struct drm_auth {
+struct drm_auth {
drm_magic_t magic;
-} drm_auth_t;
+};
/**
* DRM_IOCTL_IRQ_BUSID ioctl argument type.
*
* \sa drmGetInterruptFromBusID().
*/
-typedef struct drm_irq_busid {
+struct drm_irq_busid {
int irq; /**< IRQ number */
int busnum; /**< bus number */
int devnum; /**< device number */
int funcnum; /**< function number */
-} drm_irq_busid_t;
+};
-typedef enum {
+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_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */
_DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */
_DRM_VBLANK_SIGNAL = 0x40000000 /**< Send signal instead of blocking */
-} drm_vblank_seq_type_t;
+};
#define _DRM_VBLANK_TYPES_MASK (_DRM_VBLANK_ABSOLUTE | _DRM_VBLANK_RELATIVE)
#define _DRM_VBLANK_FLAGS_MASK (_DRM_VBLANK_SIGNAL | _DRM_VBLANK_SECONDARY | \
_DRM_VBLANK_NEXTONMISS)
struct drm_wait_vblank_request {
- drm_vblank_seq_type_t type;
+ enum drm_vblank_seq_type type;
unsigned int sequence;
unsigned long signal;
};
struct drm_wait_vblank_reply {
- drm_vblank_seq_type_t type;
+ enum drm_vblank_seq_type type;
unsigned int sequence;
long tval_sec;
long tval_usec;
@@ -515,41 +515,41 @@ struct drm_wait_vblank_reply {
*
* \sa drmWaitVBlank().
*/
-typedef union drm_wait_vblank {
+union drm_wait_vblank {
struct drm_wait_vblank_request request;
struct drm_wait_vblank_reply reply;
-} drm_wait_vblank_t;
+};
/**
* DRM_IOCTL_AGP_ENABLE ioctl argument type.
*
* \sa drmAgpEnable().
*/
-typedef struct drm_agp_mode {
+struct drm_agp_mode {
unsigned long mode; /**< AGP mode */
-} drm_agp_mode_t;
+};
/**
* DRM_IOCTL_AGP_ALLOC and DRM_IOCTL_AGP_FREE ioctls argument type.
*
* \sa drmAgpAlloc() and drmAgpFree().
*/
-typedef struct drm_agp_buffer {
+struct drm_agp_buffer {
unsigned long size; /**< In bytes -- will round to page boundary */
unsigned long handle; /**< Used for binding / unbinding */
unsigned long type; /**< Type of memory to allocate */
unsigned long physical; /**< Physical used by i810 */
-} drm_agp_buffer_t;
+};
/**
* DRM_IOCTL_AGP_BIND and DRM_IOCTL_AGP_UNBIND ioctls argument type.
*
* \sa drmAgpBind() and drmAgpUnbind().
*/
-typedef struct drm_agp_binding {
+struct drm_agp_binding {
unsigned long handle; /**< From drm_agp_buffer */
unsigned long offset; /**< In bytes -- will round to page boundary */
-} drm_agp_binding_t;
+};
/**
* DRM_IOCTL_AGP_INFO ioctl argument type.
@@ -558,7 +558,7 @@ typedef struct drm_agp_binding {
* drmAgpBase(), drmAgpSize(), drmAgpMemoryUsed(), drmAgpMemoryAvail(),
* drmAgpVendorId() and drmAgpDeviceId().
*/
-typedef struct drm_agp_info {
+struct drm_agp_info {
int agp_version_major;
int agp_version_minor;
unsigned long mode;
@@ -570,25 +570,25 @@ typedef struct drm_agp_info {
/* PCI information */
unsigned short id_vendor;
unsigned short id_device;
-} drm_agp_info_t;
+};
/**
* DRM_IOCTL_SG_ALLOC ioctl argument type.
*/
-typedef struct drm_scatter_gather {
+struct drm_scatter_gather {
unsigned long size; /**< In bytes -- will round to page boundary */
unsigned long handle; /**< Used for mapping / unmapping */
-} drm_scatter_gather_t;
+};
/**
* DRM_IOCTL_SET_VERSION ioctl argument type.
*/
-typedef struct drm_set_version {
+struct drm_set_version {
int drm_di_major;
int drm_di_minor;
int drm_dd_major;
int drm_dd_minor;
-} drm_set_version_t;
+};
#define DRM_IOCTL_BASE 'd'
#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr)
@@ -596,61 +596,61 @@ typedef struct drm_set_version {
#define DRM_IOW(nr,type) _IOW(DRM_IOCTL_BASE,nr,type)
#define DRM_IOWR(nr,type) _IOWR(DRM_IOCTL_BASE,nr,type)
-#define DRM_IOCTL_VERSION DRM_IOWR(0x00, drm_version_t)
-#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, drm_unique_t)
-#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, drm_auth_t)
-#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, drm_irq_busid_t)
-#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, drm_map_t)
-#define DRM_IOCTL_GET_CLIENT DRM_IOWR(0x05, drm_client_t)
-#define DRM_IOCTL_GET_STATS DRM_IOR( 0x06, drm_stats_t)
-#define DRM_IOCTL_SET_VERSION DRM_IOWR(0x07, drm_set_version_t)
-
-#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, drm_unique_t)
-#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, drm_auth_t)
-#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, drm_block_t)
-#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, drm_block_t)
-#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, drm_control_t)
-#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, drm_map_t)
-#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, drm_buf_desc_t)
-#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, drm_buf_desc_t)
-#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, drm_buf_info_t)
-#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, drm_buf_map_t)
-#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, drm_buf_free_t)
-
-#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, drm_map_t)
-
-#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, drm_ctx_priv_map_t)
-#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, drm_ctx_priv_map_t)
-
-#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, drm_ctx_t)
-#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, drm_ctx_t)
-#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, drm_ctx_t)
-#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, drm_ctx_t)
-#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, drm_ctx_t)
-#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, drm_ctx_t)
-#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, drm_ctx_res_t)
-#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, drm_draw_t)
-#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, drm_draw_t)
-#define DRM_IOCTL_DMA DRM_IOWR(0x29, drm_dma_t)
-#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, drm_lock_t)
-#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, drm_lock_t)
-#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, drm_lock_t)
+#define DRM_IOCTL_VERSION DRM_IOWR(0x00, struct drm_version)
+#define DRM_IOCTL_GET_UNIQUE DRM_IOWR(0x01, struct drm_unique)
+#define DRM_IOCTL_GET_MAGIC DRM_IOR( 0x02, struct drm_auth)
+#define DRM_IOCTL_IRQ_BUSID DRM_IOWR(0x03, struct drm_irq_busid)
+#define DRM_IOCTL_GET_MAP DRM_IOWR(0x04, struct drm_map)
+#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_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique)
+#define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth)
+#define DRM_IOCTL_BLOCK DRM_IOWR(0x12, struct drm_block)
+#define DRM_IOCTL_UNBLOCK DRM_IOWR(0x13, struct drm_block)
+#define DRM_IOCTL_CONTROL DRM_IOW( 0x14, struct drm_control)
+#define DRM_IOCTL_ADD_MAP DRM_IOWR(0x15, struct drm_map)
+#define DRM_IOCTL_ADD_BUFS DRM_IOWR(0x16, struct drm_buf_desc)
+#define DRM_IOCTL_MARK_BUFS DRM_IOW( 0x17, struct drm_buf_desc)
+#define DRM_IOCTL_INFO_BUFS DRM_IOWR(0x18, struct drm_buf_info)
+#define DRM_IOCTL_MAP_BUFS DRM_IOWR(0x19, struct drm_buf_map)
+#define DRM_IOCTL_FREE_BUFS DRM_IOW( 0x1a, struct drm_buf_free)
+
+#define DRM_IOCTL_RM_MAP DRM_IOW( 0x1b, struct drm_map)
+
+#define DRM_IOCTL_SET_SAREA_CTX DRM_IOW( 0x1c, struct drm_ctx_priv_map)
+#define DRM_IOCTL_GET_SAREA_CTX DRM_IOWR(0x1d, struct drm_ctx_priv_map)
+
+#define DRM_IOCTL_ADD_CTX DRM_IOWR(0x20, struct drm_ctx)
+#define DRM_IOCTL_RM_CTX DRM_IOWR(0x21, struct drm_ctx)
+#define DRM_IOCTL_MOD_CTX DRM_IOW( 0x22, struct drm_ctx)
+#define DRM_IOCTL_GET_CTX DRM_IOWR(0x23, struct drm_ctx)
+#define DRM_IOCTL_SWITCH_CTX DRM_IOW( 0x24, struct drm_ctx)
+#define DRM_IOCTL_NEW_CTX DRM_IOW( 0x25, struct drm_ctx)
+#define DRM_IOCTL_RES_CTX DRM_IOWR(0x26, struct drm_ctx_res)
+#define DRM_IOCTL_ADD_DRAW DRM_IOWR(0x27, struct drm_draw)
+#define DRM_IOCTL_RM_DRAW DRM_IOWR(0x28, struct drm_draw)
+#define DRM_IOCTL_DMA DRM_IOWR(0x29, struct drm_dma)
+#define DRM_IOCTL_LOCK DRM_IOW( 0x2a, struct drm_lock)
+#define DRM_IOCTL_UNLOCK DRM_IOW( 0x2b, struct drm_lock)
+#define DRM_IOCTL_FINISH DRM_IOW( 0x2c, struct drm_lock)
#define DRM_IOCTL_AGP_ACQUIRE DRM_IO( 0x30)
#define DRM_IOCTL_AGP_RELEASE DRM_IO( 0x31)
-#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, drm_agp_mode_t)
-#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, drm_agp_info_t)
-#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, drm_agp_buffer_t)
-#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, drm_agp_buffer_t)
-#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, drm_agp_binding_t)
-#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, drm_agp_binding_t)
+#define DRM_IOCTL_AGP_ENABLE DRM_IOW( 0x32, struct drm_agp_mode)
+#define DRM_IOCTL_AGP_INFO DRM_IOR( 0x33, struct drm_agp_info)
+#define DRM_IOCTL_AGP_ALLOC DRM_IOWR(0x34, struct drm_agp_buffer)
+#define DRM_IOCTL_AGP_FREE DRM_IOW( 0x35, struct drm_agp_buffer)
+#define DRM_IOCTL_AGP_BIND DRM_IOW( 0x36, struct drm_agp_binding)
+#define DRM_IOCTL_AGP_UNBIND DRM_IOW( 0x37, struct drm_agp_binding)
-#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, drm_scatter_gather_t)
-#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, drm_scatter_gather_t)
+#define DRM_IOCTL_SG_ALLOC DRM_IOW( 0x38, struct drm_scatter_gather)
+#define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, struct drm_scatter_gather)
-#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, drm_wait_vblank_t)
+#define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank)
-#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, drm_update_draw_t)
+#define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw)
/**
* Device specific ioctls should only be in their respective headers
@@ -663,4 +663,49 @@ typedef struct drm_set_version {
#define DRM_COMMAND_BASE 0x40
#define DRM_COMMAND_END 0xA0
+/* typedef area */
+#ifndef __KERNEL__
+typedef struct drm_clip_rect drm_clip_rect_t;
+typedef struct drm_drawable_info drm_drawable_info_t;
+typedef struct drm_tex_region drm_tex_region_t;
+typedef struct drm_hw_lock drm_hw_lock_t;
+typedef struct drm_version drm_version_t;
+typedef struct drm_unique drm_unique_t;
+typedef struct drm_list drm_list_t;
+typedef struct drm_block drm_block_t;
+typedef struct drm_control drm_control_t;
+typedef enum drm_map_type drm_map_type_t;
+typedef enum drm_map_flags drm_map_flags_t;
+typedef struct drm_ctx_priv_map drm_ctx_priv_map_t;
+typedef struct drm_map drm_map_t;
+typedef struct drm_client drm_client_t;
+typedef enum drm_stat_type drm_stat_type_t;
+typedef struct drm_stats drm_stats_t;
+typedef enum drm_lock_flags drm_lock_flags_t;
+typedef struct drm_lock drm_lock_t;
+typedef enum drm_dma_flags drm_dma_flags_t;
+typedef struct drm_buf_desc drm_buf_desc_t;
+typedef struct drm_buf_info drm_buf_info_t;
+typedef struct drm_buf_free drm_buf_free_t;
+typedef struct drm_buf_pub drm_buf_pub_t;
+typedef struct drm_buf_map drm_buf_map_t;
+typedef struct drm_dma drm_dma_t;
+typedef union drm_wait_vblank drm_wait_vblank_t;
+typedef struct drm_agp_mode drm_agp_mode_t;
+typedef enum drm_ctx_flags drm_ctx_flags_t;
+typedef struct drm_ctx drm_ctx_t;
+typedef struct drm_ctx_res drm_ctx_res_t;
+typedef struct drm_draw drm_draw_t;
+typedef struct drm_update_draw drm_update_draw_t;
+typedef struct drm_auth drm_auth_t;
+typedef struct drm_irq_busid drm_irq_busid_t;
+typedef enum drm_vblank_seq_type drm_vblank_seq_type_t;
+
+typedef struct drm_agp_buffer drm_agp_buffer_t;
+typedef struct drm_agp_binding drm_agp_binding_t;
+typedef struct drm_agp_info drm_agp_info_t;
+typedef struct drm_scatter_gather drm_scatter_gather_t;
+typedef struct drm_set_version drm_set_version_t;
+#endif
+
#endif
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index d494315752a2..0df87fc3dcb2 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -75,6 +75,8 @@
#include <asm/pgalloc.h>
#include "drm.h"
+#include <linux/idr.h>
+
#define __OS_HAS_AGP (defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)))
#define __OS_HAS_MTRR (defined(CONFIG_MTRR))
@@ -274,32 +276,23 @@ typedef struct drm_ioctl_desc {
int flags;
} drm_ioctl_desc_t;
-typedef struct drm_devstate {
- pid_t owner; /**< X server pid holding x_lock */
-} drm_devstate_t;
-
-typedef struct drm_magic_entry {
- drm_hash_item_t hash_item;
+struct drm_magic_entry {
struct list_head head;
+ struct drm_hash_item hash_item;
struct drm_file *priv;
struct drm_magic_entry *next;
-} drm_magic_entry_t;
-
-typedef struct drm_magic_head {
- struct drm_magic_entry *head;
- struct drm_magic_entry *tail;
-} drm_magic_head_t;
+};
-typedef struct drm_vma_entry {
+struct drm_vma_entry {
+ struct list_head head;
struct vm_area_struct *vma;
- struct drm_vma_entry *next;
pid_t pid;
-} drm_vma_entry_t;
+};
/**
* DMA buffer.
*/
-typedef struct drm_buf {
+struct drm_buf {
int idx; /**< Index into master buflist */
int total; /**< Buffer size */
int order; /**< log-base-2(total) */
@@ -325,30 +318,30 @@ typedef struct drm_buf {
int dev_priv_size; /**< Size of buffer private storage */
void *dev_private; /**< Per-buffer private storage */
-} drm_buf_t;
+};
/** bufs is one longer than it has to be */
-typedef struct drm_waitlist {
+struct drm_waitlist {
int count; /**< Number of possible buffers */
- drm_buf_t **bufs; /**< List of pointers to buffers */
- drm_buf_t **rp; /**< Read pointer */
- drm_buf_t **wp; /**< Write pointer */
- drm_buf_t **end; /**< End pointer */
+ struct drm_buf **bufs; /**< List of pointers to buffers */
+ struct drm_buf **rp; /**< Read pointer */
+ struct drm_buf **wp; /**< Write pointer */
+ struct drm_buf **end; /**< End pointer */
spinlock_t read_lock;
spinlock_t write_lock;
-} drm_waitlist_t;
+};
-typedef struct drm_freelist {
+struct drm_freelist {
int initialized; /**< Freelist in use */
atomic_t count; /**< Number of free buffers */
- drm_buf_t *next; /**< End pointer */
+ struct drm_buf *next; /**< End pointer */
wait_queue_head_t waiting; /**< Processes waiting on free bufs */
int low_mark; /**< Low water mark */
int high_mark; /**< High water mark */
atomic_t wfh; /**< If waiting for high mark */
spinlock_t lock;
-} drm_freelist_t;
+};
typedef struct drm_dma_handle {
dma_addr_t busaddr;
@@ -359,19 +352,19 @@ typedef struct drm_dma_handle {
/**
* Buffer entry. There is one of this for each buffer size order.
*/
-typedef struct drm_buf_entry {
+struct drm_buf_entry {
int buf_size; /**< size */
int buf_count; /**< number of buffers */
- drm_buf_t *buflist; /**< buffer list */
+ struct drm_buf *buflist; /**< buffer list */
int seg_count;
int page_order;
- drm_dma_handle_t **seglist;
+ struct drm_dma_handle **seglist;
- drm_freelist_t freelist;
-} drm_buf_entry_t;
+ struct drm_freelist freelist;
+};
/** File private data */
-typedef struct drm_file {
+struct drm_file {
int authenticated;
int master;
int minor;
@@ -379,16 +372,15 @@ typedef struct drm_file {
uid_t uid;
drm_magic_t magic;
unsigned long ioctl_count;
- struct drm_file *next;
- struct drm_file *prev;
+ struct list_head lhead;
struct drm_head *head;
int remove_auth_on_close;
unsigned long lock_count;
void *driver_priv;
-} drm_file_t;
+};
/** Wait queue */
-typedef struct drm_queue {
+struct drm_queue {
atomic_t use_count; /**< Outstanding uses (+1) */
atomic_t finalization; /**< Finalization in progress */
atomic_t block_count; /**< Count of processes waiting */
@@ -401,16 +393,16 @@ typedef struct drm_queue {
atomic_t total_flushed; /**< Total flushes statistic */
atomic_t total_locks; /**< Total locks statistics */
#endif
- drm_ctx_flags_t flags; /**< Context preserving and 2D-only */
- drm_waitlist_t waitlist; /**< Pending buffers */
+ enum drm_ctx_flags flags; /**< Context preserving and 2D-only */
+ struct drm_waitlist waitlist; /**< Pending buffers */
wait_queue_head_t flush_queue; /**< Processes waiting until flush */
-} drm_queue_t;
+};
/**
* Lock data.
*/
-typedef struct drm_lock_data {
- drm_hw_lock_t *hw_lock; /**< Hardware lock */
+struct drm_lock_data {
+ struct drm_hw_lock *hw_lock; /**< Hardware lock */
struct file *filp; /**< File descr of lock holder (0=kernel) */
wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */
@@ -418,16 +410,16 @@ typedef struct drm_lock_data {
uint32_t kernel_waiters;
uint32_t user_waiters;
int idle_has_lock;
-} drm_lock_data_t;
+};
/**
* DMA data.
*/
-typedef struct drm_device_dma {
+struct drm_device_dma {
- drm_buf_entry_t bufs[DRM_MAX_ORDER + 1]; /**< buffers, grouped by their size order */
+ struct drm_buf_entry bufs[DRM_MAX_ORDER + 1]; /**< buffers, grouped by their size order */
int buf_count; /**< total number of buffers */
- drm_buf_t **buflist; /**< Vector of pointers into drm_device_dma::bufs */
+ struct drm_buf **buflist; /**< Vector of pointers into drm_device_dma::bufs */
int seg_count;
int page_count; /**< number of pages */
unsigned long *pagelist; /**< page list */
@@ -439,28 +431,27 @@ typedef struct drm_device_dma {
_DRM_DMA_USE_PCI_RO = 0x08
} flags;
-} drm_device_dma_t;
+};
/**
* AGP memory entry. Stored as a doubly linked list.
*/
-typedef struct drm_agp_mem {
+struct drm_agp_mem {
unsigned long handle; /**< handle */
DRM_AGP_MEM *memory;
unsigned long bound; /**< address */
int pages;
- struct drm_agp_mem *prev; /**< previous entry */
- struct drm_agp_mem *next; /**< next entry */
-} drm_agp_mem_t;
+ struct list_head head;
+};
/**
* AGP data.
*
* \sa drm_agp_init() and drm_device::agp.
*/
-typedef struct drm_agp_head {
+struct drm_agp_head {
DRM_AGP_KERN agp_info; /**< AGP device information */
- drm_agp_mem_t *memory; /**< memory entries */
+ struct list_head memory;
unsigned long mode; /**< AGP mode */
struct agp_bridge_data *bridge;
int enabled; /**< whether the AGP bus as been enabled */
@@ -469,51 +460,51 @@ typedef struct drm_agp_head {
int agp_mtrr;
int cant_use_aperture;
unsigned long page_mask;
-} drm_agp_head_t;
+};
/**
* Scatter-gather memory.
*/
-typedef struct drm_sg_mem {
+struct drm_sg_mem {
unsigned long handle;
void *virtual;
int pages;
struct page **pagelist;
dma_addr_t *busaddr;
-} drm_sg_mem_t;
+};
-typedef struct drm_sigdata {
+struct drm_sigdata {
int context;
- drm_hw_lock_t *lock;
-} drm_sigdata_t;
+ struct drm_hw_lock *lock;
+};
/**
* Mappings list
*/
-typedef struct drm_map_list {
+struct drm_map_list {
struct list_head head; /**< list head */
- drm_hash_item_t hash;
- drm_map_t *map; /**< mapping */
+ struct drm_hash_item hash;
+ struct drm_map *map; /**< mapping */
unsigned int user_token;
-} drm_map_list_t;
+};
-typedef drm_map_t drm_local_map_t;
+typedef struct drm_map drm_local_map_t;
/**
* Context handle list
*/
-typedef struct drm_ctx_list {
+struct drm_ctx_list {
struct list_head head; /**< list head */
drm_context_t handle; /**< context handle */
- drm_file_t *tag; /**< associated fd private data */
-} drm_ctx_list_t;
+ struct drm_file *tag; /**< associated fd private data */
+};
-typedef struct drm_vbl_sig {
+struct drm_vbl_sig {
struct list_head head;
unsigned int sequence;
struct siginfo info;
struct task_struct *task;
-} drm_vbl_sig_t;
+};
/* location of GART table */
#define DRM_ATI_GART_MAIN 1
@@ -523,19 +514,19 @@ typedef struct drm_vbl_sig {
#define DRM_ATI_GART_PCIE 2
#define DRM_ATI_GART_IGP 3
-typedef struct ati_pcigart_info {
+struct drm_ati_pcigart_info {
int gart_table_location;
int gart_reg_if;
void *addr;
dma_addr_t bus_addr;
drm_local_map_t mapping;
int table_size;
-} drm_ati_pcigart_info;
+};
/*
* Generic memory manager structs
*/
-typedef struct drm_mm_node {
+struct drm_mm_node {
struct list_head fl_entry;
struct list_head ml_entry;
int free;
@@ -543,12 +534,12 @@ typedef struct drm_mm_node {
unsigned long size;
struct drm_mm *mm;
void *private;
-} drm_mm_node_t;
+};
-typedef struct drm_mm {
+struct drm_mm {
struct list_head fl_entry;
struct list_head ml_entry;
-} drm_mm_t;
+};
/**
* DRM driver structure. This structure represent the common code for
@@ -560,21 +551,21 @@ struct drm_device;
struct drm_driver {
int (*load) (struct drm_device *, unsigned long flags);
int (*firstopen) (struct drm_device *);
- int (*open) (struct drm_device *, drm_file_t *);
+ int (*open) (struct drm_device *, struct drm_file *);
void (*preclose) (struct drm_device *, struct file * filp);
- void (*postclose) (struct drm_device *, drm_file_t *);
+ void (*postclose) (struct drm_device *, struct drm_file *);
void (*lastclose) (struct drm_device *);
int (*unload) (struct drm_device *);
int (*dma_ioctl) (DRM_IOCTL_ARGS);
void (*dma_ready) (struct drm_device *);
int (*dma_quiescent) (struct drm_device *);
- int (*context_ctor) (struct drm_device * dev, int context);
- int (*context_dtor) (struct drm_device * dev, int context);
- int (*kernel_context_switch) (struct drm_device * dev, int old,
+ int (*context_ctor) (struct drm_device *dev, int context);
+ 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);
+ 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);
/**
@@ -588,22 +579,23 @@ struct drm_driver {
* card is absolutely \b not AGP (return of 0), absolutely \b is AGP
* (return of 1), or may or may not be AGP (return of 2).
*/
- int (*device_is_agp) (struct drm_device * dev);
+ int (*device_is_agp) (struct drm_device *dev);
/* these have to be filled in */
irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
- void (*irq_preinstall) (struct drm_device * dev);
- void (*irq_postinstall) (struct drm_device * dev);
- void (*irq_uninstall) (struct drm_device * dev);
- void (*reclaim_buffers) (struct drm_device * dev, struct file * filp);
+ void (*irq_preinstall) (struct drm_device *dev);
+ void (*irq_postinstall) (struct drm_device *dev);
+ void (*irq_uninstall) (struct drm_device *dev);
+ void (*reclaim_buffers) (struct drm_device *dev, struct file * filp);
void (*reclaim_buffers_locked) (struct drm_device *dev,
struct file *filp);
void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
struct file * filp);
- unsigned long (*get_map_ofs) (drm_map_t * map);
- unsigned long (*get_reg_ofs) (struct drm_device * dev);
- void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
+ unsigned long (*get_map_ofs) (struct drm_map * map);
+ unsigned long (*get_reg_ofs) (struct drm_device *dev);
+ void (*set_version) (struct drm_device *dev,
+ struct drm_set_version *sv);
int major;
int minor;
@@ -625,19 +617,19 @@ struct drm_driver {
* that may contain multiple heads. Embed one per head of these in the
* private drm_device structure.
*/
-typedef struct drm_head {
+struct drm_head {
int minor; /**< Minor device number */
struct drm_device *dev;
struct proc_dir_entry *dev_root; /**< proc directory entry */
dev_t device; /**< Device number for mknod */
struct class_device *dev_class;
-} drm_head_t;
+};
/**
* DRM device structure. This structure represent a complete card that
* may contain multiple heads.
*/
-typedef struct drm_device {
+struct drm_device {
char *unique; /**< Unique identifier: e.g., busid */
int unique_len; /**< Length of unique field */
char *devname; /**< For /proc/interrupts */
@@ -663,35 +655,33 @@ typedef struct drm_device {
/** \name Performance counters */
/*@{ */
unsigned long counters;
- drm_stat_type_t types[15];
+ enum drm_stat_type types[15];
atomic_t counts[15];
/*@} */
/** \name Authentication */
/*@{ */
- drm_file_t *file_first; /**< file list head */
- drm_file_t *file_last; /**< file list tail */
- drm_open_hash_t magiclist; /**< magic hash table */
+ struct list_head filelist;
+ struct drm_open_hash magiclist; /**< magic hash table */
struct list_head magicfree;
/*@} */
/** \name Memory management */
/*@{ */
- drm_map_list_t *maplist; /**< Linked list of regions */
+ struct list_head maplist; /**< Linked list of regions */
int map_count; /**< Number of mappable regions */
- drm_open_hash_t map_hash; /**< User token hash table for maps */
+ struct drm_open_hash map_hash; /**< User token hash table for maps */
/** \name Context handle management */
/*@{ */
- drm_ctx_list_t *ctxlist; /**< Linked list of context handles */
+ struct list_head ctxlist; /**< Linked list of context handles */
int ctx_count; /**< Number of context handles */
struct mutex ctxlist_mutex; /**< For ctxlist */
- drm_map_t **context_sareas; /**< per-context SAREA's */
- int max_context;
+ struct idr ctx_idr;
- drm_vma_entry_t *vmalist; /**< List of vmas (for debugging) */
- drm_lock_data_t lock; /**< Information on hardware lock */
+ struct list_head vmalist; /**< List of vmas (for debugging) */
+ struct drm_lock_data lock; /**< Information on hardware lock */
/*@} */
/** \name DMA queues (contexts) */
@@ -699,8 +689,8 @@ typedef struct drm_device {
int queue_count; /**< Number of active DMA queues */
int queue_reserved; /**< Number of reserved DMA queues */
int queue_slots; /**< Actual length of queuelist */
- drm_queue_t **queuelist; /**< Vector of pointers to DMA queues */
- drm_device_dma_t *dma; /**< Optional pointer for DMA support */
+ struct drm_queue **queuelist; /**< Vector of pointers to DMA queues */
+ struct drm_device_dma *dma; /**< Optional pointer for DMA support */
/*@} */
/** \name Context support */
@@ -725,8 +715,8 @@ typedef struct drm_device {
atomic_t vbl_received;
atomic_t vbl_received2; /**< number of secondary VBLANK interrupts */
spinlock_t vbl_lock;
- drm_vbl_sig_t vbl_sigs; /**< signal list to send on VBLANK */
- drm_vbl_sig_t vbl_sigs2; /**< signals to send on secondary VBLANK */
+ 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;
spinlock_t tasklet_lock; /**< For drm_locked_tasklet */
void (*locked_tasklet_func)(struct drm_device *dev);
@@ -739,7 +729,7 @@ typedef struct drm_device {
wait_queue_head_t buf_readers; /**< Processes waiting to read */
wait_queue_head_t buf_writers; /**< Processes waiting to ctx switch */
- drm_agp_head_t *agp; /**< AGP data */
+ struct drm_agp_head *agp; /**< AGP data */
struct pci_dev *pdev; /**< PCI device structure */
int pci_vendor; /**< PCI vendor id */
@@ -747,26 +737,23 @@ typedef struct drm_device {
#ifdef __alpha__
struct pci_controller *hose;
#endif
- drm_sg_mem_t *sg; /**< Scatter gather memory */
+ struct drm_sg_mem *sg; /**< Scatter gather memory */
unsigned long *ctx_bitmap; /**< context bitmap */
void *dev_private; /**< device private data */
- drm_sigdata_t sigdata; /**< For block_all_signals */
+ struct drm_sigdata sigdata; /**< For block_all_signals */
sigset_t sigmask;
struct drm_driver *driver;
drm_local_map_t *agp_buffer_map;
unsigned int agp_buffer_token;
- drm_head_t primary; /**< primary screen head */
+ struct drm_head primary; /**< primary screen head */
/** \name Drawable information */
/*@{ */
spinlock_t drw_lock;
- unsigned int drw_bitfield_length;
- u32 *drw_bitfield;
- unsigned int drw_info_length;
- drm_drawable_info_t **drw_info;
+ struct idr drw_idr;
/*@} */
-} drm_device_t;
+};
static __inline__ int drm_core_check_feature(struct drm_device *dev,
int feature)
@@ -838,7 +825,7 @@ extern int drm_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern long drm_compat_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_lastclose(drm_device_t *dev);
+extern int drm_lastclose(struct drm_device *dev);
/* Device support (drm_fops.h) */
extern int drm_open(struct inode *inode, struct file *filp);
@@ -857,7 +844,7 @@ extern int drm_mem_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type);
+extern DRM_AGP_MEM *drm_alloc_agp(struct drm_device *dev, int pages, u32 type);
extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
extern int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
extern int drm_unbind_agp(DRM_AGP_MEM * handle);
@@ -896,9 +883,9 @@ extern int drm_newctx(struct inode *inode, struct file *filp,
extern int drm_rmctx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_ctxbitmap_init(drm_device_t * dev);
-extern void drm_ctxbitmap_cleanup(drm_device_t * dev);
-extern void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle);
+extern int drm_ctxbitmap_init(struct drm_device *dev);
+extern void drm_ctxbitmap_cleanup(struct drm_device *dev);
+extern void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle);
extern int drm_setsareactx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
@@ -912,8 +899,9 @@ extern int drm_rmdraw(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_update_drawable_info(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev,
+extern struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev,
drm_drawable_t id);
+extern void drm_drawable_free_all(struct drm_device *dev);
/* Authentication IOCTL support (drm_auth.h) */
extern int drm_getmagic(struct inode *inode, struct file *filp,
@@ -926,10 +914,10 @@ extern int drm_lock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context);
-extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context);
-extern void drm_idlelock_take(drm_lock_data_t *lock_data);
-extern void drm_idlelock_release(drm_lock_data_t *lock_data);
+extern int drm_lock_take(struct drm_lock_data *lock_data, unsigned int context);
+extern int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context);
+extern void drm_idlelock_take(struct drm_lock_data *lock_data);
+extern void drm_idlelock_release(struct drm_lock_data *lock_data);
/*
* These are exported to drivers so that they can implement fencing using
@@ -940,15 +928,15 @@ extern int drm_i_have_hw_lock(struct file *filp);
extern int drm_kernel_take_hw_lock(struct file *filp);
/* Buffer management support (drm_bufs.h) */
-extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request);
-extern int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request);
-extern int drm_addmap(drm_device_t * dev, unsigned int offset,
- unsigned int size, drm_map_type_t type,
- drm_map_flags_t flags, drm_local_map_t ** map_ptr);
+extern int drm_addbufs_agp(struct drm_device *dev, struct drm_buf_desc * request);
+extern int drm_addbufs_pci(struct drm_device *dev, struct drm_buf_desc * request);
+extern int drm_addmap(struct drm_device *dev, unsigned int offset,
+ unsigned int size, enum drm_map_type type,
+ enum drm_map_flags flags, drm_local_map_t ** map_ptr);
extern int drm_addmap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_rmmap(drm_device_t * dev, drm_local_map_t * map);
-extern int drm_rmmap_locked(drm_device_t * dev, drm_local_map_t * map);
+extern int drm_rmmap(struct drm_device *dev, drm_local_map_t * map);
+extern int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t * map);
extern int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
@@ -963,56 +951,56 @@ extern int drm_freebufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_mapbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern unsigned long drm_get_resource_start(drm_device_t * dev,
+extern unsigned long drm_get_resource_start(struct drm_device *dev,
unsigned int resource);
-extern unsigned long drm_get_resource_len(drm_device_t * dev,
+extern unsigned long drm_get_resource_len(struct drm_device *dev,
unsigned int resource);
/* DMA support (drm_dma.h) */
-extern int drm_dma_setup(drm_device_t * dev);
-extern void drm_dma_takedown(drm_device_t * dev);
-extern void drm_free_buffer(drm_device_t * dev, drm_buf_t * buf);
-extern void drm_core_reclaim_buffers(drm_device_t * dev, struct file *filp);
+extern int drm_dma_setup(struct drm_device *dev);
+extern void drm_dma_takedown(struct drm_device *dev);
+extern void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf);
+extern void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp);
/* IRQ support (drm_irq.h) */
extern int drm_control(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern irqreturn_t drm_irq_handler(DRM_IRQ_ARGS);
-extern int drm_irq_uninstall(drm_device_t * dev);
-extern void drm_driver_irq_preinstall(drm_device_t * dev);
-extern void drm_driver_irq_postinstall(drm_device_t * dev);
-extern void drm_driver_irq_uninstall(drm_device_t * dev);
+extern int drm_irq_uninstall(struct drm_device *dev);
+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 inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_vblank_wait(drm_device_t * dev, unsigned int *vbl_seq);
-extern void drm_vbl_send_signals(drm_device_t * dev);
-extern void drm_locked_tasklet(drm_device_t *dev, void(*func)(drm_device_t*));
+extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq);
+extern void drm_vbl_send_signals(struct drm_device *dev);
+extern void drm_locked_tasklet(struct drm_device *dev, void(*func)(struct drm_device*));
/* AGP/GART support (drm_agpsupport.h) */
-extern drm_agp_head_t *drm_agp_init(drm_device_t * dev);
-extern int drm_agp_acquire(drm_device_t * dev);
+extern struct drm_agp_head *drm_agp_init(struct drm_device *dev);
+extern int drm_agp_acquire(struct drm_device *dev);
extern int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_release(drm_device_t * dev);
+extern int drm_agp_release(struct drm_device *dev);
extern int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_enable(drm_device_t * dev, drm_agp_mode_t mode);
+extern int drm_agp_enable(struct drm_device *dev, struct drm_agp_mode mode);
extern int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_info(drm_device_t * dev, drm_agp_info_t * info);
+extern int drm_agp_info(struct drm_device *dev, struct drm_agp_info * info);
extern int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request);
+extern int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request);
extern int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request);
+extern int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request);
extern int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request);
+extern int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request);
extern int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_agp_bind(drm_device_t *dev, drm_agp_binding_t *request);
+extern int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request);
extern int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern DRM_AGP_MEM *drm_agp_allocate_memory(struct agp_bridge_data *bridge,
@@ -1024,16 +1012,18 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM * handle);
/* Stub support (drm_stub.h) */
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver);
-extern int drm_put_dev(drm_device_t * dev);
-extern int drm_put_head(drm_head_t * head);
+extern int drm_put_dev(struct drm_device *dev);
+extern int drm_put_head(struct drm_head *head);
extern unsigned int drm_debug;
extern unsigned int drm_cards_limit;
-extern drm_head_t **drm_heads;
+extern struct drm_head **drm_heads;
extern struct class *drm_class;
extern struct proc_dir_entry *drm_proc_root;
+extern drm_local_map_t *drm_getsarea(struct drm_device *dev);
+
/* Proc support (drm_proc.h) */
-extern int drm_proc_init(drm_device_t * dev,
+extern int drm_proc_init(struct drm_device *dev,
int minor,
struct proc_dir_entry *root,
struct proc_dir_entry **dev_root);
@@ -1042,45 +1032,45 @@ extern int drm_proc_cleanup(int minor,
struct proc_dir_entry *dev_root);
/* Scatter Gather Support (drm_scatter.h) */
-extern void drm_sg_cleanup(drm_sg_mem_t * entry);
+extern void drm_sg_cleanup(struct drm_sg_mem * entry);
extern int drm_sg_alloc(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_sg_free(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
/* ATI PCIGART support (ati_pcigart.h) */
-extern int drm_ati_pcigart_init(drm_device_t * dev,
- drm_ati_pcigart_info * gart_info);
-extern int drm_ati_pcigart_cleanup(drm_device_t * dev,
- drm_ati_pcigart_info * gart_info);
+extern int drm_ati_pcigart_init(struct drm_device *dev,
+ struct drm_ati_pcigart_info * gart_info);
+extern int drm_ati_pcigart_cleanup(struct drm_device *dev,
+ struct drm_ati_pcigart_info * gart_info);
-extern drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size,
+extern drm_dma_handle_t *drm_pci_alloc(struct drm_device *dev, size_t size,
size_t align, dma_addr_t maxaddr);
-extern void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah);
-extern void drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah);
+extern void __drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
+extern void drm_pci_free(struct drm_device *dev, drm_dma_handle_t * dmah);
/* sysfs support (drm_sysfs.c) */
extern struct class *drm_sysfs_create(struct module *owner, char *name);
extern void drm_sysfs_destroy(struct class *cs);
extern struct class_device *drm_sysfs_device_add(struct class *cs,
- drm_head_t *head);
+ struct drm_head *head);
extern void drm_sysfs_device_remove(struct class_device *class_dev);
/*
* Basic memory manager support (drm_mm.c)
*/
-extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
+extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
unsigned long size,
unsigned alignment);
-void drm_mm_put_block(drm_mm_node_t * cur);
-extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
+void drm_mm_put_block(struct drm_mm_node * cur);
+extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size,
unsigned alignment, int best_match);
-extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
-extern void drm_mm_takedown(drm_mm_t *mm);
-extern int drm_mm_clean(drm_mm_t *mm);
-extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
-extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
-extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
+extern int drm_mm_init(struct drm_mm *mm, unsigned long start, unsigned long size);
+extern void drm_mm_takedown(struct drm_mm *mm);
+extern int drm_mm_clean(struct drm_mm *mm);
+extern unsigned long drm_mm_tail_space(struct drm_mm *mm);
+extern int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size);
+extern int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size);
extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
@@ -1088,14 +1078,14 @@ extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
unsigned int token)
{
- drm_map_list_t *_entry;
- list_for_each_entry(_entry, &dev->maplist->head, head)
+ struct drm_map_list *_entry;
+ list_for_each_entry(_entry, &dev->maplist, head)
if (_entry->user_token == token)
return _entry->map;
return NULL;
}
-static __inline__ int drm_device_is_agp(drm_device_t * dev)
+static __inline__ int drm_device_is_agp(struct drm_device *dev)
{
if (dev->driver->device_is_agp != NULL) {
int err = (*dev->driver->device_is_agp) (dev);
@@ -1108,7 +1098,7 @@ static __inline__ int drm_device_is_agp(drm_device_t * dev)
return pci_find_capability(dev->pdev, PCI_CAP_ID_AGP);
}
-static __inline__ int drm_device_is_pcie(drm_device_t * dev)
+static __inline__ int drm_device_is_pcie(struct drm_device *dev)
{
return pci_find_capability(dev->pdev, PCI_CAP_ID_EXP);
}
@@ -1143,7 +1133,7 @@ extern void *drm_calloc(size_t nmemb, size_t size, int area);
/*@}*/
-extern unsigned long drm_core_get_map_ofs(drm_map_t * map);
+extern unsigned long drm_core_get_map_ofs(struct drm_map * map);
extern unsigned long drm_core_get_reg_ofs(struct drm_device *dev);
#endif /* __KERNEL__ */
diff --git a/drivers/char/drm/drm_agpsupport.c b/drivers/char/drm/drm_agpsupport.c
index 40bfd9b01e39..354f0e3674bf 100644
--- a/drivers/char/drm/drm_agpsupport.c
+++ b/drivers/char/drm/drm_agpsupport.c
@@ -48,7 +48,7 @@
* Verifies the AGP device has been initialized and acquired and fills in the
* drm_agp_info structure with the information in drm_agp_head::agp_info.
*/
-int drm_agp_info(drm_device_t * dev, drm_agp_info_t * info)
+int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
{
DRM_AGP_KERN *kern;
@@ -74,16 +74,16 @@ EXPORT_SYMBOL(drm_agp_info);
int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_agp_info_t info;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_agp_info info;
int err;
err = drm_agp_info(dev, &info);
if (err)
return err;
- if (copy_to_user((drm_agp_info_t __user *) arg, &info, sizeof(info)))
+ if (copy_to_user((struct drm_agp_info __user *) arg, &info, sizeof(info)))
return -EFAULT;
return 0;
}
@@ -97,7 +97,7 @@ int drm_agp_info_ioctl(struct inode *inode, struct file *filp,
* Verifies the AGP device hasn't been acquired before and calls
* \c agp_backend_acquire.
*/
-int drm_agp_acquire(drm_device_t * dev)
+int drm_agp_acquire(struct drm_device * dev)
{
if (!dev->agp)
return -ENODEV;
@@ -126,9 +126,9 @@ EXPORT_SYMBOL(drm_agp_acquire);
int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
+ struct drm_file *priv = filp->private_data;
- return drm_agp_acquire((drm_device_t *) priv->head->dev);
+ return drm_agp_acquire((struct drm_device *) priv->head->dev);
}
/**
@@ -139,7 +139,7 @@ int drm_agp_acquire_ioctl(struct inode *inode, struct file *filp,
*
* Verifies the AGP device has been acquired and calls \c agp_backend_release.
*/
-int drm_agp_release(drm_device_t * dev)
+int drm_agp_release(struct drm_device * dev)
{
if (!dev->agp || !dev->agp->acquired)
return -EINVAL;
@@ -152,8 +152,8 @@ EXPORT_SYMBOL(drm_agp_release);
int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
return drm_agp_release(dev);
}
@@ -168,7 +168,7 @@ int drm_agp_release_ioctl(struct inode *inode, struct file *filp,
* Verifies the AGP device has been acquired but not enabled, and calls
* \c agp_enable.
*/
-int drm_agp_enable(drm_device_t * dev, drm_agp_mode_t mode)
+int drm_agp_enable(struct drm_device * dev, struct drm_agp_mode mode)
{
if (!dev->agp || !dev->agp->acquired)
return -EINVAL;
@@ -185,11 +185,11 @@ EXPORT_SYMBOL(drm_agp_enable);
int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_agp_mode_t mode;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_agp_mode mode;
- if (copy_from_user(&mode, (drm_agp_mode_t __user *) arg, sizeof(mode)))
+ if (copy_from_user(&mode, (struct drm_agp_mode __user *) arg, sizeof(mode)))
return -EFAULT;
return drm_agp_enable(dev, mode);
@@ -207,9 +207,9 @@ int drm_agp_enable_ioctl(struct inode *inode, struct file *filp,
* Verifies the AGP device is present and has been acquired, allocates the
* memory via alloc_agp() and creates a drm_agp_mem entry for it.
*/
-int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request)
+int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
{
- drm_agp_mem_t *entry;
+ struct drm_agp_mem *entry;
DRM_AGP_MEM *memory;
unsigned long pages;
u32 type;
@@ -232,11 +232,7 @@ int drm_agp_alloc(drm_device_t *dev, drm_agp_buffer_t *request)
entry->memory = memory;
entry->bound = 0;
entry->pages = pages;
- entry->prev = NULL;
- entry->next = dev->agp->memory;
- if (dev->agp->memory)
- dev->agp->memory->prev = entry;
- dev->agp->memory = entry;
+ list_add(&entry->head, &dev->agp->memory);
request->handle = entry->handle;
request->physical = memory->physical;
@@ -248,10 +244,10 @@ EXPORT_SYMBOL(drm_agp_alloc);
int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_agp_buffer_t request;
- drm_agp_buffer_t __user *argp = (void __user *)arg;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_agp_buffer request;
+ struct drm_agp_buffer __user *argp = (void __user *)arg;
int err;
if (copy_from_user(&request, argp, sizeof(request)))
@@ -262,10 +258,12 @@ int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
return err;
if (copy_to_user(argp, &request, sizeof(request))) {
- drm_agp_mem_t *entry = dev->agp->memory;
-
- dev->agp->memory = entry->next;
- dev->agp->memory->prev = NULL;
+ struct drm_agp_mem *entry;
+ list_for_each_entry(entry, &dev->agp->memory, head) {
+ if (entry->handle == request.handle)
+ break;
+ }
+ list_del(&entry->head);
drm_free_agp(entry->memory, entry->pages);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
return -EFAULT;
@@ -283,12 +281,12 @@ int drm_agp_alloc_ioctl(struct inode *inode, struct file *filp,
*
* Walks through drm_agp_head::memory until finding a matching handle.
*/
-static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t * dev,
+static struct drm_agp_mem *drm_agp_lookup_entry(struct drm_device * dev,
unsigned long handle)
{
- drm_agp_mem_t *entry;
+ struct drm_agp_mem *entry;
- for (entry = dev->agp->memory; entry; entry = entry->next) {
+ list_for_each_entry(entry, &dev->agp->memory, head) {
if (entry->handle == handle)
return entry;
}
@@ -307,9 +305,9 @@ static drm_agp_mem_t *drm_agp_lookup_entry(drm_device_t * dev,
* Verifies the AGP device is present and acquired, looks-up the AGP memory
* entry and passes it to the unbind_agp() function.
*/
-int drm_agp_unbind(drm_device_t *dev, drm_agp_binding_t *request)
+int drm_agp_unbind(struct drm_device *dev, struct drm_agp_binding *request)
{
- drm_agp_mem_t *entry;
+ struct drm_agp_mem *entry;
int ret;
if (!dev->agp || !dev->agp->acquired)
@@ -328,12 +326,12 @@ EXPORT_SYMBOL(drm_agp_unbind);
int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_agp_binding_t request;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_agp_binding request;
if (copy_from_user
- (&request, (drm_agp_binding_t __user *) arg, sizeof(request)))
+ (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
return -EFAULT;
return drm_agp_unbind(dev, &request);
@@ -352,9 +350,9 @@ int drm_agp_unbind_ioctl(struct inode *inode, struct file *filp,
* is currently bound into the GATT. Looks-up the AGP memory entry and passes
* it to bind_agp() function.
*/
-int drm_agp_bind(drm_device_t *dev, drm_agp_binding_t *request)
+int drm_agp_bind(struct drm_device *dev, struct drm_agp_binding *request)
{
- drm_agp_mem_t *entry;
+ struct drm_agp_mem *entry;
int retcode;
int page;
@@ -377,12 +375,12 @@ EXPORT_SYMBOL(drm_agp_bind);
int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_agp_binding_t request;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_agp_binding request;
if (copy_from_user
- (&request, (drm_agp_binding_t __user *) arg, sizeof(request)))
+ (&request, (struct drm_agp_binding __user *) arg, sizeof(request)))
return -EFAULT;
return drm_agp_bind(dev, &request);
@@ -402,9 +400,9 @@ int drm_agp_bind_ioctl(struct inode *inode, struct file *filp,
* unbind_agp(). Frees it via free_agp() as well as the entry itself
* and unlinks from the doubly linked list it's inserted in.
*/
-int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request)
+int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request)
{
- drm_agp_mem_t *entry;
+ struct drm_agp_mem *entry;
if (!dev->agp || !dev->agp->acquired)
return -EINVAL;
@@ -413,13 +411,7 @@ int drm_agp_free(drm_device_t *dev, drm_agp_buffer_t *request)
if (entry->bound)
drm_unbind_agp(entry->memory);
- if (entry->prev)
- entry->prev->next = entry->next;
- else
- dev->agp->memory = entry->next;
-
- if (entry->next)
- entry->next->prev = entry->prev;
+ list_del(&entry->head);
drm_free_agp(entry->memory, entry->pages);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
@@ -430,12 +422,12 @@ EXPORT_SYMBOL(drm_agp_free);
int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_agp_buffer_t request;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_agp_buffer request;
if (copy_from_user
- (&request, (drm_agp_buffer_t __user *) arg, sizeof(request)))
+ (&request, (struct drm_agp_buffer __user *) arg, sizeof(request)))
return -EFAULT;
return drm_agp_free(dev, &request);
@@ -450,9 +442,9 @@ int drm_agp_free_ioctl(struct inode *inode, struct file *filp,
* via the inter_module_* functions. Creates and initializes a drm_agp_head
* structure.
*/
-drm_agp_head_t *drm_agp_init(drm_device_t * dev)
+struct drm_agp_head *drm_agp_init(struct drm_device *dev)
{
- drm_agp_head_t *head = NULL;
+ struct drm_agp_head *head = NULL;
if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS)))
return NULL;
@@ -472,7 +464,7 @@ drm_agp_head_t *drm_agp_init(drm_device_t * dev)
drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS);
return NULL;
}
- head->memory = NULL;
+ INIT_LIST_HEAD(&head->memory);
head->cant_use_aperture = head->agp_info.cant_use_aperture;
head->page_mask = head->agp_info.page_mask;
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index c7b19d35bcd6..7f777da872cd 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -45,15 +45,15 @@
* the one with matching magic number, while holding the drm_device::struct_mutex
* lock.
*/
-static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
+static struct drm_file *drm_find_file(struct drm_device * dev, drm_magic_t magic)
{
- drm_file_t *retval = NULL;
- drm_magic_entry_t *pt;
- drm_hash_item_t *hash;
+ struct drm_file *retval = NULL;
+ struct drm_magic_entry *pt;
+ struct drm_hash_item *hash;
mutex_lock(&dev->struct_mutex);
if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
- pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+ pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
retval = pt->priv;
}
mutex_unlock(&dev->struct_mutex);
@@ -71,10 +71,10 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
* associated the magic number hash key in drm_device::magiclist, while holding
* the drm_device::struct_mutex lock.
*/
-static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
+static int drm_add_magic(struct drm_device * dev, struct drm_file * priv,
drm_magic_t magic)
{
- drm_magic_entry_t *entry;
+ struct drm_magic_entry *entry;
DRM_DEBUG("%d\n", magic);
@@ -102,10 +102,10 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
* Searches and unlinks the entry in drm_device::magiclist with the magic
* number hash key, while holding the drm_device::struct_mutex lock.
*/
-static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
+static int drm_remove_magic(struct drm_device * dev, drm_magic_t magic)
{
- drm_magic_entry_t *pt;
- drm_hash_item_t *hash;
+ struct drm_magic_entry *pt;
+ struct drm_hash_item *hash;
DRM_DEBUG("%d\n", magic);
@@ -114,7 +114,7 @@ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
- pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+ pt = drm_hash_entry(hash, struct drm_magic_entry, hash_item);
drm_ht_remove_item(&dev->magiclist, hash);
list_del(&pt->head);
mutex_unlock(&dev->struct_mutex);
@@ -142,9 +142,9 @@ int drm_getmagic(struct inode *inode, struct file *filp,
{
static drm_magic_t sequence = 0;
static DEFINE_SPINLOCK(lock);
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_auth_t auth;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_auth auth;
/* Find unique magic */
if (priv->magic) {
@@ -162,7 +162,7 @@ int drm_getmagic(struct inode *inode, struct file *filp,
}
DRM_DEBUG("%u\n", auth.magic);
- if (copy_to_user((drm_auth_t __user *) arg, &auth, sizeof(auth)))
+ if (copy_to_user((struct drm_auth __user *) arg, &auth, sizeof(auth)))
return -EFAULT;
return 0;
}
@@ -181,12 +181,12 @@ int drm_getmagic(struct inode *inode, struct file *filp,
int drm_authmagic(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_auth_t auth;
- drm_file_t *file;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_auth auth;
+ struct drm_file *file;
- if (copy_from_user(&auth, (drm_auth_t __user *) arg, sizeof(auth)))
+ if (copy_from_user(&auth, (struct drm_auth __user *) arg, sizeof(auth)))
return -EFAULT;
DRM_DEBUG("%u\n", auth.magic);
if ((file = drm_find_file(dev, auth.magic))) {
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index c11345856ffe..923174c54a1c 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -36,26 +36,24 @@
#include <linux/vmalloc.h>
#include "drmP.h"
-unsigned long drm_get_resource_start(drm_device_t *dev, unsigned int resource)
+unsigned long drm_get_resource_start(struct drm_device *dev, unsigned int resource)
{
return pci_resource_start(dev->pdev, resource);
}
EXPORT_SYMBOL(drm_get_resource_start);
-unsigned long drm_get_resource_len(drm_device_t *dev, unsigned int resource)
+unsigned long drm_get_resource_len(struct drm_device *dev, unsigned int resource)
{
return pci_resource_len(dev->pdev, resource);
}
EXPORT_SYMBOL(drm_get_resource_len);
-static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
+static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
drm_local_map_t *map)
{
- struct list_head *list;
-
- list_for_each(list, &dev->maplist->head) {
- drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
+ struct drm_map_list *entry;
+ list_for_each_entry(entry, &dev->maplist, head) {
if (entry->map && map->type == entry->map->type &&
((entry->map->offset == map->offset) ||
(map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
@@ -66,7 +64,7 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
return NULL;
}
-static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
+static int drm_map_handle(struct drm_device *dev, struct drm_hash_item *hash,
unsigned long user_token, int hashed_handle)
{
int use_hashed_handle;
@@ -103,12 +101,13 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
* type. Adds the map to the map list drm_device::maplist. Adds MTRR's where
* applicable and if supported by the kernel.
*/
-static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
- unsigned int size, drm_map_type_t type,
- drm_map_flags_t flags, drm_map_list_t ** maplist)
+static int drm_addmap_core(struct drm_device * dev, unsigned int offset,
+ unsigned int size, enum drm_map_type type,
+ enum drm_map_flags flags,
+ struct drm_map_list ** maplist)
{
- drm_map_t *map;
- drm_map_list_t *list;
+ struct drm_map *map;
+ struct drm_map_list *list;
drm_dma_handle_t *dmah;
unsigned long user_token;
int ret;
@@ -214,7 +213,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
}
break;
case _DRM_AGP: {
- drm_agp_mem_t *entry;
+ struct drm_agp_mem *entry;
int valid = 0;
if (!drm_core_has_AGP(dev)) {
@@ -237,14 +236,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
* skipped and we double check that dev->agp->memory is
* actually set as well as being invalid before EPERM'ing
*/
- for (entry = dev->agp->memory; entry; entry = entry->next) {
+ list_for_each_entry(entry, &dev->agp->memory, head) {
if ((map->offset >= entry->bound) &&
(map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) {
valid = 1;
break;
}
}
- if (dev->agp->memory && !valid) {
+ if (!list_empty(&dev->agp->memory) && !valid) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EPERM;
}
@@ -289,7 +288,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
list->map = map;
mutex_lock(&dev->struct_mutex);
- list_add(&list->head, &dev->maplist->head);
+ list_add(&list->head, &dev->maplist);
/* Assign a 32-bit handle */
/* We do it here so that dev->struct_mutex protects the increment */
@@ -312,11 +311,11 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
return 0;
}
-int drm_addmap(drm_device_t * dev, unsigned int offset,
- unsigned int size, drm_map_type_t type,
- drm_map_flags_t flags, drm_local_map_t ** map_ptr)
+int drm_addmap(struct drm_device * dev, unsigned int offset,
+ unsigned int size, enum drm_map_type type,
+ enum drm_map_flags flags, drm_local_map_t ** map_ptr)
{
- drm_map_list_t *list;
+ struct drm_map_list *list;
int rc;
rc = drm_addmap_core(dev, offset, size, type, flags, &list);
@@ -330,11 +329,11 @@ EXPORT_SYMBOL(drm_addmap);
int drm_addmap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_map_t map;
- drm_map_list_t *maplist;
- drm_map_t __user *argp = (void __user *)arg;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_map map;
+ struct drm_map_list *maplist;
+ struct drm_map __user *argp = (void __user *)arg;
int err;
if (!(filp->f_mode & 3))
@@ -353,7 +352,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
if (err)
return err;
- if (copy_to_user(argp, maplist->map, sizeof(drm_map_t)))
+ if (copy_to_user(argp, maplist->map, sizeof(struct drm_map)))
return -EFAULT;
/* avoid a warning on 64-bit, this casting isn't very nice, but the API is set so too late */
@@ -369,7 +368,7 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
* \param inode device inode.
* \param filp file pointer.
* \param cmd command.
- * \param arg pointer to a drm_map_t structure.
+ * \param arg pointer to a struct drm_map structure.
* \return zero on success or a negative value on error.
*
* Searches the map on drm_device::maplist, removes it from the list, see if
@@ -378,31 +377,26 @@ int drm_addmap_ioctl(struct inode *inode, struct file *filp,
*
* \sa drm_addmap
*/
-int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
+int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
{
- struct list_head *list;
- drm_map_list_t *r_list = NULL;
+ struct drm_map_list *r_list = NULL, *list_t;
drm_dma_handle_t dmah;
+ int found = 0;
/* Find the list entry for the map and remove it */
- list_for_each(list, &dev->maplist->head) {
- r_list = list_entry(list, drm_map_list_t, head);
-
+ list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
if (r_list->map == map) {
- list_del(list);
+ list_del(&r_list->head);
drm_ht_remove_key(&dev->map_hash,
r_list->user_token >> PAGE_SHIFT);
- drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+ drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS);
+ found = 1;
break;
}
}
- /* List has wrapped around to the head pointer, or it's empty and we
- * didn't find anything.
- */
- if (list == (&dev->maplist->head)) {
+ if (!found)
return -EINVAL;
- }
switch (map->type) {
case _DRM_REGISTERS:
@@ -433,7 +427,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
return 0;
}
-int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
+int drm_rmmap(struct drm_device *dev, drm_local_map_t *map)
{
int ret;
@@ -456,21 +450,19 @@ int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_map_t request;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_map request;
drm_local_map_t *map = NULL;
- struct list_head *list;
+ struct drm_map_list *r_list;
int ret;
- if (copy_from_user(&request, (drm_map_t __user *) arg, sizeof(request))) {
+ if (copy_from_user(&request, (struct drm_map __user *) arg, sizeof(request))) {
return -EFAULT;
}
mutex_lock(&dev->struct_mutex);
- list_for_each(list, &dev->maplist->head) {
- drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
-
+ list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map &&
r_list->user_token == (unsigned long)request.handle &&
r_list->map->flags & _DRM_REMOVABLE) {
@@ -482,7 +474,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
/* List has wrapped around to the head pointer, or its empty we didn't
* find anything.
*/
- if (list == (&dev->maplist->head)) {
+ if (list_empty(&dev->maplist) || !map) {
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
@@ -513,7 +505,8 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
*
* Frees any pages and buffers associated with the given entry.
*/
-static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry)
+static void drm_cleanup_buf_error(struct drm_device * dev,
+ struct drm_buf_entry * entry)
{
int i;
@@ -550,20 +543,20 @@ static void drm_cleanup_buf_error(drm_device_t * dev, drm_buf_entry_t * entry)
/**
* Add AGP buffers for DMA transfers.
*
- * \param dev drm_device_t to which the buffers are to be added.
- * \param request pointer to a drm_buf_desc_t describing the request.
+ * \param dev struct drm_device to which the buffers are to be added.
+ * \param request pointer to a struct drm_buf_desc describing the request.
* \return zero on success or a negative number on failure.
*
* After some sanity checks creates a drm_buf structure for each buffer and
* reallocates the buffer list of the same size order to accommodate the new
* buffers.
*/
-int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
+int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request)
{
- drm_device_dma_t *dma = dev->dma;
- drm_buf_entry_t *entry;
- drm_agp_mem_t *agp_entry;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf_entry *entry;
+ struct drm_agp_mem *agp_entry;
+ struct drm_buf *buf;
unsigned long offset;
unsigned long agp_offset;
int count;
@@ -574,7 +567,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
int total;
int byte_count;
int i, valid;
- drm_buf_t **temp_buflist;
+ struct drm_buf **temp_buflist;
if (!dma)
return -EINVAL;
@@ -606,14 +599,14 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
/* Make sure buffers are located in AGP memory that we own */
valid = 0;
- for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) {
+ list_for_each_entry(agp_entry, &dev->agp->memory, head) {
if ((agp_offset >= agp_entry->bound) &&
(agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
valid = 1;
break;
}
}
- if (dev->agp->memory && !valid) {
+ if (!list_empty(&dev->agp->memory) && !valid) {
DRM_DEBUG("zone invalid\n");
return -EINVAL;
}
@@ -728,24 +721,24 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
EXPORT_SYMBOL(drm_addbufs_agp);
#endif /* __OS_HAS_AGP */
-int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
+int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int count;
int order;
int size;
int total;
int page_order;
- drm_buf_entry_t *entry;
+ struct drm_buf_entry *entry;
drm_dma_handle_t *dmah;
- drm_buf_t *buf;
+ struct drm_buf *buf;
int alignment;
unsigned long offset;
int i;
int byte_count;
int page_count;
unsigned long *temp_pagelist;
- drm_buf_t **temp_buflist;
+ struct drm_buf **temp_buflist;
if (!drm_core_check_feature(dev, DRIVER_PCI_DMA))
return -EINVAL;
@@ -954,11 +947,11 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
}
EXPORT_SYMBOL(drm_addbufs_pci);
-static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
+static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request)
{
- drm_device_dma_t *dma = dev->dma;
- drm_buf_entry_t *entry;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf_entry *entry;
+ struct drm_buf *buf;
unsigned long offset;
unsigned long agp_offset;
int count;
@@ -969,7 +962,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
int total;
int byte_count;
int i;
- drm_buf_t **temp_buflist;
+ struct drm_buf **temp_buflist;
if (!drm_core_check_feature(dev, DRIVER_SG))
return -EINVAL;
@@ -1116,11 +1109,11 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
return 0;
}
-static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
+static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request)
{
- drm_device_dma_t *dma = dev->dma;
- drm_buf_entry_t *entry;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf_entry *entry;
+ struct drm_buf *buf;
unsigned long offset;
unsigned long agp_offset;
int count;
@@ -1131,7 +1124,7 @@ static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
int total;
int byte_count;
int i;
- drm_buf_t **temp_buflist;
+ struct drm_buf **temp_buflist;
if (!drm_core_check_feature(dev, DRIVER_FB_DMA))
return -EINVAL;
@@ -1283,7 +1276,7 @@ static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
* \param inode device inode.
* \param filp file pointer.
* \param cmd command.
- * \param arg pointer to a drm_buf_desc_t request.
+ * \param arg pointer to a struct drm_buf_desc request.
* \return zero on success or a negative number on failure.
*
* According with the memory type specified in drm_buf_desc::flags and the
@@ -1294,15 +1287,15 @@ static int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
int drm_addbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_buf_desc_t request;
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_buf_desc request;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
int ret;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
return -EINVAL;
- if (copy_from_user(&request, (drm_buf_desc_t __user *) arg,
+ if (copy_from_user(&request, (struct drm_buf_desc __user *) arg,
sizeof(request)))
return -EFAULT;
@@ -1346,11 +1339,11 @@ int drm_addbufs(struct inode *inode, struct file *filp,
int drm_infobufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_info_t request;
- drm_buf_info_t __user *argp = (void __user *)arg;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf_info request;
+ struct drm_buf_info __user *argp = (void __user *)arg;
int i;
int count;
@@ -1381,10 +1374,10 @@ int drm_infobufs(struct inode *inode, struct file *filp,
if (request.count >= count) {
for (i = 0, count = 0; i < DRM_MAX_ORDER + 1; i++) {
if (dma->bufs[i].buf_count) {
- drm_buf_desc_t __user *to =
+ struct drm_buf_desc __user *to =
&request.list[count];
- drm_buf_entry_t *from = &dma->bufs[i];
- drm_freelist_t *list = &dma->bufs[i].freelist;
+ struct drm_buf_entry *from = &dma->bufs[i];
+ struct drm_freelist *list = &dma->bufs[i].freelist;
if (copy_to_user(&to->count,
&from->buf_count,
sizeof(from->buf_count)) ||
@@ -1434,12 +1427,12 @@ int drm_infobufs(struct inode *inode, struct file *filp,
int drm_markbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_desc_t request;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf_desc request;
int order;
- drm_buf_entry_t *entry;
+ struct drm_buf_entry *entry;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
return -EINVAL;
@@ -1448,7 +1441,7 @@ int drm_markbufs(struct inode *inode, struct file *filp,
return -EINVAL;
if (copy_from_user(&request,
- (drm_buf_desc_t __user *) arg, sizeof(request)))
+ (struct drm_buf_desc __user *) arg, sizeof(request)))
return -EFAULT;
DRM_DEBUG("%d, %d, %d\n",
@@ -1484,13 +1477,13 @@ int drm_markbufs(struct inode *inode, struct file *filp,
int drm_freebufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_free_t request;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf_free request;
int i;
int idx;
- drm_buf_t *buf;
+ struct drm_buf *buf;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
return -EINVAL;
@@ -1499,7 +1492,7 @@ int drm_freebufs(struct inode *inode, struct file *filp,
return -EINVAL;
if (copy_from_user(&request,
- (drm_buf_free_t __user *) arg, sizeof(request)))
+ (struct drm_buf_free __user *) arg, sizeof(request)))
return -EFAULT;
DRM_DEBUG("%d\n", request.count);
@@ -1540,15 +1533,15 @@ int drm_freebufs(struct inode *inode, struct file *filp,
int drm_mapbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_map_t __user *argp = (void __user *)arg;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf_map __user *argp = (void __user *)arg;
int retcode = 0;
const int zero = 0;
unsigned long virtual;
unsigned long address;
- drm_buf_map_t request;
+ struct drm_buf_map request;
int i;
if (!drm_core_check_feature(dev, DRIVER_HAVE_DMA))
@@ -1574,7 +1567,7 @@ int drm_mapbufs(struct inode *inode, struct file *filp,
&& (dma->flags & _DRM_DMA_USE_SG))
|| (drm_core_check_feature(dev, DRIVER_FB_DMA)
&& (dma->flags & _DRM_DMA_USE_FB))) {
- drm_map_t *map = dev->agp_buffer_map;
+ struct drm_map *map = dev->agp_buffer_map;
unsigned long token = dev->agp_buffer_token;
if (!map) {
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index 83094c73da67..61ad986baa8d 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -53,26 +53,14 @@
* \param ctx_handle context handle.
*
* Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
- * in drm_device::context_sareas, while holding the drm_device::struct_mutex
+ * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
* lock.
*/
-void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
+void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
{
- if (ctx_handle < 0)
- goto failed;
- if (!dev->ctx_bitmap)
- goto failed;
-
- if (ctx_handle < DRM_MAX_CTXBITMAP) {
- mutex_lock(&dev->struct_mutex);
- clear_bit(ctx_handle, dev->ctx_bitmap);
- dev->context_sareas[ctx_handle] = NULL;
- mutex_unlock(&dev->struct_mutex);
- return;
- }
- failed:
- DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle);
- return;
+ mutex_lock(&dev->struct_mutex);
+ idr_remove(&dev->ctx_idr, ctx_handle);
+ mutex_unlock(&dev->struct_mutex);
}
/**
@@ -81,62 +69,28 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
* \param dev DRM device.
* \return (non-negative) context handle on success or a negative number on failure.
*
- * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
- * drm_device::context_sareas to accommodate the new entry while holding the
+ * Allocate a new idr from drm_device::ctx_idr while holding the
* drm_device::struct_mutex lock.
*/
-static int drm_ctxbitmap_next(drm_device_t * dev)
+static int drm_ctxbitmap_next(struct drm_device * dev)
{
- int bit;
-
- if (!dev->ctx_bitmap)
- return -1;
+ int new_id;
+ int ret;
+again:
+ if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) {
+ DRM_ERROR("Out of memory expanding drawable idr\n");
+ return -ENOMEM;
+ }
mutex_lock(&dev->struct_mutex);
- bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
- if (bit < DRM_MAX_CTXBITMAP) {
- set_bit(bit, dev->ctx_bitmap);
- DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
- if ((bit + 1) > dev->max_context) {
- dev->max_context = (bit + 1);
- if (dev->context_sareas) {
- drm_map_t **ctx_sareas;
-
- ctx_sareas = drm_realloc(dev->context_sareas,
- (dev->max_context -
- 1) *
- sizeof(*dev->
- context_sareas),
- dev->max_context *
- sizeof(*dev->
- context_sareas),
- DRM_MEM_MAPS);
- if (!ctx_sareas) {
- clear_bit(bit, dev->ctx_bitmap);
- mutex_unlock(&dev->struct_mutex);
- return -1;
- }
- dev->context_sareas = ctx_sareas;
- dev->context_sareas[bit] = NULL;
- } else {
- /* max_context == 1 at this point */
- dev->context_sareas =
- drm_alloc(dev->max_context *
- sizeof(*dev->context_sareas),
- DRM_MEM_MAPS);
- if (!dev->context_sareas) {
- clear_bit(bit, dev->ctx_bitmap);
- mutex_unlock(&dev->struct_mutex);
- return -1;
- }
- dev->context_sareas[bit] = NULL;
- }
- }
+ ret = idr_get_new_above(&dev->ctx_idr, NULL,
+ DRM_RESERVED_CONTEXTS, &new_id);
+ if (ret == -EAGAIN) {
mutex_unlock(&dev->struct_mutex);
- return bit;
+ goto again;
}
mutex_unlock(&dev->struct_mutex);
- return -1;
+ return new_id;
}
/**
@@ -144,31 +98,11 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
*
* \param dev DRM device.
*
- * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_mutex lock.
+ * Initialise the drm_device::ctx_idr
*/
-int drm_ctxbitmap_init(drm_device_t * dev)
+int drm_ctxbitmap_init(struct drm_device * dev)
{
- int i;
- int temp;
-
- mutex_lock(&dev->struct_mutex);
- dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE,
- DRM_MEM_CTXBITMAP);
- if (dev->ctx_bitmap == NULL) {
- mutex_unlock(&dev->struct_mutex);
- return -ENOMEM;
- }
- memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE);
- dev->context_sareas = NULL;
- dev->max_context = -1;
- mutex_unlock(&dev->struct_mutex);
-
- for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
- temp = drm_ctxbitmap_next(dev);
- DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
- }
-
+ idr_init(&dev->ctx_idr);
return 0;
}
@@ -177,17 +111,13 @@ int drm_ctxbitmap_init(drm_device_t * dev)
*
* \param dev DRM device.
*
- * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_mutex lock.
+ * Free all idr members using drm_ctx_sarea_free helper function
+ * while holding the drm_device::struct_mutex lock.
*/
-void drm_ctxbitmap_cleanup(drm_device_t * dev)
+void drm_ctxbitmap_cleanup(struct drm_device * dev)
{
mutex_lock(&dev->struct_mutex);
- if (dev->context_sareas)
- drm_free(dev->context_sareas,
- sizeof(*dev->context_sareas) *
- dev->max_context, DRM_MEM_MAPS);
- drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP);
+ idr_remove_all(&dev->ctx_idr);
mutex_unlock(&dev->struct_mutex);
}
@@ -206,34 +136,34 @@ void drm_ctxbitmap_cleanup(drm_device_t * dev)
* \param arg user argument pointing to a drm_ctx_priv_map structure.
* \return zero on success or a negative number on failure.
*
- * Gets the map from drm_device::context_sareas with the handle specified and
+ * Gets the map from drm_device::ctx_idr with the handle specified and
* returns its handle.
*/
int drm_getsareactx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_ctx_priv_map_t __user *argp = (void __user *)arg;
- drm_ctx_priv_map_t request;
- drm_map_t *map;
- drm_map_list_t *_entry;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_ctx_priv_map __user *argp = (void __user *)arg;
+ struct drm_ctx_priv_map request;
+ struct drm_map *map;
+ struct drm_map_list *_entry;
if (copy_from_user(&request, argp, sizeof(request)))
return -EFAULT;
mutex_lock(&dev->struct_mutex);
- if (dev->max_context < 0
- || request.ctx_id >= (unsigned)dev->max_context) {
+
+ map = idr_find(&dev->ctx_idr, request.ctx_id);
+ if (!map) {
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
- map = dev->context_sareas[request.ctx_id];
mutex_unlock(&dev->struct_mutex);
request.handle = NULL;
- list_for_each_entry(_entry, &dev->maplist->head, head) {
+ list_for_each_entry(_entry, &dev->maplist, head) {
if (_entry->map == map) {
request.handle =
(void *)(unsigned long)_entry->user_token;
@@ -258,25 +188,24 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
* \return zero on success or a negative number on failure.
*
* Searches the mapping specified in \p arg and update the entry in
- * drm_device::context_sareas with it.
+ * drm_device::ctx_idr with it.
*/
int drm_setsareactx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_ctx_priv_map_t request;
- drm_map_t *map = NULL;
- drm_map_list_t *r_list = NULL;
- struct list_head *list;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_ctx_priv_map request;
+ struct drm_map *map = NULL;
+ struct drm_map_list *r_list = NULL;
if (copy_from_user(&request,
- (drm_ctx_priv_map_t __user *) arg, sizeof(request)))
+ (struct drm_ctx_priv_map __user *) arg,
+ sizeof(request)))
return -EFAULT;
mutex_lock(&dev->struct_mutex);
- list_for_each(list, &dev->maplist->head) {
- r_list = list_entry(list, drm_map_list_t, head);
+ list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map
&& r_list->user_token == (unsigned long)request.handle)
goto found;
@@ -289,11 +218,10 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
map = r_list->map;
if (!map)
goto bad;
- if (dev->max_context < 0)
- goto bad;
- if (request.ctx_id >= (unsigned)dev->max_context)
+
+ if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id)))
goto bad;
- dev->context_sareas[request.ctx_id] = map;
+
mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -314,7 +242,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
*
* Attempt to set drm_device::context_flag.
*/
-static int drm_context_switch(drm_device_t * dev, int old, int new)
+static int drm_context_switch(struct drm_device * dev, int old, int new)
{
if (test_and_set_bit(0, &dev->context_flag)) {
DRM_ERROR("Reentering -- FIXME\n");
@@ -342,7 +270,7 @@ static int drm_context_switch(drm_device_t * dev, int old, int new)
* hardware lock is held, clears the drm_device::context_flag and wakes up
* drm_device::context_wait.
*/
-static int drm_context_switch_complete(drm_device_t * dev, int new)
+static int drm_context_switch_complete(struct drm_device * dev, int new)
{
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
dev->last_switch = jiffies;
@@ -372,9 +300,9 @@ static int drm_context_switch_complete(drm_device_t * dev, int new)
int drm_resctx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_ctx_res_t res;
- drm_ctx_t __user *argp = (void __user *)arg;
- drm_ctx_t ctx;
+ struct drm_ctx_res res;
+ struct drm_ctx_res __user *argp = (void __user *)arg;
+ struct drm_ctx ctx;
int i;
if (copy_from_user(&res, argp, sizeof(res)))
@@ -409,11 +337,11 @@ int drm_resctx(struct inode *inode, struct file *filp,
int drm_addctx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_ctx_list_t *ctx_entry;
- drm_ctx_t __user *argp = (void __user *)arg;
- drm_ctx_t ctx;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_ctx_list *ctx_entry;
+ struct drm_ctx __user *argp = (void __user *)arg;
+ struct drm_ctx ctx;
if (copy_from_user(&ctx, argp, sizeof(ctx)))
return -EFAULT;
@@ -449,7 +377,7 @@ int drm_addctx(struct inode *inode, struct file *filp,
ctx_entry->tag = priv;
mutex_lock(&dev->ctxlist_mutex);
- list_add(&ctx_entry->head, &dev->ctxlist->head);
+ list_add(&ctx_entry->head, &dev->ctxlist);
++dev->ctx_count;
mutex_unlock(&dev->ctxlist_mutex);
@@ -477,8 +405,8 @@ int drm_modctx(struct inode *inode, struct file *filp,
int drm_getctx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_ctx_t __user *argp = (void __user *)arg;
- drm_ctx_t ctx;
+ struct drm_ctx __user *argp = (void __user *)arg;
+ struct drm_ctx ctx;
if (copy_from_user(&ctx, argp, sizeof(ctx)))
return -EFAULT;
@@ -505,11 +433,11 @@ int drm_getctx(struct inode *inode, struct file *filp,
int drm_switchctx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_ctx_t ctx;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_ctx ctx;
- if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
+ if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
@@ -530,11 +458,11 @@ int drm_switchctx(struct inode *inode, struct file *filp,
int drm_newctx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_ctx_t ctx;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_ctx ctx;
- if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
+ if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
@@ -557,11 +485,11 @@ int drm_newctx(struct inode *inode, struct file *filp,
int drm_rmctx(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_ctx_t ctx;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_ctx ctx;
- if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx)))
+ if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx)))
return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
@@ -575,10 +503,10 @@ int drm_rmctx(struct inode *inode, struct file *filp,
}
mutex_lock(&dev->ctxlist_mutex);
- if (!list_empty(&dev->ctxlist->head)) {
- drm_ctx_list_t *pos, *n;
+ if (!list_empty(&dev->ctxlist)) {
+ struct drm_ctx_list *pos, *n;
- list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) {
+ list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
if (pos->handle == ctx.handle) {
list_del(&pos->head);
drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST);
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 32ed19c9ec1c..802fbdbfe1b3 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -43,7 +43,7 @@
*
* Allocate and initialize a drm_device_dma structure.
*/
-int drm_dma_setup(drm_device_t * dev)
+int drm_dma_setup(struct drm_device *dev)
{
int i;
@@ -67,9 +67,9 @@ int drm_dma_setup(drm_device_t * dev)
* Free all pages associated with DMA buffers, the buffers and pages lists, and
* finally the drm_device::dma structure itself.
*/
-void drm_dma_takedown(drm_device_t * dev)
+void drm_dma_takedown(struct drm_device *dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i, j;
if (!dma)
@@ -129,7 +129,7 @@ void drm_dma_takedown(drm_device_t * dev)
*
* Resets the fields of \p buf.
*/
-void drm_free_buffer(drm_device_t * dev, drm_buf_t * buf)
+void drm_free_buffer(struct drm_device *dev, struct drm_buf * buf)
{
if (!buf)
return;
@@ -152,9 +152,9 @@ void drm_free_buffer(drm_device_t * dev, drm_buf_t * buf)
*
* Frees each buffer associated with \p filp not already on the hardware.
*/
-void drm_core_reclaim_buffers(drm_device_t * dev, struct file *filp)
+void drm_core_reclaim_buffers(struct drm_device *dev, struct file *filp)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i;
if (!dma)
diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c
index b33313be2547..d6cdba5644e2 100644
--- a/drivers/char/drm/drm_drawable.c
+++ b/drivers/char/drm/drm_drawable.c
@@ -44,83 +44,30 @@ int drm_adddraw(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
unsigned long irqflags;
- int i, j;
- u32 *bitfield = dev->drw_bitfield;
- unsigned int bitfield_length = dev->drw_bitfield_length;
- drm_drawable_info_t **info = dev->drw_info;
- unsigned int info_length = dev->drw_info_length;
- drm_draw_t draw;
-
- for (i = 0, j = 0; i < bitfield_length; i++) {
- if (bitfield[i] == ~0)
- continue;
-
- for (; j < 8 * sizeof(*bitfield); j++)
- if (!(bitfield[i] & (1 << j)))
- goto done;
+ struct drm_draw draw;
+ int new_id = 0;
+ int ret;
+
+again:
+ if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
+ DRM_ERROR("Out of memory expanding drawable idr\n");
+ return -ENOMEM;
}
-done:
-
- if (i == bitfield_length) {
- bitfield_length++;
-
- bitfield = drm_alloc(bitfield_length * sizeof(*bitfield),
- DRM_MEM_BUFS);
-
- if (!bitfield) {
- DRM_ERROR("Failed to allocate new drawable bitfield\n");
- return DRM_ERR(ENOMEM);
- }
-
- if (8 * sizeof(*bitfield) * bitfield_length > info_length) {
- info_length += 8 * sizeof(*bitfield);
-
- info = drm_alloc(info_length * sizeof(*info),
- DRM_MEM_BUFS);
-
- if (!info) {
- DRM_ERROR("Failed to allocate new drawable info"
- " array\n");
-
- drm_free(bitfield,
- bitfield_length * sizeof(*bitfield),
- DRM_MEM_BUFS);
- return DRM_ERR(ENOMEM);
- }
- }
-
- bitfield[i] = 0;
- }
-
- draw.handle = i * 8 * sizeof(*bitfield) + j + 1;
- DRM_DEBUG("%d\n", draw.handle);
spin_lock_irqsave(&dev->drw_lock, irqflags);
-
- bitfield[i] |= 1 << j;
- info[draw.handle - 1] = NULL;
-
- if (bitfield != dev->drw_bitfield) {
- memcpy(bitfield, dev->drw_bitfield, dev->drw_bitfield_length *
- sizeof(*bitfield));
- drm_free(dev->drw_bitfield, sizeof(*bitfield) *
- dev->drw_bitfield_length, DRM_MEM_BUFS);
- dev->drw_bitfield = bitfield;
- dev->drw_bitfield_length = bitfield_length;
- }
-
- if (info != dev->drw_info) {
- memcpy(info, dev->drw_info, dev->drw_info_length *
- sizeof(*info));
- drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length,
- DRM_MEM_BUFS);
- dev->drw_info = info;
- dev->drw_info_length = info_length;
+ ret = idr_get_new_above(&dev->drw_idr, NULL, 1, &new_id);
+ if (ret == -EAGAIN) {
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
+ goto again;
}
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- DRM_COPY_TO_USER_IOCTL((drm_draw_t __user *)data, draw, sizeof(draw));
+ draw.handle = new_id;
+
+ DRM_DEBUG("%d\n", draw.handle);
+
+ DRM_COPY_TO_USER_IOCTL((struct drm_draw __user *)data, draw, sizeof(draw));
return 0;
}
@@ -131,141 +78,52 @@ done:
int drm_rmdraw(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_draw_t draw;
- int id, idx;
- unsigned int shift;
+ struct drm_draw draw;
unsigned long irqflags;
- u32 *bitfield = dev->drw_bitfield;
- unsigned int bitfield_length = dev->drw_bitfield_length;
- drm_drawable_info_t **info = dev->drw_info;
- unsigned int info_length = dev->drw_info_length;
- DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
+ DRM_COPY_FROM_USER_IOCTL(draw, (struct drm_draw __user *) data,
sizeof(draw));
- id = draw.handle - 1;
- idx = id / (8 * sizeof(*bitfield));
- shift = id % (8 * sizeof(*bitfield));
-
- if (idx < 0 || idx >= bitfield_length ||
- !(bitfield[idx] & (1 << shift))) {
- DRM_DEBUG("No such drawable %d\n", draw.handle);
- return 0;
- }
-
spin_lock_irqsave(&dev->drw_lock, irqflags);
- bitfield[idx] &= ~(1 << shift);
-
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
-
- if (info[id]) {
- drm_free(info[id]->rects, info[id]->num_rects *
- sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
- drm_free(info[id], sizeof(**info), DRM_MEM_BUFS);
- }
-
- /* Can we shrink the arrays? */
- if (idx == bitfield_length - 1) {
- while (idx >= 0 && !bitfield[idx])
- --idx;
-
- bitfield_length = idx + 1;
-
- bitfield = NULL;
-
- if (bitfield_length) {
- if (bitfield_length != dev->drw_bitfield_length)
- bitfield = drm_alloc(bitfield_length *
- sizeof(*bitfield),
- DRM_MEM_BUFS);
-
- if (!bitfield) {
- bitfield = dev->drw_bitfield;
- bitfield_length = dev->drw_bitfield_length;
- }
- }
- }
-
- if (bitfield != dev->drw_bitfield) {
- info_length = 8 * sizeof(*bitfield) * bitfield_length;
-
- if (info_length) {
- info = drm_alloc(info_length * sizeof(*info),
- DRM_MEM_BUFS);
-
- if (!info) {
- info = dev->drw_info;
- info_length = dev->drw_info_length;
- }
- } else
- info = NULL;
-
- spin_lock_irqsave(&dev->drw_lock, irqflags);
+ drm_free(drm_get_drawable_info(dev, draw.handle),
+ sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
- if (bitfield)
- memcpy(bitfield, dev->drw_bitfield, bitfield_length *
- sizeof(*bitfield));
- drm_free(dev->drw_bitfield, sizeof(*bitfield) *
- dev->drw_bitfield_length, DRM_MEM_BUFS);
- dev->drw_bitfield = bitfield;
- dev->drw_bitfield_length = bitfield_length;
-
- if (info != dev->drw_info) {
- if (info)
- memcpy(info, dev->drw_info, info_length *
- sizeof(*info));
- drm_free(dev->drw_info, sizeof(*info) *
- dev->drw_info_length, DRM_MEM_BUFS);
- dev->drw_info = info;
- dev->drw_info_length = info_length;
- }
-
- spin_unlock_irqrestore(&dev->drw_lock, irqflags);
- }
+ idr_remove(&dev->drw_idr, draw.handle);
+ spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("%d\n", draw.handle);
return 0;
}
-int drm_update_drawable_info(DRM_IOCTL_ARGS) {
+int drm_update_drawable_info(DRM_IOCTL_ARGS)
+{
DRM_DEVICE;
- drm_update_draw_t update;
- unsigned int id, idx, shift;
- u32 *bitfield = dev->drw_bitfield;
- unsigned long irqflags, bitfield_length = dev->drw_bitfield_length;
- drm_drawable_info_t *info;
- drm_clip_rect_t *rects;
+ struct drm_update_draw update;
+ unsigned long irqflags;
+ struct drm_clip_rect *rects;
+ struct drm_drawable_info *info;
int err;
- DRM_COPY_FROM_USER_IOCTL(update, (drm_update_draw_t __user *) data,
+ DRM_COPY_FROM_USER_IOCTL(update, (struct drm_update_draw __user *) data,
sizeof(update));
- id = update.handle - 1;
- idx = id / (8 * sizeof(*bitfield));
- shift = id % (8 * sizeof(*bitfield));
-
- if (idx < 0 || idx >= bitfield_length ||
- !(bitfield[idx] & (1 << shift))) {
- DRM_ERROR("No such drawable %d\n", update.handle);
- return DRM_ERR(EINVAL);
- }
-
- info = dev->drw_info[id];
-
+ info = idr_find(&dev->drw_idr, update.handle);
if (!info) {
- info = drm_calloc(1, sizeof(drm_drawable_info_t), DRM_MEM_BUFS);
-
- if (!info) {
- DRM_ERROR("Failed to allocate drawable info memory\n");
- return DRM_ERR(ENOMEM);
+ info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS);
+ if (!info)
+ return -ENOMEM;
+ if (IS_ERR(idr_replace(&dev->drw_idr, info, update.handle))) {
+ DRM_ERROR("No such drawable %d\n", update.handle);
+ drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+ return -EINVAL;
}
}
switch (update.type) {
case DRM_DRAWABLE_CLIPRECTS:
if (update.num != info->num_rects) {
- rects = drm_alloc(update.num * sizeof(drm_clip_rect_t),
+ rects = drm_alloc(update.num * sizeof(struct drm_clip_rect),
DRM_MEM_BUFS);
} else
rects = info->rects;
@@ -277,7 +135,7 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) {
}
if (update.num && DRM_COPY_FROM_USER(rects,
- (drm_clip_rect_t __user *)
+ (struct drm_clip_rect __user *)
(unsigned long)update.data,
update.num *
sizeof(*rects))) {
@@ -290,17 +148,16 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) {
if (rects != info->rects) {
drm_free(info->rects, info->num_rects *
- sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ sizeof(struct drm_clip_rect), DRM_MEM_BUFS);
}
info->rects = rects;
info->num_rects = update.num;
- dev->drw_info[id] = info;
spin_unlock_irqrestore(&dev->drw_lock, irqflags);
DRM_DEBUG("Updated %d cliprects for drawable %d\n",
- info->num_rects, id);
+ info->num_rects, update.handle);
break;
default:
DRM_ERROR("Invalid update type %d\n", update.type);
@@ -310,11 +167,9 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS) {
return 0;
error:
- if (!dev->drw_info[id])
- drm_free(info, sizeof(*info), DRM_MEM_BUFS);
- else if (rects != dev->drw_info[id]->rects)
- drm_free(rects, update.num *
- sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+ if (rects != info->rects)
+ drm_free(rects, update.num * sizeof(struct drm_clip_rect),
+ DRM_MEM_BUFS);
return err;
}
@@ -322,20 +177,27 @@ error:
/**
* Caller must hold the drawable spinlock!
*/
-drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id) {
- u32 *bitfield = dev->drw_bitfield;
- unsigned int idx, shift;
-
- id--;
- idx = id / (8 * sizeof(*bitfield));
- shift = id % (8 * sizeof(*bitfield));
-
- if (idx < 0 || idx >= dev->drw_bitfield_length ||
- !(bitfield[idx] & (1 << shift))) {
- DRM_DEBUG("No such drawable %d\n", id);
- return NULL;
+struct drm_drawable_info *drm_get_drawable_info(struct drm_device *dev, drm_drawable_t id)
+{
+ return idr_find(&dev->drw_idr, id);
+}
+EXPORT_SYMBOL(drm_get_drawable_info);
+
+static int drm_drawable_free(int idr, void *p, void *data)
+{
+ struct drm_drawable_info *info = p;
+
+ if (info) {
+ drm_free(info->rects, info->num_rects *
+ sizeof(struct drm_clip_rect), DRM_MEM_BUFS);
+ drm_free(info, sizeof(*info), DRM_MEM_BUFS);
}
- return dev->drw_info[id];
+ return 0;
+}
+
+void drm_drawable_free_all(struct drm_device *dev)
+{
+ idr_for_each(&dev->drw_idr, drm_drawable_free, NULL);
+ idr_remove_all(&dev->drw_idr);
}
-EXPORT_SYMBOL(drm_get_drawable_info);
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 8e77b7ed0f44..19994cd865de 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -129,11 +129,11 @@ static drm_ioctl_desc_t drm_ioctls[] = {
*
* \sa drm_device
*/
-int drm_lastclose(drm_device_t * dev)
+int drm_lastclose(struct drm_device * dev)
{
- drm_magic_entry_t *pt, *next;
- drm_map_list_t *r_list;
- drm_vma_entry_t *vma, *vma_next;
+ struct drm_magic_entry *pt, *next;
+ struct drm_map_list *r_list, *list_t;
+ struct drm_vma_entry *vma, *vma_temp;
int i;
DRM_DEBUG("\n");
@@ -151,19 +151,10 @@ int drm_lastclose(drm_device_t * dev)
if (dev->irq_enabled)
drm_irq_uninstall(dev);
- /* Free drawable information memory */
- for (i = 0; i < dev->drw_bitfield_length / sizeof(*dev->drw_bitfield);
- i++) {
- drm_drawable_info_t *info = drm_get_drawable_info(dev, i);
-
- if (info) {
- drm_free(info->rects, info->num_rects *
- sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
- drm_free(info, sizeof(*info), DRM_MEM_BUFS);
- }
- }
-
mutex_lock(&dev->struct_mutex);
+
+ /* Free drawable information memory */
+ drm_drawable_free_all(dev);
del_timer(&dev->timer);
/* Clear pid list */
@@ -178,19 +169,17 @@ int drm_lastclose(drm_device_t * dev)
/* Clear AGP information */
if (drm_core_has_AGP(dev) && dev->agp) {
- drm_agp_mem_t *entry;
- drm_agp_mem_t *nexte;
+ struct drm_agp_mem *entry, *tempe;
/* Remove AGP resources, but leave dev->agp
intact until drv_cleanup is called. */
- for (entry = dev->agp->memory; entry; entry = nexte) {
- nexte = entry->next;
+ list_for_each_entry_safe(entry, tempe, &dev->agp->memory, head) {
if (entry->bound)
drm_unbind_agp(entry->memory);
drm_free_agp(entry->memory, entry->pages);
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
}
- dev->agp->memory = NULL;
+ INIT_LIST_HEAD(&dev->agp->memory);
if (dev->agp->acquired)
drm_agp_release(dev);
@@ -204,20 +193,14 @@ int drm_lastclose(drm_device_t * dev)
}
/* Clear vma list (only built for debugging) */
- if (dev->vmalist) {
- for (vma = dev->vmalist; vma; vma = vma_next) {
- vma_next = vma->next;
- drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
- }
- dev->vmalist = NULL;
+ list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) {
+ list_del(&vma->head);
+ drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
}
- if (dev->maplist) {
- while (!list_empty(&dev->maplist->head)) {
- struct list_head *list = dev->maplist->head.next;
- r_list = list_entry(list, drm_map_list_t, head);
- drm_rmmap_locked(dev, r_list->map);
- }
+ list_for_each_entry_safe(r_list, list_t, &dev->maplist, head) {
+ drm_rmmap_locked(dev, r_list->map);
+ r_list = NULL;
}
if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) {
@@ -298,7 +281,7 @@ EXPORT_SYMBOL(drm_init);
*
* \sa drm_init
*/
-static void drm_cleanup(drm_device_t * dev)
+static void drm_cleanup(struct drm_device * dev)
{
DRM_DEBUG("\n");
@@ -309,11 +292,7 @@ static void drm_cleanup(drm_device_t * dev)
drm_lastclose(dev);
- if (dev->maplist) {
- drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
- dev->maplist = NULL;
- drm_ht_remove(&dev->map_hash);
- }
+ drm_ht_remove(&dev->map_hash);
drm_ctxbitmap_cleanup(dev);
@@ -342,8 +321,8 @@ static void drm_cleanup(drm_device_t * dev)
void drm_exit(struct drm_driver *driver)
{
int i;
- drm_device_t *dev = NULL;
- drm_head_t *head;
+ struct drm_device *dev = NULL;
+ struct drm_head *head;
DRM_DEBUG("\n");
@@ -442,10 +421,10 @@ module_exit(drm_core_exit);
static int drm_version(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_version_t __user *argp = (void __user *)arg;
- drm_version_t version;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_version __user *argp = (void __user *)arg;
+ struct drm_version version;
int len;
if (copy_from_user(&version, argp, sizeof(version)))
@@ -478,8 +457,8 @@ static int drm_version(struct inode *inode, struct file *filp,
int drm_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_ioctl_desc_t *ioctl;
drm_ioctl_t *func;
unsigned int nr = DRM_IOCTL_NR(cmd);
@@ -529,3 +508,17 @@ int drm_ioctl(struct inode *inode, struct file *filp,
}
EXPORT_SYMBOL(drm_ioctl);
+
+drm_local_map_t *drm_getsarea(struct drm_device *dev)
+{
+ struct drm_map_list *entry;
+
+ list_for_each_entry(entry, &dev->maplist, head) {
+ if (entry->map && entry->map->type == _DRM_SHM &&
+ (entry->map->flags & _DRM_CONTAINS_LOCK)) {
+ return entry->map;
+ }
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(drm_getsarea);
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 3b159cab3bc8..7bc51bac450d 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -39,9 +39,9 @@
#include <linux/poll.h>
static int drm_open_helper(struct inode *inode, struct file *filp,
- drm_device_t * dev);
+ struct drm_device * dev);
-static int drm_setup(drm_device_t * dev)
+static int drm_setup(struct drm_device * dev)
{
drm_local_map_t *map;
int i;
@@ -79,13 +79,6 @@ static int drm_setup(drm_device_t * dev)
drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
INIT_LIST_HEAD(&dev->magicfree);
- dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
- if (dev->ctxlist == NULL)
- return -ENOMEM;
- memset(dev->ctxlist, 0, sizeof(*dev->ctxlist));
- INIT_LIST_HEAD(&dev->ctxlist->head);
-
- dev->vmalist = NULL;
dev->sigdata.lock = NULL;
init_waitqueue_head(&dev->lock.lock_queue);
dev->queue_count = 0;
@@ -135,7 +128,7 @@ static int drm_setup(drm_device_t * dev)
*/
int drm_open(struct inode *inode, struct file *filp)
{
- drm_device_t *dev = NULL;
+ struct drm_device *dev = NULL;
int minor = iminor(inode);
int retcode = 0;
@@ -174,7 +167,7 @@ EXPORT_SYMBOL(drm_open);
*/
int drm_stub_open(struct inode *inode, struct file *filp)
{
- drm_device_t *dev = NULL;
+ struct drm_device *dev = NULL;
int minor = iminor(inode);
int err = -ENODEV;
const struct file_operations *old_fops;
@@ -230,10 +223,10 @@ static int drm_cpu_valid(void)
* filp and add it into the double linked list in \p dev.
*/
static int drm_open_helper(struct inode *inode, struct file *filp,
- drm_device_t * dev)
+ struct drm_device * dev)
{
int minor = iminor(inode);
- drm_file_t *priv;
+ struct drm_file *priv;
int ret;
if (filp->f_flags & O_EXCL)
@@ -258,6 +251,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
priv->authenticated = capable(CAP_SYS_ADMIN);
priv->lock_count = 0;
+ INIT_LIST_HEAD(&priv->lhead);
+
if (dev->driver->open) {
ret = dev->driver->open(dev, priv);
if (ret < 0)
@@ -265,19 +260,10 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
}
mutex_lock(&dev->struct_mutex);
- if (!dev->file_last) {
- priv->next = NULL;
- priv->prev = NULL;
- dev->file_first = priv;
- dev->file_last = priv;
- /* first opener automatically becomes master */
+ if (list_empty(&dev->filelist))
priv->master = 1;
- } else {
- priv->next = NULL;
- priv->prev = dev->file_last;
- dev->file_last->next = priv;
- dev->file_last = priv;
- }
+
+ list_add(&priv->lhead, &dev->filelist);
mutex_unlock(&dev->struct_mutex);
#ifdef __alpha__
@@ -309,8 +295,8 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
/** No-op. */
int drm_fasync(int fd, struct file *filp, int on)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
int retcode;
DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
@@ -336,8 +322,8 @@ EXPORT_SYMBOL(drm_fasync);
*/
int drm_release(struct inode *inode, struct file *filp)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev;
int retcode = 0;
lock_kernel();
@@ -414,10 +400,10 @@ int drm_release(struct inode *inode, struct file *filp)
drm_fasync(-1, filp, 0);
mutex_lock(&dev->ctxlist_mutex);
- if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) {
- drm_ctx_list_t *pos, *n;
+ if (!list_empty(&dev->ctxlist)) {
+ struct drm_ctx_list *pos, *n;
- list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) {
+ list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
if (pos->tag == priv &&
pos->handle != DRM_KERNEL_CONTEXT) {
if (dev->driver->context_dtor)
@@ -436,22 +422,12 @@ int drm_release(struct inode *inode, struct file *filp)
mutex_lock(&dev->struct_mutex);
if (priv->remove_auth_on_close == 1) {
- drm_file_t *temp = dev->file_first;
- while (temp) {
+ struct drm_file *temp;
+
+ list_for_each_entry(temp, &dev->filelist, lhead)
temp->authenticated = 0;
- temp = temp->next;
- }
- }
- if (priv->prev) {
- priv->prev->next = priv->next;
- } else {
- dev->file_first = priv->next;
- }
- if (priv->next) {
- priv->next->prev = priv->prev;
- } else {
- dev->file_last = priv->prev;
}
+ list_del(&priv->lhead);
mutex_unlock(&dev->struct_mutex);
if (dev->driver->postclose)
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
index 31acb621dcce..3ad319070704 100644
--- a/drivers/char/drm/drm_hashtab.c
+++ b/drivers/char/drm/drm_hashtab.c
@@ -36,7 +36,7 @@
#include "drm_hashtab.h"
#include <linux/hash.h>
-int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
+int drm_ht_create(struct drm_open_hash *ht, unsigned int order)
{
unsigned int i;
@@ -63,9 +63,9 @@ int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
return 0;
}
-void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key)
+void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key)
{
- drm_hash_item_t *entry;
+ struct drm_hash_item *entry;
struct hlist_head *h_list;
struct hlist_node *list;
unsigned int hashed_key;
@@ -75,15 +75,15 @@ void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key)
DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
h_list = &ht->table[hashed_key];
hlist_for_each(list, h_list) {
- entry = hlist_entry(list, drm_hash_item_t, head);
+ entry = hlist_entry(list, struct drm_hash_item, head);
DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
}
}
-static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht,
+static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht,
unsigned long key)
{
- drm_hash_item_t *entry;
+ struct drm_hash_item *entry;
struct hlist_head *h_list;
struct hlist_node *list;
unsigned int hashed_key;
@@ -91,7 +91,7 @@ static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht,
hashed_key = hash_long(key, ht->order);
h_list = &ht->table[hashed_key];
hlist_for_each(list, h_list) {
- entry = hlist_entry(list, drm_hash_item_t, head);
+ entry = hlist_entry(list, struct drm_hash_item, head);
if (entry->key == key)
return list;
if (entry->key > key)
@@ -101,9 +101,9 @@ static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht,
}
-int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item)
{
- drm_hash_item_t *entry;
+ struct drm_hash_item *entry;
struct hlist_head *h_list;
struct hlist_node *list, *parent;
unsigned int hashed_key;
@@ -113,7 +113,7 @@ int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
h_list = &ht->table[hashed_key];
parent = NULL;
hlist_for_each(list, h_list) {
- entry = hlist_entry(list, drm_hash_item_t, head);
+ entry = hlist_entry(list, struct drm_hash_item, head);
if (entry->key == key)
return -EINVAL;
if (entry->key > key)
@@ -132,7 +132,7 @@ int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
* Just insert an item and return any "bits" bit key that hasn't been
* used before.
*/
-int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
unsigned long seed, int bits, int shift,
unsigned long add)
{
@@ -156,8 +156,8 @@ int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
return 0;
}
-int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key,
- drm_hash_item_t **item)
+int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key,
+ struct drm_hash_item **item)
{
struct hlist_node *list;
@@ -165,11 +165,11 @@ int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key,
if (!list)
return -EINVAL;
- *item = hlist_entry(list, drm_hash_item_t, head);
+ *item = hlist_entry(list, struct drm_hash_item, head);
return 0;
}
-int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key)
+int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key)
{
struct hlist_node *list;
@@ -182,14 +182,14 @@ int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key)
return -EINVAL;
}
-int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item)
{
hlist_del_init(&item->head);
ht->fill--;
return 0;
}
-void drm_ht_remove(drm_open_hash_t *ht)
+void drm_ht_remove(struct drm_open_hash *ht)
{
if (ht->table) {
if (ht->use_vmalloc)
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
index 613091c970af..0f1376774168 100644
--- a/drivers/char/drm/drm_hashtab.h
+++ b/drivers/char/drm/drm_hashtab.h
@@ -37,31 +37,31 @@
#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
-typedef struct drm_hash_item{
+struct drm_hash_item {
struct hlist_node head;
unsigned long key;
-} drm_hash_item_t;
+};
-typedef struct drm_open_hash{
+struct drm_open_hash {
unsigned int size;
unsigned int order;
unsigned int fill;
struct hlist_head *table;
int use_vmalloc;
-} drm_open_hash_t;
+};
-extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order);
-extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item);
-extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+extern int drm_ht_create(struct drm_open_hash *ht, unsigned int order);
+extern int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item);
+extern int drm_ht_just_insert_please(struct drm_open_hash *ht, struct drm_hash_item *item,
unsigned long seed, int bits, int shift,
unsigned long add);
-extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item);
+extern int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, struct drm_hash_item **item);
-extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key);
-extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key);
-extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item);
-extern void drm_ht_remove(drm_open_hash_t *ht);
+extern void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key);
+extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key);
+extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item);
+extern void drm_ht_remove(struct drm_open_hash *ht);
#endif
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index fafeb34f89d5..462f46f2049a 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -82,7 +82,7 @@ static int compat_drm_version(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_version32_t v32;
- drm_version_t __user *version;
+ struct drm_version __user *version;
int err;
if (copy_from_user(&v32, (void __user *)arg, sizeof(v32)))
@@ -129,7 +129,7 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_unique32_t uq32;
- drm_unique_t __user *u;
+ struct drm_unique __user *u;
int err;
if (copy_from_user(&uq32, (void __user *)arg, sizeof(uq32)))
@@ -159,7 +159,7 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_unique32_t uq32;
- drm_unique_t __user *u;
+ struct drm_unique __user *u;
if (copy_from_user(&uq32, (void __user *)arg, sizeof(uq32)))
return -EFAULT;
@@ -179,8 +179,8 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd,
typedef struct drm_map32 {
u32 offset; /**< Requested physical address (0 for SAREA)*/
u32 size; /**< Requested physical size (bytes) */
- drm_map_type_t type; /**< Type of memory to map */
- drm_map_flags_t flags; /**< Flags */
+ enum drm_map_type type; /**< Type of memory to map */
+ enum drm_map_flags flags; /**< Flags */
u32 handle; /**< User-space: "Handle" to pass to mmap() */
int mtrr; /**< MTRR slot used */
} drm_map32_t;
@@ -190,7 +190,7 @@ static int compat_drm_getmap(struct file *file, unsigned int cmd,
{
drm_map32_t __user *argp = (void __user *)arg;
drm_map32_t m32;
- drm_map_t __user *map;
+ struct drm_map __user *map;
int idx, err;
void *handle;
@@ -228,7 +228,7 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd,
{
drm_map32_t __user *argp = (void __user *)arg;
drm_map32_t m32;
- drm_map_t __user *map;
+ struct drm_map __user *map;
int err;
void *handle;
@@ -270,7 +270,7 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_map32_t __user *argp = (void __user *)arg;
- drm_map_t __user *map;
+ struct drm_map __user *map;
u32 handle;
if (get_user(handle, &argp->handle))
@@ -300,7 +300,7 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd,
{
drm_client32_t c32;
drm_client32_t __user *argp = (void __user *)arg;
- drm_client_t __user *client;
+ struct drm_client __user *client;
int idx, err;
if (get_user(idx, &argp->idx))
@@ -333,7 +333,7 @@ typedef struct drm_stats32 {
u32 count;
struct {
u32 value;
- drm_stat_type_t type;
+ enum drm_stat_type type;
} data[15];
} drm_stats32_t;
@@ -342,7 +342,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd,
{
drm_stats32_t s32;
drm_stats32_t __user *argp = (void __user *)arg;
- drm_stats_t __user *stats;
+ struct drm_stats __user *stats;
int i, err;
stats = compat_alloc_user_space(sizeof(*stats));
@@ -379,7 +379,7 @@ static int compat_drm_addbufs(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_buf_desc32_t __user *argp = (void __user *)arg;
- drm_buf_desc_t __user *buf;
+ struct drm_buf_desc __user *buf;
int err;
unsigned long agp_start;
@@ -411,7 +411,7 @@ static int compat_drm_markbufs(struct file *file, unsigned int cmd,
{
drm_buf_desc32_t b32;
drm_buf_desc32_t __user *argp = (void __user *)arg;
- drm_buf_desc_t __user *buf;
+ struct drm_buf_desc __user *buf;
if (copy_from_user(&b32, argp, sizeof(b32)))
return -EFAULT;
@@ -440,8 +440,8 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd,
drm_buf_info32_t req32;
drm_buf_info32_t __user *argp = (void __user *)arg;
drm_buf_desc32_t __user *to;
- drm_buf_info_t __user *request;
- drm_buf_desc_t __user *list;
+ struct drm_buf_info __user *request;
+ struct drm_buf_desc __user *list;
size_t nbytes;
int i, err;
int count, actual;
@@ -457,11 +457,11 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd,
&& !access_ok(VERIFY_WRITE, to, count * sizeof(drm_buf_desc32_t)))
return -EFAULT;
- nbytes = sizeof(*request) + count * sizeof(drm_buf_desc_t);
+ nbytes = sizeof(*request) + count * sizeof(struct drm_buf_desc);
request = compat_alloc_user_space(nbytes);
if (!access_ok(VERIFY_WRITE, request, nbytes))
return -EFAULT;
- list = (drm_buf_desc_t *) (request + 1);
+ list = (struct drm_buf_desc *) (request + 1);
if (__put_user(count, &request->count)
|| __put_user(list, &request->list))
@@ -477,7 +477,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd,
if (count >= actual)
for (i = 0; i < actual; ++i)
if (__copy_in_user(&to[i], &list[i],
- offsetof(drm_buf_desc_t, flags)))
+ offsetof(struct drm_buf_desc, flags)))
return -EFAULT;
if (__put_user(actual, &argp->count))
@@ -505,8 +505,8 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
drm_buf_map32_t __user *argp = (void __user *)arg;
drm_buf_map32_t req32;
drm_buf_pub32_t __user *list32;
- drm_buf_map_t __user *request;
- drm_buf_pub_t __user *list;
+ struct drm_buf_map __user *request;
+ struct drm_buf_pub __user *list;
int i, err;
int count, actual;
size_t nbytes;
@@ -519,11 +519,11 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
if (count < 0)
return -EINVAL;
- nbytes = sizeof(*request) + count * sizeof(drm_buf_pub_t);
+ nbytes = sizeof(*request) + count * sizeof(struct drm_buf_pub);
request = compat_alloc_user_space(nbytes);
if (!access_ok(VERIFY_WRITE, request, nbytes))
return -EFAULT;
- list = (drm_buf_pub_t *) (request + 1);
+ list = (struct drm_buf_pub *) (request + 1);
if (__put_user(count, &request->count)
|| __put_user(list, &request->list))
@@ -539,7 +539,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
if (count >= actual)
for (i = 0; i < actual; ++i)
if (__copy_in_user(&list32[i], &list[i],
- offsetof(drm_buf_pub_t, address))
+ offsetof(struct drm_buf_pub, address))
|| __get_user(addr, &list[i].address)
|| __put_user((unsigned long)addr,
&list32[i].address))
@@ -562,7 +562,7 @@ static int compat_drm_freebufs(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_buf_free32_t req32;
- drm_buf_free_t __user *request;
+ struct drm_buf_free __user *request;
drm_buf_free32_t __user *argp = (void __user *)arg;
if (copy_from_user(&req32, argp, sizeof(req32)))
@@ -589,7 +589,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_ctx_priv_map32_t req32;
- drm_ctx_priv_map_t __user *request;
+ struct drm_ctx_priv_map __user *request;
drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
if (copy_from_user(&req32, argp, sizeof(req32)))
@@ -610,7 +610,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
unsigned long arg)
{
- drm_ctx_priv_map_t __user *request;
+ struct drm_ctx_priv_map __user *request;
drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
int err;
unsigned int ctx_id;
@@ -648,7 +648,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd,
{
drm_ctx_res32_t __user *argp = (void __user *)arg;
drm_ctx_res32_t res32;
- drm_ctx_res_t __user *res;
+ struct drm_ctx_res __user *res;
int err;
if (copy_from_user(&res32, argp, sizeof(res32)))
@@ -658,7 +658,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd,
if (!access_ok(VERIFY_WRITE, res, sizeof(*res)))
return -EFAULT;
if (__put_user(res32.count, &res->count)
- || __put_user((drm_ctx_t __user *) (unsigned long)res32.contexts,
+ || __put_user((struct drm_ctx __user *) (unsigned long)res32.contexts,
&res->contexts))
return -EFAULT;
@@ -679,7 +679,7 @@ typedef struct drm_dma32 {
int send_count; /**< Number of buffers to send */
u32 send_indices; /**< List of handles to buffers */
u32 send_sizes; /**< Lengths of data to send */
- drm_dma_flags_t flags; /**< Flags */
+ enum drm_dma_flags flags; /**< Flags */
int request_count; /**< Number of buffers requested */
int request_size; /**< Desired size for buffers */
u32 request_indices; /**< Buffer information */
@@ -692,7 +692,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd,
{
drm_dma32_t d32;
drm_dma32_t __user *argp = (void __user *)arg;
- drm_dma_t __user *d;
+ struct drm_dma __user *d;
int err;
if (copy_from_user(&d32, argp, sizeof(d32)))
@@ -740,7 +740,7 @@ static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
{
drm_agp_mode32_t __user *argp = (void __user *)arg;
drm_agp_mode32_t m32;
- drm_agp_mode_t __user *mode;
+ struct drm_agp_mode __user *mode;
if (get_user(m32.mode, &argp->mode))
return -EFAULT;
@@ -772,7 +772,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd,
{
drm_agp_info32_t __user *argp = (void __user *)arg;
drm_agp_info32_t i32;
- drm_agp_info_t __user *info;
+ struct drm_agp_info __user *info;
int err;
info = compat_alloc_user_space(sizeof(*info));
@@ -813,7 +813,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
{
drm_agp_buffer32_t __user *argp = (void __user *)arg;
drm_agp_buffer32_t req32;
- drm_agp_buffer_t __user *request;
+ struct drm_agp_buffer __user *request;
int err;
if (copy_from_user(&req32, argp, sizeof(req32)))
@@ -845,7 +845,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_agp_buffer32_t __user *argp = (void __user *)arg;
- drm_agp_buffer_t __user *request;
+ struct drm_agp_buffer __user *request;
u32 handle;
request = compat_alloc_user_space(sizeof(*request));
@@ -868,7 +868,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
{
drm_agp_binding32_t __user *argp = (void __user *)arg;
drm_agp_binding32_t req32;
- drm_agp_binding_t __user *request;
+ struct drm_agp_binding __user *request;
if (copy_from_user(&req32, argp, sizeof(req32)))
return -EFAULT;
@@ -887,7 +887,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_agp_binding32_t __user *argp = (void __user *)arg;
- drm_agp_binding_t __user *request;
+ struct drm_agp_binding __user *request;
u32 handle;
request = compat_alloc_user_space(sizeof(*request));
@@ -910,7 +910,7 @@ static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_scatter_gather32_t __user *argp = (void __user *)arg;
- drm_scatter_gather_t __user *request;
+ struct drm_scatter_gather __user *request;
int err;
unsigned long x;
@@ -938,7 +938,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
unsigned long arg)
{
drm_scatter_gather32_t __user *argp = (void __user *)arg;
- drm_scatter_gather_t __user *request;
+ struct drm_scatter_gather __user *request;
unsigned long x;
request = compat_alloc_user_space(sizeof(*request));
@@ -953,13 +953,13 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd,
}
struct drm_wait_vblank_request32 {
- drm_vblank_seq_type_t type;
+ enum drm_vblank_seq_type type;
unsigned int sequence;
u32 signal;
};
struct drm_wait_vblank_reply32 {
- drm_vblank_seq_type_t type;
+ enum drm_vblank_seq_type type;
unsigned int sequence;
s32 tval_sec;
s32 tval_usec;
@@ -975,7 +975,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
{
drm_wait_vblank32_t __user *argp = (void __user *)arg;
drm_wait_vblank32_t req32;
- drm_wait_vblank_t __user *request;
+ union drm_wait_vblank __user *request;
int err;
if (copy_from_user(&req32, argp, sizeof(req32)))
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
index 565895547d75..b195e102e737 100644
--- a/drivers/char/drm/drm_ioctl.c
+++ b/drivers/char/drm/drm_ioctl.c
@@ -52,10 +52,10 @@
int drm_getunique(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_unique_t __user *argp = (void __user *)arg;
- drm_unique_t u;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_unique __user *argp = (void __user *)arg;
+ struct drm_unique u;
if (copy_from_user(&u, argp, sizeof(u)))
return -EFAULT;
@@ -86,15 +86,15 @@ int drm_getunique(struct inode *inode, struct file *filp,
int drm_setunique(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_unique_t u;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_unique u;
int domain, bus, slot, func, ret;
if (dev->unique_len || dev->unique)
return -EBUSY;
- if (copy_from_user(&u, (drm_unique_t __user *) arg, sizeof(u)))
+ if (copy_from_user(&u, (struct drm_unique __user *) arg, sizeof(u)))
return -EFAULT;
if (!u.unique_len || u.unique_len > 1024)
@@ -136,7 +136,7 @@ int drm_setunique(struct inode *inode, struct file *filp,
return 0;
}
-static int drm_set_busid(drm_device_t * dev)
+static int drm_set_busid(struct drm_device * dev)
{
int len;
@@ -184,11 +184,11 @@ static int drm_set_busid(drm_device_t * dev)
int drm_getmap(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_map_t __user *argp = (void __user *)arg;
- drm_map_t map;
- drm_map_list_t *r_list = NULL;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_map __user *argp = (void __user *)arg;
+ struct drm_map map;
+ struct drm_map_list *r_list = NULL;
struct list_head *list;
int idx;
int i;
@@ -204,9 +204,9 @@ int drm_getmap(struct inode *inode, struct file *filp,
}
i = 0;
- list_for_each(list, &dev->maplist->head) {
+ list_for_each(list, &dev->maplist) {
if (i == idx) {
- r_list = list_entry(list, drm_map_list_t, head);
+ r_list = list_entry(list, struct drm_map_list, head);
break;
}
i++;
@@ -245,11 +245,11 @@ int drm_getmap(struct inode *inode, struct file *filp,
int drm_getclient(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_client_t __user *argp = (drm_client_t __user *)arg;
- drm_client_t client;
- drm_file_t *pt;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_client __user *argp = (struct drm_client __user *)arg;
+ struct drm_client client;
+ struct drm_file *pt;
int idx;
int i;
@@ -257,12 +257,18 @@ int drm_getclient(struct inode *inode, struct file *filp,
return -EFAULT;
idx = client.idx;
mutex_lock(&dev->struct_mutex);
- for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) ;
-
- if (!pt) {
+
+ if (list_empty(&dev->filelist)) {
mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
+
+ i = 0;
+ list_for_each_entry(pt, &dev->filelist, lhead) {
+ if (i++ >= idx)
+ break;
+ }
+
client.auth = pt->authenticated;
client.pid = pt->pid;
client.uid = pt->uid;
@@ -288,9 +294,9 @@ int drm_getclient(struct inode *inode, struct file *filp,
int drm_getstats(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_stats_t stats;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_stats stats;
int i;
memset(&stats, 0, sizeof(stats));
@@ -310,7 +316,7 @@ int drm_getstats(struct inode *inode, struct file *filp,
mutex_unlock(&dev->struct_mutex);
- if (copy_to_user((drm_stats_t __user *) arg, &stats, sizeof(stats)))
+ if (copy_to_user((struct drm_stats __user *) arg, &stats, sizeof(stats)))
return -EFAULT;
return 0;
}
@@ -329,10 +335,10 @@ int drm_getstats(struct inode *inode, struct file *filp,
int drm_setversion(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_set_version_t sv;
- drm_set_version_t retv;
+ struct drm_set_version sv;
+ struct drm_set_version retv;
int if_version;
- drm_set_version_t __user *argp = (void __user *)data;
+ struct drm_set_version __user *argp = (void __user *)data;
int ret;
if (copy_from_user(&sv, argp, sizeof(sv)))
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 2e75331fd83e..871d2fde09b3 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -53,10 +53,10 @@
int drm_irq_by_busid(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_irq_busid_t __user *argp = (void __user *)arg;
- drm_irq_busid_t p;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_irq_busid __user *argp = (void __user *)arg;
+ struct drm_irq_busid p;
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
@@ -87,7 +87,7 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
* before and after the installation.
*/
-static int drm_irq_install(drm_device_t * dev)
+static int drm_irq_install(struct drm_device * dev)
{
int ret;
unsigned long sh_flags = 0;
@@ -120,8 +120,8 @@ static int drm_irq_install(drm_device_t * dev)
spin_lock_init(&dev->vbl_lock);
- INIT_LIST_HEAD(&dev->vbl_sigs.head);
- INIT_LIST_HEAD(&dev->vbl_sigs2.head);
+ INIT_LIST_HEAD(&dev->vbl_sigs);
+ INIT_LIST_HEAD(&dev->vbl_sigs2);
dev->vbl_pending = 0;
}
@@ -155,7 +155,7 @@ static int drm_irq_install(drm_device_t * dev)
*
* Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq.
*/
-int drm_irq_uninstall(drm_device_t * dev)
+int drm_irq_uninstall(struct drm_device * dev)
{
int irq_enabled;
@@ -197,13 +197,13 @@ EXPORT_SYMBOL(drm_irq_uninstall);
int drm_control(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_control_t ctl;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_control ctl;
/* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */
- if (copy_from_user(&ctl, (drm_control_t __user *) arg, sizeof(ctl)))
+ if (copy_from_user(&ctl, (struct drm_control __user *) arg, sizeof(ctl)))
return -EFAULT;
switch (ctl.func) {
@@ -244,10 +244,10 @@ int drm_control(struct inode *inode, struct file *filp,
*/
int drm_wait_vblank(DRM_IOCTL_ARGS)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_wait_vblank_t __user *argp = (void __user *)data;
- drm_wait_vblank_t vblwait;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ union drm_wait_vblank __user *argp = (void __user *)data;
+ union drm_wait_vblank vblwait;
struct timeval now;
int ret = 0;
unsigned int flags, seq;
@@ -292,9 +292,9 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
if (flags & _DRM_VBLANK_SIGNAL) {
unsigned long irqflags;
- drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
+ struct list_head *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
? &dev->vbl_sigs2 : &dev->vbl_sigs;
- drm_vbl_sig_t *vbl_sig;
+ struct drm_vbl_sig *vbl_sig;
spin_lock_irqsave(&dev->vbl_lock, irqflags);
@@ -302,7 +302,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
* for the same vblank sequence number; nothing to be done in
* that case
*/
- list_for_each_entry(vbl_sig, &vbl_sigs->head, head) {
+ list_for_each_entry(vbl_sig, vbl_sigs, head) {
if (vbl_sig->sequence == vblwait.request.sequence
&& vbl_sig->info.si_signo == vblwait.request.signal
&& vbl_sig->task == current) {
@@ -324,7 +324,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
if (!
(vbl_sig =
- drm_alloc(sizeof(drm_vbl_sig_t), DRM_MEM_DRIVER))) {
+ drm_alloc(sizeof(struct drm_vbl_sig), DRM_MEM_DRIVER))) {
return -ENOMEM;
}
@@ -336,7 +336,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
spin_lock_irqsave(&dev->vbl_lock, irqflags);
- list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
+ list_add_tail(&vbl_sig->head, vbl_sigs);
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
@@ -371,7 +371,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
*
* If a signal is not requested, then calls vblank_wait().
*/
-void drm_vbl_send_signals(drm_device_t * dev)
+void drm_vbl_send_signals(struct drm_device * dev)
{
unsigned long flags;
int i;
@@ -379,20 +379,18 @@ void drm_vbl_send_signals(drm_device_t * dev)
spin_lock_irqsave(&dev->vbl_lock, flags);
for (i = 0; i < 2; i++) {
- struct list_head *list, *tmp;
- drm_vbl_sig_t *vbl_sig;
- drm_vbl_sig_t *vbl_sigs = i ? &dev->vbl_sigs2 : &dev->vbl_sigs;
+ 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);
- list_for_each_safe(list, tmp, &vbl_sigs->head) {
- vbl_sig = list_entry(list, drm_vbl_sig_t, head);
+ 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(list);
+ list_del(&vbl_sig->head);
drm_free(vbl_sig, sizeof(*vbl_sig),
DRM_MEM_DRIVER);
@@ -418,7 +416,7 @@ EXPORT_SYMBOL(drm_vbl_send_signals);
*/
static void drm_locked_tasklet_func(unsigned long data)
{
- drm_device_t *dev = (drm_device_t*)data;
+ struct drm_device *dev = (struct drm_device *)data;
unsigned long irqflags;
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
@@ -455,7 +453,7 @@ static void drm_locked_tasklet_func(unsigned long data)
* context, it must not make any assumptions about this. Also, the HW lock will
* be held with the kernel context or any client context.
*/
-void drm_locked_tasklet(drm_device_t *dev, void (*func)(drm_device_t*))
+void drm_locked_tasklet(struct drm_device *dev, void (*func)(struct drm_device *))
{
unsigned long irqflags;
static DECLARE_TASKLET(drm_tasklet, drm_locked_tasklet_func, 0);
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index befd1af19dfe..c0534b5a8b78 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -51,15 +51,15 @@ static int drm_notifier(void *priv);
int drm_lock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
DECLARE_WAITQUEUE(entry, current);
- drm_lock_t lock;
+ struct drm_lock lock;
int ret = 0;
++priv->lock_count;
- if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
+ if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
return -EFAULT;
if (lock.context == DRM_KERNEL_CONTEXT) {
@@ -152,12 +152,12 @@ int drm_lock(struct inode *inode, struct file *filp,
int drm_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_lock_t lock;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_lock lock;
unsigned long irqflags;
- if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
+ if (copy_from_user(&lock, (struct drm_lock __user *) arg, sizeof(lock)))
return -EFAULT;
if (lock.context == DRM_KERNEL_CONTEXT) {
@@ -202,7 +202,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
*
* Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
*/
-int drm_lock_take(drm_lock_data_t *lock_data,
+int drm_lock_take(struct drm_lock_data *lock_data,
unsigned int context)
{
unsigned int old, new, prev;
@@ -251,7 +251,7 @@ int drm_lock_take(drm_lock_data_t *lock_data,
* Resets the lock file pointer.
* Marks the lock as held by the given context, via the \p cmpxchg instruction.
*/
-static int drm_lock_transfer(drm_lock_data_t *lock_data,
+static int drm_lock_transfer(struct drm_lock_data *lock_data,
unsigned int context)
{
unsigned int old, new, prev;
@@ -277,7 +277,7 @@ static int drm_lock_transfer(drm_lock_data_t *lock_data,
* Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
* waiting on the lock queue.
*/
-int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context)
+int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
{
unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
@@ -319,7 +319,7 @@ int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context)
*/
static int drm_notifier(void *priv)
{
- drm_sigdata_t *s = (drm_sigdata_t *) priv;
+ struct drm_sigdata *s = (struct drm_sigdata *) priv;
unsigned int old, new, prev;
/* Allow signal delivery if lock isn't held */
@@ -350,7 +350,7 @@ static int drm_notifier(void *priv)
* having to worry about starvation.
*/
-void drm_idlelock_take(drm_lock_data_t *lock_data)
+void drm_idlelock_take(struct drm_lock_data *lock_data)
{
int ret = 0;
@@ -369,7 +369,7 @@ void drm_idlelock_take(drm_lock_data_t *lock_data)
}
EXPORT_SYMBOL(drm_idlelock_take);
-void drm_idlelock_release(drm_lock_data_t *lock_data)
+void drm_idlelock_release(struct drm_lock_data *lock_data)
{
unsigned int old, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock;
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 92a867082376..93019901bd30 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -80,7 +80,7 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
#if __OS_HAS_AGP
static void *agp_remap(unsigned long offset, unsigned long size,
- drm_device_t * dev)
+ struct drm_device * dev)
{
unsigned long *phys_addr_map, i, num_pages =
PAGE_ALIGN(size) / PAGE_SIZE;
@@ -94,7 +94,7 @@ static void *agp_remap(unsigned long offset, unsigned long size,
offset -= dev->hose->mem_space->start;
#endif
- for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next)
+ list_for_each_entry(agpmem, &dev->agp->memory, head)
if (agpmem->bound <= offset
&& (agpmem->bound + (agpmem->pages << PAGE_SHIFT)) >=
(offset + size))
@@ -123,7 +123,7 @@ static void *agp_remap(unsigned long offset, unsigned long size,
}
/** Wrapper around agp_allocate_memory() */
-DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type)
+DRM_AGP_MEM *drm_alloc_agp(struct drm_device * dev, int pages, u32 type)
{
return drm_agp_allocate_memory(dev->agp->bridge, pages, type);
}
@@ -148,7 +148,7 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
#else /* __OS_HAS_AGP */
static inline void *agp_remap(unsigned long offset, unsigned long size,
- drm_device_t * dev)
+ struct drm_device * dev)
{
return NULL;
}
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 2ec1d9f26264..3e6bc14f7441 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -44,26 +44,26 @@
#include "drmP.h"
#include <linux/slab.h>
-unsigned long drm_mm_tail_space(drm_mm_t *mm)
+unsigned long drm_mm_tail_space(struct drm_mm *mm)
{
struct list_head *tail_node;
- drm_mm_node_t *entry;
+ struct drm_mm_node *entry;
tail_node = mm->ml_entry.prev;
- entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
if (!entry->free)
return 0;
return entry->size;
}
-int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
+int drm_mm_remove_space_from_tail(struct drm_mm *mm, unsigned long size)
{
struct list_head *tail_node;
- drm_mm_node_t *entry;
+ struct drm_mm_node *entry;
tail_node = mm->ml_entry.prev;
- entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
if (!entry->free)
return -ENOMEM;
@@ -75,13 +75,13 @@ int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
}
-static int drm_mm_create_tail_node(drm_mm_t *mm,
+static int drm_mm_create_tail_node(struct drm_mm *mm,
unsigned long start,
unsigned long size)
{
- drm_mm_node_t *child;
+ struct drm_mm_node *child;
- child = (drm_mm_node_t *)
+ child = (struct drm_mm_node *)
drm_alloc(sizeof(*child), DRM_MEM_MM);
if (!child)
return -ENOMEM;
@@ -98,13 +98,13 @@ static int drm_mm_create_tail_node(drm_mm_t *mm,
}
-int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
+int drm_mm_add_space_to_tail(struct drm_mm *mm, unsigned long size)
{
struct list_head *tail_node;
- drm_mm_node_t *entry;
+ struct drm_mm_node *entry;
tail_node = mm->ml_entry.prev;
- entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+ entry = list_entry(tail_node, struct drm_mm_node, ml_entry);
if (!entry->free) {
return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
}
@@ -112,12 +112,12 @@ int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
return 0;
}
-static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
+static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent,
unsigned long size)
{
- drm_mm_node_t *child;
+ struct drm_mm_node *child;
- child = (drm_mm_node_t *)
+ child = (struct drm_mm_node *)
drm_alloc(sizeof(*child), DRM_MEM_MM);
if (!child)
return NULL;
@@ -139,12 +139,12 @@ static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
-drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
+struct drm_mm_node *drm_mm_get_block(struct drm_mm_node * parent,
unsigned long size, unsigned alignment)
{
- drm_mm_node_t *align_splitoff = NULL;
- drm_mm_node_t *child;
+ struct drm_mm_node *align_splitoff = NULL;
+ struct drm_mm_node *child;
unsigned tmp = 0;
if (alignment)
@@ -175,26 +175,26 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
* Otherwise add to the free stack.
*/
-void drm_mm_put_block(drm_mm_node_t * cur)
+void drm_mm_put_block(struct drm_mm_node * cur)
{
- drm_mm_t *mm = cur->mm;
+ struct drm_mm *mm = cur->mm;
struct list_head *cur_head = &cur->ml_entry;
struct list_head *root_head = &mm->ml_entry;
- drm_mm_node_t *prev_node = NULL;
- drm_mm_node_t *next_node;
+ struct drm_mm_node *prev_node = NULL;
+ struct drm_mm_node *next_node;
int merged = 0;
if (cur_head->prev != root_head) {
- prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry);
+ prev_node = list_entry(cur_head->prev, struct drm_mm_node, ml_entry);
if (prev_node->free) {
prev_node->size += cur->size;
merged = 1;
}
}
if (cur_head->next != root_head) {
- next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry);
+ next_node = list_entry(cur_head->next, struct drm_mm_node, ml_entry);
if (next_node->free) {
if (merged) {
prev_node->size += next_node->size;
@@ -218,14 +218,14 @@ void drm_mm_put_block(drm_mm_node_t * cur)
}
}
-drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
+struct drm_mm_node *drm_mm_search_free(const struct drm_mm * mm,
unsigned long size,
unsigned alignment, int best_match)
{
struct list_head *list;
const struct list_head *free_stack = &mm->fl_entry;
- drm_mm_node_t *entry;
- drm_mm_node_t *best;
+ struct drm_mm_node *entry;
+ struct drm_mm_node *best;
unsigned long best_size;
unsigned wasted;
@@ -233,7 +233,7 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
best_size = ~0UL;
list_for_each(list, free_stack) {
- entry = list_entry(list, drm_mm_node_t, fl_entry);
+ entry = list_entry(list, struct drm_mm_node, fl_entry);
wasted = 0;
if (entry->size < size)
@@ -259,14 +259,14 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
return best;
}
-int drm_mm_clean(drm_mm_t * mm)
+int drm_mm_clean(struct drm_mm * mm)
{
struct list_head *head = &mm->ml_entry;
return (head->next->next == head);
}
-int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+int drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
{
INIT_LIST_HEAD(&mm->ml_entry);
INIT_LIST_HEAD(&mm->fl_entry);
@@ -275,12 +275,12 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
}
-void drm_mm_takedown(drm_mm_t * mm)
+void drm_mm_takedown(struct drm_mm * mm)
{
struct list_head *bnode = mm->fl_entry.next;
- drm_mm_node_t *entry;
+ struct drm_mm_node *entry;
- entry = list_entry(bnode, drm_mm_node_t, fl_entry);
+ entry = list_entry(bnode, struct drm_mm_node, fl_entry);
if (entry->ml_entry.next != &mm->ml_entry ||
entry->fl_entry.next != &mm->fl_entry) {
diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
index 0fe7b4497927..0b8d3433386d 100644
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -34,8 +34,8 @@
/** Read/write memory barrier */
#define DRM_MEMORYBARRIER() mb()
/** DRM device local declaration */
-#define DRM_DEVICE drm_file_t *priv = filp->private_data; \
- drm_device_t *dev = priv->head->dev
+#define DRM_DEVICE struct drm_file *priv = filp->private_data; \
+ struct drm_device *dev = priv->head->dev
/** IRQ handler arguments and return type and values */
#define DRM_IRQ_ARGS int irq, void *arg
@@ -96,24 +96,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
-/**
- * Get the pointer to the SAREA.
- *
- * Searches the SAREA on the mapping lists and points drm_device::sarea to it.
- */
-#define DRM_GETSAREA() \
-do { \
- drm_map_list_t *entry; \
- list_for_each_entry( entry, &dev->maplist->head, head ) { \
- if ( entry->map && \
- entry->map->type == _DRM_SHM && \
- (entry->map->flags & _DRM_CONTAINS_LOCK) ) { \
- dev_priv->sarea = entry->map; \
- break; \
- } \
- } \
-} while (0)
-
#define DRM_HZ HZ
#define DRM_WAIT_ON( ret, queue, timeout, condition ) \
diff --git a/drivers/char/drm/drm_pci.c b/drivers/char/drm/drm_pci.c
index 86a0f1c22091..e292bb0eaca2 100644
--- a/drivers/char/drm/drm_pci.c
+++ b/drivers/char/drm/drm_pci.c
@@ -47,7 +47,7 @@
/**
* \brief Allocate a PCI consistent memory block, for DMA.
*/
-drm_dma_handle_t *drm_pci_alloc(drm_device_t * dev, size_t size, size_t align,
+drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t align,
dma_addr_t maxaddr)
{
drm_dma_handle_t *dmah;
@@ -126,7 +126,7 @@ EXPORT_SYMBOL(drm_pci_alloc);
*
* This function is for internal use in the Linux-specific DRM core code.
*/
-void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
+void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
{
#if 1
unsigned long addr;
@@ -172,7 +172,7 @@ void __drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
/**
* \brief Free a PCI consistent memory block
*/
-void drm_pci_free(drm_device_t * dev, drm_dma_handle_t * dmah)
+void drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah)
{
__drm_pci_free(dev, dmah);
kfree(dmah);
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index b204498d1a28..12dfea89c7f3 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -87,7 +87,7 @@ static struct drm_proc_list {
* "/proc/dri/%minor%/", and each entry in proc_list as
* "/proc/dri/%minor%/%name%".
*/
-int drm_proc_init(drm_device_t * dev, int minor,
+int drm_proc_init(struct drm_device * dev, int minor,
struct proc_dir_entry *root, struct proc_dir_entry **dev_root)
{
struct proc_dir_entry *ent;
@@ -163,7 +163,7 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int len = 0;
if (offset > DRM_PROC_LIMIT) {
@@ -205,11 +205,10 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int len = 0;
- drm_map_t *map;
- drm_map_list_t *r_list;
- struct list_head *list;
+ struct drm_map *map;
+ struct drm_map_list *r_list;
/* Hardcoded from _DRM_FRAME_BUFFER,
_DRM_REGISTERS, _DRM_SHM, _DRM_AGP, and
@@ -229,9 +228,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("slot offset size type flags "
"address mtrr\n\n");
i = 0;
- if (dev->maplist != NULL)
- list_for_each(list, &dev->maplist->head) {
- r_list = list_entry(list, drm_map_list_t, head);
+ list_for_each_entry(r_list, &dev->maplist, head) {
map = r_list->map;
if (!map)
continue;
@@ -242,14 +239,15 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("%4d 0x%08lx 0x%08lx %4.4s 0x%02x 0x%08x ",
i,
map->offset,
- map->size, type, map->flags, r_list->user_token);
+ map->size, type, map->flags,
+ r_list->user_token);
if (map->mtrr < 0) {
DRM_PROC_PRINT("none\n");
} else {
DRM_PROC_PRINT("%4d\n", map->mtrr);
}
i++;
- }
+ }
if (len > request + offset)
return request;
@@ -263,7 +261,7 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -286,10 +284,10 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int len = 0;
int i;
- drm_queue_t *q;
+ struct drm_queue *q;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
@@ -336,7 +334,7 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -359,9 +357,9 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int len = 0;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i;
if (!dma || offset > DRM_PROC_LIMIT) {
@@ -408,7 +406,7 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -431,9 +429,9 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int len = 0;
- drm_file_t *priv;
+ struct drm_file *priv;
if (offset > DRM_PROC_LIMIT) {
*eof = 1;
@@ -444,7 +442,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset,
*eof = 0;
DRM_PROC_PRINT("a dev pid uid magic ioctls\n\n");
- for (priv = dev->file_first; priv; priv = priv->next) {
+ list_for_each_entry(priv, &dev->filelist, lhead) {
DRM_PROC_PRINT("%c %3d %5d %5d %10u %10lu\n",
priv->authenticated ? 'y' : 'n',
priv->minor,
@@ -464,7 +462,7 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int ret;
mutex_lock(&dev->struct_mutex);
@@ -478,9 +476,9 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int len = 0;
- drm_vma_entry_t *pt;
+ struct drm_vma_entry *pt;
struct vm_area_struct *vma;
#if defined(__i386__)
unsigned int pgprot;
@@ -497,7 +495,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
DRM_PROC_PRINT("vma use count: %d, high_memory = %p, 0x%08lx\n",
atomic_read(&dev->vma_count),
high_memory, virt_to_phys(high_memory));
- for (pt = dev->vmalist; pt; pt = pt->next) {
+ list_for_each_entry(pt, &dev->vmalist, head) {
if (!(vma = pt->vma))
continue;
DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
@@ -537,7 +535,7 @@ 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)
{
- drm_device_t *dev = (drm_device_t *) data;
+ struct drm_device *dev = (struct drm_device *) data;
int ret;
mutex_lock(&dev->struct_mutex);
diff --git a/drivers/char/drm/drm_sarea.h b/drivers/char/drm/drm_sarea.h
index e94297b751b8..f5466966081e 100644
--- a/drivers/char/drm/drm_sarea.h
+++ b/drivers/char/drm/drm_sarea.h
@@ -50,29 +50,35 @@
#define SAREA_DRAWABLE_CLAIMED_ENTRY 0x80000000
/** SAREA drawable */
-typedef struct drm_sarea_drawable {
+struct drm_sarea_drawable {
unsigned int stamp;
unsigned int flags;
-} drm_sarea_drawable_t;
+};
/** SAREA frame */
-typedef struct drm_sarea_frame {
+struct drm_sarea_frame {
unsigned int x;
unsigned int y;
unsigned int width;
unsigned int height;
unsigned int fullscreen;
-} drm_sarea_frame_t;
+};
/** SAREA */
-typedef struct drm_sarea {
+struct drm_sarea {
/** first thing is always the DRM locking structure */
- drm_hw_lock_t lock;
+ struct drm_hw_lock lock;
/** \todo Use readers/writer lock for drm_sarea::drawable_lock */
- drm_hw_lock_t drawable_lock;
- drm_sarea_drawable_t drawableTable[SAREA_MAX_DRAWABLES]; /**< drawables */
- drm_sarea_frame_t frame; /**< frame */
+ struct drm_hw_lock drawable_lock;
+ struct drm_sarea_drawable drawableTable[SAREA_MAX_DRAWABLES]; /**< drawables */
+ struct drm_sarea_frame frame; /**< frame */
drm_context_t dummy_context;
-} drm_sarea_t;
+};
+
+#ifndef __KERNEL__
+typedef struct drm_sarea_drawable drm_sarea_drawable_t;
+typedef struct drm_sarea_frame drm_sarea_frame_t;
+typedef struct drm_sarea drm_sarea_t;
+#endif
#endif /* _DRM_SAREA_H_ */
diff --git a/drivers/char/drm/drm_scatter.c b/drivers/char/drm/drm_scatter.c
index 06ef7ddbe67d..067d25daaf17 100644
--- a/drivers/char/drm/drm_scatter.c
+++ b/drivers/char/drm/drm_scatter.c
@@ -36,7 +36,7 @@
#define DEBUG_SCATTER 0
-void drm_sg_cleanup(drm_sg_mem_t * entry)
+void drm_sg_cleanup(struct drm_sg_mem * entry)
{
struct page *page;
int i;
@@ -65,11 +65,11 @@ void drm_sg_cleanup(drm_sg_mem_t * entry)
int drm_sg_alloc(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_scatter_gather_t __user *argp = (void __user *)arg;
- drm_scatter_gather_t request;
- drm_sg_mem_t *entry;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_scatter_gather __user *argp = (void __user *)arg;
+ struct drm_scatter_gather request;
+ struct drm_sg_mem *entry;
unsigned long pages, i, j;
DRM_DEBUG("%s\n", __FUNCTION__);
@@ -201,16 +201,16 @@ int drm_sg_alloc(struct inode *inode, struct file *filp,
int drm_sg_free(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_scatter_gather_t request;
- drm_sg_mem_t *entry;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_scatter_gather request;
+ struct drm_sg_mem *entry;
if (!drm_core_check_feature(dev, DRIVER_SG))
return -EINVAL;
if (copy_from_user(&request,
- (drm_scatter_gather_t __user *) arg,
+ (struct drm_scatter_gather __user *) arg,
sizeof(request)))
return -EFAULT;
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
index e15db6d6bea9..8421a93946d8 100644
--- a/drivers/char/drm/drm_sman.c
+++ b/drivers/char/drm/drm_sman.c
@@ -38,13 +38,13 @@
#include "drm_sman.h"
-typedef struct drm_owner_item {
- drm_hash_item_t owner_hash;
+struct drm_owner_item {
+ struct drm_hash_item owner_hash;
struct list_head sman_list;
struct list_head mem_blocks;
-} drm_owner_item_t;
+};
-void drm_sman_takedown(drm_sman_t * sman)
+void drm_sman_takedown(struct drm_sman * sman)
{
drm_ht_remove(&sman->user_hash_tab);
drm_ht_remove(&sman->owner_hash_tab);
@@ -56,12 +56,12 @@ void drm_sman_takedown(drm_sman_t * sman)
EXPORT_SYMBOL(drm_sman_takedown);
int
-drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
unsigned int user_order, unsigned int owner_order)
{
int ret = 0;
- sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm),
+ sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers, sizeof(*sman->mm),
DRM_MEM_MM);
if (!sman->mm) {
ret = -ENOMEM;
@@ -88,8 +88,8 @@ EXPORT_SYMBOL(drm_sman_init);
static void *drm_sman_mm_allocate(void *private, unsigned long size,
unsigned alignment)
{
- drm_mm_t *mm = (drm_mm_t *) private;
- drm_mm_node_t *tmp;
+ struct drm_mm *mm = (struct drm_mm *) private;
+ struct drm_mm_node *tmp;
tmp = drm_mm_search_free(mm, size, alignment, 1);
if (!tmp) {
@@ -101,30 +101,30 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size,
static void drm_sman_mm_free(void *private, void *ref)
{
- drm_mm_node_t *node = (drm_mm_node_t *) ref;
+ struct drm_mm_node *node = (struct drm_mm_node *) ref;
drm_mm_put_block(node);
}
static void drm_sman_mm_destroy(void *private)
{
- drm_mm_t *mm = (drm_mm_t *) private;
+ struct drm_mm *mm = (struct drm_mm *) private;
drm_mm_takedown(mm);
drm_free(mm, sizeof(*mm), DRM_MEM_MM);
}
static unsigned long drm_sman_mm_offset(void *private, void *ref)
{
- drm_mm_node_t *node = (drm_mm_node_t *) ref;
+ struct drm_mm_node *node = (struct drm_mm_node *) ref;
return node->start;
}
int
-drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
unsigned long start, unsigned long size)
{
- drm_sman_mm_t *sman_mm;
- drm_mm_t *mm;
+ struct drm_sman_mm *sman_mm;
+ struct drm_mm *mm;
int ret;
BUG_ON(manager >= sman->num_managers);
@@ -153,8 +153,8 @@ drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
EXPORT_SYMBOL(drm_sman_set_range);
int
-drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
- drm_sman_mm_t * allocator)
+drm_sman_set_manager(struct drm_sman * sman, unsigned int manager,
+ struct drm_sman_mm * allocator)
{
BUG_ON(manager >= sman->num_managers);
sman->mm[manager] = *allocator;
@@ -163,16 +163,16 @@ drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
}
EXPORT_SYMBOL(drm_sman_set_manager);
-static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman,
+static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman,
unsigned long owner)
{
int ret;
- drm_hash_item_t *owner_hash_item;
- drm_owner_item_t *owner_item;
+ struct drm_hash_item *owner_hash_item;
+ struct drm_owner_item *owner_item;
ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
if (!ret) {
- return drm_hash_entry(owner_hash_item, drm_owner_item_t,
+ return drm_hash_entry(owner_hash_item, struct drm_owner_item,
owner_hash);
}
@@ -194,14 +194,14 @@ out:
return NULL;
}
-drm_memblock_item_t *drm_sman_alloc(drm_sman_t *sman, unsigned int manager,
+struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int manager,
unsigned long size, unsigned alignment,
unsigned long owner)
{
void *tmp;
- drm_sman_mm_t *sman_mm;
- drm_owner_item_t *owner_item;
- drm_memblock_item_t *memblock;
+ struct drm_sman_mm *sman_mm;
+ struct drm_owner_item *owner_item;
+ struct drm_memblock_item *memblock;
BUG_ON(manager >= sman->num_managers);
@@ -246,9 +246,9 @@ out:
EXPORT_SYMBOL(drm_sman_alloc);
-static void drm_sman_free(drm_memblock_item_t *item)
+static void drm_sman_free(struct drm_memblock_item *item)
{
- drm_sman_t *sman = item->sman;
+ struct drm_sman *sman = item->sman;
list_del(&item->owner_list);
drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
@@ -256,40 +256,41 @@ static void drm_sman_free(drm_memblock_item_t *item)
drm_free(item, sizeof(*item), DRM_MEM_MM);
}
-int drm_sman_free_key(drm_sman_t *sman, unsigned int key)
+int drm_sman_free_key(struct drm_sman *sman, unsigned int key)
{
- drm_hash_item_t *hash_item;
- drm_memblock_item_t *memblock_item;
+ struct drm_hash_item *hash_item;
+ struct drm_memblock_item *memblock_item;
if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
return -EINVAL;
- memblock_item = drm_hash_entry(hash_item, drm_memblock_item_t, user_hash);
+ memblock_item = drm_hash_entry(hash_item, struct drm_memblock_item,
+ user_hash);
drm_sman_free(memblock_item);
return 0;
}
EXPORT_SYMBOL(drm_sman_free_key);
-static void drm_sman_remove_owner(drm_sman_t *sman,
- drm_owner_item_t *owner_item)
+static void drm_sman_remove_owner(struct drm_sman *sman,
+ struct drm_owner_item *owner_item)
{
list_del(&owner_item->sman_list);
drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
}
-int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner)
+int drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner)
{
- drm_hash_item_t *hash_item;
- drm_owner_item_t *owner_item;
+ struct drm_hash_item *hash_item;
+ struct drm_owner_item *owner_item;
if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
return -1;
}
- owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
+ owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
drm_sman_remove_owner(sman, owner_item);
return -1;
@@ -300,10 +301,10 @@ int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner)
EXPORT_SYMBOL(drm_sman_owner_clean);
-static void drm_sman_do_owner_cleanup(drm_sman_t *sman,
- drm_owner_item_t *owner_item)
+static void drm_sman_do_owner_cleanup(struct drm_sman *sman,
+ struct drm_owner_item *owner_item)
{
- drm_memblock_item_t *entry, *next;
+ struct drm_memblock_item *entry, *next;
list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
owner_list) {
@@ -312,28 +313,28 @@ static void drm_sman_do_owner_cleanup(drm_sman_t *sman,
drm_sman_remove_owner(sman, owner_item);
}
-void drm_sman_owner_cleanup(drm_sman_t *sman, unsigned long owner)
+void drm_sman_owner_cleanup(struct drm_sman *sman, unsigned long owner)
{
- drm_hash_item_t *hash_item;
- drm_owner_item_t *owner_item;
+ struct drm_hash_item *hash_item;
+ struct drm_owner_item *owner_item;
if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
return;
}
- owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
+ owner_item = drm_hash_entry(hash_item, struct drm_owner_item, owner_hash);
drm_sman_do_owner_cleanup(sman, owner_item);
}
EXPORT_SYMBOL(drm_sman_owner_cleanup);
-void drm_sman_cleanup(drm_sman_t *sman)
+void drm_sman_cleanup(struct drm_sman *sman)
{
- drm_owner_item_t *entry, *next;
+ struct drm_owner_item *entry, *next;
unsigned int i;
- drm_sman_mm_t *sman_mm;
+ struct drm_sman_mm *sman_mm;
list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
drm_sman_do_owner_cleanup(sman, entry);
diff --git a/drivers/char/drm/drm_sman.h b/drivers/char/drm/drm_sman.h
index ddc732a1bf27..39a39fefeef1 100644
--- a/drivers/char/drm/drm_sman.h
+++ b/drivers/char/drm/drm_sman.h
@@ -50,7 +50,7 @@
* for memory management.
*/
-typedef struct drm_sman_mm {
+struct drm_sman_mm {
/* private info. If allocated, needs to be destroyed by the destroy
function */
void *private;
@@ -74,30 +74,30 @@ typedef struct drm_sman_mm {
"alloc" function */
unsigned long (*offset) (void *private, void *ref);
-} drm_sman_mm_t;
+};
-typedef struct drm_memblock_item {
+struct drm_memblock_item {
struct list_head owner_list;
- drm_hash_item_t user_hash;
+ struct drm_hash_item user_hash;
void *mm_info;
- drm_sman_mm_t *mm;
+ struct drm_sman_mm *mm;
struct drm_sman *sman;
-} drm_memblock_item_t;
+};
-typedef struct drm_sman {
- drm_sman_mm_t *mm;
+struct drm_sman {
+ struct drm_sman_mm *mm;
int num_managers;
- drm_open_hash_t owner_hash_tab;
- drm_open_hash_t user_hash_tab;
+ struct drm_open_hash owner_hash_tab;
+ struct drm_open_hash user_hash_tab;
struct list_head owner_items;
-} drm_sman_t;
+};
/*
* Take down a memory manager. This function should only be called after a
* successful init and after a call to drm_sman_cleanup.
*/
-extern void drm_sman_takedown(drm_sman_t * sman);
+extern void drm_sman_takedown(struct drm_sman * sman);
/*
* Allocate structures for a manager.
@@ -112,7 +112,7 @@ extern void drm_sman_takedown(drm_sman_t * sman);
*
*/
-extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+extern int drm_sman_init(struct drm_sman * sman, unsigned int num_managers,
unsigned int user_order, unsigned int owner_order);
/*
@@ -120,7 +120,7 @@ extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
* manager unless a customized allogator is used.
*/
-extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+extern int drm_sman_set_range(struct drm_sman * sman, unsigned int manager,
unsigned long start, unsigned long size);
/*
@@ -129,23 +129,23 @@ extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
* so it can be destroyed after this call.
*/
-extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger,
- drm_sman_mm_t * allocator);
+extern int drm_sman_set_manager(struct drm_sman * sman, unsigned int mananger,
+ struct drm_sman_mm * allocator);
/*
* Allocate a memory block. Aligment is not implemented yet.
*/
-extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman,
- unsigned int manager,
- unsigned long size,
- unsigned alignment,
- unsigned long owner);
+extern struct drm_memblock_item *drm_sman_alloc(struct drm_sman * sman,
+ unsigned int manager,
+ unsigned long size,
+ unsigned alignment,
+ unsigned long owner);
/*
* Free a memory block identified by its user hash key.
*/
-extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key);
+extern int drm_sman_free_key(struct drm_sman * sman, unsigned int key);
/*
* returns 1 iff there are no stale memory blocks associated with this owner.
@@ -154,7 +154,7 @@ extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key);
* resources associated with owner.
*/
-extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner);
+extern int drm_sman_owner_clean(struct drm_sman * sman, unsigned long owner);
/*
* Frees all stale memory blocks associated with this owner. Note that this
@@ -164,13 +164,13 @@ extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner);
* is not going to be referenced anymore.
*/
-extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner);
+extern void drm_sman_owner_cleanup(struct drm_sman * sman, unsigned long owner);
/*
* Frees all stale memory blocks associated with the memory manager.
* See idling above.
*/
-extern void drm_sman_cleanup(drm_sman_t * sman);
+extern void drm_sman_cleanup(struct drm_sman * sman);
#endif
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 19408adcc775..ee83ff9efed6 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -49,16 +49,21 @@ 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);
-drm_head_t **drm_heads;
+struct drm_head **drm_heads;
struct class *drm_class;
struct proc_dir_entry *drm_proc_root;
-static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
+static int drm_fill_in_dev(struct drm_device * dev, struct pci_dev *pdev,
const struct pci_device_id *ent,
struct drm_driver *driver)
{
int retcode;
+ INIT_LIST_HEAD(&dev->filelist);
+ INIT_LIST_HEAD(&dev->ctxlist);
+ INIT_LIST_HEAD(&dev->vmalist);
+ INIT_LIST_HEAD(&dev->maplist);
+
spin_lock_init(&dev->count_lock);
spin_lock_init(&dev->drw_lock);
spin_lock_init(&dev->tasklet_lock);
@@ -67,6 +72,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex);
+ idr_init(&dev->drw_idr);
+
dev->pdev = pdev;
dev->pci_device = pdev->device;
dev->pci_vendor = pdev->vendor;
@@ -76,12 +83,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
#endif
dev->irq = pdev->irq;
- dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
- if (dev->maplist == NULL)
- return -ENOMEM;
- INIT_LIST_HEAD(&dev->maplist->head);
if (drm_ht_create(&dev->map_hash, 12)) {
- drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
return -ENOMEM;
}
@@ -143,9 +145,9 @@ static int drm_fill_in_dev(drm_device_t * 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(drm_device_t * dev, drm_head_t * head)
+static int drm_get_head(struct drm_device * dev, struct drm_head * head)
{
- drm_head_t **heads = drm_heads;
+ struct drm_head **heads = drm_heads;
int ret;
int minor;
@@ -154,7 +156,7 @@ static int drm_get_head(drm_device_t * dev, drm_head_t * head)
for (minor = 0; minor < drm_cards_limit; minor++, heads++) {
if (!*heads) {
- *head = (drm_head_t) {
+ *head = (struct drm_head) {
.dev = dev,.device =
MKDEV(DRM_MAJOR, minor),.minor = minor,};
@@ -184,7 +186,7 @@ static int drm_get_head(drm_device_t * dev, drm_head_t * head)
err_g2:
drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
err_g1:
- *head = (drm_head_t) {
+ *head = (struct drm_head) {
.dev = NULL};
return ret;
}
@@ -203,7 +205,7 @@ static int drm_get_head(drm_device_t * dev, drm_head_t * head)
int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver)
{
- drm_device_t *dev;
+ struct drm_device *dev;
int ret;
DRM_DEBUG("\n");
@@ -246,7 +248,7 @@ err_g1:
* "drm" data, otherwise unregisters the "drm" data, frees the dev list and
* unregisters the character device.
*/
-int drm_put_dev(drm_device_t * dev)
+int drm_put_dev(struct drm_device * dev)
{
DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
@@ -274,7 +276,7 @@ int drm_put_dev(drm_device_t * dev)
* last minor released.
*
*/
-int drm_put_head(drm_head_t * head)
+int drm_put_head(struct drm_head * head)
{
int minor = head->minor;
@@ -283,7 +285,7 @@ int drm_put_head(drm_head_t * head)
drm_proc_cleanup(minor, drm_proc_root, head->dev_root);
drm_sysfs_device_remove(head->dev_class);
- *head = (drm_head_t) {.dev = NULL};
+ *head = (struct drm_head) {.dev = NULL};
drm_heads[minor] = NULL;
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index cc8e2ebe128c..cf4349b00b07 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -80,7 +80,7 @@ void drm_sysfs_destroy(struct class *class)
static ssize_t show_dri(struct class_device *class_device, char *buf)
{
- drm_device_t * dev = ((drm_head_t *)class_get_devdata(class_device))->dev;
+ struct drm_device * dev = ((struct drm_head *)class_get_devdata(class_device))->dev;
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);
@@ -104,7 +104,7 @@ static struct class_device_attribute class_device_attrs[] = {
* Note: the struct class passed to this function must have previously been
* created with a call to drm_sysfs_create().
*/
-struct class_device *drm_sysfs_device_add(struct class *cs, drm_head_t *head)
+struct class_device *drm_sysfs_device_add(struct class *cs, struct drm_head *head)
{
struct class_device *class_dev;
int i, j, err;
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index b5c5b9fa84c3..68e36e51ba0c 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -79,11 +79,11 @@ static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
unsigned long address)
{
- drm_file_t *priv = vma->vm_file->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_map_t *map = NULL;
- drm_map_list_t *r_list;
- drm_hash_item_t *hash;
+ struct drm_file *priv = vma->vm_file->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_map *map = NULL;
+ struct drm_map_list *r_list;
+ struct drm_hash_item *hash;
/*
* Find the right map
@@ -97,7 +97,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
goto vm_nopage_error;
- r_list = drm_hash_entry(hash, drm_map_list_t, hash);
+ r_list = drm_hash_entry(hash, struct drm_map_list, hash);
map = r_list->map;
if (map && map->type == _DRM_AGP) {
@@ -116,7 +116,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
/*
* It's AGP memory - find the real physical page to map
*/
- for (agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) {
+ list_for_each_entry(agpmem, &dev->agp->memory, head) {
if (agpmem->bound <= baddr &&
agpmem->bound + agpmem->pages * PAGE_SIZE > baddr)
break;
@@ -163,7 +163,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
unsigned long address)
{
- drm_map_t *map = (drm_map_t *) vma->vm_private_data;
+ struct drm_map *map = (struct drm_map *) vma->vm_private_data;
unsigned long offset;
unsigned long i;
struct page *page;
@@ -194,12 +194,11 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
*/
static void drm_vm_shm_close(struct vm_area_struct *vma)
{
- drm_file_t *priv = vma->vm_file->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_vma_entry_t *pt, *prev, *next;
- drm_map_t *map;
- drm_map_list_t *r_list;
- struct list_head *list;
+ struct drm_file *priv = vma->vm_file->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_vma_entry *pt, *temp;
+ struct drm_map *map;
+ struct drm_map_list *r_list;
int found_maps = 0;
DRM_DEBUG("0x%08lx,0x%08lx\n",
@@ -209,30 +208,22 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map = vma->vm_private_data;
mutex_lock(&dev->struct_mutex);
- for (pt = dev->vmalist, prev = NULL; pt; pt = next) {
- next = pt->next;
+ list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
if (pt->vma->vm_private_data == map)
found_maps++;
if (pt->vma == vma) {
- if (prev) {
- prev->next = pt->next;
- } else {
- dev->vmalist = pt->next;
- }
+ list_del(&pt->head);
drm_free(pt, sizeof(*pt), DRM_MEM_VMAS);
- } else {
- prev = pt;
}
}
+
/* We were the only map that was found */
if (found_maps == 1 && map->flags & _DRM_REMOVABLE) {
/* Check to see if we are in the maplist, if we are not, then
* we delete this mappings information.
*/
found_maps = 0;
- list = &dev->maplist->head;
- list_for_each(list, &dev->maplist->head) {
- r_list = list_entry(list, drm_map_list_t, head);
+ list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map == map)
found_maps++;
}
@@ -283,9 +274,9 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
unsigned long address)
{
- drm_file_t *priv = vma->vm_file->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_file *priv = vma->vm_file->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
unsigned long offset;
unsigned long page_nr;
struct page *page;
@@ -319,10 +310,10 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma,
static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma,
unsigned long address)
{
- drm_map_t *map = (drm_map_t *) vma->vm_private_data;
- drm_file_t *priv = vma->vm_file->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_sg_mem_t *entry = dev->sg;
+ 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_sg_mem *entry = dev->sg;
unsigned long offset;
unsigned long map_offset;
unsigned long page_offset;
@@ -414,9 +405,9 @@ static struct vm_operations_struct drm_vm_sg_ops = {
*/
static void drm_vm_open_locked(struct vm_area_struct *vma)
{
- drm_file_t *priv = vma->vm_file->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_vma_entry_t *vma_entry;
+ struct drm_file *priv = vma->vm_file->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_vma_entry *vma_entry;
DRM_DEBUG("0x%08lx,0x%08lx\n",
vma->vm_start, vma->vm_end - vma->vm_start);
@@ -425,16 +416,15 @@ static void drm_vm_open_locked(struct vm_area_struct *vma)
vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
if (vma_entry) {
vma_entry->vma = vma;
- vma_entry->next = dev->vmalist;
vma_entry->pid = current->pid;
- dev->vmalist = vma_entry;
+ list_add(&vma_entry->head, &dev->vmalist);
}
}
static void drm_vm_open(struct vm_area_struct *vma)
{
- drm_file_t *priv = vma->vm_file->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = vma->vm_file->private_data;
+ struct drm_device *dev = priv->head->dev;
mutex_lock(&dev->struct_mutex);
drm_vm_open_locked(vma);
@@ -451,22 +441,18 @@ static void drm_vm_open(struct vm_area_struct *vma)
*/
static void drm_vm_close(struct vm_area_struct *vma)
{
- drm_file_t *priv = vma->vm_file->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_vma_entry_t *pt, *prev;
+ struct drm_file *priv = vma->vm_file->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_vma_entry *pt, *temp;
DRM_DEBUG("0x%08lx,0x%08lx\n",
vma->vm_start, vma->vm_end - vma->vm_start);
atomic_dec(&dev->vma_count);
mutex_lock(&dev->struct_mutex);
- for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
+ list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
if (pt->vma == vma) {
- if (prev) {
- prev->next = pt->next;
- } else {
- dev->vmalist = pt->next;
- }
+ list_del(&pt->head);
drm_free(pt, sizeof(*pt), DRM_MEM_VMAS);
break;
}
@@ -486,9 +472,9 @@ static void drm_vm_close(struct vm_area_struct *vma)
*/
static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
- drm_device_dma_t *dma;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev;
+ struct drm_device_dma *dma;
unsigned long length = vma->vm_end - vma->vm_start;
dev = priv->head->dev;
@@ -526,7 +512,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
return 0;
}
-unsigned long drm_core_get_map_ofs(drm_map_t * map)
+unsigned long drm_core_get_map_ofs(struct drm_map * map)
{
return map->offset;
}
@@ -559,11 +545,11 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
*/
static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_map_t *map = NULL;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_map *map = NULL;
unsigned long offset = 0;
- drm_hash_item_t *hash;
+ struct drm_hash_item *hash;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
vma->vm_start, vma->vm_end, vma->vm_pgoff);
@@ -588,7 +574,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
return -EINVAL;
}
- map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
+ map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
return -EPERM;
@@ -677,8 +663,8 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
int drm_mmap(struct file *filp, struct vm_area_struct *vma)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->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 603d17fd2d69..cb449999d0ef 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -45,16 +45,16 @@
#define I810_BUF_UNMAPPED 0
#define I810_BUF_MAPPED 1
-static drm_buf_t *i810_freelist_get(drm_device_t * dev)
+static struct drm_buf *i810_freelist_get(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i;
int used;
/* Linear search might not be the best solution */
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
/* In use is already a pointer */
used = cmpxchg(buf_priv->in_use, I810_BUF_FREE,
@@ -70,7 +70,7 @@ static drm_buf_t *i810_freelist_get(drm_device_t * dev)
* yet, the hardware updates in use for us once its on the ring buffer.
*/
-static int i810_freelist_put(drm_device_t * dev, drm_buf_t * buf)
+static int i810_freelist_put(struct drm_device * dev, struct drm_buf * buf)
{
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int used;
@@ -87,10 +87,10 @@ static int i810_freelist_put(drm_device_t * dev, drm_buf_t * buf)
static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev;
drm_i810_private_t *dev_priv;
- drm_buf_t *buf;
+ struct drm_buf *buf;
drm_i810_buf_priv_t *buf_priv;
lock_kernel();
@@ -120,10 +120,10 @@ static const struct file_operations i810_buffer_fops = {
.fasync = drm_fasync,
};
-static int i810_map_buffer(drm_buf_t * buf, struct file *filp)
+static int i810_map_buffer(struct drm_buf * buf, struct file *filp)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->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;
@@ -152,7 +152,7 @@ static int i810_map_buffer(drm_buf_t * buf, struct file *filp)
return retcode;
}
-static int i810_unmap_buffer(drm_buf_t * buf)
+static int i810_unmap_buffer(struct drm_buf * buf)
{
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int retcode = 0;
@@ -172,10 +172,10 @@ static int i810_unmap_buffer(drm_buf_t * buf)
return retcode;
}
-static int i810_dma_get_buffer(drm_device_t * dev, drm_i810_dma_t * d,
+static int i810_dma_get_buffer(struct drm_device * dev, drm_i810_dma_t * d,
struct file *filp)
{
- drm_buf_t *buf;
+ struct drm_buf *buf;
drm_i810_buf_priv_t *buf_priv;
int retcode = 0;
@@ -202,9 +202,9 @@ static int i810_dma_get_buffer(drm_device_t * dev, drm_i810_dma_t * d,
return retcode;
}
-static int i810_dma_cleanup(drm_device_t * dev)
+static int i810_dma_cleanup(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
@@ -233,7 +233,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
dev->dev_private = NULL;
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
if (buf_priv->kernel_virtual && buf->total)
@@ -243,7 +243,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
return 0;
}
-static int i810_wait_ring(drm_device_t * dev, int n)
+static int i810_wait_ring(struct drm_device * dev, int n)
{
drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
@@ -276,7 +276,7 @@ static int i810_wait_ring(drm_device_t * dev, int n)
return iters;
}
-static void i810_kernel_lost_context(drm_device_t * dev)
+static void i810_kernel_lost_context(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_ring_buffer_t *ring = &(dev_priv->ring);
@@ -288,9 +288,9 @@ static void i810_kernel_lost_context(drm_device_t * dev)
ring->space += ring->Size;
}
-static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
+static int i810_freelist_init(struct drm_device * dev, drm_i810_private_t * dev_priv)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int my_idx = 24;
u32 *hw_status = (u32 *) (dev_priv->hw_status_page + my_idx);
int i;
@@ -301,7 +301,7 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
}
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
buf_priv->in_use = hw_status++;
@@ -323,16 +323,14 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
return 0;
}
-static int i810_dma_initialize(drm_device_t * dev,
+static int i810_dma_initialize(struct drm_device * dev,
drm_i810_private_t * dev_priv,
drm_i810_init_t * init)
{
- struct list_head *list;
-
+ struct drm_map_list *r_list;
memset(dev_priv, 0, sizeof(drm_i810_private_t));
- list_for_each(list, &dev->maplist->head) {
- drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
+ list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map &&
r_list->map->type == _DRM_SHM &&
r_list->map->flags & _DRM_CONTAINS_LOCK) {
@@ -478,8 +476,8 @@ static int i810_dma_init_compat(drm_i810_init_t * init, unsigned long arg)
static int i810_dma_init(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv;
drm_i810_init_t init;
int retcode = 0;
@@ -536,7 +534,7 @@ static int i810_dma_init(struct inode *inode, struct file *filp,
* Use 'volatile' & local var tmp to force the emitted values to be
* identical to the verified ones.
*/
-static void i810EmitContextVerified(drm_device_t * dev,
+static void i810EmitContextVerified(struct drm_device * dev,
volatile unsigned int *code)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -569,7 +567,7 @@ static void i810EmitContextVerified(drm_device_t * dev,
ADVANCE_LP_RING();
}
-static void i810EmitTexVerified(drm_device_t * dev, volatile unsigned int *code)
+static void i810EmitTexVerified(struct drm_device * dev, volatile unsigned int *code)
{
drm_i810_private_t *dev_priv = dev->dev_private;
int i, j = 0;
@@ -602,7 +600,7 @@ static void i810EmitTexVerified(drm_device_t * dev, volatile unsigned int *code)
/* Need to do some additional checking when setting the dest buffer.
*/
-static void i810EmitDestVerified(drm_device_t * dev,
+static void i810EmitDestVerified(struct drm_device * dev,
volatile unsigned int *code)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -637,7 +635,7 @@ static void i810EmitDestVerified(drm_device_t * dev,
ADVANCE_LP_RING();
}
-static void i810EmitState(drm_device_t * dev)
+static void i810EmitState(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
@@ -668,14 +666,14 @@ static void i810EmitState(drm_device_t * dev)
/* need to verify
*/
-static void i810_dma_dispatch_clear(drm_device_t * dev, int flags,
+static void i810_dma_dispatch_clear(struct drm_device * dev, int flags,
unsigned int clear_color,
unsigned int clear_zval)
{
drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int pitch = dev_priv->pitch;
int cpp = 2;
int i;
@@ -743,12 +741,12 @@ static void i810_dma_dispatch_clear(drm_device_t * dev, int flags,
}
}
-static void i810_dma_dispatch_swap(drm_device_t * dev)
+static void i810_dma_dispatch_swap(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int pitch = dev_priv->pitch;
int cpp = 2;
int i;
@@ -789,13 +787,13 @@ static void i810_dma_dispatch_swap(drm_device_t * dev)
}
}
-static void i810_dma_dispatch_vertex(drm_device_t * dev,
- drm_buf_t * buf, int discard, int used)
+static void i810_dma_dispatch_vertex(struct drm_device * dev,
+ struct drm_buf * buf, int discard, int used)
{
drm_i810_private_t *dev_priv = dev->dev_private;
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
drm_i810_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_clip_rect_t *box = sarea_priv->boxes;
+ struct drm_clip_rect *box = sarea_priv->boxes;
int nbox = sarea_priv->nbox;
unsigned long address = (unsigned long)buf->bus_address;
unsigned long start = address - dev->agp->base;
@@ -869,7 +867,7 @@ static void i810_dma_dispatch_vertex(drm_device_t * dev,
}
}
-static void i810_dma_dispatch_flip(drm_device_t * dev)
+static void i810_dma_dispatch_flip(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
int pitch = dev_priv->pitch;
@@ -916,7 +914,7 @@ static void i810_dma_dispatch_flip(drm_device_t * dev)
}
-static void i810_dma_quiescent(drm_device_t * dev)
+static void i810_dma_quiescent(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -935,10 +933,10 @@ static void i810_dma_quiescent(drm_device_t * dev)
i810_wait_ring(dev, dev_priv->ring.Size - 8);
}
-static int i810_flush_queue(drm_device_t * dev)
+static int i810_flush_queue(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i, ret = 0;
RING_LOCALS;
@@ -954,7 +952,7 @@ static int i810_flush_queue(drm_device_t * dev)
i810_wait_ring(dev, dev_priv->ring.Size - 8);
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
int used = cmpxchg(buf_priv->in_use, I810_BUF_HARDWARE,
@@ -970,9 +968,9 @@ static int i810_flush_queue(drm_device_t * dev)
}
/* Must be called with the lock held */
-static void i810_reclaim_buffers(drm_device_t * dev, struct file *filp)
+static void i810_reclaim_buffers(struct drm_device * dev, struct file *filp)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i;
if (!dma)
@@ -985,7 +983,7 @@ static void i810_reclaim_buffers(drm_device_t * dev, struct file *filp)
i810_flush_queue(dev);
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i810_buf_priv_t *buf_priv = buf->dev_private;
if (buf->filp == filp && buf_priv) {
@@ -1003,8 +1001,8 @@ static void i810_reclaim_buffers(drm_device_t * dev, struct file *filp)
static int i810_flush_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
LOCK_TEST_WITH_RETURN(dev, filp);
@@ -1015,9 +1013,9 @@ static int i810_flush_ioctl(struct inode *inode, struct file *filp,
static int i810_dma_vertex(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
@@ -1051,8 +1049,8 @@ static int i810_dma_vertex(struct inode *inode, struct file *filp,
static int i810_clear_bufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_clear_t clear;
if (copy_from_user
@@ -1074,8 +1072,8 @@ static int i810_clear_bufs(struct inode *inode, struct file *filp,
static int i810_swap_bufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
DRM_DEBUG("i810_swap_bufs\n");
@@ -1088,8 +1086,8 @@ static int i810_swap_bufs(struct inode *inode, struct file *filp,
static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
@@ -1102,8 +1100,8 @@ static int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd,
static int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
int retcode = 0;
drm_i810_dma_t d;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
@@ -1123,7 +1121,7 @@ static int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
current->pid, retcode, d.granted);
- if (copy_to_user((drm_dma_t __user *) arg, &d, sizeof(d)))
+ if (copy_to_user((void __user *) arg, &d, sizeof(d)))
return -EFAULT;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1144,7 +1142,7 @@ static int i810_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
-static void i810_dma_dispatch_mc(drm_device_t * dev, drm_buf_t * buf, int used,
+static void i810_dma_dispatch_mc(struct drm_device * dev, struct drm_buf * buf, int used,
unsigned int last_render)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1207,9 +1205,9 @@ static void i810_dma_dispatch_mc(drm_device_t * dev, drm_buf_t * buf, int used,
static int i810_dma_mc(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i810_sarea_t *sarea_priv = (drm_i810_sarea_t *)
@@ -1238,8 +1236,8 @@ static int i810_dma_mc(struct inode *inode, struct file *filp,
static int i810_rstatus(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
return (int)(((u32 *) (dev_priv->hw_status_page))[4]);
@@ -1248,8 +1246,8 @@ static int i810_rstatus(struct inode *inode, struct file *filp,
static int i810_ov0_info(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
drm_i810_overlay_t data;
@@ -1264,8 +1262,8 @@ static int i810_ov0_info(struct inode *inode, struct file *filp,
static int i810_fstatus(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
LOCK_TEST_WITH_RETURN(dev, filp);
@@ -1276,8 +1274,8 @@ static int i810_fstatus(struct inode *inode, struct file *filp,
static int i810_ov0_flip(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = (drm_i810_private_t *) dev->dev_private;
LOCK_TEST_WITH_RETURN(dev, filp);
@@ -1290,7 +1288,7 @@ static int i810_ov0_flip(struct inode *inode, struct file *filp,
/* Not sure why this isn't set all the time:
*/
-static void i810_do_init_pageflip(drm_device_t * dev)
+static void i810_do_init_pageflip(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1300,7 +1298,7 @@ static void i810_do_init_pageflip(drm_device_t * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}
-static int i810_do_cleanup_pageflip(drm_device_t * dev)
+static int i810_do_cleanup_pageflip(struct drm_device * dev)
{
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1315,8 +1313,8 @@ static int i810_do_cleanup_pageflip(drm_device_t * dev)
static int i810_flip_bufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i810_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
@@ -1330,7 +1328,7 @@ static int i810_flip_bufs(struct inode *inode, struct file *filp,
return 0;
}
-int i810_driver_load(drm_device_t *dev, unsigned long flags)
+int i810_driver_load(struct drm_device *dev, unsigned long flags)
{
/* i810 has 4 more counters */
dev->counters += 4;
@@ -1342,12 +1340,12 @@ int i810_driver_load(drm_device_t *dev, unsigned long flags)
return 0;
}
-void i810_driver_lastclose(drm_device_t * dev)
+void i810_driver_lastclose(struct drm_device * dev)
{
i810_dma_cleanup(dev);
}
-void i810_driver_preclose(drm_device_t * dev, DRMFILE filp)
+void i810_driver_preclose(struct drm_device * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_i810_private_t *dev_priv = dev->dev_private;
@@ -1357,12 +1355,12 @@ void i810_driver_preclose(drm_device_t * dev, DRMFILE filp)
}
}
-void i810_driver_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+void i810_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
{
i810_reclaim_buffers(dev, filp);
}
-int i810_driver_dma_quiescent(drm_device_t * dev)
+int i810_driver_dma_quiescent(struct drm_device * dev)
{
i810_dma_quiescent(dev);
return 0;
@@ -1399,7 +1397,7 @@ int i810_max_ioctl = DRM_ARRAY_SIZE(i810_ioctls);
* \returns
* A value of 1 is always retured to indictate every i810 is AGP.
*/
-int i810_driver_device_is_agp(drm_device_t * dev)
+int i810_driver_device_is_agp(struct drm_device * dev)
{
return 1;
}
diff --git a/drivers/char/drm/i810_drm.h b/drivers/char/drm/i810_drm.h
index 2deb925a94f3..614977dbce45 100644
--- a/drivers/char/drm/i810_drm.h
+++ b/drivers/char/drm/i810_drm.h
@@ -158,7 +158,7 @@ typedef struct _drm_i810_sarea {
unsigned int dirty;
unsigned int nbox;
- drm_clip_rect_t boxes[I810_NR_SAREA_CLIPRECTS];
+ struct drm_clip_rect boxes[I810_NR_SAREA_CLIPRECTS];
/* Maintain an LRU of contiguous regions of texture space. If
* you think you own a region of texture memory, and it has an
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index e6df49f4928a..648833844c7f 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -77,8 +77,8 @@ typedef struct _drm_i810_ring_buffer {
} drm_i810_ring_buffer_t;
typedef struct drm_i810_private {
- drm_map_t *sarea_map;
- drm_map_t *mmio_map;
+ struct drm_map *sarea_map;
+ struct drm_map *mmio_map;
drm_i810_sarea_t *sarea_priv;
drm_i810_ring_buffer_t ring;
@@ -88,7 +88,7 @@ typedef struct drm_i810_private {
dma_addr_t dma_status_page;
- drm_buf_t *mmap_buffer;
+ struct drm_buf *mmap_buffer;
u32 front_di1, back_di1, zi1;
@@ -115,15 +115,15 @@ typedef struct drm_i810_private {
} drm_i810_private_t;
/* i810_dma.c */
-extern int i810_driver_dma_quiescent(drm_device_t * dev);
-extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev,
+extern int i810_driver_dma_quiescent(struct drm_device * dev);
+extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
struct file *filp);
extern int i810_driver_load(struct drm_device *, unsigned long flags);
-extern void i810_driver_lastclose(drm_device_t * dev);
-extern void i810_driver_preclose(drm_device_t * dev, DRMFILE filp);
-extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev,
+extern void i810_driver_lastclose(struct drm_device * dev);
+extern void i810_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i810_driver_reclaim_buffers_locked(struct drm_device * dev,
struct file *filp);
-extern int i810_driver_device_is_agp(drm_device_t * dev);
+extern int i810_driver_device_is_agp(struct drm_device * dev);
extern drm_ioctl_desc_t i810_ioctls[];
extern int i810_max_ioctl;
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 3314a9fea9e5..dc20c1a7834e 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -47,16 +47,16 @@
#define I830_BUF_UNMAPPED 0
#define I830_BUF_MAPPED 1
-static drm_buf_t *i830_freelist_get(drm_device_t * dev)
+static struct drm_buf *i830_freelist_get(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i;
int used;
/* Linear search might not be the best solution */
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
/* In use is already a pointer */
used = cmpxchg(buf_priv->in_use, I830_BUF_FREE,
@@ -72,7 +72,7 @@ static drm_buf_t *i830_freelist_get(drm_device_t * dev)
* yet, the hardware updates in use for us once its on the ring buffer.
*/
-static int i830_freelist_put(drm_device_t * dev, drm_buf_t * buf)
+static int i830_freelist_put(struct drm_device * dev, struct drm_buf * buf)
{
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
int used;
@@ -89,10 +89,10 @@ static int i830_freelist_put(drm_device_t * dev, drm_buf_t * buf)
static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev;
drm_i830_private_t *dev_priv;
- drm_buf_t *buf;
+ struct drm_buf *buf;
drm_i830_buf_priv_t *buf_priv;
lock_kernel();
@@ -122,10 +122,10 @@ static const struct file_operations i830_buffer_fops = {
.fasync = drm_fasync,
};
-static int i830_map_buffer(drm_buf_t * buf, struct file *filp)
+static int i830_map_buffer(struct drm_buf * buf, struct file *filp)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->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;
@@ -156,7 +156,7 @@ static int i830_map_buffer(drm_buf_t * buf, struct file *filp)
return retcode;
}
-static int i830_unmap_buffer(drm_buf_t * buf)
+static int i830_unmap_buffer(struct drm_buf * buf)
{
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
int retcode = 0;
@@ -176,10 +176,10 @@ static int i830_unmap_buffer(drm_buf_t * buf)
return retcode;
}
-static int i830_dma_get_buffer(drm_device_t * dev, drm_i830_dma_t * d,
+static int i830_dma_get_buffer(struct drm_device * dev, drm_i830_dma_t * d,
struct file *filp)
{
- drm_buf_t *buf;
+ struct drm_buf *buf;
drm_i830_buf_priv_t *buf_priv;
int retcode = 0;
@@ -206,9 +206,9 @@ static int i830_dma_get_buffer(drm_device_t * dev, drm_i830_dma_t * d,
return retcode;
}
-static int i830_dma_cleanup(drm_device_t * dev)
+static int i830_dma_cleanup(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
@@ -238,7 +238,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
dev->dev_private = NULL;
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
if (buf_priv->kernel_virtual && buf->total)
drm_core_ioremapfree(&buf_priv->map, dev);
@@ -247,7 +247,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
return 0;
}
-int i830_wait_ring(drm_device_t * dev, int n, const char *caller)
+int i830_wait_ring(struct drm_device * dev, int n, const char *caller)
{
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
@@ -281,7 +281,7 @@ int i830_wait_ring(drm_device_t * dev, int n, const char *caller)
return iters;
}
-static void i830_kernel_lost_context(drm_device_t * dev)
+static void i830_kernel_lost_context(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_ring_buffer_t *ring = &(dev_priv->ring);
@@ -296,9 +296,9 @@ static void i830_kernel_lost_context(drm_device_t * dev)
dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY;
}
-static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
+static int i830_freelist_init(struct drm_device * dev, drm_i830_private_t * dev_priv)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int my_idx = 36;
u32 *hw_status = (u32 *) (dev_priv->hw_status_page + my_idx);
int i;
@@ -309,7 +309,7 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
}
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
buf_priv->in_use = hw_status++;
@@ -330,16 +330,15 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
return 0;
}
-static int i830_dma_initialize(drm_device_t * dev,
+static int i830_dma_initialize(struct drm_device * dev,
drm_i830_private_t * dev_priv,
drm_i830_init_t * init)
{
- struct list_head *list;
+ struct drm_map_list *r_list;
memset(dev_priv, 0, sizeof(drm_i830_private_t));
- list_for_each(list, &dev->maplist->head) {
- drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
+ list_for_each_entry(r_list, &dev->maplist, head) {
if (r_list->map &&
r_list->map->type == _DRM_SHM &&
r_list->map->flags & _DRM_CONTAINS_LOCK) {
@@ -455,8 +454,8 @@ static int i830_dma_initialize(drm_device_t * dev,
static int i830_dma_init(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv;
drm_i830_init_t init;
int retcode = 0;
@@ -490,7 +489,7 @@ static int i830_dma_init(struct inode *inode, struct file *filp,
/* Most efficient way to verify state for the i830 is as it is
* emitted. Non-conformant state is silently dropped.
*/
-static void i830EmitContextVerified(drm_device_t * dev, unsigned int *code)
+static void i830EmitContextVerified(struct drm_device * dev, unsigned int *code)
{
drm_i830_private_t *dev_priv = dev->dev_private;
int i, j = 0;
@@ -535,7 +534,7 @@ static void i830EmitContextVerified(drm_device_t * dev, unsigned int *code)
ADVANCE_LP_RING();
}
-static void i830EmitTexVerified(drm_device_t * dev, unsigned int *code)
+static void i830EmitTexVerified(struct drm_device * dev, unsigned int *code)
{
drm_i830_private_t *dev_priv = dev->dev_private;
int i, j = 0;
@@ -569,7 +568,7 @@ static void i830EmitTexVerified(drm_device_t * dev, unsigned int *code)
printk("rejected packet %x\n", code[0]);
}
-static void i830EmitTexBlendVerified(drm_device_t * dev,
+static void i830EmitTexBlendVerified(struct drm_device * dev,
unsigned int *code, unsigned int num)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -594,7 +593,7 @@ static void i830EmitTexBlendVerified(drm_device_t * dev,
ADVANCE_LP_RING();
}
-static void i830EmitTexPalette(drm_device_t * dev,
+static void i830EmitTexPalette(struct drm_device * dev,
unsigned int *palette, int number, int is_shared)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -621,7 +620,7 @@ static void i830EmitTexPalette(drm_device_t * dev,
/* Need to do some additional checking when setting the dest buffer.
*/
-static void i830EmitDestVerified(drm_device_t * dev, unsigned int *code)
+static void i830EmitDestVerified(struct drm_device * dev, unsigned int *code)
{
drm_i830_private_t *dev_priv = dev->dev_private;
unsigned int tmp;
@@ -682,7 +681,7 @@ static void i830EmitDestVerified(drm_device_t * dev, unsigned int *code)
ADVANCE_LP_RING();
}
-static void i830EmitStippleVerified(drm_device_t * dev, unsigned int *code)
+static void i830EmitStippleVerified(struct drm_device * dev, unsigned int *code)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -693,7 +692,7 @@ static void i830EmitStippleVerified(drm_device_t * dev, unsigned int *code)
ADVANCE_LP_RING();
}
-static void i830EmitState(drm_device_t * dev)
+static void i830EmitState(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
@@ -796,7 +795,7 @@ static void i830EmitState(drm_device_t * dev)
* Performance monitoring functions
*/
-static void i830_fill_box(drm_device_t * dev,
+static void i830_fill_box(struct drm_device * dev,
int x, int y, int w, int h, int r, int g, int b)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -834,7 +833,7 @@ static void i830_fill_box(drm_device_t * dev,
ADVANCE_LP_RING();
}
-static void i830_cp_performance_boxes(drm_device_t * dev)
+static void i830_cp_performance_boxes(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -879,7 +878,7 @@ static void i830_cp_performance_boxes(drm_device_t * dev)
dev_priv->sarea_priv->perf_boxes = 0;
}
-static void i830_dma_dispatch_clear(drm_device_t * dev, int flags,
+static void i830_dma_dispatch_clear(struct drm_device * dev, int flags,
unsigned int clear_color,
unsigned int clear_zval,
unsigned int clear_depthmask)
@@ -887,7 +886,7 @@ static void i830_dma_dispatch_clear(drm_device_t * dev, int flags,
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int pitch = dev_priv->pitch;
int cpp = dev_priv->cpp;
int i;
@@ -974,12 +973,12 @@ static void i830_dma_dispatch_clear(drm_device_t * dev, int flags,
}
}
-static void i830_dma_dispatch_swap(drm_device_t * dev)
+static void i830_dma_dispatch_swap(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int pitch = dev_priv->pitch;
int cpp = dev_priv->cpp;
int i;
@@ -1044,7 +1043,7 @@ static void i830_dma_dispatch_swap(drm_device_t * dev)
}
}
-static void i830_dma_dispatch_flip(drm_device_t * dev)
+static void i830_dma_dispatch_flip(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -1087,13 +1086,13 @@ static void i830_dma_dispatch_flip(drm_device_t * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}
-static void i830_dma_dispatch_vertex(drm_device_t * dev,
- drm_buf_t * buf, int discard, int used)
+static void i830_dma_dispatch_vertex(struct drm_device * dev,
+ struct drm_buf * buf, int discard, int used)
{
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_clip_rect_t *box = sarea_priv->boxes;
+ struct drm_clip_rect *box = sarea_priv->boxes;
int nbox = sarea_priv->nbox;
unsigned long address = (unsigned long)buf->bus_address;
unsigned long start = address - dev->agp->base;
@@ -1199,7 +1198,7 @@ static void i830_dma_dispatch_vertex(drm_device_t * dev,
}
}
-static void i830_dma_quiescent(drm_device_t * dev)
+static void i830_dma_quiescent(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -1216,10 +1215,10 @@ static void i830_dma_quiescent(drm_device_t * dev)
i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
}
-static int i830_flush_queue(drm_device_t * dev)
+static int i830_flush_queue(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i, ret = 0;
RING_LOCALS;
@@ -1233,7 +1232,7 @@ static int i830_flush_queue(drm_device_t * dev)
i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
int used = cmpxchg(buf_priv->in_use, I830_BUF_HARDWARE,
@@ -1249,9 +1248,9 @@ static int i830_flush_queue(drm_device_t * dev)
}
/* Must be called with the lock held */
-static void i830_reclaim_buffers(drm_device_t * dev, struct file *filp)
+static void i830_reclaim_buffers(struct drm_device * dev, struct file *filp)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i;
if (!dma)
@@ -1264,7 +1263,7 @@ static void i830_reclaim_buffers(drm_device_t * dev, struct file *filp)
i830_flush_queue(dev);
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_i830_buf_priv_t *buf_priv = buf->dev_private;
if (buf->filp == filp && buf_priv) {
@@ -1282,8 +1281,8 @@ static void i830_reclaim_buffers(drm_device_t * dev, struct file *filp)
static int i830_flush_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
LOCK_TEST_WITH_RETURN(dev, filp);
@@ -1294,9 +1293,9 @@ static int i830_flush_ioctl(struct inode *inode, struct file *filp,
static int i830_dma_vertex(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
+ struct drm_device_dma *dma = dev->dma;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
@@ -1328,8 +1327,8 @@ static int i830_dma_vertex(struct inode *inode, struct file *filp,
static int i830_clear_bufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_clear_t clear;
if (copy_from_user
@@ -1352,8 +1351,8 @@ static int i830_clear_bufs(struct inode *inode, struct file *filp,
static int i830_swap_bufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
DRM_DEBUG("i830_swap_bufs\n");
@@ -1365,7 +1364,7 @@ static int i830_swap_bufs(struct inode *inode, struct file *filp,
/* Not sure why this isn't set all the time:
*/
-static void i830_do_init_pageflip(drm_device_t * dev)
+static void i830_do_init_pageflip(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1375,7 +1374,7 @@ static void i830_do_init_pageflip(drm_device_t * dev)
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
}
-static int i830_do_cleanup_pageflip(drm_device_t * dev)
+static int i830_do_cleanup_pageflip(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1390,8 +1389,8 @@ static int i830_do_cleanup_pageflip(drm_device_t * dev)
static int i830_flip_bufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
@@ -1408,8 +1407,8 @@ static int i830_flip_bufs(struct inode *inode, struct file *filp,
static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u32 *hw_status = dev_priv->hw_status_page;
drm_i830_sarea_t *sarea_priv = (drm_i830_sarea_t *)
@@ -1422,8 +1421,8 @@ static int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
static int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
int retcode = 0;
drm_i830_dma_t d;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
@@ -1444,7 +1443,7 @@ static int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
current->pid, retcode, d.granted);
- if (copy_to_user((drm_dma_t __user *) arg, &d, sizeof(d)))
+ if (copy_to_user((void __user *) arg, &d, sizeof(d)))
return -EFAULT;
sarea_priv->last_dispatch = (int)hw_status[5];
@@ -1467,8 +1466,8 @@ static int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd,
static int i830_getparam(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_getparam_t param;
int value;
@@ -1501,8 +1500,8 @@ static int i830_getparam(struct inode *inode, struct file *filp,
static int i830_setparam(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_setparam_t param;
@@ -1526,7 +1525,7 @@ static int i830_setparam(struct inode *inode, struct file *filp,
return 0;
}
-int i830_driver_load(drm_device_t *dev, unsigned long flags)
+int i830_driver_load(struct drm_device *dev, unsigned long flags)
{
/* i830 has 4 more counters */
dev->counters += 4;
@@ -1538,12 +1537,12 @@ int i830_driver_load(drm_device_t *dev, unsigned long flags)
return 0;
}
-void i830_driver_lastclose(drm_device_t * dev)
+void i830_driver_lastclose(struct drm_device * dev)
{
i830_dma_cleanup(dev);
}
-void i830_driver_preclose(drm_device_t * dev, DRMFILE filp)
+void i830_driver_preclose(struct drm_device * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_i830_private_t *dev_priv = dev->dev_private;
@@ -1553,12 +1552,12 @@ void i830_driver_preclose(drm_device_t * dev, DRMFILE filp)
}
}
-void i830_driver_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+void i830_driver_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
{
i830_reclaim_buffers(dev, filp);
}
-int i830_driver_dma_quiescent(drm_device_t * dev)
+int i830_driver_dma_quiescent(struct drm_device * dev)
{
i830_dma_quiescent(dev);
return 0;
@@ -1594,7 +1593,7 @@ int i830_max_ioctl = DRM_ARRAY_SIZE(i830_ioctls);
* \returns
* A value of 1 is always retured to indictate every i8xx is AGP.
*/
-int i830_driver_device_is_agp(drm_device_t * dev)
+int i830_driver_device_is_agp(struct drm_device * dev)
{
return 1;
}
diff --git a/drivers/char/drm/i830_drm.h b/drivers/char/drm/i830_drm.h
index 66dd75027967..968a6d9f9dcb 100644
--- a/drivers/char/drm/i830_drm.h
+++ b/drivers/char/drm/i830_drm.h
@@ -191,7 +191,7 @@ typedef struct _drm_i830_sarea {
unsigned int dirty;
unsigned int nbox;
- drm_clip_rect_t boxes[I830_NR_SAREA_CLIPRECTS];
+ struct drm_clip_rect boxes[I830_NR_SAREA_CLIPRECTS];
/* Maintain an LRU of contiguous regions of texture space. If
* you think you own a region of texture memory, and it has an
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index e91f94afb4bb..ddda67956dea 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -84,8 +84,8 @@ typedef struct _drm_i830_ring_buffer {
} drm_i830_ring_buffer_t;
typedef struct drm_i830_private {
- drm_map_t *sarea_map;
- drm_map_t *mmio_map;
+ struct drm_map *sarea_map;
+ struct drm_map *mmio_map;
drm_i830_sarea_t *sarea_priv;
drm_i830_ring_buffer_t ring;
@@ -95,7 +95,7 @@ typedef struct drm_i830_private {
dma_addr_t dma_status_page;
- drm_buf_t *mmap_buffer;
+ struct drm_buf *mmap_buffer;
u32 front_di1, back_di1, zi1;
@@ -132,16 +132,16 @@ extern int i830_irq_wait(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS);
-extern void i830_driver_irq_preinstall(drm_device_t * dev);
-extern void i830_driver_irq_postinstall(drm_device_t * dev);
-extern void i830_driver_irq_uninstall(drm_device_t * dev);
+extern void i830_driver_irq_preinstall(struct drm_device * dev);
+extern void i830_driver_irq_postinstall(struct drm_device * dev);
+extern void i830_driver_irq_uninstall(struct drm_device * dev);
extern int i830_driver_load(struct drm_device *, unsigned long flags);
-extern void i830_driver_preclose(drm_device_t * dev, DRMFILE filp);
-extern void i830_driver_lastclose(drm_device_t * dev);
-extern void i830_driver_reclaim_buffers_locked(drm_device_t * dev,
+extern void i830_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void i830_driver_lastclose(struct drm_device * dev);
+extern void i830_driver_reclaim_buffers_locked(struct drm_device * dev,
struct file *filp);
-extern int i830_driver_dma_quiescent(drm_device_t * dev);
-extern int i830_driver_device_is_agp(drm_device_t * dev);
+extern int i830_driver_dma_quiescent(struct drm_device * dev);
+extern int i830_driver_device_is_agp(struct drm_device * dev);
#define I830_READ(reg) DRM_READ32(dev_priv->mmio_map, reg)
#define I830_WRITE(reg,val) DRM_WRITE32(dev_priv->mmio_map, reg, val)
@@ -180,7 +180,7 @@ extern int i830_driver_device_is_agp(drm_device_t * dev);
I830_WRITE(LP_RING + RING_TAIL, outring); \
} while(0)
-extern int i830_wait_ring(drm_device_t * dev, int n, const char *caller);
+extern int i830_wait_ring(struct drm_device * dev, int n, const char *caller);
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index 5841f7674956..a1b5c63c3c3e 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -35,7 +35,7 @@
irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
{
- drm_device_t *dev = (drm_device_t *) arg;
+ struct drm_device *dev = (struct drm_device *) arg;
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
u16 temp;
@@ -53,7 +53,7 @@ irqreturn_t i830_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_HANDLED;
}
-static int i830_emit_irq(drm_device_t * dev)
+static int i830_emit_irq(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -70,7 +70,7 @@ static int i830_emit_irq(drm_device_t * dev)
return atomic_read(&dev_priv->irq_emitted);
}
-static int i830_wait_irq(drm_device_t * dev, int irq_nr)
+static int i830_wait_irq(struct drm_device * dev, int irq_nr)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
DECLARE_WAITQUEUE(entry, current);
@@ -117,8 +117,8 @@ static int i830_wait_irq(drm_device_t * dev, int irq_nr)
int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_irq_emit_t emit;
int result;
@@ -149,8 +149,8 @@ int i830_irq_emit(struct inode *inode, struct file *filp, unsigned int cmd,
int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg)
{
- drm_file_t *priv = filp->private_data;
- drm_device_t *dev = priv->head->dev;
+ struct drm_file *priv = filp->private_data;
+ struct drm_device *dev = priv->head->dev;
drm_i830_private_t *dev_priv = dev->dev_private;
drm_i830_irq_wait_t irqwait;
@@ -168,7 +168,7 @@ int i830_irq_wait(struct inode *inode, struct file *filp, unsigned int cmd,
/* drm_dma.h hooks
*/
-void i830_driver_irq_preinstall(drm_device_t * dev)
+void i830_driver_irq_preinstall(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
@@ -180,14 +180,14 @@ void i830_driver_irq_preinstall(drm_device_t * dev)
init_waitqueue_head(&dev_priv->irq_queue);
}
-void i830_driver_irq_postinstall(drm_device_t * dev)
+void i830_driver_irq_postinstall(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
I830_WRITE16(I830REG_INT_ENABLE_R, 0x2);
}
-void i830_driver_irq_uninstall(drm_device_t * dev)
+void i830_driver_irq_uninstall(struct drm_device * dev)
{
drm_i830_private_t *dev_priv = (drm_i830_private_t *) dev->dev_private;
if (!dev_priv)
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index ea52740af4f6..3359cc2b9736 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -47,7 +47,7 @@
* the head pointer changes, so that EBUSY only happens if the ring
* actually stalls for (eg) 3 seconds.
*/
-int i915_wait_ring(drm_device_t * dev, int n, const char *caller)
+int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
@@ -73,7 +73,7 @@ int i915_wait_ring(drm_device_t * dev, int n, const char *caller)
return DRM_ERR(EBUSY);
}
-void i915_kernel_lost_context(drm_device_t * dev)
+void i915_kernel_lost_context(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
@@ -88,7 +88,7 @@ void i915_kernel_lost_context(drm_device_t * dev)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
-static int i915_dma_cleanup(drm_device_t * dev)
+static int i915_dma_cleanup(struct drm_device * dev)
{
/* Make sure interrupts are disabled here because the uninstall ioctl
* may not have been called from userspace and after dev_private
@@ -126,13 +126,13 @@ static int i915_dma_cleanup(drm_device_t * dev)
return 0;
}
-static int i915_initialize(drm_device_t * dev,
+static int i915_initialize(struct drm_device * dev,
drm_i915_private_t * dev_priv,
drm_i915_init_t * init)
{
memset(dev_priv, 0, sizeof(drm_i915_private_t));
- DRM_GETSAREA();
+ dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
dev->dev_private = (void *)dev_priv;
@@ -211,7 +211,7 @@ static int i915_initialize(drm_device_t * dev,
return 0;
}
-static int i915_dma_resume(drm_device_t * dev)
+static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -357,7 +357,7 @@ static int validate_cmd(int cmd)
return ret;
}
-static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
+static int i915_emit_cmds(struct drm_device * dev, int __user * buffer, int dwords)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
@@ -396,12 +396,12 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
return 0;
}
-static int i915_emit_box(drm_device_t * dev,
- drm_clip_rect_t __user * boxes,
+static int i915_emit_box(struct drm_device * dev,
+ struct drm_clip_rect __user * boxes,
int i, int DR1, int DR4)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_clip_rect_t box;
+ struct drm_clip_rect box;
RING_LOCALS;
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
@@ -439,7 +439,7 @@ static int i915_emit_box(drm_device_t * dev,
* emit. For now, do it in both places:
*/
-static void i915_emit_breadcrumb(drm_device_t *dev)
+static void i915_emit_breadcrumb(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -457,7 +457,7 @@ static void i915_emit_breadcrumb(drm_device_t *dev)
ADVANCE_LP_RING();
}
-static int i915_dispatch_cmdbuffer(drm_device_t * dev,
+static int i915_dispatch_cmdbuffer(struct drm_device * dev,
drm_i915_cmdbuffer_t * cmd)
{
int nbox = cmd->num_cliprects;
@@ -489,11 +489,11 @@ static int i915_dispatch_cmdbuffer(drm_device_t * dev,
return 0;
}
-static int i915_dispatch_batchbuffer(drm_device_t * dev,
+static int i915_dispatch_batchbuffer(struct drm_device * dev,
drm_i915_batchbuffer_t * batch)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- drm_clip_rect_t __user *boxes = batch->cliprects;
+ struct drm_clip_rect __user *boxes = batch->cliprects;
int nbox = batch->num_cliprects;
int i = 0, count;
RING_LOCALS;
@@ -535,7 +535,7 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
return 0;
}
-static int i915_dispatch_flip(drm_device_t * dev)
+static int i915_dispatch_flip(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -583,7 +583,7 @@ static int i915_dispatch_flip(drm_device_t * dev)
return 0;
}
-static int i915_quiescent(drm_device_t * dev)
+static int i915_quiescent(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -625,7 +625,7 @@ static int i915_batchbuffer(DRM_IOCTL_ARGS)
if (batch.num_cliprects && DRM_VERIFYAREA_READ(batch.cliprects,
batch.num_cliprects *
- sizeof(drm_clip_rect_t)))
+ sizeof(struct drm_clip_rect)))
return DRM_ERR(EFAULT);
ret = i915_dispatch_batchbuffer(dev, &batch);
@@ -655,7 +655,7 @@ static int i915_cmdbuffer(DRM_IOCTL_ARGS)
if (cmdbuf.num_cliprects &&
DRM_VERIFYAREA_READ(cmdbuf.cliprects,
cmdbuf.num_cliprects *
- sizeof(drm_clip_rect_t))) {
+ sizeof(struct drm_clip_rect))) {
DRM_ERROR("Fault accessing cliprects\n");
return DRM_ERR(EFAULT);
}
@@ -792,7 +792,7 @@ static int i915_set_status_page(DRM_IOCTL_ARGS)
return 0;
}
-int i915_driver_load(drm_device_t *dev, unsigned long flags)
+int i915_driver_load(struct drm_device *dev, unsigned long flags)
{
/* i915 has 4 more counters */
dev->counters += 4;
@@ -804,7 +804,7 @@ int i915_driver_load(drm_device_t *dev, unsigned long flags)
return 0;
}
-void i915_driver_lastclose(drm_device_t * dev)
+void i915_driver_lastclose(struct drm_device * dev)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -813,7 +813,7 @@ void i915_driver_lastclose(drm_device_t * dev)
i915_dma_cleanup(dev);
}
-void i915_driver_preclose(drm_device_t * dev, DRMFILE filp)
+void i915_driver_preclose(struct drm_device * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -854,7 +854,7 @@ int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
* \returns
* A value of 1 is always retured to indictate every i9x5 is AGP.
*/
-int i915_driver_device_is_agp(drm_device_t * dev)
+int i915_driver_device_is_agp(struct drm_device * dev)
{
return 1;
}
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 7b7b68b96f31..05c66cf03a9e 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -64,7 +64,7 @@ typedef struct _drm_i915_init {
} drm_i915_init_t;
typedef struct _drm_i915_sarea {
- drm_tex_region_t texList[I915_NR_TEX_REGIONS + 1];
+ struct drm_tex_region texList[I915_NR_TEX_REGIONS + 1];
int last_upload; /* last time texture was uploaded */
int last_enqueue; /* last time a buffer was enqueued */
int last_dispatch; /* age of the most recently dispatched buffer */
@@ -170,7 +170,7 @@ typedef struct _drm_i915_batchbuffer {
int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */
int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */
int num_cliprects; /* mulitpass with multiple cliprects? */
- drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */
+ struct drm_clip_rect __user *cliprects; /* pointer to userspace cliprects */
} drm_i915_batchbuffer_t;
/* As above, but pass a pointer to userspace buffer which can be
@@ -182,7 +182,7 @@ typedef struct _drm_i915_cmdbuffer {
int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */
int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */
int num_cliprects; /* mulitpass with multiple cliprects? */
- drm_clip_rect_t __user *cliprects; /* pointer to userspace cliprects */
+ struct drm_clip_rect __user *cliprects; /* pointer to userspace cliprects */
} drm_i915_cmdbuffer_t;
/* Userspace can request & wait on irq's:
@@ -259,7 +259,7 @@ typedef struct drm_i915_vblank_pipe {
*/
typedef struct drm_i915_vblank_swap {
drm_drawable_t drawable;
- drm_vblank_seq_type_t seqtype;
+ enum drm_vblank_seq_type seqtype;
unsigned int sequence;
} drm_i915_vblank_swap_t;
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 85e323acb95d..fd918565f4e5 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -120,11 +120,11 @@ extern drm_ioctl_desc_t i915_ioctls[];
extern int i915_max_ioctl;
/* i915_dma.c */
-extern void i915_kernel_lost_context(drm_device_t * dev);
+extern void i915_kernel_lost_context(struct drm_device * dev);
extern int i915_driver_load(struct drm_device *, unsigned long flags);
-extern void i915_driver_lastclose(drm_device_t * dev);
-extern void i915_driver_preclose(drm_device_t * dev, DRMFILE filp);
-extern int i915_driver_device_is_agp(drm_device_t * dev);
+extern void i915_driver_lastclose(struct drm_device * dev);
+extern void i915_driver_preclose(struct drm_device * dev, DRMFILE filp);
+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);
@@ -132,12 +132,12 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
extern int i915_irq_emit(DRM_IOCTL_ARGS);
extern int i915_irq_wait(DRM_IOCTL_ARGS);
-extern int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence);
-extern int i915_driver_vblank_wait2(drm_device_t *dev, unsigned int *sequence);
+extern int i915_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
+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(drm_device_t * dev);
-extern void i915_driver_irq_postinstall(drm_device_t * dev);
-extern void i915_driver_irq_uninstall(drm_device_t * dev);
+extern void i915_driver_irq_preinstall(struct drm_device * dev);
+extern void i915_driver_irq_postinstall(struct drm_device * dev);
+extern void i915_driver_irq_uninstall(struct drm_device * dev);
extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
extern int i915_vblank_swap(DRM_IOCTL_ARGS);
@@ -148,7 +148,7 @@ extern int i915_mem_free(DRM_IOCTL_ARGS);
extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
extern void i915_mem_takedown(struct mem_block **heap);
-extern void i915_mem_release(drm_device_t * dev,
+extern void i915_mem_release(struct drm_device * dev,
DRMFILE filp, struct mem_block *heap);
#define I915_READ(reg) DRM_READ32(dev_priv->mmio_map, (reg))
@@ -188,7 +188,7 @@ extern void i915_mem_release(drm_device_t * dev,
I915_WRITE(LP_RING + RING_TAIL, outring); \
} while(0)
-extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
+extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
#define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23))
#define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23))
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index b92062a239f1..4b4b2ce89863 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -42,7 +42,7 @@
*
* This function will be called with the HW lock held.
*/
-static void i915_vblank_tasklet(drm_device_t *dev)
+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;
@@ -50,7 +50,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
int nhits, nrects, slice[2], upper[2], lower[2], i;
unsigned counter[2] = { atomic_read(&dev->vbl_received),
atomic_read(&dev->vbl_received2) };
- drm_drawable_info_t *drw;
+ struct drm_drawable_info *drw;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
u32 cpp = dev_priv->cpp;
u32 cmd = (cpp == 4) ? (XY_SRC_COPY_BLT_CMD |
@@ -95,7 +95,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
list_for_each(hit, &hits) {
drm_i915_vbl_swap_t *swap_cmp =
list_entry(hit, drm_i915_vbl_swap_t, head);
- drm_drawable_info_t *drw_cmp =
+ struct drm_drawable_info *drw_cmp =
drm_get_drawable_info(dev, swap_cmp->drw_id);
if (drw_cmp &&
@@ -160,7 +160,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
list_for_each(hit, &hits) {
drm_i915_vbl_swap_t *swap_hit =
list_entry(hit, drm_i915_vbl_swap_t, head);
- drm_clip_rect_t *rect;
+ struct drm_clip_rect *rect;
int num_rects, pipe;
unsigned short top, bottom;
@@ -211,7 +211,7 @@ static void i915_vblank_tasklet(drm_device_t *dev)
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
- drm_device_t *dev = (drm_device_t *) arg;
+ struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 temp;
@@ -257,7 +257,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_HANDLED;
}
-static int i915_emit_irq(drm_device_t * dev)
+static int i915_emit_irq(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -283,7 +283,7 @@ static int i915_emit_irq(drm_device_t * dev)
return dev_priv->counter;
}
-static int i915_wait_irq(drm_device_t * dev, int irq_nr)
+static int i915_wait_irq(struct drm_device * dev, int irq_nr)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = 0;
@@ -309,7 +309,7 @@ static int i915_wait_irq(drm_device_t * dev, int irq_nr)
return ret;
}
-static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
+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;
@@ -331,12 +331,12 @@ static int i915_driver_vblank_do_wait(drm_device_t *dev, unsigned int *sequence,
}
-int i915_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
+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(drm_device_t *dev, unsigned int *sequence)
+int i915_driver_vblank_wait2(struct drm_device *dev, unsigned int *sequence)
{
return i915_driver_vblank_do_wait(dev, sequence, &dev->vbl_received2);
}
@@ -389,7 +389,7 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
-static void i915_enable_interrupt (drm_device_t *dev)
+static void i915_enable_interrupt (struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 flag;
@@ -569,7 +569,7 @@ int i915_vblank_swap(DRM_IOCTL_ARGS)
/* drm_dma.h hooks
*/
-void i915_driver_irq_preinstall(drm_device_t * dev)
+void i915_driver_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -578,7 +578,7 @@ void i915_driver_irq_preinstall(drm_device_t * dev)
I915_WRITE16(I915REG_INT_ENABLE_R, 0x0);
}
-void i915_driver_irq_postinstall(drm_device_t * dev)
+void i915_driver_irq_postinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -592,7 +592,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}
-void i915_driver_irq_uninstall(drm_device_t * dev)
+void i915_driver_irq_uninstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u16 temp;
diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c
index 52c67324df58..50b4bacef0e0 100644
--- a/drivers/char/drm/i915_mem.c
+++ b/drivers/char/drm/i915_mem.c
@@ -43,11 +43,11 @@
* block to allocate, and the ring is drained prior to allocations --
* in other words allocation is expensive.
*/
-static void mark_block(drm_device_t * dev, struct mem_block *p, int in_use)
+static void mark_block(struct drm_device * dev, struct mem_block *p, int in_use)
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_tex_region_t *list;
+ struct drm_tex_region *list;
unsigned shift, nr;
unsigned start;
unsigned end;
@@ -208,7 +208,7 @@ static int init_heap(struct mem_block **heap, int start, int size)
/* Free all blocks associated with the releasing file.
*/
-void i915_mem_release(drm_device_t * dev, DRMFILE filp, struct mem_block *heap)
+void i915_mem_release(struct drm_device * dev, DRMFILE filp, struct mem_block *heap)
{
struct mem_block *p;
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
index c2a4bac14521..9c73a6e3861b 100644
--- a/drivers/char/drm/mga_dma.c
+++ b/drivers/char/drm/mga_dma.c
@@ -46,7 +46,7 @@
#define MINIMAL_CLEANUP 0
#define FULL_CLEANUP 1
-static int mga_do_cleanup_dma(drm_device_t *dev, int full_cleanup);
+static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup);
/* ================================================================
* Engine control
@@ -224,7 +224,7 @@ void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv)
#define MGA_BUFFER_FREE 0
#if MGA_FREELIST_DEBUG
-static void mga_freelist_print(drm_device_t * dev)
+static void mga_freelist_print(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_freelist_t *entry;
@@ -245,10 +245,10 @@ static void mga_freelist_print(drm_device_t * dev)
}
#endif
-static int mga_freelist_init(drm_device_t * dev, drm_mga_private_t * dev_priv)
+static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_priv)
{
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
drm_mga_freelist_t *entry;
int i;
@@ -291,7 +291,7 @@ static int mga_freelist_init(drm_device_t * dev, drm_mga_private_t * dev_priv)
return 0;
}
-static void mga_freelist_cleanup(drm_device_t * dev)
+static void mga_freelist_cleanup(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_freelist_t *entry;
@@ -311,10 +311,10 @@ static void mga_freelist_cleanup(drm_device_t * dev)
#if 0
/* FIXME: Still needed?
*/
-static void mga_freelist_reset(drm_device_t * dev)
+static void mga_freelist_reset(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
int i;
@@ -326,7 +326,7 @@ static void mga_freelist_reset(drm_device_t * dev)
}
#endif
-static drm_buf_t *mga_freelist_get(drm_device_t * dev)
+static struct drm_buf *mga_freelist_get(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_freelist_t *next;
@@ -359,7 +359,7 @@ static drm_buf_t *mga_freelist_get(drm_device_t * dev)
return NULL;
}
-int mga_freelist_put(drm_device_t * dev, drm_buf_t * buf)
+int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_buf_priv_t *buf_priv = buf->dev_private;
@@ -393,7 +393,7 @@ int mga_freelist_put(drm_device_t * dev, drm_buf_t * buf)
* DMA initialization, cleanup
*/
-int mga_driver_load(drm_device_t * dev, unsigned long flags)
+int mga_driver_load(struct drm_device * dev, unsigned long flags)
{
drm_mga_private_t *dev_priv;
@@ -434,7 +434,7 @@ int mga_driver_load(drm_device_t * dev, unsigned long flags)
*
* \sa mga_do_dma_bootstrap, mga_do_pci_dma_bootstrap
*/
-static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
+static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
drm_mga_dma_bootstrap_t * dma_bs)
{
drm_mga_private_t *const dev_priv =
@@ -445,11 +445,11 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
const unsigned secondary_size = dma_bs->secondary_bin_count
* dma_bs->secondary_bin_size;
const unsigned agp_size = (dma_bs->agp_size << 20);
- drm_buf_desc_t req;
- drm_agp_mode_t mode;
- drm_agp_info_t info;
- drm_agp_buffer_t agp_req;
- drm_agp_binding_t bind_req;
+ struct drm_buf_desc req;
+ struct drm_agp_mode mode;
+ struct drm_agp_info info;
+ struct drm_agp_buffer agp_req;
+ struct drm_agp_binding bind_req;
/* Acquire AGP. */
err = drm_agp_acquire(dev);
@@ -548,10 +548,10 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
}
{
- drm_map_list_t *_entry;
+ struct drm_map_list *_entry;
unsigned long agp_token = 0;
- list_for_each_entry(_entry, &dev->maplist->head, head) {
+ list_for_each_entry(_entry, &dev->maplist, head) {
if (_entry->map == dev->agp_buffer_map)
agp_token = _entry->user_token;
}
@@ -588,7 +588,7 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
return 0;
}
#else
-static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
+static int mga_do_agp_dma_bootstrap(struct drm_device * dev,
drm_mga_dma_bootstrap_t * dma_bs)
{
return -EINVAL;
@@ -609,7 +609,7 @@ static int mga_do_agp_dma_bootstrap(drm_device_t * dev,
*
* \sa mga_do_dma_bootstrap, mga_do_agp_dma_bootstrap
*/
-static int mga_do_pci_dma_bootstrap(drm_device_t * dev,
+static int mga_do_pci_dma_bootstrap(struct drm_device * dev,
drm_mga_dma_bootstrap_t * dma_bs)
{
drm_mga_private_t *const dev_priv =
@@ -618,7 +618,7 @@ static int mga_do_pci_dma_bootstrap(drm_device_t * dev,
unsigned int primary_size;
unsigned int bin_count;
int err;
- drm_buf_desc_t req;
+ struct drm_buf_desc req;
if (dev->dma == NULL) {
DRM_ERROR("dev->dma is NULL\n");
@@ -699,7 +699,7 @@ static int mga_do_pci_dma_bootstrap(drm_device_t * dev,
return 0;
}
-static int mga_do_dma_bootstrap(drm_device_t * dev,
+static int mga_do_dma_bootstrap(struct drm_device * dev,
drm_mga_dma_bootstrap_t * dma_bs)
{
const int is_agp = (dma_bs->agp_mode != 0) && drm_device_is_agp(dev);
@@ -793,7 +793,7 @@ int mga_dma_bootstrap(DRM_IOCTL_ARGS)
return err;
}
-static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init)
+static int mga_do_init_dma(struct drm_device * dev, drm_mga_init_t * init)
{
drm_mga_private_t *dev_priv;
int ret;
@@ -823,8 +823,7 @@ static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init)
dev_priv->texture_offset = init->texture_offset[0];
dev_priv->texture_size = init->texture_size[0];
- DRM_GETSAREA();
-
+ dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("failed to find sarea!\n");
return DRM_ERR(EINVAL);
@@ -934,7 +933,7 @@ static int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init)
return 0;
}
-static int mga_do_cleanup_dma(drm_device_t *dev, int full_cleanup)
+static int mga_do_cleanup_dma(struct drm_device *dev, int full_cleanup)
{
int err = 0;
DRM_DEBUG("\n");
@@ -963,8 +962,8 @@ static int mga_do_cleanup_dma(drm_device_t *dev, int full_cleanup)
if (dev_priv->used_new_dma_init) {
#if __OS_HAS_AGP
if (dev_priv->agp_handle != 0) {
- drm_agp_binding_t unbind_req;
- drm_agp_buffer_t free_req;
+ struct drm_agp_binding unbind_req;
+ struct drm_agp_buffer free_req;
unbind_req.handle = dev_priv->agp_handle;
drm_agp_unbind(dev, &unbind_req);
@@ -1041,11 +1040,11 @@ int mga_dma_flush(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- drm_lock_t lock;
+ struct drm_lock lock;
LOCK_TEST_WITH_RETURN(dev, filp);
- DRM_COPY_FROM_USER_IOCTL(lock, (drm_lock_t __user *) data,
+ DRM_COPY_FROM_USER_IOCTL(lock, (struct drm_lock __user *) data,
sizeof(lock));
DRM_DEBUG("%s%s%s\n",
@@ -1087,9 +1086,9 @@ int mga_dma_reset(DRM_IOCTL_ARGS)
* DMA buffer management
*/
-static int mga_dma_get_buffers(DRMFILE filp, drm_device_t * dev, drm_dma_t * d)
+static int mga_dma_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
{
- drm_buf_t *buf;
+ struct drm_buf *buf;
int i;
for (i = d->granted_count; i < d->request_count; i++) {
@@ -1114,10 +1113,10 @@ static int mga_dma_get_buffers(DRMFILE filp, drm_device_t * dev, drm_dma_t * d)
int mga_dma_buffers(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
- drm_dma_t __user *argp = (void __user *)data;
- drm_dma_t d;
+ struct drm_dma __user *argp = (void __user *)data;
+ struct drm_dma d;
int ret = 0;
LOCK_TEST_WITH_RETURN(dev, filp);
@@ -1156,7 +1155,7 @@ int mga_dma_buffers(DRM_IOCTL_ARGS)
/**
* Called just before the module is unloaded.
*/
-int mga_driver_unload(drm_device_t * dev)
+int mga_driver_unload(struct drm_device * dev)
{
drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
dev->dev_private = NULL;
@@ -1167,12 +1166,12 @@ int mga_driver_unload(drm_device_t * dev)
/**
* Called when the last opener of the device is closed.
*/
-void mga_driver_lastclose(drm_device_t * dev)
+void mga_driver_lastclose(struct drm_device * dev)
{
mga_do_cleanup_dma(dev, FULL_CLEANUP);
}
-int mga_driver_dma_quiescent(drm_device_t * dev)
+int mga_driver_dma_quiescent(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = dev->dev_private;
return mga_do_wait_for_idle(dev_priv);
diff --git a/drivers/char/drm/mga_drm.h b/drivers/char/drm/mga_drm.h
index 44d1293e2947..944b50a5ff24 100644
--- a/drivers/char/drm/mga_drm.h
+++ b/drivers/char/drm/mga_drm.h
@@ -181,7 +181,7 @@ typedef struct _drm_mga_sarea {
/* The current cliprects, or a subset thereof.
*/
- drm_clip_rect_t boxes[MGA_NR_SAREA_CLIPRECTS];
+ struct drm_clip_rect boxes[MGA_NR_SAREA_CLIPRECTS];
unsigned int nbox;
/* Information about the most recently used 3d drawable. The
@@ -202,7 +202,7 @@ typedef struct _drm_mga_sarea {
unsigned int exported_nback;
int exported_back_x, exported_front_x, exported_w;
int exported_back_y, exported_front_y, exported_h;
- drm_clip_rect_t exported_boxes[MGA_NR_SAREA_CLIPRECTS];
+ struct drm_clip_rect exported_boxes[MGA_NR_SAREA_CLIPRECTS];
/* Counters for aging textures and for client-side throttling.
*/
@@ -216,7 +216,7 @@ typedef struct _drm_mga_sarea {
/* LRU lists for texture memory in agp space and on the card.
*/
- drm_tex_region_t texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS + 1];
+ struct drm_tex_region texList[MGA_NR_TEX_HEAPS][MGA_NR_TEX_REGIONS + 1];
unsigned int texAge[MGA_NR_TEX_HEAPS];
/* Mechanism to validate card state.
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index be49dbb9ec3f..5572939fc7d1 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -36,7 +36,7 @@
#include "drm_pciids.h"
-static int mga_driver_device_is_agp(drm_device_t * dev);
+static int mga_driver_device_is_agp(struct drm_device * dev);
static struct pci_device_id pciidlist[] = {
mga_PCI_IDS
@@ -118,7 +118,7 @@ MODULE_LICENSE("GPL and additional rights");
* \returns
* If the device is a PCI G450, zero is returned. Otherwise 2 is returned.
*/
-static int mga_driver_device_is_agp(drm_device_t * dev)
+static int mga_driver_device_is_agp(struct drm_device * dev)
{
const struct pci_dev *const pdev = dev->pdev;
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index 6b0c53193506..49253affa475 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -65,7 +65,7 @@ typedef struct drm_mga_freelist {
struct drm_mga_freelist *next;
struct drm_mga_freelist *prev;
drm_mga_age_t age;
- drm_buf_t *buf;
+ struct drm_buf *buf;
} drm_mga_freelist_t;
typedef struct {
@@ -157,10 +157,10 @@ extern int mga_dma_init(DRM_IOCTL_ARGS);
extern int mga_dma_flush(DRM_IOCTL_ARGS);
extern int mga_dma_reset(DRM_IOCTL_ARGS);
extern int mga_dma_buffers(DRM_IOCTL_ARGS);
-extern int mga_driver_load(drm_device_t *dev, unsigned long flags);
-extern int mga_driver_unload(drm_device_t * dev);
-extern void mga_driver_lastclose(drm_device_t * dev);
-extern int mga_driver_dma_quiescent(drm_device_t * dev);
+extern int mga_driver_load(struct drm_device *dev, unsigned long flags);
+extern int mga_driver_unload(struct drm_device * dev);
+extern void mga_driver_lastclose(struct drm_device * dev);
+extern int mga_driver_dma_quiescent(struct drm_device * dev);
extern int mga_do_wait_for_idle(drm_mga_private_t * dev_priv);
@@ -168,7 +168,7 @@ extern void mga_do_dma_flush(drm_mga_private_t * dev_priv);
extern void mga_do_dma_wrap_start(drm_mga_private_t * dev_priv);
extern void mga_do_dma_wrap_end(drm_mga_private_t * dev_priv);
-extern int mga_freelist_put(drm_device_t * dev, drm_buf_t * buf);
+extern int mga_freelist_put(struct drm_device * dev, struct drm_buf * buf);
/* mga_warp.c */
extern unsigned int mga_warp_microcode_size(const drm_mga_private_t * dev_priv);
@@ -176,12 +176,12 @@ 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_driver_fence_wait(drm_device_t * dev, unsigned int *sequence);
-extern int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+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(drm_device_t * dev);
-extern void mga_driver_irq_postinstall(drm_device_t * dev);
-extern void mga_driver_irq_uninstall(drm_device_t * dev);
+extern void mga_driver_irq_preinstall(struct drm_device * dev);
+extern void 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 eb9644024172..9302cb8f0f83 100644
--- a/drivers/char/drm/mga_irq.c
+++ b/drivers/char/drm/mga_irq.c
@@ -37,7 +37,7 @@
irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
{
- drm_device_t *dev = (drm_device_t *) arg;
+ struct drm_device *dev = (struct drm_device *) arg;
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
int status;
int handled = 0;
@@ -78,7 +78,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_NONE;
}
-int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+int mga_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
{
unsigned int cur_vblank;
int ret = 0;
@@ -96,7 +96,7 @@ int mga_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
return ret;
}
-int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
+int mga_driver_fence_wait(struct drm_device * dev, unsigned int *sequence)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
unsigned int cur_fence;
@@ -115,7 +115,7 @@ int mga_driver_fence_wait(drm_device_t * dev, unsigned int *sequence)
return ret;
}
-void mga_driver_irq_preinstall(drm_device_t * dev)
+void mga_driver_irq_preinstall(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
@@ -125,7 +125,7 @@ void mga_driver_irq_preinstall(drm_device_t * dev)
MGA_WRITE(MGA_ICLEAR, ~0);
}
-void mga_driver_irq_postinstall(drm_device_t * dev)
+void mga_driver_irq_postinstall(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
@@ -135,7 +135,7 @@ void mga_driver_irq_postinstall(drm_device_t * dev)
MGA_WRITE(MGA_IEN, MGA_VLINEIEN | MGA_SOFTRAPEN);
}
-void mga_driver_irq_uninstall(drm_device_t * dev)
+void mga_driver_irq_uninstall(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
if (!dev_priv)
diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c
index 2837e669183a..d448b0aef33c 100644
--- a/drivers/char/drm/mga_state.c
+++ b/drivers/char/drm/mga_state.c
@@ -42,7 +42,7 @@
*/
static void mga_emit_clip_rect(drm_mga_private_t * dev_priv,
- drm_clip_rect_t * box)
+ struct drm_clip_rect * box)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
@@ -480,12 +480,12 @@ static int mga_verify_blit(drm_mga_private_t * dev_priv,
*
*/
-static void mga_dma_dispatch_clear(drm_device_t * dev, drm_mga_clear_t * clear)
+static void mga_dma_dispatch_clear(struct drm_device * dev, drm_mga_clear_t * clear)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int nbox = sarea_priv->nbox;
int i;
DMA_LOCALS;
@@ -500,7 +500,7 @@ static void mga_dma_dispatch_clear(drm_device_t * dev, drm_mga_clear_t * clear)
ADVANCE_DMA();
for (i = 0; i < nbox; i++) {
- drm_clip_rect_t *box = &pbox[i];
+ struct drm_clip_rect *box = &pbox[i];
u32 height = box->y2 - box->y1;
DRM_DEBUG(" from=%d,%d to=%d,%d\n",
@@ -568,12 +568,12 @@ static void mga_dma_dispatch_clear(drm_device_t * dev, drm_mga_clear_t * clear)
FLUSH_DMA();
}
-static void mga_dma_dispatch_swap(drm_device_t * dev)
+static void mga_dma_dispatch_swap(struct drm_device * dev)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int nbox = sarea_priv->nbox;
int i;
DMA_LOCALS;
@@ -598,7 +598,7 @@ static void mga_dma_dispatch_swap(drm_device_t * dev)
MGA_PLNWT, 0xffffffff, MGA_DWGCTL, MGA_DWGCTL_COPY);
for (i = 0; i < nbox; i++) {
- drm_clip_rect_t *box = &pbox[i];
+ struct drm_clip_rect *box = &pbox[i];
u32 height = box->y2 - box->y1;
u32 start = box->y1 * dev_priv->front_pitch;
@@ -622,7 +622,7 @@ static void mga_dma_dispatch_swap(drm_device_t * dev)
DRM_DEBUG("%s... done.\n", __FUNCTION__);
}
-static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf)
+static void mga_dma_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_buf_priv_t *buf_priv = buf->dev_private;
@@ -669,7 +669,7 @@ static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf)
FLUSH_DMA();
}
-static void mga_dma_dispatch_indices(drm_device_t * dev, drm_buf_t * buf,
+static void mga_dma_dispatch_indices(struct drm_device * dev, struct drm_buf * buf,
unsigned int start, unsigned int end)
{
drm_mga_private_t *dev_priv = dev->dev_private;
@@ -718,7 +718,7 @@ static void mga_dma_dispatch_indices(drm_device_t * dev, drm_buf_t * buf,
/* This copies a 64 byte aligned agp region to the frambuffer with a
* standard blit, the ioctl needs to do checking.
*/
-static void mga_dma_dispatch_iload(drm_device_t * dev, drm_buf_t * buf,
+static void mga_dma_dispatch_iload(struct drm_device * dev, struct drm_buf * buf,
unsigned int dstorg, unsigned int length)
{
drm_mga_private_t *dev_priv = dev->dev_private;
@@ -766,12 +766,12 @@ static void mga_dma_dispatch_iload(drm_device_t * dev, drm_buf_t * buf,
FLUSH_DMA();
}
-static void mga_dma_dispatch_blit(drm_device_t * dev, drm_mga_blit_t * blit)
+static void mga_dma_dispatch_blit(struct drm_device * dev, drm_mga_blit_t * blit)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_context_regs_t *ctx = &sarea_priv->context_state;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int nbox = sarea_priv->nbox;
u32 scandir = 0, i;
DMA_LOCALS;
@@ -880,8 +880,8 @@ static int mga_dma_vertex(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
drm_mga_vertex_t vertex;
@@ -920,8 +920,8 @@ static int mga_dma_indices(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_mga_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
drm_mga_indices_t indices;
@@ -959,9 +959,9 @@ static int mga_dma_indices(DRM_IOCTL_ARGS)
static int mga_dma_iload(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_mga_private_t *dev_priv = dev->dev_private;
- drm_buf_t *buf;
+ struct drm_buf *buf;
drm_mga_buf_priv_t *buf_priv;
drm_mga_iload_t iload;
DRM_DEBUG("\n");
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index 1014602c43a7..b163ed09bd81 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -81,7 +81,7 @@ static u32 r128_cce_microcode[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
-static int R128_READ_PLL(drm_device_t * dev, int addr)
+static int R128_READ_PLL(struct drm_device * dev, int addr)
{
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -271,7 +271,7 @@ static void r128_do_cce_stop(drm_r128_private_t * dev_priv)
/* Reset the engine. This will stop the CCE if it is running.
*/
-static int r128_do_engine_reset(drm_device_t * dev)
+static int r128_do_engine_reset(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
u32 clock_cntl_index, mclk_cntl, gen_reset_cntl;
@@ -308,7 +308,7 @@ static int r128_do_engine_reset(drm_device_t * dev)
return 0;
}
-static void r128_cce_init_ring_buffer(drm_device_t * dev,
+static void r128_cce_init_ring_buffer(struct drm_device * dev,
drm_r128_private_t * dev_priv)
{
u32 ring_start;
@@ -347,7 +347,7 @@ static void r128_cce_init_ring_buffer(drm_device_t * dev,
R128_WRITE(R128_BUS_CNTL, tmp);
}
-static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init)
+static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
{
drm_r128_private_t *dev_priv;
@@ -456,8 +456,7 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init)
dev_priv->span_pitch_offset_c = (((dev_priv->depth_pitch / 8) << 21) |
(dev_priv->span_offset >> 5));
- DRM_GETSAREA();
-
+ dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
dev->dev_private = (void *)dev_priv;
@@ -585,7 +584,7 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init)
return 0;
}
-int r128_do_cleanup_cce(drm_device_t * dev)
+int r128_do_cleanup_cce(struct drm_device * dev)
{
/* Make sure interrupts are disabled here because the uninstall ioctl
@@ -770,11 +769,11 @@ int r128_fullscreen(DRM_IOCTL_ARGS)
#define R128_BUFFER_FREE 0
#if 0
-static int r128_freelist_init(drm_device_t * dev)
+static int r128_freelist_init(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_buf_t *buf;
+ struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
drm_r128_freelist_t *entry;
int i;
@@ -816,12 +815,12 @@ static int r128_freelist_init(drm_device_t * dev)
}
#endif
-static drm_buf_t *r128_freelist_get(drm_device_t * dev)
+static struct drm_buf *r128_freelist_get(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_buf_priv_t *buf_priv;
- drm_buf_t *buf;
+ struct drm_buf *buf;
int i, t;
/* FIXME: Optimize -- use freelist code */
@@ -854,13 +853,13 @@ static drm_buf_t *r128_freelist_get(drm_device_t * dev)
return NULL;
}
-void r128_freelist_reset(drm_device_t * dev)
+void r128_freelist_reset(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int i;
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_r128_buf_priv_t *buf_priv = buf->dev_private;
buf_priv->age = 0;
}
@@ -887,10 +886,10 @@ int r128_wait_ring(drm_r128_private_t * dev_priv, int n)
return DRM_ERR(EBUSY);
}
-static int r128_cce_get_buffers(DRMFILE filp, drm_device_t * dev, drm_dma_t * d)
+static int r128_cce_get_buffers(DRMFILE filp, struct drm_device * dev, struct drm_dma * d)
{
int i;
- drm_buf_t *buf;
+ struct drm_buf *buf;
for (i = d->granted_count; i < d->request_count; i++) {
buf = r128_freelist_get(dev);
@@ -914,10 +913,10 @@ static int r128_cce_get_buffers(DRMFILE filp, drm_device_t * dev, drm_dma_t * d)
int r128_cce_buffers(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int ret = 0;
- drm_dma_t __user *argp = (void __user *)data;
- drm_dma_t d;
+ struct drm_dma __user *argp = (void __user *)data;
+ struct drm_dma d;
LOCK_TEST_WITH_RETURN(dev, filp);
diff --git a/drivers/char/drm/r128_drm.h b/drivers/char/drm/r128_drm.h
index 6e8af313f2b4..e94a39c6e327 100644
--- a/drivers/char/drm/r128_drm.h
+++ b/drivers/char/drm/r128_drm.h
@@ -153,7 +153,7 @@ typedef struct drm_r128_sarea {
/* The current cliprects, or a subset thereof.
*/
- drm_clip_rect_t boxes[R128_NR_SAREA_CLIPRECTS];
+ struct drm_clip_rect boxes[R128_NR_SAREA_CLIPRECTS];
unsigned int nbox;
/* Counters for client-side throttling of rendering clients.
@@ -161,7 +161,7 @@ typedef struct drm_r128_sarea {
unsigned int last_frame;
unsigned int last_dispatch;
- drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS + 1];
+ struct drm_tex_region tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS + 1];
unsigned int tex_age[R128_NR_TEX_HEAPS];
int ctx_owner;
int pfAllowPageFlip; /* number of 3d windows (0,1,2 or more) */
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 9086835686dc..72249fb2fd1c 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -57,7 +57,7 @@
typedef struct drm_r128_freelist {
unsigned int age;
- drm_buf_t *buf;
+ struct drm_buf *buf;
struct drm_r128_freelist *next;
struct drm_r128_freelist *prev;
} drm_r128_freelist_t;
@@ -118,7 +118,7 @@ typedef struct drm_r128_private {
drm_local_map_t *cce_ring;
drm_local_map_t *ring_rptr;
drm_local_map_t *agp_textures;
- drm_ati_pcigart_info gart_info;
+ struct drm_ati_pcigart_info gart_info;
} drm_r128_private_t;
typedef struct drm_r128_buf_priv {
@@ -142,21 +142,21 @@ extern int r128_engine_reset(DRM_IOCTL_ARGS);
extern int r128_fullscreen(DRM_IOCTL_ARGS);
extern int r128_cce_buffers(DRM_IOCTL_ARGS);
-extern void r128_freelist_reset(drm_device_t * dev);
+extern void r128_freelist_reset(struct drm_device * dev);
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(drm_device_t * dev);
+extern int r128_do_cleanup_cce(struct drm_device * dev);
-extern int r128_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+extern int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
-extern void r128_driver_irq_preinstall(drm_device_t * dev);
-extern void r128_driver_irq_postinstall(drm_device_t * dev);
-extern void r128_driver_irq_uninstall(drm_device_t * dev);
-extern void r128_driver_lastclose(drm_device_t * dev);
-extern void r128_driver_preclose(drm_device_t * dev, DRMFILE filp);
+extern void r128_driver_irq_preinstall(struct drm_device * dev);
+extern void 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, DRMFILE filp);
extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
diff --git a/drivers/char/drm/r128_irq.c b/drivers/char/drm/r128_irq.c
index 87f8ca2b0685..c76fdca7662d 100644
--- a/drivers/char/drm/r128_irq.c
+++ b/drivers/char/drm/r128_irq.c
@@ -37,7 +37,7 @@
irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
{
- drm_device_t *dev = (drm_device_t *) arg;
+ struct drm_device *dev = (struct drm_device *) arg;
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
int status;
@@ -54,7 +54,7 @@ irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_NONE;
}
-int r128_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+int r128_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
{
unsigned int cur_vblank;
int ret = 0;
@@ -72,7 +72,7 @@ int r128_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
return ret;
}
-void r128_driver_irq_preinstall(drm_device_t * dev)
+void r128_driver_irq_preinstall(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
@@ -82,7 +82,7 @@ void r128_driver_irq_preinstall(drm_device_t * dev)
R128_WRITE(R128_GEN_INT_STATUS, R128_CRTC_VBLANK_INT_AK);
}
-void r128_driver_irq_postinstall(drm_device_t * dev)
+void r128_driver_irq_postinstall(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
@@ -90,7 +90,7 @@ void r128_driver_irq_postinstall(drm_device_t * dev)
R128_WRITE(R128_GEN_INT_CNTL, R128_CRTC_VBLANK_INT_EN);
}
-void r128_driver_irq_uninstall(drm_device_t * dev)
+void r128_driver_irq_uninstall(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
if (!dev_priv)
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index 17b11e7d8f32..7b334fb7d649 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -38,7 +38,7 @@
*/
static void r128_emit_clip_rects(drm_r128_private_t * dev_priv,
- drm_clip_rect_t * boxes, int count)
+ struct drm_clip_rect * boxes, int count)
{
u32 aux_sc_cntl = 0x00000000;
RING_LOCALS;
@@ -352,13 +352,13 @@ static void r128_print_dirty(const char *msg, unsigned int flags)
(flags & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "");
}
-static void r128_cce_dispatch_clear(drm_device_t * dev,
+static void r128_cce_dispatch_clear(struct drm_device * dev,
drm_r128_clear_t * clear)
{
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
unsigned int flags = clear->flags;
int i;
RING_LOCALS;
@@ -458,12 +458,12 @@ static void r128_cce_dispatch_clear(drm_device_t * dev,
}
}
-static void r128_cce_dispatch_swap(drm_device_t * dev)
+static void r128_cce_dispatch_swap(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int i;
RING_LOCALS;
DRM_DEBUG("%s\n", __FUNCTION__);
@@ -524,7 +524,7 @@ static void r128_cce_dispatch_swap(drm_device_t * dev)
ADVANCE_RING();
}
-static void r128_cce_dispatch_flip(drm_device_t * dev)
+static void r128_cce_dispatch_flip(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -567,7 +567,7 @@ static void r128_cce_dispatch_flip(drm_device_t * dev)
ADVANCE_RING();
}
-static void r128_cce_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf)
+static void r128_cce_dispatch_vertex(struct drm_device * dev, struct drm_buf * buf)
{
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_buf_priv_t *buf_priv = buf->dev_private;
@@ -637,8 +637,8 @@ static void r128_cce_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf)
sarea_priv->nbox = 0;
}
-static void r128_cce_dispatch_indirect(drm_device_t * dev,
- drm_buf_t * buf, int start, int end)
+static void r128_cce_dispatch_indirect(struct drm_device * dev,
+ struct drm_buf * buf, int start, int end)
{
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_buf_priv_t *buf_priv = buf->dev_private;
@@ -692,8 +692,8 @@ static void r128_cce_dispatch_indirect(drm_device_t * dev,
dev_priv->sarea_priv->last_dispatch++;
}
-static void r128_cce_dispatch_indices(drm_device_t * dev,
- drm_buf_t * buf,
+static void r128_cce_dispatch_indices(struct drm_device * dev,
+ struct drm_buf * buf,
int start, int end, int count)
{
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -777,11 +777,11 @@ static void r128_cce_dispatch_indices(drm_device_t * dev,
}
static int r128_cce_dispatch_blit(DRMFILE filp,
- drm_device_t * dev, drm_r128_blit_t * blit)
+ struct drm_device * dev, drm_r128_blit_t * blit)
{
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
u32 *data;
int dword_shift, dwords;
@@ -887,7 +887,7 @@ static int r128_cce_dispatch_blit(DRMFILE filp,
* have hardware stencil support.
*/
-static int r128_cce_dispatch_write_span(drm_device_t * dev,
+static int r128_cce_dispatch_write_span(struct drm_device * dev,
drm_r128_depth_t * depth)
{
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -983,7 +983,7 @@ static int r128_cce_dispatch_write_span(drm_device_t * dev,
return 0;
}
-static int r128_cce_dispatch_write_pixels(drm_device_t * dev,
+static int r128_cce_dispatch_write_pixels(struct drm_device * dev,
drm_r128_depth_t * depth)
{
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1105,7 +1105,7 @@ static int r128_cce_dispatch_write_pixels(drm_device_t * dev,
return 0;
}
-static int r128_cce_dispatch_read_span(drm_device_t * dev,
+static int r128_cce_dispatch_read_span(struct drm_device * dev,
drm_r128_depth_t * depth)
{
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1148,7 +1148,7 @@ static int r128_cce_dispatch_read_span(drm_device_t * dev,
return 0;
}
-static int r128_cce_dispatch_read_pixels(drm_device_t * dev,
+static int r128_cce_dispatch_read_pixels(struct drm_device * dev,
drm_r128_depth_t * depth)
{
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1220,7 +1220,7 @@ static int r128_cce_dispatch_read_pixels(drm_device_t * dev,
* Polygon stipple
*/
-static void r128_cce_dispatch_stipple(drm_device_t * dev, u32 * stipple)
+static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple)
{
drm_r128_private_t *dev_priv = dev->dev_private;
int i;
@@ -1269,7 +1269,7 @@ static int r128_cce_clear(DRM_IOCTL_ARGS)
return 0;
}
-static int r128_do_init_pageflip(drm_device_t * dev)
+static int r128_do_init_pageflip(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
@@ -1288,7 +1288,7 @@ static int r128_do_init_pageflip(drm_device_t * dev)
return 0;
}
-static int r128_do_cleanup_pageflip(drm_device_t * dev)
+static int r128_do_cleanup_pageflip(struct drm_device * dev)
{
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
@@ -1354,8 +1354,8 @@ static int r128_cce_vertex(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
drm_r128_vertex_t vertex;
@@ -1413,8 +1413,8 @@ static int r128_cce_indices(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
drm_r128_indices_t elts;
int count;
@@ -1483,7 +1483,7 @@ static int r128_cce_indices(DRM_IOCTL_ARGS)
static int r128_cce_blit(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_r128_private_t *dev_priv = dev->dev_private;
drm_r128_blit_t blit;
int ret;
@@ -1571,8 +1571,8 @@ static int r128_cce_indirect(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_r128_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_r128_buf_priv_t *buf_priv;
drm_r128_indirect_t indirect;
#if 0
@@ -1675,7 +1675,7 @@ static int r128_getparam(DRM_IOCTL_ARGS)
return 0;
}
-void r128_driver_preclose(drm_device_t * dev, DRMFILE filp)
+void r128_driver_preclose(struct drm_device * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_r128_private_t *dev_priv = dev->dev_private;
@@ -1685,7 +1685,7 @@ void r128_driver_preclose(drm_device_t * dev, DRMFILE filp)
}
}
-void r128_driver_lastclose(drm_device_t * dev)
+void r128_driver_lastclose(struct drm_device * dev)
{
r128_do_cleanup_cce(dev);
}
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index 032a022ec6a8..4e5aca6ba59a 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -55,7 +55,7 @@ static const int r300_cliprect_cntl[4] = {
static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
drm_radeon_kcmd_buffer_t *cmdbuf, int n)
{
- drm_clip_rect_t box;
+ struct drm_clip_rect box;
int nr;
int i;
RING_LOCALS;
@@ -148,15 +148,16 @@ void r300_init_reg_flags(void)
/* these match cmducs() command in r300_driver/r300/r300_cmdbuf.c */
ADD_RANGE(R300_SE_VPORT_XSCALE, 6);
- ADD_RANGE(0x2080, 1);
+ ADD_RANGE(R300_VAP_CNTL, 1);
ADD_RANGE(R300_SE_VTE_CNTL, 2);
ADD_RANGE(0x2134, 2);
- ADD_RANGE(0x2140, 1);
+ ADD_RANGE(R300_VAP_CNTL_STATUS, 1);
ADD_RANGE(R300_VAP_INPUT_CNTL_0, 2);
ADD_RANGE(0x21DC, 1);
- ADD_RANGE(0x221C, 1);
- ADD_RANGE(0x2220, 4);
- ADD_RANGE(0x2288, 1);
+ ADD_RANGE(R300_VAP_UNKNOWN_221C, 1);
+ ADD_RANGE(R300_VAP_CLIP_X_0, 4);
+ ADD_RANGE(R300_VAP_PVS_WAITIDLE, 1);
+ ADD_RANGE(R300_VAP_UNKNOWN_2288, 1);
ADD_RANGE(R300_VAP_OUTPUT_VTX_FMT_0, 2);
ADD_RANGE(R300_VAP_PVS_CNTL_1, 3);
ADD_RANGE(R300_GB_ENABLE, 1);
@@ -168,13 +169,13 @@ void r300_init_reg_flags(void)
ADD_RANGE(R300_RE_POINTSIZE, 1);
ADD_RANGE(0x4230, 3);
ADD_RANGE(R300_RE_LINE_CNT, 1);
- ADD_RANGE(0x4238, 1);
+ ADD_RANGE(R300_RE_UNK4238, 1);
ADD_RANGE(0x4260, 3);
- ADD_RANGE(0x4274, 4);
- ADD_RANGE(0x4288, 5);
- ADD_RANGE(0x42A0, 1);
+ ADD_RANGE(R300_RE_SHADE, 4);
+ ADD_RANGE(R300_RE_POLYGON_MODE, 5);
+ ADD_RANGE(R300_RE_ZBIAS_CNTL, 1);
ADD_RANGE(R300_RE_ZBIAS_T_FACTOR, 4);
- ADD_RANGE(0x42B4, 1);
+ ADD_RANGE(R300_RE_OCCLUSION_CNTL, 1);
ADD_RANGE(R300_RE_CULL_CNTL, 1);
ADD_RANGE(0x42C0, 2);
ADD_RANGE(R300_RS_CNTL_0, 2);
@@ -190,22 +191,22 @@ void r300_init_reg_flags(void)
ADD_RANGE(R300_PFS_INSTR1_0, 64);
ADD_RANGE(R300_PFS_INSTR2_0, 64);
ADD_RANGE(R300_PFS_INSTR3_0, 64);
- ADD_RANGE(0x4BC0, 1);
- ADD_RANGE(0x4BC8, 3);
+ ADD_RANGE(R300_RE_FOG_STATE, 1);
+ ADD_RANGE(R300_FOG_COLOR_R, 3);
ADD_RANGE(R300_PP_ALPHA_TEST, 2);
ADD_RANGE(0x4BD8, 1);
ADD_RANGE(R300_PFS_PARAM_0_X, 64);
ADD_RANGE(0x4E00, 1);
ADD_RANGE(R300_RB3D_CBLEND, 2);
ADD_RANGE(R300_RB3D_COLORMASK, 1);
- ADD_RANGE(0x4E10, 3);
+ ADD_RANGE(R300_RB3D_BLEND_COLOR, 3);
ADD_RANGE_MARK(R300_RB3D_COLOROFFSET0, 1, MARK_CHECK_OFFSET); /* check offset */
ADD_RANGE(R300_RB3D_COLORPITCH0, 1);
ADD_RANGE(0x4E50, 9);
ADD_RANGE(0x4E88, 1);
ADD_RANGE(0x4EA0, 2);
ADD_RANGE(R300_RB3D_ZSTENCIL_CNTL_0, 3);
- ADD_RANGE(0x4F10, 4);
+ ADD_RANGE(R300_RB3D_ZSTENCIL_FORMAT, 4);
ADD_RANGE_MARK(R300_RB3D_DEPTHOFFSET, 1, MARK_CHECK_OFFSET); /* check offset */
ADD_RANGE(R300_RB3D_DEPTHPITCH, 1);
ADD_RANGE(0x4F28, 1);
@@ -224,7 +225,7 @@ void r300_init_reg_flags(void)
ADD_RANGE(R300_TX_BORDER_COLOR_0, 16);
/* Sporadic registers used as primitives are emitted */
- ADD_RANGE(0x4f18, 1);
+ ADD_RANGE(R300_RB3D_ZCACHE_CTLSTAT, 1);
ADD_RANGE(R300_RB3D_DSTCACHE_CTLSTAT, 1);
ADD_RANGE(R300_VAP_INPUT_ROUTE_0_0, 8);
ADD_RANGE(R300_VAP_INPUT_ROUTE_1_0, 8);
@@ -692,9 +693,9 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
BEGIN_RING(6);
OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
- OUT_RING(0xa);
- OUT_RING(CP_PACKET0(0x4f18, 0));
- OUT_RING(0x3);
+ OUT_RING(R300_RB3D_DSTCACHE_UNKNOWN_0A);
+ OUT_RING(CP_PACKET0(R300_RB3D_ZCACHE_CTLSTAT, 0));
+ OUT_RING(R300_RB3D_ZCACHE_UNKNOWN_03);
OUT_RING(CP_PACKET3(RADEON_CP_NOP, 0));
OUT_RING(0x0);
ADVANCE_RING();
@@ -705,7 +706,7 @@ static __inline__ void r300_pacify(drm_radeon_private_t *dev_priv)
* The actual age emit is done by r300_do_cp_cmdbuf, which is why you must
* be careful about how this function is called.
*/
-static void r300_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
+static void r300_discard_buffer(struct drm_device * dev, struct drm_buf * buf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
@@ -766,8 +767,8 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
}
BEGIN_RING(2);
- OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0));
- OUT_RING(dev_priv->scratch_ages[header.scratch.reg]);
+ OUT_RING( CP_PACKET0( RADEON_SCRATCH_REG0 + header.scratch.reg * 4, 0 ) );
+ OUT_RING( dev_priv->scratch_ages[header.scratch.reg] );
ADVANCE_RING();
return 0;
@@ -778,14 +779,14 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
* commands on the DMA ring buffer.
* Called by the ioctl handler function radeon_cp_cmdbuf.
*/
-int r300_do_cp_cmdbuf(drm_device_t *dev,
+int r300_do_cp_cmdbuf(struct drm_device *dev,
DRMFILE filp,
- drm_file_t *filp_priv,
+ struct drm_file *filp_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf = NULL;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf = NULL;
int emit_dispatch_age = 0;
int ret = 0;
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index ecda760ae8c0..3ae57ecc7afd 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -47,12 +47,12 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
# define R300_MC_MISC__MC_GLOBW_FULL_LAT_SHIFT 28
/*
-This file contains registers and constants for the R300. They have been
-found mostly by examining command buffers captured using glxtest, as well
-as by extrapolating some known registers and constants from the R200.
-
-I am fairly certain that they are correct unless stated otherwise in comments.
-*/
+ * This file contains registers and constants for the R300. They have been
+ * found mostly by examining command buffers captured using glxtest, as well
+ * as by extrapolating some known registers and constants from the R200.
+ * I am fairly certain that they are correct unless stated otherwise
+ * in comments.
+ */
#define R300_SE_VPORT_XSCALE 0x1D98
#define R300_SE_VPORT_XOFFSET 0x1D9C
@@ -61,49 +61,60 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_SE_VPORT_ZSCALE 0x1DA8
#define R300_SE_VPORT_ZOFFSET 0x1DAC
-/* This register is written directly and also starts data section in many 3d CP_PACKET3's */
-#define R300_VAP_VF_CNTL 0x2084
-# define R300_VAP_VF_CNTL__PRIM_TYPE__SHIFT 0
-# define R300_VAP_VF_CNTL__PRIM_NONE (0<<0)
-# define R300_VAP_VF_CNTL__PRIM_POINTS (1<<0)
-# define R300_VAP_VF_CNTL__PRIM_LINES (2<<0)
-# define R300_VAP_VF_CNTL__PRIM_LINE_STRIP (3<<0)
-# define R300_VAP_VF_CNTL__PRIM_TRIANGLES (4<<0)
-# define R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN (5<<0)
-# define R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP (6<<0)
-# define R300_VAP_VF_CNTL__PRIM_LINE_LOOP (12<<0)
-# define R300_VAP_VF_CNTL__PRIM_QUADS (13<<0)
-# define R300_VAP_VF_CNTL__PRIM_QUAD_STRIP (14<<0)
-# define R300_VAP_VF_CNTL__PRIM_POLYGON (15<<0)
-
-# define R300_VAP_VF_CNTL__PRIM_WALK__SHIFT 4
- /* State based - direct writes to registers trigger vertex generation */
-# define R300_VAP_VF_CNTL__PRIM_WALK_STATE_BASED (0<<4)
-# define R300_VAP_VF_CNTL__PRIM_WALK_INDICES (1<<4)
-# define R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST (2<<4)
-# define R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED (3<<4)
-
- /* I don't think I saw these three used.. */
-# define R300_VAP_VF_CNTL__COLOR_ORDER__SHIFT 6
-# define R300_VAP_VF_CNTL__TCL_OUTPUT_CTL_ENA__SHIFT 9
-# define R300_VAP_VF_CNTL__PROG_STREAM_ENA__SHIFT 10
-
- /* index size - when not set the indices are assumed to be 16 bit */
-# define R300_VAP_VF_CNTL__INDEX_SIZE_32bit (1<<11)
- /* number of vertices */
-# define R300_VAP_VF_CNTL__NUM_VERTICES__SHIFT 16
+/*
+ * Vertex Array Processing (VAP) Control
+ * Stolen from r200 code from Christoph Brill (It's a guess!)
+ */
+#define R300_VAP_CNTL 0x2080
+
+/* This register is written directly and also starts data section
+ * in many 3d CP_PACKET3's
+ */
+#define R300_VAP_VF_CNTL 0x2084
+# define R300_VAP_VF_CNTL__PRIM_TYPE__SHIFT 0
+# define R300_VAP_VF_CNTL__PRIM_NONE (0<<0)
+# define R300_VAP_VF_CNTL__PRIM_POINTS (1<<0)
+# define R300_VAP_VF_CNTL__PRIM_LINES (2<<0)
+# define R300_VAP_VF_CNTL__PRIM_LINE_STRIP (3<<0)
+# define R300_VAP_VF_CNTL__PRIM_TRIANGLES (4<<0)
+# define R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN (5<<0)
+# define R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP (6<<0)
+# define R300_VAP_VF_CNTL__PRIM_LINE_LOOP (12<<0)
+# define R300_VAP_VF_CNTL__PRIM_QUADS (13<<0)
+# define R300_VAP_VF_CNTL__PRIM_QUAD_STRIP (14<<0)
+# define R300_VAP_VF_CNTL__PRIM_POLYGON (15<<0)
+
+# define R300_VAP_VF_CNTL__PRIM_WALK__SHIFT 4
+ /* State based - direct writes to registers trigger vertex
+ generation */
+# define R300_VAP_VF_CNTL__PRIM_WALK_STATE_BASED (0<<4)
+# define R300_VAP_VF_CNTL__PRIM_WALK_INDICES (1<<4)
+# define R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST (2<<4)
+# define R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_EMBEDDED (3<<4)
+
+ /* I don't think I saw these three used.. */
+# define R300_VAP_VF_CNTL__COLOR_ORDER__SHIFT 6
+# define R300_VAP_VF_CNTL__TCL_OUTPUT_CTL_ENA__SHIFT 9
+# define R300_VAP_VF_CNTL__PROG_STREAM_ENA__SHIFT 10
+
+ /* index size - when not set the indices are assumed to be 16 bit */
+# define R300_VAP_VF_CNTL__INDEX_SIZE_32bit (1<<11)
+ /* number of vertices */
+# define R300_VAP_VF_CNTL__NUM_VERTICES__SHIFT 16
/* BEGIN: Wild guesses */
#define R300_VAP_OUTPUT_VTX_FMT_0 0x2090
# define R300_VAP_OUTPUT_VTX_FMT_0__POS_PRESENT (1<<0)
# define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_PRESENT (1<<1)
-# define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_1_PRESENT (1<<2) /* GUESS */
-# define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_2_PRESENT (1<<3) /* GUESS */
-# define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_3_PRESENT (1<<4) /* GUESS */
-# define R300_VAP_OUTPUT_VTX_FMT_0__PT_SIZE_PRESENT (1<<16) /* GUESS */
+# define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_1_PRESENT (1<<2) /* GUESS */
+# define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_2_PRESENT (1<<3) /* GUESS */
+# define R300_VAP_OUTPUT_VTX_FMT_0__COLOR_3_PRESENT (1<<4) /* GUESS */
+# define R300_VAP_OUTPUT_VTX_FMT_0__PT_SIZE_PRESENT (1<<16) /* GUESS */
#define R300_VAP_OUTPUT_VTX_FMT_1 0x2094
+ /* each of the following is 3 bits wide, specifies number
+ of components */
# define R300_VAP_OUTPUT_VTX_FMT_1__TEX_0_COMP_CNT_SHIFT 0
# define R300_VAP_OUTPUT_VTX_FMT_1__TEX_1_COMP_CNT_SHIFT 3
# define R300_VAP_OUTPUT_VTX_FMT_1__TEX_2_COMP_CNT_SHIFT 6
@@ -112,7 +123,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_VAP_OUTPUT_VTX_FMT_1__TEX_5_COMP_CNT_SHIFT 15
# define R300_VAP_OUTPUT_VTX_FMT_1__TEX_6_COMP_CNT_SHIFT 18
# define R300_VAP_OUTPUT_VTX_FMT_1__TEX_7_COMP_CNT_SHIFT 21
-/* END */
+/* END: Wild guesses */
#define R300_SE_VTE_CNTL 0x20b0
# define R300_VPORT_X_SCALE_ENA 0x00000001
@@ -128,43 +139,54 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_VTX_ST_DENORMALIZED 0x00001000
/* BEGIN: Vertex data assembly - lots of uncertainties */
+
+/* gap */
+
+#define R300_VAP_CNTL_STATUS 0x2140
+# define R300_VC_NO_SWAP (0 << 0)
+# define R300_VC_16BIT_SWAP (1 << 0)
+# define R300_VC_32BIT_SWAP (2 << 0)
+# define R300_VAP_TCL_BYPASS (1 << 8)
+
/* gap */
+
/* Where do we get our vertex data?
-//
-// Vertex data either comes either from immediate mode registers or from
-// vertex arrays.
-// There appears to be no mixed mode (though we can force the pitch of
-// vertex arrays to 0, effectively reusing the same element over and over
-// again).
-//
-// Immediate mode is controlled by the INPUT_CNTL registers. I am not sure
-// if these registers influence vertex array processing.
-//
-// Vertex arrays are controlled via the 3D_LOAD_VBPNTR packet3.
-//
-// In both cases, vertex attributes are then passed through INPUT_ROUTE.
-
-// Beginning with INPUT_ROUTE_0_0 is a list of WORDs that route vertex data
-// into the vertex processor's input registers.
-// The first word routes the first input, the second word the second, etc.
-// The corresponding input is routed into the register with the given index.
-// The list is ended by a word with INPUT_ROUTE_END set.
-//
-// Always set COMPONENTS_4 in immediate mode. */
+ *
+ * Vertex data either comes either from immediate mode registers or from
+ * vertex arrays.
+ * There appears to be no mixed mode (though we can force the pitch of
+ * vertex arrays to 0, effectively reusing the same element over and over
+ * again).
+ *
+ * Immediate mode is controlled by the INPUT_CNTL registers. I am not sure
+ * if these registers influence vertex array processing.
+ *
+ * Vertex arrays are controlled via the 3D_LOAD_VBPNTR packet3.
+ *
+ * In both cases, vertex attributes are then passed through INPUT_ROUTE.
+ *
+ * Beginning with INPUT_ROUTE_0_0 is a list of WORDs that route vertex data
+ * into the vertex processor's input registers.
+ * The first word routes the first input, the second word the second, etc.
+ * The corresponding input is routed into the register with the given index.
+ * The list is ended by a word with INPUT_ROUTE_END set.
+ *
+ * Always set COMPONENTS_4 in immediate mode.
+ */
#define R300_VAP_INPUT_ROUTE_0_0 0x2150
# define R300_INPUT_ROUTE_COMPONENTS_1 (0 << 0)
# define R300_INPUT_ROUTE_COMPONENTS_2 (1 << 0)
# define R300_INPUT_ROUTE_COMPONENTS_3 (2 << 0)
# define R300_INPUT_ROUTE_COMPONENTS_4 (3 << 0)
-# define R300_INPUT_ROUTE_COMPONENTS_RGBA (4 << 0) /* GUESS */
+# define R300_INPUT_ROUTE_COMPONENTS_RGBA (4 << 0) /* GUESS */
# define R300_VAP_INPUT_ROUTE_IDX_SHIFT 8
-# define R300_VAP_INPUT_ROUTE_IDX_MASK (31 << 8) /* GUESS */
+# define R300_VAP_INPUT_ROUTE_IDX_MASK (31 << 8) /* GUESS */
# define R300_VAP_INPUT_ROUTE_END (1 << 13)
-# define R300_INPUT_ROUTE_IMMEDIATE_MODE (0 << 14) /* GUESS */
-# define R300_INPUT_ROUTE_FLOAT (1 << 14) /* GUESS */
-# define R300_INPUT_ROUTE_UNSIGNED_BYTE (2 << 14) /* GUESS */
-# define R300_INPUT_ROUTE_FLOAT_COLOR (3 << 14) /* GUESS */
+# define R300_INPUT_ROUTE_IMMEDIATE_MODE (0 << 14) /* GUESS */
+# define R300_INPUT_ROUTE_FLOAT (1 << 14) /* GUESS */
+# define R300_INPUT_ROUTE_UNSIGNED_BYTE (2 << 14) /* GUESS */
+# define R300_INPUT_ROUTE_FLOAT_COLOR (3 << 14) /* GUESS */
#define R300_VAP_INPUT_ROUTE_0_1 0x2154
#define R300_VAP_INPUT_ROUTE_0_2 0x2158
#define R300_VAP_INPUT_ROUTE_0_3 0x215C
@@ -174,10 +196,12 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_VAP_INPUT_ROUTE_0_7 0x216C
/* gap */
+
/* Notes:
-// - always set up to produce at least two attributes:
-// if vertex program uses only position, fglrx will set normal, too
-// - INPUT_CNTL_0_COLOR and INPUT_CNTL_COLOR bits are always equal */
+ * - always set up to produce at least two attributes:
+ * if vertex program uses only position, fglrx will set normal, too
+ * - INPUT_CNTL_0_COLOR and INPUT_CNTL_COLOR bits are always equal.
+ */
#define R300_VAP_INPUT_CNTL_0 0x2180
# define R300_INPUT_CNTL_0_COLOR 0x00000001
#define R300_VAP_INPUT_CNTL_1 0x2184
@@ -186,20 +210,22 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_INPUT_CNTL_COLOR 0x00000004
# define R300_INPUT_CNTL_TC0 0x00000400
# define R300_INPUT_CNTL_TC1 0x00000800
-# define R300_INPUT_CNTL_TC2 0x00001000 /* GUESS */
-# define R300_INPUT_CNTL_TC3 0x00002000 /* GUESS */
-# define R300_INPUT_CNTL_TC4 0x00004000 /* GUESS */
-# define R300_INPUT_CNTL_TC5 0x00008000 /* GUESS */
-# define R300_INPUT_CNTL_TC6 0x00010000 /* GUESS */
-# define R300_INPUT_CNTL_TC7 0x00020000 /* GUESS */
+# define R300_INPUT_CNTL_TC2 0x00001000 /* GUESS */
+# define R300_INPUT_CNTL_TC3 0x00002000 /* GUESS */
+# define R300_INPUT_CNTL_TC4 0x00004000 /* GUESS */
+# define R300_INPUT_CNTL_TC5 0x00008000 /* GUESS */
+# define R300_INPUT_CNTL_TC6 0x00010000 /* GUESS */
+# define R300_INPUT_CNTL_TC7 0x00020000 /* GUESS */
/* gap */
+
/* Words parallel to INPUT_ROUTE_0; All words that are active in INPUT_ROUTE_0
-// are set to a swizzling bit pattern, other words are 0.
-//
-// In immediate mode, the pattern is always set to xyzw. In vertex array
-// mode, the swizzling pattern is e.g. used to set zw components in texture
-// coordinates with only tweo components. */
+ * are set to a swizzling bit pattern, other words are 0.
+ *
+ * In immediate mode, the pattern is always set to xyzw. In vertex array
+ * mode, the swizzling pattern is e.g. used to set zw components in texture
+ * coordinates with only tweo components.
+ */
#define R300_VAP_INPUT_ROUTE_1_0 0x21E0
# define R300_INPUT_ROUTE_SELECT_X 0
# define R300_INPUT_ROUTE_SELECT_Y 1
@@ -208,11 +234,11 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_INPUT_ROUTE_SELECT_ZERO 4
# define R300_INPUT_ROUTE_SELECT_ONE 5
# define R300_INPUT_ROUTE_SELECT_MASK 7
-# define R300_INPUT_ROUTE_X_SHIFT 0
-# define R300_INPUT_ROUTE_Y_SHIFT 3
-# define R300_INPUT_ROUTE_Z_SHIFT 6
-# define R300_INPUT_ROUTE_W_SHIFT 9
-# define R300_INPUT_ROUTE_ENABLE (15 << 12)
+# define R300_INPUT_ROUTE_X_SHIFT 0
+# define R300_INPUT_ROUTE_Y_SHIFT 3
+# define R300_INPUT_ROUTE_Z_SHIFT 6
+# define R300_INPUT_ROUTE_W_SHIFT 9
+# define R300_INPUT_ROUTE_ENABLE (15 << 12)
#define R300_VAP_INPUT_ROUTE_1_1 0x21E4
#define R300_VAP_INPUT_ROUTE_1_2 0x21E8
#define R300_VAP_INPUT_ROUTE_1_3 0x21EC
@@ -221,79 +247,107 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_VAP_INPUT_ROUTE_1_6 0x21F8
#define R300_VAP_INPUT_ROUTE_1_7 0x21FC
-/* END */
+/* END: Vertex data assembly */
/* gap */
-/* BEGIN: Upload vertex program and data
-// The programmable vertex shader unit has a memory bank of unknown size
-// that can be written to in 16 byte units by writing the address into
-// UPLOAD_ADDRESS, followed by data in UPLOAD_DATA (multiples of 4 DWORDs).
-//
-// Pointers into the memory bank are always in multiples of 16 bytes.
-//
-// The memory bank is divided into areas with fixed meaning.
-//
-// Starting at address UPLOAD_PROGRAM: Vertex program instructions.
-// Native limits reported by drivers from ATI suggest size 256 (i.e. 4KB),
-// whereas the difference between known addresses suggests size 512.
-//
-// Starting at address UPLOAD_PARAMETERS: Vertex program parameters.
-// Native reported limits and the VPI layout suggest size 256, whereas
-// difference between known addresses suggests size 512.
-//
-// At address UPLOAD_POINTSIZE is a vector (0, 0, ps, 0), where ps is the
-// floating point pointsize. The exact purpose of this state is uncertain,
-// as there is also the R300_RE_POINTSIZE register.
-//
-// Multiple vertex programs and parameter sets can be loaded at once,
-// which could explain the size discrepancy. */
+
+/* BEGIN: Upload vertex program and data */
+
+/*
+ * The programmable vertex shader unit has a memory bank of unknown size
+ * that can be written to in 16 byte units by writing the address into
+ * UPLOAD_ADDRESS, followed by data in UPLOAD_DATA (multiples of 4 DWORDs).
+ *
+ * Pointers into the memory bank are always in multiples of 16 bytes.
+ *
+ * The memory bank is divided into areas with fixed meaning.
+ *
+ * Starting at address UPLOAD_PROGRAM: Vertex program instructions.
+ * Native limits reported by drivers from ATI suggest size 256 (i.e. 4KB),
+ * whereas the difference between known addresses suggests size 512.
+ *
+ * Starting at address UPLOAD_PARAMETERS: Vertex program parameters.
+ * Native reported limits and the VPI layout suggest size 256, whereas
+ * difference between known addresses suggests size 512.
+ *
+ * At address UPLOAD_POINTSIZE is a vector (0, 0, ps, 0), where ps is the
+ * floating point pointsize. The exact purpose of this state is uncertain,
+ * as there is also the R300_RE_POINTSIZE register.
+ *
+ * Multiple vertex programs and parameter sets can be loaded at once,
+ * which could explain the size discrepancy.
+ */
#define R300_VAP_PVS_UPLOAD_ADDRESS 0x2200
# define R300_PVS_UPLOAD_PROGRAM 0x00000000
# define R300_PVS_UPLOAD_PARAMETERS 0x00000200
# define R300_PVS_UPLOAD_POINTSIZE 0x00000406
+
/* gap */
+
#define R300_VAP_PVS_UPLOAD_DATA 0x2208
-/* END */
+
+/* END: Upload vertex program and data */
/* gap */
+
/* I do not know the purpose of this register. However, I do know that
-// it is set to 221C_CLEAR for clear operations and to 221C_NORMAL
-// for normal rendering. */
+ * it is set to 221C_CLEAR for clear operations and to 221C_NORMAL
+ * for normal rendering.
+ */
#define R300_VAP_UNKNOWN_221C 0x221C
# define R300_221C_NORMAL 0x00000000
# define R300_221C_CLEAR 0x0001C000
+/* These seem to be per-pixel and per-vertex X and Y clipping planes. The first
+ * plane is per-pixel and the second plane is per-vertex.
+ *
+ * This was determined by experimentation alone but I believe it is correct.
+ *
+ * These registers are called X_QUAD0_1_FL to X_QUAD0_4_FL by glxtest.
+ */
+#define R300_VAP_CLIP_X_0 0x2220
+#define R300_VAP_CLIP_X_1 0x2224
+#define R300_VAP_CLIP_Y_0 0x2228
+#define R300_VAP_CLIP_Y_1 0x2230
+
/* gap */
+
/* Sometimes, END_OF_PKT and 0x2284=0 are the only commands sent between
-// rendering commands and overwriting vertex program parameters.
-// Therefore, I suspect writing zero to 0x2284 synchronizes the engine and
-// avoids bugs caused by still running shaders reading bad data from memory. */
-#define R300_VAP_PVS_WAITIDLE 0x2284 /* GUESS */
+ * rendering commands and overwriting vertex program parameters.
+ * Therefore, I suspect writing zero to 0x2284 synchronizes the engine and
+ * avoids bugs caused by still running shaders reading bad data from memory.
+ */
+#define R300_VAP_PVS_WAITIDLE 0x2284 /* GUESS */
/* Absolutely no clue what this register is about. */
#define R300_VAP_UNKNOWN_2288 0x2288
-# define R300_2288_R300 0x00750000 /* -- nh */
-# define R300_2288_RV350 0x0000FFFF /* -- Vladimir */
+# define R300_2288_R300 0x00750000 /* -- nh */
+# define R300_2288_RV350 0x0000FFFF /* -- Vladimir */
/* gap */
+
/* Addresses are relative to the vertex program instruction area of the
-// memory bank. PROGRAM_END points to the last instruction of the active
-// program
-//
-// The meaning of the two UNKNOWN fields is obviously not known. However,
-// experiments so far have shown that both *must* point to an instruction
-// inside the vertex program, otherwise the GPU locks up.
-// fglrx usually sets CNTL_3_UNKNOWN to the end of the program and
-// CNTL_1_UNKNOWN points to instruction where last write to position takes place.
-// Most likely this is used to ignore rest of the program in cases where group of verts arent visible.
-// For some reason this "section" is sometimes accepted other instruction that have
-// no relationship with position calculations.
-*/
+ * memory bank. PROGRAM_END points to the last instruction of the active
+ * program
+ *
+ * The meaning of the two UNKNOWN fields is obviously not known. However,
+ * experiments so far have shown that both *must* point to an instruction
+ * inside the vertex program, otherwise the GPU locks up.
+ *
+ * fglrx usually sets CNTL_3_UNKNOWN to the end of the program and
+ * R300_PVS_CNTL_1_POS_END_SHIFT points to instruction where last write to
+ * position takes place.
+ *
+ * Most likely this is used to ignore rest of the program in cases
+ * where group of verts arent visible. For some reason this "section"
+ * is sometimes accepted other instruction that have no relationship with
+ * position calculations.
+ */
#define R300_VAP_PVS_CNTL_1 0x22D0
# define R300_PVS_CNTL_1_PROGRAM_START_SHIFT 0
# define R300_PVS_CNTL_1_POS_END_SHIFT 10
# define R300_PVS_CNTL_1_PROGRAM_END_SHIFT 20
-/* Addresses are relative to the vertex program parameters area. */
+/* Addresses are relative the the vertex program parameters area. */
#define R300_VAP_PVS_CNTL_2 0x22D4
# define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
# define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT 16
@@ -302,23 +356,26 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_PVS_CNTL_3_PROGRAM_UNKNOWN2_SHIFT 0
/* The entire range from 0x2300 to 0x2AC inclusive seems to be used for
-// immediate vertices */
+ * immediate vertices
+ */
#define R300_VAP_VTX_COLOR_R 0x2464
#define R300_VAP_VTX_COLOR_G 0x2468
#define R300_VAP_VTX_COLOR_B 0x246C
-#define R300_VAP_VTX_POS_0_X_1 0x2490 /* used for glVertex2*() */
+#define R300_VAP_VTX_POS_0_X_1 0x2490 /* used for glVertex2*() */
#define R300_VAP_VTX_POS_0_Y_1 0x2494
-#define R300_VAP_VTX_COLOR_PKD 0x249C /* RGBA */
-#define R300_VAP_VTX_POS_0_X_2 0x24A0 /* used for glVertex3*() */
+#define R300_VAP_VTX_COLOR_PKD 0x249C /* RGBA */
+#define R300_VAP_VTX_POS_0_X_2 0x24A0 /* used for glVertex3*() */
#define R300_VAP_VTX_POS_0_Y_2 0x24A4
#define R300_VAP_VTX_POS_0_Z_2 0x24A8
-#define R300_VAP_VTX_END_OF_PKT 0x24AC /* write 0 to indicate end of packet? */
+/* write 0 to indicate end of packet? */
+#define R300_VAP_VTX_END_OF_PKT 0x24AC
/* gap */
/* These are values from r300_reg/r300_reg.h - they are known to be correct
- and are here so we can use one register file instead of several
- - Vladimir */
+ * and are here so we can use one register file instead of several
+ * - Vladimir
+ */
#define R300_GB_VAP_RASTER_VTX_FMT_0 0x4000
# define R300_GB_VAP_RASTER_VTX_FMT_0__POS_PRESENT (1<<0)
# define R300_GB_VAP_RASTER_VTX_FMT_0__COLOR_0_PRESENT (1<<1)
@@ -341,14 +398,16 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_GB_VAP_RASTER_VTX_FMT_1__TEX_7_COMP_CNT_SHIFT 21
/* UNK30 seems to enables point to quad transformation on textures
- (or something closely related to that).
- This bit is rather fatal at the time being due to lackings at pixel shader side */
+ * (or something closely related to that).
+ * This bit is rather fatal at the time being due to lackings at pixel
+ * shader side
+ */
#define R300_GB_ENABLE 0x4008
# define R300_GB_POINT_STUFF_ENABLE (1<<0)
# define R300_GB_LINE_STUFF_ENABLE (1<<1)
# define R300_GB_TRIANGLE_STUFF_ENABLE (1<<2)
# define R300_GB_STENCIL_AUTO_ENABLE (1<<4)
-# define R300_GB_UNK30 (1<<30)
+# define R300_GB_UNK31 (1<<31)
/* each of the following is 2 bits wide */
#define R300_GB_TEX_REPLICATE 0
#define R300_GB_TEX_ST 1
@@ -383,11 +442,13 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_GB_MSPOS1__MS_Y5_SHIFT 20
# define R300_GB_MSPOS1__MSBD1 24
+
#define R300_GB_TILE_CONFIG 0x4018
# define R300_GB_TILE_ENABLE (1<<0)
# define R300_GB_TILE_PIPE_COUNT_RV300 0
# define R300_GB_TILE_PIPE_COUNT_R300 (3<<1)
# define R300_GB_TILE_PIPE_COUNT_R420 (7<<1)
+# define R300_GB_TILE_PIPE_COUNT_RV410 (3<<1)
# define R300_GB_TILE_SIZE_8 0
# define R300_GB_TILE_SIZE_16 (1<<4)
# define R300_GB_TILE_SIZE_32 (2<<4)
@@ -442,17 +503,18 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_GB_W_SELECT_1 (1<<4)
#define R300_GB_AA_CONFIG 0x4020
+# define R300_AA_DISABLE 0x00
# define R300_AA_ENABLE 0x01
# define R300_AA_SUBSAMPLES_2 0
# define R300_AA_SUBSAMPLES_3 (1<<1)
# define R300_AA_SUBSAMPLES_4 (2<<1)
# define R300_AA_SUBSAMPLES_6 (3<<1)
-/* END */
-
/* gap */
+
/* Zero to flush caches. */
#define R300_TX_CNTL 0x4100
+#define R300_TX_FLUSH 0x0
/* The upper enable bits are guessed, based on fglrx reported limits. */
#define R300_TX_ENABLE 0x4104
@@ -474,24 +536,25 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_TX_ENABLE_15 (1 << 15)
/* The pointsize is given in multiples of 6. The pointsize can be
-// enormous: Clear() renders a single point that fills the entire
-// framebuffer. */
+ * enormous: Clear() renders a single point that fills the entire
+ * framebuffer.
+ */
#define R300_RE_POINTSIZE 0x421C
# define R300_POINTSIZE_Y_SHIFT 0
-# define R300_POINTSIZE_Y_MASK (0xFFFF << 0) /* GUESS */
+# define R300_POINTSIZE_Y_MASK (0xFFFF << 0) /* GUESS */
# define R300_POINTSIZE_X_SHIFT 16
-# define R300_POINTSIZE_X_MASK (0xFFFF << 16) /* GUESS */
+# define R300_POINTSIZE_X_MASK (0xFFFF << 16) /* GUESS */
# define R300_POINTSIZE_MAX (R300_POINTSIZE_Y_MASK / 6)
/* The line width is given in multiples of 6.
- In default mode lines are classified as vertical lines.
- HO: horizontal
- VE: vertical or horizontal
- HO & VE: no classification
-*/
+ * In default mode lines are classified as vertical lines.
+ * HO: horizontal
+ * VE: vertical or horizontal
+ * HO & VE: no classification
+ */
#define R300_RE_LINE_CNT 0x4234
# define R300_LINESIZE_SHIFT 0
-# define R300_LINESIZE_MASK (0xFFFF << 0) /* GUESS */
+# define R300_LINESIZE_MASK (0xFFFF << 0) /* GUESS */
# define R300_LINESIZE_MAX (R300_LINESIZE_MASK / 6)
# define R300_LINE_CNT_HO (1 << 16)
# define R300_LINE_CNT_VE (1 << 17)
@@ -499,6 +562,9 @@ I am fairly certain that they are correct unless stated otherwise in comments.
/* Some sort of scale or clamp value for texcoordless textures. */
#define R300_RE_UNK4238 0x4238
+/* Something shade related */
+#define R300_RE_SHADE 0x4274
+
#define R300_RE_SHADE_MODEL 0x4278
# define R300_RE_SHADE_MODEL_SMOOTH 0x3aaaa
# define R300_RE_SHADE_MODEL_FLAT 0x39595
@@ -513,24 +579,31 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_PM_BACK_LINE (1 << 7)
# define R300_PM_BACK_FILL (1 << 8)
+/* Fog parameters */
+#define R300_RE_FOG_SCALE 0x4294
+#define R300_RE_FOG_START 0x4298
+
/* Not sure why there are duplicate of factor and constant values.
- My best guess so far is that there are seperate zbiases for test and write.
- Ordering might be wrong.
- Some of the tests indicate that fgl has a fallback implementation of zbias
- via pixel shaders. */
+ * My best guess so far is that there are seperate zbiases for test and write.
+ * Ordering might be wrong.
+ * Some of the tests indicate that fgl has a fallback implementation of zbias
+ * via pixel shaders.
+ */
+#define R300_RE_ZBIAS_CNTL 0x42A0 /* GUESS */
#define R300_RE_ZBIAS_T_FACTOR 0x42A4
#define R300_RE_ZBIAS_T_CONSTANT 0x42A8
#define R300_RE_ZBIAS_W_FACTOR 0x42AC
#define R300_RE_ZBIAS_W_CONSTANT 0x42B0
/* This register needs to be set to (1<<1) for RV350 to correctly
- perform depth test (see --vb-triangles in r300_demo)
- Don't know about other chips. - Vladimir
- This is set to 3 when GL_POLYGON_OFFSET_FILL is on.
- My guess is that there are two bits for each zbias primitive (FILL, LINE, POINT).
- One to enable depth test and one for depth write.
- Yet this doesnt explain why depth writes work ...
- */
+ * perform depth test (see --vb-triangles in r300_demo)
+ * Don't know about other chips. - Vladimir
+ * This is set to 3 when GL_POLYGON_OFFSET_FILL is on.
+ * My guess is that there are two bits for each zbias primitive
+ * (FILL, LINE, POINT).
+ * One to enable depth test and one for depth write.
+ * Yet this doesnt explain why depth writes work ...
+ */
#define R300_RE_OCCLUSION_CNTL 0x42B4
# define R300_OCCLUSION_ON (1<<1)
@@ -540,30 +613,38 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_FRONT_FACE_CCW (0 << 2)
# define R300_FRONT_FACE_CW (1 << 2)
-/* BEGIN: Rasterization / Interpolators - many guesses
-// 0_UNKNOWN_18 has always been set except for clear operations.
-// TC_CNT is the number of incoming texture coordinate sets (i.e. it depends
-// on the vertex program, *not* the fragment program) */
+
+/* BEGIN: Rasterization / Interpolators - many guesses */
+
+/* 0_UNKNOWN_18 has always been set except for clear operations.
+ * TC_CNT is the number of incoming texture coordinate sets (i.e. it depends
+ * on the vertex program, *not* the fragment program)
+ */
#define R300_RS_CNTL_0 0x4300
# define R300_RS_CNTL_TC_CNT_SHIFT 2
# define R300_RS_CNTL_TC_CNT_MASK (7 << 2)
-# define R300_RS_CNTL_CI_CNT_SHIFT 7 /* number of color interpolators used */
+ /* number of color interpolators used */
+# define R300_RS_CNTL_CI_CNT_SHIFT 7
# define R300_RS_CNTL_0_UNKNOWN_18 (1 << 18)
-/* Guess: RS_CNTL_1 holds the index of the highest used RS_ROUTE_n register. */
+ /* Guess: RS_CNTL_1 holds the index of the highest used RS_ROUTE_n
+ register. */
#define R300_RS_CNTL_1 0x4304
/* gap */
+
/* Only used for texture coordinates.
-// Use the source field to route texture coordinate input from the vertex program
-// to the desired interpolator. Note that the source field is relative to the
-// outputs the vertex program *actually* writes. If a vertex program only writes
-// texcoord[1], this will be source index 0.
-// Set INTERP_USED on all interpolators that produce data used by the
-// fragment program. INTERP_USED looks like a swizzling mask, but
-// I haven't seen it used that way.
-//
-// Note: The _UNKNOWN constants are always set in their respective register.
-// I don't know if this is necessary. */
+ * Use the source field to route texture coordinate input from the
+ * vertex program to the desired interpolator. Note that the source
+ * field is relative to the outputs the vertex program *actually*
+ * writes. If a vertex program only writes texcoord[1], this will
+ * be source index 0.
+ * Set INTERP_USED on all interpolators that produce data used by
+ * the fragment program. INTERP_USED looks like a swizzling mask,
+ * but I haven't seen it used that way.
+ *
+ * Note: The _UNKNOWN constants are always set in their respective
+ * register. I don't know if this is necessary.
+ */
#define R300_RS_INTERP_0 0x4310
#define R300_RS_INTERP_1 0x4314
# define R300_RS_INTERP_1_UNKNOWN 0x40
@@ -580,54 +661,63 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_RS_INTERP_USED 0x00D10000
/* These DWORDs control how vertex data is routed into fragment program
-// registers, after interpolators. */
+ * registers, after interpolators.
+ */
#define R300_RS_ROUTE_0 0x4330
#define R300_RS_ROUTE_1 0x4334
#define R300_RS_ROUTE_2 0x4338
-#define R300_RS_ROUTE_3 0x433C /* GUESS */
-#define R300_RS_ROUTE_4 0x4340 /* GUESS */
-#define R300_RS_ROUTE_5 0x4344 /* GUESS */
-#define R300_RS_ROUTE_6 0x4348 /* GUESS */
-#define R300_RS_ROUTE_7 0x434C /* GUESS */
+#define R300_RS_ROUTE_3 0x433C /* GUESS */
+#define R300_RS_ROUTE_4 0x4340 /* GUESS */
+#define R300_RS_ROUTE_5 0x4344 /* GUESS */
+#define R300_RS_ROUTE_6 0x4348 /* GUESS */
+#define R300_RS_ROUTE_7 0x434C /* GUESS */
# define R300_RS_ROUTE_SOURCE_INTERP_0 0
# define R300_RS_ROUTE_SOURCE_INTERP_1 1
# define R300_RS_ROUTE_SOURCE_INTERP_2 2
# define R300_RS_ROUTE_SOURCE_INTERP_3 3
# define R300_RS_ROUTE_SOURCE_INTERP_4 4
-# define R300_RS_ROUTE_SOURCE_INTERP_5 5 /* GUESS */
-# define R300_RS_ROUTE_SOURCE_INTERP_6 6 /* GUESS */
-# define R300_RS_ROUTE_SOURCE_INTERP_7 7 /* GUESS */
-# define R300_RS_ROUTE_ENABLE (1 << 3) /* GUESS */
+# define R300_RS_ROUTE_SOURCE_INTERP_5 5 /* GUESS */
+# define R300_RS_ROUTE_SOURCE_INTERP_6 6 /* GUESS */
+# define R300_RS_ROUTE_SOURCE_INTERP_7 7 /* GUESS */
+# define R300_RS_ROUTE_ENABLE (1 << 3) /* GUESS */
# define R300_RS_ROUTE_DEST_SHIFT 6
-# define R300_RS_ROUTE_DEST_MASK (31 << 6) /* GUESS */
+# define R300_RS_ROUTE_DEST_MASK (31 << 6) /* GUESS */
/* Special handling for color: When the fragment program uses color,
-// the ROUTE_0_COLOR bit is set and ROUTE_0_COLOR_DEST contains the
-// color register index. */
+ * the ROUTE_0_COLOR bit is set and ROUTE_0_COLOR_DEST contains the
+ * color register index.
+ *
+ * Apperently you may set the R300_RS_ROUTE_0_COLOR bit, but not provide any
+ * R300_RS_ROUTE_0_COLOR_DEST value; this setup is used for clearing the state.
+ * See r300_ioctl.c:r300EmitClearState. I'm not sure if this setup is strictly
+ * correct or not. - Oliver.
+ */
# define R300_RS_ROUTE_0_COLOR (1 << 14)
# define R300_RS_ROUTE_0_COLOR_DEST_SHIFT 17
-# define R300_RS_ROUTE_0_COLOR_DEST_MASK (31 << 17) /* GUESS */
+# define R300_RS_ROUTE_0_COLOR_DEST_MASK (31 << 17) /* GUESS */
/* As above, but for secondary color */
# define R300_RS_ROUTE_1_COLOR1 (1 << 14)
# define R300_RS_ROUTE_1_COLOR1_DEST_SHIFT 17
# define R300_RS_ROUTE_1_COLOR1_DEST_MASK (31 << 17)
# define R300_RS_ROUTE_1_UNKNOWN11 (1 << 11)
-/* END */
-
-/* BEGIN: Scissors and cliprects
-// There are four clipping rectangles. Their corner coordinates are inclusive.
-// Every pixel is assigned a number from 0 and 15 by setting bits 0-3 depending
-// on whether the pixel is inside cliprects 0-3, respectively. For example,
-// if a pixel is inside cliprects 0 and 1, but outside 2 and 3, it is assigned
-// the number 3 (binary 0011).
-// Iff the bit corresponding to the pixel's number in RE_CLIPRECT_CNTL is set,
-// the pixel is rasterized.
-//
-// In addition to this, there is a scissors rectangle. Only pixels inside the
-// scissors rectangle are drawn. (coordinates are inclusive)
-//
-// For some reason, the top-left corner of the framebuffer is at (1440, 1440)
-// for the purpose of clipping and scissors. */
+/* END: Rasterization / Interpolators - many guesses */
+
+/* BEGIN: Scissors and cliprects */
+
+/* There are four clipping rectangles. Their corner coordinates are inclusive.
+ * Every pixel is assigned a number from 0 and 15 by setting bits 0-3 depending
+ * on whether the pixel is inside cliprects 0-3, respectively. For example,
+ * if a pixel is inside cliprects 0 and 1, but outside 2 and 3, it is assigned
+ * the number 3 (binary 0011).
+ * Iff the bit corresponding to the pixel's number in RE_CLIPRECT_CNTL is set,
+ * the pixel is rasterized.
+ *
+ * In addition to this, there is a scissors rectangle. Only pixels inside the
+ * scissors rectangle are drawn. (coordinates are inclusive)
+ *
+ * For some reason, the top-left corner of the framebuffer is at (1440, 1440)
+ * for the purpose of clipping and scissors.
+ */
#define R300_RE_CLIPRECT_TL_0 0x43B0
#define R300_RE_CLIPRECT_BR_0 0x43B4
#define R300_RE_CLIPRECT_TL_1 0x43B8
@@ -661,6 +751,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_CLIP_3210 (1 << 15)
/* gap */
+
#define R300_RE_SCISSORS_TL 0x43E0
#define R300_RE_SCISSORS_BR 0x43E4
# define R300_SCISSORS_OFFSET 1440
@@ -668,12 +759,15 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_SCISSORS_X_MASK (0x1FFF << 0)
# define R300_SCISSORS_Y_SHIFT 13
# define R300_SCISSORS_Y_MASK (0x1FFF << 13)
-/* END */
+/* END: Scissors and cliprects */
-/* BEGIN: Texture specification
-// The texture specification dwords are grouped by meaning and not by texture unit.
-// This means that e.g. the offset for texture image unit N is found in register
-// TX_OFFSET_0 + (4*N) */
+/* BEGIN: Texture specification */
+
+/*
+ * The texture specification dwords are grouped by meaning and not by texture
+ * unit. This means that e.g. the offset for texture image unit N is found in
+ * register TX_OFFSET_0 + (4*N)
+ */
#define R300_TX_FILTER_0 0x4400
# define R300_TX_REPEAT 0
# define R300_TX_MIRRORED 1
@@ -697,13 +791,14 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_TX_MIN_FILTER_LINEAR_MIP_LINEAR (10 << 11)
/* NOTE: NEAREST doesnt seem to exist.
- Im not seting MAG_FILTER_MASK and (3 << 11) on for all
- anisotropy modes because that would void selected mag filter */
-# define R300_TX_MIN_FILTER_ANISO_NEAREST ((0 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
-# define R300_TX_MIN_FILTER_ANISO_LINEAR ((0 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
-# define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST ((1 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
-# define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR ((2 << 13) /*|R300_TX_MAG_FILTER_MASK|(3<<11)*/)
-# define R300_TX_MIN_FILTER_MASK ( (15 << 11) | (3 << 13) )
+ * Im not seting MAG_FILTER_MASK and (3 << 11) on for all
+ * anisotropy modes because that would void selected mag filter
+ */
+# define R300_TX_MIN_FILTER_ANISO_NEAREST (0 << 13)
+# define R300_TX_MIN_FILTER_ANISO_LINEAR (0 << 13)
+# define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST (1 << 13)
+# define R300_TX_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR (2 << 13)
+# define R300_TX_MIN_FILTER_MASK ( (15 << 11) | (3 << 13) )
# define R300_TX_MAX_ANISO_1_TO_1 (0 << 21)
# define R300_TX_MAX_ANISO_2_TO_1 (2 << 21)
# define R300_TX_MAX_ANISO_4_TO_1 (4 << 21)
@@ -734,10 +829,10 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_TX_HEIGHTMASK_SHIFT 11
# define R300_TX_HEIGHTMASK_MASK (2047 << 11)
# define R300_TX_UNK23 (1 << 23)
-# define R300_TX_SIZE_SHIFT 26 /* largest of width, height */
-# define R300_TX_SIZE_MASK (15 << 26)
-# define R300_TX_SIZE_PROJECTED (1<<30)
-# define R300_TX_SIZE_TXPITCH_EN (1<<31)
+# define R300_TX_MAX_MIP_LEVEL_SHIFT 26
+# define R300_TX_MAX_MIP_LEVEL_MASK (0xf << 26)
+# define R300_TX_SIZE_PROJECTED (1<<30)
+# define R300_TX_SIZE_TXPITCH_EN (1<<31)
#define R300_TX_FORMAT_0 0x44C0
/* The interpretation of the format word by Wladimir van der Laan */
/* The X, Y, Z and W refer to the layout of the components.
@@ -761,11 +856,11 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_TX_FORMAT_DXT1 0xF
# define R300_TX_FORMAT_DXT3 0x10
# define R300_TX_FORMAT_DXT5 0x11
-# define R300_TX_FORMAT_D3DMFT_CxV8U8 0x12 /* no swizzle */
-# define R300_TX_FORMAT_A8R8G8B8 0x13 /* no swizzle */
-# define R300_TX_FORMAT_B8G8_B8G8 0x14 /* no swizzle */
-# define R300_TX_FORMAT_G8R8_G8B8 0x15 /* no swizzle */
- /* 0x16 - some 16 bit green format.. ?? */
+# define R300_TX_FORMAT_D3DMFT_CxV8U8 0x12 /* no swizzle */
+# define R300_TX_FORMAT_A8R8G8B8 0x13 /* no swizzle */
+# define R300_TX_FORMAT_B8G8_B8G8 0x14 /* no swizzle */
+# define R300_TX_FORMAT_G8R8_G8B8 0x15 /* no swizzle */
+ /* 0x16 - some 16 bit green format.. ?? */
# define R300_TX_FORMAT_UNK25 (1 << 25) /* no swizzle */
# define R300_TX_FORMAT_CUBIC_MAP (1 << 26)
@@ -793,23 +888,26 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_TX_FORMAT_W 3
# define R300_TX_FORMAT_ZERO 4
# define R300_TX_FORMAT_ONE 5
-# define R300_TX_FORMAT_CUT_Z 6 /* 2.0*Z, everything above 1.0 is set to 0.0 */
-# define R300_TX_FORMAT_CUT_W 7 /* 2.0*W, everything above 1.0 is set to 0.0 */
+ /* 2.0*Z, everything above 1.0 is set to 0.0 */
+# define R300_TX_FORMAT_CUT_Z 6
+ /* 2.0*W, everything above 1.0 is set to 0.0 */
+# define R300_TX_FORMAT_CUT_W 7
# define R300_TX_FORMAT_B_SHIFT 18
# define R300_TX_FORMAT_G_SHIFT 15
# define R300_TX_FORMAT_R_SHIFT 12
# define R300_TX_FORMAT_A_SHIFT 9
/* Convenience macro to take care of layout and swizzling */
-# define R300_EASY_TX_FORMAT(B, G, R, A, FMT) (\
- ((R300_TX_FORMAT_##B)<<R300_TX_FORMAT_B_SHIFT) \
- | ((R300_TX_FORMAT_##G)<<R300_TX_FORMAT_G_SHIFT) \
- | ((R300_TX_FORMAT_##R)<<R300_TX_FORMAT_R_SHIFT) \
- | ((R300_TX_FORMAT_##A)<<R300_TX_FORMAT_A_SHIFT) \
- | (R300_TX_FORMAT_##FMT) \
- )
- /* These can be ORed with result of R300_EASY_TX_FORMAT() */
- /* We don't really know what they do. Take values from a constant color ? */
+# define R300_EASY_TX_FORMAT(B, G, R, A, FMT) ( \
+ ((R300_TX_FORMAT_##B)<<R300_TX_FORMAT_B_SHIFT) \
+ | ((R300_TX_FORMAT_##G)<<R300_TX_FORMAT_G_SHIFT) \
+ | ((R300_TX_FORMAT_##R)<<R300_TX_FORMAT_R_SHIFT) \
+ | ((R300_TX_FORMAT_##A)<<R300_TX_FORMAT_A_SHIFT) \
+ | (R300_TX_FORMAT_##FMT) \
+ )
+ /* These can be ORed with result of R300_EASY_TX_FORMAT()
+ We don't really know what they do. Take values from a
+ constant color ? */
# define R300_TX_FORMAT_CONST_X (1<<5)
# define R300_TX_FORMAT_CONST_Y (2<<5)
# define R300_TX_FORMAT_CONST_Z (4<<5)
@@ -819,7 +917,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_TX_PITCH_0 0x4500 /* obvious missing in gap */
#define R300_TX_OFFSET_0 0x4540
-/* BEGIN: Guess from R200 */
+ /* BEGIN: Guess from R200 */
# define R300_TXO_ENDIAN_NO_SWAP (0 << 0)
# define R300_TXO_ENDIAN_BYTE_SWAP (1 << 0)
# define R300_TXO_ENDIAN_WORD_SWAP (2 << 0)
@@ -828,53 +926,61 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_TXO_MICRO_TILE (1 << 3)
# define R300_TXO_OFFSET_MASK 0xffffffe0
# define R300_TXO_OFFSET_SHIFT 5
-/* END */
-#define R300_TX_CHROMA_KEY_0 0x4580 /* 32 bit chroma key */
-#define R300_TX_BORDER_COLOR_0 0x45C0 //ff00ff00 == { 0, 1.0, 0, 1.0 }
-
-/* END */
-
-/* BEGIN: Fragment program instruction set
-// Fragment programs are written directly into register space.
-// There are separate instruction streams for texture instructions and ALU
-// instructions.
-// In order to synchronize these streams, the program is divided into up
-// to 4 nodes. Each node begins with a number of TEX operations, followed
-// by a number of ALU operations.
-// The first node can have zero TEX ops, all subsequent nodes must have at least
-// one TEX ops.
-// All nodes must have at least one ALU op.
-//
-// The index of the last node is stored in PFS_CNTL_0: A value of 0 means
-// 1 node, a value of 3 means 4 nodes.
-// The total amount of instructions is defined in PFS_CNTL_2. The offsets are
-// offsets into the respective instruction streams, while *_END points to the
-// last instruction relative to this offset. */
+ /* END: Guess from R200 */
+
+/* 32 bit chroma key */
+#define R300_TX_CHROMA_KEY_0 0x4580
+/* ff00ff00 == { 0, 1.0, 0, 1.0 } */
+#define R300_TX_BORDER_COLOR_0 0x45C0
+
+/* END: Texture specification */
+
+/* BEGIN: Fragment program instruction set */
+
+/* Fragment programs are written directly into register space.
+ * There are separate instruction streams for texture instructions and ALU
+ * instructions.
+ * In order to synchronize these streams, the program is divided into up
+ * to 4 nodes. Each node begins with a number of TEX operations, followed
+ * by a number of ALU operations.
+ * The first node can have zero TEX ops, all subsequent nodes must have at
+ * least
+ * one TEX ops.
+ * All nodes must have at least one ALU op.
+ *
+ * The index of the last node is stored in PFS_CNTL_0: A value of 0 means
+ * 1 node, a value of 3 means 4 nodes.
+ * The total amount of instructions is defined in PFS_CNTL_2. The offsets are
+ * offsets into the respective instruction streams, while *_END points to the
+ * last instruction relative to this offset.
+ */
#define R300_PFS_CNTL_0 0x4600
# define R300_PFS_CNTL_LAST_NODES_SHIFT 0
# define R300_PFS_CNTL_LAST_NODES_MASK (3 << 0)
# define R300_PFS_CNTL_FIRST_NODE_HAS_TEX (1 << 3)
#define R300_PFS_CNTL_1 0x4604
/* There is an unshifted value here which has so far always been equal to the
-// index of the highest used temporary register. */
+ * index of the highest used temporary register.
+ */
#define R300_PFS_CNTL_2 0x4608
# define R300_PFS_CNTL_ALU_OFFSET_SHIFT 0
# define R300_PFS_CNTL_ALU_OFFSET_MASK (63 << 0)
# define R300_PFS_CNTL_ALU_END_SHIFT 6
-# define R300_PFS_CNTL_ALU_END_MASK (63 << 0)
+# define R300_PFS_CNTL_ALU_END_MASK (63 << 6)
# define R300_PFS_CNTL_TEX_OFFSET_SHIFT 12
-# define R300_PFS_CNTL_TEX_OFFSET_MASK (31 << 12) /* GUESS */
+# define R300_PFS_CNTL_TEX_OFFSET_MASK (31 << 12) /* GUESS */
# define R300_PFS_CNTL_TEX_END_SHIFT 18
-# define R300_PFS_CNTL_TEX_END_MASK (31 << 18) /* GUESS */
+# define R300_PFS_CNTL_TEX_END_MASK (31 << 18) /* GUESS */
/* gap */
+
/* Nodes are stored backwards. The last active node is always stored in
-// PFS_NODE_3.
-// Example: In a 2-node program, NODE_0 and NODE_1 are set to 0. The
-// first node is stored in NODE_2, the second node is stored in NODE_3.
-//
-// Offsets are relative to the master offset from PFS_CNTL_2.
-// LAST_NODE is set for the last node, and only for the last node. */
+ * PFS_NODE_3.
+ * Example: In a 2-node program, NODE_0 and NODE_1 are set to 0. The
+ * first node is stored in NODE_2, the second node is stored in NODE_3.
+ *
+ * Offsets are relative to the master offset from PFS_CNTL_2.
+ */
#define R300_PFS_NODE_0 0x4610
#define R300_PFS_NODE_1 0x4614
#define R300_PFS_NODE_2 0x4618
@@ -887,91 +993,98 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_PFS_NODE_TEX_OFFSET_MASK (31 << 12)
# define R300_PFS_NODE_TEX_END_SHIFT 17
# define R300_PFS_NODE_TEX_END_MASK (31 << 17)
-/*# define R300_PFS_NODE_LAST_NODE (1 << 22) */
# define R300_PFS_NODE_OUTPUT_COLOR (1 << 22)
# define R300_PFS_NODE_OUTPUT_DEPTH (1 << 23)
/* TEX
-// As far as I can tell, texture instructions cannot write into output
-// registers directly. A subsequent ALU instruction is always necessary,
-// even if it's just MAD o0, r0, 1, 0 */
+ * As far as I can tell, texture instructions cannot write into output
+ * registers directly. A subsequent ALU instruction is always necessary,
+ * even if it's just MAD o0, r0, 1, 0
+ */
#define R300_PFS_TEXI_0 0x4620
-# define R300_FPITX_SRC_SHIFT 0
-# define R300_FPITX_SRC_MASK (31 << 0)
-# define R300_FPITX_SRC_CONST (1 << 5) /* GUESS */
-# define R300_FPITX_DST_SHIFT 6
-# define R300_FPITX_DST_MASK (31 << 6)
-# define R300_FPITX_IMAGE_SHIFT 11
-# define R300_FPITX_IMAGE_MASK (15 << 11) /* GUESS based on layout and native limits */
+# define R300_FPITX_SRC_SHIFT 0
+# define R300_FPITX_SRC_MASK (31 << 0)
+ /* GUESS */
+# define R300_FPITX_SRC_CONST (1 << 5)
+# define R300_FPITX_DST_SHIFT 6
+# define R300_FPITX_DST_MASK (31 << 6)
+# define R300_FPITX_IMAGE_SHIFT 11
+ /* GUESS based on layout and native limits */
+# define R300_FPITX_IMAGE_MASK (15 << 11)
/* Unsure if these are opcodes, or some kind of bitfield, but this is how
* they were set when I checked
*/
-# define R300_FPITX_OPCODE_SHIFT 15
-# define R300_FPITX_OP_TEX 1
-# define R300_FPITX_OP_KIL 2
-# define R300_FPITX_OP_TXP 3
-# define R300_FPITX_OP_TXB 4
+# define R300_FPITX_OPCODE_SHIFT 15
+# define R300_FPITX_OP_TEX 1
+# define R300_FPITX_OP_KIL 2
+# define R300_FPITX_OP_TXP 3
+# define R300_FPITX_OP_TXB 4
+# define R300_FPITX_OPCODE_MASK (7 << 15)
/* ALU
-// The ALU instructions register blocks are enumerated according to the order
-// in which fglrx. I assume there is space for 64 instructions, since
-// each block has space for a maximum of 64 DWORDs, and this matches reported
-// native limits.
-//
-// The basic functional block seems to be one MAD for each color and alpha,
-// and an adder that adds all components after the MUL.
-// - ADD, MUL, MAD etc.: use MAD with appropriate neutral operands
-// - DP4: Use OUTC_DP4, OUTA_DP4
-// - DP3: Use OUTC_DP3, OUTA_DP4, appropriate alpha operands
-// - DPH: Use OUTC_DP4, OUTA_DP4, appropriate alpha operands
-// - CMP: If ARG2 < 0, return ARG1, else return ARG0
-// - FLR: use FRC+MAD
-// - XPD: use MAD+MAD
-// - SGE, SLT: use MAD+CMP
-// - RSQ: use ABS modifier for argument
-// - Use OUTC_REPL_ALPHA to write results of an alpha-only operation (e.g. RCP)
-// into color register
-// - apparently, there's no quick DST operation
-// - fglrx set FPI2_UNKNOWN_31 on a "MAD fragment.color, tmp0, tmp1, tmp2"
-// - fglrx set FPI2_UNKNOWN_31 on a "MAX r2, r1, c0"
-// - fglrx once set FPI0_UNKNOWN_31 on a "FRC r1, r1"
-//
-// Operand selection
-// First stage selects three sources from the available registers and
-// constant parameters. This is defined in INSTR1 (color) and INSTR3 (alpha).
-// fglrx sorts the three source fields: Registers before constants,
-// lower indices before higher indices; I do not know whether this is necessary.
-// fglrx fills unused sources with "read constant 0"
-// According to specs, you cannot select more than two different constants.
-//
-// Second stage selects the operands from the sources. This is defined in
-// INSTR0 (color) and INSTR2 (alpha). You can also select the special constants
-// zero and one.
-// Swizzling and negation happens in this stage, as well.
-//
-// Important: Color and alpha seem to be mostly separate, i.e. their sources
-// selection appears to be fully independent (the register storage is probably
-// physically split into a color and an alpha section).
-// However (because of the apparent physical split), there is some interaction
-// WRT swizzling. If, for example, you want to load an R component into an
-// Alpha operand, this R component is taken from a *color* source, not from
-// an alpha source. The corresponding register doesn't even have to appear in
-// the alpha sources list. (I hope this alll makes sense to you)
-//
-// Destination selection
-// The destination register index is in FPI1 (color) and FPI3 (alpha) together
-// with enable bits.
-// There are separate enable bits for writing into temporary registers
-// (DSTC_REG_* /DSTA_REG) and and program output registers (DSTC_OUTPUT_* /DSTA_OUTPUT).
-// You can write to both at once, or not write at all (the same index
-// must be used for both).
-//
-// Note: There is a special form for LRP
-// - Argument order is the same as in ARB_fragment_program.
-// - Operation is MAD
-// - ARG1 is set to ARGC_SRC1C_LRP/ARGC_SRC1A_LRP
-// - Set FPI0/FPI2_SPECIAL_LRP
-// Arbitrary LRP (including support for swizzling) requires vanilla MAD+MAD */
+ * The ALU instructions register blocks are enumerated according to the order
+ * in which fglrx. I assume there is space for 64 instructions, since
+ * each block has space for a maximum of 64 DWORDs, and this matches reported
+ * native limits.
+ *
+ * The basic functional block seems to be one MAD for each color and alpha,
+ * and an adder that adds all components after the MUL.
+ * - ADD, MUL, MAD etc.: use MAD with appropriate neutral operands
+ * - DP4: Use OUTC_DP4, OUTA_DP4
+ * - DP3: Use OUTC_DP3, OUTA_DP4, appropriate alpha operands
+ * - DPH: Use OUTC_DP4, OUTA_DP4, appropriate alpha operands
+ * - CMPH: If ARG2 > 0.5, return ARG0, else return ARG1
+ * - CMP: If ARG2 < 0, return ARG1, else return ARG0
+ * - FLR: use FRC+MAD
+ * - XPD: use MAD+MAD
+ * - SGE, SLT: use MAD+CMP
+ * - RSQ: use ABS modifier for argument
+ * - Use OUTC_REPL_ALPHA to write results of an alpha-only operation
+ * (e.g. RCP) into color register
+ * - apparently, there's no quick DST operation
+ * - fglrx set FPI2_UNKNOWN_31 on a "MAD fragment.color, tmp0, tmp1, tmp2"
+ * - fglrx set FPI2_UNKNOWN_31 on a "MAX r2, r1, c0"
+ * - fglrx once set FPI0_UNKNOWN_31 on a "FRC r1, r1"
+ *
+ * Operand selection
+ * First stage selects three sources from the available registers and
+ * constant parameters. This is defined in INSTR1 (color) and INSTR3 (alpha).
+ * fglrx sorts the three source fields: Registers before constants,
+ * lower indices before higher indices; I do not know whether this is
+ * necessary.
+ *
+ * fglrx fills unused sources with "read constant 0"
+ * According to specs, you cannot select more than two different constants.
+ *
+ * Second stage selects the operands from the sources. This is defined in
+ * INSTR0 (color) and INSTR2 (alpha). You can also select the special constants
+ * zero and one.
+ * Swizzling and negation happens in this stage, as well.
+ *
+ * Important: Color and alpha seem to be mostly separate, i.e. their sources
+ * selection appears to be fully independent (the register storage is probably
+ * physically split into a color and an alpha section).
+ * However (because of the apparent physical split), there is some interaction
+ * WRT swizzling. If, for example, you want to load an R component into an
+ * Alpha operand, this R component is taken from a *color* source, not from
+ * an alpha source. The corresponding register doesn't even have to appear in
+ * the alpha sources list. (I hope this all makes sense to you)
+ *
+ * Destination selection
+ * The destination register index is in FPI1 (color) and FPI3 (alpha)
+ * together with enable bits.
+ * There are separate enable bits for writing into temporary registers
+ * (DSTC_REG_* /DSTA_REG) and and program output registers (DSTC_OUTPUT_*
+ * /DSTA_OUTPUT). You can write to both at once, or not write at all (the
+ * same index must be used for both).
+ *
+ * Note: There is a special form for LRP
+ * - Argument order is the same as in ARB_fragment_program.
+ * - Operation is MAD
+ * - ARG1 is set to ARGC_SRC1C_LRP/ARGC_SRC1A_LRP
+ * - Set FPI0/FPI2_SPECIAL_LRP
+ * Arbitrary LRP (including support for swizzling) requires vanilla MAD+MAD
+ */
#define R300_PFS_INSTR1_0 0x46C0
# define R300_FPI1_SRC0C_SHIFT 0
# define R300_FPI1_SRC0C_MASK (31 << 0)
@@ -982,6 +1095,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_FPI1_SRC2C_SHIFT 12
# define R300_FPI1_SRC2C_MASK (31 << 12)
# define R300_FPI1_SRC2C_CONST (1 << 17)
+# define R300_FPI1_SRC_MASK 0x0003ffff
# define R300_FPI1_DSTC_SHIFT 18
# define R300_FPI1_DSTC_MASK (31 << 18)
# define R300_FPI1_DSTC_REG_MASK_SHIFT 23
@@ -1003,6 +1117,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_FPI3_SRC2A_SHIFT 12
# define R300_FPI3_SRC2A_MASK (31 << 12)
# define R300_FPI3_SRC2A_CONST (1 << 17)
+# define R300_FPI3_SRC_MASK 0x0003ffff
# define R300_FPI3_DSTA_SHIFT 18
# define R300_FPI3_DSTA_MASK (31 << 18)
# define R300_FPI3_DSTA_REG (1 << 23)
@@ -1028,7 +1143,8 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_FPI0_ARGC_SRC1C_LRP 15
# define R300_FPI0_ARGC_ZERO 20
# define R300_FPI0_ARGC_ONE 21
-# define R300_FPI0_ARGC_HALF 22 /* GUESS */
+ /* GUESS */
+# define R300_FPI0_ARGC_HALF 22
# define R300_FPI0_ARGC_SRC0C_YZX 23
# define R300_FPI0_ARGC_SRC1C_YZX 24
# define R300_FPI0_ARGC_SRC2C_YZX 25
@@ -1057,6 +1173,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_FPI0_OUTC_DP4 (2 << 23)
# define R300_FPI0_OUTC_MIN (4 << 23)
# define R300_FPI0_OUTC_MAX (5 << 23)
+# define R300_FPI0_OUTC_CMPH (7 << 23)
# define R300_FPI0_OUTC_CMP (8 << 23)
# define R300_FPI0_OUTC_FRC (9 << 23)
# define R300_FPI0_OUTC_REPL_ALPHA (10 << 23)
@@ -1079,20 +1196,23 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_FPI2_ARGA_SRC1A_LRP 15
# define R300_FPI2_ARGA_ZERO 16
# define R300_FPI2_ARGA_ONE 17
-# define R300_FPI2_ARGA_HALF 18 /* GUESS */
-
+ /* GUESS */
+# define R300_FPI2_ARGA_HALF 18
# define R300_FPI2_ARG0A_SHIFT 0
# define R300_FPI2_ARG0A_MASK (31 << 0)
# define R300_FPI2_ARG0A_NEG (1 << 5)
-# define R300_FPI2_ARG0A_ABS (1 << 6) /* GUESS */
+ /* GUESS */
+# define R300_FPI2_ARG0A_ABS (1 << 6)
# define R300_FPI2_ARG1A_SHIFT 7
# define R300_FPI2_ARG1A_MASK (31 << 7)
# define R300_FPI2_ARG1A_NEG (1 << 12)
-# define R300_FPI2_ARG1A_ABS (1 << 13) /* GUESS */
+ /* GUESS */
+# define R300_FPI2_ARG1A_ABS (1 << 13)
# define R300_FPI2_ARG2A_SHIFT 14
# define R300_FPI2_ARG2A_MASK (31 << 14)
# define R300_FPI2_ARG2A_NEG (1 << 19)
-# define R300_FPI2_ARG2A_ABS (1 << 20) /* GUESS */
+ /* GUESS */
+# define R300_FPI2_ARG2A_ABS (1 << 20)
# define R300_FPI2_SPECIAL_LRP (1 << 21)
# define R300_FPI2_OUTA_MAD (0 << 23)
# define R300_FPI2_OUTA_DP4 (1 << 23)
@@ -1106,9 +1226,19 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_FPI2_OUTA_RSQ (11 << 23)
# define R300_FPI2_OUTA_SAT (1 << 30)
# define R300_FPI2_UNKNOWN_31 (1 << 31)
-/* END */
+/* END: Fragment program instruction set */
+
+/* Fog state and color */
+#define R300_RE_FOG_STATE 0x4BC0
+# define R300_FOG_ENABLE (1 << 0)
+# define R300_FOG_MODE_LINEAR (0 << 1)
+# define R300_FOG_MODE_EXP (1 << 1)
+# define R300_FOG_MODE_EXP2 (2 << 1)
+# define R300_FOG_MODE_MASK (3 << 1)
+#define R300_FOG_COLOR_R 0x4BC8
+#define R300_FOG_COLOR_G 0x4BCC
+#define R300_FOG_COLOR_B 0x4BD0
-/* gap */
#define R300_PP_ALPHA_TEST 0x4BD4
# define R300_REF_ALPHA_MASK 0x000000ff
# define R300_ALPHA_TEST_FAIL (0 << 8)
@@ -1123,6 +1253,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_ALPHA_TEST_ENABLE (1 << 11)
/* gap */
+
/* Fragment program parameters in 7.16 floating point */
#define R300_PFS_PARAM_0_X 0x4C00
#define R300_PFS_PARAM_0_Y 0x4C04
@@ -1135,45 +1266,48 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_PFS_PARAM_31_W 0x4DFC
/* Notes:
-// - AFAIK fglrx always sets BLEND_UNKNOWN when blending is used in the application
-// - AFAIK fglrx always sets BLEND_NO_SEPARATE when CBLEND and ABLEND are set to the same
-// function (both registers are always set up completely in any case)
-// - Most blend flags are simply copied from R200 and not tested yet */
+ * - AFAIK fglrx always sets BLEND_UNKNOWN when blending is used in
+ * the application
+ * - AFAIK fglrx always sets BLEND_NO_SEPARATE when CBLEND and ABLEND
+ * are set to the same
+ * function (both registers are always set up completely in any case)
+ * - Most blend flags are simply copied from R200 and not tested yet
+ */
#define R300_RB3D_CBLEND 0x4E04
#define R300_RB3D_ABLEND 0x4E08
- /* the following only appear in CBLEND */
+/* the following only appear in CBLEND */
# define R300_BLEND_ENABLE (1 << 0)
# define R300_BLEND_UNKNOWN (3 << 1)
# define R300_BLEND_NO_SEPARATE (1 << 3)
- /* the following are shared between CBLEND and ABLEND */
+/* the following are shared between CBLEND and ABLEND */
# define R300_FCN_MASK (3 << 12)
# define R300_COMB_FCN_ADD_CLAMP (0 << 12)
# define R300_COMB_FCN_ADD_NOCLAMP (1 << 12)
# define R300_COMB_FCN_SUB_CLAMP (2 << 12)
# define R300_COMB_FCN_SUB_NOCLAMP (3 << 12)
-# define R300_SRC_BLEND_GL_ZERO (32 << 16)
-# define R300_SRC_BLEND_GL_ONE (33 << 16)
-# define R300_SRC_BLEND_GL_SRC_COLOR (34 << 16)
-# define R300_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 16)
-# define R300_SRC_BLEND_GL_DST_COLOR (36 << 16)
-# define R300_SRC_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 16)
-# define R300_SRC_BLEND_GL_SRC_ALPHA (38 << 16)
-# define R300_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 16)
-# define R300_SRC_BLEND_GL_DST_ALPHA (40 << 16)
-# define R300_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 16)
-# define R300_SRC_BLEND_GL_SRC_ALPHA_SATURATE (42 << 16)
-# define R300_SRC_BLEND_MASK (63 << 16)
-# define R300_DST_BLEND_GL_ZERO (32 << 24)
-# define R300_DST_BLEND_GL_ONE (33 << 24)
-# define R300_DST_BLEND_GL_SRC_COLOR (34 << 24)
-# define R300_DST_BLEND_GL_ONE_MINUS_SRC_COLOR (35 << 24)
-# define R300_DST_BLEND_GL_DST_COLOR (36 << 24)
-# define R300_DST_BLEND_GL_ONE_MINUS_DST_COLOR (37 << 24)
-# define R300_DST_BLEND_GL_SRC_ALPHA (38 << 24)
-# define R300_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA (39 << 24)
-# define R300_DST_BLEND_GL_DST_ALPHA (40 << 24)
-# define R300_DST_BLEND_GL_ONE_MINUS_DST_ALPHA (41 << 24)
-# define R300_DST_BLEND_MASK (63 << 24)
+# define R300_COMB_FCN_MIN (4 << 12)
+# define R300_COMB_FCN_MAX (5 << 12)
+# define R300_COMB_FCN_RSUB_CLAMP (6 << 12)
+# define R300_COMB_FCN_RSUB_NOCLAMP (7 << 12)
+# define R300_BLEND_GL_ZERO (32)
+# define R300_BLEND_GL_ONE (33)
+# define R300_BLEND_GL_SRC_COLOR (34)
+# define R300_BLEND_GL_ONE_MINUS_SRC_COLOR (35)
+# define R300_BLEND_GL_DST_COLOR (36)
+# define R300_BLEND_GL_ONE_MINUS_DST_COLOR (37)
+# define R300_BLEND_GL_SRC_ALPHA (38)
+# define R300_BLEND_GL_ONE_MINUS_SRC_ALPHA (39)
+# define R300_BLEND_GL_DST_ALPHA (40)
+# define R300_BLEND_GL_ONE_MINUS_DST_ALPHA (41)
+# define R300_BLEND_GL_SRC_ALPHA_SATURATE (42)
+# define R300_BLEND_GL_CONST_COLOR (43)
+# define R300_BLEND_GL_ONE_MINUS_CONST_COLOR (44)
+# define R300_BLEND_GL_CONST_ALPHA (45)
+# define R300_BLEND_GL_ONE_MINUS_CONST_ALPHA (46)
+# define R300_BLEND_MASK (63)
+# define R300_SRC_BLEND_SHIFT (16)
+# define R300_DST_BLEND_SHIFT (24)
+#define R300_RB3D_BLEND_COLOR 0x4E10
#define R300_RB3D_COLORMASK 0x4E0C
# define R300_COLORMASK0_B (1<<0)
# define R300_COLORMASK0_G (1<<1)
@@ -1181,41 +1315,49 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_COLORMASK0_A (1<<3)
/* gap */
+
#define R300_RB3D_COLOROFFSET0 0x4E28
-# define R300_COLOROFFSET_MASK 0xFFFFFFF0 /* GUESS */
-#define R300_RB3D_COLOROFFSET1 0x4E2C /* GUESS */
-#define R300_RB3D_COLOROFFSET2 0x4E30 /* GUESS */
-#define R300_RB3D_COLOROFFSET3 0x4E34 /* GUESS */
+# define R300_COLOROFFSET_MASK 0xFFFFFFF0 /* GUESS */
+#define R300_RB3D_COLOROFFSET1 0x4E2C /* GUESS */
+#define R300_RB3D_COLOROFFSET2 0x4E30 /* GUESS */
+#define R300_RB3D_COLOROFFSET3 0x4E34 /* GUESS */
+
/* gap */
+
/* Bit 16: Larger tiles
-// Bit 17: 4x2 tiles
-// Bit 18: Extremely weird tile like, but some pixels duplicated? */
+ * Bit 17: 4x2 tiles
+ * Bit 18: Extremely weird tile like, but some pixels duplicated?
+ */
#define R300_RB3D_COLORPITCH0 0x4E38
-# define R300_COLORPITCH_MASK 0x00001FF8 /* GUESS */
-# define R300_COLOR_TILE_ENABLE (1 << 16) /* GUESS */
-# define R300_COLOR_MICROTILE_ENABLE (1 << 17) /* GUESS */
-# define R300_COLOR_ENDIAN_NO_SWAP (0 << 18) /* GUESS */
-# define R300_COLOR_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */
-# define R300_COLOR_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */
+# define R300_COLORPITCH_MASK 0x00001FF8 /* GUESS */
+# define R300_COLOR_TILE_ENABLE (1 << 16) /* GUESS */
+# define R300_COLOR_MICROTILE_ENABLE (1 << 17) /* GUESS */
+# define R300_COLOR_ENDIAN_NO_SWAP (0 << 18) /* GUESS */
+# define R300_COLOR_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */
+# define R300_COLOR_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */
# define R300_COLOR_FORMAT_RGB565 (2 << 22)
# define R300_COLOR_FORMAT_ARGB8888 (3 << 22)
-#define R300_RB3D_COLORPITCH1 0x4E3C /* GUESS */
-#define R300_RB3D_COLORPITCH2 0x4E40 /* GUESS */
-#define R300_RB3D_COLORPITCH3 0x4E44 /* GUESS */
+#define R300_RB3D_COLORPITCH1 0x4E3C /* GUESS */
+#define R300_RB3D_COLORPITCH2 0x4E40 /* GUESS */
+#define R300_RB3D_COLORPITCH3 0x4E44 /* GUESS */
/* gap */
+
/* Guess by Vladimir.
-// Set to 0A before 3D operations, set to 02 afterwards. */
+ * Set to 0A before 3D operations, set to 02 afterwards.
+ */
#define R300_RB3D_DSTCACHE_CTLSTAT 0x4E4C
-# define R300_RB3D_DSTCACHE_02 0x00000002
-# define R300_RB3D_DSTCACHE_0A 0x0000000A
+# define R300_RB3D_DSTCACHE_UNKNOWN_02 0x00000002
+# define R300_RB3D_DSTCACHE_UNKNOWN_0A 0x0000000A
/* gap */
-/* There seems to be no "write only" setting, so use Z-test = ALWAYS for this. */
-/* Bit (1<<8) is the "test" bit. so plain write is 6 - vd */
+/* There seems to be no "write only" setting, so use Z-test = ALWAYS
+ * for this.
+ * Bit (1<<8) is the "test" bit. so plain write is 6 - vd
+ */
#define R300_RB3D_ZSTENCIL_CNTL_0 0x4F00
-# define R300_RB3D_Z_DISABLED_1 0x00000010 /* GUESS */
-# define R300_RB3D_Z_DISABLED_2 0x00000014 /* GUESS */
+# define R300_RB3D_Z_DISABLED_1 0x00000010
+# define R300_RB3D_Z_DISABLED_2 0x00000014
# define R300_RB3D_Z_TEST 0x00000012
# define R300_RB3D_Z_TEST_AND_WRITE 0x00000016
# define R300_RB3D_Z_WRITE_ONLY 0x00000006
@@ -1226,7 +1368,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_RB3D_STENCIL_ENABLE 0x00000001
#define R300_RB3D_ZSTENCIL_CNTL_1 0x4F04
- /* functions */
+ /* functions */
# define R300_ZS_NEVER 0
# define R300_ZS_LESS 1
# define R300_ZS_LEQUAL 2
@@ -1236,7 +1378,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_ZS_NOTEQUAL 6
# define R300_ZS_ALWAYS 7
# define R300_ZS_MASK 7
- /* operations */
+ /* operations */
# define R300_ZS_KEEP 0
# define R300_ZS_ZERO 1
# define R300_ZS_REPLACE 2
@@ -1245,9 +1387,8 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_ZS_INVERT 5
# define R300_ZS_INCR_WRAP 6
# define R300_ZS_DECR_WRAP 7
-
- /* front and back refer to operations done for front
- and back faces, i.e. separate stencil function support */
+ /* front and back refer to operations done for front
+ and back faces, i.e. separate stencil function support */
# define R300_RB3D_ZS1_DEPTH_FUNC_SHIFT 0
# define R300_RB3D_ZS1_FRONT_FUNC_SHIFT 3
# define R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT 6
@@ -1269,45 +1410,64 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_RB3D_ZSTENCIL_FORMAT 0x4F10
# define R300_DEPTH_FORMAT_16BIT_INT_Z (0 << 0)
# define R300_DEPTH_FORMAT_24BIT_INT_Z (2 << 0)
+ /* 16 bit format or some aditional bit ? */
+# define R300_DEPTH_FORMAT_UNK32 (32 << 0)
+
+#define R300_RB3D_EARLY_Z 0x4F14
+# define R300_EARLY_Z_DISABLE (0 << 0)
+# define R300_EARLY_Z_ENABLE (1 << 0)
+
+/* gap */
+
+#define R300_RB3D_ZCACHE_CTLSTAT 0x4F18 /* GUESS */
+# define R300_RB3D_ZCACHE_UNKNOWN_01 0x1
+# define R300_RB3D_ZCACHE_UNKNOWN_03 0x3
/* gap */
+
#define R300_RB3D_DEPTHOFFSET 0x4F20
#define R300_RB3D_DEPTHPITCH 0x4F24
-# define R300_DEPTHPITCH_MASK 0x00001FF8 /* GUESS */
-# define R300_DEPTH_TILE_ENABLE (1 << 16) /* GUESS */
-# define R300_DEPTH_MICROTILE_ENABLE (1 << 17) /* GUESS */
-# define R300_DEPTH_ENDIAN_NO_SWAP (0 << 18) /* GUESS */
-# define R300_DEPTH_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */
-# define R300_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */
-
-/* BEGIN: Vertex program instruction set
-// Every instruction is four dwords long:
-// DWORD 0: output and opcode
-// DWORD 1: first argument
-// DWORD 2: second argument
-// DWORD 3: third argument
-//
-// Notes:
-// - ABS r, a is implemented as MAX r, a, -a
-// - MOV is implemented as ADD to zero
-// - XPD is implemented as MUL + MAD
-// - FLR is implemented as FRC + ADD
-// - apparently, fglrx tries to schedule instructions so that there is at least
-// one instruction between the write to a temporary and the first read
-// from said temporary; however, violations of this scheduling are allowed
-// - register indices seem to be unrelated with OpenGL aliasing to conventional state
-// - only one attribute and one parameter can be loaded at a time; however, the
-// same attribute/parameter can be used for more than one argument
-// - the second software argument for POW is the third hardware argument (no idea why)
-// - MAD with only temporaries as input seems to use VPI_OUT_SELECT_MAD_2
-//
-// There is some magic surrounding LIT:
-// The single argument is replicated across all three inputs, but swizzled:
-// First argument: xyzy
-// Second argument: xyzx
-// Third argument: xyzw
-// Whenever the result is used later in the fragment program, fglrx forces x and w
-// to be 1.0 in the input selection; I don't know whether this is strictly necessary */
+# define R300_DEPTHPITCH_MASK 0x00001FF8 /* GUESS */
+# define R300_DEPTH_TILE_ENABLE (1 << 16) /* GUESS */
+# define R300_DEPTH_MICROTILE_ENABLE (1 << 17) /* GUESS */
+# define R300_DEPTH_ENDIAN_NO_SWAP (0 << 18) /* GUESS */
+# define R300_DEPTH_ENDIAN_WORD_SWAP (1 << 18) /* GUESS */
+# define R300_DEPTH_ENDIAN_DWORD_SWAP (2 << 18) /* GUESS */
+
+/* BEGIN: Vertex program instruction set */
+
+/* Every instruction is four dwords long:
+ * DWORD 0: output and opcode
+ * DWORD 1: first argument
+ * DWORD 2: second argument
+ * DWORD 3: third argument
+ *
+ * Notes:
+ * - ABS r, a is implemented as MAX r, a, -a
+ * - MOV is implemented as ADD to zero
+ * - XPD is implemented as MUL + MAD
+ * - FLR is implemented as FRC + ADD
+ * - apparently, fglrx tries to schedule instructions so that there is at
+ * least one instruction between the write to a temporary and the first
+ * read from said temporary; however, violations of this scheduling are
+ * allowed
+ * - register indices seem to be unrelated with OpenGL aliasing to
+ * conventional state
+ * - only one attribute and one parameter can be loaded at a time; however,
+ * the same attribute/parameter can be used for more than one argument
+ * - the second software argument for POW is the third hardware argument
+ * (no idea why)
+ * - MAD with only temporaries as input seems to use VPI_OUT_SELECT_MAD_2
+ *
+ * There is some magic surrounding LIT:
+ * The single argument is replicated across all three inputs, but swizzled:
+ * First argument: xyzy
+ * Second argument: xyzx
+ * Third argument: xyzw
+ * Whenever the result is used later in the fragment program, fglrx forces
+ * x and w to be 1.0 in the input selection; I don't know whether this is
+ * strictly necessary
+ */
#define R300_VPI_OUT_OP_DOT (1 << 0)
#define R300_VPI_OUT_OP_MUL (2 << 0)
#define R300_VPI_OUT_OP_ADD (3 << 0)
@@ -1318,26 +1478,33 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_VPI_OUT_OP_MIN (8 << 0)
#define R300_VPI_OUT_OP_SGE (9 << 0)
#define R300_VPI_OUT_OP_SLT (10 << 0)
-#define R300_VPI_OUT_OP_UNK12 (12 << 0) /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, vector(scalar, vector) */
+ /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, vector(scalar, vector) */
+#define R300_VPI_OUT_OP_UNK12 (12 << 0)
+#define R300_VPI_OUT_OP_ARL (13 << 0)
#define R300_VPI_OUT_OP_EXP (65 << 0)
#define R300_VPI_OUT_OP_LOG (66 << 0)
-#define R300_VPI_OUT_OP_UNK67 (67 << 0) /* Used in fog computations, scalar(scalar) */
+ /* Used in fog computations, scalar(scalar) */
+#define R300_VPI_OUT_OP_UNK67 (67 << 0)
#define R300_VPI_OUT_OP_LIT (68 << 0)
#define R300_VPI_OUT_OP_POW (69 << 0)
#define R300_VPI_OUT_OP_RCP (70 << 0)
#define R300_VPI_OUT_OP_RSQ (72 << 0)
-#define R300_VPI_OUT_OP_UNK73 (73 << 0) /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, scalar(scalar) */
+ /* Used in GL_POINT_DISTANCE_ATTENUATION_ARB, scalar(scalar) */
+#define R300_VPI_OUT_OP_UNK73 (73 << 0)
#define R300_VPI_OUT_OP_EX2 (75 << 0)
#define R300_VPI_OUT_OP_LG2 (76 << 0)
#define R300_VPI_OUT_OP_MAD_2 (128 << 0)
-#define R300_VPI_OUT_OP_UNK129 (129 << 0) /* all temps, vector(scalar, vector, vector) */
+ /* all temps, vector(scalar, vector, vector) */
+#define R300_VPI_OUT_OP_UNK129 (129 << 0)
#define R300_VPI_OUT_REG_CLASS_TEMPORARY (0 << 8)
+#define R300_VPI_OUT_REG_CLASS_ADDR (1 << 8)
#define R300_VPI_OUT_REG_CLASS_RESULT (2 << 8)
#define R300_VPI_OUT_REG_CLASS_MASK (31 << 8)
#define R300_VPI_OUT_REG_INDEX_SHIFT 13
-#define R300_VPI_OUT_REG_INDEX_MASK (31 << 13) /* GUESS based on fglrx native limits */
+ /* GUESS based on fglrx native limits */
+#define R300_VPI_OUT_REG_INDEX_MASK (31 << 13)
#define R300_VPI_OUT_WRITE_X (1 << 20)
#define R300_VPI_OUT_WRITE_Y (1 << 21)
@@ -1348,14 +1515,16 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_VPI_IN_REG_CLASS_ATTRIBUTE (1 << 0)
#define R300_VPI_IN_REG_CLASS_PARAMETER (2 << 0)
#define R300_VPI_IN_REG_CLASS_NONE (9 << 0)
-#define R300_VPI_IN_REG_CLASS_MASK (31 << 0) /* GUESS */
+#define R300_VPI_IN_REG_CLASS_MASK (31 << 0)
#define R300_VPI_IN_REG_INDEX_SHIFT 5
-#define R300_VPI_IN_REG_INDEX_MASK (255 << 5) /* GUESS based on fglrx native limits */
+ /* GUESS based on fglrx native limits */
+#define R300_VPI_IN_REG_INDEX_MASK (255 << 5)
/* The R300 can select components from the input register arbitrarily.
-// Use the following constants, shifted by the component shift you
-// want to select */
+ * Use the following constants, shifted by the component shift you
+ * want to select
+ */
#define R300_VPI_IN_SELECT_X 0
#define R300_VPI_IN_SELECT_Y 1
#define R300_VPI_IN_SELECT_Z 2
@@ -1373,11 +1542,11 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_VPI_IN_NEG_Y (1 << 26)
#define R300_VPI_IN_NEG_Z (1 << 27)
#define R300_VPI_IN_NEG_W (1 << 28)
-/* END */
+/* END: Vertex program instruction set */
-//BEGIN: Packet 3 commands
+/* BEGIN: Packet 3 commands */
-// A primitive emission dword.
+/* A primitive emission dword. */
#define R300_PRIM_TYPE_NONE (0 << 0)
#define R300_PRIM_TYPE_POINT (1 << 0)
#define R300_PRIM_TYPE_LINE (2 << 0)
@@ -1389,7 +1558,8 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_PRIM_TYPE_RECT_LIST (8 << 0)
#define R300_PRIM_TYPE_3VRT_POINT_LIST (9 << 0)
#define R300_PRIM_TYPE_3VRT_LINE_LIST (10 << 0)
-#define R300_PRIM_TYPE_POINT_SPRITES (11 << 0) // GUESS (based on r200)
+ /* GUESS (based on r200) */
+#define R300_PRIM_TYPE_POINT_SPRITES (11 << 0)
#define R300_PRIM_TYPE_LINE_LOOP (12 << 0)
#define R300_PRIM_TYPE_QUADS (13 << 0)
#define R300_PRIM_TYPE_QUAD_STRIP (14 << 0)
@@ -1399,37 +1569,58 @@ I am fairly certain that they are correct unless stated otherwise in comments.
#define R300_PRIM_WALK_LIST (2 << 4)
#define R300_PRIM_WALK_RING (3 << 4)
#define R300_PRIM_WALK_MASK (3 << 4)
-#define R300_PRIM_COLOR_ORDER_BGRA (0 << 6) // GUESS (based on r200)
-#define R300_PRIM_COLOR_ORDER_RGBA (1 << 6) // GUESS
+ /* GUESS (based on r200) */
+#define R300_PRIM_COLOR_ORDER_BGRA (0 << 6)
+#define R300_PRIM_COLOR_ORDER_RGBA (1 << 6)
#define R300_PRIM_NUM_VERTICES_SHIFT 16
+#define R300_PRIM_NUM_VERTICES_MASK 0xffff
-// Draw a primitive from vertex data in arrays loaded via 3D_LOAD_VBPNTR.
-// Two parameter dwords:
-// 0. The first parameter appears to be always 0
-// 1. The second parameter is a standard primitive emission dword.
+/* Draw a primitive from vertex data in arrays loaded via 3D_LOAD_VBPNTR.
+ * Two parameter dwords:
+ * 0. The first parameter appears to be always 0
+ * 1. The second parameter is a standard primitive emission dword.
+ */
#define R300_PACKET3_3D_DRAW_VBUF 0x00002800
-// Specify the full set of vertex arrays as (address, stride).
-// The first parameter is the number of vertex arrays specified.
-// The rest of the command is a variable length list of blocks, where
-// each block is three dwords long and specifies two arrays.
-// The first dword of a block is split into two words, the lower significant
-// word refers to the first array, the more significant word to the second
-// array in the block.
-// The low byte of each word contains the size of an array entry in dwords,
-// the high byte contains the stride of the array.
-// The second dword of a block contains the pointer to the first array,
-// the third dword of a block contains the pointer to the second array.
-// Note that if the total number of arrays is odd, the third dword of
-// the last block is omitted.
+/* Specify the full set of vertex arrays as (address, stride).
+ * The first parameter is the number of vertex arrays specified.
+ * The rest of the command is a variable length list of blocks, where
+ * each block is three dwords long and specifies two arrays.
+ * The first dword of a block is split into two words, the lower significant
+ * word refers to the first array, the more significant word to the second
+ * array in the block.
+ * The low byte of each word contains the size of an array entry in dwords,
+ * the high byte contains the stride of the array.
+ * The second dword of a block contains the pointer to the first array,
+ * the third dword of a block contains the pointer to the second array.
+ * Note that if the total number of arrays is odd, the third dword of
+ * the last block is omitted.
+ */
#define R300_PACKET3_3D_LOAD_VBPNTR 0x00002F00
#define R300_PACKET3_INDX_BUFFER 0x00003300
# define R300_EB_UNK1_SHIFT 24
# define R300_EB_UNK1 (0x80<<24)
# define R300_EB_UNK2 0x0810
+#define R300_PACKET3_3D_DRAW_VBUF_2 0x00003400
#define R300_PACKET3_3D_DRAW_INDX_2 0x00003600
-//END
+/* END: Packet 3 commands */
+
+
+/* Color formats for 2d packets
+ */
+#define R300_CP_COLOR_FORMAT_CI8 2
+#define R300_CP_COLOR_FORMAT_ARGB1555 3
+#define R300_CP_COLOR_FORMAT_RGB565 4
+#define R300_CP_COLOR_FORMAT_ARGB8888 6
+#define R300_CP_COLOR_FORMAT_RGB332 7
+#define R300_CP_COLOR_FORMAT_RGB8 9
+#define R300_CP_COLOR_FORMAT_ARGB4444 15
+
+/*
+ * CP type-3 packets
+ */
+#define R300_CP_CMD_BITBLT_MULTI 0xC0009B00
-#endif /* _R300_REG_H */
+#endif /* _R300_REG_H */
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 68338389d836..af5790f8fd53 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -36,7 +36,7 @@
#define RADEON_FIFO_DEBUG 0
-static int radeon_do_cleanup_cp(drm_device_t * dev);
+static int radeon_do_cleanup_cp(struct drm_device * dev);
/* CP microcode (from ATI) */
static const u32 R200_cp_microcode[][2] = {
@@ -816,7 +816,7 @@ static const u32 R300_cp_microcode[][2] = {
{0000000000, 0000000000},
};
-static int RADEON_READ_PLL(drm_device_t * dev, int addr)
+static int RADEON_READ_PLL(struct drm_device * dev, int addr)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1066,7 +1066,7 @@ static void radeon_do_cp_stop(drm_radeon_private_t * dev_priv)
/* Reset the engine. This will stop the CP if it is running.
*/
-static int radeon_do_engine_reset(drm_device_t * dev)
+static int radeon_do_engine_reset(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
u32 clock_cntl_index, mclk_cntl, rbbm_soft_reset;
@@ -1122,7 +1122,7 @@ static int radeon_do_engine_reset(drm_device_t * dev)
return 0;
}
-static void radeon_cp_init_ring_buffer(drm_device_t * dev,
+static void radeon_cp_init_ring_buffer(struct drm_device * dev,
drm_radeon_private_t * dev_priv)
{
u32 ring_start, cur_read_ptr;
@@ -1174,7 +1174,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
} else
#endif
{
- drm_sg_mem_t *entry = dev->sg;
+ struct drm_sg_mem *entry = dev->sg;
unsigned long tmp_ofs, page_ofs;
tmp_ofs = dev_priv->ring_rptr->offset -
@@ -1384,7 +1384,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
}
}
-static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
+static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1420,6 +1420,10 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
return DRM_ERR(EINVAL);
}
+ /* Enable vblank on CRTC1 for older X servers
+ */
+ dev_priv->vblank_crtc = DRM_RADEON_VBLANK_CRTC1;
+
switch(init->func) {
case RADEON_INIT_R200_CP:
dev_priv->microcode_version = UCODE_R200;
@@ -1501,13 +1505,13 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
RADEON_ROUND_MODE_TRUNC |
RADEON_ROUND_PREC_8TH_PIX);
- DRM_GETSAREA();
dev_priv->ring_offset = init->ring_offset;
dev_priv->ring_rptr_offset = init->ring_rptr_offset;
dev_priv->buffers_offset = init->buffers_offset;
dev_priv->gart_textures_offset = init->gart_textures_offset;
+ dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
radeon_do_cleanup_cp(dev);
@@ -1731,7 +1735,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
return 0;
}
-static int radeon_do_cleanup_cp(drm_device_t * dev)
+static int radeon_do_cleanup_cp(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("\n");
@@ -1787,7 +1791,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev)
*
* Charl P. Botha <http://cpbotha.net>
*/
-static int radeon_do_resume_cp(drm_device_t * dev)
+static int radeon_do_resume_cp(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1914,7 +1918,7 @@ int radeon_cp_stop(DRM_IOCTL_ARGS)
return 0;
}
-void radeon_do_release(drm_device_t * dev)
+void radeon_do_release(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
int i, ret;
@@ -2042,12 +2046,12 @@ int radeon_fullscreen(DRM_IOCTL_ARGS)
* they can't get the lock.
*/
-drm_buf_t *radeon_freelist_get(drm_device_t * dev)
+struct drm_buf *radeon_freelist_get(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_buf_priv_t *buf_priv;
- drm_buf_t *buf;
+ struct drm_buf *buf;
int i, t;
int start;
@@ -2082,12 +2086,12 @@ drm_buf_t *radeon_freelist_get(drm_device_t * dev)
}
#if 0
-drm_buf_t *radeon_freelist_get(drm_device_t * dev)
+struct drm_buf *radeon_freelist_get(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_buf_priv_t *buf_priv;
- drm_buf_t *buf;
+ struct drm_buf *buf;
int i, t;
int start;
u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1));
@@ -2116,15 +2120,15 @@ drm_buf_t *radeon_freelist_get(drm_device_t * dev)
}
#endif
-void radeon_freelist_reset(drm_device_t * dev)
+void radeon_freelist_reset(struct drm_device * dev)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_radeon_private_t *dev_priv = dev->dev_private;
int i;
dev_priv->last_buf = 0;
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
buf_priv->age = 0;
}
@@ -2166,11 +2170,11 @@ int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n)
return DRM_ERR(EBUSY);
}
-static int radeon_cp_get_buffers(DRMFILE filp, drm_device_t * dev,
- drm_dma_t * d)
+static int radeon_cp_get_buffers(DRMFILE filp, struct drm_device * dev,
+ struct drm_dma * d)
{
int i;
- drm_buf_t *buf;
+ struct drm_buf *buf;
for (i = d->granted_count; i < d->request_count; i++) {
buf = radeon_freelist_get(dev);
@@ -2194,10 +2198,10 @@ static int radeon_cp_get_buffers(DRMFILE filp, drm_device_t * dev,
int radeon_cp_buffers(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
int ret = 0;
- drm_dma_t __user *argp = (void __user *)data;
- drm_dma_t d;
+ struct drm_dma __user *argp = (void __user *)data;
+ struct drm_dma d;
LOCK_TEST_WITH_RETURN(dev, filp);
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index 66c4b6fed04f..5a8e23f916fc 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -417,7 +417,7 @@ typedef struct {
/* The current cliprects, or a subset thereof.
*/
- drm_clip_rect_t boxes[RADEON_NR_SAREA_CLIPRECTS];
+ struct drm_clip_rect boxes[RADEON_NR_SAREA_CLIPRECTS];
unsigned int nbox;
/* Counters for client-side throttling of rendering clients.
@@ -426,7 +426,7 @@ typedef struct {
unsigned int last_dispatch;
unsigned int last_clear;
- drm_tex_region_t tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS +
+ struct drm_tex_region tex_list[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS +
1];
unsigned int tex_age[RADEON_NR_TEX_HEAPS];
int ctx_owner;
@@ -604,7 +604,7 @@ typedef struct drm_radeon_cmd_buffer {
int bufsz;
char __user *buf;
int nbox;
- drm_clip_rect_t __user *boxes;
+ struct drm_clip_rect __user *boxes;
} drm_radeon_cmd_buffer_t;
typedef struct drm_radeon_tex_image {
@@ -655,6 +655,7 @@ typedef struct drm_radeon_indirect {
#define RADEON_PARAM_GART_TEX_HANDLE 10
#define RADEON_PARAM_SCRATCH_OFFSET 11
#define RADEON_PARAM_CARD_TYPE 12
+#define RADEON_PARAM_VBLANK_CRTC 13 /* VBLANK CRTC */
typedef struct drm_radeon_getparam {
int param;
@@ -708,7 +709,7 @@ typedef struct drm_radeon_setparam {
#define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */
#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */
#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */
-
+#define RADEON_SETPARAM_VBLANK_CRTC 6 /* VBLANK CRTC */
/* 1.14: Clients can allocate/free a surface
*/
typedef struct drm_radeon_surface_alloc {
@@ -721,4 +722,7 @@ typedef struct drm_radeon_surface_free {
unsigned int address;
} drm_radeon_surface_free_t;
+#define DRM_RADEON_VBLANK_CRTC1 1
+#define DRM_RADEON_VBLANK_CRTC2 2
+
#endif
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index 2eb652ec6745..349ac3d3b848 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -60,7 +60,7 @@ 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_VBL | DRIVER_IRQ_VBL2,
.dev_priv_size = sizeof(drm_radeon_buf_priv_t),
.load = radeon_driver_load,
.firstopen = radeon_driver_firstopen,
@@ -70,6 +70,7 @@ static struct drm_driver driver = {
.lastclose = radeon_driver_lastclose,
.unload = radeon_driver_unload,
.vblank_wait = radeon_driver_vblank_wait,
+ .vblank_wait2 = radeon_driver_vblank_wait2,
.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 54f49ef4bef0..3b3d9357201c 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -97,9 +97,10 @@
* new packet type)
* 1.26- Add support for variable size PCI(E) gart aperture
* 1.27- Add support for IGP GART
+ * 1.28- Add support for VBL on CRTC2
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 27
+#define DRIVER_MINOR 28
#define DRIVER_PATCHLEVEL 0
/*
@@ -154,7 +155,7 @@ enum radeon_chip_flags {
typedef struct drm_radeon_freelist {
unsigned int age;
- drm_buf_t *buf;
+ struct drm_buf *buf;
struct drm_radeon_freelist *next;
struct drm_radeon_freelist *prev;
} drm_radeon_freelist_t;
@@ -277,13 +278,16 @@ typedef struct drm_radeon_private {
/* SW interrupt */
wait_queue_head_t swi_queue;
atomic_t swi_emitted;
+ int vblank_crtc;
+ uint32_t irq_enable_reg;
+ int irq_enabled;
struct radeon_surface surfaces[RADEON_MAX_SURFACES];
struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
unsigned long pcigart_offset;
unsigned int pcigart_offset_set;
- drm_ati_pcigart_info gart_info;
+ struct drm_ati_pcigart_info gart_info;
u32 scratch_ages[5];
@@ -299,7 +303,7 @@ typedef struct drm_radeon_kcmd_buffer {
int bufsz;
char *buf;
int nbox;
- drm_clip_rect_t __user *boxes;
+ struct drm_clip_rect __user *boxes;
} drm_radeon_kcmd_buffer_t;
extern int radeon_no_wb;
@@ -332,8 +336,8 @@ extern int radeon_engine_reset(DRM_IOCTL_ARGS);
extern int radeon_fullscreen(DRM_IOCTL_ARGS);
extern int radeon_cp_buffers(DRM_IOCTL_ARGS);
-extern void radeon_freelist_reset(drm_device_t * dev);
-extern drm_buf_t *radeon_freelist_get(drm_device_t * dev);
+extern void radeon_freelist_reset(struct drm_device * dev);
+extern struct drm_buf *radeon_freelist_get(struct drm_device * dev);
extern int radeon_wait_ring(drm_radeon_private_t * dev_priv, int n);
@@ -353,29 +357,33 @@ extern void radeon_mem_release(DRMFILE filp, struct mem_block *heap);
extern int radeon_irq_emit(DRM_IOCTL_ARGS);
extern int radeon_irq_wait(DRM_IOCTL_ARGS);
-extern void radeon_do_release(drm_device_t * dev);
-extern int radeon_driver_vblank_wait(drm_device_t * dev,
+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 irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
-extern void radeon_driver_irq_preinstall(drm_device_t * dev);
-extern void radeon_driver_irq_postinstall(drm_device_t * dev);
-extern void radeon_driver_irq_uninstall(drm_device_t * dev);
+extern void radeon_driver_irq_preinstall(struct drm_device * dev);
+extern void 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);
extern int radeon_driver_load(struct drm_device *dev, unsigned long flags);
extern int radeon_driver_unload(struct drm_device *dev);
extern int radeon_driver_firstopen(struct drm_device *dev);
-extern void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp);
-extern void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp);
-extern void radeon_driver_lastclose(drm_device_t * dev);
-extern int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv);
+extern void radeon_driver_preclose(struct drm_device * dev, DRMFILE filp);
+extern void radeon_driver_postclose(struct drm_device * dev, struct drm_file * filp);
+extern void radeon_driver_lastclose(struct drm_device * dev);
+extern int radeon_driver_open(struct drm_device * dev, struct drm_file * filp_priv);
extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
/* r300_cmdbuf.c */
extern void r300_init_reg_flags(void);
-extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
- drm_file_t * filp_priv,
+extern int r300_do_cp_cmdbuf(struct drm_device * dev, DRMFILE filp,
+ struct drm_file * filp_priv,
drm_radeon_kcmd_buffer_t * cmdbuf);
/* Flags for stats.boxes
@@ -496,12 +504,15 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_GEN_INT_CNTL 0x0040
# define RADEON_CRTC_VBLANK_MASK (1 << 0)
+# define RADEON_CRTC2_VBLANK_MASK (1 << 9)
# define RADEON_GUI_IDLE_INT_ENABLE (1 << 19)
# define RADEON_SW_INT_ENABLE (1 << 25)
#define RADEON_GEN_INT_STATUS 0x0044
# define RADEON_CRTC_VBLANK_STAT (1 << 0)
# define RADEON_CRTC_VBLANK_STAT_ACK (1 << 0)
+# define RADEON_CRTC2_VBLANK_STAT (1 << 9)
+# define RADEON_CRTC2_VBLANK_STAT_ACK (1 << 9)
# define RADEON_GUI_IDLE_INT_TEST_ACK (1 << 19)
# define RADEON_SW_INT_TEST (1 << 25)
# define RADEON_SW_INT_TEST_ACK (1 << 25)
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index 3ff0baa2fbfa..ad8a0ac7182e 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -64,7 +64,7 @@ static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t * dev_priv,
irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
{
- drm_device_t *dev = (drm_device_t *) arg;
+ struct drm_device *dev = (struct drm_device *) arg;
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
u32 stat;
@@ -73,18 +73,35 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
* outside the DRM
*/
stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
- RADEON_CRTC_VBLANK_STAT));
+ RADEON_CRTC_VBLANK_STAT |
+ RADEON_CRTC2_VBLANK_STAT));
if (!stat)
return IRQ_NONE;
+ stat &= dev_priv->irq_enable_reg;
+
/* SW interrupt */
if (stat & RADEON_SW_INT_TEST) {
DRM_WAKEUP(&dev_priv->swi_queue);
}
/* VBLANK interrupt */
- if (stat & RADEON_CRTC_VBLANK_STAT) {
- atomic_inc(&dev->vbl_received);
+ 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);
}
@@ -92,7 +109,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_HANDLED;
}
-static int radeon_emit_irq(drm_device_t * dev)
+static int radeon_emit_irq(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
unsigned int ret;
@@ -110,7 +127,7 @@ static int radeon_emit_irq(drm_device_t * dev)
return ret;
}
-static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
+static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
@@ -127,19 +144,30 @@ static int radeon_wait_irq(drm_device_t * dev, int swi_nr)
return ret;
}
-int radeon_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+int radeon_driver_vblank_do_wait(struct drm_device * dev, unsigned int *sequence,
+ 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;
if (!dev_priv) {
DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
return DRM_ERR(EINVAL);
}
- radeon_acknowledge_irqs(dev_priv, RADEON_CRTC_VBLANK_STAT);
+ 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
+ return DRM_ERR(EINVAL);
+
+ radeon_acknowledge_irqs(dev_priv, ack);
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
@@ -148,7 +176,7 @@ int radeon_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
* using vertical blanks...
*/
DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
- (((cur_vblank = atomic_read(&dev->vbl_received))
+ (((cur_vblank = atomic_read(counter))
- *sequence) <= (1 << 23)));
*sequence = cur_vblank;
@@ -156,6 +184,16 @@ int radeon_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
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);
+}
+
/* Needs the lock as it touches the ring.
*/
int radeon_irq_emit(DRM_IOCTL_ARGS)
@@ -204,9 +242,24 @@ int radeon_irq_wait(DRM_IOCTL_ARGS)
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(drm_device_t * dev)
+void radeon_driver_irq_preinstall(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
@@ -216,10 +269,11 @@ void radeon_driver_irq_preinstall(drm_device_t * dev)
/* Clear bits if they're already high */
radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
- RADEON_CRTC_VBLANK_STAT));
+ RADEON_CRTC_VBLANK_STAT |
+ RADEON_CRTC2_VBLANK_STAT));
}
-void radeon_driver_irq_postinstall(drm_device_t * dev)
+void radeon_driver_irq_postinstall(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
@@ -227,18 +281,48 @@ void radeon_driver_irq_postinstall(drm_device_t * dev)
atomic_set(&dev_priv->swi_emitted, 0);
DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
- /* Turn on SW and VBL ints */
- RADEON_WRITE(RADEON_GEN_INT_CNTL,
- RADEON_CRTC_VBLANK_MASK | RADEON_SW_INT_ENABLE);
+ radeon_enable_interrupt(dev);
}
-void radeon_driver_irq_uninstall(drm_device_t * dev)
+void radeon_driver_irq_uninstall(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv =
(drm_radeon_private_t *) dev->dev_private;
if (!dev_priv)
return;
+ dev_priv->irq_enabled = 0;
+
/* Disable *all* interrupts */
RADEON_WRITE(RADEON_GEN_INT_CNTL, 0);
}
+
+
+int radeon_vblank_crtc_get(struct drm_device *dev)
+{
+ drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+ u32 flag;
+ u32 value;
+
+ flag = RADEON_READ(RADEON_GEN_INT_CNTL);
+ value = 0;
+
+ if (flag & RADEON_CRTC_VBLANK_MASK)
+ value |= DRM_RADEON_VBLANK_CRTC1;
+
+ if (flag & RADEON_CRTC2_VBLANK_MASK)
+ value |= DRM_RADEON_VBLANK_CRTC2;
+ return value;
+}
+
+int radeon_vblank_crtc_set(struct drm_device *dev, int64_t value)
+{
+ drm_radeon_private_t *dev_priv = (drm_radeon_private_t *) dev->dev_private;
+ if (value & ~(DRM_RADEON_VBLANK_CRTC1 | DRM_RADEON_VBLANK_CRTC2)) {
+ DRM_ERROR("called with invalid crtc 0x%x\n", (unsigned int)value);
+ return DRM_ERR(EINVAL);
+ }
+ dev_priv->vblank_crtc = (unsigned int)value;
+ radeon_enable_interrupt(dev);
+ return 0;
+}
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 98c5f1d3a8e7..3ddf86f2abf0 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -39,7 +39,7 @@
static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
dev_priv,
- drm_file_t * filp_priv,
+ struct drm_file * filp_priv,
u32 *offset)
{
u64 off = *offset;
@@ -90,7 +90,7 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
dev_priv,
- drm_file_t * filp_priv,
+ struct drm_file * filp_priv,
int id, u32 *data)
{
switch (id) {
@@ -264,7 +264,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
dev_priv,
- drm_file_t *filp_priv,
+ struct drm_file *filp_priv,
drm_radeon_kcmd_buffer_t *
cmdbuf,
unsigned int *cmdsz)
@@ -421,7 +421,7 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
*/
static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
- drm_clip_rect_t * box)
+ struct drm_clip_rect * box)
{
RING_LOCALS;
@@ -439,7 +439,7 @@ static __inline__ void radeon_emit_clip_rect(drm_radeon_private_t * dev_priv,
/* Emit 1.1 state
*/
static int radeon_emit_state(drm_radeon_private_t * dev_priv,
- drm_file_t * filp_priv,
+ struct drm_file * filp_priv,
drm_radeon_context_regs_t * ctx,
drm_radeon_texture_regs_t * tex,
unsigned int dirty)
@@ -608,7 +608,7 @@ static int radeon_emit_state(drm_radeon_private_t * dev_priv,
/* Emit 1.2 state
*/
static int radeon_emit_state2(drm_radeon_private_t * dev_priv,
- drm_file_t * filp_priv,
+ struct drm_file * filp_priv,
drm_radeon_state_t * state)
{
RING_LOCALS;
@@ -844,7 +844,7 @@ static void radeon_cp_performance_boxes(drm_radeon_private_t * dev_priv)
* CP command dispatch functions
*/
-static void radeon_cp_dispatch_clear(drm_device_t * dev,
+static void radeon_cp_dispatch_clear(struct drm_device * dev,
drm_radeon_clear_t * clear,
drm_radeon_clear_rect_t * depth_boxes)
{
@@ -852,7 +852,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_radeon_depth_clear_t *depth_clear = &dev_priv->depth_clear;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
unsigned int flags = clear->flags;
u32 rb3d_cntl = 0, rb3d_stencilrefmask = 0;
int i;
@@ -1335,12 +1335,12 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
ADVANCE_RING();
}
-static void radeon_cp_dispatch_swap(drm_device_t * dev)
+static void radeon_cp_dispatch_swap(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
int nbox = sarea_priv->nbox;
- drm_clip_rect_t *pbox = sarea_priv->boxes;
+ struct drm_clip_rect *pbox = sarea_priv->boxes;
int i;
RING_LOCALS;
DRM_DEBUG("\n");
@@ -1412,10 +1412,10 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
ADVANCE_RING();
}
-static void radeon_cp_dispatch_flip(drm_device_t * dev)
+static void radeon_cp_dispatch_flip(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
+ struct drm_sarea *sarea = (struct drm_sarea *) dev_priv->sarea->handle;
int offset = (dev_priv->sarea_priv->pfCurrentPage == 1)
? dev_priv->front_offset : dev_priv->back_offset;
RING_LOCALS;
@@ -1491,8 +1491,8 @@ typedef struct {
unsigned int vc_format;
} drm_radeon_tcl_prim_t;
-static void radeon_cp_dispatch_vertex(drm_device_t * dev,
- drm_buf_t * buf,
+static void radeon_cp_dispatch_vertex(struct drm_device * dev,
+ struct drm_buf * buf,
drm_radeon_tcl_prim_t * prim)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1537,7 +1537,7 @@ static void radeon_cp_dispatch_vertex(drm_device_t * dev,
} while (i < nbox);
}
-static void radeon_cp_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
+static void radeon_cp_discard_buffer(struct drm_device * dev, struct drm_buf * buf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_radeon_buf_priv_t *buf_priv = buf->dev_private;
@@ -1554,8 +1554,8 @@ static void radeon_cp_discard_buffer(drm_device_t * dev, drm_buf_t * buf)
buf->used = 0;
}
-static void radeon_cp_dispatch_indirect(drm_device_t * dev,
- drm_buf_t * buf, int start, int end)
+static void radeon_cp_dispatch_indirect(struct drm_device * dev,
+ struct drm_buf * buf, int start, int end)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -1588,8 +1588,8 @@ static void radeon_cp_dispatch_indirect(drm_device_t * dev,
}
}
-static void radeon_cp_dispatch_indices(drm_device_t * dev,
- drm_buf_t * elt_buf,
+static void radeon_cp_dispatch_indices(struct drm_device * dev,
+ struct drm_buf * elt_buf,
drm_radeon_tcl_prim_t * prim)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -1647,13 +1647,13 @@ static void radeon_cp_dispatch_indices(drm_device_t * dev,
#define RADEON_MAX_TEXTURE_SIZE RADEON_BUFFER_SIZE
static int radeon_cp_dispatch_texture(DRMFILE filp,
- drm_device_t * dev,
+ struct drm_device * dev,
drm_radeon_texture_t * tex,
drm_radeon_tex_image_t * image)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_file_t *filp_priv;
- drm_buf_t *buf;
+ struct drm_file *filp_priv;
+ struct drm_buf *buf;
u32 format;
u32 *buffer;
const u8 __user *data;
@@ -1881,7 +1881,7 @@ static int radeon_cp_dispatch_texture(DRMFILE filp,
return 0;
}
-static void radeon_cp_dispatch_stipple(drm_device_t * dev, u32 * stipple)
+static void radeon_cp_dispatch_stipple(struct drm_device * dev, u32 * stipple)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
int i;
@@ -2134,7 +2134,7 @@ static int radeon_cp_clear(DRM_IOCTL_ARGS)
/* Not sure why this isn't set all the time:
*/
-static int radeon_do_init_pageflip(drm_device_t * dev)
+static int radeon_do_init_pageflip(struct drm_device * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -2206,10 +2206,10 @@ static int radeon_cp_vertex(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_file_t *filp_priv;
+ struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_radeon_vertex_t vertex;
drm_radeon_tcl_prim_t prim;
@@ -2289,10 +2289,10 @@ static int radeon_cp_indices(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_file_t *filp_priv;
+ struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_radeon_indices_t elts;
drm_radeon_tcl_prim_t prim;
int count;
@@ -2438,8 +2438,8 @@ static int radeon_cp_indirect(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_radeon_indirect_t indirect;
RING_LOCALS;
@@ -2507,10 +2507,10 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_file_t *filp_priv;
+ struct drm_file *filp_priv;
drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_radeon_vertex2_t vertex;
int i;
unsigned char laststate;
@@ -2603,7 +2603,7 @@ static int radeon_cp_vertex2(DRM_IOCTL_ARGS)
}
static int radeon_emit_packets(drm_radeon_private_t * dev_priv,
- drm_file_t * filp_priv,
+ struct drm_file * filp_priv,
drm_radeon_cmd_header_t header,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
@@ -2728,8 +2728,8 @@ static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
return 0;
}
-static int radeon_emit_packet3(drm_device_t * dev,
- drm_file_t * filp_priv,
+static int radeon_emit_packet3(struct drm_device * dev,
+ struct drm_file * filp_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -2754,16 +2754,16 @@ static int radeon_emit_packet3(drm_device_t * dev,
return 0;
}
-static int radeon_emit_packet3_cliprect(drm_device_t *dev,
- drm_file_t *filp_priv,
+static int radeon_emit_packet3_cliprect(struct drm_device *dev,
+ struct drm_file *filp_priv,
drm_radeon_kcmd_buffer_t *cmdbuf,
int orig_nbox)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_clip_rect_t box;
+ struct drm_clip_rect box;
unsigned int cmdsz;
int ret;
- drm_clip_rect_t __user *boxes = cmdbuf->boxes;
+ struct drm_clip_rect __user *boxes = cmdbuf->boxes;
int i = 0;
RING_LOCALS;
@@ -2816,7 +2816,7 @@ static int radeon_emit_packet3_cliprect(drm_device_t *dev,
return 0;
}
-static int radeon_emit_wait(drm_device_t * dev, int flags)
+static int radeon_emit_wait(struct drm_device * dev, int flags)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -2849,9 +2849,9 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_file_t *filp_priv;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf = NULL;
+ struct drm_file *filp_priv;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf = NULL;
int idx;
drm_radeon_kcmd_buffer_t cmdbuf;
drm_radeon_cmd_header_t header;
@@ -3085,6 +3085,9 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
else
value = RADEON_CARD_PCI;
break;
+ case RADEON_PARAM_VBLANK_CRTC:
+ value = radeon_vblank_crtc_get(dev);
+ break;
default:
DRM_DEBUG("Invalid parameter %d\n", param.param);
return DRM_ERR(EINVAL);
@@ -3102,7 +3105,7 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_radeon_private_t *dev_priv = dev->dev_private;
- drm_file_t *filp_priv;
+ struct drm_file *filp_priv;
drm_radeon_setparam_t sp;
struct drm_radeon_driver_file_fields *radeon_priv;
@@ -3141,6 +3144,9 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
break;
+ case RADEON_SETPARAM_VBLANK_CRTC:
+ return radeon_vblank_crtc_set(dev, sp.value);
+ break;
default:
DRM_DEBUG("Invalid parameter %d\n", sp.param);
return DRM_ERR(EINVAL);
@@ -3156,7 +3162,7 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
*
* DRM infrastructure takes care of reclaiming dma buffers.
*/
-void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
+void radeon_driver_preclose(struct drm_device *dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -3167,7 +3173,7 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
}
}
-void radeon_driver_lastclose(drm_device_t * dev)
+void radeon_driver_lastclose(struct drm_device *dev)
{
if (dev->dev_private) {
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -3180,7 +3186,7 @@ void radeon_driver_lastclose(drm_device_t * dev)
radeon_do_release(dev);
}
-int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv)
+int radeon_driver_open(struct drm_device *dev, struct drm_file *filp_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
struct drm_radeon_driver_file_fields *radeon_priv;
@@ -3202,7 +3208,7 @@ int radeon_driver_open(drm_device_t * dev, drm_file_t * filp_priv)
return 0;
}
-void radeon_driver_postclose(drm_device_t * dev, drm_file_t * filp_priv)
+void radeon_driver_postclose(struct drm_device *dev, struct drm_file *filp_priv)
{
struct drm_radeon_driver_file_fields *radeon_priv =
filp_priv->driver_priv;
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
index b94fab556809..18c7235f6b73 100644
--- a/drivers/char/drm/savage_bci.c
+++ b/drivers/char/drm/savage_bci.c
@@ -32,7 +32,7 @@
#define SAVAGE_EVENT_USEC_TIMEOUT 5000000 /* 5s */
#define SAVAGE_FREELIST_DEBUG 0
-static int savage_do_cleanup_bci(drm_device_t *dev);
+static int savage_do_cleanup_bci(struct drm_device *dev);
static int
savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
@@ -203,11 +203,11 @@ uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
/*
* Freelist management
*/
-static int savage_freelist_init(drm_device_t * dev)
+static int savage_freelist_init(struct drm_device * dev)
{
drm_savage_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *buf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *buf;
drm_savage_buf_priv_t *entry;
int i;
DRM_DEBUG("count=%d\n", dma->buf_count);
@@ -236,7 +236,7 @@ static int savage_freelist_init(drm_device_t * dev)
return 0;
}
-static drm_buf_t *savage_freelist_get(drm_device_t * dev)
+static struct drm_buf *savage_freelist_get(struct drm_device * dev)
{
drm_savage_private_t *dev_priv = dev->dev_private;
drm_savage_buf_priv_t *tail = dev_priv->tail.prev;
@@ -269,7 +269,7 @@ static drm_buf_t *savage_freelist_get(drm_device_t * dev)
return NULL;
}
-void savage_freelist_put(drm_device_t * dev, drm_buf_t * buf)
+void savage_freelist_put(struct drm_device * dev, struct drm_buf * buf)
{
drm_savage_private_t *dev_priv = dev->dev_private;
drm_savage_buf_priv_t *entry = buf->dev_private, *prev, *next;
@@ -535,7 +535,7 @@ static void savage_fake_dma_flush(drm_savage_private_t * dev_priv)
dev_priv->first_dma_page = dev_priv->current_dma_page = 0;
}
-int savage_driver_load(drm_device_t *dev, unsigned long chipset)
+int savage_driver_load(struct drm_device *dev, unsigned long chipset)
{
drm_savage_private_t *dev_priv;
@@ -558,7 +558,7 @@ int savage_driver_load(drm_device_t *dev, unsigned long chipset)
* in drm_addmap. Therefore we add them manually before the maps are
* initialized, and tear them down on last close.
*/
-int savage_driver_firstopen(drm_device_t *dev)
+int savage_driver_firstopen(struct drm_device *dev)
{
drm_savage_private_t *dev_priv = dev->dev_private;
unsigned long mmio_base, fb_base, fb_size, aperture_base;
@@ -655,7 +655,7 @@ int savage_driver_firstopen(drm_device_t *dev)
/*
* Delete MTRRs and free device-private data.
*/
-void savage_driver_lastclose(drm_device_t *dev)
+void savage_driver_lastclose(struct drm_device *dev)
{
drm_savage_private_t *dev_priv = dev->dev_private;
int i;
@@ -667,7 +667,7 @@ void savage_driver_lastclose(drm_device_t *dev)
dev_priv->mtrr[i].size, DRM_MTRR_WC);
}
-int savage_driver_unload(drm_device_t *dev)
+int savage_driver_unload(struct drm_device *dev)
{
drm_savage_private_t *dev_priv = dev->dev_private;
@@ -676,7 +676,7 @@ int savage_driver_unload(drm_device_t *dev)
return 0;
}
-static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init)
+static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init)
{
drm_savage_private_t *dev_priv = dev->dev_private;
@@ -711,7 +711,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init)
dev_priv->texture_offset = init->texture_offset;
dev_priv->texture_size = init->texture_size;
- DRM_GETSAREA();
+ dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
savage_do_cleanup_bci(dev);
@@ -898,7 +898,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init)
return 0;
}
-static int savage_do_cleanup_bci(drm_device_t * dev)
+static int savage_do_cleanup_bci(struct drm_device * dev)
{
drm_savage_private_t *dev_priv = dev->dev_private;
@@ -1007,9 +1007,9 @@ static int savage_bci_event_wait(DRM_IOCTL_ARGS)
* DMA buffer management
*/
-static int savage_bci_get_buffers(DRMFILE filp, drm_device_t *dev, drm_dma_t *d)
+static int savage_bci_get_buffers(DRMFILE filp, struct drm_device *dev, struct drm_dma *d)
{
- drm_buf_t *buf;
+ struct drm_buf *buf;
int i;
for (i = d->granted_count; i < d->request_count; i++) {
@@ -1034,13 +1034,13 @@ static int savage_bci_get_buffers(DRMFILE filp, drm_device_t *dev, drm_dma_t *d)
int savage_bci_buffers(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_device_dma_t *dma = dev->dma;
- drm_dma_t d;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_dma d;
int ret = 0;
LOCK_TEST_WITH_RETURN(dev, filp);
- DRM_COPY_FROM_USER_IOCTL(d, (drm_dma_t __user *) data, sizeof(d));
+ DRM_COPY_FROM_USER_IOCTL(d, (struct drm_dma __user *) data, sizeof(d));
/* Please don't send us buffers.
*/
@@ -1064,14 +1064,14 @@ int savage_bci_buffers(DRM_IOCTL_ARGS)
ret = savage_bci_get_buffers(filp, dev, &d);
}
- DRM_COPY_TO_USER_IOCTL((drm_dma_t __user *) data, d, sizeof(d));
+ DRM_COPY_TO_USER_IOCTL((struct drm_dma __user *) data, d, sizeof(d));
return ret;
}
-void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp)
+void savage_reclaim_buffers(struct drm_device *dev, DRMFILE filp)
{
- drm_device_dma_t *dma = dev->dma;
+ struct drm_device_dma *dma = dev->dma;
drm_savage_private_t *dev_priv = dev->dev_private;
int i;
@@ -1085,7 +1085,7 @@ void savage_reclaim_buffers(drm_device_t *dev, DRMFILE filp)
/*i830_flush_queue(dev); */
for (i = 0; i < dma->buf_count; i++) {
- drm_buf_t *buf = dma->buflist[i];
+ struct drm_buf *buf = dma->buflist[i];
drm_savage_buf_priv_t *buf_priv = buf->dev_private;
if (buf->filp == filp && buf_priv &&
diff --git a/drivers/char/drm/savage_drm.h b/drivers/char/drm/savage_drm.h
index e1148e8e7994..8a576ef01821 100644
--- a/drivers/char/drm/savage_drm.h
+++ b/drivers/char/drm/savage_drm.h
@@ -47,7 +47,7 @@
typedef struct _drm_savage_sarea {
/* LRU lists for texture memory in agp space and on the card.
*/
- drm_tex_region_t texList[SAVAGE_NR_TEX_HEAPS][SAVAGE_NR_TEX_REGIONS +
+ struct drm_tex_region texList[SAVAGE_NR_TEX_HEAPS][SAVAGE_NR_TEX_REGIONS +
1];
unsigned int texAge[SAVAGE_NR_TEX_HEAPS];
@@ -113,7 +113,7 @@ typedef struct drm_savage_cmdbuf {
unsigned int vb_size; /* size of client vertex buffer in bytes */
unsigned int vb_stride; /* stride of vertices in 32bit words */
/* boxes in client's address space */
- drm_clip_rect_t __user *box_addr;
+ struct drm_clip_rect __user *box_addr;
unsigned int nbox; /* number of clipping boxes */
} drm_savage_cmdbuf_t;
diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h
index 8f04b3d82292..5fd54de4280e 100644
--- a/drivers/char/drm/savage_drv.h
+++ b/drivers/char/drm/savage_drv.h
@@ -58,7 +58,7 @@ typedef struct drm_savage_buf_priv {
struct drm_savage_buf_priv *next;
struct drm_savage_buf_priv *prev;
drm_savage_age_t age;
- drm_buf_t *buf;
+ struct drm_buf *buf;
} drm_savage_buf_priv_t;
typedef struct drm_savage_dma_page {
@@ -192,7 +192,7 @@ typedef struct drm_savage_private {
/* Err, there is a macro wait_event in include/linux/wait.h.
* Avoid unwanted macro expansion. */
void (*emit_clip_rect) (struct drm_savage_private * dev_priv,
- const drm_clip_rect_t * pbox);
+ const struct drm_clip_rect * pbox);
void (*dma_flush) (struct drm_savage_private * dev_priv);
} drm_savage_private_t;
@@ -203,22 +203,22 @@ extern int savage_bci_buffers(DRM_IOCTL_ARGS);
/* BCI functions */
extern uint16_t savage_bci_emit_event(drm_savage_private_t * dev_priv,
unsigned int flags);
-extern void savage_freelist_put(drm_device_t * dev, drm_buf_t * buf);
+extern void savage_freelist_put(struct drm_device * dev, struct drm_buf * buf);
extern void savage_dma_reset(drm_savage_private_t * dev_priv);
extern void savage_dma_wait(drm_savage_private_t * dev_priv, unsigned int page);
extern uint32_t *savage_dma_alloc(drm_savage_private_t * dev_priv,
unsigned int n);
-extern int savage_driver_load(drm_device_t *dev, unsigned long chipset);
-extern int savage_driver_firstopen(drm_device_t *dev);
-extern void savage_driver_lastclose(drm_device_t *dev);
-extern int savage_driver_unload(drm_device_t *dev);
-extern void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp);
+extern int savage_driver_load(struct drm_device *dev, unsigned long chipset);
+extern int savage_driver_firstopen(struct drm_device *dev);
+extern void savage_driver_lastclose(struct drm_device *dev);
+extern int savage_driver_unload(struct drm_device *dev);
+extern void savage_reclaim_buffers(struct drm_device * dev, DRMFILE filp);
/* state functions */
extern void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
- const drm_clip_rect_t * pbox);
+ const struct drm_clip_rect * pbox);
extern void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv,
- const drm_clip_rect_t * pbox);
+ const struct drm_clip_rect * pbox);
#define SAVAGE_FB_SIZE_S3 0x01000000 /* 16MB */
#define SAVAGE_FB_SIZE_S4 0x02000000 /* 32MB */
diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c
index 1ca1e9cb5a33..77497841478a 100644
--- a/drivers/char/drm/savage_state.c
+++ b/drivers/char/drm/savage_state.c
@@ -27,7 +27,7 @@
#include "savage_drv.h"
void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
- const drm_clip_rect_t * pbox)
+ const struct drm_clip_rect * pbox)
{
uint32_t scstart = dev_priv->state.s3d.new_scstart;
uint32_t scend = dev_priv->state.s3d.new_scend;
@@ -53,7 +53,7 @@ void savage_emit_clip_rect_s3d(drm_savage_private_t * dev_priv,
}
void savage_emit_clip_rect_s4(drm_savage_private_t * dev_priv,
- const drm_clip_rect_t * pbox)
+ const struct drm_clip_rect * pbox)
{
uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;
uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;
@@ -277,7 +277,7 @@ static int savage_dispatch_state(drm_savage_private_t * dev_priv,
static int savage_dispatch_dma_prim(drm_savage_private_t * dev_priv,
const drm_savage_cmd_header_t * cmd_header,
- const drm_buf_t * dmabuf)
+ const struct drm_buf * dmabuf)
{
unsigned char reorder = 0;
unsigned int prim = cmd_header->prim.prim;
@@ -536,7 +536,7 @@ static int savage_dispatch_vb_prim(drm_savage_private_t * dev_priv,
static int savage_dispatch_dma_idx(drm_savage_private_t * dev_priv,
const drm_savage_cmd_header_t * cmd_header,
const uint16_t *idx,
- const drm_buf_t * dmabuf)
+ const struct drm_buf * dmabuf)
{
unsigned char reorder = 0;
unsigned int prim = cmd_header->idx.prim;
@@ -792,7 +792,7 @@ static int savage_dispatch_clear(drm_savage_private_t * dev_priv,
const drm_savage_cmd_header_t * cmd_header,
const drm_savage_cmd_header_t *data,
unsigned int nbox,
- const drm_clip_rect_t *boxes)
+ const struct drm_clip_rect *boxes)
{
unsigned int flags = cmd_header->clear0.flags;
unsigned int clear_cmd;
@@ -861,7 +861,7 @@ static int savage_dispatch_clear(drm_savage_private_t * dev_priv,
}
static int savage_dispatch_swap(drm_savage_private_t * dev_priv,
- unsigned int nbox, const drm_clip_rect_t *boxes)
+ unsigned int nbox, const struct drm_clip_rect *boxes)
{
unsigned int swap_cmd;
unsigned int i;
@@ -892,11 +892,11 @@ static int savage_dispatch_swap(drm_savage_private_t * dev_priv,
static int savage_dispatch_draw(drm_savage_private_t * dev_priv,
const drm_savage_cmd_header_t *start,
const drm_savage_cmd_header_t *end,
- const drm_buf_t * dmabuf,
+ const struct drm_buf * dmabuf,
const unsigned int *vtxbuf,
unsigned int vb_size, unsigned int vb_stride,
unsigned int nbox,
- const drm_clip_rect_t *boxes)
+ const struct drm_clip_rect *boxes)
{
unsigned int i, j;
int ret;
@@ -957,13 +957,13 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_savage_private_t *dev_priv = dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- drm_buf_t *dmabuf;
+ struct drm_device_dma *dma = dev->dma;
+ struct drm_buf *dmabuf;
drm_savage_cmdbuf_t cmdbuf;
drm_savage_cmd_header_t *kcmd_addr = NULL;
drm_savage_cmd_header_t *first_draw_cmd;
unsigned int *kvb_addr = NULL;
- drm_clip_rect_t *kbox_addr = NULL;
+ struct drm_clip_rect *kbox_addr = NULL;
unsigned int i, j;
int ret = 0;
@@ -1019,7 +1019,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
cmdbuf.vb_addr = kvb_addr;
}
if (cmdbuf.nbox) {
- kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(drm_clip_rect_t),
+ kbox_addr = drm_alloc(cmdbuf.nbox * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
if (kbox_addr == NULL) {
ret = DRM_ERR(ENOMEM);
@@ -1027,7 +1027,7 @@ int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
}
if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf.box_addr,
- cmdbuf.nbox * sizeof(drm_clip_rect_t))) {
+ cmdbuf.nbox * sizeof(struct drm_clip_rect))) {
ret = DRM_ERR(EFAULT);
goto done;
}
@@ -1158,7 +1158,7 @@ done:
/* If we didn't need to allocate them, these'll be NULL */
drm_free(kcmd_addr, cmdbuf.size * 8, DRM_MEM_DRIVER);
drm_free(kvb_addr, cmdbuf.vb_size, DRM_MEM_DRIVER);
- drm_free(kbox_addr, cmdbuf.nbox * sizeof(drm_clip_rect_t),
+ drm_free(kbox_addr, cmdbuf.nbox * sizeof(struct drm_clip_rect),
DRM_MEM_DRIVER);
return ret;
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 690e0af8e7c2..1912f5857051 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -35,7 +35,7 @@ static struct pci_device_id pciidlist[] = {
sisdrv_PCI_IDS
};
-static int sis_driver_load(drm_device_t *dev, unsigned long chipset)
+static int sis_driver_load(struct drm_device *dev, unsigned long chipset)
{
drm_sis_private_t *dev_priv;
int ret;
@@ -54,7 +54,7 @@ static int sis_driver_load(drm_device_t *dev, unsigned long chipset)
return ret;
}
-static int sis_driver_unload(drm_device_t *dev)
+static int sis_driver_unload(struct drm_device *dev)
{
drm_sis_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h
index 70d4ede75fe8..5630df874353 100644
--- a/drivers/char/drm/sis_drv.h
+++ b/drivers/char/drm/sis_drv.h
@@ -46,6 +46,7 @@ enum sis_family {
#include "drm_sman.h"
+
#define SIS_BASE (dev_priv->mmio)
#define SIS_READ(reg) DRM_READ32(SIS_BASE, reg);
#define SIS_WRITE(reg, val) DRM_WRITE32(SIS_BASE, reg, val);
@@ -53,7 +54,7 @@ enum sis_family {
typedef struct drm_sis_private {
drm_local_map_t *mmio;
unsigned int idle_fault;
- drm_sman_t sman;
+ struct drm_sman sman;
unsigned int chipset;
int vram_initialized;
int agp_initialized;
@@ -61,9 +62,9 @@ typedef struct drm_sis_private {
unsigned long agp_offset;
} drm_sis_private_t;
-extern int sis_idle(drm_device_t *dev);
-extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
-extern void sis_lastclose(drm_device_t *dev);
+extern int sis_idle(struct drm_device *dev);
+extern void sis_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void sis_lastclose(struct drm_device *dev);
extern drm_ioctl_desc_t sis_ioctls[];
extern int sis_max_ioctl;
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
index d26f5dbb7853..441bbdbf1510 100644
--- a/drivers/char/drm/sis_mm.c
+++ b/drivers/char/drm/sis_mm.c
@@ -94,7 +94,7 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
mutex_lock(&dev->struct_mutex);
#if defined(CONFIG_FB_SIS)
{
- drm_sman_mm_t sman_mm;
+ struct drm_sman_mm sman_mm;
sman_mm.private = (void *)0xFFFFFFFF;
sman_mm.allocate = sis_sman_mm_allocate;
sman_mm.free = sis_sman_mm_free;
@@ -123,14 +123,14 @@ static int sis_fb_init(DRM_IOCTL_ARGS)
return 0;
}
-static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
+static int sis_drm_alloc(struct drm_device *dev, struct drm_file * priv,
unsigned long data, int pool)
{
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
drm_sis_mem_t mem;
int retval = 0;
- drm_memblock_item_t *item;
+ struct drm_memblock_item *item;
DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
@@ -229,12 +229,12 @@ static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
return sis_drm_alloc(dev, priv, data, AGP_TYPE);
}
-static drm_local_map_t *sis_reg_init(drm_device_t *dev)
+static drm_local_map_t *sis_reg_init(struct drm_device *dev)
{
- drm_map_list_t *entry;
+ struct drm_map_list *entry;
drm_local_map_t *map;
- list_for_each_entry(entry, &dev->maplist->head, head) {
+ list_for_each_entry(entry, &dev->maplist, head) {
map = entry->map;
if (!map)
continue;
@@ -245,7 +245,7 @@ static drm_local_map_t *sis_reg_init(drm_device_t *dev)
return NULL;
}
-int sis_idle(drm_device_t *dev)
+int sis_idle(struct drm_device *dev)
{
drm_sis_private_t *dev_priv = dev->dev_private;
uint32_t idle_reg;
@@ -314,10 +314,10 @@ void sis_lastclose(struct drm_device *dev)
mutex_unlock(&dev->struct_mutex);
}
-void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+void sis_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
{
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_file_t *priv = filp->private_data;
+ struct drm_file *priv = filp->private_data;
mutex_lock(&dev->struct_mutex);
if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index 13a9c5ca4593..7ff2b623c2d4 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -151,7 +151,7 @@ static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
}
-int via_dma_cleanup(drm_device_t * dev)
+int via_dma_cleanup(struct drm_device * dev)
{
if (dev->dev_private) {
drm_via_private_t *dev_priv =
@@ -169,7 +169,7 @@ int via_dma_cleanup(drm_device_t * dev)
return 0;
}
-static int via_initialize(drm_device_t * dev,
+static int via_initialize(struct drm_device * dev,
drm_via_private_t * dev_priv,
drm_via_dma_init_t * init)
{
@@ -262,7 +262,7 @@ static int via_dma_init(DRM_IOCTL_ARGS)
return retcode;
}
-static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
+static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * cmd)
{
drm_via_private_t *dev_priv;
uint32_t *vb;
@@ -316,7 +316,7 @@ static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
return 0;
}
-int via_driver_dma_quiescent(drm_device_t * dev)
+int via_driver_dma_quiescent(struct drm_device * dev)
{
drm_via_private_t *dev_priv = dev->dev_private;
@@ -356,7 +356,7 @@ static int via_cmdbuffer(DRM_IOCTL_ARGS)
return 0;
}
-static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
+static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
drm_via_cmdbuffer_t * cmd)
{
drm_via_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 2881a06b6f55..832de1d9ba7e 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -207,7 +207,7 @@ via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
*/
static void
-via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine)
+via_fire_dmablit(struct drm_device *dev, drm_via_sg_info_t *vsg, int engine)
{
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
@@ -273,10 +273,9 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) /
vsg->descriptors_per_page;
- if (NULL == (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL)))
+ if (NULL == (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
return DRM_ERR(ENOMEM);
- memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages);
vsg->state = dr_via_desc_pages_alloc;
for (i=0; i<vsg->num_desc_pages; ++i) {
if (NULL == (vsg->desc_pages[i] =
@@ -289,7 +288,7 @@ via_alloc_desc_pages(drm_via_sg_info_t *vsg)
}
static void
-via_abort_dmablit(drm_device_t *dev, int engine)
+via_abort_dmablit(struct drm_device *dev, int engine)
{
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
@@ -297,7 +296,7 @@ via_abort_dmablit(drm_device_t *dev, int engine)
}
static void
-via_dmablit_engine_off(drm_device_t *dev, int engine)
+via_dmablit_engine_off(struct drm_device *dev, int engine)
{
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
@@ -314,7 +313,7 @@ via_dmablit_engine_off(drm_device_t *dev, int engine)
*/
void
-via_dmablit_handler(drm_device_t *dev, int engine, int from_irq)
+via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
{
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
drm_via_blitq_t *blitq = dev_priv->blit_queues + engine;
@@ -433,7 +432,7 @@ via_dmablit_active(drm_via_blitq_t *blitq, int engine, uint32_t handle, wait_que
*/
static int
-via_dmablit_sync(drm_device_t *dev, uint32_t handle, int engine)
+via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine)
{
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
@@ -466,7 +465,7 @@ static void
via_dmablit_timer(unsigned long data)
{
drm_via_blitq_t *blitq = (drm_via_blitq_t *) data;
- drm_device_t *dev = blitq->dev;
+ struct drm_device *dev = blitq->dev;
int engine = (int)
(blitq - ((drm_via_private_t *)dev->dev_private)->blit_queues);
@@ -502,7 +501,7 @@ static void
via_dmablit_workqueue(struct work_struct *work)
{
drm_via_blitq_t *blitq = container_of(work, drm_via_blitq_t, wq);
- drm_device_t *dev = blitq->dev;
+ struct drm_device *dev = blitq->dev;
unsigned long irqsave;
drm_via_sg_info_t *cur_sg;
int cur_released;
@@ -545,7 +544,7 @@ via_dmablit_workqueue(struct work_struct *work)
void
-via_init_dmablit(drm_device_t *dev)
+via_init_dmablit(struct drm_device *dev)
{
int i,j;
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
@@ -582,7 +581,7 @@ via_init_dmablit(drm_device_t *dev)
static int
-via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
+via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
{
int draw = xfer->to_fb;
int ret = 0;
@@ -730,7 +729,7 @@ via_dmablit_release_slot(drm_via_blitq_t *blitq)
static int
-via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer)
+via_dmablit(struct drm_device *dev, drm_via_dmablit_t *xfer)
{
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
drm_via_sg_info_t *vsg;
diff --git a/drivers/char/drm/via_dmablit.h b/drivers/char/drm/via_dmablit.h
index f4036cd5d0e0..6f6a513d5147 100644
--- a/drivers/char/drm/via_dmablit.h
+++ b/drivers/char/drm/via_dmablit.h
@@ -59,7 +59,7 @@ typedef struct _drm_via_sg_info {
} drm_via_sg_info_t;
typedef struct _drm_via_blitq {
- drm_device_t *dev;
+ struct drm_device *dev;
uint32_t cur_blit_handle;
uint32_t done_blit_handle;
unsigned serviced;
diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h
index e4ee97d7156f..8f53c76062e9 100644
--- a/drivers/char/drm/via_drm.h
+++ b/drivers/char/drm/via_drm.h
@@ -40,7 +40,7 @@
#define VIA_NR_XVMC_LOCKS 5
#define VIA_MAX_CACHELINE_SIZE 64
#define XVMCLOCKPTR(saPriv,lockNo) \
- ((volatile drm_hw_lock_t *)(((((unsigned long) (saPriv)->XvMCLockArea) + \
+ ((volatile struct drm_hw_lock *)(((((unsigned long) (saPriv)->XvMCLockArea) + \
(VIA_MAX_CACHELINE_SIZE - 1)) & \
~(VIA_MAX_CACHELINE_SIZE - 1)) + \
VIA_MAX_CACHELINE_SIZE*(lockNo)))
@@ -182,7 +182,7 @@ typedef struct _drm_via_tex_region {
typedef struct _drm_via_sarea {
unsigned int dirty;
unsigned int nbox;
- drm_clip_rect_t boxes[VIA_NR_SAREA_CLIPRECTS];
+ struct drm_clip_rect boxes[VIA_NR_SAREA_CLIPRECTS];
drm_via_tex_region_t texList[VIA_NR_TEX_REGIONS + 1];
int texAge; /* last time texture was uploaded */
int ctxOwner; /* last context to upload state */
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index b46ca8e6306d..576711564a11 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -87,7 +87,7 @@ typedef struct drm_via_private {
uint32_t irq_pending_mask;
int *irq_map;
unsigned int idle_fault;
- drm_sman_t sman;
+ struct drm_sman sman;
int vram_initialized;
int agp_initialized;
unsigned long vram_offset;
@@ -123,31 +123,31 @@ extern int via_wait_irq(DRM_IOCTL_ARGS);
extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
extern int via_dma_blit( DRM_IOCTL_ARGS );
-extern int via_driver_load(drm_device_t *dev, unsigned long chipset);
-extern int via_driver_unload(drm_device_t *dev);
+extern int via_driver_load(struct drm_device *dev, unsigned long chipset);
+extern int via_driver_unload(struct drm_device *dev);
-extern int via_init_context(drm_device_t * dev, int context);
-extern int via_final_context(drm_device_t * dev, int context);
+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(drm_device_t * dev);
-extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+extern int via_do_cleanup_map(struct drm_device * dev);
+extern int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence);
extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
-extern void via_driver_irq_preinstall(drm_device_t * dev);
-extern void via_driver_irq_postinstall(drm_device_t * dev);
-extern void via_driver_irq_uninstall(drm_device_t * dev);
+extern void via_driver_irq_preinstall(struct drm_device * dev);
+extern void via_driver_irq_postinstall(struct drm_device * dev);
+extern void via_driver_irq_uninstall(struct drm_device * dev);
-extern int via_dma_cleanup(drm_device_t * dev);
+extern int via_dma_cleanup(struct drm_device * dev);
extern void via_init_command_verifier(void);
-extern int via_driver_dma_quiescent(drm_device_t * dev);
+extern int via_driver_dma_quiescent(struct drm_device * dev);
extern void via_init_futex(drm_via_private_t * dev_priv);
extern void via_cleanup_futex(drm_via_private_t * dev_priv);
extern void via_release_futex(drm_via_private_t * dev_priv, int context);
-extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
-extern void via_lastclose(drm_device_t *dev);
+extern void via_reclaim_buffers_locked(struct drm_device *dev, struct file *filp);
+extern void via_lastclose(struct drm_device *dev);
-extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
-extern void via_init_dmablit(drm_device_t *dev);
+extern void via_dmablit_handler(struct drm_device *dev, int engine, int from_irq);
+extern void via_init_dmablit(struct drm_device *dev);
#endif
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index 1ac5941ad237..8dc99b5fbab6 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -98,7 +98,7 @@ static unsigned time_diff(struct timeval *now, struct timeval *then)
irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
{
- drm_device_t *dev = (drm_device_t *) arg;
+ struct drm_device *dev = (struct drm_device *) arg;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
int handled = 0;
@@ -163,7 +163,7 @@ static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
}
}
-int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+int via_driver_vblank_wait(struct drm_device * dev, unsigned int *sequence)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
unsigned int cur_vblank;
@@ -191,7 +191,7 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
}
static int
-via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
+via_driver_irq_wait(struct drm_device * dev, unsigned int irq, int force_sequence,
unsigned int *sequence)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -244,7 +244,7 @@ via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
* drm_dma.h hooks
*/
-void via_driver_irq_preinstall(drm_device_t * dev)
+void via_driver_irq_preinstall(struct drm_device * dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
@@ -293,7 +293,7 @@ void via_driver_irq_preinstall(drm_device_t * dev)
}
}
-void via_driver_irq_postinstall(drm_device_t * dev)
+void via_driver_irq_postinstall(struct drm_device * dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
@@ -312,7 +312,7 @@ void via_driver_irq_postinstall(drm_device_t * dev)
}
}
-void via_driver_irq_uninstall(drm_device_t * dev)
+void via_driver_irq_uninstall(struct drm_device * dev)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
u32 status;
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index 4e3fc072aa3b..7fb9d2a2cce2 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -25,13 +25,13 @@
#include "via_drm.h"
#include "via_drv.h"
-static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
+static int via_do_init_map(struct drm_device * dev, drm_via_init_t * init)
{
drm_via_private_t *dev_priv = dev->dev_private;
DRM_DEBUG("%s\n", __FUNCTION__);
- DRM_GETSAREA();
+ dev_priv->sarea = drm_getsarea(dev);
if (!dev_priv->sarea) {
DRM_ERROR("could not find sarea!\n");
dev->dev_private = (void *)dev_priv;
@@ -68,7 +68,7 @@ static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
return 0;
}
-int via_do_cleanup_map(drm_device_t * dev)
+int via_do_cleanup_map(struct drm_device * dev)
{
via_dma_cleanup(dev);
@@ -95,7 +95,7 @@ int via_map_init(DRM_IOCTL_ARGS)
return -EINVAL;
}
-int via_driver_load(drm_device_t *dev, unsigned long chipset)
+int via_driver_load(struct drm_device *dev, unsigned long chipset)
{
drm_via_private_t *dev_priv;
int ret = 0;
@@ -115,7 +115,7 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
return ret;
}
-int via_driver_unload(drm_device_t *dev)
+int via_driver_unload(struct drm_device *dev)
{
drm_via_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
index 2fcf0577a7aa..85d56acd9d82 100644
--- a/drivers/char/drm/via_mm.c
+++ b/drivers/char/drm/via_mm.c
@@ -127,7 +127,7 @@ int via_mem_alloc(DRM_IOCTL_ARGS)
drm_via_mem_t mem;
int retval = 0;
- drm_memblock_item_t *item;
+ struct drm_memblock_item *item;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
unsigned long tmpSize;
@@ -188,10 +188,10 @@ int via_mem_free(DRM_IOCTL_ARGS)
}
-void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
+void via_reclaim_buffers_locked(struct drm_device * dev, struct file *filp)
{
drm_via_private_t *dev_priv = dev->dev_private;
- drm_file_t *priv = filp->private_data;
+ struct drm_file *priv = filp->private_data;
mutex_lock(&dev->struct_mutex);
if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
index 2e7e08078287..832d48356e91 100644
--- a/drivers/char/drm/via_verifier.c
+++ b/drivers/char/drm/via_verifier.c
@@ -252,10 +252,9 @@ eat_words(const uint32_t ** buf, const uint32_t * buf_end, unsigned num_words)
static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq,
unsigned long offset,
unsigned long size,
- drm_device_t * dev)
+ struct drm_device * dev)
{
- struct list_head *list;
- drm_map_list_t *r_list;
+ struct drm_map_list *r_list;
drm_local_map_t *map = seq->map_cache;
if (map && map->offset <= offset
@@ -263,8 +262,7 @@ static __inline__ drm_local_map_t *via_drm_lookup_agp_map(drm_via_state_t *seq,
return map;
}
- list_for_each(list, &dev->maplist->head) {
- r_list = (drm_map_list_t *) list;
+ list_for_each_entry(r_list, &dev->maplist, head) {
map = r_list->map;
if (!map)
continue;
@@ -964,7 +962,7 @@ via_parse_vheader6(drm_via_private_t * dev_priv, uint32_t const **buffer,
int
via_verify_command_stream(const uint32_t * buf, unsigned int size,
- drm_device_t * dev, int agp)
+ struct drm_device * dev, int agp)
{
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -1039,7 +1037,7 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
}
int
-via_parse_command_stream(drm_device_t * dev, const uint32_t * buf,
+via_parse_command_stream(struct drm_device * dev, const uint32_t * buf,
unsigned int size)
{
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
index b77f59df0278..28b50296a7bd 100644
--- a/drivers/char/drm/via_verifier.h
+++ b/drivers/char/drm/via_verifier.h
@@ -47,7 +47,7 @@ typedef struct {
drm_via_sequence_t unfinished;
int agp_texture;
int multitex;
- drm_device_t *dev;
+ struct drm_device *dev;
drm_local_map_t *map_cache;
uint32_t vertex_count;
int agp;
@@ -55,8 +55,8 @@ typedef struct {
} drm_via_state_t;
extern int via_verify_command_stream(const uint32_t * buf, unsigned int size,
- drm_device_t * dev, int agp);
-extern int via_parse_command_stream(drm_device_t *dev, const uint32_t *buf,
+ struct drm_device * dev, int agp);
+extern int via_parse_command_stream(struct drm_device *dev, const uint32_t *buf,
unsigned int size);
#endif
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index d1bfbaa2aa02..2e7ae42a5503 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -1121,8 +1121,6 @@ static void change_speed(struct esp_struct *info)
/*
* Set up parity check flag
*/
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (I_INPCK(info->tty))
info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
@@ -1920,11 +1918,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
struct esp_struct *info = (struct esp_struct *)tty->driver_data;
unsigned long flags;
- if ( (tty->termios->c_cflag == old_termios->c_cflag)
- && ( RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
-
change_speed(info);
spin_lock_irqsave(&info->lock, flags);
@@ -2466,7 +2459,7 @@ static int __init espserial_init(void)
return 1;
}
- info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+ info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
if (!info)
{
@@ -2476,7 +2469,6 @@ static int __init espserial_init(void)
return 1;
}
- memset((void *)info, 0, sizeof(struct esp_struct));
spin_lock_init(&info->lock);
/* rx_trigger, tx_trigger are needed by autoconfig */
info->config.rx_trigger = rx_trigger;
@@ -2534,7 +2526,7 @@ static int __init espserial_init(void)
if (!dma)
info->stat_flags |= ESP_STAT_NEVER_DMA;
- info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+ info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
if (!info)
{
printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
@@ -2543,7 +2535,6 @@ static int __init espserial_init(void)
return 0;
}
- memset((void *)info, 0, sizeof(struct esp_struct));
/* rx_trigger, tx_trigger are needed by autoconfig */
info->config.rx_trigger = rx_trigger;
info->config.tx_trigger = tx_trigger;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 8ea02755b1c9..8facf3e25c49 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -43,16 +43,6 @@ static int gs_debug;
#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__)
#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__)
-#define NEW_WRITE_LOCKING 1
-#if NEW_WRITE_LOCKING
-#define DECL /* Nothing */
-#define LOCKIT mutex_lock(& port->port_write_mutex);
-#define RELEASEIT mutex_unlock(&port->port_write_mutex);
-#else
-#define DECL unsigned long flags;
-#define LOCKIT save_flags (flags);cli ()
-#define RELEASEIT restore_flags (flags)
-#endif
#define RS_EVENT_WRITE_WAKEUP 1
@@ -62,7 +52,6 @@ module_param(gs_debug, int, 0644);
void gs_put_char(struct tty_struct * tty, unsigned char ch)
{
struct gs_port *port;
- DECL
func_enter ();
@@ -75,11 +64,11 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch)
if (! (port->flags & ASYNC_INITIALIZED)) return;
/* Take a lock on the serial tranmit buffer! */
- LOCKIT;
+ mutex_lock(& port->port_write_mutex);
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
/* Sorry, buffer is full, drop character. Update statistics???? -- REW */
- RELEASEIT;
+ mutex_unlock(&port->port_write_mutex);
return;
}
@@ -87,13 +76,11 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch)
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++; /* Characters in buffer */
- RELEASEIT;
+ mutex_unlock(&port->port_write_mutex);
func_exit ();
}
-#ifdef NEW_WRITE_LOCKING
-
/*
> Problems to take into account are:
> -1- Interrupts that empty part of the buffer.
@@ -166,90 +153,6 @@ int gs_write(struct tty_struct * tty,
func_exit ();
return total;
}
-#else
-/*
-> Problems to take into account are:
-> -1- Interrupts that empty part of the buffer.
-> -2- page faults on the access to userspace.
-> -3- Other processes that are also trying to do a "write".
-*/
-
-int gs_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- struct gs_port *port;
- int c, total = 0;
- int t;
- unsigned long flags;
-
- func_enter ();
-
- /* The standard serial driver returns 0 in this case.
- That sounds to me as "No error, I just didn't get to writing any
- bytes. Feel free to try again."
- The "official" way to write n bytes from buf is:
-
- for (nwritten = 0;nwritten < n;nwritten += rv) {
- rv = write (fd, buf+nwritten, n-nwritten);
- if (rv < 0) break; // Error: bail out. //
- }
-
- which will loop endlessly in this case. The manual page for write
- agrees with me. In practise almost everybody writes
- "write (fd, buf,n);" but some people might have had to deal with
- incomplete writes in the past and correctly implemented it by now...
- */
-
- if (!tty) return -EIO;
-
- port = tty->driver_data;
- if (!port || !port->xmit_buf)
- return -EIO;
-
- local_save_flags(flags);
- while (1) {
- cli();
- c = count;
-
- /* This is safe because we "OWN" the "head". Noone else can
- change the "head": we own the port_write_mutex. */
- /* Don't overrun the end of the buffer */
- t = SERIAL_XMIT_SIZE - port->xmit_head;
- if (t < c) c = t;
-
- /* This is safe because the xmit_cnt can only decrease. This
- would increase "t", so we might copy too little chars. */
- /* Don't copy past the "head" of the buffer */
- t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
- if (t < c) c = t;
-
- /* Can't copy more? break out! */
- if (c <= 0) {
- local_restore_flags(flags);
- break;
- }
- memcpy(port->xmit_buf + port->xmit_head, buf, c);
- port->xmit_head = ((port->xmit_head + c) &
- (SERIAL_XMIT_SIZE-1));
- port->xmit_cnt += c;
- local_restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
- }
-
- if (port->xmit_cnt &&
- !tty->stopped &&
- !tty->hw_stopped &&
- !(port->flags & GS_TX_INTEN)) {
- port->flags |= GS_TX_INTEN;
- port->rd->enable_tx_interrupts (port);
- }
- func_exit ();
- return total;
-}
-
-#endif
@@ -737,23 +640,6 @@ void gs_set_termios (struct tty_struct * tty,
gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
}
- /* This is an optimization that is only allowed for dumb cards */
- /* Smart cards require knowledge of iflags and oflags too: that
- might change hardware cooking mode.... */
- if (old_termios) {
- if( (tiosp->c_iflag == old_termios->c_iflag)
- && (tiosp->c_oflag == old_termios->c_oflag)
- && (tiosp->c_cflag == old_termios->c_cflag)
- && (tiosp->c_lflag == old_termios->c_lflag)
- && (tiosp->c_line == old_termios->c_line)
- && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) {
- gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n");
- return /* 0 */;
- }
- } else
- gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: "
- "no optimization\n");
-
if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) {
if(tiosp->c_iflag != old_termios->c_iflag) printk("c_iflag changed\n");
if(tiosp->c_oflag != old_termios->c_oflag) printk("c_oflag changed\n");
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 9e1fc02967ff..69f0a2993af0 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -173,7 +173,6 @@ static void gen_rtc_interrupt(unsigned long arg)
static ssize_t gen_rtc_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- DECLARE_WAITQUEUE(wait, current);
unsigned long data;
ssize_t retval;
@@ -183,18 +182,10 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf,
if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
return -EAGAIN;
- add_wait_queue(&gen_rtc_wait, &wait);
- retval = -ERESTARTSYS;
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- data = xchg(&gen_rtc_irq_data, 0);
- if (data)
- break;
- if (signal_pending(current))
- goto out;
- schedule();
- }
+ retval = wait_event_interruptible(gen_rtc_wait,
+ (data = xchg(&gen_rtc_irq_data, 0)));
+ if (retval)
+ goto out;
/* first test allows optimizer to nuke this case for 32-bit machines */
if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) {
@@ -206,10 +197,7 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf,
retval = put_user(data, (unsigned long __user *)buf) ?:
sizeof(unsigned long);
}
- out:
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&gen_rtc_wait, &wait);
-
+out:
return retval;
}
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0be700f4e8fd..ba0e74ad74bb 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -29,6 +29,7 @@
#include <linux/bcd.h>
#include <linux/seq_file.h>
#include <linux/bitops.h>
+#include <linux/clocksource.h>
#include <asm/current.h>
#include <asm/uaccess.h>
@@ -51,8 +52,34 @@
#define HPET_RANGE_SIZE 1024 /* from HPET spec */
+#if BITS_PER_LONG == 64
+#define write_counter(V, MC) writeq(V, MC)
+#define read_counter(MC) readq(MC)
+#else
+#define write_counter(V, MC) writel(V, MC)
+#define read_counter(MC) readl(MC)
+#endif
+
static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
+static void __iomem *hpet_mctr;
+
+static cycle_t read_hpet(void)
+{
+ return (cycle_t)read_counter((void __iomem *)hpet_mctr);
+}
+
+static struct clocksource clocksource_hpet = {
+ .name = "hpet",
+ .rating = 250,
+ .read = read_hpet,
+ .mask = 0xffffffffffffffff,
+ .mult = 0, /*to be caluclated*/
+ .shift = 10,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+static struct clocksource *hpet_clocksource;
+
/* A lock for concurrent access by app and isr hpet activity. */
static DEFINE_SPINLOCK(hpet_lock);
/* A lock for concurrent intermodule access to hpet and isr hpet activity. */
@@ -79,7 +106,7 @@ struct hpets {
struct hpets *hp_next;
struct hpet __iomem *hp_hpet;
unsigned long hp_hpet_phys;
- struct time_interpolator *hp_interpolator;
+ struct clocksource *hp_clocksource;
unsigned long long hp_tick_freq;
unsigned long hp_delta;
unsigned int hp_ntimer;
@@ -94,13 +121,6 @@ static struct hpets *hpets;
#define HPET_PERIODIC 0x0004
#define HPET_SHARED_IRQ 0x0008
-#if BITS_PER_LONG == 64
-#define write_counter(V, MC) writeq(V, MC)
-#define read_counter(MC) readq(MC)
-#else
-#define write_counter(V, MC) writel(V, MC)
-#define read_counter(MC) readl(MC)
-#endif
#ifndef readq
static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +757,6 @@ static ctl_table dev_root[] = {
static struct ctl_table_header *sysctl_header;
-static void hpet_register_interpolator(struct hpets *hpetp)
-{
-#ifdef CONFIG_TIME_INTERPOLATION
- struct time_interpolator *ti;
-
- ti = kzalloc(sizeof(*ti), GFP_KERNEL);
- if (!ti)
- return;
-
- ti->source = TIME_SOURCE_MMIO64;
- ti->shift = 10;
- ti->addr = &hpetp->hp_hpet->hpet_mc;
- ti->frequency = hpetp->hp_tick_freq;
- ti->drift = HPET_DRIFT;
- ti->mask = -1;
-
- hpetp->hp_interpolator = ti;
- register_time_interpolator(ti);
-#endif
-}
-
/*
* Adjustment for when arming the timer with
* initial conditions. That is, main counter
@@ -909,7 +908,16 @@ int hpet_alloc(struct hpet_data *hdp)
}
hpetp->hp_delta = hpet_calibrate(hpetp);
- hpet_register_interpolator(hpetp);
+
+ if (!hpet_clocksource) {
+ hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
+ CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
+ clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
+ clocksource_hpet.shift);
+ clocksource_register(&clocksource_hpet);
+ hpetp->hp_clocksource = &clocksource_hpet;
+ hpet_clocksource = &clocksource_hpet;
+ }
return 0;
}
@@ -995,7 +1003,7 @@ static int hpet_acpi_add(struct acpi_device *device)
static int hpet_acpi_remove(struct acpi_device *device, int type)
{
- /* XXX need to unregister interpolator, dealloc mem, etc */
+ /* XXX need to unregister clocksource, dealloc mem, etc */
return -EINVAL;
}
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 322bc5f7d86b..83c1151ec7a2 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -674,11 +674,12 @@ static const cpumask_t cpus_in_xmon = CPU_MASK_NONE;
* calling hvc_poll() who determines whether a console adapter support
* interrupts.
*/
-int khvcd(void *unused)
+static int khvcd(void *unused)
{
int poll_mask;
struct hvc_struct *hp;
+ set_freezable();
__set_current_state(TASK_RUNNING);
do {
poll_mask = 0;
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b37f1d5a5be6..a08f8f981c11 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -472,7 +472,7 @@ static void hvc_handle_event(struct HvLpEvent *event)
}
}
-static int send_open(HvLpIndex remoteLp, void *sem)
+static int __init send_open(HvLpIndex remoteLp, void *sem)
{
return HvCallEvent_signalLpEventFast(remoteLp,
HvLpEvent_Type_VirtualIo,
@@ -484,7 +484,7 @@ static int send_open(HvLpIndex remoteLp, void *sem)
0, 0, 0, 0);
}
-static int hvc_vio_init(void)
+static int __init hvc_vio_init(void)
{
atomic_t wait_flag;
int rc;
@@ -552,14 +552,14 @@ static int hvc_vio_init(void)
}
module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
-static void hvc_vio_exit(void)
+static void __exit hvc_vio_exit(void)
{
vio_unregister_driver(&hvc_vio_driver);
}
module_exit(hvc_vio_exit);
/* the device tree order defines our numbering */
-static int hvc_find_vtys(void)
+static int __init hvc_find_vtys(void)
{
struct device_node *vty;
int num_found = 0;
diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c
new file mode 100644
index 000000000000..e7b889e404a7
--- /dev/null
+++ b/drivers/char/hvc_lguest.c
@@ -0,0 +1,102 @@
+/* Simple console for lguest.
+ *
+ * Copyright (C) 2006 Rusty Russell, 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 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/err.h>
+#include <linux/init.h>
+#include <linux/lguest_bus.h>
+#include "hvc_console.h"
+
+static char inbuf[256];
+static struct lguest_dma cons_input = { .used_len = 0,
+ .addr[0] = __pa(inbuf),
+ .len[0] = sizeof(inbuf),
+ .len[1] = 0 };
+
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+ struct lguest_dma dma;
+
+ /* FIXME: what if it's over a page boundary? */
+ dma.len[0] = count;
+ dma.len[1] = 0;
+ dma.addr[0] = __pa(buf);
+
+ lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma);
+ return count;
+}
+
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+ static int cons_offset;
+
+ if (!cons_input.used_len)
+ return 0;
+
+ if (cons_input.used_len - cons_offset < count)
+ count = cons_input.used_len - cons_offset;
+
+ memcpy(buf, inbuf + cons_offset, count);
+ cons_offset += count;
+ if (cons_offset == cons_input.used_len) {
+ cons_offset = 0;
+ cons_input.used_len = 0;
+ }
+ return count;
+}
+
+static struct hv_ops lguest_cons = {
+ .get_chars = get_chars,
+ .put_chars = put_chars,
+};
+
+static int __init cons_init(void)
+{
+ if (strcmp(paravirt_ops.name, "lguest") != 0)
+ return 0;
+
+ return hvc_instantiate(0, 0, &lguest_cons);
+}
+console_initcall(cons_init);
+
+static int lguestcons_probe(struct lguest_device *lgdev)
+{
+ int err;
+
+ lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256);
+ if (IS_ERR(lgdev->private))
+ return PTR_ERR(lgdev->private);
+
+ err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1,
+ lgdev_irq(lgdev));
+ if (err)
+ printk("lguest console: failed to bind buffer.\n");
+ return err;
+}
+
+static struct lguest_driver lguestcons_drv = {
+ .name = "lguestcons",
+ .owner = THIS_MODULE,
+ .device_type = LGUEST_DEVICE_T_CONSOLE,
+ .probe = lguestcons_probe,
+};
+
+static int __init hvc_lguest_init(void)
+{
+ return register_lguest_driver(&lguestcons_drv);
+}
+module_init(hvc_lguest_init);
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 4b97eaf18602..bb09413d5a21 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -115,7 +115,7 @@ static void __exit hvc_rtas_exit(void)
module_exit(hvc_rtas_exit);
/* This will happen prior to module init. There is no tty at this time? */
-static int hvc_rtas_console_init(void)
+static int __init hvc_rtas_console_init(void)
{
rtascons_put_char_token = rtas_token("put-term-char");
if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
new file mode 100644
index 000000000000..dd68f8541c2d
--- /dev/null
+++ b/drivers/char/hvc_xen.c
@@ -0,0 +1,159 @@
+/*
+ * xen console driver interface to hvc_console.c
+ *
+ * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
+ *
+ * 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/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/xen/hypervisor.h>
+#include <xen/page.h>
+#include <xen/events.h>
+#include <xen/interface/io/console.h>
+#include <xen/hvc-console.h>
+
+#include "hvc_console.h"
+
+#define HVC_COOKIE 0x58656e /* "Xen" in hex */
+
+static struct hvc_struct *hvc;
+static int xencons_irq;
+
+/* ------------------------------------------------------------------ */
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+ return mfn_to_virt(xen_start_info->console.domU.mfn);
+}
+
+static inline void notify_daemon(void)
+{
+ /* Use evtchn: this is called early, before irq is set up. */
+ notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+}
+
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+ struct xencons_interface *intf = xencons_interface();
+ XENCONS_RING_IDX cons, prod;
+ int sent = 0;
+
+ cons = intf->out_cons;
+ prod = intf->out_prod;
+ mb(); /* update queue values before going on */
+ BUG_ON((prod - cons) > sizeof(intf->out));
+
+ while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+ intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+ wmb(); /* write ring before updating pointer */
+ intf->out_prod = prod;
+
+ notify_daemon();
+ return sent;
+}
+
+static int read_console(uint32_t vtermno, char *buf, int len)
+{
+ struct xencons_interface *intf = xencons_interface();
+ XENCONS_RING_IDX cons, prod;
+ int recv = 0;
+
+ cons = intf->in_cons;
+ prod = intf->in_prod;
+ mb(); /* get pointers before reading ring */
+ BUG_ON((prod - cons) > sizeof(intf->in));
+
+ while (cons != prod && recv < len)
+ buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
+
+ mb(); /* read ring before consuming */
+ intf->in_cons = cons;
+
+ notify_daemon();
+ return recv;
+}
+
+static struct hv_ops hvc_ops = {
+ .get_chars = read_console,
+ .put_chars = write_console,
+};
+
+static int __init xen_init(void)
+{
+ struct hvc_struct *hp;
+
+ if (!is_running_on_xen())
+ return 0;
+
+ xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+ if (xencons_irq < 0)
+ xencons_irq = 0 /* NO_IRQ */;
+ hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+
+ hvc = hp;
+ return 0;
+}
+
+static void __exit xen_fini(void)
+{
+ if (hvc)
+ hvc_remove(hvc);
+}
+
+static int xen_cons_init(void)
+{
+ if (!is_running_on_xen())
+ return 0;
+
+ hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
+ return 0;
+}
+
+module_init(xen_init);
+module_exit(xen_fini);
+console_initcall(xen_cons_init);
+
+static void xenboot_write_console(struct console *console, const char *string,
+ unsigned len)
+{
+ unsigned int linelen, off = 0;
+ const char *pos;
+
+ while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
+ linelen = pos-string+off;
+ if (off + linelen > len)
+ break;
+ write_console(0, string+off, linelen);
+ write_console(0, "\r\n", 2);
+ off += linelen + 1;
+ }
+ if (off < len)
+ write_console(0, string+off, len-off);
+}
+
+struct console xenboot_console = {
+ .name = "xenboot",
+ .write = xenboot_write_console,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+};
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 207f7343ba60..69d8866de783 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -210,9 +210,9 @@ static struct ktermios hvcs_tty_termios = {
static int hvcs_parm_num_devs = -1;
module_param(hvcs_parm_num_devs, int, 0);
-char hvcs_driver_name[] = "hvcs";
-char hvcs_device_node[] = "hvcs";
-char hvcs_driver_string[]
+static const char hvcs_driver_name[] = "hvcs";
+static const char hvcs_device_node[] = "hvcs";
+static const char hvcs_driver_string[]
= "IBM hvcs (Hypervisor Virtual Console Server) Driver";
/* Status of partner info rescan triggered via sysfs. */
@@ -784,12 +784,10 @@ static int __devinit hvcs_probe(
return -EFAULT;
}
- hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL);
+ hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
if (!hvcsd)
return -ENODEV;
- /* hvcsd->tty is zeroed out with the memset */
- memset(hvcsd, 0x00, sizeof(*hvcsd));
spin_lock_init(&hvcsd->lock);
/* Automatically incs the refcount the first time */
@@ -1094,7 +1092,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
* NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
* calling this function or you will get deadlock.
*/
-struct hvcs_struct *hvcs_get_by_index(int index)
+static struct hvcs_struct *hvcs_get_by_index(int index)
{
struct hvcs_struct *hvcsd = NULL;
unsigned long flags;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 7cda04b33534..2d7cd486e025 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -41,7 +41,7 @@ config HW_RANDOM_AMD
config HW_RANDOM_GEODE
tristate "AMD Geode HW Random Number Generator support"
- depends on HW_RANDOM && X86 && PCI
+ depends on HW_RANDOM && X86_32 && PCI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 4ae9811d1a6c..753f46052b87 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -296,12 +296,10 @@ static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
(BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
== BIOS_CNTL_LOCK_ENABLE_MASK) {
static __initdata /*const*/ char warning[] =
- KERN_WARNING PFX "Firmware space is locked read-only. "
- KERN_WARNING PFX "If you can't or\n don't want to "
- KERN_WARNING PFX "disable this in firmware setup, and "
- KERN_WARNING PFX "if\n you are certain that your "
- KERN_WARNING PFX "system has a functional\n RNG, try"
- KERN_WARNING PFX "using the 'no_fwh_detect' option.\n";
+ KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n"
+ KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n"
+ KERN_WARNING PFX "you are certain that your system has a functional\n"
+ KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
if (no_fwh_detect)
return -ENODEV;
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
index dd761a1e4f08..61ef013b8445 100644
--- a/drivers/char/ip2/i2ellis.c
+++ b/drivers/char/ip2/i2ellis.c
@@ -43,8 +43,6 @@ static void iiEnableMailIrqIIEX(i2eBordStrPtr);
static void iiWriteMaskII(i2eBordStrPtr, unsigned char);
static void iiWriteMaskIIEX(i2eBordStrPtr, unsigned char);
-static void ii2DelayTimer(unsigned int);
-static void ii2DelayWakeup(unsigned long id);
static void ii2Nop(void);
//***************
@@ -55,8 +53,6 @@ static int ii2Safe; // Safe I/O address for delay routine
static int iiDelayed; // Set when the iiResetDelay function is
// called. Cleared when ANY board is reset.
-static struct timer_list * pDelayTimer; // Used by iiDelayTimer
-static wait_queue_head_t pDelayWait; // Used by iiDelayTimer
static rwlock_t Dl_spinlock;
//********
@@ -86,9 +82,6 @@ static rwlock_t Dl_spinlock;
static void
iiEllisInit(void)
{
- pDelayTimer = kmalloc ( sizeof (struct timer_list), GFP_KERNEL );
- init_timer(pDelayTimer);
- init_waitqueue_head(&pDelayWait);
LOCK_INIT(&Dl_spinlock);
}
@@ -106,7 +99,6 @@ iiEllisInit(void)
static void
iiEllisCleanup(void)
{
- kfree(pDelayTimer);
}
//******************************************************************************
@@ -560,19 +552,6 @@ iiInitialize(i2eBordStrPtr pB)
COMPLETE(pB, I2EE_GOOD);
}
-//=======================================================
-// Delay Routines
-//
-// iiDelayIO
-// iiNop
-//=======================================================
-
-static void
-ii2DelayWakeup(unsigned long id)
-{
- wake_up_interruptible ( &pDelayWait );
-}
-
//******************************************************************************
// Function: ii2DelayTimer(mseconds)
// Parameters: mseconds - number of milliseconds to delay
@@ -594,28 +573,7 @@ ii2DelayWakeup(unsigned long id)
static void
ii2DelayTimer(unsigned int mseconds)
{
- wait_queue_t wait;
-
- init_waitqueue_entry(&wait, current);
-
- init_timer ( pDelayTimer );
-
- add_wait_queue(&pDelayWait, &wait);
-
- set_current_state( TASK_INTERRUPTIBLE );
-
- pDelayTimer->expires = jiffies + ( mseconds + 9 ) / 10;
- pDelayTimer->function = ii2DelayWakeup;
- pDelayTimer->data = 0;
-
- add_timer ( pDelayTimer );
-
- schedule();
-
- set_current_state( TASK_RUNNING );
- remove_wait_queue(&pDelayWait, &wait);
-
- del_timer ( pDelayTimer );
+ msleep_interruptible(mseconds);
}
#if 0
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 83c7258d3580..6005b5225772 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -425,9 +425,7 @@ cleanup_module(void)
printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
}
put_tty_driver(ip2_tty_driver);
- if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
- printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
- }
+ unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
remove_proc_entry("ip2mem", &proc_root);
// free memory
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index b894f67fdf14..0baa8fab4ea7 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -2,11 +2,9 @@
# IPMI device configuration
#
-menu "IPMI"
- depends on HAS_IOMEM
-
-config IPMI_HANDLER
+menuconfig IPMI_HANDLER
tristate 'IPMI top-level message handler'
+ depends on HAS_IOMEM
help
This enables the central IPMI message handler, required for IPMI
to work.
@@ -18,9 +16,10 @@ config IPMI_HANDLER
If unsure, say N.
+if IPMI_HANDLER
+
config IPMI_PANIC_EVENT
bool 'Generate a panic event to all BMCs on a panic'
- depends on IPMI_HANDLER
help
When a panic occurs, this will cause the IPMI message handler to
generate an IPMI event describing the panic to each interface
@@ -40,14 +39,12 @@ config IPMI_PANIC_STRING
config IPMI_DEVICE_INTERFACE
tristate 'Device interface for IPMI'
- depends on IPMI_HANDLER
help
This provides an IOCTL interface to the IPMI message handler so
userland processes may use IPMI. It supports poll() and select().
config IPMI_SI
tristate 'IPMI System Interface handler'
- depends on IPMI_HANDLER
help
Provides a driver for System Interfaces (KCS, SMIC, BT).
Currently, only KCS and SMIC are supported. If
@@ -55,15 +52,13 @@ config IPMI_SI
config IPMI_WATCHDOG
tristate 'IPMI Watchdog Timer'
- depends on IPMI_HANDLER
help
This enables the IPMI watchdog timer.
config IPMI_POWEROFF
tristate 'IPMI Poweroff'
- depends on IPMI_HANDLER
help
This enables a function to power off the system with IPMI if
the IPMI management controller is capable of this.
-endmenu
+endif # IPMI_HANDLER
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 8e222f2b80cc..6a01dd9e43f8 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2171,52 +2171,42 @@ static int create_files(struct bmc_device *bmc)
int err;
bmc->device_id_attr.attr.name = "device_id";
- bmc->device_id_attr.attr.owner = THIS_MODULE;
bmc->device_id_attr.attr.mode = S_IRUGO;
bmc->device_id_attr.show = device_id_show;
bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs";
- bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE;
bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
bmc->revision_attr.attr.name = "revision";
- bmc->revision_attr.attr.owner = THIS_MODULE;
bmc->revision_attr.attr.mode = S_IRUGO;
bmc->revision_attr.show = revision_show;
bmc->firmware_rev_attr.attr.name = "firmware_revision";
- bmc->firmware_rev_attr.attr.owner = THIS_MODULE;
bmc->firmware_rev_attr.attr.mode = S_IRUGO;
bmc->firmware_rev_attr.show = firmware_rev_show;
bmc->version_attr.attr.name = "ipmi_version";
- bmc->version_attr.attr.owner = THIS_MODULE;
bmc->version_attr.attr.mode = S_IRUGO;
bmc->version_attr.show = ipmi_version_show;
bmc->add_dev_support_attr.attr.name = "additional_device_support";
- bmc->add_dev_support_attr.attr.owner = THIS_MODULE;
bmc->add_dev_support_attr.attr.mode = S_IRUGO;
bmc->add_dev_support_attr.show = add_dev_support_show;
bmc->manufacturer_id_attr.attr.name = "manufacturer_id";
- bmc->manufacturer_id_attr.attr.owner = THIS_MODULE;
bmc->manufacturer_id_attr.attr.mode = S_IRUGO;
bmc->manufacturer_id_attr.show = manufacturer_id_show;
bmc->product_id_attr.attr.name = "product_id";
- bmc->product_id_attr.attr.owner = THIS_MODULE;
bmc->product_id_attr.attr.mode = S_IRUGO;
bmc->product_id_attr.show = product_id_show;
bmc->guid_attr.attr.name = "guid";
- bmc->guid_attr.attr.owner = THIS_MODULE;
bmc->guid_attr.attr.mode = S_IRUGO;
bmc->guid_attr.show = guid_show;
bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
- bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE;
bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
@@ -2649,10 +2639,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
return -ENODEV;
}
- intf = kmalloc(sizeof(*intf), GFP_KERNEL);
+ intf = kzalloc(sizeof(*intf), GFP_KERNEL);
if (!intf)
return -ENOMEM;
- memset(intf, 0, sizeof(*intf));
intf->ipmi_version_major = ipmi_version_major(device_id);
intf->ipmi_version_minor = ipmi_version_minor(device_id);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index e02893b7b300..b86186de7f07 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -679,7 +679,7 @@ static int ipmi_poweroff_init (void)
{
int rv;
- printk ("Copyright (C) 2004 MontaVista Software -"
+ printk (KERN_INFO "Copyright (C) 2004 MontaVista Software -"
" IPMI Powerdown via sys_reboot.\n");
if (poweroff_powercycle)
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 78e1b962fe35..4edfdda0cf99 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2857,7 +2857,7 @@ static int try_smi_init(struct smi_info *new_smi)
mutex_unlock(&smi_infos_lock);
- printk(" IPMI %s interface initialized\n",si_to_str[new_smi->si_type]);
+ printk(KERN_INFO "IPMI %s interface initialized\n",si_to_str[new_smi->si_type]);
return 0;
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 761f77740d67..77a7a4a06620 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -171,9 +171,6 @@ static struct pci_driver isicom_driver = {
static int prev_card = 3; /* start servicing isi_card[0] */
static struct tty_driver *isicom_normal;
-static DECLARE_COMPLETION(isi_timerdone);
-static char re_schedule = 1;
-
static void isicom_tx(unsigned long _data);
static void isicom_start(struct tty_struct *tty);
@@ -187,7 +184,7 @@ static signed char linuxb_to_isib[] = {
struct isi_board {
unsigned long base;
- unsigned char irq;
+ int irq;
unsigned char port_count;
unsigned short status;
unsigned short port_status; /* each bit for each port */
@@ -227,7 +224,7 @@ static struct isi_port isi_ports[PORT_COUNT];
* it wants to talk.
*/
-static inline int WaitTillCardIsFree(u16 base)
+static inline int WaitTillCardIsFree(unsigned long base)
{
unsigned int count = 0;
unsigned int a = in_atomic(); /* do we run under spinlock? */
@@ -243,17 +240,18 @@ static inline int WaitTillCardIsFree(u16 base)
static int lock_card(struct isi_board *card)
{
- char retries;
unsigned long base = card->base;
+ unsigned int retries, a;
- for (retries = 0; retries < 100; retries++) {
+ for (retries = 0; retries < 10; retries++) {
spin_lock_irqsave(&card->card_lock, card->flags);
- if (inw(base + 0xe) & 0x1) {
- return 1;
- } else {
- spin_unlock_irqrestore(&card->card_lock, card->flags);
- udelay(1000); /* 1ms */
+ for (a = 0; a < 10; a++) {
+ if (inw(base + 0xe) & 0x1)
+ return 1;
+ udelay(10);
}
+ spin_unlock_irqrestore(&card->card_lock, card->flags);
+ msleep(10);
}
printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n",
card->base);
@@ -261,23 +259,6 @@ static int lock_card(struct isi_board *card)
return 0; /* Failed to acquire the card! */
}
-static int lock_card_at_interrupt(struct isi_board *card)
-{
- unsigned char retries;
- unsigned long base = card->base;
-
- for (retries = 0; retries < 200; retries++) {
- spin_lock_irqsave(&card->card_lock, card->flags);
-
- if (inw(base + 0xe) & 0x1)
- return 1;
- else
- spin_unlock_irqrestore(&card->card_lock, card->flags);
- }
- /* Failing in interrupt is an acceptable event */
- return 0; /* Failed to acquire the card! */
-}
-
static void unlock_card(struct isi_board *card)
{
spin_unlock_irqrestore(&card->card_lock, card->flags);
@@ -415,7 +396,9 @@ static inline int __isicom_paranoia_check(struct isi_port const *port,
static void isicom_tx(unsigned long _data)
{
- short count = (BOARD_COUNT-1), card, base;
+ unsigned long flags, base;
+ unsigned int retries;
+ short count = (BOARD_COUNT-1), card;
short txcount, wrd, residue, word_count, cnt;
struct isi_port *port;
struct tty_struct *tty;
@@ -435,32 +418,34 @@ static void isicom_tx(unsigned long _data)
count = isi_card[card].port_count;
port = isi_card[card].ports;
base = isi_card[card].base;
+
+ spin_lock_irqsave(&isi_card[card].card_lock, flags);
+ for (retries = 0; retries < 100; retries++) {
+ if (inw(base + 0xe) & 0x1)
+ break;
+ udelay(2);
+ }
+ if (retries >= 100)
+ goto unlock;
+
for (;count > 0;count--, port++) {
- if (!lock_card_at_interrupt(&isi_card[card]))
- continue;
/* port not active or tx disabled to force flow control */
if (!(port->flags & ASYNC_INITIALIZED) ||
!(port->status & ISI_TXOK))
- unlock_card(&isi_card[card]);
continue;
tty = port->tty;
-
- if (tty == NULL) {
- unlock_card(&isi_card[card]);
+ if (tty == NULL)
continue;
- }
txcount = min_t(short, TX_SIZE, port->xmit_cnt);
- if (txcount <= 0 || tty->stopped || tty->hw_stopped) {
- unlock_card(&isi_card[card]);
+ if (txcount <= 0 || tty->stopped || tty->hw_stopped)
continue;
- }
- if (!(inw(base + 0x02) & (1 << port->channel))) {
- unlock_card(&isi_card[card]);
+
+ if (!(inw(base + 0x02) & (1 << port->channel)))
continue;
- }
+
pr_dbg("txing %d bytes, port%d.\n", txcount,
port->channel + 1);
outw((port->channel << isi_card[card].shift_count) | txcount,
@@ -508,16 +493,12 @@ static void isicom_tx(unsigned long _data)
port->status &= ~ISI_TXOK;
if (port->xmit_cnt <= WAKEUP_CHARS)
tty_wakeup(tty);
- unlock_card(&isi_card[card]);
}
+unlock:
+ spin_unlock_irqrestore(&isi_card[card].card_lock, flags);
/* schedule another tx for hopefully in about 10ms */
sched_again:
- if (!re_schedule) {
- complete(&isi_timerdone);
- return;
- }
-
mod_timer(&tx, jiffies + msecs_to_jiffies(10));
}
@@ -1749,17 +1730,13 @@ static unsigned int card_count;
static int __devinit isicom_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- unsigned int ioaddr, signature, index;
+ unsigned int signature, index;
int retval = -EPERM;
- u8 pciirq;
struct isi_board *board = NULL;
if (card_count >= BOARD_COUNT)
goto err;
- ioaddr = pci_resource_start(pdev, 3);
- /* i.e at offset 0x1c in the PCI configuration register space. */
- pciirq = pdev->irq;
dev_info(&pdev->dev, "ISI PCI Card(Device ID 0x%x)\n", ent->device);
/* allot the first empty slot in the array */
@@ -1770,8 +1747,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
}
board->index = index;
- board->base = ioaddr;
- board->irq = pciirq;
+ board->base = pci_resource_start(pdev, 3);
+ board->irq = pdev->irq;
card_count++;
pci_set_drvdata(pdev, board);
@@ -1901,9 +1878,7 @@ error:
static void __exit isicom_exit(void)
{
- re_schedule = 0;
-
- wait_for_completion_timeout(&isi_timerdone, HZ);
+ del_timer_sync(&tx);
pci_unregister_driver(&isicom_driver);
tty_unregister_driver(isicom_normal);
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 7b279d1de4a2..3c66f402f9d7 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -1753,9 +1753,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old)
return;
tiosp = tty->termios;
- if ((tiosp->c_cflag == old->c_cflag) &&
- (tiosp->c_iflag == old->c_iflag))
- return;
stli_mkasyport(portp, &aport, tiosp);
stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0);
@@ -2166,14 +2163,10 @@ static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigne
cdkhdr_t __iomem *hdrp;
cdkctrl_t __iomem *cp;
unsigned char __iomem *bits;
- unsigned long flags;
-
- spin_lock_irqsave(&brd_lock, flags);
if (test_bit(ST_CMDING, &portp->state)) {
printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
(int) cmd);
- spin_unlock_irqrestore(&brd_lock, flags);
return;
}
@@ -2194,7 +2187,6 @@ static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigne
writeb(readb(bits) | portp->portbit, bits);
set_bit(ST_CMDING, &portp->state);
EBRDDISABLE(brdp);
- spin_unlock_irqrestore(&brd_lock, flags);
}
static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback)
@@ -3218,13 +3210,13 @@ static int stli_initecp(struct stlibrd *brdp)
goto err;
}
+ brdp->iosize = ECP_IOSIZE;
+
if (!request_region(brdp->iobase, brdp->iosize, "istallion")) {
retval = -EIO;
goto err;
}
- brdp->iosize = ECP_IOSIZE;
-
/*
* Based on the specific board type setup the common vars to access
* and enable shared memory. Set all board specific information now
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 90965b4def5c..2ce0af1bd588 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -24,6 +24,7 @@
* 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
*/
+#include <linux/consolemap.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -308,10 +309,9 @@ static void applkey(struct vc_data *vc, int key, char mode)
* Many other routines do put_queue, but I think either
* they produce ASCII, or they produce some user-assigned
* string, and in both cases we might assume that it is
- * in utf-8 already. UTF-8 is defined for words of up to 31 bits,
- * but we need only 16 bits here
+ * in utf-8 already.
*/
-static void to_utf8(struct vc_data *vc, ushort c)
+static void to_utf8(struct vc_data *vc, uint c)
{
if (c < 0x80)
/* 0******* */
@@ -320,11 +320,21 @@ static void to_utf8(struct vc_data *vc, ushort c)
/* 110***** 10****** */
put_queue(vc, 0xc0 | (c >> 6));
put_queue(vc, 0x80 | (c & 0x3f));
- } else {
+ } else if (c < 0x10000) {
+ if (c >= 0xD800 && c < 0xE000)
+ return;
+ if (c == 0xFFFF)
+ return;
/* 1110**** 10****** 10****** */
put_queue(vc, 0xe0 | (c >> 12));
put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
put_queue(vc, 0x80 | (c & 0x3f));
+ } else if (c < 0x110000) {
+ /* 11110*** 10****** 10****** 10****** */
+ put_queue(vc, 0xf0 | (c >> 18));
+ put_queue(vc, 0x80 | ((c >> 12) & 0x3f));
+ put_queue(vc, 0x80 | ((c >> 6) & 0x3f));
+ put_queue(vc, 0x80 | (c & 0x3f));
}
}
@@ -393,7 +403,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
return d;
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, d);
+ to_utf8(vc, conv_8bit_to_uni(d));
else if (d < 0x100)
put_queue(vc, d);
@@ -407,7 +417,7 @@ static void fn_enter(struct vc_data *vc)
{
if (diacr) {
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, diacr);
+ to_utf8(vc, conv_8bit_to_uni(diacr));
else if (diacr < 0x100)
put_queue(vc, diacr);
diacr = 0;
@@ -617,7 +627,7 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
return;
}
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, value);
+ to_utf8(vc, conv_8bit_to_uni(value));
else if (value < 0x100)
put_queue(vc, value);
}
@@ -775,7 +785,7 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
/* kludge */
if (up_flag && shift_state != old_state && npadch != -1) {
if (kbd->kbdmode == VC_UNICODE)
- to_utf8(vc, npadch & 0xffff);
+ to_utf8(vc, npadch);
else
put_queue(vc, npadch & 0xff);
npadch = -1;
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 57f9115a456c..7ee5d9444926 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -39,14 +39,14 @@
#else
#define DBG(fmt...)
#endif
-int mbcs_major;
+static int mbcs_major;
-LIST_HEAD(soft_list);
+static LIST_HEAD(soft_list);
/*
* file operations
*/
-const struct file_operations mbcs_ops = {
+static const struct file_operations mbcs_ops = {
.open = mbcs_open,
.llseek = mbcs_sram_llseek,
.read = mbcs_sram_read,
@@ -377,7 +377,7 @@ dmaread_exit:
return rv;
}
-int mbcs_open(struct inode *ip, struct file *fp)
+static int mbcs_open(struct inode *ip, struct file *fp)
{
struct mbcs_soft *soft;
int minor;
@@ -394,7 +394,7 @@ int mbcs_open(struct inode *ip, struct file *fp)
return -ENODEV;
}
-ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
+static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
{
struct cx_dev *cx_dev = fp->private_data;
struct mbcs_soft *soft = cx_dev->soft;
@@ -418,7 +418,7 @@ ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t *
return rv;
}
-ssize_t
+static ssize_t
mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off)
{
struct cx_dev *cx_dev = fp->private_data;
@@ -443,7 +443,7 @@ mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * o
return rv;
}
-loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
+static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
{
loff_t newpos;
@@ -491,7 +491,7 @@ static void mbcs_gscr_pioaddr_set(struct mbcs_soft *soft)
soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
}
-int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
{
struct cx_dev *cx_dev = fp->private_data;
struct mbcs_soft *soft = cx_dev->soft;
@@ -793,7 +793,7 @@ static int mbcs_remove(struct cx_dev *dev)
return 0;
}
-const struct cx_device_id __devinitdata mbcs_id_table[] = {
+static const struct cx_device_id __devinitdata mbcs_id_table[] = {
{
.part_num = MBCS_PART_NUM,
.mfg_num = MBCS_MFG_NUM,
@@ -807,7 +807,7 @@ const struct cx_device_id __devinitdata mbcs_id_table[] = {
MODULE_DEVICE_TABLE(cx, mbcs_id_table);
-struct cx_drv mbcs_driver = {
+static struct cx_drv mbcs_driver = {
.name = DEVICE_NAME,
.id_table = mbcs_id_table,
.probe = mbcs_probe,
@@ -816,12 +816,7 @@ struct cx_drv mbcs_driver = {
static void __exit mbcs_exit(void)
{
- int rv;
-
- rv = unregister_chrdev(mbcs_major, DEVICE_NAME);
- if (rv < 0)
- DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv);
-
+ unregister_chrdev(mbcs_major, DEVICE_NAME);
cx_driver_unregister(&mbcs_driver);
}
diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h
index e7fd47e43257..c9905a3c3353 100644
--- a/drivers/char/mbcs.h
+++ b/drivers/char/mbcs.h
@@ -542,12 +542,12 @@ struct mbcs_soft {
struct semaphore algolock;
};
-extern int mbcs_open(struct inode *ip, struct file *fp);
-extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
+static int mbcs_open(struct inode *ip, struct file *fp);
+static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
loff_t * off);
-extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
+static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
loff_t * off);
-extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
-extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
+static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
#endif // __MBCS_H__
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 4e6fb9651a16..71c8cd7fa15f 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -67,25 +67,13 @@ extern int pmu_device_init(void);
#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
{
- struct miscdevice *p;
- loff_t off = 0;
-
mutex_lock(&misc_mtx);
- list_for_each_entry(p, &misc_list, list) {
- if (*pos == off++)
- return p;
- }
- return NULL;
+ return seq_list_start(&misc_list, *pos);
}
static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct list_head *n = ((struct miscdevice *)v)->list.next;
-
- ++*pos;
-
- return (n != &misc_list) ? list_entry(n, struct miscdevice, list)
- : NULL;
+ return seq_list_next(v, &misc_list, pos);
}
static void misc_seq_stop(struct seq_file *seq, void *v)
@@ -95,7 +83,7 @@ static void misc_seq_stop(struct seq_file *seq, void *v)
static int misc_seq_show(struct seq_file *seq, void *v)
{
- const struct miscdevice *p = v;
+ const struct miscdevice *p = list_entry(v, struct miscdevice, list);
seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
return 0;
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index e0d35c20c04f..ed76f0a127fd 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -1405,7 +1405,6 @@ static int moxaCard;
static struct mon_str moxaLog;
static int moxaFuncTout = HZ / 2;
-static void moxadelay(int);
static void moxafunc(void __iomem *, int, ushort);
static void wait_finish(void __iomem *);
static void low_water_check(void __iomem *);
@@ -2404,10 +2403,10 @@ void MoxaPortSendBreak(int port, int ms100)
ofsAddr = moxa_ports[port].tableAddr;
if (ms100) {
moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- moxadelay(ms100 * (HZ / 10));
+ msleep(ms100 * 10);
} else {
moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- moxadelay(HZ / 4); /* 250 ms */
+ msleep(250);
}
moxafunc(ofsAddr, FC_StopBreak, Magic_code);
}
@@ -2476,18 +2475,6 @@ static int moxa_set_serial_info(struct moxa_port *info,
/*****************************************************************************
* Static local functions: *
*****************************************************************************/
-/*
- * moxadelay - delays a specified number ticks
- */
-static void moxadelay(int tick)
-{
- unsigned long st, et;
-
- st = jiffies;
- et = st + tick;
- while (time_before(jiffies, et));
-}
-
static void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
{
@@ -2535,7 +2522,7 @@ static int moxaloadbios(int cardno, unsigned char __user *tmp, int len)
return -EFAULT;
baseAddr = moxa_boards[cardno].basemem;
writeb(HW_reset, baseAddr + Control_reg); /* reset */
- moxadelay(1); /* delay 10 ms */
+ msleep(10);
for (i = 0; i < 4096; i++)
writeb(0, baseAddr + i); /* clear fix page */
for (i = 0; i < len; i++)
@@ -2713,7 +2700,7 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
for (i = 0; i < 100; i++) {
if (readw(baseAddr + C218_key) == keycode)
break;
- moxadelay(1); /* delay 10 ms */
+ msleep(10);
}
if (readw(baseAddr + C218_key) != keycode) {
return (-1);
@@ -2725,7 +2712,7 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
for (i = 0; i < 100; i++) {
if (readw(baseAddr + C218_key) == keycode)
break;
- moxadelay(1); /* delay 10 ms */
+ msleep(10);
}
retry++;
} while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3));
@@ -2736,7 +2723,7 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
for (i = 0; i < 100; i++) {
if (readw(baseAddr + Magic_no) == Magic_code)
break;
- moxadelay(1); /* delay 10 ms */
+ msleep(10);
}
if (readw(baseAddr + Magic_no) != Magic_code) {
return (-1);
@@ -2746,7 +2733,7 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
for (i = 0; i < 100; i++) {
if (readw(baseAddr + Magic_no) == Magic_code)
break;
- moxadelay(1); /* delay 10 ms */
+ msleep(10);
}
if (readw(baseAddr + Magic_no) != Magic_code) {
return (-1);
@@ -2788,7 +2775,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor
for (i = 0; i < 10; i++) {
if (readw(baseAddr + C320_key) == C320_KeyCode)
break;
- moxadelay(1);
+ msleep(10);
}
if (readw(baseAddr + C320_key) != C320_KeyCode)
return (-1);
@@ -2799,7 +2786,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor
for (i = 0; i < 10; i++) {
if (readw(baseAddr + C320_key) == C320_KeyCode)
break;
- moxadelay(1);
+ msleep(10);
}
retry++;
} while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3));
@@ -2809,7 +2796,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor
for (i = 0; i < 600; i++) {
if (readw(baseAddr + Magic_no) == Magic_code)
break;
- moxadelay(1);
+ msleep(10);
}
if (readw(baseAddr + Magic_no) != Magic_code)
return (-100);
@@ -2828,7 +2815,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor
for (i = 0; i < 500; i++) {
if (readw(baseAddr + Magic_no) == Magic_code)
break;
- moxadelay(1);
+ msleep(10);
}
if (readw(baseAddr + Magic_no) != Magic_code)
return (-102);
@@ -2842,7 +2829,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor
for (i = 0; i < 600; i++) {
if (readw(baseAddr + Magic_no) == Magic_code)
break;
- moxadelay(1);
+ msleep(10);
}
if (readw(baseAddr + Magic_no) != Magic_code)
return (-102);
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 7ac30612068b..c716ef0dd370 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -265,7 +265,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
vdata->refcnt = ATOMIC_INIT(1);
vma->vm_private_data = vdata;
- vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED | VM_PFNMAP);
+ vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP);
if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &mspec_vm_ops;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 5953a45d7e96..2aee3fef0416 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -90,8 +90,6 @@
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
- IXON|IXOFF))
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
@@ -1729,16 +1727,12 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if ((tty->termios->c_cflag != old_termios->c_cflag) ||
- (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+ mxser_change_speed(info, old_termios);
- mxser_change_speed(info, old_termios);
-
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- mxser_start(tty);
- }
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
}
/* Handle sw stopped */
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index 6cde448cd5b2..6a563932ba19 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -72,8 +72,6 @@
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
- IXON|IXOFF))
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
@@ -1560,7 +1558,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
return -EFAULT;
return 0;
case MOXA_ASPP_MON_EXT: {
- int status, p, shiftbit;
+ int p, shiftbit;
unsigned long opmode;
unsigned cflag, iflag;
@@ -1990,18 +1988,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
struct mxser_port *info = tty->driver_data;
unsigned long flags;
- if ((tty->termios->c_cflag != old_termios->c_cflag) ||
- (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
-
- spin_lock_irqsave(&info->slock, flags);
- mxser_change_speed(info, old_termios);
- spin_unlock_irqrestore(&info->slock, flags);
+ spin_lock_irqsave(&info->slock, flags);
+ mxser_change_speed(info, old_termios);
+ spin_unlock_irqrestore(&info->slock, flags);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- mxser_start(tty);
- }
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ mxser_start(tty);
}
/* Handle sw stopped */
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 337a87f86a3b..e8332f305d72 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -400,7 +400,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
/* Send the next block of data to device */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
actual = tty->driver->write(tty, tbuf->buf, tbuf->count);
-
+
+ /* rollback was possible and has been done */
+ if (actual == -ERESTARTSYS) {
+ n_hdlc->tbuf = tbuf;
+ break;
+ }
/* if transmit error, throw frame away by */
/* pretending it was accepted by driver */
if (actual < 0)
@@ -780,13 +785,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
poll_wait(filp, &tty->write_wait, wait);
/* set bits for operations that won't block */
- if(n_hdlc->rx_buf_list.head)
+ if (n_hdlc->rx_buf_list.head)
mask |= POLLIN | POLLRDNORM; /* readable */
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
mask |= POLLHUP;
- if(tty_hung_up_p(filp))
+ if (tty_hung_up_p(filp))
mask |= POLLHUP;
- if(n_hdlc->tx_free_buf_list.head)
+ if (!tty_is_writelocked(tty) &&
+ n_hdlc->tx_free_buf_list.head)
mask |= POLLOUT | POLLWRNORM; /* writable */
}
return mask;
@@ -861,7 +867,7 @@ static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
spin_lock_irqsave(&list->spinlock,flags);
buf->link=NULL;
- if(list->tail)
+ if (list->tail)
list->tail->link = buf;
else
list->head = buf;
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 14557a4822c0..6b918b80f73e 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -1071,8 +1071,6 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
struct r3964_client_info *pClient;
struct r3964_message *pMsg;
struct r3964_client_message theMsg;
- DECLARE_WAITQUEUE(wait, current);
-
int count;
TRACE_L("read()");
@@ -1086,16 +1084,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
return -EAGAIN;
}
/* block until there is a message: */
- add_wait_queue(&pInfo->read_wait, &wait);
-repeat:
- __set_current_state(TASK_INTERRUPTIBLE);
- pMsg = remove_msg(pInfo, pClient);
- if (!pMsg && !signal_pending(current)) {
- schedule();
- goto repeat;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&pInfo->read_wait, &wait);
+ wait_event_interruptible(pInfo->read_wait,
+ (pMsg = remove_msg(pInfo, pClient)));
}
/* If we still haven't got a message, we must have been signalled */
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 154f42203b05..038056911934 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -45,6 +45,8 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/bitops.h>
+#include <linux/audit.h>
+#include <linux/file.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -78,6 +80,13 @@ static inline void free_buf(unsigned char *buf)
free_page((unsigned long) buf);
}
+static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
+ unsigned char __user *ptr)
+{
+ tty_audit_add_data(tty, &x, 1);
+ return put_user(x, ptr);
+}
+
/**
* n_tty_set__room - receive space
* @tty: terminal
@@ -1153,6 +1162,7 @@ static int copy_from_read_buf(struct tty_struct *tty,
if (n) {
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);
n -= retval;
+ tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);
tty->read_cnt -= n;
@@ -1279,7 +1289,7 @@ do_it_again:
break;
cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
- if (put_user(cs, b++)) {
+ if (tty_put_user(tty, cs, b++)) {
retval = -EFAULT;
b--;
break;
@@ -1321,7 +1331,7 @@ do_it_again:
/* Deal with packet mode. */
if (tty->packet && b == buf) {
- if (put_user(TIOCPKT_DATA, b++)) {
+ if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
retval = -EFAULT;
b--;
break;
@@ -1352,15 +1362,17 @@ do_it_again:
spin_unlock_irqrestore(&tty->read_lock, flags);
if (!eol || (c != __DISABLED_CHAR)) {
- if (put_user(c, b++)) {
+ if (tty_put_user(tty, c, b++)) {
retval = -EFAULT;
b--;
break;
}
nr--;
}
- if (eol)
+ if (eol) {
+ tty_audit_push(tty);
break;
+ }
}
if (retval)
break;
@@ -1538,7 +1550,8 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol
else
tty->minimum_to_wake = 1;
}
- if (tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS &&
+ if (!tty_is_writelocked(tty) &&
+ tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS &&
tty->driver->write_room(tty) > 0)
mask |= POLLOUT | POLLWRNORM;
return mask;
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 204deaa0de80..98dec380af49 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -42,19 +42,12 @@
#define PC 1
#define ATARI 2
-#define COBALT 3
/* select machine configuration */
#if defined(CONFIG_ATARI)
# define MACH ATARI
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */
-#define MACH PC
-# if defined(CONFIG_COBALT)
-# include <linux/cobalt-nvram.h>
-# define MACH COBALT
-# else
-# define MACH PC
-# endif
+# define MACH PC
#else
# error Cannot build nvram driver for this machine configuration.
#endif
@@ -76,18 +69,6 @@
#endif
-#if MACH == COBALT
-
-#define CHECK_DRIVER_INIT() 1
-
-#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE)
-
-#define mach_check_checksum cobalt_check_checksum
-#define mach_set_checksum cobalt_set_checksum
-#define mach_proc_infos cobalt_proc_infos
-
-#endif
-
#if MACH == ATARI
/* Special parameters for RTC in Atari machines */
@@ -604,177 +585,6 @@ pc_proc_infos(unsigned char *nvram, char *buffer, int *len,
#endif /* MACH == PC */
-#if MACH == COBALT
-
-/* the cobalt CMOS has a wider range of its checksum */
-static int cobalt_check_checksum(void)
-{
- int i;
- unsigned short sum = 0;
- unsigned short expect;
-
- for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) {
- if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1)))
- continue;
-
- sum += __nvram_read_byte(i);
- }
- expect = __nvram_read_byte(COBT_CMOS_CHECKSUM) << 8 |
- __nvram_read_byte(COBT_CMOS_CHECKSUM+1);
- return ((sum & 0xffff) == expect);
-}
-
-static void cobalt_set_checksum(void)
-{
- int i;
- unsigned short sum = 0;
-
- for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) {
- if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1)))
- continue;
-
- sum += __nvram_read_byte(i);
- }
-
- __nvram_write_byte(sum >> 8, COBT_CMOS_CHECKSUM);
- __nvram_write_byte(sum & 0xff, COBT_CMOS_CHECKSUM+1);
-}
-
-#ifdef CONFIG_PROC_FS
-
-static int cobalt_proc_infos(unsigned char *nvram, char *buffer, int *len,
- off_t *begin, off_t offset, int size)
-{
- int i;
- unsigned int checksum;
- unsigned int flags;
- char sernum[14];
- char *key = "cNoEbTaWlOtR!";
- unsigned char bto_csum;
-
- spin_lock_irq(&rtc_lock);
- checksum = __nvram_check_checksum();
- spin_unlock_irq(&rtc_lock);
-
- PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not ");
-
- flags = nvram[COBT_CMOS_FLAG_BYTE_0] << 8
- | nvram[COBT_CMOS_FLAG_BYTE_1];
-
- PRINT_PROC("Console: %s\n",
- flags & COBT_CMOS_CONSOLE_FLAG ? "on": "off");
-
- PRINT_PROC("Firmware Debug Messages: %s\n",
- flags & COBT_CMOS_DEBUG_FLAG ? "on": "off");
-
- PRINT_PROC("Auto Prompt: %s\n",
- flags & COBT_CMOS_AUTO_PROMPT_FLAG ? "on": "off");
-
- PRINT_PROC("Shutdown Status: %s\n",
- flags & COBT_CMOS_CLEAN_BOOT_FLAG ? "clean": "dirty");
-
- PRINT_PROC("Hardware Probe: %s\n",
- flags & COBT_CMOS_HW_NOPROBE_FLAG ? "partial": "full");
-
- PRINT_PROC("System Fault: %sdetected\n",
- flags & COBT_CMOS_SYSFAULT_FLAG ? "": "not ");
-
- PRINT_PROC("Panic on OOPS: %s\n",
- flags & COBT_CMOS_OOPSPANIC_FLAG ? "yes": "no");
-
- PRINT_PROC("Delayed Cache Initialization: %s\n",
- flags & COBT_CMOS_DELAY_CACHE_FLAG ? "yes": "no");
-
- PRINT_PROC("Show Logo at Boot: %s\n",
- flags & COBT_CMOS_NOLOGO_FLAG ? "no": "yes");
-
- PRINT_PROC("Boot Method: ");
- switch (nvram[COBT_CMOS_BOOT_METHOD]) {
- case COBT_CMOS_BOOT_METHOD_DISK:
- PRINT_PROC("disk\n");
- break;
-
- case COBT_CMOS_BOOT_METHOD_ROM:
- PRINT_PROC("rom\n");
- break;
-
- case COBT_CMOS_BOOT_METHOD_NET:
- PRINT_PROC("net\n");
- break;
-
- default:
- PRINT_PROC("unknown\n");
- break;
- }
-
- PRINT_PROC("Primary Boot Device: %d:%d\n",
- nvram[COBT_CMOS_BOOT_DEV0_MAJ],
- nvram[COBT_CMOS_BOOT_DEV0_MIN] );
- PRINT_PROC("Secondary Boot Device: %d:%d\n",
- nvram[COBT_CMOS_BOOT_DEV1_MAJ],
- nvram[COBT_CMOS_BOOT_DEV1_MIN] );
- PRINT_PROC("Tertiary Boot Device: %d:%d\n",
- nvram[COBT_CMOS_BOOT_DEV2_MAJ],
- nvram[COBT_CMOS_BOOT_DEV2_MIN] );
-
- PRINT_PROC("Uptime: %d\n",
- nvram[COBT_CMOS_UPTIME_0] << 24 |
- nvram[COBT_CMOS_UPTIME_1] << 16 |
- nvram[COBT_CMOS_UPTIME_2] << 8 |
- nvram[COBT_CMOS_UPTIME_3]);
-
- PRINT_PROC("Boot Count: %d\n",
- nvram[COBT_CMOS_BOOTCOUNT_0] << 24 |
- nvram[COBT_CMOS_BOOTCOUNT_1] << 16 |
- nvram[COBT_CMOS_BOOTCOUNT_2] << 8 |
- nvram[COBT_CMOS_BOOTCOUNT_3]);
-
- /* 13 bytes of serial num */
- for (i=0 ; i<13 ; i++) {
- sernum[i] = nvram[COBT_CMOS_SYS_SERNUM_0 + i];
- }
- sernum[13] = '\0';
-
- checksum = 0;
- for (i=0 ; i<13 ; i++) {
- checksum += sernum[i] ^ key[i];
- }
- checksum = ((checksum & 0x7f) ^ (0xd6)) & 0xff;
-
- PRINT_PROC("Serial Number: %s", sernum);
- if (checksum != nvram[COBT_CMOS_SYS_SERNUM_CSUM]) {
- PRINT_PROC(" (invalid checksum)");
- }
- PRINT_PROC("\n");
-
- PRINT_PROC("Rom Revison: %d.%d.%d\n", nvram[COBT_CMOS_ROM_REV_MAJ],
- nvram[COBT_CMOS_ROM_REV_MIN], nvram[COBT_CMOS_ROM_REV_REV]);
-
- PRINT_PROC("BTO Server: %d.%d.%d.%d", nvram[COBT_CMOS_BTO_IP_0],
- nvram[COBT_CMOS_BTO_IP_1], nvram[COBT_CMOS_BTO_IP_2],
- nvram[COBT_CMOS_BTO_IP_3]);
- bto_csum = nvram[COBT_CMOS_BTO_IP_0] + nvram[COBT_CMOS_BTO_IP_1]
- + nvram[COBT_CMOS_BTO_IP_2] + nvram[COBT_CMOS_BTO_IP_3];
- if (bto_csum != nvram[COBT_CMOS_BTO_IP_CSUM]) {
- PRINT_PROC(" (invalid checksum)");
- }
- PRINT_PROC("\n");
-
- if (flags & COBT_CMOS_VERSION_FLAG
- && nvram[COBT_CMOS_VERSION] >= COBT_CMOS_VER_BTOCODE) {
- PRINT_PROC("BTO Code: 0x%x\n",
- nvram[COBT_CMOS_BTO_CODE_0] << 24 |
- nvram[COBT_CMOS_BTO_CODE_1] << 16 |
- nvram[COBT_CMOS_BTO_CODE_2] << 8 |
- nvram[COBT_CMOS_BTO_CODE_3]);
- }
-
- return 1;
-}
-#endif /* CONFIG_PROC_FS */
-
-#endif /* MACH == COBALT */
-
#if MACH == ATARI
static int
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 13808f6083a0..2b889317461e 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -540,13 +540,12 @@ static int mgslpc_probe(struct pcmcia_device *link)
if (debug_level >= DEBUG_LEVEL_INFO)
printk("mgslpc_attach\n");
- info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+ info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
if (!info) {
printk("Error can't allocate device instance data\n");
return -ENOMEM;
}
- memset(info, 0, sizeof(MGSLPC_INFO));
info->magic = MGSLPC_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
new file mode 100644
index 000000000000..79b6f461be75
--- /dev/null
+++ b/drivers/char/ps3flash.c
@@ -0,0 +1,440 @@
+/*
+ * PS3 FLASH ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME "ps3flash"
+
+#define FLASH_BLOCK_SIZE (256*1024)
+
+
+struct ps3flash_private {
+ struct mutex mutex; /* Bounce buffer mutex */
+};
+
+static struct ps3_storage_device *ps3flash_dev;
+
+static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+ u64 lpar, u64 start_sector,
+ u64 sectors, int write)
+{
+ u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+ write);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ __LINE__, write ? "write" : "read", res);
+ return -EIO;
+ }
+ return sectors;
+}
+
+static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
+ u64 start_sector, u64 sectors,
+ unsigned int sector_offset)
+{
+ u64 max_sectors, lpar;
+
+ max_sectors = dev->bounce_size / dev->blk_size;
+ if (sectors > max_sectors) {
+ dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n",
+ __func__, __LINE__, max_sectors);
+ sectors = max_sectors;
+ }
+
+ lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
+ return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
+ 0);
+}
+
+static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
+ u64 start_sector)
+{
+ u64 sectors = dev->bounce_size / dev->blk_size;
+ return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
+ sectors, 1);
+}
+
+static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
+{
+ struct ps3_storage_device *dev = ps3flash_dev;
+ loff_t res;
+
+ mutex_lock(&file->f_mapping->host->i_mutex);
+ switch (origin) {
+ case 1:
+ offset += file->f_pos;
+ break;
+ case 2:
+ offset += dev->regions[dev->region_idx].size*dev->blk_size;
+ break;
+ }
+ if (offset < 0) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ file->f_pos = offset;
+ res = file->f_pos;
+
+out:
+ mutex_unlock(&file->f_mapping->host->i_mutex);
+ return res;
+}
+
+static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct ps3_storage_device *dev = ps3flash_dev;
+ struct ps3flash_private *priv = dev->sbd.core.driver_data;
+ u64 size, start_sector, end_sector, offset;
+ ssize_t sectors_read;
+ size_t remaining, n;
+
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
+ __func__, __LINE__, count, *pos, buf);
+
+ size = dev->regions[dev->region_idx].size*dev->blk_size;
+ if (*pos >= size || !count)
+ return 0;
+
+ if (*pos + count > size) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u Truncating count from %zu to %llu\n", __func__,
+ __LINE__, count, size - *pos);
+ count = size - *pos;
+ }
+
+ start_sector = *pos / dev->blk_size;
+ offset = *pos % dev->blk_size;
+ end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+
+ remaining = count;
+ do {
+ mutex_lock(&priv->mutex);
+
+ sectors_read = ps3flash_read_sectors(dev, start_sector,
+ end_sector-start_sector,
+ 0);
+ if (sectors_read < 0) {
+ mutex_unlock(&priv->mutex);
+ goto fail;
+ }
+
+ n = min(remaining, sectors_read*dev->blk_size-offset);
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
+ __func__, __LINE__, n, dev->bounce_buf+offset, buf);
+ if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
+ mutex_unlock(&priv->mutex);
+ sectors_read = -EFAULT;
+ goto fail;
+ }
+
+ mutex_unlock(&priv->mutex);
+
+ *pos += n;
+ buf += n;
+ remaining -= n;
+ start_sector += sectors_read;
+ offset = 0;
+ } while (remaining > 0);
+
+ return count;
+
+fail:
+ return sectors_read;
+}
+
+static ssize_t ps3flash_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct ps3_storage_device *dev = ps3flash_dev;
+ struct ps3flash_private *priv = dev->sbd.core.driver_data;
+ u64 size, chunk_sectors, start_write_sector, end_write_sector,
+ end_read_sector, start_read_sector, head, tail, offset;
+ ssize_t res;
+ size_t remaining, n;
+ unsigned int sec_off;
+
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
+ __func__, __LINE__, count, *pos, buf);
+
+ size = dev->regions[dev->region_idx].size*dev->blk_size;
+ if (*pos >= size || !count)
+ return 0;
+
+ if (*pos + count > size) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u Truncating count from %zu to %llu\n", __func__,
+ __LINE__, count, size - *pos);
+ count = size - *pos;
+ }
+
+ chunk_sectors = dev->bounce_size / dev->blk_size;
+
+ start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+ offset = *pos % dev->bounce_size;
+ end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
+ chunk_sectors;
+
+ end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
+ start_read_sector = (*pos + count) / dev->blk_size;
+
+ /*
+ * As we have to write in 256 KiB chunks, while we can read in blk_size
+ * (usually 512 bytes) chunks, we perform the following steps:
+ * 1. Read from start_write_sector to end_read_sector ("head")
+ * 2. Read from start_read_sector to end_write_sector ("tail")
+ * 3. Copy data to buffer
+ * 4. Write from start_write_sector to end_write_sector
+ * All of this is complicated by using only one 256 KiB bounce buffer.
+ */
+
+ head = end_read_sector - start_write_sector;
+ tail = end_write_sector - start_read_sector;
+
+ remaining = count;
+ do {
+ mutex_lock(&priv->mutex);
+
+ if (end_read_sector >= start_read_sector) {
+ /* Merge head and tail */
+ dev_dbg(&dev->sbd.core,
+ "Merged head and tail: %lu sectors at %lu\n",
+ chunk_sectors, start_write_sector);
+ res = ps3flash_read_sectors(dev, start_write_sector,
+ chunk_sectors, 0);
+ if (res < 0)
+ goto fail;
+ } else {
+ if (head) {
+ /* Read head */
+ dev_dbg(&dev->sbd.core,
+ "head: %lu sectors at %lu\n", head,
+ start_write_sector);
+ res = ps3flash_read_sectors(dev,
+ start_write_sector,
+ head, 0);
+ if (res < 0)
+ goto fail;
+ }
+ if (start_read_sector <
+ start_write_sector+chunk_sectors) {
+ /* Read tail */
+ dev_dbg(&dev->sbd.core,
+ "tail: %lu sectors at %lu\n", tail,
+ start_read_sector);
+ sec_off = start_read_sector-start_write_sector;
+ res = ps3flash_read_sectors(dev,
+ start_read_sector,
+ tail, sec_off);
+ if (res < 0)
+ goto fail;
+ }
+ }
+
+ n = min(remaining, dev->bounce_size-offset);
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
+ __func__, __LINE__, n, buf, dev->bounce_buf+offset);
+ if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
+ res = -EFAULT;
+ goto fail;
+ }
+
+ res = ps3flash_write_chunk(dev, start_write_sector);
+ if (res < 0)
+ goto fail;
+
+ mutex_unlock(&priv->mutex);
+
+ *pos += n;
+ buf += n;
+ remaining -= n;
+ start_write_sector += chunk_sectors;
+ head = 0;
+ offset = 0;
+ } while (remaining > 0);
+
+ return count;
+
+fail:
+ mutex_unlock(&priv->mutex);
+ return res;
+}
+
+
+static irqreturn_t ps3flash_interrupt(int irq, void *data)
+{
+ struct ps3_storage_device *dev = data;
+ int res;
+ u64 tag, status;
+
+ res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+ if (tag != dev->tag)
+ dev_err(&dev->sbd.core,
+ "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ __func__, __LINE__, tag, dev->tag);
+
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ __func__, __LINE__, res, status);
+ } else {
+ dev->lv1_status = status;
+ complete(&dev->done);
+ }
+ return IRQ_HANDLED;
+}
+
+
+static const struct file_operations ps3flash_fops = {
+ .owner = THIS_MODULE,
+ .llseek = ps3flash_llseek,
+ .read = ps3flash_read,
+ .write = ps3flash_write,
+};
+
+static struct miscdevice ps3flash_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DEVICE_NAME,
+ .fops = &ps3flash_fops,
+};
+
+static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct ps3flash_private *priv;
+ int error;
+ unsigned long tmp;
+
+ tmp = dev->regions[dev->region_idx].start*dev->blk_size;
+ if (tmp % FLASH_BLOCK_SIZE) {
+ dev_err(&dev->sbd.core,
+ "%s:%u region start %lu is not aligned\n", __func__,
+ __LINE__, tmp);
+ return -EINVAL;
+ }
+ tmp = dev->regions[dev->region_idx].size*dev->blk_size;
+ if (tmp % FLASH_BLOCK_SIZE) {
+ dev_err(&dev->sbd.core,
+ "%s:%u region size %lu is not aligned\n", __func__,
+ __LINE__, tmp);
+ return -EINVAL;
+ }
+
+ /* use static buffer, kmalloc cannot allocate 256 KiB */
+ if (!ps3flash_bounce_buffer.address)
+ return -ENODEV;
+
+ if (ps3flash_dev) {
+ dev_err(&dev->sbd.core,
+ "Only one FLASH device is supported\n");
+ return -EBUSY;
+ }
+
+ ps3flash_dev = dev;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ dev->sbd.core.driver_data = priv;
+ mutex_init(&priv->mutex);
+
+ dev->bounce_size = ps3flash_bounce_buffer.size;
+ dev->bounce_buf = ps3flash_bounce_buffer.address;
+
+ error = ps3stor_setup(dev, ps3flash_interrupt);
+ if (error)
+ goto fail_free_priv;
+
+ ps3flash_misc.parent = &dev->sbd.core;
+ error = misc_register(&ps3flash_misc);
+ if (error) {
+ dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
+ __func__, __LINE__, error);
+ goto fail_teardown;
+ }
+
+ dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
+ __func__, __LINE__, ps3flash_misc.minor);
+ return 0;
+
+fail_teardown:
+ ps3stor_teardown(dev);
+fail_free_priv:
+ kfree(priv);
+ dev->sbd.core.driver_data = NULL;
+fail:
+ ps3flash_dev = NULL;
+ return error;
+}
+
+static int ps3flash_remove(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+
+ misc_deregister(&ps3flash_misc);
+ ps3stor_teardown(dev);
+ kfree(dev->sbd.core.driver_data);
+ dev->sbd.core.driver_data = NULL;
+ ps3flash_dev = NULL;
+ return 0;
+}
+
+
+static struct ps3_system_bus_driver ps3flash = {
+ .match_id = PS3_MATCH_ID_STOR_FLASH,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3flash_probe,
+ .remove = ps3flash_remove,
+ .shutdown = ps3flash_remove,
+};
+
+
+static int __init ps3flash_init(void)
+{
+ return ps3_system_bus_driver_register(&ps3flash);
+}
+
+static void __exit ps3flash_exit(void)
+{
+ ps3_system_bus_driver_unregister(&ps3flash);
+}
+
+module_init(ps3flash_init);
+module_exit(ps3flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 7f5271272f91..397c714cf2ba 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -693,9 +693,14 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
if (r->pull && r->entropy_count < nbytes * 8 &&
r->entropy_count < r->poolinfo->POOLBITS) {
- int bytes = max_t(int, random_read_wakeup_thresh / 8,
- min_t(int, nbytes, sizeof(tmp)));
+ /* If we're limited, always leave two wakeup worth's BITS */
int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
+ int bytes = nbytes;
+
+ /* pull at least as many as BYTES as wakeup BITS */
+ bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
+ /* but never more than the buffer size */
+ bytes = min_t(int, bytes, sizeof(tmp));
DEBUG_ENT("going to reseed %s with %d bits "
"(%d of %d requested)\n",
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 294e9cb0c449..0ce96670f979 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -803,9 +803,7 @@ static void *ckmalloc(int size)
{
void *p;
- p = kmalloc(size, GFP_KERNEL);
- if (p)
- memset(p, 0, size);
+ p = kzalloc(size, GFP_KERNEL);
return p;
}
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 8cc60b693460..7321d002c34f 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -556,9 +556,7 @@ struct CmdBlk *RIOGetCmdBlk(void)
{
struct CmdBlk *CmdBlkP;
- CmdBlkP = kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
- if (CmdBlkP)
- memset(CmdBlkP, 0, sizeof(struct CmdBlk));
+ CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
return CmdBlkP;
}
diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c
index 7e988357326e..991119c9f473 100644
--- a/drivers/char/rio/riotable.c
+++ b/drivers/char/rio/riotable.c
@@ -863,8 +863,7 @@ int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP)
if (PortP->TxRingBuffer)
memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
else if (p->RIOBufferSize) {
- PortP->TxRingBuffer = kmalloc(p->RIOBufferSize, GFP_KERNEL);
- memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
+ PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL);
}
PortP->TxBufferOut = 0;
PortP->TxBufferIn = 0;
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 3494e3fc44bf..b37e626f4faa 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -213,14 +213,6 @@ static inline void rc_release_io_range(struct riscom_board * const bp)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
}
-/* Must be called with enabled interrupts */
-static inline void rc_long_delay(unsigned long delay)
-{
- unsigned long i;
-
- for (i = jiffies + delay; time_after(i,jiffies); ) ;
-}
-
/* Reset and setup CD180 chip */
static void __init rc_init_CD180(struct riscom_board const * bp)
{
@@ -231,7 +223,7 @@ static void __init rc_init_CD180(struct riscom_board const * bp)
rc_wait_CCR(bp); /* Wait for CCR ready */
rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
sti();
- rc_long_delay(HZ/20); /* Delay 0.05 sec */
+ msleep(50); /* Delay 0.05 sec */
cli();
rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
rc_out(bp, CD180_GICR, 0); /* Clear all bits */
@@ -280,7 +272,7 @@ static int __init rc_probe(struct riscom_board *bp)
rc_wait_CCR(bp);
rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */
- rc_long_delay(HZ/20);
+ msleep(50);
irqs = probe_irq_off(irqs);
val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index a3fd7e7ba5a9..56cbba7b6ec0 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -635,12 +635,11 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
ctlp = sCtlNumToCtlPtr(board);
/* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
- info = kmalloc(sizeof (struct r_port), GFP_KERNEL);
+ info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
if (!info) {
printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);
return;
}
- memset(info, 0, sizeof (struct r_port));
info->magic = RPORT_MAGIC;
info->line = line;
@@ -1702,7 +1701,8 @@ static int rp_write(struct tty_struct *tty,
if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
return 0;
- mutex_lock_interruptible(&info->write_mtx);
+ if (mutex_lock_interruptible(&info->write_mtx))
+ return -ERESTARTSYS;
#ifdef ROCKET_DEBUG_WRITE
printk(KERN_INFO "rp_write %d chars...", count);
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 20380a2c4dee..ec6b65ec69ea 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -82,16 +82,13 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#if defined(__i386__)
+#ifdef CONFIG_X86
#include <asm/hpet.h>
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
#include <linux/pci.h>
#include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
static unsigned long rtc_port;
static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@ static int __init rtc_init(void)
unsigned int year, ctrl;
char *guess = NULL;
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev;
-#endif
#else
void *r;
#ifdef RTC_IRQ
@@ -944,7 +937,7 @@ static int __init rtc_init(void)
#endif
#endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@ static int __init rtc_init(void)
}
}
}
-#ifdef __sparc_v9__
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
- rtc_port = isa_dev->resource.start;
- rtc_irq = isa_dev->irq;
- goto found;
- }
- }
- }
-#endif
rtc_has_irq = 0;
printk(KERN_ERR "rtc_init: no PC rtc found\n");
return -EIO;
@@ -1020,7 +1002,7 @@ no_irq:
#endif
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
if (misc_register(&rtc_dev)) {
#ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void)
remove_proc_entry ("driver/rtc", NULL);
misc_deregister(&rtc_dev);
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
@@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void)
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
#endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
}
module_init(rtc_init);
@@ -1159,7 +1141,8 @@ static void rtc_dropped_irq(unsigned long data)
spin_unlock_irq(&rtc_lock);
- printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);
+ if (printk_ratelimit())
+ printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);
/* Now we have new data */
wake_up_interruptible(&rtc_wait);
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index a69f094d1ed3..d63f5ccc29e6 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -20,6 +20,7 @@
#include <asm/uaccess.h>
+#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
#include <linux/consolemap.h>
#include <linux/selection.h>
@@ -34,6 +35,7 @@ extern void poke_blanked_console(void);
/* Variables for selection control. */
/* Use a dynamic buffer, instead of static (Dec 1994) */
struct vc_data *sel_cons; /* must not be deallocated */
+static int use_unicode;
static volatile int sel_start = -1; /* cleared by clear_selection */
static int sel_end;
static int sel_buffer_lth;
@@ -54,10 +56,11 @@ static inline void highlight_pointer(const int where)
complement_pos(sel_cons, where);
}
-static unsigned char
+static u16
sel_pos(int n)
{
- return inverse_translate(sel_cons, screen_glyph(sel_cons, n));
+ return inverse_translate(sel_cons, screen_glyph(sel_cons, n),
+ use_unicode);
}
/* remove the current selection highlight, if any,
@@ -86,8 +89,8 @@ static u32 inwordLut[8]={
0xFF7FFFFF /* latin-1 accented letters, not division sign */
};
-static inline int inword(const unsigned char c) {
- return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1;
+static inline int inword(const u16 c) {
+ return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1);
}
/* set inwordLut contents. Invoked by ioctl(). */
@@ -108,13 +111,36 @@ static inline unsigned short limit(const unsigned short v, const unsigned short
return (v > u) ? u : v;
}
+/* stores the char in UTF8 and returns the number of bytes used (1-3) */
+static int store_utf8(u16 c, char *p)
+{
+ if (c < 0x80) {
+ /* 0******* */
+ p[0] = c;
+ return 1;
+ } else if (c < 0x800) {
+ /* 110***** 10****** */
+ p[0] = 0xc0 | (c >> 6);
+ p[1] = 0x80 | (c & 0x3f);
+ return 2;
+ } else {
+ /* 1110**** 10****** 10****** */
+ p[0] = 0xe0 | (c >> 12);
+ p[1] = 0x80 | ((c >> 6) & 0x3f);
+ p[2] = 0x80 | (c & 0x3f);
+ return 3;
+ }
+}
+
/* set the current selection. Invoked by ioctl() or by kernel code. */
int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty)
{
struct vc_data *vc = vc_cons[fg_console].d;
int sel_mode, new_sel_start, new_sel_end, spc;
char *bp, *obp;
- int i, ps, pe;
+ int i, ps, pe, multiplier;
+ u16 c;
+ struct kbd_struct *kbd = kbd_table + fg_console;
poke_blanked_console();
@@ -158,6 +184,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
clear_selection();
sel_cons = vc_cons[fg_console].d;
}
+ use_unicode = kbd && kbd->kbdmode == VC_UNICODE;
switch (sel_mode)
{
@@ -240,7 +267,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
sel_end = new_sel_end;
/* Allocate a new buffer before freeing the old one ... */
- bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
+ multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */
+ bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL);
if (!bp) {
printk(KERN_WARNING "selection: kmalloc() failed\n");
clear_selection();
@@ -251,8 +279,12 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t
obp = bp;
for (i = sel_start; i <= sel_end; i += 2) {
- *bp = sel_pos(i);
- if (!isspace(*bp++))
+ c = sel_pos(i);
+ if (use_unicode)
+ bp += store_utf8(c, bp);
+ else
+ *bp++ = c;
+ if (!isspace(c))
obp = bp;
if (! ((i + 2) % vc->vc_size_row)) {
/* strip trailing blanks from line and add newline,
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index c585b4738f86..f1497cecffd8 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2573,16 +2573,10 @@ static struct tty_driver *serial167_console_device(struct console *c,
return cy_serial_driver;
}
-static int __init serial167_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
static struct console sercons = {
.name = "ttyS",
.write = serial167_console_write,
.device = serial167_console_device,
- .setup = serial167_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 3ef593a9015f..73037a4d3c50 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -885,53 +885,6 @@ found:
return IRQ_HANDLED;
}
-/* External camera command (exported to the motion eye v4l driver) */
-int sonypi_camera_command(int command, u8 value)
-{
- if (!camera)
- return -EIO;
-
- mutex_lock(&sonypi_device.lock);
-
- switch (command) {
- case SONYPI_COMMAND_SETCAMERA:
- if (value)
- sonypi_camera_on();
- else
- sonypi_camera_off();
- break;
- case SONYPI_COMMAND_SETCAMERABRIGHTNESS:
- sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value);
- break;
- case SONYPI_COMMAND_SETCAMERACONTRAST:
- sonypi_set(SONYPI_CAMERA_CONTRAST, value);
- break;
- case SONYPI_COMMAND_SETCAMERAHUE:
- sonypi_set(SONYPI_CAMERA_HUE, value);
- break;
- case SONYPI_COMMAND_SETCAMERACOLOR:
- sonypi_set(SONYPI_CAMERA_COLOR, value);
- break;
- case SONYPI_COMMAND_SETCAMERASHARPNESS:
- sonypi_set(SONYPI_CAMERA_SHARPNESS, value);
- break;
- case SONYPI_COMMAND_SETCAMERAPICTURE:
- sonypi_set(SONYPI_CAMERA_PICTURE, value);
- break;
- case SONYPI_COMMAND_SETCAMERAAGC:
- sonypi_set(SONYPI_CAMERA_AGC, value);
- break;
- default:
- printk(KERN_ERR "sonypi: sonypi_camera_command invalid: %d\n",
- command);
- break;
- }
- mutex_unlock(&sonypi_device.lock);
- return 0;
-}
-
-EXPORT_SYMBOL(sonypi_camera_command);
-
static int sonypi_misc_fasync(int fd, struct file *filp, int on)
{
int retval;
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index baf7234b6e66..455855631aef 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -345,18 +345,6 @@ static inline void sx_release_io_range(struct specialix_board * bp)
}
-/* Must be called with enabled interrupts */
-/* Ugly. Very ugly. Don't use this for anything else than initialization
- code */
-static inline void sx_long_delay(unsigned long delay)
-{
- unsigned long i;
-
- for (i = jiffies + delay; time_after(i, jiffies); ) ;
-}
-
-
-
/* Set the IRQ using the RTS lines that run to the PAL on the board.... */
static int sx_set_irq ( struct specialix_board *bp)
{
@@ -397,7 +385,7 @@ static int sx_init_CD186x(struct specialix_board * bp)
spin_lock_irqsave(&bp->lock, flags);
sx_out_off(bp, CD186x_CCR, CCR_HARDRESET); /* Reset CD186x chip */
spin_unlock_irqrestore(&bp->lock, flags);
- sx_long_delay(HZ/20); /* Delay 0.05 sec */
+ msleep(50); /* Delay 0.05 sec */
spin_lock_irqsave(&bp->lock, flags);
sx_out_off(bp, CD186x_GIVR, SX_ID); /* Set ID for this chip */
sx_out_off(bp, CD186x_GICR, 0); /* Clear all bits */
@@ -533,7 +521,7 @@ static int sx_probe(struct specialix_board *bp)
sx_wait_CCR(bp);
sx_out(bp, CD186x_CCR, CCR_TXEN); /* Enable transmitter */
sx_out(bp, CD186x_IER, IER_TXRDY); /* Enable tx empty intr */
- sx_long_delay(HZ/20);
+ msleep(50);
irqs = probe_irq_off(irqs);
dprintk (SX_DEBUG_INIT, "SRSR = %02x, ", sx_in(bp, CD186x_SRSR));
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 8c73ccb8830f..4a80b2f864e0 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -1788,7 +1788,6 @@ static void stl_offintr(struct work_struct *work)
if (tty == NULL)
return;
- lock_kernel();
if (test_bit(ASYI_TXLOW, &portp->istate))
tty_wakeup(tty);
@@ -1802,7 +1801,6 @@ static void stl_offintr(struct work_struct *work)
if (portp->flags & ASYNC_CHECK_CD)
tty_hangup(tty); /* FIXME: module removal race here - AKPM */
}
- unlock_kernel();
}
/*****************************************************************************/
@@ -2357,9 +2355,6 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev,
if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE)
goto err;
- dev_info(&pdev->dev, "please, report this to LKML: %x/%x/%x\n",
- pdev->vendor, pdev->device, pdev->class);
-
retval = pci_enable_device(pdev);
if (retval)
goto err;
@@ -4800,7 +4795,6 @@ static void __exit stallion_module_exit(void)
{
struct stlbrd *brdp;
unsigned int i, j;
- int retval;
pr_debug("cleanup_module()\n");
@@ -4823,9 +4817,7 @@ static void __exit stallion_module_exit(void)
for (i = 0; i < 4; i++)
class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
- printk("STALLION: failed to un-register serial memory device, "
- "errno=%d\n", -retval);
+ unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
class_destroy(stallion_class);
pci_unregister_driver(&stl_pcidriver);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index f02a0795983f..fdc256b380b8 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -160,8 +160,6 @@ typedef struct _DMABUFFERENTRY
#define IO_PIN_SHUTDOWN_LIMIT 100
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
struct _input_signal_events {
int ri_up;
int ri_down;
@@ -3064,12 +3062,6 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
printk("%s(%d):mgsl_set_termios %s\n", __FILE__,__LINE__,
tty->driver->name );
- /* just return if nothing has changed */
- if ((tty->termios->c_cflag == old_termios->c_cflag)
- && (RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
-
mgsl_change_params(info);
/* Handle transition to B0 status */
@@ -4332,13 +4324,12 @@ static struct mgsl_struct* mgsl_allocate_device(void)
{
struct mgsl_struct *info;
- info = kmalloc(sizeof(struct mgsl_struct),
+ info = kzalloc(sizeof(struct mgsl_struct),
GFP_KERNEL);
if (!info) {
printk("Error can't allocate device instance data\n");
} else {
- memset(info, 0, sizeof(struct mgsl_struct));
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, mgsl_bh_handler);
info->max_frame_size = 4096;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 02b49bc00028..372a37e25620 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -144,8 +144,6 @@ MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable")
/*
* tty support and callbacks
*/
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
static struct tty_driver *serial_driver;
static int open(struct tty_struct *tty, struct file * filp);
@@ -823,12 +821,6 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
DBGINFO(("%s set_termios\n", tty->driver->name));
- /* just return if nothing has changed */
- if ((tty->termios->c_cflag == old_termios->c_cflag)
- && (RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
-
change_params(info);
/* Handle transition to B0 status */
@@ -3422,13 +3414,12 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
{
struct slgt_info *info;
- info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL);
+ info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL);
if (!info) {
DBGERR(("%s device alloc failed adapter=%d port=%d\n",
driver_name, adapter_num, port_num));
} else {
- memset(info, 0, sizeof(struct slgt_info));
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index ef93d055bdd7..c63013b2fc36 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -135,8 +135,6 @@ typedef struct _SCADESC_EX
#define IO_PIN_SHUTDOWN_LIMIT 100
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
struct _input_signal_events {
int ri_up;
int ri_down;
@@ -927,12 +925,6 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__,
tty->driver->name );
- /* just return if nothing has changed */
- if ((tty->termios->c_cflag == old_termios->c_cflag)
- && (RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
-
change_params(info);
/* Handle transition to B0 status */
@@ -3794,14 +3786,13 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
{
SLMP_INFO *info;
- info = kmalloc(sizeof(SLMP_INFO),
+ info = kzalloc(sizeof(SLMP_INFO),
GFP_KERNEL);
if (!info) {
printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n",
__FILE__,__LINE__, adapter_num, port_num);
} else {
- memset(info, 0, sizeof(SLMP_INFO));
info->magic = MGSL_MAGIC;
INIT_WORK(&info->task, bh_handler);
info->max_frame_size = 4096;
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index dc4e1ff7f56f..8f3f7620f95a 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -2,11 +2,9 @@
# TPM device configuration
#
-menu "TPM devices"
- depends on HAS_IOMEM
-
-config TCG_TPM
+menuconfig TCG_TPM
tristate "TPM Hardware Support"
+ depends on HAS_IOMEM
depends on EXPERIMENTAL
---help---
If you have a TPM security chip in your system, which
@@ -21,9 +19,11 @@ config TCG_TPM
Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI
and CONFIG_PNPACPI.
+if TCG_TPM
+
config TCG_TIS
tristate "TPM Interface Specification 1.2 Interface"
- depends on TCG_TPM && PNPACPI
+ depends on PNPACPI
---help---
If you have a TPM security chip that is compliant with the
TCG TIS 1.2 TPM specification say Yes and it will be accessible
@@ -32,7 +32,7 @@ config TCG_TIS
config TCG_NSC
tristate "National Semiconductor TPM Interface"
- depends on TCG_TPM && PNPACPI
+ depends on PNPACPI
---help---
If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To
@@ -41,7 +41,6 @@ config TCG_NSC
config TCG_ATMEL
tristate "Atmel TPM Interface"
- depends on TCG_TPM
---help---
If you have a TPM security chip from Atmel say Yes and it
will be accessible from within Linux. To compile this driver
@@ -49,7 +48,7 @@ config TCG_ATMEL
config TCG_INFINEON
tristate "Infineon Technologies TPM Interface"
- depends on TCG_TPM && PNPACPI
+ depends on PNPACPI
---help---
If you have a TPM security chip from Infineon Technologies
(either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it
@@ -59,5 +58,4 @@ config TCG_INFINEON
Further information on this driver and the supported hardware
can be found at http://www.prosec.rub.de/tpm
-endmenu
-
+endif # TCG_TPM
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 4eba32b23b29..8677fc6a545e 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -427,7 +427,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
return -ENOMEM;
if ((err = read_log(log)))
- return err;
+ goto out_free;
/* now register seq file */
err = seq_open(file, &tpm_ascii_b_measurments_seqops);
@@ -435,10 +435,15 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode,
seq = file->private_data;
seq->private = log;
} else {
- kfree(log->bios_event_log);
- kfree(log);
+ goto out_free;
}
+
+out:
return err;
+out_free:
+ kfree(log->bios_event_log);
+ kfree(log);
+ goto out;
}
const struct file_operations tpm_ascii_bios_measurements_ops = {
@@ -460,7 +465,7 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
return -ENOMEM;
if ((err = read_log(log)))
- return err;
+ goto out_free;
/* now register seq file */
err = seq_open(file, &tpm_binary_b_measurments_seqops);
@@ -468,10 +473,15 @@ static int tpm_binary_bios_measurements_open(struct inode *inode,
seq = file->private_data;
seq->private = log;
} else {
- kfree(log->bios_event_log);
- kfree(log);
+ goto out_free;
}
+
+out:
return err;
+out_free:
+ kfree(log->bios_event_log);
+ kfree(log);
+ goto out;
}
const struct file_operations tpm_binary_bios_measurements_ops = {
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
new file mode 100644
index 000000000000..d222012c1b0c
--- /dev/null
+++ b/drivers/char/tty_audit.c
@@ -0,0 +1,345 @@
+/*
+ * Creating audit events from TTY input.
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved. This copyrighted
+ * material is made available to anyone wishing to use, modify, copy, or
+ * redistribute it subject to the terms and conditions of the GNU General
+ * Public License v.2.
+ *
+ * Authors: Miloslav Trmac <mitr@redhat.com>
+ */
+
+#include <linux/audit.h>
+#include <linux/file.h>
+#include <linux/tty.h>
+
+struct tty_audit_buf {
+ atomic_t count;
+ struct mutex mutex; /* Protects all data below */
+ int major, minor; /* The TTY which the data is from */
+ unsigned icanon:1;
+ size_t valid;
+ unsigned char *data; /* Allocated size N_TTY_BUF_SIZE */
+};
+
+static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
+ int icanon)
+{
+ struct tty_audit_buf *buf;
+
+ buf = kmalloc(sizeof (*buf), GFP_KERNEL);
+ if (!buf)
+ goto err;
+ if (PAGE_SIZE != N_TTY_BUF_SIZE)
+ buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ else
+ buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
+ if (!buf->data)
+ goto err_buf;
+ atomic_set(&buf->count, 1);
+ mutex_init(&buf->mutex);
+ buf->major = major;
+ buf->minor = minor;
+ buf->icanon = icanon;
+ buf->valid = 0;
+ return buf;
+
+err_buf:
+ kfree(buf);
+err:
+ return NULL;
+}
+
+static void tty_audit_buf_free(struct tty_audit_buf *buf)
+{
+ WARN_ON(buf->valid != 0);
+ if (PAGE_SIZE != N_TTY_BUF_SIZE)
+ kfree(buf->data);
+ else
+ free_page((unsigned long)buf->data);
+ kfree(buf);
+}
+
+static void tty_audit_buf_put(struct tty_audit_buf *buf)
+{
+ if (atomic_dec_and_test(&buf->count))
+ tty_audit_buf_free(buf);
+}
+
+/**
+ * tty_audit_buf_push - Push buffered data out
+ *
+ * Generate an audit message from the contents of @buf, which is owned by
+ * @tsk with @loginuid. @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+ struct tty_audit_buf *buf)
+{
+ struct audit_buffer *ab;
+
+ if (buf->valid == 0)
+ return;
+ if (audit_enabled == 0)
+ return;
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY);
+ if (ab) {
+ char name[sizeof(tsk->comm)];
+
+ audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d "
+ "minor=%d comm=", tsk->pid, tsk->uid,
+ loginuid, buf->major, buf->minor);
+ get_task_comm(name, tsk);
+ audit_log_untrustedstring(ab, name);
+ audit_log_format(ab, " data=");
+ audit_log_n_untrustedstring(ab, buf->valid, buf->data);
+ audit_log_end(ab);
+ }
+ buf->valid = 0;
+}
+
+/**
+ * tty_audit_buf_push_current - Push buffered data out
+ *
+ * Generate an audit message from the contents of @buf, which is owned by
+ * the current task. @buf->mutex must be locked.
+ */
+static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
+{
+ tty_audit_buf_push(current, audit_get_loginuid(current->audit_context),
+ buf);
+}
+
+/**
+ * tty_audit_exit - Handle a task exit
+ *
+ * Make sure all buffered data is written out and deallocate the buffer.
+ * Only needs to be called if current->signal->tty_audit_buf != %NULL.
+ */
+void tty_audit_exit(void)
+{
+ struct tty_audit_buf *buf;
+
+ spin_lock_irq(&current->sighand->siglock);
+ buf = current->signal->tty_audit_buf;
+ current->signal->tty_audit_buf = NULL;
+ spin_unlock_irq(&current->sighand->siglock);
+ if (!buf)
+ return;
+
+ mutex_lock(&buf->mutex);
+ tty_audit_buf_push_current(buf);
+ mutex_unlock(&buf->mutex);
+
+ tty_audit_buf_put(buf);
+}
+
+/**
+ * tty_audit_fork - Copy TTY audit state for a new task
+ *
+ * Set up TTY audit state in @sig from current. @sig needs no locking.
+ */
+void tty_audit_fork(struct signal_struct *sig)
+{
+ spin_lock_irq(&current->sighand->siglock);
+ sig->audit_tty = current->signal->audit_tty;
+ spin_unlock_irq(&current->sighand->siglock);
+ sig->tty_audit_buf = NULL;
+}
+
+/**
+ * tty_audit_push_task - Flush task's pending audit data
+ */
+void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
+{
+ struct tty_audit_buf *buf;
+
+ spin_lock_irq(&tsk->sighand->siglock);
+ buf = tsk->signal->tty_audit_buf;
+ if (buf)
+ atomic_inc(&buf->count);
+ spin_unlock_irq(&tsk->sighand->siglock);
+ if (!buf)
+ return;
+
+ mutex_lock(&buf->mutex);
+ tty_audit_buf_push(tsk, loginuid, buf);
+ mutex_unlock(&buf->mutex);
+
+ tty_audit_buf_put(buf);
+}
+
+/**
+ * tty_audit_buf_get - Get an audit buffer.
+ *
+ * Get an audit buffer for @tty, allocate it if necessary. Return %NULL
+ * if TTY auditing is disabled or out of memory. Otherwise, return a new
+ * reference to the buffer.
+ */
+static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty)
+{
+ struct tty_audit_buf *buf, *buf2;
+
+ buf = NULL;
+ buf2 = NULL;
+ spin_lock_irq(&current->sighand->siglock);
+ if (likely(!current->signal->audit_tty))
+ goto out;
+ buf = current->signal->tty_audit_buf;
+ if (buf) {
+ atomic_inc(&buf->count);
+ goto out;
+ }
+ spin_unlock_irq(&current->sighand->siglock);
+
+ buf2 = tty_audit_buf_alloc(tty->driver->major,
+ tty->driver->minor_start + tty->index,
+ tty->icanon);
+ if (buf2 == NULL) {
+ audit_log_lost("out of memory in TTY auditing");
+ return NULL;
+ }
+
+ spin_lock_irq(&current->sighand->siglock);
+ if (!current->signal->audit_tty)
+ goto out;
+ buf = current->signal->tty_audit_buf;
+ if (!buf) {
+ current->signal->tty_audit_buf = buf2;
+ buf = buf2;
+ buf2 = NULL;
+ }
+ atomic_inc(&buf->count);
+ /* Fall through */
+ out:
+ spin_unlock_irq(&current->sighand->siglock);
+ if (buf2)
+ tty_audit_buf_free(buf2);
+ return buf;
+}
+
+/**
+ * tty_audit_add_data - Add data for TTY auditing.
+ *
+ * Audit @data of @size from @tty, if necessary.
+ */
+void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+ size_t size)
+{
+ struct tty_audit_buf *buf;
+ int major, minor;
+
+ if (unlikely(size == 0))
+ return;
+
+ buf = tty_audit_buf_get(tty);
+ if (!buf)
+ return;
+
+ mutex_lock(&buf->mutex);
+ major = tty->driver->major;
+ minor = tty->driver->minor_start + tty->index;
+ if (buf->major != major || buf->minor != minor
+ || buf->icanon != tty->icanon) {
+ tty_audit_buf_push_current(buf);
+ buf->major = major;
+ buf->minor = minor;
+ buf->icanon = tty->icanon;
+ }
+ do {
+ size_t run;
+
+ run = N_TTY_BUF_SIZE - buf->valid;
+ if (run > size)
+ run = size;
+ memcpy(buf->data + buf->valid, data, run);
+ buf->valid += run;
+ data += run;
+ size -= run;
+ if (buf->valid == N_TTY_BUF_SIZE)
+ tty_audit_buf_push_current(buf);
+ } while (size != 0);
+ mutex_unlock(&buf->mutex);
+ tty_audit_buf_put(buf);
+}
+
+/**
+ * tty_audit_push - Push buffered data out
+ *
+ * Make sure no audit data is pending for @tty on the current process.
+ */
+void tty_audit_push(struct tty_struct *tty)
+{
+ struct tty_audit_buf *buf;
+
+ spin_lock_irq(&current->sighand->siglock);
+ if (likely(!current->signal->audit_tty)) {
+ spin_unlock_irq(&current->sighand->siglock);
+ return;
+ }
+ buf = current->signal->tty_audit_buf;
+ if (buf)
+ atomic_inc(&buf->count);
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (buf) {
+ int major, minor;
+
+ major = tty->driver->major;
+ minor = tty->driver->minor_start + tty->index;
+ mutex_lock(&buf->mutex);
+ if (buf->major == major && buf->minor == minor)
+ tty_audit_buf_push_current(buf);
+ mutex_unlock(&buf->mutex);
+ tty_audit_buf_put(buf);
+ }
+}
+
+/**
+ * tty_audit_opening - A TTY is being opened.
+ *
+ * As a special hack, tasks that close all their TTYs and open new ones
+ * are assumed to be system daemons (e.g. getty) and auditing is
+ * automatically disabled for them.
+ */
+void tty_audit_opening(void)
+{
+ int disable;
+
+ disable = 1;
+ spin_lock_irq(&current->sighand->siglock);
+ if (current->signal->audit_tty == 0)
+ disable = 0;
+ spin_unlock_irq(&current->sighand->siglock);
+ if (!disable)
+ return;
+
+ task_lock(current);
+ if (current->files) {
+ struct fdtable *fdt;
+ unsigned i;
+
+ /*
+ * We don't take a ref to the file, so we must hold ->file_lock
+ * instead.
+ */
+ spin_lock(&current->files->file_lock);
+ fdt = files_fdtable(current->files);
+ for (i = 0; i < fdt->max_fds; i++) {
+ struct file *filp;
+
+ filp = fcheck_files(current->files, i);
+ if (filp && is_tty(filp)) {
+ disable = 0;
+ break;
+ }
+ }
+ spin_unlock(&current->files->file_lock);
+ }
+ task_unlock(current);
+ if (!disable)
+ return;
+
+ spin_lock_irq(&current->sighand->siglock);
+ current->signal->audit_tty = 0;
+ spin_unlock_irq(&current->sighand->siglock);
+}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index a96f26a63fa2..de37ebc3a4cf 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1503,6 +1503,15 @@ int tty_hung_up_p(struct file * filp)
EXPORT_SYMBOL(tty_hung_up_p);
+/**
+ * is_tty - checker whether file is a TTY
+ */
+int is_tty(struct file *filp)
+{
+ return filp->f_op->read == tty_read
+ || filp->f_op->read == hung_up_tty_read;
+}
+
static void session_clear_tty(struct pid *session)
{
struct task_struct *p;
@@ -1726,6 +1735,23 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count,
return i;
}
+void tty_write_unlock(struct tty_struct *tty)
+{
+ mutex_unlock(&tty->atomic_write_lock);
+ wake_up_interruptible(&tty->write_wait);
+}
+
+int tty_write_lock(struct tty_struct *tty, int ndelay)
+{
+ if (!mutex_trylock(&tty->atomic_write_lock)) {
+ if (ndelay)
+ return -EAGAIN;
+ if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ return -ERESTARTSYS;
+ }
+ return 0;
+}
+
/*
* Split writes up in sane blocksizes to avoid
* denial-of-service type attacks
@@ -1737,13 +1763,12 @@ static inline ssize_t do_tty_write(
const char __user *buf,
size_t count)
{
- ssize_t ret = 0, written = 0;
+ ssize_t ret, written = 0;
unsigned int chunk;
- /* FIXME: O_NDELAY ... */
- if (mutex_lock_interruptible(&tty->atomic_write_lock)) {
- return -ERESTARTSYS;
- }
+ ret = tty_write_lock(tty, file->f_flags & O_NDELAY);
+ if (ret < 0)
+ return ret;
/*
* We chunk up writes into a temporary buffer. This
@@ -1776,8 +1801,8 @@ static inline ssize_t do_tty_write(
buf = kmalloc(chunk, GFP_KERNEL);
if (!buf) {
- mutex_unlock(&tty->atomic_write_lock);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
kfree(tty->write_buf);
tty->write_cnt = chunk;
@@ -1812,7 +1837,8 @@ static inline ssize_t do_tty_write(
inode->i_mtime = current_fs_time(inode->i_sb);
ret = written;
}
- mutex_unlock(&tty->atomic_write_lock);
+out:
+ tty_write_unlock(tty);
return ret;
}
@@ -2016,11 +2042,9 @@ static int init_dev(struct tty_driver *driver, int idx,
}
if (!*ltp_loc) {
- ltp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
- GFP_KERNEL);
+ ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!ltp)
goto free_mem_out;
- memset(ltp, 0, sizeof(struct ktermios));
}
if (driver->type == TTY_DRIVER_TYPE_PTY) {
@@ -2049,11 +2073,9 @@ static int init_dev(struct tty_driver *driver, int idx,
}
if (!*o_ltp_loc) {
- o_ltp = (struct ktermios *)
- kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+ o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL);
if (!o_ltp)
goto free_mem_out;
- memset(o_ltp, 0, sizeof(struct ktermios));
}
/*
@@ -2660,6 +2682,7 @@ got_driver:
__proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
mutex_unlock(&tty_mutex);
+ tty_audit_opening();
return 0;
}
@@ -2722,8 +2745,10 @@ static int ptmx_open(struct inode * inode, struct file * filp)
check_tty_count(tty, "tty_open");
retval = ptm_driver->open(tty, filp);
- if (!retval)
+ if (!retval) {
+ tty_audit_opening();
return 0;
+ }
out1:
release_dev(filp);
return retval;
@@ -3163,14 +3188,13 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
static int send_break(struct tty_struct *tty, unsigned int duration)
{
- if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ if (tty_write_lock(tty, 0) < 0)
return -EINTR;
tty->driver->break_ctl(tty, -1);
- if (!signal_pending(current)) {
+ if (!signal_pending(current))
msleep_interruptible(duration);
- }
tty->driver->break_ctl(tty, 0);
- mutex_unlock(&tty->atomic_write_lock);
+ tty_write_unlock(tty);
if (signal_pending(current))
return -EINTR;
return 0;
@@ -3739,9 +3763,8 @@ struct tty_driver *alloc_tty_driver(int lines)
{
struct tty_driver *driver;
- driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL);
+ driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
if (driver) {
- memset(driver, 0, sizeof(struct tty_driver));
driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines;
/* later we'll move allocation of tables here */
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index fd471cb3338f..3423e9ee6481 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -52,8 +52,6 @@
void tty_wait_until_sent(struct tty_struct * tty, long timeout)
{
- DECLARE_WAITQUEUE(wait, current);
-
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
char buf[64];
@@ -61,26 +59,13 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout)
#endif
if (!tty->driver->chars_in_buffer)
return;
- add_wait_queue(&tty->write_wait, &wait);
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
- do {
-#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
- printk(KERN_DEBUG "waiting %s...(%d)\n", tty_name(tty, buf),
- tty->driver->chars_in_buffer(tty));
-#endif
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current))
- goto stop_waiting;
- if (!tty->driver->chars_in_buffer(tty))
- break;
- timeout = schedule_timeout(timeout);
- } while (timeout);
+ if (wait_event_interruptible_timeout(tty->write_wait,
+ !tty->driver->chars_in_buffer(tty), timeout))
+ return;
if (tty->driver->wait_until_sent)
tty->driver->wait_until_sent(tty, timeout);
-stop_waiting:
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&tty->write_wait, &wait);
}
EXPORT_SYMBOL(tty_wait_until_sent);
@@ -276,13 +261,12 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed
termios->c_cflag |= (baud_bits[i] << IBSHIFT);
ifound = i;
}
- }
- while(++i < n_baud_table);
+ } while (++i < n_baud_table);
if (ofound == -1)
termios->c_cflag |= BOTHER;
/* Set exact input bits only if the input and output differ or the
user already did */
- if (ifound == -1 && (ibaud != obaud || ibinput))
+ if (ifound == -1 && (ibaud != obaud || ibinput))
termios->c_cflag |= (BOTHER << IBSHIFT);
}
@@ -575,7 +559,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
return -EFAULT;
mutex_lock(&tty->termios_mutex);
- termios = *tty->termios;
+ termios = *tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
@@ -667,7 +651,7 @@ static int send_prio_char(struct tty_struct *tty, char ch)
return 0;
}
- if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ if (tty_write_lock(tty, 0) < 0)
return -ERESTARTSYS;
if (was_stopped)
@@ -675,7 +659,7 @@ static int send_prio_char(struct tty_struct *tty, char ch)
tty->driver->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
- mutex_unlock(&tty->atomic_write_lock);
+ tty_write_unlock(tty);
return 0;
}
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index 13faf8d17482..e12275df6ea2 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -873,12 +873,12 @@ free_op:
}
const struct file_operations viotap_fops = {
- owner: THIS_MODULE,
- read: viotap_read,
- write: viotap_write,
- ioctl: viotap_ioctl,
- open: viotap_open,
- release: viotap_release,
+ .owner = THIS_MODULE,
+ .read = viotap_read,
+ .write = viotap_write,
+ .ioctl = viotap_ioctl,
+ .open = viotap_open,
+ .release = viotap_release,
};
/* Handle interrupt events for tape */
@@ -1098,15 +1098,10 @@ static int chg_state(int index, unsigned char new_state, struct file *file)
/* Cleanup */
static void __exit viotap_exit(void)
{
- int ret;
-
remove_proc_entry("iSeries/viotape", NULL);
vio_unregister_driver(&viotape_driver);
class_destroy(tape_class);
- ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");
- if (ret < 0)
- printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n",
- ret);
+ unregister_chrdev(VIOTAPE_MAJOR, "viotape");
if (viotape_unitinfo)
dma_free_coherent(iSeries_vio_dev,
sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index bef6d886d4fb..e122a0e87bb0 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -1013,18 +1013,10 @@ static struct tty_driver *scc_console_device(struct console *c, int *index)
return scc_driver;
}
-
-static int __init scc_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
-
static struct console sercons = {
.name = "ttyS",
.write = scc_console_write,
.device = scc_console_device,
- .setup = scc_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 0cea8d4907df..e5ed09192be8 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -19,18 +19,17 @@
* 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/platform_device.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
-#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/types.h>
-#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/vr41xx/giu.h>
#include <asm/vr41xx/irq.h>
@@ -44,18 +43,6 @@ static int major; /* default is dynamic major device number */
module_param(major, int, 0);
MODULE_PARM_DESC(major, "Major device number");
-#define GIU_TYPE1_START 0x0b000100UL
-#define GIU_TYPE1_SIZE 0x20UL
-
-#define GIU_TYPE2_START 0x0f000140UL
-#define GIU_TYPE2_SIZE 0x20UL
-
-#define GIU_TYPE3_START 0x0f000140UL
-#define GIU_TYPE3_SIZE 0x28UL
-
-#define GIU_PULLUPDOWN_START 0x0b0002e0UL
-#define GIU_PULLUPDOWN_SIZE 0x04UL
-
#define GIUIOSELL 0x00
#define GIUIOSELH 0x02
#define GIUPIODL 0x04
@@ -89,8 +76,6 @@ MODULE_PARM_DESC(major, "Major device number");
#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
static spinlock_t giu_lock;
-static struct resource *giu_resource1;
-static struct resource *giu_resource2;
static unsigned long giu_flags;
static unsigned int giu_nr_pins;
@@ -234,7 +219,7 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
giu_set(GIUINTHTSELL, mask);
else
giu_clear(GIUINTHTSELL, mask);
- if (current_cpu_data.cputype == CPU_VR4133) {
+ if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
switch (trigger) {
case IRQ_TRIGGER_EDGE_FALLING:
giu_set(GIUFEDGEINHL, mask);
@@ -269,7 +254,7 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
giu_set(GIUINTHTSELH, mask);
else
giu_clear(GIUINTHTSELH, mask);
- if (current_cpu_data.cputype == CPU_VR4133) {
+ if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
switch (trigger) {
case IRQ_TRIGGER_EDGE_FALLING:
giu_set(GIUFEDGEINHH, mask);
@@ -298,7 +283,6 @@ void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_
giu_write(GIUINTSTATH, mask);
}
}
-
EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
@@ -321,7 +305,6 @@ void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
giu_write(GIUINTSTATH, mask);
}
}
-
EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
@@ -350,7 +333,6 @@ gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
return GPIO_DATA_LOW;
}
-
EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin);
int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
@@ -388,7 +370,6 @@ int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
return 0;
}
-
EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);
int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
@@ -438,7 +419,6 @@ int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
return 0;
}
-
EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);
int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
@@ -477,7 +457,6 @@ int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
return 0;
}
-
EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
@@ -596,61 +575,40 @@ static const struct file_operations gpio_fops = {
static int __devinit giu_probe(struct platform_device *dev)
{
- unsigned long start, size, flags = 0;
- unsigned int nr_pins = 0, trigger, i, pin;
- struct resource *res1, *res2 = NULL;
- void *base;
+ struct resource *res;
+ unsigned int trigger, i, pin;
struct irq_chip *chip;
- int retval;
-
- switch (current_cpu_data.cputype) {
- case CPU_VR4111:
- case CPU_VR4121:
- start = GIU_TYPE1_START;
- size = GIU_TYPE1_SIZE;
- flags = GPIO_HAS_PULLUPDOWN_IO;
- nr_pins = 50;
+ int irq, retval;
+
+ switch (dev->id) {
+ case GPIO_50PINS_PULLUPDOWN:
+ giu_flags = GPIO_HAS_PULLUPDOWN_IO;
+ giu_nr_pins = 50;
break;
- case CPU_VR4122:
- case CPU_VR4131:
- start = GIU_TYPE2_START;
- size = GIU_TYPE2_SIZE;
- nr_pins = 36;
+ case GPIO_36PINS:
+ giu_nr_pins = 36;
break;
- case CPU_VR4133:
- start = GIU_TYPE3_START;
- size = GIU_TYPE3_SIZE;
- flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
- nr_pins = 48;
+ case GPIO_48PINS_EDGE_SELECT:
+ giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
+ giu_nr_pins = 48;
break;
default:
+ printk(KERN_ERR "GIU: unknown ID %d\n", dev->id);
return -ENODEV;
}
- res1 = request_mem_region(start, size, "GIU");
- if (res1 == NULL)
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
return -EBUSY;
- base = ioremap(start, size);
- if (base == NULL) {
- release_resource(res1);
+ giu_base = ioremap(res->start, res->end - res->start + 1);
+ if (!giu_base)
return -ENOMEM;
- }
-
- if (flags & GPIO_HAS_PULLUPDOWN_IO) {
- res2 = request_mem_region(GIU_PULLUPDOWN_START, GIU_PULLUPDOWN_SIZE, "GIU");
- if (res2 == NULL) {
- iounmap(base);
- release_resource(res1);
- return -EBUSY;
- }
- }
retval = register_chrdev(major, "GIU", &gpio_fops);
if (retval < 0) {
- iounmap(base);
- release_resource(res1);
- release_resource(res2);
+ iounmap(giu_base);
+ giu_base = NULL;
return retval;
}
@@ -660,11 +618,6 @@ static int __devinit giu_probe(struct platform_device *dev)
}
spin_lock_init(&giu_lock);
- giu_base = base;
- giu_resource1 = res1;
- giu_resource2 = res2;
- giu_flags = flags;
- giu_nr_pins = nr_pins;
giu_write(GIUINTENL, 0);
giu_write(GIUINTENH, 0);
@@ -685,22 +638,23 @@ static int __devinit giu_probe(struct platform_device *dev)
}
- return cascade_irq(GIUINT_IRQ, giu_get_irq);
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0 || irq >= NR_IRQS)
+ return -EBUSY;
+
+ return cascade_irq(irq, giu_get_irq);
}
static int __devexit giu_remove(struct platform_device *dev)
{
- iounmap(giu_base);
-
- release_resource(giu_resource1);
- if (giu_flags & GPIO_HAS_PULLUPDOWN_IO)
- release_resource(giu_resource2);
+ if (giu_base) {
+ iounmap(giu_base);
+ giu_base = NULL;
+ }
return 0;
}
-static struct platform_device *giu_platform_device;
-
static struct platform_driver giu_device_driver = {
.probe = giu_probe,
.remove = __devexit_p(giu_remove),
@@ -712,30 +666,12 @@ static struct platform_driver giu_device_driver = {
static int __init vr41xx_giu_init(void)
{
- int retval;
-
- giu_platform_device = platform_device_alloc("GIU", -1);
- if (!giu_platform_device)
- return -ENOMEM;
-
- retval = platform_device_add(giu_platform_device);
- if (retval < 0) {
- platform_device_put(giu_platform_device);
- return retval;
- }
-
- retval = platform_driver_register(&giu_device_driver);
- if (retval < 0)
- platform_device_unregister(giu_platform_device);
-
- return retval;
+ return platform_driver_register(&giu_device_driver);
}
static void __exit vr41xx_giu_exit(void)
{
platform_driver_unregister(&giu_device_driver);
-
- platform_device_unregister(giu_platform_device);
}
module_init(vr41xx_giu_init);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 6650ae1c088f..edb7002a3216 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -729,10 +729,9 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
/* although the numbers above are not valid since long ago, the
point is still up-to-date and the comment still has its value
even if only as a historical artifact. --mj, July 1998 */
- vc = kmalloc(sizeof(struct vc_data), GFP_KERNEL);
+ vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
if (!vc)
return -ENOMEM;
- memset(vc, 0, sizeof(*vc));
vc_cons[currcons].d = vc;
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
visual_init(vc, currcons, 1);
@@ -1991,8 +1990,7 @@ static int is_double_width(uint32_t ucs)
{ 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
{ 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
};
- return bisearch(ucs, double_width,
- sizeof(double_width) / sizeof(*double_width) - 1);
+ return bisearch(ucs, double_width, ARRAY_SIZE(double_width) - 1);
}
/* acquires console_sem */
@@ -2989,8 +2987,24 @@ static int con_is_graphics(const struct consw *csw, int first, int last)
return retval;
}
-static int unbind_con_driver(const struct consw *csw, int first, int last,
- int deflt)
+/**
+ * unbind_con_driver - unbind a console driver
+ * @csw: pointer to console driver to unregister
+ * @first: first in range of consoles that @csw should be unbound from
+ * @last: last in range of consoles that @csw should be unbound from
+ * @deflt: should next bound console driver be default after @csw is unbound?
+ *
+ * To unbind a driver from all possible consoles, pass 0 as @first and
+ * %MAX_NR_CONSOLES as @last.
+ *
+ * @deflt controls whether the console that ends up replacing @csw should be
+ * the default console.
+ *
+ * RETURNS:
+ * -ENODEV if @csw isn't a registered console driver or can't be unregistered
+ * or 0 on success.
+ */
+int unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
{
struct module *owner = csw->owner;
const struct consw *defcsw = NULL;
@@ -3075,6 +3089,7 @@ err:
return retval;
}
+EXPORT_SYMBOL(unbind_con_driver);
static int vt_bind(struct con_driver *con)
{
@@ -3491,9 +3506,6 @@ void do_blank_screen(int entering_gfx)
}
return;
}
- if (blank_state != blank_normal_wait)
- return;
- blank_state = blank_off;
/* entering graphics mode? */
if (entering_gfx) {
@@ -3501,10 +3513,15 @@ void do_blank_screen(int entering_gfx)
save_screen(vc);
vc->vc_sw->con_blank(vc, -1, 1);
console_blanked = fg_console + 1;
+ blank_state = blank_off;
set_origin(vc);
return;
}
+ if (blank_state != blank_normal_wait)
+ return;
+ blank_state = blank_off;
+
/* don't blank graphics */
if (vc->vc_mode != KD_TEXT) {
console_blanked = fg_console + 1;
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 53f5538c0c05..16fb23125e96 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -187,6 +187,31 @@ config PNX4008_WATCHDOG
Say N if you are unsure.
+config IOP_WATCHDOG
+ tristate "IOP Watchdog"
+ depends on WATCHDOG && PLAT_IOP
+ select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
+ help
+ Say Y here if to include support for the watchdog timer
+ in the Intel IOP3XX & IOP13XX I/O Processors. This driver can
+ be built as a module by choosing M. The module will
+ be called iop_wdt.
+
+ Note: The IOP13XX watchdog does an Internal Bus Reset which will
+ affect both cores and the peripherals of the IOP. The ATU-X
+ and/or ATUe configuration registers will remain intact, but if
+ operating as an Root Complex and/or Central Resource, the PCI-X
+ and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER.
+
+# AVR32 Architecture
+
+config AT32AP700X_WDT
+ tristate "AT32AP700x watchdog"
+ depends on WATCHDOG && CPU_AT32AP7000
+ help
+ Watchdog timer embedded into AT32AP700x devices. This will reboot
+ your system when the timeout is reached.
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -593,7 +618,7 @@ config ZVM_WATCHDOG
config SH_WDT
tristate "SuperH Watchdog"
- depends on SUPERH
+ depends on SUPERH && (CPU_SH3 || CPU_SH4)
help
This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index d90f649038c2..bdb9d5e3bb41 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -35,6 +35,10 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
+obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
+
+# AVR32 Architecture
+obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c
new file mode 100644
index 000000000000..54a516169d07
--- /dev/null
+++ b/drivers/char/watchdog/at32ap700x_wdt.c
@@ -0,0 +1,386 @@
+/*
+ * Watchdog driver for Atmel AT32AP700X devices
+ *
+ * Copyright (C) 2005-2006 Atmel 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#define TIMEOUT_MIN 1
+#define TIMEOUT_MAX 2
+#define TIMEOUT_DEFAULT TIMEOUT_MAX
+
+/* module parameters */
+static int timeout = TIMEOUT_DEFAULT;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout,
+ "Timeout value. Limited to be 1 or 2 seconds. (default="
+ __MODULE_STRING(TIMEOUT_DEFAULT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/* Watchdog registers and write/read macro */
+#define WDT_CTRL 0x00
+#define WDT_CTRL_EN 0
+#define WDT_CTRL_PSEL 8
+#define WDT_CTRL_KEY 24
+
+#define WDT_CLR 0x04
+
+#define WDT_BIT(name) (1 << WDT_##name)
+#define WDT_BF(name, value) ((value) << WDT_##name)
+
+#define wdt_readl(dev, reg) \
+ __raw_readl((dev)->regs + WDT_##reg)
+#define wdt_writel(dev, reg, value) \
+ __raw_writel((value), (dev)->regs + WDT_##reg)
+
+struct wdt_at32ap700x {
+ void __iomem *regs;
+ spinlock_t io_lock;
+ int timeout;
+ unsigned long users;
+ struct miscdevice miscdev;
+};
+
+static struct wdt_at32ap700x *wdt;
+static char expect_release;
+
+/*
+ * Disable the watchdog.
+ */
+static inline void at32_wdt_stop(void)
+{
+ unsigned long psel;
+
+ spin_lock(&wdt->io_lock);
+ psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f);
+ wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55));
+ wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa));
+ spin_unlock(&wdt->io_lock);
+}
+
+/*
+ * Enable and reset the watchdog.
+ */
+static inline void at32_wdt_start(void)
+{
+ /* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */
+ unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe;
+
+ spin_lock(&wdt->io_lock);
+ wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
+ | WDT_BF(CTRL_PSEL, psel)
+ | WDT_BF(CTRL_KEY, 0x55));
+ wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
+ | WDT_BF(CTRL_PSEL, psel)
+ | WDT_BF(CTRL_KEY, 0xaa));
+ spin_unlock(&wdt->io_lock);
+}
+
+/*
+ * Pat the watchdog timer.
+ */
+static inline void at32_wdt_pat(void)
+{
+ spin_lock(&wdt->io_lock);
+ wdt_writel(wdt, CLR, 0x42);
+ spin_unlock(&wdt->io_lock);
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int at32_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(1, &wdt->users))
+ return -EBUSY;
+
+ at32_wdt_start();
+ return nonseekable_open(inode, file);
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int at32_wdt_close(struct inode *inode, struct file *file)
+{
+ if (expect_release == 42) {
+ at32_wdt_stop();
+ } else {
+ dev_dbg(wdt->miscdev.parent,
+ "Unexpected close, not stopping watchdog!\n");
+ at32_wdt_pat();
+ }
+ clear_bit(1, &wdt->users);
+ expect_release = 0;
+ return 0;
+}
+
+/*
+ * Change the watchdog time interval.
+ */
+static int at32_wdt_settimeout(int time)
+{
+ /*
+ * All counting occurs at 1 / SLOW_CLOCK (32 kHz) and max prescaler is
+ * 2 ^ 16 allowing up to 2 seconds timeout.
+ */
+ if ((time < TIMEOUT_MIN) || (time > TIMEOUT_MAX))
+ return -EINVAL;
+
+ /*
+ * Set new watchdog time. It will be used when at32_wdt_start() is
+ * called.
+ */
+ wdt->timeout = time;
+ return 0;
+}
+
+static struct watchdog_info at32_wdt_info = {
+ .identity = "at32ap700x watchdog",
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+/*
+ * Handle commands from user-space.
+ */
+static int at32_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = -ENOTTY;
+ int time;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+
+ switch (cmd) {
+ case WDIOC_KEEPALIVE:
+ at32_wdt_pat();
+ ret = 0;
+ break;
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user(argp, &at32_wdt_info,
+ sizeof(at32_wdt_info)) ? -EFAULT : 0;
+ break;
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(time, p);
+ if (ret)
+ break;
+ ret = at32_wdt_settimeout(time);
+ if (ret)
+ break;
+ /* Enable new time value */
+ at32_wdt_start();
+ /* fall through */
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(wdt->timeout, p);
+ break;
+ case WDIOC_GETSTATUS: /* fall through */
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, p);
+ break;
+ case WDIOC_SETOPTIONS:
+ ret = get_user(time, p);
+ if (ret)
+ break;
+ if (time & WDIOS_DISABLECARD)
+ at32_wdt_stop();
+ if (time & WDIOS_ENABLECARD)
+ at32_wdt_start();
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static ssize_t at32_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /*
+ * note: just in case someone wrote the magic
+ * character five months ago...
+ */
+ expect_release = 0;
+
+ /*
+ * scan to see whether or not we got the magic
+ * character
+ */
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data+i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_release = 42;
+ }
+ }
+ /* someone wrote to us, we should pat the watchdog */
+ at32_wdt_pat();
+ }
+ return len;
+}
+
+static const struct file_operations at32_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = at32_wdt_ioctl,
+ .open = at32_wdt_open,
+ .release = at32_wdt_close,
+ .write = at32_wdt_write,
+};
+
+static int __init at32_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ int ret;
+
+ if (wdt) {
+ dev_dbg(&pdev->dev, "only 1 wdt instance supported.\n");
+ return -EBUSY;
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_dbg(&pdev->dev, "missing mmio resource\n");
+ return -ENXIO;
+ }
+
+ wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL);
+ if (!wdt) {
+ dev_dbg(&pdev->dev, "no memory for wdt structure\n");
+ return -ENOMEM;
+ }
+
+ wdt->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!wdt->regs) {
+ ret = -ENOMEM;
+ dev_dbg(&pdev->dev, "could not map I/O memory\n");
+ goto err_free;
+ }
+ spin_lock_init(&wdt->io_lock);
+ wdt->users = 0;
+ wdt->miscdev.minor = WATCHDOG_MINOR;
+ wdt->miscdev.name = "watchdog";
+ wdt->miscdev.fops = &at32_wdt_fops;
+
+ if (at32_wdt_settimeout(timeout)) {
+ at32_wdt_settimeout(TIMEOUT_DEFAULT);
+ dev_dbg(&pdev->dev,
+ "default timeout invalid, set to %d sec.\n",
+ TIMEOUT_DEFAULT);
+ }
+
+ ret = misc_register(&wdt->miscdev);
+ if (ret) {
+ dev_dbg(&pdev->dev, "failed to register wdt miscdev\n");
+ goto err_iounmap;
+ }
+
+ platform_set_drvdata(pdev, wdt);
+ wdt->miscdev.parent = &pdev->dev;
+ dev_info(&pdev->dev,
+ "AT32AP700X WDT at 0x%p, timeout %d sec (nowayout=%d)\n",
+ wdt->regs, wdt->timeout, nowayout);
+
+ return 0;
+
+err_iounmap:
+ iounmap(wdt->regs);
+err_free:
+ kfree(wdt);
+ wdt = NULL;
+ return ret;
+}
+
+static int __exit at32_wdt_remove(struct platform_device *pdev)
+{
+ if (wdt && platform_get_drvdata(pdev) == wdt) {
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ at32_wdt_stop();
+
+ misc_deregister(&wdt->miscdev);
+ iounmap(wdt->regs);
+ kfree(wdt);
+ wdt = NULL;
+ platform_set_drvdata(pdev, NULL);
+ }
+
+ return 0;
+}
+
+static void at32_wdt_shutdown(struct platform_device *pdev)
+{
+ at32_wdt_stop();
+}
+
+#ifdef CONFIG_PM
+static int at32_wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ at32_wdt_stop();
+ return 0;
+}
+
+static int at32_wdt_resume(struct platform_device *pdev)
+{
+ if (wdt->users)
+ at32_wdt_start();
+ return 0;
+}
+#else
+#define at32_wdt_suspend NULL
+#define at32_wdt_resume NULL
+#endif
+
+static struct platform_driver at32_wdt_driver = {
+ .remove = __exit_p(at32_wdt_remove),
+ .suspend = at32_wdt_suspend,
+ .resume = at32_wdt_resume,
+ .driver = {
+ .name = "at32_wdt",
+ .owner = THIS_MODULE,
+ },
+ .shutdown = at32_wdt_shutdown,
+};
+
+static int __init at32_wdt_init(void)
+{
+ return platform_driver_probe(&at32_wdt_driver, at32_wdt_probe);
+}
+module_init(at32_wdt_init);
+
+static void __exit at32_wdt_exit(void)
+{
+ platform_driver_unregister(&at32_wdt_driver);
+}
+module_exit(at32_wdt_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c
index 01cf123b1616..0e4787a0bb87 100644
--- a/drivers/char/watchdog/ep93xx_wdt.c
+++ b/drivers/char/watchdog/ep93xx_wdt.c
@@ -107,10 +107,6 @@ static ssize_t
ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
loff_t *ppos)
{
- /* Can't seek (pwrite) on this device */
- if (*ppos != file->f_pos)
- return -ESPIPE;
-
if (len) {
if (!nowayout) {
size_t i;
diff --git a/drivers/char/watchdog/iop_wdt.c b/drivers/char/watchdog/iop_wdt.c
new file mode 100644
index 000000000000..bbbd91af754d
--- /dev/null
+++ b/drivers/char/watchdog/iop_wdt.c
@@ -0,0 +1,262 @@
+/*
+ * drivers/char/watchdog/iop_wdt.c
+ *
+ * WDT driver for Intel I/O Processors
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
+ *
+ * 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.
+ *
+ * Curt E Bruns <curt.e.bruns@intel.com>
+ * Peter Milne <peter.milne@d-tacq.com>
+ * Dan Williams <dan.j.williams@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <asm/hardware.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+#define WDT_ENABLED 2
+
+static unsigned long iop_watchdog_timeout(void)
+{
+ return (0xffffffffUL / get_iop_tick_rate());
+}
+
+/**
+ * wdt_supports_disable - determine if we are accessing a iop13xx watchdog
+ * or iop3xx by whether it has a disable command
+ */
+static int wdt_supports_disable(void)
+{
+ int can_disable;
+
+ if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
+ can_disable = 1;
+ else
+ can_disable = 0;
+
+ return can_disable;
+}
+
+static void wdt_enable(void)
+{
+ /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
+ * Takes approx. 10.7s to timeout
+ */
+ write_wdtcr(IOP_WDTCR_EN_ARM);
+ write_wdtcr(IOP_WDTCR_EN);
+}
+
+/* returns 0 if the timer was successfully disabled */
+static int wdt_disable(void)
+{
+ /* Stop Counting */
+ if (wdt_supports_disable()) {
+ write_wdtcr(IOP_WDTCR_DIS_ARM);
+ write_wdtcr(IOP_WDTCR_DIS);
+ clear_bit(WDT_ENABLED, &wdt_status);
+ printk(KERN_INFO "WATCHDOG: Disabled\n");
+ return 0;
+ } else
+ return 1;
+}
+
+static int iop_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ wdt_enable();
+
+ set_bit(WDT_ENABLED, &wdt_status);
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+iop_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+ wdt_enable();
+ }
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .identity = "iop watchdog",
+};
+
+static int
+iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int options;
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user
+ ((struct watchdog_info *)arg, &ident, sizeof ident))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(boot_status, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(iop_watchdog_timeout(), (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_enable();
+ ret = 0;
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(options, (int *)arg))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ if (!nowayout) {
+ if (wdt_disable() == 0) {
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ ret = 0;
+ } else
+ ret = -ENXIO;
+ } else
+ ret = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ wdt_enable();
+ ret = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int iop_wdt_release(struct inode *inode, struct file *file)
+{
+ int state = 1;
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ if (test_bit(WDT_ENABLED, &wdt_status))
+ state = wdt_disable();
+
+ /* if the timer is not disbaled reload and notify that we are still
+ * going down
+ */
+ if (state != 0) {
+ wdt_enable();
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+ "reset in %lu seconds\n", iop_watchdog_timeout());
+ }
+
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+static const struct file_operations iop_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = iop_wdt_write,
+ .ioctl = iop_wdt_ioctl,
+ .open = iop_wdt_open,
+ .release = iop_wdt_release,
+};
+
+static struct miscdevice iop_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &iop_wdt_fops,
+};
+
+static int __init iop_wdt_init(void)
+{
+ int ret;
+
+ ret = misc_register(&iop_wdt_miscdev);
+ if (ret == 0)
+ printk("iop watchdog timer: timeout %lu sec\n",
+ iop_watchdog_timeout());
+
+ /* check if the reset was caused by the watchdog timer */
+ boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
+
+ /* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
+ * NOTE: An IB Reset will Reset both cores in the IOP342
+ */
+ write_wdtsr(IOP13XX_WDTCR_IB_RESET);
+
+ return ret;
+}
+
+static void __exit iop_wdt_exit(void)
+{
+ misc_deregister(&iop_wdt_miscdev);
+}
+
+module_init(iop_wdt_init);
+module_exit(iop_wdt_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
+MODULE_DESCRIPTION("iop watchdog timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index f35e2848aa3e..db2ccb864412 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -29,11 +29,18 @@
* - support for one more type board
*
* Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
- * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *
+ * Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com>
+ * - make mixcomwd_opened unsigned,
+ * removed lock_kernel/unlock_kernel from mixcomwd_release,
+ * modified ioctl a bit to conform to API
*
*/
-#define VERSION "0.5"
+#define VERSION "0.6"
+#define WATCHDOG_NAME "mixcomwd"
+#define PFX WATCHDOG_NAME ": "
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -49,12 +56,46 @@
#include <asm/uaccess.h>
#include <asm/io.h>
-static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 };
-
-#define MIXCOM_WATCHDOG_OFFSET 0xc10
+/*
+ * We have two types of cards that can be probed:
+ * 1) The Mixcom cards: these cards can be found at addresses
+ * 0x180, 0x280, 0x380 with an additional offset of 0xc10.
+ * (Or 0xd90, 0xe90, 0xf90).
+ * 2) The FlashCOM cards: these cards can be set up at
+ * 0x300 -> 0x378, in 0x8 jumps with an offset of 0x04.
+ * (Or 0x304 -> 0x37c in 0x8 jumps).
+ * Each card has it's own ID.
+ */
#define MIXCOM_ID 0x11
-#define FLASHCOM_WATCHDOG_OFFSET 0x4
#define FLASHCOM_ID 0x18
+static struct {
+ int ioport;
+ int id;
+} mixcomwd_io_info[] __devinitdata = {
+ /* The Mixcom cards */
+ {0x0d90, MIXCOM_ID},
+ {0x0e90, MIXCOM_ID},
+ {0x0f90, MIXCOM_ID},
+ /* The FlashCOM cards */
+ {0x0304, FLASHCOM_ID},
+ {0x030c, FLASHCOM_ID},
+ {0x0314, FLASHCOM_ID},
+ {0x031c, FLASHCOM_ID},
+ {0x0324, FLASHCOM_ID},
+ {0x032c, FLASHCOM_ID},
+ {0x0334, FLASHCOM_ID},
+ {0x033c, FLASHCOM_ID},
+ {0x0344, FLASHCOM_ID},
+ {0x034c, FLASHCOM_ID},
+ {0x0354, FLASHCOM_ID},
+ {0x035c, FLASHCOM_ID},
+ {0x0364, FLASHCOM_ID},
+ {0x036c, FLASHCOM_ID},
+ {0x0374, FLASHCOM_ID},
+ {0x037c, FLASHCOM_ID},
+ /* The end of the list */
+ {0x0000, 0},
+};
static void mixcomwd_timerfun(unsigned long d);
@@ -113,13 +154,13 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
{
if (expect_close == 42) {
if(mixcomwd_timer_alive) {
- printk(KERN_ERR "mixcomwd: release called while internal timer alive");
+ printk(KERN_ERR PFX "release called while internal timer alive");
return -EBUSY;
}
mixcomwd_timer_alive=1;
mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
} else {
- printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly. WDT will not stop!\n");
+ printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
}
clear_bit(0,&mixcomwd_opened);
@@ -188,8 +229,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
return 0;
}
-static const struct file_operations mixcomwd_fops=
-{
+static const struct file_operations mixcomwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mixcomwd_write,
@@ -198,46 +238,30 @@ static const struct file_operations mixcomwd_fops=
.release = mixcomwd_release,
};
-static struct miscdevice mixcomwd_miscdev=
-{
+static struct miscdevice mixcomwd_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &mixcomwd_fops,
};
-static int __init mixcomwd_checkcard(int port)
+static int __init checkcard(int port, int card_id)
{
int id;
- port += MIXCOM_WATCHDOG_OFFSET;
- if (!request_region(port, 1, "MixCOM watchdog")) {
- return 0;
- }
-
- id=inb_p(port) & 0x3f;
- if(id!=MIXCOM_ID) {
- release_region(port, 1);
- return 0;
- }
- return port;
-}
-
-static int __init flashcom_checkcard(int port)
-{
- int id;
-
- port += FLASHCOM_WATCHDOG_OFFSET;
if (!request_region(port, 1, "MixCOM watchdog")) {
return 0;
}
id=inb_p(port);
- if(id!=FLASHCOM_ID) {
+ if (card_id==MIXCOM_ID)
+ id &= 0x3f;
+
+ if (id!=card_id) {
release_region(port, 1);
return 0;
}
- return port;
- }
+ return 1;
+}
static int __init mixcomwd_init(void)
{
@@ -245,50 +269,50 @@ static int __init mixcomwd_init(void)
int ret;
int found=0;
- for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) {
- watchdog_port = mixcomwd_checkcard(mixcomwd_ioports[i]);
- if (watchdog_port) {
- found = 1;
- }
- }
-
- /* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */
- for (i = 0x300; !found && i < 0x380; i+=0x8) {
- watchdog_port = flashcom_checkcard(i);
- if (watchdog_port) {
+ for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) {
+ if (checkcard(mixcomwd_io_info[i].ioport,
+ mixcomwd_io_info[i].id)) {
found = 1;
+ watchdog_port = mixcomwd_io_info[i].ioport;
}
}
if (!found) {
- printk("mixcomwd: No card detected, or port not available.\n");
+ printk(KERN_ERR PFX "No card detected, or port not available.\n");
return -ENODEV;
}
ret = misc_register(&mixcomwd_miscdev);
if (ret)
{
- release_region(watchdog_port, 1);
- return ret;
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto error_misc_register_watchdog;
}
- printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port);
+ printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
+ VERSION, watchdog_port);
return 0;
+
+error_misc_register_watchdog:
+ release_region(watchdog_port, 1);
+ watchdog_port = 0x0000;
+ return ret;
}
static void __exit mixcomwd_exit(void)
{
if (!nowayout) {
if(mixcomwd_timer_alive) {
- printk(KERN_WARNING "mixcomwd: I quit now, hardware will"
+ printk(KERN_WARNING PFX "I quit now, hardware will"
" probably reboot!\n");
del_timer_sync(&mixcomwd_timer);
mixcomwd_timer_alive=0;
}
}
- release_region(watchdog_port,1);
misc_deregister(&mixcomwd_miscdev);
+ release_region(watchdog_port,1);
}
module_init(mixcomwd_init);
@@ -296,5 +320,6 @@ module_exit(mixcomwd_exit);
MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
MODULE_DESCRIPTION("MixCom Watchdog driver");
+MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index e88947f8fe53..0d2b27735419 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -328,12 +328,11 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
goto err_out;
}
- wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
+ wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
if (!wdt) {
ret = -ENOMEM;
goto err_out;
}
- memset(wdt, 0, sizeof(struct mpcore_wdt));
wdt->dev = &dev->dev;
wdt->irq = platform_get_irq(dev, 0);
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 1e7a6719d5ba..0f3fd6c9c354 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -626,12 +626,11 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
/* allocate memory for our device and initialize it */
- usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
+ usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
if (usb_pcwd == NULL) {
printk(KERN_ERR PFX "Out of memory\n");
goto error;
}
- memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
usb_pcwd_device = usb_pcwd;
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c
index 5991add702b0..22f8873dd092 100644
--- a/drivers/char/watchdog/pnx4008_wdt.c
+++ b/drivers/char/watchdog/pnx4008_wdt.c
@@ -148,10 +148,6 @@ static ssize_t
pnx4008_wdt_write(struct file *file, const char *data, size_t len,
loff_t * ppos)
{
- /* Can't seek (pwrite) on this device */
- if (ppos != &file->f_pos)
- return -ESPIPE;
-
if (len) {
if (!nowayout) {
size_t i;
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 20fa29ca7404..50430bced2f2 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -92,6 +92,7 @@ typedef enum close_state {
static DECLARE_MUTEX(open_lock);
+static struct device *wdt_dev; /* platform device attached to */
static struct resource *wdt_mem;
static struct resource *wdt_irq;
static struct clk *wdt_clock;
@@ -180,7 +181,7 @@ static int s3c2410wdt_set_heartbeat(int timeout)
}
if ((count / divisor) >= 0x10000) {
- printk(KERN_ERR PFX "timeout %d too big\n", timeout);
+ dev_err(wdt_dev, "timeout %d too big\n", timeout);
return -EINVAL;
}
}
@@ -233,7 +234,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
if (allow_close == CLOSE_STATE_ALLOW) {
s3c2410wdt_stop();
} else {
- printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");
s3c2410wdt_keepalive();
}
@@ -338,7 +339,7 @@ static struct miscdevice s3c2410wdt_miscdev = {
static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
{
- printk(KERN_INFO PFX "Watchdog timer expired!\n");
+ dev_info(wdt_dev, "watchdog timer expired (irq)\n");
s3c2410wdt_keepalive();
return IRQ_HANDLED;
@@ -348,31 +349,36 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
static int s3c2410wdt_probe(struct platform_device *pdev)
{
struct resource *res;
+ struct device *dev;
+ unsigned int wtcon;
int started = 0;
int ret;
int size;
DBG("%s: probe=%p\n", __FUNCTION__, pdev);
+ dev = &pdev->dev;
+ wdt_dev = &pdev->dev;
+
/* get the memory region for the watchdog timer */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
- printk(KERN_INFO PFX "failed to get memory region resouce\n");
+ dev_err(dev, "no memory resource specified\n");
return -ENOENT;
}
size = (res->end-res->start)+1;
wdt_mem = request_mem_region(res->start, size, pdev->name);
if (wdt_mem == NULL) {
- printk(KERN_INFO PFX "failed to get memory region\n");
+ dev_err(dev, "failed to get memory region\n");
ret = -ENOENT;
goto err_req;
}
wdt_base = ioremap(res->start, size);
if (wdt_base == 0) {
- printk(KERN_INFO PFX "failed to ioremap() region\n");
+ dev_err(dev, "failed to ioremap() region\n");
ret = -EINVAL;
goto err_req;
}
@@ -381,20 +387,20 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (wdt_irq == NULL) {
- printk(KERN_INFO PFX "failed to get irq resource\n");
+ dev_err(dev, "no irq resource specified\n");
ret = -ENOENT;
goto err_map;
}
ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
if (ret != 0) {
- printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
+ dev_err(dev, "failed to install irq (%d)\n", ret);
goto err_map;
}
wdt_clock = clk_get(&pdev->dev, "watchdog");
if (IS_ERR(wdt_clock)) {
- printk(KERN_INFO PFX "failed to find watchdog clock source\n");
+ dev_err(dev, "failed to find watchdog clock source\n");
ret = PTR_ERR(wdt_clock);
goto err_irq;
}
@@ -408,22 +414,22 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
if (started == 0) {
- printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n",
+ dev_info(dev,"tmr_margin value out of range, default %d used\n",
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
} else {
- printk(KERN_INFO PFX "default timer value is out of range, cannot start\n");
+ dev_info(dev, "default timer value is out of range, cannot start\n");
}
}
ret = misc_register(&s3c2410wdt_miscdev);
if (ret) {
- printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
+ dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
goto err_clk;
}
if (tmr_atboot && started == 0) {
- printk(KERN_INFO PFX "Starting Watchdog Timer\n");
+ dev_info(dev, "starting watchdog timer\n");
s3c2410wdt_start();
} else if (!tmr_atboot) {
/* if we're not enabling the watchdog, then ensure it is
@@ -433,6 +439,15 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
s3c2410wdt_stop();
}
+ /* print out a statement of readiness */
+
+ wtcon = readl(wdt_base + S3C2410_WTCON);
+
+ dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
+ (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in",
+ (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis",
+ (wtcon & S3C2410_WTCON_INTEN) ? "" : "en");
+
return 0;
err_clk:
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 5cfcff532545..7b46faf22318 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -71,7 +71,7 @@ static struct clocksource clocksource_acpi_pm = {
.rating = 200,
.read = acpi_pm_read,
.mask = (cycle_t)ACPI_PM_MASK,
- .mult = 0, /*to be caluclated*/
+ .mult = 0, /*to be calculated*/
.shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -105,14 +105,11 @@ static inline void acpi_pm_need_workaround(void)
*/
static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
{
- u8 rev;
-
if (acpi_pm_good)
return;
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
/* the bug has been fixed in PIIX4M */
- if (rev < 3) {
+ if (dev->revision < 3) {
printk(KERN_WARNING "* Found PM-Timer Bug on the chipset."
" Due to workarounds for a bug,\n"
"* this clock source is slow. Consider trying"
diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig
index e0bdc0db9640..100bfd422066 100644
--- a/drivers/connector/Kconfig
+++ b/drivers/connector/Kconfig
@@ -1,6 +1,5 @@
-menu "Connector - unified userspace <-> kernelspace linker"
-config CONNECTOR
+menuconfig CONNECTOR
tristate "Connector - unified userspace <-> kernelspace linker"
depends on NET
---help---
@@ -10,6 +9,8 @@ config CONNECTOR
Connector support can also be built as a module. If so, the module
will be called cn.ko.
+if CONNECTOR
+
config PROC_EVENTS
boolean "Report process events to userspace"
depends on CONNECTOR=y
@@ -18,4 +19,4 @@ config PROC_EVENTS
Provide a connector that reports process events to userspace. Send
events such as fork, exec, id change (uid, gid, suid, etc), and exit.
-endmenu
+endif # CONNECTOR
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index eb37fba9b7ef..2f6a73c01b71 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -39,6 +39,10 @@
*/
static struct cpufreq_driver *cpufreq_driver;
static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS];
+#ifdef CONFIG_HOTPLUG_CPU
+/* This one keeps track of the previously set governor of a removed CPU */
+static struct cpufreq_governor *cpufreq_cpu_governor[NR_CPUS];
+#endif
static DEFINE_SPINLOCK(cpufreq_driver_lock);
/*
@@ -770,9 +774,17 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
}
policy->user_policy.min = policy->cpuinfo.min_freq;
policy->user_policy.max = policy->cpuinfo.max_freq;
- policy->user_policy.governor = policy->governor;
#ifdef CONFIG_SMP
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if (cpufreq_cpu_governor[cpu]){
+ policy->governor = cpufreq_cpu_governor[cpu];
+ dprintk("Restoring governor %s for cpu %d\n",
+ policy->governor->name, cpu);
+ }
+#endif
+
for_each_cpu_mask(j, policy->cpus) {
if (cpu == j)
continue;
@@ -826,13 +838,21 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
while ((drv_attr) && (*drv_attr)) {
- sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
+ ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
+ if (ret)
+ goto err_out_driver_exit;
drv_attr++;
}
- if (cpufreq_driver->get)
- sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
- if (cpufreq_driver->target)
- sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
+ if (cpufreq_driver->get){
+ ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
+ if (ret)
+ goto err_out_driver_exit;
+ }
+ if (cpufreq_driver->target){
+ ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
+ if (ret)
+ goto err_out_driver_exit;
+ }
spin_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu_mask(j, policy->cpus) {
@@ -865,6 +885,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev)
/* set default policy */
ret = __cpufreq_set_policy(policy, &new_policy);
policy->user_policy.policy = policy->policy;
+ policy->user_policy.governor = policy->governor;
unlock_policy_rwsem_write(cpu);
@@ -961,6 +982,11 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
}
#ifdef CONFIG_SMP
+
+#ifdef CONFIG_HOTPLUG_CPU
+ cpufreq_cpu_governor[cpu] = data->governor;
+#endif
+
/* if we have other CPUs still registered, we need to unlink them,
* or else wait_for_completion below will lock up. Clean the
* cpufreq_cpu_data[] while holding the lock, and remove the sysfs
@@ -981,6 +1007,9 @@ static int __cpufreq_remove_dev (struct sys_device * sys_dev)
if (j == cpu)
continue;
dprintk("removing link for cpu %u\n", j);
+#ifdef CONFIG_HOTPLUG_CPU
+ cpufreq_cpu_governor[j] = data->governor;
+#endif
cpu_sys_dev = get_cpu_sysdev(j);
sysfs_remove_link(&cpu_sys_dev->kobj, "cpufreq");
cpufreq_cpu_put(data);
@@ -1679,7 +1708,6 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
{
unsigned int cpu = (unsigned long)hcpu;
struct sys_device *sys_dev;
- struct cpufreq_policy *policy;
sys_dev = get_cpu_sysdev(cpu);
if (sys_dev) {
@@ -1693,11 +1721,6 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
if (unlikely(lock_policy_rwsem_write(cpu)))
BUG();
- policy = cpufreq_cpu_data[cpu];
- if (policy) {
- __cpufreq_driver_target(policy, policy->min,
- CPUFREQ_RELATION_H);
- }
__cpufreq_remove_dev(sys_dev);
break;
case CPU_DOWN_FAILED:
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 8532bb79e5fc..e794527e4925 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -96,15 +96,25 @@ static struct dbs_tuners {
static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
{
- cputime64_t retval;
+ cputime64_t idle_time;
+ cputime64_t cur_jiffies;
+ cputime64_t busy_time;
- retval = cputime64_add(kstat_cpu(cpu).cpustat.idle,
- kstat_cpu(cpu).cpustat.iowait);
+ cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
+ busy_time = cputime64_add(kstat_cpu(cpu).cpustat.user,
+ kstat_cpu(cpu).cpustat.system);
- if (dbs_tuners_ins.ignore_nice)
- retval = cputime64_add(retval, kstat_cpu(cpu).cpustat.nice);
+ busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.irq);
+ busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.softirq);
+ busy_time = cputime64_add(busy_time, kstat_cpu(cpu).cpustat.steal);
- return retval;
+ if (!dbs_tuners_ins.ignore_nice) {
+ busy_time = cputime64_add(busy_time,
+ kstat_cpu(cpu).cpustat.nice);
+ }
+
+ idle_time = cputime64_sub(cur_jiffies, busy_time);
+ return idle_time;
}
/*
@@ -325,7 +335,7 @@ static struct attribute_group dbs_attr_group = {
static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
{
unsigned int idle_ticks, total_ticks;
- unsigned int load;
+ unsigned int load = 0;
cputime64_t cur_jiffies;
struct cpufreq_policy *policy;
@@ -339,7 +349,8 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
total_ticks = (unsigned int) cputime64_sub(cur_jiffies,
this_dbs_info->prev_cpu_wall);
- this_dbs_info->prev_cpu_wall = cur_jiffies;
+ this_dbs_info->prev_cpu_wall = get_jiffies_64();
+
if (!total_ticks)
return;
/*
@@ -370,7 +381,8 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
}
- load = (100 * (total_ticks - idle_ticks)) / total_ticks;
+ if (likely(total_ticks > idle_ticks))
+ load = (100 * (total_ticks - idle_ticks)) / total_ticks;
/* Check for frequency increase */
if (load > dbs_tuners_ins.up_threshold) {
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index d2f0cbd8b8f3..917b9bab9ccb 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -25,8 +25,7 @@ static spinlock_t cpufreq_stats_lock;
#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \
static struct freq_attr _attr_##_name = {\
- .attr = {.name = __stringify(_name), .owner = THIS_MODULE, \
- .mode = _mode, }, \
+ .attr = {.name = __stringify(_name), .mode = _mode, }, \
.show = _show,\
};
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 860345c7799a..51bedab6c808 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -37,6 +37,7 @@ static unsigned int cpu_set_freq[NR_CPUS]; /* CPU freq desired by userspace */
static unsigned int cpu_is_managed[NR_CPUS];
static DEFINE_MUTEX (userspace_mutex);
+static int cpus_using_userspace_governor;
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg)
@@ -47,7 +48,11 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
{
struct cpufreq_freqs *freq = data;
- dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n", freq->cpu, freq->new);
+ if (!cpu_is_managed[freq->cpu])
+ return 0;
+
+ dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n",
+ freq->cpu, freq->new);
cpu_cur_freq[freq->cpu] = freq->new;
return 0;
@@ -120,7 +125,7 @@ store_speed (struct cpufreq_policy *policy, const char *buf, size_t count)
static struct freq_attr freq_attr_scaling_setspeed =
{
- .attr = { .name = "scaling_setspeed", .mode = 0644, .owner = THIS_MODULE },
+ .attr = { .name = "scaling_setspeed", .mode = 0644 },
.show = show_speed,
.store = store_speed,
};
@@ -142,6 +147,13 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
if (rc)
goto start_out;
+ if (cpus_using_userspace_governor == 0) {
+ cpufreq_register_notifier(
+ &userspace_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+ cpus_using_userspace_governor++;
+
cpu_is_managed[cpu] = 1;
cpu_min_freq[cpu] = policy->min;
cpu_max_freq[cpu] = policy->max;
@@ -153,6 +165,13 @@ start_out:
break;
case CPUFREQ_GOV_STOP:
mutex_lock(&userspace_mutex);
+ cpus_using_userspace_governor--;
+ if (cpus_using_userspace_governor == 0) {
+ cpufreq_unregister_notifier(
+ &userspace_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ }
+
cpu_is_managed[cpu] = 0;
cpu_min_freq[cpu] = 0;
cpu_max_freq[cpu] = 0;
@@ -198,7 +217,6 @@ EXPORT_SYMBOL(cpufreq_gov_userspace);
static int __init cpufreq_gov_userspace_init(void)
{
- cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
return cpufreq_register_governor(&cpufreq_gov_userspace);
}
@@ -206,7 +224,6 @@ static int __init cpufreq_gov_userspace_init(void)
static void __exit cpufreq_gov_userspace_exit(void)
{
cpufreq_unregister_governor(&cpufreq_gov_userspace);
- cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
}
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index e7490925fdcf..5409f3afb3f8 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -199,7 +199,6 @@ static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
.attr = { .name = "scaling_available_frequencies",
.mode = 0444,
- .owner=THIS_MODULE
},
.show = show_available_freqs,
};
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index bb90cbd7ca51..84ebfcc1ffb4 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -1,4 +1,9 @@
-menu "Hardware crypto devices"
+
+menuconfig CRYPTO_HW
+ bool "Hardware crypto devices"
+ default y
+
+if CRYPTO_HW
config CRYPTO_DEV_PADLOCK
tristate "Support for VIA PadLock ACE"
@@ -78,4 +83,4 @@ config ZCRYPT_MONOLITHIC
that contains all parts of the crypto device driver (ap bus,
request router and all the card drivers).
-endmenu
+endif # CRYPTO_HW
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 72be6c63edfc..8f670dae53bb 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -3,13 +3,13 @@
#
menu "DMA Engine support"
- depends on !S390
+ depends on HAS_DMA
config DMA_ENGINE
bool "Support for DMA engines"
---help---
- DMA engines offload copy operations from the CPU to dedicated
- hardware, allowing the copies to happen asynchronously.
+ DMA engines offload bulk memory operations from the CPU to dedicated
+ hardware, allowing the operations to happen asynchronously.
comment "DMA Clients"
@@ -32,4 +32,12 @@ config INTEL_IOATDMA
---help---
Enable support for the Intel(R) I/OAT DMA engine.
+config INTEL_IOP_ADMA
+ tristate "Intel IOP ADMA support"
+ depends on DMA_ENGINE && (ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX)
+ select ASYNC_CORE
+ default m
+ ---help---
+ Enable support for the Intel(R) IOP Series RAID engines.
+
endmenu
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index bdcfdbdb1aec..b3839b687ae0 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
obj-$(CONFIG_NET_DMA) += iovlock.o
obj-$(CONFIG_INTEL_IOATDMA) += ioatdma.o
+obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 322ee2984e3d..82489923af09 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -37,11 +37,11 @@
* Each device has a channels list, which runs unlocked but is never modified
* once the device is registered, it's just setup by the driver.
*
- * Each client has a channels list, it's only modified under the client->lock
- * and in an RCU callback, so it's safe to read under rcu_read_lock().
+ * Each client is responsible for keeping track of the channels it uses. See
+ * the definition of dma_event_callback in dmaengine.h.
*
* Each device has a kref, which is initialized to 1 when the device is
- * registered. A kref_put is done for each class_device registered. When the
+ * registered. A kref_get is done for each class_device registered. When the
* class_device is released, the coresponding kref_put is done in the release
* method. Every time one of the device's channels is allocated to a client,
* a kref_get occurs. When the channel is freed, the coresponding kref_put
@@ -51,14 +51,17 @@
* references to finish.
*
* Each channel has an open-coded implementation of Rusty Russell's "bigref,"
- * with a kref and a per_cpu local_t. A single reference is set when on an
- * ADDED event, and removed with a REMOVE event. Net DMA client takes an
- * extra reference per outstanding transaction. The relase function does a
- * kref_put on the device. -ChrisL
+ * with a kref and a per_cpu local_t. A dma_chan_get is called when a client
+ * signals that it wants to use a channel, and dma_chan_put is called when
+ * a channel is removed or a client using it is unregesitered. A client can
+ * take extra references per outstanding transaction, as is the case with
+ * the NET DMA client. The release function does a kref_put on the device.
+ * -ChrisL, DanW
*/
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mm.h>
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/hardirq.h>
@@ -66,6 +69,7 @@
#include <linux/percpu.h>
#include <linux/rcupdate.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
static DEFINE_MUTEX(dma_list_mutex);
static LIST_HEAD(dma_device_list);
@@ -100,8 +104,19 @@ static ssize_t show_bytes_transferred(struct class_device *cd, char *buf)
static ssize_t show_in_use(struct class_device *cd, char *buf)
{
struct dma_chan *chan = container_of(cd, struct dma_chan, class_dev);
+ int in_use = 0;
+
+ if (unlikely(chan->slow_ref) &&
+ atomic_read(&chan->refcount.refcount) > 1)
+ in_use = 1;
+ else {
+ if (local_read(&(per_cpu_ptr(chan->local,
+ get_cpu())->refcount)) > 0)
+ in_use = 1;
+ put_cpu();
+ }
- return sprintf(buf, "%d\n", (chan->client ? 1 : 0));
+ return sprintf(buf, "%d\n", in_use);
}
static struct class_device_attribute dma_class_attrs[] = {
@@ -127,43 +142,72 @@ static struct class dma_devclass = {
/* --- client and device registration --- */
+#define dma_chan_satisfies_mask(chan, mask) \
+ __dma_chan_satisfies_mask((chan), &(mask))
+static int
+__dma_chan_satisfies_mask(struct dma_chan *chan, dma_cap_mask_t *want)
+{
+ dma_cap_mask_t has;
+
+ bitmap_and(has.bits, want->bits, chan->device->cap_mask.bits,
+ DMA_TX_TYPE_END);
+ return bitmap_equal(want->bits, has.bits, DMA_TX_TYPE_END);
+}
+
/**
- * dma_client_chan_alloc - try to allocate a channel to a client
+ * dma_client_chan_alloc - try to allocate channels to a client
* @client: &dma_client
*
* Called with dma_list_mutex held.
*/
-static struct dma_chan *dma_client_chan_alloc(struct dma_client *client)
+static void dma_client_chan_alloc(struct dma_client *client)
{
struct dma_device *device;
struct dma_chan *chan;
- unsigned long flags;
int desc; /* allocated descriptor count */
+ enum dma_state_client ack;
- /* Find a channel, any DMA engine will do */
- list_for_each_entry(device, &dma_device_list, global_node) {
+ /* Find a channel */
+ list_for_each_entry(device, &dma_device_list, global_node)
list_for_each_entry(chan, &device->channels, device_node) {
- if (chan->client)
+ if (!dma_chan_satisfies_mask(chan, client->cap_mask))
continue;
desc = chan->device->device_alloc_chan_resources(chan);
if (desc >= 0) {
- kref_get(&device->refcount);
- kref_init(&chan->refcount);
- chan->slow_ref = 0;
- INIT_RCU_HEAD(&chan->rcu);
- chan->client = client;
- spin_lock_irqsave(&client->lock, flags);
- list_add_tail_rcu(&chan->client_node,
- &client->channels);
- spin_unlock_irqrestore(&client->lock, flags);
- return chan;
+ ack = client->event_callback(client,
+ chan,
+ DMA_RESOURCE_AVAILABLE);
+
+ /* we are done once this client rejects
+ * an available resource
+ */
+ if (ack == DMA_ACK) {
+ dma_chan_get(chan);
+ kref_get(&device->refcount);
+ } else if (ack == DMA_NAK)
+ return;
}
}
- }
+}
+
+enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
+{
+ enum dma_status status;
+ unsigned long dma_sync_wait_timeout = jiffies + msecs_to_jiffies(5000);
+
+ dma_async_issue_pending(chan);
+ do {
+ status = dma_async_is_tx_complete(chan, cookie, NULL, NULL);
+ if (time_after_eq(jiffies, dma_sync_wait_timeout)) {
+ printk(KERN_ERR "dma_sync_wait_timeout!\n");
+ return DMA_ERROR;
+ }
+ } while (status == DMA_IN_PROGRESS);
- return NULL;
+ return status;
}
+EXPORT_SYMBOL(dma_sync_wait);
/**
* dma_chan_cleanup - release a DMA channel's resources
@@ -173,7 +217,6 @@ void dma_chan_cleanup(struct kref *kref)
{
struct dma_chan *chan = container_of(kref, struct dma_chan, refcount);
chan->device->device_free_chan_resources(chan);
- chan->client = NULL;
kref_put(&chan->device->refcount, dma_async_device_cleanup);
}
EXPORT_SYMBOL(dma_chan_cleanup);
@@ -189,7 +232,7 @@ static void dma_chan_free_rcu(struct rcu_head *rcu)
kref_put(&chan->refcount, dma_chan_cleanup);
}
-static void dma_client_chan_free(struct dma_chan *chan)
+static void dma_chan_release(struct dma_chan *chan)
{
atomic_add(0x7FFFFFFF, &chan->refcount.refcount);
chan->slow_ref = 1;
@@ -197,70 +240,57 @@ static void dma_client_chan_free(struct dma_chan *chan)
}
/**
- * dma_chans_rebalance - reallocate channels to clients
- *
- * When the number of DMA channel in the system changes,
- * channels need to be rebalanced among clients.
+ * dma_chans_notify_available - broadcast available channels to the clients
*/
-static void dma_chans_rebalance(void)
+static void dma_clients_notify_available(void)
{
struct dma_client *client;
- struct dma_chan *chan;
- unsigned long flags;
mutex_lock(&dma_list_mutex);
- list_for_each_entry(client, &dma_client_list, global_node) {
- while (client->chans_desired > client->chan_count) {
- chan = dma_client_chan_alloc(client);
- if (!chan)
- break;
- client->chan_count++;
- client->event_callback(client,
- chan,
- DMA_RESOURCE_ADDED);
- }
- while (client->chans_desired < client->chan_count) {
- spin_lock_irqsave(&client->lock, flags);
- chan = list_entry(client->channels.next,
- struct dma_chan,
- client_node);
- list_del_rcu(&chan->client_node);
- spin_unlock_irqrestore(&client->lock, flags);
- client->chan_count--;
- client->event_callback(client,
- chan,
- DMA_RESOURCE_REMOVED);
- dma_client_chan_free(chan);
- }
- }
+ list_for_each_entry(client, &dma_client_list, global_node)
+ dma_client_chan_alloc(client);
mutex_unlock(&dma_list_mutex);
}
/**
- * dma_async_client_register - allocate and register a &dma_client
- * @event_callback: callback for notification of channel addition/removal
+ * dma_chans_notify_available - tell the clients that a channel is going away
+ * @chan: channel on its way out
*/
-struct dma_client *dma_async_client_register(dma_event_callback event_callback)
+static void dma_clients_notify_removed(struct dma_chan *chan)
{
struct dma_client *client;
+ enum dma_state_client ack;
- client = kzalloc(sizeof(*client), GFP_KERNEL);
- if (!client)
- return NULL;
+ mutex_lock(&dma_list_mutex);
- INIT_LIST_HEAD(&client->channels);
- spin_lock_init(&client->lock);
- client->chans_desired = 0;
- client->chan_count = 0;
- client->event_callback = event_callback;
+ list_for_each_entry(client, &dma_client_list, global_node) {
+ ack = client->event_callback(client, chan,
+ DMA_RESOURCE_REMOVED);
+
+ /* client was holding resources for this channel so
+ * free it
+ */
+ if (ack == DMA_ACK) {
+ dma_chan_put(chan);
+ kref_put(&chan->device->refcount,
+ dma_async_device_cleanup);
+ }
+ }
+ mutex_unlock(&dma_list_mutex);
+}
+
+/**
+ * dma_async_client_register - register a &dma_client
+ * @client: ptr to a client structure with valid 'event_callback' and 'cap_mask'
+ */
+void dma_async_client_register(struct dma_client *client)
+{
mutex_lock(&dma_list_mutex);
list_add_tail(&client->global_node, &dma_client_list);
mutex_unlock(&dma_list_mutex);
-
- return client;
}
EXPORT_SYMBOL(dma_async_client_register);
@@ -272,40 +302,42 @@ EXPORT_SYMBOL(dma_async_client_register);
*/
void dma_async_client_unregister(struct dma_client *client)
{
+ struct dma_device *device;
struct dma_chan *chan;
+ enum dma_state_client ack;
if (!client)
return;
- rcu_read_lock();
- list_for_each_entry_rcu(chan, &client->channels, client_node)
- dma_client_chan_free(chan);
- rcu_read_unlock();
-
mutex_lock(&dma_list_mutex);
+ /* free all channels the client is holding */
+ list_for_each_entry(device, &dma_device_list, global_node)
+ list_for_each_entry(chan, &device->channels, device_node) {
+ ack = client->event_callback(client, chan,
+ DMA_RESOURCE_REMOVED);
+
+ if (ack == DMA_ACK) {
+ dma_chan_put(chan);
+ kref_put(&chan->device->refcount,
+ dma_async_device_cleanup);
+ }
+ }
+
list_del(&client->global_node);
mutex_unlock(&dma_list_mutex);
-
- kfree(client);
- dma_chans_rebalance();
}
EXPORT_SYMBOL(dma_async_client_unregister);
/**
- * dma_async_client_chan_request - request DMA channels
- * @client: &dma_client
- * @number: count of DMA channels requested
- *
- * Clients call dma_async_client_chan_request() to specify how many
- * DMA channels they need, 0 to free all currently allocated.
- * The resulting allocations/frees are indicated to the client via the
- * event callback.
+ * dma_async_client_chan_request - send all available channels to the
+ * client that satisfy the capability mask
+ * @client - requester
*/
-void dma_async_client_chan_request(struct dma_client *client,
- unsigned int number)
+void dma_async_client_chan_request(struct dma_client *client)
{
- client->chans_desired = number;
- dma_chans_rebalance();
+ mutex_lock(&dma_list_mutex);
+ dma_client_chan_alloc(client);
+ mutex_unlock(&dma_list_mutex);
}
EXPORT_SYMBOL(dma_async_client_chan_request);
@@ -316,12 +348,31 @@ EXPORT_SYMBOL(dma_async_client_chan_request);
int dma_async_device_register(struct dma_device *device)
{
static int id;
- int chancnt = 0;
+ int chancnt = 0, rc;
struct dma_chan* chan;
if (!device)
return -ENODEV;
+ /* validate device routines */
+ BUG_ON(dma_has_cap(DMA_MEMCPY, device->cap_mask) &&
+ !device->device_prep_dma_memcpy);
+ BUG_ON(dma_has_cap(DMA_XOR, device->cap_mask) &&
+ !device->device_prep_dma_xor);
+ BUG_ON(dma_has_cap(DMA_ZERO_SUM, device->cap_mask) &&
+ !device->device_prep_dma_zero_sum);
+ BUG_ON(dma_has_cap(DMA_MEMSET, device->cap_mask) &&
+ !device->device_prep_dma_memset);
+ BUG_ON(dma_has_cap(DMA_ZERO_SUM, device->cap_mask) &&
+ !device->device_prep_dma_interrupt);
+
+ BUG_ON(!device->device_alloc_chan_resources);
+ BUG_ON(!device->device_free_chan_resources);
+ BUG_ON(!device->device_dependency_added);
+ BUG_ON(!device->device_is_tx_complete);
+ BUG_ON(!device->device_issue_pending);
+ BUG_ON(!device->dev);
+
init_completion(&device->done);
kref_init(&device->refcount);
device->dev_id = id++;
@@ -338,17 +389,38 @@ int dma_async_device_register(struct dma_device *device)
snprintf(chan->class_dev.class_id, BUS_ID_SIZE, "dma%dchan%d",
device->dev_id, chan->chan_id);
+ rc = class_device_register(&chan->class_dev);
+ if (rc) {
+ chancnt--;
+ free_percpu(chan->local);
+ chan->local = NULL;
+ goto err_out;
+ }
+
kref_get(&device->refcount);
- class_device_register(&chan->class_dev);
+ kref_init(&chan->refcount);
+ chan->slow_ref = 0;
+ INIT_RCU_HEAD(&chan->rcu);
}
mutex_lock(&dma_list_mutex);
list_add_tail(&device->global_node, &dma_device_list);
mutex_unlock(&dma_list_mutex);
- dma_chans_rebalance();
+ dma_clients_notify_available();
return 0;
+
+err_out:
+ list_for_each_entry(chan, &device->channels, device_node) {
+ if (chan->local == NULL)
+ continue;
+ kref_put(&device->refcount, dma_async_device_cleanup);
+ class_device_unregister(&chan->class_dev);
+ chancnt--;
+ free_percpu(chan->local);
+ }
+ return rc;
}
EXPORT_SYMBOL(dma_async_device_register);
@@ -371,32 +443,165 @@ static void dma_async_device_cleanup(struct kref *kref)
void dma_async_device_unregister(struct dma_device *device)
{
struct dma_chan *chan;
- unsigned long flags;
mutex_lock(&dma_list_mutex);
list_del(&device->global_node);
mutex_unlock(&dma_list_mutex);
list_for_each_entry(chan, &device->channels, device_node) {
- if (chan->client) {
- spin_lock_irqsave(&chan->client->lock, flags);
- list_del(&chan->client_node);
- chan->client->chan_count--;
- spin_unlock_irqrestore(&chan->client->lock, flags);
- chan->client->event_callback(chan->client,
- chan,
- DMA_RESOURCE_REMOVED);
- dma_client_chan_free(chan);
- }
+ dma_clients_notify_removed(chan);
class_device_unregister(&chan->class_dev);
+ dma_chan_release(chan);
}
- dma_chans_rebalance();
kref_put(&device->refcount, dma_async_device_cleanup);
wait_for_completion(&device->done);
}
EXPORT_SYMBOL(dma_async_device_unregister);
+/**
+ * dma_async_memcpy_buf_to_buf - offloaded copy between virtual addresses
+ * @chan: DMA channel to offload copy to
+ * @dest: destination address (virtual)
+ * @src: source address (virtual)
+ * @len: length
+ *
+ * Both @dest and @src must be mappable to a bus address according to the
+ * DMA mapping API rules for streaming mappings.
+ * Both @dest and @src must stay memory resident (kernel memory or locked
+ * user space pages).
+ */
+dma_cookie_t
+dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest,
+ void *src, size_t len)
+{
+ struct dma_device *dev = chan->device;
+ struct dma_async_tx_descriptor *tx;
+ dma_addr_t addr;
+ dma_cookie_t cookie;
+ int cpu;
+
+ tx = dev->device_prep_dma_memcpy(chan, len, 0);
+ if (!tx)
+ return -ENOMEM;
+
+ tx->ack = 1;
+ tx->callback = NULL;
+ addr = dma_map_single(dev->dev, src, len, DMA_TO_DEVICE);
+ tx->tx_set_src(addr, tx, 0);
+ addr = dma_map_single(dev->dev, dest, len, DMA_FROM_DEVICE);
+ tx->tx_set_dest(addr, tx, 0);
+ cookie = tx->tx_submit(tx);
+
+ cpu = get_cpu();
+ per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
+ per_cpu_ptr(chan->local, cpu)->memcpy_count++;
+ put_cpu();
+
+ return cookie;
+}
+EXPORT_SYMBOL(dma_async_memcpy_buf_to_buf);
+
+/**
+ * dma_async_memcpy_buf_to_pg - offloaded copy from address to page
+ * @chan: DMA channel to offload copy to
+ * @page: destination page
+ * @offset: offset in page to copy to
+ * @kdata: source address (virtual)
+ * @len: length
+ *
+ * Both @page/@offset and @kdata must be mappable to a bus address according
+ * to the DMA mapping API rules for streaming mappings.
+ * Both @page/@offset and @kdata must stay memory resident (kernel memory or
+ * locked user space pages)
+ */
+dma_cookie_t
+dma_async_memcpy_buf_to_pg(struct dma_chan *chan, struct page *page,
+ unsigned int offset, void *kdata, size_t len)
+{
+ struct dma_device *dev = chan->device;
+ struct dma_async_tx_descriptor *tx;
+ dma_addr_t addr;
+ dma_cookie_t cookie;
+ int cpu;
+
+ tx = dev->device_prep_dma_memcpy(chan, len, 0);
+ if (!tx)
+ return -ENOMEM;
+
+ tx->ack = 1;
+ tx->callback = NULL;
+ addr = dma_map_single(dev->dev, kdata, len, DMA_TO_DEVICE);
+ tx->tx_set_src(addr, tx, 0);
+ addr = dma_map_page(dev->dev, page, offset, len, DMA_FROM_DEVICE);
+ tx->tx_set_dest(addr, tx, 0);
+ cookie = tx->tx_submit(tx);
+
+ cpu = get_cpu();
+ per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
+ per_cpu_ptr(chan->local, cpu)->memcpy_count++;
+ put_cpu();
+
+ return cookie;
+}
+EXPORT_SYMBOL(dma_async_memcpy_buf_to_pg);
+
+/**
+ * dma_async_memcpy_pg_to_pg - offloaded copy from page to page
+ * @chan: DMA channel to offload copy to
+ * @dest_pg: destination page
+ * @dest_off: offset in page to copy to
+ * @src_pg: source page
+ * @src_off: offset in page to copy from
+ * @len: length
+ *
+ * Both @dest_page/@dest_off and @src_page/@src_off must be mappable to a bus
+ * address according to the DMA mapping API rules for streaming mappings.
+ * Both @dest_page/@dest_off and @src_page/@src_off must stay memory resident
+ * (kernel memory or locked user space pages).
+ */
+dma_cookie_t
+dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg,
+ unsigned int dest_off, struct page *src_pg, unsigned int src_off,
+ size_t len)
+{
+ struct dma_device *dev = chan->device;
+ struct dma_async_tx_descriptor *tx;
+ dma_addr_t addr;
+ dma_cookie_t cookie;
+ int cpu;
+
+ tx = dev->device_prep_dma_memcpy(chan, len, 0);
+ if (!tx)
+ return -ENOMEM;
+
+ tx->ack = 1;
+ tx->callback = NULL;
+ addr = dma_map_page(dev->dev, src_pg, src_off, len, DMA_TO_DEVICE);
+ tx->tx_set_src(addr, tx, 0);
+ addr = dma_map_page(dev->dev, dest_pg, dest_off, len, DMA_FROM_DEVICE);
+ tx->tx_set_dest(addr, tx, 0);
+ cookie = tx->tx_submit(tx);
+
+ cpu = get_cpu();
+ per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
+ per_cpu_ptr(chan->local, cpu)->memcpy_count++;
+ put_cpu();
+
+ return cookie;
+}
+EXPORT_SYMBOL(dma_async_memcpy_pg_to_pg);
+
+void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
+ struct dma_chan *chan)
+{
+ tx->chan = chan;
+ spin_lock_init(&tx->lock);
+ INIT_LIST_HEAD(&tx->depend_node);
+ INIT_LIST_HEAD(&tx->depend_list);
+}
+EXPORT_SYMBOL(dma_async_tx_descriptor_init);
+
static int __init dma_bus_init(void)
{
mutex_init(&dma_list_mutex);
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index 850014139556..5fbe56b5cea0 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -32,16 +32,17 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include "ioatdma.h"
-#include "ioatdma_io.h"
#include "ioatdma_registers.h"
#include "ioatdma_hw.h"
#define to_ioat_chan(chan) container_of(chan, struct ioat_dma_chan, common)
#define to_ioat_device(dev) container_of(dev, struct ioat_device, common)
#define to_ioat_desc(lh) container_of(lh, struct ioat_desc_sw, node)
+#define tx_to_ioat_desc(tx) container_of(tx, struct ioat_desc_sw, async_tx)
/* internal functions */
static int __devinit ioat_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void ioat_shutdown(struct pci_dev *pdev);
static void __devexit ioat_remove(struct pci_dev *pdev);
static int enumerate_dma_channels(struct ioat_device *device)
@@ -51,8 +52,8 @@ static int enumerate_dma_channels(struct ioat_device *device)
int i;
struct ioat_dma_chan *ioat_chan;
- device->common.chancnt = ioatdma_read8(device, IOAT_CHANCNT_OFFSET);
- xfercap_scale = ioatdma_read8(device, IOAT_XFERCAP_OFFSET);
+ device->common.chancnt = readb(device->reg_base + IOAT_CHANCNT_OFFSET);
+ xfercap_scale = readb(device->reg_base + IOAT_XFERCAP_OFFSET);
xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
for (i = 0; i < device->common.chancnt; i++) {
@@ -71,13 +72,79 @@ static int enumerate_dma_channels(struct ioat_device *device)
INIT_LIST_HEAD(&ioat_chan->used_desc);
/* This should be made common somewhere in dmaengine.c */
ioat_chan->common.device = &device->common;
- ioat_chan->common.client = NULL;
list_add_tail(&ioat_chan->common.device_node,
&device->common.channels);
}
return device->common.chancnt;
}
+static void
+ioat_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index)
+{
+ struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx);
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
+
+ pci_unmap_addr_set(desc, src, addr);
+
+ list_for_each_entry(iter, &desc->async_tx.tx_list, node) {
+ iter->hw->src_addr = addr;
+ addr += ioat_chan->xfercap;
+ }
+
+}
+
+static void
+ioat_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx, int index)
+{
+ struct ioat_desc_sw *iter, *desc = tx_to_ioat_desc(tx);
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
+
+ pci_unmap_addr_set(desc, dst, addr);
+
+ list_for_each_entry(iter, &desc->async_tx.tx_list, node) {
+ iter->hw->dst_addr = addr;
+ addr += ioat_chan->xfercap;
+ }
+}
+
+static dma_cookie_t
+ioat_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(tx->chan);
+ struct ioat_desc_sw *desc = tx_to_ioat_desc(tx);
+ int append = 0;
+ dma_cookie_t cookie;
+ struct ioat_desc_sw *group_start;
+
+ group_start = list_entry(desc->async_tx.tx_list.next,
+ struct ioat_desc_sw, node);
+ spin_lock_bh(&ioat_chan->desc_lock);
+ /* cookie incr and addition to used_list must be atomic */
+ cookie = ioat_chan->common.cookie;
+ cookie++;
+ if (cookie < 0)
+ cookie = 1;
+ ioat_chan->common.cookie = desc->async_tx.cookie = cookie;
+
+ /* write address into NextDescriptor field of last desc in chain */
+ to_ioat_desc(ioat_chan->used_desc.prev)->hw->next =
+ group_start->async_tx.phys;
+ list_splice_init(&desc->async_tx.tx_list, ioat_chan->used_desc.prev);
+
+ ioat_chan->pending += desc->tx_cnt;
+ if (ioat_chan->pending >= 4) {
+ append = 1;
+ ioat_chan->pending = 0;
+ }
+ spin_unlock_bh(&ioat_chan->desc_lock);
+
+ if (append)
+ writeb(IOAT_CHANCMD_APPEND,
+ ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
+
+ return cookie;
+}
+
static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
struct ioat_dma_chan *ioat_chan,
gfp_t flags)
@@ -99,8 +166,13 @@ static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
}
memset(desc, 0, sizeof(*desc));
+ dma_async_tx_descriptor_init(&desc_sw->async_tx, &ioat_chan->common);
+ desc_sw->async_tx.tx_set_src = ioat_set_src;
+ desc_sw->async_tx.tx_set_dest = ioat_set_dest;
+ desc_sw->async_tx.tx_submit = ioat_tx_submit;
+ INIT_LIST_HEAD(&desc_sw->async_tx.tx_list);
desc_sw->hw = desc;
- desc_sw->phys = phys;
+ desc_sw->async_tx.phys = phys;
return desc_sw;
}
@@ -123,7 +195,7 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
* In-use bit automatically set by reading chanctrl
* If 0, we got it, if 1, someone else did
*/
- chanctrl = ioatdma_chan_read16(ioat_chan, IOAT_CHANCTRL_OFFSET);
+ chanctrl = readw(ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
if (chanctrl & IOAT_CHANCTRL_CHANNEL_IN_USE)
return -EBUSY;
@@ -132,12 +204,12 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
IOAT_CHANCTRL_ERR_INT_EN |
IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
IOAT_CHANCTRL_ERR_COMPLETION_EN;
- ioatdma_chan_write16(ioat_chan, IOAT_CHANCTRL_OFFSET, chanctrl);
+ writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
- chanerr = ioatdma_chan_read32(ioat_chan, IOAT_CHANERR_OFFSET);
+ chanerr = readl(ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
if (chanerr) {
printk("IOAT: CHANERR = %x, clearing\n", chanerr);
- ioatdma_chan_write32(ioat_chan, IOAT_CHANERR_OFFSET, chanerr);
+ writel(chanerr, ioat_chan->reg_base + IOAT_CHANERR_OFFSET);
}
/* Allocate descriptors */
@@ -161,10 +233,10 @@ static int ioat_dma_alloc_chan_resources(struct dma_chan *chan)
&ioat_chan->completion_addr);
memset(ioat_chan->completion_virt, 0,
sizeof(*ioat_chan->completion_virt));
- ioatdma_chan_write32(ioat_chan, IOAT_CHANCMP_OFFSET_LOW,
- ((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF);
- ioatdma_chan_write32(ioat_chan, IOAT_CHANCMP_OFFSET_HIGH,
- ((u64) ioat_chan->completion_addr) >> 32);
+ writel(((u64) ioat_chan->completion_addr) & 0x00000000FFFFFFFF,
+ ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_LOW);
+ writel(((u64) ioat_chan->completion_addr) >> 32,
+ ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
ioat_start_null_desc(ioat_chan);
return i;
@@ -182,18 +254,20 @@ static void ioat_dma_free_chan_resources(struct dma_chan *chan)
ioat_dma_memcpy_cleanup(ioat_chan);
- ioatdma_chan_write8(ioat_chan, IOAT_CHANCMD_OFFSET, IOAT_CHANCMD_RESET);
+ writeb(IOAT_CHANCMD_RESET, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
spin_lock_bh(&ioat_chan->desc_lock);
list_for_each_entry_safe(desc, _desc, &ioat_chan->used_desc, node) {
in_use_descs++;
list_del(&desc->node);
- pci_pool_free(ioat_device->dma_pool, desc->hw, desc->phys);
+ pci_pool_free(ioat_device->dma_pool, desc->hw,
+ desc->async_tx.phys);
kfree(desc);
}
list_for_each_entry_safe(desc, _desc, &ioat_chan->free_desc, node) {
list_del(&desc->node);
- pci_pool_free(ioat_device->dma_pool, desc->hw, desc->phys);
+ pci_pool_free(ioat_device->dma_pool, desc->hw,
+ desc->async_tx.phys);
kfree(desc);
}
spin_unlock_bh(&ioat_chan->desc_lock);
@@ -210,50 +284,30 @@ static void ioat_dma_free_chan_resources(struct dma_chan *chan)
ioat_chan->last_completion = ioat_chan->completion_addr = 0;
/* Tell hw the chan is free */
- chanctrl = ioatdma_chan_read16(ioat_chan, IOAT_CHANCTRL_OFFSET);
+ chanctrl = readw(ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
chanctrl &= ~IOAT_CHANCTRL_CHANNEL_IN_USE;
- ioatdma_chan_write16(ioat_chan, IOAT_CHANCTRL_OFFSET, chanctrl);
+ writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
}
-/**
- * do_ioat_dma_memcpy - actual function that initiates a IOAT DMA transaction
- * @ioat_chan: IOAT DMA channel handle
- * @dest: DMA destination address
- * @src: DMA source address
- * @len: transaction length in bytes
- */
-
-static dma_cookie_t do_ioat_dma_memcpy(struct ioat_dma_chan *ioat_chan,
- dma_addr_t dest,
- dma_addr_t src,
- size_t len)
+static struct dma_async_tx_descriptor *
+ioat_dma_prep_memcpy(struct dma_chan *chan, size_t len, int int_en)
{
- struct ioat_desc_sw *first;
- struct ioat_desc_sw *prev;
- struct ioat_desc_sw *new;
- dma_cookie_t cookie;
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ struct ioat_desc_sw *first, *prev, *new;
LIST_HEAD(new_chain);
u32 copy;
size_t orig_len;
- dma_addr_t orig_src, orig_dst;
- unsigned int desc_count = 0;
- unsigned int append = 0;
-
- if (!ioat_chan || !dest || !src)
- return -EFAULT;
+ int desc_count = 0;
if (!len)
- return ioat_chan->common.cookie;
+ return NULL;
orig_len = len;
- orig_src = src;
- orig_dst = dest;
first = NULL;
prev = NULL;
spin_lock_bh(&ioat_chan->desc_lock);
-
while (len) {
if (!list_empty(&ioat_chan->free_desc)) {
new = to_ioat_desc(ioat_chan->free_desc.next);
@@ -270,141 +324,36 @@ static dma_cookie_t do_ioat_dma_memcpy(struct ioat_dma_chan *ioat_chan,
new->hw->size = copy;
new->hw->ctl = 0;
- new->hw->src_addr = src;
- new->hw->dst_addr = dest;
- new->cookie = 0;
+ new->async_tx.cookie = 0;
+ new->async_tx.ack = 1;
/* chain together the physical address list for the HW */
if (!first)
first = new;
else
- prev->hw->next = (u64) new->phys;
+ prev->hw->next = (u64) new->async_tx.phys;
prev = new;
-
len -= copy;
- dest += copy;
- src += copy;
-
list_add_tail(&new->node, &new_chain);
desc_count++;
}
- new->hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
- new->hw->next = 0;
- /* cookie incr and addition to used_list must be atomic */
+ list_splice(&new_chain, &new->async_tx.tx_list);
- cookie = ioat_chan->common.cookie;
- cookie++;
- if (cookie < 0)
- cookie = 1;
- ioat_chan->common.cookie = new->cookie = cookie;
+ new->hw->ctl = IOAT_DMA_DESCRIPTOR_CTL_CP_STS;
+ new->hw->next = 0;
+ new->tx_cnt = desc_count;
+ new->async_tx.ack = 0; /* client is in control of this ack */
+ new->async_tx.cookie = -EBUSY;
- pci_unmap_addr_set(new, src, orig_src);
- pci_unmap_addr_set(new, dst, orig_dst);
pci_unmap_len_set(new, src_len, orig_len);
pci_unmap_len_set(new, dst_len, orig_len);
-
- /* write address into NextDescriptor field of last desc in chain */
- to_ioat_desc(ioat_chan->used_desc.prev)->hw->next = first->phys;
- list_splice_init(&new_chain, ioat_chan->used_desc.prev);
-
- ioat_chan->pending += desc_count;
- if (ioat_chan->pending >= 20) {
- append = 1;
- ioat_chan->pending = 0;
- }
-
spin_unlock_bh(&ioat_chan->desc_lock);
- if (append)
- ioatdma_chan_write8(ioat_chan,
- IOAT_CHANCMD_OFFSET,
- IOAT_CHANCMD_APPEND);
- return cookie;
-}
-
-/**
- * ioat_dma_memcpy_buf_to_buf - wrapper that takes src & dest bufs
- * @chan: IOAT DMA channel handle
- * @dest: DMA destination address
- * @src: DMA source address
- * @len: transaction length in bytes
- */
-
-static dma_cookie_t ioat_dma_memcpy_buf_to_buf(struct dma_chan *chan,
- void *dest,
- void *src,
- size_t len)
-{
- dma_addr_t dest_addr;
- dma_addr_t src_addr;
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
-
- dest_addr = pci_map_single(ioat_chan->device->pdev,
- dest, len, PCI_DMA_FROMDEVICE);
- src_addr = pci_map_single(ioat_chan->device->pdev,
- src, len, PCI_DMA_TODEVICE);
-
- return do_ioat_dma_memcpy(ioat_chan, dest_addr, src_addr, len);
+ return new ? &new->async_tx : NULL;
}
-/**
- * ioat_dma_memcpy_buf_to_pg - wrapper, copying from a buf to a page
- * @chan: IOAT DMA channel handle
- * @page: pointer to the page to copy to
- * @offset: offset into that page
- * @src: DMA source address
- * @len: transaction length in bytes
- */
-
-static dma_cookie_t ioat_dma_memcpy_buf_to_pg(struct dma_chan *chan,
- struct page *page,
- unsigned int offset,
- void *src,
- size_t len)
-{
- dma_addr_t dest_addr;
- dma_addr_t src_addr;
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
-
- dest_addr = pci_map_page(ioat_chan->device->pdev,
- page, offset, len, PCI_DMA_FROMDEVICE);
- src_addr = pci_map_single(ioat_chan->device->pdev,
- src, len, PCI_DMA_TODEVICE);
-
- return do_ioat_dma_memcpy(ioat_chan, dest_addr, src_addr, len);
-}
-
-/**
- * ioat_dma_memcpy_pg_to_pg - wrapper, copying between two pages
- * @chan: IOAT DMA channel handle
- * @dest_pg: pointer to the page to copy to
- * @dest_off: offset into that page
- * @src_pg: pointer to the page to copy from
- * @src_off: offset into that page
- * @len: transaction length in bytes. This is guaranteed not to make a copy
- * across a page boundary.
- */
-
-static dma_cookie_t ioat_dma_memcpy_pg_to_pg(struct dma_chan *chan,
- struct page *dest_pg,
- unsigned int dest_off,
- struct page *src_pg,
- unsigned int src_off,
- size_t len)
-{
- dma_addr_t dest_addr;
- dma_addr_t src_addr;
- struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
-
- dest_addr = pci_map_page(ioat_chan->device->pdev,
- dest_pg, dest_off, len, PCI_DMA_FROMDEVICE);
- src_addr = pci_map_page(ioat_chan->device->pdev,
- src_pg, src_off, len, PCI_DMA_TODEVICE);
-
- return do_ioat_dma_memcpy(ioat_chan, dest_addr, src_addr, len);
-}
/**
* ioat_dma_memcpy_issue_pending - push potentially unrecognized appended descriptors to hw
@@ -417,9 +366,8 @@ static void ioat_dma_memcpy_issue_pending(struct dma_chan *chan)
if (ioat_chan->pending != 0) {
ioat_chan->pending = 0;
- ioatdma_chan_write8(ioat_chan,
- IOAT_CHANCMD_OFFSET,
- IOAT_CHANCMD_APPEND);
+ writeb(IOAT_CHANCMD_APPEND,
+ ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
}
}
@@ -449,7 +397,7 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
if ((chan->completion_virt->full & IOAT_CHANSTS_DMA_TRANSFER_STATUS) ==
IOAT_CHANSTS_DMA_TRANSFER_STATUS_HALTED) {
printk("IOAT: Channel halted, chanerr = %x\n",
- ioatdma_chan_read32(chan, IOAT_CHANERR_OFFSET));
+ readl(chan->reg_base + IOAT_CHANERR_OFFSET));
/* TODO do something to salvage the situation */
}
@@ -467,8 +415,8 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
* exceeding xfercap, perhaps. If so, only the last one will
* have a cookie, and require unmapping.
*/
- if (desc->cookie) {
- cookie = desc->cookie;
+ if (desc->async_tx.cookie) {
+ cookie = desc->async_tx.cookie;
/* yes we are unmapping both _page and _single alloc'd
regions with unmap_page. Is this *really* that bad?
@@ -483,14 +431,19 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
PCI_DMA_TODEVICE);
}
- if (desc->phys != phys_complete) {
- /* a completed entry, but not the last, so cleanup */
- list_del(&desc->node);
- list_add_tail(&desc->node, &chan->free_desc);
+ if (desc->async_tx.phys != phys_complete) {
+ /* a completed entry, but not the last, so cleanup
+ * if the client is done with the descriptor
+ */
+ if (desc->async_tx.ack) {
+ list_del(&desc->node);
+ list_add_tail(&desc->node, &chan->free_desc);
+ } else
+ desc->async_tx.cookie = 0;
} else {
/* last used desc. Do not remove, so we can append from
it, but don't look at it next time, either */
- desc->cookie = 0;
+ desc->async_tx.cookie = 0;
/* TODO check status bits? */
break;
@@ -506,6 +459,17 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
spin_unlock(&chan->cleanup_lock);
}
+static void ioat_dma_dependency_added(struct dma_chan *chan)
+{
+ struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan);
+ spin_lock_bh(&ioat_chan->desc_lock);
+ if (ioat_chan->pending == 0) {
+ spin_unlock_bh(&ioat_chan->desc_lock);
+ ioat_dma_memcpy_cleanup(ioat_chan);
+ } else
+ spin_unlock_bh(&ioat_chan->desc_lock);
+}
+
/**
* ioat_dma_is_complete - poll the status of a IOAT DMA transaction
* @chan: IOAT DMA channel handle
@@ -553,6 +517,8 @@ static enum dma_status ioat_dma_is_complete(struct dma_chan *chan,
static struct pci_device_id ioat_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
+ { PCI_DEVICE(PCI_VENDOR_ID_UNISYS,
+ PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
{ 0, }
};
@@ -560,6 +526,7 @@ static struct pci_driver ioat_pci_driver = {
.name = "ioatdma",
.id_table = ioat_pci_tbl,
.probe = ioat_probe,
+ .shutdown = ioat_shutdown,
.remove = __devexit_p(ioat_remove),
};
@@ -569,21 +536,21 @@ static irqreturn_t ioat_do_interrupt(int irq, void *data)
unsigned long attnstatus;
u8 intrctrl;
- intrctrl = ioatdma_read8(instance, IOAT_INTRCTRL_OFFSET);
+ intrctrl = readb(instance->reg_base + IOAT_INTRCTRL_OFFSET);
if (!(intrctrl & IOAT_INTRCTRL_MASTER_INT_EN))
return IRQ_NONE;
if (!(intrctrl & IOAT_INTRCTRL_INT_STATUS)) {
- ioatdma_write8(instance, IOAT_INTRCTRL_OFFSET, intrctrl);
+ writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
return IRQ_NONE;
}
- attnstatus = ioatdma_read32(instance, IOAT_ATTNSTATUS_OFFSET);
+ attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET);
printk(KERN_ERR "ioatdma error: interrupt! status %lx\n", attnstatus);
- ioatdma_write8(instance, IOAT_INTRCTRL_OFFSET, intrctrl);
+ writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET);
return IRQ_HANDLED;
}
@@ -607,19 +574,17 @@ static void ioat_start_null_desc(struct ioat_dma_chan *ioat_chan)
desc->hw->ctl = IOAT_DMA_DESCRIPTOR_NUL;
desc->hw->next = 0;
+ desc->async_tx.ack = 1;
list_add_tail(&desc->node, &ioat_chan->used_desc);
spin_unlock_bh(&ioat_chan->desc_lock);
-#if (BITS_PER_LONG == 64)
- ioatdma_chan_write64(ioat_chan, IOAT_CHAINADDR_OFFSET, desc->phys);
-#else
- ioatdma_chan_write32(ioat_chan,
- IOAT_CHAINADDR_OFFSET_LOW,
- (u32) desc->phys);
- ioatdma_chan_write32(ioat_chan, IOAT_CHAINADDR_OFFSET_HIGH, 0);
-#endif
- ioatdma_chan_write8(ioat_chan, IOAT_CHANCMD_OFFSET, IOAT_CHANCMD_START);
+ writel(((u64) desc->async_tx.phys) & 0x00000000FFFFFFFF,
+ ioat_chan->reg_base + IOAT_CHAINADDR_OFFSET_LOW);
+ writel(((u64) desc->async_tx.phys) >> 32,
+ ioat_chan->reg_base + IOAT_CHAINADDR_OFFSET_HIGH);
+
+ writeb(IOAT_CHANCMD_START, ioat_chan->reg_base + IOAT_CHANCMD_OFFSET);
}
/*
@@ -633,6 +598,8 @@ static int ioat_self_test(struct ioat_device *device)
u8 *src;
u8 *dest;
struct dma_chan *dma_chan;
+ struct dma_async_tx_descriptor *tx;
+ dma_addr_t addr;
dma_cookie_t cookie;
int err = 0;
@@ -658,7 +625,15 @@ static int ioat_self_test(struct ioat_device *device)
goto out;
}
- cookie = ioat_dma_memcpy_buf_to_buf(dma_chan, dest, src, IOAT_TEST_SIZE);
+ tx = ioat_dma_prep_memcpy(dma_chan, IOAT_TEST_SIZE, 0);
+ async_tx_ack(tx);
+ addr = dma_map_single(dma_chan->device->dev, src, IOAT_TEST_SIZE,
+ DMA_TO_DEVICE);
+ ioat_set_src(addr, tx, 0);
+ addr = dma_map_single(dma_chan->device->dev, dest, IOAT_TEST_SIZE,
+ DMA_FROM_DEVICE);
+ ioat_set_dest(addr, tx, 0);
+ cookie = ioat_tx_submit(tx);
ioat_dma_memcpy_issue_pending(dma_chan);
msleep(1);
@@ -748,19 +723,20 @@ static int __devinit ioat_probe(struct pci_dev *pdev,
device->reg_base = reg_base;
- ioatdma_write8(device, IOAT_INTRCTRL_OFFSET, IOAT_INTRCTRL_MASTER_INT_EN);
+ writeb(IOAT_INTRCTRL_MASTER_INT_EN, device->reg_base + IOAT_INTRCTRL_OFFSET);
pci_set_master(pdev);
INIT_LIST_HEAD(&device->common.channels);
enumerate_dma_channels(device);
+ dma_cap_set(DMA_MEMCPY, device->common.cap_mask);
device->common.device_alloc_chan_resources = ioat_dma_alloc_chan_resources;
device->common.device_free_chan_resources = ioat_dma_free_chan_resources;
- device->common.device_memcpy_buf_to_buf = ioat_dma_memcpy_buf_to_buf;
- device->common.device_memcpy_buf_to_pg = ioat_dma_memcpy_buf_to_pg;
- device->common.device_memcpy_pg_to_pg = ioat_dma_memcpy_pg_to_pg;
- device->common.device_memcpy_complete = ioat_dma_is_complete;
- device->common.device_memcpy_issue_pending = ioat_dma_memcpy_issue_pending;
+ device->common.device_prep_dma_memcpy = ioat_dma_prep_memcpy;
+ device->common.device_is_tx_complete = ioat_dma_is_complete;
+ device->common.device_issue_pending = ioat_dma_memcpy_issue_pending;
+ device->common.device_dependency_added = ioat_dma_dependency_added;
+ device->common.dev = &pdev->dev;
printk(KERN_INFO "Intel(R) I/OAT DMA Engine found, %d channels\n",
device->common.chancnt);
@@ -787,9 +763,20 @@ err_request_regions:
err_set_dma_mask:
pci_disable_device(pdev);
err_enable_device:
+
+ printk(KERN_ERR "Intel(R) I/OAT DMA Engine initialization failed\n");
+
return err;
}
+static void ioat_shutdown(struct pci_dev *pdev)
+{
+ struct ioat_device *device;
+ device = pci_get_drvdata(pdev);
+
+ dma_async_device_unregister(&device->common);
+}
+
static void __devexit ioat_remove(struct pci_dev *pdev)
{
struct ioat_device *device;
@@ -818,7 +805,7 @@ static void __devexit ioat_remove(struct pci_dev *pdev)
}
/* MODULE API */
-MODULE_VERSION("1.7");
+MODULE_VERSION("1.9");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Intel Corporation");
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
index 62b26a9be4c9..d3726478031a 100644
--- a/drivers/dma/ioatdma.h
+++ b/drivers/dma/ioatdma.h
@@ -30,9 +30,6 @@
#define IOAT_LOW_COMPLETION_MASK 0xffffffc0
-extern struct list_head dma_device_list;
-extern struct list_head dma_client_list;
-
/**
* struct ioat_device - internal representation of a IOAT device
* @pdev: PCI-Express device
@@ -105,21 +102,20 @@ struct ioat_dma_chan {
/**
* struct ioat_desc_sw - wrapper around hardware descriptor
* @hw: hardware DMA descriptor
- * @node:
- * @cookie:
- * @phys:
+ * @node: this descriptor will either be on the free list,
+ * or attached to a transaction list (async_tx.tx_list)
+ * @tx_cnt: number of descriptors required to complete the transaction
+ * @async_tx: the generic software descriptor for all engines
*/
-
struct ioat_desc_sw {
struct ioat_dma_descriptor *hw;
struct list_head node;
- dma_cookie_t cookie;
- dma_addr_t phys;
+ int tx_cnt;
DECLARE_PCI_UNMAP_ADDR(src)
DECLARE_PCI_UNMAP_LEN(src_len)
DECLARE_PCI_UNMAP_ADDR(dst)
DECLARE_PCI_UNMAP_LEN(dst_len)
+ struct dma_async_tx_descriptor async_tx;
};
#endif /* IOATDMA_H */
-
diff --git a/drivers/dma/ioatdma_io.h b/drivers/dma/ioatdma_io.h
deleted file mode 100644
index c0b4bf66c920..000000000000
--- a/drivers/dma/ioatdma_io.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The full GNU General Public License is included in this distribution in the
- * file called COPYING.
- */
-#ifndef IOATDMA_IO_H
-#define IOATDMA_IO_H
-
-#include <asm/io.h>
-
-/*
- * device and per-channel MMIO register read and write functions
- * this is a lot of anoying inline functions, but it's typesafe
- */
-
-static inline u8 ioatdma_read8(struct ioat_device *device,
- unsigned int offset)
-{
- return readb(device->reg_base + offset);
-}
-
-static inline u16 ioatdma_read16(struct ioat_device *device,
- unsigned int offset)
-{
- return readw(device->reg_base + offset);
-}
-
-static inline u32 ioatdma_read32(struct ioat_device *device,
- unsigned int offset)
-{
- return readl(device->reg_base + offset);
-}
-
-static inline void ioatdma_write8(struct ioat_device *device,
- unsigned int offset, u8 value)
-{
- writeb(value, device->reg_base + offset);
-}
-
-static inline void ioatdma_write16(struct ioat_device *device,
- unsigned int offset, u16 value)
-{
- writew(value, device->reg_base + offset);
-}
-
-static inline void ioatdma_write32(struct ioat_device *device,
- unsigned int offset, u32 value)
-{
- writel(value, device->reg_base + offset);
-}
-
-static inline u8 ioatdma_chan_read8(struct ioat_dma_chan *chan,
- unsigned int offset)
-{
- return readb(chan->reg_base + offset);
-}
-
-static inline u16 ioatdma_chan_read16(struct ioat_dma_chan *chan,
- unsigned int offset)
-{
- return readw(chan->reg_base + offset);
-}
-
-static inline u32 ioatdma_chan_read32(struct ioat_dma_chan *chan,
- unsigned int offset)
-{
- return readl(chan->reg_base + offset);
-}
-
-static inline void ioatdma_chan_write8(struct ioat_dma_chan *chan,
- unsigned int offset, u8 value)
-{
- writeb(value, chan->reg_base + offset);
-}
-
-static inline void ioatdma_chan_write16(struct ioat_dma_chan *chan,
- unsigned int offset, u16 value)
-{
- writew(value, chan->reg_base + offset);
-}
-
-static inline void ioatdma_chan_write32(struct ioat_dma_chan *chan,
- unsigned int offset, u32 value)
-{
- writel(value, chan->reg_base + offset);
-}
-
-#if (BITS_PER_LONG == 64)
-static inline u64 ioatdma_chan_read64(struct ioat_dma_chan *chan,
- unsigned int offset)
-{
- return readq(chan->reg_base + offset);
-}
-
-static inline void ioatdma_chan_write64(struct ioat_dma_chan *chan,
- unsigned int offset, u64 value)
-{
- writeq(value, chan->reg_base + offset);
-}
-#endif
-
-#endif /* IOATDMA_IO_H */
-
diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c
new file mode 100644
index 000000000000..5a1d426744d6
--- /dev/null
+++ b/drivers/dma/iop-adma.c
@@ -0,0 +1,1467 @@
+/*
+ * offload engine driver for the Intel Xscale series of i/o processors
+ * Copyright © 2006, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+/*
+ * This driver supports the asynchrounous DMA copy and RAID engines available
+ * on the Intel Xscale(R) family of I/O Processors (IOP 32x, 33x, 134x)
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/async_tx.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/memory.h>
+#include <linux/ioport.h>
+
+#include <asm/arch/adma.h>
+
+#define to_iop_adma_chan(chan) container_of(chan, struct iop_adma_chan, common)
+#define to_iop_adma_device(dev) \
+ container_of(dev, struct iop_adma_device, common)
+#define tx_to_iop_adma_slot(tx) \
+ container_of(tx, struct iop_adma_desc_slot, async_tx)
+
+/**
+ * iop_adma_free_slots - flags descriptor slots for reuse
+ * @slot: Slot to free
+ * Caller must hold &iop_chan->lock while calling this function
+ */
+static void iop_adma_free_slots(struct iop_adma_desc_slot *slot)
+{
+ int stride = slot->slots_per_op;
+
+ while (stride--) {
+ slot->slots_per_op = 0;
+ slot = list_entry(slot->slot_node.next,
+ struct iop_adma_desc_slot,
+ slot_node);
+ }
+}
+
+static dma_cookie_t
+iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *iop_chan, dma_cookie_t cookie)
+{
+ BUG_ON(desc->async_tx.cookie < 0);
+ spin_lock_bh(&desc->async_tx.lock);
+ if (desc->async_tx.cookie > 0) {
+ cookie = desc->async_tx.cookie;
+ desc->async_tx.cookie = 0;
+
+ /* call the callback (must not sleep or submit new
+ * operations to this channel)
+ */
+ if (desc->async_tx.callback)
+ desc->async_tx.callback(
+ desc->async_tx.callback_param);
+
+ /* unmap dma addresses
+ * (unmap_single vs unmap_page?)
+ */
+ if (desc->group_head && desc->unmap_len) {
+ struct iop_adma_desc_slot *unmap = desc->group_head;
+ struct device *dev =
+ &iop_chan->device->pdev->dev;
+ u32 len = unmap->unmap_len;
+ u32 src_cnt = unmap->unmap_src_cnt;
+ dma_addr_t addr = iop_desc_get_dest_addr(unmap,
+ iop_chan);
+
+ dma_unmap_page(dev, addr, len, DMA_FROM_DEVICE);
+ while (src_cnt--) {
+ addr = iop_desc_get_src_addr(unmap,
+ iop_chan,
+ src_cnt);
+ dma_unmap_page(dev, addr, len,
+ DMA_TO_DEVICE);
+ }
+ desc->group_head = NULL;
+ }
+ }
+
+ /* run dependent operations */
+ async_tx_run_dependencies(&desc->async_tx);
+ spin_unlock_bh(&desc->async_tx.lock);
+
+ return cookie;
+}
+
+static int
+iop_adma_clean_slot(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *iop_chan)
+{
+ /* the client is allowed to attach dependent operations
+ * until 'ack' is set
+ */
+ if (!desc->async_tx.ack)
+ return 0;
+
+ /* leave the last descriptor in the chain
+ * so we can append to it
+ */
+ if (desc->chain_node.next == &iop_chan->chain)
+ return 1;
+
+ dev_dbg(iop_chan->device->common.dev,
+ "\tfree slot: %d slots_per_op: %d\n",
+ desc->idx, desc->slots_per_op);
+
+ list_del(&desc->chain_node);
+ iop_adma_free_slots(desc);
+
+ return 0;
+}
+
+static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
+{
+ struct iop_adma_desc_slot *iter, *_iter, *grp_start = NULL;
+ dma_cookie_t cookie = 0;
+ u32 current_desc = iop_chan_get_current_descriptor(iop_chan);
+ int busy = iop_chan_is_busy(iop_chan);
+ int seen_current = 0, slot_cnt = 0, slots_per_op = 0;
+
+ dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__);
+ /* free completed slots from the chain starting with
+ * the oldest descriptor
+ */
+ list_for_each_entry_safe(iter, _iter, &iop_chan->chain,
+ chain_node) {
+ pr_debug("\tcookie: %d slot: %d busy: %d "
+ "this_desc: %#x next_desc: %#x ack: %d\n",
+ iter->async_tx.cookie, iter->idx, busy,
+ iter->async_tx.phys, iop_desc_get_next_desc(iter),
+ iter->async_tx.ack);
+ prefetch(_iter);
+ prefetch(&_iter->async_tx);
+
+ /* do not advance past the current descriptor loaded into the
+ * hardware channel, subsequent descriptors are either in
+ * process or have not been submitted
+ */
+ if (seen_current)
+ break;
+
+ /* stop the search if we reach the current descriptor and the
+ * channel is busy, or if it appears that the current descriptor
+ * needs to be re-read (i.e. has been appended to)
+ */
+ if (iter->async_tx.phys == current_desc) {
+ BUG_ON(seen_current++);
+ if (busy || iop_desc_get_next_desc(iter))
+ break;
+ }
+
+ /* detect the start of a group transaction */
+ if (!slot_cnt && !slots_per_op) {
+ slot_cnt = iter->slot_cnt;
+ slots_per_op = iter->slots_per_op;
+ if (slot_cnt <= slots_per_op) {
+ slot_cnt = 0;
+ slots_per_op = 0;
+ }
+ }
+
+ if (slot_cnt) {
+ pr_debug("\tgroup++\n");
+ if (!grp_start)
+ grp_start = iter;
+ slot_cnt -= slots_per_op;
+ }
+
+ /* all the members of a group are complete */
+ if (slots_per_op != 0 && slot_cnt == 0) {
+ struct iop_adma_desc_slot *grp_iter, *_grp_iter;
+ int end_of_chain = 0;
+ pr_debug("\tgroup end\n");
+
+ /* collect the total results */
+ if (grp_start->xor_check_result) {
+ u32 zero_sum_result = 0;
+ slot_cnt = grp_start->slot_cnt;
+ grp_iter = grp_start;
+
+ list_for_each_entry_from(grp_iter,
+ &iop_chan->chain, chain_node) {
+ zero_sum_result |=
+ iop_desc_get_zero_result(grp_iter);
+ pr_debug("\titer%d result: %d\n",
+ grp_iter->idx, zero_sum_result);
+ slot_cnt -= slots_per_op;
+ if (slot_cnt == 0)
+ break;
+ }
+ pr_debug("\tgrp_start->xor_check_result: %p\n",
+ grp_start->xor_check_result);
+ *grp_start->xor_check_result = zero_sum_result;
+ }
+
+ /* clean up the group */
+ slot_cnt = grp_start->slot_cnt;
+ grp_iter = grp_start;
+ list_for_each_entry_safe_from(grp_iter, _grp_iter,
+ &iop_chan->chain, chain_node) {
+ cookie = iop_adma_run_tx_complete_actions(
+ grp_iter, iop_chan, cookie);
+
+ slot_cnt -= slots_per_op;
+ end_of_chain = iop_adma_clean_slot(grp_iter,
+ iop_chan);
+
+ if (slot_cnt == 0 || end_of_chain)
+ break;
+ }
+
+ /* the group should be complete at this point */
+ BUG_ON(slot_cnt);
+
+ slots_per_op = 0;
+ grp_start = NULL;
+ if (end_of_chain)
+ break;
+ else
+ continue;
+ } else if (slots_per_op) /* wait for group completion */
+ continue;
+
+ /* write back zero sum results (single descriptor case) */
+ if (iter->xor_check_result && iter->async_tx.cookie)
+ *iter->xor_check_result =
+ iop_desc_get_zero_result(iter);
+
+ cookie = iop_adma_run_tx_complete_actions(
+ iter, iop_chan, cookie);
+
+ if (iop_adma_clean_slot(iter, iop_chan))
+ break;
+ }
+
+ BUG_ON(!seen_current);
+
+ iop_chan_idle(busy, iop_chan);
+
+ if (cookie > 0) {
+ iop_chan->completed_cookie = cookie;
+ pr_debug("\tcompleted cookie %d\n", cookie);
+ }
+}
+
+static void
+iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan)
+{
+ spin_lock_bh(&iop_chan->lock);
+ __iop_adma_slot_cleanup(iop_chan);
+ spin_unlock_bh(&iop_chan->lock);
+}
+
+static void iop_adma_tasklet(unsigned long data)
+{
+ struct iop_adma_chan *chan = (struct iop_adma_chan *) data;
+ __iop_adma_slot_cleanup(chan);
+}
+
+static struct iop_adma_desc_slot *
+iop_adma_alloc_slots(struct iop_adma_chan *iop_chan, int num_slots,
+ int slots_per_op)
+{
+ struct iop_adma_desc_slot *iter, *_iter, *alloc_start = NULL;
+ struct list_head chain = LIST_HEAD_INIT(chain);
+ int slots_found, retry = 0;
+
+ /* start search from the last allocated descrtiptor
+ * if a contiguous allocation can not be found start searching
+ * from the beginning of the list
+ */
+retry:
+ slots_found = 0;
+ if (retry == 0)
+ iter = iop_chan->last_used;
+ else
+ iter = list_entry(&iop_chan->all_slots,
+ struct iop_adma_desc_slot,
+ slot_node);
+
+ list_for_each_entry_safe_continue(
+ iter, _iter, &iop_chan->all_slots, slot_node) {
+ prefetch(_iter);
+ prefetch(&_iter->async_tx);
+ if (iter->slots_per_op) {
+ /* give up after finding the first busy slot
+ * on the second pass through the list
+ */
+ if (retry)
+ break;
+
+ slots_found = 0;
+ continue;
+ }
+
+ /* start the allocation if the slot is correctly aligned */
+ if (!slots_found++) {
+ if (iop_desc_is_aligned(iter, slots_per_op))
+ alloc_start = iter;
+ else {
+ slots_found = 0;
+ continue;
+ }
+ }
+
+ if (slots_found == num_slots) {
+ struct iop_adma_desc_slot *alloc_tail = NULL;
+ struct iop_adma_desc_slot *last_used = NULL;
+ iter = alloc_start;
+ while (num_slots) {
+ int i;
+ dev_dbg(iop_chan->device->common.dev,
+ "allocated slot: %d "
+ "(desc %p phys: %#x) slots_per_op %d\n",
+ iter->idx, iter->hw_desc,
+ iter->async_tx.phys, slots_per_op);
+
+ /* pre-ack all but the last descriptor */
+ if (num_slots != slots_per_op)
+ iter->async_tx.ack = 1;
+ else
+ iter->async_tx.ack = 0;
+
+ list_add_tail(&iter->chain_node, &chain);
+ alloc_tail = iter;
+ iter->async_tx.cookie = 0;
+ iter->slot_cnt = num_slots;
+ iter->xor_check_result = NULL;
+ for (i = 0; i < slots_per_op; i++) {
+ iter->slots_per_op = slots_per_op - i;
+ last_used = iter;
+ iter = list_entry(iter->slot_node.next,
+ struct iop_adma_desc_slot,
+ slot_node);
+ }
+ num_slots -= slots_per_op;
+ }
+ alloc_tail->group_head = alloc_start;
+ alloc_tail->async_tx.cookie = -EBUSY;
+ list_splice(&chain, &alloc_tail->async_tx.tx_list);
+ iop_chan->last_used = last_used;
+ iop_desc_clear_next_desc(alloc_start);
+ iop_desc_clear_next_desc(alloc_tail);
+ return alloc_tail;
+ }
+ }
+ if (!retry++)
+ goto retry;
+
+ /* try to free some slots if the allocation fails */
+ tasklet_schedule(&iop_chan->irq_tasklet);
+
+ return NULL;
+}
+
+static dma_cookie_t
+iop_desc_assign_cookie(struct iop_adma_chan *iop_chan,
+ struct iop_adma_desc_slot *desc)
+{
+ dma_cookie_t cookie = iop_chan->common.cookie;
+ cookie++;
+ if (cookie < 0)
+ cookie = 1;
+ iop_chan->common.cookie = desc->async_tx.cookie = cookie;
+ return cookie;
+}
+
+static void iop_adma_check_threshold(struct iop_adma_chan *iop_chan)
+{
+ dev_dbg(iop_chan->device->common.dev, "pending: %d\n",
+ iop_chan->pending);
+
+ if (iop_chan->pending >= IOP_ADMA_THRESHOLD) {
+ iop_chan->pending = 0;
+ iop_chan_append(iop_chan);
+ }
+}
+
+static dma_cookie_t
+iop_adma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(tx->chan);
+ struct iop_adma_desc_slot *grp_start, *old_chain_tail;
+ int slot_cnt;
+ int slots_per_op;
+ dma_cookie_t cookie;
+
+ grp_start = sw_desc->group_head;
+ slot_cnt = grp_start->slot_cnt;
+ slots_per_op = grp_start->slots_per_op;
+
+ spin_lock_bh(&iop_chan->lock);
+ cookie = iop_desc_assign_cookie(iop_chan, sw_desc);
+
+ old_chain_tail = list_entry(iop_chan->chain.prev,
+ struct iop_adma_desc_slot, chain_node);
+ list_splice_init(&sw_desc->async_tx.tx_list,
+ &old_chain_tail->chain_node);
+
+ /* fix up the hardware chain */
+ iop_desc_set_next_desc(old_chain_tail, grp_start->async_tx.phys);
+
+ /* 1/ don't add pre-chained descriptors
+ * 2/ dummy read to flush next_desc write
+ */
+ BUG_ON(iop_desc_get_next_desc(sw_desc));
+
+ /* increment the pending count by the number of slots
+ * memcpy operations have a 1:1 (slot:operation) relation
+ * other operations are heavier and will pop the threshold
+ * more often.
+ */
+ iop_chan->pending += slot_cnt;
+ iop_adma_check_threshold(iop_chan);
+ spin_unlock_bh(&iop_chan->lock);
+
+ dev_dbg(iop_chan->device->common.dev, "%s cookie: %d slot: %d\n",
+ __FUNCTION__, sw_desc->async_tx.cookie, sw_desc->idx);
+
+ return cookie;
+}
+
+static void
+iop_adma_set_dest(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
+ int index)
+{
+ struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(tx->chan);
+
+ /* to do: support transfers lengths > IOP_ADMA_MAX_BYTE_COUNT */
+ iop_desc_set_dest_addr(sw_desc->group_head, iop_chan, addr);
+}
+
+static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan);
+static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan);
+
+/* returns the number of allocated descriptors */
+static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
+{
+ char *hw_desc;
+ int idx;
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ struct iop_adma_desc_slot *slot = NULL;
+ int init = iop_chan->slots_allocated ? 0 : 1;
+ struct iop_adma_platform_data *plat_data =
+ iop_chan->device->pdev->dev.platform_data;
+ int num_descs_in_pool = plat_data->pool_size/IOP_ADMA_SLOT_SIZE;
+
+ /* Allocate descriptor slots */
+ do {
+ idx = iop_chan->slots_allocated;
+ if (idx == num_descs_in_pool)
+ break;
+
+ slot = kzalloc(sizeof(*slot), GFP_KERNEL);
+ if (!slot) {
+ printk(KERN_INFO "IOP ADMA Channel only initialized"
+ " %d descriptor slots", idx);
+ break;
+ }
+ hw_desc = (char *) iop_chan->device->dma_desc_pool_virt;
+ slot->hw_desc = (void *) &hw_desc[idx * IOP_ADMA_SLOT_SIZE];
+
+ dma_async_tx_descriptor_init(&slot->async_tx, chan);
+ slot->async_tx.tx_submit = iop_adma_tx_submit;
+ slot->async_tx.tx_set_dest = iop_adma_set_dest;
+ INIT_LIST_HEAD(&slot->chain_node);
+ INIT_LIST_HEAD(&slot->slot_node);
+ INIT_LIST_HEAD(&slot->async_tx.tx_list);
+ hw_desc = (char *) iop_chan->device->dma_desc_pool;
+ slot->async_tx.phys =
+ (dma_addr_t) &hw_desc[idx * IOP_ADMA_SLOT_SIZE];
+ slot->idx = idx;
+
+ spin_lock_bh(&iop_chan->lock);
+ iop_chan->slots_allocated++;
+ list_add_tail(&slot->slot_node, &iop_chan->all_slots);
+ spin_unlock_bh(&iop_chan->lock);
+ } while (iop_chan->slots_allocated < num_descs_in_pool);
+
+ if (idx && !iop_chan->last_used)
+ iop_chan->last_used = list_entry(iop_chan->all_slots.next,
+ struct iop_adma_desc_slot,
+ slot_node);
+
+ dev_dbg(iop_chan->device->common.dev,
+ "allocated %d descriptor slots last_used: %p\n",
+ iop_chan->slots_allocated, iop_chan->last_used);
+
+ /* initialize the channel and the chain with a null operation */
+ if (init) {
+ if (dma_has_cap(DMA_MEMCPY,
+ iop_chan->device->common.cap_mask))
+ iop_chan_start_null_memcpy(iop_chan);
+ else if (dma_has_cap(DMA_XOR,
+ iop_chan->device->common.cap_mask))
+ iop_chan_start_null_xor(iop_chan);
+ else
+ BUG();
+ }
+
+ return (idx > 0) ? idx : -ENOMEM;
+}
+
+static struct dma_async_tx_descriptor *
+iop_adma_prep_dma_interrupt(struct dma_chan *chan)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ struct iop_adma_desc_slot *sw_desc, *grp_start;
+ int slot_cnt, slots_per_op;
+
+ dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__);
+
+ spin_lock_bh(&iop_chan->lock);
+ slot_cnt = iop_chan_interrupt_slot_count(&slots_per_op, iop_chan);
+ sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
+ if (sw_desc) {
+ grp_start = sw_desc->group_head;
+ iop_desc_init_interrupt(grp_start, iop_chan);
+ grp_start->unmap_len = 0;
+ }
+ spin_unlock_bh(&iop_chan->lock);
+
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
+static void
+iop_adma_memcpy_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
+ int index)
+{
+ struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
+ struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
+
+ iop_desc_set_memcpy_src_addr(grp_start, addr);
+}
+
+static struct dma_async_tx_descriptor *
+iop_adma_prep_dma_memcpy(struct dma_chan *chan, size_t len, int int_en)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ struct iop_adma_desc_slot *sw_desc, *grp_start;
+ int slot_cnt, slots_per_op;
+
+ if (unlikely(!len))
+ return NULL;
+ BUG_ON(unlikely(len > IOP_ADMA_MAX_BYTE_COUNT));
+
+ dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
+ __FUNCTION__, len);
+
+ spin_lock_bh(&iop_chan->lock);
+ slot_cnt = iop_chan_memcpy_slot_count(len, &slots_per_op);
+ sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
+ if (sw_desc) {
+ grp_start = sw_desc->group_head;
+ iop_desc_init_memcpy(grp_start, int_en);
+ iop_desc_set_byte_count(grp_start, iop_chan, len);
+ sw_desc->unmap_src_cnt = 1;
+ sw_desc->unmap_len = len;
+ sw_desc->async_tx.tx_set_src = iop_adma_memcpy_set_src;
+ }
+ spin_unlock_bh(&iop_chan->lock);
+
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
+static struct dma_async_tx_descriptor *
+iop_adma_prep_dma_memset(struct dma_chan *chan, int value, size_t len,
+ int int_en)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ struct iop_adma_desc_slot *sw_desc, *grp_start;
+ int slot_cnt, slots_per_op;
+
+ if (unlikely(!len))
+ return NULL;
+ BUG_ON(unlikely(len > IOP_ADMA_MAX_BYTE_COUNT));
+
+ dev_dbg(iop_chan->device->common.dev, "%s len: %u\n",
+ __FUNCTION__, len);
+
+ spin_lock_bh(&iop_chan->lock);
+ slot_cnt = iop_chan_memset_slot_count(len, &slots_per_op);
+ sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
+ if (sw_desc) {
+ grp_start = sw_desc->group_head;
+ iop_desc_init_memset(grp_start, int_en);
+ iop_desc_set_byte_count(grp_start, iop_chan, len);
+ iop_desc_set_block_fill_val(grp_start, value);
+ sw_desc->unmap_src_cnt = 1;
+ sw_desc->unmap_len = len;
+ }
+ spin_unlock_bh(&iop_chan->lock);
+
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
+static void
+iop_adma_xor_set_src(dma_addr_t addr, struct dma_async_tx_descriptor *tx,
+ int index)
+{
+ struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
+ struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
+
+ iop_desc_set_xor_src_addr(grp_start, index, addr);
+}
+
+static struct dma_async_tx_descriptor *
+iop_adma_prep_dma_xor(struct dma_chan *chan, unsigned int src_cnt, size_t len,
+ int int_en)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ struct iop_adma_desc_slot *sw_desc, *grp_start;
+ int slot_cnt, slots_per_op;
+
+ if (unlikely(!len))
+ return NULL;
+ BUG_ON(unlikely(len > IOP_ADMA_XOR_MAX_BYTE_COUNT));
+
+ dev_dbg(iop_chan->device->common.dev,
+ "%s src_cnt: %d len: %u int_en: %d\n",
+ __FUNCTION__, src_cnt, len, int_en);
+
+ spin_lock_bh(&iop_chan->lock);
+ slot_cnt = iop_chan_xor_slot_count(len, src_cnt, &slots_per_op);
+ sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
+ if (sw_desc) {
+ grp_start = sw_desc->group_head;
+ iop_desc_init_xor(grp_start, src_cnt, int_en);
+ iop_desc_set_byte_count(grp_start, iop_chan, len);
+ sw_desc->unmap_src_cnt = src_cnt;
+ sw_desc->unmap_len = len;
+ sw_desc->async_tx.tx_set_src = iop_adma_xor_set_src;
+ }
+ spin_unlock_bh(&iop_chan->lock);
+
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
+static void
+iop_adma_xor_zero_sum_set_src(dma_addr_t addr,
+ struct dma_async_tx_descriptor *tx,
+ int index)
+{
+ struct iop_adma_desc_slot *sw_desc = tx_to_iop_adma_slot(tx);
+ struct iop_adma_desc_slot *grp_start = sw_desc->group_head;
+
+ iop_desc_set_zero_sum_src_addr(grp_start, index, addr);
+}
+
+static struct dma_async_tx_descriptor *
+iop_adma_prep_dma_zero_sum(struct dma_chan *chan, unsigned int src_cnt,
+ size_t len, u32 *result, int int_en)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ struct iop_adma_desc_slot *sw_desc, *grp_start;
+ int slot_cnt, slots_per_op;
+
+ if (unlikely(!len))
+ return NULL;
+
+ dev_dbg(iop_chan->device->common.dev, "%s src_cnt: %d len: %u\n",
+ __FUNCTION__, src_cnt, len);
+
+ spin_lock_bh(&iop_chan->lock);
+ slot_cnt = iop_chan_zero_sum_slot_count(len, src_cnt, &slots_per_op);
+ sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
+ if (sw_desc) {
+ grp_start = sw_desc->group_head;
+ iop_desc_init_zero_sum(grp_start, src_cnt, int_en);
+ iop_desc_set_zero_sum_byte_count(grp_start, len);
+ grp_start->xor_check_result = result;
+ pr_debug("\t%s: grp_start->xor_check_result: %p\n",
+ __FUNCTION__, grp_start->xor_check_result);
+ sw_desc->unmap_src_cnt = src_cnt;
+ sw_desc->unmap_len = len;
+ sw_desc->async_tx.tx_set_src = iop_adma_xor_zero_sum_set_src;
+ }
+ spin_unlock_bh(&iop_chan->lock);
+
+ return sw_desc ? &sw_desc->async_tx : NULL;
+}
+
+static void iop_adma_dependency_added(struct dma_chan *chan)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ tasklet_schedule(&iop_chan->irq_tasklet);
+}
+
+static void iop_adma_free_chan_resources(struct dma_chan *chan)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ struct iop_adma_desc_slot *iter, *_iter;
+ int in_use_descs = 0;
+
+ iop_adma_slot_cleanup(iop_chan);
+
+ spin_lock_bh(&iop_chan->lock);
+ list_for_each_entry_safe(iter, _iter, &iop_chan->chain,
+ chain_node) {
+ in_use_descs++;
+ list_del(&iter->chain_node);
+ }
+ list_for_each_entry_safe_reverse(
+ iter, _iter, &iop_chan->all_slots, slot_node) {
+ list_del(&iter->slot_node);
+ kfree(iter);
+ iop_chan->slots_allocated--;
+ }
+ iop_chan->last_used = NULL;
+
+ dev_dbg(iop_chan->device->common.dev, "%s slots_allocated %d\n",
+ __FUNCTION__, iop_chan->slots_allocated);
+ spin_unlock_bh(&iop_chan->lock);
+
+ /* one is ok since we left it on there on purpose */
+ if (in_use_descs > 1)
+ printk(KERN_ERR "IOP: Freeing %d in use descriptors!\n",
+ in_use_descs - 1);
+}
+
+/**
+ * iop_adma_is_complete - poll the status of an ADMA transaction
+ * @chan: ADMA channel handle
+ * @cookie: ADMA transaction identifier
+ */
+static enum dma_status iop_adma_is_complete(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ dma_cookie_t *done,
+ dma_cookie_t *used)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+ dma_cookie_t last_used;
+ dma_cookie_t last_complete;
+ enum dma_status ret;
+
+ last_used = chan->cookie;
+ last_complete = iop_chan->completed_cookie;
+
+ if (done)
+ *done = last_complete;
+ if (used)
+ *used = last_used;
+
+ ret = dma_async_is_complete(cookie, last_complete, last_used);
+ if (ret == DMA_SUCCESS)
+ return ret;
+
+ iop_adma_slot_cleanup(iop_chan);
+
+ last_used = chan->cookie;
+ last_complete = iop_chan->completed_cookie;
+
+ if (done)
+ *done = last_complete;
+ if (used)
+ *used = last_used;
+
+ return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+static irqreturn_t iop_adma_eot_handler(int irq, void *data)
+{
+ struct iop_adma_chan *chan = data;
+
+ dev_dbg(chan->device->common.dev, "%s\n", __FUNCTION__);
+
+ tasklet_schedule(&chan->irq_tasklet);
+
+ iop_adma_device_clear_eot_status(chan);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t iop_adma_eoc_handler(int irq, void *data)
+{
+ struct iop_adma_chan *chan = data;
+
+ dev_dbg(chan->device->common.dev, "%s\n", __FUNCTION__);
+
+ tasklet_schedule(&chan->irq_tasklet);
+
+ iop_adma_device_clear_eoc_status(chan);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t iop_adma_err_handler(int irq, void *data)
+{
+ struct iop_adma_chan *chan = data;
+ unsigned long status = iop_chan_get_status(chan);
+
+ dev_printk(KERN_ERR, chan->device->common.dev,
+ "error ( %s%s%s%s%s%s%s)\n",
+ iop_is_err_int_parity(status, chan) ? "int_parity " : "",
+ iop_is_err_mcu_abort(status, chan) ? "mcu_abort " : "",
+ iop_is_err_int_tabort(status, chan) ? "int_tabort " : "",
+ iop_is_err_int_mabort(status, chan) ? "int_mabort " : "",
+ iop_is_err_pci_tabort(status, chan) ? "pci_tabort " : "",
+ iop_is_err_pci_mabort(status, chan) ? "pci_mabort " : "",
+ iop_is_err_split_tx(status, chan) ? "split_tx " : "");
+
+ iop_adma_device_clear_err_status(chan);
+
+ BUG();
+
+ return IRQ_HANDLED;
+}
+
+static void iop_adma_issue_pending(struct dma_chan *chan)
+{
+ struct iop_adma_chan *iop_chan = to_iop_adma_chan(chan);
+
+ if (iop_chan->pending) {
+ iop_chan->pending = 0;
+ iop_chan_append(iop_chan);
+ }
+}
+
+/*
+ * Perform a transaction to verify the HW works.
+ */
+#define IOP_ADMA_TEST_SIZE 2000
+
+static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device)
+{
+ int i;
+ void *src, *dest;
+ dma_addr_t src_dma, dest_dma;
+ struct dma_chan *dma_chan;
+ dma_cookie_t cookie;
+ struct dma_async_tx_descriptor *tx;
+ int err = 0;
+ struct iop_adma_chan *iop_chan;
+
+ dev_dbg(device->common.dev, "%s\n", __FUNCTION__);
+
+ src = kzalloc(sizeof(u8) * IOP_ADMA_TEST_SIZE, GFP_KERNEL);
+ if (!src)
+ return -ENOMEM;
+ dest = kzalloc(sizeof(u8) * IOP_ADMA_TEST_SIZE, GFP_KERNEL);
+ if (!dest) {
+ kfree(src);
+ return -ENOMEM;
+ }
+
+ /* Fill in src buffer */
+ for (i = 0; i < IOP_ADMA_TEST_SIZE; i++)
+ ((u8 *) src)[i] = (u8)i;
+
+ memset(dest, 0, IOP_ADMA_TEST_SIZE);
+
+ /* Start copy, using first DMA channel */
+ dma_chan = container_of(device->common.channels.next,
+ struct dma_chan,
+ device_node);
+ if (iop_adma_alloc_chan_resources(dma_chan) < 1) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ tx = iop_adma_prep_dma_memcpy(dma_chan, IOP_ADMA_TEST_SIZE, 1);
+ dest_dma = dma_map_single(dma_chan->device->dev, dest,
+ IOP_ADMA_TEST_SIZE, DMA_FROM_DEVICE);
+ iop_adma_set_dest(dest_dma, tx, 0);
+ src_dma = dma_map_single(dma_chan->device->dev, src,
+ IOP_ADMA_TEST_SIZE, DMA_TO_DEVICE);
+ iop_adma_memcpy_set_src(src_dma, tx, 0);
+
+ cookie = iop_adma_tx_submit(tx);
+ iop_adma_issue_pending(dma_chan);
+ async_tx_ack(tx);
+ msleep(1);
+
+ if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) !=
+ DMA_SUCCESS) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test copy timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ iop_chan = to_iop_adma_chan(dma_chan);
+ dma_sync_single_for_cpu(&iop_chan->device->pdev->dev, dest_dma,
+ IOP_ADMA_TEST_SIZE, DMA_FROM_DEVICE);
+ if (memcmp(src, dest, IOP_ADMA_TEST_SIZE)) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test copy failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+free_resources:
+ iop_adma_free_chan_resources(dma_chan);
+out:
+ kfree(src);
+ kfree(dest);
+ return err;
+}
+
+#define IOP_ADMA_NUM_SRC_TEST 4 /* must be <= 15 */
+static int __devinit
+iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
+{
+ int i, src_idx;
+ struct page *dest;
+ struct page *xor_srcs[IOP_ADMA_NUM_SRC_TEST];
+ struct page *zero_sum_srcs[IOP_ADMA_NUM_SRC_TEST + 1];
+ dma_addr_t dma_addr, dest_dma;
+ struct dma_async_tx_descriptor *tx;
+ struct dma_chan *dma_chan;
+ dma_cookie_t cookie;
+ u8 cmp_byte = 0;
+ u32 cmp_word;
+ u32 zero_sum_result;
+ int err = 0;
+ struct iop_adma_chan *iop_chan;
+
+ dev_dbg(device->common.dev, "%s\n", __FUNCTION__);
+
+ for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++) {
+ xor_srcs[src_idx] = alloc_page(GFP_KERNEL);
+ if (!xor_srcs[src_idx])
+ while (src_idx--) {
+ __free_page(xor_srcs[src_idx]);
+ return -ENOMEM;
+ }
+ }
+
+ dest = alloc_page(GFP_KERNEL);
+ if (!dest)
+ while (src_idx--) {
+ __free_page(xor_srcs[src_idx]);
+ return -ENOMEM;
+ }
+
+ /* Fill in src buffers */
+ for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++) {
+ u8 *ptr = page_address(xor_srcs[src_idx]);
+ for (i = 0; i < PAGE_SIZE; i++)
+ ptr[i] = (1 << src_idx);
+ }
+
+ for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++)
+ cmp_byte ^= (u8) (1 << src_idx);
+
+ cmp_word = (cmp_byte << 24) | (cmp_byte << 16) |
+ (cmp_byte << 8) | cmp_byte;
+
+ memset(page_address(dest), 0, PAGE_SIZE);
+
+ dma_chan = container_of(device->common.channels.next,
+ struct dma_chan,
+ device_node);
+ if (iop_adma_alloc_chan_resources(dma_chan) < 1) {
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* test xor */
+ tx = iop_adma_prep_dma_xor(dma_chan, IOP_ADMA_NUM_SRC_TEST,
+ PAGE_SIZE, 1);
+ dest_dma = dma_map_page(dma_chan->device->dev, dest, 0,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ iop_adma_set_dest(dest_dma, tx, 0);
+
+ for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++) {
+ dma_addr = dma_map_page(dma_chan->device->dev, xor_srcs[i], 0,
+ PAGE_SIZE, DMA_TO_DEVICE);
+ iop_adma_xor_set_src(dma_addr, tx, i);
+ }
+
+ cookie = iop_adma_tx_submit(tx);
+ iop_adma_issue_pending(dma_chan);
+ async_tx_ack(tx);
+ msleep(8);
+
+ if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) !=
+ DMA_SUCCESS) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test xor timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ iop_chan = to_iop_adma_chan(dma_chan);
+ dma_sync_single_for_cpu(&iop_chan->device->pdev->dev, dest_dma,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ for (i = 0; i < (PAGE_SIZE / sizeof(u32)); i++) {
+ u32 *ptr = page_address(dest);
+ if (ptr[i] != cmp_word) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test xor failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ }
+ dma_sync_single_for_device(&iop_chan->device->pdev->dev, dest_dma,
+ PAGE_SIZE, DMA_TO_DEVICE);
+
+ /* skip zero sum if the capability is not present */
+ if (!dma_has_cap(DMA_ZERO_SUM, dma_chan->device->cap_mask))
+ goto free_resources;
+
+ /* zero sum the sources with the destintation page */
+ for (i = 0; i < IOP_ADMA_NUM_SRC_TEST; i++)
+ zero_sum_srcs[i] = xor_srcs[i];
+ zero_sum_srcs[i] = dest;
+
+ zero_sum_result = 1;
+
+ tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
+ PAGE_SIZE, &zero_sum_result, 1);
+ for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
+ dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
+ 0, PAGE_SIZE, DMA_TO_DEVICE);
+ iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
+ }
+
+ cookie = iop_adma_tx_submit(tx);
+ iop_adma_issue_pending(dma_chan);
+ async_tx_ack(tx);
+ msleep(8);
+
+ if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test zero sum timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ if (zero_sum_result != 0) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test zero sum failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ /* test memset */
+ tx = iop_adma_prep_dma_memset(dma_chan, 0, PAGE_SIZE, 1);
+ dma_addr = dma_map_page(dma_chan->device->dev, dest, 0,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ iop_adma_set_dest(dma_addr, tx, 0);
+
+ cookie = iop_adma_tx_submit(tx);
+ iop_adma_issue_pending(dma_chan);
+ async_tx_ack(tx);
+ msleep(8);
+
+ if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test memset timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ for (i = 0; i < PAGE_SIZE/sizeof(u32); i++) {
+ u32 *ptr = page_address(dest);
+ if (ptr[i]) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test memset failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+ }
+
+ /* test for non-zero parity sum */
+ zero_sum_result = 0;
+ tx = iop_adma_prep_dma_zero_sum(dma_chan, IOP_ADMA_NUM_SRC_TEST + 1,
+ PAGE_SIZE, &zero_sum_result, 1);
+ for (i = 0; i < IOP_ADMA_NUM_SRC_TEST + 1; i++) {
+ dma_addr = dma_map_page(dma_chan->device->dev, zero_sum_srcs[i],
+ 0, PAGE_SIZE, DMA_TO_DEVICE);
+ iop_adma_xor_zero_sum_set_src(dma_addr, tx, i);
+ }
+
+ cookie = iop_adma_tx_submit(tx);
+ iop_adma_issue_pending(dma_chan);
+ async_tx_ack(tx);
+ msleep(8);
+
+ if (iop_adma_is_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test non-zero sum timed out, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+ if (zero_sum_result != 1) {
+ dev_printk(KERN_ERR, dma_chan->device->dev,
+ "Self-test non-zero sum failed compare, disabling\n");
+ err = -ENODEV;
+ goto free_resources;
+ }
+
+free_resources:
+ iop_adma_free_chan_resources(dma_chan);
+out:
+ src_idx = IOP_ADMA_NUM_SRC_TEST;
+ while (src_idx--)
+ __free_page(xor_srcs[src_idx]);
+ __free_page(dest);
+ return err;
+}
+
+static int __devexit iop_adma_remove(struct platform_device *dev)
+{
+ struct iop_adma_device *device = platform_get_drvdata(dev);
+ struct dma_chan *chan, *_chan;
+ struct iop_adma_chan *iop_chan;
+ int i;
+ struct iop_adma_platform_data *plat_data = dev->dev.platform_data;
+
+ dma_async_device_unregister(&device->common);
+
+ for (i = 0; i < 3; i++) {
+ unsigned int irq;
+ irq = platform_get_irq(dev, i);
+ free_irq(irq, device);
+ }
+
+ dma_free_coherent(&dev->dev, plat_data->pool_size,
+ device->dma_desc_pool_virt, device->dma_desc_pool);
+
+ do {
+ struct resource *res;
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start);
+ } while (0);
+
+ list_for_each_entry_safe(chan, _chan, &device->common.channels,
+ device_node) {
+ iop_chan = to_iop_adma_chan(chan);
+ list_del(&chan->device_node);
+ kfree(iop_chan);
+ }
+ kfree(device);
+
+ return 0;
+}
+
+static int __devinit iop_adma_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret = 0, i;
+ struct iop_adma_device *adev;
+ struct iop_adma_chan *iop_chan;
+ struct dma_device *dma_dev;
+ struct iop_adma_platform_data *plat_data = pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ res->end - res->start, pdev->name))
+ return -EBUSY;
+
+ adev = kzalloc(sizeof(*adev), GFP_KERNEL);
+ if (!adev)
+ return -ENOMEM;
+ dma_dev = &adev->common;
+
+ /* allocate coherent memory for hardware descriptors
+ * note: writecombine gives slightly better performance, but
+ * requires that we explicitly flush the writes
+ */
+ if ((adev->dma_desc_pool_virt = dma_alloc_writecombine(&pdev->dev,
+ plat_data->pool_size,
+ &adev->dma_desc_pool,
+ GFP_KERNEL)) == NULL) {
+ ret = -ENOMEM;
+ goto err_free_adev;
+ }
+
+ dev_dbg(&pdev->dev, "%s: allocted descriptor pool virt %p phys %p\n",
+ __FUNCTION__, adev->dma_desc_pool_virt,
+ (void *) adev->dma_desc_pool);
+
+ adev->id = plat_data->hw_id;
+
+ /* discover transaction capabilites from the platform data */
+ dma_dev->cap_mask = plat_data->cap_mask;
+
+ adev->pdev = pdev;
+ platform_set_drvdata(pdev, adev);
+
+ INIT_LIST_HEAD(&dma_dev->channels);
+
+ /* set base routines */
+ dma_dev->device_alloc_chan_resources = iop_adma_alloc_chan_resources;
+ dma_dev->device_free_chan_resources = iop_adma_free_chan_resources;
+ dma_dev->device_is_tx_complete = iop_adma_is_complete;
+ dma_dev->device_issue_pending = iop_adma_issue_pending;
+ dma_dev->device_dependency_added = iop_adma_dependency_added;
+ dma_dev->dev = &pdev->dev;
+
+ /* set prep routines based on capability */
+ if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask))
+ dma_dev->device_prep_dma_memcpy = iop_adma_prep_dma_memcpy;
+ if (dma_has_cap(DMA_MEMSET, dma_dev->cap_mask))
+ dma_dev->device_prep_dma_memset = iop_adma_prep_dma_memset;
+ if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) {
+ dma_dev->max_xor = iop_adma_get_max_xor();
+ dma_dev->device_prep_dma_xor = iop_adma_prep_dma_xor;
+ }
+ if (dma_has_cap(DMA_ZERO_SUM, dma_dev->cap_mask))
+ dma_dev->device_prep_dma_zero_sum =
+ iop_adma_prep_dma_zero_sum;
+ if (dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask))
+ dma_dev->device_prep_dma_interrupt =
+ iop_adma_prep_dma_interrupt;
+
+ iop_chan = kzalloc(sizeof(*iop_chan), GFP_KERNEL);
+ if (!iop_chan) {
+ ret = -ENOMEM;
+ goto err_free_dma;
+ }
+ iop_chan->device = adev;
+
+ iop_chan->mmr_base = devm_ioremap(&pdev->dev, res->start,
+ res->end - res->start);
+ if (!iop_chan->mmr_base) {
+ ret = -ENOMEM;
+ goto err_free_iop_chan;
+ }
+ tasklet_init(&iop_chan->irq_tasklet, iop_adma_tasklet, (unsigned long)
+ iop_chan);
+
+ /* clear errors before enabling interrupts */
+ iop_adma_device_clear_err_status(iop_chan);
+
+ for (i = 0; i < 3; i++) {
+ irq_handler_t handler[] = { iop_adma_eot_handler,
+ iop_adma_eoc_handler,
+ iop_adma_err_handler };
+ int irq = platform_get_irq(pdev, i);
+ if (irq < 0) {
+ ret = -ENXIO;
+ goto err_free_iop_chan;
+ } else {
+ ret = devm_request_irq(&pdev->dev, irq,
+ handler[i], 0, pdev->name, iop_chan);
+ if (ret)
+ goto err_free_iop_chan;
+ }
+ }
+
+ spin_lock_init(&iop_chan->lock);
+ init_timer(&iop_chan->cleanup_watchdog);
+ iop_chan->cleanup_watchdog.data = (unsigned long) iop_chan;
+ iop_chan->cleanup_watchdog.function = iop_adma_tasklet;
+ INIT_LIST_HEAD(&iop_chan->chain);
+ INIT_LIST_HEAD(&iop_chan->all_slots);
+ INIT_RCU_HEAD(&iop_chan->common.rcu);
+ iop_chan->common.device = dma_dev;
+ list_add_tail(&iop_chan->common.device_node, &dma_dev->channels);
+
+ if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) {
+ ret = iop_adma_memcpy_self_test(adev);
+ dev_dbg(&pdev->dev, "memcpy self test returned %d\n", ret);
+ if (ret)
+ goto err_free_iop_chan;
+ }
+
+ if (dma_has_cap(DMA_XOR, dma_dev->cap_mask) ||
+ dma_has_cap(DMA_MEMSET, dma_dev->cap_mask)) {
+ ret = iop_adma_xor_zero_sum_self_test(adev);
+ dev_dbg(&pdev->dev, "xor self test returned %d\n", ret);
+ if (ret)
+ goto err_free_iop_chan;
+ }
+
+ dev_printk(KERN_INFO, &pdev->dev, "Intel(R) IOP: "
+ "( %s%s%s%s%s%s%s%s%s%s)\n",
+ dma_has_cap(DMA_PQ_XOR, dma_dev->cap_mask) ? "pq_xor " : "",
+ dma_has_cap(DMA_PQ_UPDATE, dma_dev->cap_mask) ? "pq_update " : "",
+ dma_has_cap(DMA_PQ_ZERO_SUM, dma_dev->cap_mask) ? "pq_zero_sum " : "",
+ dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "",
+ dma_has_cap(DMA_DUAL_XOR, dma_dev->cap_mask) ? "dual_xor " : "",
+ dma_has_cap(DMA_ZERO_SUM, dma_dev->cap_mask) ? "xor_zero_sum " : "",
+ dma_has_cap(DMA_MEMSET, dma_dev->cap_mask) ? "fill " : "",
+ dma_has_cap(DMA_MEMCPY_CRC32C, dma_dev->cap_mask) ? "cpy+crc " : "",
+ dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "",
+ dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : "");
+
+ dma_async_device_register(dma_dev);
+ goto out;
+
+ err_free_iop_chan:
+ kfree(iop_chan);
+ err_free_dma:
+ dma_free_coherent(&adev->pdev->dev, plat_data->pool_size,
+ adev->dma_desc_pool_virt, adev->dma_desc_pool);
+ err_free_adev:
+ kfree(adev);
+ out:
+ return ret;
+}
+
+static void iop_chan_start_null_memcpy(struct iop_adma_chan *iop_chan)
+{
+ struct iop_adma_desc_slot *sw_desc, *grp_start;
+ dma_cookie_t cookie;
+ int slot_cnt, slots_per_op;
+
+ dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__);
+
+ spin_lock_bh(&iop_chan->lock);
+ slot_cnt = iop_chan_memcpy_slot_count(0, &slots_per_op);
+ sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
+ if (sw_desc) {
+ grp_start = sw_desc->group_head;
+
+ list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain);
+ sw_desc->async_tx.ack = 1;
+ iop_desc_init_memcpy(grp_start, 0);
+ iop_desc_set_byte_count(grp_start, iop_chan, 0);
+ iop_desc_set_dest_addr(grp_start, iop_chan, 0);
+ iop_desc_set_memcpy_src_addr(grp_start, 0);
+
+ cookie = iop_chan->common.cookie;
+ cookie++;
+ if (cookie <= 1)
+ cookie = 2;
+
+ /* initialize the completed cookie to be less than
+ * the most recently used cookie
+ */
+ iop_chan->completed_cookie = cookie - 1;
+ iop_chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+
+ /* channel should not be busy */
+ BUG_ON(iop_chan_is_busy(iop_chan));
+
+ /* clear any prior error-status bits */
+ iop_adma_device_clear_err_status(iop_chan);
+
+ /* disable operation */
+ iop_chan_disable(iop_chan);
+
+ /* set the descriptor address */
+ iop_chan_set_next_descriptor(iop_chan, sw_desc->async_tx.phys);
+
+ /* 1/ don't add pre-chained descriptors
+ * 2/ dummy read to flush next_desc write
+ */
+ BUG_ON(iop_desc_get_next_desc(sw_desc));
+
+ /* run the descriptor */
+ iop_chan_enable(iop_chan);
+ } else
+ dev_printk(KERN_ERR, iop_chan->device->common.dev,
+ "failed to allocate null descriptor\n");
+ spin_unlock_bh(&iop_chan->lock);
+}
+
+static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan)
+{
+ struct iop_adma_desc_slot *sw_desc, *grp_start;
+ dma_cookie_t cookie;
+ int slot_cnt, slots_per_op;
+
+ dev_dbg(iop_chan->device->common.dev, "%s\n", __FUNCTION__);
+
+ spin_lock_bh(&iop_chan->lock);
+ slot_cnt = iop_chan_xor_slot_count(0, 2, &slots_per_op);
+ sw_desc = iop_adma_alloc_slots(iop_chan, slot_cnt, slots_per_op);
+ if (sw_desc) {
+ grp_start = sw_desc->group_head;
+ list_splice_init(&sw_desc->async_tx.tx_list, &iop_chan->chain);
+ sw_desc->async_tx.ack = 1;
+ iop_desc_init_null_xor(grp_start, 2, 0);
+ iop_desc_set_byte_count(grp_start, iop_chan, 0);
+ iop_desc_set_dest_addr(grp_start, iop_chan, 0);
+ iop_desc_set_xor_src_addr(grp_start, 0, 0);
+ iop_desc_set_xor_src_addr(grp_start, 1, 0);
+
+ cookie = iop_chan->common.cookie;
+ cookie++;
+ if (cookie <= 1)
+ cookie = 2;
+
+ /* initialize the completed cookie to be less than
+ * the most recently used cookie
+ */
+ iop_chan->completed_cookie = cookie - 1;
+ iop_chan->common.cookie = sw_desc->async_tx.cookie = cookie;
+
+ /* channel should not be busy */
+ BUG_ON(iop_chan_is_busy(iop_chan));
+
+ /* clear any prior error-status bits */
+ iop_adma_device_clear_err_status(iop_chan);
+
+ /* disable operation */
+ iop_chan_disable(iop_chan);
+
+ /* set the descriptor address */
+ iop_chan_set_next_descriptor(iop_chan, sw_desc->async_tx.phys);
+
+ /* 1/ don't add pre-chained descriptors
+ * 2/ dummy read to flush next_desc write
+ */
+ BUG_ON(iop_desc_get_next_desc(sw_desc));
+
+ /* run the descriptor */
+ iop_chan_enable(iop_chan);
+ } else
+ dev_printk(KERN_ERR, iop_chan->device->common.dev,
+ "failed to allocate null descriptor\n");
+ spin_unlock_bh(&iop_chan->lock);
+}
+
+static struct platform_driver iop_adma_driver = {
+ .probe = iop_adma_probe,
+ .remove = iop_adma_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "iop-adma",
+ },
+};
+
+static int __init iop_adma_init (void)
+{
+ /* it's currently unsafe to unload this module */
+ /* if forced, worst case is that rmmod hangs */
+ __unsafe(THIS_MODULE);
+
+ return platform_driver_register(&iop_adma_driver);
+}
+
+static void __exit iop_adma_exit (void)
+{
+ platform_driver_unregister(&iop_adma_driver);
+ return;
+}
+
+module_init(iop_adma_init);
+module_exit(iop_adma_exit);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("IOP ADMA Engine Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 807c402df049..1724c41d2414 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -3,20 +3,18 @@
# Copyright (c) 2003 Linux Networx
# Licensed and distributed under the GPL
#
-# $Id: Kconfig,v 1.4.2.7 2005/07/08 22:05:38 dsp_llnl Exp $
-#
-menu 'EDAC - error detection and reporting (RAS) (EXPERIMENTAL)'
+menuconfig EDAC
+ bool "EDAC - error detection and reporting (EXPERIMENTAL)"
depends on HAS_IOMEM
-
-config EDAC
- tristate "EDAC core system error reporting (EXPERIMENTAL)"
- depends on X86 && EXPERIMENTAL
+ depends on EXPERIMENTAL
+ depends on X86 || MIPS || PPC
help
EDAC is designed to report errors in the core system.
These are low-level errors that are reported in the CPU or
- supporting chipset: memory errors, cache errors, PCI errors,
- thermal throttling, etc.. If unsure, select 'Y'.
+ supporting chipset or other subsystems:
+ memory errors, cache errors, PCI errors, thermal throttling, etc..
+ If unsure, select 'Y'.
If this code is reporting problems on your system, please
see the EDAC project web pages for more information at:
@@ -30,13 +28,12 @@ config EDAC
There is also a mailing list for the EDAC project, which can
be found via the sourceforge page.
+if EDAC
comment "Reporting subsystems"
- depends on EDAC
config EDAC_DEBUG
bool "Debugging"
- depends on EDAC
help
This turns on debugging information for the entire EDAC
sub-system. You can insert module with "debug_level=x", current
@@ -45,7 +42,6 @@ config EDAC_DEBUG
config EDAC_MM_EDAC
tristate "Main Memory EDAC (Error Detection And Correction) reporting"
- depends on EDAC
default y
help
Some systems are able to detect and correct errors in main
@@ -77,6 +73,14 @@ config EDAC_E752X
Support for error detection and correction on the Intel
E7520, E7525, E7320 server chipsets.
+config EDAC_I82443BXGX
+ tristate "Intel 82443BX/GX (440BX/GX)"
+ depends on EDAC_MM_EDAC && PCI && X86_32
+ depends on BROKEN
+ help
+ Support for error detection and correction on the Intel
+ 82443BX/GX memory controllers (440BX/GX chipsets).
+
config EDAC_I82875P
tristate "Intel 82875p (D82875P, E7210)"
depends on EDAC_MM_EDAC && PCI && X86_32
@@ -84,6 +88,20 @@ config EDAC_I82875P
Support for error detection and correction on the Intel
DP82785P and E7210 server chipsets.
+config EDAC_I82975X
+ tristate "Intel 82975x (D82975x)"
+ depends on EDAC_MM_EDAC && PCI && X86
+ help
+ Support for error detection and correction on the Intel
+ DP82975x server chipsets.
+
+config EDAC_I3000
+ tristate "Intel 3000/3010"
+ depends on EDAC_MM_EDAC && PCI && X86_32
+ help
+ Support for error detection and correction on the Intel
+ 3000 and 3010 server chipsets.
+
config EDAC_I82860
tristate "Intel 82860"
depends on EDAC_MM_EDAC && PCI && X86_32
@@ -98,17 +116,20 @@ config EDAC_R82600
Support for error detection and correction on the Radisys
82600 embedded chipset.
-choice
- prompt "Error detecting method"
- depends on EDAC
- default EDAC_POLL
+config EDAC_I5000
+ tristate "Intel Greencreek/Blackford chipset"
+ depends on EDAC_MM_EDAC && X86 && PCI
+ help
+ Support for error detection and correction the Intel
+ Greekcreek/Blackford chipsets.
-config EDAC_POLL
- bool "Poll for errors"
- depends on EDAC
+config EDAC_PASEMI
+ tristate "PA Semi PWRficient"
+ depends on EDAC_MM_EDAC && PCI
+ depends on PPC
help
- Poll the chipset periodically to detect errors.
+ Support for error detection and correction on PA Semi
+ PWRficient.
-endchoice
-endmenu
+endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 93137fdab4b3..02c09f0ff157 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -5,14 +5,27 @@
# This file may be distributed under the terms of the
# GNU General Public License.
#
-# $Id: Makefile,v 1.4.2.3 2005/07/08 22:05:38 dsp_llnl Exp $
-obj-$(CONFIG_EDAC_MM_EDAC) += edac_mc.o
+obj-$(CONFIG_EDAC) := edac_stub.o
+obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
+
+edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-objs += edac_module.o edac_device_sysfs.o
+
+ifdef CONFIG_PCI
+edac_core-objs += edac_pci.o edac_pci_sysfs.o
+endif
+
obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
+obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
+obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
obj-$(CONFIG_EDAC_I82875P) += i82875p_edac.o
+obj-$(CONFIG_EDAC_I82975X) += i82975x_edac.o
+obj-$(CONFIG_EDAC_I3000) += i3000_edac.o
obj-$(CONFIG_EDAC_I82860) += i82860_edac.o
obj-$(CONFIG_EDAC_R82600) += r82600_edac.o
+obj-$(CONFIG_EDAC_PASEMI) += pasemi_edac.o
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index f79f6b587bfa..f22075410591 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -17,9 +17,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define AMD76X_REVISION " Ver: 2.0.1 " __DATE__
+#define AMD76X_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "amd76x_edac"
#define amd76x_printk(level, fmt, arg...) \
@@ -86,13 +86,13 @@ struct amd76x_dev_info {
static const struct amd76x_dev_info amd76x_devs[] = {
[AMD761] = {
- .ctl_name = "AMD761"
- },
+ .ctl_name = "AMD761"},
[AMD762] = {
- .ctl_name = "AMD762"
- },
+ .ctl_name = "AMD762"},
};
+static struct edac_pci_ctl_info *amd76x_pci;
+
/**
* amd76x_get_error_info - fetch error information
* @mci: Memory controller
@@ -102,21 +102,21 @@ static const struct amd76x_dev_info amd76x_devs[] = {
* on the chip so that further errors will be reported
*/
static void amd76x_get_error_info(struct mem_ctl_info *mci,
- struct amd76x_error_info *info)
+ struct amd76x_error_info *info)
{
struct pci_dev *pdev;
pdev = to_pci_dev(mci->dev);
pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
- &info->ecc_mode_status);
+ &info->ecc_mode_status);
if (info->ecc_mode_status & BIT(8))
pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
- (u32) BIT(8), (u32) BIT(8));
+ (u32) BIT(8), (u32) BIT(8));
if (info->ecc_mode_status & BIT(9))
pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
- (u32) BIT(9), (u32) BIT(9));
+ (u32) BIT(9), (u32) BIT(9));
}
/**
@@ -130,7 +130,8 @@ static void amd76x_get_error_info(struct mem_ctl_info *mci,
* then attempt to handle and clean up after the error
*/
static int amd76x_process_error_info(struct mem_ctl_info *mci,
- struct amd76x_error_info *info, int handle_errors)
+ struct amd76x_error_info *info,
+ int handle_errors)
{
int error_found;
u32 row;
@@ -138,7 +139,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
error_found = 0;
/*
- * Check for an uncorrectable error
+ * Check for an uncorrectable error
*/
if (info->ecc_mode_status & BIT(8)) {
error_found = 1;
@@ -146,12 +147,12 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
if (handle_errors) {
row = (info->ecc_mode_status >> 4) & 0xf;
edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0,
- row, mci->ctl_name);
+ row, mci->ctl_name);
}
}
/*
- * Check for a correctable error
+ * Check for a correctable error
*/
if (info->ecc_mode_status & BIT(9)) {
error_found = 1;
@@ -159,7 +160,7 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
if (handle_errors) {
row = info->ecc_mode_status & 0xf;
edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0,
- 0, row, 0, mci->ctl_name);
+ 0, row, 0, mci->ctl_name);
}
}
@@ -182,7 +183,7 @@ static void amd76x_check(struct mem_ctl_info *mci)
}
static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- enum edac_type edac_mode)
+ enum edac_type edac_mode)
{
struct csrow_info *csrow;
u32 mba, mba_base, mba_mask, dms;
@@ -193,8 +194,7 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
/* find the DRAM Chip Select Base address and mask */
pci_read_config_dword(pdev,
- AMD76X_MEM_BASE_ADDR + (index * 4),
- &mba);
+ AMD76X_MEM_BASE_ADDR + (index * 4), &mba);
if (!(mba & BIT(0)))
continue;
@@ -238,7 +238,7 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
debugf0("%s()\n", __func__);
pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
ems_mode = (ems >> 10) & 0x3;
- mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS);
+ mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS, 0);
if (mci == NULL) {
return -ENOMEM;
@@ -249,24 +249,36 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
mci->mtype_cap = MEM_FLAG_RDDR;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
mci->edac_cap = ems_mode ?
- (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
+ (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = AMD76X_REVISION;
mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = amd76x_check;
mci->ctl_page_to_phys = NULL;
amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]);
- amd76x_get_error_info(mci, &discard); /* clear counters */
+ amd76x_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
+ /* allocating generic PCI control info */
+ amd76x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!amd76x_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
@@ -278,7 +290,7 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit amd76x_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
@@ -300,6 +312,9 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (amd76x_pci)
+ edac_pci_release_generic_ctl(amd76x_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
@@ -308,16 +323,14 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- AMD762
- },
+ PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ AMD762},
{
- PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- AMD761
- },
+ PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ AMD761},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 8bcc887692ab..3bba224cb55d 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -22,13 +22,16 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
-#define E752X_REVISION " Ver: 2.0.1 " __DATE__
+#define E752X_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "e752x_edac"
static int force_function_unhide;
+static struct edac_pci_ctl_info *e752x_pci;
+
#define e752x_printk(level, fmt, arg...) \
edac_printk(level, "e752x", fmt, ##arg)
@@ -203,25 +206,22 @@ static const struct e752x_dev_info e752x_devs[] = {
[E7520] = {
.err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
- .ctl_name = "E7520"
- },
+ .ctl_name = "E7520"},
[E7525] = {
.err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
- .ctl_name = "E7525"
- },
+ .ctl_name = "E7525"},
[E7320] = {
.err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
- .ctl_name = "E7320"
- },
+ .ctl_name = "E7320"},
};
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
- unsigned long page)
+ unsigned long page)
{
u32 remap;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
@@ -241,13 +241,13 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
}
static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
- u32 sec1_add, u16 sec1_syndrome)
+ u32 sec1_add, u16 sec1_syndrome)
{
u32 page;
int row;
int channel;
int i;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
@@ -261,7 +261,8 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
e752x_printk(KERN_WARNING,
"Test row %d Table %d %d %d %d %d %d %d %d\n", row,
pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
- pvt->map[4], pvt->map[5], pvt->map[6], pvt->map[7]);
+ pvt->map[4], pvt->map[5], pvt->map[6],
+ pvt->map[7]);
/* test for channel remapping */
for (i = 0; i < 8; i++) {
@@ -275,24 +276,22 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
row = i;
else
e752x_mc_printk(mci, KERN_WARNING,
- "row %d not found in remap table\n", row);
+ "row %d not found in remap table\n",
+ row);
} else
row = edac_mc_find_csrow_by_page(mci, page);
/* 0 = channel A, 1 = channel B */
channel = !(error_one & 1);
- if (!pvt->map_type)
- row = 7 - row;
-
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
sec1_syndrome, row, channel, "e752x CE");
}
static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
- u32 sec1_add, u16 sec1_syndrome, int *error_found,
- int handle_error)
+ u32 sec1_add, u16 sec1_syndrome, int *error_found,
+ int handle_error)
{
*error_found = 1;
@@ -301,11 +300,11 @@ static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
}
static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
- u32 ded_add, u32 scrb_add)
+ u32 ded_add, u32 scrb_add)
{
u32 error_2b, block_page;
int row;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
@@ -316,14 +315,14 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
block_page = error_2b >> (PAGE_SHIFT - 4);
row = pvt->mc_symmetric ?
- /* chip select are bits 14 & 13 */
+ /* chip select are bits 14 & 13 */
((block_page >> 1) & 3) :
edac_mc_find_csrow_by_page(mci, block_page);
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ue(mci, block_page,
- offset_in_page(error_2b << 4),
- row, "e752x UE from Read");
+ offset_in_page(error_2b << 4),
+ row, "e752x UE from Read");
}
if (error_one & 0x0404) {
error_2b = scrb_add;
@@ -332,19 +331,20 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
block_page = error_2b >> (PAGE_SHIFT - 4);
row = pvt->mc_symmetric ?
- /* chip select are bits 14 & 13 */
+ /* chip select are bits 14 & 13 */
((block_page >> 1) & 3) :
edac_mc_find_csrow_by_page(mci, block_page);
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ue(mci, block_page,
- offset_in_page(error_2b << 4),
- row, "e752x UE from Scruber");
+ offset_in_page(error_2b << 4),
+ row, "e752x UE from Scruber");
}
}
static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
- u32 ded_add, u32 scrb_add, int *error_found, int handle_error)
+ u32 ded_add, u32 scrb_add, int *error_found,
+ int handle_error)
{
*error_found = 1;
@@ -353,7 +353,7 @@ static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
}
static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
*error_found = 1;
@@ -365,24 +365,24 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
}
static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
- u32 retry_add)
+ u32 retry_add)
{
u32 error_1b, page;
int row;
- struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+ struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
error_1b = retry_add;
- page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
- row = pvt->mc_symmetric ?
- ((page >> 1) & 3) : /* chip select are bits 14 & 13 */
+ page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
+ row = pvt->mc_symmetric ? ((page >> 1) & 3) : /* chip select are bits 14 & 13 */
edac_mc_find_csrow_by_page(mci, page);
e752x_mc_printk(mci, KERN_WARNING,
- "CE page 0x%lx, row %d : Memory read retry\n",
- (long unsigned int) page, row);
+ "CE page 0x%lx, row %d : Memory read retry\n",
+ (long unsigned int)page, row);
}
static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
- u32 retry_add, int *error_found, int handle_error)
+ u32 retry_add, int *error_found,
+ int handle_error)
{
*error_found = 1;
@@ -391,7 +391,7 @@ static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
}
static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
*error_found = 1;
@@ -420,7 +420,7 @@ static void do_global_error(int fatal, u32 errors)
}
static inline void global_error(int fatal, u32 errors, int *error_found,
- int handle_error)
+ int handle_error)
{
*error_found = 1;
@@ -447,7 +447,7 @@ static void do_hub_error(int fatal, u8 errors)
}
static inline void hub_error(int fatal, u8 errors, int *error_found,
- int handle_error)
+ int handle_error)
{
*error_found = 1;
@@ -505,7 +505,7 @@ static void do_sysbus_error(int fatal, u32 errors)
}
static inline void sysbus_error(int fatal, u32 errors, int *error_found,
- int handle_error)
+ int handle_error)
{
*error_found = 1;
@@ -514,7 +514,7 @@ static inline void sysbus_error(int fatal, u32 errors, int *error_found,
}
static void e752x_check_hub_interface(struct e752x_error_info *info,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
u8 stat8;
@@ -522,33 +522,32 @@ static void e752x_check_hub_interface(struct e752x_error_info *info,
stat8 = info->hi_ferr;
- if(stat8 & 0x7f) { /* Error, so process */
+ if (stat8 & 0x7f) { /* Error, so process */
stat8 &= 0x7f;
- if(stat8 & 0x2b)
+ if (stat8 & 0x2b)
hub_error(1, stat8 & 0x2b, error_found, handle_error);
- if(stat8 & 0x54)
+ if (stat8 & 0x54)
hub_error(0, stat8 & 0x54, error_found, handle_error);
}
-
//pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
stat8 = info->hi_nerr;
- if(stat8 & 0x7f) { /* Error, so process */
+ if (stat8 & 0x7f) { /* Error, so process */
stat8 &= 0x7f;
if (stat8 & 0x2b)
hub_error(1, stat8 & 0x2b, error_found, handle_error);
- if(stat8 & 0x54)
+ if (stat8 & 0x54)
hub_error(0, stat8 & 0x54, error_found, handle_error);
}
}
static void e752x_check_sysbus(struct e752x_error_info *info,
- int *error_found, int handle_error)
+ int *error_found, int handle_error)
{
u32 stat32, error32;
@@ -556,47 +555,47 @@ static void e752x_check_sysbus(struct e752x_error_info *info,
stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16);
if (stat32 == 0)
- return; /* no errors */
+ return; /* no errors */
error32 = (stat32 >> 16) & 0x3ff;
stat32 = stat32 & 0x3ff;
- if(stat32 & 0x087)
+ if (stat32 & 0x087)
sysbus_error(1, stat32 & 0x087, error_found, handle_error);
- if(stat32 & 0x378)
+ if (stat32 & 0x378)
sysbus_error(0, stat32 & 0x378, error_found, handle_error);
- if(error32 & 0x087)
+ if (error32 & 0x087)
sysbus_error(1, error32 & 0x087, error_found, handle_error);
- if(error32 & 0x378)
+ if (error32 & 0x378)
sysbus_error(0, error32 & 0x378, error_found, handle_error);
}
-static void e752x_check_membuf (struct e752x_error_info *info,
- int *error_found, int handle_error)
+static void e752x_check_membuf(struct e752x_error_info *info,
+ int *error_found, int handle_error)
{
u8 stat8;
stat8 = info->buf_ferr;
- if (stat8 & 0x0f) { /* Error, so process */
+ if (stat8 & 0x0f) { /* Error, so process */
stat8 &= 0x0f;
membuf_error(stat8, error_found, handle_error);
}
stat8 = info->buf_nerr;
- if (stat8 & 0x0f) { /* Error, so process */
+ if (stat8 & 0x0f) { /* Error, so process */
stat8 &= 0x0f;
membuf_error(stat8, error_found, handle_error);
}
}
-static void e752x_check_dram (struct mem_ctl_info *mci,
- struct e752x_error_info *info, int *error_found,
- int handle_error)
+static void e752x_check_dram(struct mem_ctl_info *mci,
+ struct e752x_error_info *info, int *error_found,
+ int handle_error)
{
u16 error_one, error_next;
@@ -604,55 +603,52 @@ static void e752x_check_dram (struct mem_ctl_info *mci,
error_next = info->dram_nerr;
/* decode and report errors */
- if(error_one & 0x0101) /* check first error correctable */
+ if (error_one & 0x0101) /* check first error correctable */
process_ce(mci, error_one, info->dram_sec1_add,
- info->dram_sec1_syndrome, error_found,
- handle_error);
+ info->dram_sec1_syndrome, error_found, handle_error);
- if(error_next & 0x0101) /* check next error correctable */
+ if (error_next & 0x0101) /* check next error correctable */
process_ce(mci, error_next, info->dram_sec2_add,
- info->dram_sec2_syndrome, error_found,
- handle_error);
+ info->dram_sec2_syndrome, error_found, handle_error);
- if(error_one & 0x4040)
+ if (error_one & 0x4040)
process_ue_no_info_wr(mci, error_found, handle_error);
- if(error_next & 0x4040)
+ if (error_next & 0x4040)
process_ue_no_info_wr(mci, error_found, handle_error);
- if(error_one & 0x2020)
+ if (error_one & 0x2020)
process_ded_retry(mci, error_one, info->dram_retr_add,
- error_found, handle_error);
+ error_found, handle_error);
- if(error_next & 0x2020)
+ if (error_next & 0x2020)
process_ded_retry(mci, error_next, info->dram_retr_add,
- error_found, handle_error);
+ error_found, handle_error);
- if(error_one & 0x0808)
- process_threshold_ce(mci, error_one, error_found,
- handle_error);
+ if (error_one & 0x0808)
+ process_threshold_ce(mci, error_one, error_found, handle_error);
- if(error_next & 0x0808)
+ if (error_next & 0x0808)
process_threshold_ce(mci, error_next, error_found,
- handle_error);
+ handle_error);
- if(error_one & 0x0606)
+ if (error_one & 0x0606)
process_ue(mci, error_one, info->dram_ded_add,
- info->dram_scrb_add, error_found, handle_error);
+ info->dram_scrb_add, error_found, handle_error);
- if(error_next & 0x0606)
+ if (error_next & 0x0606)
process_ue(mci, error_next, info->dram_ded_add,
- info->dram_scrb_add, error_found, handle_error);
+ info->dram_scrb_add, error_found, handle_error);
}
-static void e752x_get_error_info (struct mem_ctl_info *mci,
- struct e752x_error_info *info)
+static void e752x_get_error_info(struct mem_ctl_info *mci,
+ struct e752x_error_info *info)
{
struct pci_dev *dev;
struct e752x_pvt *pvt;
memset(info, 0, sizeof(*info));
- pvt = (struct e752x_pvt *) mci->pvt_info;
+ pvt = (struct e752x_pvt *)mci->pvt_info;
dev = pvt->dev_d0f1;
pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
@@ -661,8 +657,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
pci_read_config_word(dev, E752X_SYSBUS_FERR,
&info->sysbus_ferr);
pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
- pci_read_config_word(dev, E752X_DRAM_FERR,
- &info->dram_ferr);
+ pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr);
pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD,
&info->dram_sec1_add);
pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME,
@@ -688,7 +683,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
if (info->dram_ferr)
pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
- info->dram_ferr, info->dram_ferr);
+ info->dram_ferr, info->dram_ferr);
pci_write_config_dword(dev, E752X_FERR_GLOBAL,
info->ferr_global);
@@ -701,8 +696,7 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
pci_read_config_word(dev, E752X_SYSBUS_NERR,
&info->sysbus_nerr);
pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
- pci_read_config_word(dev, E752X_DRAM_NERR,
- &info->dram_nerr);
+ pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr);
pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD,
&info->dram_sec2_add);
pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME,
@@ -722,15 +716,16 @@ static void e752x_get_error_info (struct mem_ctl_info *mci,
if (info->dram_nerr)
pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
- info->dram_nerr, info->dram_nerr);
+ info->dram_nerr, info->dram_nerr);
pci_write_config_dword(dev, E752X_NERR_GLOBAL,
info->nerr_global);
}
}
-static int e752x_process_error_info (struct mem_ctl_info *mci,
- struct e752x_error_info *info, int handle_errors)
+static int e752x_process_error_info(struct mem_ctl_info *mci,
+ struct e752x_error_info *info,
+ int handle_errors)
{
u32 error32, stat32;
int error_found;
@@ -776,26 +771,38 @@ static inline int dual_channel_active(u16 ddrcsr)
return (((ddrcsr >> 12) & 3) == 3);
}
+/* Remap csrow index numbers if map_type is "reverse"
+ */
+static inline int remap_csrow_index(struct mem_ctl_info *mci, int index)
+{
+ struct e752x_pvt *pvt = mci->pvt_info;
+
+ if (!pvt->map_type)
+ return (7 - index);
+
+ return (index);
+}
+
static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- u16 ddrcsr)
+ u16 ddrcsr)
{
struct csrow_info *csrow;
unsigned long last_cumul_size;
int index, mem_dev, drc_chan;
- int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
- int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
+ int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
+ int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
u8 value;
u32 dra, drc, cumul_size;
dra = 0;
- for (index=0; index < 4; index++) {
+ for (index = 0; index < 4; index++) {
u8 dra_reg;
- pci_read_config_byte(pdev, E752X_DRA+index, &dra_reg);
+ pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);
dra |= dra_reg << (index * 8);
}
pci_read_config_dword(pdev, E752X_DRC, &drc);
drc_chan = dual_channel_active(ddrcsr);
- drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
+ drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
drc_ddim = (drc >> 20) & 0x3;
/* The dram row boundary (DRB) reg values are boundary address for
@@ -806,7 +813,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
/* mem_dev 0=x8, 1=x4 */
mem_dev = (dra >> (index * 4 + 2)) & 0x3;
- csrow = &mci->csrows[index];
+ csrow = &mci->csrows[remap_csrow_index(mci, index)];
mem_dev = (mem_dev == 2);
pci_read_config_byte(pdev, E752X_DRB + index, &value);
@@ -843,10 +850,10 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
}
static void e752x_init_mem_map_table(struct pci_dev *pdev,
- struct e752x_pvt *pvt)
+ struct e752x_pvt *pvt)
{
int index;
- u8 value, last, row, stat8;
+ u8 value, last, row;
last = 0;
row = 0;
@@ -858,7 +865,7 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
/* no dimm in the slot, so flag it as empty */
pvt->map[index] = 0xff;
pvt->map[index + 1] = 0xff;
- } else { /* there is a dimm in the slot */
+ } else { /* there is a dimm in the slot */
pvt->map[index] = row;
row++;
last = value;
@@ -866,31 +873,25 @@ static void e752x_init_mem_map_table(struct pci_dev *pdev,
* sided
*/
pci_read_config_byte(pdev, E752X_DRB + index + 1,
- &value);
- pvt->map[index + 1] = (value == last) ?
- 0xff : /* the dimm is single sided,
- so flag as empty */
- row; /* this is a double sided dimm
- to save the next row # */
+ &value);
+
+ /* the dimm is single sided, so flag as empty */
+ /* this is a double sided dimm to save the next row #*/
+ pvt->map[index + 1] = (value == last) ? 0xff : row;
row++;
last = value;
}
}
-
- /* set the map type. 1 = normal, 0 = reversed */
- pci_read_config_byte(pdev, E752X_DRM, &stat8);
- pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
}
/* Return 0 on success or 1 on failure. */
static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
- struct e752x_pvt *pvt)
+ struct e752x_pvt *pvt)
{
struct pci_dev *dev;
pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev,
- pvt->bridge_ck);
+ pvt->dev_info->err_dev, pvt->bridge_ck);
if (pvt->bridge_ck == NULL)
pvt->bridge_ck = pci_scan_single_device(pdev->bus,
@@ -898,13 +899,13 @@ static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
if (pvt->bridge_ck == NULL) {
e752x_printk(KERN_ERR, "error reporting device not found:"
- "vendor %x device 0x%x (broken BIOS?)\n",
- PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
+ "vendor %x device 0x%x (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
return 1;
}
dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
- NULL);
+ NULL);
if (dev == NULL)
goto fail;
@@ -942,12 +943,22 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
struct mem_ctl_info *mci;
struct e752x_pvt *pvt;
u16 ddrcsr;
- int drc_chan; /* Number of channels 0=1chan,1=2chan */
+ int drc_chan; /* Number of channels 0=1chan,1=2chan */
struct e752x_error_info discard;
debugf0("%s(): mci\n", __func__);
debugf0("Starting Probe1\n");
+ /* make sure error reporting method is sane */
+ switch (edac_op_state) {
+ case EDAC_OPSTATE_POLL:
+ case EDAC_OPSTATE_NMI:
+ break;
+ default:
+ edac_op_state = EDAC_OPSTATE_POLL;
+ break;
+ }
+
/* check to see if device 0 function 1 is enabled; if it isn't, we
* assume the BIOS has reserved it for a reason and is expecting
* exclusive access, we take care not to violate that assumption and
@@ -966,7 +977,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
/* Dual channel = 1, Single channel = 0 */
drc_chan = dual_channel_active(ddrcsr);
- mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1);
+ mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
if (mci == NULL) {
return -ENOMEM;
@@ -975,14 +986,14 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): init mci\n", __func__);
mci->mtype_cap = MEM_FLAG_RDDR;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
- EDAC_FLAG_S4ECD4ED;
+ EDAC_FLAG_S4ECD4ED;
/* FIXME - what if different memory types are in different csrows? */
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = E752X_REVISION;
mci->dev = &pdev->dev;
debugf3("%s(): init pvt\n", __func__);
- pvt = (struct e752x_pvt *) mci->pvt_info;
+ pvt = (struct e752x_pvt *)mci->pvt_info;
pvt->dev_info = &e752x_devs[dev_idx];
pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
@@ -993,16 +1004,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): more mci init\n", __func__);
mci->ctl_name = pvt->dev_info->ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = e752x_check;
mci->ctl_page_to_phys = ctl_page_to_phys;
- e752x_init_csrows(mci, pdev, ddrcsr);
- e752x_init_mem_map_table(pdev, pvt);
-
- /* set the map type. 1 = normal, 0 = reversed */
+ /* set the map type. 1 = normal, 0 = reversed
+ * Must be set before e752x_init_csrows in case csrow mapping
+ * is reversed.
+ */
pci_read_config_byte(pdev, E752X_DRM, &stat8);
pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
+ e752x_init_csrows(mci, pdev, ddrcsr);
+ e752x_init_mem_map_table(pdev, pvt);
+
mci->edac_cap |= EDAC_FLAG_NONE;
debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
@@ -1014,19 +1029,29 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
pvt->remaplimit = ((u32) pci_data) << 14;
e752x_printk(KERN_INFO,
- "tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
- pvt->remapbase, pvt->remaplimit);
+ "tolm = %x, remapbase = %x, remaplimit = %x\n",
+ pvt->tolm, pvt->remapbase, pvt->remaplimit);
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
e752x_init_error_reporting_regs(pvt);
- e752x_get_error_info(mci, &discard); /* clear other MCH errors */
+ e752x_get_error_info(mci, &discard); /* clear other MCH errors */
+
+ /* allocating generic PCI control info */
+ e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!e752x_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n", __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
@@ -1043,12 +1068,12 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit e752x_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
/* wake up and enable device */
- if(pci_enable_device(pdev) < 0)
+ if (pci_enable_device(pdev) < 0)
return -EIO;
return e752x_probe1(pdev, ent->driver_data);
@@ -1061,10 +1086,13 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (e752x_pci)
+ edac_pci_release_generic_ctl(e752x_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
- pvt = (struct e752x_pvt *) mci->pvt_info;
+ pvt = (struct e752x_pvt *)mci->pvt_info;
pci_dev_put(pvt->dev_d0f0);
pci_dev_put(pvt->dev_d0f1);
pci_dev_put(pvt->bridge_ck);
@@ -1073,20 +1101,17 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7520
- },
+ PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7520},
{
- PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7525
- },
+ PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7525},
{
- PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7320
- },
+ PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7320},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
@@ -1122,5 +1147,6 @@ MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
module_param(force_function_unhide, int, 0444);
MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
-" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
-
+ " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 310d91b41c96..96ecc4926641 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -27,9 +27,10 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
-#define E7XXX_REVISION " Ver: 2.0.1 " __DATE__
+#define E7XXX_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "e7xxx_edac"
#define e7xxx_printk(level, fmt, arg...) \
@@ -143,23 +144,21 @@ struct e7xxx_error_info {
u32 dram_uelog_add;
};
+static struct edac_pci_ctl_info *e7xxx_pci;
+
static const struct e7xxx_dev_info e7xxx_devs[] = {
[E7500] = {
.err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
- .ctl_name = "E7500"
- },
+ .ctl_name = "E7500"},
[E7501] = {
.err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
- .ctl_name = "E7501"
- },
+ .ctl_name = "E7501"},
[E7505] = {
.err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
- .ctl_name = "E7505"
- },
+ .ctl_name = "E7505"},
[E7205] = {
.err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
- .ctl_name = "E7205"
- },
+ .ctl_name = "E7205"},
};
/* FIXME - is this valid for both SECDED and S4ECD4ED? */
@@ -180,15 +179,15 @@ static inline int e7xxx_find_channel(u16 syndrome)
}
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
- unsigned long page)
+ unsigned long page)
{
u32 remap;
- struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info;
+ struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
debugf3("%s()\n", __func__);
if ((page < pvt->tolm) ||
- ((page >= 0x100000) && (page < pvt->remapbase)))
+ ((page >= 0x100000) && (page < pvt->remapbase)))
return page;
remap = (page - pvt->tolm) + pvt->remapbase;
@@ -200,8 +199,7 @@ static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
return pvt->tolm - 1;
}
-static void process_ce(struct mem_ctl_info *mci,
- struct e7xxx_error_info *info)
+static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
{
u32 error_1b, page;
u16 syndrome;
@@ -212,7 +210,7 @@ static void process_ce(struct mem_ctl_info *mci,
/* read the error address */
error_1b = info->dram_celog_add;
/* FIXME - should use PAGE_SHIFT */
- page = error_1b >> 6; /* convert the address to 4k page */
+ page = error_1b >> 6; /* convert the address to 4k page */
/* read the syndrome */
syndrome = info->dram_celog_syndrome;
/* FIXME - check for -1 */
@@ -228,8 +226,7 @@ static void process_ce_no_info(struct mem_ctl_info *mci)
edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");
}
-static void process_ue(struct mem_ctl_info *mci,
- struct e7xxx_error_info *info)
+static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
{
u32 error_2b, block_page;
int row;
@@ -238,7 +235,7 @@ static void process_ue(struct mem_ctl_info *mci,
/* read the error address */
error_2b = info->dram_uelog_add;
/* FIXME - should use PAGE_SHIFT */
- block_page = error_2b >> 6; /* convert to 4k address */
+ block_page = error_2b >> 6; /* convert to 4k address */
row = edac_mc_find_csrow_by_page(mci, block_page);
edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");
}
@@ -249,16 +246,14 @@ static void process_ue_no_info(struct mem_ctl_info *mci)
edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");
}
-static void e7xxx_get_error_info (struct mem_ctl_info *mci,
- struct e7xxx_error_info *info)
+static void e7xxx_get_error_info(struct mem_ctl_info *mci,
+ struct e7xxx_error_info *info)
{
struct e7xxx_pvt *pvt;
- pvt = (struct e7xxx_pvt *) mci->pvt_info;
- pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR,
- &info->dram_ferr);
- pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR,
- &info->dram_nerr);
+ pvt = (struct e7xxx_pvt *)mci->pvt_info;
+ pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, &info->dram_ferr);
+ pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, &info->dram_nerr);
if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) {
pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD,
@@ -279,8 +274,9 @@ static void e7xxx_get_error_info (struct mem_ctl_info *mci,
pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
}
-static int e7xxx_process_error_info (struct mem_ctl_info *mci,
- struct e7xxx_error_info *info, int handle_errors)
+static int e7xxx_process_error_info(struct mem_ctl_info *mci,
+ struct e7xxx_error_info *info,
+ int handle_errors)
{
int error_found;
@@ -341,7 +337,6 @@ static inline int dual_channel_active(u32 drc, int dev_idx)
return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1;
}
-
/* Return DRB granularity (0=32mb, 1=64mb). */
static inline int drb_granularity(u32 drc, int dev_idx)
{
@@ -349,9 +344,8 @@ static inline int drb_granularity(u32 drc, int dev_idx)
return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1;
}
-
static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- int dev_idx, u32 drc)
+ int dev_idx, u32 drc)
{
unsigned long last_cumul_size;
int index;
@@ -419,10 +413,21 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
struct e7xxx_error_info discard;
debugf0("%s(): mci\n", __func__);
+
+ /* make sure error reporting method is sane */
+ switch (edac_op_state) {
+ case EDAC_OPSTATE_POLL:
+ case EDAC_OPSTATE_NMI:
+ break;
+ default:
+ edac_op_state = EDAC_OPSTATE_POLL;
+ break;
+ }
+
pci_read_config_dword(pdev, E7XXX_DRC, &drc);
drc_chan = dual_channel_active(drc, dev_idx);
- mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);
+ mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0);
if (mci == NULL)
return -ENOMEM;
@@ -430,17 +435,16 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): init mci\n", __func__);
mci->mtype_cap = MEM_FLAG_RDDR;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
- EDAC_FLAG_S4ECD4ED;
+ EDAC_FLAG_S4ECD4ED;
/* FIXME - what if different memory types are in different csrows? */
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = E7XXX_REVISION;
mci->dev = &pdev->dev;
debugf3("%s(): init pvt\n", __func__);
- pvt = (struct e7xxx_pvt *) mci->pvt_info;
+ pvt = (struct e7xxx_pvt *)mci->pvt_info;
pvt->dev_info = &e7xxx_devs[dev_idx];
pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev,
- pvt->bridge_ck);
+ pvt->dev_info->err_dev, pvt->bridge_ck);
if (!pvt->bridge_ck) {
e7xxx_printk(KERN_ERR, "error reporting device not found:"
@@ -451,6 +455,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
debugf3("%s(): more mci init\n", __func__);
mci->ctl_name = pvt->dev_info->ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = e7xxx_check;
mci->ctl_page_to_phys = ctl_page_to_phys;
e7xxx_init_csrows(mci, pdev, dev_idx, drc);
@@ -473,11 +478,22 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail1;
}
+ /* allocating generic PCI control info */
+ e7xxx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!e7xxx_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
@@ -493,7 +509,7 @@ fail0:
/* returns count (>= 0), or negative on error */
static int __devinit e7xxx_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
@@ -509,34 +525,33 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (e7xxx_pci)
+ edac_pci_release_generic_ctl(e7xxx_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
- pvt = (struct e7xxx_pvt *) mci->pvt_info;
+ pvt = (struct e7xxx_pvt *)mci->pvt_info;
pci_dev_put(pvt->bridge_ck);
edac_mc_free(mci);
}
static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7205
- },
+ PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7205},
{
- PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7500
- },
+ PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7500},
{
- PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7501
- },
+ PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7501},
{
- PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- E7505
- },
+ PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ E7505},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
@@ -563,5 +578,7 @@ module_exit(e7xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
- "Based on.work by Dan Hollis et al");
+ "Based on.work by Dan Hollis et al");
MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_core.h
index 713444cc4105..4e6bad15c4ba 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_core.h
@@ -1,6 +1,7 @@
/*
- * MC kernel module
- * (C) 2003 Linux Networx (http://lnxi.com)
+ * Defines, structures, APIs for edac_core module
+ *
+ * (C) 2007 Linux Networx (http://lnxi.com)
* This file may be distributed under the terms of the
* GNU General Public License.
*
@@ -11,12 +12,13 @@
* NMI handling support added by
* Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
*
- * $Id: edac_mc.h,v 1.4.2.10 2005/10/05 00:43:44 dsp_llnl Exp $
+ * Refactored for multi-source files:
+ * Doug Thompson <norsk5@xmission.com>
*
*/
-#ifndef _EDAC_MC_H_
-#define _EDAC_MC_H_
+#ifndef _EDAC_CORE_H_
+#define _EDAC_CORE_H_
#include <linux/kernel.h>
#include <linux/types.h>
@@ -30,9 +32,14 @@
#include <linux/completion.h>
#include <linux/kobject.h>
#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
#define EDAC_MC_LABEL_LEN 31
-#define MC_PROC_NAME_MAX_LEN 7
+#define EDAC_DEVICE_NAME_LEN 31
+#define EDAC_ATTRIB_VALUE_LEN 15
+#define MC_PROC_NAME_MAX_LEN 7
#if PAGE_SHIFT < 20
#define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) )
@@ -49,6 +56,14 @@
#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
+/* edac_device printk */
+#define edac_device_printk(ctl, level, fmt, arg...) \
+ printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
+
+/* edac_pci printk */
+#define edac_pci_printk(ctl, level, fmt, arg...) \
+ printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)
+
/* prefixes for edac_printk() and edac_mc_printk() */
#define EDAC_MC "MC"
#define EDAC_PCI "PCI"
@@ -60,7 +75,7 @@ extern int edac_debug_level;
#define edac_debug_printk(level, fmt, arg...) \
do { \
if (level <= edac_debug_level) \
- edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \
+ edac_printk(KERN_EMERG, EDAC_DEBUG, fmt, ##arg); \
} while(0)
#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
@@ -69,7 +84,7 @@ extern int edac_debug_level;
#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
-#else /* !CONFIG_EDAC_DEBUG */
+#else /* !CONFIG_EDAC_DEBUG */
#define debugf0( ... )
#define debugf1( ... )
@@ -77,18 +92,14 @@ extern int edac_debug_level;
#define debugf3( ... )
#define debugf4( ... )
-#endif /* !CONFIG_EDAC_DEBUG */
+#endif /* !CONFIG_EDAC_DEBUG */
#define BIT(x) (1 << (x))
#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
PCI_DEVICE_ID_ ## vend ## _ ## dev
-#if defined(CONFIG_X86) && defined(CONFIG_PCI)
-#define dev_name(dev) pci_name(to_pci_dev(dev))
-#else
-#define dev_name(dev) to_platform_device(dev)->name
-#endif
+#define dev_name(dev) (dev)->dev_name
/* memory devices */
enum dev_type {
@@ -124,8 +135,9 @@ enum mem_type {
MEM_DDR, /* Double data rate SDRAM */
MEM_RDDR, /* Registered Double data rate SDRAM */
MEM_RMBS, /* Rambus DRAM */
- MEM_DDR2, /* DDR2 RAM */
- MEM_FB_DDR2, /* fully buffered DDR2 */
+ MEM_DDR2, /* DDR2 RAM */
+ MEM_FB_DDR2, /* fully buffered DDR2 */
+ MEM_RDDR2, /* Registered DDR2 RAM */
};
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
@@ -141,6 +153,7 @@ enum mem_type {
#define MEM_FLAG_RMBS BIT(MEM_RMBS)
#define MEM_FLAG_DDR2 BIT(MEM_DDR2)
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
+#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
/* chipset Error Detection and Correction capabilities and mode */
enum edac_type {
@@ -181,16 +194,23 @@ enum scrub_type {
};
#define SCRUB_FLAG_SW_PROG BIT(SCRUB_SW_PROG)
-#define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC_CORR)
-#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC_CORR)
+#define SCRUB_FLAG_SW_SRC BIT(SCRUB_SW_SRC)
+#define SCRUB_FLAG_SW_PROG_SRC BIT(SCRUB_SW_PROG_SRC)
#define SCRUB_FLAG_SW_TUN BIT(SCRUB_SW_SCRUB_TUNABLE)
#define SCRUB_FLAG_HW_PROG BIT(SCRUB_HW_PROG)
-#define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC_CORR)
-#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC_CORR)
+#define SCRUB_FLAG_HW_SRC BIT(SCRUB_HW_SRC)
+#define SCRUB_FLAG_HW_PROG_SRC BIT(SCRUB_HW_PROG_SRC)
#define SCRUB_FLAG_HW_TUN BIT(SCRUB_HW_TUNABLE)
/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
+/* EDAC internal operation states */
+#define OP_ALLOC 0x100
+#define OP_RUNNING_POLL 0x201
+#define OP_RUNNING_INTERRUPT 0x202
+#define OP_RUNNING_POLL_INTR 0x203
+#define OP_OFFLINE 0x300
+
/*
* There are several things to be aware of that aren't at all obvious:
*
@@ -276,7 +296,7 @@ enum scrub_type {
struct channel_info {
int chan_idx; /* channel index */
u32 ce_count; /* Correctable Errors for this CHANNEL */
- char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
+ char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */
struct csrow_info *csrow; /* the parent */
};
@@ -297,15 +317,29 @@ struct csrow_info {
struct mem_ctl_info *mci; /* the parent */
struct kobject kobj; /* sysfs kobject for this csrow */
- struct completion kobj_complete;
- /* FIXME the number of CHANNELs might need to become dynamic */
+ /* channel information for this csrow */
u32 nr_channels;
struct channel_info *channels;
};
+/* mcidev_sysfs_attribute structure
+ * used for driver sysfs attributes and in mem_ctl_info
+ * sysfs top level entries
+ */
+struct mcidev_sysfs_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct mem_ctl_info *,char *);
+ ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
+};
+
+/* MEMORY controller information structure
+ */
struct mem_ctl_info {
- struct list_head link; /* for global list of mem_ctl_info structs */
+ struct list_head link; /* for global list of mem_ctl_info structs */
+
+ struct module *owner; /* Module owner of this control struct */
+
unsigned long mtype_cap; /* memory types supported by mc */
unsigned long edac_ctl_cap; /* Mem controller EDAC capabilities */
unsigned long edac_cap; /* configuration capabilities - this is
@@ -322,14 +356,15 @@ struct mem_ctl_info {
/* Translates sdram memory scrub rate given in bytes/sec to the
internal representation and configures whatever else needs
to be configured.
- */
- int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+ */
+ int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
/* Get the current sdram memory scrub rate from the internal
representation and converts it to the closest matching
bandwith in bytes/sec.
- */
- int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
+ */
+ int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
+
/* pointer to edac checking routine */
void (*edac_check) (struct mem_ctl_info * mci);
@@ -340,7 +375,7 @@ struct mem_ctl_info {
*/
/* FIXME - why not send the phys page to begin with? */
unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
- unsigned long page);
+ unsigned long page);
int mc_idx;
int nr_csrows;
struct csrow_info *csrows;
@@ -353,6 +388,7 @@ struct mem_ctl_info {
const char *mod_name;
const char *mod_ver;
const char *ctl_name;
+ const char *dev_name;
char proc_name[MC_PROC_NAME_MAX_LEN + 1];
void *pvt_info;
u32 ue_noinfo_count; /* Uncorrectable Errors w/o info */
@@ -369,14 +405,327 @@ struct mem_ctl_info {
/* edac sysfs device control */
struct kobject edac_mci_kobj;
- struct completion kobj_complete;
+
+ /* Additional top controller level attributes, but specified
+ * by the low level driver.
+ *
+ * Set by the low level driver to provide attributes at the
+ * controller level, same level as 'ue_count' and 'ce_count' above.
+ * An array of structures, NULL terminated
+ *
+ * If attributes are desired, then set to array of attributes
+ * If no attributes are desired, leave NULL
+ */
+ struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
+
+ /* work struct for this MC */
+ struct delayed_work work;
+
+ /* the internal state of this controller instance */
+ int op_state;
+};
+
+/*
+ * The following are the structures to provide for a generic
+ * or abstract 'edac_device'. This set of structures and the
+ * code that implements the APIs for the same, provide for
+ * registering EDAC type devices which are NOT standard memory.
+ *
+ * CPU caches (L1 and L2)
+ * DMA engines
+ * Core CPU swithces
+ * Fabric switch units
+ * PCIe interface controllers
+ * other EDAC/ECC type devices that can be monitored for
+ * errors, etc.
+ *
+ * It allows for a 2 level set of hiearchry. For example:
+ *
+ * cache could be composed of L1, L2 and L3 levels of cache.
+ * Each CPU core would have its own L1 cache, while sharing
+ * L2 and maybe L3 caches.
+ *
+ * View them arranged, via the sysfs presentation:
+ * /sys/devices/system/edac/..
+ *
+ * mc/ <existing memory device directory>
+ * cpu/cpu0/.. <L1 and L2 block directory>
+ * /L1-cache/ce_count
+ * /ue_count
+ * /L2-cache/ce_count
+ * /ue_count
+ * cpu/cpu1/.. <L1 and L2 block directory>
+ * /L1-cache/ce_count
+ * /ue_count
+ * /L2-cache/ce_count
+ * /ue_count
+ * ...
+ *
+ * the L1 and L2 directories would be "edac_device_block's"
+ */
+
+struct edac_device_counter {
+ u32 ue_count;
+ u32 ce_count;
+};
+
+/* forward reference */
+struct edac_device_ctl_info;
+struct edac_device_block;
+
+/* edac_dev_sysfs_attribute structure
+ * used for driver sysfs attributes in mem_ctl_info
+ * for extra controls and attributes:
+ * like high level error Injection controls
+ */
+struct edac_dev_sysfs_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct edac_device_ctl_info *, char *);
+ ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t);
+};
+
+/* edac_dev_sysfs_block_attribute structure
+ *
+ * used in leaf 'block' nodes for adding controls/attributes
+ *
+ * each block in each instance of the containing control structure
+ * can have an array of the following. The show and store functions
+ * will be filled in with the show/store function in the
+ * low level driver.
+ *
+ * The 'value' field will be the actual value field used for
+ * counting
+ */
+struct edac_dev_sysfs_block_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct kobject *, struct attribute *, char *);
+ ssize_t (*store)(struct kobject *, struct attribute *,
+ const char *, size_t);
+ struct edac_device_block *block;
+
+ unsigned int value;
+};
+
+/* device block control structure */
+struct edac_device_block {
+ struct edac_device_instance *instance; /* Up Pointer */
+ char name[EDAC_DEVICE_NAME_LEN + 1];
+
+ struct edac_device_counter counters; /* basic UE and CE counters */
+
+ int nr_attribs; /* how many attributes */
+
+ /* this block's attributes, could be NULL */
+ struct edac_dev_sysfs_block_attribute *block_attributes;
+
+ /* edac sysfs device control */
+ struct kobject kobj;
+};
+
+/* device instance control structure */
+struct edac_device_instance {
+ struct edac_device_ctl_info *ctl; /* Up pointer */
+ char name[EDAC_DEVICE_NAME_LEN + 4];
+
+ struct edac_device_counter counters; /* instance counters */
+
+ u32 nr_blocks; /* how many blocks */
+ struct edac_device_block *blocks; /* block array */
+
+ /* edac sysfs device control */
+ struct kobject kobj;
+};
+
+
+/*
+ * Abstract edac_device control info structure
+ *
+ */
+struct edac_device_ctl_info {
+ /* for global list of edac_device_ctl_info structs */
+ struct list_head link;
+
+ struct module *owner; /* Module owner of this control struct */
+
+ int dev_idx;
+
+ /* Per instance controls for this edac_device */
+ int log_ue; /* boolean for logging UEs */
+ int log_ce; /* boolean for logging CEs */
+ int panic_on_ue; /* boolean for panic'ing on an UE */
+ unsigned poll_msec; /* number of milliseconds to poll interval */
+ unsigned long delay; /* number of jiffies for poll_msec */
+
+ /* Additional top controller level attributes, but specified
+ * by the low level driver.
+ *
+ * Set by the low level driver to provide attributes at the
+ * controller level, same level as 'ue_count' and 'ce_count' above.
+ * An array of structures, NULL terminated
+ *
+ * If attributes are desired, then set to array of attributes
+ * If no attributes are desired, leave NULL
+ */
+ struct edac_dev_sysfs_attribute *sysfs_attributes;
+
+ /* pointer to main 'edac' class in sysfs */
+ struct sysdev_class *edac_class;
+
+ /* the internal state of this controller instance */
+ int op_state;
+ /* work struct for this instance */
+ struct delayed_work work;
+
+ /* pointer to edac polling checking routine:
+ * If NOT NULL: points to polling check routine
+ * If NULL: Then assumes INTERRUPT operation, where
+ * MC driver will receive events
+ */
+ void (*edac_check) (struct edac_device_ctl_info * edac_dev);
+
+ struct device *dev; /* pointer to device structure */
+
+ const char *mod_name; /* module name */
+ const char *ctl_name; /* edac controller name */
+ const char *dev_name; /* pci/platform/etc... name */
+
+ void *pvt_info; /* pointer to 'private driver' info */
+
+ unsigned long start_time; /* edac_device load start time (jiffies) */
+
+ /* these are for safe removal of mc devices from global list while
+ * NMI handlers may be traversing list
+ */
+ struct rcu_head rcu;
+ struct completion removal_complete;
+
+ /* sysfs top name under 'edac' directory
+ * and instance name:
+ * cpu/cpu0/...
+ * cpu/cpu1/...
+ * cpu/cpu2/...
+ * ...
+ */
+ char name[EDAC_DEVICE_NAME_LEN + 1];
+
+ /* Number of instances supported on this control structure
+ * and the array of those instances
+ */
+ u32 nr_instances;
+ struct edac_device_instance *instances;
+
+ /* Event counters for the this whole EDAC Device */
+ struct edac_device_counter counters;
+
+ /* edac sysfs device control for the 'name'
+ * device this structure controls
+ */
+ struct kobject kobj;
};
+/* To get from the instance's wq to the beginning of the ctl structure */
+#define to_edac_mem_ctl_work(w) \
+ container_of(w, struct mem_ctl_info, work)
+
+#define to_edac_device_ctl_work(w) \
+ container_of(w,struct edac_device_ctl_info,work)
+
+/*
+ * The alloc() and free() functions for the 'edac_device' control info
+ * structure. A MC driver will allocate one of these for each edac_device
+ * it is going to control/register with the EDAC CORE.
+ */
+extern struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+ unsigned sizeof_private,
+ char *edac_device_name, unsigned nr_instances,
+ char *edac_block_name, unsigned nr_blocks,
+ unsigned offset_value,
+ struct edac_dev_sysfs_block_attribute *block_attributes,
+ unsigned nr_attribs,
+ int device_index);
+
+/* The offset value can be:
+ * -1 indicating no offset value
+ * 0 for zero-based block numbers
+ * 1 for 1-based block number
+ * other for other-based block number
+ */
+#define BLOCK_OFFSET_VALUE_OFF ((unsigned) -1)
+
+extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info);
+
#ifdef CONFIG_PCI
+struct edac_pci_counter {
+ atomic_t pe_count;
+ atomic_t npe_count;
+};
+
+/*
+ * Abstract edac_pci control info structure
+ *
+ */
+struct edac_pci_ctl_info {
+ /* for global list of edac_pci_ctl_info structs */
+ struct list_head link;
+
+ int pci_idx;
+
+ struct sysdev_class *edac_class; /* pointer to class */
+
+ /* the internal state of this controller instance */
+ int op_state;
+ /* work struct for this instance */
+ struct delayed_work work;
+
+ /* pointer to edac polling checking routine:
+ * If NOT NULL: points to polling check routine
+ * If NULL: Then assumes INTERRUPT operation, where
+ * MC driver will receive events
+ */
+ void (*edac_check) (struct edac_pci_ctl_info * edac_dev);
+
+ struct device *dev; /* pointer to device structure */
+
+ const char *mod_name; /* module name */
+ const char *ctl_name; /* edac controller name */
+ const char *dev_name; /* pci/platform/etc... name */
+
+ void *pvt_info; /* pointer to 'private driver' info */
+
+ unsigned long start_time; /* edac_pci load start time (jiffies) */
+
+ /* these are for safe removal of devices from global list while
+ * NMI handlers may be traversing list
+ */
+ struct rcu_head rcu;
+ struct completion complete;
+
+ /* sysfs top name under 'edac' directory
+ * and instance name:
+ * cpu/cpu0/...
+ * cpu/cpu1/...
+ * cpu/cpu2/...
+ * ...
+ */
+ char name[EDAC_DEVICE_NAME_LEN + 1];
+
+ /* Event counters for the this whole EDAC Device */
+ struct edac_pci_counter counters;
+
+ /* edac sysfs device control for the 'name'
+ * device this structure controls
+ */
+ struct kobject kobj;
+ struct completion kobj_complete;
+};
+
+#define to_edac_pci_ctl_work(w) \
+ container_of(w, struct edac_pci_ctl_info,work)
+
/* write all or some bits in a byte-register*/
static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
- u8 mask)
+ u8 mask)
{
if (mask != 0xff) {
u8 buf;
@@ -392,7 +741,7 @@ static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
/* write all or some bits in a word-register*/
static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
- u16 value, u16 mask)
+ u16 value, u16 mask)
{
if (mask != 0xffff) {
u16 buf;
@@ -408,7 +757,7 @@ static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
/* write all or some bits in a dword-register*/
static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
- u32 value, u32 mask)
+ u32 value, u32 mask)
{
if (mask != 0xffff) {
u32 buf;
@@ -422,20 +771,16 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
pci_write_config_dword(pdev, offset, value);
}
-#endif /* CONFIG_PCI */
+#endif /* CONFIG_PCI */
-#ifdef CONFIG_EDAC_DEBUG
-void edac_mc_dump_channel(struct channel_info *chan);
-void edac_mc_dump_mci(struct mem_ctl_info *mci);
-void edac_mc_dump_csrow(struct csrow_info *csrow);
-#endif /* CONFIG_EDAC_DEBUG */
-
-extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx);
-extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev);
+extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
+ unsigned nr_chans, int edac_index);
+extern int edac_mc_add_mc(struct mem_ctl_info *mci);
+extern void edac_mc_free(struct mem_ctl_info *mci);
+extern struct mem_ctl_info *edac_mc_find(int idx);
+extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
- unsigned long page);
-extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
- u32 size);
+ unsigned long page);
/*
* The no info errors are used when error overflows are reported.
@@ -448,34 +793,59 @@ extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
* statement clutter and extra function arguments.
*/
extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- unsigned long syndrome, int row, int channel,
- const char *msg);
+ unsigned long page_frame_number,
+ unsigned long offset_in_page,
+ unsigned long syndrome, int row, int channel,
+ const char *msg);
extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
- const char *msg);
+ const char *msg);
extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- int row, const char *msg);
+ unsigned long page_frame_number,
+ unsigned long offset_in_page, int row,
+ const char *msg);
extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
- const char *msg);
-extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channel0,
- unsigned int channel1,
- char *msg);
-extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channel,
- char *msg);
+ const char *msg);
+extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow,
+ unsigned int channel0, unsigned int channel1,
+ char *msg);
+extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow,
+ unsigned int channel, char *msg);
/*
- * This kmalloc's and initializes all the structures.
- * Can't be used if all structures don't have the same lifetime.
+ * edac_device APIs
*/
-extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
- unsigned nr_chans);
+extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev);
+extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev);
+extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg);
+extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg);
-/* Free an mc previously allocated by edac_mc_alloc() */
-extern void edac_mc_free(struct mem_ctl_info *mci);
+/*
+ * edac_pci APIs
+ */
+extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+ const char *edac_pci_name);
+
+extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
+
+extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+ unsigned long value);
+
+extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
+extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);
+
+extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl(
+ struct device *dev,
+ const char *mod_name);
+
+extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
+extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
+extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
+
+/*
+ * edac misc APIs
+ */
+extern char *edac_op_state_to_string(int op_state);
-#endif /* _EDAC_MC_H_ */
+#endif /* _EDAC_CORE_H_ */
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
new file mode 100644
index 000000000000..f3690a697cf9
--- /dev/null
+++ b/drivers/edac/edac_device.c
@@ -0,0 +1,746 @@
+
+/*
+ * edac_device.c
+ * (C) 2007 www.douglaskthompson.com
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Doug Thompson <norsk5@xmission.com>
+ *
+ * edac_device API implementation
+ * 19 Jan 2007
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* lock for the list: 'edac_device_list', manipulation of this list
+ * is protected by the 'device_ctls_mutex' lock
+ */
+static DEFINE_MUTEX(device_ctls_mutex);
+static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list);
+
+#ifdef CONFIG_EDAC_DEBUG
+static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
+{
+ debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx);
+ debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
+ debugf3("\tdev = %p\n", edac_dev->dev);
+ debugf3("\tmod_name:ctl_name = %s:%s\n",
+ edac_dev->mod_name, edac_dev->ctl_name);
+ debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
+}
+#endif /* CONFIG_EDAC_DEBUG */
+
+
+/*
+ * edac_device_alloc_ctl_info()
+ * Allocate a new edac device control info structure
+ *
+ * The control structure is allocated in complete chunk
+ * from the OS. It is in turn sub allocated to the
+ * various objects that compose the struture
+ *
+ * The structure has a 'nr_instance' array within itself.
+ * Each instance represents a major component
+ * Example: L1 cache and L2 cache are 2 instance components
+ *
+ * Within each instance is an array of 'nr_blocks' blockoffsets
+ */
+struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+ unsigned sz_private,
+ char *edac_device_name, unsigned nr_instances,
+ char *edac_block_name, unsigned nr_blocks,
+ unsigned offset_value, /* zero, 1, or other based offset */
+ struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib,
+ int device_index)
+{
+ struct edac_device_ctl_info *dev_ctl;
+ struct edac_device_instance *dev_inst, *inst;
+ struct edac_device_block *dev_blk, *blk_p, *blk;
+ struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
+ unsigned total_size;
+ unsigned count;
+ unsigned instance, block, attr;
+ void *pvt;
+ int err;
+
+ debugf4("%s() instances=%d blocks=%d\n",
+ __func__, nr_instances, nr_blocks);
+
+ /* Calculate the size of memory we need to allocate AND
+ * determine the offsets of the various item arrays
+ * (instance,block,attrib) from the start of an allocated structure.
+ * We want the alignment of each item (instance,block,attrib)
+ * to be at least as stringent as what the compiler would
+ * provide if we could simply hardcode everything into a single struct.
+ */
+ dev_ctl = (struct edac_device_ctl_info *)NULL;
+
+ /* Calc the 'end' offset past end of ONE ctl_info structure
+ * which will become the start of the 'instance' array
+ */
+ dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst));
+
+ /* Calc the 'end' offset past the instance array within the ctl_info
+ * which will become the start of the block array
+ */
+ dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk));
+
+ /* Calc the 'end' offset past the dev_blk array
+ * which will become the start of the attrib array, if any.
+ */
+ count = nr_instances * nr_blocks;
+ dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib));
+
+ /* Check for case of when an attribute array is specified */
+ if (nr_attrib > 0) {
+ /* calc how many nr_attrib we need */
+ count *= nr_attrib;
+
+ /* Calc the 'end' offset past the attributes array */
+ pvt = edac_align_ptr(&dev_attrib[count], sz_private);
+ } else {
+ /* no attribute array specificed */
+ pvt = edac_align_ptr(dev_attrib, sz_private);
+ }
+
+ /* 'pvt' now points to where the private data area is.
+ * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
+ * is baselined at ZERO
+ */
+ total_size = ((unsigned long)pvt) + sz_private;
+
+ /* Allocate the amount of memory for the set of control structures */
+ dev_ctl = kzalloc(total_size, GFP_KERNEL);
+ if (dev_ctl == NULL)
+ return NULL;
+
+ /* Adjust pointers so they point within the actual memory we
+ * just allocated rather than an imaginary chunk of memory
+ * located at address 0.
+ * 'dev_ctl' points to REAL memory, while the others are
+ * ZERO based and thus need to be adjusted to point within
+ * the allocated memory.
+ */
+ dev_inst = (struct edac_device_instance *)
+ (((char *)dev_ctl) + ((unsigned long)dev_inst));
+ dev_blk = (struct edac_device_block *)
+ (((char *)dev_ctl) + ((unsigned long)dev_blk));
+ dev_attrib = (struct edac_dev_sysfs_block_attribute *)
+ (((char *)dev_ctl) + ((unsigned long)dev_attrib));
+ pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;
+
+ /* Begin storing the information into the control info structure */
+ dev_ctl->dev_idx = device_index;
+ dev_ctl->nr_instances = nr_instances;
+ dev_ctl->instances = dev_inst;
+ dev_ctl->pvt_info = pvt;
+
+ /* Name of this edac device */
+ snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
+
+ debugf4("%s() edac_dev=%p next after end=%p\n",
+ __func__, dev_ctl, pvt + sz_private );
+
+ /* Initialize every Instance */
+ for (instance = 0; instance < nr_instances; instance++) {
+ inst = &dev_inst[instance];
+ inst->ctl = dev_ctl;
+ inst->nr_blocks = nr_blocks;
+ blk_p = &dev_blk[instance * nr_blocks];
+ inst->blocks = blk_p;
+
+ /* name of this instance */
+ snprintf(inst->name, sizeof(inst->name),
+ "%s%u", edac_device_name, instance);
+
+ /* Initialize every block in each instance */
+ for (block = 0; block < nr_blocks; block++) {
+ blk = &blk_p[block];
+ blk->instance = inst;
+ snprintf(blk->name, sizeof(blk->name),
+ "%s%d", edac_block_name, block+offset_value);
+
+ debugf4("%s() instance=%d inst_p=%p block=#%d "
+ "block_p=%p name='%s'\n",
+ __func__, instance, inst, block,
+ blk, blk->name);
+
+ /* if there are NO attributes OR no attribute pointer
+ * then continue on to next block iteration
+ */
+ if ((nr_attrib == 0) || (attrib_spec == NULL))
+ continue;
+
+ /* setup the attribute array for this block */
+ blk->nr_attribs = nr_attrib;
+ attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
+ blk->block_attributes = attrib_p;
+
+ debugf4("%s() THIS BLOCK_ATTRIB=%p\n",
+ __func__, blk->block_attributes);
+
+ /* Initialize every user specified attribute in this
+ * block with the data the caller passed in
+ * Each block gets its own copy of pointers,
+ * and its unique 'value'
+ */
+ for (attr = 0; attr < nr_attrib; attr++) {
+ attrib = &attrib_p[attr];
+
+ /* populate the unique per attrib
+ * with the code pointers and info
+ */
+ attrib->attr = attrib_spec[attr].attr;
+ attrib->show = attrib_spec[attr].show;
+ attrib->store = attrib_spec[attr].store;
+
+ attrib->block = blk; /* up link */
+
+ debugf4("%s() alloc-attrib=%p attrib_name='%s' "
+ "attrib-spec=%p spec-name=%s\n",
+ __func__, attrib, attrib->attr.name,
+ &attrib_spec[attr],
+ attrib_spec[attr].attr.name
+ );
+ }
+ }
+ }
+
+ /* Mark this instance as merely ALLOCATED */
+ dev_ctl->op_state = OP_ALLOC;
+
+ /*
+ * Initialize the 'root' kobj for the edac_device controller
+ */
+ err = edac_device_register_sysfs_main_kobj(dev_ctl);
+ if (err) {
+ kfree(dev_ctl);
+ return NULL;
+ }
+
+ /* at this point, the root kobj is valid, and in order to
+ * 'free' the object, then the function:
+ * edac_device_unregister_sysfs_main_kobj() must be called
+ * which will perform kobj unregistration and the actual free
+ * will occur during the kobject callback operation
+ */
+
+ return dev_ctl;
+}
+EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
+
+/*
+ * edac_device_free_ctl_info()
+ * frees the memory allocated by the edac_device_alloc_ctl_info()
+ * function
+ */
+void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info)
+{
+ edac_device_unregister_sysfs_main_kobj(ctl_info);
+}
+EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);
+
+/*
+ * find_edac_device_by_dev
+ * scans the edac_device list for a specific 'struct device *'
+ *
+ * lock to be held prior to call: device_ctls_mutex
+ *
+ * Return:
+ * pointer to control structure managing 'dev'
+ * NULL if not found on list
+ */
+static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
+{
+ struct edac_device_ctl_info *edac_dev;
+ struct list_head *item;
+
+ debugf0("%s()\n", __func__);
+
+ list_for_each(item, &edac_device_list) {
+ edac_dev = list_entry(item, struct edac_device_ctl_info, link);
+
+ if (edac_dev->dev == dev)
+ return edac_dev;
+ }
+
+ return NULL;
+}
+
+/*
+ * add_edac_dev_to_global_list
+ * Before calling this function, caller must
+ * assign a unique value to edac_dev->dev_idx.
+ *
+ * lock to be held prior to call: device_ctls_mutex
+ *
+ * Return:
+ * 0 on success
+ * 1 on failure.
+ */
+static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev)
+{
+ struct list_head *item, *insert_before;
+ struct edac_device_ctl_info *rover;
+
+ insert_before = &edac_device_list;
+
+ /* Determine if already on the list */
+ rover = find_edac_device_by_dev(edac_dev->dev);
+ if (unlikely(rover != NULL))
+ goto fail0;
+
+ /* Insert in ascending order by 'dev_idx', so find position */
+ list_for_each(item, &edac_device_list) {
+ rover = list_entry(item, struct edac_device_ctl_info, link);
+
+ if (rover->dev_idx >= edac_dev->dev_idx) {
+ if (unlikely(rover->dev_idx == edac_dev->dev_idx))
+ goto fail1;
+
+ insert_before = item;
+ break;
+ }
+ }
+
+ list_add_tail_rcu(&edac_dev->link, insert_before);
+ return 0;
+
+fail0:
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "%s (%s) %s %s already assigned %d\n",
+ rover->dev->bus_id, dev_name(rover),
+ rover->mod_name, rover->ctl_name, rover->dev_idx);
+ return 1;
+
+fail1:
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "bug in low-level driver: attempt to assign\n"
+ " duplicate dev_idx %d in %s()\n", rover->dev_idx,
+ __func__);
+ return 1;
+}
+
+/*
+ * complete_edac_device_list_del
+ *
+ * callback function when reference count is zero
+ */
+static void complete_edac_device_list_del(struct rcu_head *head)
+{
+ struct edac_device_ctl_info *edac_dev;
+
+ edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
+ INIT_LIST_HEAD(&edac_dev->link);
+ complete(&edac_dev->removal_complete);
+}
+
+/*
+ * del_edac_device_from_global_list
+ *
+ * remove the RCU, setup for a callback call,
+ * then wait for the callback to occur
+ */
+static void del_edac_device_from_global_list(struct edac_device_ctl_info
+ *edac_device)
+{
+ list_del_rcu(&edac_device->link);
+
+ init_completion(&edac_device->removal_complete);
+ call_rcu(&edac_device->rcu, complete_edac_device_list_del);
+ wait_for_completion(&edac_device->removal_complete);
+}
+
+/**
+ * edac_device_find
+ * Search for a edac_device_ctl_info structure whose index is 'idx'.
+ *
+ * If found, return a pointer to the structure.
+ * Else return NULL.
+ *
+ * Caller must hold device_ctls_mutex.
+ */
+struct edac_device_ctl_info *edac_device_find(int idx)
+{
+ struct list_head *item;
+ struct edac_device_ctl_info *edac_dev;
+
+ /* Iterate over list, looking for exact match of ID */
+ list_for_each(item, &edac_device_list) {
+ edac_dev = list_entry(item, struct edac_device_ctl_info, link);
+
+ if (edac_dev->dev_idx >= idx) {
+ if (edac_dev->dev_idx == idx)
+ return edac_dev;
+
+ /* not on list, so terminate early */
+ break;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(edac_device_find);
+
+/*
+ * edac_device_workq_function
+ * performs the operation scheduled by a workq request
+ *
+ * this workq is embedded within an edac_device_ctl_info
+ * structure, that needs to be polled for possible error events.
+ *
+ * This operation is to acquire the list mutex lock
+ * (thus preventing insertation or deletion)
+ * and then call the device's poll function IFF this device is
+ * running polled and there is a poll function defined.
+ */
+static void edac_device_workq_function(struct work_struct *work_req)
+{
+ struct delayed_work *d_work = (struct delayed_work *)work_req;
+ struct edac_device_ctl_info *edac_dev = to_edac_device_ctl_work(d_work);
+
+ mutex_lock(&device_ctls_mutex);
+
+ /* Only poll controllers that are running polled and have a check */
+ if ((edac_dev->op_state == OP_RUNNING_POLL) &&
+ (edac_dev->edac_check != NULL)) {
+ edac_dev->edac_check(edac_dev);
+ }
+
+ mutex_unlock(&device_ctls_mutex);
+
+ /* Reschedule the workq for the next time period to start again
+ * if the number of msec is for 1 sec, then adjust to the next
+ * whole one second to save timers fireing all over the period
+ * between integral seconds
+ */
+ if (edac_dev->poll_msec == 1000)
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ round_jiffies(edac_dev->delay));
+ else
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_setup
+ * initialize a workq item for this edac_device instance
+ * passing in the new delay period in msec
+ */
+void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+ unsigned msec)
+{
+ debugf0("%s()\n", __func__);
+
+ /* take the arg 'msec' and set it into the control structure
+ * to used in the time period calculation
+ * then calc the number of jiffies that represents
+ */
+ edac_dev->poll_msec = msec;
+ edac_dev->delay = msecs_to_jiffies(msec);
+
+ INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function);
+
+ /* optimize here for the 1 second case, which will be normal value, to
+ * fire ON the 1 second time event. This helps reduce all sorts of
+ * timers firing on sub-second basis, while they are happy
+ * to fire together on the 1 second exactly
+ */
+ if (edac_dev->poll_msec == 1000)
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ round_jiffies(edac_dev->delay));
+ else
+ queue_delayed_work(edac_workqueue, &edac_dev->work,
+ edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_teardown
+ * stop the workq processing on this edac_dev
+ */
+void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
+{
+ int status;
+
+ status = cancel_delayed_work(&edac_dev->work);
+ if (status == 0) {
+ /* workq instance might be running, wait for it */
+ flush_workqueue(edac_workqueue);
+ }
+}
+
+/*
+ * edac_device_reset_delay_period
+ *
+ * need to stop any outstanding workq queued up at this time
+ * because we will be resetting the sleep time.
+ * Then restart the workq on the new delay
+ */
+void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
+ unsigned long value)
+{
+ /* cancel the current workq request, without the mutex lock */
+ edac_device_workq_teardown(edac_dev);
+
+ /* acquire the mutex before doing the workq setup */
+ mutex_lock(&device_ctls_mutex);
+
+ /* restart the workq request, with new delay value */
+ edac_device_workq_setup(edac_dev, value);
+
+ mutex_unlock(&device_ctls_mutex);
+}
+
+/**
+ * edac_device_add_device: Insert the 'edac_dev' structure into the
+ * edac_device global list and create sysfs entries associated with
+ * edac_device structure.
+ * @edac_device: pointer to the edac_device structure to be added to the list
+ * 'edac_device' structure.
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
+{
+ debugf0("%s()\n", __func__);
+
+#ifdef CONFIG_EDAC_DEBUG
+ if (edac_debug_level >= 3)
+ edac_device_dump_device(edac_dev);
+#endif
+ mutex_lock(&device_ctls_mutex);
+
+ if (add_edac_dev_to_global_list(edac_dev))
+ goto fail0;
+
+ /* set load time so that error rate can be tracked */
+ edac_dev->start_time = jiffies;
+
+ /* create this instance's sysfs entries */
+ if (edac_device_create_sysfs(edac_dev)) {
+ edac_device_printk(edac_dev, KERN_WARNING,
+ "failed to create sysfs device\n");
+ goto fail1;
+ }
+
+ /* If there IS a check routine, then we are running POLLED */
+ if (edac_dev->edac_check != NULL) {
+ /* This instance is NOW RUNNING */
+ edac_dev->op_state = OP_RUNNING_POLL;
+
+ /*
+ * enable workq processing on this instance,
+ * default = 1000 msec
+ */
+ edac_device_workq_setup(edac_dev, 1000);
+ } else {
+ edac_dev->op_state = OP_RUNNING_INTERRUPT;
+ }
+
+ /* Report action taken */
+ edac_device_printk(edac_dev, KERN_INFO,
+ "Giving out device to module '%s' controller "
+ "'%s': DEV '%s' (%s)\n",
+ edac_dev->mod_name,
+ edac_dev->ctl_name,
+ dev_name(edac_dev),
+ edac_op_state_to_string(edac_dev->op_state));
+
+ mutex_unlock(&device_ctls_mutex);
+ return 0;
+
+fail1:
+ /* Some error, so remove the entry from the lsit */
+ del_edac_device_from_global_list(edac_dev);
+
+fail0:
+ mutex_unlock(&device_ctls_mutex);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(edac_device_add_device);
+
+/**
+ * edac_device_del_device:
+ * Remove sysfs entries for specified edac_device structure and
+ * then remove edac_device structure from global list
+ *
+ * @pdev:
+ * Pointer to 'struct device' representing edac_device
+ * structure to remove.
+ *
+ * Return:
+ * Pointer to removed edac_device structure,
+ * OR NULL if device not found.
+ */
+struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
+{
+ struct edac_device_ctl_info *edac_dev;
+
+ debugf0("%s()\n", __func__);
+
+ mutex_lock(&device_ctls_mutex);
+
+ /* Find the structure on the list, if not there, then leave */
+ edac_dev = find_edac_device_by_dev(dev);
+ if (edac_dev == NULL) {
+ mutex_unlock(&device_ctls_mutex);
+ return NULL;
+ }
+
+ /* mark this instance as OFFLINE */
+ edac_dev->op_state = OP_OFFLINE;
+
+ /* clear workq processing on this instance */
+ edac_device_workq_teardown(edac_dev);
+
+ /* deregister from global list */
+ del_edac_device_from_global_list(edac_dev);
+
+ mutex_unlock(&device_ctls_mutex);
+
+ /* Tear down the sysfs entries for this instance */
+ edac_device_remove_sysfs(edac_dev);
+
+ edac_printk(KERN_INFO, EDAC_MC,
+ "Removed device %d for %s %s: DEV %s\n",
+ edac_dev->dev_idx,
+ edac_dev->mod_name, edac_dev->ctl_name, dev_name(edac_dev));
+
+ return edac_dev;
+}
+EXPORT_SYMBOL_GPL(edac_device_del_device);
+
+static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev)
+{
+ return edac_dev->log_ce;
+}
+
+static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev)
+{
+ return edac_dev->log_ue;
+}
+
+static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info
+ *edac_dev)
+{
+ return edac_dev->panic_on_ue;
+}
+
+/*
+ * edac_device_handle_ce
+ * perform a common output and handling of an 'edac_dev' CE event
+ */
+void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg)
+{
+ struct edac_device_instance *instance;
+ struct edac_device_block *block = NULL;
+
+ if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: 'instance' out of range "
+ "(%d >= %d)\n", inst_nr,
+ edac_dev->nr_instances);
+ return;
+ }
+
+ instance = edac_dev->instances + inst_nr;
+
+ if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: instance %d 'block' "
+ "out of range (%d >= %d)\n",
+ inst_nr, block_nr,
+ instance->nr_blocks);
+ return;
+ }
+
+ if (instance->nr_blocks > 0) {
+ block = instance->blocks + block_nr;
+ block->counters.ce_count++;
+ }
+
+ /* Propogate the count up the 'totals' tree */
+ instance->counters.ce_count++;
+ edac_dev->counters.ce_count++;
+
+ if (edac_device_get_log_ce(edac_dev))
+ edac_device_printk(edac_dev, KERN_WARNING,
+ "CE: %s instance: %s block: %s '%s'\n",
+ edac_dev->ctl_name, instance->name,
+ block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ce);
+
+/*
+ * edac_device_handle_ue
+ * perform a common output and handling of an 'edac_dev' UE event
+ */
+void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+ int inst_nr, int block_nr, const char *msg)
+{
+ struct edac_device_instance *instance;
+ struct edac_device_block *block = NULL;
+
+ if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: 'instance' out of range "
+ "(%d >= %d)\n", inst_nr,
+ edac_dev->nr_instances);
+ return;
+ }
+
+ instance = edac_dev->instances + inst_nr;
+
+ if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+ edac_device_printk(edac_dev, KERN_ERR,
+ "INTERNAL ERROR: instance %d 'block' "
+ "out of range (%d >= %d)\n",
+ inst_nr, block_nr,
+ instance->nr_blocks);
+ return;
+ }
+
+ if (instance->nr_blocks > 0) {
+ block = instance->blocks + block_nr;
+ block->counters.ue_count++;
+ }
+
+ /* Propogate the count up the 'totals' tree */
+ instance->counters.ue_count++;
+ edac_dev->counters.ue_count++;
+
+ if (edac_device_get_log_ue(edac_dev))
+ edac_device_printk(edac_dev, KERN_EMERG,
+ "UE: %s instance: %s block: %s '%s'\n",
+ edac_dev->ctl_name, instance->name,
+ block ? block->name : "N/A", msg);
+
+ if (edac_device_get_panic_on_ue(edac_dev))
+ panic("EDAC %s: UE instance: %s block %s '%s'\n",
+ edac_dev->ctl_name, instance->name,
+ block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ue);
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
new file mode 100644
index 000000000000..70b837f23c43
--- /dev/null
+++ b/drivers/edac/edac_device_sysfs.c
@@ -0,0 +1,896 @@
+/*
+ * file for managing the edac_device class of devices for EDAC
+ *
+ * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_DEVICE_SYMLINK "device"
+
+#define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
+
+
+/*
+ * Set of edac_device_ctl_info attribute store/show functions
+ */
+
+/* 'log_ue' */
+static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->log_ue);
+}
+
+static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ /* if parameter is zero, turn off flag, if non-zero turn on flag */
+ ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+ return count;
+}
+
+/* 'log_ce' */
+static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->log_ce);
+}
+
+static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ /* if parameter is zero, turn off flag, if non-zero turn on flag */
+ ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0);
+
+ return count;
+}
+
+/* 'panic_on_ue' */
+static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->panic_on_ue);
+}
+
+static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ /* if parameter is zero, turn off flag, if non-zero turn on flag */
+ ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+ return count;
+}
+
+/* 'poll_msec' show and store functions*/
+static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info
+ *ctl_info, char *data)
+{
+ return sprintf(data, "%u\n", ctl_info->poll_msec);
+}
+
+static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info
+ *ctl_info, const char *data,
+ size_t count)
+{
+ unsigned long value;
+
+ /* get the value and enforce that it is non-zero, must be at least
+ * one millisecond for the delay period, between scans
+ * Then cancel last outstanding delay for the work request
+ * and set a new one.
+ */
+ value = simple_strtoul(data, NULL, 0);
+ edac_device_reset_delay_period(ctl_info, value);
+
+ return count;
+}
+
+/* edac_device_ctl_info specific attribute structure */
+struct ctl_info_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct edac_device_ctl_info *, char *);
+ ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t);
+};
+
+#define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
+
+/* Function to 'show' fields from the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+ struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+ if (ctl_info_attr->show)
+ return ctl_info_attr->show(edac_dev, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+ struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+ if (ctl_info_attr->store)
+ return ctl_info_attr->store(edac_dev, buffer, count);
+ return -EIO;
+}
+
+/* edac_dev file operations for an 'ctl_info' */
+static struct sysfs_ops device_ctl_info_ops = {
+ .show = edac_dev_ctl_info_show,
+ .store = edac_dev_ctl_info_store
+};
+
+#define CTL_INFO_ATTR(_name,_mode,_show,_store) \
+static struct ctl_info_attribute attr_ctl_info_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* Declare the various ctl_info attributes here and their respective ops */
+CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR,
+ edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store);
+CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR,
+ edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store);
+CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR,
+ edac_device_ctl_panic_on_ue_show,
+ edac_device_ctl_panic_on_ue_store);
+CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR,
+ edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store);
+
+/* Base Attributes of the EDAC_DEVICE ECC object */
+static struct ctl_info_attribute *device_ctrl_attr[] = {
+ &attr_ctl_info_panic_on_ue,
+ &attr_ctl_info_log_ue,
+ &attr_ctl_info_log_ce,
+ &attr_ctl_info_poll_msec,
+ NULL,
+};
+
+/*
+ * edac_device_ctrl_master_release
+ *
+ * called when the reference count for the 'main' kobj
+ * for a edac_device control struct reaches zero
+ *
+ * Reference count model:
+ * One 'main' kobject for each control structure allocated.
+ * That main kobj is initially set to one AND
+ * the reference count for the EDAC 'core' module is
+ * bumped by one, thus added 'keep in memory' dependency.
+ *
+ * Each new internal kobj (in instances and blocks) then
+ * bumps the 'main' kobject.
+ *
+ * When they are released their release functions decrement
+ * the 'main' kobj.
+ *
+ * When the main kobj reaches zero (0) then THIS function
+ * is called which then decrements the EDAC 'core' module.
+ * When the module reference count reaches zero then the
+ * module no longer has dependency on keeping the release
+ * function code in memory and module can be unloaded.
+ *
+ * This will support several control objects as well, each
+ * with its own 'main' kobj.
+ */
+static void edac_device_ctrl_master_release(struct kobject *kobj)
+{
+ struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
+
+ debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx);
+
+ /* decrement the EDAC CORE module ref count */
+ module_put(edac_dev->owner);
+
+ /* free the control struct containing the 'main' kobj
+ * passed in to this routine
+ */
+ kfree(edac_dev);
+}
+
+/* ktype for the main (master) kobject */
+static struct kobj_type ktype_device_ctrl = {
+ .release = edac_device_ctrl_master_release,
+ .sysfs_ops = &device_ctl_info_ops,
+ .default_attrs = (struct attribute **)device_ctrl_attr,
+};
+
+/*
+ * edac_device_register_sysfs_main_kobj
+ *
+ * perform the high level setup for the new edac_device instance
+ *
+ * Return: 0 SUCCESS
+ * !0 FAILURE
+ */
+int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
+{
+ struct sysdev_class *edac_class;
+ int err;
+
+ debugf1("%s()\n", __func__);
+
+ /* get the /sys/devices/system/edac reference */
+ edac_class = edac_get_edac_class();
+ if (edac_class == NULL) {
+ debugf1("%s() no edac_class error\n", __func__);
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Point to the 'edac_class' this instance 'reports' to */
+ edac_dev->edac_class = edac_class;
+
+ /* Init the devices's kobject */
+ memset(&edac_dev->kobj, 0, sizeof(struct kobject));
+ edac_dev->kobj.ktype = &ktype_device_ctrl;
+
+ /* set this new device under the edac_class kobject */
+ edac_dev->kobj.parent = &edac_class->kset.kobj;
+
+ /* generate sysfs "..../edac/<name>" */
+ debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
+ err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
+ if (err)
+ goto err_out;
+
+ /* Record which module 'owns' this control structure
+ * and bump the ref count of the module
+ */
+ edac_dev->owner = THIS_MODULE;
+
+ if (!try_module_get(edac_dev->owner)) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* register */
+ err = kobject_register(&edac_dev->kobj);
+ if (err) {
+ debugf1("%s()Failed to register '.../edac/%s'\n",
+ __func__, edac_dev->name);
+ goto err_kobj_reg;
+ }
+
+ /* At this point, to 'free' the control struct,
+ * edac_device_unregister_sysfs_main_kobj() must be used
+ */
+
+ debugf4("%s() Registered '.../edac/%s' kobject\n",
+ __func__, edac_dev->name);
+
+ return 0;
+
+ /* Error exit stack */
+err_kobj_reg:
+ module_put(edac_dev->owner);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_unregister_sysfs_main_kobj:
+ * the '..../edac/<name>' kobject
+ */
+void edac_device_unregister_sysfs_main_kobj(
+ struct edac_device_ctl_info *edac_dev)
+{
+ debugf0("%s()\n", __func__);
+ debugf4("%s() name of kobject is: %s\n",
+ __func__, kobject_name(&edac_dev->kobj));
+
+ /*
+ * Unregister the edac device's kobject and
+ * allow for reference count to reach 0 at which point
+ * the callback will be called to:
+ * a) module_put() this module
+ * b) 'kfree' the memory
+ */
+ kobject_unregister(&edac_dev->kobj);
+}
+
+/* edac_dev -> instance information */
+
+/*
+ * Set of low-level instance attribute show functions
+ */
+static ssize_t instance_ue_count_show(struct edac_device_instance *instance,
+ char *data)
+{
+ return sprintf(data, "%u\n", instance->counters.ue_count);
+}
+
+static ssize_t instance_ce_count_show(struct edac_device_instance *instance,
+ char *data)
+{
+ return sprintf(data, "%u\n", instance->counters.ce_count);
+}
+
+#define to_instance(k) container_of(k, struct edac_device_instance, kobj)
+#define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_device_ctrl_instance_release(struct kobject *kobj)
+{
+ struct edac_device_instance *instance;
+
+ debugf1("%s()\n", __func__);
+
+ /* map from this kobj to the main control struct
+ * and then dec the main kobj count
+ */
+ instance = to_instance(kobj);
+ kobject_put(&instance->ctl->kobj);
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct edac_device_instance *, char *);
+ ssize_t(*store) (struct edac_device_instance *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_device_instance *instance = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->show)
+ return instance_attr->show(instance, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_device_instance *instance = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->store)
+ return instance_attr->store(instance, buffer, count);
+ return -EIO;
+}
+
+/* edac_dev file operations for an 'instance' */
+static struct sysfs_ops device_instance_ops = {
+ .show = edac_dev_instance_show,
+ .store = edac_dev_instance_store
+};
+
+#define INSTANCE_ATTR(_name,_mode,_show,_store) \
+static struct instance_attribute attr_instance_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/*
+ * Define attributes visible for the edac_device instance object
+ * Each contains a pointer to a show and an optional set
+ * function pointer that does the low level output/input
+ */
+INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL);
+INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL);
+
+/* list of edac_dev 'instance' attributes */
+static struct instance_attribute *device_instance_attr[] = {
+ &attr_instance_ce_count,
+ &attr_instance_ue_count,
+ NULL,
+};
+
+/* The 'ktype' for each edac_dev 'instance' */
+static struct kobj_type ktype_instance_ctrl = {
+ .release = edac_device_ctrl_instance_release,
+ .sysfs_ops = &device_instance_ops,
+ .default_attrs = (struct attribute **)device_instance_attr,
+};
+
+/* edac_dev -> instance -> block information */
+
+#define to_block(k) container_of(k, struct edac_device_block, kobj)
+#define to_block_attr(a) \
+ container_of(a, struct edac_dev_sysfs_block_attribute, attr)
+
+/*
+ * Set of low-level block attribute show functions
+ */
+static ssize_t block_ue_count_show(struct kobject *kobj,
+ struct attribute *attr, char *data)
+{
+ struct edac_device_block *block = to_block(kobj);
+
+ return sprintf(data, "%u\n", block->counters.ue_count);
+}
+
+static ssize_t block_ce_count_show(struct kobject *kobj,
+ struct attribute *attr, char *data)
+{
+ struct edac_device_block *block = to_block(kobj);
+
+ return sprintf(data, "%u\n", block->counters.ce_count);
+}
+
+/* DEVICE block kobject release() function */
+static void edac_device_ctrl_block_release(struct kobject *kobj)
+{
+ struct edac_device_block *block;
+
+ debugf1("%s()\n", __func__);
+
+ /* get the container of the kobj */
+ block = to_block(kobj);
+
+ /* map from 'block kobj' to 'block->instance->controller->main_kobj'
+ * now 'release' the block kobject
+ */
+ kobject_put(&block->instance->ctl->kobj);
+}
+
+
+/* Function to 'show' fields from the edac_dev 'block' structure */
+static ssize_t edac_dev_block_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_dev_sysfs_block_attribute *block_attr =
+ to_block_attr(attr);
+
+ if (block_attr->show)
+ return block_attr->show(kobj, attr, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'block' structure */
+static ssize_t edac_dev_block_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_dev_sysfs_block_attribute *block_attr;
+
+ block_attr = to_block_attr(attr);
+
+ if (block_attr->store)
+ return block_attr->store(kobj, attr, buffer, count);
+ return -EIO;
+}
+
+/* edac_dev file operations for a 'block' */
+static struct sysfs_ops device_block_ops = {
+ .show = edac_dev_block_show,
+ .store = edac_dev_block_store
+};
+
+#define BLOCK_ATTR(_name,_mode,_show,_store) \
+static struct edac_dev_sysfs_block_attribute attr_block_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+BLOCK_ATTR(ce_count, S_IRUGO, block_ce_count_show, NULL);
+BLOCK_ATTR(ue_count, S_IRUGO, block_ue_count_show, NULL);
+
+/* list of edac_dev 'block' attributes */
+static struct edac_dev_sysfs_block_attribute *device_block_attr[] = {
+ &attr_block_ce_count,
+ &attr_block_ue_count,
+ NULL,
+};
+
+/* The 'ktype' for each edac_dev 'block' */
+static struct kobj_type ktype_block_ctrl = {
+ .release = edac_device_ctrl_block_release,
+ .sysfs_ops = &device_block_ops,
+ .default_attrs = (struct attribute **)device_block_attr,
+};
+
+/* block ctor/dtor code */
+
+/*
+ * edac_device_create_block
+ */
+static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+ struct edac_device_instance *instance,
+ struct edac_device_block *block)
+{
+ int i;
+ int err;
+ struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+ struct kobject *main_kobj;
+
+ debugf4("%s() Instance '%s' inst_p=%p block '%s' block_p=%p\n",
+ __func__, instance->name, instance, block->name, block);
+ debugf4("%s() block kobj=%p block kobj->parent=%p\n",
+ __func__, &block->kobj, &block->kobj.parent);
+
+ /* init this block's kobject */
+ memset(&block->kobj, 0, sizeof(struct kobject));
+ block->kobj.parent = &instance->kobj;
+ block->kobj.ktype = &ktype_block_ctrl;
+
+ err = kobject_set_name(&block->kobj, "%s", block->name);
+ if (err)
+ return err;
+
+ /* bump the main kobject's reference count for this controller
+ * and this instance is dependant on the main
+ */
+ main_kobj = kobject_get(&edac_dev->kobj);
+ if (!main_kobj) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Add this block's kobject */
+ err = kobject_register(&block->kobj);
+ if (err) {
+ debugf1("%s() Failed to register instance '%s'\n",
+ __func__, block->name);
+ kobject_put(main_kobj);
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* If there are driver level block attributes, then added them
+ * to the block kobject
+ */
+ sysfs_attrib = block->block_attributes;
+ if (sysfs_attrib && block->nr_attribs) {
+ for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+ debugf4("%s() creating block attrib='%s' "
+ "attrib->%p to kobj=%p\n",
+ __func__,
+ sysfs_attrib->attr.name,
+ sysfs_attrib, &block->kobj);
+
+ /* Create each block_attribute file */
+ err = sysfs_create_file(&block->kobj,
+ &sysfs_attrib->attr);
+ if (err)
+ goto err_on_attrib;
+ }
+ }
+
+ return 0;
+
+ /* Error unwind stack */
+err_on_attrib:
+ kobject_unregister(&block->kobj);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_delete_block(edac_dev,block);
+ */
+static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
+ struct edac_device_block *block)
+{
+ struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+ int i;
+
+ /* if this block has 'attributes' then we need to iterate over the list
+ * and 'remove' the attributes on this block
+ */
+ sysfs_attrib = block->block_attributes;
+ if (sysfs_attrib && block->nr_attribs) {
+ for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+ /* remove each block_attrib file */
+ sysfs_remove_file(&block->kobj,
+ (struct attribute *) sysfs_attrib);
+ }
+ }
+
+ /* unregister this block's kobject, SEE:
+ * edac_device_ctrl_block_release() callback operation
+ */
+ kobject_unregister(&block->kobj);
+}
+
+/* instance ctor/dtor code */
+
+/*
+ * edac_device_create_instance
+ * create just one instance of an edac_device 'instance'
+ */
+static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+ int idx)
+{
+ int i, j;
+ int err;
+ struct edac_device_instance *instance;
+ struct kobject *main_kobj;
+
+ instance = &edac_dev->instances[idx];
+
+ /* Init the instance's kobject */
+ memset(&instance->kobj, 0, sizeof(struct kobject));
+
+ /* set this new device under the edac_device main kobject */
+ instance->kobj.parent = &edac_dev->kobj;
+ instance->kobj.ktype = &ktype_instance_ctrl;
+ instance->ctl = edac_dev;
+
+ err = kobject_set_name(&instance->kobj, "%s", instance->name);
+ if (err)
+ goto err_out;
+
+ /* bump the main kobject's reference count for this controller
+ * and this instance is dependant on the main
+ */
+ main_kobj = kobject_get(&edac_dev->kobj);
+ if (!main_kobj) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Formally register this instance's kobject */
+ err = kobject_register(&instance->kobj);
+ if (err != 0) {
+ debugf2("%s() Failed to register instance '%s'\n",
+ __func__, instance->name);
+ kobject_put(main_kobj);
+ goto err_out;
+ }
+
+ debugf4("%s() now register '%d' blocks for instance %d\n",
+ __func__, instance->nr_blocks, idx);
+
+ /* register all blocks of this instance */
+ for (i = 0; i < instance->nr_blocks; i++) {
+ err = edac_device_create_block(edac_dev, instance,
+ &instance->blocks[i]);
+ if (err) {
+ /* If any fail, remove all previous ones */
+ for (j = 0; j < i; j++)
+ edac_device_delete_block(edac_dev,
+ &instance->blocks[j]);
+ goto err_release_instance_kobj;
+ }
+ }
+
+ debugf4("%s() Registered instance %d '%s' kobject\n",
+ __func__, idx, instance->name);
+
+ return 0;
+
+ /* error unwind stack */
+err_release_instance_kobj:
+ kobject_unregister(&instance->kobj);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_remove_instance
+ * remove an edac_device instance
+ */
+static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
+ int idx)
+{
+ struct edac_device_instance *instance;
+ int i;
+
+ instance = &edac_dev->instances[idx];
+
+ /* unregister all blocks in this instance */
+ for (i = 0; i < instance->nr_blocks; i++)
+ edac_device_delete_block(edac_dev, &instance->blocks[i]);
+
+ /* unregister this instance's kobject, SEE:
+ * edac_device_ctrl_instance_release() for callback operation
+ */
+ kobject_unregister(&instance->kobj);
+}
+
+/*
+ * edac_device_create_instances
+ * create the first level of 'instances' for this device
+ * (ie 'cache' might have 'cache0', 'cache1', 'cache2', etc
+ */
+static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
+{
+ int i, j;
+ int err;
+
+ debugf0("%s()\n", __func__);
+
+ /* iterate over creation of the instances */
+ for (i = 0; i < edac_dev->nr_instances; i++) {
+ err = edac_device_create_instance(edac_dev, i);
+ if (err) {
+ /* unwind previous instances on error */
+ for (j = 0; j < i; j++)
+ edac_device_delete_instance(edac_dev, j);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * edac_device_delete_instances(edac_dev);
+ * unregister all the kobjects of the instances
+ */
+static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev)
+{
+ int i;
+
+ /* iterate over creation of the instances */
+ for (i = 0; i < edac_dev->nr_instances; i++)
+ edac_device_delete_instance(edac_dev, i);
+}
+
+/* edac_dev sysfs ctor/dtor code */
+
+/*
+ * edac_device_add_main_sysfs_attributes
+ * add some attributes to this instance's main kobject
+ */
+static int edac_device_add_main_sysfs_attributes(
+ struct edac_device_ctl_info *edac_dev)
+{
+ struct edac_dev_sysfs_attribute *sysfs_attrib;
+ int err = 0;
+
+ sysfs_attrib = edac_dev->sysfs_attributes;
+ if (sysfs_attrib) {
+ /* iterate over the array and create an attribute for each
+ * entry in the list
+ */
+ while (sysfs_attrib->attr.name != NULL) {
+ err = sysfs_create_file(&edac_dev->kobj,
+ (struct attribute*) sysfs_attrib);
+ if (err)
+ goto err_out;
+
+ sysfs_attrib++;
+ }
+ }
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_remove_main_sysfs_attributes
+ * remove any attributes to this instance's main kobject
+ */
+static void edac_device_remove_main_sysfs_attributes(
+ struct edac_device_ctl_info *edac_dev)
+{
+ struct edac_dev_sysfs_attribute *sysfs_attrib;
+
+ /* if there are main attributes, defined, remove them. First,
+ * point to the start of the array and iterate over it
+ * removing each attribute listed from this device's instance's kobject
+ */
+ sysfs_attrib = edac_dev->sysfs_attributes;
+ if (sysfs_attrib) {
+ while (sysfs_attrib->attr.name != NULL) {
+ sysfs_remove_file(&edac_dev->kobj,
+ (struct attribute *) sysfs_attrib);
+ sysfs_attrib++;
+ }
+ }
+}
+
+/*
+ * edac_device_create_sysfs() Constructor
+ *
+ * accept a created edac_device control structure
+ * and 'export' it to sysfs. The 'main' kobj should already have been
+ * created. 'instance' and 'block' kobjects should be registered
+ * along with any 'block' attributes from the low driver. In addition,
+ * the main attributes (if any) are connected to the main kobject of
+ * the control structure.
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+ int err;
+ struct kobject *edac_kobj = &edac_dev->kobj;
+
+ debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
+
+ /* go create any main attributes callers wants */
+ err = edac_device_add_main_sysfs_attributes(edac_dev);
+ if (err) {
+ debugf0("%s() failed to add sysfs attribs\n", __func__);
+ goto err_out;
+ }
+
+ /* create a symlink from the edac device
+ * to the platform 'device' being used for this
+ */
+ err = sysfs_create_link(edac_kobj,
+ &edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
+ if (err) {
+ debugf0("%s() sysfs_create_link() returned err= %d\n",
+ __func__, err);
+ goto err_remove_main_attribs;
+ }
+
+ /* Create the first level instance directories
+ * In turn, the nested blocks beneath the instances will
+ * be registered as well
+ */
+ err = edac_device_create_instances(edac_dev);
+ if (err) {
+ debugf0("%s() edac_device_create_instances() "
+ "returned err= %d\n", __func__, err);
+ goto err_remove_link;
+ }
+
+
+ debugf4("%s() create-instances done, idx=%d\n",
+ __func__, edac_dev->dev_idx);
+
+ return 0;
+
+ /* Error unwind stack */
+err_remove_link:
+ /* remove the sym link */
+ sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+err_remove_main_attribs:
+ edac_device_remove_main_sysfs_attributes(edac_dev);
+
+err_out:
+ return err;
+}
+
+/*
+ * edac_device_remove_sysfs() destructor
+ *
+ * given an edac_device struct, tear down the kobject resources
+ */
+void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+ debugf0("%s()\n", __func__);
+
+ /* remove any main attributes for this device */
+ edac_device_remove_main_sysfs_attributes(edac_dev);
+
+ /* remove the device sym link */
+ sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+ /* walk the instance/block kobject tree, deconstructing it */
+ edac_device_delete_instances(edac_dev);
+}
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 7b622300d0e5..4471be362599 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -27,1200 +27,20 @@
#include <linux/list.h>
#include <linux/sysdev.h>
#include <linux/ctype.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
+#include <linux/edac.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/edac.h>
-#include "edac_mc.h"
-
-#define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__
-
-
-#ifdef CONFIG_EDAC_DEBUG
-/* Values of 0 to 4 will generate output */
-int edac_debug_level = 1;
-EXPORT_SYMBOL_GPL(edac_debug_level);
-#endif
-
-/* EDAC Controls, setable by module parameter, and sysfs */
-static int log_ue = 1;
-static int log_ce = 1;
-static int panic_on_ue;
-static int poll_msec = 1000;
+#include "edac_core.h"
+#include "edac_module.h"
/* lock to memory controller's control array */
-static DECLARE_MUTEX(mem_ctls_mutex);
+static DEFINE_MUTEX(mem_ctls_mutex);
static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
-static struct task_struct *edac_thread;
-
-#ifdef CONFIG_PCI
-static int check_pci_parity = 0; /* default YES check PCI parity */
-static int panic_on_pci_parity; /* default no panic on PCI Parity */
-static atomic_t pci_parity_count = ATOMIC_INIT(0);
-
-static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
-static struct completion edac_pci_kobj_complete;
-#endif /* CONFIG_PCI */
-
-/* START sysfs data and methods */
-
-
-static const char *mem_types[] = {
- [MEM_EMPTY] = "Empty",
- [MEM_RESERVED] = "Reserved",
- [MEM_UNKNOWN] = "Unknown",
- [MEM_FPM] = "FPM",
- [MEM_EDO] = "EDO",
- [MEM_BEDO] = "BEDO",
- [MEM_SDR] = "Unbuffered-SDR",
- [MEM_RDR] = "Registered-SDR",
- [MEM_DDR] = "Unbuffered-DDR",
- [MEM_RDDR] = "Registered-DDR",
- [MEM_RMBS] = "RMBS"
-};
-
-static const char *dev_types[] = {
- [DEV_UNKNOWN] = "Unknown",
- [DEV_X1] = "x1",
- [DEV_X2] = "x2",
- [DEV_X4] = "x4",
- [DEV_X8] = "x8",
- [DEV_X16] = "x16",
- [DEV_X32] = "x32",
- [DEV_X64] = "x64"
-};
-
-static const char *edac_caps[] = {
- [EDAC_UNKNOWN] = "Unknown",
- [EDAC_NONE] = "None",
- [EDAC_RESERVED] = "Reserved",
- [EDAC_PARITY] = "PARITY",
- [EDAC_EC] = "EC",
- [EDAC_SECDED] = "SECDED",
- [EDAC_S2ECD2ED] = "S2ECD2ED",
- [EDAC_S4ECD4ED] = "S4ECD4ED",
- [EDAC_S8ECD8ED] = "S8ECD8ED",
- [EDAC_S16ECD16ED] = "S16ECD16ED"
-};
-
-/* sysfs object: /sys/devices/system/edac */
-static struct sysdev_class edac_class = {
- set_kset_name("edac"),
-};
-
-/* sysfs object:
- * /sys/devices/system/edac/mc
- */
-static struct kobject edac_memctrl_kobj;
-
-/* We use these to wait for the reference counts on edac_memctrl_kobj and
- * edac_pci_kobj to reach 0.
- */
-static struct completion edac_memctrl_kobj_complete;
-
-/*
- * /sys/devices/system/edac/mc;
- * data structures and methods
- */
-static ssize_t memctrl_int_show(void *ptr, char *buffer)
-{
- int *value = (int*) ptr;
- return sprintf(buffer, "%u\n", *value);
-}
-
-static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
-{
- int *value = (int*) ptr;
-
- if (isdigit(*buffer))
- *value = simple_strtoul(buffer, NULL, 0);
-
- return count;
-}
-
-struct memctrl_dev_attribute {
- struct attribute attr;
- void *value;
- ssize_t (*show)(void *,char *);
- ssize_t (*store)(void *, const char *, size_t);
-};
-
-/* Set of show/store abstract level functions for memory control object */
-static ssize_t memctrl_dev_show(struct kobject *kobj,
- struct attribute *attr, char *buffer)
-{
- struct memctrl_dev_attribute *memctrl_dev;
- memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
- if (memctrl_dev->show)
- return memctrl_dev->show(memctrl_dev->value, buffer);
-
- return -EIO;
-}
-
-static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer, size_t count)
-{
- struct memctrl_dev_attribute *memctrl_dev;
- memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
- if (memctrl_dev->store)
- return memctrl_dev->store(memctrl_dev->value, buffer, count);
-
- return -EIO;
-}
-
-static struct sysfs_ops memctrlfs_ops = {
- .show = memctrl_dev_show,
- .store = memctrl_dev_store
-};
-
-#define MEMCTRL_ATTR(_name,_mode,_show,_store) \
-struct memctrl_dev_attribute attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = &_name, \
- .show = _show, \
- .store = _store, \
-};
-
-#define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store) \
-struct memctrl_dev_attribute attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = _data, \
- .show = _show, \
- .store = _store, \
-};
-
-/* csrow<id> control files */
-MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-
-/* Base Attributes of the memory ECC object */
-static struct memctrl_dev_attribute *memctrl_attr[] = {
- &attr_panic_on_ue,
- &attr_log_ue,
- &attr_log_ce,
- &attr_poll_msec,
- NULL,
-};
-
-/* Main MC kobject release() function */
-static void edac_memctrl_master_release(struct kobject *kobj)
-{
- debugf1("%s()\n", __func__);
- complete(&edac_memctrl_kobj_complete);
-}
-
-static struct kobj_type ktype_memctrl = {
- .release = edac_memctrl_master_release,
- .sysfs_ops = &memctrlfs_ops,
- .default_attrs = (struct attribute **) memctrl_attr,
-};
-
-/* Initialize the main sysfs entries for edac:
- * /sys/devices/system/edac
- *
- * and children
- *
- * Return: 0 SUCCESS
- * !0 FAILURE
- */
-static int edac_sysfs_memctrl_setup(void)
-{
- int err = 0;
-
- debugf1("%s()\n", __func__);
-
- /* create the /sys/devices/system/edac directory */
- err = sysdev_class_register(&edac_class);
-
- if (err) {
- debugf1("%s() error=%d\n", __func__, err);
- return err;
- }
-
- /* Init the MC's kobject */
- memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
- edac_memctrl_kobj.parent = &edac_class.kset.kobj;
- edac_memctrl_kobj.ktype = &ktype_memctrl;
-
- /* generate sysfs "..../edac/mc" */
- err = kobject_set_name(&edac_memctrl_kobj,"mc");
-
- if (err)
- goto fail;
-
- /* FIXME: maybe new sysdev_create_subdir() */
- err = kobject_register(&edac_memctrl_kobj);
-
- if (err) {
- debugf1("Failed to register '.../edac/mc'\n");
- goto fail;
- }
-
- debugf1("Registered '.../edac/mc' kobject\n");
-
- return 0;
-
-fail:
- sysdev_class_unregister(&edac_class);
- return err;
-}
-
-/*
- * MC teardown:
- * the '..../edac/mc' kobject followed by '..../edac' itself
- */
-static void edac_sysfs_memctrl_teardown(void)
-{
- debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
- /* Unregister the MC's kobject and wait for reference count to reach
- * 0.
- */
- init_completion(&edac_memctrl_kobj_complete);
- kobject_unregister(&edac_memctrl_kobj);
- wait_for_completion(&edac_memctrl_kobj_complete);
-
- /* Unregister the 'edac' object */
- sysdev_class_unregister(&edac_class);
-}
-
-#ifdef CONFIG_PCI
-static ssize_t edac_pci_int_show(void *ptr, char *buffer)
-{
- int *value = ptr;
- return sprintf(buffer,"%d\n",*value);
-}
-
-static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
-{
- int *value = ptr;
-
- if (isdigit(*buffer))
- *value = simple_strtoul(buffer,NULL,0);
-
- return count;
-}
-
-struct edac_pci_dev_attribute {
- struct attribute attr;
- void *value;
- ssize_t (*show)(void *,char *);
- ssize_t (*store)(void *, const char *,size_t);
-};
-
-/* Set of show/store abstract level functions for PCI Parity object */
-static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
- char *buffer)
-{
- struct edac_pci_dev_attribute *edac_pci_dev;
- edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
- if (edac_pci_dev->show)
- return edac_pci_dev->show(edac_pci_dev->value, buffer);
- return -EIO;
-}
-
-static ssize_t edac_pci_dev_store(struct kobject *kobj,
- struct attribute *attr, const char *buffer, size_t count)
-{
- struct edac_pci_dev_attribute *edac_pci_dev;
- edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
- if (edac_pci_dev->show)
- return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
- return -EIO;
-}
-
-static struct sysfs_ops edac_pci_sysfs_ops = {
- .show = edac_pci_dev_show,
- .store = edac_pci_dev_store
-};
-
-#define EDAC_PCI_ATTR(_name,_mode,_show,_store) \
-struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = &_name, \
- .show = _show, \
- .store = _store, \
-};
-
-#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \
-struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .value = _data, \
- .show = _show, \
- .store = _store, \
-};
-
-/* PCI Parity control files */
-EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
- edac_pci_int_store);
-EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
- edac_pci_int_store);
-EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
-
-/* Base Attributes of the memory ECC object */
-static struct edac_pci_dev_attribute *edac_pci_attr[] = {
- &edac_pci_attr_check_pci_parity,
- &edac_pci_attr_panic_on_pci_parity,
- &edac_pci_attr_pci_parity_count,
- NULL,
-};
-
-/* No memory to release */
-static void edac_pci_release(struct kobject *kobj)
-{
- debugf1("%s()\n", __func__);
- complete(&edac_pci_kobj_complete);
-}
-
-static struct kobj_type ktype_edac_pci = {
- .release = edac_pci_release,
- .sysfs_ops = &edac_pci_sysfs_ops,
- .default_attrs = (struct attribute **) edac_pci_attr,
-};
-
-/**
- * edac_sysfs_pci_setup()
- *
- */
-static int edac_sysfs_pci_setup(void)
-{
- int err;
-
- debugf1("%s()\n", __func__);
-
- memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj));
- edac_pci_kobj.parent = &edac_class.kset.kobj;
- edac_pci_kobj.ktype = &ktype_edac_pci;
- err = kobject_set_name(&edac_pci_kobj, "pci");
-
- if (!err) {
- /* Instanstiate the csrow object */
- /* FIXME: maybe new sysdev_create_subdir() */
- err = kobject_register(&edac_pci_kobj);
-
- if (err)
- debugf1("Failed to register '.../edac/pci'\n");
- else
- debugf1("Registered '.../edac/pci' kobject\n");
- }
-
- return err;
-}
-
-static void edac_sysfs_pci_teardown(void)
-{
- debugf0("%s()\n", __func__);
- init_completion(&edac_pci_kobj_complete);
- kobject_unregister(&edac_pci_kobj);
- wait_for_completion(&edac_pci_kobj_complete);
-}
-
-
-static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
-{
- int where;
- u16 status;
-
- where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
- pci_read_config_word(dev, where, &status);
-
- /* If we get back 0xFFFF then we must suspect that the card has been
- * pulled but the Linux PCI layer has not yet finished cleaning up.
- * We don't want to report on such devices
- */
-
- if (status == 0xFFFF) {
- u32 sanity;
-
- pci_read_config_dword(dev, 0, &sanity);
-
- if (sanity == 0xFFFFFFFF)
- return 0;
- }
-
- status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
- PCI_STATUS_PARITY;
-
- if (status)
- /* reset only the bits we are interested in */
- pci_write_config_word(dev, where, status);
-
- return status;
-}
-
-typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
-
-/* Clear any PCI parity errors logged by this device. */
-static void edac_pci_dev_parity_clear(struct pci_dev *dev)
-{
- u8 header_type;
-
- get_pci_parity_status(dev, 0);
-
- /* read the device TYPE, looking for bridges */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
- get_pci_parity_status(dev, 1);
-}
-
-/*
- * PCI Parity polling
- *
- */
-static void edac_pci_dev_parity_test(struct pci_dev *dev)
-{
- u16 status;
- u8 header_type;
-
- /* read the STATUS register on this device
- */
- status = get_pci_parity_status(dev, 0);
-
- debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id );
-
- /* check the status reg for errors */
- if (status) {
- if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Signaled System Error on %s\n",
- pci_name(dev));
-
- if (status & (PCI_STATUS_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Master Data Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
-
- if (status & (PCI_STATUS_DETECTED_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Detected Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
- }
-
- /* read the device TYPE, looking for bridges */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
- debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id );
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
- /* On bridges, need to examine secondary status register */
- status = get_pci_parity_status(dev, 1);
-
- debugf2("PCI SEC_STATUS= 0x%04x %s\n",
- status, dev->dev.bus_id );
-
- /* check the secondary status reg for errors */
- if (status) {
- if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Signaled System Error on %s\n",
- pci_name(dev));
-
- if (status & (PCI_STATUS_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Master Data Parity Error on "
- "%s\n", pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
-
- if (status & (PCI_STATUS_DETECTED_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Detected Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
- }
- }
-}
-
-/*
- * pci_dev parity list iterator
- * Scan the PCI device list for one iteration, looking for SERRORs
- * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
- */
-static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
-{
- struct pci_dev *dev = NULL;
-
- /* request for kernel access to the next PCI device, if any,
- * and while we are looking at it have its reference count
- * bumped until we are done with it
- */
- while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
- fn(dev);
- }
-}
-
-static void do_pci_parity_check(void)
-{
- unsigned long flags;
- int before_count;
-
- debugf3("%s()\n", __func__);
-
- if (!check_pci_parity)
- return;
-
- before_count = atomic_read(&pci_parity_count);
-
- /* scan all PCI devices looking for a Parity Error on devices and
- * bridges
- */
- local_irq_save(flags);
- edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
- local_irq_restore(flags);
-
- /* Only if operator has selected panic on PCI Error */
- if (panic_on_pci_parity) {
- /* If the count is different 'after' from 'before' */
- if (before_count != atomic_read(&pci_parity_count))
- panic("EDAC: PCI Parity Error");
- }
-}
-
-static inline void clear_pci_parity_errors(void)
-{
- /* Clear any PCI bus parity errors that devices initially have logged
- * in their registers.
- */
- edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
-}
-
-#else /* CONFIG_PCI */
-
-/* pre-process these away */
-#define do_pci_parity_check()
-#define clear_pci_parity_errors()
-#define edac_sysfs_pci_teardown()
-#define edac_sysfs_pci_setup() (0)
-
-#endif /* CONFIG_PCI */
-
-/* EDAC sysfs CSROW data structures and methods
- */
-
-/* Set of more default csrow<id> attribute show/store functions */
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%u\n", csrow->ue_count);
-}
-
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%u\n", csrow->ce_count);
-}
-
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
-}
-
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%s\n", mem_types[csrow->mtype]);
-}
-
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%s\n", dev_types[csrow->dtype]);
-}
-
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private)
-{
- return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
-}
-
-/* show/store functions for DIMM Label attributes */
-static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
- char *data, int channel)
-{
- return snprintf(data, EDAC_MC_LABEL_LEN,"%s",
- csrow->channels[channel].label);
-}
-
-static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
- const char *data,
- size_t count,
- int channel)
-{
- ssize_t max_size = 0;
-
- max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1);
- strncpy(csrow->channels[channel].label, data, max_size);
- csrow->channels[channel].label[max_size] = '\0';
-
- return max_size;
-}
-
-/* show function for dynamic chX_ce_count attribute */
-static ssize_t channel_ce_count_show(struct csrow_info *csrow,
- char *data,
- int channel)
-{
- return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
-}
-
-/* csrow specific attribute structure */
-struct csrowdev_attribute {
- struct attribute attr;
- ssize_t (*show)(struct csrow_info *,char *,int);
- ssize_t (*store)(struct csrow_info *, const char *,size_t,int);
- int private;
-};
-
-#define to_csrow(k) container_of(k, struct csrow_info, kobj)
-#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
-
-/* Set of show/store higher level functions for default csrow attributes */
-static ssize_t csrowdev_show(struct kobject *kobj,
- struct attribute *attr,
- char *buffer)
-{
- struct csrow_info *csrow = to_csrow(kobj);
- struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
-
- if (csrowdev_attr->show)
- return csrowdev_attr->show(csrow,
- buffer,
- csrowdev_attr->private);
- return -EIO;
-}
-
-static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer, size_t count)
-{
- struct csrow_info *csrow = to_csrow(kobj);
- struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
-
- if (csrowdev_attr->store)
- return csrowdev_attr->store(csrow,
- buffer,
- count,
- csrowdev_attr->private);
- return -EIO;
-}
-
-static struct sysfs_ops csrowfs_ops = {
- .show = csrowdev_show,
- .store = csrowdev_store
-};
-
-#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
-struct csrowdev_attribute attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
- .private = _private, \
-};
-
-/* default cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0);
-CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0);
-CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0);
-CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0);
-CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0);
-CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0);
-
-/* default attributes of the CSROW<id> object */
-static struct csrowdev_attribute *default_csrow_attr[] = {
- &attr_dev_type,
- &attr_mem_type,
- &attr_edac_mode,
- &attr_size_mb,
- &attr_ue_count,
- &attr_ce_count,
- NULL,
-};
-
-
-/* possible dynamic channel DIMM Label attribute files */
-CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 0 );
-CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 1 );
-CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 2 );
-CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 3 );
-CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 4 );
-CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR,
- channel_dimm_label_show,
- channel_dimm_label_store,
- 5 );
-
-/* Total possible dynamic DIMM Label attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
- &attr_ch0_dimm_label,
- &attr_ch1_dimm_label,
- &attr_ch2_dimm_label,
- &attr_ch3_dimm_label,
- &attr_ch4_dimm_label,
- &attr_ch5_dimm_label
-};
-
-/* possible dynamic channel ce_count attribute files */
-CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 0 );
-CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 1 );
-CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 2 );
-CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 3 );
-CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 4 );
-CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR,
- channel_ce_count_show,
- NULL,
- 5 );
-
-/* Total possible dynamic ce_count attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
- &attr_ch0_ce_count,
- &attr_ch1_ce_count,
- &attr_ch2_ce_count,
- &attr_ch3_ce_count,
- &attr_ch4_ce_count,
- &attr_ch5_ce_count
-};
-
-
-#define EDAC_NR_CHANNELS 6
-
-/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
-static int edac_create_channel_files(struct kobject *kobj, int chan)
-{
- int err=-ENODEV;
-
- if (chan >= EDAC_NR_CHANNELS)
- return err;
-
- /* create the DIMM label attribute file */
- err = sysfs_create_file(kobj,
- (struct attribute *) dynamic_csrow_dimm_attr[chan]);
-
- if (!err) {
- /* create the CE Count attribute file */
- err = sysfs_create_file(kobj,
- (struct attribute *) dynamic_csrow_ce_count_attr[chan]);
- } else {
- debugf1("%s() dimm labels and ce_count files created", __func__);
- }
-
- return err;
-}
-
-/* No memory to release for this kobj */
-static void edac_csrow_instance_release(struct kobject *kobj)
-{
- struct csrow_info *cs;
-
- cs = container_of(kobj, struct csrow_info, kobj);
- complete(&cs->kobj_complete);
-}
-
-/* the kobj_type instance for a CSROW */
-static struct kobj_type ktype_csrow = {
- .release = edac_csrow_instance_release,
- .sysfs_ops = &csrowfs_ops,
- .default_attrs = (struct attribute **) default_csrow_attr,
-};
-
-/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(
- struct kobject *edac_mci_kobj,
- struct csrow_info *csrow,
- int index)
-{
- int err = 0;
- int chan;
-
- memset(&csrow->kobj, 0, sizeof(csrow->kobj));
-
- /* generate ..../edac/mc/mc<id>/csrow<index> */
-
- csrow->kobj.parent = edac_mci_kobj;
- csrow->kobj.ktype = &ktype_csrow;
-
- /* name this instance of csrow<id> */
- err = kobject_set_name(&csrow->kobj,"csrow%d",index);
- if (err)
- goto error_exit;
-
- /* Instanstiate the csrow object */
- err = kobject_register(&csrow->kobj);
- if (!err) {
- /* Create the dyanmic attribute files on this csrow,
- * namely, the DIMM labels and the channel ce_count
- */
- for (chan = 0; chan < csrow->nr_channels; chan++) {
- err = edac_create_channel_files(&csrow->kobj,chan);
- if (err)
- break;
- }
- }
-
-error_exit:
- return err;
-}
-
-/* default sysfs methods and data structures for the main MCI kobject */
-
-static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
- const char *data, size_t count)
-{
- int row, chan;
-
- mci->ue_noinfo_count = 0;
- mci->ce_noinfo_count = 0;
- mci->ue_count = 0;
- mci->ce_count = 0;
-
- for (row = 0; row < mci->nr_csrows; row++) {
- struct csrow_info *ri = &mci->csrows[row];
-
- ri->ue_count = 0;
- ri->ce_count = 0;
-
- for (chan = 0; chan < ri->nr_channels; chan++)
- ri->channels[chan].ce_count = 0;
- }
-
- mci->start_time = jiffies;
- return count;
-}
-
-/* memory scrubbing */
-static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
- const char *data, size_t count)
-{
- u32 bandwidth = -1;
-
- if (mci->set_sdram_scrub_rate) {
-
- memctrl_int_store(&bandwidth, data, count);
-
- if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate set successfully, applied: %d\n",
- bandwidth);
- } else {
- /* FIXME: error codes maybe? */
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate set FAILED, could not apply: %d\n",
- bandwidth);
- }
- } else {
- /* FIXME: produce "not implemented" ERROR for user-side. */
- edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrubbing 'set'control is not implemented!\n");
- }
- return count;
-}
-
-static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
-{
- u32 bandwidth = -1;
-
- if (mci->get_sdram_scrub_rate) {
- if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate successfully, fetched: %d\n",
- bandwidth);
- } else {
- /* FIXME: error codes maybe? */
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate fetch FAILED, got: %d\n",
- bandwidth);
- }
- } else {
- /* FIXME: produce "not implemented" ERROR for user-side. */
- edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrubbing 'get' control is not implemented!\n");
- }
- return sprintf(data, "%d\n", bandwidth);
-}
-
-/* default attribute files for the MCI object */
-static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ue_count);
-}
-
-static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ce_count);
-}
-
-static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ce_noinfo_count);
-}
-
-static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%d\n", mci->ue_noinfo_count);
-}
-
-static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ);
-}
-
-static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%s\n", mci->ctl_name);
-}
-
-static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
-{
- int total_pages, csrow_idx;
-
- for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
- csrow_idx++) {
- struct csrow_info *csrow = &mci->csrows[csrow_idx];
-
- if (!csrow->nr_pages)
- continue;
-
- total_pages += csrow->nr_pages;
- }
-
- return sprintf(data,"%u\n", PAGES_TO_MiB(total_pages));
-}
-
-struct mcidev_attribute {
- struct attribute attr;
- ssize_t (*show)(struct mem_ctl_info *,char *);
- ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
-};
-
-#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
-#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
-
-/* MCI show/store functions for top most object */
-static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
- char *buffer)
-{
- struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
- struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
- if (mcidev_attr->show)
- return mcidev_attr->show(mem_ctl_info, buffer);
-
- return -EIO;
-}
-
-static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer, size_t count)
-{
- struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
- struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
- if (mcidev_attr->store)
- return mcidev_attr->store(mem_ctl_info, buffer, count);
-
- return -EIO;
-}
-
-static struct sysfs_ops mci_ops = {
- .show = mcidev_show,
- .store = mcidev_store
-};
-
-#define MCIDEV_ATTR(_name,_mode,_show,_store) \
-struct mcidev_attribute mci_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode }, \
- .show = _show, \
- .store = _store, \
-};
-
-/* default Control file */
-MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store);
-
-/* default Attribute files */
-MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL);
-MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL);
-MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL);
-MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL);
-MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
-MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
-MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
-
-/* memory scrubber attribute file */
-MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store);
-
-static struct mcidev_attribute *mci_attr[] = {
- &mci_attr_reset_counters,
- &mci_attr_mc_name,
- &mci_attr_size_mb,
- &mci_attr_seconds_since_reset,
- &mci_attr_ue_noinfo_count,
- &mci_attr_ce_noinfo_count,
- &mci_attr_ue_count,
- &mci_attr_ce_count,
- &mci_attr_sdram_scrub_rate,
- NULL
-};
-
-/*
- * Release of a MC controlling instance
- */
-static void edac_mci_instance_release(struct kobject *kobj)
-{
- struct mem_ctl_info *mci;
-
- mci = to_mci(kobj);
- debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
- complete(&mci->kobj_complete);
-}
-
-static struct kobj_type ktype_mci = {
- .release = edac_mci_instance_release,
- .sysfs_ops = &mci_ops,
- .default_attrs = (struct attribute **) mci_attr,
-};
-
-
-#define EDAC_DEVICE_SYMLINK "device"
-
-/*
- * Create a new Memory Controller kobject instance,
- * mc<id> under the 'mc' directory
- *
- * Return:
- * 0 Success
- * !0 Failure
- */
-static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
-{
- int i;
- int err;
- struct csrow_info *csrow;
- struct kobject *edac_mci_kobj=&mci->edac_mci_kobj;
-
- debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
- memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj));
-
- /* set the name of the mc<id> object */
- err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
- if (err)
- return err;
-
- /* link to our parent the '..../edac/mc' object */
- edac_mci_kobj->parent = &edac_memctrl_kobj;
- edac_mci_kobj->ktype = &ktype_mci;
-
- /* register the mc<id> kobject */
- err = kobject_register(edac_mci_kobj);
- if (err)
- return err;
-
- /* create a symlink for the device */
- err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj,
- EDAC_DEVICE_SYMLINK);
- if (err)
- goto fail0;
-
- /* Make directories for each CSROW object
- * under the mc<id> kobject
- */
- for (i = 0; i < mci->nr_csrows; i++) {
- csrow = &mci->csrows[i];
-
- /* Only expose populated CSROWs */
- if (csrow->nr_pages > 0) {
- err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
- if (err)
- goto fail1;
- }
- }
-
- return 0;
-
- /* CSROW error: backout what has already been registered, */
-fail1:
- for ( i--; i >= 0; i--) {
- if (csrow->nr_pages > 0) {
- init_completion(&csrow->kobj_complete);
- kobject_unregister(&mci->csrows[i].kobj);
- wait_for_completion(&csrow->kobj_complete);
- }
- }
-
-fail0:
- init_completion(&mci->kobj_complete);
- kobject_unregister(edac_mci_kobj);
- wait_for_completion(&mci->kobj_complete);
- return err;
-}
-
-/*
- * remove a Memory Controller instance
- */
-static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
-{
- int i;
-
- debugf0("%s()\n", __func__);
-
- /* remove all csrow kobjects */
- for (i = 0; i < mci->nr_csrows; i++) {
- if (mci->csrows[i].nr_pages > 0) {
- init_completion(&mci->csrows[i].kobj_complete);
- kobject_unregister(&mci->csrows[i].kobj);
- wait_for_completion(&mci->csrows[i].kobj_complete);
- }
- }
-
- sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
- init_completion(&mci->kobj_complete);
- kobject_unregister(&mci->edac_mci_kobj);
- wait_for_completion(&mci->kobj_complete);
-}
-
-/* END OF sysfs data and methods */
-
#ifdef CONFIG_EDAC_DEBUG
-void edac_mc_dump_channel(struct channel_info *chan)
+static void edac_mc_dump_channel(struct channel_info *chan)
{
debugf4("\tchannel = %p\n", chan);
debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
@@ -1228,25 +48,21 @@ void edac_mc_dump_channel(struct channel_info *chan)
debugf4("\tchannel->label = '%s'\n", chan->label);
debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
}
-EXPORT_SYMBOL_GPL(edac_mc_dump_channel);
-void edac_mc_dump_csrow(struct csrow_info *csrow)
+static void edac_mc_dump_csrow(struct csrow_info *csrow)
{
debugf4("\tcsrow = %p\n", csrow);
debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
- debugf4("\tcsrow->first_page = 0x%lx\n",
- csrow->first_page);
+ debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages);
- debugf4("\tcsrow->nr_channels = %d\n",
- csrow->nr_channels);
+ debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels);
debugf4("\tcsrow->channels = %p\n", csrow->channels);
debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
}
-EXPORT_SYMBOL_GPL(edac_mc_dump_csrow);
-void edac_mc_dump_mci(struct mem_ctl_info *mci)
+static void edac_mc_dump_mci(struct mem_ctl_info *mci)
{
debugf3("\tmci = %p\n", mci);
debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap);
@@ -1256,13 +72,11 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci)
debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
mci->nr_csrows, mci->csrows);
debugf3("\tdev = %p\n", mci->dev);
- debugf3("\tmod_name:ctl_name = %s:%s\n",
- mci->mod_name, mci->ctl_name);
+ debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
}
-EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
-#endif /* CONFIG_EDAC_DEBUG */
+#endif /* CONFIG_EDAC_DEBUG */
/* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'.
* Adjust 'ptr' so that its alignment is at least as stringent as what the
@@ -1271,7 +85,7 @@ EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
* If 'size' is a constant, the compiler will optimize this whole function
* down to either a no-op or the addition of a constant to the value of 'ptr'.
*/
-static inline char * align_ptr(void *ptr, unsigned size)
+void *edac_align_ptr(void *ptr, unsigned size)
{
unsigned align, r;
@@ -1288,14 +102,14 @@ static inline char * align_ptr(void *ptr, unsigned size)
else if (size > sizeof(char))
align = sizeof(short);
else
- return (char *) ptr;
+ return (char *)ptr;
r = size % align;
if (r == 0)
- return (char *) ptr;
+ return (char *)ptr;
- return (char *) (((unsigned long) ptr) + align - r);
+ return (void *)(((unsigned long)ptr) + align - r);
}
/**
@@ -1315,7 +129,7 @@ static inline char * align_ptr(void *ptr, unsigned size)
* struct mem_ctl_info pointer
*/
struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
- unsigned nr_chans)
+ unsigned nr_chans, int edac_index)
{
struct mem_ctl_info *mci;
struct csrow_info *csi, *csrow;
@@ -1323,30 +137,32 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
void *pvt;
unsigned size;
int row, chn;
+ int err;
/* Figure out the offsets of the various items from the start of an mc
* structure. We want the alignment of each item to be at least as
* stringent as what the compiler would provide if we could simply
* hardcode everything into a single struct.
*/
- mci = (struct mem_ctl_info *) 0;
- csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi));
- chi = (struct channel_info *)
- align_ptr(&csi[nr_csrows], sizeof(*chi));
- pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
- size = ((unsigned long) pvt) + sz_pvt;
-
- if ((mci = kmalloc(size, GFP_KERNEL)) == NULL)
+ mci = (struct mem_ctl_info *)0;
+ csi = edac_align_ptr(&mci[1], sizeof(*csi));
+ chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi));
+ pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
+ size = ((unsigned long)pvt) + sz_pvt;
+
+ mci = kzalloc(size, GFP_KERNEL);
+ if (mci == NULL)
return NULL;
/* Adjust pointers so they point within the memory we just allocated
* rather than an imaginary chunk of memory located at address 0.
*/
- csi = (struct csrow_info *) (((char *) mci) + ((unsigned long) csi));
- chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi));
- pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL;
+ csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
+ chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi));
+ pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
- memset(mci, 0, size); /* clear all fields */
+ /* setup index and various internal pointers */
+ mci->mc_idx = edac_index;
mci->csrows = csi;
mci->pvt_info = pvt;
mci->nr_csrows = nr_csrows;
@@ -1366,17 +182,35 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
}
}
+ mci->op_state = OP_ALLOC;
+
+ /*
+ * Initialize the 'root' kobj for the edac_mc controller
+ */
+ err = edac_mc_register_sysfs_main_kobj(mci);
+ if (err) {
+ kfree(mci);
+ return NULL;
+ }
+
+ /* at this point, the root kobj is valid, and in order to
+ * 'free' the object, then the function:
+ * edac_mc_unregister_sysfs_main_kobj() must be called
+ * which will perform kobj unregistration and the actual free
+ * will occur during the kobject callback operation
+ */
return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_alloc);
/**
- * edac_mc_free: Free a previously allocated 'mci' structure
+ * edac_mc_free
+ * 'Free' a previously allocated 'mci' structure
* @mci: pointer to a struct mem_ctl_info structure
*/
void edac_mc_free(struct mem_ctl_info *mci)
{
- kfree(mci);
+ edac_mc_unregister_sysfs_main_kobj(mci);
}
EXPORT_SYMBOL_GPL(edac_mc_free);
@@ -1397,18 +231,136 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
return NULL;
}
+/*
+ * handler for EDAC to check if NMI type handler has asserted interrupt
+ */
+static int edac_mc_assert_error_check_and_clear(void)
+{
+ int old_state;
+
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ return 1;
+
+ old_state = edac_err_assert;
+ edac_err_assert = 0;
+
+ return old_state;
+}
+
+/*
+ * edac_mc_workq_function
+ * performs the operation scheduled by a workq request
+ */
+static void edac_mc_workq_function(struct work_struct *work_req)
+{
+ struct delayed_work *d_work = (struct delayed_work *)work_req;
+ struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
+
+ mutex_lock(&mem_ctls_mutex);
+
+ /* if this control struct has movd to offline state, we are done */
+ if (mci->op_state == OP_OFFLINE) {
+ mutex_unlock(&mem_ctls_mutex);
+ return;
+ }
+
+ /* Only poll controllers that are running polled and have a check */
+ if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
+ mci->edac_check(mci);
+
+ /*
+ * FIXME: temp place holder for PCI checks,
+ * goes away when we break out PCI
+ */
+ edac_pci_do_parity_check();
+
+ mutex_unlock(&mem_ctls_mutex);
+
+ /* Reschedule */
+ queue_delayed_work(edac_workqueue, &mci->work,
+ msecs_to_jiffies(edac_mc_get_poll_msec()));
+}
+
+/*
+ * edac_mc_workq_setup
+ * initialize a workq item for this mci
+ * passing in the new delay period in msec
+ *
+ * locking model:
+ *
+ * called with the mem_ctls_mutex held
+ */
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
+{
+ debugf0("%s()\n", __func__);
+
+ /* if this instance is not in the POLL state, then simply return */
+ if (mci->op_state != OP_RUNNING_POLL)
+ return;
+
+ INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+ queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+}
+
+/*
+ * edac_mc_workq_teardown
+ * stop the workq processing on this mci
+ *
+ * locking model:
+ *
+ * called WITHOUT lock held
+ */
+static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
+{
+ int status;
+
+ /* if not running POLL, leave now */
+ if (mci->op_state == OP_RUNNING_POLL) {
+ status = cancel_delayed_work(&mci->work);
+ if (status == 0) {
+ debugf0("%s() not canceled, flush the queue\n",
+ __func__);
+
+ /* workq instance might be running, wait for it */
+ flush_workqueue(edac_workqueue);
+ }
+ }
+}
+
+/*
+ * edac_reset_delay_period
+ */
+static void edac_reset_delay_period(struct mem_ctl_info *mci, unsigned long value)
+{
+ /* cancel the current workq request */
+ edac_mc_workq_teardown(mci);
+
+ /* lock the list of devices for the new setup */
+ mutex_lock(&mem_ctls_mutex);
+
+ /* restart the workq request, with new delay value */
+ edac_mc_workq_setup(mci, value);
+
+ mutex_unlock(&mem_ctls_mutex);
+}
+
/* Return 0 on success, 1 on failure.
* Before calling this function, caller must
* assign a unique value to mci->mc_idx.
+ *
+ * locking model:
+ *
+ * called with the mem_ctls_mutex lock held
*/
-static int add_mc_to_global_list (struct mem_ctl_info *mci)
+static int add_mc_to_global_list(struct mem_ctl_info *mci)
{
struct list_head *item, *insert_before;
struct mem_ctl_info *p;
insert_before = &mc_devices;
- if (unlikely((p = find_mci_by_dev(mci->dev)) != NULL))
+ p = find_mci_by_dev(mci->dev);
+ if (unlikely(p != NULL))
goto fail0;
list_for_each(item, &mc_devices) {
@@ -1424,18 +376,19 @@ static int add_mc_to_global_list (struct mem_ctl_info *mci)
}
list_add_tail_rcu(&mci->link, insert_before);
+ atomic_inc(&edac_handlers);
return 0;
fail0:
edac_printk(KERN_WARNING, EDAC_MC,
- "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
- dev_name(p->dev), p->mod_name, p->ctl_name, p->mc_idx);
+ "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
+ dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
return 1;
fail1:
edac_printk(KERN_WARNING, EDAC_MC,
- "bug in low-level driver: attempt to assign\n"
- " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
+ "bug in low-level driver: attempt to assign\n"
+ " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
return 1;
}
@@ -1450,6 +403,7 @@ static void complete_mc_list_del(struct rcu_head *head)
static void del_mc_from_global_list(struct mem_ctl_info *mci)
{
+ atomic_dec(&edac_handlers);
list_del_rcu(&mci->link);
init_completion(&mci->complete);
call_rcu(&mci->rcu, complete_mc_list_del);
@@ -1457,6 +411,34 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci)
}
/**
+ * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'.
+ *
+ * If found, return a pointer to the structure.
+ * Else return NULL.
+ *
+ * Caller must hold mem_ctls_mutex.
+ */
+struct mem_ctl_info *edac_mc_find(int idx)
+{
+ struct list_head *item;
+ struct mem_ctl_info *mci;
+
+ list_for_each(item, &mc_devices) {
+ mci = list_entry(item, struct mem_ctl_info, link);
+
+ if (mci->mc_idx >= idx) {
+ if (mci->mc_idx == idx)
+ return mci;
+
+ break;
+ }
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(edac_mc_find);
+
+/**
* edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
* create sysfs entries associated with mci structure
* @mci: pointer to the mci structure to be added to the list
@@ -1468,10 +450,10 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci)
*/
/* FIXME - should a warning be printed if no error detection? correction? */
-int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
+int edac_mc_add_mc(struct mem_ctl_info *mci)
{
debugf0("%s()\n", __func__);
- mci->mc_idx = mc_idx;
+
#ifdef CONFIG_EDAC_DEBUG
if (edac_debug_level >= 3)
edac_mc_dump_mci(mci);
@@ -1484,12 +466,12 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
edac_mc_dump_csrow(&mci->csrows[i]);
for (j = 0; j < mci->csrows[i].nr_channels; j++)
- edac_mc_dump_channel(
- &mci->csrows[i].channels[j]);
+ edac_mc_dump_channel(&mci->csrows[i].
+ channels[j]);
}
}
#endif
- down(&mem_ctls_mutex);
+ mutex_lock(&mem_ctls_mutex);
if (add_mc_to_global_list(mci))
goto fail0;
@@ -1503,18 +485,28 @@ int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
goto fail1;
}
+ /* If there IS a check routine, then we are running POLLED */
+ if (mci->edac_check != NULL) {
+ /* This instance is NOW RUNNING */
+ mci->op_state = OP_RUNNING_POLL;
+
+ edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+ } else {
+ mci->op_state = OP_RUNNING_INTERRUPT;
+ }
+
/* Report action taken */
- edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n",
- mci->mod_name, mci->ctl_name, dev_name(mci->dev));
+ edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':"
+ " DEV %s\n", mci->mod_name, mci->ctl_name, dev_name(mci));
- up(&mem_ctls_mutex);
+ mutex_unlock(&mem_ctls_mutex);
return 0;
fail1:
del_mc_from_global_list(mci);
fail0:
- up(&mem_ctls_mutex);
+ mutex_unlock(&mem_ctls_mutex);
return 1;
}
EXPORT_SYMBOL_GPL(edac_mc_add_mc);
@@ -1526,29 +518,41 @@ EXPORT_SYMBOL_GPL(edac_mc_add_mc);
*
* Return pointer to removed mci structure, or NULL if device not found.
*/
-struct mem_ctl_info * edac_mc_del_mc(struct device *dev)
+struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
{
struct mem_ctl_info *mci;
- debugf0("MC: %s()\n", __func__);
- down(&mem_ctls_mutex);
+ debugf0("%s()\n", __func__);
+
+ mutex_lock(&mem_ctls_mutex);
- if ((mci = find_mci_by_dev(dev)) == NULL) {
- up(&mem_ctls_mutex);
+ /* find the requested mci struct in the global list */
+ mci = find_mci_by_dev(dev);
+ if (mci == NULL) {
+ mutex_unlock(&mem_ctls_mutex);
return NULL;
}
- edac_remove_sysfs_mci_device(mci);
+ /* marking MCI offline */
+ mci->op_state = OP_OFFLINE;
+
del_mc_from_global_list(mci);
- up(&mem_ctls_mutex);
+ mutex_unlock(&mem_ctls_mutex);
+
+ /* flush workq processes and remove sysfs */
+ edac_mc_workq_teardown(mci);
+ edac_remove_sysfs_mci_device(mci);
+
edac_printk(KERN_INFO, EDAC_MC,
"Removed device %d for %s %s: DEV %s\n", mci->mc_idx,
- mci->mod_name, mci->ctl_name, dev_name(mci->dev));
+ mci->mod_name, mci->ctl_name, dev_name(mci));
+
return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_del_mc);
-void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
+static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
+ u32 size)
{
struct page *pg;
void *virt_addr;
@@ -1557,7 +561,7 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
debugf3("%s()\n", __func__);
/* ECC error page was not in our memory. Ignore it. */
- if(!pfn_valid(page))
+ if (!pfn_valid(page))
return;
/* Find the actual page structure then map it and fix */
@@ -1577,7 +581,6 @@ void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
if (PageHighMem(pg))
local_irq_restore(flags);
}
-EXPORT_SYMBOL_GPL(edac_mc_scrub_block);
/* FIXME - should return -1 */
int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
@@ -1611,7 +614,7 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
if (row == -1)
edac_mc_printk(mci, KERN_ERR,
"could not look up page error address %lx\n",
- (unsigned long) page);
+ (unsigned long)page);
return row;
}
@@ -1620,8 +623,9 @@ EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
/* FIXME - setable log (warning/emerg) levels */
/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
void edac_mc_handle_ce(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- unsigned long syndrome, int row, int channel, const char *msg)
+ unsigned long page_frame_number,
+ unsigned long offset_in_page, unsigned long syndrome,
+ int row, int channel, const char *msg)
{
unsigned long remapped_page;
@@ -1647,7 +651,7 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci,
return;
}
- if (log_ce)
+ if (edac_mc_get_log_ce())
/* FIXME - put in DIMM location */
edac_mc_printk(mci, KERN_WARNING,
"CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
@@ -1671,18 +675,18 @@ void edac_mc_handle_ce(struct mem_ctl_info *mci,
* page - which can then be scrubbed.
*/
remapped_page = mci->ctl_page_to_phys ?
- mci->ctl_page_to_phys(mci, page_frame_number) :
- page_frame_number;
+ mci->ctl_page_to_phys(mci, page_frame_number) :
+ page_frame_number;
edac_mc_scrub_block(remapped_page, offset_in_page,
- mci->csrows[row].grain);
+ mci->csrows[row].grain);
}
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
{
- if (log_ce)
+ if (edac_mc_get_log_ce())
edac_mc_printk(mci, KERN_WARNING,
"CE - no information available: %s\n", msg);
@@ -1692,8 +696,8 @@ void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
void edac_mc_handle_ue(struct mem_ctl_info *mci,
- unsigned long page_frame_number, unsigned long offset_in_page,
- int row, const char *msg)
+ unsigned long page_frame_number,
+ unsigned long offset_in_page, int row, const char *msg)
{
int len = EDAC_MC_LABEL_LEN * 4;
char labels[len + 1];
@@ -1714,26 +718,26 @@ void edac_mc_handle_ue(struct mem_ctl_info *mci,
}
chars = snprintf(pos, len + 1, "%s",
- mci->csrows[row].channels[0].label);
+ mci->csrows[row].channels[0].label);
len -= chars;
pos += chars;
for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0);
- chan++) {
+ chan++) {
chars = snprintf(pos, len + 1, ":%s",
- mci->csrows[row].channels[chan].label);
+ mci->csrows[row].channels[chan].label);
len -= chars;
pos += chars;
}
- if (log_ue)
+ if (edac_mc_get_log_ue())
edac_mc_printk(mci, KERN_EMERG,
"UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
"labels \"%s\": %s\n", page_frame_number,
- offset_in_page, mci->csrows[row].grain, row, labels,
- msg);
+ offset_in_page, mci->csrows[row].grain, row,
+ labels, msg);
- if (panic_on_ue)
+ if (edac_mc_get_panic_on_ue())
panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
"row %d, labels \"%s\": %s\n", mci->mc_idx,
page_frame_number, offset_in_page,
@@ -1746,10 +750,10 @@ EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
{
- if (panic_on_ue)
+ if (edac_mc_get_panic_on_ue())
panic("EDAC MC%d: Uncorrected Error", mci->mc_idx);
- if (log_ue)
+ if (edac_mc_get_log_ue())
edac_mc_printk(mci, KERN_WARNING,
"UE - no information available: %s\n", msg);
mci->ue_noinfo_count++;
@@ -1757,16 +761,14 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
-
/*************************************************************
* On Fully Buffered DIMM modules, this help function is
* called to process UE events
*/
void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channela,
- unsigned int channelb,
- char *msg)
+ unsigned int csrow,
+ unsigned int channela,
+ unsigned int channelb, char *msg)
{
int len = EDAC_MC_LABEL_LEN * 4;
char labels[len + 1];
@@ -1808,20 +810,21 @@ void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
/* Generate the DIMM labels from the specified channels */
chars = snprintf(pos, len + 1, "%s",
mci->csrows[csrow].channels[channela].label);
- len -= chars; pos += chars;
+ len -= chars;
+ pos += chars;
chars = snprintf(pos, len + 1, "-%s",
mci->csrows[csrow].channels[channelb].label);
- if (log_ue)
+ if (edac_mc_get_log_ue())
edac_mc_printk(mci, KERN_EMERG,
"UE row %d, channel-a= %d channel-b= %d "
"labels \"%s\": %s\n", csrow, channela, channelb,
labels, msg);
- if (panic_on_ue)
+ if (edac_mc_get_panic_on_ue())
panic("UE row %d, channel-a= %d channel-b= %d "
- "labels \"%s\": %s\n", csrow, channela,
- channelb, labels, msg);
+ "labels \"%s\": %s\n", csrow, channela,
+ channelb, labels, msg);
}
EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
@@ -1830,9 +833,7 @@ EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
* called to process CE events
*/
void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
- unsigned int csrow,
- unsigned int channel,
- char *msg)
+ unsigned int csrow, unsigned int channel, char *msg)
{
/* Ensure boundary values */
@@ -1853,13 +854,12 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
return;
}
- if (log_ce)
+ if (edac_mc_get_log_ce())
/* FIXME - put in DIMM location */
edac_mc_printk(mci, KERN_WARNING,
"CE row %d, channel %d, label \"%s\": %s\n",
csrow, channel,
- mci->csrows[csrow].channels[channel].label,
- msg);
+ mci->csrows[csrow].channels[channel].label, msg);
mci->ce_count++;
mci->csrows[csrow].ce_count++;
@@ -1867,17 +867,16 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
}
EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
-
/*
* Iterate over all MC instances and check for ECC, et al, errors
*/
-static inline void check_mc_devices(void)
+void edac_check_mc_devices(void)
{
struct list_head *item;
struct mem_ctl_info *mci;
debugf3("%s()\n", __func__);
- down(&mem_ctls_mutex);
+ mutex_lock(&mem_ctls_mutex);
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
@@ -1886,119 +885,5 @@ static inline void check_mc_devices(void)
mci->edac_check(mci);
}
- up(&mem_ctls_mutex);
-}
-
-/*
- * Check MC status every poll_msec.
- * Check PCI status every poll_msec as well.
- *
- * This where the work gets done for edac.
- *
- * SMP safe, doesn't use NMI, and auto-rate-limits.
- */
-static void do_edac_check(void)
-{
- debugf3("%s()\n", __func__);
- check_mc_devices();
- do_pci_parity_check();
-}
-
-static int edac_kernel_thread(void *arg)
-{
- while (!kthread_should_stop()) {
- do_edac_check();
-
- /* goto sleep for the interval */
- schedule_timeout_interruptible((HZ * poll_msec) / 1000);
- try_to_freeze();
- }
-
- return 0;
+ mutex_unlock(&mem_ctls_mutex);
}
-
-/*
- * edac_mc_init
- * module initialization entry point
- */
-static int __init edac_mc_init(void)
-{
- edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
-
- /*
- * Harvest and clear any boot/initialization PCI parity errors
- *
- * FIXME: This only clears errors logged by devices present at time of
- * module initialization. We should also do an initial clear
- * of each newly hotplugged device.
- */
- clear_pci_parity_errors();
-
- /* Create the MC sysfs entries */
- if (edac_sysfs_memctrl_setup()) {
- edac_printk(KERN_ERR, EDAC_MC,
- "Error initializing sysfs code\n");
- return -ENODEV;
- }
-
- /* Create the PCI parity sysfs entries */
- if (edac_sysfs_pci_setup()) {
- edac_sysfs_memctrl_teardown();
- edac_printk(KERN_ERR, EDAC_MC,
- "EDAC PCI: Error initializing sysfs code\n");
- return -ENODEV;
- }
-
- /* create our kernel thread */
- edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
-
- if (IS_ERR(edac_thread)) {
- /* remove the sysfs entries */
- edac_sysfs_memctrl_teardown();
- edac_sysfs_pci_teardown();
- return PTR_ERR(edac_thread);
- }
-
- return 0;
-}
-
-/*
- * edac_mc_exit()
- * module exit/termination functioni
- */
-static void __exit edac_mc_exit(void)
-{
- debugf0("%s()\n", __func__);
- kthread_stop(edac_thread);
-
- /* tear down the sysfs device */
- edac_sysfs_memctrl_teardown();
- edac_sysfs_pci_teardown();
-}
-
-module_init(edac_mc_init);
-module_exit(edac_mc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
- "Based on work by Dan Hollis et al");
-MODULE_DESCRIPTION("Core library routines for MC reporting");
-
-module_param(panic_on_ue, int, 0644);
-MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
-#ifdef CONFIG_PCI
-module_param(check_pci_parity, int, 0644);
-MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on");
-module_param(panic_on_pci_parity, int, 0644);
-MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on");
-#endif
-module_param(log_ue, int, 0644);
-MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on");
-module_param(log_ce, int, 0644);
-MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on");
-module_param(poll_msec, int, 0644);
-MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds");
-#ifdef CONFIG_EDAC_DEBUG
-module_param(edac_debug_level, int, 0644);
-MODULE_PARM_DESC(edac_debug_level, "Debug level");
-#endif
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
new file mode 100644
index 000000000000..cd090b0677a7
--- /dev/null
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -0,0 +1,1024 @@
+/*
+ * edac_mc kernel module
+ * (C) 2005-2007 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+
+/* MC EDAC Controls, setable by module parameter, and sysfs */
+static int edac_mc_log_ue = 1;
+static int edac_mc_log_ce = 1;
+static int edac_mc_panic_on_ue;
+static int edac_mc_poll_msec = 1000;
+
+/* Getter functions for above */
+int edac_mc_get_log_ue(void)
+{
+ return edac_mc_log_ue;
+}
+
+int edac_mc_get_log_ce(void)
+{
+ return edac_mc_log_ce;
+}
+
+int edac_mc_get_panic_on_ue(void)
+{
+ return edac_mc_panic_on_ue;
+}
+
+/* this is temporary */
+int edac_mc_get_poll_msec(void)
+{
+ return edac_mc_poll_msec;
+}
+
+/* Parameter declarations for above */
+module_param(edac_mc_panic_on_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
+module_param(edac_mc_log_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ue,
+ "Log uncorrectable error to console: 0=off 1=on");
+module_param(edac_mc_log_ce, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ce,
+ "Log correctable error to console: 0=off 1=on");
+module_param(edac_mc_poll_msec, int, 0644);
+MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
+
+/*
+ * various constants for Memory Controllers
+ */
+static const char *mem_types[] = {
+ [MEM_EMPTY] = "Empty",
+ [MEM_RESERVED] = "Reserved",
+ [MEM_UNKNOWN] = "Unknown",
+ [MEM_FPM] = "FPM",
+ [MEM_EDO] = "EDO",
+ [MEM_BEDO] = "BEDO",
+ [MEM_SDR] = "Unbuffered-SDR",
+ [MEM_RDR] = "Registered-SDR",
+ [MEM_DDR] = "Unbuffered-DDR",
+ [MEM_RDDR] = "Registered-DDR",
+ [MEM_RMBS] = "RMBS",
+ [MEM_DDR2] = "Unbuffered-DDR2",
+ [MEM_FB_DDR2] = "FullyBuffered-DDR2",
+ [MEM_RDDR2] = "Registered-DDR2"
+};
+
+static const char *dev_types[] = {
+ [DEV_UNKNOWN] = "Unknown",
+ [DEV_X1] = "x1",
+ [DEV_X2] = "x2",
+ [DEV_X4] = "x4",
+ [DEV_X8] = "x8",
+ [DEV_X16] = "x16",
+ [DEV_X32] = "x32",
+ [DEV_X64] = "x64"
+};
+
+static const char *edac_caps[] = {
+ [EDAC_UNKNOWN] = "Unknown",
+ [EDAC_NONE] = "None",
+ [EDAC_RESERVED] = "Reserved",
+ [EDAC_PARITY] = "PARITY",
+ [EDAC_EC] = "EC",
+ [EDAC_SECDED] = "SECDED",
+ [EDAC_S2ECD2ED] = "S2ECD2ED",
+ [EDAC_S4ECD4ED] = "S4ECD4ED",
+ [EDAC_S8ECD8ED] = "S8ECD8ED",
+ [EDAC_S16ECD16ED] = "S16ECD16ED"
+};
+
+
+
+/*
+ * /sys/devices/system/edac/mc;
+ * data structures and methods
+ */
+static ssize_t memctrl_int_show(void *ptr, char *buffer)
+{
+ int *value = (int *)ptr;
+ return sprintf(buffer, "%u\n", *value);
+}
+
+static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
+{
+ int *value = (int *)ptr;
+
+ if (isdigit(*buffer))
+ *value = simple_strtoul(buffer, NULL, 0);
+
+ return count;
+}
+
+
+/* EDAC sysfs CSROW data structures and methods
+ */
+
+/* Set of more default csrow<id> attribute show/store functions */
+static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%u\n", csrow->ue_count);
+}
+
+static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%u\n", csrow->ce_count);
+}
+
+static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages));
+}
+
+static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%s\n", mem_types[csrow->mtype]);
+}
+
+static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%s\n", dev_types[csrow->dtype]);
+}
+
+static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
+ int private)
+{
+ return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]);
+}
+
+/* show/store functions for DIMM Label attributes */
+static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
+ char *data, int channel)
+{
+ return snprintf(data, EDAC_MC_LABEL_LEN, "%s",
+ csrow->channels[channel].label);
+}
+
+static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
+ const char *data,
+ size_t count, int channel)
+{
+ ssize_t max_size = 0;
+
+ max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
+ strncpy(csrow->channels[channel].label, data, max_size);
+ csrow->channels[channel].label[max_size] = '\0';
+
+ return max_size;
+}
+
+/* show function for dynamic chX_ce_count attribute */
+static ssize_t channel_ce_count_show(struct csrow_info *csrow,
+ char *data, int channel)
+{
+ return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
+}
+
+/* csrow specific attribute structure */
+struct csrowdev_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct csrow_info *, char *, int);
+ ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
+ int private;
+};
+
+#define to_csrow(k) container_of(k, struct csrow_info, kobj)
+#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
+
+/* Set of show/store higher level functions for default csrow attributes */
+static ssize_t csrowdev_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct csrow_info *csrow = to_csrow(kobj);
+ struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+ if (csrowdev_attr->show)
+ return csrowdev_attr->show(csrow,
+ buffer, csrowdev_attr->private);
+ return -EIO;
+}
+
+static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct csrow_info *csrow = to_csrow(kobj);
+ struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+ if (csrowdev_attr->store)
+ return csrowdev_attr->store(csrow,
+ buffer,
+ count, csrowdev_attr->private);
+ return -EIO;
+}
+
+static struct sysfs_ops csrowfs_ops = {
+ .show = csrowdev_show,
+ .store = csrowdev_store
+};
+
+#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
+static struct csrowdev_attribute attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+ .private = _private, \
+};
+
+/* default cwrow<id>/attribute files */
+CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
+CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
+CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
+CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
+CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
+CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
+
+/* default attributes of the CSROW<id> object */
+static struct csrowdev_attribute *default_csrow_attr[] = {
+ &attr_dev_type,
+ &attr_mem_type,
+ &attr_edac_mode,
+ &attr_size_mb,
+ &attr_ue_count,
+ &attr_ce_count,
+ NULL,
+};
+
+/* possible dynamic channel DIMM Label attribute files */
+CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 0);
+CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 1);
+CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 2);
+CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 3);
+CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 4);
+CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
+ channel_dimm_label_show, channel_dimm_label_store, 5);
+
+/* Total possible dynamic DIMM Label attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
+ &attr_ch0_dimm_label,
+ &attr_ch1_dimm_label,
+ &attr_ch2_dimm_label,
+ &attr_ch3_dimm_label,
+ &attr_ch4_dimm_label,
+ &attr_ch5_dimm_label
+};
+
+/* possible dynamic channel ce_count attribute files */
+CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
+CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
+CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
+CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
+CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
+CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
+
+/* Total possible dynamic ce_count attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
+ &attr_ch0_ce_count,
+ &attr_ch1_ce_count,
+ &attr_ch2_ce_count,
+ &attr_ch3_ce_count,
+ &attr_ch4_ce_count,
+ &attr_ch5_ce_count
+};
+
+#define EDAC_NR_CHANNELS 6
+
+/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
+static int edac_create_channel_files(struct kobject *kobj, int chan)
+{
+ int err = -ENODEV;
+
+ if (chan >= EDAC_NR_CHANNELS)
+ return err;
+
+ /* create the DIMM label attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *)
+ dynamic_csrow_dimm_attr[chan]);
+
+ if (!err) {
+ /* create the CE Count attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *)
+ dynamic_csrow_ce_count_attr[chan]);
+ } else {
+ debugf1("%s() dimm labels and ce_count files created",
+ __func__);
+ }
+
+ return err;
+}
+
+/* No memory to release for this kobj */
+static void edac_csrow_instance_release(struct kobject *kobj)
+{
+ struct mem_ctl_info *mci;
+ struct csrow_info *cs;
+
+ debugf1("%s()\n", __func__);
+
+ cs = container_of(kobj, struct csrow_info, kobj);
+ mci = cs->mci;
+
+ kobject_put(&mci->edac_mci_kobj);
+}
+
+/* the kobj_type instance for a CSROW */
+static struct kobj_type ktype_csrow = {
+ .release = edac_csrow_instance_release,
+ .sysfs_ops = &csrowfs_ops,
+ .default_attrs = (struct attribute **)default_csrow_attr,
+};
+
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_object(struct mem_ctl_info *mci,
+ struct csrow_info *csrow, int index)
+{
+ struct kobject *kobj_mci = &mci->edac_mci_kobj;
+ struct kobject *kobj;
+ int chan;
+ int err;
+
+ /* generate ..../edac/mc/mc<id>/csrow<index> */
+ memset(&csrow->kobj, 0, sizeof(csrow->kobj));
+ csrow->mci = mci; /* include container up link */
+ csrow->kobj.parent = kobj_mci;
+ csrow->kobj.ktype = &ktype_csrow;
+
+ /* name this instance of csrow<id> */
+ err = kobject_set_name(&csrow->kobj, "csrow%d", index);
+ if (err)
+ goto err_out;
+
+ /* bump the mci instance's kobject's ref count */
+ kobj = kobject_get(&mci->edac_mci_kobj);
+ if (!kobj) {
+ err = -ENODEV;
+ goto err_out;
+ }
+
+ /* Instanstiate the csrow object */
+ err = kobject_register(&csrow->kobj);
+ if (err)
+ goto err_release_top_kobj;
+
+ /* At this point, to release a csrow kobj, one must
+ * call the kobject_unregister and allow that tear down
+ * to work the releasing
+ */
+
+ /* Create the dyanmic attribute files on this csrow,
+ * namely, the DIMM labels and the channel ce_count
+ */
+ for (chan = 0; chan < csrow->nr_channels; chan++) {
+ err = edac_create_channel_files(&csrow->kobj, chan);
+ if (err) {
+ /* special case the unregister here */
+ kobject_unregister(&csrow->kobj);
+ goto err_out;
+ }
+ }
+
+ return 0;
+
+ /* error unwind stack */
+err_release_top_kobj:
+ kobject_put(&mci->edac_mci_kobj);
+
+err_out:
+ return err;
+}
+
+/* default sysfs methods and data structures for the main MCI kobject */
+
+static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ int row, chan;
+
+ mci->ue_noinfo_count = 0;
+ mci->ce_noinfo_count = 0;
+ mci->ue_count = 0;
+ mci->ce_count = 0;
+
+ for (row = 0; row < mci->nr_csrows; row++) {
+ struct csrow_info *ri = &mci->csrows[row];
+
+ ri->ue_count = 0;
+ ri->ce_count = 0;
+
+ for (chan = 0; chan < ri->nr_channels; chan++)
+ ri->channels[chan].ce_count = 0;
+ }
+
+ mci->start_time = jiffies;
+ return count;
+}
+
+/* memory scrubbing */
+static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ u32 bandwidth = -1;
+
+ if (mci->set_sdram_scrub_rate) {
+
+ memctrl_int_store(&bandwidth, data, count);
+
+ if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set successfully, applied: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set FAILED, could not apply: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'set'control is not implemented!\n");
+ }
+ return count;
+}
+
+static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+{
+ u32 bandwidth = -1;
+
+ if (mci->get_sdram_scrub_rate) {
+ if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate successfully, fetched: %d\n",
+ bandwidth);
+ } else {
+ /* FIXME: error codes maybe? */
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate fetch FAILED, got: %d\n",
+ bandwidth);
+ }
+ } else {
+ /* FIXME: produce "not implemented" ERROR for user-side. */
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrubbing 'get' control is not implemented\n");
+ }
+ return sprintf(data, "%d\n", bandwidth);
+}
+
+/* default attribute files for the MCI object */
+static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ue_count);
+}
+
+static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ce_count);
+}
+
+static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ce_noinfo_count);
+}
+
+static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%d\n", mci->ue_noinfo_count);
+}
+
+static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
+}
+
+static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
+{
+ return sprintf(data, "%s\n", mci->ctl_name);
+}
+
+static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
+{
+ int total_pages, csrow_idx;
+
+ for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
+ csrow_idx++) {
+ struct csrow_info *csrow = &mci->csrows[csrow_idx];
+
+ if (!csrow->nr_pages)
+ continue;
+
+ total_pages += csrow->nr_pages;
+ }
+
+ return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
+}
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
+#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
+
+/* MCI show/store functions for top most object */
+static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+{
+ struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ if (mcidev_attr->show)
+ return mcidev_attr->show(mem_ctl_info, buffer);
+
+ return -EIO;
+}
+
+static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ if (mcidev_attr->store)
+ return mcidev_attr->store(mem_ctl_info, buffer, count);
+
+ return -EIO;
+}
+
+/* Intermediate show/store table */
+static struct sysfs_ops mci_ops = {
+ .show = mcidev_show,
+ .store = mcidev_store
+};
+
+#define MCIDEV_ATTR(_name,_mode,_show,_store) \
+static struct mcidev_sysfs_attribute mci_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* default Control file */
+MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+
+/* default Attribute files */
+MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+
+/* memory scrubber attribute file */
+MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
+ mci_sdram_scrub_rate_store);
+
+static struct mcidev_sysfs_attribute *mci_attr[] = {
+ &mci_attr_reset_counters,
+ &mci_attr_mc_name,
+ &mci_attr_size_mb,
+ &mci_attr_seconds_since_reset,
+ &mci_attr_ue_noinfo_count,
+ &mci_attr_ce_noinfo_count,
+ &mci_attr_ue_count,
+ &mci_attr_ce_count,
+ &mci_attr_sdram_scrub_rate,
+ NULL
+};
+
+
+/*
+ * Release of a MC controlling instance
+ *
+ * each MC control instance has the following resources upon entry:
+ * a) a ref count on the top memctl kobj
+ * b) a ref count on this module
+ *
+ * this function must decrement those ref counts and then
+ * issue a free on the instance's memory
+ */
+static void edac_mci_control_release(struct kobject *kobj)
+{
+ struct mem_ctl_info *mci;
+
+ mci = to_mci(kobj);
+
+ debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);
+
+ /* decrement the module ref count */
+ module_put(mci->owner);
+
+ /* free the mci instance memory here */
+ kfree(mci);
+}
+
+static struct kobj_type ktype_mci = {
+ .release = edac_mci_control_release,
+ .sysfs_ops = &mci_ops,
+ .default_attrs = (struct attribute **)mci_attr,
+};
+
+/* show/store, tables, etc for the MC kset */
+
+
+struct memctrl_dev_attribute {
+ struct attribute attr;
+ void *value;
+ ssize_t(*show) (void *, char *);
+ ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for memory control object */
+static ssize_t memctrl_dev_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct memctrl_dev_attribute *memctrl_dev;
+ memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+ if (memctrl_dev->show)
+ return memctrl_dev->show(memctrl_dev->value, buffer);
+
+ return -EIO;
+}
+
+static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct memctrl_dev_attribute *memctrl_dev;
+ memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+ if (memctrl_dev->store)
+ return memctrl_dev->store(memctrl_dev->value, buffer, count);
+
+ return -EIO;
+}
+
+static struct sysfs_ops memctrlfs_ops = {
+ .show = memctrl_dev_show,
+ .store = memctrl_dev_store
+};
+
+#define MEMCTRL_ATTR(_name, _mode, _show, _store) \
+static struct memctrl_dev_attribute attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = &_name, \
+ .show = _show, \
+ .store = _store, \
+};
+
+#define MEMCTRL_STRING_ATTR(_name, _data, _mode, _show, _store) \
+static struct memctrl_dev_attribute attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = _data, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* csrow<id> control files */
+MEMCTRL_ATTR(edac_mc_panic_on_ue,
+ S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ue,
+ S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ce,
+ S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_poll_msec,
+ S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+/* Base Attributes of the memory ECC object */
+static struct memctrl_dev_attribute *memctrl_attr[] = {
+ &attr_edac_mc_panic_on_ue,
+ &attr_edac_mc_log_ue,
+ &attr_edac_mc_log_ce,
+ &attr_edac_mc_poll_msec,
+ NULL,
+};
+
+
+/* the ktype for the mc_kset internal kobj */
+static struct kobj_type ktype_mc_set_attribs = {
+ .sysfs_ops = &memctrlfs_ops,
+ .default_attrs = (struct attribute **)memctrl_attr,
+};
+
+/* EDAC memory controller sysfs kset:
+ * /sys/devices/system/edac/mc
+ */
+static struct kset mc_kset = {
+ .kobj = {.name = "mc", .ktype = &ktype_mc_set_attribs },
+ .ktype = &ktype_mci,
+};
+
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ * setups and registers the main kobject for each mci
+ */
+int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+ struct kobject *kobj_mci;
+ int err;
+
+ debugf1("%s()\n", __func__);
+
+ kobj_mci = &mci->edac_mci_kobj;
+
+ /* Init the mci's kobject */
+ memset(kobj_mci, 0, sizeof(*kobj_mci));
+
+ /* this instance become part of the mc_kset */
+ kobj_mci->kset = &mc_kset;
+
+ /* set the name of the mc<id> object */
+ err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
+ if (err)
+ goto fail_out;
+
+ /* Record which module 'owns' this control structure
+ * and bump the ref count of the module
+ */
+ mci->owner = THIS_MODULE;
+
+ /* bump ref count on this module */
+ if (!try_module_get(mci->owner)) {
+ err = -ENODEV;
+ goto fail_out;
+ }
+
+ /* register the mc<id> kobject to the mc_kset */
+ err = kobject_register(kobj_mci);
+ if (err) {
+ debugf1("%s()Failed to register '.../edac/mc%d'\n",
+ __func__, mci->mc_idx);
+ goto kobj_reg_fail;
+ }
+
+ /* At this point, to 'free' the control struct,
+ * edac_mc_unregister_sysfs_main_kobj() must be used
+ */
+
+ debugf1("%s() Registered '.../edac/mc%d' kobject\n",
+ __func__, mci->mc_idx);
+
+ return 0;
+
+ /* Error exit stack */
+
+kobj_reg_fail:
+ module_put(mci->owner);
+
+fail_out:
+ return err;
+}
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ * tears down and the main mci kobject from the mc_kset
+ */
+void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+ /* delete the kobj from the mc_kset */
+ kobject_unregister(&mci->edac_mci_kobj);
+}
+
+#define EDAC_DEVICE_SYMLINK "device"
+
+/*
+ * edac_create_mci_instance_attributes
+ * create MC driver specific attributes at the topmost level
+ * directory of this mci instance.
+ */
+static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+ int err;
+ struct mcidev_sysfs_attribute *sysfs_attrib;
+
+ /* point to the start of the array and iterate over it
+ * adding each attribute listed to this mci instance's kobject
+ */
+ sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+ while (sysfs_attrib && sysfs_attrib->attr.name) {
+ err = sysfs_create_file(&mci->edac_mci_kobj,
+ (struct attribute*) sysfs_attrib);
+ if (err) {
+ return err;
+ }
+
+ sysfs_attrib++;
+ }
+
+ return 0;
+}
+
+/*
+ * edac_remove_mci_instance_attributes
+ * remove MC driver specific attributes at the topmost level
+ * directory of this mci instance.
+ */
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+ struct mcidev_sysfs_attribute *sysfs_attrib;
+
+ /* point to the start of the array and iterate over it
+ * adding each attribute listed to this mci instance's kobject
+ */
+ sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+ /* loop if there are attributes and until we hit a NULL entry */
+ while (sysfs_attrib && sysfs_attrib->attr.name) {
+ sysfs_remove_file(&mci->edac_mci_kobj,
+ (struct attribute *) sysfs_attrib);
+ sysfs_attrib++;
+ }
+}
+
+
+/*
+ * Create a new Memory Controller kobject instance,
+ * mc<id> under the 'mc' directory
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+ int i;
+ int err;
+ struct csrow_info *csrow;
+ struct kobject *kobj_mci = &mci->edac_mci_kobj;
+
+ debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+
+ /* create a symlink for the device */
+ err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
+ EDAC_DEVICE_SYMLINK);
+ if (err) {
+ debugf1("%s() failure to create symlink\n", __func__);
+ goto fail0;
+ }
+
+ /* If the low level driver desires some attributes,
+ * then create them now for the driver.
+ */
+ if (mci->mc_driver_sysfs_attributes) {
+ err = edac_create_mci_instance_attributes(mci);
+ if (err) {
+ debugf1("%s() failure to create mci attributes\n",
+ __func__);
+ goto fail0;
+ }
+ }
+
+ /* Make directories for each CSROW object under the mc<id> kobject
+ */
+ for (i = 0; i < mci->nr_csrows; i++) {
+ csrow = &mci->csrows[i];
+
+ /* Only expose populated CSROWs */
+ if (csrow->nr_pages > 0) {
+ err = edac_create_csrow_object(mci, csrow, i);
+ if (err) {
+ debugf1("%s() failure: create csrow %d obj\n",
+ __func__, i);
+ goto fail1;
+ }
+ }
+ }
+
+ return 0;
+
+ /* CSROW error: backout what has already been registered, */
+fail1:
+ for (i--; i >= 0; i--) {
+ if (csrow->nr_pages > 0) {
+ kobject_unregister(&mci->csrows[i].kobj);
+ }
+ }
+
+ /* remove the mci instance's attributes, if any */
+ edac_remove_mci_instance_attributes(mci);
+
+ /* remove the symlink */
+ sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
+
+fail0:
+ return err;
+}
+
+/*
+ * remove a Memory Controller instance
+ */
+void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+ int i;
+
+ debugf0("%s()\n", __func__);
+
+ /* remove all csrow kobjects */
+ for (i = 0; i < mci->nr_csrows; i++) {
+ if (mci->csrows[i].nr_pages > 0) {
+ debugf0("%s() unreg csrow-%d\n", __func__, i);
+ kobject_unregister(&mci->csrows[i].kobj);
+ }
+ }
+
+ debugf0("%s() remove_link\n", __func__);
+
+ /* remove the symlink */
+ sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
+
+ debugf0("%s() remove_mci_instance\n", __func__);
+
+ /* remove this mci instance's attribtes */
+ edac_remove_mci_instance_attributes(mci);
+
+ debugf0("%s() unregister this mci kobj\n", __func__);
+
+ /* unregister this instance's kobject */
+ kobject_unregister(&mci->edac_mci_kobj);
+}
+
+
+
+
+/*
+ * edac_setup_sysfs_mc_kset(void)
+ *
+ * Initialize the mc_kset for the 'mc' entry
+ * This requires creating the top 'mc' directory with a kset
+ * and its controls/attributes.
+ *
+ * To this 'mc' kset, instance 'mci' will be grouped as children.
+ *
+ * Return: 0 SUCCESS
+ * !0 FAILURE error code
+ */
+int edac_sysfs_setup_mc_kset(void)
+{
+ int err = 0;
+ struct sysdev_class *edac_class;
+
+ debugf1("%s()\n", __func__);
+
+ /* get the /sys/devices/system/edac class reference */
+ edac_class = edac_get_edac_class();
+ if (edac_class == NULL) {
+ debugf1("%s() no edac_class error=%d\n", __func__, err);
+ goto fail_out;
+ }
+
+ /* Init the MC's kobject */
+ mc_kset.kobj.parent = &edac_class->kset.kobj;
+
+ /* register the mc_kset */
+ err = kset_register(&mc_kset);
+ if (err) {
+ debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
+ goto fail_out;
+ }
+
+ debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
+
+ return 0;
+
+
+ /* error unwind stack */
+fail_out:
+ return err;
+}
+
+/*
+ * edac_sysfs_teardown_mc_kset
+ *
+ * deconstruct the mc_ket for memory controllers
+ */
+void edac_sysfs_teardown_mc_kset(void)
+{
+ kset_unregister(&mc_kset);
+}
+
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
new file mode 100644
index 000000000000..e0c4a4086055
--- /dev/null
+++ b/drivers/edac/edac_module.c
@@ -0,0 +1,222 @@
+/*
+ * edac_module.c
+ *
+ * (C) 2007 www.softwarebitmaker.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.
+ *
+ * Author: Doug Thompson <dougthompson@xmission.com>
+ *
+ */
+#include <linux/edac.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_VERSION "Ver: 2.1.0 " __DATE__
+
+#ifdef CONFIG_EDAC_DEBUG
+/* Values of 0 to 4 will generate output */
+int edac_debug_level = 2;
+EXPORT_SYMBOL_GPL(edac_debug_level);
+#endif
+
+/* scope is to module level only */
+struct workqueue_struct *edac_workqueue;
+
+/*
+ * sysfs object: /sys/devices/system/edac
+ * need to export to other files in this modules
+ */
+static struct sysdev_class edac_class = {
+ set_kset_name("edac"),
+};
+static int edac_class_valid;
+
+/*
+ * edac_op_state_to_string()
+ */
+char *edac_op_state_to_string(int opstate)
+{
+ if (opstate == OP_RUNNING_POLL)
+ return "POLLED";
+ else if (opstate == OP_RUNNING_INTERRUPT)
+ return "INTERRUPT";
+ else if (opstate == OP_RUNNING_POLL_INTR)
+ return "POLL-INTR";
+ else if (opstate == OP_ALLOC)
+ return "ALLOC";
+ else if (opstate == OP_OFFLINE)
+ return "OFFLINE";
+
+ return "UNKNOWN";
+}
+
+/*
+ * edac_get_edac_class()
+ *
+ * return pointer to the edac class of 'edac'
+ */
+struct sysdev_class *edac_get_edac_class(void)
+{
+ struct sysdev_class *classptr = NULL;
+
+ if (edac_class_valid)
+ classptr = &edac_class;
+
+ return classptr;
+}
+
+/*
+ * edac_register_sysfs_edac_name()
+ *
+ * register the 'edac' into /sys/devices/system
+ *
+ * return:
+ * 0 success
+ * !0 error
+ */
+static int edac_register_sysfs_edac_name(void)
+{
+ int err;
+
+ /* create the /sys/devices/system/edac directory */
+ err = sysdev_class_register(&edac_class);
+
+ if (err) {
+ debugf1("%s() error=%d\n", __func__, err);
+ return err;
+ }
+
+ edac_class_valid = 1;
+ return 0;
+}
+
+/*
+ * sysdev_class_unregister()
+ *
+ * unregister the 'edac' from /sys/devices/system
+ */
+static void edac_unregister_sysfs_edac_name(void)
+{
+ /* only if currently registered, then unregister it */
+ if (edac_class_valid)
+ sysdev_class_unregister(&edac_class);
+
+ edac_class_valid = 0;
+}
+
+/*
+ * edac_workqueue_setup
+ * initialize the edac work queue for polling operations
+ */
+static int edac_workqueue_setup(void)
+{
+ edac_workqueue = create_singlethread_workqueue("edac-poller");
+ if (edac_workqueue == NULL)
+ return -ENODEV;
+ else
+ return 0;
+}
+
+/*
+ * edac_workqueue_teardown
+ * teardown the edac workqueue
+ */
+static void edac_workqueue_teardown(void)
+{
+ if (edac_workqueue) {
+ flush_workqueue(edac_workqueue);
+ destroy_workqueue(edac_workqueue);
+ edac_workqueue = NULL;
+ }
+}
+
+/*
+ * edac_init
+ * module initialization entry point
+ */
+static int __init edac_init(void)
+{
+ int err = 0;
+
+ edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
+
+ /*
+ * Harvest and clear any boot/initialization PCI parity errors
+ *
+ * FIXME: This only clears errors logged by devices present at time of
+ * module initialization. We should also do an initial clear
+ * of each newly hotplugged device.
+ */
+ edac_pci_clear_parity_errors();
+
+ /*
+ * perform the registration of the /sys/devices/system/edac class object
+ */
+ if (edac_register_sysfs_edac_name()) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Error initializing 'edac' kobject\n");
+ err = -ENODEV;
+ goto error;
+ }
+
+ /*
+ * now set up the mc_kset under the edac class object
+ */
+ err = edac_sysfs_setup_mc_kset();
+ if (err)
+ goto sysfs_setup_fail;
+
+ /* Setup/Initialize the workq for this core */
+ err = edac_workqueue_setup();
+ if (err) {
+ edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
+ goto workq_fail;
+ }
+
+ return 0;
+
+ /* Error teardown stack */
+workq_fail:
+ edac_sysfs_teardown_mc_kset();
+
+sysfs_setup_fail:
+ edac_unregister_sysfs_edac_name();
+
+error:
+ return err;
+}
+
+/*
+ * edac_exit()
+ * module exit/termination function
+ */
+static void __exit edac_exit(void)
+{
+ debugf0("%s()\n", __func__);
+
+ /* tear down the various subsystems */
+ edac_workqueue_teardown();
+ edac_sysfs_teardown_mc_kset();
+ edac_unregister_sysfs_edac_name();
+}
+
+/*
+ * Inform the kernel of our entry and exit points
+ */
+module_init(edac_init);
+module_exit(edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
+MODULE_DESCRIPTION("Core library routines for EDAC reporting");
+
+/* refer to *_sysfs.c files for parameters that are exported via sysfs */
+
+#ifdef CONFIG_EDAC_DEBUG
+module_param(edac_debug_level, int, 0644);
+MODULE_PARM_DESC(edac_debug_level, "Debug level");
+#endif
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
new file mode 100644
index 000000000000..a2134dfc3cc6
--- /dev/null
+++ b/drivers/edac/edac_module.h
@@ -0,0 +1,77 @@
+
+/*
+ * edac_module.h
+ *
+ * For defining functions/data for within the EDAC_CORE module only
+ *
+ * written by doug thompson <norsk5@xmission.h>
+ */
+
+#ifndef __EDAC_MODULE_H__
+#define __EDAC_MODULE_H__
+
+#include <linux/sysdev.h>
+
+#include "edac_core.h"
+
+/*
+ * INTERNAL EDAC MODULE:
+ * EDAC memory controller sysfs create/remove functions
+ * and setup/teardown functions
+ *
+ * edac_mc objects
+ */
+extern int edac_sysfs_setup_mc_kset(void);
+extern void edac_sysfs_teardown_mc_kset(void);
+extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
+extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
+extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+extern void edac_check_mc_devices(void);
+extern int edac_get_log_ue(void);
+extern int edac_get_log_ce(void);
+extern int edac_get_panic_on_ue(void);
+extern int edac_mc_get_log_ue(void);
+extern int edac_mc_get_log_ce(void);
+extern int edac_mc_get_panic_on_ue(void);
+extern int edac_get_poll_msec(void);
+extern int edac_mc_get_poll_msec(void);
+
+extern int edac_device_register_sysfs_main_kobj(
+ struct edac_device_ctl_info *edac_dev);
+extern void edac_device_unregister_sysfs_main_kobj(
+ struct edac_device_ctl_info *edac_dev);
+extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
+extern struct sysdev_class *edac_get_edac_class(void);
+
+/* edac core workqueue: single CPU mode */
+extern struct workqueue_struct *edac_workqueue;
+extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+ unsigned msec);
+extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_reset_delay_period(struct edac_device_ctl_info
+ *edac_dev, unsigned long value);
+extern void *edac_align_ptr(void *ptr, unsigned size);
+
+/*
+ * EDAC PCI functions
+ */
+#ifdef CONFIG_PCI
+extern void edac_pci_do_parity_check(void);
+extern void edac_pci_clear_parity_errors(void);
+extern int edac_sysfs_pci_setup(void);
+extern void edac_sysfs_pci_teardown(void);
+extern int edac_pci_get_check_errors(void);
+extern int edac_pci_get_poll_msec(void);
+#else /* CONFIG_PCI */
+/* pre-process these away */
+#define edac_pci_do_parity_check()
+#define edac_pci_clear_parity_errors()
+#define edac_sysfs_pci_setup() (0)
+#define edac_sysfs_pci_teardown()
+#define edac_pci_get_check_errors()
+#define edac_pci_get_poll_msec()
+#endif /* CONFIG_PCI */
+
+#endif /* __EDAC_MODULE_H__ */
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
new file mode 100644
index 000000000000..d9cd5e048cee
--- /dev/null
+++ b/drivers/edac/edac_pci.c
@@ -0,0 +1,433 @@
+/*
+ * EDAC PCI component
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+static DEFINE_MUTEX(edac_pci_ctls_mutex);
+static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
+
+static inline void edac_lock_pci_list(void)
+{
+ mutex_lock(&edac_pci_ctls_mutex);
+}
+
+static inline void edac_unlock_pci_list(void)
+{
+ mutex_unlock(&edac_pci_ctls_mutex);
+}
+
+/*
+ * The alloc() and free() functions for the 'edac_pci' control info
+ * structure. The chip driver will allocate one of these for each
+ * edac_pci it is going to control/register with the EDAC CORE.
+ */
+struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+ const char *edac_pci_name)
+{
+ struct edac_pci_ctl_info *pci;
+ void *pvt;
+ unsigned int size;
+
+ pci = (struct edac_pci_ctl_info *)0;
+ pvt = edac_align_ptr(&pci[1], sz_pvt);
+ size = ((unsigned long)pvt) + sz_pvt;
+
+ if ((pci = kzalloc(size, GFP_KERNEL)) == NULL)
+ return NULL;
+
+ pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
+
+ pci->pvt_info = pvt;
+
+ pci->op_state = OP_ALLOC;
+
+ snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
+
+ return pci;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
+
+/*
+ * edac_pci_free_ctl_info()
+ * frees the memory allocated by edac_pci_alloc_ctl_info() function
+ */
+void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
+{
+ kfree(pci);
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
+
+/*
+ * find_edac_pci_by_dev()
+ * scans the edac_pci list for a specific 'struct device *'
+ */
+static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
+{
+ struct edac_pci_ctl_info *pci;
+ struct list_head *item;
+
+ debugf3("%s()\n", __func__);
+
+ list_for_each(item, &edac_pci_list) {
+ pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+ if (pci->dev == dev)
+ return pci;
+ }
+
+ return NULL;
+}
+
+/*
+ * add_edac_pci_to_global_list
+ * Before calling this function, caller must assign a unique value to
+ * edac_dev->pci_idx.
+ * Return:
+ * 0 on success
+ * 1 on failure
+ */
+static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
+{
+ struct list_head *item, *insert_before;
+ struct edac_pci_ctl_info *rover;
+
+ insert_before = &edac_pci_list;
+
+ /* Determine if already on the list */
+ if (unlikely((rover = find_edac_pci_by_dev(pci->dev)) != NULL))
+ goto fail0;
+
+ /* Insert in ascending order by 'pci_idx', so find position */
+ list_for_each(item, &edac_pci_list) {
+ rover = list_entry(item, struct edac_pci_ctl_info, link);
+
+ if (rover->pci_idx >= pci->pci_idx) {
+ if (unlikely(rover->pci_idx == pci->pci_idx))
+ goto fail1;
+
+ insert_before = item;
+ break;
+ }
+ }
+
+ list_add_tail_rcu(&pci->link, insert_before);
+ return 0;
+
+fail0:
+ edac_printk(KERN_WARNING, EDAC_PCI,
+ "%s (%s) %s %s already assigned %d\n",
+ rover->dev->bus_id, dev_name(rover),
+ rover->mod_name, rover->ctl_name, rover->pci_idx);
+ return 1;
+
+fail1:
+ edac_printk(KERN_WARNING, EDAC_PCI,
+ "but in low-level driver: attempt to assign\n"
+ "\tduplicate pci_idx %d in %s()\n", rover->pci_idx,
+ __func__);
+ return 1;
+}
+
+/*
+ * complete_edac_pci_list_del
+ */
+static void complete_edac_pci_list_del(struct rcu_head *head)
+{
+ struct edac_pci_ctl_info *pci;
+
+ pci = container_of(head, struct edac_pci_ctl_info, rcu);
+ INIT_LIST_HEAD(&pci->link);
+ complete(&pci->complete);
+}
+
+/*
+ * del_edac_pci_from_global_list
+ */
+static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
+{
+ list_del_rcu(&pci->link);
+ init_completion(&pci->complete);
+ call_rcu(&pci->rcu, complete_edac_pci_list_del);
+ wait_for_completion(&pci->complete);
+}
+
+/*
+ * edac_pci_find()
+ * Search for an edac_pci_ctl_info structure whose index is 'idx'
+ *
+ * If found, return a pointer to the structure
+ * Else return NULL.
+ *
+ * Caller must hold pci_ctls_mutex.
+ */
+struct edac_pci_ctl_info *edac_pci_find(int idx)
+{
+ struct list_head *item;
+ struct edac_pci_ctl_info *pci;
+
+ /* Iterage over list, looking for exact match of ID */
+ list_for_each(item, &edac_pci_list) {
+ pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+ if (pci->pci_idx >= idx) {
+ if (pci->pci_idx == idx)
+ return pci;
+
+ /* not on list, so terminate early */
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_find);
+
+/*
+ * edac_pci_workq_function()
+ * performs the operation scheduled by a workq request
+ */
+static void edac_pci_workq_function(struct work_struct *work_req)
+{
+ struct delayed_work *d_work = (struct delayed_work *)work_req;
+ struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
+
+ edac_lock_pci_list();
+
+ if ((pci->op_state == OP_RUNNING_POLL) &&
+ (pci->edac_check != NULL) && (edac_pci_get_check_errors()))
+ pci->edac_check(pci);
+
+ edac_unlock_pci_list();
+
+ /* Reschedule */
+ queue_delayed_work(edac_workqueue, &pci->work,
+ msecs_to_jiffies(edac_pci_get_poll_msec()));
+}
+
+/*
+ * edac_pci_workq_setup()
+ * initialize a workq item for this edac_pci instance
+ * passing in the new delay period in msec
+ */
+static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
+ unsigned int msec)
+{
+ debugf0("%s()\n", __func__);
+
+ INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
+ queue_delayed_work(edac_workqueue, &pci->work,
+ msecs_to_jiffies(edac_pci_get_poll_msec()));
+}
+
+/*
+ * edac_pci_workq_teardown()
+ * stop the workq processing on this edac_pci instance
+ */
+static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
+{
+ int status;
+
+ status = cancel_delayed_work(&pci->work);
+ if (status == 0)
+ flush_workqueue(edac_workqueue);
+}
+
+/*
+ * edac_pci_reset_delay_period
+ */
+void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+ unsigned long value)
+{
+ edac_lock_pci_list();
+
+ edac_pci_workq_teardown(pci);
+
+ edac_pci_workq_setup(pci, value);
+
+ edac_unlock_pci_list();
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
+
+/*
+ * edac_pci_add_device: Insert the 'edac_dev' structure into the
+ * edac_pci global list and create sysfs entries associated with
+ * edac_pci structure.
+ * @pci: pointer to the edac_device structure to be added to the list
+ * @edac_idx: A unique numeric identifier to be assigned to the
+ * 'edac_pci' structure.
+ *
+ * Return:
+ * 0 Success
+ * !0 Failure
+ */
+int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
+{
+ debugf0("%s()\n", __func__);
+
+ pci->pci_idx = edac_idx;
+
+ edac_lock_pci_list();
+
+ if (add_edac_pci_to_global_list(pci))
+ goto fail0;
+
+ pci->start_time = jiffies;
+
+ if (edac_pci_create_sysfs(pci)) {
+ edac_pci_printk(pci, KERN_WARNING,
+ "failed to create sysfs pci\n");
+ goto fail1;
+ }
+
+ if (pci->edac_check != NULL) {
+ pci->op_state = OP_RUNNING_POLL;
+
+ edac_pci_workq_setup(pci, 1000);
+ } else {
+ pci->op_state = OP_RUNNING_INTERRUPT;
+ }
+
+ edac_pci_printk(pci, KERN_INFO,
+ "Giving out device to module '%s' controller '%s':"
+ " DEV '%s' (%s)\n",
+ pci->mod_name,
+ pci->ctl_name,
+ dev_name(pci), edac_op_state_to_string(pci->op_state));
+
+ edac_unlock_pci_list();
+ return 0;
+
+fail1:
+ del_edac_pci_from_global_list(pci);
+fail0:
+ edac_unlock_pci_list();
+ return 1;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_add_device);
+
+/*
+ * edac_pci_del_device()
+ * Remove sysfs entries for specified edac_pci structure and
+ * then remove edac_pci structure from global list
+ *
+ * @dev:
+ * Pointer to 'struct device' representing edac_pci structure
+ * to remove
+ *
+ * Return:
+ * Pointer to removed edac_pci structure,
+ * or NULL if device not found
+ */
+struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
+{
+ struct edac_pci_ctl_info *pci;
+
+ debugf0("%s()\n", __func__);
+
+ edac_lock_pci_list();
+
+ if ((pci = find_edac_pci_by_dev(dev)) == NULL) {
+ edac_unlock_pci_list();
+ return NULL;
+ }
+
+ pci->op_state = OP_OFFLINE;
+
+ edac_pci_workq_teardown(pci);
+
+ edac_pci_remove_sysfs(pci);
+
+ del_edac_pci_from_global_list(pci);
+
+ edac_unlock_pci_list();
+
+ edac_printk(KERN_INFO, EDAC_PCI,
+ "Removed device %d for %s %s: DEV %s\n",
+ pci->pci_idx, pci->mod_name, pci->ctl_name, dev_name(pci));
+
+ return pci;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_del_device);
+
+void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
+{
+ edac_pci_do_parity_check();
+}
+
+static int edac_pci_idx;
+#define EDAC_PCI_GENCTL_NAME "EDAC PCI controller"
+
+struct edac_pci_gen_data {
+ int edac_idx;
+};
+
+struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
+ const char *mod_name)
+{
+ struct edac_pci_ctl_info *pci;
+ struct edac_pci_gen_data *pdata;
+
+ pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME);
+ if (!pci)
+ return NULL;
+
+ pdata = pci->pvt_info;
+ pci->dev = dev;
+ dev_set_drvdata(pci->dev, pci);
+ pci->dev_name = pci_name(to_pci_dev(dev));
+
+ pci->mod_name = mod_name;
+ pci->ctl_name = EDAC_PCI_GENCTL_NAME;
+ pci->edac_check = edac_pci_generic_check;
+
+ pdata->edac_idx = edac_pci_idx++;
+
+ if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
+ debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+ edac_pci_free_ctl_info(pci);
+ return NULL;
+ }
+
+ return pci;
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
+
+void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
+{
+ edac_pci_del_device(pci->dev);
+ edac_pci_free_ctl_info(pci);
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
new file mode 100644
index 000000000000..fac94cae2c3d
--- /dev/null
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -0,0 +1,620 @@
+/*
+ * (C) 2005, 2006 Linux Networx (http://lnxi.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#ifdef CONFIG_PCI
+
+#define EDAC_PCI_SYMLINK "device"
+
+static int check_pci_errors; /* default YES check PCI parity */
+static int edac_pci_panic_on_pe; /* default no panic on PCI Parity */
+static int edac_pci_log_pe = 1; /* log PCI parity errors */
+static int edac_pci_log_npe = 1; /* log PCI non-parity error errors */
+static atomic_t pci_parity_count = ATOMIC_INIT(0);
+static atomic_t pci_nonparity_count = ATOMIC_INIT(0);
+static int edac_pci_poll_msec = 1000;
+
+static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
+static struct completion edac_pci_kobj_complete;
+static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
+
+int edac_pci_get_check_errors(void)
+{
+ return check_pci_errors;
+}
+
+int edac_pci_get_log_pe(void)
+{
+ return edac_pci_log_pe;
+}
+
+int edac_pci_get_log_npe(void)
+{
+ return edac_pci_log_npe;
+}
+
+int edac_pci_get_panic_on_pe(void)
+{
+ return edac_pci_panic_on_pe;
+}
+
+int edac_pci_get_poll_msec(void)
+{
+ return edac_pci_poll_msec;
+}
+
+/**************************** EDAC PCI sysfs instance *******************/
+static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data)
+{
+ return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count));
+}
+
+static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci,
+ char *data)
+{
+ return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count));
+}
+
+#define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_instance_attr(a) container_of(a, struct instance_attribute, attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_pci_instance_release(struct kobject *kobj)
+{
+ struct edac_pci_ctl_info *pci;
+
+ debugf1("%s()\n", __func__);
+
+ pci = to_instance(kobj);
+ complete(&pci->kobj_complete);
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct edac_pci_ctl_info *, char *);
+ ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_show(struct kobject *kobj,
+ struct attribute *attr, char *buffer)
+{
+ struct edac_pci_ctl_info *pci = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->show)
+ return instance_attr->show(pci, buffer);
+ return -EIO;
+}
+
+/* Function to 'store' fields into the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_store(struct kobject *kobj,
+ struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct edac_pci_ctl_info *pci = to_instance(kobj);
+ struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+ if (instance_attr->store)
+ return instance_attr->store(pci, buffer, count);
+ return -EIO;
+}
+
+static struct sysfs_ops pci_instance_ops = {
+ .show = edac_pci_instance_show,
+ .store = edac_pci_instance_store
+};
+
+#define INSTANCE_ATTR(_name, _mode, _show, _store) \
+static struct instance_attribute attr_instance_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .show = _show, \
+ .store = _store, \
+};
+
+INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);
+INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);
+
+/* pci instance attributes */
+static struct instance_attribute *pci_instance_attr[] = {
+ &attr_instance_pe_count,
+ &attr_instance_npe_count,
+ NULL
+};
+
+/* the ktype for pci instance */
+static struct kobj_type ktype_pci_instance = {
+ .release = edac_pci_instance_release,
+ .sysfs_ops = &pci_instance_ops,
+ .default_attrs = (struct attribute **)pci_instance_attr,
+};
+
+static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+{
+ int err;
+
+ pci->kobj.parent = &edac_pci_kobj;
+ pci->kobj.ktype = &ktype_pci_instance;
+
+ err = kobject_set_name(&pci->kobj, "pci%d", idx);
+ if (err)
+ return err;
+
+ err = kobject_register(&pci->kobj);
+ if (err != 0) {
+ debugf2("%s() failed to register instance pci%d\n",
+ __func__, idx);
+ return err;
+ }
+
+ debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+
+ return 0;
+}
+
+static void
+edac_pci_delete_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+{
+ init_completion(&pci->kobj_complete);
+ kobject_unregister(&pci->kobj);
+ wait_for_completion(&pci->kobj_complete);
+}
+
+/***************************** EDAC PCI sysfs root **********************/
+#define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)
+
+static ssize_t edac_pci_int_show(void *ptr, char *buffer)
+{
+ int *value = ptr;
+ return sprintf(buffer, "%d\n", *value);
+}
+
+static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
+{
+ int *value = ptr;
+
+ if (isdigit(*buffer))
+ *value = simple_strtoul(buffer, NULL, 0);
+
+ return count;
+}
+
+struct edac_pci_dev_attribute {
+ struct attribute attr;
+ void *value;
+ ssize_t(*show) (void *, char *);
+ ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for PCI Parity object */
+static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+{
+ struct edac_pci_dev_attribute *edac_pci_dev;
+ edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+ if (edac_pci_dev->show)
+ return edac_pci_dev->show(edac_pci_dev->value, buffer);
+ return -EIO;
+}
+
+static ssize_t edac_pci_dev_store(struct kobject *kobj,
+ struct attribute *attr, const char *buffer,
+ size_t count)
+{
+ struct edac_pci_dev_attribute *edac_pci_dev;
+ edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+ if (edac_pci_dev->show)
+ return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
+ return -EIO;
+}
+
+static struct sysfs_ops edac_pci_sysfs_ops = {
+ .show = edac_pci_dev_show,
+ .store = edac_pci_dev_store
+};
+
+#define EDAC_PCI_ATTR(_name,_mode,_show,_store) \
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = &_name, \
+ .show = _show, \
+ .store = _store, \
+};
+
+#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store) \
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
+ .value = _data, \
+ .show = _show, \
+ .store = _store, \
+};
+
+/* PCI Parity control files */
+EDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+ edac_pci_int_store);
+EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
+EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL);
+
+/* Base Attributes of the memory ECC object */
+static struct edac_pci_dev_attribute *edac_pci_attr[] = {
+ &edac_pci_attr_check_pci_errors,
+ &edac_pci_attr_edac_pci_log_pe,
+ &edac_pci_attr_edac_pci_log_npe,
+ &edac_pci_attr_edac_pci_panic_on_pe,
+ &edac_pci_attr_pci_parity_count,
+ &edac_pci_attr_pci_nonparity_count,
+ NULL,
+};
+
+/* No memory to release */
+static void edac_pci_release(struct kobject *kobj)
+{
+ struct edac_pci_ctl_info *pci;
+
+ pci = to_edacpci(kobj);
+
+ debugf1("%s()\n", __func__);
+ complete(&pci->kobj_complete);
+}
+
+static struct kobj_type ktype_edac_pci = {
+ .release = edac_pci_release,
+ .sysfs_ops = &edac_pci_sysfs_ops,
+ .default_attrs = (struct attribute **)edac_pci_attr,
+};
+
+/**
+ * edac_sysfs_pci_setup()
+ *
+ * setup the sysfs for EDAC PCI attributes
+ * assumes edac_class has already been initialized
+ */
+int edac_pci_register_main_kobj(void)
+{
+ int err;
+ struct sysdev_class *edac_class;
+
+ debugf1("%s()\n", __func__);
+
+ edac_class = edac_get_edac_class();
+ if (edac_class == NULL) {
+ debugf1("%s() no edac_class\n", __func__);
+ return -ENODEV;
+ }
+
+ edac_pci_kobj.ktype = &ktype_edac_pci;
+
+ edac_pci_kobj.parent = &edac_class->kset.kobj;
+
+ err = kobject_set_name(&edac_pci_kobj, "pci");
+ if (err)
+ return err;
+
+ /* Instanstiate the pci object */
+ /* FIXME: maybe new sysdev_create_subdir() */
+ err = kobject_register(&edac_pci_kobj);
+
+ if (err) {
+ debugf1("Failed to register '.../edac/pci'\n");
+ return err;
+ }
+
+ debugf1("Registered '.../edac/pci' kobject\n");
+
+ return 0;
+}
+
+/*
+ * edac_pci_unregister_main_kobj()
+ *
+ * perform the sysfs teardown for the PCI attributes
+ */
+void edac_pci_unregister_main_kobj(void)
+{
+ debugf0("%s()\n", __func__);
+ init_completion(&edac_pci_kobj_complete);
+ kobject_unregister(&edac_pci_kobj);
+ wait_for_completion(&edac_pci_kobj_complete);
+}
+
+int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
+{
+ int err;
+ struct kobject *edac_kobj = &pci->kobj;
+
+ if (atomic_inc_return(&edac_pci_sysfs_refcount) == 1) {
+ err = edac_pci_register_main_kobj();
+ if (err) {
+ atomic_dec(&edac_pci_sysfs_refcount);
+ return err;
+ }
+ }
+
+ err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
+ if (err) {
+ if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0)
+ edac_pci_unregister_main_kobj();
+ }
+
+ debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
+
+ err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
+ if (err) {
+ debugf0("%s() sysfs_create_link() returned err= %d\n",
+ __func__, err);
+ return err;
+ }
+
+ return 0;
+}
+
+void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
+{
+ debugf0("%s()\n", __func__);
+
+ edac_pci_delete_instance_kobj(pci, pci->pci_idx);
+
+ sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
+
+ if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0)
+ edac_pci_unregister_main_kobj();
+}
+
+/************************ PCI error handling *************************/
+static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
+{
+ int where;
+ u16 status;
+
+ where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
+ pci_read_config_word(dev, where, &status);
+
+ /* If we get back 0xFFFF then we must suspect that the card has been
+ * pulled but the Linux PCI layer has not yet finished cleaning up.
+ * We don't want to report on such devices
+ */
+
+ if (status == 0xFFFF) {
+ u32 sanity;
+
+ pci_read_config_dword(dev, 0, &sanity);
+
+ if (sanity == 0xFFFFFFFF)
+ return 0;
+ }
+
+ status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
+ PCI_STATUS_PARITY;
+
+ if (status)
+ /* reset only the bits we are interested in */
+ pci_write_config_word(dev, where, status);
+
+ return status;
+}
+
+typedef void (*pci_parity_check_fn_t) (struct pci_dev * dev);
+
+/* Clear any PCI parity errors logged by this device. */
+static void edac_pci_dev_parity_clear(struct pci_dev *dev)
+{
+ u8 header_type;
+
+ get_pci_parity_status(dev, 0);
+
+ /* read the device TYPE, looking for bridges */
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
+ get_pci_parity_status(dev, 1);
+}
+
+/*
+ * PCI Parity polling
+ *
+ */
+static void edac_pci_dev_parity_test(struct pci_dev *dev)
+{
+ u16 status;
+ u8 header_type;
+
+ /* read the STATUS register on this device
+ */
+ status = get_pci_parity_status(dev, 0);
+
+ debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+ /* check the status reg for errors */
+ if (status) {
+ if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Signaled System Error on %s\n",
+ pci_name(dev));
+ atomic_inc(&pci_nonparity_count);
+ }
+
+ if (status & (PCI_STATUS_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Master Data Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+
+ if (status & (PCI_STATUS_DETECTED_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Detected Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+ }
+
+ /* read the device TYPE, looking for bridges */
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id);
+
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+ /* On bridges, need to examine secondary status register */
+ status = get_pci_parity_status(dev, 1);
+
+ debugf2("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+ /* check the secondary status reg for errors */
+ if (status) {
+ if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Signaled System Error on %s\n",
+ pci_name(dev));
+ atomic_inc(&pci_nonparity_count);
+ }
+
+ if (status & (PCI_STATUS_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Master Data Parity Error on "
+ "%s\n", pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+
+ if (status & (PCI_STATUS_DETECTED_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Detected Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+ }
+ }
+}
+
+/*
+ * pci_dev parity list iterator
+ * Scan the PCI device list for one iteration, looking for SERRORs
+ * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
+ */
+static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
+{
+ struct pci_dev *dev = NULL;
+
+ /* request for kernel access to the next PCI device, if any,
+ * and while we are looking at it have its reference count
+ * bumped until we are done with it
+ */
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ fn(dev);
+ }
+}
+
+/*
+ * edac_pci_do_parity_check
+ *
+ * performs the actual PCI parity check operation
+ */
+void edac_pci_do_parity_check(void)
+{
+ unsigned long flags;
+ int before_count;
+
+ debugf3("%s()\n", __func__);
+
+ if (!check_pci_errors)
+ return;
+
+ before_count = atomic_read(&pci_parity_count);
+
+ /* scan all PCI devices looking for a Parity Error on devices and
+ * bridges
+ */
+ local_irq_save(flags);
+ edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
+ local_irq_restore(flags);
+
+ /* Only if operator has selected panic on PCI Error */
+ if (edac_pci_get_panic_on_pe()) {
+ /* If the count is different 'after' from 'before' */
+ if (before_count != atomic_read(&pci_parity_count))
+ panic("EDAC: PCI Parity Error");
+ }
+}
+
+void edac_pci_clear_parity_errors(void)
+{
+ /* Clear any PCI bus parity errors that devices initially have logged
+ * in their registers.
+ */
+ edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
+}
+void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+ /* global PE counter incremented by edac_pci_do_parity_check() */
+ atomic_inc(&pci->counters.pe_count);
+
+ if (edac_pci_get_log_pe())
+ edac_pci_printk(pci, KERN_WARNING,
+ "Parity Error ctl: %s %d: %s\n",
+ pci->ctl_name, pci->pci_idx, msg);
+
+ /*
+ * poke all PCI devices and see which one is the troublemaker
+ * panic() is called if set
+ */
+ edac_pci_do_parity_check();
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_handle_pe);
+
+void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+ /* global NPE counter incremented by edac_pci_do_parity_check() */
+ atomic_inc(&pci->counters.npe_count);
+
+ if (edac_pci_get_log_npe())
+ edac_pci_printk(pci, KERN_WARNING,
+ "Non-Parity Error ctl: %s %d: %s\n",
+ pci->ctl_name, pci->pci_idx, msg);
+
+ /*
+ * poke all PCI devices and see which one is the troublemaker
+ * panic() is called if set
+ */
+ edac_pci_do_parity_check();
+}
+
+EXPORT_SYMBOL_GPL(edac_pci_handle_npe);
+
+/*
+ * Define the PCI parameter to the module
+ */
+module_param(check_pci_errors, int, 0644);
+MODULE_PARM_DESC(check_pci_errors,
+ "Check for PCI bus parity errors: 0=off 1=on");
+module_param(edac_pci_panic_on_pe, int, 0644);
+MODULE_PARM_DESC(edac_pci_panic_on_pe,
+ "Panic on PCI Bus Parity error: 0=off 1=on");
+
+#endif /* CONFIG_PCI */
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
new file mode 100644
index 000000000000..20b428aa155e
--- /dev/null
+++ b/drivers/edac/edac_stub.c
@@ -0,0 +1,46 @@
+/*
+ * common EDAC components that must be in kernel
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (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.
+ *
+ */
+#include <linux/module.h>
+#include <linux/edac.h>
+#include <asm/atomic.h>
+#include <asm/edac.h>
+
+int edac_op_state = EDAC_OPSTATE_INVAL;
+EXPORT_SYMBOL_GPL(edac_op_state);
+
+atomic_t edac_handlers = ATOMIC_INIT(0);
+EXPORT_SYMBOL_GPL(edac_handlers);
+
+int edac_err_assert = 0;
+EXPORT_SYMBOL_GPL(edac_err_assert);
+
+/*
+ * called to determine if there is an EDAC driver interested in
+ * knowing an event (such as NMI) occurred
+ */
+int edac_handler_set(void)
+{
+ if (edac_op_state == EDAC_OPSTATE_POLL)
+ return 0;
+
+ return atomic_read(&edac_handlers);
+}
+EXPORT_SYMBOL_GPL(edac_handler_set);
+
+/*
+ * handler for NMI type of interrupts to assert error
+ */
+void edac_atomic_assert_error(void)
+{
+ edac_err_assert++;
+}
+EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
new file mode 100644
index 000000000000..0ecfdc432f87
--- /dev/null
+++ b/drivers/edac/i3000_edac.c
@@ -0,0 +1,506 @@
+/*
+ * Intel 3000/3010 Memory Controller kernel module
+ * Copyright (C) 2007 Akamai Technologies, Inc.
+ * Shamelessly copied from:
+ * Intel D82875P Memory Controller kernel module
+ * (C) 2003 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define I3000_REVISION "1.1"
+
+#define EDAC_MOD_STR "i3000_edac"
+
+#define I3000_RANKS 8
+#define I3000_RANKS_PER_CHANNEL 4
+#define I3000_CHANNELS 2
+
+/* Intel 3000 register addresses - device 0 function 0 - DRAM Controller */
+
+#define I3000_MCHBAR 0x44 /* MCH Memory Mapped Register BAR */
+#define I3000_MCHBAR_MASK 0xffffc000
+#define I3000_MMR_WINDOW_SIZE 16384
+
+#define I3000_EDEAP 0x70 /* Extended DRAM Error Address Pointer (8b)
+ *
+ * 7:1 reserved
+ * 0 bit 32 of address
+ */
+#define I3000_DEAP 0x58 /* DRAM Error Address Pointer (32b)
+ *
+ * 31:7 address
+ * 6:1 reserved
+ * 0 Error channel 0/1
+ */
+#define I3000_DEAP_GRAIN (1 << 7)
+#define I3000_DEAP_PFN(edeap, deap) ((((edeap) & 1) << (32 - PAGE_SHIFT)) | \
+ ((deap) >> PAGE_SHIFT))
+#define I3000_DEAP_OFFSET(deap) ((deap) & ~(I3000_DEAP_GRAIN-1) & ~PAGE_MASK)
+#define I3000_DEAP_CHANNEL(deap) ((deap) & 1)
+
+#define I3000_DERRSYN 0x5c /* DRAM Error Syndrome (8b)
+ *
+ * 7:0 DRAM ECC Syndrome
+ */
+
+#define I3000_ERRSTS 0xc8 /* Error Status Register (16b)
+ *
+ * 15:12 reserved
+ * 11 MCH Thermal Sensor Event for SMI/SCI/SERR
+ * 10 reserved
+ * 9 LOCK to non-DRAM Memory Flag (LCKF)
+ * 8 Received Refresh Timeout Flag (RRTOF)
+ * 7:2 reserved
+ * 1 Multiple-bit DRAM ECC Error Flag (DMERR)
+ * 0 Single-bit DRAM ECC Error Flag (DSERR)
+ */
+#define I3000_ERRSTS_BITS 0x0b03 /* bits which indicate errors */
+#define I3000_ERRSTS_UE 0x0002
+#define I3000_ERRSTS_CE 0x0001
+
+#define I3000_ERRCMD 0xca /* Error Command (16b)
+ *
+ * 15:12 reserved
+ * 11 SERR on MCH Thermal Sensor Event (TSESERR)
+ * 10 reserved
+ * 9 SERR on LOCK to non-DRAM Memory (LCKERR)
+ * 8 SERR on DRAM Refresh Timeout (DRTOERR)
+ * 7:2 reserved
+ * 1 SERR Multiple-Bit DRAM ECC Error (DMERR)
+ * 0 SERR on Single-Bit ECC Error (DSERR)
+ */
+
+/* Intel MMIO register space - device 0 function 0 - MMR space */
+
+#define I3000_DRB_SHIFT 25 /* 32MiB grain */
+
+#define I3000_C0DRB 0x100 /* Channel 0 DRAM Rank Boundary (8b x 4)
+ *
+ * 7:0 Channel 0 DRAM Rank Boundary Address
+ */
+#define I3000_C1DRB 0x180 /* Channel 1 DRAM Rank Boundary (8b x 4)
+ *
+ * 7:0 Channel 1 DRAM Rank Boundary Address
+ */
+
+#define I3000_C0DRA 0x108 /* Channel 0 DRAM Rank Attribute (8b x 2)
+ *
+ * 7 reserved
+ * 6:4 DRAM odd Rank Attribute
+ * 3 reserved
+ * 2:0 DRAM even Rank Attribute
+ *
+ * Each attribute defines the page
+ * size of the corresponding rank:
+ * 000: unpopulated
+ * 001: reserved
+ * 010: 4 KB
+ * 011: 8 KB
+ * 100: 16 KB
+ * Others: reserved
+ */
+#define I3000_C1DRA 0x188 /* Channel 1 DRAM Rank Attribute (8b x 2) */
+#define ODD_RANK_ATTRIB(dra) (((dra) & 0x70) >> 4)
+#define EVEN_RANK_ATTRIB(dra) ((dra) & 0x07)
+
+#define I3000_C0DRC0 0x120 /* DRAM Controller Mode 0 (32b)
+ *
+ * 31:30 reserved
+ * 29 Initialization Complete (IC)
+ * 28:11 reserved
+ * 10:8 Refresh Mode Select (RMS)
+ * 7 reserved
+ * 6:4 Mode Select (SMS)
+ * 3:2 reserved
+ * 1:0 DRAM Type (DT)
+ */
+
+#define I3000_C0DRC1 0x124 /* DRAM Controller Mode 1 (32b)
+ *
+ * 31 Enhanced Addressing Enable (ENHADE)
+ * 30:0 reserved
+ */
+
+enum i3000p_chips {
+ I3000 = 0,
+};
+
+struct i3000_dev_info {
+ const char *ctl_name;
+};
+
+struct i3000_error_info {
+ u16 errsts;
+ u8 derrsyn;
+ u8 edeap;
+ u32 deap;
+ u16 errsts2;
+};
+
+static const struct i3000_dev_info i3000_devs[] = {
+ [I3000] = {
+ .ctl_name = "i3000"},
+};
+
+static struct pci_dev *mci_pdev;
+static int i3000_registered = 1;
+static struct edac_pci_ctl_info *i3000_pci;
+
+static void i3000_get_error_info(struct mem_ctl_info *mci,
+ struct i3000_error_info *info)
+{
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+
+ /*
+ * This is a mess because there is no atomic way to read all the
+ * registers at once and the registers can transition from CE being
+ * overwritten by UE.
+ */
+ pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts);
+ if (!(info->errsts & I3000_ERRSTS_BITS))
+ return;
+ pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+ pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+ pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+ pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts2);
+
+ /*
+ * If the error is the same for both reads then the first set
+ * of reads is valid. If there is a change then there is a CE
+ * with no info and the second set of reads is valid and
+ * should be UE info.
+ */
+ if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+ pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+ pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+ pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+ }
+
+ /* Clear any error bits.
+ * (Yes, we really clear bits by writing 1 to them.)
+ */
+ pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+ I3000_ERRSTS_BITS);
+}
+
+static int i3000_process_error_info(struct mem_ctl_info *mci,
+ struct i3000_error_info *info,
+ int handle_errors)
+{
+ int row, multi_chan;
+ int pfn, offset, channel;
+
+ multi_chan = mci->csrows[0].nr_channels - 1;
+
+ if (!(info->errsts & I3000_ERRSTS_BITS))
+ return 0;
+
+ if (!handle_errors)
+ return 1;
+
+ if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+ edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+ info->errsts = info->errsts2;
+ }
+
+ pfn = I3000_DEAP_PFN(info->edeap, info->deap);
+ offset = I3000_DEAP_OFFSET(info->deap);
+ channel = I3000_DEAP_CHANNEL(info->deap);
+
+ row = edac_mc_find_csrow_by_page(mci, pfn);
+
+ if (info->errsts & I3000_ERRSTS_UE)
+ edac_mc_handle_ue(mci, pfn, offset, row, "i3000 UE");
+ else
+ edac_mc_handle_ce(mci, pfn, offset, info->derrsyn, row,
+ multi_chan ? channel : 0, "i3000 CE");
+
+ return 1;
+}
+
+static void i3000_check(struct mem_ctl_info *mci)
+{
+ struct i3000_error_info info;
+
+ debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+ i3000_get_error_info(mci, &info);
+ i3000_process_error_info(mci, &info, 1);
+}
+
+static int i3000_is_interleaved(const unsigned char *c0dra,
+ const unsigned char *c1dra,
+ const unsigned char *c0drb,
+ const unsigned char *c1drb)
+{
+ int i;
+
+ /* If the channels aren't populated identically then
+ * we're not interleaved.
+ */
+ for (i = 0; i < I3000_RANKS_PER_CHANNEL / 2; i++)
+ if (ODD_RANK_ATTRIB(c0dra[i]) != ODD_RANK_ATTRIB(c1dra[i]) ||
+ EVEN_RANK_ATTRIB(c0dra[i]) !=
+ EVEN_RANK_ATTRIB(c1dra[i]))
+ return 0;
+
+ /* If the rank boundaries for the two channels are different
+ * then we're not interleaved.
+ */
+ for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++)
+ if (c0drb[i] != c1drb[i])
+ return 0;
+
+ return 1;
+}
+
+static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ int rc;
+ int i;
+ struct mem_ctl_info *mci = NULL;
+ unsigned long last_cumul_size;
+ int interleaved, nr_channels;
+ unsigned char dra[I3000_RANKS / 2], drb[I3000_RANKS];
+ unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2];
+ unsigned char *c0drb = drb, *c1drb = &drb[I3000_RANKS_PER_CHANNEL];
+ unsigned long mchbar;
+ void *window;
+
+ debugf0("MC: %s()\n", __func__);
+
+ pci_read_config_dword(pdev, I3000_MCHBAR, (u32 *) & mchbar);
+ mchbar &= I3000_MCHBAR_MASK;
+ window = ioremap_nocache(mchbar, I3000_MMR_WINDOW_SIZE);
+ if (!window) {
+ printk(KERN_ERR "i3000: cannot map mmio space at 0x%lx\n",
+ mchbar);
+ return -ENODEV;
+ }
+
+ c0dra[0] = readb(window + I3000_C0DRA + 0); /* ranks 0,1 */
+ c0dra[1] = readb(window + I3000_C0DRA + 1); /* ranks 2,3 */
+ c1dra[0] = readb(window + I3000_C1DRA + 0); /* ranks 0,1 */
+ c1dra[1] = readb(window + I3000_C1DRA + 1); /* ranks 2,3 */
+
+ for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++) {
+ c0drb[i] = readb(window + I3000_C0DRB + i);
+ c1drb[i] = readb(window + I3000_C1DRB + i);
+ }
+
+ iounmap(window);
+
+ /* Figure out how many channels we have.
+ *
+ * If we have what the datasheet calls "asymmetric channels"
+ * (essentially the same as what was called "virtual single
+ * channel mode" in the i82875) then it's a single channel as
+ * far as EDAC is concerned.
+ */
+ interleaved = i3000_is_interleaved(c0dra, c1dra, c0drb, c1drb);
+ nr_channels = interleaved ? 2 : 1;
+ mci = edac_mc_alloc(0, I3000_RANKS / nr_channels, nr_channels, 0);
+ if (!mci)
+ return -ENOMEM;
+
+ debugf3("MC: %s(): init mci\n", __func__);
+
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR2;
+
+ mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_SECDED;
+
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = I3000_REVISION;
+ mci->ctl_name = i3000_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
+ mci->edac_check = i3000_check;
+ mci->ctl_page_to_phys = NULL;
+
+ /*
+ * The dram rank boundary (DRB) reg values are boundary addresses
+ * for each DRAM rank with a granularity of 32MB. DRB regs are
+ * cumulative; the last one will contain the total memory
+ * contained in all ranks.
+ *
+ * If we're in interleaved mode then we're only walking through
+ * the ranks of controller 0, so we double all the values we see.
+ */
+ for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
+ u8 value;
+ u32 cumul_size;
+ struct csrow_info *csrow = &mci->csrows[i];
+
+ value = drb[i];
+ cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
+ if (interleaved)
+ cumul_size <<= 1;
+ debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
+ __func__, i, cumul_size);
+ if (cumul_size == last_cumul_size) {
+ csrow->mtype = MEM_EMPTY;
+ continue;
+ }
+
+ csrow->first_page = last_cumul_size;
+ csrow->last_page = cumul_size - 1;
+ csrow->nr_pages = cumul_size - last_cumul_size;
+ last_cumul_size = cumul_size;
+ csrow->grain = I3000_DEAP_GRAIN;
+ csrow->mtype = MEM_DDR2;
+ csrow->dtype = DEV_UNKNOWN;
+ csrow->edac_mode = EDAC_UNKNOWN;
+ }
+
+ /* Clear any error bits.
+ * (Yes, we really clear bits by writing 1 to them.)
+ */
+ pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+ I3000_ERRSTS_BITS);
+
+ rc = -ENODEV;
+ if (edac_mc_add_mc(mci)) {
+ debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+ goto fail;
+ }
+
+ /* allocating generic PCI control info */
+ i3000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i3000_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ /* get this far and it's successful */
+ debugf3("MC: %s(): success\n", __func__);
+ return 0;
+
+ fail:
+ if (mci)
+ edac_mc_free(mci);
+
+ return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i3000_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+
+ debugf0("MC: %s()\n", __func__);
+
+ if (pci_enable_device(pdev) < 0)
+ return -EIO;
+
+ rc = i3000_probe1(pdev, ent->driver_data);
+ if (mci_pdev == NULL)
+ mci_pdev = pci_dev_get(pdev);
+
+ return rc;
+}
+
+static void __devexit i3000_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+
+ debugf0("%s()\n", __func__);
+
+ if (i3000_pci)
+ edac_pci_release_generic_ctl(i3000_pci);
+
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+ return;
+
+ edac_mc_free(mci);
+}
+
+static const struct pci_device_id i3000_pci_tbl[] __devinitdata = {
+ {
+ PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I3000},
+ {
+ 0,
+ } /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i3000_pci_tbl);
+
+static struct pci_driver i3000_driver = {
+ .name = EDAC_MOD_STR,
+ .probe = i3000_init_one,
+ .remove = __devexit_p(i3000_remove_one),
+ .id_table = i3000_pci_tbl,
+};
+
+static int __init i3000_init(void)
+{
+ int pci_rc;
+
+ debugf3("MC: %s()\n", __func__);
+ pci_rc = pci_register_driver(&i3000_driver);
+ if (pci_rc < 0)
+ goto fail0;
+
+ if (mci_pdev == NULL) {
+ i3000_registered = 0;
+ mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_3000_HB, NULL);
+ if (!mci_pdev) {
+ debugf0("i3000 pci_get_device fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+
+ pci_rc = i3000_init_one(mci_pdev, i3000_pci_tbl);
+ if (pci_rc < 0) {
+ debugf0("i3000 init fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+ }
+
+ return 0;
+
+fail1:
+ pci_unregister_driver(&i3000_driver);
+
+fail0:
+ if (mci_pdev)
+ pci_dev_put(mci_pdev);
+
+ return pci_rc;
+}
+
+static void __exit i3000_exit(void)
+{
+ debugf3("MC: %s()\n", __func__);
+
+ pci_unregister_driver(&i3000_driver);
+ if (!i3000_registered) {
+ i3000_remove_one(mci_pdev);
+ pci_dev_put(mci_pdev);
+ }
+}
+
+module_init(i3000_init);
+module_exit(i3000_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akamai Technologies Arthur Ulfeldt/Jason Uhlenkott");
+MODULE_DESCRIPTION("MC support for Intel 3000 memory hub controllers");
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
new file mode 100644
index 000000000000..96f7e63e3996
--- /dev/null
+++ b/drivers/edac/i5000_edac.c
@@ -0,0 +1,1505 @@
+/*
+ * Intel 5000(P/V/X) class Memory Controllers kernel module
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Douglas Thompson Linux Networx (http://lnxi.com)
+ * norsk5@xmission.com
+ *
+ * This module is based on the following document:
+ *
+ * Intel 5000X Chipset Memory Controller Hub (MCH) - Datasheet
+ * http://developer.intel.com/design/chipsets/datashts/313070.htm
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/edac.h>
+#include <asm/mmzone.h>
+
+#include "edac_core.h"
+
+/*
+ * Alter this version for the I5000 module when modifications are made
+ */
+#define I5000_REVISION " Ver: 2.0.12 " __DATE__
+#define EDAC_MOD_STR "i5000_edac"
+
+#define i5000_printk(level, fmt, arg...) \
+ edac_printk(level, "i5000", fmt, ##arg)
+
+#define i5000_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "i5000", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_FBD_0
+#define PCI_DEVICE_ID_INTEL_FBD_0 0x25F5
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_FBD_1
+#define PCI_DEVICE_ID_INTEL_FBD_1 0x25F6
+#endif
+
+/* Device 16,
+ * Function 0: System Address
+ * Function 1: Memory Branch Map, Control, Errors Register
+ * Function 2: FSB Error Registers
+ *
+ * All 3 functions of Device 16 (0,1,2) share the SAME DID
+ */
+#define PCI_DEVICE_ID_INTEL_I5000_DEV16 0x25F0
+
+/* OFFSETS for Function 0 */
+
+/* OFFSETS for Function 1 */
+#define AMBASE 0x48
+#define MAXCH 0x56
+#define MAXDIMMPERCH 0x57
+#define TOLM 0x6C
+#define REDMEMB 0x7C
+#define RED_ECC_LOCATOR(x) ((x) & 0x3FFFF)
+#define REC_ECC_LOCATOR_EVEN(x) ((x) & 0x001FF)
+#define REC_ECC_LOCATOR_ODD(x) ((x) & 0x3FE00)
+#define MIR0 0x80
+#define MIR1 0x84
+#define MIR2 0x88
+#define AMIR0 0x8C
+#define AMIR1 0x90
+#define AMIR2 0x94
+
+#define FERR_FAT_FBD 0x98
+#define NERR_FAT_FBD 0x9C
+#define EXTRACT_FBDCHAN_INDX(x) (((x)>>28) & 0x3)
+#define FERR_FAT_FBDCHAN 0x30000000
+#define FERR_FAT_M3ERR 0x00000004
+#define FERR_FAT_M2ERR 0x00000002
+#define FERR_FAT_M1ERR 0x00000001
+#define FERR_FAT_MASK (FERR_FAT_M1ERR | \
+ FERR_FAT_M2ERR | \
+ FERR_FAT_M3ERR)
+
+#define FERR_NF_FBD 0xA0
+
+/* Thermal and SPD or BFD errors */
+#define FERR_NF_M28ERR 0x01000000
+#define FERR_NF_M27ERR 0x00800000
+#define FERR_NF_M26ERR 0x00400000
+#define FERR_NF_M25ERR 0x00200000
+#define FERR_NF_M24ERR 0x00100000
+#define FERR_NF_M23ERR 0x00080000
+#define FERR_NF_M22ERR 0x00040000
+#define FERR_NF_M21ERR 0x00020000
+
+/* Correctable errors */
+#define FERR_NF_M20ERR 0x00010000
+#define FERR_NF_M19ERR 0x00008000
+#define FERR_NF_M18ERR 0x00004000
+#define FERR_NF_M17ERR 0x00002000
+
+/* Non-Retry or redundant Retry errors */
+#define FERR_NF_M16ERR 0x00001000
+#define FERR_NF_M15ERR 0x00000800
+#define FERR_NF_M14ERR 0x00000400
+#define FERR_NF_M13ERR 0x00000200
+
+/* Uncorrectable errors */
+#define FERR_NF_M12ERR 0x00000100
+#define FERR_NF_M11ERR 0x00000080
+#define FERR_NF_M10ERR 0x00000040
+#define FERR_NF_M9ERR 0x00000020
+#define FERR_NF_M8ERR 0x00000010
+#define FERR_NF_M7ERR 0x00000008
+#define FERR_NF_M6ERR 0x00000004
+#define FERR_NF_M5ERR 0x00000002
+#define FERR_NF_M4ERR 0x00000001
+
+#define FERR_NF_UNCORRECTABLE (FERR_NF_M12ERR | \
+ FERR_NF_M11ERR | \
+ FERR_NF_M10ERR | \
+ FERR_NF_M8ERR | \
+ FERR_NF_M7ERR | \
+ FERR_NF_M6ERR | \
+ FERR_NF_M5ERR | \
+ FERR_NF_M4ERR)
+#define FERR_NF_CORRECTABLE (FERR_NF_M20ERR | \
+ FERR_NF_M19ERR | \
+ FERR_NF_M18ERR | \
+ FERR_NF_M17ERR)
+#define FERR_NF_DIMM_SPARE (FERR_NF_M27ERR | \
+ FERR_NF_M28ERR)
+#define FERR_NF_THERMAL (FERR_NF_M26ERR | \
+ FERR_NF_M25ERR | \
+ FERR_NF_M24ERR | \
+ FERR_NF_M23ERR)
+#define FERR_NF_SPD_PROTOCOL (FERR_NF_M22ERR)
+#define FERR_NF_NORTH_CRC (FERR_NF_M21ERR)
+#define FERR_NF_NON_RETRY (FERR_NF_M13ERR | \
+ FERR_NF_M14ERR | \
+ FERR_NF_M15ERR)
+
+#define NERR_NF_FBD 0xA4
+#define FERR_NF_MASK (FERR_NF_UNCORRECTABLE | \
+ FERR_NF_CORRECTABLE | \
+ FERR_NF_DIMM_SPARE | \
+ FERR_NF_THERMAL | \
+ FERR_NF_SPD_PROTOCOL | \
+ FERR_NF_NORTH_CRC | \
+ FERR_NF_NON_RETRY)
+
+#define EMASK_FBD 0xA8
+#define EMASK_FBD_M28ERR 0x08000000
+#define EMASK_FBD_M27ERR 0x04000000
+#define EMASK_FBD_M26ERR 0x02000000
+#define EMASK_FBD_M25ERR 0x01000000
+#define EMASK_FBD_M24ERR 0x00800000
+#define EMASK_FBD_M23ERR 0x00400000
+#define EMASK_FBD_M22ERR 0x00200000
+#define EMASK_FBD_M21ERR 0x00100000
+#define EMASK_FBD_M20ERR 0x00080000
+#define EMASK_FBD_M19ERR 0x00040000
+#define EMASK_FBD_M18ERR 0x00020000
+#define EMASK_FBD_M17ERR 0x00010000
+
+#define EMASK_FBD_M15ERR 0x00004000
+#define EMASK_FBD_M14ERR 0x00002000
+#define EMASK_FBD_M13ERR 0x00001000
+#define EMASK_FBD_M12ERR 0x00000800
+#define EMASK_FBD_M11ERR 0x00000400
+#define EMASK_FBD_M10ERR 0x00000200
+#define EMASK_FBD_M9ERR 0x00000100
+#define EMASK_FBD_M8ERR 0x00000080
+#define EMASK_FBD_M7ERR 0x00000040
+#define EMASK_FBD_M6ERR 0x00000020
+#define EMASK_FBD_M5ERR 0x00000010
+#define EMASK_FBD_M4ERR 0x00000008
+#define EMASK_FBD_M3ERR 0x00000004
+#define EMASK_FBD_M2ERR 0x00000002
+#define EMASK_FBD_M1ERR 0x00000001
+
+#define ENABLE_EMASK_FBD_FATAL_ERRORS (EMASK_FBD_M1ERR | \
+ EMASK_FBD_M2ERR | \
+ EMASK_FBD_M3ERR)
+
+#define ENABLE_EMASK_FBD_UNCORRECTABLE (EMASK_FBD_M4ERR | \
+ EMASK_FBD_M5ERR | \
+ EMASK_FBD_M6ERR | \
+ EMASK_FBD_M7ERR | \
+ EMASK_FBD_M8ERR | \
+ EMASK_FBD_M9ERR | \
+ EMASK_FBD_M10ERR | \
+ EMASK_FBD_M11ERR | \
+ EMASK_FBD_M12ERR)
+#define ENABLE_EMASK_FBD_CORRECTABLE (EMASK_FBD_M17ERR | \
+ EMASK_FBD_M18ERR | \
+ EMASK_FBD_M19ERR | \
+ EMASK_FBD_M20ERR)
+#define ENABLE_EMASK_FBD_DIMM_SPARE (EMASK_FBD_M27ERR | \
+ EMASK_FBD_M28ERR)
+#define ENABLE_EMASK_FBD_THERMALS (EMASK_FBD_M26ERR | \
+ EMASK_FBD_M25ERR | \
+ EMASK_FBD_M24ERR | \
+ EMASK_FBD_M23ERR)
+#define ENABLE_EMASK_FBD_SPD_PROTOCOL (EMASK_FBD_M22ERR)
+#define ENABLE_EMASK_FBD_NORTH_CRC (EMASK_FBD_M21ERR)
+#define ENABLE_EMASK_FBD_NON_RETRY (EMASK_FBD_M15ERR | \
+ EMASK_FBD_M14ERR | \
+ EMASK_FBD_M13ERR)
+
+#define ENABLE_EMASK_ALL (ENABLE_EMASK_FBD_NON_RETRY | \
+ ENABLE_EMASK_FBD_NORTH_CRC | \
+ ENABLE_EMASK_FBD_SPD_PROTOCOL | \
+ ENABLE_EMASK_FBD_THERMALS | \
+ ENABLE_EMASK_FBD_DIMM_SPARE | \
+ ENABLE_EMASK_FBD_FATAL_ERRORS | \
+ ENABLE_EMASK_FBD_CORRECTABLE | \
+ ENABLE_EMASK_FBD_UNCORRECTABLE)
+
+#define ERR0_FBD 0xAC
+#define ERR1_FBD 0xB0
+#define ERR2_FBD 0xB4
+#define MCERR_FBD 0xB8
+#define NRECMEMA 0xBE
+#define NREC_BANK(x) (((x)>>12) & 0x7)
+#define NREC_RDWR(x) (((x)>>11) & 1)
+#define NREC_RANK(x) (((x)>>8) & 0x7)
+#define NRECMEMB 0xC0
+#define NREC_CAS(x) (((x)>>16) & 0xFFFFFF)
+#define NREC_RAS(x) ((x) & 0x7FFF)
+#define NRECFGLOG 0xC4
+#define NREEECFBDA 0xC8
+#define NREEECFBDB 0xCC
+#define NREEECFBDC 0xD0
+#define NREEECFBDD 0xD4
+#define NREEECFBDE 0xD8
+#define REDMEMA 0xDC
+#define RECMEMA 0xE2
+#define REC_BANK(x) (((x)>>12) & 0x7)
+#define REC_RDWR(x) (((x)>>11) & 1)
+#define REC_RANK(x) (((x)>>8) & 0x7)
+#define RECMEMB 0xE4
+#define REC_CAS(x) (((x)>>16) & 0xFFFFFF)
+#define REC_RAS(x) ((x) & 0x7FFF)
+#define RECFGLOG 0xE8
+#define RECFBDA 0xEC
+#define RECFBDB 0xF0
+#define RECFBDC 0xF4
+#define RECFBDD 0xF8
+#define RECFBDE 0xFC
+
+/* OFFSETS for Function 2 */
+
+/*
+ * Device 21,
+ * Function 0: Memory Map Branch 0
+ *
+ * Device 22,
+ * Function 0: Memory Map Branch 1
+ */
+#define PCI_DEVICE_ID_I5000_BRANCH_0 0x25F5
+#define PCI_DEVICE_ID_I5000_BRANCH_1 0x25F6
+
+#define AMB_PRESENT_0 0x64
+#define AMB_PRESENT_1 0x66
+#define MTR0 0x80
+#define MTR1 0x84
+#define MTR2 0x88
+#define MTR3 0x8C
+
+#define NUM_MTRS 4
+#define CHANNELS_PER_BRANCH (2)
+
+/* Defines to extract the vaious fields from the
+ * MTRx - Memory Technology Registers
+ */
+#define MTR_DIMMS_PRESENT(mtr) ((mtr) & (0x1 << 8))
+#define MTR_DRAM_WIDTH(mtr) ((((mtr) >> 6) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS(mtr) ((((mtr) >> 5) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS_ADDR_BITS(mtr) ((MTR_DRAM_BANKS(mtr) == 8) ? 3 : 2)
+#define MTR_DIMM_RANK(mtr) (((mtr) >> 4) & 0x1)
+#define MTR_DIMM_RANK_ADDR_BITS(mtr) (MTR_DIMM_RANK(mtr) ? 2 : 1)
+#define MTR_DIMM_ROWS(mtr) (((mtr) >> 2) & 0x3)
+#define MTR_DIMM_ROWS_ADDR_BITS(mtr) (MTR_DIMM_ROWS(mtr) + 13)
+#define MTR_DIMM_COLS(mtr) ((mtr) & 0x3)
+#define MTR_DIMM_COLS_ADDR_BITS(mtr) (MTR_DIMM_COLS(mtr) + 10)
+
+#ifdef CONFIG_EDAC_DEBUG
+static char *numrow_toString[] = {
+ "8,192 - 13 rows",
+ "16,384 - 14 rows",
+ "32,768 - 15 rows",
+ "reserved"
+};
+
+static char *numcol_toString[] = {
+ "1,024 - 10 columns",
+ "2,048 - 11 columns",
+ "4,096 - 12 columns",
+ "reserved"
+};
+#endif
+
+/* Enumeration of supported devices */
+enum i5000_chips {
+ I5000P = 0,
+ I5000V = 1, /* future */
+ I5000X = 2 /* future */
+};
+
+/* Device name and register DID (Device ID) */
+struct i5000_dev_info {
+ const char *ctl_name; /* name for this device */
+ u16 fsb_mapping_errors; /* DID for the branchmap,control */
+};
+
+/* Table of devices attributes supported by this driver */
+static const struct i5000_dev_info i5000_devs[] = {
+ [I5000P] = {
+ .ctl_name = "I5000",
+ .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I5000_DEV16,
+ },
+};
+
+struct i5000_dimm_info {
+ int megabytes; /* size, 0 means not present */
+ int dual_rank;
+};
+
+#define MAX_CHANNELS 6 /* max possible channels */
+#define MAX_CSROWS (8*2) /* max possible csrows per channel */
+
+/* driver private data structure */
+struct i5000_pvt {
+ struct pci_dev *system_address; /* 16.0 */
+ struct pci_dev *branchmap_werrors; /* 16.1 */
+ struct pci_dev *fsb_error_regs; /* 16.2 */
+ struct pci_dev *branch_0; /* 21.0 */
+ struct pci_dev *branch_1; /* 22.0 */
+
+ u16 tolm; /* top of low memory */
+ u64 ambase; /* AMB BAR */
+
+ u16 mir0, mir1, mir2;
+
+ u16 b0_mtr[NUM_MTRS]; /* Memory Technlogy Reg */
+ u16 b0_ambpresent0; /* Branch 0, Channel 0 */
+ u16 b0_ambpresent1; /* Brnach 0, Channel 1 */
+
+ u16 b1_mtr[NUM_MTRS]; /* Memory Technlogy Reg */
+ u16 b1_ambpresent0; /* Branch 1, Channel 8 */
+ u16 b1_ambpresent1; /* Branch 1, Channel 1 */
+
+ /* DIMM infomation matrix, allocating architecture maximums */
+ struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];
+
+ /* Actual values for this controller */
+ int maxch; /* Max channels */
+ int maxdimmperch; /* Max DIMMs per channel */
+};
+
+/* I5000 MCH error information retrieved from Hardware */
+struct i5000_error_info {
+
+ /* These registers are always read from the MC */
+ u32 ferr_fat_fbd; /* First Errors Fatal */
+ u32 nerr_fat_fbd; /* Next Errors Fatal */
+ u32 ferr_nf_fbd; /* First Errors Non-Fatal */
+ u32 nerr_nf_fbd; /* Next Errors Non-Fatal */
+
+ /* These registers are input ONLY if there was a Recoverable Error */
+ u32 redmemb; /* Recoverable Mem Data Error log B */
+ u16 recmema; /* Recoverable Mem Error log A */
+ u32 recmemb; /* Recoverable Mem Error log B */
+
+ /* These registers are input ONLY if there was a
+ * Non-Recoverable Error */
+ u16 nrecmema; /* Non-Recoverable Mem log A */
+ u16 nrecmemb; /* Non-Recoverable Mem log B */
+
+};
+
+static struct edac_pci_ctl_info *i5000_pci;
+
+/*
+ * i5000_get_error_info Retrieve the hardware error information from
+ * the hardware and cache it in the 'info'
+ * structure
+ */
+static void i5000_get_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info)
+{
+ struct i5000_pvt *pvt;
+ u32 value;
+
+ pvt = mci->pvt_info;
+
+ /* read in the 1st FATAL error register */
+ pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value);
+
+ /* Mask only the bits that the doc says are valid
+ */
+ value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK);
+
+ /* If there is an error, then read in the */
+ /* NEXT FATAL error register and the Memory Error Log Register A */
+ if (value & FERR_FAT_MASK) {
+ info->ferr_fat_fbd = value;
+
+ /* harvest the various error data we need */
+ pci_read_config_dword(pvt->branchmap_werrors,
+ NERR_FAT_FBD, &info->nerr_fat_fbd);
+ pci_read_config_word(pvt->branchmap_werrors,
+ NRECMEMA, &info->nrecmema);
+ pci_read_config_word(pvt->branchmap_werrors,
+ NRECMEMB, &info->nrecmemb);
+
+ /* Clear the error bits, by writing them back */
+ pci_write_config_dword(pvt->branchmap_werrors,
+ FERR_FAT_FBD, value);
+ } else {
+ info->ferr_fat_fbd = 0;
+ info->nerr_fat_fbd = 0;
+ info->nrecmema = 0;
+ info->nrecmemb = 0;
+ }
+
+ /* read in the 1st NON-FATAL error register */
+ pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value);
+
+ /* If there is an error, then read in the 1st NON-FATAL error
+ * register as well */
+ if (value & FERR_NF_MASK) {
+ info->ferr_nf_fbd = value;
+
+ /* harvest the various error data we need */
+ pci_read_config_dword(pvt->branchmap_werrors,
+ NERR_NF_FBD, &info->nerr_nf_fbd);
+ pci_read_config_word(pvt->branchmap_werrors,
+ RECMEMA, &info->recmema);
+ pci_read_config_dword(pvt->branchmap_werrors,
+ RECMEMB, &info->recmemb);
+ pci_read_config_dword(pvt->branchmap_werrors,
+ REDMEMB, &info->redmemb);
+
+ /* Clear the error bits, by writing them back */
+ pci_write_config_dword(pvt->branchmap_werrors,
+ FERR_NF_FBD, value);
+ } else {
+ info->ferr_nf_fbd = 0;
+ info->nerr_nf_fbd = 0;
+ info->recmema = 0;
+ info->recmemb = 0;
+ info->redmemb = 0;
+ }
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ * struct i5000_error_info *info,
+ * int handle_errors);
+ *
+ * handle the Intel FATAL errors, if any
+ */
+static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info,
+ int handle_errors)
+{
+ char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+ u32 allErrors;
+ int branch;
+ int channel;
+ int bank;
+ int rank;
+ int rdwr;
+ int ras, cas;
+
+ /* mask off the Error bits that are possible */
+ allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK);
+ if (!allErrors)
+ return; /* if no error, return now */
+
+ /* ONLY ONE of the possible error bits will be set, as per the docs */
+ i5000_mc_printk(mci, KERN_ERR,
+ "FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n",
+ allErrors);
+
+ branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
+ channel = branch;
+
+ /* Use the NON-Recoverable macros to extract data */
+ bank = NREC_BANK(info->nrecmema);
+ rank = NREC_RANK(info->nrecmema);
+ rdwr = NREC_RDWR(info->nrecmema);
+ ras = NREC_RAS(info->nrecmemb);
+ cas = NREC_CAS(info->nrecmemb);
+
+ debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d "
+ "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+ rank, channel, channel + 1, branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas);
+
+ /* Only 1 bit will be on */
+ if (allErrors & FERR_FAT_M1ERR) {
+ i5000_mc_printk(mci, KERN_ERR,
+ "Alert on non-redundant retry or fast "
+ "reset timeout\n");
+
+ } else if (allErrors & FERR_FAT_M2ERR) {
+ i5000_mc_printk(mci, KERN_ERR,
+ "Northbound CRC error on non-redundant "
+ "retry\n");
+
+ } else if (allErrors & FERR_FAT_M3ERR) {
+ i5000_mc_printk(mci, KERN_ERR,
+ ">Tmid Thermal event with intelligent "
+ "throttling disabled\n");
+ }
+
+ /* Form out message */
+ snprintf(msg, sizeof(msg),
+ "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d "
+ "FATAL Err=0x%x)",
+ branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+ allErrors);
+
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ * struct i5000_error_info *info,
+ * int handle_errors);
+ *
+ * handle the Intel NON-FATAL errors, if any
+ */
+static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info,
+ int handle_errors)
+{
+ char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+ u32 allErrors;
+ u32 ue_errors;
+ u32 ce_errors;
+ u32 misc_errors;
+ int branch;
+ int channel;
+ int bank;
+ int rank;
+ int rdwr;
+ int ras, cas;
+
+ /* mask off the Error bits that are possible */
+ allErrors = (info->ferr_nf_fbd & FERR_NF_MASK);
+ if (!allErrors)
+ return; /* if no error, return now */
+
+ /* ONLY ONE of the possible error bits will be set, as per the docs */
+ i5000_mc_printk(mci, KERN_WARNING,
+ "NON-FATAL ERRORS Found!!! 1st NON-FATAL Err "
+ "Reg= 0x%x\n", allErrors);
+
+ ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
+ if (ue_errors) {
+ debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
+
+ branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+ channel = branch;
+ bank = NREC_BANK(info->nrecmema);
+ rank = NREC_RANK(info->nrecmema);
+ rdwr = NREC_RDWR(info->nrecmema);
+ ras = NREC_RAS(info->nrecmemb);
+ cas = NREC_CAS(info->nrecmemb);
+
+ debugf0
+ ("\t\tCSROW= %d Channels= %d,%d (Branch= %d "
+ "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+ rank, channel, channel + 1, branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas);
+
+ /* Form out message */
+ snprintf(msg, sizeof(msg),
+ "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+ "CAS=%d, UE Err=0x%x)",
+ branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+ ue_errors);
+
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+ }
+
+ /* Check correctable errors */
+ ce_errors = allErrors & FERR_NF_CORRECTABLE;
+ if (ce_errors) {
+ debugf0("\tCorrected bits= 0x%x\n", ce_errors);
+
+ branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+
+ channel = 0;
+ if (REC_ECC_LOCATOR_ODD(info->redmemb))
+ channel = 1;
+
+ /* Convert channel to be based from zero, instead of
+ * from branch base of 0 */
+ channel += branch;
+
+ bank = REC_BANK(info->recmema);
+ rank = REC_RANK(info->recmema);
+ rdwr = REC_RDWR(info->recmema);
+ ras = REC_RAS(info->recmemb);
+ cas = REC_CAS(info->recmemb);
+
+ debugf0("\t\tCSROW= %d Channel= %d (Branch %d "
+ "DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+ rank, channel, branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas);
+
+ /* Form out message */
+ snprintf(msg, sizeof(msg),
+ "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+ "CAS=%d, CE Err=0x%x)", branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas, ce_errors);
+
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ce(mci, rank, channel, msg);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_THERMAL;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING, "\tTHERMAL Error, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_NON_RETRY;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING, "\tNON-Retry Errors, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_NORTH_CRC;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING,
+ "\tNORTHBOUND CRC Error, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_SPD_PROTOCOL;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING,
+ "\tSPD Protocol Error, bits= 0x%x\n",
+ misc_errors);
+ }
+
+ /* See if any of the thermal errors have fired */
+ misc_errors = allErrors & FERR_NF_DIMM_SPARE;
+ if (misc_errors) {
+ i5000_printk(KERN_WARNING, "\tDIMM-Spare Error, bits= 0x%x\n",
+ misc_errors);
+ }
+}
+
+/*
+ * i5000_process_error_info Process the error info that is
+ * in the 'info' structure, previously retrieved from hardware
+ */
+static void i5000_process_error_info(struct mem_ctl_info *mci,
+ struct i5000_error_info *info,
+ int handle_errors)
+{
+ /* First handle any fatal errors that occurred */
+ i5000_process_fatal_error_info(mci, info, handle_errors);
+
+ /* now handle any non-fatal errors that occurred */
+ i5000_process_nonfatal_error_info(mci, info, handle_errors);
+}
+
+/*
+ * i5000_clear_error Retrieve any error from the hardware
+ * but do NOT process that error.
+ * Used for 'clearing' out of previous errors
+ * Called by the Core module.
+ */
+static void i5000_clear_error(struct mem_ctl_info *mci)
+{
+ struct i5000_error_info info;
+
+ i5000_get_error_info(mci, &info);
+}
+
+/*
+ * i5000_check_error Retrieve and process errors reported by the
+ * hardware. Called by the Core module.
+ */
+static void i5000_check_error(struct mem_ctl_info *mci)
+{
+ struct i5000_error_info info;
+ debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+ i5000_get_error_info(mci, &info);
+ i5000_process_error_info(mci, &info, 1);
+}
+
+/*
+ * i5000_get_devices Find and perform 'get' operation on the MCH's
+ * device/functions we want to reference for this driver
+ *
+ * Need to 'get' device 16 func 1 and func 2
+ */
+static int i5000_get_devices(struct mem_ctl_info *mci, int dev_idx)
+{
+ //const struct i5000_dev_info *i5000_dev = &i5000_devs[dev_idx];
+ struct i5000_pvt *pvt;
+ struct pci_dev *pdev;
+
+ pvt = mci->pvt_info;
+
+ /* Attempt to 'get' the MCH register we want */
+ pdev = NULL;
+ while (1) {
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+ /* End of list, leave */
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "'system address,Process Bus' "
+ "device not found:"
+ "vendor 0x%x device 0x%x FUNC 1 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+ return 1;
+ }
+
+ /* Scan for device 16 func 1 */
+ if (PCI_FUNC(pdev->devfn) == 1)
+ break;
+ }
+
+ pvt->branchmap_werrors = pdev;
+
+ /* Attempt to 'get' the MCH register we want */
+ pdev = NULL;
+ while (1) {
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "MC: 'branchmap,control,errors' "
+ "device not found:"
+ "vendor 0x%x device 0x%x Func 2 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+ pci_dev_put(pvt->branchmap_werrors);
+ return 1;
+ }
+
+ /* Scan for device 16 func 1 */
+ if (PCI_FUNC(pdev->devfn) == 2)
+ break;
+ }
+
+ pvt->fsb_error_regs = pdev;
+
+ debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->system_address),
+ pvt->system_address->vendor, pvt->system_address->device);
+ debugf1("Branchmap, control and errors - PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->branchmap_werrors),
+ pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
+ debugf1("FSB Error Regs - PCI Bus ID: %s %x:%x\n",
+ pci_name(pvt->fsb_error_regs),
+ pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+
+ pdev = NULL;
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_I5000_BRANCH_0, pdev);
+
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "MC: 'BRANCH 0' device not found:"
+ "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_I5000_BRANCH_0);
+
+ pci_dev_put(pvt->branchmap_werrors);
+ pci_dev_put(pvt->fsb_error_regs);
+ return 1;
+ }
+
+ pvt->branch_0 = pdev;
+
+ /* If this device claims to have more than 2 channels then
+ * fetch Branch 1's information
+ */
+ if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+ pdev = NULL;
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_I5000_BRANCH_1, pdev);
+
+ if (pdev == NULL) {
+ i5000_printk(KERN_ERR,
+ "MC: 'BRANCH 1' device not found:"
+ "vendor 0x%x device 0x%x Func 0 "
+ "(broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_I5000_BRANCH_1);
+
+ pci_dev_put(pvt->branchmap_werrors);
+ pci_dev_put(pvt->fsb_error_regs);
+ pci_dev_put(pvt->branch_0);
+ return 1;
+ }
+
+ pvt->branch_1 = pdev;
+ }
+
+ return 0;
+}
+
+/*
+ * i5000_put_devices 'put' all the devices that we have
+ * reserved via 'get'
+ */
+static void i5000_put_devices(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+
+ pvt = mci->pvt_info;
+
+ pci_dev_put(pvt->branchmap_werrors); /* FUNC 1 */
+ pci_dev_put(pvt->fsb_error_regs); /* FUNC 2 */
+ pci_dev_put(pvt->branch_0); /* DEV 21 */
+
+ /* Only if more than 2 channels do we release the second branch */
+ if (pvt->maxch >= CHANNELS_PER_BRANCH)
+ pci_dev_put(pvt->branch_1); /* DEV 22 */
+}
+
+/*
+ * determine_amb_resent
+ *
+ * the information is contained in NUM_MTRS different registers
+ * determineing which of the NUM_MTRS requires knowing
+ * which channel is in question
+ *
+ * 2 branches, each with 2 channels
+ * b0_ambpresent0 for channel '0'
+ * b0_ambpresent1 for channel '1'
+ * b1_ambpresent0 for channel '2'
+ * b1_ambpresent1 for channel '3'
+ */
+static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel)
+{
+ int amb_present;
+
+ if (channel < CHANNELS_PER_BRANCH) {
+ if (channel & 0x1)
+ amb_present = pvt->b0_ambpresent1;
+ else
+ amb_present = pvt->b0_ambpresent0;
+ } else {
+ if (channel & 0x1)
+ amb_present = pvt->b1_ambpresent1;
+ else
+ amb_present = pvt->b1_ambpresent0;
+ }
+
+ return amb_present;
+}
+
+/*
+ * determine_mtr(pvt, csrow, channel)
+ *
+ * return the proper MTR register as determine by the csrow and channel desired
+ */
+static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel)
+{
+ int mtr;
+
+ if (channel < CHANNELS_PER_BRANCH)
+ mtr = pvt->b0_mtr[csrow >> 1];
+ else
+ mtr = pvt->b1_mtr[csrow >> 1];
+
+ return mtr;
+}
+
+/*
+ */
+static void decode_mtr(int slot_row, u16 mtr)
+{
+ int ans;
+
+ ans = MTR_DIMMS_PRESENT(mtr);
+
+ debugf2("\tMTR%d=0x%x: DIMMs are %s\n", slot_row, mtr,
+ ans ? "Present" : "NOT Present");
+ if (!ans)
+ return;
+
+ debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+ debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+ debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
+ debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
+ debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+}
+
+static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
+ struct i5000_dimm_info *dinfo)
+{
+ int mtr;
+ int amb_present_reg;
+ int addrBits;
+
+ mtr = determine_mtr(pvt, csrow, channel);
+ if (MTR_DIMMS_PRESENT(mtr)) {
+ amb_present_reg = determine_amb_present_reg(pvt, channel);
+
+ /* Determine if there is a DIMM present in this DIMM slot */
+ if (amb_present_reg & (1 << (csrow >> 1))) {
+ dinfo->dual_rank = MTR_DIMM_RANK(mtr);
+
+ if (!((dinfo->dual_rank == 0) &&
+ ((csrow & 0x1) == 0x1))) {
+ /* Start with the number of bits for a Bank
+ * on the DRAM */
+ addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
+ /* Add thenumber of ROW bits */
+ addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
+ /* add the number of COLUMN bits */
+ addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
+
+ addrBits += 6; /* add 64 bits per DIMM */
+ addrBits -= 20; /* divide by 2^^20 */
+ addrBits -= 3; /* 8 bits per bytes */
+
+ dinfo->megabytes = 1 << addrBits;
+ }
+ }
+ }
+}
+
+/*
+ * calculate_dimm_size
+ *
+ * also will output a DIMM matrix map, if debug is enabled, for viewing
+ * how the DIMMs are populated
+ */
+static void calculate_dimm_size(struct i5000_pvt *pvt)
+{
+ struct i5000_dimm_info *dinfo;
+ int csrow, max_csrows;
+ char *p, *mem_buffer;
+ int space, n;
+ int channel;
+
+ /* ================= Generate some debug output ================= */
+ space = PAGE_SIZE;
+ mem_buffer = p = kmalloc(space, GFP_KERNEL);
+ if (p == NULL) {
+ i5000_printk(KERN_ERR, "MC: %s:%s() kmalloc() failed\n",
+ __FILE__, __func__);
+ return;
+ }
+
+ n = snprintf(p, space, "\n");
+ p += n;
+ space -= n;
+
+ /* Scan all the actual CSROWS (which is # of DIMMS * 2)
+ * and calculate the information for each DIMM
+ * Start with the highest csrow first, to display it first
+ * and work toward the 0th csrow
+ */
+ max_csrows = pvt->maxdimmperch * 2;
+ for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
+
+ /* on an odd csrow, first output a 'boundary' marker,
+ * then reset the message buffer */
+ if (csrow & 0x1) {
+ n = snprintf(p, space, "---------------------------"
+ "--------------------------------");
+ p += n;
+ space -= n;
+ debugf2("%s\n", mem_buffer);
+ p = mem_buffer;
+ space = PAGE_SIZE;
+ }
+ n = snprintf(p, space, "csrow %2d ", csrow);
+ p += n;
+ space -= n;
+
+ for (channel = 0; channel < pvt->maxch; channel++) {
+ dinfo = &pvt->dimm_info[csrow][channel];
+ handle_channel(pvt, csrow, channel, dinfo);
+ n = snprintf(p, space, "%4d MB | ", dinfo->megabytes);
+ p += n;
+ space -= n;
+ }
+ n = snprintf(p, space, "\n");
+ p += n;
+ space -= n;
+ }
+
+ /* Output the last bottom 'boundary' marker */
+ n = snprintf(p, space, "---------------------------"
+ "--------------------------------\n");
+ p += n;
+ space -= n;
+
+ /* now output the 'channel' labels */
+ n = snprintf(p, space, " ");
+ p += n;
+ space -= n;
+ for (channel = 0; channel < pvt->maxch; channel++) {
+ n = snprintf(p, space, "channel %d | ", channel);
+ p += n;
+ space -= n;
+ }
+ n = snprintf(p, space, "\n");
+ p += n;
+ space -= n;
+
+ /* output the last message and free buffer */
+ debugf2("%s\n", mem_buffer);
+ kfree(mem_buffer);
+}
+
+/*
+ * i5000_get_mc_regs read in the necessary registers and
+ * cache locally
+ *
+ * Fills in the private data members
+ */
+static void i5000_get_mc_regs(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+ u32 actual_tolm;
+ u16 limit;
+ int slot_row;
+ int maxch;
+ int maxdimmperch;
+ int way0, way1;
+
+ pvt = mci->pvt_info;
+
+ pci_read_config_dword(pvt->system_address, AMBASE,
+ (u32 *) & pvt->ambase);
+ pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
+ ((u32 *) & pvt->ambase) + sizeof(u32));
+
+ maxdimmperch = pvt->maxdimmperch;
+ maxch = pvt->maxch;
+
+ debugf2("AMBASE= 0x%lx MAXCH= %d MAX-DIMM-Per-CH= %d\n",
+ (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+
+ /* Get the Branch Map regs */
+ pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
+ pvt->tolm >>= 12;
+ debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
+ pvt->tolm);
+
+ actual_tolm = pvt->tolm << 28;
+ debugf2("Actual TOLM byte addr=%u (0x%x)\n", actual_tolm, actual_tolm);
+
+ pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
+ pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
+ pci_read_config_word(pvt->branchmap_werrors, MIR2, &pvt->mir2);
+
+ /* Get the MIR[0-2] regs */
+ limit = (pvt->mir0 >> 4) & 0x0FFF;
+ way0 = pvt->mir0 & 0x1;
+ way1 = pvt->mir0 & 0x2;
+ debugf2("MIR0: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
+ limit = (pvt->mir1 >> 4) & 0x0FFF;
+ way0 = pvt->mir1 & 0x1;
+ way1 = pvt->mir1 & 0x2;
+ debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
+ limit = (pvt->mir2 >> 4) & 0x0FFF;
+ way0 = pvt->mir2 & 0x1;
+ way1 = pvt->mir2 & 0x2;
+ debugf2("MIR2: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
+
+ /* Get the MTR[0-3] regs */
+ for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+ int where = MTR0 + (slot_row * sizeof(u32));
+
+ pci_read_config_word(pvt->branch_0, where,
+ &pvt->b0_mtr[slot_row]);
+
+ debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
+ pvt->b0_mtr[slot_row]);
+
+ if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+ pci_read_config_word(pvt->branch_1, where,
+ &pvt->b1_mtr[slot_row]);
+ debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row,
+ where, pvt->b0_mtr[slot_row]);
+ } else {
+ pvt->b1_mtr[slot_row] = 0;
+ }
+ }
+
+ /* Read and dump branch 0's MTRs */
+ debugf2("\nMemory Technology Registers:\n");
+ debugf2(" Branch 0:\n");
+ for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+ decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
+ }
+ pci_read_config_word(pvt->branch_0, AMB_PRESENT_0,
+ &pvt->b0_ambpresent0);
+ debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+ pci_read_config_word(pvt->branch_0, AMB_PRESENT_1,
+ &pvt->b0_ambpresent1);
+ debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+
+ /* Only if we have 2 branchs (4 channels) */
+ if (pvt->maxch < CHANNELS_PER_BRANCH) {
+ pvt->b1_ambpresent0 = 0;
+ pvt->b1_ambpresent1 = 0;
+ } else {
+ /* Read and dump branch 1's MTRs */
+ debugf2(" Branch 1:\n");
+ for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+ decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
+ }
+ pci_read_config_word(pvt->branch_1, AMB_PRESENT_0,
+ &pvt->b1_ambpresent0);
+ debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
+ pvt->b1_ambpresent0);
+ pci_read_config_word(pvt->branch_1, AMB_PRESENT_1,
+ &pvt->b1_ambpresent1);
+ debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
+ pvt->b1_ambpresent1);
+ }
+
+ /* Go and determine the size of each DIMM and place in an
+ * orderly matrix */
+ calculate_dimm_size(pvt);
+}
+
+/*
+ * i5000_init_csrows Initialize the 'csrows' table within
+ * the mci control structure with the
+ * addressing of memory.
+ *
+ * return:
+ * 0 success
+ * 1 no actual memory found on this MC
+ */
+static int i5000_init_csrows(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+ struct csrow_info *p_csrow;
+ int empty, channel_count;
+ int max_csrows;
+ int mtr;
+ int csrow_megs;
+ int channel;
+ int csrow;
+
+ pvt = mci->pvt_info;
+
+ channel_count = pvt->maxch;
+ max_csrows = pvt->maxdimmperch * 2;
+
+ empty = 1; /* Assume NO memory */
+
+ for (csrow = 0; csrow < max_csrows; csrow++) {
+ p_csrow = &mci->csrows[csrow];
+
+ p_csrow->csrow_idx = csrow;
+
+ /* use branch 0 for the basis */
+ mtr = pvt->b0_mtr[csrow >> 1];
+
+ /* if no DIMMS on this row, continue */
+ if (!MTR_DIMMS_PRESENT(mtr))
+ continue;
+
+ /* FAKE OUT VALUES, FIXME */
+ p_csrow->first_page = 0 + csrow * 20;
+ p_csrow->last_page = 9 + csrow * 20;
+ p_csrow->page_mask = 0xFFF;
+
+ p_csrow->grain = 8;
+
+ csrow_megs = 0;
+ for (channel = 0; channel < pvt->maxch; channel++) {
+ csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
+ }
+
+ p_csrow->nr_pages = csrow_megs << 8;
+
+ /* Assume DDR2 for now */
+ p_csrow->mtype = MEM_FB_DDR2;
+
+ /* ask what device type on this row */
+ if (MTR_DRAM_WIDTH(mtr))
+ p_csrow->dtype = DEV_X8;
+ else
+ p_csrow->dtype = DEV_X4;
+
+ p_csrow->edac_mode = EDAC_S8ECD8ED;
+
+ empty = 0;
+ }
+
+ return empty;
+}
+
+/*
+ * i5000_enable_error_reporting
+ * Turn on the memory reporting features of the hardware
+ */
+static void i5000_enable_error_reporting(struct mem_ctl_info *mci)
+{
+ struct i5000_pvt *pvt;
+ u32 fbd_error_mask;
+
+ pvt = mci->pvt_info;
+
+ /* Read the FBD Error Mask Register */
+ pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+ &fbd_error_mask);
+
+ /* Enable with a '0' */
+ fbd_error_mask &= ~(ENABLE_EMASK_ALL);
+
+ pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+ fbd_error_mask);
+}
+
+/*
+ * i5000_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels)
+ *
+ * ask the device how many channels are present and how many CSROWS
+ * as well
+ */
+static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
+ int *num_dimms_per_channel,
+ int *num_channels)
+{
+ u8 value;
+
+ /* Need to retrieve just how many channels and dimms per channel are
+ * supported on this memory controller
+ */
+ pci_read_config_byte(pdev, MAXDIMMPERCH, &value);
+ *num_dimms_per_channel = (int)value *2;
+
+ pci_read_config_byte(pdev, MAXCH, &value);
+ *num_channels = (int)value;
+}
+
+/*
+ * i5000_probe1 Probe for ONE instance of device to see if it is
+ * present.
+ * return:
+ * 0 for FOUND a device
+ * < 0 for error code
+ */
+static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ struct mem_ctl_info *mci;
+ struct i5000_pvt *pvt;
+ int num_channels;
+ int num_dimms_per_channel;
+ int num_csrows;
+
+ debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+ __func__,
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+ /* We only are looking for func 0 of the set */
+ if (PCI_FUNC(pdev->devfn) != 0)
+ return -ENODEV;
+
+ /* make sure error reporting method is sane */
+ switch (edac_op_state) {
+ case EDAC_OPSTATE_POLL:
+ case EDAC_OPSTATE_NMI:
+ break;
+ default:
+ edac_op_state = EDAC_OPSTATE_POLL;
+ break;
+ }
+
+ /* Ask the devices for the number of CSROWS and CHANNELS so
+ * that we can calculate the memory resources, etc
+ *
+ * The Chipset will report what it can handle which will be greater
+ * or equal to what the motherboard manufacturer will implement.
+ *
+ * As we don't have a motherboard identification routine to determine
+ * actual number of slots/dimms per channel, we thus utilize the
+ * resource as specified by the chipset. Thus, we might have
+ * have more DIMMs per channel than actually on the mobo, but this
+ * allows the driver to support upto the chipset max, without
+ * some fancy mobo determination.
+ */
+ i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel,
+ &num_channels);
+ num_csrows = num_dimms_per_channel * 2;
+
+ debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n",
+ __func__, num_channels, num_dimms_per_channel, num_csrows);
+
+ /* allocate a new MC control structure */
+ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+ mci->dev = &pdev->dev; /* record ptr to the generic device */
+
+ pvt = mci->pvt_info;
+ pvt->system_address = pdev; /* Record this device in our private */
+ pvt->maxch = num_channels;
+ pvt->maxdimmperch = num_dimms_per_channel;
+
+ /* 'get' the pci devices we want to reserve for our use */
+ if (i5000_get_devices(mci, dev_idx))
+ goto fail0;
+
+ /* Time to get serious */
+ i5000_get_mc_regs(mci); /* retrieve the hardware registers */
+
+ mci->mc_idx = 0;
+ mci->mtype_cap = MEM_FLAG_FB_DDR2;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE;
+ mci->edac_cap = EDAC_FLAG_NONE;
+ mci->mod_name = "i5000_edac.c";
+ mci->mod_ver = I5000_REVISION;
+ mci->ctl_name = i5000_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
+ mci->ctl_page_to_phys = NULL;
+
+ /* Set the function pointer to an actual operation function */
+ mci->edac_check = i5000_check_error;
+
+ /* initialize the MC control structure 'csrows' table
+ * with the mapping and control information */
+ if (i5000_init_csrows(mci)) {
+ debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
+ " because i5000_init_csrows() returned nonzero "
+ "value\n");
+ mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
+ } else {
+ debugf1("MC: Enable error reporting now\n");
+ i5000_enable_error_reporting(mci);
+ }
+
+ /* add this new MC control structure to EDAC's list of MCs */
+ if (edac_mc_add_mc(mci)) {
+ debugf0("MC: " __FILE__
+ ": %s(): failed edac_mc_add_mc()\n", __func__);
+ /* FIXME: perhaps some code should go here that disables error
+ * reporting if we just enabled it
+ */
+ goto fail1;
+ }
+
+ i5000_clear_error(mci);
+
+ /* allocating generic PCI control info */
+ i5000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i5000_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ return 0;
+
+ /* Error exit unwinding stack */
+fail1:
+
+ i5000_put_devices(mci);
+
+fail0:
+ edac_mc_free(mci);
+ return -ENODEV;
+}
+
+/*
+ * i5000_init_one constructor for one instance of device
+ *
+ * returns:
+ * negative on error
+ * count (>= 0)
+ */
+static int __devinit i5000_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int rc;
+
+ debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* wake up device */
+ rc = pci_enable_device(pdev);
+ if (rc == -EIO)
+ return rc;
+
+ /* now probe and enable the device */
+ return i5000_probe1(pdev, id->driver_data);
+}
+
+/*
+ * i5000_remove_one destructor for one instance of device
+ *
+ */
+static void __devexit i5000_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+
+ if (i5000_pci)
+ edac_pci_release_generic_ctl(i5000_pci);
+
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+ return;
+
+ /* retrieve references to resources, and free those resources */
+ i5000_put_devices(mci);
+
+ edac_mc_free(mci);
+}
+
+/*
+ * pci_device_id table for which devices we are looking for
+ *
+ * The "E500P" device is the first device supported.
+ */
+static const struct pci_device_id i5000_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),
+ .driver_data = I5000P},
+
+ {0,} /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i5000_pci_tbl);
+
+/*
+ * i5000_driver pci_driver structure for this module
+ *
+ */
+static struct pci_driver i5000_driver = {
+ .name = __stringify(KBUILD_BASENAME),
+ .probe = i5000_init_one,
+ .remove = __devexit_p(i5000_remove_one),
+ .id_table = i5000_pci_tbl,
+};
+
+/*
+ * i5000_init Module entry function
+ * Try to initialize this module for its devices
+ */
+static int __init i5000_init(void)
+{
+ int pci_rc;
+
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+ pci_rc = pci_register_driver(&i5000_driver);
+
+ return (pci_rc < 0) ? pci_rc : 0;
+}
+
+/*
+ * i5000_exit() Module exit function
+ * Unregister the driver
+ */
+static void __exit i5000_exit(void)
+{
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+ pci_unregister_driver(&i5000_driver);
+}
+
+module_init(i5000_init);
+module_exit(i5000_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR
+ ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>");
+MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - "
+ I5000_REVISION);
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
new file mode 100644
index 000000000000..83bfe37c4bbb
--- /dev/null
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -0,0 +1,402 @@
+/*
+ * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel
+ * module (C) 2006 Tim Small
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License.
+ *
+ * Written by Tim Small <tim@buttersideup.com>, based on work by Linux
+ * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and
+ * others.
+ *
+ * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
+ *
+ * Written with reference to 82443BX Host Bridge Datasheet:
+ * http://www.intel.com/design/chipsets/440/documentation.htm
+ * references to this document given in [].
+ *
+ * This module doesn't support the 440LX, but it may be possible to
+ * make it do so (the 440LX's register definitions are different, but
+ * not completely so - I haven't studied them in enough detail to know
+ * how easy this would be).
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82443_REVISION "0.1"
+
+#define EDAC_MOD_STR "i82443bxgx_edac"
+
+/* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory
+ * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory
+ * rows" "The 82443BX supports multiple-bit error detection and
+ * single-bit error correction when ECC mode is enabled and
+ * single/multi-bit error detection when correction is disabled.
+ * During writes to the DRAM, the 82443BX generates ECC for the data
+ * on a QWord basis. Partial QWord writes require a read-modify-write
+ * cycle when ECC is enabled."
+*/
+
+/* "Additionally, the 82443BX ensures that the data is corrected in
+ * main memory so that accumulation of errors is prevented. Another
+ * error within the same QWord would result in a double-bit error
+ * which is unrecoverable. This is known as hardware scrubbing since
+ * it requires no software intervention to correct the data in memory."
+ */
+
+/* [Also see page 100 (section 4.3), "DRAM Interface"]
+ * [Also see page 112 (section 4.6.1.4), ECC]
+ */
+
+#define I82443BXGX_NR_CSROWS 8
+#define I82443BXGX_NR_CHANS 1
+#define I82443BXGX_NR_DIMMS 4
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_NBXCFG 0x50 /* 32bit register starting at this PCI
+ * config space offset */
+#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24 /* Array of bits, zero if
+ * row is non-ECC */
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12 /* 2 bits,00=100MHz,10=66 MHz */
+
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7 /* 2 bits: */
+#define I82443BXGX_NBXCFG_INTEGRITY_NONE 0x0 /* 00 = Non-ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_EC 0x1 /* 01 = EC (only) */
+#define I82443BXGX_NBXCFG_INTEGRITY_ECC 0x2 /* 10 = ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB 0x3 /* 11 = ECC + HW Scrub */
+
+#define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE 6
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_EAP 0x80 /* 32bit register starting at this PCI
+ * config space offset, Error Address
+ * Pointer Register */
+#define I82443BXGX_EAP_OFFSET_EAP 12 /* High 20 bits of error address */
+#define I82443BXGX_EAP_OFFSET_MBE BIT(1) /* Err at EAP was multi-bit (W1TC) */
+#define I82443BXGX_EAP_OFFSET_SBE BIT(0) /* Err at EAP was single-bit (W1TC) */
+
+#define I82443BXGX_ERRCMD 0x90 /* 8bit register starting at this PCI
+ * config space offset. */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1) /* 1 = enable */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0) /* 1 = enable */
+
+#define I82443BXGX_ERRSTS 0x91 /* 16bit register starting at this PCI
+ * config space offset. */
+#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5 /* 3 bits - first err row multibit */
+#define I82443BXGX_ERRSTS_OFFSET_MEF BIT(4) /* 1 = MBE occurred */
+#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1 /* 3 bits - first err row singlebit */
+#define I82443BXGX_ERRSTS_OFFSET_SEF BIT(0) /* 1 = SBE occurred */
+
+#define I82443BXGX_DRAMC 0x57 /* 8bit register starting at this PCI
+ * config space offset. */
+#define I82443BXGX_DRAMC_OFFSET_DT 3 /* 2 bits, DRAM Type */
+#define I82443BXGX_DRAMC_DRAM_IS_EDO 0 /* 00 = EDO */
+#define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1 /* 01 = SDRAM */
+#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2 /* 10 = Registered SDRAM */
+
+#define I82443BXGX_DRB 0x60 /* 8x 8bit registers starting at this PCI
+ * config space offset. */
+
+/* FIXME - don't poll when ECC disabled? */
+
+struct i82443bxgx_edacmc_error_info {
+ u32 eap;
+};
+
+static struct edac_pci_ctl_info *i82443bxgx_pci;
+
+static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
+ struct i82443bxgx_edacmc_error_info
+ *info)
+{
+ struct pci_dev *pdev;
+ pdev = to_pci_dev(mci->dev);
+ pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
+ if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
+ /* Clear error to allow next error to be reported [p.61] */
+ pci_write_bits32(pdev, I82443BXGX_EAP,
+ I82443BXGX_EAP_OFFSET_SBE,
+ I82443BXGX_EAP_OFFSET_SBE);
+
+ if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
+ /* Clear error to allow next error to be reported [p.61] */
+ pci_write_bits32(pdev, I82443BXGX_EAP,
+ I82443BXGX_EAP_OFFSET_MBE,
+ I82443BXGX_EAP_OFFSET_MBE);
+}
+
+static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
+ struct
+ i82443bxgx_edacmc_error_info
+ *info, int handle_errors)
+{
+ int error_found = 0;
+ u32 eapaddr, page, pageoffset;
+
+ /* bits 30:12 hold the 4kb block in which the error occurred
+ * [p.61] */
+ eapaddr = (info->eap & 0xfffff000);
+ page = eapaddr >> PAGE_SHIFT;
+ pageoffset = eapaddr - (page << PAGE_SHIFT);
+
+ if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
+ error_found = 1;
+ if (handle_errors)
+ edac_mc_handle_ce(mci, page, pageoffset,
+ /* 440BX/GX don't make syndrome information
+ * available */
+ 0, edac_mc_find_csrow_by_page(mci, page), 0,
+ mci->ctl_name);
+ }
+
+ if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
+ error_found = 1;
+ if (handle_errors)
+ edac_mc_handle_ue(mci, page, pageoffset,
+ edac_mc_find_csrow_by_page(mci, page),
+ mci->ctl_name);
+ }
+
+ return error_found;
+}
+
+static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
+{
+ struct i82443bxgx_edacmc_error_info info;
+
+ debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+ i82443bxgx_edacmc_get_error_info(mci, &info);
+ i82443bxgx_edacmc_process_error_info(mci, &info, 1);
+}
+
+static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
+ struct pci_dev *pdev,
+ enum edac_type edac_mode,
+ enum mem_type mtype)
+{
+ struct csrow_info *csrow;
+ int index;
+ u8 drbar, dramc;
+ u32 row_base, row_high_limit, row_high_limit_last;
+
+ pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+ row_high_limit_last = 0;
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+ pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
+ debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n",
+ mci->mc_idx, __func__, index, drbar);
+ row_high_limit = ((u32) drbar << 23);
+ /* find the DRAM Chip Select Base address and mask */
+ debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
+ "Boundry Address=%#0x, Last = %#0x \n",
+ mci->mc_idx, __func__, index, row_high_limit,
+ row_high_limit_last);
+
+ /* 440GX goes to 2GB, represented with a DRB of 0. */
+ if (row_high_limit_last && !row_high_limit)
+ row_high_limit = 1UL << 31;
+
+ /* This row is empty [p.49] */
+ if (row_high_limit == row_high_limit_last)
+ continue;
+ row_base = row_high_limit_last;
+ csrow->first_page = row_base >> PAGE_SHIFT;
+ csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
+ csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
+ /* EAP reports in 4kilobyte granularity [61] */
+ csrow->grain = 1 << 12;
+ csrow->mtype = mtype;
+ /* I don't think 440BX can tell you device type? FIXME? */
+ csrow->dtype = DEV_UNKNOWN;
+ /* Mode is global to all rows on 440BX */
+ csrow->edac_mode = edac_mode;
+ row_high_limit_last = row_high_limit;
+ }
+}
+
+static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ struct mem_ctl_info *mci;
+ u8 dramc;
+ u32 nbxcfg, ecc_mode;
+ enum mem_type mtype;
+ enum edac_type edac_mode;
+
+ debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* Something is really hosed if PCI config space reads from
+ * the MC aren't working.
+ */
+ if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
+ return -EIO;
+
+ mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+ pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+ switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
+ case I82443BXGX_DRAMC_DRAM_IS_EDO:
+ mtype = MEM_EDO;
+ break;
+ case I82443BXGX_DRAMC_DRAM_IS_SDRAM:
+ mtype = MEM_SDR;
+ break;
+ case I82443BXGX_DRAMC_DRAM_IS_RSDRAM:
+ mtype = MEM_RDR;
+ break;
+ default:
+ debugf0("Unknown/reserved DRAM type value "
+ "in DRAMC register!\n");
+ mtype = -MEM_UNKNOWN;
+ }
+
+ if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
+ mci->edac_cap = mci->edac_ctl_cap;
+ else
+ mci->edac_cap = EDAC_FLAG_NONE;
+
+ mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+ pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
+ ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
+ (BIT(0) | BIT(1)));
+
+ mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
+ ? SCRUB_HW_SRC : SCRUB_NONE;
+
+ switch (ecc_mode) {
+ case I82443BXGX_NBXCFG_INTEGRITY_NONE:
+ edac_mode = EDAC_NONE;
+ break;
+ case I82443BXGX_NBXCFG_INTEGRITY_EC:
+ edac_mode = EDAC_EC;
+ break;
+ case I82443BXGX_NBXCFG_INTEGRITY_ECC:
+ case I82443BXGX_NBXCFG_INTEGRITY_SCRUB:
+ edac_mode = EDAC_SECDED;
+ break;
+ default:
+ debugf0("%s(): Unknown/reserved ECC state "
+ "in NBXCFG register!\n", __func__);
+ edac_mode = EDAC_UNKNOWN;
+ break;
+ }
+
+ i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
+
+ /* Many BIOSes don't clear error flags on boot, so do this
+ * here, or we get "phantom" errors occuring at module-load
+ * time. */
+ pci_write_bits32(pdev, I82443BXGX_EAP,
+ (I82443BXGX_EAP_OFFSET_SBE |
+ I82443BXGX_EAP_OFFSET_MBE),
+ (I82443BXGX_EAP_OFFSET_SBE |
+ I82443BXGX_EAP_OFFSET_MBE));
+
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = I82443_REVISION;
+ mci->ctl_name = "I82443BXGX";
+ mci->dev_name = pci_name(pdev);
+ mci->edac_check = i82443bxgx_edacmc_check;
+ mci->ctl_page_to_phys = NULL;
+
+ if (edac_mc_add_mc(mci)) {
+ debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+ goto fail;
+ }
+
+ /* allocating generic PCI control info */
+ i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i82443bxgx_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+ return 0;
+
+fail:
+ edac_mc_free(mci);
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* don't need to call pci_device_enable() */
+ return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+}
+
+static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+
+ if (i82443bxgx_pci)
+ edac_pci_release_generic_ctl(i82443bxgx_pci);
+
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+ return;
+
+ edac_mc_free(mci);
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
+
+static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)},
+ {0,} /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
+
+static struct pci_driver i82443bxgx_edacmc_driver = {
+ .name = EDAC_MOD_STR,
+ .probe = i82443bxgx_edacmc_init_one,
+ .remove = __devexit_p(i82443bxgx_edacmc_remove_one),
+ .id_table = i82443bxgx_pci_tbl,
+};
+
+static int __init i82443bxgx_edacmc_init(void)
+{
+ return pci_register_driver(&i82443bxgx_edacmc_driver);
+}
+
+static void __exit i82443bxgx_edacmc_exit(void)
+{
+ pci_unregister_driver(&i82443bxgx_edacmc_driver);
+}
+
+module_init(i82443bxgx_edacmc_init);
+module_exit(i82443bxgx_edacmc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
+MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index e4bb298e613f..f5ecd2c4d813 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -14,9 +14,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define I82860_REVISION " Ver: 2.0.1 " __DATE__
+#define I82860_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "i82860_edac"
#define i82860_printk(level, fmt, arg...) \
@@ -54,16 +54,16 @@ struct i82860_error_info {
static const struct i82860_dev_info i82860_devs[] = {
[I82860] = {
- .ctl_name = "i82860"
- },
+ .ctl_name = "i82860"},
};
-static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code
* has already registered driver
*/
+static struct edac_pci_ctl_info *i82860_pci;
static void i82860_get_error_info(struct mem_ctl_info *mci,
- struct i82860_error_info *info)
+ struct i82860_error_info *info)
{
struct pci_dev *pdev;
@@ -91,13 +91,13 @@ static void i82860_get_error_info(struct mem_ctl_info *mci,
if ((info->errsts ^ info->errsts2) & 0x0003) {
pci_read_config_dword(pdev, I82860_EAP, &info->eap);
- pci_read_config_word(pdev, I82860_DERRCTL_STS,
- &info->derrsyn);
+ pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
}
}
static int i82860_process_error_info(struct mem_ctl_info *mci,
- struct i82860_error_info *info, int handle_errors)
+ struct i82860_error_info *info,
+ int handle_errors)
{
int row;
@@ -136,7 +136,7 @@ static void i82860_check(struct mem_ctl_info *mci)
static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
{
unsigned long last_cumul_size;
- u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
+ u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
u16 value;
u32 cumul_size;
struct csrow_info *csrow;
@@ -155,7 +155,7 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
csrow = &mci->csrows[index];
pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
cumul_size = (value & I82860_GBA_MASK) <<
- (I82860_GBA_SHIFT - PAGE_SHIFT);
+ (I82860_GBA_SHIFT - PAGE_SHIFT);
debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
cumul_size);
@@ -186,7 +186,7 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
the channel and the GRA registers map to physical devices so we are
going to make 1 channel for group.
*/
- mci = edac_mc_alloc(0, 16, 1);
+ mci = edac_mc_alloc(0, 16, 1, 0);
if (!mci)
return -ENOMEM;
@@ -200,19 +200,31 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = I82860_REVISION;
mci->ctl_name = i82860_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = i82860_check;
mci->ctl_page_to_phys = NULL;
i82860_init_csrows(mci, pdev);
- i82860_get_error_info(mci, &discard); /* clear counters */
+ i82860_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
+ /* allocating generic PCI control info */
+ i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i82860_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
@@ -225,7 +237,7 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit i82860_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
@@ -249,6 +261,9 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (i82860_pci)
+ edac_pci_release_generic_ctl(i82860_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
@@ -257,12 +272,11 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- I82860
- },
+ PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I82860},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
@@ -329,5 +343,5 @@ module_exit(i82860_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
- "Ben Woodard <woodard@redhat.com>");
+ "Ben Woodard <woodard@redhat.com>");
MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 2800b3e614a9..031abadc439a 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -18,9 +18,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define I82875P_REVISION " Ver: 2.0.1 " __DATE__
+#define I82875P_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "i82875p_edac"
#define i82875p_printk(level, fmt, arg...) \
@@ -174,18 +174,19 @@ struct i82875p_error_info {
static const struct i82875p_dev_info i82875p_devs[] = {
[I82875P] = {
- .ctl_name = "i82875p"
- },
+ .ctl_name = "i82875p"},
};
-static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code has
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
* already registered driver
*/
static int i82875p_registered = 1;
+static struct edac_pci_ctl_info *i82875p_pci;
+
static void i82875p_get_error_info(struct mem_ctl_info *mci,
- struct i82875p_error_info *info)
+ struct i82875p_error_info *info)
{
struct pci_dev *pdev;
@@ -197,38 +198,39 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
* overwritten by UE.
*/
pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);
+
+ if (!(info->errsts & 0x0081))
+ return;
+
pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
pci_read_config_byte(pdev, I82875P_DES, &info->des);
pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);
- pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
-
/*
* If the error is the same then we can for both reads then
* the first set of reads is valid. If there is a change then
* there is a CE no info and the second set of reads is valid
* and should be UE info.
*/
- if (!(info->errsts2 & 0x0081))
- return;
-
if ((info->errsts ^ info->errsts2) & 0x0081) {
pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
pci_read_config_byte(pdev, I82875P_DES, &info->des);
- pci_read_config_byte(pdev, I82875P_DERRSYN,
- &info->derrsyn);
+ pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
}
+
+ pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
}
static int i82875p_process_error_info(struct mem_ctl_info *mci,
- struct i82875p_error_info *info, int handle_errors)
+ struct i82875p_error_info *info,
+ int handle_errors)
{
int row, multi_chan;
multi_chan = mci->csrows[0].nr_channels - 1;
- if (!(info->errsts2 & 0x0081))
+ if (!(info->errsts & 0x0081))
return 0;
if (!handle_errors)
@@ -263,10 +265,12 @@ static void i82875p_check(struct mem_ctl_info *mci)
/* Return 0 on success or 1 on failure. */
static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
- struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window)
+ struct pci_dev **ovrfl_pdev,
+ void __iomem **ovrfl_window)
{
struct pci_dev *dev;
void __iomem *window;
+ int err;
*ovrfl_pdev = NULL;
*ovrfl_window = NULL;
@@ -284,14 +288,19 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
if (dev == NULL)
return 1;
- pci_bus_add_device(dev);
+ err = pci_bus_add_device(dev);
+ if (err) {
+ i82875p_printk(KERN_ERR,
+ "%s(): pci_bus_add_device() Failed\n",
+ __func__);
+ }
}
*ovrfl_pdev = dev;
if (pci_enable_device(dev)) {
i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
- "device\n", __func__);
+ "device\n", __func__);
return 1;
}
@@ -307,7 +316,7 @@ static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
if (window == NULL) {
i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
- __func__);
+ __func__);
goto fail1;
}
@@ -325,21 +334,20 @@ fail0:
return 1;
}
-
/* Return 1 if dual channel mode is active. Else return 0. */
static inline int dual_channel_active(u32 drc)
{
return (drc >> 21) & 0x1;
}
-
static void i82875p_init_csrows(struct mem_ctl_info *mci,
- struct pci_dev *pdev, void __iomem *ovrfl_window, u32 drc)
+ struct pci_dev *pdev,
+ void __iomem * ovrfl_window, u32 drc)
{
struct csrow_info *csrow;
unsigned long last_cumul_size;
u8 value;
- u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
+ u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
u32 cumul_size;
int index;
@@ -392,7 +400,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
drc = readl(ovrfl_window + I82875P_DRC);
nr_chans = dual_channel_active(drc) + 1;
mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
- nr_chans);
+ nr_chans, 0);
if (!mci) {
rc = -ENOMEM;
@@ -407,23 +415,35 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = I82875P_REVISION;
mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
+ mci->dev_name = pci_name(pdev);
mci->edac_check = i82875p_check;
mci->ctl_page_to_phys = NULL;
debugf3("%s(): init pvt\n", __func__);
- pvt = (struct i82875p_pvt *) mci->pvt_info;
+ pvt = (struct i82875p_pvt *)mci->pvt_info;
pvt->ovrfl_pdev = ovrfl_pdev;
pvt->ovrfl_window = ovrfl_window;
i82875p_init_csrows(mci, pdev, ovrfl_window, drc);
- i82875p_get_error_info(mci, &discard); /* clear counters */
+ i82875p_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail1;
}
+ /* allocating generic PCI control info */
+ i82875p_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!i82875p_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
@@ -442,7 +462,7 @@ fail0:
/* returns count (>= 0), or negative on error */
static int __devinit i82875p_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
@@ -467,10 +487,13 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (i82875p_pci)
+ edac_pci_release_generic_ctl(i82875p_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
- pvt = (struct i82875p_pvt *) mci->pvt_info;
+ pvt = (struct i82875p_pvt *)mci->pvt_info;
if (pvt->ovrfl_window)
iounmap(pvt->ovrfl_window);
@@ -488,12 +511,11 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
{
- PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- I82875P
- },
+ PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I82875P},
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
@@ -517,7 +539,7 @@ static int __init i82875p_init(void)
if (mci_pdev == NULL) {
mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82875_0, NULL);
+ PCI_DEVICE_ID_INTEL_82875_0, NULL);
if (!mci_pdev) {
debugf0("875p pci_get_device fail\n");
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
new file mode 100644
index 000000000000..0ee888456932
--- /dev/null
+++ b/drivers/edac/i82975x_edac.c
@@ -0,0 +1,666 @@
+/*
+ * Intel 82975X Memory Controller kernel module
+ * (C) 2007 aCarLab (India) Pvt. Ltd. (http://acarlab.com)
+ * (C) 2007 jetzbroadband (http://jetzbroadband.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Arvind R.
+ * Copied from i82875p_edac.c source:
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82975X_REVISION " Ver: 1.0.0 " __DATE__
+#define EDAC_MOD_STR "i82975x_edac"
+
+#define i82975x_printk(level, fmt, arg...) \
+ edac_printk(level, "i82975x", fmt, ##arg)
+
+#define i82975x_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "i82975x", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_82975_0
+#define PCI_DEVICE_ID_INTEL_82975_0 0x277c
+#endif /* PCI_DEVICE_ID_INTEL_82975_0 */
+
+#define I82975X_NR_CSROWS(nr_chans) (8/(nr_chans))
+
+/* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */
+#define I82975X_EAP 0x58 /* Dram Error Address Pointer (32b)
+ *
+ * 31:7 128 byte cache-line address
+ * 6:1 reserved
+ * 0 0: CH0; 1: CH1
+ */
+
+#define I82975X_DERRSYN 0x5c /* Dram Error SYNdrome (8b)
+ *
+ * 7:0 DRAM ECC Syndrome
+ */
+
+#define I82975X_DES 0x5d /* Dram ERRor DeSTination (8b)
+ * 0h: Processor Memory Reads
+ * 1h:7h reserved
+ * More - See Page 65 of Intel DocSheet.
+ */
+
+#define I82975X_ERRSTS 0xc8 /* Error Status Register (16b)
+ *
+ * 15:12 reserved
+ * 11 Thermal Sensor Event
+ * 10 reserved
+ * 9 non-DRAM lock error (ndlock)
+ * 8 Refresh Timeout
+ * 7:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+/* Error Reporting is supported by 3 mechanisms:
+ 1. DMI SERR generation ( ERRCMD )
+ 2. SMI DMI generation ( SMICMD )
+ 3. SCI DMI generation ( SCICMD )
+NOTE: Only ONE of the three must be enabled
+*/
+#define I82975X_ERRCMD 0xca /* Error Command (16b)
+ *
+ * 15:12 reserved
+ * 11 Thermal Sensor Event
+ * 10 reserved
+ * 9 non-DRAM lock error (ndlock)
+ * 8 Refresh Timeout
+ * 7:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+#define I82975X_SMICMD 0xcc /* Error Command (16b)
+ *
+ * 15:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+#define I82975X_SCICMD 0xce /* Error Command (16b)
+ *
+ * 15:2 reserved
+ * 1 ECC UE (multibit DRAM error)
+ * 0 ECC CE (singlebit DRAM error)
+ */
+
+#define I82975X_XEAP 0xfc /* Extended Dram Error Address Pointer (8b)
+ *
+ * 7:1 reserved
+ * 0 Bit32 of the Dram Error Address
+ */
+
+#define I82975X_MCHBAR 0x44 /*
+ *
+ * 31:14 Base Addr of 16K memory-mapped
+ * configuration space
+ * 13:1 reserverd
+ * 0 mem-mapped config space enable
+ */
+
+/* NOTE: Following addresses have to indexed using MCHBAR offset (44h, 32b) */
+/* Intel 82975x memory mapped register space */
+
+#define I82975X_DRB_SHIFT 25 /* fixed 32MiB grain */
+
+#define I82975X_DRB 0x100 /* DRAM Row Boundary (8b x 8)
+ *
+ * 7 set to 1 in highest DRB of
+ * channel if 4GB in ch.
+ * 6:2 upper boundary of rank in
+ * 32MB grains
+ * 1:0 set to 0
+ */
+#define I82975X_DRB_CH0R0 0x100
+#define I82975X_DRB_CH0R1 0x101
+#define I82975X_DRB_CH0R2 0x102
+#define I82975X_DRB_CH0R3 0x103
+#define I82975X_DRB_CH1R0 0x180
+#define I82975X_DRB_CH1R1 0x181
+#define I82975X_DRB_CH1R2 0x182
+#define I82975X_DRB_CH1R3 0x183
+
+
+#define I82975X_DRA 0x108 /* DRAM Row Attribute (4b x 8)
+ * defines the PAGE SIZE to be used
+ * for the rank
+ * 7 reserved
+ * 6:4 row attr of odd rank, i.e. 1
+ * 3 reserved
+ * 2:0 row attr of even rank, i.e. 0
+ *
+ * 000 = unpopulated
+ * 001 = reserved
+ * 010 = 4KiB
+ * 011 = 8KiB
+ * 100 = 16KiB
+ * others = reserved
+ */
+#define I82975X_DRA_CH0R01 0x108
+#define I82975X_DRA_CH0R23 0x109
+#define I82975X_DRA_CH1R01 0x188
+#define I82975X_DRA_CH1R23 0x189
+
+
+#define I82975X_BNKARC 0x10e /* Type of device in each rank - Bank Arch (16b)
+ *
+ * 15:8 reserved
+ * 7:6 Rank 3 architecture
+ * 5:4 Rank 2 architecture
+ * 3:2 Rank 1 architecture
+ * 1:0 Rank 0 architecture
+ *
+ * 00 => x16 devices; i.e 4 banks
+ * 01 => x8 devices; i.e 8 banks
+ */
+#define I82975X_C0BNKARC 0x10e
+#define I82975X_C1BNKARC 0x18e
+
+
+
+#define I82975X_DRC 0x120 /* DRAM Controller Mode0 (32b)
+ *
+ * 31:30 reserved
+ * 29 init complete
+ * 28:11 reserved, according to Intel
+ * 22:21 number of channels
+ * 00=1 01=2 in 82875
+ * seems to be ECC mode
+ * bits in 82975 in Asus
+ * P5W
+ * 19:18 Data Integ Mode
+ * 00=none 01=ECC in 82875
+ * 10:8 refresh mode
+ * 7 reserved
+ * 6:4 mode select
+ * 3:2 reserved
+ * 1:0 DRAM type 10=Second Revision
+ * DDR2 SDRAM
+ * 00, 01, 11 reserved
+ */
+#define I82975X_DRC_CH0M0 0x120
+#define I82975X_DRC_CH1M0 0x1A0
+
+
+#define I82975X_DRC_M1 0x124 /* DRAM Controller Mode1 (32b)
+ * 31 0=Standard Address Map
+ * 1=Enhanced Address Map
+ * 30:0 reserved
+ */
+
+#define I82975X_DRC_CH0M1 0x124
+#define I82975X_DRC_CH1M1 0x1A4
+
+enum i82975x_chips {
+ I82975X = 0,
+};
+
+struct i82975x_pvt {
+ void __iomem *mch_window;
+};
+
+struct i82975x_dev_info {
+ const char *ctl_name;
+};
+
+struct i82975x_error_info {
+ u16 errsts;
+ u32 eap;
+ u8 des;
+ u8 derrsyn;
+ u16 errsts2;
+ u8 chan; /* the channel is bit 0 of EAP */
+ u8 xeap; /* extended eap bit */
+};
+
+static const struct i82975x_dev_info i82975x_devs[] = {
+ [I82975X] = {
+ .ctl_name = "i82975x"
+ },
+};
+
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
+ * already registered driver
+ */
+
+static int i82975x_registered = 1;
+
+static void i82975x_get_error_info(struct mem_ctl_info *mci,
+ struct i82975x_error_info *info)
+{
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+
+ /*
+ * This is a mess because there is no atomic way to read all the
+ * registers at once and the registers can transition from CE being
+ * overwritten by UE.
+ */
+ pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts);
+ pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+ pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+ pci_read_config_byte(pdev, I82975X_DES, &info->des);
+ pci_read_config_byte(pdev, I82975X_DERRSYN, &info->derrsyn);
+ pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts2);
+
+ pci_write_bits16(pdev, I82975X_ERRSTS, 0x0003, 0x0003);
+
+ /*
+ * If the error is the same then we can for both reads then
+ * the first set of reads is valid. If there is a change then
+ * there is a CE no info and the second set of reads is valid
+ * and should be UE info.
+ */
+ if (!(info->errsts2 & 0x0003))
+ return;
+
+ if ((info->errsts ^ info->errsts2) & 0x0003) {
+ pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+ pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+ pci_read_config_byte(pdev, I82975X_DES, &info->des);
+ pci_read_config_byte(pdev, I82975X_DERRSYN,
+ &info->derrsyn);
+ }
+}
+
+static int i82975x_process_error_info(struct mem_ctl_info *mci,
+ struct i82975x_error_info *info, int handle_errors)
+{
+ int row, multi_chan, chan;
+
+ multi_chan = mci->csrows[0].nr_channels - 1;
+
+ if (!(info->errsts2 & 0x0003))
+ return 0;
+
+ if (!handle_errors)
+ return 1;
+
+ if ((info->errsts ^ info->errsts2) & 0x0003) {
+ edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+ info->errsts = info->errsts2;
+ }
+
+ chan = info->eap & 1;
+ info->eap >>= 1;
+ if (info->xeap )
+ info->eap |= 0x80000000;
+ info->eap >>= PAGE_SHIFT;
+ row = edac_mc_find_csrow_by_page(mci, info->eap);
+
+ if (info->errsts & 0x0002)
+ edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE");
+ else
+ edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
+ multi_chan ? chan : 0,
+ "i82975x CE");
+
+ return 1;
+}
+
+static void i82975x_check(struct mem_ctl_info *mci)
+{
+ struct i82975x_error_info info;
+
+ debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+ i82975x_get_error_info(mci, &info);
+ i82975x_process_error_info(mci, &info, 1);
+}
+
+/* Return 1 if dual channel mode is active. Else return 0. */
+static int dual_channel_active(void __iomem *mch_window)
+{
+ /*
+ * We treat interleaved-symmetric configuration as dual-channel - EAP's
+ * bit-0 giving the channel of the error location.
+ *
+ * All other configurations are treated as single channel - the EAP's
+ * bit-0 will resolve ok in symmetric area of mixed
+ * (symmetric/asymmetric) configurations
+ */
+ u8 drb[4][2];
+ int row;
+ int dualch;
+
+ for (dualch = 1, row = 0; dualch && (row < 4); row++) {
+ drb[row][0] = readb(mch_window + I82975X_DRB + row);
+ drb[row][1] = readb(mch_window + I82975X_DRB + row + 0x80);
+ dualch = dualch && (drb[row][0] == drb[row][1]);
+ }
+ return dualch;
+}
+
+static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
+{
+ /*
+ * ASUS P5W DH either does not program this register or programs
+ * it wrong!
+ * ECC is possible on i92975x ONLY with DEV_X8 which should mean 'val'
+ * for each rank should be 01b - the LSB of the word should be 0x55;
+ * but it reads 0!
+ */
+ return DEV_X8;
+}
+
+static void i82975x_init_csrows(struct mem_ctl_info *mci,
+ struct pci_dev *pdev, void __iomem *mch_window)
+{
+ struct csrow_info *csrow;
+ unsigned long last_cumul_size;
+ u8 value;
+ u32 cumul_size;
+ int index;
+
+ last_cumul_size = 0;
+
+ /*
+ * 82875 comment:
+ * The dram row boundary (DRB) reg values are boundary address
+ * for each DRAM row with a granularity of 32 or 64MB (single/dual
+ * channel operation). DRB regs are cumulative; therefore DRB7 will
+ * contain the total memory contained in all eight rows.
+ *
+ * FIXME:
+ * EDAC currently works for Dual-channel Interleaved configuration.
+ * Other configurations, which the chip supports, need fixing/testing.
+ *
+ */
+
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+
+ value = readb(mch_window + I82975X_DRB + index +
+ ((index >= 4) ? 0x80 : 0));
+ cumul_size = value;
+ cumul_size <<= (I82975X_DRB_SHIFT - PAGE_SHIFT);
+ debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+ cumul_size);
+ if (cumul_size == last_cumul_size)
+ continue; /* not populated */
+
+ csrow->first_page = last_cumul_size;
+ csrow->last_page = cumul_size - 1;
+ csrow->nr_pages = cumul_size - last_cumul_size;
+ last_cumul_size = cumul_size;
+ csrow->grain = 1 << 7; /* I82975X_EAP has 128B resolution */
+ csrow->mtype = MEM_DDR; /* i82975x supports only DDR2 */
+ csrow->dtype = i82975x_dram_type(mch_window, index);
+ csrow->edac_mode = EDAC_SECDED; /* only supported */
+ }
+}
+
+/* #define i82975x_DEBUG_IOMEM */
+
+#ifdef i82975x_DEBUG_IOMEM
+static void i82975x_print_dram_timings(void __iomem *mch_window)
+{
+ /*
+ * The register meanings are from Intel specs;
+ * (shows 13-5-5-5 for 800-DDR2)
+ * Asus P5W Bios reports 15-5-4-4
+ * What's your religion?
+ */
+ static const int caslats[4] = { 5, 4, 3, 6 };
+ u32 dtreg[2];
+
+ dtreg[0] = readl(mch_window + 0x114);
+ dtreg[1] = readl(mch_window + 0x194);
+ i82975x_printk(KERN_INFO, "DRAM Timings : Ch0 Ch1\n"
+ " RAS Active Min = %d %d\n"
+ " CAS latency = %d %d\n"
+ " RAS to CAS = %d %d\n"
+ " RAS precharge = %d %d\n",
+ (dtreg[0] >> 19 ) & 0x0f,
+ (dtreg[1] >> 19) & 0x0f,
+ caslats[(dtreg[0] >> 8) & 0x03],
+ caslats[(dtreg[1] >> 8) & 0x03],
+ ((dtreg[0] >> 4) & 0x07) + 2,
+ ((dtreg[1] >> 4) & 0x07) + 2,
+ (dtreg[0] & 0x07) + 2,
+ (dtreg[1] & 0x07) + 2
+ );
+
+}
+#endif
+
+static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ int rc = -ENODEV;
+ struct mem_ctl_info *mci;
+ struct i82975x_pvt *pvt;
+ void __iomem *mch_window;
+ u32 mchbar;
+ u32 drc[2];
+ struct i82975x_error_info discard;
+ int chans;
+#ifdef i82975x_DEBUG_IOMEM
+ u8 c0drb[4];
+ u8 c1drb[4];
+#endif
+
+ debugf0("%s()\n", __func__);
+
+ pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar);
+ if (!(mchbar & 1)) {
+ debugf3("%s(): failed, MCHBAR disabled!\n", __func__);
+ goto fail0;
+ }
+ mchbar &= 0xffffc000; /* bits 31:14 used for 16K window */
+ mch_window = ioremap_nocache(mchbar, 0x1000);
+
+#ifdef i82975x_DEBUG_IOMEM
+ i82975x_printk(KERN_INFO, "MCHBAR real = %0x, remapped = %p\n",
+ mchbar, mch_window);
+
+ c0drb[0] = readb(mch_window + I82975X_DRB_CH0R0);
+ c0drb[1] = readb(mch_window + I82975X_DRB_CH0R1);
+ c0drb[2] = readb(mch_window + I82975X_DRB_CH0R2);
+ c0drb[3] = readb(mch_window + I82975X_DRB_CH0R3);
+ c1drb[0] = readb(mch_window + I82975X_DRB_CH1R0);
+ c1drb[1] = readb(mch_window + I82975X_DRB_CH1R1);
+ c1drb[2] = readb(mch_window + I82975X_DRB_CH1R2);
+ c1drb[3] = readb(mch_window + I82975X_DRB_CH1R3);
+ i82975x_printk(KERN_INFO, "DRBCH0R0 = 0x%02x\n", c0drb[0]);
+ i82975x_printk(KERN_INFO, "DRBCH0R1 = 0x%02x\n", c0drb[1]);
+ i82975x_printk(KERN_INFO, "DRBCH0R2 = 0x%02x\n", c0drb[2]);
+ i82975x_printk(KERN_INFO, "DRBCH0R3 = 0x%02x\n", c0drb[3]);
+ i82975x_printk(KERN_INFO, "DRBCH1R0 = 0x%02x\n", c1drb[0]);
+ i82975x_printk(KERN_INFO, "DRBCH1R1 = 0x%02x\n", c1drb[1]);
+ i82975x_printk(KERN_INFO, "DRBCH1R2 = 0x%02x\n", c1drb[2]);
+ i82975x_printk(KERN_INFO, "DRBCH1R3 = 0x%02x\n", c1drb[3]);
+#endif
+
+ drc[0] = readl(mch_window + I82975X_DRC_CH0M0);
+ drc[1] = readl(mch_window + I82975X_DRC_CH1M0);
+#ifdef i82975x_DEBUG_IOMEM
+ i82975x_printk(KERN_INFO, "DRC_CH0 = %0x, %s\n", drc[0],
+ ((drc[0] >> 21) & 3) == 1 ?
+ "ECC enabled" : "ECC disabled");
+ i82975x_printk(KERN_INFO, "DRC_CH1 = %0x, %s\n", drc[1],
+ ((drc[1] >> 21) & 3) == 1 ?
+ "ECC enabled" : "ECC disabled");
+
+ i82975x_printk(KERN_INFO, "C0 BNKARC = %0x\n",
+ readw(mch_window + I82975X_C0BNKARC));
+ i82975x_printk(KERN_INFO, "C1 BNKARC = %0x\n",
+ readw(mch_window + I82975X_C1BNKARC));
+ i82975x_print_dram_timings(mch_window);
+ goto fail1;
+#endif
+ if (!(((drc[0] >> 21) & 3) == 1 || ((drc[1] >> 21) & 3) == 1)) {
+ i82975x_printk(KERN_INFO, "ECC disabled on both channels.\n");
+ goto fail1;
+ }
+
+ chans = dual_channel_active(mch_window) + 1;
+
+ /* assuming only one controller, index thus is 0 */
+ mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans),
+ chans, 0);
+ if (!mci) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ debugf3("%s(): init mci\n", __func__);
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = I82975X_REVISION;
+ mci->ctl_name = i82975x_devs[dev_idx].ctl_name;
+ mci->edac_check = i82975x_check;
+ mci->ctl_page_to_phys = NULL;
+ debugf3("%s(): init pvt\n", __func__);
+ pvt = (struct i82975x_pvt *) mci->pvt_info;
+ pvt->mch_window = mch_window;
+ i82975x_init_csrows(mci, pdev, mch_window);
+ i82975x_get_error_info(mci, &discard); /* clear counters */
+
+ /* finalize this instance of memory controller with edac core */
+ if (edac_mc_add_mc(mci)) {
+ debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+ goto fail2;
+ }
+
+ /* get this far and it's successful */
+ debugf3("%s(): success\n", __func__);
+ return 0;
+
+fail2:
+ edac_mc_free(mci);
+
+fail1:
+ iounmap(mch_window);
+fail0:
+ return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82975x_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int rc;
+
+ debugf0("%s()\n", __func__);
+
+ if (pci_enable_device(pdev) < 0)
+ return -EIO;
+
+ rc = i82975x_probe1(pdev, ent->driver_data);
+
+ if (mci_pdev == NULL)
+ mci_pdev = pci_dev_get(pdev);
+
+ return rc;
+}
+
+static void __devexit i82975x_remove_one(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+ struct i82975x_pvt *pvt;
+
+ debugf0("%s()\n", __func__);
+
+ mci = edac_mc_del_mc(&pdev->dev);
+ if (mci == NULL)
+ return;
+
+ pvt = mci->pvt_info;
+ if (pvt->mch_window)
+ iounmap( pvt->mch_window );
+
+ edac_mc_free(mci);
+}
+
+static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = {
+ {
+ PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I82975X
+ },
+ {
+ 0,
+ } /* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl);
+
+static struct pci_driver i82975x_driver = {
+ .name = EDAC_MOD_STR,
+ .probe = i82975x_init_one,
+ .remove = __devexit_p(i82975x_remove_one),
+ .id_table = i82975x_pci_tbl,
+};
+
+static int __init i82975x_init(void)
+{
+ int pci_rc;
+
+ debugf3("%s()\n", __func__);
+
+ pci_rc = pci_register_driver(&i82975x_driver);
+ if (pci_rc < 0)
+ goto fail0;
+
+ if (mci_pdev == NULL) {
+ mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82975_0, NULL);
+
+ if (!mci_pdev) {
+ debugf0("i82975x pci_get_device fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+
+ pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl);
+
+ if (pci_rc < 0) {
+ debugf0("i82975x init fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+ }
+
+ return 0;
+
+fail1:
+ pci_unregister_driver(&i82975x_driver);
+
+fail0:
+ if (mci_pdev != NULL)
+ pci_dev_put(mci_pdev);
+
+ return pci_rc;
+}
+
+static void __exit i82975x_exit(void)
+{
+ debugf3("%s()\n", __func__);
+
+ pci_unregister_driver(&i82975x_driver);
+
+ if (!i82975x_registered) {
+ i82975x_remove_one(mci_pdev);
+ pci_dev_put(mci_pdev);
+ }
+}
+
+module_init(i82975x_init);
+module_exit(i82975x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>");
+MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers");
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
new file mode 100644
index 000000000000..e66cdd42a392
--- /dev/null
+++ b/drivers/edac/pasemi_edac.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Egor Martovetsky <egor@pasemi.com>
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip memory controllers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define MODULE_NAME "pasemi_edac"
+
+#define MCCFG_MCEN 0x300
+#define MCCFG_MCEN_MMC_EN 0x00000001
+#define MCCFG_ERRCOR 0x388
+#define MCCFG_ERRCOR_RNK_FAIL_DET_EN 0x00000100
+#define MCCFG_ERRCOR_ECC_GEN_EN 0x00000010
+#define MCCFG_ERRCOR_ECC_CRR_EN 0x00000001
+#define MCCFG_SCRUB 0x384
+#define MCCFG_SCRUB_RGLR_SCRB_EN 0x00000001
+#define MCDEBUG_ERRCTL1 0x728
+#define MCDEBUG_ERRCTL1_RFL_LOG_EN 0x00080000
+#define MCDEBUG_ERRCTL1_MBE_LOG_EN 0x00040000
+#define MCDEBUG_ERRCTL1_SBE_LOG_EN 0x00020000
+#define MCDEBUG_ERRSTA 0x730
+#define MCDEBUG_ERRSTA_RFL_STATUS 0x00000004
+#define MCDEBUG_ERRSTA_MBE_STATUS 0x00000002
+#define MCDEBUG_ERRSTA_SBE_STATUS 0x00000001
+#define MCDEBUG_ERRCNT1 0x734
+#define MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO 0x00000080
+#define MCDEBUG_ERRLOG1A 0x738
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_M 0x30000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_NONE 0x00000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_SBE 0x10000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_MBE 0x20000000
+#define MCDEBUG_ERRLOG1A_MERR_TYPE_RFL 0x30000000
+#define MCDEBUG_ERRLOG1A_MERR_BA_M 0x00700000
+#define MCDEBUG_ERRLOG1A_MERR_BA_S 20
+#define MCDEBUG_ERRLOG1A_MERR_CS_M 0x00070000
+#define MCDEBUG_ERRLOG1A_MERR_CS_S 16
+#define MCDEBUG_ERRLOG1A_SYNDROME_M 0x0000ffff
+#define MCDRAM_RANKCFG 0x114
+#define MCDRAM_RANKCFG_EN 0x00000001
+#define MCDRAM_RANKCFG_TYPE_SIZE_M 0x000001c0
+#define MCDRAM_RANKCFG_TYPE_SIZE_S 6
+
+#define PASEMI_EDAC_NR_CSROWS 8
+#define PASEMI_EDAC_NR_CHANS 1
+#define PASEMI_EDAC_ERROR_GRAIN 64
+
+static int last_page_in_mmc;
+static int system_mmc_id;
+
+
+static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
+{
+ struct pci_dev *pdev = to_pci_dev(mci->dev);
+ u32 tmp;
+
+ pci_read_config_dword(pdev, MCDEBUG_ERRSTA,
+ &tmp);
+
+ tmp &= (MCDEBUG_ERRSTA_RFL_STATUS | MCDEBUG_ERRSTA_MBE_STATUS
+ | MCDEBUG_ERRSTA_SBE_STATUS);
+
+ if (tmp) {
+ if (tmp & MCDEBUG_ERRSTA_SBE_STATUS)
+ pci_write_config_dword(pdev, MCDEBUG_ERRCNT1,
+ MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO);
+ pci_write_config_dword(pdev, MCDEBUG_ERRSTA, tmp);
+ }
+
+ return tmp;
+}
+
+static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
+{
+ struct pci_dev *pdev = to_pci_dev(mci->dev);
+ u32 errlog1a;
+ u32 cs;
+
+ if (!errsta)
+ return;
+
+ pci_read_config_dword(pdev, MCDEBUG_ERRLOG1A, &errlog1a);
+
+ cs = (errlog1a & MCDEBUG_ERRLOG1A_MERR_CS_M) >>
+ MCDEBUG_ERRLOG1A_MERR_CS_S;
+
+ /* uncorrectable/multi-bit errors */
+ if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
+ MCDEBUG_ERRSTA_RFL_STATUS)) {
+ edac_mc_handle_ue(mci, mci->csrows[cs].first_page, 0,
+ cs, mci->ctl_name);
+ }
+
+ /* correctable/single-bit errors */
+ if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) {
+ edac_mc_handle_ce(mci, mci->csrows[cs].first_page, 0,
+ 0, cs, 0, mci->ctl_name);
+ }
+}
+
+static void pasemi_edac_check(struct mem_ctl_info *mci)
+{
+ u32 errsta;
+
+ errsta = pasemi_edac_get_error_info(mci);
+ if (errsta)
+ pasemi_edac_process_error_info(mci, errsta);
+}
+
+static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
+ struct pci_dev *pdev,
+ enum edac_type edac_mode)
+{
+ struct csrow_info *csrow;
+ u32 rankcfg;
+ int index;
+
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+
+ pci_read_config_dword(pdev,
+ MCDRAM_RANKCFG + (index * 12),
+ &rankcfg);
+
+ if (!(rankcfg & MCDRAM_RANKCFG_EN))
+ continue;
+
+ switch ((rankcfg & MCDRAM_RANKCFG_TYPE_SIZE_M) >>
+ MCDRAM_RANKCFG_TYPE_SIZE_S) {
+ case 0:
+ csrow->nr_pages = 128 << (20 - PAGE_SHIFT);
+ break;
+ case 1:
+ csrow->nr_pages = 256 << (20 - PAGE_SHIFT);
+ break;
+ case 2:
+ case 3:
+ csrow->nr_pages = 512 << (20 - PAGE_SHIFT);
+ break;
+ case 4:
+ csrow->nr_pages = 1024 << (20 - PAGE_SHIFT);
+ break;
+ case 5:
+ csrow->nr_pages = 2048 << (20 - PAGE_SHIFT);
+ break;
+ default:
+ edac_mc_printk(mci, KERN_ERR,
+ "Unrecognized Rank Config. rankcfg=%u\n",
+ rankcfg);
+ return -EINVAL;
+ }
+
+ csrow->first_page = last_page_in_mmc;
+ csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+ last_page_in_mmc += csrow->nr_pages;
+ csrow->page_mask = 0;
+ csrow->grain = PASEMI_EDAC_ERROR_GRAIN;
+ csrow->mtype = MEM_DDR;
+ csrow->dtype = DEV_UNKNOWN;
+ csrow->edac_mode = edac_mode;
+ }
+ return 0;
+}
+
+static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct mem_ctl_info *mci = NULL;
+ u32 errctl1, errcor, scrub, mcen;
+
+ pci_read_config_dword(pdev, MCCFG_MCEN, &mcen);
+ if (!(mcen & MCCFG_MCEN_MMC_EN))
+ return -ENODEV;
+
+ /*
+ * We should think about enabling other error detection later on
+ */
+
+ pci_read_config_dword(pdev, MCDEBUG_ERRCTL1, &errctl1);
+ errctl1 |= MCDEBUG_ERRCTL1_SBE_LOG_EN |
+ MCDEBUG_ERRCTL1_MBE_LOG_EN |
+ MCDEBUG_ERRCTL1_RFL_LOG_EN;
+ pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1);
+
+ mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS,
+ system_mmc_id++);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ pci_read_config_dword(pdev, MCCFG_ERRCOR, &errcor);
+ errcor |= MCCFG_ERRCOR_RNK_FAIL_DET_EN |
+ MCCFG_ERRCOR_ECC_GEN_EN |
+ MCCFG_ERRCOR_ECC_CRR_EN;
+
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+ mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ?
+ ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ?
+ (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_EC) :
+ EDAC_FLAG_NONE;
+ mci->mod_name = MODULE_NAME;
+ mci->dev_name = pci_name(pdev);
+ mci->ctl_name = "pasemi,1682m-mc";
+ mci->edac_check = pasemi_edac_check;
+ mci->ctl_page_to_phys = NULL;
+ pci_read_config_dword(pdev, MCCFG_SCRUB, &scrub);
+ mci->scrub_cap = SCRUB_FLAG_HW_PROG | SCRUB_FLAG_HW_SRC;
+ mci->scrub_mode =
+ ((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ? SCRUB_FLAG_HW_SRC : 0) |
+ ((scrub & MCCFG_SCRUB_RGLR_SCRB_EN) ? SCRUB_FLAG_HW_PROG : 0);
+
+ if (pasemi_edac_init_csrows(mci, pdev,
+ (mci->edac_cap & EDAC_FLAG_SECDED) ?
+ EDAC_SECDED :
+ ((mci->edac_cap & EDAC_FLAG_EC) ?
+ EDAC_EC : EDAC_NONE)))
+ goto fail;
+
+ /*
+ * Clear status
+ */
+ pasemi_edac_get_error_info(mci);
+
+ if (edac_mc_add_mc(mci))
+ goto fail;
+
+ /* get this far and it's successful */
+ return 0;
+
+fail:
+ edac_mc_free(mci);
+ return -ENODEV;
+}
+
+static void __devexit pasemi_edac_remove(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
+
+ if (!mci)
+ return;
+
+ edac_mc_free(mci);
+}
+
+
+static const struct pci_device_id pasemi_edac_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa00a) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl);
+
+static struct pci_driver pasemi_edac_driver = {
+ .name = MODULE_NAME,
+ .probe = pasemi_edac_probe,
+ .remove = __devexit_p(pasemi_edac_remove),
+ .id_table = pasemi_edac_pci_tbl,
+};
+
+static int __init pasemi_edac_init(void)
+{
+ return pci_register_driver(&pasemi_edac_driver);
+}
+
+static void __exit pasemi_edac_exit(void)
+{
+ pci_unregister_driver(&pasemi_edac_driver);
+}
+
+module_init(pasemi_edac_init);
+module_exit(pasemi_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("MC support for PA Semi PA6T-1682M memory controller");
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index a49cf0a39398..e25f712f2dc3 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -11,7 +11,7 @@
*
* Written with reference to 82600 High Integration Dual PCI System
* Controller Data Book:
- * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
+ * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
* references to this document given in []
*/
@@ -20,9 +20,9 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
-#define R82600_REVISION " Ver: 2.0.1 " __DATE__
+#define R82600_REVISION " Ver: 2.0.2 " __DATE__
#define EDAC_MOD_STR "r82600_edac"
#define r82600_printk(level, fmt, arg...) \
@@ -131,10 +131,12 @@ struct r82600_error_info {
u32 eapr;
};
-static unsigned int disable_hardware_scrub = 0;
+static unsigned int disable_hardware_scrub;
-static void r82600_get_error_info (struct mem_ctl_info *mci,
- struct r82600_error_info *info)
+static struct edac_pci_ctl_info *r82600_pci;
+
+static void r82600_get_error_info(struct mem_ctl_info *mci,
+ struct r82600_error_info *info)
{
struct pci_dev *pdev;
@@ -144,18 +146,19 @@ static void r82600_get_error_info (struct mem_ctl_info *mci,
if (info->eapr & BIT(0))
/* Clear error to allow next error to be reported [p.62] */
pci_write_bits32(pdev, R82600_EAP,
- ((u32) BIT(0) & (u32) BIT(1)),
- ((u32) BIT(0) & (u32) BIT(1)));
+ ((u32) BIT(0) & (u32) BIT(1)),
+ ((u32) BIT(0) & (u32) BIT(1)));
if (info->eapr & BIT(1))
/* Clear error to allow next error to be reported [p.62] */
pci_write_bits32(pdev, R82600_EAP,
- ((u32) BIT(0) & (u32) BIT(1)),
- ((u32) BIT(0) & (u32) BIT(1)));
+ ((u32) BIT(0) & (u32) BIT(1)),
+ ((u32) BIT(0) & (u32) BIT(1)));
}
-static int r82600_process_error_info (struct mem_ctl_info *mci,
- struct r82600_error_info *info, int handle_errors)
+static int r82600_process_error_info(struct mem_ctl_info *mci,
+ struct r82600_error_info *info,
+ int handle_errors)
{
int error_found;
u32 eapaddr, page;
@@ -172,25 +175,24 @@ static int r82600_process_error_info (struct mem_ctl_info *mci,
* granularity (upper 19 bits only) */
page = eapaddr >> PAGE_SHIFT;
- if (info->eapr & BIT(0)) { /* CE? */
+ if (info->eapr & BIT(0)) { /* CE? */
error_found = 1;
if (handle_errors)
- edac_mc_handle_ce(mci, page, 0, /* not avail */
+ edac_mc_handle_ce(mci, page, 0, /* not avail */
syndrome,
edac_mc_find_csrow_by_page(mci, page),
- 0, /* channel */
- mci->ctl_name);
+ 0, mci->ctl_name);
}
- if (info->eapr & BIT(1)) { /* UE? */
+ if (info->eapr & BIT(1)) { /* UE? */
error_found = 1;
if (handle_errors)
/* 82600 doesn't give enough info */
edac_mc_handle_ue(mci, page, 0,
- edac_mc_find_csrow_by_page(mci, page),
- mci->ctl_name);
+ edac_mc_find_csrow_by_page(mci, page),
+ mci->ctl_name);
}
return error_found;
@@ -211,11 +213,11 @@ static inline int ecc_enabled(u8 dramcr)
}
static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
- u8 dramcr)
+ u8 dramcr)
{
struct csrow_info *csrow;
int index;
- u8 drbar; /* SDRAM Row Boundry Address Register */
+ u8 drbar; /* SDRAM Row Boundry Address Register */
u32 row_high_limit, row_high_limit_last;
u32 reg_sdram, ecc_on, row_base;
@@ -276,7 +278,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
sdram_refresh_rate);
debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
- mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS);
+ mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0);
if (mci == NULL)
return -ENOMEM;
@@ -305,15 +307,16 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = R82600_REVISION;
mci->ctl_name = "R82600";
+ mci->dev_name = pci_name(pdev);
mci->edac_check = r82600_check;
mci->ctl_page_to_phys = NULL;
r82600_init_csrows(mci, pdev, dramcr);
- r82600_get_error_info(mci, &discard); /* clear counters */
+ r82600_get_error_info(mci, &discard); /* clear counters */
/* Here we assume that we will never see multiple instances of this
* type of memory controller. The ID is therefore hardcoded to 0.
*/
- if (edac_mc_add_mc(mci,0)) {
+ if (edac_mc_add_mc(mci)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
@@ -326,6 +329,17 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
}
+ /* allocating generic PCI control info */
+ r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+ if (!r82600_pci) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
debugf3("%s(): success\n", __func__);
return 0;
@@ -336,7 +350,7 @@ fail:
/* returns count (>= 0), or negative on error */
static int __devinit r82600_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
debugf0("%s()\n", __func__);
@@ -350,6 +364,9 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
+ if (r82600_pci)
+ edac_pci_release_generic_ctl(r82600_pci);
+
if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
@@ -358,11 +375,11 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
{
- PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
- },
+ PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
+ },
{
- 0,
- } /* 0 terminated list. */
+ 0,
+ } /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
@@ -389,7 +406,7 @@ module_exit(r82600_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
- "on behalf of EADS Astrium");
+ "on behalf of EADS Astrium");
MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
module_param(disable_hardware_scrub, bool, 0644);
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 41476abc0693..db703758db98 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -224,6 +224,7 @@ ohci_update_phy_reg(struct fw_card *card, int addr,
u32 val, old;
reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
+ flush_writes(ohci);
msleep(2);
val = reg_read(ohci, OHCI1394_PhyControl);
if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
@@ -586,7 +587,7 @@ static void context_stop(struct context *ctx)
break;
fw_notify("context_stop: still active (0x%08x)\n", reg);
- msleep(1);
+ mdelay(1);
}
}
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 7c53be0387fb..3e4a369d0057 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -840,7 +840,6 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
container_of(base_orb, struct sbp2_command_orb, base);
struct fw_unit *unit = orb->unit;
struct fw_device *device = fw_device(unit->device.parent);
- struct scatterlist *sg;
int result;
if (status != NULL) {
@@ -876,11 +875,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
dma_unmap_single(device->card->device, orb->base.request_bus,
sizeof(orb->request), DMA_TO_DEVICE);
- if (orb->cmd->use_sg > 0) {
- sg = (struct scatterlist *)orb->cmd->request_buffer;
- dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+ if (scsi_sg_count(orb->cmd) > 0)
+ dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
+ scsi_sg_count(orb->cmd),
orb->cmd->sc_data_direction);
- }
if (orb->page_table_bus != 0)
dma_unmap_single(device->card->device, orb->page_table_bus,
@@ -901,8 +899,8 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
int sg_len, l, i, j, count;
dma_addr_t sg_addr;
- sg = (struct scatterlist *)orb->cmd->request_buffer;
- count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg,
+ sg = scsi_sglist(orb->cmd);
+ count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
orb->cmd->sc_data_direction);
if (count == 0)
goto fail;
@@ -971,7 +969,7 @@ static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
return 0;
fail_page_table:
- dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+ dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
orb->cmd->sc_data_direction);
fail:
return -ENOMEM;
@@ -1031,7 +1029,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
orb->request.misc |=
COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
- if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
+ if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0)
goto fail_mapping;
fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
@@ -1162,7 +1160,7 @@ static struct device_attribute *sbp2_scsi_sysfs_attrs[] = {
static struct scsi_host_template scsi_driver_template = {
.module = THIS_MODULE,
.name = "SBP-2 IEEE-1394",
- .proc_name = (char *)sbp2_driver_name,
+ .proc_name = sbp2_driver_name,
.queuecommand = sbp2_scsi_queuecommand,
.slave_alloc = sbp2_scsi_slave_alloc,
.slave_configure = sbp2_scsi_slave_configure,
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 80d0121463d0..3ce8e2fbe15f 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -605,8 +605,10 @@ fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
* check is sufficient to ensure we don't send response to
* broadcast packets or posted writes.
*/
- if (request->ack != ACK_PENDING)
+ if (request->ack != ACK_PENDING) {
+ kfree(request);
return;
+ }
if (rcode == RCODE_COMPLETE)
fw_fill_response(&request->response, request->request_header,
@@ -628,11 +630,6 @@ fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
unsigned long flags;
int tcode, destination, source;
- if (p->payload_length > 2048) {
- /* FIXME: send error response. */
- return;
- }
-
if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
return;
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index 5abed193f4a6..5ceaccd10564 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -123,6 +123,10 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
size_t length,
void *callback_data);
+/*
+ * Important note: The callback must guarantee that either fw_send_response()
+ * or kfree() is called on the @request.
+ */
typedef void (*fw_address_callback_t)(struct fw_card *card,
struct fw_request *request,
int tcode, int destination, int source,
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 88f462122a30..05f02a326f1c 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -84,4 +84,13 @@ config DCDBAS
Say Y or M here to enable the driver for use by Dell systems
management software such as Dell OpenManage.
+config DMIID
+ bool "Export DMI identification via sysfs to userspace"
+ depends on DMI
+ default y
+ help
+ Say Y here if you want to query SMBIOS/DMI system identification
+ information from userspace through /sys/class/dmi/id/ or if you want
+ DMI-based module auto-loading.
+
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 98e395f4bb29..8d4ebc805a50 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_EFI_VARS) += efivars.o
obj-$(CONFIG_EFI_PCDP) += pcdp.o
obj-$(CONFIG_DELL_RBU) += dell_rbu.o
obj-$(CONFIG_DCDBAS) += dcdbas.o
+obj-$(CONFIG_DMIID) += dmi-id.o
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 1865b56fb141..18cdcb3ae1ca 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -149,8 +149,9 @@ static ssize_t smi_data_buf_size_store(struct device *dev,
return count;
}
-static ssize_t smi_data_read(struct kobject *kobj, char *buf, loff_t pos,
- size_t count)
+static ssize_t smi_data_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
{
size_t max_read;
ssize_t ret;
@@ -170,8 +171,9 @@ out:
return ret;
}
-static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
- size_t count)
+static ssize_t smi_data_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
{
ssize_t ret;
diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h
index 58a85182b3e8..dcdba0f1b32c 100644
--- a/drivers/firmware/dcdbas.h
+++ b/drivers/firmware/dcdbas.h
@@ -67,8 +67,7 @@
#define DCDBAS_BIN_ATTR_RW(_name) \
struct bin_attribute bin_attr_##_name = { \
.attr = { .name = __stringify(_name), \
- .mode = 0600, \
- .owner = THIS_MODULE }, \
+ .mode = 0600 }, \
.read = _name##_read, \
.write = _name##_write, \
}
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index fc702e40bd43..477a3d0e3caf 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -543,8 +543,9 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
return ret_count;
}
-static ssize_t read_rbu_data(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t read_rbu_data(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
ssize_t ret_count = 0;
@@ -591,8 +592,9 @@ static void callbackfn_rbu(const struct firmware *fw, void *context)
spin_unlock(&rbu_data.lock);
}
-static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t read_rbu_image_type(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
int size = 0;
if (!pos)
@@ -600,8 +602,9 @@ static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer,
return size;
}
-static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t write_rbu_image_type(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
int rc = count;
int req_firm_rc = 0;
@@ -660,8 +663,9 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer,
return rc;
}
-static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t read_rbu_packet_size(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
int size = 0;
if (!pos) {
@@ -672,8 +676,9 @@ static ssize_t read_rbu_packet_size(struct kobject *kobj, char *buffer,
return size;
}
-static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer,
- loff_t pos, size_t count)
+static ssize_t write_rbu_packet_size(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t count)
{
unsigned long temp;
spin_lock(&rbu_data.lock);
@@ -687,18 +692,18 @@ static ssize_t write_rbu_packet_size(struct kobject *kobj, char *buffer,
}
static struct bin_attribute rbu_data_attr = {
- .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444},
+ .attr = {.name = "data", .mode = 0444},
.read = read_rbu_data,
};
static struct bin_attribute rbu_image_type_attr = {
- .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644},
+ .attr = {.name = "image_type", .mode = 0644},
.read = read_rbu_image_type,
.write = write_rbu_image_type,
};
static struct bin_attribute rbu_packet_size_attr = {
- .attr = {.name = "packet_size",.owner = THIS_MODULE,.mode = 0644},
+ .attr = {.name = "packet_size", .mode = 0644},
.read = read_rbu_packet_size,
.write = write_rbu_packet_size,
};
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
new file mode 100644
index 000000000000..59c3b5aa89f4
--- /dev/null
+++ b/drivers/firmware/dmi-id.c
@@ -0,0 +1,222 @@
+/*
+ * Export SMBIOS/DMI info via sysfs to userspace
+ *
+ * Copyright 2007, Lennart Poettering
+ *
+ * Licensed under GPLv2
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+#include <linux/device.h>
+#include <linux/autoconf.h>
+
+#define DEFINE_DMI_ATTR(_name, _mode, _show) \
+static struct device_attribute sys_dmi_##_name##_attr = \
+ __ATTR(_name, _mode, _show, NULL);
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field) \
+static ssize_t sys_dmi_##_name##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *page) \
+{ \
+ ssize_t len; \
+ len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
+ page[len-1] = '\n'; \
+ return len; \
+} \
+DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+
+DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor, 0444, DMI_BIOS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(bios_version, 0444, DMI_BIOS_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(bios_date, 0444, DMI_BIOS_DATE);
+DEFINE_DMI_ATTR_WITH_SHOW(sys_vendor, 0444, DMI_SYS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(product_name, 0444, DMI_PRODUCT_NAME);
+DEFINE_DMI_ATTR_WITH_SHOW(product_version, 0444, DMI_PRODUCT_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(product_serial, 0400, DMI_PRODUCT_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(product_uuid, 0400, DMI_PRODUCT_UUID);
+DEFINE_DMI_ATTR_WITH_SHOW(board_vendor, 0444, DMI_BOARD_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(board_name, 0444, DMI_BOARD_NAME);
+DEFINE_DMI_ATTR_WITH_SHOW(board_version, 0444, DMI_BOARD_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(board_serial, 0400, DMI_BOARD_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(board_asset_tag, 0444, DMI_BOARD_ASSET_TAG);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_vendor, 0444, DMI_CHASSIS_VENDOR);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_type, 0444, DMI_CHASSIS_TYPE);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_version, 0444, DMI_CHASSIS_VERSION);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_serial, 0400, DMI_CHASSIS_SERIAL);
+DEFINE_DMI_ATTR_WITH_SHOW(chassis_asset_tag, 0444, DMI_CHASSIS_ASSET_TAG);
+
+static void ascii_filter(char *d, const char *s)
+{
+ /* Filter out characters we don't want to see in the modalias string */
+ for (; *s; s++)
+ if (*s > ' ' && *s < 127 && *s != ':')
+ *(d++) = *s;
+
+ *d = 0;
+}
+
+static ssize_t get_modalias(char *buffer, size_t buffer_size)
+{
+ static const struct mafield {
+ const char *prefix;
+ int field;
+ } fields[] = {
+ { "bvn", DMI_BIOS_VENDOR },
+ { "bvr", DMI_BIOS_VERSION },
+ { "bd", DMI_BIOS_DATE },
+ { "svn", DMI_SYS_VENDOR },
+ { "pn", DMI_PRODUCT_NAME },
+ { "pvr", DMI_PRODUCT_VERSION },
+ { "rvn", DMI_BOARD_VENDOR },
+ { "rn", DMI_BOARD_NAME },
+ { "rvr", DMI_BOARD_VERSION },
+ { "cvn", DMI_CHASSIS_VENDOR },
+ { "ct", DMI_CHASSIS_TYPE },
+ { "cvr", DMI_CHASSIS_VERSION },
+ { NULL, DMI_NONE }
+ };
+
+ ssize_t l, left;
+ char *p;
+ const struct mafield *f;
+
+ strcpy(buffer, "dmi");
+ p = buffer + 3; left = buffer_size - 4;
+
+ for (f = fields; f->prefix && left > 0; f++) {
+ const char *c;
+ char *t;
+
+ c = dmi_get_system_info(f->field);
+ if (!c)
+ continue;
+
+ t = kmalloc(strlen(c) + 1, GFP_KERNEL);
+ if (!t)
+ break;
+ ascii_filter(t, c);
+ l = scnprintf(p, left, ":%s%s", f->prefix, t);
+ kfree(t);
+
+ p += l;
+ left -= l;
+ }
+
+ p[0] = ':';
+ p[1] = 0;
+
+ return p - buffer + 1;
+}
+
+static ssize_t sys_dmi_modalias_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ ssize_t r;
+ r = get_modalias(page, PAGE_SIZE-1);
+ page[r] = '\n';
+ page[r+1] = 0;
+ return r+1;
+}
+
+DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+
+static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
+
+static struct attribute_group sys_dmi_attribute_group = {
+ .attrs = sys_dmi_attributes,
+};
+
+static struct attribute_group* sys_dmi_attribute_groups[] = {
+ &sys_dmi_attribute_group,
+ NULL
+};
+
+static int dmi_dev_uevent(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ strcpy(buffer, "MODALIAS=");
+ get_modalias(buffer+9, buffer_size-9);
+ envp[0] = buffer;
+ envp[1] = NULL;
+
+ return 0;
+}
+
+static struct class dmi_class = {
+ .name = "dmi",
+ .dev_release = (void(*)(struct device *)) kfree,
+ .dev_uevent = dmi_dev_uevent,
+};
+
+static struct device *dmi_dev;
+
+/* Initialization */
+
+#define ADD_DMI_ATTR(_name, _field) \
+ if (dmi_get_system_info(_field)) \
+ sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+
+extern int dmi_available;
+
+static int __init dmi_id_init(void)
+{
+ int ret, i;
+
+ if (!dmi_available)
+ return -ENODEV;
+
+ /* Not necessarily all DMI fields are available on all
+ * systems, hence let's built an attribute table of just
+ * what's available */
+ i = 0;
+ ADD_DMI_ATTR(bios_vendor, DMI_BIOS_VENDOR);
+ ADD_DMI_ATTR(bios_version, DMI_BIOS_VERSION);
+ ADD_DMI_ATTR(bios_date, DMI_BIOS_DATE);
+ ADD_DMI_ATTR(sys_vendor, DMI_SYS_VENDOR);
+ ADD_DMI_ATTR(product_name, DMI_PRODUCT_NAME);
+ ADD_DMI_ATTR(product_version, DMI_PRODUCT_VERSION);
+ ADD_DMI_ATTR(product_serial, DMI_PRODUCT_SERIAL);
+ ADD_DMI_ATTR(product_uuid, DMI_PRODUCT_UUID);
+ ADD_DMI_ATTR(board_vendor, DMI_BOARD_VENDOR);
+ ADD_DMI_ATTR(board_name, DMI_BOARD_NAME);
+ ADD_DMI_ATTR(board_version, DMI_BOARD_VERSION);
+ ADD_DMI_ATTR(board_serial, DMI_BOARD_SERIAL);
+ ADD_DMI_ATTR(board_asset_tag, DMI_BOARD_ASSET_TAG);
+ ADD_DMI_ATTR(chassis_vendor, DMI_CHASSIS_VENDOR);
+ ADD_DMI_ATTR(chassis_type, DMI_CHASSIS_TYPE);
+ ADD_DMI_ATTR(chassis_version, DMI_CHASSIS_VERSION);
+ ADD_DMI_ATTR(chassis_serial, DMI_CHASSIS_SERIAL);
+ ADD_DMI_ATTR(chassis_asset_tag, DMI_CHASSIS_ASSET_TAG);
+ sys_dmi_attributes[i++] = &sys_dmi_modalias_attr.attr;
+
+ ret = class_register(&dmi_class);
+ if (ret)
+ return ret;
+
+ dmi_dev = kzalloc(sizeof(*dmi_dev), GFP_KERNEL);
+ if (!dmi_dev) {
+ ret = -ENOMEM;
+ goto fail_class_unregister;
+ }
+
+ dmi_dev->class = &dmi_class;
+ strcpy(dmi_dev->bus_id, "id");
+ dmi_dev->groups = sys_dmi_attribute_groups;
+
+ ret = device_register(dmi_dev);
+ if (ret)
+ goto fail_class_unregister;
+
+ return 0;
+
+fail_class_unregister:
+
+ class_unregister(&dmi_class);
+
+ return ret;
+}
+
+arch_initcall(dmi_id_init);
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 37deee6c0c1c..f7318b3b51f2 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -84,6 +84,7 @@ static int __init dmi_checksum(u8 *buf)
static char *dmi_ident[DMI_STRING_MAX];
static LIST_HEAD(dmi_devices);
+int dmi_available;
/*
* Save a DMI string
@@ -102,6 +103,51 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
dmi_ident[slot] = p;
}
+static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
+{
+ u8 *d = (u8*) dm + index;
+ char *s;
+ int is_ff = 1, is_00 = 1, i;
+
+ if (dmi_ident[slot])
+ return;
+
+ for (i = 0; i < 16 && (is_ff || is_00); i++) {
+ if(d[i] != 0x00) is_ff = 0;
+ if(d[i] != 0xFF) is_00 = 0;
+ }
+
+ if (is_ff || is_00)
+ return;
+
+ s = dmi_alloc(16*2+4+1);
+ if (!s)
+ return;
+
+ sprintf(s,
+ "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7],
+ d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]);
+
+ dmi_ident[slot] = s;
+}
+
+static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
+{
+ u8 *d = (u8*) dm + index;
+ char *s;
+
+ if (dmi_ident[slot])
+ return;
+
+ s = dmi_alloc(4);
+ if (!s)
+ return;
+
+ sprintf(s, "%u", *d & 0x7F);
+ dmi_ident[slot] = s;
+}
+
static void __init dmi_save_devices(struct dmi_header *dm)
{
int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
@@ -192,11 +238,21 @@ static void __init dmi_decode(struct dmi_header *dm)
dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
+ dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8);
break;
case 2: /* Base Board Information */
dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
dmi_save_ident(dm, DMI_BOARD_NAME, 5);
dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
+ dmi_save_ident(dm, DMI_BOARD_SERIAL, 7);
+ dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8);
+ break;
+ case 3: /* Chassis Information */
+ dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4);
+ dmi_save_type(dm, DMI_CHASSIS_TYPE, 5);
+ dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6);
+ dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7);
+ dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8);
break;
case 10: /* Onboard Devices Information */
dmi_save_devices(dm);
@@ -243,18 +299,20 @@ void __init dmi_scan_machine(void)
if (efi.smbios == EFI_INVALID_TABLE_ADDR)
goto out;
- /* This is called as a core_initcall() because it isn't
- * needed during early boot. This also means we can
- * iounmap the space when we're done with it.
- */
+ /* This is called as a core_initcall() because it isn't
+ * needed during early boot. This also means we can
+ * iounmap the space when we're done with it.
+ */
p = dmi_ioremap(efi.smbios, 32);
if (p == NULL)
goto out;
rc = dmi_present(p + 0x10); /* offset of _DMI_ string */
dmi_iounmap(p, 32);
- if (!rc)
+ if (!rc) {
+ dmi_available = 1;
return;
+ }
}
else {
/*
@@ -268,8 +326,10 @@ void __init dmi_scan_machine(void)
for (q = p; q < p + 0x10000; q += 16) {
rc = dmi_present(q);
- if (!rc)
+ if (!rc) {
+ dmi_available = 1;
return;
+ }
}
}
out: printk(KERN_INFO "DMI not present or invalid.\n");
@@ -404,3 +464,4 @@ int dmi_get_year(int field)
return year;
}
+
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index d8806e4f1829..0fb730ee1da8 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -74,7 +74,7 @@ static struct edd_device *edd_devices[EDD_MBR_SIG_MAX];
#define EDD_DEVICE_ATTR(_name,_mode,_show,_test) \
struct edd_attribute edd_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.test = _test, \
};
@@ -669,7 +669,7 @@ edd_get_pci_dev(struct edd_device *edev)
struct edd_info *info = edd_dev_get_info(edev);
if (edd_dev_is_type(edev, "PCI")) {
- return pci_find_slot(info->params.interface_path.pci.bus,
+ return pci_get_bus_and_slot(info->params.interface_path.pci.bus,
PCI_DEVFN(info->params.interface_path.pci.slot,
info->params.interface_path.pci.
function));
@@ -682,9 +682,12 @@ edd_create_symlink_to_pcidev(struct edd_device *edev)
{
struct pci_dev *pci_dev = edd_get_pci_dev(edev);
+ int ret;
if (!pci_dev)
return 1;
- return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
+ ret = sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev");
+ pci_dev_put(pci_dev);
+ return ret;
}
static inline void
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 1324984a4c35..bfd2d67df689 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -131,21 +131,21 @@ struct efivar_attribute {
#define EFI_ATTR(_name, _mode, _show, _store) \
struct subsys_attribute efi_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};
#define EFIVAR_ATTR(_name, _mode, _show, _store) \
struct efivar_attribute efivar_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};
#define VAR_SUBSYS_ATTR(_name, _mode, _show, _store) \
struct subsys_attribute var_subsys_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index 2b4b76e8bd72..58e9f8e457f8 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -15,6 +15,7 @@
#include <linux/console.h>
#include <linux/efi.h>
#include <linux/serial.h>
+#include <linux/serial_8250.h>
#include <asm/vga.h>
#include "pcdp.h"
@@ -27,7 +28,7 @@ setup_serial_console(struct pcdp_uart *uart)
char parity;
mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
- p += sprintf(p, "console=uart,%s,0x%lx",
+ p += sprintf(p, "uart8250,%s,0x%lx",
mmio ? "mmio" : "io", uart->addr.address);
if (uart->baud) {
p += sprintf(p, ",%lu", uart->baud);
@@ -41,7 +42,8 @@ setup_serial_console(struct pcdp_uart *uart)
}
}
- return early_serial_console_init(options);
+ add_preferred_console("uart", 8250, &options[9]);
+ return setup_early_serial8250_console(options);
#else
return -ENODEV;
#endif
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 3afa4a5035b7..b2baeaeba9be 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1009,20 +1009,22 @@ static int hid_resume(struct usb_interface *intf)
}
/* Treat USB reset pretty much the same as suspend/resume */
-static void hid_pre_reset(struct usb_interface *intf)
+static int hid_pre_reset(struct usb_interface *intf)
{
/* FIXME: What if the interface is already suspended? */
hid_suspend(intf, PMSG_ON);
+ return 0;
}
-static void hid_post_reset(struct usb_interface *intf)
+/* Same routine used for post_reset and reset_resume */
+static int hid_post_reset(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev (intf);
hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
/* FIXME: Any more reinitialization needed? */
- hid_resume(intf);
+ return hid_resume(intf);
}
static struct usb_device_id hid_usb_ids [] = {
@@ -1039,6 +1041,7 @@ static struct usb_driver hid_driver = {
.disconnect = hid_disconnect,
.suspend = hid_suspend,
.resume = hid_resume,
+ .reset_resume = hid_post_reset,
.pre_reset = hid_pre_reset,
.post_reset = hid_post_reset,
.id_table = hid_usb_ids,
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 13eea47dceb3..dbdca6f10e46 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -29,17 +29,34 @@ config HWMON_VID
default n
config SENSORS_ABITUGURU
- tristate "Abit uGuru"
+ tristate "Abit uGuru (rev 1 & 2)"
depends on EXPERIMENTAL
help
- If you say yes here you get support for the Abit uGuru chips
- sensor part. The voltage and frequency control parts of the Abit
- uGuru are not supported. The Abit uGuru chip can be found on Abit
- uGuru featuring motherboards (most modern Abit motherboards).
+ If you say yes here you get support for the sensor part of the first
+ and second revision of the Abit uGuru chip. The voltage and frequency
+ control parts of the Abit uGuru are not supported. The Abit uGuru
+ chip can be found on Abit uGuru featuring motherboards (most modern
+ Abit motherboards from before end 2005). For more info and a list
+ of which motherboards have which revision see
+ Documentation/hwmon/abituguru
This driver can also be built as a module. If so, the module
will be called abituguru.
+config SENSORS_ABITUGURU3
+ tristate "Abit uGuru (rev 3)"
+ depends on HWMON && EXPERIMENTAL
+ help
+ If you say yes here you get support for the sensor part of the
+ third revision of the Abit uGuru chip. Only reading the sensors
+ and their settings is supported. The third revision of the Abit
+ uGuru chip can be found on recent Abit motherboards (since end
+ 2005). For more info and a list of which motherboards have which
+ revision see Documentation/hwmon/abituguru3
+
+ This driver can also be built as a module. If so, the module
+ will be called abituguru3.
+
config SENSORS_AD7418
tristate "Analog Devices AD7416, AD7417 and AD7418"
depends on I2C && EXPERIMENTAL
@@ -250,12 +267,10 @@ config SENSORS_CORETEMP
config SENSORS_IT87
tristate "ITE IT87xx and compatibles"
- depends on I2C
- select I2C_ISA
select HWMON_VID
help
If you say yes here you get support for ITE IT8705F, IT8712F,
- IT8716F and IT8718F sensor chips, and the SiS960 clone.
+ IT8716F, IT8718F and IT8726F sensor chips, and the SiS960 clone.
This driver can also be built as a module. If so, the module
will be called it87.
@@ -365,8 +380,8 @@ config SENSORS_LM90
depends on I2C
help
If you say yes here you get support for National Semiconductor LM90,
- LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
- MAX6658 sensor chips.
+ LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657,
+ MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
The Analog Devices ADT7461 sensor chip is also supported, but only
if found in ADM1032 compatibility mode.
@@ -384,6 +399,17 @@ config SENSORS_LM92
This driver can also be built as a module. If so, the module
will be called lm92.
+config SENSORS_LM93
+ tristate "National Semiconductor LM93 and compatibles"
+ depends on HWMON && I2C
+ select HWMON_VID
+ help
+ If you say yes here you get support for National Semiconductor LM93
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm93.
+
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on I2C
@@ -405,8 +431,6 @@ config SENSORS_MAX6650
config SENSORS_PC87360
tristate "National Semiconductor PC87360 family"
- depends on I2C && EXPERIMENTAL
- select I2C_ISA
select HWMON_VID
help
If you say yes here you get access to the hardware monitoring
@@ -433,8 +457,7 @@ config SENSORS_PC87427
config SENSORS_SIS5595
tristate "Silicon Integrated Systems Corp. SiS5595"
- depends on I2C && PCI && EXPERIMENTAL
- select I2C_ISA
+ depends on PCI
help
If you say yes here you get support for the integrated sensors in
SiS5595 South Bridges.
@@ -442,6 +465,18 @@ config SENSORS_SIS5595
This driver can also be built as a module. If so, the module
will be called sis5595.
+config SENSORS_DME1737
+ tristate "SMSC DME1737 and compatibles"
+ depends on I2C && EXPERIMENTAL
+ select HWMON_VID
+ help
+ If you say yes here you get support for the hardware monitoring
+ and fan control features of the SMSC DME1737 (and compatibles
+ like the Asus A8000) Super-I/O chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called dme1737.
+
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
help
@@ -487,8 +522,7 @@ config SENSORS_SMSC47B397
config SENSORS_VIA686A
tristate "VIA686A"
- depends on I2C && PCI
- select I2C_ISA
+ depends on PCI
help
If you say yes here you get support for the integrated sensors in
Via 686A/B South Bridges.
@@ -509,9 +543,8 @@ config SENSORS_VT1211
config SENSORS_VT8231
tristate "VIA VT8231"
- depends on I2C && PCI && EXPERIMENTAL
+ depends on PCI
select HWMON_VID
- select I2C_ISA
help
If you say yes here then you get support for the integrated sensors
in the VIA VT8231 device.
@@ -584,17 +617,16 @@ config SENSORS_W83627HF
will be called w83627hf.
config SENSORS_W83627EHF
- tristate "Winbond W83627EHF"
- depends on I2C && EXPERIMENTAL
- select I2C_ISA
+ tristate "Winbond W83627EHF/DHG"
+ select HWMON_VID
help
- If you say yes here you get preliminary support for the hardware
+ If you say yes here you get support for the hardware
monitoring functionality of the Winbond W83627EHF Super-I/O chip.
- Only fan and temperature inputs are supported at the moment, while
- the chip does much more than that.
This driver also supports the W83627EHG, which is the lead-free
- version of the W83627EHF.
+ version of the W83627EHF, and the W83627DHG, which is a similar
+ chip suited for specific Intel processors that use PECI such as
+ the Core 2 Duo.
This driver can also be built as a module. If so, the module
will be called w83627ehf.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index cfaf338919dd..59f81fae40a0 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
obj-$(CONFIG_SENSORS_W83791D) += w83791d.o
obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o
+obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
obj-$(CONFIG_SENSORS_AD7418) += ad7418.o
obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
obj-$(CONFIG_SENSORS_AMS) += ams/
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
+obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
@@ -45,6 +47,7 @@ obj-$(CONFIG_SENSORS_LM85) += lm85.o
obj-$(CONFIG_SENSORS_LM87) += lm87.o
obj-$(CONFIG_SENSORS_LM90) += lm90.o
obj-$(CONFIG_SENSORS_LM92) += lm92.o
+obj-$(CONFIG_SENSORS_LM93) += lm93.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index bede4d990ea6..d575ee958de5 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -16,9 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
- This driver supports the sensor part of the custom Abit uGuru chip found
- on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
- etc voltage & frequency control is not supported!
+ This driver supports the sensor part of the first and second revision of
+ the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
+ of lack of specs the CPU/RAM voltage & frequency control is not supported!
*/
#include <linux/module.h>
#include <linux/sched.h>
@@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
#include <asm/io.h>
/* Banks */
@@ -418,7 +419,7 @@ static int __devinit
abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
u8 sensor_addr)
{
- u8 val, buf[3];
+ u8 val, test_flag, buf[3];
int i, ret = -ENODEV; /* error is the most common used retval :| */
/* If overriden by the user return the user selected type */
@@ -436,7 +437,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
return -ENODEV;
/* Test val is sane / usable for sensor type detection. */
- if ((val < 10u) || (val > 240u)) {
+ if ((val < 10u) || (val > 250u)) {
printk(KERN_WARNING ABIT_UGURU_NAME
": bank1-sensor: %d reading (%d) too close to limits, "
"unable to determine sensor type, skipping sensor\n",
@@ -449,10 +450,20 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
/* Volt sensor test, enable volt low alarm, set min value ridicously
- high. If its a volt sensor this should always give us an alarm. */
- buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
- buf[1] = 245;
- buf[2] = 250;
+ high, or vica versa if the reading is very high. If its a volt
+ sensor this should always give us an alarm. */
+ if (val <= 240u) {
+ buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
+ buf[1] = 245;
+ buf[2] = 250;
+ test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG;
+ } else {
+ buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE;
+ buf[1] = 5;
+ buf[2] = 10;
+ test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG;
+ }
+
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
buf, 3) != 3)
goto abituguru_detect_bank1_sensor_type_exit;
@@ -469,13 +480,13 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
sensor_addr, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
goto abituguru_detect_bank1_sensor_type_exit;
- if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+ if (buf[0] & test_flag) {
ABIT_UGURU_DEBUG(2, " found volt sensor\n");
ret = ABIT_UGURU_IN_SENSOR;
goto abituguru_detect_bank1_sensor_type_exit;
} else
ABIT_UGURU_DEBUG(2, " alarm raised during volt "
- "sensor test, but volt low flag not set\n");
+ "sensor test, but volt range flag not set\n");
} else
ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor "
"test\n");
@@ -1287,6 +1298,7 @@ abituguru_probe_error:
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return res;
}
@@ -1296,13 +1308,13 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
int i;
struct abituguru_data *data = platform_get_drvdata(pdev);
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
device_remove_file(&pdev->dev,
&abituguru_sysfs_attr[i].dev_attr);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -1436,6 +1448,15 @@ static int __init abituguru_init(void)
int address, err;
struct resource res = { .flags = IORESOURCE_IO };
+#ifdef CONFIG_DMI
+ char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+
+ /* safety check, refuse to load on non Abit motherboards */
+ if (!force && (!board_vendor ||
+ strcmp(board_vendor, "http://www.abit.com.tw/")))
+ return -ENODEV;
+#endif
+
address = abituguru_detect();
if (address < 0)
return address;
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
new file mode 100644
index 000000000000..a003d104ca45
--- /dev/null
+++ b/drivers/hwmon/abituguru3.c
@@ -0,0 +1,1140 @@
+/*
+ abituguru3.c Copyright (c) 2006 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+ This driver supports the sensor part of revision 3 of the custom Abit uGuru
+ chip found on newer Abit uGuru motherboards. Note: because of lack of specs
+ only reading the sensors and their settings is supported.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+
+/* uGuru3 bank addresses */
+#define ABIT_UGURU3_SETTINGS_BANK 0x01
+#define ABIT_UGURU3_SENSORS_BANK 0x08
+#define ABIT_UGURU3_MISC_BANK 0x09
+#define ABIT_UGURU3_ALARMS_START 0x1E
+#define ABIT_UGURU3_SETTINGS_START 0x24
+#define ABIT_UGURU3_VALUES_START 0x80
+#define ABIT_UGURU3_BOARD_ID 0x0A
+/* uGuru3 sensor bank flags */ /* Alarm if: */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE 0x01 /* temp over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE 0x02 /* volt over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE 0x04 /* volt under min */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_FLAG 0x10 /* temp is over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG 0x20 /* volt is over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_FLAG 0x40 /* volt is under min */
+#define ABIT_UGURU3_FAN_LOW_ALARM_ENABLE 0x01 /* fan under min */
+#define ABIT_UGURU3_BEEP_ENABLE 0x08 /* beep if alarm */
+#define ABIT_UGURU3_SHUTDOWN_ENABLE 0x80 /* shutdown if alarm */
+/* sensor types */
+#define ABIT_UGURU3_IN_SENSOR 0
+#define ABIT_UGURU3_TEMP_SENSOR 1
+#define ABIT_UGURU3_FAN_SENSOR 2
+
+/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
+ convert them to params. Determined by trial and error. I assume this is
+ cpu-speed independent, since the ISA-bus and not the CPU should be the
+ bottleneck. */
+#define ABIT_UGURU3_WAIT_TIMEOUT 250
+/* Normally the 0xAC at the end of synchronize() is reported after the
+ first read, but sometimes not and we need to poll */
+#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT 5
+/* utility macros */
+#define ABIT_UGURU3_NAME "abituguru3"
+#define ABIT_UGURU3_DEBUG(format, arg...) \
+ if (verbose) \
+ printk(KERN_DEBUG ABIT_UGURU3_NAME ": " format , ## arg)
+
+/* Macros to help calculate the sysfs_names array length */
+#define ABIT_UGURU3_MAX_NO_SENSORS 26
+/* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
+ in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 */
+#define ABIT_UGURU3_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
+/* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
+ temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
+ temp??_label\0 */
+#define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
+/* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
+ fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 */
+#define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
+/* Worst case scenario 16 in sensors (longest names_length) and the rest
+ temp sensors (second longest names_length). */
+#define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
+ (ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
+
+/* All the macros below are named identical to the openguru2 program
+ reverse engineered by Louis Kruger, hence the names might not be 100%
+ logical. I could come up with better names, but I prefer keeping the names
+ identical so that this driver can be compared with his work more easily. */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU3_BASE 0x00E0
+#define ABIT_UGURU3_CMD 0x00
+#define ABIT_UGURU3_DATA 0x04
+#define ABIT_UGURU3_REGION_LENGTH 5
+/* The wait_xxx functions return this on success and the last contents
+ of the DATA register (0-255) on failure. */
+#define ABIT_UGURU3_SUCCESS -1
+/* uGuru status flags */
+#define ABIT_UGURU3_STATUS_READY_FOR_READ 0x01
+#define ABIT_UGURU3_STATUS_BUSY 0x02
+
+
+/* Structures */
+struct abituguru3_sensor_info {
+ const char* name;
+ int port;
+ int type;
+ int multiplier;
+ int divisor;
+ int offset;
+};
+
+struct abituguru3_motherboard_info {
+ u16 id;
+ const char *name;
+ /* + 1 -> end of sensors indicated by a sensor with name == NULL */
+ struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
+};
+
+/* For the Abit uGuru, we need to keep some data in memory.
+ The structure is dynamically allocated, at the same time when a new
+ abituguru3 device is allocated. */
+struct abituguru3_data {
+ struct class_device *class_dev; /* hwmon registered device */
+ struct mutex update_lock; /* protect access to data and uGuru */
+ unsigned short addr; /* uguru base address */
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* For convenience the sysfs attr and their names are generated
+ automatically. We have max 10 entries per sensor (for in sensors) */
+ struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
+ * 10];
+
+ /* Buffer to store the dynamically generated sysfs names */
+ char sysfs_names[ABIT_UGURU3_SYSFS_NAMES_LENGTH];
+
+ /* Pointer to the sensors info for the detected motherboard */
+ const struct abituguru3_sensor_info *sensors;
+
+ /* The abituguru3 supports upto 48 sensors, and thus has registers
+ sets for 48 sensors, for convienence reasons / simplicity of the
+ code we always read and store all registers for all 48 sensors */
+
+ /* Alarms for all 48 sensors (1 bit per sensor) */
+ u8 alarms[48/8];
+
+ /* Value of all 48 sensors */
+ u8 value[48];
+
+ /* Settings of all 48 sensors, note in and temp sensors (the first 32
+ sensors) have 3 bytes of settings, while fans only have 2 bytes,
+ for convenience we use 3 bytes for all sensors */
+ u8 settings[48][3];
+};
+
+
+/* Constants */
+static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
+ { 0x000C, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS FAN", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x000D, "Abit AW8", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM1", 26, 1, 1, 1, 0 },
+ { "PWM2", 27, 1, 1, 1, 0 },
+ { "PWM3", 28, 1, 1, 1, 0 },
+ { "PWM4", 29, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { "AUX3 Fan", 37, 2, 60, 1, 0 },
+ { "AUX4 Fan", 38, 2, 60, 1, 0 },
+ { "AUX5 Fan", 39, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x000E, "AL-8", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x000F, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0010, "Abit NI8 SLI GR", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "NB 1.4V", 4, 0, 10, 1, 0 },
+ { "SB 1.5V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "SYS", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "OTES1 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0011, "Abit AT8 32X", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 20, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 6, 0, 20, 1, 0 },
+ { "NB 1.8V", 4, 0, 10, 1, 0 },
+ { "NB 1.8V Dual", 5, 0, 10, 1, 0 },
+ { "HTV 1.2", 3, 0, 10, 1, 0 },
+ { "PCIE 1.2V", 12, 0, 10, 1, 0 },
+ { "NB 1.2V", 13, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "NB", 25, 1, 1, 1, 0 },
+ { "System", 26, 1, 1, 1, 0 },
+ { "PWM", 27, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0012, "Abit AN8 32X", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 20, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "HyperTransport", 3, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
+ { "NB", 4, 0, 10, 1, 0 },
+ { "SB", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "SYS", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0013, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM1", 26, 1, 1, 1, 0 },
+ { "PWM2", 27, 1, 1, 1, 0 },
+ { "PWM3", 28, 1, 1, 1, 0 },
+ { "PWM4", 29, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { "AUX3 Fan", 37, 2, 60, 1, 0 },
+ { "AUX4 Fan", 38, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0014, "Abit AB9 Pro", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 10, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0015, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR", 1, 0, 20, 1, 0 },
+ { "DDR VTT", 2, 0, 10, 1, 0 },
+ { "HyperTransport", 3, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 5, 0, 20, 1, 0 },
+ { "NB", 4, 0, 10, 1, 0 },
+ { "SB", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "SYS", 25, 1, 1, 1, 0 },
+ { "PWM", 26, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0016, "AW9D-MAX", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH & PCIE 1.5V", 4, 0, 10, 1, 0 },
+ { "MCH 2.5V", 5, 0, 20, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM1", 26, 1, 1, 1, 0 },
+ { "PWM2", 27, 1, 1, 1, 0 },
+ { "PWM3", 28, 1, 1, 1, 0 },
+ { "PWM4", 29, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "NB Fan", 33, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 35, 2, 60, 1, 0 },
+ { "AUX2 Fan", 36, 2, 60, 1, 0 },
+ { "AUX3 Fan", 37, 2, 60, 1, 0 },
+ { "OTES1 Fan", 38, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0017, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "HyperTransport", 3, 0, 10, 1, 0 },
+ { "CPU VDDA 2.5V", 6, 0, 20, 1, 0 },
+ { "NB 1.8V", 4, 0, 10, 1, 0 },
+ { "NB 1.2V ", 13, 0, 10, 1, 0 },
+ { "SB 1.2V", 5, 0, 10, 1, 0 },
+ { "PCIE 1.2V", 12, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "ATX +3.3V", 10, 0, 20, 1, 0 },
+ { "ATX 5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 26, 1, 1, 1, 0 },
+ { "PWM", 27, 1, 1, 1, 0 },
+ { "CPU FAN", 32, 2, 60, 1, 0 },
+ { "SYS FAN", 34, 2, 60, 1, 0 },
+ { "AUX1 FAN", 35, 2, 60, 1, 0 },
+ { "AUX2 FAN", 36, 2, 60, 1, 0 },
+ { "AUX3 FAN", 37, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0018, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT", 3, 0, 10, 1, 0 },
+ { "MCH 1.25V", 4, 0, 10, 1, 0 },
+ { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM Phase1", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0019, "unknown", {
+ { "CPU Core", 7, 0, 10, 1, 0 },
+ { "DDR2", 13, 0, 20, 1, 0 },
+ { "DDR2 VTT", 14, 0, 10, 1, 0 },
+ { "CPU VTT", 3, 0, 20, 1, 0 },
+ { "NB 1.2V ", 4, 0, 10, 1, 0 },
+ { "SB 1.5V", 6, 0, 10, 1, 0 },
+ { "HyperTransport", 5, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 12, 0, 60, 1, 0 },
+ { "ATX +12V (4-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "ATX +3.3V", 10, 0, 20, 1, 0 },
+ { "ATX 5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM Phase1", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU FAN", 32, 2, 60, 1, 0 },
+ { "SYS FAN", 34, 2, 60, 1, 0 },
+ { "AUX1 FAN", 33, 2, 60, 1, 0 },
+ { "AUX2 FAN", 35, 2, 60, 1, 0 },
+ { "AUX3 FAN", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x001A, "unknown", {
+ { "CPU Core", 0, 0, 10, 1, 0 },
+ { "DDR2", 1, 0, 20, 1, 0 },
+ { "DDR2 VTT", 2, 0, 10, 1, 0 },
+ { "CPU VTT 1.2V", 3, 0, 10, 1, 0 },
+ { "MCH 1.25V", 4, 0, 10, 1, 0 },
+ { "ICHIO 1.5V", 5, 0, 10, 1, 0 },
+ { "ICH 1.05V", 6, 0, 10, 1, 0 },
+ { "ATX +12V (24-Pin)", 7, 0, 60, 1, 0 },
+ { "ATX +12V (8-pin)", 8, 0, 60, 1, 0 },
+ { "ATX +5V", 9, 0, 30, 1, 0 },
+ { "+3.3V", 10, 0, 20, 1, 0 },
+ { "5VSB", 11, 0, 30, 1, 0 },
+ { "CPU", 24, 1, 1, 1, 0 },
+ { "System ", 25, 1, 1, 1, 0 },
+ { "PWM ", 26, 1, 1, 1, 0 },
+ { "PWM Phase2", 27, 1, 1, 1, 0 },
+ { "PWM Phase3", 28, 1, 1, 1, 0 },
+ { "PWM Phase4", 29, 1, 1, 1, 0 },
+ { "PWM Phase5", 30, 1, 1, 1, 0 },
+ { "CPU Fan", 32, 2, 60, 1, 0 },
+ { "SYS Fan", 34, 2, 60, 1, 0 },
+ { "AUX1 Fan", 33, 2, 60, 1, 0 },
+ { "AUX2 Fan", 35, 2, 60, 1, 0 },
+ { "AUX3 Fan", 36, 2, 60, 1, 0 },
+ { NULL, 0, 0, 0, 0, 0 } }
+ },
+ { 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } }
+};
+
+
+/* Insmod parameters */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+/* Default verbose is 1, since this driver is still in the testing phase */
+static int verbose = 1;
+module_param(verbose, bool, 0644);
+MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
+
+
+/* wait while the uguru is busy (usually after a write) */
+static int abituguru3_wait_while_busy(struct abituguru3_data *data)
+{
+ u8 x;
+ int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+ while ((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+ ABIT_UGURU3_STATUS_BUSY) {
+ timeout--;
+ if (timeout == 0)
+ return x;
+ /* sleep a bit before our last try, to give the uGuru3 one
+ last chance to respond. */
+ if (timeout == 1)
+ msleep(1);
+ }
+ return ABIT_UGURU3_SUCCESS;
+}
+
+/* wait till uguru is ready to be read */
+static int abituguru3_wait_for_read(struct abituguru3_data *data)
+{
+ u8 x;
+ int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+ while (!((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+ ABIT_UGURU3_STATUS_READY_FOR_READ)) {
+ timeout--;
+ if (timeout == 0)
+ return x;
+ /* sleep a bit before our last try, to give the uGuru3 one
+ last chance to respond. */
+ if (timeout == 1)
+ msleep(1);
+ }
+ return ABIT_UGURU3_SUCCESS;
+}
+
+/* This synchronizes us with the uGuru3's protocol state machine, this
+ must be done before each command. */
+static int abituguru3_synchronize(struct abituguru3_data *data)
+{
+ int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
+
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
+ "wait, status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ outb(0x20, data->addr + ABIT_UGURU3_DATA);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ outb(0x10, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ outb(0x00, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ if ((x = abituguru3_wait_for_read(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
+ "status: 0x%02x\n", x);
+ return -EIO;
+ }
+
+ while ((x = inb(data->addr + ABIT_UGURU3_CMD)) != 0xAC) {
+ timeout--;
+ if (timeout == 0) {
+ ABIT_UGURU3_DEBUG("synchronize timeout cmd does not "
+ "hold 0xAC after synchronize, cmd: 0x%02x\n",
+ x);
+ return -EIO;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
+ result in buf */
+static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
+ u8 count, u8 *buf)
+{
+ int i, x;
+
+ if ((x = abituguru3_synchronize(data)))
+ return x;
+
+ outb(0x1A, data->addr + ABIT_UGURU3_DATA);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
+ (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ outb(bank, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending the bank, status: 0x%02x\n",
+ (unsigned int)bank, (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ outb(offset, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending the offset, status: 0x%02x\n",
+ (unsigned int)bank, (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ outb(count, data->addr + ABIT_UGURU3_CMD);
+ if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+ "sending the count, status: 0x%02x\n",
+ (unsigned int)bank, (unsigned int)offset, x);
+ return -EIO;
+ }
+
+ for (i = 0; i < count; i++) {
+ if ((x = abituguru3_wait_for_read(data)) !=
+ ABIT_UGURU3_SUCCESS) {
+ ABIT_UGURU3_DEBUG("timeout reading byte %d from "
+ "0x%02x:0x%02x, status: 0x%02x\n", i,
+ (unsigned int)bank, (unsigned int)offset, x);
+ break;
+ }
+ buf[i] = inb(data->addr + ABIT_UGURU3_CMD);
+ }
+ return i;
+}
+
+/* Sensor settings are stored 1 byte per offset with the bytes
+ placed add consecutive offsets. */
+int abituguru3_read_increment_offset(struct abituguru3_data *data, u8 bank,
+ u8 offset, u8 count, u8 *buf, int offset_count)
+{
+ int i, x;
+
+ for (i = 0; i < offset_count; i++)
+ if ((x = abituguru3_read(data, bank, offset + i, count,
+ buf + i * count)) != count)
+ return i * count + (i && (x < 0)) ? 0 : x;
+
+ return i * count;
+}
+
+/* Following are the sysfs callback functions. These functions expect:
+ sensor_device_attribute_2->index: index into the data->sensors array
+ sensor_device_attribute_2->nr: register offset, bitmask or NA. */
+static struct abituguru3_data *abituguru3_update_device(struct device *dev);
+
+static ssize_t show_value(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int value;
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = abituguru3_update_device(dev);
+ const struct abituguru3_sensor_info *sensor;
+
+ if (!data)
+ return -EIO;
+
+ sensor = &data->sensors[attr->index];
+
+ /* are we reading a setting, or is this a normal read? */
+ if (attr->nr)
+ value = data->settings[sensor->port][attr->nr];
+ else
+ value = data->value[sensor->port];
+
+ /* convert the value */
+ value = (value * sensor->multiplier) / sensor->divisor +
+ sensor->offset;
+
+ /* alternatively we could update the sensors settings struct for this,
+ but then its contents would differ from the windows sw ini files */
+ if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
+ value *= 1000;
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t show_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ int port;
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = abituguru3_update_device(dev);
+
+ if (!data)
+ return -EIO;
+
+ port = data->sensors[attr->index].port;
+
+ /* See if the alarm bit for this sensor is set and if a bitmask is
+ given in attr->nr also check if the alarm matches the type of alarm
+ we're looking for (for volt it can be either low or high). The type
+ is stored in a few readonly bits in the settings of the sensor. */
+ if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
+ (!attr->nr || (data->settings[port][0] & attr->nr)))
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_mask(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = dev_get_drvdata(dev);
+
+ if (data->settings[data->sensors[attr->index].port][0] & attr->nr)
+ return sprintf(buf, "1\n");
+ else
+ return sprintf(buf, "0\n");
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ struct abituguru3_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->sensors[attr->index].name);
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "%s\n", ABIT_UGURU3_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru3_sysfs_templ[3][10] = { {
+ SENSOR_ATTR_2(in%d_input, 0444, show_value, NULL, 0, 0),
+ SENSOR_ATTR_2(in%d_min, 0444, show_value, NULL, 1, 0),
+ SENSOR_ATTR_2(in%d_max, 0444, show_value, NULL, 2, 0),
+ SENSOR_ATTR_2(in%d_min_alarm, 0444, show_alarm, NULL,
+ ABIT_UGURU3_VOLT_LOW_ALARM_FLAG, 0),
+ SENSOR_ATTR_2(in%d_max_alarm, 0444, show_alarm, NULL,
+ ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG, 0),
+ SENSOR_ATTR_2(in%d_beep, 0444, show_mask, NULL,
+ ABIT_UGURU3_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_shutdown, 0444, show_mask, NULL,
+ ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_min_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_max_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(in%d_label, 0444, show_label, NULL, 0, 0)
+ }, {
+ SENSOR_ATTR_2(temp%d_input, 0444, show_value, NULL, 0, 0),
+ SENSOR_ATTR_2(temp%d_max, 0444, show_value, NULL, 1, 0),
+ SENSOR_ATTR_2(temp%d_crit, 0444, show_value, NULL, 2, 0),
+ SENSOR_ATTR_2(temp%d_alarm, 0444, show_alarm, NULL, 0, 0),
+ SENSOR_ATTR_2(temp%d_beep, 0444, show_mask, NULL,
+ ABIT_UGURU3_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_shutdown, 0444, show_mask, NULL,
+ ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(temp%d_label, 0444, show_label, NULL, 0, 0)
+ }, {
+ SENSOR_ATTR_2(fan%d_input, 0444, show_value, NULL, 0, 0),
+ SENSOR_ATTR_2(fan%d_min, 0444, show_value, NULL, 1, 0),
+ SENSOR_ATTR_2(fan%d_alarm, 0444, show_alarm, NULL, 0, 0),
+ SENSOR_ATTR_2(fan%d_beep, 0444, show_mask, NULL,
+ ABIT_UGURU3_BEEP_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_shutdown, 0444, show_mask, NULL,
+ ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_alarm_enable, 0444, show_mask, NULL,
+ ABIT_UGURU3_FAN_LOW_ALARM_ENABLE, 0),
+ SENSOR_ATTR_2(fan%d_label, 0444, show_label, NULL, 0, 0)
+} };
+
+static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = {
+ SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int __devinit abituguru3_probe(struct platform_device *pdev)
+{
+ const int no_sysfs_attr[3] = { 10, 8, 7 };
+ int sensor_index[3] = { 0, 1, 1 };
+ struct abituguru3_data *data;
+ int i, j, type, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+ char *sysfs_filename;
+ u8 buf[2];
+ u16 id;
+
+ if (!(data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL)))
+ return -ENOMEM;
+
+ data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+ mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
+
+ /* Read the motherboard ID */
+ if ((i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK,
+ ABIT_UGURU3_BOARD_ID, 2, buf)) != 2) {
+ goto abituguru3_probe_error;
+ }
+
+ /* Completely read the uGuru to see if one really is there */
+ if (!abituguru3_update_device(&pdev->dev))
+ goto abituguru3_probe_error;
+
+ /* lookup the ID in our motherboard table */
+ id = ((u16)buf[0] << 8) | (u16)buf[1];
+ for (i = 0; abituguru3_motherboards[i].id; i++)
+ if (abituguru3_motherboards[i].id == id)
+ break;
+ if (!abituguru3_motherboards[i].id) {
+ printk(KERN_ERR ABIT_UGURU3_NAME ": error unknown motherboard "
+ "ID: %04X. Please report this to the abituguru3 "
+ "maintainer (see MAINTAINERS)\n", (unsigned int)id);
+ goto abituguru3_probe_error;
+ }
+ data->sensors = abituguru3_motherboards[i].sensors;
+ printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
+ "ID: %04X (%s)\n", (unsigned int)id,
+ abituguru3_motherboards[i].name);
+
+ /* Fill the sysfs attr array */
+ sysfs_attr_i = 0;
+ sysfs_filename = data->sysfs_names;
+ sysfs_names_free = ABIT_UGURU3_SYSFS_NAMES_LENGTH;
+ for (i = 0; data->sensors[i].name; i++) {
+ /* Fail safe check, this should never happen! */
+ if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Fatal error motherboard has more sensors "
+ "then ABIT_UGURU3_MAX_NO_SENSORS. This should "
+ "never happen please report to the abituguru3 "
+ "maintainer (see MAINTAINERS)\n");
+ res = -ENAMETOOLONG;
+ goto abituguru3_probe_error;
+ }
+ type = data->sensors[i].type;
+ for (j = 0; j < no_sysfs_attr[type]; j++) {
+ used = snprintf(sysfs_filename, sysfs_names_free,
+ abituguru3_sysfs_templ[type][j].dev_attr.attr.
+ name, sensor_index[type]) + 1;
+ data->sysfs_attr[sysfs_attr_i] =
+ abituguru3_sysfs_templ[type][j];
+ data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+ sysfs_filename;
+ data->sysfs_attr[sysfs_attr_i].index = i;
+ sysfs_filename += used;
+ sysfs_names_free -= used;
+ sysfs_attr_i++;
+ }
+ sensor_index[type]++;
+ }
+ /* Fail safe check, this should never happen! */
+ if (sysfs_names_free < 0) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Fatal error ran out of space for sysfs attr names. "
+ "This should never happen please report to the "
+ "abituguru3 maintainer (see MAINTAINERS)\n");
+ res = -ENAMETOOLONG;
+ goto abituguru3_probe_error;
+ }
+
+ /* Register sysfs hooks */
+ for (i = 0; i < sysfs_attr_i; i++)
+ if (device_create_file(&pdev->dev,
+ &data->sysfs_attr[i].dev_attr))
+ goto abituguru3_probe_error;
+ for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+ if (device_create_file(&pdev->dev,
+ &abituguru3_sysfs_attr[i].dev_attr))
+ goto abituguru3_probe_error;
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ res = PTR_ERR(data->class_dev);
+ goto abituguru3_probe_error;
+ }
+
+ return 0; /* success */
+
+abituguru3_probe_error:
+ for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+ device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+ device_remove_file(&pdev->dev,
+ &abituguru3_sysfs_attr[i].dev_attr);
+ kfree(data);
+ return res;
+}
+
+static int __devexit abituguru3_remove(struct platform_device *pdev)
+{
+ int i;
+ struct abituguru3_data *data = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ hwmon_device_unregister(data->class_dev);
+ for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+ device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+ device_remove_file(&pdev->dev,
+ &abituguru3_sysfs_attr[i].dev_attr);
+ kfree(data);
+
+ return 0;
+}
+
+static struct abituguru3_data *abituguru3_update_device(struct device *dev)
+{
+ int i;
+ struct abituguru3_data *data = dev_get_drvdata(dev);
+
+ mutex_lock(&data->update_lock);
+ if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+ /* Clear data->valid while updating */
+ data->valid = 0;
+ /* Read alarms */
+ if (abituguru3_read_increment_offset(data,
+ ABIT_UGURU3_SETTINGS_BANK,
+ ABIT_UGURU3_ALARMS_START,
+ 1, data->alarms, 48/8) != (48/8))
+ goto LEAVE_UPDATE;
+ /* Read in and temp sensors (3 byte settings / sensor) */
+ for (i = 0; i < 32; i++) {
+ if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+ ABIT_UGURU3_VALUES_START + i,
+ 1, &data->value[i]) != 1)
+ goto LEAVE_UPDATE;
+ if (abituguru3_read_increment_offset(data,
+ ABIT_UGURU3_SETTINGS_BANK,
+ ABIT_UGURU3_SETTINGS_START + i * 3,
+ 1,
+ data->settings[i], 3) != 3)
+ goto LEAVE_UPDATE;
+ }
+ /* Read temp sensors (2 byte settings / sensor) */
+ for (i = 0; i < 16; i++) {
+ if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+ ABIT_UGURU3_VALUES_START + 32 + i,
+ 1, &data->value[32 + i]) != 1)
+ goto LEAVE_UPDATE;
+ if (abituguru3_read_increment_offset(data,
+ ABIT_UGURU3_SETTINGS_BANK,
+ ABIT_UGURU3_SETTINGS_START + 32 * 3 +
+ i * 2, 1,
+ data->settings[32 + i], 2) != 2)
+ goto LEAVE_UPDATE;
+ }
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+LEAVE_UPDATE:
+ mutex_unlock(&data->update_lock);
+ if (data->valid)
+ return data;
+ else
+ return NULL;
+}
+
+#ifdef CONFIG_PM
+static int abituguru3_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct abituguru3_data *data = platform_get_drvdata(pdev);
+ /* make sure all communications with the uguru3 are done and no new
+ ones are started */
+ mutex_lock(&data->update_lock);
+ return 0;
+}
+
+static int abituguru3_resume(struct platform_device *pdev)
+{
+ struct abituguru3_data *data = platform_get_drvdata(pdev);
+ mutex_unlock(&data->update_lock);
+ return 0;
+}
+#else
+#define abituguru3_suspend NULL
+#define abituguru3_resume NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver abituguru3_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = ABIT_UGURU3_NAME,
+ },
+ .probe = abituguru3_probe,
+ .remove = __devexit_p(abituguru3_remove),
+ .suspend = abituguru3_suspend,
+ .resume = abituguru3_resume
+};
+
+static int __init abituguru3_detect(void)
+{
+ /* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
+ 0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
+ at CMD instead, why is unknown. So we test for 0x05 too. */
+ u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
+ u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
+ if (((data_val == 0x00) || (data_val == 0x08)) &&
+ ((cmd_val == 0xAC) || (cmd_val == 0x05)))
+ return ABIT_UGURU3_BASE;
+
+ ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
+ "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+ if (force) {
+ printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is "
+ "present because of \"force\" parameter\n");
+ return ABIT_UGURU3_BASE;
+ }
+
+ /* No uGuru3 found */
+ return -ENODEV;
+}
+
+static struct platform_device *abituguru3_pdev;
+
+static int __init abituguru3_init(void)
+{
+ int address, err;
+ struct resource res = { .flags = IORESOURCE_IO };
+
+ address = abituguru3_detect();
+ if (address < 0)
+ return address;
+
+ err = platform_driver_register(&abituguru3_driver);
+ if (err)
+ goto exit;
+
+ abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME, address);
+ if (!abituguru3_pdev) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Device allocation failed\n");
+ err = -ENOMEM;
+ goto exit_driver_unregister;
+ }
+
+ res.start = address;
+ res.end = address + ABIT_UGURU3_REGION_LENGTH - 1;
+ res.name = ABIT_UGURU3_NAME;
+
+ err = platform_device_add_resources(abituguru3_pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Device resource addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(abituguru3_pdev);
+ if (err) {
+ printk(KERN_ERR ABIT_UGURU3_NAME
+ ": Device addition failed (%d)\n", err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(abituguru3_pdev);
+exit_driver_unregister:
+ platform_driver_unregister(&abituguru3_driver);
+exit:
+ return err;
+}
+
+static void __exit abituguru3_exit(void)
+{
+ platform_device_unregister(abituguru3_pdev);
+ platform_driver_unregister(&abituguru3_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru3_init);
+module_exit(abituguru3_exit);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 6d54c8caed79..7c1795225b06 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -318,7 +318,7 @@ exit:
}
#ifdef CONFIG_HOTPLUG_CPU
-void coretemp_device_remove(unsigned int cpu)
+static void coretemp_device_remove(unsigned int cpu)
{
struct pdev_entry *p, *n;
mutex_lock(&pdev_list_mutex);
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
new file mode 100644
index 000000000000..be3aaa5d0b91
--- /dev/null
+++ b/drivers/hwmon/dme1737.c
@@ -0,0 +1,2080 @@
+/*
+ * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips
+ * integrated hardware monitoring features.
+ * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is based on the LM85 driver. The hardware monitoring
+ * capabilities of the DME1737 are very similar to the LM85 with some
+ * additional features. Even though the DME1737 is a Super-I/O chip, the
+ * hardware monitoring registers are only accessible via SMBus.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+/* Module load parameters */
+static int force_start;
+module_param(force_start, bool, 0);
+MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(dme1737);
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows:
+ *
+ * Voltages Temperatures
+ * -------- ------------
+ * in0 +5VTR (+5V stdby) temp1 Remote diode 1
+ * in1 Vccp (proc core) temp2 Internal temp
+ * in2 VCC (internal +3.3V) temp3 Remote diode 2
+ * in3 +5V
+ * in4 +12V
+ * in5 VTR (+3.3V stby)
+ * in6 Vbat
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-6 (ix) */
+#define DME1737_REG_IN(ix) ((ix) < 5 ? 0x20 + (ix) \
+ : 0x94 + (ix))
+#define DME1737_REG_IN_MIN(ix) ((ix) < 5 ? 0x44 + (ix) * 2 \
+ : 0x91 + (ix) * 2)
+#define DME1737_REG_IN_MAX(ix) ((ix) < 5 ? 0x45 + (ix) * 2 \
+ : 0x92 + (ix) * 2)
+
+/* Temperatures (temp) numbered 0-2 (ix) */
+#define DME1737_REG_TEMP(ix) (0x25 + (ix))
+#define DME1737_REG_TEMP_MIN(ix) (0x4e + (ix) * 2)
+#define DME1737_REG_TEMP_MAX(ix) (0x4f + (ix) * 2)
+#define DME1737_REG_TEMP_OFFSET(ix) ((ix) == 0 ? 0x1f \
+ : 0x1c + (ix))
+
+/* Voltage and temperature LSBs
+ * The LSBs (4 bits each) are stored in 5 registers with the following layouts:
+ * IN_TEMP_LSB(0) = [in5, in6]
+ * IN_TEMP_LSB(1) = [temp3, temp1]
+ * IN_TEMP_LSB(2) = [in4, temp2]
+ * IN_TEMP_LSB(3) = [in3, in0]
+ * IN_TEMP_LSB(4) = [in2, in1] */
+#define DME1737_REG_IN_TEMP_LSB(ix) (0x84 + (ix))
+static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0};
+static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4};
+static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};
+static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
+
+/* Fans numbered 0-5 (ix) */
+#define DME1737_REG_FAN(ix) ((ix) < 4 ? 0x28 + (ix) * 2 \
+ : 0xa1 + (ix) * 2)
+#define DME1737_REG_FAN_MIN(ix) ((ix) < 4 ? 0x54 + (ix) * 2 \
+ : 0xa5 + (ix) * 2)
+#define DME1737_REG_FAN_OPT(ix) ((ix) < 4 ? 0x90 + (ix) \
+ : 0xb2 + (ix))
+#define DME1737_REG_FAN_MAX(ix) (0xb4 + (ix)) /* only for fan[4-5] */
+
+/* PWMs numbered 0-2, 4-5 (ix) */
+#define DME1737_REG_PWM(ix) ((ix) < 3 ? 0x30 + (ix) \
+ : 0xa1 + (ix))
+#define DME1737_REG_PWM_CONFIG(ix) (0x5c + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_MIN(ix) (0x64 + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_FREQ(ix) ((ix) < 3 ? 0x5f + (ix) \
+ : 0xa3 + (ix))
+/* The layout of the ramp rate registers is different from the other pwm
+ * registers. The bits for the 3 PWMs are stored in 2 registers:
+ * PWM_RR(0) = [OFF3, OFF2, OFF1, RES, RR1E, RR1-2, RR1-1, RR1-0]
+ * PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] */
+#define DME1737_REG_PWM_RR(ix) (0x62 + (ix)) /* only for pwm[0-2] */
+
+/* Thermal zones 0-2 */
+#define DME1737_REG_ZONE_LOW(ix) (0x67 + (ix))
+#define DME1737_REG_ZONE_ABS(ix) (0x6a + (ix))
+/* The layout of the hysteresis registers is different from the other zone
+ * registers. The bits for the 3 zones are stored in 2 registers:
+ * ZONE_HYST(0) = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ * ZONE_HYST(1) = [H3-3, H3-2, H3-1, H3-0, RES, RES, RES, RES] */
+#define DME1737_REG_ZONE_HYST(ix) (0x6d + (ix))
+
+/* Alarm registers and bit mapping
+ * The 3 8-bit alarm registers will be concatenated to a single 32-bit
+ * alarm value [0, ALARM3, ALARM2, ALARM1]. */
+#define DME1737_REG_ALARM1 0x41
+#define DME1737_REG_ALARM2 0x42
+#define DME1737_REG_ALARM3 0x83
+static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17};
+static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
+static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
+
+/* Miscellaneous registers */
+#define DME1737_REG_COMPANY 0x3e
+#define DME1737_REG_VERSTEP 0x3f
+#define DME1737_REG_CONFIG 0x40
+#define DME1737_REG_CONFIG2 0x7f
+#define DME1737_REG_VID 0x43
+#define DME1737_REG_TACH_PWM 0x81
+
+/* ---------------------------------------------------------------------
+ * Misc defines
+ * --------------------------------------------------------------------- */
+
+/* Chip identification */
+#define DME1737_COMPANY_SMSC 0x5c
+#define DME1737_VERSTEP 0x88
+#define DME1737_VERSTEP_MASK 0xf8
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct dme1737_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+
+ struct mutex update_lock;
+ int valid; /* !=0 if following fields are valid */
+ unsigned long last_update; /* in jiffies */
+ unsigned long last_vbat; /* in jiffies */
+
+ u8 vid;
+ u8 pwm_rr_en;
+ u8 has_pwm;
+ u8 has_fan;
+
+ /* Register values */
+ u16 in[7];
+ u8 in_min[7];
+ u8 in_max[7];
+ s16 temp[3];
+ s8 temp_min[3];
+ s8 temp_max[3];
+ s8 temp_offset[3];
+ u8 config;
+ u8 config2;
+ u8 vrm;
+ u16 fan[6];
+ u16 fan_min[6];
+ u8 fan_max[2];
+ u8 fan_opt[6];
+ u8 pwm[6];
+ u8 pwm_min[3];
+ u8 pwm_config[3];
+ u8 pwm_acz[3];
+ u8 pwm_freq[6];
+ u8 pwm_rr[2];
+ u8 zone_low[3];
+ u8 zone_abs[3];
+ u8 zone_hyst[2];
+ u32 alarms;
+};
+
+/* Nominal voltage values */
+static const int IN_NOMINAL[] = {5000, 2250, 3300, 5000, 12000, 3300, 3300};
+
+/* Voltage input
+ * Voltage inputs have 16 bits resolution, limit values have 8 bits
+ * resolution. */
+static inline int IN_FROM_REG(int reg, int ix, int res)
+{
+ return (reg * IN_NOMINAL[ix] + (3 << (res - 3))) / (3 << (res - 2));
+}
+
+static inline int IN_TO_REG(int val, int ix)
+{
+ return SENSORS_LIMIT((val * 192 + IN_NOMINAL[ix] / 2) /
+ IN_NOMINAL[ix], 0, 255);
+}
+
+/* Temperature input
+ * The register values represent temperatures in 2's complement notation from
+ * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit
+ * values have 8 bits resolution. */
+static inline int TEMP_FROM_REG(int reg, int res)
+{
+ return (reg * 1000) >> (res - 8);
+}
+
+static inline int TEMP_TO_REG(int val)
+{
+ return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,
+ -128, 127);
+}
+
+/* Temperature range */
+static const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000,
+ 10000, 13333, 16000, 20000, 26666, 32000,
+ 40000, 53333, 80000};
+
+static inline int TEMP_RANGE_FROM_REG(int reg)
+{
+ return TEMP_RANGE[(reg >> 4) & 0x0f];
+}
+
+static int TEMP_RANGE_TO_REG(int val, int reg)
+{
+ int i;
+
+ for (i = 15; i > 0; i--) {
+ if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) {
+ break;
+ }
+ }
+
+ return (reg & 0x0f) | (i << 4);
+}
+
+/* Temperature hysteresis
+ * Register layout:
+ * reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ * reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] */
+static inline int TEMP_HYST_FROM_REG(int reg, int ix)
+{
+ return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;
+}
+
+static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
+{
+ int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);
+
+ return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
+}
+
+/* Fan input RPM */
+static inline int FAN_FROM_REG(int reg, int tpc)
+{
+ return (reg == 0 || reg == 0xffff) ? 0 :
+ (tpc == 0) ? 90000 * 60 / reg : tpc * reg;
+}
+
+static inline int FAN_TO_REG(int val, int tpc)
+{
+ return SENSORS_LIMIT((tpc == 0) ? 90000 * 60 / val : val / tpc,
+ 0, 0xffff);
+}
+
+/* Fan TPC (tach pulse count)
+ * Converts a register value to a TPC multiplier or returns 0 if the tachometer
+ * is configured in legacy (non-tpc) mode */
+static inline int FAN_TPC_FROM_REG(int reg)
+{
+ return (reg & 0x20) ? 0 : 60 >> (reg & 0x03);
+}
+
+/* Fan type
+ * The type of a fan is expressed in number of pulses-per-revolution that it
+ * emits */
+static inline int FAN_TYPE_FROM_REG(int reg)
+{
+ int edge = (reg >> 1) & 0x03;
+
+ return (edge > 0) ? 1 << (edge - 1) : 0;
+}
+
+static inline int FAN_TYPE_TO_REG(int val, int reg)
+{
+ int edge = (val == 4) ? 3 : val;
+
+ return (reg & 0xf9) | (edge << 1);
+}
+
+/* Fan max RPM */
+static const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12,
+ 0x11, 0x0f, 0x0e};
+
+static int FAN_MAX_FROM_REG(int reg)
+{
+ int i;
+
+ for (i = 10; i > 0; i--) {
+ if (reg == FAN_MAX[i]) {
+ break;
+ }
+ }
+
+ return 1000 + i * 500;
+}
+
+static int FAN_MAX_TO_REG(int val)
+{
+ int i;
+
+ for (i = 10; i > 0; i--) {
+ if (val > (1000 + (i - 1) * 500)) {
+ break;
+ }
+ }
+
+ return FAN_MAX[i];
+}
+
+/* PWM enable
+ * Register to enable mapping:
+ * 000: 2 fan on zone 1 auto
+ * 001: 2 fan on zone 2 auto
+ * 010: 2 fan on zone 3 auto
+ * 011: 0 fan full on
+ * 100: -1 fan disabled
+ * 101: 2 fan on hottest of zones 2,3 auto
+ * 110: 2 fan on hottest of zones 1,2,3 auto
+ * 111: 1 fan in manual mode */
+static inline int PWM_EN_FROM_REG(int reg)
+{
+ static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1};
+
+ return en[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_EN_TO_REG(int val, int reg)
+{
+ int en = (val == 1) ? 7 : 3;
+
+ return (reg & 0x1f) | ((en & 0x07) << 5);
+}
+
+/* PWM auto channels zone
+ * Register to auto channels zone mapping (ACZ is a bitfield with bit x
+ * corresponding to zone x+1):
+ * 000: 001 fan on zone 1 auto
+ * 001: 010 fan on zone 2 auto
+ * 010: 100 fan on zone 3 auto
+ * 011: 000 fan full on
+ * 100: 000 fan disabled
+ * 101: 110 fan on hottest of zones 2,3 auto
+ * 110: 111 fan on hottest of zones 1,2,3 auto
+ * 111: 000 fan in manual mode */
+static inline int PWM_ACZ_FROM_REG(int reg)
+{
+ static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0};
+
+ return acz[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_ACZ_TO_REG(int val, int reg)
+{
+ int acz = (val == 4) ? 2 : val - 1;
+
+ return (reg & 0x1f) | ((acz & 0x07) << 5);
+}
+
+/* PWM frequency */
+static const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88,
+ 15000, 20000, 30000, 25000, 0, 0, 0, 0};
+
+static inline int PWM_FREQ_FROM_REG(int reg)
+{
+ return PWM_FREQ[reg & 0x0f];
+}
+
+static int PWM_FREQ_TO_REG(int val, int reg)
+{
+ int i;
+
+ /* the first two cases are special - stupid chip design! */
+ if (val > 27500) {
+ i = 10;
+ } else if (val > 22500) {
+ i = 11;
+ } else {
+ for (i = 9; i > 0; i--) {
+ if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) {
+ break;
+ }
+ }
+ }
+
+ return (reg & 0xf0) | i;
+}
+
+/* PWM ramp rate
+ * Register layout:
+ * reg[0] = [OFF3, OFF2, OFF1, RES, RR1-E, RR1-2, RR1-1, RR1-0]
+ * reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] */
+static const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5};
+
+static inline int PWM_RR_FROM_REG(int reg, int ix)
+{
+ int rr = (ix == 1) ? reg >> 4 : reg;
+
+ return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0;
+}
+
+static int PWM_RR_TO_REG(int val, int ix, int reg)
+{
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) {
+ break;
+ }
+ }
+
+ return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i;
+}
+
+/* PWM ramp rate enable */
+static inline int PWM_RR_EN_FROM_REG(int reg, int ix)
+{
+ return PWM_RR_FROM_REG(reg, ix) ? 1 : 0;
+}
+
+static inline int PWM_RR_EN_TO_REG(int val, int ix, int reg)
+{
+ int en = (ix == 1) ? 0x80 : 0x08;
+
+ return val ? reg | en : reg & ~en;
+}
+
+/* PWM min/off
+ * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for
+ * the register layout). */
+static inline int PWM_OFF_FROM_REG(int reg, int ix)
+{
+ return (reg >> (ix + 5)) & 0x01;
+}
+
+static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
+{
+ return (reg & ~(1 << (ix + 5))) | ((val & 0x01) << (ix + 5));
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ * --------------------------------------------------------------------- */
+
+static u8 dme1737_read(struct i2c_client *client, u8 reg)
+{
+ s32 val = i2c_smbus_read_byte_data(client, reg);
+
+ if (val < 0) {
+ dev_warn(&client->dev, "Read from register 0x%02x failed! "
+ "Please report to the driver maintainer.\n", reg);
+ }
+
+ return val;
+}
+
+static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
+{
+ s32 res = i2c_smbus_write_byte_data(client, reg, value);
+
+ if (res < 0) {
+ dev_warn(&client->dev, "Write to register 0x%02x failed! "
+ "Please report to the driver maintainer.\n", reg);
+ }
+
+ return res;
+}
+
+static struct dme1737_data *dme1737_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int ix;
+ u8 lsb[5];
+
+ mutex_lock(&data->update_lock);
+
+ /* Enable a Vbat monitoring cycle every 10 mins */
+ if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
+ dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
+ DME1737_REG_CONFIG) | 0x10);
+ data->last_vbat = jiffies;
+ }
+
+ /* Sample register contents every 1 sec */
+ if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
+ data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f;
+
+ /* In (voltage) registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+ /* Voltage inputs are stored as 16 bit values even
+ * though they have only 12 bits resolution. This is
+ * to make it consistent with the temp inputs. */
+ data->in[ix] = dme1737_read(client,
+ DME1737_REG_IN(ix)) << 8;
+ data->in_min[ix] = dme1737_read(client,
+ DME1737_REG_IN_MIN(ix));
+ data->in_max[ix] = dme1737_read(client,
+ DME1737_REG_IN_MAX(ix));
+ }
+
+ /* Temp registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+ /* Temp inputs are stored as 16 bit values even
+ * though they have only 12 bits resolution. This is
+ * to take advantage of implicit conversions between
+ * register values (2's complement) and temp values
+ * (signed decimal). */
+ data->temp[ix] = dme1737_read(client,
+ DME1737_REG_TEMP(ix)) << 8;
+ data->temp_min[ix] = dme1737_read(client,
+ DME1737_REG_TEMP_MIN(ix));
+ data->temp_max[ix] = dme1737_read(client,
+ DME1737_REG_TEMP_MAX(ix));
+ data->temp_offset[ix] = dme1737_read(client,
+ DME1737_REG_TEMP_OFFSET(ix));
+ }
+
+ /* In and temp LSB registers
+ * The LSBs are latched when the MSBs are read, so the order in
+ * which the registers are read (MSB first, then LSB) is
+ * important! */
+ for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
+ lsb[ix] = dme1737_read(client,
+ DME1737_REG_IN_TEMP_LSB(ix));
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+ data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] <<
+ DME1737_REG_IN_LSB_SHL[ix]) & 0xf0;
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+ data->temp[ix] |= (lsb[DME1737_REG_TEMP_LSB[ix]] <<
+ DME1737_REG_TEMP_LSB_SHL[ix]) & 0xf0;
+ }
+
+ /* Fan registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+ /* Skip reading registers if optional fans are not
+ * present */
+ if (!(data->has_fan & (1 << ix))) {
+ continue;
+ }
+ data->fan[ix] = dme1737_read(client,
+ DME1737_REG_FAN(ix));
+ data->fan[ix] |= dme1737_read(client,
+ DME1737_REG_FAN(ix) + 1) << 8;
+ data->fan_min[ix] = dme1737_read(client,
+ DME1737_REG_FAN_MIN(ix));
+ data->fan_min[ix] |= dme1737_read(client,
+ DME1737_REG_FAN_MIN(ix) + 1) << 8;
+ data->fan_opt[ix] = dme1737_read(client,
+ DME1737_REG_FAN_OPT(ix));
+ /* fan_max exists only for fan[5-6] */
+ if (ix > 3) {
+ data->fan_max[ix - 4] = dme1737_read(client,
+ DME1737_REG_FAN_MAX(ix));
+ }
+ }
+
+ /* PWM registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
+ /* Skip reading registers if optional PWMs are not
+ * present */
+ if (!(data->has_pwm & (1 << ix))) {
+ continue;
+ }
+ data->pwm[ix] = dme1737_read(client,
+ DME1737_REG_PWM(ix));
+ data->pwm_freq[ix] = dme1737_read(client,
+ DME1737_REG_PWM_FREQ(ix));
+ /* pwm_config and pwm_min exist only for pwm[1-3] */
+ if (ix < 3) {
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ data->pwm_min[ix] = dme1737_read(client,
+ DME1737_REG_PWM_MIN(ix));
+ }
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
+ data->pwm_rr[ix] = dme1737_read(client,
+ DME1737_REG_PWM_RR(ix));
+ }
+
+ /* Thermal zone registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
+ data->zone_low[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_LOW(ix));
+ data->zone_abs[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_ABS(ix));
+ }
+ for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
+ data->zone_hyst[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_HYST(ix));
+ }
+
+ /* Alarm registers */
+ data->alarms = dme1737_read(client,
+ DME1737_REG_ALARM1);
+ /* Bit 7 tells us if the other alarm registers are non-zero and
+ * therefore also need to be read */
+ if (data->alarms & 0x80) {
+ data->alarms |= dme1737_read(client,
+ DME1737_REG_ALARM2) << 8;
+ data->alarms |= dme1737_read(client,
+ DME1737_REG_ALARM3) << 16;
+ }
+
+ data->last_update = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_IN_INPUT 0
+#define SYS_IN_MIN 1
+#define SYS_IN_MAX 2
+#define SYS_IN_ALARM 3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_IN_INPUT:
+ res = IN_FROM_REG(data->in[ix], ix, 16);
+ break;
+ case SYS_IN_MIN:
+ res = IN_FROM_REG(data->in_min[ix], ix, 8);
+ break;
+ case SYS_IN_MAX:
+ res = IN_FROM_REG(data->in_max[ix], ix, 8);
+ break;
+ case SYS_IN_ALARM:
+ res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_IN_MIN:
+ data->in_min[ix] = IN_TO_REG(val, ix);
+ dme1737_write(client, DME1737_REG_IN_MIN(ix),
+ data->in_min[ix]);
+ break;
+ case SYS_IN_MAX:
+ data->in_max[ix] = IN_TO_REG(val, ix);
+ dme1737_write(client, DME1737_REG_IN_MAX(ix),
+ data->in_max[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_TEMP_INPUT 0
+#define SYS_TEMP_MIN 1
+#define SYS_TEMP_MAX 2
+#define SYS_TEMP_OFFSET 3
+#define SYS_TEMP_ALARM 4
+#define SYS_TEMP_FAULT 5
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_TEMP_INPUT:
+ res = TEMP_FROM_REG(data->temp[ix], 16);
+ break;
+ case SYS_TEMP_MIN:
+ res = TEMP_FROM_REG(data->temp_min[ix], 8);
+ break;
+ case SYS_TEMP_MAX:
+ res = TEMP_FROM_REG(data->temp_max[ix], 8);
+ break;
+ case SYS_TEMP_OFFSET:
+ res = TEMP_FROM_REG(data->temp_offset[ix], 8);
+ break;
+ case SYS_TEMP_ALARM:
+ res = (data->alarms >> DME1737_BIT_ALARM_TEMP[ix]) & 0x01;
+ break;
+ case SYS_TEMP_FAULT:
+ res = (data->temp[ix] == 0x0800);
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_TEMP_MIN:
+ data->temp_min[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
+ data->temp_min[ix]);
+ break;
+ case SYS_TEMP_MAX:
+ data->temp_max[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
+ data->temp_max[ix]);
+ break;
+ case SYS_TEMP_OFFSET:
+ data->temp_offset[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
+ data->temp_offset[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Zone sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_ZONE_AUTO_CHANNELS_TEMP 0
+#define SYS_ZONE_AUTO_POINT1_TEMP_HYST 1
+#define SYS_ZONE_AUTO_POINT1_TEMP 2
+#define SYS_ZONE_AUTO_POINT2_TEMP 3
+#define SYS_ZONE_AUTO_POINT3_TEMP 4
+
+static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_ZONE_AUTO_CHANNELS_TEMP:
+ /* check config2 for non-standard temp-to-zone mapping */
+ if ((ix == 1) && (data->config2 & 0x02)) {
+ res = 4;
+ } else {
+ res = 1 << ix;
+ }
+ break;
+ case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+ res = TEMP_FROM_REG(data->zone_low[ix], 8) -
+ TEMP_HYST_FROM_REG(data->zone_hyst[ix == 2], ix);
+ break;
+ case SYS_ZONE_AUTO_POINT1_TEMP:
+ res = TEMP_FROM_REG(data->zone_low[ix], 8);
+ break;
+ case SYS_ZONE_AUTO_POINT2_TEMP:
+ /* pwm_freq holds the temp range bits in the upper nibble */
+ res = TEMP_FROM_REG(data->zone_low[ix], 8) +
+ TEMP_RANGE_FROM_REG(data->pwm_freq[ix]);
+ break;
+ case SYS_ZONE_AUTO_POINT3_TEMP:
+ res = TEMP_FROM_REG(data->zone_abs[ix], 8);
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+ /* Refresh the cache */
+ data->zone_low[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_LOW(ix));
+ /* Modify the temp hyst value */
+ data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
+ TEMP_FROM_REG(data->zone_low[ix], 8) -
+ val, ix, dme1737_read(client,
+ DME1737_REG_ZONE_HYST(ix == 2)));
+ dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
+ data->zone_hyst[ix == 2]);
+ break;
+ case SYS_ZONE_AUTO_POINT1_TEMP:
+ data->zone_low[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
+ data->zone_low[ix]);
+ break;
+ case SYS_ZONE_AUTO_POINT2_TEMP:
+ /* Refresh the cache */
+ data->zone_low[ix] = dme1737_read(client,
+ DME1737_REG_ZONE_LOW(ix));
+ /* Modify the temp range value (which is stored in the upper
+ * nibble of the pwm_freq register) */
+ data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
+ TEMP_FROM_REG(data->zone_low[ix], 8),
+ dme1737_read(client,
+ DME1737_REG_PWM_FREQ(ix)));
+ dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+ data->pwm_freq[ix]);
+ break;
+ case SYS_ZONE_AUTO_POINT3_TEMP:
+ data->zone_abs[ix] = TEMP_TO_REG(val);
+ dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
+ data->zone_abs[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_FAN_INPUT 0
+#define SYS_FAN_MIN 1
+#define SYS_FAN_MAX 2
+#define SYS_FAN_ALARM 3
+#define SYS_FAN_TYPE 4
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_FAN_INPUT:
+ res = FAN_FROM_REG(data->fan[ix],
+ ix < 4 ? 0 :
+ FAN_TPC_FROM_REG(data->fan_opt[ix]));
+ break;
+ case SYS_FAN_MIN:
+ res = FAN_FROM_REG(data->fan_min[ix],
+ ix < 4 ? 0 :
+ FAN_TPC_FROM_REG(data->fan_opt[ix]));
+ break;
+ case SYS_FAN_MAX:
+ /* only valid for fan[5-6] */
+ res = FAN_MAX_FROM_REG(data->fan_max[ix - 4]);
+ break;
+ case SYS_FAN_ALARM:
+ res = (data->alarms >> DME1737_BIT_ALARM_FAN[ix]) & 0x01;
+ break;
+ case SYS_FAN_TYPE:
+ /* only valid for fan[1-4] */
+ res = FAN_TYPE_FROM_REG(data->fan_opt[ix]);
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_FAN_MIN:
+ if (ix < 4) {
+ data->fan_min[ix] = FAN_TO_REG(val, 0);
+ } else {
+ /* Refresh the cache */
+ data->fan_opt[ix] = dme1737_read(client,
+ DME1737_REG_FAN_OPT(ix));
+ /* Modify the fan min value */
+ data->fan_min[ix] = FAN_TO_REG(val,
+ FAN_TPC_FROM_REG(data->fan_opt[ix]));
+ }
+ dme1737_write(client, DME1737_REG_FAN_MIN(ix),
+ data->fan_min[ix] & 0xff);
+ dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
+ data->fan_min[ix] >> 8);
+ break;
+ case SYS_FAN_MAX:
+ /* Only valid for fan[5-6] */
+ data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
+ dme1737_write(client, DME1737_REG_FAN_MAX(ix),
+ data->fan_max[ix - 4]);
+ break;
+ case SYS_FAN_TYPE:
+ /* Only valid for fan[1-4] */
+ if (!(val == 1 || val == 2 || val == 4)) {
+ count = -EINVAL;
+ dev_warn(&client->dev, "Fan type value %ld not "
+ "supported. Choose one of 1, 2, or 4.\n",
+ val);
+ goto exit;
+ }
+ data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
+ DME1737_REG_FAN_OPT(ix)));
+ dme1737_write(client, DME1737_REG_FAN_OPT(ix),
+ data->fan_opt[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs attributes
+ * ix = [0-4]
+ * --------------------------------------------------------------------- */
+
+#define SYS_PWM 0
+#define SYS_PWM_FREQ 1
+#define SYS_PWM_ENABLE 2
+#define SYS_PWM_RAMP_RATE 3
+#define SYS_PWM_AUTO_CHANNELS_ZONE 4
+#define SYS_PWM_AUTO_PWM_MIN 5
+#define SYS_PWM_AUTO_POINT1_PWM 6
+#define SYS_PWM_AUTO_POINT2_PWM 7
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SYS_PWM:
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0) {
+ res = 255;
+ } else {
+ res = data->pwm[ix];
+ }
+ break;
+ case SYS_PWM_FREQ:
+ res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]);
+ break;
+ case SYS_PWM_ENABLE:
+ if (ix > 3) {
+ res = 1; /* pwm[5-6] hard-wired to manual mode */
+ } else {
+ res = PWM_EN_FROM_REG(data->pwm_config[ix]);
+ }
+ break;
+ case SYS_PWM_RAMP_RATE:
+ /* Only valid for pwm[1-3] */
+ res = PWM_RR_FROM_REG(data->pwm_rr[ix > 0], ix);
+ break;
+ case SYS_PWM_AUTO_CHANNELS_ZONE:
+ /* Only valid for pwm[1-3] */
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ res = PWM_ACZ_FROM_REG(data->pwm_config[ix]);
+ } else {
+ res = data->pwm_acz[ix];
+ }
+ break;
+ case SYS_PWM_AUTO_PWM_MIN:
+ /* Only valid for pwm[1-3] */
+ if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix)) {
+ res = data->pwm_min[ix];
+ } else {
+ res = 0;
+ }
+ break;
+ case SYS_PWM_AUTO_POINT1_PWM:
+ /* Only valid for pwm[1-3] */
+ res = data->pwm_min[ix];
+ break;
+ case SYS_PWM_AUTO_POINT2_PWM:
+ /* Only valid for pwm[1-3] */
+ res = 255; /* hard-wired */
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static struct attribute *dme1737_attr_pwm[];
+static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t);
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2
+ *sensor_attr_2 = to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SYS_PWM:
+ data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
+ dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
+ break;
+ case SYS_PWM_FREQ:
+ data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
+ DME1737_REG_PWM_FREQ(ix)));
+ dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+ data->pwm_freq[ix]);
+ break;
+ case SYS_PWM_ENABLE:
+ /* Only valid for pwm[1-3] */
+ if (val < 0 || val > 2) {
+ count = -EINVAL;
+ dev_warn(&client->dev, "PWM enable %ld not "
+ "supported. Choose one of 0, 1, or 2.\n",
+ val);
+ goto exit;
+ }
+ /* Refresh the cache */
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
+ /* Bail out if no change */
+ goto exit;
+ }
+ /* Do some housekeeping if we are currently in auto mode */
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ /* Save the current zone channel assignment */
+ data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
+ data->pwm_config[ix]);
+ /* Save the current ramp rate state and disable it */
+ data->pwm_rr[ix > 0] = dme1737_read(client,
+ DME1737_REG_PWM_RR(ix > 0));
+ data->pwm_rr_en &= ~(1 << ix);
+ if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
+ data->pwm_rr_en |= (1 << ix);
+ data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
+ data->pwm_rr[ix > 0]);
+ dme1737_write(client,
+ DME1737_REG_PWM_RR(ix > 0),
+ data->pwm_rr[ix > 0]);
+ }
+ }
+ /* Set the new PWM mode */
+ switch (val) {
+ case 0:
+ /* Change permissions of pwm[ix] to read-only */
+ dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ S_IRUGO);
+ /* Turn fan fully on */
+ data->pwm_config[ix] = PWM_EN_TO_REG(0,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ break;
+ case 1:
+ /* Turn on manual mode */
+ data->pwm_config[ix] = PWM_EN_TO_REG(1,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ /* Change permissions of pwm[ix] to read-writeable */
+ dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ S_IRUGO | S_IWUSR);
+ break;
+ case 2:
+ /* Change permissions of pwm[ix] to read-only */
+ dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+ S_IRUGO);
+ /* Turn on auto mode using the saved zone channel
+ * assignment */
+ data->pwm_config[ix] = PWM_ACZ_TO_REG(
+ data->pwm_acz[ix],
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ /* Enable PWM ramp rate if previously enabled */
+ if (data->pwm_rr_en & (1 << ix)) {
+ data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
+ dme1737_read(client,
+ DME1737_REG_PWM_RR(ix > 0)));
+ dme1737_write(client,
+ DME1737_REG_PWM_RR(ix > 0),
+ data->pwm_rr[ix > 0]);
+ }
+ break;
+ }
+ break;
+ case SYS_PWM_RAMP_RATE:
+ /* Only valid for pwm[1-3] */
+ /* Refresh the cache */
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ data->pwm_rr[ix > 0] = dme1737_read(client,
+ DME1737_REG_PWM_RR(ix > 0));
+ /* Set the ramp rate value */
+ if (val > 0) {
+ data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix,
+ data->pwm_rr[ix > 0]);
+ }
+ /* Enable/disable the feature only if the associated PWM
+ * output is in automatic mode. */
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
+ data->pwm_rr[ix > 0]);
+ }
+ dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
+ data->pwm_rr[ix > 0]);
+ break;
+ case SYS_PWM_AUTO_CHANNELS_ZONE:
+ /* Only valid for pwm[1-3] */
+ if (!(val == 1 || val == 2 || val == 4 ||
+ val == 6 || val == 7)) {
+ count = -EINVAL;
+ dev_warn(&client->dev, "PWM auto channels zone %ld "
+ "not supported. Choose one of 1, 2, 4, 6, "
+ "or 7.\n", val);
+ goto exit;
+ }
+ /* Refresh the cache */
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+ /* PWM is already in auto mode so update the temp
+ * channel assignment */
+ data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ } else {
+ /* PWM is not in auto mode so we save the temp
+ * channel assignment for later use */
+ data->pwm_acz[ix] = val;
+ }
+ break;
+ case SYS_PWM_AUTO_PWM_MIN:
+ /* Only valid for pwm[1-3] */
+ /* Refresh the cache */
+ data->pwm_min[ix] = dme1737_read(client,
+ DME1737_REG_PWM_MIN(ix));
+ /* There are only 2 values supported for the auto_pwm_min
+ * value: 0 or auto_point1_pwm. So if the temperature drops
+ * below the auto_point1_temp_hyst value, the fan either turns
+ * off or runs at auto_point1_pwm duty-cycle. */
+ if (val > ((data->pwm_min[ix] + 1) / 2)) {
+ data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
+ dme1737_read(client,
+ DME1737_REG_PWM_RR(0)));
+
+ } else {
+ data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
+ dme1737_read(client,
+ DME1737_REG_PWM_RR(0)));
+
+ }
+ dme1737_write(client, DME1737_REG_PWM_RR(0),
+ data->pwm_rr[0]);
+ break;
+ case SYS_PWM_AUTO_POINT1_PWM:
+ /* Only valid for pwm[1-3] */
+ data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
+ dme1737_write(client, DME1737_REG_PWM_MIN(ix),
+ data->pwm_min[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+exit:
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs attributes
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+
+ return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ long val = simple_strtol(buf, NULL, 10);
+
+ data->vrm = val;
+ return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct dme1737_data *data = dme1737_update_device(dev);
+
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+/* ---------------------------------------------------------------------
+ * Sysfs device attribute defines and structs
+ * --------------------------------------------------------------------- */
+
+/* Voltages 0-6 */
+
+#define SENSOR_DEVICE_ATTR_IN(ix) \
+static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
+ show_in, NULL, SYS_IN_INPUT, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SYS_IN_MIN, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SYS_IN_MAX, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
+ show_in, NULL, SYS_IN_ALARM, ix)
+
+SENSOR_DEVICE_ATTR_IN(0);
+SENSOR_DEVICE_ATTR_IN(1);
+SENSOR_DEVICE_ATTR_IN(2);
+SENSOR_DEVICE_ATTR_IN(3);
+SENSOR_DEVICE_ATTR_IN(4);
+SENSOR_DEVICE_ATTR_IN(5);
+SENSOR_DEVICE_ATTR_IN(6);
+
+/* Temperatures 1-3 */
+
+#define SENSOR_DEVICE_ATTR_TEMP(ix) \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
+ show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
+ show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+ show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
+ show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+
+SENSOR_DEVICE_ATTR_TEMP(1);
+SENSOR_DEVICE_ATTR_TEMP(2);
+SENSOR_DEVICE_ATTR_TEMP(3);
+
+/* Zones 1-3 */
+
+#define SENSOR_DEVICE_ATTR_ZONE(ix) \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
+ show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
+ show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+
+SENSOR_DEVICE_ATTR_ZONE(1);
+SENSOR_DEVICE_ATTR_ZONE(2);
+SENSOR_DEVICE_ATTR_ZONE(3);
+
+/* Fans 1-4 */
+
+#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_1TO4(1);
+SENSOR_DEVICE_ATTR_FAN_1TO4(2);
+SENSOR_DEVICE_ATTR_FAN_1TO4(3);
+SENSOR_DEVICE_ATTR_FAN_1TO4(4);
+
+/* Fans 5-6 */
+
+#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+ show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SYS_FAN_MAX, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_5TO6(5);
+SENSOR_DEVICE_ATTR_FAN_5TO6(6);
+
+/* PWMs 1-3 */
+
+#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
+ show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
+ show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_1TO3(1);
+SENSOR_DEVICE_ATTR_PWM_1TO3(2);
+SENSOR_DEVICE_ATTR_PWM_1TO3(3);
+
+/* PWMs 5-6 */
+
+#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+ show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_5TO6(5);
+SENSOR_DEVICE_ATTR_PWM_5TO6(6);
+
+/* Misc */
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+#define SENSOR_DEV_ATTR_IN(ix) \
+&sensor_dev_attr_in##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_alarm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_TEMP_LOCK(ix) \
+&sensor_dev_attr_temp##ix##_offset.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_TEMP(ix) \
+SENSOR_DEV_ATTR_TEMP_LOCK(ix), \
+&sensor_dev_attr_temp##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_fault.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_ZONE_LOCK(ix) \
+&sensor_dev_attr_zone##ix##_auto_point1_temp_hyst.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point1_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point2_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point3_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_ZONE(ix) \
+SENSOR_DEV_ATTR_ZONE_LOCK(ix), \
+&sensor_dev_attr_zone##ix##_auto_channels_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_1TO4(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_type.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_5TO6(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_max.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix) \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_ramp_rate.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_channels_zone.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_pwm_min.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point1_pwm.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_1TO3(ix) \
+SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix), \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point2_pwm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix) \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_5TO6(ix) \
+SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr
+
+/* This struct holds all the attributes that are always present and need to be
+ * created unconditionally. The attributes that need modification of their
+ * permissions are created read-only and write permissions are added or removed
+ * on the fly when required */
+static struct attribute *dme1737_attr[] ={
+ /* Voltages */
+ SENSOR_DEV_ATTR_IN(0),
+ SENSOR_DEV_ATTR_IN(1),
+ SENSOR_DEV_ATTR_IN(2),
+ SENSOR_DEV_ATTR_IN(3),
+ SENSOR_DEV_ATTR_IN(4),
+ SENSOR_DEV_ATTR_IN(5),
+ SENSOR_DEV_ATTR_IN(6),
+ /* Temperatures */
+ SENSOR_DEV_ATTR_TEMP(1),
+ SENSOR_DEV_ATTR_TEMP(2),
+ SENSOR_DEV_ATTR_TEMP(3),
+ /* Zones */
+ SENSOR_DEV_ATTR_ZONE(1),
+ SENSOR_DEV_ATTR_ZONE(2),
+ SENSOR_DEV_ATTR_ZONE(3),
+ /* Misc */
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group dme1737_group = {
+ .attrs = dme1737_attr,
+};
+
+/* The following structs hold the PWM attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_pwm1[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3(1),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm2[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3(2),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm3[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3(3),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm5[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6(5),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm6[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6(6),
+ NULL
+};
+
+static const struct attribute_group dme1737_pwm_group[] = {
+ { .attrs = dme1737_attr_pwm1 },
+ { .attrs = dme1737_attr_pwm2 },
+ { .attrs = dme1737_attr_pwm3 },
+ { .attrs = NULL },
+ { .attrs = dme1737_attr_pwm5 },
+ { .attrs = dme1737_attr_pwm6 },
+};
+
+/* The following structs hold the fan attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_fan1[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(1),
+ NULL
+};
+static struct attribute *dme1737_attr_fan2[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(2),
+ NULL
+};
+static struct attribute *dme1737_attr_fan3[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(3),
+ NULL
+};
+static struct attribute *dme1737_attr_fan4[] = {
+ SENSOR_DEV_ATTR_FAN_1TO4(4),
+ NULL
+};
+static struct attribute *dme1737_attr_fan5[] = {
+ SENSOR_DEV_ATTR_FAN_5TO6(5),
+ NULL
+};
+static struct attribute *dme1737_attr_fan6[] = {
+ SENSOR_DEV_ATTR_FAN_5TO6(6),
+ NULL
+};
+
+static const struct attribute_group dme1737_fan_group[] = {
+ { .attrs = dme1737_attr_fan1 },
+ { .attrs = dme1737_attr_fan2 },
+ { .attrs = dme1737_attr_fan3 },
+ { .attrs = dme1737_attr_fan4 },
+ { .attrs = dme1737_attr_fan5 },
+ { .attrs = dme1737_attr_fan6 },
+};
+
+/* The permissions of all of the following attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_lock[] = {
+ /* Temperatures */
+ SENSOR_DEV_ATTR_TEMP_LOCK(1),
+ SENSOR_DEV_ATTR_TEMP_LOCK(2),
+ SENSOR_DEV_ATTR_TEMP_LOCK(3),
+ /* Zones */
+ SENSOR_DEV_ATTR_ZONE_LOCK(1),
+ SENSOR_DEV_ATTR_ZONE_LOCK(2),
+ SENSOR_DEV_ATTR_ZONE_LOCK(3),
+ NULL
+};
+
+static const struct attribute_group dme1737_lock_group = {
+ .attrs = dme1737_attr_lock,
+};
+
+/* The permissions of the following PWM attributes are changed to read-
+ * writeable if the chip is *not* locked and the respective PWM is available.
+ * Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_pwm1_lock[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm2_lock[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm3_lock[] = {
+ SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm5_lock[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
+ NULL
+};
+static struct attribute *dme1737_attr_pwm6_lock[] = {
+ SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
+ NULL
+};
+
+static const struct attribute_group dme1737_pwm_lock_group[] = {
+ { .attrs = dme1737_attr_pwm1_lock },
+ { .attrs = dme1737_attr_pwm2_lock },
+ { .attrs = dme1737_attr_pwm3_lock },
+ { .attrs = NULL },
+ { .attrs = dme1737_attr_pwm5_lock },
+ { .attrs = dme1737_attr_pwm6_lock },
+};
+
+/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
+ * chip is not locked. Otherwise they are read-only. */
+static struct attribute *dme1737_attr_pwm[] = {
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+};
+
+/* ---------------------------------------------------------------------
+ * Super-IO functions
+ * --------------------------------------------------------------------- */
+
+static inline int dme1737_sio_inb(int sio_cip, int reg)
+{
+ outb(reg, sio_cip);
+ return inb(sio_cip + 1);
+}
+
+static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
+{
+ outb(reg, sio_cip);
+ outb(val, sio_cip + 1);
+}
+
+static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client)
+{
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int err = 0, reg;
+ u16 addr;
+
+ /* Enter configuration mode */
+ outb(0x55, sio_cip);
+
+ /* Check device ID
+ * The DME1737 can return either 0x78 or 0x77 as its device ID. */
+ reg = dme1737_sio_inb(sio_cip, 0x20);
+ if (!(reg == 0x77 || reg == 0x78)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Select logical device A (runtime registers) */
+ dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+ /* Get the base address of the runtime registers */
+ if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+ dme1737_sio_inb(sio_cip, 0x61))) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ /* Read the runtime registers to determine which optional features
+ * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+ * to '10' if the respective feature is enabled. */
+ if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
+ data->has_fan |= (1 << 5);
+ }
+ if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
+ data->has_pwm |= (1 << 5);
+ }
+ if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
+ data->has_fan |= (1 << 4);
+ }
+ if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
+ data->has_pwm |= (1 << 4);
+ }
+
+exit:
+ /* Exit configuration mode */
+ outb(0xaa, sio_cip);
+
+ return err;
+}
+
+/* ---------------------------------------------------------------------
+ * Device detection, registration and initialization
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_driver;
+
+static void dme1737_chmod_file(struct i2c_client *client,
+ struct attribute *attr, mode_t mode)
+{
+ if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) {
+ dev_warn(&client->dev, "Failed to change permissions of %s.\n",
+ attr->name);
+ }
+}
+
+static void dme1737_chmod_group(struct i2c_client *client,
+ const struct attribute_group *group,
+ mode_t mode)
+{
+ struct attribute **attr;
+
+ for (attr = group->attrs; *attr; attr++) {
+ dme1737_chmod_file(client, *attr, mode);
+ }
+}
+
+static int dme1737_init_client(struct i2c_client *client)
+{
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int ix;
+ u8 reg;
+
+ data->config = dme1737_read(client, DME1737_REG_CONFIG);
+ /* Inform if part is not monitoring/started */
+ if (!(data->config & 0x01)) {
+ if (!force_start) {
+ dev_err(&client->dev, "Device is not monitoring. "
+ "Use the force_start load parameter to "
+ "override.\n");
+ return -EFAULT;
+ }
+
+ /* Force monitoring */
+ data->config |= 0x01;
+ dme1737_write(client, DME1737_REG_CONFIG, data->config);
+ }
+ /* Inform if part is not ready */
+ if (!(data->config & 0x04)) {
+ dev_err(&client->dev, "Device is not ready.\n");
+ return -EFAULT;
+ }
+
+ data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+ /* Check if optional fan3 input is enabled */
+ if (data->config2 & 0x04) {
+ data->has_fan |= (1 << 2);
+ }
+
+ /* Fan4 and pwm3 are only available if the client's I2C address
+ * is the default 0x2e. Otherwise the I/Os associated with these
+ * functions are used for addr enable/select. */
+ if (client->addr == 0x2e) {
+ data->has_fan |= (1 << 3);
+ data->has_pwm |= (1 << 2);
+ }
+
+ /* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled.
+ * For this, we need to query the runtime registers through the
+ * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */
+ if (dme1737_sio_get_features(0x2e, client) &&
+ dme1737_sio_get_features(0x4e, client)) {
+ dev_warn(&client->dev, "Failed to query Super-IO for optional "
+ "features.\n");
+ }
+
+ /* Fan1, fan2, pwm1, and pwm2 are always present */
+ data->has_fan |= 0x03;
+ data->has_pwm |= 0x03;
+
+ dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
+ "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
+ (data->has_pwm & (1 << 2)) ? "yes" : "no",
+ (data->has_pwm & (1 << 4)) ? "yes" : "no",
+ (data->has_pwm & (1 << 5)) ? "yes" : "no",
+ (data->has_fan & (1 << 2)) ? "yes" : "no",
+ (data->has_fan & (1 << 3)) ? "yes" : "no",
+ (data->has_fan & (1 << 4)) ? "yes" : "no",
+ (data->has_fan & (1 << 5)) ? "yes" : "no");
+
+ reg = dme1737_read(client, DME1737_REG_TACH_PWM);
+ /* Inform if fan-to-pwm mapping differs from the default */
+ if (reg != 0xa4) {
+ dev_warn(&client->dev, "Non-standard fan to pwm mapping: "
+ "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
+ "fan4->pwm%d. Please report to the driver "
+ "maintainer.\n",
+ (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+ ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+ }
+
+ /* Switch pwm[1-3] to manual mode if they are currently disabled and
+ * set the duty-cycles to 0% (which is identical to the PWMs being
+ * disabled). */
+ if (!(data->config & 0x02)) {
+ for (ix = 0; ix < 3; ix++) {
+ data->pwm_config[ix] = dme1737_read(client,
+ DME1737_REG_PWM_CONFIG(ix));
+ if ((data->has_pwm & (1 << ix)) &&
+ (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
+ dev_info(&client->dev, "Switching pwm%d to "
+ "manual mode.\n", ix + 1);
+ data->pwm_config[ix] = PWM_EN_TO_REG(1,
+ data->pwm_config[ix]);
+ dme1737_write(client, DME1737_REG_PWM(ix), 0);
+ dme1737_write(client,
+ DME1737_REG_PWM_CONFIG(ix),
+ data->pwm_config[ix]);
+ }
+ }
+ }
+
+ /* Initialize the default PWM auto channels zone (acz) assignments */
+ data->pwm_acz[0] = 1; /* pwm1 -> zone1 */
+ data->pwm_acz[1] = 2; /* pwm2 -> zone2 */
+ data->pwm_acz[2] = 4; /* pwm3 -> zone3 */
+
+ /* Set VRM */
+ data->vrm = vid_which_vrm();
+
+ return 0;
+}
+
+static int dme1737_detect(struct i2c_adapter *adapter, int address,
+ int kind)
+{
+ u8 company, verstep = 0;
+ struct i2c_client *client;
+ struct dme1737_data *data;
+ int ix, err = 0;
+ const char *name;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ goto exit;
+ }
+
+ if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &dme1737_driver;
+
+ /* A negative kind means that the driver was loaded with no force
+ * parameter (default), so we must identify the chip. */
+ if (kind < 0) {
+ company = dme1737_read(client, DME1737_REG_COMPANY);
+ verstep = dme1737_read(client, DME1737_REG_VERSTEP);
+
+ if (!((company == DME1737_COMPANY_SMSC) &&
+ ((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
+ err = -ENODEV;
+ goto exit_kfree;
+ }
+ }
+
+ kind = dme1737;
+ name = "dme1737";
+
+ /* Fill in the remaining client fields and put it into the global
+ * list */
+ strlcpy(client->name, name, I2C_NAME_SIZE);
+ mutex_init(&data->update_lock);
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client))) {
+ goto exit_kfree;
+ }
+
+ /* Initialize the DME1737 chip */
+ if ((err = dme1737_init_client(client))) {
+ goto exit_detach;
+ }
+
+ /* Create standard sysfs attributes */
+ if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) {
+ goto exit_detach;
+ }
+
+ /* Create fan sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &dme1737_fan_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
+
+ /* Create PWM sysfs attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &dme1737_pwm_group[ix]))) {
+ goto exit_remove;
+ }
+ }
+ }
+
+ /* Inform if the device is locked. Otherwise change the permissions of
+ * selected attributes from read-only to read-writeable. */
+ if (data->config & 0x02) {
+ dev_info(&client->dev, "Device is locked. Some attributes "
+ "will be read-only.\n");
+ } else {
+ /* Change permissions of standard attributes */
+ dme1737_chmod_group(client, &dme1737_lock_group,
+ S_IRUGO | S_IWUSR);
+
+ /* Change permissions of PWM attributes */
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ dme1737_chmod_group(client,
+ &dme1737_pwm_lock_group[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
+
+ /* Change permissions of pwm[1-3] if in manual mode */
+ for (ix = 0; ix < 3; ix++) {
+ if ((data->has_pwm & (1 << ix)) &&
+ (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+ dme1737_chmod_file(client,
+ dme1737_attr_pwm[ix],
+ S_IRUGO | S_IWUSR);
+ }
+ }
+ }
+
+ /* Register device */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
+
+ dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x "
+ "(rev 0x%02x)\n", client->addr, verstep);
+
+ return 0;
+
+exit_remove:
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_fan_group[ix]);
+ }
+ }
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_pwm_group[ix]);
+ }
+ }
+ sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+exit_detach:
+ i2c_detach_client(client);
+exit_kfree:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int dme1737_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!(adapter->class & I2C_CLASS_HWMON)) {
+ return 0;
+ }
+
+ return i2c_probe(adapter, &addr_data, dme1737_detect);
+}
+
+static int dme1737_detach_client(struct i2c_client *client)
+{
+ struct dme1737_data *data = i2c_get_clientdata(client);
+ int ix, err;
+
+ hwmon_device_unregister(data->class_dev);
+
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+ if (data->has_fan & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_fan_group[ix]);
+ }
+ }
+ for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+ if (data->has_pwm & (1 << ix)) {
+ sysfs_remove_group(&client->dev.kobj,
+ &dme1737_pwm_group[ix]);
+ }
+ }
+ sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+
+ if ((err = i2c_detach_client(client))) {
+ return err;
+ }
+
+ kfree(data);
+ return 0;
+}
+
+static struct i2c_driver dme1737_driver = {
+ .driver = {
+ .name = "dme1737",
+ },
+ .attach_adapter = dme1737_attach_adapter,
+ .detach_client = dme1737_detach_client,
+};
+
+static int __init dme1737_init(void)
+{
+ return i2c_add_driver(&dme1737_driver);
+}
+
+static void __exit dme1737_exit(void)
+{
+ i2c_del_driver(&dme1737_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("DME1737 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(dme1737_init);
+module_exit(dme1737_exit);
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index d5ac422d73b2..1212d6b7f316 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -27,6 +27,7 @@
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
@@ -52,9 +53,11 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
#define DS1621_REG_CONFIG_DONE 0x80
/* The DS1621 registers */
-#define DS1621_REG_TEMP 0xAA /* word, RO */
-#define DS1621_REG_TEMP_MIN 0xA2 /* word, RW */
-#define DS1621_REG_TEMP_MAX 0xA1 /* word, RW */
+static const u8 DS1621_REG_TEMP[3] = {
+ 0xAA, /* input, word, RO */
+ 0xA2, /* min, word, RW */
+ 0xA1, /* max, word, RW */
+};
#define DS1621_REG_CONF 0xAC /* byte, RW */
#define DS1621_COM_START 0xEE /* no data */
#define DS1621_COM_STOP 0x22 /* no data */
@@ -63,10 +66,7 @@ MODULE_PARM_DESC(polarity, "Output's polarity: 0 = active high, 1 = active low")
#define DS1621_ALARM_TEMP_HIGH 0x40
#define DS1621_ALARM_TEMP_LOW 0x20
-/* Conversions. Rounding and limit checking is only done on the TO_REG
- variants. Note that you should be a bit careful with which arguments
- these macros are called: arguments may be evaluated more than once.
- Fixing this is just not worth it. */
+/* Conversions */
#define ALARMS_FROM_REG(val) ((val) & \
(DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
@@ -78,7 +78,7 @@ struct ds1621_data {
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
- u16 temp, temp_min, temp_max; /* Register values, word */
+ u16 temp[3]; /* Register values, word */
u8 conf; /* Register encoding, combined */
};
@@ -101,7 +101,7 @@ static struct i2c_driver ds1621_driver = {
/* All registers are word-sized, except for the configuration register.
DS1621 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
+ the SMBus standard. */
static int ds1621_read_value(struct i2c_client *client, u8 reg)
{
if (reg == DS1621_REG_CONF)
@@ -110,9 +110,6 @@ static int ds1621_read_value(struct i2c_client *client, u8 reg)
return swab16(i2c_smbus_read_word_data(client, reg));
}
-/* All registers are word-sized, except for the configuration register.
- DS1621 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if (reg == DS1621_REG_CONF)
@@ -139,50 +136,61 @@ static void ds1621_init_client(struct i2c_client *client)
i2c_smbus_write_byte(client, DS1621_COM_START);
}
-#define show(value) \
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct ds1621_data *data = ds1621_update_client(dev); \
- return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value)); \
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ds1621_data *data = ds1621_update_client(dev);
+ return sprintf(buf, "%d\n",
+ LM75_TEMP_FROM_REG(data->temp[attr->index]));
}
-show(temp);
-show(temp_min);
-show(temp_max);
-
-#define set_temp(suffix, value, reg) \
-static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
-{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct ds1621_data *data = ds1621_update_client(dev); \
- u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10)); \
- \
- mutex_lock(&data->update_lock); \
- data->value = val; \
- ds1621_write_value(client, reg, data->value); \
- mutex_unlock(&data->update_lock); \
- return count; \
-}
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1621_data *data = ds1621_update_client(dev);
+ u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
-set_temp(min, temp_min, DS1621_REG_TEMP_MIN);
-set_temp(max, temp_max, DS1621_REG_TEMP_MAX);
+ mutex_lock(&data->update_lock);
+ data->temp[attr->index] = val;
+ ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
+ data->temp[attr->index]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct ds1621_data *data = ds1621_update_client(dev);
return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ds1621_data *data = ds1621_update_client(dev);
+ return sprintf(buf, "%d\n", !!(data->conf & attr->index));
+}
+
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+ DS1621_ALARM_TEMP_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+ DS1621_ALARM_TEMP_HIGH);
static struct attribute *ds1621_attributes[] = {
- &dev_attr_temp1_input.attr,
- &dev_attr_temp1_min.attr,
- &dev_attr_temp1_max.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
NULL
};
@@ -204,9 +212,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
int kind)
{
int conf, temp;
- struct i2c_client *new_client;
+ struct i2c_client *client;
struct ds1621_data *data;
- int err = 0;
+ int i, err = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_WORD_DATA
@@ -221,55 +229,44 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
goto exit;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &ds1621_driver;
- new_client->flags = 0;
-
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &ds1621_driver;
/* Now, we do the remaining detection. It is lousy. */
if (kind < 0) {
/* The NVB bit should be low if no EEPROM write has been
requested during the latest 10ms, which is highly
improbable in our case. */
- conf = ds1621_read_value(new_client, DS1621_REG_CONF);
+ conf = ds1621_read_value(client, DS1621_REG_CONF);
if (conf & DS1621_REG_CONFIG_NVB)
goto exit_free;
/* The 7 lowest bits of a temperature should always be 0. */
- temp = ds1621_read_value(new_client, DS1621_REG_TEMP);
- if (temp & 0x007f)
- goto exit_free;
- temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN);
- if (temp & 0x007f)
- goto exit_free;
- temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX);
- if (temp & 0x007f)
- goto exit_free;
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+ temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
+ if (temp & 0x007f)
+ goto exit_free;
+ }
}
- /* Determine the chip type - only one kind supported! */
- if (kind <= 0)
- kind = ds1621;
-
/* Fill in remaining client fields and put it into the global list */
- strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
- data->valid = 0;
+ strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto exit_free;
/* Initialize the DS1621 chip */
- ds1621_init_client(new_client);
+ ds1621_init_client(client);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
+ if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
goto exit_detach;
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -278,9 +275,9 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
+ sysfs_remove_group(&client->dev.kobj, &ds1621_group);
exit_detach:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
exit_free:
kfree(data);
exit:
@@ -314,23 +311,21 @@ static struct ds1621_data *ds1621_update_client(struct device *dev)
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
+ int i;
dev_dbg(&client->dev, "Starting ds1621 update\n");
data->conf = ds1621_read_value(client, DS1621_REG_CONF);
- data->temp = ds1621_read_value(client, DS1621_REG_TEMP);
-
- data->temp_min = ds1621_read_value(client,
- DS1621_REG_TEMP_MIN);
- data->temp_max = ds1621_read_value(client,
- DS1621_REG_TEMP_MAX);
+ for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+ data->temp[i] = ds1621_read_value(client,
+ DS1621_REG_TEMP[i]);
/* reset alarms if necessary */
new_conf = data->conf;
- if (data->temp > data->temp_min)
+ if (data->temp[0] > data->temp[1]) /* input > min */
new_conf &= ~DS1621_ALARM_TEMP_LOW;
- if (data->temp < data->temp_max)
+ if (data->temp[0] < data->temp[2]) /* input < max */
new_conf &= ~DS1621_ALARM_TEMP_HIGH;
if (data->conf != new_conf)
ds1621_write_value(client, DS1621_REG_CONF,
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index cdbe309b8fc4..6f60715f34f8 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -127,6 +127,13 @@ superio_exit(int base)
#define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr))
#define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr))
#define F71805F_REG_TEMP_MODE 0x01
+/* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */
+/* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */
+#define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \
+ (0xA0 + 0x10 * (pwmnr) + (2 - (apnr)))
+#define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \
+ (0xA4 + 0x10 * (pwmnr) + \
+ 2 * (2 - (apnr)))
#define F71805F_REG_START 0x00
/* status nr from 0 to 2 */
@@ -144,6 +151,11 @@ superio_exit(int base)
* Data structures and manipulation thereof
*/
+struct f71805f_auto_point {
+ u8 temp[3];
+ u16 fan[3];
+};
+
struct f71805f_data {
unsigned short addr;
const char *name;
@@ -170,6 +182,7 @@ struct f71805f_data {
u8 temp_hyst[3];
u8 temp_mode;
unsigned long alarms;
+ struct f71805f_auto_point auto_points[3];
};
struct f71805f_sio_data {
@@ -312,7 +325,7 @@ static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val)
static struct f71805f_data *f71805f_update_device(struct device *dev)
{
struct f71805f_data *data = dev_get_drvdata(dev);
- int nr;
+ int nr, apnr;
mutex_lock(&data->update_lock);
@@ -342,6 +355,18 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
F71805F_REG_TEMP_HYST(nr));
}
data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE);
+ for (nr = 0; nr < 3; nr++) {
+ for (apnr = 0; apnr < 3; apnr++) {
+ data->auto_points[nr].temp[apnr] =
+ f71805f_read8(data,
+ F71805F_REG_PWM_AUTO_POINT_TEMP(nr,
+ apnr));
+ data->auto_points[nr].fan[apnr] =
+ f71805f_read16(data,
+ F71805F_REG_PWM_AUTO_POINT_FAN(nr,
+ apnr));
+ }
+ }
data->last_limits = jiffies;
}
@@ -705,6 +730,70 @@ static ssize_t set_pwm_freq(struct device *dev, struct device_attribute
return count;
}
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char* buf)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+
+ return sprintf(buf, "%ld\n",
+ temp_from_reg(data->auto_points[pwmnr].temp[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *devattr,
+ const char* buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+ unsigned long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val);
+ f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr),
+ data->auto_points[pwmnr].temp[apnr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t show_pwm_auto_point_fan(struct device *dev,
+ struct device_attribute *devattr,
+ char* buf)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+
+ return sprintf(buf, "%ld\n",
+ fan_from_reg(data->auto_points[pwmnr].fan[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_fan(struct device *dev,
+ struct device_attribute *devattr,
+ const char* buf, size_t count)
+{
+ struct f71805f_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+ int pwmnr = attr->nr;
+ int apnr = attr->index;
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val);
+ f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr),
+ data->auto_points[pwmnr].fan[apnr]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@@ -932,6 +1021,63 @@ static SENSOR_DEVICE_ATTR(pwm3_freq, S_IRUGO | S_IWUSR,
show_pwm_freq, set_pwm_freq, 2);
static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 0, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 1, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+ 2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR,
+ show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+ 2, 2);
+
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
@@ -1014,6 +1160,25 @@ static struct attribute *f71805f_attributes[] = {
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr,
+
&sensor_dev_attr_in0_alarm.dev_attr.attr,
&sensor_dev_attr_in1_alarm.dev_attr.attr,
&sensor_dev_attr_in2_alarm.dev_attr.attr,
@@ -1242,12 +1407,12 @@ static int __devexit f71805f_remove(struct platform_device *pdev)
struct resource *res;
int i;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
for (i = 0; i < 4; i++)
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1290,15 +1455,12 @@ static int __init f71805f_device_add(unsigned short address,
goto exit_device_put;
}
- pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data),
- GFP_KERNEL);
- if (!pdev->dev.platform_data) {
- err = -ENOMEM;
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct f71805f_sio_data));
+ if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
- memcpy(pdev->dev.platform_data, sio_data,
- sizeof(struct f71805f_sio_data));
err = platform_device_add(pdev);
if (err) {
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 62afc63708a5..eff6036e15c0 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -6,6 +6,7 @@
IT8712F Super I/O chip w/LPC interface
IT8716F Super I/O chip w/LPC interface
IT8718F Super I/O chip w/LPC interface
+ IT8726F Super I/O chip w/LPC interface
Sis950 A clone of the IT8705F
Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com>
@@ -30,8 +31,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -40,10 +40,12 @@
#include <linux/sysfs.h>
#include <asm/io.h>
+#define DRVNAME "it87"
-static unsigned short isa_address;
enum chips { it87, it8712, it8716, it8718 };
+static struct platform_device *pdev;
+
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
#define VAL 0x2f /* The value to read/write */
@@ -97,6 +99,7 @@ superio_exit(void)
#define IT8705F_DEVID 0x8705
#define IT8716F_DEVID 0x8716
#define IT8718F_DEVID 0x8718
+#define IT8726F_DEVID 0x8726
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
@@ -110,10 +113,6 @@ static int update_vbat;
/* Not all BIOSes properly configure the PWM registers */
static int fix_pwm_polarity;
-/* Values read from Super-I/O config space */
-static u16 chip_type;
-static u8 vid_value;
-
/* Many IT87 constants specified below */
/* Length of ISA address segment */
@@ -214,13 +213,20 @@ static const unsigned int pwm_freq[8] = {
};
+struct it87_sio_data {
+ enum chips type;
+ /* Values read from Super-I/O config space */
+ u8 vid_value;
+};
+
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct it87_data {
- struct i2c_client client;
struct class_device *class_dev;
enum chips type;
+ unsigned short addr;
+ const char *name;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -245,26 +251,25 @@ struct it87_data {
};
-static int it87_detect(struct i2c_adapter *adapter);
-static int it87_detach_client(struct i2c_client *client);
+static int it87_probe(struct platform_device *pdev);
+static int it87_remove(struct platform_device *pdev);
-static int it87_read_value(struct i2c_client *client, u8 reg);
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int it87_read_value(struct it87_data *data, u8 reg);
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value);
static struct it87_data *it87_update_device(struct device *dev);
-static int it87_check_pwm(struct i2c_client *client);
-static void it87_init_client(struct i2c_client *client, struct it87_data *data);
+static int it87_check_pwm(struct device *dev);
+static void it87_init_device(struct platform_device *pdev);
-static struct i2c_driver it87_isa_driver = {
+static struct platform_driver it87_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "it87-isa",
+ .name = DRVNAME,
},
- .attach_adapter = it87_detect,
- .detach_client = it87_detach_client,
+ .probe = it87_probe,
+ .remove = __devexit_p(it87_remove),
};
-
static ssize_t show_in(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -301,13 +306,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val);
- it87_write_value(client, IT87_REG_VIN_MIN(nr),
+ it87_write_value(data, IT87_REG_VIN_MIN(nr),
data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -318,13 +322,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val);
- it87_write_value(client, IT87_REG_VIN_MAX(nr),
+ it87_write_value(data, IT87_REG_VIN_MAX(nr),
data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -392,13 +395,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_high[nr] = TEMP_TO_REG(val);
- it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+ it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -408,13 +410,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_low[nr] = TEMP_TO_REG(val);
- it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
+ it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -451,8 +452,7 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -468,7 +468,7 @@ static ssize_t set_sensor(struct device *dev, struct device_attribute *attr,
mutex_unlock(&data->update_lock);
return -EINVAL;
}
- it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+ it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
mutex_unlock(&data->update_lock);
return count;
}
@@ -542,13 +542,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
u8 reg;
mutex_lock(&data->update_lock);
- reg = it87_read_value(client, IT87_REG_FAN_DIV);
+ reg = it87_read_value(data, IT87_REG_FAN_DIV);
switch (nr) {
case 0: data->fan_div[nr] = reg & 0x07; break;
case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
@@ -556,7 +555,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
}
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -566,14 +565,13 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
int min;
u8 old;
mutex_lock(&data->update_lock);
- old = it87_read_value(client, IT87_REG_FAN_DIV);
+ old = it87_read_value(data, IT87_REG_FAN_DIV);
/* Save fan min limit */
min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
@@ -594,11 +592,11 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
val |= (data->fan_div[1] & 0x07) << 3;
if (data->fan_div[2] == 3)
val |= 0x1 << 6;
- it87_write_value(client, IT87_REG_FAN_DIV, val);
+ it87_write_value(data, IT87_REG_FAN_DIV, val);
/* Restore fan min limit */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+ it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
@@ -609,8 +607,7 @@ static ssize_t set_pwm_enable(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -618,17 +615,17 @@ static ssize_t set_pwm_enable(struct device *dev,
if (val == 0) {
int tmp;
/* make sure the fan is on when in on/off mode */
- tmp = it87_read_value(client, IT87_REG_FAN_CTL);
- it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr));
+ tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+ it87_write_value(data, IT87_REG_FAN_CTL, tmp | (1 << nr));
/* set on/off mode */
data->fan_main_ctrl &= ~(1 << nr);
- it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
} else if (val == 1) {
/* set SmartGuardian mode */
data->fan_main_ctrl |= (1 << nr);
- it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
/* set saved pwm value, clear FAN_CTLX PWM mode bit */
- it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+ it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
} else {
mutex_unlock(&data->update_lock);
return -EINVAL;
@@ -643,8 +640,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
if (val < 0 || val > 255)
@@ -653,15 +649,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
mutex_lock(&data->update_lock);
data->manual_pwm_ctl[nr] = val;
if (data->fan_main_ctrl & (1 << nr))
- it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+ it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_pwm_freq(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
int i;
@@ -672,9 +667,9 @@ static ssize_t set_pwm_freq(struct device *dev,
}
mutex_lock(&data->update_lock);
- data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL) & 0x8f;
+ data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
data->fan_ctl |= i << 4;
- it87_write_value(client, IT87_REG_FAN_CTL, data->fan_ctl);
+ it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
mutex_unlock(&data->update_lock);
return count;
@@ -729,15 +724,14 @@ static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN16_TO_REG(val);
- it87_write_value(client, IT87_REG_FAN_MIN(nr),
+ it87_write_value(data, IT87_REG_FAN_MIN(nr),
data->fan_min[nr] & 0xff);
- it87_write_value(client, IT87_REG_FANX_MIN(nr),
+ it87_write_value(data, IT87_REG_FANX_MIN(nr),
data->fan_min[nr] >> 8);
mutex_unlock(&data->update_lock);
return count;
@@ -775,8 +769,7 @@ show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t
store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
u32 val;
val = simple_strtoul(buf, NULL, 10);
@@ -794,6 +787,14 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct it87_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *it87_attributes[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
@@ -835,6 +836,7 @@ static struct attribute *it87_attributes[] = {
&sensor_dev_attr_temp3_type.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -877,17 +879,36 @@ static const struct attribute_group it87_group_opt = {
};
/* SuperIO detection - will change isa_address if a chip is found */
-static int __init it87_find(unsigned short *address)
+static int __init it87_find(unsigned short *address,
+ struct it87_sio_data *sio_data)
{
int err = -ENODEV;
+ u16 chip_type;
superio_enter();
chip_type = superio_inw(DEVID);
- if (chip_type != IT8712F_DEVID
- && chip_type != IT8716F_DEVID
- && chip_type != IT8718F_DEVID
- && chip_type != IT8705F_DEVID)
- goto exit;
+
+ switch (chip_type) {
+ case IT8705F_DEVID:
+ sio_data->type = it87;
+ break;
+ case IT8712F_DEVID:
+ sio_data->type = it8712;
+ break;
+ case IT8716F_DEVID:
+ case IT8726F_DEVID:
+ sio_data->type = it8716;
+ break;
+ case IT8718F_DEVID:
+ sio_data->type = it8718;
+ break;
+ case 0xffff: /* No device at all */
+ goto exit;
+ default:
+ pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n",
+ chip_type);
+ goto exit;
+ }
superio_select(PME);
if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
@@ -911,7 +932,7 @@ static int __init it87_find(unsigned short *address)
superio_select(GPIO);
if (chip_type == it8718)
- vid_value = superio_inb(IT87_SIO_VID_REG);
+ sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
reg = superio_inb(IT87_SIO_PINX2_REG);
if (reg & (1 << 0))
@@ -925,18 +946,26 @@ exit:
return err;
}
-/* This function is called by i2c_probe */
-static int it87_detect(struct i2c_adapter *adapter)
+static int __devinit it87_probe(struct platform_device *pdev)
{
- struct i2c_client *new_client;
struct it87_data *data;
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct it87_sio_data *sio_data = dev->platform_data;
int err = 0;
- const char *name;
int enable_pwm_interface;
-
- /* Reserve the ISA region */
- if (!request_region(isa_address, IT87_EXTENT,
- it87_isa_driver.driver.name)){
+ static const char *names[] = {
+ "it87",
+ "it8712",
+ "it8716",
+ "it8718",
+ };
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, IT87_EXTENT, DRVNAME)) {
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start,
+ (unsigned long)(res->start + IT87_EXTENT - 1));
err = -EBUSY;
goto ERROR0;
}
@@ -946,129 +975,104 @@ static int it87_detect(struct i2c_adapter *adapter)
goto ERROR1;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = isa_address;
- new_client->adapter = adapter;
- new_client->driver = &it87_isa_driver;
+ data->addr = res->start;
+ data->type = sio_data->type;
+ data->name = names[sio_data->type];
/* Now, we do the remaining detection. */
- if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80)
- || it87_read_value(new_client, IT87_REG_CHIPID) != 0x90) {
+ if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
+ || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
err = -ENODEV;
goto ERROR2;
}
- /* Determine the chip type. */
- switch (chip_type) {
- case IT8712F_DEVID:
- data->type = it8712;
- name = "it8712";
- break;
- case IT8716F_DEVID:
- data->type = it8716;
- name = "it8716";
- break;
- case IT8718F_DEVID:
- data->type = it8718;
- name = "it8718";
- break;
- default:
- data->type = it87;
- name = "it87";
- }
+ platform_set_drvdata(pdev, data);
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto ERROR2;
-
/* Check PWM configuration */
- enable_pwm_interface = it87_check_pwm(new_client);
+ enable_pwm_interface = it87_check_pwm(dev);
/* Initialize the IT87 chip */
- it87_init_client(new_client, data);
+ it87_init_device(pdev);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
- goto ERROR3;
+ if ((err = sysfs_create_group(&dev->kobj, &it87_group)))
+ goto ERROR2;
/* Do not create fan files for disabled fans */
if (data->type == it8716 || data->type == it8718) {
/* 16-bit tachometers */
if (data->has_fan & (1 << 0)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan1_input16.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan1_min16.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 1)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan2_input16.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan2_min16.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 2)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan3_input16.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan3_min16.dev_attr)))
goto ERROR4;
}
} else {
/* 8-bit tachometers with clock divider */
if (data->has_fan & (1 << 0)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan1_input.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan1_min.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan1_div.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 1)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan2_input.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan2_min.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan2_div.dev_attr)))
goto ERROR4;
}
if (data->has_fan & (1 << 2)) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_fan3_input.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan3_min.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_fan3_div.dev_attr)))
goto ERROR4;
}
}
if (enable_pwm_interface) {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(dev,
&sensor_dev_attr_pwm1_enable.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm2_enable.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm3_enable.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm1.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm2.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&sensor_dev_attr_pwm3.dev_attr))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_pwm1_freq))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_pwm2_freq))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_pwm3_freq)))
goto ERROR4;
}
@@ -1077,15 +1081,15 @@ static int it87_detect(struct i2c_adapter *adapter)
|| data->type == it8718) {
data->vrm = vid_which_vrm();
/* VID reading from Super-I/O config space if available */
- data->vid = vid_value;
- if ((err = device_create_file(&new_client->dev,
+ data->vid = sio_data->vid_value;
+ if ((err = device_create_file(dev,
&dev_attr_vrm))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(dev,
&dev_attr_cpu0_vid)))
goto ERROR4;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto ERROR4;
@@ -1094,31 +1098,27 @@ static int it87_detect(struct i2c_adapter *adapter)
return 0;
ERROR4:
- sysfs_remove_group(&new_client->dev.kobj, &it87_group);
- sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
-ERROR3:
- i2c_detach_client(new_client);
+ sysfs_remove_group(&dev->kobj, &it87_group);
+ sysfs_remove_group(&dev->kobj, &it87_group_opt);
ERROR2:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
ERROR1:
- release_region(isa_address, IT87_EXTENT);
+ release_region(res->start, IT87_EXTENT);
ERROR0:
return err;
}
-static int it87_detach_client(struct i2c_client *client)
+static int __devexit it87_remove(struct platform_device *pdev)
{
- struct it87_data *data = i2c_get_clientdata(client);
- int err;
+ struct it87_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &it87_group);
- sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
+ sysfs_remove_group(&pdev->dev.kobj, &it87_group);
+ sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr, IT87_EXTENT);
+ release_region(data->addr, IT87_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -1127,28 +1127,29 @@ static int it87_detach_client(struct i2c_client *client)
/* Must be called with data->update_lock held, except during initialization.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
-static int it87_read_value(struct i2c_client *client, u8 reg)
+static int it87_read_value(struct it87_data *data, u8 reg)
{
- outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
- return inb_p(client->addr + IT87_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+ return inb_p(data->addr + IT87_DATA_REG_OFFSET);
}
/* Must be called with data->update_lock held, except during initialization.
We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
would slow down the IT87 access and should not be necessary. */
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
{
- outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
- outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+ outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
}
/* Return 1 if and only if the PWM interface is safe to use */
-static int it87_check_pwm(struct i2c_client *client)
+static int __devinit it87_check_pwm(struct device *dev)
{
+ struct it87_data *data = dev_get_drvdata(dev);
/* Some BIOSes fail to correctly configure the IT87 fans. All fans off
* and polarity set to active low is sign that this is the case so we
* disable pwm control to protect the user. */
- int tmp = it87_read_value(client, IT87_REG_FAN_CTL);
+ int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
if ((tmp & 0x87) == 0) {
if (fix_pwm_polarity) {
/* The user asks us to attempt a chip reconfiguration.
@@ -1158,7 +1159,7 @@ static int it87_check_pwm(struct i2c_client *client)
u8 pwm[3];
for (i = 0; i < 3; i++)
- pwm[i] = it87_read_value(client,
+ pwm[i] = it87_read_value(data,
IT87_REG_PWM(i));
/* If any fan is in automatic pwm mode, the polarity
@@ -1166,26 +1167,26 @@ static int it87_check_pwm(struct i2c_client *client)
* better don't change anything (but still disable the
* PWM interface). */
if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
- dev_info(&client->dev, "Reconfiguring PWM to "
+ dev_info(dev, "Reconfiguring PWM to "
"active high polarity\n");
- it87_write_value(client, IT87_REG_FAN_CTL,
+ it87_write_value(data, IT87_REG_FAN_CTL,
tmp | 0x87);
for (i = 0; i < 3; i++)
- it87_write_value(client,
+ it87_write_value(data,
IT87_REG_PWM(i),
0x7f & ~pwm[i]);
return 1;
}
- dev_info(&client->dev, "PWM configuration is "
+ dev_info(dev, "PWM configuration is "
"too broken to be fixed\n");
}
- dev_info(&client->dev, "Detected broken BIOS "
+ dev_info(dev, "Detected broken BIOS "
"defaults, disabling PWM interface\n");
return 0;
} else if (fix_pwm_polarity) {
- dev_info(&client->dev, "PWM configuration looks "
+ dev_info(dev, "PWM configuration looks "
"sane, won't touch\n");
}
@@ -1193,8 +1194,9 @@ static int it87_check_pwm(struct i2c_client *client)
}
/* Called when we have found a new IT87. */
-static void it87_init_client(struct i2c_client *client, struct it87_data *data)
+static void __devinit it87_init_device(struct platform_device *pdev)
{
+ struct it87_data *data = platform_get_drvdata(pdev);
int tmp, i;
/* initialize to sane defaults:
@@ -1214,48 +1216,48 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
* means -1 degree C, which surprisingly doesn't trigger an alarm,
* but is still confusing, so change to 127 degrees C. */
for (i = 0; i < 8; i++) {
- tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
+ tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
if (tmp == 0xff)
- it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
+ it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
}
for (i = 0; i < 3; i++) {
- tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+ tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
if (tmp == 0xff)
- it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
+ it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
}
/* Check if temperature channnels are reset manually or by some reason */
- tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+ tmp = it87_read_value(data, IT87_REG_TEMP_ENABLE);
if ((tmp & 0x3f) == 0) {
/* Temp1,Temp3=thermistor; Temp2=thermal diode */
tmp = (tmp & 0xc0) | 0x2a;
- it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp);
+ it87_write_value(data, IT87_REG_TEMP_ENABLE, tmp);
}
data->sensor = tmp;
/* Check if voltage monitors are reset manually or by some reason */
- tmp = it87_read_value(client, IT87_REG_VIN_ENABLE);
+ tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
if ((tmp & 0xff) == 0) {
/* Enable all voltage monitors */
- it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
+ it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
}
/* Check if tachometers are reset manually or by some reason */
- data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
+ data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
if ((data->fan_main_ctrl & 0x70) == 0) {
/* Enable all fan tachometers */
data->fan_main_ctrl |= 0x70;
- it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+ it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
}
data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
/* Set tachometers to 16-bit mode if needed */
if (data->type == it8716 || data->type == it8718) {
- tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
+ tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
if (~tmp & 0x07 & data->has_fan) {
- dev_dbg(&client->dev,
+ dev_dbg(&pdev->dev,
"Setting fan1-3 to 16-bit mode\n");
- it87_write_value(client, IT87_REG_FAN_16BIT,
+ it87_write_value(data, IT87_REG_FAN_16BIT,
tmp | 0x07);
}
}
@@ -1265,7 +1267,7 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
for (i = 0; i < 3; i++) {
if (data->fan_main_ctrl & (1 << i)) {
/* pwm mode */
- tmp = it87_read_value(client, IT87_REG_PWM(i));
+ tmp = it87_read_value(data, IT87_REG_PWM(i));
if (tmp & 0x80) {
/* automatic pwm - not yet implemented, but
* leave the settings made by the BIOS alone
@@ -1279,15 +1281,14 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
}
/* Start monitoring */
- it87_write_value(client, IT87_REG_CONFIG,
- (it87_read_value(client, IT87_REG_CONFIG) & 0x36)
+ it87_write_value(data, IT87_REG_CONFIG,
+ (it87_read_value(data, IT87_REG_CONFIG) & 0x36)
| (update_vbat ? 0x41 : 0x01));
}
static struct it87_data *it87_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct it87_data *data = i2c_get_clientdata(client);
+ struct it87_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -1298,20 +1299,20 @@ static struct it87_data *it87_update_device(struct device *dev)
if (update_vbat) {
/* Cleared after each update, so reenable. Value
returned by this read will be previous value */
- it87_write_value(client, IT87_REG_CONFIG,
- it87_read_value(client, IT87_REG_CONFIG) | 0x40);
+ it87_write_value(data, IT87_REG_CONFIG,
+ it87_read_value(data, IT87_REG_CONFIG) | 0x40);
}
for (i = 0; i <= 7; i++) {
data->in[i] =
- it87_read_value(client, IT87_REG_VIN(i));
+ it87_read_value(data, IT87_REG_VIN(i));
data->in_min[i] =
- it87_read_value(client, IT87_REG_VIN_MIN(i));
+ it87_read_value(data, IT87_REG_VIN_MIN(i));
data->in_max[i] =
- it87_read_value(client, IT87_REG_VIN_MAX(i));
+ it87_read_value(data, IT87_REG_VIN_MAX(i));
}
/* in8 (battery) has no limit registers */
data->in[8] =
- it87_read_value(client, IT87_REG_VIN(8));
+ it87_read_value(data, IT87_REG_VIN(8));
for (i = 0; i < 3; i++) {
/* Skip disabled fans */
@@ -1319,46 +1320,47 @@ static struct it87_data *it87_update_device(struct device *dev)
continue;
data->fan_min[i] =
- it87_read_value(client, IT87_REG_FAN_MIN(i));
- data->fan[i] = it87_read_value(client,
+ it87_read_value(data, IT87_REG_FAN_MIN(i));
+ data->fan[i] = it87_read_value(data,
IT87_REG_FAN(i));
/* Add high byte if in 16-bit mode */
if (data->type == it8716 || data->type == it8718) {
- data->fan[i] |= it87_read_value(client,
+ data->fan[i] |= it87_read_value(data,
IT87_REG_FANX(i)) << 8;
- data->fan_min[i] |= it87_read_value(client,
+ data->fan_min[i] |= it87_read_value(data,
IT87_REG_FANX_MIN(i)) << 8;
}
}
for (i = 0; i < 3; i++) {
data->temp[i] =
- it87_read_value(client, IT87_REG_TEMP(i));
+ it87_read_value(data, IT87_REG_TEMP(i));
data->temp_high[i] =
- it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+ it87_read_value(data, IT87_REG_TEMP_HIGH(i));
data->temp_low[i] =
- it87_read_value(client, IT87_REG_TEMP_LOW(i));
+ it87_read_value(data, IT87_REG_TEMP_LOW(i));
}
/* Newer chips don't have clock dividers */
if ((data->has_fan & 0x07) && data->type != it8716
&& data->type != it8718) {
- i = it87_read_value(client, IT87_REG_FAN_DIV);
+ i = it87_read_value(data, IT87_REG_FAN_DIV);
data->fan_div[0] = i & 0x07;
data->fan_div[1] = (i >> 3) & 0x07;
data->fan_div[2] = (i & 0x40) ? 3 : 1;
}
data->alarms =
- it87_read_value(client, IT87_REG_ALARM1) |
- (it87_read_value(client, IT87_REG_ALARM2) << 8) |
- (it87_read_value(client, IT87_REG_ALARM3) << 16);
- data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
- data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL);
-
- data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+ it87_read_value(data, IT87_REG_ALARM1) |
+ (it87_read_value(data, IT87_REG_ALARM2) << 8) |
+ (it87_read_value(data, IT87_REG_ALARM3) << 16);
+ data->fan_main_ctrl = it87_read_value(data,
+ IT87_REG_FAN_MAIN_CTRL);
+ data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
+
+ data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability */
if (data->type == it8712 || data->type == it8716) {
- data->vid = it87_read_value(client, IT87_REG_VID);
+ data->vid = it87_read_value(data, IT87_REG_VID);
/* The older IT8712F revisions had only 5 VID pins,
but we assume it is always safe to read 6 bits. */
data->vid &= 0x3f;
@@ -1372,24 +1374,85 @@ static struct it87_data *it87_update_device(struct device *dev)
return data;
}
+static int __init it87_device_add(unsigned short address,
+ const struct it87_sio_data *sio_data)
+{
+ struct resource res = {
+ .start = address ,
+ .end = address + IT87_EXTENT - 1,
+ .name = DRVNAME,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct it87_sio_data));
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __init sm_it87_init(void)
{
- int res;
+ int err;
+ unsigned short isa_address=0;
+ struct it87_sio_data sio_data;
+
+ err = it87_find(&isa_address, &sio_data);
+ if (err)
+ return err;
+ err = platform_driver_register(&it87_driver);
+ if (err)
+ return err;
- if ((res = it87_find(&isa_address)))
- return res;
- return i2c_isa_add_driver(&it87_isa_driver);
+ err = it87_device_add(isa_address, &sio_data);
+ if (err){
+ platform_driver_unregister(&it87_driver);
+ return err;
+ }
+
+ return 0;
}
static void __exit sm_it87_exit(void)
{
- i2c_isa_del_driver(&it87_isa_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&it87_driver);
}
MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
"Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
+MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8726F, SiS950 driver");
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
module_param(fix_pwm_polarity, bool, 0);
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index d69f3cf07122..2162d69a8c06 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -364,7 +364,7 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
@@ -383,7 +383,7 @@ static struct attribute *lm63_attributes[] = {
&dev_attr_temp2_crit_hyst.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 7eaae3834e15..275d392eca61 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -96,6 +96,10 @@ static int __devinit lm70_probe(struct spi_device *spi)
struct lm70 *p_lm70;
int status;
+ /* signaling is SPI_MODE_0 on a 3-wire link (shared SI/SO) */
+ if ((spi->mode & (SPI_CPOL|SPI_CPHA)) || !(spi->mode & SPI_3WIRE))
+ return -EINVAL;
+
p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
if (!p_lm70)
return -ENOMEM;
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index feb87b41e986..654c0f73464d 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -223,14 +223,14 @@ static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 10);
static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
@@ -245,7 +245,7 @@ static struct attribute *lm83_attributes[] = {
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&dev_attr_alarms.attr,
@@ -266,9 +266,9 @@ static struct attribute *lm83_attributes_opt[] = {
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp4_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
NULL
};
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 6882ce75feee..48833fff4920 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -43,6 +43,13 @@
* variants. The extra address and features of the MAX6659 are not
* supported by this driver.
*
+ * This driver also supports the MAX6680 and MAX6681, two other sensor
+ * chips made by Maxim. These are quite similar to the other Maxim
+ * chips. Complete datasheet can be obtained at:
+ * http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
+ * The MAX6680 and MAX6681 only differ in the pinout so they can be
+ * treated identically.
+ *
* This driver also supports the ADT7461 chip from Analog Devices but
* only in its "compatability mode". If an ADT7461 chip is found but
* is configured in non-compatible mode (where its temperature
@@ -84,20 +91,25 @@
/*
* Addresses to scan
* Address is fully defined internally and cannot be changed except for
- * MAX6659.
+ * MAX6659, MAX6680 and MAX6681.
* LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658
* have address 0x4c.
* ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d.
* MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
+ * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+ * 0x4c, 0x4d or 0x4e.
*/
-static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
+ 0x29, 0x2a, 0x2b,
+ 0x4c, 0x4d, 0x4e,
+ I2C_CLIENT_END };
/*
* Insmod parameters
*/
-I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
+I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
/*
* The LM90 registers
@@ -359,7 +371,7 @@ static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
/* Individual alarm files */
static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
@@ -381,7 +393,7 @@ static struct attribute *lm90_attributes[] = {
&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
@@ -429,7 +441,7 @@ static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec);
*/
/* The ADM1032 supports PEC but not on write byte transactions, so we need
- to explicitely ask for a transaction without PEC. */
+ to explicitly ask for a transaction without PEC. */
static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
{
return i2c_smbus_xfer(client->adapter, client->addr,
@@ -525,7 +537,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
&reg_convrate) < 0)
goto exit_free;
- if (man_id == 0x01) { /* National Semiconductor */
+ if ((address == 0x4C || address == 0x4D)
+ && man_id == 0x01) { /* National Semiconductor */
u8 reg_config2;
if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2,
@@ -548,7 +561,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
}
}
} else
- if (man_id == 0x41) { /* Analog Devices */
+ if ((address == 0x4C || address == 0x4D)
+ && man_id == 0x41) { /* Analog Devices */
if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
&& (reg_config1 & 0x3F) == 0x00
&& reg_convrate <= 0x0A) {
@@ -562,18 +576,30 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
} else
if (man_id == 0x4D) { /* Maxim */
/*
- * The Maxim variants do NOT have a chip_id register.
- * Reading from that address will return the last read
- * value, which in our case is those of the man_id
- * register. Likewise, the config1 register seems to
- * lack a low nibble, so the value will be those of the
- * previous read, so in our case those of the man_id
- * register.
+ * The MAX6657, MAX6658 and MAX6659 do NOT have a
+ * chip_id register. Reading from that address will
+ * return the last read value, which in our case is
+ * those of the man_id register. Likewise, the config1
+ * register seems to lack a low nibble, so the value
+ * will be those of the previous read, so in our case
+ * those of the man_id register.
*/
if (chip_id == man_id
+ && (address == 0x4F || address == 0x4D)
&& (reg_config1 & 0x1F) == (man_id & 0x0F)
&& reg_convrate <= 0x09) {
kind = max6657;
+ } else
+ /* The chip_id register of the MAX6680 and MAX6681
+ * holds the revision of the chip.
+ * the lowest bit of the config1 register is unused
+ * and should return zero when read, so should the
+ * second to last bit of config1 (software reset)
+ */
+ if (chip_id == 0x01
+ && (reg_config1 & 0x03) == 0x00
+ && reg_convrate <= 0x07) {
+ kind = max6680;
}
}
@@ -599,6 +625,8 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
name = "lm86";
} else if (kind == max6657) {
name = "max6657";
+ } else if (kind == max6680) {
+ name = "max6680";
} else if (kind == adt7461) {
name = "adt7461";
}
@@ -646,7 +674,8 @@ exit:
static void lm90_init_client(struct i2c_client *client)
{
- u8 config;
+ u8 config, config_orig;
+ struct lm90_data *data = i2c_get_clientdata(client);
/*
* Start the conversions.
@@ -657,9 +686,20 @@ static void lm90_init_client(struct i2c_client *client)
dev_warn(&client->dev, "Initialization failed!\n");
return;
}
- if (config & 0x40)
- i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
- config & 0xBF); /* run */
+ config_orig = config;
+
+ /*
+ * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
+ * 0.125 degree resolution) and range (0x08, extend range
+ * to -64 degree) mode for the remote temperature sensor.
+ */
+ if (data->kind == max6680) {
+ config |= 0x18;
+ }
+
+ config &= 0xBF; /* run */
+ if (config != config_orig) /* Only write if changed */
+ i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
}
static int lm90_detach_client(struct i2c_client *client)
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
new file mode 100644
index 000000000000..23edf4fe4221
--- /dev/null
+++ b/drivers/hwmon/lm93.c
@@ -0,0 +1,2655 @@
+/*
+ lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+
+ Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
+ Copyright (c) 2004 Utilitek Systems, Inc.
+
+ derived in part from lm78.c:
+ Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
+
+ derived in part from lm85.c:
+ Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
+ Copyright (c) 2003 Margit Schubert-While <margitsw@t-online.de>
+
+ derived in part from w83l785ts.c:
+ Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
+
+ Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
+ Copyright (c) 2005 Aspen Systems, Inc.
+
+ Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
+ Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
+
+ Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+ Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+/* LM93 REGISTER ADDRESSES */
+
+/* miscellaneous */
+#define LM93_REG_MFR_ID 0x3e
+#define LM93_REG_VER 0x3f
+#define LM93_REG_STATUS_CONTROL 0xe2
+#define LM93_REG_CONFIG 0xe3
+#define LM93_REG_SLEEP_CONTROL 0xe4
+
+/* alarm values start here */
+#define LM93_REG_HOST_ERROR_1 0x48
+
+/* voltage inputs: in1-in16 (nr => 0-15) */
+#define LM93_REG_IN(nr) (0x56 + (nr))
+#define LM93_REG_IN_MIN(nr) (0x90 + (nr) * 2)
+#define LM93_REG_IN_MAX(nr) (0x91 + (nr) * 2)
+
+/* temperature inputs: temp1-temp4 (nr => 0-3) */
+#define LM93_REG_TEMP(nr) (0x50 + (nr))
+#define LM93_REG_TEMP_MIN(nr) (0x78 + (nr) * 2)
+#define LM93_REG_TEMP_MAX(nr) (0x79 + (nr) * 2)
+
+/* temp[1-4]_auto_boost (nr => 0-3) */
+#define LM93_REG_BOOST(nr) (0x80 + (nr))
+
+/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */
+#define LM93_REG_PROCHOT_CUR(nr) (0x67 + (nr) * 2)
+#define LM93_REG_PROCHOT_AVG(nr) (0x68 + (nr) * 2)
+#define LM93_REG_PROCHOT_MAX(nr) (0xb0 + (nr))
+
+/* fan tach inputs: fan1-fan4 (nr => 0-3) */
+#define LM93_REG_FAN(nr) (0x6e + (nr) * 2)
+#define LM93_REG_FAN_MIN(nr) (0xb4 + (nr) * 2)
+
+/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */
+#define LM93_REG_PWM_CTL(nr,reg) (0xc8 + (reg) + (nr) * 4)
+#define LM93_PWM_CTL1 0x0
+#define LM93_PWM_CTL2 0x1
+#define LM93_PWM_CTL3 0x2
+#define LM93_PWM_CTL4 0x3
+
+/* GPIO input state */
+#define LM93_REG_GPI 0x6b
+
+/* vid inputs: vid1-vid2 (nr => 0-1) */
+#define LM93_REG_VID(nr) (0x6c + (nr))
+
+/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */
+#define LM93_REG_VCCP_LIMIT_OFF(nr) (0xb2 + (nr))
+
+/* temp[1-4]_auto_boost_hyst */
+#define LM93_REG_BOOST_HYST_12 0xc0
+#define LM93_REG_BOOST_HYST_34 0xc1
+#define LM93_REG_BOOST_HYST(nr) (0xc0 + (nr)/2)
+
+/* temp[1-4]_auto_pwm_[min|hyst] */
+#define LM93_REG_PWM_MIN_HYST_12 0xc3
+#define LM93_REG_PWM_MIN_HYST_34 0xc4
+#define LM93_REG_PWM_MIN_HYST(nr) (0xc3 + (nr)/2)
+
+/* prochot_override & prochot_interval */
+#define LM93_REG_PROCHOT_OVERRIDE 0xc6
+#define LM93_REG_PROCHOT_INTERVAL 0xc7
+
+/* temp[1-4]_auto_base (nr => 0-3) */
+#define LM93_REG_TEMP_BASE(nr) (0xd0 + (nr))
+
+/* temp[1-4]_auto_offsets (step => 0-11) */
+#define LM93_REG_TEMP_OFFSET(step) (0xd4 + (step))
+
+/* #PROCHOT & #VRDHOT PWM ramp control */
+#define LM93_REG_PWM_RAMP_CTL 0xbf
+
+/* miscellaneous */
+#define LM93_REG_SFC1 0xbc
+#define LM93_REG_SFC2 0xbd
+#define LM93_REG_GPI_VID_CTL 0xbe
+#define LM93_REG_SF_TACH_TO_PWM 0xe0
+
+/* error masks */
+#define LM93_REG_GPI_ERR_MASK 0xec
+#define LM93_REG_MISC_ERR_MASK 0xed
+
+/* LM93 REGISTER VALUES */
+#define LM93_MFR_ID 0x73
+#define LM93_MFR_ID_PROTOTYPE 0x72
+
+/* SMBus capabilities */
+#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)
+#define LM93_SMBUS_FUNC_MIN (I2C_FUNC_SMBUS_BYTE_DATA | \
+ I2C_FUNC_SMBUS_WORD_DATA)
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(lm93);
+
+static int disable_block;
+module_param(disable_block, bool, 0);
+MODULE_PARM_DESC(disable_block,
+ "Set to non-zero to disable SMBus block data transactions.");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization.");
+
+static int vccp_limit_type[2] = {0,0};
+module_param_array(vccp_limit_type, int, NULL, 0);
+MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes.");
+
+static int vid_agtl;
+module_param(vid_agtl, int, 0);
+MODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds.");
+
+/* Driver data */
+static struct i2c_driver lm93_driver;
+
+/* LM93 BLOCK READ COMMANDS */
+static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = {
+ { 0xf2, 8 },
+ { 0xf3, 8 },
+ { 0xf4, 6 },
+ { 0xf5, 16 },
+ { 0xf6, 4 },
+ { 0xf7, 8 },
+ { 0xf8, 12 },
+ { 0xf9, 32 },
+ { 0xfa, 8 },
+ { 0xfb, 8 },
+ { 0xfc, 16 },
+ { 0xfd, 9 },
+};
+
+/* ALARMS: SYSCTL format described further below
+ REG: 64 bits in 8 registers, as immediately below */
+struct block1_t {
+ u8 host_status_1;
+ u8 host_status_2;
+ u8 host_status_3;
+ u8 host_status_4;
+ u8 p1_prochot_status;
+ u8 p2_prochot_status;
+ u8 gpi_status;
+ u8 fan_status;
+};
+
+/*
+ * Client-specific data
+ */
+struct lm93_data {
+ struct i2c_client client;
+ struct class_device *class_dev;
+
+ struct mutex update_lock;
+ unsigned long last_updated; /* In jiffies */
+
+ /* client update function */
+ void (*update)(struct lm93_data *, struct i2c_client *);
+
+ char valid; /* !=0 if following fields are valid */
+
+ /* register values, arranged by block read groups */
+ struct block1_t block1;
+
+ /* temp1 - temp4: unfiltered readings
+ temp1 - temp2: filtered readings */
+ u8 block2[6];
+
+ /* vin1 - vin16: readings */
+ u8 block3[16];
+
+ /* prochot1 - prochot2: readings */
+ struct {
+ u8 cur;
+ u8 avg;
+ } block4[2];
+
+ /* fan counts 1-4 => 14-bits, LE, *left* justified */
+ u16 block5[4];
+
+ /* block6 has a lot of data we don't need */
+ struct {
+ u8 min;
+ u8 max;
+ } temp_lim[3];
+
+ /* vin1 - vin16: low and high limits */
+ struct {
+ u8 min;
+ u8 max;
+ } block7[16];
+
+ /* fan count limits 1-4 => same format as block5 */
+ u16 block8[4];
+
+ /* pwm control registers (2 pwms, 4 regs) */
+ u8 block9[2][4];
+
+ /* auto/pwm base temp and offset temp registers */
+ struct {
+ u8 base[4];
+ u8 offset[12];
+ } block10;
+
+ /* master config register */
+ u8 config;
+
+ /* VID1 & VID2 => register format, 6-bits, right justified */
+ u8 vid[2];
+
+ /* prochot1 - prochot2: limits */
+ u8 prochot_max[2];
+
+ /* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */
+ u8 vccp_limits[2];
+
+ /* GPIO input state (register format, i.e. inverted) */
+ u8 gpi;
+
+ /* #PROCHOT override (register format) */
+ u8 prochot_override;
+
+ /* #PROCHOT intervals (register format) */
+ u8 prochot_interval;
+
+ /* Fan Boost Temperatures (register format) */
+ u8 boost[4];
+
+ /* Fan Boost Hysteresis (register format) */
+ u8 boost_hyst[2];
+
+ /* Temperature Zone Min. PWM & Hysteresis (register format) */
+ u8 auto_pwm_min_hyst[2];
+
+ /* #PROCHOT & #VRDHOT PWM Ramp Control */
+ u8 pwm_ramp_ctl;
+
+ /* miscellaneous setup regs */
+ u8 sfc1;
+ u8 sfc2;
+ u8 sf_tach_to_pwm;
+
+ /* The two PWM CTL2 registers can read something other than what was
+ last written for the OVR_DC field (duty cycle override). So, we
+ save the user-commanded value here. */
+ u8 pwm_override[2];
+};
+
+/* VID: mV
+ REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */
+static int LM93_VID_FROM_REG(u8 reg)
+{
+ return vid_from_reg((reg & 0x3f), 100);
+}
+
+/* min, max, and nominal register values, per channel (u8) */
+static const u8 lm93_vin_reg_min[16] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae,
+};
+static const u8 lm93_vin_reg_max[16] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const u8 lm93_vin_reg_nom[16] = {
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0,
+};
+*/
+
+/* min, max, and nominal voltage readings, per channel (mV)*/
+static const unsigned long lm93_vin_val_min[16] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3000,
+};
+
+static const unsigned long lm93_vin_val_max[16] = {
+ 1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600,
+ 4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const unsigned long lm93_vin_val_nom[16] = {
+ 927, 927, 927, 1200, 1500, 1500, 1200, 1200,
+ 3300, 5000, 2500, 1969, 984, 984, 309, 3300,
+};
+*/
+
+static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
+{
+ const long uV_max = lm93_vin_val_max[nr] * 1000;
+ const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+ const long slope = (uV_max - uV_min) /
+ (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+ const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+ return (slope * reg + intercept + 500) / 1000;
+}
+
+/* IN: mV, limits determined by channel nr
+ REG: scaling determined by channel nr */
+static u8 LM93_IN_TO_REG(int nr, unsigned val)
+{
+ /* range limit */
+ const long mV = SENSORS_LIMIT(val,
+ lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+
+ /* try not to lose too much precision here */
+ const long uV = mV * 1000;
+ const long uV_max = lm93_vin_val_max[nr] * 1000;
+ const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+ /* convert */
+ const long slope = (uV_max - uV_min) /
+ (lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+ const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+ u8 result = ((uV - intercept + (slope/2)) / slope);
+ result = SENSORS_LIMIT(result,
+ lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+ return result;
+}
+
+/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
+static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
+{
+ const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
+ (((reg >> 0 & 0x0f) + 1) * -25000);
+ const long uV_vid = vid * 1000;
+ return (uV_vid + uV_offset + 5000) / 10000;
+}
+
+#define LM93_IN_MIN_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,0,vid)
+#define LM93_IN_MAX_FROM_REG(reg,vid) LM93_IN_REL_FROM_REG(reg,1,vid)
+
+/* vid in mV , upper == 0 indicates low limit, otherwise upper limit
+ upper also determines which nibble of the register is returned
+ (the other nibble will be 0x0) */
+static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
+{
+ long uV_offset = vid * 1000 - val * 10000;
+ if (upper) {
+ uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000);
+ return (u8)((uV_offset / 12500 - 1) << 4);
+ } else {
+ uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000);
+ return (u8)((uV_offset / -25000 - 1) << 0);
+ }
+}
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+ REG: 1C/bit, two's complement */
+static int LM93_TEMP_FROM_REG(u8 reg)
+{
+ return (s8)reg * 1000;
+}
+
+#define LM93_TEMP_MIN (-128000)
+#define LM93_TEMP_MAX ( 127000)
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+ REG: 1C/bit, two's complement */
+static u8 LM93_TEMP_TO_REG(int temp)
+{
+ int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+ ntemp += (ntemp<0 ? -500 : 500);
+ return (u8)(ntemp / 1000);
+}
+
+/* Determine 4-bit temperature offset resolution */
+static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr)
+{
+ /* mode: 0 => 1C/bit, nonzero => 0.5C/bit */
+ return sfc2 & (nr < 2 ? 0x10 : 0x20);
+}
+
+/* This function is common to all 4-bit temperature offsets
+ reg is 4 bits right justified
+ mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
+{
+ return (reg & 0x0f) * (mode ? 5 : 10);
+}
+
+#define LM93_TEMP_OFFSET_MIN ( 0)
+#define LM93_TEMP_OFFSET_MAX0 (150)
+#define LM93_TEMP_OFFSET_MAX1 ( 75)
+
+/* This function is common to all 4-bit temperature offsets
+ returns 4 bits right justified
+ mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
+{
+ int factor = mode ? 5 : 10;
+
+ off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN,
+ mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
+ return (u8)((off + factor/2) / factor);
+}
+
+/* 0 <= nr <= 3 */
+static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode)
+{
+ /* temp1-temp2 (nr=0,1) use lower nibble */
+ if (nr < 2)
+ return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode);
+
+ /* temp3-temp4 (nr=2,3) use upper nibble */
+ else
+ return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode);
+}
+
+/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero))
+ REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero)
+ 0 <= nr <= 3 */
+static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode)
+{
+ u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode);
+
+ /* temp1-temp2 (nr=0,1) use lower nibble */
+ if (nr < 2)
+ return (old & 0xf0) | (new & 0x0f);
+
+ /* temp3-temp4 (nr=2,3) use upper nibble */
+ else
+ return (new << 4 & 0xf0) | (old & 0x0f);
+}
+
+static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr,
+ int mode)
+{
+ u8 reg;
+
+ switch (nr) {
+ case 0:
+ reg = data->boost_hyst[0] & 0x0f;
+ break;
+ case 1:
+ reg = data->boost_hyst[0] >> 4 & 0x0f;
+ break;
+ case 2:
+ reg = data->boost_hyst[1] & 0x0f;
+ break;
+ case 3:
+ default:
+ reg = data->boost_hyst[1] >> 4 & 0x0f;
+ break;
+ }
+
+ return LM93_TEMP_FROM_REG(data->boost[nr]) -
+ LM93_TEMP_OFFSET_FROM_REG(reg, mode);
+}
+
+static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst,
+ int nr, int mode)
+{
+ u8 reg = LM93_TEMP_OFFSET_TO_REG(
+ (LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode);
+
+ switch (nr) {
+ case 0:
+ reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f);
+ break;
+ case 1:
+ reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f);
+ break;
+ case 2:
+ reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f);
+ break;
+ case 3:
+ default:
+ reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f);
+ break;
+ }
+
+ return reg;
+}
+
+/* PWM: 0-255 per sensors documentation
+ REG: 0-13 as mapped below... right justified */
+typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t;
+static int lm93_pwm_map[2][16] = {
+ {
+ 0x00, /* 0.00% */ 0x40, /* 25.00% */
+ 0x50, /* 31.25% */ 0x60, /* 37.50% */
+ 0x70, /* 43.75% */ 0x80, /* 50.00% */
+ 0x90, /* 56.25% */ 0xa0, /* 62.50% */
+ 0xb0, /* 68.75% */ 0xc0, /* 75.00% */
+ 0xd0, /* 81.25% */ 0xe0, /* 87.50% */
+ 0xf0, /* 93.75% */ 0xff, /* 100.00% */
+ 0xff, 0xff, /* 14, 15 are reserved and should never occur */
+ },
+ {
+ 0x00, /* 0.00% */ 0x40, /* 25.00% */
+ 0x49, /* 28.57% */ 0x52, /* 32.14% */
+ 0x5b, /* 35.71% */ 0x64, /* 39.29% */
+ 0x6d, /* 42.86% */ 0x76, /* 46.43% */
+ 0x80, /* 50.00% */ 0x89, /* 53.57% */
+ 0x92, /* 57.14% */ 0xb6, /* 71.43% */
+ 0xdb, /* 85.71% */ 0xff, /* 100.00% */
+ 0xff, 0xff, /* 14, 15 are reserved and should never occur */
+ },
+};
+
+static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq)
+{
+ return lm93_pwm_map[freq][reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq)
+{
+ int i;
+ for (i = 0; i < 13; i++)
+ if (pwm <= lm93_pwm_map[freq][i])
+ break;
+
+ /* can fall through with i==13 */
+ return (u8)i;
+}
+
+static int LM93_FAN_FROM_REG(u16 regs)
+{
+ const u16 count = le16_to_cpu(regs) >> 2;
+ return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count;
+}
+
+/*
+ * RPM: (82.5 to 1350000)
+ * REG: 14-bits, LE, *left* justified
+ */
+static u16 LM93_FAN_TO_REG(long rpm)
+{
+ u16 count, regs;
+
+ if (rpm == 0) {
+ count = 0x3fff;
+ } else {
+ rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+ count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe);
+ }
+
+ regs = count << 2;
+ return cpu_to_le16(regs);
+}
+
+/* PWM FREQ: HZ
+ REG: 0-7 as mapped below */
+static int lm93_pwm_freq_map[8] = {
+ 22500, 96, 84, 72, 60, 48, 36, 12
+};
+
+static int LM93_PWM_FREQ_FROM_REG(u8 reg)
+{
+ return lm93_pwm_freq_map[reg & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_FREQ_TO_REG(int freq)
+{
+ int i;
+ for (i = 7; i > 0; i--)
+ if (freq <= lm93_pwm_freq_map[i])
+ break;
+
+ /* can fall through with i==0 */
+ return (u8)i;
+}
+
+/* TIME: 1/100 seconds
+ * REG: 0-7 as mapped below */
+static int lm93_spinup_time_map[8] = {
+ 0, 10, 25, 40, 70, 100, 200, 400,
+};
+
+static int LM93_SPINUP_TIME_FROM_REG(u8 reg)
+{
+ return lm93_spinup_time_map[reg >> 5 & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_SPINUP_TIME_TO_REG(int time)
+{
+ int i;
+ for (i = 0; i < 7; i++)
+ if (time <= lm93_spinup_time_map[i])
+ break;
+
+ /* can fall through with i==8 */
+ return (u8)i;
+}
+
+#define LM93_RAMP_MIN 0
+#define LM93_RAMP_MAX 75
+
+static int LM93_RAMP_FROM_REG(u8 reg)
+{
+ return (reg & 0x0f) * 5;
+}
+
+/* RAMP: 1/100 seconds
+ REG: 50mS/bit 4-bits right justified */
+static u8 LM93_RAMP_TO_REG(int ramp)
+{
+ ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+ return (u8)((ramp + 2) / 5);
+}
+
+/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6%
+ * REG: (same) */
+static u8 LM93_PROCHOT_TO_REG(long prochot)
+{
+ prochot = SENSORS_LIMIT(prochot, 0, 255);
+ return (u8)prochot;
+}
+
+/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds)
+ * REG: 0-9 as mapped below */
+static int lm93_interval_map[10] = {
+ 73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200,
+};
+
+static int LM93_INTERVAL_FROM_REG(u8 reg)
+{
+ return lm93_interval_map[reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_INTERVAL_TO_REG(long interval)
+{
+ int i;
+ for (i = 0; i < 9; i++)
+ if (interval <= lm93_interval_map[i])
+ break;
+
+ /* can fall through with i==9 */
+ return (u8)i;
+}
+
+/* GPIO: 0-255, GPIO0 is LSB
+ * REG: inverted */
+static unsigned LM93_GPI_FROM_REG(u8 reg)
+{
+ return ~reg & 0xff;
+}
+
+/* alarm bitmask definitions
+ The LM93 has nearly 64 bits of error status... I've pared that down to
+ what I think is a useful subset in order to fit it into 32 bits.
+
+ Especially note that the #VRD_HOT alarms are missing because we provide
+ that information as values in another sysfs file.
+
+ If libsensors is extended to support 64 bit values, this could be revisited.
+*/
+#define LM93_ALARM_IN1 0x00000001
+#define LM93_ALARM_IN2 0x00000002
+#define LM93_ALARM_IN3 0x00000004
+#define LM93_ALARM_IN4 0x00000008
+#define LM93_ALARM_IN5 0x00000010
+#define LM93_ALARM_IN6 0x00000020
+#define LM93_ALARM_IN7 0x00000040
+#define LM93_ALARM_IN8 0x00000080
+#define LM93_ALARM_IN9 0x00000100
+#define LM93_ALARM_IN10 0x00000200
+#define LM93_ALARM_IN11 0x00000400
+#define LM93_ALARM_IN12 0x00000800
+#define LM93_ALARM_IN13 0x00001000
+#define LM93_ALARM_IN14 0x00002000
+#define LM93_ALARM_IN15 0x00004000
+#define LM93_ALARM_IN16 0x00008000
+#define LM93_ALARM_FAN1 0x00010000
+#define LM93_ALARM_FAN2 0x00020000
+#define LM93_ALARM_FAN3 0x00040000
+#define LM93_ALARM_FAN4 0x00080000
+#define LM93_ALARM_PH1_ERR 0x00100000
+#define LM93_ALARM_PH2_ERR 0x00200000
+#define LM93_ALARM_SCSI1_ERR 0x00400000
+#define LM93_ALARM_SCSI2_ERR 0x00800000
+#define LM93_ALARM_DVDDP1_ERR 0x01000000
+#define LM93_ALARM_DVDDP2_ERR 0x02000000
+#define LM93_ALARM_D1_ERR 0x04000000
+#define LM93_ALARM_D2_ERR 0x08000000
+#define LM93_ALARM_TEMP1 0x10000000
+#define LM93_ALARM_TEMP2 0x20000000
+#define LM93_ALARM_TEMP3 0x40000000
+
+static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1)
+{
+ unsigned result;
+ result = b1.host_status_2 & 0x3f;
+
+ if (vccp_limit_type[0])
+ result |= (b1.host_status_4 & 0x10) << 2;
+ else
+ result |= b1.host_status_2 & 0x40;
+
+ if (vccp_limit_type[1])
+ result |= (b1.host_status_4 & 0x20) << 2;
+ else
+ result |= b1.host_status_2 & 0x80;
+
+ result |= b1.host_status_3 << 8;
+ result |= (b1.fan_status & 0x0f) << 16;
+ result |= (b1.p1_prochot_status & 0x80) << 13;
+ result |= (b1.p2_prochot_status & 0x80) << 14;
+ result |= (b1.host_status_4 & 0xfc) << 20;
+ result |= (b1.host_status_1 & 0x07) << 28;
+ return result;
+}
+
+#define MAX_RETRIES 5
+
+static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
+{
+ int value, i;
+
+ /* retry in case of read errors */
+ for (i=1; i<=MAX_RETRIES; i++) {
+ if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) {
+ return value;
+ } else {
+ dev_warn(&client->dev,"lm93: read byte data failed, "
+ "address 0x%02x.\n", reg);
+ mdelay(i + 3);
+ }
+
+ }
+
+ /* <TODO> what to return in case of error? */
+ dev_err(&client->dev,"lm93: All read byte retries failed!!\n");
+ return 0;
+}
+
+static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
+{
+ int result;
+
+ /* <TODO> how to handle write errors? */
+ result = i2c_smbus_write_byte_data(client, reg, value);
+
+ if (result < 0)
+ dev_warn(&client->dev,"lm93: write byte data failed, "
+ "0x%02x at address 0x%02x.\n", value, reg);
+
+ return result;
+}
+
+static u16 lm93_read_word(struct i2c_client *client, u8 reg)
+{
+ int value, i;
+
+ /* retry in case of read errors */
+ for (i=1; i<=MAX_RETRIES; i++) {
+ if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) {
+ return value;
+ } else {
+ dev_warn(&client->dev,"lm93: read word data failed, "
+ "address 0x%02x.\n", reg);
+ mdelay(i + 3);
+ }
+
+ }
+
+ /* <TODO> what to return in case of error? */
+ dev_err(&client->dev,"lm93: All read word retries failed!!\n");
+ return 0;
+}
+
+static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
+{
+ int result;
+
+ /* <TODO> how to handle write errors? */
+ result = i2c_smbus_write_word_data(client, reg, value);
+
+ if (result < 0)
+ dev_warn(&client->dev,"lm93: write word data failed, "
+ "0x%04x at address 0x%02x.\n", value, reg);
+
+ return result;
+}
+
+static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX];
+
+/*
+ read block data into values, retry if not expected length
+ fbn => index to lm93_block_read_cmds table
+ (Fixed Block Number - section 14.5.2 of LM93 datasheet)
+*/
+static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
+{
+ int i, result=0;
+
+ for (i = 1; i <= MAX_RETRIES; i++) {
+ result = i2c_smbus_read_block_data(client,
+ lm93_block_read_cmds[fbn].cmd, lm93_block_buffer);
+
+ if (result == lm93_block_read_cmds[fbn].len) {
+ break;
+ } else {
+ dev_warn(&client->dev,"lm93: block read data failed, "
+ "command 0x%02x.\n",
+ lm93_block_read_cmds[fbn].cmd);
+ mdelay(i + 3);
+ }
+ }
+
+ if (result == lm93_block_read_cmds[fbn].len) {
+ memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len);
+ } else {
+ /* <TODO> what to do in case of error? */
+ }
+}
+
+static struct lm93_data *lm93_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ const unsigned long interval = HZ + (HZ / 2);
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + interval) ||
+ !data->valid) {
+
+ data->update(data, client);
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/* update routine for data that has no corresponding SMBus block command */
+static void lm93_update_client_common(struct lm93_data *data,
+ struct i2c_client *client)
+{
+ int i;
+ u8 *ptr;
+
+ /* temp1 - temp4: limits */
+ for (i = 0; i < 4; i++) {
+ data->temp_lim[i].min =
+ lm93_read_byte(client, LM93_REG_TEMP_MIN(i));
+ data->temp_lim[i].max =
+ lm93_read_byte(client, LM93_REG_TEMP_MAX(i));
+ }
+
+ /* config register */
+ data->config = lm93_read_byte(client, LM93_REG_CONFIG);
+
+ /* vid1 - vid2: values */
+ for (i = 0; i < 2; i++)
+ data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i));
+
+ /* prochot1 - prochot2: limits */
+ for (i = 0; i < 2; i++)
+ data->prochot_max[i] = lm93_read_byte(client,
+ LM93_REG_PROCHOT_MAX(i));
+
+ /* vccp1 - vccp2: VID relative limits */
+ for (i = 0; i < 2; i++)
+ data->vccp_limits[i] = lm93_read_byte(client,
+ LM93_REG_VCCP_LIMIT_OFF(i));
+
+ /* GPIO input state */
+ data->gpi = lm93_read_byte(client, LM93_REG_GPI);
+
+ /* #PROCHOT override state */
+ data->prochot_override = lm93_read_byte(client,
+ LM93_REG_PROCHOT_OVERRIDE);
+
+ /* #PROCHOT intervals */
+ data->prochot_interval = lm93_read_byte(client,
+ LM93_REG_PROCHOT_INTERVAL);
+
+ /* Fan Boost Termperature registers */
+ for (i = 0; i < 4; i++)
+ data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i));
+
+ /* Fan Boost Temperature Hyst. registers */
+ data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12);
+ data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34);
+
+ /* Temperature Zone Min. PWM & Hysteresis registers */
+ data->auto_pwm_min_hyst[0] =
+ lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12);
+ data->auto_pwm_min_hyst[1] =
+ lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34);
+
+ /* #PROCHOT & #VRDHOT PWM Ramp Control register */
+ data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+
+ /* misc setup registers */
+ data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1);
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sf_tach_to_pwm = lm93_read_byte(client,
+ LM93_REG_SF_TACH_TO_PWM);
+
+ /* write back alarm values to clear */
+ for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++)
+ lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i));
+}
+
+/* update routine which uses SMBus block data commands */
+static void lm93_update_client_full(struct lm93_data *data,
+ struct i2c_client *client)
+{
+ dev_dbg(&client->dev,"starting device update (block data enabled)\n");
+
+ /* in1 - in16: values & limits */
+ lm93_read_block(client, 3, (u8 *)(data->block3));
+ lm93_read_block(client, 7, (u8 *)(data->block7));
+
+ /* temp1 - temp4: values */
+ lm93_read_block(client, 2, (u8 *)(data->block2));
+
+ /* prochot1 - prochot2: values */
+ lm93_read_block(client, 4, (u8 *)(data->block4));
+
+ /* fan1 - fan4: values & limits */
+ lm93_read_block(client, 5, (u8 *)(data->block5));
+ lm93_read_block(client, 8, (u8 *)(data->block8));
+
+ /* pmw control registers */
+ lm93_read_block(client, 9, (u8 *)(data->block9));
+
+ /* alarm values */
+ lm93_read_block(client, 1, (u8 *)(&data->block1));
+
+ /* auto/pwm registers */
+ lm93_read_block(client, 10, (u8 *)(&data->block10));
+
+ lm93_update_client_common(data, client);
+}
+
+/* update routine which uses SMBus byte/word data commands only */
+static void lm93_update_client_min(struct lm93_data *data,
+ struct i2c_client *client)
+{
+ int i,j;
+ u8 *ptr;
+
+ dev_dbg(&client->dev,"starting device update (block data disabled)\n");
+
+ /* in1 - in16: values & limits */
+ for (i = 0; i < 16; i++) {
+ data->block3[i] =
+ lm93_read_byte(client, LM93_REG_IN(i));
+ data->block7[i].min =
+ lm93_read_byte(client, LM93_REG_IN_MIN(i));
+ data->block7[i].max =
+ lm93_read_byte(client, LM93_REG_IN_MAX(i));
+ }
+
+ /* temp1 - temp4: values */
+ for (i = 0; i < 4; i++) {
+ data->block2[i] =
+ lm93_read_byte(client, LM93_REG_TEMP(i));
+ }
+
+ /* prochot1 - prochot2: values */
+ for (i = 0; i < 2; i++) {
+ data->block4[i].cur =
+ lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i));
+ data->block4[i].avg =
+ lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i));
+ }
+
+ /* fan1 - fan4: values & limits */
+ for (i = 0; i < 4; i++) {
+ data->block5[i] =
+ lm93_read_word(client, LM93_REG_FAN(i));
+ data->block8[i] =
+ lm93_read_word(client, LM93_REG_FAN_MIN(i));
+ }
+
+ /* pwm control registers */
+ for (i = 0; i < 2; i++) {
+ for (j = 0; j < 4; j++) {
+ data->block9[i][j] =
+ lm93_read_byte(client, LM93_REG_PWM_CTL(i,j));
+ }
+ }
+
+ /* alarm values */
+ for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) {
+ *(ptr + i) =
+ lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i);
+ }
+
+ /* auto/pwm (base temp) registers */
+ for (i = 0; i < 4; i++) {
+ data->block10.base[i] =
+ lm93_read_byte(client, LM93_REG_TEMP_BASE(i));
+ }
+
+ /* auto/pwm (offset temp) registers */
+ for (i = 0; i < 12; i++) {
+ data->block10.offset[i] =
+ lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i));
+ }
+
+ lm93_update_client_common(data, client);
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf, "%d\n", LM93_IN_FROM_REG(nr, data->block3[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_in, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_in, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_in, NULL, 12);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_in, NULL, 13);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_in, NULL, 14);
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in, NULL, 15);
+
+static ssize_t show_in_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int vccp = nr - 6;
+ long rc, vid;
+
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid);
+ }
+ else {
+ rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); \
+ }
+ return sprintf(buf, "%ld\n", rc); \
+}
+
+static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ int vccp = nr - 6;
+ long vid;
+
+ mutex_lock(&data->update_lock);
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) |
+ LM93_IN_REL_TO_REG(val, 0, vid);
+ lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+ data->vccp_limits[vccp]);
+ }
+ else {
+ data->block7[nr].min = LM93_IN_TO_REG(nr,val);
+ lm93_write_byte(client, LM93_REG_IN_MIN(nr),
+ data->block7[nr].min);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in9_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in10_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 9);
+static SENSOR_DEVICE_ATTR(in11_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 10);
+static SENSOR_DEVICE_ATTR(in12_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 11);
+static SENSOR_DEVICE_ATTR(in13_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 12);
+static SENSOR_DEVICE_ATTR(in14_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 13);
+static SENSOR_DEVICE_ATTR(in15_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 14);
+static SENSOR_DEVICE_ATTR(in16_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 15);
+
+static ssize_t show_in_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int vccp = nr - 6;
+ long rc, vid;
+
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp],vid);
+ }
+ else {
+ rc = LM93_IN_FROM_REG(nr,data->block7[nr].max); \
+ }
+ return sprintf(buf,"%ld\n",rc); \
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ int vccp = nr - 6;
+ long vid;
+
+ mutex_lock(&data->update_lock);
+ if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+ vid = LM93_VID_FROM_REG(data->vid[vccp]);
+ data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) |
+ LM93_IN_REL_TO_REG(val, 1, vid);
+ lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+ data->vccp_limits[vccp]);
+ }
+ else {
+ data->block7[nr].max = LM93_IN_TO_REG(nr,val);
+ lm93_write_byte(client, LM93_REG_IN_MAX(nr),
+ data->block7[nr].max);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in9_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR(in10_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 9);
+static SENSOR_DEVICE_ATTR(in11_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 10);
+static SENSOR_DEVICE_ATTR(in12_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 11);
+static SENSOR_DEVICE_ATTR(in13_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 12);
+static SENSOR_DEVICE_ATTR(in14_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 13);
+static SENSOR_DEVICE_ATTR(in15_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 14);
+static SENSOR_DEVICE_ATTR(in16_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 15);
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block2[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static ssize_t show_temp_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].min));
+}
+
+static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), data->temp_lim[nr].min);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+ show_temp_min, store_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO,
+ show_temp_min, store_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO,
+ show_temp_min, store_temp_min, 2);
+
+static ssize_t show_temp_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].max));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), data->temp_lim[nr].max);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+ show_temp_max, store_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO,
+ show_temp_max, store_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO,
+ show_temp_max, store_temp_max, 2);
+
+static ssize_t show_temp_auto_base(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block10.base[nr]));
+}
+
+static ssize_t store_temp_auto_base(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->block10.base[nr] = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), data->block10.base[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_base, S_IWUSR | S_IRUGO,
+ show_temp_auto_base, store_temp_auto_base, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_base, S_IWUSR | S_IRUGO,
+ show_temp_auto_base, store_temp_auto_base, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_base, S_IWUSR | S_IRUGO,
+ show_temp_auto_base, store_temp_auto_base, 2);
+
+static ssize_t show_temp_auto_boost(struct device *dev,
+ struct device_attribute *attr,char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->boost[nr]));
+}
+
+static ssize_t store_temp_auto_boost(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->boost[nr] = LM93_TEMP_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_BOOST(nr), data->boost[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost, store_temp_auto_boost, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost, store_temp_auto_boost, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost, store_temp_auto_boost, 2);
+
+static ssize_t show_temp_auto_boost_hyst(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+ return sprintf(buf,"%d\n",
+ LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode));
+}
+
+static ssize_t store_temp_auto_boost_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ /* force 0.5C/bit mode */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+ data->boost_hyst[nr/2] = LM93_AUTO_BOOST_HYST_TO_REG(data, val, nr, 1);
+ lm93_write_byte(client, LM93_REG_BOOST_HYST(nr),
+ data->boost_hyst[nr/2]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost_hyst,
+ store_temp_auto_boost_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost_hyst,
+ store_temp_auto_boost_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_boost_hyst,
+ store_temp_auto_boost_hyst, 2);
+
+static ssize_t show_temp_auto_offset(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+ int nr = s_attr->index;
+ int ofs = s_attr->nr;
+ struct lm93_data *data = lm93_update_device(dev);
+ int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+ return sprintf(buf,"%d\n",
+ LM93_TEMP_AUTO_OFFSET_FROM_REG(data->block10.offset[ofs],
+ nr,mode));
+}
+
+static ssize_t store_temp_auto_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+ int nr = s_attr->index;
+ int ofs = s_attr->nr;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ /* force 0.5C/bit mode */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+ data->block10.offset[ofs] = LM93_TEMP_AUTO_OFFSET_TO_REG(
+ data->block10.offset[ofs], val, nr, 1);
+ lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ofs),
+ data->block10.offset[ofs]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset1, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset2, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset3, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset4, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 3, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset5, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset6, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset7, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 6, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset8, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 7, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset9, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 8, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset10, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 9, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset11, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 10, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset12, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 11, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset1, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset2, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset3, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset4, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 3, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset5, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset6, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 5, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset7, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 6, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset8, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 7, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset9, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 8, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset10, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 9, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset11, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 10, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset12, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 11, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset1, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset2, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset3, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset4, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 3, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset5, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 4, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset6, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 5, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset7, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 6, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset8, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 7, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset9, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 8, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset10, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 9, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset11, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 10, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset12, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset, store_temp_auto_offset, 11, 2);
+
+static ssize_t show_temp_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ u8 reg, ctl4;
+ struct lm93_data *data = lm93_update_device(dev);
+ reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f;
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ return sprintf(buf,"%d\n",LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_temp_auto_pwm_min(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 reg, ctl4;
+
+ mutex_lock(&data->update_lock);
+ reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr));
+ ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+ reg = (reg & 0x0f) |
+ LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ :
+ LM93_PWM_MAP_HI_FREQ) << 4;
+ data->auto_pwm_min_hyst[nr/2] = reg;
+ lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_pwm_min, S_IWUSR | S_IRUGO,
+ show_temp_auto_pwm_min,
+ store_temp_auto_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_pwm_min, S_IWUSR | S_IRUGO,
+ show_temp_auto_pwm_min,
+ store_temp_auto_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_pwm_min, S_IWUSR | S_IRUGO,
+ show_temp_auto_pwm_min,
+ store_temp_auto_pwm_min, 2);
+
+static ssize_t show_temp_auto_offset_hyst(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+ return sprintf(buf,"%d\n",LM93_TEMP_OFFSET_FROM_REG(
+ data->auto_pwm_min_hyst[nr/2], mode));
+}
+
+static ssize_t store_temp_auto_offset_hyst(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 reg;
+
+ mutex_lock(&data->update_lock);
+ /* force 0.5C/bit mode */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+ reg = data->auto_pwm_min_hyst[nr/2];
+ reg = (reg & 0xf0) | (LM93_TEMP_OFFSET_TO_REG(val, 1) & 0x0f);
+ data->auto_pwm_min_hyst[nr/2] = reg;
+ lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_offset_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset_hyst,
+ store_temp_auto_offset_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_offset_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset_hyst,
+ store_temp_auto_offset_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_offset_hyst, S_IWUSR | S_IRUGO,
+ show_temp_auto_offset_hyst,
+ store_temp_auto_offset_hyst, 2);
+
+static ssize_t show_fan_input(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
+ int nr = s_attr->index;
+ struct lm93_data *data = lm93_update_device(dev);
+
+ return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block5[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
+
+static ssize_t show_fan_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+
+ return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block8[nr]));
+}
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->block8[nr] = LM93_FAN_TO_REG(val);
+ lm93_write_word(client,LM93_REG_FAN_MIN(nr),data->block8[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 3);
+
+/* some tedious bit-twiddling here to deal with the register format:
+
+ data->sf_tach_to_pwm: (tach to pwm mapping bits)
+
+ bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
+ T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1
+
+ data->sfc2: (enable bits)
+
+ bit | 3 | 2 | 1 | 0
+ T4 T3 T2 T1
+*/
+
+static ssize_t show_fan_smart_tach(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ long rc = 0;
+ int mapping;
+
+ /* extract the relevant mapping */
+ mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03;
+
+ /* if there's a mapping and it's enabled */
+ if (mapping && ((data->sfc2 >> nr) & 0x01))
+ rc = mapping;
+ return sprintf(buf,"%ld\n",rc);
+}
+
+/* helper function - must grab data->update_lock before calling
+ fan is 0-3, indicating fan1-fan4 */
+static void lm93_write_fan_smart_tach(struct i2c_client *client,
+ struct lm93_data *data, int fan, long value)
+{
+ /* insert the new mapping and write it out */
+ data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+ data->sf_tach_to_pwm &= ~(0x3 << fan * 2);
+ data->sf_tach_to_pwm |= value << fan * 2;
+ lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm);
+
+ /* insert the enable bit and write it out */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ if (value)
+ data->sfc2 |= 1 << fan;
+ else
+ data->sfc2 &= ~(1 << fan);
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_fan_smart_tach(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ /* sanity test, ignore the write otherwise */
+ if (0 <= val && val <= 2) {
+ /* can't enable if pwm freq is 22.5KHz */
+ if (val) {
+ u8 ctl4 = lm93_read_byte(client,
+ LM93_REG_PWM_CTL(val-1,LM93_PWM_CTL4));
+ if ((ctl4 & 0x07) == 0)
+ val = 0;
+ }
+ lm93_write_fan_smart_tach(client, data, nr, val);
+ }
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 0);
+static SENSOR_DEVICE_ATTR(fan2_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 1);
+static SENSOR_DEVICE_ATTR(fan3_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 2);
+static SENSOR_DEVICE_ATTR(fan4_smart_tach, S_IWUSR | S_IRUGO,
+ show_fan_smart_tach, store_fan_smart_tach, 3);
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl2, ctl4;
+ long rc;
+
+ ctl2 = data->block9[nr][LM93_PWM_CTL2];
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ if (ctl2 & 0x01) /* show user commanded value if enabled */
+ rc = data->pwm_override[nr];
+ else /* show present h/w value if manual pwm disabled */
+ rc = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ);
+ return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl2, ctl4;
+
+ mutex_lock(&data->update_lock);
+ ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+ ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+ ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val,(ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ) << 4;
+ /* save user commanded value */
+ data->pwm_override[nr] = LM93_PWM_FROM_REG(ctl2 >> 4,
+ (ctl4 & 0x07) ? LM93_PWM_MAP_LO_FREQ :
+ LM93_PWM_MAP_HI_FREQ);
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+
+static ssize_t show_pwm_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl2;
+ long rc;
+
+ ctl2 = data->block9[nr][LM93_PWM_CTL2];
+ if (ctl2 & 0x01) /* manual override enabled ? */
+ rc = ((ctl2 & 0xF0) == 0xF0) ? 0 : 1;
+ else
+ rc = 2;
+ return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl2;
+
+ mutex_lock(&data->update_lock);
+ ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+
+ switch (val) {
+ case 0:
+ ctl2 |= 0xF1; /* enable manual override, set PWM to max */
+ break;
+ case 1: ctl2 |= 0x01; /* enable manual override */
+ break;
+ case 2: ctl2 &= ~0x01; /* disable manual override */
+ break;
+ default:
+ mutex_unlock(&data->update_lock);
+ return -EINVAL;
+ }
+
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+ show_pwm_enable, store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+ show_pwm_enable, store_pwm_enable, 1);
+
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl4;
+
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ return sprintf(buf,"%d\n",LM93_PWM_FREQ_FROM_REG(ctl4));
+}
+
+/* helper function - must grab data->update_lock before calling
+ pwm is 0-1, indicating pwm1-pwm2
+ this disables smart tach for all tach channels bound to the given pwm */
+static void lm93_disable_fan_smart_tach(struct i2c_client *client,
+ struct lm93_data *data, int pwm)
+{
+ int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+ int mask;
+
+ /* collapse the mapping into a mask of enable bits */
+ mapping = (mapping >> pwm) & 0x55;
+ mask = mapping & 0x01;
+ mask |= (mapping & 0x04) >> 1;
+ mask |= (mapping & 0x10) >> 2;
+ mask |= (mapping & 0x40) >> 3;
+
+ /* disable smart tach according to the mask */
+ data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+ data->sfc2 &= ~mask;
+ lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_pwm_freq(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl4;
+
+ mutex_lock(&data->update_lock);
+ ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+ ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(val);
+ data->block9[nr][LM93_PWM_CTL4] = ctl4;
+ /* ctl4 == 0 -> 22.5KHz -> disable smart tach */
+ if (!ctl4)
+ lm93_disable_fan_smart_tach(client, data, nr);
+ lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IWUSR | S_IRUGO,
+ show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IWUSR | S_IRUGO,
+ show_pwm_freq, store_pwm_freq, 1);
+
+static ssize_t show_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->block9[nr][LM93_PWM_CTL1]);
+}
+
+static ssize_t store_pwm_auto_channels(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
+ lm93_write_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL1),
+ data->block9[nr][LM93_PWM_CTL1]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels, S_IWUSR | S_IRUGO,
+ show_pwm_auto_channels, store_pwm_auto_channels, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels, S_IWUSR | S_IRUGO,
+ show_pwm_auto_channels, store_pwm_auto_channels, 1);
+
+static ssize_t show_pwm_auto_spinup_min(struct device *dev,
+ struct device_attribute *attr,char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 ctl3, ctl4;
+
+ ctl3 = data->block9[nr][LM93_PWM_CTL3];
+ ctl4 = data->block9[nr][LM93_PWM_CTL4];
+ return sprintf(buf,"%d\n",
+ LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_pwm_auto_spinup_min(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl3, ctl4;
+
+ mutex_lock(&data->update_lock);
+ ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+ ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+ ctl3 = (ctl3 & 0xf0) | LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+ LM93_PWM_MAP_LO_FREQ :
+ LM93_PWM_MAP_HI_FREQ);
+ data->block9[nr][LM93_PWM_CTL3] = ctl3;
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_min, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_min,
+ store_pwm_auto_spinup_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_min, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_min,
+ store_pwm_auto_spinup_min, 1);
+
+static ssize_t show_pwm_auto_spinup_time(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_SPINUP_TIME_FROM_REG(
+ data->block9[nr][LM93_PWM_CTL3]));
+}
+
+static ssize_t store_pwm_auto_spinup_time(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ctl3;
+
+ mutex_lock(&data->update_lock);
+ ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+ ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG(val) << 5 & 0xe0);
+ data->block9[nr][LM93_PWM_CTL3] = ctl3;
+ lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_time, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_time,
+ store_pwm_auto_spinup_time, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_time, S_IWUSR | S_IRUGO,
+ show_pwm_auto_spinup_time,
+ store_pwm_auto_spinup_time, 1);
+
+static ssize_t show_pwm_auto_prochot_ramp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f));
+}
+
+static ssize_t store_pwm_auto_prochot_ramp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ramp;
+
+ mutex_lock(&data->update_lock);
+ ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+ ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG(val) << 4 & 0xf0);
+ lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(pwm_auto_prochot_ramp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_prochot_ramp,
+ store_pwm_auto_prochot_ramp);
+
+static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f));
+}
+
+static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 ramp;
+
+ mutex_lock(&data->update_lock);
+ ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+ ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG(val) & 0x0f);
+ lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+ mutex_unlock(&data->update_lock);
+ return 0;
+}
+
+static DEVICE_ATTR(pwm_auto_vrdhot_ramp, S_IRUGO | S_IWUSR,
+ show_pwm_auto_vrdhot_ramp,
+ store_pwm_auto_vrdhot_ramp);
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
+
+static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->block4[nr].cur);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1, S_IRUGO, show_prochot, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2, S_IRUGO, show_prochot, NULL, 1);
+
+static ssize_t show_prochot_avg(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->block4[nr].avg);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_avg, S_IRUGO, show_prochot_avg, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2_avg, S_IRUGO, show_prochot_avg, NULL, 1);
+
+static ssize_t show_prochot_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->prochot_max[nr]);
+}
+
+static ssize_t store_prochot_max(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val);
+ lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr),
+ data->prochot_max[nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_max, S_IWUSR | S_IRUGO,
+ show_prochot_max, store_prochot_max, 0);
+static SENSOR_DEVICE_ATTR(prochot2_max, S_IWUSR | S_IRUGO,
+ show_prochot_max, store_prochot_max, 1);
+
+static const u8 prochot_override_mask[] = { 0x80, 0x40 };
+
+static ssize_t show_prochot_override(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ (data->prochot_override & prochot_override_mask[nr]) ? 1 : 0);
+}
+
+static ssize_t store_prochot_override(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->prochot_override |= prochot_override_mask[nr];
+ else
+ data->prochot_override &= (~prochot_override_mask[nr]);
+ lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+ data->prochot_override);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_override, S_IWUSR | S_IRUGO,
+ show_prochot_override, store_prochot_override, 0);
+static SENSOR_DEVICE_ATTR(prochot2_override, S_IWUSR | S_IRUGO,
+ show_prochot_override, store_prochot_override, 1);
+
+static ssize_t show_prochot_interval(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ u8 tmp;
+ if (nr==1)
+ tmp = (data->prochot_interval & 0xf0) >> 4;
+ else
+ tmp = data->prochot_interval & 0x0f;
+ return sprintf(buf,"%d\n",LM93_INTERVAL_FROM_REG(tmp));
+}
+
+static ssize_t store_prochot_interval(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u8 tmp;
+
+ mutex_lock(&data->update_lock);
+ tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL);
+ if (nr==1)
+ tmp = (tmp & 0x0f) | (LM93_INTERVAL_TO_REG(val) << 4);
+ else
+ tmp = (tmp & 0xf0) | LM93_INTERVAL_TO_REG(val);
+ data->prochot_interval = tmp;
+ lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, tmp);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_interval, S_IWUSR | S_IRUGO,
+ show_prochot_interval, store_prochot_interval, 0);
+static SENSOR_DEVICE_ATTR(prochot2_interval, S_IWUSR | S_IRUGO,
+ show_prochot_interval, store_prochot_interval, 1);
+
+static ssize_t show_prochot_override_duty_cycle(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",data->prochot_override & 0x0f);
+}
+
+static ssize_t store_prochot_override_duty_cycle(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->prochot_override = (data->prochot_override & 0xf0) |
+ SENSORS_LIMIT(val, 0, 15);
+ lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+ data->prochot_override);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(prochot_override_duty_cycle, S_IRUGO | S_IWUSR,
+ show_prochot_override_duty_cycle,
+ store_prochot_override_duty_cycle);
+
+static ssize_t show_prochot_short(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",(data->config & 0x10) ? 1 : 0);
+}
+
+static ssize_t store_prochot_short(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct lm93_data *data = i2c_get_clientdata(client);
+ u32 val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ if (val)
+ data->config |= 0x10;
+ else
+ data->config &= ~0x10;
+ lm93_write_byte(client, LM93_REG_CONFIG, data->config);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static DEVICE_ATTR(prochot_short, S_IRUGO | S_IWUSR,
+ show_prochot_short, store_prochot_short);
+
+static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int nr = (to_sensor_dev_attr(attr))->index;
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",
+ data->block1.host_status_1 & (1 << (nr+4)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(vrdhot1, S_IRUGO, show_vrdhot, NULL, 0);
+static SENSOR_DEVICE_ATTR(vrdhot2, S_IRUGO, show_vrdhot, NULL, 1);
+
+static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_GPI_FROM_REG(data->gpi));
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO, show_gpio, NULL);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct lm93_data *data = lm93_update_device(dev);
+ return sprintf(buf,"%d\n",LM93_ALARMS_FROM_REG(data->block1));
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *lm93_attrs[] = {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ &sensor_dev_attr_in12_input.dev_attr.attr,
+ &sensor_dev_attr_in13_input.dev_attr.attr,
+ &sensor_dev_attr_in14_input.dev_attr.attr,
+ &sensor_dev_attr_in15_input.dev_attr.attr,
+ &sensor_dev_attr_in16_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in10_min.dev_attr.attr,
+ &sensor_dev_attr_in11_min.dev_attr.attr,
+ &sensor_dev_attr_in12_min.dev_attr.attr,
+ &sensor_dev_attr_in13_min.dev_attr.attr,
+ &sensor_dev_attr_in14_min.dev_attr.attr,
+ &sensor_dev_attr_in15_min.dev_attr.attr,
+ &sensor_dev_attr_in16_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in9_max.dev_attr.attr,
+ &sensor_dev_attr_in10_max.dev_attr.attr,
+ &sensor_dev_attr_in11_max.dev_attr.attr,
+ &sensor_dev_attr_in12_max.dev_attr.attr,
+ &sensor_dev_attr_in13_max.dev_attr.attr,
+ &sensor_dev_attr_in14_max.dev_attr.attr,
+ &sensor_dev_attr_in15_max.dev_attr.attr,
+ &sensor_dev_attr_in16_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_base.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_base.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_base.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_boost.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_boost.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_boost.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_boost_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_boost_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_boost_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset1.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset2.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset3.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset4.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset5.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset6.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset7.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset8.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset9.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset10.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset11.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset12.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset1.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset2.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset3.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset4.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset5.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset6.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset7.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset8.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset9.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset10.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset11.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset12.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset1.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset2.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset3.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset4.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset5.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset6.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset7.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset8.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset9.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset10.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset11.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset12.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_pwm_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_offset_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_offset_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_offset_hyst.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_fan2_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_fan3_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_fan4_smart_tach.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm2_freq.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_spinup_min.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_spinup_min.dev_attr.attr,
+ &sensor_dev_attr_pwm1_auto_spinup_time.dev_attr.attr,
+ &sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
+ &dev_attr_pwm_auto_prochot_ramp.attr,
+ &dev_attr_pwm_auto_vrdhot_ramp.attr,
+ &sensor_dev_attr_vid1.dev_attr.attr,
+ &sensor_dev_attr_vid2.dev_attr.attr,
+ &sensor_dev_attr_prochot1.dev_attr.attr,
+ &sensor_dev_attr_prochot2.dev_attr.attr,
+ &sensor_dev_attr_prochot1_avg.dev_attr.attr,
+ &sensor_dev_attr_prochot2_avg.dev_attr.attr,
+ &sensor_dev_attr_prochot1_max.dev_attr.attr,
+ &sensor_dev_attr_prochot2_max.dev_attr.attr,
+ &sensor_dev_attr_prochot1_override.dev_attr.attr,
+ &sensor_dev_attr_prochot2_override.dev_attr.attr,
+ &sensor_dev_attr_prochot1_interval.dev_attr.attr,
+ &sensor_dev_attr_prochot2_interval.dev_attr.attr,
+ &dev_attr_prochot_override_duty_cycle.attr,
+ &dev_attr_prochot_short.attr,
+ &sensor_dev_attr_vrdhot1.dev_attr.attr,
+ &sensor_dev_attr_vrdhot2.dev_attr.attr,
+ &dev_attr_gpio.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static struct attribute_group lm93_attr_grp = {
+ .attrs = lm93_attrs,
+};
+
+static void lm93_init_client(struct i2c_client *client)
+{
+ int i;
+ u8 reg;
+
+ /* configure VID pin input thresholds */
+ reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL);
+ lm93_write_byte(client, LM93_REG_GPI_VID_CTL,
+ reg | (vid_agtl ? 0x03 : 0x00));
+
+ if (init) {
+ /* enable #ALERT pin */
+ reg = lm93_read_byte(client, LM93_REG_CONFIG);
+ lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08);
+
+ /* enable ASF mode for BMC status registers */
+ reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL);
+ lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02);
+
+ /* set sleep state to S0 */
+ lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0);
+
+ /* unmask #VRDHOT and dynamic VCCP (if nec) error events */
+ reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK);
+ reg &= ~0x03;
+ reg &= ~(vccp_limit_type[0] ? 0x10 : 0);
+ reg &= ~(vccp_limit_type[1] ? 0x20 : 0);
+ lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg);
+ }
+
+ /* start monitoring */
+ reg = lm93_read_byte(client, LM93_REG_CONFIG);
+ lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01);
+
+ /* spin until ready */
+ for (i=0; i<20; i++) {
+ msleep(10);
+ if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80)
+ return;
+ }
+
+ dev_warn(&client->dev,"timed out waiting for sensor "
+ "chip to signal ready!\n");
+}
+
+static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct lm93_data *data;
+ struct i2c_client *client;
+
+ int err = -ENODEV, func;
+ void (*update)(struct lm93_data *, struct i2c_client *);
+
+ /* choose update routine based on bus capabilities */
+ func = i2c_get_functionality(adapter);
+ if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
+ (!disable_block) ) {
+ dev_dbg(&adapter->dev,"using SMBus block data transactions\n");
+ update = lm93_update_client_full;
+ } else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
+ dev_dbg(&adapter->dev,"disabled SMBus block data "
+ "transactions\n");
+ update = lm93_update_client_min;
+ } else {
+ dev_dbg(&adapter->dev,"detect failed, "
+ "smbus byte and/or word data not supported!\n");
+ goto err_out;
+ }
+
+ /* OK. For now, we presume we have a valid client. We now create the
+ client structure, even though we cannot fill it completely yet.
+ But it allows us to access lm78_{read,write}_value. */
+
+ if ( !(data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL))) {
+ dev_dbg(&adapter->dev,"out of memory!\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &lm93_driver;
+
+ /* detection */
+ if (kind < 0) {
+ int mfr = lm93_read_byte(client, LM93_REG_MFR_ID);
+
+ if (mfr != 0x01) {
+ dev_dbg(&adapter->dev,"detect failed, "
+ "bad manufacturer id 0x%02x!\n", mfr);
+ goto err_free;
+ }
+ }
+
+ if (kind <= 0) {
+ int ver = lm93_read_byte(client, LM93_REG_VER);
+
+ if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) {
+ kind = lm93;
+ } else {
+ dev_dbg(&adapter->dev,"detect failed, "
+ "bad version id 0x%02x!\n", ver);
+ if (kind == 0)
+ dev_dbg(&adapter->dev,
+ "(ignored 'force' parameter)\n");
+ goto err_free;
+ }
+ }
+
+ /* fill in remaining client fields */
+ strlcpy(client->name, "lm93", I2C_NAME_SIZE);
+ dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
+ client->name, i2c_adapter_id(client->adapter),
+ client->addr);
+
+ /* housekeeping */
+ data->valid = 0;
+ data->update = update;
+ mutex_init(&data->update_lock);
+
+ /* tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto err_free;
+
+ /* initialize the chip */
+ lm93_init_client(client);
+
+ err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
+ if (err)
+ goto err_detach;
+
+ /* Register hwmon driver class */
+ data->class_dev = hwmon_device_register(&client->dev);
+ if ( !IS_ERR(data->class_dev))
+ return 0;
+
+ err = PTR_ERR(data->class_dev);
+ dev_err(&client->dev, "error registering hwmon device.\n");
+ sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+err_detach:
+ i2c_detach_client(client);
+err_free:
+ kfree(data);
+err_out:
+ return err;
+}
+
+/* This function is called when:
+ * lm93_driver is inserted (when this module is loaded), for each
+ available adapter
+ * when a new adapter is inserted (and lm93_driver is still present) */
+static int lm93_attach_adapter(struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, lm93_detect);
+}
+
+static int lm93_detach_client(struct i2c_client *client)
+{
+ struct lm93_data *data = i2c_get_clientdata(client);
+ int err = 0;
+
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+
+ err = i2c_detach_client(client);
+ if (!err)
+ kfree(data);
+ return err;
+}
+
+static struct i2c_driver lm93_driver = {
+ .driver = {
+ .name = "lm93",
+ },
+ .attach_adapter = lm93_attach_adapter,
+ .detach_client = lm93_detach_client,
+};
+
+static int __init lm93_init(void)
+{
+ return i2c_add_driver(&lm93_driver);
+}
+
+static void __exit lm93_exit(void)
+{
+ i2c_del_driver(&lm93_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
+ "Hans J. Koch <hjk@linutronix.de");
+MODULE_DESCRIPTION("LM93 driver");
+MODULE_LICENSE("GPL");
+
+module_init(lm93_init);
+module_exit(lm93_exit);
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index c8a21be09d87..cb72526c346a 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1,7 +1,7 @@
/*
* pc87360.c - Part of lm_sensors, Linux kernel modules
* for hardware monitoring
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org>
*
* Copied from smsc47m1.c:
* Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
@@ -37,8 +37,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -47,12 +46,10 @@
#include <asm/io.h>
static u8 devid;
-static unsigned short address;
+static struct platform_device *pdev;
static unsigned short extra_isa[3];
static u8 confreg[4];
-enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-
static int init = 1;
module_param(init, int, 0);
MODULE_PARM_DESC(init,
@@ -178,11 +175,11 @@ static inline u8 PWM_TO_REG(int val, int inv)
((val) + 500) / 1000)
/*
- * Client data (each client gets its own)
+ * Device data
*/
struct pc87360_data {
- struct i2c_client client;
+ const char *name;
struct class_device *class_dev;
struct mutex lock;
struct mutex update_lock;
@@ -222,27 +219,28 @@ struct pc87360_data {
* Functions declaration
*/
-static int pc87360_detect(struct i2c_adapter *adapter);
-static int pc87360_detach_client(struct i2c_client *client);
+static int pc87360_probe(struct platform_device *pdev);
+static int pc87360_remove(struct platform_device *pdev);
static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
u8 reg);
static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
u8 reg, u8 value);
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
+static void pc87360_init_device(struct platform_device *pdev,
+ int use_thermistors);
static struct pc87360_data *pc87360_update_device(struct device *dev);
/*
- * Driver data (common to all clients)
+ * Driver data
*/
-static struct i2c_driver pc87360_driver = {
+static struct platform_driver pc87360_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "pc87360",
},
- .attach_adapter = pc87360_detect,
- .detach_client = pc87360_detach_client,
+ .probe = pc87360_probe,
+ .remove = __devexit_p(pc87360_remove),
};
/*
@@ -281,8 +279,7 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long fan_min = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -347,8 +344,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, con
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -410,8 +406,7 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -425,8 +420,7 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *devattr,
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -511,8 +505,7 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char
}
static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
data->vrm = simple_strtoul(buf, NULL, 10);
return count;
}
@@ -584,8 +577,7 @@ static ssize_t set_therm_min(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -599,8 +591,7 @@ static ssize_t set_therm_max(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -614,8 +605,7 @@ static ssize_t set_therm_crit(struct device *dev, struct device_attribute *devat
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -715,8 +705,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *devattr
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -730,8 +719,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *devattr
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -745,8 +733,7 @@ static ssize_t set_temp_crit(struct device *dev, struct device_attribute *devatt
size_t count)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
@@ -818,6 +805,14 @@ static const struct attribute_group pc8736x_temp_group = {
.attrs = pc8736x_temp_attr_array,
};
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct pc87360_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
/*
* Device detection, registration and update
*/
@@ -912,28 +907,18 @@ static int __init pc87360_find(int sioaddr, u8 *devid, unsigned short *addresses
return 0;
}
-static int pc87360_detect(struct i2c_adapter *adapter)
+static int __devinit pc87360_probe(struct platform_device *pdev)
{
int i;
- struct i2c_client *client;
struct pc87360_data *data;
int err = 0;
const char *name = "pc87360";
int use_thermistors = 0;
- struct device *dev;
+ struct device *dev = &pdev->dev;
if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
return -ENOMEM;
- client = &data->client;
- dev = &client->dev;
- i2c_set_clientdata(client, data);
- client->addr = address;
- mutex_init(&data->lock);
- client->adapter = adapter;
- client->driver = &pc87360_driver;
- client->flags = 0;
-
data->fannr = 2;
data->innr = 0;
data->tempnr = 0;
@@ -960,15 +945,17 @@ static int pc87360_detect(struct i2c_adapter *adapter)
break;
}
- strlcpy(client->name, name, sizeof(client->name));
+ data->name = name;
data->valid = 0;
+ mutex_init(&data->lock);
mutex_init(&data->update_lock);
+ platform_set_drvdata(pdev, data);
for (i = 0; i < 3; i++) {
if (((data->address[i] = extra_isa[i]))
&& !request_region(extra_isa[i], PC87360_EXTENT,
pc87360_driver.driver.name)) {
- dev_err(&client->dev, "Region 0x%x-0x%x already "
+ dev_err(dev, "Region 0x%x-0x%x already "
"in use!\n", extra_isa[i],
extra_isa[i]+PC87360_EXTENT-1);
for (i--; i >= 0; i--)
@@ -982,9 +969,6 @@ static int pc87360_detect(struct i2c_adapter *adapter)
if (data->fannr)
data->fan_conf = confreg[0] | (confreg[1] << 8);
- if ((err = i2c_attach_client(client)))
- goto ERROR2;
-
/* Use the correct reference voltage
Unless both the VLM and the TMS logical devices agree to
use an external Vref, the internal one is used. */
@@ -996,7 +980,7 @@ static int pc87360_detect(struct i2c_adapter *adapter)
PC87365_REG_TEMP_CONFIG);
}
data->in_vref = (i&0x02) ? 3025 : 2966;
- dev_dbg(&client->dev, "Using %s reference voltage\n",
+ dev_dbg(dev, "Using %s reference voltage\n",
(i&0x02) ? "external" : "internal");
data->vid_conf = confreg[3];
@@ -1015,18 +999,18 @@ static int pc87360_detect(struct i2c_adapter *adapter)
if (devid == 0xe9 && data->address[1]) /* PC87366 */
use_thermistors = confreg[2] & 0x40;
- pc87360_init_client(client, use_thermistors);
+ pc87360_init_device(pdev, use_thermistors);
}
/* Register all-or-nothing sysfs groups */
if (data->innr &&
- (err = sysfs_create_group(&client->dev.kobj,
+ (err = sysfs_create_group(&dev->kobj,
&pc8736x_vin_group)))
goto ERROR3;
if (data->innr == 14 &&
- (err = sysfs_create_group(&client->dev.kobj,
+ (err = sysfs_create_group(&dev->kobj,
&pc8736x_therm_group)))
goto ERROR3;
@@ -1067,7 +1051,10 @@ static int pc87360_detect(struct i2c_adapter *adapter)
goto ERROR3;
}
- data->class_dev = hwmon_device_register(&client->dev);
+ if ((err = device_create_file(dev, &dev_attr_name)))
+ goto ERROR3;
+
+ data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto ERROR3;
@@ -1075,14 +1062,12 @@ static int pc87360_detect(struct i2c_adapter *adapter)
return 0;
ERROR3:
+ device_remove_file(dev, &dev_attr_name);
/* can still remove groups whose members were added individually */
- sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
- i2c_detach_client(client);
-ERROR2:
+ sysfs_remove_group(&dev->kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&dev->kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
for (i = 0; i < 3; i++) {
if (data->address[i]) {
release_region(data->address[i], PC87360_EXTENT);
@@ -1093,20 +1078,18 @@ ERROR1:
return err;
}
-static int pc87360_detach_client(struct i2c_client *client)
+static int __devexit pc87360_remove(struct platform_device *pdev)
{
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = platform_get_drvdata(pdev);
int i;
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
- sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
- if ((i = i2c_detach_client(client)))
- return i;
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group);
for (i = 0; i < 3; i++) {
if (data->address[i]) {
@@ -1144,9 +1127,10 @@ static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
mutex_unlock(&(data->lock));
}
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
+static void pc87360_init_device(struct platform_device *pdev,
+ int use_thermistors)
{
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = platform_get_drvdata(pdev);
int i, nr;
const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
const u8 init_temp[3] = { 2, 2, 1 };
@@ -1155,7 +1139,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
if (init >= 2 && data->innr) {
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE);
- dev_info(&client->dev, "VLM conversion set to "
+ dev_info(&pdev->dev, "VLM conversion set to "
"1s period, 160us delay\n");
pc87360_write_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONVRATE,
@@ -1169,7 +1153,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_IN_STATUS);
if (!(reg & 0x01)) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling in%d\n", i);
pc87360_write_value(data, LD_IN, i,
PC87365_REG_IN_STATUS,
@@ -1193,7 +1177,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP, i,
PC87365_REG_TEMP_STATUS);
if (!(reg & 0x01)) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i+1);
pc87360_write_value(data, LD_TEMP, i,
PC87365_REG_TEMP_STATUS,
@@ -1210,7 +1194,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP,
(i-11)/2, PC87365_REG_TEMP_STATUS);
if (reg & 0x01) {
- dev_dbg(&client->dev, "Skipping "
+ dev_dbg(&pdev->dev, "Skipping "
"temp%d, pin already in use "
"by temp%d\n", i-7, (i-11)/2);
continue;
@@ -1220,7 +1204,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, i,
PC87365_REG_IN_STATUS);
if (!(reg & 0x01)) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling temp%d\n", i-7);
pc87360_write_value(data, LD_IN, i,
PC87365_REG_TEMP_STATUS,
@@ -1234,7 +1218,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONFIG);
if (reg & 0x01) {
- dev_dbg(&client->dev, "Forcibly "
+ dev_dbg(&pdev->dev, "Forcibly "
"enabling monitoring (VLM)\n");
pc87360_write_value(data, LD_IN, NO_BANK,
PC87365_REG_IN_CONFIG,
@@ -1246,7 +1230,7 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
PC87365_REG_TEMP_CONFIG);
if (reg & 0x01) {
- dev_dbg(&client->dev, "Forcibly enabling "
+ dev_dbg(&pdev->dev, "Forcibly enabling "
"monitoring (TMS)\n");
pc87360_write_value(data, LD_TEMP, NO_BANK,
PC87365_REG_TEMP_CONFIG,
@@ -1268,9 +1252,9 @@ static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
}
}
-static void pc87360_autodiv(struct i2c_client *client, int nr)
+static void pc87360_autodiv(struct device *dev, int nr)
{
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
u8 old_min = data->fan_min[nr];
/* Increase clock divider if needed and possible */
@@ -1280,7 +1264,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
data->fan_status[nr] += 0x20;
data->fan_min[nr] >>= 1;
data->fan[nr] >>= 1;
- dev_dbg(&client->dev, "Increasing "
+ dev_dbg(dev, "Increasing "
"clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1);
}
@@ -1292,7 +1276,7 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
data->fan_status[nr] -= 0x20;
data->fan_min[nr] <<= 1;
data->fan[nr] <<= 1;
- dev_dbg(&client->dev, "Decreasing "
+ dev_dbg(dev, "Decreasing "
"clock divider to %d for fan %d\n",
FAN_DIV_FROM_REG(data->fan_status[nr]),
nr+1);
@@ -1309,14 +1293,13 @@ static void pc87360_autodiv(struct i2c_client *client, int nr)
static struct pc87360_data *pc87360_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
+ struct pc87360_data *data = dev_get_drvdata(dev);
u8 i;
mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
- dev_dbg(&client->dev, "Data update\n");
+ dev_dbg(dev, "Data update\n");
/* Fans */
for (i = 0; i < data->fannr; i++) {
@@ -1330,7 +1313,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
LD_FAN, NO_BANK,
PC87360_REG_FAN_MIN(i));
/* Change clock divider if needed */
- pc87360_autodiv(client, i);
+ pc87360_autodiv(dev, i);
/* Clear bits and write new divider */
pc87360_write_value(data, LD_FAN, NO_BANK,
PC87360_REG_FAN_STATUS(i),
@@ -1418,9 +1401,53 @@ static struct pc87360_data *pc87360_update_device(struct device *dev)
return data;
}
+static int __init pc87360_device_add(unsigned short address)
+{
+ struct resource res = {
+ .name = "pc87360",
+ .flags = IORESOURCE_IO,
+ };
+ int err, i;
+
+ pdev = platform_device_alloc("pc87360", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "pc87360: Device allocation failed\n");
+ goto exit;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (!extra_isa[i])
+ continue;
+ res.start = extra_isa[i];
+ res.end = extra_isa[i] + PC87360_EXTENT - 1;
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "pc87360: Device resource[%d] "
+ "addition failed (%d)\n", i, err);
+ goto exit_device_put;
+ }
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "pc87360: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __init pc87360_init(void)
{
- int i;
+ int err, i;
+ unsigned short address = 0;
if (pc87360_find(0x2e, &devid, extra_isa)
&& pc87360_find(0x4e, &devid, extra_isa)) {
@@ -1443,12 +1470,27 @@ static int __init pc87360_init(void)
return -ENODEV;
}
- return i2c_isa_add_driver(&pc87360_driver);
+ err = platform_driver_register(&pc87360_driver);
+ if (err)
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ err = pc87360_device_add(address);
+ if (err)
+ goto exit_driver;
+
+ return 0;
+
+ exit_driver:
+ platform_driver_unregister(&pc87360_driver);
+ exit:
+ return err;
}
static void __exit pc87360_exit(void)
{
- i2c_isa_del_driver(&pc87360_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&pc87360_driver);
}
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 29354fa26f81..2915bc4ad0d5 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -484,7 +484,6 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
struct resource *res;
int i;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
device_remove_file(&pdev->dev, &dev_attr_name);
for (i = 0; i < 8; i++) {
@@ -492,6 +491,7 @@ static int __devexit pc87427_remove(struct platform_device *pdev)
continue;
sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
}
+ platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 3f400263fc0f..83321b28cf0e 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -54,9 +54,9 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/jiffies.h>
@@ -72,17 +72,13 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Device address
- Note that we can't determine the ISA address until we have initialized
- our module */
-static unsigned short address;
+static struct platform_device *pdev;
/* Many SIS5595 constants specified below */
/* Length of ISA address segment */
#define SIS5595_EXTENT 8
/* PCI Config Registers */
-#define SIS5595_REVISION_REG 0x08
#define SIS5595_BASE_REG 0x68
#define SIS5595_PIN_REG 0x7A
#define SIS5595_ENABLE_REG 0x7B
@@ -165,7 +161,8 @@ static inline u8 DIV_TO_REG(int val)
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct sis5595_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
struct class_device *class_dev;
struct mutex lock;
@@ -189,102 +186,88 @@ struct sis5595_data {
static struct pci_dev *s_bridge; /* pointer to the (only) sis5595 */
-static int sis5595_detect(struct i2c_adapter *adapter);
-static int sis5595_detach_client(struct i2c_client *client);
+static int sis5595_probe(struct platform_device *pdev);
+static int sis5595_remove(struct platform_device *pdev);
-static int sis5595_read_value(struct i2c_client *client, u8 reg);
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int sis5595_read_value(struct sis5595_data *data, u8 reg);
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
static struct sis5595_data *sis5595_update_device(struct device *dev);
-static void sis5595_init_client(struct i2c_client *client);
+static void sis5595_init_device(struct sis5595_data *data);
-static struct i2c_driver sis5595_driver = {
+static struct platform_driver sis5595_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "sis5595",
},
- .attach_adapter = sis5595_detect,
- .detach_client = sis5595_detach_client,
+ .probe = sis5595_probe,
+ .remove = __devexit_p(sis5595_remove),
};
/* 4 Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
+ sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
+ sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_in_offset(offset) \
-static ssize_t \
- show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, \
- show_in##offset, NULL); \
-static ssize_t \
- show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset);
show_in_offset(0);
show_in_offset(1);
@@ -307,13 +290,12 @@ static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_over = TEMP_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
+ sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
mutex_unlock(&data->update_lock);
return count;
}
@@ -326,13 +308,12 @@ static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
long val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_hyst = TEMP_TO_REG(val);
- sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
+ sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
mutex_unlock(&data->update_lock);
return count;
}
@@ -344,37 +325,47 @@ static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
show_temp_hyst, set_temp_hyst);
/* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+ sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+ char *buf)
{
struct sis5595_data *data = sis5595_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
}
@@ -382,11 +373,12 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
determined in part by the fan divisor. This follows the principle of
least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long min;
unsigned long val = simple_strtoul(buf, NULL, 10);
int reg;
@@ -394,7 +386,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
mutex_lock(&data->update_lock);
min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
- reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
+ reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
switch (val) {
case 1: data->fan_div[nr] = 0; break;
@@ -402,7 +394,7 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
- dev_err(&client->dev, "fan_div value %ld not "
+ dev_err(dev, "fan_div value %ld not "
"supported. Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
@@ -416,55 +408,25 @@ static ssize_t set_fan_div(struct device *dev, const char *buf,
reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
break;
}
- sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
+ sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
data->fan_min[nr] =
FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+ sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, set_fan_div, offset - 1);
show_fan_offset(1);
show_fan_offset(2);
-static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
-{
- return set_fan_div(dev, buf, count, 0) ;
-}
-
-static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
- size_t count)
-{
- return set_fan_div(dev, buf, count, 1) ;
-}
-static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
- show_fan_1_div, set_fan_1_div);
-static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
- show_fan_2_div, set_fan_2_div);
-
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -473,28 +435,37 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sis5595_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *sis5595_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in3_max.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan2_div.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -503,9 +474,9 @@ static const struct attribute_group sis5595_group = {
};
static struct attribute *sis5595_attributes_opt[] = {
- &dev_attr_in4_input.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in4_max.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
&dev_attr_temp1_input.attr,
&dev_attr_temp1_max.attr,
@@ -518,68 +489,35 @@ static const struct attribute_group sis5595_group_opt = {
};
/* This is called when the module is loaded */
-static int sis5595_detect(struct i2c_adapter *adapter)
+static int __devinit sis5595_probe(struct platform_device *pdev)
{
int err = 0;
int i;
- struct i2c_client *new_client;
struct sis5595_data *data;
+ struct resource *res;
char val;
- u16 a;
- if (force_addr)
- address = force_addr & ~(SIS5595_EXTENT - 1);
/* Reserve the ISA region */
- if (!request_region(address, SIS5595_EXTENT,
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, SIS5595_EXTENT,
sis5595_driver.driver.name)) {
err = -EBUSY;
goto exit;
}
- if (force_addr) {
- dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
- goto exit_release;
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
- goto exit_release;
- if ((a & ~(SIS5595_EXTENT - 1)) != address)
- /* doesn't work for some chips? */
- goto exit_release;
- }
-
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
- goto exit_release;
- }
- if ((val & 0x80) == 0) {
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
- val | 0x80))
- goto exit_release;
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
- goto exit_release;
- if ((val & 0x80) == 0)
- /* doesn't work for some chips! */
- goto exit_release;
- }
if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit_release;
}
- new_client = &data->client;
- new_client->addr = address;
mutex_init(&data->lock);
- i2c_set_clientdata(new_client, data);
- new_client->adapter = adapter;
- new_client->driver = &sis5595_driver;
- new_client->flags = 0;
+ mutex_init(&data->update_lock);
+ data->addr = res->start;
+ data->name = "sis5595";
+ platform_set_drvdata(pdev, data);
/* Check revision and pin registers to determine whether 4 or 5 voltages */
- pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
+ pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
/* 4 voltages, 1 temp */
data->maxins = 3;
if (data->revision >= REV2MIN) {
@@ -589,47 +527,37 @@ static int sis5595_detect(struct i2c_adapter *adapter)
data->maxins = 4;
}
- /* Fill in the remaining client fields and put it into the global list */
- strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
-
- data->valid = 0;
- mutex_init(&data->update_lock);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
-
/* Initialize the SIS5595 chip */
- sis5595_init_client(new_client);
+ sis5595_init_device(data);
/* A few vars need to be filled upon startup */
for (i = 0; i < 2; i++) {
- data->fan_min[i] = sis5595_read_value(new_client,
+ data->fan_min[i] = sis5595_read_value(data,
SIS5595_REG_FAN_MIN(i));
}
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
- goto exit_detach;
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
+ goto exit_free;
if (data->maxins == 4) {
- if ((err = device_create_file(&new_client->dev,
- &dev_attr_in4_input))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_min))
- || (err = device_create_file(&new_client->dev,
- &dev_attr_in4_max)))
+ if ((err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_in4_input.dev_attr))
+ || (err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_in4_min.dev_attr))
+ || (err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_in4_max.dev_attr)))
goto exit_remove_files;
} else {
- if ((err = device_create_file(&new_client->dev,
+ if ((err = device_create_file(&pdev->dev,
&dev_attr_temp1_input))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(&pdev->dev,
&dev_attr_temp1_max))
- || (err = device_create_file(&new_client->dev,
+ || (err = device_create_file(&pdev->dev,
&dev_attr_temp1_max_hyst)))
goto exit_remove_files;
}
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -638,32 +566,26 @@ static int sis5595_detect(struct i2c_adapter *adapter)
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
- sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
-exit_detach:
- i2c_detach_client(new_client);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
exit_free:
kfree(data);
exit_release:
- release_region(address, SIS5595_EXTENT);
+ release_region(res->start, SIS5595_EXTENT);
exit:
return err;
}
-static int sis5595_detach_client(struct i2c_client *client)
+static int __devexit sis5595_remove(struct platform_device *pdev)
{
- struct sis5595_data *data = i2c_get_clientdata(client);
- int err;
+ struct sis5595_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &sis5595_group);
- sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
-
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr, SIS5595_EXTENT);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
+ release_region(data->addr, SIS5595_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -671,41 +593,37 @@ static int sis5595_detach_client(struct i2c_client *client)
/* ISA access must be locked explicitly. */
-static int sis5595_read_value(struct i2c_client *client, u8 reg)
+static int sis5595_read_value(struct sis5595_data *data, u8 reg)
{
int res;
- struct sis5595_data *data = i2c_get_clientdata(client);
mutex_lock(&data->lock);
- outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
- res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+ res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
mutex_unlock(&data->lock);
return res;
}
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
{
- struct sis5595_data *data = i2c_get_clientdata(client);
mutex_lock(&data->lock);
- outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
- outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
+ outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+ outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
mutex_unlock(&data->lock);
- return 0;
}
/* Called when we have found a new SIS5595. */
-static void sis5595_init_client(struct i2c_client *client)
+static void __devinit sis5595_init_device(struct sis5595_data *data)
{
- u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
+ u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
if (!(config & 0x01))
- sis5595_write_value(client, SIS5595_REG_CONFIG,
+ sis5595_write_value(data, SIS5595_REG_CONFIG,
(config & 0xf7) | 0x01);
}
static struct sis5595_data *sis5595_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct sis5595_data *data = i2c_get_clientdata(client);
+ struct sis5595_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -715,35 +633,35 @@ static struct sis5595_data *sis5595_update_device(struct device *dev)
for (i = 0; i <= data->maxins; i++) {
data->in[i] =
- sis5595_read_value(client, SIS5595_REG_IN(i));
+ sis5595_read_value(data, SIS5595_REG_IN(i));
data->in_min[i] =
- sis5595_read_value(client,
+ sis5595_read_value(data,
SIS5595_REG_IN_MIN(i));
data->in_max[i] =
- sis5595_read_value(client,
+ sis5595_read_value(data,
SIS5595_REG_IN_MAX(i));
}
for (i = 0; i < 2; i++) {
data->fan[i] =
- sis5595_read_value(client, SIS5595_REG_FAN(i));
+ sis5595_read_value(data, SIS5595_REG_FAN(i));
data->fan_min[i] =
- sis5595_read_value(client,
+ sis5595_read_value(data,
SIS5595_REG_FAN_MIN(i));
}
if (data->maxins == 3) {
data->temp =
- sis5595_read_value(client, SIS5595_REG_TEMP);
+ sis5595_read_value(data, SIS5595_REG_TEMP);
data->temp_over =
- sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
+ sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
data->temp_hyst =
- sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
+ sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
}
- i = sis5595_read_value(client, SIS5595_REG_FANDIV);
+ i = sis5595_read_value(data, SIS5595_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
data->alarms =
- sis5595_read_value(client, SIS5595_REG_ALARM1) |
- (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
+ sis5595_read_value(data, SIS5595_REG_ALARM1) |
+ (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
}
@@ -774,10 +692,50 @@ static int blacklist[] __devinitdata = {
PCI_DEVICE_ID_SI_5598,
0 };
+static int __devinit sis5595_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + SIS5595_EXTENT - 1,
+ .name = "sis5595",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("sis5595", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "sis5595: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "sis5595: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "sis5595: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __devinit sis5595_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- u16 val;
+ u16 address;
+ u8 enable;
int *i;
for (i = blacklist; *i != 0; i++) {
@@ -790,27 +748,68 @@ static int __devinit sis5595_pci_probe(struct pci_dev *dev,
}
}
+ force_addr &= ~(SIS5595_EXTENT - 1);
+ if (force_addr) {
+ dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
+ pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
+ }
+
if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(dev, SIS5595_BASE_REG, &val))
+ pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
+ dev_err(&dev->dev, "Failed to read ISA address\n");
return -ENODEV;
+ }
- address = val & ~(SIS5595_EXTENT - 1);
- if (address == 0 && force_addr == 0) {
+ address &= ~(SIS5595_EXTENT - 1);
+ if (!address) {
dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
+ if (force_addr && address != force_addr) {
+ /* doesn't work for some chips? */
+ dev_err(&dev->dev, "Failed to force ISA address\n");
+ return -ENODEV;
+ }
- s_bridge = pci_dev_get(dev);
- if (i2c_isa_add_driver(&sis5595_driver)) {
- pci_dev_put(s_bridge);
- s_bridge = NULL;
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
+ dev_err(&dev->dev, "Failed to read enable register\n");
+ return -ENODEV;
+ }
+ if (!(enable & 0x80)) {
+ if ((PCIBIOS_SUCCESSFUL !=
+ pci_write_config_byte(dev, SIS5595_ENABLE_REG,
+ enable | 0x80))
+ || (PCIBIOS_SUCCESSFUL !=
+ pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
+ || (!(enable & 0x80))) {
+ /* doesn't work for some chips! */
+ dev_err(&dev->dev, "Failed to enable HWM device\n");
+ return -ENODEV;
+ }
}
+ if (platform_driver_register(&sis5595_driver)) {
+ dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
+ goto exit;
+ }
+
+ s_bridge = pci_dev_get(dev);
+ /* Sets global pdev as a side effect */
+ if (sis5595_device_add(address))
+ goto exit_unregister;
+
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
return -ENODEV;
+
+exit_unregister:
+ pci_dev_put(dev);
+ platform_driver_unregister(&sis5595_driver);
+exit:
+ return -ENODEV;
}
static struct pci_driver sis5595_pci_driver = {
@@ -828,7 +827,8 @@ static void __exit sm_sis5595_exit(void)
{
pci_unregister_driver(&sis5595_pci_driver);
if (s_bridge != NULL) {
- i2c_isa_del_driver(&sis5595_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&sis5595_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 943abbd95ab5..45266b30ce1d 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -174,6 +174,8 @@ static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);
REG: count of 90kHz pulses / revolution */
static int fan_from_reg(u16 reg)
{
+ if (reg == 0 || reg == 0xffff)
+ return 0;
return 90000 * 60 / reg;
}
@@ -333,7 +335,7 @@ static int __init smsc47b397_find(unsigned short *addr)
superio_enter();
id = superio_inb(SUPERIO_REG_DEVID);
- if ((id != 0x6f) && (id != 0x81)) {
+ if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
superio_exit();
return -ENODEV;
}
@@ -346,7 +348,8 @@ static int __init smsc47b397_find(unsigned short *addr)
printk(KERN_INFO DRVNAME ": found SMSC %s "
"(base address 0x%04x, revision %u)\n",
- id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
+ id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
+ "LPC47B397-NC", *addr, rev);
superio_exit();
return 0;
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 1e21c8cc948f..1de2f2be8708 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -597,6 +597,7 @@ static int __devinit smsc47m1_probe(struct platform_device *pdev)
error_remove_files:
sysfs_remove_group(&dev->kobj, &smsc47m1_group);
error_free:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
error_release:
release_region(res->start, SMSC_EXTENT);
@@ -608,12 +609,12 @@ static int __devexit smsc47m1_remove(struct platform_device *pdev)
struct smsc47m1_data *data = platform_get_drvdata(pdev);
struct resource *res;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
release_region(res->start, SMSC_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
@@ -693,15 +694,12 @@ static int __init smsc47m1_device_add(unsigned short address,
goto exit_device_put;
}
- pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
- GFP_KERNEL);
- if (!pdev->dev.platform_data) {
- err = -ENOMEM;
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct smsc47m1_sio_data));
+ if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
- memcpy(pdev->dev.platform_data, sio_data,
- sizeof(struct smsc47m1_sio_data));
err = platform_device_add(pdev);
if (err) {
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index a012f396f354..d3a3ba04cb0f 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -31,6 +31,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/sysfs.h>
+#include <linux/mutex.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -97,7 +98,7 @@ static inline int TEMP_FROM_REG(s8 val)
struct smsc47m192_data {
struct i2c_client client;
struct class_device *class_dev;
- struct semaphore update_lock;
+ struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
@@ -164,11 +165,11 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val, nr);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
data->in_min[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -181,11 +182,11 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
unsigned long val = simple_strtoul(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val, nr);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
data->in_max[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -243,11 +244,11 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->temp_min[nr] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
data->temp_min[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -260,11 +261,11 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
struct smsc47m192_data *data = i2c_get_clientdata(client);
long val = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->temp_max[nr] = TEMP_TO_REG(val);
i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
data->temp_max[nr]);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -287,7 +288,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
long val = simple_strtol(buf, NULL, 10);
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
data->temp_offset[nr] = TEMP_TO_REG(val);
if (nr>1)
i2c_smbus_write_byte_data(client,
@@ -303,7 +304,7 @@ static ssize_t set_temp_offset(struct device *dev, struct device_attribute
} else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
i2c_smbus_write_byte_data(client,
SMSC47M192_REG_TEMP_OFFSET(nr), 0);
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return count;
}
@@ -360,8 +361,8 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 0x4000);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 0x8000);
static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
@@ -411,13 +412,13 @@ static struct attribute *smsc47m192_attributes[] = {
&sensor_dev_attr_temp2_min.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp2_alarm.dev_attr.attr,
- &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
&sensor_dev_attr_temp3_min.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
&sensor_dev_attr_temp3_alarm.dev_attr.attr,
- &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
&dev_attr_cpu0_vid.attr,
&dev_attr_vrm.attr,
@@ -531,7 +532,7 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
/* Fill in the remaining client fields and put into the global list */
strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
data->vrm = vid_which_vrm();
- init_MUTEX(&data->update_lock);
+ mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
if ((err = i2c_attach_client(client)))
@@ -594,7 +595,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
struct smsc47m192_data *data = i2c_get_clientdata(client);
int i, config;
- down(&data->update_lock);
+ mutex_lock(&data->update_lock);
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|| !data->valid) {
@@ -645,7 +646,7 @@ static struct smsc47m192_data *smsc47m192_update_device(struct device *dev)
data->valid = 1;
}
- up(&data->update_lock);
+ mutex_unlock(&data->update_lock);
return data;
}
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 9a440c8cc520..24a6851491d0 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -34,9 +34,9 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
@@ -51,10 +51,7 @@ module_param(force_addr, ushort, 0);
MODULE_PARM_DESC(force_addr,
"Initialize the base address of the sensors");
-/* Device address
- Note that we can't determine the ISA address until we have initialized
- our module */
-static unsigned short address;
+static struct platform_device *pdev;
/*
The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@@ -295,7 +292,8 @@ static inline long TEMP_FROM_REG10(u16 val)
/* For each registered chip, we need to keep some data in memory.
The structure is dynamically allocated. */
struct via686a_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
struct class_device *class_dev;
struct mutex update_lock;
char valid; /* !=0 if following fields are valid */
@@ -315,98 +313,85 @@ struct via686a_data {
static struct pci_dev *s_bridge; /* pointer to the (only) via686a */
-static int via686a_detect(struct i2c_adapter *adapter);
-static int via686a_detach_client(struct i2c_client *client);
+static int via686a_probe(struct platform_device *pdev);
+static int via686a_remove(struct platform_device *pdev);
-static inline int via686a_read_value(struct i2c_client *client, u8 reg)
+static inline int via686a_read_value(struct via686a_data *data, u8 reg)
{
- return (inb_p(client->addr + reg));
+ return inb_p(data->addr + reg);
}
-static inline void via686a_write_value(struct i2c_client *client, u8 reg,
+static inline void via686a_write_value(struct via686a_data *data, u8 reg,
u8 value)
{
- outb_p(value, client->addr + reg);
+ outb_p(value, data->addr + reg);
}
static struct via686a_data *via686a_update_device(struct device *dev);
-static void via686a_init_client(struct i2c_client *client);
+static void via686a_init_device(struct via686a_data *data);
/* following are the sysfs callback functions */
/* 7 voltage sensors */
-static ssize_t show_in(struct device *dev, char *buf, int nr) {
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
}
-static ssize_t show_in_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
}
-static ssize_t show_in_max(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
}
-static ssize_t set_in_min(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = IN_TO_REG(val, nr);
- via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
+ via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_in_max(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = IN_TO_REG(val, nr);
- via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
+ via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_in_offset(offset) \
-static ssize_t \
- show_in##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_min(dev, buf, offset); \
-} \
-static ssize_t \
- show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_in_max(dev, buf, offset); \
-} \
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_min(dev, buf, count, offset); \
-} \
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_in_max(dev, buf, count, offset); \
-} \
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
- show_in##offset##_min, set_in##offset##_min); \
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
- show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \
+ show_in, NULL, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \
+ show_in_min, set_in_min, offset); \
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \
+ show_in_max, set_in_max, offset);
show_in_offset(0);
show_in_offset(1);
@@ -415,150 +400,128 @@ show_in_offset(3);
show_in_offset(4);
/* 3 temperatures */
-static ssize_t show_temp(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
}
-static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
}
-static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
}
-static ssize_t set_temp_over(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_over[nr] = TEMP_TO_REG(val);
- via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
+ via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
data->temp_over[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_temp_hyst(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_hyst[nr] = TEMP_TO_REG(val);
- via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
+ via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
data->temp_hyst[nr]);
mutex_unlock(&data->update_lock);
return count;
}
#define show_temp_offset(offset) \
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp(dev, buf, offset - 1); \
-} \
-static ssize_t \
-show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_over(dev, buf, offset - 1); \
-} \
-static ssize_t \
-show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_temp_hyst(dev, buf, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_over(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_temp_hyst(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_over, set_temp_##offset##_over); \
-static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
- show_temp_##offset##_hyst, set_temp_##offset##_hyst);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \
+ show_temp, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \
+ show_temp_over, set_temp_over, offset - 1); \
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp_hyst, set_temp_hyst, offset - 1);
show_temp_offset(1);
show_temp_offset(2);
show_temp_offset(3);
/* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n",
FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
}
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+ char *buf) {
struct via686a_data *data = via686a_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
}
-static ssize_t set_fan_min(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+ via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
-static ssize_t set_fan_div(struct device *dev, const char *buf,
- size_t count, int nr) {
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+ const char *buf, size_t count) {
+ struct via686a_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ int nr = attr->index;
int val = simple_strtol(buf, NULL, 10);
int old;
mutex_lock(&data->update_lock);
- old = via686a_read_value(client, VIA686A_REG_FANDIV);
+ old = via686a_read_value(data, VIA686A_REG_FANDIV);
data->fan_div[nr] = DIV_TO_REG(val);
old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
- via686a_write_value(client, VIA686A_REG_FANDIV, old);
+ via686a_write_value(data, VIA686A_REG_FANDIV, old);
mutex_unlock(&data->update_lock);
return count;
}
#define show_fan_offset(offset) \
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_min(dev, buf, offset - 1); \
-} \
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- return show_fan_div(dev, buf, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_min(dev, buf, count, offset - 1); \
-} \
-static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- return set_fan_div(dev, buf, count, offset - 1); \
-} \
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_min, set_fan_##offset##_min); \
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
- show_fan_##offset##_div, set_fan_##offset##_div);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan, NULL, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan_min, set_fan_min, offset - 1); \
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \
+ show_fan_div, set_fan_div, offset - 1);
show_fan_offset(1);
show_fan_offset(2);
@@ -570,41 +533,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct via686a_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *via686a_attributes[] = {
- &dev_attr_in0_input.attr,
- &dev_attr_in1_input.attr,
- &dev_attr_in2_input.attr,
- &dev_attr_in3_input.attr,
- &dev_attr_in4_input.attr,
- &dev_attr_in0_min.attr,
- &dev_attr_in1_min.attr,
- &dev_attr_in2_min.attr,
- &dev_attr_in3_min.attr,
- &dev_attr_in4_min.attr,
- &dev_attr_in0_max.attr,
- &dev_attr_in1_max.attr,
- &dev_attr_in2_max.attr,
- &dev_attr_in3_max.attr,
- &dev_attr_in4_max.attr,
-
- &dev_attr_temp1_input.attr,
- &dev_attr_temp2_input.attr,
- &dev_attr_temp3_input.attr,
- &dev_attr_temp1_max.attr,
- &dev_attr_temp2_max.attr,
- &dev_attr_temp3_max.attr,
- &dev_attr_temp1_max_hyst.attr,
- &dev_attr_temp2_max_hyst.attr,
- &dev_attr_temp3_max_hyst.attr,
-
- &dev_attr_fan1_input.attr,
- &dev_attr_fan2_input.attr,
- &dev_attr_fan1_min.attr,
- &dev_attr_fan2_min.attr,
- &dev_attr_fan1_div.attr,
- &dev_attr_fan2_div.attr,
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -612,58 +584,29 @@ static const struct attribute_group via686a_group = {
.attrs = via686a_attributes,
};
-/* The driver. I choose to use type i2c_driver, as at is identical to both
- smbus_driver and isa_driver, and clients could be of either kind */
-static struct i2c_driver via686a_driver = {
+static struct platform_driver via686a_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "via686a",
},
- .attach_adapter = via686a_detect,
- .detach_client = via686a_detach_client,
+ .probe = via686a_probe,
+ .remove = __devexit_p(via686a_remove),
};
/* This is called when the module is loaded */
-static int via686a_detect(struct i2c_adapter *adapter)
+static int __devinit via686a_probe(struct platform_device *pdev)
{
- struct i2c_client *new_client;
struct via686a_data *data;
- int err = 0;
- const char client_name[] = "via686a";
- u16 val;
-
- /* 8231 requires multiple of 256, we enforce that on 686 as well */
- if (force_addr) {
- address = force_addr & 0xFF00;
- dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
- address);
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
- return -ENODEV;
- }
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
- return -ENODEV;
- if (!(val & 0x0001)) {
- if (force_addr) {
- dev_info(&adapter->dev, "enabling sensors\n");
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
- val | 0x0001))
- return -ENODEV;
- } else {
- dev_warn(&adapter->dev, "sensors disabled - enable "
- "with force_addr=0x%x\n", address);
- return -ENODEV;
- }
- }
+ struct resource *res;
+ int err;
/* Reserve the ISA region */
- if (!request_region(address, VIA686A_EXTENT,
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, VIA686A_EXTENT,
via686a_driver.driver.name)) {
- dev_err(&adapter->dev, "region 0x%x already in use!\n",
- address);
+ dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+ (unsigned long)res->start, (unsigned long)res->end);
return -ENODEV;
}
@@ -672,30 +615,19 @@ static int via686a_detect(struct i2c_adapter *adapter)
goto exit_release;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
- new_client->adapter = adapter;
- new_client->driver = &via686a_driver;
- new_client->flags = 0;
-
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
-
- data->valid = 0;
+ platform_set_drvdata(pdev, data);
+ data->addr = res->start;
+ data->name = "via686a";
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
/* Initialize the VIA686A chip */
- via686a_init_client(new_client);
+ via686a_init_device(data);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
- goto exit_detach;
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
+ goto exit_free;
- data->class_dev = hwmon_device_register(&new_client->dev);
+ data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -704,51 +636,46 @@ static int via686a_detect(struct i2c_adapter *adapter)
return 0;
exit_remove_files:
- sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
-exit_detach:
- i2c_detach_client(new_client);
+ sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
exit_free:
kfree(data);
exit_release:
- release_region(address, VIA686A_EXTENT);
+ release_region(res->start, VIA686A_EXTENT);
return err;
}
-static int via686a_detach_client(struct i2c_client *client)
+static int __devexit via686a_remove(struct platform_device *pdev)
{
- struct via686a_data *data = i2c_get_clientdata(client);
- int err;
+ struct via686a_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- sysfs_remove_group(&client->dev.kobj, &via686a_group);
+ sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
- if ((err = i2c_detach_client(client)))
- return err;
-
- release_region(client->addr, VIA686A_EXTENT);
+ release_region(data->addr, VIA686A_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
-static void via686a_init_client(struct i2c_client *client)
+static void __devinit via686a_init_device(struct via686a_data *data)
{
u8 reg;
/* Start monitoring */
- reg = via686a_read_value(client, VIA686A_REG_CONFIG);
- via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
+ reg = via686a_read_value(data, VIA686A_REG_CONFIG);
+ via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
/* Configure temp interrupt mode for continuous-interrupt operation */
- via686a_write_value(client, VIA686A_REG_TEMP_MODE,
- via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
- !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
+ reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
+ via686a_write_value(data, VIA686A_REG_TEMP_MODE,
+ (reg & ~VIA686A_TEMP_MODE_MASK)
+ | VIA686A_TEMP_MODE_CONTINUOUS);
}
static struct via686a_data *via686a_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct via686a_data *data = i2c_get_clientdata(client);
+ struct via686a_data *data = dev_get_drvdata(dev);
int i;
mutex_lock(&data->update_lock);
@@ -757,27 +684,27 @@ static struct via686a_data *via686a_update_device(struct device *dev)
|| !data->valid) {
for (i = 0; i <= 4; i++) {
data->in[i] =
- via686a_read_value(client, VIA686A_REG_IN(i));
- data->in_min[i] = via686a_read_value(client,
+ via686a_read_value(data, VIA686A_REG_IN(i));
+ data->in_min[i] = via686a_read_value(data,
VIA686A_REG_IN_MIN
(i));
data->in_max[i] =
- via686a_read_value(client, VIA686A_REG_IN_MAX(i));
+ via686a_read_value(data, VIA686A_REG_IN_MAX(i));
}
for (i = 1; i <= 2; i++) {
data->fan[i - 1] =
- via686a_read_value(client, VIA686A_REG_FAN(i));
- data->fan_min[i - 1] = via686a_read_value(client,
+ via686a_read_value(data, VIA686A_REG_FAN(i));
+ data->fan_min[i - 1] = via686a_read_value(data,
VIA686A_REG_FAN_MIN(i));
}
for (i = 0; i <= 2; i++) {
- data->temp[i] = via686a_read_value(client,
+ data->temp[i] = via686a_read_value(data,
VIA686A_REG_TEMP[i]) << 2;
data->temp_over[i] =
- via686a_read_value(client,
+ via686a_read_value(data,
VIA686A_REG_TEMP_OVER[i]);
data->temp_hyst[i] =
- via686a_read_value(client,
+ via686a_read_value(data,
VIA686A_REG_TEMP_HYST[i]);
}
/* add in lower 2 bits
@@ -785,23 +712,23 @@ static struct via686a_data *via686a_update_device(struct device *dev)
temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
*/
- data->temp[0] |= (via686a_read_value(client,
+ data->temp[0] |= (via686a_read_value(data,
VIA686A_REG_TEMP_LOW1)
& 0xc0) >> 6;
data->temp[1] |=
- (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+ (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
0x30) >> 4;
data->temp[2] |=
- (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+ (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
0xc0) >> 6;
- i = via686a_read_value(client, VIA686A_REG_FANDIV);
+ i = via686a_read_value(data, VIA686A_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
data->alarms =
- via686a_read_value(client,
+ via686a_read_value(data,
VIA686A_REG_ALARM1) |
- (via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
+ (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
data->last_updated = jiffies;
data->valid = 1;
}
@@ -818,32 +745,102 @@ static struct pci_device_id via686a_pci_ids[] = {
MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
+static int __devinit via686a_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + VIA686A_EXTENT - 1,
+ .name = "via686a",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("via686a", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "via686a: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "via686a: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "via686a: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __devinit via686a_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- u16 val;
+ u16 address, val;
+ if (force_addr) {
+ address = force_addr & ~(VIA686A_EXTENT - 1);
+ dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
+ return -ENODEV;
+ }
if (PCIBIOS_SUCCESSFUL !=
pci_read_config_word(dev, VIA686A_BASE_REG, &val))
return -ENODEV;
address = val & ~(VIA686A_EXTENT - 1);
- if (address == 0 && force_addr == 0) {
+ if (address == 0) {
dev_err(&dev->dev, "base address not set - upgrade BIOS "
"or use force_addr=0xaddr\n");
return -ENODEV;
}
- s_bridge = pci_dev_get(dev);
- if (i2c_isa_add_driver(&via686a_driver)) {
- pci_dev_put(s_bridge);
- s_bridge = NULL;
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
+ return -ENODEV;
+ if (!(val & 0x0001)) {
+ if (!force_addr) {
+ dev_warn(&dev->dev, "Sensors disabled, enable "
+ "with force_addr=0x%x\n", address);
+ return -ENODEV;
+ }
+
+ dev_warn(&dev->dev, "Enabling sensors\n");
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VIA686A_ENABLE_REG,
+ val | 0x0001))
+ return -ENODEV;
}
+ if (platform_driver_register(&via686a_driver))
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ if (via686a_device_add(address))
+ goto exit_unregister;
+
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
+ s_bridge = pci_dev_get(dev);
+ return -ENODEV;
+
+exit_unregister:
+ platform_driver_unregister(&via686a_driver);
+exit:
return -ENODEV;
}
@@ -862,7 +859,8 @@ static void __exit sm_via686a_exit(void)
{
pci_unregister_driver(&via686a_pci_driver);
if (s_bridge != NULL) {
- i2c_isa_del_driver(&via686a_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&via686a_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index a6a4aa0eee16..c604972f0186 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -29,8 +29,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
@@ -42,10 +41,7 @@ static int force_addr;
module_param(force_addr, int, 0);
MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");
-/* Device address
- Note that we can't determine the ISA address until we have initialized
- our module */
-static unsigned short isa_address;
+static struct platform_device *pdev;
#define VT8231_EXTENT 0x80
#define VT8231_BASE_REG 0x70
@@ -148,7 +144,9 @@ static inline u8 FAN_TO_REG(long rpm, int div)
#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
struct vt8231_data {
- struct i2c_client client;
+ unsigned short addr;
+ const char *name;
+
struct mutex update_lock;
struct class_device *class_dev;
char valid; /* !=0 if following fields are valid */
@@ -168,20 +166,20 @@ struct vt8231_data {
};
static struct pci_dev *s_bridge;
-static int vt8231_detect(struct i2c_adapter *adapter);
-static int vt8231_detach_client(struct i2c_client *client);
+static int vt8231_probe(struct platform_device *pdev);
+static int vt8231_remove(struct platform_device *pdev);
static struct vt8231_data *vt8231_update_device(struct device *dev);
-static void vt8231_init_client(struct i2c_client *client);
+static void vt8231_init_device(struct vt8231_data *data);
-static inline int vt8231_read_value(struct i2c_client *client, u8 reg)
+static inline int vt8231_read_value(struct vt8231_data *data, u8 reg)
{
- return inb_p(client->addr + reg);
+ return inb_p(data->addr + reg);
}
-static inline void vt8231_write_value(struct i2c_client *client, u8 reg,
+static inline void vt8231_write_value(struct vt8231_data *data, u8 reg,
u8 value)
{
- outb_p(value, client->addr + reg);
+ outb_p(value, data->addr + reg);
}
/* following are the sysfs callback functions */
@@ -220,13 +218,12 @@ static ssize_t set_in_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
- vt8231_write_value(client, regvoltmin[nr], data->in_min[nr]);
+ vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -236,13 +233,12 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
- vt8231_write_value(client, regvoltmax[nr], data->in_max[nr]);
+ vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -278,14 +274,13 @@ static ssize_t show_in5_max(struct device *dev, struct device_attribute *attr,
static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
0, 255);
- vt8231_write_value(client, regvoltmin[5], data->in_min[5]);
+ vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -293,14 +288,13 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
unsigned long val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
0, 255);
- vt8231_write_value(client, regvoltmax[5], data->in_max[5]);
+ vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -348,26 +342,24 @@ static ssize_t show_temp0_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
- vt8231_write_value(client, regtempmax[0], data->temp_max[0]);
+ vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
mutex_unlock(&data->update_lock);
return count;
}
static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
- vt8231_write_value(client, regtempmin[0], data->temp_min[0]);
+ vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -404,13 +396,12 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
- vt8231_write_value(client, regtempmax[nr], data->temp_max[nr]);
+ vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -419,13 +410,12 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtol(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
- vt8231_write_value(client, regtempmin[nr], data->temp_min[nr]);
+ vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -486,13 +476,12 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
{
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int val = simple_strtoul(buf, NULL, 10);
mutex_lock(&data->update_lock);
data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
- vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+ vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
mutex_unlock(&data->update_lock);
return count;
}
@@ -500,12 +489,11 @@ static ssize_t set_fan_min(struct device *dev, struct device_attribute *attr,
static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
unsigned long val = simple_strtoul(buf, NULL, 10);
int nr = sensor_attr->index;
- int old = vt8231_read_value(client, VT8231_REG_FANDIV);
+ int old = vt8231_read_value(data, VT8231_REG_FANDIV);
long min = FAN_FROM_REG(data->fan_min[nr],
DIV_FROM_REG(data->fan_div[nr]));
@@ -516,7 +504,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
case 4: data->fan_div[nr] = 2; break;
case 8: data->fan_div[nr] = 3; break;
default:
- dev_err(&client->dev, "fan_div value %ld not supported."
+ dev_err(dev, "fan_div value %ld not supported."
"Choose one of 1, 2, 4 or 8!\n", val);
mutex_unlock(&data->update_lock);
return -EINVAL;
@@ -524,10 +512,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
/* Correct the fan minimum speed */
data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
- vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+ vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
- vt8231_write_value(client, VT8231_REG_FANDIV, old);
+ vt8231_write_value(data, VT8231_REG_FANDIV, old);
mutex_unlock(&data->update_lock);
return count;
}
@@ -551,9 +539,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
struct vt8231_data *data = vt8231_update_device(dev);
return sprintf(buf, "%d\n", data->alarms);
}
-
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct vt8231_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
static struct attribute *vt8231_attributes_temps[6][4] = {
{
&dev_attr_temp1_input.attr,
@@ -648,6 +643,7 @@ static struct attribute *vt8231_attributes[] = {
&sensor_dev_attr_fan1_div.dev_attr.attr,
&sensor_dev_attr_fan2_div.dev_attr.attr,
&dev_attr_alarms.attr,
+ &dev_attr_name.attr,
NULL
};
@@ -655,13 +651,13 @@ static const struct attribute_group vt8231_group = {
.attrs = vt8231_attributes,
};
-static struct i2c_driver vt8231_driver = {
+static struct platform_driver vt8231_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "vt8231",
},
- .attach_adapter = vt8231_detect,
- .detach_client = vt8231_detach_client,
+ .probe = vt8231_probe,
+ .remove = __devexit_p(vt8231_remove),
};
static struct pci_device_id vt8231_pci_ids[] = {
@@ -680,40 +676,18 @@ static struct pci_driver vt8231_pci_driver = {
.probe = vt8231_pci_probe,
};
-int vt8231_detect(struct i2c_adapter *adapter)
+int vt8231_probe(struct platform_device *pdev)
{
- struct i2c_client *client;
+ struct resource *res;
struct vt8231_data *data;
int err = 0, i;
- u16 val;
-
- /* 8231 requires multiple of 256 */
- if (force_addr) {
- isa_address = force_addr & 0xFF00;
- dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
- isa_address);
- if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge,
- VT8231_BASE_REG, isa_address))
- return -ENODEV;
- }
-
- if (PCIBIOS_SUCCESSFUL !=
- pci_read_config_word(s_bridge, VT8231_ENABLE_REG, &val))
- return -ENODEV;
-
- if (!(val & 0x0001)) {
- dev_warn(&adapter->dev, "enabling sensors\n");
- if (PCIBIOS_SUCCESSFUL !=
- pci_write_config_word(s_bridge, VT8231_ENABLE_REG,
- val | 0x0001))
- return -ENODEV;
- }
/* Reserve the ISA region */
- if (!request_region(isa_address, VT8231_EXTENT,
- vt8231_pci_driver.name)) {
- dev_err(&adapter->dev, "region 0x%x already in use!\n",
- isa_address);
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, VT8231_EXTENT,
+ vt8231_driver.driver.name)) {
+ dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+ (unsigned long)res->start, (unsigned long)res->end);
return -ENODEV;
}
@@ -722,33 +696,23 @@ int vt8231_detect(struct i2c_adapter *adapter)
goto exit_release;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = isa_address;
- client->adapter = adapter;
- client->driver = &vt8231_driver;
-
- /* Fill in the remaining client fields and put into the global list */
- strlcpy(client->name, "vt8231", I2C_NAME_SIZE);
+ platform_set_drvdata(pdev, data);
+ data->addr = res->start;
+ data->name = "vt8231";
mutex_init(&data->update_lock);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
- vt8231_init_client(client);
+ vt8231_init_device(data);
/* Register sysfs hooks */
- if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
- goto exit_detach;
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group)))
+ goto exit_free;
/* Must update device information to find out the config field */
- data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
+ data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
if (ISTEMP(i, data->uch_config)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
&vt8231_group_temps[i])))
goto exit_remove_files;
}
@@ -756,13 +720,13 @@ int vt8231_detect(struct i2c_adapter *adapter)
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
if (ISVOLT(i, data->uch_config)) {
- if ((err = sysfs_create_group(&client->dev.kobj,
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
&vt8231_group_volts[i])))
goto exit_remove_files;
}
}
- data->class_dev = hwmon_device_register(&client->dev);
+ data->class_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
goto exit_remove_files;
@@ -771,56 +735,52 @@ int vt8231_detect(struct i2c_adapter *adapter)
exit_remove_files:
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
+
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
- sysfs_remove_group(&client->dev.kobj, &vt8231_group);
-exit_detach:
- i2c_detach_client(client);
exit_free:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
+
exit_release:
- release_region(isa_address, VT8231_EXTENT);
+ release_region(res->start, VT8231_EXTENT);
return err;
}
-static int vt8231_detach_client(struct i2c_client *client)
+static int vt8231_remove(struct platform_device *pdev)
{
- struct vt8231_data *data = i2c_get_clientdata(client);
- int err, i;
+ struct vt8231_data *data = platform_get_drvdata(pdev);
+ int i;
hwmon_device_unregister(data->class_dev);
for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
- sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
- sysfs_remove_group(&client->dev.kobj, &vt8231_group);
+ sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
- if ((err = i2c_detach_client(client))) {
- return err;
- }
-
- release_region(client->addr, VT8231_EXTENT);
+ release_region(data->addr, VT8231_EXTENT);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
-
return 0;
}
-static void vt8231_init_client(struct i2c_client *client)
+static void vt8231_init_device(struct vt8231_data *data)
{
- vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0);
- vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0);
+ vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0);
+ vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0);
}
static struct vt8231_data *vt8231_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct vt8231_data *data = i2c_get_clientdata(client);
+ struct vt8231_data *data = dev_get_drvdata(dev);
int i;
u16 low;
@@ -830,41 +790,41 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
|| !data->valid) {
for (i = 0; i < 6; i++) {
if (ISVOLT(i, data->uch_config)) {
- data->in[i] = vt8231_read_value(client,
+ data->in[i] = vt8231_read_value(data,
regvolt[i]);
- data->in_min[i] = vt8231_read_value(client,
+ data->in_min[i] = vt8231_read_value(data,
regvoltmin[i]);
- data->in_max[i] = vt8231_read_value(client,
+ data->in_max[i] = vt8231_read_value(data,
regvoltmax[i]);
}
}
for (i = 0; i < 2; i++) {
- data->fan[i] = vt8231_read_value(client,
+ data->fan[i] = vt8231_read_value(data,
VT8231_REG_FAN(i));
- data->fan_min[i] = vt8231_read_value(client,
+ data->fan_min[i] = vt8231_read_value(data,
VT8231_REG_FAN_MIN(i));
}
- low = vt8231_read_value(client, VT8231_REG_TEMP_LOW01);
+ low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01);
low = (low >> 6) | ((low & 0x30) >> 2)
- | (vt8231_read_value(client, VT8231_REG_TEMP_LOW25) << 4);
+ | (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4);
for (i = 0; i < 6; i++) {
if (ISTEMP(i, data->uch_config)) {
- data->temp[i] = (vt8231_read_value(client,
+ data->temp[i] = (vt8231_read_value(data,
regtemp[i]) << 2)
| ((low >> (2 * i)) & 0x03);
- data->temp_max[i] = vt8231_read_value(client,
+ data->temp_max[i] = vt8231_read_value(data,
regtempmax[i]);
- data->temp_min[i] = vt8231_read_value(client,
+ data->temp_min[i] = vt8231_read_value(data,
regtempmin[i]);
}
}
- i = vt8231_read_value(client, VT8231_REG_FANDIV);
+ i = vt8231_read_value(data, VT8231_REG_FANDIV);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = i >> 6;
- data->alarms = vt8231_read_value(client, VT8231_REG_ALARM1) |
- (vt8231_read_value(client, VT8231_REG_ALARM2) << 8);
+ data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) |
+ (vt8231_read_value(data, VT8231_REG_ALARM2) << 8);
/* Set alarm flags correctly */
if (!data->fan[0] && data->fan_min[0]) {
@@ -888,33 +848,102 @@ static struct vt8231_data *vt8231_update_device(struct device *dev)
return data;
}
+static int __devinit vt8231_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + VT8231_EXTENT - 1,
+ .name = "vt8231",
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc("vt8231", address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR "vt8231: Device allocation failed\n");
+ goto exit;
+ }
+
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR "vt8231: Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR "vt8231: Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit:
+ return err;
+}
+
static int __devinit vt8231_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- u16 val;
+ u16 address, val;
+ if (force_addr) {
+ address = force_addr & 0xff00;
+ dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
+ address);
+
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
+ return -ENODEV;
+ }
if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_BASE_REG,
&val))
return -ENODEV;
- isa_address = val & ~(VT8231_EXTENT - 1);
- if (isa_address == 0 && force_addr == 0) {
+ address = val & ~(VT8231_EXTENT - 1);
+ if (address == 0) {
dev_err(&dev->dev, "base address not set -\
upgrade BIOS or use force_addr=0xaddr\n");
return -ENODEV;
}
- s_bridge = pci_dev_get(dev);
+ if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_ENABLE_REG,
+ &val))
+ return -ENODEV;
- if (i2c_isa_add_driver(&vt8231_driver)) {
- pci_dev_put(s_bridge);
- s_bridge = NULL;
+ if (!(val & 0x0001)) {
+ dev_warn(&dev->dev, "enabling sensors\n");
+ if (PCIBIOS_SUCCESSFUL !=
+ pci_write_config_word(dev, VT8231_ENABLE_REG,
+ val | 0x0001))
+ return -ENODEV;
}
+ if (platform_driver_register(&vt8231_driver))
+ goto exit;
+
+ /* Sets global pdev as a side effect */
+ if (vt8231_device_add(address))
+ goto exit_unregister;
+
/* Always return failure here. This is to allow other drivers to bind
* to this pci device. We don't really want to have control over the
* pci device, we only wanted to read as few register values from it.
*/
+
+ /* We do, however, mark ourselves as using the PCI device to stop it
+ getting unloaded. */
+ s_bridge = pci_dev_get(dev);
+ return -ENODEV;
+
+exit_unregister:
+ platform_driver_unregister(&vt8231_driver);
+exit:
return -ENODEV;
}
@@ -927,7 +956,8 @@ static void __exit sm_vt8231_exit(void)
{
pci_unregister_driver(&vt8231_pci_driver);
if (s_bridge != NULL) {
- i2c_isa_del_driver(&vt8231_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&vt8231_driver);
pci_dev_put(s_bridge);
s_bridge = NULL;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 30a76404f0af..c51ae2e17758 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -41,41 +41,39 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include "lm75.h"
-/* The actual ISA address is read from Super-I/O configuration space */
-static unsigned short address;
+enum kinds { w83627ehf, w83627dhg };
-/*
- * Super-I/O constants and functions
- */
+/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
+static const char * w83627ehf_device_names[] = {
+ "w83627ehf",
+ "w83627dhg",
+};
+
+#define DRVNAME "w83627ehf"
/*
- * The three following globals are initialized in w83627ehf_find(), before
- * the i2c-isa device is created. Otherwise, they could be stored in
- * w83627ehf_data. This is ugly, but necessary, and when the driver is next
- * updated to become a platform driver, the globals will disappear.
+ * Super-I/O constants and functions
*/
-static int REG; /* The register to read/write */
-static int VAL; /* The value to read/write */
-/* The w83627ehf/ehg have 10 voltage inputs, but the w83627dhg has 9. This
- * value is also used in w83627ehf_detect() to export a device name in sysfs
- * (e.g. w83627ehf or w83627dhg) */
-static int w83627ehf_num_in;
#define W83627EHF_LD_HWM 0x0b
#define SIO_REG_LDSEL 0x07 /* Logical device select */
#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
+#define SIO_REG_EN_VRM10 0x2C /* GPIO3, GPIO4 selection */
#define SIO_REG_ENABLE 0x30 /* Logical device enable */
#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
+#define SIO_REG_VID_CTRL 0xF0 /* VID control */
+#define SIO_REG_VID_DATA 0xF1 /* VID data */
#define SIO_W83627EHF_ID 0x8850
#define SIO_W83627EHG_ID 0x8860
@@ -83,38 +81,38 @@ static int w83627ehf_num_in;
#define SIO_ID_MASK 0xFFF0
static inline void
-superio_outb(int reg, int val)
+superio_outb(int ioreg, int reg, int val)
{
- outb(reg, REG);
- outb(val, VAL);
+ outb(reg, ioreg);
+ outb(val, ioreg + 1);
}
static inline int
-superio_inb(int reg)
+superio_inb(int ioreg, int reg)
{
- outb(reg, REG);
- return inb(VAL);
+ outb(reg, ioreg);
+ return inb(ioreg + 1);
}
static inline void
-superio_select(int ld)
+superio_select(int ioreg, int ld)
{
- outb(SIO_REG_LDSEL, REG);
- outb(ld, VAL);
+ outb(SIO_REG_LDSEL, ioreg);
+ outb(ld, ioreg + 1);
}
static inline void
-superio_enter(void)
+superio_enter(int ioreg)
{
- outb(0x87, REG);
- outb(0x87, REG);
+ outb(0x87, ioreg);
+ outb(0x87, ioreg);
}
static inline void
-superio_exit(void)
+superio_exit(int ioreg)
{
- outb(0x02, REG);
- outb(0x02, VAL);
+ outb(0x02, ioreg);
+ outb(0x02, ioreg + 1);
}
/*
@@ -124,8 +122,8 @@ superio_exit(void)
#define IOREGION_ALIGNMENT ~7
#define IOREGION_OFFSET 5
#define IOREGION_LENGTH 2
-#define ADDR_REG_OFFSET 5
-#define DATA_REG_OFFSET 6
+#define ADDR_REG_OFFSET 0
+#define DATA_REG_OFFSET 1
#define W83627EHF_REG_BANK 0x4E
#define W83627EHF_REG_CONFIG 0x40
@@ -255,7 +253,9 @@ static inline u8 in_to_reg(u32 val, u8 nr)
*/
struct w83627ehf_data {
- struct i2c_client client;
+ int addr; /* IO base of hw monitor block */
+ const char *name;
+
struct class_device *class_dev;
struct mutex lock;
@@ -264,6 +264,7 @@ struct w83627ehf_data {
unsigned long last_updated; /* In jiffies */
/* Register values */
+ u8 in_num; /* number of in inputs we have */
u8 in[10]; /* Register value */
u8 in_max[10]; /* Register value */
u8 in_min[10]; /* Register value */
@@ -271,6 +272,7 @@ struct w83627ehf_data {
u8 fan_min[5];
u8 fan_div[5];
u8 has_fan; /* some fan inputs can be disabled */
+ u8 temp_type[3];
s8 temp1;
s8 temp1_max;
s8 temp1_max_hyst;
@@ -288,6 +290,14 @@ struct w83627ehf_data {
u8 fan_min_output[4]; /* minimum fan speed */
u8 fan_stop_time[4];
+
+ u8 vid;
+ u8 vrm;
+};
+
+struct w83627ehf_sio_data {
+ int sioreg;
+ enum kinds kind;
};
static inline int is_word_sized(u16 reg)
@@ -303,156 +313,152 @@ static inline int is_word_sized(u16 reg)
nothing for registers which live in bank 0. For others, they respectively
set the bank register to the correct value (before the register is
accessed), and back to 0 (afterwards). */
-static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
+static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
{
if (reg & 0xff00) {
- outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
- outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
+ outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+ outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
}
}
-static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
+static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
{
if (reg & 0xff00) {
- outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
- outb_p(0, client->addr + DATA_REG_OFFSET);
+ outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+ outb_p(0, data->addr + DATA_REG_OFFSET);
}
}
-static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
+static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
int res, word_sized = is_word_sized(reg);
mutex_lock(&data->lock);
- w83627ehf_set_bank(client, reg);
- outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
- res = inb_p(client->addr + DATA_REG_OFFSET);
+ w83627ehf_set_bank(data, reg);
+ outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+ res = inb_p(data->addr + DATA_REG_OFFSET);
if (word_sized) {
outb_p((reg & 0xff) + 1,
- client->addr + ADDR_REG_OFFSET);
- res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
+ data->addr + ADDR_REG_OFFSET);
+ res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
}
- w83627ehf_reset_bank(client, reg);
+ w83627ehf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return res;
}
-static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
int word_sized = is_word_sized(reg);
mutex_lock(&data->lock);
- w83627ehf_set_bank(client, reg);
- outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
+ w83627ehf_set_bank(data, reg);
+ outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
if (word_sized) {
- outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
+ outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
outb_p((reg & 0xff) + 1,
- client->addr + ADDR_REG_OFFSET);
+ data->addr + ADDR_REG_OFFSET);
}
- outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
- w83627ehf_reset_bank(client, reg);
+ outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+ w83627ehf_reset_bank(data, reg);
mutex_unlock(&data->lock);
return 0;
}
/* This function assumes that the caller holds data->update_lock */
-static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
+static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
u8 reg;
switch (nr) {
case 0:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
| ((data->fan_div[0] & 0x03) << 4);
/* fan5 input control bit is write only, compute the value */
reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
+ w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
| ((data->fan_div[0] & 0x04) << 3);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
break;
case 1:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
| ((data->fan_div[1] & 0x03) << 6);
/* fan5 input control bit is write only, compute the value */
reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
+ w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
| ((data->fan_div[1] & 0x04) << 4);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
break;
case 2:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
| ((data->fan_div[2] & 0x03) << 6);
- w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
+ w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
| ((data->fan_div[2] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
break;
case 3:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
| (data->fan_div[3] & 0x03);
- w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
- reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
+ w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
| ((data->fan_div[3] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
break;
case 4:
- reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
+ reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
| ((data->fan_div[4] & 0x03) << 2)
| ((data->fan_div[4] & 0x04) << 5);
- w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
+ w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
break;
}
}
static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
int i;
mutex_lock(&data->update_lock);
- if (time_after(jiffies, data->last_updated + HZ)
+ if (time_after(jiffies, data->last_updated + HZ + HZ/2)
|| !data->valid) {
/* Fan clock dividers */
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
data->fan_div[0] = (i >> 4) & 0x03;
data->fan_div[1] = (i >> 6) & 0x03;
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
data->fan_div[2] = (i >> 6) & 0x03;
- i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
+ i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
data->fan_div[0] |= (i >> 3) & 0x04;
data->fan_div[1] |= (i >> 4) & 0x04;
data->fan_div[2] |= (i >> 5) & 0x04;
if (data->has_fan & ((1 << 3) | (1 << 4))) {
- i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
+ i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
data->fan_div[3] = i & 0x03;
data->fan_div[4] = ((i >> 2) & 0x03)
| ((i >> 5) & 0x04);
}
if (data->has_fan & (1 << 3)) {
- i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
+ i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
data->fan_div[3] |= (i >> 5) & 0x04;
}
/* Measured voltages and limits */
- for (i = 0; i < w83627ehf_num_in; i++) {
- data->in[i] = w83627ehf_read_value(client,
+ for (i = 0; i < data->in_num; i++) {
+ data->in[i] = w83627ehf_read_value(data,
W83627EHF_REG_IN(i));
- data->in_min[i] = w83627ehf_read_value(client,
+ data->in_min[i] = w83627ehf_read_value(data,
W83627EHF_REG_IN_MIN(i));
- data->in_max[i] = w83627ehf_read_value(client,
+ data->in_max[i] = w83627ehf_read_value(data,
W83627EHF_REG_IN_MAX(i));
}
@@ -461,9 +467,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
if (!(data->has_fan & (1 << i)))
continue;
- data->fan[i] = w83627ehf_read_value(client,
+ data->fan[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN[i]);
- data->fan_min[i] = w83627ehf_read_value(client,
+ data->fan_min[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN_MIN[i]);
/* If we failed to measure the fan speed and clock
@@ -471,16 +477,16 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
time */
if (data->fan[i] == 0xff
&& data->fan_div[i] < 0x07) {
- dev_dbg(&client->dev, "Increasing fan%d "
+ dev_dbg(dev, "Increasing fan%d "
"clock divider from %u to %u\n",
i + 1, div_from_reg(data->fan_div[i]),
div_from_reg(data->fan_div[i] + 1));
data->fan_div[i]++;
- w83627ehf_write_fan_div(client, i);
+ w83627ehf_write_fan_div(data, i);
/* Preserve min limit if possible */
if (data->fan_min[i] >= 2
&& data->fan_min[i] != 255)
- w83627ehf_write_value(client,
+ w83627ehf_write_value(data,
W83627EHF_REG_FAN_MIN[i],
(data->fan_min[i] /= 2));
}
@@ -489,9 +495,9 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
for (i = 0; i < 4; i++) {
/* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
if (i != 1) {
- pwmcfg = w83627ehf_read_value(client,
+ pwmcfg = w83627ehf_read_value(data,
W83627EHF_REG_PWM_ENABLE[i]);
- tolerance = w83627ehf_read_value(client,
+ tolerance = w83627ehf_read_value(data,
W83627EHF_REG_TOLERANCE[i]);
}
data->pwm_mode[i] =
@@ -500,14 +506,14 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
data->pwm_enable[i] =
((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
& 3) + 1;
- data->pwm[i] = w83627ehf_read_value(client,
+ data->pwm[i] = w83627ehf_read_value(data,
W83627EHF_REG_PWM[i]);
- data->fan_min_output[i] = w83627ehf_read_value(client,
+ data->fan_min_output[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN_MIN_OUTPUT[i]);
- data->fan_stop_time[i] = w83627ehf_read_value(client,
+ data->fan_stop_time[i] = w83627ehf_read_value(data,
W83627EHF_REG_FAN_STOP_TIME[i]);
data->target_temp[i] =
- w83627ehf_read_value(client,
+ w83627ehf_read_value(data,
W83627EHF_REG_TARGET[i]) &
(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
@@ -515,26 +521,26 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
}
/* Measured temperatures and limits */
- data->temp1 = w83627ehf_read_value(client,
+ data->temp1 = w83627ehf_read_value(data,
W83627EHF_REG_TEMP1);
- data->temp1_max = w83627ehf_read_value(client,
+ data->temp1_max = w83627ehf_read_value(data,
W83627EHF_REG_TEMP1_OVER);
- data->temp1_max_hyst = w83627ehf_read_value(client,
+ data->temp1_max_hyst = w83627ehf_read_value(data,
W83627EHF_REG_TEMP1_HYST);
for (i = 0; i < 2; i++) {
- data->temp[i] = w83627ehf_read_value(client,
+ data->temp[i] = w83627ehf_read_value(data,
W83627EHF_REG_TEMP[i]);
- data->temp_max[i] = w83627ehf_read_value(client,
+ data->temp_max[i] = w83627ehf_read_value(data,
W83627EHF_REG_TEMP_OVER[i]);
- data->temp_max_hyst[i] = w83627ehf_read_value(client,
+ data->temp_max_hyst[i] = w83627ehf_read_value(data,
W83627EHF_REG_TEMP_HYST[i]);
}
- data->alarms = w83627ehf_read_value(client,
+ data->alarms = w83627ehf_read_value(data,
W83627EHF_REG_ALARM1) |
- (w83627ehf_read_value(client,
+ (w83627ehf_read_value(data,
W83627EHF_REG_ALARM2) << 8) |
- (w83627ehf_read_value(client,
+ (w83627ehf_read_value(data,
W83627EHF_REG_ALARM3) << 16);
data->last_updated = jiffies;
@@ -567,15 +573,14 @@ static ssize_t \
store_in_##reg (struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->in_##reg[nr] = in_to_reg(val, nr); \
- w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \
+ w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
data->in_##reg[nr]); \
mutex_unlock(&data->update_lock); \
return count; \
@@ -673,8 +678,7 @@ static ssize_t
store_fan_min(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
unsigned int val = simple_strtoul(buf, NULL, 10);
@@ -716,18 +720,25 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
/* Write both the fan clock divider (if it changed) and the new
fan min (unconditionally) */
if (new_div != data->fan_div[nr]) {
- if (new_div > data->fan_div[nr])
- data->fan[nr] >>= (data->fan_div[nr] - new_div);
- else
- data->fan[nr] <<= (new_div - data->fan_div[nr]);
+ /* Preserve the fan speed reading */
+ if (data->fan[nr] != 0xff) {
+ if (new_div > data->fan_div[nr])
+ data->fan[nr] >>= new_div - data->fan_div[nr];
+ else if (data->fan[nr] & 0x80)
+ data->fan[nr] = 0xff;
+ else
+ data->fan[nr] <<= data->fan_div[nr] - new_div;
+ }
dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
nr + 1, div_from_reg(data->fan_div[nr]),
div_from_reg(new_div));
data->fan_div[nr] = new_div;
- w83627ehf_write_fan_div(client, nr);
+ w83627ehf_write_fan_div(data, nr);
+ /* Give the chip time to sample a new speed value */
+ data->last_updated = jiffies;
}
- w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
+ w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
data->fan_min[nr]);
mutex_unlock(&data->update_lock);
@@ -788,13 +799,12 @@ static ssize_t \
store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
- w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
+ w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
data->temp1_##reg); \
mutex_unlock(&data->update_lock); \
return count; \
@@ -822,15 +832,14 @@ static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
data->reg[nr] = LM75_TEMP_TO_REG(val); \
- w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
+ w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
data->reg[nr]); \
mutex_unlock(&data->update_lock); \
return count; \
@@ -838,6 +847,15 @@ store_##reg(struct device *dev, struct device_attribute *attr, \
store_temp_reg(OVER, temp_max);
store_temp_reg(HYST, temp_max_hyst);
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = w83627ehf_update_device(dev);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
static struct sensor_device_attribute sda_temp[] = {
SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
@@ -857,6 +875,9 @@ static struct sensor_device_attribute sda_temp[] = {
SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+ SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+ SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+ SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
};
#define show_pwm_reg(reg) \
@@ -877,8 +898,7 @@ static ssize_t
store_pwm_mode(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u32 val = simple_strtoul(buf, NULL, 10);
@@ -887,12 +907,12 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
if (val > 1)
return -EINVAL;
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
data->pwm_mode[nr] = val;
reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
if (!val)
reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
- w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
@@ -901,15 +921,14 @@ static ssize_t
store_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
mutex_lock(&data->update_lock);
data->pwm[nr] = val;
- w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
+ w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
mutex_unlock(&data->update_lock);
return count;
}
@@ -918,8 +937,7 @@ static ssize_t
store_pwm_enable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u32 val = simple_strtoul(buf, NULL, 10);
@@ -928,11 +946,11 @@ store_pwm_enable(struct device *dev, struct device_attribute *attr,
if (!val || (val > 2)) /* only modes 1 and 2 are supported */
return -EINVAL;
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
data->pwm_enable[nr] = val;
reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
- w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
@@ -955,15 +973,14 @@ static ssize_t
store_target_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
mutex_lock(&data->update_lock);
data->target_temp[nr] = val;
- w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
+ w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
mutex_unlock(&data->update_lock);
return count;
}
@@ -972,8 +989,7 @@ static ssize_t
store_tolerance(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
int nr = sensor_attr->index;
u16 reg;
@@ -981,13 +997,13 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
mutex_lock(&data->update_lock);
- reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
+ reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
data->tolerance[nr] = val;
if (nr == 1)
reg = (reg & 0x0f) | (val << 4);
else
reg = (reg & 0xf0) | val;
- w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
+ w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
mutex_unlock(&data->update_lock);
return count;
}
@@ -1058,14 +1074,13 @@ static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{\
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
- w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
mutex_unlock(&data->update_lock); \
return count; \
}
@@ -1087,21 +1102,28 @@ static ssize_t \
store_##reg(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
- struct i2c_client *client = to_i2c_client(dev); \
- struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct w83627ehf_data *data = dev_get_drvdata(dev); \
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
int nr = sensor_attr->index; \
u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
data->pwm_mode[nr]); \
mutex_lock(&data->update_lock); \
data->reg[nr] = val; \
- w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
mutex_unlock(&data->update_lock); \
return count; \
} \
fan_time_functions(fan_stop_time, FAN_STOP_TIME)
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
@@ -1125,8 +1147,16 @@ static struct sensor_device_attribute sda_sf3_arrays[] = {
store_fan_min_output, 2),
};
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
/*
- * Driver and client management
+ * Driver and device management
*/
static void w83627ehf_device_remove_files(struct device *dev)
@@ -1134,12 +1164,13 @@ static void w83627ehf_device_remove_files(struct device *dev)
/* some entries in the following arrays may not have been used in
* device_create_file(), but device_remove_file() will ignore them */
int i;
+ struct w83627ehf_data *data = dev_get_drvdata(dev);
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
- for (i = 0; i < w83627ehf_num_in; i++) {
+ for (i = 0; i < data->in_num; i++) {
device_remove_file(dev, &sda_in_input[i].dev_attr);
device_remove_file(dev, &sda_in_alarm[i].dev_attr);
device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1160,43 +1191,64 @@ static void w83627ehf_device_remove_files(struct device *dev)
}
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
device_remove_file(dev, &sda_temp[i].dev_attr);
-}
-static struct i2c_driver w83627ehf_driver;
+ device_remove_file(dev, &dev_attr_name);
+ if (data->vid != 0x3f)
+ device_remove_file(dev, &dev_attr_cpu0_vid);
+}
-static void w83627ehf_init_client(struct i2c_client *client)
+/* Get the monitoring functions started */
+static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
{
int i;
- u8 tmp;
+ u8 tmp, diode;
/* Start monitoring is needed */
- tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
+ tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
if (!(tmp & 0x01))
- w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
+ w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
tmp | 0x01);
/* Enable temp2 and temp3 if needed */
for (i = 0; i < 2; i++) {
- tmp = w83627ehf_read_value(client,
+ tmp = w83627ehf_read_value(data,
W83627EHF_REG_TEMP_CONFIG[i]);
if (tmp & 0x01)
- w83627ehf_write_value(client,
+ w83627ehf_write_value(data,
W83627EHF_REG_TEMP_CONFIG[i],
tmp & 0xfe);
}
+
+ /* Enable VBAT monitoring if needed */
+ tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+ if (!(tmp & 0x01))
+ w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
+
+ /* Get thermal sensor types */
+ diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+ for (i = 0; i < 3; i++) {
+ if ((tmp & (0x02 << i)))
+ data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
+ else
+ data->temp_type[i] = 4; /* thermistor */
+ }
}
-static int w83627ehf_detect(struct i2c_adapter *adapter)
+static int __devinit w83627ehf_probe(struct platform_device *pdev)
{
- struct i2c_client *client;
+ struct device *dev = &pdev->dev;
+ struct w83627ehf_sio_data *sio_data = dev->platform_data;
struct w83627ehf_data *data;
- struct device *dev;
- u8 fan4pin, fan5pin;
+ struct resource *res;
+ u8 fan4pin, fan5pin, en_vrm10;
int i, err = 0;
- if (!request_region(address + IOREGION_OFFSET, IOREGION_LENGTH,
- w83627ehf_driver.driver.name)) {
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
err = -EBUSY;
+ dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+ (unsigned long)res->start,
+ (unsigned long)res->start + IOREGION_LENGTH - 1);
goto exit;
}
@@ -1205,41 +1257,47 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
goto exit_release;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
+ data->addr = res->start;
mutex_init(&data->lock);
- client->adapter = adapter;
- client->driver = &w83627ehf_driver;
- client->flags = 0;
- dev = &client->dev;
-
- if (w83627ehf_num_in == 9)
- strlcpy(client->name, "w83627dhg", I2C_NAME_SIZE);
- else /* just say ehf. 627EHG is 627EHF in lead-free packaging. */
- strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
-
- data->valid = 0;
mutex_init(&data->update_lock);
+ data->name = w83627ehf_device_names[sio_data->kind];
+ platform_set_drvdata(pdev, data);
- /* Tell the i2c layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ /* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
+ data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
/* Initialize the chip */
- w83627ehf_init_client(client);
-
- /* A few vars need to be filled upon startup */
- for (i = 0; i < 5; i++)
- data->fan_min[i] = w83627ehf_read_value(client,
- W83627EHF_REG_FAN_MIN[i]);
+ w83627ehf_init_device(data);
+
+ data->vrm = vid_which_vrm();
+ superio_enter(sio_data->sioreg);
+ /* Set VID input sensibility if needed. In theory the BIOS should
+ have set it, but in practice it's not always the case. */
+ en_vrm10 = superio_inb(sio_data->sioreg, SIO_REG_EN_VRM10);
+ if ((en_vrm10 & 0x08) && data->vrm != 100) {
+ dev_warn(dev, "Setting VID input voltage to TTL\n");
+ superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+ en_vrm10 & ~0x08);
+ } else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
+ dev_warn(dev, "Setting VID input voltage to VRM10\n");
+ superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+ en_vrm10 | 0x08);
+ }
+ /* Read VID value */
+ superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+ if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80)
+ data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f;
+ else {
+ dev_info(dev, "VID pins in output mode, CPU VID not "
+ "available\n");
+ data->vid = 0x3f;
+ }
/* fan4 and fan5 share some pins with the GPIO and serial flash */
- superio_enter();
- fan5pin = superio_inb(0x24) & 0x2;
- fan4pin = superio_inb(0x29) & 0x6;
- superio_exit();
+ fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
+ fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
+ superio_exit(sio_data->sioreg);
/* It looks like fan4 and fan5 pins can be alternatively used
as fan on/off switches, but fan5 control is write only :/
@@ -1248,7 +1306,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
is not the default. */
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
- i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+ i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
if ((i & (1 << 2)) && (!fan4pin))
data->has_fan |= (1 << 3);
if (!(i & (1 << 1)) && (!fan5pin))
@@ -1268,7 +1326,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
goto exit_remove;
}
- for (i = 0; i < w83627ehf_num_in; i++)
+ for (i = 0; i < data->in_num; i++)
if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
|| (err = device_create_file(dev,
&sda_in_alarm[i].dev_attr))
@@ -1308,6 +1366,16 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
goto exit_remove;
+ err = device_create_file(dev, &dev_attr_name);
+ if (err)
+ goto exit_remove;
+
+ if (data->vid != 0x3f) {
+ err = device_create_file(dev, &dev_attr_cpu0_vid);
+ if (err)
+ goto exit_remove;
+ }
+
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
@@ -1318,95 +1386,172 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
exit_remove:
w83627ehf_device_remove_files(dev);
- i2c_detach_client(client);
-exit_free:
kfree(data);
+ platform_set_drvdata(pdev, NULL);
exit_release:
- release_region(address + IOREGION_OFFSET, IOREGION_LENGTH);
+ release_region(res->start, IOREGION_LENGTH);
exit:
return err;
}
-static int w83627ehf_detach_client(struct i2c_client *client)
+static int __devexit w83627ehf_remove(struct platform_device *pdev)
{
- struct w83627ehf_data *data = i2c_get_clientdata(client);
- int err;
+ struct w83627ehf_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->class_dev);
- w83627ehf_device_remove_files(&client->dev);
-
- if ((err = i2c_detach_client(client)))
- return err;
- release_region(client->addr + IOREGION_OFFSET, IOREGION_LENGTH);
+ w83627ehf_device_remove_files(&pdev->dev);
+ release_region(data->addr, IOREGION_LENGTH);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
return 0;
}
-static struct i2c_driver w83627ehf_driver = {
+static struct platform_driver w83627ehf_driver = {
.driver = {
.owner = THIS_MODULE,
- .name = "w83627ehf",
+ .name = DRVNAME,
},
- .attach_adapter = w83627ehf_detect,
- .detach_client = w83627ehf_detach_client,
+ .probe = w83627ehf_probe,
+ .remove = __devexit_p(w83627ehf_remove),
};
-static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
+/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
+ struct w83627ehf_sio_data *sio_data)
{
+ static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
+ static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
+ static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+
u16 val;
+ const char *sio_name;
- REG = sioaddr;
- VAL = sioaddr + 1;
- superio_enter();
+ superio_enter(sioaddr);
- val = (superio_inb(SIO_REG_DEVID) << 8)
- | superio_inb(SIO_REG_DEVID + 1);
+ val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+ | superio_inb(sioaddr, SIO_REG_DEVID + 1);
switch (val & SIO_ID_MASK) {
- case SIO_W83627DHG_ID:
- w83627ehf_num_in = 9;
- break;
case SIO_W83627EHF_ID:
+ sio_data->kind = w83627ehf;
+ sio_name = sio_name_W83627EHF;
+ break;
case SIO_W83627EHG_ID:
- w83627ehf_num_in = 10;
+ sio_data->kind = w83627ehf;
+ sio_name = sio_name_W83627EHG;
+ break;
+ case SIO_W83627DHG_ID:
+ sio_data->kind = w83627dhg;
+ sio_name = sio_name_W83627DHG;
break;
default:
- printk(KERN_WARNING "w83627ehf: unsupported chip ID: 0x%04x\n",
- val);
- superio_exit();
+ if (val != 0xffff)
+ pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
+ val);
+ superio_exit(sioaddr);
return -ENODEV;
}
- superio_select(W83627EHF_LD_HWM);
- val = (superio_inb(SIO_REG_ADDR) << 8)
- | superio_inb(SIO_REG_ADDR + 1);
+ /* We have a known chip, find the HWM I/O address */
+ superio_select(sioaddr, W83627EHF_LD_HWM);
+ val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+ | superio_inb(sioaddr, SIO_REG_ADDR + 1);
*addr = val & IOREGION_ALIGNMENT;
if (*addr == 0) {
- superio_exit();
+ printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
+ "device with a base I/O port 0.\n");
+ superio_exit(sioaddr);
return -ENODEV;
}
/* Activate logical device if needed */
- val = superio_inb(SIO_REG_ENABLE);
- if (!(val & 0x01))
- superio_outb(SIO_REG_ENABLE, val | 0x01);
+ val = superio_inb(sioaddr, SIO_REG_ENABLE);
+ if (!(val & 0x01)) {
+ printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
+ "Sensor is probably unusable.\n");
+ superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+ }
+
+ superio_exit(sioaddr);
+ pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
+ sio_data->sioreg = sioaddr;
- superio_exit();
return 0;
}
+/* when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the w83627ehf driver. But since we platform_device_alloc(), we
+ * must keep track of the device */
+static struct platform_device *pdev;
+
static int __init sensors_w83627ehf_init(void)
{
- if (w83627ehf_find(0x2e, &address)
- && w83627ehf_find(0x4e, &address))
+ int err;
+ unsigned short address;
+ struct resource res;
+ struct w83627ehf_sio_data sio_data;
+
+ /* initialize sio_data->kind and sio_data->sioreg.
+ *
+ * when Super-I/O functions move to a separate file, the Super-I/O
+ * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+ * w83627ehf hardware monitor, and call probe() */
+ if (w83627ehf_find(0x2e, &address, &sio_data) &&
+ w83627ehf_find(0x4e, &address, &sio_data))
return -ENODEV;
- return i2c_isa_add_driver(&w83627ehf_driver);
+ err = platform_driver_register(&w83627ehf_driver);
+ if (err)
+ goto exit;
+
+ if (!(pdev = platform_device_alloc(DRVNAME, address))) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+ goto exit_unregister;
+ }
+
+ err = platform_device_add_data(pdev, &sio_data,
+ sizeof(struct w83627ehf_sio_data));
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+ goto exit_device_put;
+ }
+
+ memset(&res, 0, sizeof(res));
+ res.name = DRVNAME;
+ res.start = address + IOREGION_OFFSET;
+ res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+ res.flags = IORESOURCE_IO;
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto exit_device_put;
+ }
+
+ /* platform_device_add calls probe() */
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto exit_device_put;
+ }
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(pdev);
+exit_unregister:
+ platform_driver_unregister(&w83627ehf_driver);
+exit:
+ return err;
}
static void __exit sensors_w83627ehf_exit(void)
{
- i2c_isa_del_driver(&w83627ehf_driver);
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&w83627ehf_driver);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 12cb40a975de..1ce78179b005 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -220,6 +220,18 @@ static const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2,
#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
+#define W83627HF_REG_PWM_FREQ 0x5C /* Only for the 627HF */
+
+#define W83637HF_REG_PWM_FREQ1 0x00 /* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ2 0x02 /* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ3 0x10 /* 687THF too */
+
+static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
+ W83637HF_REG_PWM_FREQ2,
+ W83637HF_REG_PWM_FREQ3 };
+
+#define W83627HF_BASE_PWM_FREQ 46870
+
#define W83781D_REG_I2C_ADDR 0x48
#define W83781D_REG_I2C_SUBADDR 0x4A
@@ -267,6 +279,49 @@ static int TEMP_FROM_REG(u8 reg)
#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
+static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
+{
+ unsigned long freq;
+ freq = W83627HF_BASE_PWM_FREQ >> reg;
+ return freq;
+}
+static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
+{
+ u8 i;
+ /* Only 5 dividers (1 2 4 8 16)
+ Search for the nearest available frequency */
+ for (i = 0; i < 4; i++) {
+ if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
+ (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
+ break;
+ }
+ return i;
+}
+
+static inline unsigned long pwm_freq_from_reg(u8 reg)
+{
+ /* Clock bit 8 -> 180 kHz or 24 MHz */
+ unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
+
+ reg &= 0x7f;
+ /* This should not happen but anyway... */
+ if (reg == 0)
+ reg++;
+ return (clock / (reg << 8));
+}
+static inline u8 pwm_freq_to_reg(unsigned long val)
+{
+ /* Minimum divider value is 0x01 and maximum is 0x7F */
+ if (val >= 93750) /* The highest we can do */
+ return 0x01;
+ if (val >= 720) /* Use 24 MHz clock */
+ return (24000000UL / (val << 8));
+ if (val < 6) /* The lowest we can do */
+ return 0xFF;
+ else /* Use 180 kHz clock */
+ return (0x80 | (180000UL / (val << 8)));
+}
+
#define BEEP_MASK_FROM_REG(val) (val)
#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff)
#define BEEP_ENABLE_TO_REG(val) ((val)?1:0)
@@ -316,6 +371,7 @@ struct w83627hf_data {
u32 beep_mask; /* Register encoding, combined */
u8 beep_enable; /* Boolean */
u8 pwm[3]; /* Register value */
+ u8 pwm_freq[3]; /* Register value */
u16 sens[3]; /* 782D/783S only.
1 = pentium diode; 2 = 3904 diode;
3000-5000 = thermistor beta.
@@ -852,6 +908,64 @@ sysfs_pwm(2);
sysfs_pwm(3);
static ssize_t
+show_pwm_freq_reg(struct device *dev, char *buf, int nr)
+{
+ struct w83627hf_data *data = w83627hf_update_device(dev);
+ if (data->type == w83627hf)
+ return sprintf(buf, "%ld\n",
+ pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
+ else
+ return sprintf(buf, "%ld\n",
+ pwm_freq_from_reg(data->pwm_freq[nr - 1]));
+}
+
+static ssize_t
+store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
+{
+ struct w83627hf_data *data = dev_get_drvdata(dev);
+ static const u8 mask[]={0xF8, 0x8F};
+ u32 val;
+
+ val = simple_strtoul(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+
+ if (data->type == w83627hf) {
+ data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
+ w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
+ (data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
+ (w83627hf_read_value(data,
+ W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
+ } else {
+ data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
+ w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
+ data->pwm_freq[nr - 1]);
+ }
+
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+#define sysfs_pwm_freq(offset) \
+static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ return show_pwm_freq_reg(dev, buf, offset); \
+} \
+static ssize_t \
+store_regs_pwm_freq_##offset(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+ return store_pwm_freq_reg(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
+ show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
+
+sysfs_pwm_freq(1);
+sysfs_pwm_freq(2);
+sysfs_pwm_freq(3);
+
+static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
struct w83627hf_data *data = w83627hf_update_device(dev);
@@ -1077,6 +1191,9 @@ static struct attribute *w83627hf_attributes_opt[] = {
&dev_attr_pwm3.attr,
+ &dev_attr_pwm1_freq.attr,
+ &dev_attr_pwm2_freq.attr,
+ &dev_attr_pwm3_freq.attr,
NULL
};
@@ -1139,7 +1256,9 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
|| (err = device_create_file(dev, &dev_attr_in5_max))
|| (err = device_create_file(dev, &dev_attr_in6_input))
|| (err = device_create_file(dev, &dev_attr_in6_min))
- || (err = device_create_file(dev, &dev_attr_in6_max)))
+ || (err = device_create_file(dev, &dev_attr_in6_max))
+ || (err = device_create_file(dev, &dev_attr_pwm1_freq))
+ || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
goto ERROR4;
if (data->type != w83697hf)
@@ -1169,6 +1288,12 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
if ((err = device_create_file(dev, &dev_attr_pwm3)))
goto ERROR4;
+ if (data->type == w83637hf || data->type == w83687thf)
+ if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
+ || (err = device_create_file(dev, &dev_attr_pwm2_freq))
+ || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
+ goto ERROR4;
+
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
@@ -1181,6 +1306,7 @@ static int __devinit w83627hf_probe(struct platform_device *pdev)
sysfs_remove_group(&dev->kobj, &w83627hf_group);
sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
ERROR3:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
ERROR1:
release_region(res->start, WINB_REGION_SIZE);
@@ -1193,11 +1319,11 @@ static int __devexit w83627hf_remove(struct platform_device *pdev)
struct w83627hf_data *data = platform_get_drvdata(pdev);
struct resource *res;
- platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
+ platform_set_drvdata(pdev, NULL);
kfree(data);
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1472,6 +1598,20 @@ static struct w83627hf_data *w83627hf_update_device(struct device *dev)
(data->type == w83627hf || data->type == w83697hf))
break;
}
+ if (data->type == w83627hf) {
+ u8 tmp = w83627hf_read_value(data,
+ W83627HF_REG_PWM_FREQ);
+ data->pwm_freq[0] = tmp & 0x07;
+ data->pwm_freq[1] = (tmp >> 4) & 0x07;
+ } else if (data->type != w83627thf) {
+ for (i = 1; i <= 3; i++) {
+ data->pwm_freq[i - 1] =
+ w83627hf_read_value(data,
+ W83637HF_REG_PWM_FREQ[i - 1]);
+ if (i == 2 && (data->type == w83697hf))
+ break;
+ }
+ }
data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
data->temp_max =
@@ -1548,15 +1688,12 @@ static int __init w83627hf_device_add(unsigned short address,
goto exit_device_put;
}
- pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data),
- GFP_KERNEL);
- if (!pdev->dev.platform_data) {
- err = -ENOMEM;
+ err = platform_device_add_data(pdev, sio_data,
+ sizeof(struct w83627hf_sio_data));
+ if (err) {
printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
goto exit_device_put;
}
- memcpy(pdev->dev.platform_data, sio_data,
- sizeof(struct w83627hf_sio_data));
err = platform_device_add(pdev);
if (err) {
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index 58899078810b..014dfa575be7 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -34,10 +34,6 @@ config I2C_ALGOPCA
This support is also available as a module. If so, the module
will be called i2c-algo-pca.
-config I2C_ALGO8XX
- tristate "MPC8xx CPM I2C interface"
- depends on 8xx
-
config I2C_ALGO_SGI
tristate "I2C SGI interfaces"
depends on SGI_IP22 || SGI_IP32 || X86_VISWS
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 838dc1c19d61..da1647869f91 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -207,6 +207,7 @@ config I2C_PIIX4
ATI IXP300
ATI IXP400
ATI SB600
+ ATI SB700
Serverworks OSB4
Serverworks CSB5
Serverworks CSB6
@@ -236,9 +237,6 @@ config I2C_IOP3XX
This driver can also be built as a module. If so, the module
will be called i2c-iop3xx.
-config I2C_ISA
- tristate
-
config I2C_IXP4XX
tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
depends on ARCH_IXP4XX
@@ -390,11 +388,6 @@ config I2C_PROSAVAGE
This support is also available as a module. If so, the module
will be called i2c-prosavage.
-config I2C_RPXLITE
- tristate "Embedded Planet RPX Lite/Classic support"
- depends on RPXLITE || RPXCLASSIC
- select I2C_ALGO8XX
-
config I2C_S3C2410
tristate "S3C2410 I2C Driver"
depends on ARCH_S3C2410
@@ -512,6 +505,22 @@ config I2C_SIS96X
This driver can also be built as a module. If so, the module
will be called i2c-sis96x.
+config I2C_TAOS_EVM
+ tristate "TAOS evaluation module"
+ depends on EXPERIMENTAL
+ select SERIO
+ select SERIO_SERPORT
+ default n
+ help
+ This supports TAOS evaluation modules on serial port. In order to
+ use this driver, you will need the inputattach tool, which is part
+ of the input-utils package.
+
+ If unsure, say N.
+
+ This support is also available as a module. If so, the module
+ will be called i2c-taos-evm.
+
config I2C_STUB
tristate "I2C/SMBus Test Stub"
depends on EXPERIMENTAL && m
@@ -548,7 +557,7 @@ config I2C_VERSATILE
will be called i2c-versatile.
config I2C_ACORN
- bool "Acorn IOC/IOMD I2C bus support"
+ tristate "Acorn IOC/IOMD I2C bus support"
depends on ARCH_ACORN
default y
select I2C_ALGOBIT
@@ -635,4 +644,13 @@ config I2C_PNX
This driver can also be built as a module. If so, the module
will be called i2c-pnx.
+config I2C_PMCMSP
+ tristate "PMC MSP I2C TWI Controller"
+ depends on PMC_MSP
+ help
+ This driver supports the PMC TWI controller on MSP devices.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-pmcmsp.
+
endmenu
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 14d1432f698b..5b752e4e1918 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -18,7 +18,6 @@ obj-$(CONFIG_I2C_I801) += i2c-i801.o
obj-$(CONFIG_I2C_I810) += i2c-i810.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
-obj-$(CONFIG_I2C_ISA) += i2c-isa.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
@@ -32,10 +31,10 @@ obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o
+obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PROSAVAGE) += i2c-prosavage.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
-obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
@@ -44,6 +43,7 @@ obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o
obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o
obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
+obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o
obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
diff --git a/drivers/i2c/busses/i2c-acorn.c b/drivers/i2c/busses/i2c-acorn.c
index 09bd7f40b90c..7c2be3558a24 100644
--- a/drivers/i2c/busses/i2c-acorn.c
+++ b/drivers/i2c/busses/i2c-acorn.c
@@ -94,4 +94,4 @@ static int __init i2c_ioc_init(void)
return i2c_bit_add_bus(&ioc_ops);
}
-__initcall(i2c_ioc_init);
+module_init(i2c_ioc_init);
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index a7dd54654a9a..025f19423faf 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -63,14 +63,14 @@ static void i2c_gpio_setscl_val(void *data, int state)
gpio_set_value(pdata->scl_pin, state);
}
-int i2c_gpio_getsda(void *data)
+static int i2c_gpio_getsda(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
return gpio_get_value(pdata->sda_pin);
}
-int i2c_gpio_getscl(void *data)
+static int i2c_gpio_getscl(void *data)
{
struct i2c_gpio_platform_data *pdata = data;
@@ -142,7 +142,13 @@ static int __init i2c_gpio_probe(struct platform_device *pdev)
adap->algo_data = bit_data;
adap->dev.parent = &pdev->dev;
- ret = i2c_bit_add_bus(adap);
+ /*
+ * If "dev->id" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ adap->nr = pdev->id >= 0 ? pdev->id : 0;
+ ret = i2c_bit_add_numbered_bus(adap);
if (ret)
goto err_add_bus;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 611b57192c96..8f5c686123b8 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -22,12 +22,12 @@
/*
SUPPORTED DEVICES PCI ID
- 82801AA 2413
- 82801AB 2423
- 82801BA 2443
- 82801CA/CAM 2483
- 82801DB 24C3 (HW PEC supported, 32 byte buffer not supported)
- 82801EB 24D3 (HW PEC supported, 32 byte buffer not supported)
+ 82801AA 2413
+ 82801AB 2423
+ 82801BA 2443
+ 82801CA/CAM 2483
+ 82801DB 24C3 (HW PEC supported)
+ 82801EB 24D3 (HW PEC supported)
6300ESB 25A4
ICH6 266A
ICH7 27DA
@@ -74,6 +74,13 @@
#define SMBHSTCFG_SMB_SMI_EN 2
#define SMBHSTCFG_I2C_EN 4
+/* Auxillary control register bits, ICH4+ only */
+#define SMBAUXCTL_CRC 1
+#define SMBAUXCTL_E32B 2
+
+/* kill bit for SMBHSTCNT */
+#define SMBHSTCNT_KILL 2
+
/* Other settings */
#define MAX_TIMEOUT 100
#define ENABLE_INT9 0 /* set to 0x01 to enable - untested */
@@ -91,10 +98,15 @@
#define I801_START 0x40
#define I801_PEC_EN 0x80 /* ICH4 only */
-
-static int i801_transaction(void);
-static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
- int command, int hwpec);
+/* I801 Hosts Status register bits */
+#define SMBHSTSTS_BYTE_DONE 0x80
+#define SMBHSTSTS_INUSE_STS 0x40
+#define SMBHSTSTS_SMBALERT_STS 0x20
+#define SMBHSTSTS_FAILED 0x10
+#define SMBHSTSTS_BUS_ERR 0x08
+#define SMBHSTSTS_DEV_ERR 0x04
+#define SMBHSTSTS_INTR 0x02
+#define SMBHSTSTS_HOST_BUSY 0x01
static unsigned long i801_smba;
static unsigned char i801_original_hstcfg;
@@ -102,7 +114,7 @@ static struct pci_driver i801_driver;
static struct pci_dev *I801_dev;
static int isich4;
-static int i801_transaction(void)
+static int i801_transaction(int xact)
{
int temp;
int result = 0;
@@ -127,33 +139,40 @@ static int i801_transaction(void)
}
}
- outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT);
+ /* the current contents of SMBHSTCNT can be overwritten, since PEC,
+ * INTREN, SMBSCMD are passed in xact */
+ outb_p(xact | I801_START, SMBHSTCNT);
/* We will always wait for a fraction of a second! */
do {
msleep(1);
temp = inb_p(SMBHSTSTS);
- } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
+ } while ((temp & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
result = -1;
+ /* try to stop the current command */
+ dev_dbg(&I801_dev->dev, "Terminating the current operation\n");
+ outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
+ msleep(1);
+ outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT);
}
- if (temp & 0x10) {
+ if (temp & SMBHSTSTS_FAILED) {
result = -1;
dev_dbg(&I801_dev->dev, "Error: Failed bus transaction\n");
}
- if (temp & 0x08) {
+ if (temp & SMBHSTSTS_BUS_ERR) {
result = -1;
dev_err(&I801_dev->dev, "Bus collision! SMBus may be locked "
"until next hard reset. (sorry!)\n");
/* Clock stops and slave is stuck in mid-transmission */
}
- if (temp & 0x04) {
+ if (temp & SMBHSTSTS_DEV_ERR) {
result = -1;
dev_dbg(&I801_dev->dev, "Error: no response!\n");
}
@@ -172,44 +191,70 @@ static int i801_transaction(void)
return result;
}
-/* All-inclusive block transaction function */
-static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
- int command, int hwpec)
+/* wait for INTR bit as advised by Intel */
+static void i801_wait_hwpec(void)
+{
+ int timeout = 0;
+ int temp;
+
+ do {
+ msleep(1);
+ temp = inb_p(SMBHSTSTS);
+ } while ((!(temp & SMBHSTSTS_INTR))
+ && (timeout++ < MAX_TIMEOUT));
+
+ if (timeout >= MAX_TIMEOUT) {
+ dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
+ }
+ outb_p(temp, SMBHSTSTS);
+}
+
+static int i801_block_transaction_by_block(union i2c_smbus_data *data,
+ char read_write, int hwpec)
+{
+ int i, len;
+
+ inb_p(SMBHSTCNT); /* reset the data buffer index */
+
+ /* Use 32-byte buffer to process this transaction */
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ outb_p(len, SMBHSTDAT0);
+ for (i = 0; i < len; i++)
+ outb_p(data->block[i+1], SMBBLKDAT);
+ }
+
+ if (i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 |
+ I801_PEC_EN * hwpec))
+ return -1;
+
+ if (read_write == I2C_SMBUS_READ) {
+ len = inb_p(SMBHSTDAT0);
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+ return -1;
+
+ data->block[0] = len;
+ for (i = 0; i < len; i++)
+ data->block[i + 1] = inb_p(SMBBLKDAT);
+ }
+ return 0;
+}
+
+static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,
+ char read_write, int hwpec)
{
int i, len;
int smbcmd;
int temp;
int result = 0;
int timeout;
- unsigned char hostc, errmask;
+ unsigned char errmask;
- if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
- if (read_write == I2C_SMBUS_WRITE) {
- /* set I2C_EN bit in configuration register */
- pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
- pci_write_config_byte(I801_dev, SMBHSTCFG,
- hostc | SMBHSTCFG_I2C_EN);
- } else {
- dev_err(&I801_dev->dev,
- "I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
- return -1;
- }
- }
+ len = data->block[0];
if (read_write == I2C_SMBUS_WRITE) {
- len = data->block[0];
- if (len < 1)
- len = 1;
- if (len > 32)
- len = 32;
outb_p(len, SMBHSTDAT0);
outb_p(data->block[1], SMBBLKDAT);
- } else {
- len = 32; /* max for reads */
- }
-
- if(isich4 && command != I2C_SMBUS_I2C_BLOCK_DATA) {
- /* set 32 byte buffer */
}
for (i = 1; i <= len; i++) {
@@ -227,13 +272,13 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
/* Make sure the SMBus host is ready to start transmitting */
temp = inb_p(SMBHSTSTS);
if (i == 1) {
- /* Erronenous conditions before transaction:
+ /* Erronenous conditions before transaction:
* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
- errmask=0x9f;
+ errmask = 0x9f;
} else {
- /* Erronenous conditions during transaction:
+ /* Erronenous conditions during transaction:
* Failed, Bus_Err, Dev_Err, Intr */
- errmask=0x1e;
+ errmask = 0x1e;
}
if (temp & errmask) {
dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
@@ -242,14 +287,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
dev_err(&I801_dev->dev,
"Reset failed! (%02x)\n", temp);
- result = -1;
- goto END;
+ return -1;
}
- if (i != 1) {
+ if (i != 1)
/* if die in middle of block transaction, fail */
- result = -1;
- goto END;
- }
+ return -1;
}
if (i == 1)
@@ -261,33 +303,38 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
msleep(1);
temp = inb_p(SMBHSTSTS);
}
- while ((!(temp & 0x80))
- && (timeout++ < MAX_TIMEOUT));
+ while ((!(temp & SMBHSTSTS_BYTE_DONE))
+ && (timeout++ < MAX_TIMEOUT));
/* If the SMBus is still busy, we give up */
if (timeout >= MAX_TIMEOUT) {
+ /* try to stop the current command */
+ dev_dbg(&I801_dev->dev, "Terminating the current "
+ "operation\n");
+ outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT);
+ msleep(1);
+ outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL),
+ SMBHSTCNT);
result = -1;
dev_dbg(&I801_dev->dev, "SMBus Timeout!\n");
}
- if (temp & 0x10) {
+ if (temp & SMBHSTSTS_FAILED) {
result = -1;
dev_dbg(&I801_dev->dev,
"Error: Failed bus transaction\n");
- } else if (temp & 0x08) {
+ } else if (temp & SMBHSTSTS_BUS_ERR) {
result = -1;
dev_err(&I801_dev->dev, "Bus collision!\n");
- } else if (temp & 0x04) {
+ } else if (temp & SMBHSTSTS_DEV_ERR) {
result = -1;
dev_dbg(&I801_dev->dev, "Error: no response!\n");
}
if (i == 1 && read_write == I2C_SMBUS_READ) {
len = inb_p(SMBHSTDAT0);
- if (len < 1)
- len = 1;
- if (len > 32)
- len = 32;
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)
+ return -1;
data->block[0] = len;
}
@@ -310,25 +357,58 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
inb_p(SMBHSTDAT0), inb_p(SMBBLKDAT));
if (result < 0)
- goto END;
+ return result;
}
+ return result;
+}
- if (hwpec) {
- /* wait for INTR bit as advised by Intel */
- timeout = 0;
- do {
- msleep(1);
- temp = inb_p(SMBHSTSTS);
- } while ((!(temp & 0x02))
- && (timeout++ < MAX_TIMEOUT));
+static int i801_set_block_buffer_mode(void)
+{
+ outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL);
+ if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0)
+ return -1;
+ return 0;
+}
- if (timeout >= MAX_TIMEOUT) {
- dev_dbg(&I801_dev->dev, "PEC Timeout!\n");
+/* Block transaction function */
+static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
+ int command, int hwpec)
+{
+ int result = 0;
+ unsigned char hostc;
+
+ if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
+ if (read_write == I2C_SMBUS_WRITE) {
+ /* set I2C_EN bit in configuration register */
+ pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc);
+ pci_write_config_byte(I801_dev, SMBHSTCFG,
+ hostc | SMBHSTCFG_I2C_EN);
+ } else {
+ dev_err(&I801_dev->dev,
+ "I2C_SMBUS_I2C_BLOCK_READ not DB!\n");
+ return -1;
}
- outb_p(temp, SMBHSTSTS);
}
- result = 0;
-END:
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ if (data->block[0] < 1)
+ data->block[0] = 1;
+ if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX;
+ } else {
+ data->block[0] = 32; /* max for reads */
+ }
+
+ if (isich4 && i801_set_block_buffer_mode() == 0 )
+ result = i801_block_transaction_by_block(data, read_write,
+ hwpec);
+ else
+ result = i801_block_transaction_byte_by_byte(data, read_write,
+ hwpec);
+
+ if (result == 0 && hwpec)
+ i801_wait_hwpec();
+
if (command == I2C_SMBUS_I2C_BLOCK_DATA) {
/* restore saved configuration register value */
pci_write_config_byte(I801_dev, SMBHSTCFG, hostc);
@@ -393,19 +473,22 @@ static s32 i801_access(struct i2c_adapter * adap, u16 addr,
return -1;
}
- outb_p(hwpec, SMBAUXCTL); /* enable/disable hardware PEC */
+ if (hwpec) /* enable/disable hardware PEC */
+ outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL);
+ else
+ outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL);
if(block)
ret = i801_block_transaction(data, read_write, size, hwpec);
- else {
- outb_p(xact | ENABLE_INT9, SMBHSTCNT);
- ret = i801_transaction();
- }
+ else
+ ret = i801_transaction(xact | ENABLE_INT9);
/* Some BIOSes don't like it when PEC is enabled at reboot or resume
- time, so we forcibly disable it after every transaction. */
+ time, so we forcibly disable it after every transaction. Turn off
+ E32B for the same reason. */
if (hwpec)
- outb_p(0, SMBAUXCTL);
+ outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B),
+ SMBAUXCTL);
if(block)
return ret;
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 90e2d9350c1b..440342bc62e1 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -491,6 +491,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
new_adapter->id = I2C_HW_IOP3XX;
new_adapter->owner = THIS_MODULE;
new_adapter->dev.parent = &pdev->dev;
+ new_adapter->nr = pdev->id;
/*
* Default values...should these come in from board code?
@@ -508,7 +509,7 @@ iop3xx_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, new_adapter);
new_adapter->algo_data = adapter_data;
- i2c_add_adapter(new_adapter);
+ i2c_add_numbered_adapter(new_adapter);
return 0;
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
deleted file mode 100644
index b0e1370075de..000000000000
--- a/drivers/i2c/busses/i2c-isa.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
- Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
-
- Based on the i2c-isa pseudo-adapter from the lm_sensors project
- Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-/* This implements an i2c-core-like thing for ISA hardware monitoring
- chips. Such chips are linked to the i2c subsystem for historical
- reasons (because the early ISA hardware monitoring chips such as the
- LM78 had both an I2C and an ISA interface). They used to be
- registered with the main i2c-core, but as a first step in the
- direction of a clean separation between I2C and ISA chip drivers,
- we now have this separate core for ISA ones. It is significantly
- more simple than the real one, of course, because we don't have to
- handle multiple busses: there is only one (fake) ISA adapter.
- It is worth noting that we still rely on i2c-core for some things
- at the moment - but hopefully this won't last. */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
-#include <linux/platform_device.h>
-#include <linux/completion.h>
-
-/* Exported by i2c-core for i2c-isa only */
-extern void i2c_adapter_dev_release(struct device *dev);
-extern struct class i2c_adapter_class;
-
-static u32 isa_func(struct i2c_adapter *adapter);
-
-/* This is the actual algorithm we define */
-static const struct i2c_algorithm isa_algorithm = {
- .functionality = isa_func,
-};
-
-/* There can only be one... */
-static struct i2c_adapter isa_adapter = {
- .owner = THIS_MODULE,
- .id = I2C_HW_ISA,
- .class = I2C_CLASS_HWMON,
- .algo = &isa_algorithm,
- .name = "ISA main adapter",
-};
-
-/* We can't do a thing... */
-static u32 isa_func(struct i2c_adapter *adapter)
-{
- return 0;
-}
-
-
-/* We implement an interface which resembles i2c_{add,del}_driver,
- but for i2c-isa drivers. We don't have to remember and handle lists
- of drivers and adapters so this is much more simple, of course. */
-
-int i2c_isa_add_driver(struct i2c_driver *driver)
-{
- int res;
-
- /* Add the driver to the list of i2c drivers in the driver core */
- driver->driver.bus = &i2c_bus_type;
- res = driver_register(&driver->driver);
- if (res)
- return res;
- dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
-
- /* Now look for clients */
- res = driver->attach_adapter(&isa_adapter);
- if (res) {
- dev_dbg(&isa_adapter.dev,
- "Driver %s failed to attach adapter, unregistering\n",
- driver->driver.name);
- driver_unregister(&driver->driver);
- }
- return res;
-}
-
-int i2c_isa_del_driver(struct i2c_driver *driver)
-{
- struct list_head *item, *_n;
- struct i2c_client *client;
- int res;
-
- /* Detach all clients belonging to this one driver */
- list_for_each_safe(item, _n, &isa_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
- if (client->driver != driver)
- continue;
- dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
- client->name, client->addr);
- if ((res = driver->detach_client(client))) {
- dev_err(&isa_adapter.dev, "Failed, driver "
- "%s not unregistered!\n",
- driver->driver.name);
- return res;
- }
- }
-
- /* Get the driver off the core list */
- driver_unregister(&driver->driver);
- dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->driver.name);
-
- return 0;
-}
-
-
-static int __init i2c_isa_init(void)
-{
- int err;
-
- mutex_init(&isa_adapter.clist_lock);
- INIT_LIST_HEAD(&isa_adapter.clients);
-
- isa_adapter.nr = ANY_I2C_ISA_BUS;
- isa_adapter.dev.parent = &platform_bus;
- sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
- isa_adapter.dev.release = &i2c_adapter_dev_release;
- isa_adapter.dev.class = &i2c_adapter_class;
- err = device_register(&isa_adapter.dev);
- if (err) {
- printk(KERN_ERR "i2c-isa: Failed to register device\n");
- goto exit;
- }
-
- dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
-
- return 0;
-
-exit:
- return err;
-}
-
-static void __exit i2c_isa_exit(void)
-{
-#ifdef DEBUG
- struct list_head *item, *_n;
- struct i2c_client *client = NULL;
-#endif
-
- /* There should be no more active client */
-#ifdef DEBUG
- dev_dbg(&isa_adapter.dev, "Looking for clients\n");
- list_for_each_safe(item, _n, &isa_adapter.clients) {
- client = list_entry(item, struct i2c_client, list);
- dev_err(&isa_adapter.dev, "Driver %s still has an active "
- "ISA client at 0x%x\n", client->driver->driver.name,
- client->addr);
- }
- if (client != NULL)
- return;
-#endif
-
- /* Clean up the sysfs representation */
- dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
- init_completion(&isa_adapter.dev_released);
- device_unregister(&isa_adapter.dev);
-
- /* Wait for sysfs to drop all references */
- dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
- wait_for_completion(&isa_adapter.dev_released);
-
- dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
-}
-
-EXPORT_SYMBOL(i2c_isa_add_driver);
-EXPORT_SYMBOL(i2c_isa_del_driver);
-
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("ISA bus access through i2c");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_isa_init);
-module_exit(i2c_isa_exit);
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index c6b6898592b1..851c3ed513d0 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -74,6 +74,25 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
+ * the bus, because it wants to send ACK.
+ * Following sequence of enabling/disabling and sending start/stop generates
+ * the pulse, so it's all OK.
+ */
+static void mpc_i2c_fixup(struct mpc_i2c *i2c)
+{
+ writeccr(i2c, 0);
+ udelay(30);
+ writeccr(i2c, CCR_MEN);
+ udelay(30);
+ writeccr(i2c, CCR_MSTA | CCR_MTX);
+ udelay(30);
+ writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+ udelay(30);
+ writeccr(i2c, CCR_MEN);
+ udelay(30);
+}
+
static int i2c_wait(struct mpc_i2c *i2c, unsigned timeout, int writing)
{
unsigned long orig_jiffies = jiffies;
@@ -153,6 +172,7 @@ static void mpc_i2c_start(struct mpc_i2c *i2c)
static void mpc_i2c_stop(struct mpc_i2c *i2c)
{
writeccr(i2c, CCR_MEN);
+ writeccr(i2c, 0);
}
static int mpc_write(struct mpc_i2c *i2c, int target,
@@ -245,6 +265,9 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
}
if (time_after(jiffies, orig_jiffies + HZ)) {
pr_debug("I2C: timeout\n");
+ if (readb(i2c->base + MPC_I2C_SR) ==
+ (CSR_MCF | CSR_MBB | CSR_RXAK))
+ mpc_i2c_fixup(i2c);
return -EIO;
}
schedule();
@@ -327,9 +350,10 @@ static int fsl_i2c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, i2c);
i2c->adap = mpc_ops;
+ i2c->adap.nr = pdev->id;
i2c_set_adapdata(&i2c->adap, i2c);
i2c->adap.dev.parent = &pdev->dev;
- if ((result = i2c_add_adapter(&i2c->adap)) < 0) {
+ if ((result = i2c_add_numbered_adapter(&i2c->adap)) < 0) {
printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
goto fail_add;
}
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index a55b3335d1be..251154ae5d97 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -527,6 +527,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->adapter.class = I2C_CLASS_HWMON;
drv_data->adapter.timeout = pdata->timeout;
drv_data->adapter.retries = pdata->retries;
+ drv_data->adapter.nr = pd->id;
platform_set_drvdata(pd, drv_data);
i2c_set_adapdata(&drv_data->adapter, drv_data);
@@ -539,7 +540,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
drv_data->irq);
rc = -EINVAL;
goto exit_unmap_regs;
- } else if ((rc = i2c_add_adapter(&drv_data->adapter)) != 0) {
+ } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
dev_err(&drv_data->adapter.dev,
"mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
goto exit_free_irq;
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 3cd0d63e7b50..c48140f782d0 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -61,6 +61,7 @@ struct nforce2_smbus {
struct i2c_adapter adapter;
int base;
int size;
+ int blockops;
};
@@ -80,6 +81,8 @@ struct nforce2_smbus {
#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
+#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data
+ bytes */
#define NVIDIA_SMB_STS_DONE 0x80
#define NVIDIA_SMB_STS_ALRM 0x40
@@ -92,6 +95,7 @@ struct nforce2_smbus {
#define NVIDIA_SMB_PRTCL_BYTE 0x04
#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
+#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
#define NVIDIA_SMB_PRTCL_PEC 0x80
static struct pci_driver nforce2_driver;
@@ -103,6 +107,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
{
struct nforce2_smbus *smbus = adap->algo_data;
unsigned char protocol, pec, temp;
+ u8 len;
+ int i;
protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
NVIDIA_SMB_PRTCL_WRITE;
@@ -137,6 +143,25 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
break;
+ case I2C_SMBUS_BLOCK_DATA:
+ outb_p(command, NVIDIA_SMB_CMD);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = data->block[0];
+ if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
+ dev_err(&adap->dev,
+ "Transaction failed "
+ "(requested block size: %d)\n",
+ len);
+ return -1;
+ }
+ outb_p(len, NVIDIA_SMB_BCNT);
+ for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
+ outb_p(data->block[i + 1],
+ NVIDIA_SMB_DATA+i);
+ }
+ protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
+ break;
+
default:
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
return -1;
@@ -174,6 +199,14 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
case I2C_SMBUS_WORD_DATA:
data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ len = inb_p(NVIDIA_SMB_BCNT);
+ len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
+ for (i = 0; i < len; i++)
+ data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
+ data->block[0] = len;
+ break;
}
return 0;
@@ -184,7 +217,9 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
{
/* other functionality might be possible, but is not tested */
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ (((struct nforce2_smbus*)adapter->algo_data)->blockops ?
+ I2C_FUNC_SMBUS_BLOCK_DATA : 0);
}
static struct i2c_algorithm smbus_algorithm = {
@@ -268,6 +303,13 @@ static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_
return -ENOMEM;
pci_set_drvdata(dev, smbuses);
+ switch(dev->device) {
+ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
+ case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
+ smbuses[0].blockops = 1;
+ smbuses[1].blockops = 1;
+ }
+
/* SMBus adapter 1 */
res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
if (res1 < 0) {
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 5a52bf5e3fb0..debc76cd2161 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -23,7 +23,7 @@
Supports:
Intel PIIX4, 440MX
Serverworks OSB4, CSB5, CSB6, HT-1000
- ATI IXP200, IXP300, IXP400, SB600
+ ATI IXP200, IXP300, IXP400, SB600, SB700
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
@@ -399,6 +399,8 @@ static struct pci_device_id piix4_ids[] = {
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS),
.driver_data = 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS),
+ .driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5),
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
new file mode 100644
index 000000000000..17cecf1ea797
--- /dev/null
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -0,0 +1,653 @@
+/*
+ * Specific bus support for PMC-TWI compliant implementation on MSP71xx.
+ *
+ * Copyright 2005-2007 PMC-Sierra, 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#define DRV_NAME "pmcmsptwi"
+
+#define MSP_TWI_SF_CLK_REG_OFFSET 0x00
+#define MSP_TWI_HS_CLK_REG_OFFSET 0x04
+#define MSP_TWI_CFG_REG_OFFSET 0x08
+#define MSP_TWI_CMD_REG_OFFSET 0x0c
+#define MSP_TWI_ADD_REG_OFFSET 0x10
+#define MSP_TWI_DAT_0_REG_OFFSET 0x14
+#define MSP_TWI_DAT_1_REG_OFFSET 0x18
+#define MSP_TWI_INT_STS_REG_OFFSET 0x1c
+#define MSP_TWI_INT_MSK_REG_OFFSET 0x20
+#define MSP_TWI_BUSY_REG_OFFSET 0x24
+
+#define MSP_TWI_INT_STS_DONE (1 << 0)
+#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1)
+#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2)
+#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3)
+#define MSP_TWI_INT_STS_BUSY (1 << 4)
+#define MSP_TWI_INT_STS_ALL 0x1f
+
+#define MSP_MAX_BYTES_PER_RW 8
+#define MSP_MAX_POLL 5
+#define MSP_POLL_DELAY 10
+#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY)
+
+/* IO Operation macros */
+#define pmcmsptwi_readl __raw_readl
+#define pmcmsptwi_writel __raw_writel
+
+/* TWI command type */
+enum pmcmsptwi_cmd_type {
+ MSP_TWI_CMD_WRITE = 0, /* Write only */
+ MSP_TWI_CMD_READ = 1, /* Read only */
+ MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */
+};
+
+/* The possible results of the xferCmd */
+enum pmcmsptwi_xfer_result {
+ MSP_TWI_XFER_OK = 0,
+ MSP_TWI_XFER_TIMEOUT,
+ MSP_TWI_XFER_BUSY,
+ MSP_TWI_XFER_DATA_COLLISION,
+ MSP_TWI_XFER_NO_RESPONSE,
+ MSP_TWI_XFER_LOST_ARBITRATION,
+};
+
+/* Corresponds to a PMCTWI clock configuration register */
+struct pmcmsptwi_clock {
+ u8 filter; /* Bits 15:12, default = 0x03 */
+ u16 clock; /* Bits 9:0, default = 0x001f */
+};
+
+struct pmcmsptwi_clockcfg {
+ struct pmcmsptwi_clock standard; /* The standard/fast clock config */
+ struct pmcmsptwi_clock highspeed; /* The highspeed clock config */
+};
+
+/* Corresponds to the main TWI configuration register */
+struct pmcmsptwi_cfg {
+ u8 arbf; /* Bits 15:12, default=0x03 */
+ u8 nak; /* Bits 11:8, default=0x03 */
+ u8 add10; /* Bit 7, default=0x00 */
+ u8 mst_code; /* Bits 6:4, default=0x00 */
+ u8 arb; /* Bit 1, default=0x01 */
+ u8 highspeed; /* Bit 0, default=0x00 */
+};
+
+/* A single pmctwi command to issue */
+struct pmcmsptwi_cmd {
+ u16 addr; /* The slave address (7 or 10 bits) */
+ enum pmcmsptwi_cmd_type type; /* The command type */
+ u8 write_len; /* Number of bytes in the write buffer */
+ u8 read_len; /* Number of bytes in the read buffer */
+ u8 *write_data; /* Buffer of characters to send */
+ u8 *read_data; /* Buffer to fill with incoming data */
+};
+
+/* The private data */
+struct pmcmsptwi_data {
+ void __iomem *iobase; /* iomapped base for IO */
+ int irq; /* IRQ to use (0 disables) */
+ struct completion wait; /* Completion for xfer */
+ struct mutex lock; /* Used for threadsafeness */
+ enum pmcmsptwi_xfer_result last_result; /* result of last xfer */
+};
+
+/* The default settings */
+const static struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = {
+ .standard = {
+ .filter = 0x3,
+ .clock = 0x1f,
+ },
+ .highspeed = {
+ .filter = 0x3,
+ .clock = 0x1f,
+ },
+};
+
+const static struct pmcmsptwi_cfg pmcmsptwi_defcfg = {
+ .arbf = 0x03,
+ .nak = 0x03,
+ .add10 = 0x00,
+ .mst_code = 0x00,
+ .arb = 0x01,
+ .highspeed = 0x00,
+};
+
+static struct pmcmsptwi_data pmcmsptwi_data;
+
+static struct i2c_adapter pmcmsptwi_adapter;
+
+/* inline helper functions */
+static inline u32 pmcmsptwi_clock_to_reg(
+ const struct pmcmsptwi_clock *clock)
+{
+ return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
+}
+
+static inline void pmcmsptwi_reg_to_clock(
+ u32 reg, struct pmcmsptwi_clock *clock)
+{
+ clock->filter = (reg >> 12) & 0xf;
+ clock->clock = reg & 0x03ff;
+}
+
+static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
+{
+ return ((cfg->arbf & 0xf) << 12) |
+ ((cfg->nak & 0xf) << 8) |
+ ((cfg->add10 & 0x1) << 7) |
+ ((cfg->mst_code & 0x7) << 4) |
+ ((cfg->arb & 0x1) << 1) |
+ (cfg->highspeed & 0x1);
+}
+
+static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg)
+{
+ cfg->arbf = (reg >> 12) & 0xf;
+ cfg->nak = (reg >> 8) & 0xf;
+ cfg->add10 = (reg >> 7) & 0x1;
+ cfg->mst_code = (reg >> 4) & 0x7;
+ cfg->arb = (reg >> 1) & 0x1;
+ cfg->highspeed = reg & 0x1;
+}
+
+/*
+ * Sets the current clock configuration
+ */
+static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard),
+ data->iobase + MSP_TWI_SF_CLK_REG_OFFSET);
+ pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed),
+ data->iobase + MSP_TWI_HS_CLK_REG_OFFSET);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Gets the current TWI bus configuration
+ */
+static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_reg_to_cfg(pmcmsptwi_readl(
+ data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Sets the current TWI bus configuration
+ */
+static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg,
+ struct pmcmsptwi_data *data)
+{
+ mutex_lock(&data->lock);
+ pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg),
+ data->iobase + MSP_TWI_CFG_REG_OFFSET);
+ mutex_unlock(&data->lock);
+}
+
+/*
+ * Parses the 'int_sts' register and returns a well-defined error code
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg)
+{
+ if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Lost arbitration\n");
+ return MSP_TWI_XFER_LOST_ARBITRATION;
+ } else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: No response\n");
+ return MSP_TWI_XFER_NO_RESPONSE;
+ } else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Data collision\n");
+ return MSP_TWI_XFER_DATA_COLLISION;
+ } else if (reg & MSP_TWI_INT_STS_BUSY) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: Bus busy\n");
+ return MSP_TWI_XFER_BUSY;
+ }
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n");
+ return MSP_TWI_XFER_OK;
+}
+
+/*
+ * In interrupt mode, handle the interrupt.
+ * NOTE: Assumes data->lock is held.
+ */
+static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr)
+{
+ struct pmcmsptwi_data *data = ptr;
+
+ u32 reason = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET);
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason);
+ if (!(reason & MSP_TWI_INT_STS_DONE))
+ return IRQ_NONE;
+
+ data->last_result = pmcmsptwi_get_result(reason);
+ complete(&data->wait);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Probe for and register the device and return 0 if there is one.
+ */
+static int __devinit pmcmsptwi_probe(struct platform_device *pldev)
+{
+ struct resource *res;
+ int rc = -ENODEV;
+
+ /* get the static platform resources */
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pldev->dev, "IOMEM resource not found\n");
+ goto ret_err;
+ }
+
+ /* reserve the memory region */
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pldev->name)) {
+ dev_err(&pldev->dev,
+ "Unable to get memory/io address region 0x%08x\n",
+ res->start);
+ rc = -EBUSY;
+ goto ret_err;
+ }
+
+ /* remap the memory */
+ pmcmsptwi_data.iobase = ioremap_nocache(res->start,
+ res->end - res->start + 1);
+ if (!pmcmsptwi_data.iobase) {
+ dev_err(&pldev->dev,
+ "Unable to ioremap address 0x%08x\n", res->start);
+ rc = -EIO;
+ goto ret_unreserve;
+ }
+
+ /* request the irq */
+ pmcmsptwi_data.irq = platform_get_irq(pldev, 0);
+ if (pmcmsptwi_data.irq) {
+ rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt,
+ IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
+ pldev->name, &pmcmsptwi_data);
+ if (rc == 0) {
+ /*
+ * Enable 'DONE' interrupt only.
+ *
+ * If you enable all interrupts, you will get one on
+ * error and another when the operation completes.
+ * This way you only have to handle one interrupt,
+ * but you can still check all result flags.
+ */
+ pmcmsptwi_writel(MSP_TWI_INT_STS_DONE,
+ pmcmsptwi_data.iobase +
+ MSP_TWI_INT_MSK_REG_OFFSET);
+ } else {
+ dev_warn(&pldev->dev,
+ "Could not assign TWI IRQ handler "
+ "to irq %d (continuing with poll)\n",
+ pmcmsptwi_data.irq);
+ pmcmsptwi_data.irq = 0;
+ }
+ }
+
+ init_completion(&pmcmsptwi_data.wait);
+ mutex_init(&pmcmsptwi_data.lock);
+
+ pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data);
+ pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data);
+
+ printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n");
+
+ pmcmsptwi_adapter.dev.parent = &pldev->dev;
+ platform_set_drvdata(pldev, &pmcmsptwi_adapter);
+ i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data);
+
+ rc = i2c_add_adapter(&pmcmsptwi_adapter);
+ if (rc) {
+ dev_err(&pldev->dev, "Unable to register I2C adapter\n");
+ goto ret_unmap;
+ }
+
+ return 0;
+
+ret_unmap:
+ platform_set_drvdata(pldev, NULL);
+ if (pmcmsptwi_data.irq) {
+ pmcmsptwi_writel(0,
+ pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+ free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+ }
+
+ iounmap(pmcmsptwi_data.iobase);
+
+ret_unreserve:
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ret_err:
+ return rc;
+}
+
+/*
+ * Release the device and return 0 if there is one.
+ */
+static int __devexit pmcmsptwi_remove(struct platform_device *pldev)
+{
+ struct resource *res;
+
+ i2c_del_adapter(&pmcmsptwi_adapter);
+
+ platform_set_drvdata(pldev, NULL);
+ if (pmcmsptwi_data.irq) {
+ pmcmsptwi_writel(0,
+ pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET);
+ free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data);
+ }
+
+ iounmap(pmcmsptwi_data.iobase);
+
+ res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ return 0;
+}
+
+/*
+ * Polls the 'busy' register until the command is complete.
+ * NOTE: Assumes data->lock is held.
+ */
+static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data)
+{
+ int i;
+
+ for (i = 0; i < MSP_MAX_POLL; i++) {
+ u32 val = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_BUSY_REG_OFFSET);
+ if (val == 0) {
+ u32 reason = pmcmsptwi_readl(data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ pmcmsptwi_writel(reason, data->iobase +
+ MSP_TWI_INT_STS_REG_OFFSET);
+ data->last_result = pmcmsptwi_get_result(reason);
+ return;
+ }
+ udelay(MSP_POLL_DELAY);
+ }
+
+ dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n");
+ data->last_result = MSP_TWI_XFER_TIMEOUT;
+}
+
+/*
+ * Do the transfer (low level):
+ * May use interrupt-driven or polling, depending on if an IRQ is
+ * presently registered.
+ * NOTE: Assumes data->lock is held.
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer(
+ u32 reg, struct pmcmsptwi_data *data)
+{
+ dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg);
+ pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET);
+ if (data->irq) {
+ unsigned long timeleft = wait_for_completion_timeout(
+ &data->wait, MSP_IRQ_TIMEOUT);
+ if (timeleft == 0) {
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Result: IRQ timeout\n");
+ complete(&data->wait);
+ data->last_result = MSP_TWI_XFER_TIMEOUT;
+ }
+ } else
+ pmcmsptwi_poll_complete(data);
+
+ return data->last_result;
+}
+
+/*
+ * Helper routine, converts 'pmctwi_cmd' struct to register format
+ */
+static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd)
+{
+ return ((cmd->type & 0x3) << 8) |
+ (((cmd->write_len - 1) & 0x7) << 4) |
+ ((cmd->read_len - 1) & 0x7);
+}
+
+/*
+ * Do the transfer (high level)
+ */
+static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
+ struct pmcmsptwi_cmd *cmd,
+ struct pmcmsptwi_data *data)
+{
+ enum pmcmsptwi_xfer_result retval;
+
+ if ((cmd->type == MSP_TWI_CMD_WRITE && cmd->write_len == 0) ||
+ (cmd->type == MSP_TWI_CMD_READ && cmd->read_len == 0) ||
+ (cmd->type == MSP_TWI_CMD_WRITE_READ &&
+ (cmd->read_len == 0 || cmd->write_len == 0))) {
+ dev_err(&pmcmsptwi_adapter.dev,
+ "%s: Cannot transfer less than 1 byte\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
+ cmd->write_len > MSP_MAX_BYTES_PER_RW) {
+ dev_err(&pmcmsptwi_adapter.dev,
+ "%s: Cannot transfer more than %d bytes\n",
+ __FUNCTION__, MSP_MAX_BYTES_PER_RW);
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->lock);
+ dev_dbg(&pmcmsptwi_adapter.dev,
+ "Setting address to 0x%04x\n", cmd->addr);
+ pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET);
+
+ if (cmd->type == MSP_TWI_CMD_WRITE ||
+ cmd->type == MSP_TWI_CMD_WRITE_READ) {
+ __be64 tmp = cpu_to_be64p((u64 *)cmd->write_data);
+ tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8;
+ dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp);
+ pmcmsptwi_writel(tmp & 0x00000000ffffffffLL,
+ data->iobase + MSP_TWI_DAT_0_REG_OFFSET);
+ if (cmd->write_len > 4)
+ pmcmsptwi_writel(tmp >> 32,
+ data->iobase + MSP_TWI_DAT_1_REG_OFFSET);
+ }
+
+ retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data);
+ if (retval != MSP_TWI_XFER_OK)
+ goto xfer_err;
+
+ if (cmd->type == MSP_TWI_CMD_READ ||
+ cmd->type == MSP_TWI_CMD_WRITE_READ) {
+ int i;
+ u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8));
+ u64 tmp = (u64)pmcmsptwi_readl(data->iobase +
+ MSP_TWI_DAT_0_REG_OFFSET);
+ if (cmd->read_len > 4)
+ tmp |= (u64)pmcmsptwi_readl(data->iobase +
+ MSP_TWI_DAT_1_REG_OFFSET) << 32;
+ tmp &= rmsk;
+ dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp);
+
+ for (i = 0; i < cmd->read_len; i++)
+ cmd->read_data[i] = tmp >> i;
+ }
+
+xfer_err:
+ mutex_unlock(&data->lock);
+
+ return retval;
+}
+
+/* -- Algorithm functions -- */
+
+/*
+ * Sends an i2c command out on the adapter
+ */
+static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int num)
+{
+ struct pmcmsptwi_data *data = i2c_get_adapdata(adap);
+ struct pmcmsptwi_cmd cmd;
+ struct pmcmsptwi_cfg oldcfg, newcfg;
+ int ret;
+
+ if (num > 2) {
+ dev_dbg(&adap->dev, "%d messages unsupported\n", num);
+ return -EINVAL;
+ } else if (num == 2) {
+ /* Check for a dual write-then-read command */
+ struct i2c_msg *nextmsg = msg + 1;
+ if (!(msg->flags & I2C_M_RD) &&
+ (nextmsg->flags & I2C_M_RD) &&
+ msg->addr == nextmsg->addr) {
+ cmd.type = MSP_TWI_CMD_WRITE_READ;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ cmd.read_len = nextmsg->len;
+ cmd.read_data = nextmsg->buf;
+ } else {
+ dev_dbg(&adap->dev,
+ "Non write-read dual messages unsupported\n");
+ return -EINVAL;
+ }
+ } else if (msg->flags & I2C_M_RD) {
+ cmd.type = MSP_TWI_CMD_READ;
+ cmd.read_len = msg->len;
+ cmd.read_data = msg->buf;
+ cmd.write_len = 0;
+ cmd.write_data = NULL;
+ } else {
+ cmd.type = MSP_TWI_CMD_WRITE;
+ cmd.read_len = 0;
+ cmd.read_data = NULL;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ }
+
+ if (msg->len == 0) {
+ dev_err(&adap->dev, "Zero-byte messages unsupported\n");
+ return -EINVAL;
+ }
+
+ cmd.addr = msg->addr;
+
+ if (msg->flags & I2C_M_TEN) {
+ pmcmsptwi_get_twi_config(&newcfg, data);
+ memcpy(&oldcfg, &newcfg, sizeof(oldcfg));
+
+ /* Set the special 10-bit address flag */
+ newcfg.add10 = 1;
+
+ pmcmsptwi_set_twi_config(&newcfg, data);
+ }
+
+ /* Execute the command */
+ ret = pmcmsptwi_xfer_cmd(&cmd, data);
+
+ if (msg->flags & I2C_M_TEN)
+ pmcmsptwi_set_twi_config(&oldcfg, data);
+
+ dev_dbg(&adap->dev, "I2C %s of %d bytes ",
+ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len);
+ if (ret != MSP_TWI_XFER_OK) {
+ /*
+ * TODO: We could potentially loop and retry in the case
+ * of MSP_TWI_XFER_TIMEOUT.
+ */
+ dev_dbg(&adap->dev, "failed\n");
+ return -1;
+ }
+
+ dev_dbg(&adap->dev, "succeeded\n");
+ return 0;
+}
+
+static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+/* -- Initialization -- */
+
+static struct i2c_algorithm pmcmsptwi_algo = {
+ .master_xfer = pmcmsptwi_master_xfer,
+ .functionality = pmcmsptwi_i2c_func,
+};
+
+static struct i2c_adapter pmcmsptwi_adapter = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_HWMON,
+ .algo = &pmcmsptwi_algo,
+ .name = DRV_NAME,
+};
+
+static struct platform_driver pmcmsptwi_driver = {
+ .probe = pmcmsptwi_probe,
+ .remove = __devexit_p(pmcmsptwi_remove),
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pmcmsptwi_init(void)
+{
+ return platform_driver_register(&pmcmsptwi_driver);
+}
+
+static void __exit pmcmsptwi_exit(void)
+{
+ platform_driver_unregister(&pmcmsptwi_driver);
+}
+
+MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver");
+MODULE_LICENSE("GPL");
+
+module_init(pmcmsptwi_init);
+module_exit(pmcmsptwi_exit);
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 1425d2245c82..0ab4f2627c26 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -121,8 +121,7 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap,
if (rc)
goto bail;
rc = pmac_i2c_xfer(bus, addrdir, 1, command,
- read ? data->block : &data->block[1],
- data->block[0]);
+ &data->block[1], data->block[0]);
break;
default:
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 28e7b91a4553..9d6b790d4321 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -921,7 +921,14 @@ static int i2c_pxa_probe(struct platform_device *dev)
i2c->adap.class = plat->class;
}
- ret = i2c_add_adapter(&i2c->adap);
+ /*
+ * If "dev->id" is negative we consider it as zero.
+ * The reason to do so is to avoid sysfs names that only make
+ * sense when there are multiple adapters.
+ */
+ i2c->adap.nr = dev->id >= 0 ? dev->id : 0;
+
+ ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret < 0) {
printk(KERN_INFO "I2C: Failed to add bus\n");
goto eadapt;
diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c
deleted file mode 100644
index 8764df06f51d..000000000000
--- a/drivers/i2c/busses/i2c-rpx.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Embedded Planet RPX Lite MPC8xx CPM I2C interface.
- * Copyright (c) 1999 Dan Malek (dmalek@jlc.net).
- *
- * moved into proper i2c interface;
- * Brad Parker (brad@heeltoe.com)
- *
- * RPX lite specific parts of the i2c interface
- * Update: There actually isn't anything RPXLite-specific about this module.
- * This should work for most any 8xx board. The console messages have been
- * changed to eliminate RPXLite references.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/stddef.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-8xx.h>
-#include <asm/mpc8xx.h>
-#include <asm/commproc.h>
-
-
-static void
-rpx_iic_init(struct i2c_algo_8xx_data *data)
-{
- volatile cpm8xx_t *cp;
- volatile immap_t *immap;
-
- cp = cpmp; /* Get pointer to Communication Processor */
- immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
-
- data->iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
-
- /* Check for and use a microcode relocation patch.
- */
- if ((data->reloc = data->iip->iic_rpbase))
- data->iip = (iic_t *)&cp->cp_dpmem[data->iip->iic_rpbase];
-
- data->i2c = (i2c8xx_t *)&(immap->im_i2c);
- data->cp = cp;
-
- /* Initialize Port B IIC pins.
- */
- cp->cp_pbpar |= 0x00000030;
- cp->cp_pbdir |= 0x00000030;
- cp->cp_pbodr |= 0x00000030;
-
- /* Allocate space for two transmit and two receive buffer
- * descriptors in the DP ram.
- */
- data->dp_addr = cpm_dpalloc(sizeof(cbd_t) * 4, 8);
-
- /* ptr to i2c area */
- data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
-}
-
-static int rpx_install_isr(int irq, void (*func)(void *), void *data)
-{
- /* install interrupt handler */
- cpm_install_handler(irq, func, data);
-
- return 0;
-}
-
-static struct i2c_algo_8xx_data rpx_data = {
- .setisr = rpx_install_isr
-};
-
-static struct i2c_adapter rpx_ops = {
- .owner = THIS_MODULE,
- .name = "m8xx",
- .id = I2C_HW_MPC8XX_EPON,
- .algo_data = &rpx_data,
-};
-
-int __init i2c_rpx_init(void)
-{
- printk(KERN_INFO "i2c-rpx: i2c MPC8xx driver\n");
-
- /* reset hardware to sane state */
- rpx_iic_init(&rpx_data);
-
- if (i2c_8xx_add_bus(&rpx_ops) < 0) {
- printk(KERN_ERR "i2c-rpx: Unable to register with I2C\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-void __exit i2c_rpx_exit(void)
-{
- i2c_8xx_del_bus(&rpx_ops);
-}
-
-MODULE_AUTHOR("Dan Malek <dmalek@jlc.net>");
-MODULE_DESCRIPTION("I2C-Bus adapter routines for MPC8xx boards");
-
-module_init(i2c_rpx_init);
-module_exit(i2c_rpx_exit);
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
index b7fb65c30112..8adf4abaa035 100644
--- a/drivers/i2c/busses/i2c-savage4.c
+++ b/drivers/i2c/busses/i2c-savage4.c
@@ -25,8 +25,6 @@
/* This interfaces to the I2C bus of the Savage4 to gain access to
the BT869 and possibly other I2C devices. The DDC bus is not
yet supported because its register is not memory-mapped.
- However we leave the DDC code here, commented out, to make
- it easier to add later.
*/
#include <linux/kernel.h>
@@ -37,36 +35,19 @@
#include <linux/i2c-algo-bit.h>
#include <asm/io.h>
-/* 3DFX defines */
-#define PCI_CHIP_SAVAGE3D 0x8A20
-#define PCI_CHIP_SAVAGE3D_MV 0x8A21
+/* device IDs */
#define PCI_CHIP_SAVAGE4 0x8A22
#define PCI_CHIP_SAVAGE2000 0x9102
-#define PCI_CHIP_PROSAVAGE_PM 0x8A25
-#define PCI_CHIP_PROSAVAGE_KM 0x8A26
-#define PCI_CHIP_SAVAGE_MX_MV 0x8c10
-#define PCI_CHIP_SAVAGE_MX 0x8c11
-#define PCI_CHIP_SAVAGE_IX_MV 0x8c12
-#define PCI_CHIP_SAVAGE_IX 0x8c13
#define REG 0xff20 /* Serial Port 1 Register */
/* bit locations in the register */
-#define DDC_ENAB 0x00040000
-#define DDC_SCL_OUT 0x00080000
-#define DDC_SDA_OUT 0x00100000
-#define DDC_SCL_IN 0x00200000
-#define DDC_SDA_IN 0x00400000
#define I2C_ENAB 0x00000020
#define I2C_SCL_OUT 0x00000001
#define I2C_SDA_OUT 0x00000002
#define I2C_SCL_IN 0x00000008
#define I2C_SDA_IN 0x00000010
-/* initialization states */
-#define INIT2 0x20
-#define INIT3 0x04
-
/* delays */
#define CYCLE_DELAY 10
#define TIMEOUT (HZ / 2)
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index a6feed449dbe..283769cecee2 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -129,6 +129,7 @@ MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller"
static struct pci_driver sis5595_driver;
static unsigned short sis5595_base;
+static struct pci_dev *sis5595_pdev;
static u8 sis5595_read(u8 reg)
{
@@ -379,6 +380,8 @@ MODULE_DEVICE_TABLE (pci, sis5595_ids);
static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
+ int err;
+
if (sis5595_setup(dev)) {
dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n");
return -ENODEV;
@@ -389,20 +392,24 @@ static int __devinit sis5595_probe(struct pci_dev *dev, const struct pci_device_
sprintf(sis5595_adapter.name, "SMBus SIS5595 adapter at %04x",
sis5595_base + SMB_INDEX);
- return i2c_add_adapter(&sis5595_adapter);
-}
+ err = i2c_add_adapter(&sis5595_adapter);
+ if (err) {
+ release_region(sis5595_base + SMB_INDEX, 2);
+ return err;
+ }
-static void __devexit sis5595_remove(struct pci_dev *dev)
-{
- i2c_del_adapter(&sis5595_adapter);
- release_region(sis5595_base + SMB_INDEX, 2);
+ /* Always return failure here. This is to allow other drivers to bind
+ * to this pci device. We don't really want to have control over the
+ * pci device, we only wanted to read as few register values from it.
+ */
+ sis5595_pdev = pci_dev_get(dev);
+ return -ENODEV;
}
static struct pci_driver sis5595_driver = {
.name = "sis5595_smbus",
.id_table = sis5595_ids,
.probe = sis5595_probe,
- .remove = __devexit_p(sis5595_remove),
};
static int __init i2c_sis5595_init(void)
@@ -413,6 +420,12 @@ static int __init i2c_sis5595_init(void)
static void __exit i2c_sis5595_exit(void)
{
pci_unregister_driver(&sis5595_driver);
+ if (sis5595_pdev) {
+ i2c_del_adapter(&sis5595_adapter);
+ release_region(sis5595_base + SMB_INDEX, 2);
+ pci_dev_put(sis5595_pdev);
+ sis5595_pdev = NULL;
+ }
}
MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
new file mode 100644
index 000000000000..1b0cfd5472fd
--- /dev/null
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -0,0 +1,330 @@
+/*
+ * Driver for the TAOS evaluation modules
+ * These devices include an I2C master which can be controlled over the
+ * serial port.
+ *
+ * Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+#define TAOS_BUFFER_SIZE 63
+
+#define TAOS_STATE_INIT 0
+#define TAOS_STATE_IDLE 1
+#define TAOS_STATE_SEND 2
+#define TAOS_STATE_RECV 3
+
+#define TAOS_CMD_RESET 0x12
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+struct taos_data {
+ struct i2c_adapter adapter;
+ struct i2c_client *client;
+ int state;
+ u8 addr; /* last used address */
+ unsigned char buffer[TAOS_BUFFER_SIZE];
+ unsigned int pos; /* position inside the buffer */
+};
+
+/* TAOS TSL2550 EVM */
+static struct i2c_board_info tsl2550_info = {
+ I2C_BOARD_INFO("tsl2550", 0x39),
+ .type = "tsl2550",
+};
+
+/* Instantiate i2c devices based on the adapter name */
+static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter)
+{
+ if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
+ dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
+ tsl2550_info.driver_name, tsl2550_info.addr);
+ return i2c_new_device(adapter, &tsl2550_info);
+ }
+
+ return NULL;
+}
+
+static int taos_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
+ unsigned short flags, char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct serio *serio = adapter->algo_data;
+ struct taos_data *taos = serio_get_drvdata(serio);
+ char *p;
+
+ /* Encode our transaction. "@" is for the device address, "$" for the
+ SMBus command and "#" for the data. */
+ p = taos->buffer;
+
+ /* The device remembers the last used address, no need to send it
+ again if it's the same */
+ if (addr != taos->addr)
+ p += sprintf(p, "@%02X", addr);
+
+ switch (size) {
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE)
+ sprintf(p, "$#%02X", command);
+ else
+ sprintf(p, "$");
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ if (read_write == I2C_SMBUS_WRITE)
+ sprintf(p, "$%02X#%02X", command, data->byte);
+ else
+ sprintf(p, "$%02X", command);
+ break;
+ default:
+ dev_dbg(&adapter->dev, "Unsupported transaction size %d\n",
+ size);
+ return -EINVAL;
+ }
+
+ /* Send the transaction to the TAOS EVM */
+ dev_dbg(&adapter->dev, "Command buffer: %s\n", taos->buffer);
+ taos->pos = 0;
+ taos->state = TAOS_STATE_SEND;
+ serio_write(serio, taos->buffer[0]);
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(250));
+ if (taos->state != TAOS_STATE_IDLE) {
+ dev_err(&adapter->dev, "Transaction failed "
+ "(state=%d, pos=%d)\n", taos->state, taos->pos);
+ taos->addr = 0;
+ return -EIO;
+ }
+ taos->addr = addr;
+
+ /* Start the transaction and read the answer */
+ taos->pos = 0;
+ taos->state = TAOS_STATE_RECV;
+ serio_write(serio, read_write == I2C_SMBUS_WRITE ? '>' : '<');
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(150));
+ if (taos->state != TAOS_STATE_IDLE
+ || taos->pos != 6) {
+ dev_err(&adapter->dev, "Transaction timeout (pos=%d)\n",
+ taos->pos);
+ return -EIO;
+ }
+ dev_dbg(&adapter->dev, "Answer buffer: %s\n", taos->buffer);
+
+ /* Interpret the returned string */
+ p = taos->buffer + 2;
+ p[3] = '\0';
+ if (!strcmp(p, "NAK"))
+ return -ENODEV;
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ if (!strcmp(p, "ACK"))
+ return 0;
+ } else {
+ if (p[0] == 'x') {
+ data->byte = simple_strtol(p + 1, NULL, 16);
+ return 0;
+ }
+ }
+
+ return -EIO;
+}
+
+static u32 taos_smbus_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static const struct i2c_algorithm taos_algorithm = {
+ .smbus_xfer = taos_smbus_xfer,
+ .functionality = taos_smbus_func,
+};
+
+static irqreturn_t taos_interrupt(struct serio *serio, unsigned char data,
+ unsigned int flags)
+{
+ struct taos_data *taos = serio_get_drvdata(serio);
+
+ switch (taos->state) {
+ case TAOS_STATE_INIT:
+ taos->buffer[taos->pos++] = data;
+ if (data == ':'
+ || taos->pos == TAOS_BUFFER_SIZE - 1) {
+ taos->buffer[taos->pos] = '\0';
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ }
+ break;
+ case TAOS_STATE_SEND:
+ if (taos->buffer[++taos->pos])
+ serio_write(serio, taos->buffer[taos->pos]);
+ else {
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ }
+ break;
+ case TAOS_STATE_RECV:
+ taos->buffer[taos->pos++] = data;
+ if (data == ']') {
+ taos->buffer[taos->pos] = '\0';
+ taos->state = TAOS_STATE_IDLE;
+ wake_up_interruptible(&wq);
+ }
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Extract the adapter name from the buffer received after reset.
+ The buffer is modified and a pointer inside the buffer is returned. */
+static char *taos_adapter_name(char *buffer)
+{
+ char *start, *end;
+
+ start = strstr(buffer, "TAOS ");
+ if (!start)
+ return NULL;
+
+ end = strchr(start, '\r');
+ if (!end)
+ return NULL;
+ *end = '\0';
+
+ return start;
+}
+
+static int taos_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct taos_data *taos;
+ struct i2c_adapter *adapter;
+ char *name;
+ int err;
+
+ taos = kzalloc(sizeof(struct taos_data), GFP_KERNEL);
+ if (!taos) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ taos->state = TAOS_STATE_INIT;
+ serio_set_drvdata(serio, taos);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto exit_kfree;
+
+ adapter = &taos->adapter;
+ adapter->owner = THIS_MODULE;
+ adapter->algo = &taos_algorithm;
+ adapter->algo_data = serio;
+ adapter->dev.parent = &serio->dev;
+
+ /* Reset the TAOS evaluation module to identify it */
+ serio_write(serio, TAOS_CMD_RESET);
+ wait_event_interruptible_timeout(wq, taos->state == TAOS_STATE_IDLE,
+ msecs_to_jiffies(2000));
+
+ if (taos->state != TAOS_STATE_IDLE) {
+ err = -ENODEV;
+ dev_dbg(&serio->dev, "TAOS EVM reset failed (state=%d, "
+ "pos=%d)\n", taos->state, taos->pos);
+ goto exit_close;
+ }
+
+ name = taos_adapter_name(taos->buffer);
+ if (!name) {
+ err = -ENODEV;
+ dev_err(&serio->dev, "TAOS EVM identification failed\n");
+ goto exit_close;
+ }
+ strlcpy(adapter->name, name, sizeof(adapter->name));
+
+ err = i2c_add_adapter(adapter);
+ if (err)
+ goto exit_close;
+ dev_dbg(&serio->dev, "Connected to TAOS EVM\n");
+
+ taos->client = taos_instantiate_device(adapter);
+ return 0;
+
+ exit_close:
+ serio_close(serio);
+ exit_kfree:
+ serio_set_drvdata(serio, NULL);
+ kfree(taos);
+ exit:
+ return err;
+}
+
+static void taos_disconnect(struct serio *serio)
+{
+ struct taos_data *taos = serio_get_drvdata(serio);
+
+ if (taos->client)
+ i2c_unregister_device(taos->client);
+ i2c_del_adapter(&taos->adapter);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ kfree(taos);
+
+ dev_dbg(&serio->dev, "Disconnected from TAOS EVM\n");
+}
+
+static struct serio_device_id taos_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_TAOSEVM,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(serio, taos_serio_ids);
+
+static struct serio_driver taos_drv = {
+ .driver = {
+ .name = "taos-evm",
+ },
+ .description = "TAOS evaluation module driver",
+ .id_table = taos_serio_ids,
+ .connect = taos_connect,
+ .disconnect = taos_disconnect,
+ .interrupt = taos_interrupt,
+};
+
+static int __init taos_init(void)
+{
+ return serio_register_driver(&taos_drv);
+}
+
+static void __exit taos_exit(void)
+{
+ serio_unregister_driver(&taos_drv);
+}
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("TAOS evaluation module driver");
+MODULE_LICENSE("GPL");
+
+module_init(taos_init);
+module_exit(taos_exit);
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 7a2bc06304fc..edc275002f80 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -235,7 +235,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
if (!(vt596_features & FEATURE_I2CBLOCK))
goto exit_unsupported;
if (read_write == I2C_SMBUS_READ)
- outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0);
+ outb_p(data->block[0], SMBHSTDAT0);
/* Fall through */
case I2C_SMBUS_BLOCK_DATA:
outb_p(command, SMBHSTCMD);
@@ -397,8 +397,7 @@ found:
case PCI_DEVICE_ID_VIA_82C686_4:
/* The VT82C686B (rev 0x40) does support I2C block
transactions, but the VT82C686A (rev 0x30) doesn't */
- if (!pci_read_config_byte(pdev, PCI_REVISION_ID, &temp)
- && temp >= 0x40)
+ if (pdev->revision >= 0x40)
vt596_features |= FEATURE_I2CBLOCK;
break;
}
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 0d6bd4f7b7fa..e6c4a2b762ec 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -310,8 +310,6 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
- if (rw == I2C_SMBUS_READ)
- data->block[0] = I2C_SMBUS_BLOCK_MAX; /* For now */
len = data->block[0];
if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
return -EINVAL;
@@ -388,7 +386,7 @@ static const struct i2c_algorithm scx200_acb_algorithm = {
};
static struct scx200_acb_iface *scx200_acb_list;
-static DECLARE_MUTEX(scx200_acb_list_mutex);
+static DEFINE_MUTEX(scx200_acb_list_mutex);
static __init int scx200_acb_probe(struct scx200_acb_iface *iface)
{
@@ -472,10 +470,10 @@ static int __init scx200_acb_create(struct scx200_acb_iface *iface)
return -ENODEV;
}
- down(&scx200_acb_list_mutex);
+ mutex_lock(&scx200_acb_list_mutex);
iface->next = scx200_acb_list;
scx200_acb_list = iface;
- up(&scx200_acb_list_mutex);
+ mutex_unlock(&scx200_acb_list_mutex);
return 0;
}
@@ -633,10 +631,10 @@ static void __exit scx200_acb_cleanup(void)
{
struct scx200_acb_iface *iface;
- down(&scx200_acb_list_mutex);
+ mutex_lock(&scx200_acb_list_mutex);
while ((iface = scx200_acb_list) != NULL) {
scx200_acb_list = iface->next;
- up(&scx200_acb_list_mutex);
+ mutex_unlock(&scx200_acb_list_mutex);
i2c_del_adapter(&iface->adapter);
@@ -648,9 +646,9 @@ static void __exit scx200_acb_cleanup(void)
release_region(iface->base, 8);
kfree(iface);
- down(&scx200_acb_list_mutex);
+ mutex_lock(&scx200_acb_list_mutex);
}
- up(&scx200_acb_list_mutex);
+ mutex_unlock(&scx200_acb_list_mutex);
}
module_init(scx200_acb_init);
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index ea085a006ead..2e1c24f671cf 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -5,7 +5,7 @@
menu "Miscellaneous I2C Chip support"
config SENSORS_DS1337
- tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock"
+ tristate "Dallas DS1337 and DS1339 Real Time Clock (DEPRECATED)"
depends on EXPERIMENTAL
help
If you say yes here you get support for Dallas Semiconductor
@@ -14,8 +14,11 @@ config SENSORS_DS1337
This driver can also be built as a module. If so, the module
will be called ds1337.
+ This driver is deprecated and will be dropped soon. Use
+ rtc-ds1307 instead.
+
config SENSORS_DS1374
- tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+ tristate "Dallas DS1374 Real Time Clock (DEPRECATED)"
depends on EXPERIMENTAL
help
If you say yes here you get support for Dallas Semiconductor
@@ -24,6 +27,19 @@ config SENSORS_DS1374
This driver can also be built as a module. If so, the module
will be called ds1374.
+ This driver is deprecated and will be dropped soon. Use
+ rtc-ds1374 instead.
+
+config DS1682
+ tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS1682 Total Elapsed Time Recorder.
+
+ This driver can also be built as a module. If so, the module
+ will be called ds1682.
+
config SENSORS_EEPROM
tristate "EEPROM reader"
depends on EXPERIMENTAL
@@ -101,7 +117,7 @@ config TPS65010
will be called tps65010.
config SENSORS_M41T00
- tristate "ST M41T00 RTC chip"
+ tristate "ST M41T00 RTC chip (DEPRECATED)"
depends on PPC32
help
If you say yes here you get support for the ST M41T00 RTC chip.
@@ -109,6 +125,9 @@ config SENSORS_M41T00
This driver can also be built as a module. If so, the module
will be called m41t00.
+ This driver is deprecated and will be dropped soon. Use
+ rtc-ds1307 or rtc-m41t80 instead.
+
config SENSORS_MAX6875
tristate "Maxim MAX6875 Power supply supervisor"
depends on EXPERIMENTAL
@@ -124,4 +143,24 @@ config SENSORS_MAX6875
This driver can also be built as a module. If so, the module
will be called max6875.
+config SENSORS_TSL2550
+ tristate "Taos TSL2550 ambient light sensor"
+ depends on EXPERIMENTAL
+ help
+ If you say yes here you get support for the Taos TSL2550
+ ambient light sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called tsl2550.
+
+config MENELAUS
+ bool "TWL92330/Menelaus PM chip"
+ depends on I2C=y && ARCH_OMAP24XX
+ help
+ If you say yes here you get support for the Texas Instruments
+ TWL92330/Menelaus Power Management chip. This include voltage
+ regulators, Dual slot memory card tranceivers, real-time clock
+ and other features that are often used in portable devices like
+ cell phones and PDAs.
+
endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 779868ef2e26..ca924e105959 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_SENSORS_DS1337) += ds1337.o
obj-$(CONFIG_SENSORS_DS1374) += ds1374.o
+obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
@@ -12,6 +13,8 @@ obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
+obj-$(CONFIG_MENELAUS) += menelaus.o
+obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
new file mode 100644
index 000000000000..5879f0f25495
--- /dev/null
+++ b/drivers/i2c/chips/ds1682.c
@@ -0,0 +1,259 @@
+/*
+ * Dallas Semiconductor DS1682 Elapsed Time Recorder device driver
+ *
+ * Written by: Grant Likely <grant.likely@secretlab.ca>
+ *
+ * Copyright (C) 2007 Secret Lab Technologies 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.
+ */
+
+/*
+ * The DS1682 elapsed timer recorder is a simple device that implements
+ * one elapsed time counter, one event counter, an alarm signal and 10
+ * bytes of general purpose EEPROM.
+ *
+ * This driver provides access to the DS1682 counters and user data via
+ * the sysfs. The following attributes are added to the device node:
+ * elapsed_time (u32): Total elapsed event time in ms resolution
+ * alarm_time (u32): When elapsed time exceeds the value in alarm_time,
+ * then the alarm pin is asserted.
+ * event_count (u16): number of times the event pin has gone low.
+ * eeprom (u8[10]): general purpose EEPROM
+ *
+ * Counter registers and user data are both read/write unless the device
+ * has been write protected. This driver does not support turning off write
+ * protection. Once write protection is turned on, it is impossible to
+ * turn it off again, so I have left the feature out of this driver to avoid
+ * accidental enabling, but it is trivial to add write protect support.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/sysfs.h>
+#include <linux/ctype.h>
+#include <linux/hwmon-sysfs.h>
+
+/* Device registers */
+#define DS1682_REG_CONFIG 0x00
+#define DS1682_REG_ALARM 0x01
+#define DS1682_REG_ELAPSED 0x05
+#define DS1682_REG_EVT_CNTR 0x09
+#define DS1682_REG_EEPROM 0x0b
+#define DS1682_REG_RESET 0x1d
+#define DS1682_REG_WRITE_DISABLE 0x1e
+#define DS1682_REG_WRITE_MEM_DISABLE 0x1f
+
+#define DS1682_EEPROM_SIZE 10
+
+/*
+ * Generic counter attributes
+ */
+static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ __le32 val = 0;
+ int rc;
+
+ dev_dbg(dev, "ds1682_show() called on %s\n", attr->attr.name);
+
+ /* Read the register */
+ rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr,
+ (u8 *) & val);
+ if (rc < 0)
+ return -EIO;
+
+ /* Special case: the 32 bit regs are time values with 1/4s
+ * resolution, scale them up to milliseconds */
+ if (sattr->nr == 4)
+ return sprintf(buf, "%llu\n", ((u64) le32_to_cpu(val)) * 250);
+
+ /* Format the output string and return # of bytes */
+ return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
+}
+
+static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct i2c_client *client = to_i2c_client(dev);
+ char *endp;
+ u64 val;
+ __le32 val_le;
+ int rc;
+
+ dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name);
+
+ /* Decode input */
+ val = simple_strtoull(buf, &endp, 0);
+ if (buf == endp) {
+ dev_dbg(dev, "input string not a number\n");
+ return -EINVAL;
+ }
+
+ /* Special case: the 32 bit regs are time values with 1/4s
+ * resolution, scale input down to quarter-seconds */
+ if (sattr->nr == 4)
+ do_div(val, 250);
+
+ /* write out the value */
+ val_le = cpu_to_le32(val);
+ rc = i2c_smbus_write_i2c_block_data(client, sattr->index, sattr->nr,
+ (u8 *) & val_le);
+ if (rc < 0) {
+ dev_err(dev, "register write failed; reg=0x%x, size=%i\n",
+ sattr->index, sattr->nr);
+ return -EIO;
+ }
+
+ return count;
+}
+
+/*
+ * Simple register attributes
+ */
+static SENSOR_DEVICE_ATTR_2(elapsed_time, S_IRUGO | S_IWUSR, ds1682_show,
+ ds1682_store, 4, DS1682_REG_ELAPSED);
+static SENSOR_DEVICE_ATTR_2(alarm_time, S_IRUGO | S_IWUSR, ds1682_show,
+ ds1682_store, 4, DS1682_REG_ALARM);
+static SENSOR_DEVICE_ATTR_2(event_count, S_IRUGO | S_IWUSR, ds1682_show,
+ ds1682_store, 2, DS1682_REG_EVT_CNTR);
+
+static const struct attribute_group ds1682_group = {
+ .attrs = (struct attribute *[]) {
+ &sensor_dev_attr_elapsed_time.dev_attr.attr,
+ &sensor_dev_attr_alarm_time.dev_attr.attr,
+ &sensor_dev_attr_event_count.dev_attr.attr,
+ NULL,
+ },
+};
+
+/*
+ * User data attribute
+ */
+static ssize_t ds1682_eeprom_read(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
+ int rc;
+
+ dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n",
+ buf, off, count);
+
+ if (off >= DS1682_EEPROM_SIZE)
+ return 0;
+
+ if (off + count > DS1682_EEPROM_SIZE)
+ count = DS1682_EEPROM_SIZE - off;
+
+ rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off,
+ count, buf);
+ if (rc < 0)
+ return -EIO;
+
+ return count;
+}
+
+static ssize_t ds1682_eeprom_write(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct i2c_client *client = kobj_to_i2c_client(kobj);
+
+ dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n",
+ buf, off, count);
+
+ if (off >= DS1682_EEPROM_SIZE)
+ return -ENOSPC;
+
+ if (off + count > DS1682_EEPROM_SIZE)
+ count = DS1682_EEPROM_SIZE - off;
+
+ /* Write out to the device */
+ if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off,
+ count, buf) < 0)
+ return -EIO;
+
+ return count;
+}
+
+static struct bin_attribute ds1682_eeprom_attr = {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = DS1682_EEPROM_SIZE,
+ .read = ds1682_eeprom_read,
+ .write = ds1682_eeprom_write,
+};
+
+/*
+ * Called when a ds1682 device is matched with this driver
+ */
+static int ds1682_probe(struct i2c_client *client)
+{
+ int rc;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_I2C_BLOCK)) {
+ dev_err(&client->dev, "i2c bus does not support the ds1682\n");
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ rc = sysfs_create_group(&client->dev.kobj, &ds1682_group);
+ if (rc)
+ goto exit;
+
+ rc = sysfs_create_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
+ if (rc)
+ goto exit_bin_attr;
+
+ return 0;
+
+ exit_bin_attr:
+ sysfs_remove_group(&client->dev.kobj, &ds1682_group);
+ exit:
+ return rc;
+}
+
+static int ds1682_remove(struct i2c_client *client)
+{
+ sysfs_remove_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
+ sysfs_remove_group(&client->dev.kobj, &ds1682_group);
+ return 0;
+}
+
+static struct i2c_driver ds1682_driver = {
+ .driver = {
+ .name = "ds1682",
+ },
+ .probe = ds1682_probe,
+ .remove = ds1682_remove,
+};
+
+static int __init ds1682_init(void)
+{
+ return i2c_add_driver(&ds1682_driver);
+}
+
+static void __exit ds1682_exit(void)
+{
+ i2c_del_driver(&ds1682_driver);
+}
+
+MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
+MODULE_DESCRIPTION("DS1682 Elapsed Time Indicator driver");
+MODULE_LICENSE("GPL");
+
+module_init(ds1682_init);
+module_exit(ds1682_exit);
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index bfce13c8f1ff..d3da1fb05b9b 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -88,8 +88,10 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice)
dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
- for (i = slice << 5; i < (slice + 1) << 5; i += I2C_SMBUS_BLOCK_MAX)
- if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_BLOCK_MAX)
+ for (i = slice << 5; i < (slice + 1) << 5; i += 32)
+ if (i2c_smbus_read_i2c_block_data(client, i,
+ 32, data->data + i)
+ != 32)
goto exit;
} else {
if (i2c_smbus_write_byte(client, slice << 5)) {
@@ -110,7 +112,8 @@ exit:
mutex_unlock(&data->update_lock);
}
-static ssize_t eeprom_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t eeprom_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
struct eeprom_data *data = i2c_get_clientdata(client);
@@ -143,7 +146,6 @@ static struct bin_attribute eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO,
- .owner = THIS_MODULE,
},
.size = EEPROM_SIZE,
.read = eeprom_read,
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index 76645c142977..64692f666372 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -106,6 +106,7 @@ static void max6875_update_slice(struct i2c_client *client, int slice)
I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
if (i2c_smbus_read_i2c_block_data(client,
MAX6875_CMD_BLK_READ,
+ SLICE_SIZE,
buf) != SLICE_SIZE) {
goto exit_up;
}
@@ -125,8 +126,9 @@ exit_up:
mutex_unlock(&data->update_lock);
}
-static ssize_t max6875_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t max6875_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct i2c_client *client = kobj_to_i2c_client(kobj);
struct max6875_data *data = i2c_get_clientdata(client);
@@ -152,7 +154,6 @@ static struct bin_attribute user_eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO,
- .owner = THIS_MODULE,
},
.size = USER_EEPROM_SIZE,
.read = max6875_read,
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
new file mode 100644
index 000000000000..48a7e2f0bdd3
--- /dev/null
+++ b/drivers/i2c/chips/menelaus.c
@@ -0,0 +1,1281 @@
+#define DEBUG
+/*
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * Some parts based tps65010.c:
+ * Copyright (C) 2004 Texas Instruments and
+ * Copyright (C) 2004-2005 David Brownell
+ *
+ * Some parts based on tlv320aic24.c:
+ * Copyright (C) by Kai Svahn <kai.svahn@nokia.com>
+ *
+ * Changes for interrupt handling and clean-up by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * Cleanup and generalized support for voltage setting by
+ * Juha Yrjola
+ * Added support for controlling VCORE and regulator sleep states,
+ * Amit Kucheria <amit.kucheria@nokia.com>
+ * Copyright (C) 2005, 2006 Nokia 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/menelaus.h>
+
+#define DRIVER_NAME "menelaus"
+
+#define pr_err(fmt, arg...) printk(KERN_ERR DRIVER_NAME ": ", ## arg);
+
+#define MENELAUS_I2C_ADDRESS 0x72
+
+#define MENELAUS_REV 0x01
+#define MENELAUS_VCORE_CTRL1 0x02
+#define MENELAUS_VCORE_CTRL2 0x03
+#define MENELAUS_VCORE_CTRL3 0x04
+#define MENELAUS_VCORE_CTRL4 0x05
+#define MENELAUS_VCORE_CTRL5 0x06
+#define MENELAUS_DCDC_CTRL1 0x07
+#define MENELAUS_DCDC_CTRL2 0x08
+#define MENELAUS_DCDC_CTRL3 0x09
+#define MENELAUS_LDO_CTRL1 0x0A
+#define MENELAUS_LDO_CTRL2 0x0B
+#define MENELAUS_LDO_CTRL3 0x0C
+#define MENELAUS_LDO_CTRL4 0x0D
+#define MENELAUS_LDO_CTRL5 0x0E
+#define MENELAUS_LDO_CTRL6 0x0F
+#define MENELAUS_LDO_CTRL7 0x10
+#define MENELAUS_LDO_CTRL8 0x11
+#define MENELAUS_SLEEP_CTRL1 0x12
+#define MENELAUS_SLEEP_CTRL2 0x13
+#define MENELAUS_DEVICE_OFF 0x14
+#define MENELAUS_OSC_CTRL 0x15
+#define MENELAUS_DETECT_CTRL 0x16
+#define MENELAUS_INT_MASK1 0x17
+#define MENELAUS_INT_MASK2 0x18
+#define MENELAUS_INT_STATUS1 0x19
+#define MENELAUS_INT_STATUS2 0x1A
+#define MENELAUS_INT_ACK1 0x1B
+#define MENELAUS_INT_ACK2 0x1C
+#define MENELAUS_GPIO_CTRL 0x1D
+#define MENELAUS_GPIO_IN 0x1E
+#define MENELAUS_GPIO_OUT 0x1F
+#define MENELAUS_BBSMS 0x20
+#define MENELAUS_RTC_CTRL 0x21
+#define MENELAUS_RTC_UPDATE 0x22
+#define MENELAUS_RTC_SEC 0x23
+#define MENELAUS_RTC_MIN 0x24
+#define MENELAUS_RTC_HR 0x25
+#define MENELAUS_RTC_DAY 0x26
+#define MENELAUS_RTC_MON 0x27
+#define MENELAUS_RTC_YR 0x28
+#define MENELAUS_RTC_WKDAY 0x29
+#define MENELAUS_RTC_AL_SEC 0x2A
+#define MENELAUS_RTC_AL_MIN 0x2B
+#define MENELAUS_RTC_AL_HR 0x2C
+#define MENELAUS_RTC_AL_DAY 0x2D
+#define MENELAUS_RTC_AL_MON 0x2E
+#define MENELAUS_RTC_AL_YR 0x2F
+#define MENELAUS_RTC_COMP_MSB 0x30
+#define MENELAUS_RTC_COMP_LSB 0x31
+#define MENELAUS_S1_PULL_EN 0x32
+#define MENELAUS_S1_PULL_DIR 0x33
+#define MENELAUS_S2_PULL_EN 0x34
+#define MENELAUS_S2_PULL_DIR 0x35
+#define MENELAUS_MCT_CTRL1 0x36
+#define MENELAUS_MCT_CTRL2 0x37
+#define MENELAUS_MCT_CTRL3 0x38
+#define MENELAUS_MCT_PIN_ST 0x39
+#define MENELAUS_DEBOUNCE1 0x3A
+
+#define IH_MENELAUS_IRQS 12
+#define MENELAUS_MMC_S1CD_IRQ 0 /* MMC slot 1 card change */
+#define MENELAUS_MMC_S2CD_IRQ 1 /* MMC slot 2 card change */
+#define MENELAUS_MMC_S1D1_IRQ 2 /* MMC DAT1 low in slot 1 */
+#define MENELAUS_MMC_S2D1_IRQ 3 /* MMC DAT1 low in slot 2 */
+#define MENELAUS_LOWBAT_IRQ 4 /* Low battery */
+#define MENELAUS_HOTDIE_IRQ 5 /* Hot die detect */
+#define MENELAUS_UVLO_IRQ 6 /* UVLO detect */
+#define MENELAUS_TSHUT_IRQ 7 /* Thermal shutdown */
+#define MENELAUS_RTCTMR_IRQ 8 /* RTC timer */
+#define MENELAUS_RTCALM_IRQ 9 /* RTC alarm */
+#define MENELAUS_RTCERR_IRQ 10 /* RTC error */
+#define MENELAUS_PSHBTN_IRQ 11 /* Push button */
+#define MENELAUS_RESERVED12_IRQ 12 /* Reserved */
+#define MENELAUS_RESERVED13_IRQ 13 /* Reserved */
+#define MENELAUS_RESERVED14_IRQ 14 /* Reserved */
+#define MENELAUS_RESERVED15_IRQ 15 /* Reserved */
+
+static void menelaus_work(struct work_struct *_menelaus);
+
+struct menelaus_chip {
+ struct mutex lock;
+ struct i2c_client *client;
+ struct work_struct work;
+#ifdef CONFIG_RTC_DRV_TWL92330
+ struct rtc_device *rtc;
+ u8 rtc_control;
+ unsigned uie:1;
+#endif
+ unsigned vcore_hw_mode:1;
+ u8 mask1, mask2;
+ void (*handlers[16])(struct menelaus_chip *);
+ void (*mmc_callback)(void *data, u8 mask);
+ void *mmc_callback_data;
+};
+
+static struct menelaus_chip *the_menelaus;
+
+static int menelaus_write_reg(int reg, u8 value)
+{
+ int val = i2c_smbus_write_byte_data(the_menelaus->client, reg, value);
+
+ if (val < 0) {
+ pr_err("write error");
+ return val;
+ }
+
+ return 0;
+}
+
+static int menelaus_read_reg(int reg)
+{
+ int val = i2c_smbus_read_byte_data(the_menelaus->client, reg);
+
+ if (val < 0)
+ pr_err("read error");
+
+ return val;
+}
+
+static int menelaus_enable_irq(int irq)
+{
+ if (irq > 7) {
+ irq -= 8;
+ the_menelaus->mask2 &= ~(1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK2,
+ the_menelaus->mask2);
+ } else {
+ the_menelaus->mask1 &= ~(1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK1,
+ the_menelaus->mask1);
+ }
+}
+
+static int menelaus_disable_irq(int irq)
+{
+ if (irq > 7) {
+ irq -= 8;
+ the_menelaus->mask2 |= (1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK2,
+ the_menelaus->mask2);
+ } else {
+ the_menelaus->mask1 |= (1 << irq);
+ return menelaus_write_reg(MENELAUS_INT_MASK1,
+ the_menelaus->mask1);
+ }
+}
+
+static int menelaus_ack_irq(int irq)
+{
+ if (irq > 7)
+ return menelaus_write_reg(MENELAUS_INT_ACK2, 1 << (irq - 8));
+ else
+ return menelaus_write_reg(MENELAUS_INT_ACK1, 1 << irq);
+}
+
+/* Adds a handler for an interrupt. Does not run in interrupt context */
+static int menelaus_add_irq_work(int irq,
+ void (*handler)(struct menelaus_chip *))
+{
+ int ret = 0;
+
+ mutex_lock(&the_menelaus->lock);
+ the_menelaus->handlers[irq] = handler;
+ ret = menelaus_enable_irq(irq);
+ mutex_unlock(&the_menelaus->lock);
+
+ return ret;
+}
+
+/* Removes handler for an interrupt */
+static int menelaus_remove_irq_work(int irq)
+{
+ int ret = 0;
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_disable_irq(irq);
+ the_menelaus->handlers[irq] = NULL;
+ mutex_unlock(&the_menelaus->lock);
+
+ return ret;
+}
+
+/*
+ * Gets scheduled when a card detect interrupt happens. Note that in some cases
+ * this line is wired to card cover switch rather than the card detect switch
+ * in each slot. In this case the cards are not seen by menelaus.
+ * FIXME: Add handling for D1 too
+ */
+static void menelaus_mmc_cd_work(struct menelaus_chip *menelaus_hw)
+{
+ int reg;
+ unsigned char card_mask = 0;
+
+ reg = menelaus_read_reg(MENELAUS_MCT_PIN_ST);
+ if (reg < 0)
+ return;
+
+ if (!(reg & 0x1))
+ card_mask |= (1 << 0);
+
+ if (!(reg & 0x2))
+ card_mask |= (1 << 1);
+
+ if (menelaus_hw->mmc_callback)
+ menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data,
+ card_mask);
+}
+
+/*
+ * Toggles the MMC slots between open-drain and push-pull mode.
+ */
+int menelaus_set_mmc_opendrain(int slot, int enable)
+{
+ int ret, val;
+
+ if (slot != 1 && slot != 2)
+ return -EINVAL;
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_read_reg(MENELAUS_MCT_CTRL1);
+ if (ret < 0) {
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+ }
+ val = ret;
+ if (slot == 1) {
+ if (enable)
+ val |= 1 << 2;
+ else
+ val &= ~(1 << 2);
+ } else {
+ if (enable)
+ val |= 1 << 3;
+ else
+ val &= ~(1 << 3);
+ }
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val);
+ mutex_unlock(&the_menelaus->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_set_mmc_opendrain);
+
+int menelaus_set_slot_sel(int enable)
+{
+ int ret;
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
+ if (ret < 0)
+ goto out;
+ ret |= 0x02;
+ if (enable)
+ ret |= 1 << 5;
+ else
+ ret &= ~(1 << 5);
+ ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_set_slot_sel);
+
+int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
+{
+ int ret, val;
+
+ if (slot != 1 && slot != 2)
+ return -EINVAL;
+ if (power >= 3)
+ return -EINVAL;
+
+ mutex_lock(&the_menelaus->lock);
+
+ ret = menelaus_read_reg(MENELAUS_MCT_CTRL2);
+ if (ret < 0)
+ goto out;
+ val = ret;
+ if (slot == 1) {
+ if (cd_en)
+ val |= (1 << 4) | (1 << 6);
+ else
+ val &= ~((1 << 4) | (1 << 6));
+ } else {
+ if (cd_en)
+ val |= (1 << 5) | (1 << 7);
+ else
+ val &= ~((1 << 5) | (1 << 7));
+ }
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val);
+ if (ret < 0)
+ goto out;
+
+ ret = menelaus_read_reg(MENELAUS_MCT_CTRL3);
+ if (ret < 0)
+ goto out;
+ val = ret;
+ if (slot == 1) {
+ if (enable)
+ val |= 1 << 0;
+ else
+ val &= ~(1 << 0);
+ } else {
+ int b;
+
+ if (enable)
+ ret |= 1 << 1;
+ else
+ ret &= ~(1 << 1);
+ b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
+ b &= ~0x03;
+ b |= power;
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b);
+ if (ret < 0)
+ goto out;
+ }
+ /* Disable autonomous shutdown */
+ val &= ~(0x03 << 2);
+ ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_set_mmc_slot);
+
+int menelaus_register_mmc_callback(void (*callback)(void *data, u8 card_mask),
+ void *data)
+{
+ int ret = 0;
+
+ the_menelaus->mmc_callback_data = data;
+ the_menelaus->mmc_callback = callback;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S1CD_IRQ,
+ menelaus_mmc_cd_work);
+ if (ret < 0)
+ return ret;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S2CD_IRQ,
+ menelaus_mmc_cd_work);
+ if (ret < 0)
+ return ret;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S1D1_IRQ,
+ menelaus_mmc_cd_work);
+ if (ret < 0)
+ return ret;
+ ret = menelaus_add_irq_work(MENELAUS_MMC_S2D1_IRQ,
+ menelaus_mmc_cd_work);
+
+ return ret;
+}
+EXPORT_SYMBOL(menelaus_register_mmc_callback);
+
+void menelaus_unregister_mmc_callback(void)
+{
+ menelaus_remove_irq_work(MENELAUS_MMC_S1CD_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S2CD_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S1D1_IRQ);
+ menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ);
+
+ the_menelaus->mmc_callback = NULL;
+ the_menelaus->mmc_callback_data = 0;
+}
+EXPORT_SYMBOL(menelaus_unregister_mmc_callback);
+
+struct menelaus_vtg {
+ const char *name;
+ u8 vtg_reg;
+ u8 vtg_shift;
+ u8 vtg_bits;
+ u8 mode_reg;
+};
+
+struct menelaus_vtg_value {
+ u16 vtg;
+ u16 val;
+};
+
+static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV,
+ int vtg_val, int mode)
+{
+ int val, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ mutex_lock(&the_menelaus->lock);
+ if (vtg == 0)
+ goto set_voltage;
+
+ ret = menelaus_read_reg(vtg->vtg_reg);
+ if (ret < 0)
+ goto out;
+ val = ret & ~(((1 << vtg->vtg_bits) - 1) << vtg->vtg_shift);
+ val |= vtg_val << vtg->vtg_shift;
+
+ dev_dbg(&c->dev, "Setting voltage '%s'"
+ "to %d mV (reg 0x%02x, val 0x%02x)\n",
+ vtg->name, mV, vtg->vtg_reg, val);
+
+ ret = menelaus_write_reg(vtg->vtg_reg, val);
+ if (ret < 0)
+ goto out;
+set_voltage:
+ ret = menelaus_write_reg(vtg->mode_reg, mode);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ if (ret == 0) {
+ /* Wait for voltage to stabilize */
+ msleep(1);
+ }
+ return ret;
+}
+
+static int menelaus_get_vtg_value(int vtg, const struct menelaus_vtg_value *tbl,
+ int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++, tbl++)
+ if (tbl->vtg == vtg)
+ return tbl->val;
+ return -EINVAL;
+}
+
+/*
+ * Vcore can be programmed in two ways:
+ * SW-controlled: Required voltage is programmed into VCORE_CTRL1
+ * HW-controlled: Required range (roof-floor) is programmed into VCORE_CTRL3
+ * and VCORE_CTRL4
+ *
+ * Call correct 'set' function accordingly
+ */
+
+static const struct menelaus_vtg_value vcore_values[] = {
+ { 1000, 0 },
+ { 1025, 1 },
+ { 1050, 2 },
+ { 1075, 3 },
+ { 1100, 4 },
+ { 1125, 5 },
+ { 1150, 6 },
+ { 1175, 7 },
+ { 1200, 8 },
+ { 1225, 9 },
+ { 1250, 10 },
+ { 1275, 11 },
+ { 1300, 12 },
+ { 1325, 13 },
+ { 1350, 14 },
+ { 1375, 15 },
+ { 1400, 16 },
+ { 1425, 17 },
+ { 1450, 18 },
+};
+
+int menelaus_set_vcore_sw(unsigned int mV)
+{
+ int val, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ val = menelaus_get_vtg_value(mV, vcore_values,
+ ARRAY_SIZE(vcore_values));
+ if (val < 0)
+ return -EINVAL;
+
+ dev_dbg(&c->dev, "Setting VCORE to %d mV (val 0x%02x)\n", mV, val);
+
+ /* Set SW mode and the voltage in one go. */
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
+ if (ret == 0)
+ the_menelaus->vcore_hw_mode = 0;
+ mutex_unlock(&the_menelaus->lock);
+ msleep(1);
+
+ return ret;
+}
+
+int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV)
+{
+ int fval, rval, val, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ rval = menelaus_get_vtg_value(roof_mV, vcore_values,
+ ARRAY_SIZE(vcore_values));
+ if (rval < 0)
+ return -EINVAL;
+ fval = menelaus_get_vtg_value(floor_mV, vcore_values,
+ ARRAY_SIZE(vcore_values));
+ if (fval < 0)
+ return -EINVAL;
+
+ dev_dbg(&c->dev, "Setting VCORE FLOOR to %d mV and ROOF to %d mV\n",
+ floor_mV, roof_mV);
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL3, fval);
+ if (ret < 0)
+ goto out;
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL4, rval);
+ if (ret < 0)
+ goto out;
+ if (!the_menelaus->vcore_hw_mode) {
+ val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
+ /* HW mode, turn OFF byte comparator */
+ val |= ((1 << 7) | (1 << 5));
+ ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
+ the_menelaus->vcore_hw_mode = 1;
+ }
+ msleep(1);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+
+static const struct menelaus_vtg vmem_vtg = {
+ .name = "VMEM",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 0,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL3,
+};
+
+static const struct menelaus_vtg_value vmem_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 1900, 2 },
+ { 2500, 3 },
+};
+
+int menelaus_set_vmem(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vmem_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vmem_values, ARRAY_SIZE(vmem_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vmem_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vmem);
+
+static const struct menelaus_vtg vio_vtg = {
+ .name = "VIO",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 2,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL4,
+};
+
+static const struct menelaus_vtg_value vio_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 2500, 2 },
+ { 2800, 3 },
+};
+
+int menelaus_set_vio(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vio_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vio_values, ARRAY_SIZE(vio_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vio_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vio);
+
+static const struct menelaus_vtg_value vdcdc_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 2000, 2 },
+ { 2200, 3 },
+ { 2400, 4 },
+ { 2800, 5 },
+ { 3000, 6 },
+ { 3300, 7 },
+};
+
+static const struct menelaus_vtg vdcdc2_vtg = {
+ .name = "VDCDC2",
+ .vtg_reg = MENELAUS_DCDC_CTRL1,
+ .vtg_shift = 0,
+ .vtg_bits = 3,
+ .mode_reg = MENELAUS_DCDC_CTRL2,
+};
+
+static const struct menelaus_vtg vdcdc3_vtg = {
+ .name = "VDCDC3",
+ .vtg_reg = MENELAUS_DCDC_CTRL1,
+ .vtg_shift = 3,
+ .vtg_bits = 3,
+ .mode_reg = MENELAUS_DCDC_CTRL3,
+};
+
+int menelaus_set_vdcdc(int dcdc, unsigned int mV)
+{
+ const struct menelaus_vtg *vtg;
+ int val;
+
+ if (dcdc != 2 && dcdc != 3)
+ return -EINVAL;
+ if (dcdc == 2)
+ vtg = &vdcdc2_vtg;
+ else
+ vtg = &vdcdc3_vtg;
+
+ if (mV == 0)
+ return menelaus_set_voltage(vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vdcdc_values,
+ ARRAY_SIZE(vdcdc_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(vtg, mV, val, 0x03);
+}
+
+static const struct menelaus_vtg_value vmmc_values[] = {
+ { 1850, 0 },
+ { 2800, 1 },
+ { 3000, 2 },
+ { 3100, 3 },
+};
+
+static const struct menelaus_vtg vmmc_vtg = {
+ .name = "VMMC",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 6,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL7,
+};
+
+int menelaus_set_vmmc(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vmmc_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vmmc_values, ARRAY_SIZE(vmmc_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vmmc_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vmmc);
+
+
+static const struct menelaus_vtg_value vaux_values[] = {
+ { 1500, 0 },
+ { 1800, 1 },
+ { 2500, 2 },
+ { 2800, 3 },
+};
+
+static const struct menelaus_vtg vaux_vtg = {
+ .name = "VAUX",
+ .vtg_reg = MENELAUS_LDO_CTRL1,
+ .vtg_shift = 4,
+ .vtg_bits = 2,
+ .mode_reg = MENELAUS_LDO_CTRL6,
+};
+
+int menelaus_set_vaux(unsigned int mV)
+{
+ int val;
+
+ if (mV == 0)
+ return menelaus_set_voltage(&vaux_vtg, 0, 0, 0);
+
+ val = menelaus_get_vtg_value(mV, vaux_values, ARRAY_SIZE(vaux_values));
+ if (val < 0)
+ return -EINVAL;
+ return menelaus_set_voltage(&vaux_vtg, mV, val, 0x02);
+}
+EXPORT_SYMBOL(menelaus_set_vaux);
+
+int menelaus_get_slot_pin_states(void)
+{
+ return menelaus_read_reg(MENELAUS_MCT_PIN_ST);
+}
+EXPORT_SYMBOL(menelaus_get_slot_pin_states);
+
+int menelaus_set_regulator_sleep(int enable, u32 val)
+{
+ int t, ret;
+ struct i2c_client *c = the_menelaus->client;
+
+ mutex_lock(&the_menelaus->lock);
+ ret = menelaus_write_reg(MENELAUS_SLEEP_CTRL2, val);
+ if (ret < 0)
+ goto out;
+
+ dev_dbg(&c->dev, "regulator sleep configuration: %02x\n", val);
+
+ ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
+ if (ret < 0)
+ goto out;
+ t = ((1 << 6) | 0x04);
+ if (enable)
+ ret |= t;
+ else
+ ret &= ~t;
+ ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
+out:
+ mutex_unlock(&the_menelaus->lock);
+ return ret;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* Handles Menelaus interrupts. Does not run in interrupt context */
+static void menelaus_work(struct work_struct *_menelaus)
+{
+ struct menelaus_chip *menelaus =
+ container_of(_menelaus, struct menelaus_chip, work);
+ void (*handler)(struct menelaus_chip *menelaus);
+
+ while (1) {
+ unsigned isr;
+
+ isr = (menelaus_read_reg(MENELAUS_INT_STATUS2)
+ & ~menelaus->mask2) << 8;
+ isr |= menelaus_read_reg(MENELAUS_INT_STATUS1)
+ & ~menelaus->mask1;
+ if (!isr)
+ break;
+
+ while (isr) {
+ int irq = fls(isr) - 1;
+ isr &= ~(1 << irq);
+
+ mutex_lock(&menelaus->lock);
+ menelaus_disable_irq(irq);
+ menelaus_ack_irq(irq);
+ handler = menelaus->handlers[irq];
+ if (handler)
+ handler(menelaus);
+ menelaus_enable_irq(irq);
+ mutex_unlock(&menelaus->lock);
+ }
+ }
+ enable_irq(menelaus->client->irq);
+}
+
+/*
+ * We cannot use I2C in interrupt context, so we just schedule work.
+ */
+static irqreturn_t menelaus_irq(int irq, void *_menelaus)
+{
+ struct menelaus_chip *menelaus = _menelaus;
+
+ disable_irq_nosync(irq);
+ (void)schedule_work(&menelaus->work);
+
+ return IRQ_HANDLED;
+}
+
+/*-----------------------------------------------------------------------*/
+
+/*
+ * The RTC needs to be set once, then it runs on backup battery power.
+ * It supports alarms, including system wake alarms (from some modes);
+ * and 1/second IRQs if requested.
+ */
+#ifdef CONFIG_RTC_DRV_TWL92330
+
+#define RTC_CTRL_RTC_EN (1 << 0)
+#define RTC_CTRL_AL_EN (1 << 1)
+#define RTC_CTRL_MODE12 (1 << 2)
+#define RTC_CTRL_EVERY_MASK (3 << 3)
+#define RTC_CTRL_EVERY_SEC (0 << 3)
+#define RTC_CTRL_EVERY_MIN (1 << 3)
+#define RTC_CTRL_EVERY_HR (2 << 3)
+#define RTC_CTRL_EVERY_DAY (3 << 3)
+
+#define RTC_UPDATE_EVERY 0x08
+
+#define RTC_HR_PM (1 << 7)
+
+static void menelaus_to_time(char *regs, struct rtc_time *t)
+{
+ t->tm_sec = BCD2BIN(regs[0]);
+ t->tm_min = BCD2BIN(regs[1]);
+ if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
+ t->tm_hour = BCD2BIN(regs[2] & 0x1f) - 1;
+ if (regs[2] & RTC_HR_PM)
+ t->tm_hour += 12;
+ } else
+ t->tm_hour = BCD2BIN(regs[2] & 0x3f);
+ t->tm_mday = BCD2BIN(regs[3]);
+ t->tm_mon = BCD2BIN(regs[4]) - 1;
+ t->tm_year = BCD2BIN(regs[5]) + 100;
+}
+
+static int time_to_menelaus(struct rtc_time *t, int regnum)
+{
+ int hour, status;
+
+ status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_sec));
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_min));
+ if (status < 0)
+ goto fail;
+
+ if (the_menelaus->rtc_control & RTC_CTRL_MODE12) {
+ hour = t->tm_hour + 1;
+ if (hour > 12)
+ hour = RTC_HR_PM | BIN2BCD(hour - 12);
+ else
+ hour = BIN2BCD(hour);
+ } else
+ hour = BIN2BCD(t->tm_hour);
+ status = menelaus_write_reg(regnum++, hour);
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_mday));
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_mon + 1));
+ if (status < 0)
+ goto fail;
+
+ status = menelaus_write_reg(regnum++, BIN2BCD(t->tm_year - 100));
+ if (status < 0)
+ goto fail;
+
+ return 0;
+fail:
+ dev_err(&the_menelaus->client->dev, "rtc write reg %02x, err %d\n",
+ --regnum, status);
+ return status;
+}
+
+static int menelaus_read_time(struct device *dev, struct rtc_time *t)
+{
+ struct i2c_msg msg[2];
+ char regs[7];
+ int status;
+
+ /* block read date and time registers */
+ regs[0] = MENELAUS_RTC_SEC;
+
+ msg[0].addr = MENELAUS_I2C_ADDRESS;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = regs;
+
+ msg[1].addr = MENELAUS_I2C_ADDRESS;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = sizeof(regs);
+ msg[1].buf = regs;
+
+ status = i2c_transfer(the_menelaus->client->adapter, msg, 2);
+ if (status != 2) {
+ dev_err(dev, "%s error %d\n", "read", status);
+ return -EIO;
+ }
+
+ menelaus_to_time(regs, t);
+ t->tm_wday = BCD2BIN(regs[6]);
+
+ return 0;
+}
+
+static int menelaus_set_time(struct device *dev, struct rtc_time *t)
+{
+ int status;
+
+ /* write date and time registers */
+ status = time_to_menelaus(t, MENELAUS_RTC_SEC);
+ if (status < 0)
+ return status;
+ status = menelaus_write_reg(MENELAUS_RTC_WKDAY, BIN2BCD(t->tm_wday));
+ if (status < 0) {
+ dev_err(&the_menelaus->client->dev, "rtc write reg %02x",
+ "err %d\n", MENELAUS_RTC_WKDAY, status);
+ return status;
+ }
+
+ /* now commit the write */
+ status = menelaus_write_reg(MENELAUS_RTC_UPDATE, RTC_UPDATE_EVERY);
+ if (status < 0)
+ dev_err(&the_menelaus->client->dev, "rtc commit time, err %d\n",
+ status);
+
+ return 0;
+}
+
+static int menelaus_read_alarm(struct device *dev, struct rtc_wkalrm *w)
+{
+ struct i2c_msg msg[2];
+ char regs[6];
+ int status;
+
+ /* block read alarm registers */
+ regs[0] = MENELAUS_RTC_AL_SEC;
+
+ msg[0].addr = MENELAUS_I2C_ADDRESS;
+ msg[0].flags = 0;
+ msg[0].len = 1;
+ msg[0].buf = regs;
+
+ msg[1].addr = MENELAUS_I2C_ADDRESS;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = sizeof(regs);
+ msg[1].buf = regs;
+
+ status = i2c_transfer(the_menelaus->client->adapter, msg, 2);
+ if (status != 2) {
+ dev_err(dev, "%s error %d\n", "alarm read", status);
+ return -EIO;
+ }
+
+ menelaus_to_time(regs, &w->time);
+
+ w->enabled = !!(the_menelaus->rtc_control & RTC_CTRL_AL_EN);
+
+ /* NOTE we *could* check if actually pending... */
+ w->pending = 0;
+
+ return 0;
+}
+
+static int menelaus_set_alarm(struct device *dev, struct rtc_wkalrm *w)
+{
+ int status;
+
+ if (the_menelaus->client->irq <= 0 && w->enabled)
+ return -ENODEV;
+
+ /* clear previous alarm enable */
+ if (the_menelaus->rtc_control & RTC_CTRL_AL_EN) {
+ the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
+ status = menelaus_write_reg(MENELAUS_RTC_CTRL,
+ the_menelaus->rtc_control);
+ if (status < 0)
+ return status;
+ }
+
+ /* write alarm registers */
+ status = time_to_menelaus(&w->time, MENELAUS_RTC_AL_SEC);
+ if (status < 0)
+ return status;
+
+ /* enable alarm if requested */
+ if (w->enabled) {
+ the_menelaus->rtc_control |= RTC_CTRL_AL_EN;
+ status = menelaus_write_reg(MENELAUS_RTC_CTRL,
+ the_menelaus->rtc_control);
+ }
+
+ return status;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+
+static void menelaus_rtc_update_work(struct menelaus_chip *m)
+{
+ /* report 1/sec update */
+ local_irq_disable();
+ rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_UF);
+ local_irq_enable();
+}
+
+static int menelaus_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
+{
+ int status;
+
+ if (the_menelaus->client->irq <= 0)
+ return -ENOIOCTLCMD;
+
+ switch (cmd) {
+ /* alarm IRQ */
+ case RTC_AIE_ON:
+ if (the_menelaus->rtc_control & RTC_CTRL_AL_EN)
+ return 0;
+ the_menelaus->rtc_control |= RTC_CTRL_AL_EN;
+ break;
+ case RTC_AIE_OFF:
+ if (!(the_menelaus->rtc_control & RTC_CTRL_AL_EN))
+ return 0;
+ the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
+ break;
+ /* 1/second "update" IRQ */
+ case RTC_UIE_ON:
+ if (the_menelaus->uie)
+ return 0;
+ status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ);
+ status = menelaus_add_irq_work(MENELAUS_RTCTMR_IRQ,
+ menelaus_rtc_update_work);
+ if (status == 0)
+ the_menelaus->uie = 1;
+ return status;
+ case RTC_UIE_OFF:
+ if (!the_menelaus->uie)
+ return 0;
+ status = menelaus_remove_irq_work(MENELAUS_RTCTMR_IRQ);
+ if (status == 0)
+ the_menelaus->uie = 0;
+ return status;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control);
+}
+
+#else
+#define menelaus_ioctl NULL
+#endif
+
+/* REVISIT no compensation register support ... */
+
+static const struct rtc_class_ops menelaus_rtc_ops = {
+ .ioctl = menelaus_ioctl,
+ .read_time = menelaus_read_time,
+ .set_time = menelaus_set_time,
+ .read_alarm = menelaus_read_alarm,
+ .set_alarm = menelaus_set_alarm,
+};
+
+static void menelaus_rtc_alarm_work(struct menelaus_chip *m)
+{
+ /* report alarm */
+ local_irq_disable();
+ rtc_update_irq(m->rtc, 1, RTC_IRQF | RTC_AF);
+ local_irq_enable();
+
+ /* then disable it; alarms are oneshot */
+ the_menelaus->rtc_control &= ~RTC_CTRL_AL_EN;
+ menelaus_write_reg(MENELAUS_RTC_CTRL, the_menelaus->rtc_control);
+}
+
+static inline void menelaus_rtc_init(struct menelaus_chip *m)
+{
+ int alarm = (m->client->irq > 0);
+
+ /* assume 32KDETEN pin is pulled high */
+ if (!(menelaus_read_reg(MENELAUS_OSC_CTRL) & 0x80)) {
+ dev_dbg(&m->client->dev, "no 32k oscillator\n");
+ return;
+ }
+
+ /* support RTC alarm; it can issue wakeups */
+ if (alarm) {
+ if (menelaus_add_irq_work(MENELAUS_RTCALM_IRQ,
+ menelaus_rtc_alarm_work) < 0) {
+ dev_err(&m->client->dev, "can't handle RTC alarm\n");
+ return;
+ }
+ device_init_wakeup(&m->client->dev, 1);
+ }
+
+ /* be sure RTC is enabled; allow 1/sec irqs; leave 12hr mode alone */
+ m->rtc_control = menelaus_read_reg(MENELAUS_RTC_CTRL);
+ if (!(m->rtc_control & RTC_CTRL_RTC_EN)
+ || (m->rtc_control & RTC_CTRL_AL_EN)
+ || (m->rtc_control & RTC_CTRL_EVERY_MASK)) {
+ if (!(m->rtc_control & RTC_CTRL_RTC_EN)) {
+ dev_warn(&m->client->dev, "rtc clock needs setting\n");
+ m->rtc_control |= RTC_CTRL_RTC_EN;
+ }
+ m->rtc_control &= ~RTC_CTRL_EVERY_MASK;
+ m->rtc_control &= ~RTC_CTRL_AL_EN;
+ menelaus_write_reg(MENELAUS_RTC_CTRL, m->rtc_control);
+ }
+
+ m->rtc = rtc_device_register(DRIVER_NAME,
+ &m->client->dev,
+ &menelaus_rtc_ops, THIS_MODULE);
+ if (IS_ERR(m->rtc)) {
+ if (alarm) {
+ menelaus_remove_irq_work(MENELAUS_RTCALM_IRQ);
+ device_init_wakeup(&m->client->dev, 0);
+ }
+ dev_err(&m->client->dev, "can't register RTC: %d\n",
+ (int) PTR_ERR(m->rtc));
+ the_menelaus->rtc = NULL;
+ }
+}
+
+#else
+
+static inline void menelaus_rtc_init(struct menelaus_chip *m)
+{
+ /* nothing */
+}
+
+#endif
+
+/*-----------------------------------------------------------------------*/
+
+static struct i2c_driver menelaus_i2c_driver;
+
+static int menelaus_probe(struct i2c_client *client)
+{
+ struct menelaus_chip *menelaus;
+ int rev = 0, val;
+ int err = 0;
+ struct menelaus_platform_data *menelaus_pdata =
+ client->dev.platform_data;
+
+ if (the_menelaus) {
+ dev_dbg(&client->dev, "only one %s for now\n",
+ DRIVER_NAME);
+ return -ENODEV;
+ }
+
+ menelaus = kzalloc(sizeof *menelaus, GFP_KERNEL);
+ if (!menelaus)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, menelaus);
+
+ the_menelaus = menelaus;
+ menelaus->client = client;
+
+ /* If a true probe check the device */
+ rev = menelaus_read_reg(MENELAUS_REV);
+ if (rev < 0) {
+ pr_err("device not found");
+ err = -ENODEV;
+ goto fail1;
+ }
+
+ /* Ack and disable all Menelaus interrupts */
+ menelaus_write_reg(MENELAUS_INT_ACK1, 0xff);
+ menelaus_write_reg(MENELAUS_INT_ACK2, 0xff);
+ menelaus_write_reg(MENELAUS_INT_MASK1, 0xff);
+ menelaus_write_reg(MENELAUS_INT_MASK2, 0xff);
+ menelaus->mask1 = 0xff;
+ menelaus->mask2 = 0xff;
+
+ /* Set output buffer strengths */
+ menelaus_write_reg(MENELAUS_MCT_CTRL1, 0x73);
+
+ if (client->irq > 0) {
+ err = request_irq(client->irq, menelaus_irq, IRQF_DISABLED,
+ DRIVER_NAME, menelaus);
+ if (err) {
+ dev_dbg(&client->dev, "can't get IRQ %d, err %d",
+ client->irq, err);
+ goto fail1;
+ }
+ }
+
+ mutex_init(&menelaus->lock);
+ INIT_WORK(&menelaus->work, menelaus_work);
+
+ pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f);
+
+ val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
+ if (val < 0)
+ goto fail2;
+ if (val & (1 << 7))
+ menelaus->vcore_hw_mode = 1;
+ else
+ menelaus->vcore_hw_mode = 0;
+
+ if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) {
+ err = menelaus_pdata->late_init(&client->dev);
+ if (err < 0)
+ goto fail2;
+ }
+
+ menelaus_rtc_init(menelaus);
+
+ return 0;
+fail2:
+ free_irq(client->irq, menelaus);
+ flush_scheduled_work();
+fail1:
+ kfree(menelaus);
+ return err;
+}
+
+static int __exit menelaus_remove(struct i2c_client *client)
+{
+ struct menelaus_chip *menelaus = i2c_get_clientdata(client);
+
+ free_irq(client->irq, menelaus);
+ kfree(menelaus);
+ i2c_set_clientdata(client, NULL);
+ the_menelaus = NULL;
+ return 0;
+}
+
+static struct i2c_driver menelaus_i2c_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = menelaus_probe,
+ .remove = __exit_p(menelaus_remove),
+};
+
+static int __init menelaus_init(void)
+{
+ int res;
+
+ res = i2c_add_driver(&menelaus_i2c_driver);
+ if (res < 0) {
+ pr_err("driver registration failed\n");
+ return res;
+ }
+
+ return 0;
+}
+
+static void __exit menelaus_exit(void)
+{
+ i2c_del_driver(&menelaus_i2c_driver);
+
+ /* FIXME: Shutdown menelaus parts that can be shut down */
+}
+
+MODULE_AUTHOR("Texas Instruments, Inc. (and others)");
+MODULE_DESCRIPTION("I2C interface for Menelaus.");
+MODULE_LICENSE("GPL");
+
+module_init(menelaus_init);
+module_exit(menelaus_exit);
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
new file mode 100644
index 000000000000..3de4b19ba08f
--- /dev/null
+++ b/drivers/i2c/chips/tsl2550.c
@@ -0,0 +1,460 @@
+/*
+ * tsl2550.c - Linux kernel modules for ambient light sensor
+ *
+ * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
+ * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+#define TSL2550_DRV_NAME "tsl2550"
+#define DRIVER_VERSION "1.1.1"
+
+/*
+ * Defines
+ */
+
+#define TSL2550_POWER_DOWN 0x00
+#define TSL2550_POWER_UP 0x03
+#define TSL2550_STANDARD_RANGE 0x18
+#define TSL2550_EXTENDED_RANGE 0x1d
+#define TSL2550_READ_ADC0 0x43
+#define TSL2550_READ_ADC1 0x83
+
+/*
+ * Structs
+ */
+
+struct tsl2550_data {
+ struct i2c_client *client;
+ struct mutex update_lock;
+
+ unsigned int power_state : 1;
+ unsigned int operating_mode : 1;
+};
+
+/*
+ * Global data
+ */
+
+static const u8 TSL2550_MODE_RANGE[2] = {
+ TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
+};
+
+/*
+ * Management functions
+ */
+
+static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
+{
+ struct tsl2550_data *data = i2c_get_clientdata(client);
+
+ int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]);
+
+ data->operating_mode = mode;
+
+ return ret;
+}
+
+static int tsl2550_set_power_state(struct i2c_client *client, int state)
+{
+ struct tsl2550_data *data = i2c_get_clientdata(client);
+ int ret;
+
+ if (state == 0)
+ ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN);
+ else {
+ ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
+
+ /* On power up we should reset operating mode also... */
+ tsl2550_set_operating_mode(client, data->operating_mode);
+ }
+
+ data->power_state = state;
+
+ return ret;
+}
+
+static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
+{
+ unsigned long end;
+ int loop = 0, ret = 0;
+
+ /*
+ * Read ADC channel waiting at most 400ms (see data sheet for further
+ * info).
+ * To avoid long busy wait we spin for few milliseconds then
+ * start sleeping.
+ */
+ end = jiffies + msecs_to_jiffies(400);
+ while (time_before(jiffies, end)) {
+ i2c_smbus_write_byte(client, cmd);
+
+ if (loop++ < 5)
+ mdelay(1);
+ else
+ msleep(1);
+
+ ret = i2c_smbus_read_byte(client);
+ if (ret < 0)
+ return ret;
+ else if (ret & 0x0080)
+ break;
+ }
+ if (!(ret & 0x80))
+ return -EIO;
+ return ret & 0x7f; /* remove the "valid" bit */
+}
+
+/*
+ * LUX calculation
+ */
+
+#define TSL2550_MAX_LUX 1846
+
+static const u8 ratio_lut[] = {
+ 100, 100, 100, 100, 100, 100, 100, 100,
+ 100, 100, 100, 100, 100, 100, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 98, 98, 98, 98, 98,
+ 98, 98, 97, 97, 97, 97, 97, 96,
+ 96, 96, 96, 95, 95, 95, 94, 94,
+ 93, 93, 93, 92, 92, 91, 91, 90,
+ 89, 89, 88, 87, 87, 86, 85, 84,
+ 83, 82, 81, 80, 79, 78, 77, 75,
+ 74, 73, 71, 69, 68, 66, 64, 62,
+ 60, 58, 56, 54, 52, 49, 47, 44,
+ 42, 41, 40, 40, 39, 39, 38, 38,
+ 37, 37, 37, 36, 36, 36, 35, 35,
+ 35, 35, 34, 34, 34, 34, 33, 33,
+ 33, 33, 32, 32, 32, 32, 32, 31,
+ 31, 31, 31, 31, 30, 30, 30, 30,
+ 30,
+};
+
+static const u16 count_lut[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46,
+ 49, 53, 57, 61, 65, 69, 73, 77,
+ 81, 85, 89, 93, 97, 101, 105, 109,
+ 115, 123, 131, 139, 147, 155, 163, 171,
+ 179, 187, 195, 203, 211, 219, 227, 235,
+ 247, 263, 279, 295, 311, 327, 343, 359,
+ 375, 391, 407, 423, 439, 455, 471, 487,
+ 511, 543, 575, 607, 639, 671, 703, 735,
+ 767, 799, 831, 863, 895, 927, 959, 991,
+ 1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
+ 1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
+ 2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
+ 3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015,
+};
+
+/*
+ * This function is described into Taos TSL2550 Designer's Notebook
+ * pages 2, 3.
+ */
+static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
+{
+ unsigned int lux;
+
+ /* Look up count from channel values */
+ u16 c0 = count_lut[ch0];
+ u16 c1 = count_lut[ch1];
+
+ /*
+ * Calculate ratio.
+ * Note: the "128" is a scaling factor
+ */
+ u8 r = 128;
+
+ /* Avoid division by 0 and count 1 cannot be greater than count 0 */
+ if (c0 && (c1 <= c0))
+ r = c1 * 128 / c0;
+ else
+ return -1;
+
+ /* Calculate LUX */
+ lux = ((c0 - c1) * ratio_lut[r]) / 256;
+
+ /* LUX range check */
+ return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
+}
+
+/*
+ * SysFS support
+ */
+
+static ssize_t tsl2550_show_power_state(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+ return sprintf(buf, "%u\n", data->power_state);
+}
+
+static ssize_t tsl2550_store_power_state(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tsl2550_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ int ret;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ ret = tsl2550_set_power_state(client, val);
+ mutex_unlock(&data->update_lock);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
+ tsl2550_show_power_state, tsl2550_store_power_state);
+
+static ssize_t tsl2550_show_operating_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+ return sprintf(buf, "%u\n", data->operating_mode);
+}
+
+static ssize_t tsl2550_store_operating_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tsl2550_data *data = i2c_get_clientdata(client);
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ int ret;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+
+ if (data->power_state == 0)
+ return -EBUSY;
+
+ mutex_lock(&data->update_lock);
+ ret = tsl2550_set_operating_mode(client, val);
+ mutex_unlock(&data->update_lock);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
+ tsl2550_show_operating_mode, tsl2550_store_operating_mode);
+
+static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
+{
+ u8 ch0, ch1;
+ int ret;
+
+ ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
+ if (ret < 0)
+ return ret;
+ ch0 = ret;
+
+ mdelay(1);
+
+ ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
+ if (ret < 0)
+ return ret;
+ ch1 = ret;
+
+ /* Do the job */
+ ret = tsl2550_calculate_lux(ch0, ch1);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t tsl2550_show_lux1_input(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct tsl2550_data *data = i2c_get_clientdata(client);
+ int ret;
+
+ /* No LUX data if not operational */
+ if (!data->power_state)
+ return -EBUSY;
+
+ mutex_lock(&data->update_lock);
+ ret = __tsl2550_show_lux(client, buf);
+ mutex_unlock(&data->update_lock);
+
+ return ret;
+}
+
+static DEVICE_ATTR(lux1_input, S_IRUGO,
+ tsl2550_show_lux1_input, NULL);
+
+static struct attribute *tsl2550_attributes[] = {
+ &dev_attr_power_state.attr,
+ &dev_attr_operating_mode.attr,
+ &dev_attr_lux1_input.attr,
+ NULL
+};
+
+static const struct attribute_group tsl2550_attr_group = {
+ .attrs = tsl2550_attributes,
+};
+
+/*
+ * Initialization function
+ */
+
+static int tsl2550_init_client(struct i2c_client *client)
+{
+ struct tsl2550_data *data = i2c_get_clientdata(client);
+ int err;
+
+ /*
+ * Probe the chip. To do so we try to power up the device and then to
+ * read back the 0x03 code
+ */
+ err = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
+ if (err < 0)
+ return err;
+ mdelay(1);
+ if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
+ return -ENODEV;
+ data->power_state = 1;
+
+ /* Set the default operating mode */
+ err = i2c_smbus_write_byte(client,
+ TSL2550_MODE_RANGE[data->operating_mode]);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+
+static struct i2c_driver tsl2550_driver;
+static int __devinit tsl2550_probe(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct tsl2550_data *data;
+ int *opmode, err = 0;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
+ err = -EIO;
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ data->client = client;
+ i2c_set_clientdata(client, data);
+
+ /* Check platform data */
+ opmode = client->dev.platform_data;
+ if (opmode) {
+ if (*opmode < 0 || *opmode > 1) {
+ dev_err(&client->dev, "invalid operating_mode (%d)\n",
+ *opmode);
+ err = -EINVAL;
+ goto exit_kfree;
+ }
+ data->operating_mode = *opmode;
+ } else
+ data->operating_mode = 0; /* default mode is standard */
+ dev_info(&client->dev, "%s operating mode\n",
+ data->operating_mode ? "extended" : "standard");
+
+ mutex_init(&data->update_lock);
+
+ /* Initialize the TSL2550 chip */
+ err = tsl2550_init_client(client);
+ if (err)
+ goto exit_kfree;
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
+ if (err)
+ goto exit_kfree;
+
+ dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
+
+ return 0;
+
+exit_kfree:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int __devexit tsl2550_remove(struct i2c_client *client)
+{
+ sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
+
+ /* Power down the device */
+ tsl2550_set_power_state(client, 0);
+
+ kfree(i2c_get_clientdata(client));
+
+ return 0;
+}
+
+static struct i2c_driver tsl2550_driver = {
+ .driver = {
+ .name = TSL2550_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = tsl2550_probe,
+ .remove = __devexit_p(tsl2550_remove),
+};
+
+static int __init tsl2550_init(void)
+{
+ return i2c_add_driver(&tsl2550_driver);
+}
+
+static void __exit tsl2550_exit(void)
+{
+ i2c_del_driver(&tsl2550_driver);
+}
+
+MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
+MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tsl2550_init);
+module_exit(tsl2550_exit);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 435925eba437..d663e6960d93 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -207,6 +207,7 @@ EXPORT_SYMBOL_GPL(i2c_bus_type);
* i2c_new_device - instantiate an i2c device for use with a new style driver
* @adap: the adapter managing the device
* @info: describes one I2C device; bus_num is ignored
+ * Context: can sleep
*
* Create a device to work with a new style i2c driver, where binding is
* handled through driver model probe()/remove() methods. This call is not
@@ -255,6 +256,7 @@ EXPORT_SYMBOL_GPL(i2c_new_device);
/**
* i2c_unregister_device - reverse effect of i2c_new_device()
* @client: value returned from i2c_new_device()
+ * Context: can sleep
*/
void i2c_unregister_device(struct i2c_client *client)
{
@@ -286,7 +288,6 @@ void i2c_adapter_dev_release(struct device *dev)
struct i2c_adapter *adap = to_i2c_adapter(dev);
complete(&adap->dev_released);
}
-EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); /* exported to i2c-isa */
static ssize_t
show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -305,7 +306,6 @@ struct class i2c_adapter_class = {
.name = "i2c-adapter",
.dev_attrs = i2c_adapter_attrs,
};
-EXPORT_SYMBOL_GPL(i2c_adapter_class); /* exported to i2c-isa */
static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
{
@@ -379,6 +379,7 @@ out_list:
/**
* i2c_add_adapter - declare i2c adapter, use dynamic bus number
* @adapter: the adapter to add
+ * Context: can sleep
*
* This routine is used to declare an I2C adapter when its bus number
* doesn't matter. Examples: for I2C adapters dynamically added by
@@ -416,6 +417,7 @@ EXPORT_SYMBOL(i2c_add_adapter);
/**
* i2c_add_numbered_adapter - declare i2c adapter, use static bus number
* @adap: the adapter to register (with adap->nr initialized)
+ * Context: can sleep
*
* This routine is used to declare an I2C adapter when its bus number
* matters. Example: for I2C adapters from system-on-chip CPUs, or
@@ -463,6 +465,14 @@ retry:
}
EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter);
+/**
+ * i2c_del_adapter - unregister I2C adapter
+ * @adap: the adapter being unregistered
+ * Context: can sleep
+ *
+ * This unregisters an I2C adapter which was previously registered
+ * by @i2c_add_adapter or @i2c_add_numbered_adapter.
+ */
int i2c_del_adapter(struct i2c_adapter *adap)
{
struct list_head *item, *_n;
@@ -598,6 +608,7 @@ EXPORT_SYMBOL(i2c_register_driver);
/**
* i2c_del_driver - unregister I2C driver
* @driver: the driver being unregistered
+ * Context: can sleep
*/
void i2c_del_driver(struct i2c_driver *driver)
{
@@ -1331,10 +1342,14 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command,
EXPORT_SYMBOL(i2c_smbus_write_block_data);
/* Returns the number of read bytes */
-s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values)
+s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command,
+ u8 length, u8 *values)
{
union i2c_smbus_data data;
+ if (length > I2C_SMBUS_BLOCK_MAX)
+ length = I2C_SMBUS_BLOCK_MAX;
+ data.block[0] = length;
if (i2c_smbus_xfer(client->adapter,client->addr,client->flags,
I2C_SMBUS_READ,command,
I2C_SMBUS_I2C_BLOCK_DATA,&data))
@@ -1455,7 +1470,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
- msg[1].len = I2C_SMBUS_BLOCK_MAX;
+ msg[1].len = data->block[0];
} else {
msg[0].len = data->block[0] + 1;
if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
@@ -1511,9 +1526,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
data->word = msgbuf1[0] | (msgbuf1[1] << 8);
break;
case I2C_SMBUS_I2C_BLOCK_DATA:
- /* fixed at 32 for now */
- data->block[0] = I2C_SMBUS_BLOCK_MAX;
- for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
+ for (i = 0; i < data->block[0]; i++)
data->block[i+1] = msgbuf1[i];
break;
case I2C_SMBUS_BLOCK_DATA:
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index e7a709710592..64eee9551b22 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -283,6 +283,7 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
(data_arg.size != I2C_SMBUS_WORD_DATA) &&
(data_arg.size != I2C_SMBUS_PROC_CALL) &&
(data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
+ (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
(data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
(data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
dev_dbg(&client->adapter->dev,
@@ -329,10 +330,18 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
(data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
+ (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
(data_arg.read_write == I2C_SMBUS_WRITE)) {
if (copy_from_user(&temp, data_arg.data, datasize))
return -EFAULT;
}
+ if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
+ /* Convert old I2C block commands to the new
+ convention. This preserves binary compatibility. */
+ data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
+ if (data_arg.read_write == I2C_SMBUS_READ)
+ temp.block[0] = I2C_SMBUS_BLOCK_MAX;
+ }
res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
data_arg.read_write,
data_arg.command,data_arg.size,&temp);
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 444a0b84f5bd..c89b5f4b2d04 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -18,10 +18,10 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/scatterlist.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <asm/ecard.h>
-#include <asm/io.h>
#define ICS_IDENT_OFFSET 0x2280
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 886091bc7db0..fbfea46a34f2 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -414,12 +414,6 @@ 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_CSE1_16_RESET
- REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, val);
-#endif
-#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
- REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, val);
-#endif
#ifdef CONFIG_ETRAX_IDE_PB7_RESET
port_pb_dir_shadow = port_pb_dir_shadow |
IO_STATE(R_PORT_PB_DIR, dir7, output);
@@ -690,6 +684,8 @@ static void tune_cris_ide(ide_drive_t *drive, u8 pio)
{
int setup, strobe, hold;
+ pio = ide_get_best_pio_mode(drive, pio, 4);
+
switch(pio)
{
case 0:
@@ -820,6 +816,7 @@ init_e100_ide (void)
hwif->dma_host_on = &cris_dma_on;
hwif->dma_off_quietly = &cris_dma_off;
hwif->cbl = ATA_CBL_PATA40;
+ hwif->pio_mask = ATA_PIO4,
hwif->ultra_mask = cris_ultra_mask;
hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
hwif->autodma = 1;
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index f429be88c4f9..ae8e1a64b8ad 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -99,6 +99,8 @@
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <scsi/scsi_ioctl.h>
+
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -1258,19 +1260,25 @@ static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t
set_bit(PC_DMA_RECOMMENDED, &pc->flags);
}
-static int
+static void
idefloppy_blockpc_cmd(idefloppy_floppy_t *floppy, idefloppy_pc_t *pc, struct request *rq)
{
- /*
- * just support eject for now, it would not be hard to make the
- * REQ_BLOCK_PC support fully-featured
- */
- if (rq->cmd[0] != IDEFLOPPY_START_STOP_CMD)
- return 1;
-
idefloppy_init_pc(pc);
+ pc->callback = &idefloppy_rw_callback;
memcpy(pc->c, rq->cmd, sizeof(pc->c));
- return 0;
+ pc->rq = rq;
+ pc->b_count = rq->data_len;
+ if (rq->data_len && rq_data_dir(rq) == WRITE)
+ set_bit(PC_WRITING, &pc->flags);
+ pc->buffer = rq->data;
+ if (rq->bio)
+ set_bit(PC_DMA_RECOMMENDED, &pc->flags);
+
+ /*
+ * possibly problematic, doesn't look like ide-floppy correctly
+ * handled scattered requests if dma fails...
+ */
+ pc->request_transfer = pc->buffer_size = rq->data_len;
}
/*
@@ -1317,10 +1325,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
pc = (idefloppy_pc_t *) rq->buffer;
} else if (blk_pc_request(rq)) {
pc = idefloppy_next_pc_storage(drive);
- if (idefloppy_blockpc_cmd(floppy, pc, rq)) {
- idefloppy_do_end_request(drive, 0, 0);
- return ide_stopped;
- }
+ idefloppy_blockpc_cmd(floppy, pc, rq);
} else {
blk_dump_rq_flags(rq,
"ide-floppy: unsupported command in queue");
@@ -2096,7 +2101,21 @@ static int idefloppy_ioctl(struct inode *inode, struct file *file,
case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
return idefloppy_get_format_progress(drive, argp);
}
- return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+ /*
+ * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+ * and CDROM_SEND_PACKET (legacy) ioctls
+ */
+ if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+ err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
+ bdev->bd_disk, cmd, argp);
+ else
+ err = -ENOTTY;
+
+ if (err == -ENOTTY)
+ err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+ return err;
}
static int idefloppy_media_changed(struct gendisk *disk)
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index c5b5011da56e..484c50e71446 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,7 +55,7 @@
#include <asm/bitops.h>
static int __ide_end_request(ide_drive_t *drive, struct request *rq,
- int uptodate, int nr_sectors)
+ int uptodate, unsigned int nr_bytes)
{
int ret = 1;
@@ -64,7 +64,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
* complete the whole request right now
*/
if (blk_noretry_request(rq) && end_io_error(uptodate))
- nr_sectors = rq->hard_nr_sectors;
+ nr_bytes = rq->hard_nr_sectors << 9;
if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
rq->errors = -EIO;
@@ -78,7 +78,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
HWGROUP(drive)->hwif->ide_dma_on(drive);
}
- if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+ if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
add_disk_randomness(rq->rq_disk);
if (!list_empty(&rq->queuelist))
blkdev_dequeue_request(rq);
@@ -103,6 +103,7 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
{
+ unsigned int nr_bytes = nr_sectors << 9;
struct request *rq;
unsigned long flags;
int ret = 1;
@@ -114,10 +115,14 @@ int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
spin_lock_irqsave(&ide_lock, flags);
rq = HWGROUP(drive)->rq;
- if (!nr_sectors)
- nr_sectors = rq->hard_cur_sectors;
+ if (!nr_bytes) {
+ if (blk_pc_request(rq))
+ nr_bytes = rq->data_len;
+ else
+ nr_bytes = rq->hard_cur_sectors << 9;
+ }
- ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
+ ret = __ide_end_request(drive, rq, uptodate, nr_bytes);
spin_unlock_irqrestore(&ide_lock, flags);
return ret;
@@ -219,11 +224,12 @@ 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->id->capability & 1) == 0)
- break;
if (drive->hwif->ide_dma_check == NULL)
break;
drive->hwif->dma_off_quietly(drive);
+ /*
+ * TODO: respect ->using_dma setting
+ */
ide_set_dma(drive);
break;
}
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 074bb32a4a40..92a6c7bcf527 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -249,12 +249,34 @@ static int ide_scan_pio_blacklist (char *model)
return -1;
}
+unsigned int ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
+{
+ struct hd_driveid *id = drive->id;
+ int cycle_time = 0;
+
+ if (id->field_valid & 2) {
+ if (id->capability & 8)
+ cycle_time = id->eide_pio_iordy;
+ else
+ cycle_time = id->eide_pio;
+ }
+
+ /* conservative "downgrade" for all pre-ATA2 drives */
+ if (pio < 3) {
+ if (cycle_time && cycle_time < ide_pio_timings[pio].cycle_time)
+ cycle_time = 0; /* use standard timing */
+ }
+
+ return cycle_time ? cycle_time : ide_pio_timings[pio].cycle_time;
+}
+
+EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
+
/**
* ide_get_best_pio_mode - get PIO mode from drive
* @drive: drive to consider
* @mode_wanted: preferred mode
* @max_mode: highest allowed mode
- * @d: PIO data
*
* This routine returns the recommended PIO settings for a given drive,
* based on the drive->id information and the ide_pio_blacklist[].
@@ -263,22 +285,18 @@ static int ide_scan_pio_blacklist (char *model)
* This is used by most chipset support modules when "auto-tuning".
*/
-u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
{
int pio_mode;
- int cycle_time = 0;
- int use_iordy = 0;
struct hd_driveid* id = drive->id;
int overridden = 0;
- if (mode_wanted != 255) {
- pio_mode = mode_wanted;
- use_iordy = (pio_mode > 2);
- } else if (!drive->id) {
- pio_mode = 0;
- } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
- overridden = 1;
- use_iordy = (pio_mode > 2);
+ if (mode_wanted != 255)
+ return min_t(u8, mode_wanted, max_mode);
+
+ if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 &&
+ (pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+ printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
} else {
pio_mode = id->tPIO;
if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */
@@ -286,9 +304,7 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
overridden = 1;
}
if (id->field_valid & 2) { /* drive implements ATA2? */
- if (id->capability & 8) { /* drive supports use_iordy? */
- use_iordy = 1;
- cycle_time = id->eide_pio_iordy;
+ if (id->capability & 8) { /* IORDY supported? */
if (id->eide_pio_modes & 7) {
overridden = 0;
if (id->eide_pio_modes & 4)
@@ -298,31 +314,27 @@ u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_p
else
pio_mode = 3;
}
- } else {
- cycle_time = id->eide_pio;
}
}
+ if (overridden)
+ printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
+ drive->name);
+
/*
* Conservative "downgrade" for all pre-ATA2 drives
*/
- if (pio_mode && pio_mode < 4) {
+ if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_DOWNGRADE) == 0 &&
+ pio_mode && pio_mode < 4) {
pio_mode--;
- overridden = 1;
- if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
- cycle_time = 0; /* use standard timing */
+ printk(KERN_INFO "%s: applying conservative "
+ "PIO \"downgrade\"\n", drive->name);
}
}
- if (pio_mode > max_mode) {
+
+ if (pio_mode > max_mode)
pio_mode = max_mode;
- cycle_time = 0;
- }
- if (d) {
- d->pio_mode = pio_mode;
- d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
- d->use_iordy = use_iordy;
- d->overridden = overridden;
- }
+
return pio_mode;
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index cc5801399467..5a4c5ea12f89 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1073,14 +1073,14 @@ static int init_irq (ide_hwif_t *hwif)
hwgroup->hwif->next = hwif;
spin_unlock_irq(&ide_lock);
} else {
- hwgroup = kmalloc_node(sizeof(ide_hwgroup_t), GFP_KERNEL,
+ hwgroup = kmalloc_node(sizeof(ide_hwgroup_t),
+ GFP_KERNEL | __GFP_ZERO,
hwif_to_node(hwif->drives[0].hwif));
if (!hwgroup)
goto out_up;
hwif->hwgroup = hwgroup;
- memset(hwgroup, 0, sizeof(ide_hwgroup_t));
hwgroup->hwif = hwif->next = hwif;
hwgroup->rq = NULL;
hwgroup->handler = NULL;
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
index e6cb8593b5ba..daffbb9797e1 100644
--- a/drivers/ide/ide-timing.h
+++ b/drivers/ide/ide-timing.h
@@ -106,23 +106,6 @@ static struct ide_timing ide_timing[] = {
#define XFER_EPIO 0x01
#define XFER_PIO 0x00
-static short ide_find_best_pio_mode(ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
- short best = 0;
-
- if (id->field_valid & 2) { /* EIDE PIO modes */
-
- if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
- (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
- (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best;
- }
-
- return (drive->id->tPIO == 2) ? XFER_PIO_2 :
- (drive->id->tPIO == 1) ? XFER_PIO_1 :
- (drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
-}
-
static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
{
q->setup = EZ(t->setup * 1000, T);
@@ -212,7 +195,8 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing
*/
if ((speed & XFER_MODE) != XFER_PIO) {
- ide_timing_compute(drive, ide_find_best_pio_mode(drive), &p, T, UT);
+ u8 pio = ide_get_best_pio_mode(drive, 255, 5);
+ ide_timing_compute(drive, XFER_PIO_0 + pio, &p, T, UT);
ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index c948a5c17a5d..5e88a060df06 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -16,10 +16,6 @@
* (usually 14 & 15).
* There can be up to two drives per interface, as per the ATA-2 spec.
*
- * Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64
- * Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
- * Tertiary: ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
- * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
* ...
*
* From hd.c:
@@ -47,80 +43,6 @@
* This was a rewrite of just about everything from hd.c, though some original
* code is still sprinkled about. Think of it as a major evolution, with
* inspiration from lots of linux users, esp. hamish@zot.apana.org.au
- *
- * Version 1.0 ALPHA initial code, primary i/f working okay
- * Version 1.3 BETA dual i/f on shared irq tested & working!
- * Version 1.4 BETA added auto probing for irq(s)
- * Version 1.5 BETA added ALPHA (untested) support for IDE cd-roms,
- * ...
- * Version 5.50 allow values as small as 20 for idebus=
- * Version 5.51 force non io_32bit in drive_cmd_intr()
- * change delay_10ms() to delay_50ms() to fix problems
- * Version 5.52 fix incorrect invalidation of removable devices
- * add "hdx=slow" command line option
- * Version 5.60 start to modularize the driver; the disk and ATAPI
- * drivers can be compiled as loadable modules.
- * move IDE probe code to ide-probe.c
- * move IDE disk code to ide-disk.c
- * add support for generic IDE device subdrivers
- * add m68k code from Geert Uytterhoeven
- * probe all interfaces by default
- * add ioctl to (re)probe an interface
- * Version 6.00 use per device request queues
- * attempt to optimize shared hwgroup performance
- * add ioctl to manually adjust bandwidth algorithms
- * add kerneld support for the probe module
- * fix bug in ide_error()
- * fix bug in the first ide_get_lock() call for Atari
- * don't flush leftover data for ATAPI devices
- * Version 6.01 clear hwgroup->active while the hwgroup sleeps
- * support HDIO_GETGEO for floppies
- * Version 6.02 fix ide_ack_intr() call
- * check partition table on floppies
- * Version 6.03 handle bad status bit sequencing in ide_wait_stat()
- * Version 6.10 deleted old entries from this list of updates
- * replaced triton.c with ide-dma.c generic PCI DMA
- * added support for BIOS-enabled UltraDMA
- * rename all "promise" things to "pdc4030"
- * fix EZ-DRIVE handling on small disks
- * Version 6.11 fix probe error in ide_scan_devices()
- * fix ancient "jiffies" polling bugs
- * mask all hwgroup interrupts on each irq entry
- * Version 6.12 integrate ioctl and proc interfaces
- * fix parsing of "idex=" command line parameter
- * Version 6.13 add support for ide4/ide5 courtesy rjones@orchestream.com
- * Version 6.14 fixed IRQ sharing among PCI devices
- * Version 6.15 added SMP awareness to IDE drivers
- * Version 6.16 fixed various bugs; even more SMP friendly
- * Version 6.17 fix for newest EZ-Drive problem
- * Version 6.18 default unpartitioned-disk translation now "BIOS LBA"
- * Version 6.19 Re-design for a UNIFORM driver for all platforms,
- * model based on suggestions from Russell King and
- * Geert Uytterhoeven
- * Promise DC4030VL now supported.
- * add support for ide6/ide7
- * delay_50ms() changed to ide_delay_50ms() and exported.
- * Version 6.20 Added/Fixed Generic ATA-66 support and hwif detection.
- * Added hdx=flash to allow for second flash disk
- * detection w/o the hang loop.
- * Added support for ide8/ide9
- * Added idex=ata66 for the quirky chipsets that are
- * ATA-66 compliant, but have yet to determine a method
- * of verification of the 80c cable presence.
- * Specifically Promise's PDC20262 chipset.
- * Version 6.21 Fixing/Fixed SMP spinlock issue with insight from an old
- * hat that clarified original low level driver design.
- * Version 6.30 Added SMP support; fixed multmode issues. -ml
- * Version 6.31 Debug Share INTR's and request queue streaming
- * Native ATA-100 support
- * Prep for Cascades Project
- * Version 7.00alpha First named revision of ide rearrange
- *
- * Some additional driver compile-time options are in ./include/linux/ide.h
- *
- * To do, in likely order of completion:
- * - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
*/
#define REVISION "Revision: 7.00alpha2"
@@ -455,6 +377,10 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->straight8 = tmp_hwif->straight8;
hwif->bus_state = tmp_hwif->bus_state;
+ hwif->host_flags = tmp_hwif->host_flags;
+
+ hwif->pio_mask = tmp_hwif->pio_mask;
+
hwif->atapi_dma = tmp_hwif->atapi_dma;
hwif->ultra_mask = tmp_hwif->ultra_mask;
hwif->mwdma_mask = tmp_hwif->mwdma_mask;
@@ -1171,10 +1097,6 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
return 0;
}
- case CDROMEJECT:
- case CDROMCLOSETRAY:
- return scsi_cmd_ioctl(file, bdev->bd_disk, cmd, p);
-
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index df17ed68c0bc..9b9c4761cb7d 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -115,13 +115,12 @@ static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
int time1, time2;
u8 param1, param2, param3, param4;
unsigned long flags;
- ide_pio_data_t d;
int bus_speed = system_bus_clock();
- pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
+ pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO);
/* calculate timing, according to PIO mode */
- time1 = d.cycle_time;
+ time1 = ide_pio_cycle_time(drive, pio);
time2 = ide_pio_timings[pio].active_time;
param3 = param1 = (time2 * bus_speed + 999) / 1000;
param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
@@ -212,10 +211,12 @@ static int __init ali14xx_probe(void)
mate = &ide_hwifs[1];
hwif->chipset = ide_ali14xx;
+ hwif->pio_mask = ATA_PIO4;
hwif->tuneproc = &ali14xx_tune_drive;
hwif->mate = mate;
mate->chipset = ide_ali14xx;
+ mate->pio_mask = ATA_PIO4;
mate->tuneproc = &ali14xx_tune_drive;
mate->mate = hwif;
mate->channel = 1;
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 36a3f0ac6162..6c01d951d074 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -71,7 +71,7 @@ static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
{
unsigned long flags;
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
if (pio >= 3) {
spin_lock_irqsave(&ide_lock, flags);
@@ -123,6 +123,7 @@ static int __init dtc2278_probe(void)
hwif->serialized = 1;
hwif->chipset = ide_dtc2278;
+ hwif->pio_mask = ATA_PIO4;
hwif->tuneproc = &tune_dtc2278;
hwif->drives[0].no_unmask = 1;
hwif->drives[1].no_unmask = 1;
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index e1e9d9d6893f..f0829b83e970 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -8,6 +8,7 @@
* more details.
*/
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
@@ -54,6 +55,7 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = {
*/
int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
/*
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 7f4c0a5050a1..8f2db8dd35f7 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -719,74 +719,25 @@ static int __init hd_init(void)
device_timer.function = hd_times_out;
blk_queue_hardsect_size(hd_queue, 512);
-#ifdef __i386__
if (!NR_HD) {
- extern struct drive_info drive_info;
- unsigned char *BIOS = (unsigned char *) &drive_info;
- unsigned long flags;
- int cmos_disks;
-
- for (drive=0 ; drive<2 ; drive++) {
- hd_info[drive].cyl = *(unsigned short *) BIOS;
- hd_info[drive].head = *(2+BIOS);
- hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
- hd_info[drive].ctl = *(8+BIOS);
- hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
- hd_info[drive].sect = *(14+BIOS);
-#ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
- if (hd_info[drive].cyl && NR_HD == drive)
- NR_HD++;
-#endif
- BIOS += 16;
- }
-
- /*
- We query CMOS about hard disks : it could be that
- we have a SCSI/ESDI/etc controller that is BIOS
- compatible with ST-506, and thus showing up in our
- BIOS table, but not register compatible, and therefore
- not present in CMOS.
-
- Furthermore, we will assume that our ST-506 drives
- <if any> are the primary drives in the system, and
- the ones reflected as drive 1 or 2.
-
- The first drive is stored in the high nibble of CMOS
- byte 0x12, the second in the low nibble. This will be
- either a 4 bit drive type or 0xf indicating use byte 0x19
- for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
-
- Needless to say, a non-zero value means we have
- an AT controller hard disk for that drive.
-
- Currently the rtc_lock is a bit academic since this
- driver is non-modular, but someday... ? Paul G.
- */
-
- spin_lock_irqsave(&rtc_lock, flags);
- cmos_disks = CMOS_READ(0x12);
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- if (cmos_disks & 0xf0) {
- if (cmos_disks & 0x0f)
- NR_HD = 2;
- else
- NR_HD = 1;
- }
- }
-#endif /* __i386__ */
-#ifdef __arm__
- if (!NR_HD) {
- /* We don't know anything about the drive. This means
+ /*
+ * We don't know anything about the drive. This means
* that you *MUST* specify the drive parameters to the
* kernel yourself.
+ *
+ * If we were on an i386, we used to read this info from
+ * the BIOS or CMOS. This doesn't work all that well,
+ * since this assumes that this is a primary or secondary
+ * drive, and if we're using this legacy driver, it's
+ * probably an auxilliary controller added to recover
+ * legacy data off an ST-506 drive. Either way, it's
+ * definitely safest to have the user explicitly specify
+ * the information.
*/
printk("hd: no drives specified - use hd=cyl,head,sectors"
" on kernel command line\n");
- }
-#endif
- if (!NR_HD)
goto out;
+ }
for (drive=0 ; drive < NR_HD ; drive++) {
struct gendisk *disk = alloc_disk(64);
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index c8f353b1296f..bfaa2025173b 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -203,19 +203,21 @@ static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
{
int active_time, recovery_time;
int active_cycles, recovery_cycles;
- ide_pio_data_t d;
int bus_speed = system_bus_clock();
if (pio) {
- pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-
+ unsigned int cycle_time;
+
+ pio = ide_get_best_pio_mode(drive, pio, 5);
+ cycle_time = ide_pio_cycle_time(drive, pio);
+
/*
* Just like opti621.c we try to calculate the
* actual cycle time for recovery and activity
* according system bus speed.
*/
active_time = ide_pio_timings[pio].active_time;
- recovery_time = d.cycle_time
+ recovery_time = cycle_time
- active_time
- ide_pio_timings[pio].setup_time;
/*
@@ -331,12 +333,14 @@ int __init ht6560b_init(void)
hwif->chipset = ide_ht6560b;
hwif->selectproc = &ht6560b_selectproc;
+ hwif->pio_mask = ATA_PIO5;
hwif->tuneproc = &tune_ht6560b;
hwif->serialized = 1; /* is this needed? */
hwif->mate = mate;
mate->chipset = ide_ht6560b;
mate->selectproc = &ht6560b_selectproc;
+ mate->pio_mask = ATA_PIO5;
mate->tuneproc = &tune_ht6560b;
mate->serialized = 1; /* is this needed? */
mate->mate = hwif;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 2f3977f195b7..4cdb519f9832 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -386,6 +386,7 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 7783745dd167..8b87a424094a 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -252,38 +252,38 @@ static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
{
- ide_pio_data_t d;
int base = HWIF(drive)->select_data;
+ unsigned int cycle_time;
int active_time = 175;
int recovery_time = 415; /* worst case values from the dos driver */
if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
- pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
+ cycle_time = ide_pio_cycle_time(drive, pio);
switch (pio) {
case 0: break;
case 3:
- if (d.cycle_time >= 110) {
+ if (cycle_time >= 110) {
active_time = 86;
- recovery_time = d.cycle_time - 102;
+ recovery_time = cycle_time - 102;
} else
printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
break;
case 4:
- if (d.cycle_time >= 69) {
+ if (cycle_time >= 69) {
active_time = 70;
- recovery_time = d.cycle_time - 61;
+ recovery_time = cycle_time - 61;
} else
printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
break;
default:
- if (d.cycle_time >= 180) {
+ if (cycle_time >= 180) {
active_time = 110;
- recovery_time = d.cycle_time - 120;
+ recovery_time = cycle_time - 120;
} else {
active_time = ide_pio_timings[pio].active_time;
- recovery_time = d.cycle_time
- -active_time;
+ recovery_time = cycle_time - active_time;
}
}
printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
@@ -346,6 +346,7 @@ static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
hwif->drives[1].drive_data = data1;
hwif->drives[0].io_32bit =
hwif->drives[1].io_32bit = 1;
+ hwif->pio_mask = ATA_PIO4;
hwif->tuneproc = tuneproc;
probe_hwif_init(hwif);
}
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index ddc403a0bd82..d2862e638bc5 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -110,7 +110,7 @@ static void tune_umc (ide_drive_t *drive, u8 pio)
unsigned long flags;
ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
drive->name, pio, pio_to_umc[pio]);
spin_lock_irqsave(&ide_lock, flags);
@@ -149,10 +149,12 @@ static int __init umc8672_probe(void)
mate = &ide_hwifs[1];
hwif->chipset = ide_umc8672;
+ hwif->pio_mask = ATA_PIO4;
hwif->tuneproc = &tune_umc;
hwif->mate = mate;
mate->chipset = ide_umc8672;
+ mate->pio_mask = ATA_PIO4;
mate->tuneproc = &tune_umc;
mate->mate = hwif;
mate->channel = 1;
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 2e7013a2a7f6..2ba6a054b861 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -106,7 +106,7 @@ static void auide_tune_drive(ide_drive_t *drive, byte pio)
u8 speed;
/* get the best pio mode for the drive */
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n",
drive->name, pio);
@@ -692,6 +692,8 @@ static int au_ide_probe(struct device *dev)
hwif->swdma_mask = 0x0;
#endif
+ hwif->pio_mask = ATA_PIO4;
+
hwif->noprobe = 0;
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 6e935d7c63fd..c2e29571b007 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -165,12 +165,11 @@ static int __devinit swarm_ide_init_module(void)
goto out;
}
- if (!(pldev = kmalloc(sizeof (*pldev), GFP_KERNEL))) {
+ if (!(pldev = kzalloc(sizeof (*pldev), GFP_KERNEL))) {
err = -ENOMEM;
goto out_unregister_driver;
}
- memset (pldev, 0, sizeof (*pldev));
pldev->name = swarm_ide_string;
pldev->id = 0;
pldev->dev.release = swarm_ide_platform_release;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index e5d09367627e..74432830abf7 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -142,7 +142,7 @@ static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
(void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
}
@@ -174,12 +174,6 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
{
int bus_speed = system_bus_clock();
- if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
-
if (bus_speed <= 33)
pci_set_drvdata(dev, (void *) aec6xxx_33_base);
else
@@ -271,48 +265,48 @@ static ide_pci_device_t aec62xx_chipsets[] __devinitdata = {
.init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x07, /* udma0-2 */
},{ /* 1 */
.name = "AEC6260",
.init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 2 */
.name = "AEC6260R",
.init_setup = init_setup_aec62xx,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = NEVER_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 3 */
.name = "AEC6280",
.init_setup = init_setup_aec6x80,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 4 */
.name = "AEC6280R",
.init_setup = init_setup_aec6x80,
.init_chipset = init_chipset_aec62xx,
.init_hwif = init_hwif_aec62xx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
}
};
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 8a6b27b3bcc3..5511c86733dc 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -295,7 +295,6 @@ static int ali_get_info (char *buffer, char **addr, off_t offset, int count)
static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
{
- ide_pio_data_t d;
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
int s_time, a_time, c_time;
@@ -307,7 +306,7 @@ static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
u8 cd_dma_fifo = 0;
int unit = drive->select.b.unit & 1;
- pio = ide_get_best_pio_mode(drive, pio, 5, &d);
+ pio = ide_get_best_pio_mode(drive, pio, 5);
s_time = ide_pio_timings[pio].setup_time;
a_time = ide_pio_timings[pio].active_time;
if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
@@ -508,7 +507,7 @@ static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const c
u8 tmpbyte;
struct pci_dev *north = pci_get_slot(dev->bus, PCI_DEVFN(0,0));
- pci_read_config_byte(dev, PCI_REVISION_ID, &m5229_revision);
+ m5229_revision = dev->revision;
isa_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
@@ -817,9 +816,9 @@ static ide_pci_device_t ali15x3_chipset __devinitdata = {
.init_chipset = init_chipset_ali15x3,
.init_hwif = init_hwif_ali15x3,
.init_dma = init_dma_ali15x3,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
};
/**
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 84ed30cdb324..06c15a6a3e7d 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -1,5 +1,5 @@
/*
- * Version 2.20
+ * Version 2.21
*
* AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
* IDE driver for Linux.
@@ -123,8 +123,7 @@ static int amd74xx_get_info(char *buffer, char **addr, off_t offset, int count)
amd_print("Driver Version: 2.13");
amd_print("South Bridge: %s", pci_name(bmide_dev));
- pci_read_config_byte(dev, PCI_REVISION_ID, &t);
- amd_print("Revision: IDE %#x", t);
+ amd_print("Revision: IDE %#x", dev->revision);
amd_print("Highest DMA rate: UDMA%s", amd_dma[fls(amd_config->udma_mask) - 1]);
amd_print("BM-DMA base: %#lx", amd_base);
@@ -273,10 +272,8 @@ static int amd_set_drive(ide_drive_t *drive, u8 speed)
static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
{
- if (pio == 255) {
- amd_set_drive(drive, ide_find_best_pio_mode(drive));
- return;
- }
+ if (pio == 255)
+ pio = ide_get_best_pio_mode(drive, 255, 5);
amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
}
@@ -285,12 +282,14 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive)
{
u8 speed = ide_max_dma_mode(drive);
- if (speed == 0)
- speed = ide_find_best_pio_mode(drive);
+ if (speed == 0) {
+ amd74xx_tune_drive(drive, 255);
+ return -1;
+ }
amd_set_drive(drive, speed);
- if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ if (drive->autodma)
return 0;
return -1;
@@ -312,8 +311,7 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
*/
if (amd_config->flags & AMD_CHECK_SWDMA) {
- pci_read_config_byte(dev, PCI_REVISION_ID, &t);
- if (t <= 7)
+ if (dev->revision <= 7)
amd_config->flags |= AMD_BAD_SWDMA;
}
@@ -383,7 +381,7 @@ static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const ch
pci_read_config_byte(dev, PCI_REVISION_ID, &t);
printk(KERN_INFO "%s: %s (rev %02x) UDMA%s controller\n",
- amd_chipset->name, pci_name(dev), t,
+ amd_chipset->name, pci_name(dev), dev->revision,
amd_dma[fls(amd_config->udma_mask) - 1]);
/*
@@ -450,10 +448,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.name = name_str, \
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
- .channels = 2, \
.autodma = AUTODMA, \
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
+ | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ .pio_mask = ATA_PIO5, \
}
#define DECLARE_NV_DEV(name_str) \
@@ -461,10 +461,12 @@ static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
.name = name_str, \
.init_chipset = init_chipset_amd74xx, \
.init_hwif = init_hwif_amd74xx, \
- .channels = 2, \
.autodma = AUTODMA, \
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST \
+ | IDE_HFLAG_PIO_NO_DOWNGRADE, \
+ .pio_mask = ATA_PIO5, \
}
static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 2761510309b3..1725aa402d98 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -1,9 +1,8 @@
/*
- * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004
+ * linux/drivers/ide/pci/atiixp.c Version 0.02 Jun 16 2007
*
* Copyright (C) 2003 ATI Inc. <hyu@ati.com>
- * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
- *
+ * Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
*/
#include <linux/types.h>
@@ -123,14 +122,14 @@ static void atiixp_dma_host_off(ide_drive_t *drive)
}
/**
- * atiixp_tune_drive - tune a drive attached to a ATIIXP
+ * atiixp_tune_pio - tune a drive attached to a ATIIXP
* @drive: drive to tune
* @pio: desired PIO mode
*
* Set the interface PIO mode.
*/
-static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
{
struct pci_dev *dev = drive->hwif->pci_dev;
unsigned long flags;
@@ -154,6 +153,13 @@ static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
spin_unlock_irqrestore(&atiixp_lock, flags);
}
+static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+{
+ pio = ide_get_best_pio_mode(drive, pio, 4);
+ atiixp_tune_pio(drive, pio);
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
/**
* atiixp_tune_chipset - tune a ATIIXP interface
* @drive: IDE drive to tune
@@ -175,6 +181,11 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
speed = ide_rate_filter(drive, xferspeed);
+ if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
+ atiixp_tune_pio(drive, speed - XFER_PIO_0);
+ return ide_config_drive_speed(drive, speed);
+ }
+
spin_lock_irqsave(&atiixp_lock, flags);
save_mdma_mode[drive->dn] = 0;
@@ -201,7 +212,7 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
else
pio = speed - XFER_PIO_0;
- atiixp_tuneproc(drive, pio);
+ atiixp_tune_pio(drive, pio);
return ide_config_drive_speed(drive, speed);
}
@@ -216,18 +227,13 @@ static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
static int atiixp_dma_check(ide_drive_t *drive)
{
- u8 tspeed, speed;
-
drive->init_speed = 0;
if (ide_tune_dma(drive))
return 0;
- if (ide_use_fast_pio(drive)) {
- tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
- speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
- atiixp_speedproc(drive, speed);
- }
+ if (ide_use_fast_pio(drive))
+ atiixp_tuneproc(drive, 255);
return -1;
}
@@ -285,17 +291,18 @@ static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
{ /* 0 */
.name = "ATIIXP",
.init_hwif = init_hwif_atiixp,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 1 */
.name = "SB600_PATA",
.init_hwif = init_hwif_atiixp,
- .channels = 1,
.autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
},
};
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index dc43f009acab..9689494efa24 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -633,9 +633,8 @@ static void cmd640_set_mode (unsigned int index, u8 pio_mode, unsigned int cycle
*/
static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
{
+ unsigned int index = 0, cycle_time;
u8 b;
- ide_pio_data_t d;
- unsigned int index = 0;
while (drive != cmd_drives[index]) {
if (++index > 3) {
@@ -662,16 +661,14 @@ static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
return;
}
- (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
- cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+ mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 5);
+ cycle_time = ide_pio_cycle_time(drive, mode_wanted);
+ cmd640_set_mode(index, mode_wanted, cycle_time);
+
+ printk("%s: selected cmd640 PIO mode%d (%dns)",
+ drive->name, mode_wanted, cycle_time);
- printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
- drive->name,
- d.pio_mode,
- d.cycle_time,
- d.overridden ? " (overriding vendor mode)" : "");
display_clocks(index);
- return;
}
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -769,6 +766,7 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
cmd_hwif0->chipset = ide_cmd640;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ cmd_hwif0->pio_mask = ATA_PIO5;
cmd_hwif0->tuneproc = &cmd640_tune_drive;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -824,6 +822,7 @@ int __init ide_probe_for_cmd640x (void)
cmd_hwif1->mate = cmd_hwif0;
cmd_hwif1->channel = 1;
#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
+ cmd_hwif1->pio_mask = ATA_PIO5;
cmd_hwif1->tuneproc = &cmd640_tune_drive;
#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
}
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 8631b6c8aa15..19633c5aba15 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -88,7 +88,6 @@ static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
u8 reg72 = 0, reg73 = 0; /* primary */
u8 reg7a = 0, reg7b = 0; /* secondary */
u8 reg50 = 1, reg51 = 1, reg57 = 0, reg71 = 0; /* extra */
- u8 rev = 0;
p += sprintf(p, "\nController: %d\n", index);
p += sprintf(p, "PCI-%x Chipset.\n", dev->device);
@@ -103,9 +102,8 @@ static char * print_cmd64x_get_info (char *buf, struct pci_dev *dev, int index)
(void) pci_read_config_byte(dev, UDIDETCR1, &reg7b);
/* PCI0643/6 originally didn't have the primary channel enable bit */
- (void) pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
if ((dev->device == PCI_DEVICE_ID_CMD_643) ||
- (dev->device == PCI_DEVICE_ID_CMD_646 && rev < 3))
+ (dev->device == PCI_DEVICE_ID_CMD_646 && dev->revision < 3))
reg51 |= CNTRL_ENA_1ST;
p += sprintf(p, "---------------- Primary Channel "
@@ -223,17 +221,18 @@ static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
{
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
- ide_pio_data_t pio;
+ unsigned int cycle_time;
u8 pio_mode, setup_count, arttim = 0;
static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
- pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio);
- cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n",
- drive->name, mode_wanted, pio_mode, pio.cycle_time,
- pio.overridden ? " (overriding vendor mode)" : "");
+ pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5);
+ cycle_time = ide_pio_cycle_time(drive, pio_mode);
- program_cycle_times(drive, pio.cycle_time,
+ cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)\n",
+ drive->name, mode_wanted, pio_mode, cycle_time);
+
+ program_cycle_times(drive, cycle_time,
ide_pio_timings[pio_mode].active_time);
setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
@@ -604,14 +603,11 @@ static int __devinit init_setup_cmd64x(struct pci_dev *dev, ide_pci_device_t *d)
static int __devinit init_setup_cmd646(struct pci_dev *dev, ide_pci_device_t *d)
{
- u8 rev = 0;
-
/*
* The original PCI0646 didn't have the primary channel enable bit,
* it appeared starting with PCI0646U (i.e. revision ID 3).
*/
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
- if (rev < 3)
+ if (dev->revision < 3)
d->enablebits[0].reg = 0;
return ide_setup_pci_device(dev, d);
@@ -623,40 +619,40 @@ static ide_pci_device_t cmd64x_chipsets[] __devinitdata = {
.init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x00, /* no udma */
},{ /* 1 */
.name = "CMD646",
.init_setup = init_setup_cmd646,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x07, /* udma0-2 */
},{ /* 2 */
.name = "CMD648",
.init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 3 */
.name = "CMD649",
.init_setup = init_setup_cmd64x,
.init_chipset = init_chipset_cmd64x,
.init_hwif = init_hwif_cmd64x,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
.udma_mask = 0x3f, /* udma0-5 */
}
};
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 3b88a3a56116..bccedf9b8b28 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -126,7 +126,7 @@ static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static void cs5520_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
cs5520_tune_chipset(drive, (XFER_PIO_0 + pio));
}
@@ -194,10 +194,10 @@ static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
.name = name_str, \
.init_setup_dma = cs5520_init_setup_dma, \
.init_hwif = init_hwif_cs5520, \
- .channels = 2, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
- .flags = IDEPCI_FLAG_ISA_PORTS, \
+ .host_flags = IDE_HFLAG_ISA_PORTS, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 1eec1f308d16..acaf71fd4c09 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -82,7 +82,7 @@ static void cs5530_tunepio(ide_drive_t *drive, u8 pio)
static void cs5530_tuneproc (ide_drive_t *drive, u8 pio) /* pio=255 means "autotune" */
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
cs5530_tunepio(drive, pio);
@@ -236,7 +236,7 @@ static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const ch
*/
pci_set_master(cs5530_0);
- pci_set_mwi(cs5530_0);
+ pci_try_set_mwi(cs5530_0);
/*
* Set PCI CacheLineSize to 16-bytes:
@@ -341,9 +341,9 @@ static ide_pci_device_t cs5530_chipset __devinitdata = {
.name = "CS5530",
.init_chipset = init_chipset_cs5530,
.init_hwif = init_hwif_cs5530,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 10f61f38243c..ce44e38390aa 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -89,7 +89,7 @@ static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
pioa = speed - XFER_PIO_0;
piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]),
- 255, 4, NULL);
+ 255, 4);
cmd = pioa < piob ? pioa : piob;
/* Write the speed of the current drive */
@@ -159,7 +159,7 @@ static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed)
/* cs5535 max pio is pio 4, best_pio will check the blacklist.
i think we don't need to rate_filter the incoming xferspeed
since we know we're only going to choose pio */
- xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL);
+ xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4);
ide_config_drive_speed(drive, modes[xferspeed]);
cs5535_set_speed(drive, xferspeed);
}
@@ -174,7 +174,7 @@ static int cs5535_dma_check(ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive)) {
- speed = ide_get_best_pio_mode(drive, 255, 4, NULL);
+ speed = ide_get_best_pio_mode(drive, 255, 4);
cs5535_set_drive(drive, speed);
}
@@ -228,9 +228,10 @@ static void __devinit init_hwif_cs5535(ide_hwif_t *hwif)
static ide_pci_device_t cs5535_chipset __devinitdata = {
.name = "CS5535",
.init_hwif = init_hwif_cs5535,
- .channels = 1,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
};
static int __devinit cs5535_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 103b9db97853..daa36fcbc8ef 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -330,7 +330,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
#endif /* CY82C693_DEBUG_LOGS */
/* first let's calc the pio modes */
- pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO);
#if CY82C693_DEBUG_INFO
printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
@@ -483,9 +483,10 @@ static ide_pci_device_t cy82c693_chipset __devinitdata = {
.init_chipset = init_chipset_cy82c693,
.init_iops = init_iops_cy82c693,
.init_hwif = init_hwif_cy82c693,
- .channels = 1,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
};
static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 0d51a11e81da..48caa468b762 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -95,92 +95,77 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = {
{ /* 0 */
.name = "Unknown",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 1 */
.name = "NS87410",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
.bootable = ON_BOARD,
},{ /* 2 */
.name = "SAMURAI",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 3 */
.name = "HT6565",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 4 */
.name = "UM8673F",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
},{ /* 5 */
.name = "UM8886A",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
},{ /* 6 */
.name = "UM8886BF",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
},{ /* 7 */
.name = "HINT_IDE",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
},{ /* 8 */
.name = "VIA_IDE",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 9 */
.name = "OPTI621V",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 10 */
.name = "VIA8237SATA",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
},{ /* 11 */
.name = "Piccolo0102",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 12 */
.name = "Piccolo0103",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 13 */
.name = "Piccolo0105",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
},{ /* 14 */
.name = "Revolution",
.init_hwif = init_hwif_generic,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
}
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index 2c24c3de8846..19778c5fe711 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -80,7 +80,7 @@ static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 5);
(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
}
@@ -120,17 +120,10 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
pci_read_config_word(dev, PCI_COMMAND, &cmd);
- if (cmd & PCI_COMMAND_MEMORY) {
- if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
+ if (cmd & PCI_COMMAND_MEMORY)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
- } else {
+ else
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
- }
/*
* Since 20-23 can be assigned and are R/W, we correct them.
@@ -182,10 +175,10 @@ static ide_pci_device_t hpt34x_chipset __devinitdata = {
.name = "HPT34X",
.init_chipset = init_chipset_hpt34x,
.init_hwif = init_hwif_hpt34x,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = NEVER_BOARD,
- .extra = 16
+ .extra = 16,
+ .pio_mask = ATA_PIO5,
};
static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 4b6bae8eee82..2cd74c345a6c 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -652,7 +652,7 @@ static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
(void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
}
@@ -994,14 +994,6 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
*/
*info = *(struct hpt_info *)pci_get_drvdata(dev);
- /*
- * FIXME: Not portable. Also, why do we enable the ROM in the first place?
- * We don't seem to be using it.
- */
- if (dev->resource[PCI_ROM_RESOURCE].start)
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
@@ -1413,11 +1405,9 @@ static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d
static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
{
struct hpt_info *info;
- u8 rev = 0, mcr1 = 0;
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+ u8 mcr1 = 0;
- if (rev > 1) {
+ if (dev->revision > 1) {
d->name = "HPT371N";
info = &hpt371n;
@@ -1442,11 +1432,8 @@ static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
{
struct hpt_info *info;
- u8 rev = 0;
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-
- if (rev > 1) {
+ if (dev->revision > 1) {
d->name = "HPT372N";
info = &hpt372n;
@@ -1460,11 +1447,8 @@ static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d
static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
{
struct hpt_info *info;
- u8 rev = 0;
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
- if (rev > 1) {
+ if (dev->revision > 1) {
d->name = "HPT302N";
info = &hpt302n;
@@ -1478,7 +1462,7 @@ static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
{
struct pci_dev *dev2;
- u8 rev = 0;
+ u8 rev = dev->revision;
static char *chipset_names[] = { "HPT366", "HPT366", "HPT368",
"HPT370", "HPT370A", "HPT372",
"HPT372N" };
@@ -1489,8 +1473,6 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
if (PCI_FUNC(dev->devfn) & 1)
return -ENODEV;
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
-
switch (rev) {
case 0:
case 1:
@@ -1501,7 +1483,7 @@ static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
* to both functions -- really stupid design decision... :-(
* Bit 4 is for the primary channel, bit 5 for the secondary.
*/
- d->channels = 1;
+ d->host_flags |= IDE_HFLAG_SINGLE;
d->enablebits[0].mask = d->enablebits[0].val = 0x10;
d->udma_mask = HPT366_ALLOW_ATA66_3 ?
@@ -1564,71 +1546,71 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 1 */
.name = "HPT372A",
.init_setup = init_setup_hpt372a,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 2 */
.name = "HPT302",
.init_setup = init_setup_hpt302,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.udma_mask = HPT302_ALLOW_ATA133_6 ? 0x7f : 0x3f,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 3 */
.name = "HPT371",
.init_setup = init_setup_hpt371,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.udma_mask = HPT371_ALLOW_ATA133_6 ? 0x7f : 0x3f,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 4 */
.name = "HPT374",
.init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2, /* 4 */
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.udma_mask = 0x3f,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
},{ /* 5 */
.name = "HPT372N",
.init_setup = init_setup_hpt372n,
.init_chipset = init_chipset_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
- .channels = 2, /* 4 */
.autodma = AUTODMA,
.enablebits = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
.udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
.bootable = OFF_BOARD,
- .extra = 240
+ .extra = 240,
+ .pio_mask = ATA_PIO4,
}
};
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index ff48c23e571e..95dbed7e6022 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -82,7 +82,7 @@ static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
{ 2, 1 },
{ 2, 3 }, };
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
spin_lock_irqsave(&tune_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
@@ -214,7 +214,7 @@ static int it8213_config_drive_for_dma (ide_drive_t *drive)
if (ide_tune_dma(drive))
return 0;
- pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, 255, 4);
it8213_tune_chipset(drive, XFER_PIO_0 + pio);
return -1;
@@ -272,10 +272,11 @@ static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
{ \
.name = name_str, \
.init_hwif = init_hwif_it8213, \
- .channels = 1, \
.autodma = AUTODMA, \
.enablebits = {{0x41,0x80,0x80}}, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_SINGLE, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t it8213_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 8197b653ba1e..9286c99e2ff0 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -255,7 +255,7 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
* on the cable.
*/
if (pair) {
- u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
+ u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
/* trim PIO to the slowest of the master/slave */
if (pair_pio < set_pio)
set_pio = pair_pio;
@@ -276,7 +276,7 @@ static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
(void)it821x_tunepio(drive, pio);
}
@@ -718,10 +718,10 @@ static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const cha
.name = name_str, \
.init_chipset = init_chipset_it821x, \
.init_hwif = init_hwif_it821x, \
- .channels = 2, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
- .fixup = it821x_fixups \
+ .fixup = it821x_fixups, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t it821x_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index a6008f63e71e..d7ce9dd8de16 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -97,7 +97,7 @@ static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
static void config_jmicron_chipset_for_pio (ide_drive_t *drive, byte set_speed)
{
- u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+ u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5);
if (set_speed)
(void) ide_config_drive_speed(drive, speed);
}
@@ -177,10 +177,10 @@ fallback:
{ \
.name = name_str, \
.init_hwif = init_hwif_jmicron, \
- .channels = 2, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
.enablebits = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \
+ .pio_mask = ATA_PIO5, \
}
static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index b310c4f51077..09941f37d635 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -281,7 +281,6 @@ static ide_pci_device_t ns87415_chipset __devinitdata = {
.init_iops = init_iops_ns87415,
#endif
.init_hwif = init_hwif_ns87415,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
};
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index aede7eee9246..3a2bb2723515 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -147,12 +147,12 @@ static void compute_pios(ide_drive_t *drive, u8 pio)
int d;
ide_hwif_t *hwif = HWIF(drive);
- drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+ drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO);
for (d = 0; d < 2; ++d) {
drive = &hwif->drives[d];
if (drive->present) {
if (drive->drive_data == PIO_DONT_KNOW)
- drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+ drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO);
#ifdef OPTI621_DEBUG
printk("%s: Selected PIO mode %d\n",
drive->name, drive->drive_data);
@@ -350,17 +350,17 @@ static ide_pci_device_t opti621_chipsets[] __devinitdata = {
{ /* 0 */
.name = "OPTI621",
.init_hwif = init_hwif_opti621,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO3,
},{ /* 1 */
.name = "OPTI621X",
.init_hwif = init_hwif_opti621,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO3,
}
};
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index ee5020df005d..8a66a2871b3a 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -219,7 +219,7 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
(void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
}
@@ -378,13 +378,6 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
int f, r;
u8 pll_ctl0, pll_ctl1;
- if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
-
#ifdef CONFIG_PPC_PMAC
apple_kiwi_init(dev);
#endif
@@ -573,63 +566,63 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 1 */
.name = "PDC20269",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 2 */
.name = "PDC20270",
.init_setup = init_setup_pdc20270,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 3 */
.name = "PDC20271",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 4 */
.name = "PDC20275",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 5 */
.name = "PDC20276",
.init_setup = init_setup_pdc20276,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
},{ /* 6 */
.name = "PDC20277",
.init_setup = init_setup_pdcnew,
.init_chipset = init_chipset_pdcnew,
.init_hwif = init_hwif_pdc202new,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x7f, /* udma0-6*/
}
};
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 41ac4a94959f..fbcb0bb9c956 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -145,7 +145,7 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
}
@@ -316,14 +316,6 @@ static void pdc202xx_reset (ide_drive_t *drive)
static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
const char *name)
{
- /* This doesn't appear needed */
- if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS,
- dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
- (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
- }
-
return dev->irq;
}
@@ -449,10 +441,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 16,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x07, /* udma0-2 */
},{ /* 1 */
.name = "PDC20262",
@@ -460,10 +452,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 2 */
.name = "PDC20263",
@@ -471,10 +463,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x1f, /* udma0-4 */
},{ /* 3 */
.name = "PDC20265",
@@ -482,10 +474,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
},{ /* 4 */
.name = "PDC20267",
@@ -493,10 +485,10 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_chipset = init_chipset_pdc202xx,
.init_hwif = init_hwif_pdc202xx,
.init_dma = init_dma_pdc202xx,
- .channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
.extra = 48,
+ .pio_mask = ATA_PIO4,
.udma_mask = 0x3f, /* udma0-5 */
}
};
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 2e0b29ef596a..4f69cd067e5e 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -219,7 +219,7 @@ static void piix_tune_pio (ide_drive_t *drive, u8 pio)
*/
static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
piix_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
@@ -495,10 +495,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
.name = name_str, \
.init_chipset = init_chipset_piix, \
.init_hwif = init_hwif_piix, \
- .channels = 2, \
.autodma = AUTODMA, \
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
.bootable = ON_BOARD, \
+ .pio_mask = ATA_PIO4, \
.udma_mask = udma, \
}
@@ -514,11 +514,11 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
*/
.name = "MPIIX",
.init_hwif = init_hwif_piix,
- .channels = 2,
.autodma = NODMA,
.enablebits = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
.bootable = ON_BOARD,
- .flags = IDEPCI_FLAG_ISA_PORTS
+ .host_flags = IDE_HFLAG_ISA_PORTS,
+ .pio_mask = ATA_PIO4,
},
/* 3 */ DECLARE_PIIX_DEV("PIIX3", 0x00), /* no udma */
@@ -572,18 +572,16 @@ static void __devinit piix_check_450nx(void)
{
struct pci_dev *pdev = NULL;
u16 cfg;
- u8 rev;
while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
{
/* Look for 450NX PXB. Check for problem configurations
A PCI quirk checks bit 6 already */
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
pci_read_config_word(pdev, 0x41, &cfg);
/* Only on the original revision: IDE DMA can hang */
- if(rev == 0x00)
+ if (pdev->revision == 0x00)
no_piix_dma = 1;
/* On all revisions below 5 PXB bus lock must be disabled for IDE */
- else if(cfg & (1<<14) && rev < 5)
+ else if (cfg & (1<<14) && pdev->revision < 5)
no_piix_dma = 2;
}
if(no_piix_dma)
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index f8c954690142..10e1ae7a4a02 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -52,7 +52,6 @@ static void __devinit init_hwif_rz1000 (ide_hwif_t *hwif)
static ide_pci_device_t rz1000_chipset __devinitdata = {
.name = "RZ100x",
.init_hwif = init_hwif_rz1000,
- .channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
};
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 523363c93794..9bdc9694d50d 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/sc1200.c Version 0.94 Mar 10 2007
+ * linux/drivers/ide/pci/sc1200.c Version 0.95 Jun 16 2007
*
* Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
* Copyright (C) 2007 Bartlomiej Zolnierkiewicz
@@ -304,7 +304,7 @@ static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "au
return;
}
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
@@ -390,7 +390,7 @@ static int sc1200_resume (struct pci_dev *dev)
// loop over all interfaces that are part of this pci device:
//
while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
- unsigned int basereg, r, d, format;
+ unsigned int basereg, r;
sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data;
//
@@ -402,41 +402,6 @@ static int sc1200_resume (struct pci_dev *dev)
pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
}
}
- //
- // Re-program drive PIO modes
- //
- pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
- format = (format >> 31) & 1;
- if (format)
- format += sc1200_get_pci_clock();
- for (d = 0; d < 2; ++d) {
- ide_drive_t *drive = &(hwif->drives[d]);
- if (drive->present) {
- unsigned int pio, timings;
- pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
- for (pio = 0; pio <= 4; ++pio) {
- if (sc1200_pio_timings[format][pio] == timings)
- break;
- }
- if (pio > 4)
- pio = 255; /* autotune */
- (void)sc1200_tuneproc(drive, pio);
- }
- }
- //
- // Re-program drive DMA modes
- //
- for (d = 0; d < MAX_DRIVES; ++d) {
- ide_drive_t *drive = &(hwif->drives[d]);
- if (drive->present && !__ide_dma_bad_drive(drive)) {
- int enable_dma = drive->using_dma;
- hwif->dma_off_quietly(drive);
- if (sc1200_config_dma(drive))
- enable_dma = 0;
- if (enable_dma)
- hwif->dma_host_on(drive);
- }
- }
}
return 0;
}
@@ -471,9 +436,9 @@ static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
static ide_pci_device_t sc1200_chipset __devinitdata = {
.name = "SC1200",
.init_hwif = init_hwif_sc1200,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index 7b87488e3daa..f668d235e6be 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -165,9 +165,9 @@ scc_ide_outbsync(ide_drive_t * drive, u8 addr, unsigned long port)
ide_hwif_t *hwif = HWIF(drive);
out_be32((void*)port, addr);
- __asm__ __volatile__("eieio":::"memory");
+ eieio();
in_be32((void*)(hwif->dma_base + 0x01c));
- __asm__ __volatile__("eieio":::"memory");
+ eieio();
}
static void
@@ -210,7 +210,7 @@ static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted)
unsigned char speed = XFER_PIO_0;
int offset;
- mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4, NULL);
+ mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4);
switch (mode_wanted) {
case 4:
speed = XFER_PIO_4;
@@ -401,6 +401,33 @@ static int scc_ide_dma_end(ide_drive_t * drive)
ide_hwif_t *hwif = HWIF(drive);
unsigned long intsts_port = hwif->dma_base + 0x014;
u32 reg;
+ int dma_stat, data_loss = 0;
+ static int retry = 0;
+
+ /* 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 *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+ drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
+ reg = in_be32((void __iomem *)intsts_port);
+ if (!(reg & INTSTS_ACTEINT)) {
+ printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
+ drive->name);
+ data_loss = 1;
+ if (retry++) {
+ struct request *rq = HWGROUP(drive)->rq;
+ int unit;
+ /* ERROR_RESET and drive->crc_count are needed
+ * to reduce DMA transfer mode in retry process.
+ */
+ if (rq)
+ rq->errors |= ERROR_RESET;
+ for (unit = 0; unit < MAX_DRIVES; unit++) {
+ ide_drive_t *drive = &hwif->drives[unit];
+ drive->crc_count++;
+ }
+ }
+ }
+ }
while (1) {
reg = in_be32((void __iomem *)intsts_port);
@@ -469,27 +496,25 @@ static int scc_ide_dma_end(ide_drive_t * drive)
break;
}
- return __ide_dma_end(drive);
+ dma_stat = __ide_dma_end(drive);
+ if (data_loss)
+ dma_stat |= 2; /* emulate DMA error (to retry command) */
+ return dma_stat;
}
/* returns 1 if dma irq issued, 0 otherwise */
static int scc_dma_test_irq(ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
- u8 dma_stat = hwif->INB(hwif->dma_status);
+ ide_hwif_t *hwif = HWIF(drive);
+ u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
- /* return 1 if INTR asserted */
- if ((dma_stat & 4) == 4)
+ /* SCC errata A252,A308 workaround: Step4 */
+ if ((in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+ (int_stat & INTSTS_INTRQ))
return 1;
- /* Workaround for PTERADD: emulate DMA_INTR when
- * - IDE_STATUS[ERR] = 1
- * - INT_STATUS[INTRQ] = 1
- * - DMA_STATUS[IORACTA] = 1
- */
- if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT &&
- in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ &&
- dma_stat & 1)
+ /* SCC errata A308 workaround: Step5 (polling IOIRQS) */
+ if (int_stat & INTSTS_IOIRQS)
return 1;
if (!drive->waiting_for_dma)
@@ -498,6 +523,21 @@ static int scc_dma_test_irq(ide_drive_t *drive)
return 0;
}
+static u8 scc_udma_filter(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ u8 mask = hwif->ultra_mask;
+
+ /* errata A308 workaround: limit non ide_disk drive to UDMA4 */
+ if ((drive->media != ide_disk) && (mask & 0xE0)) {
+ printk(KERN_INFO "%s: limit %s to UDMA4\n",
+ SCC_PATA_NAME, drive->name);
+ mask = 0x1F;
+ }
+
+ return mask;
+}
+
/**
* setup_mmio_scc - map CTRL/BMID region
* @dev: PCI device we are configuring
@@ -702,6 +742,7 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
hwif->tuneproc = scc_tuneproc;
hwif->ide_dma_check = scc_config_drive_for_dma;
hwif->ide_dma_test_irq = scc_dma_test_irq;
+ hwif->udma_filter = scc_udma_filter;
hwif->drives[0].autotune = IDE_TUNE_AUTO;
hwif->drives[1].autotune = IDE_TUNE_AUTO;
@@ -731,9 +772,10 @@ static void __devinit init_hwif_scc(ide_hwif_t *hwif)
.init_setup = init_setup_scc, \
.init_iops = init_iops_scc, \
.init_hwif = init_hwif_scc, \
- .channels = 1, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
+ .host_flags = IDE_HFLAG_SINGLE, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t scc_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 1371b5bf6bf0..9fead2e7d4c8 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/pci/serverworks.c Version 0.20 Jun 3 2007
+ * linux/drivers/ide/pci/serverworks.c Version 0.22 Jun 27 2007
*
* Copyright (C) 1998-2000 Michel Aubry
* Copyright (C) 1998-2000 Andrzej Krzysztofowicz
@@ -55,7 +55,6 @@ static const char *svwks_bad_ata100[] = {
NULL
};
-static u8 svwks_revision = 0;
static struct pci_dev *isa_dev;
static int check_in_drive_lists (ide_drive_t *drive, const char **list)
@@ -71,9 +70,6 @@ static u8 svwks_udma_filter(ide_drive_t *drive)
struct pci_dev *dev = HWIF(drive)->pci_dev;
u8 mask = 0;
- if (!svwks_revision)
- pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
-
if (dev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
return 0x1f;
if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
@@ -88,9 +84,9 @@ static u8 svwks_udma_filter(ide_drive_t *drive)
return 0;
/* Check the OSB4 DMA33 enable bit */
return ((reg & 0x00004000) == 0x00004000) ? 0x07 : 0;
- } else if (svwks_revision < SVWKS_CSB5_REVISION_NEW) {
+ } else if (dev->revision < SVWKS_CSB5_REVISION_NEW) {
return 0x07;
- } else if (svwks_revision >= SVWKS_CSB5_REVISION_NEW) {
+ } else if (dev->revision >= SVWKS_CSB5_REVISION_NEW) {
u8 btr = 0, mode;
pci_read_config_byte(dev, 0x5A, &btr);
mode = btr & 0x3;
@@ -127,23 +123,45 @@ static u8 svwks_csb_check (struct pci_dev *dev)
}
return 0;
}
+
+static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
+{
+ static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+
+ struct pci_dev *dev = drive->hwif->pci_dev;
+
+ pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
+
+ if (svwks_csb_check(dev)) {
+ u16 csb_pio = 0;
+
+ pci_read_config_word(dev, 0x4a, &csb_pio);
+
+ csb_pio &= ~(0x0f << (4 * drive->dn));
+ csb_pio |= (pio << (4 * drive->dn));
+
+ pci_write_config_word(dev, 0x4a, csb_pio);
+ }
+}
+
static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
- static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
- static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
u8 speed = ide_rate_filter(drive, xferspeed);
- u8 pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
u8 unit = (drive->select.b.unit & 0x01);
- u8 csb5 = svwks_csb_check(dev);
- u8 ultra_enable = 0, ultra_timing = 0;
- u8 dma_timing = 0, pio_timing = 0;
- u16 csb5_pio = 0;
+
+ u8 ultra_enable = 0, ultra_timing = 0, dma_timing = 0;
+
+ if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
+ svwks_tune_pio(drive, speed - XFER_PIO_0);
+ return ide_config_drive_speed(drive, speed);
+ }
/* If we are about to put a disk into UDMA mode we screwed up.
Our code assumes we never _ever_ do this on an OSB4 */
@@ -153,31 +171,15 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
BUG();
pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
- pci_read_config_word(dev, 0x4A, &csb5_pio);
pci_read_config_byte(dev, 0x54, &ultra_enable);
ultra_timing &= ~(0x0F << (4*unit));
ultra_enable &= ~(0x01 << drive->dn);
- csb5_pio &= ~(0x0F << (4*drive->dn));
switch(speed) {
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_1:
- case XFER_PIO_0:
- pio_timing |= pio_modes[speed - XFER_PIO_0];
- csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn));
- break;
-
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_MW_DMA_0:
- /*
- * TODO: always setup PIO mode so this won't be needed
- */
- pio_timing |= pio_modes[pio];
- csb5_pio |= (pio << (4*drive->dn));
dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
break;
@@ -187,11 +189,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_UDMA_2:
case XFER_UDMA_1:
case XFER_UDMA_0:
- /*
- * TODO: always setup PIO mode so this won't be needed
- */
- pio_timing |= pio_modes[pio];
- csb5_pio |= (pio << (4*drive->dn));
dma_timing |= dma_modes[2];
ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
ultra_enable |= (0x01 << drive->dn);
@@ -199,10 +196,6 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
break;
}
- pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
- if (csb5)
- pci_write_config_word(dev, 0x4A, csb5_pio);
-
pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
pci_write_config_byte(dev, 0x54, ultra_enable);
@@ -212,8 +205,9 @@ static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
- (void)svwks_tune_chipset(drive, XFER_PIO_0 + pio);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
+ svwks_tune_pio(drive, pio);
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
@@ -234,9 +228,6 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
unsigned int reg;
u8 btr;
- /* save revision id to determine DMA capability */
- pci_read_config_byte(dev, PCI_REVISION_ID, &svwks_revision);
-
/* force Master Latency Timer value to 64 PCICLKs */
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
@@ -315,7 +306,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
if (!(PCI_FUNC(dev->devfn) & 1))
btr |= 0x2;
else
- btr |= (svwks_revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ btr |= (dev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
pci_write_config_byte(dev, 0x5A, btr);
}
/* Setup HT1000 SouthBridge Controller - Single Channel Only */
@@ -396,8 +387,6 @@ static u8 __devinit ata66_svwks(ide_hwif_t *hwif)
static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
{
- u8 dma_stat = 0;
-
if (!hwif->irq)
hwif->irq = hwif->channel ? 15 : 14;
@@ -414,11 +403,11 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
hwif->autodma = 0;
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
return;
- }
hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
@@ -428,11 +417,7 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
if (!noautodma)
hwif->autodma = 1;
- dma_stat = inb(hwif->dma_status);
- hwif->drives[0].autodma = (dma_stat & 0x20);
- hwif->drives[1].autodma = (dma_stat & 0x40);
- hwif->drives[0].autotune = (!(dma_stat & 0x20));
- hwif->drives[1].autotune = (!(dma_stat & 0x40));
+ hwif->drives[0].autodma = hwif->drives[1].autodma = 1;
}
static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
@@ -448,9 +433,12 @@ static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
d->bootable = ON_BOARD;
}
- d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
- dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
- (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+ if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ d->host_flags |= IDE_HFLAG_SINGLE;
+ else
+ d->host_flags &= ~IDE_HFLAG_SINGLE;
return ide_setup_pci_device(dev, d);
}
@@ -461,41 +449,43 @@ static ide_pci_device_t serverworks_chipsets[] __devinitdata = {
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 1 */
.name = "SvrWks CSB5",
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 2 */
.name = "SvrWks CSB6",
.init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
},{ /* 3 */
.name = "SvrWks CSB6",
.init_setup = init_setup_csb6,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 1, /* 2 */
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
},{ /* 4 */
.name = "SvrWks HT1000",
.init_setup = init_setup_svwks,
.init_chipset = init_chipset_svwks,
.init_hwif = init_hwif_svwks,
- .channels = 1, /* 2 */
.autodma = AUTODMA,
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
}
};
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index d396b2929ed8..57145767c3df 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -586,6 +586,7 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->ultra_mask = 0x0; /* Disable Ultra DMA */
hwif->mwdma_mask = 0x2; /* Multimode-2 DMA */
hwif->swdma_mask = 0x2;
+ hwif->pio_mask = 0x00;
hwif->tuneproc = NULL; /* Sets timing for PIO mode */
hwif->speedproc = NULL; /* Sets timing for DMA &/or PIO modes */
hwif->selectproc = NULL;/* Use the default routine to select drive */
@@ -724,10 +725,10 @@ static ide_pci_device_t sgiioc4_chipset __devinitdata = {
.name = "SGIIOC4",
.init_hwif = ide_init_sgiioc4,
.init_dma = ide_dma_sgiioc4,
- .channels = 1,
.autodma = AUTODMA,
/* SGI IOC4 doesn't have enablebits. */
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
};
int
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 1c3e35487893..50f6d172ef77 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,9 +1,10 @@
/*
- * linux/drivers/ide/pci/siimage.c Version 1.12 Mar 10 2007
+ * linux/drivers/ide/pci/siimage.c Version 1.15 Jun 29 2007
*
* 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
*
* May be copied or modified under the terms of the GNU General Public License
*
@@ -31,6 +32,10 @@
* unplugging/replugging the virtual CD interface when the DRAC is reset.
* This often causes drivers/ide/siimage to panic but is ok with the rather
* smarter code in libata.
+ *
+ * TODO:
+ * - IORDY fixes
+ * - VDMA support
*/
#include <linux/types.h>
@@ -160,82 +165,45 @@ out:
}
/**
- * siimage_taskfile_timing - turn timing data to a mode
- * @hwif: interface to query
- *
- * Read the timing data for the interface and return the
- * mode that is being used.
- */
-
-static byte siimage_taskfile_timing (ide_hwif_t *hwif)
-{
- u16 timing = 0x328a;
- unsigned long addr = siimage_selreg(hwif, 2);
-
- if (hwif->mmio)
- timing = hwif->INW(addr);
- else
- pci_read_config_word(hwif->pci_dev, addr, &timing);
-
- switch (timing) {
- case 0x10c1: return 4;
- case 0x10c3: return 3;
- case 0x1104:
- case 0x1281: return 2;
- case 0x2283: return 1;
- case 0x328a:
- default: return 0;
- }
-}
-
-/**
- * simmage_tuneproc - tune a drive
+ * sil_tune_pio - tune a drive
* @drive: drive to tune
- * @mode_wanted: the target operating mode
+ * @pio: the desired PIO mode
*
* Load the timing settings for this device mode into the
* controller. If we are in PIO mode 3 or 4 turn on IORDY
* monitoring (bit 9). The TF timing is bits 31:16
*/
-
-static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+
+static void sil_tune_pio(ide_drive_t *drive, u8 pio)
{
+ const u16 tf_speed[] = { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
+ const u16 data_speed[] = { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+
ide_hwif_t *hwif = HWIF(drive);
+ ide_drive_t *pair = &hwif->drives[drive->dn ^ 1];
u32 speedt = 0;
u16 speedp = 0;
unsigned long addr = siimage_seldev(drive, 0x04);
unsigned long tfaddr = siimage_selreg(hwif, 0x02);
-
- /* cheat for now and use the docs */
- switch (mode_wanted) {
- case 4:
- speedp = 0x10c1;
- speedt = 0x10c1;
- break;
- case 3:
- speedp = 0x10c3;
- speedt = 0x10c3;
- break;
- case 2:
- speedp = 0x1104;
- speedt = 0x1281;
- break;
- case 1:
- speedp = 0x2283;
- speedt = 0x2283;
- break;
- case 0:
- default:
- speedp = 0x328a;
- speedt = 0x328a;
- break;
+ u8 tf_pio = pio;
+
+ /* trim *taskfile* PIO to the slowest of the master/slave */
+ if (pair->present) {
+ u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+
+ if (pair_pio < tf_pio)
+ tf_pio = pair_pio;
}
+ /* cheat for now and use the docs */
+ 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(mode_wanted == 3 || mode_wanted == 4)
+ if (pio > 2)
hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
else
hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
@@ -245,42 +213,17 @@ static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
speedp &= ~0x200;
/* Set IORDY for mode 3 or 4 */
- if(mode_wanted == 3 || mode_wanted == 4)
+ if (pio > 2)
speedp |= 0x200;
pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
}
}
-/**
- * config_siimage_chipset_for_pio - set drive timings
- * @drive: drive to tune
- * @speed we want
- *
- * Compute the best pio mode we can for a given device. Also honour
- * the timings for the driver when dealing with mixed devices. Some
- * of this is ugly but its all wrapped up here
- *
- * The SI680 can also do VDMA - we need to start using that
- *
- * FIXME: we use the BIOS channel timings to avoid driving the task
- * files too fast at the disk. We need to compute the master/slave
- * drive PIO mode properly so that we can up the speed on a hotplug
- * system.
- */
-
-static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static void sil_tuneproc(ide_drive_t *drive, u8 pio)
{
- u8 channel_timings = siimage_taskfile_timing(HWIF(drive));
- u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 4, 5, NULL);
-
- /* WARNING PIO timing mess is going to happen b/w devices, argh */
- if ((channel_timings != set_pio) && (set_pio > channel_timings))
- set_pio = channel_timings;
-
- siimage_tuneproc(drive, set_pio);
- speed = XFER_PIO_0 + set_pio;
- if (set_speed)
- (void) ide_config_drive_speed(drive, speed);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
+ sil_tune_pio(drive, pio);
+ (void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
/**
@@ -335,7 +278,7 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
case XFER_PIO_2:
case XFER_PIO_1:
case XFER_PIO_0:
- siimage_tuneproc(drive, (speed - XFER_PIO_0));
+ sil_tune_pio(drive, speed - XFER_PIO_0);
mode |= ((unit) ? 0x10 : 0x01);
break;
case XFER_MW_DMA_2:
@@ -343,7 +286,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
case XFER_MW_DMA_0:
multi = dma[speed - XFER_MW_DMA_0];
mode |= ((unit) ? 0x20 : 0x02);
- config_siimage_chipset_for_pio(drive, 0);
break;
case XFER_UDMA_6:
case XFER_UDMA_5:
@@ -356,7 +298,6 @@ static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
(ultra5[speed - XFER_UDMA_0]));
mode |= ((unit) ? 0x30 : 0x03);
- config_siimage_chipset_for_pio(drive, 0);
break;
default:
return 1;
@@ -390,7 +331,7 @@ static int siimage_config_drive_for_dma (ide_drive_t *drive)
return 0;
if (ide_use_fast_pio(drive))
- config_siimage_chipset_for_pio(drive, 1);
+ sil_tuneproc(drive, 255);
return -1;
}
@@ -961,7 +902,7 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
hwif->resetproc = &siimage_reset;
hwif->speedproc = &siimage_tune_chipset;
- hwif->tuneproc = &siimage_tuneproc;
+ hwif->tuneproc = &sil_tuneproc;
hwif->reset_poll = &siimage_reset_poll;
hwif->pre_reset = &siimage_pre_reset;
hwif->udma_filter = &sil_udma_filter;
@@ -976,11 +917,11 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
first = 0;
}
}
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
+
+ hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+ if (hwif->dma_base == 0)
return;
- }
hwif->ultra_mask = 0x7f;
hwif->mwdma_mask = 0x07;
@@ -1016,9 +957,9 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
.init_iops = init_iops_siimage, \
.init_hwif = init_hwif_siimage, \
.fixup = siimage_fixup, \
- .channels = 2, \
.autodma = AUTODMA, \
.bootable = ON_BOARD, \
+ .pio_mask = ATA_PIO4, \
}
static ide_pci_device_t siimage_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index f875183ac8d9..63fbb79e8178 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -521,7 +521,7 @@ static void config_art_rwp_pio (ide_drive_t *drive, u8 pio)
static int sis5513_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
config_art_rwp_pio(drive, pio);
return ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
@@ -659,9 +659,7 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
/* Special case for SiS630 : 630S/ET is ATA_100a */
if (SiSHostChipInfo[i].host_id == PCI_DEVICE_ID_SI_630) {
- u8 hostrev;
- pci_read_config_byte(host, PCI_REVISION_ID, &hostrev);
- if (hostrev >= 0x30)
+ if (host->revision >= 0x30)
chipset_family = ATA_100a;
}
pci_dev_put(host);
@@ -702,7 +700,6 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
u16 trueid;
u8 prefctl;
u8 idecfg;
- u8 sbrev;
pci_read_config_byte(dev, 0x4a, &idecfg);
pci_write_config_byte(dev, 0x4a, idecfg | 0x10);
@@ -712,11 +709,10 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
if (trueid == 0x5517) { /* SiS 961/961B */
lpc_bridge = pci_get_slot(dev->bus, 0x10); /* Bus 0, Dev 2, Fn 0 */
- pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
pci_read_config_byte(dev, 0x49, &prefctl);
pci_dev_put(lpc_bridge);
- if (sbrev == 0x10 && (prefctl & 0x80)) {
+ if (lpc_bridge->revision == 0x10 && (prefctl & 0x80)) {
printk(KERN_INFO "SIS5513: SiS 961B MuTIOL IDE UDMA133 controller\n");
chipset_family = ATA_133a;
} else {
@@ -882,10 +878,10 @@ static ide_pci_device_t sis5513_chipset __devinitdata = {
.name = "SIS5513",
.init_chipset = init_chipset_sis5513,
.init_hwif = init_hwif_sis5513,
- .channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 487879842af4..0947cab00595 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -52,12 +52,13 @@
* Convert a PIO mode and cycle time to the required on/off times
* for the interface. This has protection against runaway timings.
*/
-static unsigned int get_pio_timings(ide_pio_data_t *p)
+static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
{
unsigned int cmd_on, cmd_off;
+ u8 iordy = 0;
- cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
- cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+ cmd_on = (ide_pio_timings[pio].active_time + 29) / 30;
+ cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30;
if (cmd_on == 0)
cmd_on = 1;
@@ -65,7 +66,10 @@ static unsigned int get_pio_timings(ide_pio_data_t *p)
if (cmd_off == 0)
cmd_off = 1;
- return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+ if (pio > 2 || ide_dev_has_iordy(drive->id))
+ iordy = 0x40;
+
+ return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
}
/*
@@ -75,14 +79,13 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
{
struct pci_dev *dev = HWIF(drive)->pci_dev;
int reg = 0x44 + drive->dn * 4;
- ide_pio_data_t p;
u16 drv_ctrl;
DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio));
- pio = ide_get_best_pio_mode(drive, pio, 5, &p);
+ pio = ide_get_best_pio_mode(drive, pio, 5);
- drv_ctrl = get_pio_timings(&p);
+ drv_ctrl = get_pio_timings(drive, pio);
/*
* Store the PIO timings so that we can restore them
@@ -101,7 +104,8 @@ static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
}
printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
- ide_xfer_verbose(pio + XFER_PIO_0), p.cycle_time, drv_ctrl);
+ ide_xfer_verbose(pio + XFER_PIO_0),
+ ide_pio_cycle_time(drive, pio), drv_ctrl);
return pio;
}
@@ -338,7 +342,6 @@ static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio)
static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
{
struct pci_dev *bridge;
- u8 rev;
/*
* The bridge should be part of the same device, but function 0.
@@ -360,10 +363,9 @@ static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
/*
* We need to find function 0's revision, not function 1
*/
- pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
pci_dev_put(bridge);
- return rev;
+ return bridge->revision;
}
/*
@@ -451,10 +453,10 @@ static ide_pci_device_t sl82c105_chipset __devinitdata = {
.name = "W82C105",
.init_chipset = init_chipset_sl82c105,
.init_hwif = init_hwif_sl82c105,
- .channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO5,
};
static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 575dbbd8b482..8e655f2db5cb 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -103,7 +103,7 @@ static void slc90e66_tune_pio (ide_drive_t *drive, u8 pio)
static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
slc90e66_tune_pio(drive, pio);
(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
}
@@ -214,10 +214,10 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
static ide_pci_device_t slc90e66_chipset __devinitdata = {
.name = "SLC90E66",
.init_hwif = init_hwif_slc90e66,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index 8de1f8e22494..ec79bacc30c2 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -47,7 +47,7 @@ static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
{
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
(void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
}
@@ -248,9 +248,10 @@ static ide_pci_device_t tc86c001_chipset __devinitdata = {
.name = "TC86C001",
.init_chipset = init_chipset_tc86c001,
.init_hwif = init_hwif_tc86c001,
- .channels = 1,
.autodma = AUTODMA,
- .bootable = OFF_BOARD
+ .bootable = OFF_BOARD,
+ .host_flags = IDE_HFLAG_SINGLE,
+ .pio_mask = ATA_PIO4,
};
static int __devinit tc86c001_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index 35e8c612638f..024bbfae0429 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -96,7 +96,7 @@ static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
{
- int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+ int use_pio = ide_get_best_pio_mode(drive, pio, 4);
(void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
}
@@ -129,10 +129,10 @@ static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
static ide_pci_device_t triflex_device __devinitdata = {
.name = "TRIFLEX",
.init_hwif = init_hwif_triflex,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
.bootable = ON_BOARD,
+ .pio_mask = ATA_PIO4,
};
static int __devinit triflex_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index cbb1b11119a5..dc4f4e298e00 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -327,7 +327,6 @@ static void __devinit init_hwif_trm290(ide_hwif_t *hwif)
static ide_pci_device_t trm290_chipset __devinitdata = {
.name = "TRM290",
.init_hwif = init_hwif_trm290,
- .channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
};
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index d21dd2e7eeb3..581316f9581d 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -1,6 +1,6 @@
/*
*
- * Version 3.45
+ * Version 3.46
*
* VIA IDE driver for Linux. Supported southbridges:
*
@@ -203,10 +203,8 @@ static int via_set_drive(ide_drive_t *drive, u8 speed)
static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
{
- if (pio == 255) {
- via_set_drive(drive, ide_find_best_pio_mode(drive));
- return;
- }
+ if (pio == 255)
+ pio = ide_get_best_pio_mode(drive, 255, 5);
via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
}
@@ -223,12 +221,14 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive)
{
u8 speed = ide_max_dma_mode(drive);
- if (speed == 0)
- speed = ide_find_best_pio_mode(drive);
+ if (speed == 0) {
+ via82cxxx_tune_drive(drive, 255);
+ return -1;
+ }
via_set_drive(drive, speed);
- if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+ if (drive->autodma)
return 0;
return -1;
@@ -237,16 +237,14 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive)
static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
{
struct via_isa_bridge *via_config;
- u8 t;
for (via_config = via_isa_bridges; via_config->id; via_config++)
if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA +
!!(via_config->flags & VIA_BAD_ID),
via_config->id, NULL))) {
- pci_read_config_byte(*isa, PCI_REVISION_ID, &t);
- if (t >= via_config->rev_min &&
- t <= via_config->rev_max)
+ if ((*isa)->revision >= via_config->rev_min &&
+ (*isa)->revision <= via_config->rev_max)
break;
pci_dev_put(*isa);
}
@@ -404,10 +402,9 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
* Print the boot message.
*/
- pci_read_config_byte(isa, PCI_REVISION_ID, &t);
printk(KERN_INFO "VP_IDE: VIA %s (rev %02x) IDE %sDMA%s "
"controller on pci%s\n",
- via_config->name, t,
+ via_config->name, isa->revision,
via_config->udma_mask ? "U" : "MW",
via_dma[via_config->udma_mask ?
(fls(via_config->udma_mask) - 1) : 0],
@@ -501,18 +498,22 @@ static ide_pci_device_t via82cxxx_chipsets[] __devinitdata = {
.name = "VP_IDE",
.init_chipset = init_chipset_via82cxxx,
.init_hwif = init_hwif_via82cxxx,
- .channels = 2,
.autodma = NOAUTODMA,
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
- .bootable = ON_BOARD
+ .bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
+ | IDE_HFLAG_PIO_NO_DOWNGRADE,
+ .pio_mask = ATA_PIO5,
},{ /* 1 */
.name = "VP_IDE",
.init_chipset = init_chipset_via82cxxx,
.init_hwif = init_hwif_via82cxxx,
- .channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
.bootable = ON_BOARD,
+ .host_flags = IDE_HFLAG_PIO_NO_BLACKLIST
+ | IDE_HFLAG_PIO_NO_DOWNGRADE,
+ .pio_mask = ATA_PIO5,
}
};
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index 82de2d781f2e..8859fe2f5ac2 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -316,6 +316,7 @@ m8xx_ide_init_hwif_ports(hw_regs_t *hw, unsigned long data_port,
}
/* register routine to tune PIO mode */
+ ide_hwifs[data_port].pio_mask = ATA_PIO4;
ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
@@ -402,6 +403,7 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
}
/* register routine to tune PIO mode */
+ ide_hwifs[data_port].pio_mask = ATA_PIO4;
ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
@@ -431,13 +433,12 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw,
static void
m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
{
- ide_pio_data_t d;
#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
volatile pcmconf8xx_t *pcmp;
ulong timing, mask, reg;
#endif
- pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
#if 1
printk("%s[%d] %s: best PIO mode: %d\n",
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index e46f47206542..33630ad3e794 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -615,24 +615,25 @@ out:
static void
pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
{
- ide_pio_data_t d;
u32 *timings;
unsigned accessTicks, recTicks;
unsigned accessTime, recTime;
pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
-
+ unsigned int cycle_time;
+
if (pmif == NULL)
return;
/* which drive is it ? */
timings = &pmif->timings[drive->select.b.unit & 0x01];
- pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+ pio = ide_get_best_pio_mode(drive, pio, 4);
+ cycle_time = ide_pio_cycle_time(drive, pio);
switch (pmif->kind) {
case controller_sh_ata6: {
/* 133Mhz cell */
- u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time);
+ u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
if (tr == 0)
return;
*timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
@@ -641,7 +642,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
case controller_un_ata6:
case controller_k2_ata6: {
/* 100Mhz cell */
- u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time);
+ u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
if (tr == 0)
return;
*timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
@@ -649,7 +650,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
}
case controller_kl_ata4:
/* 66Mhz cell */
- recTime = d.cycle_time - ide_pio_timings[pio].active_time
+ recTime = cycle_time - ide_pio_timings[pio].active_time
- ide_pio_timings[pio].setup_time;
recTime = max(recTime, 150U);
accessTime = ide_pio_timings[pio].active_time;
@@ -665,7 +666,7 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
default: {
/* 33Mhz cell */
int ebit = 0;
- recTime = d.cycle_time - ide_pio_timings[pio].active_time
+ recTime = cycle_time - ide_pio_timings[pio].active_time
- ide_pio_timings[pio].setup_time;
recTime = max(recTime, 150U);
accessTime = ide_pio_timings[pio].active_time;
@@ -1247,6 +1248,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
hwif->drives[0].unmask = 1;
hwif->drives[1].unmask = 1;
+ hwif->pio_mask = ATA_PIO4;
hwif->tuneproc = pmac_ide_tuneproc;
if (pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index c88d33225cf9..30e596c0f120 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -5,12 +5,6 @@
*
* Copyright (c) 1995-1998 Mark Lord
* May be copied or modified under the terms of the GNU General Public License
- *
- * Recent Changes
- * Split the set up function into multiple functions
- * Use pci_set_master
- * Fix misreporting of I/O v MMIO problems
- * Initial fixups for simplex devices
*/
/*
@@ -407,7 +401,7 @@ static ide_hwif_t *ide_hwif_configure(struct pci_dev *dev, ide_pci_device_t *d,
unsigned long ctl = 0, base = 0;
ide_hwif_t *hwif;
- if ((d->flags & IDEPCI_FLAG_ISA_PORTS) == 0) {
+ 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);
@@ -571,7 +565,7 @@ out:
void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, ata_index_t *index)
{
- int port;
+ int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
int at_least_one_hwif_enabled = 0;
ide_hwif_t *hwif, *mate = NULL;
u8 tmp;
@@ -582,16 +576,13 @@ void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, a
* Set up the IDE ports
*/
- for (port = 0; port <= 1; ++port) {
+ for (port = 0; port < channels; ++port) {
ide_pci_enablebit_t *e = &(d->enablebits[port]);
if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
(tmp & e->mask) != e->val))
continue; /* port not enabled */
- if (d->channels <= port)
- break;
-
if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
continue;
@@ -616,6 +607,9 @@ void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, a
else
ide_hwif_setup_dma(dev, d, hwif);
bypass_legacy_dma:
+ hwif->host_flags = d->host_flags;
+ hwif->pio_mask = d->pio_mask;
+
if (d->init_hwif)
/* Call chipset-specific routine
* for each enabled hwif
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 93362eed94ed..3a9d7e2d4de6 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -1729,7 +1729,7 @@ static int __init ether1394_init_module(void)
packet_task_cache = kmem_cache_create("packet_task",
sizeof(struct packet_task),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!packet_task_cache)
return -ENOMEM;
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 0fc8c6e559e4..ee45259573c8 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -30,6 +30,7 @@
#include <linux/moduleparam.h>
#include <linux/bitops.h>
#include <linux/kdev_t.h>
+#include <linux/freezer.h>
#include <linux/suspend.h>
#include <linux/kthread.h>
#include <linux/preempt.h>
@@ -1128,8 +1129,6 @@ static int hpsbpkt_thread(void *__hi)
struct list_head tmp;
int may_schedule;
- current->flags |= PF_NOFREEZE;
-
while (!kthread_should_stop()) {
INIT_LIST_HEAD(&tmp);
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index c4d3d4131f01..2ffd53461db6 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -283,7 +283,7 @@ static ssize_t fw_show_##class##_##td_kv (struct device *dev, struct device_attr
memcpy(buf, \
CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(class->td_kv), \
len); \
- while ((buf + len - 1) == '\0') \
+ while (buf[len - 1] == '\0') \
len--; \
buf[len++] = '\n'; \
buf[len] = '\0'; \
@@ -1699,6 +1699,7 @@ static int nodemgr_host_thread(void *__hi)
unsigned int g, generation = 0;
int i, reset_cycles = 0;
+ set_freezable();
/* Setup our device-model entries */
nodemgr_create_host_dev_files(host);
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index e0c385a3b450..e882cb951b47 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1509,69 +1509,6 @@ static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
}
}
-static void sbp2_prep_command_orb_no_sg(struct sbp2_command_orb *orb,
- struct sbp2_fwhost_info *hi,
- struct sbp2_command_info *cmd,
- struct scatterlist *sgpnt,
- u32 orb_direction,
- unsigned int scsi_request_bufflen,
- void *scsi_request_buffer,
- enum dma_data_direction dma_dir)
-{
- cmd->dma_dir = dma_dir;
- cmd->dma_size = scsi_request_bufflen;
- cmd->dma_type = CMD_DMA_SINGLE;
- cmd->cmd_dma = dma_map_single(hi->host->device.parent,
- scsi_request_buffer,
- cmd->dma_size, cmd->dma_dir);
- orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
- orb->misc |= ORB_SET_DIRECTION(orb_direction);
-
- /* handle case where we get a command w/o s/g enabled
- * (but check for transfers larger than 64K) */
- if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) {
-
- orb->data_descriptor_lo = cmd->cmd_dma;
- orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);
-
- } else {
- /* The buffer is too large. Turn this into page tables. */
-
- struct sbp2_unrestricted_page_table *sg_element =
- &cmd->scatter_gather_element[0];
- u32 sg_count, sg_len;
- dma_addr_t sg_addr;
-
- orb->data_descriptor_lo = cmd->sge_dma;
- orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
-
- /* fill out our SBP-2 page tables; split up the large buffer */
- sg_count = 0;
- sg_len = scsi_request_bufflen;
- sg_addr = cmd->cmd_dma;
- while (sg_len) {
- sg_element[sg_count].segment_base_lo = sg_addr;
- if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {
- sg_element[sg_count].length_segment_base_hi =
- PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
- sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
- sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
- } else {
- sg_element[sg_count].length_segment_base_hi =
- PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
- sg_len = 0;
- }
- sg_count++;
- }
-
- orb->misc |= ORB_SET_DATA_SIZE(sg_count);
-
- sbp2util_cpu_to_be32_buffer(sg_element,
- (sizeof(struct sbp2_unrestricted_page_table)) *
- sg_count);
- }
-}
-
static void sbp2_create_command_orb(struct sbp2_lu *lu,
struct sbp2_command_info *cmd,
unchar *scsi_cmd,
@@ -1615,13 +1552,9 @@ static void sbp2_create_command_orb(struct sbp2_lu *lu,
orb->data_descriptor_hi = 0x0;
orb->data_descriptor_lo = 0x0;
orb->misc |= ORB_SET_DIRECTION(1);
- } else if (scsi_use_sg)
+ } else
sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_use_sg, sgpnt,
orb_direction, dma_dir);
- else
- sbp2_prep_command_orb_no_sg(orb, hi, cmd, sgpnt, orb_direction,
- scsi_request_bufflen,
- scsi_request_buffer, dma_dir);
sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
@@ -1710,15 +1643,15 @@ static int sbp2_send_command(struct sbp2_lu *lu, struct scsi_cmnd *SCpnt,
void (*done)(struct scsi_cmnd *))
{
unchar *scsi_cmd = (unchar *)SCpnt->cmnd;
- unsigned int request_bufflen = SCpnt->request_bufflen;
+ unsigned int request_bufflen = scsi_bufflen(SCpnt);
struct sbp2_command_info *cmd;
cmd = sbp2util_allocate_command_orb(lu, SCpnt, done);
if (!cmd)
return -EIO;
- sbp2_create_command_orb(lu, cmd, scsi_cmd, SCpnt->use_sg,
- request_bufflen, SCpnt->request_buffer,
+ sbp2_create_command_orb(lu, cmd, scsi_cmd, scsi_sg_count(SCpnt),
+ request_bufflen, scsi_sglist(SCpnt),
SCpnt->sc_data_direction);
sbp2_link_orb_command(lu, cmd);
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 994decc7bcf2..a193dfbf99d2 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -1,14 +1,14 @@
-menu "InfiniBand support"
- depends on HAS_IOMEM
-
-config INFINIBAND
- depends on PCI || BROKEN
+menuconfig INFINIBAND
tristate "InfiniBand support"
+ depends on PCI || BROKEN
+ depends on HAS_IOMEM
---help---
Core support for InfiniBand (IB). Make sure to also select
any protocols you wish to use as well as drivers for your
InfiniBand hardware.
+if INFINIBAND
+
config INFINIBAND_USER_MAD
tristate "InfiniBand userspace MAD support"
depends on INFINIBAND
@@ -20,7 +20,6 @@ config INFINIBAND_USER_MAD
config INFINIBAND_USER_ACCESS
tristate "InfiniBand userspace access (verbs and CM)"
- depends on INFINIBAND
---help---
Userspace InfiniBand access support. This enables the
kernel side of userspace verbs and the userspace
@@ -37,7 +36,7 @@ config INFINIBAND_USER_MEM
config INFINIBAND_ADDR_TRANS
bool
- depends on INFINIBAND && INET
+ depends on INET
default y
source "drivers/infiniband/hw/mthca/Kconfig"
@@ -54,4 +53,4 @@ source "drivers/infiniband/ulp/srp/Kconfig"
source "drivers/infiniband/ulp/iser/Kconfig"
-endmenu
+endif # INFINIBAND
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index a91001c59b69..c5c33d35f87d 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -295,10 +295,9 @@ int rdma_resolve_ip(struct rdma_addr_client *client,
struct addr_req *req;
int ret = 0;
- req = kmalloc(sizeof *req, GFP_KERNEL);
+ req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
return -ENOMEM;
- memset(req, 0, sizeof *req);
if (src_addr)
memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
index ecd1a3057c61..db2633e4aae6 100644
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -3,7 +3,7 @@
* Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved.
* Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
* Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved.
- * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
+ * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -34,7 +34,6 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
- * $Id: agent.c 1389 2004-12-27 22:56:47Z roland $
*/
#include <linux/slab.h>
@@ -42,6 +41,7 @@
#include "agent.h"
#include "smi.h"
+#include "mad_priv.h"
#define SPFX "ib_agent: "
@@ -87,8 +87,13 @@ int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
struct ib_mad_send_buf *send_buf;
struct ib_ah *ah;
int ret;
+ struct ib_mad_send_wr_private *mad_send_wr;
+
+ if (device->node_type == RDMA_NODE_IB_SWITCH)
+ port_priv = ib_get_agent_port(device, 0);
+ else
+ port_priv = ib_get_agent_port(device, port_num);
- port_priv = ib_get_agent_port(device, port_num);
if (!port_priv) {
printk(KERN_ERR SPFX "Unable to find port agent\n");
return -ENODEV;
@@ -113,6 +118,14 @@ int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
memcpy(send_buf->mad, mad, sizeof *mad);
send_buf->ah = ah;
+
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
+ mad_send_wr = container_of(send_buf,
+ struct ib_mad_send_wr_private,
+ send_buf);
+ mad_send_wr->send_wr.wr.ud.port_num = port_num;
+ }
+
if ((ret = ib_post_send_mad(send_buf, NULL))) {
printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret);
goto err2;
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 40c004a2697e..4df269f5d9ac 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -87,6 +87,7 @@ struct cm_port {
struct cm_device {
struct list_head list;
struct ib_device *device;
+ u8 ack_delay;
struct cm_port port[0];
};
@@ -95,7 +96,7 @@ struct cm_av {
union ib_gid dgid;
struct ib_ah_attr ah_attr;
u16 pkey_index;
- u8 packet_life_time;
+ u8 timeout;
};
struct cm_work {
@@ -154,6 +155,7 @@ struct cm_id_private {
u8 retry_count;
u8 rnr_retry_count;
u8 service_timeout;
+ u8 target_ack_delay;
struct list_head work_list;
atomic_t work_count;
@@ -293,7 +295,7 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
av->port = port;
ib_init_ah_from_path(cm_dev->device, port->port_num, path,
&av->ah_attr);
- av->packet_life_time = path->packet_life_time;
+ av->timeout = path->packet_life_time + 1;
return 0;
}
@@ -318,12 +320,10 @@ static int cm_alloc_id(struct cm_id_private *cm_id_priv)
static void cm_free_id(__be32 local_id)
{
- unsigned long flags;
-
- spin_lock_irqsave(&cm.lock, flags);
+ spin_lock_irq(&cm.lock);
idr_remove(&cm.local_id_table,
(__force int) (local_id ^ cm.random_id_operand));
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
}
static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id)
@@ -345,11 +345,10 @@ static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id)
static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id)
{
struct cm_id_private *cm_id_priv;
- unsigned long flags;
- spin_lock_irqsave(&cm.lock, flags);
+ spin_lock_irq(&cm.lock);
cm_id_priv = cm_get_id(local_id, remote_id);
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
return cm_id_priv;
}
@@ -646,6 +645,25 @@ static inline int cm_convert_to_ms(int iba_time)
return 1 << max(iba_time - 8, 0);
}
+/*
+ * calculate: 4.096x2^ack_timeout = 4.096x2^ack_delay + 2x4.096x2^life_time
+ * Because of how ack_timeout is stored, adding one doubles the timeout.
+ * To avoid large timeouts, select the max(ack_delay, life_time + 1), and
+ * increment it (round up) only if the other is within 50%.
+ */
+static u8 cm_ack_timeout(u8 ca_ack_delay, u8 packet_life_time)
+{
+ int ack_timeout = packet_life_time + 1;
+
+ if (ack_timeout >= ca_ack_delay)
+ ack_timeout += (ca_ack_delay >= (ack_timeout - 1));
+ else
+ ack_timeout = ca_ack_delay +
+ (ack_timeout >= (ca_ack_delay - 1));
+
+ return min(31, ack_timeout);
+}
+
static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
{
if (timewait_info->inserted_remote_id) {
@@ -689,7 +707,7 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
* timewait before notifying the user that we've exited timewait.
*/
cm_id_priv->id.state = IB_CM_TIMEWAIT;
- wait_time = cm_convert_to_ms(cm_id_priv->av.packet_life_time + 1);
+ wait_time = cm_convert_to_ms(cm_id_priv->av.timeout);
queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work,
msecs_to_jiffies(wait_time));
cm_id_priv->timewait_info = NULL;
@@ -713,31 +731,30 @@ static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
{
struct cm_id_private *cm_id_priv;
struct cm_work *work;
- unsigned long flags;
cm_id_priv = container_of(cm_id, struct cm_id_private, id);
retest:
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
switch (cm_id->state) {
case IB_CM_LISTEN:
cm_id->state = IB_CM_IDLE;
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
- spin_lock_irqsave(&cm.lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
+ spin_lock_irq(&cm.lock);
rb_erase(&cm_id_priv->service_node, &cm.listen_service_table);
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
break;
case IB_CM_SIDR_REQ_SENT:
cm_id->state = IB_CM_IDLE;
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
break;
case IB_CM_SIDR_REQ_RCVD:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT);
break;
case IB_CM_REQ_SENT:
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ib_send_cm_rej(cm_id, IB_CM_REJ_TIMEOUT,
&cm_id_priv->id.device->node_guid,
sizeof cm_id_priv->id.device->node_guid,
@@ -747,9 +764,9 @@ retest:
if (err == -ENOMEM) {
/* Do not reject to allow future retries. */
cm_reset_to_idle(cm_id_priv);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
} else {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
NULL, 0, NULL, 0);
}
@@ -762,25 +779,25 @@ retest:
case IB_CM_MRA_REQ_SENT:
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
NULL, 0, NULL, 0);
break;
case IB_CM_ESTABLISHED:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ib_send_cm_dreq(cm_id, NULL, 0);
goto retest;
case IB_CM_DREQ_SENT:
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
cm_enter_timewait(cm_id_priv);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
break;
case IB_CM_DREQ_RCVD:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ib_send_cm_drep(cm_id, NULL, 0);
break;
default:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
break;
}
@@ -912,7 +929,8 @@ static void cm_format_req(struct cm_req_msg *req_msg,
cm_req_set_primary_sl(req_msg, param->primary_path->sl);
cm_req_set_primary_subnet_local(req_msg, 1); /* local only... */
cm_req_set_primary_local_ack_timeout(req_msg,
- min(31, param->primary_path->packet_life_time + 1));
+ cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
+ param->primary_path->packet_life_time));
if (param->alternate_path) {
req_msg->alt_local_lid = param->alternate_path->slid;
@@ -927,7 +945,8 @@ static void cm_format_req(struct cm_req_msg *req_msg,
cm_req_set_alt_sl(req_msg, param->alternate_path->sl);
cm_req_set_alt_subnet_local(req_msg, 1); /* local only... */
cm_req_set_alt_local_ack_timeout(req_msg,
- min(31, param->alternate_path->packet_life_time + 1));
+ cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
+ param->alternate_path->packet_life_time));
}
if (param->private_data && param->private_data_len)
@@ -1169,7 +1188,6 @@ static void cm_format_req_event(struct cm_work *work,
static void cm_process_work(struct cm_id_private *cm_id_priv,
struct cm_work *work)
{
- unsigned long flags;
int ret;
/* We will typically only have the current event to report. */
@@ -1177,9 +1195,9 @@ static void cm_process_work(struct cm_id_private *cm_id_priv,
cm_free_work(work);
while (!ret && !atomic_add_negative(-1, &cm_id_priv->work_count)) {
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
work = cm_dequeue_work(cm_id_priv);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
BUG_ON(!work);
ret = cm_id_priv->id.cm_handler(&cm_id_priv->id,
&work->cm_event);
@@ -1250,7 +1268,6 @@ static void cm_dup_req_handler(struct cm_work *work,
struct cm_id_private *cm_id_priv)
{
struct ib_mad_send_buf *msg = NULL;
- unsigned long flags;
int ret;
/* Quick state check to discard duplicate REQs. */
@@ -1261,7 +1278,7 @@ static void cm_dup_req_handler(struct cm_work *work,
if (ret)
return;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
switch (cm_id_priv->id.state) {
case IB_CM_MRA_REQ_SENT:
cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
@@ -1276,14 +1293,14 @@ static void cm_dup_req_handler(struct cm_work *work,
default:
goto unlock;
}
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ret = ib_post_send_mad(msg, NULL);
if (ret)
goto free;
return;
-unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+unlock: spin_unlock_irq(&cm_id_priv->lock);
free: cm_free_msg(msg);
}
@@ -1293,17 +1310,16 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
struct cm_id_private *listen_cm_id_priv, *cur_cm_id_priv;
struct cm_timewait_info *timewait_info;
struct cm_req_msg *req_msg;
- unsigned long flags;
req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
/* Check for possible duplicate REQ. */
- spin_lock_irqsave(&cm.lock, flags);
+ spin_lock_irq(&cm.lock);
timewait_info = cm_insert_remote_id(cm_id_priv->timewait_info);
if (timewait_info) {
cur_cm_id_priv = cm_get_id(timewait_info->work.local_id,
timewait_info->work.remote_id);
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
if (cur_cm_id_priv) {
cm_dup_req_handler(work, cur_cm_id_priv);
cm_deref_id(cur_cm_id_priv);
@@ -1315,7 +1331,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info);
if (timewait_info) {
cm_cleanup_timewait(cm_id_priv->timewait_info);
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
cm_issue_rej(work->port, work->mad_recv_wc,
IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ,
NULL, 0);
@@ -1328,7 +1344,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
req_msg->private_data);
if (!listen_cm_id_priv) {
cm_cleanup_timewait(cm_id_priv->timewait_info);
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
cm_issue_rej(work->port, work->mad_recv_wc,
IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
NULL, 0);
@@ -1338,7 +1354,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
atomic_inc(&cm_id_priv->refcount);
cm_id_priv->id.state = IB_CM_REQ_RCVD;
atomic_inc(&cm_id_priv->work_count);
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
out:
return listen_cm_id_priv;
}
@@ -1440,7 +1456,8 @@ static void cm_format_rep(struct cm_rep_msg *rep_msg,
cm_rep_set_starting_psn(rep_msg, cpu_to_be32(param->starting_psn));
rep_msg->resp_resources = param->responder_resources;
rep_msg->initiator_depth = param->initiator_depth;
- cm_rep_set_target_ack_delay(rep_msg, param->target_ack_delay);
+ cm_rep_set_target_ack_delay(rep_msg,
+ cm_id_priv->av.port->cm_dev->ack_delay);
cm_rep_set_failover(rep_msg, param->failover_accepted);
cm_rep_set_flow_ctrl(rep_msg, param->flow_control);
cm_rep_set_rnr_retry_count(rep_msg, param->rnr_retry_count);
@@ -1591,7 +1608,6 @@ static void cm_dup_rep_handler(struct cm_work *work)
struct cm_id_private *cm_id_priv;
struct cm_rep_msg *rep_msg;
struct ib_mad_send_buf *msg = NULL;
- unsigned long flags;
int ret;
rep_msg = (struct cm_rep_msg *) work->mad_recv_wc->recv_buf.mad;
@@ -1604,7 +1620,7 @@ static void cm_dup_rep_handler(struct cm_work *work)
if (ret)
goto deref;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state == IB_CM_ESTABLISHED)
cm_format_rtu((struct cm_rtu_msg *) msg->mad, cm_id_priv,
cm_id_priv->private_data,
@@ -1616,14 +1632,14 @@ static void cm_dup_rep_handler(struct cm_work *work)
cm_id_priv->private_data_len);
else
goto unlock;
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ret = ib_post_send_mad(msg, NULL);
if (ret)
goto free;
goto deref;
-unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+unlock: spin_unlock_irq(&cm_id_priv->lock);
free: cm_free_msg(msg);
deref: cm_deref_id(cm_id_priv);
}
@@ -1632,7 +1648,6 @@ static int cm_rep_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
struct cm_rep_msg *rep_msg;
- unsigned long flags;
int ret;
rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad;
@@ -1644,13 +1659,13 @@ static int cm_rep_handler(struct cm_work *work)
cm_format_rep_event(work);
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
switch (cm_id_priv->id.state) {
case IB_CM_REQ_SENT:
case IB_CM_MRA_REQ_RCVD:
break;
default:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ret = -EINVAL;
goto error;
}
@@ -1663,7 +1678,7 @@ static int cm_rep_handler(struct cm_work *work)
/* Check for duplicate REP. */
if (cm_insert_remote_id(cm_id_priv->timewait_info)) {
spin_unlock(&cm.lock);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ret = -EINVAL;
goto error;
}
@@ -1673,7 +1688,7 @@ static int cm_rep_handler(struct cm_work *work)
&cm.remote_id_table);
cm_id_priv->timewait_info->inserted_remote_id = 0;
spin_unlock(&cm.lock);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
cm_issue_rej(work->port, work->mad_recv_wc,
IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP,
NULL, 0);
@@ -1689,6 +1704,13 @@ static int cm_rep_handler(struct cm_work *work)
cm_id_priv->responder_resources = rep_msg->initiator_depth;
cm_id_priv->sq_psn = cm_rep_get_starting_psn(rep_msg);
cm_id_priv->rnr_retry_count = cm_rep_get_rnr_retry_count(rep_msg);
+ cm_id_priv->target_ack_delay = cm_rep_get_target_ack_delay(rep_msg);
+ cm_id_priv->av.timeout =
+ cm_ack_timeout(cm_id_priv->target_ack_delay,
+ cm_id_priv->av.timeout - 1);
+ cm_id_priv->alt_av.timeout =
+ cm_ack_timeout(cm_id_priv->target_ack_delay,
+ cm_id_priv->alt_av.timeout - 1);
/* todo: handle peer_to_peer */
@@ -1696,7 +1718,7 @@ static int cm_rep_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -1712,7 +1734,6 @@ error:
static int cm_establish_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
- unsigned long flags;
int ret;
/* See comment in cm_establish about lookup. */
@@ -1720,9 +1741,9 @@ static int cm_establish_handler(struct cm_work *work)
if (!cm_id_priv)
return -EINVAL;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state != IB_CM_ESTABLISHED) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
goto out;
}
@@ -1730,7 +1751,7 @@ static int cm_establish_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -1746,7 +1767,6 @@ static int cm_rtu_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
struct cm_rtu_msg *rtu_msg;
- unsigned long flags;
int ret;
rtu_msg = (struct cm_rtu_msg *)work->mad_recv_wc->recv_buf.mad;
@@ -1757,10 +1777,10 @@ static int cm_rtu_handler(struct cm_work *work)
work->cm_event.private_data = &rtu_msg->private_data;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state != IB_CM_REP_SENT &&
cm_id_priv->id.state != IB_CM_MRA_REP_RCVD) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
goto out;
}
cm_id_priv->id.state = IB_CM_ESTABLISHED;
@@ -1769,7 +1789,7 @@ static int cm_rtu_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -1932,7 +1952,6 @@ static int cm_dreq_handler(struct cm_work *work)
struct cm_id_private *cm_id_priv;
struct cm_dreq_msg *dreq_msg;
struct ib_mad_send_buf *msg = NULL;
- unsigned long flags;
int ret;
dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad;
@@ -1945,7 +1964,7 @@ static int cm_dreq_handler(struct cm_work *work)
work->cm_event.private_data = &dreq_msg->private_data;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->local_qpn != cm_dreq_get_remote_qpn(dreq_msg))
goto unlock;
@@ -1964,7 +1983,7 @@ static int cm_dreq_handler(struct cm_work *work)
cm_format_drep((struct cm_drep_msg *) msg->mad, cm_id_priv,
cm_id_priv->private_data,
cm_id_priv->private_data_len);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ib_post_send_mad(msg, NULL))
cm_free_msg(msg);
@@ -1977,7 +1996,7 @@ static int cm_dreq_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -1985,7 +2004,7 @@ static int cm_dreq_handler(struct cm_work *work)
cm_deref_id(cm_id_priv);
return 0;
-unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+unlock: spin_unlock_irq(&cm_id_priv->lock);
deref: cm_deref_id(cm_id_priv);
return -EINVAL;
}
@@ -1994,7 +2013,6 @@ static int cm_drep_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
struct cm_drep_msg *drep_msg;
- unsigned long flags;
int ret;
drep_msg = (struct cm_drep_msg *)work->mad_recv_wc->recv_buf.mad;
@@ -2005,10 +2023,10 @@ static int cm_drep_handler(struct cm_work *work)
work->cm_event.private_data = &drep_msg->private_data;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state != IB_CM_DREQ_SENT &&
cm_id_priv->id.state != IB_CM_DREQ_RCVD) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
goto out;
}
cm_enter_timewait(cm_id_priv);
@@ -2017,7 +2035,7 @@ static int cm_drep_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -2107,17 +2125,16 @@ static struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg)
{
struct cm_timewait_info *timewait_info;
struct cm_id_private *cm_id_priv;
- unsigned long flags;
__be32 remote_id;
remote_id = rej_msg->local_comm_id;
if (__be16_to_cpu(rej_msg->reason) == IB_CM_REJ_TIMEOUT) {
- spin_lock_irqsave(&cm.lock, flags);
+ spin_lock_irq(&cm.lock);
timewait_info = cm_find_remote_id( *((__be64 *) rej_msg->ari),
remote_id);
if (!timewait_info) {
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
return NULL;
}
cm_id_priv = idr_find(&cm.local_id_table, (__force int)
@@ -2129,7 +2146,7 @@ static struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg)
else
cm_id_priv = NULL;
}
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
} else if (cm_rej_get_msg_rejected(rej_msg) == CM_MSG_RESPONSE_REQ)
cm_id_priv = cm_acquire_id(rej_msg->remote_comm_id, 0);
else
@@ -2142,7 +2159,6 @@ static int cm_rej_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
struct cm_rej_msg *rej_msg;
- unsigned long flags;
int ret;
rej_msg = (struct cm_rej_msg *)work->mad_recv_wc->recv_buf.mad;
@@ -2152,7 +2168,7 @@ static int cm_rej_handler(struct cm_work *work)
cm_format_rej_event(work);
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
switch (cm_id_priv->id.state) {
case IB_CM_REQ_SENT:
case IB_CM_MRA_REQ_RCVD:
@@ -2176,7 +2192,7 @@ static int cm_rej_handler(struct cm_work *work)
cm_enter_timewait(cm_id_priv);
break;
default:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
ret = -EINVAL;
goto out;
}
@@ -2184,7 +2200,7 @@ static int cm_rej_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -2295,7 +2311,6 @@ static int cm_mra_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
struct cm_mra_msg *mra_msg;
- unsigned long flags;
int timeout, ret;
mra_msg = (struct cm_mra_msg *)work->mad_recv_wc->recv_buf.mad;
@@ -2307,9 +2322,9 @@ static int cm_mra_handler(struct cm_work *work)
work->cm_event.param.mra_rcvd.service_timeout =
cm_mra_get_service_timeout(mra_msg);
timeout = cm_convert_to_ms(cm_mra_get_service_timeout(mra_msg)) +
- cm_convert_to_ms(cm_id_priv->av.packet_life_time);
+ cm_convert_to_ms(cm_id_priv->av.timeout);
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
switch (cm_id_priv->id.state) {
case IB_CM_REQ_SENT:
if (cm_mra_get_msg_mraed(mra_msg) != CM_MSG_RESPONSE_REQ ||
@@ -2342,7 +2357,7 @@ static int cm_mra_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -2350,7 +2365,7 @@ static int cm_mra_handler(struct cm_work *work)
cm_deref_id(cm_id_priv);
return 0;
out:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
cm_deref_id(cm_id_priv);
return -EINVAL;
}
@@ -2379,7 +2394,8 @@ static void cm_format_lap(struct cm_lap_msg *lap_msg,
cm_lap_set_sl(lap_msg, alternate_path->sl);
cm_lap_set_subnet_local(lap_msg, 1); /* local only... */
cm_lap_set_local_ack_timeout(lap_msg,
- min(31, alternate_path->packet_life_time + 1));
+ cm_ack_timeout(cm_id_priv->av.port->cm_dev->ack_delay,
+ alternate_path->packet_life_time));
if (private_data && private_data_len)
memcpy(lap_msg->private_data, private_data, private_data_len);
@@ -2410,6 +2426,9 @@ int ib_send_cm_lap(struct ib_cm_id *cm_id,
ret = cm_init_av_by_path(alternate_path, &cm_id_priv->alt_av);
if (ret)
goto out;
+ cm_id_priv->alt_av.timeout =
+ cm_ack_timeout(cm_id_priv->target_ack_delay,
+ cm_id_priv->alt_av.timeout - 1);
ret = cm_alloc_msg(cm_id_priv, &msg);
if (ret)
@@ -2465,7 +2484,6 @@ static int cm_lap_handler(struct cm_work *work)
struct cm_lap_msg *lap_msg;
struct ib_cm_lap_event_param *param;
struct ib_mad_send_buf *msg = NULL;
- unsigned long flags;
int ret;
/* todo: verify LAP request and send reject APR if invalid. */
@@ -2480,7 +2498,7 @@ static int cm_lap_handler(struct cm_work *work)
cm_format_path_from_lap(cm_id_priv, param->alternate_path, lap_msg);
work->cm_event.private_data = &lap_msg->private_data;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state != IB_CM_ESTABLISHED)
goto unlock;
@@ -2497,7 +2515,7 @@ static int cm_lap_handler(struct cm_work *work)
cm_id_priv->service_timeout,
cm_id_priv->private_data,
cm_id_priv->private_data_len);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ib_post_send_mad(msg, NULL))
cm_free_msg(msg);
@@ -2515,7 +2533,7 @@ static int cm_lap_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -2523,7 +2541,7 @@ static int cm_lap_handler(struct cm_work *work)
cm_deref_id(cm_id_priv);
return 0;
-unlock: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+unlock: spin_unlock_irq(&cm_id_priv->lock);
deref: cm_deref_id(cm_id_priv);
return -EINVAL;
}
@@ -2598,7 +2616,6 @@ static int cm_apr_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
struct cm_apr_msg *apr_msg;
- unsigned long flags;
int ret;
apr_msg = (struct cm_apr_msg *)work->mad_recv_wc->recv_buf.mad;
@@ -2612,11 +2629,11 @@ static int cm_apr_handler(struct cm_work *work)
work->cm_event.param.apr_rcvd.info_len = apr_msg->info_length;
work->cm_event.private_data = &apr_msg->private_data;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state != IB_CM_ESTABLISHED ||
(cm_id_priv->id.lap_state != IB_CM_LAP_SENT &&
cm_id_priv->id.lap_state != IB_CM_MRA_LAP_RCVD)) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
goto out;
}
cm_id_priv->id.lap_state = IB_CM_LAP_IDLE;
@@ -2626,7 +2643,7 @@ static int cm_apr_handler(struct cm_work *work)
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -2761,7 +2778,6 @@ static int cm_sidr_req_handler(struct cm_work *work)
struct cm_id_private *cm_id_priv, *cur_cm_id_priv;
struct cm_sidr_req_msg *sidr_req_msg;
struct ib_wc *wc;
- unsigned long flags;
cm_id = ib_create_cm_id(work->port->cm_dev->device, NULL, NULL);
if (IS_ERR(cm_id))
@@ -2778,27 +2794,26 @@ static int cm_sidr_req_handler(struct cm_work *work)
work->mad_recv_wc->recv_buf.grh,
&cm_id_priv->av);
cm_id_priv->id.remote_id = sidr_req_msg->request_id;
- cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
cm_id_priv->tid = sidr_req_msg->hdr.tid;
atomic_inc(&cm_id_priv->work_count);
- spin_lock_irqsave(&cm.lock, flags);
+ spin_lock_irq(&cm.lock);
cur_cm_id_priv = cm_insert_remote_sidr(cm_id_priv);
if (cur_cm_id_priv) {
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
goto out; /* Duplicate message. */
}
+ cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD;
cur_cm_id_priv = cm_find_listen(cm_id->device,
sidr_req_msg->service_id,
sidr_req_msg->private_data);
if (!cur_cm_id_priv) {
- rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table);
- spin_unlock_irqrestore(&cm.lock, flags);
- /* todo: reply with no match */
+ spin_unlock_irq(&cm.lock);
+ cm_reject_sidr_req(cm_id_priv, IB_SIDR_UNSUPPORTED);
goto out; /* No match. */
}
atomic_inc(&cur_cm_id_priv->refcount);
- spin_unlock_irqrestore(&cm.lock, flags);
+ spin_unlock_irq(&cm.lock);
cm_id_priv->id.cm_handler = cur_cm_id_priv->id.cm_handler;
cm_id_priv->id.context = cur_cm_id_priv->id.context;
@@ -2899,7 +2914,6 @@ static int cm_sidr_rep_handler(struct cm_work *work)
{
struct cm_sidr_rep_msg *sidr_rep_msg;
struct cm_id_private *cm_id_priv;
- unsigned long flags;
sidr_rep_msg = (struct cm_sidr_rep_msg *)
work->mad_recv_wc->recv_buf.mad;
@@ -2907,14 +2921,14 @@ static int cm_sidr_rep_handler(struct cm_work *work)
if (!cm_id_priv)
return -EINVAL; /* Unmatched reply. */
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state != IB_CM_SIDR_REQ_SENT) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
goto out;
}
cm_id_priv->id.state = IB_CM_IDLE;
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
cm_format_sidr_rep_event(work);
cm_process_work(cm_id_priv, work);
@@ -2930,14 +2944,13 @@ static void cm_process_send_error(struct ib_mad_send_buf *msg,
struct cm_id_private *cm_id_priv;
struct ib_cm_event cm_event;
enum ib_cm_state state;
- unsigned long flags;
int ret;
memset(&cm_event, 0, sizeof cm_event);
cm_id_priv = msg->context[0];
/* Discard old sends or ones without a response. */
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
state = (enum ib_cm_state) (unsigned long) msg->context[1];
if (msg != cm_id_priv->msg || state != cm_id_priv->id.state)
goto discard;
@@ -2964,7 +2977,7 @@ static void cm_process_send_error(struct ib_mad_send_buf *msg,
default:
goto discard;
}
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
cm_event.param.send_status = wc_status;
/* No other events can occur on the cm_id at this point. */
@@ -2974,7 +2987,7 @@ static void cm_process_send_error(struct ib_mad_send_buf *msg,
ib_destroy_cm_id(&cm_id_priv->id);
return;
discard:
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
cm_free_msg(msg);
}
@@ -3269,8 +3282,7 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv,
*qp_attr_mask |= IB_QP_ALT_PATH;
qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num;
qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index;
- qp_attr->alt_timeout =
- cm_id_priv->alt_av.packet_life_time + 1;
+ qp_attr->alt_timeout = cm_id_priv->alt_av.timeout;
qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr;
}
ret = 0;
@@ -3308,8 +3320,7 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv,
*qp_attr_mask |= IB_QP_TIMEOUT | IB_QP_RETRY_CNT |
IB_QP_RNR_RETRY |
IB_QP_MAX_QP_RD_ATOMIC;
- qp_attr->timeout =
- cm_id_priv->av.packet_life_time + 1;
+ qp_attr->timeout = cm_id_priv->av.timeout;
qp_attr->retry_cnt = cm_id_priv->retry_count;
qp_attr->rnr_retry = cm_id_priv->rnr_retry_count;
qp_attr->max_rd_atomic =
@@ -3323,8 +3334,7 @@ static int cm_init_qp_rts_attr(struct cm_id_private *cm_id_priv,
*qp_attr_mask = IB_QP_ALT_PATH | IB_QP_PATH_MIG_STATE;
qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num;
qp_attr->alt_pkey_index = cm_id_priv->alt_av.pkey_index;
- qp_attr->alt_timeout =
- cm_id_priv->alt_av.packet_life_time + 1;
+ qp_attr->alt_timeout = cm_id_priv->alt_av.timeout;
qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr;
qp_attr->path_mig_state = IB_MIG_REARM;
}
@@ -3364,6 +3374,16 @@ int ib_cm_init_qp_attr(struct ib_cm_id *cm_id,
}
EXPORT_SYMBOL(ib_cm_init_qp_attr);
+static void cm_get_ack_delay(struct cm_device *cm_dev)
+{
+ struct ib_device_attr attr;
+
+ if (ib_query_device(cm_dev->device, &attr))
+ cm_dev->ack_delay = 0; /* acks will rely on packet life time */
+ else
+ cm_dev->ack_delay = attr.local_ca_ack_delay;
+}
+
static void cm_add_one(struct ib_device *device)
{
struct cm_device *cm_dev;
@@ -3388,6 +3408,7 @@ static void cm_add_one(struct ib_device *device)
return;
cm_dev->device = device;
+ cm_get_ack_delay(cm_dev);
set_bit(IB_MGMT_METHOD_SEND, reg_req.method_mask);
for (i = 1; i <= device->phys_port_cnt; i++) {
diff --git a/drivers/infiniband/core/cm_msgs.h b/drivers/infiniband/core/cm_msgs.h
index 4d3aee90c249..aec9c7af825d 100644
--- a/drivers/infiniband/core/cm_msgs.h
+++ b/drivers/infiniband/core/cm_msgs.h
@@ -35,6 +35,7 @@
#define CM_MSGS_H
#include <rdma/ib_mad.h>
+#include <rdma/ib_cm.h>
/*
* Parameters to routines below should be in network-byte order, and values
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 32a0e66d2a23..9ffb9987450a 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -573,7 +573,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
break;
case RDMA_TRANSPORT_IWARP:
if (!id_priv->cm_id.iw) {
- qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+ qp_attr->qp_access_flags = 0;
*qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
} else
ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
@@ -2326,7 +2326,6 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
rep.private_data_len = conn_param->private_data_len;
rep.responder_resources = conn_param->responder_resources;
rep.initiator_depth = conn_param->initiator_depth;
- rep.target_ack_delay = CMA_CM_RESPONSE_TIMEOUT;
rep.failover_accepted = 0;
rep.flow_control = conn_param->flow_control;
rep.rnr_retry_count = conn_param->rnr_retry_count;
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 85ccf13b8041..bc547f1d34ba 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -675,10 +675,16 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
struct ib_mad_port_private *port_priv;
struct ib_mad_agent_private *recv_mad_agent = NULL;
struct ib_device *device = mad_agent_priv->agent.device;
- u8 port_num = mad_agent_priv->agent.port_num;
+ u8 port_num;
struct ib_wc mad_wc;
struct ib_send_wr *send_wr = &mad_send_wr->send_wr;
+ if (device->node_type == RDMA_NODE_IB_SWITCH &&
+ smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE)
+ port_num = send_wr->wr.ud.port_num;
+ else
+ port_num = mad_agent_priv->agent.port_num;
+
/*
* Directed route handling starts if the initial LID routed part of
* a request or the ending LID routed part of a response is empty.
@@ -1839,6 +1845,7 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
struct ib_mad_private *recv, *response;
struct ib_mad_list_head *mad_list;
struct ib_mad_agent_private *mad_agent;
+ int port_num;
response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL);
if (!response)
@@ -1872,25 +1879,50 @@ static void ib_mad_recv_done_handler(struct ib_mad_port_private *port_priv,
if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num))
goto out;
+ if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH)
+ port_num = wc->port_num;
+ else
+ port_num = port_priv->port_num;
+
if (recv->mad.mad.mad_hdr.mgmt_class ==
IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) {
+ enum smi_forward_action retsmi;
+
if (smi_handle_dr_smp_recv(&recv->mad.smp,
port_priv->device->node_type,
- port_priv->port_num,
+ port_num,
port_priv->device->phys_port_cnt) ==
IB_SMI_DISCARD)
goto out;
- if (smi_check_forward_dr_smp(&recv->mad.smp) == IB_SMI_LOCAL)
+ retsmi = smi_check_forward_dr_smp(&recv->mad.smp);
+ if (retsmi == IB_SMI_LOCAL)
goto local;
- if (smi_handle_dr_smp_send(&recv->mad.smp,
- port_priv->device->node_type,
- port_priv->port_num) == IB_SMI_DISCARD)
- goto out;
+ if (retsmi == IB_SMI_SEND) { /* don't forward */
+ if (smi_handle_dr_smp_send(&recv->mad.smp,
+ port_priv->device->node_type,
+ port_num) == IB_SMI_DISCARD)
+ goto out;
+
+ if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD)
+ goto out;
+ } else if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH) {
+ /* forward case for switches */
+ memcpy(response, recv, sizeof(*response));
+ response->header.recv_wc.wc = &response->header.wc;
+ response->header.recv_wc.recv_buf.mad = &response->mad.mad;
+ response->header.recv_wc.recv_buf.grh = &response->grh;
+
+ if (!agent_send_response(&response->mad.mad,
+ &response->grh, wc,
+ port_priv->device,
+ smi_get_fwd_port(&recv->mad.smp),
+ qp_info->qp->qp_num))
+ response = NULL;
- if (smi_check_local_smp(&recv->mad.smp, port_priv->device) == IB_SMI_DISCARD)
goto out;
+ }
}
local:
@@ -1919,7 +1951,7 @@ local:
agent_send_response(&response->mad.mad,
&recv->grh, wc,
port_priv->device,
- port_priv->port_num,
+ port_num,
qp_info->qp->qp_num);
goto out;
}
@@ -2966,7 +2998,6 @@ static int __init ib_mad_init_module(void)
sizeof(struct ib_mad_private),
0,
SLAB_HWCACHE_ALIGN,
- NULL,
NULL);
if (!ib_mad_cache) {
printk(KERN_ERR PFX "Couldn't create ib_mad cache\n");
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 1e13ab42b70b..15b4c4d3606d 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2006 Intel Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/core/sa.h b/drivers/infiniband/core/sa.h
index 24c93fd320fb..b1d4bbf4ce5c 100644
--- a/drivers/infiniband/core/sa.h
+++ b/drivers/infiniband/core/sa.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Voltaire, Inc.  All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2006 Intel Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 6469406ea9d8..20ab6b3e484d 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Voltaire, Inc.  All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2006 Intel Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -56,6 +56,7 @@ MODULE_LICENSE("Dual BSD/GPL");
struct ib_sa_sm_ah {
struct ib_ah *ah;
struct kref ref;
+ u16 pkey_index;
u8 src_path_mask;
};
@@ -382,6 +383,13 @@ static void update_sm_ah(struct work_struct *work)
kref_init(&new_ah->ref);
new_ah->src_path_mask = (1 << port_attr.lmc) - 1;
+ new_ah->pkey_index = 0;
+ if (ib_find_pkey(port->agent->device, port->port_num,
+ IB_DEFAULT_PKEY_FULL, &new_ah->pkey_index) &&
+ ib_find_pkey(port->agent->device, port->port_num,
+ IB_DEFAULT_PKEY_PARTIAL, &new_ah->pkey_index))
+ printk(KERN_ERR "Couldn't find index for default PKey\n");
+
memset(&ah_attr, 0, sizeof ah_attr);
ah_attr.dlid = port_attr.sm_lid;
ah_attr.sl = port_attr.sm_sl;
@@ -512,6 +520,35 @@ int ib_init_ah_from_path(struct ib_device *device, u8 port_num,
}
EXPORT_SYMBOL(ib_init_ah_from_path);
+static int alloc_mad(struct ib_sa_query *query, gfp_t gfp_mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&query->port->ah_lock, flags);
+ kref_get(&query->port->sm_ah->ref);
+ query->sm_ah = query->port->sm_ah;
+ spin_unlock_irqrestore(&query->port->ah_lock, flags);
+
+ query->mad_buf = ib_create_send_mad(query->port->agent, 1,
+ query->sm_ah->pkey_index,
+ 0, IB_MGMT_SA_HDR, IB_MGMT_SA_DATA,
+ gfp_mask);
+ if (!query->mad_buf) {
+ kref_put(&query->sm_ah->ref, free_sm_ah);
+ return -ENOMEM;
+ }
+
+ query->mad_buf->ah = query->sm_ah->ah;
+
+ return 0;
+}
+
+static void free_mad(struct ib_sa_query *query)
+{
+ ib_free_send_mad(query->mad_buf);
+ kref_put(&query->sm_ah->ref, free_sm_ah);
+}
+
static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
{
unsigned long flags;
@@ -548,20 +585,11 @@ retry:
query->mad_buf->context[0] = query;
query->id = id;
- spin_lock_irqsave(&query->port->ah_lock, flags);
- kref_get(&query->port->sm_ah->ref);
- query->sm_ah = query->port->sm_ah;
- spin_unlock_irqrestore(&query->port->ah_lock, flags);
-
- query->mad_buf->ah = query->sm_ah->ah;
-
ret = ib_post_send_mad(query->mad_buf, NULL);
if (ret) {
spin_lock_irqsave(&idr_lock, flags);
idr_remove(&query_idr, id);
spin_unlock_irqrestore(&idr_lock, flags);
-
- kref_put(&query->sm_ah->ref, free_sm_ah);
}
/*
@@ -647,13 +675,10 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
if (!query)
return -ENOMEM;
- query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0,
- 0, IB_MGMT_SA_HDR,
- IB_MGMT_SA_DATA, gfp_mask);
- if (!query->sa_query.mad_buf) {
- ret = -ENOMEM;
+ query->sa_query.port = port;
+ ret = alloc_mad(&query->sa_query, gfp_mask);
+ if (ret)
goto err1;
- }
ib_sa_client_get(client);
query->sa_query.client = client;
@@ -665,7 +690,6 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
query->sa_query.callback = callback ? ib_sa_path_rec_callback : NULL;
query->sa_query.release = ib_sa_path_rec_release;
- query->sa_query.port = port;
mad->mad_hdr.method = IB_MGMT_METHOD_GET;
mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_PATH_REC);
mad->sa_hdr.comp_mask = comp_mask;
@@ -683,7 +707,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client,
err2:
*sa_query = NULL;
ib_sa_client_put(query->sa_query.client);
- ib_free_send_mad(query->sa_query.mad_buf);
+ free_mad(&query->sa_query);
err1:
kfree(query);
@@ -773,13 +797,10 @@ int ib_sa_service_rec_query(struct ib_sa_client *client,
if (!query)
return -ENOMEM;
- query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0,
- 0, IB_MGMT_SA_HDR,
- IB_MGMT_SA_DATA, gfp_mask);
- if (!query->sa_query.mad_buf) {
- ret = -ENOMEM;
+ query->sa_query.port = port;
+ ret = alloc_mad(&query->sa_query, gfp_mask);
+ if (ret)
goto err1;
- }
ib_sa_client_get(client);
query->sa_query.client = client;
@@ -791,7 +812,6 @@ int ib_sa_service_rec_query(struct ib_sa_client *client,
query->sa_query.callback = callback ? ib_sa_service_rec_callback : NULL;
query->sa_query.release = ib_sa_service_rec_release;
- query->sa_query.port = port;
mad->mad_hdr.method = method;
mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_SERVICE_REC);
mad->sa_hdr.comp_mask = comp_mask;
@@ -810,7 +830,7 @@ int ib_sa_service_rec_query(struct ib_sa_client *client,
err2:
*sa_query = NULL;
ib_sa_client_put(query->sa_query.client);
- ib_free_send_mad(query->sa_query.mad_buf);
+ free_mad(&query->sa_query);
err1:
kfree(query);
@@ -869,13 +889,10 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
if (!query)
return -ENOMEM;
- query->sa_query.mad_buf = ib_create_send_mad(agent, 1, 0,
- 0, IB_MGMT_SA_HDR,
- IB_MGMT_SA_DATA, gfp_mask);
- if (!query->sa_query.mad_buf) {
- ret = -ENOMEM;
+ query->sa_query.port = port;
+ ret = alloc_mad(&query->sa_query, gfp_mask);
+ if (ret)
goto err1;
- }
ib_sa_client_get(client);
query->sa_query.client = client;
@@ -887,7 +904,6 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
query->sa_query.callback = callback ? ib_sa_mcmember_rec_callback : NULL;
query->sa_query.release = ib_sa_mcmember_rec_release;
- query->sa_query.port = port;
mad->mad_hdr.method = method;
mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_MC_MEMBER_REC);
mad->sa_hdr.comp_mask = comp_mask;
@@ -906,7 +922,7 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
err2:
*sa_query = NULL;
ib_sa_client_put(query->sa_query.client);
- ib_free_send_mad(query->sa_query.mad_buf);
+ free_mad(&query->sa_query);
err1:
kfree(query);
@@ -939,8 +955,7 @@ static void send_handler(struct ib_mad_agent *agent,
idr_remove(&query_idr, query->id);
spin_unlock_irqrestore(&idr_lock, flags);
- ib_free_send_mad(mad_send_wc->send_buf);
- kref_put(&query->sm_ah->ref, free_sm_ah);
+ free_mad(query);
ib_sa_client_put(query->client);
query->release(query);
}
diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c
index 2bca753eb622..87236753bce9 100644
--- a/drivers/infiniband/core/smi.c
+++ b/drivers/infiniband/core/smi.c
@@ -192,7 +192,7 @@ enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
}
/* smp->hop_ptr updated when sending */
return (node_type == RDMA_NODE_IB_SWITCH ?
- IB_SMI_HANDLE: IB_SMI_DISCARD);
+ IB_SMI_HANDLE : IB_SMI_DISCARD);
}
/* C14-13:4 -- hop_ptr = 0 -> give to SM */
@@ -211,7 +211,7 @@ enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
if (!ib_get_smp_direction(smp)) {
/* C14-9:2 -- intermediate hop */
if (hop_ptr && hop_ptr < hop_cnt)
- return IB_SMI_SEND;
+ return IB_SMI_FORWARD;
/* C14-9:3 -- at the end of the DR segment of path */
if (hop_ptr == hop_cnt)
@@ -224,7 +224,7 @@ enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
} else {
/* C14-13:2 -- intermediate hop */
if (2 <= hop_ptr && hop_ptr <= hop_cnt)
- return IB_SMI_SEND;
+ return IB_SMI_FORWARD;
/* C14-13:3 -- at the end of the DR segment of path */
if (hop_ptr == 1)
@@ -233,3 +233,13 @@ enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp)
}
return IB_SMI_LOCAL;
}
+
+/*
+ * Return the forwarding port number from initial_path for outgoing SMP and
+ * from return_path for returning SMP
+ */
+int smi_get_fwd_port(struct ib_smp *smp)
+{
+ return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] :
+ smp->return_path[smp->hop_ptr-1]);
+}
diff --git a/drivers/infiniband/core/smi.h b/drivers/infiniband/core/smi.h
index 9a4b349efc30..1cfc2984434f 100644
--- a/drivers/infiniband/core/smi.h
+++ b/drivers/infiniband/core/smi.h
@@ -48,10 +48,12 @@ enum smi_action {
enum smi_forward_action {
IB_SMI_LOCAL, /* SMP should be completed up the stack */
IB_SMI_SEND, /* received DR SMP should be forwarded to the send queue */
+ IB_SMI_FORWARD /* SMP should be forwarded (for switches only) */
};
enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type,
int port_num, int phys_port_cnt);
+int smi_get_fwd_port(struct ib_smp *smp);
extern enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp);
extern enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp,
u8 node_type, int port_num);
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 08c299ebf4a8..70b77ae67422 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -311,7 +311,7 @@ static ssize_t show_pma_counter(struct ib_port *p, struct port_attribute *attr,
return sprintf(buf, "N/A (no PMA)\n");
in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL);
- out_mad = kmalloc(sizeof *in_mad, GFP_KERNEL);
+ out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL);
if (!in_mad || !out_mad) {
ret = -ENOMEM;
goto out;
@@ -479,7 +479,6 @@ alloc_group_attrs(ssize_t (*show)(struct ib_port *,
element->attr.attr.name = element->name;
element->attr.attr.mode = S_IRUGO;
- element->attr.attr.owner = THIS_MODULE;
element->attr.show = show;
element->index = i;
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index 2586a3ee8eba..424983f5b1ee 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -823,7 +823,6 @@ static ssize_t ib_ucm_send_rep(struct ib_ucm_file *file,
param.private_data_len = cmd.len;
param.responder_resources = cmd.responder_resources;
param.initiator_depth = cmd.initiator_depth;
- param.target_ack_delay = cmd.target_ack_delay;
param.failover_accepted = cmd.failover_accepted;
param.flow_control = cmd.flow_control;
param.rnr_retry_count = cmd.rnr_retry_count;
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index d40652a80151..26d0470eef6e 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -121,6 +121,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
cur_base = addr & PAGE_MASK;
+ ret = 0;
while (npages) {
ret = get_user_pages(current, current->mm, cur_base,
min_t(int, npages,
diff --git a/drivers/infiniband/hw/amso1100/Kconfig b/drivers/infiniband/hw/amso1100/Kconfig
index 809cb14ac6de..e6ce5f209e47 100644
--- a/drivers/infiniband/hw/amso1100/Kconfig
+++ b/drivers/infiniband/hw/amso1100/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_AMSO1100
tristate "Ammasso 1100 HCA support"
- depends on PCI && INET && INFINIBAND
+ depends on PCI && INET
---help---
This is a low-level driver for the Ammasso 1100 host
channel adapter (HCA).
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c
index 36620a22413c..cfdacb1ec279 100644
--- a/drivers/infiniband/hw/amso1100/c2_vq.c
+++ b/drivers/infiniband/hw/amso1100/c2_vq.c
@@ -85,7 +85,7 @@ int vq_init(struct c2_dev *c2dev)
(char) ('0' + c2dev->devnum));
c2dev->host_msg_cache =
kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (c2dev->host_msg_cache == NULL) {
return -ENOMEM;
}
diff --git a/drivers/infiniband/hw/cxgb3/Kconfig b/drivers/infiniband/hw/cxgb3/Kconfig
index 77977f55dca3..2acec3fadf69 100644
--- a/drivers/infiniband/hw/cxgb3/Kconfig
+++ b/drivers/infiniband/hw/cxgb3/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_CXGB3
tristate "Chelsio RDMA Driver"
- depends on CHELSIO_T3 && INFINIBAND && INET
+ depends on CHELSIO_T3 && INET
select GENERIC_ALLOCATOR
---help---
This is an iWARP/RDMA driver for the Chelsio T3 1GbE and
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 76049afc7655..1518b41482ae 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -144,7 +144,7 @@ static int cxio_hal_clear_qp_ctx(struct cxio_rdev *rdev_p, u32 qpid)
}
wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe));
memset(wqe, 0, sizeof(*wqe));
- build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 3, 1, qpid, 7);
+ build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 3, 0, qpid, 7);
wqe->flags = cpu_to_be32(MODQP_WRITE_EC);
sge_cmd = qpid << 8 | 3;
wqe->sge_cmd = cpu_to_be64(sge_cmd);
@@ -548,7 +548,7 @@ static int cxio_hal_init_ctrl_qp(struct cxio_rdev *rdev_p)
V_EC_UP_TOKEN(T3_CTL_QP_TID) | F_EC_VALID)) << 32;
wqe = (struct t3_modify_qp_wr *) skb_put(skb, sizeof(*wqe));
memset(wqe, 0, sizeof(*wqe));
- build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 0, 1,
+ build_fw_riwrh((struct fw_riwrh *) wqe, T3_WR_QP_MOD, 0, 0,
T3_CTL_QP_TID, 7);
wqe->flags = cpu_to_be32(MODQP_WRITE_EC);
sge_cmd = (3ULL << 56) | FW_RI_SGEEC_START << 8 | 3;
@@ -833,7 +833,7 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr)
wqe->ird = cpu_to_be32(attr->ird);
wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr);
wqe->qp_dma_size = cpu_to_be32(attr->qp_dma_size);
- wqe->rsvd = 0;
+ wqe->irs = cpu_to_be32(attr->irs);
skb->priority = 0; /* 0=>ToeQ; 1=>CtrlQ */
return (cxgb3_ofld_send(rdev_p->t3cdev_p, skb));
}
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index ff7290eacefb..c84d4ac49355 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -294,6 +294,7 @@ struct t3_rdma_init_attr {
u64 qp_dma_addr;
u32 qp_dma_size;
u32 flags;
+ u32 irs;
};
struct t3_rdma_init_wr {
@@ -314,7 +315,7 @@ struct t3_rdma_init_wr {
__be32 ird;
__be64 qp_dma_addr; /* 7 */
__be32 qp_dma_size; /* 8 */
- u32 rsvd;
+ u32 irs;
};
struct t3_genbit {
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index b2faff5abce8..9574088f0d4e 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -229,9 +229,8 @@ static void *alloc_ep(int size, gfp_t gfp)
{
struct iwch_ep_common *epc;
- epc = kmalloc(size, gfp);
+ epc = kzalloc(size, gfp);
if (epc) {
- memset(epc, 0, size);
kref_init(&epc->kref);
spin_lock_init(&epc->lock);
init_waitqueue_head(&epc->waitq);
@@ -254,8 +253,6 @@ static void release_ep_resources(struct iwch_ep *ep)
cxgb3_remove_tid(ep->com.tdev, (void *)ep, ep->hwtid);
dst_release(ep->dst);
l2t_release(L2DATA(ep->com.tdev), ep->l2t);
- if (ep->com.tdev->type == T3B)
- release_tid(ep->com.tdev, ep->hwtid, NULL);
put_ep(&ep->com);
}
@@ -515,7 +512,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb)
req->len = htonl(len);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
V_TX_SNDBUF(snd_win>>15));
- req->flags = htonl(F_TX_IMM_ACK|F_TX_INIT);
+ req->flags = htonl(F_TX_INIT);
req->sndseq = htonl(ep->snd_seq);
BUG_ON(ep->mpa_skb);
ep->mpa_skb = skb;
@@ -566,7 +563,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen)
req->len = htonl(mpalen);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
V_TX_SNDBUF(snd_win>>15));
- req->flags = htonl(F_TX_IMM_ACK|F_TX_INIT);
+ req->flags = htonl(F_TX_INIT);
req->sndseq = htonl(ep->snd_seq);
BUG_ON(ep->mpa_skb);
ep->mpa_skb = skb;
@@ -618,7 +615,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen)
req->len = htonl(len);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
V_TX_SNDBUF(snd_win>>15));
- req->flags = htonl(F_TX_MORE | F_TX_IMM_ACK | F_TX_INIT);
+ req->flags = htonl(F_TX_INIT);
req->sndseq = htonl(ep->snd_seq);
ep->mpa_skb = skb;
state_set(&ep->com, MPA_REP_SENT);
@@ -641,6 +638,7 @@ static int act_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
cxgb3_insert_tid(ep->com.tdev, &t3c_client, ep, tid);
ep->snd_seq = ntohl(req->snd_isn);
+ ep->rcv_seq = ntohl(req->rcv_isn);
set_emss(ep, ntohs(req->tcp_opt));
@@ -1023,6 +1021,9 @@ static int rx_data(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
skb_pull(skb, sizeof(*hdr));
skb_trim(skb, dlen);
+ ep->rcv_seq += dlen;
+ BUG_ON(ep->rcv_seq != (ntohl(hdr->seq) + dlen));
+
switch (state_read(&ep->com)) {
case MPA_REQ_SENT:
process_mpa_reply(ep, skb);
@@ -1060,7 +1061,6 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
struct iwch_ep *ep = ctx;
struct cpl_wr_ack *hdr = cplhdr(skb);
unsigned int credits = ntohs(hdr->credits);
- enum iwch_qp_attr_mask mask;
PDBG("%s ep %p credits %u\n", __FUNCTION__, ep, credits);
@@ -1072,30 +1072,6 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
ep->mpa_skb = NULL;
dst_confirm(ep->dst);
if (state_read(&ep->com) == MPA_REP_SENT) {
- struct iwch_qp_attributes attrs;
-
- /* bind QP to EP and move to RTS */
- attrs.mpa_attr = ep->mpa_attr;
- attrs.max_ird = ep->ord;
- attrs.max_ord = ep->ord;
- attrs.llp_stream_handle = ep;
- attrs.next_state = IWCH_QP_STATE_RTS;
-
- /* bind QP and TID with INIT_WR */
- mask = IWCH_QP_ATTR_NEXT_STATE |
- IWCH_QP_ATTR_LLP_STREAM_HANDLE |
- IWCH_QP_ATTR_MPA_ATTR |
- IWCH_QP_ATTR_MAX_IRD |
- IWCH_QP_ATTR_MAX_ORD;
-
- ep->com.rpl_err = iwch_modify_qp(ep->com.qp->rhp,
- ep->com.qp, mask, &attrs, 1);
-
- if (!ep->com.rpl_err) {
- state_set(&ep->com, FPDU_MODE);
- established_upcall(ep);
- }
-
ep->com.rpl_done = 1;
PDBG("waking up ep %p\n", ep);
wake_up(&ep->com.waitq);
@@ -1124,6 +1100,15 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
return CPL_RET_BUF_DONE;
}
+/*
+ * Return whether a failed active open has allocated a TID
+ */
+static inline int act_open_has_tid(int status)
+{
+ return status != CPL_ERR_TCAM_FULL && status != CPL_ERR_CONN_EXIST &&
+ status != CPL_ERR_ARP_MISS;
+}
+
static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
{
struct iwch_ep *ep = ctx;
@@ -1133,7 +1118,7 @@ static int act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
status2errno(rpl->status));
connect_reply_upcall(ep, status2errno(rpl->status));
state_set(&ep->com, DEAD);
- if (ep->com.tdev->type == T3B)
+ if (ep->com.tdev->type == T3B && act_open_has_tid(rpl->status))
release_tid(ep->com.tdev, GET_TID(rpl), NULL);
cxgb3_free_atid(ep->com.tdev, ep->atid);
dst_release(ep->dst);
@@ -1378,6 +1363,7 @@ static int pass_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
PDBG("%s ep %p\n", __FUNCTION__, ep);
ep->snd_seq = ntohl(req->snd_isn);
+ ep->rcv_seq = ntohl(req->rcv_isn);
set_emss(ep, ntohs(req->tcp_opt));
@@ -1485,6 +1471,13 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
int ret;
int state;
+ if (is_neg_adv_abort(req->status)) {
+ PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep,
+ ep->hwtid);
+ t3_l2t_send_event(ep->com.tdev, ep->l2t);
+ return CPL_RET_BUF_DONE;
+ }
+
/*
* We get 2 peer aborts from the HW. The first one must
* be ignored except for scribbling that we need one more.
@@ -1494,13 +1487,6 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
return CPL_RET_BUF_DONE;
}
- if (is_neg_adv_abort(req->status)) {
- PDBG("%s neg_adv_abort ep %p tid %d\n", __FUNCTION__, ep,
- ep->hwtid);
- t3_l2t_send_event(ep->com.tdev, ep->l2t);
- return CPL_RET_BUF_DONE;
- }
-
state = state_read(&ep->com);
PDBG("%s ep %p state %u\n", __FUNCTION__, ep, state);
switch (state) {
@@ -1732,10 +1718,8 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
struct iwch_qp *qp = get_qhp(h, conn_param->qpn);
PDBG("%s ep %p tid %u\n", __FUNCTION__, ep, ep->hwtid);
- if (state_read(&ep->com) == DEAD) {
- put_ep(&ep->com);
+ if (state_read(&ep->com) == DEAD)
return -ECONNRESET;
- }
BUG_ON(state_read(&ep->com) != MPA_REQ_RCVD);
BUG_ON(!qp);
@@ -1755,17 +1739,8 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
ep->ird = conn_param->ird;
ep->ord = conn_param->ord;
PDBG("%s %d ird %d ord %d\n", __FUNCTION__, __LINE__, ep->ird, ep->ord);
+
get_ep(&ep->com);
- err = send_mpa_reply(ep, conn_param->private_data,
- conn_param->private_data_len);
- if (err) {
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
- cm_id->rem_ref(cm_id);
- abort_connection(ep, NULL, GFP_KERNEL);
- put_ep(&ep->com);
- return err;
- }
/* bind QP to EP and move to RTS */
attrs.mpa_attr = ep->mpa_attr;
@@ -1783,16 +1758,28 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
err = iwch_modify_qp(ep->com.qp->rhp,
ep->com.qp, mask, &attrs, 1);
+ if (err)
+ goto err;
- if (err) {
- ep->com.cm_id = NULL;
- ep->com.qp = NULL;
- cm_id->rem_ref(cm_id);
- abort_connection(ep, NULL, GFP_KERNEL);
- } else {
- state_set(&ep->com, FPDU_MODE);
- established_upcall(ep);
- }
+ err = send_mpa_reply(ep, conn_param->private_data,
+ conn_param->private_data_len);
+ if (err)
+ goto err;
+
+ /* wait for wr_ack */
+ wait_event(ep->com.waitq, ep->com.rpl_done);
+ err = ep->com.rpl_err;
+ if (err)
+ goto err;
+
+ state_set(&ep->com, FPDU_MODE);
+ established_upcall(ep);
+ put_ep(&ep->com);
+ return 0;
+err:
+ ep->com.cm_id = NULL;
+ ep->com.qp = NULL;
+ cm_id->rem_ref(cm_id);
put_ep(&ep->com);
return err;
}
@@ -1926,6 +1913,7 @@ int iwch_create_listen(struct iw_cm_id *cm_id, int backlog)
fail3:
cxgb3_free_stid(ep->com.tdev, ep->stid);
fail2:
+ cm_id->rem_ref(cm_id);
put_ep(&ep->com);
fail1:
out:
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h
index 21a388c313cf..6107e7cd9b57 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h
@@ -175,6 +175,7 @@ struct iwch_ep {
unsigned int atid;
u32 hwtid;
u32 snd_seq;
+ u32 rcv_seq;
struct l2t_entry *l2t;
struct dst_entry *dst;
struct sk_buff *mpa_skb;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index e7c2c3948037..f0c777589374 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -1163,9 +1163,10 @@ int iwch_register_device(struct iwch_dev *dev)
dev->ibdev.post_recv = iwch_post_receive;
- dev->ibdev.iwcm =
- (struct iw_cm_verbs *) kmalloc(sizeof(struct iw_cm_verbs),
- GFP_KERNEL);
+ dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
+ if (!dev->ibdev.iwcm)
+ return -ENOMEM;
+
dev->ibdev.iwcm->connect = iwch_connect;
dev->ibdev.iwcm->accept = iwch_accept_cr;
dev->ibdev.iwcm->reject = iwch_reject_cr;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 714dddbc9a98..dd89b6b91f9c 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -628,9 +628,9 @@ int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg)
/* immediate data starts here. */
term = (struct terminate_message *)wqe->send.sgl;
build_term_codes(rsp_msg, &term->layer_etype, &term->ecode);
- build_fw_riwrh((void *)wqe, T3_WR_SEND,
- T3_COMPLETION_FLAG | T3_NOTIFY_FLAG, 1,
- qhp->ep->hwtid, 5);
+ wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_SEND) |
+ V_FW_RIWR_FLAGS(T3_COMPLETION_FLAG | T3_NOTIFY_FLAG));
+ wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid));
skb->priority = CPL_PRIORITY_DATA;
return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb);
}
@@ -732,6 +732,7 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
init_attr.qp_dma_addr = qhp->wq.dma_addr;
init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
+ init_attr.irs = qhp->ep->rcv_seq;
PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
"flags 0x%x qpcaps 0x%x\n", __FUNCTION__,
init_attr.rq_addr, init_attr.rq_size,
diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig
index 1a854598e0e6..59f807d8d58e 100644
--- a/drivers/infiniband/hw/ehca/Kconfig
+++ b/drivers/infiniband/hw/ehca/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_EHCA
tristate "eHCA support"
- depends on IBMEBUS && INFINIBAND
+ depends on IBMEBUS
---help---
This driver supports the IBM pSeries eHCA InfiniBand adapter.
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
index 0d6e2c4bb245..97d108634c58 100644
--- a/drivers/infiniband/hw/ehca/ehca_av.c
+++ b/drivers/infiniband/hw/ehca/ehca_av.c
@@ -79,7 +79,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
av->av.ipd = (ah_mult > 0) ?
((ehca_mult - 1) / ah_mult) : 0;
} else
- av->av.ipd = ehca_static_rate;
+ av->av.ipd = ehca_static_rate;
av->av.lnh = ah_attr->ah_flags;
av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
@@ -118,7 +118,7 @@ struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
}
memcpy(&av->av.grh.word_1, &gid, sizeof(gid));
}
- av->av.pmtu = EHCA_MAX_MTU;
+ av->av.pmtu = shca->max_mtu;
/* dgid comes in grh.word_3 */
memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid,
@@ -137,6 +137,8 @@ int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
struct ehca_av *av;
struct ehca_ud_av new_ehca_av;
struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
+ struct ehca_shca *shca = container_of(ah->pd->device, struct ehca_shca,
+ ib_device);
u32 cur_pid = current->tgid;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
@@ -192,7 +194,7 @@ int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid));
}
- new_ehca_av.pmtu = EHCA_MAX_MTU;
+ new_ehca_av.pmtu = shca->max_mtu;
memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid,
sizeof(ah_attr->grh.dgid));
@@ -257,7 +259,7 @@ int ehca_init_av_cache(void)
av_cache = kmem_cache_create("ehca_cache_av",
sizeof(struct ehca_av), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!av_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 1d286d3cc2d5..3725aa8664d9 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -5,6 +5,7 @@
*
* Authors: Heiko J Schick <schickhj@de.ibm.com>
* Christoph Raisch <raisch@de.ibm.com>
+ * Joachim Fenkes <fenkes@de.ibm.com>
*
* Copyright (c) 2005 IBM Corporation
*
@@ -42,7 +43,6 @@
#ifndef __EHCA_CLASSES_H__
#define __EHCA_CLASSES_H__
-
struct ehca_module;
struct ehca_qp;
struct ehca_cq;
@@ -86,13 +86,24 @@ struct ehca_eq {
struct ehca_eqe_cache_entry eqe_cache[EHCA_EQE_CACHE_SIZE];
};
+struct ehca_sma_attr {
+ u16 lid, lmc, sm_sl, sm_lid;
+ u16 pkey_tbl_len, pkeys[16];
+};
+
struct ehca_sport {
struct ib_cq *ibcq_aqp1;
struct ib_qp *ibqp_aqp1;
enum ib_rate rate;
enum ib_port_state port_state;
+ struct ehca_sma_attr saved_attr;
};
+#define HCA_CAP_MR_PGSIZE_4K 1
+#define HCA_CAP_MR_PGSIZE_64K 2
+#define HCA_CAP_MR_PGSIZE_1M 4
+#define HCA_CAP_MR_PGSIZE_16M 8
+
struct ehca_shca {
struct ib_device ib_device;
struct ibmebus_dev *ibmebus_dev;
@@ -107,17 +118,36 @@ struct ehca_shca {
struct ehca_pd *pd;
struct h_galpas galpas;
struct mutex modify_mutex;
+ u64 hca_cap;
+ /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */
+ u32 hca_cap_mr_pgsize;
+ int max_mtu;
};
struct ehca_pd {
struct ib_pd ib_pd;
struct ipz_pd fw_pd;
u32 ownpid;
+ /* small queue mgmt */
+ struct mutex lock;
+ struct list_head free[2];
+ struct list_head full[2];
+};
+
+enum ehca_ext_qp_type {
+ EQPT_NORMAL = 0,
+ EQPT_LLQP = 1,
+ EQPT_SRQBASE = 2,
+ EQPT_SRQ = 3,
};
struct ehca_qp {
- struct ib_qp ib_qp;
+ union {
+ struct ib_qp ib_qp;
+ struct ib_srq ib_srq;
+ };
u32 qp_type;
+ enum ehca_ext_qp_type ext_type;
struct ipz_queue ipz_squeue;
struct ipz_queue ipz_rqueue;
struct h_galpas galpas;
@@ -140,6 +170,10 @@ struct ehca_qp {
u32 mm_count_galpa;
};
+#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
+#define HAS_SQ(qp) (qp->ext_type != EQPT_SRQ)
+#define HAS_RQ(qp) (qp->ext_type != EQPT_SRQBASE)
+
/* must be power of 2 */
#define QP_HASHTAB_LEN 8
@@ -156,8 +190,8 @@ struct ehca_cq {
spinlock_t cb_lock;
struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
struct list_head entry;
- u32 nr_callbacks; /* #events assigned to cpu by scaling code */
- u32 nr_events; /* #events seen */
+ u32 nr_callbacks; /* #events assigned to cpu by scaling code */
+ atomic_t nr_events; /* #events seen */
wait_queue_head_t wait_completion;
spinlock_t task_lock;
u32 ownpid;
@@ -180,11 +214,12 @@ struct ehca_mr {
spinlock_t mrlock;
enum ehca_mr_flag flags;
- u32 num_pages; /* number of MR pages */
- u32 num_4k; /* number of 4k "page" portions to form MR */
+ u32 num_kpages; /* number of kernel pages */
+ u32 num_hwpages; /* number of hw pages to form MR */
+ u64 hwpage_size; /* hw page size used for this MR */
int acl; /* ACL (stored here for usage in reregister) */
u64 *start; /* virtual start address (stored here for */
- /* usage in reregister) */
+ /* usage in reregister) */
u64 size; /* size (stored here for usage in reregister) */
u32 fmr_page_size; /* page size for FMR */
u32 fmr_max_pages; /* max pages for FMR */
@@ -193,9 +228,6 @@ struct ehca_mr {
/* fw specific data */
struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */
struct h_galpas galpas;
- /* data for userspace bridge */
- u32 nr_of_pages;
- void *pagearray;
};
struct ehca_mw {
@@ -217,26 +249,30 @@ enum ehca_mr_pgi_type {
struct ehca_mr_pginfo {
enum ehca_mr_pgi_type type;
- u64 num_pages;
- u64 page_cnt;
- u64 num_4k; /* number of 4k "page" portions */
- u64 page_4k_cnt; /* counter for 4k "page" portions */
- u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */
-
- /* type EHCA_MR_PGI_PHYS section */
- int num_phys_buf;
- struct ib_phys_buf *phys_buf_array;
- u64 next_buf;
-
- /* type EHCA_MR_PGI_USER section */
- struct ib_umem *region;
- struct ib_umem_chunk *next_chunk;
- u64 next_nmap;
-
- /* type EHCA_MR_PGI_FMR section */
- u64 *page_list;
- u64 next_listelem;
- /* next_4k also used within EHCA_MR_PGI_FMR */
+ u64 num_kpages;
+ u64 kpage_cnt;
+ u64 hwpage_size; /* hw page size used for this MR */
+ u64 num_hwpages; /* number of hw pages */
+ u64 hwpage_cnt; /* counter for hw pages */
+ u64 next_hwpage; /* next hw page in buffer/chunk/listelem */
+
+ union {
+ struct { /* type EHCA_MR_PGI_PHYS section */
+ int num_phys_buf;
+ struct ib_phys_buf *phys_buf_array;
+ u64 next_buf;
+ } phy;
+ struct { /* type EHCA_MR_PGI_USER section */
+ struct ib_umem *region;
+ struct ib_umem_chunk *next_chunk;
+ u64 next_nmap;
+ } usr;
+ struct { /* type EHCA_MR_PGI_FMR section */
+ u64 fmr_pgsize;
+ u64 *page_list;
+ u64 next_listelem;
+ } fmr;
+ } u;
};
/* output parameters for MR/FMR hipz calls */
@@ -274,10 +310,11 @@ int ehca_init_av_cache(void);
void ehca_cleanup_av_cache(void);
int ehca_init_mrmw_cache(void);
void ehca_cleanup_mrmw_cache(void);
+int ehca_init_small_qp_cache(void);
+void ehca_cleanup_small_qp_cache(void);
-extern spinlock_t ehca_qp_idr_lock;
-extern spinlock_t ehca_cq_idr_lock;
-extern spinlock_t hcall_lock;
+extern rwlock_t ehca_qp_idr_lock;
+extern rwlock_t ehca_cq_idr_lock;
extern struct idr ehca_qp_idr;
extern struct idr ehca_cq_idr;
@@ -292,7 +329,7 @@ struct ipzu_queue_resp {
u32 queue_length; /* queue length allocated in bytes */
u32 pagesize;
u32 toggle_state;
- u32 dummy; /* padding for 8 byte alignment */
+ u32 offset; /* save offset within a page for small_qp */
};
struct ehca_create_cq_resp {
@@ -305,6 +342,7 @@ struct ehca_create_qp_resp {
u32 qp_num;
u32 token;
u32 qp_type;
+ u32 ext_type;
u32 qkey;
/* qp_num assigned by ehca: sqp0/1 may have got different numbers */
u32 real_qp_num;
@@ -320,28 +358,59 @@ struct ehca_alloc_cq_parms {
struct ipz_eq_handle eq_handle;
};
+enum ehca_service_type {
+ ST_RC = 0,
+ ST_UC = 1,
+ ST_RD = 2,
+ ST_UD = 3,
+};
+
+enum ehca_ll_comp_flags {
+ LLQP_SEND_COMP = 0x20,
+ LLQP_RECV_COMP = 0x40,
+ LLQP_COMP_MASK = 0x60,
+};
+
+struct ehca_alloc_queue_parms {
+ /* input parameters */
+ int max_wr;
+ int max_sge;
+ int page_size;
+ int is_small;
+
+ /* output parameters */
+ u16 act_nr_wqes;
+ u8 act_nr_sges;
+ u32 queue_size; /* bytes for small queues, pages otherwise */
+};
+
struct ehca_alloc_qp_parms {
- int servicetype;
+ struct ehca_alloc_queue_parms squeue;
+ struct ehca_alloc_queue_parms rqueue;
+
+ /* input parameters */
+ enum ehca_service_type servicetype;
+ int qp_storage;
int sigtype;
- int daqp_ctrl;
- int max_send_sge;
- int max_recv_sge;
+ enum ehca_ext_qp_type ext_type;
+ enum ehca_ll_comp_flags ll_comp_flags;
int ud_av_l_key_ctl;
- u16 act_nr_send_wqes;
- u16 act_nr_recv_wqes;
- u8 act_nr_recv_sges;
- u8 act_nr_send_sges;
+ u32 token;
+ struct ipz_eq_handle eq_handle;
+ struct ipz_pd pd;
+ struct ipz_cq_handle send_cq_handle, recv_cq_handle;
- u32 nr_rq_pages;
- u32 nr_sq_pages;
+ u32 srq_qpn, srq_token, srq_limit;
- struct ipz_eq_handle ipz_eq_handle;
- struct ipz_pd pd;
+ /* output parameters */
+ u32 real_qp_num;
+ struct ipz_qp_handle qp_handle;
+ struct h_galpas galpas;
};
int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
-struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
index 5665f213b81a..1798e6466bd0 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
@@ -154,83 +154,83 @@ struct hcp_modify_qp_control_block {
u32 reserved_70_127[58]; /* 70 */
};
-#define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0)
-#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2)
-#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3)
-#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4)
-#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5)
-#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6)
-#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7)
-#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8)
-#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9)
-#define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11)
-#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12)
-#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13)
-#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14)
-#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15)
-#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16)
-#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17)
-#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18)
-#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19)
-#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20)
-#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21)
-#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22)
-#define MQPCB_DLID EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23)
-#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24)
-#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25)
-#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26)
-#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27)
-#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28)
-#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30)
-#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31)
-#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31)
-#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32)
-#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33)
-#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34)
-#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31)
-#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35)
-#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36)
-#define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37)
-#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38)
-#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39)
-#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40)
-#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41)
-#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42)
-#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44)
-#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45)
-#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46)
-#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47)
-#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31)
-#define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31)
-#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48)
-#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_CURR_SQR_LIMIT EHCA_BMASK_IBM(49,49)
-#define MQPCB_CURR_SQR_LIMIT EHCA_BMASK_IBM(15,31)
-#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50)
-#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51)
+#define MQPCB_MASK_QKEY EHCA_BMASK_IBM( 0, 0)
+#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM( 2, 2)
+#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM( 3, 3)
+#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM( 4, 4)
+#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM( 5, 5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM( 6, 6)
+#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM( 7, 7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM( 8, 8)
+#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM( 9, 9)
+#define MQPCB_QP_STATE EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11, 11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12, 12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13, 13)
+#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14, 14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15, 15)
+#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16, 16)
+#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17, 17)
+#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18, 18)
+#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19, 19)
+#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20, 20)
+#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21, 21)
+#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22, 22)
+#define MQPCB_DLID EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23, 23)
+#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24, 24)
+#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25, 25)
+#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26, 26)
+#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27, 27)
+#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28, 28)
+#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30, 30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31, 31)
+#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28, 31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32, 32)
+#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33, 33)
+#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34, 34)
+#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35, 35)
+#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36, 36)
+#define MQPCB_DLID_AL EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37, 37)
+#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38, 38)
+#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39, 39)
+#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40, 40)
+#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41, 41)
+#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42, 42)
+#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44, 44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45, 45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46, 46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47, 47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31, 31)
+#define MQPCB_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48, 48)
+#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_CURR_SRQ_LIMIT EHCA_BMASK_IBM(49, 49)
+#define MQPCB_CURR_SRQ_LIMIT EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50, 50)
+#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51, 51)
#endif /* __EHCA_CLASSES_PSERIES_H__ */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 67f0670fe3b1..81aff36101ba 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -56,11 +56,11 @@ int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp)
{
unsigned int qp_num = qp->real_qp_num;
unsigned int key = qp_num & (QP_HASHTAB_LEN-1);
- unsigned long spl_flags;
+ unsigned long flags;
- spin_lock_irqsave(&cq->spinlock, spl_flags);
+ spin_lock_irqsave(&cq->spinlock, flags);
hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]);
- spin_unlock_irqrestore(&cq->spinlock, spl_flags);
+ spin_unlock_irqrestore(&cq->spinlock, flags);
ehca_dbg(cq->ib_cq.device, "cq_num=%x real_qp_num=%x",
cq->cq_number, qp_num);
@@ -74,9 +74,9 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
struct hlist_node *iter;
struct ehca_qp *qp;
- unsigned long spl_flags;
+ unsigned long flags;
- spin_lock_irqsave(&cq->spinlock, spl_flags);
+ spin_lock_irqsave(&cq->spinlock, flags);
hlist_for_each(iter, &cq->qp_hashtab[key]) {
qp = hlist_entry(iter, struct ehca_qp, list_entries);
if (qp->real_qp_num == real_qp_num) {
@@ -88,7 +88,7 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
break;
}
}
- spin_unlock_irqrestore(&cq->spinlock, spl_flags);
+ spin_unlock_irqrestore(&cq->spinlock, flags);
if (ret)
ehca_err(cq->ib_cq.device,
"qp not found cq_num=%x real_qp_num=%x",
@@ -97,7 +97,7 @@ int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
return ret;
}
-struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
{
struct ehca_qp *ret = NULL;
unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
@@ -146,6 +146,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
spin_lock_init(&my_cq->spinlock);
spin_lock_init(&my_cq->cb_lock);
spin_lock_init(&my_cq->task_lock);
+ atomic_set(&my_cq->nr_events, 0);
init_waitqueue_head(&my_cq->wait_completion);
my_cq->ownpid = current->tgid;
@@ -162,9 +163,9 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
goto create_cq_exit1;
}
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ write_lock_irqsave(&ehca_cq_idr_lock, flags);
ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
} while (ret == -EAGAIN);
@@ -189,8 +190,8 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
goto create_cq_exit2;
}
- ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages,
- EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
+ ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0);
if (!ipz_rc) {
ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
ipz_rc, device);
@@ -284,7 +285,7 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector,
return cq;
create_cq_exit4:
- ipz_queue_dtor(&my_cq->ipz_queue);
+ ipz_queue_dtor(NULL, &my_cq->ipz_queue);
create_cq_exit3:
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
@@ -293,9 +294,9 @@ create_cq_exit3:
"cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret);
create_cq_exit2:
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ write_lock_irqsave(&ehca_cq_idr_lock, flags);
idr_remove(&ehca_cq_idr, my_cq->token);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
create_cq_exit1:
kmem_cache_free(cq_cache, my_cq);
@@ -303,16 +304,6 @@ create_cq_exit1:
return cq;
}
-static int get_cq_nr_events(struct ehca_cq *my_cq)
-{
- int ret;
- unsigned long flags;
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- ret = my_cq->nr_events;
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
- return ret;
-}
-
int ehca_destroy_cq(struct ib_cq *cq)
{
u64 h_ret;
@@ -339,17 +330,18 @@ int ehca_destroy_cq(struct ib_cq *cq)
}
}
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- while (my_cq->nr_events) {
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
- wait_event(my_cq->wait_completion, !get_cq_nr_events(my_cq));
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- /* recheck nr_events to assure no cqe has just arrived */
- }
-
+ /*
+ * remove the CQ from the idr first to make sure
+ * no more interrupt tasklets will touch this CQ
+ */
+ write_lock_irqsave(&ehca_cq_idr_lock, flags);
idr_remove(&ehca_cq_idr, my_cq->token);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ /* now wait until all pending events have completed */
+ wait_event(my_cq->wait_completion, !atomic_read(&my_cq->nr_events));
+ /* nobody's using our CQ any longer -- we can destroy it */
h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
if (h_ret == H_R_STATE) {
/* cq in err: read err data and destroy it forcibly */
@@ -367,7 +359,7 @@ int ehca_destroy_cq(struct ib_cq *cq)
"ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
return ehca2ib_return_code(h_ret);
}
- ipz_queue_dtor(&my_cq->ipz_queue);
+ ipz_queue_dtor(NULL, &my_cq->ipz_queue);
kmem_cache_free(cq_cache, my_cq);
return 0;
@@ -395,7 +387,7 @@ int ehca_init_cq_cache(void)
cq_cache = kmem_cache_create("ehca_cache_cq",
sizeof(struct ehca_cq), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!cq_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 4961eb88827c..1d41faa7a337 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -86,8 +86,8 @@ int ehca_create_eq(struct ehca_shca *shca,
return -EINVAL;
}
- ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
- EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
+ ret = ipz_queue_ctor(NULL, &eq->ipz_queue, nr_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0, 0);
if (!ret) {
ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
goto create_eq_exit1;
@@ -96,7 +96,8 @@ int ehca_create_eq(struct ehca_shca *shca,
for (i = 0; i < nr_pages; i++) {
u64 rpage;
- if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+ vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+ if (!vpage) {
ret = H_RESOURCE;
goto create_eq_exit2;
}
@@ -144,7 +145,7 @@ int ehca_create_eq(struct ehca_shca *shca,
return 0;
create_eq_exit2:
- ipz_queue_dtor(&eq->ipz_queue);
+ ipz_queue_dtor(NULL, &eq->ipz_queue);
create_eq_exit1:
hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
@@ -180,7 +181,7 @@ int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
ehca_err(&shca->ib_device, "Can't free EQ resources.");
return -EINVAL;
}
- ipz_queue_dtor(&eq->ipz_queue);
+ ipz_queue_dtor(NULL, &eq->ipz_queue);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index 32b55a4f0e5b..fc19ef9fd963 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -45,11 +45,25 @@
int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
{
- int ret = 0;
+ int i, ret = 0;
struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
ib_device);
struct hipz_query_hca *rblock;
+ static const u32 cap_mapping[] = {
+ IB_DEVICE_RESIZE_MAX_WR, HCA_CAP_WQE_RESIZE,
+ IB_DEVICE_BAD_PKEY_CNTR, HCA_CAP_BAD_P_KEY_CTR,
+ IB_DEVICE_BAD_QKEY_CNTR, HCA_CAP_Q_KEY_VIOL_CTR,
+ IB_DEVICE_RAW_MULTI, HCA_CAP_RAW_PACKET_MCAST,
+ IB_DEVICE_AUTO_PATH_MIG, HCA_CAP_AUTO_PATH_MIG,
+ IB_DEVICE_CHANGE_PHY_PORT, HCA_CAP_SQD_RTS_PORT_CHANGE,
+ IB_DEVICE_UD_AV_PORT_ENFORCE, HCA_CAP_AH_PORT_NR_CHECK,
+ IB_DEVICE_CURR_QP_STATE_MOD, HCA_CAP_CUR_QP_STATE_MOD,
+ IB_DEVICE_SHUTDOWN_PORT, HCA_CAP_SHUTDOWN_PORT,
+ IB_DEVICE_INIT_TYPE, HCA_CAP_INIT_TYPE,
+ IB_DEVICE_PORT_ACTIVE_EVENT, HCA_CAP_PORT_ACTIVE_EVENT,
+ };
+
rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
@@ -96,6 +110,13 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
props->max_total_mcast_qp_attach
= min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
+ /* translate device capabilities */
+ props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID |
+ IB_DEVICE_RC_RNR_NAK_GEN | IB_DEVICE_N_NOTIFY_CQ;
+ for (i = 0; i < ARRAY_SIZE(cap_mapping); i += 2)
+ if (rblock->hca_cap_indicators & cap_mapping[i + 1])
+ props->device_cap_flags |= cap_mapping[i];
+
query_device1:
ehca_free_fw_ctrlblock(rblock);
@@ -106,6 +127,7 @@ int ehca_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props)
{
int ret = 0;
+ u64 h_ret;
struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
ib_device);
struct hipz_query_port *rblock;
@@ -116,7 +138,8 @@ int ehca_query_port(struct ib_device *ibdev,
return -ENOMEM;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_port1;
@@ -172,12 +195,50 @@ query_port1:
return ret;
}
+int ehca_query_sma_attr(struct ehca_shca *shca,
+ u8 port, struct ehca_sma_attr *attr)
+{
+ int ret = 0;
+ u64 h_ret;
+ struct hipz_query_port *rblock;
+
+ rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
+ if (!rblock) {
+ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+ return -ENOMEM;
+ }
+
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_sma_attr1;
+ }
+
+ memset(attr, 0, sizeof(struct ehca_sma_attr));
+
+ attr->lid = rblock->lid;
+ attr->lmc = rblock->lmc;
+ attr->sm_sl = rblock->sm_sl;
+ attr->sm_lid = rblock->sm_lid;
+
+ attr->pkey_tbl_len = rblock->pkey_tbl_len;
+ memcpy(attr->pkeys, rblock->pkey_entries, sizeof(attr->pkeys));
+
+query_sma_attr1:
+ ehca_free_fw_ctrlblock(rblock);
+
+ return ret;
+}
+
int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
{
int ret = 0;
- struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+ u64 h_ret;
+ struct ehca_shca *shca;
struct hipz_query_port *rblock;
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
if (index > 16) {
ehca_err(&shca->ib_device, "Invalid index: %x.", index);
return -EINVAL;
@@ -189,7 +250,8 @@ int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
return -ENOMEM;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_pkey1;
@@ -207,6 +269,7 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
int index, union ib_gid *gid)
{
int ret = 0;
+ u64 h_ret;
struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
ib_device);
struct hipz_query_port *rblock;
@@ -222,7 +285,8 @@ int ehca_query_gid(struct ib_device *ibdev, u8 port,
return -ENOMEM;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto query_gid1;
@@ -247,11 +311,12 @@ int ehca_modify_port(struct ib_device *ibdev,
struct ib_port_modify *props)
{
int ret = 0;
- struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+ struct ehca_shca *shca;
struct hipz_query_port *rblock;
u32 cap;
u64 hret;
+ shca = container_of(ibdev, struct ehca_shca, ib_device);
if ((props->set_port_cap_mask | props->clr_port_cap_mask)
& ~allowed_port_caps) {
ehca_err(&shca->ib_device, "Non-changeable bits set in masks "
@@ -261,7 +326,7 @@ int ehca_modify_port(struct ib_device *ibdev,
}
if (mutex_lock_interruptible(&shca->modify_mutex))
- return -ERESTARTSYS;
+ return -ERESTARTSYS;
rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
@@ -270,7 +335,8 @@ int ehca_modify_port(struct ib_device *ibdev,
goto modify_port1;
}
- if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+ if (hret != H_SUCCESS) {
ehca_err(&shca->ib_device, "Can't query port properties");
ret = -EINVAL;
goto modify_port2;
@@ -282,7 +348,8 @@ int ehca_modify_port(struct ib_device *ibdev,
hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
cap, props->init_type, port_modify_mask);
if (hret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "Modify port failed hret=%lx", hret);
+ ehca_err(&shca->ib_device, "Modify port failed hret=%lx",
+ hret);
ret = -EINVAL;
}
@@ -290,7 +357,7 @@ modify_port2:
ehca_free_fw_ctrlblock(rblock);
modify_port1:
- mutex_unlock(&shca->modify_mutex);
+ mutex_unlock(&shca->modify_mutex);
return ret;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 100329ba3343..71c0799b3500 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -5,6 +5,8 @@
*
* Authors: Heiko J Schick <schickhj@de.ibm.com>
* Khadija Souissi <souissi@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Joachim Fenkes <fenkes@de.ibm.com>
*
* Copyright (c) 2005 IBM Corporation
*
@@ -47,25 +49,26 @@
#include "hipz_fns.h"
#include "ipz_pt_fn.h"
-#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
-#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31)
-#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM(2,7)
-#define EQE_CQ_NUMBER EHCA_BMASK_IBM(8,31)
-#define EQE_QP_NUMBER EHCA_BMASK_IBM(8,31)
-#define EQE_QP_TOKEN EHCA_BMASK_IBM(32,63)
-#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32,63)
+#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1)
+#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM( 2, 7)
+#define EQE_CQ_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_NUMBER EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_TOKEN EHCA_BMASK_IBM(32, 63)
+#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32, 63)
-#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
-#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7)
-#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15)
-#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
+#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM( 1, 1)
+#define NEQE_EVENT_CODE EHCA_BMASK_IBM( 2, 7)
+#define NEQE_PORT_NUMBER EHCA_BMASK_IBM( 8, 15)
+#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
+#define NEQE_DISRUPTIVE EHCA_BMASK_IBM(16, 16)
-#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
-#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
+#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52, 63)
+#define ERROR_DATA_TYPE EHCA_BMASK_IBM( 0, 7)
static void queue_comp_task(struct ehca_cq *__cq);
-static struct ehca_comp_pool* pool;
+static struct ehca_comp_pool *pool;
#ifdef CONFIG_HOTPLUG_CPU
static struct notifier_block comp_pool_callback_nb;
#endif
@@ -82,8 +85,8 @@ static inline void comp_event_callback(struct ehca_cq *cq)
return;
}
-static void print_error_data(struct ehca_shca * shca, void* data,
- u64* rblock, int length)
+static void print_error_data(struct ehca_shca *shca, void *data,
+ u64 *rblock, int length)
{
u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
u64 resource = rblock[1];
@@ -91,7 +94,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
switch (type) {
case 0x1: /* Queue Pair */
{
- struct ehca_qp *qp = (struct ehca_qp*)data;
+ struct ehca_qp *qp = (struct ehca_qp *)data;
/* only print error data if AER is set */
if (rblock[6] == 0)
@@ -104,7 +107,7 @@ static void print_error_data(struct ehca_shca * shca, void* data,
}
case 0x4: /* Completion Queue */
{
- struct ehca_cq *cq = (struct ehca_cq*)data;
+ struct ehca_cq *cq = (struct ehca_cq *)data;
ehca_err(&shca->ib_device,
"CQ 0x%x (resource=%lx) has errors.",
@@ -172,33 +175,41 @@ error_data1:
}
-static void qp_event_callback(struct ehca_shca *shca,
- u64 eqe,
- enum ib_event_type event_type)
+static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
+ enum ib_event_type event_type, int fatal)
{
struct ib_event event;
struct ehca_qp *qp;
- unsigned long flags;
u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ read_lock(&ehca_qp_idr_lock);
qp = idr_find(&ehca_qp_idr, token);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ read_unlock(&ehca_qp_idr_lock);
if (!qp)
return;
- ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
+ if (fatal)
+ ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
- if (!qp->ib_qp.event_handler)
- return;
+ event.device = &shca->ib_device;
- event.device = &shca->ib_device;
- event.event = event_type;
- event.element.qp = &qp->ib_qp;
+ if (qp->ext_type == EQPT_SRQ) {
+ if (!qp->ib_srq.event_handler)
+ return;
- qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+ event.event = fatal ? IB_EVENT_SRQ_ERR : event_type;
+ event.element.srq = &qp->ib_srq;
+ qp->ib_srq.event_handler(&event, qp->ib_srq.srq_context);
+ } else {
+ if (!qp->ib_qp.event_handler)
+ return;
+
+ event.event = event_type;
+ event.element.qp = &qp->ib_qp;
+ qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+ }
return;
}
@@ -207,18 +218,22 @@ static void cq_event_callback(struct ehca_shca *shca,
u64 eqe)
{
struct ehca_cq *cq;
- unsigned long flags;
u32 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe);
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ read_lock(&ehca_cq_idr_lock);
cq = idr_find(&ehca_cq_idr, token);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ if (cq)
+ atomic_inc(&cq->nr_events);
+ read_unlock(&ehca_cq_idr_lock);
if (!cq)
return;
ehca_error_data(shca, cq, cq->ipz_cq_handle.handle);
+ if (atomic_dec_and_test(&cq->nr_events))
+ wake_up(&cq->wait_completion);
+
return;
}
@@ -228,17 +243,17 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
switch (identifier) {
case 0x02: /* path migrated */
- qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG);
+ qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG, 0);
break;
case 0x03: /* communication established */
- qp_event_callback(shca, eqe, IB_EVENT_COMM_EST);
+ qp_event_callback(shca, eqe, IB_EVENT_COMM_EST, 0);
break;
case 0x04: /* send queue drained */
- qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED);
+ qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED, 0);
break;
case 0x05: /* QP error */
case 0x06: /* QP error */
- qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL);
+ qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL, 1);
break;
case 0x07: /* CQ error */
case 0x08: /* CQ error */
@@ -272,6 +287,11 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
ehca_err(&shca->ib_device, "Interface trace stopped.");
break;
case 0x14: /* first error capture info available */
+ ehca_info(&shca->ib_device, "First error capture available");
+ break;
+ case 0x15: /* SRQ limit reached */
+ qp_event_callback(shca, eqe, IB_EVENT_SRQ_LIMIT_REACHED, 0);
+ break;
default:
ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.",
identifier, shca->ib_device.name);
@@ -281,30 +301,61 @@ static void parse_identifier(struct ehca_shca *shca, u64 eqe)
return;
}
-static void parse_ec(struct ehca_shca *shca, u64 eqe)
+static void dispatch_port_event(struct ehca_shca *shca, int port_num,
+ enum ib_event_type type, const char *msg)
{
struct ib_event event;
+
+ ehca_info(&shca->ib_device, "port %d %s.", port_num, msg);
+ event.device = &shca->ib_device;
+ event.event = type;
+ event.element.port_num = port_num;
+ ib_dispatch_event(&event);
+}
+
+static void notify_port_conf_change(struct ehca_shca *shca, int port_num)
+{
+ struct ehca_sma_attr new_attr;
+ struct ehca_sma_attr *old_attr = &shca->sport[port_num - 1].saved_attr;
+
+ ehca_query_sma_attr(shca, port_num, &new_attr);
+
+ if (new_attr.sm_sl != old_attr->sm_sl ||
+ new_attr.sm_lid != old_attr->sm_lid)
+ dispatch_port_event(shca, port_num, IB_EVENT_SM_CHANGE,
+ "SM changed");
+
+ if (new_attr.lid != old_attr->lid ||
+ new_attr.lmc != old_attr->lmc)
+ dispatch_port_event(shca, port_num, IB_EVENT_LID_CHANGE,
+ "LID changed");
+
+ if (new_attr.pkey_tbl_len != old_attr->pkey_tbl_len ||
+ memcmp(new_attr.pkeys, old_attr->pkeys,
+ sizeof(u16) * new_attr.pkey_tbl_len))
+ dispatch_port_event(shca, port_num, IB_EVENT_PKEY_CHANGE,
+ "P_Key changed");
+
+ *old_attr = new_attr;
+}
+
+static void parse_ec(struct ehca_shca *shca, u64 eqe)
+{
u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
switch (ec) {
case 0x30: /* port availability change */
if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
- ehca_info(&shca->ib_device,
- "port %x is active.", port);
- event.device = &shca->ib_device;
- event.event = IB_EVENT_PORT_ACTIVE;
- event.element.port_num = port;
shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
- ib_dispatch_event(&event);
+ dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
+ "is active");
+ ehca_query_sma_attr(shca, port,
+ &shca->sport[port - 1].saved_attr);
} else {
- ehca_info(&shca->ib_device,
- "port %x is inactive.", port);
- event.device = &shca->ib_device;
- event.event = IB_EVENT_PORT_ERR;
- event.element.port_num = port;
shca->sport[port - 1].port_state = IB_PORT_DOWN;
- ib_dispatch_event(&event);
+ dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
+ "is inactive");
}
break;
case 0x31:
@@ -312,24 +363,19 @@ static void parse_ec(struct ehca_shca *shca, u64 eqe)
* disruptive change is caused by
* LID, PKEY or SM change
*/
- ehca_warn(&shca->ib_device,
- "disruptive port %x configuration change", port);
-
- ehca_info(&shca->ib_device,
- "port %x is inactive.", port);
- event.device = &shca->ib_device;
- event.event = IB_EVENT_PORT_ERR;
- event.element.port_num = port;
- shca->sport[port - 1].port_state = IB_PORT_DOWN;
- ib_dispatch_event(&event);
-
- ehca_info(&shca->ib_device,
- "port %x is active.", port);
- event.device = &shca->ib_device;
- event.event = IB_EVENT_PORT_ACTIVE;
- event.element.port_num = port;
- shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
- ib_dispatch_event(&event);
+ if (EHCA_BMASK_GET(NEQE_DISRUPTIVE, eqe)) {
+ ehca_warn(&shca->ib_device, "disruptive port "
+ "%d configuration change", port);
+
+ shca->sport[port - 1].port_state = IB_PORT_DOWN;
+ dispatch_port_event(shca, port, IB_EVENT_PORT_ERR,
+ "is inactive");
+
+ shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+ dispatch_port_event(shca, port, IB_EVENT_PORT_ACTIVE,
+ "is active");
+ } else
+ notify_port_conf_change(shca, port);
break;
case 0x32: /* adapter malfunction */
ehca_err(&shca->ib_device, "Adapter malfunction.");
@@ -404,7 +450,6 @@ static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
{
u64 eqe_value;
u32 token;
- unsigned long flags;
struct ehca_cq *cq;
eqe_value = eqe->entry;
@@ -412,27 +457,24 @@ static inline void process_eqe(struct ehca_shca *shca, struct ehca_eqe *eqe)
if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
ehca_dbg(&shca->ib_device, "Got completion event");
token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ read_lock(&ehca_cq_idr_lock);
cq = idr_find(&ehca_cq_idr, token);
+ if (cq)
+ atomic_inc(&cq->nr_events);
+ read_unlock(&ehca_cq_idr_lock);
if (cq == NULL) {
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
ehca_err(&shca->ib_device,
"Invalid eqe for non-existing cq token=%x",
token);
return;
}
reset_eq_pending(cq);
- cq->nr_events++;
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
if (ehca_scaling_code)
queue_comp_task(cq);
else {
comp_event_callback(cq);
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- cq->nr_events--;
- if (!cq->nr_events)
+ if (atomic_dec_and_test(&cq->nr_events))
wake_up(&cq->wait_completion);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
}
} else {
ehca_dbg(&shca->ib_device, "Got non completion event");
@@ -476,17 +518,17 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
eqe_value = eqe_cache[eqe_cnt].eqe->entry;
if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT, eqe_value)) {
token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe_value);
- spin_lock(&ehca_cq_idr_lock);
+ read_lock(&ehca_cq_idr_lock);
eqe_cache[eqe_cnt].cq = idr_find(&ehca_cq_idr, token);
+ if (eqe_cache[eqe_cnt].cq)
+ atomic_inc(&eqe_cache[eqe_cnt].cq->nr_events);
+ read_unlock(&ehca_cq_idr_lock);
if (!eqe_cache[eqe_cnt].cq) {
- spin_unlock(&ehca_cq_idr_lock);
ehca_err(&shca->ib_device,
"Invalid eqe for non-existing cq "
"token=%x", token);
continue;
}
- eqe_cache[eqe_cnt].cq->nr_events++;
- spin_unlock(&ehca_cq_idr_lock);
} else
eqe_cache[eqe_cnt].cq = NULL;
eqe_cnt++;
@@ -517,11 +559,8 @@ void ehca_process_eq(struct ehca_shca *shca, int is_irq)
else {
struct ehca_cq *cq = eq->eqe_cache[i].cq;
comp_event_callback(cq);
- spin_lock(&ehca_cq_idr_lock);
- cq->nr_events--;
- if (!cq->nr_events)
+ if (atomic_dec_and_test(&cq->nr_events))
wake_up(&cq->wait_completion);
- spin_unlock(&ehca_cq_idr_lock);
}
} else {
ehca_dbg(&shca->ib_device, "Got non completion event");
@@ -547,7 +586,7 @@ void ehca_tasklet_eq(unsigned long data)
ehca_process_eq((struct ehca_shca*)data, 1);
}
-static inline int find_next_online_cpu(struct ehca_comp_pool* pool)
+static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
{
int cpu;
unsigned long flags;
@@ -611,7 +650,7 @@ static void queue_comp_task(struct ehca_cq *__cq)
__queue_comp_task(__cq, cct);
}
-static void run_comp_task(struct ehca_cpu_comp_task* cct)
+static void run_comp_task(struct ehca_cpu_comp_task *cct)
{
struct ehca_cq *cq;
unsigned long flags;
@@ -621,13 +660,10 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct)
while (!list_empty(&cct->cq_list)) {
cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
spin_unlock_irqrestore(&cct->task_lock, flags);
- comp_event_callback(cq);
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
- cq->nr_events--;
- if (!cq->nr_events)
+ comp_event_callback(cq);
+ if (atomic_dec_and_test(&cq->nr_events))
wake_up(&cq->wait_completion);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
spin_lock_irqsave(&cct->task_lock, flags);
spin_lock(&cq->task_lock);
@@ -644,12 +680,12 @@ static void run_comp_task(struct ehca_cpu_comp_task* cct)
static int comp_task(void *__cct)
{
- struct ehca_cpu_comp_task* cct = __cct;
+ struct ehca_cpu_comp_task *cct = __cct;
int cql_empty;
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_INTERRUPTIBLE);
- while(!kthread_should_stop()) {
+ while (!kthread_should_stop()) {
add_wait_queue(&cct->wait_queue, &wait);
spin_lock_irq(&cct->task_lock);
@@ -723,7 +759,7 @@ static void take_over_work(struct ehca_comp_pool *pool,
list_splice_init(&cct->cq_list, &list);
- while(!list_empty(&list)) {
+ while (!list_empty(&list)) {
cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
list_del(&cq->entry);
@@ -746,7 +782,7 @@ static int comp_pool_callback(struct notifier_block *nfb,
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
- if(!create_comp_task(pool, cpu)) {
+ if (!create_comp_task(pool, cpu)) {
ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
return NOTIFY_BAD;
}
@@ -816,7 +852,7 @@ int ehca_create_comp_pool(void)
#ifdef CONFIG_HOTPLUG_CPU
comp_pool_callback_nb.notifier_call = comp_pool_callback;
- comp_pool_callback_nb.priority =0;
+ comp_pool_callback_nb.priority = 0;
register_cpu_notifier(&comp_pool_callback_nb);
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h
index 6ed06ee033ed..3346cb06cea6 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.h
+++ b/drivers/infiniband/hw/ehca/ehca_irq.h
@@ -47,7 +47,6 @@ struct ehca_shca;
#include <linux/interrupt.h>
#include <linux/types.h>
-#include <asm/atomic.h>
int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource);
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index 37e7fe0908cf..dce503bb7d6b 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -49,6 +49,9 @@ int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props);
int ehca_query_port(struct ib_device *ibdev, u8 port,
struct ib_port_attr *props);
+int ehca_query_sma_attr(struct ehca_shca *shca, u8 port,
+ struct ehca_sma_attr *attr);
+
int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,
@@ -78,8 +81,9 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
int num_phys_buf,
int mr_access_flags, u64 *iova_start);
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
- int mr_access_flags, struct ib_udata *udata);
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt, int mr_access_flags,
+ struct ib_udata *udata);
int ehca_rereg_phys_mr(struct ib_mr *mr,
int mr_rereg_mask,
@@ -154,6 +158,21 @@ int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr,
int ehca_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
struct ib_recv_wr **bad_recv_wr);
+int ehca_post_srq_recv(struct ib_srq *srq,
+ struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr);
+
+struct ib_srq *ehca_create_srq(struct ib_pd *pd,
+ struct ib_srq_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int ehca_modify_srq(struct ib_srq *srq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+
+int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
+
+int ehca_destroy_srq(struct ib_srq *srq);
+
u64 ehca_define_sqp(struct ehca_shca *shca, struct ehca_qp *ibqp,
struct ib_qp_init_attr *qp_init_attr);
@@ -174,7 +193,7 @@ void ehca_poll_eqs(unsigned long data);
void *ehca_alloc_fw_ctrlblock(gfp_t flags);
void ehca_free_fw_ctrlblock(void *ptr);
#else
-#define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags))
+#define ehca_alloc_fw_ctrlblock(flags) ((void *)get_zeroed_page(flags))
#define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index c3f99f33b49c..99036b65bb84 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -63,6 +63,7 @@ int ehca_port_act_time = 30;
int ehca_poll_all_eqs = 1;
int ehca_static_rate = -1;
int ehca_scaling_code = 0;
+int ehca_mr_largepage = 0;
module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
module_param_named(debug_level, ehca_debug_level, int, 0);
@@ -72,7 +73,8 @@ module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
module_param_named(port_act_time, ehca_port_act_time, int, 0);
module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
module_param_named(static_rate, ehca_static_rate, int, 0);
-module_param_named(scaling_code, ehca_scaling_code, int, 0);
+module_param_named(scaling_code, ehca_scaling_code, int, 0);
+module_param_named(mr_largepage, ehca_mr_largepage, int, 0);
MODULE_PARM_DESC(open_aqp1,
"AQP1 on startup (0: no (default), 1: yes)");
@@ -94,22 +96,23 @@ MODULE_PARM_DESC(poll_all_eqs,
MODULE_PARM_DESC(static_rate,
"set permanent static rate (default: disabled)");
MODULE_PARM_DESC(scaling_code,
- "set scaling code (0: disabled, 1: enabled/default)");
+ "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");
-spinlock_t ehca_qp_idr_lock;
-spinlock_t ehca_cq_idr_lock;
-spinlock_t hcall_lock;
+DEFINE_RWLOCK(ehca_qp_idr_lock);
+DEFINE_RWLOCK(ehca_cq_idr_lock);
DEFINE_IDR(ehca_qp_idr);
DEFINE_IDR(ehca_cq_idr);
-
-static struct list_head shca_list; /* list of all registered ehcas */
-static spinlock_t shca_list_lock;
+static LIST_HEAD(shca_list); /* list of all registered ehcas */
+static DEFINE_SPINLOCK(shca_list_lock);
static struct timer_list poll_eqs_timer;
#ifdef CONFIG_PPC_64K_PAGES
-static struct kmem_cache *ctblk_cache = NULL;
+static struct kmem_cache *ctblk_cache;
void *ehca_alloc_fw_ctrlblock(gfp_t flags)
{
@@ -127,6 +130,23 @@ void ehca_free_fw_ctrlblock(void *ptr)
}
#endif
+int ehca2ib_return_code(u64 ehca_rc)
+{
+ switch (ehca_rc) {
+ case H_SUCCESS:
+ return 0;
+ case H_RESOURCE: /* Resource in use */
+ case H_BUSY:
+ return -EBUSY;
+ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+ case H_CONSTRAINED: /* resource constraint */
+ case H_NO_MEM:
+ return -ENOMEM;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ehca_create_slab_caches(void)
{
int ret;
@@ -161,19 +181,28 @@ static int ehca_create_slab_caches(void)
goto create_slab_caches5;
}
+ ret = ehca_init_small_qp_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create small queue SLAB cache.");
+ goto create_slab_caches6;
+ }
+
#ifdef CONFIG_PPC_64K_PAGES
ctblk_cache = kmem_cache_create("ehca_cache_ctblk",
EHCA_PAGESIZE, H_CB_ALIGNMENT,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!ctblk_cache) {
ehca_gen_err("Cannot create ctblk SLAB cache.");
- ehca_cleanup_mrmw_cache();
- goto create_slab_caches5;
+ ehca_cleanup_small_qp_cache();
+ goto create_slab_caches6;
}
#endif
return 0;
+create_slab_caches6:
+ ehca_cleanup_mrmw_cache();
+
create_slab_caches5:
ehca_cleanup_av_cache();
@@ -191,6 +220,7 @@ create_slab_caches2:
static void ehca_destroy_slab_caches(void)
{
+ ehca_cleanup_small_qp_cache();
ehca_cleanup_mrmw_cache();
ehca_cleanup_av_cache();
ehca_cleanup_qp_cache();
@@ -202,14 +232,38 @@ static void ehca_destroy_slab_caches(void)
#endif
}
-#define EHCA_HCAAVER EHCA_BMASK_IBM(32,39)
-#define EHCA_REVID EHCA_BMASK_IBM(40,63)
+#define EHCA_HCAAVER EHCA_BMASK_IBM(32, 39)
+#define EHCA_REVID EHCA_BMASK_IBM(40, 63)
+
+static struct cap_descr {
+ u64 mask;
+ char *descr;
+} hca_cap_descr[] = {
+ { HCA_CAP_AH_PORT_NR_CHECK, "HCA_CAP_AH_PORT_NR_CHECK" },
+ { HCA_CAP_ATOMIC, "HCA_CAP_ATOMIC" },
+ { HCA_CAP_AUTO_PATH_MIG, "HCA_CAP_AUTO_PATH_MIG" },
+ { HCA_CAP_BAD_P_KEY_CTR, "HCA_CAP_BAD_P_KEY_CTR" },
+ { HCA_CAP_SQD_RTS_PORT_CHANGE, "HCA_CAP_SQD_RTS_PORT_CHANGE" },
+ { HCA_CAP_CUR_QP_STATE_MOD, "HCA_CAP_CUR_QP_STATE_MOD" },
+ { HCA_CAP_INIT_TYPE, "HCA_CAP_INIT_TYPE" },
+ { HCA_CAP_PORT_ACTIVE_EVENT, "HCA_CAP_PORT_ACTIVE_EVENT" },
+ { HCA_CAP_Q_KEY_VIOL_CTR, "HCA_CAP_Q_KEY_VIOL_CTR" },
+ { HCA_CAP_WQE_RESIZE, "HCA_CAP_WQE_RESIZE" },
+ { HCA_CAP_RAW_PACKET_MCAST, "HCA_CAP_RAW_PACKET_MCAST" },
+ { HCA_CAP_SHUTDOWN_PORT, "HCA_CAP_SHUTDOWN_PORT" },
+ { HCA_CAP_RC_LL_QP, "HCA_CAP_RC_LL_QP" },
+ { HCA_CAP_SRQ, "HCA_CAP_SRQ" },
+ { HCA_CAP_UD_LL_QP, "HCA_CAP_UD_LL_QP" },
+ { HCA_CAP_RESIZE_MR, "HCA_CAP_RESIZE_MR" },
+ { HCA_CAP_MINI_QP, "HCA_CAP_MINI_QP" },
+};
int ehca_sense_attributes(struct ehca_shca *shca)
{
- int ret = 0;
+ int i, ret = 0;
u64 h_ret;
struct hipz_query_hca *rblock;
+ struct hipz_query_port *port;
rblock = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!rblock) {
@@ -222,7 +276,7 @@ int ehca_sense_attributes(struct ehca_shca *shca)
ehca_gen_err("Cannot query device properties. h_ret=%lx",
h_ret);
ret = -EPERM;
- goto num_ports1;
+ goto sense_attributes1;
}
if (ehca_nr_ports == 1)
@@ -241,19 +295,52 @@ int ehca_sense_attributes(struct ehca_shca *shca)
ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
- if ((hcaaver == 1) && (revid == 0))
- shca->hw_level = 0;
- else if ((hcaaver == 1) && (revid == 1))
- shca->hw_level = 1;
- else if ((hcaaver == 1) && (revid == 2))
- shca->hw_level = 2;
- }
+ if (hcaaver == 1) {
+ if (revid <= 3)
+ shca->hw_level = 0x10 | (revid + 1);
+ else
+ shca->hw_level = 0x14;
+ } else if (hcaaver == 2) {
+ if (revid == 0)
+ shca->hw_level = 0x21;
+ else if (revid == 0x10)
+ shca->hw_level = 0x22;
+ else if (revid == 0x20 || revid == 0x21)
+ shca->hw_level = 0x23;
+ }
+
+ if (!shca->hw_level) {
+ ehca_gen_warn("unknown hardware version"
+ " - assuming default level");
+ shca->hw_level = 0x22;
+ }
+ } else
+ shca->hw_level = ehca_hw_level;
ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
shca->sport[0].rate = IB_RATE_30_GBPS;
shca->sport[1].rate = IB_RATE_30_GBPS;
-num_ports1:
+ shca->hca_cap = rblock->hca_cap_indicators;
+ ehca_gen_dbg(" ... HCA capabilities:");
+ for (i = 0; i < ARRAY_SIZE(hca_cap_descr); i++)
+ if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
+ ehca_gen_dbg(" %s", hca_cap_descr[i].descr);
+
+ shca->hca_cap_mr_pgsize = rblock->memory_page_size_supported;
+
+ port = (struct hipz_query_port *)rblock;
+ h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
+ if (h_ret != H_SUCCESS) {
+ ehca_gen_err("Cannot query port properties. h_ret=%lx",
+ h_ret);
+ ret = -EPERM;
+ goto sense_attributes1;
+ }
+
+ shca->max_mtu = port->max_mtu;
+
+sense_attributes1:
ehca_free_fw_ctrlblock(rblock);
return ret;
}
@@ -293,7 +380,7 @@ int ehca_init_device(struct ehca_shca *shca)
strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
shca->ib_device.owner = THIS_MODULE;
- shca->ib_device.uverbs_abi_ver = 6;
+ shca->ib_device.uverbs_abi_ver = 7;
shca->ib_device.uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
@@ -361,6 +448,20 @@ int ehca_init_device(struct ehca_shca *shca)
/* shca->ib_device.process_mad = ehca_process_mad; */
shca->ib_device.mmap = ehca_mmap;
+ if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
+ shca->ib_device.uverbs_cmd_mask |=
+ (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
+
+ shca->ib_device.create_srq = ehca_create_srq;
+ shca->ib_device.modify_srq = ehca_modify_srq;
+ shca->ib_device.query_srq = ehca_query_srq;
+ shca->ib_device.destroy_srq = ehca_destroy_srq;
+ shca->ib_device.post_srq_recv = ehca_post_srq_recv;
+ }
+
return ret;
}
@@ -377,7 +478,7 @@ static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
return -EPERM;
}
- ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
+ ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1), 10, 0);
if (IS_ERR(ibcq)) {
ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
return PTR_ERR(ibcq);
@@ -523,6 +624,14 @@ 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,
@@ -539,6 +648,7 @@ 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
};
@@ -604,7 +714,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
}
/* create internal protection domain */
- ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+ ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL);
if (IS_ERR(ibpd)) {
ehca_err(&shca->ib_device, "Cannot create internal PD.");
ret = PTR_ERR(ibpd);
@@ -800,27 +910,22 @@ int __init ehca_module_init(void)
printk(KERN_INFO "eHCA Infiniband Device Driver "
"(Rel.: SVNEHCA_0023)\n");
- idr_init(&ehca_qp_idr);
- idr_init(&ehca_cq_idr);
- spin_lock_init(&ehca_qp_idr_lock);
- spin_lock_init(&ehca_cq_idr_lock);
- spin_lock_init(&hcall_lock);
- INIT_LIST_HEAD(&shca_list);
- spin_lock_init(&shca_list_lock);
-
- if ((ret = ehca_create_comp_pool())) {
+ ret = ehca_create_comp_pool();
+ if (ret) {
ehca_gen_err("Cannot create comp pool.");
return ret;
}
- if ((ret = ehca_create_slab_caches())) {
+ ret = ehca_create_slab_caches();
+ if (ret) {
ehca_gen_err("Cannot create SLAB caches");
ret = -ENOMEM;
goto module_init1;
}
- if ((ret = ibmebus_register_driver(&ehca_driver))) {
+ ret = ibmebus_register_driver(&ehca_driver);
+ if (ret) {
ehca_gen_err("Cannot register eHCA device driver");
ret = -EINVAL;
goto module_init2;
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index add79bd44e39..c1b868b79d67 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -5,6 +5,7 @@
*
* Authors: Dietmar Decker <ddecker@de.ibm.com>
* Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
*
* Copyright (c) 2005 IBM Corporation
*
@@ -48,17 +49,53 @@
#include "hcp_if.h"
#include "hipz_hw.h"
+#define NUM_CHUNKS(length, chunk_size) \
+ (((length) + (chunk_size - 1)) / (chunk_size))
+/* max number of rpages (per hcall register_rpages) */
+#define MAX_RPAGES 512
+
static struct kmem_cache *mr_cache;
static struct kmem_cache *mw_cache;
+enum ehca_mr_pgsize {
+ EHCA_MR_PGSIZE4K = 0x1000L,
+ EHCA_MR_PGSIZE64K = 0x10000L,
+ EHCA_MR_PGSIZE1M = 0x100000L,
+ EHCA_MR_PGSIZE16M = 0x1000000L
+};
+
+extern int ehca_mr_largepage;
+
+static u32 ehca_encode_hwpage_size(u32 pgsize)
+{
+ u32 idx = 0;
+ pgsize >>= 12;
+ /*
+ * map mr page size into hw code:
+ * 0, 1, 2, 3 for 4K, 64K, 1M, 64M
+ */
+ while (!(pgsize & 1)) {
+ idx++;
+ pgsize >>= 4;
+ }
+ return idx;
+}
+
+static u64 ehca_get_max_hwpage_size(struct ehca_shca *shca)
+{
+ if (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)
+ return EHCA_MR_PGSIZE16M;
+ return EHCA_MR_PGSIZE4K;
+}
+
static struct ehca_mr *ehca_mr_new(void)
{
struct ehca_mr *me;
me = kmem_cache_zalloc(mr_cache, GFP_KERNEL);
- if (me) {
+ if (me)
spin_lock_init(&me->mrlock);
- } else
+ else
ehca_gen_err("alloc failed");
return me;
@@ -74,9 +111,9 @@ static struct ehca_mw *ehca_mw_new(void)
struct ehca_mw *me;
me = kmem_cache_zalloc(mw_cache, GFP_KERNEL);
- if (me) {
+ if (me)
spin_lock_init(&me->mwlock);
- } else
+ else
ehca_gen_err("alloc failed");
return me;
@@ -106,11 +143,12 @@ struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
goto get_dma_mr_exit0;
}
- ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE,
+ ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE,
mr_access_flags, e_pd,
&e_maxmr->ib.ib_mr.lkey,
&e_maxmr->ib.ib_mr.rkey);
if (ret) {
+ ehca_mr_delete(e_maxmr);
ib_mr = ERR_PTR(ret);
goto get_dma_mr_exit0;
}
@@ -144,9 +182,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
u64 size;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
- u32 num_pages_mr;
- u32 num_pages_4k; /* 4k portion "pages" */
if ((num_phys_buf <= 0) || !phys_buf_array) {
ehca_err(pd->device, "bad input values: num_phys_buf=%x "
@@ -190,12 +225,6 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
goto reg_phys_mr_exit0;
}
- /* determine number of MR pages */
- num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size +
- PAGE_SIZE - 1) / PAGE_SIZE);
- num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
/* register MR on HCA */
if (ehca_mr_is_maxmr(size, iova_start)) {
e_mr->flags |= EHCA_MR_FLAG_MAXMR;
@@ -207,13 +236,26 @@ struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
goto reg_phys_mr_exit1;
}
} else {
- pginfo.type = EHCA_MR_PGI_PHYS;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.num_phys_buf = num_phys_buf;
- pginfo.phys_buf_array = phys_buf_array;
- pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
- EHCA_PAGESIZE);
+ struct ehca_mr_pginfo pginfo;
+ u32 num_kpages;
+ u32 num_hwpages;
+ u64 hw_pgsize;
+
+ num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size,
+ PAGE_SIZE);
+ /* for kernel space we try most possible pgsize */
+ hw_pgsize = ehca_get_max_hwpage_size(shca);
+ num_hwpages = NUM_CHUNKS(((u64)iova_start % hw_pgsize) + size,
+ hw_pgsize);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_kpages = num_kpages;
+ pginfo.hwpage_size = hw_pgsize;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.u.phy.num_phys_buf = num_phys_buf;
+ pginfo.u.phy.phys_buf_array = phys_buf_array;
+ pginfo.next_hwpage =
+ ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
@@ -240,18 +282,20 @@ reg_phys_mr_exit0:
/*----------------------------------------------------------------------*/
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
- int mr_access_flags, struct ib_udata *udata)
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+ u64 virt, int mr_access_flags,
+ struct ib_udata *udata)
{
struct ib_mr *ib_mr;
struct ehca_mr *e_mr;
struct ehca_shca *shca =
container_of(pd->device, struct ehca_shca, ib_device);
struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
int ret;
- u32 num_pages_mr;
- u32 num_pages_4k; /* 4k portion "pages" */
+ u32 num_kpages;
+ u32 num_hwpages;
+ u64 hwpage_size;
if (!pd) {
ehca_gen_err("bad pd=%p", pd);
@@ -289,7 +333,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
mr_access_flags);
if (IS_ERR(e_mr->umem)) {
- ib_mr = (void *) e_mr->umem;
+ ib_mr = (void *)e_mr->umem;
goto reg_user_mr_exit1;
}
@@ -301,23 +345,52 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt
}
/* determine number of MR pages */
- num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) /
- PAGE_SIZE);
- num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) /
- EHCA_PAGESIZE);
+ num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
+ /* select proper hw_pgsize */
+ if (ehca_mr_largepage &&
+ (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)) {
+ if (length <= EHCA_MR_PGSIZE4K
+ && PAGE_SIZE == EHCA_MR_PGSIZE4K)
+ hwpage_size = EHCA_MR_PGSIZE4K;
+ else if (length <= EHCA_MR_PGSIZE64K)
+ hwpage_size = EHCA_MR_PGSIZE64K;
+ else if (length <= EHCA_MR_PGSIZE1M)
+ hwpage_size = EHCA_MR_PGSIZE1M;
+ else
+ hwpage_size = EHCA_MR_PGSIZE16M;
+ } else
+ hwpage_size = EHCA_MR_PGSIZE4K;
+ ehca_dbg(pd->device, "hwpage_size=%lx", hwpage_size);
+reg_user_mr_fallback:
+ num_hwpages = NUM_CHUNKS((virt % hwpage_size) + length, hwpage_size);
/* register MR on HCA */
- pginfo.type = EHCA_MR_PGI_USER;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.region = e_mr->umem;
- pginfo.next_4k = e_mr->umem->offset / EHCA_PAGESIZE;
- pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
- (&e_mr->umem->chunk_list),
- list);
-
- ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd,
- &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_USER;
+ pginfo.hwpage_size = hwpage_size;
+ pginfo.num_kpages = num_kpages;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.u.usr.region = e_mr->umem;
+ pginfo.next_hwpage = e_mr->umem->offset / hwpage_size;
+ pginfo.u.usr.next_chunk = list_prepare_entry(pginfo.u.usr.next_chunk,
+ (&e_mr->umem->chunk_list),
+ list);
+
+ ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
+ e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) {
+ ehca_warn(pd->device, "failed to register mr "
+ "with hwpage_size=%lx", hwpage_size);
+ ehca_info(pd->device, "try to register mr with "
+ "kpage_size=%lx", PAGE_SIZE);
+ /*
+ * this means kpages are not contiguous for a hw page
+ * try kernel page size as fallback solution
+ */
+ hwpage_size = PAGE_SIZE;
+ goto reg_user_mr_fallback;
+ }
if (ret) {
ib_mr = ERR_PTR(ret);
goto reg_user_mr_exit2;
@@ -360,9 +433,9 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
struct ehca_pd *new_pd;
u32 tmp_lkey, tmp_rkey;
unsigned long sl_flags;
- u32 num_pages_mr = 0;
- u32 num_pages_4k = 0; /* 4k portion "pages" */
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ u32 num_kpages = 0;
+ u32 num_hwpages = 0;
+ struct ehca_mr_pginfo pginfo;
u32 cur_pid = current->tgid;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
@@ -414,7 +487,7 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
goto rereg_phys_mr_exit0;
}
if (!phys_buf_array || num_phys_buf <= 0) {
- ehca_err(mr->device, "bad input values: mr_rereg_mask=%x"
+ ehca_err(mr->device, "bad input values mr_rereg_mask=%x"
" phys_buf_array=%p num_phys_buf=%x",
mr_rereg_mask, phys_buf_array, num_phys_buf);
ret = -EINVAL;
@@ -438,12 +511,14 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
/* set requested values dependent on rereg request */
spin_lock_irqsave(&e_mr->mrlock, sl_flags);
- new_start = e_mr->start; /* new == old address */
- new_size = e_mr->size; /* new == old length */
- new_acl = e_mr->acl; /* new == old access control */
- new_pd = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
+ new_start = e_mr->start;
+ new_size = e_mr->size;
+ new_acl = e_mr->acl;
+ new_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
if (mr_rereg_mask & IB_MR_REREG_TRANS) {
+ u64 hw_pgsize = ehca_get_max_hwpage_size(shca);
+
new_start = iova_start; /* change address */
/* check physical buffer list and calculate size */
ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array,
@@ -458,17 +533,19 @@ int ehca_rereg_phys_mr(struct ib_mr *mr,
ret = -EINVAL;
goto rereg_phys_mr_exit1;
}
- num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size +
- PAGE_SIZE - 1) / PAGE_SIZE);
- num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
- pginfo.type = EHCA_MR_PGI_PHYS;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.num_phys_buf = num_phys_buf;
- pginfo.phys_buf_array = phys_buf_array;
- pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
- EHCA_PAGESIZE);
+ num_kpages = NUM_CHUNKS(((u64)new_start % PAGE_SIZE) +
+ new_size, PAGE_SIZE);
+ num_hwpages = NUM_CHUNKS(((u64)new_start % hw_pgsize) +
+ new_size, hw_pgsize);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_kpages = num_kpages;
+ pginfo.hwpage_size = hw_pgsize;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.u.phy.num_phys_buf = num_phys_buf;
+ pginfo.u.phy.phys_buf_array = phys_buf_array;
+ pginfo.next_hwpage =
+ ((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
}
if (mr_rereg_mask & IB_MR_REREG_ACCESS)
new_acl = mr_access_flags;
@@ -510,7 +587,7 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
u32 cur_pid = current->tgid;
unsigned long sl_flags;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
(my_pd->ownpid != cur_pid)) {
@@ -536,14 +613,14 @@ int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
"hca_hndl=%lx mr_hndl=%lx lkey=%x",
h_ret, mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
- ret = ehca_mrmw_map_hrc_query_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto query_mr_exit1;
}
- mr_attr->pd = mr->pd;
+ mr_attr->pd = mr->pd;
mr_attr->device_virt_addr = hipzout.vaddr;
- mr_attr->size = hipzout.len;
- mr_attr->lkey = hipzout.lkey;
- mr_attr->rkey = hipzout.rkey;
+ mr_attr->size = hipzout.len;
+ mr_attr->lkey = hipzout.lkey;
+ mr_attr->rkey = hipzout.rkey;
ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags);
query_mr_exit1:
@@ -596,7 +673,7 @@ int ehca_dereg_mr(struct ib_mr *mr)
"e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle, mr->lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto dereg_mr_exit0;
}
@@ -622,7 +699,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
struct ehca_shca *shca =
container_of(pd->device, struct ehca_shca, ib_device);
- struct ehca_mw_hipzout_parms hipzout = {{0},0};
+ struct ehca_mw_hipzout_parms hipzout;
e_mw = ehca_mw_new();
if (!e_mw) {
@@ -636,7 +713,7 @@ struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
"shca=%p hca_hndl=%lx mw=%p",
h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
- ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret));
+ ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
goto alloc_mw_exit1;
}
/* successful MW allocation */
@@ -679,7 +756,7 @@ int ehca_dealloc_mw(struct ib_mw *mw)
"mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
e_mw->ipz_mw_handle.handle);
- return ehca_mrmw_map_hrc_free_mw(h_ret);
+ return ehca2ib_return_code(h_ret);
}
/* successful deallocation */
ehca_mw_delete(e_mw);
@@ -699,7 +776,8 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
struct ehca_mr *e_fmr;
int ret;
u32 tmp_lkey, tmp_rkey;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
+ u64 hw_pgsize;
/* check other parameters */
if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
@@ -729,8 +807,8 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
ib_fmr = ERR_PTR(-EINVAL);
goto alloc_fmr_exit0;
}
- if (((1 << fmr_attr->page_shift) != EHCA_PAGESIZE) &&
- ((1 << fmr_attr->page_shift) != PAGE_SIZE)) {
+ hw_pgsize = ehca_get_max_hwpage_size(shca);
+ if ((1 << fmr_attr->page_shift) != hw_pgsize) {
ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
fmr_attr->page_shift);
ib_fmr = ERR_PTR(-EINVAL);
@@ -745,6 +823,11 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
e_fmr->flags |= EHCA_MR_FLAG_FMR;
/* register MR on HCA */
+ memset(&pginfo, 0, sizeof(pginfo));
+ /*
+ * pginfo.num_hwpages==0, ie register_rpages() will not be called
+ * but deferred to map_phys_fmr()
+ */
ret = ehca_reg_mr(shca, e_fmr, NULL,
fmr_attr->max_pages * (1 << fmr_attr->page_shift),
mr_access_flags, e_pd, &pginfo,
@@ -755,6 +838,7 @@ struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
}
/* successful */
+ e_fmr->hwpage_size = hw_pgsize;
e_fmr->fmr_page_size = 1 << fmr_attr->page_shift;
e_fmr->fmr_max_pages = fmr_attr->max_pages;
e_fmr->fmr_max_maps = fmr_attr->max_maps;
@@ -783,7 +867,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
container_of(fmr->device, struct ehca_shca, ib_device);
struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
u32 tmp_lkey, tmp_rkey;
if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
@@ -809,14 +893,18 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
}
- pginfo.type = EHCA_MR_PGI_FMR;
- pginfo.num_pages = list_len;
- pginfo.num_4k = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
- pginfo.page_list = page_list;
- pginfo.next_4k = ((iova & (e_fmr->fmr_page_size-1)) /
- EHCA_PAGESIZE);
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_FMR;
+ pginfo.num_kpages = list_len;
+ pginfo.hwpage_size = e_fmr->hwpage_size;
+ pginfo.num_hwpages =
+ list_len * e_fmr->fmr_page_size / pginfo.hwpage_size;
+ pginfo.u.fmr.page_list = page_list;
+ pginfo.next_hwpage =
+ (iova & (e_fmr->fmr_page_size-1)) / pginfo.hwpage_size;
+ pginfo.u.fmr.fmr_pgsize = e_fmr->fmr_page_size;
- ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova,
+ ret = ehca_rereg_mr(shca, e_fmr, (u64 *)iova,
list_len * e_fmr->fmr_page_size,
e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
if (ret)
@@ -831,8 +919,7 @@ int ehca_map_phys_fmr(struct ib_fmr *fmr,
map_phys_fmr_exit0:
if (ret)
ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
- "iova=%lx",
- ret, fmr, page_list, list_len, iova);
+ "iova=%lx", ret, fmr, page_list, list_len, iova);
return ret;
} /* end ehca_map_phys_fmr() */
@@ -922,7 +1009,7 @@ int ehca_dealloc_fmr(struct ib_fmr *fmr)
"hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
h_ret, e_fmr, shca->ipz_hca_handle.handle,
e_fmr->ipz_mr_handle.handle, fmr->lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto free_fmr_exit0;
}
/* successful deregistration */
@@ -950,12 +1037,12 @@ int ehca_reg_mr(struct ehca_shca *shca,
int ret;
u64 h_ret;
u32 hipz_acl;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
if (ehca_use_hp_mr == 1)
- hipz_acl |= 0x00000001;
+ hipz_acl |= 0x00000001;
h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
(u64)iova_start, size, hipz_acl,
@@ -963,7 +1050,7 @@ int ehca_reg_mr(struct ehca_shca *shca,
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
"hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
- ret = ehca_mrmw_map_hrc_alloc(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto ehca_reg_mr_exit0;
}
@@ -974,11 +1061,12 @@ int ehca_reg_mr(struct ehca_shca *shca,
goto ehca_reg_mr_exit1;
/* successful registration */
- e_mr->num_pages = pginfo->num_pages;
- e_mr->num_4k = pginfo->num_4k;
- e_mr->start = iova_start;
- e_mr->size = size;
- e_mr->acl = acl;
+ e_mr->num_kpages = pginfo->num_kpages;
+ e_mr->num_hwpages = pginfo->num_hwpages;
+ e_mr->hwpage_size = pginfo->hwpage_size;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
return 0;
@@ -988,10 +1076,10 @@ ehca_reg_mr_exit1:
if (h_ret != H_SUCCESS) {
ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
- "pginfo=%p num_pages=%lx num_4k=%lx ret=%x",
+ "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%x",
h_ret, shca, e_mr, iova_start, size, acl, e_pd,
- hipzout.lkey, pginfo, pginfo->num_pages,
- pginfo->num_4k, ret);
+ hipzout.lkey, pginfo, pginfo->num_kpages,
+ pginfo->num_hwpages, ret);
ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
"not recoverable");
}
@@ -999,9 +1087,9 @@ ehca_reg_mr_exit0:
if (ret)
ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
- "num_pages=%lx num_4k=%lx",
+ "num_kpages=%lx num_hwpages=%lx",
ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
- pginfo->num_pages, pginfo->num_4k);
+ pginfo->num_kpages, pginfo->num_hwpages);
return ret;
} /* end ehca_reg_mr() */
@@ -1018,6 +1106,9 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
u32 i;
u64 *kpage;
+ if (!pginfo->num_hwpages) /* in case of fmr */
+ return 0;
+
kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!kpage) {
ehca_err(&shca->ib_device, "kpage alloc failed");
@@ -1025,25 +1116,25 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
goto ehca_reg_mr_rpages_exit0;
}
- /* max 512 pages per shot */
- for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
+ /* max MAX_RPAGES ehca mr pages per register call */
+ for (i = 0; i < NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES); i++) {
- if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
- rnum = pginfo->num_4k % 512; /* last shot */
+ if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
+ rnum = pginfo->num_hwpages % MAX_RPAGES; /* last shot */
if (rnum == 0)
- rnum = 512; /* last shot is full */
+ rnum = MAX_RPAGES; /* last shot is full */
} else
- rnum = 512;
+ rnum = MAX_RPAGES;
+
+ ret = ehca_set_pagebuf(pginfo, rnum, kpage);
+ if (ret) {
+ ehca_err(&shca->ib_device, "ehca_set_pagebuf "
+ "bad rc, ret=%x rnum=%x kpage=%p",
+ ret, rnum, kpage);
+ goto ehca_reg_mr_rpages_exit1;
+ }
if (rnum > 1) {
- ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
- if (ret) {
- ehca_err(&shca->ib_device, "ehca_set_pagebuf "
- "bad rc, ret=%x rnum=%x kpage=%p",
- ret, rnum, kpage);
- ret = -EFAULT;
- goto ehca_reg_mr_rpages_exit1;
- }
rpage = virt_to_abs(kpage);
if (!rpage) {
ehca_err(&shca->ib_device, "kpage=%p i=%x",
@@ -1051,21 +1142,15 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
ret = -EFAULT;
goto ehca_reg_mr_rpages_exit1;
}
- } else { /* rnum==1 */
- ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
- if (ret) {
- ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 "
- "bad rc, ret=%x i=%x", ret, i);
- ret = -EFAULT;
- goto ehca_reg_mr_rpages_exit1;
- }
- }
+ } else
+ rpage = *kpage;
- h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr,
- 0, /* pagesize 4k */
- 0, rpage, rnum);
+ h_ret = hipz_h_register_rpage_mr(
+ shca->ipz_hca_handle, e_mr,
+ ehca_encode_hwpage_size(pginfo->hwpage_size),
+ 0, rpage, rnum);
- if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+ if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
/*
* check for 'registration complete'==H_SUCCESS
* and for 'page registered'==H_PAGE_REGISTERED
@@ -1078,7 +1163,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle,
e_mr->ib.ib_mr.lkey);
- ret = ehca_mrmw_map_hrc_rrpg_last(h_ret);
+ ret = ehca2ib_return_code(h_ret);
break;
} else
ret = 0;
@@ -1089,7 +1174,7 @@ int ehca_reg_mr_rpages(struct ehca_shca *shca,
e_mr->ib.ib_mr.lkey,
shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle);
- ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret);
+ ret = ehca2ib_return_code(h_ret);
break;
} else
ret = 0;
@@ -1101,8 +1186,8 @@ ehca_reg_mr_rpages_exit1:
ehca_reg_mr_rpages_exit0:
if (ret)
ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
- "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo,
- pginfo->num_pages, pginfo->num_4k);
+ "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr,
+ pginfo, pginfo->num_kpages, pginfo->num_hwpages);
return ret;
} /* end ehca_reg_mr_rpages() */
@@ -1124,10 +1209,10 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
u64 *kpage;
u64 rpage;
struct ehca_mr_pginfo pginfo_save;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!kpage) {
@@ -1137,12 +1222,12 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
}
pginfo_save = *pginfo;
- ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
+ ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage);
if (ret) {
ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
- "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p",
- e_mr, pginfo, pginfo->type, pginfo->num_pages,
- pginfo->num_4k,kpage);
+ "pginfo=%p type=%x num_kpages=%lx num_hwpages=%lx "
+ "kpage=%p", e_mr, pginfo, pginfo->type,
+ pginfo->num_kpages, pginfo->num_hwpages, kpage);
goto ehca_rereg_mr_rereg1_exit1;
}
rpage = virt_to_abs(kpage);
@@ -1164,7 +1249,7 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
"(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
*pginfo = pginfo_save;
ret = -EAGAIN;
- } else if ((u64*)hipzout.vaddr != iova_start) {
+ } else if ((u64 *)hipzout.vaddr != iova_start) {
ehca_err(&shca->ib_device, "PHYP changed iova_start in "
"rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
"mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
@@ -1176,11 +1261,12 @@ inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
* successful reregistration
* note: start and start_out are identical for eServer HCAs
*/
- e_mr->num_pages = pginfo->num_pages;
- e_mr->num_4k = pginfo->num_4k;
- e_mr->start = iova_start;
- e_mr->size = size;
- e_mr->acl = acl;
+ e_mr->num_kpages = pginfo->num_kpages;
+ e_mr->num_hwpages = pginfo->num_hwpages;
+ e_mr->hwpage_size = pginfo->hwpage_size;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
}
@@ -1190,9 +1276,9 @@ ehca_rereg_mr_rereg1_exit1:
ehca_rereg_mr_rereg1_exit0:
if ( ret && (ret != -EAGAIN) )
ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
- "pginfo=%p num_pages=%lx num_4k=%lx",
- ret, *lkey, *rkey, pginfo, pginfo->num_pages,
- pginfo->num_4k);
+ "pginfo=%p num_kpages=%lx num_hwpages=%lx",
+ ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
+ pginfo->num_hwpages);
return ret;
} /* end ehca_rereg_mr_rereg1() */
@@ -1214,10 +1300,12 @@ int ehca_rereg_mr(struct ehca_shca *shca,
int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
/* first determine reregistration hCall(s) */
- if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
- (pginfo->num_4k > e_mr->num_4k)) {
- ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx "
- "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
+ if ((pginfo->num_hwpages > MAX_RPAGES) ||
+ (e_mr->num_hwpages > MAX_RPAGES) ||
+ (pginfo->num_hwpages > e_mr->num_hwpages)) {
+ ehca_dbg(&shca->ib_device, "Rereg3 case, "
+ "pginfo->num_hwpages=%lx e_mr->num_hwpages=%x",
+ pginfo->num_hwpages, e_mr->num_hwpages);
rereg_1_hcall = 0;
rereg_3_hcall = 1;
}
@@ -1253,7 +1341,7 @@ int ehca_rereg_mr(struct ehca_shca *shca,
h_ret, e_mr, shca->ipz_hca_handle.handle,
e_mr->ipz_mr_handle.handle,
e_mr->ib.ib_mr.lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto ehca_rereg_mr_exit0;
}
/* clean ehca_mr_t, without changing struct ib_mr and lock */
@@ -1262,13 +1350,14 @@ int ehca_rereg_mr(struct ehca_shca *shca,
/* set some MR values */
e_mr->flags = save_mr.flags;
+ e_mr->hwpage_size = save_mr.hwpage_size;
e_mr->fmr_page_size = save_mr.fmr_page_size;
e_mr->fmr_max_pages = save_mr.fmr_max_pages;
e_mr->fmr_max_maps = save_mr.fmr_max_maps;
e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
- e_pd, pginfo, lkey, rkey);
+ e_pd, pginfo, lkey, rkey);
if (ret) {
u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
memcpy(&e_mr->flags, &(save_mr.flags),
@@ -1281,9 +1370,9 @@ ehca_rereg_mr_exit0:
if (ret)
ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
"iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
- "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
+ "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
"rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
- acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey,
+ acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey,
rereg_1_hcall, rereg_3_hcall);
return ret;
} /* end ehca_rereg_mr() */
@@ -1295,97 +1384,84 @@ int ehca_unmap_one_fmr(struct ehca_shca *shca,
{
int ret = 0;
u64 h_ret;
- int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */
- int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */
struct ehca_pd *e_pd =
container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
struct ehca_mr save_fmr;
u32 tmp_lkey, tmp_rkey;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
-
- /* first check if reregistration hCall can be used for unmap */
- if (e_fmr->fmr_max_pages > 512) {
- rereg_1_hcall = 0;
- rereg_3_hcall = 1;
- }
+ struct ehca_mr_pginfo pginfo;
+ struct ehca_mr_hipzout_parms hipzout;
+ struct ehca_mr save_mr;
- if (rereg_1_hcall) {
+ if (e_fmr->fmr_max_pages <= MAX_RPAGES) {
/*
* note: after using rereg hcall with len=0,
* rereg hcall must be used again for registering pages
*/
h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
0, 0, e_pd->fw_pd, 0, &hipzout);
- if (h_ret != H_SUCCESS) {
- /*
- * should not happen, because length checked above,
- * FMRs are not shared and no MW bound to FMRs
- */
- ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
- "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
- "mr_hndl=%lx lkey=%x lkey_out=%x",
- h_ret, e_fmr, shca->ipz_hca_handle.handle,
- e_fmr->ipz_mr_handle.handle,
- e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
- rereg_3_hcall = 1;
- } else {
+ if (h_ret == H_SUCCESS) {
/* successful reregistration */
e_fmr->start = NULL;
e_fmr->size = 0;
tmp_lkey = hipzout.lkey;
tmp_rkey = hipzout.rkey;
+ return 0;
}
+ /*
+ * should not happen, because length checked above,
+ * FMRs are not shared and no MW bound to FMRs
+ */
+ ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
+ "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
+ "mr_hndl=%lx lkey=%x lkey_out=%x",
+ h_ret, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
+ /* try free and rereg */
}
- if (rereg_3_hcall) {
- struct ehca_mr save_mr;
-
- /* first free old FMR */
- h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
- if (h_ret != H_SUCCESS) {
- ehca_err(&shca->ib_device, "hipz_free_mr failed, "
- "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
- "lkey=%x",
- h_ret, e_fmr, shca->ipz_hca_handle.handle,
- e_fmr->ipz_mr_handle.handle,
- e_fmr->ib.ib_fmr.lkey);
- ret = ehca_mrmw_map_hrc_free_mr(h_ret);
- goto ehca_unmap_one_fmr_exit0;
- }
- /* clean ehca_mr_t, without changing lock */
- save_fmr = *e_fmr;
- ehca_mr_deletenew(e_fmr);
-
- /* set some MR values */
- e_fmr->flags = save_fmr.flags;
- e_fmr->fmr_page_size = save_fmr.fmr_page_size;
- e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
- e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
- e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
- e_fmr->acl = save_fmr.acl;
-
- pginfo.type = EHCA_MR_PGI_FMR;
- pginfo.num_pages = 0;
- pginfo.num_4k = 0;
- ret = ehca_reg_mr(shca, e_fmr, NULL,
- (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
- e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
- &tmp_rkey);
- if (ret) {
- u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
- memcpy(&e_fmr->flags, &(save_mr.flags),
- sizeof(struct ehca_mr) - offset);
- goto ehca_unmap_one_fmr_exit0;
- }
+ /* first free old FMR */
+ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_free_mr failed, "
+ "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+ "lkey=%x",
+ h_ret, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey);
+ ret = ehca2ib_return_code(h_ret);
+ goto ehca_unmap_one_fmr_exit0;
+ }
+ /* clean ehca_mr_t, without changing lock */
+ save_fmr = *e_fmr;
+ ehca_mr_deletenew(e_fmr);
+
+ /* set some MR values */
+ e_fmr->flags = save_fmr.flags;
+ e_fmr->hwpage_size = save_fmr.hwpage_size;
+ e_fmr->fmr_page_size = save_fmr.fmr_page_size;
+ e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
+ e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
+ e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
+ e_fmr->acl = save_fmr.acl;
+
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_FMR;
+ ret = ehca_reg_mr(shca, e_fmr, NULL,
+ (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
+ e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
+ &tmp_rkey);
+ if (ret) {
+ u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
+ memcpy(&e_fmr->flags, &(save_mr.flags),
+ sizeof(struct ehca_mr) - offset);
}
ehca_unmap_one_fmr_exit0:
if (ret)
ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
- "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x",
- ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages,
- rereg_1_hcall, rereg_3_hcall);
+ "fmr_max_pages=%x",
+ ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages);
return ret;
} /* end ehca_unmap_one_fmr() */
@@ -1403,10 +1479,10 @@ int ehca_reg_smr(struct ehca_shca *shca,
int ret = 0;
u64 h_ret;
u32 hipz_acl;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
@@ -1419,15 +1495,16 @@ int ehca_reg_smr(struct ehca_shca *shca,
shca->ipz_hca_handle.handle,
e_origmr->ipz_mr_handle.handle,
e_origmr->ib.ib_mr.lkey);
- ret = ehca_mrmw_map_hrc_reg_smr(h_ret);
+ ret = ehca2ib_return_code(h_ret);
goto ehca_reg_smr_exit0;
}
/* successful registration */
- e_newmr->num_pages = e_origmr->num_pages;
- e_newmr->num_4k = e_origmr->num_4k;
- e_newmr->start = iova_start;
- e_newmr->size = e_origmr->size;
- e_newmr->acl = acl;
+ e_newmr->num_kpages = e_origmr->num_kpages;
+ e_newmr->num_hwpages = e_origmr->num_hwpages;
+ e_newmr->hwpage_size = e_origmr->hwpage_size;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
e_newmr->ipz_mr_handle = hipzout.handle;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
@@ -1453,10 +1530,11 @@ int ehca_reg_internal_maxmr(
struct ehca_mr *e_mr;
u64 *iova_start;
u64 size_maxmr;
- struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_pginfo pginfo;
struct ib_phys_buf ib_pbuf;
- u32 num_pages_mr;
- u32 num_pages_4k; /* 4k portion "pages" */
+ u32 num_kpages;
+ u32 num_hwpages;
+ u64 hw_pgsize;
e_mr = ehca_mr_new();
if (!e_mr) {
@@ -1468,28 +1546,31 @@ int ehca_reg_internal_maxmr(
/* register internal max-MR on HCA */
size_maxmr = (u64)high_memory - PAGE_OFFSET;
- iova_start = (u64*)KERNELBASE;
+ iova_start = (u64 *)KERNELBASE;
ib_pbuf.addr = 0;
ib_pbuf.size = size_maxmr;
- num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr +
- PAGE_SIZE - 1) / PAGE_SIZE);
- num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
- pginfo.type = EHCA_MR_PGI_PHYS;
- pginfo.num_pages = num_pages_mr;
- pginfo.num_4k = num_pages_4k;
- pginfo.num_phys_buf = 1;
- pginfo.phys_buf_array = &ib_pbuf;
+ num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
+ PAGE_SIZE);
+ hw_pgsize = ehca_get_max_hwpage_size(shca);
+ num_hwpages = NUM_CHUNKS(((u64)iova_start % hw_pgsize) + size_maxmr,
+ hw_pgsize);
+
+ memset(&pginfo, 0, sizeof(pginfo));
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_kpages = num_kpages;
+ pginfo.num_hwpages = num_hwpages;
+ pginfo.hwpage_size = hw_pgsize;
+ pginfo.u.phy.num_phys_buf = 1;
+ pginfo.u.phy.phys_buf_array = &ib_pbuf;
ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
&pginfo, &e_mr->ib.ib_mr.lkey,
&e_mr->ib.ib_mr.rkey);
if (ret) {
ehca_err(&shca->ib_device, "reg of internal max MR failed, "
- "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x "
- "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
- num_pages_mr, num_pages_4k);
+ "e_mr=%p iova_start=%p size_maxmr=%lx num_kpages=%x "
+ "num_hwpages=%x", e_mr, iova_start, size_maxmr,
+ num_kpages, num_hwpages);
goto ehca_reg_internal_maxmr_exit1;
}
@@ -1524,10 +1605,10 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
u64 h_ret;
struct ehca_mr *e_origmr = shca->maxmr;
u32 hipz_acl;
- struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+ struct ehca_mr_hipzout_parms hipzout;
ehca_mrmw_map_acl(acl, &hipz_acl);
- ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
(u64)iova_start, hipz_acl, e_pd->fw_pd,
@@ -1538,14 +1619,15 @@ int ehca_reg_maxmr(struct ehca_shca *shca,
h_ret, e_origmr, shca->ipz_hca_handle.handle,
e_origmr->ipz_mr_handle.handle,
e_origmr->ib.ib_mr.lkey);
- return ehca_mrmw_map_hrc_reg_smr(h_ret);
+ return ehca2ib_return_code(h_ret);
}
/* successful registration */
- e_newmr->num_pages = e_origmr->num_pages;
- e_newmr->num_4k = e_origmr->num_4k;
- e_newmr->start = iova_start;
- e_newmr->size = e_origmr->size;
- e_newmr->acl = acl;
+ e_newmr->num_kpages = e_origmr->num_kpages;
+ e_newmr->num_hwpages = e_origmr->num_hwpages;
+ e_newmr->hwpage_size = e_origmr->hwpage_size;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
e_newmr->ipz_mr_handle = hipzout.handle;
*lkey = hipzout.lkey;
*rkey = hipzout.rkey;
@@ -1677,299 +1759,352 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
/*----------------------------------------------------------------------*/
-/* setup page buffer from page info */
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
- u32 number,
- u64 *kpage)
+/* PAGE_SIZE >= pginfo->hwpage_size */
+static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
{
int ret = 0;
struct ib_umem_chunk *prev_chunk;
struct ib_umem_chunk *chunk;
- struct ib_phys_buf *pbuf;
- u64 *fmrlist;
- u64 num4k, pgaddr, offs4k;
+ u64 pgaddr;
u32 i = 0;
u32 j = 0;
-
- if (pginfo->type == EHCA_MR_PGI_PHYS) {
- /* loop over desired phys_buf_array entries */
- while (i < number) {
- pbuf = pginfo->phys_buf_array + pginfo->next_buf;
- num4k = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
- offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
- while (pginfo->next_4k < offs4k + num4k) {
- /* sanity check */
- if ((pginfo->page_cnt >= pginfo->num_pages) ||
- (pginfo->page_4k_cnt >= pginfo->num_4k)) {
- ehca_gen_err("page_cnt >= num_pages, "
- "page_cnt=%lx "
- "num_pages=%lx "
- "page_4k_cnt=%lx "
- "num_4k=%lx i=%x",
- pginfo->page_cnt,
- pginfo->num_pages,
- pginfo->page_4k_cnt,
- pginfo->num_4k, i);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
- }
- *kpage = phys_to_abs(
- (pbuf->addr & EHCA_PAGEMASK)
- + (pginfo->next_4k * EHCA_PAGESIZE));
- if ( !(*kpage) && pbuf->addr ) {
- ehca_gen_err("pbuf->addr=%lx "
- "pbuf->size=%lx "
- "next_4k=%lx", pbuf->addr,
- pbuf->size,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
- }
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k %
- (PAGE_SIZE / EHCA_PAGESIZE) == 0)
- (pginfo->page_cnt)++;
- kpage++;
- i++;
- if (i >= number) break;
+ int hwpages_per_kpage = PAGE_SIZE / pginfo->hwpage_size;
+
+ /* loop over desired chunk entries */
+ chunk = pginfo->u.usr.next_chunk;
+ prev_chunk = pginfo->u.usr.next_chunk;
+ list_for_each_entry_continue(
+ chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+ for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+ pgaddr = page_to_pfn(chunk->page_list[i].page)
+ << PAGE_SHIFT ;
+ *kpage = phys_to_abs(pgaddr +
+ (pginfo->next_hwpage *
+ pginfo->hwpage_size));
+ if ( !(*kpage) ) {
+ ehca_gen_err("pgaddr=%lx "
+ "chunk->page_list[i]=%lx "
+ "i=%x next_hwpage=%lx",
+ pgaddr, (u64)sg_dma_address(
+ &chunk->page_list[i]),
+ i, pginfo->next_hwpage);
+ return -EFAULT;
}
- if (pginfo->next_4k >= offs4k + num4k) {
- (pginfo->next_buf)++;
- pginfo->next_4k = 0;
+ (pginfo->hwpage_cnt)++;
+ (pginfo->next_hwpage)++;
+ kpage++;
+ if (pginfo->next_hwpage % hwpages_per_kpage == 0) {
+ (pginfo->kpage_cnt)++;
+ (pginfo->u.usr.next_nmap)++;
+ pginfo->next_hwpage = 0;
+ i++;
}
+ j++;
+ if (j >= number) break;
}
- } else if (pginfo->type == EHCA_MR_PGI_USER) {
- /* loop over desired chunk entries */
- chunk = pginfo->next_chunk;
- prev_chunk = pginfo->next_chunk;
- list_for_each_entry_continue(chunk,
- (&(pginfo->region->chunk_list)),
- list) {
- for (i = pginfo->next_nmap; i < chunk->nmap; ) {
+ if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+ (j >= number)) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ break;
+ } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ } else if (j >= number)
+ break;
+ else
+ prev_chunk = chunk;
+ }
+ pginfo->u.usr.next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->u.usr.region->chunk_list)),
+ list);
+ return ret;
+}
+
+/*
+ * check given pages for contiguous layout
+ * last page addr is returned in prev_pgaddr for further check
+ */
+static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
+ int start_idx, int end_idx,
+ u64 *prev_pgaddr)
+{
+ int t;
+ for (t = start_idx; t <= end_idx; t++) {
+ u64 pgaddr = page_to_pfn(page_list[t].page) << PAGE_SHIFT;
+ 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",
+ pgaddr, *prev_pgaddr, t);
+ return -EINVAL;
+ }
+ *prev_pgaddr = pgaddr;
+ }
+ return 0;
+}
+
+/* PAGE_SIZE < pginfo->hwpage_size */
+static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int ret = 0;
+ struct ib_umem_chunk *prev_chunk;
+ struct ib_umem_chunk *chunk;
+ u64 pgaddr, prev_pgaddr;
+ u32 i = 0;
+ u32 j = 0;
+ int kpages_per_hwpage = pginfo->hwpage_size / PAGE_SIZE;
+ int nr_kpages = kpages_per_hwpage;
+
+ /* loop over desired chunk entries */
+ chunk = pginfo->u.usr.next_chunk;
+ prev_chunk = pginfo->u.usr.next_chunk;
+ list_for_each_entry_continue(
+ chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+ for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+ if (nr_kpages == kpages_per_hwpage) {
pgaddr = ( page_to_pfn(chunk->page_list[i].page)
<< PAGE_SHIFT );
- *kpage = phys_to_abs(pgaddr +
- (pginfo->next_4k *
- EHCA_PAGESIZE));
+ *kpage = phys_to_abs(pgaddr);
if ( !(*kpage) ) {
- ehca_gen_err("pgaddr=%lx "
- "chunk->page_list[i]=%lx "
- "i=%x next_4k=%lx mr=%p",
- pgaddr,
- (u64)sg_dma_address(
- &chunk->
- page_list[i]),
- i, pginfo->next_4k, e_mr);
+ ehca_gen_err("pgaddr=%lx i=%x",
+ pgaddr, i);
ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
+ return ret;
}
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- kpage++;
- if (pginfo->next_4k %
- (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_nmap)++;
- pginfo->next_4k = 0;
- i++;
+ /*
+ * The first page in a hwpage must be aligned;
+ * the first MR page is exempt from this rule.
+ */
+ if (pgaddr & (pginfo->hwpage_size - 1)) {
+ if (pginfo->hwpage_cnt) {
+ ehca_gen_err(
+ "invalid alignment "
+ "pgaddr=%lx i=%x "
+ "mr_pgsize=%lx",
+ pgaddr, i,
+ pginfo->hwpage_size);
+ ret = -EFAULT;
+ return ret;
+ }
+ /* first MR page */
+ pginfo->kpage_cnt =
+ (pgaddr &
+ (pginfo->hwpage_size - 1)) >>
+ PAGE_SHIFT;
+ nr_kpages -= pginfo->kpage_cnt;
+ *kpage = phys_to_abs(
+ pgaddr &
+ ~(pginfo->hwpage_size - 1));
}
- j++;
- if (j >= number) break;
+ ehca_gen_dbg("kpage=%lx chunk_page=%lx "
+ "value=%016lx", *kpage, pgaddr,
+ *(u64 *)abs_to_virt(
+ phys_to_abs(pgaddr)));
+ prev_pgaddr = pgaddr;
+ i++;
+ pginfo->kpage_cnt++;
+ pginfo->u.usr.next_nmap++;
+ nr_kpages--;
+ if (!nr_kpages)
+ goto next_kpage;
+ continue;
}
- if ((pginfo->next_nmap >= chunk->nmap) &&
- (j >= number)) {
- pginfo->next_nmap = 0;
- prev_chunk = chunk;
- break;
- } else if (pginfo->next_nmap >= chunk->nmap) {
- pginfo->next_nmap = 0;
- prev_chunk = chunk;
- } else if (j >= number)
+ if (i + nr_kpages > chunk->nmap) {
+ ret = ehca_check_kpages_per_ate(
+ chunk->page_list, i,
+ chunk->nmap - 1, &prev_pgaddr);
+ if (ret) return ret;
+ pginfo->kpage_cnt += chunk->nmap - i;
+ pginfo->u.usr.next_nmap += chunk->nmap - i;
+ nr_kpages -= chunk->nmap - i;
break;
- else
- prev_chunk = chunk;
- }
- pginfo->next_chunk =
- list_prepare_entry(prev_chunk,
- (&(pginfo->region->chunk_list)),
- list);
- } else if (pginfo->type == EHCA_MR_PGI_FMR) {
- /* loop over desired page_list entries */
- fmrlist = pginfo->page_list + pginfo->next_listelem;
- for (i = 0; i < number; i++) {
- *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
- pginfo->next_4k * EHCA_PAGESIZE);
- if ( !(*kpage) ) {
- ehca_gen_err("*fmrlist=%lx fmrlist=%p "
- "next_listelem=%lx next_4k=%lx",
- *fmrlist, fmrlist,
- pginfo->next_listelem,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
}
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
+
+ ret = ehca_check_kpages_per_ate(chunk->page_list, i,
+ i + nr_kpages - 1,
+ &prev_pgaddr);
+ if (ret) return ret;
+ i += nr_kpages;
+ pginfo->kpage_cnt += nr_kpages;
+ pginfo->u.usr.next_nmap += nr_kpages;
+next_kpage:
+ nr_kpages = kpages_per_hwpage;
+ (pginfo->hwpage_cnt)++;
kpage++;
- if (pginfo->next_4k %
- (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_listelem)++;
- fmrlist++;
- pginfo->next_4k = 0;
- }
+ j++;
+ if (j >= number) break;
}
- } else {
- ehca_gen_err("bad pginfo->type=%x", pginfo->type);
- ret = -EFAULT;
- goto ehca_set_pagebuf_exit0;
+ if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+ (j >= number)) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ break;
+ } else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+ pginfo->u.usr.next_nmap = 0;
+ prev_chunk = chunk;
+ } else if (j >= number)
+ break;
+ else
+ prev_chunk = chunk;
}
-
-ehca_set_pagebuf_exit0:
- if (ret)
- ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
- "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
- "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
- "next_listelem=%lx region=%p next_chunk=%p "
- "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type,
- pginfo->num_pages, pginfo->num_4k,
- pginfo->next_buf, pginfo->next_4k, number, kpage,
- pginfo->page_cnt, pginfo->page_4k_cnt, i,
- pginfo->next_listelem, pginfo->region,
- pginfo->next_chunk, pginfo->next_nmap);
+ pginfo->u.usr.next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->u.usr.region->chunk_list)),
+ list);
return ret;
-} /* end ehca_set_pagebuf() */
-
-/*----------------------------------------------------------------------*/
+}
-/* setup 1 page from page info page buffer */
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
- u64 *rpage)
+int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
{
int ret = 0;
- struct ib_phys_buf *tmp_pbuf;
- u64 *fmrlist;
- struct ib_umem_chunk *chunk;
- struct ib_umem_chunk *prev_chunk;
- u64 pgaddr, num4k, offs4k;
-
- if (pginfo->type == EHCA_MR_PGI_PHYS) {
- /* sanity check */
- if ((pginfo->page_cnt >= pginfo->num_pages) ||
- (pginfo->page_4k_cnt >= pginfo->num_4k)) {
- ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx "
- "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
- pginfo->page_cnt, pginfo->num_pages,
- pginfo->page_4k_cnt, pginfo->num_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
- }
- tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
- num4k = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
- EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
- offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
- *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) +
- (pginfo->next_4k * EHCA_PAGESIZE));
- if ( !(*rpage) && tmp_pbuf->addr ) {
- ehca_gen_err("tmp_pbuf->addr=%lx"
- " tmp_pbuf->size=%lx next_4k=%lx",
- tmp_pbuf->addr, tmp_pbuf->size,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
- }
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0)
- (pginfo->page_cnt)++;
- if (pginfo->next_4k >= offs4k + num4k) {
- (pginfo->next_buf)++;
- pginfo->next_4k = 0;
- }
- } else if (pginfo->type == EHCA_MR_PGI_USER) {
- chunk = pginfo->next_chunk;
- prev_chunk = pginfo->next_chunk;
- list_for_each_entry_continue(chunk,
- (&(pginfo->region->chunk_list)),
- list) {
- pgaddr = ( page_to_pfn(chunk->page_list[
- pginfo->next_nmap].page)
- << PAGE_SHIFT);
- *rpage = phys_to_abs(pgaddr +
- (pginfo->next_4k * EHCA_PAGESIZE));
- if ( !(*rpage) ) {
- ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx"
- " next_nmap=%lx next_4k=%lx mr=%p",
- pgaddr, (u64)sg_dma_address(
- &chunk->page_list[
- pginfo->
- next_nmap]),
- pginfo->next_nmap, pginfo->next_4k,
- e_mr);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
- }
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k %
- (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_nmap)++;
- pginfo->next_4k = 0;
+ struct ib_phys_buf *pbuf;
+ u64 num_hw, offs_hw;
+ u32 i = 0;
+
+ /* loop over desired phys_buf_array entries */
+ while (i < number) {
+ pbuf = pginfo->u.phy.phys_buf_array + pginfo->u.phy.next_buf;
+ num_hw = NUM_CHUNKS((pbuf->addr % pginfo->hwpage_size) +
+ pbuf->size, pginfo->hwpage_size);
+ offs_hw = (pbuf->addr & ~(pginfo->hwpage_size - 1)) /
+ pginfo->hwpage_size;
+ while (pginfo->next_hwpage < offs_hw + num_hw) {
+ /* sanity check */
+ if ((pginfo->kpage_cnt >= pginfo->num_kpages) ||
+ (pginfo->hwpage_cnt >= pginfo->num_hwpages)) {
+ ehca_gen_err("kpage_cnt >= num_kpages, "
+ "kpage_cnt=%lx num_kpages=%lx "
+ "hwpage_cnt=%lx "
+ "num_hwpages=%lx i=%x",
+ pginfo->kpage_cnt,
+ pginfo->num_kpages,
+ pginfo->hwpage_cnt,
+ pginfo->num_hwpages, i);
+ return -EFAULT;
}
- if (pginfo->next_nmap >= chunk->nmap) {
- pginfo->next_nmap = 0;
- prev_chunk = chunk;
+ *kpage = phys_to_abs(
+ (pbuf->addr & ~(pginfo->hwpage_size - 1)) +
+ (pginfo->next_hwpage * pginfo->hwpage_size));
+ if ( !(*kpage) && pbuf->addr ) {
+ ehca_gen_err("pbuf->addr=%lx pbuf->size=%lx "
+ "next_hwpage=%lx", pbuf->addr,
+ pbuf->size, pginfo->next_hwpage);
+ return -EFAULT;
}
- break;
+ (pginfo->hwpage_cnt)++;
+ (pginfo->next_hwpage)++;
+ if (PAGE_SIZE >= pginfo->hwpage_size) {
+ if (pginfo->next_hwpage %
+ (PAGE_SIZE / pginfo->hwpage_size) == 0)
+ (pginfo->kpage_cnt)++;
+ } else
+ pginfo->kpage_cnt += pginfo->hwpage_size /
+ PAGE_SIZE;
+ kpage++;
+ i++;
+ if (i >= number) break;
+ }
+ if (pginfo->next_hwpage >= offs_hw + num_hw) {
+ (pginfo->u.phy.next_buf)++;
+ pginfo->next_hwpage = 0;
}
- pginfo->next_chunk =
- list_prepare_entry(prev_chunk,
- (&(pginfo->region->chunk_list)),
- list);
- } else if (pginfo->type == EHCA_MR_PGI_FMR) {
- fmrlist = pginfo->page_list + pginfo->next_listelem;
- *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
- pginfo->next_4k * EHCA_PAGESIZE);
- if ( !(*rpage) ) {
+ }
+ return ret;
+}
+
+int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int ret = 0;
+ u64 *fmrlist;
+ u32 i;
+
+ /* loop over desired page_list entries */
+ fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem;
+ for (i = 0; i < number; i++) {
+ *kpage = phys_to_abs((*fmrlist & ~(pginfo->hwpage_size - 1)) +
+ pginfo->next_hwpage * pginfo->hwpage_size);
+ if ( !(*kpage) ) {
ehca_gen_err("*fmrlist=%lx fmrlist=%p "
- "next_listelem=%lx next_4k=%lx",
- *fmrlist, fmrlist, pginfo->next_listelem,
- pginfo->next_4k);
- ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
+ "next_listelem=%lx next_hwpage=%lx",
+ *fmrlist, fmrlist,
+ pginfo->u.fmr.next_listelem,
+ pginfo->next_hwpage);
+ return -EFAULT;
}
- (pginfo->page_4k_cnt)++;
- (pginfo->next_4k)++;
- if (pginfo->next_4k %
- (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
- (pginfo->page_cnt)++;
- (pginfo->next_listelem)++;
- pginfo->next_4k = 0;
+ (pginfo->hwpage_cnt)++;
+ if (pginfo->u.fmr.fmr_pgsize >= pginfo->hwpage_size) {
+ if (pginfo->next_hwpage %
+ (pginfo->u.fmr.fmr_pgsize /
+ pginfo->hwpage_size) == 0) {
+ (pginfo->kpage_cnt)++;
+ (pginfo->u.fmr.next_listelem)++;
+ fmrlist++;
+ pginfo->next_hwpage = 0;
+ } else
+ (pginfo->next_hwpage)++;
+ } else {
+ unsigned int cnt_per_hwpage = pginfo->hwpage_size /
+ pginfo->u.fmr.fmr_pgsize;
+ unsigned int j;
+ u64 prev = *kpage;
+ /* check if adrs are contiguous */
+ for (j = 1; j < cnt_per_hwpage; j++) {
+ u64 p = phys_to_abs(fmrlist[j] &
+ ~(pginfo->hwpage_size - 1));
+ if (prev + pginfo->u.fmr.fmr_pgsize != p) {
+ ehca_gen_err("uncontiguous fmr pages "
+ "found prev=%lx p=%lx "
+ "idx=%x", prev, p, i + j);
+ return -EINVAL;
+ }
+ prev = p;
+ }
+ pginfo->kpage_cnt += cnt_per_hwpage;
+ pginfo->u.fmr.next_listelem += cnt_per_hwpage;
+ fmrlist += cnt_per_hwpage;
}
- } else {
+ kpage++;
+ }
+ return ret;
+}
+
+/* setup page buffer from page info */
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int ret;
+
+ switch (pginfo->type) {
+ case EHCA_MR_PGI_PHYS:
+ ret = ehca_set_pagebuf_phys(pginfo, number, kpage);
+ break;
+ case EHCA_MR_PGI_USER:
+ ret = PAGE_SIZE >= pginfo->hwpage_size ?
+ ehca_set_pagebuf_user1(pginfo, number, kpage) :
+ ehca_set_pagebuf_user2(pginfo, number, kpage);
+ break;
+ case EHCA_MR_PGI_FMR:
+ ret = ehca_set_pagebuf_fmr(pginfo, number, kpage);
+ break;
+ default:
ehca_gen_err("bad pginfo->type=%x", pginfo->type);
ret = -EFAULT;
- goto ehca_set_pagebuf_1_exit0;
+ break;
}
-
-ehca_set_pagebuf_1_exit0:
- if (ret)
- ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
- "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
- "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
- "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr,
- pginfo, pginfo->type, pginfo->num_pages,
- pginfo->num_4k, pginfo->next_buf, pginfo->next_4k,
- rpage, pginfo->page_cnt, pginfo->page_4k_cnt,
- pginfo->next_listelem, pginfo->region,
- pginfo->next_chunk, pginfo->next_nmap);
return ret;
-} /* end ehca_set_pagebuf_1() */
+} /* end ehca_set_pagebuf() */
/*----------------------------------------------------------------------*/
@@ -1982,7 +2117,7 @@ int ehca_mr_is_maxmr(u64 size,
{
/* a MR is treated as max-MR only if it fits following: */
if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
- (iova_start == (void*)KERNELBASE)) {
+ (iova_start == (void *)KERNELBASE)) {
ehca_gen_dbg("this is a max-MR");
return 1;
} else
@@ -2011,9 +2146,9 @@ void ehca_mrmw_map_acl(int ib_acl,
/*----------------------------------------------------------------------*/
/* sets page size in hipz access control for MR/MW. */
-void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl) /*INOUT*/
+void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl) /*INOUT*/
{
- return; /* HCA supports only 4k */
+ *hipz_acl |= (ehca_encode_hwpage_size(pgsize) << 24);
} /* end ehca_mrmw_set_pgsize_hipz_acl() */
/*----------------------------------------------------------------------*/
@@ -2042,196 +2177,23 @@ void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
/*----------------------------------------------------------------------*/
/*
- * map HIPZ rc to IB retcodes for MR/MW allocations
- * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
- */
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* successful completion */
- return 0;
- case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
- case H_CONSTRAINED: /* resource constraint */
- case H_NO_MEM:
- return -ENOMEM;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_alloc() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering last page
- */
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* registration complete */
- return 0;
- case H_PAGE_REGISTERED: /* page registered */
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
-/* case H_QT_PARM: invalid queue type */
- case H_PARAMETER: /*
- * invalid logical address,
- * or count zero or greater 512
- */
- case H_TABLE_FULL: /* page table full */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_rrpg_last() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering one page, but not last page
- */
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_PAGE_REGISTERED: /* page registered */
- return 0;
- case H_SUCCESS: /* registration complete */
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
-/* case H_QT_PARM: invalid queue type */
- case H_PARAMETER: /*
- * invalid logical address,
- * or count zero or greater 512
- */
- case H_TABLE_FULL: /* page table full */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_rrpg_notlast() */
-
-/*----------------------------------------------------------------------*/
-
-/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* successful completion */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_query_mr() */
-
-/*----------------------------------------------------------------------*/
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MR resource
- * Used for hipz_h_free_resource_mr
- */
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* resource freed */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- case H_R_STATE: /* invalid resource state */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_RESOURCE: /* Resource in use */
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_free_mr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MW resource
- * Used for hipz_h_free_resource_mw
- */
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* resource freed */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- case H_R_STATE: /* invalid resource state */
- case H_HARDWARE: /* HCA not operational */
- return -EINVAL;
- case H_RESOURCE: /* Resource in use */
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_free_mw() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for SMR registrations
- * Used for hipz_h_register_smr.
- */
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
-{
- switch (hipz_rc) {
- case H_SUCCESS: /* successful completion */
- return 0;
- case H_ADAPTER_PARM: /* invalid adapter handle */
- case H_RH_PARM: /* invalid resource handle */
- case H_MEM_PARM: /* invalid MR virtual address */
- case H_MEM_ACCESS_PARM: /* invalid access controls */
- case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
- return -EINVAL;
- case H_BUSY: /* long busy */
- return -EBUSY;
- default:
- return -EINVAL;
- }
-} /* end ehca_mrmw_map_hrc_reg_smr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
* MR destructor and constructor
* used in Reregister MR verb, sets all fields in ehca_mr_t to 0,
* except struct ib_mr and spinlock
*/
void ehca_mr_deletenew(struct ehca_mr *mr)
{
- mr->flags = 0;
- mr->num_pages = 0;
- mr->num_4k = 0;
- mr->acl = 0;
- mr->start = NULL;
+ mr->flags = 0;
+ mr->num_kpages = 0;
+ mr->num_hwpages = 0;
+ mr->acl = 0;
+ mr->start = NULL;
mr->fmr_page_size = 0;
mr->fmr_max_pages = 0;
- mr->fmr_max_maps = 0;
- mr->fmr_map_cnt = 0;
+ mr->fmr_max_maps = 0;
+ mr->fmr_map_cnt = 0;
memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
memset(&mr->galpas, 0, sizeof(mr->galpas));
- mr->nr_of_pages = 0;
- mr->pagearray = NULL;
} /* end ehca_mr_deletenew() */
int ehca_init_mrmw_cache(void)
@@ -2239,13 +2201,13 @@ int ehca_init_mrmw_cache(void)
mr_cache = kmem_cache_create("ehca_cache_mr",
sizeof(struct ehca_mr), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!mr_cache)
return -ENOMEM;
mw_cache = kmem_cache_create("ehca_cache_mw",
sizeof(struct ehca_mw), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!mw_cache) {
kmem_cache_destroy(mr_cache);
mr_cache = NULL;
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h
index d936e40a5748..bc8f4e31c123 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.h
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h
@@ -101,40 +101,21 @@ int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
u64 *page_list,
int list_len);
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
u32 number,
u64 *kpage);
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
- struct ehca_mr_pginfo *pginfo,
- u64 *rpage);
-
int ehca_mr_is_maxmr(u64 size,
u64 *iova_start);
void ehca_mrmw_map_acl(int ib_acl,
u32 *hipz_acl);
-void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
+void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl);
void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
int *ib_acl);
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc);
-
void ehca_mr_deletenew(struct ehca_mr *mr);
#endif /*_EHCA_MRMW_H_*/
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c
index 79d0591a8043..3dafd7ff36cd 100644
--- a/drivers/infiniband/hw/ehca/ehca_pd.c
+++ b/drivers/infiniband/hw/ehca/ehca_pd.c
@@ -49,6 +49,7 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
struct ib_ucontext *context, struct ib_udata *udata)
{
struct ehca_pd *pd;
+ int i;
pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL);
if (!pd) {
@@ -58,6 +59,11 @@ struct ib_pd *ehca_alloc_pd(struct ib_device *device,
}
pd->ownpid = current->tgid;
+ for (i = 0; i < 2; i++) {
+ INIT_LIST_HEAD(&pd->free[i]);
+ INIT_LIST_HEAD(&pd->full[i]);
+ }
+ mutex_init(&pd->lock);
/*
* Kernel PD: when device = -1, 0
@@ -81,6 +87,9 @@ int ehca_dealloc_pd(struct ib_pd *pd)
{
u32 cur_pid = current->tgid;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
+ int i, leftovers = 0;
+ extern struct kmem_cache *small_qp_cache;
+ struct ipz_small_queue_page *page, *tmp;
if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
my_pd->ownpid != cur_pid) {
@@ -89,8 +98,20 @@ int ehca_dealloc_pd(struct ib_pd *pd)
return -EINVAL;
}
- kmem_cache_free(pd_cache,
- container_of(pd, struct ehca_pd, ib_pd));
+ for (i = 0; i < 2; i++) {
+ list_splice(&my_pd->full[i], &my_pd->free[i]);
+ list_for_each_entry_safe(page, tmp, &my_pd->free[i], list) {
+ leftovers = 1;
+ free_page(page->page);
+ kmem_cache_free(small_qp_cache, page);
+ }
+ }
+
+ if (leftovers)
+ ehca_warn(pd->device,
+ "Some small queue pages were not freed");
+
+ kmem_cache_free(pd_cache, my_pd);
return 0;
}
@@ -100,7 +121,7 @@ int ehca_init_pd_cache(void)
pd_cache = kmem_cache_create("ehca_cache_pd",
sizeof(struct ehca_pd), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!pd_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h
index 8707d297ce4c..818803057ebf 100644
--- a/drivers/infiniband/hw/ehca/ehca_qes.h
+++ b/drivers/infiniband/hw/ehca/ehca_qes.h
@@ -53,13 +53,13 @@ struct ehca_vsgentry {
u32 length;
};
-#define GRH_FLAG_MASK EHCA_BMASK_IBM(7,7)
-#define GRH_IPVERSION_MASK EHCA_BMASK_IBM(0,3)
-#define GRH_TCLASS_MASK EHCA_BMASK_IBM(4,12)
-#define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13,31)
-#define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32,47)
-#define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48,55)
-#define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56,63)
+#define GRH_FLAG_MASK EHCA_BMASK_IBM( 7, 7)
+#define GRH_IPVERSION_MASK EHCA_BMASK_IBM( 0, 3)
+#define GRH_TCLASS_MASK EHCA_BMASK_IBM( 4, 12)
+#define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13, 31)
+#define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32, 47)
+#define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48, 55)
+#define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56, 63)
/*
* Unreliable Datagram Address Vector Format
@@ -206,10 +206,10 @@ struct ehca_wqe {
};
-#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
-#define WC_IMM_DATA EHCA_BMASK_IBM(1,1)
-#define WC_GRH_PRESENT EHCA_BMASK_IBM(2,2)
-#define WC_SE_BIT EHCA_BMASK_IBM(3,3)
+#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0, 0)
+#define WC_IMM_DATA EHCA_BMASK_IBM(1, 1)
+#define WC_GRH_PRESENT EHCA_BMASK_IBM(2, 2)
+#define WC_SE_BIT EHCA_BMASK_IBM(3, 3)
#define WC_STATUS_ERROR_BIT 0x80000000
#define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
#define WC_STATUS_PURGE_BIT 0x10
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index b5bc787c77b6..b178cba96345 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -3,7 +3,9 @@
*
* QP functions
*
- * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Authors: Joachim Fenkes <fenkes@de.ibm.com>
+ * Stefan Roscher <stefan.roscher@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
* Hoang-Nam Nguyen <hnguyen@de.ibm.com>
* Reinhard Ernst <rernst@de.ibm.com>
* Heiko J Schick <schickhj@de.ibm.com>
@@ -234,13 +236,6 @@ static inline enum ib_qp_statetrans get_modqp_statetrans(int ib_fromstate,
return index;
}
-enum ehca_service_type {
- ST_RC = 0,
- ST_UC = 1,
- ST_RD = 2,
- ST_UD = 3
-};
-
/*
* ibqptype2servicetype returns hcp service type corresponding to given
* ib qp type used by create_qp()
@@ -268,143 +263,169 @@ static inline int ibqptype2servicetype(enum ib_qp_type ibqptype)
}
/*
- * init_qp_queues initializes/constructs r/squeue and registers queue pages.
+ * init userspace queue info from ipz_queue data
+ */
+static inline void queue2resp(struct ipzu_queue_resp *resp,
+ struct ipz_queue *queue)
+{
+ resp->qe_size = queue->qe_size;
+ resp->act_nr_of_sg = queue->act_nr_of_sg;
+ resp->queue_length = queue->queue_length;
+ resp->pagesize = queue->pagesize;
+ resp->toggle_state = queue->toggle_state;
+}
+
+/*
+ * init_qp_queue initializes/constructs r/squeue and registers queue pages.
*/
-static inline int init_qp_queues(struct ehca_shca *shca,
- struct ehca_qp *my_qp,
- int nr_sq_pages,
- int nr_rq_pages,
- int swqe_size,
- int rwqe_size,
- int nr_send_sges, int nr_receive_sges)
+static inline int init_qp_queue(struct ehca_shca *shca,
+ struct ehca_pd *pd,
+ struct ehca_qp *my_qp,
+ struct ipz_queue *queue,
+ int q_type,
+ u64 expected_hret,
+ struct ehca_alloc_queue_parms *parms,
+ int wqe_size)
{
- int ret, cnt, ipz_rc;
+ int ret, cnt, ipz_rc, nr_q_pages;
void *vpage;
u64 rpage, h_ret;
struct ib_device *ib_dev = &shca->ib_device;
struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
- ipz_rc = ipz_queue_ctor(&my_qp->ipz_squeue,
- nr_sq_pages,
- EHCA_PAGESIZE, swqe_size, nr_send_sges);
- if (!ipz_rc) {
- ehca_err(ib_dev,"Cannot allocate page for squeue. ipz_rc=%x",
- ipz_rc);
- return -EBUSY;
+ if (!parms->queue_size)
+ return 0;
+
+ if (parms->is_small) {
+ nr_q_pages = 1;
+ ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+ 128 << parms->page_size,
+ wqe_size, parms->act_nr_sges, 1);
+ } else {
+ nr_q_pages = parms->queue_size;
+ ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+ EHCA_PAGESIZE, wqe_size,
+ parms->act_nr_sges, 0);
}
- ipz_rc = ipz_queue_ctor(&my_qp->ipz_rqueue,
- nr_rq_pages,
- EHCA_PAGESIZE, rwqe_size, nr_receive_sges);
if (!ipz_rc) {
- ehca_err(ib_dev, "Cannot allocate page for rqueue. ipz_rc=%x",
+ ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x",
ipz_rc);
- ret = -EBUSY;
- goto init_qp_queues0;
+ return -EBUSY;
}
- /* register SQ pages */
- for (cnt = 0; cnt < nr_sq_pages; cnt++) {
- vpage = ipz_qpageit_get_inc(&my_qp->ipz_squeue);
+
+ /* register queue pages */
+ for (cnt = 0; cnt < nr_q_pages; cnt++) {
+ vpage = ipz_qpageit_get_inc(queue);
if (!vpage) {
- ehca_err(ib_dev, "SQ ipz_qpageit_get_inc() "
+ ehca_err(ib_dev, "ipz_qpageit_get_inc() "
"failed p_vpage= %p", vpage);
ret = -EINVAL;
- goto init_qp_queues1;
+ goto init_qp_queue1;
}
rpage = virt_to_abs(vpage);
h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
my_qp->ipz_qp_handle,
- &my_qp->pf, 0, 0,
- rpage, 1,
+ NULL, 0, q_type,
+ rpage, parms->is_small ? 0 : 1,
my_qp->galpas.kernel);
- if (h_ret < H_SUCCESS) {
- ehca_err(ib_dev, "SQ hipz_qp_register_rpage()"
- " failed rc=%lx", h_ret);
- ret = ehca2ib_return_code(h_ret);
- goto init_qp_queues1;
- }
- }
-
- ipz_qeit_reset(&my_qp->ipz_squeue);
-
- /* register RQ pages */
- for (cnt = 0; cnt < nr_rq_pages; cnt++) {
- vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
- if (!vpage) {
- ehca_err(ib_dev, "RQ ipz_qpageit_get_inc() "
- "failed p_vpage = %p", vpage);
- ret = -EINVAL;
- goto init_qp_queues1;
- }
-
- rpage = virt_to_abs(vpage);
-
- h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
- my_qp->ipz_qp_handle,
- &my_qp->pf, 0, 1,
- rpage, 1,my_qp->galpas.kernel);
- if (h_ret < H_SUCCESS) {
- ehca_err(ib_dev, "RQ hipz_qp_register_rpage() failed "
- "rc=%lx", h_ret);
- ret = ehca2ib_return_code(h_ret);
- goto init_qp_queues1;
- }
- if (cnt == (nr_rq_pages - 1)) { /* last page! */
- if (h_ret != H_SUCCESS) {
- ehca_err(ib_dev, "RQ hipz_qp_register_rpage() "
+ if (cnt == (nr_q_pages - 1)) { /* last page! */
+ if (h_ret != expected_hret) {
+ ehca_err(ib_dev, "hipz_qp_register_rpage() "
"h_ret= %lx ", h_ret);
ret = ehca2ib_return_code(h_ret);
- goto init_qp_queues1;
+ goto init_qp_queue1;
}
vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
if (vpage) {
ehca_err(ib_dev, "ipz_qpageit_get_inc() "
"should not succeed vpage=%p", vpage);
ret = -EINVAL;
- goto init_qp_queues1;
+ goto init_qp_queue1;
}
} else {
if (h_ret != H_PAGE_REGISTERED) {
- ehca_err(ib_dev, "RQ hipz_qp_register_rpage() "
+ ehca_err(ib_dev, "hipz_qp_register_rpage() "
"h_ret= %lx ", h_ret);
ret = ehca2ib_return_code(h_ret);
- goto init_qp_queues1;
+ goto init_qp_queue1;
}
}
}
- ipz_qeit_reset(&my_qp->ipz_rqueue);
+ ipz_qeit_reset(queue);
return 0;
-init_qp_queues1:
- ipz_queue_dtor(&my_qp->ipz_rqueue);
-init_qp_queues0:
- ipz_queue_dtor(&my_qp->ipz_squeue);
+init_qp_queue1:
+ ipz_queue_dtor(pd, queue);
return ret;
}
-struct ib_qp *ehca_create_qp(struct ib_pd *pd,
- struct ib_qp_init_attr *init_attr,
- struct ib_udata *udata)
+static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp)
+{
+ if (is_llqp)
+ return 128 << act_nr_sge;
+ else
+ return offsetof(struct ehca_wqe,
+ u.nud.sg_list[act_nr_sge]);
+}
+
+static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
+ int req_nr_sge, int is_llqp)
+{
+ u32 wqe_size, q_size;
+ int act_nr_sge = req_nr_sge;
+
+ if (!is_llqp)
+ /* round up #SGEs so WQE size is a power of 2 */
+ for (act_nr_sge = 4; act_nr_sge <= 252;
+ act_nr_sge = 4 + 2 * act_nr_sge)
+ if (act_nr_sge >= req_nr_sge)
+ break;
+
+ wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp);
+ q_size = wqe_size * (queue->max_wr + 1);
+
+ if (q_size <= 512)
+ queue->page_size = 2;
+ else if (q_size <= 1024)
+ queue->page_size = 3;
+ else
+ queue->page_size = 0;
+
+ queue->is_small = (queue->page_size != 0);
+}
+
+/*
+ * Create an ib_qp struct that is either a QP or an SRQ, depending on
+ * the value of the is_srq parameter. If init_attr and srq_init_attr share
+ * fields, the field out of init_attr is used.
+ */
+static struct ehca_qp *internal_create_qp(
+ struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_srq_init_attr *srq_init_attr,
+ struct ib_udata *udata, int is_srq)
{
- static int da_rc_msg_size[]={ 128, 256, 512, 1024, 2048, 4096 };
- static int da_ud_sq_msg_size[]={ 128, 384, 896, 1920, 3968 };
struct ehca_qp *my_qp;
struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
ib_device);
struct ib_ucontext *context = NULL;
u64 h_ret;
- int max_send_sge, max_recv_sge, ret;
+ int is_llqp = 0, has_srq = 0;
+ int qp_type, max_send_sge, max_recv_sge, ret;
/* h_call's out parameters */
struct ehca_alloc_qp_parms parms;
- u32 swqe_size = 0, rwqe_size = 0;
- u8 daqp_completion, isdaqp;
+ u32 swqe_size = 0, rwqe_size = 0, ib_qp_num;
unsigned long flags;
+ memset(&parms, 0, sizeof(parms));
+ qp_type = init_attr->qp_type;
+
if (init_attr->sq_sig_type != IB_SIGNAL_REQ_WR &&
init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {
ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed",
@@ -412,41 +433,98 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
return ERR_PTR(-EINVAL);
}
- /* save daqp completion bits */
- daqp_completion = init_attr->qp_type & 0x60;
- /* save daqp bit */
- isdaqp = (init_attr->qp_type & 0x80) ? 1 : 0;
- init_attr->qp_type = init_attr->qp_type & 0x1F;
+ /* save LLQP info */
+ if (qp_type & 0x80) {
+ is_llqp = 1;
+ parms.ext_type = EQPT_LLQP;
+ parms.ll_comp_flags = qp_type & LLQP_COMP_MASK;
+ }
+ qp_type &= 0x1F;
+ init_attr->qp_type &= 0x1F;
- if (init_attr->qp_type != IB_QPT_UD &&
- init_attr->qp_type != IB_QPT_SMI &&
- init_attr->qp_type != IB_QPT_GSI &&
- init_attr->qp_type != IB_QPT_UC &&
- init_attr->qp_type != IB_QPT_RC) {
- ehca_err(pd->device, "wrong QP Type=%x", init_attr->qp_type);
- return ERR_PTR(-EINVAL);
+ /* handle SRQ base QPs */
+ if (init_attr->srq) {
+ struct ehca_qp *my_srq =
+ container_of(init_attr->srq, struct ehca_qp, ib_srq);
+
+ has_srq = 1;
+ parms.ext_type = EQPT_SRQBASE;
+ parms.srq_qpn = my_srq->real_qp_num;
+ parms.srq_token = my_srq->token;
}
- if ((init_attr->qp_type != IB_QPT_RC && init_attr->qp_type != IB_QPT_UD)
- && isdaqp) {
- ehca_err(pd->device, "unsupported LL QP Type=%x",
- init_attr->qp_type);
+
+ if (is_llqp && has_srq) {
+ ehca_err(pd->device, "LLQPs can't have an SRQ");
return ERR_PTR(-EINVAL);
- } else if (init_attr->qp_type == IB_QPT_RC && isdaqp &&
- (init_attr->cap.max_send_wr > 255 ||
- init_attr->cap.max_recv_wr > 255 )) {
- ehca_err(pd->device, "Invalid Number of max_sq_wr =%x "
- "or max_rq_wr=%x for QP Type=%x",
- init_attr->cap.max_send_wr,
- init_attr->cap.max_recv_wr,init_attr->qp_type);
- return ERR_PTR(-EINVAL);
- } else if (init_attr->qp_type == IB_QPT_UD && isdaqp &&
- init_attr->cap.max_send_wr > 255) {
- ehca_err(pd->device,
- "Invalid Number of max_send_wr=%x for UD QP_TYPE=%x",
- init_attr->cap.max_send_wr, init_attr->qp_type);
+ }
+
+ /* handle SRQs */
+ if (is_srq) {
+ parms.ext_type = EQPT_SRQ;
+ parms.srq_limit = srq_init_attr->attr.srq_limit;
+ if (init_attr->cap.max_recv_sge > 3) {
+ ehca_err(pd->device, "no more than three SGEs "
+ "supported for SRQ pd=%p max_sge=%x",
+ pd, init_attr->cap.max_recv_sge);
+ return ERR_PTR(-EINVAL);
+ }
+ }
+
+ /* check QP type */
+ if (qp_type != IB_QPT_UD &&
+ qp_type != IB_QPT_UC &&
+ qp_type != IB_QPT_RC &&
+ qp_type != IB_QPT_SMI &&
+ qp_type != IB_QPT_GSI) {
+ ehca_err(pd->device, "wrong QP Type=%x", qp_type);
return ERR_PTR(-EINVAL);
}
+ if (is_llqp) {
+ switch (qp_type) {
+ case IB_QPT_RC:
+ if ((init_attr->cap.max_send_wr > 255) ||
+ (init_attr->cap.max_recv_wr > 255)) {
+ ehca_err(pd->device,
+ "Invalid Number of max_sq_wr=%x "
+ "or max_rq_wr=%x for RC LLQP",
+ init_attr->cap.max_send_wr,
+ init_attr->cap.max_recv_wr);
+ return ERR_PTR(-EINVAL);
+ }
+ break;
+ case IB_QPT_UD:
+ if (!EHCA_BMASK_GET(HCA_CAP_UD_LL_QP, shca->hca_cap)) {
+ ehca_err(pd->device, "UD LLQP not supported "
+ "by this adapter");
+ return ERR_PTR(-ENOSYS);
+ }
+ if (!(init_attr->cap.max_send_sge <= 5
+ && init_attr->cap.max_send_sge >= 1
+ && init_attr->cap.max_recv_sge <= 5
+ && init_attr->cap.max_recv_sge >= 1)) {
+ ehca_err(pd->device,
+ "Invalid Number of max_send_sge=%x "
+ "or max_recv_sge=%x for UD LLQP",
+ init_attr->cap.max_send_sge,
+ init_attr->cap.max_recv_sge);
+ return ERR_PTR(-EINVAL);
+ } else if (init_attr->cap.max_send_wr > 255) {
+ ehca_err(pd->device,
+ "Invalid Number of "
+ "ax_send_wr=%x for UD QP_TYPE=%x",
+ init_attr->cap.max_send_wr, qp_type);
+ return ERR_PTR(-EINVAL);
+ }
+ break;
+ default:
+ ehca_err(pd->device, "unsupported LL QP Type=%x",
+ qp_type);
+ return ERR_PTR(-EINVAL);
+ break;
+ }
+ }
+
if (pd->uobject && udata)
context = pd->uobject->context;
@@ -456,16 +534,17 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
return ERR_PTR(-ENOMEM);
}
- memset (&parms, 0, sizeof(struct ehca_alloc_qp_parms));
spin_lock_init(&my_qp->spinlock_s);
spin_lock_init(&my_qp->spinlock_r);
+ my_qp->qp_type = qp_type;
+ my_qp->ext_type = parms.ext_type;
- my_qp->recv_cq =
- container_of(init_attr->recv_cq, struct ehca_cq, ib_cq);
- my_qp->send_cq =
- container_of(init_attr->send_cq, struct ehca_cq, ib_cq);
-
- my_qp->init_attr = *init_attr;
+ if (init_attr->recv_cq)
+ my_qp->recv_cq =
+ container_of(init_attr->recv_cq, struct ehca_cq, ib_cq);
+ if (init_attr->send_cq)
+ my_qp->send_cq =
+ container_of(init_attr->send_cq, struct ehca_cq, ib_cq);
do {
if (!idr_pre_get(&ehca_qp_idr, GFP_KERNEL)) {
@@ -474,9 +553,9 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
goto create_qp_exit0;
}
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ write_lock_irqsave(&ehca_qp_idr_lock, flags);
ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
} while (ret == -EAGAIN);
@@ -486,10 +565,10 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
goto create_qp_exit0;
}
- parms.servicetype = ibqptype2servicetype(init_attr->qp_type);
+ parms.servicetype = ibqptype2servicetype(qp_type);
if (parms.servicetype < 0) {
ret = -EINVAL;
- ehca_err(pd->device, "Invalid qp_type=%x", init_attr->qp_type);
+ ehca_err(pd->device, "Invalid qp_type=%x", qp_type);
goto create_qp_exit0;
}
@@ -501,21 +580,35 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
/* UD_AV CIRCUMVENTION */
max_send_sge = init_attr->cap.max_send_sge;
max_recv_sge = init_attr->cap.max_recv_sge;
- if (IB_QPT_UD == init_attr->qp_type ||
- IB_QPT_GSI == init_attr->qp_type ||
- IB_QPT_SMI == init_attr->qp_type) {
+ if (parms.servicetype == ST_UD && !is_llqp) {
max_send_sge += 2;
max_recv_sge += 2;
}
- parms.ipz_eq_handle = shca->eq.ipz_eq_handle;
- parms.daqp_ctrl = isdaqp | daqp_completion;
+ parms.token = my_qp->token;
+ parms.eq_handle = shca->eq.ipz_eq_handle;
parms.pd = my_pd->fw_pd;
- parms.max_recv_sge = max_recv_sge;
- parms.max_send_sge = max_send_sge;
-
- h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, my_qp, &parms);
-
+ if (my_qp->send_cq)
+ parms.send_cq_handle = my_qp->send_cq->ipz_cq_handle;
+ if (my_qp->recv_cq)
+ parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle;
+
+ parms.squeue.max_wr = init_attr->cap.max_send_wr;
+ parms.rqueue.max_wr = init_attr->cap.max_recv_wr;
+ parms.squeue.max_sge = max_send_sge;
+ parms.rqueue.max_sge = max_recv_sge;
+
+ if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)
+ && !(context && udata)) { /* no small QP support in userspace ATM */
+ ehca_determine_small_queue(
+ &parms.squeue, max_send_sge, is_llqp);
+ ehca_determine_small_queue(
+ &parms.rqueue, max_recv_sge, is_llqp);
+ parms.qp_storage =
+ (parms.squeue.is_small || parms.rqueue.is_small);
+ }
+
+ h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
if (h_ret != H_SUCCESS) {
ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx",
h_ret);
@@ -523,55 +616,38 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
goto create_qp_exit1;
}
- my_qp->ib_qp.qp_num = my_qp->real_qp_num;
+ ib_qp_num = my_qp->real_qp_num = parms.real_qp_num;
+ my_qp->ipz_qp_handle = parms.qp_handle;
+ my_qp->galpas = parms.galpas;
- switch (init_attr->qp_type) {
+ swqe_size = ehca_calc_wqe_size(parms.squeue.act_nr_sges, is_llqp);
+ rwqe_size = ehca_calc_wqe_size(parms.rqueue.act_nr_sges, is_llqp);
+
+ switch (qp_type) {
case IB_QPT_RC:
- if (isdaqp == 0) {
- swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
- (parms.act_nr_send_sges)]);
- rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
- (parms.act_nr_recv_sges)]);
- } else { /* for daqp we need to use msg size, not wqe size */
- swqe_size = da_rc_msg_size[max_send_sge];
- rwqe_size = da_rc_msg_size[max_recv_sge];
- parms.act_nr_send_sges = 1;
- parms.act_nr_recv_sges = 1;
+ if (is_llqp) {
+ parms.squeue.act_nr_sges = 1;
+ parms.rqueue.act_nr_sges = 1;
}
break;
- case IB_QPT_UC:
- swqe_size = offsetof(struct ehca_wqe,
- u.nud.sg_list[parms.act_nr_send_sges]);
- rwqe_size = offsetof(struct ehca_wqe,
- u.nud.sg_list[parms.act_nr_recv_sges]);
- break;
-
case IB_QPT_UD:
case IB_QPT_GSI:
case IB_QPT_SMI:
/* UD circumvention */
- parms.act_nr_recv_sges -= 2;
- parms.act_nr_send_sges -= 2;
- if (isdaqp) {
- swqe_size = da_ud_sq_msg_size[max_send_sge];
- rwqe_size = da_rc_msg_size[max_recv_sge];
- parms.act_nr_send_sges = 1;
- parms.act_nr_recv_sges = 1;
+ if (is_llqp) {
+ parms.squeue.act_nr_sges = 1;
+ parms.rqueue.act_nr_sges = 1;
} else {
- swqe_size = offsetof(struct ehca_wqe,
- u.ud_av.sg_list[parms.act_nr_send_sges]);
- rwqe_size = offsetof(struct ehca_wqe,
- u.ud_av.sg_list[parms.act_nr_recv_sges]);
+ parms.squeue.act_nr_sges -= 2;
+ parms.rqueue.act_nr_sges -= 2;
}
- if (IB_QPT_GSI == init_attr->qp_type ||
- IB_QPT_SMI == init_attr->qp_type) {
- parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
- parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
- parms.act_nr_send_sges = init_attr->cap.max_send_sge;
- parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
- my_qp->ib_qp.qp_num =
- (init_attr->qp_type == IB_QPT_SMI) ? 0 : 1;
+ if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
+ parms.squeue.act_nr_wqes = init_attr->cap.max_send_wr;
+ parms.rqueue.act_nr_wqes = init_attr->cap.max_recv_wr;
+ parms.squeue.act_nr_sges = init_attr->cap.max_send_sge;
+ parms.rqueue.act_nr_sges = init_attr->cap.max_recv_sge;
+ ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1;
}
break;
@@ -580,108 +656,234 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
break;
}
- /* initializes r/squeue and registers queue pages */
- ret = init_qp_queues(shca, my_qp,
- parms.nr_sq_pages, parms.nr_rq_pages,
- swqe_size, rwqe_size,
- parms.act_nr_send_sges, parms.act_nr_recv_sges);
- if (ret) {
- ehca_err(pd->device,
- "Couldn't initialize r/squeue and pages ret=%x", ret);
- goto create_qp_exit2;
+ /* initialize r/squeue and register queue pages */
+ if (HAS_SQ(my_qp)) {
+ ret = init_qp_queue(
+ shca, my_pd, my_qp, &my_qp->ipz_squeue, 0,
+ HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS,
+ &parms.squeue, swqe_size);
+ if (ret) {
+ ehca_err(pd->device, "Couldn't initialize squeue "
+ "and pages ret=%x", ret);
+ goto create_qp_exit2;
+ }
}
- my_qp->ib_qp.pd = &my_pd->ib_pd;
- my_qp->ib_qp.device = my_pd->ib_pd.device;
+ if (HAS_RQ(my_qp)) {
+ ret = init_qp_queue(
+ shca, my_pd, my_qp, &my_qp->ipz_rqueue, 1,
+ H_SUCCESS, &parms.rqueue, rwqe_size);
+ if (ret) {
+ ehca_err(pd->device, "Couldn't initialize rqueue "
+ "and pages ret=%x", ret);
+ goto create_qp_exit3;
+ }
+ }
+
+ if (is_srq) {
+ my_qp->ib_srq.pd = &my_pd->ib_pd;
+ my_qp->ib_srq.device = my_pd->ib_pd.device;
- my_qp->ib_qp.recv_cq = init_attr->recv_cq;
- my_qp->ib_qp.send_cq = init_attr->send_cq;
+ my_qp->ib_srq.srq_context = init_attr->qp_context;
+ my_qp->ib_srq.event_handler = init_attr->event_handler;
+ } else {
+ my_qp->ib_qp.qp_num = ib_qp_num;
+ my_qp->ib_qp.pd = &my_pd->ib_pd;
+ my_qp->ib_qp.device = my_pd->ib_pd.device;
- my_qp->ib_qp.qp_type = init_attr->qp_type;
+ my_qp->ib_qp.recv_cq = init_attr->recv_cq;
+ my_qp->ib_qp.send_cq = init_attr->send_cq;
- my_qp->qp_type = init_attr->qp_type;
- my_qp->ib_qp.srq = init_attr->srq;
+ my_qp->ib_qp.qp_type = qp_type;
+ my_qp->ib_qp.srq = init_attr->srq;
- my_qp->ib_qp.qp_context = init_attr->qp_context;
- my_qp->ib_qp.event_handler = init_attr->event_handler;
+ my_qp->ib_qp.qp_context = init_attr->qp_context;
+ my_qp->ib_qp.event_handler = init_attr->event_handler;
+ }
init_attr->cap.max_inline_data = 0; /* not supported yet */
- init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
- init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
- init_attr->cap.max_send_sge = parms.act_nr_send_sges;
- init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
+ init_attr->cap.max_recv_sge = parms.rqueue.act_nr_sges;
+ init_attr->cap.max_recv_wr = parms.rqueue.act_nr_wqes;
+ init_attr->cap.max_send_sge = parms.squeue.act_nr_sges;
+ init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
+ my_qp->init_attr = *init_attr;
/* NOTE: define_apq0() not supported yet */
- if (init_attr->qp_type == IB_QPT_GSI) {
+ if (qp_type == IB_QPT_GSI) {
h_ret = ehca_define_sqp(shca, my_qp, init_attr);
if (h_ret != H_SUCCESS) {
ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx",
h_ret);
ret = ehca2ib_return_code(h_ret);
- goto create_qp_exit3;
+ goto create_qp_exit4;
}
}
- if (init_attr->send_cq) {
- struct ehca_cq *cq = container_of(init_attr->send_cq,
- struct ehca_cq, ib_cq);
- ret = ehca_cq_assign_qp(cq, my_qp);
+
+ if (my_qp->send_cq) {
+ ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp);
if (ret) {
- ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x",
- ret);
- goto create_qp_exit3;
+ ehca_err(pd->device,
+ "Couldn't assign qp to send_cq ret=%x", ret);
+ goto create_qp_exit4;
}
- my_qp->send_cq = cq;
}
+
/* copy queues, galpa data to user space */
if (context && udata) {
- struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
- struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
struct ehca_create_qp_resp resp;
memset(&resp, 0, sizeof(resp));
resp.qp_num = my_qp->real_qp_num;
resp.token = my_qp->token;
resp.qp_type = my_qp->qp_type;
+ resp.ext_type = my_qp->ext_type;
resp.qkey = my_qp->qkey;
resp.real_qp_num = my_qp->real_qp_num;
- /* rqueue properties */
- resp.ipz_rqueue.qe_size = ipz_rqueue->qe_size;
- resp.ipz_rqueue.act_nr_of_sg = ipz_rqueue->act_nr_of_sg;
- resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
- resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
- resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
- /* squeue properties */
- resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
- resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
- resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
- resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
- resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
+ resp.ipz_rqueue.offset = my_qp->ipz_rqueue.offset;
+ resp.ipz_squeue.offset = my_qp->ipz_squeue.offset;
+ if (HAS_SQ(my_qp))
+ queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue);
+ if (HAS_RQ(my_qp))
+ queue2resp(&resp.ipz_rqueue, &my_qp->ipz_rqueue);
+
if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
ehca_err(pd->device, "Copy to udata failed");
ret = -EINVAL;
- goto create_qp_exit3;
+ goto create_qp_exit4;
}
}
- return &my_qp->ib_qp;
+ return my_qp;
+
+create_qp_exit4:
+ if (HAS_RQ(my_qp))
+ ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
create_qp_exit3:
- ipz_queue_dtor(&my_qp->ipz_rqueue);
- ipz_queue_dtor(&my_qp->ipz_squeue);
+ if (HAS_SQ(my_qp))
+ ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
create_qp_exit2:
hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
create_qp_exit1:
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ write_lock_irqsave(&ehca_qp_idr_lock, flags);
idr_remove(&ehca_qp_idr, my_qp->token);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
create_qp_exit0:
kmem_cache_free(qp_cache, my_qp);
return ERR_PTR(ret);
}
+struct ib_qp *ehca_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *qp_init_attr,
+ struct ib_udata *udata)
+{
+ struct ehca_qp *ret;
+
+ ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0);
+ return IS_ERR(ret) ? (struct ib_qp *)ret : &ret->ib_qp;
+}
+
+static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+ struct ib_uobject *uobject);
+
+struct ib_srq *ehca_create_srq(struct ib_pd *pd,
+ struct ib_srq_init_attr *srq_init_attr,
+ struct ib_udata *udata)
+{
+ struct ib_qp_init_attr qp_init_attr;
+ struct ehca_qp *my_qp;
+ struct ib_srq *ret;
+ struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
+ ib_device);
+ struct hcp_modify_qp_control_block *mqpcb;
+ u64 hret, update_mask;
+
+ /* For common attributes, internal_create_qp() takes its info
+ * out of qp_init_attr, so copy all common attrs there.
+ */
+ memset(&qp_init_attr, 0, sizeof(qp_init_attr));
+ qp_init_attr.event_handler = srq_init_attr->event_handler;
+ qp_init_attr.qp_context = srq_init_attr->srq_context;
+ qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
+ qp_init_attr.qp_type = IB_QPT_RC;
+ qp_init_attr.cap.max_recv_wr = srq_init_attr->attr.max_wr;
+ qp_init_attr.cap.max_recv_sge = srq_init_attr->attr.max_sge;
+
+ my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1);
+ if (IS_ERR(my_qp))
+ return (struct ib_srq *)my_qp;
+
+ /* copy back return values */
+ srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr;
+ srq_init_attr->attr.max_sge = qp_init_attr.cap.max_recv_sge;
+
+ /* drive SRQ into RTR state */
+ mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+ if (!mqpcb) {
+ ehca_err(pd->device, "Could not get zeroed page for mqpcb "
+ "ehca_qp=%p qp_num=%x ", my_qp, my_qp->real_qp_num);
+ ret = ERR_PTR(-ENOMEM);
+ goto create_srq1;
+ }
+
+ mqpcb->qp_state = EHCA_QPS_INIT;
+ mqpcb->prim_phys_port = 1;
+ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
+ hret = hipz_h_modify_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ update_mask,
+ mqpcb, my_qp->galpas.kernel);
+ if (hret != H_SUCCESS) {
+ ehca_err(pd->device, "Could not modify SRQ to INIT"
+ "ehca_qp=%p qp_num=%x hret=%lx",
+ my_qp, my_qp->real_qp_num, hret);
+ goto create_srq2;
+ }
+
+ mqpcb->qp_enable = 1;
+ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_ENABLE, 1);
+ hret = hipz_h_modify_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ update_mask,
+ mqpcb, my_qp->galpas.kernel);
+ if (hret != H_SUCCESS) {
+ ehca_err(pd->device, "Could not enable SRQ"
+ "ehca_qp=%p qp_num=%x hret=%lx",
+ my_qp, my_qp->real_qp_num, hret);
+ goto create_srq2;
+ }
+
+ mqpcb->qp_state = EHCA_QPS_RTR;
+ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
+ hret = hipz_h_modify_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ update_mask,
+ mqpcb, my_qp->galpas.kernel);
+ if (hret != H_SUCCESS) {
+ ehca_err(pd->device, "Could not modify SRQ to RTR"
+ "ehca_qp=%p qp_num=%x hret=%lx",
+ my_qp, my_qp->real_qp_num, hret);
+ goto create_srq2;
+ }
+
+ return &my_qp->ib_srq;
+
+create_srq2:
+ ret = ERR_PTR(ehca2ib_return_code(hret));
+ ehca_free_fw_ctrlblock(mqpcb);
+
+create_srq1:
+ internal_destroy_qp(pd->device, my_qp, my_qp->ib_srq.uobject);
+
+ return ret;
+}
+
/*
* prepare_sqe_rts called by internal_modify_qp() at trans sqe -> rts
* set purge bit of bad wqe and subsequent wqes to avoid reentering sqe
@@ -707,7 +909,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
my_qp, qp_num, h_ret);
return ehca2ib_return_code(h_ret);
}
- bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
+ bad_send_wqe_p = (void *)((u64)bad_send_wqe_p & (~(1L << 63)));
ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
qp_num, bad_send_wqe_p);
/* convert wqe pointer to vadr */
@@ -722,7 +924,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
}
/* loop sets wqe's purge bit */
- wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+ 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)
@@ -730,7 +932,7 @@ static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
wqe->nr_of_data_seg = 0; /* suppress data access */
wqe->wqef = WQEF_PURGE; /* WQE to be purged */
q_ofs = ipz_queue_advance_offset(squeue, q_ofs);
- wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+ wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
*bad_wqe_cnt = (*bad_wqe_cnt)+1;
}
/*
@@ -765,7 +967,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
u64 h_ret;
int bad_wqe_cnt = 0;
int squeue_locked = 0;
- unsigned long spl_flags = 0;
+ unsigned long flags = 0;
/* do query_qp to obtain current attr values */
mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
@@ -835,7 +1037,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
goto modify_qp_exit1;
}
- ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x "
+ ehca_dbg(ibqp->device, "ehca_qp=%p qp_num=%x current qp_state=%x "
"new qp_state=%x attribute_mask=%x",
my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
@@ -851,7 +1053,8 @@ static int internal_modify_qp(struct ib_qp *ibqp,
goto modify_qp_exit1;
}
- if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
+ mqpcb->qp_state = ib2ehca_qp_state(qp_new_state);
+ if (mqpcb->qp_state)
update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
else {
ret = -EINVAL;
@@ -886,6 +1089,17 @@ static int internal_modify_qp(struct ib_qp *ibqp,
"ehca_qp=%p qp_num=%x <VALID STATE CHANGE> qp_state_xsit=%x",
my_qp, ibqp->qp_num, statetrans);
+ /* eHCA2 rev2 and higher require the SEND_GRH_FLAG to be set
+ * in non-LL UD QPs.
+ */
+ if ((my_qp->qp_type == IB_QPT_UD) &&
+ (my_qp->ext_type != EQPT_LLQP) &&
+ (statetrans == IB_QPST_INIT2RTR) &&
+ (shca->hw_level >= 0x22)) {
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG, 1);
+ mqpcb->send_grh_flag = 1;
+ }
+
/* sqe -> rts: set purge bit of bad wqe before actual trans */
if ((my_qp->qp_type == IB_QPT_UD ||
my_qp->qp_type == IB_QPT_GSI ||
@@ -895,10 +1109,10 @@ static int internal_modify_qp(struct ib_qp *ibqp,
if (!ibqp->uobject) {
struct ehca_wqe *wqe;
/* lock send queue */
- spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
+ spin_lock_irqsave(&my_qp->spinlock_s, flags);
squeue_locked = 1;
/* mark next free wqe */
- wqe = (struct ehca_wqe*)
+ wqe = (struct ehca_wqe *)
ipz_qeit_get(&my_qp->ipz_squeue);
wqe->optype = wqe->wqef = 0xff;
ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
@@ -1133,7 +1347,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
- "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num);
+ "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
goto modify_qp_exit2;
}
@@ -1181,7 +1395,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
modify_qp_exit2:
if (squeue_locked) { /* this means: sqe -> rts */
- spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
+ spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
my_qp->sqerr_purgeflag = 1;
}
@@ -1232,7 +1446,7 @@ int ehca_query_qp(struct ib_qp *qp,
}
if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
- ehca_err(qp->device,"Invalid attribute mask "
+ ehca_err(qp->device, "Invalid attribute mask "
"ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
my_qp, qp->qp_num, qp_attr_mask);
return -EINVAL;
@@ -1240,7 +1454,7 @@ int ehca_query_qp(struct ib_qp *qp,
qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
if (!qpcb) {
- ehca_err(qp->device,"Out of memory for qpcb "
+ ehca_err(qp->device, "Out of memory for qpcb "
"ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
return -ENOMEM;
}
@@ -1252,7 +1466,7 @@ int ehca_query_qp(struct ib_qp *qp,
if (h_ret != H_SUCCESS) {
ret = ehca2ib_return_code(h_ret);
- ehca_err(qp->device,"hipz_h_query_qp() failed "
+ ehca_err(qp->device, "hipz_h_query_qp() failed "
"ehca_qp=%p qp_num=%x h_ret=%lx",
my_qp, qp->qp_num, h_ret);
goto query_qp_exit1;
@@ -1263,7 +1477,7 @@ int ehca_query_qp(struct ib_qp *qp,
if (qp_attr->cur_qp_state == -EINVAL) {
ret = -EINVAL;
- ehca_err(qp->device,"Got invalid ehca_qp_state=%x "
+ ehca_err(qp->device, "Got invalid ehca_qp_state=%x "
"ehca_qp=%p qp_num=%x",
qpcb->qp_state, my_qp, qp->qp_num);
goto query_qp_exit1;
@@ -1312,6 +1526,9 @@ int ehca_query_qp(struct ib_qp *qp,
qp_attr->alt_port_num = qpcb->alt_phys_port;
qp_attr->alt_timeout = qpcb->timeout_al;
+ qp_attr->max_dest_rd_atomic = qpcb->rdma_nr_atomic_resp_res;
+ qp_attr->max_rd_atomic = qpcb->rdma_atomic_outst_dest_qp;
+
/* primary av */
qp_attr->ah_attr.sl = qpcb->service_level;
@@ -1367,53 +1584,170 @@ query_qp_exit1:
return ret;
}
-int ehca_destroy_qp(struct ib_qp *ibqp)
+int ehca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
{
- struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
- struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
+ struct ehca_qp *my_qp =
+ container_of(ibsrq, struct ehca_qp, ib_srq);
+ struct ehca_pd *my_pd =
+ container_of(ibsrq->pd, struct ehca_pd, ib_pd);
+ struct ehca_shca *shca =
+ container_of(ibsrq->pd->device, struct ehca_shca, ib_device);
+ struct hcp_modify_qp_control_block *mqpcb;
+ u64 update_mask;
+ u64 h_ret;
+ int ret = 0;
+
+ u32 cur_pid = current->tgid;
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(ibsrq->pd->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ mqpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+ if (!mqpcb) {
+ ehca_err(ibsrq->device, "Could not get zeroed page for mqpcb "
+ "ehca_qp=%p qp_num=%x ", my_qp, my_qp->real_qp_num);
+ return -ENOMEM;
+ }
+
+ update_mask = 0;
+ if (attr_mask & IB_SRQ_LIMIT) {
+ attr_mask &= ~IB_SRQ_LIMIT;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_CURR_SRQ_LIMIT, 1)
+ | EHCA_BMASK_SET(MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG, 1);
+ mqpcb->curr_srq_limit =
+ EHCA_BMASK_SET(MQPCB_CURR_SRQ_LIMIT, attr->srq_limit);
+ mqpcb->qp_aff_asyn_ev_log_reg =
+ EHCA_BMASK_SET(QPX_AAELOG_RESET_SRQ_LIMIT, 1);
+ }
+
+ /* by now, all bits in attr_mask should have been cleared */
+ if (attr_mask) {
+ ehca_err(ibsrq->device, "invalid attribute mask bits set "
+ "attr_mask=%x", attr_mask);
+ ret = -EINVAL;
+ goto modify_srq_exit0;
+ }
+
+ if (ehca_debug_level)
+ 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,
+ NULL, update_mask, mqpcb,
+ my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ ehca_err(ibsrq->device, "hipz_h_modify_qp() failed rc=%lx "
+ "ehca_qp=%p qp_num=%x",
+ h_ret, my_qp, my_qp->real_qp_num);
+ }
+
+modify_srq_exit0:
+ ehca_free_fw_ctrlblock(mqpcb);
+
+ return ret;
+}
+
+int ehca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr)
+{
+ struct ehca_qp *my_qp = container_of(srq, struct ehca_qp, ib_srq);
+ struct ehca_pd *my_pd = container_of(srq->pd, struct ehca_pd, ib_pd);
+ struct ehca_shca *shca = container_of(srq->device, struct ehca_shca,
ib_device);
+ struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
+ struct hcp_modify_qp_control_block *qpcb;
+ u32 cur_pid = current->tgid;
+ int ret = 0;
+ u64 h_ret;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(srq->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
+ if (!qpcb) {
+ ehca_err(srq->device, "Out of memory for qpcb "
+ "ehca_qp=%p qp_num=%x", my_qp, my_qp->real_qp_num);
+ return -ENOMEM;
+ }
+
+ h_ret = hipz_h_query_qp(adapter_handle, my_qp->ipz_qp_handle,
+ NULL, qpcb, my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ ehca_err(srq->device, "hipz_h_query_qp() failed "
+ "ehca_qp=%p qp_num=%x h_ret=%lx",
+ my_qp, my_qp->real_qp_num, h_ret);
+ goto query_srq_exit1;
+ }
+
+ srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1;
+ srq_attr->srq_limit = EHCA_BMASK_GET(
+ MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit);
+
+ if (ehca_debug_level)
+ ehca_dmp(qpcb, 4*70, "qp_num=%x", my_qp->real_qp_num);
+
+query_srq_exit1:
+ ehca_free_fw_ctrlblock(qpcb);
+
+ return ret;
+}
+
+static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+ struct ib_uobject *uobject)
+{
+ struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
ib_pd);
u32 cur_pid = current->tgid;
- u32 qp_num = ibqp->qp_num;
+ u32 qp_num = my_qp->real_qp_num;
int ret;
u64 h_ret;
u8 port_num;
enum ib_qp_type qp_type;
unsigned long flags;
- if (ibqp->uobject) {
+ if (uobject) {
if (my_qp->mm_count_galpa ||
my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
- ehca_err(ibqp->device, "Resources still referenced in "
- "user space qp_num=%x", ibqp->qp_num);
+ ehca_err(dev, "Resources still referenced in "
+ "user space qp_num=%x", qp_num);
return -EINVAL;
}
if (my_pd->ownpid != cur_pid) {
- ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
+ ehca_err(dev, "Invalid caller pid=%x ownpid=%x",
cur_pid, my_pd->ownpid);
return -EINVAL;
}
}
if (my_qp->send_cq) {
- ret = ehca_cq_unassign_qp(my_qp->send_cq,
- my_qp->real_qp_num);
+ ret = ehca_cq_unassign_qp(my_qp->send_cq, qp_num);
if (ret) {
- ehca_err(ibqp->device, "Couldn't unassign qp from "
+ ehca_err(dev, "Couldn't unassign qp from "
"send_cq ret=%x qp_num=%x cq_num=%x", ret,
- my_qp->ib_qp.qp_num, my_qp->send_cq->cq_number);
+ qp_num, my_qp->send_cq->cq_number);
return ret;
}
}
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ write_lock_irqsave(&ehca_qp_idr_lock, flags);
idr_remove(&ehca_qp_idr, my_qp->token);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
- ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
+ ehca_err(dev, "hipz_h_destroy_qp() failed rc=%lx "
"ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
return ehca2ib_return_code(h_ret);
}
@@ -1424,7 +1758,7 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
/* no support for IB_QPT_SMI yet */
if (qp_type == IB_QPT_GSI) {
struct ib_event event;
- ehca_info(ibqp->device, "device %s: port %x is inactive.",
+ ehca_info(dev, "device %s: port %x is inactive.",
shca->ib_device.name, port_num);
event.device = &shca->ib_device;
event.event = IB_EVENT_PORT_ERR;
@@ -1433,18 +1767,34 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
ib_dispatch_event(&event);
}
- ipz_queue_dtor(&my_qp->ipz_rqueue);
- ipz_queue_dtor(&my_qp->ipz_squeue);
+ if (HAS_RQ(my_qp))
+ ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
+ if (HAS_SQ(my_qp))
+ ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
kmem_cache_free(qp_cache, my_qp);
return 0;
}
+int ehca_destroy_qp(struct ib_qp *qp)
+{
+ return internal_destroy_qp(qp->device,
+ container_of(qp, struct ehca_qp, ib_qp),
+ qp->uobject);
+}
+
+int ehca_destroy_srq(struct ib_srq *srq)
+{
+ return internal_destroy_qp(srq->device,
+ container_of(srq, struct ehca_qp, ib_srq),
+ srq->uobject);
+}
+
int ehca_init_qp_cache(void)
{
qp_cache = kmem_cache_create("ehca_cache_qp",
sizeof(struct ehca_qp), 0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!qp_cache)
return -ENOMEM;
return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index caec9dee09e1..94eed70fedf5 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -3,8 +3,9 @@
*
* post_send/recv, poll_cq, req_notify
*
- * Authors: Waleri Fomin <fomin@de.ibm.com>
- * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ * Joachim Fenkes <fenkes@de.ibm.com>
* Reinhard Ernst <rernst@de.ibm.com>
*
* Copyright (c) 2005 IBM Corporation
@@ -78,7 +79,8 @@ static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
}
if (ehca_debug_level) {
- ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
+ 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");
}
@@ -98,7 +100,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
struct ib_sge *sge = send_wr->sg_list;
ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
- "send_flags=%x opcode=%x",idx, send_wr->wr_id,
+ "send_flags=%x opcode=%x", idx, send_wr->wr_id,
send_wr->num_sge, send_wr->send_flags,
send_wr->opcode);
if (mad_hdr) {
@@ -115,7 +117,7 @@ static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
mad_hdr->attr_mod);
}
for (j = 0; j < send_wr->num_sge; j++) {
- u8 *data = (u8 *) abs_to_virt(sge->addr);
+ u8 *data = (u8 *)abs_to_virt(sge->addr);
ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
"lkey=%x",
idx, j, data, sge->length, sge->lkey);
@@ -362,10 +364,10 @@ int ehca_post_send(struct ib_qp *qp,
struct ehca_wqe *wqe_p;
int wqe_cnt = 0;
int ret = 0;
- unsigned long spl_flags;
+ unsigned long flags;
/* LOCK the QUEUE */
- spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
+ spin_lock_irqsave(&my_qp->spinlock_s, flags);
/* loop processes list of send reqs */
for (cur_send_wr = send_wr; cur_send_wr != NULL;
@@ -406,26 +408,31 @@ int ehca_post_send(struct ib_qp *qp,
} /* eof for cur_send_wr */
post_send_exit0:
- /* UNLOCK the QUEUE */
- spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
iosync(); /* serialize GAL register access */
hipz_update_sqa(my_qp, wqe_cnt);
+ spin_unlock_irqrestore(&my_qp->spinlock_s, flags);
return ret;
}
-int ehca_post_recv(struct ib_qp *qp,
- struct ib_recv_wr *recv_wr,
- struct ib_recv_wr **bad_recv_wr)
+static int internal_post_recv(struct ehca_qp *my_qp,
+ struct ib_device *dev,
+ struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr)
{
- struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
struct ib_recv_wr *cur_recv_wr;
struct ehca_wqe *wqe_p;
int wqe_cnt = 0;
int ret = 0;
- unsigned long spl_flags;
+ unsigned long flags;
+
+ if (unlikely(!HAS_RQ(my_qp))) {
+ ehca_err(dev, "QP has no RQ ehca_qp=%p qp_num=%x ext_type=%d",
+ my_qp, my_qp->real_qp_num, my_qp->ext_type);
+ return -ENODEV;
+ }
/* LOCK the QUEUE */
- spin_lock_irqsave(&my_qp->spinlock_r, spl_flags);
+ spin_lock_irqsave(&my_qp->spinlock_r, flags);
/* loop processes list of send reqs */
for (cur_recv_wr = recv_wr; cur_recv_wr != NULL;
@@ -439,8 +446,8 @@ int ehca_post_recv(struct ib_qp *qp,
*bad_recv_wr = cur_recv_wr;
if (wqe_cnt == 0) {
ret = -ENOMEM;
- ehca_err(qp->device, "Too many posted WQEs "
- "qp_num=%x", qp->qp_num);
+ ehca_err(dev, "Too many posted WQEs "
+ "qp_num=%x", my_qp->real_qp_num);
}
goto post_recv_exit0;
}
@@ -455,23 +462,39 @@ int ehca_post_recv(struct ib_qp *qp,
*bad_recv_wr = cur_recv_wr;
if (wqe_cnt == 0) {
ret = -EINVAL;
- ehca_err(qp->device, "Could not write WQE "
- "qp_num=%x", qp->qp_num);
+ ehca_err(dev, "Could not write WQE "
+ "qp_num=%x", my_qp->real_qp_num);
}
goto post_recv_exit0;
}
wqe_cnt++;
- ehca_gen_dbg("ehca_qp=%p qp_num=%x wqe_cnt=%d",
- my_qp, qp->qp_num, 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:
- spin_unlock_irqrestore(&my_qp->spinlock_r, spl_flags);
iosync(); /* serialize GAL register access */
hipz_update_rqa(my_qp, wqe_cnt);
+ spin_unlock_irqrestore(&my_qp->spinlock_r, flags);
return ret;
}
+int ehca_post_recv(struct ib_qp *qp,
+ struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr)
+{
+ return internal_post_recv(container_of(qp, struct ehca_qp, ib_qp),
+ qp->device, recv_wr, bad_recv_wr);
+}
+
+int ehca_post_srq_recv(struct ib_srq *srq,
+ struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr)
+{
+ return internal_post_recv(container_of(srq, struct ehca_qp, ib_srq),
+ srq->device, recv_wr, bad_recv_wr);
+}
+
/*
* ib_wc_opcode table converts ehca wc opcode to ib
* Since we use zero to indicate invalid opcode, the actual ib opcode must
@@ -494,6 +517,7 @@ static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
int ret = 0;
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;
poll_cq_one_read_cqe:
@@ -511,9 +535,11 @@ poll_cq_one_read_cqe:
cqe_count++;
if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
- struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
+ struct ehca_qp *qp;
int purgeflag;
- unsigned long spl_flags;
+ unsigned long flags;
+
+ qp = ehca_cq_get_qp(my_cq, cqe->local_qp_number);
if (!qp) {
ehca_err(cq->device, "cq_num=%x qp_num=%x "
"could not find qp -> ignore cqe",
@@ -523,13 +549,13 @@ poll_cq_one_read_cqe:
/* ignore this purged cqe */
goto poll_cq_one_read_cqe;
}
- spin_lock_irqsave(&qp->spinlock_s, spl_flags);
+ spin_lock_irqsave(&qp->spinlock_s, flags);
purgeflag = qp->sqerr_purgeflag;
- spin_unlock_irqrestore(&qp->spinlock_s, spl_flags);
+ spin_unlock_irqrestore(&qp->spinlock_s, flags);
if (purgeflag) {
- ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x "
- "src_qp=%x",
+ 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)
ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
@@ -545,7 +571,7 @@ poll_cq_one_read_cqe:
}
/* tracing cqe */
- if (ehca_debug_level) {
+ if (unlikely(ehca_debug_level)) {
ehca_dbg(cq->device,
"Received COMPLETION ehca_cq=%p cq_num=%x -----",
my_cq, my_cq->cq_number);
@@ -579,7 +605,11 @@ poll_cq_one_read_cqe:
} else
wc->status = IB_WC_SUCCESS;
- wc->qp = NULL;
+ read_lock(&ehca_qp_idr_lock);
+ my_qp = idr_find(&ehca_qp_idr, cqe->qp_token);
+ wc->qp = &my_qp->ib_qp;
+ read_unlock(&ehca_qp_idr_lock);
+
wc->byte_len = cqe->nr_bytes_transferred;
wc->pkey_index = cqe->pkey_index;
wc->slid = cqe->rlid;
@@ -589,7 +619,7 @@ poll_cq_one_read_cqe:
wc->imm_data = cpu_to_be32(cqe->immediate_data);
wc->sl = cqe->service_level;
- if (wc->status != IB_WC_SUCCESS)
+ 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 "
@@ -610,7 +640,7 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
int nr;
struct ib_wc *current_wc = wc;
int ret = 0;
- unsigned long spl_flags;
+ unsigned long flags;
if (num_entries < 1) {
ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p "
@@ -619,14 +649,14 @@ int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
goto poll_cq_exit0;
}
- spin_lock_irqsave(&my_cq->spinlock, spl_flags);
+ spin_lock_irqsave(&my_cq->spinlock, flags);
for (nr = 0; nr < num_entries; nr++) {
ret = ehca_poll_cq_one(cq, current_wc);
if (ret)
break;
current_wc++;
} /* eof for nr */
- spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
+ spin_unlock_irqrestore(&my_cq->spinlock, flags);
if (ret == -EAGAIN || !ret)
ret = nr;
@@ -637,7 +667,6 @@ poll_cq_exit0:
int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags)
{
struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
- unsigned long spl_flags;
int ret = 0;
switch (notify_flags & IB_CQ_SOLICITED_MASK) {
@@ -652,6 +681,7 @@ int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags notify_flags)
}
if (notify_flags & IB_CQ_REPORT_MISSED_EVENTS) {
+ unsigned long spl_flags;
spin_lock_irqsave(&my_cq->spinlock, spl_flags);
ret = ipz_qeit_is_valid(&my_cq->ipz_queue);
spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
index 973c4b591545..57c77a715f46 100644
--- a/drivers/infiniband/hw/ehca/ehca_tools.h
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -59,6 +59,7 @@
#include <linux/cpu.h>
#include <linux/device.h>
+#include <asm/atomic.h>
#include <asm/abs_addr.h>
#include <asm/ibmebus.h>
#include <asm/io.h>
@@ -92,14 +93,14 @@ extern int ehca_debug_level;
#define ehca_gen_dbg(format, arg...) \
do { \
if (unlikely(ehca_debug_level)) \
- printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\
+ printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \
get_paca()->paca_index, __FUNCTION__, ## arg); \
} while (0)
#define ehca_gen_warn(format, arg...) \
do { \
if (unlikely(ehca_debug_level)) \
- printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\
+ printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
get_paca()->paca_index, __FUNCTION__, ## arg); \
} while (0)
@@ -113,12 +114,12 @@ extern int ehca_debug_level;
* <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
*/
#define ehca_dmp(adr, len, format, args...) \
- do { \
- unsigned int x; \
+ do { \
+ unsigned int x; \
unsigned int l = (unsigned int)(len); \
- unsigned char *deb = (unsigned char*)(adr); \
+ unsigned char *deb = (unsigned char *)(adr); \
for (x = 0; x < l; x += 16) { \
- printk("EHCA_DMP:%s " format \
+ printk(KERN_INFO "EHCA_DMP:%s " format \
" adr=%p ofs=%04x %016lx %016lx\n", \
__FUNCTION__, ##args, deb, x, \
*((u64 *)&deb[0]), *((u64 *)&deb[8])); \
@@ -127,16 +128,16 @@ extern int ehca_debug_level;
} while (0)
/* define a bitmask, little endian version */
-#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+#define EHCA_BMASK(pos, length) (((pos) << 16) + (length))
/* define a bitmask, the ibm way... */
-#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+#define EHCA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
/* internal function, don't use */
-#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
/* internal function, don't use */
-#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+#define EHCA_BMASK_MASK(mask) (~0ULL >> ((64 - (mask)) & 0xffff))
/**
* EHCA_BMASK_SET - return value shifted and masked by mask
@@ -144,30 +145,16 @@ extern int ehca_debug_level;
* variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
* in variable
*/
-#define EHCA_BMASK_SET(mask,value) \
- ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+#define EHCA_BMASK_SET(mask, value) \
+ ((EHCA_BMASK_MASK(mask) & ((u64)(value))) << EHCA_BMASK_SHIFTPOS(mask))
/**
* EHCA_BMASK_GET - extract a parameter from value by mask
*/
-#define EHCA_BMASK_GET(mask,value) \
- (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
-
+#define EHCA_BMASK_GET(mask, value) \
+ (EHCA_BMASK_MASK(mask) & (((u64)(value)) >> EHCA_BMASK_SHIFTPOS(mask)))
/* Converts ehca to ib return code */
-static inline int ehca2ib_return_code(u64 ehca_rc)
-{
- switch (ehca_rc) {
- case H_SUCCESS:
- return 0;
- case H_BUSY:
- return -EBUSY;
- case H_NO_MEM:
- return -ENOMEM;
- default:
- return -EINVAL;
- }
-}
-
+int ehca2ib_return_code(u64 ehca_rc);
#endif /* EHCA_TOOLS_H */
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index 73db920b6945..4bc687fdf531 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -70,7 +70,7 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
static void ehca_mm_open(struct vm_area_struct *vma)
{
- u32 *count = (u32*)vma->vm_private_data;
+ u32 *count = (u32 *)vma->vm_private_data;
if (!count) {
ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
vma->vm_start, vma->vm_end);
@@ -86,7 +86,7 @@ static void ehca_mm_open(struct vm_area_struct *vma)
static void ehca_mm_close(struct vm_area_struct *vma)
{
- u32 *count = (u32*)vma->vm_private_data;
+ u32 *count = (u32 *)vma->vm_private_data;
if (!count) {
ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
vma->vm_start, vma->vm_end);
@@ -149,7 +149,7 @@ static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
ehca_gen_err("vm_insert_page() failed rc=%x", ret);
return ret;
}
- start += PAGE_SIZE;
+ start += PAGE_SIZE;
}
vma->vm_private_data = mm_count;
(*mm_count)++;
@@ -215,7 +215,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
case 2: /* qp rqueue_addr */
ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
qp->ib_qp.qp_num);
- ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+ ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
+ &qp->mm_count_rqueue);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
"ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
@@ -227,7 +228,8 @@ static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
case 3: /* qp squeue_addr */
ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
qp->ib_qp.qp_num);
- ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+ ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
+ &qp->mm_count_squeue);
if (unlikely(ret)) {
ehca_err(qp->ib_qp.device,
"ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
@@ -253,16 +255,16 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
u32 cur_pid = current->tgid;
u32 ret;
- unsigned long flags;
struct ehca_cq *cq;
struct ehca_qp *qp;
struct ehca_pd *pd;
+ struct ib_uobject *uobject;
switch (q_type) {
case 1: /* CQ */
- spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ read_lock(&ehca_cq_idr_lock);
cq = idr_find(&ehca_cq_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+ read_unlock(&ehca_cq_idr_lock);
/* make sure this mmap really belongs to the authorized user */
if (!cq)
@@ -288,9 +290,9 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
break;
case 2: /* QP */
- spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ read_lock(&ehca_qp_idr_lock);
qp = idr_find(&ehca_qp_idr, idr_handle);
- spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ read_unlock(&ehca_qp_idr_lock);
/* make sure this mmap really belongs to the authorized user */
if (!qp)
@@ -304,7 +306,8 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
return -ENOMEM;
}
- if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
+ uobject = IS_SRQ(qp) ? qp->ib_srq.uobject : qp->ib_qp.uobject;
+ if (!uobject || uobject->context != context)
return -EINVAL;
ret = ehca_mmap_qp(vma, qp, rsrc_type);
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 5766ae3a2029..fdbfebea7d11 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -5,6 +5,7 @@
*
* Authors: Christoph Raisch <raisch@de.ibm.com>
* Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Joachim Fenkes <fenkes@de.ibm.com>
* Gerd Bayer <gerd.bayer@de.ibm.com>
* Waleri Fomin <fomin@de.ibm.com>
*
@@ -51,10 +52,13 @@
#define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11)
#define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12)
#define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_STORAGE EHCA_BMASK_IBM(16, 17)
#define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18)
#define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21)
#define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23)
#define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31)
+#define H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE EHCA_BMASK_IBM(32, 35)
+#define H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE EHCA_BMASK_IBM(36, 39)
#define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63)
#define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15)
@@ -62,6 +66,12 @@
#define H_ALL_RES_QP_MAX_SEND_SGE EHCA_BMASK_IBM(32, 39)
#define H_ALL_RES_QP_MAX_RECV_SGE EHCA_BMASK_IBM(40, 47)
+#define H_ALL_RES_QP_UD_AV_LKEY EHCA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SRQ_QP_TOKEN EHCA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SRQ_QP_HANDLE EHCA_BMASK_IBM(0, 64)
+#define H_ALL_RES_QP_SRQ_LIMIT EHCA_BMASK_IBM(48, 63)
+#define H_ALL_RES_QP_SRQ_QPN EHCA_BMASK_IBM(40, 63)
+
#define H_ALL_RES_QP_ACT_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31)
#define H_ALL_RES_QP_ACT_OUTST_RECV_WR EHCA_BMASK_IBM(48, 63)
#define H_ALL_RES_QP_ACT_SEND_SGE EHCA_BMASK_IBM(8, 15)
@@ -74,10 +84,7 @@
#define H_MP_SHUTDOWN EHCA_BMASK_IBM(48, 48)
#define H_MP_RESET_QKEY_CTR EHCA_BMASK_IBM(49, 49)
-/* direct access qp controls */
-#define DAQP_CTRL_ENABLE 0x01
-#define DAQP_CTRL_SEND_COMP 0x20
-#define DAQP_CTRL_RECV_COMP 0x40
+static DEFINE_SPINLOCK(hcall_lock);
static u32 get_longbusy_msecs(int longbusy_rc)
{
@@ -155,7 +162,7 @@ static long ehca_plpar_hcall9(unsigned long opcode,
{
long ret;
int i, sleep_msecs, lock_is_set = 0;
- unsigned long flags;
+ unsigned long flags = 0;
ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
"arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
@@ -284,68 +291,73 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
}
u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
- struct ehca_qp *qp,
struct ehca_alloc_qp_parms *parms)
{
u64 ret;
- u64 allocate_controls;
- u64 max_r10_reg;
+ u64 allocate_controls, max_r10_reg, r11, r12;
u64 outs[PLPAR_HCALL9_BUFSIZE];
- u16 max_nr_receive_wqes = qp->init_attr.cap.max_recv_wr + 1;
- u16 max_nr_send_wqes = qp->init_attr.cap.max_send_wr + 1;
- int daqp_ctrl = parms->daqp_ctrl;
allocate_controls =
- EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS,
- (daqp_ctrl & DAQP_CTRL_ENABLE) ? 1 : 0)
+ EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS, parms->ext_type)
| EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
| EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
| EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_STORAGE, parms->qp_storage)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE,
+ parms->squeue.page_size)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE,
+ parms->rqueue.page_size)
| EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
- (daqp_ctrl & DAQP_CTRL_RECV_COMP) ? 1 : 0)
+ !!(parms->ll_comp_flags & LLQP_RECV_COMP))
| EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
- (daqp_ctrl & DAQP_CTRL_SEND_COMP) ? 1 : 0)
+ !!(parms->ll_comp_flags & LLQP_SEND_COMP))
| EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL,
parms->ud_av_l_key_ctl)
| EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1);
max_r10_reg =
EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
- max_nr_send_wqes)
+ parms->squeue.max_wr + 1)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
- max_nr_receive_wqes)
+ parms->rqueue.max_wr + 1)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
- parms->max_send_sge)
+ parms->squeue.max_sge)
| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
- parms->max_recv_sge);
+ parms->rqueue.max_sge);
+
+ r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token);
+
+ if (parms->ext_type == EQPT_SRQ)
+ r12 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_LIMIT, parms->srq_limit);
+ else
+ r12 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QPN, parms->srq_qpn);
ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
adapter_handle.handle, /* r4 */
allocate_controls, /* r5 */
- qp->send_cq->ipz_cq_handle.handle,
- qp->recv_cq->ipz_cq_handle.handle,
- parms->ipz_eq_handle.handle,
- ((u64)qp->token << 32) | parms->pd.value,
- max_r10_reg, /* r10 */
- parms->ud_av_l_key_ctl, /* r11 */
- 0);
- qp->ipz_qp_handle.handle = outs[0];
- qp->real_qp_num = (u32)outs[1];
- parms->act_nr_send_wqes =
+ parms->send_cq_handle.handle,
+ parms->recv_cq_handle.handle,
+ parms->eq_handle.handle,
+ ((u64)parms->token << 32) | parms->pd.value,
+ max_r10_reg, r11, r12);
+
+ parms->qp_handle.handle = outs[0];
+ parms->real_qp_num = (u32)outs[1];
+ parms->squeue.act_nr_wqes =
(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
- parms->act_nr_recv_wqes =
+ parms->rqueue.act_nr_wqes =
(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
- parms->act_nr_send_sges =
+ parms->squeue.act_nr_sges =
(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
- parms->act_nr_recv_sges =
+ parms->rqueue.act_nr_sges =
(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
- parms->nr_sq_pages =
+ parms->squeue.queue_size =
(u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
- parms->nr_rq_pages =
+ parms->rqueue.queue_size =
(u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
if (ret == H_SUCCESS)
- hcp_galpas_ctor(&qp->galpas, outs[6], outs[6]);
+ hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]);
if (ret == H_NOT_ENOUGH_RESOURCES)
ehca_gen_err("Not enough resources. ret=%lx", ret);
@@ -423,7 +435,8 @@ u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
{
return ehca_plpar_hcall_norets(H_REGISTER_RPAGES,
adapter_handle.handle, /* r4 */
- queue_type | pagesize << 8, /* r5 */
+ (u64)queue_type | ((u64)pagesize) << 8,
+ /* r5 */
resource_handle, /* r6 */
logical_address_of_page, /* r7 */
count, /* r8 */
@@ -492,13 +505,13 @@ u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
const u64 count,
const struct h_galpa galpa)
{
- if (count != 1) {
+ if (count > 1) {
ehca_gen_err("Page counter=%lx", count);
return H_PARAMETER;
}
- return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
- qp_handle.handle,logical_address_of_page,
+ return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
+ qp_handle.handle, logical_address_of_page,
count);
}
@@ -518,9 +531,9 @@ u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
qp_handle.handle, /* r6 */
0, 0, 0, 0, 0, 0);
if (log_addr_next_sq_wqe2processed)
- *log_addr_next_sq_wqe2processed = (void*)outs[0];
+ *log_addr_next_sq_wqe2processed = (void *)outs[0];
if (log_addr_next_rq_wqe2processed)
- *log_addr_next_rq_wqe2processed = (void*)outs[1];
+ *log_addr_next_rq_wqe2processed = (void *)outs[1];
return ret;
}
@@ -720,6 +733,9 @@ 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 */
@@ -742,8 +758,22 @@ u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
const u64 logical_address_of_page,
const u64 count)
{
+ extern int ehca_debug_level;
u64 ret;
+ if (unlikely(ehca_debug_level >= 2)) {
+ if (count > 1) {
+ u64 *kpage;
+ int i;
+ kpage = (u64 *)abs_to_virt(logical_address_of_page);
+ for (i = 0; i < count; i++)
+ ehca_gen_dbg("kpage[%d]=%p",
+ i, (void *)kpage[i]);
+ } else
+ ehca_gen_dbg("kpage=%p",
+ (void *)logical_address_of_page);
+ }
+
if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
ehca_gen_err("logical_address_of_page not on a 4k boundary "
"adapter_handle=%lx mr=%p mr_handle=%lx "
diff --git a/drivers/infiniband/hw/ehca/hcp_if.h b/drivers/infiniband/hw/ehca/hcp_if.h
index 2869f7dd6196..60ce02b70663 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.h
+++ b/drivers/infiniband/hw/ehca/hcp_if.h
@@ -78,7 +78,6 @@ u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
* initialize resources, create empty QPPTs (2 rings).
*/
u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
- struct ehca_qp *qp,
struct ehca_alloc_qp_parms *parms);
u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c
index 0b1a4772c78a..214821095cb1 100644
--- a/drivers/infiniband/hw/ehca/hcp_phyp.c
+++ b/drivers/infiniband/hw/ehca/hcp_phyp.c
@@ -50,7 +50,7 @@ int hcall_map_page(u64 physaddr, u64 *mapaddr)
int hcall_unmap_page(u64 mapaddr)
{
- iounmap((volatile void __iomem*)mapaddr);
+ iounmap((volatile void __iomem *) mapaddr);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/hipz_fns_core.h b/drivers/infiniband/hw/ehca/hipz_fns_core.h
index 20898a153446..868735fd3187 100644
--- a/drivers/infiniband/hw/ehca/hipz_fns_core.h
+++ b/drivers/infiniband/hw/ehca/hipz_fns_core.h
@@ -53,10 +53,10 @@
#define hipz_galpa_load_cq(gal, offset) \
hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
-#define hipz_galpa_store_qp(gal,offset, value) \
+#define hipz_galpa_store_qp(gal, offset, value) \
hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
#define hipz_galpa_load_qp(gal, offset) \
- hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
+ hipz_galpa_load(gal, QPTEMM_OFFSET(offset))
static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
{
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h
index fad91368dc5a..d9739e554515 100644
--- a/drivers/infiniband/hw/ehca/hipz_hw.h
+++ b/drivers/infiniband/hw/ehca/hipz_hw.h
@@ -161,10 +161,11 @@ struct hipz_qptemm {
/* 0x1000 */
};
-#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
+#define QPX_SQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_RQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3, 3)
-#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
+#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm, x)
/* MRMWPT Entry Memory Map */
struct hipz_mrmwmm {
@@ -186,7 +187,7 @@ struct hipz_mrmwmm {
};
-#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
+#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm, x)
struct hipz_qpedmm {
/* 0x00 */
@@ -237,7 +238,7 @@ struct hipz_qpedmm {
u64 qpedx_rrva3;
};
-#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x)
+#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm, x)
/* CQ Table Entry Memory Map */
struct hipz_cqtemm {
@@ -262,12 +263,12 @@ struct hipz_cqtemm {
/* 0x1000 */
};
-#define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32,63)
-#define CQX_FECADDER EHCA_BMASK_IBM(32,63)
-#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
-#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
+#define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32, 63)
+#define CQX_FECADDER EHCA_BMASK_IBM(32, 63)
+#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0, 0)
+#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0, 0)
-#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
+#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm, x)
/* EQ Table Entry Memory Map */
struct hipz_eqtemm {
@@ -292,7 +293,7 @@ struct hipz_eqtemm {
};
-#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
+#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm, x)
/* access control defines for MR/MW */
#define HIPZ_ACCESSCTRL_L_WRITE 0x00800000
@@ -360,6 +361,24 @@ struct hipz_query_hca {
u32 max_neq;
} __attribute__ ((packed));
+#define HCA_CAP_AH_PORT_NR_CHECK EHCA_BMASK_IBM( 0, 0)
+#define HCA_CAP_ATOMIC EHCA_BMASK_IBM( 1, 1)
+#define HCA_CAP_AUTO_PATH_MIG EHCA_BMASK_IBM( 2, 2)
+#define HCA_CAP_BAD_P_KEY_CTR EHCA_BMASK_IBM( 3, 3)
+#define HCA_CAP_SQD_RTS_PORT_CHANGE EHCA_BMASK_IBM( 4, 4)
+#define HCA_CAP_CUR_QP_STATE_MOD EHCA_BMASK_IBM( 5, 5)
+#define HCA_CAP_INIT_TYPE EHCA_BMASK_IBM( 6, 6)
+#define HCA_CAP_PORT_ACTIVE_EVENT EHCA_BMASK_IBM( 7, 7)
+#define HCA_CAP_Q_KEY_VIOL_CTR EHCA_BMASK_IBM( 8, 8)
+#define HCA_CAP_WQE_RESIZE EHCA_BMASK_IBM( 9, 9)
+#define HCA_CAP_RAW_PACKET_MCAST EHCA_BMASK_IBM(10, 10)
+#define HCA_CAP_SHUTDOWN_PORT EHCA_BMASK_IBM(11, 11)
+#define HCA_CAP_RC_LL_QP EHCA_BMASK_IBM(12, 12)
+#define HCA_CAP_SRQ EHCA_BMASK_IBM(13, 13)
+#define HCA_CAP_UD_LL_QP EHCA_BMASK_IBM(16, 16)
+#define HCA_CAP_RESIZE_MR EHCA_BMASK_IBM(17, 17)
+#define HCA_CAP_MINI_QP EHCA_BMASK_IBM(18, 18)
+
/* query port response block */
struct hipz_query_port {
u32 state;
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
index bf7a40088f61..a090c679c397 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
@@ -40,6 +40,11 @@
#include "ehca_tools.h"
#include "ipz_pt_fn.h"
+#include "ehca_classes.h"
+
+#define PAGES_PER_KPAGE (PAGE_SIZE >> EHCA_PAGESHIFT)
+
+struct kmem_cache *small_qp_cache;
void *ipz_qpageit_get_inc(struct ipz_queue *queue)
{
@@ -49,7 +54,7 @@ void *ipz_qpageit_get_inc(struct ipz_queue *queue)
queue->current_q_offset -= queue->pagesize;
ret = NULL;
}
- if (((u64)ret) % EHCA_PAGESIZE) {
+ if (((u64)ret) % queue->pagesize) {
ehca_gen_err("ERROR!! not at PAGE-Boundary");
return NULL;
}
@@ -83,80 +88,195 @@ int ipz_queue_abs_to_offset(struct ipz_queue *queue, u64 addr, u64 *q_offset)
return -EINVAL;
}
-int ipz_queue_ctor(struct ipz_queue *queue,
- const u32 nr_of_pages,
- const u32 pagesize, const u32 qe_size, const u32 nr_of_sg)
+#if PAGE_SHIFT < EHCA_PAGESHIFT
+#error Kernel pages must be at least as large than eHCA pages (4K) !
+#endif
+
+/*
+ * allocate pages for queue:
+ * outer loop allocates whole kernel pages (page aligned) and
+ * inner loop divides a kernel page into smaller hca queue pages
+ */
+static int alloc_queue_pages(struct ipz_queue *queue, const u32 nr_of_pages)
{
- int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
- int f;
+ int k, f = 0;
+ u8 *kpage;
- if (pagesize > PAGE_SIZE) {
- ehca_gen_err("FATAL ERROR: pagesize=%x is greater "
- "than kernel page size", pagesize);
- return 0;
- }
- if (!pages_per_kpage) {
- ehca_gen_err("FATAL ERROR: invalid kernel page size. "
- "pages_per_kpage=%x", pages_per_kpage);
- return 0;
- }
- queue->queue_length = nr_of_pages * pagesize;
- queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
- if (!queue->queue_pages) {
- ehca_gen_err("ERROR!! didn't get the memory");
- return 0;
- }
- memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
- /*
- * allocate pages for queue:
- * outer loop allocates whole kernel pages (page aligned) and
- * inner loop divides a kernel page into smaller hca queue pages
- */
- f = 0;
while (f < nr_of_pages) {
- u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
- int k;
+ kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
if (!kpage)
- goto ipz_queue_ctor_exit0; /*NOMEM*/
- for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) {
- (queue->queue_pages)[f] = (struct ipz_page *)kpage;
+ goto out;
+
+ for (k = 0; k < PAGES_PER_KPAGE && f < nr_of_pages; k++) {
+ queue->queue_pages[f] = (struct ipz_page *)kpage;
kpage += EHCA_PAGESIZE;
f++;
}
}
+ return 1;
- queue->current_q_offset = 0;
+out:
+ for (f = 0; f < nr_of_pages && queue->queue_pages[f];
+ f += PAGES_PER_KPAGE)
+ free_page((unsigned long)(queue->queue_pages)[f]);
+ return 0;
+}
+
+static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
+{
+ int order = ilog2(queue->pagesize) - 9;
+ struct ipz_small_queue_page *page;
+ unsigned long bit;
+
+ mutex_lock(&pd->lock);
+
+ if (!list_empty(&pd->free[order]))
+ page = list_entry(pd->free[order].next,
+ struct ipz_small_queue_page, list);
+ else {
+ page = kmem_cache_zalloc(small_qp_cache, GFP_KERNEL);
+ if (!page)
+ goto out;
+
+ page->page = get_zeroed_page(GFP_KERNEL);
+ if (!page->page) {
+ kmem_cache_free(small_qp_cache, page);
+ goto out;
+ }
+
+ list_add(&page->list, &pd->free[order]);
+ }
+
+ bit = find_first_zero_bit(page->bitmap, IPZ_SPAGE_PER_KPAGE >> order);
+ __set_bit(bit, page->bitmap);
+ page->fill++;
+
+ if (page->fill == IPZ_SPAGE_PER_KPAGE >> order)
+ list_move(&page->list, &pd->full[order]);
+
+ mutex_unlock(&pd->lock);
+
+ queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9)));
+ queue->small_page = page;
+ return 1;
+
+out:
+ ehca_err(pd->ib_pd.device, "failed to allocate small queue page");
+ return 0;
+}
+
+static void free_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
+{
+ int order = ilog2(queue->pagesize) - 9;
+ struct ipz_small_queue_page *page = queue->small_page;
+ unsigned long bit;
+ int free_page = 0;
+
+ bit = ((unsigned long)queue->queue_pages[0] & PAGE_MASK)
+ >> (order + 9);
+
+ mutex_lock(&pd->lock);
+
+ __clear_bit(bit, page->bitmap);
+ page->fill--;
+
+ if (page->fill == 0) {
+ list_del(&page->list);
+ free_page = 1;
+ }
+
+ if (page->fill == (IPZ_SPAGE_PER_KPAGE >> order) - 1)
+ /* the page was full until we freed the chunk */
+ list_move_tail(&page->list, &pd->free[order]);
+
+ mutex_unlock(&pd->lock);
+
+ if (free_page) {
+ free_page(page->page);
+ kmem_cache_free(small_qp_cache, page);
+ }
+}
+
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+ const u32 nr_of_pages, const u32 pagesize,
+ const u32 qe_size, const u32 nr_of_sg,
+ int is_small)
+{
+ if (pagesize > PAGE_SIZE) {
+ ehca_gen_err("FATAL ERROR: pagesize=%x "
+ "is greater than kernel page size", pagesize);
+ return 0;
+ }
+
+ /* init queue fields */
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->pagesize = pagesize;
queue->qe_size = qe_size;
queue->act_nr_of_sg = nr_of_sg;
- queue->pagesize = pagesize;
+ queue->current_q_offset = 0;
queue->toggle_state = 1;
- return 1;
+ queue->small_page = NULL;
- ipz_queue_ctor_exit0:
- ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x",
- queue, f, nr_of_pages);
- for (f = 0; f < nr_of_pages; f += pages_per_kpage) {
- if (!(queue->queue_pages)[f])
- break;
- free_page((unsigned long)(queue->queue_pages)[f]);
+ /* allocate queue page pointers */
+ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ if (!queue->queue_pages) {
+ ehca_gen_err("Couldn't allocate queue page list");
+ return 0;
}
+ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+
+ /* allocate actual queue pages */
+ if (is_small) {
+ if (!alloc_small_queue_page(queue, pd))
+ goto ipz_queue_ctor_exit0;
+ } else
+ if (!alloc_queue_pages(queue, nr_of_pages))
+ goto ipz_queue_ctor_exit0;
+
+ return 1;
+
+ipz_queue_ctor_exit0:
+ ehca_gen_err("Couldn't alloc pages queue=%p "
+ "nr_of_pages=%x", queue, nr_of_pages);
+ vfree(queue->queue_pages);
+
return 0;
}
-int ipz_queue_dtor(struct ipz_queue *queue)
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue)
{
- int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
- int g;
- int nr_pages;
+ int i, nr_pages;
if (!queue || !queue->queue_pages) {
ehca_gen_dbg("queue or queue_pages is NULL");
return 0;
}
- nr_pages = queue->queue_length / queue->pagesize;
- for (g = 0; g < nr_pages; g += pages_per_kpage)
- free_page((unsigned long)(queue->queue_pages)[g]);
+
+ if (queue->small_page)
+ free_small_queue_page(queue, pd);
+ else {
+ nr_pages = queue->queue_length / queue->pagesize;
+ for (i = 0; i < nr_pages; i += PAGES_PER_KPAGE)
+ free_page((unsigned long)queue->queue_pages[i]);
+ }
+
vfree(queue->queue_pages);
return 1;
}
+
+int ehca_init_small_qp_cache(void)
+{
+ small_qp_cache = kmem_cache_create("ehca_cache_small_qp",
+ sizeof(struct ipz_small_queue_page),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!small_qp_cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void ehca_cleanup_small_qp_cache(void)
+{
+ kmem_cache_destroy(small_qp_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
index 57f141a36bce..c6937a044e8a 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -51,11 +51,25 @@
#include "ehca_tools.h"
#include "ehca_qes.h"
+struct ehca_pd;
+struct ipz_small_queue_page;
+
/* struct generic ehca page */
struct ipz_page {
u8 entries[EHCA_PAGESIZE];
};
+#define IPZ_SPAGE_PER_KPAGE (PAGE_SIZE / 512)
+
+struct ipz_small_queue_page {
+ unsigned long page;
+ unsigned long bitmap[IPZ_SPAGE_PER_KPAGE / BITS_PER_LONG];
+ int fill;
+ void *mapped_addr;
+ u32 mmap_count;
+ struct list_head list;
+};
+
/* struct generic queue in linux kernel virtual memory (kv) */
struct ipz_queue {
u64 current_q_offset; /* current queue entry */
@@ -66,7 +80,8 @@ struct ipz_queue {
u32 queue_length; /* queue length allocated in bytes */
u32 pagesize;
u32 toggle_state; /* toggle flag - per page */
- u32 dummy3; /* 64 bit alignment */
+ u32 offset; /* save offset within page for small_qp */
+ struct ipz_small_queue_page *small_page;
};
/*
@@ -105,7 +120,6 @@ void *ipz_qpageit_get_inc(struct ipz_queue *queue);
* step in struct ipz_queue, will wrap in ringbuffer
* returns address (kv) of Queue Entry BEFORE increment
* warning don't use in parallel with ipz_qpageit_get_inc()
- * warning unpredictable results may occur if steps>act_nr_of_queue_entries
*/
static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
{
@@ -121,31 +135,24 @@ static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
}
/*
+ * return a bool indicating whether current Queue Entry is valid
+ */
+static inline int ipz_qeit_is_valid(struct ipz_queue *queue)
+{
+ struct ehca_cqe *cqe = ipz_qeit_get(queue);
+ return ((cqe->cqe_flags >> 7) == (queue->toggle_state & 1));
+}
+
+/*
* return current Queue Entry, increment Queue Entry iterator by one
* step in struct ipz_queue, will wrap in ringbuffer
* returns address (kv) of Queue Entry BEFORE increment
* returns 0 and does not increment, if wrong valid state
* warning don't use in parallel with ipz_qpageit_get_inc()
- * warning unpredictable results may occur if steps>act_nr_of_queue_entries
*/
static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
{
- struct ehca_cqe *cqe = ipz_qeit_get(queue);
- u32 cqe_flags = cqe->cqe_flags;
-
- if ((cqe_flags >> 7) != (queue->toggle_state & 1))
- return NULL;
-
- ipz_qeit_get_inc(queue);
- return cqe;
-}
-
-static inline int ipz_qeit_is_valid(struct ipz_queue *queue)
-{
- struct ehca_cqe *cqe = ipz_qeit_get(queue);
- u32 cqe_flags = cqe->cqe_flags;
-
- return cqe_flags >> 7 == (queue->toggle_state & 1);
+ return ipz_qeit_is_valid(queue) ? ipz_qeit_get_inc(queue) : NULL;
}
/*
@@ -196,9 +203,10 @@ struct ipz_qpt {
* see ipz_qpt_ctor()
* returns true if ok, false if out of memory
*/
-int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
- const u32 pagesize, const u32 qe_size,
- const u32 nr_of_sg);
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+ const u32 nr_of_pages, const u32 pagesize,
+ const u32 qe_size, const u32 nr_of_sg,
+ int is_small);
/*
* destructor for a ipz_queue_t
@@ -206,7 +214,7 @@ int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
* see ipz_queue_ctor()
* returns true if ok, false if queue was NULL-ptr of free failed
*/
-int ipz_queue_dtor(struct ipz_queue *queue);
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue);
/*
* constructor for a ipz_qpt_t,
@@ -248,7 +256,7 @@ void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
{
void *ret = ipz_qeit_get(queue);
- u32 qe = *(u8 *) ret;
+ u32 qe = *(u8 *)ret;
if ((qe >> 7) != (queue->toggle_state & 1))
return NULL;
ipz_qeit_eq_get_inc(queue); /* this is a good one */
@@ -258,7 +266,7 @@ static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
{
void *ret = ipz_qeit_get(queue);
- u32 qe = *(u8 *) ret;
+ u32 qe = *(u8 *)ret;
if ((qe >> 7) != (queue->toggle_state & 1))
return NULL;
return ret;
diff --git a/drivers/infiniband/hw/ipath/Kconfig b/drivers/infiniband/hw/ipath/Kconfig
index 90c14543677d..044da5828a78 100644
--- a/drivers/infiniband/hw/ipath/Kconfig
+++ b/drivers/infiniband/hw/ipath/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_IPATH
tristate "QLogic InfiniPath Driver"
- depends on (PCI_MSI || HT_IRQ) && 64BIT && INFINIBAND && NET
+ depends on (PCI_MSI || HT_IRQ) && 64BIT && NET
---help---
This is a driver for QLogic InfiniPath host channel adapters,
including InfiniBand verbs support. This driver allows these
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
index ec2e603ea241..fe6738826865 100644
--- a/drivers/infiniband/hw/ipath/Makefile
+++ b/drivers/infiniband/hw/ipath/Makefile
@@ -14,7 +14,6 @@ ib_ipath-y := \
ipath_init_chip.o \
ipath_intr.o \
ipath_keys.o \
- ipath_layer.o \
ipath_mad.o \
ipath_mmap.o \
ipath_mr.o \
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index 10c008f22ba6..b4b786d0dfca 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -189,8 +189,7 @@ typedef enum _ipath_ureg {
#define IPATH_RUNTIME_FORCE_WC_ORDER 0x4
#define IPATH_RUNTIME_RCVHDR_COPY 0x8
#define IPATH_RUNTIME_MASTER 0x10
-#define IPATH_RUNTIME_PBC_REWRITE 0x20
-#define IPATH_RUNTIME_LOOSE_DMA_ALIGN 0x40
+/* 0x20 and 0x40 are no longer used, but are reserved for ABI compatibility */
/*
* This structure is returned by ipath_userinit() immediately after
@@ -432,8 +431,15 @@ struct ipath_user_info {
#define IPATH_CMD_UNUSED_1 25
#define IPATH_CMD_UNUSED_2 26
#define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */
+#define IPATH_CMD_POLL_TYPE 28 /* set the kind of polling we want */
-#define IPATH_CMD_MAX 27
+#define IPATH_CMD_MAX 28
+
+/*
+ * Poll types
+ */
+#define IPATH_POLL_TYPE_URGENT 0x01
+#define IPATH_POLL_TYPE_OVERFLOW 0x02
struct ipath_port_info {
__u32 num_active; /* number of active units */
@@ -474,6 +480,8 @@ struct ipath_cmd {
__u16 part_key;
/* user address of __u32 bitmask of active slaves */
__u64 slave_mask_addr;
+ /* type of polling we want */
+ __u16 poll_type;
} cmd;
};
@@ -502,13 +510,30 @@ struct __ipath_sendpkt {
struct ipath_iovec sps_iov[4];
};
-/* Passed into diag data special file's ->write method. */
+/*
+ * diagnostics can send a packet by "writing" one of the following
+ * two structs to diag data special file
+ * The first is the legacy version for backward compatibility
+ */
struct ipath_diag_pkt {
__u32 unit;
__u64 data;
__u32 len;
};
+/* The second diag_pkt struct is the expanded version that allows
+ * more control over the packet, specifically, by allowing a custom
+ * pbc (+ extra) qword, so that special modes and deliberate
+ * changes to CRCs can be used. The elements were also re-ordered
+ * for better alignment and to avoid padding issues.
+ */
+struct ipath_diag_xpkt {
+ __u64 data;
+ __u64 pbc_wd;
+ __u32 unit;
+ __u32 len;
+};
+
/*
* Data layout in I2C flash (for GUID, etc.)
* All fields are little-endian binary unless otherwise stated
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index 3e9241badba0..a6f04d27ec57 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -90,6 +90,8 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
wc->queue[head].sl = entry->sl;
wc->queue[head].dlid_path_bits = entry->dlid_path_bits;
wc->queue[head].port_num = entry->port_num;
+ /* Make sure queue entry is written before the head index. */
+ smp_wmb();
wc->head = next;
if (cq->notify == IB_CQ_NEXT_COMP ||
@@ -139,7 +141,8 @@ int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
if (tail == wc->head)
break;
-
+ /* Make sure entry is read after head index is read. */
+ smp_rmb();
qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table,
wc->queue[tail].qp_num);
entry->qp = &qp->ibqp;
diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
index 42bfbdb0d3e6..19c56e6491eb 100644
--- a/drivers/infiniband/hw/ipath/ipath_debug.h
+++ b/drivers/infiniband/hw/ipath/ipath_debug.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 63e8368b0e95..a698f1949d10 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -323,13 +323,14 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
{
u32 __iomem *piobuf;
u32 plen, clen, pbufn;
- struct ipath_diag_pkt dp;
+ struct ipath_diag_pkt odp;
+ struct ipath_diag_xpkt dp;
u32 *tmpbuf = NULL;
struct ipath_devdata *dd;
ssize_t ret = 0;
u64 val;
- if (count < sizeof(dp)) {
+ if (count != sizeof(dp)) {
ret = -EINVAL;
goto bail;
}
@@ -339,6 +340,29 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
goto bail;
}
+ /*
+ * Due to padding/alignment issues (lessened with new struct)
+ * the old and new structs are the same length. We need to
+ * disambiguate them, which we can do because odp.len has never
+ * been less than the total of LRH+BTH+DETH so far, while
+ * dp.unit (same offset) unit is unlikely to get that high.
+ * Similarly, dp.data, the pointer to user at the same offset
+ * as odp.unit, is almost certainly at least one (512byte)page
+ * "above" NULL. The if-block below can be omitted if compatibility
+ * between a new driver and older diagnostic code is unimportant.
+ * compatibility the other direction (new diags, old driver) is
+ * handled in the diagnostic code, with a warning.
+ */
+ if (dp.unit >= 20 && dp.data < 512) {
+ /* very probable version mismatch. Fix it up */
+ memcpy(&odp, &dp, sizeof(odp));
+ /* We got a legacy dp, copy elements to dp */
+ dp.unit = odp.unit;
+ dp.data = odp.data;
+ dp.len = odp.len;
+ dp.pbc_wd = 0; /* Indicate we need to compute PBC wd */
+ }
+
/* send count must be an exact number of dwords */
if (dp.len & 3) {
ret = -EINVAL;
@@ -371,9 +395,10 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
ret = -ENODEV;
goto bail;
}
+ /* Check link state, but not if we have custom PBC */
val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
- if (val != IPATH_IBSTATE_INIT && val != IPATH_IBSTATE_ARM &&
- val != IPATH_IBSTATE_ACTIVE) {
+ if (!dp.pbc_wd && val != IPATH_IBSTATE_INIT &&
+ val != IPATH_IBSTATE_ARM && val != IPATH_IBSTATE_ACTIVE) {
ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
dd->ipath_unit, (unsigned long long) val);
ret = -EINVAL;
@@ -419,9 +444,13 @@ static ssize_t ipath_diagpkt_write(struct file *fp,
ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
dd->ipath_unit, plen - 1, pbufn);
+ if (dp.pbc_wd == 0)
+ /* Legacy operation, use computed pbc_wd */
+ dp.pbc_wd = plen;
+
/* we have to flush after the PBC for correctness on some cpus
* or WC buffer can be written out of order */
- writeq(plen, piobuf);
+ writeq(dp.pbc_wd, piobuf);
ipath_flush_wc();
/* copy all by the trigger word, then flush, so it's written
* to chip before trigger word, then write trigger word, then
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index e3a223209710..09c5fd84b1e3 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -104,6 +104,9 @@ static int __devinit ipath_init_one(struct pci_dev *,
#define PCI_DEVICE_ID_INFINIPATH_HT 0xd
#define PCI_DEVICE_ID_INFINIPATH_PE800 0x10
+/* Number of seconds before our card status check... */
+#define STATUS_TIMEOUT 60
+
static const struct pci_device_id ipath_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_HT) },
{ PCI_DEVICE(PCI_VENDOR_ID_PATHSCALE, PCI_DEVICE_ID_INFINIPATH_PE800) },
@@ -119,6 +122,18 @@ static struct pci_driver ipath_driver = {
.id_table = ipath_pci_tbl,
};
+static void ipath_check_status(struct work_struct *work)
+{
+ struct ipath_devdata *dd = container_of(work, struct ipath_devdata,
+ status_work.work);
+
+ /*
+ * If we don't have any interrupts, let the user know and
+ * don't bother checking again.
+ */
+ if (dd->ipath_int_counter == 0)
+ dev_err(&dd->pcidev->dev, "No interrupts detected.\n");
+}
static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev,
u32 *bar0, u32 *bar1)
@@ -187,6 +202,8 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev)
dd->pcidev = pdev;
pci_set_drvdata(pdev, dd);
+ INIT_DELAYED_WORK(&dd->status_work, ipath_check_status);
+
list_add(&dd->ipath_list, &ipath_dev_list);
bail_unlock:
@@ -270,7 +287,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
struct ipath_devdata *dd;
unsigned long long addr;
u32 bar0 = 0, bar1 = 0;
- u8 rev;
dd = ipath_alloc_devdata(pdev);
if (IS_ERR(dd)) {
@@ -432,13 +448,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
dd->ipath_deviceid = ent->device; /* save for later use */
dd->ipath_vendorid = ent->vendor;
- ret = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
- if (ret) {
- ipath_dev_err(dd, "Failed to read PCI revision ID unit "
- "%u: err %d\n", dd->ipath_unit, -ret);
- goto bail_regions; /* shouldn't ever happen */
- }
- dd->ipath_pcirev = rev;
+ dd->ipath_pcirev = pdev->revision;
#if defined(__powerpc__)
/* There isn't a generic way to specify writethrough mappings */
@@ -511,6 +521,9 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ipath_diag_add(dd);
ipath_register_ib_device(dd);
+ /* Check that card status in STATUS_TIMEOUT seconds. */
+ schedule_delayed_work(&dd->status_work, HZ * STATUS_TIMEOUT);
+
goto bail;
bail_irqsetup:
@@ -638,6 +651,9 @@ static void __devexit ipath_remove_one(struct pci_dev *pdev)
*/
ipath_shutdown_device(dd);
+ cancel_delayed_work(&dd->status_work);
+ flush_scheduled_work();
+
if (dd->verbs_dev)
ipath_unregister_ib_device(dd->verbs_dev);
@@ -706,9 +722,9 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
u64 sendctrl, sendorig;
ipath_cdbg(PKT, "disarm %u PIObufs first=%u\n", cnt, first);
- sendorig = dd->ipath_sendctrl | INFINIPATH_S_DISARM;
+ sendorig = dd->ipath_sendctrl;
for (i = first; i < last; i++) {
- sendctrl = sendorig |
+ sendctrl = sendorig | INFINIPATH_S_DISARM |
(i << INFINIPATH_S_DISARMPIOBUF_SHIFT);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
sendctrl);
@@ -719,12 +735,12 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
* while we were looping; no critical bits that would require
* locking.
*
- * Write a 0, and then the original value, reading scratch in
+ * disable PIOAVAILUPD, then re-enable, reading scratch in
* between. This seems to avoid a chip timing race that causes
* pioavail updates to memory to stop.
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- 0);
+ sendorig & ~IPATH_S_PIOBUFAVAILUPD);
sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
dd->ipath_sendctrl);
@@ -1021,14 +1037,10 @@ void ipath_kreceive(struct ipath_devdata *dd)
goto bail;
}
- /* There is already a thread processing this queue. */
- if (test_and_set_bit(0, &dd->ipath_rcv_pending))
- goto bail;
-
l = dd->ipath_port0head;
hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
if (l == hdrqtail)
- goto done;
+ goto bail;
reloop:
for (i = 0; l != hdrqtail; i++) {
@@ -1163,10 +1175,6 @@ reloop:
ipath_stats.sps_avgpkts_call =
ipath_stats.sps_port0pkts / ++totcalls;
-done:
- clear_bit(0, &dd->ipath_rcv_pending);
- smp_mb__after_clear_bit();
-
bail:;
}
@@ -1596,6 +1604,35 @@ int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
return ret;
}
+
+/*
+ * Flush all sends that might be in the ready to send state, as well as any
+ * that are in the process of being sent. Used whenever we need to be
+ * sure the send side is idle. Cleans up all buffer state by canceling
+ * all pio buffers, and issuing an abort, which cleans up anything in the
+ * launch fifo. The cancel is superfluous on some chip versions, but
+ * it's safer to always do it.
+ * PIOAvail bits are updated by the chip as if normal send had happened.
+ */
+void ipath_cancel_sends(struct ipath_devdata *dd)
+{
+ ipath_dbg("Cancelling all in-progress send buffers\n");
+ dd->ipath_lastcancel = jiffies+HZ/2; /* skip armlaunch errs a bit */
+ /*
+ * the abort bit is auto-clearing. We read scratch to be sure
+ * that cancels and the abort have taken effect in the chip.
+ */
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ INFINIPATH_S_ABORT);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ ipath_disarm_piobufs(dd, 0,
+ (unsigned)(dd->ipath_piobcnt2k + dd->ipath_piobcnt4k));
+
+ /* and again, be sure all have hit the chip */
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+}
+
+
static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
{
static const char *what[4] = {
@@ -1617,14 +1654,8 @@ static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]);
/* flush all queued sends when going to DOWN or INIT, to be sure that
* they don't block MAD packets */
- if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT) {
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- INFINIPATH_S_ABORT);
- ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
- (unsigned)(dd->ipath_piobcnt2k +
- dd->ipath_piobcnt4k) -
- dd->ipath_lastport_piobuf);
- }
+ if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT)
+ ipath_cancel_sends(dd);
ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
dd->ipath_ibcctrl | which);
@@ -1846,6 +1877,87 @@ void ipath_write_kreg_port(const struct ipath_devdata *dd, ipath_kreg regno,
ipath_write_kreg(dd, where, value);
}
+/*
+ * Following deal with the "obviously simple" task of overriding the state
+ * of the LEDS, which normally indicate link physical and logical status.
+ * The complications arise in dealing with different hardware mappings
+ * and the board-dependent routine being called from interrupts.
+ * and then there's the requirement to _flash_ them.
+ */
+#define LED_OVER_FREQ_SHIFT 8
+#define LED_OVER_FREQ_MASK (0xFF<<LED_OVER_FREQ_SHIFT)
+/* Below is "non-zero" to force override, but both actual LEDs are off */
+#define LED_OVER_BOTH_OFF (8)
+
+static void ipath_run_led_override(unsigned long opaque)
+{
+ struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
+ int timeoff;
+ int pidx;
+ u64 lstate, ltstate, val;
+
+ if (!(dd->ipath_flags & IPATH_INITTED))
+ return;
+
+ pidx = dd->ipath_led_override_phase++ & 1;
+ dd->ipath_led_override = dd->ipath_led_override_vals[pidx];
+ timeoff = dd->ipath_led_override_timeoff;
+
+ /*
+ * below potentially restores the LED values per current status,
+ * should also possibly setup the traffic-blink register,
+ * but leave that to per-chip functions.
+ */
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
+ ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
+ INFINIPATH_IBCS_LINKTRAININGSTATE_MASK;
+ lstate = (val >> INFINIPATH_IBCS_LINKSTATE_SHIFT) &
+ INFINIPATH_IBCS_LINKSTATE_MASK;
+
+ dd->ipath_f_setextled(dd, lstate, ltstate);
+ mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff);
+}
+
+void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val)
+{
+ int timeoff, freq;
+
+ if (!(dd->ipath_flags & IPATH_INITTED))
+ return;
+
+ /* First check if we are blinking. If not, use 1HZ polling */
+ timeoff = HZ;
+ freq = (val & LED_OVER_FREQ_MASK) >> LED_OVER_FREQ_SHIFT;
+
+ if (freq) {
+ /* For blink, set each phase from one nybble of val */
+ dd->ipath_led_override_vals[0] = val & 0xF;
+ dd->ipath_led_override_vals[1] = (val >> 4) & 0xF;
+ timeoff = (HZ << 4)/freq;
+ } else {
+ /* Non-blink set both phases the same. */
+ dd->ipath_led_override_vals[0] = val & 0xF;
+ dd->ipath_led_override_vals[1] = val & 0xF;
+ }
+ dd->ipath_led_override_timeoff = timeoff;
+
+ /*
+ * If the timer has not already been started, do so. Use a "quick"
+ * timeout so the function will be called soon, to look at our request.
+ */
+ if (atomic_inc_return(&dd->ipath_led_override_timer_active) == 1) {
+ /* Need to start timer */
+ init_timer(&dd->ipath_led_override_timer);
+ dd->ipath_led_override_timer.function =
+ ipath_run_led_override;
+ dd->ipath_led_override_timer.data = (unsigned long) dd;
+ dd->ipath_led_override_timer.expires = jiffies + 1;
+ add_timer(&dd->ipath_led_override_timer);
+ } else {
+ atomic_dec(&dd->ipath_led_override_timer_active);
+ }
+}
+
/**
* ipath_shutdown_device - shut down a device
* @dd: the infinipath device
@@ -1886,17 +1998,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
*/
udelay(5);
- /*
- * abort any armed or launched PIO buffers that didn't go. (self
- * clearing). Will cause any packet currently being transmitted to
- * go out with an EBP, and may also cause a short packet error on
- * the receiver.
- */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- INFINIPATH_S_ABORT);
-
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+ ipath_cancel_sends(dd);
/* disable IBC */
dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
@@ -1909,7 +2013,6 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
* Turn the LEDs off explictly for the same reason.
*/
dd->ipath_f_quiet_serdes(dd);
- dd->ipath_f_setextled(dd, 0, 0);
if (dd->ipath_stats_timer_active) {
del_timer_sync(&dd->ipath_stats_timer);
@@ -1925,6 +2028,9 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
~0ULL & ~INFINIPATH_HWE_MEMBISTFAILED);
ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL);
ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL);
+
+ ipath_cdbg(VERBOSE, "Flush time and errors to EEPROM\n");
+ ipath_update_eeprom_log(dd);
}
/**
@@ -2085,6 +2191,16 @@ int ipath_reset_device(int unit)
goto bail;
}
+ if (atomic_read(&dd->ipath_led_override_timer_active)) {
+ /* Need to stop LED timer, _then_ shut off LEDs */
+ del_timer_sync(&dd->ipath_led_override_timer);
+ atomic_set(&dd->ipath_led_override_timer_active, 0);
+ }
+
+ /* Shut off LEDs after we are sure timer is not running */
+ dd->ipath_led_override = LED_OVER_BOTH_OFF;
+ dd->ipath_f_setextled(dd, 0, 0);
+
dev_info(&dd->pcidev->dev, "Reset on unit %u requested\n", unit);
if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT)) {
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index 030185f90ee2..b4503e9c1e95 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -95,39 +95,37 @@ static int i2c_gpio_set(struct ipath_devdata *dd,
enum i2c_type line,
enum i2c_state new_line_state)
{
- u64 read_val, write_val, mask, *gpioval;
+ u64 out_mask, dir_mask, *gpioval;
+ unsigned long flags = 0;
gpioval = &dd->ipath_gpio_out;
- read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
- if (line == i2c_line_scl)
- mask = dd->ipath_gpio_scl;
- else
- mask = dd->ipath_gpio_sda;
- if (new_line_state == i2c_line_high)
+ if (line == i2c_line_scl) {
+ dir_mask = dd->ipath_gpio_scl;
+ out_mask = (1UL << dd->ipath_gpio_scl_num);
+ } else {
+ dir_mask = dd->ipath_gpio_sda;
+ out_mask = (1UL << dd->ipath_gpio_sda_num);
+ }
+
+ spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
+ if (new_line_state == i2c_line_high) {
/* tri-state the output rather than force high */
- write_val = read_val & ~mask;
- else
+ dd->ipath_extctrl &= ~dir_mask;
+ } else {
/* config line to be an output */
- write_val = read_val | mask;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val);
+ dd->ipath_extctrl |= dir_mask;
+ }
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl);
- /* set high and verify */
+ /* set output as well (no real verify) */
if (new_line_state == i2c_line_high)
- write_val = 0x1UL;
+ *gpioval |= out_mask;
else
- write_val = 0x0UL;
+ *gpioval &= ~out_mask;
- if (line == i2c_line_scl) {
- write_val <<= dd->ipath_gpio_scl_num;
- *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_scl_num);
- *gpioval |= write_val;
- } else {
- write_val <<= dd->ipath_gpio_sda_num;
- *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_sda_num);
- *gpioval |= write_val;
- }
ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval);
+ spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
return 0;
}
@@ -145,8 +143,9 @@ static int i2c_gpio_get(struct ipath_devdata *dd,
enum i2c_type line,
enum i2c_state *curr_statep)
{
- u64 read_val, write_val, mask;
+ u64 read_val, mask;
int ret;
+ unsigned long flags = 0;
/* check args */
if (curr_statep == NULL) {
@@ -154,15 +153,21 @@ static int i2c_gpio_get(struct ipath_devdata *dd,
goto bail;
}
- read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
/* config line to be an input */
if (line == i2c_line_scl)
mask = dd->ipath_gpio_scl;
else
mask = dd->ipath_gpio_sda;
- write_val = read_val & ~mask;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val);
+
+ spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
+ dd->ipath_extctrl &= ~mask;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl);
+ /*
+ * Below is very unlikely to reflect true input state if Output
+ * Enable actually changed.
+ */
read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
+ spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
if (read_val & mask)
*curr_statep = i2c_line_high;
@@ -192,6 +197,7 @@ static void i2c_wait_for_writes(struct ipath_devdata *dd)
static void scl_out(struct ipath_devdata *dd, u8 bit)
{
+ udelay(1);
i2c_gpio_set(dd, i2c_line_scl, bit ? i2c_line_high : i2c_line_low);
i2c_wait_for_writes(dd);
@@ -314,12 +320,18 @@ static int eeprom_reset(struct ipath_devdata *dd)
int clock_cycles_left = 9;
u64 *gpioval = &dd->ipath_gpio_out;
int ret;
+ unsigned long flags;
- eeprom_init = 1;
+ spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
+ /* Make sure shadows are consistent */
+ dd->ipath_extctrl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
*gpioval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_out);
+ spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
+
ipath_cdbg(VERBOSE, "Resetting i2c eeprom; initial gpioout reg "
"is %llx\n", (unsigned long long) *gpioval);
+ eeprom_init = 1;
/*
* This is to get the i2c into a known state, by first going low,
* then tristate sda (and then tristate scl as first thing
@@ -355,8 +367,8 @@ bail:
* @len: number of bytes to receive
*/
-int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
- void *buffer, int len)
+static int ipath_eeprom_internal_read(struct ipath_devdata *dd,
+ u8 eeprom_offset, void *buffer, int len)
{
/* compiler complains unless initialized */
u8 single_byte = 0;
@@ -406,6 +418,7 @@ bail:
return ret;
}
+
/**
* ipath_eeprom_write - writes data to the eeprom via I2C
* @dd: the infinipath device
@@ -413,8 +426,8 @@ bail:
* @buffer: data to write
* @len: number of bytes to write
*/
-int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
- const void *buffer, int len)
+static int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
+ const void *buffer, int len)
{
u8 single_byte;
int sub_len;
@@ -488,6 +501,38 @@ bail:
return ret;
}
+/*
+ * The public entry-points ipath_eeprom_read() and ipath_eeprom_write()
+ * are now just wrappers around the internal functions.
+ */
+int ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset,
+ void *buff, int len)
+{
+ int ret;
+
+ ret = down_interruptible(&dd->ipath_eep_sem);
+ if (!ret) {
+ ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len);
+ up(&dd->ipath_eep_sem);
+ }
+
+ return ret;
+}
+
+int ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset,
+ const void *buff, int len)
+{
+ int ret;
+
+ ret = down_interruptible(&dd->ipath_eep_sem);
+ if (!ret) {
+ ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len);
+ up(&dd->ipath_eep_sem);
+ }
+
+ return ret;
+}
+
static u8 flash_csum(struct ipath_flash *ifp, int adjust)
{
u8 *ip = (u8 *) ifp;
@@ -515,7 +560,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
void *buf;
struct ipath_flash *ifp;
__be64 guid;
- int len;
+ int len, eep_stat;
u8 csum, *bguid;
int t = dd->ipath_unit;
struct ipath_devdata *dd0 = ipath_lookup(0);
@@ -559,7 +604,11 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
goto bail;
}
- if (ipath_eeprom_read(dd, 0, buf, len)) {
+ down(&dd->ipath_eep_sem);
+ eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len);
+ up(&dd->ipath_eep_sem);
+
+ if (eep_stat) {
ipath_dev_err(dd, "Failed reading GUID from eeprom\n");
goto done;
}
@@ -634,8 +683,192 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n",
(unsigned long long) be64_to_cpu(dd->ipath_guid));
+ memcpy(&dd->ipath_eep_st_errs, &ifp->if_errcntp, IPATH_EEP_LOG_CNT);
+ /*
+ * Power-on (actually "active") hours are kept as little-endian value
+ * in EEPROM, but as seconds in a (possibly as small as 24-bit)
+ * atomic_t while running.
+ */
+ atomic_set(&dd->ipath_active_time, 0);
+ dd->ipath_eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8);
+
done:
vfree(buf);
bail:;
}
+
+/**
+ * ipath_update_eeprom_log - copy active-time and error counters to eeprom
+ * @dd: the infinipath device
+ *
+ * Although the time is kept as seconds in the ipath_devdata struct, it is
+ * rounded to hours for re-write, as we have only 16 bits in EEPROM.
+ * First-cut code reads whole (expected) struct ipath_flash, modifies,
+ * re-writes. Future direction: read/write only what we need, assuming
+ * that the EEPROM had to have been "good enough" for driver init, and
+ * if not, we aren't making it worse.
+ *
+ */
+
+int ipath_update_eeprom_log(struct ipath_devdata *dd)
+{
+ void *buf;
+ struct ipath_flash *ifp;
+ int len, hi_water;
+ uint32_t new_time, new_hrs;
+ u8 csum;
+ int ret, idx;
+ unsigned long flags;
+
+ /* first, check if we actually need to do anything. */
+ ret = 0;
+ for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
+ if (dd->ipath_eep_st_new_errs[idx]) {
+ ret = 1;
+ break;
+ }
+ }
+ new_time = atomic_read(&dd->ipath_active_time);
+
+ if (ret == 0 && new_time < 3600)
+ return 0;
+
+ /*
+ * The quick-check above determined that there is something worthy
+ * of logging, so get current contents and do a more detailed idea.
+ */
+ len = offsetof(struct ipath_flash, if_future);
+ buf = vmalloc(len);
+ ret = 1;
+ if (!buf) {
+ ipath_dev_err(dd, "Couldn't allocate memory to read %u "
+ "bytes from eeprom for logging\n", len);
+ goto bail;
+ }
+
+ /* Grab semaphore and read current EEPROM. If we get an
+ * error, let go, but if not, keep it until we finish write.
+ */
+ ret = down_interruptible(&dd->ipath_eep_sem);
+ if (ret) {
+ ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n");
+ goto free_bail;
+ }
+ ret = ipath_eeprom_internal_read(dd, 0, buf, len);
+ if (ret) {
+ up(&dd->ipath_eep_sem);
+ ipath_dev_err(dd, "Unable read EEPROM for logging\n");
+ goto free_bail;
+ }
+ ifp = (struct ipath_flash *)buf;
+
+ csum = flash_csum(ifp, 0);
+ if (csum != ifp->if_csum) {
+ up(&dd->ipath_eep_sem);
+ ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
+ csum, ifp->if_csum);
+ ret = 1;
+ goto free_bail;
+ }
+ hi_water = 0;
+ spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
+ for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
+ int new_val = dd->ipath_eep_st_new_errs[idx];
+ if (new_val) {
+ /*
+ * If we have seen any errors, add to EEPROM values
+ * We need to saturate at 0xFF (255) and we also
+ * would need to adjust the checksum if we were
+ * trying to minimize EEPROM traffic
+ * Note that we add to actual current count in EEPROM,
+ * in case it was altered while we were running.
+ */
+ new_val += ifp->if_errcntp[idx];
+ if (new_val > 0xFF)
+ new_val = 0xFF;
+ if (ifp->if_errcntp[idx] != new_val) {
+ ifp->if_errcntp[idx] = new_val;
+ hi_water = offsetof(struct ipath_flash,
+ if_errcntp) + idx;
+ }
+ /*
+ * update our shadow (used to minimize EEPROM
+ * traffic), to match what we are about to write.
+ */
+ dd->ipath_eep_st_errs[idx] = new_val;
+ dd->ipath_eep_st_new_errs[idx] = 0;
+ }
+ }
+ /*
+ * now update active-time. We would like to round to the nearest hour
+ * but unless atomic_t are sure to be proper signed ints we cannot,
+ * because we need to account for what we "transfer" to EEPROM and
+ * if we log an hour at 31 minutes, then we would need to set
+ * active_time to -29 to accurately count the _next_ hour.
+ */
+ if (new_time > 3600) {
+ new_hrs = new_time / 3600;
+ atomic_sub((new_hrs * 3600), &dd->ipath_active_time);
+ new_hrs += dd->ipath_eep_hrs;
+ if (new_hrs > 0xFFFF)
+ new_hrs = 0xFFFF;
+ dd->ipath_eep_hrs = new_hrs;
+ if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) {
+ ifp->if_powerhour[0] = new_hrs & 0xFF;
+ hi_water = offsetof(struct ipath_flash, if_powerhour);
+ }
+ if ((new_hrs >> 8) != ifp->if_powerhour[1]) {
+ ifp->if_powerhour[1] = new_hrs >> 8;
+ hi_water = offsetof(struct ipath_flash, if_powerhour)
+ + 1;
+ }
+ }
+ /*
+ * There is a tiny possibility that we could somehow fail to write
+ * the EEPROM after updating our shadows, but problems from holding
+ * the spinlock too long are a much bigger issue.
+ */
+ spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
+ if (hi_water) {
+ /* we made some change to the data, uopdate cksum and write */
+ csum = flash_csum(ifp, 1);
+ ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1);
+ }
+ up(&dd->ipath_eep_sem);
+ if (ret)
+ ipath_dev_err(dd, "Failed updating EEPROM\n");
+
+free_bail:
+ vfree(buf);
+bail:
+ return ret;
+
+}
+
+/**
+ * ipath_inc_eeprom_err - increment one of the four error counters
+ * that are logged to EEPROM.
+ * @dd: the infinipath device
+ * @eidx: 0..3, the counter to increment
+ * @incr: how much to add
+ *
+ * Each counter is 8-bits, and saturates at 255 (0xFF). They
+ * are copied to the EEPROM (aka flash) whenever ipath_update_eeprom_log()
+ * is called, but it can only be called in a context that allows sleep.
+ * This function can be called even at interrupt level.
+ */
+
+void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr)
+{
+ uint new_val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
+ new_val = dd->ipath_eep_st_new_errs[eidx] + incr;
+ if (new_val > 255)
+ new_val = 255;
+ dd->ipath_eep_st_new_errs[eidx] = new_val;
+ spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
+ return;
+}
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 1272aaf2a785..33ab0d6b80ff 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -396,7 +396,8 @@ static int ipath_tid_update(struct ipath_portdata *pd, struct file *fp,
"TID %u, vaddr %lx, physaddr %llx pgp %p\n",
tid, vaddr, (unsigned long long) physaddr,
pagep[i]);
- dd->ipath_f_put_tid(dd, &tidbase[tid], 1, physaddr);
+ dd->ipath_f_put_tid(dd, &tidbase[tid], RCVHQ_RCV_TYPE_EXPECTED,
+ physaddr);
/*
* don't check this tid in ipath_portshadow, since we
* just filled it in; start with the next one.
@@ -422,7 +423,8 @@ static int ipath_tid_update(struct ipath_portdata *pd, struct file *fp,
if (dd->ipath_pageshadow[porttid + tid]) {
ipath_cdbg(VERBOSE, "Freeing TID %u\n",
tid);
- dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
+ dd->ipath_f_put_tid(dd, &tidbase[tid],
+ RCVHQ_RCV_TYPE_EXPECTED,
dd->ipath_tidinvalid);
pci_unmap_page(dd->pcidev,
dd->ipath_physshadow[porttid + tid],
@@ -538,7 +540,8 @@ static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
if (dd->ipath_pageshadow[porttid + tid]) {
ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n",
pd->port_pid, tid);
- dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
+ dd->ipath_f_put_tid(dd, &tidbase[tid],
+ RCVHQ_RCV_TYPE_EXPECTED,
dd->ipath_tidinvalid);
pci_unmap_page(dd->pcidev,
dd->ipath_physshadow[porttid + tid],
@@ -921,7 +924,8 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
(u64 __iomem *)
((char __iomem *)
dd->ipath_kregbase +
- dd->ipath_rcvegrbase), 0, pa);
+ dd->ipath_rcvegrbase),
+ RCVHQ_RCV_TYPE_EAGER, pa);
pa += egrsize;
}
cond_resched(); /* don't hog the cpu */
@@ -1337,68 +1341,133 @@ bail:
return ret;
}
-static unsigned int ipath_poll(struct file *fp,
- struct poll_table_struct *pt)
+static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
+ struct file *fp,
+ struct poll_table_struct *pt)
{
- struct ipath_portdata *pd;
- u32 head, tail;
- int bit;
unsigned pollflag = 0;
struct ipath_devdata *dd;
- pd = port_fp(fp);
- if (!pd)
- goto bail;
dd = pd->port_dd;
- bit = pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT;
- set_bit(bit, &dd->ipath_rcvctrl);
+ if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
+ pollflag |= POLLERR;
+ clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
+ }
- /*
- * Before blocking, make sure that head is still == tail,
- * reading from the chip, so we can be sure the interrupt
- * enable has made it to the chip. If not equal, disable
- * interrupt again and return immediately. This avoids races,
- * and the overhead of the chip read doesn't matter much at
- * this point, since we are waiting for something anyway.
- */
+ if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) {
+ pollflag |= POLLIN | POLLRDNORM;
+ clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag);
+ }
- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- dd->ipath_rcvctrl);
+ if (!pollflag) {
+ set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag);
+ if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
+ set_bit(IPATH_PORT_WAITING_OVERFLOW,
+ &pd->port_flag);
+
+ poll_wait(fp, &pd->port_wait, pt);
+ }
+
+ return pollflag;
+}
+
+static unsigned int ipath_poll_next(struct ipath_portdata *pd,
+ struct file *fp,
+ struct poll_table_struct *pt)
+{
+ u32 head, tail;
+ unsigned pollflag = 0;
+ struct ipath_devdata *dd;
+
+ dd = pd->port_dd;
head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
- tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
+ tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
- if (tail == head) {
+ if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
+ pollflag |= POLLERR;
+ clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
+ }
+
+ if (tail != head ||
+ test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) {
+ pollflag |= POLLIN | POLLRDNORM;
+ clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag);
+ }
+
+ if (!pollflag) {
set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
+ if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
+ set_bit(IPATH_PORT_WAITING_OVERFLOW,
+ &pd->port_flag);
+
+ set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+ &dd->ipath_rcvctrl);
+
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl);
+
if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
- (void)ipath_write_ureg(dd, ur_rcvhdrhead,
- dd->ipath_rhdrhead_intr_off
- | head, pd->port_port);
- poll_wait(fp, &pd->port_wait, pt);
+ ipath_write_ureg(dd, ur_rcvhdrhead,
+ dd->ipath_rhdrhead_intr_off | head,
+ pd->port_port);
- if (test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
- /* timed out, no packets received */
- clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
- pd->port_rcvwait_to++;
- }
- else
- pollflag = POLLIN | POLLRDNORM;
- }
- else {
- /* it's already happened; don't do wait_event overhead */
- pollflag = POLLIN | POLLRDNORM;
- pd->port_rcvnowait++;
+ poll_wait(fp, &pd->port_wait, pt);
}
- clear_bit(bit, &dd->ipath_rcvctrl);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- dd->ipath_rcvctrl);
+ return pollflag;
+}
+
+static unsigned int ipath_poll(struct file *fp,
+ struct poll_table_struct *pt)
+{
+ struct ipath_portdata *pd;
+ unsigned pollflag;
+
+ pd = port_fp(fp);
+ if (!pd)
+ pollflag = 0;
+ else if (pd->poll_type & IPATH_POLL_TYPE_URGENT)
+ pollflag = ipath_poll_urgent(pd, fp, pt);
+ else
+ pollflag = ipath_poll_next(pd, fp, pt);
-bail:
return pollflag;
}
+static int ipath_supports_subports(int user_swmajor, int user_swminor)
+{
+ /* no subport implementation prior to software version 1.3 */
+ return (user_swmajor > 1) || (user_swminor >= 3);
+}
+
+static int ipath_compatible_subports(int user_swmajor, int user_swminor)
+{
+ /* this code is written long-hand for clarity */
+ if (IPATH_USER_SWMAJOR != user_swmajor) {
+ /* no promise of compatibility if major mismatch */
+ return 0;
+ }
+ if (IPATH_USER_SWMAJOR == 1) {
+ switch (IPATH_USER_SWMINOR) {
+ case 0:
+ case 1:
+ case 2:
+ /* no subport implementation so cannot be compatible */
+ return 0;
+ case 3:
+ /* 3 is only compatible with itself */
+ return user_swminor == 3;
+ default:
+ /* >= 4 are compatible (or are expected to be) */
+ return user_swminor >= 4;
+ }
+ }
+ /* make no promises yet for future major versions */
+ return 0;
+}
+
static int init_subports(struct ipath_devdata *dd,
struct ipath_portdata *pd,
const struct ipath_user_info *uinfo)
@@ -1408,20 +1477,32 @@ static int init_subports(struct ipath_devdata *dd,
size_t size;
/*
- * If the user is requesting zero or one port,
+ * If the user is requesting zero subports,
* skip the subport allocation.
*/
- if (uinfo->spu_subport_cnt <= 1)
+ if (uinfo->spu_subport_cnt <= 0)
+ goto bail;
+
+ /* Self-consistency check for ipath_compatible_subports() */
+ if (ipath_supports_subports(IPATH_USER_SWMAJOR, IPATH_USER_SWMINOR) &&
+ !ipath_compatible_subports(IPATH_USER_SWMAJOR,
+ IPATH_USER_SWMINOR)) {
+ dev_info(&dd->pcidev->dev,
+ "Inconsistent ipath_compatible_subports()\n");
goto bail;
+ }
- /* Old user binaries don't know about new subport implementation */
- if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR) {
+ /* Check for subport compatibility */
+ if (!ipath_compatible_subports(uinfo->spu_userversion >> 16,
+ uinfo->spu_userversion & 0xffff)) {
dev_info(&dd->pcidev->dev,
- "Mismatched user minor version (%d) and driver "
- "minor version (%d) while port sharing. Ensure "
+ "Mismatched user version (%d.%d) and driver "
+ "version (%d.%d) while port sharing. Ensure "
"that driver and library are from the same "
"release.\n",
+ (int) (uinfo->spu_userversion >> 16),
(int) (uinfo->spu_userversion & 0xffff),
+ IPATH_USER_SWMAJOR,
IPATH_USER_SWMINOR);
goto bail;
}
@@ -1725,14 +1806,13 @@ static int ipath_open(struct inode *in, struct file *fp)
return fp->private_data ? 0 : -ENOMEM;
}
-
/* Get port early, so can set affinity prior to memory allocation */
static int ipath_assign_port(struct file *fp,
const struct ipath_user_info *uinfo)
{
int ret;
int i_minor;
- unsigned swminor;
+ unsigned swmajor, swminor;
/* Check to be sure we haven't already initialized this file */
if (port_fp(fp)) {
@@ -1741,7 +1821,8 @@ static int ipath_assign_port(struct file *fp,
}
/* for now, if major version is different, bail */
- if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) {
+ swmajor = uinfo->spu_userversion >> 16;
+ if (swmajor != IPATH_USER_SWMAJOR) {
ipath_dbg("User major version %d not same as driver "
"major %d\n", uinfo->spu_userversion >> 16,
IPATH_USER_SWMAJOR);
@@ -1756,7 +1837,8 @@ static int ipath_assign_port(struct file *fp,
mutex_lock(&ipath_mutex);
- if (swminor == IPATH_USER_SWMINOR && uinfo->spu_subport_cnt &&
+ if (ipath_compatible_subports(swmajor, swminor) &&
+ uinfo->spu_subport_cnt &&
(ret = find_shared_port(fp, uinfo))) {
mutex_unlock(&ipath_mutex);
if (ret > 0)
@@ -2020,7 +2102,8 @@ static int ipath_port_info(struct ipath_portdata *pd, u16 subport,
info.port = pd->port_port;
info.subport = subport;
/* Don't return new fields if old library opened the port. */
- if ((pd->userversion & 0xffff) == IPATH_USER_SWMINOR) {
+ if (ipath_supports_subports(pd->userversion >> 16,
+ pd->userversion & 0xffff)) {
/* Number of user ports available for this device. */
info.num_ports = pd->port_dd->ipath_cfgports - 1;
info.num_subports = pd->port_subport_cnt;
@@ -2123,6 +2206,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
src = NULL;
dest = NULL;
break;
+ case IPATH_CMD_POLL_TYPE:
+ copy = sizeof(cmd.cmd.poll_type);
+ dest = &cmd.cmd.poll_type;
+ src = &ucmd->cmd.poll_type;
+ break;
default:
ret = -EINVAL;
goto bail;
@@ -2195,6 +2283,9 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
case IPATH_CMD_PIOAVAILUPD:
ret = ipath_force_pio_avail_update(pd->port_dd);
break;
+ case IPATH_CMD_POLL_TYPE:
+ pd->poll_type = cmd.cmd.poll_type;
+ break;
}
if (ret >= 0)
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index ebd5c7bd2cdb..2e689b974e1f 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -257,9 +257,14 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
/* Notimpl InitType (actually, an SMA decision) */
/* VLHighLimit is 0 (only one VL) */
; /* VLArbitrationHighCap is 0 (only one VL) */
+ /*
+ * Note: the chips support a maximum MTU of 4096, but the driver
+ * hasn't implemented this feature yet, so set the maximum
+ * to 2048.
+ */
portinfo[10] = /* VLArbitrationLowCap is 0 (only one VL) */
/* InitTypeReply is SMA decision */
- (5 << 16) /* MTUCap 4096 */
+ (4 << 16) /* MTUCap 2048 */
| (7 << 13) /* VLStallCount */
| (0x1f << 8) /* HOQLife */
| (1 << 4)
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 4171198fc202..650745d83fac 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -36,6 +36,7 @@
* HT chip.
*/
+#include <linux/vmalloc.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/htirq.h>
@@ -439,6 +440,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
u32 bits, ctrl;
int isfatal = 0;
char bitsmsg[64];
+ int log_idx;
hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
@@ -467,6 +469,11 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
hwerrs &= dd->ipath_hwerrmask;
+ /* We log some errors to EEPROM, check if we have any of those. */
+ for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx)
+ if (hwerrs & dd->ipath_eep_st_masks[log_idx].hwerrs_to_log)
+ ipath_inc_eeprom_err(dd, log_idx, 1);
+
/*
* make sure we get this much out, unless told to be quiet,
* it's a parity error we may recover from,
@@ -502,9 +509,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
if (!hwerrs) {
ipath_dbg("Clearing freezemode on ignored or "
"recovered hardware error\n");
- ctrl &= ~INFINIPATH_C_FREEZEMODE;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
- ctrl);
+ ipath_clear_freeze(dd);
}
}
@@ -672,10 +677,16 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
if (n)
snprintf(name, namelen, "%s", n);
+ if (dd->ipath_boardrev != 6 && dd->ipath_boardrev != 7 &&
+ dd->ipath_boardrev != 11) {
+ ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name);
+ ret = 1;
+ goto bail;
+ }
if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 ||
- dd->ipath_minrev > 3)) {
+ dd->ipath_minrev > 4)) {
/*
- * This version of the driver only supports Rev 3.2 and 3.3
+ * This version of the driver only supports Rev 3.2 - 3.4
*/
ipath_dev_err(dd,
"Unsupported InfiniPath hardware revision %u.%u!\n",
@@ -689,36 +700,11 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
* copies
*/
dd->ipath_flags |= IPATH_32BITCOUNTERS;
+ dd->ipath_flags |= IPATH_GPIO_INTR;
if (dd->ipath_htspeed != 800)
ipath_dev_err(dd,
"Incorrectly configured for HT @ %uMHz\n",
dd->ipath_htspeed);
- if (dd->ipath_boardrev == 7 || dd->ipath_boardrev == 11 ||
- dd->ipath_boardrev == 6)
- dd->ipath_flags |= IPATH_GPIO_INTR;
- else
- dd->ipath_flags |= IPATH_POLL_RX_INTR;
- if (dd->ipath_boardrev == 8) { /* LS/X-1 */
- u64 val;
- val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
- if (val & INFINIPATH_EXTS_SERDESSEL) {
- /*
- * hardware disabled
- *
- * This means that the chip is hardware disabled,
- * and will not be able to bring up the link,
- * in any case. We special case this and abort
- * early, to avoid later messages. We also set
- * the DISABLED status bit
- */
- ipath_dbg("Unit %u is hardware-disabled\n",
- dd->ipath_unit);
- *dd->ipath_statusp |= IPATH_STATUS_DISABLED;
- /* this value is handled differently */
- ret = 2;
- goto bail;
- }
- }
ret = 0;
bail:
@@ -1058,12 +1044,24 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
u64 lst, u64 ltst)
{
u64 extctl;
+ unsigned long flags = 0;
/* the diags use the LED to indicate diag info, so we leave
* the external LED alone when the diags are running */
if (ipath_diag_inuse)
return;
+ /* Allow override of LED display for, e.g. Locating system in rack */
+ if (dd->ipath_led_override) {
+ ltst = (dd->ipath_led_override & IPATH_LED_PHYS)
+ ? INFINIPATH_IBCS_LT_STATE_LINKUP
+ : INFINIPATH_IBCS_LT_STATE_DISABLED;
+ lst = (dd->ipath_led_override & IPATH_LED_LOG)
+ ? INFINIPATH_IBCS_L_STATE_ACTIVE
+ : INFINIPATH_IBCS_L_STATE_DOWN;
+ }
+
+ spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
/*
* start by setting both LED control bits to off, then turn
* on the appropriate bit(s).
@@ -1092,6 +1090,7 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
}
dd->ipath_extctrl = extctl;
ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
+ spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
}
static void ipath_init_ht_variables(struct ipath_devdata *dd)
@@ -1157,6 +1156,22 @@ static void ipath_init_ht_variables(struct ipath_devdata *dd)
dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+
+ /*
+ * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
+ * 2 is Some Misc, 3 is reserved for future.
+ */
+ dd->ipath_eep_st_masks[0].hwerrs_to_log =
+ INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT;
+
+ dd->ipath_eep_st_masks[1].hwerrs_to_log =
+ INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
+
+ dd->ipath_eep_st_masks[2].errs_to_log =
+ INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
+
}
/**
@@ -1372,7 +1387,7 @@ static void ipath_ht_quiet_serdes(struct ipath_devdata *dd)
* ipath_pe_put_tid - write a TID in chip
* @dd: the infinipath device
* @tidptr: pointer to the expected TID (in chip) to udpate
- * @tidtype: 0 for eager, 1 for expected
+ * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected
* @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
*
* This exists as a separate routine to allow for special locking etc.
@@ -1393,7 +1408,7 @@ static void ipath_ht_put_tid(struct ipath_devdata *dd,
"40 bits, using only 40!!!\n", pa);
pa &= INFINIPATH_RT_ADDR_MASK;
}
- if (type == 0)
+ if (type == RCVHQ_RCV_TYPE_EAGER)
pa |= dd->ipath_tidtemplate;
else {
/* in words (fixed, full page). */
@@ -1433,7 +1448,8 @@ static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port)
port * dd->ipath_rcvtidcnt *
sizeof(*tidbase));
for (i = 0; i < dd->ipath_rcvtidcnt; i++)
- ipath_ht_put_tid(dd, &tidbase[i], 1, dd->ipath_tidinvalid);
+ ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
+ dd->ipath_tidinvalid);
tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
dd->ipath_rcvegrbase +
@@ -1441,7 +1457,8 @@ static void ipath_ht_clear_tids(struct ipath_devdata *dd, unsigned port)
sizeof(*tidbase));
for (i = 0; i < dd->ipath_rcvegrcnt; i++)
- ipath_ht_put_tid(dd, &tidbase[i], 0, dd->ipath_tidinvalid);
+ ipath_ht_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
+ dd->ipath_tidinvalid);
}
/**
@@ -1528,11 +1545,6 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
writel(16, piobuf);
piobuf += pioincr;
}
- /*
- * self-clearing
- */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- INFINIPATH_S_ABORT);
ipath_get_eeprom_info(dd);
if (dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
@@ -1543,8 +1555,10 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
* with 128, rather than 112.
*/
dd->ipath_flags |= IPATH_GPIO_INTR;
- dd->ipath_flags &= ~IPATH_POLL_RX_INTR;
- }
+ } else
+ ipath_dev_err(dd, "Unsupported InfiniPath serial "
+ "number %.16s!\n", dd->ipath_serial);
+
return 0;
}
@@ -1561,7 +1575,6 @@ static int ipath_ht_txe_recover(struct ipath_devdata *dd)
}
dev_info(&dd->pcidev->dev,
"Recovering from TXE PIO parity error\n");
- ipath_disarm_senderrbufs(dd, 1);
return 1;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 4e2e3dfeb2c8..9868ccda5f26 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -296,13 +296,6 @@ static const struct ipath_cregs ipath_pe_cregs = {
#define IPATH_GPIO_SCL (1ULL << \
(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
-/*
- * Rev2 silicon allows suppressing check for ArmLaunch errors.
- * this can speed up short packet sends on systems that do
- * not guaranteee write-order.
- */
-#define INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR (1ULL<<63)
-
/* 6120 specific hardware errors... */
static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
@@ -347,6 +340,7 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
u32 bits, ctrl;
int isfatal = 0;
char bitsmsg[64];
+ int log_idx;
hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
if (!hwerrs) {
@@ -374,6 +368,11 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
hwerrs &= dd->ipath_hwerrmask;
+ /* We log some errors to EEPROM, check if we have any of those. */
+ for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx)
+ if (hwerrs & dd->ipath_eep_st_masks[log_idx].hwerrs_to_log)
+ ipath_inc_eeprom_err(dd, log_idx, 1);
+
/*
* make sure we get this much out, unless told to be quiet,
* or it's occurred within the last 5 seconds
@@ -431,10 +430,12 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
dd->ipath_flags &= ~IPATH_INITTED;
} else {
- ipath_dbg("Clearing freezemode on ignored hardware "
- "error\n");
- ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
- dd->ipath_control);
+ static u32 freeze_cnt;
+
+ freeze_cnt++;
+ ipath_dbg("Clearing freezemode on ignored or recovered "
+ "hardware error (%u)\n", freeze_cnt);
+ ipath_clear_freeze(dd);
}
}
@@ -680,17 +681,6 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
val |= dd->ipath_rx_pol_inv <<
INFINIPATH_XGXS_RX_POL_SHIFT;
}
- if (dd->ipath_minrev >= 2) {
- /* Rev 2. can tolerate multiple writes to PBC, and
- * allowing them can provide lower latency on some
- * CPUs, but this feature is off by default, only
- * turned on by setting D63 of XGXSconfig reg.
- * May want to make this conditional more
- * fine-grained in future. This is not exactly
- * related to XGXS, but where the bit ended up.
- */
- val |= INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR;
- }
if (val != prev_val)
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
@@ -791,12 +781,24 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,
u64 ltst)
{
u64 extctl;
+ unsigned long flags = 0;
/* the diags use the LED to indicate diag info, so we leave
* the external LED alone when the diags are running */
if (ipath_diag_inuse)
return;
+ /* Allow override of LED display for, e.g. Locating system in rack */
+ if (dd->ipath_led_override) {
+ ltst = (dd->ipath_led_override & IPATH_LED_PHYS)
+ ? INFINIPATH_IBCS_LT_STATE_LINKUP
+ : INFINIPATH_IBCS_LT_STATE_DISABLED;
+ lst = (dd->ipath_led_override & IPATH_LED_LOG)
+ ? INFINIPATH_IBCS_L_STATE_ACTIVE
+ : INFINIPATH_IBCS_L_STATE_DOWN;
+ }
+
+ spin_lock_irqsave(&dd->ipath_gpio_lock, flags);
extctl = dd->ipath_extctrl & ~(INFINIPATH_EXTC_LED1PRIPORT_ON |
INFINIPATH_EXTC_LED2PRIPORT_ON);
@@ -806,6 +808,7 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,
extctl |= INFINIPATH_EXTC_LED1PRIPORT_ON;
dd->ipath_extctrl = extctl;
ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
+ spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags);
}
/**
@@ -955,6 +958,27 @@ static void ipath_init_pe_variables(struct ipath_devdata *dd)
dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+
+ /*
+ * EEPROM error log 0 is TXE Parity errors. 1 is RXE Parity.
+ * 2 is Some Misc, 3 is reserved for future.
+ */
+ dd->ipath_eep_st_masks[0].hwerrs_to_log =
+ INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT;
+
+ /* Ignore errors in PIO/PBC on systems with unordered write-combining */
+ if (ipath_unordered_wc())
+ dd->ipath_eep_st_masks[0].hwerrs_to_log &= ~TXE_PIO_PARITY;
+
+ dd->ipath_eep_st_masks[1].hwerrs_to_log =
+ INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT;
+
+ dd->ipath_eep_st_masks[2].errs_to_log =
+ INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET;
+
+
}
/* setup the MSI stuff again after a reset. I'd like to just call
@@ -1082,7 +1106,7 @@ bail:
* ipath_pe_put_tid - write a TID in chip
* @dd: the infinipath device
* @tidptr: pointer to the expected TID (in chip) to udpate
- * @tidtype: 0 for eager, 1 for expected
+ * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected
* @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
*
* This exists as a separate routine to allow for special locking etc.
@@ -1108,7 +1132,7 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
"BUG: Physical page address 0x%lx "
"has bits set in 31-29\n", pa);
- if (type == 0)
+ if (type == RCVHQ_RCV_TYPE_EAGER)
pa |= dd->ipath_tidtemplate;
else /* for now, always full 4KB page */
pa |= 2 << 29;
@@ -1132,7 +1156,7 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
* ipath_pe_put_tid_2 - write a TID in chip, Revision 2 or higher
* @dd: the infinipath device
* @tidptr: pointer to the expected TID (in chip) to udpate
- * @tidtype: 0 for eager, 1 for expected
+ * @tidtype: RCVHQ_RCV_TYPE_EAGER (1) for eager, RCVHQ_RCV_TYPE_EXPECTED (0) for expected
* @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
*
* This exists as a separate routine to allow for selection of the
@@ -1157,7 +1181,7 @@ static void ipath_pe_put_tid_2(struct ipath_devdata *dd, u64 __iomem *tidptr,
"BUG: Physical page address 0x%lx "
"has bits set in 31-29\n", pa);
- if (type == 0)
+ if (type == RCVHQ_RCV_TYPE_EAGER)
pa |= dd->ipath_tidtemplate;
else /* for now, always full 4KB page */
pa |= 2 << 29;
@@ -1196,7 +1220,8 @@ static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port)
port * dd->ipath_rcvtidcnt * sizeof(*tidbase));
for (i = 0; i < dd->ipath_rcvtidcnt; i++)
- ipath_pe_put_tid(dd, &tidbase[i], 0, tidinv);
+ ipath_pe_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
+ tidinv);
tidbase = (u64 __iomem *)
((char __iomem *)(dd->ipath_kregbase) +
@@ -1204,7 +1229,8 @@ static void ipath_pe_clear_tids(struct ipath_devdata *dd, unsigned port)
port * dd->ipath_rcvegrcnt * sizeof(*tidbase));
for (i = 0; i < dd->ipath_rcvegrcnt; i++)
- ipath_pe_put_tid(dd, &tidbase[i], 1, tidinv);
+ ipath_pe_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
+ tidinv);
}
/**
@@ -1311,13 +1337,6 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
dd = pd->port_dd;
- if (dd != NULL && dd->ipath_minrev >= 2) {
- ipath_cdbg(PROC, "IBA6120 Rev2, allow multiple PBC write\n");
- kinfo->spi_runtime_flags |= IPATH_RUNTIME_PBC_REWRITE;
- ipath_cdbg(PROC, "IBA6120 Rev2, allow loose DMA alignment\n");
- kinfo->spi_runtime_flags |= IPATH_RUNTIME_LOOSE_DMA_ALIGN;
- }
-
done:
kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
return 0;
@@ -1354,7 +1373,6 @@ static int ipath_pe_txe_recover(struct ipath_devdata *dd)
dev_info(&dd->pcidev->dev,
"Recovering from TXE PIO parity error\n");
}
- ipath_disarm_senderrbufs(dd, 1);
return 1;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 7045ba689494..49951d583804 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -133,7 +133,8 @@ static int create_port0_egr(struct ipath_devdata *dd)
dd->ipath_ibmaxlen, PCI_DMA_FROMDEVICE);
dd->ipath_f_put_tid(dd, e + (u64 __iomem *)
((char __iomem *) dd->ipath_kregbase +
- dd->ipath_rcvegrbase), 0,
+ dd->ipath_rcvegrbase),
+ RCVHQ_RCV_TYPE_EAGER,
dd->ipath_port0_skbinfo[e].phys);
}
@@ -310,7 +311,12 @@ static int init_chip_first(struct ipath_devdata *dd,
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiosize);
dd->ipath_piosize2k = val & ~0U;
dd->ipath_piosize4k = val >> 32;
- dd->ipath_ibmtu = 4096; /* default to largest legal MTU */
+ /*
+ * Note: the chips support a maximum MTU of 4096, but the driver
+ * hasn't implemented this feature yet, so set the initial value
+ * to 2048.
+ */
+ dd->ipath_ibmtu = 2048;
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_sendpiobufcnt);
dd->ipath_piobcnt2k = val & ~0U;
dd->ipath_piobcnt4k = val >> 32;
@@ -340,6 +346,10 @@ static int init_chip_first(struct ipath_devdata *dd,
spin_lock_init(&dd->ipath_tid_lock);
+ spin_lock_init(&dd->ipath_gpio_lock);
+ spin_lock_init(&dd->ipath_eep_st_lock);
+ sema_init(&dd->ipath_eep_sem, 1);
+
done:
*pdp = pd;
return ret;
@@ -646,7 +656,7 @@ static int init_housekeeping(struct ipath_devdata *dd,
ret = dd->ipath_f_get_boardname(dd, boardn, sizeof boardn);
snprintf(dd->ipath_boardversion, sizeof(dd->ipath_boardversion),
- "Driver %u.%u, %s, InfiniPath%u %u.%u, PCI %u, "
+ "ChipABI %u.%u, %s, InfiniPath%u %u.%u, PCI %u, "
"SW Compat %u\n",
IPATH_CHIP_VERS_MAJ, IPATH_CHIP_VERS_MIN, boardn,
(unsigned)(dd->ipath_revision >> INFINIPATH_R_ARCH_SHIFT) &
@@ -727,7 +737,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
uports = dd->ipath_cfgports ? dd->ipath_cfgports - 1 : 0;
if (ipath_kpiobufs == 0) {
/* not set by user (this is default) */
- if (piobufs >= (uports * IPATH_MIN_USER_PORT_BUFCNT) + 32)
+ if (piobufs > 144)
kpiobufs = 32;
else
kpiobufs = 16;
@@ -767,6 +777,12 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
piobufs, dd->ipath_pbufsport, uports);
dd->ipath_f_early_init(dd);
+ /*
+ * cancel any possible active sends from early driver load.
+ * Follows early_init because some chips have to initialize
+ * PIO buffers in early_init to avoid false parity errors.
+ */
+ ipath_cancel_sends(dd);
/* early_init sets rcvhdrentsize and rcvhdrsize, so this must be
* done after early_init */
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index a90d3b5699c4..1fd91c59f246 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -70,7 +70,7 @@ static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
* If rewrite is true, and bits are set in the sendbufferror registers,
* we'll write to the buffer, for error recovery on parity errors.
*/
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
{
u32 piobcnt;
unsigned long sbuf[4];
@@ -93,7 +93,8 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
int i;
- if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG)) {
+ if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG) &&
+ dd->ipath_lastcancel > jiffies) {
__IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG,
"SendbufErrs %lx %lx", sbuf[0],
sbuf[1]);
@@ -108,7 +109,8 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
ipath_clrpiobuf(dd, i);
ipath_disarm_piobufs(dd, i, 1);
}
- dd->ipath_lastcancel = jiffies+3; /* no armlaunch for a bit */
+ /* ignore armlaunch errs for a bit */
+ dd->ipath_lastcancel = jiffies+3;
}
}
@@ -131,6 +133,17 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
INFINIPATH_E_INVALIDADDR)
/*
+ * this is similar to E_SUM_ERRS, but can't ignore armlaunch, don't ignore
+ * errors not related to freeze and cancelling buffers. Can't ignore
+ * armlaunch because could get more while still cleaning up, and need
+ * to cancel those as they happen.
+ */
+#define E_SPKT_ERRS_IGNORE \
+ (INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
+ INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SMINPKTLEN | \
+ INFINIPATH_E_SPKTLEN)
+
+/*
* these are errors that can occur when the link changes state while
* a packet is being sent or received. This doesn't cover things
* like EBP or VCRC that can be the result of a sending having the
@@ -290,12 +303,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
* Flush all queued sends when link went to DOWN or INIT,
* to be sure that they don't block SMA and other MAD packets
*/
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- INFINIPATH_S_ABORT);
- ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
- (unsigned)(dd->ipath_piobcnt2k +
- dd->ipath_piobcnt4k) -
- dd->ipath_lastport_piobuf);
+ ipath_cancel_sends(dd);
}
else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
lstate == IPATH_IBSTATE_ACTIVE) {
@@ -505,6 +513,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
int i, iserr = 0;
int chkerrpkts = 0, noprint = 0;
unsigned supp_msgs;
+ int log_idx;
supp_msgs = handle_frequent_errors(dd, errs, msg, &noprint);
@@ -518,6 +527,13 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
if (errs & INFINIPATH_E_HARDWARE) {
/* reuse same msg buf */
dd->ipath_f_handle_hwerrors(dd, msg, sizeof msg);
+ } else {
+ u64 mask;
+ for (log_idx = 0; log_idx < IPATH_EEP_LOG_CNT; ++log_idx) {
+ mask = dd->ipath_eep_st_masks[log_idx].errs_to_log;
+ if (errs & mask)
+ ipath_inc_eeprom_err(dd, log_idx, 1);
+ }
}
if (!noprint && (errs & ~dd->ipath_e_bitsextant))
@@ -675,6 +691,17 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
chkerrpkts = 1;
dd->ipath_lastrcvhdrqtails[i] = tl;
pd->port_hdrqfull++;
+ if (test_bit(IPATH_PORT_WAITING_OVERFLOW,
+ &pd->port_flag)) {
+ clear_bit(
+ IPATH_PORT_WAITING_OVERFLOW,
+ &pd->port_flag);
+ set_bit(
+ IPATH_PORT_WAITING_OVERFLOW,
+ &pd->int_flag);
+ wake_up_interruptible(
+ &pd->port_wait);
+ }
}
}
}
@@ -744,6 +771,72 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
return chkerrpkts;
}
+
+/*
+ * try to cleanup as much as possible for anything that might have gone
+ * wrong while in freeze mode, such as pio buffers being written by user
+ * processes (causing armlaunch), send errors due to going into freeze mode,
+ * etc., and try to avoid causing extra interrupts while doing so.
+ * Forcibly update the in-memory pioavail register copies after cleanup
+ * because the chip won't do it for anything changing while in freeze mode
+ * (we don't want to wait for the next pio buffer state change).
+ * Make sure that we don't lose any important interrupts by using the chip
+ * feature that says that writing 0 to a bit in *clear that is set in
+ * *status will cause an interrupt to be generated again (if allowed by
+ * the *mask value).
+ */
+void ipath_clear_freeze(struct ipath_devdata *dd)
+{
+ int i, im;
+ __le64 val;
+
+ /* disable error interrupts, to avoid confusion */
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
+
+ /*
+ * clear all sends, because they have may been
+ * completed by usercode while in freeze mode, and
+ * therefore would not be sent, and eventually
+ * might cause the process to run out of bufs
+ */
+ ipath_cancel_sends(dd);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
+ dd->ipath_control);
+
+ /* ensure pio avail updates continue */
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ dd->ipath_sendctrl & ~IPATH_S_PIOBUFAVAILUPD);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ dd->ipath_sendctrl);
+
+ /*
+ * We just enabled pioavailupdate, so dma copy is almost certainly
+ * not yet right, so read the registers directly. Similar to init
+ */
+ for (i = 0; i < dd->ipath_pioavregs; i++) {
+ /* deal with 6110 chip bug */
+ im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
+ val = ipath_read_kreg64(dd, 0x1000+(im*sizeof(u64)));
+ dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
+ = le64_to_cpu(val);
+ }
+
+ /*
+ * force new interrupt if any hwerr, error or interrupt bits are
+ * still set, and clear "safe" send packet errors related to freeze
+ * and cancelling sends. Re-enable error interrupts before possible
+ * force of re-interrupt on pending interrupts.
+ */
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, 0ULL);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
+ E_SPKT_ERRS_IGNORE);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+ ~dd->ipath_maskederrs);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
+}
+
+
/* this is separate to allow for better optimization of ipath_intr() */
static void ipath_bad_intr(struct ipath_devdata *dd, u32 * unexpectp)
@@ -872,14 +965,25 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
dd->ipath_i_rcvurg_mask);
for (i = 1; i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
- if (portr & (1 << i) && pd && pd->port_cnt &&
- test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
- clear_bit(IPATH_PORT_WAITING_RCV,
- &pd->port_flag);
- clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
- &dd->ipath_rcvctrl);
- wake_up_interruptible(&pd->port_wait);
- rcvdint = 1;
+ if (portr & (1 << i) && pd && pd->port_cnt) {
+ if (test_bit(IPATH_PORT_WAITING_RCV,
+ &pd->port_flag)) {
+ clear_bit(IPATH_PORT_WAITING_RCV,
+ &pd->port_flag);
+ set_bit(IPATH_PORT_WAITING_RCV,
+ &pd->int_flag);
+ clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
+ &dd->ipath_rcvctrl);
+ wake_up_interruptible(&pd->port_wait);
+ rcvdint = 1;
+ } else if (test_bit(IPATH_PORT_WAITING_URG,
+ &pd->port_flag)) {
+ clear_bit(IPATH_PORT_WAITING_URG,
+ &pd->port_flag);
+ set_bit(IPATH_PORT_WAITING_URG,
+ &pd->int_flag);
+ wake_up_interruptible(&pd->port_wait);
+ }
}
}
if (rcvdint) {
@@ -905,6 +1009,9 @@ irqreturn_t ipath_intr(int irq, void *data)
ipath_stats.sps_ints++;
+ if (dd->ipath_int_counter != (u32) -1)
+ dd->ipath_int_counter++;
+
if (!(dd->ipath_flags & IPATH_PRESENT)) {
/*
* This return value is not great, but we do not want the
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 12194f3dd8cc..ace63ef78e6f 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -1,7 +1,7 @@
#ifndef _IPATH_KERNEL_H
#define _IPATH_KERNEL_H
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -57,6 +57,24 @@
extern struct infinipath_stats ipath_stats;
#define IPATH_CHIP_SWVERSION IPATH_CHIP_VERS_MAJ
+/*
+ * First-cut critierion for "device is active" is
+ * two thousand dwords combined Tx, Rx traffic per
+ * 5-second interval. SMA packets are 64 dwords,
+ * and occur "a few per second", presumably each way.
+ */
+#define IPATH_TRAFFIC_ACTIVE_THRESHOLD (2000)
+/*
+ * Struct used to indicate which errors are logged in each of the
+ * error-counters that are logged to EEPROM. A counter is incremented
+ * _once_ (saturating at 255) for each event with any bits set in
+ * the error or hwerror register masks below.
+ */
+#define IPATH_EEP_LOG_CNT (4)
+struct ipath_eep_log_mask {
+ u64 errs_to_log;
+ u64 hwerrs_to_log;
+};
struct ipath_portdata {
void **port_rcvegrbuf;
@@ -109,6 +127,8 @@ struct ipath_portdata {
u32 port_tidcursor;
/* next expected TID to check */
unsigned long port_flag;
+ /* what happened */
+ unsigned long int_flag;
/* WAIT_RCV that timed out, no interrupt */
u32 port_rcvwait_to;
/* WAIT_PIO that timed out, no interrupt */
@@ -137,6 +157,8 @@ struct ipath_portdata {
u32 userversion;
/* Bitmask of active slaves */
u32 active_slaves;
+ /* Type of packets or conditions we want to poll for */
+ u16 poll_type;
};
struct sk_buff;
@@ -275,6 +297,8 @@ struct ipath_devdata {
u32 ipath_lastport_piobuf;
/* is a stats timer active */
u32 ipath_stats_timer_active;
+ /* number of interrupts for this device -- saturates... */
+ u32 ipath_int_counter;
/* dwords sent read from counter */
u32 ipath_lastsword;
/* dwords received read from counter */
@@ -369,9 +393,6 @@ struct ipath_devdata {
struct class_device *diag_class_dev;
/* timer used to prevent stats overflow, error throttling, etc. */
struct timer_list ipath_stats_timer;
- /* check for stale messages in rcv queue */
- /* only allow one intr at a time. */
- unsigned long ipath_rcv_pending;
void *ipath_dummy_hdrq; /* used after port close */
dma_addr_t ipath_dummy_hdrq_phys;
@@ -399,6 +420,8 @@ struct ipath_devdata {
u64 ipath_gpio_out;
/* shadow the gpio mask register */
u64 ipath_gpio_mask;
+ /* shadow the gpio output enable, etc... */
+ u64 ipath_extctrl;
/* kr_revision shadow */
u64 ipath_revision;
/*
@@ -473,8 +496,6 @@ struct ipath_devdata {
u32 ipath_cregbase;
/* shadow the control register contents */
u32 ipath_control;
- /* shadow the gpio output contents */
- u32 ipath_extctrl;
/* PCI revision register (HTC rev on FPGA) */
u32 ipath_pcirev;
@@ -552,6 +573,9 @@ struct ipath_devdata {
u32 ipath_overrun_thresh_errs;
u32 ipath_lli_errs;
+ /* status check work */
+ struct delayed_work status_work;
+
/*
* Not all devices managed by a driver instance are the same
* type, so these fields must be per-device.
@@ -575,6 +599,37 @@ struct ipath_devdata {
u16 ipath_gpio_scl_num;
u64 ipath_gpio_sda;
u64 ipath_gpio_scl;
+
+ /* lock for doing RMW of shadows/regs for ExtCtrl and GPIO */
+ spinlock_t ipath_gpio_lock;
+
+ /* used to override LED behavior */
+ u8 ipath_led_override; /* Substituted for normal value, if non-zero */
+ u16 ipath_led_override_timeoff; /* delta to next timer event */
+ u8 ipath_led_override_vals[2]; /* Alternates per blink-frame */
+ u8 ipath_led_override_phase; /* Just counts, LSB picks from vals[] */
+ atomic_t ipath_led_override_timer_active;
+ /* Used to flash LEDs in override mode */
+ struct timer_list ipath_led_override_timer;
+
+ /* Support (including locks) for EEPROM logging of errors and time */
+ /* control access to actual counters, timer */
+ spinlock_t ipath_eep_st_lock;
+ /* control high-level access to EEPROM */
+ struct semaphore ipath_eep_sem;
+ /* Below inc'd by ipath_snap_cntrs(), locked by ipath_eep_st_lock */
+ uint64_t ipath_traffic_wds;
+ /* active time is kept in seconds, but logged in hours */
+ atomic_t ipath_active_time;
+ /* Below are nominal shadow of EEPROM, new since last EEPROM update */
+ uint8_t ipath_eep_st_errs[IPATH_EEP_LOG_CNT];
+ uint8_t ipath_eep_st_new_errs[IPATH_EEP_LOG_CNT];
+ uint16_t ipath_eep_hrs;
+ /*
+ * masks for which bits of errs, hwerrs that cause
+ * each of the counters to increment.
+ */
+ struct ipath_eep_log_mask ipath_eep_st_masks[IPATH_EEP_LOG_CNT];
};
/* Private data for file operations */
@@ -592,6 +647,7 @@ int ipath_enable_wc(struct ipath_devdata *dd);
void ipath_disable_wc(struct ipath_devdata *dd);
int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp);
void ipath_shutdown_device(struct ipath_devdata *);
+void ipath_clear_freeze(struct ipath_devdata *);
struct file_operations;
int ipath_cdev_init(int minor, char *name, const struct file_operations *fops,
@@ -627,6 +683,7 @@ int ipath_unordered_wc(void);
void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
unsigned cnt);
+void ipath_cancel_sends(struct ipath_devdata *);
int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *);
void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
@@ -685,7 +742,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
* are 64bit */
#define IPATH_32BITCOUNTERS 0x20000
/* can miss port0 rx interrupts */
-#define IPATH_POLL_RX_INTR 0x40000
#define IPATH_DISABLED 0x80000 /* administratively disabled */
/* Use GPIO interrupts for new counters */
#define IPATH_GPIO_ERRINTRS 0x100000
@@ -704,6 +760,10 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
#define IPATH_PORT_WAITING_PIO 3
/* master has not finished initializing */
#define IPATH_PORT_MASTER_UNINIT 4
+ /* waiting for an urgent packet to arrive */
+#define IPATH_PORT_WAITING_URG 5
+ /* waiting for a header overflow */
+#define IPATH_PORT_WAITING_OVERFLOW 6
/* free up any allocated data at closes */
void ipath_free_data(struct ipath_portdata *dd);
@@ -713,8 +773,18 @@ u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
void ipath_init_iba6120_funcs(struct ipath_devdata *);
void ipath_init_iba6110_funcs(struct ipath_devdata *);
void ipath_get_eeprom_info(struct ipath_devdata *);
+int ipath_update_eeprom_log(struct ipath_devdata *dd);
+void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
-void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
+
+/*
+ * Set LED override, only the two LSBs have "public" meaning, but
+ * any non-zero value substitutes them for the Link and LinkTrain
+ * LED states.
+ */
+#define IPATH_LED_PHYS 1 /* Physical (linktraining) GREEN LED */
+#define IPATH_LED_LOG 2 /* Logical (link) YELLOW LED */
+void ipath_set_led_override(struct ipath_devdata *dd, unsigned int val);
/*
* number of words used for protocol header if not set by ipath_userinit();
@@ -749,7 +819,6 @@ static inline u64 ipath_mdio_req(int cmd, int dev, int reg, int data)
#define IPATH_MDIO_CTRL_8355_REG_10 0x1D
int ipath_get_user_pages(unsigned long, size_t, struct page **);
-int ipath_get_user_pages_nocopy(unsigned long, struct page **);
void ipath_release_user_pages(struct page **, size_t);
void ipath_release_user_pages_on_close(struct page **, size_t);
int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int);
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index dd487c100f5b..85a4aefc6c03 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
deleted file mode 100644
index 05a1d2b01d9d..000000000000
--- a/drivers/infiniband/hw/ipath/ipath_layer.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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.
- */
-
-/*
- * These are the routines used by layered drivers, currently just the
- * layered ethernet driver and verbs layer.
- */
-
-#include <linux/io.h>
-#include <asm/byteorder.h>
-
-#include "ipath_kernel.h"
-#include "ipath_layer.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-/* Acquire before ipath_devs_lock. */
-static DEFINE_MUTEX(ipath_layer_mutex);
-
-u16 ipath_layer_rcv_opcode;
-
-static int (*layer_intr)(void *, u32);
-static int (*layer_rcv)(void *, void *, struct sk_buff *);
-static int (*layer_rcv_lid)(void *, void *);
-
-static void *(*layer_add_one)(int, struct ipath_devdata *);
-static void (*layer_remove_one)(void *);
-
-int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
-{
- int ret = -ENODEV;
-
- if (dd->ipath_layer.l_arg && layer_intr)
- ret = layer_intr(dd->ipath_layer.l_arg, arg);
-
- return ret;
-}
-
-int ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
-{
- int ret;
-
- mutex_lock(&ipath_layer_mutex);
-
- ret = __ipath_layer_intr(dd, arg);
-
- mutex_unlock(&ipath_layer_mutex);
-
- return ret;
-}
-
-int __ipath_layer_rcv(struct ipath_devdata *dd, void *hdr,
- struct sk_buff *skb)
-{
- int ret = -ENODEV;
-
- if (dd->ipath_layer.l_arg && layer_rcv)
- ret = layer_rcv(dd->ipath_layer.l_arg, hdr, skb);
-
- return ret;
-}
-
-int __ipath_layer_rcv_lid(struct ipath_devdata *dd, void *hdr)
-{
- int ret = -ENODEV;
-
- if (dd->ipath_layer.l_arg && layer_rcv_lid)
- ret = layer_rcv_lid(dd->ipath_layer.l_arg, hdr);
-
- return ret;
-}
-
-void ipath_layer_lid_changed(struct ipath_devdata *dd)
-{
- mutex_lock(&ipath_layer_mutex);
-
- if (dd->ipath_layer.l_arg && layer_intr)
- layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID);
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-void ipath_layer_add(struct ipath_devdata *dd)
-{
- mutex_lock(&ipath_layer_mutex);
-
- if (layer_add_one)
- dd->ipath_layer.l_arg =
- layer_add_one(dd->ipath_unit, dd);
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-void ipath_layer_remove(struct ipath_devdata *dd)
-{
- mutex_lock(&ipath_layer_mutex);
-
- if (dd->ipath_layer.l_arg && layer_remove_one) {
- layer_remove_one(dd->ipath_layer.l_arg);
- dd->ipath_layer.l_arg = NULL;
- }
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
- void (*l_remove)(void *),
- int (*l_intr)(void *, u32),
- int (*l_rcv)(void *, void *, struct sk_buff *),
- u16 l_rcv_opcode,
- int (*l_rcv_lid)(void *, void *))
-{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
- mutex_lock(&ipath_layer_mutex);
-
- layer_add_one = l_add;
- layer_remove_one = l_remove;
- layer_intr = l_intr;
- layer_rcv = l_rcv;
- layer_rcv_lid = l_rcv_lid;
- ipath_layer_rcv_opcode = l_rcv_opcode;
-
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- if (!(dd->ipath_flags & IPATH_INITTED))
- continue;
-
- if (dd->ipath_layer.l_arg)
- continue;
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd);
- spin_lock_irqsave(&ipath_devs_lock, flags);
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- mutex_unlock(&ipath_layer_mutex);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_register);
-
-void ipath_layer_unregister(void)
-{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
- mutex_lock(&ipath_layer_mutex);
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- if (dd->ipath_layer.l_arg && layer_remove_one) {
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- layer_remove_one(dd->ipath_layer.l_arg);
- spin_lock_irqsave(&ipath_devs_lock, flags);
- dd->ipath_layer.l_arg = NULL;
- }
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
- layer_add_one = NULL;
- layer_remove_one = NULL;
- layer_intr = NULL;
- layer_rcv = NULL;
- layer_rcv_lid = NULL;
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_unregister);
-
-int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax)
-{
- int ret;
- u32 intval = 0;
-
- mutex_lock(&ipath_layer_mutex);
-
- if (!dd->ipath_layer.l_arg) {
- ret = -EINVAL;
- goto bail;
- }
-
- ret = ipath_setrcvhdrsize(dd, IPATH_HEADER_QUEUE_WORDS);
-
- if (ret < 0)
- goto bail;
-
- *pktmax = dd->ipath_ibmaxlen;
-
- if (*dd->ipath_statusp & IPATH_STATUS_IB_READY)
- intval |= IPATH_LAYER_INT_IF_UP;
- if (dd->ipath_lid)
- intval |= IPATH_LAYER_INT_LID;
- if (dd->ipath_mlid)
- intval |= IPATH_LAYER_INT_BCAST;
- /*
- * do this on open, in case low level is already up and
- * just layered driver was reloaded, etc.
- */
- if (intval)
- layer_intr(dd->ipath_layer.l_arg, intval);
-
- ret = 0;
-bail:
- mutex_unlock(&ipath_layer_mutex);
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_open);
-
-u16 ipath_layer_get_lid(struct ipath_devdata *dd)
-{
- return dd->ipath_lid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_lid);
-
-/**
- * ipath_layer_get_mac - get the MAC address
- * @dd: the infinipath device
- * @mac: the MAC is put here
- *
- * This is the EUID-64 OUI octets (top 3), then
- * skip the next 2 (which should both be zero or 0xff).
- * The returned MAC is in network order
- * mac points to at least 6 bytes of buffer
- * We assume that by the time the LID is set, that the GUID is as valid
- * as it's ever going to be, rather than adding yet another status bit.
- */
-
-int ipath_layer_get_mac(struct ipath_devdata *dd, u8 * mac)
-{
- u8 *guid;
-
- guid = (u8 *) &dd->ipath_guid;
-
- mac[0] = guid[0];
- mac[1] = guid[1];
- mac[2] = guid[2];
- mac[3] = guid[5];
- mac[4] = guid[6];
- mac[5] = guid[7];
- if ((guid[3] || guid[4]) && !(guid[3] == 0xff && guid[4] == 0xff))
- ipath_dbg("Warning, guid bytes 3 and 4 not 0 or 0xffff: "
- "%x %x\n", guid[3], guid[4]);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_mac);
-
-u16 ipath_layer_get_bcast(struct ipath_devdata *dd)
-{
- return dd->ipath_mlid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_bcast);
-
-int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr)
-{
- int ret = 0;
- u32 __iomem *piobuf;
- u32 plen, *uhdr;
- size_t count;
- __be16 vlsllnh;
-
- if (!(dd->ipath_flags & IPATH_RCVHDRSZ_SET)) {
- ipath_dbg("send while not open\n");
- ret = -EINVAL;
- } else
- if ((dd->ipath_flags & (IPATH_LINKUNK | IPATH_LINKDOWN)) ||
- dd->ipath_lid == 0) {
- /*
- * lid check is for when sma hasn't yet configured
- */
- ret = -ENETDOWN;
- ipath_cdbg(VERBOSE, "send while not ready, "
- "mylid=%u, flags=0x%x\n",
- dd->ipath_lid, dd->ipath_flags);
- }
-
- vlsllnh = *((__be16 *) hdr);
- if (vlsllnh != htons(IPATH_LRH_BTH)) {
- ipath_dbg("Warning: lrh[0] wrong (%x, not %x); "
- "not sending\n", be16_to_cpu(vlsllnh),
- IPATH_LRH_BTH);
- ret = -EINVAL;
- }
- if (ret)
- goto done;
-
- /* Get a PIO buffer to use. */
- piobuf = ipath_getpiobuf(dd, NULL);
- if (piobuf == NULL) {
- ret = -EBUSY;
- goto done;
- }
-
- plen = (sizeof(*hdr) >> 2); /* actual length */
- ipath_cdbg(EPKT, "0x%x+1w pio %p\n", plen, piobuf);
-
- writeq(plen+1, piobuf); /* len (+1 for pad) to pbc, no flags */
- ipath_flush_wc();
- piobuf += 2;
- uhdr = (u32 *)hdr;
- count = plen-1; /* amount we can copy before trigger word */
- __iowrite32_copy(piobuf, uhdr, count);
- ipath_flush_wc();
- __raw_writel(uhdr[count], piobuf + count);
- ipath_flush_wc(); /* ensure it's sent, now */
-
- ipath_stats.sps_ether_spkts++; /* ether packet sent */
-
-done:
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_send_hdr);
-
-int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd)
-{
- set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
-
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- dd->ipath_sendctrl);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int);
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.h b/drivers/infiniband/hw/ipath/ipath_layer.h
deleted file mode 100644
index 3854a4eae684..000000000000
--- a/drivers/infiniband/hw/ipath/ipath_layer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * 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 _IPATH_LAYER_H
-#define _IPATH_LAYER_H
-
-/*
- * This header file is for symbols shared between the infinipath driver
- * and drivers layered upon it (such as ipath).
- */
-
-struct sk_buff;
-struct ipath_devdata;
-struct ether_header;
-
-int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
- void (*l_remove)(void *),
- int (*l_intr)(void *, u32),
- int (*l_rcv)(void *, void *,
- struct sk_buff *),
- u16 rcv_opcode,
- int (*l_rcv_lid)(void *, void *));
-void ipath_layer_unregister(void);
-int ipath_layer_open(struct ipath_devdata *, u32 * pktmax);
-u16 ipath_layer_get_lid(struct ipath_devdata *dd);
-int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *);
-u16 ipath_layer_get_bcast(struct ipath_devdata *dd);
-int ipath_layer_send_hdr(struct ipath_devdata *dd,
- struct ether_header *hdr);
-int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd);
-
-/* ipath_ether interrupt values */
-#define IPATH_LAYER_INT_IF_UP 0x2
-#define IPATH_LAYER_INT_IF_DOWN 0x4
-#define IPATH_LAYER_INT_LID 0x8
-#define IPATH_LAYER_INT_SEND_CONTINUE 0x10
-#define IPATH_LAYER_INT_BCAST 0x40
-
-extern unsigned ipath_debug; /* debugging bit mask */
-
-#endif /* _IPATH_LAYER_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index 25908b02fbe5..d61c03044545 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -103,7 +103,7 @@ static int recv_subn_get_nodeinfo(struct ib_smp *smp,
/* This is already in network order */
nip->sys_guid = to_idev(ibdev)->sys_image_guid;
nip->node_guid = dd->ipath_guid;
- nip->port_guid = nip->sys_guid;
+ nip->port_guid = dd->ipath_guid;
nip->partition_cap = cpu_to_be16(ipath_get_npkeys(dd));
nip->device_id = cpu_to_be16(dd->ipath_deviceid);
majrev = dd->ipath_majrev;
@@ -292,7 +292,12 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
/* pip->vl_arb_high_cap; // only one VL */
/* pip->vl_arb_low_cap; // only one VL */
/* InitTypeReply = 0 */
- pip->inittypereply_mtucap = IB_MTU_4096;
+ /*
+ * Note: the chips support a maximum MTU of 4096, but the driver
+ * hasn't implemented this feature yet, so set the maximum value
+ * to 2048.
+ */
+ pip->inittypereply_mtucap = IB_MTU_2048;
// HCAs ignore VLStallCount and HOQLife
/* pip->vlstallcnt_hoqlife; */
pip->operationalvl_pei_peo_fpi_fpo = 0x10; /* OVLs = 1 */
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c
index 937bc3396b53..fa830e22002f 100644
--- a/drivers/infiniband/hw/ipath/ipath_mmap.c
+++ b/drivers/infiniband/hw/ipath/ipath_mmap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index bdeef8d4f279..e442470a2375 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index bfef08ecd342..1324b35ff1f8 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -336,7 +336,7 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->qkey = 0;
qp->qp_access_flags = 0;
qp->s_busy = 0;
- qp->s_flags &= ~IPATH_S_SIGNAL_REQ_WR;
+ qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
qp->s_hdrwords = 0;
qp->s_psn = 0;
qp->r_psn = 0;
@@ -507,16 +507,13 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
attr->port_num > ibqp->device->phys_port_cnt)
goto inval;
+ /*
+ * Note: the chips support a maximum MTU of 4096, but the driver
+ * hasn't implemented this feature yet, so don't allow Path MTU
+ * values greater than 2048.
+ */
if (attr_mask & IB_QP_PATH_MTU)
- if (attr->path_mtu > IB_MTU_4096)
- goto inval;
-
- if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
- if (attr->max_dest_rd_atomic > 1)
- goto inval;
-
- if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
- if (attr->max_rd_atomic > 1)
+ if (attr->path_mtu > IB_MTU_2048)
goto inval;
if (attr_mask & IB_QP_PATH_MIG_STATE)
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 1915771fd038..46744ea2babd 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -125,8 +125,10 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
if (len > pmtu) {
len = pmtu;
qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
- } else
+ } else {
qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
+ e->sent = 1;
+ }
ohdr->u.aeth = ipath_compute_aeth(qp);
hwords++;
qp->s_ack_rdma_psn = e->psn;
@@ -143,6 +145,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
cpu_to_be32(e->atomic_data);
hwords += sizeof(ohdr->u.at) / sizeof(u32);
bth2 = e->psn;
+ e->sent = 1;
}
bth0 = qp->s_ack_state << 24;
break;
@@ -158,6 +161,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
ohdr->u.aeth = ipath_compute_aeth(qp);
hwords++;
qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
+ qp->s_ack_queue[qp->s_tail_ack_queue].sent = 1;
}
bth0 = qp->s_ack_state << 24;
bth2 = qp->s_ack_rdma_psn++ & IPATH_PSN_MASK;
@@ -188,7 +192,7 @@ static int ipath_make_rc_ack(struct ipath_qp *qp,
}
qp->s_hdrwords = hwords;
qp->s_cur_size = len;
- *bth0p = bth0;
+ *bth0p = bth0 | (1 << 22); /* Set M bit */
*bth2p = bth2;
return 1;
@@ -240,7 +244,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
- bth0 = 0;
+ bth0 = 1 << 22; /* Set M bit */
/* Send a request. */
wqe = get_swqe_ptr(qp, qp->s_cur);
@@ -604,7 +608,7 @@ static void send_rc_ack(struct ipath_qp *qp)
}
/* read pkey_index w/o lock (its atomic) */
bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index) |
- OP(ACKNOWLEDGE) << 24;
+ (OP(ACKNOWLEDGE) << 24) | (1 << 22);
if (qp->r_nak_state)
ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
(qp->r_nak_state <<
@@ -806,13 +810,15 @@ static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
* Called at interrupt level with the QP s_lock held and interrupts disabled.
* Returns 1 if OK, 0 if current operation should be aborted (NAK).
*/
-static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
+static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode,
+ u64 val)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ib_wc wc;
struct ipath_swqe *wqe;
int ret = 0;
u32 ack_psn;
+ int diff;
/*
* Remove the QP from the timeout queue (or RNR timeout queue).
@@ -840,7 +846,19 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* The MSN might be for a later WQE than the PSN indicates so
* only complete WQEs that the PSN finishes.
*/
- while (ipath_cmp24(ack_psn, wqe->lpsn) >= 0) {
+ while ((diff = ipath_cmp24(ack_psn, wqe->lpsn)) >= 0) {
+ /*
+ * RDMA_READ_RESPONSE_ONLY is a special case since
+ * we want to generate completion events for everything
+ * before the RDMA read, copy the data, then generate
+ * the completion for the read.
+ */
+ if (wqe->wr.opcode == IB_WR_RDMA_READ &&
+ opcode == OP(RDMA_READ_RESPONSE_ONLY) &&
+ diff == 0) {
+ ret = 1;
+ goto bail;
+ }
/*
* If this request is a RDMA read or atomic, and the ACK is
* for a later operation, this ACK NAKs the RDMA read or
@@ -851,12 +869,10 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* is sent but before the response is received.
*/
if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
- (opcode != OP(RDMA_READ_RESPONSE_LAST) ||
- ipath_cmp24(ack_psn, wqe->lpsn) != 0)) ||
+ (opcode != OP(RDMA_READ_RESPONSE_LAST) || diff != 0)) ||
((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) &&
- (opcode != OP(ATOMIC_ACKNOWLEDGE) ||
- ipath_cmp24(wqe->psn, psn) != 0))) {
+ (opcode != OP(ATOMIC_ACKNOWLEDGE) || diff != 0))) {
/*
* The last valid PSN seen is the previous
* request's.
@@ -870,6 +886,9 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
*/
goto bail;
}
+ if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+ wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
+ *(u64 *) wqe->sg_list[0].vaddr = val;
if (qp->s_num_rd_atomic &&
(wqe->wr.opcode == IB_WR_RDMA_READ ||
wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
@@ -1079,6 +1098,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
int diff;
u32 pad;
u32 aeth;
+ u64 val;
spin_lock_irqsave(&qp->s_lock, flags);
@@ -1118,8 +1138,6 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
data += sizeof(__be32);
}
if (opcode == OP(ATOMIC_ACKNOWLEDGE)) {
- u64 val;
-
if (!header_in_data) {
__be32 *p = ohdr->u.at.atomic_ack_eth;
@@ -1127,12 +1145,13 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
be32_to_cpu(p[1]);
} else
val = be64_to_cpu(((__be64 *) data)[0]);
- *(u64 *) wqe->sg_list[0].vaddr = val;
- }
- if (!do_rc_ack(qp, aeth, psn, opcode) ||
+ } else
+ val = 0;
+ if (!do_rc_ack(qp, aeth, psn, opcode, val) ||
opcode != OP(RDMA_READ_RESPONSE_FIRST))
goto ack_done;
hdrsize += 4;
+ wqe = get_swqe_ptr(qp, qp->s_last);
if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
goto ack_op_err;
/*
@@ -1176,13 +1195,12 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto bail;
case OP(RDMA_READ_RESPONSE_ONLY):
- if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
- dev->n_rdma_seq++;
- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ if (!header_in_data)
+ aeth = be32_to_cpu(ohdr->u.aeth);
+ else
+ aeth = be32_to_cpu(((__be32 *) data)[0]);
+ if (!do_rc_ack(qp, aeth, psn, opcode, 0))
goto ack_done;
- }
- if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ))
- goto ack_op_err;
/* Get the number of bytes the message was padded by. */
pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
/*
@@ -1197,6 +1215,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
* have to be careful to copy the data to the right
* location.
*/
+ wqe = get_swqe_ptr(qp, qp->s_last);
qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge,
wqe, psn, pmtu);
goto read_last;
@@ -1230,7 +1249,8 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
data += sizeof(__be32);
}
ipath_copy_sge(&qp->s_rdma_read_sge, data, tlen);
- (void) do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST));
+ (void) do_rc_ack(qp, aeth, psn,
+ OP(RDMA_READ_RESPONSE_LAST), 0);
goto ack_done;
}
@@ -1344,8 +1364,11 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
e = NULL;
break;
}
- if (ipath_cmp24(psn, e->psn) >= 0)
+ if (ipath_cmp24(psn, e->psn) >= 0) {
+ if (prev == qp->s_tail_ack_queue)
+ old_req = 0;
break;
+ }
}
switch (opcode) {
case OP(RDMA_READ_REQUEST): {
@@ -1460,6 +1483,22 @@ static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
spin_unlock_irqrestore(&qp->s_lock, flags);
}
+static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
+{
+ unsigned long flags;
+ unsigned next;
+
+ next = n + 1;
+ if (next > IPATH_MAX_RDMA_ATOMIC)
+ next = 0;
+ spin_lock_irqsave(&qp->s_lock, flags);
+ if (n == qp->s_tail_ack_queue) {
+ qp->s_tail_ack_queue = next;
+ qp->s_ack_state = OP(ACKNOWLEDGE);
+ }
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+}
+
/**
* ipath_rc_rcv - process an incoming RC packet
* @dev: the device this packet came in on
@@ -1672,6 +1711,9 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
case OP(RDMA_WRITE_FIRST):
case OP(RDMA_WRITE_ONLY):
case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE):
+ if (unlikely(!(qp->qp_access_flags &
+ IB_ACCESS_REMOTE_WRITE)))
+ goto nack_inv;
/* consume RWQE */
/* RETH comes after BTH */
if (!header_in_data)
@@ -1701,9 +1743,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
qp->r_sge.sge.length = 0;
qp->r_sge.sge.sge_length = 0;
}
- if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_WRITE)))
- goto nack_acc;
if (opcode == OP(RDMA_WRITE_FIRST))
goto send_middle;
else if (opcode == OP(RDMA_WRITE_ONLY))
@@ -1717,13 +1756,17 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
u32 len;
u8 next;
- if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ)))
- goto nack_acc;
+ if (unlikely(!(qp->qp_access_flags &
+ IB_ACCESS_REMOTE_READ)))
+ goto nack_inv;
next = qp->r_head_ack_queue + 1;
if (next > IPATH_MAX_RDMA_ATOMIC)
next = 0;
- if (unlikely(next == qp->s_tail_ack_queue))
- goto nack_inv;
+ if (unlikely(next == qp->s_tail_ack_queue)) {
+ if (!qp->s_ack_queue[next].sent)
+ goto nack_inv;
+ ipath_update_ack_queue(qp, next);
+ }
e = &qp->s_ack_queue[qp->r_head_ack_queue];
/* RETH comes after BTH */
if (!header_in_data)
@@ -1758,6 +1801,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
e->rdma_sge.sge.sge_length = 0;
}
e->opcode = opcode;
+ e->sent = 0;
e->psn = psn;
/*
* We need to increment the MSN here instead of when we
@@ -1789,12 +1833,15 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
if (unlikely(!(qp->qp_access_flags &
IB_ACCESS_REMOTE_ATOMIC)))
- goto nack_acc;
+ goto nack_inv;
next = qp->r_head_ack_queue + 1;
if (next > IPATH_MAX_RDMA_ATOMIC)
next = 0;
- if (unlikely(next == qp->s_tail_ack_queue))
- goto nack_inv;
+ if (unlikely(next == qp->s_tail_ack_queue)) {
+ if (!qp->s_ack_queue[next].sent)
+ goto nack_inv;
+ ipath_update_ack_queue(qp, next);
+ }
if (!header_in_data)
ateth = &ohdr->u.atomic_eth;
else
@@ -1819,6 +1866,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
be64_to_cpu(ateth->compare_data),
sdata);
e->opcode = opcode;
+ e->sent = 0;
e->psn = psn & IPATH_PSN_MASK;
qp->r_msn++;
qp->r_psn++;
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
index c182bcd62098..708eba3165d7 100644
--- a/drivers/infiniband/hw/ipath/ipath_registers.h
+++ b/drivers/infiniband/hw/ipath/ipath_registers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index d9c2a9b15d86..c69c25239443 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -194,6 +194,8 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
ret = 0;
goto bail;
}
+ /* Make sure entry is read after head index is read. */
+ smp_rmb();
wqe = get_rwqe_ptr(rq, tail);
if (++tail >= rq->size)
tail = 0;
@@ -267,7 +269,7 @@ again:
spin_lock_irqsave(&sqp->s_lock, flags);
if (!(ib_ipath_state_ops[sqp->state] & IPATH_PROCESS_SEND_OK) ||
- qp->s_rnr_timeout) {
+ sqp->s_rnr_timeout) {
spin_unlock_irqrestore(&sqp->s_lock, flags);
goto done;
}
@@ -319,12 +321,22 @@ again:
break;
case IB_WR_RDMA_WRITE_WITH_IMM:
+ if (unlikely(!(qp->qp_access_flags &
+ IB_ACCESS_REMOTE_WRITE))) {
+ wc.status = IB_WC_REM_INV_REQ_ERR;
+ goto err;
+ }
wc.wc_flags = IB_WC_WITH_IMM;
wc.imm_data = wqe->wr.imm_data;
if (!ipath_get_rwqe(qp, 1))
goto rnr_nak;
/* FALLTHROUGH */
case IB_WR_RDMA_WRITE:
+ if (unlikely(!(qp->qp_access_flags &
+ IB_ACCESS_REMOTE_WRITE))) {
+ wc.status = IB_WC_REM_INV_REQ_ERR;
+ goto err;
+ }
if (wqe->length == 0)
break;
if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
@@ -354,8 +366,10 @@ again:
case IB_WR_RDMA_READ:
if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_READ)))
- goto acc_err;
+ IB_ACCESS_REMOTE_READ))) {
+ wc.status = IB_WC_REM_INV_REQ_ERR;
+ goto err;
+ }
if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
@@ -369,8 +383,10 @@ again:
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_ATOMIC)))
- goto acc_err;
+ IB_ACCESS_REMOTE_ATOMIC))) {
+ wc.status = IB_WC_REM_INV_REQ_ERR;
+ goto err;
+ }
if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
wqe->wr.wr.atomic.remote_addr,
wqe->wr.wr.atomic.rkey,
@@ -396,6 +412,8 @@ again:
if (len > sge->length)
len = sge->length;
+ if (len > sge->sge_length)
+ len = sge->sge_length;
BUG_ON(len == 0);
ipath_copy_sge(&qp->r_sge, sge->vaddr, len);
sge->vaddr += len;
@@ -489,7 +507,7 @@ static int want_buffer(struct ipath_devdata *dd)
*
* Called when we run out of PIO buffers.
*/
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
+static void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
{
unsigned long flags;
@@ -503,11 +521,9 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
* could be called. If we are still in the tasklet function,
* tasklet_hi_schedule() will not call us until the next time
* tasklet_hi_schedule() is called.
- * We clear the tasklet flag now since we are committing to return
- * from the tasklet function.
+ * We leave the busy flag set so that another post send doesn't
+ * try to put the same QP on the piowait list again.
*/
- clear_bit(IPATH_S_BUSY, &qp->s_busy);
- tasklet_unlock(&qp->s_task);
want_buffer(dev->dd);
dev->n_piowait++;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
index 03acae66ba81..40c36ec19016 100644
--- a/drivers/infiniband/hw/ipath/ipath_srq.c
+++ b/drivers/infiniband/hw/ipath/ipath_srq.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -80,6 +80,8 @@ int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
wqe->num_sge = wr->num_sge;
for (i = 0; i < wr->num_sge; i++)
wqe->sg_list[i] = wr->sg_list[i];
+ /* Make sure queue entry is written before the head index. */
+ smp_wmb();
wq->head = next;
spin_unlock_irqrestore(&srq->rq.lock, flags);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index d8b5e4cefe25..73ed17d03188 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -55,6 +55,7 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
u64 val64;
unsigned long t0, t1;
u64 ret;
+ unsigned long flags;
t0 = jiffies;
/* If fast increment counters are only 32 bits, snapshot them,
@@ -91,12 +92,18 @@ u64 ipath_snap_cntr(struct ipath_devdata *dd, ipath_creg creg)
if (creg == dd->ipath_cregs->cr_wordsendcnt) {
if (val != dd->ipath_lastsword) {
dd->ipath_sword += val - dd->ipath_lastsword;
+ spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
+ dd->ipath_traffic_wds += val - dd->ipath_lastsword;
+ spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
dd->ipath_lastsword = val;
}
val64 = dd->ipath_sword;
} else if (creg == dd->ipath_cregs->cr_wordrcvcnt) {
if (val != dd->ipath_lastrword) {
dd->ipath_rword += val - dd->ipath_lastrword;
+ spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
+ dd->ipath_traffic_wds += val - dd->ipath_lastrword;
+ spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
dd->ipath_lastrword = val;
}
val64 = dd->ipath_rword;
@@ -200,6 +207,7 @@ void ipath_get_faststats(unsigned long opaque)
struct ipath_devdata *dd = (struct ipath_devdata *) opaque;
u32 val;
static unsigned cnt;
+ unsigned long flags;
/*
* don't access the chip while running diags, or memory diags can
@@ -210,9 +218,20 @@ void ipath_get_faststats(unsigned long opaque)
/* but re-arm the timer, for diags case; won't hurt other */
goto done;
+ /*
+ * We now try to maintain a "active timer", based on traffic
+ * exceeding a threshold, so we need to check the word-counts
+ * even if they are 64-bit.
+ */
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+ spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
+ if (dd->ipath_traffic_wds >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
+ atomic_add(5, &dd->ipath_active_time); /* S/B #define */
+ dd->ipath_traffic_wds = 0;
+ spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
+
if (dd->ipath_flags & IPATH_32BITCOUNTERS) {
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index 4dc398d5e011..16238cd3a036 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -596,6 +596,43 @@ bail:
return ret;
}
+static ssize_t store_led_override(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+ int ret;
+ u16 val;
+
+ ret = ipath_parse_ushort(buf, &val);
+ if (ret > 0)
+ ipath_set_led_override(dd, val);
+ else
+ ipath_dev_err(dd, "attempt to set invalid LED override\n");
+ return ret;
+}
+
+static ssize_t show_logged_errs(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+ int idx, count;
+
+ /* force consistency with actual EEPROM */
+ if (ipath_update_eeprom_log(dd) != 0)
+ return -ENXIO;
+
+ count = 0;
+ for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) {
+ count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c",
+ dd->ipath_eep_st_errs[idx],
+ idx == (IPATH_EEP_LOG_CNT - 1) ? '\n' : ' ');
+ }
+
+ return count;
+}
static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
@@ -625,6 +662,8 @@ static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL);
static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
+static DEVICE_ATTR(led_override, S_IWUSR, NULL, store_led_override);
+static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
static struct attribute *dev_attributes[] = {
&dev_attr_guid.attr,
@@ -641,6 +680,8 @@ static struct attribute *dev_attributes[] = {
&dev_attr_unit.attr,
&dev_attr_enabled.attr,
&dev_attr_rx_pol_inv.attr,
+ &dev_attr_led_override.attr,
+ &dev_attr_logged_errors.attr,
NULL
};
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 1c2b03c2ef5e..8380fbc50d2c 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -58,7 +58,6 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
wc->port_num = 0;
ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0);
}
- wqe = get_swqe_ptr(qp, qp->s_last);
}
/**
@@ -87,7 +86,7 @@ int ipath_make_uc_req(struct ipath_qp *qp,
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
- bth0 = 0;
+ bth0 = 1 << 22; /* Set M bit */
/* Get the next send request. */
wqe = get_swqe_ptr(qp, qp->s_last);
@@ -97,8 +96,10 @@ int ipath_make_uc_req(struct ipath_qp *qp,
* Signal the completion of the last send
* (if there is one).
*/
- if (qp->s_last != qp->s_tail)
+ if (qp->s_last != qp->s_tail) {
complete_last_send(qp, wqe, &wc);
+ wqe = get_swqe_ptr(qp, qp->s_last);
+ }
/* Check if send work queue is empty. */
if (qp->s_tail == qp->s_head)
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index a518f7c8fa83..f9a3338a5fb7 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -176,6 +176,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
dev->n_pkt_drops++;
goto bail_sge;
}
+ /* Make sure entry is read after head index is read. */
+ smp_rmb();
wqe = get_rwqe_ptr(rq, tail);
if (++tail >= rq->size)
tail = 0;
@@ -231,6 +233,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
if (len > length)
len = length;
+ if (len > sge->sge_length)
+ len = sge->sge_length;
BUG_ON(len == 0);
ipath_copy_sge(&rsge, sge->vaddr, len);
sge->vaddr += len;
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 8536aeb96af8..0190edc8044e 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -171,32 +171,6 @@ int ipath_get_user_pages(unsigned long start_page, size_t num_pages,
return ret;
}
-/**
- * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared
- * @start_page: the page to lock
- * @p: the output page structure
- *
- * This is similar to ipath_get_user_pages, but it's always one page, and we
- * mark the page as locked for I/O, and shared. This is used for the user
- * process page that contains the destination address for the rcvhdrq tail
- * update, so we need to have the vma. If we don't do this, the page can be
- * taken away from us on fork, even if the child never touches it, and then
- * the user process never sees the tail register updates.
- */
-int ipath_get_user_pages_nocopy(unsigned long page, struct page **p)
-{
- struct vm_area_struct *vma;
- int ret;
-
- down_write(&current->mm->mmap_sem);
-
- ret = __get_user_pages(page, 1, p, &vma);
-
- up_write(&current->mm->mmap_sem);
-
- return ret;
-}
-
void ipath_release_user_pages(struct page **p, size_t num_pages)
{
down_write(&current->mm->mmap_sem);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index bb70845279b8..16aa61fd8085 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -164,9 +164,11 @@ void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length)
while (length) {
u32 len = sge->length;
- BUG_ON(len == 0);
if (len > length)
len = length;
+ if (len > sge->sge_length)
+ len = sge->sge_length;
+ BUG_ON(len == 0);
memcpy(sge->vaddr, data, len);
sge->vaddr += len;
sge->length -= len;
@@ -202,9 +204,11 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
while (length) {
u32 len = sge->length;
- BUG_ON(len == 0);
if (len > length)
len = length;
+ if (len > sge->sge_length)
+ len = sge->sge_length;
+ BUG_ON(len == 0);
sge->vaddr += len;
sge->length -= len;
sge->sge_length -= len;
@@ -323,6 +327,8 @@ static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
wqe->num_sge = wr->num_sge;
for (i = 0; i < wr->num_sge; i++)
wqe->sg_list[i] = wr->sg_list[i];
+ /* Make sure queue entry is written before the head index. */
+ smp_wmb();
wq->head = next;
spin_unlock_irqrestore(&qp->r_rq.lock, flags);
}
@@ -482,7 +488,7 @@ bail:;
* This is called from ipath_do_rcv_timer() at interrupt level to check for
* QPs which need retransmits and to collect performance numbers.
*/
-void ipath_ib_timer(struct ipath_ibdev *dev)
+static void ipath_ib_timer(struct ipath_ibdev *dev)
{
struct ipath_qp *resend = NULL;
struct list_head *last;
@@ -948,6 +954,7 @@ int ipath_ib_piobufavail(struct ipath_ibdev *dev)
qp = list_entry(dev->piowait.next, struct ipath_qp,
piowait);
list_del_init(&qp->piowait);
+ clear_bit(IPATH_S_BUSY, &qp->s_busy);
tasklet_hi_schedule(&qp->s_task);
}
spin_unlock_irqrestore(&dev->pending_lock, flags);
@@ -981,6 +988,8 @@ static int ipath_query_device(struct ib_device *ibdev,
props->max_ah = ib_ipath_max_ahs;
props->max_cqe = ib_ipath_max_cqes;
props->max_mr = dev->lk_table.max;
+ props->max_fmr = dev->lk_table.max;
+ props->max_map_per_fmr = 32767;
props->max_pd = ib_ipath_max_pds;
props->max_qp_rd_atom = IPATH_MAX_RDMA_ATOMIC;
props->max_qp_init_rd_atom = 255;
@@ -1051,7 +1060,12 @@ static int ipath_query_port(struct ib_device *ibdev,
props->max_vl_num = 1; /* VLCap = VL0 */
props->init_type_reply = 0;
- props->max_mtu = IB_MTU_4096;
+ /*
+ * Note: the chips support a maximum MTU of 4096, but the driver
+ * hasn't implemented this feature yet, so set the maximum value
+ * to 2048.
+ */
+ props->max_mtu = IB_MTU_2048;
switch (dev->dd->ipath_ibmtu) {
case 4096:
mtu = IB_MTU_4096;
@@ -1361,13 +1375,6 @@ static void __verbs_timer(unsigned long arg)
{
struct ipath_devdata *dd = (struct ipath_devdata *) arg;
- /*
- * If port 0 receive packet interrupts are not available, or
- * can be missed, poll the receive queue
- */
- if (dd->ipath_flags & IPATH_POLL_RX_INTR)
- ipath_kreceive(dd);
-
/* Handle verbs layer timeouts. */
ipath_ib_timer(dd->verbs_dev);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 088b837ebea8..1a24c6a4a814 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -42,8 +42,6 @@
#include <rdma/ib_pack.h>
#include <rdma/ib_user_verbs.h>
-#include "ipath_layer.h"
-
#define IPATH_MAX_RDMA_ATOMIC 4
#define QPN_MAX (1 << 24)
@@ -321,6 +319,7 @@ struct ipath_sge_state {
*/
struct ipath_ack_entry {
u8 opcode;
+ u8 sent;
u32 psn;
union {
struct ipath_sge_state rdma_sge;
@@ -781,8 +780,6 @@ void ipath_update_mmap_info(struct ipath_ibdev *dev,
int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
-
void ipath_insert_rnr_queue(struct ipath_qp *qp);
int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
@@ -806,8 +803,6 @@ void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32);
int ipath_ib_piobufavail(struct ipath_ibdev *);
-void ipath_ib_timer(struct ipath_ibdev *);
-
unsigned ipath_get_npkeys(struct ipath_devdata *);
u32 ipath_get_cr_errpkey(struct ipath_devdata *);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
index dd691cfa5079..9e5abf9c309d 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
index 0095bb70f34e..1d7bd82a1fb1 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
index 04696e62da87..3428acb0868c 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -63,12 +63,29 @@ int ipath_enable_wc(struct ipath_devdata *dd)
* of 2 address matching the length (which has to be a power of 2).
* For rev1, that means the base address, for rev2, it will be just
* the PIO buffers themselves.
+ * For chips with two sets of buffers, the calculations are
+ * somewhat more complicated; we need to sum, and the piobufbase
+ * register has both offsets, 2K in low 32 bits, 4K in high 32 bits.
+ * The buffers are still packed, so a single range covers both.
*/
- pioaddr = addr + dd->ipath_piobufbase;
- piolen = (dd->ipath_piobcnt2k +
- dd->ipath_piobcnt4k) *
- ALIGN(dd->ipath_piobcnt2k +
- dd->ipath_piobcnt4k, dd->ipath_palign);
+ if (dd->ipath_piobcnt2k && dd->ipath_piobcnt4k) { /* 2 sizes */
+ unsigned long pio2kbase, pio4kbase;
+ pio2kbase = dd->ipath_piobufbase & 0xffffffffUL;
+ pio4kbase = (dd->ipath_piobufbase >> 32) & 0xffffffffUL;
+ if (pio2kbase < pio4kbase) { /* all, for now */
+ pioaddr = addr + pio2kbase;
+ piolen = pio4kbase - pio2kbase +
+ dd->ipath_piobcnt4k * dd->ipath_4kalign;
+ } else {
+ pioaddr = addr + pio4kbase;
+ piolen = pio2kbase - pio4kbase +
+ dd->ipath_piobcnt2k * dd->ipath_palign;
+ }
+ } else { /* single buffer size (2K, currently) */
+ pioaddr = addr + dd->ipath_piobufbase;
+ piolen = dd->ipath_piobcnt2k * dd->ipath_palign +
+ dd->ipath_piobcnt4k * dd->ipath_4kalign;
+ }
for (bits = 0; !(piolen & (1ULL << bits)); bits++)
/* do nothing */ ;
diff --git a/drivers/infiniband/hw/mlx4/Kconfig b/drivers/infiniband/hw/mlx4/Kconfig
index b8912cdb9663..4175a4bd0c78 100644
--- a/drivers/infiniband/hw/mlx4/Kconfig
+++ b/drivers/infiniband/hw/mlx4/Kconfig
@@ -1,6 +1,5 @@
config MLX4_INFINIBAND
tristate "Mellanox ConnectX HCA support"
- depends on INFINIBAND
select MLX4_CORE
---help---
This driver provides low-level InfiniBand support for
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index c591616dccde..dde8fe9af47e 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -169,7 +169,7 @@ static int mlx4_ib_query_port(struct ib_device *ibdev, u8 port,
props->phys_state = out_mad->data[33] >> 4;
props->port_cap_flags = be32_to_cpup((__be32 *) (out_mad->data + 20));
props->gid_tbl_len = to_mdev(ibdev)->dev->caps.gid_table_len[port];
- props->max_msg_sz = 0x80000000;
+ props->max_msg_sz = to_mdev(ibdev)->dev->caps.max_msg_sz;
props->pkey_tbl_len = to_mdev(ibdev)->dev->caps.pkey_table_len[port];
props->bad_pkey_cntr = be16_to_cpup((__be16 *) (out_mad->data + 46));
props->qkey_viol_cntr = be16_to_cpup((__be16 *) (out_mad->data + 48));
@@ -523,11 +523,13 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
(1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
(1ull << IB_USER_VERBS_CMD_CREATE_QP) |
(1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
(1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
(1ull << IB_USER_VERBS_CMD_DETACH_MCAST) |
(1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
(1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
ibdev->ib_dev.query_device = mlx4_ib_query_device;
@@ -546,10 +548,12 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->ib_dev.destroy_ah = mlx4_ib_destroy_ah;
ibdev->ib_dev.create_srq = mlx4_ib_create_srq;
ibdev->ib_dev.modify_srq = mlx4_ib_modify_srq;
+ ibdev->ib_dev.query_srq = mlx4_ib_query_srq;
ibdev->ib_dev.destroy_srq = mlx4_ib_destroy_srq;
ibdev->ib_dev.post_srq_recv = mlx4_ib_post_srq_recv;
ibdev->ib_dev.create_qp = mlx4_ib_create_qp;
ibdev->ib_dev.modify_qp = mlx4_ib_modify_qp;
+ ibdev->ib_dev.query_qp = mlx4_ib_query_qp;
ibdev->ib_dev.destroy_qp = mlx4_ib_destroy_qp;
ibdev->ib_dev.post_send = mlx4_ib_post_send;
ibdev->ib_dev.post_recv = mlx4_ib_post_recv;
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 24ccadd6e4f8..705ff2fa237e 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -35,6 +35,7 @@
#include <linux/compiler.h>
#include <linux/list.h>
+#include <linux/mutex.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_umem.h>
@@ -255,6 +256,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
struct ib_udata *udata);
int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
+int mlx4_ib_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
int mlx4_ib_destroy_srq(struct ib_srq *srq);
void mlx4_ib_free_srq_wqe(struct mlx4_ib_srq *srq, int wqe_index);
int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
@@ -266,6 +268,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd,
int mlx4_ib_destroy_qp(struct ib_qp *qp);
int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
+int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+ struct ib_qp_init_attr *qp_init_attr);
int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr);
int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 28a08bdd1800..f6315dfb213e 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -415,9 +415,11 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
return 0;
err_wrid:
- if (pd->uobject && !init_attr->srq)
- mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
- else {
+ if (pd->uobject) {
+ if (!init_attr->srq)
+ mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context),
+ &qp->db);
+ } else {
kfree(qp->sq.wrid);
kfree(qp->rq.wrid);
}
@@ -742,7 +744,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
printk(KERN_ERR "path MTU (%u) is invalid\n",
attr->path_mtu);
- return -EINVAL;
+ goto out;
}
context->mtu_msgmax = (attr->path_mtu << 5) | 31;
}
@@ -781,10 +783,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_AV) {
if (mlx4_set_path(dev, &attr->ah_attr, &context->pri_path,
- attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) {
- err = -EINVAL;
+ attr_mask & IB_QP_PORT ? attr->port_num : qp->port))
goto out;
- }
optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH |
MLX4_QP_OPTPAR_SCHED_QUEUE);
@@ -798,15 +798,15 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
if (attr_mask & IB_QP_ALT_PATH) {
if (attr->alt_port_num == 0 ||
attr->alt_port_num > dev->dev->caps.num_ports)
- return -EINVAL;
+ goto out;
if (attr->alt_pkey_index >=
dev->dev->caps.pkey_table_len[attr->alt_port_num])
- return -EINVAL;
+ goto out;
if (mlx4_set_path(dev, &attr->alt_ah_attr, &context->alt_path,
attr->alt_port_num))
- return -EINVAL;
+ goto out;
context->alt_path.pkey_index = attr->alt_pkey_index;
context->alt_path.ackto = attr->alt_timeout << 3;
@@ -1183,6 +1183,43 @@ static int mlx4_wq_overflow(struct mlx4_ib_wq *wq, int nreq, struct ib_cq *ib_cq
return cur + nreq >= wq->max_post;
}
+static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg,
+ u64 remote_addr, u32 rkey)
+{
+ rseg->raddr = cpu_to_be64(remote_addr);
+ rseg->rkey = cpu_to_be32(rkey);
+ rseg->reserved = 0;
+}
+
+static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+{
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+ aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add);
+ } else {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+ aseg->compare = 0;
+ }
+
+}
+
+static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
+ struct ib_send_wr *wr)
+{
+ memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
+ dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+ dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_data_seg(struct mlx4_wqe_data_seg *dseg,
+ struct ib_sge *sg)
+{
+ dseg->byte_count = cpu_to_be32(sg->length);
+ dseg->lkey = cpu_to_be32(sg->lkey);
+ dseg->addr = cpu_to_be64(sg->addr);
+}
+
int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
@@ -1238,26 +1275,13 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.atomic.remote_addr);
- ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.atomic.rkey);
- ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
wqe += sizeof (struct mlx4_wqe_raddr_seg);
- if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
- ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.swap);
- ((struct mlx4_wqe_atomic_seg *) wqe)->compare =
- cpu_to_be64(wr->wr.atomic.compare_add);
- } else {
- ((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.compare_add);
- ((struct mlx4_wqe_atomic_seg *) wqe)->compare = 0;
- }
-
+ set_atomic_seg(wqe, wr);
wqe += sizeof (struct mlx4_wqe_atomic_seg);
+
size += (sizeof (struct mlx4_wqe_raddr_seg) +
sizeof (struct mlx4_wqe_atomic_seg)) / 16;
@@ -1266,15 +1290,10 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_RDMA_READ:
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
wqe += sizeof (struct mlx4_wqe_raddr_seg);
size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
-
break;
default:
@@ -1284,13 +1303,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
case IB_QPT_UD:
- memcpy(((struct mlx4_wqe_datagram_seg *) wqe)->av,
- &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
- ((struct mlx4_wqe_datagram_seg *) wqe)->dqpn =
- cpu_to_be32(wr->wr.ud.remote_qpn);
- ((struct mlx4_wqe_datagram_seg *) wqe)->qkey =
- cpu_to_be32(wr->wr.ud.remote_qkey);
-
+ set_datagram_seg(wqe, wr);
wqe += sizeof (struct mlx4_wqe_datagram_seg);
size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
break;
@@ -1313,12 +1326,7 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mlx4_wqe_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mlx4_wqe_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mlx4_wqe_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ set_data_seg(wqe, wr->sg_list + i);
wqe += sizeof (struct mlx4_wqe_data_seg);
size += sizeof (struct mlx4_wqe_data_seg) / 16;
@@ -1455,3 +1463,151 @@ out:
return err;
}
+
+static inline enum ib_qp_state to_ib_qp_state(enum mlx4_qp_state mlx4_state)
+{
+ switch (mlx4_state) {
+ case MLX4_QP_STATE_RST: return IB_QPS_RESET;
+ case MLX4_QP_STATE_INIT: return IB_QPS_INIT;
+ case MLX4_QP_STATE_RTR: return IB_QPS_RTR;
+ case MLX4_QP_STATE_RTS: return IB_QPS_RTS;
+ case MLX4_QP_STATE_SQ_DRAINING:
+ case MLX4_QP_STATE_SQD: return IB_QPS_SQD;
+ case MLX4_QP_STATE_SQER: return IB_QPS_SQE;
+ case MLX4_QP_STATE_ERR: return IB_QPS_ERR;
+ default: return -1;
+ }
+}
+
+static inline enum ib_mig_state to_ib_mig_state(int mlx4_mig_state)
+{
+ switch (mlx4_mig_state) {
+ case MLX4_QP_PM_ARMED: return IB_MIG_ARMED;
+ case MLX4_QP_PM_REARM: return IB_MIG_REARM;
+ case MLX4_QP_PM_MIGRATED: return IB_MIG_MIGRATED;
+ default: return -1;
+ }
+}
+
+static int to_ib_qp_access_flags(int mlx4_flags)
+{
+ int ib_flags = 0;
+
+ if (mlx4_flags & MLX4_QP_BIT_RRE)
+ ib_flags |= IB_ACCESS_REMOTE_READ;
+ if (mlx4_flags & MLX4_QP_BIT_RWE)
+ ib_flags |= IB_ACCESS_REMOTE_WRITE;
+ if (mlx4_flags & MLX4_QP_BIT_RAE)
+ ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
+
+ return ib_flags;
+}
+
+static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
+ struct mlx4_qp_path *path)
+{
+ memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
+ ib_ah_attr->port_num = path->sched_queue & 0x40 ? 2 : 1;
+
+ if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
+ return;
+
+ ib_ah_attr->dlid = be16_to_cpu(path->rlid);
+ ib_ah_attr->sl = (path->sched_queue >> 2) & 0xf;
+ ib_ah_attr->src_path_bits = path->grh_mylmc & 0x7f;
+ ib_ah_attr->static_rate = path->static_rate ? path->static_rate - 5 : 0;
+ ib_ah_attr->ah_flags = (path->grh_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
+ if (ib_ah_attr->ah_flags) {
+ ib_ah_attr->grh.sgid_index = path->mgid_index;
+ ib_ah_attr->grh.hop_limit = path->hop_limit;
+ ib_ah_attr->grh.traffic_class =
+ (be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
+ ib_ah_attr->grh.flow_label =
+ be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
+ memcpy(ib_ah_attr->grh.dgid.raw,
+ path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
+ }
+}
+
+int mlx4_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
+ struct ib_qp_init_attr *qp_init_attr)
+{
+ struct mlx4_ib_dev *dev = to_mdev(ibqp->device);
+ struct mlx4_ib_qp *qp = to_mqp(ibqp);
+ struct mlx4_qp_context context;
+ int mlx4_state;
+ int err;
+
+ if (qp->state == IB_QPS_RESET) {
+ qp_attr->qp_state = IB_QPS_RESET;
+ goto done;
+ }
+
+ err = mlx4_qp_query(dev->dev, &qp->mqp, &context);
+ if (err)
+ return -EINVAL;
+
+ mlx4_state = be32_to_cpu(context.flags) >> 28;
+
+ qp_attr->qp_state = to_ib_qp_state(mlx4_state);
+ qp_attr->path_mtu = context.mtu_msgmax >> 5;
+ qp_attr->path_mig_state =
+ to_ib_mig_state((be32_to_cpu(context.flags) >> 11) & 0x3);
+ qp_attr->qkey = be32_to_cpu(context.qkey);
+ qp_attr->rq_psn = be32_to_cpu(context.rnr_nextrecvpsn) & 0xffffff;
+ qp_attr->sq_psn = be32_to_cpu(context.next_send_psn) & 0xffffff;
+ qp_attr->dest_qp_num = be32_to_cpu(context.remote_qpn) & 0xffffff;
+ qp_attr->qp_access_flags =
+ to_ib_qp_access_flags(be32_to_cpu(context.params2));
+
+ if (qp->ibqp.qp_type == IB_QPT_RC || qp->ibqp.qp_type == IB_QPT_UC) {
+ to_ib_ah_attr(dev->dev, &qp_attr->ah_attr, &context.pri_path);
+ to_ib_ah_attr(dev->dev, &qp_attr->alt_ah_attr, &context.alt_path);
+ qp_attr->alt_pkey_index = context.alt_path.pkey_index & 0x7f;
+ qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
+ }
+
+ qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f;
+ if (qp_attr->qp_state == IB_QPS_INIT)
+ qp_attr->port_num = qp->port;
+ else
+ qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1;
+
+ /* qp_attr->en_sqd_async_notify is only applicable in modify qp */
+ qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING;
+
+ qp_attr->max_rd_atomic = 1 << ((be32_to_cpu(context.params1) >> 21) & 0x7);
+
+ qp_attr->max_dest_rd_atomic =
+ 1 << ((be32_to_cpu(context.params2) >> 21) & 0x7);
+ qp_attr->min_rnr_timer =
+ (be32_to_cpu(context.rnr_nextrecvpsn) >> 24) & 0x1f;
+ qp_attr->timeout = context.pri_path.ackto >> 3;
+ qp_attr->retry_cnt = (be32_to_cpu(context.params1) >> 16) & 0x7;
+ qp_attr->rnr_retry = (be32_to_cpu(context.params1) >> 13) & 0x7;
+ qp_attr->alt_timeout = context.alt_path.ackto >> 3;
+
+done:
+ qp_attr->cur_qp_state = qp_attr->qp_state;
+ qp_attr->cap.max_recv_wr = qp->rq.wqe_cnt;
+ qp_attr->cap.max_recv_sge = qp->rq.max_gs;
+
+ if (!ibqp->uobject) {
+ qp_attr->cap.max_send_wr = qp->sq.wqe_cnt;
+ qp_attr->cap.max_send_sge = qp->sq.max_gs;
+ } else {
+ qp_attr->cap.max_send_wr = 0;
+ qp_attr->cap.max_send_sge = 0;
+ }
+
+ /*
+ * We don't support inline sends for kernel QPs (yet), and we
+ * don't know what userspace's value should be.
+ */
+ qp_attr->cap.max_inline_data = 0;
+
+ qp_init_attr->cap = qp_attr->cap;
+
+ return 0;
+}
+
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 12fac1c8989d..408748fb5285 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -240,6 +240,24 @@ int mlx4_ib_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
return 0;
}
+int mlx4_ib_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+ struct mlx4_ib_dev *dev = to_mdev(ibsrq->device);
+ struct mlx4_ib_srq *srq = to_msrq(ibsrq);
+ int ret;
+ int limit_watermark;
+
+ ret = mlx4_srq_query(dev->dev, &srq->msrq, &limit_watermark);
+ if (ret)
+ return ret;
+
+ srq_attr->srq_limit = be16_to_cpu(limit_watermark);
+ srq_attr->max_wr = srq->msrq.max - 1;
+ srq_attr->max_sge = srq->msrq.max_gs;
+
+ return 0;
+}
+
int mlx4_ib_destroy_srq(struct ib_srq *srq)
{
struct mlx4_ib_dev *dev = to_mdev(srq->device);
diff --git a/drivers/infiniband/hw/mthca/Kconfig b/drivers/infiniband/hw/mthca/Kconfig
index 9aa5a4468a75..03efc074967e 100644
--- a/drivers/infiniband/hw/mthca/Kconfig
+++ b/drivers/infiniband/hw/mthca/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_MTHCA
tristate "Mellanox HCA support"
- depends on PCI && INFINIBAND
+ depends on PCI
---help---
This is a low-level driver for Mellanox InfiniHost host
channel adapters (HCAs), including the MT23108 PCI-X HCA
diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c
index f930e55b58fc..a76306709618 100644
--- a/drivers/infiniband/hw/mthca/mthca_allocator.c
+++ b/drivers/infiniband/hw/mthca/mthca_allocator.c
@@ -255,7 +255,7 @@ int mthca_buf_alloc(struct mthca_dev *dev, int size, int max_direct,
dma_list[i] = t;
pci_unmap_addr_set(&buf->page_list[i], mapping, t);
- memset(buf->page_list[i].buf, 0, PAGE_SIZE);
+ clear_page(buf->page_list[i].buf);
}
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index f40558d76475..acc95892713a 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -357,8 +357,6 @@ void mthca_cmd_event(struct mthca_dev *dev,
context->status = status;
context->out_param = out_param;
- context->token += dev->cmd.token_mask + 1;
-
complete(&context->done);
}
@@ -380,6 +378,7 @@ static int mthca_cmd_wait(struct mthca_dev *dev,
spin_lock(&dev->cmd.context_lock);
BUG_ON(dev->cmd.free_head < 0);
context = &dev->cmd.context[dev->cmd.free_head];
+ context->token += dev->cmd.token_mask + 1;
dev->cmd.free_head = context->next;
spin_unlock(&dev->cmd.context_lock);
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index 8ec9fa1ff9ea..8592b26dc4e1 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -522,7 +522,7 @@ static int mthca_create_eq(struct mthca_dev *dev,
dma_list[i] = t;
pci_unmap_addr_set(&eq->page_list[i], mapping, t);
- memset(eq->page_list[i].buf, 0, PAGE_SIZE);
+ clear_page(eq->page_list[i].buf);
}
for (i = 0; i < eq->nent; ++i)
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index aa563e61de65..76fed7545c53 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
static int msi = 0;
module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
+MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
#else /* CONFIG_PCI_MSI */
@@ -1117,9 +1117,21 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
if (msi_x && !mthca_enable_msi_x(mdev))
mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
- if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) &&
- !pci_enable_msi(pdev))
- mdev->mthca_flags |= MTHCA_FLAG_MSI;
+ else if (msi) {
+ static int warned;
+
+ if (!warned) {
+ printk(KERN_WARNING PFX "WARNING: MSI support will be "
+ "removed from the ib_mthca driver in January 2008.\n");
+ printk(KERN_WARNING " If you are using MSI and cannot "
+ "switch to MSI-X, please tell "
+ "<general@lists.openfabrics.org>.\n");
+ ++warned;
+ }
+
+ if (!pci_enable_msi(pdev))
+ mdev->mthca_flags |= MTHCA_FLAG_MSI;
+ }
if (mthca_cmd_init(mdev)) {
mthca_err(mdev, "Failed to init command interface, aborting.\n");
@@ -1135,7 +1147,7 @@ static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
goto err_cmd;
if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {
- mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n",
+ mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n",
(int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
(int) (mdev->fw_ver & 0xffff),
(int) (mthca_hca_table[hca_type].latest_fw >> 32),
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index eef415b12b2e..df01b2026a64 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1578,6 +1578,45 @@ static inline int mthca_wq_overflow(struct mthca_wq *wq, int nreq,
return cur + nreq >= wq->max;
}
+static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg,
+ u64 remote_addr, u32 rkey)
+{
+ rseg->raddr = cpu_to_be64(remote_addr);
+ rseg->rkey = cpu_to_be32(rkey);
+ rseg->reserved = 0;
+}
+
+static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg,
+ struct ib_send_wr *wr)
+{
+ if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+ aseg->compare = cpu_to_be64(wr->wr.atomic.compare_add);
+ } else {
+ aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+ aseg->compare = 0;
+ }
+
+}
+
+static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg,
+ struct ib_send_wr *wr)
+{
+ useg->lkey = cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
+ useg->av_addr = cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
+ useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+ useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg,
+ struct ib_send_wr *wr)
+{
+ memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
+ useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+ useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
@@ -1590,8 +1629,15 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int nreq;
int i;
int size;
- int size0 = 0;
- u32 f0;
+ /*
+ * f0 and size0 are only used if nreq != 0, and they will
+ * always be initialized the first time through the main loop
+ * before nreq is incremented. So nreq cannot become non-zero
+ * without initializing f0 and size0, and they are in fact
+ * never used uninitialized.
+ */
+ int uninitialized_var(size0);
+ u32 uninitialized_var(f0);
int ind;
u8 op0 = 0;
@@ -1636,25 +1682,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.atomic.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.atomic.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
wqe += sizeof (struct mthca_raddr_seg);
- if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.swap);
- ((struct mthca_atomic_seg *) wqe)->compare =
- cpu_to_be64(wr->wr.atomic.compare_add);
- } else {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.compare_add);
- ((struct mthca_atomic_seg *) wqe)->compare = 0;
- }
-
+ set_atomic_seg(wqe, wr);
wqe += sizeof (struct mthca_atomic_seg);
size += (sizeof (struct mthca_raddr_seg) +
sizeof (struct mthca_atomic_seg)) / 16;
@@ -1663,12 +1695,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
case IB_WR_RDMA_READ:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -1683,12 +1712,9 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -1700,16 +1726,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
case UD:
- ((struct mthca_tavor_ud_seg *) wqe)->lkey =
- cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
- ((struct mthca_tavor_ud_seg *) wqe)->av_addr =
- cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
- ((struct mthca_tavor_ud_seg *) wqe)->dqpn =
- cpu_to_be32(wr->wr.ud.remote_qpn);
- ((struct mthca_tavor_ud_seg *) wqe)->qkey =
- cpu_to_be32(wr->wr.ud.remote_qkey);
-
- wqe += sizeof (struct mthca_tavor_ud_seg);
+ set_tavor_ud_seg(wqe, wr);
+ wqe += sizeof (struct mthca_tavor_ud_seg);
size += sizeof (struct mthca_tavor_ud_seg) / 16;
break;
@@ -1734,13 +1752,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
- wqe += sizeof (struct mthca_data_seg);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
+ wqe += sizeof (struct mthca_data_seg);
size += sizeof (struct mthca_data_seg) / 16;
}
@@ -1768,11 +1781,11 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
mthca_opcode[wr->opcode]);
wmb();
((struct mthca_next_seg *) prev_wqe)->ee_nds =
- cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+ cpu_to_be32((nreq ? 0 : MTHCA_NEXT_DBD) | size |
((wr->send_flags & IB_SEND_FENCE) ?
MTHCA_NEXT_FENCE : 0));
- if (!size0) {
+ if (!nreq) {
size0 = size;
op0 = mthca_opcode[wr->opcode];
f0 = wr->send_flags & IB_SEND_FENCE ?
@@ -1822,7 +1835,14 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
int nreq;
int i;
int size;
- int size0 = 0;
+ /*
+ * size0 is only used if nreq != 0, and it will always be
+ * initialized the first time through the main loop before
+ * nreq is incremented. So nreq cannot become non-zero
+ * without initializing size0, and it is in fact never used
+ * uninitialized.
+ */
+ int uninitialized_var(size0);
int ind;
void *wqe;
void *prev_wqe;
@@ -1863,13 +1883,8 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
- wqe += sizeof (struct mthca_data_seg);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
+ wqe += sizeof (struct mthca_data_seg);
size += sizeof (struct mthca_data_seg) / 16;
}
@@ -1881,7 +1896,7 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
((struct mthca_next_seg *) prev_wqe)->ee_nds =
cpu_to_be32(MTHCA_NEXT_DBD | size);
- if (!size0)
+ if (!nreq)
size0 = size;
++ind;
@@ -1903,7 +1918,6 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
qp->rq.next_ind = ind;
qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
- size0 = 0;
}
}
@@ -1945,8 +1959,15 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int nreq;
int i;
int size;
- int size0 = 0;
- u32 f0;
+ /*
+ * f0 and size0 are only used if nreq != 0, and they will
+ * always be initialized the first time through the main loop
+ * before nreq is incremented. So nreq cannot become non-zero
+ * without initializing f0 and size0, and they are in fact
+ * never used uninitialized.
+ */
+ int uninitialized_var(size0);
+ u32 uninitialized_var(f0);
int ind;
u8 op0 = 0;
@@ -1966,7 +1987,6 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB;
- size0 = 0;
/*
* Make sure that descriptors are written before
@@ -2017,26 +2037,12 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.atomic.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.atomic.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+ set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+ wr->wr.atomic.rkey);
wqe += sizeof (struct mthca_raddr_seg);
- if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.swap);
- ((struct mthca_atomic_seg *) wqe)->compare =
- cpu_to_be64(wr->wr.atomic.compare_add);
- } else {
- ((struct mthca_atomic_seg *) wqe)->swap_add =
- cpu_to_be64(wr->wr.atomic.compare_add);
- ((struct mthca_atomic_seg *) wqe)->compare = 0;
- }
-
- wqe += sizeof (struct mthca_atomic_seg);
+ set_atomic_seg(wqe, wr);
+ wqe += sizeof (struct mthca_atomic_seg);
size += (sizeof (struct mthca_raddr_seg) +
sizeof (struct mthca_atomic_seg)) / 16;
break;
@@ -2044,12 +2050,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
case IB_WR_RDMA_READ:
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -2064,12 +2067,9 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (wr->opcode) {
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- ((struct mthca_raddr_seg *) wqe)->raddr =
- cpu_to_be64(wr->wr.rdma.remote_addr);
- ((struct mthca_raddr_seg *) wqe)->rkey =
- cpu_to_be32(wr->wr.rdma.rkey);
- ((struct mthca_raddr_seg *) wqe)->reserved = 0;
- wqe += sizeof (struct mthca_raddr_seg);
+ set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+ wr->wr.rdma.rkey);
+ wqe += sizeof (struct mthca_raddr_seg);
size += sizeof (struct mthca_raddr_seg) / 16;
break;
@@ -2081,14 +2081,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
case UD:
- memcpy(((struct mthca_arbel_ud_seg *) wqe)->av,
- to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
- ((struct mthca_arbel_ud_seg *) wqe)->dqpn =
- cpu_to_be32(wr->wr.ud.remote_qpn);
- ((struct mthca_arbel_ud_seg *) wqe)->qkey =
- cpu_to_be32(wr->wr.ud.remote_qkey);
-
- wqe += sizeof (struct mthca_arbel_ud_seg);
+ set_arbel_ud_seg(wqe, wr);
+ wqe += sizeof (struct mthca_arbel_ud_seg);
size += sizeof (struct mthca_arbel_ud_seg) / 16;
break;
@@ -2113,13 +2107,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
- wqe += sizeof (struct mthca_data_seg);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
+ wqe += sizeof (struct mthca_data_seg);
size += sizeof (struct mthca_data_seg) / 16;
}
@@ -2151,7 +2140,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
((wr->send_flags & IB_SEND_FENCE) ?
MTHCA_NEXT_FENCE : 0));
- if (!size0) {
+ if (!nreq) {
size0 = size;
op0 = mthca_opcode[wr->opcode];
f0 = wr->send_flags & IB_SEND_FENCE ?
@@ -2241,20 +2230,12 @@ int mthca_arbel_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
wqe += sizeof (struct mthca_data_seg);
}
- if (i < qp->rq.max_gs) {
- ((struct mthca_data_seg *) wqe)->byte_count = 0;
- ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
- ((struct mthca_data_seg *) wqe)->addr = 0;
- }
+ if (i < qp->rq.max_gs)
+ mthca_set_data_seg_inval(wqe);
qp->wrid[ind] = wr->wr_id;
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index b8f05a526673..88d219e730ad 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -543,20 +543,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
wqe += sizeof (struct mthca_data_seg);
}
- if (i < srq->max_gs) {
- ((struct mthca_data_seg *) wqe)->byte_count = 0;
- ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
- ((struct mthca_data_seg *) wqe)->addr = 0;
- }
+ if (i < srq->max_gs)
+ mthca_set_data_seg_inval(wqe);
((struct mthca_next_seg *) prev_wqe)->nda_op =
cpu_to_be32((ind << srq->wqe_shift) | 1);
@@ -662,20 +654,12 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
}
for (i = 0; i < wr->num_sge; ++i) {
- ((struct mthca_data_seg *) wqe)->byte_count =
- cpu_to_be32(wr->sg_list[i].length);
- ((struct mthca_data_seg *) wqe)->lkey =
- cpu_to_be32(wr->sg_list[i].lkey);
- ((struct mthca_data_seg *) wqe)->addr =
- cpu_to_be64(wr->sg_list[i].addr);
+ mthca_set_data_seg(wqe, wr->sg_list + i);
wqe += sizeof (struct mthca_data_seg);
}
- if (i < srq->max_gs) {
- ((struct mthca_data_seg *) wqe)->byte_count = 0;
- ((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
- ((struct mthca_data_seg *) wqe)->addr = 0;
- }
+ if (i < srq->max_gs)
+ mthca_set_data_seg_inval(wqe);
srq->wrid[ind] = wr->wr_id;
srq->first_free = next_ind;
diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h
index e7d2c1e86199..f6a66fe78e48 100644
--- a/drivers/infiniband/hw/mthca/mthca_wqe.h
+++ b/drivers/infiniband/hw/mthca/mthca_wqe.h
@@ -113,4 +113,19 @@ struct mthca_mlx_seg {
__be16 vcrc;
};
+static __always_inline void mthca_set_data_seg(struct mthca_data_seg *dseg,
+ struct ib_sge *sg)
+{
+ dseg->byte_count = cpu_to_be32(sg->length);
+ dseg->lkey = cpu_to_be32(sg->lkey);
+ dseg->addr = cpu_to_be64(sg->addr);
+}
+
+static __always_inline void mthca_set_data_seg_inval(struct mthca_data_seg *dseg)
+{
+ dseg->byte_count = 0;
+ dseg->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
+ dseg->addr = 0;
+}
+
#endif /* MTHCA_WQE_H */
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index af78ccc4ce71..1f76bad020f3 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_IPOIB
tristate "IP-over-InfiniBand"
- depends on INFINIBAND && NETDEVICES && INET && (IPV6 || IPV6=n)
+ depends on NETDEVICES && INET && (IPV6 || IPV6=n)
---help---
Support for the IP-over-InfiniBand protocol (IPoIB). This
transports IP packets over InfiniBand so you can use your IB
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index ea74d1eaf004..08b4676a3820 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -281,7 +281,6 @@ static int ipoib_cm_send_rep(struct net_device *dev, struct ib_cm_id *cm_id,
rep.private_data_len = sizeof data;
rep.flow_control = 0;
rep.rnr_retry_count = req->rnr_retry_count;
- rep.target_ack_delay = 20; /* FIXME */
rep.srq = 1;
rep.qp_num = qp->qp_num;
rep.starting_psn = psn;
@@ -1148,7 +1147,6 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
{
struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv,
cm.skb_task);
- struct net_device *dev = priv->dev;
struct sk_buff *skb;
unsigned mtu = priv->mcast_mtu;
@@ -1162,7 +1160,7 @@ static void ipoib_cm_skb_reap(struct work_struct *work)
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
else if (skb->protocol == htons(ETH_P_IPV6))
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, priv->dev);
#endif
dev_kfree_skb_any(skb);
spin_lock_irq(&priv->tx_lock);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 8404f05b2b6e..10944888cffd 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -197,6 +197,13 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
}
/*
+ * Drop packets that this interface sent, ie multicast packets
+ * that the HCA has replicated.
+ */
+ if (wc->slid == priv->local_lid && wc->src_qp == priv->qp->qp_num)
+ goto repost;
+
+ /*
* If we can't allocate a new RX buffer, dump
* this packet and reuse the old buffer.
*/
@@ -213,24 +220,18 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
skb_put(skb, wc->byte_len);
skb_pull(skb, IB_GRH_BYTES);
- if (wc->slid != priv->local_lid ||
- wc->src_qp != priv->qp->qp_num) {
- skb->protocol = ((struct ipoib_header *) skb->data)->proto;
- skb_reset_mac_header(skb);
- skb_pull(skb, IPOIB_ENCAP_LEN);
+ skb->protocol = ((struct ipoib_header *) skb->data)->proto;
+ skb_reset_mac_header(skb);
+ skb_pull(skb, IPOIB_ENCAP_LEN);
- dev->last_rx = jiffies;
- ++priv->stats.rx_packets;
- priv->stats.rx_bytes += skb->len;
+ dev->last_rx = jiffies;
+ ++priv->stats.rx_packets;
+ priv->stats.rx_bytes += skb->len;
- skb->dev = dev;
- /* XXX get correct PACKET_ type here */
- skb->pkt_type = PACKET_HOST;
- netif_receive_skb(skb);
- } else {
- ipoib_dbg_data(priv, "dropping loopback packet\n");
- dev_kfree_skb_any(skb);
- }
+ skb->dev = dev;
+ /* XXX get correct PACKET_ type here */
+ skb->pkt_type = PACKET_HOST;
+ netif_receive_skb(skb);
repost:
if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
index aecbb9083f0c..fe604c8d2996 100644
--- a/drivers/infiniband/ulp/iser/Kconfig
+++ b/drivers/infiniband/ulp/iser/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_ISER
tristate "iSCSI Extensions for RDMA (iSER)"
- depends on INFINIBAND && SCSI && INET
+ depends on SCSI && INET
select SCSI_ISCSI_ATTRS
---help---
Support for the iSCSI Extensions for RDMA (iSER) Protocol
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index dd221eda3ea6..5db314380271 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -134,19 +134,9 @@ iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
{
struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data;
struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
- struct scsi_cmnd *sc = ctask->sc;
iser_ctask->command_sent = 0;
iser_ctask->iser_conn = iser_conn;
-
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
- BUG_ON(ctask->total_length == 0);
-
- debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
- ctask->itt, ctask->total_length, ctask->imm_count,
- ctask->unsol_count);
- }
-
iser_ctask_rdma_init(iser_ctask);
}
@@ -219,6 +209,14 @@ iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
int error = 0;
+ if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) {
+ BUG_ON(scsi_bufflen(ctask->sc) == 0);
+
+ debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
+ ctask->itt, scsi_bufflen(ctask->sc),
+ ctask->imm_count, ctask->unsol_count);
+ }
+
debug_scsi("ctask deq [cid %d itt 0x%x]\n",
conn->id, ctask->itt);
@@ -375,7 +373,8 @@ static struct iscsi_transport iscsi_iser_transport;
static struct iscsi_cls_session *
iscsi_iser_session_create(struct iscsi_transport *iscsit,
struct scsi_transport_template *scsit,
- uint32_t initial_cmdsn, uint32_t *hostno)
+ uint16_t cmds_max, uint16_t qdepth,
+ uint32_t initial_cmdsn, uint32_t *hostno)
{
struct iscsi_cls_session *cls_session;
struct iscsi_session *session;
@@ -386,7 +385,13 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit,
struct iscsi_iser_cmd_task *iser_ctask;
struct iser_desc *desc;
+ /*
+ * we do not support setting can_queue cmd_per_lun from userspace yet
+ * because we preallocate so many resources
+ */
cls_session = iscsi_session_setup(iscsit, scsit,
+ ISCSI_DEF_XMIT_CMDS_MAX,
+ ISCSI_MAX_CMD_PER_LUN,
sizeof(struct iscsi_iser_cmd_task),
sizeof(struct iser_desc),
initial_cmdsn, &hn);
@@ -545,7 +550,7 @@ iscsi_iser_ep_disconnect(__u64 ep_handle)
static struct scsi_host_template iscsi_iser_sht = {
.name = "iSCSI Initiator over iSER, v." DRV_VER,
.queuecommand = iscsi_queuecommand,
- .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
+ .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
.max_sectors = 1024,
.cmd_per_lun = ISCSI_MAX_CMD_PER_LUN,
@@ -574,8 +579,12 @@ static struct iscsi_transport iscsi_iser_transport = {
ISCSI_EXP_STATSN |
ISCSI_PERSISTENT_PORT |
ISCSI_PERSISTENT_ADDRESS |
- ISCSI_TARGET_NAME |
- ISCSI_TPGT,
+ ISCSI_TARGET_NAME | ISCSI_TPGT |
+ ISCSI_USERNAME | ISCSI_PASSWORD |
+ ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+ .host_param_mask = ISCSI_HOST_HWADDRESS |
+ ISCSI_HOST_NETDEV_NAME |
+ ISCSI_HOST_INITIATOR_NAME,
.host_template = &iscsi_iser_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_lun = ISCSI_ISER_MAX_LUN,
@@ -592,6 +601,9 @@ static struct iscsi_transport iscsi_iser_transport = {
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_iser_conn_start,
.stop_conn = iscsi_conn_stop,
+ /* iscsi host params */
+ .get_host_param = iscsi_host_get_param,
+ .set_host_param = iscsi_host_set_param,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_iser_conn_get_stats,
@@ -625,7 +637,7 @@ static int __init iser_init(void)
ig.desc_cache = kmem_cache_create("iser_descriptors",
sizeof (struct iser_desc),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (ig.desc_cache == NULL)
return -ENOMEM;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 8960196ffb0f..1ee867b1b341 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -98,7 +98,7 @@
#define ISER_MAX_TX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), *
* SCSI_TMFUNC(2), LOGOUT(1) */
-#define ISER_QP_MAX_RECV_DTOS (ISCSI_XMIT_CMDS_MAX + \
+#define ISER_QP_MAX_RECV_DTOS (ISCSI_DEF_XMIT_CMDS_MAX + \
ISER_MAX_RX_MISC_PDUS + \
ISER_MAX_TX_MISC_PDUS)
@@ -110,7 +110,7 @@
#define ISER_INFLIGHT_DATAOUTS 8
-#define ISER_QP_MAX_REQ_DTOS (ISCSI_XMIT_CMDS_MAX * \
+#define ISER_QP_MAX_REQ_DTOS (ISCSI_DEF_XMIT_CMDS_MAX * \
(1 + ISER_INFLIGHT_DATAOUTS) + \
ISER_MAX_TX_MISC_PDUS + \
ISER_MAX_RX_MISC_PDUS)
@@ -310,8 +310,6 @@ int iser_conn_init(struct iser_conn **ib_conn);
void iser_conn_terminate(struct iser_conn *ib_conn);
-void iser_conn_release(struct iser_conn *ib_conn);
-
void iser_rcv_completion(struct iser_desc *desc,
unsigned long dto_xfer_len);
@@ -329,9 +327,6 @@ void iser_reg_single(struct iser_device *device,
struct iser_regd_buf *regd_buf,
enum dma_data_direction direction);
-int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
- enum iser_data_dir cmd_dir);
-
void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
enum iser_data_dir cmd_dir);
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 3651072f6c1f..9ea5b9aaba7c 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -351,18 +351,12 @@ int iser_send_command(struct iscsi_conn *conn,
else
data_buf = &iser_ctask->data[ISER_DIR_OUT];
- if (sc->use_sg) { /* using a scatter list */
- data_buf->buf = sc->request_buffer;
- data_buf->size = sc->use_sg;
- } else if (sc->request_bufflen) {
- /* using a single buffer - convert it into one entry SG */
- sg_init_one(&data_buf->sg_single,
- sc->request_buffer, sc->request_bufflen);
- data_buf->buf = &data_buf->sg_single;
- data_buf->size = 1;
+ if (scsi_sg_count(sc)) { /* using a scatter list */
+ data_buf->buf = scsi_sglist(sc);
+ data_buf->size = scsi_sg_count(sc);
}
- data_buf->data_len = sc->request_bufflen;
+ data_buf->data_len = scsi_bufflen(sc);
if (hdr->flags & ISCSI_FLAG_CMD_READ) {
err = iser_prepare_read_cmd(ctask, edtl);
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index fc9f1fd0ae54..36cdf77ae92a 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -103,8 +103,8 @@ void iser_reg_single(struct iser_device *device,
/**
* iser_start_rdma_unaligned_sg
*/
-int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
- enum iser_data_dir cmd_dir)
+static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ enum iser_data_dir cmd_dir)
{
int dma_nents;
struct ib_device *dev;
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 3702e2375553..d42ec0156eec 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -155,8 +155,8 @@ static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
params.max_pages_per_fmr = ISCSI_ISER_SG_TABLESIZE + 1;
/* make the pool size twice the max number of SCSI commands *
* the ML is expected to queue, watermark for unmap at 50% */
- params.pool_size = ISCSI_XMIT_CMDS_MAX * 2;
- params.dirty_watermark = ISCSI_XMIT_CMDS_MAX;
+ params.pool_size = ISCSI_DEF_XMIT_CMDS_MAX * 2;
+ params.dirty_watermark = ISCSI_DEF_XMIT_CMDS_MAX;
params.cache = 0;
params.flush_function = NULL;
params.access = (IB_ACCESS_LOCAL_WRITE |
@@ -311,6 +311,29 @@ static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
}
/**
+ * Frees all conn objects and deallocs conn descriptor
+ */
+static void iser_conn_release(struct iser_conn *ib_conn)
+{
+ struct iser_device *device = ib_conn->device;
+
+ BUG_ON(ib_conn->state != ISER_CONN_DOWN);
+
+ mutex_lock(&ig.connlist_mutex);
+ list_del(&ib_conn->conn_list);
+ mutex_unlock(&ig.connlist_mutex);
+
+ iser_free_ib_conn_res(ib_conn);
+ ib_conn->device = NULL;
+ /* on EVENT_ADDR_ERROR there's no device yet for this conn */
+ if (device != NULL)
+ iser_device_try_release(device);
+ if (ib_conn->iser_conn)
+ ib_conn->iser_conn->ib_conn = NULL;
+ kfree(ib_conn);
+}
+
+/**
* triggers start of the disconnect procedures and wait for them to be done
*/
void iser_conn_terminate(struct iser_conn *ib_conn)
@@ -550,30 +573,6 @@ connect_failure:
}
/**
- * Frees all conn objects and deallocs conn descriptor
- */
-void iser_conn_release(struct iser_conn *ib_conn)
-{
- struct iser_device *device = ib_conn->device;
-
- BUG_ON(ib_conn->state != ISER_CONN_DOWN);
-
- mutex_lock(&ig.connlist_mutex);
- list_del(&ib_conn->conn_list);
- mutex_unlock(&ig.connlist_mutex);
-
- iser_free_ib_conn_res(ib_conn);
- ib_conn->device = NULL;
- /* on EVENT_ADDR_ERROR there's no device yet for this conn */
- if (device != NULL)
- iser_device_try_release(device);
- if (ib_conn->iser_conn)
- ib_conn->iser_conn->ib_conn = NULL;
- kfree(ib_conn);
-}
-
-
-/**
* iser_reg_page_vec - Register physical memory
*
* returns: 0 on success, errno code on failure
diff --git a/drivers/infiniband/ulp/srp/Kconfig b/drivers/infiniband/ulp/srp/Kconfig
index 8fe3be4e9910..3432dce29520 100644
--- a/drivers/infiniband/ulp/srp/Kconfig
+++ b/drivers/infiniband/ulp/srp/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_SRP
tristate "InfiniBand SCSI RDMA Protocol"
- depends on INFINIBAND && SCSI
+ depends on SCSI
---help---
Support for the SCSI RDMA Protocol over InfiniBand. This
allows you to access storage devices that speak SRP over
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 39bf057fbc43..f01ca182f226 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -455,10 +455,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
struct srp_target_port *target,
struct srp_request *req)
{
- struct scatterlist *scat;
- int nents;
-
- if (!scmnd->request_buffer ||
+ if (!scsi_sglist(scmnd) ||
(scmnd->sc_data_direction != DMA_TO_DEVICE &&
scmnd->sc_data_direction != DMA_FROM_DEVICE))
return;
@@ -468,20 +465,8 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
req->fmr = NULL;
}
- /*
- * This handling of non-SG commands can be killed when the
- * SCSI midlayer no longer generates non-SG commands.
- */
- if (likely(scmnd->use_sg)) {
- nents = scmnd->use_sg;
- scat = scmnd->request_buffer;
- } else {
- nents = 1;
- scat = &req->fake_sg;
- }
-
- ib_dma_unmap_sg(target->srp_host->dev->dev, scat, nents,
- scmnd->sc_data_direction);
+ ib_dma_unmap_sg(target->srp_host->dev->dev, scsi_sglist(scmnd),
+ scsi_sg_count(scmnd), scmnd->sc_data_direction);
}
static void srp_remove_req(struct srp_target_port *target, struct srp_request *req)
@@ -595,6 +580,7 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
int ret;
struct srp_device *dev = target->srp_host->dev;
struct ib_device *ibdev = dev->dev;
+ struct scatterlist *sg;
if (!dev->fmr_pool)
return -ENODEV;
@@ -604,16 +590,16 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
return -EINVAL;
len = page_cnt = 0;
- for (i = 0; i < sg_cnt; ++i) {
- unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+ scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
- if (ib_sg_dma_address(ibdev, &scat[i]) & ~dev->fmr_page_mask) {
+ if (ib_sg_dma_address(ibdev, sg) & ~dev->fmr_page_mask) {
if (i > 0)
return -EINVAL;
else
++page_cnt;
}
- if ((ib_sg_dma_address(ibdev, &scat[i]) + dma_len) &
+ if ((ib_sg_dma_address(ibdev, sg) + dma_len) &
~dev->fmr_page_mask) {
if (i < sg_cnt - 1)
return -EINVAL;
@@ -633,12 +619,12 @@ static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
return -ENOMEM;
page_cnt = 0;
- for (i = 0; i < sg_cnt; ++i) {
- unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+ scsi_for_each_sg(req->scmnd, sg, sg_cnt, i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
for (j = 0; j < dma_len; j += dev->fmr_page_size)
dma_pages[page_cnt++] =
- (ib_sg_dma_address(ibdev, &scat[i]) &
+ (ib_sg_dma_address(ibdev, sg) &
dev->fmr_page_mask) + j;
}
@@ -673,7 +659,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
struct srp_device *dev;
struct ib_device *ibdev;
- if (!scmnd->request_buffer || scmnd->sc_data_direction == DMA_NONE)
+ if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE)
return sizeof (struct srp_cmd);
if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
@@ -683,18 +669,8 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
return -EINVAL;
}
- /*
- * This handling of non-SG commands can be killed when the
- * SCSI midlayer no longer generates non-SG commands.
- */
- if (likely(scmnd->use_sg)) {
- nents = scmnd->use_sg;
- scat = scmnd->request_buffer;
- } else {
- nents = 1;
- scat = &req->fake_sg;
- sg_init_one(scat, scmnd->request_buffer, scmnd->request_bufflen);
- }
+ nents = scsi_sg_count(scmnd);
+ scat = scsi_sglist(scmnd);
dev = target->srp_host->dev;
ibdev = dev->dev;
@@ -724,6 +700,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
* descriptor.
*/
struct srp_indirect_buf *buf = (void *) cmd->add_data;
+ struct scatterlist *sg;
u32 datalen = 0;
int i;
@@ -732,11 +709,11 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
sizeof (struct srp_indirect_buf) +
count * sizeof (struct srp_direct_buf);
- for (i = 0; i < count; ++i) {
- unsigned int dma_len = ib_sg_dma_len(ibdev, &scat[i]);
+ scsi_for_each_sg(scmnd, sg, count, i) {
+ unsigned int dma_len = ib_sg_dma_len(ibdev, sg);
buf->desc_list[i].va =
- cpu_to_be64(ib_sg_dma_address(ibdev, &scat[i]));
+ cpu_to_be64(ib_sg_dma_address(ibdev, sg));
buf->desc_list[i].key =
cpu_to_be32(dev->mr->rkey);
buf->desc_list[i].len = cpu_to_be32(dma_len);
@@ -802,9 +779,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
}
if (rsp->flags & (SRP_RSP_FLAG_DOOVER | SRP_RSP_FLAG_DOUNDER))
- scmnd->resid = be32_to_cpu(rsp->data_out_res_cnt);
+ scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt));
else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))
- scmnd->resid = be32_to_cpu(rsp->data_in_res_cnt);
+ scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
if (!req->tsk_mgmt) {
scmnd->host_scribble = (void *) -1L;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 1d53c7bc368f..e3573e7038c4 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -106,11 +106,6 @@ struct srp_request {
struct srp_iu *cmd;
struct srp_iu *tsk_mgmt;
struct ib_pool_fmr *fmr;
- /*
- * Fake scatterlist used when scmnd->use_sg==0. Can be killed
- * when the SCSI midlayer no longer generates non-SG commands.
- */
- struct scatterlist fake_sg;
struct completion done;
short index;
u8 cmd_done;
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index bd686a2a517d..20896d5e5f0e 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -445,6 +445,7 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
static int gameport_thread(void *nothing)
{
+ set_freezable();
do {
gameport_handle_event();
wait_event_interruptible(gameport_wait,
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 75b4d2a83dd9..5fe755586623 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -471,37 +471,16 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
return 0;
}
-static struct list_head *list_get_nth_element(struct list_head *list, loff_t *pos)
-{
- struct list_head *node;
- loff_t i = 0;
-
- list_for_each(node, list)
- if (i++ == *pos)
- return node;
-
- return NULL;
-}
-
-static struct list_head *list_get_next_element(struct list_head *list, struct list_head *element, loff_t *pos)
-{
- if (element->next == list)
- return NULL;
-
- ++(*pos);
- return element->next;
-}
-
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
- return list_get_nth_element(&input_dev_list, pos);
+ return seq_list_start(&input_dev_list, *pos);
}
static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- return list_get_next_element(&input_dev_list, v, pos);
+ return seq_list_next(v, &input_dev_list, pos);
}
static void input_devices_seq_stop(struct seq_file *seq, void *v)
@@ -592,13 +571,13 @@ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
/* acquire lock here ... Yes, we do need locking, I knowi, I know... */
seq->private = (void *)(unsigned long)*pos;
- return list_get_nth_element(&input_handler_list, pos);
+ return seq_list_start(&input_handler_list, *pos);
}
static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
seq->private = (void *)(unsigned long)(*pos + 1);
- return list_get_next_element(&input_handler_list, v, pos);
+ return seq_list_next(v, &input_handler_list, pos);
}
static void input_handlers_seq_stop(struct seq_file *seq, void *v)
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 12db72d83ea0..e2abe18e575d 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -275,4 +275,11 @@ config JOYSTICK_XPAD_FF
---help---
Say Y here if you want to take advantage of xbox 360 rumble features.
+config JOYSTICK_XPAD_LEDS
+ bool "LED Support for Xbox360 controller 'BigX' LED"
+ depends on LEDS_CLASS && JOYSTICK_XPAD
+ ---help---
+ This option enables support for the LED which surrounds the Big X on
+ XBox 360 controller.
+
endif
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 244089c52650..28080395899c 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -191,13 +191,18 @@ struct usb_xpad {
unsigned char *idata; /* input data */
dma_addr_t idata_dma;
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
struct urb *irq_out; /* urb for interrupt out report */
unsigned char *odata; /* output data */
dma_addr_t odata_dma;
+ struct mutex odata_mutex;
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+ struct xpad_led *led;
#endif
- char phys[65]; /* physical device path */
+ char phys[64]; /* physical device path */
int dpad_mapping; /* map d-pad to buttons or to axes */
int xtype; /* type of xbox device */
@@ -349,7 +354,7 @@ exit:
__FUNCTION__, retval);
}
-#ifdef CONFIG_JOYSTICK_XPAD_FF
+#if defined(CONFIG_JOYSTICK_XPAD_FF) || defined(CONFIG_JOYSTICK_XPAD_LEDS)
static void xpad_irq_out(struct urb *urb)
{
int retval;
@@ -376,29 +381,7 @@ exit:
__FUNCTION__, retval);
}
-static int xpad_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
-{
- struct usb_xpad *xpad = input_get_drvdata(dev);
-
- if (effect->type == FF_RUMBLE) {
- __u16 strong = effect->u.rumble.strong_magnitude;
- __u16 weak = effect->u.rumble.weak_magnitude;
- xpad->odata[0] = 0x00;
- xpad->odata[1] = 0x08;
- xpad->odata[2] = 0x00;
- xpad->odata[3] = strong / 256;
- xpad->odata[4] = weak / 256;
- xpad->odata[5] = 0x00;
- xpad->odata[6] = 0x00;
- xpad->odata[7] = 0x00;
- usb_submit_urb(xpad->irq_out, GFP_KERNEL);
- }
-
- return 0;
-}
-
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad)
{
struct usb_endpoint_descriptor *ep_irq_out;
int error = -ENOMEM;
@@ -411,6 +394,8 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
if (!xpad->odata)
goto fail1;
+ mutex_init(&xpad->odata_mutex);
+
xpad->irq_out = usb_alloc_urb(0, GFP_KERNEL);
if (!xpad->irq_out)
goto fail2;
@@ -423,25 +408,19 @@ static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad)
xpad->irq_out->transfer_dma = xpad->odata_dma;
xpad->irq_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
-
- error = input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
- if (error)
- goto fail2;
-
return 0;
fail2: usb_buffer_free(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma);
fail1: return error;
}
-static void xpad_stop_ff(struct usb_xpad *xpad)
+static void xpad_stop_output(struct usb_xpad *xpad)
{
if (xpad->xtype == XTYPE_XBOX360)
usb_kill_urb(xpad->irq_out);
}
-static void xpad_deinit_ff(struct usb_xpad *xpad)
+static void xpad_deinit_output(struct usb_xpad *xpad)
{
if (xpad->xtype == XTYPE_XBOX360) {
usb_free_urb(xpad->irq_out);
@@ -449,13 +428,130 @@ static void xpad_deinit_ff(struct usb_xpad *xpad)
xpad->odata, xpad->odata_dma);
}
}
+#else
+static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
+static void xpad_deinit_output(struct usb_xpad *xpad) {}
+static void xpad_stop_output(struct usb_xpad *xpad) {}
+#endif
+
+#ifdef CONFIG_JOYSTICK_XPAD_FF
+static int xpad_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct usb_xpad *xpad = input_get_drvdata(dev);
+ if (effect->type == FF_RUMBLE) {
+ __u16 strong = effect->u.rumble.strong_magnitude;
+ __u16 weak = effect->u.rumble.weak_magnitude;
+ xpad->odata[0] = 0x00;
+ xpad->odata[1] = 0x08;
+ xpad->odata[2] = 0x00;
+ xpad->odata[3] = strong / 256;
+ xpad->odata[4] = weak / 256;
+ xpad->odata[5] = 0x00;
+ xpad->odata[6] = 0x00;
+ xpad->odata[7] = 0x00;
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ }
+
+ return 0;
+}
+
+static int xpad_init_ff(struct usb_xpad *xpad)
+{
+ input_set_capability(xpad->dev, EV_FF, FF_RUMBLE);
+
+ return input_ff_create_memless(xpad->dev, NULL, xpad_play_effect);
+}
+
+#else
+static int xpad_init_ff(struct usb_xpad *xpad) { return 0; }
+#endif
+
+#if defined(CONFIG_JOYSTICK_XPAD_LEDS)
+#include <linux/leds.h>
+
+struct xpad_led {
+ char name[16];
+ struct led_classdev led_cdev;
+ struct usb_xpad *xpad;
+};
+
+static void xpad_send_led_command(struct usb_xpad *xpad, int command)
+{
+ if (command >= 0 && command < 14) {
+ mutex_lock(&xpad->odata_mutex);
+ xpad->odata[0] = 0x01;
+ xpad->odata[1] = 0x03;
+ xpad->odata[2] = command;
+ usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ mutex_unlock(&xpad->odata_mutex);
+ }
+}
+
+static void xpad_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct xpad_led *xpad_led = container_of(led_cdev,
+ struct xpad_led, led_cdev);
+
+ xpad_send_led_command(xpad_led->xpad, value);
+}
+
+static int xpad_led_probe(struct usb_xpad *xpad)
+{
+ static atomic_t led_seq = ATOMIC_INIT(0);
+ long led_no;
+ struct xpad_led *led;
+ struct led_classdev *led_cdev;
+ int error;
+
+ if (xpad->xtype != XTYPE_XBOX360)
+ return 0;
+
+ xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
+ if (!led)
+ return -ENOMEM;
+
+ led_no = (long)atomic_inc_return(&led_seq) - 1;
+
+ snprintf(led->name, sizeof(led->name), "xpad%ld", led_no);
+ led->xpad = xpad;
+
+ led_cdev = &led->led_cdev;
+ led_cdev->name = led->name;
+ led_cdev->brightness_set = xpad_led_set;
+
+ error = led_classdev_register(&xpad->udev->dev, led_cdev);
+ if (error) {
+ kfree(led);
+ xpad->led = NULL;
+ return error;
+ }
+
+ /*
+ * Light up the segment corresponding to controller number
+ */
+ xpad_send_led_command(xpad, (led_no % 4) + 2);
+
+ return 0;
+}
+
+static void xpad_led_disconnect(struct usb_xpad *xpad)
+{
+ struct xpad_led *xpad_led = xpad->led;
+
+ if (xpad_led) {
+ led_classdev_unregister(&xpad_led->led_cdev);
+ kfree(xpad_led->name);
+ }
+}
#else
-static int xpad_init_ff(struct usb_interface *intf, struct usb_xpad *xpad) { return 0; }
-static void xpad_stop_ff(struct usb_xpad *xpad) { }
-static void xpad_deinit_ff(struct usb_xpad *xpad) { }
+static int xpad_led_probe(struct usb_xpad *xpad) { return 0; }
+static void xpad_led_disconnect(struct usb_xpad *xpad) { }
#endif
+
static int xpad_open(struct input_dev *dev)
{
struct usb_xpad *xpad = input_get_drvdata(dev);
@@ -472,7 +568,7 @@ static void xpad_close(struct input_dev *dev)
struct usb_xpad *xpad = input_get_drvdata(dev);
usb_kill_urb(xpad->irq_in);
- xpad_stop_ff(xpad);
+ xpad_stop_output(xpad);
}
static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
@@ -564,10 +660,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
for (i = 0; xpad_abs_pad[i] >= 0; i++)
xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
- error = xpad_init_ff(intf, xpad);
+ error = xpad_init_output(intf, xpad);
if (error)
goto fail2;
+ error = xpad_init_ff(xpad);
+ if (error)
+ goto fail3;
+
+ error = xpad_led_probe(xpad);
+ if (error)
+ goto fail3;
+
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(xpad->irq_in, udev,
usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
@@ -578,12 +682,13 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
error = input_register_device(xpad->dev);
if (error)
- goto fail3;
+ goto fail4;
usb_set_intfdata(intf, xpad);
return 0;
- fail3: usb_free_urb(xpad->irq_in);
+ fail4: usb_free_urb(xpad->irq_in);
+ fail3: xpad_deinit_output(xpad);
fail2: usb_buffer_free(udev, XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
fail1: input_free_device(input_dev);
kfree(xpad);
@@ -597,8 +702,9 @@ static void xpad_disconnect(struct usb_interface *intf)
usb_set_intfdata(intf, NULL);
if (xpad) {
+ xpad_led_disconnect(xpad);
input_unregister_device(xpad->dev);
- xpad_deinit_ff(xpad);
+ xpad_deinit_output(xpad);
usb_free_urb(xpad->irq_in);
usb_buffer_free(xpad->udev, XPAD_PKT_LEN,
xpad->idata, xpad->idata_dma);
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 31989dcd922c..906bf5e8de89 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -24,7 +24,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("PC Speaker beeper driver");
MODULE_LICENSE("GPL");
-static DEFINE_SPINLOCK(i8253_beep_lock);
+#ifdef CONFIG_X86
+/* Use the global PIT lock ! */
+#include <asm/i8253.h>
+#else
+static DEFINE_SPINLOCK(i8253_lock);
+#endif
static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -43,7 +48,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
if (value > 20 && value < 32767)
count = PIT_TICK_RATE / value;
- spin_lock_irqsave(&i8253_beep_lock, flags);
+ spin_lock_irqsave(&i8253_lock, flags);
if (count) {
/* enable counter 2 */
@@ -58,7 +63,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c
outb(inb_p(0x61) & 0xFC, 0x61);
}
- spin_unlock_irqrestore(&i8253_beep_lock, flags);
+ spin_unlock_irqrestore(&i8253_lock, flags);
return 0;
}
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e3215267db11..2bea1b2c631c 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -155,6 +155,8 @@ struct atp {
int xy_acc[ATP_XSENSORS + ATP_YSENSORS];
int overflowwarn; /* overflow warning printed? */
int datalen; /* size of an USB urb transfer */
+ int idlecount; /* number of empty packets */
+ struct work_struct work;
};
#define dbg_dump(msg, tab) \
@@ -208,6 +210,55 @@ static inline int atp_is_geyser_3(struct atp *dev)
(productId == GEYSER4_JIS_PRODUCT_ID);
}
+/*
+ * By default Geyser 3 device sends standard USB HID mouse
+ * packets (Report ID 2). This code changes device mode, so it
+ * sends raw sensor reports (Report ID 5).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+ char data[8];
+ int size;
+
+ size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ ATP_GEYSER3_MODE_READ_REQUEST_ID,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ATP_GEYSER3_MODE_REQUEST_VALUE,
+ ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+ if (size != 8) {
+ err("Could not do mode read request from device"
+ " (Geyser 3 mode)");
+ return -EIO;
+ }
+
+ /* Apply the mode switch */
+ data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+ size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+ USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ATP_GEYSER3_MODE_REQUEST_VALUE,
+ ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+ if (size != 8) {
+ err("Could not do mode write request to device"
+ " (Geyser 3 mode)");
+ return -EIO;
+ }
+ return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+ struct atp *dev = container_of(work, struct atp, work);
+ struct usb_device *udev = dev->udev;
+
+ dev->idlecount = 0;
+ atp_geyser3_init(udev);
+}
+
static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
int *z, int *fingers)
{
@@ -439,8 +490,8 @@ static void atp_complete(struct urb* urb)
}
dev->x_old = x;
dev->y_old = y;
- }
- else if (!x && !y) {
+
+ } else if (!x && !y) {
dev->x_old = dev->y_old = -1;
input_report_key(dev->input, BTN_TOUCH, 0);
@@ -449,11 +500,21 @@ static void atp_complete(struct urb* urb)
/* reset the accumulator on release */
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
- }
- input_report_key(dev->input, BTN_LEFT,
- !!dev->data[dev->datalen - 1]);
+ /* Geyser 3 will continue to send packets continually after
+ the first touch unless reinitialised. Do so if it's been
+ idle for a while in order to avoid waking the kernel up
+ several hundred times a second */
+ if (atp_is_geyser_3(dev)) {
+ dev->idlecount++;
+ if (dev->idlecount == 10) {
+ dev->valid = 0;
+ schedule_work(&dev->work);
+ }
+ }
+ }
+ input_report_key(dev->input, BTN_LEFT, dev->data[dev->datalen - 1] & 1);
input_sync(dev->input);
exit:
@@ -480,6 +541,7 @@ static void atp_close(struct input_dev *input)
struct atp *dev = input_get_drvdata(input);
usb_kill_urb(dev->urb);
+ cancel_work_sync(&dev->work);
dev->open = 0;
}
@@ -528,40 +590,10 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
dev->datalen = 81;
if (atp_is_geyser_3(dev)) {
- /*
- * By default Geyser 3 device sends standard USB HID mouse
- * packets (Report ID 2). This code changes device mode, so it
- * sends raw sensor reports (Report ID 5).
- */
- char data[8];
- int size;
-
- size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_READ_REQUEST_ID,
- USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
- if (size != 8) {
- err("Could not do mode read request from device"
- " (Geyser 3 mode)");
+ /* switch to raw sensor mode */
+ if (atp_geyser3_init(udev))
goto err_free_devs;
- }
-
- /* Apply the mode switch */
- data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
- size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- ATP_GEYSER3_MODE_REQUEST_VALUE,
- ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
- if (size != 8) {
- err("Could not do mode write request to device"
- " (Geyser 3 mode)");
- goto err_free_devs;
- }
printk("appletouch Geyser 3 inited.\n");
}
@@ -636,6 +668,8 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
/* save our data pointer in this interface device */
usb_set_intfdata(iface, dev);
+ INIT_WORK(&dev->work, atp_reinit);
+
return 0;
err_free_buffer:
@@ -669,14 +703,17 @@ static void atp_disconnect(struct usb_interface *iface)
static int atp_suspend(struct usb_interface *iface, pm_message_t message)
{
struct atp *dev = usb_get_intfdata(iface);
+
usb_kill_urb(dev->urb);
dev->valid = 0;
+
return 0;
}
static int atp_resume(struct usb_interface *iface)
{
struct atp *dev = usb_get_intfdata(iface);
+
if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
return -EIO;
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 1740cadd9594..91109b49fde1 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -109,7 +109,7 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
{
struct lifebook_data *priv = psmouse->private;
struct input_dev *dev1 = psmouse->dev;
- struct input_dev *dev2 = priv->dev2;
+ struct input_dev *dev2 = priv ? priv->dev2 : NULL;
unsigned char *packet = psmouse->packet;
int relative_packet = packet[0] & 0x08;
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 27a68835b5ba..1317bdd8cc7c 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -119,7 +119,6 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
.attr = { \
.name = __stringify(_name), \
.mode = _mode, \
- .owner = THIS_MODULE, \
}, \
.show = psmouse_attr_show_helper, \
.store = psmouse_attr_set_helper, \
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 5a7b49c35539..b10ffae7c39b 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -117,15 +117,13 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
if (ret)
return ret;
- kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
- io = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
+ io = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!kmi || !io) {
ret = -ENOMEM;
goto out;
}
- memset(kmi, 0, sizeof(struct amba_kmi_port));
- memset(io, 0, sizeof(struct serio));
io->id.type = SERIO_8042;
io->write = amba_kmi_write;
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 4fca1e7f2678..702a526cf45b 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -366,6 +366,7 @@ static void i8042_pnp_exit(void)
static int __init i8042_pnp_init(void)
{
char kbd_irq_str[4] = { 0 }, aux_irq_str[4] = { 0 };
+ int pnp_data_busted = 0;
int err;
if (i8042_nopnp) {
@@ -413,27 +414,48 @@ static int __init i8042_pnp_init(void)
#endif
if (((i8042_pnp_data_reg & ~0xf) == (i8042_data_reg & ~0xf) &&
- i8042_pnp_data_reg != i8042_data_reg) || !i8042_pnp_data_reg) {
- printk(KERN_WARNING "PNP: PS/2 controller has invalid data port %#x; using default %#x\n",
+ i8042_pnp_data_reg != i8042_data_reg) ||
+ !i8042_pnp_data_reg) {
+ printk(KERN_WARNING
+ "PNP: PS/2 controller has invalid data port %#x; "
+ "using default %#x\n",
i8042_pnp_data_reg, i8042_data_reg);
i8042_pnp_data_reg = i8042_data_reg;
+ pnp_data_busted = 1;
}
if (((i8042_pnp_command_reg & ~0xf) == (i8042_command_reg & ~0xf) &&
- i8042_pnp_command_reg != i8042_command_reg) || !i8042_pnp_command_reg) {
- printk(KERN_WARNING "PNP: PS/2 controller has invalid command port %#x; using default %#x\n",
+ i8042_pnp_command_reg != i8042_command_reg) ||
+ !i8042_pnp_command_reg) {
+ printk(KERN_WARNING
+ "PNP: PS/2 controller has invalid command port %#x; "
+ "using default %#x\n",
i8042_pnp_command_reg, i8042_command_reg);
i8042_pnp_command_reg = i8042_command_reg;
+ pnp_data_busted = 1;
}
if (!i8042_nokbd && !i8042_pnp_kbd_irq) {
- printk(KERN_WARNING "PNP: PS/2 controller doesn't have KBD irq; using default %d\n", i8042_kbd_irq);
+ printk(KERN_WARNING
+ "PNP: PS/2 controller doesn't have KBD irq; "
+ "using default %d\n", i8042_kbd_irq);
i8042_pnp_kbd_irq = i8042_kbd_irq;
+ pnp_data_busted = 1;
}
if (!i8042_noaux && !i8042_pnp_aux_irq) {
- printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %d\n", i8042_aux_irq);
- i8042_pnp_aux_irq = i8042_aux_irq;
+ if (!pnp_data_busted && i8042_pnp_kbd_irq) {
+ printk(KERN_WARNING
+ "PNP: PS/2 appears to have AUX port disabled, "
+ "if this is incorrect please boot with "
+ "i8042.nopnp\n");
+ i8042_noaux = 1;
+ } else {
+ printk(KERN_WARNING
+ "PNP: PS/2 controller doesn't have AUX irq; "
+ "using default %d\n", i8042_aux_irq);
+ i8042_pnp_aux_irq = i8042_aux_irq;
+ }
}
i8042_data_reg = i8042_pnp_data_reg;
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index ea5e3c6ddb62..1b404f9e3bff 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -140,15 +140,13 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i
if (ret)
goto disable;
- ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL);
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!ps2if || !serio) {
ret = -ENOMEM;
goto release;
}
- memset(ps2if, 0, sizeof(struct pcips2_data));
- memset(serio, 0, sizeof(struct serio));
serio->id.type = SERIO_8042;
serio->write = pcips2_write;
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index d31ece8f68e9..2ad88780a170 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -234,15 +234,13 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
struct serio *serio;
int ret;
- ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
- serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!ps2if || !serio) {
ret = -ENOMEM;
goto free;
}
- memset(ps2if, 0, sizeof(struct ps2if));
- memset(serio, 0, sizeof(struct serio));
serio->id.type = SERIO_8042;
serio->write = ps2_write;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index a8f3bc1dff22..372ca4931194 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -384,6 +384,7 @@ static struct serio *serio_get_pending_child(struct serio *parent)
static int serio_thread(void *nothing)
{
+ set_freezable();
do {
serio_handle_event();
wait_event_interruptible(serio_wait,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 69371779806a..f929fcdbae2e 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -54,6 +54,19 @@ config TOUCHSCREEN_CORGI
To compile this driver as a module, choose M here: the
module will be called corgi_ts.
+config TOUCHSCREEN_FUJITSU
+ tristate "Fujitsu serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have the Fujitsu touchscreen (such as one
+ installed in Lifebook P series laptop) connected to your
+ system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called fujitsu-ts.
+
config TOUCHSCREEN_GUNZE
tristate "Gunze AHL-51S touchscreen"
select SERIO
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 2f86d6ad06d3..5de8933c4993 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
+obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 1c9069cd3bae..96581d08774f 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -95,7 +95,7 @@ struct ads7846 {
u16 dummy; /* for the pwrdown read */
struct ts_event tc;
- struct spi_transfer xfer[10];
+ struct spi_transfer xfer[18];
struct spi_message msg[5];
struct spi_message *last_msg;
int msg_idx;
@@ -107,6 +107,8 @@ struct ads7846 {
u16 debounce_tol;
u16 debounce_rep;
+ u16 penirq_recheck_delay_usecs;
+
spinlock_t lock;
struct hrtimer timer;
unsigned pendown:1; /* P: lock */
@@ -553,6 +555,15 @@ static void ads7846_rx(void *ads)
return;
}
+ /* Maybe check the pendown state before reporting. This discards
+ * false readings when the pen is lifted.
+ */
+ if (ts->penirq_recheck_delay_usecs) {
+ udelay(ts->penirq_recheck_delay_usecs);
+ if (!ts->get_pendown_state())
+ Rt = 0;
+ }
+
/* NOTE: We can't rely on the pressure to determine the pen down
* state, even this controller has a pressure sensor. The pressure
* value can fluctuate for quite a while after lifting the pen and
@@ -896,6 +907,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->filter = ads7846_no_filter;
ts->get_pendown_state = pdata->get_pendown_state;
+ if (pdata->penirq_recheck_delay_usecs)
+ ts->penirq_recheck_delay_usecs =
+ pdata->penirq_recheck_delay_usecs;
+
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
input_dev->name = "ADS784x Touchscreen";
@@ -936,6 +951,24 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* the first sample after switching drivers can be low quality;
+ * optionally discard it, using a second one after the signals
+ * have had enough time to stabilize.
+ */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_y;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.y;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
@@ -954,6 +987,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* ... maybe discard first sample ... */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_x;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.x;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
@@ -973,6 +1021,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* ... maybe discard first sample ... */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_z1;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.z1;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
@@ -990,6 +1053,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->len = 2;
spi_message_add_tail(x, m);
+ /* ... maybe discard first sample ... */
+ if (pdata->settle_delay_usecs) {
+ x->delay_usecs = pdata->settle_delay_usecs;
+
+ x++;
+ x->tx_buf = &ts->read_z2;
+ x->len = 1;
+ spi_message_add_tail(x, m);
+
+ x++;
+ x->rx_buf = &ts->tc.z2;
+ x->len = 2;
+ spi_message_add_tail(x, m);
+ }
+
m->complete = ads7846_rx_val;
m->context = ts;
}
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
new file mode 100644
index 000000000000..daf7a4afc935
--- /dev/null
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -0,0 +1,189 @@
+/*
+ * Fujitsu serial touchscreen driver
+ *
+ * Copyright (c) Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC "Fujitsu serial touchscreen driver"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define FUJITSU_LENGTH 5
+
+/*
+ * Per-touchscreen data.
+ */
+struct fujitsu {
+ struct input_dev *dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[FUJITSU_LENGTH];
+ char phys[32];
+};
+
+/*
+ * Decode serial data (5 bytes per packet)
+ * First byte
+ * 1 C 0 0 R S S S
+ * Where C is 1 while in calibration mode (which we don't use)
+ * R is 1 when no coordinate corection was done.
+ * S are button state
+ */
+static irqreturn_t fujitsu_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct fujitsu *fujitsu = serio_get_drvdata(serio);
+ struct input_dev *dev = fujitsu->dev;
+
+ if (fujitsu->idx == 0) {
+ /* resync skip until start of frame */
+ if ((data & 0xf0) != 0x80)
+ return IRQ_HANDLED;
+ } else {
+ /* resync skip garbage */
+ if (data & 0x80) {
+ fujitsu->idx = 0;
+ return IRQ_HANDLED;
+ }
+ }
+
+ fujitsu->data[fujitsu->idx++] = data;
+ if (fujitsu->idx == FUJITSU_LENGTH) {
+ input_report_abs(dev, ABS_X,
+ (fujitsu->data[2] << 7) | fujitsu->data[1]);
+ input_report_abs(dev, ABS_Y,
+ (fujitsu->data[4] << 7) | fujitsu->data[3]);
+ input_report_key(dev, BTN_TOUCH,
+ (fujitsu->data[0] & 0x03) != 2);
+ input_sync(dev);
+ fujitsu->idx = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * fujitsu_disconnect() is the opposite of fujitsu_connect()
+ */
+static void fujitsu_disconnect(struct serio *serio)
+{
+ struct fujitsu *fujitsu = serio_get_drvdata(serio);
+
+ input_get_device(fujitsu->dev);
+ input_unregister_device(fujitsu->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_put_device(fujitsu->dev);
+ kfree(fujitsu);
+}
+
+/*
+ * fujitsu_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Fujitsu protocol and registers it
+ * as input device.
+ */
+static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct fujitsu *fujitsu;
+ struct input_dev *input_dev;
+ int err;
+
+ fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!fujitsu || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ fujitsu->serio = serio;
+ fujitsu->dev = input_dev;
+ snprintf(fujitsu->phys, sizeof(fujitsu->phys),
+ "%s/input0", serio->phys);
+
+ input_dev->name = "Fujitsu Serial Touchscreen";
+ input_dev->phys = fujitsu->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_FUJITSU;
+ input_dev->id.product = 0;
+ input_dev->id.version = 0x0100;
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+ input_set_abs_params(input_dev, ABS_X, 0, 4096, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, 4096, 0, 0);
+ serio_set_drvdata(serio, fujitsu);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(fujitsu->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3:
+ serio_close(serio);
+ fail2:
+ serio_set_drvdata(serio, NULL);
+ fail1:
+ input_free_device(input_dev);
+ kfree(fujitsu);
+ return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+static struct serio_device_id fujitsu_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_FUJITSU,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, fujitsu_serio_ids);
+
+static struct serio_driver fujitsu_drv = {
+ .driver = {
+ .name = "fujitsu_ts",
+ },
+ .description = DRIVER_DESC,
+ .id_table = fujitsu_serio_ids,
+ .interrupt = fujitsu_interrupt,
+ .connect = fujitsu_connect,
+ .disconnect = fujitsu_disconnect,
+};
+
+static int __init fujitsu_init(void)
+{
+ return serio_register_driver(&fujitsu_drv);
+}
+
+static void __exit fujitsu_exit(void)
+{
+ serio_unregister_driver(&fujitsu_drv);
+}
+
+module_init(fujitsu_init);
+module_exit(fujitsu_exit);
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c
index f0cbcdb008ed..36f944019158 100644
--- a/drivers/input/touchscreen/ucb1400_ts.c
+++ b/drivers/input/touchscreen/ucb1400_ts.c
@@ -292,6 +292,7 @@ static int ucb1400_ts_thread(void *_ucb)
sched_setscheduler(tsk, SCHED_FIFO, &param);
+ set_freezable();
while (!kthread_should_stop()) {
unsigned int x, y, p;
long timeout;
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index 3e088c42b222..66f946aa30b3 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -2,12 +2,10 @@
# ISDN device configuration
#
-menu "ISDN subsystem"
- depends on !S390
-
-config ISDN
+menuconfig ISDN
tristate "ISDN support"
depends on NET
+ depends on !S390
---help---
ISDN ("Integrated Services Digital Networks", called RNIS in France)
is a special type of fully digital telephone service; it's mostly
@@ -21,11 +19,9 @@ config ISDN
Select this option if you want your kernel to support ISDN.
+if ISDN
-menu "Old ISDN4Linux"
- depends on NET && ISDN
-
-config ISDN_I4L
+menuconfig ISDN_I4L
tristate "Old ISDN4Linux (deprecated)"
---help---
This driver allows you to use an ISDN adapter for networking
@@ -47,23 +43,20 @@ if ISDN_I4L
source "drivers/isdn/i4l/Kconfig"
endif
-endmenu
-
-comment "CAPI subsystem"
- depends on NET && ISDN
-
-config ISDN_CAPI
- tristate "CAPI2.0 support"
- depends on ISDN
+menuconfig ISDN_CAPI
+ tristate "CAPI 2.0 subsystem"
help
This provides the CAPI (Common ISDN Application Programming
Interface, a standard making it easy for programs to access ISDN
hardware, see <http://www.capi.org/>. This is needed for AVM's set
of active ISDN controllers like B1, T1, M1.
+if ISDN_CAPI
+
source "drivers/isdn/capi/Kconfig"
source "drivers/isdn/hardware/Kconfig"
-endmenu
+endif # ISDN_CAPI
+endif # ISDN
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
index 78e6ad8d57c5..3fc1a5434ef7 100644
--- a/drivers/isdn/act2000/Kconfig
+++ b/drivers/isdn/act2000/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_ACT2000
tristate "IBM Active 2000 support"
- depends on ISDN_I4L && ISA
+ depends on ISA
help
Say Y here if you have an IBM Active 2000 ISDN card. In order to use
this card, additional firmware is necessary, which has to be loaded
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index c92f9d764fce..e1afd60924fb 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -3,7 +3,6 @@
#
config ISDN_DRV_AVMB1_VERBOSE_REASON
bool "Verbose reason code reporting"
- depends on ISDN_CAPI
default y
help
If you say Y here, the CAPI drivers will give verbose reasons for
@@ -12,7 +11,6 @@ config ISDN_DRV_AVMB1_VERBOSE_REASON
config CAPI_TRACE
bool "CAPI trace support"
- depends on ISDN_CAPI
default y
help
If you say Y here, the kernelcapi driver can make verbose traces
@@ -23,7 +21,7 @@ config CAPI_TRACE
config ISDN_CAPI_MIDDLEWARE
bool "CAPI2.0 Middleware support (EXPERIMENTAL)"
- depends on ISDN_CAPI && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
This option will enhance the capabilities of the /dev/capi20
interface. It will provide a means of moving a data connection,
@@ -33,7 +31,6 @@ config ISDN_CAPI_MIDDLEWARE
config ISDN_CAPI_CAPI20
tristate "CAPI2.0 /dev/capi support"
- depends on ISDN_CAPI
help
This option will provide the CAPI 2.0 interface to userspace
applications via /dev/capi20. Applications should use the
@@ -56,7 +53,7 @@ config ISDN_CAPI_CAPIFS
config ISDN_CAPI_CAPIDRV
tristate "CAPI2.0 capidrv interface support"
- depends on ISDN_CAPI && ISDN_I4L
+ depends on ISDN_I4L
help
This option provides the glue code to hook up CAPI driven cards to
the legacy isdn4linux link layer. If you have a card which is
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 81661b8bd3a8..f449daef3eed 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -549,7 +549,7 @@ static int handle_minor_send(struct capiminor *mp)
capimsg_setu8 (skb->data, 5, CAPI_REQ);
capimsg_setu16(skb->data, 6, mp->msgid++);
capimsg_setu32(skb->data, 8, mp->ncci); /* NCCI */
- capimsg_setu32(skb->data, 12, (u32) skb->data); /* Data32 */
+ capimsg_setu32(skb->data, 12, (u32)(long)skb->data);/* Data32 */
capimsg_setu16(skb->data, 16, len); /* Data length */
capimsg_setu16(skb->data, 18, datahandle);
capimsg_setu16(skb->data, 20, 0); /* Flags */
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 3ed34f7a1c4f..9f73bc2727c2 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -258,7 +258,7 @@ static void recv_handler(struct work_struct *work)
if ((!ap) || (ap->release_in_progress))
return;
- down(&ap->recv_sem);
+ mutex_lock(&ap->recv_mtx);
while ((skb = skb_dequeue(&ap->recv_queue))) {
if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND)
ap->nrecvdatapkt++;
@@ -267,7 +267,7 @@ static void recv_handler(struct work_struct *work)
ap->recv_message(ap, skb);
}
- up(&ap->recv_sem);
+ mutex_unlock(&ap->recv_mtx);
}
void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
@@ -547,7 +547,7 @@ u16 capi20_register(struct capi20_appl *ap)
ap->nsentctlpkt = 0;
ap->nsentdatapkt = 0;
ap->callback = NULL;
- init_MUTEX(&ap->recv_sem);
+ mutex_init(&ap->recv_mtx);
skb_queue_head_init(&ap->recv_queue);
INIT_WORK(&ap->recv_work, recv_handler);
ap->release_in_progress = 0;
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
index 31f4fd8b8b0a..845a797b0030 100644
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -243,36 +243,15 @@ create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
// ---------------------------------------------------------------------------
-
-static __inline__ struct capi_driver *capi_driver_get_idx(loff_t pos)
-{
- struct capi_driver *drv = NULL;
- struct list_head *l;
- loff_t i;
-
- i = 0;
- list_for_each(l, &capi_drivers) {
- drv = list_entry(l, struct capi_driver, list);
- if (i++ == pos)
- return drv;
- }
- return NULL;
-}
-
static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
{
- struct capi_driver *drv;
read_lock(&capi_drivers_list_lock);
- drv = capi_driver_get_idx(*pos);
- return drv;
+ return seq_list_start(&capi_drivers, *pos);
}
static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct capi_driver *drv = (struct capi_driver *)v;
- ++*pos;
- if (drv->list.next == &capi_drivers) return NULL;
- return list_entry(drv->list.next, struct capi_driver, list);
+ return seq_list_next(v, &capi_drivers, pos);
}
static void capi_driver_stop(struct seq_file *seq, void *v)
@@ -282,7 +261,8 @@ static void capi_driver_stop(struct seq_file *seq, void *v)
static int capi_driver_show(struct seq_file *seq, void *v)
{
- struct capi_driver *drv = (struct capi_driver *)v;
+ struct capi_driver *drv = list_entry(v, struct capi_driver, list);
+
seq_printf(seq, "%-32s %s\n", drv->name, drv->revision);
return 0;
}
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index bcbb6502a773..0017e50c6948 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -1,9 +1,5 @@
-menu "Siemens Gigaset"
- depends on ISDN_I4L
-
-config ISDN_DRV_GIGASET
+menuconfig ISDN_DRV_GIGASET
tristate "Siemens Gigaset support (isdn)"
- depends on ISDN_I4L
select CRC_CCITT
select BITREVERSE
help
@@ -55,6 +51,4 @@ config GIGASET_UNDOCREQ
features like configuration mode of M105, say yes. If you
care about your device, say no.
-endif
-
-endmenu
+endif # ISDN_DRV_GIGASET != n
diff --git a/drivers/isdn/hardware/Kconfig b/drivers/isdn/hardware/Kconfig
index 139f19797713..30d028d24955 100644
--- a/drivers/isdn/hardware/Kconfig
+++ b/drivers/isdn/hardware/Kconfig
@@ -2,7 +2,6 @@
# ISDN hardware drivers
#
comment "CAPI hardware drivers"
- depends on NET && ISDN && ISDN_CAPI
source "drivers/isdn/hardware/avm/Kconfig"
diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/isdn/hardware/avm/Kconfig
index 29a32a8830c0..5dbcbe3a54a6 100644
--- a/drivers/isdn/hardware/avm/Kconfig
+++ b/drivers/isdn/hardware/avm/Kconfig
@@ -2,23 +2,22 @@
# ISDN AVM drivers
#
-menu "Active AVM cards"
- depends on NET && ISDN && ISDN_CAPI!=n
-
-config CAPI_AVM
- bool "Support AVM cards"
+menuconfig CAPI_AVM
+ bool "Active AVM cards"
help
Enable support for AVM active ISDN cards.
+if CAPI_AVM
+
config ISDN_DRV_AVMB1_B1ISA
tristate "AVM B1 ISA support"
- depends on CAPI_AVM && ISDN_CAPI && ISA
+ depends on ISA
help
Enable support for the ISA version of the AVM B1 card.
config ISDN_DRV_AVMB1_B1PCI
tristate "AVM B1 PCI support"
- depends on CAPI_AVM && ISDN_CAPI && PCI
+ depends on PCI
help
Enable support for the PCI version of the AVM B1 card.
@@ -30,14 +29,13 @@ config ISDN_DRV_AVMB1_B1PCIV4
config ISDN_DRV_AVMB1_T1ISA
tristate "AVM T1/T1-B ISA support"
- depends on CAPI_AVM && ISDN_CAPI && ISA
+ depends on ISA
help
Enable support for the AVM T1 T1B card.
Note: This is a PRI card and handle 30 B-channels.
config ISDN_DRV_AVMB1_B1PCMCIA
tristate "AVM B1/M1/M2 PCMCIA support"
- depends on CAPI_AVM && ISDN_CAPI
help
Enable support for the PCMCIA version of the AVM B1 card.
@@ -50,17 +48,16 @@ config ISDN_DRV_AVMB1_AVM_CS
config ISDN_DRV_AVMB1_T1PCI
tristate "AVM T1/T1-B PCI support"
- depends on CAPI_AVM && ISDN_CAPI && PCI
+ depends on PCI
help
Enable support for the AVM T1 T1B card.
Note: This is a PRI card and handle 30 B-channels.
config ISDN_DRV_AVMB1_C4
tristate "AVM C4/C2 support"
- depends on CAPI_AVM && ISDN_CAPI && PCI
+ depends on PCI
help
Enable support for the AVM C4/C2 PCI cards.
These cards handle 4/2 BRI ISDN lines (8/4 channels).
-endmenu
-
+endif # CAPI_AVM
diff --git a/drivers/isdn/hardware/eicon/Kconfig b/drivers/isdn/hardware/eicon/Kconfig
index 01d4afd9d843..6082b6a5ced3 100644
--- a/drivers/isdn/hardware/eicon/Kconfig
+++ b/drivers/isdn/hardware/eicon/Kconfig
@@ -2,52 +2,50 @@
# ISDN DIVAS Eicon driver
#
-menu "Active Eicon DIVA Server cards"
- depends on NET && ISDN && ISDN_CAPI!=n
-
-config CAPI_EICON
- bool "Support Eicon cards"
+menuconfig CAPI_EICON
+ bool "Active Eicon DIVA Server cards"
help
Enable support for Eicon Networks active ISDN cards.
+if CAPI_EICON
+
config ISDN_DIVAS
tristate "Support Eicon DIVA Server cards"
- depends on CAPI_EICON && PROC_FS && PCI
+ depends on PROC_FS && PCI
help
Say Y here if you have an Eicon Networks DIVA Server PCI ISDN card.
In order to use this card, additional firmware is necessary, which
has to be downloaded into the card using the divactrl utility.
+if ISDN_DIVAS
+
config ISDN_DIVAS_BRIPCI
bool "DIVA Server BRI/PCI support"
- depends on ISDN_DIVAS
help
Enable support for DIVA Server BRI-PCI.
config ISDN_DIVAS_PRIPCI
bool "DIVA Server PRI/PCI support"
- depends on ISDN_DIVAS
help
Enable support for DIVA Server PRI-PCI.
config ISDN_DIVAS_DIVACAPI
tristate "DIVA CAPI2.0 interface support"
- depends on ISDN_DIVAS && ISDN_CAPI
help
You need this to provide the CAPI interface
for DIVA Server cards.
config ISDN_DIVAS_USERIDI
tristate "DIVA User-IDI interface support"
- depends on ISDN_DIVAS
help
Enable support for user-mode IDI interface.
config ISDN_DIVAS_MAINT
tristate "DIVA Maint driver support"
- depends on ISDN_DIVAS && m
+ depends on m
help
Enable Divas Maintenance driver.
-endmenu
+endif # ISDN_DIVAS
+endif # CAPI_EICON
diff --git a/drivers/isdn/hardware/eicon/idifunc.c b/drivers/isdn/hardware/eicon/idifunc.c
index 4cbc68cf4dba..db87d5105422 100644
--- a/drivers/isdn/hardware/eicon/idifunc.c
+++ b/drivers/isdn/hardware/eicon/idifunc.c
@@ -106,6 +106,7 @@ static void um_new_card(DESCRIPTOR * d)
} else {
DBG_ERR(("could not create user mode idi card %d",
adapter_nr));
+ diva_os_free(0, card);
}
}
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 12d91fb9f8cb..a3b945ac3256 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -1,6 +1,5 @@
menu "Passive cards"
- depends on ISDN_I4L
config ISDN_DRV_HISAX
tristate "HiSax SiemensChipSet driver support"
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index 871310d56a6e..3d1bdc8431ad 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -255,54 +255,38 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return (0);
}
-static struct pci_dev *dev_a4t __devinitdata = NULL;
+static int __devinit a4t_pci_probe(struct pci_dev *dev_a4t,
+ struct IsdnCardState *cs,
+ u_int *found,
+ u_int *pci_memaddr)
+{
+ u16 sub_sys;
+ u16 sub_vendor;
+
+ sub_vendor = dev_a4t->subsystem_vendor;
+ sub_sys = dev_a4t->subsystem_device;
+ if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
+ if (pci_enable_device(dev_a4t))
+ return (0); /* end loop & function */
+ *found = 1;
+ *pci_memaddr = pci_resource_start(dev_a4t, 0);
+ cs->irq = dev_a4t->irq;
+ return (1); /* end loop */
+ }
-int __devinit
-setup_bkm_a4t(struct IsdnCard *card)
+ return (-1); /* continue looping */
+}
+
+static int __devinit a4t_cs_init(struct IsdnCard *card,
+ struct IsdnCardState *cs,
+ u_int pci_memaddr)
{
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
- u_int pci_memaddr = 0, found = 0;
I20_REGISTER_FILE *pI20_Regs;
-#ifdef CONFIG_PCI
-#endif
-
- strcpy(tmp, bkm_a4t_revision);
- printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ == ISDN_CTYPE_BKM_A4T) {
- cs->subtyp = BKM_A4T;
- } else
- return (0);
-#ifdef CONFIG_PCI
- while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
- PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
- u16 sub_sys;
- u16 sub_vendor;
-
- sub_vendor = dev_a4t->subsystem_vendor;
- sub_sys = dev_a4t->subsystem_device;
- if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
- if (pci_enable_device(dev_a4t))
- return(0);
- found = 1;
- pci_memaddr = pci_resource_start(dev_a4t, 0);
- cs->irq = dev_a4t->irq;
- break;
- }
- }
- if (!found) {
- printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
- return (0);
- }
if (!cs->irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]);
return (0);
}
- if (!pci_memaddr) {
- printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
- return (0);
- }
cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096);
/* Check suspecious address */
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
@@ -317,11 +301,7 @@ setup_bkm_a4t(struct IsdnCard *card)
cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
cs->hw.ax.isac_ale = GCS_1;
cs->hw.ax.jade_ale = GCS_3;
-#else
- printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]);
- printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]);
- return (0);
-#endif /* CONFIG_PCI */
+
printk(KERN_INFO "HiSax: %s: Card configured at 0x%lX IRQ %d\n",
CardType[card->typ], cs->hw.ax.base, cs->irq);
@@ -339,5 +319,43 @@ setup_bkm_a4t(struct IsdnCard *card)
ISACVersion(cs, "Telekom A4T:");
/* Jade version */
JadeVersion(cs, "Telekom A4T:");
+
return (1);
}
+
+static struct pci_dev *dev_a4t __devinitdata = NULL;
+
+int __devinit
+setup_bkm_a4t(struct IsdnCard *card)
+{
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+ u_int pci_memaddr = 0, found = 0;
+ int ret;
+
+ strcpy(tmp, bkm_a4t_revision);
+ printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ == ISDN_CTYPE_BKM_A4T) {
+ cs->subtyp = BKM_A4T;
+ } else
+ return (0);
+
+ while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
+ PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
+ ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr);
+ if (!ret)
+ return (0);
+ if (ret > 0)
+ break;
+ }
+ if (!found) {
+ printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
+ return (0);
+ }
+ if (!pci_memaddr) {
+ printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
+ return (0);
+ }
+
+ return a4t_cs_init(card, cs, pci_memaddr);
+}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 340310645346..6339bb443f62 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -287,7 +287,6 @@ setup_sct_quadro(struct IsdnCard *card)
#ifdef CONFIG_PCI
struct IsdnCardState *cs = card->cs;
char tmp[64];
- u_char pci_rev_id;
u_int found = 0;
u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
@@ -335,8 +334,7 @@ setup_sct_quadro(struct IsdnCard *card)
}
#ifdef ATTEMPT_PCI_REMAPPING
/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
- pci_read_config_byte(dev_a8, PCI_REVISION_ID, &pci_rev_id);
- if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
+ if ((pci_ioaddr1 & 0x80) && (dev_a8->revision == 1)) {
printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp]);
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 8d53a7fd2671..97097ef3491e 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -361,11 +361,11 @@ module_param_array(io1, int, NULL, 0);
int nrcards;
-extern char *l1_revision;
-extern char *l2_revision;
-extern char *l3_revision;
-extern char *lli_revision;
-extern char *tei_revision;
+extern const char *l1_revision;
+extern const char *l2_revision;
+extern const char *l3_revision;
+extern const char *lli_revision;
+extern const char *tei_revision;
char *HiSax_getrev(const char *revision)
{
@@ -847,95 +847,10 @@ static int init_card(struct IsdnCardState *cs)
return 3;
}
-static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
+static int hisax_cs_setup_card(struct IsdnCard *card)
{
- int ret = 0;
- struct IsdnCard *card = cards + cardnr;
- struct IsdnCardState *cs;
-
- cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
- if (!cs) {
- printk(KERN_WARNING
- "HiSax: No memory for IsdnCardState(card %d)\n",
- cardnr + 1);
- goto out;
- }
- card->cs = cs;
- spin_lock_init(&cs->statlock);
- spin_lock_init(&cs->lock);
- cs->chanlimit = 2; /* maximum B-channel number */
- cs->logecho = 0; /* No echo logging */
- cs->cardnr = cardnr;
- cs->debug = L1_DEB_WARN;
- cs->HW_Flags = 0;
- cs->busy_flag = busy_flag;
- cs->irq_flags = I4L_IRQ_FLAG;
-#if TEI_PER_CARD
- if (card->protocol == ISDN_PTYPE_NI1)
- test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#else
- test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
-#endif
- cs->protocol = card->protocol;
-
- if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
- printk(KERN_WARNING
- "HiSax: Card Type %d out of range\n", card->typ);
- goto outf_cs;
- }
- if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
- goto outf_cs;
- }
- if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
- printk(KERN_WARNING
- "HiSax: No memory for status_buf(card %d)\n",
- cardnr + 1);
- goto outf_dlog;
- }
- cs->stlist = NULL;
- cs->status_read = cs->status_buf;
- cs->status_write = cs->status_buf;
- cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
- cs->typ = card->typ;
-#ifdef MODULE
- cs->iif.owner = lockowner;
-#endif
- strcpy(cs->iif.id, id);
- cs->iif.channels = 2;
- cs->iif.maxbufsize = MAX_DATA_SIZE;
- cs->iif.hl_hdrlen = MAX_HEADER_LEN;
- cs->iif.features =
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L2_HDLC_56K |
- ISDN_FEATURE_L2_TRANS |
- ISDN_FEATURE_L3_TRANS |
-#ifdef CONFIG_HISAX_1TR6
- ISDN_FEATURE_P_1TR6 |
-#endif
-#ifdef CONFIG_HISAX_EURO
- ISDN_FEATURE_P_EURO |
-#endif
-#ifdef CONFIG_HISAX_NI1
- ISDN_FEATURE_P_NI1 |
-#endif
- 0;
+ int ret;
- cs->iif.command = HiSax_command;
- cs->iif.writecmd = NULL;
- cs->iif.writebuf_skb = HiSax_writebuf_skb;
- cs->iif.readstat = HiSax_readstatus;
- register_isdn(&cs->iif);
- cs->myid = cs->iif.channels;
- printk(KERN_INFO
- "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
- (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
- (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
- (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
- (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
- "NONE", cs->iif.id, cs->myid);
switch (card->typ) {
#if CARD_TELES0
case ISDN_CTYPE_16_0:
@@ -1094,13 +1009,115 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
printk(KERN_WARNING
"HiSax: Support for %s Card not selected\n",
CardType[card->typ]);
- ll_unload(cs);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int hisax_cs_new(int cardnr, char *id, struct IsdnCard *card,
+ struct IsdnCardState **cs_out, int *busy_flag,
+ struct module *lockowner)
+{
+ struct IsdnCardState *cs;
+
+ *cs_out = NULL;
+
+ cs = kzalloc(sizeof(struct IsdnCardState), GFP_ATOMIC);
+ if (!cs) {
+ printk(KERN_WARNING
+ "HiSax: No memory for IsdnCardState(card %d)\n",
+ cardnr + 1);
+ goto out;
+ }
+ card->cs = cs;
+ spin_lock_init(&cs->statlock);
+ spin_lock_init(&cs->lock);
+ cs->chanlimit = 2; /* maximum B-channel number */
+ cs->logecho = 0; /* No echo logging */
+ cs->cardnr = cardnr;
+ cs->debug = L1_DEB_WARN;
+ cs->HW_Flags = 0;
+ cs->busy_flag = busy_flag;
+ cs->irq_flags = I4L_IRQ_FLAG;
+#if TEI_PER_CARD
+ if (card->protocol == ISDN_PTYPE_NI1)
+ test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#else
+ test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
+#endif
+ cs->protocol = card->protocol;
+
+ if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) {
+ printk(KERN_WARNING
+ "HiSax: Card Type %d out of range\n", card->typ);
goto outf_cs;
}
- if (!ret) {
- ll_unload(cs);
+ if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for dlog(card %d)\n", cardnr + 1);
goto outf_cs;
}
+ if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) {
+ printk(KERN_WARNING
+ "HiSax: No memory for status_buf(card %d)\n",
+ cardnr + 1);
+ goto outf_dlog;
+ }
+ cs->stlist = NULL;
+ cs->status_read = cs->status_buf;
+ cs->status_write = cs->status_buf;
+ cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1;
+ cs->typ = card->typ;
+#ifdef MODULE
+ cs->iif.owner = lockowner;
+#endif
+ strcpy(cs->iif.id, id);
+ cs->iif.channels = 2;
+ cs->iif.maxbufsize = MAX_DATA_SIZE;
+ cs->iif.hl_hdrlen = MAX_HEADER_LEN;
+ cs->iif.features =
+ ISDN_FEATURE_L2_X75I |
+ ISDN_FEATURE_L2_HDLC |
+ ISDN_FEATURE_L2_HDLC_56K |
+ ISDN_FEATURE_L2_TRANS |
+ ISDN_FEATURE_L3_TRANS |
+#ifdef CONFIG_HISAX_1TR6
+ ISDN_FEATURE_P_1TR6 |
+#endif
+#ifdef CONFIG_HISAX_EURO
+ ISDN_FEATURE_P_EURO |
+#endif
+#ifdef CONFIG_HISAX_NI1
+ ISDN_FEATURE_P_NI1 |
+#endif
+ 0;
+
+ cs->iif.command = HiSax_command;
+ cs->iif.writecmd = NULL;
+ cs->iif.writebuf_skb = HiSax_writebuf_skb;
+ cs->iif.readstat = HiSax_readstatus;
+ register_isdn(&cs->iif);
+ cs->myid = cs->iif.channels;
+
+ *cs_out = cs;
+ return 1; /* success */
+
+outf_dlog:
+ kfree(cs->dlog);
+outf_cs:
+ kfree(cs);
+ card->cs = NULL;
+out:
+ return 0; /* error */
+}
+
+static int hisax_cs_setup(int cardnr, struct IsdnCard *card,
+ struct IsdnCardState *cs)
+{
+ int ret;
+
if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) {
printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n");
ll_unload(cs);
@@ -1129,25 +1146,53 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
}
if (ret) {
closecard(cardnr);
- ret = 0;
goto outf_cs;
}
init_tei(cs, cs->protocol);
ret = CallcNewChan(cs);
if (ret) {
closecard(cardnr);
- ret = 0;
goto outf_cs;
}
/* ISAR needs firmware download first */
if (!test_bit(HW_ISAR, &cs->HW_Flags))
ll_run(cs, 0);
- ret = 1;
+ return 1;
+
+outf_cs:
+ kfree(cs);
+ card->cs = NULL;
+ return 0;
+}
+
+static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
+{
+ int ret;
+ struct IsdnCard *card = cards + cardnr;
+ struct IsdnCardState *cs;
+
+ ret = hisax_cs_new(cardnr, id, card, &cs, busy_flag, lockowner);
+ if (!ret)
+ return 0;
+
+ printk(KERN_INFO
+ "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1,
+ (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" :
+ (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" :
+ (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" :
+ (card->protocol == ISDN_PTYPE_NI1) ? "NI1" :
+ "NONE", cs->iif.id, cs->myid);
+
+ ret = hisax_cs_setup_card(card);
+ if (!ret) {
+ ll_unload(cs);
+ goto outf_cs;
+ }
+
+ ret = hisax_cs_setup(cardnr, card, cs);
goto out;
- outf_dlog:
- kfree(cs->dlog);
outf_cs:
kfree(cs);
card->cs = NULL;
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index b45de9d408d1..b73027ff50e8 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -300,98 +300,72 @@ enpci_interrupt(int intno, void *dev_id)
return IRQ_HANDLED;
}
-
-static struct pci_dev *dev_netjet __devinitdata = NULL;
-
-/* called by config.c */
-int __devinit
-setup_enternow_pci(struct IsdnCard *card)
+static int __devinit en_pci_probe(struct pci_dev *dev_netjet,
+ struct IsdnCardState *cs)
{
- int bytecnt;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-
-#ifdef CONFIG_PCI
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
- strcpy(tmp, enternow_pci_rev);
- printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_ENTERNOW)
+ if (pci_enable_device(dev_netjet))
return(0);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-
- for ( ;; )
- {
- if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
- if (pci_enable_device(dev_netjet))
- return(0);
- cs->irq = dev_netjet->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
- if (!cs->hw.njet.base) {
- printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
- return(0);
- }
- /* checks Sub-Vendor ID because system crashes with Traverse-Card */
- if ((dev_netjet->subsystem_vendor != 0x55) ||
- (dev_netjet->subsystem_device != 0x02)) {
- printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
- printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
- return(0);
- }
- } else {
- printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
- return(0);
- }
-
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
-
- /* Reset an */
- cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff
- outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
- /* 20 ms Pause */
- mdelay(20);
+ cs->irq = dev_netjet->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ /* checks Sub-Vendor ID because system crashes with Traverse-Card */
+ if ((dev_netjet->subsystem_vendor != 0x55) ||
+ (dev_netjet->subsystem_device != 0x02)) {
+ printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
+ printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
+ return(0);
+ }
- cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
- outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
- mdelay(10);
+ return(1);
+}
- cs->hw.njet.auxd = 0x00; // war 0xc0
- cs->hw.njet.dmactrl = 0;
+static void __devinit en_cs_init(struct IsdnCard *card,
+ struct IsdnCardState *cs)
+{
+ cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+ cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
- outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
- outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
- outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
+ /* Reset an */
+ cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff
+ outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
+ /* 20 ms Pause */
+ mdelay(20);
- break;
- }
-#else
+ cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
+ outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
+ mdelay(10);
- printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
- printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
- return (0);
+ cs->hw.njet.auxd = 0x00; // war 0xc0
+ cs->hw.njet.dmactrl = 0;
-#endif /* CONFIG_PCI */
+ outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
+ outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
+ outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
+}
- bytecnt = 256;
+static int __devinit en_cs_init_rest(struct IsdnCard *card,
+ struct IsdnCardState *cs)
+{
+ const int bytecnt = 256;
printk(KERN_INFO
"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
cs->hw.njet.base, cs->irq);
if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) {
printk(KERN_WARNING
- "HiSax: %s config port %lx-%lx already in use\n",
- CardType[card->typ],
- cs->hw.njet.base,
- cs->hw.njet.base + bytecnt);
+ "HiSax: enter:now config port %lx-%lx already in use\n",
+ cs->hw.njet.base,
+ cs->hw.njet.base + bytecnt);
return (0);
}
+
setup_Amd7930(cs);
cs->hw.njet.last_is0 = 0;
/* macro rByteAMD */
@@ -407,5 +381,44 @@ setup_enternow_pci(struct IsdnCard *card)
cs->irq_func = &enpci_interrupt;
cs->irq_flags |= IRQF_SHARED;
- return (1);
+ return (1);
+}
+
+static struct pci_dev *dev_netjet __devinitdata = NULL;
+
+/* called by config.c */
+int __devinit
+setup_enternow_pci(struct IsdnCard *card)
+{
+ int ret;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+
+ strcpy(tmp, enternow_pci_rev);
+ printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_ENTERNOW)
+ return(0);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+ for ( ;; )
+ {
+ if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
+ ret = en_pci_probe(dev_netjet, cs);
+ if (!ret)
+ return(0);
+ } else {
+ printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
+ return(0);
+ }
+
+ en_cs_init(card, cs);
+ break;
+ }
+
+ return en_cs_init_rest(card, cs);
}
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 8a48a3ce0a55..077080aca799 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -6,7 +6,7 @@
* based on existing driver for CCD hfc ISA cards
* Copyright by Werner Cornelius <werner@isdn4linux.de>
* by Karsten Keil <keil@isdn4linux.de>
- *
+ *
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
@@ -67,8 +67,6 @@ static const PCI_ENTRY id_list[] =
};
-#ifdef CONFIG_PCI
-
/******************************************/
/* free hardware resources used by driver */
/******************************************/
@@ -237,7 +235,7 @@ static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo)
if (fifo_state)
cs->hw.hfcpci.fifo_en |= fifo_state;
Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-}
+}
/***************************************/
/* clear the desired B-channel tx fifo */
@@ -263,7 +261,7 @@ static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo)
if (fifo_state)
cs->hw.hfcpci.fifo_en |= fifo_state;
Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en);
-}
+}
/*********************************************/
/* read a complete B-frame out of the buffer */
@@ -511,7 +509,6 @@ main_rec_hfcpci(struct BCState *bcs)
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
if (count && receive)
goto Begin;
- return;
}
/**************************/
@@ -582,7 +579,6 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs)
dev_kfree_skb_any(cs->tx_skb);
cs->tx_skb = NULL;
- return;
}
/**************************/
@@ -729,7 +725,6 @@ hfcpci_fill_fifo(struct BCState *bcs)
dev_kfree_skb_any(bcs->tx_skb);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
- return;
}
/**********************************************/
@@ -924,7 +919,6 @@ receive_emsg(struct IsdnCardState *cs)
test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
if (count && receive)
goto Begin;
- return;
} /* receive_emsg */
/*********************/
@@ -1350,13 +1344,13 @@ mode_hfcpci(struct BCState *bcs, int mode, int bc)
cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA;
}
if (fifo2) {
- cs->hw.hfcpci.last_bfifo_cnt[1] = 0;
+ cs->hw.hfcpci.last_bfifo_cnt[1] = 0;
cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2;
cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC);
cs->hw.hfcpci.ctmt &= ~2;
cs->hw.hfcpci.conn &= ~0x18;
} else {
- cs->hw.hfcpci.last_bfifo_cnt[0] = 0;
+ cs->hw.hfcpci.last_bfifo_cnt[0] = 0;
cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1;
cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC);
cs->hw.hfcpci.ctmt &= ~1;
@@ -1642,8 +1636,6 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
/* this variable is used as card index when more than one cards are present */
static struct pci_dev *dev_hfcpci __devinitdata = NULL;
-#endif /* CONFIG_PCI */
-
int __devinit
setup_hfcpci(struct IsdnCard *card)
{
@@ -1656,96 +1648,99 @@ setup_hfcpci(struct IsdnCard *card)
#ifdef __BIG_ENDIAN
#error "not running on big endian machines now"
#endif
+
strcpy(tmp, hfcpci_revision);
printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
-#ifdef CONFIG_PCI
+
cs->hw.hfcpci.int_s1 = 0;
cs->dc.hfcpci.ph_state = 0;
cs->hw.hfcpci.fifo = 255;
- if (cs->typ == ISDN_CTYPE_HFC_PCI) {
- i = 0;
- while (id_list[i].vendor_id) {
- tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
- id_list[i].device_id,
- dev_hfcpci);
- i++;
- if (tmp_hfcpci) {
- if (pci_enable_device(tmp_hfcpci))
- continue;
- pci_set_master(tmp_hfcpci);
- if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
- continue;
- else
- break;
- }
- }
-
+ if (cs->typ != ISDN_CTYPE_HFC_PCI)
+ return(0);
+
+ i = 0;
+ while (id_list[i].vendor_id) {
+ tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
+ id_list[i].device_id,
+ dev_hfcpci);
+ i++;
if (tmp_hfcpci) {
- i--;
- dev_hfcpci = tmp_hfcpci; /* old device */
- cs->hw.hfcpci.dev = dev_hfcpci;
- cs->irq = dev_hfcpci->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
- return (0);
- }
- cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
- printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
- } else {
- printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
- return (0);
- }
- if (!cs->hw.hfcpci.pci_io) {
- printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
- return (0);
- }
- /* Allocate memory for FIFOS */
- /* Because the HFC-PCI needs a 32K physical alignment, we */
- /* need to allocate the double mem and align the address */
- if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
- printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
- return 0;
+ if (pci_enable_device(tmp_hfcpci))
+ continue;
+ pci_set_master(tmp_hfcpci);
+ if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[ 0].start & PCI_BASE_ADDRESS_IO_MASK)))
+ continue;
+ else
+ break;
}
- cs->hw.hfcpci.fifos = (void *)
- (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
- pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
- cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
- printk(KERN_INFO
- "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n",
- cs->hw.hfcpci.pci_io,
- cs->hw.hfcpci.fifos,
- (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
- cs->irq, HZ);
- spin_lock_irqsave(&cs->lock, flags);
- pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
- cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
- cs->hw.hfcpci.int_m1 = 0;
- Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
- Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
- /* At this point the needed PCI config is done */
- /* fifos are still not enabled */
- INIT_WORK(&cs->tqueue, hfcpci_bh);
- cs->setstack_d = setstack_hfcpci;
- cs->BC_Send_Data = &hfcpci_send_data;
- cs->readisac = NULL;
- cs->writeisac = NULL;
- cs->readisacfifo = NULL;
- cs->writeisacfifo = NULL;
- cs->BC_Read_Reg = NULL;
- cs->BC_Write_Reg = NULL;
- cs->irq_func = &hfcpci_interrupt;
- cs->irq_flags |= IRQF_SHARED;
- cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
- cs->hw.hfcpci.timer.data = (long) cs;
- init_timer(&cs->hw.hfcpci.timer);
- cs->cardmsg = &hfcpci_card_msg;
- cs->auxcmd = &hfcpci_auxcmd;
- spin_unlock_irqrestore(&cs->lock, flags);
- return (1);
- } else
- return (0); /* no valid card type */
-#else
- printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
- return (0);
-#endif /* CONFIG_PCI */
+ }
+
+ if (!tmp_hfcpci) {
+ printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
+ return (0);
+ }
+
+ i--;
+ dev_hfcpci = tmp_hfcpci; /* old device */
+ cs->hw.hfcpci.dev = dev_hfcpci;
+ cs->irq = dev_hfcpci->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
+ return (0);
+ }
+ cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
+ printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
+
+ if (!cs->hw.hfcpci.pci_io) {
+ printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
+ return (0);
+ }
+ /* Allocate memory for FIFOS */
+ /* Because the HFC-PCI needs a 32K physical alignment, we */
+ /* need to allocate the double mem and align the address */
+ if (!(cs->hw.hfcpci.share_start = kmalloc(65536, GFP_KERNEL))) {
+ printk(KERN_WARNING "HFC-PCI: Error allocating memory for FIFO!\n");
+ return 0;
+ }
+ cs->hw.hfcpci.fifos = (void *)
+ (((ulong) cs->hw.hfcpci.share_start) & ~0x7FFF) + 0x8000;
+ pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u_int) virt_to_bus(cs->hw.hfcpci.fifos));
+ cs->hw.hfcpci.pci_io = ioremap((ulong) cs->hw.hfcpci.pci_io, 256);
+ printk(KERN_INFO
+ "HFC-PCI: defined at mem %p fifo %p(%#x) IRQ %d HZ %d\n",
+ cs->hw.hfcpci.pci_io,
+ cs->hw.hfcpci.fifos,
+ (u_int) virt_to_bus(cs->hw.hfcpci.fifos),
+ cs->irq, HZ);
+
+ spin_lock_irqsave(&cs->lock, flags);
+
+ pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */
+ cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */
+ cs->hw.hfcpci.int_m1 = 0;
+ Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1);
+ Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2);
+ /* At this point the needed PCI config is done */
+ /* fifos are still not enabled */
+
+ INIT_WORK(&cs->tqueue, hfcpci_bh);
+ cs->setstack_d = setstack_hfcpci;
+ cs->BC_Send_Data = &hfcpci_send_data;
+ cs->readisac = NULL;
+ cs->writeisac = NULL;
+ cs->readisacfifo = NULL;
+ cs->writeisacfifo = NULL;
+ cs->BC_Read_Reg = NULL;
+ cs->BC_Write_Reg = NULL;
+ cs->irq_func = &hfcpci_interrupt;
+ cs->irq_flags |= IRQF_SHARED;
+ cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
+ cs->hw.hfcpci.timer.data = (long) cs;
+ init_timer(&cs->hw.hfcpci.timer);
+ cs->cardmsg = &hfcpci_card_msg;
+ cs->auxcmd = &hfcpci_auxcmd;
+
+ spin_unlock_irqrestore(&cs->lock, flags);
+
+ return (1);
}
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index c09ffb135330..fa2db87667c8 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -148,107 +148,87 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_netjet __devinitdata = NULL;
-
-int __devinit
-setup_netjet_s(struct IsdnCard *card)
+static int __devinit njs_pci_probe(struct pci_dev *dev_netjet,
+ struct IsdnCardState *cs)
{
- int bytecnt,cfg;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
+ int cfg;
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
- strcpy(tmp, NETjet_S_revision);
- printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_NETJET_S)
+ if (pci_enable_device(dev_netjet))
return(0);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+ pci_set_master(dev_netjet);
+ cs->irq = dev_netjet->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
+ return(0);
+ }
+ /* the TJ300 and TJ320 must be detected, the IRQ handling is different
+ * unfortunatly the chips use the same device ID, but the TJ320 has
+ * the bit20 in status PCI cfg register set
+ */
+ pci_read_config_dword(dev_netjet, 0x04, &cfg);
+ if (cfg & 0x00100000)
+ cs->subtyp = 1; /* TJ320 */
+ else
+ cs->subtyp = 0; /* TJ300 */
+ /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
+ if ((dev_netjet->subsystem_vendor == 0x55) &&
+ (dev_netjet->subsystem_device == 0x02)) {
+ printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
+ printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
+ return(0);
+ }
+ /* end new code */
-#ifdef CONFIG_PCI
+ return(1);
+}
- for ( ;; )
- {
- if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
- if (pci_enable_device(dev_netjet))
- return(0);
- pci_set_master(dev_netjet);
- cs->irq = dev_netjet->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
- if (!cs->hw.njet.base) {
- printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
- return(0);
- }
- /* the TJ300 and TJ320 must be detected, the IRQ handling is different
- * unfortunatly the chips use the same device ID, but the TJ320 has
- * the bit20 in status PCI cfg register set
- */
- pci_read_config_dword(dev_netjet, 0x04, &cfg);
- if (cfg & 0x00100000)
- cs->subtyp = 1; /* TJ320 */
- else
- cs->subtyp = 0; /* TJ300 */
- /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
- if ((dev_netjet->subsystem_vendor == 0x55) &&
- (dev_netjet->subsystem_device == 0x02)) {
- printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
- printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
- return(0);
- }
- /* end new code */
- } else {
- printk(KERN_WARNING "NETjet-S: No PCI card found\n");
- return(0);
- }
+static int __devinit njs_cs_init(struct IsdnCard *card,
+ struct IsdnCardState *cs)
+{
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+ cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+ cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
- cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
+ cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ mdelay(10);
- cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
+ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ mdelay(10);
- cs->hw.njet.auxd = 0xC0;
- cs->hw.njet.dmactrl = 0;
+ cs->hw.njet.auxd = 0xC0;
+ cs->hw.njet.dmactrl = 0;
- byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+ byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
- {
- case 0 :
- break;
+ switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
+ {
+ case 0 :
+ return 1; /* end loop */
- case 3 :
- printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
- continue;
+ case 3 :
+ printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
+ return -1; /* continue looping */
- default :
- printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
- return 0;
- }
- break;
+ default :
+ printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
+ return 0; /* end loop & function */
}
-#else
-
- printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n");
- printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n");
- return (0);
-
-#endif /* CONFIG_PCI */
+ return 1; /* end loop */
+}
- bytecnt = 256;
+static int __devinit njs_cs_init_rest(struct IsdnCard *card,
+ struct IsdnCardState *cs)
+{
+ const int bytecnt = 256;
printk(KERN_INFO
"NETjet-S: %s card configured at %#lx IRQ %d\n",
@@ -273,5 +253,47 @@ setup_netjet_s(struct IsdnCard *card)
cs->irq_func = &netjet_s_interrupt;
cs->irq_flags |= IRQF_SHARED;
ISACVersion(cs, "NETjet-S:");
+
return (1);
}
+
+static struct pci_dev *dev_netjet __devinitdata = NULL;
+
+int __devinit
+setup_netjet_s(struct IsdnCard *card)
+{
+ int ret;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+ strcpy(tmp, NETjet_S_revision);
+ printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_NETJET_S)
+ return(0);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+ for ( ;; )
+ {
+ if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
+ ret = njs_pci_probe(dev_netjet, cs);
+ if (!ret)
+ return(0);
+ } else {
+ printk(KERN_WARNING "NETjet-S: No PCI card found\n");
+ return(0);
+ }
+
+ ret = njs_cs_init(card, cs);
+ if (!ret)
+ return(0);
+ if (ret > 0)
+ break;
+ /* otherwise, ret < 0, continue looping */
+ }
+
+ return njs_cs_init_rest(card, cs);
+}
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index 8202cf34ecae..f017d3816b1d 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -128,93 +128,69 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_netjet __devinitdata = NULL;
-
-int __devinit
-setup_netjet_u(struct IsdnCard *card)
+static int __devinit nju_pci_probe(struct pci_dev *dev_netjet,
+ struct IsdnCardState *cs)
{
- int bytecnt;
- struct IsdnCardState *cs = card->cs;
- char tmp[64];
-#ifdef CONFIG_PCI
-#endif
-#ifdef __BIG_ENDIAN
-#error "not running on big endian machines now"
-#endif
- strcpy(tmp, NETjet_U_revision);
- printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
- if (cs->typ != ISDN_CTYPE_NETJET_U)
+ if (pci_enable_device(dev_netjet))
return(0);
- test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-
-#ifdef CONFIG_PCI
+ pci_set_master(dev_netjet);
+ cs->irq = dev_netjet->irq;
+ if (!cs->irq) {
+ printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
+ return(0);
+ }
+ cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+ if (!cs->hw.njet.base) {
+ printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
+ return(0);
+ }
- for ( ;; )
- {
- if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
- PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
- if (pci_enable_device(dev_netjet))
- return(0);
- pci_set_master(dev_netjet);
- cs->irq = dev_netjet->irq;
- if (!cs->irq) {
- printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
- return(0);
- }
- cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
- if (!cs->hw.njet.base) {
- printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
- return(0);
- }
- } else {
- printk(KERN_WARNING "NETspider-U: No PCI card found\n");
- return(0);
- }
+ return (1);
+}
- cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
- cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
- mdelay(10);
+static int __devinit nju_cs_init(struct IsdnCard *card,
+ struct IsdnCardState *cs)
+{
+ cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+ cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+ mdelay(10);
- cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
+ cs->hw.njet.ctrl_reg = 0xff; /* Reset On */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ mdelay(10);
- cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
- byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
- mdelay(10);
+ cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */
+ byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ mdelay(10);
- cs->hw.njet.auxd = 0xC0;
- cs->hw.njet.dmactrl = 0;
+ cs->hw.njet.auxd = 0xC0;
+ cs->hw.njet.dmactrl = 0;
- byteout(cs->hw.njet.auxa, 0);
- byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
- byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
- byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+ byteout(cs->hw.njet.auxa, 0);
+ byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+ byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+ byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
- switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
- {
- case 3 :
- break;
+ switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
+ {
+ case 3 :
+ return 1; /* end loop */
- case 0 :
- printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
- continue;
+ case 0 :
+ printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
+ return -1; /* continue looping */
- default :
- printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
- return 0;
- }
- break;
+ default :
+ printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
+ return 0; /* end loop & function */
}
-#else
-
- printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n");
- printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n");
- return (0);
-
-#endif /* CONFIG_PCI */
+ return 1; /* end loop */
+}
- bytecnt = 256;
+static int __devinit nju_cs_init_rest(struct IsdnCard *card,
+ struct IsdnCardState *cs)
+{
+ const int bytecnt = 256;
printk(KERN_INFO
"NETspider-U: PCI card configured at %#lx IRQ %d\n",
@@ -239,5 +215,48 @@ setup_netjet_u(struct IsdnCard *card)
cs->irq_func = &netjet_u_interrupt;
cs->irq_flags |= IRQF_SHARED;
ICCVersion(cs, "NETspider-U:");
+
return (1);
}
+
+static struct pci_dev *dev_netjet __devinitdata = NULL;
+
+int __devinit
+setup_netjet_u(struct IsdnCard *card)
+{
+ int ret;
+ struct IsdnCardState *cs = card->cs;
+ char tmp[64];
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+
+ strcpy(tmp, NETjet_U_revision);
+ printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
+ if (cs->typ != ISDN_CTYPE_NETJET_U)
+ return(0);
+ test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+ for ( ;; )
+ {
+ if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+ PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) {
+ ret = nju_pci_probe(dev_netjet, cs);
+ if (!ret)
+ return(0);
+ } else {
+ printk(KERN_WARNING "NETspider-U: No PCI card found\n");
+ return(0);
+ }
+
+ ret = nju_cs_init(card, cs);
+ if (!ret)
+ return (0);
+ if (ret > 0)
+ break;
+ /* ret < 0 == continue looping */
+ }
+
+ return nju_cs_init_rest(card, cs);
+}
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 030d1625c5c6..ad06f3cc60fb 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -451,6 +451,9 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
spin_unlock_irqrestore(&cs->lock, flags);
return(0);
case CARD_RELEASE:
+ if (cs->hw.sedl.bus == SEDL_BUS_PCI)
+ /* disable all IRQ */
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0);
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
spin_lock_irqsave(&cs->lock, flags);
writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx,
@@ -468,6 +471,9 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
case CARD_INIT:
spin_lock_irqsave(&cs->lock, flags);
+ if (cs->hw.sedl.bus == SEDL_BUS_PCI)
+ /* enable all IRQ */
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
reset_sedlbauer(cs);
if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) {
clear_pending_isac_ints(cs);
@@ -667,7 +673,7 @@ setup_sedlbauer(struct IsdnCard *card)
byteout(cs->hw.sedl.cfg_reg, 0xff);
byteout(cs->hw.sedl.cfg_reg, 0x00);
byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
- byteout(cs->hw.sedl.cfg_reg+ 5, 0x02);
+ byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
mdelay(2);
byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index 3ef567b99c74..36778b270c30 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -86,7 +86,6 @@ config ISDN_X25
menu "ISDN feature submodules"
- depends on ISDN
config ISDN_DRV_LOOP
tristate "isdnloop support"
@@ -100,7 +99,6 @@ config ISDN_DRV_LOOP
config ISDN_DIVERSION
tristate "Support isdn diversion services"
- depends on ISDN && ISDN_I4L
help
This option allows you to use some supplementary diversion
services in conjunction with the HiSax driver on an EURO/DSS1
@@ -120,13 +118,11 @@ config ISDN_DIVERSION
endmenu
comment "ISDN4Linux hardware drivers"
- depends on NET && ISDN && ISDN_I4L
source "drivers/isdn/hisax/Kconfig"
menu "Active cards"
- depends on NET && ISDN && ISDN_I4L!=n
source "drivers/isdn/icn/Kconfig"
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
index fcb99f5f0b26..89d15eed765e 100644
--- a/drivers/isdn/icn/Kconfig
+++ b/drivers/isdn/icn/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_ICN
tristate "ICN 2B and 4B support"
- depends on ISDN_I4L && ISA
+ depends on ISA
help
This enables support for two kinds of ISDN-cards made by a German
company called ICN. 2B is the standard version for a single ISDN
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
index 0933881ab0c2..ffba6eca1244 100644
--- a/drivers/isdn/pcbit/Kconfig
+++ b/drivers/isdn/pcbit/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_PCBIT
tristate "PCBIT-D support"
- depends on ISDN_I4L && ISA && (BROKEN || X86)
+ depends on ISA && (BROKEN || X86)
help
This enables support for the PCBIT ISDN-card. This card is
manufactured in Portugal by Octal. For running this card,
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
index 5346e33d816c..e6510ca7bf43 100644
--- a/drivers/isdn/sc/Kconfig
+++ b/drivers/isdn/sc/Kconfig
@@ -3,7 +3,7 @@
#
config ISDN_DRV_SC
tristate "Spellcaster support"
- depends on ISDN_I4L && ISA
+ depends on ISA
help
This enables support for the Spellcaster BRI ISDN boards. This
driver currently builds only in a modularized version.
diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h
index 4fbfa825c3a2..5992f63c383e 100644
--- a/drivers/isdn/sc/card.h
+++ b/drivers/isdn/sc/card.h
@@ -125,7 +125,7 @@ int sendmessage(int card, unsigned int procid, unsigned int type,
int receivemessage(int card, RspMessage *rspmsg);
int sc_ioctl(int card, scs_ioctl *data);
int setup_buffers(int card, int c);
-void check_reset(unsigned long data);
+void sc_check_reset(unsigned long data);
void check_phystat(unsigned long data);
#endif /* CARD_H */
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
index b7bb7cbcf503..0e4969c2ef95 100644
--- a/drivers/isdn/sc/command.c
+++ b/drivers/isdn/sc/command.c
@@ -344,7 +344,7 @@ int reset(int card)
spin_lock_irqsave(&sc_adapter[card]->lock, flags);
init_timer(&sc_adapter[card]->reset_timer);
- sc_adapter[card]->reset_timer.function = check_reset;
+ sc_adapter[card]->reset_timer.function = sc_check_reset;
sc_adapter[card]->reset_timer.data = card;
sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
add_timer(&sc_adapter[card]->reset_timer);
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
index cc1b8861be2a..91fbe0dc28ec 100644
--- a/drivers/isdn/sc/timer.c
+++ b/drivers/isdn/sc/timer.c
@@ -43,7 +43,7 @@ static void setup_ports(int card)
* Then, check to see if the signate has been set. Next, set the
* signature to a known value and issue a startproc if needed.
*/
-void check_reset(unsigned long data)
+void sc_check_reset(unsigned long data)
{
unsigned long flags;
unsigned long sig;
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index e8e37d826478..6cecc396e040 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -1,12 +1,17 @@
#
# KVM configuration
#
-menu "Virtualization"
+menuconfig VIRTUALIZATION
+ bool "Virtualization"
depends on X86
+ default y
+
+if VIRTUALIZATION
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
depends on X86 && EXPERIMENTAL
+ select ANON_INODES
---help---
Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent
@@ -35,4 +40,4 @@ config KVM_AMD
Provides support for KVM on AMD processors equipped with the AMD-V
(SVM) extensions.
-endmenu
+endif # VIRTUALIZATION
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 152312c1fafa..3ac9cbce3369 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -10,6 +10,8 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/signal.h>
@@ -18,6 +20,7 @@
#include <linux/kvm_para.h>
#define CR0_PE_MASK (1ULL << 0)
+#define CR0_MP_MASK (1ULL << 1)
#define CR0_TS_MASK (1ULL << 3)
#define CR0_NE_MASK (1ULL << 5)
#define CR0_WP_MASK (1ULL << 16)
@@ -42,7 +45,8 @@
(CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK \
| CR0_NW_MASK | CR0_CD_MASK)
#define KVM_VM_CR0_ALWAYS_ON \
- (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK)
+ (CR0_PG_MASK | CR0_PE_MASK | CR0_WP_MASK | CR0_NE_MASK | CR0_TS_MASK \
+ | CR0_MP_MASK)
#define KVM_GUEST_CR4_MASK \
(CR4_PSE_MASK | CR4_PAE_MASK | CR4_PGE_MASK | CR4_VMXE_MASK | CR4_VME_MASK)
#define KVM_PMODE_VM_CR4_ALWAYS_ON (CR4_VMXE_MASK | CR4_PAE_MASK)
@@ -51,10 +55,10 @@
#define INVALID_PAGE (~(hpa_t)0)
#define UNMAPPED_GVA (~(gpa_t)0)
-#define KVM_MAX_VCPUS 1
+#define KVM_MAX_VCPUS 4
#define KVM_ALIAS_SLOTS 4
#define KVM_MEMORY_SLOTS 4
-#define KVM_NUM_MMU_PAGES 256
+#define KVM_NUM_MMU_PAGES 1024
#define KVM_MIN_FREE_MMU_PAGES 5
#define KVM_REFILL_PAGES 25
#define KVM_MAX_CPUID_ENTRIES 40
@@ -80,6 +84,11 @@
#define KVM_PIO_PAGE_OFFSET 1
/*
+ * vcpu->requests bit members
+ */
+#define KVM_TLB_FLUSH 0
+
+/*
* Address types:
*
* gva - guest virtual address
@@ -112,7 +121,7 @@ struct kvm_pte_chain {
* bits 4:7 - page table level for this shadow (1-4)
* bits 8:9 - page table quadrant for 2-level guests
* bit 16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- * bits 17:18 - "access" - the user and writable bits of a huge page pde
+ * bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
*/
union kvm_mmu_page_role {
unsigned word;
@@ -122,7 +131,7 @@ union kvm_mmu_page_role {
unsigned quadrant : 2;
unsigned pad_for_nice_hex_output : 6;
unsigned metaphysical : 1;
- unsigned hugepage_access : 2;
+ unsigned hugepage_access : 3;
};
};
@@ -137,7 +146,7 @@ struct kvm_mmu_page {
gfn_t gfn;
union kvm_mmu_page_role role;
- hpa_t page_hpa;
+ u64 *spt;
unsigned long slot_bitmap; /* One bit set per slot which has memory
* in this shadow page.
*/
@@ -232,6 +241,7 @@ struct kvm_pio_request {
struct page *guest_pages[2];
unsigned guest_page_offset;
int in;
+ int port;
int size;
int string;
int down;
@@ -252,8 +262,70 @@ struct kvm_stat {
u32 halt_exits;
u32 request_irq_exits;
u32 irq_exits;
+ u32 light_exits;
+ u32 efer_reload;
+};
+
+struct kvm_io_device {
+ void (*read)(struct kvm_io_device *this,
+ gpa_t addr,
+ int len,
+ void *val);
+ void (*write)(struct kvm_io_device *this,
+ gpa_t addr,
+ int len,
+ const void *val);
+ int (*in_range)(struct kvm_io_device *this, gpa_t addr);
+ void (*destructor)(struct kvm_io_device *this);
+
+ void *private;
+};
+
+static inline void kvm_iodevice_read(struct kvm_io_device *dev,
+ gpa_t addr,
+ int len,
+ void *val)
+{
+ dev->read(dev, addr, len, val);
+}
+
+static inline void kvm_iodevice_write(struct kvm_io_device *dev,
+ gpa_t addr,
+ int len,
+ const void *val)
+{
+ dev->write(dev, addr, len, val);
+}
+
+static inline int kvm_iodevice_inrange(struct kvm_io_device *dev, gpa_t addr)
+{
+ return dev->in_range(dev, addr);
+}
+
+static inline void kvm_iodevice_destructor(struct kvm_io_device *dev)
+{
+ if (dev->destructor)
+ dev->destructor(dev);
+}
+
+/*
+ * It would be nice to use something smarter than a linear search, TBD...
+ * Thankfully we dont expect many devices to register (famous last words :),
+ * so until then it will suffice. At least its abstracted so we can change
+ * in one place.
+ */
+struct kvm_io_bus {
+ int dev_count;
+#define NR_IOBUS_DEVS 6
+ struct kvm_io_device *devs[NR_IOBUS_DEVS];
};
+void kvm_io_bus_init(struct kvm_io_bus *bus);
+void kvm_io_bus_destroy(struct kvm_io_bus *bus);
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr);
+void kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+ struct kvm_io_device *dev);
+
struct kvm_vcpu {
struct kvm *kvm;
union {
@@ -266,6 +338,8 @@ struct kvm_vcpu {
u64 host_tsc;
struct kvm_run *run;
int interrupt_window_open;
+ int guest_mode;
+ unsigned long requests;
unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */
#define NR_IRQ_WORDS KVM_IRQ_BITMAP_SIZE(unsigned long)
unsigned long irq_pending[NR_IRQ_WORDS];
@@ -285,15 +359,20 @@ struct kvm_vcpu {
u64 apic_base;
u64 ia32_misc_enable_msr;
int nmsrs;
+ int save_nmsrs;
+ int msr_offset_efer;
+#ifdef CONFIG_X86_64
+ int msr_offset_kernel_gs_base;
+#endif
struct vmx_msr_entry *guest_msrs;
struct vmx_msr_entry *host_msrs;
- struct list_head free_pages;
- struct kvm_mmu_page page_header_buf[KVM_NUM_MMU_PAGES];
struct kvm_mmu mmu;
struct kvm_mmu_memory_cache mmu_pte_chain_cache;
struct kvm_mmu_memory_cache mmu_rmap_desc_cache;
+ struct kvm_mmu_memory_cache mmu_page_cache;
+ struct kvm_mmu_memory_cache mmu_page_header_cache;
gfn_t last_pt_write_gfn;
int last_pt_write_count;
@@ -305,6 +384,11 @@ struct kvm_vcpu {
char *guest_fx_image;
int fpu_active;
int guest_fpu_loaded;
+ struct vmx_host_state {
+ int loaded;
+ u16 fs_sel, gs_sel, ldt_sel;
+ int fs_gs_ldt_reload_needed;
+ } vmx_host_state;
int mmio_needed;
int mmio_read_completed;
@@ -331,6 +415,7 @@ struct kvm_vcpu {
u32 ar;
} tr, es, ds, fs, gs;
} rmode;
+ int halt_request; /* real mode on Intel only */
int cpuid_nent;
struct kvm_cpuid_entry cpuid_entries[KVM_MAX_CPUID_ENTRIES];
@@ -362,12 +447,15 @@ struct kvm {
struct list_head active_mmu_pages;
int n_free_mmu_pages;
struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES];
+ int nvcpus;
struct kvm_vcpu vcpus[KVM_MAX_VCPUS];
int memory_config_version;
int busy;
unsigned long rmap_overflow;
struct list_head vm_list;
struct file *filp;
+ struct kvm_io_bus mmio_bus;
+ struct kvm_io_bus pio_bus;
};
struct descriptor_table {
@@ -447,8 +535,8 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu);
int kvm_mmu_setup(struct kvm_vcpu *vcpu);
int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
@@ -481,6 +569,8 @@ void realmode_lmsw(struct kvm_vcpu *vcpu, unsigned long msw,
unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
unsigned long *rflags);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
struct x86_emulate_ctxt;
@@ -488,6 +578,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int size, unsigned long count, int string, int down,
gva_t address, int rep, unsigned port);
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
+int kvm_emulate_halt(struct kvm_vcpu *vcpu);
int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
int emulate_clts(struct kvm_vcpu *vcpu);
int emulator_get_dr(struct x86_emulate_ctxt* ctxt, int dr,
@@ -511,6 +602,7 @@ void save_msrs(struct vmx_msr_entry *e, int n);
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);
int kvm_read_guest(struct kvm_vcpu *vcpu,
gva_t addr,
@@ -524,10 +616,12 @@ int kvm_write_guest(struct kvm_vcpu *vcpu,
unsigned long segment_base(u16 selector);
-void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
-void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes);
+void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
+ const u8 *old, const u8 *new, int bytes);
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+int kvm_mmu_load(struct kvm_vcpu *vcpu);
+void kvm_mmu_unload(struct kvm_vcpu *vcpu);
int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run);
@@ -539,6 +633,14 @@ static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
return vcpu->mmu.page_fault(vcpu, gva, error_code);
}
+static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
+{
+ if (likely(vcpu->mmu.root_hpa != INVALID_PAGE))
+ return 0;
+
+ return kvm_mmu_load(vcpu);
+}
+
static inline int is_long_mode(struct kvm_vcpu *vcpu)
{
#ifdef CONFIG_X86_64
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 8f1f07adb04e..bcbe6835beb4 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -16,34 +16,33 @@
*/
#include "kvm.h"
+#include "x86_emulate.h"
+#include "segment_descriptor.h"
#include <linux/kvm.h>
#include <linux/module.h>
#include <linux/errno.h>
-#include <linux/magic.h>
-#include <asm/processor.h>
#include <linux/percpu.h>
#include <linux/gfp.h>
-#include <asm/msr.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/vmalloc.h>
-#include <asm/uaccess.h>
#include <linux/reboot.h>
-#include <asm/io.h>
#include <linux/debugfs.h>
#include <linux/highmem.h>
#include <linux/file.h>
-#include <asm/desc.h>
#include <linux/sysdev.h>
#include <linux/cpu.h>
-#include <linux/file.h>
-#include <linux/fs.h>
-#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/smp.h>
+#include <linux/anon_inodes.h>
-#include "x86_emulate.h"
-#include "segment_descriptor.h"
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/desc.h>
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
@@ -51,8 +50,12 @@ MODULE_LICENSE("GPL");
static DEFINE_SPINLOCK(kvm_lock);
static LIST_HEAD(vm_list);
+static cpumask_t cpus_hardware_enabled;
+
struct kvm_arch_ops *kvm_arch_ops;
+static void hardware_disable(void *ignored);
+
#define STAT_OFFSET(x) offsetof(struct kvm_vcpu, stat.x)
static struct kvm_stats_debugfs_item {
@@ -72,13 +75,13 @@ static struct kvm_stats_debugfs_item {
{ "halt_exits", STAT_OFFSET(halt_exits) },
{ "request_irq", STAT_OFFSET(request_irq_exits) },
{ "irq_exits", STAT_OFFSET(irq_exits) },
+ { "light_exits", STAT_OFFSET(light_exits) },
+ { "efer_reload", STAT_OFFSET(efer_reload) },
{ NULL }
};
static struct dentry *debugfs_dir;
-struct vfsmount *kvmfs_mnt;
-
#define MAX_IO_MSRS 256
#define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL
@@ -100,55 +103,6 @@ struct segment_descriptor_64 {
static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
unsigned long arg);
-static struct inode *kvmfs_inode(struct file_operations *fops)
-{
- int error = -ENOMEM;
- struct inode *inode = new_inode(kvmfs_mnt->mnt_sb);
-
- if (!inode)
- goto eexit_1;
-
- inode->i_fop = fops;
-
- /*
- * Mark the inode dirty from the very beginning,
- * that way it will never be moved to the dirty
- * list because mark_inode_dirty() will think
- * that it already _is_ on the dirty list.
- */
- inode->i_state = I_DIRTY;
- inode->i_mode = S_IRUSR | S_IWUSR;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- return inode;
-
-eexit_1:
- return ERR_PTR(error);
-}
-
-static struct file *kvmfs_file(struct inode *inode, void *private_data)
-{
- struct file *file = get_empty_filp();
-
- if (!file)
- return ERR_PTR(-ENFILE);
-
- file->f_path.mnt = mntget(kvmfs_mnt);
- file->f_path.dentry = d_alloc_anon(inode);
- if (!file->f_path.dentry)
- return ERR_PTR(-ENOMEM);
- file->f_mapping = inode->i_mapping;
-
- file->f_pos = 0;
- file->f_flags = O_RDWR;
- file->f_op = inode->i_fop;
- file->f_mode = FMODE_READ | FMODE_WRITE;
- file->f_version = 0;
- file->private_data = private_data;
- return file;
-}
-
unsigned long segment_base(u16 selector)
{
struct descriptor_table gdt;
@@ -284,27 +238,52 @@ static void vcpu_load(struct kvm_vcpu *vcpu)
kvm_arch_ops->vcpu_load(vcpu);
}
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
+static void vcpu_put(struct kvm_vcpu *vcpu)
+{
+ kvm_arch_ops->vcpu_put(vcpu);
+ mutex_unlock(&vcpu->mutex);
+}
+
+static void ack_flush(void *_completed)
{
- struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
+ atomic_t *completed = _completed;
- mutex_lock(&vcpu->mutex);
- if (!vcpu->vmcs) {
- mutex_unlock(&vcpu->mutex);
- return NULL;
- }
- kvm_arch_ops->vcpu_load(vcpu);
- return vcpu;
+ atomic_inc(completed);
}
-static void vcpu_put(struct kvm_vcpu *vcpu)
+void kvm_flush_remote_tlbs(struct kvm *kvm)
{
- kvm_arch_ops->vcpu_put(vcpu);
- mutex_unlock(&vcpu->mutex);
+ int i, cpu, needed;
+ cpumask_t cpus;
+ struct kvm_vcpu *vcpu;
+ atomic_t completed;
+
+ atomic_set(&completed, 0);
+ cpus_clear(cpus);
+ needed = 0;
+ for (i = 0; i < kvm->nvcpus; ++i) {
+ vcpu = &kvm->vcpus[i];
+ if (test_and_set_bit(KVM_TLB_FLUSH, &vcpu->requests))
+ continue;
+ cpu = vcpu->cpu;
+ if (cpu != -1 && cpu != raw_smp_processor_id())
+ if (!cpu_isset(cpu, cpus)) {
+ cpu_set(cpu, cpus);
+ ++needed;
+ }
+ }
+
+ /*
+ * We really want smp_call_function_mask() here. But that's not
+ * available, so ipi all cpus in parallel and wait for them
+ * to complete.
+ */
+ for (cpu = first_cpu(cpus); cpu != NR_CPUS; cpu = next_cpu(cpu, cpus))
+ smp_call_function_single(cpu, ack_flush, &completed, 1, 0);
+ while (atomic_read(&completed) != needed) {
+ cpu_relax();
+ barrier();
+ }
}
static struct kvm *kvm_create_vm(void)
@@ -315,8 +294,13 @@ static struct kvm *kvm_create_vm(void)
if (!kvm)
return ERR_PTR(-ENOMEM);
+ kvm_io_bus_init(&kvm->pio_bus);
spin_lock_init(&kvm->lock);
INIT_LIST_HEAD(&kvm->active_mmu_pages);
+ spin_lock(&kvm_lock);
+ list_add(&kvm->vm_list, &vm_list);
+ spin_unlock(&kvm_lock);
+ kvm_io_bus_init(&kvm->mmio_bus);
for (i = 0; i < KVM_MAX_VCPUS; ++i) {
struct kvm_vcpu *vcpu = &kvm->vcpus[i];
@@ -324,10 +308,6 @@ static struct kvm *kvm_create_vm(void)
vcpu->cpu = -1;
vcpu->kvm = kvm;
vcpu->mmu.root_hpa = INVALID_PAGE;
- INIT_LIST_HEAD(&vcpu->free_pages);
- spin_lock(&kvm_lock);
- list_add(&kvm->vm_list, &vm_list);
- spin_unlock(&kvm_lock);
}
return kvm;
}
@@ -380,6 +360,16 @@ static void free_pio_guest_pages(struct kvm_vcpu *vcpu)
}
}
+static void kvm_unload_vcpu_mmu(struct kvm_vcpu *vcpu)
+{
+ if (!vcpu->vmcs)
+ return;
+
+ vcpu_load(vcpu);
+ kvm_mmu_unload(vcpu);
+ vcpu_put(vcpu);
+}
+
static void kvm_free_vcpu(struct kvm_vcpu *vcpu)
{
if (!vcpu->vmcs)
@@ -400,6 +390,11 @@ static void kvm_free_vcpus(struct kvm *kvm)
{
unsigned int i;
+ /*
+ * Unpin any mmu pages first.
+ */
+ for (i = 0; i < KVM_MAX_VCPUS; ++i)
+ kvm_unload_vcpu_mmu(&kvm->vcpus[i]);
for (i = 0; i < KVM_MAX_VCPUS; ++i)
kvm_free_vcpu(&kvm->vcpus[i]);
}
@@ -414,6 +409,8 @@ static void kvm_destroy_vm(struct kvm *kvm)
spin_lock(&kvm_lock);
list_del(&kvm->vm_list);
spin_unlock(&kvm_lock);
+ kvm_io_bus_destroy(&kvm->pio_bus);
+ kvm_io_bus_destroy(&kvm->mmio_bus);
kvm_free_vcpus(kvm);
kvm_free_physmem(kvm);
kfree(kvm);
@@ -649,13 +646,6 @@ void fx_init(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(fx_init);
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
- spin_lock(&vcpu->kvm->lock);
- kvm_mmu_slot_remove_write_access(vcpu, slot);
- spin_unlock(&vcpu->kvm->lock);
-}
-
/*
* Allocate some memory and give it an address in the guest physical address
* space.
@@ -778,19 +768,10 @@ raced:
*memslot = new;
++kvm->memory_config_version;
- spin_unlock(&kvm->lock);
-
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu;
+ kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+ kvm_flush_remote_tlbs(kvm);
- vcpu = vcpu_load_slot(kvm, i);
- if (!vcpu)
- continue;
- if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
- do_remove_write_access(vcpu, mem->slot);
- kvm_mmu_reset_context(vcpu);
- vcpu_put(vcpu);
- }
+ spin_unlock(&kvm->lock);
kvm_free_physmem_slot(&old, &new);
return 0;
@@ -812,7 +793,6 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
struct kvm_memory_slot *memslot;
int r, i;
int n;
- int cleared;
unsigned long any = 0;
spin_lock(&kvm->lock);
@@ -841,23 +821,11 @@ static int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
goto out;
- if (any) {
- cleared = 0;
- for (i = 0; i < KVM_MAX_VCPUS; ++i) {
- struct kvm_vcpu *vcpu;
-
- vcpu = vcpu_load_slot(kvm, i);
- if (!vcpu)
- continue;
- if (!cleared) {
- do_remove_write_access(vcpu, log->slot);
- memset(memslot->dirty_bitmap, 0, n);
- cleared = 1;
- }
- kvm_arch_ops->tlb_flush(vcpu);
- vcpu_put(vcpu);
- }
- }
+ spin_lock(&kvm->lock);
+ kvm_mmu_slot_remove_write_access(kvm, log->slot);
+ kvm_flush_remote_tlbs(kvm);
+ memset(memslot->dirty_bitmap, 0, n);
+ spin_unlock(&kvm->lock);
r = 0;
@@ -906,13 +874,9 @@ static int kvm_vm_ioctl_set_memory_alias(struct kvm *kvm,
break;
kvm->naliases = n;
- spin_unlock(&kvm->lock);
+ kvm_mmu_zap_all(kvm);
- vcpu_load(&kvm->vcpus[0]);
- spin_lock(&kvm->lock);
- kvm_mmu_zap_all(&kvm->vcpus[0]);
spin_unlock(&kvm->lock);
- vcpu_put(&kvm->vcpus[0]);
return 0;
@@ -969,7 +933,7 @@ EXPORT_SYMBOL_GPL(gfn_to_page);
void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
{
int i;
- struct kvm_memory_slot *memslot = NULL;
+ struct kvm_memory_slot *memslot;
unsigned long rel_gfn;
for (i = 0; i < kvm->nmemslots; ++i) {
@@ -978,7 +942,7 @@ void mark_page_dirty(struct kvm *kvm, gfn_t gfn)
if (gfn >= memslot->base_gfn
&& gfn < memslot->base_gfn + memslot->npages) {
- if (!memslot || !memslot->dirty_bitmap)
+ if (!memslot->dirty_bitmap)
return;
rel_gfn = gfn - memslot->base_gfn;
@@ -1037,12 +1001,31 @@ static int emulator_write_std(unsigned long addr,
return X86EMUL_UNHANDLEABLE;
}
+static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu,
+ gpa_t addr)
+{
+ /*
+ * Note that its important to have this wrapper function because
+ * in the very near future we will be checking for MMIOs against
+ * the LAPIC as well as the general MMIO bus
+ */
+ return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr);
+}
+
+static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu,
+ gpa_t addr)
+{
+ return kvm_io_bus_find_dev(&vcpu->kvm->pio_bus, addr);
+}
+
static int emulator_read_emulated(unsigned long addr,
void *val,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
+ struct kvm_vcpu *vcpu = ctxt->vcpu;
+ struct kvm_io_device *mmio_dev;
+ gpa_t gpa;
if (vcpu->mmio_read_completed) {
memcpy(val, vcpu->mmio_data, bytes);
@@ -1051,18 +1034,26 @@ static int emulator_read_emulated(unsigned long addr,
} else if (emulator_read_std(addr, val, bytes, ctxt)
== X86EMUL_CONTINUE)
return X86EMUL_CONTINUE;
- else {
- gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
- if (gpa == UNMAPPED_GVA)
- return X86EMUL_PROPAGATE_FAULT;
- vcpu->mmio_needed = 1;
- vcpu->mmio_phys_addr = gpa;
- vcpu->mmio_size = bytes;
- vcpu->mmio_is_write = 0;
+ gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+ if (gpa == UNMAPPED_GVA)
+ return X86EMUL_PROPAGATE_FAULT;
- return X86EMUL_UNHANDLEABLE;
+ /*
+ * Is this MMIO handled locally?
+ */
+ mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
+ if (mmio_dev) {
+ kvm_iodevice_read(mmio_dev, gpa, bytes, val);
+ return X86EMUL_CONTINUE;
}
+
+ vcpu->mmio_needed = 1;
+ vcpu->mmio_phys_addr = gpa;
+ vcpu->mmio_size = bytes;
+ vcpu->mmio_is_write = 0;
+
+ return X86EMUL_UNHANDLEABLE;
}
static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
@@ -1070,18 +1061,20 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa,
{
struct page *page;
void *virt;
+ unsigned offset = offset_in_page(gpa);
if (((gpa + bytes - 1) >> PAGE_SHIFT) != (gpa >> PAGE_SHIFT))
return 0;
page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
if (!page)
return 0;
- kvm_mmu_pre_write(vcpu, gpa, bytes);
mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
virt = kmap_atomic(page, KM_USER0);
- memcpy(virt + offset_in_page(gpa), val, bytes);
+ if (memcmp(virt + offset_in_page(gpa), val, bytes)) {
+ kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
+ memcpy(virt + offset_in_page(gpa), val, bytes);
+ }
kunmap_atomic(virt, KM_USER0);
- kvm_mmu_post_write(vcpu, gpa, bytes);
return 1;
}
@@ -1090,8 +1083,9 @@ static int emulator_write_emulated(unsigned long addr,
unsigned int bytes,
struct x86_emulate_ctxt *ctxt)
{
- struct kvm_vcpu *vcpu = ctxt->vcpu;
- gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
+ struct kvm_vcpu *vcpu = ctxt->vcpu;
+ struct kvm_io_device *mmio_dev;
+ gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, addr);
if (gpa == UNMAPPED_GVA) {
kvm_arch_ops->inject_page_fault(vcpu, addr, 2);
@@ -1101,6 +1095,15 @@ static int emulator_write_emulated(unsigned long addr,
if (emulator_write_phys(vcpu, gpa, val, bytes))
return X86EMUL_CONTINUE;
+ /*
+ * Is this MMIO handled locally?
+ */
+ mmio_dev = vcpu_find_mmio_dev(vcpu, gpa);
+ if (mmio_dev) {
+ kvm_iodevice_write(mmio_dev, gpa, bytes, val);
+ return X86EMUL_CONTINUE;
+ }
+
vcpu->mmio_needed = 1;
vcpu->mmio_phys_addr = gpa;
vcpu->mmio_size = bytes;
@@ -1269,6 +1272,17 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
}
EXPORT_SYMBOL_GPL(emulate_instruction);
+int kvm_emulate_halt(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->irq_summary)
+ return 1;
+
+ vcpu->run->exit_reason = KVM_EXIT_HLT;
+ ++vcpu->stat.halt_exits;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(kvm_emulate_halt);
+
int kvm_hypercall(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
unsigned long nr, a0, a1, a2, a3, a4, a5, ret;
@@ -1469,6 +1483,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
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:
case 0x200 ... 0x2ff:
@@ -1502,7 +1517,7 @@ EXPORT_SYMBOL_GPL(kvm_get_msr_common);
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
{
return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
}
@@ -1580,7 +1595,7 @@ EXPORT_SYMBOL_GPL(kvm_set_msr_common);
* Returns 0 on success, non-0 otherwise.
* Assumes vcpu_load() was already called.
*/
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
return kvm_arch_ops->set_msr(vcpu, msr_index, data);
}
@@ -1727,6 +1742,20 @@ static int complete_pio(struct kvm_vcpu *vcpu)
return 0;
}
+void kernel_pio(struct kvm_io_device *pio_dev, struct kvm_vcpu *vcpu)
+{
+ /* TODO: String I/O for in kernel device */
+
+ if (vcpu->pio.in)
+ kvm_iodevice_read(pio_dev, vcpu->pio.port,
+ vcpu->pio.size,
+ vcpu->pio_data);
+ else
+ kvm_iodevice_write(pio_dev, vcpu->pio.port,
+ vcpu->pio.size,
+ vcpu->pio_data);
+}
+
int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int size, unsigned long count, int string, int down,
gva_t address, int rep, unsigned port)
@@ -1735,6 +1764,7 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
int i;
int nr_pages = 1;
struct page *page;
+ struct kvm_io_device *pio_dev;
vcpu->run->exit_reason = KVM_EXIT_IO;
vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT;
@@ -1746,17 +1776,27 @@ int kvm_setup_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in,
vcpu->pio.cur_count = count;
vcpu->pio.size = size;
vcpu->pio.in = in;
+ vcpu->pio.port = port;
vcpu->pio.string = string;
vcpu->pio.down = down;
vcpu->pio.guest_page_offset = offset_in_page(address);
vcpu->pio.rep = rep;
+ pio_dev = vcpu_find_pio_dev(vcpu, port);
if (!string) {
kvm_arch_ops->cache_regs(vcpu);
memcpy(vcpu->pio_data, &vcpu->regs[VCPU_REGS_RAX], 4);
kvm_arch_ops->decache_regs(vcpu);
+ if (pio_dev) {
+ kernel_pio(pio_dev, vcpu);
+ complete_pio(vcpu);
+ return 1;
+ }
return 0;
}
+ /* TODO: String I/O for in kernel device */
+ if (pio_dev)
+ printk(KERN_ERR "kvm_setup_pio: no string io support\n");
if (!count) {
kvm_arch_ops->skip_emulated_instruction(vcpu);
@@ -2093,7 +2133,7 @@ static __init void kvm_init_msr_list(void)
*/
static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
{
- return set_msr(vcpu, index, *data);
+ return kvm_set_msr(vcpu, index, *data);
}
/*
@@ -2273,34 +2313,12 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu)
struct inode *inode;
struct file *file;
+ r = anon_inode_getfd(&fd, &inode, &file,
+ "kvm-vcpu", &kvm_vcpu_fops, vcpu);
+ if (r)
+ return r;
atomic_inc(&vcpu->kvm->filp->f_count);
- inode = kvmfs_inode(&kvm_vcpu_fops);
- if (IS_ERR(inode)) {
- r = PTR_ERR(inode);
- goto out1;
- }
-
- file = kvmfs_file(inode, vcpu);
- if (IS_ERR(file)) {
- r = PTR_ERR(file);
- goto out2;
- }
-
- r = get_unused_fd();
- if (r < 0)
- goto out3;
- fd = r;
- fd_install(fd, file);
-
return fd;
-
-out3:
- fput(file);
-out2:
- iput(inode);
-out1:
- fput(vcpu->kvm->filp);
- return r;
}
/*
@@ -2363,6 +2381,11 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, int n)
if (r < 0)
goto out_free_vcpus;
+ spin_lock(&kvm_lock);
+ if (n >= kvm->nvcpus)
+ kvm->nvcpus = n + 1;
+ spin_unlock(&kvm_lock);
+
return r;
out_free_vcpus:
@@ -2376,6 +2399,27 @@ out:
return r;
}
+static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu)
+{
+ u64 efer;
+ int i;
+ struct kvm_cpuid_entry *e, *entry;
+
+ rdmsrl(MSR_EFER, efer);
+ entry = NULL;
+ for (i = 0; i < vcpu->cpuid_nent; ++i) {
+ e = &vcpu->cpuid_entries[i];
+ if (e->function == 0x80000001) {
+ entry = e;
+ break;
+ }
+ }
+ if (entry && (entry->edx & EFER_NX) && !(efer & EFER_NX)) {
+ entry->edx &= ~(1 << 20);
+ printk(KERN_INFO ": guest NX capability removed\n");
+ }
+}
+
static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
struct kvm_cpuid *cpuid,
struct kvm_cpuid_entry __user *entries)
@@ -2390,6 +2434,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
cpuid->nent * sizeof(struct kvm_cpuid_entry)))
goto out;
vcpu->cpuid_nent = cpuid->nent;
+ cpuid_fix_nx_cap(vcpu);
return 0;
out:
@@ -2572,7 +2617,7 @@ static long kvm_vcpu_ioctl(struct file *filp,
break;
}
case KVM_GET_MSRS:
- r = msr_io(vcpu, argp, get_msr, 1);
+ r = msr_io(vcpu, argp, kvm_get_msr, 1);
break;
case KVM_SET_MSRS:
r = msr_io(vcpu, argp, do_set_msr, 0);
@@ -2738,41 +2783,18 @@ static int kvm_dev_ioctl_create_vm(void)
struct file *file;
struct kvm *kvm;
- inode = kvmfs_inode(&kvm_vm_fops);
- if (IS_ERR(inode)) {
- r = PTR_ERR(inode);
- goto out1;
- }
-
kvm = kvm_create_vm();
- if (IS_ERR(kvm)) {
- r = PTR_ERR(kvm);
- goto out2;
+ if (IS_ERR(kvm))
+ return PTR_ERR(kvm);
+ r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
+ if (r) {
+ kvm_destroy_vm(kvm);
+ return r;
}
- file = kvmfs_file(inode, kvm);
- if (IS_ERR(file)) {
- r = PTR_ERR(file);
- goto out3;
- }
kvm->filp = file;
- r = get_unused_fd();
- if (r < 0)
- goto out4;
- fd = r;
- fd_install(fd, file);
-
return fd;
-
-out4:
- fput(file);
-out3:
- kvm_destroy_vm(kvm);
-out2:
- iput(inode);
-out1:
- return r;
}
static long kvm_dev_ioctl(struct file *filp,
@@ -2862,7 +2884,7 @@ static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
* in vmx root mode.
*/
printk(KERN_INFO "kvm: exiting hardware virtualization\n");
- on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+ on_each_cpu(hardware_disable, NULL, 0, 1);
}
return NOTIFY_OK;
}
@@ -2905,33 +2927,88 @@ static void decache_vcpus_on_cpu(int cpu)
spin_unlock(&kvm_lock);
}
+static void hardware_enable(void *junk)
+{
+ int cpu = raw_smp_processor_id();
+
+ if (cpu_isset(cpu, cpus_hardware_enabled))
+ return;
+ cpu_set(cpu, cpus_hardware_enabled);
+ kvm_arch_ops->hardware_enable(NULL);
+}
+
+static void hardware_disable(void *junk)
+{
+ int cpu = raw_smp_processor_id();
+
+ if (!cpu_isset(cpu, cpus_hardware_enabled))
+ return;
+ cpu_clear(cpu, cpus_hardware_enabled);
+ decache_vcpus_on_cpu(cpu);
+ kvm_arch_ops->hardware_disable(NULL);
+}
+
static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
void *v)
{
int cpu = (long)v;
switch (val) {
- case CPU_DOWN_PREPARE:
- case CPU_DOWN_PREPARE_FROZEN:
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
cpu);
- decache_vcpus_on_cpu(cpu);
- smp_call_function_single(cpu, kvm_arch_ops->hardware_disable,
- NULL, 0, 1);
+ smp_call_function_single(cpu, hardware_disable, NULL, 0, 1);
break;
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
printk(KERN_INFO "kvm: enabling virtualization on CPU%d\n",
cpu);
- smp_call_function_single(cpu, kvm_arch_ops->hardware_enable,
- NULL, 0, 1);
+ smp_call_function_single(cpu, hardware_enable, NULL, 0, 1);
break;
}
return NOTIFY_OK;
}
+void kvm_io_bus_init(struct kvm_io_bus *bus)
+{
+ memset(bus, 0, sizeof(*bus));
+}
+
+void kvm_io_bus_destroy(struct kvm_io_bus *bus)
+{
+ int i;
+
+ for (i = 0; i < bus->dev_count; i++) {
+ struct kvm_io_device *pos = bus->devs[i];
+
+ kvm_iodevice_destructor(pos);
+ }
+}
+
+struct kvm_io_device *kvm_io_bus_find_dev(struct kvm_io_bus *bus, gpa_t addr)
+{
+ int i;
+
+ for (i = 0; i < bus->dev_count; i++) {
+ struct kvm_io_device *pos = bus->devs[i];
+
+ if (pos->in_range(pos, addr))
+ return pos;
+ }
+
+ return NULL;
+}
+
+void kvm_io_bus_register_dev(struct kvm_io_bus *bus, struct kvm_io_device *dev)
+{
+ BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
+
+ bus->devs[bus->dev_count++] = dev;
+}
+
static struct notifier_block kvm_cpu_notifier = {
.notifier_call = kvm_cpu_hotplug,
.priority = 20, /* must be > scheduler priority */
@@ -2983,14 +3060,13 @@ static void kvm_exit_debug(void)
static int kvm_suspend(struct sys_device *dev, pm_message_t state)
{
- decache_vcpus_on_cpu(raw_smp_processor_id());
- on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+ hardware_disable(NULL);
return 0;
}
static int kvm_resume(struct sys_device *dev)
{
- on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
+ hardware_enable(NULL);
return 0;
}
@@ -3007,18 +3083,6 @@ static struct sys_device kvm_sysdev = {
hpa_t bad_page_address;
-static int kvmfs_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data, struct vfsmount *mnt)
-{
- return get_sb_pseudo(fs_type, "kvm:", NULL, KVMFS_SUPER_MAGIC, mnt);
-}
-
-static struct file_system_type kvm_fs_type = {
- .name = "kvmfs",
- .get_sb = kvmfs_get_sb,
- .kill_sb = kill_anon_super,
-};
-
int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
{
int r;
@@ -3043,7 +3107,7 @@ int kvm_init_arch(struct kvm_arch_ops *ops, struct module *module)
if (r < 0)
goto out;
- on_each_cpu(kvm_arch_ops->hardware_enable, NULL, 0, 1);
+ on_each_cpu(hardware_enable, NULL, 0, 1);
r = register_cpu_notifier(&kvm_cpu_notifier);
if (r)
goto out_free_1;
@@ -3075,7 +3139,7 @@ out_free_2:
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
out_free_1:
- on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+ on_each_cpu(hardware_disable, NULL, 0, 1);
kvm_arch_ops->hardware_unsetup();
out:
kvm_arch_ops = NULL;
@@ -3089,7 +3153,7 @@ void kvm_exit_arch(void)
sysdev_class_unregister(&kvm_sysdev_class);
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
- on_each_cpu(kvm_arch_ops->hardware_disable, NULL, 0, 1);
+ on_each_cpu(hardware_disable, NULL, 0, 1);
kvm_arch_ops->hardware_unsetup();
kvm_arch_ops = NULL;
}
@@ -3103,14 +3167,6 @@ static __init int kvm_init(void)
if (r)
goto out4;
- r = register_filesystem(&kvm_fs_type);
- if (r)
- goto out3;
-
- kvmfs_mnt = kern_mount(&kvm_fs_type);
- r = PTR_ERR(kvmfs_mnt);
- if (IS_ERR(kvmfs_mnt))
- goto out2;
kvm_init_debug();
kvm_init_msr_list();
@@ -3127,10 +3183,6 @@ static __init int kvm_init(void)
out:
kvm_exit_debug();
- mntput(kvmfs_mnt);
-out2:
- unregister_filesystem(&kvm_fs_type);
-out3:
kvm_mmu_module_exit();
out4:
return r;
@@ -3140,8 +3192,6 @@ static __exit void kvm_exit(void)
{
kvm_exit_debug();
__free_page(pfn_to_page(bad_page_address >> PAGE_SHIFT));
- mntput(kvmfs_mnt);
- unregister_filesystem(&kvm_fs_type);
kvm_mmu_module_exit();
}
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index e8e228118de9..1a87ba9d5156 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -16,15 +16,18 @@
* the COPYING file in the top-level directory.
*
*/
+
+#include "vmx.h"
+#include "kvm.h"
+
#include <linux/types.h>
#include <linux/string.h>
-#include <asm/page.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/module.h>
-#include "vmx.h"
-#include "kvm.h"
+#include <asm/page.h>
+#include <asm/cmpxchg.h>
#undef MMU_DEBUG
@@ -90,25 +93,11 @@ static int dbg = 1;
#define PT32_DIR_PSE36_MASK (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT)
-#define PT32_PTE_COPY_MASK \
- (PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK | PT_GLOBAL_MASK)
-
-#define PT64_PTE_COPY_MASK (PT64_NX_MASK | PT32_PTE_COPY_MASK)
-
#define PT_FIRST_AVAIL_BITS_SHIFT 9
#define PT64_SECOND_AVAIL_BITS_SHIFT 52
-#define PT_SHADOW_PS_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
#define PT_SHADOW_IO_MARK (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
-#define PT_SHADOW_WRITABLE_SHIFT (PT_FIRST_AVAIL_BITS_SHIFT + 1)
-#define PT_SHADOW_WRITABLE_MASK (1ULL << PT_SHADOW_WRITABLE_SHIFT)
-
-#define PT_SHADOW_USER_SHIFT (PT_SHADOW_WRITABLE_SHIFT + 1)
-#define PT_SHADOW_USER_MASK (1ULL << (PT_SHADOW_USER_SHIFT))
-
-#define PT_SHADOW_BITS_OFFSET (PT_SHADOW_WRITABLE_SHIFT - PT_WRITABLE_SHIFT)
-
#define VALID_PAGE(x) ((x) != INVALID_PAGE)
#define PT64_LEVEL_BITS 9
@@ -165,6 +154,7 @@ struct kvm_rmap_desc {
static struct kmem_cache *pte_chain_cache;
static struct kmem_cache *rmap_desc_cache;
+static struct kmem_cache *mmu_page_header_cache;
static int is_write_protection(struct kvm_vcpu *vcpu)
{
@@ -202,6 +192,15 @@ static int is_rmap_pte(u64 pte)
== (PT_WRITABLE_MASK | PT_PRESENT_MASK);
}
+static void set_shadow_pte(u64 *sptep, u64 spte)
+{
+#ifdef CONFIG_X86_64
+ set_64bit((unsigned long *)sptep, spte);
+#else
+ set_64bit((unsigned long long *)sptep, spte);
+#endif
+}
+
static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
struct kmem_cache *base_cache, int min,
gfp_t gfp_flags)
@@ -225,6 +224,29 @@ static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
kfree(mc->objects[--mc->nobjs]);
}
+static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
+ int min, gfp_t gfp_flags)
+{
+ struct page *page;
+
+ if (cache->nobjs >= min)
+ return 0;
+ while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+ page = alloc_page(gfp_flags);
+ if (!page)
+ return -ENOMEM;
+ set_page_private(page, 0);
+ cache->objects[cache->nobjs++] = page_address(page);
+ }
+ return 0;
+}
+
+static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
+{
+ while (mc->nobjs)
+ free_page((unsigned long)mc->objects[--mc->nobjs]);
+}
+
static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
{
int r;
@@ -235,6 +257,13 @@ static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
goto out;
r = mmu_topup_memory_cache(&vcpu->mmu_rmap_desc_cache,
rmap_desc_cache, 1, gfp_flags);
+ if (r)
+ goto out;
+ r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
+ if (r)
+ goto out;
+ r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
+ mmu_page_header_cache, 4, gfp_flags);
out:
return r;
}
@@ -258,6 +287,8 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu)
{
mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
+ mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
+ mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
}
static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
@@ -271,24 +302,15 @@ static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc,
return p;
}
-static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
-{
- if (mc->nobjs < KVM_NR_MEM_OBJS)
- mc->objects[mc->nobjs++] = obj;
- else
- kfree(obj);
-}
-
static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
{
return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
sizeof(struct kvm_pte_chain));
}
-static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
- struct kvm_pte_chain *pc)
+static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
{
- mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+ kfree(pc);
}
static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -297,10 +319,9 @@ static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
sizeof(struct kvm_rmap_desc));
}
-static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
- struct kvm_rmap_desc *rd)
+static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
{
- mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+ kfree(rd);
}
/*
@@ -345,8 +366,7 @@ static void rmap_add(struct kvm_vcpu *vcpu, u64 *spte)
}
}
-static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
- struct page *page,
+static void rmap_desc_remove_entry(struct page *page,
struct kvm_rmap_desc *desc,
int i,
struct kvm_rmap_desc *prev_desc)
@@ -366,10 +386,10 @@ static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
prev_desc->more = desc->more;
else
set_page_private(page,(unsigned long)desc->more | 1);
- mmu_free_rmap_desc(vcpu, desc);
+ mmu_free_rmap_desc(desc);
}
-static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+static void rmap_remove(u64 *spte)
{
struct page *page;
struct kvm_rmap_desc *desc;
@@ -397,7 +417,7 @@ static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
while (desc) {
for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
if (desc->shadow_ptes[i] == spte) {
- rmap_desc_remove_entry(vcpu, page,
+ rmap_desc_remove_entry(page,
desc, i,
prev_desc);
return;
@@ -432,20 +452,19 @@ static void rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
BUG_ON(!(*spte & PT_PRESENT_MASK));
BUG_ON(!(*spte & PT_WRITABLE_MASK));
rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
- rmap_remove(vcpu, spte);
- kvm_arch_ops->tlb_flush(vcpu);
- *spte &= ~(u64)PT_WRITABLE_MASK;
+ rmap_remove(spte);
+ set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
+ kvm_flush_remote_tlbs(vcpu->kvm);
}
}
#ifdef MMU_DEBUG
-static int is_empty_shadow_page(hpa_t page_hpa)
+static int is_empty_shadow_page(u64 *spt)
{
u64 *pos;
u64 *end;
- for (pos = __va(page_hpa), end = pos + PAGE_SIZE / sizeof(u64);
- pos != end; pos++)
+ for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++)
if (*pos != 0) {
printk(KERN_ERR "%s: %p %llx\n", __FUNCTION__,
pos, *pos);
@@ -455,14 +474,14 @@ static int is_empty_shadow_page(hpa_t page_hpa)
}
#endif
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu, hpa_t page_hpa)
+static void kvm_mmu_free_page(struct kvm *kvm,
+ struct kvm_mmu_page *page_head)
{
- struct kvm_mmu_page *page_head = page_header(page_hpa);
-
- ASSERT(is_empty_shadow_page(page_hpa));
- page_head->page_hpa = page_hpa;
- list_move(&page_head->link, &vcpu->free_pages);
- ++vcpu->kvm->n_free_mmu_pages;
+ ASSERT(is_empty_shadow_page(page_head->spt));
+ list_del(&page_head->link);
+ __free_page(virt_to_page(page_head->spt));
+ kfree(page_head);
+ ++kvm->n_free_mmu_pages;
}
static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -475,12 +494,15 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
{
struct kvm_mmu_page *page;
- if (list_empty(&vcpu->free_pages))
+ if (!vcpu->kvm->n_free_mmu_pages)
return NULL;
- page = list_entry(vcpu->free_pages.next, struct kvm_mmu_page, link);
- list_move(&page->link, &vcpu->kvm->active_mmu_pages);
- ASSERT(is_empty_shadow_page(page->page_hpa));
+ page = mmu_memory_cache_alloc(&vcpu->mmu_page_header_cache,
+ sizeof *page);
+ page->spt = mmu_memory_cache_alloc(&vcpu->mmu_page_cache, PAGE_SIZE);
+ set_page_private(virt_to_page(page->spt), (unsigned long)page);
+ list_add(&page->link, &vcpu->kvm->active_mmu_pages);
+ ASSERT(is_empty_shadow_page(page->spt));
page->slot_bitmap = 0;
page->multimapped = 0;
page->parent_pte = parent_pte;
@@ -525,8 +547,7 @@ static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu,
pte_chain->parent_ptes[0] = parent_pte;
}
-static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *page,
+static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
u64 *parent_pte)
{
struct kvm_pte_chain *pte_chain;
@@ -553,7 +574,7 @@ static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
pte_chain->parent_ptes[i] = NULL;
if (i == 0) {
hlist_del(&pte_chain->link);
- mmu_free_pte_chain(vcpu, pte_chain);
+ mmu_free_pte_chain(pte_chain);
if (hlist_empty(&page->parent_ptes)) {
page->multimapped = 0;
page->parent_pte = NULL;
@@ -631,22 +652,22 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
return page;
}
-static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+static void kvm_mmu_page_unlink_children(struct kvm *kvm,
struct kvm_mmu_page *page)
{
unsigned i;
u64 *pt;
u64 ent;
- pt = __va(page->page_hpa);
+ pt = page->spt;
if (page->role.level == PT_PAGE_TABLE_LEVEL) {
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
if (pt[i] & PT_PRESENT_MASK)
- rmap_remove(vcpu, &pt[i]);
+ rmap_remove(&pt[i]);
pt[i] = 0;
}
- kvm_arch_ops->tlb_flush(vcpu);
+ kvm_flush_remote_tlbs(kvm);
return;
}
@@ -657,18 +678,18 @@ static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
if (!(ent & PT_PRESENT_MASK))
continue;
ent &= PT64_BASE_ADDR_MASK;
- mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+ mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
}
+ kvm_flush_remote_tlbs(kvm);
}
-static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *page,
+static void kvm_mmu_put_page(struct kvm_mmu_page *page,
u64 *parent_pte)
{
- mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+ mmu_page_remove_parent_pte(page, parent_pte);
}
-static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_zap_page(struct kvm *kvm,
struct kvm_mmu_page *page)
{
u64 *parent_pte;
@@ -684,15 +705,15 @@ static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
parent_pte = chain->parent_ptes[0];
}
BUG_ON(!parent_pte);
- kvm_mmu_put_page(vcpu, page, parent_pte);
- *parent_pte = 0;
+ kvm_mmu_put_page(page, parent_pte);
+ set_shadow_pte(parent_pte, 0);
}
- kvm_mmu_page_unlink_children(vcpu, page);
+ kvm_mmu_page_unlink_children(kvm, page);
if (!page->root_count) {
hlist_del(&page->hash_link);
- kvm_mmu_free_page(vcpu, page->page_hpa);
+ kvm_mmu_free_page(kvm, page);
} else
- list_move(&page->link, &vcpu->kvm->active_mmu_pages);
+ list_move(&page->link, &kvm->active_mmu_pages);
}
static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -711,12 +732,23 @@ static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
if (page->gfn == gfn && !page->role.metaphysical) {
pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
r = 1;
}
return r;
}
+static void mmu_unshadow(struct kvm_vcpu *vcpu, gfn_t gfn)
+{
+ struct kvm_mmu_page *page;
+
+ while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
+ pgprintk("%s: zap %lx %x\n",
+ __FUNCTION__, gfn, page->role.word);
+ kvm_mmu_zap_page(vcpu->kvm, page);
+ }
+}
+
static void page_header_update_slot(struct kvm *kvm, void *pte, gpa_t gpa)
{
int slot = memslot_id(kvm, gfn_to_memslot(kvm, gpa >> PAGE_SHIFT));
@@ -805,7 +837,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, hpa_t p)
return -ENOMEM;
}
- table[index] = new_table->page_hpa | PT_PRESENT_MASK
+ table[index] = __pa(new_table->spt) | PT_PRESENT_MASK
| PT_WRITABLE_MASK | PT_USER_MASK;
}
table_addr = table[index] & PT64_BASE_ADDR_MASK;
@@ -817,11 +849,12 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
int i;
struct kvm_mmu_page *page;
+ if (!VALID_PAGE(vcpu->mmu.root_hpa))
+ return;
#ifdef CONFIG_X86_64
if (vcpu->mmu.shadow_root_level == PT64_ROOT_LEVEL) {
hpa_t root = vcpu->mmu.root_hpa;
- ASSERT(VALID_PAGE(root));
page = page_header(root);
--page->root_count;
vcpu->mmu.root_hpa = INVALID_PAGE;
@@ -832,7 +865,6 @@ static void mmu_free_roots(struct kvm_vcpu *vcpu)
hpa_t root = vcpu->mmu.pae_root[i];
if (root) {
- ASSERT(VALID_PAGE(root));
root &= PT64_BASE_ADDR_MASK;
page = page_header(root);
--page->root_count;
@@ -857,7 +889,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
ASSERT(!VALID_PAGE(root));
page = kvm_mmu_get_page(vcpu, root_gfn, 0,
PT64_ROOT_LEVEL, 0, 0, NULL);
- root = page->page_hpa;
+ root = __pa(page->spt);
++page->root_count;
vcpu->mmu.root_hpa = root;
return;
@@ -878,7 +910,7 @@ static void mmu_alloc_roots(struct kvm_vcpu *vcpu)
page = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
PT32_ROOT_LEVEL, !is_paging(vcpu),
0, NULL);
- root = page->page_hpa;
+ root = __pa(page->spt);
++page->root_count;
vcpu->mmu.pae_root[i] = root | PT_PRESENT_MASK;
}
@@ -928,9 +960,7 @@ static int nonpaging_init_context(struct kvm_vcpu *vcpu)
context->free = nonpaging_free;
context->root_level = 0;
context->shadow_root_level = PT32E_ROOT_LEVEL;
- mmu_alloc_roots(vcpu);
- ASSERT(VALID_PAGE(context->root_hpa));
- kvm_arch_ops->set_cr3(vcpu, context->root_hpa);
+ context->root_hpa = INVALID_PAGE;
return 0;
}
@@ -944,59 +974,6 @@ static void paging_new_cr3(struct kvm_vcpu *vcpu)
{
pgprintk("%s: cr3 %lx\n", __FUNCTION__, vcpu->cr3);
mmu_free_roots(vcpu);
- if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
- kvm_mmu_free_some_pages(vcpu);
- mmu_alloc_roots(vcpu);
- kvm_mmu_flush_tlb(vcpu);
- kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
-}
-
-static inline void set_pte_common(struct kvm_vcpu *vcpu,
- u64 *shadow_pte,
- gpa_t gaddr,
- int dirty,
- u64 access_bits,
- gfn_t gfn)
-{
- hpa_t paddr;
-
- *shadow_pte |= access_bits << PT_SHADOW_BITS_OFFSET;
- if (!dirty)
- access_bits &= ~PT_WRITABLE_MASK;
-
- paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
-
- *shadow_pte |= access_bits;
-
- if (is_error_hpa(paddr)) {
- *shadow_pte |= gaddr;
- *shadow_pte |= PT_SHADOW_IO_MARK;
- *shadow_pte &= ~PT_PRESENT_MASK;
- return;
- }
-
- *shadow_pte |= paddr;
-
- if (access_bits & PT_WRITABLE_MASK) {
- struct kvm_mmu_page *shadow;
-
- shadow = kvm_mmu_lookup_page(vcpu, gfn);
- if (shadow) {
- pgprintk("%s: found shadow page for %lx, marking ro\n",
- __FUNCTION__, gfn);
- access_bits &= ~PT_WRITABLE_MASK;
- if (is_writeble_pte(*shadow_pte)) {
- *shadow_pte &= ~PT_WRITABLE_MASK;
- kvm_arch_ops->tlb_flush(vcpu);
- }
- }
- }
-
- if (access_bits & PT_WRITABLE_MASK)
- mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
-
- page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
- rmap_add(vcpu, shadow_pte);
}
static void inject_page_fault(struct kvm_vcpu *vcpu,
@@ -1006,23 +983,6 @@ static void inject_page_fault(struct kvm_vcpu *vcpu,
kvm_arch_ops->inject_page_fault(vcpu, addr, err_code);
}
-static inline int fix_read_pf(u64 *shadow_ent)
-{
- if ((*shadow_ent & PT_SHADOW_USER_MASK) &&
- !(*shadow_ent & PT_USER_MASK)) {
- /*
- * If supervisor write protect is disabled, we shadow kernel
- * pages as user pages so we can trap the write access.
- */
- *shadow_ent |= PT_USER_MASK;
- *shadow_ent &= ~PT_WRITABLE_MASK;
-
- return 1;
-
- }
- return 0;
-}
-
static void paging_free(struct kvm_vcpu *vcpu)
{
nonpaging_free(vcpu);
@@ -1047,10 +1007,7 @@ static int paging64_init_context_common(struct kvm_vcpu *vcpu, int level)
context->free = paging_free;
context->root_level = level;
context->shadow_root_level = level;
- mmu_alloc_roots(vcpu);
- ASSERT(VALID_PAGE(context->root_hpa));
- kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
- (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+ context->root_hpa = INVALID_PAGE;
return 0;
}
@@ -1069,10 +1026,7 @@ static int paging32_init_context(struct kvm_vcpu *vcpu)
context->free = paging_free;
context->root_level = PT32_ROOT_LEVEL;
context->shadow_root_level = PT32E_ROOT_LEVEL;
- mmu_alloc_roots(vcpu);
- ASSERT(VALID_PAGE(context->root_hpa));
- kvm_arch_ops->set_cr3(vcpu, context->root_hpa |
- (vcpu->cr3 & (CR3_PCD_MASK | CR3_WPT_MASK)));
+ context->root_hpa = INVALID_PAGE;
return 0;
}
@@ -1107,18 +1061,33 @@ static void destroy_kvm_mmu(struct kvm_vcpu *vcpu)
int kvm_mmu_reset_context(struct kvm_vcpu *vcpu)
{
+ destroy_kvm_mmu(vcpu);
+ return init_kvm_mmu(vcpu);
+}
+
+int kvm_mmu_load(struct kvm_vcpu *vcpu)
+{
int r;
- destroy_kvm_mmu(vcpu);
- r = init_kvm_mmu(vcpu);
- if (r < 0)
- goto out;
+ spin_lock(&vcpu->kvm->lock);
r = mmu_topup_memory_caches(vcpu);
+ if (r)
+ goto out;
+ mmu_alloc_roots(vcpu);
+ kvm_arch_ops->set_cr3(vcpu, vcpu->mmu.root_hpa);
+ kvm_mmu_flush_tlb(vcpu);
out:
+ spin_unlock(&vcpu->kvm->lock);
return r;
}
+EXPORT_SYMBOL_GPL(kvm_mmu_load);
+
+void kvm_mmu_unload(struct kvm_vcpu *vcpu)
+{
+ mmu_free_roots(vcpu);
+}
-static void mmu_pre_write_zap_pte(struct kvm_vcpu *vcpu,
+static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *page,
u64 *spte)
{
@@ -1128,16 +1097,32 @@ static void mmu_pre_write_zap_pte(struct kvm_vcpu *vcpu,
pte = *spte;
if (is_present_pte(pte)) {
if (page->role.level == PT_PAGE_TABLE_LEVEL)
- rmap_remove(vcpu, spte);
+ rmap_remove(spte);
else {
child = page_header(pte & PT64_BASE_ADDR_MASK);
- mmu_page_remove_parent_pte(vcpu, child, spte);
+ mmu_page_remove_parent_pte(child, spte);
}
}
*spte = 0;
+ kvm_flush_remote_tlbs(vcpu->kvm);
+}
+
+static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
+ struct kvm_mmu_page *page,
+ u64 *spte,
+ const void *new, int bytes)
+{
+ if (page->role.level != PT_PAGE_TABLE_LEVEL)
+ return;
+
+ if (page->role.glevels == PT32_ROOT_LEVEL)
+ paging32_update_pte(vcpu, page, spte, new, bytes);
+ else
+ paging64_update_pte(vcpu, page, spte, new, bytes);
}
-void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
+void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
+ const u8 *old, const u8 *new, int bytes)
{
gfn_t gfn = gpa >> PAGE_SHIFT;
struct kvm_mmu_page *page;
@@ -1149,6 +1134,7 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
unsigned pte_size;
unsigned page_offset;
unsigned misaligned;
+ unsigned quadrant;
int level;
int flooded = 0;
int npte;
@@ -1169,6 +1155,7 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
continue;
pte_size = page->role.glevels == PT32_ROOT_LEVEL ? 4 : 8;
misaligned = (offset ^ (offset + bytes - 1)) & ~(pte_size - 1);
+ misaligned |= bytes < 4;
if (misaligned || flooded) {
/*
* Misaligned accesses are too much trouble to fix
@@ -1182,7 +1169,7 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
*/
pgprintk("misaligned: gpa %llx bytes %d role %x\n",
gpa, bytes, page->role.word);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
continue;
}
page_offset = offset;
@@ -1200,21 +1187,20 @@ void kvm_mmu_pre_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
page_offset <<= 1;
npte = 2;
}
+ quadrant = page_offset >> PAGE_SHIFT;
page_offset &= ~PAGE_MASK;
+ if (quadrant != page->role.quadrant)
+ continue;
}
- spte = __va(page->page_hpa);
- spte += page_offset / sizeof(*spte);
+ spte = &page->spt[page_offset / sizeof(*spte)];
while (npte--) {
- mmu_pre_write_zap_pte(vcpu, page, spte);
+ mmu_pte_write_zap_pte(vcpu, page, spte);
+ mmu_pte_write_new_pte(vcpu, page, spte, new, bytes);
++spte;
}
}
}
-void kvm_mmu_post_write(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes)
-{
-}
-
int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva)
{
gpa_t gpa = vcpu->mmu.gva_to_gpa(vcpu, gva);
@@ -1229,7 +1215,7 @@ void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
page = container_of(vcpu->kvm->active_mmu_pages.prev,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
}
EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
@@ -1241,14 +1227,7 @@ static void free_mmu_pages(struct kvm_vcpu *vcpu)
while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
page = container_of(vcpu->kvm->active_mmu_pages.next,
struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
- }
- while (!list_empty(&vcpu->free_pages)) {
- page = list_entry(vcpu->free_pages.next,
- struct kvm_mmu_page, link);
- list_del(&page->link);
- __free_page(pfn_to_page(page->page_hpa >> PAGE_SHIFT));
- page->page_hpa = INVALID_PAGE;
+ kvm_mmu_zap_page(vcpu->kvm, page);
}
free_page((unsigned long)vcpu->mmu.pae_root);
}
@@ -1260,18 +1239,7 @@ static int alloc_mmu_pages(struct kvm_vcpu *vcpu)
ASSERT(vcpu);
- for (i = 0; i < KVM_NUM_MMU_PAGES; i++) {
- struct kvm_mmu_page *page_header = &vcpu->page_header_buf[i];
-
- INIT_LIST_HEAD(&page_header->link);
- if ((page = alloc_page(GFP_KERNEL)) == NULL)
- goto error_1;
- set_page_private(page, (unsigned long)page_header);
- page_header->page_hpa = (hpa_t)page_to_pfn(page) << PAGE_SHIFT;
- memset(__va(page_header->page_hpa), 0, PAGE_SIZE);
- list_add(&page_header->link, &vcpu->free_pages);
- ++vcpu->kvm->n_free_mmu_pages;
- }
+ vcpu->kvm->n_free_mmu_pages = KVM_NUM_MMU_PAGES;
/*
* When emulating 32-bit mode, cr3 is only 32 bits even on x86_64.
@@ -1296,7 +1264,6 @@ int kvm_mmu_create(struct kvm_vcpu *vcpu)
{
ASSERT(vcpu);
ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
- ASSERT(list_empty(&vcpu->free_pages));
return alloc_mmu_pages(vcpu);
}
@@ -1305,7 +1272,6 @@ int kvm_mmu_setup(struct kvm_vcpu *vcpu)
{
ASSERT(vcpu);
ASSERT(!VALID_PAGE(vcpu->mmu.root_hpa));
- ASSERT(!list_empty(&vcpu->free_pages));
return init_kvm_mmu(vcpu);
}
@@ -1319,9 +1285,8 @@ void kvm_mmu_destroy(struct kvm_vcpu *vcpu)
mmu_free_memory_caches(vcpu);
}
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
{
- struct kvm *kvm = vcpu->kvm;
struct kvm_mmu_page *page;
list_for_each_entry(page, &kvm->active_mmu_pages, link) {
@@ -1331,31 +1296,24 @@ void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
if (!test_bit(slot, &page->slot_bitmap))
continue;
- pt = __va(page->page_hpa);
+ pt = page->spt;
for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
/* avoid RMW */
if (pt[i] & PT_WRITABLE_MASK) {
- rmap_remove(vcpu, &pt[i]);
+ rmap_remove(&pt[i]);
pt[i] &= ~PT_WRITABLE_MASK;
}
}
}
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+void kvm_mmu_zap_all(struct kvm *kvm)
{
- destroy_kvm_mmu(vcpu);
+ struct kvm_mmu_page *page, *node;
- while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
- struct kvm_mmu_page *page;
+ list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
+ kvm_mmu_zap_page(kvm, page);
- page = container_of(vcpu->kvm->active_mmu_pages.next,
- struct kvm_mmu_page, link);
- kvm_mmu_zap_page(vcpu, page);
- }
-
- mmu_free_memory_caches(vcpu);
- kvm_arch_ops->tlb_flush(vcpu);
- init_kvm_mmu(vcpu);
+ kvm_flush_remote_tlbs(kvm);
}
void kvm_mmu_module_exit(void)
@@ -1364,21 +1322,29 @@ void kvm_mmu_module_exit(void)
kmem_cache_destroy(pte_chain_cache);
if (rmap_desc_cache)
kmem_cache_destroy(rmap_desc_cache);
+ if (mmu_page_header_cache)
+ kmem_cache_destroy(mmu_page_header_cache);
}
int kvm_mmu_module_init(void)
{
pte_chain_cache = kmem_cache_create("kvm_pte_chain",
sizeof(struct kvm_pte_chain),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!pte_chain_cache)
goto nomem;
rmap_desc_cache = kmem_cache_create("kvm_rmap_desc",
sizeof(struct kvm_rmap_desc),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!rmap_desc_cache)
goto nomem;
+ mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
+ sizeof(struct kvm_mmu_page),
+ 0, 0, NULL);
+ if (!mmu_page_header_cache)
+ goto nomem;
+
return 0;
nomem:
@@ -1482,7 +1448,7 @@ static int count_writable_mappings(struct kvm_vcpu *vcpu)
int i;
list_for_each_entry(page, &vcpu->kvm->active_mmu_pages, link) {
- u64 *pt = __va(page->page_hpa);
+ u64 *pt = page->spt;
if (page->role.level != PT_PAGE_TABLE_LEVEL)
continue;
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index 73ffbffb1097..4b5391c717f8 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -31,7 +31,6 @@
#define PT_INDEX(addr, level) PT64_INDEX(addr, level)
#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
#define PT_LEVEL_MASK(level) PT64_LEVEL_MASK(level)
- #define PT_PTE_COPY_MASK PT64_PTE_COPY_MASK
#ifdef CONFIG_X86_64
#define PT_MAX_FULL_LEVELS 4
#else
@@ -46,7 +45,6 @@
#define PT_INDEX(addr, level) PT32_INDEX(addr, level)
#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
#define PT_LEVEL_MASK(level) PT32_LEVEL_MASK(level)
- #define PT_PTE_COPY_MASK PT32_PTE_COPY_MASK
#define PT_MAX_FULL_LEVELS 2
#else
#error Invalid PTTYPE value
@@ -192,40 +190,143 @@ static void FNAME(mark_pagetable_dirty)(struct kvm *kvm,
mark_page_dirty(kvm, walker->table_gfn[walker->level - 1]);
}
-static void FNAME(set_pte)(struct kvm_vcpu *vcpu, u64 guest_pte,
- u64 *shadow_pte, u64 access_bits, gfn_t gfn)
+static void FNAME(set_pte_common)(struct kvm_vcpu *vcpu,
+ u64 *shadow_pte,
+ gpa_t gaddr,
+ pt_element_t *gpte,
+ u64 access_bits,
+ int user_fault,
+ int write_fault,
+ int *ptwrite,
+ struct guest_walker *walker,
+ gfn_t gfn)
{
- ASSERT(*shadow_pte == 0);
- access_bits &= guest_pte;
- *shadow_pte = (guest_pte & PT_PTE_COPY_MASK);
- set_pte_common(vcpu, shadow_pte, guest_pte & PT_BASE_ADDR_MASK,
- guest_pte & PT_DIRTY_MASK, access_bits, gfn);
+ hpa_t paddr;
+ int dirty = *gpte & PT_DIRTY_MASK;
+ u64 spte = *shadow_pte;
+ int was_rmapped = is_rmap_pte(spte);
+
+ pgprintk("%s: spte %llx gpte %llx access %llx write_fault %d"
+ " user_fault %d gfn %lx\n",
+ __FUNCTION__, spte, (u64)*gpte, access_bits,
+ write_fault, user_fault, gfn);
+
+ if (write_fault && !dirty) {
+ *gpte |= PT_DIRTY_MASK;
+ dirty = 1;
+ FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
+ }
+
+ spte |= PT_PRESENT_MASK | PT_ACCESSED_MASK | PT_DIRTY_MASK;
+ spte |= *gpte & PT64_NX_MASK;
+ if (!dirty)
+ access_bits &= ~PT_WRITABLE_MASK;
+
+ paddr = gpa_to_hpa(vcpu, gaddr & PT64_BASE_ADDR_MASK);
+
+ spte |= PT_PRESENT_MASK;
+ if (access_bits & PT_USER_MASK)
+ spte |= PT_USER_MASK;
+
+ if (is_error_hpa(paddr)) {
+ spte |= gaddr;
+ spte |= PT_SHADOW_IO_MARK;
+ spte &= ~PT_PRESENT_MASK;
+ set_shadow_pte(shadow_pte, spte);
+ return;
+ }
+
+ spte |= paddr;
+
+ if ((access_bits & PT_WRITABLE_MASK)
+ || (write_fault && !is_write_protection(vcpu) && !user_fault)) {
+ struct kvm_mmu_page *shadow;
+
+ spte |= PT_WRITABLE_MASK;
+ if (user_fault) {
+ mmu_unshadow(vcpu, gfn);
+ goto unshadowed;
+ }
+
+ shadow = kvm_mmu_lookup_page(vcpu, gfn);
+ if (shadow) {
+ pgprintk("%s: found shadow page for %lx, marking ro\n",
+ __FUNCTION__, gfn);
+ access_bits &= ~PT_WRITABLE_MASK;
+ if (is_writeble_pte(spte)) {
+ spte &= ~PT_WRITABLE_MASK;
+ kvm_arch_ops->tlb_flush(vcpu);
+ }
+ if (write_fault)
+ *ptwrite = 1;
+ }
+ }
+
+unshadowed:
+
+ if (access_bits & PT_WRITABLE_MASK)
+ mark_page_dirty(vcpu->kvm, gaddr >> PAGE_SHIFT);
+
+ set_shadow_pte(shadow_pte, spte);
+ page_header_update_slot(vcpu->kvm, shadow_pte, gaddr);
+ if (!was_rmapped)
+ rmap_add(vcpu, shadow_pte);
}
-static void FNAME(set_pde)(struct kvm_vcpu *vcpu, u64 guest_pde,
- u64 *shadow_pte, u64 access_bits, gfn_t gfn)
+static void FNAME(set_pte)(struct kvm_vcpu *vcpu, pt_element_t *gpte,
+ u64 *shadow_pte, u64 access_bits,
+ int user_fault, int write_fault, int *ptwrite,
+ struct guest_walker *walker, gfn_t gfn)
+{
+ access_bits &= *gpte;
+ FNAME(set_pte_common)(vcpu, shadow_pte, *gpte & PT_BASE_ADDR_MASK,
+ gpte, access_bits, user_fault, write_fault,
+ ptwrite, walker, gfn);
+}
+
+static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
+ u64 *spte, const void *pte, int bytes)
+{
+ pt_element_t gpte;
+
+ if (bytes < sizeof(pt_element_t))
+ return;
+ gpte = *(const pt_element_t *)pte;
+ if (~gpte & (PT_PRESENT_MASK | PT_ACCESSED_MASK))
+ return;
+ pgprintk("%s: gpte %llx spte %p\n", __FUNCTION__, (u64)gpte, spte);
+ FNAME(set_pte)(vcpu, &gpte, spte, PT_USER_MASK | PT_WRITABLE_MASK, 0,
+ 0, NULL, NULL,
+ (gpte & PT_BASE_ADDR_MASK) >> PAGE_SHIFT);
+}
+
+static void FNAME(set_pde)(struct kvm_vcpu *vcpu, pt_element_t *gpde,
+ u64 *shadow_pte, u64 access_bits,
+ int user_fault, int write_fault, int *ptwrite,
+ struct guest_walker *walker, gfn_t gfn)
{
gpa_t gaddr;
- ASSERT(*shadow_pte == 0);
- access_bits &= guest_pde;
+ access_bits &= *gpde;
gaddr = (gpa_t)gfn << PAGE_SHIFT;
if (PTTYPE == 32 && is_cpuid_PSE36())
- gaddr |= (guest_pde & PT32_DIR_PSE36_MASK) <<
+ gaddr |= (*gpde & PT32_DIR_PSE36_MASK) <<
(32 - PT32_DIR_PSE36_SHIFT);
- *shadow_pte = guest_pde & PT_PTE_COPY_MASK;
- set_pte_common(vcpu, shadow_pte, gaddr,
- guest_pde & PT_DIRTY_MASK, access_bits, gfn);
+ FNAME(set_pte_common)(vcpu, shadow_pte, gaddr,
+ gpde, access_bits, user_fault, write_fault,
+ ptwrite, walker, gfn);
}
/*
* Fetch a shadow pte for a specific level in the paging hierarchy.
*/
static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
- struct guest_walker *walker)
+ struct guest_walker *walker,
+ int user_fault, int write_fault, int *ptwrite)
{
hpa_t shadow_addr;
int level;
+ u64 *shadow_ent;
u64 *prev_shadow_ent = NULL;
pt_element_t *guest_ent = walker->ptep;
@@ -242,43 +343,31 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
for (; ; level--) {
u32 index = SHADOW_PT_INDEX(addr, level);
- u64 *shadow_ent = ((u64 *)__va(shadow_addr)) + index;
struct kvm_mmu_page *shadow_page;
u64 shadow_pte;
int metaphysical;
gfn_t table_gfn;
unsigned hugepage_access = 0;
+ shadow_ent = ((u64 *)__va(shadow_addr)) + index;
if (is_present_pte(*shadow_ent) || is_io_pte(*shadow_ent)) {
if (level == PT_PAGE_TABLE_LEVEL)
- return shadow_ent;
+ break;
shadow_addr = *shadow_ent & PT64_BASE_ADDR_MASK;
prev_shadow_ent = shadow_ent;
continue;
}
- if (level == PT_PAGE_TABLE_LEVEL) {
-
- if (walker->level == PT_DIRECTORY_LEVEL) {
- if (prev_shadow_ent)
- *prev_shadow_ent |= PT_SHADOW_PS_MARK;
- FNAME(set_pde)(vcpu, *guest_ent, shadow_ent,
- walker->inherited_ar,
- walker->gfn);
- } else {
- ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
- FNAME(set_pte)(vcpu, *guest_ent, shadow_ent,
- walker->inherited_ar,
- walker->gfn);
- }
- return shadow_ent;
- }
+ if (level == PT_PAGE_TABLE_LEVEL)
+ break;
if (level - 1 == PT_PAGE_TABLE_LEVEL
&& walker->level == PT_DIRECTORY_LEVEL) {
metaphysical = 1;
hugepage_access = *guest_ent;
hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+ if (*guest_ent & PT64_NX_MASK)
+ hugepage_access |= (1 << 2);
hugepage_access >>= PT_WRITABLE_SHIFT;
table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
>> PAGE_SHIFT;
@@ -289,90 +378,24 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
shadow_page = kvm_mmu_get_page(vcpu, table_gfn, addr, level-1,
metaphysical, hugepage_access,
shadow_ent);
- shadow_addr = shadow_page->page_hpa;
+ shadow_addr = __pa(shadow_page->spt);
shadow_pte = shadow_addr | PT_PRESENT_MASK | PT_ACCESSED_MASK
| PT_WRITABLE_MASK | PT_USER_MASK;
*shadow_ent = shadow_pte;
prev_shadow_ent = shadow_ent;
}
-}
-/*
- * The guest faulted for write. We need to
- *
- * - check write permissions
- * - update the guest pte dirty bit
- * - update our own dirty page tracking structures
- */
-static int FNAME(fix_write_pf)(struct kvm_vcpu *vcpu,
- u64 *shadow_ent,
- struct guest_walker *walker,
- gva_t addr,
- int user,
- int *write_pt)
-{
- pt_element_t *guest_ent;
- int writable_shadow;
- gfn_t gfn;
- struct kvm_mmu_page *page;
-
- if (is_writeble_pte(*shadow_ent))
- return !user || (*shadow_ent & PT_USER_MASK);
-
- writable_shadow = *shadow_ent & PT_SHADOW_WRITABLE_MASK;
- if (user) {
- /*
- * User mode access. Fail if it's a kernel page or a read-only
- * page.
- */
- if (!(*shadow_ent & PT_SHADOW_USER_MASK) || !writable_shadow)
- return 0;
- ASSERT(*shadow_ent & PT_USER_MASK);
- } else
- /*
- * Kernel mode access. Fail if it's a read-only page and
- * supervisor write protection is enabled.
- */
- if (!writable_shadow) {
- if (is_write_protection(vcpu))
- return 0;
- *shadow_ent &= ~PT_USER_MASK;
- }
-
- guest_ent = walker->ptep;
-
- if (!is_present_pte(*guest_ent)) {
- *shadow_ent = 0;
- return 0;
+ if (walker->level == PT_DIRECTORY_LEVEL) {
+ FNAME(set_pde)(vcpu, guest_ent, shadow_ent,
+ walker->inherited_ar, user_fault, write_fault,
+ ptwrite, walker, walker->gfn);
+ } else {
+ ASSERT(walker->level == PT_PAGE_TABLE_LEVEL);
+ FNAME(set_pte)(vcpu, guest_ent, shadow_ent,
+ walker->inherited_ar, user_fault, write_fault,
+ ptwrite, walker, walker->gfn);
}
-
- gfn = walker->gfn;
-
- if (user) {
- /*
- * Usermode page faults won't be for page table updates.
- */
- while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
- pgprintk("%s: zap %lx %x\n",
- __FUNCTION__, gfn, page->role.word);
- kvm_mmu_zap_page(vcpu, page);
- }
- } else if (kvm_mmu_lookup_page(vcpu, gfn)) {
- pgprintk("%s: found shadow page for %lx, marking ro\n",
- __FUNCTION__, gfn);
- mark_page_dirty(vcpu->kvm, gfn);
- FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
- *guest_ent |= PT_DIRTY_MASK;
- *write_pt = 1;
- return 0;
- }
- mark_page_dirty(vcpu->kvm, gfn);
- *shadow_ent |= PT_WRITABLE_MASK;
- FNAME(mark_pagetable_dirty)(vcpu->kvm, walker);
- *guest_ent |= PT_DIRTY_MASK;
- rmap_add(vcpu, shadow_ent);
-
- return 1;
+ return shadow_ent;
}
/*
@@ -397,7 +420,6 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
int fetch_fault = error_code & PFERR_FETCH_MASK;
struct guest_walker walker;
u64 *shadow_pte;
- int fixed;
int write_pt = 0;
int r;
@@ -421,27 +443,20 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr,
pgprintk("%s: guest page fault\n", __FUNCTION__);
inject_page_fault(vcpu, addr, walker.error_code);
FNAME(release_walker)(&walker);
+ vcpu->last_pt_write_count = 0; /* reset fork detector */
return 0;
}
- shadow_pte = FNAME(fetch)(vcpu, addr, &walker);
- pgprintk("%s: shadow pte %p %llx\n", __FUNCTION__,
- shadow_pte, *shadow_pte);
-
- /*
- * Update the shadow pte.
- */
- if (write_fault)
- fixed = FNAME(fix_write_pf)(vcpu, shadow_pte, &walker, addr,
- user_fault, &write_pt);
- else
- fixed = fix_read_pf(shadow_pte);
-
- pgprintk("%s: updated shadow pte %p %llx\n", __FUNCTION__,
- shadow_pte, *shadow_pte);
+ shadow_pte = FNAME(fetch)(vcpu, addr, &walker, user_fault, write_fault,
+ &write_pt);
+ pgprintk("%s: shadow pte %p %llx ptwrite %d\n", __FUNCTION__,
+ shadow_pte, *shadow_pte, write_pt);
FNAME(release_walker)(&walker);
+ if (!write_pt)
+ vcpu->last_pt_write_count = 0; /* reset fork detector */
+
/*
* mmio: emulate if accessible, otherwise its a guest fault.
*/
@@ -478,7 +493,5 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, gva_t vaddr)
#undef PT_INDEX
#undef SHADOW_PT_INDEX
#undef PT_LEVEL_MASK
-#undef PT_PTE_COPY_MASK
-#undef PT_NON_PTE_COPY_MASK
#undef PT_DIR_BASE_ADDR_MASK
#undef PT_MAX_FULL_LEVELS
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index fa17d6d4f0cb..bc818cc126e3 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -14,16 +14,17 @@
*
*/
+#include "kvm_svm.h"
+#include "x86_emulate.h"
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
#include <linux/highmem.h>
#include <linux/profile.h>
#include <linux/sched.h>
-#include <asm/desc.h>
-#include "kvm_svm.h"
-#include "x86_emulate.h"
+#include <asm/desc.h>
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
@@ -378,7 +379,7 @@ static __init int svm_hardware_setup(void)
int cpu;
struct page *iopm_pages;
struct page *msrpm_pages;
- void *msrpm_va;
+ void *iopm_va, *msrpm_va;
int r;
kvm_emulator_want_group7_invlpg();
@@ -387,8 +388,10 @@ static __init int svm_hardware_setup(void)
if (!iopm_pages)
return -ENOMEM;
- memset(page_address(iopm_pages), 0xff,
- PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+
+ iopm_va = page_address(iopm_pages);
+ memset(iopm_va, 0xff, PAGE_SIZE * (1 << IOPM_ALLOC_ORDER));
+ clear_bit(0x80, iopm_va); /* allow direct access to PC debug port */
iopm_base = page_to_pfn(iopm_pages) << PAGE_SHIFT;
@@ -579,7 +582,7 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
goto out2;
vcpu->svm->vmcb = page_address(page);
- memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
+ clear_page(vcpu->svm->vmcb);
vcpu->svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
vcpu->svm->asid_generation = 0;
memset(vcpu->svm->db_regs, 0, sizeof(vcpu->svm->db_regs));
@@ -587,9 +590,9 @@ static int svm_create_vcpu(struct kvm_vcpu *vcpu)
fx_init(vcpu);
vcpu->fpu_active = 1;
- vcpu->apic_base = 0xfee00000 |
- /*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
- MSR_IA32_APICBASE_ENABLE;
+ vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+ if (vcpu == &vcpu->kvm->vcpus[0])
+ vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
return 0;
@@ -955,7 +958,7 @@ static int shutdown_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
* VMCB is undefined after a SHUTDOWN intercept
* so reinitialize it.
*/
- memset(vcpu->svm->vmcb, 0, PAGE_SIZE);
+ clear_page(vcpu->svm->vmcb);
init_vmcb(vcpu->svm->vmcb);
kvm_run->exit_reason = KVM_EXIT_SHUTDOWN;
@@ -1113,12 +1116,7 @@ static int halt_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
vcpu->svm->next_rip = vcpu->svm->vmcb->save.rip + 1;
skip_emulated_instruction(vcpu);
- if (vcpu->irq_summary)
- return 1;
-
- kvm_run->exit_reason = KVM_EXIT_HLT;
- ++vcpu->stat.halt_exits;
- return 0;
+ return kvm_emulate_halt(vcpu);
}
static int vmmcall_interception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1473,6 +1471,11 @@ static void load_db_regs(unsigned long *db_regs)
asm volatile ("mov %0, %%dr3" : : "r"(db_regs[3]));
}
+static void svm_flush_tlb(struct kvm_vcpu *vcpu)
+{
+ force_new_asid(vcpu);
+}
+
static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u16 fs_selector;
@@ -1481,11 +1484,20 @@ static int svm_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
int r;
again:
+ r = kvm_mmu_reload(vcpu);
+ if (unlikely(r))
+ return r;
+
if (!vcpu->mmio_read_completed)
do_interrupt_requests(vcpu, kvm_run);
clgi();
+ vcpu->guest_mode = 1;
+ if (vcpu->requests)
+ if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
+ svm_flush_tlb(vcpu);
+
pre_svm_run(vcpu);
save_host_msrs(vcpu);
@@ -1617,6 +1629,8 @@ again:
#endif
: "cc", "memory" );
+ vcpu->guest_mode = 0;
+
if (vcpu->fpu_active) {
fx_save(vcpu->guest_fx_image);
fx_restore(vcpu->host_fx_image);
@@ -1681,11 +1695,6 @@ again:
return r;
}
-static void svm_flush_tlb(struct kvm_vcpu *vcpu)
-{
- force_new_asid(vcpu);
-}
-
static void svm_set_cr3(struct kvm_vcpu *vcpu, unsigned long root)
{
vcpu->svm->vmcb->save.cr3 = root;
@@ -1727,6 +1736,12 @@ static void svm_inject_page_fault(struct kvm_vcpu *vcpu,
static int is_disabled(void)
{
+ u64 vm_cr;
+
+ rdmsrl(MSR_VM_CR, vm_cr);
+ if (vm_cr & (1 << SVM_VM_CR_SVM_DISABLE))
+ return 1;
+
return 0;
}
diff --git a/drivers/kvm/svm.h b/drivers/kvm/svm.h
index 5e93814400ce..3b1b0f35b6cb 100644
--- a/drivers/kvm/svm.h
+++ b/drivers/kvm/svm.h
@@ -175,8 +175,11 @@ struct __attribute__ ((__packed__)) vmcb {
#define SVM_CPUID_FUNC 0x8000000a
#define MSR_EFER_SVME_MASK (1ULL << 12)
+#define MSR_VM_CR 0xc0010114
#define MSR_VM_HSAVE_PA 0xc0010117ULL
+#define SVM_VM_CR_SVM_DISABLE 4
+
#define SVM_SELECTOR_S_SHIFT 4
#define SVM_SELECTOR_DPL_SHIFT 5
#define SVM_SELECTOR_P_SHIFT 7
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index c1ac106ace8c..80628f69916d 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -17,28 +17,35 @@
#include "kvm.h"
#include "vmx.h"
+#include "segment_descriptor.h"
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/profile.h>
#include <linux/sched.h>
+
#include <asm/io.h>
#include <asm/desc.h>
-#include "segment_descriptor.h"
-
MODULE_AUTHOR("Qumranet");
MODULE_LICENSE("GPL");
+static int init_rmode_tss(struct kvm *kvm);
+
static DEFINE_PER_CPU(struct vmcs *, vmxarea);
static DEFINE_PER_CPU(struct vmcs *, current_vmcs);
+static struct page *vmx_io_bitmap_a;
+static struct page *vmx_io_bitmap_b;
+
#ifdef CONFIG_X86_64
#define HOST_IS_64 1
#else
#define HOST_IS_64 0
#endif
+#define EFER_SAVE_RESTORE_BITS ((u64)EFER_SCE)
static struct vmcs_descriptor {
int size;
@@ -82,18 +89,17 @@ static const u32 vmx_msr_index[] = {
};
#define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
-#ifdef CONFIG_X86_64
-static unsigned msr_offset_kernel_gs_base;
-#define NR_64BIT_MSRS 4
-/*
- * avoid save/load MSR_SYSCALL_MASK and MSR_LSTAR by std vt
- * mechanism (cpu bug AA24)
- */
-#define NR_BAD_MSRS 2
-#else
-#define NR_64BIT_MSRS 0
-#define NR_BAD_MSRS 0
-#endif
+static inline u64 msr_efer_save_restore_bits(struct vmx_msr_entry msr)
+{
+ return (u64)msr.data & EFER_SAVE_RESTORE_BITS;
+}
+
+static inline int msr_efer_need_save_restore(struct kvm_vcpu *vcpu)
+{
+ int efer_offset = vcpu->msr_offset_efer;
+ return msr_efer_save_restore_bits(vcpu->host_msrs[efer_offset]) !=
+ msr_efer_save_restore_bits(vcpu->guest_msrs[efer_offset]);
+}
static inline int is_page_fault(u32 intr_info)
{
@@ -115,13 +121,23 @@ static inline int is_external_interrupt(u32 intr_info)
== (INTR_TYPE_EXT_INTR | INTR_INFO_VALID_MASK);
}
-static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+static int __find_msr_index(struct kvm_vcpu *vcpu, u32 msr)
{
int i;
for (i = 0; i < vcpu->nmsrs; ++i)
if (vcpu->guest_msrs[i].index == msr)
- return &vcpu->guest_msrs[i];
+ return i;
+ return -1;
+}
+
+static struct vmx_msr_entry *find_msr_entry(struct kvm_vcpu *vcpu, u32 msr)
+{
+ int i;
+
+ i = __find_msr_index(vcpu, msr);
+ if (i >= 0)
+ return &vcpu->guest_msrs[i];
return NULL;
}
@@ -147,6 +163,7 @@ static void __vcpu_clear(void *arg)
vmcs_clear(vcpu->vmcs);
if (per_cpu(current_vmcs, cpu) == vcpu->vmcs)
per_cpu(current_vmcs, cpu) = NULL;
+ rdtscll(vcpu->host_tsc);
}
static void vcpu_clear(struct kvm_vcpu *vcpu)
@@ -234,6 +251,127 @@ static void vmcs_set_bits(unsigned long field, u32 mask)
vmcs_writel(field, vmcs_readl(field) | mask);
}
+static void update_exception_bitmap(struct kvm_vcpu *vcpu)
+{
+ u32 eb;
+
+ eb = 1u << PF_VECTOR;
+ if (!vcpu->fpu_active)
+ eb |= 1u << NM_VECTOR;
+ if (vcpu->guest_debug.enabled)
+ eb |= 1u << 1;
+ if (vcpu->rmode.active)
+ eb = ~0;
+ vmcs_write32(EXCEPTION_BITMAP, eb);
+}
+
+static void reload_tss(void)
+{
+#ifndef CONFIG_X86_64
+
+ /*
+ * VT restores TR but not its size. Useless.
+ */
+ struct descriptor_table gdt;
+ struct segment_descriptor *descs;
+
+ get_gdt(&gdt);
+ descs = (void *)gdt.base;
+ descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
+ load_TR_desc();
+#endif
+}
+
+static void load_transition_efer(struct kvm_vcpu *vcpu)
+{
+ u64 trans_efer;
+ int efer_offset = vcpu->msr_offset_efer;
+
+ trans_efer = vcpu->host_msrs[efer_offset].data;
+ trans_efer &= ~EFER_SAVE_RESTORE_BITS;
+ trans_efer |= msr_efer_save_restore_bits(
+ vcpu->guest_msrs[efer_offset]);
+ wrmsrl(MSR_EFER, trans_efer);
+ vcpu->stat.efer_reload++;
+}
+
+static void vmx_save_host_state(struct kvm_vcpu *vcpu)
+{
+ struct vmx_host_state *hs = &vcpu->vmx_host_state;
+
+ if (hs->loaded)
+ return;
+
+ hs->loaded = 1;
+ /*
+ * Set host fs and gs selectors. Unfortunately, 22.2.3 does not
+ * allow segment selectors with cpl > 0 or ti == 1.
+ */
+ hs->ldt_sel = read_ldt();
+ hs->fs_gs_ldt_reload_needed = hs->ldt_sel;
+ hs->fs_sel = read_fs();
+ if (!(hs->fs_sel & 7))
+ vmcs_write16(HOST_FS_SELECTOR, hs->fs_sel);
+ else {
+ vmcs_write16(HOST_FS_SELECTOR, 0);
+ hs->fs_gs_ldt_reload_needed = 1;
+ }
+ hs->gs_sel = read_gs();
+ if (!(hs->gs_sel & 7))
+ vmcs_write16(HOST_GS_SELECTOR, hs->gs_sel);
+ else {
+ vmcs_write16(HOST_GS_SELECTOR, 0);
+ hs->fs_gs_ldt_reload_needed = 1;
+ }
+
+#ifdef CONFIG_X86_64
+ vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
+ vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
+#else
+ vmcs_writel(HOST_FS_BASE, segment_base(hs->fs_sel));
+ vmcs_writel(HOST_GS_BASE, segment_base(hs->gs_sel));
+#endif
+
+#ifdef CONFIG_X86_64
+ if (is_long_mode(vcpu)) {
+ save_msrs(vcpu->host_msrs + vcpu->msr_offset_kernel_gs_base, 1);
+ }
+#endif
+ load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
+ if (msr_efer_need_save_restore(vcpu))
+ load_transition_efer(vcpu);
+}
+
+static void vmx_load_host_state(struct kvm_vcpu *vcpu)
+{
+ struct vmx_host_state *hs = &vcpu->vmx_host_state;
+
+ if (!hs->loaded)
+ return;
+
+ hs->loaded = 0;
+ if (hs->fs_gs_ldt_reload_needed) {
+ load_ldt(hs->ldt_sel);
+ load_fs(hs->fs_sel);
+ /*
+ * If we have to reload gs, we must take care to
+ * preserve our gs base.
+ */
+ local_irq_disable();
+ load_gs(hs->gs_sel);
+#ifdef CONFIG_X86_64
+ wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
+#endif
+ local_irq_enable();
+
+ reload_tss();
+ }
+ save_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
+ load_msrs(vcpu->host_msrs, vcpu->save_nmsrs);
+ if (msr_efer_need_save_restore(vcpu))
+ load_msrs(vcpu->host_msrs + vcpu->msr_offset_efer, 1);
+}
+
/*
* Switches to specified vcpu, until a matching vcpu_put(), but assumes
* vcpu mutex is already taken.
@@ -242,6 +380,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
{
u64 phys_addr = __pa(vcpu->vmcs);
int cpu;
+ u64 tsc_this, delta;
cpu = get_cpu();
@@ -275,15 +414,43 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu)
rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
+
+ /*
+ * Make sure the time stamp counter is monotonous.
+ */
+ rdtscll(tsc_this);
+ delta = vcpu->host_tsc - tsc_this;
+ vmcs_write64(TSC_OFFSET, vmcs_read64(TSC_OFFSET) + delta);
}
}
static void vmx_vcpu_put(struct kvm_vcpu *vcpu)
{
+ vmx_load_host_state(vcpu);
kvm_put_guest_fpu(vcpu);
put_cpu();
}
+static void vmx_fpu_activate(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->fpu_active)
+ return;
+ vcpu->fpu_active = 1;
+ vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+ if (vcpu->cr0 & CR0_TS_MASK)
+ vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+ update_exception_bitmap(vcpu);
+}
+
+static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
+{
+ if (!vcpu->fpu_active)
+ return;
+ vcpu->fpu_active = 0;
+ vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
+ update_exception_bitmap(vcpu);
+}
+
static void vmx_vcpu_decache(struct kvm_vcpu *vcpu)
{
vcpu_clear(vcpu);
@@ -332,41 +499,61 @@ static void vmx_inject_gp(struct kvm_vcpu *vcpu, unsigned error_code)
}
/*
+ * Swap MSR entry in host/guest MSR entry array.
+ */
+void move_msr_up(struct kvm_vcpu *vcpu, int from, int to)
+{
+ struct vmx_msr_entry tmp;
+ tmp = vcpu->guest_msrs[to];
+ vcpu->guest_msrs[to] = vcpu->guest_msrs[from];
+ vcpu->guest_msrs[from] = tmp;
+ tmp = vcpu->host_msrs[to];
+ vcpu->host_msrs[to] = vcpu->host_msrs[from];
+ vcpu->host_msrs[from] = tmp;
+}
+
+/*
* Set up the vmcs to automatically save and restore system
* msrs. Don't touch the 64-bit msrs if the guest is in legacy
* mode, as fiddling with msrs is very expensive.
*/
static void setup_msrs(struct kvm_vcpu *vcpu)
{
- int nr_skip, nr_good_msrs;
-
- if (is_long_mode(vcpu))
- nr_skip = NR_BAD_MSRS;
- else
- nr_skip = NR_64BIT_MSRS;
- nr_good_msrs = vcpu->nmsrs - nr_skip;
+ int save_nmsrs;
- /*
- * MSR_K6_STAR is only needed on long mode guests, and only
- * if efer.sce is enabled.
- */
- if (find_msr_entry(vcpu, MSR_K6_STAR)) {
- --nr_good_msrs;
+ save_nmsrs = 0;
#ifdef CONFIG_X86_64
- if (is_long_mode(vcpu) && (vcpu->shadow_efer & EFER_SCE))
- ++nr_good_msrs;
-#endif
+ if (is_long_mode(vcpu)) {
+ int index;
+
+ index = __find_msr_index(vcpu, MSR_SYSCALL_MASK);
+ if (index >= 0)
+ move_msr_up(vcpu, index, save_nmsrs++);
+ index = __find_msr_index(vcpu, MSR_LSTAR);
+ if (index >= 0)
+ move_msr_up(vcpu, index, save_nmsrs++);
+ index = __find_msr_index(vcpu, MSR_CSTAR);
+ if (index >= 0)
+ move_msr_up(vcpu, index, save_nmsrs++);
+ index = __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+ if (index >= 0)
+ move_msr_up(vcpu, index, save_nmsrs++);
+ /*
+ * MSR_K6_STAR is only needed on long mode guests, and only
+ * if efer.sce is enabled.
+ */
+ index = __find_msr_index(vcpu, MSR_K6_STAR);
+ if ((index >= 0) && (vcpu->shadow_efer & EFER_SCE))
+ move_msr_up(vcpu, index, save_nmsrs++);
}
+#endif
+ vcpu->save_nmsrs = save_nmsrs;
- vmcs_writel(VM_ENTRY_MSR_LOAD_ADDR,
- virt_to_phys(vcpu->guest_msrs + nr_skip));
- vmcs_writel(VM_EXIT_MSR_STORE_ADDR,
- virt_to_phys(vcpu->guest_msrs + nr_skip));
- vmcs_writel(VM_EXIT_MSR_LOAD_ADDR,
- virt_to_phys(vcpu->host_msrs + nr_skip));
- vmcs_write32(VM_EXIT_MSR_STORE_COUNT, nr_good_msrs); /* 22.2.2 */
- vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
- vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, nr_good_msrs); /* 22.2.2 */
+#ifdef CONFIG_X86_64
+ vcpu->msr_offset_kernel_gs_base =
+ __find_msr_index(vcpu, MSR_KERNEL_GS_BASE);
+#endif
+ vcpu->msr_offset_efer = __find_msr_index(vcpu, MSR_EFER);
}
/*
@@ -394,23 +581,6 @@ static void guest_write_tsc(u64 guest_tsc)
vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
}
-static void reload_tss(void)
-{
-#ifndef CONFIG_X86_64
-
- /*
- * VT restores TR but not its size. Useless.
- */
- struct descriptor_table gdt;
- struct segment_descriptor *descs;
-
- get_gdt(&gdt);
- descs = (void *)gdt.base;
- descs[GDT_ENTRY_TSS].type = 9; /* available TSS */
- load_TR_desc();
-#endif
-}
-
/*
* Reads an msr value (of 'msr_index') into 'pdata'.
* Returns 0 on success, non-0 otherwise.
@@ -470,10 +640,15 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
{
struct vmx_msr_entry *msr;
+ int ret = 0;
+
switch (msr_index) {
#ifdef CONFIG_X86_64
case MSR_EFER:
- return kvm_set_msr_common(vcpu, msr_index, data);
+ ret = kvm_set_msr_common(vcpu, msr_index, data);
+ if (vcpu->vmx_host_state.loaded)
+ load_transition_efer(vcpu);
+ break;
case MSR_FS_BASE:
vmcs_writel(GUEST_FS_BASE, data);
break;
@@ -497,14 +672,14 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
msr = find_msr_entry(vcpu, msr_index);
if (msr) {
msr->data = data;
+ if (vcpu->vmx_host_state.loaded)
+ load_msrs(vcpu->guest_msrs, vcpu->save_nmsrs);
break;
}
- return kvm_set_msr_common(vcpu, msr_index, data);
- msr->data = data;
- break;
+ ret = kvm_set_msr_common(vcpu, msr_index, data);
}
- return 0;
+ return ret;
}
/*
@@ -530,10 +705,8 @@ static void vcpu_put_rsp_rip(struct kvm_vcpu *vcpu)
static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
{
unsigned long dr7 = 0x400;
- u32 exception_bitmap;
int old_singlestep;
- exception_bitmap = vmcs_read32(EXCEPTION_BITMAP);
old_singlestep = vcpu->guest_debug.singlestep;
vcpu->guest_debug.enabled = dbg->enabled;
@@ -549,13 +722,9 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
dr7 |= 0 << (i*4+16); /* execution breakpoint */
}
- exception_bitmap |= (1u << 1); /* Trap debug exceptions */
-
vcpu->guest_debug.singlestep = dbg->singlestep;
- } else {
- exception_bitmap &= ~(1u << 1); /* Ignore debug exceptions */
+ } else
vcpu->guest_debug.singlestep = 0;
- }
if (old_singlestep && !vcpu->guest_debug.singlestep) {
unsigned long flags;
@@ -565,7 +734,7 @@ static int set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg)
vmcs_writel(GUEST_RFLAGS, flags);
}
- vmcs_write32(EXCEPTION_BITMAP, exception_bitmap);
+ update_exception_bitmap(vcpu);
vmcs_writel(GUEST_DR7, dr7);
return 0;
@@ -679,14 +848,6 @@ static __exit void hardware_unsetup(void)
free_kvm_area();
}
-static void update_exception_bitmap(struct kvm_vcpu *vcpu)
-{
- if (vcpu->rmode.active)
- vmcs_write32(EXCEPTION_BITMAP, ~0);
- else
- vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
-}
-
static void fix_pmode_dataseg(int seg, struct kvm_save_segment *save)
{
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
@@ -793,6 +954,8 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
fix_rmode_seg(VCPU_SREG_DS, &vcpu->rmode.ds);
fix_rmode_seg(VCPU_SREG_GS, &vcpu->rmode.gs);
fix_rmode_seg(VCPU_SREG_FS, &vcpu->rmode.fs);
+
+ init_rmode_tss(vcpu->kvm);
}
#ifdef CONFIG_X86_64
@@ -837,6 +1000,8 @@ static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
+ vmx_fpu_deactivate(vcpu);
+
if (vcpu->rmode.active && (cr0 & CR0_PE_MASK))
enter_pmode(vcpu);
@@ -852,26 +1017,20 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
}
#endif
- if (!(cr0 & CR0_TS_MASK)) {
- vcpu->fpu_active = 1;
- vmcs_clear_bits(EXCEPTION_BITMAP, CR0_TS_MASK);
- }
-
vmcs_writel(CR0_READ_SHADOW, cr0);
vmcs_writel(GUEST_CR0,
(cr0 & ~KVM_GUEST_CR0_MASK) | KVM_VM_CR0_ALWAYS_ON);
vcpu->cr0 = cr0;
+
+ if (!(cr0 & CR0_TS_MASK) || !(cr0 & CR0_PE_MASK))
+ vmx_fpu_activate(vcpu);
}
static void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3)
{
vmcs_writel(GUEST_CR3, cr3);
-
- if (!(vcpu->cr0 & CR0_TS_MASK)) {
- vcpu->fpu_active = 0;
- vmcs_set_bits(GUEST_CR0, CR0_TS_MASK);
- vmcs_set_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
- }
+ if (vcpu->cr0 & CR0_PE_MASK)
+ vmx_fpu_deactivate(vcpu);
}
static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
@@ -937,23 +1096,11 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
var->unusable = (ar >> 16) & 1;
}
-static void vmx_set_segment(struct kvm_vcpu *vcpu,
- struct kvm_segment *var, int seg)
+static u32 vmx_segment_access_rights(struct kvm_segment *var)
{
- struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
u32 ar;
- vmcs_writel(sf->base, var->base);
- vmcs_write32(sf->limit, var->limit);
- vmcs_write16(sf->selector, var->selector);
- if (vcpu->rmode.active && var->s) {
- /*
- * Hack real-mode segments into vm86 compatibility.
- */
- if (var->base == 0xffff0000 && var->selector == 0xf000)
- vmcs_writel(sf->base, 0xf0000);
- ar = 0xf3;
- } else if (var->unusable)
+ if (var->unusable)
ar = 1 << 16;
else {
ar = var->type & 15;
@@ -967,6 +1114,35 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
}
if (ar == 0) /* a 0 value means unusable */
ar = AR_UNUSABLE_MASK;
+
+ return ar;
+}
+
+static void vmx_set_segment(struct kvm_vcpu *vcpu,
+ struct kvm_segment *var, int seg)
+{
+ struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
+ u32 ar;
+
+ if (vcpu->rmode.active && seg == VCPU_SREG_TR) {
+ vcpu->rmode.tr.selector = var->selector;
+ vcpu->rmode.tr.base = var->base;
+ vcpu->rmode.tr.limit = var->limit;
+ vcpu->rmode.tr.ar = vmx_segment_access_rights(var);
+ return;
+ }
+ vmcs_writel(sf->base, var->base);
+ vmcs_write32(sf->limit, var->limit);
+ vmcs_write16(sf->selector, var->selector);
+ if (vcpu->rmode.active && var->s) {
+ /*
+ * Hack real-mode segments into vm86 compatibility.
+ */
+ if (var->base == 0xffff0000 && var->selector == 0xf000)
+ vmcs_writel(sf->base, 0xf0000);
+ ar = 0xf3;
+ } else
+ ar = vmx_segment_access_rights(var);
vmcs_write32(sf->ar_bytes, ar);
}
@@ -1018,16 +1194,16 @@ static int init_rmode_tss(struct kvm* kvm)
}
page = kmap_atomic(p1, KM_USER0);
- memset(page, 0, PAGE_SIZE);
+ clear_page(page);
*(u16*)(page + 0x66) = TSS_BASE_SIZE + TSS_REDIRECTION_SIZE;
kunmap_atomic(page, KM_USER0);
page = kmap_atomic(p2, KM_USER0);
- memset(page, 0, PAGE_SIZE);
+ clear_page(page);
kunmap_atomic(page, KM_USER0);
page = kmap_atomic(p3, KM_USER0);
- memset(page, 0, PAGE_SIZE);
+ clear_page(page);
*(page + RMODE_TSS_SIZE - 2 * PAGE_SIZE - 1) = ~0;
kunmap_atomic(page, KM_USER0);
@@ -1066,7 +1242,7 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
struct descriptor_table dt;
int i;
int ret = 0;
- extern asmlinkage void kvm_vmx_return(void);
+ unsigned long kvm_vmx_return;
if (!init_rmode_tss(vcpu->kvm)) {
ret = -ENOMEM;
@@ -1076,9 +1252,9 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
memset(vcpu->regs, 0, sizeof(vcpu->regs));
vcpu->regs[VCPU_REGS_RDX] = get_rdx_init_val();
vcpu->cr8 = 0;
- vcpu->apic_base = 0xfee00000 |
- /*for vcpu 0*/ MSR_IA32_APICBASE_BSP |
- MSR_IA32_APICBASE_ENABLE;
+ vcpu->apic_base = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+ if (vcpu == &vcpu->kvm->vcpus[0])
+ vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
fx_init(vcpu);
@@ -1129,8 +1305,8 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
/* I/O */
- vmcs_write64(IO_BITMAP_A, 0);
- vmcs_write64(IO_BITMAP_B, 0);
+ vmcs_write64(IO_BITMAP_A, page_to_phys(vmx_io_bitmap_a));
+ vmcs_write64(IO_BITMAP_B, page_to_phys(vmx_io_bitmap_b));
guest_write_tsc(0);
@@ -1150,12 +1326,11 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
CPU_BASED_HLT_EXITING /* 20.6.2 */
| CPU_BASED_CR8_LOAD_EXITING /* 20.6.2 */
| CPU_BASED_CR8_STORE_EXITING /* 20.6.2 */
- | CPU_BASED_UNCOND_IO_EXITING /* 20.6.2 */
+ | CPU_BASED_ACTIVATE_IO_BITMAP /* 20.6.2 */
| CPU_BASED_MOV_DR_EXITING
| CPU_BASED_USE_TSC_OFFSETING /* 21.3 */
);
- vmcs_write32(EXCEPTION_BITMAP, 1 << PF_VECTOR);
vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0);
vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0);
vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */
@@ -1185,8 +1360,11 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
get_idt(&dt);
vmcs_writel(HOST_IDTR_BASE, dt.base); /* 22.2.4 */
-
- vmcs_writel(HOST_RIP, (unsigned long)kvm_vmx_return); /* 22.2.5 */
+ asm ("mov $.Lkvm_vmx_return, %0" : "=r"(kvm_vmx_return));
+ vmcs_writel(HOST_RIP, kvm_vmx_return); /* 22.2.5 */
+ vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
+ vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
+ vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
rdmsr(MSR_IA32_SYSENTER_CS, host_sysenter_cs, junk);
vmcs_write32(HOST_IA32_SYSENTER_CS, host_sysenter_cs);
@@ -1210,10 +1388,6 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->host_msrs[j].reserved = 0;
vcpu->host_msrs[j].data = data;
vcpu->guest_msrs[j] = vcpu->host_msrs[j];
-#ifdef CONFIG_X86_64
- if (index == MSR_KERNEL_GS_BASE)
- msr_offset_kernel_gs_base = j;
-#endif
++vcpu->nmsrs;
}
@@ -1241,6 +1415,8 @@ static int vmx_vcpu_setup(struct kvm_vcpu *vcpu)
#ifdef CONFIG_X86_64
vmx_set_efer(vcpu, 0);
#endif
+ vmx_fpu_activate(vcpu);
+ update_exception_bitmap(vcpu);
return 0;
@@ -1365,7 +1541,11 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu,
if (!vcpu->rmode.active)
return 0;
- if (vec == GP_VECTOR && err_code == 0)
+ /*
+ * Instruction with address size override prefix opcode 0x67
+ * Cause the #SS fault with 0 error code in VM86 mode.
+ */
+ if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) && err_code == 0)
if (emulate_instruction(vcpu, NULL, 0, 0) == EMULATE_DONE)
return 1;
return 0;
@@ -1400,10 +1580,7 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
if (is_no_device(intr_info)) {
- vcpu->fpu_active = 1;
- vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
- if (!(vcpu->cr0 & CR0_TS_MASK))
- vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+ vmx_fpu_activate(vcpu);
return 1;
}
@@ -1445,8 +1622,13 @@ static int handle_exception(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
if (vcpu->rmode.active &&
handle_rmode_exception(vcpu, intr_info & INTR_INFO_VECTOR_MASK,
- error_code))
+ error_code)) {
+ if (vcpu->halt_request) {
+ vcpu->halt_request = 0;
+ return kvm_emulate_halt(vcpu);
+ }
return 1;
+ }
if ((intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VECTOR_MASK)) == (INTR_TYPE_EXCEPTION | 1)) {
kvm_run->exit_reason = KVM_EXIT_DEBUG;
@@ -1595,11 +1777,10 @@ static int handle_cr(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
break;
case 2: /* clts */
vcpu_load_rsp_rip(vcpu);
- vcpu->fpu_active = 1;
- vmcs_clear_bits(EXCEPTION_BITMAP, 1 << NM_VECTOR);
- vmcs_clear_bits(GUEST_CR0, CR0_TS_MASK);
+ vmx_fpu_deactivate(vcpu);
vcpu->cr0 &= ~CR0_TS_MASK;
vmcs_writel(CR0_READ_SHADOW, vcpu->cr0);
+ vmx_fpu_activate(vcpu);
skip_emulated_instruction(vcpu);
return 1;
case 1: /*mov from cr*/
@@ -1734,12 +1915,7 @@ static int handle_interrupt_window(struct kvm_vcpu *vcpu,
static int handle_halt(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
skip_emulated_instruction(vcpu);
- if (vcpu->irq_summary)
- return 1;
-
- kvm_run->exit_reason = KVM_EXIT_HLT;
- ++vcpu->stat.halt_exits;
- return 0;
+ return kvm_emulate_halt(vcpu);
}
static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
@@ -1770,7 +1946,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu,
};
static const int kvm_vmx_max_exit_handlers =
- sizeof(kvm_vmx_exit_handlers) / sizeof(*kvm_vmx_exit_handlers);
+ ARRAY_SIZE(kvm_vmx_exit_handlers);
/*
* The guest has exited. See if we can fix it or if we need userspace
@@ -1810,61 +1986,44 @@ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu,
(vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF));
}
+static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
+{
+}
+
static int vmx_vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
u8 fail;
- u16 fs_sel, gs_sel, ldt_sel;
- int fs_gs_ldt_reload_needed;
int r;
-again:
- /*
- * Set host fs and gs selectors. Unfortunately, 22.2.3 does not
- * allow segment selectors with cpl > 0 or ti == 1.
- */
- fs_sel = read_fs();
- gs_sel = read_gs();
- ldt_sel = read_ldt();
- fs_gs_ldt_reload_needed = (fs_sel & 7) | (gs_sel & 7) | ldt_sel;
- if (!fs_gs_ldt_reload_needed) {
- vmcs_write16(HOST_FS_SELECTOR, fs_sel);
- vmcs_write16(HOST_GS_SELECTOR, gs_sel);
- } else {
- vmcs_write16(HOST_FS_SELECTOR, 0);
- vmcs_write16(HOST_GS_SELECTOR, 0);
- }
-
-#ifdef CONFIG_X86_64
- vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
- vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
-#else
- vmcs_writel(HOST_FS_BASE, segment_base(fs_sel));
- vmcs_writel(HOST_GS_BASE, segment_base(gs_sel));
-#endif
+preempted:
+ if (vcpu->guest_debug.enabled)
+ kvm_guest_debug_pre(vcpu);
+again:
if (!vcpu->mmio_read_completed)
do_interrupt_requests(vcpu, kvm_run);
- if (vcpu->guest_debug.enabled)
- kvm_guest_debug_pre(vcpu);
-
+ vmx_save_host_state(vcpu);
kvm_load_guest_fpu(vcpu);
+ r = kvm_mmu_reload(vcpu);
+ if (unlikely(r))
+ goto out;
+
/*
* Loading guest fpu may have cleared host cr0.ts
*/
vmcs_writel(HOST_CR0, read_cr0());
-#ifdef CONFIG_X86_64
- if (is_long_mode(vcpu)) {
- save_msrs(vcpu->host_msrs + msr_offset_kernel_gs_base, 1);
- load_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
- }
-#endif
+ local_irq_disable();
+
+ vcpu->guest_mode = 1;
+ if (vcpu->requests)
+ if (test_and_clear_bit(KVM_TLB_FLUSH, &vcpu->requests))
+ vmx_flush_tlb(vcpu);
asm (
/* Store host registers */
- "pushf \n\t"
#ifdef CONFIG_X86_64
"push %%rax; push %%rbx; push %%rdx;"
"push %%rsi; push %%rdi; push %%rbp;"
@@ -1909,12 +2068,11 @@ again:
"mov %c[rcx](%3), %%ecx \n\t" /* kills %3 (ecx) */
#endif
/* Enter guest mode */
- "jne launched \n\t"
+ "jne .Llaunched \n\t"
ASM_VMX_VMLAUNCH "\n\t"
- "jmp kvm_vmx_return \n\t"
- "launched: " ASM_VMX_VMRESUME "\n\t"
- ".globl kvm_vmx_return \n\t"
- "kvm_vmx_return: "
+ "jmp .Lkvm_vmx_return \n\t"
+ ".Llaunched: " ASM_VMX_VMRESUME "\n\t"
+ ".Lkvm_vmx_return: "
/* Save guest registers, load host registers, keep flags */
#ifdef CONFIG_X86_64
"xchg %3, (%%rsp) \n\t"
@@ -1957,7 +2115,6 @@ again:
"pop %%ecx; popa \n\t"
#endif
"setbe %0 \n\t"
- "popf \n\t"
: "=q" (fail)
: "r"(vcpu->launched), "d"((unsigned long)HOST_RSP),
"c"(vcpu),
@@ -1981,84 +2138,61 @@ again:
[cr2]"i"(offsetof(struct kvm_vcpu, cr2))
: "cc", "memory" );
- /*
- * Reload segment selectors ASAP. (it's needed for a functional
- * kernel: x86 relies on having __KERNEL_PDA in %fs and x86_64
- * relies on having 0 in %gs for the CPU PDA to work.)
- */
- if (fs_gs_ldt_reload_needed) {
- load_ldt(ldt_sel);
- load_fs(fs_sel);
- /*
- * If we have to reload gs, we must take care to
- * preserve our gs base.
- */
- local_irq_disable();
- load_gs(gs_sel);
-#ifdef CONFIG_X86_64
- wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
-#endif
- local_irq_enable();
+ vcpu->guest_mode = 0;
+ local_irq_enable();
- reload_tss();
- }
++vcpu->stat.exits;
-#ifdef CONFIG_X86_64
- if (is_long_mode(vcpu)) {
- save_msrs(vcpu->guest_msrs, NR_BAD_MSRS);
- load_msrs(vcpu->host_msrs, NR_BAD_MSRS);
- }
-#endif
-
vcpu->interrupt_window_open = (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0;
asm ("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
- if (fail) {
+ if (unlikely(fail)) {
kvm_run->exit_reason = KVM_EXIT_FAIL_ENTRY;
kvm_run->fail_entry.hardware_entry_failure_reason
= vmcs_read32(VM_INSTRUCTION_ERROR);
r = 0;
- } else {
- /*
- * Profile KVM exit RIPs:
- */
- if (unlikely(prof_on == KVM_PROFILING))
- profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
-
- vcpu->launched = 1;
- r = kvm_handle_exit(kvm_run, vcpu);
- if (r > 0) {
- /* Give scheduler a change to reschedule. */
- if (signal_pending(current)) {
- ++vcpu->stat.signal_exits;
- post_kvm_run_save(vcpu, kvm_run);
- kvm_run->exit_reason = KVM_EXIT_INTR;
- return -EINTR;
- }
-
- if (dm_request_for_irq_injection(vcpu, kvm_run)) {
- ++vcpu->stat.request_irq_exits;
- post_kvm_run_save(vcpu, kvm_run);
- kvm_run->exit_reason = KVM_EXIT_INTR;
- return -EINTR;
- }
-
- kvm_resched(vcpu);
+ goto out;
+ }
+ /*
+ * Profile KVM exit RIPs:
+ */
+ if (unlikely(prof_on == KVM_PROFILING))
+ profile_hit(KVM_PROFILING, (void *)vmcs_readl(GUEST_RIP));
+
+ vcpu->launched = 1;
+ r = kvm_handle_exit(kvm_run, vcpu);
+ if (r > 0) {
+ /* Give scheduler a change to reschedule. */
+ if (signal_pending(current)) {
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.signal_exits;
+ goto out;
+ }
+
+ if (dm_request_for_irq_injection(vcpu, kvm_run)) {
+ r = -EINTR;
+ kvm_run->exit_reason = KVM_EXIT_INTR;
+ ++vcpu->stat.request_irq_exits;
+ goto out;
+ }
+ if (!need_resched()) {
+ ++vcpu->stat.light_exits;
goto again;
}
}
+out:
+ if (r > 0) {
+ kvm_resched(vcpu);
+ goto preempted;
+ }
+
post_kvm_run_save(vcpu, kvm_run);
return r;
}
-static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
-{
- vmcs_writel(GUEST_CR3, vmcs_readl(GUEST_CR3));
-}
-
static void vmx_inject_page_fault(struct kvm_vcpu *vcpu,
unsigned long addr,
u32 err_code)
@@ -2122,7 +2256,6 @@ static int vmx_create_vcpu(struct kvm_vcpu *vcpu)
vmcs_clear(vmcs);
vcpu->vmcs = vmcs;
vcpu->launched = 0;
- vcpu->fpu_active = 1;
return 0;
@@ -2188,11 +2321,50 @@ static struct kvm_arch_ops vmx_arch_ops = {
static int __init vmx_init(void)
{
- return kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+ void *iova;
+ int r;
+
+ vmx_io_bitmap_a = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ if (!vmx_io_bitmap_a)
+ return -ENOMEM;
+
+ vmx_io_bitmap_b = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ if (!vmx_io_bitmap_b) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * 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);
+ kunmap(vmx_io_bitmap_a);
+
+ iova = kmap(vmx_io_bitmap_b);
+ memset(iova, 0xff, PAGE_SIZE);
+ kunmap(vmx_io_bitmap_b);
+
+ r = kvm_init_arch(&vmx_arch_ops, THIS_MODULE);
+ if (r)
+ goto out1;
+
+ return 0;
+
+out1:
+ __free_page(vmx_io_bitmap_b);
+out:
+ __free_page(vmx_io_bitmap_a);
+ return r;
}
static void __exit vmx_exit(void)
{
+ __free_page(vmx_io_bitmap_b);
+ __free_page(vmx_io_bitmap_a);
+
kvm_exit_arch();
}
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index 7ade09086aa5..1b800fc00342 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -98,8 +98,11 @@ static u8 opcode_table[256] = {
0, 0, 0, 0,
/* 0x40 - 0x4F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 0x50 - 0x5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x50 - 0x57 */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 0x58 - 0x5F */
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
+ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
/* 0x60 - 0x6F */
0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -128,9 +131,9 @@ static u8 opcode_table[256] = {
/* 0xB0 - 0xBF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xC0 - 0xC7 */
- ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM, 0, 0,
- 0, 0, ByteOp | DstMem | SrcImm | ModRM | Mov,
- DstMem | SrcImm | ModRM | Mov,
+ ByteOp | DstMem | SrcImm | ModRM, DstMem | SrcImmByte | ModRM,
+ 0, ImplicitOps, 0, 0,
+ ByteOp | DstMem | SrcImm | ModRM | Mov, DstMem | SrcImm | ModRM | Mov,
/* 0xC8 - 0xCF */
0, 0, 0, 0, 0, 0, 0, 0,
/* 0xD0 - 0xD7 */
@@ -143,7 +146,8 @@ static u8 opcode_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0xF0 - 0xF7 */
0, 0, 0, 0,
- 0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
+ ImplicitOps, 0,
+ ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
/* 0xF8 - 0xFF */
0, 0, 0, 0,
0, 0, ByteOp | DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM
@@ -152,14 +156,14 @@ static u8 opcode_table[256] = {
static u16 twobyte_table[256] = {
/* 0x00 - 0x0F */
0, SrcMem | ModRM | DstReg, 0, 0, 0, 0, ImplicitOps, 0,
- 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
+ 0, 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,
/* 0x20 - 0x2F */
ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
/* 0x30 - 0x3F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 0x40 - 0x47 */
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -481,6 +485,8 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
int mode = ctxt->mode;
unsigned long modrm_ea;
int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
+ int no_wb = 0;
+ u64 msr_data;
/* Shadow copy of register state. Committed on successful emulation. */
unsigned long _regs[NR_VCPU_REGS];
@@ -1047,7 +1053,7 @@ done_prefixes:
_regs[VCPU_REGS_RSP]),
&dst.val, dst.bytes, ctxt)) != 0)
goto done;
- dst.val = dst.orig_val; /* skanky: disable writeback */
+ no_wb = 1;
break;
default:
goto cannot_emulate;
@@ -1056,7 +1062,7 @@ done_prefixes:
}
writeback:
- if ((d & Mov) || (dst.orig_val != dst.val)) {
+ if (!no_wb) {
switch (dst.type) {
case OP_REG:
/* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */
@@ -1149,6 +1155,23 @@ special_insn:
case 0xae ... 0xaf: /* scas */
DPRINTF("Urk! I don't handle SCAS.\n");
goto cannot_emulate;
+ case 0xf4: /* hlt */
+ ctxt->vcpu->halt_request = 1;
+ goto done;
+ case 0xc3: /* ret */
+ dst.ptr = &_eip;
+ goto pop_instruction;
+ case 0x58 ... 0x5f: /* pop reg */
+ dst.ptr = (unsigned long *)&_regs[b & 0x7];
+
+pop_instruction:
+ if ((rc = ops->read_std(register_address(ctxt->ss_base,
+ _regs[VCPU_REGS_RSP]), dst.ptr, op_bytes, ctxt)) != 0)
+ goto done;
+
+ register_address_increment(_regs[VCPU_REGS_RSP], op_bytes);
+ no_wb = 1; /* Disable writeback. */
+ break;
}
goto writeback;
@@ -1302,8 +1325,10 @@ twobyte_insn:
twobyte_special_insn:
/* Disable writeback. */
- dst.orig_val = dst.val;
+ no_wb = 1;
switch (b) {
+ case 0x09: /* wbinvd */
+ break;
case 0x0d: /* GrpP (prefetch) */
case 0x18: /* Grp16 (prefetch/nop) */
break;
@@ -1320,6 +1345,29 @@ twobyte_special_insn:
goto cannot_emulate;
realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
break;
+ case 0x30:
+ /* wrmsr */
+ msr_data = (u32)_regs[VCPU_REGS_RAX]
+ | ((u64)_regs[VCPU_REGS_RDX] << 32);
+ rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+ if (rc) {
+ kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ _eip = ctxt->vcpu->rip;
+ }
+ rc = X86EMUL_CONTINUE;
+ break;
+ case 0x32:
+ /* rdmsr */
+ rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+ if (rc) {
+ kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+ _eip = ctxt->vcpu->rip;
+ } else {
+ _regs[VCPU_REGS_RAX] = (u32)msr_data;
+ _regs[VCPU_REGS_RDX] = msr_data >> 32;
+ }
+ rc = X86EMUL_CONTINUE;
+ break;
case 0xc7: /* Grp9 (cmpxchg8b) */
{
u64 old, new;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 87d2046f866c..4468cb3a8d24 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1,9 +1,6 @@
-
-menu "LED devices"
- depends on HAS_IOMEM
-
-config NEW_LEDS
+menuconfig NEW_LEDS
bool "LED Support"
+ depends on HAS_IOMEM
help
Say Y to enable Linux LED support. This allows control of supported
LEDs from both userspace and optionally, by kernel events (triggers).
@@ -11,9 +8,10 @@ config NEW_LEDS
This is not related to standard keyboard LEDs which are controlled
via the input system.
+if NEW_LEDS
+
config LEDS_CLASS
tristate "LED Class Support"
- depends on NEW_LEDS
help
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
@@ -95,11 +93,18 @@ config LEDS_COBALT
help
This option enables support for the front LED on Cobalt Server
+config LEDS_GPIO
+ tristate "LED Support for GPIO connected LEDs"
+ depends on LEDS_CLASS && GENERIC_GPIO
+ help
+ This option enables support for the LEDs connected to GPIO
+ outputs. To be useful the particular board must have LEDs
+ and they must be connected to the GPIO lines.
+
comment "LED Triggers"
config LEDS_TRIGGERS
bool "LED Trigger support"
- depends on NEW_LEDS
help
This option enables trigger support for the leds class.
These triggers allow kernel events to drive the LEDs and can
@@ -128,5 +133,4 @@ config LEDS_TRIGGER_HEARTBEAT
load average.
If unsure, say Y.
-endmenu
-
+endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index aa2c18efa5b2..f8995c9bc2ea 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT) += leds-cobalt.o
+obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 3c1711210e38..4211293ce862 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -2,7 +2,7 @@
* LED Class Core
*
* Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
- * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com>
+ * Copyright (C) 2005-2007 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
@@ -24,9 +24,10 @@
static struct class *leds_class;
-static ssize_t led_brightness_show(struct class_device *dev, char *buf)
+static ssize_t led_brightness_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
ssize_t ret = 0;
/* no lock needed for this */
@@ -36,10 +37,10 @@ static ssize_t led_brightness_show(struct class_device *dev, char *buf)
return ret;
}
-static ssize_t led_brightness_store(struct class_device *dev,
- const char *buf, size_t size)
+static ssize_t led_brightness_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
ssize_t ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
@@ -56,10 +57,9 @@ static ssize_t led_brightness_store(struct class_device *dev,
return ret;
}
-static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show,
- led_brightness_store);
+static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
#ifdef CONFIG_LEDS_TRIGGERS
-static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
#endif
/**
@@ -93,16 +93,15 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
int rc;
- led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
- parent, "%s", led_cdev->name);
- if (unlikely(IS_ERR(led_cdev->class_dev)))
- return PTR_ERR(led_cdev->class_dev);
+ led_cdev->dev = device_create(leds_class, parent, 0, "%s",
+ led_cdev->name);
+ if (unlikely(IS_ERR(led_cdev->dev)))
+ return PTR_ERR(led_cdev->dev);
- class_set_devdata(led_cdev->class_dev, led_cdev);
+ dev_set_drvdata(led_cdev->dev, led_cdev);
/* register the attributes */
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_brightness);
+ rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
if (rc)
goto err_out;
@@ -114,8 +113,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
#ifdef CONFIG_LEDS_TRIGGERS
rwlock_init(&led_cdev->trigger_lock);
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_trigger);
+ rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
if (rc)
goto err_out_led_list;
@@ -123,18 +121,17 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
#endif
printk(KERN_INFO "Registered led device: %s\n",
- led_cdev->class_dev->class_id);
+ led_cdev->name);
return 0;
#ifdef CONFIG_LEDS_TRIGGERS
err_out_led_list:
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_brightness);
+ device_remove_file(led_cdev->dev, &dev_attr_brightness);
list_del(&led_cdev->node);
#endif
err_out:
- class_device_unregister(led_cdev->class_dev);
+ device_unregister(led_cdev->dev);
return rc;
}
EXPORT_SYMBOL_GPL(led_classdev_register);
@@ -147,18 +144,16 @@ EXPORT_SYMBOL_GPL(led_classdev_register);
*/
void led_classdev_unregister(struct led_classdev *led_cdev)
{
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_brightness);
+ device_remove_file(led_cdev->dev, &dev_attr_brightness);
#ifdef CONFIG_LEDS_TRIGGERS
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_trigger);
+ device_remove_file(led_cdev->dev, &dev_attr_trigger);
write_lock(&led_cdev->trigger_lock);
if (led_cdev->trigger)
led_trigger_set(led_cdev, NULL);
write_unlock(&led_cdev->trigger_lock);
#endif
- class_device_unregister(led_cdev->class_dev);
+ device_unregister(led_cdev->dev);
write_lock(&leds_list_lock);
list_del(&led_cdev->node);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 454fb0901f82..575368c2b100 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -1,7 +1,7 @@
/*
* LED Triggers Core
*
- * Copyright 2005-2006 Openedhand Ltd.
+ * Copyright 2005-2007 Openedhand Ltd.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
*
@@ -28,10 +28,10 @@
static DEFINE_RWLOCK(triggers_list_lock);
static LIST_HEAD(trigger_list);
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
- size_t count)
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
char trigger_name[TRIG_NAME_MAX];
struct led_trigger *trig;
size_t len;
@@ -67,9 +67,10 @@ ssize_t led_trigger_store(struct class_device *dev, const char *buf,
}
-ssize_t led_trigger_show(struct class_device *dev, char *buf)
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_trigger *trig;
int len = 0;
@@ -183,13 +184,20 @@ int led_trigger_register(struct led_trigger *trigger)
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;
- led_trigger_register(trigger);
- }
+ 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;
}
@@ -215,7 +223,8 @@ void led_trigger_unregister(struct led_trigger *trigger)
void led_trigger_unregister_simple(struct led_trigger *trigger)
{
- led_trigger_unregister(trigger);
+ if (trigger)
+ led_trigger_unregister(trigger);
kfree(trigger);
}
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
new file mode 100644
index 000000000000..47d90db280ce
--- /dev/null
+++ b/drivers/leds/leds-gpio.c
@@ -0,0 +1,199 @@
+/*
+ * LEDs driver for GPIOs
+ *
+ * Copyright (C) 2007 8D Technologies inc.
+ * Raphael Assenat <raph@8d.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 <linux/workqueue.h>
+
+#include <asm/gpio.h>
+
+struct gpio_led_data {
+ struct led_classdev cdev;
+ unsigned gpio;
+ struct work_struct work;
+ u8 new_level;
+ u8 can_sleep;
+ u8 active_low;
+};
+
+static void gpio_led_work(struct work_struct *work)
+{
+ struct gpio_led_data *led_dat =
+ container_of(work, struct gpio_led_data, work);
+
+ gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+}
+
+static void gpio_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct gpio_led_data *led_dat =
+ container_of(led_cdev, struct gpio_led_data, cdev);
+ int level;
+
+ if (value == LED_OFF)
+ level = 0;
+ else
+ level = 1;
+
+ if (led_dat->active_low)
+ level = !level;
+
+ /* setting GPIOs with I2C/etc requires a preemptible task context */
+ if (led_dat->can_sleep) {
+ if (preempt_count()) {
+ led_dat->new_level = level;
+ schedule_work(&led_dat->work);
+ } else
+ gpio_set_value_cansleep(led_dat->gpio, level);
+ } else
+ gpio_set_value(led_dat->gpio, level);
+}
+
+static int __init gpio_led_probe(struct platform_device *pdev)
+{
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led *cur_led;
+ struct gpio_led_data *leds_data, *led_dat;
+ int i, ret = 0;
+
+ if (!pdata)
+ return -EBUSY;
+
+ leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
+ GFP_KERNEL);
+ if (!leds_data)
+ return -ENOMEM;
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ cur_led = &pdata->leds[i];
+ led_dat = &leds_data[i];
+
+ led_dat->cdev.name = cur_led->name;
+ led_dat->cdev.default_trigger = cur_led->default_trigger;
+ led_dat->gpio = cur_led->gpio;
+ led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
+ led_dat->active_low = cur_led->active_low;
+ led_dat->cdev.brightness_set = gpio_led_set;
+ led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
+
+ ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
+ if (ret < 0)
+ goto err;
+
+ gpio_direction_output(led_dat->gpio, led_dat->active_low);
+
+ ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+ if (ret < 0) {
+ gpio_free(led_dat->gpio);
+ goto err;
+ }
+
+ INIT_WORK(&led_dat->work, gpio_led_work);
+ }
+
+ platform_set_drvdata(pdev, leds_data);
+
+ return 0;
+
+err:
+ if (i > 0) {
+ for (i = i - 1; i >= 0; i--) {
+ led_classdev_unregister(&leds_data[i].cdev);
+ gpio_free(leds_data[i].gpio);
+ }
+ }
+
+ flush_scheduled_work();
+ kfree(leds_data);
+
+ return ret;
+}
+
+static int __exit gpio_led_remove(struct platform_device *pdev)
+{
+ int i;
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led_data *leds_data;
+
+ leds_data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ led_classdev_unregister(&leds_data[i].cdev);
+ gpio_free(leds_data[i].gpio);
+ }
+
+ kfree(leds_data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led_data *leds_data;
+ int i;
+
+ leds_data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++)
+ led_classdev_suspend(&leds_data[i].cdev);
+
+ return 0;
+}
+
+static int gpio_led_resume(struct platform_device *pdev)
+{
+ struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+ struct gpio_led_data *leds_data;
+ int i;
+
+ leds_data = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->num_leds; i++)
+ led_classdev_resume(&leds_data[i].cdev);
+
+ return 0;
+}
+#else
+#define gpio_led_suspend NULL
+#define gpio_led_resume NULL
+#endif
+
+static struct platform_driver gpio_led_driver = {
+ .remove = __exit_p(gpio_led_remove),
+ .suspend = gpio_led_suspend,
+ .resume = gpio_led_resume,
+ .driver = {
+ .name = "leds-gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gpio_led_init(void)
+{
+ return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
+}
+
+static void __exit gpio_led_exit(void)
+{
+ platform_driver_unregister(&gpio_led_driver);
+}
+
+module_init(gpio_led_init);
+module_exit(gpio_led_exit);
+
+MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
+MODULE_DESCRIPTION("GPIO LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 6f2d449ba983..bfac499f3258 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -19,7 +19,7 @@
static void locomoled_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value, int offset)
{
- struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev);
+ struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
unsigned long flags;
local_irq_save(flags);
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index a715c4ed93ff..f2f3884fe063 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -13,6 +13,7 @@
#ifndef __LEDS_H_INCLUDED
#define __LEDS_H_INCLUDED
+#include <linux/device.h>
#include <linux/leds.h>
static inline void led_set_brightness(struct led_classdev *led_cdev,
@@ -37,8 +38,9 @@ void led_trigger_set(struct led_classdev *led_cdev,
#define led_trigger_set(x, y) do {} while(0)
#endif
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
- size_t count);
-ssize_t led_trigger_show(struct class_device *dev, char *buf);
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
#endif /* __LEDS_H_INCLUDED */
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d756bdb01c59..ed9ff02c77ea 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -52,9 +52,10 @@ 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 class_device *dev, char *buf)
+static ssize_t led_delay_on_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
sprintf(buf, "%lu\n", timer_data->delay_on);
@@ -62,10 +63,10 @@ static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
return strlen(buf) + 1;
}
-static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
- size_t size)
+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 = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
@@ -84,9 +85,10 @@ static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
return ret;
}
-static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_off_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct led_classdev *led_cdev = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
sprintf(buf, "%lu\n", timer_data->delay_off);
@@ -94,10 +96,10 @@ static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
return strlen(buf) + 1;
}
-static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
- size_t size)
+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 = class_get_devdata(dev);
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct timer_trig_data *timer_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
@@ -116,10 +118,8 @@ static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
return ret;
}
-static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show,
- led_delay_on_store);
-static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
- led_delay_off_store);
+static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
+static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
static void timer_trig_activate(struct led_classdev *led_cdev)
{
@@ -136,18 +136,17 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
timer_data->timer.function = led_timer_function;
timer_data->timer.data = (unsigned long) led_cdev;
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_delay_on);
- if (rc) goto err_out;
- rc = class_device_create_file(led_cdev->class_dev,
- &class_device_attr_delay_off);
- if (rc) goto err_out_delayon;
+ rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
+ if (rc)
+ goto err_out;
+ rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
+ if (rc)
+ goto err_out_delayon;
return;
err_out_delayon:
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_delay_on);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_on);
err_out:
led_cdev->trigger_data = NULL;
kfree(timer_data);
@@ -158,10 +157,8 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev)
struct timer_trig_data *timer_data = led_cdev->trigger_data;
if (timer_data) {
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_delay_on);
- class_device_remove_file(led_cdev->class_dev,
- &class_device_attr_delay_off);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+ device_remove_file(led_cdev->dev, &dev_attr_delay_off);
del_timer_sync(&timer_data->timer);
kfree(timer_data);
}
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
new file mode 100644
index 000000000000..43d901fdc77f
--- /dev/null
+++ b/drivers/lguest/Kconfig
@@ -0,0 +1,20 @@
+config LGUEST
+ tristate "Linux hypervisor example code"
+ depends on X86 && PARAVIRT && NET && EXPERIMENTAL && !X86_PAE
+ select LGUEST_GUEST
+ select HVC_DRIVER
+ ---help---
+ This is a very simple module which allows you to run
+ multiple instances of the same Linux kernel, using the
+ "lguest" command found in the Documentation/lguest directory.
+ Note that "lguest" is pronounced to rhyme with "fell quest",
+ not "rustyvisor". See Documentation/lguest/lguest.txt.
+
+ If unsure, say N. If curious, say M. If masochistic, say Y.
+
+config LGUEST_GUEST
+ bool
+ help
+ The guest needs code built-in, even if the host has lguest
+ support as a module. The drivers are tiny, so we build them
+ in too.
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile
new file mode 100644
index 000000000000..55382c7d799c
--- /dev/null
+++ b/drivers/lguest/Makefile
@@ -0,0 +1,7 @@
+# Guest requires the paravirt_ops replacement and the bus driver.
+obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o
+
+# Host requires the other files, which can be a module.
+obj-$(CONFIG_LGUEST) += lg.o
+lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
+ segments.o io.o lguest_user.o switcher.o
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
new file mode 100644
index 000000000000..ce909ec57499
--- /dev/null
+++ b/drivers/lguest/core.c
@@ -0,0 +1,462 @@
+/* World's simplest hypervisor, to test paravirt_ops and show
+ * unbelievers that virtualization is the future. Plus, it's fun! */
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/cpu.h>
+#include <linux/freezer.h>
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/poll.h>
+#include <asm/highmem.h>
+#include <asm/asm-offsets.h>
+#include <asm/i387.h>
+#include "lg.h"
+
+/* Found in switcher.S */
+extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
+extern unsigned long default_idt_entries[];
+
+/* Every guest maps the core switcher code. */
+#define SHARED_SWITCHER_PAGES \
+ DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE)
+/* Pages for switcher itself, then two pages per cpu */
+#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS)
+
+/* We map at -4M for ease of mapping into the guest (one PTE page). */
+#define SWITCHER_ADDR 0xFFC00000
+
+static struct vm_struct *switcher_vma;
+static struct page **switcher_page;
+
+static int cpu_had_pge;
+static struct {
+ unsigned long offset;
+ unsigned short segment;
+} lguest_entry;
+
+/* This One Big lock protects all inter-guest data structures. */
+DEFINE_MUTEX(lguest_lock);
+static DEFINE_PER_CPU(struct lguest *, last_guest);
+
+/* FIXME: Make dynamic. */
+#define MAX_LGUEST_GUESTS 16
+struct lguest lguests[MAX_LGUEST_GUESTS];
+
+/* Offset from where switcher.S was compiled to where we've copied it */
+static unsigned long switcher_offset(void)
+{
+ return SWITCHER_ADDR - (unsigned long)start_switcher_text;
+}
+
+/* This cpu's struct lguest_pages. */
+static struct lguest_pages *lguest_pages(unsigned int cpu)
+{
+ return &(((struct lguest_pages *)
+ (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
+}
+
+static __init int map_switcher(void)
+{
+ int i, err;
+ struct page **pagep;
+
+ switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
+ GFP_KERNEL);
+ if (!switcher_page) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ if (!addr) {
+ err = -ENOMEM;
+ goto free_some_pages;
+ }
+ switcher_page[i] = virt_to_page(addr);
+ }
+
+ switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
+ VM_ALLOC, SWITCHER_ADDR, VMALLOC_END);
+ if (!switcher_vma) {
+ err = -ENOMEM;
+ printk("lguest: could not map switcher pages high\n");
+ goto free_pages;
+ }
+
+ pagep = switcher_page;
+ err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep);
+ if (err) {
+ printk("lguest: map_vm_area failed: %i\n", err);
+ goto free_vma;
+ }
+ memcpy(switcher_vma->addr, start_switcher_text,
+ end_switcher_text - start_switcher_text);
+
+ /* Fix up IDT entries to point into copied text. */
+ for (i = 0; i < IDT_ENTRIES; i++)
+ default_idt_entries[i] += switcher_offset();
+
+ for_each_possible_cpu(i) {
+ struct lguest_pages *pages = lguest_pages(i);
+ struct lguest_ro_state *state = &pages->state;
+
+ /* These fields are static: rest done in copy_in_guest_info */
+ state->host_gdt_desc.size = GDT_SIZE-1;
+ state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+ store_idt(&state->host_idt_desc);
+ state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
+ state->guest_idt_desc.address = (long)&state->guest_idt;
+ state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
+ state->guest_gdt_desc.address = (long)&state->guest_gdt;
+ state->guest_tss.esp0 = (long)(&pages->regs + 1);
+ state->guest_tss.ss0 = LGUEST_DS;
+ /* No I/O for you! */
+ state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+ setup_default_gdt_entries(state);
+ setup_default_idt_entries(state, default_idt_entries);
+
+ /* Setup LGUEST segments on all cpus */
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+ get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+ }
+
+ /* Initialize entry point into switcher. */
+ lguest_entry.offset = (long)switch_to_guest + switcher_offset();
+ lguest_entry.segment = LGUEST_CS;
+
+ printk(KERN_INFO "lguest: mapped switcher at %p\n",
+ switcher_vma->addr);
+ return 0;
+
+free_vma:
+ vunmap(switcher_vma->addr);
+free_pages:
+ i = TOTAL_SWITCHER_PAGES;
+free_some_pages:
+ for (--i; i >= 0; i--)
+ __free_pages(switcher_page[i], 0);
+ kfree(switcher_page);
+out:
+ return err;
+}
+
+static void unmap_switcher(void)
+{
+ unsigned int i;
+
+ vunmap(switcher_vma->addr);
+ for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
+ __free_pages(switcher_page[i], 0);
+}
+
+/* IN/OUT insns: enough to get us past boot-time probing. */
+static int emulate_insn(struct lguest *lg)
+{
+ u8 insn;
+ unsigned int insnlen = 0, in = 0, shift = 0;
+ unsigned long physaddr = guest_pa(lg, lg->regs->eip);
+
+ /* This only works for addresses in linear mapping... */
+ if (lg->regs->eip < lg->page_offset)
+ return 0;
+ lgread(lg, &insn, physaddr, 1);
+
+ /* Operand size prefix means it's actually for ax. */
+ if (insn == 0x66) {
+ shift = 16;
+ insnlen = 1;
+ lgread(lg, &insn, physaddr + insnlen, 1);
+ }
+
+ switch (insn & 0xFE) {
+ case 0xE4: /* in <next byte>,%al */
+ insnlen += 2;
+ in = 1;
+ break;
+ case 0xEC: /* in (%dx),%al */
+ insnlen += 1;
+ in = 1;
+ break;
+ case 0xE6: /* out %al,<next byte> */
+ insnlen += 2;
+ break;
+ case 0xEE: /* out %al,(%dx) */
+ insnlen += 1;
+ break;
+ default:
+ return 0;
+ }
+
+ if (in) {
+ /* Lower bit tells is whether it's a 16 or 32 bit access */
+ if (insn & 0x1)
+ lg->regs->eax = 0xFFFFFFFF;
+ else
+ lg->regs->eax |= (0xFFFF << shift);
+ }
+ lg->regs->eip += insnlen;
+ return 1;
+}
+
+int lguest_address_ok(const struct lguest *lg,
+ unsigned long addr, unsigned long len)
+{
+ return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
+}
+
+/* Just like get_user, but don't let guest access lguest binary. */
+u32 lgread_u32(struct lguest *lg, unsigned long addr)
+{
+ u32 val = 0;
+
+ /* Don't let them access lguest binary */
+ if (!lguest_address_ok(lg, addr, sizeof(val))
+ || get_user(val, (u32 __user *)addr) != 0)
+ kill_guest(lg, "bad read address %#lx", addr);
+ return val;
+}
+
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
+{
+ if (!lguest_address_ok(lg, addr, sizeof(val))
+ || put_user(val, (u32 __user *)addr) != 0)
+ kill_guest(lg, "bad write address %#lx", addr);
+}
+
+void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || copy_from_user(b, (void __user *)addr, bytes) != 0) {
+ /* copy_from_user should do this, but as we rely on it... */
+ memset(b, 0, bytes);
+ kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
+ }
+}
+
+void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
+ unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || copy_to_user((void __user *)addr, b, bytes) != 0)
+ kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
+}
+
+static void set_ts(void)
+{
+ u32 cr0;
+
+ cr0 = read_cr0();
+ if (!(cr0 & 8))
+ write_cr0(cr0|8);
+}
+
+static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+{
+ if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
+ __get_cpu_var(last_guest) = lg;
+ lg->last_pages = pages;
+ lg->changed = CHANGED_ALL;
+ }
+
+ /* These are pretty cheap, so we do them unconditionally. */
+ pages->state.host_cr3 = __pa(current->mm->pgd);
+ map_switcher_in_guest(lg, pages);
+ pages->state.guest_tss.esp1 = lg->esp1;
+ pages->state.guest_tss.ss1 = lg->ss1;
+
+ /* Copy direct trap entries. */
+ if (lg->changed & CHANGED_IDT)
+ copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+
+ /* Copy all GDT entries but the TSS. */
+ if (lg->changed & CHANGED_GDT)
+ copy_gdt(lg, pages->state.guest_gdt);
+ /* If only the TLS entries have changed, copy them. */
+ else if (lg->changed & CHANGED_GDT_TLS)
+ copy_gdt_tls(lg, pages->state.guest_gdt);
+
+ lg->changed = 0;
+}
+
+static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
+{
+ unsigned int clobber;
+
+ copy_in_guest_info(lg, pages);
+
+ /* Put eflags on stack, lcall does rest: suitable for iret return. */
+ asm volatile("pushf; lcall *lguest_entry"
+ : "=a"(clobber), "=b"(clobber)
+ : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+ : "memory", "%edx", "%ecx", "%edi", "%esi");
+}
+
+int run_guest(struct lguest *lg, unsigned long __user *user)
+{
+ while (!lg->dead) {
+ unsigned int cr2 = 0; /* Damn gcc */
+
+ /* Hypercalls first: we might have been out to userspace */
+ do_hypercalls(lg);
+ if (lg->dma_is_pending) {
+ if (put_user(lg->pending_dma, user) ||
+ put_user(lg->pending_key, user+1))
+ return -EFAULT;
+ return sizeof(unsigned long)*2;
+ }
+
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ /* If Waker set break_out, return to Launcher. */
+ if (lg->break_out)
+ return -EAGAIN;
+
+ maybe_do_interrupt(lg);
+
+ try_to_freeze();
+
+ if (lg->dead)
+ break;
+
+ if (lg->halted) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ continue;
+ }
+
+ local_irq_disable();
+
+ /* Even if *we* don't want FPU trap, guest might... */
+ if (lg->ts)
+ set_ts();
+
+ /* Don't let Guest do SYSENTER: we can't handle it. */
+ if (boot_cpu_has(X86_FEATURE_SEP))
+ wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+
+ run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
+
+ /* Save cr2 now if we page-faulted. */
+ if (lg->regs->trapnum == 14)
+ cr2 = read_cr2();
+ else if (lg->regs->trapnum == 7)
+ math_state_restore();
+
+ if (boot_cpu_has(X86_FEATURE_SEP))
+ wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+ local_irq_enable();
+
+ switch (lg->regs->trapnum) {
+ case 13: /* We've intercepted a GPF. */
+ if (lg->regs->errcode == 0) {
+ if (emulate_insn(lg))
+ continue;
+ }
+ break;
+ case 14: /* We've intercepted a page fault. */
+ if (demand_page(lg, cr2, lg->regs->errcode))
+ continue;
+
+ /* If lguest_data is NULL, this won't hurt. */
+ if (put_user(cr2, &lg->lguest_data->cr2))
+ kill_guest(lg, "Writing cr2");
+ break;
+ case 7: /* We've intercepted a Device Not Available fault. */
+ /* If they don't want to know, just absorb it. */
+ if (!lg->ts)
+ continue;
+ break;
+ case 32 ... 255: /* Real interrupt, fall thru */
+ cond_resched();
+ case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
+ continue;
+ }
+
+ if (deliver_trap(lg, lg->regs->trapnum))
+ continue;
+
+ kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
+ lg->regs->trapnum, lg->regs->eip,
+ lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
+ }
+ return -ENOENT;
+}
+
+int find_free_guest(void)
+{
+ unsigned int i;
+ for (i = 0; i < MAX_LGUEST_GUESTS; i++)
+ if (!lguests[i].tsk)
+ return i;
+ return -1;
+}
+
+static void adjust_pge(void *on)
+{
+ if (on)
+ write_cr4(read_cr4() | X86_CR4_PGE);
+ else
+ write_cr4(read_cr4() & ~X86_CR4_PGE);
+}
+
+static int __init init(void)
+{
+ int err;
+
+ if (paravirt_enabled()) {
+ printk("lguest is afraid of %s\n", paravirt_ops.name);
+ return -EPERM;
+ }
+
+ err = map_switcher();
+ if (err)
+ return err;
+
+ err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
+ if (err) {
+ unmap_switcher();
+ return err;
+ }
+ lguest_io_init();
+
+ err = lguest_device_init();
+ if (err) {
+ free_pagetables();
+ unmap_switcher();
+ return err;
+ }
+ lock_cpu_hotplug();
+ if (cpu_has_pge) { /* We have a broader idea of "global". */
+ cpu_had_pge = 1;
+ on_each_cpu(adjust_pge, (void *)0, 0, 1);
+ clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ }
+ unlock_cpu_hotplug();
+ return 0;
+}
+
+static void __exit fini(void)
+{
+ lguest_device_remove();
+ free_pagetables();
+ unmap_switcher();
+ lock_cpu_hotplug();
+ if (cpu_had_pge) {
+ set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+ on_each_cpu(adjust_pge, (void *)1, 0, 1);
+ }
+ unlock_cpu_hotplug();
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
new file mode 100644
index 000000000000..ea52ca451f74
--- /dev/null
+++ b/drivers/lguest/hypercalls.c
@@ -0,0 +1,192 @@
+/* Actual hypercalls, which allow guests to actually do something.
+ Copyright (C) 2006 Rusty Russell 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 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/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <irq_vectors.h>
+#include "lg.h"
+
+static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
+{
+ switch (regs->eax) {
+ case LHCALL_FLUSH_ASYNC:
+ break;
+ case LHCALL_LGUEST_INIT:
+ kill_guest(lg, "already have lguest_data");
+ break;
+ case LHCALL_CRASH: {
+ char msg[128];
+ lgread(lg, msg, regs->edx, sizeof(msg));
+ msg[sizeof(msg)-1] = '\0';
+ kill_guest(lg, "CRASH: %s", msg);
+ break;
+ }
+ case LHCALL_FLUSH_TLB:
+ if (regs->edx)
+ guest_pagetable_clear_all(lg);
+ else
+ guest_pagetable_flush_user(lg);
+ break;
+ case LHCALL_GET_WALLCLOCK: {
+ struct timespec ts;
+ ktime_get_real_ts(&ts);
+ regs->eax = ts.tv_sec;
+ break;
+ }
+ case LHCALL_BIND_DMA:
+ regs->eax = bind_dma(lg, regs->edx, regs->ebx,
+ regs->ecx >> 8, regs->ecx & 0xFF);
+ break;
+ case LHCALL_SEND_DMA:
+ send_dma(lg, regs->edx, regs->ebx);
+ break;
+ case LHCALL_LOAD_GDT:
+ load_guest_gdt(lg, regs->edx, regs->ebx);
+ break;
+ case LHCALL_LOAD_IDT_ENTRY:
+ load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx);
+ break;
+ case LHCALL_NEW_PGTABLE:
+ guest_new_pagetable(lg, regs->edx);
+ break;
+ case LHCALL_SET_STACK:
+ guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx);
+ break;
+ case LHCALL_SET_PTE:
+ guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx));
+ break;
+ case LHCALL_SET_PMD:
+ guest_set_pmd(lg, regs->edx, regs->ebx);
+ break;
+ case LHCALL_LOAD_TLS:
+ guest_load_tls(lg, regs->edx);
+ break;
+ case LHCALL_SET_CLOCKEVENT:
+ guest_set_clockevent(lg, regs->edx);
+ break;
+ case LHCALL_TS:
+ lg->ts = regs->edx;
+ break;
+ case LHCALL_HALT:
+ lg->halted = 1;
+ break;
+ default:
+ kill_guest(lg, "Bad hypercall %li\n", regs->eax);
+ }
+}
+
+/* We always do queued calls before actual hypercall. */
+static void do_async_hcalls(struct lguest *lg)
+{
+ unsigned int i;
+ u8 st[LHCALL_RING_SIZE];
+
+ if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(st); i++) {
+ struct lguest_regs regs;
+ unsigned int n = lg->next_hcall;
+
+ if (st[n] == 0xFF)
+ break;
+
+ if (++lg->next_hcall == LHCALL_RING_SIZE)
+ lg->next_hcall = 0;
+
+ if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax)
+ || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx)
+ || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx)
+ || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) {
+ kill_guest(lg, "Fetching async hypercalls");
+ break;
+ }
+
+ do_hcall(lg, &regs);
+ if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
+ kill_guest(lg, "Writing result for async hypercall");
+ break;
+ }
+
+ if (lg->dma_is_pending)
+ break;
+ }
+}
+
+static void initialize(struct lguest *lg)
+{
+ u32 tsc_speed;
+
+ if (lg->regs->eax != LHCALL_LGUEST_INIT) {
+ kill_guest(lg, "hypercall %li before LGUEST_INIT",
+ lg->regs->eax);
+ return;
+ }
+
+ /* We only tell the guest to use the TSC if it's reliable. */
+ if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
+ tsc_speed = tsc_khz;
+ else
+ tsc_speed = 0;
+
+ lg->lguest_data = (struct lguest_data __user *)lg->regs->edx;
+ /* We check here so we can simply copy_to_user/from_user */
+ if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) {
+ kill_guest(lg, "bad guest page %p", lg->lguest_data);
+ return;
+ }
+ if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
+ || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)
+ /* We reserve the top pgd entry. */
+ || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
+ || put_user(tsc_speed, &lg->lguest_data->tsc_khz)
+ || put_user(lg->guestid, &lg->lguest_data->guestid))
+ kill_guest(lg, "bad guest page %p", lg->lguest_data);
+
+ /* This is the one case where the above accesses might have
+ * been the first write to a Guest page. This may have caused
+ * a copy-on-write fault, but the Guest might be referring to
+ * the old (read-only) page. */
+ guest_pagetable_clear_all(lg);
+}
+
+/* Even if we go out to userspace and come back, we don't want to do
+ * the hypercall again. */
+static void clear_hcall(struct lguest *lg)
+{
+ lg->regs->trapnum = 255;
+}
+
+void do_hypercalls(struct lguest *lg)
+{
+ if (unlikely(!lg->lguest_data)) {
+ if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+ initialize(lg);
+ clear_hcall(lg);
+ }
+ return;
+ }
+
+ do_async_hcalls(lg);
+ if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+ do_hcall(lg, lg->regs);
+ clear_hcall(lg);
+ }
+}
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
new file mode 100644
index 000000000000..bee029bb2c7b
--- /dev/null
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -0,0 +1,268 @@
+#include <linux/uaccess.h>
+#include "lg.h"
+
+static unsigned long idt_address(u32 lo, u32 hi)
+{
+ return (lo & 0x0000FFFF) | (hi & 0xFFFF0000);
+}
+
+static int idt_type(u32 lo, u32 hi)
+{
+ return (hi >> 8) & 0xF;
+}
+
+static int idt_present(u32 lo, u32 hi)
+{
+ return (hi & 0x8000);
+}
+
+static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
+{
+ *gstack -= 4;
+ lgwrite_u32(lg, *gstack, val);
+}
+
+static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
+{
+ unsigned long gstack;
+ u32 eflags, ss, irq_enable;
+
+ /* If they want a ring change, we use new stack and push old ss/esp */
+ if ((lg->regs->ss&0x3) != GUEST_PL) {
+ gstack = guest_pa(lg, lg->esp1);
+ ss = lg->ss1;
+ push_guest_stack(lg, &gstack, lg->regs->ss);
+ push_guest_stack(lg, &gstack, lg->regs->esp);
+ } else {
+ gstack = guest_pa(lg, lg->regs->esp);
+ ss = lg->regs->ss;
+ }
+
+ /* We use IF bit in eflags to indicate whether irqs were enabled
+ (it's always 1, since irqs are enabled when guest is running). */
+ eflags = lg->regs->eflags;
+ if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+ && !(irq_enable & X86_EFLAGS_IF))
+ eflags &= ~X86_EFLAGS_IF;
+
+ push_guest_stack(lg, &gstack, eflags);
+ push_guest_stack(lg, &gstack, lg->regs->cs);
+ push_guest_stack(lg, &gstack, lg->regs->eip);
+
+ if (has_err)
+ push_guest_stack(lg, &gstack, lg->regs->errcode);
+
+ /* Change the real stack so switcher returns to trap handler */
+ lg->regs->ss = ss;
+ lg->regs->esp = gstack + lg->page_offset;
+ lg->regs->cs = (__KERNEL_CS|GUEST_PL);
+ lg->regs->eip = idt_address(lo, hi);
+
+ /* Disable interrupts for an interrupt gate. */
+ if (idt_type(lo, hi) == 0xE)
+ if (put_user(0, &lg->lguest_data->irq_enabled))
+ kill_guest(lg, "Disabling interrupts");
+}
+
+void maybe_do_interrupt(struct lguest *lg)
+{
+ unsigned int irq;
+ DECLARE_BITMAP(blk, LGUEST_IRQS);
+ struct desc_struct *idt;
+
+ if (!lg->lguest_data)
+ return;
+
+ /* Mask out any interrupts they have blocked. */
+ if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts,
+ sizeof(blk)))
+ return;
+
+ bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS);
+
+ irq = find_first_bit(blk, LGUEST_IRQS);
+ if (irq >= LGUEST_IRQS)
+ return;
+
+ if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end)
+ return;
+
+ /* If they're halted, we re-enable interrupts. */
+ if (lg->halted) {
+ /* Re-enable interrupts. */
+ if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
+ kill_guest(lg, "Re-enabling interrupts");
+ lg->halted = 0;
+ } else {
+ /* Maybe they have interrupts disabled? */
+ u32 irq_enabled;
+ if (get_user(irq_enabled, &lg->lguest_data->irq_enabled))
+ irq_enabled = 0;
+ if (!irq_enabled)
+ return;
+ }
+
+ idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+ if (idt_present(idt->a, idt->b)) {
+ clear_bit(irq, lg->irqs_pending);
+ set_guest_interrupt(lg, idt->a, idt->b, 0);
+ }
+}
+
+static int has_err(unsigned int trap)
+{
+ return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
+}
+
+int deliver_trap(struct lguest *lg, unsigned int num)
+{
+ u32 lo = lg->idt[num].a, hi = lg->idt[num].b;
+
+ if (!idt_present(lo, hi))
+ return 0;
+ set_guest_interrupt(lg, lo, hi, has_err(num));
+ return 1;
+}
+
+static int direct_trap(const struct lguest *lg,
+ const struct desc_struct *trap,
+ unsigned int num)
+{
+ /* Hardware interrupts don't go to guest (except syscall). */
+ if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR)
+ return 0;
+
+ /* We intercept page fault (demand shadow paging & cr2 saving)
+ protection fault (in/out emulation) and device not
+ available (TS handling), and hypercall */
+ if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
+ return 0;
+
+ /* Interrupt gates (0xE) or not present (0x0) can't go direct. */
+ return idt_type(trap->a, trap->b) == 0xF;
+}
+
+void pin_stack_pages(struct lguest *lg)
+{
+ unsigned int i;
+
+ for (i = 0; i < lg->stack_pages; i++)
+ pin_page(lg, lg->esp1 - i * PAGE_SIZE);
+}
+
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
+{
+ /* You cannot have a stack segment with priv level 0. */
+ if ((seg & 0x3) != GUEST_PL)
+ kill_guest(lg, "bad stack segment %i", seg);
+ if (pages > 2)
+ kill_guest(lg, "bad stack pages %u", pages);
+ lg->ss1 = seg;
+ lg->esp1 = esp;
+ lg->stack_pages = pages;
+ pin_stack_pages(lg);
+}
+
+/* Set up trap in IDT. */
+static void set_trap(struct lguest *lg, struct desc_struct *trap,
+ unsigned int num, u32 lo, u32 hi)
+{
+ u8 type = idt_type(lo, hi);
+
+ if (!idt_present(lo, hi)) {
+ trap->a = trap->b = 0;
+ return;
+ }
+
+ if (type != 0xE && type != 0xF)
+ kill_guest(lg, "bad IDT type %i", type);
+
+ trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF);
+ trap->b = (hi&0xFFFFEF00);
+}
+
+void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
+{
+ /* Guest never handles: NMI, doublefault, hypercall, spurious irq. */
+ if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY)
+ return;
+
+ lg->changed |= CHANGED_IDT;
+ if (num < ARRAY_SIZE(lg->idt))
+ set_trap(lg, &lg->idt[num], num, lo, hi);
+ else if (num == SYSCALL_VECTOR)
+ set_trap(lg, &lg->syscall_idt, num, lo, hi);
+}
+
+static void default_idt_entry(struct desc_struct *idt,
+ int trap,
+ const unsigned long handler)
+{
+ u32 flags = 0x8e00;
+
+ /* They can't "int" into any of them except hypercall. */
+ if (trap == LGUEST_TRAP_ENTRY)
+ flags |= (GUEST_PL << 13);
+
+ idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF);
+ idt->b = (handler&0xFFFF0000) | flags;
+}
+
+void setup_default_idt_entries(struct lguest_ro_state *state,
+ const unsigned long *def)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++)
+ default_idt_entry(&state->guest_idt[i], i, def[i]);
+}
+
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+ const unsigned long *def)
+{
+ unsigned int i;
+
+ /* All hardware interrupts are same whatever the guest: only the
+ * traps might be different. */
+ for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) {
+ if (direct_trap(lg, &lg->idt[i], i))
+ idt[i] = lg->idt[i];
+ else
+ default_idt_entry(&idt[i], i, def[i]);
+ }
+ i = SYSCALL_VECTOR;
+ if (direct_trap(lg, &lg->syscall_idt, i))
+ idt[i] = lg->syscall_idt;
+ else
+ default_idt_entry(&idt[i], i, def[i]);
+}
+
+void guest_set_clockevent(struct lguest *lg, unsigned long delta)
+{
+ ktime_t expires;
+
+ if (unlikely(delta == 0)) {
+ /* Clock event device is shutting down. */
+ hrtimer_cancel(&lg->hrt);
+ return;
+ }
+
+ expires = ktime_add_ns(ktime_get_real(), delta);
+ hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
+}
+
+static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
+{
+ struct lguest *lg = container_of(timer, struct lguest, hrt);
+
+ set_bit(0, lg->irqs_pending);
+ if (lg->halted)
+ wake_up_process(lg->tsk);
+ return HRTIMER_NORESTART;
+}
+
+void init_clockdev(struct lguest *lg)
+{
+ hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ lg->hrt.function = clockdev_fn;
+}
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
new file mode 100644
index 000000000000..c8eb79266991
--- /dev/null
+++ b/drivers/lguest/io.c
@@ -0,0 +1,399 @@
+/* Simple I/O model for guests, based on shared memory.
+ * Copyright (C) 2006 Rusty Russell 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 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/types.h>
+#include <linux/futex.h>
+#include <linux/jhash.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/uaccess.h>
+#include "lg.h"
+
+static struct list_head dma_hash[61];
+
+void lguest_io_init(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(dma_hash); i++)
+ INIT_LIST_HEAD(&dma_hash[i]);
+}
+
+/* FIXME: allow multi-page lengths. */
+static int check_dma_list(struct lguest *lg, const struct lguest_dma *dma)
+{
+ unsigned int i;
+
+ for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+ if (!dma->len[i])
+ return 1;
+ if (!lguest_address_ok(lg, dma->addr[i], dma->len[i]))
+ goto kill;
+ if (dma->len[i] > PAGE_SIZE)
+ goto kill;
+ /* We could do over a page, but is it worth it? */
+ if ((dma->addr[i] % PAGE_SIZE) + dma->len[i] > PAGE_SIZE)
+ goto kill;
+ }
+ return 1;
+
+kill:
+ kill_guest(lg, "bad DMA entry: %u@%#lx", dma->len[i], dma->addr[i]);
+ return 0;
+}
+
+static unsigned int hash(const union futex_key *key)
+{
+ return jhash2((u32*)&key->both.word,
+ (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
+ key->both.offset)
+ % ARRAY_SIZE(dma_hash);
+}
+
+static inline int key_eq(const union futex_key *a, const union futex_key *b)
+{
+ return (a->both.word == b->both.word
+ && a->both.ptr == b->both.ptr
+ && a->both.offset == b->both.offset);
+}
+
+/* Must hold read lock on dmainfo owner's current->mm->mmap_sem */
+static void unlink_dma(struct lguest_dma_info *dmainfo)
+{
+ BUG_ON(!mutex_is_locked(&lguest_lock));
+ dmainfo->interrupt = 0;
+ list_del(&dmainfo->list);
+ drop_futex_key_refs(&dmainfo->key);
+}
+
+static int unbind_dma(struct lguest *lg,
+ const union futex_key *key,
+ unsigned long dmas)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < LGUEST_MAX_DMA; i++) {
+ if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) {
+ unlink_dma(&lg->dma[i]);
+ ret = 1;
+ break;
+ }
+ }
+ return ret;
+}
+
+int bind_dma(struct lguest *lg,
+ unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt)
+{
+ unsigned int i;
+ int ret = 0;
+ union futex_key key;
+ struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+ if (interrupt >= LGUEST_IRQS)
+ return 0;
+
+ mutex_lock(&lguest_lock);
+ down_read(fshared);
+ if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+ kill_guest(lg, "bad dma key %#lx", ukey);
+ goto unlock;
+ }
+ get_futex_key_refs(&key);
+
+ if (interrupt == 0)
+ ret = unbind_dma(lg, &key, dmas);
+ else {
+ for (i = 0; i < LGUEST_MAX_DMA; i++) {
+ if (lg->dma[i].interrupt)
+ continue;
+
+ lg->dma[i].dmas = dmas;
+ lg->dma[i].num_dmas = numdmas;
+ lg->dma[i].next_dma = 0;
+ lg->dma[i].key = key;
+ lg->dma[i].guestid = lg->guestid;
+ lg->dma[i].interrupt = interrupt;
+ list_add(&lg->dma[i].list, &dma_hash[hash(&key)]);
+ ret = 1;
+ goto unlock;
+ }
+ }
+ drop_futex_key_refs(&key);
+unlock:
+ up_read(fshared);
+ mutex_unlock(&lguest_lock);
+ return ret;
+}
+
+/* lgread from another guest */
+static int lgread_other(struct lguest *lg,
+ void *buf, u32 addr, unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) {
+ memset(buf, 0, bytes);
+ kill_guest(lg, "bad address in registered DMA struct");
+ return 0;
+ }
+ return 1;
+}
+
+/* lgwrite to another guest */
+static int lgwrite_other(struct lguest *lg, u32 addr,
+ const void *buf, unsigned bytes)
+{
+ if (!lguest_address_ok(lg, addr, bytes)
+ || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1)
+ != bytes)) {
+ kill_guest(lg, "bad address writing to registered DMA");
+ return 0;
+ }
+ return 1;
+}
+
+static u32 copy_data(struct lguest *srclg,
+ const struct lguest_dma *src,
+ const struct lguest_dma *dst,
+ struct page *pages[])
+{
+ unsigned int totlen, si, di, srcoff, dstoff;
+ void *maddr = NULL;
+
+ totlen = 0;
+ si = di = 0;
+ srcoff = dstoff = 0;
+ while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si]
+ && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) {
+ u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff);
+
+ if (!maddr)
+ maddr = kmap(pages[di]);
+
+ /* FIXME: This is not completely portable, since
+ archs do different things for copy_to_user_page. */
+ if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
+ (void __user *)src->addr[si], len) != 0) {
+ kill_guest(srclg, "bad address in sending DMA");
+ totlen = 0;
+ break;
+ }
+
+ totlen += len;
+ srcoff += len;
+ dstoff += len;
+ if (srcoff == src->len[si]) {
+ si++;
+ srcoff = 0;
+ }
+ if (dstoff == dst->len[di]) {
+ kunmap(pages[di]);
+ maddr = NULL;
+ di++;
+ dstoff = 0;
+ }
+ }
+
+ if (maddr)
+ kunmap(pages[di]);
+
+ return totlen;
+}
+
+/* Src is us, ie. current. */
+static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
+ struct lguest *dstlg, const struct lguest_dma *dst)
+{
+ int i;
+ u32 ret;
+ struct page *pages[LGUEST_MAX_DMA_SECTIONS];
+
+ if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src))
+ return 0;
+
+ /* First get the destination pages */
+ for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+ if (dst->len[i] == 0)
+ break;
+ if (get_user_pages(dstlg->tsk, dstlg->mm,
+ dst->addr[i], 1, 1, 1, pages+i, NULL)
+ != 1) {
+ kill_guest(dstlg, "Error mapping DMA pages");
+ ret = 0;
+ goto drop_pages;
+ }
+ }
+
+ /* Now copy until we run out of src or dst. */
+ ret = copy_data(srclg, src, dst, pages);
+
+drop_pages:
+ while (--i >= 0)
+ put_page(pages[i]);
+ return ret;
+}
+
+static int dma_transfer(struct lguest *srclg,
+ unsigned long udma,
+ struct lguest_dma_info *dst)
+{
+ struct lguest_dma dst_dma, src_dma;
+ struct lguest *dstlg;
+ u32 i, dma = 0;
+
+ dstlg = &lguests[dst->guestid];
+ /* Get our dma list. */
+ lgread(srclg, &src_dma, udma, sizeof(src_dma));
+
+ /* We can't deadlock against them dmaing to us, because this
+ * is all under the lguest_lock. */
+ down_read(&dstlg->mm->mmap_sem);
+
+ for (i = 0; i < dst->num_dmas; i++) {
+ dma = (dst->next_dma + i) % dst->num_dmas;
+ if (!lgread_other(dstlg, &dst_dma,
+ dst->dmas + dma * sizeof(struct lguest_dma),
+ sizeof(dst_dma))) {
+ goto fail;
+ }
+ if (!dst_dma.used_len)
+ break;
+ }
+ if (i != dst->num_dmas) {
+ unsigned long used_lenp;
+ unsigned int ret;
+
+ ret = do_dma(srclg, &src_dma, dstlg, &dst_dma);
+ /* Put used length in src. */
+ lgwrite_u32(srclg,
+ udma+offsetof(struct lguest_dma, used_len), ret);
+ if (ret == 0 && src_dma.len[0] != 0)
+ goto fail;
+
+ /* Make sure destination sees contents before length. */
+ wmb();
+ used_lenp = dst->dmas
+ + dma * sizeof(struct lguest_dma)
+ + offsetof(struct lguest_dma, used_len);
+ lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret));
+ dst->next_dma++;
+ }
+ up_read(&dstlg->mm->mmap_sem);
+
+ /* Do this last so dst doesn't simply sleep on lock. */
+ set_bit(dst->interrupt, dstlg->irqs_pending);
+ wake_up_process(dstlg->tsk);
+ return i == dst->num_dmas;
+
+fail:
+ up_read(&dstlg->mm->mmap_sem);
+ return 0;
+}
+
+void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
+{
+ union futex_key key;
+ int empty = 0;
+ struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+again:
+ mutex_lock(&lguest_lock);
+ down_read(fshared);
+ if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+ kill_guest(lg, "bad sending DMA key");
+ goto unlock;
+ }
+ /* Shared mapping? Look for other guests... */
+ if (key.shared.offset & 1) {
+ struct lguest_dma_info *i;
+ list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+ if (i->guestid == lg->guestid)
+ continue;
+ if (!key_eq(&key, &i->key))
+ continue;
+
+ empty += dma_transfer(lg, udma, i);
+ break;
+ }
+ if (empty == 1) {
+ /* Give any recipients one chance to restock. */
+ up_read(&current->mm->mmap_sem);
+ mutex_unlock(&lguest_lock);
+ empty++;
+ goto again;
+ }
+ } else {
+ /* Private mapping: tell our userspace. */
+ lg->dma_is_pending = 1;
+ lg->pending_dma = udma;
+ lg->pending_key = ukey;
+ }
+unlock:
+ up_read(fshared);
+ mutex_unlock(&lguest_lock);
+}
+
+void release_all_dma(struct lguest *lg)
+{
+ unsigned int i;
+
+ BUG_ON(!mutex_is_locked(&lguest_lock));
+
+ down_read(&lg->mm->mmap_sem);
+ for (i = 0; i < LGUEST_MAX_DMA; i++) {
+ if (lg->dma[i].interrupt)
+ unlink_dma(&lg->dma[i]);
+ }
+ up_read(&lg->mm->mmap_sem);
+}
+
+/* Userspace wants a dma buffer from this guest. */
+unsigned long get_dma_buffer(struct lguest *lg,
+ unsigned long ukey, unsigned long *interrupt)
+{
+ unsigned long ret = 0;
+ union futex_key key;
+ struct lguest_dma_info *i;
+ struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+ mutex_lock(&lguest_lock);
+ down_read(fshared);
+ if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+ kill_guest(lg, "bad registered DMA buffer");
+ goto unlock;
+ }
+ list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+ if (key_eq(&key, &i->key) && i->guestid == lg->guestid) {
+ unsigned int j;
+ for (j = 0; j < i->num_dmas; j++) {
+ struct lguest_dma dma;
+
+ ret = i->dmas + j * sizeof(struct lguest_dma);
+ lgread(lg, &dma, ret, sizeof(dma));
+ if (dma.used_len == 0)
+ break;
+ }
+ *interrupt = i->interrupt;
+ break;
+ }
+ }
+unlock:
+ up_read(fshared);
+ mutex_unlock(&lguest_lock);
+ return ret;
+}
+
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
new file mode 100644
index 000000000000..3e2ddfbc816e
--- /dev/null
+++ b/drivers/lguest/lg.h
@@ -0,0 +1,261 @@
+#ifndef _LGUEST_H
+#define _LGUEST_H
+
+#include <asm/desc.h>
+
+#define GDT_ENTRY_LGUEST_CS 10
+#define GDT_ENTRY_LGUEST_DS 11
+#define LGUEST_CS (GDT_ENTRY_LGUEST_CS * 8)
+#define LGUEST_DS (GDT_ENTRY_LGUEST_DS * 8)
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/stringify.h>
+#include <linux/binfmts.h>
+#include <linux/futex.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <asm/semaphore.h>
+#include "irq_vectors.h"
+
+#define GUEST_PL 1
+
+struct lguest_regs
+{
+ /* Manually saved part. */
+ unsigned long ebx, ecx, edx;
+ unsigned long esi, edi, ebp;
+ unsigned long gs;
+ unsigned long eax;
+ unsigned long fs, ds, es;
+ unsigned long trapnum, errcode;
+ /* Trap pushed part */
+ unsigned long eip;
+ unsigned long cs;
+ unsigned long eflags;
+ unsigned long esp;
+ unsigned long ss;
+};
+
+void free_pagetables(void);
+int init_pagetables(struct page **switcher_page, unsigned int pages);
+
+/* Full 4G segment descriptors, suitable for CS and DS. */
+#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
+#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
+
+struct lguest_dma_info
+{
+ struct list_head list;
+ union futex_key key;
+ unsigned long dmas;
+ u16 next_dma;
+ u16 num_dmas;
+ u16 guestid;
+ u8 interrupt; /* 0 when not registered */
+};
+
+/* We have separate types for the guest's ptes & pgds and the shadow ptes &
+ * pgds. Since this host might use three-level pagetables and the guest and
+ * shadow pagetables don't, we can't use the normal pte_t/pgd_t. */
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} spgd_t;
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} spte_t;
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} gpgd_t;
+typedef union {
+ struct { unsigned flags:12, pfn:20; };
+ struct { unsigned long val; } raw;
+} gpte_t;
+#define mkgpte(_val) ((gpte_t){.raw.val = _val})
+#define mkgpgd(_val) ((gpgd_t){.raw.val = _val})
+
+struct pgdir
+{
+ unsigned long cr3;
+ spgd_t *pgdir;
+};
+
+/* This is a guest-specific page (mapped ro) into the guest. */
+struct lguest_ro_state
+{
+ /* Host information we need to restore when we switch back. */
+ u32 host_cr3;
+ struct Xgt_desc_struct host_idt_desc;
+ struct Xgt_desc_struct host_gdt_desc;
+ u32 host_sp;
+
+ /* Fields which are used when guest is running. */
+ struct Xgt_desc_struct guest_idt_desc;
+ struct Xgt_desc_struct guest_gdt_desc;
+ struct i386_hw_tss guest_tss;
+ struct desc_struct guest_idt[IDT_ENTRIES];
+ struct desc_struct guest_gdt[GDT_ENTRIES];
+};
+
+/* We have two pages shared with guests, per cpu. */
+struct lguest_pages
+{
+ /* This is the stack page mapped rw in guest */
+ char spare[PAGE_SIZE - sizeof(struct lguest_regs)];
+ struct lguest_regs regs;
+
+ /* This is the host state & guest descriptor page, ro in guest */
+ struct lguest_ro_state state;
+} __attribute__((aligned(PAGE_SIZE)));
+
+#define CHANGED_IDT 1
+#define CHANGED_GDT 2
+#define CHANGED_GDT_TLS 4 /* Actually a subset of CHANGED_GDT */
+#define CHANGED_ALL 3
+
+/* The private info the thread maintains about the guest. */
+struct lguest
+{
+ /* At end of a page shared mapped over lguest_pages in guest. */
+ unsigned long regs_page;
+ struct lguest_regs *regs;
+ struct lguest_data __user *lguest_data;
+ struct task_struct *tsk;
+ struct mm_struct *mm; /* == tsk->mm, but that becomes NULL on exit */
+ u16 guestid;
+ u32 pfn_limit;
+ u32 page_offset;
+ u32 cr2;
+ int halted;
+ int ts;
+ u32 next_hcall;
+ u32 esp1;
+ u8 ss1;
+
+ /* Do we need to stop what we're doing and return to userspace? */
+ int break_out;
+ wait_queue_head_t break_wq;
+
+ /* Bitmap of what has changed: see CHANGED_* above. */
+ int changed;
+ struct lguest_pages *last_pages;
+
+ /* We keep a small number of these. */
+ u32 pgdidx;
+ struct pgdir pgdirs[4];
+
+ /* Cached wakeup: we hold a reference to this task. */
+ struct task_struct *wake;
+
+ unsigned long noirq_start, noirq_end;
+ int dma_is_pending;
+ unsigned long pending_dma; /* struct lguest_dma */
+ unsigned long pending_key; /* address they're sending to */
+
+ unsigned int stack_pages;
+ u32 tsc_khz;
+
+ struct lguest_dma_info dma[LGUEST_MAX_DMA];
+
+ /* Dead? */
+ const char *dead;
+
+ /* The GDT entries copied into lguest_ro_state when running. */
+ struct desc_struct gdt[GDT_ENTRIES];
+
+ /* The IDT entries: some copied into lguest_ro_state when running. */
+ struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
+ struct desc_struct syscall_idt;
+
+ /* Virtual clock device */
+ struct hrtimer hrt;
+
+ /* Pending virtual interrupts */
+ DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
+};
+
+extern struct lguest lguests[];
+extern struct mutex lguest_lock;
+
+/* core.c: */
+u32 lgread_u32(struct lguest *lg, unsigned long addr);
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
+void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
+void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
+int find_free_guest(void);
+int lguest_address_ok(const struct lguest *lg,
+ unsigned long addr, unsigned long len);
+int run_guest(struct lguest *lg, unsigned long __user *user);
+
+
+/* interrupts_and_traps.c: */
+void maybe_do_interrupt(struct lguest *lg);
+int deliver_trap(struct lguest *lg, unsigned int num);
+void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi);
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages);
+void pin_stack_pages(struct lguest *lg);
+void setup_default_idt_entries(struct lguest_ro_state *state,
+ const unsigned long *def);
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+ const unsigned long *def);
+void guest_set_clockevent(struct lguest *lg, unsigned long delta);
+void init_clockdev(struct lguest *lg);
+
+/* segments.c: */
+void setup_default_gdt_entries(struct lguest_ro_state *state);
+void setup_guest_gdt(struct lguest *lg);
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num);
+void guest_load_tls(struct lguest *lg, unsigned long tls_array);
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt);
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
+
+/* page_tables.c: */
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
+void free_guest_pagetable(struct lguest *lg);
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable);
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 i);
+void guest_pagetable_clear_all(struct lguest *lg);
+void guest_pagetable_flush_user(struct lguest *lg);
+void guest_set_pte(struct lguest *lg, unsigned long cr3,
+ unsigned long vaddr, gpte_t val);
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
+int demand_page(struct lguest *info, unsigned long cr2, int errcode);
+void pin_page(struct lguest *lg, unsigned long vaddr);
+
+/* lguest_user.c: */
+int lguest_device_init(void);
+void lguest_device_remove(void);
+
+/* io.c: */
+void lguest_io_init(void);
+int bind_dma(struct lguest *lg,
+ unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt);
+void send_dma(struct lguest *info, unsigned long key, unsigned long udma);
+void release_all_dma(struct lguest *lg);
+unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
+ unsigned long *interrupt);
+
+/* hypercalls.c: */
+void do_hypercalls(struct lguest *lg);
+
+#define kill_guest(lg, fmt...) \
+do { \
+ if (!(lg)->dead) { \
+ (lg)->dead = kasprintf(GFP_ATOMIC, fmt); \
+ if (!(lg)->dead) \
+ (lg)->dead = ERR_PTR(-ENOMEM); \
+ } \
+} while(0)
+
+static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
+{
+ return vaddr - lg->page_offset;
+}
+#endif /* __ASSEMBLY__ */
+#endif /* _LGUEST_H */
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c
new file mode 100644
index 000000000000..18dade06d4a9
--- /dev/null
+++ b/drivers/lguest/lguest.c
@@ -0,0 +1,630 @@
+/*
+ * Lguest specific paravirt-ops implementation
+ *
+ * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> 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 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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/start_kernel.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/lguest_bus.h>
+#include <asm/paravirt.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+#include <asm/setup.h>
+#include <asm/e820.h>
+#include <asm/mce.h>
+#include <asm/io.h>
+
+/* Declarations for definitions in lguest_guest.S */
+extern char lguest_noirq_start[], lguest_noirq_end[];
+extern const char lgstart_cli[], lgend_cli[];
+extern const char lgstart_sti[], lgend_sti[];
+extern const char lgstart_popf[], lgend_popf[];
+extern const char lgstart_pushf[], lgend_pushf[];
+extern const char lgstart_iret[], lgend_iret[];
+extern void lguest_iret(void);
+
+struct lguest_data lguest_data = {
+ .hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
+ .noirq_start = (u32)lguest_noirq_start,
+ .noirq_end = (u32)lguest_noirq_end,
+ .blocked_interrupts = { 1 }, /* Block timer interrupts */
+};
+struct lguest_device_desc *lguest_devices;
+static cycle_t clock_base;
+
+static enum paravirt_lazy_mode lazy_mode;
+static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
+{
+ if (mode == PARAVIRT_LAZY_FLUSH) {
+ if (unlikely(lazy_mode != PARAVIRT_LAZY_NONE))
+ hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+ } else {
+ lazy_mode = mode;
+ if (mode == PARAVIRT_LAZY_NONE)
+ hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+ }
+}
+
+static void lazy_hcall(unsigned long call,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3)
+{
+ if (lazy_mode == PARAVIRT_LAZY_NONE)
+ hcall(call, arg1, arg2, arg3);
+ else
+ async_hcall(call, arg1, arg2, arg3);
+}
+
+void async_hcall(unsigned long call,
+ unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+ /* Note: This code assumes we're uniprocessor. */
+ static unsigned int next_call;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (lguest_data.hcall_status[next_call] != 0xFF) {
+ /* Table full, so do normal hcall which will flush table. */
+ hcall(call, arg1, arg2, arg3);
+ } else {
+ lguest_data.hcalls[next_call].eax = call;
+ lguest_data.hcalls[next_call].edx = arg1;
+ lguest_data.hcalls[next_call].ebx = arg2;
+ lguest_data.hcalls[next_call].ecx = arg3;
+ /* Make sure host sees arguments before "valid" flag. */
+ wmb();
+ lguest_data.hcall_status[next_call] = 0;
+ if (++next_call == LHCALL_RING_SIZE)
+ next_call = 0;
+ }
+ local_irq_restore(flags);
+}
+
+void lguest_send_dma(unsigned long key, struct lguest_dma *dma)
+{
+ dma->used_len = 0;
+ hcall(LHCALL_SEND_DMA, key, __pa(dma), 0);
+}
+
+int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
+ unsigned int num, u8 irq)
+{
+ if (!hcall(LHCALL_BIND_DMA, key, __pa(dmas), (num << 8) | irq))
+ return -ENOMEM;
+ return 0;
+}
+
+void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas)
+{
+ hcall(LHCALL_BIND_DMA, key, __pa(dmas), 0);
+}
+
+/* For guests, device memory can be used as normal memory, so we cast away the
+ * __iomem to quieten sparse. */
+void *lguest_map(unsigned long phys_addr, unsigned long pages)
+{
+ return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+}
+
+void lguest_unmap(void *addr)
+{
+ iounmap((__force void __iomem *)addr);
+}
+
+static unsigned long save_fl(void)
+{
+ return lguest_data.irq_enabled;
+}
+
+static void restore_fl(unsigned long flags)
+{
+ /* FIXME: Check if interrupt pending... */
+ lguest_data.irq_enabled = flags;
+}
+
+static void irq_disable(void)
+{
+ lguest_data.irq_enabled = 0;
+}
+
+static void irq_enable(void)
+{
+ /* FIXME: Check if interrupt pending... */
+ lguest_data.irq_enabled = X86_EFLAGS_IF;
+}
+
+static void lguest_write_idt_entry(struct desc_struct *dt,
+ int entrynum, u32 low, u32 high)
+{
+ write_dt_entry(dt, entrynum, low, high);
+ hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high);
+}
+
+static void lguest_load_idt(const struct Xgt_desc_struct *desc)
+{
+ unsigned int i;
+ struct desc_struct *idt = (void *)desc->address;
+
+ for (i = 0; i < (desc->size+1)/8; i++)
+ hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
+}
+
+static void lguest_load_gdt(const struct Xgt_desc_struct *desc)
+{
+ BUG_ON((desc->size+1)/8 != GDT_ENTRIES);
+ hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0);
+}
+
+static void lguest_write_gdt_entry(struct desc_struct *dt,
+ int entrynum, u32 low, u32 high)
+{
+ write_dt_entry(dt, entrynum, low, high);
+ hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0);
+}
+
+static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+ lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0);
+}
+
+static void lguest_set_ldt(const void *addr, unsigned entries)
+{
+}
+
+static void lguest_load_tr_desc(void)
+{
+}
+
+static void lguest_cpuid(unsigned int *eax, unsigned int *ebx,
+ unsigned int *ecx, unsigned int *edx)
+{
+ int function = *eax;
+
+ native_cpuid(eax, ebx, ecx, edx);
+ switch (function) {
+ case 1: /* Basic feature request. */
+ /* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
+ *ecx &= 0x00002201;
+ /* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, FPU. */
+ *edx &= 0x07808101;
+ /* Host wants to know when we flush kernel pages: set PGE. */
+ *edx |= 0x00002000;
+ break;
+ case 0x80000000:
+ /* Futureproof this a little: if they ask how much extended
+ * processor information, limit it to known fields. */
+ if (*eax > 0x80000008)
+ *eax = 0x80000008;
+ break;
+ }
+}
+
+static unsigned long current_cr0, current_cr3;
+static void lguest_write_cr0(unsigned long val)
+{
+ lazy_hcall(LHCALL_TS, val & 8, 0, 0);
+ current_cr0 = val;
+}
+
+static unsigned long lguest_read_cr0(void)
+{
+ return current_cr0;
+}
+
+static void lguest_clts(void)
+{
+ lazy_hcall(LHCALL_TS, 0, 0, 0);
+ current_cr0 &= ~8U;
+}
+
+static unsigned long lguest_read_cr2(void)
+{
+ return lguest_data.cr2;
+}
+
+static void lguest_write_cr3(unsigned long cr3)
+{
+ lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0);
+ current_cr3 = cr3;
+}
+
+static unsigned long lguest_read_cr3(void)
+{
+ return current_cr3;
+}
+
+/* Used to enable/disable PGE, but we don't care. */
+static unsigned long lguest_read_cr4(void)
+{
+ return 0;
+}
+
+static void lguest_write_cr4(unsigned long val)
+{
+}
+
+static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ *ptep = pteval;
+ lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low);
+}
+
+/* We only support two-level pagetables at the moment. */
+static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+ *pmdp = pmdval;
+ lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
+ (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+}
+
+/* FIXME: Eliminate all callers of this. */
+static void lguest_set_pte(pte_t *ptep, pte_t pteval)
+{
+ *ptep = pteval;
+ /* Don't bother with hypercall before initial setup. */
+ if (current_cr3)
+ lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+static void lguest_flush_tlb_single(unsigned long addr)
+{
+ /* Simply set it to zero, and it will fault back in. */
+ lazy_hcall(LHCALL_SET_PTE, current_cr3, addr, 0);
+}
+
+static void lguest_flush_tlb_user(void)
+{
+ lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0);
+}
+
+static void lguest_flush_tlb_kernel(void)
+{
+ lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+static void disable_lguest_irq(unsigned int irq)
+{
+ set_bit(irq, lguest_data.blocked_interrupts);
+}
+
+static void enable_lguest_irq(unsigned int irq)
+{
+ clear_bit(irq, lguest_data.blocked_interrupts);
+ /* FIXME: If it's pending? */
+}
+
+static struct irq_chip lguest_irq_controller = {
+ .name = "lguest",
+ .mask = disable_lguest_irq,
+ .mask_ack = disable_lguest_irq,
+ .unmask = enable_lguest_irq,
+};
+
+static void __init lguest_init_IRQ(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < LGUEST_IRQS; i++) {
+ int vector = FIRST_EXTERNAL_VECTOR + i;
+ if (vector != SYSCALL_VECTOR) {
+ set_intr_gate(vector, interrupt[i]);
+ set_irq_chip_and_handler(i, &lguest_irq_controller,
+ handle_level_irq);
+ }
+ }
+ irq_ctx_init(smp_processor_id());
+}
+
+static unsigned long lguest_get_wallclock(void)
+{
+ return hcall(LHCALL_GET_WALLCLOCK, 0, 0, 0);
+}
+
+static cycle_t lguest_clock_read(void)
+{
+ if (lguest_data.tsc_khz)
+ return native_read_tsc();
+ else
+ return jiffies;
+}
+
+/* This is what we tell the kernel is our clocksource. */
+static struct clocksource lguest_clock = {
+ .name = "lguest",
+ .rating = 400,
+ .read = lguest_clock_read,
+};
+
+static unsigned long long lguest_sched_clock(void)
+{
+ return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
+}
+
+/* We also need a "struct clock_event_device": Linux asks us to set it to go
+ * off some time in the future. Actually, James Morris figured all this out, I
+ * just applied the patch. */
+static int lguest_clockevent_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ if (delta < LG_CLOCK_MIN_DELTA) {
+ if (printk_ratelimit())
+ printk(KERN_DEBUG "%s: small delta %lu ns\n",
+ __FUNCTION__, delta);
+ return -ETIME;
+ }
+ hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
+ return 0;
+}
+
+static void lguest_clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /* A 0 argument shuts the clock down. */
+ hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* This is what we expect. */
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ BUG();
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+/* This describes our primitive timer chip. */
+static struct clock_event_device lguest_clockevent = {
+ .name = "lguest",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = lguest_clockevent_set_next_event,
+ .set_mode = lguest_clockevent_set_mode,
+ .rating = INT_MAX,
+ .mult = 1,
+ .shift = 0,
+ .min_delta_ns = LG_CLOCK_MIN_DELTA,
+ .max_delta_ns = LG_CLOCK_MAX_DELTA,
+};
+
+/* This is the Guest timer interrupt handler (hardware interrupt 0). We just
+ * call the clockevent infrastructure and it does whatever needs doing. */
+static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned long flags;
+
+ /* Don't interrupt us while this is running. */
+ local_irq_save(flags);
+ lguest_clockevent.event_handler(&lguest_clockevent);
+ local_irq_restore(flags);
+}
+
+static void lguest_time_init(void)
+{
+ set_irq_handler(0, lguest_time_irq);
+
+ /* We use the TSC if the Host tells us we can, otherwise a dumb
+ * jiffies-based clock. */
+ if (lguest_data.tsc_khz) {
+ lguest_clock.shift = 22;
+ lguest_clock.mult = clocksource_khz2mult(lguest_data.tsc_khz,
+ lguest_clock.shift);
+ lguest_clock.mask = CLOCKSOURCE_MASK(64);
+ lguest_clock.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+ } else {
+ /* To understand this, start at kernel/time/jiffies.c... */
+ lguest_clock.shift = 8;
+ lguest_clock.mult = (((u64)NSEC_PER_SEC<<8)/ACTHZ) << 8;
+ lguest_clock.mask = CLOCKSOURCE_MASK(32);
+ }
+ clock_base = lguest_clock_read();
+ clocksource_register(&lguest_clock);
+
+ /* We can't set cpumask in the initializer: damn C limitations! */
+ lguest_clockevent.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&lguest_clockevent);
+
+ enable_lguest_irq(0);
+}
+
+static void lguest_load_esp0(struct tss_struct *tss,
+ struct thread_struct *thread)
+{
+ lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->esp0,
+ THREAD_SIZE/PAGE_SIZE);
+}
+
+static void lguest_set_debugreg(int regno, unsigned long value)
+{
+ /* FIXME: Implement */
+}
+
+static void lguest_wbinvd(void)
+{
+}
+
+#ifdef CONFIG_X86_LOCAL_APIC
+static void lguest_apic_write(unsigned long reg, unsigned long v)
+{
+}
+
+static unsigned long lguest_apic_read(unsigned long reg)
+{
+ return 0;
+}
+#endif
+
+static void lguest_safe_halt(void)
+{
+ hcall(LHCALL_HALT, 0, 0, 0);
+}
+
+static void lguest_power_off(void)
+{
+ hcall(LHCALL_CRASH, __pa("Power down"), 0, 0);
+}
+
+static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
+{
+ hcall(LHCALL_CRASH, __pa(p), 0, 0);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block paniced = {
+ .notifier_call = lguest_panic
+};
+
+static __init char *lguest_memory_setup(void)
+{
+ /* We do this here because lockcheck barfs if before start_kernel */
+ atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+
+ add_memory_region(E820_MAP->addr, E820_MAP->size, E820_MAP->type);
+ return "LGUEST";
+}
+
+static const struct lguest_insns
+{
+ const char *start, *end;
+} lguest_insns[] = {
+ [PARAVIRT_PATCH(irq_disable)] = { lgstart_cli, lgend_cli },
+ [PARAVIRT_PATCH(irq_enable)] = { lgstart_sti, lgend_sti },
+ [PARAVIRT_PATCH(restore_fl)] = { lgstart_popf, lgend_popf },
+ [PARAVIRT_PATCH(save_fl)] = { lgstart_pushf, lgend_pushf },
+};
+static unsigned lguest_patch(u8 type, u16 clobber, void *insns, unsigned len)
+{
+ unsigned int insn_len;
+
+ /* Don't touch it if we don't have a replacement */
+ if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start)
+ return paravirt_patch_default(type, clobber, insns, len);
+
+ insn_len = lguest_insns[type].end - lguest_insns[type].start;
+
+ /* Similarly if we can't fit replacement. */
+ if (len < insn_len)
+ return paravirt_patch_default(type, clobber, insns, len);
+
+ memcpy(insns, lguest_insns[type].start, insn_len);
+ return insn_len;
+}
+
+__init void lguest_init(void *boot)
+{
+ /* Copy boot parameters first. */
+ memcpy(&boot_params, boot, PARAM_SIZE);
+ memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr),
+ COMMAND_LINE_SIZE);
+
+ paravirt_ops.name = "lguest";
+ paravirt_ops.paravirt_enabled = 1;
+ paravirt_ops.kernel_rpl = 1;
+
+ paravirt_ops.save_fl = save_fl;
+ paravirt_ops.restore_fl = restore_fl;
+ paravirt_ops.irq_disable = irq_disable;
+ paravirt_ops.irq_enable = irq_enable;
+ paravirt_ops.load_gdt = lguest_load_gdt;
+ paravirt_ops.memory_setup = lguest_memory_setup;
+ paravirt_ops.cpuid = lguest_cpuid;
+ paravirt_ops.write_cr3 = lguest_write_cr3;
+ paravirt_ops.flush_tlb_user = lguest_flush_tlb_user;
+ paravirt_ops.flush_tlb_single = lguest_flush_tlb_single;
+ paravirt_ops.flush_tlb_kernel = lguest_flush_tlb_kernel;
+ paravirt_ops.set_pte = lguest_set_pte;
+ paravirt_ops.set_pte_at = lguest_set_pte_at;
+ paravirt_ops.set_pmd = lguest_set_pmd;
+#ifdef CONFIG_X86_LOCAL_APIC
+ paravirt_ops.apic_write = lguest_apic_write;
+ paravirt_ops.apic_write_atomic = lguest_apic_write;
+ paravirt_ops.apic_read = lguest_apic_read;
+#endif
+ paravirt_ops.load_idt = lguest_load_idt;
+ paravirt_ops.iret = lguest_iret;
+ paravirt_ops.load_esp0 = lguest_load_esp0;
+ paravirt_ops.load_tr_desc = lguest_load_tr_desc;
+ paravirt_ops.set_ldt = lguest_set_ldt;
+ paravirt_ops.load_tls = lguest_load_tls;
+ paravirt_ops.set_debugreg = lguest_set_debugreg;
+ paravirt_ops.clts = lguest_clts;
+ paravirt_ops.read_cr0 = lguest_read_cr0;
+ paravirt_ops.write_cr0 = lguest_write_cr0;
+ paravirt_ops.init_IRQ = lguest_init_IRQ;
+ paravirt_ops.read_cr2 = lguest_read_cr2;
+ paravirt_ops.read_cr3 = lguest_read_cr3;
+ paravirt_ops.read_cr4 = lguest_read_cr4;
+ paravirt_ops.write_cr4 = lguest_write_cr4;
+ paravirt_ops.write_gdt_entry = lguest_write_gdt_entry;
+ paravirt_ops.write_idt_entry = lguest_write_idt_entry;
+ paravirt_ops.patch = lguest_patch;
+ paravirt_ops.safe_halt = lguest_safe_halt;
+ paravirt_ops.get_wallclock = lguest_get_wallclock;
+ paravirt_ops.time_init = lguest_time_init;
+ paravirt_ops.set_lazy_mode = lguest_lazy_mode;
+ paravirt_ops.wbinvd = lguest_wbinvd;
+ paravirt_ops.sched_clock = lguest_sched_clock;
+
+ hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
+
+ /* We use top of mem for initial pagetables. */
+ init_pg_tables_end = __pa(pg0);
+
+ asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory");
+
+ reserve_top_address(lguest_data.reserve_mem);
+
+ lockdep_init();
+
+ paravirt_disable_iospace();
+
+ cpu_detect(&new_cpu_data);
+ /* head.S usually sets up the first capability word, so do it here. */
+ new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+ /* Math is always hard! */
+ new_cpu_data.hard_math = 1;
+
+#ifdef CONFIG_X86_MCE
+ mce_disabled = 1;
+#endif
+
+#ifdef CONFIG_ACPI
+ acpi_disabled = 1;
+ acpi_ht = 0;
+#endif
+
+ add_preferred_console("hvc", 0, NULL);
+
+ pm_power_off = lguest_power_off;
+ start_kernel();
+}
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S
new file mode 100644
index 000000000000..a3dbf22ee365
--- /dev/null
+++ b/drivers/lguest/lguest_asm.S
@@ -0,0 +1,54 @@
+#include <linux/linkage.h>
+#include <linux/lguest.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/processor-flags.h>
+
+/*
+ * This is where we begin: we have a magic signature which the launcher looks
+ * for. The plan is that the Linux boot protocol will be extended with a
+ * "platform type" field which will guide us here from the normal entry point,
+ * but for the moment this suffices. We pass the virtual address of the boot
+ * info to lguest_init().
+ *
+ * We put it in .init.text will be discarded after boot.
+ */
+.section .init.text, "ax", @progbits
+.ascii "GenuineLguest"
+ /* Set up initial stack. */
+ movl $(init_thread_union+THREAD_SIZE),%esp
+ movl %esi, %eax
+ addl $__PAGE_OFFSET, %eax
+ jmp lguest_init
+
+/* The templates for inline patching. */
+#define LGUEST_PATCH(name, insns...) \
+ lgstart_##name: insns; lgend_##name:; \
+ .globl lgstart_##name; .globl lgend_##name
+
+LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
+
+.text
+/* These demark the EIP range where host should never deliver interrupts. */
+.global lguest_noirq_start
+.global lguest_noirq_end
+
+/*
+ * We move eflags word to lguest_data.irq_enabled to restore interrupt state.
+ * For page faults, gpfs and virtual interrupts, the hypervisor has saved
+ * eflags manually, otherwise it was delivered directly and so eflags reflects
+ * the real machine IF state, ie. interrupts on. Since the kernel always dies
+ * if it takes such a trap with interrupts disabled anyway, turning interrupts
+ * back on unconditionally here is OK.
+ */
+ENTRY(lguest_iret)
+ pushl %eax
+ movl 12(%esp), %eax
+lguest_noirq_start:
+ movl %eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
+ popl %eax
+ iret
+lguest_noirq_end:
diff --git a/drivers/lguest/lguest_bus.c b/drivers/lguest/lguest_bus.c
new file mode 100644
index 000000000000..18d6ab21a43b
--- /dev/null
+++ b/drivers/lguest/lguest_bus.c
@@ -0,0 +1,148 @@
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lguest_bus.h>
+#include <asm/io.h>
+
+static ssize_t type_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%hu", lguest_devices[dev->index].type);
+}
+static ssize_t features_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%hx", lguest_devices[dev->index].features);
+}
+static ssize_t pfn_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%u", lguest_devices[dev->index].pfn);
+}
+static ssize_t status_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ return sprintf(buf, "%hx", lguest_devices[dev->index].status);
+}
+static ssize_t status_store(struct device *_dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ if (sscanf(buf, "%hi", &lguest_devices[dev->index].status) != 1)
+ return -EINVAL;
+ return count;
+}
+static struct device_attribute lguest_dev_attrs[] = {
+ __ATTR_RO(type),
+ __ATTR_RO(features),
+ __ATTR_RO(pfn),
+ __ATTR(status, 0644, status_show, status_store),
+ __ATTR_NULL
+};
+
+static int lguest_dev_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ struct lguest_driver *drv = container_of(_drv,struct lguest_driver,drv);
+
+ return (drv->device_type == lguest_devices[dev->index].type);
+}
+
+struct lguest_bus {
+ struct bus_type bus;
+ struct device dev;
+};
+
+static struct lguest_bus lguest_bus = {
+ .bus = {
+ .name = "lguest",
+ .match = lguest_dev_match,
+ .dev_attrs = lguest_dev_attrs,
+ },
+ .dev = {
+ .parent = NULL,
+ .bus_id = "lguest",
+ }
+};
+
+static int lguest_dev_probe(struct device *_dev)
+{
+ int ret;
+ struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+ struct lguest_driver *drv = container_of(dev->dev.driver,
+ struct lguest_driver, drv);
+
+ lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER;
+ ret = drv->probe(dev);
+ if (ret == 0)
+ lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER_OK;
+ return ret;
+}
+
+int register_lguest_driver(struct lguest_driver *drv)
+{
+ if (!lguest_devices)
+ return 0;
+
+ drv->drv.bus = &lguest_bus.bus;
+ drv->drv.name = drv->name;
+ drv->drv.owner = drv->owner;
+ drv->drv.probe = lguest_dev_probe;
+
+ return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(register_lguest_driver);
+
+static void add_lguest_device(unsigned int index)
+{
+ struct lguest_device *new;
+
+ lguest_devices[index].status |= LGUEST_DEVICE_S_ACKNOWLEDGE;
+ new = kmalloc(sizeof(struct lguest_device), GFP_KERNEL);
+ if (!new) {
+ printk(KERN_EMERG "Cannot allocate lguest device %u\n", index);
+ lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+ return;
+ }
+
+ new->index = index;
+ new->private = NULL;
+ memset(&new->dev, 0, sizeof(new->dev));
+ new->dev.parent = &lguest_bus.dev;
+ new->dev.bus = &lguest_bus.bus;
+ sprintf(new->dev.bus_id, "%u", index);
+ if (device_register(&new->dev) != 0) {
+ printk(KERN_EMERG "Cannot register lguest device %u\n", index);
+ lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+ kfree(new);
+ }
+}
+
+static void scan_devices(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < LGUEST_MAX_DEVICES; i++)
+ if (lguest_devices[i].type)
+ add_lguest_device(i);
+}
+
+static int __init lguest_bus_init(void)
+{
+ if (strcmp(paravirt_ops.name, "lguest") != 0)
+ return 0;
+
+ /* Devices are in page above top of "normal" mem. */
+ lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
+
+ if (bus_register(&lguest_bus.bus) != 0
+ || device_register(&lguest_bus.dev) != 0)
+ panic("lguest bus registration failed");
+
+ scan_devices();
+ return 0;
+}
+postcore_initcall(lguest_bus_init);
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
new file mode 100644
index 000000000000..e90d7a783daf
--- /dev/null
+++ b/drivers/lguest/lguest_user.c
@@ -0,0 +1,236 @@
+/* Userspace control of the guest, via /dev/lguest. */
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include "lg.h"
+
+static void setup_regs(struct lguest_regs *regs, unsigned long start)
+{
+ /* Write out stack in format lguest expects, so we can switch to it. */
+ regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
+ regs->cs = __KERNEL_CS|GUEST_PL;
+ regs->eflags = 0x202; /* Interrupts enabled. */
+ regs->eip = start;
+ /* esi points to our boot information (physical address 0) */
+}
+
+/* + addr */
+static long user_get_dma(struct lguest *lg, const u32 __user *input)
+{
+ unsigned long key, udma, irq;
+
+ if (get_user(key, input) != 0)
+ return -EFAULT;
+ udma = get_dma_buffer(lg, key, &irq);
+ if (!udma)
+ return -ENOENT;
+
+ /* We put irq number in udma->used_len. */
+ lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
+ return udma;
+}
+
+/* To force the Guest to stop running and return to the Launcher, the
+ * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The
+ * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
+static int break_guest_out(struct lguest *lg, const u32 __user *input)
+{
+ unsigned long on;
+
+ /* Fetch whether they're turning break on or off.. */
+ if (get_user(on, input) != 0)
+ return -EFAULT;
+
+ if (on) {
+ lg->break_out = 1;
+ /* Pop it out (may be running on different CPU) */
+ wake_up_process(lg->tsk);
+ /* Wait for them to reset it */
+ return wait_event_interruptible(lg->break_wq, !lg->break_out);
+ } else {
+ lg->break_out = 0;
+ wake_up(&lg->break_wq);
+ return 0;
+ }
+}
+
+/* + irq */
+static int user_send_irq(struct lguest *lg, const u32 __user *input)
+{
+ u32 irq;
+
+ if (get_user(irq, input) != 0)
+ return -EFAULT;
+ if (irq >= LGUEST_IRQS)
+ return -EINVAL;
+ set_bit(irq, lg->irqs_pending);
+ return 0;
+}
+
+static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
+{
+ struct lguest *lg = file->private_data;
+
+ if (!lg)
+ return -EINVAL;
+
+ /* If you're not the task which owns the guest, go away. */
+ if (current != lg->tsk)
+ return -EPERM;
+
+ if (lg->dead) {
+ size_t len;
+
+ if (IS_ERR(lg->dead))
+ return PTR_ERR(lg->dead);
+
+ len = min(size, strlen(lg->dead)+1);
+ if (copy_to_user(user, lg->dead, len) != 0)
+ return -EFAULT;
+ return len;
+ }
+
+ if (lg->dma_is_pending)
+ lg->dma_is_pending = 0;
+
+ return run_guest(lg, (unsigned long __user *)user);
+}
+
+/* Take: pfnlimit, pgdir, start, pageoffset. */
+static int initialize(struct file *file, const u32 __user *input)
+{
+ struct lguest *lg;
+ int err, i;
+ u32 args[4];
+
+ /* We grab the Big Lguest lock, which protects the global array
+ * "lguests" and multiple simultaneous initializations. */
+ mutex_lock(&lguest_lock);
+
+ if (file->private_data) {
+ err = -EBUSY;
+ goto unlock;
+ }
+
+ if (copy_from_user(args, input, sizeof(args)) != 0) {
+ err = -EFAULT;
+ goto unlock;
+ }
+
+ i = find_free_guest();
+ if (i < 0) {
+ err = -ENOSPC;
+ goto unlock;
+ }
+ lg = &lguests[i];
+ lg->guestid = i;
+ lg->pfn_limit = args[0];
+ lg->page_offset = args[3];
+ lg->regs_page = get_zeroed_page(GFP_KERNEL);
+ if (!lg->regs_page) {
+ err = -ENOMEM;
+ goto release_guest;
+ }
+ lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs);
+
+ err = init_guest_pagetable(lg, args[1]);
+ if (err)
+ goto free_regs;
+
+ setup_regs(lg->regs, args[2]);
+ setup_guest_gdt(lg);
+ init_clockdev(lg);
+ lg->tsk = current;
+ lg->mm = get_task_mm(lg->tsk);
+ init_waitqueue_head(&lg->break_wq);
+ lg->last_pages = NULL;
+ file->private_data = lg;
+
+ mutex_unlock(&lguest_lock);
+
+ return sizeof(args);
+
+free_regs:
+ free_page(lg->regs_page);
+release_guest:
+ memset(lg, 0, sizeof(*lg));
+unlock:
+ mutex_unlock(&lguest_lock);
+ return err;
+}
+
+static ssize_t write(struct file *file, const char __user *input,
+ size_t size, loff_t *off)
+{
+ struct lguest *lg = file->private_data;
+ u32 req;
+
+ if (get_user(req, input) != 0)
+ return -EFAULT;
+ input += sizeof(req);
+
+ if (req != LHREQ_INITIALIZE && !lg)
+ return -EINVAL;
+ if (lg && lg->dead)
+ return -ENOENT;
+
+ /* If you're not the task which owns the Guest, you can only break */
+ if (lg && current != lg->tsk && req != LHREQ_BREAK)
+ return -EPERM;
+
+ switch (req) {
+ case LHREQ_INITIALIZE:
+ return initialize(file, (const u32 __user *)input);
+ case LHREQ_GETDMA:
+ return user_get_dma(lg, (const u32 __user *)input);
+ case LHREQ_IRQ:
+ return user_send_irq(lg, (const u32 __user *)input);
+ case LHREQ_BREAK:
+ return break_guest_out(lg, (const u32 __user *)input);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int close(struct inode *inode, struct file *file)
+{
+ struct lguest *lg = file->private_data;
+
+ if (!lg)
+ return 0;
+
+ mutex_lock(&lguest_lock);
+ /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
+ hrtimer_cancel(&lg->hrt);
+ release_all_dma(lg);
+ free_guest_pagetable(lg);
+ mmput(lg->mm);
+ if (!IS_ERR(lg->dead))
+ kfree(lg->dead);
+ free_page(lg->regs_page);
+ memset(lg, 0, sizeof(*lg));
+ mutex_unlock(&lguest_lock);
+ return 0;
+}
+
+static struct file_operations lguest_fops = {
+ .owner = THIS_MODULE,
+ .release = close,
+ .write = write,
+ .read = read,
+};
+static struct miscdevice lguest_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "lguest",
+ .fops = &lguest_fops,
+};
+
+int __init lguest_device_init(void)
+{
+ return misc_register(&lguest_dev);
+}
+
+void __exit lguest_device_remove(void)
+{
+ misc_deregister(&lguest_dev);
+}
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
new file mode 100644
index 000000000000..1b0ba09b1269
--- /dev/null
+++ b/drivers/lguest/page_tables.c
@@ -0,0 +1,411 @@
+/* Shadow page table operations.
+ * Copyright (C) Rusty Russell IBM Corporation 2006.
+ * GPL v2 and any later version */
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/percpu.h>
+#include <asm/tlbflush.h>
+#include "lg.h"
+
+#define PTES_PER_PAGE_SHIFT 10
+#define PTES_PER_PAGE (1 << PTES_PER_PAGE_SHIFT)
+#define SWITCHER_PGD_INDEX (PTES_PER_PAGE - 1)
+
+static DEFINE_PER_CPU(spte_t *, switcher_pte_pages);
+#define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu)
+
+static unsigned vaddr_to_pgd_index(unsigned long vaddr)
+{
+ return vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+}
+
+/* These access the shadow versions (ie. the ones used by the CPU). */
+static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
+{
+ unsigned int index = vaddr_to_pgd_index(vaddr);
+
+ if (index >= SWITCHER_PGD_INDEX) {
+ kill_guest(lg, "attempt to access switcher pages");
+ index = 0;
+ }
+ return &lg->pgdirs[i].pgdir[index];
+}
+
+static spte_t *spte_addr(struct lguest *lg, spgd_t spgd, unsigned long vaddr)
+{
+ spte_t *page = __va(spgd.pfn << PAGE_SHIFT);
+ BUG_ON(!(spgd.flags & _PAGE_PRESENT));
+ return &page[(vaddr >> PAGE_SHIFT) % PTES_PER_PAGE];
+}
+
+/* These access the guest versions. */
+static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr)
+{
+ unsigned int index = vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+ return lg->pgdirs[lg->pgdidx].cr3 + index * sizeof(gpgd_t);
+}
+
+static unsigned long gpte_addr(struct lguest *lg,
+ gpgd_t gpgd, unsigned long vaddr)
+{
+ unsigned long gpage = gpgd.pfn << PAGE_SHIFT;
+ BUG_ON(!(gpgd.flags & _PAGE_PRESENT));
+ return gpage + ((vaddr>>PAGE_SHIFT) % PTES_PER_PAGE) * sizeof(gpte_t);
+}
+
+/* Do a virtual -> physical mapping on a user page. */
+static unsigned long get_pfn(unsigned long virtpfn, int write)
+{
+ struct page *page;
+ unsigned long ret = -1UL;
+
+ down_read(&current->mm->mmap_sem);
+ if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT,
+ 1, write, 1, &page, NULL) == 1)
+ ret = page_to_pfn(page);
+ up_read(&current->mm->mmap_sem);
+ return ret;
+}
+
+static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write)
+{
+ spte_t spte;
+ unsigned long pfn;
+
+ /* We ignore the global flag. */
+ spte.flags = (gpte.flags & ~_PAGE_GLOBAL);
+ pfn = get_pfn(gpte.pfn, write);
+ if (pfn == -1UL) {
+ kill_guest(lg, "failed to get page %u", gpte.pfn);
+ /* Must not put_page() bogus page on cleanup. */
+ spte.flags = 0;
+ }
+ spte.pfn = pfn;
+ return spte;
+}
+
+static void release_pte(spte_t pte)
+{
+ if (pte.flags & _PAGE_PRESENT)
+ put_page(pfn_to_page(pte.pfn));
+}
+
+static void check_gpte(struct lguest *lg, gpte_t gpte)
+{
+ if ((gpte.flags & (_PAGE_PWT|_PAGE_PSE)) || gpte.pfn >= lg->pfn_limit)
+ kill_guest(lg, "bad page table entry");
+}
+
+static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
+{
+ if ((gpgd.flags & ~_PAGE_TABLE) || gpgd.pfn >= lg->pfn_limit)
+ kill_guest(lg, "bad page directory entry");
+}
+
+/* FIXME: We hold reference to pages, which prevents them from being
+ swapped. It'd be nice to have a callback when Linux wants to swap out. */
+
+/* We fault pages in, which allows us to update accessed/dirty bits.
+ * Return true if we got page. */
+int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
+{
+ gpgd_t gpgd;
+ spgd_t *spgd;
+ unsigned long gpte_ptr;
+ gpte_t gpte;
+ spte_t *spte;
+
+ gpgd = mkgpgd(lgread_u32(lg, gpgd_addr(lg, vaddr)));
+ if (!(gpgd.flags & _PAGE_PRESENT))
+ return 0;
+
+ spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+ if (!(spgd->flags & _PAGE_PRESENT)) {
+ /* Get a page of PTEs for them. */
+ unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
+ /* FIXME: Steal from self in this case? */
+ if (!ptepage) {
+ kill_guest(lg, "out of memory allocating pte page");
+ return 0;
+ }
+ check_gpgd(lg, gpgd);
+ spgd->raw.val = (__pa(ptepage) | gpgd.flags);
+ }
+
+ gpte_ptr = gpte_addr(lg, gpgd, vaddr);
+ gpte = mkgpte(lgread_u32(lg, gpte_ptr));
+
+ /* No page? */
+ if (!(gpte.flags & _PAGE_PRESENT))
+ return 0;
+
+ /* Write to read-only page? */
+ if ((errcode & 2) && !(gpte.flags & _PAGE_RW))
+ return 0;
+
+ /* User access to a non-user page? */
+ if ((errcode & 4) && !(gpte.flags & _PAGE_USER))
+ return 0;
+
+ check_gpte(lg, gpte);
+ gpte.flags |= _PAGE_ACCESSED;
+ if (errcode & 2)
+ gpte.flags |= _PAGE_DIRTY;
+
+ /* We're done with the old pte. */
+ spte = spte_addr(lg, *spgd, vaddr);
+ release_pte(*spte);
+
+ /* We don't make it writable if this isn't a write: later
+ * write will fault so we can set dirty bit in guest. */
+ if (gpte.flags & _PAGE_DIRTY)
+ *spte = gpte_to_spte(lg, gpte, 1);
+ else {
+ gpte_t ro_gpte = gpte;
+ ro_gpte.flags &= ~_PAGE_RW;
+ *spte = gpte_to_spte(lg, ro_gpte, 0);
+ }
+
+ /* Now we update dirty/accessed on guest. */
+ lgwrite_u32(lg, gpte_ptr, gpte.raw.val);
+ return 1;
+}
+
+/* This is much faster than the full demand_page logic. */
+static int page_writable(struct lguest *lg, unsigned long vaddr)
+{
+ spgd_t *spgd;
+ unsigned long flags;
+
+ spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+ if (!(spgd->flags & _PAGE_PRESENT))
+ return 0;
+
+ flags = spte_addr(lg, *spgd, vaddr)->flags;
+ return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
+}
+
+void pin_page(struct lguest *lg, unsigned long vaddr)
+{
+ if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2))
+ kill_guest(lg, "bad stack page %#lx", vaddr);
+}
+
+static void release_pgd(struct lguest *lg, spgd_t *spgd)
+{
+ if (spgd->flags & _PAGE_PRESENT) {
+ unsigned int i;
+ spte_t *ptepage = __va(spgd->pfn << PAGE_SHIFT);
+ for (i = 0; i < PTES_PER_PAGE; i++)
+ release_pte(ptepage[i]);
+ free_page((long)ptepage);
+ spgd->raw.val = 0;
+ }
+}
+
+static void flush_user_mappings(struct lguest *lg, int idx)
+{
+ unsigned int i;
+ for (i = 0; i < vaddr_to_pgd_index(lg->page_offset); i++)
+ release_pgd(lg, lg->pgdirs[idx].pgdir + i);
+}
+
+void guest_pagetable_flush_user(struct lguest *lg)
+{
+ flush_user_mappings(lg, lg->pgdidx);
+}
+
+static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
+{
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ if (lg->pgdirs[i].cr3 == pgtable)
+ break;
+ return i;
+}
+
+static unsigned int new_pgdir(struct lguest *lg,
+ unsigned long cr3,
+ int *blank_pgdir)
+{
+ unsigned int next;
+
+ next = random32() % ARRAY_SIZE(lg->pgdirs);
+ if (!lg->pgdirs[next].pgdir) {
+ lg->pgdirs[next].pgdir = (spgd_t *)get_zeroed_page(GFP_KERNEL);
+ if (!lg->pgdirs[next].pgdir)
+ next = lg->pgdidx;
+ else
+ /* There are no mappings: you'll need to re-pin */
+ *blank_pgdir = 1;
+ }
+ lg->pgdirs[next].cr3 = cr3;
+ /* Release all the non-kernel mappings. */
+ flush_user_mappings(lg, next);
+
+ return next;
+}
+
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+ int newpgdir, repin = 0;
+
+ newpgdir = find_pgdir(lg, pgtable);
+ if (newpgdir == ARRAY_SIZE(lg->pgdirs))
+ newpgdir = new_pgdir(lg, pgtable, &repin);
+ lg->pgdidx = newpgdir;
+ if (repin)
+ pin_stack_pages(lg);
+}
+
+static void release_all_pagetables(struct lguest *lg)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ if (lg->pgdirs[i].pgdir)
+ for (j = 0; j < SWITCHER_PGD_INDEX; j++)
+ release_pgd(lg, lg->pgdirs[i].pgdir + j);
+}
+
+void guest_pagetable_clear_all(struct lguest *lg)
+{
+ release_all_pagetables(lg);
+ pin_stack_pages(lg);
+}
+
+static void do_set_pte(struct lguest *lg, int idx,
+ unsigned long vaddr, gpte_t gpte)
+{
+ spgd_t *spgd = spgd_addr(lg, idx, vaddr);
+ if (spgd->flags & _PAGE_PRESENT) {
+ spte_t *spte = spte_addr(lg, *spgd, vaddr);
+ release_pte(*spte);
+ if (gpte.flags & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+ check_gpte(lg, gpte);
+ *spte = gpte_to_spte(lg, gpte, gpte.flags&_PAGE_DIRTY);
+ } else
+ spte->raw.val = 0;
+ }
+}
+
+void guest_set_pte(struct lguest *lg,
+ unsigned long cr3, unsigned long vaddr, gpte_t gpte)
+{
+ /* Kernel mappings must be changed on all top levels. */
+ if (vaddr >= lg->page_offset) {
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ if (lg->pgdirs[i].pgdir)
+ do_set_pte(lg, i, vaddr, gpte);
+ } else {
+ int pgdir = find_pgdir(lg, cr3);
+ if (pgdir != ARRAY_SIZE(lg->pgdirs))
+ do_set_pte(lg, pgdir, vaddr, gpte);
+ }
+}
+
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
+{
+ int pgdir;
+
+ if (idx >= SWITCHER_PGD_INDEX)
+ return;
+
+ pgdir = find_pgdir(lg, cr3);
+ if (pgdir < ARRAY_SIZE(lg->pgdirs))
+ release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
+}
+
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+ /* We assume this in flush_user_mappings, so check now */
+ if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX)
+ return -EINVAL;
+ lg->pgdidx = 0;
+ lg->pgdirs[lg->pgdidx].cr3 = pgtable;
+ lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL);
+ if (!lg->pgdirs[lg->pgdidx].pgdir)
+ return -ENOMEM;
+ return 0;
+}
+
+void free_guest_pagetable(struct lguest *lg)
+{
+ unsigned int i;
+
+ release_all_pagetables(lg);
+ for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+ free_page((long)lg->pgdirs[i].pgdir);
+}
+
+/* Caller must be preempt-safe */
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
+{
+ spte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+ spgd_t switcher_pgd;
+ spte_t regs_pte;
+
+ /* Since switcher less that 4MB, we simply mug top pte page. */
+ switcher_pgd.pfn = __pa(switcher_pte_page) >> PAGE_SHIFT;
+ switcher_pgd.flags = _PAGE_KERNEL;
+ lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
+
+ /* Map our regs page over stack page. */
+ regs_pte.pfn = __pa(lg->regs_page) >> PAGE_SHIFT;
+ regs_pte.flags = _PAGE_KERNEL;
+ switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTES_PER_PAGE]
+ = regs_pte;
+}
+
+static void free_switcher_pte_pages(void)
+{
+ unsigned int i;
+
+ for_each_possible_cpu(i)
+ free_page((long)switcher_pte_page(i));
+}
+
+static __init void populate_switcher_pte_page(unsigned int cpu,
+ struct page *switcher_page[],
+ unsigned int pages)
+{
+ unsigned int i;
+ spte_t *pte = switcher_pte_page(cpu);
+
+ for (i = 0; i < pages; i++) {
+ pte[i].pfn = page_to_pfn(switcher_page[i]);
+ pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+ }
+
+ /* We only map this CPU's pages, so guest can't see others. */
+ i = pages + cpu*2;
+
+ /* First page (regs) is rw, second (state) is ro. */
+ pte[i].pfn = page_to_pfn(switcher_page[i]);
+ pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW;
+ pte[i+1].pfn = page_to_pfn(switcher_page[i+1]);
+ pte[i+1].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+}
+
+__init int init_pagetables(struct page **switcher_page, unsigned int pages)
+{
+ unsigned int i;
+
+ for_each_possible_cpu(i) {
+ switcher_pte_page(i) = (spte_t *)get_zeroed_page(GFP_KERNEL);
+ if (!switcher_pte_page(i)) {
+ free_switcher_pte_pages();
+ return -ENOMEM;
+ }
+ populate_switcher_pte_page(i, switcher_page, pages);
+ }
+ return 0;
+}
+
+void free_pagetables(void)
+{
+ free_switcher_pte_pages();
+}
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
new file mode 100644
index 000000000000..1b2cfe89dcd5
--- /dev/null
+++ b/drivers/lguest/segments.c
@@ -0,0 +1,125 @@
+#include "lg.h"
+
+static int desc_ok(const struct desc_struct *gdt)
+{
+ /* MBZ=0, P=1, DT=1 */
+ return ((gdt->b & 0x00209000) == 0x00009000);
+}
+
+static int segment_present(const struct desc_struct *gdt)
+{
+ return gdt->b & 0x8000;
+}
+
+static int ignored_gdt(unsigned int num)
+{
+ return (num == GDT_ENTRY_TSS
+ || num == GDT_ENTRY_LGUEST_CS
+ || num == GDT_ENTRY_LGUEST_DS
+ || num == GDT_ENTRY_DOUBLEFAULT_TSS);
+}
+
+/* We don't allow removal of CS, DS or SS; it doesn't make sense. */
+static void check_segment_use(struct lguest *lg, unsigned int desc)
+{
+ if (lg->regs->gs / 8 == desc)
+ lg->regs->gs = 0;
+ if (lg->regs->fs / 8 == desc)
+ lg->regs->fs = 0;
+ if (lg->regs->es / 8 == desc)
+ lg->regs->es = 0;
+ if (lg->regs->ds / 8 == desc
+ || lg->regs->cs / 8 == desc
+ || lg->regs->ss / 8 == desc)
+ kill_guest(lg, "Removed live GDT entry %u", desc);
+}
+
+static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
+{
+ unsigned int i;
+
+ for (i = start; i < end; i++) {
+ /* We never copy these ones to real gdt */
+ if (ignored_gdt(i))
+ continue;
+
+ /* We could fault in switch_to_guest if they are using
+ * a removed segment. */
+ if (!segment_present(&lg->gdt[i])) {
+ check_segment_use(lg, i);
+ continue;
+ }
+
+ if (!desc_ok(&lg->gdt[i]))
+ kill_guest(lg, "Bad GDT descriptor %i", i);
+
+ /* DPL 0 presumably means "for use by guest". */
+ if ((lg->gdt[i].b & 0x00006000) == 0)
+ lg->gdt[i].b |= (GUEST_PL << 13);
+
+ /* Set accessed bit, since gdt isn't writable. */
+ lg->gdt[i].b |= 0x00000100;
+ }
+}
+
+void setup_default_gdt_entries(struct lguest_ro_state *state)
+{
+ struct desc_struct *gdt = state->guest_gdt;
+ unsigned long tss = (unsigned long)&state->guest_tss;
+
+ /* Hypervisor segments. */
+ gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+ gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+
+ /* This is the one which we *cannot* copy from guest, since tss
+ is depended on this lguest_ro_state, ie. this cpu. */
+ gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
+ gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
+ | ((tss >> 16) & 0x000000FF);
+}
+
+void setup_guest_gdt(struct lguest *lg)
+{
+ lg->gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
+ lg->gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
+ lg->gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
+ lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+}
+
+/* This is a fast version for the common case where only the three TLS entries
+ * have changed. */
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
+{
+ unsigned int i;
+
+ for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
+ gdt[i] = lg->gdt[i];
+}
+
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
+{
+ unsigned int i;
+
+ for (i = 0; i < GDT_ENTRIES; i++)
+ if (!ignored_gdt(i))
+ gdt[i] = lg->gdt[i];
+}
+
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
+{
+ if (num > ARRAY_SIZE(lg->gdt))
+ kill_guest(lg, "too many gdt entries %i", num);
+
+ lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0]));
+ fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt));
+ lg->changed |= CHANGED_GDT;
+}
+
+void guest_load_tls(struct lguest *lg, unsigned long gtls)
+{
+ struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN];
+
+ lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
+ fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
+ lg->changed |= CHANGED_GDT_TLS;
+}
diff --git a/drivers/lguest/switcher.S b/drivers/lguest/switcher.S
new file mode 100644
index 000000000000..eadd4cc299d2
--- /dev/null
+++ b/drivers/lguest/switcher.S
@@ -0,0 +1,159 @@
+/* This code sits at 0xFFC00000 to do the low-level guest<->host switch.
+
+ There is are two pages above us for this CPU (struct lguest_pages).
+ The second page (struct lguest_ro_state) becomes read-only after the
+ context switch. The first page (the stack for traps) remains writable,
+ but while we're in here, the guest cannot be running.
+*/
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include "lg.h"
+
+.text
+ENTRY(start_switcher_text)
+
+/* %eax points to lguest pages for this CPU. %ebx contains cr3 value.
+ All normal registers can be clobbered! */
+ENTRY(switch_to_guest)
+ /* Save host segments on host stack. */
+ pushl %es
+ pushl %ds
+ pushl %gs
+ pushl %fs
+ /* With CONFIG_FRAME_POINTER, gcc doesn't let us clobber this! */
+ pushl %ebp
+ /* Save host stack. */
+ movl %esp, LGUEST_PAGES_host_sp(%eax)
+ /* Switch to guest stack: if we get NMI we expect to be there. */
+ movl %eax, %edx
+ addl $LGUEST_PAGES_regs, %edx
+ movl %edx, %esp
+ /* Switch to guest's GDT, IDT. */
+ lgdt LGUEST_PAGES_guest_gdt_desc(%eax)
+ lidt LGUEST_PAGES_guest_idt_desc(%eax)
+ /* Switch to guest's TSS while GDT still writable. */
+ movl $(GDT_ENTRY_TSS*8), %edx
+ ltr %dx
+ /* Set host's TSS GDT entry to available (clear byte 5 bit 2). */
+ movl (LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx
+ andb $0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx)
+ /* Switch to guest page tables: lguest_pages->state now read-only. */
+ movl %ebx, %cr3
+ /* Restore guest regs */
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %gs
+ popl %eax
+ popl %fs
+ popl %ds
+ popl %es
+ /* Skip error code and trap number */
+ addl $8, %esp
+ iret
+
+#define SWITCH_TO_HOST \
+ /* Save guest state */ \
+ pushl %es; \
+ pushl %ds; \
+ pushl %fs; \
+ pushl %eax; \
+ pushl %gs; \
+ pushl %ebp; \
+ pushl %edi; \
+ pushl %esi; \
+ pushl %edx; \
+ pushl %ecx; \
+ pushl %ebx; \
+ /* Load lguest ds segment for convenience. */ \
+ movl $(LGUEST_DS), %eax; \
+ movl %eax, %ds; \
+ /* Figure out where we are, based on stack (at top of regs). */ \
+ movl %esp, %eax; \
+ subl $LGUEST_PAGES_regs, %eax; \
+ /* Put trap number in %ebx before we switch cr3 and lose it. */ \
+ movl LGUEST_PAGES_regs_trapnum(%eax), %ebx; \
+ /* Switch to host page tables (host GDT, IDT and stack are in host \
+ mem, so need this first) */ \
+ movl LGUEST_PAGES_host_cr3(%eax), %edx; \
+ movl %edx, %cr3; \
+ /* Set guest's TSS to available (clear byte 5 bit 2). */ \
+ andb $0xFD, (LGUEST_PAGES_guest_gdt+GDT_ENTRY_TSS*8+5)(%eax); \
+ /* Switch to host's GDT & IDT. */ \
+ lgdt LGUEST_PAGES_host_gdt_desc(%eax); \
+ lidt LGUEST_PAGES_host_idt_desc(%eax); \
+ /* Switch to host's stack. */ \
+ movl LGUEST_PAGES_host_sp(%eax), %esp; \
+ /* Switch to host's TSS */ \
+ movl $(GDT_ENTRY_TSS*8), %edx; \
+ ltr %dx; \
+ popl %ebp; \
+ popl %fs; \
+ popl %gs; \
+ popl %ds; \
+ popl %es
+
+/* Return to run_guest_once. */
+return_to_host:
+ SWITCH_TO_HOST
+ iret
+
+deliver_to_host:
+ SWITCH_TO_HOST
+ /* Decode IDT and jump to hosts' irq handler. When that does iret, it
+ * will return to run_guest_once. This is a feature. */
+ movl (LGUEST_PAGES_host_idt_desc+2)(%eax), %edx
+ leal (%edx,%ebx,8), %eax
+ movzwl (%eax),%edx
+ movl 4(%eax), %eax
+ xorw %ax, %ax
+ orl %eax, %edx
+ jmp *%edx
+
+/* Real hardware interrupts are delivered straight to the host. Others
+ cause us to return to run_guest_once so it can decide what to do. Note
+ that some of these are overridden by the guest to deliver directly, and
+ never enter here (see load_guest_idt_entry). */
+.macro IRQ_STUB N TARGET
+ .data; .long 1f; .text; 1:
+ /* Make an error number for most traps, which don't have one. */
+ .if (\N <> 8) && (\N < 10 || \N > 14) && (\N <> 17)
+ pushl $0
+ .endif
+ pushl $\N
+ jmp \TARGET
+ ALIGN
+.endm
+
+.macro IRQ_STUBS FIRST LAST TARGET
+ irq=\FIRST
+ .rept \LAST-\FIRST+1
+ IRQ_STUB irq \TARGET
+ irq=irq+1
+ .endr
+.endm
+
+/* We intercept every interrupt, because we may need to switch back to
+ * host. Unfortunately we can't tell them apart except by entry
+ * point, so we need 256 entry points.
+ */
+.data
+.global default_idt_entries
+default_idt_entries:
+.text
+ IRQ_STUBS 0 1 return_to_host /* First two traps */
+ IRQ_STUB 2 handle_nmi /* NMI */
+ IRQ_STUBS 3 31 return_to_host /* Rest of traps */
+ IRQ_STUBS 32 127 deliver_to_host /* Real interrupts */
+ IRQ_STUB 128 return_to_host /* System call (overridden) */
+ IRQ_STUBS 129 255 deliver_to_host /* Other real interrupts */
+
+/* We ignore NMI and return. */
+handle_nmi:
+ addl $8, %esp
+ iret
+
+ENTRY(end_switcher_text)
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index adfea3c7c62a..bc77c5e2ca9f 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -248,21 +248,15 @@ static int adb_scan_bus(void)
static int
adb_probe_task(void *x)
{
- sigset_t blocked;
-
strcpy(current->comm, "kadbprobe");
- sigfillset(&blocked);
- sigprocmask(SIG_BLOCK, &blocked, NULL);
- flush_signals(current);
-
printk(KERN_INFO "adb: starting probe task...\n");
do_adb_reset_bus();
printk(KERN_INFO "adb: finished probe task...\n");
-
+
adb_probe_task_pid = 0;
up(&adb_probe_mutex);
-
+
return 0;
}
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index c96b7fe882a4..ec9e5f32f0ae 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -365,10 +365,9 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
if (np == NULL)
return NULL;
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->bus = &chip->lbus;
dev->media_bay = in_bay;
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 4177ff004753..2c21d4f25cc8 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -30,7 +30,6 @@
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
-#include <asm/dbdma.h>
#include <asm/macio.h>
#include <asm/keylargo.h>
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index f8e1a135bf9d..d409f6759482 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -1053,10 +1053,9 @@ static int smu_open(struct inode *inode, struct file *file)
struct smu_private *pp;
unsigned long flags;
- pp = kmalloc(sizeof(struct smu_private), GFP_KERNEL);
+ pp = kzalloc(sizeof(struct smu_private), GFP_KERNEL);
if (pp == 0)
return -ENOMEM;
- memset(pp, 0, sizeof(struct smu_private));
spin_lock_init(&pp->lock);
pp->mode = smu_file_commands;
init_waitqueue_head(&pp->wait);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index bd55e6ab99fc..f25685b9b7cf 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -335,6 +335,7 @@ static int monitor_task(void *arg)
{
struct thermostat* th = arg;
+ set_freezable();
while(!kthread_should_stop()) {
try_to_freeze();
msleep_interruptible(2000);
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index dbb22403979f..e43554e754a4 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -318,10 +318,9 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name)
if (adap == NULL)
return NULL;
- clt = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (clt == NULL)
return NULL;
- memset(clt, 0, sizeof(struct i2c_client));
clt->addr = (id >> 1) & 0x7f;
clt->adapter = adap;
@@ -1770,7 +1769,8 @@ static int call_critical_overtemp(void)
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
- return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+ return call_usermodehelper(critical_overtemp_path,
+ argv, envp, UMH_WAIT_EXEC);
}
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 3d0354e96a97..5452da1bb1a5 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -431,9 +431,8 @@ do_probe( struct i2c_adapter *adapter, int addr, int kind )
| I2C_FUNC_SMBUS_WRITE_BYTE) )
return 0;
- if( !(cl=kmalloc(sizeof(*cl), GFP_KERNEL)) )
+ if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) )
return -ENOMEM;
- memset( cl, 0, sizeof(struct i2c_client) );
cl->addr = addr;
cl->adapter = adapter;
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index 11ced17f438a..516d943227e2 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -80,7 +80,8 @@ int wf_critical_overtemp(void)
"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
NULL };
- return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+ return call_usermodehelper(critical_overtemp_path,
+ argv, envp, UMH_WAIT_EXEC);
}
EXPORT_SYMBOL_GPL(wf_critical_overtemp);
@@ -92,6 +93,7 @@ static int wf_thread_func(void *data)
DBG("wf: thread started\n");
+ set_freezable();
while(!kthread_should_stop()) {
if (time_after_eq(jiffies, next)) {
wf_notify(WF_EVENT_TICK, NULL);
@@ -212,7 +214,6 @@ int wf_register_control(struct wf_control *new_ct)
list_add(&new_ct->link, &wf_controls);
new_ct->attr.attr.name = new_ct->name;
- new_ct->attr.attr.owner = THIS_MODULE;
new_ct->attr.attr.mode = 0644;
new_ct->attr.show = wf_show_control;
new_ct->attr.store = wf_store_control;
@@ -325,7 +326,6 @@ int wf_register_sensor(struct wf_sensor *new_sr)
list_add(&new_sr->link, &wf_sensors);
new_sr->attr.attr.name = new_sr->name;
- new_sr->attr.attr.owner = THIS_MODULE;
new_sr->attr.attr.mode = 0444;
new_sr->attr.show = wf_show_sensor;
new_sr->attr.store = NULL;
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index a0fabf3c2008..7e10c3ab4d50 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -117,10 +117,9 @@ static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
DBG("wf_lm75: creating %s device at address 0x%02x\n",
ds1775 ? "ds1775" : "lm75", addr);
- lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+ lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
if (lm == NULL)
return NULL;
- memset(lm, 0, sizeof(struct wf_lm75_sensor));
/* Usual rant about sensor names not beeing very consistent in
* the device-tree, oh well ...
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 1043b39aa123..351982bcec1b 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -67,26 +67,6 @@ static struct i2c_driver wf_sat_driver = {
.detach_client = wf_sat_detach,
};
-/*
- * XXX i2c_smbus_read_i2c_block_data doesn't pass the requested
- * length down to the low-level driver, so we use this, which
- * works well enough with the SMU i2c driver code...
- */
-static int sat_read_block(struct i2c_client *client, u8 command,
- u8 *values, int len)
-{
- union i2c_smbus_data data;
- int err;
-
- data.block[0] = len;
- err = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
- I2C_SMBUS_READ, command, I2C_SMBUS_I2C_BLOCK_DATA,
- &data);
- if (!err)
- memcpy(values, data.block, len);
- return err;
-}
-
struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
unsigned int *size)
{
@@ -124,8 +104,8 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id,
return NULL;
for (i = 0; i < len; i += 4) {
- err = sat_read_block(&sat->i2c, 0xa, data, 4);
- if (err) {
+ err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data);
+ if (err < 0) {
printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n",
err);
goto fail;
@@ -157,8 +137,8 @@ static int wf_sat_read_cache(struct wf_sat *sat)
{
int err;
- err = sat_read_block(&sat->i2c, 0x3f, sat->cache, 16);
- if (err)
+ err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache);
+ if (err < 0)
return err;
sat->last_read = jiffies;
#ifdef LOTSA_DEBUG
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 7df934d69134..531d4d17d011 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -2,19 +2,17 @@
# Block device driver configuration
#
-if BLOCK
-
-menu "Multi-device support (RAID and LVM)"
-
-config MD
+menuconfig MD
bool "Multiple devices driver support (RAID and LVM)"
+ depends on BLOCK
help
Support multiple physical spindles through a single logical device.
Required for RAID and logical volume management.
+if MD
+
config BLK_DEV_MD
tristate "RAID support"
- depends on MD
---help---
This driver lets you combine several hard disk partitions into one
logical block device. This can be used to simply append one
@@ -109,6 +107,8 @@ config MD_RAID10
config MD_RAID456
tristate "RAID-4/RAID-5/RAID-6 mode"
depends on BLK_DEV_MD
+ select ASYNC_MEMCPY
+ select ASYNC_XOR
---help---
A RAID-5 set of N drives with a capacity of C MB per drive provides
the capacity of C * (N - 1) MB, and protects against a failure
@@ -189,7 +189,6 @@ config MD_FAULTY
config BLK_DEV_DM
tristate "Device mapper support"
- depends on MD
---help---
Device-mapper is a low level volume manager. It works by allowing
people to specify mappings for ranges of logical sectors. Various
@@ -262,6 +261,12 @@ config DM_MULTIPATH_EMC
---help---
Multipath support for EMC CX/AX series hardware.
+config DM_MULTIPATH_RDAC
+ tristate "LSI/Engenio RDAC multipath support (EXPERIMENTAL)"
+ depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL
+ ---help---
+ Multipath support for LSI/Engenio RDAC.
+
config DM_DELAY
tristate "I/O delaying target (EXPERIMENTAL)"
depends on BLK_DEV_DM && EXPERIMENTAL
@@ -271,6 +276,4 @@ config DM_DELAY
If unsure, say N.
-endmenu
-
-endif
+endif # MD
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index 38754084eac7..c49366cdc05d 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -7,6 +7,7 @@ dm-mod-objs := dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.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-rdac-objs := dm-mpath-rdac.o
md-mod-objs := md.o bitmap.o
raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \
raid6int1.o raid6int2.o raid6int4.o \
@@ -17,7 +18,7 @@ raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \
hostprogs-y := mktables
# Note: link order is important. All raid personalities
-# and xor.o must come before md.o, as they each initialise
+# and must come before md.o, as they each initialise
# themselves, and md.o may use the personalities when it
# auto-initialised.
@@ -25,7 +26,7 @@ obj-$(CONFIG_MD_LINEAR) += linear.o
obj-$(CONFIG_MD_RAID0) += raid0.o
obj-$(CONFIG_MD_RAID1) += raid1.o
obj-$(CONFIG_MD_RAID10) += raid10.o
-obj-$(CONFIG_MD_RAID456) += raid456.o xor.o
+obj-$(CONFIG_MD_RAID456) += raid456.o
obj-$(CONFIG_MD_MULTIPATH) += multipath.o
obj-$(CONFIG_MD_FAULTY) += faulty.o
obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
@@ -34,6 +35,7 @@ obj-$(CONFIG_DM_CRYPT) += dm-crypt.o
obj-$(CONFIG_DM_DELAY) += dm-delay.o
obj-$(CONFIG_DM_MULTIPATH) += dm-multipath.o dm-round-robin.o
obj-$(CONFIG_DM_MULTIPATH_EMC) += dm-emc.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_ZERO) += dm-zero.o
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 9620d452d030..927cb34c4805 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -268,6 +268,31 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
if (page->index == bitmap->file_pages-1)
size = roundup(bitmap->last_page_size,
bdev_hardsect_size(rdev->bdev));
+ /* Just make sure we aren't corrupting data or
+ * metadata
+ */
+ if (bitmap->offset < 0) {
+ /* DATA BITMAP METADATA */
+ if (bitmap->offset
+ + page->index * (PAGE_SIZE/512)
+ + size/512 > 0)
+ /* bitmap runs in to metadata */
+ return -EINVAL;
+ if (rdev->data_offset + mddev->size*2
+ > rdev->sb_offset*2 + bitmap->offset)
+ /* data runs in to bitmap */
+ return -EINVAL;
+ } else if (rdev->sb_offset*2 < rdev->data_offset) {
+ /* METADATA BITMAP DATA */
+ if (rdev->sb_offset*2
+ + bitmap->offset
+ + page->index*(PAGE_SIZE/512) + size/512
+ > rdev->data_offset)
+ /* bitmap runs in to data */
+ return -EINVAL;
+ } else {
+ /* DATA METADATA BITMAP - no problems */
+ }
md_super_write(mddev, rdev,
(rdev->sb_offset<<1) + bitmap->offset
+ page->index * (PAGE_SIZE/512),
@@ -280,32 +305,38 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait)
return 0;
}
+static void bitmap_file_kick(struct bitmap *bitmap);
/*
* write out a page to a file
*/
-static int write_page(struct bitmap *bitmap, struct page *page, int wait)
+static void write_page(struct bitmap *bitmap, struct page *page, int wait)
{
struct buffer_head *bh;
- if (bitmap->file == NULL)
- return write_sb_page(bitmap, page, wait);
+ if (bitmap->file == NULL) {
+ switch (write_sb_page(bitmap, page, wait)) {
+ case -EINVAL:
+ bitmap->flags |= BITMAP_WRITE_ERROR;
+ }
+ } else {
- bh = page_buffers(page);
+ bh = page_buffers(page);
- while (bh && bh->b_blocknr) {
- atomic_inc(&bitmap->pending_writes);
- set_buffer_locked(bh);
- set_buffer_mapped(bh);
- submit_bh(WRITE, bh);
- bh = bh->b_this_page;
- }
+ while (bh && bh->b_blocknr) {
+ atomic_inc(&bitmap->pending_writes);
+ set_buffer_locked(bh);
+ set_buffer_mapped(bh);
+ submit_bh(WRITE, bh);
+ bh = bh->b_this_page;
+ }
- if (wait) {
- wait_event(bitmap->write_wait,
- atomic_read(&bitmap->pending_writes)==0);
- return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;
+ if (wait) {
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes)==0);
+ }
}
- return 0;
+ if (bitmap->flags & BITMAP_WRITE_ERROR)
+ bitmap_file_kick(bitmap);
}
static void end_bitmap_write(struct buffer_head *bh, int uptodate)
@@ -425,17 +456,17 @@ out:
*/
/* update the event counter and sync the superblock to disk */
-int bitmap_update_sb(struct bitmap *bitmap)
+void bitmap_update_sb(struct bitmap *bitmap)
{
bitmap_super_t *sb;
unsigned long flags;
if (!bitmap || !bitmap->mddev) /* no bitmap for this array */
- return 0;
+ return;
spin_lock_irqsave(&bitmap->lock, flags);
if (!bitmap->sb_page) { /* no superblock */
spin_unlock_irqrestore(&bitmap->lock, flags);
- return 0;
+ return;
}
spin_unlock_irqrestore(&bitmap->lock, flags);
sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
@@ -443,7 +474,7 @@ int bitmap_update_sb(struct bitmap *bitmap)
if (!bitmap->mddev->degraded)
sb->events_cleared = cpu_to_le64(bitmap->mddev->events);
kunmap_atomic(sb, KM_USER0);
- return write_page(bitmap, bitmap->sb_page, 1);
+ write_page(bitmap, bitmap->sb_page, 1);
}
/* print out the bitmap file superblock */
@@ -572,20 +603,22 @@ enum bitmap_mask_op {
MASK_UNSET
};
-/* record the state of the bitmap in the superblock */
-static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
- enum bitmap_mask_op op)
+/* record the state of the bitmap in the superblock. Return the old value */
+static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
+ enum bitmap_mask_op op)
{
bitmap_super_t *sb;
unsigned long flags;
+ int old;
spin_lock_irqsave(&bitmap->lock, flags);
if (!bitmap->sb_page) { /* can't set the state */
spin_unlock_irqrestore(&bitmap->lock, flags);
- return;
+ return 0;
}
spin_unlock_irqrestore(&bitmap->lock, flags);
sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
+ old = le32_to_cpu(sb->state) & bits;
switch (op) {
case MASK_SET: sb->state |= cpu_to_le32(bits);
break;
@@ -594,6 +627,7 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
default: BUG();
}
kunmap_atomic(sb, KM_USER0);
+ return old;
}
/*
@@ -687,18 +721,23 @@ static void bitmap_file_kick(struct bitmap *bitmap)
{
char *path, *ptr = NULL;
- bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET);
- bitmap_update_sb(bitmap);
+ if (bitmap_mask_state(bitmap, BITMAP_STALE, MASK_SET) == 0) {
+ bitmap_update_sb(bitmap);
- if (bitmap->file) {
- path = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (path)
- ptr = file_path(bitmap->file, path, PAGE_SIZE);
+ if (bitmap->file) {
+ path = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (path)
+ ptr = file_path(bitmap->file, path, PAGE_SIZE);
- printk(KERN_ALERT "%s: kicking failed bitmap file %s from array!\n",
- bmname(bitmap), ptr ? ptr : "");
+ printk(KERN_ALERT
+ "%s: kicking failed bitmap file %s from array!\n",
+ bmname(bitmap), ptr ? ptr : "");
- kfree(path);
+ kfree(path);
+ } else
+ printk(KERN_ALERT
+ "%s: disabling internal bitmap due to errors\n",
+ bmname(bitmap));
}
bitmap_file_put(bitmap);
@@ -769,16 +808,15 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
/* this gets called when the md device is ready to unplug its underlying
* (slave) device queues -- before we let any writes go down, we need to
* sync the dirty pages of the bitmap file to disk */
-int bitmap_unplug(struct bitmap *bitmap)
+void bitmap_unplug(struct bitmap *bitmap)
{
unsigned long i, flags;
int dirty, need_write;
struct page *page;
int wait = 0;
- int err;
if (!bitmap)
- return 0;
+ return;
/* look at each page to see if there are any set bits that need to be
* flushed out to disk */
@@ -786,7 +824,7 @@ int bitmap_unplug(struct bitmap *bitmap)
spin_lock_irqsave(&bitmap->lock, flags);
if (!bitmap->filemap) {
spin_unlock_irqrestore(&bitmap->lock, flags);
- return 0;
+ return;
}
page = bitmap->filemap[i];
dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
@@ -798,7 +836,7 @@ int bitmap_unplug(struct bitmap *bitmap)
spin_unlock_irqrestore(&bitmap->lock, flags);
if (dirty | need_write)
- err = write_page(bitmap, page, 0);
+ write_page(bitmap, page, 0);
}
if (wait) { /* if any writes were performed, we need to wait on them */
if (bitmap->file)
@@ -809,7 +847,6 @@ int bitmap_unplug(struct bitmap *bitmap)
}
if (bitmap->flags & BITMAP_WRITE_ERROR)
bitmap_file_kick(bitmap);
- return 0;
}
static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed);
@@ -858,21 +895,21 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
bmname(bitmap),
(unsigned long) i_size_read(file->f_mapping->host),
bytes + sizeof(bitmap_super_t));
- goto out;
+ goto err;
}
ret = -ENOMEM;
bitmap->filemap = kmalloc(sizeof(struct page *) * num_pages, GFP_KERNEL);
if (!bitmap->filemap)
- goto out;
+ goto err;
/* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
bitmap->filemap_attr = kzalloc(
roundup( DIV_ROUND_UP(num_pages*4, 8), sizeof(unsigned long)),
GFP_KERNEL);
if (!bitmap->filemap_attr)
- goto out;
+ goto err;
oldindex = ~0L;
@@ -905,7 +942,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
}
if (IS_ERR(page)) { /* read error */
ret = PTR_ERR(page);
- goto out;
+ goto err;
}
oldindex = index;
@@ -920,11 +957,13 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
memset(paddr + offset, 0xff,
PAGE_SIZE - offset);
kunmap_atomic(paddr, KM_USER0);
- ret = write_page(bitmap, page, 1);
- if (ret) {
+ write_page(bitmap, page, 1);
+
+ ret = -EIO;
+ if (bitmap->flags & BITMAP_WRITE_ERROR) {
/* release, page not in filemap yet */
put_page(page);
- goto out;
+ goto err;
}
}
@@ -956,11 +995,15 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
md_wakeup_thread(bitmap->mddev->thread);
}
-out:
printk(KERN_INFO "%s: bitmap initialized from disk: "
- "read %lu/%lu pages, set %lu bits, status: %d\n",
- bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt, ret);
+ "read %lu/%lu pages, set %lu bits\n",
+ bmname(bitmap), bitmap->file_pages, num_pages, bit_cnt);
+
+ return 0;
+ err:
+ printk(KERN_INFO "%s: bitmap initialisation failed: %d\n",
+ bmname(bitmap), ret);
return ret;
}
@@ -997,19 +1040,18 @@ static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
* out to disk
*/
-int bitmap_daemon_work(struct bitmap *bitmap)
+void bitmap_daemon_work(struct bitmap *bitmap)
{
unsigned long j;
unsigned long flags;
struct page *page = NULL, *lastpage = NULL;
- int err = 0;
int blocks;
void *paddr;
if (bitmap == NULL)
- return 0;
+ return;
if (time_before(jiffies, bitmap->daemon_lastrun + bitmap->daemon_sleep*HZ))
- return 0;
+ return;
bitmap->daemon_lastrun = jiffies;
for (j = 0; j < bitmap->chunks; j++) {
@@ -1032,14 +1074,8 @@ int bitmap_daemon_work(struct bitmap *bitmap)
clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
- if (need_write) {
- switch (write_page(bitmap, page, 0)) {
- case 0:
- break;
- default:
- bitmap_file_kick(bitmap);
- }
- }
+ if (need_write)
+ write_page(bitmap, page, 0);
continue;
}
@@ -1048,13 +1084,11 @@ int bitmap_daemon_work(struct bitmap *bitmap)
if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
- err = write_page(bitmap, lastpage, 0);
+ write_page(bitmap, lastpage, 0);
} else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
}
- if (err)
- bitmap_file_kick(bitmap);
} else
spin_unlock_irqrestore(&bitmap->lock, flags);
lastpage = page;
@@ -1097,14 +1131,13 @@ int bitmap_daemon_work(struct bitmap *bitmap)
if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
- err = write_page(bitmap, lastpage, 0);
+ write_page(bitmap, lastpage, 0);
} else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
}
}
- return err;
}
static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
@@ -1517,7 +1550,9 @@ int bitmap_create(mddev_t *mddev)
mddev->thread->timeout = bitmap->daemon_sleep * HZ;
- return bitmap_update_sb(bitmap);
+ bitmap_update_sb(bitmap);
+
+ return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;
error:
bitmap_free(bitmap);
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index c6be88826fae..16ee3b018b3a 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -8,7 +8,6 @@
#define DM_BIO_LIST_H
#include <linux/bio.h>
-#include <linux/prefetch.h>
struct bio_list {
struct bio *head;
@@ -31,8 +30,7 @@ static inline void bio_list_init(struct bio_list *bl)
}
#define bio_list_for_each(bio, bl) \
- for (bio = (bl)->head; bio && ({ prefetch(bio->bi_next); 1; }); \
- bio = bio->bi_next)
+ for (bio = (bl)->head; bio; bio = bio->bi_next)
static inline unsigned bio_list_size(const struct bio_list *bl)
{
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 7b0fcfc9eaa5..bdc52d6922b7 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -30,7 +30,7 @@
/*
* per bio private data
*/
-struct crypt_io {
+struct dm_crypt_io {
struct dm_target *target;
struct bio *base_bio;
struct work_struct work;
@@ -106,7 +106,7 @@ struct crypt_config {
static struct kmem_cache *_crypt_io_pool;
-static void clone_init(struct crypt_io *, struct bio *);
+static void clone_init(struct dm_crypt_io *, struct bio *);
/*
* Different IV generation algorithms:
@@ -382,7 +382,7 @@ static int crypt_convert(struct crypt_config *cc,
static void dm_crypt_bio_destructor(struct bio *bio)
{
- struct crypt_io *io = bio->bi_private;
+ struct dm_crypt_io *io = bio->bi_private;
struct crypt_config *cc = io->target->private;
bio_free(bio, cc->bs);
@@ -393,7 +393,7 @@ static int crypt_convert(struct crypt_config *cc,
* This should never violate the device limitations
* May return a smaller bio when running out of pages
*/
-static struct bio *crypt_alloc_buffer(struct crypt_io *io, unsigned int size)
+static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
{
struct crypt_config *cc = io->target->private;
struct bio *clone;
@@ -479,7 +479,7 @@ static void crypt_free_buffer_pages(struct crypt_config *cc,
* One of the bios was finished. Check for completion of
* the whole request and correctly clean up the buffer.
*/
-static void dec_pending(struct crypt_io *io, int error)
+static void dec_pending(struct dm_crypt_io *io, int error)
{
struct crypt_config *cc = (struct crypt_config *) io->target->private;
@@ -503,7 +503,7 @@ static void dec_pending(struct crypt_io *io, int error)
static struct workqueue_struct *_kcryptd_workqueue;
static void kcryptd_do_work(struct work_struct *work);
-static void kcryptd_queue_io(struct crypt_io *io)
+static void kcryptd_queue_io(struct dm_crypt_io *io)
{
INIT_WORK(&io->work, kcryptd_do_work);
queue_work(_kcryptd_workqueue, &io->work);
@@ -511,7 +511,7 @@ static void kcryptd_queue_io(struct crypt_io *io)
static int crypt_endio(struct bio *clone, unsigned int done, int error)
{
- struct crypt_io *io = clone->bi_private;
+ struct dm_crypt_io *io = clone->bi_private;
struct crypt_config *cc = io->target->private;
unsigned read_io = bio_data_dir(clone) == READ;
@@ -545,7 +545,7 @@ out:
return error;
}
-static void clone_init(struct crypt_io *io, struct bio *clone)
+static void clone_init(struct dm_crypt_io *io, struct bio *clone)
{
struct crypt_config *cc = io->target->private;
@@ -556,7 +556,7 @@ static void clone_init(struct crypt_io *io, struct bio *clone)
clone->bi_destructor = dm_crypt_bio_destructor;
}
-static void process_read(struct crypt_io *io)
+static void process_read(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->target->private;
struct bio *base_bio = io->base_bio;
@@ -587,7 +587,7 @@ static void process_read(struct crypt_io *io)
generic_make_request(clone);
}
-static void process_write(struct crypt_io *io)
+static void process_write(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->target->private;
struct bio *base_bio = io->base_bio;
@@ -644,7 +644,7 @@ static void process_write(struct crypt_io *io)
}
}
-static void process_read_endio(struct crypt_io *io)
+static void process_read_endio(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->target->private;
struct convert_context ctx;
@@ -657,7 +657,7 @@ static void process_read_endio(struct crypt_io *io)
static void kcryptd_do_work(struct work_struct *work)
{
- struct crypt_io *io = container_of(work, struct crypt_io, work);
+ struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
if (io->post_process)
process_read_endio(io);
@@ -920,6 +920,8 @@ static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = (struct crypt_config *) ti->private;
+ flush_workqueue(_kcryptd_workqueue);
+
bioset_free(cc->bs);
mempool_destroy(cc->page_pool);
mempool_destroy(cc->io_pool);
@@ -939,10 +941,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
struct crypt_config *cc = ti->private;
- struct crypt_io *io;
-
- if (bio_barrier(bio))
- return -EOPNOTSUPP;
+ struct dm_crypt_io *io;
io = mempool_alloc(cc->io_pool, GFP_NOIO);
io->target = ti;
@@ -1062,9 +1061,7 @@ static int __init dm_crypt_init(void)
{
int r;
- _crypt_io_pool = kmem_cache_create("dm-crypt_io",
- sizeof(struct crypt_io),
- 0, 0, NULL, NULL);
+ _crypt_io_pool = KMEM_CACHE(dm_crypt_io, 0);
if (!_crypt_io_pool)
return -ENOMEM;
diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c
index 52c7cf9e5803..6928c136d3c5 100644
--- a/drivers/md/dm-delay.c
+++ b/drivers/md/dm-delay.c
@@ -20,7 +20,7 @@
struct delay_c {
struct timer_list delay_timer;
- struct semaphore timer_lock;
+ struct mutex timer_lock;
struct work_struct flush_expired_bios;
struct list_head delayed_bios;
atomic_t may_delay;
@@ -37,7 +37,7 @@ struct delay_c {
unsigned writes;
};
-struct delay_info {
+struct dm_delay_info {
struct delay_c *context;
struct list_head list;
struct bio *bio;
@@ -58,12 +58,12 @@ static void handle_delayed_timer(unsigned long data)
static void queue_timeout(struct delay_c *dc, unsigned long expires)
{
- down(&dc->timer_lock);
+ mutex_lock(&dc->timer_lock);
if (!timer_pending(&dc->delay_timer) || expires < dc->delay_timer.expires)
mod_timer(&dc->delay_timer, expires);
- up(&dc->timer_lock);
+ mutex_unlock(&dc->timer_lock);
}
static void flush_bios(struct bio *bio)
@@ -80,7 +80,7 @@ static void flush_bios(struct bio *bio)
static struct bio *flush_delayed_bios(struct delay_c *dc, int flush_all)
{
- struct delay_info *delayed, *next;
+ struct dm_delay_info *delayed, *next;
unsigned long next_expires = 0;
int start_timer = 0;
BIO_LIST(flush_bios);
@@ -193,13 +193,11 @@ out:
goto bad;
}
- init_timer(&dc->delay_timer);
- dc->delay_timer.function = handle_delayed_timer;
- dc->delay_timer.data = (unsigned long)dc;
+ setup_timer(&dc->delay_timer, handle_delayed_timer, (unsigned long)dc);
INIT_WORK(&dc->flush_expired_bios, flush_expired_bios);
INIT_LIST_HEAD(&dc->delayed_bios);
- init_MUTEX(&dc->timer_lock);
+ mutex_init(&dc->timer_lock);
atomic_set(&dc->may_delay, 1);
ti->private = dc;
@@ -227,7 +225,7 @@ static void delay_dtr(struct dm_target *ti)
static int delay_bio(struct delay_c *dc, int delay, struct bio *bio)
{
- struct delay_info *delayed;
+ struct dm_delay_info *delayed;
unsigned long expires = 0;
if (!delay || !atomic_read(&dc->may_delay))
@@ -338,10 +336,7 @@ static int __init dm_delay_init(void)
goto bad_queue;
}
- delayed_cache = kmem_cache_create("dm-delay",
- sizeof(struct delay_info),
- __alignof__(struct delay_info),
- 0, NULL, NULL);
+ delayed_cache = KMEM_CACHE(dm_delay_info, 0);
if (!delayed_cache) {
DMERR("Couldn't create delayed bio cache.");
goto bad_memcache;
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 07e0a0c84f6e..8fe81e1807e0 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -125,9 +125,11 @@ struct pstore {
uint32_t callback_count;
struct commit_callback *callbacks;
struct dm_io_client *io_client;
+
+ struct workqueue_struct *metadata_wq;
};
-static inline unsigned int sectors_to_pages(unsigned int sectors)
+static unsigned sectors_to_pages(unsigned sectors)
{
return sectors / (PAGE_SIZE >> 9);
}
@@ -156,10 +158,24 @@ static void free_area(struct pstore *ps)
ps->area = NULL;
}
+struct mdata_req {
+ struct io_region *where;
+ struct dm_io_request *io_req;
+ struct work_struct work;
+ int result;
+};
+
+static void do_metadata(struct work_struct *work)
+{
+ struct mdata_req *req = container_of(work, struct mdata_req, work);
+
+ req->result = dm_io(req->io_req, 1, req->where, NULL);
+}
+
/*
* Read or write a chunk aligned and sized block of data from a device.
*/
-static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
+static int chunk_io(struct pstore *ps, uint32_t chunk, int rw, int metadata)
{
struct io_region where = {
.bdev = ps->snap->cow->bdev,
@@ -173,8 +189,23 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
.client = ps->io_client,
.notify.fn = NULL,
};
+ struct mdata_req req;
+
+ if (!metadata)
+ return dm_io(&io_req, 1, &where, NULL);
+
+ req.where = &where;
+ req.io_req = &io_req;
- return dm_io(&io_req, 1, &where, NULL);
+ /*
+ * Issue the synchronous I/O from a different thread
+ * to avoid generic_make_request recursion.
+ */
+ INIT_WORK(&req.work, do_metadata);
+ queue_work(ps->metadata_wq, &req.work);
+ flush_workqueue(ps->metadata_wq);
+
+ return req.result;
}
/*
@@ -189,7 +220,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw)
/* convert a metadata area index to a chunk index */
chunk = 1 + ((ps->exceptions_per_area + 1) * area);
- r = chunk_io(ps, chunk, rw);
+ r = chunk_io(ps, chunk, rw, 0);
if (r)
return r;
@@ -230,7 +261,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
if (r)
return r;
- r = chunk_io(ps, 0, READ);
+ r = chunk_io(ps, 0, READ, 1);
if (r)
goto bad;
@@ -292,7 +323,7 @@ static int write_header(struct pstore *ps)
dh->version = cpu_to_le32(ps->version);
dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);
- return chunk_io(ps, 0, WRITE);
+ return chunk_io(ps, 0, WRITE, 1);
}
/*
@@ -393,7 +424,7 @@ static int read_exceptions(struct pstore *ps)
return 0;
}
-static inline struct pstore *get_info(struct exception_store *store)
+static struct pstore *get_info(struct exception_store *store)
{
return (struct pstore *) store->context;
}
@@ -409,6 +440,7 @@ static void persistent_destroy(struct exception_store *store)
{
struct pstore *ps = get_info(store);
+ destroy_workqueue(ps->metadata_wq);
dm_io_client_destroy(ps->io_client);
vfree(ps->callbacks);
free_area(ps);
@@ -457,11 +489,6 @@ static int persistent_read_metadata(struct exception_store *store)
/*
* Sanity checks.
*/
- if (!ps->valid) {
- DMWARN("snapshot is marked invalid");
- return -EINVAL;
- }
-
if (ps->version != SNAPSHOT_DISK_VERSION) {
DMWARN("unable to handle snapshot disk version %d",
ps->version);
@@ -469,6 +496,12 @@ static int persistent_read_metadata(struct exception_store *store)
}
/*
+ * Metadata are valid, but snapshot is invalidated
+ */
+ if (!ps->valid)
+ return 1;
+
+ /*
* Read the metadata.
*/
r = read_exceptions(ps);
@@ -480,7 +513,7 @@ static int persistent_read_metadata(struct exception_store *store)
}
static int persistent_prepare(struct exception_store *store,
- struct exception *e)
+ struct dm_snap_exception *e)
{
struct pstore *ps = get_info(store);
uint32_t stride;
@@ -505,7 +538,7 @@ static int persistent_prepare(struct exception_store *store,
}
static void persistent_commit(struct exception_store *store,
- struct exception *e,
+ struct dm_snap_exception *e,
void (*callback) (void *, int success),
void *callback_context)
{
@@ -588,6 +621,13 @@ int dm_create_persistent(struct exception_store *store)
atomic_set(&ps->pending_count, 0);
ps->callbacks = NULL;
+ ps->metadata_wq = create_singlethread_workqueue("ksnaphd");
+ if (!ps->metadata_wq) {
+ kfree(ps);
+ DMERR("couldn't start header metadata update thread");
+ return -ENOMEM;
+ }
+
store->destroy = persistent_destroy;
store->read_metadata = persistent_read_metadata;
store->prepare_exception = persistent_prepare;
@@ -616,7 +656,8 @@ static int transient_read_metadata(struct exception_store *store)
return 0;
}
-static int transient_prepare(struct exception_store *store, struct exception *e)
+static int transient_prepare(struct exception_store *store,
+ struct dm_snap_exception *e)
{
struct transient_c *tc = (struct transient_c *) store->context;
sector_t size = get_dev_size(store->snap->cow->bdev);
@@ -631,9 +672,9 @@ static int transient_prepare(struct exception_store *store, struct exception *e)
}
static void transient_commit(struct exception_store *store,
- struct exception *e,
- void (*callback) (void *, int success),
- void *callback_context)
+ struct dm_snap_exception *e,
+ void (*callback) (void *, int success),
+ void *callback_context)
{
/* Just succeed */
callback(callback_context, 1);
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 352c6fbeac53..f3a772486437 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -293,7 +293,10 @@ static void do_region(int rw, unsigned int region, struct io_region *where,
* bvec for bio_get/set_region() and decrement bi_max_vecs
* to hide it from bio_add_page().
*/
- num_bvecs = (remaining / (PAGE_SIZE >> SECTOR_SHIFT)) + 2;
+ num_bvecs = dm_sector_div_up(remaining,
+ (PAGE_SIZE >> SECTOR_SHIFT));
+ num_bvecs = 1 + min_t(int, bio_get_nr_vecs(where->bdev),
+ num_bvecs);
bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
bio->bi_sector = where->sector + (where->count - remaining);
bio->bi_bdev = where->bdev;
diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c
new file mode 100644
index 000000000000..8b776b8cb7f7
--- /dev/null
+++ b/drivers/md/dm-mpath-rdac.c
@@ -0,0 +1,700 @@
+/*
+ * Engenio/LSI RDAC DM HW handler
+ *
+ * Copyright (C) 2005 Mike Christie. All rights reserved.
+ * Copyright (C) Chandra Seetharaman, IBM Corp. 2007
+ *
+ * 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 <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_eh.h>
+
+#define DM_MSG_PREFIX "multipath rdac"
+
+#include "dm.h"
+#include "dm-hw-handler.h"
+
+#define RDAC_DM_HWH_NAME "rdac"
+#define RDAC_DM_HWH_VER "0.4"
+
+/*
+ * LSI mode page stuff
+ *
+ * These struct definitions and the forming of the
+ * mode page were taken from the LSI RDAC 2.4 GPL'd
+ * driver, and then converted to Linux conventions.
+ */
+#define RDAC_QUIESCENCE_TIME 20;
+/*
+ * Page Codes
+ */
+#define RDAC_PAGE_CODE_REDUNDANT_CONTROLLER 0x2c
+
+/*
+ * Controller modes definitions
+ */
+#define RDAC_MODE_TRANSFER_ALL_LUNS 0x01
+#define RDAC_MODE_TRANSFER_SPECIFIED_LUNS 0x02
+
+/*
+ * RDAC Options field
+ */
+#define RDAC_FORCED_QUIESENCE 0x02
+
+#define RDAC_FAILOVER_TIMEOUT (60 * HZ)
+
+struct rdac_mode_6_hdr {
+ u8 data_len;
+ u8 medium_type;
+ u8 device_params;
+ u8 block_desc_len;
+};
+
+struct rdac_mode_10_hdr {
+ u16 data_len;
+ u8 medium_type;
+ u8 device_params;
+ u16 reserved;
+ u16 block_desc_len;
+};
+
+struct rdac_mode_common {
+ u8 controller_serial[16];
+ u8 alt_controller_serial[16];
+ u8 rdac_mode[2];
+ u8 alt_rdac_mode[2];
+ u8 quiescence_timeout;
+ u8 rdac_options;
+};
+
+struct rdac_pg_legacy {
+ struct rdac_mode_6_hdr hdr;
+ u8 page_code;
+ u8 page_len;
+ struct rdac_mode_common common;
+#define MODE6_MAX_LUN 32
+ u8 lun_table[MODE6_MAX_LUN];
+ u8 reserved2[32];
+ u8 reserved3;
+ u8 reserved4;
+};
+
+struct rdac_pg_expanded {
+ struct rdac_mode_10_hdr hdr;
+ u8 page_code;
+ u8 subpage_code;
+ u8 page_len[2];
+ struct rdac_mode_common common;
+ u8 lun_table[256];
+ u8 reserved3;
+ u8 reserved4;
+};
+
+struct c9_inquiry {
+ u8 peripheral_info;
+ u8 page_code; /* 0xC9 */
+ u8 reserved1;
+ u8 page_len;
+ u8 page_id[4]; /* "vace" */
+ u8 avte_cvp;
+ u8 path_prio;
+ u8 reserved2[38];
+};
+
+#define SUBSYS_ID_LEN 16
+#define SLOT_ID_LEN 2
+
+struct c4_inquiry {
+ u8 peripheral_info;
+ u8 page_code; /* 0xC4 */
+ u8 reserved1;
+ u8 page_len;
+ u8 page_id[4]; /* "subs" */
+ u8 subsys_id[SUBSYS_ID_LEN];
+ u8 revision[4];
+ u8 slot_id[SLOT_ID_LEN];
+ u8 reserved[2];
+};
+
+struct rdac_controller {
+ u8 subsys_id[SUBSYS_ID_LEN];
+ u8 slot_id[SLOT_ID_LEN];
+ int use_10_ms;
+ struct kref kref;
+ struct list_head node; /* list of all controllers */
+ spinlock_t lock;
+ int submitted;
+ struct list_head cmd_list; /* list of commands to be submitted */
+ union {
+ struct rdac_pg_legacy legacy;
+ struct rdac_pg_expanded expanded;
+ } mode_select;
+};
+struct c8_inquiry {
+ u8 peripheral_info;
+ u8 page_code; /* 0xC8 */
+ u8 reserved1;
+ u8 page_len;
+ u8 page_id[4]; /* "edid" */
+ u8 reserved2[3];
+ u8 vol_uniq_id_len;
+ u8 vol_uniq_id[16];
+ u8 vol_user_label_len;
+ u8 vol_user_label[60];
+ u8 array_uniq_id_len;
+ u8 array_unique_id[16];
+ u8 array_user_label_len;
+ u8 array_user_label[60];
+ u8 lun[8];
+};
+
+struct c2_inquiry {
+ u8 peripheral_info;
+ u8 page_code; /* 0xC2 */
+ u8 reserved1;
+ u8 page_len;
+ u8 page_id[4]; /* "swr4" */
+ u8 sw_version[3];
+ u8 sw_date[3];
+ u8 features_enabled;
+ u8 max_lun_supported;
+ u8 partitions[239]; /* Total allocation length should be 0xFF */
+};
+
+struct rdac_handler {
+ struct list_head entry; /* list waiting to submit MODE SELECT */
+ unsigned timeout;
+ struct rdac_controller *ctlr;
+#define UNINITIALIZED_LUN (1 << 8)
+ unsigned lun;
+ unsigned char sense[SCSI_SENSE_BUFFERSIZE];
+ struct dm_path *path;
+ struct work_struct work;
+#define SEND_C2_INQUIRY 1
+#define SEND_C4_INQUIRY 2
+#define SEND_C8_INQUIRY 3
+#define SEND_C9_INQUIRY 4
+#define SEND_MODE_SELECT 5
+ int cmd_to_send;
+ union {
+ struct c2_inquiry c2;
+ struct c4_inquiry c4;
+ struct c8_inquiry c8;
+ struct c9_inquiry c9;
+ } inq;
+};
+
+static LIST_HEAD(ctlr_list);
+static DEFINE_SPINLOCK(list_lock);
+static struct workqueue_struct *rdac_wkqd;
+
+static inline int had_failures(struct request *req, int error)
+{
+ return (error || host_byte(req->errors) != DID_OK ||
+ msg_byte(req->errors) != COMMAND_COMPLETE);
+}
+
+static void rdac_resubmit_all(struct rdac_handler *h)
+{
+ struct rdac_controller *ctlr = h->ctlr;
+ struct rdac_handler *tmp, *h1;
+
+ spin_lock(&ctlr->lock);
+ list_for_each_entry_safe(h1, tmp, &ctlr->cmd_list, entry) {
+ h1->cmd_to_send = SEND_C9_INQUIRY;
+ queue_work(rdac_wkqd, &h1->work);
+ list_del(&h1->entry);
+ }
+ ctlr->submitted = 0;
+ spin_unlock(&ctlr->lock);
+}
+
+static void mode_select_endio(struct request *req, int error)
+{
+ struct rdac_handler *h = req->end_io_data;
+ struct scsi_sense_hdr sense_hdr;
+ int sense = 0, fail = 0;
+
+ if (had_failures(req, error)) {
+ fail = 1;
+ goto failed;
+ }
+
+ if (status_byte(req->errors) == CHECK_CONDITION) {
+ scsi_normalize_sense(req->sense, SCSI_SENSE_BUFFERSIZE,
+ &sense_hdr);
+ sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) |
+ sense_hdr.ascq;
+ /* If it is retryable failure, submit the c9 inquiry again */
+ if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 ||
+ sense == 0x62900) {
+ /* 0x59136 - Command lock contention
+ * 0x[6b]8b02 - Quiesense in progress or achieved
+ * 0x62900 - Power On, Reset, or Bus Device Reset
+ */
+ h->cmd_to_send = SEND_C9_INQUIRY;
+ queue_work(rdac_wkqd, &h->work);
+ goto done;
+ }
+ if (sense)
+ DMINFO("MODE_SELECT failed on %s with sense 0x%x",
+ h->path->dev->name, sense);
+ }
+failed:
+ if (fail || sense)
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+ else
+ dm_pg_init_complete(h->path, 0);
+
+done:
+ rdac_resubmit_all(h);
+ __blk_put_request(req->q, req);
+}
+
+static struct request *get_rdac_req(struct rdac_handler *h,
+ void *buffer, unsigned buflen, int rw)
+{
+ struct request *rq;
+ struct request_queue *q = bdev_get_queue(h->path->dev->bdev);
+
+ rq = blk_get_request(q, rw, GFP_KERNEL);
+
+ if (!rq) {
+ DMINFO("get_rdac_req: blk_get_request failed");
+ return NULL;
+ }
+
+ if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) {
+ blk_put_request(rq);
+ DMINFO("get_rdac_req: blk_rq_map_kern failed");
+ return NULL;
+ }
+
+ memset(&rq->cmd, 0, BLK_MAX_CDB);
+ rq->sense = h->sense;
+ memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
+ rq->sense_len = 0;
+
+ rq->end_io_data = h;
+ rq->timeout = h->timeout;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->cmd_flags = REQ_FAILFAST | REQ_NOMERGE;
+ return rq;
+}
+
+static struct request *rdac_failover_get(struct rdac_handler *h)
+{
+ struct request *rq;
+ struct rdac_mode_common *common;
+ unsigned data_size;
+
+ if (h->ctlr->use_10_ms) {
+ struct rdac_pg_expanded *rdac_pg;
+
+ data_size = sizeof(struct rdac_pg_expanded);
+ rdac_pg = &h->ctlr->mode_select.expanded;
+ memset(rdac_pg, 0, data_size);
+ common = &rdac_pg->common;
+ rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40;
+ rdac_pg->subpage_code = 0x1;
+ rdac_pg->page_len[0] = 0x01;
+ rdac_pg->page_len[1] = 0x28;
+ rdac_pg->lun_table[h->lun] = 0x81;
+ } else {
+ struct rdac_pg_legacy *rdac_pg;
+
+ data_size = sizeof(struct rdac_pg_legacy);
+ rdac_pg = &h->ctlr->mode_select.legacy;
+ memset(rdac_pg, 0, data_size);
+ common = &rdac_pg->common;
+ rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER;
+ rdac_pg->page_len = 0x68;
+ rdac_pg->lun_table[h->lun] = 0x81;
+ }
+ common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS;
+ common->quiescence_timeout = RDAC_QUIESCENCE_TIME;
+ common->rdac_options = RDAC_FORCED_QUIESENCE;
+
+ /* get request for block layer packet command */
+ rq = get_rdac_req(h, &h->ctlr->mode_select, data_size, WRITE);
+ if (!rq) {
+ DMERR("rdac_failover_get: no rq");
+ return NULL;
+ }
+
+ /* Prepare the command. */
+ if (h->ctlr->use_10_ms) {
+ rq->cmd[0] = MODE_SELECT_10;
+ rq->cmd[7] = data_size >> 8;
+ rq->cmd[8] = data_size & 0xff;
+ } else {
+ rq->cmd[0] = MODE_SELECT;
+ rq->cmd[4] = data_size;
+ }
+ rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
+
+ return rq;
+}
+
+/* Acquires h->ctlr->lock */
+static void submit_mode_select(struct rdac_handler *h)
+{
+ struct request *rq;
+ struct request_queue *q = bdev_get_queue(h->path->dev->bdev);
+
+ spin_lock(&h->ctlr->lock);
+ if (h->ctlr->submitted) {
+ list_add(&h->entry, &h->ctlr->cmd_list);
+ goto drop_lock;
+ }
+
+ if (!q) {
+ DMINFO("submit_mode_select: no queue");
+ goto fail_path;
+ }
+
+ rq = rdac_failover_get(h);
+ if (!rq) {
+ DMERR("submit_mode_select: no rq");
+ goto fail_path;
+ }
+
+ DMINFO("queueing MODE_SELECT command on %s", h->path->dev->name);
+
+ blk_execute_rq_nowait(q, NULL, rq, 1, mode_select_endio);
+ h->ctlr->submitted = 1;
+ goto drop_lock;
+fail_path:
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+drop_lock:
+ spin_unlock(&h->ctlr->lock);
+}
+
+static void release_ctlr(struct kref *kref)
+{
+ struct rdac_controller *ctlr;
+ ctlr = container_of(kref, struct rdac_controller, kref);
+
+ spin_lock(&list_lock);
+ list_del(&ctlr->node);
+ spin_unlock(&list_lock);
+ kfree(ctlr);
+}
+
+static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id)
+{
+ struct rdac_controller *ctlr, *tmp;
+
+ spin_lock(&list_lock);
+
+ list_for_each_entry(tmp, &ctlr_list, node) {
+ if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) &&
+ (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) {
+ kref_get(&tmp->kref);
+ spin_unlock(&list_lock);
+ return tmp;
+ }
+ }
+ ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC);
+ if (!ctlr)
+ goto done;
+
+ /* initialize fields of controller */
+ memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN);
+ memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN);
+ kref_init(&ctlr->kref);
+ spin_lock_init(&ctlr->lock);
+ ctlr->submitted = 0;
+ ctlr->use_10_ms = -1;
+ INIT_LIST_HEAD(&ctlr->cmd_list);
+ list_add(&ctlr->node, &ctlr_list);
+done:
+ spin_unlock(&list_lock);
+ return ctlr;
+}
+
+static void c4_endio(struct request *req, int error)
+{
+ struct rdac_handler *h = req->end_io_data;
+ struct c4_inquiry *sp;
+
+ if (had_failures(req, error)) {
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+ goto done;
+ }
+
+ sp = &h->inq.c4;
+
+ h->ctlr = get_controller(sp->subsys_id, sp->slot_id);
+
+ if (h->ctlr) {
+ h->cmd_to_send = SEND_C9_INQUIRY;
+ queue_work(rdac_wkqd, &h->work);
+ } else
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+done:
+ __blk_put_request(req->q, req);
+}
+
+static void c2_endio(struct request *req, int error)
+{
+ struct rdac_handler *h = req->end_io_data;
+ struct c2_inquiry *sp;
+
+ if (had_failures(req, error)) {
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+ goto done;
+ }
+
+ sp = &h->inq.c2;
+
+ /* If more than MODE6_MAX_LUN luns are supported, use mode select 10 */
+ if (sp->max_lun_supported >= MODE6_MAX_LUN)
+ h->ctlr->use_10_ms = 1;
+ else
+ h->ctlr->use_10_ms = 0;
+
+ h->cmd_to_send = SEND_MODE_SELECT;
+ queue_work(rdac_wkqd, &h->work);
+done:
+ __blk_put_request(req->q, req);
+}
+
+static void c9_endio(struct request *req, int error)
+{
+ struct rdac_handler *h = req->end_io_data;
+ struct c9_inquiry *sp;
+
+ if (had_failures(req, error)) {
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+ goto done;
+ }
+
+ /* We need to look at the sense keys here to take clear action.
+ * For now simple logic: If the host is in AVT mode or if controller
+ * owns the lun, return dm_pg_init_complete(), otherwise submit
+ * MODE SELECT.
+ */
+ sp = &h->inq.c9;
+
+ /* If in AVT mode, return success */
+ if ((sp->avte_cvp >> 7) == 0x1) {
+ dm_pg_init_complete(h->path, 0);
+ goto done;
+ }
+
+ /* If the controller on this path owns the LUN, return success */
+ if (sp->avte_cvp & 0x1) {
+ dm_pg_init_complete(h->path, 0);
+ goto done;
+ }
+
+ if (h->ctlr) {
+ if (h->ctlr->use_10_ms == -1)
+ h->cmd_to_send = SEND_C2_INQUIRY;
+ else
+ h->cmd_to_send = SEND_MODE_SELECT;
+ } else
+ h->cmd_to_send = SEND_C4_INQUIRY;
+ queue_work(rdac_wkqd, &h->work);
+done:
+ __blk_put_request(req->q, req);
+}
+
+static void c8_endio(struct request *req, int error)
+{
+ struct rdac_handler *h = req->end_io_data;
+ struct c8_inquiry *sp;
+
+ if (had_failures(req, error)) {
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+ goto done;
+ }
+
+ /* We need to look at the sense keys here to take clear action.
+ * For now simple logic: Get the lun from the inquiry page.
+ */
+ sp = &h->inq.c8;
+ h->lun = sp->lun[7]; /* currently it uses only one byte */
+ h->cmd_to_send = SEND_C9_INQUIRY;
+ queue_work(rdac_wkqd, &h->work);
+done:
+ __blk_put_request(req->q, req);
+}
+
+static void submit_inquiry(struct rdac_handler *h, int page_code,
+ unsigned int len, rq_end_io_fn endio)
+{
+ struct request *rq;
+ struct request_queue *q = bdev_get_queue(h->path->dev->bdev);
+
+ if (!q)
+ goto fail_path;
+
+ rq = get_rdac_req(h, &h->inq, len, READ);
+ if (!rq)
+ goto fail_path;
+
+ /* Prepare the command. */
+ rq->cmd[0] = INQUIRY;
+ rq->cmd[1] = 1;
+ rq->cmd[2] = page_code;
+ rq->cmd[4] = len;
+ rq->cmd_len = COMMAND_SIZE(INQUIRY);
+ blk_execute_rq_nowait(q, NULL, rq, 1, endio);
+ return;
+
+fail_path:
+ dm_pg_init_complete(h->path, MP_FAIL_PATH);
+}
+
+static void service_wkq(struct work_struct *work)
+{
+ struct rdac_handler *h = container_of(work, struct rdac_handler, work);
+
+ switch (h->cmd_to_send) {
+ case SEND_C2_INQUIRY:
+ submit_inquiry(h, 0xC2, sizeof(struct c2_inquiry), c2_endio);
+ break;
+ case SEND_C4_INQUIRY:
+ submit_inquiry(h, 0xC4, sizeof(struct c4_inquiry), c4_endio);
+ break;
+ case SEND_C8_INQUIRY:
+ submit_inquiry(h, 0xC8, sizeof(struct c8_inquiry), c8_endio);
+ break;
+ case SEND_C9_INQUIRY:
+ submit_inquiry(h, 0xC9, sizeof(struct c9_inquiry), c9_endio);
+ break;
+ case SEND_MODE_SELECT:
+ submit_mode_select(h);
+ break;
+ default:
+ BUG();
+ }
+}
+/*
+ * only support subpage2c until we confirm that this is just a matter of
+ * of updating firmware or not, and RDAC (basic AVT works already) for now
+ * but we can add these in in when we get time and testers
+ */
+static int rdac_create(struct hw_handler *hwh, unsigned argc, char **argv)
+{
+ struct rdac_handler *h;
+ unsigned timeout;
+
+ if (argc == 0) {
+ /* No arguments: use defaults */
+ timeout = RDAC_FAILOVER_TIMEOUT;
+ } else if (argc != 1) {
+ DMWARN("incorrect number of arguments");
+ return -EINVAL;
+ } else {
+ if (sscanf(argv[1], "%u", &timeout) != 1) {
+ DMWARN("invalid timeout value");
+ return -EINVAL;
+ }
+ }
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return -ENOMEM;
+
+ hwh->context = h;
+ h->timeout = timeout;
+ h->lun = UNINITIALIZED_LUN;
+ INIT_WORK(&h->work, service_wkq);
+ DMWARN("using RDAC command with timeout %u", h->timeout);
+
+ return 0;
+}
+
+static void rdac_destroy(struct hw_handler *hwh)
+{
+ struct rdac_handler *h = hwh->context;
+
+ if (h->ctlr)
+ kref_put(&h->ctlr->kref, release_ctlr);
+ kfree(h);
+ hwh->context = NULL;
+}
+
+static unsigned rdac_error(struct hw_handler *hwh, struct bio *bio)
+{
+ /* Try default handler */
+ return dm_scsi_err_handler(hwh, bio);
+}
+
+static void rdac_pg_init(struct hw_handler *hwh, unsigned bypassed,
+ struct dm_path *path)
+{
+ struct rdac_handler *h = hwh->context;
+
+ h->path = path;
+ switch (h->lun) {
+ case UNINITIALIZED_LUN:
+ submit_inquiry(h, 0xC8, sizeof(struct c8_inquiry), c8_endio);
+ break;
+ default:
+ submit_inquiry(h, 0xC9, sizeof(struct c9_inquiry), c9_endio);
+ }
+}
+
+static struct hw_handler_type rdac_handler = {
+ .name = RDAC_DM_HWH_NAME,
+ .module = THIS_MODULE,
+ .create = rdac_create,
+ .destroy = rdac_destroy,
+ .pg_init = rdac_pg_init,
+ .error = rdac_error,
+};
+
+static int __init rdac_init(void)
+{
+ int r = dm_register_hw_handler(&rdac_handler);
+
+ if (r < 0) {
+ DMERR("%s: register failed %d", RDAC_DM_HWH_NAME, r);
+ return r;
+ }
+
+ rdac_wkqd = create_singlethread_workqueue("rdac_wkqd");
+ if (!rdac_wkqd) {
+ DMERR("Failed to create workqueue rdac_wkqd.");
+ dm_unregister_hw_handler(&rdac_handler);
+ return -ENOMEM;
+ }
+
+ DMINFO("%s: version %s loaded", RDAC_DM_HWH_NAME, RDAC_DM_HWH_VER);
+ return 0;
+}
+
+static void __exit rdac_exit(void)
+{
+ int r = dm_unregister_hw_handler(&rdac_handler);
+
+ destroy_workqueue(rdac_wkqd);
+ if (r < 0)
+ DMERR("%s: unregister failed %d", RDAC_DM_HWH_NAME, r);
+}
+
+module_init(rdac_init);
+module_exit(rdac_exit);
+
+MODULE_DESCRIPTION("DM Multipath LSI/Engenio RDAC support");
+MODULE_AUTHOR("Mike Christie, Chandra Seetharaman");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(RDAC_DM_HWH_VER);
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index de54b39e6ffe..d6ca9d0a6fd1 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -83,7 +83,7 @@ struct multipath {
struct work_struct trigger_event;
/*
- * We must use a mempool of mpath_io structs so that we
+ * We must use a mempool of dm_mpath_io structs so that we
* can resubmit bios on error.
*/
mempool_t *mpio_pool;
@@ -92,7 +92,7 @@ struct multipath {
/*
* Context information attached to each bio we process.
*/
-struct mpath_io {
+struct dm_mpath_io {
struct pgpath *pgpath;
struct dm_bio_details details;
};
@@ -122,7 +122,7 @@ static struct pgpath *alloc_pgpath(void)
return pgpath;
}
-static inline void free_pgpath(struct pgpath *pgpath)
+static void free_pgpath(struct pgpath *pgpath)
{
kfree(pgpath);
}
@@ -299,8 +299,8 @@ static int __must_push_back(struct multipath *m)
dm_noflush_suspending(m->ti));
}
-static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio,
- unsigned was_queued)
+static int map_io(struct multipath *m, struct bio *bio,
+ struct dm_mpath_io *mpio, unsigned was_queued)
{
int r = DM_MAPIO_REMAPPED;
unsigned long flags;
@@ -374,7 +374,7 @@ static void dispatch_queued_ios(struct multipath *m)
int r;
unsigned long flags;
struct bio *bio = NULL, *next;
- struct mpath_io *mpio;
+ struct dm_mpath_io *mpio;
union map_info *info;
spin_lock_irqsave(&m->lock, flags);
@@ -795,12 +795,9 @@ static int multipath_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
int r;
- struct mpath_io *mpio;
+ struct dm_mpath_io *mpio;
struct multipath *m = (struct multipath *) ti->private;
- if (bio_barrier(bio))
- return -EOPNOTSUPP;
-
mpio = mempool_alloc(m->mpio_pool, GFP_NOIO);
dm_bio_record(&mpio->details, bio);
@@ -1014,7 +1011,7 @@ void dm_pg_init_complete(struct dm_path *path, unsigned err_flags)
* end_io handling
*/
static int do_end_io(struct multipath *m, struct bio *bio,
- int error, struct mpath_io *mpio)
+ int error, struct dm_mpath_io *mpio)
{
struct hw_handler *hwh = &m->hw_handler;
unsigned err_flags = MP_FAIL_PATH; /* Default behavior */
@@ -1075,8 +1072,8 @@ static int do_end_io(struct multipath *m, struct bio *bio,
static int multipath_end_io(struct dm_target *ti, struct bio *bio,
int error, union map_info *map_context)
{
- struct multipath *m = (struct multipath *) ti->private;
- struct mpath_io *mpio = (struct mpath_io *) map_context->ptr;
+ struct multipath *m = ti->private;
+ struct dm_mpath_io *mpio = map_context->ptr;
struct pgpath *pgpath = mpio->pgpath;
struct path_selector *ps;
int r;
@@ -1346,22 +1343,20 @@ static int __init dm_multipath_init(void)
int r;
/* allocate a slab for the dm_ios */
- _mpio_cache = kmem_cache_create("dm_mpath", sizeof(struct mpath_io),
- 0, 0, NULL, NULL);
+ _mpio_cache = KMEM_CACHE(dm_mpath_io, 0);
if (!_mpio_cache)
return -ENOMEM;
r = dm_register_target(&multipath_target);
if (r < 0) {
- DMERR("%s: register failed %d", multipath_target.name, r);
+ DMERR("register failed %d", r);
kmem_cache_destroy(_mpio_cache);
return -EINVAL;
}
kmultipathd = create_workqueue("kmpathd");
if (!kmultipathd) {
- DMERR("%s: failed to create workqueue kmpathd",
- multipath_target.name);
+ DMERR("failed to create workqueue kmpathd");
dm_unregister_target(&multipath_target);
kmem_cache_destroy(_mpio_cache);
return -ENOMEM;
@@ -1382,8 +1377,7 @@ static void __exit dm_multipath_exit(void)
r = dm_unregister_target(&multipath_target);
if (r < 0)
- DMERR("%s: target unregister failed %d",
- multipath_target.name, r);
+ DMERR("target unregister failed %d", r);
kmem_cache_destroy(_mpio_cache);
}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index ef124b71ccc8..144071e70a93 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -24,6 +24,7 @@
#define DM_IO_PAGES 64
#define DM_RAID1_HANDLE_ERRORS 0x01
+#define errors_handled(p) ((p)->features & DM_RAID1_HANDLE_ERRORS)
static DECLARE_WAIT_QUEUE_HEAD(_kmirrord_recovery_stopped);
@@ -85,6 +86,7 @@ struct region_hash {
struct list_head clean_regions;
struct list_head quiesced_regions;
struct list_head recovered_regions;
+ struct list_head failed_recovered_regions;
};
enum {
@@ -132,6 +134,7 @@ struct mirror_set {
/* recovery */
region_t nr_regions;
int in_sync;
+ int log_failure;
struct mirror *default_mirror; /* Default mirror */
@@ -204,6 +207,7 @@ static int rh_init(struct region_hash *rh, struct mirror_set *ms,
INIT_LIST_HEAD(&rh->clean_regions);
INIT_LIST_HEAD(&rh->quiesced_regions);
INIT_LIST_HEAD(&rh->recovered_regions);
+ INIT_LIST_HEAD(&rh->failed_recovered_regions);
rh->region_pool = mempool_create_kmalloc_pool(MIN_REGIONS,
sizeof(struct region));
@@ -368,6 +372,7 @@ static void rh_update_states(struct region_hash *rh)
LIST_HEAD(clean);
LIST_HEAD(recovered);
+ LIST_HEAD(failed_recovered);
/*
* Quickly grab the lists.
@@ -378,10 +383,8 @@ static void rh_update_states(struct region_hash *rh)
list_splice(&rh->clean_regions, &clean);
INIT_LIST_HEAD(&rh->clean_regions);
- list_for_each_entry (reg, &clean, list) {
- rh->log->type->clear_region(rh->log, reg->key);
+ list_for_each_entry(reg, &clean, list)
list_del(&reg->hash_list);
- }
}
if (!list_empty(&rh->recovered_regions)) {
@@ -391,6 +394,15 @@ static void rh_update_states(struct region_hash *rh)
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_for_each_entry(reg, &failed_recovered, list)
+ list_del(&reg->hash_list);
+ }
+
spin_unlock(&rh->region_lock);
write_unlock_irq(&rh->hash_lock);
@@ -405,10 +417,17 @@ static void rh_update_states(struct region_hash *rh)
mempool_free(reg, rh->region_pool);
}
- rh->log->type->flush(rh->log);
+ list_for_each_entry_safe(reg, next, &failed_recovered, list) {
+ complete_resync_work(reg, errors_handled(rh->ms) ? 0 : 1);
+ mempool_free(reg, rh->region_pool);
+ }
- list_for_each_entry_safe (reg, next, &clean, list)
+ list_for_each_entry_safe(reg, next, &clean, list) {
+ rh->log->type->clear_region(rh->log, reg->key);
mempool_free(reg, rh->region_pool);
+ }
+
+ rh->log->type->flush(rh->log);
}
static void rh_inc(struct region_hash *rh, region_t region)
@@ -555,21 +574,25 @@ static struct region *rh_recovery_start(struct region_hash *rh)
return reg;
}
-/* FIXME: success ignored for now */
static void rh_recovery_end(struct region *reg, int success)
{
struct region_hash *rh = reg->rh;
spin_lock_irq(&rh->region_lock);
- list_add(&reg->list, &reg->rh->recovered_regions);
+ if (success)
+ list_add(&reg->list, &reg->rh->recovered_regions);
+ else {
+ reg->state = RH_NOSYNC;
+ list_add(&reg->list, &reg->rh->failed_recovered_regions);
+ }
spin_unlock_irq(&rh->region_lock);
wake(rh->ms);
}
-static void rh_flush(struct region_hash *rh)
+static int rh_flush(struct region_hash *rh)
{
- rh->log->type->flush(rh->log);
+ return rh->log->type->flush(rh->log);
}
static void rh_delay(struct region_hash *rh, struct bio *bio)
@@ -633,7 +656,14 @@ static void recovery_complete(int read_err, unsigned int write_err,
{
struct region *reg = (struct region *) context;
- /* FIXME: better error handling */
+ if (read_err)
+ /* Read error means the failure of default mirror. */
+ DMERR_LIMIT("Unable to read primary mirror during recovery");
+
+ if (write_err)
+ DMERR_LIMIT("Write error during recovery (error = 0x%x)",
+ write_err);
+
rh_recovery_end(reg, !(read_err || write_err));
}
@@ -863,12 +893,15 @@ static void do_writes(struct mirror_set *ms, struct bio_list *writes)
*/
rh_inc_pending(&ms->rh, &sync);
rh_inc_pending(&ms->rh, &nosync);
- rh_flush(&ms->rh);
+ ms->log_failure = rh_flush(&ms->rh) ? 1 : 0;
/*
* Dispatch io.
*/
- while ((bio = bio_list_pop(&sync)))
+ if (unlikely(ms->log_failure))
+ while ((bio = bio_list_pop(&sync)))
+ bio_endio(bio, bio->bi_size, -EIO);
+ else while ((bio = bio_list_pop(&sync)))
do_write(ms, bio);
while ((bio = bio_list_pop(&recover)))
@@ -918,13 +951,12 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors);
- ms = kmalloc(len, GFP_KERNEL);
+ ms = kzalloc(len, GFP_KERNEL);
if (!ms) {
ti->error = "Cannot allocate mirror context";
return NULL;
}
- memset(ms, 0, len);
spin_lock_init(&ms->lock);
ms->ti = ti;
@@ -1145,6 +1177,15 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argv += args_used;
argc -= args_used;
+ /*
+ * Any read-balancing addition depends on the
+ * DM_RAID1_HANDLE_ERRORS flag being present.
+ * This is because the decision to balance depends
+ * on the sync state of a region. If the above
+ * flag is not present, we ignore errors; and
+ * the sync state may be inaccurate.
+ */
+
if (argc) {
ti->error = "Too many mirror arguments";
free_context(ms, ti, ms->nr_mirrors);
@@ -1288,12 +1329,12 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
for (m = 0; m < ms->nr_mirrors; m++)
DMEMIT("%s ", ms->mirror[m].dev->name);
- DMEMIT("%llu/%llu",
+ DMEMIT("%llu/%llu 0 ",
(unsigned long long)ms->rh.log->type->
get_sync_count(ms->rh.log),
(unsigned long long)ms->nr_regions);
- sz = ms->rh.log->type->status(ms->rh.log, type, result, maxlen);
+ sz += ms->rh.log->type->status(ms->rh.log, type, result+sz, maxlen-sz);
break;
@@ -1335,8 +1376,7 @@ static int __init dm_mirror_init(void)
r = dm_register_target(&mirror_target);
if (r < 0) {
- DMERR("%s: Failed to register mirror target",
- mirror_target.name);
+ DMERR("Failed to register mirror target");
dm_dirty_log_exit();
}
@@ -1349,7 +1389,7 @@ static void __exit dm_mirror_exit(void)
r = dm_unregister_target(&mirror_target);
if (r < 0)
- DMERR("%s: unregister failed %d", mirror_target.name, r);
+ DMERR("unregister failed %d", r);
dm_dirty_log_exit();
}
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index a348a97b65af..391dfa2ad434 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -205,7 +205,7 @@ static void __exit dm_rr_exit(void)
int r = dm_unregister_path_selector(&rr_ps);
if (r < 0)
- DMERR("round-robin: unregister failed %d", r);
+ DMERR("unregister failed %d", r);
}
module_init(dm_rr_init);
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 0821a2b68a73..83ddbfe6b8a4 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -42,8 +42,8 @@
static struct workqueue_struct *ksnapd;
static void flush_queued_bios(struct work_struct *work);
-struct pending_exception {
- struct exception e;
+struct dm_snap_pending_exception {
+ struct dm_snap_exception e;
/*
* Origin buffers waiting for this to complete are held
@@ -63,7 +63,7 @@ struct pending_exception {
* group of pending_exceptions. It is always last to get freed.
* These fields get set up when writing to the origin.
*/
- struct pending_exception *primary_pe;
+ struct dm_snap_pending_exception *primary_pe;
/*
* Number of pending_exceptions processing this chunk.
@@ -137,7 +137,7 @@ static void exit_origin_hash(void)
kfree(_origins);
}
-static inline unsigned int origin_hash(struct block_device *bdev)
+static unsigned origin_hash(struct block_device *bdev)
{
return bdev->bd_dev & ORIGIN_MASK;
}
@@ -231,7 +231,7 @@ static int init_exception_table(struct exception_table *et, uint32_t size)
static void exit_exception_table(struct exception_table *et, struct kmem_cache *mem)
{
struct list_head *slot;
- struct exception *ex, *next;
+ struct dm_snap_exception *ex, *next;
int i, size;
size = et->hash_mask + 1;
@@ -245,18 +245,19 @@ static void exit_exception_table(struct exception_table *et, struct kmem_cache *
vfree(et->table);
}
-static inline uint32_t exception_hash(struct exception_table *et, chunk_t chunk)
+static uint32_t exception_hash(struct exception_table *et, chunk_t chunk)
{
return chunk & et->hash_mask;
}
-static void insert_exception(struct exception_table *eh, struct exception *e)
+static void insert_exception(struct exception_table *eh,
+ struct dm_snap_exception *e)
{
struct list_head *l = &eh->table[exception_hash(eh, e->old_chunk)];
list_add(&e->hash_list, l);
}
-static inline void remove_exception(struct exception *e)
+static void remove_exception(struct dm_snap_exception *e)
{
list_del(&e->hash_list);
}
@@ -265,11 +266,11 @@ static inline void remove_exception(struct exception *e)
* Return the exception data for a sector, or NULL if not
* remapped.
*/
-static struct exception *lookup_exception(struct exception_table *et,
- chunk_t chunk)
+static struct dm_snap_exception *lookup_exception(struct exception_table *et,
+ chunk_t chunk)
{
struct list_head *slot;
- struct exception *e;
+ struct dm_snap_exception *e;
slot = &et->table[exception_hash(et, chunk)];
list_for_each_entry (e, slot, hash_list)
@@ -279,9 +280,9 @@ static struct exception *lookup_exception(struct exception_table *et,
return NULL;
}
-static inline struct exception *alloc_exception(void)
+static struct dm_snap_exception *alloc_exception(void)
{
- struct exception *e;
+ struct dm_snap_exception *e;
e = kmem_cache_alloc(exception_cache, GFP_NOIO);
if (!e)
@@ -290,24 +291,24 @@ static inline struct exception *alloc_exception(void)
return e;
}
-static inline void free_exception(struct exception *e)
+static void free_exception(struct dm_snap_exception *e)
{
kmem_cache_free(exception_cache, e);
}
-static inline struct pending_exception *alloc_pending_exception(void)
+static struct dm_snap_pending_exception *alloc_pending_exception(void)
{
return mempool_alloc(pending_pool, GFP_NOIO);
}
-static inline void free_pending_exception(struct pending_exception *pe)
+static void free_pending_exception(struct dm_snap_pending_exception *pe)
{
mempool_free(pe, pending_pool);
}
int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new)
{
- struct exception *e;
+ struct dm_snap_exception *e;
e = alloc_exception();
if (!e)
@@ -334,7 +335,7 @@ static int calc_max_buckets(void)
/*
* Rounds a number down to a power of 2.
*/
-static inline uint32_t round_down(uint32_t n)
+static uint32_t round_down(uint32_t n)
{
while (n & (n - 1))
n &= (n - 1);
@@ -384,7 +385,7 @@ static int init_hash_tables(struct dm_snapshot *s)
* Round a number up to the nearest 'size' boundary. size must
* be a power of 2.
*/
-static inline ulong round_up(ulong n, ulong size)
+static ulong round_up(ulong n, ulong size)
{
size--;
return (n + size) & ~size;
@@ -522,9 +523,12 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
/* Metadata must only be loaded into one table at once */
r = s->store.read_metadata(&s->store);
- if (r) {
+ if (r < 0) {
ti->error = "Failed to read snapshot metadata";
goto bad6;
+ } else if (r > 0) {
+ s->valid = 0;
+ DMWARN("Snapshot is marked invalid.");
}
bio_list_init(&s->queued_bios);
@@ -577,7 +581,7 @@ static void __free_exceptions(struct dm_snapshot *s)
static void snapshot_dtr(struct dm_target *ti)
{
- struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+ struct dm_snapshot *s = ti->private;
flush_workqueue(ksnapd);
@@ -655,14 +659,14 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
dm_table_event(s->table);
}
-static void get_pending_exception(struct pending_exception *pe)
+static void get_pending_exception(struct dm_snap_pending_exception *pe)
{
atomic_inc(&pe->ref_count);
}
-static struct bio *put_pending_exception(struct pending_exception *pe)
+static struct bio *put_pending_exception(struct dm_snap_pending_exception *pe)
{
- struct pending_exception *primary_pe;
+ struct dm_snap_pending_exception *primary_pe;
struct bio *origin_bios = NULL;
primary_pe = pe->primary_pe;
@@ -692,9 +696,9 @@ static struct bio *put_pending_exception(struct pending_exception *pe)
return origin_bios;
}
-static void pending_complete(struct pending_exception *pe, int success)
+static void pending_complete(struct dm_snap_pending_exception *pe, int success)
{
- struct exception *e;
+ struct dm_snap_exception *e;
struct dm_snapshot *s = pe->snap;
struct bio *origin_bios = NULL;
struct bio *snapshot_bios = NULL;
@@ -748,7 +752,8 @@ static void pending_complete(struct pending_exception *pe, int success)
static void commit_callback(void *context, int success)
{
- struct pending_exception *pe = (struct pending_exception *) context;
+ struct dm_snap_pending_exception *pe = context;
+
pending_complete(pe, success);
}
@@ -758,7 +763,7 @@ static void commit_callback(void *context, int success)
*/
static void copy_callback(int read_err, unsigned int write_err, void *context)
{
- struct pending_exception *pe = (struct pending_exception *) context;
+ struct dm_snap_pending_exception *pe = context;
struct dm_snapshot *s = pe->snap;
if (read_err || write_err)
@@ -773,7 +778,7 @@ static void copy_callback(int read_err, unsigned int write_err, void *context)
/*
* Dispatches the copy operation to kcopyd.
*/
-static void start_copy(struct pending_exception *pe)
+static void start_copy(struct dm_snap_pending_exception *pe)
{
struct dm_snapshot *s = pe->snap;
struct io_region src, dest;
@@ -803,11 +808,11 @@ static void start_copy(struct pending_exception *pe)
* NOTE: a write lock must be held on snap->lock before calling
* this.
*/
-static struct pending_exception *
+static struct dm_snap_pending_exception *
__find_pending_exception(struct dm_snapshot *s, struct bio *bio)
{
- struct exception *e;
- struct pending_exception *pe;
+ struct dm_snap_exception *e;
+ struct dm_snap_pending_exception *pe;
chunk_t chunk = sector_to_chunk(s, bio->bi_sector);
/*
@@ -816,7 +821,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
e = lookup_exception(&s->pending, chunk);
if (e) {
/* cast the exception to a pending exception */
- pe = container_of(e, struct pending_exception, e);
+ pe = container_of(e, struct dm_snap_pending_exception, e);
goto out;
}
@@ -836,7 +841,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
e = lookup_exception(&s->pending, chunk);
if (e) {
free_pending_exception(pe);
- pe = container_of(e, struct pending_exception, e);
+ pe = container_of(e, struct dm_snap_pending_exception, e);
goto out;
}
@@ -860,8 +865,8 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
return pe;
}
-static inline void remap_exception(struct dm_snapshot *s, struct exception *e,
- struct bio *bio)
+static void remap_exception(struct dm_snapshot *s, struct dm_snap_exception *e,
+ struct bio *bio)
{
bio->bi_bdev = s->cow->bdev;
bio->bi_sector = chunk_to_sector(s, e->new_chunk) +
@@ -871,11 +876,11 @@ static inline void remap_exception(struct dm_snapshot *s, struct exception *e,
static int snapshot_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
- struct exception *e;
- struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+ struct dm_snap_exception *e;
+ struct dm_snapshot *s = ti->private;
int r = DM_MAPIO_REMAPPED;
chunk_t chunk;
- struct pending_exception *pe = NULL;
+ struct dm_snap_pending_exception *pe = NULL;
chunk = sector_to_chunk(s, bio->bi_sector);
@@ -884,9 +889,6 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
if (!s->valid)
return -EIO;
- if (unlikely(bio_barrier(bio)))
- return -EOPNOTSUPP;
-
/* FIXME: should only take write lock if we need
* to copy an exception */
down_write(&s->lock);
@@ -945,7 +947,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
static void snapshot_resume(struct dm_target *ti)
{
- struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+ struct dm_snapshot *s = ti->private;
down_write(&s->lock);
s->active = 1;
@@ -955,7 +957,7 @@ static void snapshot_resume(struct dm_target *ti)
static int snapshot_status(struct dm_target *ti, status_type_t type,
char *result, unsigned int maxlen)
{
- struct dm_snapshot *snap = (struct dm_snapshot *) ti->private;
+ struct dm_snapshot *snap = ti->private;
switch (type) {
case STATUSTYPE_INFO:
@@ -999,8 +1001,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
{
int r = DM_MAPIO_REMAPPED, first = 0;
struct dm_snapshot *snap;
- struct exception *e;
- struct pending_exception *pe, *next_pe, *primary_pe = NULL;
+ struct dm_snap_exception *e;
+ struct dm_snap_pending_exception *pe, *next_pe, *primary_pe = NULL;
chunk_t chunk;
LIST_HEAD(pe_queue);
@@ -1147,19 +1149,16 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
static void origin_dtr(struct dm_target *ti)
{
- struct dm_dev *dev = (struct dm_dev *) ti->private;
+ struct dm_dev *dev = ti->private;
dm_put_device(ti, dev);
}
static int origin_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
- struct dm_dev *dev = (struct dm_dev *) ti->private;
+ struct dm_dev *dev = ti->private;
bio->bi_bdev = dev->bdev;
- if (unlikely(bio_barrier(bio)))
- return -EOPNOTSUPP;
-
/* Only tell snapshots if this is a write */
return (bio_rw(bio) == WRITE) ? do_origin(dev, bio) : DM_MAPIO_REMAPPED;
}
@@ -1172,7 +1171,7 @@ static int origin_map(struct dm_target *ti, struct bio *bio,
*/
static void origin_resume(struct dm_target *ti)
{
- struct dm_dev *dev = (struct dm_dev *) ti->private;
+ struct dm_dev *dev = ti->private;
struct dm_snapshot *snap;
struct origin *o;
chunk_t chunk_size = 0;
@@ -1190,7 +1189,7 @@ static void origin_resume(struct dm_target *ti)
static int origin_status(struct dm_target *ti, status_type_t type, char *result,
unsigned int maxlen)
{
- struct dm_dev *dev = (struct dm_dev *) ti->private;
+ struct dm_dev *dev = ti->private;
switch (type) {
case STATUSTYPE_INFO:
@@ -1249,21 +1248,14 @@ static int __init dm_snapshot_init(void)
goto bad2;
}
- exception_cache = kmem_cache_create("dm-snapshot-ex",
- sizeof(struct exception),
- __alignof__(struct exception),
- 0, NULL, NULL);
+ exception_cache = KMEM_CACHE(dm_snap_exception, 0);
if (!exception_cache) {
DMERR("Couldn't create exception cache.");
r = -ENOMEM;
goto bad3;
}
- pending_cache =
- kmem_cache_create("dm-snapshot-in",
- sizeof(struct pending_exception),
- __alignof__(struct pending_exception),
- 0, NULL, NULL);
+ pending_cache = KMEM_CACHE(dm_snap_pending_exception, 0);
if (!pending_cache) {
DMERR("Couldn't create pending cache.");
r = -ENOMEM;
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
index 15fa2ae6cdc2..650e0f1f51d8 100644
--- a/drivers/md/dm-snap.h
+++ b/drivers/md/dm-snap.h
@@ -30,7 +30,7 @@ typedef sector_t chunk_t;
* An exception is used where an old chunk of data has been
* replaced by a new one.
*/
-struct exception {
+struct dm_snap_exception {
struct list_head hash_list;
chunk_t old_chunk;
@@ -58,13 +58,13 @@ struct exception_store {
* Find somewhere to store the next exception.
*/
int (*prepare_exception) (struct exception_store *store,
- struct exception *e);
+ struct dm_snap_exception *e);
/*
* Update the metadata with this exception.
*/
void (*commit_exception) (struct exception_store *store,
- struct exception *e,
+ struct dm_snap_exception *e,
void (*callback) (void *, int success),
void *callback_context);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 2717a355dc5b..846614e676c6 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -45,7 +45,7 @@ struct dm_io {
* One of these is allocated per target within a bio. Hopefully
* this will be simplified out one day.
*/
-struct target_io {
+struct dm_target_io {
struct dm_io *io;
struct dm_target *ti;
union map_info info;
@@ -54,7 +54,7 @@ struct target_io {
union map_info *dm_get_mapinfo(struct bio *bio)
{
if (bio && bio->bi_private)
- return &((struct target_io *)bio->bi_private)->info;
+ return &((struct dm_target_io *)bio->bi_private)->info;
return NULL;
}
@@ -132,14 +132,12 @@ static int __init local_init(void)
int r;
/* allocate a slab for the dm_ios */
- _io_cache = kmem_cache_create("dm_io",
- sizeof(struct dm_io), 0, 0, NULL, NULL);
+ _io_cache = KMEM_CACHE(dm_io, 0);
if (!_io_cache)
return -ENOMEM;
/* allocate a slab for the target ios */
- _tio_cache = kmem_cache_create("dm_tio", sizeof(struct target_io),
- 0, 0, NULL, NULL);
+ _tio_cache = KMEM_CACHE(dm_target_io, 0);
if (!_tio_cache) {
kmem_cache_destroy(_io_cache);
return -ENOMEM;
@@ -163,9 +161,7 @@ static void local_exit(void)
{
kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache);
-
- if (unregister_blkdev(_major, _name) < 0)
- DMERR("unregister_blkdev failed");
+ unregister_blkdev(_major, _name);
_major = 0;
@@ -325,22 +321,22 @@ out:
return r;
}
-static inline struct dm_io *alloc_io(struct mapped_device *md)
+static struct dm_io *alloc_io(struct mapped_device *md)
{
return mempool_alloc(md->io_pool, GFP_NOIO);
}
-static inline void free_io(struct mapped_device *md, struct dm_io *io)
+static void free_io(struct mapped_device *md, struct dm_io *io)
{
mempool_free(io, md->io_pool);
}
-static inline struct target_io *alloc_tio(struct mapped_device *md)
+static struct dm_target_io *alloc_tio(struct mapped_device *md)
{
return mempool_alloc(md->tio_pool, GFP_NOIO);
}
-static inline void free_tio(struct mapped_device *md, struct target_io *tio)
+static void free_tio(struct mapped_device *md, struct dm_target_io *tio)
{
mempool_free(tio, md->tio_pool);
}
@@ -498,7 +494,7 @@ static void dec_pending(struct dm_io *io, int error)
static int clone_endio(struct bio *bio, unsigned int done, int error)
{
int r = 0;
- struct target_io *tio = bio->bi_private;
+ struct dm_target_io *tio = bio->bi_private;
struct mapped_device *md = tio->io->md;
dm_endio_fn endio = tio->ti->type->end_io;
@@ -558,7 +554,7 @@ static sector_t max_io_len(struct mapped_device *md,
}
static void __map_bio(struct dm_target *ti, struct bio *clone,
- struct target_io *tio)
+ struct dm_target_io *tio)
{
int r;
sector_t sector;
@@ -672,7 +668,7 @@ static void __clone_and_map(struct clone_info *ci)
struct bio *clone, *bio = ci->bio;
struct dm_target *ti = dm_table_find_target(ci->map, ci->sector);
sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti);
- struct target_io *tio;
+ struct dm_target_io *tio;
/*
* Allocate a target io object.
@@ -802,6 +798,15 @@ static int dm_request(request_queue_t *q, struct bio *bio)
int rw = bio_data_dir(bio);
struct mapped_device *md = q->queuedata;
+ /*
+ * There is no use in forwarding any barrier request since we can't
+ * guarantee it is (or can be) handled by the targets correctly.
+ */
+ if (unlikely(bio_barrier(bio))) {
+ bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+ return 0;
+ }
+
down_read(&md->io_lock);
disk_stat_inc(dm_disk(md), ios[rw]);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 2f796b1436b2..462ee652a890 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -18,13 +18,45 @@
#define DM_NAME "device-mapper"
-#define DMERR(f, arg...) printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMWARN(f, arg...) printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
-#define DMINFO(f, arg...) printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#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(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) ? \
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index dbc234e3c69f..7e052378c47e 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -29,7 +29,7 @@
static struct workqueue_struct *_kcopyd_wq;
static struct work_struct _kcopyd_work;
-static inline void wake(void)
+static void wake(void)
{
queue_work(_kcopyd_wq, &_kcopyd_work);
}
@@ -226,10 +226,7 @@ static LIST_HEAD(_pages_jobs);
static int jobs_init(void)
{
- _job_cache = kmem_cache_create("kcopyd-jobs",
- sizeof(struct kcopyd_job),
- __alignof__(struct kcopyd_job),
- 0, NULL, NULL);
+ _job_cache = KMEM_CACHE(kcopyd_job, 0);
if (!_job_cache)
return -ENOMEM;
@@ -258,7 +255,7 @@ static void jobs_exit(void)
* Functions to push and pop a job onto the head of a given job
* list.
*/
-static inline struct kcopyd_job *pop(struct list_head *jobs)
+static struct kcopyd_job *pop(struct list_head *jobs)
{
struct kcopyd_job *job = NULL;
unsigned long flags;
@@ -274,7 +271,7 @@ static inline struct kcopyd_job *pop(struct list_head *jobs)
return job;
}
-static inline void push(struct list_head *jobs, struct kcopyd_job *job)
+static void push(struct list_head *jobs, struct kcopyd_job *job)
{
unsigned long flags;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 1c54f3c1cca7..65ddc887dfd7 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1640,7 +1640,6 @@ static void sync_sbs(mddev_t * mddev, int nospares)
static void md_update_sb(mddev_t * mddev, int force_change)
{
- int err;
struct list_head *tmp;
mdk_rdev_t *rdev;
int sync_req;
@@ -1727,7 +1726,7 @@ repeat:
"md: updating %s RAID superblock on device (in sync %d)\n",
mdname(mddev),mddev->in_sync);
- err = bitmap_update_sb(mddev->bitmap);
+ bitmap_update_sb(mddev->bitmap);
ITERATE_RDEV(mddev,rdev,tmp) {
char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: ");
@@ -2073,9 +2072,11 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
err = super_types[super_format].
load_super(rdev, NULL, super_minor);
if (err == -EINVAL) {
- printk(KERN_WARNING
- "md: %s has invalid sb, not importing!\n",
- bdevname(rdev->bdev,b));
+ printk(KERN_WARNING
+ "md: %s does not have a valid v%d.%d "
+ "superblock, not importing!\n",
+ bdevname(rdev->bdev,b),
+ super_format, super_minor);
goto abort_free;
}
if (err < 0) {
@@ -3174,13 +3175,33 @@ static int do_md_run(mddev_t * mddev)
* Drop all container device buffers, from now on
* the only valid external interface is through the md
* device.
- * Also find largest hardsector size
*/
ITERATE_RDEV(mddev,rdev,tmp) {
if (test_bit(Faulty, &rdev->flags))
continue;
sync_blockdev(rdev->bdev);
invalidate_bdev(rdev->bdev);
+
+ /* perform some consistency tests on the device.
+ * We don't want the data to overlap the metadata,
+ * Internal Bitmap issues has handled elsewhere.
+ */
+ if (rdev->data_offset < rdev->sb_offset) {
+ if (mddev->size &&
+ rdev->data_offset + mddev->size*2
+ > rdev->sb_offset*2) {
+ printk("md: %s: data overlaps metadata\n",
+ mdname(mddev));
+ return -EINVAL;
+ }
+ } else {
+ if (rdev->sb_offset*2 + rdev->sb_size/512
+ > rdev->data_offset) {
+ printk("md: %s: metadata overlaps data\n",
+ mdname(mddev));
+ return -EINVAL;
+ }
+ }
}
md_probe(mddev->unit, NULL, NULL);
@@ -4642,7 +4663,6 @@ static int md_thread(void * arg)
* many dirty RAID5 blocks.
*/
- current->flags |= PF_NOFREEZE;
allow_signal(SIGKILL);
while (!kthread_should_stop()) {
@@ -5090,7 +5110,7 @@ static int is_mddev_idle(mddev_t *mddev)
mdk_rdev_t * rdev;
struct list_head *tmp;
int idle;
- unsigned long curr_events;
+ long curr_events;
idle = 1;
ITERATE_RDEV(mddev,rdev,tmp) {
@@ -5098,20 +5118,29 @@ static int is_mddev_idle(mddev_t *mddev)
curr_events = disk_stat_read(disk, sectors[0]) +
disk_stat_read(disk, sectors[1]) -
atomic_read(&disk->sync_io);
- /* The difference between curr_events and last_events
- * will be affected by any new non-sync IO (making
- * curr_events bigger) and any difference in the amount of
- * in-flight syncio (making current_events bigger or smaller)
- * The amount in-flight is currently limited to
- * 32*64K in raid1/10 and 256*PAGE_SIZE in raid5/6
- * which is at most 4096 sectors.
- * These numbers are fairly fragile and should be made
- * more robust, probably by enforcing the
- * 'window size' that md_do_sync sort-of uses.
+ /* sync IO will cause sync_io to increase before the disk_stats
+ * as sync_io is counted when a request starts, and
+ * disk_stats is counted when it completes.
+ * So resync activity will cause curr_events to be smaller than
+ * when there was no such activity.
+ * non-sync IO will cause disk_stat to increase without
+ * increasing sync_io so curr_events will (eventually)
+ * be larger than it was before. Once it becomes
+ * substantially larger, the test below will cause
+ * the array to appear non-idle, and resync will slow
+ * down.
+ * If there is a lot of outstanding resync activity when
+ * we set last_event to curr_events, then all that activity
+ * completing might cause the array to appear non-idle
+ * and resync will be slowed down even though there might
+ * not have been non-resync activity. This will only
+ * happen once though. 'last_events' will soon reflect
+ * the state where there is little or no outstanding
+ * resync requests, and further resync activity will
+ * always make curr_events less than last_events.
*
- * Note: the following is an unsigned comparison.
*/
- if ((long)curr_events - (long)rdev->last_events > 4096) {
+ if (curr_events - rdev->last_events > 4096) {
rdev->last_events = curr_events;
idle = 0;
}
@@ -5772,7 +5801,7 @@ static void autostart_arrays(int part)
for (i = 0; i < dev_cnt; i++) {
dev_t dev = detected_devices[i];
- rdev = md_import_device(dev,0, 0);
+ rdev = md_import_device(dev,0, 90);
if (IS_ERR(rdev))
continue;
@@ -5814,7 +5843,7 @@ static __exit void md_exit(void)
}
}
-module_init(md_init)
+subsys_initcall(md_init);
module_exit(md_exit)
static int get_ro(char *buffer, struct kernel_param *kp)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 46677d7d9980..00c78b77b13d 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1526,8 +1526,7 @@ static void raid1d(mddev_t *mddev)
blk_remove_plug(mddev->queue);
spin_unlock_irqrestore(&conf->device_lock, flags);
/* flush any pending bitmap writes to disk before proceeding w/ I/O */
- if (bitmap_unplug(mddev->bitmap) != 0)
- printk("%s: bitmap file write failed!\n", mdname(mddev));
+ bitmap_unplug(mddev->bitmap);
while (bio) { /* submit pending writes */
struct bio *next = bio->bi_next;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 9eb66c1b523b..a95ada1cfac4 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1510,8 +1510,7 @@ static void raid10d(mddev_t *mddev)
blk_remove_plug(mddev->queue);
spin_unlock_irqrestore(&conf->device_lock, flags);
/* flush any pending bitmap writes to disk before proceeding w/ I/O */
- if (bitmap_unplug(mddev->bitmap) != 0)
- printk("%s: bitmap file write failed!\n", mdname(mddev));
+ bitmap_unplug(mddev->bitmap);
while (bio) { /* submit pending writes */
struct bio *next = bio->bi_next;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 061375ee6592..d90ee145effe 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -52,6 +52,7 @@
#include "raid6.h"
#include <linux/raid/bitmap.h>
+#include <linux/async_tx.h>
/*
* Stripe cache
@@ -80,7 +81,6 @@
/*
* The following can be used to debug the driver
*/
-#define RAID5_DEBUG 0
#define RAID5_PARANOIA 1
#if RAID5_PARANOIA && defined(CONFIG_SMP)
# define CHECK_DEVLOCK() assert_spin_locked(&conf->device_lock)
@@ -88,8 +88,7 @@
# define CHECK_DEVLOCK()
#endif
-#define PRINTK(x...) ((void)(RAID5_DEBUG && printk(x)))
-#if RAID5_DEBUG
+#ifdef DEBUG
#define inline
#define __inline__
#endif
@@ -104,6 +103,23 @@ static inline int raid6_next_disk(int disk, int raid_disks)
disk++;
return (disk < raid_disks) ? disk : 0;
}
+
+static void return_io(struct bio *return_bi)
+{
+ struct bio *bi = return_bi;
+ while (bi) {
+ int bytes = bi->bi_size;
+
+ return_bi = bi->bi_next;
+ bi->bi_next = NULL;
+ bi->bi_size = 0;
+ bi->bi_end_io(bi, bytes,
+ test_bit(BIO_UPTODATE, &bi->bi_flags)
+ ? 0 : -EIO);
+ bi = return_bi;
+ }
+}
+
static void print_raid5_conf (raid5_conf_t *conf);
static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
@@ -125,6 +141,7 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
}
md_wakeup_thread(conf->mddev->thread);
} else {
+ BUG_ON(sh->ops.pending);
if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
atomic_dec(&conf->preread_active_stripes);
if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
@@ -152,7 +169,8 @@ static void release_stripe(struct stripe_head *sh)
static inline void remove_hash(struct stripe_head *sh)
{
- PRINTK("remove_hash(), stripe %llu\n", (unsigned long long)sh->sector);
+ pr_debug("remove_hash(), stripe %llu\n",
+ (unsigned long long)sh->sector);
hlist_del_init(&sh->hash);
}
@@ -161,7 +179,8 @@ static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
{
struct hlist_head *hp = stripe_hash(conf, sh->sector);
- PRINTK("insert_hash(), stripe %llu\n", (unsigned long long)sh->sector);
+ pr_debug("insert_hash(), stripe %llu\n",
+ (unsigned long long)sh->sector);
CHECK_DEVLOCK();
hlist_add_head(&sh->hash, hp);
@@ -224,9 +243,10 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int
BUG_ON(atomic_read(&sh->count) != 0);
BUG_ON(test_bit(STRIPE_HANDLE, &sh->state));
-
+ BUG_ON(sh->ops.pending || sh->ops.ack || sh->ops.complete);
+
CHECK_DEVLOCK();
- PRINTK("init_stripe called, stripe %llu\n",
+ pr_debug("init_stripe called, stripe %llu\n",
(unsigned long long)sh->sector);
remove_hash(sh);
@@ -240,11 +260,11 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int
for (i = sh->disks; i--; ) {
struct r5dev *dev = &sh->dev[i];
- if (dev->toread || dev->towrite || dev->written ||
+ if (dev->toread || dev->read || dev->towrite || dev->written ||
test_bit(R5_LOCKED, &dev->flags)) {
- printk("sector=%llx i=%d %p %p %p %d\n",
+ printk(KERN_ERR "sector=%llx i=%d %p %p %p %p %d\n",
(unsigned long long)sh->sector, i, dev->toread,
- dev->towrite, dev->written,
+ dev->read, dev->towrite, dev->written,
test_bit(R5_LOCKED, &dev->flags));
BUG();
}
@@ -260,11 +280,11 @@ static struct stripe_head *__find_stripe(raid5_conf_t *conf, sector_t sector, in
struct hlist_node *hn;
CHECK_DEVLOCK();
- PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector);
+ pr_debug("__find_stripe, sector %llu\n", (unsigned long long)sector);
hlist_for_each_entry(sh, hn, stripe_hash(conf, sector), hash)
if (sh->sector == sector && sh->disks == disks)
return sh;
- PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector);
+ pr_debug("__stripe %llu not in cache\n", (unsigned long long)sector);
return NULL;
}
@@ -276,7 +296,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
{
struct stripe_head *sh;
- PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector);
+ pr_debug("get_stripe, sector %llu\n", (unsigned long long)sector);
spin_lock_irq(&conf->device_lock);
@@ -324,6 +344,579 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
return sh;
}
+/* test_and_ack_op() ensures that we only dequeue an operation once */
+#define test_and_ack_op(op, pend) \
+do { \
+ if (test_bit(op, &sh->ops.pending) && \
+ !test_bit(op, &sh->ops.complete)) { \
+ if (test_and_set_bit(op, &sh->ops.ack)) \
+ clear_bit(op, &pend); \
+ else \
+ ack++; \
+ } else \
+ clear_bit(op, &pend); \
+} while (0)
+
+/* find new work to run, do not resubmit work that is already
+ * in flight
+ */
+static unsigned long get_stripe_work(struct stripe_head *sh)
+{
+ unsigned long pending;
+ int ack = 0;
+
+ pending = sh->ops.pending;
+
+ test_and_ack_op(STRIPE_OP_BIOFILL, pending);
+ test_and_ack_op(STRIPE_OP_COMPUTE_BLK, pending);
+ test_and_ack_op(STRIPE_OP_PREXOR, pending);
+ test_and_ack_op(STRIPE_OP_BIODRAIN, pending);
+ test_and_ack_op(STRIPE_OP_POSTXOR, pending);
+ test_and_ack_op(STRIPE_OP_CHECK, pending);
+ if (test_and_clear_bit(STRIPE_OP_IO, &sh->ops.pending))
+ ack++;
+
+ sh->ops.count -= ack;
+ BUG_ON(sh->ops.count < 0);
+
+ return pending;
+}
+
+static int
+raid5_end_read_request(struct bio *bi, unsigned int bytes_done, int error);
+static int
+raid5_end_write_request (struct bio *bi, unsigned int bytes_done, int error);
+
+static void ops_run_io(struct stripe_head *sh)
+{
+ raid5_conf_t *conf = sh->raid_conf;
+ int i, disks = sh->disks;
+
+ might_sleep();
+
+ for (i = disks; i--; ) {
+ int rw;
+ struct bio *bi;
+ mdk_rdev_t *rdev;
+ if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
+ rw = WRITE;
+ else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
+ rw = READ;
+ else
+ continue;
+
+ bi = &sh->dev[i].req;
+
+ bi->bi_rw = rw;
+ if (rw == WRITE)
+ bi->bi_end_io = raid5_end_write_request;
+ else
+ bi->bi_end_io = raid5_end_read_request;
+
+ rcu_read_lock();
+ rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && test_bit(Faulty, &rdev->flags))
+ rdev = NULL;
+ if (rdev)
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+
+ if (rdev) {
+ if (test_bit(STRIPE_SYNCING, &sh->state) ||
+ test_bit(STRIPE_EXPAND_SOURCE, &sh->state) ||
+ test_bit(STRIPE_EXPAND_READY, &sh->state))
+ md_sync_acct(rdev->bdev, STRIPE_SECTORS);
+
+ bi->bi_bdev = rdev->bdev;
+ pr_debug("%s: for %llu schedule op %ld on disc %d\n",
+ __FUNCTION__, (unsigned long long)sh->sector,
+ bi->bi_rw, i);
+ atomic_inc(&sh->count);
+ bi->bi_sector = sh->sector + rdev->data_offset;
+ bi->bi_flags = 1 << BIO_UPTODATE;
+ bi->bi_vcnt = 1;
+ bi->bi_max_vecs = 1;
+ bi->bi_idx = 0;
+ bi->bi_io_vec = &sh->dev[i].vec;
+ bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
+ bi->bi_io_vec[0].bv_offset = 0;
+ bi->bi_size = STRIPE_SIZE;
+ bi->bi_next = NULL;
+ if (rw == WRITE &&
+ test_bit(R5_ReWrite, &sh->dev[i].flags))
+ atomic_add(STRIPE_SECTORS,
+ &rdev->corrected_errors);
+ generic_make_request(bi);
+ } else {
+ if (rw == WRITE)
+ set_bit(STRIPE_DEGRADED, &sh->state);
+ pr_debug("skip op %ld on disc %d for sector %llu\n",
+ bi->bi_rw, i, (unsigned long long)sh->sector);
+ clear_bit(R5_LOCKED, &sh->dev[i].flags);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+ }
+}
+
+static struct dma_async_tx_descriptor *
+async_copy_data(int frombio, struct bio *bio, struct page *page,
+ sector_t sector, struct dma_async_tx_descriptor *tx)
+{
+ struct bio_vec *bvl;
+ struct page *bio_page;
+ int i;
+ int page_offset;
+
+ if (bio->bi_sector >= sector)
+ page_offset = (signed)(bio->bi_sector - sector) * 512;
+ else
+ page_offset = (signed)(sector - bio->bi_sector) * -512;
+ bio_for_each_segment(bvl, bio, i) {
+ int len = bio_iovec_idx(bio, i)->bv_len;
+ int clen;
+ int b_offset = 0;
+
+ if (page_offset < 0) {
+ b_offset = -page_offset;
+ page_offset += b_offset;
+ len -= b_offset;
+ }
+
+ if (len > 0 && page_offset + len > STRIPE_SIZE)
+ clen = STRIPE_SIZE - page_offset;
+ else
+ clen = len;
+
+ if (clen > 0) {
+ b_offset += bio_iovec_idx(bio, i)->bv_offset;
+ bio_page = bio_iovec_idx(bio, i)->bv_page;
+ if (frombio)
+ tx = async_memcpy(page, bio_page, page_offset,
+ b_offset, clen,
+ ASYNC_TX_DEP_ACK,
+ tx, NULL, NULL);
+ else
+ tx = async_memcpy(bio_page, page, b_offset,
+ page_offset, clen,
+ ASYNC_TX_DEP_ACK,
+ tx, NULL, NULL);
+ }
+ if (clen < len) /* hit end of page */
+ break;
+ page_offset += len;
+ }
+
+ return tx;
+}
+
+static void ops_complete_biofill(void *stripe_head_ref)
+{
+ struct stripe_head *sh = stripe_head_ref;
+ struct bio *return_bi = NULL;
+ raid5_conf_t *conf = sh->raid_conf;
+ int i, more_to_read = 0;
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ /* clear completed biofills */
+ for (i = sh->disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ /* check if this stripe has new incoming reads */
+ if (dev->toread)
+ more_to_read++;
+
+ /* acknowledge completion of a biofill operation */
+ /* and check if we need to reply to a read request
+ */
+ if (test_bit(R5_Wantfill, &dev->flags) && !dev->toread) {
+ struct bio *rbi, *rbi2;
+ clear_bit(R5_Wantfill, &dev->flags);
+
+ /* The access to dev->read is outside of the
+ * spin_lock_irq(&conf->device_lock), but is protected
+ * by the STRIPE_OP_BIOFILL pending bit
+ */
+ BUG_ON(!dev->read);
+ rbi = dev->read;
+ dev->read = NULL;
+ while (rbi && rbi->bi_sector <
+ dev->sector + STRIPE_SECTORS) {
+ rbi2 = r5_next_bio(rbi, dev->sector);
+ spin_lock_irq(&conf->device_lock);
+ if (--rbi->bi_phys_segments == 0) {
+ rbi->bi_next = return_bi;
+ return_bi = rbi;
+ }
+ spin_unlock_irq(&conf->device_lock);
+ rbi = rbi2;
+ }
+ }
+ }
+ clear_bit(STRIPE_OP_BIOFILL, &sh->ops.ack);
+ clear_bit(STRIPE_OP_BIOFILL, &sh->ops.pending);
+
+ return_io(return_bi);
+
+ if (more_to_read)
+ set_bit(STRIPE_HANDLE, &sh->state);
+ release_stripe(sh);
+}
+
+static void ops_run_biofill(struct stripe_head *sh)
+{
+ struct dma_async_tx_descriptor *tx = NULL;
+ raid5_conf_t *conf = sh->raid_conf;
+ int i;
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ for (i = sh->disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (test_bit(R5_Wantfill, &dev->flags)) {
+ struct bio *rbi;
+ spin_lock_irq(&conf->device_lock);
+ dev->read = rbi = dev->toread;
+ dev->toread = NULL;
+ spin_unlock_irq(&conf->device_lock);
+ while (rbi && rbi->bi_sector <
+ dev->sector + STRIPE_SECTORS) {
+ tx = async_copy_data(0, rbi, dev->page,
+ dev->sector, tx);
+ rbi = r5_next_bio(rbi, dev->sector);
+ }
+ }
+ }
+
+ atomic_inc(&sh->count);
+ async_trigger_callback(ASYNC_TX_DEP_ACK | ASYNC_TX_ACK, tx,
+ ops_complete_biofill, sh);
+}
+
+static void ops_complete_compute5(void *stripe_head_ref)
+{
+ struct stripe_head *sh = stripe_head_ref;
+ int target = sh->ops.target;
+ struct r5dev *tgt = &sh->dev[target];
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ set_bit(R5_UPTODATE, &tgt->flags);
+ BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags));
+ clear_bit(R5_Wantcompute, &tgt->flags);
+ set_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ release_stripe(sh);
+}
+
+static struct dma_async_tx_descriptor *
+ops_run_compute5(struct stripe_head *sh, unsigned long pending)
+{
+ /* kernel stack size limits the total number of disks */
+ int disks = sh->disks;
+ struct page *xor_srcs[disks];
+ int target = sh->ops.target;
+ struct r5dev *tgt = &sh->dev[target];
+ struct page *xor_dest = tgt->page;
+ int count = 0;
+ struct dma_async_tx_descriptor *tx;
+ int i;
+
+ pr_debug("%s: stripe %llu block: %d\n",
+ __FUNCTION__, (unsigned long long)sh->sector, target);
+ BUG_ON(!test_bit(R5_Wantcompute, &tgt->flags));
+
+ for (i = disks; i--; )
+ if (i != target)
+ xor_srcs[count++] = sh->dev[i].page;
+
+ atomic_inc(&sh->count);
+
+ if (unlikely(count == 1))
+ tx = async_memcpy(xor_dest, xor_srcs[0], 0, 0, STRIPE_SIZE,
+ 0, NULL, ops_complete_compute5, sh);
+ else
+ tx = async_xor(xor_dest, xor_srcs, 0, count, STRIPE_SIZE,
+ ASYNC_TX_XOR_ZERO_DST, NULL,
+ ops_complete_compute5, sh);
+
+ /* ack now if postxor is not set to be run */
+ if (tx && !test_bit(STRIPE_OP_POSTXOR, &pending))
+ async_tx_ack(tx);
+
+ return tx;
+}
+
+static void ops_complete_prexor(void *stripe_head_ref)
+{
+ struct stripe_head *sh = stripe_head_ref;
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ set_bit(STRIPE_OP_PREXOR, &sh->ops.complete);
+}
+
+static struct dma_async_tx_descriptor *
+ops_run_prexor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
+{
+ /* kernel stack size limits the total number of disks */
+ int disks = sh->disks;
+ struct page *xor_srcs[disks];
+ int count = 0, pd_idx = sh->pd_idx, i;
+
+ /* existing parity data subtracted */
+ struct page *xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page;
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ /* Only process blocks that are known to be uptodate */
+ if (dev->towrite && test_bit(R5_Wantprexor, &dev->flags))
+ xor_srcs[count++] = dev->page;
+ }
+
+ tx = async_xor(xor_dest, xor_srcs, 0, count, STRIPE_SIZE,
+ ASYNC_TX_DEP_ACK | ASYNC_TX_XOR_DROP_DST, tx,
+ ops_complete_prexor, sh);
+
+ return tx;
+}
+
+static struct dma_async_tx_descriptor *
+ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
+{
+ int disks = sh->disks;
+ int pd_idx = sh->pd_idx, i;
+
+ /* check if prexor is active which means only process blocks
+ * that are part of a read-modify-write (Wantprexor)
+ */
+ int prexor = test_bit(STRIPE_OP_PREXOR, &sh->ops.pending);
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ struct bio *chosen;
+ int towrite;
+
+ towrite = 0;
+ if (prexor) { /* rmw */
+ if (dev->towrite &&
+ test_bit(R5_Wantprexor, &dev->flags))
+ towrite = 1;
+ } else { /* rcw */
+ if (i != pd_idx && dev->towrite &&
+ test_bit(R5_LOCKED, &dev->flags))
+ towrite = 1;
+ }
+
+ if (towrite) {
+ struct bio *wbi;
+
+ spin_lock(&sh->lock);
+ chosen = dev->towrite;
+ dev->towrite = NULL;
+ BUG_ON(dev->written);
+ wbi = dev->written = chosen;
+ spin_unlock(&sh->lock);
+
+ while (wbi && wbi->bi_sector <
+ dev->sector + STRIPE_SECTORS) {
+ tx = async_copy_data(1, wbi, dev->page,
+ dev->sector, tx);
+ wbi = r5_next_bio(wbi, dev->sector);
+ }
+ }
+ }
+
+ return tx;
+}
+
+static void ops_complete_postxor(void *stripe_head_ref)
+{
+ struct stripe_head *sh = stripe_head_ref;
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ set_bit(STRIPE_OP_POSTXOR, &sh->ops.complete);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ release_stripe(sh);
+}
+
+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__,
+ (unsigned long long)sh->sector);
+
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (dev->written || i == pd_idx)
+ set_bit(R5_UPTODATE, &dev->flags);
+ }
+
+ set_bit(STRIPE_OP_BIODRAIN, &sh->ops.complete);
+ set_bit(STRIPE_OP_POSTXOR, &sh->ops.complete);
+
+ set_bit(STRIPE_HANDLE, &sh->state);
+ release_stripe(sh);
+}
+
+static void
+ops_run_postxor(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
+{
+ /* kernel stack size limits the total number of disks */
+ int disks = sh->disks;
+ struct page *xor_srcs[disks];
+
+ int count = 0, pd_idx = sh->pd_idx, i;
+ struct page *xor_dest;
+ int prexor = test_bit(STRIPE_OP_PREXOR, &sh->ops.pending);
+ unsigned long flags;
+ dma_async_tx_callback callback;
+
+ pr_debug("%s: stripe %llu\n", __FUNCTION__,
+ (unsigned long long)sh->sector);
+
+ /* check if prexor is active which means only process blocks
+ * that are part of a read-modify-write (written)
+ */
+ if (prexor) {
+ xor_dest = xor_srcs[count++] = sh->dev[pd_idx].page;
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (dev->written)
+ xor_srcs[count++] = dev->page;
+ }
+ } else {
+ xor_dest = sh->dev[pd_idx].page;
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (i != pd_idx)
+ xor_srcs[count++] = dev->page;
+ }
+ }
+
+ /* check whether this postxor is part of a write */
+ callback = test_bit(STRIPE_OP_BIODRAIN, &sh->ops.pending) ?
+ ops_complete_write : ops_complete_postxor;
+
+ /* 1/ if we prexor'd then the dest is reused as a source
+ * 2/ if we did not prexor then we are redoing the parity
+ * set ASYNC_TX_XOR_DROP_DST and ASYNC_TX_XOR_ZERO_DST
+ * for the synchronous xor case
+ */
+ flags = ASYNC_TX_DEP_ACK | ASYNC_TX_ACK |
+ (prexor ? ASYNC_TX_XOR_DROP_DST : ASYNC_TX_XOR_ZERO_DST);
+
+ atomic_inc(&sh->count);
+
+ if (unlikely(count == 1)) {
+ flags &= ~(ASYNC_TX_XOR_DROP_DST | ASYNC_TX_XOR_ZERO_DST);
+ tx = async_memcpy(xor_dest, xor_srcs[0], 0, 0, STRIPE_SIZE,
+ flags, tx, callback, sh);
+ } else
+ tx = async_xor(xor_dest, xor_srcs, 0, count, STRIPE_SIZE,
+ flags, tx, callback, sh);
+}
+
+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__,
+ (unsigned long long)sh->sector);
+
+ if (test_and_clear_bit(STRIPE_OP_MOD_DMA_CHECK, &sh->ops.pending) &&
+ sh->ops.zero_sum_result == 0)
+ set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
+
+ set_bit(STRIPE_OP_CHECK, &sh->ops.complete);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ release_stripe(sh);
+}
+
+static void ops_run_check(struct stripe_head *sh)
+{
+ /* kernel stack size limits the total number of disks */
+ int disks = sh->disks;
+ struct page *xor_srcs[disks];
+ struct dma_async_tx_descriptor *tx;
+
+ 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__,
+ (unsigned long long)sh->sector);
+
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (i != pd_idx)
+ xor_srcs[count++] = dev->page;
+ }
+
+ tx = async_xor_zero_sum(xor_dest, xor_srcs, 0, count, STRIPE_SIZE,
+ &sh->ops.zero_sum_result, 0, NULL, NULL, NULL);
+
+ if (tx)
+ set_bit(STRIPE_OP_MOD_DMA_CHECK, &sh->ops.pending);
+ else
+ clear_bit(STRIPE_OP_MOD_DMA_CHECK, &sh->ops.pending);
+
+ atomic_inc(&sh->count);
+ tx = async_trigger_callback(ASYNC_TX_DEP_ACK | ASYNC_TX_ACK, tx,
+ ops_complete_check, sh);
+}
+
+static void raid5_run_ops(struct stripe_head *sh, unsigned long pending)
+{
+ int overlap_clear = 0, i, disks = sh->disks;
+ struct dma_async_tx_descriptor *tx = NULL;
+
+ if (test_bit(STRIPE_OP_BIOFILL, &pending)) {
+ ops_run_biofill(sh);
+ overlap_clear++;
+ }
+
+ if (test_bit(STRIPE_OP_COMPUTE_BLK, &pending))
+ tx = ops_run_compute5(sh, pending);
+
+ if (test_bit(STRIPE_OP_PREXOR, &pending))
+ tx = ops_run_prexor(sh, tx);
+
+ if (test_bit(STRIPE_OP_BIODRAIN, &pending)) {
+ tx = ops_run_biodrain(sh, tx);
+ overlap_clear++;
+ }
+
+ if (test_bit(STRIPE_OP_POSTXOR, &pending))
+ ops_run_postxor(sh, tx);
+
+ if (test_bit(STRIPE_OP_CHECK, &pending))
+ ops_run_check(sh);
+
+ if (test_bit(STRIPE_OP_IO, &pending))
+ ops_run_io(sh);
+
+ if (overlap_clear)
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (test_and_clear_bit(R5_Overlap, &dev->flags))
+ wake_up(&sh->raid_conf->wait_for_overlap);
+ }
+}
+
static int grow_one_stripe(raid5_conf_t *conf)
{
struct stripe_head *sh;
@@ -358,7 +951,7 @@ static int grow_stripes(raid5_conf_t *conf, int num)
conf->active_name = 0;
sc = kmem_cache_create(conf->cache_name[conf->active_name],
sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!sc)
return 1;
conf->slab_cache = sc;
@@ -410,7 +1003,7 @@ static int resize_stripes(raid5_conf_t *conf, int newsize)
/* Step 1 */
sc = kmem_cache_create(conf->cache_name[1-conf->active_name],
sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!sc)
return -ENOMEM;
@@ -537,8 +1130,8 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
if (bi == &sh->dev[i].req)
break;
- PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n",
- (unsigned long long)sh->sector, i, atomic_read(&sh->count),
+ pr_debug("end_read_request %llu/%d, count: %d, uptodate %d.\n",
+ (unsigned long long)sh->sector, i, atomic_read(&sh->count),
uptodate);
if (i == disks) {
BUG();
@@ -613,7 +1206,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
if (bi == &sh->dev[i].req)
break;
- PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n",
+ pr_debug("end_write_request %llu/%d, count %d, uptodate: %d.\n",
(unsigned long long)sh->sector, i, atomic_read(&sh->count),
uptodate);
if (i == disks) {
@@ -658,7 +1251,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
{
char b[BDEVNAME_SIZE];
raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
- PRINTK("raid5: error called\n");
+ pr_debug("raid5: error called\n");
if (!test_bit(Faulty, &rdev->flags)) {
set_bit(MD_CHANGE_DEVS, &mddev->flags);
@@ -916,137 +1509,13 @@ static void copy_data(int frombio, struct bio *bio,
}
}
-#define check_xor() do { \
- if (count == MAX_XOR_BLOCKS) { \
- xor_block(count, STRIPE_SIZE, ptr); \
- count = 1; \
- } \
+#define check_xor() do { \
+ if (count == MAX_XOR_BLOCKS) { \
+ xor_blocks(count, STRIPE_SIZE, dest, ptr);\
+ count = 0; \
+ } \
} while(0)
-
-static void compute_block(struct stripe_head *sh, int dd_idx)
-{
- int i, count, disks = sh->disks;
- void *ptr[MAX_XOR_BLOCKS], *p;
-
- PRINTK("compute_block, stripe %llu, idx %d\n",
- (unsigned long long)sh->sector, dd_idx);
-
- ptr[0] = page_address(sh->dev[dd_idx].page);
- memset(ptr[0], 0, STRIPE_SIZE);
- count = 1;
- for (i = disks ; i--; ) {
- if (i == dd_idx)
- continue;
- p = page_address(sh->dev[i].page);
- if (test_bit(R5_UPTODATE, &sh->dev[i].flags))
- ptr[count++] = p;
- else
- printk(KERN_ERR "compute_block() %d, stripe %llu, %d"
- " not present\n", dd_idx,
- (unsigned long long)sh->sector, i);
-
- check_xor();
- }
- if (count != 1)
- xor_block(count, STRIPE_SIZE, ptr);
- set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
-}
-
-static void compute_parity5(struct stripe_head *sh, int method)
-{
- raid5_conf_t *conf = sh->raid_conf;
- int i, pd_idx = sh->pd_idx, disks = sh->disks, count;
- void *ptr[MAX_XOR_BLOCKS];
- struct bio *chosen;
-
- PRINTK("compute_parity5, stripe %llu, method %d\n",
- (unsigned long long)sh->sector, method);
-
- count = 1;
- ptr[0] = page_address(sh->dev[pd_idx].page);
- switch(method) {
- case READ_MODIFY_WRITE:
- BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags));
- for (i=disks ; i-- ;) {
- if (i==pd_idx)
- continue;
- if (sh->dev[i].towrite &&
- test_bit(R5_UPTODATE, &sh->dev[i].flags)) {
- ptr[count++] = page_address(sh->dev[i].page);
- chosen = sh->dev[i].towrite;
- sh->dev[i].towrite = NULL;
-
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
-
- BUG_ON(sh->dev[i].written);
- sh->dev[i].written = chosen;
- check_xor();
- }
- }
- break;
- case RECONSTRUCT_WRITE:
- memset(ptr[0], 0, STRIPE_SIZE);
- for (i= disks; i-- ;)
- if (i!=pd_idx && sh->dev[i].towrite) {
- chosen = sh->dev[i].towrite;
- sh->dev[i].towrite = NULL;
-
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
-
- BUG_ON(sh->dev[i].written);
- sh->dev[i].written = chosen;
- }
- break;
- case CHECK_PARITY:
- break;
- }
- if (count>1) {
- xor_block(count, STRIPE_SIZE, ptr);
- count = 1;
- }
-
- for (i = disks; i--;)
- if (sh->dev[i].written) {
- sector_t sector = sh->dev[i].sector;
- struct bio *wbi = sh->dev[i].written;
- while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) {
- copy_data(1, wbi, sh->dev[i].page, sector);
- wbi = r5_next_bio(wbi, sector);
- }
-
- set_bit(R5_LOCKED, &sh->dev[i].flags);
- set_bit(R5_UPTODATE, &sh->dev[i].flags);
- }
-
- switch(method) {
- case RECONSTRUCT_WRITE:
- case CHECK_PARITY:
- for (i=disks; i--;)
- if (i != pd_idx) {
- ptr[count++] = page_address(sh->dev[i].page);
- check_xor();
- }
- break;
- case READ_MODIFY_WRITE:
- for (i = disks; i--;)
- if (sh->dev[i].written) {
- ptr[count++] = page_address(sh->dev[i].page);
- check_xor();
- }
- }
- if (count != 1)
- xor_block(count, STRIPE_SIZE, ptr);
-
- if (method != CHECK_PARITY) {
- set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
- set_bit(R5_LOCKED, &sh->dev[pd_idx].flags);
- } else
- clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
-}
-
static void compute_parity6(struct stripe_head *sh, int method)
{
raid6_conf_t *conf = sh->raid_conf;
@@ -1058,7 +1527,7 @@ static void compute_parity6(struct stripe_head *sh, int method)
qd_idx = raid6_next_disk(pd_idx, disks);
d0_idx = raid6_next_disk(qd_idx, disks);
- PRINTK("compute_parity, stripe %llu, method %d\n",
+ pr_debug("compute_parity, stripe %llu, method %d\n",
(unsigned long long)sh->sector, method);
switch(method) {
@@ -1132,20 +1601,20 @@ static void compute_parity6(struct stripe_head *sh, int method)
static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
{
int i, count, disks = sh->disks;
- void *ptr[MAX_XOR_BLOCKS], *p;
+ void *ptr[MAX_XOR_BLOCKS], *dest, *p;
int pd_idx = sh->pd_idx;
int qd_idx = raid6_next_disk(pd_idx, disks);
- PRINTK("compute_block_1, stripe %llu, idx %d\n",
+ pr_debug("compute_block_1, stripe %llu, idx %d\n",
(unsigned long long)sh->sector, dd_idx);
if ( dd_idx == qd_idx ) {
/* We're actually computing the Q drive */
compute_parity6(sh, UPDATE_PARITY);
} else {
- ptr[0] = page_address(sh->dev[dd_idx].page);
- if (!nozero) memset(ptr[0], 0, STRIPE_SIZE);
- count = 1;
+ dest = page_address(sh->dev[dd_idx].page);
+ if (!nozero) memset(dest, 0, STRIPE_SIZE);
+ count = 0;
for (i = disks ; i--; ) {
if (i == dd_idx || i == qd_idx)
continue;
@@ -1159,8 +1628,8 @@ static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
check_xor();
}
- if (count != 1)
- xor_block(count, STRIPE_SIZE, ptr);
+ if (count)
+ xor_blocks(count, STRIPE_SIZE, dest, ptr);
if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
}
@@ -1183,7 +1652,7 @@ static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
BUG_ON(faila == failb);
if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; }
- PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n",
+ pr_debug("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n",
(unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb);
if ( failb == disks-1 ) {
@@ -1229,7 +1698,79 @@ static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
}
}
+static int
+handle_write_operations5(struct stripe_head *sh, int rcw, int expand)
+{
+ int i, pd_idx = sh->pd_idx, disks = sh->disks;
+ int locked = 0;
+ if (rcw) {
+ /* if we are not expanding this is a proper write request, and
+ * there will be bios with new data to be drained into the
+ * stripe cache
+ */
+ if (!expand) {
+ set_bit(STRIPE_OP_BIODRAIN, &sh->ops.pending);
+ sh->ops.count++;
+ }
+
+ set_bit(STRIPE_OP_POSTXOR, &sh->ops.pending);
+ sh->ops.count++;
+
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+
+ if (dev->towrite) {
+ set_bit(R5_LOCKED, &dev->flags);
+ if (!expand)
+ clear_bit(R5_UPTODATE, &dev->flags);
+ locked++;
+ }
+ }
+ } else {
+ BUG_ON(!(test_bit(R5_UPTODATE, &sh->dev[pd_idx].flags) ||
+ test_bit(R5_Wantcompute, &sh->dev[pd_idx].flags)));
+
+ set_bit(STRIPE_OP_PREXOR, &sh->ops.pending);
+ set_bit(STRIPE_OP_BIODRAIN, &sh->ops.pending);
+ set_bit(STRIPE_OP_POSTXOR, &sh->ops.pending);
+
+ sh->ops.count += 3;
+
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (i == pd_idx)
+ continue;
+
+ /* For a read-modify write there may be blocks that are
+ * locked for reading while others are ready to be
+ * written so we distinguish these blocks by the
+ * R5_Wantprexor bit
+ */
+ if (dev->towrite &&
+ (test_bit(R5_UPTODATE, &dev->flags) ||
+ test_bit(R5_Wantcompute, &dev->flags))) {
+ set_bit(R5_Wantprexor, &dev->flags);
+ set_bit(R5_LOCKED, &dev->flags);
+ clear_bit(R5_UPTODATE, &dev->flags);
+ locked++;
+ }
+ }
+ }
+
+ /* keep the parity disk locked while asynchronous operations
+ * are in flight
+ */
+ set_bit(R5_LOCKED, &sh->dev[pd_idx].flags);
+ clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
+ locked++;
+
+ pr_debug("%s: stripe %llu locked: %d pending: %lx\n",
+ __FUNCTION__, (unsigned long long)sh->sector,
+ locked, sh->ops.pending);
+
+ return locked;
+}
/*
* Each stripe/dev can have one or more bion attached.
@@ -1242,7 +1783,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
raid5_conf_t *conf = sh->raid_conf;
int firstwrite=0;
- PRINTK("adding bh b#%llu to stripe s#%llu\n",
+ pr_debug("adding bh b#%llu to stripe s#%llu\n",
(unsigned long long)bi->bi_sector,
(unsigned long long)sh->sector);
@@ -1271,7 +1812,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
spin_unlock_irq(&conf->device_lock);
spin_unlock(&sh->lock);
- PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n",
+ pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
(unsigned long long)bi->bi_sector,
(unsigned long long)sh->sector, dd_idx);
@@ -1326,6 +1867,729 @@ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
return pd_idx;
}
+static void
+handle_requests_to_failed_array(raid5_conf_t *conf, struct stripe_head *sh,
+ struct stripe_head_state *s, int disks,
+ struct bio **return_bi)
+{
+ int i;
+ for (i = disks; i--; ) {
+ struct bio *bi;
+ int bitmap_end = 0;
+
+ if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
+ mdk_rdev_t *rdev;
+ rcu_read_lock();
+ rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && test_bit(In_sync, &rdev->flags))
+ /* multiple read failures in one stripe */
+ md_error(conf->mddev, rdev);
+ rcu_read_unlock();
+ }
+ spin_lock_irq(&conf->device_lock);
+ /* fail all writes first */
+ bi = sh->dev[i].towrite;
+ sh->dev[i].towrite = NULL;
+ if (bi) {
+ s->to_write--;
+ bitmap_end = 1;
+ }
+
+ if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+ wake_up(&conf->wait_for_overlap);
+
+ while (bi && bi->bi_sector <
+ sh->dev[i].sector + STRIPE_SECTORS) {
+ struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
+ clear_bit(BIO_UPTODATE, &bi->bi_flags);
+ if (--bi->bi_phys_segments == 0) {
+ md_write_end(conf->mddev);
+ bi->bi_next = *return_bi;
+ *return_bi = bi;
+ }
+ bi = nextbi;
+ }
+ /* and fail all 'written' */
+ bi = sh->dev[i].written;
+ sh->dev[i].written = NULL;
+ if (bi) bitmap_end = 1;
+ while (bi && bi->bi_sector <
+ sh->dev[i].sector + STRIPE_SECTORS) {
+ struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
+ clear_bit(BIO_UPTODATE, &bi->bi_flags);
+ if (--bi->bi_phys_segments == 0) {
+ md_write_end(conf->mddev);
+ bi->bi_next = *return_bi;
+ *return_bi = bi;
+ }
+ bi = bi2;
+ }
+
+ /* fail any reads if this device is non-operational and
+ * the data has not reached the cache yet.
+ */
+ if (!test_bit(R5_Wantfill, &sh->dev[i].flags) &&
+ (!test_bit(R5_Insync, &sh->dev[i].flags) ||
+ test_bit(R5_ReadError, &sh->dev[i].flags))) {
+ bi = sh->dev[i].toread;
+ sh->dev[i].toread = NULL;
+ if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+ wake_up(&conf->wait_for_overlap);
+ if (bi) s->to_read--;
+ while (bi && bi->bi_sector <
+ sh->dev[i].sector + STRIPE_SECTORS) {
+ struct bio *nextbi =
+ r5_next_bio(bi, sh->dev[i].sector);
+ clear_bit(BIO_UPTODATE, &bi->bi_flags);
+ if (--bi->bi_phys_segments == 0) {
+ bi->bi_next = *return_bi;
+ *return_bi = bi;
+ }
+ bi = nextbi;
+ }
+ }
+ spin_unlock_irq(&conf->device_lock);
+ if (bitmap_end)
+ bitmap_endwrite(conf->mddev->bitmap, sh->sector,
+ STRIPE_SECTORS, 0, 0);
+ }
+
+}
+
+/* __handle_issuing_new_read_requests5 - returns 0 if there are no more disks
+ * to process
+ */
+static int __handle_issuing_new_read_requests5(struct stripe_head *sh,
+ struct stripe_head_state *s, int disk_idx, int disks)
+{
+ struct r5dev *dev = &sh->dev[disk_idx];
+ struct r5dev *failed_dev = &sh->dev[s->failed_num];
+
+ /* don't schedule compute operations or reads on the parity block while
+ * a check is in flight
+ */
+ if ((disk_idx == sh->pd_idx) &&
+ test_bit(STRIPE_OP_CHECK, &sh->ops.pending))
+ return ~0;
+
+ /* is the data in this block needed, and can we get it? */
+ if (!test_bit(R5_LOCKED, &dev->flags) &&
+ !test_bit(R5_UPTODATE, &dev->flags) && (dev->toread ||
+ (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
+ s->syncing || s->expanding || (s->failed &&
+ (failed_dev->toread || (failed_dev->towrite &&
+ !test_bit(R5_OVERWRITE, &failed_dev->flags)
+ ))))) {
+ /* 1/ We would like to get this block, possibly by computing it,
+ * but we might not be able to.
+ *
+ * 2/ Since parity check operations potentially make the parity
+ * block !uptodate it will need to be refreshed before any
+ * compute operations on data disks are scheduled.
+ *
+ * 3/ We hold off parity block re-reads until check operations
+ * have quiesced.
+ */
+ if ((s->uptodate == disks - 1) &&
+ !test_bit(STRIPE_OP_CHECK, &sh->ops.pending)) {
+ set_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
+ set_bit(R5_Wantcompute, &dev->flags);
+ sh->ops.target = disk_idx;
+ s->req_compute = 1;
+ sh->ops.count++;
+ /* Careful: from this point on 'uptodate' is in the eye
+ * of raid5_run_ops which services 'compute' operations
+ * before writes. R5_Wantcompute flags a block that will
+ * be R5_UPTODATE by the time it is needed for a
+ * subsequent operation.
+ */
+ s->uptodate++;
+ return 0; /* uptodate + compute == disks */
+ } else if ((s->uptodate < disks - 1) &&
+ test_bit(R5_Insync, &dev->flags)) {
+ /* Note: we hold off compute operations while checks are
+ * in flight, but we still prefer 'compute' over 'read'
+ * hence we only read if (uptodate < * disks-1)
+ */
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantread, &dev->flags);
+ if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
+ s->locked++;
+ pr_debug("Reading block %d (sync=%d)\n", disk_idx,
+ s->syncing);
+ }
+ }
+
+ return ~0;
+}
+
+static void handle_issuing_new_read_requests5(struct stripe_head *sh,
+ struct stripe_head_state *s, int disks)
+{
+ int i;
+
+ /* Clear completed compute operations. Parity recovery
+ * (STRIPE_OP_MOD_REPAIR_PD) implies a write-back which is handled
+ * later on in this routine
+ */
+ if (test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete) &&
+ !test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) {
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.ack);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
+ }
+
+ /* look for blocks to read/compute, skip this if a compute
+ * is already in flight, or if the stripe contents are in the
+ * midst of changing due to a write
+ */
+ if (!test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending) &&
+ !test_bit(STRIPE_OP_PREXOR, &sh->ops.pending) &&
+ !test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
+ for (i = disks; i--; )
+ if (__handle_issuing_new_read_requests5(
+ sh, s, i, disks) == 0)
+ break;
+ }
+ set_bit(STRIPE_HANDLE, &sh->state);
+}
+
+static void handle_issuing_new_read_requests6(struct stripe_head *sh,
+ struct stripe_head_state *s, struct r6_state *r6s,
+ int disks)
+{
+ int i;
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (!test_bit(R5_LOCKED, &dev->flags) &&
+ !test_bit(R5_UPTODATE, &dev->flags) &&
+ (dev->toread || (dev->towrite &&
+ !test_bit(R5_OVERWRITE, &dev->flags)) ||
+ s->syncing || s->expanding ||
+ (s->failed >= 1 &&
+ (sh->dev[r6s->failed_num[0]].toread ||
+ s->to_write)) ||
+ (s->failed >= 2 &&
+ (sh->dev[r6s->failed_num[1]].toread ||
+ s->to_write)))) {
+ /* we would like to get this block, possibly
+ * by computing it, but we might not be able to
+ */
+ if (s->uptodate == disks-1) {
+ pr_debug("Computing stripe %llu block %d\n",
+ (unsigned long long)sh->sector, i);
+ compute_block_1(sh, i, 0);
+ s->uptodate++;
+ } else if ( s->uptodate == disks-2 && s->failed >= 2 ) {
+ /* Computing 2-failure is *very* expensive; only
+ * do it if failed >= 2
+ */
+ int other;
+ for (other = disks; other--; ) {
+ if (other == i)
+ continue;
+ if (!test_bit(R5_UPTODATE,
+ &sh->dev[other].flags))
+ break;
+ }
+ BUG_ON(other < 0);
+ pr_debug("Computing stripe %llu blocks %d,%d\n",
+ (unsigned long long)sh->sector,
+ i, other);
+ compute_block_2(sh, i, other);
+ s->uptodate += 2;
+ } else if (test_bit(R5_Insync, &dev->flags)) {
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantread, &dev->flags);
+ s->locked++;
+ pr_debug("Reading block %d (sync=%d)\n",
+ i, s->syncing);
+ }
+ }
+ }
+ set_bit(STRIPE_HANDLE, &sh->state);
+}
+
+
+/* handle_completed_write_requests
+ * any written block on an uptodate or failed drive can be returned.
+ * Note that if we 'wrote' to a failed drive, it will be UPTODATE, but
+ * never LOCKED, so we don't need to test 'failed' directly.
+ */
+static void handle_completed_write_requests(raid5_conf_t *conf,
+ struct stripe_head *sh, int disks, struct bio **return_bi)
+{
+ int i;
+ struct r5dev *dev;
+
+ for (i = disks; i--; )
+ if (sh->dev[i].written) {
+ dev = &sh->dev[i];
+ if (!test_bit(R5_LOCKED, &dev->flags) &&
+ test_bit(R5_UPTODATE, &dev->flags)) {
+ /* We can return any write requests */
+ struct bio *wbi, *wbi2;
+ int bitmap_end = 0;
+ pr_debug("Return write for disc %d\n", i);
+ spin_lock_irq(&conf->device_lock);
+ wbi = dev->written;
+ dev->written = NULL;
+ while (wbi && wbi->bi_sector <
+ dev->sector + STRIPE_SECTORS) {
+ wbi2 = r5_next_bio(wbi, dev->sector);
+ if (--wbi->bi_phys_segments == 0) {
+ md_write_end(conf->mddev);
+ wbi->bi_next = *return_bi;
+ *return_bi = wbi;
+ }
+ wbi = wbi2;
+ }
+ if (dev->towrite == NULL)
+ bitmap_end = 1;
+ spin_unlock_irq(&conf->device_lock);
+ if (bitmap_end)
+ bitmap_endwrite(conf->mddev->bitmap,
+ sh->sector,
+ STRIPE_SECTORS,
+ !test_bit(STRIPE_DEGRADED, &sh->state),
+ 0);
+ }
+ }
+}
+
+static void handle_issuing_new_write_requests5(raid5_conf_t *conf,
+ struct stripe_head *sh, struct stripe_head_state *s, int disks)
+{
+ int rmw = 0, rcw = 0, i;
+ for (i = disks; i--; ) {
+ /* would I have to read this buffer for read_modify_write */
+ struct r5dev *dev = &sh->dev[i];
+ if ((dev->towrite || i == sh->pd_idx) &&
+ !test_bit(R5_LOCKED, &dev->flags) &&
+ !(test_bit(R5_UPTODATE, &dev->flags) ||
+ test_bit(R5_Wantcompute, &dev->flags))) {
+ if (test_bit(R5_Insync, &dev->flags))
+ rmw++;
+ else
+ rmw += 2*disks; /* cannot read it */
+ }
+ /* Would I have to read this buffer for reconstruct_write */
+ if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx &&
+ !test_bit(R5_LOCKED, &dev->flags) &&
+ !(test_bit(R5_UPTODATE, &dev->flags) ||
+ test_bit(R5_Wantcompute, &dev->flags))) {
+ if (test_bit(R5_Insync, &dev->flags)) rcw++;
+ else
+ rcw += 2*disks;
+ }
+ }
+ pr_debug("for sector %llu, rmw=%d rcw=%d\n",
+ (unsigned long long)sh->sector, rmw, rcw);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ if (rmw < rcw && rmw > 0)
+ /* prefer read-modify-write, but need to get some data */
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if ((dev->towrite || i == sh->pd_idx) &&
+ !test_bit(R5_LOCKED, &dev->flags) &&
+ !(test_bit(R5_UPTODATE, &dev->flags) ||
+ test_bit(R5_Wantcompute, &dev->flags)) &&
+ test_bit(R5_Insync, &dev->flags)) {
+ if (
+ test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+ pr_debug("Read_old block "
+ "%d for r-m-w\n", i);
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantread, &dev->flags);
+ if (!test_and_set_bit(
+ STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
+ s->locked++;
+ } else {
+ set_bit(STRIPE_DELAYED, &sh->state);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+ }
+ }
+ if (rcw <= rmw && rcw > 0)
+ /* want reconstruct write, but need to get some data */
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (!test_bit(R5_OVERWRITE, &dev->flags) &&
+ i != sh->pd_idx &&
+ !test_bit(R5_LOCKED, &dev->flags) &&
+ !(test_bit(R5_UPTODATE, &dev->flags) ||
+ test_bit(R5_Wantcompute, &dev->flags)) &&
+ test_bit(R5_Insync, &dev->flags)) {
+ if (
+ test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+ pr_debug("Read_old block "
+ "%d for Reconstruct\n", i);
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantread, &dev->flags);
+ if (!test_and_set_bit(
+ STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
+ s->locked++;
+ } else {
+ set_bit(STRIPE_DELAYED, &sh->state);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+ }
+ }
+ /* now if nothing is locked, and if we have enough data,
+ * we can start a write request
+ */
+ /* since handle_stripe can be called at any time we need to handle the
+ * case where a compute block operation has been submitted and then a
+ * subsequent call wants to start a write request. raid5_run_ops only
+ * handles the case where compute block and postxor are requested
+ * simultaneously. If this is not the case then new writes need to be
+ * held off until the compute completes.
+ */
+ if ((s->req_compute ||
+ !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) &&
+ (s->locked == 0 && (rcw == 0 || rmw == 0) &&
+ !test_bit(STRIPE_BIT_DELAY, &sh->state)))
+ s->locked += handle_write_operations5(sh, rcw == 0, 0);
+}
+
+static void handle_issuing_new_write_requests6(raid5_conf_t *conf,
+ struct stripe_head *sh, struct stripe_head_state *s,
+ struct r6_state *r6s, int disks)
+{
+ int rcw = 0, must_compute = 0, pd_idx = sh->pd_idx, i;
+ int qd_idx = r6s->qd_idx;
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ /* Would I have to read this buffer for reconstruct_write */
+ if (!test_bit(R5_OVERWRITE, &dev->flags)
+ && i != pd_idx && i != qd_idx
+ && (!test_bit(R5_LOCKED, &dev->flags)
+ ) &&
+ !test_bit(R5_UPTODATE, &dev->flags)) {
+ if (test_bit(R5_Insync, &dev->flags)) rcw++;
+ else {
+ pr_debug("raid6: must_compute: "
+ "disk %d flags=%#lx\n", i, dev->flags);
+ must_compute++;
+ }
+ }
+ }
+ pr_debug("for sector %llu, rcw=%d, must_compute=%d\n",
+ (unsigned long long)sh->sector, rcw, must_compute);
+ set_bit(STRIPE_HANDLE, &sh->state);
+
+ if (rcw > 0)
+ /* want reconstruct write, but need to get some data */
+ for (i = disks; i--; ) {
+ struct r5dev *dev = &sh->dev[i];
+ if (!test_bit(R5_OVERWRITE, &dev->flags)
+ && !(s->failed == 0 && (i == pd_idx || i == qd_idx))
+ && !test_bit(R5_LOCKED, &dev->flags) &&
+ !test_bit(R5_UPTODATE, &dev->flags) &&
+ test_bit(R5_Insync, &dev->flags)) {
+ if (
+ test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+ pr_debug("Read_old stripe %llu "
+ "block %d for Reconstruct\n",
+ (unsigned long long)sh->sector, i);
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantread, &dev->flags);
+ s->locked++;
+ } else {
+ pr_debug("Request delayed stripe %llu "
+ "block %d for Reconstruct\n",
+ (unsigned long long)sh->sector, i);
+ set_bit(STRIPE_DELAYED, &sh->state);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+ }
+ }
+ /* now if nothing is locked, and if we have enough data, we can start a
+ * write request
+ */
+ if (s->locked == 0 && rcw == 0 &&
+ !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
+ if (must_compute > 0) {
+ /* We have failed blocks and need to compute them */
+ switch (s->failed) {
+ case 0:
+ BUG();
+ case 1:
+ compute_block_1(sh, r6s->failed_num[0], 0);
+ break;
+ case 2:
+ compute_block_2(sh, r6s->failed_num[0],
+ r6s->failed_num[1]);
+ break;
+ default: /* This request should have been failed? */
+ BUG();
+ }
+ }
+
+ pr_debug("Computing parity for stripe %llu\n",
+ (unsigned long long)sh->sector);
+ compute_parity6(sh, RECONSTRUCT_WRITE);
+ /* now every locked buffer is ready to be written */
+ for (i = disks; i--; )
+ if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
+ pr_debug("Writing stripe %llu block %d\n",
+ (unsigned long long)sh->sector, i);
+ s->locked++;
+ set_bit(R5_Wantwrite, &sh->dev[i].flags);
+ }
+ /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */
+ set_bit(STRIPE_INSYNC, &sh->state);
+
+ if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+ atomic_dec(&conf->preread_active_stripes);
+ if (atomic_read(&conf->preread_active_stripes) <
+ IO_THRESHOLD)
+ md_wakeup_thread(conf->mddev->thread);
+ }
+ }
+}
+
+static void handle_parity_checks5(raid5_conf_t *conf, struct stripe_head *sh,
+ struct stripe_head_state *s, int disks)
+{
+ set_bit(STRIPE_HANDLE, &sh->state);
+ /* Take one of the following actions:
+ * 1/ start a check parity operation if (uptodate == disks)
+ * 2/ finish a check parity operation and act on the result
+ * 3/ skip to the writeback section if we previously
+ * initiated a recovery operation
+ */
+ if (s->failed == 0 &&
+ !test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) {
+ if (!test_and_set_bit(STRIPE_OP_CHECK, &sh->ops.pending)) {
+ BUG_ON(s->uptodate != disks);
+ clear_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags);
+ sh->ops.count++;
+ s->uptodate--;
+ } else if (
+ test_and_clear_bit(STRIPE_OP_CHECK, &sh->ops.complete)) {
+ clear_bit(STRIPE_OP_CHECK, &sh->ops.ack);
+ clear_bit(STRIPE_OP_CHECK, &sh->ops.pending);
+
+ if (sh->ops.zero_sum_result == 0)
+ /* parity is correct (on disc,
+ * not in buffer any more)
+ */
+ set_bit(STRIPE_INSYNC, &sh->state);
+ else {
+ conf->mddev->resync_mismatches +=
+ STRIPE_SECTORS;
+ if (test_bit(
+ MD_RECOVERY_CHECK, &conf->mddev->recovery))
+ /* don't try to repair!! */
+ set_bit(STRIPE_INSYNC, &sh->state);
+ else {
+ set_bit(STRIPE_OP_COMPUTE_BLK,
+ &sh->ops.pending);
+ set_bit(STRIPE_OP_MOD_REPAIR_PD,
+ &sh->ops.pending);
+ set_bit(R5_Wantcompute,
+ &sh->dev[sh->pd_idx].flags);
+ sh->ops.target = sh->pd_idx;
+ sh->ops.count++;
+ s->uptodate++;
+ }
+ }
+ }
+ }
+
+ /* check if we can clear a parity disk reconstruct */
+ if (test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete) &&
+ test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending)) {
+
+ clear_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.complete);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.ack);
+ clear_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending);
+ }
+
+ /* Wait for check parity and compute block operations to complete
+ * before write-back
+ */
+ if (!test_bit(STRIPE_INSYNC, &sh->state) &&
+ !test_bit(STRIPE_OP_CHECK, &sh->ops.pending) &&
+ !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) {
+ struct r5dev *dev;
+ /* either failed parity check, or recovery is happening */
+ if (s->failed == 0)
+ s->failed_num = sh->pd_idx;
+ dev = &sh->dev[s->failed_num];
+ BUG_ON(!test_bit(R5_UPTODATE, &dev->flags));
+ BUG_ON(s->uptodate != disks);
+
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
+
+ clear_bit(STRIPE_DEGRADED, &sh->state);
+ s->locked++;
+ set_bit(STRIPE_INSYNC, &sh->state);
+ }
+}
+
+
+static void handle_parity_checks6(raid5_conf_t *conf, struct stripe_head *sh,
+ struct stripe_head_state *s,
+ struct r6_state *r6s, struct page *tmp_page,
+ int disks)
+{
+ int update_p = 0, update_q = 0;
+ struct r5dev *dev;
+ int pd_idx = sh->pd_idx;
+ int qd_idx = r6s->qd_idx;
+
+ set_bit(STRIPE_HANDLE, &sh->state);
+
+ BUG_ON(s->failed > 2);
+ BUG_ON(s->uptodate < disks);
+ /* Want to check and possibly repair P and Q.
+ * However there could be one 'failed' device, in which
+ * case we can only check one of them, possibly using the
+ * other to generate missing data
+ */
+
+ /* If !tmp_page, we cannot do the calculations,
+ * but as we have set STRIPE_HANDLE, we will soon be called
+ * by stripe_handle with a tmp_page - just wait until then.
+ */
+ if (tmp_page) {
+ if (s->failed == r6s->q_failed) {
+ /* The only possible failed device holds 'Q', so it
+ * makes sense to check P (If anything else were failed,
+ * we would have used P to recreate it).
+ */
+ compute_block_1(sh, pd_idx, 1);
+ if (!page_is_zero(sh->dev[pd_idx].page)) {
+ compute_block_1(sh, pd_idx, 0);
+ update_p = 1;
+ }
+ }
+ if (!r6s->q_failed && s->failed < 2) {
+ /* q is not failed, and we didn't use it to generate
+ * anything, so it makes sense to check it
+ */
+ memcpy(page_address(tmp_page),
+ page_address(sh->dev[qd_idx].page),
+ STRIPE_SIZE);
+ compute_parity6(sh, UPDATE_PARITY);
+ if (memcmp(page_address(tmp_page),
+ page_address(sh->dev[qd_idx].page),
+ STRIPE_SIZE) != 0) {
+ clear_bit(STRIPE_INSYNC, &sh->state);
+ update_q = 1;
+ }
+ }
+ if (update_p || update_q) {
+ conf->mddev->resync_mismatches += STRIPE_SECTORS;
+ if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
+ /* don't try to repair!! */
+ update_p = update_q = 0;
+ }
+
+ /* now write out any block on a failed drive,
+ * or P or Q if they need it
+ */
+
+ if (s->failed == 2) {
+ dev = &sh->dev[r6s->failed_num[1]];
+ s->locked++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+ if (s->failed >= 1) {
+ dev = &sh->dev[r6s->failed_num[0]];
+ s->locked++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+
+ if (update_p) {
+ dev = &sh->dev[pd_idx];
+ s->locked++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+ if (update_q) {
+ dev = &sh->dev[qd_idx];
+ s->locked++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+ clear_bit(STRIPE_DEGRADED, &sh->state);
+
+ set_bit(STRIPE_INSYNC, &sh->state);
+ }
+}
+
+static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh,
+ struct r6_state *r6s)
+{
+ int i;
+
+ /* We have read all the blocks in this stripe and now we need to
+ * copy some of them into a target stripe for expand.
+ */
+ struct dma_async_tx_descriptor *tx = NULL;
+ clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+ for (i = 0; i < sh->disks; i++)
+ if (i != sh->pd_idx && (r6s && i != r6s->qd_idx)) {
+ int dd_idx, pd_idx, j;
+ struct stripe_head *sh2;
+
+ sector_t bn = compute_blocknr(sh, i);
+ sector_t s = raid5_compute_sector(bn, conf->raid_disks,
+ conf->raid_disks -
+ conf->max_degraded, &dd_idx,
+ &pd_idx, conf);
+ sh2 = get_active_stripe(conf, s, conf->raid_disks,
+ pd_idx, 1);
+ if (sh2 == NULL)
+ /* so far only the early blocks of this stripe
+ * have been requested. When later blocks
+ * get requested, we will try again
+ */
+ continue;
+ if (!test_bit(STRIPE_EXPANDING, &sh2->state) ||
+ test_bit(R5_Expanded, &sh2->dev[dd_idx].flags)) {
+ /* must have already done this block */
+ release_stripe(sh2);
+ continue;
+ }
+
+ /* place all the copies on one channel */
+ tx = async_memcpy(sh2->dev[dd_idx].page,
+ sh->dev[i].page, 0, 0, STRIPE_SIZE,
+ ASYNC_TX_DEP_ACK, tx, NULL, NULL);
+
+ set_bit(R5_Expanded, &sh2->dev[dd_idx].flags);
+ set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
+ for (j = 0; j < conf->raid_disks; j++)
+ if (j != sh2->pd_idx &&
+ (r6s && j != r6s->qd_idx) &&
+ !test_bit(R5_Expanded, &sh2->dev[j].flags))
+ break;
+ if (j == conf->raid_disks) {
+ set_bit(STRIPE_EXPAND_READY, &sh2->state);
+ set_bit(STRIPE_HANDLE, &sh2->state);
+ }
+ release_stripe(sh2);
+
+ /* done submitting copies, wait for them to complete */
+ if (i + 1 >= sh->disks) {
+ async_tx_ack(tx);
+ dma_wait_for_async_tx(tx);
+ }
+ }
+}
/*
* handle_stripe - do things to a stripe.
@@ -1339,81 +2603,70 @@ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
* schedule a write of some buffers
* return confirmation of parity correctness
*
- * Parity calculations are done inside the stripe lock
* buffers are taken off read_list or write_list, and bh_cache buffers
* get BH_Lock set before the stripe lock is released.
*
*/
-
+
static void handle_stripe5(struct stripe_head *sh)
{
raid5_conf_t *conf = sh->raid_conf;
- int disks = sh->disks;
- struct bio *return_bi= NULL;
- struct bio *bi;
- int i;
- int syncing, expanding, expanded;
- int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
- int non_overwrite = 0;
- int failed_num=0;
+ int disks = sh->disks, i;
+ struct bio *return_bi = NULL;
+ struct stripe_head_state s;
struct r5dev *dev;
+ unsigned long pending = 0;
- PRINTK("handling stripe %llu, cnt=%d, pd_idx=%d\n",
- (unsigned long long)sh->sector, atomic_read(&sh->count),
- sh->pd_idx);
+ memset(&s, 0, sizeof(s));
+ pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d "
+ "ops=%lx:%lx:%lx\n", (unsigned long long)sh->sector, sh->state,
+ atomic_read(&sh->count), sh->pd_idx,
+ sh->ops.pending, sh->ops.ack, sh->ops.complete);
spin_lock(&sh->lock);
clear_bit(STRIPE_HANDLE, &sh->state);
clear_bit(STRIPE_DELAYED, &sh->state);
- syncing = test_bit(STRIPE_SYNCING, &sh->state);
- expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
- expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
+ s.syncing = test_bit(STRIPE_SYNCING, &sh->state);
+ s.expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+ s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
/* Now to look around and see what can be done */
rcu_read_lock();
for (i=disks; i--; ) {
mdk_rdev_t *rdev;
- dev = &sh->dev[i];
+ struct r5dev *dev = &sh->dev[i];
clear_bit(R5_Insync, &dev->flags);
- PRINTK("check %d: state 0x%lx read %p write %p written %p\n",
- i, dev->flags, dev->toread, dev->towrite, dev->written);
- /* maybe we can reply to a read */
- if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) {
- struct bio *rbi, *rbi2;
- PRINTK("Return read for disc %d\n", i);
- spin_lock_irq(&conf->device_lock);
- rbi = dev->toread;
- dev->toread = NULL;
- if (test_and_clear_bit(R5_Overlap, &dev->flags))
- wake_up(&conf->wait_for_overlap);
- spin_unlock_irq(&conf->device_lock);
- while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) {
- copy_data(0, rbi, dev->page, dev->sector);
- rbi2 = r5_next_bio(rbi, dev->sector);
- spin_lock_irq(&conf->device_lock);
- if (--rbi->bi_phys_segments == 0) {
- rbi->bi_next = return_bi;
- return_bi = rbi;
- }
- spin_unlock_irq(&conf->device_lock);
- rbi = rbi2;
- }
- }
+ pr_debug("check %d: state 0x%lx toread %p read %p write %p "
+ "written %p\n", i, dev->flags, dev->toread, dev->read,
+ dev->towrite, dev->written);
- /* now count some things */
- if (test_bit(R5_LOCKED, &dev->flags)) locked++;
- if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++;
+ /* maybe we can request a biofill operation
+ *
+ * new wantfill requests are only permitted while
+ * STRIPE_OP_BIOFILL is clear
+ */
+ if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread &&
+ !test_bit(STRIPE_OP_BIOFILL, &sh->ops.pending))
+ set_bit(R5_Wantfill, &dev->flags);
-
- if (dev->toread) to_read++;
+ /* now count some things */
+ if (test_bit(R5_LOCKED, &dev->flags)) s.locked++;
+ if (test_bit(R5_UPTODATE, &dev->flags)) s.uptodate++;
+ if (test_bit(R5_Wantcompute, &dev->flags)) s.compute++;
+
+ if (test_bit(R5_Wantfill, &dev->flags))
+ s.to_fill++;
+ else if (dev->toread)
+ s.to_read++;
if (dev->towrite) {
- to_write++;
+ s.to_write++;
if (!test_bit(R5_OVERWRITE, &dev->flags))
- non_overwrite++;
+ s.non_overwrite++;
}
- if (dev->written) written++;
+ if (dev->written)
+ s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
@@ -1422,306 +2675,131 @@ static void handle_stripe5(struct stripe_head *sh)
}
if (!rdev || !test_bit(In_sync, &rdev->flags)
|| test_bit(R5_ReadError, &dev->flags)) {
- failed++;
- failed_num = i;
+ s.failed++;
+ s.failed_num = i;
} else
set_bit(R5_Insync, &dev->flags);
}
rcu_read_unlock();
- PRINTK("locked=%d uptodate=%d to_read=%d"
+
+ if (s.to_fill && !test_and_set_bit(STRIPE_OP_BIOFILL, &sh->ops.pending))
+ sh->ops.count++;
+
+ pr_debug("locked=%d uptodate=%d to_read=%d"
" to_write=%d failed=%d failed_num=%d\n",
- locked, uptodate, to_read, to_write, failed, failed_num);
+ s.locked, s.uptodate, s.to_read, s.to_write,
+ s.failed, s.failed_num);
/* check if the array has lost two devices and, if so, some requests might
* need to be failed
*/
- if (failed > 1 && to_read+to_write+written) {
- for (i=disks; i--; ) {
- int bitmap_end = 0;
-
- if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
- mdk_rdev_t *rdev;
- rcu_read_lock();
- rdev = rcu_dereference(conf->disks[i].rdev);
- if (rdev && test_bit(In_sync, &rdev->flags))
- /* multiple read failures in one stripe */
- md_error(conf->mddev, rdev);
- rcu_read_unlock();
- }
-
- spin_lock_irq(&conf->device_lock);
- /* fail all writes first */
- bi = sh->dev[i].towrite;
- sh->dev[i].towrite = NULL;
- if (bi) { to_write--; bitmap_end = 1; }
-
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
-
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
- struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = nextbi;
- }
- /* and fail all 'written' */
- bi = sh->dev[i].written;
- sh->dev[i].written = NULL;
- if (bi) bitmap_end = 1;
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) {
- struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = bi2;
- }
-
- /* fail any reads if this device is non-operational */
- if (!test_bit(R5_Insync, &sh->dev[i].flags) ||
- test_bit(R5_ReadError, &sh->dev[i].flags)) {
- bi = sh->dev[i].toread;
- sh->dev[i].toread = NULL;
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
- if (bi) to_read--;
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
- struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = nextbi;
- }
- }
- spin_unlock_irq(&conf->device_lock);
- if (bitmap_end)
- bitmap_endwrite(conf->mddev->bitmap, sh->sector,
- STRIPE_SECTORS, 0, 0);
- }
- }
- if (failed > 1 && syncing) {
+ if (s.failed > 1 && s.to_read+s.to_write+s.written)
+ handle_requests_to_failed_array(conf, sh, &s, disks,
+ &return_bi);
+ if (s.failed > 1 && s.syncing) {
md_done_sync(conf->mddev, STRIPE_SECTORS,0);
clear_bit(STRIPE_SYNCING, &sh->state);
- syncing = 0;
+ s.syncing = 0;
}
/* might be able to return some write requests if the parity block
* is safe, or on a failed drive
*/
dev = &sh->dev[sh->pd_idx];
- if ( written &&
- ( (test_bit(R5_Insync, &dev->flags) && !test_bit(R5_LOCKED, &dev->flags) &&
- test_bit(R5_UPTODATE, &dev->flags))
- || (failed == 1 && failed_num == sh->pd_idx))
- ) {
- /* any written block on an uptodate or failed drive can be returned.
- * Note that if we 'wrote' to a failed drive, it will be UPTODATE, but
- * never LOCKED, so we don't need to test 'failed' directly.
- */
- for (i=disks; i--; )
- if (sh->dev[i].written) {
- dev = &sh->dev[i];
- if (!test_bit(R5_LOCKED, &dev->flags) &&
- test_bit(R5_UPTODATE, &dev->flags) ) {
- /* We can return any write requests */
- struct bio *wbi, *wbi2;
- int bitmap_end = 0;
- PRINTK("Return write for disc %d\n", i);
- spin_lock_irq(&conf->device_lock);
- wbi = dev->written;
- dev->written = NULL;
- while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) {
- wbi2 = r5_next_bio(wbi, dev->sector);
- if (--wbi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- wbi->bi_next = return_bi;
- return_bi = wbi;
- }
- wbi = wbi2;
- }
- if (dev->towrite == NULL)
- bitmap_end = 1;
- spin_unlock_irq(&conf->device_lock);
- if (bitmap_end)
- bitmap_endwrite(conf->mddev->bitmap, sh->sector,
- STRIPE_SECTORS,
- !test_bit(STRIPE_DEGRADED, &sh->state), 0);
- }
- }
- }
+ if ( s.written &&
+ ((test_bit(R5_Insync, &dev->flags) &&
+ !test_bit(R5_LOCKED, &dev->flags) &&
+ test_bit(R5_UPTODATE, &dev->flags)) ||
+ (s.failed == 1 && s.failed_num == sh->pd_idx)))
+ handle_completed_write_requests(conf, sh, disks, &return_bi);
/* Now we might consider reading some blocks, either to check/generate
* parity, or to satisfy requests
* or to load a block that is being partially written.
*/
- if (to_read || non_overwrite || (syncing && (uptodate < disks)) || expanding) {
- for (i=disks; i--;) {
- dev = &sh->dev[i];
- if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
- (dev->toread ||
- (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
- syncing ||
- expanding ||
- (failed && (sh->dev[failed_num].toread ||
- (sh->dev[failed_num].towrite && !test_bit(R5_OVERWRITE, &sh->dev[failed_num].flags))))
- )
- ) {
- /* we would like to get this block, possibly
- * by computing it, but we might not be able to
- */
- if (uptodate == disks-1) {
- PRINTK("Computing block %d\n", i);
- compute_block(sh, i);
- uptodate++;
- } else if (test_bit(R5_Insync, &dev->flags)) {
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantread, &dev->flags);
- locked++;
- PRINTK("Reading block %d (sync=%d)\n",
- i, syncing);
- }
- }
- }
- set_bit(STRIPE_HANDLE, &sh->state);
+ if (s.to_read || s.non_overwrite ||
+ (s.syncing && (s.uptodate + s.compute < disks)) || s.expanding ||
+ test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
+ handle_issuing_new_read_requests5(sh, &s, disks);
+
+ /* Now we check to see if any write operations have recently
+ * completed
+ */
+
+ /* leave prexor set until postxor is done, allows us to distinguish
+ * a rmw from a rcw during biodrain
+ */
+ if (test_bit(STRIPE_OP_PREXOR, &sh->ops.complete) &&
+ test_bit(STRIPE_OP_POSTXOR, &sh->ops.complete)) {
+
+ clear_bit(STRIPE_OP_PREXOR, &sh->ops.complete);
+ clear_bit(STRIPE_OP_PREXOR, &sh->ops.ack);
+ clear_bit(STRIPE_OP_PREXOR, &sh->ops.pending);
+
+ for (i = disks; i--; )
+ clear_bit(R5_Wantprexor, &sh->dev[i].flags);
}
- /* now to consider writing and what else, if anything should be read */
- if (to_write) {
- int rmw=0, rcw=0;
- for (i=disks ; i--;) {
- /* would I have to read this buffer for read_modify_write */
+ /* if only POSTXOR is set then this is an 'expand' postxor */
+ if (test_bit(STRIPE_OP_BIODRAIN, &sh->ops.complete) &&
+ test_bit(STRIPE_OP_POSTXOR, &sh->ops.complete)) {
+
+ clear_bit(STRIPE_OP_BIODRAIN, &sh->ops.complete);
+ clear_bit(STRIPE_OP_BIODRAIN, &sh->ops.ack);
+ clear_bit(STRIPE_OP_BIODRAIN, &sh->ops.pending);
+
+ clear_bit(STRIPE_OP_POSTXOR, &sh->ops.complete);
+ clear_bit(STRIPE_OP_POSTXOR, &sh->ops.ack);
+ clear_bit(STRIPE_OP_POSTXOR, &sh->ops.pending);
+
+ /* All the 'written' buffers and the parity block are ready to
+ * be written back to disk
+ */
+ BUG_ON(!test_bit(R5_UPTODATE, &sh->dev[sh->pd_idx].flags));
+ for (i = disks; i--; ) {
dev = &sh->dev[i];
- if ((dev->towrite || i == sh->pd_idx) &&
- (!test_bit(R5_LOCKED, &dev->flags)
- ) &&
- !test_bit(R5_UPTODATE, &dev->flags)) {
- if (test_bit(R5_Insync, &dev->flags)
-/* && !(!mddev->insync && i == sh->pd_idx) */
- )
- rmw++;
- else rmw += 2*disks; /* cannot read it */
- }
- /* Would I have to read this buffer for reconstruct_write */
- if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx &&
- (!test_bit(R5_LOCKED, &dev->flags)
- ) &&
- !test_bit(R5_UPTODATE, &dev->flags)) {
- if (test_bit(R5_Insync, &dev->flags)) rcw++;
- else rcw += 2*disks;
+ if (test_bit(R5_LOCKED, &dev->flags) &&
+ (i == sh->pd_idx || dev->written)) {
+ pr_debug("Writing block %d\n", i);
+ set_bit(R5_Wantwrite, &dev->flags);
+ if (!test_and_set_bit(
+ STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
+ if (!test_bit(R5_Insync, &dev->flags) ||
+ (i == sh->pd_idx && s.failed == 0))
+ set_bit(STRIPE_INSYNC, &sh->state);
}
}
- PRINTK("for sector %llu, rmw=%d rcw=%d\n",
- (unsigned long long)sh->sector, rmw, rcw);
- set_bit(STRIPE_HANDLE, &sh->state);
- if (rmw < rcw && rmw > 0)
- /* prefer read-modify-write, but need to get some data */
- for (i=disks; i--;) {
- dev = &sh->dev[i];
- if ((dev->towrite || i == sh->pd_idx) &&
- !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
- test_bit(R5_Insync, &dev->flags)) {
- if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
- {
- PRINTK("Read_old block %d for r-m-w\n", i);
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantread, &dev->flags);
- locked++;
- } else {
- set_bit(STRIPE_DELAYED, &sh->state);
- set_bit(STRIPE_HANDLE, &sh->state);
- }
- }
- }
- if (rcw <= rmw && rcw > 0)
- /* want reconstruct write, but need to get some data */
- for (i=disks; i--;) {
- dev = &sh->dev[i];
- if (!test_bit(R5_OVERWRITE, &dev->flags) && i != sh->pd_idx &&
- !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
- test_bit(R5_Insync, &dev->flags)) {
- if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
- {
- PRINTK("Read_old block %d for Reconstruct\n", i);
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantread, &dev->flags);
- locked++;
- } else {
- set_bit(STRIPE_DELAYED, &sh->state);
- set_bit(STRIPE_HANDLE, &sh->state);
- }
- }
- }
- /* now if nothing is locked, and if we have enough data, we can start a write request */
- if (locked == 0 && (rcw == 0 ||rmw == 0) &&
- !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
- PRINTK("Computing parity...\n");
- compute_parity5(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE);
- /* now every locked buffer is ready to be written */
- for (i=disks; i--;)
- if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
- PRINTK("Writing block %d\n", i);
- locked++;
- set_bit(R5_Wantwrite, &sh->dev[i].flags);
- if (!test_bit(R5_Insync, &sh->dev[i].flags)
- || (i==sh->pd_idx && failed == 0))
- set_bit(STRIPE_INSYNC, &sh->state);
- }
- if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
- atomic_dec(&conf->preread_active_stripes);
- if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
- md_wakeup_thread(conf->mddev->thread);
- }
+ if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+ atomic_dec(&conf->preread_active_stripes);
+ if (atomic_read(&conf->preread_active_stripes) <
+ IO_THRESHOLD)
+ md_wakeup_thread(conf->mddev->thread);
}
}
- /* maybe we need to check and possibly fix the parity for this stripe
- * Any reads will already have been scheduled, so we just see if enough data
- * is available
+ /* Now to consider new write requests and what else, if anything
+ * should be read. We do not handle new writes when:
+ * 1/ A 'write' operation (copy+xor) is already in flight.
+ * 2/ A 'check' operation is in flight, as it may clobber the parity
+ * block.
*/
- if (syncing && locked == 0 &&
- !test_bit(STRIPE_INSYNC, &sh->state)) {
- set_bit(STRIPE_HANDLE, &sh->state);
- if (failed == 0) {
- BUG_ON(uptodate != disks);
- compute_parity5(sh, CHECK_PARITY);
- uptodate--;
- if (page_is_zero(sh->dev[sh->pd_idx].page)) {
- /* parity is correct (on disc, not in buffer any more) */
- set_bit(STRIPE_INSYNC, &sh->state);
- } else {
- conf->mddev->resync_mismatches += STRIPE_SECTORS;
- if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
- /* don't try to repair!! */
- set_bit(STRIPE_INSYNC, &sh->state);
- else {
- compute_block(sh, sh->pd_idx);
- uptodate++;
- }
- }
- }
- if (!test_bit(STRIPE_INSYNC, &sh->state)) {
- /* either failed parity check, or recovery is happening */
- if (failed==0)
- failed_num = sh->pd_idx;
- dev = &sh->dev[failed_num];
- BUG_ON(!test_bit(R5_UPTODATE, &dev->flags));
- BUG_ON(uptodate != disks);
+ if (s.to_write && !test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending) &&
+ !test_bit(STRIPE_OP_CHECK, &sh->ops.pending))
+ handle_issuing_new_write_requests5(conf, sh, &s, disks);
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- clear_bit(STRIPE_DEGRADED, &sh->state);
- locked++;
- set_bit(STRIPE_INSYNC, &sh->state);
- }
- }
- if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
+ /* maybe we need to check and possibly fix the parity for this stripe
+ * Any reads will already have been scheduled, so we just see if enough
+ * data is available. The parity check is held off while parity
+ * dependent operations are in flight.
+ */
+ if ((s.syncing && s.locked == 0 &&
+ !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending) &&
+ !test_bit(STRIPE_INSYNC, &sh->state)) ||
+ test_bit(STRIPE_OP_CHECK, &sh->ops.pending) ||
+ test_bit(STRIPE_OP_MOD_REPAIR_PD, &sh->ops.pending))
+ handle_parity_checks5(conf, sh, &s, disks);
+
+ if (s.syncing && s.locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
md_done_sync(conf->mddev, STRIPE_SECTORS,1);
clear_bit(STRIPE_SYNCING, &sh->state);
}
@@ -1729,186 +2807,102 @@ static void handle_stripe5(struct stripe_head *sh)
/* If the failed drive is just a ReadError, then we might need to progress
* the repair/check process
*/
- if (failed == 1 && ! conf->mddev->ro &&
- test_bit(R5_ReadError, &sh->dev[failed_num].flags)
- && !test_bit(R5_LOCKED, &sh->dev[failed_num].flags)
- && test_bit(R5_UPTODATE, &sh->dev[failed_num].flags)
+ if (s.failed == 1 && !conf->mddev->ro &&
+ test_bit(R5_ReadError, &sh->dev[s.failed_num].flags)
+ && !test_bit(R5_LOCKED, &sh->dev[s.failed_num].flags)
+ && test_bit(R5_UPTODATE, &sh->dev[s.failed_num].flags)
) {
- dev = &sh->dev[failed_num];
+ dev = &sh->dev[s.failed_num];
if (!test_bit(R5_ReWrite, &dev->flags)) {
set_bit(R5_Wantwrite, &dev->flags);
+ if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
set_bit(R5_ReWrite, &dev->flags);
set_bit(R5_LOCKED, &dev->flags);
- locked++;
+ s.locked++;
} else {
/* let's read it back */
set_bit(R5_Wantread, &dev->flags);
+ if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
set_bit(R5_LOCKED, &dev->flags);
- locked++;
+ s.locked++;
}
}
- if (expanded && test_bit(STRIPE_EXPANDING, &sh->state)) {
- /* Need to write out all blocks after computing parity */
- sh->disks = conf->raid_disks;
- sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks);
- compute_parity5(sh, RECONSTRUCT_WRITE);
- for (i= conf->raid_disks; i--;) {
- set_bit(R5_LOCKED, &sh->dev[i].flags);
- locked++;
+ /* Finish postxor operations initiated by the expansion
+ * process
+ */
+ if (test_bit(STRIPE_OP_POSTXOR, &sh->ops.complete) &&
+ !test_bit(STRIPE_OP_BIODRAIN, &sh->ops.pending)) {
+
+ clear_bit(STRIPE_EXPANDING, &sh->state);
+
+ clear_bit(STRIPE_OP_POSTXOR, &sh->ops.pending);
+ clear_bit(STRIPE_OP_POSTXOR, &sh->ops.ack);
+ clear_bit(STRIPE_OP_POSTXOR, &sh->ops.complete);
+
+ for (i = conf->raid_disks; i--; ) {
set_bit(R5_Wantwrite, &sh->dev[i].flags);
+ if (!test_and_set_bit(STRIPE_OP_IO, &sh->ops.pending))
+ sh->ops.count++;
}
- clear_bit(STRIPE_EXPANDING, &sh->state);
- } else if (expanded) {
+ }
+
+ if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state) &&
+ !test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
+ /* Need to write out all blocks after computing parity */
+ sh->disks = conf->raid_disks;
+ sh->pd_idx = stripe_to_pdidx(sh->sector, conf,
+ conf->raid_disks);
+ s.locked += handle_write_operations5(sh, 0, 1);
+ } else if (s.expanded &&
+ !test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
clear_bit(STRIPE_EXPAND_READY, &sh->state);
atomic_dec(&conf->reshape_stripes);
wake_up(&conf->wait_for_overlap);
md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
}
- if (expanding && locked == 0) {
- /* We have read all the blocks in this stripe and now we need to
- * copy some of them into a target stripe for expand.
- */
- clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
- for (i=0; i< sh->disks; i++)
- if (i != sh->pd_idx) {
- int dd_idx, pd_idx, j;
- struct stripe_head *sh2;
-
- sector_t bn = compute_blocknr(sh, i);
- sector_t s = raid5_compute_sector(bn, conf->raid_disks,
- conf->raid_disks-1,
- &dd_idx, &pd_idx, conf);
- sh2 = get_active_stripe(conf, s, conf->raid_disks, pd_idx, 1);
- if (sh2 == NULL)
- /* so far only the early blocks of this stripe
- * have been requested. When later blocks
- * get requested, we will try again
- */
- continue;
- if(!test_bit(STRIPE_EXPANDING, &sh2->state) ||
- test_bit(R5_Expanded, &sh2->dev[dd_idx].flags)) {
- /* must have already done this block */
- release_stripe(sh2);
- continue;
- }
- memcpy(page_address(sh2->dev[dd_idx].page),
- page_address(sh->dev[i].page),
- STRIPE_SIZE);
- set_bit(R5_Expanded, &sh2->dev[dd_idx].flags);
- set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
- for (j=0; j<conf->raid_disks; j++)
- if (j != sh2->pd_idx &&
- !test_bit(R5_Expanded, &sh2->dev[j].flags))
- break;
- if (j == conf->raid_disks) {
- set_bit(STRIPE_EXPAND_READY, &sh2->state);
- set_bit(STRIPE_HANDLE, &sh2->state);
- }
- release_stripe(sh2);
- }
- }
+ if (s.expanding && s.locked == 0)
+ handle_stripe_expansion(conf, sh, NULL);
+
+ if (sh->ops.count)
+ pending = get_stripe_work(sh);
spin_unlock(&sh->lock);
- while ((bi=return_bi)) {
- int bytes = bi->bi_size;
+ if (pending)
+ raid5_run_ops(sh, pending);
- return_bi = bi->bi_next;
- bi->bi_next = NULL;
- bi->bi_size = 0;
- bi->bi_end_io(bi, bytes,
- test_bit(BIO_UPTODATE, &bi->bi_flags)
- ? 0 : -EIO);
- }
- for (i=disks; i-- ;) {
- int rw;
- struct bio *bi;
- mdk_rdev_t *rdev;
- if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
- rw = WRITE;
- else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
- rw = READ;
- else
- continue;
-
- bi = &sh->dev[i].req;
-
- bi->bi_rw = rw;
- if (rw == WRITE)
- bi->bi_end_io = raid5_end_write_request;
- else
- bi->bi_end_io = raid5_end_read_request;
-
- rcu_read_lock();
- rdev = rcu_dereference(conf->disks[i].rdev);
- if (rdev && test_bit(Faulty, &rdev->flags))
- rdev = NULL;
- if (rdev)
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
-
- if (rdev) {
- if (syncing || expanding || expanded)
- md_sync_acct(rdev->bdev, STRIPE_SECTORS);
+ return_io(return_bi);
- bi->bi_bdev = rdev->bdev;
- PRINTK("for %llu schedule op %ld on disc %d\n",
- (unsigned long long)sh->sector, bi->bi_rw, i);
- atomic_inc(&sh->count);
- bi->bi_sector = sh->sector + rdev->data_offset;
- bi->bi_flags = 1 << BIO_UPTODATE;
- bi->bi_vcnt = 1;
- bi->bi_max_vecs = 1;
- bi->bi_idx = 0;
- bi->bi_io_vec = &sh->dev[i].vec;
- bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
- bi->bi_io_vec[0].bv_offset = 0;
- bi->bi_size = STRIPE_SIZE;
- bi->bi_next = NULL;
- if (rw == WRITE &&
- test_bit(R5_ReWrite, &sh->dev[i].flags))
- atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
- generic_make_request(bi);
- } else {
- if (rw == WRITE)
- set_bit(STRIPE_DEGRADED, &sh->state);
- PRINTK("skip op %ld on disc %d for sector %llu\n",
- bi->bi_rw, i, (unsigned long long)sh->sector);
- clear_bit(R5_LOCKED, &sh->dev[i].flags);
- set_bit(STRIPE_HANDLE, &sh->state);
- }
- }
}
static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
{
raid6_conf_t *conf = sh->raid_conf;
int disks = sh->disks;
- struct bio *return_bi= NULL;
- struct bio *bi;
- int i;
- int syncing, expanding, expanded;
- int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
- int non_overwrite = 0;
- int failed_num[2] = {0, 0};
+ struct bio *return_bi = NULL;
+ int i, pd_idx = sh->pd_idx;
+ struct stripe_head_state s;
+ struct r6_state r6s;
struct r5dev *dev, *pdev, *qdev;
- int pd_idx = sh->pd_idx;
- int qd_idx = raid6_next_disk(pd_idx, disks);
- int p_failed, q_failed;
- PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n",
- (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count),
- pd_idx, qd_idx);
+ r6s.qd_idx = raid6_next_disk(pd_idx, disks);
+ pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
+ "pd_idx=%d, qd_idx=%d\n",
+ (unsigned long long)sh->sector, sh->state,
+ atomic_read(&sh->count), pd_idx, r6s.qd_idx);
+ memset(&s, 0, sizeof(s));
spin_lock(&sh->lock);
clear_bit(STRIPE_HANDLE, &sh->state);
clear_bit(STRIPE_DELAYED, &sh->state);
- syncing = test_bit(STRIPE_SYNCING, &sh->state);
- expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
- expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
+ s.syncing = test_bit(STRIPE_SYNCING, &sh->state);
+ s.expanding = test_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+ s.expanded = test_bit(STRIPE_EXPAND_READY, &sh->state);
/* Now to look around and see what can be done */
rcu_read_lock();
@@ -1917,12 +2911,12 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
dev = &sh->dev[i];
clear_bit(R5_Insync, &dev->flags);
- PRINTK("check %d: state 0x%lx read %p write %p written %p\n",
+ pr_debug("check %d: state 0x%lx read %p write %p written %p\n",
i, dev->flags, dev->toread, dev->towrite, dev->written);
/* maybe we can reply to a read */
if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) {
struct bio *rbi, *rbi2;
- PRINTK("Return read for disc %d\n", i);
+ pr_debug("Return read for disc %d\n", i);
spin_lock_irq(&conf->device_lock);
rbi = dev->toread;
dev->toread = NULL;
@@ -1943,17 +2937,19 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
}
/* now count some things */
- if (test_bit(R5_LOCKED, &dev->flags)) locked++;
- if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++;
+ if (test_bit(R5_LOCKED, &dev->flags)) s.locked++;
+ if (test_bit(R5_UPTODATE, &dev->flags)) s.uptodate++;
- if (dev->toread) to_read++;
+ if (dev->toread)
+ s.to_read++;
if (dev->towrite) {
- to_write++;
+ s.to_write++;
if (!test_bit(R5_OVERWRITE, &dev->flags))
- non_overwrite++;
+ s.non_overwrite++;
}
- if (dev->written) written++;
+ if (dev->written)
+ s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
@@ -1962,96 +2958,27 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
}
if (!rdev || !test_bit(In_sync, &rdev->flags)
|| test_bit(R5_ReadError, &dev->flags)) {
- if ( failed < 2 )
- failed_num[failed] = i;
- failed++;
+ if (s.failed < 2)
+ r6s.failed_num[s.failed] = i;
+ s.failed++;
} else
set_bit(R5_Insync, &dev->flags);
}
rcu_read_unlock();
- PRINTK("locked=%d uptodate=%d to_read=%d"
+ pr_debug("locked=%d uptodate=%d to_read=%d"
" to_write=%d failed=%d failed_num=%d,%d\n",
- locked, uptodate, to_read, to_write, failed,
- failed_num[0], failed_num[1]);
- /* check if the array has lost >2 devices and, if so, some requests might
- * need to be failed
+ s.locked, s.uptodate, s.to_read, s.to_write, s.failed,
+ r6s.failed_num[0], r6s.failed_num[1]);
+ /* check if the array has lost >2 devices and, if so, some requests
+ * might need to be failed
*/
- if (failed > 2 && to_read+to_write+written) {
- for (i=disks; i--; ) {
- int bitmap_end = 0;
-
- if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
- mdk_rdev_t *rdev;
- rcu_read_lock();
- rdev = rcu_dereference(conf->disks[i].rdev);
- if (rdev && test_bit(In_sync, &rdev->flags))
- /* multiple read failures in one stripe */
- md_error(conf->mddev, rdev);
- rcu_read_unlock();
- }
-
- spin_lock_irq(&conf->device_lock);
- /* fail all writes first */
- bi = sh->dev[i].towrite;
- sh->dev[i].towrite = NULL;
- if (bi) { to_write--; bitmap_end = 1; }
-
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
-
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
- struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = nextbi;
- }
- /* and fail all 'written' */
- bi = sh->dev[i].written;
- sh->dev[i].written = NULL;
- if (bi) bitmap_end = 1;
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) {
- struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = bi2;
- }
-
- /* fail any reads if this device is non-operational */
- if (!test_bit(R5_Insync, &sh->dev[i].flags) ||
- test_bit(R5_ReadError, &sh->dev[i].flags)) {
- bi = sh->dev[i].toread;
- sh->dev[i].toread = NULL;
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
- if (bi) to_read--;
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
- struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = nextbi;
- }
- }
- spin_unlock_irq(&conf->device_lock);
- if (bitmap_end)
- bitmap_endwrite(conf->mddev->bitmap, sh->sector,
- STRIPE_SECTORS, 0, 0);
- }
- }
- if (failed > 2 && syncing) {
+ if (s.failed > 2 && s.to_read+s.to_write+s.written)
+ handle_requests_to_failed_array(conf, sh, &s, disks,
+ &return_bi);
+ if (s.failed > 2 && s.syncing) {
md_done_sync(conf->mddev, STRIPE_SECTORS,0);
clear_bit(STRIPE_SYNCING, &sh->state);
- syncing = 0;
+ s.syncing = 0;
}
/*
@@ -2059,279 +2986,41 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
* are safe, or on a failed drive
*/
pdev = &sh->dev[pd_idx];
- p_failed = (failed >= 1 && failed_num[0] == pd_idx)
- || (failed >= 2 && failed_num[1] == pd_idx);
- qdev = &sh->dev[qd_idx];
- q_failed = (failed >= 1 && failed_num[0] == qd_idx)
- || (failed >= 2 && failed_num[1] == qd_idx);
-
- if ( written &&
- ( p_failed || ((test_bit(R5_Insync, &pdev->flags)
+ r6s.p_failed = (s.failed >= 1 && r6s.failed_num[0] == pd_idx)
+ || (s.failed >= 2 && r6s.failed_num[1] == pd_idx);
+ qdev = &sh->dev[r6s.qd_idx];
+ r6s.q_failed = (s.failed >= 1 && r6s.failed_num[0] == r6s.qd_idx)
+ || (s.failed >= 2 && r6s.failed_num[1] == r6s.qd_idx);
+
+ if ( s.written &&
+ ( r6s.p_failed || ((test_bit(R5_Insync, &pdev->flags)
&& !test_bit(R5_LOCKED, &pdev->flags)
- && test_bit(R5_UPTODATE, &pdev->flags))) ) &&
- ( q_failed || ((test_bit(R5_Insync, &qdev->flags)
+ && test_bit(R5_UPTODATE, &pdev->flags)))) &&
+ ( r6s.q_failed || ((test_bit(R5_Insync, &qdev->flags)
&& !test_bit(R5_LOCKED, &qdev->flags)
- && test_bit(R5_UPTODATE, &qdev->flags))) ) ) {
- /* any written block on an uptodate or failed drive can be
- * returned. Note that if we 'wrote' to a failed drive,
- * it will be UPTODATE, but never LOCKED, so we don't need
- * to test 'failed' directly.
- */
- for (i=disks; i--; )
- if (sh->dev[i].written) {
- dev = &sh->dev[i];
- if (!test_bit(R5_LOCKED, &dev->flags) &&
- test_bit(R5_UPTODATE, &dev->flags) ) {
- /* We can return any write requests */
- int bitmap_end = 0;
- struct bio *wbi, *wbi2;
- PRINTK("Return write for stripe %llu disc %d\n",
- (unsigned long long)sh->sector, i);
- spin_lock_irq(&conf->device_lock);
- wbi = dev->written;
- dev->written = NULL;
- while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) {
- wbi2 = r5_next_bio(wbi, dev->sector);
- if (--wbi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- wbi->bi_next = return_bi;
- return_bi = wbi;
- }
- wbi = wbi2;
- }
- if (dev->towrite == NULL)
- bitmap_end = 1;
- spin_unlock_irq(&conf->device_lock);
- if (bitmap_end)
- bitmap_endwrite(conf->mddev->bitmap, sh->sector,
- STRIPE_SECTORS,
- !test_bit(STRIPE_DEGRADED, &sh->state), 0);
- }
- }
- }
+ && test_bit(R5_UPTODATE, &qdev->flags)))))
+ handle_completed_write_requests(conf, sh, disks, &return_bi);
/* Now we might consider reading some blocks, either to check/generate
* parity, or to satisfy requests
* or to load a block that is being partially written.
*/
- if (to_read || non_overwrite || (to_write && failed) ||
- (syncing && (uptodate < disks)) || expanding) {
- for (i=disks; i--;) {
- dev = &sh->dev[i];
- if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
- (dev->toread ||
- (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
- syncing ||
- expanding ||
- (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) ||
- (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write))
- )
- ) {
- /* we would like to get this block, possibly
- * by computing it, but we might not be able to
- */
- if (uptodate == disks-1) {
- PRINTK("Computing stripe %llu block %d\n",
- (unsigned long long)sh->sector, i);
- compute_block_1(sh, i, 0);
- uptodate++;
- } else if ( uptodate == disks-2 && failed >= 2 ) {
- /* Computing 2-failure is *very* expensive; only do it if failed >= 2 */
- int other;
- for (other=disks; other--;) {
- if ( other == i )
- continue;
- if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) )
- break;
- }
- BUG_ON(other < 0);
- PRINTK("Computing stripe %llu blocks %d,%d\n",
- (unsigned long long)sh->sector, i, other);
- compute_block_2(sh, i, other);
- uptodate += 2;
- } else if (test_bit(R5_Insync, &dev->flags)) {
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantread, &dev->flags);
- locked++;
- PRINTK("Reading block %d (sync=%d)\n",
- i, syncing);
- }
- }
- }
- set_bit(STRIPE_HANDLE, &sh->state);
- }
+ if (s.to_read || s.non_overwrite || (s.to_write && s.failed) ||
+ (s.syncing && (s.uptodate < disks)) || s.expanding)
+ handle_issuing_new_read_requests6(sh, &s, &r6s, disks);
/* now to consider writing and what else, if anything should be read */
- if (to_write) {
- int rcw=0, must_compute=0;
- for (i=disks ; i--;) {
- dev = &sh->dev[i];
- /* Would I have to read this buffer for reconstruct_write */
- if (!test_bit(R5_OVERWRITE, &dev->flags)
- && i != pd_idx && i != qd_idx
- && (!test_bit(R5_LOCKED, &dev->flags)
- ) &&
- !test_bit(R5_UPTODATE, &dev->flags)) {
- if (test_bit(R5_Insync, &dev->flags)) rcw++;
- else {
- PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags);
- must_compute++;
- }
- }
- }
- PRINTK("for sector %llu, rcw=%d, must_compute=%d\n",
- (unsigned long long)sh->sector, rcw, must_compute);
- set_bit(STRIPE_HANDLE, &sh->state);
-
- if (rcw > 0)
- /* want reconstruct write, but need to get some data */
- for (i=disks; i--;) {
- dev = &sh->dev[i];
- if (!test_bit(R5_OVERWRITE, &dev->flags)
- && !(failed == 0 && (i == pd_idx || i == qd_idx))
- && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
- test_bit(R5_Insync, &dev->flags)) {
- if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
- {
- PRINTK("Read_old stripe %llu block %d for Reconstruct\n",
- (unsigned long long)sh->sector, i);
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantread, &dev->flags);
- locked++;
- } else {
- PRINTK("Request delayed stripe %llu block %d for Reconstruct\n",
- (unsigned long long)sh->sector, i);
- set_bit(STRIPE_DELAYED, &sh->state);
- set_bit(STRIPE_HANDLE, &sh->state);
- }
- }
- }
- /* now if nothing is locked, and if we have enough data, we can start a write request */
- if (locked == 0 && rcw == 0 &&
- !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
- if ( must_compute > 0 ) {
- /* We have failed blocks and need to compute them */
- switch ( failed ) {
- case 0: BUG();
- case 1: compute_block_1(sh, failed_num[0], 0); break;
- case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break;
- default: BUG(); /* This request should have been failed? */
- }
- }
-
- PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector);
- compute_parity6(sh, RECONSTRUCT_WRITE);
- /* now every locked buffer is ready to be written */
- for (i=disks; i--;)
- if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
- PRINTK("Writing stripe %llu block %d\n",
- (unsigned long long)sh->sector, i);
- locked++;
- set_bit(R5_Wantwrite, &sh->dev[i].flags);
- }
- /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */
- set_bit(STRIPE_INSYNC, &sh->state);
-
- if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
- atomic_dec(&conf->preread_active_stripes);
- if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
- md_wakeup_thread(conf->mddev->thread);
- }
- }
- }
+ if (s.to_write)
+ handle_issuing_new_write_requests6(conf, sh, &s, &r6s, disks);
/* maybe we need to check and possibly fix the parity for this stripe
- * Any reads will already have been scheduled, so we just see if enough data
- * is available
+ * Any reads will already have been scheduled, so we just see if enough
+ * data is available
*/
- if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) {
- int update_p = 0, update_q = 0;
- struct r5dev *dev;
-
- set_bit(STRIPE_HANDLE, &sh->state);
-
- BUG_ON(failed>2);
- BUG_ON(uptodate < disks);
- /* Want to check and possibly repair P and Q.
- * However there could be one 'failed' device, in which
- * case we can only check one of them, possibly using the
- * other to generate missing data
- */
-
- /* If !tmp_page, we cannot do the calculations,
- * but as we have set STRIPE_HANDLE, we will soon be called
- * by stripe_handle with a tmp_page - just wait until then.
- */
- if (tmp_page) {
- if (failed == q_failed) {
- /* The only possible failed device holds 'Q', so it makes
- * sense to check P (If anything else were failed, we would
- * have used P to recreate it).
- */
- compute_block_1(sh, pd_idx, 1);
- if (!page_is_zero(sh->dev[pd_idx].page)) {
- compute_block_1(sh,pd_idx,0);
- update_p = 1;
- }
- }
- if (!q_failed && failed < 2) {
- /* q is not failed, and we didn't use it to generate
- * anything, so it makes sense to check it
- */
- memcpy(page_address(tmp_page),
- page_address(sh->dev[qd_idx].page),
- STRIPE_SIZE);
- compute_parity6(sh, UPDATE_PARITY);
- if (memcmp(page_address(tmp_page),
- page_address(sh->dev[qd_idx].page),
- STRIPE_SIZE)!= 0) {
- clear_bit(STRIPE_INSYNC, &sh->state);
- update_q = 1;
- }
- }
- if (update_p || update_q) {
- conf->mddev->resync_mismatches += STRIPE_SECTORS;
- if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
- /* don't try to repair!! */
- update_p = update_q = 0;
- }
-
- /* now write out any block on a failed drive,
- * or P or Q if they need it
- */
+ if (s.syncing && s.locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state))
+ handle_parity_checks6(conf, sh, &s, &r6s, tmp_page, disks);
- if (failed == 2) {
- dev = &sh->dev[failed_num[1]];
- locked++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
- if (failed >= 1) {
- dev = &sh->dev[failed_num[0]];
- locked++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
-
- if (update_p) {
- dev = &sh->dev[pd_idx];
- locked ++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
- if (update_q) {
- dev = &sh->dev[qd_idx];
- locked++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
- clear_bit(STRIPE_DEGRADED, &sh->state);
-
- set_bit(STRIPE_INSYNC, &sh->state);
- }
- }
-
- if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
+ if (s.syncing && s.locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
md_done_sync(conf->mddev, STRIPE_SECTORS,1);
clear_bit(STRIPE_SYNCING, &sh->state);
}
@@ -2339,9 +3028,9 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
/* If the failed drives are just a ReadError, then we might need
* to progress the repair/check process
*/
- if (failed <= 2 && ! conf->mddev->ro)
- for (i=0; i<failed;i++) {
- dev = &sh->dev[failed_num[i]];
+ if (s.failed <= 2 && !conf->mddev->ro)
+ for (i = 0; i < s.failed; i++) {
+ dev = &sh->dev[r6s.failed_num[i]];
if (test_bit(R5_ReadError, &dev->flags)
&& !test_bit(R5_LOCKED, &dev->flags)
&& test_bit(R5_UPTODATE, &dev->flags)
@@ -2358,7 +3047,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
}
}
- if (expanded && test_bit(STRIPE_EXPANDING, &sh->state)) {
+ if (s.expanded && test_bit(STRIPE_EXPANDING, &sh->state)) {
/* Need to write out all blocks after computing P&Q */
sh->disks = conf->raid_disks;
sh->pd_idx = stripe_to_pdidx(sh->sector, conf,
@@ -2366,82 +3055,24 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
compute_parity6(sh, RECONSTRUCT_WRITE);
for (i = conf->raid_disks ; i-- ; ) {
set_bit(R5_LOCKED, &sh->dev[i].flags);
- locked++;
+ s.locked++;
set_bit(R5_Wantwrite, &sh->dev[i].flags);
}
clear_bit(STRIPE_EXPANDING, &sh->state);
- } else if (expanded) {
+ } else if (s.expanded) {
clear_bit(STRIPE_EXPAND_READY, &sh->state);
atomic_dec(&conf->reshape_stripes);
wake_up(&conf->wait_for_overlap);
md_done_sync(conf->mddev, STRIPE_SECTORS, 1);
}
- if (expanding && locked == 0) {
- /* We have read all the blocks in this stripe and now we need to
- * copy some of them into a target stripe for expand.
- */
- clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
- for (i = 0; i < sh->disks ; i++)
- if (i != pd_idx && i != qd_idx) {
- int dd_idx2, pd_idx2, j;
- struct stripe_head *sh2;
-
- sector_t bn = compute_blocknr(sh, i);
- sector_t s = raid5_compute_sector(
- bn, conf->raid_disks,
- conf->raid_disks - conf->max_degraded,
- &dd_idx2, &pd_idx2, conf);
- sh2 = get_active_stripe(conf, s,
- conf->raid_disks,
- pd_idx2, 1);
- if (sh2 == NULL)
- /* so for only the early blocks of
- * this stripe have been requests.
- * When later blocks get requests, we
- * will try again
- */
- continue;
- if (!test_bit(STRIPE_EXPANDING, &sh2->state) ||
- test_bit(R5_Expanded,
- &sh2->dev[dd_idx2].flags)) {
- /* must have already done this block */
- release_stripe(sh2);
- continue;
- }
- memcpy(page_address(sh2->dev[dd_idx2].page),
- page_address(sh->dev[i].page),
- STRIPE_SIZE);
- set_bit(R5_Expanded, &sh2->dev[dd_idx2].flags);
- set_bit(R5_UPTODATE, &sh2->dev[dd_idx2].flags);
- for (j = 0 ; j < conf->raid_disks ; j++)
- if (j != sh2->pd_idx &&
- j != raid6_next_disk(sh2->pd_idx,
- sh2->disks) &&
- !test_bit(R5_Expanded,
- &sh2->dev[j].flags))
- break;
- if (j == conf->raid_disks) {
- set_bit(STRIPE_EXPAND_READY,
- &sh2->state);
- set_bit(STRIPE_HANDLE, &sh2->state);
- }
- release_stripe(sh2);
- }
- }
+ if (s.expanding && s.locked == 0)
+ handle_stripe_expansion(conf, sh, &r6s);
spin_unlock(&sh->lock);
- while ((bi=return_bi)) {
- int bytes = bi->bi_size;
+ return_io(return_bi);
- return_bi = bi->bi_next;
- bi->bi_next = NULL;
- bi->bi_size = 0;
- bi->bi_end_io(bi, bytes,
- test_bit(BIO_UPTODATE, &bi->bi_flags)
- ? 0 : -EIO);
- }
for (i=disks; i-- ;) {
int rw;
struct bio *bi;
@@ -2470,11 +3101,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
rcu_read_unlock();
if (rdev) {
- if (syncing || expanding || expanded)
+ if (s.syncing || s.expanding || s.expanded)
md_sync_acct(rdev->bdev, STRIPE_SECTORS);
bi->bi_bdev = rdev->bdev;
- PRINTK("for %llu schedule op %ld on disc %d\n",
+ pr_debug("for %llu schedule op %ld on disc %d\n",
(unsigned long long)sh->sector, bi->bi_rw, i);
atomic_inc(&sh->count);
bi->bi_sector = sh->sector + rdev->data_offset;
@@ -2494,7 +3125,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
} else {
if (rw == WRITE)
set_bit(STRIPE_DEGRADED, &sh->state);
- PRINTK("skip op %ld on disc %d for sector %llu\n",
+ pr_debug("skip op %ld on disc %d for sector %llu\n",
bi->bi_rw, i, (unsigned long long)sh->sector);
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
@@ -2738,7 +3369,7 @@ static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
}
- PRINTK("raid5_align_endio : io error...handing IO for a retry\n");
+ pr_debug("raid5_align_endio : io error...handing IO for a retry\n");
add_bio_to_retry(raid_bi, conf);
return 0;
@@ -2776,7 +3407,7 @@ static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
mdk_rdev_t *rdev;
if (!in_chunk_boundary(mddev, raid_bio)) {
- PRINTK("chunk_aligned_read : non aligned\n");
+ pr_debug("chunk_aligned_read : non aligned\n");
return 0;
}
/*
@@ -2900,7 +3531,7 @@ static int make_request(request_queue_t *q, struct bio * bi)
new_sector = raid5_compute_sector(logical_sector, disks, data_disks,
&dd_idx, &pd_idx, conf);
- PRINTK("raid5: make_request, sector %llu logical %llu\n",
+ pr_debug("raid5: make_request, sector %llu logical %llu\n",
(unsigned long long)new_sector,
(unsigned long long)logical_sector);
@@ -3273,7 +3904,7 @@ static void raid5d (mddev_t *mddev)
raid5_conf_t *conf = mddev_to_conf(mddev);
int handled;
- PRINTK("+++ raid5d active\n");
+ pr_debug("+++ raid5d active\n");
md_check_recovery(mddev);
@@ -3308,8 +3939,10 @@ static void raid5d (mddev_t *mddev)
handled++;
}
- if (list_empty(&conf->handle_list))
+ if (list_empty(&conf->handle_list)) {
+ async_tx_issue_pending_all();
break;
+ }
first = conf->handle_list.next;
sh = list_entry(first, struct stripe_head, lru);
@@ -3325,13 +3958,13 @@ static void raid5d (mddev_t *mddev)
spin_lock_irq(&conf->device_lock);
}
- PRINTK("%d stripes handled\n", handled);
+ pr_debug("%d stripes handled\n", handled);
spin_unlock_irq(&conf->device_lock);
unplug_slaves(mddev);
- PRINTK("--- raid5d inactive\n");
+ pr_debug("--- raid5d inactive\n");
}
static ssize_t
@@ -3507,7 +4140,7 @@ static int run(mddev_t *mddev)
atomic_set(&conf->preread_active_stripes, 0);
atomic_set(&conf->active_aligned_reads, 0);
- PRINTK("raid5: run(%s) called.\n", mdname(mddev));
+ pr_debug("raid5: run(%s) called.\n", mdname(mddev));
ITERATE_RDEV(mddev,rdev,tmp) {
raid_disk = rdev->raid_disk;
@@ -3690,7 +4323,7 @@ static int stop(mddev_t *mddev)
return 0;
}
-#if RAID5_DEBUG
+#ifdef DEBUG
static void print_sh (struct seq_file *seq, struct stripe_head *sh)
{
int i;
@@ -3737,7 +4370,7 @@ static void status (struct seq_file *seq, mddev_t *mddev)
conf->disks[i].rdev &&
test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
seq_printf (seq, "]");
-#if RAID5_DEBUG
+#ifdef DEBUG
seq_printf (seq, "\n");
printall(seq, conf);
#endif
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 624b21cef5b3..d9d033e07e19 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -80,8 +80,12 @@ config VIDEO_BUF_DVB
config VIDEO_BTCX
tristate
+config VIDEO_IR_I2C
+ tristate
+
config VIDEO_IR
tristate
+ select VIDEO_IR_I2C if I2C
config VIDEO_TVEEPROM
tristate
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index fcb194135627..a3292e955aaa 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -107,21 +107,20 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
}
/* -------------------------------------------------------------------------- */
-
+/* extract mask bits out of data and pack them into the result */
u32 ir_extract_bits(u32 data, u32 mask)
{
- int mbit, vbit;
- u32 value;
+ u32 vbit = 1, value = 0;
+
+ do {
+ if (mask&1) {
+ if (data&1)
+ value |= vbit;
+ vbit<<=1;
+ }
+ data>>=1;
+ } while (mask>>=1);
- value = 0;
- vbit = 0;
- for (mbit = 0; mbit < 32; mbit++) {
- if (!(mask & ((u32)1 << mbit)))
- continue;
- if (data & ((u32)1 << mbit))
- value |= (1 << vbit);
- vbit++;
- }
return value;
}
@@ -346,8 +345,8 @@ void ir_rc5_timer_end(unsigned long data)
}
/* Set/reset key-up timer */
- timeout = current_jiffies + (500 + ir->rc5_key_timeout
- * HZ) / 1000;
+ timeout = current_jiffies +
+ msecs_to_jiffies(ir->rc5_key_timeout);
mod_timer(&ir->timer_keyup, timeout);
/* Save code for repeat test */
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index ef3e54cd9407..ba6701e97671 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -27,7 +27,7 @@ static int saa7146_num;
unsigned int saa7146_debug;
-module_param(saa7146_debug, int, 0644);
+module_param(saa7146_debug, uint, 0644);
MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
#if 0
@@ -130,10 +130,10 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
/********************************************************************************/
/* common page table functions */
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
{
int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
- char *mem = vmalloc_32(length);
+ void *mem = vmalloc_32(length);
int slen = 0;
if (NULL == mem)
@@ -168,7 +168,7 @@ err_null:
return NULL;
}
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt)
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
{
pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
saa7146_pgtable_free(pci, pt);
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e3d04a4cef4d..664280c78ff2 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -889,9 +889,9 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
DEB_EE(("VIDIOC_QUERYCAP\n"));
- strcpy(cap->driver, "saa7146 v4l2");
- strlcpy(cap->card, dev->ext->name, sizeof(cap->card));
- sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+ strcpy((char *)cap->driver, "saa7146 v4l2");
+ strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+ sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
cap->version = SAA7146_VERSION_CODE;
cap->capabilities =
V4L2_CAP_VIDEO_CAPTURE |
@@ -968,7 +968,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
}
memset(f,0,sizeof(*f));
f->index = index;
- strlcpy(f->description,formats[index].name,sizeof(f->description));
+ strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
f->pixelformat = formats[index].pixelformat;
break;
}
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index a0dcd59da76e..3197aeb61d1f 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,7 +1,7 @@
config DVB_B2C2_FLEXCOP
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
depends on DVB_CORE && I2C
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_MT312 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index bff00b58bf65..e97ff60a1eff 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -12,4 +12,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
b2c2-flexcop-usb-objs = flexcop-usb.o
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index b02c2fd65baa..0378fd646591 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -500,13 +500,13 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the air atsc 2nd generation (nxt2002) */
if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC2;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
+ dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
/* try the air atsc 3nd generation (lgdt3303) */
if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC3;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
+ dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
} else
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index cfd6fb729a61..ea666174e988 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -7,7 +7,7 @@ config DVB_BT8XX
select DVB_CX24110 if !DVB_FE_CUSTOMISE
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select FW_LOADER
help
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 9d197efb481d..84cf70504d17 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index e908e3cf1e50..b7a17e69ca4d 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1652,7 +1652,7 @@ static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
static int dst_tune_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status)
{
struct dst_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 4f1c09bee538..67613eb6fa3d 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -611,7 +611,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL) {
dvb_attach(dvb_pll_attach, card->fe, 0x61,
- card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
+ card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
dprintk ("dvb_bt8xx: lgdt330x detected\n");
}
break;
@@ -692,6 +692,9 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
case BTTV_BOARD_PC_HDTV:
card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+ if (card->fe != NULL)
+ dvb_attach(dvb_pll_attach, card->fe, 0x61,
+ card->i2c_adapter, DVB_PLL_FCV1236D);
break;
}
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
index c51aece20f9f..d762d8cb0cf1 100644
--- a/drivers/media/dvb/cinergyT2/Makefile
+++ b/drivers/media/dvb/cinergyT2/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index b40af48a2edb..28929b618e20 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -829,7 +829,7 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
input_dev->id.version = 1;
- input_dev->cdev.dev = &cinergyt2->udev->dev;
+ input_dev->dev.parent = &cinergyt2->udev->dev;
err = input_register_device(input_dev);
if (err) {
@@ -905,12 +905,11 @@ static int cinergyt2_probe (struct usb_interface *intf,
struct cinergyt2 *cinergyt2;
int err;
- if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
+ if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
dprintk(1, "out of memory?!?\n");
return -ENOMEM;
}
- memset (cinergyt2, 0, sizeof (struct cinergyt2));
usb_set_intfdata (intf, (void *) cinergyt2);
mutex_init(&cinergyt2->sem);
@@ -1000,18 +999,15 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
return -ERESTARTSYS;
- if (1) {
- cinergyt2_suspend_rc(cinergyt2);
- cancel_rearming_delayed_work(&cinergyt2->query_work);
+ cinergyt2_suspend_rc(cinergyt2);
+ cancel_rearming_delayed_work(&cinergyt2->query_work);
- mutex_lock(&cinergyt2->sem);
- if (cinergyt2->streaming)
- cinergyt2_stop_stream_xfer(cinergyt2);
- cinergyt2_sleep(cinergyt2, 1);
- mutex_unlock(&cinergyt2->sem);
- }
+ mutex_lock(&cinergyt2->sem);
+ if (cinergyt2->streaming)
+ cinergyt2_stop_stream_xfer(cinergyt2);
+ cinergyt2_sleep(cinergyt2, 1);
+ mutex_unlock(&cinergyt2->sem);
- mutex_unlock(&cinergyt2->wq_sem);
return 0;
}
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 275df65fde99..5394de2e4ce0 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -97,7 +97,7 @@ static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
if (avail > todo)
avail = todo;
- ret = dvb_ringbuffer_read(src, buf, avail, 1);
+ ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
if (ret < 0)
break;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 2a03bf53cb29..4fadddb264d6 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -175,7 +175,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * e
* @param nlen Number of bytes in needle.
* @return Pointer into haystack needle was found at, or NULL if not found.
*/
-static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
{
int i;
@@ -482,7 +482,7 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
}
/* check it contains the correct DVB string */
- dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+ dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
if (dvb_str == NULL)
return -EINVAL;
if (tupleLength < ((dvb_str - (char *) tuple) + 12))
@@ -513,8 +513,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
ca->slot_info[slot].config_option = tuple[0] & 0x3f;
/* OK, check it contains the correct strings */
- if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
- (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+ if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+ (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
break;
got_cftableentry = 1;
@@ -1300,7 +1300,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
struct dvb_ca_private *ca = dvbdev->priv;
u8 slot, connection_id;
int status;
- char fragbuf[HOST_LINK_BUF_SIZE];
+ u8 fragbuf[HOST_LINK_BUF_SIZE];
int fragpos = 0;
int fraglen;
unsigned long timeout;
@@ -1486,7 +1486,7 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
}
if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
- buf + pktlen, fraglen, 1)) < 0) {
+ (u8 *)buf + pktlen, fraglen, 1)) < 0) {
goto exit;
}
pktlen += fraglen;
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 6d8d1c3df863..cb6987fce26c 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1068,7 +1068,7 @@ static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
if (mutex_lock_interruptible(&dvbdemux->mutex))
return -ERESTARTSYS;
- dvb_dmx_swfilter(dvbdemux, buf, count);
+ dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
mutex_unlock(&dvbdemux->mutex);
if (signal_pending(current))
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index f4e4ca2dcade..b6c7f6610ec5 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -523,6 +523,7 @@ static int dvb_frontend_thread(void *data)
dvb_frontend_init(fe);
+ set_freezable();
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
restart:
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index f233d78bc364..a770a87b9a93 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -103,7 +103,7 @@ struct dvb_frontend_ops {
int (*tune)(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status);
/* get frontend tuning algorithm from the module */
int (*get_frontend_algo)(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 4ebf33a5ffa2..acf026342ec5 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -347,7 +347,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
{
struct dvb_net_priv *priv = dev->priv;
unsigned long skipped = 0L;
- u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
+ const u8 *ts, *ts_end, *from_where = NULL;
+ u8 ts_remain = 0, how_much = 0, new_ts = 1;
struct ethhdr *ethh = NULL;
#ifdef ULE_DEBUG
@@ -364,7 +365,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* For all TS cells in current buffer.
* Appearently, we are called for every single TS cell.
*/
- for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+ for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
if (new_ts) {
/* We are about to process a new TS cell. */
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index a9fa3337dd81..9ef0c00605ee 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -208,7 +208,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
if ((id = dvbdev_get_free_id (adap, type)) < 0){
mutex_unlock(&dvbdev_register_lock);
*pdvbdev = NULL;
- printk ("%s: could get find free device id...\n", __FUNCTION__);
+ printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
return -ENFILE;
}
@@ -252,7 +252,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
return PTR_ERR(clsdev);
}
- dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+ dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
nums2minor(adap->num, type, id));
@@ -311,7 +311,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list);
- printk ("DVB: registering new adapter (%s).\n", name);
+ printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
adap->num = num;
adap->name = name;
@@ -407,13 +407,13 @@ static int __init init_dvbdev(void)
dev_t dev = MKDEV(DVB_MAJOR, 0);
if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
return retval;
}
cdev_init(&dvb_device_cdev, &dvb_device_fops);
if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
- printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+ printk(KERN_ERR "dvb-core: unable register character device\n");
goto error;
}
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 54488737a08f..40e41f2f5afe 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -2,7 +2,6 @@ config DVB_USB
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB && I2C
select FW_LOADER
- select DVB_PLL
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -27,13 +26,14 @@ config DVB_USB_A800
depends on DVB_USB
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
config DVB_USB_DIBUSB_MB
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MB
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
@@ -89,7 +89,7 @@ config DVB_USB_DIB0700
config DVB_USB_UMT_010
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
@@ -98,7 +98,7 @@ config DVB_USB_UMT_010
config DVB_USB_CXUSB
tristate "Conexant USB2.0 hybrid reference design support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_CX22702 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
@@ -142,7 +142,7 @@ config DVB_USB_AU6610
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_NXT6000 if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
help
@@ -188,6 +188,7 @@ config DVB_USB_NOVA_T_USB2
depends on DVB_USB
select DVB_DIB3000MC
select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
@@ -216,5 +217,23 @@ config DVB_USB_OPERA1
tristate "Opera1 DVB-S USB2.0 receiver"
depends on DVB_USB
select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+config DVB_USB_AF9005
+ tristate "Afatech AF9005 DVB-T USB1.1 support"
+ depends on DVB_USB && EXPERIMENTAL
+ select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+ and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+ tristate "Afatech AF9005 default remote control support"
+ depends on DVB_USB_AF9005
+ help
+ Say Y here to support the default remote control decoding for the
+ Afatech AF9005 based receiver.
+
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 976f840cc904..73ac0a93fdeb 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -55,4 +55,10 @@ dvb-usb-opera-objs = opera1.o
obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-af9005-objs = af9005.o af9005-fe.o
+obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
+
+dvb-usb-af9005-remote-objs = af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
new file mode 100644
index 000000000000..7195c9461524
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-fe.c
@@ -0,0 +1,1503 @@
+/* Frontend part of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+#include "af9005-script.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include <asm/div64.h>
+
+struct af9005_fe_state {
+ struct dvb_usb_device *d;
+ struct dvb_frontend *tuner;
+
+ fe_status_t stat;
+
+ /* retraining parameters */
+ u32 original_fcw;
+ u16 original_rf_top;
+ u16 original_if_top;
+ u16 original_if_min;
+ u16 original_aci0_if_top;
+ u16 original_aci1_if_top;
+ u16 original_aci0_if_min;
+ u8 original_if_unplug_th;
+ u8 original_rf_unplug_th;
+ u8 original_dtop_if_unplug_th;
+ u8 original_dtop_rf_unplug_th;
+
+ /* statistics */
+ u32 pre_vit_error_count;
+ u32 pre_vit_bit_count;
+ u32 ber;
+ u32 post_vit_error_count;
+ u32 post_vit_bit_count;
+ u32 unc;
+ u16 abort_count;
+
+ int opened;
+ int strong;
+ unsigned long next_status_check;
+ struct dvb_frontend frontend;
+};
+
+static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
+ u16 reglo, u8 pos, u8 len, u16 value)
+{
+ int ret;
+ u8 temp;
+
+ if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
+ return ret;
+ temp = (u8) ((value & 0x0300) >> 8);
+ return af9005_write_register_bits(d, reghi, pos, len,
+ (u8) ((value & 0x300) >> 8));
+}
+
+static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
+ u16 reglo, u8 pos, u8 len, u16 * value)
+{
+ int ret;
+ u8 temp0, temp1;
+
+ if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
+ return ret;
+ if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
+ return ret;
+ switch (pos) {
+ case 0:
+ *value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
+ break;
+ case 2:
+ *value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
+ break;
+ case 4:
+ *value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
+ break;
+ case 6:
+ *value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
+ break;
+ default:
+ err("invalid pos in read word agc");
+ return -EINVAL;
+ }
+ return 0;
+
+}
+
+static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp;
+
+ *available = false;
+
+ ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+ fec_vtb_rsd_mon_en_pos,
+ fec_vtb_rsd_mon_en_len, &temp);
+ if (ret)
+ return ret;
+ if (temp & 1) {
+ ret =
+ af9005_read_register_bits(state->d,
+ xd_p_reg_ofsm_read_rbc_en,
+ reg_ofsm_read_rbc_en_pos,
+ reg_ofsm_read_rbc_en_len, &temp);
+ if (ret)
+ return ret;
+ if ((temp & 1) == 0)
+ *available = true;
+
+ }
+ return 0;
+}
+
+static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
+ u32 * post_err_count,
+ u32 * post_cw_count,
+ u16 * abort_count)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u32 err_count;
+ u32 cw_count;
+ u8 temp, temp0, temp1, temp2;
+ u16 loc_abort_count;
+
+ *post_err_count = 0;
+ *post_cw_count = 0;
+
+ /* check if error bit count is ready */
+ ret =
+ af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
+ fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (!temp) {
+ deb_info("rsd counter not ready\n");
+ return 100;
+ }
+ /* get abort count */
+ ret =
+ af9005_read_ofdm_register(state->d,
+ xd_r_fec_rsd_abort_packet_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d,
+ xd_r_fec_rsd_abort_packet_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ loc_abort_count = ((u16) temp1 << 8) + temp0;
+
+ /* get error count */
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
+ &temp2);
+ if (ret)
+ return ret;
+ err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+ *post_err_count = err_count - (u32) loc_abort_count *8 * 8;
+
+ /* get RSD packet number */
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ cw_count = ((u32) temp1 << 8) + temp0;
+ if (cw_count == 0) {
+ err("wrong RSD packet count");
+ return -EIO;
+ }
+ deb_info("POST abort count %d err count %d rsd packets %d\n",
+ loc_abort_count, err_count, cw_count);
+ *post_cw_count = cw_count - (u32) loc_abort_count;
+ *abort_count = loc_abort_count;
+ return 0;
+
+}
+
+static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
+ u32 * post_err_count, u32 * post_cw_count,
+ u16 * abort_count)
+{
+ u32 loc_cw_count = 0, loc_err_count;
+ u16 loc_abort_count;
+ int ret;
+
+ ret =
+ af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
+ &loc_abort_count);
+ if (ret)
+ return ret;
+ *post_err_count = loc_err_count;
+ *post_cw_count = loc_cw_count * 204 * 8;
+ *abort_count = loc_abort_count;
+
+ return 0;
+}
+
+static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
+ u32 * pre_err_count,
+ u32 * pre_bit_count)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp, temp0, temp1, temp2;
+ u32 super_frame_count, x, bits;
+ int ret;
+
+ ret =
+ af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
+ fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (!temp) {
+ deb_info("viterbi counter not ready\n");
+ return 101; /* ERR_APO_VTB_COUNTER_NOT_READY; */
+ }
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
+ &temp2);
+ if (ret)
+ return ret;
+ *pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+ &temp0);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+ &temp1);
+ if (ret)
+ return ret;
+ super_frame_count = ((u32) temp1 << 8) + temp0;
+ if (super_frame_count == 0) {
+ deb_info("super frame count 0\n");
+ return 102;
+ }
+
+ /* read fft mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+ reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (temp == 0) {
+ /* 2K */
+ x = 1512;
+ } else if (temp == 1) {
+ /* 8k */
+ x = 6048;
+ } else {
+ err("Invalid fft mode");
+ return -EINVAL;
+ }
+
+ /* read constellation mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+ reg_tpsd_const_pos, reg_tpsd_const_len,
+ &temp);
+ if (ret)
+ return ret;
+ switch (temp) {
+ case 0: /* QPSK */
+ bits = 2;
+ break;
+ case 1: /* QAM_16 */
+ bits = 4;
+ break;
+ case 2: /* QAM_64 */
+ bits = 6;
+ break;
+ default:
+ err("invalid constellation mode");
+ return -EINVAL;
+ }
+ *pre_bit_count = super_frame_count * 68 * 4 * x * bits;
+ deb_info("PRE err count %d frame count %d bit count %d\n",
+ *pre_err_count, super_frame_count, *pre_bit_count);
+ return 0;
+}
+
+static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+
+ /* set super frame count to 1 */
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+ 1 & 0xff);
+ if (ret)
+ return ret;
+ af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+ 1 >> 8);
+ if (ret)
+ return ret;
+ /* reset pre viterbi error count */
+ ret =
+ af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
+ fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
+ 1);
+
+ return ret;
+}
+
+static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+
+ /* set packet unit */
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+ 10000 & 0xff);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+ 10000 >> 8);
+ if (ret)
+ return ret;
+ /* reset post viterbi error count */
+ ret =
+ af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
+ fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
+ 1);
+
+ return ret;
+}
+
+static int af9005_get_statistic(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret, fecavailable;
+ u64 numerator, denominator;
+
+ deb_info("GET STATISTIC\n");
+ ret = af9005_is_fecmon_available(fe, &fecavailable);
+ if (ret)
+ return ret;
+ if (!fecavailable) {
+ deb_info("fecmon not available\n");
+ return 0;
+ }
+
+ ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
+ &state->pre_vit_bit_count);
+ if (ret == 0) {
+ af9005_reset_pre_viterbi(fe);
+ if (state->pre_vit_bit_count > 0) {
+ /* according to v 0.0.4 of the dvb api ber should be a multiple
+ of 10E-9 so we have to multiply the error count by
+ 10E9=1000000000 */
+ numerator =
+ (u64) state->pre_vit_error_count * (u64) 1000000000;
+ denominator = (u64) state->pre_vit_bit_count;
+ state->ber = do_div(numerator, denominator);
+ } else {
+ state->ber = 0xffffffff;
+ }
+ }
+
+ ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
+ &state->post_vit_bit_count,
+ &state->abort_count);
+ if (ret == 0) {
+ ret = af9005_reset_post_viterbi(fe);
+ state->unc += state->abort_count;
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int af9005_fe_refresh_state(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (time_after(jiffies, state->next_status_check)) {
+ deb_info("REFRESH STATE\n");
+
+ /* statistics */
+ if (af9005_get_statistic(fe))
+ err("get_statistic_failed");
+ state->next_status_check = jiffies + 250 * HZ / 1000;
+ }
+ return 0;
+}
+
+static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp;
+ int ret;
+
+ if (state->tuner == NULL)
+ return -ENODEV;
+
+ *stat = 0;
+ ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
+ agc_lock_pos, agc_lock_len, &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_SIGNAL;
+
+ ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
+ fd_tpsd_lock_pos, fd_tpsd_lock_len,
+ &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_CARRIER;
+
+ ret = af9005_read_register_bits(state->d,
+ xd_r_mp2if_sync_byte_locked,
+ mp2if_sync_byte_locked_pos,
+ mp2if_sync_byte_locked_pos, &temp);
+ if (ret)
+ return ret;
+ if (temp)
+ *stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
+ if (state->opened)
+ af9005_led_control(state->d, *stat & FE_HAS_LOCK);
+
+ ret =
+ af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
+ reg_strong_sginal_detected_pos,
+ reg_strong_sginal_detected_len, &temp);
+ if (ret)
+ return ret;
+ if (temp != state->strong) {
+ deb_info("adjust for strong signal %d\n", temp);
+ state->strong = temp;
+ }
+ return 0;
+}
+
+static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (state->tuner == NULL)
+ return -ENODEV;
+ af9005_fe_refresh_state(fe);
+ *ber = state->ber;
+ return 0;
+}
+
+static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ if (state->tuner == NULL)
+ return -ENODEV;
+ af9005_fe_refresh_state(fe);
+ *unc = state->unc;
+ return 0;
+}
+
+static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
+ u16 * strength)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 if_gain, rf_gain;
+
+ if (state->tuner == NULL)
+ return -ENODEV;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
+ &rf_gain);
+ if (ret)
+ return ret;
+ ret =
+ af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
+ &if_gain);
+ if (ret)
+ return ret;
+ /* this value has no real meaning, but i don't have the tables that relate
+ the rf and if gain with the dbm, so I just scale the value */
+ *strength = (512 - rf_gain - if_gain) << 7;
+ return 0;
+}
+
+static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+ /* the snr can be derived from the ber and the constellation
+ but I don't think this kind of complex calculations belong
+ in the driver. I may be wrong.... */
+ return -ENOSYS;
+}
+
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+ u8 temp0, temp1, temp2, temp3, buf[4];
+ int ret;
+ u32 NS_coeff1_2048Nu;
+ u32 NS_coeff1_8191Nu;
+ u32 NS_coeff1_8192Nu;
+ u32 NS_coeff1_8193Nu;
+ u32 NS_coeff2_2k;
+ u32 NS_coeff2_8k;
+
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ NS_coeff1_2048Nu = 0x2ADB6DC;
+ NS_coeff1_8191Nu = 0xAB7313;
+ NS_coeff1_8192Nu = 0xAB6DB7;
+ NS_coeff1_8193Nu = 0xAB685C;
+ NS_coeff2_2k = 0x156DB6E;
+ NS_coeff2_8k = 0x55B6DC;
+ break;
+
+ case BANDWIDTH_7_MHZ:
+ NS_coeff1_2048Nu = 0x3200001;
+ NS_coeff1_8191Nu = 0xC80640;
+ NS_coeff1_8192Nu = 0xC80000;
+ NS_coeff1_8193Nu = 0xC7F9C0;
+ NS_coeff2_2k = 0x1900000;
+ NS_coeff2_8k = 0x640000;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ NS_coeff1_2048Nu = 0x3924926;
+ NS_coeff1_8191Nu = 0xE4996E;
+ NS_coeff1_8192Nu = 0xE49249;
+ NS_coeff1_8193Nu = 0xE48B25;
+ NS_coeff2_2k = 0x1C92493;
+ NS_coeff2_8k = 0x724925;
+ break;
+ default:
+ err("Invalid bandwith %d.", bw);
+ return -EINVAL;
+ }
+
+ /*
+ * write NS_coeff1_2048Nu
+ */
+
+ temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
+ temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
+ temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ /* cfoe_NS_2k_coeff1_25_24 */
+ ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_23_16 */
+ ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_15_8 */
+ ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
+ if (ret)
+ return ret;
+
+ /* cfoe_NS_2k_coeff1_7_0 */
+ ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff2_2k
+ */
+
+ temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
+ temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
+ temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
+ temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8191Nu
+ */
+
+ temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
+ temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8192Nu
+ */
+
+ temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
+ temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff1_8193Nu
+ */
+
+ temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
+ temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
+ temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
+ temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
+ if (ret)
+ return ret;
+
+ /*
+ * write NS_coeff2_8k
+ */
+
+ temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
+ temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
+ temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
+ temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
+
+ /* big endian to make 8051 happy */
+ buf[0] = temp3;
+ buf[1] = temp2;
+ buf[2] = temp1;
+ buf[3] = temp0;
+
+ ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
+ if (ret)
+ return ret;
+
+ ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
+ return ret;
+
+}
+
+static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+ u8 temp;
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ temp = 0;
+ break;
+ case BANDWIDTH_7_MHZ:
+ temp = 1;
+ break;
+ case BANDWIDTH_8_MHZ:
+ temp = 2;
+ break;
+ default:
+ err("Invalid bandwith %d.", bw);
+ return -EINVAL;
+ }
+ return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
+ reg_bw_len, temp);
+}
+
+static int af9005_fe_power(struct dvb_frontend *fe, int on)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ u8 temp = on;
+ int ret;
+ deb_info("power %s tuner\n", on ? "on" : "off");
+ ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+ return ret;
+}
+
+static struct mt2060_config af9005_mt2060_config = {
+ 0xC0
+};
+
+static struct qt1010_config af9005_qt1010_config = {
+ 0xC4
+};
+
+static int af9005_fe_init(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ int ret, i, scriptlen;
+ u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
+ u8 buf[2];
+ u16 if1;
+
+ deb_info("in af9005_fe_init\n");
+
+ /* reset */
+ deb_info("reset\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
+ 4, 1, 0x01)))
+ return ret;
+ if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
+ return ret;
+ /* clear ofdm reset */
+ deb_info("clear ofdm reset\n");
+ for (i = 0; i < 150; i++) {
+ if ((ret =
+ af9005_read_ofdm_register(state->d,
+ xd_I2C_reg_ofdm_rst, &temp)))
+ return ret;
+ if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
+ break;
+ msleep(10);
+ }
+ if (i == 150)
+ return -ETIMEDOUT;
+
+ /*FIXME in the dump
+ write B200 A9
+ write xd_g_reg_ofsm_clk 7
+ read eepr c6 (2)
+ read eepr c7 (2)
+ misc ctrl 3 -> 1
+ read eepr ca (6)
+ write xd_g_reg_ofsm_clk 0
+ write B200 a1
+ */
+ ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
+ if (ret)
+ return ret;
+ temp = 0x01;
+ ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
+ if (ret)
+ return ret;
+
+ temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+ reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
+ return ret;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+ reg_ofdm_rst_pos, reg_ofdm_rst_len, 0)))
+ return ret;
+
+ if (ret)
+ return ret;
+ /* don't know what register aefc is, but this is what the windows driver does */
+ ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
+ if (ret)
+ return ret;
+
+ /* set stand alone chip */
+ deb_info("set stand alone chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
+ reg_dca_stand_alone_pos,
+ reg_dca_stand_alone_len, 1)))
+ return ret;
+
+ /* set dca upper & lower chip */
+ deb_info("set dca upper & lower chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
+ reg_dca_upper_chip_pos,
+ reg_dca_upper_chip_len, 0)))
+ return ret;
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
+ reg_dca_lower_chip_pos,
+ reg_dca_lower_chip_len, 0)))
+ return ret;
+
+ /* set 2wire master clock to 0x14 (for 60KHz) */
+ deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
+ if ((ret =
+ af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
+ return ret;
+
+ /* clear dca enable chip */
+ deb_info("clear dca enable chip\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_en,
+ reg_dca_en_pos, reg_dca_en_len, 0)))
+ return ret;
+ /* FIXME these are register bits, but I don't know which ones */
+ ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
+ if (ret)
+ return ret;
+
+ /* init other parameters: program cfoe and select bandwith */
+ deb_info("program cfoe\n");
+ if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+ return ret;
+ /* set read-update bit for constellation */
+ deb_info("set read-update bit for constellation\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
+ reg_feq_read_update_pos,
+ reg_feq_read_update_len, 1)))
+ return ret;
+
+ /* sample code has a set MPEG TS code here
+ but sniffing reveals that it doesn't do it */
+
+ /* set read-update bit to 1 for DCA constellation */
+ deb_info("set read-update bit 1 for DCA constellation\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
+ reg_dca_read_update_pos,
+ reg_dca_read_update_len, 1)))
+ return ret;
+
+ /* enable fec monitor */
+ deb_info("enable fec monitor\n");
+ if ((ret =
+ af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+ fec_vtb_rsd_mon_en_pos,
+ fec_vtb_rsd_mon_en_len, 1)))
+ return ret;
+
+ /* FIXME should be register bits, I don't know which ones */
+ ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
+
+ /* set api_retrain_never_freeze */
+ deb_info("set api_retrain_never_freeze\n");
+ if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
+ return ret;
+
+ /* load init script */
+ deb_info("load init script\n");
+ scriptlen = sizeof(script) / sizeof(RegDesc);
+ for (i = 0; i < scriptlen; i++) {
+ if ((ret =
+ af9005_write_register_bits(state->d, script[i].reg,
+ script[i].pos,
+ script[i].len, script[i].val)))
+ return ret;
+ /* save 3 bytes of original fcw */
+ if (script[i].reg == 0xae18)
+ temp2 = script[i].val;
+ if (script[i].reg == 0xae19)
+ temp1 = script[i].val;
+ if (script[i].reg == 0xae1a)
+ temp0 = script[i].val;
+
+ /* save original unplug threshold */
+ if (script[i].reg == xd_p_reg_unplug_th)
+ state->original_if_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+ state->original_rf_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+ state->original_dtop_if_unplug_th = script[i].val;
+ if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+ state->original_dtop_rf_unplug_th = script[i].val;
+
+ }
+ state->original_fcw =
+ ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+
+
+ /* save original TOPs */
+ deb_info("save original TOPs\n");
+
+ /* RF TOP */
+ ret =
+ af9005_read_word_agc(state->d,
+ xd_p_reg_aagc_rf_top_numerator_9_8,
+ xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+ &state->original_rf_top);
+ if (ret)
+ return ret;
+
+ /* IF TOP */
+ ret =
+ af9005_read_word_agc(state->d,
+ xd_p_reg_aagc_if_top_numerator_9_8,
+ xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+ &state->original_if_top);
+ if (ret)
+ return ret;
+
+ /* ACI 0 IF TOP */
+ ret =
+ af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+ &state->original_aci0_if_top);
+ if (ret)
+ return ret;
+
+ /* ACI 1 IF TOP */
+ ret =
+ af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+ &state->original_aci1_if_top);
+ if (ret)
+ return ret;
+
+ /* attach tuner and init */
+ if (state->tuner == NULL) {
+ /* read tuner and board id from eeprom */
+ ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
+ if (ret) {
+ err("Impossible to read EEPROM\n");
+ return ret;
+ }
+ deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
+ switch (buf[0]) {
+ case 2: /* MT2060 */
+ /* read if1 from eeprom */
+ ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
+ if (ret) {
+ err("Impossible to read EEPROM\n");
+ return ret;
+ }
+ if1 = (u16) (buf[0] << 8) + buf[1];
+ state->tuner =
+ dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
+ &af9005_mt2060_config, if1);
+ if (state->tuner == NULL) {
+ deb_info("MT2060 attach failed\n");
+ return -ENODEV;
+ }
+ break;
+ case 3: /* QT1010 */
+ case 9: /* QT1010B */
+ state->tuner =
+ dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
+ &af9005_qt1010_config);
+ if (state->tuner == NULL) {
+ deb_info("QT1010 attach failed\n");
+ return -ENODEV;
+ }
+ break;
+ default:
+ err("Unsupported tuner type %d", buf[0]);
+ return -ENODEV;
+ }
+ ret = state->tuner->ops.tuner_ops.init(state->tuner);
+ if (ret)
+ return ret;
+ }
+
+ deb_info("profit!\n");
+ return 0;
+}
+
+static int af9005_fe_sleep(struct dvb_frontend *fe)
+{
+ return af9005_fe_power(fe, 0);
+}
+
+static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+
+ if (acquire) {
+ state->opened++;
+ } else {
+
+ state->opened--;
+ if (!state->opened)
+ af9005_led_control(state->d, 0);
+ }
+ return 0;
+}
+
+static int af9005_fe_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp, temp0, temp1, temp2;
+
+ deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
+ fep->u.ofdm.bandwidth);
+ if (state->tuner == NULL) {
+ err("Tuner not attached");
+ return -ENODEV;
+ }
+
+ deb_info("turn off led\n");
+ /* not in the log */
+ ret = af9005_led_control(state->d, 0);
+ if (ret)
+ return ret;
+ /* not sure about the bits */
+ ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
+ if (ret)
+ return ret;
+
+ /* set FCW to default value */
+ deb_info("set FCW to default value\n");
+ temp0 = (u8) (state->original_fcw & 0x000000ff);
+ temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
+ temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
+ ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
+ if (ret)
+ return ret;
+ ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
+ if (ret)
+ return ret;
+
+ /* restore original TOPs */
+ deb_info("restore original TOPs\n");
+ ret =
+ af9005_write_word_agc(state->d,
+ xd_p_reg_aagc_rf_top_numerator_9_8,
+ xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+ state->original_rf_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d,
+ xd_p_reg_aagc_if_top_numerator_9_8,
+ xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+ state->original_if_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+ state->original_aci0_if_top);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+ state->original_aci1_if_top);
+ if (ret)
+ return ret;
+
+ /* select bandwith */
+ deb_info("select bandwidth");
+ ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+ if (ret)
+ return ret;
+ ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+ if (ret)
+ return ret;
+
+ /* clear easy mode flag */
+ deb_info("clear easy mode flag\n");
+ ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
+ if (ret)
+ return ret;
+
+ /* set unplug threshold to original value */
+ deb_info("set unplug threshold to original value\n");
+ ret =
+ af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
+ state->original_if_unplug_th);
+ if (ret)
+ return ret;
+ /* set tuner */
+ deb_info("set tuner\n");
+ ret = state->tuner->ops.tuner_ops.set_params(state->tuner, fep);
+ if (ret)
+ return ret;
+
+ /* trigger ofsm */
+ deb_info("trigger ofsm\n");
+ temp = 0;
+ ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
+ if (ret)
+ return ret;
+
+ /* clear retrain and freeze flag */
+ deb_info("clear retrain and freeze flag\n");
+ ret =
+ af9005_write_register_bits(state->d,
+ xd_p_reg_api_retrain_request,
+ reg_api_retrain_request_pos, 2, 0);
+ if (ret)
+ return ret;
+
+ /* reset pre viterbi and post viterbi registers and statistics */
+ af9005_reset_pre_viterbi(fe);
+ af9005_reset_post_viterbi(fe);
+ state->pre_vit_error_count = 0;
+ state->pre_vit_bit_count = 0;
+ state->ber = 0;
+ state->post_vit_error_count = 0;
+ /* state->unc = 0; commented out since it should be ever increasing */
+ state->abort_count = 0;
+
+ state->next_status_check = jiffies;
+ state->strong = -1;
+
+ return 0;
+}
+
+static int af9005_fe_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct af9005_fe_state *state = fe->demodulator_priv;
+ int ret;
+ u8 temp;
+
+ /* mode */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+ reg_tpsd_const_pos, reg_tpsd_const_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("===== fe_get_frontend ==============\n");
+ deb_info("CONSTELLATION ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.constellation = QPSK;
+ deb_info("QPSK\n");
+ break;
+ case 1:
+ fep->u.ofdm.constellation = QAM_16;
+ deb_info("QAM_16\n");
+ break;
+ case 2:
+ fep->u.ofdm.constellation = QAM_64;
+ deb_info("QAM_64\n");
+ break;
+ }
+
+ /* tps hierarchy and alpha value */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
+ reg_tpsd_hier_pos, reg_tpsd_hier_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("HIERARCHY ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ deb_info("NONE\n");
+ break;
+ case 1:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+ deb_info("1\n");
+ break;
+ case 2:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+ deb_info("2\n");
+ break;
+ case 3:
+ fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+ deb_info("4\n");
+ break;
+ }
+
+ /* high/low priority */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
+ reg_dec_pri_pos, reg_dec_pri_len, &temp);
+ if (ret)
+ return ret;
+ /* if temp is set = high priority */
+ deb_info("PRIORITY %s\n", temp ? "high" : "low");
+
+ /* high coderate */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
+ reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("CODERATE HP ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.code_rate_HP = FEC_1_2;
+ deb_info("FEC_1_2\n");
+ break;
+ case 1:
+ fep->u.ofdm.code_rate_HP = FEC_2_3;
+ deb_info("FEC_2_3\n");
+ break;
+ case 2:
+ fep->u.ofdm.code_rate_HP = FEC_3_4;
+ deb_info("FEC_3_4\n");
+ break;
+ case 3:
+ fep->u.ofdm.code_rate_HP = FEC_5_6;
+ deb_info("FEC_5_6\n");
+ break;
+ case 4:
+ fep->u.ofdm.code_rate_HP = FEC_7_8;
+ deb_info("FEC_7_8\n");
+ break;
+ }
+
+ /* low coderate */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
+ reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("CODERATE LP ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.code_rate_LP = FEC_1_2;
+ deb_info("FEC_1_2\n");
+ break;
+ case 1:
+ fep->u.ofdm.code_rate_LP = FEC_2_3;
+ deb_info("FEC_2_3\n");
+ break;
+ case 2:
+ fep->u.ofdm.code_rate_LP = FEC_3_4;
+ deb_info("FEC_3_4\n");
+ break;
+ case 3:
+ fep->u.ofdm.code_rate_LP = FEC_5_6;
+ deb_info("FEC_5_6\n");
+ break;
+ case 4:
+ fep->u.ofdm.code_rate_LP = FEC_7_8;
+ deb_info("FEC_7_8\n");
+ break;
+ }
+
+ /* guard interval */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
+ reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
+ if (ret)
+ return ret;
+ deb_info("GUARD INTERVAL ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+ deb_info("1_32\n");
+ break;
+ case 1:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+ deb_info("1_16\n");
+ break;
+ case 2:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+ deb_info("1_8\n");
+ break;
+ case 3:
+ fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+ deb_info("1_4\n");
+ break;
+ }
+
+ /* fft */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+ reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+ &temp);
+ if (ret)
+ return ret;
+ deb_info("TRANSMISSION MODE ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+ deb_info("2K\n");
+ break;
+ case 1:
+ fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+ deb_info("8K\n");
+ break;
+ }
+
+ /* bandwidth */
+ ret =
+ af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
+ reg_bw_len, &temp);
+ deb_info("BANDWIDTH ");
+ switch (temp) {
+ case 0:
+ fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ deb_info("6\n");
+ break;
+ case 1:
+ fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+ deb_info("7\n");
+ break;
+ case 2:
+ fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+ deb_info("8\n");
+ break;
+ }
+ return 0;
+}
+
+static void af9005_fe_release(struct dvb_frontend *fe)
+{
+ struct af9005_fe_state *state =
+ (struct af9005_fe_state *)fe->demodulator_priv;
+ if (state->tuner != NULL && state->tuner->ops.tuner_ops.release != NULL) {
+ state->tuner->ops.tuner_ops.release(state->tuner);
+#ifdef CONFIG_DVB_CORE_ATTACH
+ symbol_put_addr(state->tuner->ops.tuner_ops.release);
+#endif
+ }
+ kfree(state);
+}
+
+static struct dvb_frontend_ops af9005_fe_ops;
+
+struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
+{
+ struct af9005_fe_state *state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ deb_info("attaching frontend af9005\n");
+
+ state->d = d;
+ state->tuner = NULL;
+ state->opened = 0;
+
+ memcpy(&state->frontend.ops, &af9005_fe_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+ error:
+ return NULL;
+}
+
+static struct dvb_frontend_ops af9005_fe_ops = {
+ .info = {
+ .name = "AF9005 USB DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 250000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = af9005_fe_release,
+
+ .init = af9005_fe_init,
+ .sleep = af9005_fe_sleep,
+ .ts_bus_ctrl = af9005_ts_bus_ctrl,
+
+ .set_frontend = af9005_fe_set_frontend,
+ .get_frontend = af9005_fe_get_frontend,
+
+ .read_status = af9005_fe_read_status,
+ .read_ber = af9005_fe_read_ber,
+ .read_signal_strength = af9005_fe_read_signal_strength,
+ .read_snr = af9005_fe_read_snr,
+ .read_ucblocks = af9005_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
new file mode 100644
index 000000000000..ff00c0e8f4a1
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -0,0 +1,157 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Standard remote decode function
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+/* debug */
+int dvb_usb_af9005_remote_debug;
+module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "enable (1) or disable (0) debug messages."
+ DVB_USB_DEBUG_STATUS);
+
+#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
+
+struct dvb_usb_rc_key af9005_rc_keys[] = {
+
+ {0x01, 0xb7, KEY_POWER},
+ {0x01, 0xa7, KEY_VOLUMEUP},
+ {0x01, 0x87, KEY_CHANNELUP},
+ {0x01, 0x7f, KEY_MUTE},
+ {0x01, 0xbf, KEY_VOLUMEDOWN},
+ {0x01, 0x3f, KEY_CHANNELDOWN},
+ {0x01, 0xdf, KEY_1},
+ {0x01, 0x5f, KEY_2},
+ {0x01, 0x9f, KEY_3},
+ {0x01, 0x1f, KEY_4},
+ {0x01, 0xef, KEY_5},
+ {0x01, 0x6f, KEY_6},
+ {0x01, 0xaf, KEY_7},
+ {0x01, 0x27, KEY_8},
+ {0x01, 0x07, KEY_9},
+ {0x01, 0xcf, KEY_ZOOM},
+ {0x01, 0x4f, KEY_0},
+ {0x01, 0x8f, KEY_GOTO}, /* marked jump on the remote */
+
+ {0x00, 0xbd, KEY_POWER},
+ {0x00, 0x7d, KEY_VOLUMEUP},
+ {0x00, 0xfd, KEY_CHANNELUP},
+ {0x00, 0x9d, KEY_MUTE},
+ {0x00, 0x5d, KEY_VOLUMEDOWN},
+ {0x00, 0xdd, KEY_CHANNELDOWN},
+ {0x00, 0xad, KEY_1},
+ {0x00, 0x6d, KEY_2},
+ {0x00, 0xed, KEY_3},
+ {0x00, 0x8d, KEY_4},
+ {0x00, 0x4d, KEY_5},
+ {0x00, 0xcd, KEY_6},
+ {0x00, 0xb5, KEY_7},
+ {0x00, 0x75, KEY_8},
+ {0x00, 0xf5, KEY_9},
+ {0x00, 0x95, KEY_ZOOM},
+ {0x00, 0x55, KEY_0},
+ {0x00, 0xd5, KEY_GOTO}, /* marked jump on the remote */
+};
+
+int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
+
+static int repeatable_keys[] = {
+ KEY_VOLUMEUP,
+ KEY_VOLUMEDOWN,
+ KEY_CHANNELUP,
+ KEY_CHANNELDOWN
+};
+
+int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
+ int *state)
+{
+ u16 mark, space;
+ u32 result;
+ u8 cust, dat, invdat;
+ int i;
+
+ if (len >= 6) {
+ mark = (u16) (data[0] << 8) + data[1];
+ space = (u16) (data[2] << 8) + data[3];
+ if (space * 3 < mark) {
+ for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+ if (d->last_event == repeatable_keys[i]) {
+ *state = REMOTE_KEY_REPEAT;
+ *event = d->last_event;
+ deb_decode("repeat key, event %x\n",
+ *event);
+ return 0;
+ }
+ }
+ deb_decode("repeated key ignored (non repeatable)\n");
+ return 0;
+ } else if (len >= 33 * 4) { /*32 bits + start code */
+ result = 0;
+ for (i = 4; i < 4 + 32 * 4; i += 4) {
+ result <<= 1;
+ mark = (u16) (data[i] << 8) + data[i + 1];
+ mark >>= 1;
+ space = (u16) (data[i + 2] << 8) + data[i + 3];
+ space >>= 1;
+ if (mark * 2 > space)
+ result += 1;
+ }
+ deb_decode("key pressed, raw value %x\n", result);
+ if ((result & 0xff000000) != 0xfe000000) {
+ deb_decode
+ ("doesn't start with 0xfe, ignored\n");
+ return 0;
+ }
+ cust = (result >> 16) & 0xff;
+ dat = (result >> 8) & 0xff;
+ invdat = (~result) & 0xff;
+ if (dat != invdat) {
+ deb_decode("code != inverted code\n");
+ return 0;
+ }
+ for (i = 0; i < af9005_rc_keys_size; i++) {
+ if (af9005_rc_keys[i].custom == cust
+ && af9005_rc_keys[i].data == dat) {
+ *event = af9005_rc_keys[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ deb_decode
+ ("key pressed, event %x\n", *event);
+ return 0;
+ }
+ }
+ deb_decode("not found in table\n");
+ }
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL(af9005_rc_keys);
+EXPORT_SYMBOL(af9005_rc_keys_size);
+EXPORT_SYMBOL(af9005_rc_decode);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION
+ ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
new file mode 100644
index 000000000000..6eeaae51b1ca
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-script.h
@@ -0,0 +1,203 @@
+/*
+File automatically generated by createinit.py using data
+extracted from AF05BDA.sys (windows driver):
+
+dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
+python createinit.py > af9005-script.h
+
+*/
+
+typedef struct {
+ u16 reg;
+ u8 pos;
+ u8 len;
+ u8 val;
+} RegDesc;
+
+RegDesc script[] = {
+ {0xa180, 0x0, 0x8, 0xa},
+ {0xa181, 0x0, 0x8, 0xd7},
+ {0xa182, 0x0, 0x8, 0xa3},
+ {0xa0a0, 0x0, 0x8, 0x0},
+ {0xa0a1, 0x0, 0x5, 0x0},
+ {0xa0a1, 0x5, 0x1, 0x1},
+ {0xa0c0, 0x0, 0x4, 0x1},
+ {0xa20e, 0x4, 0x4, 0xa},
+ {0xa20f, 0x0, 0x8, 0x40},
+ {0xa210, 0x0, 0x8, 0x8},
+ {0xa32a, 0x0, 0x4, 0xa},
+ {0xa32c, 0x0, 0x8, 0x20},
+ {0xa32b, 0x0, 0x8, 0x15},
+ {0xa1a0, 0x1, 0x1, 0x1},
+ {0xa000, 0x0, 0x1, 0x1},
+ {0xa000, 0x1, 0x1, 0x0},
+ {0xa001, 0x1, 0x1, 0x1},
+ {0xa001, 0x0, 0x1, 0x0},
+ {0xa001, 0x5, 0x1, 0x0},
+ {0xa00e, 0x0, 0x5, 0x10},
+ {0xa00f, 0x0, 0x3, 0x4},
+ {0xa00f, 0x3, 0x3, 0x5},
+ {0xa010, 0x0, 0x3, 0x4},
+ {0xa010, 0x3, 0x3, 0x5},
+ {0xa016, 0x4, 0x4, 0x3},
+ {0xa01f, 0x0, 0x6, 0xa},
+ {0xa020, 0x0, 0x6, 0xa},
+ {0xa2bc, 0x0, 0x1, 0x1},
+ {0xa2bc, 0x5, 0x1, 0x1},
+ {0xa015, 0x0, 0x8, 0x50},
+ {0xa016, 0x0, 0x1, 0x0},
+ {0xa02a, 0x0, 0x8, 0x50},
+ {0xa029, 0x0, 0x8, 0x4b},
+ {0xa614, 0x0, 0x8, 0x46},
+ {0xa002, 0x0, 0x5, 0x19},
+ {0xa003, 0x0, 0x5, 0x1a},
+ {0xa004, 0x0, 0x5, 0x19},
+ {0xa005, 0x0, 0x5, 0x1a},
+ {0xa008, 0x0, 0x8, 0x69},
+ {0xa009, 0x0, 0x2, 0x2},
+ {0xae1b, 0x0, 0x8, 0x69},
+ {0xae1c, 0x0, 0x8, 0x2},
+ {0xae1d, 0x0, 0x8, 0x2a},
+ {0xa022, 0x0, 0x8, 0xaa},
+ {0xa006, 0x0, 0x8, 0xc8},
+ {0xa007, 0x0, 0x2, 0x0},
+ {0xa00c, 0x0, 0x8, 0xba},
+ {0xa00d, 0x0, 0x2, 0x2},
+ {0xa608, 0x0, 0x8, 0xba},
+ {0xa60e, 0x0, 0x2, 0x2},
+ {0xa609, 0x0, 0x8, 0x80},
+ {0xa60e, 0x2, 0x2, 0x3},
+ {0xa00a, 0x0, 0x8, 0xb6},
+ {0xa00b, 0x0, 0x2, 0x0},
+ {0xa011, 0x0, 0x8, 0xb9},
+ {0xa012, 0x0, 0x2, 0x0},
+ {0xa013, 0x0, 0x8, 0xbd},
+ {0xa014, 0x0, 0x2, 0x2},
+ {0xa366, 0x0, 0x1, 0x1},
+ {0xa2bc, 0x3, 0x1, 0x0},
+ {0xa2bd, 0x0, 0x8, 0xa},
+ {0xa2be, 0x0, 0x8, 0x14},
+ {0xa2bf, 0x0, 0x8, 0x8},
+ {0xa60a, 0x0, 0x8, 0xbd},
+ {0xa60e, 0x4, 0x2, 0x2},
+ {0xa60b, 0x0, 0x8, 0x86},
+ {0xa60e, 0x6, 0x2, 0x3},
+ {0xa001, 0x2, 0x2, 0x1},
+ {0xa1c7, 0x0, 0x8, 0xf5},
+ {0xa03d, 0x0, 0x8, 0xb1},
+ {0xa616, 0x0, 0x8, 0xff},
+ {0xa617, 0x0, 0x8, 0xad},
+ {0xa618, 0x0, 0x8, 0xad},
+ {0xa61e, 0x3, 0x1, 0x1},
+ {0xae1a, 0x0, 0x8, 0x0},
+ {0xae19, 0x0, 0x8, 0xc8},
+ {0xae18, 0x0, 0x8, 0x61},
+ {0xa140, 0x0, 0x8, 0x0},
+ {0xa141, 0x0, 0x8, 0xc8},
+ {0xa142, 0x0, 0x7, 0x61},
+ {0xa023, 0x0, 0x8, 0xff},
+ {0xa021, 0x0, 0x8, 0xad},
+ {0xa026, 0x0, 0x1, 0x0},
+ {0xa024, 0x0, 0x8, 0xff},
+ {0xa025, 0x0, 0x8, 0xff},
+ {0xa1c8, 0x0, 0x8, 0xf},
+ {0xa2bc, 0x1, 0x1, 0x0},
+ {0xa60c, 0x0, 0x4, 0x5},
+ {0xa60c, 0x4, 0x4, 0x6},
+ {0xa60d, 0x0, 0x8, 0xa},
+ {0xa371, 0x0, 0x1, 0x1},
+ {0xa366, 0x1, 0x3, 0x7},
+ {0xa338, 0x0, 0x8, 0x10},
+ {0xa339, 0x0, 0x6, 0x7},
+ {0xa33a, 0x0, 0x6, 0x1f},
+ {0xa33b, 0x0, 0x8, 0xf6},
+ {0xa33c, 0x3, 0x5, 0x4},
+ {0xa33d, 0x4, 0x4, 0x0},
+ {0xa33d, 0x1, 0x1, 0x1},
+ {0xa33d, 0x2, 0x1, 0x1},
+ {0xa33d, 0x3, 0x1, 0x1},
+ {0xa16d, 0x0, 0x4, 0xf},
+ {0xa161, 0x0, 0x5, 0x5},
+ {0xa162, 0x0, 0x4, 0x5},
+ {0xa165, 0x0, 0x8, 0xff},
+ {0xa166, 0x0, 0x8, 0x9c},
+ {0xa2c3, 0x0, 0x4, 0x5},
+ {0xa61a, 0x0, 0x6, 0xf},
+ {0xb200, 0x0, 0x8, 0xa1},
+ {0xb201, 0x0, 0x8, 0x7},
+ {0xa093, 0x0, 0x1, 0x0},
+ {0xa093, 0x1, 0x5, 0xf},
+ {0xa094, 0x0, 0x8, 0xff},
+ {0xa095, 0x0, 0x8, 0xf},
+ {0xa080, 0x2, 0x5, 0x3},
+ {0xa081, 0x0, 0x4, 0x0},
+ {0xa081, 0x4, 0x4, 0x9},
+ {0xa082, 0x0, 0x5, 0x1f},
+ {0xa08d, 0x0, 0x8, 0x1},
+ {0xa083, 0x0, 0x8, 0x32},
+ {0xa084, 0x0, 0x1, 0x0},
+ {0xa08e, 0x0, 0x8, 0x3},
+ {0xa085, 0x0, 0x8, 0x32},
+ {0xa086, 0x0, 0x3, 0x0},
+ {0xa087, 0x0, 0x8, 0x6e},
+ {0xa088, 0x0, 0x5, 0x15},
+ {0xa089, 0x0, 0x8, 0x0},
+ {0xa08a, 0x0, 0x5, 0x19},
+ {0xa08b, 0x0, 0x8, 0x92},
+ {0xa08c, 0x0, 0x5, 0x1c},
+ {0xa120, 0x0, 0x8, 0x0},
+ {0xa121, 0x0, 0x5, 0x10},
+ {0xa122, 0x0, 0x8, 0x0},
+ {0xa123, 0x0, 0x7, 0x40},
+ {0xa123, 0x7, 0x1, 0x0},
+ {0xa124, 0x0, 0x8, 0x13},
+ {0xa125, 0x0, 0x7, 0x10},
+ {0xa1c0, 0x0, 0x8, 0x0},
+ {0xa1c1, 0x0, 0x5, 0x4},
+ {0xa1c2, 0x0, 0x8, 0x0},
+ {0xa1c3, 0x0, 0x5, 0x10},
+ {0xa1c3, 0x5, 0x3, 0x0},
+ {0xa1c4, 0x0, 0x6, 0x0},
+ {0xa1c5, 0x0, 0x7, 0x10},
+ {0xa100, 0x0, 0x8, 0x0},
+ {0xa101, 0x0, 0x5, 0x10},
+ {0xa102, 0x0, 0x8, 0x0},
+ {0xa103, 0x0, 0x7, 0x40},
+ {0xa103, 0x7, 0x1, 0x0},
+ {0xa104, 0x0, 0x8, 0x18},
+ {0xa105, 0x0, 0x7, 0xa},
+ {0xa106, 0x0, 0x8, 0x20},
+ {0xa107, 0x0, 0x8, 0x40},
+ {0xa108, 0x0, 0x4, 0x0},
+ {0xa38c, 0x0, 0x8, 0xfc},
+ {0xa38d, 0x0, 0x8, 0x0},
+ {0xa38e, 0x0, 0x8, 0x7e},
+ {0xa38f, 0x0, 0x8, 0x0},
+ {0xa390, 0x0, 0x8, 0x2f},
+ {0xa60f, 0x5, 0x1, 0x1},
+ {0xa170, 0x0, 0x8, 0xdc},
+ {0xa171, 0x0, 0x2, 0x0},
+ {0xa2ae, 0x0, 0x1, 0x1},
+ {0xa2ae, 0x1, 0x1, 0x1},
+ {0xa392, 0x0, 0x1, 0x1},
+ {0xa391, 0x2, 0x1, 0x0},
+ {0xabc1, 0x0, 0x8, 0xff},
+ {0xabc2, 0x0, 0x8, 0x0},
+ {0xabc8, 0x0, 0x8, 0x8},
+ {0xabca, 0x0, 0x8, 0x10},
+ {0xabcb, 0x0, 0x1, 0x0},
+ {0xabc3, 0x5, 0x3, 0x7},
+ {0xabc0, 0x6, 0x1, 0x0},
+ {0xabc0, 0x4, 0x2, 0x0},
+ {0xa344, 0x4, 0x4, 0x1},
+ {0xabc0, 0x7, 0x1, 0x1},
+ {0xabc0, 0x2, 0x1, 0x1},
+ {0xa345, 0x0, 0x8, 0x66},
+ {0xa346, 0x0, 0x8, 0x66},
+ {0xa347, 0x0, 0x4, 0x0},
+ {0xa343, 0x0, 0x4, 0xa},
+ {0xa347, 0x4, 0x4, 0x2},
+ {0xa348, 0x0, 0x4, 0xc},
+ {0xa348, 0x4, 0x4, 0x7},
+ {0xa349, 0x0, 0x6, 0x2},
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
new file mode 100644
index 000000000000..7db6eee50e39
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -0,0 +1,1141 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+
+/* debug */
+int dvb_usb_af9005_debug;
+module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
+ DVB_USB_DEBUG_STATUS);
+/* enable obnoxious led */
+int dvb_usb_af9005_led = 1;
+module_param_named(led, dvb_usb_af9005_led, bool, 0644);
+MODULE_PARM_DESC(led, "enable led (default: 1).");
+
+/* eeprom dump */
+int dvb_usb_af9005_dump_eeprom = 0;
+module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
+MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
+
+/* remote control decoder */
+int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
+ int *state);
+void *rc_keys;
+int *rc_keys_size;
+
+u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+struct af9005_device_state {
+ u8 sequence;
+ int led_state;
+};
+
+int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
+ u8 * rbuf, u16 rlen, int delay_ms)
+{
+ int actlen, ret = -ENOMEM;
+
+ if (wbuf == NULL || wlen == 0)
+ return -EINVAL;
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ deb_xfer(">>> ");
+ debug_dump(wbuf, wlen, deb_xfer);
+
+ ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+ 2), wbuf, wlen,
+ &actlen, 2000);
+
+ if (ret)
+ err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
+ else
+ ret = actlen != wlen ? -1 : 0;
+
+ /* an answer is expected, and no error before */
+ if (!ret && rbuf && rlen) {
+ if (delay_ms)
+ msleep(delay_ms);
+
+ ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+ 0x01), rbuf,
+ rlen, &actlen, 2000);
+
+ if (ret)
+ err("recv bulk message failed: %d", ret);
+ else {
+ deb_xfer("<<< ");
+ debug_dump(rbuf, actlen, deb_xfer);
+ }
+ }
+
+ mutex_unlock(&d->usb_mutex);
+ return ret;
+}
+
+int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
+{
+ return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
+}
+
+int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+ int readwrite, int type, u8 * values, int len)
+{
+ struct af9005_device_state *st = d->priv;
+ u8 obuf[16] = { 0 };
+ u8 ibuf[17] = { 0 };
+ u8 command;
+ int i;
+ int ret;
+
+ if (len < 1) {
+ err("generic read/write, less than 1 byte. Makes no sense.");
+ return -EINVAL;
+ }
+ if (len > 8) {
+ err("generic read/write, more than 8 bytes. Not supported.");
+ return -EINVAL;
+ }
+
+ obuf[0] = 14; /* rest of buffer length low */
+ obuf[1] = 0; /* rest of buffer length high */
+
+ obuf[2] = AF9005_REGISTER_RW; /* register operation */
+ obuf[3] = 12; /* rest of buffer length */
+
+ obuf[4] = st->sequence++; /* sequence number */
+
+ obuf[5] = (u8) (reg >> 8); /* register address */
+ obuf[6] = (u8) (reg & 0xff);
+
+ if (type == AF9005_OFDM_REG) {
+ command = AF9005_CMD_OFDM_REG;
+ } else {
+ command = AF9005_CMD_TUNER;
+ }
+
+ if (len > 1)
+ command |=
+ AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
+ command |= readwrite;
+ if (readwrite == AF9005_CMD_WRITE)
+ for (i = 0; i < len; i++)
+ obuf[8 + i] = values[i];
+ else if (type == AF9005_TUNER_REG)
+ /* read command for tuner, the first byte contains the i2c address */
+ obuf[8] = values[0];
+ obuf[7] = command;
+
+ ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+ if (ret)
+ return ret;
+
+ /* sanity check */
+ if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+ err("generic read/write, wrong reply code.");
+ return -EIO;
+ }
+ if (ibuf[3] != 0x0d) {
+ err("generic read/write, wrong length in reply.");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("generic read/write, wrong sequence in reply.");
+ return -EIO;
+ }
+ /*
+ Windows driver doesn't check these fields, in fact sometimes
+ the register in the reply is different that what has been sent
+
+ if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
+ err("generic read/write, wrong register in reply.");
+ return -EIO;
+ }
+ if (ibuf[7] != command) {
+ err("generic read/write wrong command in reply.");
+ return -EIO;
+ }
+ */
+ if (ibuf[16] != 0x01) {
+ err("generic read/write wrong status code in reply.");
+ return -EIO;
+ }
+ if (readwrite == AF9005_CMD_READ)
+ for (i = 0; i < len; i++)
+ values[i] = ibuf[8 + i];
+
+ return 0;
+
+}
+
+int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
+{
+ int ret;
+ deb_reg("read register %x ", reg);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_OFDM_REG,
+ value, 1);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("value %x\n", *value);
+ return ret;
+}
+
+int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ int ret;
+ deb_reg("read %d registers %x ", len, reg);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_OFDM_REG,
+ values, len);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ debug_dump(values, len, deb_reg);
+ return ret;
+}
+
+int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
+{
+ int ret;
+ u8 temp = value;
+ deb_reg("write register %x value %x ", reg, value);
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE, AF9005_OFDM_REG,
+ &temp, 1);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("ok\n");
+ return ret;
+}
+
+int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ int ret;
+ deb_reg("write %d registers %x values ", len, reg);
+ debug_dump(values, len, deb_reg);
+
+ ret = af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE, AF9005_OFDM_REG,
+ values, len);
+ if (ret)
+ deb_reg("failed\n");
+ else
+ deb_reg("ok\n");
+ return ret;
+}
+
+int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+ u8 len, u8 * value)
+{
+ u8 temp;
+ int ret;
+ deb_reg("read bits %x %x %x", reg, pos, len);
+ ret = af9005_read_ofdm_register(d, reg, &temp);
+ if (ret) {
+ deb_reg(" failed\n");
+ return ret;
+ }
+ *value = (temp >> pos) & regmask[len - 1];
+ deb_reg(" value %x\n", *value);
+ return 0;
+
+}
+
+int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+ u8 len, u8 value)
+{
+ u8 temp, mask;
+ int ret;
+ deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
+ if (pos == 0 && len == 8)
+ return af9005_write_ofdm_register(d, reg, value);
+ ret = af9005_read_ofdm_register(d, reg, &temp);
+ if (ret)
+ return ret;
+ mask = regmask[len - 1] << pos;
+ temp = (temp & ~mask) | ((value << pos) & mask);
+ return af9005_write_ofdm_register(d, reg, temp);
+
+}
+
+static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
+ u16 reg, u8 * values, int len)
+{
+ return af9005_generic_read_write(d, reg,
+ AF9005_CMD_READ, AF9005_TUNER_REG,
+ values, len);
+}
+
+static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
+ u16 reg, u8 * values, int len)
+{
+ return af9005_generic_read_write(d, reg,
+ AF9005_CMD_WRITE,
+ AF9005_TUNER_REG, values, len);
+}
+
+int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len)
+{
+ /* don't let the name of this function mislead you: it's just used
+ as an interface from the firmware to the i2c bus. The actual
+ i2c addresses are contained in the data */
+ int ret, i, done = 0, fail = 0;
+ u8 temp;
+ ret = af9005_usb_write_tuner_registers(d, reg, values, len);
+ if (ret)
+ return ret;
+ if (reg != 0xffff) {
+ /* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
+ for (i = 0; i < 200; i++) {
+ ret =
+ af9005_read_ofdm_register(d,
+ xd_I2C_i2c_m_status_wdat_done,
+ &temp);
+ if (ret)
+ return ret;
+ done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
+ << i2c_m_status_wdat_done_pos);
+ if (done)
+ break;
+ fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
+ << i2c_m_status_wdat_fail_pos);
+ if (fail)
+ break;
+ msleep(50);
+ }
+ if (i == 200)
+ return -ETIMEDOUT;
+ if (fail) {
+ /* clear write fail bit */
+ af9005_write_register_bits(d,
+ xd_I2C_i2c_m_status_wdat_fail,
+ i2c_m_status_wdat_fail_pos,
+ i2c_m_status_wdat_fail_len,
+ 1);
+ return -EIO;
+ }
+ /* clear write done bit */
+ ret =
+ af9005_write_register_bits(d,
+ xd_I2C_i2c_m_status_wdat_fail,
+ i2c_m_status_wdat_done_pos,
+ i2c_m_status_wdat_done_len, 1);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
+ u8 * values, int len)
+{
+ /* don't let the name of this function mislead you: it's just used
+ as an interface from the firmware to the i2c bus. The actual
+ i2c addresses are contained in the data */
+ int ret, i;
+ u8 temp, buf[2];
+
+ buf[0] = addr; /* tuner i2c address */
+ buf[1] = values[0]; /* tuner register */
+
+ values[0] = addr + 0x01; /* i2c read address */
+
+ if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
+ /* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
+ ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
+ if (ret)
+ return ret;
+ }
+
+ /* send read command to ofsm */
+ ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
+ if (ret)
+ return ret;
+
+ /* check if read done */
+ for (i = 0; i < 200; i++) {
+ ret = af9005_read_ofdm_register(d, 0xa408, &temp);
+ if (ret)
+ return ret;
+ if (temp & 0x01)
+ break;
+ msleep(50);
+ }
+ if (i == 200)
+ return -ETIMEDOUT;
+
+ /* clear read done bit (by writing 1) */
+ ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
+ if (ret)
+ return ret;
+
+ /* get read data (available from 0xa400) */
+ for (i = 0; i < len; i++) {
+ ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
+ if (ret)
+ return ret;
+ values[i] = temp;
+ }
+ return 0;
+}
+
+static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+ u8 * data, int len)
+{
+ int ret, i;
+ u8 buf[3];
+ deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
+ reg, len);
+ debug_dump(data, len, deb_i2c);
+
+ for (i = 0; i < len; i++) {
+ buf[0] = i2caddr;
+ buf[1] = reg + (u8) i;
+ buf[2] = data[i];
+ ret =
+ af9005_write_tuner_registers(d,
+ APO_REG_I2C_RW_SILICON_TUNER,
+ buf, 3);
+ if (ret) {
+ deb_i2c("i2c_write failed\n");
+ return ret;
+ }
+ }
+ deb_i2c("i2c_write ok\n");
+ return 0;
+}
+
+static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+ u8 * data, int len)
+{
+ int ret, i;
+ u8 temp;
+ deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
+ for (i = 0; i < len; i++) {
+ temp = reg + i;
+ ret =
+ af9005_read_tuner_registers(d,
+ APO_REG_I2C_RW_SILICON_TUNER,
+ i2caddr, &temp, 1);
+ if (ret) {
+ deb_i2c("i2c_read failed\n");
+ return ret;
+ }
+ data[i] = temp;
+ }
+ deb_i2c("i2c data read: ");
+ debug_dump(data, len, deb_i2c);
+ return 0;
+}
+
+static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ /* only implements what the mt2060 module does, don't know how
+ to make it really generic */
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int ret;
+ u8 reg, addr;
+ u8 *value;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ if (num == 2) {
+ /* reads a single register */
+ reg = *msg[0].buf;
+ addr = msg[0].addr;
+ value = msg[1].buf;
+ ret = af9005_i2c_read(d, addr, reg, value, 1);
+ if (ret == 0)
+ ret = 2;
+ } else {
+ /* write one or more registers */
+ reg = msg[0].buf[0];
+ addr = msg[0].addr;
+ value = &msg[0].buf[1];
+ ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
+ if (ret == 0)
+ ret = 1;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return ret;
+}
+
+static u32 af9005_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9005_i2c_algo = {
+ .master_xfer = af9005_i2c_xfer,
+ .functionality = af9005_i2c_func,
+};
+
+int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
+ int wlen, u8 * rbuf, int rlen)
+{
+ struct af9005_device_state *st = d->priv;
+
+ int ret, i, packet_len;
+ u8 buf[64];
+ u8 ibuf[64];
+
+ if (wlen < 0) {
+ err("send command, wlen less than 0 bytes. Makes no sense.");
+ return -EINVAL;
+ }
+ if (wlen > 54) {
+ err("send command, wlen more than 54 bytes. Not supported.");
+ return -EINVAL;
+ }
+ if (rlen > 54) {
+ err("send command, rlen more than 54 bytes. Not supported.");
+ return -EINVAL;
+ }
+ packet_len = wlen + 5;
+ buf[0] = (u8) (packet_len & 0xff);
+ buf[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+ buf[2] = 0x26; /* packet type */
+ buf[3] = wlen + 3;
+ buf[4] = st->sequence++;
+ buf[5] = command;
+ buf[6] = wlen;
+ for (i = 0; i < wlen; i++)
+ buf[7 + i] = wbuf[i];
+ ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+ if (ret)
+ return ret;
+ if (ibuf[2] != 0x27) {
+ err("send command, wrong reply code.");
+ return -EIO;
+ }
+ if (ibuf[4] != buf[4]) {
+ err("send command, wrong sequence in reply.");
+ return -EIO;
+ }
+ if (ibuf[5] != 0x01) {
+ err("send command, wrong status code in reply.");
+ return -EIO;
+ }
+ if (ibuf[6] != rlen) {
+ err("send command, invalid data length in reply.");
+ return -EIO;
+ }
+ for (i = 0; i < rlen; i++)
+ rbuf[i] = ibuf[i + 7];
+ return 0;
+}
+
+int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
+ int len)
+{
+ struct af9005_device_state *st = d->priv;
+ u8 obuf[16], ibuf[14];
+ int ret, i;
+
+ memset(obuf, 0, sizeof(obuf));
+ memset(ibuf, 0, sizeof(ibuf));
+
+ obuf[0] = 14; /* length of rest of packet low */
+ obuf[1] = 0; /* length of rest of packer high */
+
+ obuf[2] = 0x2a; /* read/write eeprom */
+
+ obuf[3] = 12; /* size */
+
+ obuf[4] = st->sequence++;
+
+ obuf[5] = 0; /* read */
+
+ obuf[6] = len;
+ obuf[7] = address;
+ ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+ if (ret)
+ return ret;
+ if (ibuf[2] != 0x2b) {
+ err("Read eeprom, invalid reply code");
+ return -EIO;
+ }
+ if (ibuf[3] != 10) {
+ err("Read eeprom, invalid reply length");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("Read eeprom, wrong sequence in reply ");
+ return -EIO;
+ }
+ if (ibuf[5] != 1) {
+ err("Read eeprom, wrong status in reply ");
+ return -EIO;
+ }
+ for (i = 0; i < len; i++) {
+ values[i] = ibuf[6 + i];
+ }
+ return 0;
+}
+
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+{
+ u8 buf[FW_BULKOUT_SIZE + 2];
+ u16 checksum;
+ int act_len, i, ret;
+ memset(buf, 0, sizeof(buf));
+ buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+ buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+ switch (type) {
+ case FW_CONFIG:
+ buf[2] = 0x11;
+ buf[3] = 0x04;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x03;
+ checksum = buf[4] + buf[5];
+ buf[6] = (u8) ((checksum >> 8) & 0xff);
+ buf[7] = (u8) (checksum & 0xff);
+ break;
+ case FW_CONFIRM:
+ buf[2] = 0x11;
+ buf[3] = 0x04;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x01;
+ checksum = buf[4] + buf[5];
+ buf[6] = (u8) ((checksum >> 8) & 0xff);
+ buf[7] = (u8) (checksum & 0xff);
+ break;
+ case FW_BOOT:
+ buf[2] = 0x10;
+ buf[3] = 0x08;
+ buf[4] = 0x00; /* sequence number, original driver doesn't increment it here */
+ buf[5] = 0x97;
+ buf[6] = 0xaa;
+ buf[7] = 0x55;
+ buf[8] = 0xa5;
+ buf[9] = 0x5a;
+ checksum = 0;
+ for (i = 4; i <= 9; i++)
+ checksum += buf[i];
+ buf[10] = (u8) ((checksum >> 8) & 0xff);
+ buf[11] = (u8) (checksum & 0xff);
+ break;
+ default:
+ err("boot packet invalid boot packet type");
+ return -EINVAL;
+ }
+ deb_fw(">>> ");
+ debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x02),
+ buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
+ if (ret)
+ err("boot packet bulk message failed: %d (%d/%d)", ret,
+ FW_BULKOUT_SIZE + 2, act_len);
+ else
+ ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
+ if (ret)
+ return ret;
+ memset(buf, 0, 9);
+ ret = usb_bulk_msg(udev,
+ usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
+ if (ret) {
+ err("boot packet recv bulk message failed: %d", ret);
+ return ret;
+ }
+ deb_fw("<<< ");
+ debug_dump(buf, act_len, deb_fw);
+ checksum = 0;
+ switch (type) {
+ case FW_CONFIG:
+ if (buf[2] != 0x11) {
+ err("boot bad config header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad config size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad config sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x04) {
+ err("boot bad config subtype.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad config checksum.");
+ return -EIO;
+ }
+ *reply = buf[6];
+ break;
+ case FW_CONFIRM:
+ if (buf[2] != 0x11) {
+ err("boot bad confirm header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad confirm size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad confirm sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x02) {
+ err("boot bad confirm subtype.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad confirm checksum.");
+ return -EIO;
+ }
+ *reply = buf[6];
+ break;
+ case FW_BOOT:
+ if (buf[2] != 0x10) {
+ err("boot bad boot header.");
+ return -EIO;
+ }
+ if (buf[3] != 0x05) {
+ err("boot bad boot size.");
+ return -EIO;
+ }
+ if (buf[4] != 0x00) {
+ err("boot bad boot sequence.");
+ return -EIO;
+ }
+ if (buf[5] != 0x01) {
+ err("boot bad boot pattern 01.");
+ return -EIO;
+ }
+ if (buf[6] != 0x10) {
+ err("boot bad boot pattern 10.");
+ return -EIO;
+ }
+ for (i = 4; i <= 6; i++)
+ checksum += buf[i];
+ if (buf[7] * 256 + buf[8] != checksum) {
+ err("boot bad boot checksum.");
+ return -EIO;
+ }
+ break;
+
+ }
+
+ return 0;
+}
+
+int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+ int i, packets, ret, act_len;
+
+ u8 buf[FW_BULKOUT_SIZE + 2];
+ u8 reply;
+
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ if (reply != 0x01) {
+ err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
+ return -EIO;
+ }
+ packets = fw->size / FW_BULKOUT_SIZE;
+ buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+ buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+ for (i = 0; i < packets; i++) {
+ memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
+ FW_BULKOUT_SIZE);
+ deb_fw(">>> ");
+ debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x02),
+ buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
+ if (ret) {
+ err("firmware download failed at packet %d with code %d", i, ret);
+ return ret;
+ }
+ }
+ ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+ if (ret)
+ return ret;
+ if (reply != (u8) (packets & 0xff)) {
+ err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
+ return -EIO;
+ }
+ ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+ if (ret)
+ return ret;
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ if (reply != 0x02) {
+ err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
+ return -EIO;
+ }
+
+ return 0;
+
+}
+
+int af9005_led_control(struct dvb_usb_device *d, int onoff)
+{
+ struct af9005_device_state *st = d->priv;
+ int temp, ret;
+
+ if (onoff && dvb_usb_af9005_led)
+ temp = 1;
+ else
+ temp = 0;
+ if (st->led_state != temp) {
+ ret =
+ af9005_write_register_bits(d, xd_p_reg_top_locken1,
+ reg_top_locken1_pos,
+ reg_top_locken1_len, temp);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_register_bits(d, xd_p_reg_top_lock1,
+ reg_top_lock1_pos,
+ reg_top_lock1_len, temp);
+ if (ret)
+ return ret;
+ st->led_state = temp;
+ }
+ return 0;
+}
+
+static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ u8 buf[8];
+ int i;
+
+ /* without these calls the first commands after downloading
+ the firmware fail. I put these calls here to simulate
+ what it is done in dvb-usb-init.c.
+ */
+ struct usb_device *udev = adap->dev->udev;
+ usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
+ usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
+ if (dvb_usb_af9005_dump_eeprom) {
+ printk("EEPROM DUMP\n");
+ for (i = 0; i < 255; i += 8) {
+ af9005_read_eeprom(adap->dev, i, buf, 8);
+ printk("ADDR %x ", i);
+ debug_dump(buf, 8, printk);
+ }
+ }
+ adap->fe = af9005_fe_attach(adap->dev);
+ return 0;
+}
+
+static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
+{
+ struct af9005_device_state *st = d->priv;
+ int ret, len;
+
+ u8 obuf[5];
+ u8 ibuf[256];
+
+ *state = REMOTE_NO_KEY_PRESSED;
+ if (rc_decode == NULL) {
+ /* it shouldn't never come here */
+ return 0;
+ }
+ /* deb_info("rc_query\n"); */
+ obuf[0] = 3; /* rest of packet length low */
+ obuf[1] = 0; /* rest of packet lentgh high */
+ obuf[2] = 0x40; /* read remote */
+ obuf[3] = 1; /* rest of packet length */
+ obuf[4] = st->sequence++; /* sequence number */
+ ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+ if (ret) {
+ err("rc query failed");
+ return ret;
+ }
+ if (ibuf[2] != 0x41) {
+ err("rc query bad header.");
+ return -EIO;
+ }
+ if (ibuf[4] != obuf[4]) {
+ err("rc query bad sequence.");
+ return -EIO;
+ }
+ len = ibuf[5];
+ if (len > 246) {
+ err("rc query invalid length");
+ return -EIO;
+ }
+ if (len > 0) {
+ deb_rc("rc data (%d) ", len);
+ debug_dump((ibuf + 6), len, deb_rc);
+ ret = rc_decode(d, &ibuf[6], len, event, state);
+ if (ret) {
+ err("rc_decode failed");
+ return ret;
+ } else {
+ deb_rc("rc_decode state %x event %x\n", *state, *event);
+ if (*state == REMOTE_KEY_REPEAT)
+ *event = d->last_event;
+ }
+ }
+ return 0;
+}
+
+static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+
+ return 0;
+}
+
+static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+ int ret;
+ deb_info("pid filter control onoff %d\n", onoff);
+ if (onoff) {
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_register_bits(adap->dev,
+ XD_MP2IF_DMX_CTRL, 1, 1, 1);
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+ } else
+ ret =
+ af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
+ if (ret)
+ return ret;
+ deb_info("pid filter control ok\n");
+ return 0;
+}
+
+static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
+ u16 pid, int onoff)
+{
+ u8 cmd = index & 0x1f;
+ int ret;
+ deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
+ pid, onoff);
+ if (onoff) {
+ /* cannot use it as pid_filter_ctrl since it has to be done
+ before setting the first pid */
+ if (adap->feedcount == 1) {
+ deb_info("first pid set, enable pid table\n");
+ ret = af9005_pid_filter_control(adap, onoff);
+ if (ret)
+ return ret;
+ }
+ ret =
+ af9005_write_ofdm_register(adap->dev,
+ XD_MP2IF_PID_DATA_L,
+ (u8) (pid & 0xff));
+ if (ret)
+ return ret;
+ ret =
+ af9005_write_ofdm_register(adap->dev,
+ XD_MP2IF_PID_DATA_H,
+ (u8) (pid >> 8));
+ if (ret)
+ return ret;
+ cmd |= 0x20 | 0x40;
+ } else {
+ if (adap->feedcount == 0) {
+ deb_info("last pid unset, disable pid table\n");
+ ret = af9005_pid_filter_control(adap, onoff);
+ if (ret)
+ return ret;
+ }
+ }
+ ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
+ if (ret)
+ return ret;
+ deb_info("set pid ok\n");
+ return 0;
+}
+
+static int af9005_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ int ret;
+ u8 reply;
+ ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+ if (ret)
+ return ret;
+ deb_info("result of FW_CONFIG in identify state %d\n", reply);
+ if (reply == 0x01)
+ *cold = 1;
+ else if (reply == 0x02)
+ *cold = 0;
+ else
+ return -EIO;
+ deb_info("Identify state cold = %d\n", *cold);
+ return 0;
+}
+
+static struct dvb_usb_device_properties af9005_properties;
+
+static int af9005_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);
+}
+
+static struct usb_device_id af9005_usb_table[] = {
+ {USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+ {0},
+};
+
+MODULE_DEVICE_TABLE(usb, af9005_usb_table);
+
+static struct dvb_usb_device_properties af9005_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .firmware = "af9005.fw",
+ .download_firmware = af9005_download_firmware,
+ .no_reconnect = 1,
+
+ .size_of_priv = sizeof(struct af9005_device_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps =
+ DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = af9005_pid_filter,
+ /* .pid_filter_ctrl = af9005_pid_filter_control, */
+ .frontend_attach = af9005_frontend_attach,
+ /* .tuner_attach = af9005_tuner_attach, */
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x04,
+ .u = {
+ .bulk = {
+ .buffersize = 4096, /* actual size seen is 3948 */
+ }
+ }
+ },
+ }
+ },
+ .power_ctrl = af9005_power_ctrl,
+ .identify_state = af9005_identify_state,
+
+ .i2c_algo = &af9005_i2c_algo,
+
+ .rc_interval = 200,
+ .rc_key_map = NULL,
+ .rc_key_map_size = 0,
+ .rc_query = af9005_rc_query,
+
+ .num_device_descs = 2,
+ .devices = {
+ {.name = "Afatech DVB-T USB1.1 stick",
+ .cold_ids = {&af9005_usb_table[0], NULL},
+ .warm_ids = {NULL},
+ },
+ {.name = "TerraTec Cinergy T USB XE",
+ .cold_ids = {&af9005_usb_table[1], NULL},
+ .warm_ids = {NULL},
+ },
+ {NULL},
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9005_usb_driver = {
+ .name = "dvb_usb_af9005",
+ .probe = af9005_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = af9005_usb_table,
+};
+
+/* module stuff */
+static int __init af9005_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&af9005_usb_driver))) {
+ err("usb_register failed. (%d)", result);
+ return result;
+ }
+ rc_decode = symbol_request(af9005_rc_decode);
+ rc_keys = symbol_request(af9005_rc_keys);
+ rc_keys_size = symbol_request(af9005_rc_keys_size);
+ if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
+ err("af9005_rc_decode function not found, disabling remote");
+ af9005_properties.rc_query = NULL;
+ } else {
+ af9005_properties.rc_key_map = rc_keys;
+ af9005_properties.rc_key_map_size = *rc_keys_size;
+ }
+
+ return 0;
+}
+
+static void __exit af9005_usb_module_exit(void)
+{
+ /* release rc decode symbols */
+ if (rc_decode != NULL)
+ symbol_put(af9005_rc_decode);
+ if (rc_keys != NULL)
+ symbol_put(af9005_rc_keys);
+ if (rc_keys_size != NULL)
+ symbol_put(af9005_rc_keys_size);
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&af9005_usb_driver);
+}
+
+module_init(af9005_usb_module_init);
+module_exit(af9005_usb_module_exit);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
new file mode 100644
index 000000000000..0bc48a012187
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -0,0 +1,3496 @@
+/* Common header-file of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_AF9005_H_
+#define _DVB_USB_AF9005_H_
+
+#define DVB_USB_LOG_PREFIX "af9005"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9005_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
+#define deb_rc(args...) dprintk(dvb_usb_af9005_debug,0x04,args)
+#define deb_reg(args...) dprintk(dvb_usb_af9005_debug,0x08,args)
+#define deb_i2c(args...) dprintk(dvb_usb_af9005_debug,0x10,args)
+#define deb_fw(args...) dprintk(dvb_usb_af9005_debug,0x20,args)
+
+extern int dvb_usb_af9005_led;
+
+/* firmware */
+#define FW_BULKOUT_SIZE 250
+enum {
+ FW_CONFIG,
+ FW_CONFIRM,
+ FW_BOOT
+};
+
+/* af9005 commands */
+#define AF9005_OFDM_REG 0
+#define AF9005_TUNER_REG 1
+
+#define AF9005_REGISTER_RW 0x20
+#define AF9005_REGISTER_RW_ACK 0x21
+
+#define AF9005_CMD_OFDM_REG 0x00
+#define AF9005_CMD_TUNER 0x80
+#define AF9005_CMD_BURST 0x02
+#define AF9005_CMD_AUTOINC 0x04
+#define AF9005_CMD_READ 0x00
+#define AF9005_CMD_WRITE 0x01
+
+/* af9005 registers */
+#define APO_REG_RESET 0xAEFF
+
+#define APO_REG_I2C_RW_CAN_TUNER 0xF000
+#define APO_REG_I2C_RW_SILICON_TUNER 0xF001
+#define APO_REG_GPIO_RW_SILICON_TUNER 0xFFFE /* also for OFSM */
+#define APO_REG_TRIGGER_OFSM 0xFFFF /* also for OFSM */
+
+/***********************************************************************
+ * Apollo Registers from VLSI *
+ ***********************************************************************/
+#define xd_p_reg_aagc_inverted_agc 0xA000
+#define reg_aagc_inverted_agc_pos 0
+#define reg_aagc_inverted_agc_len 1
+#define reg_aagc_inverted_agc_lsb 0
+#define xd_p_reg_aagc_sign_only 0xA000
+#define reg_aagc_sign_only_pos 1
+#define reg_aagc_sign_only_len 1
+#define reg_aagc_sign_only_lsb 0
+#define xd_p_reg_aagc_slow_adc_en 0xA000
+#define reg_aagc_slow_adc_en_pos 2
+#define reg_aagc_slow_adc_en_len 1
+#define reg_aagc_slow_adc_en_lsb 0
+#define xd_p_reg_aagc_slow_adc_scale 0xA000
+#define reg_aagc_slow_adc_scale_pos 3
+#define reg_aagc_slow_adc_scale_len 5
+#define reg_aagc_slow_adc_scale_lsb 0
+#define xd_p_reg_aagc_check_slow_adc_lock 0xA001
+#define reg_aagc_check_slow_adc_lock_pos 0
+#define reg_aagc_check_slow_adc_lock_len 1
+#define reg_aagc_check_slow_adc_lock_lsb 0
+#define xd_p_reg_aagc_init_control 0xA001
+#define reg_aagc_init_control_pos 1
+#define reg_aagc_init_control_len 1
+#define reg_aagc_init_control_lsb 0
+#define xd_p_reg_aagc_total_gain_sel 0xA001
+#define reg_aagc_total_gain_sel_pos 2
+#define reg_aagc_total_gain_sel_len 2
+#define reg_aagc_total_gain_sel_lsb 0
+#define xd_p_reg_aagc_out_inv 0xA001
+#define reg_aagc_out_inv_pos 5
+#define reg_aagc_out_inv_len 1
+#define reg_aagc_out_inv_lsb 0
+#define xd_p_reg_aagc_int_en 0xA001
+#define reg_aagc_int_en_pos 6
+#define reg_aagc_int_en_len 1
+#define reg_aagc_int_en_lsb 0
+#define xd_p_reg_aagc_lock_change_flag 0xA001
+#define reg_aagc_lock_change_flag_pos 7
+#define reg_aagc_lock_change_flag_len 1
+#define reg_aagc_lock_change_flag_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_acquire 0xA002
+#define reg_aagc_rf_loop_bw_scale_acquire_pos 0
+#define reg_aagc_rf_loop_bw_scale_acquire_len 5
+#define reg_aagc_rf_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_track 0xA003
+#define reg_aagc_rf_loop_bw_scale_track_pos 0
+#define reg_aagc_rf_loop_bw_scale_track_len 5
+#define reg_aagc_rf_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_acquire 0xA004
+#define reg_aagc_if_loop_bw_scale_acquire_pos 0
+#define reg_aagc_if_loop_bw_scale_acquire_len 5
+#define reg_aagc_if_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_track 0xA005
+#define reg_aagc_if_loop_bw_scale_track_pos 0
+#define reg_aagc_if_loop_bw_scale_track_len 5
+#define reg_aagc_if_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_7_0 0xA006
+#define reg_aagc_max_rf_agc_7_0_pos 0
+#define reg_aagc_max_rf_agc_7_0_len 8
+#define reg_aagc_max_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_9_8 0xA007
+#define reg_aagc_max_rf_agc_9_8_pos 0
+#define reg_aagc_max_rf_agc_9_8_len 2
+#define reg_aagc_max_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_rf_agc_7_0 0xA008
+#define reg_aagc_min_rf_agc_7_0_pos 0
+#define reg_aagc_min_rf_agc_7_0_len 8
+#define reg_aagc_min_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_rf_agc_9_8 0xA009
+#define reg_aagc_min_rf_agc_9_8_pos 0
+#define reg_aagc_min_rf_agc_9_8_len 2
+#define reg_aagc_min_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_max_if_agc_7_0 0xA00A
+#define reg_aagc_max_if_agc_7_0_pos 0
+#define reg_aagc_max_if_agc_7_0_len 8
+#define reg_aagc_max_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_if_agc_9_8 0xA00B
+#define reg_aagc_max_if_agc_9_8_pos 0
+#define reg_aagc_max_if_agc_9_8_len 2
+#define reg_aagc_max_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_if_agc_7_0 0xA00C
+#define reg_aagc_min_if_agc_7_0_pos 0
+#define reg_aagc_min_if_agc_7_0_len 8
+#define reg_aagc_min_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_if_agc_9_8 0xA00D
+#define reg_aagc_min_if_agc_9_8_pos 0
+#define reg_aagc_min_if_agc_9_8_len 2
+#define reg_aagc_min_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_lock_sample_scale 0xA00E
+#define reg_aagc_lock_sample_scale_pos 0
+#define reg_aagc_lock_sample_scale_len 5
+#define reg_aagc_lock_sample_scale_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_acquire 0xA00F
+#define reg_aagc_rf_agc_lock_scale_acquire_pos 0
+#define reg_aagc_rf_agc_lock_scale_acquire_len 3
+#define reg_aagc_rf_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_track 0xA00F
+#define reg_aagc_rf_agc_lock_scale_track_pos 3
+#define reg_aagc_rf_agc_lock_scale_track_len 3
+#define reg_aagc_rf_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_acquire 0xA010
+#define reg_aagc_if_agc_lock_scale_acquire_pos 0
+#define reg_aagc_if_agc_lock_scale_acquire_len 3
+#define reg_aagc_if_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_track 0xA010
+#define reg_aagc_if_agc_lock_scale_track_pos 3
+#define reg_aagc_if_agc_lock_scale_track_len 3
+#define reg_aagc_if_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_7_0 0xA011
+#define reg_aagc_rf_top_numerator_7_0_pos 0
+#define reg_aagc_rf_top_numerator_7_0_len 8
+#define reg_aagc_rf_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_9_8 0xA012
+#define reg_aagc_rf_top_numerator_9_8_pos 0
+#define reg_aagc_rf_top_numerator_9_8_len 2
+#define reg_aagc_rf_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_if_top_numerator_7_0 0xA013
+#define reg_aagc_if_top_numerator_7_0_pos 0
+#define reg_aagc_if_top_numerator_7_0_len 8
+#define reg_aagc_if_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_if_top_numerator_9_8 0xA014
+#define reg_aagc_if_top_numerator_9_8_pos 0
+#define reg_aagc_if_top_numerator_9_8_len 2
+#define reg_aagc_if_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_adc_out_desired_7_0 0xA015
+#define reg_aagc_adc_out_desired_7_0_pos 0
+#define reg_aagc_adc_out_desired_7_0_len 8
+#define reg_aagc_adc_out_desired_7_0_lsb 0
+#define xd_p_reg_aagc_adc_out_desired_8 0xA016
+#define reg_aagc_adc_out_desired_8_pos 0
+#define reg_aagc_adc_out_desired_8_len 1
+#define reg_aagc_adc_out_desired_8_lsb 0
+#define xd_p_reg_aagc_fixed_gain 0xA016
+#define reg_aagc_fixed_gain_pos 3
+#define reg_aagc_fixed_gain_len 1
+#define reg_aagc_fixed_gain_lsb 0
+#define xd_p_reg_aagc_lock_count_th 0xA016
+#define reg_aagc_lock_count_th_pos 4
+#define reg_aagc_lock_count_th_len 4
+#define reg_aagc_lock_count_th_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_7_0 0xA017
+#define reg_aagc_fixed_rf_agc_control_7_0_pos 0
+#define reg_aagc_fixed_rf_agc_control_7_0_len 8
+#define reg_aagc_fixed_rf_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_15_8 0xA018
+#define reg_aagc_fixed_rf_agc_control_15_8_pos 0
+#define reg_aagc_fixed_rf_agc_control_15_8_len 8
+#define reg_aagc_fixed_rf_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_rf_agc_control_23_16 0xA019
+#define reg_aagc_fixed_rf_agc_control_23_16_pos 0
+#define reg_aagc_fixed_rf_agc_control_23_16_len 8
+#define reg_aagc_fixed_rf_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_rf_agc_control_30_24 0xA01A
+#define reg_aagc_fixed_rf_agc_control_30_24_pos 0
+#define reg_aagc_fixed_rf_agc_control_30_24_len 7
+#define reg_aagc_fixed_rf_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_fixed_if_agc_control_7_0 0xA01B
+#define reg_aagc_fixed_if_agc_control_7_0_pos 0
+#define reg_aagc_fixed_if_agc_control_7_0_len 8
+#define reg_aagc_fixed_if_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_if_agc_control_15_8 0xA01C
+#define reg_aagc_fixed_if_agc_control_15_8_pos 0
+#define reg_aagc_fixed_if_agc_control_15_8_len 8
+#define reg_aagc_fixed_if_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_if_agc_control_23_16 0xA01D
+#define reg_aagc_fixed_if_agc_control_23_16_pos 0
+#define reg_aagc_fixed_if_agc_control_23_16_len 8
+#define reg_aagc_fixed_if_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_if_agc_control_30_24 0xA01E
+#define reg_aagc_fixed_if_agc_control_30_24_pos 0
+#define reg_aagc_fixed_if_agc_control_30_24_len 7
+#define reg_aagc_fixed_if_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_rf_agc_unlock_numerator 0xA01F
+#define reg_aagc_rf_agc_unlock_numerator_pos 0
+#define reg_aagc_rf_agc_unlock_numerator_len 6
+#define reg_aagc_rf_agc_unlock_numerator_lsb 0
+#define xd_p_reg_aagc_if_agc_unlock_numerator 0xA020
+#define reg_aagc_if_agc_unlock_numerator_pos 0
+#define reg_aagc_if_agc_unlock_numerator_len 6
+#define reg_aagc_if_agc_unlock_numerator_lsb 0
+#define xd_p_reg_unplug_th 0xA021
+#define reg_unplug_th_pos 0
+#define reg_unplug_th_len 8
+#define reg_aagc_rf_x0_lsb 0
+#define xd_p_reg_weak_signal_rfagc_thr 0xA022
+#define reg_weak_signal_rfagc_thr_pos 0
+#define reg_weak_signal_rfagc_thr_len 8
+#define reg_weak_signal_rfagc_thr_lsb 0
+#define xd_p_reg_unplug_rf_gain_th 0xA023
+#define reg_unplug_rf_gain_th_pos 0
+#define reg_unplug_rf_gain_th_len 8
+#define reg_unplug_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
+#define reg_unplug_dtop_rf_gain_th_pos 0
+#define reg_unplug_dtop_rf_gain_th_len 8
+#define reg_unplug_dtop_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
+#define reg_unplug_dtop_if_gain_th_pos 0
+#define reg_unplug_dtop_if_gain_th_len 8
+#define reg_unplug_dtop_if_gain_th_lsb 0
+#define xd_p_reg_top_recover_at_unplug_en 0xA026
+#define reg_top_recover_at_unplug_en_pos 0
+#define reg_top_recover_at_unplug_en_len 1
+#define reg_top_recover_at_unplug_en_lsb 0
+#define xd_p_reg_aagc_rf_x6 0xA027
+#define reg_aagc_rf_x6_pos 0
+#define reg_aagc_rf_x6_len 8
+#define reg_aagc_rf_x6_lsb 0
+#define xd_p_reg_aagc_rf_x7 0xA028
+#define reg_aagc_rf_x7_pos 0
+#define reg_aagc_rf_x7_len 8
+#define reg_aagc_rf_x7_lsb 0
+#define xd_p_reg_aagc_rf_x8 0xA029
+#define reg_aagc_rf_x8_pos 0
+#define reg_aagc_rf_x8_len 8
+#define reg_aagc_rf_x8_lsb 0
+#define xd_p_reg_aagc_rf_x9 0xA02A
+#define reg_aagc_rf_x9_pos 0
+#define reg_aagc_rf_x9_len 8
+#define reg_aagc_rf_x9_lsb 0
+#define xd_p_reg_aagc_rf_x10 0xA02B
+#define reg_aagc_rf_x10_pos 0
+#define reg_aagc_rf_x10_len 8
+#define reg_aagc_rf_x10_lsb 0
+#define xd_p_reg_aagc_rf_x11 0xA02C
+#define reg_aagc_rf_x11_pos 0
+#define reg_aagc_rf_x11_len 8
+#define reg_aagc_rf_x11_lsb 0
+#define xd_p_reg_aagc_rf_x12 0xA02D
+#define reg_aagc_rf_x12_pos 0
+#define reg_aagc_rf_x12_len 8
+#define reg_aagc_rf_x12_lsb 0
+#define xd_p_reg_aagc_rf_x13 0xA02E
+#define reg_aagc_rf_x13_pos 0
+#define reg_aagc_rf_x13_len 8
+#define reg_aagc_rf_x13_lsb 0
+#define xd_p_reg_aagc_if_x0 0xA02F
+#define reg_aagc_if_x0_pos 0
+#define reg_aagc_if_x0_len 8
+#define reg_aagc_if_x0_lsb 0
+#define xd_p_reg_aagc_if_x1 0xA030
+#define reg_aagc_if_x1_pos 0
+#define reg_aagc_if_x1_len 8
+#define reg_aagc_if_x1_lsb 0
+#define xd_p_reg_aagc_if_x2 0xA031
+#define reg_aagc_if_x2_pos 0
+#define reg_aagc_if_x2_len 8
+#define reg_aagc_if_x2_lsb 0
+#define xd_p_reg_aagc_if_x3 0xA032
+#define reg_aagc_if_x3_pos 0
+#define reg_aagc_if_x3_len 8
+#define reg_aagc_if_x3_lsb 0
+#define xd_p_reg_aagc_if_x4 0xA033
+#define reg_aagc_if_x4_pos 0
+#define reg_aagc_if_x4_len 8
+#define reg_aagc_if_x4_lsb 0
+#define xd_p_reg_aagc_if_x5 0xA034
+#define reg_aagc_if_x5_pos 0
+#define reg_aagc_if_x5_len 8
+#define reg_aagc_if_x5_lsb 0
+#define xd_p_reg_aagc_if_x6 0xA035
+#define reg_aagc_if_x6_pos 0
+#define reg_aagc_if_x6_len 8
+#define reg_aagc_if_x6_lsb 0
+#define xd_p_reg_aagc_if_x7 0xA036
+#define reg_aagc_if_x7_pos 0
+#define reg_aagc_if_x7_len 8
+#define reg_aagc_if_x7_lsb 0
+#define xd_p_reg_aagc_if_x8 0xA037
+#define reg_aagc_if_x8_pos 0
+#define reg_aagc_if_x8_len 8
+#define reg_aagc_if_x8_lsb 0
+#define xd_p_reg_aagc_if_x9 0xA038
+#define reg_aagc_if_x9_pos 0
+#define reg_aagc_if_x9_len 8
+#define reg_aagc_if_x9_lsb 0
+#define xd_p_reg_aagc_if_x10 0xA039
+#define reg_aagc_if_x10_pos 0
+#define reg_aagc_if_x10_len 8
+#define reg_aagc_if_x10_lsb 0
+#define xd_p_reg_aagc_if_x11 0xA03A
+#define reg_aagc_if_x11_pos 0
+#define reg_aagc_if_x11_len 8
+#define reg_aagc_if_x11_lsb 0
+#define xd_p_reg_aagc_if_x12 0xA03B
+#define reg_aagc_if_x12_pos 0
+#define reg_aagc_if_x12_len 8
+#define reg_aagc_if_x12_lsb 0
+#define xd_p_reg_aagc_if_x13 0xA03C
+#define reg_aagc_if_x13_pos 0
+#define reg_aagc_if_x13_len 8
+#define reg_aagc_if_x13_lsb 0
+#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca 0xA03D
+#define reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
+#define reg_aagc_min_rf_ctl_8bit_for_dca_len 8
+#define reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
+#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca 0xA03E
+#define reg_aagc_min_if_ctl_8bit_for_dca_pos 0
+#define reg_aagc_min_if_ctl_8bit_for_dca_len 8
+#define reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
+#define xd_r_reg_aagc_total_gain_7_0 0xA070
+#define reg_aagc_total_gain_7_0_pos 0
+#define reg_aagc_total_gain_7_0_len 8
+#define reg_aagc_total_gain_7_0_lsb 0
+#define xd_r_reg_aagc_total_gain_15_8 0xA071
+#define reg_aagc_total_gain_15_8_pos 0
+#define reg_aagc_total_gain_15_8_len 8
+#define reg_aagc_total_gain_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_7_0 0xA074
+#define reg_aagc_in_sat_cnt_7_0_pos 0
+#define reg_aagc_in_sat_cnt_7_0_len 8
+#define reg_aagc_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_aagc_in_sat_cnt_15_8 0xA075
+#define reg_aagc_in_sat_cnt_15_8_pos 0
+#define reg_aagc_in_sat_cnt_15_8_len 8
+#define reg_aagc_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_23_16 0xA076
+#define reg_aagc_in_sat_cnt_23_16_pos 0
+#define reg_aagc_in_sat_cnt_23_16_len 8
+#define reg_aagc_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_aagc_in_sat_cnt_31_24 0xA077
+#define reg_aagc_in_sat_cnt_31_24_pos 0
+#define reg_aagc_in_sat_cnt_31_24_len 8
+#define reg_aagc_in_sat_cnt_31_24_lsb 24
+#define xd_r_reg_aagc_digital_rf_volt_7_0 0xA078
+#define reg_aagc_digital_rf_volt_7_0_pos 0
+#define reg_aagc_digital_rf_volt_7_0_len 8
+#define reg_aagc_digital_rf_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_rf_volt_9_8 0xA079
+#define reg_aagc_digital_rf_volt_9_8_pos 0
+#define reg_aagc_digital_rf_volt_9_8_len 2
+#define reg_aagc_digital_rf_volt_9_8_lsb 8
+#define xd_r_reg_aagc_digital_if_volt_7_0 0xA07A
+#define reg_aagc_digital_if_volt_7_0_pos 0
+#define reg_aagc_digital_if_volt_7_0_len 8
+#define reg_aagc_digital_if_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_if_volt_9_8 0xA07B
+#define reg_aagc_digital_if_volt_9_8_pos 0
+#define reg_aagc_digital_if_volt_9_8_len 2
+#define reg_aagc_digital_if_volt_9_8_lsb 8
+#define xd_r_reg_aagc_rf_gain 0xA07C
+#define reg_aagc_rf_gain_pos 0
+#define reg_aagc_rf_gain_len 8
+#define reg_aagc_rf_gain_lsb 0
+#define xd_r_reg_aagc_if_gain 0xA07D
+#define reg_aagc_if_gain_pos 0
+#define reg_aagc_if_gain_len 8
+#define reg_aagc_if_gain_lsb 0
+#define xd_p_tinr_imp_indicator 0xA080
+#define tinr_imp_indicator_pos 0
+#define tinr_imp_indicator_len 2
+#define tinr_imp_indicator_lsb 0
+#define xd_p_reg_tinr_fifo_size 0xA080
+#define reg_tinr_fifo_size_pos 2
+#define reg_tinr_fifo_size_len 5
+#define reg_tinr_fifo_size_lsb 0
+#define xd_p_reg_tinr_saturation_cnt_th 0xA081
+#define reg_tinr_saturation_cnt_th_pos 0
+#define reg_tinr_saturation_cnt_th_len 4
+#define reg_tinr_saturation_cnt_th_lsb 0
+#define xd_p_reg_tinr_saturation_th_3_0 0xA081
+#define reg_tinr_saturation_th_3_0_pos 4
+#define reg_tinr_saturation_th_3_0_len 4
+#define reg_tinr_saturation_th_3_0_lsb 0
+#define xd_p_reg_tinr_saturation_th_8_4 0xA082
+#define reg_tinr_saturation_th_8_4_pos 0
+#define reg_tinr_saturation_th_8_4_len 5
+#define reg_tinr_saturation_th_8_4_lsb 4
+#define xd_p_reg_tinr_imp_duration_th_2k_7_0 0xA083
+#define reg_tinr_imp_duration_th_2k_7_0_pos 0
+#define reg_tinr_imp_duration_th_2k_7_0_len 8
+#define reg_tinr_imp_duration_th_2k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_2k_8 0xA084
+#define reg_tinr_imp_duration_th_2k_8_pos 0
+#define reg_tinr_imp_duration_th_2k_8_len 1
+#define reg_tinr_imp_duration_th_2k_8_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_7_0 0xA085
+#define reg_tinr_imp_duration_th_8k_7_0_pos 0
+#define reg_tinr_imp_duration_th_8k_7_0_len 8
+#define reg_tinr_imp_duration_th_8k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_10_8 0xA086
+#define reg_tinr_imp_duration_th_8k_10_8_pos 0
+#define reg_tinr_imp_duration_th_8k_10_8_len 3
+#define reg_tinr_imp_duration_th_8k_10_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_6m_7_0 0xA087
+#define reg_tinr_freq_ratio_6m_7_0_pos 0
+#define reg_tinr_freq_ratio_6m_7_0_len 8
+#define reg_tinr_freq_ratio_6m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_6m_12_8 0xA088
+#define reg_tinr_freq_ratio_6m_12_8_pos 0
+#define reg_tinr_freq_ratio_6m_12_8_len 5
+#define reg_tinr_freq_ratio_6m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_7m_7_0 0xA089
+#define reg_tinr_freq_ratio_7m_7_0_pos 0
+#define reg_tinr_freq_ratio_7m_7_0_len 8
+#define reg_tinr_freq_ratio_7m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_7m_12_8 0xA08A
+#define reg_tinr_freq_ratio_7m_12_8_pos 0
+#define reg_tinr_freq_ratio_7m_12_8_len 5
+#define reg_tinr_freq_ratio_7m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_8m_7_0 0xA08B
+#define reg_tinr_freq_ratio_8m_7_0_pos 0
+#define reg_tinr_freq_ratio_8m_7_0_len 8
+#define reg_tinr_freq_ratio_8m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_8m_12_8 0xA08C
+#define reg_tinr_freq_ratio_8m_12_8_pos 0
+#define reg_tinr_freq_ratio_8m_12_8_len 5
+#define reg_tinr_freq_ratio_8m_12_8_lsb 8
+#define xd_p_reg_tinr_imp_duration_th_low_2k 0xA08D
+#define reg_tinr_imp_duration_th_low_2k_pos 0
+#define reg_tinr_imp_duration_th_low_2k_len 8
+#define reg_tinr_imp_duration_th_low_2k_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_low_8k 0xA08E
+#define reg_tinr_imp_duration_th_low_8k_pos 0
+#define reg_tinr_imp_duration_th_low_8k_len 8
+#define reg_tinr_imp_duration_th_low_8k_lsb 0
+#define xd_r_reg_tinr_counter_7_0 0xA090
+#define reg_tinr_counter_7_0_pos 0
+#define reg_tinr_counter_7_0_len 8
+#define reg_tinr_counter_7_0_lsb 0
+#define xd_r_reg_tinr_counter_15_8 0xA091
+#define reg_tinr_counter_15_8_pos 0
+#define reg_tinr_counter_15_8_len 8
+#define reg_tinr_counter_15_8_lsb 8
+#define xd_p_reg_tinr_adative_tinr_en 0xA093
+#define reg_tinr_adative_tinr_en_pos 0
+#define reg_tinr_adative_tinr_en_len 1
+#define reg_tinr_adative_tinr_en_lsb 0
+#define xd_p_reg_tinr_peak_fifo_size 0xA093
+#define reg_tinr_peak_fifo_size_pos 1
+#define reg_tinr_peak_fifo_size_len 5
+#define reg_tinr_peak_fifo_size_lsb 0
+#define xd_p_reg_tinr_counter_rst 0xA093
+#define reg_tinr_counter_rst_pos 6
+#define reg_tinr_counter_rst_len 1
+#define reg_tinr_counter_rst_lsb 0
+#define xd_p_reg_tinr_search_period_7_0 0xA094
+#define reg_tinr_search_period_7_0_pos 0
+#define reg_tinr_search_period_7_0_len 8
+#define reg_tinr_search_period_7_0_lsb 0
+#define xd_p_reg_tinr_search_period_15_8 0xA095
+#define reg_tinr_search_period_15_8_pos 0
+#define reg_tinr_search_period_15_8_len 8
+#define reg_tinr_search_period_15_8_lsb 8
+#define xd_p_reg_ccifs_fcw_7_0 0xA0A0
+#define reg_ccifs_fcw_7_0_pos 0
+#define reg_ccifs_fcw_7_0_len 8
+#define reg_ccifs_fcw_7_0_lsb 0
+#define xd_p_reg_ccifs_fcw_12_8 0xA0A1
+#define reg_ccifs_fcw_12_8_pos 0
+#define reg_ccifs_fcw_12_8_len 5
+#define reg_ccifs_fcw_12_8_lsb 8
+#define xd_p_reg_ccifs_spec_inv 0xA0A1
+#define reg_ccifs_spec_inv_pos 5
+#define reg_ccifs_spec_inv_len 1
+#define reg_ccifs_spec_inv_lsb 0
+#define xd_p_reg_gp_trigger 0xA0A2
+#define reg_gp_trigger_pos 0
+#define reg_gp_trigger_len 1
+#define reg_gp_trigger_lsb 0
+#define xd_p_reg_trigger_sel 0xA0A2
+#define reg_trigger_sel_pos 1
+#define reg_trigger_sel_len 2
+#define reg_trigger_sel_lsb 0
+#define xd_p_reg_debug_ofdm 0xA0A2
+#define reg_debug_ofdm_pos 3
+#define reg_debug_ofdm_len 2
+#define reg_debug_ofdm_lsb 0
+#define xd_p_reg_trigger_module_sel 0xA0A3
+#define reg_trigger_module_sel_pos 0
+#define reg_trigger_module_sel_len 6
+#define reg_trigger_module_sel_lsb 0
+#define xd_p_reg_trigger_set_sel 0xA0A4
+#define reg_trigger_set_sel_pos 0
+#define reg_trigger_set_sel_len 6
+#define reg_trigger_set_sel_lsb 0
+#define xd_p_reg_fw_int_mask_n 0xA0A4
+#define reg_fw_int_mask_n_pos 6
+#define reg_fw_int_mask_n_len 1
+#define reg_fw_int_mask_n_lsb 0
+#define xd_p_reg_debug_group 0xA0A5
+#define reg_debug_group_pos 0
+#define reg_debug_group_len 4
+#define reg_debug_group_lsb 0
+#define xd_p_reg_odbg_clk_sel 0xA0A5
+#define reg_odbg_clk_sel_pos 4
+#define reg_odbg_clk_sel_len 2
+#define reg_odbg_clk_sel_lsb 0
+#define xd_p_reg_ccif_sc 0xA0C0
+#define reg_ccif_sc_pos 0
+#define reg_ccif_sc_len 4
+#define reg_ccif_sc_lsb 0
+#define xd_r_reg_ccif_saturate 0xA0C1
+#define reg_ccif_saturate_pos 0
+#define reg_ccif_saturate_len 2
+#define reg_ccif_saturate_lsb 0
+#define xd_r_reg_antif_saturate 0xA0C1
+#define reg_antif_saturate_pos 2
+#define reg_antif_saturate_len 4
+#define reg_antif_saturate_lsb 0
+#define xd_r_reg_acif_saturate 0xA0C2
+#define reg_acif_saturate_pos 0
+#define reg_acif_saturate_len 8
+#define reg_acif_saturate_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_7_0 0xA0C8
+#define reg_tmr_timer0_threshold_7_0_pos 0
+#define reg_tmr_timer0_threshold_7_0_len 8
+#define reg_tmr_timer0_threshold_7_0_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_15_8 0xA0C9
+#define reg_tmr_timer0_threshold_15_8_pos 0
+#define reg_tmr_timer0_threshold_15_8_len 8
+#define reg_tmr_timer0_threshold_15_8_lsb 8
+#define xd_p_reg_tmr_timer0_enable 0xA0CA
+#define reg_tmr_timer0_enable_pos 0
+#define reg_tmr_timer0_enable_len 1
+#define reg_tmr_timer0_enable_lsb 0
+#define xd_p_reg_tmr_timer0_clk_sel 0xA0CA
+#define reg_tmr_timer0_clk_sel_pos 1
+#define reg_tmr_timer0_clk_sel_len 1
+#define reg_tmr_timer0_clk_sel_lsb 0
+#define xd_p_reg_tmr_timer0_int 0xA0CA
+#define reg_tmr_timer0_int_pos 2
+#define reg_tmr_timer0_int_len 1
+#define reg_tmr_timer0_int_lsb 0
+#define xd_p_reg_tmr_timer0_rst 0xA0CA
+#define reg_tmr_timer0_rst_pos 3
+#define reg_tmr_timer0_rst_len 1
+#define reg_tmr_timer0_rst_lsb 0
+#define xd_r_reg_tmr_timer0_count_7_0 0xA0CB
+#define reg_tmr_timer0_count_7_0_pos 0
+#define reg_tmr_timer0_count_7_0_len 8
+#define reg_tmr_timer0_count_7_0_lsb 0
+#define xd_r_reg_tmr_timer0_count_15_8 0xA0CC
+#define reg_tmr_timer0_count_15_8_pos 0
+#define reg_tmr_timer0_count_15_8_len 8
+#define reg_tmr_timer0_count_15_8_lsb 8
+#define xd_p_reg_suspend 0xA0CD
+#define reg_suspend_pos 0
+#define reg_suspend_len 1
+#define reg_suspend_lsb 0
+#define xd_p_reg_suspend_rdy 0xA0CD
+#define reg_suspend_rdy_pos 1
+#define reg_suspend_rdy_len 1
+#define reg_suspend_rdy_lsb 0
+#define xd_p_reg_resume 0xA0CD
+#define reg_resume_pos 2
+#define reg_resume_len 1
+#define reg_resume_lsb 0
+#define xd_p_reg_resume_rdy 0xA0CD
+#define reg_resume_rdy_pos 3
+#define reg_resume_rdy_len 1
+#define reg_resume_rdy_lsb 0
+#define xd_p_reg_fmf 0xA0CE
+#define reg_fmf_pos 0
+#define reg_fmf_len 8
+#define reg_fmf_lsb 0
+#define xd_p_ccid_accumulate_num_2k_7_0 0xA100
+#define ccid_accumulate_num_2k_7_0_pos 0
+#define ccid_accumulate_num_2k_7_0_len 8
+#define ccid_accumulate_num_2k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_2k_12_8 0xA101
+#define ccid_accumulate_num_2k_12_8_pos 0
+#define ccid_accumulate_num_2k_12_8_len 5
+#define ccid_accumulate_num_2k_12_8_lsb 8
+#define xd_p_ccid_accumulate_num_8k_7_0 0xA102
+#define ccid_accumulate_num_8k_7_0_pos 0
+#define ccid_accumulate_num_8k_7_0_len 8
+#define ccid_accumulate_num_8k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_8k_14_8 0xA103
+#define ccid_accumulate_num_8k_14_8_pos 0
+#define ccid_accumulate_num_8k_14_8_len 7
+#define ccid_accumulate_num_8k_14_8_lsb 8
+#define xd_p_ccid_desired_level_0 0xA103
+#define ccid_desired_level_0_pos 7
+#define ccid_desired_level_0_len 1
+#define ccid_desired_level_0_lsb 0
+#define xd_p_ccid_desired_level_8_1 0xA104
+#define ccid_desired_level_8_1_pos 0
+#define ccid_desired_level_8_1_len 8
+#define ccid_desired_level_8_1_lsb 1
+#define xd_p_ccid_apply_delay 0xA105
+#define ccid_apply_delay_pos 0
+#define ccid_apply_delay_len 7
+#define ccid_apply_delay_lsb 0
+#define xd_p_ccid_CCID_Threshold1 0xA106
+#define ccid_CCID_Threshold1_pos 0
+#define ccid_CCID_Threshold1_len 8
+#define ccid_CCID_Threshold1_lsb 0
+#define xd_p_ccid_CCID_Threshold2 0xA107
+#define ccid_CCID_Threshold2_pos 0
+#define ccid_CCID_Threshold2_len 8
+#define ccid_CCID_Threshold2_lsb 0
+#define xd_p_reg_ccid_gain_scale 0xA108
+#define reg_ccid_gain_scale_pos 0
+#define reg_ccid_gain_scale_len 4
+#define reg_ccid_gain_scale_lsb 0
+#define xd_p_reg_ccid2_passband_gain_set 0xA108
+#define reg_ccid2_passband_gain_set_pos 4
+#define reg_ccid2_passband_gain_set_len 4
+#define reg_ccid2_passband_gain_set_lsb 0
+#define xd_r_ccid_multiplier_7_0 0xA109
+#define ccid_multiplier_7_0_pos 0
+#define ccid_multiplier_7_0_len 8
+#define ccid_multiplier_7_0_lsb 0
+#define xd_r_ccid_multiplier_15_8 0xA10A
+#define ccid_multiplier_15_8_pos 0
+#define ccid_multiplier_15_8_len 8
+#define ccid_multiplier_15_8_lsb 8
+#define xd_r_ccid_right_shift_bits 0xA10B
+#define ccid_right_shift_bits_pos 0
+#define ccid_right_shift_bits_len 4
+#define ccid_right_shift_bits_lsb 0
+#define xd_r_reg_ccid_sx_7_0 0xA10C
+#define reg_ccid_sx_7_0_pos 0
+#define reg_ccid_sx_7_0_len 8
+#define reg_ccid_sx_7_0_lsb 0
+#define xd_r_reg_ccid_sx_15_8 0xA10D
+#define reg_ccid_sx_15_8_pos 0
+#define reg_ccid_sx_15_8_len 8
+#define reg_ccid_sx_15_8_lsb 8
+#define xd_r_reg_ccid_sx_21_16 0xA10E
+#define reg_ccid_sx_21_16_pos 0
+#define reg_ccid_sx_21_16_len 6
+#define reg_ccid_sx_21_16_lsb 16
+#define xd_r_reg_ccid_sy_7_0 0xA110
+#define reg_ccid_sy_7_0_pos 0
+#define reg_ccid_sy_7_0_len 8
+#define reg_ccid_sy_7_0_lsb 0
+#define xd_r_reg_ccid_sy_15_8 0xA111
+#define reg_ccid_sy_15_8_pos 0
+#define reg_ccid_sy_15_8_len 8
+#define reg_ccid_sy_15_8_lsb 8
+#define xd_r_reg_ccid_sy_23_16 0xA112
+#define reg_ccid_sy_23_16_pos 0
+#define reg_ccid_sy_23_16_len 8
+#define reg_ccid_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_7_0 0xA114
+#define reg_ccid2_sz_7_0_pos 0
+#define reg_ccid2_sz_7_0_len 8
+#define reg_ccid2_sz_7_0_lsb 0
+#define xd_r_reg_ccid2_sz_15_8 0xA115
+#define reg_ccid2_sz_15_8_pos 0
+#define reg_ccid2_sz_15_8_len 8
+#define reg_ccid2_sz_15_8_lsb 8
+#define xd_r_reg_ccid2_sz_23_16 0xA116
+#define reg_ccid2_sz_23_16_pos 0
+#define reg_ccid2_sz_23_16_len 8
+#define reg_ccid2_sz_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_25_24 0xA117
+#define reg_ccid2_sz_25_24_pos 0
+#define reg_ccid2_sz_25_24_len 2
+#define reg_ccid2_sz_25_24_lsb 24
+#define xd_r_reg_ccid2_sy_7_0 0xA118
+#define reg_ccid2_sy_7_0_pos 0
+#define reg_ccid2_sy_7_0_len 8
+#define reg_ccid2_sy_7_0_lsb 0
+#define xd_r_reg_ccid2_sy_15_8 0xA119
+#define reg_ccid2_sy_15_8_pos 0
+#define reg_ccid2_sy_15_8_len 8
+#define reg_ccid2_sy_15_8_lsb 8
+#define xd_r_reg_ccid2_sy_23_16 0xA11A
+#define reg_ccid2_sy_23_16_pos 0
+#define reg_ccid2_sy_23_16_len 8
+#define reg_ccid2_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sy_25_24 0xA11B
+#define reg_ccid2_sy_25_24_pos 0
+#define reg_ccid2_sy_25_24_len 2
+#define reg_ccid2_sy_25_24_lsb 24
+#define xd_p_dagc1_accumulate_num_2k_7_0 0xA120
+#define dagc1_accumulate_num_2k_7_0_pos 0
+#define dagc1_accumulate_num_2k_7_0_len 8
+#define dagc1_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_2k_12_8 0xA121
+#define dagc1_accumulate_num_2k_12_8_pos 0
+#define dagc1_accumulate_num_2k_12_8_len 5
+#define dagc1_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc1_accumulate_num_8k_7_0 0xA122
+#define dagc1_accumulate_num_8k_7_0_pos 0
+#define dagc1_accumulate_num_8k_7_0_len 8
+#define dagc1_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_8k_14_8 0xA123
+#define dagc1_accumulate_num_8k_14_8_pos 0
+#define dagc1_accumulate_num_8k_14_8_len 7
+#define dagc1_accumulate_num_8k_14_8_lsb 8
+#define xd_p_dagc1_desired_level_0 0xA123
+#define dagc1_desired_level_0_pos 7
+#define dagc1_desired_level_0_len 1
+#define dagc1_desired_level_0_lsb 0
+#define xd_p_dagc1_desired_level_8_1 0xA124
+#define dagc1_desired_level_8_1_pos 0
+#define dagc1_desired_level_8_1_len 8
+#define dagc1_desired_level_8_1_lsb 1
+#define xd_p_dagc1_apply_delay 0xA125
+#define dagc1_apply_delay_pos 0
+#define dagc1_apply_delay_len 7
+#define dagc1_apply_delay_lsb 0
+#define xd_p_dagc1_bypass_scale_ctl 0xA126
+#define dagc1_bypass_scale_ctl_pos 0
+#define dagc1_bypass_scale_ctl_len 2
+#define dagc1_bypass_scale_ctl_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_7_0 0xA127
+#define reg_dagc1_in_sat_cnt_7_0_pos 0
+#define reg_dagc1_in_sat_cnt_7_0_len 8
+#define reg_dagc1_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_15_8 0xA128
+#define reg_dagc1_in_sat_cnt_15_8_pos 0
+#define reg_dagc1_in_sat_cnt_15_8_len 8
+#define reg_dagc1_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_in_sat_cnt_23_16 0xA129
+#define reg_dagc1_in_sat_cnt_23_16_pos 0
+#define reg_dagc1_in_sat_cnt_23_16_len 8
+#define reg_dagc1_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_in_sat_cnt_31_24 0xA12A
+#define reg_dagc1_in_sat_cnt_31_24_pos 0
+#define reg_dagc1_in_sat_cnt_31_24_len 8
+#define reg_dagc1_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc1_out_sat_cnt_7_0 0xA12B
+#define reg_dagc1_out_sat_cnt_7_0_pos 0
+#define reg_dagc1_out_sat_cnt_7_0_len 8
+#define reg_dagc1_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_out_sat_cnt_15_8 0xA12C
+#define reg_dagc1_out_sat_cnt_15_8_pos 0
+#define reg_dagc1_out_sat_cnt_15_8_len 8
+#define reg_dagc1_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_out_sat_cnt_23_16 0xA12D
+#define reg_dagc1_out_sat_cnt_23_16_pos 0
+#define reg_dagc1_out_sat_cnt_23_16_len 8
+#define reg_dagc1_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_out_sat_cnt_31_24 0xA12E
+#define reg_dagc1_out_sat_cnt_31_24_pos 0
+#define reg_dagc1_out_sat_cnt_31_24_len 8
+#define reg_dagc1_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc1_multiplier_7_0 0xA136
+#define dagc1_multiplier_7_0_pos 0
+#define dagc1_multiplier_7_0_len 8
+#define dagc1_multiplier_7_0_lsb 0
+#define xd_r_dagc1_multiplier_15_8 0xA137
+#define dagc1_multiplier_15_8_pos 0
+#define dagc1_multiplier_15_8_len 8
+#define dagc1_multiplier_15_8_lsb 8
+#define xd_r_dagc1_right_shift_bits 0xA138
+#define dagc1_right_shift_bits_pos 0
+#define dagc1_right_shift_bits_len 4
+#define dagc1_right_shift_bits_lsb 0
+#define xd_p_reg_bfs_fcw_7_0 0xA140
+#define reg_bfs_fcw_7_0_pos 0
+#define reg_bfs_fcw_7_0_len 8
+#define reg_bfs_fcw_7_0_lsb 0
+#define xd_p_reg_bfs_fcw_15_8 0xA141
+#define reg_bfs_fcw_15_8_pos 0
+#define reg_bfs_fcw_15_8_len 8
+#define reg_bfs_fcw_15_8_lsb 8
+#define xd_p_reg_bfs_fcw_22_16 0xA142
+#define reg_bfs_fcw_22_16_pos 0
+#define reg_bfs_fcw_22_16_len 7
+#define reg_bfs_fcw_22_16_lsb 16
+#define xd_p_reg_antif_sf_7_0 0xA144
+#define reg_antif_sf_7_0_pos 0
+#define reg_antif_sf_7_0_len 8
+#define reg_antif_sf_7_0_lsb 0
+#define xd_p_reg_antif_sf_11_8 0xA145
+#define reg_antif_sf_11_8_pos 0
+#define reg_antif_sf_11_8_len 4
+#define reg_antif_sf_11_8_lsb 8
+#define xd_r_bfs_fcw_q_7_0 0xA150
+#define bfs_fcw_q_7_0_pos 0
+#define bfs_fcw_q_7_0_len 8
+#define bfs_fcw_q_7_0_lsb 0
+#define xd_r_bfs_fcw_q_15_8 0xA151
+#define bfs_fcw_q_15_8_pos 0
+#define bfs_fcw_q_15_8_len 8
+#define bfs_fcw_q_15_8_lsb 8
+#define xd_r_bfs_fcw_q_22_16 0xA152
+#define bfs_fcw_q_22_16_pos 0
+#define bfs_fcw_q_22_16_len 7
+#define bfs_fcw_q_22_16_lsb 16
+#define xd_p_reg_dca_enu 0xA160
+#define reg_dca_enu_pos 0
+#define reg_dca_enu_len 1
+#define reg_dca_enu_lsb 0
+#define xd_p_reg_dca_enl 0xA160
+#define reg_dca_enl_pos 1
+#define reg_dca_enl_len 1
+#define reg_dca_enl_lsb 0
+#define xd_p_reg_dca_lower_chip 0xA160
+#define reg_dca_lower_chip_pos 2
+#define reg_dca_lower_chip_len 1
+#define reg_dca_lower_chip_lsb 0
+#define xd_p_reg_dca_upper_chip 0xA160
+#define reg_dca_upper_chip_pos 3
+#define reg_dca_upper_chip_len 1
+#define reg_dca_upper_chip_lsb 0
+#define xd_p_reg_dca_platch 0xA160
+#define reg_dca_platch_pos 4
+#define reg_dca_platch_len 1
+#define reg_dca_platch_lsb 0
+#define xd_p_reg_dca_th 0xA161
+#define reg_dca_th_pos 0
+#define reg_dca_th_len 5
+#define reg_dca_th_lsb 0
+#define xd_p_reg_dca_scale 0xA162
+#define reg_dca_scale_pos 0
+#define reg_dca_scale_len 4
+#define reg_dca_scale_lsb 0
+#define xd_p_reg_dca_tone_7_0 0xA163
+#define reg_dca_tone_7_0_pos 0
+#define reg_dca_tone_7_0_len 8
+#define reg_dca_tone_7_0_lsb 0
+#define xd_p_reg_dca_tone_12_8 0xA164
+#define reg_dca_tone_12_8_pos 0
+#define reg_dca_tone_12_8_len 5
+#define reg_dca_tone_12_8_lsb 8
+#define xd_p_reg_dca_time_7_0 0xA165
+#define reg_dca_time_7_0_pos 0
+#define reg_dca_time_7_0_len 8
+#define reg_dca_time_7_0_lsb 0
+#define xd_p_reg_dca_time_15_8 0xA166
+#define reg_dca_time_15_8_pos 0
+#define reg_dca_time_15_8_len 8
+#define reg_dca_time_15_8_lsb 8
+#define xd_r_dcasm 0xA167
+#define dcasm_pos 0
+#define dcasm_len 3
+#define dcasm_lsb 0
+#define xd_p_reg_qnt_valuew_7_0 0xA168
+#define reg_qnt_valuew_7_0_pos 0
+#define reg_qnt_valuew_7_0_len 8
+#define reg_qnt_valuew_7_0_lsb 0
+#define xd_p_reg_qnt_valuew_10_8 0xA169
+#define reg_qnt_valuew_10_8_pos 0
+#define reg_qnt_valuew_10_8_len 3
+#define reg_qnt_valuew_10_8_lsb 8
+#define xd_p_dca_sbx_gain_diff_7_0 0xA16A
+#define dca_sbx_gain_diff_7_0_pos 0
+#define dca_sbx_gain_diff_7_0_len 8
+#define dca_sbx_gain_diff_7_0_lsb 0
+#define xd_p_dca_sbx_gain_diff_9_8 0xA16B
+#define dca_sbx_gain_diff_9_8_pos 0
+#define dca_sbx_gain_diff_9_8_len 2
+#define dca_sbx_gain_diff_9_8_lsb 8
+#define xd_p_reg_dca_stand_alone 0xA16C
+#define reg_dca_stand_alone_pos 0
+#define reg_dca_stand_alone_len 1
+#define reg_dca_stand_alone_lsb 0
+#define xd_p_reg_dca_upper_out_en 0xA16C
+#define reg_dca_upper_out_en_pos 1
+#define reg_dca_upper_out_en_len 1
+#define reg_dca_upper_out_en_lsb 0
+#define xd_p_reg_dca_rc_en 0xA16C
+#define reg_dca_rc_en_pos 2
+#define reg_dca_rc_en_len 1
+#define reg_dca_rc_en_lsb 0
+#define xd_p_reg_dca_retrain_send 0xA16C
+#define reg_dca_retrain_send_pos 3
+#define reg_dca_retrain_send_len 1
+#define reg_dca_retrain_send_lsb 0
+#define xd_p_reg_dca_retrain_rec 0xA16C
+#define reg_dca_retrain_rec_pos 4
+#define reg_dca_retrain_rec_len 1
+#define reg_dca_retrain_rec_lsb 0
+#define xd_p_reg_dca_api_tpsrdy 0xA16C
+#define reg_dca_api_tpsrdy_pos 5
+#define reg_dca_api_tpsrdy_len 1
+#define reg_dca_api_tpsrdy_lsb 0
+#define xd_p_reg_dca_symbol_gap 0xA16D
+#define reg_dca_symbol_gap_pos 0
+#define reg_dca_symbol_gap_len 4
+#define reg_dca_symbol_gap_lsb 0
+#define xd_p_reg_qnt_nfvaluew_7_0 0xA16E
+#define reg_qnt_nfvaluew_7_0_pos 0
+#define reg_qnt_nfvaluew_7_0_len 8
+#define reg_qnt_nfvaluew_7_0_lsb 0
+#define xd_p_reg_qnt_nfvaluew_10_8 0xA16F
+#define reg_qnt_nfvaluew_10_8_pos 0
+#define reg_qnt_nfvaluew_10_8_len 3
+#define reg_qnt_nfvaluew_10_8_lsb 8
+#define xd_p_reg_qnt_flatness_thr_7_0 0xA170
+#define reg_qnt_flatness_thr_7_0_pos 0
+#define reg_qnt_flatness_thr_7_0_len 8
+#define reg_qnt_flatness_thr_7_0_lsb 0
+#define xd_p_reg_qnt_flatness_thr_9_8 0xA171
+#define reg_qnt_flatness_thr_9_8_pos 0
+#define reg_qnt_flatness_thr_9_8_len 2
+#define reg_qnt_flatness_thr_9_8_lsb 8
+#define xd_p_reg_dca_tone_idx_5_0 0xA171
+#define reg_dca_tone_idx_5_0_pos 2
+#define reg_dca_tone_idx_5_0_len 6
+#define reg_dca_tone_idx_5_0_lsb 0
+#define xd_p_reg_dca_tone_idx_12_6 0xA172
+#define reg_dca_tone_idx_12_6_pos 0
+#define reg_dca_tone_idx_12_6_len 7
+#define reg_dca_tone_idx_12_6_lsb 6
+#define xd_p_reg_dca_data_vld 0xA173
+#define reg_dca_data_vld_pos 0
+#define reg_dca_data_vld_len 1
+#define reg_dca_data_vld_lsb 0
+#define xd_p_reg_dca_read_update 0xA173
+#define reg_dca_read_update_pos 1
+#define reg_dca_read_update_len 1
+#define reg_dca_read_update_lsb 0
+#define xd_r_reg_dca_data_re_5_0 0xA173
+#define reg_dca_data_re_5_0_pos 2
+#define reg_dca_data_re_5_0_len 6
+#define reg_dca_data_re_5_0_lsb 0
+#define xd_r_reg_dca_data_re_10_6 0xA174
+#define reg_dca_data_re_10_6_pos 0
+#define reg_dca_data_re_10_6_len 5
+#define reg_dca_data_re_10_6_lsb 6
+#define xd_r_reg_dca_data_im_7_0 0xA175
+#define reg_dca_data_im_7_0_pos 0
+#define reg_dca_data_im_7_0_len 8
+#define reg_dca_data_im_7_0_lsb 0
+#define xd_r_reg_dca_data_im_10_8 0xA176
+#define reg_dca_data_im_10_8_pos 0
+#define reg_dca_data_im_10_8_len 3
+#define reg_dca_data_im_10_8_lsb 8
+#define xd_r_reg_dca_data_h2_7_0 0xA178
+#define reg_dca_data_h2_7_0_pos 0
+#define reg_dca_data_h2_7_0_len 8
+#define reg_dca_data_h2_7_0_lsb 0
+#define xd_r_reg_dca_data_h2_9_8 0xA179
+#define reg_dca_data_h2_9_8_pos 0
+#define reg_dca_data_h2_9_8_len 2
+#define reg_dca_data_h2_9_8_lsb 8
+#define xd_p_reg_f_adc_7_0 0xA180
+#define reg_f_adc_7_0_pos 0
+#define reg_f_adc_7_0_len 8
+#define reg_f_adc_7_0_lsb 0
+#define xd_p_reg_f_adc_15_8 0xA181
+#define reg_f_adc_15_8_pos 0
+#define reg_f_adc_15_8_len 8
+#define reg_f_adc_15_8_lsb 8
+#define xd_p_reg_f_adc_23_16 0xA182
+#define reg_f_adc_23_16_pos 0
+#define reg_f_adc_23_16_len 8
+#define reg_f_adc_23_16_lsb 16
+#define xd_r_intp_mu_7_0 0xA190
+#define intp_mu_7_0_pos 0
+#define intp_mu_7_0_len 8
+#define intp_mu_7_0_lsb 0
+#define xd_r_intp_mu_15_8 0xA191
+#define intp_mu_15_8_pos 0
+#define intp_mu_15_8_len 8
+#define intp_mu_15_8_lsb 8
+#define xd_r_intp_mu_19_16 0xA192
+#define intp_mu_19_16_pos 0
+#define intp_mu_19_16_len 4
+#define intp_mu_19_16_lsb 16
+#define xd_p_reg_agc_rst 0xA1A0
+#define reg_agc_rst_pos 0
+#define reg_agc_rst_len 1
+#define reg_agc_rst_lsb 0
+#define xd_p_rf_agc_en 0xA1A0
+#define rf_agc_en_pos 1
+#define rf_agc_en_len 1
+#define rf_agc_en_lsb 0
+#define xd_p_rf_agc_dis 0xA1A0
+#define rf_agc_dis_pos 2
+#define rf_agc_dis_len 1
+#define rf_agc_dis_lsb 0
+#define xd_p_if_agc_rst 0xA1A0
+#define if_agc_rst_pos 3
+#define if_agc_rst_len 1
+#define if_agc_rst_lsb 0
+#define xd_p_if_agc_en 0xA1A0
+#define if_agc_en_pos 4
+#define if_agc_en_len 1
+#define if_agc_en_lsb 0
+#define xd_p_if_agc_dis 0xA1A0
+#define if_agc_dis_pos 5
+#define if_agc_dis_len 1
+#define if_agc_dis_lsb 0
+#define xd_p_agc_lock 0xA1A0
+#define agc_lock_pos 6
+#define agc_lock_len 1
+#define agc_lock_lsb 0
+#define xd_p_reg_tinr_rst 0xA1A1
+#define reg_tinr_rst_pos 0
+#define reg_tinr_rst_len 1
+#define reg_tinr_rst_lsb 0
+#define xd_p_reg_tinr_en 0xA1A1
+#define reg_tinr_en_pos 1
+#define reg_tinr_en_len 1
+#define reg_tinr_en_lsb 0
+#define xd_p_reg_ccifs_en 0xA1A2
+#define reg_ccifs_en_pos 0
+#define reg_ccifs_en_len 1
+#define reg_ccifs_en_lsb 0
+#define xd_p_reg_ccifs_dis 0xA1A2
+#define reg_ccifs_dis_pos 1
+#define reg_ccifs_dis_len 1
+#define reg_ccifs_dis_lsb 0
+#define xd_p_reg_ccifs_rst 0xA1A2
+#define reg_ccifs_rst_pos 2
+#define reg_ccifs_rst_len 1
+#define reg_ccifs_rst_lsb 0
+#define xd_p_reg_ccifs_byp 0xA1A2
+#define reg_ccifs_byp_pos 3
+#define reg_ccifs_byp_len 1
+#define reg_ccifs_byp_lsb 0
+#define xd_p_reg_ccif_en 0xA1A3
+#define reg_ccif_en_pos 0
+#define reg_ccif_en_len 1
+#define reg_ccif_en_lsb 0
+#define xd_p_reg_ccif_dis 0xA1A3
+#define reg_ccif_dis_pos 1
+#define reg_ccif_dis_len 1
+#define reg_ccif_dis_lsb 0
+#define xd_p_reg_ccif_rst 0xA1A3
+#define reg_ccif_rst_pos 2
+#define reg_ccif_rst_len 1
+#define reg_ccif_rst_lsb 0
+#define xd_p_reg_ccif_byp 0xA1A3
+#define reg_ccif_byp_pos 3
+#define reg_ccif_byp_len 1
+#define reg_ccif_byp_lsb 0
+#define xd_p_dagc1_rst 0xA1A4
+#define dagc1_rst_pos 0
+#define dagc1_rst_len 1
+#define dagc1_rst_lsb 0
+#define xd_p_dagc1_en 0xA1A4
+#define dagc1_en_pos 1
+#define dagc1_en_len 1
+#define dagc1_en_lsb 0
+#define xd_p_dagc1_mode 0xA1A4
+#define dagc1_mode_pos 2
+#define dagc1_mode_len 2
+#define dagc1_mode_lsb 0
+#define xd_p_dagc1_done 0xA1A4
+#define dagc1_done_pos 4
+#define dagc1_done_len 1
+#define dagc1_done_lsb 0
+#define xd_p_ccid_rst 0xA1A5
+#define ccid_rst_pos 0
+#define ccid_rst_len 1
+#define ccid_rst_lsb 0
+#define xd_p_ccid_en 0xA1A5
+#define ccid_en_pos 1
+#define ccid_en_len 1
+#define ccid_en_lsb 0
+#define xd_p_ccid_mode 0xA1A5
+#define ccid_mode_pos 2
+#define ccid_mode_len 2
+#define ccid_mode_lsb 0
+#define xd_p_ccid_done 0xA1A5
+#define ccid_done_pos 4
+#define ccid_done_len 1
+#define ccid_done_lsb 0
+#define xd_r_ccid_deted 0xA1A5
+#define ccid_deted_pos 5
+#define ccid_deted_len 1
+#define ccid_deted_lsb 0
+#define xd_p_ccid2_en 0xA1A5
+#define ccid2_en_pos 6
+#define ccid2_en_len 1
+#define ccid2_en_lsb 0
+#define xd_p_ccid2_done 0xA1A5
+#define ccid2_done_pos 7
+#define ccid2_done_len 1
+#define ccid2_done_lsb 0
+#define xd_p_reg_bfs_en 0xA1A6
+#define reg_bfs_en_pos 0
+#define reg_bfs_en_len 1
+#define reg_bfs_en_lsb 0
+#define xd_p_reg_bfs_dis 0xA1A6
+#define reg_bfs_dis_pos 1
+#define reg_bfs_dis_len 1
+#define reg_bfs_dis_lsb 0
+#define xd_p_reg_bfs_rst 0xA1A6
+#define reg_bfs_rst_pos 2
+#define reg_bfs_rst_len 1
+#define reg_bfs_rst_lsb 0
+#define xd_p_reg_bfs_byp 0xA1A6
+#define reg_bfs_byp_pos 3
+#define reg_bfs_byp_len 1
+#define reg_bfs_byp_lsb 0
+#define xd_p_reg_antif_en 0xA1A7
+#define reg_antif_en_pos 0
+#define reg_antif_en_len 1
+#define reg_antif_en_lsb 0
+#define xd_p_reg_antif_dis 0xA1A7
+#define reg_antif_dis_pos 1
+#define reg_antif_dis_len 1
+#define reg_antif_dis_lsb 0
+#define xd_p_reg_antif_rst 0xA1A7
+#define reg_antif_rst_pos 2
+#define reg_antif_rst_len 1
+#define reg_antif_rst_lsb 0
+#define xd_p_reg_antif_byp 0xA1A7
+#define reg_antif_byp_pos 3
+#define reg_antif_byp_len 1
+#define reg_antif_byp_lsb 0
+#define xd_p_intp_en 0xA1A8
+#define intp_en_pos 0
+#define intp_en_len 1
+#define intp_en_lsb 0
+#define xd_p_intp_dis 0xA1A8
+#define intp_dis_pos 1
+#define intp_dis_len 1
+#define intp_dis_lsb 0
+#define xd_p_intp_rst 0xA1A8
+#define intp_rst_pos 2
+#define intp_rst_len 1
+#define intp_rst_lsb 0
+#define xd_p_intp_byp 0xA1A8
+#define intp_byp_pos 3
+#define intp_byp_len 1
+#define intp_byp_lsb 0
+#define xd_p_reg_acif_en 0xA1A9
+#define reg_acif_en_pos 0
+#define reg_acif_en_len 1
+#define reg_acif_en_lsb 0
+#define xd_p_reg_acif_dis 0xA1A9
+#define reg_acif_dis_pos 1
+#define reg_acif_dis_len 1
+#define reg_acif_dis_lsb 0
+#define xd_p_reg_acif_rst 0xA1A9
+#define reg_acif_rst_pos 2
+#define reg_acif_rst_len 1
+#define reg_acif_rst_lsb 0
+#define xd_p_reg_acif_byp 0xA1A9
+#define reg_acif_byp_pos 3
+#define reg_acif_byp_len 1
+#define reg_acif_byp_lsb 0
+#define xd_p_reg_acif_sync_mode 0xA1A9
+#define reg_acif_sync_mode_pos 4
+#define reg_acif_sync_mode_len 1
+#define reg_acif_sync_mode_lsb 0
+#define xd_p_dagc2_rst 0xA1AA
+#define dagc2_rst_pos 0
+#define dagc2_rst_len 1
+#define dagc2_rst_lsb 0
+#define xd_p_dagc2_en 0xA1AA
+#define dagc2_en_pos 1
+#define dagc2_en_len 1
+#define dagc2_en_lsb 0
+#define xd_p_dagc2_mode 0xA1AA
+#define dagc2_mode_pos 2
+#define dagc2_mode_len 2
+#define dagc2_mode_lsb 0
+#define xd_p_dagc2_done 0xA1AA
+#define dagc2_done_pos 4
+#define dagc2_done_len 1
+#define dagc2_done_lsb 0
+#define xd_p_reg_dca_en 0xA1AB
+#define reg_dca_en_pos 0
+#define reg_dca_en_len 1
+#define reg_dca_en_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_7_0 0xA1C0
+#define dagc2_accumulate_num_2k_7_0_pos 0
+#define dagc2_accumulate_num_2k_7_0_len 8
+#define dagc2_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_12_8 0xA1C1
+#define dagc2_accumulate_num_2k_12_8_pos 0
+#define dagc2_accumulate_num_2k_12_8_len 5
+#define dagc2_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc2_accumulate_num_8k_7_0 0xA1C2
+#define dagc2_accumulate_num_8k_7_0_pos 0
+#define dagc2_accumulate_num_8k_7_0_len 8
+#define dagc2_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_8k_12_8 0xA1C3
+#define dagc2_accumulate_num_8k_12_8_pos 0
+#define dagc2_accumulate_num_8k_12_8_len 5
+#define dagc2_accumulate_num_8k_12_8_lsb 8
+#define xd_p_dagc2_desired_level_2_0 0xA1C3
+#define dagc2_desired_level_2_0_pos 5
+#define dagc2_desired_level_2_0_len 3
+#define dagc2_desired_level_2_0_lsb 0
+#define xd_p_dagc2_desired_level_8_3 0xA1C4
+#define dagc2_desired_level_8_3_pos 0
+#define dagc2_desired_level_8_3_len 6
+#define dagc2_desired_level_8_3_lsb 3
+#define xd_p_dagc2_apply_delay 0xA1C5
+#define dagc2_apply_delay_pos 0
+#define dagc2_apply_delay_len 7
+#define dagc2_apply_delay_lsb 0
+#define xd_p_dagc2_bypass_scale_ctl 0xA1C6
+#define dagc2_bypass_scale_ctl_pos 0
+#define dagc2_bypass_scale_ctl_len 3
+#define dagc2_bypass_scale_ctl_lsb 0
+#define xd_p_dagc2_programmable_shift1 0xA1C7
+#define dagc2_programmable_shift1_pos 0
+#define dagc2_programmable_shift1_len 8
+#define dagc2_programmable_shift1_lsb 0
+#define xd_p_dagc2_programmable_shift2 0xA1C8
+#define dagc2_programmable_shift2_pos 0
+#define dagc2_programmable_shift2_len 8
+#define dagc2_programmable_shift2_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_7_0 0xA1C9
+#define reg_dagc2_in_sat_cnt_7_0_pos 0
+#define reg_dagc2_in_sat_cnt_7_0_len 8
+#define reg_dagc2_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_15_8 0xA1CA
+#define reg_dagc2_in_sat_cnt_15_8_pos 0
+#define reg_dagc2_in_sat_cnt_15_8_len 8
+#define reg_dagc2_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_in_sat_cnt_23_16 0xA1CB
+#define reg_dagc2_in_sat_cnt_23_16_pos 0
+#define reg_dagc2_in_sat_cnt_23_16_len 8
+#define reg_dagc2_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_in_sat_cnt_31_24 0xA1CC
+#define reg_dagc2_in_sat_cnt_31_24_pos 0
+#define reg_dagc2_in_sat_cnt_31_24_len 8
+#define reg_dagc2_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc2_out_sat_cnt_7_0 0xA1CD
+#define reg_dagc2_out_sat_cnt_7_0_pos 0
+#define reg_dagc2_out_sat_cnt_7_0_len 8
+#define reg_dagc2_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_out_sat_cnt_15_8 0xA1CE
+#define reg_dagc2_out_sat_cnt_15_8_pos 0
+#define reg_dagc2_out_sat_cnt_15_8_len 8
+#define reg_dagc2_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_out_sat_cnt_23_16 0xA1CF
+#define reg_dagc2_out_sat_cnt_23_16_pos 0
+#define reg_dagc2_out_sat_cnt_23_16_len 8
+#define reg_dagc2_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_out_sat_cnt_31_24 0xA1D0
+#define reg_dagc2_out_sat_cnt_31_24_pos 0
+#define reg_dagc2_out_sat_cnt_31_24_len 8
+#define reg_dagc2_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc2_multiplier_7_0 0xA1D6
+#define dagc2_multiplier_7_0_pos 0
+#define dagc2_multiplier_7_0_len 8
+#define dagc2_multiplier_7_0_lsb 0
+#define xd_r_dagc2_multiplier_15_8 0xA1D7
+#define dagc2_multiplier_15_8_pos 0
+#define dagc2_multiplier_15_8_len 8
+#define dagc2_multiplier_15_8_lsb 8
+#define xd_r_dagc2_right_shift_bits 0xA1D8
+#define dagc2_right_shift_bits_pos 0
+#define dagc2_right_shift_bits_len 4
+#define dagc2_right_shift_bits_lsb 0
+#define xd_p_cfoe_NS_coeff1_7_0 0xA200
+#define cfoe_NS_coeff1_7_0_pos 0
+#define cfoe_NS_coeff1_7_0_len 8
+#define cfoe_NS_coeff1_7_0_lsb 0
+#define xd_p_cfoe_NS_coeff1_15_8 0xA201
+#define cfoe_NS_coeff1_15_8_pos 0
+#define cfoe_NS_coeff1_15_8_len 8
+#define cfoe_NS_coeff1_15_8_lsb 8
+#define xd_p_cfoe_NS_coeff1_23_16 0xA202
+#define cfoe_NS_coeff1_23_16_pos 0
+#define cfoe_NS_coeff1_23_16_len 8
+#define cfoe_NS_coeff1_23_16_lsb 16
+#define xd_p_cfoe_NS_coeff1_25_24 0xA203
+#define cfoe_NS_coeff1_25_24_pos 0
+#define cfoe_NS_coeff1_25_24_len 2
+#define cfoe_NS_coeff1_25_24_lsb 24
+#define xd_p_cfoe_NS_coeff2_5_0 0xA203
+#define cfoe_NS_coeff2_5_0_pos 2
+#define cfoe_NS_coeff2_5_0_len 6
+#define cfoe_NS_coeff2_5_0_lsb 0
+#define xd_p_cfoe_NS_coeff2_13_6 0xA204
+#define cfoe_NS_coeff2_13_6_pos 0
+#define cfoe_NS_coeff2_13_6_len 8
+#define cfoe_NS_coeff2_13_6_lsb 6
+#define xd_p_cfoe_NS_coeff2_21_14 0xA205
+#define cfoe_NS_coeff2_21_14_pos 0
+#define cfoe_NS_coeff2_21_14_len 8
+#define cfoe_NS_coeff2_21_14_lsb 14
+#define xd_p_cfoe_NS_coeff2_24_22 0xA206
+#define cfoe_NS_coeff2_24_22_pos 0
+#define cfoe_NS_coeff2_24_22_len 3
+#define cfoe_NS_coeff2_24_22_lsb 22
+#define xd_p_cfoe_lf_c1_4_0 0xA206
+#define cfoe_lf_c1_4_0_pos 3
+#define cfoe_lf_c1_4_0_len 5
+#define cfoe_lf_c1_4_0_lsb 0
+#define xd_p_cfoe_lf_c1_12_5 0xA207
+#define cfoe_lf_c1_12_5_pos 0
+#define cfoe_lf_c1_12_5_len 8
+#define cfoe_lf_c1_12_5_lsb 5
+#define xd_p_cfoe_lf_c1_20_13 0xA208
+#define cfoe_lf_c1_20_13_pos 0
+#define cfoe_lf_c1_20_13_len 8
+#define cfoe_lf_c1_20_13_lsb 13
+#define xd_p_cfoe_lf_c1_25_21 0xA209
+#define cfoe_lf_c1_25_21_pos 0
+#define cfoe_lf_c1_25_21_len 5
+#define cfoe_lf_c1_25_21_lsb 21
+#define xd_p_cfoe_lf_c2_2_0 0xA209
+#define cfoe_lf_c2_2_0_pos 5
+#define cfoe_lf_c2_2_0_len 3
+#define cfoe_lf_c2_2_0_lsb 0
+#define xd_p_cfoe_lf_c2_10_3 0xA20A
+#define cfoe_lf_c2_10_3_pos 0
+#define cfoe_lf_c2_10_3_len 8
+#define cfoe_lf_c2_10_3_lsb 3
+#define xd_p_cfoe_lf_c2_18_11 0xA20B
+#define cfoe_lf_c2_18_11_pos 0
+#define cfoe_lf_c2_18_11_len 8
+#define cfoe_lf_c2_18_11_lsb 11
+#define xd_p_cfoe_lf_c2_25_19 0xA20C
+#define cfoe_lf_c2_25_19_pos 0
+#define cfoe_lf_c2_25_19_len 7
+#define cfoe_lf_c2_25_19_lsb 19
+#define xd_p_cfoe_ifod_7_0 0xA20D
+#define cfoe_ifod_7_0_pos 0
+#define cfoe_ifod_7_0_len 8
+#define cfoe_ifod_7_0_lsb 0
+#define xd_p_cfoe_ifod_10_8 0xA20E
+#define cfoe_ifod_10_8_pos 0
+#define cfoe_ifod_10_8_len 3
+#define cfoe_ifod_10_8_lsb 8
+#define xd_p_cfoe_Divg_ctr_th 0xA20E
+#define cfoe_Divg_ctr_th_pos 4
+#define cfoe_Divg_ctr_th_len 4
+#define cfoe_Divg_ctr_th_lsb 0
+#define xd_p_cfoe_FOT_divg_th 0xA20F
+#define cfoe_FOT_divg_th_pos 0
+#define cfoe_FOT_divg_th_len 8
+#define cfoe_FOT_divg_th_lsb 0
+#define xd_p_cfoe_FOT_cnvg_th 0xA210
+#define cfoe_FOT_cnvg_th_pos 0
+#define cfoe_FOT_cnvg_th_len 8
+#define cfoe_FOT_cnvg_th_lsb 0
+#define xd_p_reg_cfoe_offset_7_0 0xA211
+#define reg_cfoe_offset_7_0_pos 0
+#define reg_cfoe_offset_7_0_len 8
+#define reg_cfoe_offset_7_0_lsb 0
+#define xd_p_reg_cfoe_offset_9_8 0xA212
+#define reg_cfoe_offset_9_8_pos 0
+#define reg_cfoe_offset_9_8_len 2
+#define reg_cfoe_offset_9_8_lsb 8
+#define xd_p_reg_cfoe_ifoe_sign_corr 0xA212
+#define reg_cfoe_ifoe_sign_corr_pos 2
+#define reg_cfoe_ifoe_sign_corr_len 1
+#define reg_cfoe_ifoe_sign_corr_lsb 0
+#define xd_r_cfoe_fot_LF_output_7_0 0xA218
+#define cfoe_fot_LF_output_7_0_pos 0
+#define cfoe_fot_LF_output_7_0_len 8
+#define cfoe_fot_LF_output_7_0_lsb 0
+#define xd_r_cfoe_fot_LF_output_15_8 0xA219
+#define cfoe_fot_LF_output_15_8_pos 0
+#define cfoe_fot_LF_output_15_8_len 8
+#define cfoe_fot_LF_output_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_7_0 0xA21A
+#define cfoe_ifo_metric_7_0_pos 0
+#define cfoe_ifo_metric_7_0_len 8
+#define cfoe_ifo_metric_7_0_lsb 0
+#define xd_r_cfoe_ifo_metric_15_8 0xA21B
+#define cfoe_ifo_metric_15_8_pos 0
+#define cfoe_ifo_metric_15_8_len 8
+#define cfoe_ifo_metric_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_23_16 0xA21C
+#define cfoe_ifo_metric_23_16_pos 0
+#define cfoe_ifo_metric_23_16_len 8
+#define cfoe_ifo_metric_23_16_lsb 16
+#define xd_p_ste_Nu 0xA220
+#define ste_Nu_pos 0
+#define ste_Nu_len 2
+#define ste_Nu_lsb 0
+#define xd_p_ste_GI 0xA220
+#define ste_GI_pos 2
+#define ste_GI_len 3
+#define ste_GI_lsb 0
+#define xd_p_ste_symbol_num 0xA221
+#define ste_symbol_num_pos 0
+#define ste_symbol_num_len 2
+#define ste_symbol_num_lsb 0
+#define xd_p_ste_sample_num 0xA221
+#define ste_sample_num_pos 2
+#define ste_sample_num_len 2
+#define ste_sample_num_lsb 0
+#define xd_p_reg_ste_buf_en 0xA221
+#define reg_ste_buf_en_pos 7
+#define reg_ste_buf_en_len 1
+#define reg_ste_buf_en_lsb 0
+#define xd_p_ste_FFT_offset_7_0 0xA222
+#define ste_FFT_offset_7_0_pos 0
+#define ste_FFT_offset_7_0_len 8
+#define ste_FFT_offset_7_0_lsb 0
+#define xd_p_ste_FFT_offset_11_8 0xA223
+#define ste_FFT_offset_11_8_pos 0
+#define ste_FFT_offset_11_8_len 4
+#define ste_FFT_offset_11_8_lsb 8
+#define xd_p_reg_ste_tstmod 0xA223
+#define reg_ste_tstmod_pos 5
+#define reg_ste_tstmod_len 1
+#define reg_ste_tstmod_lsb 0
+#define xd_p_ste_adv_start_7_0 0xA224
+#define ste_adv_start_7_0_pos 0
+#define ste_adv_start_7_0_len 8
+#define ste_adv_start_7_0_lsb 0
+#define xd_p_ste_adv_start_10_8 0xA225
+#define ste_adv_start_10_8_pos 0
+#define ste_adv_start_10_8_len 3
+#define ste_adv_start_10_8_lsb 8
+#define xd_p_ste_adv_stop 0xA226
+#define ste_adv_stop_pos 0
+#define ste_adv_stop_len 8
+#define ste_adv_stop_lsb 0
+#define xd_r_ste_P_value_7_0 0xA228
+#define ste_P_value_7_0_pos 0
+#define ste_P_value_7_0_len 8
+#define ste_P_value_7_0_lsb 0
+#define xd_r_ste_P_value_10_8 0xA229
+#define ste_P_value_10_8_pos 0
+#define ste_P_value_10_8_len 3
+#define ste_P_value_10_8_lsb 8
+#define xd_r_ste_M_value_7_0 0xA22A
+#define ste_M_value_7_0_pos 0
+#define ste_M_value_7_0_len 8
+#define ste_M_value_7_0_lsb 0
+#define xd_r_ste_M_value_10_8 0xA22B
+#define ste_M_value_10_8_pos 0
+#define ste_M_value_10_8_len 3
+#define ste_M_value_10_8_lsb 8
+#define xd_r_ste_H1 0xA22C
+#define ste_H1_pos 0
+#define ste_H1_len 7
+#define ste_H1_lsb 0
+#define xd_r_ste_H2 0xA22D
+#define ste_H2_pos 0
+#define ste_H2_len 7
+#define ste_H2_lsb 0
+#define xd_r_ste_H3 0xA22E
+#define ste_H3_pos 0
+#define ste_H3_len 7
+#define ste_H3_lsb 0
+#define xd_r_ste_H4 0xA22F
+#define ste_H4_pos 0
+#define ste_H4_len 7
+#define ste_H4_lsb 0
+#define xd_r_ste_Corr_value_I_7_0 0xA230
+#define ste_Corr_value_I_7_0_pos 0
+#define ste_Corr_value_I_7_0_len 8
+#define ste_Corr_value_I_7_0_lsb 0
+#define xd_r_ste_Corr_value_I_15_8 0xA231
+#define ste_Corr_value_I_15_8_pos 0
+#define ste_Corr_value_I_15_8_len 8
+#define ste_Corr_value_I_15_8_lsb 8
+#define xd_r_ste_Corr_value_I_23_16 0xA232
+#define ste_Corr_value_I_23_16_pos 0
+#define ste_Corr_value_I_23_16_len 8
+#define ste_Corr_value_I_23_16_lsb 16
+#define xd_r_ste_Corr_value_I_27_24 0xA233
+#define ste_Corr_value_I_27_24_pos 0
+#define ste_Corr_value_I_27_24_len 4
+#define ste_Corr_value_I_27_24_lsb 24
+#define xd_r_ste_Corr_value_Q_7_0 0xA234
+#define ste_Corr_value_Q_7_0_pos 0
+#define ste_Corr_value_Q_7_0_len 8
+#define ste_Corr_value_Q_7_0_lsb 0
+#define xd_r_ste_Corr_value_Q_15_8 0xA235
+#define ste_Corr_value_Q_15_8_pos 0
+#define ste_Corr_value_Q_15_8_len 8
+#define ste_Corr_value_Q_15_8_lsb 8
+#define xd_r_ste_Corr_value_Q_23_16 0xA236
+#define ste_Corr_value_Q_23_16_pos 0
+#define ste_Corr_value_Q_23_16_len 8
+#define ste_Corr_value_Q_23_16_lsb 16
+#define xd_r_ste_Corr_value_Q_27_24 0xA237
+#define ste_Corr_value_Q_27_24_pos 0
+#define ste_Corr_value_Q_27_24_len 4
+#define ste_Corr_value_Q_27_24_lsb 24
+#define xd_r_ste_J_num_7_0 0xA238
+#define ste_J_num_7_0_pos 0
+#define ste_J_num_7_0_len 8
+#define ste_J_num_7_0_lsb 0
+#define xd_r_ste_J_num_15_8 0xA239
+#define ste_J_num_15_8_pos 0
+#define ste_J_num_15_8_len 8
+#define ste_J_num_15_8_lsb 8
+#define xd_r_ste_J_num_23_16 0xA23A
+#define ste_J_num_23_16_pos 0
+#define ste_J_num_23_16_len 8
+#define ste_J_num_23_16_lsb 16
+#define xd_r_ste_J_num_31_24 0xA23B
+#define ste_J_num_31_24_pos 0
+#define ste_J_num_31_24_len 8
+#define ste_J_num_31_24_lsb 24
+#define xd_r_ste_J_den_7_0 0xA23C
+#define ste_J_den_7_0_pos 0
+#define ste_J_den_7_0_len 8
+#define ste_J_den_7_0_lsb 0
+#define xd_r_ste_J_den_15_8 0xA23D
+#define ste_J_den_15_8_pos 0
+#define ste_J_den_15_8_len 8
+#define ste_J_den_15_8_lsb 8
+#define xd_r_ste_J_den_18_16 0xA23E
+#define ste_J_den_18_16_pos 0
+#define ste_J_den_18_16_len 3
+#define ste_J_den_18_16_lsb 16
+#define xd_r_ste_Beacon_Indicator 0xA23E
+#define ste_Beacon_Indicator_pos 4
+#define ste_Beacon_Indicator_len 1
+#define ste_Beacon_Indicator_lsb 0
+#define xd_r_tpsd_Frame_Num 0xA250
+#define tpsd_Frame_Num_pos 0
+#define tpsd_Frame_Num_len 2
+#define tpsd_Frame_Num_lsb 0
+#define xd_r_tpsd_Constel 0xA250
+#define tpsd_Constel_pos 2
+#define tpsd_Constel_len 2
+#define tpsd_Constel_lsb 0
+#define xd_r_tpsd_GI 0xA250
+#define tpsd_GI_pos 4
+#define tpsd_GI_len 2
+#define tpsd_GI_lsb 0
+#define xd_r_tpsd_Mode 0xA250
+#define tpsd_Mode_pos 6
+#define tpsd_Mode_len 2
+#define tpsd_Mode_lsb 0
+#define xd_r_tpsd_CR_HP 0xA251
+#define tpsd_CR_HP_pos 0
+#define tpsd_CR_HP_len 3
+#define tpsd_CR_HP_lsb 0
+#define xd_r_tpsd_CR_LP 0xA251
+#define tpsd_CR_LP_pos 3
+#define tpsd_CR_LP_len 3
+#define tpsd_CR_LP_lsb 0
+#define xd_r_tpsd_Hie 0xA252
+#define tpsd_Hie_pos 0
+#define tpsd_Hie_len 3
+#define tpsd_Hie_lsb 0
+#define xd_r_tpsd_Res_Bits 0xA252
+#define tpsd_Res_Bits_pos 3
+#define tpsd_Res_Bits_len 5
+#define tpsd_Res_Bits_lsb 0
+#define xd_r_tpsd_Res_Bits_0 0xA253
+#define tpsd_Res_Bits_0_pos 0
+#define tpsd_Res_Bits_0_len 1
+#define tpsd_Res_Bits_0_lsb 0
+#define xd_r_tpsd_LengthInd 0xA253
+#define tpsd_LengthInd_pos 1
+#define tpsd_LengthInd_len 6
+#define tpsd_LengthInd_lsb 0
+#define xd_r_tpsd_Cell_Id_7_0 0xA254
+#define tpsd_Cell_Id_7_0_pos 0
+#define tpsd_Cell_Id_7_0_len 8
+#define tpsd_Cell_Id_7_0_lsb 0
+#define xd_r_tpsd_Cell_Id_15_8 0xA255
+#define tpsd_Cell_Id_15_8_pos 0
+#define tpsd_Cell_Id_15_8_len 8
+#define tpsd_Cell_Id_15_8_lsb 0
+#define xd_p_reg_fft_mask_tone0_7_0 0xA260
+#define reg_fft_mask_tone0_7_0_pos 0
+#define reg_fft_mask_tone0_7_0_len 8
+#define reg_fft_mask_tone0_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone0_12_8 0xA261
+#define reg_fft_mask_tone0_12_8_pos 0
+#define reg_fft_mask_tone0_12_8_len 5
+#define reg_fft_mask_tone0_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone1_7_0 0xA262
+#define reg_fft_mask_tone1_7_0_pos 0
+#define reg_fft_mask_tone1_7_0_len 8
+#define reg_fft_mask_tone1_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone1_12_8 0xA263
+#define reg_fft_mask_tone1_12_8_pos 0
+#define reg_fft_mask_tone1_12_8_len 5
+#define reg_fft_mask_tone1_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone2_7_0 0xA264
+#define reg_fft_mask_tone2_7_0_pos 0
+#define reg_fft_mask_tone2_7_0_len 8
+#define reg_fft_mask_tone2_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone2_12_8 0xA265
+#define reg_fft_mask_tone2_12_8_pos 0
+#define reg_fft_mask_tone2_12_8_len 5
+#define reg_fft_mask_tone2_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone3_7_0 0xA266
+#define reg_fft_mask_tone3_7_0_pos 0
+#define reg_fft_mask_tone3_7_0_len 8
+#define reg_fft_mask_tone3_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone3_12_8 0xA267
+#define reg_fft_mask_tone3_12_8_pos 0
+#define reg_fft_mask_tone3_12_8_len 5
+#define reg_fft_mask_tone3_12_8_lsb 8
+#define xd_p_reg_fft_mask_from0_7_0 0xA268
+#define reg_fft_mask_from0_7_0_pos 0
+#define reg_fft_mask_from0_7_0_len 8
+#define reg_fft_mask_from0_7_0_lsb 0
+#define xd_p_reg_fft_mask_from0_12_8 0xA269
+#define reg_fft_mask_from0_12_8_pos 0
+#define reg_fft_mask_from0_12_8_len 5
+#define reg_fft_mask_from0_12_8_lsb 8
+#define xd_p_reg_fft_mask_to0_7_0 0xA26A
+#define reg_fft_mask_to0_7_0_pos 0
+#define reg_fft_mask_to0_7_0_len 8
+#define reg_fft_mask_to0_7_0_lsb 0
+#define xd_p_reg_fft_mask_to0_12_8 0xA26B
+#define reg_fft_mask_to0_12_8_pos 0
+#define reg_fft_mask_to0_12_8_len 5
+#define reg_fft_mask_to0_12_8_lsb 8
+#define xd_p_reg_fft_mask_from1_7_0 0xA26C
+#define reg_fft_mask_from1_7_0_pos 0
+#define reg_fft_mask_from1_7_0_len 8
+#define reg_fft_mask_from1_7_0_lsb 0
+#define xd_p_reg_fft_mask_from1_12_8 0xA26D
+#define reg_fft_mask_from1_12_8_pos 0
+#define reg_fft_mask_from1_12_8_len 5
+#define reg_fft_mask_from1_12_8_lsb 8
+#define xd_p_reg_fft_mask_to1_7_0 0xA26E
+#define reg_fft_mask_to1_7_0_pos 0
+#define reg_fft_mask_to1_7_0_len 8
+#define reg_fft_mask_to1_7_0_lsb 0
+#define xd_p_reg_fft_mask_to1_12_8 0xA26F
+#define reg_fft_mask_to1_12_8_pos 0
+#define reg_fft_mask_to1_12_8_len 5
+#define reg_fft_mask_to1_12_8_lsb 8
+#define xd_p_reg_cge_idx0_7_0 0xA280
+#define reg_cge_idx0_7_0_pos 0
+#define reg_cge_idx0_7_0_len 8
+#define reg_cge_idx0_7_0_lsb 0
+#define xd_p_reg_cge_idx0_12_8 0xA281
+#define reg_cge_idx0_12_8_pos 0
+#define reg_cge_idx0_12_8_len 5
+#define reg_cge_idx0_12_8_lsb 8
+#define xd_p_reg_cge_idx1_7_0 0xA282
+#define reg_cge_idx1_7_0_pos 0
+#define reg_cge_idx1_7_0_len 8
+#define reg_cge_idx1_7_0_lsb 0
+#define xd_p_reg_cge_idx1_12_8 0xA283
+#define reg_cge_idx1_12_8_pos 0
+#define reg_cge_idx1_12_8_len 5
+#define reg_cge_idx1_12_8_lsb 8
+#define xd_p_reg_cge_idx2_7_0 0xA284
+#define reg_cge_idx2_7_0_pos 0
+#define reg_cge_idx2_7_0_len 8
+#define reg_cge_idx2_7_0_lsb 0
+#define xd_p_reg_cge_idx2_12_8 0xA285
+#define reg_cge_idx2_12_8_pos 0
+#define reg_cge_idx2_12_8_len 5
+#define reg_cge_idx2_12_8_lsb 8
+#define xd_p_reg_cge_idx3_7_0 0xA286
+#define reg_cge_idx3_7_0_pos 0
+#define reg_cge_idx3_7_0_len 8
+#define reg_cge_idx3_7_0_lsb 0
+#define xd_p_reg_cge_idx3_12_8 0xA287
+#define reg_cge_idx3_12_8_pos 0
+#define reg_cge_idx3_12_8_len 5
+#define reg_cge_idx3_12_8_lsb 8
+#define xd_p_reg_cge_idx4_7_0 0xA288
+#define reg_cge_idx4_7_0_pos 0
+#define reg_cge_idx4_7_0_len 8
+#define reg_cge_idx4_7_0_lsb 0
+#define xd_p_reg_cge_idx4_12_8 0xA289
+#define reg_cge_idx4_12_8_pos 0
+#define reg_cge_idx4_12_8_len 5
+#define reg_cge_idx4_12_8_lsb 8
+#define xd_p_reg_cge_idx5_7_0 0xA28A
+#define reg_cge_idx5_7_0_pos 0
+#define reg_cge_idx5_7_0_len 8
+#define reg_cge_idx5_7_0_lsb 0
+#define xd_p_reg_cge_idx5_12_8 0xA28B
+#define reg_cge_idx5_12_8_pos 0
+#define reg_cge_idx5_12_8_len 5
+#define reg_cge_idx5_12_8_lsb 8
+#define xd_p_reg_cge_idx6_7_0 0xA28C
+#define reg_cge_idx6_7_0_pos 0
+#define reg_cge_idx6_7_0_len 8
+#define reg_cge_idx6_7_0_lsb 0
+#define xd_p_reg_cge_idx6_12_8 0xA28D
+#define reg_cge_idx6_12_8_pos 0
+#define reg_cge_idx6_12_8_len 5
+#define reg_cge_idx6_12_8_lsb 8
+#define xd_p_reg_cge_idx7_7_0 0xA28E
+#define reg_cge_idx7_7_0_pos 0
+#define reg_cge_idx7_7_0_len 8
+#define reg_cge_idx7_7_0_lsb 0
+#define xd_p_reg_cge_idx7_12_8 0xA28F
+#define reg_cge_idx7_12_8_pos 0
+#define reg_cge_idx7_12_8_len 5
+#define reg_cge_idx7_12_8_lsb 8
+#define xd_p_reg_cge_idx8_7_0 0xA290
+#define reg_cge_idx8_7_0_pos 0
+#define reg_cge_idx8_7_0_len 8
+#define reg_cge_idx8_7_0_lsb 0
+#define xd_p_reg_cge_idx8_12_8 0xA291
+#define reg_cge_idx8_12_8_pos 0
+#define reg_cge_idx8_12_8_len 5
+#define reg_cge_idx8_12_8_lsb 8
+#define xd_p_reg_cge_idx9_7_0 0xA292
+#define reg_cge_idx9_7_0_pos 0
+#define reg_cge_idx9_7_0_len 8
+#define reg_cge_idx9_7_0_lsb 0
+#define xd_p_reg_cge_idx9_12_8 0xA293
+#define reg_cge_idx9_12_8_pos 0
+#define reg_cge_idx9_12_8_len 5
+#define reg_cge_idx9_12_8_lsb 8
+#define xd_p_reg_cge_idx10_7_0 0xA294
+#define reg_cge_idx10_7_0_pos 0
+#define reg_cge_idx10_7_0_len 8
+#define reg_cge_idx10_7_0_lsb 0
+#define xd_p_reg_cge_idx10_12_8 0xA295
+#define reg_cge_idx10_12_8_pos 0
+#define reg_cge_idx10_12_8_len 5
+#define reg_cge_idx10_12_8_lsb 8
+#define xd_p_reg_cge_idx11_7_0 0xA296
+#define reg_cge_idx11_7_0_pos 0
+#define reg_cge_idx11_7_0_len 8
+#define reg_cge_idx11_7_0_lsb 0
+#define xd_p_reg_cge_idx11_12_8 0xA297
+#define reg_cge_idx11_12_8_pos 0
+#define reg_cge_idx11_12_8_len 5
+#define reg_cge_idx11_12_8_lsb 8
+#define xd_p_reg_cge_idx12_7_0 0xA298
+#define reg_cge_idx12_7_0_pos 0
+#define reg_cge_idx12_7_0_len 8
+#define reg_cge_idx12_7_0_lsb 0
+#define xd_p_reg_cge_idx12_12_8 0xA299
+#define reg_cge_idx12_12_8_pos 0
+#define reg_cge_idx12_12_8_len 5
+#define reg_cge_idx12_12_8_lsb 8
+#define xd_p_reg_cge_idx13_7_0 0xA29A
+#define reg_cge_idx13_7_0_pos 0
+#define reg_cge_idx13_7_0_len 8
+#define reg_cge_idx13_7_0_lsb 0
+#define xd_p_reg_cge_idx13_12_8 0xA29B
+#define reg_cge_idx13_12_8_pos 0
+#define reg_cge_idx13_12_8_len 5
+#define reg_cge_idx13_12_8_lsb 8
+#define xd_p_reg_cge_idx14_7_0 0xA29C
+#define reg_cge_idx14_7_0_pos 0
+#define reg_cge_idx14_7_0_len 8
+#define reg_cge_idx14_7_0_lsb 0
+#define xd_p_reg_cge_idx14_12_8 0xA29D
+#define reg_cge_idx14_12_8_pos 0
+#define reg_cge_idx14_12_8_len 5
+#define reg_cge_idx14_12_8_lsb 8
+#define xd_p_reg_cge_idx15_7_0 0xA29E
+#define reg_cge_idx15_7_0_pos 0
+#define reg_cge_idx15_7_0_len 8
+#define reg_cge_idx15_7_0_lsb 0
+#define xd_p_reg_cge_idx15_12_8 0xA29F
+#define reg_cge_idx15_12_8_pos 0
+#define reg_cge_idx15_12_8_len 5
+#define reg_cge_idx15_12_8_lsb 8
+#define xd_r_reg_fft_crc 0xA2A8
+#define reg_fft_crc_pos 0
+#define reg_fft_crc_len 8
+#define reg_fft_crc_lsb 0
+#define xd_p_fd_fft_shift_max 0xA2A9
+#define fd_fft_shift_max_pos 0
+#define fd_fft_shift_max_len 4
+#define fd_fft_shift_max_lsb 0
+#define xd_r_fd_fft_shift 0xA2A9
+#define fd_fft_shift_pos 4
+#define fd_fft_shift_len 4
+#define fd_fft_shift_lsb 0
+#define xd_r_fd_fft_frame_num 0xA2AA
+#define fd_fft_frame_num_pos 0
+#define fd_fft_frame_num_len 2
+#define fd_fft_frame_num_lsb 0
+#define xd_r_fd_fft_symbol_count 0xA2AB
+#define fd_fft_symbol_count_pos 0
+#define fd_fft_symbol_count_len 7
+#define fd_fft_symbol_count_lsb 0
+#define xd_r_reg_fft_idx_max_7_0 0xA2AC
+#define reg_fft_idx_max_7_0_pos 0
+#define reg_fft_idx_max_7_0_len 8
+#define reg_fft_idx_max_7_0_lsb 0
+#define xd_r_reg_fft_idx_max_12_8 0xA2AD
+#define reg_fft_idx_max_12_8_pos 0
+#define reg_fft_idx_max_12_8_len 5
+#define reg_fft_idx_max_12_8_lsb 8
+#define xd_p_reg_cge_program 0xA2AE
+#define reg_cge_program_pos 0
+#define reg_cge_program_len 1
+#define reg_cge_program_lsb 0
+#define xd_p_reg_cge_fixed 0xA2AE
+#define reg_cge_fixed_pos 1
+#define reg_cge_fixed_len 1
+#define reg_cge_fixed_lsb 0
+#define xd_p_reg_fft_rotate_en 0xA2AE
+#define reg_fft_rotate_en_pos 2
+#define reg_fft_rotate_en_len 1
+#define reg_fft_rotate_en_lsb 0
+#define xd_p_reg_fft_rotate_base_4_0 0xA2AE
+#define reg_fft_rotate_base_4_0_pos 3
+#define reg_fft_rotate_base_4_0_len 5
+#define reg_fft_rotate_base_4_0_lsb 0
+#define xd_p_reg_fft_rotate_base_12_5 0xA2AF
+#define reg_fft_rotate_base_12_5_pos 0
+#define reg_fft_rotate_base_12_5_len 8
+#define reg_fft_rotate_base_12_5_lsb 5
+#define xd_p_reg_gp_trigger_fd 0xA2B8
+#define reg_gp_trigger_fd_pos 0
+#define reg_gp_trigger_fd_len 1
+#define reg_gp_trigger_fd_lsb 0
+#define xd_p_reg_trigger_sel_fd 0xA2B8
+#define reg_trigger_sel_fd_pos 1
+#define reg_trigger_sel_fd_len 2
+#define reg_trigger_sel_fd_lsb 0
+#define xd_p_reg_trigger_module_sel_fd 0xA2B9
+#define reg_trigger_module_sel_fd_pos 0
+#define reg_trigger_module_sel_fd_len 6
+#define reg_trigger_module_sel_fd_lsb 0
+#define xd_p_reg_trigger_set_sel_fd 0xA2BA
+#define reg_trigger_set_sel_fd_pos 0
+#define reg_trigger_set_sel_fd_len 6
+#define reg_trigger_set_sel_fd_lsb 0
+#define xd_p_reg_fd_noname_7_0 0xA2BC
+#define reg_fd_noname_7_0_pos 0
+#define reg_fd_noname_7_0_len 8
+#define reg_fd_noname_7_0_lsb 0
+#define xd_p_reg_fd_noname_15_8 0xA2BD
+#define reg_fd_noname_15_8_pos 0
+#define reg_fd_noname_15_8_len 8
+#define reg_fd_noname_15_8_lsb 8
+#define xd_p_reg_fd_noname_23_16 0xA2BE
+#define reg_fd_noname_23_16_pos 0
+#define reg_fd_noname_23_16_len 8
+#define reg_fd_noname_23_16_lsb 16
+#define xd_p_reg_fd_noname_31_24 0xA2BF
+#define reg_fd_noname_31_24_pos 0
+#define reg_fd_noname_31_24_len 8
+#define reg_fd_noname_31_24_lsb 24
+#define xd_r_fd_fpcc_cp_corr_signn 0xA2C0
+#define fd_fpcc_cp_corr_signn_pos 0
+#define fd_fpcc_cp_corr_signn_len 8
+#define fd_fpcc_cp_corr_signn_lsb 0
+#define xd_p_reg_feq_s1 0xA2C1
+#define reg_feq_s1_pos 0
+#define reg_feq_s1_len 5
+#define reg_feq_s1_lsb 0
+#define xd_p_fd_fpcc_cp_corr_tone_th 0xA2C2
+#define fd_fpcc_cp_corr_tone_th_pos 0
+#define fd_fpcc_cp_corr_tone_th_len 6
+#define fd_fpcc_cp_corr_tone_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_symbol_log_th 0xA2C3
+#define fd_fpcc_cp_corr_symbol_log_th_pos 0
+#define fd_fpcc_cp_corr_symbol_log_th_len 4
+#define fd_fpcc_cp_corr_symbol_log_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_int 0xA2C4
+#define fd_fpcc_cp_corr_int_pos 0
+#define fd_fpcc_cp_corr_int_len 1
+#define fd_fpcc_cp_corr_int_lsb 0
+#define xd_p_reg_sfoe_ns_7_0 0xA320
+#define reg_sfoe_ns_7_0_pos 0
+#define reg_sfoe_ns_7_0_len 8
+#define reg_sfoe_ns_7_0_lsb 0
+#define xd_p_reg_sfoe_ns_14_8 0xA321
+#define reg_sfoe_ns_14_8_pos 0
+#define reg_sfoe_ns_14_8_len 7
+#define reg_sfoe_ns_14_8_lsb 8
+#define xd_p_reg_sfoe_c1_7_0 0xA322
+#define reg_sfoe_c1_7_0_pos 0
+#define reg_sfoe_c1_7_0_len 8
+#define reg_sfoe_c1_7_0_lsb 0
+#define xd_p_reg_sfoe_c1_15_8 0xA323
+#define reg_sfoe_c1_15_8_pos 0
+#define reg_sfoe_c1_15_8_len 8
+#define reg_sfoe_c1_15_8_lsb 8
+#define xd_p_reg_sfoe_c1_17_16 0xA324
+#define reg_sfoe_c1_17_16_pos 0
+#define reg_sfoe_c1_17_16_len 2
+#define reg_sfoe_c1_17_16_lsb 16
+#define xd_p_reg_sfoe_c2_7_0 0xA325
+#define reg_sfoe_c2_7_0_pos 0
+#define reg_sfoe_c2_7_0_len 8
+#define reg_sfoe_c2_7_0_lsb 0
+#define xd_p_reg_sfoe_c2_15_8 0xA326
+#define reg_sfoe_c2_15_8_pos 0
+#define reg_sfoe_c2_15_8_len 8
+#define reg_sfoe_c2_15_8_lsb 8
+#define xd_p_reg_sfoe_c2_17_16 0xA327
+#define reg_sfoe_c2_17_16_pos 0
+#define reg_sfoe_c2_17_16_len 2
+#define reg_sfoe_c2_17_16_lsb 16
+#define xd_r_reg_sfoe_out_9_2 0xA328
+#define reg_sfoe_out_9_2_pos 0
+#define reg_sfoe_out_9_2_len 8
+#define reg_sfoe_out_9_2_lsb 0
+#define xd_r_reg_sfoe_out_1_0 0xA329
+#define reg_sfoe_out_1_0_pos 0
+#define reg_sfoe_out_1_0_len 2
+#define reg_sfoe_out_1_0_lsb 0
+#define xd_p_reg_sfoe_lm_counter_th 0xA32A
+#define reg_sfoe_lm_counter_th_pos 0
+#define reg_sfoe_lm_counter_th_len 4
+#define reg_sfoe_lm_counter_th_lsb 0
+#define xd_p_reg_sfoe_convg_th 0xA32B
+#define reg_sfoe_convg_th_pos 0
+#define reg_sfoe_convg_th_len 8
+#define reg_sfoe_convg_th_lsb 0
+#define xd_p_reg_sfoe_divg_th 0xA32C
+#define reg_sfoe_divg_th_pos 0
+#define reg_sfoe_divg_th_len 8
+#define reg_sfoe_divg_th_lsb 0
+#define xd_p_fd_tpsd_en 0xA330
+#define fd_tpsd_en_pos 0
+#define fd_tpsd_en_len 1
+#define fd_tpsd_en_lsb 0
+#define xd_p_fd_tpsd_dis 0xA330
+#define fd_tpsd_dis_pos 1
+#define fd_tpsd_dis_len 1
+#define fd_tpsd_dis_lsb 0
+#define xd_p_fd_tpsd_rst 0xA330
+#define fd_tpsd_rst_pos 2
+#define fd_tpsd_rst_len 1
+#define fd_tpsd_rst_lsb 0
+#define xd_p_fd_tpsd_lock 0xA330
+#define fd_tpsd_lock_pos 3
+#define fd_tpsd_lock_len 1
+#define fd_tpsd_lock_lsb 0
+#define xd_r_fd_tpsd_s19 0xA330
+#define fd_tpsd_s19_pos 4
+#define fd_tpsd_s19_len 1
+#define fd_tpsd_s19_lsb 0
+#define xd_r_fd_tpsd_s17 0xA330
+#define fd_tpsd_s17_pos 5
+#define fd_tpsd_s17_len 1
+#define fd_tpsd_s17_lsb 0
+#define xd_p_fd_sfr_ste_en 0xA331
+#define fd_sfr_ste_en_pos 0
+#define fd_sfr_ste_en_len 1
+#define fd_sfr_ste_en_lsb 0
+#define xd_p_fd_sfr_ste_dis 0xA331
+#define fd_sfr_ste_dis_pos 1
+#define fd_sfr_ste_dis_len 1
+#define fd_sfr_ste_dis_lsb 0
+#define xd_p_fd_sfr_ste_rst 0xA331
+#define fd_sfr_ste_rst_pos 2
+#define fd_sfr_ste_rst_len 1
+#define fd_sfr_ste_rst_lsb 0
+#define xd_p_fd_sfr_ste_mode 0xA331
+#define fd_sfr_ste_mode_pos 3
+#define fd_sfr_ste_mode_len 1
+#define fd_sfr_ste_mode_lsb 0
+#define xd_p_fd_sfr_ste_done 0xA331
+#define fd_sfr_ste_done_pos 4
+#define fd_sfr_ste_done_len 1
+#define fd_sfr_ste_done_lsb 0
+#define xd_p_reg_cfoe_ffoe_en 0xA332
+#define reg_cfoe_ffoe_en_pos 0
+#define reg_cfoe_ffoe_en_len 1
+#define reg_cfoe_ffoe_en_lsb 0
+#define xd_p_reg_cfoe_ffoe_dis 0xA332
+#define reg_cfoe_ffoe_dis_pos 1
+#define reg_cfoe_ffoe_dis_len 1
+#define reg_cfoe_ffoe_dis_lsb 0
+#define xd_p_reg_cfoe_ffoe_rst 0xA332
+#define reg_cfoe_ffoe_rst_pos 2
+#define reg_cfoe_ffoe_rst_len 1
+#define reg_cfoe_ffoe_rst_lsb 0
+#define xd_p_reg_cfoe_ifoe_en 0xA332
+#define reg_cfoe_ifoe_en_pos 3
+#define reg_cfoe_ifoe_en_len 1
+#define reg_cfoe_ifoe_en_lsb 0
+#define xd_p_reg_cfoe_ifoe_dis 0xA332
+#define reg_cfoe_ifoe_dis_pos 4
+#define reg_cfoe_ifoe_dis_len 1
+#define reg_cfoe_ifoe_dis_lsb 0
+#define xd_p_reg_cfoe_ifoe_rst 0xA332
+#define reg_cfoe_ifoe_rst_pos 5
+#define reg_cfoe_ifoe_rst_len 1
+#define reg_cfoe_ifoe_rst_lsb 0
+#define xd_p_reg_cfoe_fot_en 0xA332
+#define reg_cfoe_fot_en_pos 6
+#define reg_cfoe_fot_en_len 1
+#define reg_cfoe_fot_en_lsb 0
+#define xd_p_reg_cfoe_fot_lm_en 0xA332
+#define reg_cfoe_fot_lm_en_pos 7
+#define reg_cfoe_fot_lm_en_len 1
+#define reg_cfoe_fot_lm_en_lsb 0
+#define xd_p_reg_cfoe_fot_rst 0xA333
+#define reg_cfoe_fot_rst_pos 0
+#define reg_cfoe_fot_rst_len 1
+#define reg_cfoe_fot_rst_lsb 0
+#define xd_r_fd_cfoe_ffoe_done 0xA333
+#define fd_cfoe_ffoe_done_pos 1
+#define fd_cfoe_ffoe_done_len 1
+#define fd_cfoe_ffoe_done_lsb 0
+#define xd_p_fd_cfoe_metric_vld 0xA333
+#define fd_cfoe_metric_vld_pos 2
+#define fd_cfoe_metric_vld_len 1
+#define fd_cfoe_metric_vld_lsb 0
+#define xd_p_reg_cfoe_ifod_vld 0xA333
+#define reg_cfoe_ifod_vld_pos 3
+#define reg_cfoe_ifod_vld_len 1
+#define reg_cfoe_ifod_vld_lsb 0
+#define xd_r_fd_cfoe_ifoe_done 0xA333
+#define fd_cfoe_ifoe_done_pos 4
+#define fd_cfoe_ifoe_done_len 1
+#define fd_cfoe_ifoe_done_lsb 0
+#define xd_r_fd_cfoe_fot_valid 0xA333
+#define fd_cfoe_fot_valid_pos 5
+#define fd_cfoe_fot_valid_len 1
+#define fd_cfoe_fot_valid_lsb 0
+#define xd_p_reg_cfoe_divg_int 0xA333
+#define reg_cfoe_divg_int_pos 6
+#define reg_cfoe_divg_int_len 1
+#define reg_cfoe_divg_int_lsb 0
+#define xd_r_reg_cfoe_divg_flag 0xA333
+#define reg_cfoe_divg_flag_pos 7
+#define reg_cfoe_divg_flag_len 1
+#define reg_cfoe_divg_flag_lsb 0
+#define xd_p_reg_sfoe_en 0xA334
+#define reg_sfoe_en_pos 0
+#define reg_sfoe_en_len 1
+#define reg_sfoe_en_lsb 0
+#define xd_p_reg_sfoe_dis 0xA334
+#define reg_sfoe_dis_pos 1
+#define reg_sfoe_dis_len 1
+#define reg_sfoe_dis_lsb 0
+#define xd_p_reg_sfoe_rst 0xA334
+#define reg_sfoe_rst_pos 2
+#define reg_sfoe_rst_len 1
+#define reg_sfoe_rst_lsb 0
+#define xd_p_reg_sfoe_vld_int 0xA334
+#define reg_sfoe_vld_int_pos 3
+#define reg_sfoe_vld_int_len 1
+#define reg_sfoe_vld_int_lsb 0
+#define xd_p_reg_sfoe_lm_en 0xA334
+#define reg_sfoe_lm_en_pos 4
+#define reg_sfoe_lm_en_len 1
+#define reg_sfoe_lm_en_lsb 0
+#define xd_p_reg_sfoe_divg_int 0xA334
+#define reg_sfoe_divg_int_pos 5
+#define reg_sfoe_divg_int_len 1
+#define reg_sfoe_divg_int_lsb 0
+#define xd_r_reg_sfoe_divg_flag 0xA334
+#define reg_sfoe_divg_flag_pos 6
+#define reg_sfoe_divg_flag_len 1
+#define reg_sfoe_divg_flag_lsb 0
+#define xd_p_reg_fft_rst 0xA335
+#define reg_fft_rst_pos 0
+#define reg_fft_rst_len 1
+#define reg_fft_rst_lsb 0
+#define xd_p_reg_fft_fast_beacon 0xA335
+#define reg_fft_fast_beacon_pos 1
+#define reg_fft_fast_beacon_len 1
+#define reg_fft_fast_beacon_lsb 0
+#define xd_p_reg_fft_fast_valid 0xA335
+#define reg_fft_fast_valid_pos 2
+#define reg_fft_fast_valid_len 1
+#define reg_fft_fast_valid_lsb 0
+#define xd_p_reg_fft_mask_en 0xA335
+#define reg_fft_mask_en_pos 3
+#define reg_fft_mask_en_len 1
+#define reg_fft_mask_en_lsb 0
+#define xd_p_reg_fft_crc_en 0xA335
+#define reg_fft_crc_en_pos 4
+#define reg_fft_crc_en_len 1
+#define reg_fft_crc_en_lsb 0
+#define xd_p_reg_finr_en 0xA336
+#define reg_finr_en_pos 0
+#define reg_finr_en_len 1
+#define reg_finr_en_lsb 0
+#define xd_p_fd_fste_en 0xA337
+#define fd_fste_en_pos 1
+#define fd_fste_en_len 1
+#define fd_fste_en_lsb 0
+#define xd_p_fd_sqi_tps_level_shift 0xA338
+#define fd_sqi_tps_level_shift_pos 0
+#define fd_sqi_tps_level_shift_len 8
+#define fd_sqi_tps_level_shift_lsb 0
+#define xd_p_fd_pilot_ma_len 0xA339
+#define fd_pilot_ma_len_pos 0
+#define fd_pilot_ma_len_len 6
+#define fd_pilot_ma_len_lsb 0
+#define xd_p_fd_tps_ma_len 0xA33A
+#define fd_tps_ma_len_pos 0
+#define fd_tps_ma_len_len 6
+#define fd_tps_ma_len_lsb 0
+#define xd_p_fd_sqi_s3 0xA33B
+#define fd_sqi_s3_pos 0
+#define fd_sqi_s3_len 8
+#define fd_sqi_s3_lsb 0
+#define xd_p_fd_sqi_dummy_reg_0 0xA33C
+#define fd_sqi_dummy_reg_0_pos 0
+#define fd_sqi_dummy_reg_0_len 1
+#define fd_sqi_dummy_reg_0_lsb 0
+#define xd_p_fd_sqi_debug_sel 0xA33C
+#define fd_sqi_debug_sel_pos 1
+#define fd_sqi_debug_sel_len 2
+#define fd_sqi_debug_sel_lsb 0
+#define xd_p_fd_sqi_s2 0xA33C
+#define fd_sqi_s2_pos 3
+#define fd_sqi_s2_len 5
+#define fd_sqi_s2_lsb 0
+#define xd_p_fd_sqi_dummy_reg_1 0xA33D
+#define fd_sqi_dummy_reg_1_pos 0
+#define fd_sqi_dummy_reg_1_len 1
+#define fd_sqi_dummy_reg_1_lsb 0
+#define xd_p_fd_inr_ignore 0xA33D
+#define fd_inr_ignore_pos 1
+#define fd_inr_ignore_len 1
+#define fd_inr_ignore_lsb 0
+#define xd_p_fd_pilot_ignore 0xA33D
+#define fd_pilot_ignore_pos 2
+#define fd_pilot_ignore_len 1
+#define fd_pilot_ignore_lsb 0
+#define xd_p_fd_etps_ignore 0xA33D
+#define fd_etps_ignore_pos 3
+#define fd_etps_ignore_len 1
+#define fd_etps_ignore_lsb 0
+#define xd_p_fd_sqi_s1 0xA33D
+#define fd_sqi_s1_pos 4
+#define fd_sqi_s1_len 4
+#define fd_sqi_s1_lsb 0
+#define xd_p_reg_fste_ehw_7_0 0xA33E
+#define reg_fste_ehw_7_0_pos 0
+#define reg_fste_ehw_7_0_len 8
+#define reg_fste_ehw_7_0_lsb 0
+#define xd_p_reg_fste_ehw_9_8 0xA33F
+#define reg_fste_ehw_9_8_pos 0
+#define reg_fste_ehw_9_8_len 2
+#define reg_fste_ehw_9_8_lsb 8
+#define xd_p_reg_fste_i_adj_vld 0xA33F
+#define reg_fste_i_adj_vld_pos 2
+#define reg_fste_i_adj_vld_len 1
+#define reg_fste_i_adj_vld_lsb 0
+#define xd_p_reg_fste_phase_ini_7_0 0xA340
+#define reg_fste_phase_ini_7_0_pos 0
+#define reg_fste_phase_ini_7_0_len 8
+#define reg_fste_phase_ini_7_0_lsb 0
+#define xd_p_reg_fste_phase_ini_11_8 0xA341
+#define reg_fste_phase_ini_11_8_pos 0
+#define reg_fste_phase_ini_11_8_len 4
+#define reg_fste_phase_ini_11_8_lsb 8
+#define xd_p_reg_fste_phase_inc_3_0 0xA341
+#define reg_fste_phase_inc_3_0_pos 4
+#define reg_fste_phase_inc_3_0_len 4
+#define reg_fste_phase_inc_3_0_lsb 0
+#define xd_p_reg_fste_phase_inc_11_4 0xA342
+#define reg_fste_phase_inc_11_4_pos 0
+#define reg_fste_phase_inc_11_4_len 8
+#define reg_fste_phase_inc_11_4_lsb 4
+#define xd_p_reg_fste_acum_cost_cnt_max 0xA343
+#define reg_fste_acum_cost_cnt_max_pos 0
+#define reg_fste_acum_cost_cnt_max_len 4
+#define reg_fste_acum_cost_cnt_max_lsb 0
+#define xd_p_reg_fste_step_size_std 0xA343
+#define reg_fste_step_size_std_pos 4
+#define reg_fste_step_size_std_len 4
+#define reg_fste_step_size_std_lsb 0
+#define xd_p_reg_fste_step_size_max 0xA344
+#define reg_fste_step_size_max_pos 0
+#define reg_fste_step_size_max_len 4
+#define reg_fste_step_size_max_lsb 0
+#define xd_p_reg_fste_step_size_min 0xA344
+#define reg_fste_step_size_min_pos 4
+#define reg_fste_step_size_min_len 4
+#define reg_fste_step_size_min_lsb 0
+#define xd_p_reg_fste_frac_step_size_7_0 0xA345
+#define reg_fste_frac_step_size_7_0_pos 0
+#define reg_fste_frac_step_size_7_0_len 8
+#define reg_fste_frac_step_size_7_0_lsb 0
+#define xd_p_reg_fste_frac_step_size_15_8 0xA346
+#define reg_fste_frac_step_size_15_8_pos 0
+#define reg_fste_frac_step_size_15_8_len 8
+#define reg_fste_frac_step_size_15_8_lsb 8
+#define xd_p_reg_fste_frac_step_size_19_16 0xA347
+#define reg_fste_frac_step_size_19_16_pos 0
+#define reg_fste_frac_step_size_19_16_len 4
+#define reg_fste_frac_step_size_19_16_lsb 16
+#define xd_p_reg_fste_rpd_dir_cnt_max 0xA347
+#define reg_fste_rpd_dir_cnt_max_pos 4
+#define reg_fste_rpd_dir_cnt_max_len 4
+#define reg_fste_rpd_dir_cnt_max_lsb 0
+#define xd_p_reg_fste_ehs 0xA348
+#define reg_fste_ehs_pos 0
+#define reg_fste_ehs_len 4
+#define reg_fste_ehs_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_3_0 0xA348
+#define reg_fste_frac_cost_cnt_max_3_0_pos 4
+#define reg_fste_frac_cost_cnt_max_3_0_len 4
+#define reg_fste_frac_cost_cnt_max_3_0_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_9_4 0xA349
+#define reg_fste_frac_cost_cnt_max_9_4_pos 0
+#define reg_fste_frac_cost_cnt_max_9_4_len 6
+#define reg_fste_frac_cost_cnt_max_9_4_lsb 4
+#define xd_p_reg_fste_w0_7_0 0xA34A
+#define reg_fste_w0_7_0_pos 0
+#define reg_fste_w0_7_0_len 8
+#define reg_fste_w0_7_0_lsb 0
+#define xd_p_reg_fste_w0_11_8 0xA34B
+#define reg_fste_w0_11_8_pos 0
+#define reg_fste_w0_11_8_len 4
+#define reg_fste_w0_11_8_lsb 8
+#define xd_p_reg_fste_w1_3_0 0xA34B
+#define reg_fste_w1_3_0_pos 4
+#define reg_fste_w1_3_0_len 4
+#define reg_fste_w1_3_0_lsb 0
+#define xd_p_reg_fste_w1_11_4 0xA34C
+#define reg_fste_w1_11_4_pos 0
+#define reg_fste_w1_11_4_len 8
+#define reg_fste_w1_11_4_lsb 4
+#define xd_p_reg_fste_w2_7_0 0xA34D
+#define reg_fste_w2_7_0_pos 0
+#define reg_fste_w2_7_0_len 8
+#define reg_fste_w2_7_0_lsb 0
+#define xd_p_reg_fste_w2_11_8 0xA34E
+#define reg_fste_w2_11_8_pos 0
+#define reg_fste_w2_11_8_len 4
+#define reg_fste_w2_11_8_lsb 8
+#define xd_p_reg_fste_w3_3_0 0xA34E
+#define reg_fste_w3_3_0_pos 4
+#define reg_fste_w3_3_0_len 4
+#define reg_fste_w3_3_0_lsb 0
+#define xd_p_reg_fste_w3_11_4 0xA34F
+#define reg_fste_w3_11_4_pos 0
+#define reg_fste_w3_11_4_len 8
+#define reg_fste_w3_11_4_lsb 4
+#define xd_p_reg_fste_w4_7_0 0xA350
+#define reg_fste_w4_7_0_pos 0
+#define reg_fste_w4_7_0_len 8
+#define reg_fste_w4_7_0_lsb 0
+#define xd_p_reg_fste_w4_11_8 0xA351
+#define reg_fste_w4_11_8_pos 0
+#define reg_fste_w4_11_8_len 4
+#define reg_fste_w4_11_8_lsb 8
+#define xd_p_reg_fste_w5_3_0 0xA351
+#define reg_fste_w5_3_0_pos 4
+#define reg_fste_w5_3_0_len 4
+#define reg_fste_w5_3_0_lsb 0
+#define xd_p_reg_fste_w5_11_4 0xA352
+#define reg_fste_w5_11_4_pos 0
+#define reg_fste_w5_11_4_len 8
+#define reg_fste_w5_11_4_lsb 4
+#define xd_p_reg_fste_w6_7_0 0xA353
+#define reg_fste_w6_7_0_pos 0
+#define reg_fste_w6_7_0_len 8
+#define reg_fste_w6_7_0_lsb 0
+#define xd_p_reg_fste_w6_11_8 0xA354
+#define reg_fste_w6_11_8_pos 0
+#define reg_fste_w6_11_8_len 4
+#define reg_fste_w6_11_8_lsb 8
+#define xd_p_reg_fste_w7_3_0 0xA354
+#define reg_fste_w7_3_0_pos 4
+#define reg_fste_w7_3_0_len 4
+#define reg_fste_w7_3_0_lsb 0
+#define xd_p_reg_fste_w7_11_4 0xA355
+#define reg_fste_w7_11_4_pos 0
+#define reg_fste_w7_11_4_len 8
+#define reg_fste_w7_11_4_lsb 4
+#define xd_p_reg_fste_w8_7_0 0xA356
+#define reg_fste_w8_7_0_pos 0
+#define reg_fste_w8_7_0_len 8
+#define reg_fste_w8_7_0_lsb 0
+#define xd_p_reg_fste_w8_11_8 0xA357
+#define reg_fste_w8_11_8_pos 0
+#define reg_fste_w8_11_8_len 4
+#define reg_fste_w8_11_8_lsb 8
+#define xd_p_reg_fste_w9_3_0 0xA357
+#define reg_fste_w9_3_0_pos 4
+#define reg_fste_w9_3_0_len 4
+#define reg_fste_w9_3_0_lsb 0
+#define xd_p_reg_fste_w9_11_4 0xA358
+#define reg_fste_w9_11_4_pos 0
+#define reg_fste_w9_11_4_len 8
+#define reg_fste_w9_11_4_lsb 4
+#define xd_p_reg_fste_wa_7_0 0xA359
+#define reg_fste_wa_7_0_pos 0
+#define reg_fste_wa_7_0_len 8
+#define reg_fste_wa_7_0_lsb 0
+#define xd_p_reg_fste_wa_11_8 0xA35A
+#define reg_fste_wa_11_8_pos 0
+#define reg_fste_wa_11_8_len 4
+#define reg_fste_wa_11_8_lsb 8
+#define xd_p_reg_fste_wb_3_0 0xA35A
+#define reg_fste_wb_3_0_pos 4
+#define reg_fste_wb_3_0_len 4
+#define reg_fste_wb_3_0_lsb 0
+#define xd_p_reg_fste_wb_11_4 0xA35B
+#define reg_fste_wb_11_4_pos 0
+#define reg_fste_wb_11_4_len 8
+#define reg_fste_wb_11_4_lsb 4
+#define xd_r_fd_fste_i_adj 0xA35C
+#define fd_fste_i_adj_pos 0
+#define fd_fste_i_adj_len 5
+#define fd_fste_i_adj_lsb 0
+#define xd_r_fd_fste_f_adj_7_0 0xA35D
+#define fd_fste_f_adj_7_0_pos 0
+#define fd_fste_f_adj_7_0_len 8
+#define fd_fste_f_adj_7_0_lsb 0
+#define xd_r_fd_fste_f_adj_15_8 0xA35E
+#define fd_fste_f_adj_15_8_pos 0
+#define fd_fste_f_adj_15_8_len 8
+#define fd_fste_f_adj_15_8_lsb 8
+#define xd_r_fd_fste_f_adj_19_16 0xA35F
+#define fd_fste_f_adj_19_16_pos 0
+#define fd_fste_f_adj_19_16_len 4
+#define fd_fste_f_adj_19_16_lsb 16
+#define xd_p_reg_feq_Leak_Bypass 0xA366
+#define reg_feq_Leak_Bypass_pos 0
+#define reg_feq_Leak_Bypass_len 1
+#define reg_feq_Leak_Bypass_lsb 0
+#define xd_p_reg_feq_Leak_Mneg1 0xA366
+#define reg_feq_Leak_Mneg1_pos 1
+#define reg_feq_Leak_Mneg1_len 3
+#define reg_feq_Leak_Mneg1_lsb 0
+#define xd_p_reg_feq_Leak_B_ShiftQ 0xA366
+#define reg_feq_Leak_B_ShiftQ_pos 4
+#define reg_feq_Leak_B_ShiftQ_len 4
+#define reg_feq_Leak_B_ShiftQ_lsb 0
+#define xd_p_reg_feq_Leak_B_Float0 0xA367
+#define reg_feq_Leak_B_Float0_pos 0
+#define reg_feq_Leak_B_Float0_len 8
+#define reg_feq_Leak_B_Float0_lsb 0
+#define xd_p_reg_feq_Leak_B_Float1 0xA368
+#define reg_feq_Leak_B_Float1_pos 0
+#define reg_feq_Leak_B_Float1_len 8
+#define reg_feq_Leak_B_Float1_lsb 0
+#define xd_p_reg_feq_Leak_B_Float2 0xA369
+#define reg_feq_Leak_B_Float2_pos 0
+#define reg_feq_Leak_B_Float2_len 8
+#define reg_feq_Leak_B_Float2_lsb 0
+#define xd_p_reg_feq_Leak_B_Float3 0xA36A
+#define reg_feq_Leak_B_Float3_pos 0
+#define reg_feq_Leak_B_Float3_len 8
+#define reg_feq_Leak_B_Float3_lsb 0
+#define xd_p_reg_feq_Leak_B_Float4 0xA36B
+#define reg_feq_Leak_B_Float4_pos 0
+#define reg_feq_Leak_B_Float4_len 8
+#define reg_feq_Leak_B_Float4_lsb 0
+#define xd_p_reg_feq_Leak_B_Float5 0xA36C
+#define reg_feq_Leak_B_Float5_pos 0
+#define reg_feq_Leak_B_Float5_len 8
+#define reg_feq_Leak_B_Float5_lsb 0
+#define xd_p_reg_feq_Leak_B_Float6 0xA36D
+#define reg_feq_Leak_B_Float6_pos 0
+#define reg_feq_Leak_B_Float6_len 8
+#define reg_feq_Leak_B_Float6_lsb 0
+#define xd_p_reg_feq_Leak_B_Float7 0xA36E
+#define reg_feq_Leak_B_Float7_pos 0
+#define reg_feq_Leak_B_Float7_len 8
+#define reg_feq_Leak_B_Float7_lsb 0
+#define xd_r_reg_feq_data_h2_7_0 0xA36F
+#define reg_feq_data_h2_7_0_pos 0
+#define reg_feq_data_h2_7_0_len 8
+#define reg_feq_data_h2_7_0_lsb 0
+#define xd_r_reg_feq_data_h2_9_8 0xA370
+#define reg_feq_data_h2_9_8_pos 0
+#define reg_feq_data_h2_9_8_len 2
+#define reg_feq_data_h2_9_8_lsb 8
+#define xd_p_reg_feq_leak_use_slice_tps 0xA371
+#define reg_feq_leak_use_slice_tps_pos 0
+#define reg_feq_leak_use_slice_tps_len 1
+#define reg_feq_leak_use_slice_tps_lsb 0
+#define xd_p_reg_feq_read_update 0xA371
+#define reg_feq_read_update_pos 1
+#define reg_feq_read_update_len 1
+#define reg_feq_read_update_lsb 0
+#define xd_p_reg_feq_data_vld 0xA371
+#define reg_feq_data_vld_pos 2
+#define reg_feq_data_vld_len 1
+#define reg_feq_data_vld_lsb 0
+#define xd_p_reg_feq_tone_idx_4_0 0xA371
+#define reg_feq_tone_idx_4_0_pos 3
+#define reg_feq_tone_idx_4_0_len 5
+#define reg_feq_tone_idx_4_0_lsb 0
+#define xd_p_reg_feq_tone_idx_12_5 0xA372
+#define reg_feq_tone_idx_12_5_pos 0
+#define reg_feq_tone_idx_12_5_len 8
+#define reg_feq_tone_idx_12_5_lsb 5
+#define xd_r_reg_feq_data_re_7_0 0xA373
+#define reg_feq_data_re_7_0_pos 0
+#define reg_feq_data_re_7_0_len 8
+#define reg_feq_data_re_7_0_lsb 0
+#define xd_r_reg_feq_data_re_10_8 0xA374
+#define reg_feq_data_re_10_8_pos 0
+#define reg_feq_data_re_10_8_len 3
+#define reg_feq_data_re_10_8_lsb 8
+#define xd_r_reg_feq_data_im_7_0 0xA375
+#define reg_feq_data_im_7_0_pos 0
+#define reg_feq_data_im_7_0_len 8
+#define reg_feq_data_im_7_0_lsb 0
+#define xd_r_reg_feq_data_im_10_8 0xA376
+#define reg_feq_data_im_10_8_pos 0
+#define reg_feq_data_im_10_8_len 3
+#define reg_feq_data_im_10_8_lsb 8
+#define xd_r_reg_feq_y_re 0xA377
+#define reg_feq_y_re_pos 0
+#define reg_feq_y_re_len 8
+#define reg_feq_y_re_lsb 0
+#define xd_r_reg_feq_y_im 0xA378
+#define reg_feq_y_im_pos 0
+#define reg_feq_y_im_len 8
+#define reg_feq_y_im_lsb 0
+#define xd_r_reg_feq_h_re_7_0 0xA379
+#define reg_feq_h_re_7_0_pos 0
+#define reg_feq_h_re_7_0_len 8
+#define reg_feq_h_re_7_0_lsb 0
+#define xd_r_reg_feq_h_re_8 0xA37A
+#define reg_feq_h_re_8_pos 0
+#define reg_feq_h_re_8_len 1
+#define reg_feq_h_re_8_lsb 0
+#define xd_r_reg_feq_h_im_7_0 0xA37B
+#define reg_feq_h_im_7_0_pos 0
+#define reg_feq_h_im_7_0_len 8
+#define reg_feq_h_im_7_0_lsb 0
+#define xd_r_reg_feq_h_im_8 0xA37C
+#define reg_feq_h_im_8_pos 0
+#define reg_feq_h_im_8_len 1
+#define reg_feq_h_im_8_lsb 0
+#define xd_p_fec_super_frm_unit_7_0 0xA380
+#define fec_super_frm_unit_7_0_pos 0
+#define fec_super_frm_unit_7_0_len 8
+#define fec_super_frm_unit_7_0_lsb 0
+#define xd_p_fec_super_frm_unit_15_8 0xA381
+#define fec_super_frm_unit_15_8_pos 0
+#define fec_super_frm_unit_15_8_len 8
+#define fec_super_frm_unit_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_7_0 0xA382
+#define fec_vtb_err_bit_cnt_7_0_pos 0
+#define fec_vtb_err_bit_cnt_7_0_len 8
+#define fec_vtb_err_bit_cnt_7_0_lsb 0
+#define xd_r_fec_vtb_err_bit_cnt_15_8 0xA383
+#define fec_vtb_err_bit_cnt_15_8_pos 0
+#define fec_vtb_err_bit_cnt_15_8_len 8
+#define fec_vtb_err_bit_cnt_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_23_16 0xA384
+#define fec_vtb_err_bit_cnt_23_16_pos 0
+#define fec_vtb_err_bit_cnt_23_16_len 8
+#define fec_vtb_err_bit_cnt_23_16_lsb 16
+#define xd_p_fec_rsd_packet_unit_7_0 0xA385
+#define fec_rsd_packet_unit_7_0_pos 0
+#define fec_rsd_packet_unit_7_0_len 8
+#define fec_rsd_packet_unit_7_0_lsb 0
+#define xd_p_fec_rsd_packet_unit_15_8 0xA386
+#define fec_rsd_packet_unit_15_8_pos 0
+#define fec_rsd_packet_unit_15_8_len 8
+#define fec_rsd_packet_unit_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_7_0 0xA387
+#define fec_rsd_bit_err_cnt_7_0_pos 0
+#define fec_rsd_bit_err_cnt_7_0_len 8
+#define fec_rsd_bit_err_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_bit_err_cnt_15_8 0xA388
+#define fec_rsd_bit_err_cnt_15_8_pos 0
+#define fec_rsd_bit_err_cnt_15_8_len 8
+#define fec_rsd_bit_err_cnt_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_23_16 0xA389
+#define fec_rsd_bit_err_cnt_23_16_pos 0
+#define fec_rsd_bit_err_cnt_23_16_len 8
+#define fec_rsd_bit_err_cnt_23_16_lsb 16
+#define xd_r_fec_rsd_abort_packet_cnt_7_0 0xA38A
+#define fec_rsd_abort_packet_cnt_7_0_pos 0
+#define fec_rsd_abort_packet_cnt_7_0_len 8
+#define fec_rsd_abort_packet_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_abort_packet_cnt_15_8 0xA38B
+#define fec_rsd_abort_packet_cnt_15_8_pos 0
+#define fec_rsd_abort_packet_cnt_15_8_len 8
+#define fec_rsd_abort_packet_cnt_15_8_lsb 8
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0 0xA38C
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
+#define fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8 0xA38D
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
+#define fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
+#define xd_p_fec_RS_TH_1_7_0 0xA38E
+#define fec_RS_TH_1_7_0_pos 0
+#define fec_RS_TH_1_7_0_len 8
+#define fec_RS_TH_1_7_0_lsb 0
+#define xd_p_fec_RS_TH_1_15_8 0xA38F
+#define fec_RS_TH_1_15_8_pos 0
+#define fec_RS_TH_1_15_8_len 8
+#define fec_RS_TH_1_15_8_lsb 8
+#define xd_p_fec_RS_TH_2 0xA390
+#define fec_RS_TH_2_pos 0
+#define fec_RS_TH_2_len 8
+#define fec_RS_TH_2_lsb 0
+#define xd_p_fec_mon_en 0xA391
+#define fec_mon_en_pos 0
+#define fec_mon_en_len 1
+#define fec_mon_en_lsb 0
+#define xd_p_reg_b8to47 0xA391
+#define reg_b8to47_pos 1
+#define reg_b8to47_len 1
+#define reg_b8to47_lsb 0
+#define xd_p_reg_rsd_sync_rep 0xA391
+#define reg_rsd_sync_rep_pos 2
+#define reg_rsd_sync_rep_len 1
+#define reg_rsd_sync_rep_lsb 0
+#define xd_p_fec_rsd_retrain_rst 0xA391
+#define fec_rsd_retrain_rst_pos 3
+#define fec_rsd_retrain_rst_len 1
+#define fec_rsd_retrain_rst_lsb 0
+#define xd_r_fec_rsd_ber_rdy 0xA391
+#define fec_rsd_ber_rdy_pos 4
+#define fec_rsd_ber_rdy_len 1
+#define fec_rsd_ber_rdy_lsb 0
+#define xd_p_fec_rsd_ber_rst 0xA391
+#define fec_rsd_ber_rst_pos 5
+#define fec_rsd_ber_rst_len 1
+#define fec_rsd_ber_rst_lsb 0
+#define xd_r_fec_vtb_ber_rdy 0xA391
+#define fec_vtb_ber_rdy_pos 6
+#define fec_vtb_ber_rdy_len 1
+#define fec_vtb_ber_rdy_lsb 0
+#define xd_p_fec_vtb_ber_rst 0xA391
+#define fec_vtb_ber_rst_pos 7
+#define fec_vtb_ber_rst_len 1
+#define fec_vtb_ber_rst_lsb 0
+#define xd_p_reg_vtb_clk40en 0xA392
+#define reg_vtb_clk40en_pos 0
+#define reg_vtb_clk40en_len 1
+#define reg_vtb_clk40en_lsb 0
+#define xd_p_fec_vtb_rsd_mon_en 0xA392
+#define fec_vtb_rsd_mon_en_pos 1
+#define fec_vtb_rsd_mon_en_len 1
+#define fec_vtb_rsd_mon_en_lsb 0
+#define xd_p_reg_fec_data_en 0xA392
+#define reg_fec_data_en_pos 2
+#define reg_fec_data_en_len 1
+#define reg_fec_data_en_lsb 0
+#define xd_p_fec_dummy_reg_2 0xA392
+#define fec_dummy_reg_2_pos 3
+#define fec_dummy_reg_2_len 3
+#define fec_dummy_reg_2_lsb 0
+#define xd_p_reg_sync_chk 0xA392
+#define reg_sync_chk_pos 6
+#define reg_sync_chk_len 1
+#define reg_sync_chk_lsb 0
+#define xd_p_fec_rsd_bypass 0xA392
+#define fec_rsd_bypass_pos 7
+#define fec_rsd_bypass_len 1
+#define fec_rsd_bypass_lsb 0
+#define xd_p_fec_sw_rst 0xA393
+#define fec_sw_rst_pos 0
+#define fec_sw_rst_len 1
+#define fec_sw_rst_lsb 0
+#define xd_r_fec_vtb_pm_crc 0xA394
+#define fec_vtb_pm_crc_pos 0
+#define fec_vtb_pm_crc_len 8
+#define fec_vtb_pm_crc_lsb 0
+#define xd_r_fec_vtb_tb_7_crc 0xA395
+#define fec_vtb_tb_7_crc_pos 0
+#define fec_vtb_tb_7_crc_len 8
+#define fec_vtb_tb_7_crc_lsb 0
+#define xd_r_fec_vtb_tb_6_crc 0xA396
+#define fec_vtb_tb_6_crc_pos 0
+#define fec_vtb_tb_6_crc_len 8
+#define fec_vtb_tb_6_crc_lsb 0
+#define xd_r_fec_vtb_tb_5_crc 0xA397
+#define fec_vtb_tb_5_crc_pos 0
+#define fec_vtb_tb_5_crc_len 8
+#define fec_vtb_tb_5_crc_lsb 0
+#define xd_r_fec_vtb_tb_4_crc 0xA398
+#define fec_vtb_tb_4_crc_pos 0
+#define fec_vtb_tb_4_crc_len 8
+#define fec_vtb_tb_4_crc_lsb 0
+#define xd_r_fec_vtb_tb_3_crc 0xA399
+#define fec_vtb_tb_3_crc_pos 0
+#define fec_vtb_tb_3_crc_len 8
+#define fec_vtb_tb_3_crc_lsb 0
+#define xd_r_fec_vtb_tb_2_crc 0xA39A
+#define fec_vtb_tb_2_crc_pos 0
+#define fec_vtb_tb_2_crc_len 8
+#define fec_vtb_tb_2_crc_lsb 0
+#define xd_r_fec_vtb_tb_1_crc 0xA39B
+#define fec_vtb_tb_1_crc_pos 0
+#define fec_vtb_tb_1_crc_len 8
+#define fec_vtb_tb_1_crc_lsb 0
+#define xd_r_fec_vtb_tb_0_crc 0xA39C
+#define fec_vtb_tb_0_crc_pos 0
+#define fec_vtb_tb_0_crc_len 8
+#define fec_vtb_tb_0_crc_lsb 0
+#define xd_r_fec_rsd_bank0_crc 0xA39D
+#define fec_rsd_bank0_crc_pos 0
+#define fec_rsd_bank0_crc_len 8
+#define fec_rsd_bank0_crc_lsb 0
+#define xd_r_fec_rsd_bank1_crc 0xA39E
+#define fec_rsd_bank1_crc_pos 0
+#define fec_rsd_bank1_crc_len 8
+#define fec_rsd_bank1_crc_lsb 0
+#define xd_r_fec_idi_vtb_crc 0xA39F
+#define fec_idi_vtb_crc_pos 0
+#define fec_idi_vtb_crc_len 8
+#define fec_idi_vtb_crc_lsb 0
+#define xd_g_reg_tpsd_txmod 0xA3C0
+#define reg_tpsd_txmod_pos 0
+#define reg_tpsd_txmod_len 2
+#define reg_tpsd_txmod_lsb 0
+#define xd_g_reg_tpsd_gi 0xA3C0
+#define reg_tpsd_gi_pos 2
+#define reg_tpsd_gi_len 2
+#define reg_tpsd_gi_lsb 0
+#define xd_g_reg_tpsd_hier 0xA3C0
+#define reg_tpsd_hier_pos 4
+#define reg_tpsd_hier_len 3
+#define reg_tpsd_hier_lsb 0
+#define xd_g_reg_bw 0xA3C1
+#define reg_bw_pos 2
+#define reg_bw_len 2
+#define reg_bw_lsb 0
+#define xd_g_reg_dec_pri 0xA3C1
+#define reg_dec_pri_pos 4
+#define reg_dec_pri_len 1
+#define reg_dec_pri_lsb 0
+#define xd_g_reg_tpsd_const 0xA3C1
+#define reg_tpsd_const_pos 6
+#define reg_tpsd_const_len 2
+#define reg_tpsd_const_lsb 0
+#define xd_g_reg_tpsd_hpcr 0xA3C2
+#define reg_tpsd_hpcr_pos 0
+#define reg_tpsd_hpcr_len 3
+#define reg_tpsd_hpcr_lsb 0
+#define xd_g_reg_tpsd_lpcr 0xA3C2
+#define reg_tpsd_lpcr_pos 3
+#define reg_tpsd_lpcr_len 3
+#define reg_tpsd_lpcr_lsb 0
+#define xd_g_reg_ofsm_clk 0xA3D0
+#define reg_ofsm_clk_pos 0
+#define reg_ofsm_clk_len 3
+#define reg_ofsm_clk_lsb 0
+#define xd_g_reg_fclk_cfg 0xA3D1
+#define reg_fclk_cfg_pos 0
+#define reg_fclk_cfg_len 1
+#define reg_fclk_cfg_lsb 0
+#define xd_g_reg_fclk_idi 0xA3D1
+#define reg_fclk_idi_pos 1
+#define reg_fclk_idi_len 1
+#define reg_fclk_idi_lsb 0
+#define xd_g_reg_fclk_odi 0xA3D1
+#define reg_fclk_odi_pos 2
+#define reg_fclk_odi_len 1
+#define reg_fclk_odi_lsb 0
+#define xd_g_reg_fclk_rsd 0xA3D1
+#define reg_fclk_rsd_pos 3
+#define reg_fclk_rsd_len 1
+#define reg_fclk_rsd_lsb 0
+#define xd_g_reg_fclk_vtb 0xA3D1
+#define reg_fclk_vtb_pos 4
+#define reg_fclk_vtb_len 1
+#define reg_fclk_vtb_lsb 0
+#define xd_g_reg_fclk_cste 0xA3D1
+#define reg_fclk_cste_pos 5
+#define reg_fclk_cste_len 1
+#define reg_fclk_cste_lsb 0
+#define xd_g_reg_fclk_mp2if 0xA3D1
+#define reg_fclk_mp2if_pos 6
+#define reg_fclk_mp2if_len 1
+#define reg_fclk_mp2if_lsb 0
+#define xd_I2C_i2c_m_slave_addr 0xA400
+#define i2c_m_slave_addr_pos 0
+#define i2c_m_slave_addr_len 8
+#define i2c_m_slave_addr_lsb 0
+#define xd_I2C_i2c_m_data1 0xA401
+#define i2c_m_data1_pos 0
+#define i2c_m_data1_len 8
+#define i2c_m_data1_lsb 0
+#define xd_I2C_i2c_m_data2 0xA402
+#define i2c_m_data2_pos 0
+#define i2c_m_data2_len 8
+#define i2c_m_data2_lsb 0
+#define xd_I2C_i2c_m_data3 0xA403
+#define i2c_m_data3_pos 0
+#define i2c_m_data3_len 8
+#define i2c_m_data3_lsb 0
+#define xd_I2C_i2c_m_data4 0xA404
+#define i2c_m_data4_pos 0
+#define i2c_m_data4_len 8
+#define i2c_m_data4_lsb 0
+#define xd_I2C_i2c_m_data5 0xA405
+#define i2c_m_data5_pos 0
+#define i2c_m_data5_len 8
+#define i2c_m_data5_lsb 0
+#define xd_I2C_i2c_m_data6 0xA406
+#define i2c_m_data6_pos 0
+#define i2c_m_data6_len 8
+#define i2c_m_data6_lsb 0
+#define xd_I2C_i2c_m_data7 0xA407
+#define i2c_m_data7_pos 0
+#define i2c_m_data7_len 8
+#define i2c_m_data7_lsb 0
+#define xd_I2C_i2c_m_data8 0xA408
+#define i2c_m_data8_pos 0
+#define i2c_m_data8_len 8
+#define i2c_m_data8_lsb 0
+#define xd_I2C_i2c_m_data9 0xA409
+#define i2c_m_data9_pos 0
+#define i2c_m_data9_len 8
+#define i2c_m_data9_lsb 0
+#define xd_I2C_i2c_m_data10 0xA40A
+#define i2c_m_data10_pos 0
+#define i2c_m_data10_len 8
+#define i2c_m_data10_lsb 0
+#define xd_I2C_i2c_m_data11 0xA40B
+#define i2c_m_data11_pos 0
+#define i2c_m_data11_len 8
+#define i2c_m_data11_lsb 0
+#define xd_I2C_i2c_m_cmd_rw 0xA40C
+#define i2c_m_cmd_rw_pos 0
+#define i2c_m_cmd_rw_len 1
+#define i2c_m_cmd_rw_lsb 0
+#define xd_I2C_i2c_m_cmd_rwlen 0xA40C
+#define i2c_m_cmd_rwlen_pos 3
+#define i2c_m_cmd_rwlen_len 4
+#define i2c_m_cmd_rwlen_lsb 0
+#define xd_I2C_i2c_m_status_cmd_exe 0xA40D
+#define i2c_m_status_cmd_exe_pos 0
+#define i2c_m_status_cmd_exe_len 1
+#define i2c_m_status_cmd_exe_lsb 0
+#define xd_I2C_i2c_m_status_wdat_done 0xA40D
+#define i2c_m_status_wdat_done_pos 1
+#define i2c_m_status_wdat_done_len 1
+#define i2c_m_status_wdat_done_lsb 0
+#define xd_I2C_i2c_m_status_wdat_fail 0xA40D
+#define i2c_m_status_wdat_fail_pos 2
+#define i2c_m_status_wdat_fail_len 1
+#define i2c_m_status_wdat_fail_lsb 0
+#define xd_I2C_i2c_m_period 0xA40E
+#define i2c_m_period_pos 0
+#define i2c_m_period_len 8
+#define i2c_m_period_lsb 0
+#define xd_I2C_i2c_m_reg_msb_lsb 0xA40F
+#define i2c_m_reg_msb_lsb_pos 0
+#define i2c_m_reg_msb_lsb_len 1
+#define i2c_m_reg_msb_lsb_lsb 0
+#define xd_I2C_reg_ofdm_rst 0xA40F
+#define reg_ofdm_rst_pos 1
+#define reg_ofdm_rst_len 1
+#define reg_ofdm_rst_lsb 0
+#define xd_I2C_reg_sample_period_on_tuner 0xA40F
+#define reg_sample_period_on_tuner_pos 2
+#define reg_sample_period_on_tuner_len 1
+#define reg_sample_period_on_tuner_lsb 0
+#define xd_I2C_reg_rst_i2c 0xA40F
+#define reg_rst_i2c_pos 3
+#define reg_rst_i2c_len 1
+#define reg_rst_i2c_lsb 0
+#define xd_I2C_reg_ofdm_rst_en 0xA40F
+#define reg_ofdm_rst_en_pos 4
+#define reg_ofdm_rst_en_len 1
+#define reg_ofdm_rst_en_lsb 0
+#define xd_I2C_reg_tuner_sda_sync_on 0xA40F
+#define reg_tuner_sda_sync_on_pos 5
+#define reg_tuner_sda_sync_on_len 1
+#define reg_tuner_sda_sync_on_lsb 0
+#define xd_p_mp2if_data_access_disable_ofsm 0xA500
+#define mp2if_data_access_disable_ofsm_pos 0
+#define mp2if_data_access_disable_ofsm_len 1
+#define mp2if_data_access_disable_ofsm_lsb 0
+#define xd_p_reg_mp2_sw_rst_ofsm 0xA500
+#define reg_mp2_sw_rst_ofsm_pos 1
+#define reg_mp2_sw_rst_ofsm_len 1
+#define reg_mp2_sw_rst_ofsm_lsb 0
+#define xd_p_reg_mp2if_clk_en_ofsm 0xA500
+#define reg_mp2if_clk_en_ofsm_pos 2
+#define reg_mp2if_clk_en_ofsm_len 1
+#define reg_mp2if_clk_en_ofsm_lsb 0
+#define xd_r_mp2if_sync_byte_locked 0xA500
+#define mp2if_sync_byte_locked_pos 3
+#define mp2if_sync_byte_locked_len 1
+#define mp2if_sync_byte_locked_lsb 0
+#define xd_r_mp2if_ts_not_188 0xA500
+#define mp2if_ts_not_188_pos 4
+#define mp2if_ts_not_188_len 1
+#define mp2if_ts_not_188_lsb 0
+#define xd_r_mp2if_psb_empty 0xA500
+#define mp2if_psb_empty_pos 5
+#define mp2if_psb_empty_len 1
+#define mp2if_psb_empty_lsb 0
+#define xd_r_mp2if_psb_overflow 0xA500
+#define mp2if_psb_overflow_pos 6
+#define mp2if_psb_overflow_len 1
+#define mp2if_psb_overflow_lsb 0
+#define xd_p_mp2if_keep_sf_sync_byte_ofsm 0xA500
+#define mp2if_keep_sf_sync_byte_ofsm_pos 7
+#define mp2if_keep_sf_sync_byte_ofsm_len 1
+#define mp2if_keep_sf_sync_byte_ofsm_lsb 0
+#define xd_r_mp2if_psb_mp2if_num_pkt 0xA501
+#define mp2if_psb_mp2if_num_pkt_pos 0
+#define mp2if_psb_mp2if_num_pkt_len 6
+#define mp2if_psb_mp2if_num_pkt_lsb 0
+#define xd_p_reg_mpeg_full_speed_ofsm 0xA501
+#define reg_mpeg_full_speed_ofsm_pos 6
+#define reg_mpeg_full_speed_ofsm_len 1
+#define reg_mpeg_full_speed_ofsm_lsb 0
+#define xd_p_mp2if_mpeg_ser_mode_ofsm 0xA501
+#define mp2if_mpeg_ser_mode_ofsm_pos 7
+#define mp2if_mpeg_ser_mode_ofsm_len 1
+#define mp2if_mpeg_ser_mode_ofsm_lsb 0
+#define xd_p_reg_sw_mon51 0xA600
+#define reg_sw_mon51_pos 0
+#define reg_sw_mon51_len 8
+#define reg_sw_mon51_lsb 0
+#define xd_p_reg_top_pcsel 0xA601
+#define reg_top_pcsel_pos 0
+#define reg_top_pcsel_len 1
+#define reg_top_pcsel_lsb 0
+#define xd_p_reg_top_rs232 0xA601
+#define reg_top_rs232_pos 1
+#define reg_top_rs232_len 1
+#define reg_top_rs232_lsb 0
+#define xd_p_reg_top_pcout 0xA601
+#define reg_top_pcout_pos 2
+#define reg_top_pcout_len 1
+#define reg_top_pcout_lsb 0
+#define xd_p_reg_top_debug 0xA601
+#define reg_top_debug_pos 3
+#define reg_top_debug_len 1
+#define reg_top_debug_lsb 0
+#define xd_p_reg_top_adcdly 0xA601
+#define reg_top_adcdly_pos 4
+#define reg_top_adcdly_len 2
+#define reg_top_adcdly_lsb 0
+#define xd_p_reg_top_pwrdw 0xA601
+#define reg_top_pwrdw_pos 6
+#define reg_top_pwrdw_len 1
+#define reg_top_pwrdw_lsb 0
+#define xd_p_reg_top_pwrdw_inv 0xA601
+#define reg_top_pwrdw_inv_pos 7
+#define reg_top_pwrdw_inv_len 1
+#define reg_top_pwrdw_inv_lsb 0
+#define xd_p_reg_top_int_inv 0xA602
+#define reg_top_int_inv_pos 0
+#define reg_top_int_inv_len 1
+#define reg_top_int_inv_lsb 0
+#define xd_p_reg_top_dio_sel 0xA602
+#define reg_top_dio_sel_pos 1
+#define reg_top_dio_sel_len 1
+#define reg_top_dio_sel_lsb 0
+#define xd_p_reg_top_gpioon0 0xA603
+#define reg_top_gpioon0_pos 0
+#define reg_top_gpioon0_len 1
+#define reg_top_gpioon0_lsb 0
+#define xd_p_reg_top_gpioon1 0xA603
+#define reg_top_gpioon1_pos 1
+#define reg_top_gpioon1_len 1
+#define reg_top_gpioon1_lsb 0
+#define xd_p_reg_top_gpioon2 0xA603
+#define reg_top_gpioon2_pos 2
+#define reg_top_gpioon2_len 1
+#define reg_top_gpioon2_lsb 0
+#define xd_p_reg_top_gpioon3 0xA603
+#define reg_top_gpioon3_pos 3
+#define reg_top_gpioon3_len 1
+#define reg_top_gpioon3_lsb 0
+#define xd_p_reg_top_lockon1 0xA603
+#define reg_top_lockon1_pos 4
+#define reg_top_lockon1_len 1
+#define reg_top_lockon1_lsb 0
+#define xd_p_reg_top_lockon2 0xA603
+#define reg_top_lockon2_pos 5
+#define reg_top_lockon2_len 1
+#define reg_top_lockon2_lsb 0
+#define xd_p_reg_top_gpioo0 0xA604
+#define reg_top_gpioo0_pos 0
+#define reg_top_gpioo0_len 1
+#define reg_top_gpioo0_lsb 0
+#define xd_p_reg_top_gpioo1 0xA604
+#define reg_top_gpioo1_pos 1
+#define reg_top_gpioo1_len 1
+#define reg_top_gpioo1_lsb 0
+#define xd_p_reg_top_gpioo2 0xA604
+#define reg_top_gpioo2_pos 2
+#define reg_top_gpioo2_len 1
+#define reg_top_gpioo2_lsb 0
+#define xd_p_reg_top_gpioo3 0xA604
+#define reg_top_gpioo3_pos 3
+#define reg_top_gpioo3_len 1
+#define reg_top_gpioo3_lsb 0
+#define xd_p_reg_top_lock1 0xA604
+#define reg_top_lock1_pos 4
+#define reg_top_lock1_len 1
+#define reg_top_lock1_lsb 0
+#define xd_p_reg_top_lock2 0xA604
+#define reg_top_lock2_pos 5
+#define reg_top_lock2_len 1
+#define reg_top_lock2_lsb 0
+#define xd_p_reg_top_gpioen0 0xA605
+#define reg_top_gpioen0_pos 0
+#define reg_top_gpioen0_len 1
+#define reg_top_gpioen0_lsb 0
+#define xd_p_reg_top_gpioen1 0xA605
+#define reg_top_gpioen1_pos 1
+#define reg_top_gpioen1_len 1
+#define reg_top_gpioen1_lsb 0
+#define xd_p_reg_top_gpioen2 0xA605
+#define reg_top_gpioen2_pos 2
+#define reg_top_gpioen2_len 1
+#define reg_top_gpioen2_lsb 0
+#define xd_p_reg_top_gpioen3 0xA605
+#define reg_top_gpioen3_pos 3
+#define reg_top_gpioen3_len 1
+#define reg_top_gpioen3_lsb 0
+#define xd_p_reg_top_locken1 0xA605
+#define reg_top_locken1_pos 4
+#define reg_top_locken1_len 1
+#define reg_top_locken1_lsb 0
+#define xd_p_reg_top_locken2 0xA605
+#define reg_top_locken2_pos 5
+#define reg_top_locken2_len 1
+#define reg_top_locken2_lsb 0
+#define xd_r_reg_top_gpioi0 0xA606
+#define reg_top_gpioi0_pos 0
+#define reg_top_gpioi0_len 1
+#define reg_top_gpioi0_lsb 0
+#define xd_r_reg_top_gpioi1 0xA606
+#define reg_top_gpioi1_pos 1
+#define reg_top_gpioi1_len 1
+#define reg_top_gpioi1_lsb 0
+#define xd_r_reg_top_gpioi2 0xA606
+#define reg_top_gpioi2_pos 2
+#define reg_top_gpioi2_len 1
+#define reg_top_gpioi2_lsb 0
+#define xd_r_reg_top_gpioi3 0xA606
+#define reg_top_gpioi3_pos 3
+#define reg_top_gpioi3_len 1
+#define reg_top_gpioi3_lsb 0
+#define xd_r_reg_top_locki1 0xA606
+#define reg_top_locki1_pos 4
+#define reg_top_locki1_len 1
+#define reg_top_locki1_lsb 0
+#define xd_r_reg_top_locki2 0xA606
+#define reg_top_locki2_pos 5
+#define reg_top_locki2_len 1
+#define reg_top_locki2_lsb 0
+#define xd_p_reg_dummy_7_0 0xA608
+#define reg_dummy_7_0_pos 0
+#define reg_dummy_7_0_len 8
+#define reg_dummy_7_0_lsb 0
+#define xd_p_reg_dummy_15_8 0xA609
+#define reg_dummy_15_8_pos 0
+#define reg_dummy_15_8_len 8
+#define reg_dummy_15_8_lsb 8
+#define xd_p_reg_dummy_23_16 0xA60A
+#define reg_dummy_23_16_pos 0
+#define reg_dummy_23_16_len 8
+#define reg_dummy_23_16_lsb 16
+#define xd_p_reg_dummy_31_24 0xA60B
+#define reg_dummy_31_24_pos 0
+#define reg_dummy_31_24_len 8
+#define reg_dummy_31_24_lsb 24
+#define xd_p_reg_dummy_39_32 0xA60C
+#define reg_dummy_39_32_pos 0
+#define reg_dummy_39_32_len 8
+#define reg_dummy_39_32_lsb 32
+#define xd_p_reg_dummy_47_40 0xA60D
+#define reg_dummy_47_40_pos 0
+#define reg_dummy_47_40_len 8
+#define reg_dummy_47_40_lsb 40
+#define xd_p_reg_dummy_55_48 0xA60E
+#define reg_dummy_55_48_pos 0
+#define reg_dummy_55_48_len 8
+#define reg_dummy_55_48_lsb 48
+#define xd_p_reg_dummy_63_56 0xA60F
+#define reg_dummy_63_56_pos 0
+#define reg_dummy_63_56_len 8
+#define reg_dummy_63_56_lsb 56
+#define xd_p_reg_dummy_71_64 0xA610
+#define reg_dummy_71_64_pos 0
+#define reg_dummy_71_64_len 8
+#define reg_dummy_71_64_lsb 64
+#define xd_p_reg_dummy_79_72 0xA611
+#define reg_dummy_79_72_pos 0
+#define reg_dummy_79_72_len 8
+#define reg_dummy_79_72_lsb 72
+#define xd_p_reg_dummy_87_80 0xA612
+#define reg_dummy_87_80_pos 0
+#define reg_dummy_87_80_len 8
+#define reg_dummy_87_80_lsb 80
+#define xd_p_reg_dummy_95_88 0xA613
+#define reg_dummy_95_88_pos 0
+#define reg_dummy_95_88_len 8
+#define reg_dummy_95_88_lsb 88
+#define xd_p_reg_dummy_103_96 0xA614
+#define reg_dummy_103_96_pos 0
+#define reg_dummy_103_96_len 8
+#define reg_dummy_103_96_lsb 96
+
+#define xd_p_reg_unplug_flag 0xA615
+#define reg_unplug_flag_pos 0
+#define reg_unplug_flag_len 1
+#define reg_unplug_flag_lsb 104
+
+#define xd_p_reg_api_dca_stes_request 0xA615
+#define reg_api_dca_stes_request_pos 1
+#define reg_api_dca_stes_request_len 1
+#define reg_api_dca_stes_request_lsb 0
+
+#define xd_p_reg_back_to_dca_flag 0xA615
+#define reg_back_to_dca_flag_pos 2
+#define reg_back_to_dca_flag_len 1
+#define reg_back_to_dca_flag_lsb 106
+
+#define xd_p_reg_api_retrain_request 0xA615
+#define reg_api_retrain_request_pos 3
+#define reg_api_retrain_request_len 1
+#define reg_api_retrain_request_lsb 0
+
+#define xd_p_reg_Dyn_Top_Try_flag 0xA615
+#define reg_Dyn_Top_Try_flag_pos 3
+#define reg_Dyn_Top_Try_flag_len 1
+#define reg_Dyn_Top_Try_flag_lsb 107
+
+#define xd_p_reg_API_retrain_freeze_flag 0xA615
+#define reg_API_retrain_freeze_flag_pos 4
+#define reg_API_retrain_freeze_flag_len 1
+#define reg_API_retrain_freeze_flag_lsb 108
+
+#define xd_p_reg_dummy_111_104 0xA615
+#define reg_dummy_111_104_pos 0
+#define reg_dummy_111_104_len 8
+#define reg_dummy_111_104_lsb 104
+#define xd_p_reg_dummy_119_112 0xA616
+#define reg_dummy_119_112_pos 0
+#define reg_dummy_119_112_len 8
+#define reg_dummy_119_112_lsb 112
+#define xd_p_reg_dummy_127_120 0xA617
+#define reg_dummy_127_120_pos 0
+#define reg_dummy_127_120_len 8
+#define reg_dummy_127_120_lsb 120
+#define xd_p_reg_dummy_135_128 0xA618
+#define reg_dummy_135_128_pos 0
+#define reg_dummy_135_128_len 8
+#define reg_dummy_135_128_lsb 128
+
+#define xd_p_reg_dummy_143_136 0xA619
+#define reg_dummy_143_136_pos 0
+#define reg_dummy_143_136_len 8
+#define reg_dummy_143_136_lsb 136
+
+#define xd_p_reg_CCIR_dis 0xA619
+#define reg_CCIR_dis_pos 0
+#define reg_CCIR_dis_len 1
+#define reg_CCIR_dis_lsb 0
+
+#define xd_p_reg_dummy_151_144 0xA61A
+#define reg_dummy_151_144_pos 0
+#define reg_dummy_151_144_len 8
+#define reg_dummy_151_144_lsb 144
+
+#define xd_p_reg_dummy_159_152 0xA61B
+#define reg_dummy_159_152_pos 0
+#define reg_dummy_159_152_len 8
+#define reg_dummy_159_152_lsb 152
+
+#define xd_p_reg_dummy_167_160 0xA61C
+#define reg_dummy_167_160_pos 0
+#define reg_dummy_167_160_len 8
+#define reg_dummy_167_160_lsb 160
+
+#define xd_p_reg_dummy_175_168 0xA61D
+#define reg_dummy_175_168_pos 0
+#define reg_dummy_175_168_len 8
+#define reg_dummy_175_168_lsb 168
+
+#define xd_p_reg_dummy_183_176 0xA61E
+#define reg_dummy_183_176_pos 0
+#define reg_dummy_183_176_len 8
+#define reg_dummy_183_176_lsb 176
+
+#define xd_p_reg_ofsm_read_rbc_en 0xA61E
+#define reg_ofsm_read_rbc_en_pos 2
+#define reg_ofsm_read_rbc_en_len 1
+#define reg_ofsm_read_rbc_en_lsb 0
+
+#define xd_p_reg_ce_filter_selection_dis 0xA61E
+#define reg_ce_filter_selection_dis_pos 1
+#define reg_ce_filter_selection_dis_len 1
+#define reg_ce_filter_selection_dis_lsb 0
+
+#define xd_p_reg_OFSM_version_control_7_0 0xA611
+#define reg_OFSM_version_control_7_0_pos 0
+#define reg_OFSM_version_control_7_0_len 8
+#define reg_OFSM_version_control_7_0_lsb 0
+
+#define xd_p_reg_OFSM_version_control_15_8 0xA61F
+#define reg_OFSM_version_control_15_8_pos 0
+#define reg_OFSM_version_control_15_8_len 8
+#define reg_OFSM_version_control_15_8_lsb 0
+
+#define xd_p_reg_OFSM_version_control_23_16 0xA620
+#define reg_OFSM_version_control_23_16_pos 0
+#define reg_OFSM_version_control_23_16_len 8
+#define reg_OFSM_version_control_23_16_lsb 0
+
+#define xd_p_reg_dummy_191_184 0xA61F
+#define reg_dummy_191_184_pos 0
+#define reg_dummy_191_184_len 8
+#define reg_dummy_191_184_lsb 184
+
+#define xd_p_reg_dummy_199_192 0xA620
+#define reg_dummy_199_192_pos 0
+#define reg_dummy_199_192_len 8
+#define reg_dummy_199_192_lsb 192
+
+#define xd_p_reg_ce_en 0xABC0
+#define reg_ce_en_pos 0
+#define reg_ce_en_len 1
+#define reg_ce_en_lsb 0
+#define xd_p_reg_ce_fctrl_en 0xABC0
+#define reg_ce_fctrl_en_pos 1
+#define reg_ce_fctrl_en_len 1
+#define reg_ce_fctrl_en_lsb 0
+#define xd_p_reg_ce_fste_tdi 0xABC0
+#define reg_ce_fste_tdi_pos 2
+#define reg_ce_fste_tdi_len 1
+#define reg_ce_fste_tdi_lsb 0
+#define xd_p_reg_ce_dynamic 0xABC0
+#define reg_ce_dynamic_pos 3
+#define reg_ce_dynamic_len 1
+#define reg_ce_dynamic_lsb 0
+#define xd_p_reg_ce_conf 0xABC0
+#define reg_ce_conf_pos 4
+#define reg_ce_conf_len 2
+#define reg_ce_conf_lsb 0
+#define xd_p_reg_ce_dyn12 0xABC0
+#define reg_ce_dyn12_pos 6
+#define reg_ce_dyn12_len 1
+#define reg_ce_dyn12_lsb 0
+#define xd_p_reg_ce_derot_en 0xABC0
+#define reg_ce_derot_en_pos 7
+#define reg_ce_derot_en_len 1
+#define reg_ce_derot_en_lsb 0
+#define xd_p_reg_ce_dynamic_th_7_0 0xABC1
+#define reg_ce_dynamic_th_7_0_pos 0
+#define reg_ce_dynamic_th_7_0_len 8
+#define reg_ce_dynamic_th_7_0_lsb 0
+#define xd_p_reg_ce_dynamic_th_15_8 0xABC2
+#define reg_ce_dynamic_th_15_8_pos 0
+#define reg_ce_dynamic_th_15_8_len 8
+#define reg_ce_dynamic_th_15_8_lsb 8
+#define xd_p_reg_ce_s1 0xABC3
+#define reg_ce_s1_pos 0
+#define reg_ce_s1_len 5
+#define reg_ce_s1_lsb 0
+#define xd_p_reg_ce_var_forced_value 0xABC3
+#define reg_ce_var_forced_value_pos 5
+#define reg_ce_var_forced_value_len 3
+#define reg_ce_var_forced_value_lsb 0
+#define xd_p_reg_ce_data_im_7_0 0xABC4
+#define reg_ce_data_im_7_0_pos 0
+#define reg_ce_data_im_7_0_len 8
+#define reg_ce_data_im_7_0_lsb 0
+#define xd_p_reg_ce_data_im_8 0xABC5
+#define reg_ce_data_im_8_pos 0
+#define reg_ce_data_im_8_len 1
+#define reg_ce_data_im_8_lsb 0
+#define xd_p_reg_ce_data_re_6_0 0xABC5
+#define reg_ce_data_re_6_0_pos 1
+#define reg_ce_data_re_6_0_len 7
+#define reg_ce_data_re_6_0_lsb 0
+#define xd_p_reg_ce_data_re_8_7 0xABC6
+#define reg_ce_data_re_8_7_pos 0
+#define reg_ce_data_re_8_7_len 2
+#define reg_ce_data_re_8_7_lsb 7
+#define xd_p_reg_ce_tone_5_0 0xABC6
+#define reg_ce_tone_5_0_pos 2
+#define reg_ce_tone_5_0_len 6
+#define reg_ce_tone_5_0_lsb 0
+#define xd_p_reg_ce_tone_12_6 0xABC7
+#define reg_ce_tone_12_6_pos 0
+#define reg_ce_tone_12_6_len 7
+#define reg_ce_tone_12_6_lsb 6
+#define xd_p_reg_ce_centroid_drift_th 0xABC8
+#define reg_ce_centroid_drift_th_pos 0
+#define reg_ce_centroid_drift_th_len 8
+#define reg_ce_centroid_drift_th_lsb 0
+#define xd_p_reg_ce_centroid_count_max 0xABC9
+#define reg_ce_centroid_count_max_pos 0
+#define reg_ce_centroid_count_max_len 4
+#define reg_ce_centroid_count_max_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_7_0 0xABCA
+#define reg_ce_centroid_bias_inc_7_0_pos 0
+#define reg_ce_centroid_bias_inc_7_0_len 8
+#define reg_ce_centroid_bias_inc_7_0_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_8 0xABCB
+#define reg_ce_centroid_bias_inc_8_pos 0
+#define reg_ce_centroid_bias_inc_8_len 1
+#define reg_ce_centroid_bias_inc_8_lsb 0
+#define xd_p_reg_ce_var_th0_7_0 0xABCC
+#define reg_ce_var_th0_7_0_pos 0
+#define reg_ce_var_th0_7_0_len 8
+#define reg_ce_var_th0_7_0_lsb 0
+#define xd_p_reg_ce_var_th0_15_8 0xABCD
+#define reg_ce_var_th0_15_8_pos 0
+#define reg_ce_var_th0_15_8_len 8
+#define reg_ce_var_th0_15_8_lsb 8
+#define xd_p_reg_ce_var_th1_7_0 0xABCE
+#define reg_ce_var_th1_7_0_pos 0
+#define reg_ce_var_th1_7_0_len 8
+#define reg_ce_var_th1_7_0_lsb 0
+#define xd_p_reg_ce_var_th1_15_8 0xABCF
+#define reg_ce_var_th1_15_8_pos 0
+#define reg_ce_var_th1_15_8_len 8
+#define reg_ce_var_th1_15_8_lsb 8
+#define xd_p_reg_ce_var_th2_7_0 0xABD0
+#define reg_ce_var_th2_7_0_pos 0
+#define reg_ce_var_th2_7_0_len 8
+#define reg_ce_var_th2_7_0_lsb 0
+#define xd_p_reg_ce_var_th2_15_8 0xABD1
+#define reg_ce_var_th2_15_8_pos 0
+#define reg_ce_var_th2_15_8_len 8
+#define reg_ce_var_th2_15_8_lsb 8
+#define xd_p_reg_ce_var_th3_7_0 0xABD2
+#define reg_ce_var_th3_7_0_pos 0
+#define reg_ce_var_th3_7_0_len 8
+#define reg_ce_var_th3_7_0_lsb 0
+#define xd_p_reg_ce_var_th3_15_8 0xABD3
+#define reg_ce_var_th3_15_8_pos 0
+#define reg_ce_var_th3_15_8_len 8
+#define reg_ce_var_th3_15_8_lsb 8
+#define xd_p_reg_ce_var_th4_7_0 0xABD4
+#define reg_ce_var_th4_7_0_pos 0
+#define reg_ce_var_th4_7_0_len 8
+#define reg_ce_var_th4_7_0_lsb 0
+#define xd_p_reg_ce_var_th4_15_8 0xABD5
+#define reg_ce_var_th4_15_8_pos 0
+#define reg_ce_var_th4_15_8_len 8
+#define reg_ce_var_th4_15_8_lsb 8
+#define xd_p_reg_ce_var_th5_7_0 0xABD6
+#define reg_ce_var_th5_7_0_pos 0
+#define reg_ce_var_th5_7_0_len 8
+#define reg_ce_var_th5_7_0_lsb 0
+#define xd_p_reg_ce_var_th5_15_8 0xABD7
+#define reg_ce_var_th5_15_8_pos 0
+#define reg_ce_var_th5_15_8_len 8
+#define reg_ce_var_th5_15_8_lsb 8
+#define xd_p_reg_ce_var_th6_7_0 0xABD8
+#define reg_ce_var_th6_7_0_pos 0
+#define reg_ce_var_th6_7_0_len 8
+#define reg_ce_var_th6_7_0_lsb 0
+#define xd_p_reg_ce_var_th6_15_8 0xABD9
+#define reg_ce_var_th6_15_8_pos 0
+#define reg_ce_var_th6_15_8_len 8
+#define reg_ce_var_th6_15_8_lsb 8
+#define xd_p_reg_ce_fctrl_reset 0xABDA
+#define reg_ce_fctrl_reset_pos 0
+#define reg_ce_fctrl_reset_len 1
+#define reg_ce_fctrl_reset_lsb 0
+#define xd_p_reg_ce_cent_auto_clr_en 0xABDA
+#define reg_ce_cent_auto_clr_en_pos 1
+#define reg_ce_cent_auto_clr_en_len 1
+#define reg_ce_cent_auto_clr_en_lsb 0
+#define xd_p_reg_ce_fctrl_auto_reset_en 0xABDA
+#define reg_ce_fctrl_auto_reset_en_pos 2
+#define reg_ce_fctrl_auto_reset_en_len 1
+#define reg_ce_fctrl_auto_reset_en_lsb 0
+#define xd_p_reg_ce_var_forced_en 0xABDA
+#define reg_ce_var_forced_en_pos 3
+#define reg_ce_var_forced_en_len 1
+#define reg_ce_var_forced_en_lsb 0
+#define xd_p_reg_ce_cent_forced_en 0xABDA
+#define reg_ce_cent_forced_en_pos 4
+#define reg_ce_cent_forced_en_len 1
+#define reg_ce_cent_forced_en_lsb 0
+#define xd_p_reg_ce_var_max 0xABDA
+#define reg_ce_var_max_pos 5
+#define reg_ce_var_max_len 3
+#define reg_ce_var_max_lsb 0
+#define xd_p_reg_ce_cent_forced_value_7_0 0xABDB
+#define reg_ce_cent_forced_value_7_0_pos 0
+#define reg_ce_cent_forced_value_7_0_len 8
+#define reg_ce_cent_forced_value_7_0_lsb 0
+#define xd_p_reg_ce_cent_forced_value_11_8 0xABDC
+#define reg_ce_cent_forced_value_11_8_pos 0
+#define reg_ce_cent_forced_value_11_8_len 4
+#define reg_ce_cent_forced_value_11_8_lsb 8
+#define xd_p_reg_ce_fctrl_rd 0xABDD
+#define reg_ce_fctrl_rd_pos 0
+#define reg_ce_fctrl_rd_len 1
+#define reg_ce_fctrl_rd_lsb 0
+#define xd_p_reg_ce_centroid_max_6_0 0xABDD
+#define reg_ce_centroid_max_6_0_pos 1
+#define reg_ce_centroid_max_6_0_len 7
+#define reg_ce_centroid_max_6_0_lsb 0
+#define xd_p_reg_ce_centroid_max_11_7 0xABDE
+#define reg_ce_centroid_max_11_7_pos 0
+#define reg_ce_centroid_max_11_7_len 5
+#define reg_ce_centroid_max_11_7_lsb 7
+#define xd_p_reg_ce_var 0xABDF
+#define reg_ce_var_pos 0
+#define reg_ce_var_len 3
+#define reg_ce_var_lsb 0
+#define xd_p_reg_ce_fctrl_rdy 0xABDF
+#define reg_ce_fctrl_rdy_pos 3
+#define reg_ce_fctrl_rdy_len 1
+#define reg_ce_fctrl_rdy_lsb 0
+#define xd_p_reg_ce_centroid_out_3_0 0xABDF
+#define reg_ce_centroid_out_3_0_pos 4
+#define reg_ce_centroid_out_3_0_len 4
+#define reg_ce_centroid_out_3_0_lsb 0
+#define xd_p_reg_ce_centroid_out_11_4 0xABE0
+#define reg_ce_centroid_out_11_4_pos 0
+#define reg_ce_centroid_out_11_4_len 8
+#define reg_ce_centroid_out_11_4_lsb 4
+#define xd_p_reg_ce_bias_7_0 0xABE1
+#define reg_ce_bias_7_0_pos 0
+#define reg_ce_bias_7_0_len 8
+#define reg_ce_bias_7_0_lsb 0
+#define xd_p_reg_ce_bias_11_8 0xABE2
+#define reg_ce_bias_11_8_pos 0
+#define reg_ce_bias_11_8_len 4
+#define reg_ce_bias_11_8_lsb 8
+#define xd_p_reg_ce_m1_3_0 0xABE2
+#define reg_ce_m1_3_0_pos 4
+#define reg_ce_m1_3_0_len 4
+#define reg_ce_m1_3_0_lsb 0
+#define xd_p_reg_ce_m1_11_4 0xABE3
+#define reg_ce_m1_11_4_pos 0
+#define reg_ce_m1_11_4_len 8
+#define reg_ce_m1_11_4_lsb 4
+#define xd_p_reg_ce_rh0_7_0 0xABE4
+#define reg_ce_rh0_7_0_pos 0
+#define reg_ce_rh0_7_0_len 8
+#define reg_ce_rh0_7_0_lsb 0
+#define xd_p_reg_ce_rh0_15_8 0xABE5
+#define reg_ce_rh0_15_8_pos 0
+#define reg_ce_rh0_15_8_len 8
+#define reg_ce_rh0_15_8_lsb 8
+#define xd_p_reg_ce_rh0_23_16 0xABE6
+#define reg_ce_rh0_23_16_pos 0
+#define reg_ce_rh0_23_16_len 8
+#define reg_ce_rh0_23_16_lsb 16
+#define xd_p_reg_ce_rh0_31_24 0xABE7
+#define reg_ce_rh0_31_24_pos 0
+#define reg_ce_rh0_31_24_len 8
+#define reg_ce_rh0_31_24_lsb 24
+#define xd_p_reg_ce_rh3_real_7_0 0xABE8
+#define reg_ce_rh3_real_7_0_pos 0
+#define reg_ce_rh3_real_7_0_len 8
+#define reg_ce_rh3_real_7_0_lsb 0
+#define xd_p_reg_ce_rh3_real_15_8 0xABE9
+#define reg_ce_rh3_real_15_8_pos 0
+#define reg_ce_rh3_real_15_8_len 8
+#define reg_ce_rh3_real_15_8_lsb 8
+#define xd_p_reg_ce_rh3_real_23_16 0xABEA
+#define reg_ce_rh3_real_23_16_pos 0
+#define reg_ce_rh3_real_23_16_len 8
+#define reg_ce_rh3_real_23_16_lsb 16
+#define xd_p_reg_ce_rh3_real_31_24 0xABEB
+#define reg_ce_rh3_real_31_24_pos 0
+#define reg_ce_rh3_real_31_24_len 8
+#define reg_ce_rh3_real_31_24_lsb 24
+#define xd_p_reg_ce_rh3_imag_7_0 0xABEC
+#define reg_ce_rh3_imag_7_0_pos 0
+#define reg_ce_rh3_imag_7_0_len 8
+#define reg_ce_rh3_imag_7_0_lsb 0
+#define xd_p_reg_ce_rh3_imag_15_8 0xABED
+#define reg_ce_rh3_imag_15_8_pos 0
+#define reg_ce_rh3_imag_15_8_len 8
+#define reg_ce_rh3_imag_15_8_lsb 8
+#define xd_p_reg_ce_rh3_imag_23_16 0xABEE
+#define reg_ce_rh3_imag_23_16_pos 0
+#define reg_ce_rh3_imag_23_16_len 8
+#define reg_ce_rh3_imag_23_16_lsb 16
+#define xd_p_reg_ce_rh3_imag_31_24 0xABEF
+#define reg_ce_rh3_imag_31_24_pos 0
+#define reg_ce_rh3_imag_31_24_len 8
+#define reg_ce_rh3_imag_31_24_lsb 24
+#define xd_p_reg_feq_fix_eh2_7_0 0xABF0
+#define reg_feq_fix_eh2_7_0_pos 0
+#define reg_feq_fix_eh2_7_0_len 8
+#define reg_feq_fix_eh2_7_0_lsb 0
+#define xd_p_reg_feq_fix_eh2_15_8 0xABF1
+#define reg_feq_fix_eh2_15_8_pos 0
+#define reg_feq_fix_eh2_15_8_len 8
+#define reg_feq_fix_eh2_15_8_lsb 8
+#define xd_p_reg_feq_fix_eh2_23_16 0xABF2
+#define reg_feq_fix_eh2_23_16_pos 0
+#define reg_feq_fix_eh2_23_16_len 8
+#define reg_feq_fix_eh2_23_16_lsb 16
+#define xd_p_reg_feq_fix_eh2_31_24 0xABF3
+#define reg_feq_fix_eh2_31_24_pos 0
+#define reg_feq_fix_eh2_31_24_len 8
+#define reg_feq_fix_eh2_31_24_lsb 24
+#define xd_p_reg_ce_m2_central_7_0 0xABF4
+#define reg_ce_m2_central_7_0_pos 0
+#define reg_ce_m2_central_7_0_len 8
+#define reg_ce_m2_central_7_0_lsb 0
+#define xd_p_reg_ce_m2_central_15_8 0xABF5
+#define reg_ce_m2_central_15_8_pos 0
+#define reg_ce_m2_central_15_8_len 8
+#define reg_ce_m2_central_15_8_lsb 8
+#define xd_p_reg_ce_fftshift 0xABF6
+#define reg_ce_fftshift_pos 0
+#define reg_ce_fftshift_len 4
+#define reg_ce_fftshift_lsb 0
+#define xd_p_reg_ce_fftshift1 0xABF6
+#define reg_ce_fftshift1_pos 4
+#define reg_ce_fftshift1_len 4
+#define reg_ce_fftshift1_lsb 0
+#define xd_p_reg_ce_fftshift2 0xABF7
+#define reg_ce_fftshift2_pos 0
+#define reg_ce_fftshift2_len 4
+#define reg_ce_fftshift2_lsb 0
+#define xd_p_reg_ce_top_mobile 0xABF7
+#define reg_ce_top_mobile_pos 4
+#define reg_ce_top_mobile_len 1
+#define reg_ce_top_mobile_lsb 0
+#define xd_p_reg_strong_sginal_detected 0xA2BC
+#define reg_strong_sginal_detected_pos 2
+#define reg_strong_sginal_detected_len 1
+#define reg_strong_sginal_detected_lsb 0
+
+#define XD_MP2IF_BASE 0xB000
+#define XD_MP2IF_CSR (0x00 + XD_MP2IF_BASE)
+#define XD_MP2IF_DMX_CTRL (0x03 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_IDX (0x04 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_L (0x05 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_H (0x06 + XD_MP2IF_BASE)
+#define XD_MP2IF_MISC (0x07 + XD_MP2IF_BASE)
+
+extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
+extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
+ u8 * value);
+extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
+ u8 value);
+extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 addr, u8 * values, int len);
+extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+ u8 * values, int len);
+extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
+ u8 pos, u8 len, u8 * value);
+extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
+ u8 pos, u8 len, u8 value);
+extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
+ u8 * wbuf, int wlen, u8 * rbuf, int rlen);
+extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
+ u8 * values, int len);
+extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
+extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
+
+extern u8 regmask[8];
+
+/* remote control decoder */
+extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
+ u32 * event, int *state);
+extern struct dvb_usb_rc_key af9005_rc_keys[];
+extern int af9005_rc_keys_size;
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index bac2ae3b4a1f..04e31cf7d530 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -354,41 +354,35 @@ static struct mt352_config cxusb_mt352_config = {
/* Callbacks for DVB USB */
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
- u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- adap->pll_addr = 0x61;
- memcpy(adap->pll_init, bpll, 4);
- adap->pll_desc = &dvb_pll_fmd1216me;
-
- adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+ DVB_PLL_FMD1216ME);
return 0;
}
static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
{
- dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
return 0;
}
static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
return 0;
}
static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 5143e426d283..9a184da01c47 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -295,7 +295,7 @@ int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
/* not found - use panasonic pll parameters */
- if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+ if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
return -ENOMEM;
} else {
st->mt2060_present = 1;
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 7a6ae8f482e0..043cadae0859 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -14,6 +14,14 @@
*/
#include "dibusb.h"
+static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dibusb_state *st = adap->priv;
+
+ return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
+}
+
static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib3000_config demod_cfg;
@@ -21,21 +29,34 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
demod_cfg.demod_address = 0x8;
- if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
+ if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+ &adap->dev->i2c_adap, &st->ops)) == NULL)
return -ENODEV;
- adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
- adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+ adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
return 0;
}
static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_tua6010xs;
+ struct dibusb_state *st = adap->priv;
+
+ st->tuner_addr = 0x61;
+
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+ DVB_PLL_TUA6010XS);
+ return 0;
+}
+
+static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dibusb_state *st = adap->priv;
+
+ st->tuner_addr = 0x60;
+
+ dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+ DVB_PLL_TDA665X);
return 0;
}
@@ -50,30 +71,28 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
{ .flags = 0, .buf = b, .len = 2 },
{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
};
+ struct dibusb_state *st = adap->priv;
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
- msg[0].addr = msg[1].addr = 0x60;
+ msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
+ if (adap->fe->ops.i2c_gate_ctrl)
+ adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
err("tuner i2c write failed.");
ret = -EREMOTEIO;
}
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
+ if (adap->fe->ops.i2c_gate_ctrl)
+ adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
if (b2[0] == 0xfe) {
info("This device has the Thomson Cable onboard. Which is default.");
- dibusb_thomson_tuner_attach(adap);
+ ret = dibusb_thomson_tuner_attach(adap);
} else {
- u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
info("This device has the Panasonic ENV77H11D5 onboard.");
- adap->pll_addr = 0x60;
- memcpy(adap->pll_init,bpll,4);
- adap->pll_desc = &dvb_pll_tda665x;
+ ret = dibusb_panasonic_tuner_attach(adap);
}
return ret;
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index b60781032742..8e847aa73ba1 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -99,6 +99,7 @@
struct dibusb_state {
struct dib_fe_xfer_ops ops;
int mt2060_present;
+ u8 tuner_addr;
};
struct dibusb_device_state {
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index b5acb11c0bc9..bca1e0905739 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -118,7 +118,8 @@ static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_f
{
struct dvb_usb_adapter *adap = fe->dvb->priv;
u8 b[5];
- dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+
+ fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
@@ -130,12 +131,14 @@ static struct nxt6000_config digitv_nxt6000_config = {
static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct digitv_state *st = adap->dev->priv;
+
if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ st->is_nxt6000 = 0;
return 0;
}
if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
- adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ st->is_nxt6000 = 1;
return 0;
}
return -EIO;
@@ -143,8 +146,14 @@ static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x60;
- adap->pll_desc = &dvb_pll_tded4;
+ struct digitv_state *st = adap->dev->priv;
+
+ if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
+ return -ENODEV;
+
+ if (st->is_nxt6000)
+ adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+
return 0;
}
@@ -273,6 +282,8 @@ static struct dvb_usb_device_properties digitv_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-digitv-02.fw",
+ .size_of_priv = sizeof(struct digitv_state),
+
.num_adapters = 1,
.adapter = {
{
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
index 477ee428a70e..8b43e3db8691 100644
--- a/drivers/media/dvb/dvb-usb/digitv.h
+++ b/drivers/media/dvb/dvb-usb/digitv.h
@@ -4,6 +4,10 @@
#define DVB_USB_LOG_PREFIX "digitv"
#include "dvb-usb.h"
+struct digitv_state {
+ int is_nxt6000;
+};
+
extern int dvb_usb_digitv_debug;
#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 088b6dee3a7f..23428cd30756 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -46,82 +46,3 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
d->state &= ~DVB_USB_STATE_I2C;
return 0;
}
-
-int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
- int ret = 0;
-
- /* if pll_desc is not used */
- if (adap->pll_desc == NULL)
- return 0;
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
- deb_pll("pll init: %x\n",adap->pll_addr);
- deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
- adap->pll_init[2], adap->pll_init[3]);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
- err("tuner i2c write failed for pll_init.");
- ret = -EREMOTEIO;
- }
- msleep(1);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
- return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-
-int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
-
- if (buf_len != 5)
- return -EINVAL;
- if (adap->pll_desc == NULL)
- return 0;
-
- deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
-
- b[0] = adap->pll_addr;
- dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
-
- deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
-
- return 5;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-
-int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
-{
- struct dvb_usb_adapter *adap = fe->dvb->priv;
- int ret = 0;
- u8 b[5];
- struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
-
- dvb_usb_tuner_calc_regs(fe,fep,b,5);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
- err("tuner i2c write failed for pll_set.");
- ret = -EREMOTEIO;
- }
- msleep(1);
-
- if (adap->tuner_pass_ctrl)
- adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
-
- return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 403081689de1..4dfab02a8a0d 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -11,7 +11,9 @@
/* Vendor IDs */
#define USB_VID_ADSTECH 0x06e1
+#define USB_VID_AFATECH 0x15a4
#define USB_VID_ALCOR_MICRO 0x058f
+#define USB_VID_ALINK 0x05e3
#define USB_VID_ANCHOR 0x0547
#define USB_VID_ANUBIS_ELECTRONIC 0x10fd
#define USB_VID_AVERMEDIA 0x07ca
@@ -35,6 +37,7 @@
#define USB_VID_MSI 0x0db0
#define USB_VID_OPERA1 0x695c
#define USB_VID_PINNACLE 0x2304
+#define USB_VID_TERRATEC 0x0ccd
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
@@ -44,6 +47,8 @@
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
#define USB_PID_ADSTECH_USB2_WARM 0xa334
+#define USB_PID_AFATECH_AF9005 0x9020
+#define USB_VID_ALINK_DTU 0xf170
#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
@@ -69,6 +74,7 @@
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 9200a30dd1b9..7b9f35bfb4f0 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -110,7 +110,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
input_dev->name = "IR-receiver inside an USB DVB receiver";
input_dev->phys = d->rc_phys;
usb_to_input_id(d->udev, &input_dev->id);
- input_dev->cdev.dev = &d->udev->dev;
+ input_dev->dev.parent = &d->udev->dev;
/* set the bits for the keys */
deb_rc("key map size: %d\n", d->props.rc_key_map_size);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 6f824a569e14..d1b3c7b81fff 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -297,12 +297,6 @@ struct dvb_usb_adapter {
int feedcount;
int pid_filtering;
- /* tuner programming information */
- u8 pll_addr;
- u8 pll_init[4];
- struct dvb_pll_desc *pll_desc;
- int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
-
/* dvb */
struct dvb_adapter dvb_adap;
struct dmxdev dmxdev;
@@ -388,11 +382,6 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
/* commonly used remote control parsing */
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
-/* commonly used pll init and set functions */
-extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
-extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
-
/* commonly used firmware download types and function */
struct hexline {
u8 len;
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index e0587e663591..f01d99c1c43c 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -157,6 +157,7 @@ static int gl861_probe(struct usb_interface *intf,
static struct usb_device_id gl861_table [] = {
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+ { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, gl861_table);
@@ -187,12 +188,16 @@ static struct dvb_usb_device_properties gl861_properties = {
}},
.i2c_algo = &gl861_i2c_algo,
- .num_device_descs = 1,
+ .num_device_descs = 2,
.devices = {
{ "MSI Mega Sky 55801 DVB-T USB2.0",
{ &gl861_table[0], NULL },
{ NULL },
},
+ { "A-LINK DTU DVB-T USB2.0",
+ { &gl861_table[1], NULL },
+ { NULL },
+ },
}
};
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index c546ddeda5d4..a956bc503a4c 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -22,6 +22,8 @@ static int dvb_usb_m920x_debug;
module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
+
static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
u16 index, void *data, int size)
{
@@ -57,7 +59,8 @@ static inline int m920x_write(struct usb_device *udev, u8 request,
static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
{
- int ret = 0;
+ int ret = 0, i, epi, flags = 0;
+ int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
if (d->props.rc_query) {
@@ -76,9 +79,51 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
deb("Initialising remote control success\n");
}
+ for (i = 0; i < d->props.num_adapters; i++)
+ flags |= d->adapter[i].props.caps;
+
+ /* Some devices(Dposh) might crash if we attempt touch at all. */
+ if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
+ for (i = 0; i < d->props.num_adapters; i++) {
+ epi = d->adapter[i].props.stream.endpoint - 0x81;
+
+ if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
+ printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
+ return -EINVAL;
+ }
+
+ adap_enabled[epi] = 1;
+ }
+
+ for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
+ if (adap_enabled[i])
+ continue;
+
+ if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
+ return ret;
+
+ if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
+ return ret;
+ }
+ }
+
return ret;
}
+static int m920x_init_ep(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *alt;
+
+ if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
+ deb("No alt found!\n");
+ return -ENODEV;
+ }
+
+ return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+}
+
static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct m920x_state *m = d->priv;
@@ -211,8 +256,7 @@ static struct i2c_algorithm m920x_i2c_algo = {
};
/* pid filter */
-static int m920x_set_filter(struct dvb_usb_adapter *adap,
- int type, int idx, int pid)
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
{
int ret = 0;
@@ -221,10 +265,10 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
pid |= 0x8000;
- if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+ if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
return ret;
- if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+ if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
return ret;
return ret;
@@ -233,40 +277,35 @@ static int m920x_set_filter(struct dvb_usb_adapter *adap,
static int m920x_update_filters(struct dvb_usb_adapter *adap)
{
struct m920x_state *m = adap->dev->priv;
- int enabled = m->filtering_enabled;
+ int enabled = m->filtering_enabled[adap->id];
int i, ret = 0, filter = 0;
+ int ep = adap->props.stream.endpoint;
for (i = 0; i < M9206_MAX_FILTERS; i++)
- if (m->filters[i] == 8192)
+ if (m->filters[adap->id][i] == 8192)
enabled = 0;
/* Disable all filters */
- if ((ret = m920x_set_filter(adap, 0x81, 1, enabled)) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
return ret;
for (i = 0; i < M9206_MAX_FILTERS; i++)
- if ((ret = m920x_set_filter(adap, 0x81, i + 2, 0)) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
return ret;
- if ((ret = m920x_set_filter(adap, 0x82, 0, 0x0)) != 0)
- return ret;
-
/* Set */
if (enabled) {
for (i = 0; i < M9206_MAX_FILTERS; i++) {
- if (m->filters[i] == 0)
+ if (m->filters[adap->id][i] == 0)
continue;
- if ((ret = m920x_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+ if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
return ret;
filter++;
}
}
- if ((ret = m920x_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
- return ret;
-
return ret;
}
@@ -274,7 +313,7 @@ static int m920x_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct m920x_state *m = adap->dev->priv;
- m->filtering_enabled = onoff ? 1 : 0;
+ m->filtering_enabled[adap->id] = onoff ? 1 : 0;
return m920x_update_filters(adap);
}
@@ -283,7 +322,7 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in
{
struct m920x_state *m = adap->dev->priv;
- m->filters[index] = onoff ? pid : 0;
+ m->filters[adap->id][index] = onoff ? pid : 0;
return m920x_update_filters(adap);
}
@@ -368,6 +407,7 @@ static int m920x_identify_state(struct usb_device *udev,
/* demod configurations */
static int m920x_mt352_demod_init(struct dvb_frontend *fe)
{
+ int ret;
u8 config[] = { CONFIG, 0x3d };
u8 clock[] = { CLOCK_CTL, 0x30 };
u8 reset[] = { RESET, 0x80 };
@@ -377,17 +417,25 @@ static int m920x_mt352_demod_init(struct dvb_frontend *fe)
u8 unk1[] = { 0x93, 0x1a };
u8 unk2[] = { 0xb5, 0x7a };
- mt352_write(fe, config, ARRAY_SIZE(config));
- mt352_write(fe, clock, ARRAY_SIZE(clock));
- mt352_write(fe, reset, ARRAY_SIZE(reset));
- mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
- mt352_write(fe, agc, ARRAY_SIZE(agc));
- mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
- mt352_write(fe, unk1, ARRAY_SIZE(unk1));
- mt352_write(fe, unk2, ARRAY_SIZE(unk2));
-
deb("Demod init!\n");
+ if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
+ return ret;
+ if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
+ return ret;
+
return 0;
}
@@ -558,8 +606,7 @@ static struct dvb_usb_device_properties dposh_properties;
static int m920x_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
- struct usb_host_interface *alt;
+ struct dvb_usb_device *d = NULL;
int ret;
struct m920x_inits *rc_init_seq = NULL;
int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
@@ -604,23 +651,13 @@ static int m920x_probe(struct usb_interface *intf,
* tvwalkertwin_properties already configured both
* tuners, so there is nothing for us to do here
*/
-
- return -ENODEV;
}
found:
- alt = usb_altnum_to_altsetting(intf, 1);
- if (alt == NULL) {
- deb("No alt found!\n");
- return -ENODEV;
- }
-
- ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
- alt->desc.bAlternateSetting);
- if (ret < 0)
+ if ((ret = m920x_init_ep(intf)) < 0)
return ret;
- if ((ret = m920x_init(d, rc_init_seq)) != 0)
+ if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
return ret;
return ret;
@@ -737,9 +774,9 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = {
*
* LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
* TDA10046 #0 is located at i2c address 0x08
- * TDA10046 #1 is located at i2c address 0x0b (presently disabled - not yet working)
+ * TDA10046 #1 is located at i2c address 0x0b
* TDA8275A #0 is located at i2c address 0x60
- * TDA8275A #1 is located at i2c address 0x61 (presently disabled - not yet working)
+ * TDA8275A #1 is located at i2c address 0x61
*/
static struct dvb_usb_device_properties tvwalkertwin_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -756,7 +793,7 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.size_of_priv = sizeof(struct m920x_state),
.identify_state = m920x_identify_state,
- .num_adapters = 1,
+ .num_adapters = 2,
.adapter = {{
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index 2c8942d04222..37532890accd 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -18,6 +18,7 @@
#define M9206_FW 0x30
#define M9206_MAX_FILTERS 8
+#define M9206_MAX_ADAPTERS 2
/*
sequences found in logs:
@@ -60,8 +61,8 @@ response to a write, is unknown.
*/
struct m920x_state {
- u16 filters[M9206_MAX_FILTERS];
- int filtering_enabled;
+ u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
+ int filtering_enabled[M9206_MAX_ADAPTERS];
int rep_count;
};
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 518d7ad217df..d7c04951ceab 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -263,7 +263,7 @@ static int opera1_tuner_attach(struct dvb_usb_adapter *adap)
{
dvb_attach(
dvb_pll_attach, adap->fe, 0xc0>>1,
- &adap->dev->i2c_adap, &dvb_pll_opera1
+ &adap->dev->i2c_adap, DVB_PLL_OPERA1
);
return 0;
}
@@ -435,9 +435,9 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
{
const struct firmware *fw = NULL;
u8 *b, *p;
- int ret = 0, i;
+ int ret = 0, i,fpgasize=40;
u8 testval;
- info("start downloading fpga firmware");
+ info("start downloading fpga firmware %s",filename);
if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
err("did not find the firmware file. (%s) "
@@ -454,17 +454,20 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
/* clear fpga ? */
opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
OPERA_WRITE_MSG);
- for (i = 0; p[i] != 0 && i < fw->size;) {
+ for (i = 0; i < fw->size;) {
+ if ( (fw->size - i) <fpgasize){
+ fpgasize=fw->size-i;
+ }
b = (u8 *) p + i;
if (opera1_xilinx_rw
- (dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
- OPERA_WRITE_MSG) != b[0]
+ (dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
+ OPERA_WRITE_MSG) != fpgasize
) {
err("error while transferring firmware");
ret = -EINVAL;
break;
}
- i = i + 1 + b[0];
+ i = i + fpgasize;
}
/* restart the CPU */
if (ret || opera1_xilinx_rw
@@ -534,18 +537,16 @@ static struct dvb_usb_device_properties opera1_properties = {
static int opera1_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
struct usb_device *udev = interface_to_usbdev(intf);
if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
udev->descriptor.idVendor == USB_VID_OPERA1 &&
- (d == NULL
- || opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
- ) {
+ opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
+ ) {
return -EINVAL;
}
- if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
+ if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0)
return -EINVAL;
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index f77b48f76582..0dcab3d4e236 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -65,9 +65,7 @@ static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
static int umt_tuner_attach (struct dvb_usb_adapter *adap)
{
- adap->pll_addr = 0x61;
- adap->pll_desc = &dvb_pll_tua6034;
- adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
return 0;
}
@@ -84,8 +82,8 @@ static int umt_probe(struct usb_interface *intf,
/* do not change the order of the ID table */
static struct usb_device_id umt_table [] = {
-/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
-/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
+/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, umt_table);
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 27f386585d43..156b062e02c4 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel DVB frontend device drivers.
#
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 335219ebce2d..1dc164d5488c 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -32,7 +32,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "cx22702.h"
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 732e94aaa364..0834c0677fef 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -917,7 +917,7 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
static int cx24123_tune(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
unsigned int mode_flags,
- int *delay,
+ unsigned int *delay,
fe_status_t *status)
{
int retval = 0;
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 5f96ffda91ad..0c0b94767bc1 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -24,6 +24,23 @@
#include "dvb-pll.h"
+struct dvb_pll_desc {
+ char *name;
+ u32 min;
+ u32 max;
+ u32 iffreq;
+ void (*set)(u8 *buf, const struct dvb_frontend_parameters *params);
+ u8 *initdata;
+ u8 *sleepdata;
+ int count;
+ struct {
+ u32 limit;
+ u32 stepsize;
+ u8 config;
+ u8 cb;
+ } entries[12];
+};
+
/* ----------------------------------------------------------- */
/* descriptions */
@@ -38,7 +55,13 @@
0x50 = AGC Take over point = 103 dBuV */
static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
-struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+/* 0x04 = 166.67 kHz divider
+
+ 0x80 = AGC Time constant 50ms Iagc = 9 uA
+ 0x20 = AGC Take over point = 112 dBuV */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
.name = "Thomson dtt7579",
.min = 177000000,
.max = 858000000,
@@ -52,9 +75,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
{ 999999999, 166667, 0xf4, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
-struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
.name = "Thomson dtt7610",
.min = 44000000,
.max = 958000000,
@@ -66,19 +88,19 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
{ 999999999, 62500, 0x8e, 0x3c },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
-static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
+static void thomson_dtt759x_bw(u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
- if (BANDWIDTH_7_MHZ == bandwidth)
+ if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
buf[3] |= 0x10;
}
-struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
.name = "Thomson dtt759x",
.min = 177000000,
.max = 896000000,
- .setbw = thomson_dtt759x_bw,
+ .set = thomson_dtt759x_bw,
.iffreq= 36166667,
.sleepdata = (u8[]){ 2, 0x84, 0x03 },
.count = 5,
@@ -90,9 +112,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
{ 999999999, 166667, 0xfc, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
-struct dvb_pll_desc dvb_pll_lg_z201 = {
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
.name = "LG z201",
.min = 174000000,
.max = 862000000,
@@ -107,9 +128,8 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
{ 999999999, 166667, 0xfc, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_lg_z201);
-struct dvb_pll_desc dvb_pll_microtune_4042 = {
+static struct dvb_pll_desc dvb_pll_microtune_4042 = {
.name = "Microtune 4042 FI5",
.min = 57000000,
.max = 858000000,
@@ -121,9 +141,8 @@ struct dvb_pll_desc dvb_pll_microtune_4042 = {
{ 999999999, 62500, 0x8e, 0x31 },
},
};
-EXPORT_SYMBOL(dvb_pll_microtune_4042);
-struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
.name = "Thomson dtt761x",
.min = 57000000,
@@ -137,9 +156,8 @@ struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
{ 999999999, 62500, 0x8e, 0x3c },
},
};
-EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
-struct dvb_pll_desc dvb_pll_unknown_1 = {
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */
.min = 174000000,
.max = 862000000,
@@ -157,12 +175,11 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
{ 999999999, 166667, 0xfc, 0x08 },
},
};
-EXPORT_SYMBOL(dvb_pll_unknown_1);
/* Infineon TUA6010XS
* used in Thomson Cable Tuner
*/
-struct dvb_pll_desc dvb_pll_tua6010xs = {
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
.name = "Infineon TUA6010XS",
.min = 44250000,
.max = 858000000,
@@ -174,10 +191,9 @@ struct dvb_pll_desc dvb_pll_tua6010xs = {
{ 999999999, 62500, 0x8e, 0x85 },
},
};
-EXPORT_SYMBOL(dvb_pll_tua6010xs);
/* Panasonic env57h1xd5 (some Philips PLL ?) */
-struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
.name = "Panasonic ENV57H1XD5",
.min = 44250000,
.max = 858000000,
@@ -190,23 +206,23 @@ struct dvb_pll_desc dvb_pll_env57h1xd5 = {
{ 999999999, 166667, 0xc2, 0xa4 },
},
};
-EXPORT_SYMBOL(dvb_pll_env57h1xd5);
/* Philips TDA6650/TDA6651
* used in Panasonic ENV77H11D5
*/
-static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
+static void tda665x_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_tda665x = {
+static struct dvb_pll_desc dvb_pll_tda665x = {
.name = "Philips TDA6650/TDA6651",
.min = 44250000,
.max = 858000000,
- .setbw = tda665x_bw,
+ .set = tda665x_bw,
.iffreq= 36166667,
+ .initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
.count = 12,
.entries = {
{ 93834000, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
@@ -223,36 +239,34 @@ struct dvb_pll_desc dvb_pll_tda665x = {
{ 861000000, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
}
};
-EXPORT_SYMBOL(dvb_pll_tda665x);
/* Infineon TUA6034
* used in LG TDTP E102P
*/
-static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
+static void tua6034_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (BANDWIDTH_7_MHZ != bandwidth)
+ if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_tua6034 = {
+static struct dvb_pll_desc dvb_pll_tua6034 = {
.name = "Infineon TUA6034",
.min = 44250000,
.max = 858000000,
.iffreq= 36166667,
.count = 3,
- .setbw = tua6034_bw,
+ .set = tua6034_bw,
.entries = {
{ 174500000, 62500, 0xce, 0x01 },
{ 230000000, 62500, 0xce, 0x02 },
{ 999999999, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
* used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
*/
-struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
.name = "LG TDVS-H06xF",
.min = 54000000,
.max = 863000000,
@@ -265,23 +279,25 @@ struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
{ 999999999, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
*/
-static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+static void fmd1216me_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+ params->frequency >= 158870000)
buf[3] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_fmd1216me = {
+static struct dvb_pll_desc dvb_pll_fmd1216me = {
.name = "Philips FMD1216ME",
.min = 50870000,
.max = 858000000,
.iffreq= 36125000,
- .setbw = fmd1216me_bw,
+ .set = fmd1216me_bw,
+ .initdata = tua603x_agc112,
+ .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
.count = 7,
.entries = {
{ 143870000, 166667, 0xbc, 0x41 },
@@ -293,23 +309,22 @@ struct dvb_pll_desc dvb_pll_fmd1216me = {
{ 999999999, 166667, 0xfc, 0x44 },
}
};
-EXPORT_SYMBOL(dvb_pll_fmd1216me);
/* ALPS TDED4
* used in Nebula-Cards and USB boxes
*/
-static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+static void tded4_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 0x04;
}
-struct dvb_pll_desc dvb_pll_tded4 = {
+static struct dvb_pll_desc dvb_pll_tded4 = {
.name = "ALPS TDED4",
.min = 47000000,
.max = 863000000,
.iffreq= 36166667,
- .setbw = tded4_bw,
+ .set = tded4_bw,
.count = 4,
.entries = {
{ 153000000, 166667, 0x85, 0x01 },
@@ -318,12 +333,11 @@ struct dvb_pll_desc dvb_pll_tded4 = {
{ 999999999, 166667, 0x85, 0x88 },
}
};
-EXPORT_SYMBOL(dvb_pll_tded4);
/* ALPS TDHU2
* used in AverTVHD MCE A180
*/
-struct dvb_pll_desc dvb_pll_tdhu2 = {
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
.name = "ALPS TDHU2",
.min = 54000000,
.max = 864000000,
@@ -336,16 +350,29 @@ struct dvb_pll_desc dvb_pll_tdhu2 = {
{ 999999999, 62500, 0x85, 0x88 },
}
};
-EXPORT_SYMBOL(dvb_pll_tdhu2);
/* Philips TUV1236D
* used in ATI HDTV Wonder
*/
-struct dvb_pll_desc dvb_pll_tuv1236d = {
+static void tuv1236d_rf(u8 *buf, const struct dvb_frontend_parameters *params)
+{
+ switch (params->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ buf[3] |= 0x08;
+ break;
+ case VSB_8:
+ default:
+ buf[3] &= ~0x08;
+ }
+}
+
+static struct dvb_pll_desc dvb_pll_tuv1236d = {
.name = "Philips TUV1236D",
.min = 54000000,
.max = 864000000,
.iffreq= 44000000,
+ .set = tuv1236d_rf,
.count = 3,
.entries = {
{ 157250000, 62500, 0xc6, 0x41 },
@@ -353,12 +380,11 @@ struct dvb_pll_desc dvb_pll_tuv1236d = {
{ 999999999, 62500, 0xc6, 0x44 },
},
};
-EXPORT_SYMBOL(dvb_pll_tuv1236d);
/* Samsung TBMV30111IN / TBMV30712IN1
* used in Air2PC ATSC - 2nd generation (nxt2002)
*/
-struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
.name = "Samsung TBMV30111IN / TBMV30712IN1",
.min = 54000000,
.max = 860000000,
@@ -373,12 +399,11 @@ struct dvb_pll_desc dvb_pll_samsung_tbmv = {
{ 999999999, 166667, 0xfc, 0x02 },
}
};
-EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
/*
* Philips SD1878 Tuner.
*/
-struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
.name = "Philips SD1878",
.min = 950000,
.max = 2150000,
@@ -391,19 +416,18 @@ struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
{ 2150000, 500, 0xc4, 0xc0},
},
};
-EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
/*
* Philips TD1316 Tuner.
*/
-static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+static void td1316_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
u8 band;
/* determine band */
- if (freq < 161000000)
+ if (params->frequency < 161000000)
band = 1;
- else if (freq < 444000000)
+ else if (params->frequency < 444000000)
band = 2;
else
band = 4;
@@ -411,16 +435,16 @@ static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
buf[3] |= band;
/* setup PLL filter */
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[3] |= 1 << 3;
}
-struct dvb_pll_desc dvb_pll_philips_td1316 = {
+static struct dvb_pll_desc dvb_pll_philips_td1316 = {
.name = "Philips TD1316",
.min = 87000000,
.max = 895000000,
.iffreq= 36166667,
- .setbw = td1316_bw,
+ .set = td1316_bw,
.count = 9,
.entries = {
{ 93834000, 166667, 0xca, 0x60},
@@ -434,10 +458,9 @@ struct dvb_pll_desc dvb_pll_philips_td1316 = {
{ 858834000, 166667, 0xca, 0xe0},
},
};
-EXPORT_SYMBOL(dvb_pll_philips_td1316);
/* FE6600 used on DViCO Hybrid */
-struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
.name = "Thomson FE6600",
.min = 44250000,
.max = 858000000,
@@ -450,19 +473,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
{ 999999999, 166667, 0xf4, 0x18 },
}
};
-EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
-static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+
+static void opera1_bw(u8 *buf, const struct dvb_frontend_parameters *params)
{
- if (bandwidth == BANDWIDTH_8_MHZ)
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
buf[2] |= 0x08;
}
-struct dvb_pll_desc dvb_pll_opera1 = {
+static struct dvb_pll_desc dvb_pll_opera1 = {
.name = "Opera Tuner",
.min = 900000,
.max = 2250000,
.iffreq= 0,
- .setbw = opera1_bw,
+ .set = opera1_bw,
.count = 8,
.entries = {
{ 1064000, 500, 0xe5, 0xc6 },
@@ -475,7 +498,54 @@ struct dvb_pll_desc dvb_pll_opera1 = {
{ 2250000, 500, 0xe5, 0xc4 },
}
};
-EXPORT_SYMBOL(dvb_pll_opera1);
+
+/* Philips FCV1236D
+ */
+struct dvb_pll_desc dvb_pll_fcv1236d = {
+/* Bit_0: RF Input select
+ * Bit_1: 0=digital, 1=analog
+ */
+ .name = "Philips FCV1236D",
+ .min = 53000000,
+ .max = 803000000,
+ .iffreq= 44000000,
+ .count = 3,
+ .entries = {
+ { 159000000, 62500, 0x8e, 0xa0 },
+ { 453000000, 62500, 0x8e, 0x90 },
+ { 999999999, 62500, 0x8e, 0x30 },
+ },
+};
+
+/* ----------------------------------------------------------- */
+
+static struct dvb_pll_desc *pll_list[] = {
+ [DVB_PLL_UNDEFINED] = NULL,
+ [DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579,
+ [DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x,
+ [DVB_PLL_THOMSON_DTT7610] = &dvb_pll_thomson_dtt7610,
+ [DVB_PLL_LG_Z201] = &dvb_pll_lg_z201,
+ [DVB_PLL_MICROTUNE_4042] = &dvb_pll_microtune_4042,
+ [DVB_PLL_THOMSON_DTT761X] = &dvb_pll_thomson_dtt761x,
+ [DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1,
+ [DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs,
+ [DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5,
+ [DVB_PLL_TUA6034] = &dvb_pll_tua6034,
+ [DVB_PLL_LG_TDVS_H06XF] = &dvb_pll_lg_tdvs_h06xf,
+ [DVB_PLL_TDA665X] = &dvb_pll_tda665x,
+ [DVB_PLL_FMD1216ME] = &dvb_pll_fmd1216me,
+ [DVB_PLL_TDED4] = &dvb_pll_tded4,
+ [DVB_PLL_TUV1236D] = &dvb_pll_tuv1236d,
+ [DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
+ [DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
+ [DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+ [DVB_PLL_PHILIPS_TD1316] = &dvb_pll_philips_td1316,
+ [DVB_PLL_THOMSON_FE6600] = &dvb_pll_thomson_fe6600,
+ [DVB_PLL_OPERA1] = &dvb_pll_opera1,
+ [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d,
+};
+
+/* ----------------------------------------------------------- */
struct dvb_pll_priv {
/* i2c details */
@@ -497,35 +567,37 @@ static int debug = 0;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
- u32 freq, int bandwidth)
+static int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+ const struct dvb_frontend_parameters *params)
{
u32 div;
int i;
- if (freq != 0 && (freq < desc->min || freq > desc->max))
- return -EINVAL;
+ if (params->frequency != 0 && (params->frequency < desc->min ||
+ params->frequency > desc->max))
+ return -EINVAL;
for (i = 0; i < desc->count; i++) {
- if (freq > desc->entries[i].limit)
+ if (params->frequency > desc->entries[i].limit)
continue;
break;
}
+
if (debug)
- printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
- desc->name, freq, bandwidth, i, desc->count);
+ printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+ params->frequency, i, desc->count);
if (i == desc->count)
return -EINVAL;
- div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
- desc->entries[i].stepsize;
+ div = (params->frequency + desc->iffreq +
+ desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
buf[0] = div >> 8;
buf[1] = div & 0xff;
buf[2] = desc->entries[i].config;
buf[3] = desc->entries[i].cb;
- if (desc->setbw)
- desc->setbw(buf, freq, bandwidth);
+ if (desc->set)
+ desc->set(buf, params);
if (debug)
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -534,7 +606,6 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
// calculate the frequency we set it to
return (div * desc->entries[i].stepsize) - desc->iffreq;
}
-EXPORT_SYMBOL(dvb_pll_configure);
static int dvb_pll_release(struct dvb_frontend *fe)
{
@@ -578,18 +649,12 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
{ .addr = priv->pll_i2c_address, .flags = 0,
.buf = buf, .len = sizeof(buf) };
int result;
- u32 bandwidth = 0, frequency = 0;
+ u32 frequency = 0;
if (priv->i2c == NULL)
return -EINVAL;
- // DVBT bandwidth only just now
- if (fe->ops.info.type == FE_OFDM) {
- bandwidth = params->u.ofdm.bandwidth;
- }
-
- if ((result = dvb_pll_configure(priv->pll_desc, buf,
- params->frequency, bandwidth)) < 0)
+ if ((result = dvb_pll_configure(priv->pll_desc, buf, params)) < 0)
return result;
else
frequency = result;
@@ -601,7 +666,7 @@ static int dvb_pll_set_params(struct dvb_frontend *fe,
}
priv->frequency = frequency;
- priv->bandwidth = bandwidth;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 0;
}
@@ -612,18 +677,12 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
{
struct dvb_pll_priv *priv = fe->tuner_priv;
int result;
- u32 bandwidth = 0, frequency = 0;
+ u32 frequency = 0;
if (buf_len < 5)
return -EINVAL;
- // DVBT bandwidth only just now
- if (fe->ops.info.type == FE_OFDM) {
- bandwidth = params->u.ofdm.bandwidth;
- }
-
- if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
- params->frequency, bandwidth)) < 0)
+ if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params)) < 0)
return result;
else
frequency = result;
@@ -631,7 +690,7 @@ static int dvb_pll_calc_regs(struct dvb_frontend *fe,
buf[0] = priv->pll_i2c_address;
priv->frequency = frequency;
- priv->bandwidth = bandwidth;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
return 5;
}
@@ -687,13 +746,18 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc)
+ unsigned int pll_desc_id)
{
u8 b1 [] = { 0 };
struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
.buf = b1, .len = 1 };
struct dvb_pll_priv *priv = NULL;
int ret;
+ struct dvb_pll_desc *desc;
+
+ BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+ desc = pll_list[pll_desc_id];
if (i2c != NULL) {
if (fe->ops.i2c_gate_ctrl)
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 5209f46f0893..e93a8104052b 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -8,50 +8,29 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-struct dvb_pll_desc {
- char *name;
- u32 min;
- u32 max;
- u32 iffreq;
- void (*setbw)(u8 *buf, u32 freq, int bandwidth);
- u8 *initdata;
- u8 *sleepdata;
- int count;
- struct {
- u32 limit;
- u32 stepsize;
- u8 config;
- u8 cb;
- } entries[12];
-};
-
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
-extern struct dvb_pll_desc dvb_pll_lg_z201;
-extern struct dvb_pll_desc dvb_pll_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
-extern struct dvb_pll_desc dvb_pll_unknown_1;
-
-extern struct dvb_pll_desc dvb_pll_tua6010xs;
-extern struct dvb_pll_desc dvb_pll_env57h1xd5;
-extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
-extern struct dvb_pll_desc dvb_pll_tda665x;
-extern struct dvb_pll_desc dvb_pll_fmd1216me;
-extern struct dvb_pll_desc dvb_pll_tded4;
-
-extern struct dvb_pll_desc dvb_pll_tuv1236d;
-extern struct dvb_pll_desc dvb_pll_tdhu2;
-extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
-extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
-extern struct dvb_pll_desc dvb_pll_philips_td1316;
-
-extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-extern struct dvb_pll_desc dvb_pll_opera1;
-
-extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
- u32 freq, int bandwidth);
+#define DVB_PLL_UNDEFINED 0
+#define DVB_PLL_THOMSON_DTT7579 1
+#define DVB_PLL_THOMSON_DTT759X 2
+#define DVB_PLL_THOMSON_DTT7610 3
+#define DVB_PLL_LG_Z201 4
+#define DVB_PLL_MICROTUNE_4042 5
+#define DVB_PLL_THOMSON_DTT761X 6
+#define DVB_PLL_UNKNOWN_1 7
+#define DVB_PLL_TUA6010XS 8
+#define DVB_PLL_ENV57H1XD5 9
+#define DVB_PLL_TUA6034 10
+#define DVB_PLL_LG_TDVS_H06XF 11
+#define DVB_PLL_TDA665X 12
+#define DVB_PLL_FMD1216ME 13
+#define DVB_PLL_TDED4 14
+#define DVB_PLL_TUV1236D 15
+#define DVB_PLL_TDHU2 16
+#define DVB_PLL_SAMSUNG_TBMV 17
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
+#define DVB_PLL_PHILIPS_TD1316 19
+#define DVB_PLL_THOMSON_FE6600 20
+#define DVB_PLL_OPERA1 21
+#define DVB_PLL_FCV1236D 22
/**
* Attach a dvb-pll to the supplied frontend structure.
@@ -59,19 +38,19 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
* @param fe Frontend to attach to.
* @param pll_addr i2c address of the PLL (if used).
* @param i2c i2c adapter to use (set to NULL if not used).
- * @param desc dvb_pll_desc to use.
+ * @param pll_desc_id dvb_pll_desc to use.
* @return Frontend pointer on success, NULL on failure
*/
#if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc);
+ unsigned int pll_desc_id);
#else
static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
int pll_addr,
struct i2c_adapter *i2c,
- struct dvb_pll_desc *desc)
+ unsigned int pll_desc_id)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
return NULL;
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index b809f83d9563..ddc84899cf86 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -49,7 +49,6 @@
#include <linux/string.h>
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "nxt200x.h"
struct nxt200x_state {
@@ -546,11 +545,6 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
nxt200x_writebytes(state, 0x17, buf, 1);
}
- /* get tuning information */
- if (fe->ops.tuner_ops.calc_regs) {
- fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
- }
-
/* set additional params */
switch (p->u.vsb.modulation) {
case QAM_64:
@@ -559,27 +553,24 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
/* This is just a guess since I am unable to test it */
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 1);
-
- /* set input */
- if (state->config->set_pll_input)
- state->config->set_pll_input(buf+1, 1);
break;
case VSB_8:
/* Set non-punctured clock for VSB */
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
-
- /* set input */
- if (state->config->set_pll_input)
- state->config->set_pll_input(buf+1, 0);
break;
default:
return -EINVAL;
break;
}
- /* write frequency information */
- nxt200x_writetuner(state, buf);
+ if (fe->ops.tuner_ops.calc_regs) {
+ /* get tuning information */
+ fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+
+ /* write frequency information */
+ nxt200x_writetuner(state, buf);
+ }
/* reset the agc now that tuning has been completed */
nxt200x_agc_reset(state);
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 28bc5591b319..bb0ef58d7972 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,9 +38,6 @@ struct nxt200x_config
/* the demodulator's i2c address */
u8 demod_address;
- /* used to set pll input */
- int (*set_pll_input)(u8* buf, int input);
-
/* need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 4e0aca7c67aa..3cc8b444b8f2 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -45,7 +45,6 @@
#include "dvb_math.h"
#include "dvb_frontend.h"
-#include "dvb-pll.h"
#include "or51132.h"
static int debug;
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 048d7cfe12d3..f46d5a46683a 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -223,38 +223,13 @@ static int or51211_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
struct or51211_state* state = fe->demodulator_priv;
- u32 freq = 0;
- u16 tunerfreq = 0;
- u8 buf[4];
/* Change only if we are actually changing the channel */
if (state->current_frequency != param->frequency) {
- freq = 44000 + (param->frequency/1000);
- tunerfreq = freq * 16/1000;
-
- dprintk("set_parameters frequency = %d (tunerfreq = %d)\n",
- param->frequency,tunerfreq);
-
- buf[0] = (tunerfreq >> 8) & 0x7F;
- buf[1] = (tunerfreq & 0xFF);
- buf[2] = 0x8E;
-
- if (param->frequency < 157250000) {
- buf[3] = 0xA0;
- dprintk("set_parameters VHF low range\n");
- } else if (param->frequency < 454000000) {
- buf[3] = 0x90;
- dprintk("set_parameters VHF high range\n");
- } else {
- buf[3] = 0x30;
- dprintk("set_parameters UHF range\n");
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
- "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
-
- if (i2c_writebytes(state,0xC2>>1,buf,4))
- printk(KERN_WARNING "or51211:set_parameters error "
- "writing to tuner\n");
/* Set to ATSC mode */
or51211_setmode(fe,0);
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 18768d2f6d40..6c607302c1b6 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -249,7 +249,7 @@ static int stv0299_get_symbolrate (struct stv0299_state* state)
dprintk ("%s\n", __FUNCTION__);
stv0299_readregs (state, 0x1f, sfr, 3);
- stv0299_readregs (state, 0x1a, &rtf, 1);
+ stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
srate = (sfr[0] << 8) | sfr[1];
srate *= Mclk;
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index da796e784be3..4bb06f97938b 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -478,7 +478,7 @@ struct dvb_frontend* tda10023_attach(const struct tda1002x_config* config,
state->i2c = i2c;
memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
state->pwm = pwm;
- for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+ for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
if (tda10023_inittab[i] == 0x00) {
state->reg0 = tda10023_inittab[i+2];
break;
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
index ce6a9aaf937e..7ac128724df8 100644
--- a/drivers/media/dvb/pluto2/Makefile
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7751628e1415..6d53289b3276 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -108,7 +108,7 @@ config DVB_BUDGET_AV
tristate "Budget cards with analog video inputs"
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146_VV
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_TDA10021 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index aa85ecdc6c80..2c1145236ee6 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-core.o budget-ci.o ttpci-eeprom.o
obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index ef1108c0bf11..8178832d14a8 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -137,6 +137,15 @@ static void init_av7110_av(struct av7110 *av7110)
if (ret < 0)
printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+ 1, (u16) av7110->display_ar);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to set aspect ratio\n");
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+ 1, av7110->display_panscan);
+ if (ret < 0)
+ printk("dvb-ttpci: unable to set pan scan\n");
+
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
if (ret < 0)
printk("dvb-ttpci: unable to configure 4:3 wss\n");
@@ -2258,7 +2267,7 @@ static int frontend_init(struct av7110 *av7110)
FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
- FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
@@ -2639,12 +2648,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
av7110->mixer.volume_left = volume;
av7110->mixer.volume_right = volume;
- init_av7110_av(av7110);
-
ret = av7110_register(av7110);
if (ret < 0)
goto err_arm_thread_stop_10;
+ init_av7110_av(av7110);
+
/* special case DVB-C: these cards have an analog tuner
plus need some special handling, so we have separate
saa7146_ext_vv data for these... */
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 115002b0390c..0cb439527498 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -194,6 +194,7 @@ struct av7110 {
int video_blank;
struct video_status videostate;
+ u16 display_panscan;
int display_ar;
int trickmode;
#define TRICK_NONE 0
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 58678c05aa53..d75e7e48addc 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -391,7 +391,7 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
****************************************************************************/
static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
- const char *buf, unsigned long count)
+ const u8 *buf, unsigned long count)
{
unsigned long todo = count;
int free;
@@ -436,7 +436,7 @@ static void play_audio_cb(u8 *buf, int count, void *priv)
#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
-static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
@@ -499,7 +499,7 @@ static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
return count - todo;
}
-static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
@@ -959,7 +959,7 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x
#define MIN_IFRAME 400000
-static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock)
+static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
{
int i, n;
@@ -1082,19 +1082,18 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_SET_DISPLAY_FORMAT:
{
video_displayformat_t format = (video_displayformat_t) arg;
- u16 val = 0;
switch (format) {
case VIDEO_PAN_SCAN:
- val = VID_PAN_SCAN_PREF;
+ av7110->display_panscan = VID_PAN_SCAN_PREF;
break;
case VIDEO_LETTER_BOX:
- val = VID_VC_AND_PS_PREF;
+ av7110->display_panscan = VID_VC_AND_PS_PREF;
break;
case VIDEO_CENTER_CUT_OUT:
- val = VID_CENTRE_CUT_PREF;
+ av7110->display_panscan = VID_CENTRE_CUT_PREF;
break;
default:
@@ -1104,7 +1103,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
break;
av7110->videostate.display_format = format;
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
- 1, (u16) val);
+ 1, av7110->display_panscan);
break;
}
@@ -1466,8 +1465,9 @@ int av7110_av_register(struct av7110 *av7110)
av7110->videostate.play_state = VIDEO_STOPPED;
av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
av7110->videostate.video_format = VIDEO_FORMAT_4_3;
- av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT;
+ av7110->videostate.display_format = VIDEO_LETTER_BOX;
av7110->display_ar = VIDEO_FORMAT_4_3;
+ av7110->display_panscan = VID_VC_AND_PS_PREF;
init_waitqueue_head(&av7110->video_events.wait_queue);
spin_lock_init(&av7110->video_events.lock);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index e1c1294bb767..c58e3fc509ed 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -151,7 +151,7 @@ static ssize_t ci_ll_write(struct dvb_ringbuffer *cibuf, struct file *file,
{
int free;
int non_blocking = file->f_flags & O_NONBLOCK;
- char *page = (char *)__get_free_page(GFP_USER);
+ u8 *page = (u8 *)__get_free_page(GFP_USER);
int res;
if (!page)
@@ -208,7 +208,7 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
return -EINVAL;
DVB_RINGBUFFER_SKIP(cibuf, 2);
- return dvb_ringbuffer_read(cibuf, buf, len, 1);
+ return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
}
static int dvb_ca_open(struct inode *inode, struct file *file)
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 70aee4eb5da4..515e8232e020 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -158,7 +158,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
}
dprintk(4, "writing DRAM block %d\n", i);
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
bootblock ^= 0x1400;
iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
@@ -173,10 +173,10 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
}
if (rest > 4)
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
else
mwdebi(av7110, DEBISWAB, bootblock,
- ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
+ ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
@@ -751,7 +751,7 @@ static int FlushText(struct av7110 *av7110)
return 0;
}
-static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
+static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
{
int i, ret;
unsigned long start;
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 673d9b3f064c..74d940f75da6 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -393,7 +393,7 @@ static inline void iwdebi(struct av7110 *av7110, u32 config, int addr, u32 val,
}
/* buffer writes */
-static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, char *val, int count)
+static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count)
{
memcpy(av7110->debi_virt, val, count);
av7110_debiwrite(av7110, config, addr, 0, count);
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index a97f166bb523..6322800ee12b 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -356,7 +356,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
input_dev->id.vendor = av7110->dev->pci->vendor;
input_dev->id.product = av7110->dev->pci->device;
}
- input_dev->cdev.dev = &av7110->dev->pci->dev;
+ input_dev->dev.parent = &av7110->dev->pci->dev;
/* initial keymap */
memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
input_register_keys(&av7110->ir);
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index fcd9994058d0..87afaebc0703 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -333,7 +333,7 @@ static int av7110_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg)
return -EINVAL;
memset(t, 0, sizeof(*t));
- strcpy(t->name, "Television");
+ strcpy((char *)t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 0e817d6f1ce5..0aee7a13a070 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -828,29 +828,6 @@ static u8 philips_sd1878_inittab[] = {
0xff, 0xff
};
-static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- u8 buf[4];
- int rc;
- struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
- struct budget *budget = (struct budget *) fe->dvb->priv;
-
- if((params->frequency < 950000) || (params->frequency > 2150000))
- return -EINVAL;
-
- rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
- params->frequency, 0);
- if(rc < 0) return rc;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
-
- return 0;
-}
-
static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
u32 srate, u32 ratio)
{
@@ -921,6 +898,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_CI 0x0016
#define SUBID_DVBS_EASYWATCH_1 0x001a
+#define SUBID_DVBS_EASYWATCH_2 0x001b
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_EASYWATCH 0x002a
@@ -982,10 +960,13 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBS_TV_STAR_CI:
case SUBID_DVBS_CYNERGY1200N:
case SUBID_DVBS_EASYWATCH:
+ case SUBID_DVBS_EASYWATCH_2:
fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
&budget_av->budget.i2c_adap);
if (fe) {
- fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+ dvb_attach(dvb_pll_attach, fe, 0x60,
+ &budget_av->budget.i2c_adap,
+ DVB_PLL_PHILIPS_SD1878_TDA8261);
}
break;
@@ -1264,6 +1245,7 @@ MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
@@ -1287,6 +1269,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+ MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 9d42f88ebb0e..873c3ba296f2 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -206,7 +206,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
input_dev->id.vendor = saa->pci->vendor;
input_dev->id.product = saa->pci->device;
}
- input_dev->cdev.dev = &saa->pci->dev;
+ input_dev->dev.parent = &saa->pci->dev;
/* Select keymap and address */
switch (budget_ci->budget.dev->pci->subsystem_device) {
diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile
index 6ab97f6b53fc..fbe2b9514c21 100644
--- a/drivers/media/dvb/ttusb-budget/Makefile
+++ b/drivers/media/dvb/ttusb-budget/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile
index b41bf1f06a9f..2d70a8269391 100644
--- a/drivers/media/dvb/ttusb-dec/Makefile
+++ b/drivers/media/dvb/ttusb-dec/Makefile
@@ -1,3 +1,3 @@
obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 194b102140ef..f8bf9fe37d36 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -324,8 +324,8 @@ config RADIO_ZOLTRIX_PORT
Enter the I/O port of your Zoltrix radio card.
config USB_DSBR
- tristate "D-Link USB FM radio support (EXPERIMENTAL)"
- depends on USB && VIDEO_V4L2 && EXPERIMENTAL
+ tristate "D-Link/GemTek USB FM radio support"
+ depends on USB && VIDEO_V4L2
---help---
Say Y here if you want to connect this type of radio to your
computer's USB port. Note that the audio is not digital, and
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 5adc27c3ced9..f0a67e93d7fd 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -63,7 +63,7 @@ struct rt_device
static void sleep_delay(long n)
{
/* Sleep nicely for 'n' uS */
- int d=n/(1000000/HZ);
+ int d=n/msecs_to_jiffies(1000);
if(!d)
udelay(n);
else
@@ -392,7 +392,6 @@ static struct video_device rtrack_radio=
.owner = THIS_MODULE,
.name = "RadioTrack radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &rtrack_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 9f1addae6928..9b1f7a99dac0 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -355,7 +355,6 @@ static struct video_device aztech_radio=
.owner = THIS_MODULE,
.name = "Aztech radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &aztech_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8cf2e9df5c8a..34e317ced5a3 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -329,7 +329,7 @@ cadet_handler(unsigned long data)
init_timer(&readtimer);
readtimer.function=cadet_handler;
readtimer.data=(unsigned long)0;
- readtimer.expires=jiffies+(HZ/20);
+ readtimer.expires=jiffies+msecs_to_jiffies(50);
add_timer(&readtimer);
}
@@ -349,7 +349,7 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
init_timer(&readtimer);
readtimer.function=cadet_handler;
readtimer.data=(unsigned long)0;
- readtimer.expires=jiffies+(HZ/20);
+ readtimer.expires=jiffies+msecs_to_jiffies(50);
add_timer(&readtimer);
}
if(rdsin==rdsout) {
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index fdf5d6e46eac..99a323131333 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -94,8 +94,6 @@ struct gemtek_pci_card {
u32 iobase;
u32 length;
- u8 chiprev;
- u16 model;
u32 current_frequency;
u8 mute;
@@ -378,7 +376,6 @@ static struct video_device vdev_template = {
.owner = THIS_MODULE,
.name = "Gemtek PCI Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &gemtek_pci_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
@@ -415,9 +412,6 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
goto err_pci;
}
- pci_read_config_byte( pci_dev, PCI_REVISION_ID, &card->chiprev );
- pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
-
pci_set_drvdata( pci_dev, card );
if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
@@ -436,7 +430,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
gemtek_pci_mute( card );
printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
- card->chiprev, card->iobase, card->iobase + card->length - 1 );
+ pci_dev->revision, card->iobase, card->iobase + card->length - 1 );
return 0;
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index b04b6a7fff7c..eab8c80a2e47 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -330,7 +330,6 @@ static struct video_device gemtek_radio=
.owner = THIS_MODULE,
.name = "GemTek radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &gemtek_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 9b493b3298cd..82aedfc95d4f 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -297,7 +297,6 @@ static struct video_device rtrack2_radio=
.owner = THIS_MODULE,
.name = "RadioTrack II radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &rtrack2_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index dc33f19c0e2c..395165367f37 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -297,7 +297,6 @@ static struct video_device fmi_radio=
.owner = THIS_MODULE,
.name = "SF16FMx radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &fmi_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index e6c125def5cb..c432c44bd634 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -442,7 +442,6 @@ static struct video_device fmr2_radio=
.owner = THIS_MODULE,
.name = "SF16FMR2 radio",
. type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &fmr2_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index e43acfd7e533..7e1911c3d54e 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -369,7 +369,6 @@ static struct video_device terratec_radio=
.owner = THIS_MODULE,
.name = "TerraTec ActiveRadio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &terratec_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index c27c629d99df..c11981fed827 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -349,7 +349,6 @@ static struct video_device trust_radio=
.owner = THIS_MODULE,
.name = "Trust FM Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &trust_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 8ff5a23a9f01..1366326474e5 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -349,7 +349,6 @@ static struct video_device typhoon_radio =
.owner = THIS_MODULE,
.name = "Typhoon Radio",
.type = VID_TYPE_TUNER,
- .hardware = 0,
.fops = &typhoon_fops,
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4d45a40016de..9dcbffd0aa15 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -489,6 +489,15 @@ config TUNER_3036
Say Y here to include support for Philips SAB3036 compatible tuners.
If in doubt, say N.
+config TUNER_TEA5761
+ bool "TEA 5761 radio tuner (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ depends on I2C
+ select VIDEO_TUNER
+ help
+ Say Y here to include support for Philips TEA5761 radio tuner.
+ If in doubt, say N.
+
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9c2de501612f..10b4d4469016 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -7,6 +7,8 @@ zr36067-objs := zoran_procfs.o zoran_device.o \
tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
mt20xx.o tda8290.o tea5767.o tda9887.o
+tuner-$(CONFIG_TUNER_TEA5761) += tea5761.o
+
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
@@ -16,7 +18,7 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
endif
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
@@ -59,7 +61,7 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 823cd6cc471e..cbab53fc6243 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -38,23 +38,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(x) (x)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 05c7820fe53e..0d0c554bfdf7 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -34,23 +34,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 59a43603b5cb..12d1b9248be5 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -38,23 +38,24 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
+
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 853b1a3d6a1d..e1028a76c042 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -38,23 +38,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 2e4cf1efdd21..b767b098d14b 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -257,7 +257,7 @@ static int bt866_write(struct bt866 *encoder,
printk(KERN_WARNING "%s: I/O error #%d "
"(write 0x%02x/0x%02x)\n",
encoder->i2c->name, err, encoder->addr, subaddr);
- schedule_timeout_interruptible(HZ/10);
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
}
if (err == 3) {
printk(KERN_WARNING "%s: giving up\n",
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 6b31e50fb951..387cb2122d4f 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -178,8 +178,8 @@ static struct CARD {
/* this seems to happen as well ... */
{ 0xff1211bd, BTTV_BOARD_PINNACLE, "Pinnacle PCTV" },
- { 0x3000121a, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
- { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM/ VoodooTV 200" },
+ { 0x3000121a, BTTV_BOARD_VOODOOTV_200, "3Dfx VoodooTV 200" },
+ { 0x263710b4, BTTV_BOARD_VOODOOTV_FM, "3Dfx VoodooTV FM" },
{ 0x3060121a, BTTV_BOARD_STB2, "3Dfx VoodooTV 100/ STB OEM" },
{ 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
@@ -313,6 +313,7 @@ static struct CARD {
{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
+ { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" },
{ 0, -1, NULL }
};
@@ -329,7 +330,7 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -344,7 +345,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 2, 0, 0, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -359,7 +360,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -387,13 +388,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = 4,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -408,7 +409,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 0, 1 },
.gpiomute = 3,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -423,7 +424,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x0c, 0x04, 0x08, 0x04 },
/* 0x04 for some cards ?? */
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = avermedia_tvphone_audio,
@@ -433,13 +434,13 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX-Vision MV-Delta",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -457,7 +458,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -488,7 +489,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 4,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -503,7 +504,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x20001,0x10001, 0, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -519,7 +520,7 @@ struct tvcard bttv_tvcards[] = {
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 13, 14, 11, 7 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -553,7 +554,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 4,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -568,7 +569,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0, 1, 0 },
.gpiomute = 10,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -587,7 +588,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x002000,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
},
[BTTV_BOARD_WINVIEW_601] = {
.name = "Leadtek WinView 601",
@@ -600,7 +601,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
.gpiomute = 0xcfa007,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = winview_audio,
@@ -616,7 +617,7 @@ struct tvcard bttv_tvcards[] = {
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 1, 0, 0, 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -624,13 +625,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
.video_inputs = 4,
.audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x8dff00,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.no_msp34xx = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -643,7 +644,7 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -674,7 +675,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -683,7 +684,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 7,
.muxsel = { 2, 3, -1 },
.digital_mode = DIGITAL_MODE_CAMERA,
@@ -708,7 +709,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xc00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -740,7 +741,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -813,13 +814,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Imagenation PXC200",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1, /* was: 4 */
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0},
.gpiomux = { 0 },
.needs_tvaudio = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = PXC200_muxsel,
@@ -836,7 +837,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x0800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -860,13 +861,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Intel Create and Share PCI/ Smart Video Recorder III",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = 4,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -911,7 +912,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.pll = PLL_28,
.has_radio = 1,
- .tuner_type = 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+ .tuner_type = TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = winfast2000_audio,
@@ -928,7 +929,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -945,7 +946,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -962,7 +963,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x29,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -978,7 +979,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x551c00,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -995,7 +996,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1030,7 +1031,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 13, 4, 11, 7 },
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -1048,7 +1049,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1063,7 +1064,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
.gpiomute = 0xff3ffc,
.no_msp34xx = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1074,14 +1075,14 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 3,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 1, 1, 0, 2 },
.gpiomute = 3,
.no_msp34xx = 1,
.pll = PLL_NONE,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1089,14 +1090,14 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX-Vision MV-Delta 2",
.video_inputs = 5,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1112,7 +1113,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0xbcb03f,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 21,
+ .tuner_type = TUNER_TEMIC_4039FR5_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1129,7 +1130,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_35,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -1148,7 +1149,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1206,7 +1207,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 1, 2, 3 },
.gpiomute = 4,
.pll = PLL_28,
- .tuner_type = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+ .tuner_type = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1234,7 +1235,7 @@ struct tvcard bttv_tvcards[] = {
1= FM stereo Radio from Tuner */
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1277,7 +1278,7 @@ struct tvcard bttv_tvcards[] = {
0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
0x0880: Tuner A2 stereo */
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1313,7 +1314,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0x800, 0x1000, 0x1000 },
.gpiomute = 0x1800,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1324,7 +1325,7 @@ struct tvcard bttv_tvcards[] = {
.name = "GrandTec 'Grand Video Capture' (Bt848)",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.gpiomask = 0,
.muxsel = { 3, 1 },
@@ -1332,7 +1333,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_35,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1365,7 +1366,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 2, 0, 0, 0 },
.gpiomute = 1,
.pll = PLL_28,
- .tuner_type = 0,
+ .tuner_type = TUNER_TEMIC_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1377,7 +1378,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 2,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 11,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 2, 0, 0, 1 },
@@ -1392,7 +1393,7 @@ struct tvcard bttv_tvcards[] = {
.name = "AG Electronics GMV1",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.gpiomask = 0xF,
.muxsel = { 2, 2 },
@@ -1400,7 +1401,7 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.needs_tvaudio = 0,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1447,7 +1448,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 1,
.muxsel = { 2, 3, 0, 1 },
.gpiomux = { 0, 0, 1, 0 },
@@ -1476,7 +1477,7 @@ struct tvcard bttv_tvcards[] = {
.no_tda9875 = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1517,13 +1518,35 @@ struct tvcard bttv_tvcards[] = {
/* ---- card 0x44 ---------------------------------- */
[BTTV_BOARD_VOODOOTV_FM] = {
- .name = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+ .name = "3Dfx VoodooTV FM (Euro)",
+ /* try "insmod msp3400 simple=0" if you have
+ * sound problems with this card. */
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = UNSET,
+ .gpiomask = 0x4f8a00,
+ /* 0x100000: 1=MSP enabled (0=disable again)
+ * 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+ .gpiomux = {0x947fff, 0x987fff,0x947fff,0x947fff },
+ .gpiomute = 0x947fff,
+ /* tvtuner, radio, external,internal, mute, stereo
+ * tuner, Composit, SVid, Composit-on-Svid-adapter */
+ .muxsel = { 2, 3 ,0 ,1 },
+ .tuner_type = TUNER_MT2032,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ },
+ [BTTV_BOARD_VOODOOTV_200] = {
+ .name = "VoodooTV 200 (USA)",
/* try "insmod msp3400 simple=0" if you have
* sound problems with this card. */
.video_inputs = 4,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0x4f8a00,
/* 0x100000: 1=MSP enabled (0=disable again)
* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1543,8 +1566,8 @@ struct tvcard bttv_tvcards[] = {
.name = "Active Imaging AIMMS",
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -1564,7 +1587,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 13,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 25,
+ .tuner_type = TUNER_LG_PAL_I_FM,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_remote = 1,
@@ -1580,7 +1603,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Lifeview FlyVideo 98EZ (capture only) LR51",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.muxsel = { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
.pll = PLL_28,
@@ -1606,7 +1629,7 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.no_tda9875 = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = pvbt878p9b_audio, /* Note: not all cards have stereo */
@@ -1626,13 +1649,13 @@ struct tvcard bttv_tvcards[] = {
.name = "Sensoray 311",
.video_inputs = 5,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 4,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1641,15 +1664,15 @@ struct tvcard bttv_tvcards[] = {
.name = "RemoteVision MX (RV605)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x00,
.gpiomask2 = 0x07ff,
.muxsel = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
.no_msp34xx = 1,
.no_tda9875 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = rv605_muxsel,
@@ -1693,15 +1716,15 @@ struct tvcard bttv_tvcards[] = {
.name = "GrandTec Multi Capture Card (Bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1724,7 +1747,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
/* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
@@ -1744,10 +1767,10 @@ struct tvcard bttv_tvcards[] = {
/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
.name = "DSP Design TCVIDEO",
.video_inputs = 4,
- .svhs = -1,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -1762,7 +1785,7 @@ struct tvcard bttv_tvcards[] = {
.muxsel = { 2, 0, 1, 1 },
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1791,11 +1814,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
.video_inputs = 4, /* id-inputs-clock */
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 3,
.muxsel = { 3, 2, 0, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1806,11 +1829,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
.video_inputs = 3,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.muxsel = { 2, 3, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1823,11 +1846,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 101 (848)", /* 0x05-40C0-C1 */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 3, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1838,11 +1861,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 101/151", /* 0x1(4|5)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1853,11 +1876,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 101/151 w/ svid", /* 0x(16|17|20)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1868,8 +1891,8 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 200/201/250/251", /* 0x1(8|9|E|F)-0004-C4 */
.video_inputs = 1,
.audio_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0 },
.pll = PLL_28,
.tuner_type = UNSET,
@@ -1885,7 +1908,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 200/250", /* 0x1(A|B)-00C4-C1 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 0, 1 },
.pll = PLL_28,
@@ -1900,7 +1923,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
@@ -1915,11 +1938,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 500", /* 500 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1930,9 +1953,9 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 540", /* 540 */
.video_inputs = 4,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -1945,7 +1968,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 2000", /* 2000 */
.video_inputs = 2,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 3 },
.pll = PLL_28,
@@ -1961,11 +1984,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IDS Eagle",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 0, 1, 2, 3 },
.muxsel_hook = eagle_muxsel,
@@ -1978,8 +2001,8 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 0,
.svhs = 1,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.no_msp34xx = 1,
@@ -2020,13 +2043,13 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 3,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 7,
.muxsel = { 2, 3, 1, 1},
.gpiomux = { 0, 1, 2, 3},
.gpiomute = 4,
.needs_tvaudio = 1,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2035,7 +2058,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Euresys Picolo",
.video_inputs = 3,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 2,
.gpiomask = 0,
.no_msp34xx = 1,
@@ -2052,8 +2075,8 @@ struct tvcard bttv_tvcards[] = {
.name = "ProVideo PV150", /* 0x4f */
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3 },
.gpiomux = { 0 },
@@ -2080,7 +2103,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 2,
+ .tuner_type = TUNER_PHILIPS_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.audio_hook = adtvk503_audio,
@@ -2098,7 +2121,7 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 1,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
/* Notes:
@@ -2121,7 +2144,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = 1,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_radio = 1,
@@ -2138,11 +2161,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IVC-200",
.video_inputs = 1,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xdf,
.muxsel = { 2 },
.pll = PLL_28,
@@ -2151,9 +2174,9 @@ struct tvcard bttv_tvcards[] = {
.name = "Grand X-Guard / Trust 814PCI",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = 4,
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.gpiomask2 = 0xff,
@@ -2169,14 +2192,14 @@ struct tvcard bttv_tvcards[] = {
[BTTV_BOARD_NEBULA_DIGITV] = {
.name = "Nebula Electronics DigiTV",
.video_inputs = 1,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
@@ -2189,15 +2212,15 @@ struct tvcard bttv_tvcards[] = {
.name = "ProVideo PV143",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0 },
.needs_tvaudio = 0,
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2206,14 +2229,14 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009-X1 MiniDIN (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 0 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2221,14 +2244,14 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009-X1 Combi (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 3,
.gpiomask = 0x00,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2238,7 +2261,7 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009 MiniDIN (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2248,7 +2271,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2256,7 +2279,7 @@ struct tvcard bttv_tvcards[] = {
.name = "PHYTEC VD-009 Combi (bt878)",
.video_inputs = 10,
.audio_inputs = 0,
- .tuner = -1, /* card has no tuner */
+ .tuner = UNSET, /* card has no tuner */
.svhs = 9,
.gpiomask = 0x00,
.gpiomask2 = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2266,7 +2289,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0, 0, 0, 0 }, /* card has no audio */
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2274,11 +2297,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IVC-100",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xdf,
.muxsel = { 2, 3, 1, 0 },
.pll = PLL_28,
@@ -2288,11 +2311,11 @@ struct tvcard bttv_tvcards[] = {
.name = "IVC-120G",
.video_inputs = 16,
.audio_inputs = 0, /* card has no audio */
- .tuner = -1, /* card has no tuner */
- .tuner_type = -1,
+ .tuner = UNSET, /* card has no tuner */
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1, /* card has no svhs */
+ .svhs = UNSET, /* card has no svhs */
.needs_tvaudio = 0,
.no_msp34xx = 1,
.no_tda9875 = 1,
@@ -2333,7 +2356,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 3,
.audio_inputs = 0,
.svhs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.muxsel = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
.no_msp34xx = 1,
.no_tda9875 = 1,
@@ -2364,9 +2387,9 @@ struct tvcard bttv_tvcards[] = {
.name = "SIMUS GVC1100",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2395,14 +2418,14 @@ struct tvcard bttv_tvcards[] = {
.name = "LMLBT4",
.video_inputs = 4, /* IN1,IN2,IN3,IN4 */
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 3, 1, 0 },
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.needs_tvaudio = 0,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2452,8 +2475,8 @@ struct tvcard bttv_tvcards[] = {
.name = "Euresys Picolo Tetra",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0,
.gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
.no_msp34xx = 1,
@@ -2464,7 +2487,7 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.needs_tvaudio = 0,
.muxsel_hook = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2490,7 +2513,7 @@ struct tvcard bttv_tvcards[] = {
.name = "AVerMedia AVerTV DVB-T 771",
.video_inputs = 2,
.svhs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -2509,14 +2532,14 @@ struct tvcard bttv_tvcards[] = {
/* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
.name = "AverMedia AverTV DVB-T 761",
.video_inputs = 2,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
@@ -2528,8 +2551,8 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX Vision Sigma-SQ",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0,
.muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2537,7 +2560,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2546,15 +2569,15 @@ struct tvcard bttv_tvcards[] = {
.name = "MATRIX Vision Sigma-SLC",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0,
.muxsel = { 2, 2, 2, 2 },
.muxsel_hook = sigmaSLC_muxsel,
.gpiomux = { 0 },
.no_msp34xx = 1,
.pll = PLL_28,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2566,7 +2589,7 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 2,
.audio_inputs = 1,
.tuner = 0,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0xFF,
.muxsel = { 2, 3, 1, 1 },
.gpiomux = { 2, 0, 0, 0 },
@@ -2584,14 +2607,14 @@ struct tvcard bttv_tvcards[] = {
[BTTV_BOARD_DVICO_DVBT_LITE] = {
/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
.name = "DViCO FusionHDTV DVB-T Lite",
- .tuner = -1,
+ .tuner = UNSET,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.no_video = 1,
.has_dvb = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2634,14 +2657,14 @@ struct tvcard bttv_tvcards[] = {
.name = "Tibet Systems 'Progress DVR' CS16",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.muxsel_hook = tibetCS16_muxsel,
@@ -2661,11 +2684,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Kodicom 4400R (master)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
/* GPIO bits 0-9 used for analog switch:
* 00 - 03: camera selector
* 04 - 06: channel (controller) selector
@@ -2693,11 +2716,11 @@ struct tvcard bttv_tvcards[] = {
.name = "Kodicom 4400R (slave)",
.video_inputs = 16,
.audio_inputs = 0,
- .tuner = -1,
- .tuner_type = -1,
+ .tuner = UNSET,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
- .svhs = -1,
+ .svhs = UNSET,
.gpiomask = 0x010000,
.no_gpioirq = 1,
.muxsel = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2717,7 +2740,7 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.pll = PLL_28,
@@ -2824,7 +2847,7 @@ struct tvcard bttv_tvcards[] = {
.name = "Osprey 440",
.video_inputs = 1,
.audio_inputs = 1,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2 },
.pll = PLL_28,
@@ -2848,7 +2871,7 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
- .tuner_type = 2,
+ .tuner_type = TUNER_PHILIPS_NTSC,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2875,14 +2898,14 @@ struct tvcard bttv_tvcards[] = {
.name = "Hauppauge ImpactVCB (bt878)",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.gpiomask = 0x0f, /* old: 7 */
.muxsel = { 0, 1, 3, 2 }, /* Composite 0-3 */
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2914,10 +2937,10 @@ struct tvcard bttv_tvcards[] = {
.name = "SSAI Security Video Interface",
.video_inputs = 4,
.audio_inputs = 0,
- .tuner = -1,
- .svhs = -1,
+ .tuner = UNSET,
+ .svhs = UNSET,
.muxsel = { 0, 1, 2, 3 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
@@ -2925,13 +2948,31 @@ struct tvcard bttv_tvcards[] = {
.name = "SSAI Ultrasound Video Interface",
.video_inputs = 2,
.audio_inputs = 0,
- .tuner = -1,
+ .tuner = UNSET,
.svhs = 1,
.muxsel = { 2, 0, 1, 3 },
- .tuner_type = -1,
+ .tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
+ /* ---- card 0x94---------------------------------- */
+ [BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+ .name = "DViCO FusionHDTV 2",
+ .tuner = 0,
+ .tuner_type = TUNER_PHILIPS_ATSC, /* FCV1236D */
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1 },
+ .gpiomask = 0x00e00007,
+ .gpiomux = { 0x00400005, 0, 0x00000001, 0 },
+ .gpiomute = 0x00c00007,
+ .no_msp34xx = 1,
+ .no_tda9875 = 1,
+ .no_tda7432 = 1,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3040,7 +3081,7 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256])
static void flyvideo_gpio(struct bttv *btv)
{
int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
- int tuner=-1,ttype;
+ int tuner=UNSET,ttype;
gpio_inout(0xffffff, 0);
udelay(8); /* without this we would see the 0x1800 mask */
@@ -3085,7 +3126,7 @@ static void flyvideo_gpio(struct bttv *btv)
* gpio & 0x001000 output bit for audio routing */
if(is_capture_only)
- tuner=4; /* No tuner present */
+ tuner = TUNER_ABSENT; /* No tuner present */
printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
@@ -3093,7 +3134,7 @@ static void flyvideo_gpio(struct bttv *btv)
btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
is_capture_only?"yes":"no ");
- if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
+ if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
btv->tuner_type = tuner;
btv->has_radio = has_radio;
@@ -3302,6 +3343,7 @@ void __devinit bttv_init_card1(struct bttv *btv)
case BTTV_BOARD_HAUPPAUGE878:
boot_msp34xx(btv,5);
break;
+ case BTTV_BOARD_VOODOOTV_200:
case BTTV_BOARD_VOODOOTV_FM:
boot_msp34xx(btv,20);
break;
@@ -3328,10 +3370,9 @@ void __devinit bttv_init_card1(struct bttv *btv)
/* initialization part two -- after registering i2c bus */
void __devinit bttv_init_card2(struct bttv *btv)
{
- int tda9887;
int addr=ADDR_UNSET;
- btv->tuner_type = -1;
+ btv->tuner_type = UNSET;
if (BTTV_BOARD_UNKNOWN == btv->c.type) {
bttv_readee(btv,eeprom_data,0xa0);
@@ -3479,7 +3520,15 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
if (UNSET != tuner[btv->c.nr])
btv->tuner_type = tuner[btv->c.nr];
- printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
+
+ if (btv->tuner_type == TUNER_ABSENT ||
+ bttv_tvcards[btv->c.type].tuner == UNSET)
+ printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
+ else if(btv->tuner_type == UNSET)
+ printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+ else
+ printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
+ btv->tuner_type);
if (btv->tuner_type != UNSET) {
struct tuner_setup tun_setup;
@@ -3521,6 +3570,9 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (!autoload)
return;
+ if (bttv_tvcards[btv->c.type].tuner == UNSET)
+ return; /* no tuner or related drivers to load */
+
/* try to detect audio/fader chips */
if (!bttv_tvcards[btv->c.type].no_msp34xx &&
bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
@@ -3541,17 +3593,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
if (bttv_tvcards[btv->c.type].needs_tvaudio)
request_module("tvaudio");
- /* tuner modules */
- tda9887 = 0;
- if (btv->tda9887_conf)
- tda9887 = 1;
- if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
- bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0)
- tda9887 = 1;
- /* Hybrid DVB card, DOES have a tda9887 */
- if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
- tda9887 = 1;
- if (btv->tuner_type != UNSET)
+ if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
request_module("tuner");
}
@@ -3865,11 +3907,15 @@ void bttv_tda9880_setnorm(struct bttv *btv, int norm)
if(norm==VIDEO_MODE_NTSC) {
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
dprintk("bttv_tda9880_setnorm to NTSC\n");
}
else {
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+ bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
dprintk("bttv_tda9880_setnorm to PAL\n");
}
/* set GPIO according */
@@ -4163,7 +4209,7 @@ static int tea5757_read(struct bttv *btv)
bus_low(btv,btv->mbox_clk);
udelay(10);
- timeout= jiffies + HZ;
+ timeout= jiffies + msecs_to_jiffies(1000);
/* wait for DATA line to go low; error if it doesn't */
while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index b1fedb0f6431..cb555f2c40f9 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -1218,7 +1218,14 @@ audio_mux(struct bttv *btv, int input, int mute)
break;
case TVAUDIO_INPUT_TUNER:
default:
- route.input = MSP_INPUT_DEFAULT;
+ /* This is the only card that uses TUNER2, and afaik,
+ is the only difference between the VOODOOTV_FM
+ and VOODOOTV_200 */
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
+ route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+ MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
+ else
+ route.input = MSP_INPUT_DEFAULT;
break;
}
route.output = MSP_OUTPUT_DEFAULT;
@@ -1253,7 +1260,7 @@ i2c_vidiocschan(struct bttv *btv)
v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
- if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
+ if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
bttv_tda9880_setnorm(btv,btv->tvnorm);
}
@@ -1323,6 +1330,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
switch (btv->c.type) {
case BTTV_BOARD_VOODOOTV_FM:
+ case BTTV_BOARD_VOODOOTV_200:
bttv_tda9880_setnorm(btv,norm);
break;
}
@@ -2251,6 +2259,24 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
printk(KERN_INFO "bttv%d: ================== END STATUS CARD #%d ==================\n", btv->c.nr, btv->c.nr);
return 0;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ {
+ struct v4l2_register *reg = arg;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* bt848 has a 12-bit register space */
+ reg->reg &= 0xfff;
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ reg->val = btread(reg->reg);
+ else
+ btwrite(reg->val, reg->reg);
+ return 0;
+ }
+#endif
default:
return -ENOIOCTLCMD;
@@ -3561,6 +3587,8 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
case VIDIOC_LOG_STATUS:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
return bttv_common_ioctls(btv,cmd,arg);
default:
@@ -3943,6 +3971,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGAUDIO:
case VIDIOCSAUDIO:
case VIDIOC_LOG_STATUS:
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
return bttv_common_ioctls(btv,cmd,arg);
default:
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 6f74c8042bc3..4201552bc3c0 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -153,7 +153,7 @@ static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
{
if (ir->polling) {
setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
- ir->timer.expires = jiffies + HZ;
+ ir->timer.expires = jiffies + msecs_to_jiffies(1000);
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
@@ -313,7 +313,7 @@ int bttv_input_init(struct bttv *btv)
input_dev->id.vendor = btv->c.pci->vendor;
input_dev->id.product = btv->c.pci->device;
}
- input_dev->cdev.dev = &btv->c.pci->dev;
+ input_dev->dev.parent = &btv->c.pci->dev;
btv->remote = ir;
bttv_ir_start(btv, ir);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index f821ba69db99..dcc847dc2486 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -170,6 +170,8 @@
#define BTTV_BOARD_MACHTV_MAGICTV 0x90
#define BTTV_BOARD_SSAI_SECURITY 0x91
#define BTTV_BOARD_SSAI_ULTRASOUND 0x92
+#define BTTV_BOARD_VOODOOTV_200 0x93
+#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 8f44f02029be..5b25faca1504 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -33,12 +33,12 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
-#include <media/v4l2-common.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
#include <asm/scatterlist.h>
#include <asm/io.h>
+#include <media/v4l2-common.h>
#include <linux/device.h>
#include <media/video-buf.h>
@@ -284,8 +284,8 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define d2printk if (bttv_debug >= 2) printk
#define BTTV_MAX_FBUF 0x208000
-#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE (HZ) /* one second */
+#define BTTV_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+#define BTTV_FREE_IDLE msecs_to_jiffies(1000) /* one second */
struct bttv_pll_info {
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 925ff17efbbc..f76c6a6c3766 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -95,7 +95,7 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+ for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
if (qcam_ready1(qcam) == value)
return 0;
@@ -120,7 +120,7 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+ for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
if (qcam_ready2(qcam) == value)
return 0;
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index fd771c7a2fe2..a76bd786cf13 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -663,15 +663,13 @@ int cpia2_reset_camera(struct camera_data *cam)
cpia2_send_command(cam, &cmd);
}
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
if (cam->params.pnp_id.device_type == DEVICE_STV_672)
retval = apply_vp_patch(cam);
/* wait for vp to go to sleep */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
/***
* If this is a 676, apply VP5 fixes before we start streaming
@@ -720,8 +718,7 @@ int cpia2_reset_camera(struct camera_data *cam)
set_default_user_mode(cam);
/* Give VP time to wake up */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
set_all_properties(cam);
@@ -2227,15 +2224,13 @@ struct camera_data *cpia2_init_camera_struct(void)
{
struct camera_data *cam;
- cam = kmalloc(sizeof(*cam), GFP_KERNEL);
+ cam = kzalloc(sizeof(*cam), GFP_KERNEL);
if (!cam) {
ERR("couldn't kmalloc cpia2 struct\n");
return NULL;
}
- /* Default everything to 0 */
- memset(cam, 0, sizeof(struct camera_data));
cam->present = 1;
mutex_init(&cam->busy_lock);
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 1bda7ad9de11..92778cd1d735 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -105,7 +105,7 @@ static struct control_menu_info framerate_controls[] =
{ CPIA2_VP_FRAMERATE_25, "25 fps" },
{ CPIA2_VP_FRAMERATE_30, "30 fps" },
};
-#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
static struct control_menu_info flicker_controls[] =
{
@@ -113,7 +113,7 @@ static struct control_menu_info flicker_controls[] =
{ FLICKER_50, "50 Hz" },
{ FLICKER_60, "60 Hz" },
};
-#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
static struct control_menu_info lights_controls[] =
{
@@ -122,7 +122,7 @@ static struct control_menu_info lights_controls[] =
{ 128, "Bottom" },
{ 192, "Both" },
};
-#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
#define GPIO_LIGHTS_MASK 192
static struct v4l2_queryctrl controls[] = {
@@ -235,7 +235,7 @@ static struct v4l2_queryctrl controls[] = {
.default_value = 0,
},
};
-#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+#define NUM_CONTROLS (ARRAY_SIZE(controls))
/******************************************************************************
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 0f9d96963618..f750a543c961 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -47,7 +47,7 @@ config VIDEO_CX88_DVB
tristate "DVB/ATSC Support for cx2388x based TV cards"
depends on VIDEO_CX88 && DVB_CORE
select VIDEO_BUF_DVB
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_OR51132 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index a80b1cb1abe8..f2fcdb92ecce 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -56,8 +56,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
/* ------------------------------------------------------------------ */
-#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144
-#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
/* defines below are from ivtv-driver.h */
@@ -405,7 +404,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev)
u32 value;
int i;
- for (i = 0; i < dev->fw_size; i++) {
+ for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
memory_read(dev->core, i, &value);
if (value == signature[signaturecnt])
signaturecnt++;
@@ -453,15 +452,12 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
return -1;
}
- if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) &&
- (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) {
- dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n",
- firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE,
- OLD_BLACKBIRD_FIRM_IMAGE_SIZE);
+ if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+ dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+ firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
}
- dev->fw_size = firmware->size;
if (0 != memcmp(firmware->data, magic, 8)) {
dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index e61102dc8ad7..6a136ddbccf8 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1335,6 +1335,26 @@ struct cx88_board cx88_boards[] = {
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
},
+ [CX88_BOARD_ADSTECH_PTV_390] = {
+ .name = "ADS Tech Instant Video PCI",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DEBUG,
+ .vmux = 3,
+ .gpio0 = 0x04ff,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x07fa,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x07fa,
+ }},
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1641,6 +1661,10 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x1421,
.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
.card = CX88_BOARD_KWORLD_DVBS_100,
+ },{
+ .subvendor = 0x1421,
+ .subdevice = 0x0390,
+ .card = CX88_BOARD_ADSTECH_PTV_390,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index dbfe4dc9cf8c..1773b40467dc 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -35,9 +35,7 @@
#include "mt352.h"
#include "mt352_priv.h"
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-# include "cx88-vp3054-i2c.h"
-#endif
+#include "cx88-vp3054-i2c.h"
#include "zl10353.h"
#include "cx22702.h"
#include "or51132.h"
@@ -199,7 +197,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
.demod_init = dvico_dual_demod_init,
};
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { 0x89, 0x38, 0x38 };
@@ -223,64 +221,6 @@ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
-
- /* this message is to set up ATC and ALC */
- static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0,
- .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
- int err;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
-{
- struct cx8802_dev *dev= fe->dvb->priv;
- u8 buf[4];
- struct i2c_msg msg =
- { .addr = dev->core->pll_addr, .flags = 0,
- .buf = buf, .len = 4 };
- int err;
-
- /* Switch PLL to DVB mode */
- err = philips_fmd1216_pll_init(fe);
- if (err)
- return err;
-
- /* Tune PLL */
- dvb_pll_configure(dev->core->pll_desc, buf,
- params->frequency,
- params->u.ofdm.bandwidth);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-
- printk(KERN_WARNING "cx88-dvb: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, dev->core->pll_addr, buf[0], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
static struct mt352_config dntv_live_dvbt_pro_config = {
.demod_address = 0x0f,
.no_tuner = 1,
@@ -370,18 +310,8 @@ static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
return 0;
}
-static int nxt200x_set_pll_input(u8* buf, int input)
-{
- if (input)
- buf[3] |= 0x08;
- else
- buf[3] &= ~0x08;
- return 0;
-}
-
static struct nxt200x_config ati_hdtvwonder = {
.demod_address = 0x0a,
- .set_pll_input = nxt200x_set_pll_input,
.set_ts_params = nxt200x_set_ts_param,
};
@@ -456,7 +386,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt759x);
+ DVB_PLL_THOMSON_DTT759X);
}
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -469,7 +399,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
@@ -482,7 +412,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+ &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -491,7 +421,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
break;
}
/* ZL10353 replaces MT352 on later cards */
@@ -500,7 +430,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -511,7 +441,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
break;
}
/* ZL10353 replaces MT352 on later cards */
@@ -520,7 +450,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_thomson_dtt7579);
+ NULL, DVB_PLL_THOMSON_DTT7579);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -529,7 +459,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_lg_z201);
+ NULL, DVB_PLL_LG_Z201);
}
break;
case CX88_BOARD_KWORLD_DVB_T:
@@ -540,17 +470,16 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_unknown_1);
+ NULL, DVB_PLL_UNKNOWN_1);
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_fmd1216me;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&((struct vp3054_i2c_state *)dev->card_priv)->adap);
if (dev->dvb.frontend != NULL) {
- dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
}
#else
printk("%s: built without vp3054 support\n", dev->core->name);
@@ -563,7 +492,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_fe6600);
+ DVB_PLL_THOMSON_FE6600);
}
break;
case CX88_BOARD_PCHDTV_HD3000:
@@ -572,7 +501,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt761x);
+ DVB_PLL_THOMSON_DTT761X);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -594,7 +523,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_microtune_4042);
+ DVB_PLL_MICROTUNE_4042);
}
}
break;
@@ -614,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_thomson_dtt761x);
+ DVB_PLL_THOMSON_DTT761X);
}
}
break;
@@ -634,7 +563,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
}
}
break;
@@ -654,7 +583,7 @@ static int dvb_register(struct cx8802_dev *dev)
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
&dev->core->i2c_adap,
- &dvb_pll_lg_tdvs_h06xf);
+ DVB_PLL_LG_TDVS_H06XF);
}
}
break;
@@ -664,7 +593,7 @@ static int dvb_register(struct cx8802_dev *dev)
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tuv1236d);
+ NULL, DVB_PLL_TUV1236D);
}
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -705,10 +634,6 @@ static int dvb_register(struct cx8802_dev *dev)
return -1;
}
- if (dev->core->pll_desc) {
- dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
- dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
- }
/* Ensure all frontends negotiate bus access */
dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
@@ -778,11 +703,10 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
goto fail_core;
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+ /* If vp3054 isn't enabled, a stub will just return 0 */
err = vp3054_i2c_probe(dev);
if (0 != err)
goto fail_core;
-#endif
/* dvb stuff */
printk("%s/2: cx2388x based dvb card\n", core->name);
@@ -807,9 +731,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
/* dvb */
videobuf_dvb_unregister(&dev->dvb);
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
vp3054_i2c_remove(dev);
-#endif
return 0;
}
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 7919a1f9da06..78bbcfab9670 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -160,7 +160,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
-static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
.setsda = cx8800_bit_setsda,
.setscl = cx8800_bit_setscl,
.getsda = cx8800_bit_getsda,
@@ -171,18 +171,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
/* ----------------------------------------------------------------------- */
-static struct i2c_adapter cx8800_i2c_adap_template = {
- .name = "cx2388x",
- .owner = THIS_MODULE,
- .id = I2C_HW_B_CX2388x,
- .client_register = attach_inform,
- .client_unregister = detach_inform,
-};
-
-static struct i2c_client cx8800_i2c_client_template = {
- .name = "cx88xx internal",
-};
-
static char *i2c_devs[128] = {
[ 0x1c >> 1 ] = "lgdt330x",
[ 0x86 >> 1 ] = "tda9887/cx22702",
@@ -212,14 +200,9 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
/* Prevents usage of invalid delay values */
if (i2c_udelay<5)
i2c_udelay=5;
- cx8800_i2c_algo_template.udelay=i2c_udelay;
- memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
- sizeof(core->i2c_adap));
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
sizeof(core->i2c_algo));
- memcpy(&core->i2c_client, &cx8800_i2c_client_template,
- sizeof(core->i2c_client));
if (core->tuner_type != TUNER_ABSENT)
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
@@ -228,10 +211,16 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+ core->i2c_adap.owner = THIS_MODULE;
+ core->i2c_adap.id = I2C_HW_B_CX2388x;
+ core->i2c_adap.client_register = attach_inform;
+ core->i2c_adap.client_unregister = detach_inform;
+ core->i2c_algo.udelay = i2c_udelay;
core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap,core);
core->i2c_adap.algo_data = &core->i2c_algo;
core->i2c_client.adapter = &core->i2c_adap;
+ strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
cx8800_bit_setscl(core,1);
cx8800_bit_setsda(core,1);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 8136673fe9e8..f5d4a565346e 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -74,7 +74,8 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
/* read gpio value */
gpio = cx_read(ir->gpio_addr);
- if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+ switch (core->board) {
+ case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
/* This board apparently uses a combination of 2 GPIO
to represent the keys. Additionally, the second GPIO
can be used for parity.
@@ -90,9 +91,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
auxgpio = cx_read(MO_GP1_IO);
/* Take out the parity part */
gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
- } else
+ break;
+ case CX88_BOARD_WINFAST_DTV1000:
+ gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
auxgpio = gpio;
-
+ break;
+ default:
+ auxgpio = gpio;
+ }
if (ir->polling) {
if (ir->last_gpio == auxgpio)
return;
@@ -148,20 +154,16 @@ static void ir_timer(unsigned long data)
static void cx88_ir_work(struct work_struct *work)
{
struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
- unsigned long timeout;
cx88_ir_handle_key(ir);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
{
if (ir->polling) {
+ setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
INIT_WORK(&ir->work, cx88_ir_work);
- init_timer(&ir->timer);
- ir->timer.function = ir_timer;
- ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
}
if (ir->sampling) {
@@ -222,7 +224,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR1300:
case CX88_BOARD_HAUPPAUGE_HVR3000:
ir_codes = ir_codes_hauppauge_new;
ir_type = IR_TYPE_RC5;
@@ -236,6 +237,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->polling = 50; /* ms */
break;
case CX88_BOARD_WINFAST2000XP_EXPERT:
+ case CX88_BOARD_WINFAST_DTV1000:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
@@ -328,7 +330,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
input_dev->id.vendor = pci->vendor;
input_dev->id.product = pci->device;
}
- input_dev->cdev.dev = &pci->dev;
+ input_dev->dev.parent = &pci->dev;
/* record handles to ourself */
ir->core = core;
core->ir = ir;
@@ -442,7 +444,6 @@ void cx88_ir_irq(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR1300:
case CX88_BOARD_HAUPPAUGE_HVR3000:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 543b05ebc0e7..317a2a3f9cc1 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -336,7 +336,7 @@ static void cx8802_timeout(unsigned long data)
{
struct cx8802_dev *dev = (struct cx8802_dev*)data;
- dprintk(0, "%s\n",__FUNCTION__);
+ dprintk(1, "%s\n",__FUNCTION__);
if (debug)
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 259ea08e784f..1cc2d286a1cb 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -906,6 +906,7 @@ int cx88_audio_thread(void *data)
u32 mode = 0;
dprintk("cx88: tvaudio thread started\n");
+ set_freezable();
for (;;) {
msleep_interruptible(1000);
if (kthread_should_stop())
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 98fa35421bdd..06b233a7b20b 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1881,8 +1881,14 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
mutex_unlock(&core->lock);
/* start tvaudio thread */
- if (core->tuner_type != TUNER_ABSENT)
+ if (core->tuner_type != TUNER_ABSENT) {
core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+ if (IS_ERR(core->kthread)) {
+ err = PTR_ERR(core->kthread);
+ printk(KERN_ERR "Failed to create cx88 audio thread, err=%d\n",
+ err);
+ }
+ }
return 0;
fail_unreg:
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 82bc3a28aa22..cd0877636a32 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -94,7 +94,7 @@ static int vp3054_bit_getsda(void *data)
/* ----------------------------------------------------------------------- */
-static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
.setsda = vp3054_bit_setsda,
.setscl = vp3054_bit_setscl,
.getsda = vp3054_bit_getsda,
@@ -105,12 +105,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
/* ----------------------------------------------------------------------- */
-static struct i2c_adapter vp3054_i2c_adap_template = {
- .name = "cx2388x",
- .owner = THIS_MODULE,
- .id = I2C_HW_B_CX2388x,
-};
-
int vp3054_i2c_probe(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -125,8 +119,6 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
return -ENOMEM;
vp3054_i2c = dev->card_priv;
- memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
- sizeof(vp3054_i2c->adap));
memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
sizeof(vp3054_i2c->algo));
@@ -135,6 +127,8 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
strlcpy(vp3054_i2c->adap.name, core->name,
sizeof(vp3054_i2c->adap.name));
+ vp3054_i2c->adap.owner = THIS_MODULE;
+ vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
vp3054_i2c->algo.data = dev;
i2c_set_adapdata(&vp3054_i2c->adap, dev);
vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h
index 637a7d232238..be99c931dc3e 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.h
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h
@@ -30,5 +30,12 @@ struct vp3054_i2c_state {
};
/* ----------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
int vp3054_i2c_probe(struct cx8802_dev *dev);
void vp3054_i2c_remove(struct cx8802_dev *dev);
+#else
+static inline int vp3054_i2c_probe(struct cx8802_dev *dev)
+{ return 0; }
+static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
+{ }
+#endif
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 738d4f20c580..809126866a3e 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -209,6 +209,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_NORWOOD_MICRO 54
#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
#define CX88_BOARD_HAUPPAUGE_HVR1300 56
+#define CX88_BOARD_ADSTECH_PTV_390 57
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -258,7 +259,7 @@ struct cx88_subid {
#define RESOURCE_VIDEO 2
#define RESOURCE_VBI 4
-#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
/* buffer for one video frame */
struct cx88_buffer {
@@ -316,8 +317,6 @@ struct cx88_core {
/* config info -- dvb */
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
- struct dvb_pll_desc *pll_desc;
- unsigned int pll_addr;
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
#endif
@@ -463,13 +462,10 @@ struct cx8802_dev {
u32 mailbox;
int width;
int height;
- int fw_size;
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
/* for dvb only */
struct videobuf_dvb dvb;
- void* fe_handle;
- int (*fe_release)(void *handle);
void *card_priv;
#endif
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
index 664676f44068..dcc1a0335440 100644
--- a/drivers/media/video/et61x251/Kconfig
+++ b/drivers/media/video/et61x251/Kconfig
@@ -1,6 +1,6 @@
config USB_ET61X251
tristate "USB ET61X[12]51 PC Camera Controller support"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2
---help---
Say Y here if you want support for cameras based on Etoms ET61X151
or ET61X251 PC Camera Controllers.
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 262f98e12409..02c741d8f85a 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/kref.h>
#include "et61x251_sensor.h"
@@ -134,7 +135,7 @@ struct et61x251_module_param {
};
static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
+static DECLARE_RWSEM(et61x251_dev_lock);
struct et61x251_device {
struct video_device* v4ldev;
@@ -158,12 +159,14 @@ struct et61x251_device {
struct et61x251_sysfs_attr sysfs;
struct et61x251_module_param module_param;
+ struct kref kref;
enum et61x251_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
@@ -177,7 +180,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
void
et61x251_attach_sensor(struct et61x251_device* cam,
- struct et61x251_sensor* sensor)
+ const struct et61x251_sensor* sensor)
{
memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
}
@@ -195,8 +198,8 @@ do { \
else if ((level) == 2) \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
+ __FILE__, __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -205,8 +208,8 @@ do { \
if ((level) == 1 || (level) == 2) \
pr_info("et61x251: " fmt "\n", ## args); \
else if ((level) == 3) \
- pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
- __LINE__ , ## args); \
+ pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
+ __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -222,8 +225,8 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+ __LINE__ , ## args)
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index a6525513cd1e..585bd1fe0765 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -45,11 +45,11 @@
#define ET61X251_MODULE_NAME "V4L2 driver for ET61X[12]51 " \
"PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia"
+#define ET61X251_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.04"
-#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 4)
+#define ET61X251_MODULE_VERSION "1:1.09"
+#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 9)
/*****************************************************************************/
@@ -245,7 +245,8 @@ int et61x251_read_reg(struct et61x251_device* cam, u16 index)
static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+et61x251_i2c_wait(struct et61x251_device* cam,
+ const struct et61x251_sensor* sensor)
{
int i, r;
@@ -270,7 +271,7 @@ et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
int
et61x251_i2c_try_read(struct et61x251_device* cam,
- struct et61x251_sensor* sensor, u8 address)
+ const struct et61x251_sensor* sensor, u8 address)
{
struct usb_device* udev = cam->usbdev;
u8* data = cam->control_buffer;
@@ -303,7 +304,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam,
int
et61x251_i2c_try_write(struct et61x251_device* cam,
- struct et61x251_sensor* sensor, u8 address, u8 value)
+ const struct et61x251_sensor* sensor, u8 address,
+ u8 value)
{
struct usb_device* udev = cam->usbdev;
u8* data = cam->control_buffer;
@@ -615,7 +617,7 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
return 0;
free_urbs:
- for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
+ for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
usb_free_urb(cam->urb[i]);
free_buffers:
@@ -682,7 +684,7 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)
if (len < 4) {
strncpy(str, buff, len);
- str[len+1] = '\0';
+ str[len] = '\0';
} else {
strncpy(str, buff, 4);
str[4] = '\0';
@@ -977,30 +979,30 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
static int et61x251_create_sysfs(struct et61x251_device* cam)
{
- struct video_device *v4ldev = cam->v4ldev;
+ struct class_device *classdev = &(cam->v4ldev->class_dev);
int err = 0;
- if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+ if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
goto err_out;
- if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+ if ((err = class_device_create_file(classdev, &class_device_attr_val)))
goto err_reg;
if (cam->sensor.sysfs_ops) {
- if ((err = video_device_create_file(v4ldev,
+ if ((err = class_device_create_file(classdev,
&class_device_attr_i2c_reg)))
goto err_val;
- if ((err = video_device_create_file(v4ldev,
+ if ((err = class_device_create_file(classdev,
&class_device_attr_i2c_val)))
goto err_i2c_reg;
}
err_i2c_reg:
if (cam->sensor.sysfs_ops)
- video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+ class_device_remove_file(classdev, &class_device_attr_i2c_reg);
err_val:
- video_device_remove_file(v4ldev, &class_device_attr_val);
+ class_device_remove_file(classdev, &class_device_attr_val);
err_reg:
- video_device_remove_file(v4ldev, &class_device_attr_reg);
+ class_device_remove_file(classdev, &class_device_attr_reg);
err_out:
return err;
}
@@ -1103,7 +1105,8 @@ static int et61x251_init(struct et61x251_device* cam)
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
@@ -1177,64 +1180,80 @@ static int et61x251_init(struct et61x251_device* cam)
return 0;
}
+/*****************************************************************************/
-static void et61x251_release_resources(struct et61x251_device* cam)
+static void et61x251_release_resources(struct kref *kref)
{
+ struct et61x251_device *cam;
+
mutex_lock(&et61x251_sysfs_lock);
+ cam = container_of(kref, struct et61x251_device, kref);
+
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
+ kfree(cam->control_buffer);
+ kfree(cam);
mutex_unlock(&et61x251_sysfs_lock);
-
- kfree(cam->control_buffer);
}
-/*****************************************************************************/
static int et61x251_open(struct inode* inode, struct file* filp)
{
struct et61x251_device* cam;
int err = 0;
- /*
- This is the only safe way to prevent race conditions with
- disconnect
- */
- if (!down_read_trylock(&et61x251_disconnect))
+ if (!down_read_trylock(&et61x251_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&et61x251_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&et61x251_dev_lock);
return -ERESTARTSYS;
}
+ kref_get(&cam->kref);
+
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, et61x251_release_resources);
+ up_read(&et61x251_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(2, "Device /dev/video%d is already in use",
+ cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&et61x251_dev_lock);
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&et61x251_disconnect);
- return err;
- }
+ down_read(&et61x251_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&et61x251_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = et61x251_init(cam);
if (err) {
@@ -1259,36 +1278,32 @@ static int et61x251_open(struct inode* inode, struct file* filp)
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&et61x251_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, et61x251_release_resources);
+ up_read(&et61x251_dev_lock);
return err;
}
static int et61x251_release(struct inode* inode, struct file* filp)
{
- struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+ struct et61x251_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&et61x251_dev_lock);
- et61x251_stop_transfer(cam);
+ cam = video_get_drvdata(video_devdata(filp));
+ et61x251_stop_transfer(cam);
et61x251_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- et61x251_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, et61x251_release_resources);
+
+ up_write(&et61x251_dev_lock);
return 0;
}
@@ -1324,7 +1339,7 @@ et61x251_read(struct file* filp, char __user * buf,
DBG(3, "Close and open the device again to choose the read "
"method");
mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
+ return -EBUSY;
}
if (cam->io == IO_NONE) {
@@ -1504,7 +1519,12 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
return -EIO;
}
- if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+ mutex_unlock(&cam->fileop_mutex);
+ return -EACCES;
+ }
+
+ if (cam->io != IO_MMAP ||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
mutex_unlock(&cam->fileop_mutex);
return -EINVAL;
@@ -1535,7 +1555,6 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
vma->vm_ops = &et61x251_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
et61x251_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -1764,7 +1783,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
/* Preserve R,G or B origin */
@@ -1921,6 +1940,8 @@ et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+ 0 : V4L2_COLORSPACE_SRGB;
pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
? 0 : (pfmt->width * pfmt->priv) / 8;
pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
@@ -1996,6 +2017,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
pix->pixelformat = pfmt->pixelformat;
pix->priv = pfmt->priv; /* bpp */
+ pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+ 0 : V4L2_COLORSPACE_SRGB;
pix->colorspace = pfmt->colorspace;
pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
? 0 : (pix->width * pix->priv) / 8;
@@ -2013,7 +2036,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2129,14 +2152,14 @@ et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose the mmap "
"I/O method");
- return -EINVAL;
+ return -EBUSY;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. "
"Previous buffers are still mapped.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -2284,9 +2307,6 @@ et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (list_empty(&cam->inqueue))
- return -EINVAL;
-
cam->stream = STREAM_ON;
DBG(3, "Stream on");
@@ -2535,8 +2555,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
DBG(2, "ET61X[12]51 PC Camera Controller detected "
"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
@@ -2568,7 +2586,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -2578,7 +2596,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -2599,11 +2617,15 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
"device controlling. Error #%d", err);
#else
DBG(2, "Optional device control through 'sysfs' interface disabled");
+ DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+ "configuration option to enable it.");
#endif
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -2620,40 +2642,31 @@ fail:
static void et61x251_usb_disconnect(struct usb_interface* intf)
{
- struct et61x251_device* cam = usb_get_intfdata(intf);
-
- if (!cam)
- return;
+ struct et61x251_device* cam;
- down_write(&et61x251_disconnect);
+ down_write(&et61x251_dev_lock);
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
et61x251_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- et61x251_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, et61x251_release_resources);
- up_write(&et61x251_disconnect);
+ up_write(&et61x251_dev_lock);
}
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
index 5fadb5de68bf..e14586330623 100644
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ b/drivers/media/video/et61x251/et61x251_sensor.h
@@ -22,7 +22,7 @@
#define _ET61X251_SENSOR_H_
#include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
@@ -47,7 +47,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);
extern void
et61x251_attach_sensor(struct et61x251_device* cam,
- struct et61x251_sensor* sensor);
+ const struct et61x251_sensor* sensor);
/*****************************************************************************/
@@ -56,10 +56,10 @@ extern int et61x251_read_reg(struct et61x251_device*, u16 index);
extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
extern int et61x251_i2c_try_write(struct et61x251_device*,
- struct et61x251_sensor*, u8 address,
+ const struct et61x251_sensor*, u8 address,
u8 value);
extern int et61x251_i2c_try_read(struct et61x251_device*,
- struct et61x251_sensor*, u8 address);
+ const struct et61x251_sensor*, u8 address);
extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
u8 data2, u8 data3, u8 data4, u8 data5,
u8 data6, u8 data7, u8 data8, u8 address);
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
index b06643409842..04b7fbb310a8 100644
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
@@ -69,7 +69,7 @@ static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
}
-static struct et61x251_sensor tas5130d1b = {
+static const struct et61x251_sensor tas5130d1b = {
.name = "TAS5130D1B",
.interface = ET61X251_I2C_3WIRES,
.rsta = ET61X251_I2C_RSTA_STOP,
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index ed92b6f7187a..2d709e064679 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -37,6 +37,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/i2c-id.h>
#include <linux/workqueue.h>
#include <asm/semaphore.h>
@@ -60,21 +61,22 @@ MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults
/* ----------------------------------------------------------------------- */
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+ int size, int offset)
{
- unsigned char buf[3];
+ unsigned char buf[6];
int start, range, toggle, dev, code;
/* poll IR chip */
- if (3 != i2c_master_recv(&ir->c,buf,3))
+ if (size != i2c_master_recv(&ir->c,buf,size))
return -EIO;
/* split rc5 data block ... */
- start = (buf[0] >> 7) & 1;
- range = (buf[0] >> 6) & 1;
- toggle = (buf[0] >> 5) & 1;
- dev = buf[0] & 0x1f;
- code = (buf[1] >> 2) & 0x3f;
+ start = (buf[offset] >> 7) & 1;
+ range = (buf[offset] >> 6) & 1;
+ toggle = (buf[offset] >> 5) & 1;
+ dev = buf[offset] & 0x1f;
+ code = (buf[offset+1] >> 2) & 0x3f;
/* rc5 has two start bits
* the first bit must be one
@@ -96,6 +98,16 @@ static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
+static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+}
+
+static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+}
+
static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char b;
@@ -270,8 +282,9 @@ static void ir_timer(unsigned long data)
static void ir_work(struct work_struct *work)
{
struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+
ir_key_poll(ir);
- mod_timer(&ir->timer, jiffies+HZ/10);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
}
/* ----------------------------------------------------------------------- */
@@ -354,9 +367,21 @@ static int ir_attach(struct i2c_adapter *adap, int addr,
case 0x7a:
case 0x47:
case 0x71:
- /* Handled by saa7134-input */
- name = "SAA713x remote";
- ir_type = IR_TYPE_OTHER;
+ if (adap->id == I2C_HW_B_CX2388x) {
+ /* Handled by cx88-input */
+ name = "CX2388x remote";
+ ir_type = IR_TYPE_RC5;
+ ir->get_key = get_key_haup_xvr;
+ if (hauppauge == 1) {
+ ir_codes = ir_codes_hauppauge_new;
+ } else {
+ ir_codes = ir_codes_rc5_tv;
+ }
+ } else {
+ /* Handled by saa7134-input */
+ name = "SAA713x remote";
+ ir_type = IR_TYPE_OTHER;
+ }
break;
default:
/* shouldn't happen */
@@ -450,6 +475,7 @@ static int ir_probe(struct i2c_adapter *adap)
static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
static const int probe_em28XX[] = { 0x30, 0x47, -1 };
+ static const int probe_cx88[] = { 0x18, 0x71, -1 };
const int *probe = NULL;
struct i2c_client c;
unsigned char buf;
@@ -468,6 +494,9 @@ static int ir_probe(struct i2c_adapter *adap)
case I2C_HW_B_EM28XX:
probe = probe_em28XX;
break;
+ case I2C_HW_B_CX2388x:
+ probe = probe_cx88;
+ break;
}
if (NULL == probe)
return 0;
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index 1aaeaa02f158..e43beb2c9cbf 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,6 +1,7 @@
config VIDEO_IVTV
tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+ select I2C_ALGOBIT
select FW_LOADER
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -16,11 +17,11 @@ config VIDEO_IVTV
select VIDEO_UPD64031A
select VIDEO_UPD64083
---help---
- This is a video4linux driver for Conexant cx23416 or cx23416 based
+ This is a video4linux driver for Conexant cx23416 or cx23415 based
PCI personal video recorder devices.
This is used in devices such as the Hauppauge PVR-150/250/350/500
- cards.
+ cards. There is a driver homepage at <http://www.ivtvdriver.org>.
To compile this driver as a module, choose M here: the
module will be called ivtv.
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index efc66355339a..d73d433a4ff6 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -56,7 +56,6 @@
#include "ivtv-gpio.h"
#include "ivtv-yuv.h"
-#include <linux/vermagic.h>
#include <media/tveeprom.h>
#include <media/v4l2-chip-ident.h>
@@ -181,7 +180,7 @@ MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
MODULE_PARM_DESC(debug,
"Debug level (bitmask). Default: errors only\n"
- "\t\t\t(debug = 511 gives full debugging)");
+ "\t\t\t(debug = 1023 gives full debugging)");
MODULE_PARM_DESC(ivtv_pci_latency,
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
"\t\t\tDefault: Yes");
@@ -276,9 +275,10 @@ int ivtv_waitq(wait_queue_head_t *waitq)
}
/* Generic utility functions */
-int ivtv_sleep_timeout(int timeout, int intr)
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
{
int ret;
+ int timeout = msecs_to_jiffies(msecs);
do {
set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -339,6 +339,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
/* In a few cases the PCI subsystem IDs do not correctly
identify the card. A better method is to check the
model number from the eeprom instead. */
+ case 30012 ... 30039: /* Low profile PVR250 */
case 32000 ... 32999:
case 48000 ... 48099: /* 48??? range are PVR250s with a cx23415 */
case 48400 ... 48599:
@@ -426,7 +427,7 @@ static void ivtv_process_eeprom(struct ivtv *itv)
if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
if (itv->options.newi2c) {
- IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+ IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
exit_ivtv_i2c(itv);
init_ivtv_i2c(itv);
}
@@ -622,6 +623,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
+ mutex_init(&itv->serialize_lock);
mutex_init(&itv->i2c_bus_lock);
mutex_init(&itv->udma.lock);
@@ -949,7 +951,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
/* Make sure we've got a place for this card */
if (ivtv_cards_active == IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: Maximum number of cards detected (%d).\n",
+ printk(KERN_ERR "ivtv: Maximum number of cards detected (%d)\n",
ivtv_cards_active);
spin_unlock(&ivtv_cards_lock);
return -ENOMEM;
@@ -964,9 +966,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
itv->dev = dev;
itv->num = ivtv_cards_active++;
snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
- if (itv->num) {
- printk(KERN_INFO "ivtv: ====================== NEXT CARD ======================\n");
- }
+ IVTV_INFO("Initializing card #%d\n", itv->num);
spin_unlock(&ivtv_cards_lock);
@@ -1213,7 +1213,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
if (itv->has_cx23415)
ivtv_set_osd_alpha(itv);
- IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
+ IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
return 0;
@@ -1246,15 +1246,15 @@ static void ivtv_remove(struct pci_dev *pci_dev)
{
struct ivtv *itv = pci_get_drvdata(pci_dev);
- IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+ IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
/* Stop all captures */
- IVTV_DEBUG_INFO(" Stopping all streams.\n");
+ IVTV_DEBUG_INFO("Stopping all streams\n");
if (atomic_read(&itv->capturing) > 0)
ivtv_stop_all_captures(itv);
/* Stop all decoding */
- IVTV_DEBUG_INFO(" Stopping decoding.\n");
+ IVTV_DEBUG_INFO("Stopping decoding\n");
if (atomic_read(&itv->decoding) > 0) {
int type;
@@ -1267,33 +1267,30 @@ static void ivtv_remove(struct pci_dev *pci_dev)
}
/* Interrupts */
- IVTV_DEBUG_INFO(" Disabling interrupts.\n");
+ IVTV_DEBUG_INFO("Disabling interrupts\n");
ivtv_set_irq_mask(itv, 0xffffffff);
del_timer_sync(&itv->dma_timer);
/* Stop all Work Queues */
- IVTV_DEBUG_INFO(" Stop Work Queues.\n");
+ IVTV_DEBUG_INFO("Stop Work Queues\n");
flush_workqueue(itv->irq_work_queues);
destroy_workqueue(itv->irq_work_queues);
- IVTV_DEBUG_INFO(" Stopping Firmware.\n");
+ IVTV_DEBUG_INFO("Stopping Firmware\n");
ivtv_halt_firmware(itv);
- IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
+ IVTV_DEBUG_INFO("Unregistering v4l devices\n");
ivtv_streams_cleanup(itv);
- IVTV_DEBUG_INFO(" Freeing dma resources.\n");
+ IVTV_DEBUG_INFO("Freeing dma resources\n");
ivtv_udma_free(itv);
exit_ivtv_i2c(itv);
- IVTV_DEBUG_INFO(" Releasing irq.\n");
+ IVTV_DEBUG_INFO(" Releasing irq\n");
free_irq(itv->dev->irq, (void *)itv);
+ ivtv_iounmap(itv);
- if (itv->dev) {
- ivtv_iounmap(itv);
- }
-
- IVTV_DEBUG_INFO(" Releasing mem.\n");
+ IVTV_DEBUG_INFO(" Releasing mem\n");
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
@@ -1314,28 +1311,27 @@ static struct pci_driver ivtv_pci_driver = {
static int module_start(void)
{
- printk(KERN_INFO "ivtv: ==================== START INIT IVTV ====================\n");
- printk(KERN_INFO "ivtv: version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+ printk(KERN_INFO "ivtv: Start initialization, version %s\n", IVTV_VERSION);
memset(ivtv_cards, 0, sizeof(ivtv_cards));
/* Validate parameters */
if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
- printk(KERN_ERR "ivtv: ivtv_first_minor must be between 0 and %d. Exiting...\n",
+ printk(KERN_ERR "ivtv: Exiting, ivtv_first_minor must be between 0 and %d\n",
IVTV_MAX_CARDS - 1);
return -1;
}
- if (ivtv_debug < 0 || ivtv_debug > 511) {
+ if (ivtv_debug < 0 || ivtv_debug > 1023) {
ivtv_debug = 0;
- printk(KERN_INFO "ivtv: debug value must be >= 0 and <= 511!\n");
+ printk(KERN_INFO "ivtv: Debug value must be >= 0 and <= 1023\n");
}
if (pci_register_driver(&ivtv_pci_driver)) {
printk(KERN_ERR "ivtv: Error detecting PCI card\n");
return -ENODEV;
}
- printk(KERN_INFO "ivtv: ==================== END INIT IVTV ====================\n");
+ printk(KERN_INFO "ivtv: End initialization\n");
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index e6e56f175f3f..91b588d261ae 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -268,6 +268,8 @@ extern const u32 yuv_offset[4];
#define IVTV_DBGFLG_IRQ (1 << 6)
#define IVTV_DBGFLG_DEC (1 << 7)
#define IVTV_DBGFLG_YUV (1 << 8)
+/* Flag to turn on high volume debugging */
+#define IVTV_DBGFLG_HIGHVOL (1 << 9)
/* NOTE: extra space before comma in 'itv->num , ## args' is required for
gcc-2.95, otherwise it won't compile. */
@@ -286,6 +288,21 @@ extern const u32 yuv_offset[4];
#define IVTV_DEBUG_DEC(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
#define IVTV_DEBUG_YUV(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+ do { \
+ if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+ printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
+ } while (0)
+#define IVTV_DEBUG_HI_WARN(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO, "info",fmt , ## args)
+#define IVTV_DEBUG_HI_API(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_API, "api", fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+
#define IVTV_FB_DEBUG(x, type, fmt, args...) \
do { \
if ((x) & ivtv_debug) \
@@ -650,7 +667,6 @@ struct vbi_info {
/* convenience pointer to sliced struct in vbi_in union */
struct v4l2_sliced_vbi_format *sliced_in;
u32 service_set_in;
- u32 service_set_out;
int insert_mpeg;
/* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
@@ -723,6 +739,7 @@ struct ivtv {
int search_pack_header;
spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+ struct mutex serialize_lock; /* lock used to serialize starting streams */
/* User based DMA for OSD */
struct ivtv_user_dma udma;
@@ -831,7 +848,7 @@ int ivtv_set_output_mode(struct ivtv *itv, int mode);
struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
/* Return non-zero if a signal is pending */
-int ivtv_sleep_timeout(int timeout, int intr);
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
/* Wait on queue, returns -EINTR if interrupted */
int ivtv_waitq(wait_queue_head_t *waitq);
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 555d5e6369c3..8e97a938398f 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -218,7 +218,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
/* Process pending program info updates and pending VBI data */
ivtv_update_pgm_info(itv);
- if (jiffies - itv->dualwatch_jiffies > HZ) {
+ if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
itv->dualwatch_jiffies = jiffies;
ivtv_dualwatch(itv);
}
@@ -406,7 +406,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co
ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
struct ivtv *itv = s->itv;
- IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+ IVTV_DEBUG_HI_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
if (rc > 0)
pos += rc;
return rc;
@@ -497,7 +497,7 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
struct ivtv_stream *s = &itv->streams[id->type];
int rc;
- IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name);
+ IVTV_DEBUG_HI_IOCTL("read %zd bytes from %s\n", count, s->name);
rc = ivtv_start_capture(id);
if (rc)
@@ -535,7 +535,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
int rc;
DEFINE_WAIT(wait);
- IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name);
+ IVTV_DEBUG_HI_IOCTL("write %zd bytes to %s\n", count, s->name);
if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
s->type != IVTV_DEC_STREAM_TYPE_YUV &&
@@ -643,7 +643,7 @@ retry:
to transfer the rest. */
if (count && !(filp->f_flags & O_NONBLOCK))
goto retry;
- IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+ IVTV_DEBUG_HI_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
return bytes_written;
}
@@ -832,7 +832,7 @@ int ivtv_v4l2_open(struct inode *inode, struct file *filp)
if (itv == NULL) {
/* Couldn't find a device registered
on that minor, shouldn't happen! */
- printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
+ printk(KERN_WARNING "ivtv: No ivtv device found on minor %d\n", minor);
return -ENXIO;
}
@@ -924,7 +924,7 @@ void ivtv_unmute(struct ivtv *itv)
if (atomic_read(&itv->capturing) == 0)
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
if (atomic_read(&itv->capturing)) {
ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index d4c910b782af..d0feabf93080 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -36,7 +36,7 @@
#define IVTV_CMD_SPU_STOP 0x00000001
#define IVTV_CMD_SDRAM_PRECHARGE_INIT 0x0000001A
#define IVTV_CMD_SDRAM_REFRESH_INIT 0x80000640
-#define IVTV_SDRAM_SLEEPTIME (60 * HZ / 100) /* 600 ms */
+#define IVTV_SDRAM_SLEEPTIME 600
#define IVTV_DECODE_INIT_MPEG_FILENAME "v4l-cx2341x-init.mpg"
#define IVTV_DECODE_INIT_MPEG_SIZE (152*1024)
@@ -56,14 +56,12 @@ retry:
volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
const u32 *src = (const u32 *)fw->data;
- /* temporarily allow 256 KB encoding firmwares as well for
- compatibility with blackbird cards */
- if (fw->size != size && fw->size != 256 * 1024) {
+ if (fw->size != size) {
/* Due to race conditions in firmware loading (esp. with udev <0.95)
the wrong file was sometimes loaded. So we check filesizes to
see if at least the right-sized file was loaded. If not, then we
retry. */
- IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+ IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
release_firmware(fw);
retries--;
goto retry;
@@ -75,11 +73,11 @@ retry:
src++;
}
release_firmware(fw);
- IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
return size;
}
- IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
- IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+ IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
return -ENOMEM;
}
@@ -91,7 +89,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
if (itv->enc_mbox.mbox)
ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
IVTV_DEBUG_INFO("Stopping VDM\n");
@@ -115,7 +113,7 @@ void ivtv_halt_firmware(struct ivtv *itv)
IVTV_DEBUG_INFO("Stopping SPU\n");
write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
@@ -131,9 +129,8 @@ void ivtv_halt_firmware(struct ivtv *itv)
write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
}
- IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
- (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
- ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+ IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+ ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
}
void ivtv_firmware_versions(struct ivtv *itv)
@@ -206,12 +203,12 @@ int ivtv_firmware_init(struct ivtv *itv)
/* start firmware */
write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
if (itv->has_cx23415)
write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
else
write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
/* find mailboxes and ping firmware */
itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
@@ -266,7 +263,7 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
IVTV_DECODE_INIT_MPEG_FILENAME);
} else {
ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
}
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
}
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index bc8f8ca2961f..6a5a7aa66976 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -115,8 +115,7 @@ void ivtv_reset_ir_gpio(struct ivtv *itv)
curout = (curout & ~0xF) | 1;
write_reg(curout, IVTV_REG_GPIO_OUT);
/* We could use something else for smaller time */
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
curout |= 2;
write_reg(curout, IVTV_REG_GPIO_OUT);
curdir &= ~0x80;
@@ -131,20 +130,18 @@ int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
return -EINVAL;
- IVTV_INFO("Resetting tuner.\n");
+ IVTV_INFO("Resetting tuner\n");
curout = read_reg(IVTV_REG_GPIO_OUT);
curdir = read_reg(IVTV_REG_GPIO_DIR);
curdir |= (1 << 12); /* GPIO bit 12 */
curout &= ~(1 << 12);
write_reg(curout, IVTV_REG_GPIO_OUT);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
curout |= (1 << 12);
write_reg(curout, IVTV_REG_GPIO_OUT);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(1);
+ schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 50624c6a62a5..b3557435456d 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -144,7 +144,7 @@ static int attach_inform(struct i2c_client *client)
}
}
if (i == I2C_CLIENTS_MAX) {
- IVTV_ERR("insufficient room for new I2C client!\n");
+ IVTV_ERR("Insufficient room for new I2C client\n");
}
return 0;
}
@@ -236,7 +236,7 @@ static int ivtv_ack(struct ivtv *itv)
int ret = 0;
if (ivtv_getscl(itv) == 1) {
- IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+ IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
@@ -263,7 +263,7 @@ static int ivtv_sendbyte(struct ivtv *itv, unsigned char byte)
{
int i, bit;
- IVTV_DEBUG_I2C("write %x\n",byte);
+ IVTV_DEBUG_HI_I2C("write %x\n",byte);
for (i = 0; i < 8; ++i, byte<<=1) {
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
@@ -318,7 +318,7 @@ static int ivtv_readbyte(struct ivtv *itv, unsigned char *byte, int nack)
ivtv_scldelay(itv);
ivtv_setscl(itv, 0);
ivtv_scldelay(itv);
- IVTV_DEBUG_I2C("read %x\n",*byte);
+ IVTV_DEBUG_HI_I2C("read %x\n",*byte);
return 0;
}
@@ -330,7 +330,7 @@ static int ivtv_start(struct ivtv *itv)
sda = ivtv_getsda(itv);
if (sda != 1) {
- IVTV_DEBUG_I2C("SDA was low at start\n");
+ IVTV_DEBUG_HI_I2C("SDA was low at start\n");
ivtv_setsda(itv, 1);
if (!ivtv_waitsda(itv, 1)) {
IVTV_DEBUG_I2C("SDA stuck low\n");
@@ -355,7 +355,7 @@ static int ivtv_stop(struct ivtv *itv)
int i;
if (ivtv_getscl(itv) != 0) {
- IVTV_DEBUG_I2C("SCL not low when stopping\n");
+ IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
ivtv_setscl(itv, 0);
if (!ivtv_waitscl(itv, 0)) {
IVTV_DEBUG_I2C("SCL could not be set low\n");
@@ -569,7 +569,7 @@ int ivtv_call_i2c_client(struct ivtv *itv, int addr, unsigned int cmd, void *arg
}
}
if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+ IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
return -ENODEV;
}
@@ -640,7 +640,7 @@ int ivtv_i2c_hw(struct ivtv *itv, u32 hw, unsigned int cmd, void *arg)
addr = ivtv_i2c_hw_addr(itv, hw);
if (addr < 0) {
- IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+ IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
hw, ivtv_i2c_hw_name(hw), cmd);
return addr;
}
@@ -655,7 +655,7 @@ int ivtv_i2c_id(struct ivtv *itv, u32 id, unsigned int cmd, void *arg)
addr = ivtv_i2c_id_addr(itv, id);
if (addr < 0) {
if (cmd != VIDIOC_G_CHIP_IDENT)
- IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+ IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
id, ivtv_i2c_id_name(id), cmd);
return addr;
}
@@ -696,7 +696,7 @@ int ivtv_upd64083(struct ivtv *itv, unsigned int cmd, void *arg)
void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
{
if (itv->i2c_adap.algo == NULL) {
- IVTV_ERR("adapter is not set");
+ IVTV_ERR("Adapter is not set");
return;
}
i2c_clients_command(&itv->i2c_adap, cmd, arg);
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 57af1762de1f..4773453e8dab 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -1159,7 +1159,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
memset(fb, 0, sizeof(*fb));
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- break;
+ return -EINVAL;
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
fb->fmt.pixelformat = itv->osd_pixelformat;
@@ -1179,7 +1179,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
struct v4l2_framebuffer *fb = arg;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
- break;
+ return -EINVAL;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index ba98bf054f2e..fcd6e7f5f121 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -48,7 +48,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
struct list_head *p;
int i = 0;
- IVTV_DEBUG_DMA("ivtv_pio_work_handler\n");
+ IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
s->v4l2dev == NULL || !ivtv_use_pio(s)) {
itv->cur_pio_stream = -1;
@@ -56,7 +56,7 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
return;
}
- IVTV_DEBUG_DMA("Process PIO %s\n", s->name);
+ IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
list_for_each(p, &s->q_dma.list) {
struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -187,7 +187,7 @@ static int stream_enc_dma_append(struct ivtv_stream *s, u32 data[CX2341X_MBOX_MA
bytes_needed += UVsize;
}
- IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+ IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
@@ -242,7 +242,7 @@ static void dma_post(struct ivtv_stream *s)
u32 *u32buf;
int x = 0;
- IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+ IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
s->name, s->dma_offset);
list_for_each(p, &s->q_dma.list) {
buf = list_entry(p, struct ivtv_buffer, list);
@@ -321,7 +321,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
unsigned long flags = 0;
int idx = 0;
- IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+ IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
list_for_each(p, &s->q_predma.list) {
struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
@@ -368,7 +368,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
int i;
- IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
+ IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
@@ -397,12 +397,17 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
itv->vbi.dma_offset = s_vbi->dma_offset;
s_vbi->SG_length = 0;
set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
- IVTV_DEBUG_DMA("include DMA for %s\n", s->name);
+ IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
}
/* Mark last buffer size for Interrupt flag */
s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+ if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
+ set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+ else
+ clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+
if (ivtv_use_pio(s)) {
for (i = 0; i < s->SG_length; i++) {
s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
@@ -420,7 +425,7 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + HZ / 10;
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&itv->dma_timer);
}
}
@@ -431,13 +436,13 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
if (s->q_predma.bytesused)
ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
- IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
+ IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
/* put SG Handle into register 0x0c */
write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + HZ / 10;
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&itv->dma_timer);
}
@@ -447,7 +452,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
struct ivtv_buffer *buf;
int hw_stream_type;
- IVTV_DEBUG_IRQ("DEC DMA READ\n");
+ IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
del_timer(&itv->dma_timer);
if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
@@ -462,7 +467,7 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
hw_stream_type = 0;
}
- IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
+ IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
ivtv_stream_sync_for_cpu(s);
@@ -495,7 +500,7 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
del_timer(&itv->dma_timer);
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
- IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
+ IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
data[1] = 3;
else if (data[1] > 2)
@@ -532,7 +537,7 @@ static void ivtv_irq_enc_pio_complete(struct ivtv *itv)
return;
}
s = &itv->streams[itv->cur_pio_stream];
- IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name);
+ IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
s->SG_length = 0;
clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
clear_bit(IVTV_F_I_PIO, &itv->i_flags);
@@ -590,14 +595,13 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv)
/* Get DMA destination and size arguments from card */
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
- IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+ IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
data[0], data[1], data[2]);
return;
}
- clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
s = &itv->streams[ivtv_stream_map[data[0]]];
if (!stream_enc_dma_append(s, data)) {
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
@@ -610,7 +614,7 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s;
- IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
+ IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
/* If more than two VBI buffers are pending, then
@@ -634,7 +638,6 @@ static void ivtv_irq_enc_vbi_cap(struct ivtv *itv)
then start a DMA request for just the VBI data. */
if (!stream_enc_dma_append(s, data) &&
!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
- set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
}
}
@@ -644,7 +647,7 @@ static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv)
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
- IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
+ IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
!stream_enc_dma_append(s, data)) {
set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
@@ -669,7 +672,7 @@ static void ivtv_irq_dec_data_req(struct ivtv *itv)
itv->dma_data_req_offset = data[1];
s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
}
- IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+ IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
itv->dma_data_req_offset, itv->dma_data_req_size);
if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
@@ -791,10 +794,10 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
/* Exclude interrupts noted below from the output, otherwise the log is flooded with
these messages */
if (combo & ~0xff6d0400)
- IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+ IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
- IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n");
+ IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
}
if (combo & IVTV_IRQ_DMA_READ) {
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 6ae42a3b03cc..814a673712b3 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -37,6 +37,7 @@
#define API_RESULT (1 << 1) /* Allow 1 second for this cmd to end */
#define API_FAST_RESULT (3 << 1) /* Allow 0.1 second for this cmd to end */
#define API_DMA (1 << 3) /* DMA mailbox, has special handling */
+#define API_HIGH_VOL (1 << 5) /* High volume command (i.e. called during encoding or decoding) */
#define API_NO_WAIT_MB (1 << 4) /* Command may not wait for a free mailbox */
#define API_NO_WAIT_RES (1 << 5) /* Command may not wait for the result */
@@ -77,11 +78,11 @@ static const struct ivtv_api_info api_info[256] = {
API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, API_CACHE),
API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, API_FAST_RESULT),
API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, API_FAST_RESULT),
- API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA),
+ API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, API_DMA | API_HIGH_VOL),
API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, API_RESULT),
API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, API_CACHE),
API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, API_RESULT),
- API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB),
+ API_ENTRY(CX2341X_ENC_REFRESH_INPUT, API_NO_WAIT_MB | API_HIGH_VOL),
API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, API_CACHE),
API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, API_RESULT),
API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, API_CACHE),
@@ -102,7 +103,7 @@ static const struct ivtv_api_info api_info[256] = {
API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, API_CACHE),
API_ENTRY(CX2341X_DEC_GET_XFER_INFO, API_FAST_RESULT),
API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, API_FAST_RESULT),
- API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA),
+ API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, API_DMA | API_HIGH_VOL),
API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, API_RESULT),
API_ENTRY(CX2341X_DEC_HALT_FW, API_FAST_RESULT),
API_ENTRY(CX2341X_DEC_SET_STANDARD, API_CACHE),
@@ -175,9 +176,9 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f
/* Sleep before a retry, if not atomic */
if (!(flags & API_NO_WAIT_MB)) {
- if (jiffies - then > retries * HZ / 100)
+ if (jiffies - then > msecs_to_jiffies(10*retries))
break;
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
}
}
return -ENODEV;
@@ -212,7 +213,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
{
struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
volatile struct ivtv_mailbox __iomem *mbox;
- int api_timeout = HZ;
+ int api_timeout = msecs_to_jiffies(1000);
int flags, mb, i;
unsigned long then;
@@ -227,7 +228,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
return -EINVAL;
}
- IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+ if (api_info[cmd].flags & API_HIGH_VOL) {
+ IVTV_DEBUG_HI_API("API Call: %s\n", api_info[cmd].name);
+ }
+ else {
+ IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+ }
/* clear possibly uninitialized part of data array */
for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
@@ -237,7 +243,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
data, then just return 0 as there is no need to issue this command again.
Just an optimization to prevent unnecessary use of mailboxes. */
if (itv->api_cache[cmd].last_jiffies &&
- jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+ jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
!memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
itv->api_cache[cmd].last_jiffies = jiffies;
return 0;
@@ -262,7 +268,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
}
if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
- api_timeout = HZ / 10;
+ api_timeout = msecs_to_jiffies(100);
mb = get_mailbox(itv, mbdata, flags);
if (mb < 0) {
@@ -295,11 +301,12 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
if (flags & API_NO_WAIT_RES)
mdelay(1);
else
- ivtv_sleep_timeout(HZ / 100, 0);
+ ivtv_msleep_timeout(10, 0);
}
- if (jiffies - then > HZ / 10)
- IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
- api_info[cmd].name, jiffies - then, HZ);
+ if (jiffies - then > msecs_to_jiffies(100))
+ IVTV_DEBUG_WARN("%s took %u jiffies\n",
+ api_info[cmd].name,
+ jiffies_to_msecs(jiffies - then));
for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
data[i] = readl(&mbox->data[i]);
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 6af88ae9295f..322b347b67c2 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -446,6 +446,9 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
if (s->v4l2dev == NULL)
return -EINVAL;
+ /* Big serialization lock to ensure no two streams are started
+ simultaneously: that can give all sorts of weird results. */
+ mutex_lock(&itv->serialize_lock);
IVTV_DEBUG_INFO("Start encoder stream %s\n", s->name);
switch (s->type) {
@@ -487,6 +490,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
0, sizeof(itv->vbi.sliced_mpeg_size));
break;
default:
+ mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}
s->subtype = subtype;
@@ -561,13 +565,14 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
/* Initialize Digitizer for Capture */
ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
- ivtv_sleep_timeout(HZ / 10, 0);
+ ivtv_msleep_timeout(100, 0);
}
/* begin_capture */
if (ivtv_vapi(itv, CX2341X_ENC_START_CAPTURE, 2, captype, subtype))
{
IVTV_DEBUG_WARN( "Error starting capture!\n");
+ mutex_unlock(&itv->serialize_lock);
return -EINVAL;
}
@@ -583,6 +588,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
/* you're live! sit back and await interrupts :) */
atomic_inc(&itv->capturing);
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
@@ -762,17 +768,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* when: 0 = end of GOP 1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
- /* only run these if we're shutting down the last cap */
- if (atomic_read(&itv->capturing) - 1 == 0) {
- /* event notification (off) */
- if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
- /* type: 0 = refresh */
- /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
- ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
- ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
- }
- }
-
then = jiffies;
if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
@@ -786,8 +781,9 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
set_current_state(TASK_INTERRUPTIBLE);
/* wait 2s for EOS interrupt */
- while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
- schedule_timeout(HZ / 100);
+ while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+ jiffies < then + msecs_to_jiffies (2000)) {
+ schedule_timeout(msecs_to_jiffies(10));
}
/* To convert jiffies to ms, we must multiply by 1000
@@ -812,7 +808,6 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
then = jiffies;
/* Make sure DMA is complete */
add_wait_queue(&s->waitq, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
do {
/* check if DMA is pending */
if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) && /* MPG Only */
@@ -827,9 +822,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
} else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
break;
}
-
- ivtv_sleep_timeout(HZ / 100, 1);
- } while (then + HZ * 2 > jiffies);
+ } while (!ivtv_msleep_timeout(10, 1) &&
+ then + msecs_to_jiffies(2000) > jiffies);
set_current_state(TASK_RUNNING);
remove_wait_queue(&s->waitq, &wait);
@@ -840,17 +834,30 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* Clear capture and no-read bits */
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ /* ensure these global cleanup actions are done only once */
+ mutex_lock(&itv->serialize_lock);
+
if (s->type == IVTV_ENC_STREAM_TYPE_VBI)
ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VBI_CAP);
if (atomic_read(&itv->capturing) > 0) {
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
/* Set the following Interrupt mask bits for capture */
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+ /* event notification (off) */
+ if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+ /* type: 0 = refresh */
+ /* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+ ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+ ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+ }
+
wake_up(&s->waitq);
+ mutex_unlock(&itv->serialize_lock);
return 0;
}
@@ -887,7 +894,7 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
break;
tmp = data[3];
}
- if (ivtv_sleep_timeout(HZ/10, 1))
+ if (ivtv_msleep_timeout(100, 1))
break;
}
}
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 3ba46e07ea1f..a7282a91bd97 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -219,31 +219,23 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
int found_cc = 0;
int cc_pos = itv->vbi.cc_pos;
- if (itv->vbi.service_set_out == 0)
- return -EPERM;
-
while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
switch (p->id) {
case V4L2_SLICED_CAPTION_525:
- if (p->id == V4L2_SLICED_CAPTION_525 &&
- p->line == 21 &&
- (itv->vbi.service_set_out &
- V4L2_SLICED_CAPTION_525) == 0) {
- break;
- }
- found_cc = 1;
- if (p->field) {
- cc[2] = p->data[0];
- cc[3] = p->data[1];
- } else {
- cc[0] = p->data[0];
- cc[1] = p->data[1];
+ if (p->line == 21) {
+ found_cc = 1;
+ if (p->field) {
+ cc[2] = p->data[0];
+ cc[3] = p->data[1];
+ } else {
+ cc[0] = p->data[0];
+ cc[1] = p->data[1];
+ }
}
break;
case V4L2_SLICED_VPS:
- if (p->line == 16 && p->field == 0 &&
- (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
+ if (p->line == 16 && p->field == 0) {
itv->vbi.vps[0] = p->data[2];
itv->vbi.vps[1] = p->data[8];
itv->vbi.vps[2] = p->data[9];
@@ -255,8 +247,7 @@ ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
break;
case V4L2_SLICED_WSS_625:
- if (p->line == 23 && p->field == 0 &&
- (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
+ if (p->line == 23 && p->field == 0) {
/* No lock needed for WSS */
itv->vbi.wss = p->data[0] | (p->data[1] << 8);
itv->vbi.wss_found = 1;
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 664aba8b4d85..7533fc203319 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1809,7 +1809,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
{
int ret = -EBUSY;
unsigned long mchip_adr;
- u8 revision;
if (meye.mchip_dev != NULL) {
printk(KERN_ERR "meye: only one device allowed!\n");
@@ -1885,7 +1884,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
goto outreqirq;
}
- pci_read_config_byte(meye.mchip_dev, PCI_REVISION_ID, &revision);
pci_write_config_byte(meye.mchip_dev, PCI_CACHE_LINE_SIZE, 8);
pci_write_config_byte(meye.mchip_dev, PCI_LATENCY_TIMER, 64);
@@ -1939,7 +1937,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
printk(KERN_INFO "meye: Motion Eye Camera Driver v%s.\n",
MEYE_DRIVER_VERSION);
printk(KERN_INFO "meye: mchip KL5A72002 rev. %d, base %lx, irq %d\n",
- revision, mchip_adr, meye.mchip_irq);
+ meye.mchip_dev->revision, mchip_adr, meye.mchip_irq);
return 0;
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 3bb7d6634862..11cfcf18ec34 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -157,8 +157,7 @@ static int msp_read(struct i2c_client *client, int dev, int addr)
break;
v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
}
if (err == 3) {
v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -197,8 +196,7 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val)
break;
v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
dev, addr);
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(msecs_to_jiffies(10));
+ schedule_timeout_interruptible(msecs_to_jiffies(10));
}
if (err == 3) {
v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -814,10 +812,9 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
int msp_product, msp_prod_hi, msp_prod_lo;
int msp_rom;
- client = kmalloc(sizeof(*client), GFP_KERNEL);
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
if (client == NULL)
return -ENOMEM;
- memset(client, 0, sizeof(*client));
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index e1821eb82fb5..d5ee2629121e 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -23,6 +23,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/freezer.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
@@ -468,6 +469,7 @@ int msp3400c_thread(void *data)
v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n");
+ set_freezable();
for (;;) {
v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n");
msp_sleep(state, -1);
@@ -646,7 +648,7 @@ int msp3410d_thread(void *data)
int val, i, std, count;
v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n");
-
+ set_freezable();
for (;;) {
v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n");
msp_sleep(state,-1);
@@ -940,7 +942,7 @@ int msp34xxg_thread(void *data)
int val, i;
v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n");
-
+ set_freezable();
for (;;) {
v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n");
msp_sleep(state, -1);
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index c7c9f3f8715c..7549114aaaca 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -7,7 +7,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/moduleparam.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
/* ---------------------------------------------------------------------- */
@@ -37,6 +37,19 @@ static char *microtune_part[] = {
[ MT2050 ] = "MT2050",
};
+struct microtune_priv {
+ unsigned int xogc;
+ unsigned int radio_if2;
+};
+
+static void microtune_release(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ kfree(t->priv);
+ t->priv = NULL;
+}
+
// IsSpurInBand()?
static int mt2032_spurcheck(struct i2c_client *c,
int f1, int f2, int spectrum_from,int spectrum_to)
@@ -218,6 +231,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
unsigned char buf[21];
int lint_try,ret,sel,lock=0;
struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = t->priv;
tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
rfin,if1,if2,from,to);
@@ -227,7 +241,7 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
i2c_master_recv(c,buf,21);
buf[0]=0;
- ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+ ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
if (ret<0)
return;
@@ -251,10 +265,10 @@ static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
tuner_dbg("mt2032: re-init PLLs by LINT\n");
buf[0]=7;
- buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
+ buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
i2c_master_send(c,buf,2);
mdelay(10);
- buf[1]=8+t->xogc;
+ buf[1]=8+priv->xogc;
i2c_master_send(c,buf,2);
}
@@ -294,17 +308,25 @@ static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
- int if2 = t->radio_if2;
+ struct microtune_priv *priv = t->priv;
+ int if2 = priv->radio_if2;
// per Manual for FM tuning: first if center freq. 1085 MHz
mt2032_set_if_freq(c, freq * 1000 / 16,
1085*1000*1000,if2,if2,if2);
}
+static struct tuner_operations mt2032_tuner_ops = {
+ .set_tv_freq = mt2032_set_tv_freq,
+ .set_radio_freq = mt2032_set_radio_freq,
+ .release = microtune_release,
+};
+
// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
static int mt2032_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct microtune_priv *priv = t->priv;
unsigned char buf[21];
int ret,xogc,xok=0;
@@ -351,23 +373,23 @@ static int mt2032_init(struct i2c_client *c)
if (ret!=2)
tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
} while (xok != 1 );
- t->xogc=xogc;
+ priv->xogc=xogc;
+
+ memcpy(&t->ops, &mt2032_tuner_ops, sizeof(struct tuner_operations));
- t->set_tv_freq = mt2032_set_tv_freq;
- t->set_radio_freq = mt2032_set_radio_freq;
return(1);
}
static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
{
struct tuner *t = i2c_get_clientdata(c);
- unsigned char buf[2];
- int ret;
+ unsigned char buf[2];
+ int ret;
- buf[0] = 6;
- buf[1] = antenna ? 0x11 : 0x10;
- ret=i2c_master_send(c,buf,2);
- tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+ buf[0] = 6;
+ buf[1] = antenna ? 0x11 : 0x10;
+ ret=i2c_master_send(c,buf,2);
+ tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
}
static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
@@ -456,12 +478,19 @@ static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
- int if2 = t->radio_if2;
+ struct microtune_priv *priv = t->priv;
+ int if2 = priv->radio_if2;
mt2050_set_if_freq(c, freq * 1000 / 16, if2);
mt2050_set_antenna(c, radio_antenna);
}
+static struct tuner_operations mt2050_tuner_ops = {
+ .set_tv_freq = mt2050_set_tv_freq,
+ .set_radio_freq = mt2050_set_radio_freq,
+ .release = microtune_release,
+};
+
static int mt2050_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
@@ -481,28 +510,35 @@ static int mt2050_init(struct i2c_client *c)
i2c_master_recv(c,buf,1);
tuner_dbg("mt2050: sro is %x\n",buf[0]);
- t->set_tv_freq = mt2050_set_tv_freq;
- t->set_radio_freq = mt2050_set_radio_freq;
+
+ memcpy(&t->ops, &mt2050_tuner_ops, sizeof(struct tuner_operations));
+
return 0;
}
int microtune_init(struct i2c_client *c)
{
+ struct microtune_priv *priv = NULL;
struct tuner *t = i2c_get_clientdata(c);
char *name;
unsigned char buf[21];
int company_code;
+ priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ t->priv = priv;
+
+ priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
+
memset(buf,0,sizeof(buf));
- t->set_tv_freq = NULL;
- t->set_radio_freq = NULL;
- t->standby = NULL;
+
if (t->std & V4L2_STD_525_60) {
tuner_dbg("pinnacle ntsc\n");
- t->radio_if2 = 41300 * 1000;
+ priv->radio_if2 = 41300 * 1000;
} else {
tuner_dbg("pinnacle pal\n");
- t->radio_if2 = 33300 * 1000;
+ priv->radio_if2 = 33300 * 1000;
}
name = "unknown";
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 3ceb8a6249dd..f8f21ddd9843 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -617,7 +617,7 @@ static struct ov7670_win_size {
},
};
-#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
/*
@@ -1183,7 +1183,7 @@ static struct ov7670_control {
.query = ov7670_q_hflip,
},
};
-#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
static struct ov7670_control *ov7670_find_control(__u32 id)
{
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 1455a8f4e930..4ab1af74a970 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -353,9 +353,8 @@ static int planb_prepare_open(struct planb *pb)
* PLANB_DUMMY)*sizeof(struct dbdma_cmd)
+(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
+MAX_GBUFFERS*sizeof(unsigned int);
- if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
+ if ((pb->priv_space = kzalloc (size, GFP_KERNEL)) == 0)
return -ENOMEM;
- memset ((void *) pb->priv_space, 0, size);
pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
DBDMA_ALIGN (pb->priv_space);
pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 085332a503de..9c0e8d18c2f6 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1099,7 +1099,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
return -EBUSY;
}
- down(&pdev->modlock);
+ mutex_lock(&pdev->modlock);
if (!pdev->usb_init) {
PWC_DEBUG_OPEN("Doing first time initialization.\n");
pdev->usb_init = 1;
@@ -1131,7 +1131,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
if (i < 0) {
PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1172,7 +1172,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
if (i) {
PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1181,7 +1181,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
pwc_isoc_cleanup(pdev);
pwc_free_buffers(pdev);
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
return i;
}
@@ -1191,7 +1191,7 @@ static int pwc_video_open(struct inode *inode, struct file *file)
pdev->vopen++;
file->private_data = vdev;
- up(&pdev->modlock);
+ mutex_unlock(&pdev->modlock);
PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
return 0;
}
@@ -1685,7 +1685,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->angle_range.tilt_max = 2500;
}
- init_MUTEX(&pdev->modlock);
+ mutex_init(&pdev->modlock);
spin_lock_init(&pdev->ptrlock);
pdev->udev = udev;
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index acbb9312960a..910a04f53920 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -31,7 +31,7 @@
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <linux/version.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/errno.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
@@ -244,7 +244,7 @@ struct pwc_device
int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */
int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */
- struct semaphore modlock; /* to prevent races in video_open(), etc */
+ struct mutex modlock; /* to prevent races in video_open(), etc */
spinlock_t ptrlock; /* for manipulating the buffer pointers */
/*** motorized pan/tilt feature */
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index f2a2f34cd626..17f1e2e9a66b 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -86,9 +86,9 @@ static const int disp_modes[8][3] =
-#define PAGE_WAIT (300*HZ/1000) /* Time between requesting page and */
+#define PAGE_WAIT msecs_to_jiffies(300) /* Time between requesting page and */
/* checking status bits */
-#define PGBUF_EXPIRE (15*HZ) /* Time to wait before retransmitting */
+#define PGBUF_EXPIRE msecs_to_jiffies(15000) /* Time to wait before retransmitting */
/* page regardless of infobits */
typedef struct {
u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */
@@ -115,8 +115,8 @@ struct saa5249_device
#define CCTWR 34 /* I²C write/read-address of vtx-chip */
#define CCTRD 35
#define NOACK_REPEAT 10 /* Retry access this many times on failure */
-#define CLEAR_DELAY (HZ/20) /* Time required to clear a page */
-#define READY_TIMEOUT (30*HZ/1000) /* Time to wait for ready signal of I²C-bus interface */
+#define CLEAR_DELAY msecs_to_jiffies(50) /* Time required to clear a page */
+#define READY_TIMEOUT msecs_to_jiffies(30) /* Time to wait for ready signal of I2C-bus interface */
#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */
#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 676b9970eb2e..061134a7ba9f 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -208,7 +208,7 @@ determine_norm (struct i2c_client *client)
saa7110_write_block(client, initseq, sizeof(initseq));
saa7110_selmux(client, decoder->input);
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
+ schedule_timeout(msecs_to_jiffies(250));
finish_wait(&decoder->wq, &wait);
status = saa7110_read(client);
if (status & 0x40) {
@@ -249,7 +249,7 @@ determine_norm (struct i2c_client *client)
//saa7110_write(client,0x2E,0x9A);
prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ/4);
+ schedule_timeout(msecs_to_jiffies(250));
finish_wait(&decoder->wq, &wait);
status = saa7110_read(client);
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index c1a392e47170..7ae2d646d000 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -37,23 +37,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0644);
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 87c3144ec7fc..677df51de1a9 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -35,28 +35,26 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
-
#include <linux/slab.h>
-
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(x) (x)->name
-#include <linux/video_decoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 309dca368f4a..9f1417a4f7d2 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -40,7 +40,7 @@ config VIDEO_SAA7134_DVB
depends on VIDEO_SAA7134 && DVB_CORE
select VIDEO_BUF_DVB
select FW_LOADER
- select DVB_PLL
+ select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select DVB_NXT200X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ffb0f647a86d..3c0fc9027ad0 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -75,7 +75,8 @@ typedef struct snd_card_saa7134 {
struct saa7134_dev *dev;
unsigned long iobase;
- int irq;
+ s16 irq;
+ u16 mute_was_on;
spinlock_t lock;
} snd_card_saa7134_t;
@@ -589,8 +590,10 @@ static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
struct saa7134_dev *dev = saa7134->dev;
- dev->ctl_mute = 1;
- saa7134_tvaudio_setmute(dev);
+ if (saa7134->mute_was_on) {
+ dev->ctl_mute = 1;
+ saa7134_tvaudio_setmute(dev);
+ }
return 0;
}
@@ -637,8 +640,11 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
runtime->private_free = snd_card_saa7134_runtime_free;
runtime->hw = snd_card_saa7134_capture;
- dev->ctl_mute = 0;
- saa7134_tvaudio_setmute(dev);
+ if (dev->ctl_mute != 0) {
+ saa7134->mute_was_on = 1;
+ dev->ctl_mute = 0;
+ saa7134_tvaudio_setmute(dev);
+ }
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 50f15adfa7c8..8ec83bd70094 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -400,7 +400,7 @@ struct saa7134_board saa7134_boards[] = {
.inputs = {{
.name = name_tv,
.vmux = 1,
- .amux = LINE2,
+ .amux = TV,
.tv = 1,
.gpio = 0x20000,
},{
@@ -3502,6 +3502,38 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
},
},
+ [SAA7134_BOARD_10MOONSTVMASTER3] = {
+ /* Tony Wan <aloha_cn@hotmail.com> */
+ .name = "10MOONS TM300 TV Card",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x7000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x2000,
+ }},
+ .mute = {
+ .name = name_mute,
+ .amux = LINE2,
+ .gpio = 0x3000,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4219,6 +4251,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x2003, /* OEM cardbus */
.driver_data = SAA7134_BOARD_SABRENT_TV_PCB05,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2304,
+ .driver_data = SAA7134_BOARD_10MOONSTVMASTER3,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4330,6 +4368,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_A16AR:
case SAA7134_BOARD_ENCORE_ENLTV:
case SAA7134_BOARD_ENCORE_ENLTV_FM:
+ case SAA7134_BOARD_10MOONSTVMASTER3:
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_FLYDVBS_LR300:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e0eec80088c7..1f6bd3300715 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -175,18 +175,6 @@ static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
return mt352_pinnacle_init(fe);
}
-static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
- if (buf_len < 5)
- return -EINVAL;
-
- pllbuf[0] = 0x61;
- dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
- params->frequency,
- params->u.ofdm.bandwidth);
- return 5;
-}
-
static struct mt352_config pinnacle_300i = {
.demod_address = 0x3c >> 1,
.adc_clock = 20333,
@@ -444,135 +432,6 @@ static struct tda1004x_config philips_europa_config = {
/* ------------------------------------------------------------------ */
-static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- /* this message is to set up ATC and ALC */
- static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
- return -EIO;
- msleep(1);
-
- return 0;
-}
-
-static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- /* this message actually turns the tuner back to analog mode */
- u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
- msleep(1);
- fmd1216_init[2] = 0x86;
- fmd1216_init[3] = 0x54;
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
- msleep(1);
- return 0;
-}
-
-static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->tuner_address;
- u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
- sizeof(tuner_buf) };
- int tuner_frequency = 0;
- int divider = 0;
- u8 band, mode, cp;
-
- /* determine charge pump */
- tuner_frequency = params->frequency + 36130000;
- if (tuner_frequency < 87000000)
- return -EINVAL;
- /* low band */
- else if (tuner_frequency < 180000000) {
- band = 1;
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 195000000) {
- band = 1;
- mode = 6;
- cp = 1;
- /* mid band */
- } else if (tuner_frequency < 366000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 10;
- } else {
- band = 2;
- }
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 478000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 10;
- } else {
- band = 2;
- }
- mode = 6;
- cp = 1;
- /* high band */
- } else if (tuner_frequency < 662000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 7;
- cp = 0;
- } else if (tuner_frequency < 840000000) {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 6;
- cp = 1;
- } else {
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
- band = 12;
- } else {
- band = 4;
- }
- mode = 7;
- cp = 1;
-
- }
- /* calculate divisor */
- /* ((36166000 + Finput) / 166666) rounded! */
- divider = (tuner_frequency + 83333) / 166667;
-
- /* setup tuner buffer */
- tuner_buf[0] = (divider >> 8) & 0x7f;
- tuner_buf[1] = divider & 0xff;
- tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4;
- tuner_buf[3] = 0x40 | band;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
- wprintk("could not write to tuner at addr: 0x%02x\n",
- addr << 1);
- return -EIO;
- }
- return 0;
-}
-
static struct tda1004x_config medion_cardbus = {
.demod_address = 0x08,
.invert = 1,
@@ -958,18 +817,8 @@ static struct nxt200x_config avertvhda180 = {
.demod_address = 0x0a,
};
-static int nxt200x_set_pll_input(u8 *buf, int input)
-{
- if (input)
- buf[3] |= 0x08;
- else
- buf[3] &= ~0x08;
- return 0;
-}
-
static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
- .set_pll_input = nxt200x_set_pll_input,
};
/* ==================================================================
@@ -1005,7 +854,8 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, DVB_PLL_PHILIPS_TD1316);
}
break;
case SAA7134_BOARD_MD7134:
@@ -1013,9 +863,8 @@ static int dvb_init(struct saa7134_dev *dev)
&medion_cardbus,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+ &dev->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -1113,7 +962,7 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tdhu2);
+ NULL, DVB_PLL_TDHU2);
}
break;
case SAA7134_BOARD_KWORLD_ATSC110:
@@ -1121,7 +970,7 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap);
if (dev->dvb.frontend) {
dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, &dvb_pll_tuv1236d);
+ NULL, DVB_PLL_TUV1236D);
}
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1144,9 +993,9 @@ static int dvb_init(struct saa7134_dev *dev)
if (dev->dvb.frontend) {
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
- dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+ &dev->i2c_adap, DVB_PLL_FMD1216ME);
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index f521603482ca..fc260ec8fdc2 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -96,6 +96,10 @@ static int ts_open(struct inode *inode, struct file *file)
if (dev->empress_users)
goto done_up;
+ /* Unmute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+
dev->empress_users++;
file->private_data = dev;
err = 0;
@@ -121,6 +125,10 @@ static int ts_release(struct inode *inode, struct file *file)
/* stop the encoder */
ts_reset_encoder(dev);
+ /* Mute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+
mutex_unlock(&dev->empress_tsq.lock);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index c0de37e3f5c6..1b6dfd801cc1 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -153,21 +153,18 @@ void saa7134_input_irq(struct saa7134_dev *dev)
static void saa7134_input_timer(unsigned long data)
{
- struct saa7134_dev *dev = (struct saa7134_dev*)data;
+ struct saa7134_dev *dev = (struct saa7134_dev *)data;
struct card_ir *ir = dev->remote;
- unsigned long timeout;
build_key(dev);
- timeout = jiffies + (ir->polling * HZ / 1000);
- mod_timer(&ir->timer, timeout);
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
{
if (ir->polling) {
- init_timer(&ir->timer);
- ir->timer.function = saa7134_input_timer;
- ir->timer.data = (unsigned long)dev;
+ setup_timer(&ir->timer, saa7134_input_timer,
+ (unsigned long)dev);
ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
@@ -314,6 +311,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0x003F00;
mask_keyup = 0x040000;
break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
case SAA7134_BOARD_FLYDVBT_LR301:
case SAA7134_BOARD_FLYDVBTDUO:
ir_codes = ir_codes_flydvb;
@@ -333,6 +331,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x040000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_10MOONSTVMASTER3:
+ ir_codes = ir_codes_encore_enltv;
+ mask_keycode = 0x5f80000;
+ mask_keyup = 0x8000000;
+ polling = 50; //ms
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -374,7 +378,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
input_dev->id.vendor = dev->pci->vendor;
input_dev->id.product = dev->pci->device;
}
- input_dev->cdev.dev = &dev->pci->dev;
+ input_dev->dev.parent = &dev->pci->dev;
dev->remote = ir;
saa7134_ir_start(dev, ir);
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 30395d6b5f14..18b4817b4aac 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
+#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/div64.h>
@@ -341,10 +342,8 @@ static void tvaudio_setmode(struct saa7134_dev *dev,
static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
{
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&dev->thread.wq, &wait);
- if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+ if (dev->thread.scan1 == dev->thread.scan2 &&
+ !kthread_should_stop()) {
if (timeout < 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
@@ -353,7 +352,6 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
(msecs_to_jiffies(timeout));
}
}
- remove_wait_queue(&dev->thread.wq, &wait);
return dev->thread.scan1 != dev->thread.scan2;
}
@@ -505,11 +503,10 @@ static int tvaudio_thread(void *data)
unsigned int i, audio, nscan;
int max1,max2,carrier,rx,mode,lastmode,default_carrier;
- daemonize("%s", dev->name);
allow_signal(SIGTERM);
for (;;) {
tvaudio_sleep(dev,-1);
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
goto done;
restart:
@@ -618,7 +615,7 @@ static int tvaudio_thread(void *data)
for (;;) {
if (tvaudio_sleep(dev,5000))
goto restart;
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
break;
if (UNSET == dev->thread.mode) {
rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -634,7 +631,6 @@ static int tvaudio_thread(void *data)
}
done:
- complete_and_exit(&dev->thread.exit, 0);
return 0;
}
@@ -782,7 +778,6 @@ static int tvaudio_thread_ddep(void *data)
struct saa7134_dev *dev = data;
u32 value, norms, clock;
- daemonize("%s", dev->name);
allow_signal(SIGTERM);
clock = saa7134_boards[dev->board].audio_clock;
@@ -796,7 +791,7 @@ static int tvaudio_thread_ddep(void *data)
for (;;) {
tvaudio_sleep(dev,-1);
- if (dev->thread.shutdown || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
goto done;
restart:
@@ -876,7 +871,6 @@ static int tvaudio_thread_ddep(void *data)
}
done:
- complete_and_exit(&dev->thread.exit, 0);
return 0;
}
@@ -973,7 +967,6 @@ int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
int saa7134_tvaudio_init2(struct saa7134_dev *dev)
{
- DECLARE_MUTEX_LOCKED(sem);
int (*my_thread)(void *data) = NULL;
switch (dev->pci->device) {
@@ -986,15 +979,15 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
break;
}
- dev->thread.pid = -1;
+ dev->thread.thread = NULL;
if (my_thread) {
/* start tvaudio thread */
- init_waitqueue_head(&dev->thread.wq);
- init_completion(&dev->thread.exit);
- dev->thread.pid = kernel_thread(my_thread,dev,0);
- if (dev->thread.pid < 0)
+ dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+ if (IS_ERR(dev->thread.thread)) {
printk(KERN_WARNING "%s: kernel_thread() failed\n",
dev->name);
+ /* XXX: missing error handling here */
+ }
saa7134_tvaudio_do_scan(dev);
}
@@ -1005,11 +998,9 @@ int saa7134_tvaudio_init2(struct saa7134_dev *dev)
int saa7134_tvaudio_fini(struct saa7134_dev *dev)
{
/* shutdown tvaudio thread */
- if (dev->thread.pid > 0) {
- dev->thread.shutdown = 1;
- wake_up_interruptible(&dev->thread.wq);
- wait_for_completion(&dev->thread.exit);
- }
+ if (dev->thread.thread)
+ kthread_stop(dev->thread.thread);
+
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
return 0;
}
@@ -1020,10 +1011,10 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
dprintk("sound IF not in use, skipping scan\n");
dev->automute = 0;
saa7134_tvaudio_setmute(dev);
- } else if (dev->thread.pid >= 0) {
+ } else if (dev->thread.thread) {
dev->thread.mode = UNSET;
dev->thread.scan2++;
- wake_up_interruptible(&dev->thread.wq);
+ wake_up_process(dev->thread.thread);
} else {
dev->automute = 0;
saa7134_tvaudio_setmute(dev);
@@ -1040,4 +1031,3 @@ EXPORT_SYMBOL(saa7134_tvaudio_setmute);
* c-basic-offset: 8
* End:
*/
-
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 15623b27ad2e..346255468dad 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -238,6 +238,7 @@ struct saa7134_format {
#define SAA7134_BOARD_ECS_TVP3XP_4CB6 113
#define SAA7134_BOARD_KWORLD_DVBT_210 114
#define SAA7134_BOARD_SABRENT_TV_PCB05 115
+#define SAA7134_BOARD_10MOONSTVMASTER3 116
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -313,7 +314,7 @@ struct saa7134_board {
#define INTERLACE_ON 1
#define INTERLACE_OFF 2
-#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
struct saa7134_dev;
struct saa7134_dma;
@@ -327,10 +328,7 @@ struct saa7134_pgtable {
/* tvaudio thread status */
struct saa7134_thread {
- pid_t pid;
- struct completion exit;
- wait_queue_head_t wq;
- unsigned int shutdown;
+ struct task_struct *thread;
unsigned int scan1;
unsigned int scan2;
unsigned int mode;
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 339592e7722d..66cc92c0ea66 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -34,23 +34,23 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
#include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
MODULE_AUTHOR("Dave Perks");
MODULE_LICENSE("GPL");
-#include <linux/i2c.h>
#define I2C_NAME(s) (s)->name
-#include <linux/video_encoder.h>
static int debug = 0;
module_param(debug, int, 0);
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 11fcb49f5b99..2e3c3de793a7 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/stddef.h>
+#include <linux/kref.h>
#include "sn9c102_config.h"
#include "sn9c102_sensor.h"
@@ -94,7 +95,7 @@ struct sn9c102_module_param {
};
static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
+static DECLARE_RWSEM(sn9c102_dev_lock);
struct sn9c102_device {
struct video_device* v4ldev;
@@ -122,12 +123,14 @@ struct sn9c102_device {
struct sn9c102_module_param module_param;
+ struct kref kref;
enum sn9c102_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 74a204f8ebc8..36d8a455e0ec 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -48,8 +48,8 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004-2007 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.44"
-#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 44)
+#define SN9C102_MODULE_VERSION "1:1.47"
+#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 47)
/*****************************************************************************/
@@ -64,9 +64,10 @@ MODULE_LICENSE(SN9C102_MODULE_LICENSE);
static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
module_param_array(video_nr, short, NULL, 0444);
MODULE_PARM_DESC(video_nr,
- "\n<-1|n[,...]> Specify V4L2 minor mode number."
- "\n -1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
+ " <-1|n[,...]>"
+ "\nSpecify V4L2 minor mode number."
+ "\n-1 = use next available (default)"
+ "\n n = use minor number n (integer >= 0)"
"\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
" cameras this way."
"\nFor example:"
@@ -79,13 +80,14 @@ static short force_munmap[] = {[0 ... SN9C102_MAX_DEVICES-1] =
SN9C102_FORCE_MUNMAP};
module_param_array(force_munmap, bool, NULL, 0444);
MODULE_PARM_DESC(force_munmap,
- "\n<0|1[,...]> Force the application to unmap previously"
+ " <0|1[,...]>"
+ "\nForce the application to unmap previously"
"\nmapped buffer memory before calling any VIDIOC_S_CROP or"
"\nVIDIOC_S_FMT ioctl's. Not all the applications support"
"\nthis feature. This parameter is specific for each"
"\ndetected camera."
- "\n 0 = do not force memory unmapping"
- "\n 1 = force memory unmapping (save memory)"
+ "\n0 = do not force memory unmapping"
+ "\n1 = force memory unmapping (save memory)"
"\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
"\n");
@@ -93,7 +95,8 @@ static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
SN9C102_FRAME_TIMEOUT};
module_param_array(frame_timeout, uint, NULL, 0644);
MODULE_PARM_DESC(frame_timeout,
- "\n<0|n[,...]> Timeout for a video frame in seconds before"
+ " <0|n[,...]>"
+ "\nTimeout for a video frame in seconds before"
"\nreturning an I/O error; 0 for infinity."
"\nThis parameter is specific for each detected camera."
"\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
@@ -103,7 +106,8 @@ MODULE_PARM_DESC(frame_timeout,
static unsigned short debug = SN9C102_DEBUG_LEVEL;
module_param(debug, ushort, 0644);
MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 3:"
+ " <n>"
+ "\nDebugging information level, from 0 to 3:"
"\n0 = none (use carefully)"
"\n1 = critical errors"
"\n2 = significant informations"
@@ -1616,7 +1620,8 @@ static int sn9c102_init(struct sn9c102_device* cam)
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
} else { /* use current values */
@@ -1706,21 +1711,27 @@ static int sn9c102_init(struct sn9c102_device* cam)
return 0;
}
+/*****************************************************************************/
-static void sn9c102_release_resources(struct sn9c102_device* cam)
+static void sn9c102_release_resources(struct kref *kref)
{
+ struct sn9c102_device *cam;
+
mutex_lock(&sn9c102_sysfs_lock);
+ cam = container_of(kref, struct sn9c102_device, kref);
+
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
+ kfree(cam->control_buffer);
+ kfree(cam);
mutex_unlock(&sn9c102_sysfs_lock);
- kfree(cam->control_buffer);
}
-/*****************************************************************************/
static int sn9c102_open(struct inode* inode, struct file* filp)
{
@@ -1728,43 +1739,78 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
int err = 0;
/*
- This is the only safe way to prevent race conditions with
- disconnect
+ A read_trylock() in open() is the only safe way to prevent race
+ conditions with disconnect(), one close() and multiple (not
+ necessarily simultaneous) attempts to open(). For example, it
+ prevents from waiting for a second access, while the device
+ structure is being deallocated, after a possible disconnect() and
+ during a following close() holding the write lock: given that, after
+ this deallocation, no access will be possible anymore, using the
+ non-trylock version would have let open() gain the access to the
+ device structure improperly.
+ For this reason the lock must also not be per-device.
*/
- if (!down_read_trylock(&sn9c102_disconnect))
+ if (!down_read_trylock(&sn9c102_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&sn9c102_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&sn9c102_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ kref_get(&cam->kref);
+
+ /*
+ Make sure to isolate all the simultaneous opens.
+ */
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, sn9c102_release_resources);
+ up_read(&sn9c102_dev_lock);
return -ERESTARTSYS;
}
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
- DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(2, "Device /dev/video%d is already in use",
+ cam->v4ldev->minor);
DBG(3, "Simultaneous opens are not supported");
+ /*
+ open() must follow the open flags and should block
+ eventually while the device is in use.
+ */
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&sn9c102_dev_lock);
+ /*
+ We will not release the "open_mutex" lock, so that only one
+ process can be in the wait queue below. This way the process
+ will be sleeping while holding the lock, without loosing its
+ priority after any wake_up().
+ */
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&sn9c102_disconnect);
- return err;
- }
+ down_read(&sn9c102_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&sn9c102_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = sn9c102_init(cam);
if (err) {
@@ -1789,36 +1835,33 @@ static int sn9c102_open(struct inode* inode, struct file* filp)
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&sn9c102_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, sn9c102_release_resources);
+
+ up_read(&sn9c102_dev_lock);
return err;
}
static int sn9c102_release(struct inode* inode, struct file* filp)
{
- struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+ struct sn9c102_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&sn9c102_dev_lock);
- sn9c102_stop_transfer(cam);
+ cam = video_get_drvdata(video_devdata(filp));
+ sn9c102_stop_transfer(cam);
sn9c102_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- sn9c102_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, sn9c102_release_resources);
+
+ up_write(&sn9c102_dev_lock);
return 0;
}
@@ -2085,7 +2128,6 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
vma->vm_ops = &sn9c102_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
sn9c102_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -3215,8 +3257,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
r = sn9c102_read_reg(cam, 0x00);
if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
DBG(1, "Sorry, this is not a SN9C1xx-based camera "
@@ -3282,7 +3322,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -3292,7 +3332,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -3318,8 +3358,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
#endif
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -3336,40 +3378,31 @@ fail:
static void sn9c102_usb_disconnect(struct usb_interface* intf)
{
- struct sn9c102_device* cam = usb_get_intfdata(intf);
-
- if (!cam)
- return;
+ struct sn9c102_device* cam;
- down_write(&sn9c102_disconnect);
+ down_write(&sn9c102_dev_lock);
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
sn9c102_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- sn9c102_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, sn9c102_release_resources);
- up_write(&sn9c102_disconnect);
+ up_write(&sn9c102_dev_lock);
}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index e6832347894f..e4856fd77982 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -104,6 +104,145 @@ static int ov7630_init(struct sn9c102_device* cam)
err += sn9c102_i2c_write(cam, 0x74, 0x21);
err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
+ {0x1a, 0x04}, {0x03, 0x10},
+ {0x0a, 0x14}, {0xe2, 0x17},
+ {0x0b, 0x18}, {0x00, 0x19},
+ {0x1d, 0x1a}, {0x10, 0x1b},
+ {0x02, 0x1c}, {0x03, 0x1d},
+ {0x0f, 0x1e}, {0x0c, 0x1f},
+ {0x00, 0x20}, {0x24, 0x21},
+ {0x3b, 0x22}, {0x47, 0x23},
+ {0x60, 0x24}, {0x71, 0x25},
+ {0x80, 0x26}, {0x8f, 0x27},
+ {0x9d, 0x28}, {0xaa, 0x29},
+ {0xb8, 0x2a}, {0xc4, 0x2b},
+ {0xd1, 0x2c}, {0xdd, 0x2d},
+ {0xe8, 0x2e}, {0xf4, 0x2f},
+ {0xff, 0x30}, {0x00, 0x3f},
+ {0xc7, 0x40}, {0x01, 0x41},
+ {0x44, 0x42}, {0x00, 0x43},
+ {0x44, 0x44}, {0x00, 0x45},
+ {0x44, 0x46}, {0x00, 0x47},
+ {0xc7, 0x48}, {0x01, 0x49},
+ {0xc7, 0x4a}, {0x01, 0x4b},
+ {0xc7, 0x4c}, {0x01, 0x4d},
+ {0x44, 0x4e}, {0x00, 0x4f},
+ {0x44, 0x50}, {0x00, 0x51},
+ {0x44, 0x52}, {0x00, 0x53},
+ {0xc7, 0x54}, {0x01, 0x55},
+ {0xc7, 0x56}, {0x01, 0x57},
+ {0xc7, 0x58}, {0x01, 0x59},
+ {0x44, 0x5a}, {0x00, 0x5b},
+ {0x44, 0x5c}, {0x00, 0x5d},
+ {0x44, 0x5e}, {0x00, 0x5f},
+ {0xc7, 0x60}, {0x01, 0x61},
+ {0xc7, 0x62}, {0x01, 0x63},
+ {0xc7, 0x64}, {0x01, 0x65},
+ {0x44, 0x66}, {0x00, 0x67},
+ {0x44, 0x68}, {0x00, 0x69},
+ {0x44, 0x6a}, {0x00, 0x6b},
+ {0xc7, 0x6c}, {0x01, 0x6d},
+ {0xc7, 0x6e}, {0x01, 0x6f},
+ {0xc7, 0x70}, {0x01, 0x71},
+ {0x44, 0x72}, {0x00, 0x73},
+ {0x44, 0x74}, {0x00, 0x75},
+ {0x44, 0x76}, {0x00, 0x77},
+ {0xc7, 0x78}, {0x01, 0x79},
+ {0xc7, 0x7a}, {0x01, 0x7b},
+ {0xc7, 0x7c}, {0x01, 0x7d},
+ {0x44, 0x7e}, {0x00, 0x7f},
+ {0x17, 0x84}, {0x00, 0x85},
+ {0x2e, 0x86}, {0x00, 0x87},
+ {0x09, 0x88}, {0x00, 0x89},
+ {0xe8, 0x8a}, {0x0f, 0x8b},
+ {0xda, 0x8c}, {0x0f, 0x8d},
+ {0x40, 0x8e}, {0x00, 0x8f},
+ {0x37, 0x90}, {0x00, 0x91},
+ {0xcf, 0x92}, {0x0f, 0x93},
+ {0xfa, 0x94}, {0x0f, 0x95},
+ {0x00, 0x96}, {0x00, 0x97},
+ {0x00, 0x98}, {0x66, 0x99},
+ {0x00, 0x9a}, {0x40, 0x9b},
+ {0x20, 0x9c}, {0x00, 0x9d},
+ {0x00, 0x9e}, {0x00, 0x9f},
+ {0x2d, 0xc0}, {0x2d, 0xc1},
+ {0x3a, 0xc2}, {0x00, 0xc3},
+ {0x04, 0xc4}, {0x3f, 0xc5},
+ {0x00, 0xc6}, {0x00, 0xc7},
+ {0x50, 0xc8}, {0x3c, 0xc9},
+ {0x28, 0xca}, {0xd8, 0xcb},
+ {0x14, 0xcc}, {0xec, 0xcd},
+ {0x32, 0xce}, {0xdd, 0xcf},
+ {0x32, 0xd0}, {0xdd, 0xd1},
+ {0x6a, 0xd2}, {0x50, 0xd3},
+ {0x60, 0xd4}, {0x00, 0xd5},
+ {0x00, 0xd6});
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x80);
+ err += sn9c102_i2c_write(cam, 0x12, 0x48);
+ err += sn9c102_i2c_write(cam, 0x01, 0x80);
+ err += sn9c102_i2c_write(cam, 0x02, 0x80);
+ err += sn9c102_i2c_write(cam, 0x03, 0x80);
+ err += sn9c102_i2c_write(cam, 0x04, 0x10);
+ err += sn9c102_i2c_write(cam, 0x05, 0x20);
+ err += sn9c102_i2c_write(cam, 0x06, 0x80);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
+ err += sn9c102_i2c_write(cam, 0x0c, 0x20);
+ err += sn9c102_i2c_write(cam, 0x0d, 0x20);
+ err += sn9c102_i2c_write(cam, 0x15, 0x80);
+ err += sn9c102_i2c_write(cam, 0x16, 0x03);
+ err += sn9c102_i2c_write(cam, 0x17, 0x1b);
+ err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+ err += sn9c102_i2c_write(cam, 0x19, 0x05);
+ err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+ err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+ err += sn9c102_i2c_write(cam, 0x21, 0x1b);
+ err += sn9c102_i2c_write(cam, 0x22, 0x00);
+ err += sn9c102_i2c_write(cam, 0x23, 0xde);
+ err += sn9c102_i2c_write(cam, 0x24, 0x10);
+ err += sn9c102_i2c_write(cam, 0x25, 0x8a);
+ err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x27, 0xca);
+ err += sn9c102_i2c_write(cam, 0x28, 0xa2);
+ err += sn9c102_i2c_write(cam, 0x29, 0x74);
+ err += sn9c102_i2c_write(cam, 0x2a, 0x88);
+ err += sn9c102_i2c_write(cam, 0x2b, 0x34);
+ err += sn9c102_i2c_write(cam, 0x2c, 0x88);
+ err += sn9c102_i2c_write(cam, 0x2e, 0x00);
+ err += sn9c102_i2c_write(cam, 0x2f, 0x00);
+ err += sn9c102_i2c_write(cam, 0x30, 0x00);
+ err += sn9c102_i2c_write(cam, 0x32, 0xc2);
+ err += sn9c102_i2c_write(cam, 0x33, 0x08);
+ err += sn9c102_i2c_write(cam, 0x4c, 0x40);
+ err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
+ err += sn9c102_i2c_write(cam, 0x60, 0x05);
+ err += sn9c102_i2c_write(cam, 0x61, 0x40);
+ err += sn9c102_i2c_write(cam, 0x62, 0x12);
+ err += sn9c102_i2c_write(cam, 0x63, 0x57);
+ err += sn9c102_i2c_write(cam, 0x64, 0x73);
+ err += sn9c102_i2c_write(cam, 0x65, 0x00);
+ err += sn9c102_i2c_write(cam, 0x66, 0x55);
+ err += sn9c102_i2c_write(cam, 0x67, 0x01);
+ err += sn9c102_i2c_write(cam, 0x68, 0xac);
+ err += sn9c102_i2c_write(cam, 0x69, 0x38);
+ err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
+ err += sn9c102_i2c_write(cam, 0x70, 0x01);
+ err += sn9c102_i2c_write(cam, 0x71, 0x00);
+ err += sn9c102_i2c_write(cam, 0x72, 0x10);
+ err += sn9c102_i2c_write(cam, 0x73, 0x50);
+ err += sn9c102_i2c_write(cam, 0x74, 0x20);
+ err += sn9c102_i2c_write(cam, 0x76, 0x01);
+ err += sn9c102_i2c_write(cam, 0x77, 0xf3);
+ err += sn9c102_i2c_write(cam, 0x78, 0x90);
+ err += sn9c102_i2c_write(cam, 0x79, 0x98);
+ err += sn9c102_i2c_write(cam, 0x7a, 0x98);
+ err += sn9c102_i2c_write(cam, 0x7b, 0x00);
+ err += sn9c102_i2c_write(cam, 0x7c, 0x38);
+ err += sn9c102_i2c_write(cam, 0x7d, 0xff);
+ break;
default:
break;
}
@@ -115,6 +254,7 @@ static int ov7630_init(struct sn9c102_device* cam)
static int ov7630_get_ctrl(struct sn9c102_device* cam,
struct v4l2_control* ctrl)
{
+ enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
switch (ctrl->id) {
@@ -123,13 +263,20 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
return -EIO;
break;
case V4L2_CID_RED_BALANCE:
- ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ else
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
ctrl->value = sn9c102_pread_reg(cam, 0x06);
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ ctrl->value = sn9c102_pread_reg(cam, 0x07);
+ else
+ ctrl->value = sn9c102_pread_reg(cam, 0x05);
+ break;
break;
case V4L2_CID_GAIN:
if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
@@ -177,6 +324,7 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
static int ov7630_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
+ enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
switch (ctrl->id) {
@@ -184,13 +332,19 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
case V4L2_CID_RED_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ else
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
break;
case V4L2_CID_BLUE_BALANCE:
err += sn9c102_write_reg(cam, ctrl->value, 0x06);
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
- err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+ if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+ err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+ else
+ err += sn9c102_write_reg(cam, ctrl->value, 0x05);
break;
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -227,8 +381,21 @@ static int ov7630_set_crop(struct sn9c102_device* cam,
{
struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
int err = 0;
- u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
- v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+ u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+ break;
+ default:
+ break;
+ }
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -242,10 +409,28 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
{
int err = 0;
- if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
- err += sn9c102_write_reg(cam, 0x20, 0x19);
- else
- err += sn9c102_write_reg(cam, 0x50, 0x19);
+ switch (sn9c102_get_bridge(cam)) {
+ case BRIDGE_SN9C101:
+ case BRIDGE_SN9C102:
+ case BRIDGE_SN9C103:
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
+ err += sn9c102_write_reg(cam, 0x50, 0x19);
+ else
+ err += sn9c102_write_reg(cam, 0x20, 0x19);
+ break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+ err += sn9c102_write_reg(cam, 0xe5, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x04);
+ } else {
+ err += sn9c102_write_reg(cam, 0xe2, 0x17);
+ err += sn9c102_i2c_write(cam, 0x11, 0x02);
+ }
+ break;
+ default:
+ break;
+ }
return err;
}
@@ -254,7 +439,8 @@ static int ov7630_set_pix_format(struct sn9c102_device* cam,
static const struct sn9c102_sensor ov7630 = {
.name = "OV7630",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
- .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+ .supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
+ BRIDGE_SN9C105 | BRIDGE_SN9C120,
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
@@ -417,6 +603,12 @@ int sn9c102_probe_ov7630(struct sn9c102_device* cam)
err += sn9c102_write_const_regs(cam, {0x01, 0x01},
{0x00, 0x01});
break;
+ case BRIDGE_SN9C105:
+ case BRIDGE_SN9C120:
+ err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+ {0x29, 0x01}, {0x74, 0x02},
+ {0x0e, 0x01}, {0x44, 0x01});
+ break;
default:
break;
}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
index 4b6474048a72..8aae416ba8ec 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7660.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -41,65 +41,65 @@ static int ov7660_init(struct sn9c102_device* cam)
{0xbb, 0x2a}, {0xc7, 0x2b},
{0xd3, 0x2c}, {0xde, 0x2d},
{0xea, 0x2e}, {0xf4, 0x2f},
- {0xff, 0x30}, {0x00, 0x3F},
- {0xC7, 0x40}, {0x01, 0x41},
+ {0xff, 0x30}, {0x00, 0x3f},
+ {0xc7, 0x40}, {0x01, 0x41},
{0x44, 0x42}, {0x00, 0x43},
{0x44, 0x44}, {0x00, 0x45},
{0x44, 0x46}, {0x00, 0x47},
- {0xC7, 0x48}, {0x01, 0x49},
- {0xC7, 0x4A}, {0x01, 0x4B},
- {0xC7, 0x4C}, {0x01, 0x4D},
- {0x44, 0x4E}, {0x00, 0x4F},
+ {0xc7, 0x48}, {0x01, 0x49},
+ {0xc7, 0x4a}, {0x01, 0x4b},
+ {0xc7, 0x4c}, {0x01, 0x4d},
+ {0x44, 0x4e}, {0x00, 0x4f},
{0x44, 0x50}, {0x00, 0x51},
{0x44, 0x52}, {0x00, 0x53},
- {0xC7, 0x54}, {0x01, 0x55},
- {0xC7, 0x56}, {0x01, 0x57},
- {0xC7, 0x58}, {0x01, 0x59},
- {0x44, 0x5A}, {0x00, 0x5B},
- {0x44, 0x5C}, {0x00, 0x5D},
- {0x44, 0x5E}, {0x00, 0x5F},
- {0xC7, 0x60}, {0x01, 0x61},
- {0xC7, 0x62}, {0x01, 0x63},
- {0xC7, 0x64}, {0x01, 0x65},
+ {0xc7, 0x54}, {0x01, 0x55},
+ {0xc7, 0x56}, {0x01, 0x57},
+ {0xc7, 0x58}, {0x01, 0x59},
+ {0x44, 0x5a}, {0x00, 0x5b},
+ {0x44, 0x5c}, {0x00, 0x5d},
+ {0x44, 0x5e}, {0x00, 0x5f},
+ {0xc7, 0x60}, {0x01, 0x61},
+ {0xc7, 0x62}, {0x01, 0x63},
+ {0xc7, 0x64}, {0x01, 0x65},
{0x44, 0x66}, {0x00, 0x67},
{0x44, 0x68}, {0x00, 0x69},
- {0x44, 0x6A}, {0x00, 0x6B},
- {0xC7, 0x6C}, {0x01, 0x6D},
- {0xC7, 0x6E}, {0x01, 0x6F},
- {0xC7, 0x70}, {0x01, 0x71},
+ {0x44, 0x6a}, {0x00, 0x6b},
+ {0xc7, 0x6c}, {0x01, 0x6d},
+ {0xc7, 0x6e}, {0x01, 0x6f},
+ {0xc7, 0x70}, {0x01, 0x71},
{0x44, 0x72}, {0x00, 0x73},
{0x44, 0x74}, {0x00, 0x75},
{0x44, 0x76}, {0x00, 0x77},
- {0xC7, 0x78}, {0x01, 0x79},
- {0xC7, 0x7A}, {0x01, 0x7B},
- {0xC7, 0x7C}, {0x01, 0x7D},
- {0x44, 0x7E}, {0x00, 0x7F},
+ {0xc7, 0x78}, {0x01, 0x79},
+ {0xc7, 0x7a}, {0x01, 0x7b},
+ {0xc7, 0x7c}, {0x01, 0x7d},
+ {0x44, 0x7e}, {0x00, 0x7f},
{0x14, 0x84}, {0x00, 0x85},
{0x27, 0x86}, {0x00, 0x87},
{0x07, 0x88}, {0x00, 0x89},
- {0xEC, 0x8A}, {0x0f, 0x8B},
- {0xD8, 0x8C}, {0x0f, 0x8D},
- {0x3D, 0x8E}, {0x00, 0x8F},
- {0x3D, 0x90}, {0x00, 0x91},
- {0xCD, 0x92}, {0x0f, 0x93},
+ {0xec, 0x8a}, {0x0f, 0x8b},
+ {0xd8, 0x8c}, {0x0f, 0x8d},
+ {0x3d, 0x8e}, {0x00, 0x8f},
+ {0x3d, 0x90}, {0x00, 0x91},
+ {0xcd, 0x92}, {0x0f, 0x93},
{0xf7, 0x94}, {0x0f, 0x95},
- {0x0C, 0x96}, {0x00, 0x97},
+ {0x0c, 0x96}, {0x00, 0x97},
{0x00, 0x98}, {0x66, 0x99},
- {0x05, 0x9A}, {0x00, 0x9B},
- {0x04, 0x9C}, {0x00, 0x9D},
- {0x08, 0x9E}, {0x00, 0x9F},
- {0x2D, 0xC0}, {0x2D, 0xC1},
- {0x3A, 0xC2}, {0x05, 0xC3},
- {0x04, 0xC4}, {0x3F, 0xC5},
- {0x00, 0xC6}, {0x00, 0xC7},
- {0x50, 0xC8}, {0x3C, 0xC9},
- {0x28, 0xCA}, {0xD8, 0xCB},
- {0x14, 0xCC}, {0xEC, 0xCD},
- {0x32, 0xCE}, {0xDD, 0xCF},
- {0x32, 0xD0}, {0xDD, 0xD1},
- {0x6A, 0xD2}, {0x50, 0xD3},
- {0x00, 0xD4}, {0x00, 0xD5},
- {0x00, 0xD6});
+ {0x05, 0x9a}, {0x00, 0x9b},
+ {0x04, 0x9c}, {0x00, 0x9d},
+ {0x08, 0x9e}, {0x00, 0x9f},
+ {0x2d, 0xc0}, {0x2d, 0xc1},
+ {0x3a, 0xc2}, {0x05, 0xc3},
+ {0x04, 0xc4}, {0x3f, 0xc5},
+ {0x00, 0xc6}, {0x00, 0xc7},
+ {0x50, 0xc8}, {0x3C, 0xc9},
+ {0x28, 0xca}, {0xd8, 0xcb},
+ {0x14, 0xcc}, {0xec, 0xcd},
+ {0x32, 0xce}, {0xdd, 0xcf},
+ {0x32, 0xd0}, {0xdd, 0xd1},
+ {0x6a, 0xd2}, {0x50, 0xd3},
+ {0x00, 0xd4}, {0x00, 0xd5},
+ {0x00, 0xd6});
err += sn9c102_i2c_write(cam, 0x12, 0x80);
err += sn9c102_i2c_write(cam, 0x11, 0x09);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 3e736be5de84..eb220461ac77 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1321,7 +1321,7 @@ static int saa_ioctl(struct inode *inode, struct file *file,
u32 format;
if (copy_from_user(&p, arg, sizeof(p)))
return -EFAULT;
- if (p.palette < sizeof(palette2fmt) / sizeof(u32)) {
+ if (p.palette < ARRAY_SIZE(palette2fmt)) {
format = palette2fmt[p.palette];
saa->win.color_fmt = format;
saawrite(format | 0x60,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index bf3aa8d2d57e..4dc5bc714b95 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -715,8 +715,11 @@ static int stv680_start_stream (struct usb_stv *stv680)
stv680_video_irq, stv680);
stv680->urb[i] = urb;
err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
- if (err)
- PDEBUG (0, "STV(e): urb burned down in start stream");
+ if (err) {
+ PDEBUG (0, "STV(e): urb burned down with err "
+ "%d in start stream %d", err, i);
+ goto nomem_err;
+ }
} /* i STV680_NUMSBUF */
stv680->framecount = 0;
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 1a1bef0e9c3d..59cff5a3c59e 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -21,7 +21,17 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
+
+/* ---------------------------------------------------------------------- */
+
+struct tda8290_priv {
+ unsigned char tda8290_easy_mode;
+ unsigned char tda827x_lpsel;
+ unsigned char tda827x_addr;
+ unsigned char tda827x_ver;
+ unsigned int sgIF;
+};
/* ---------------------------------------------------------------------- */
@@ -76,7 +86,8 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
u32 N;
int i;
struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+ struct tda8290_priv *priv = t->priv;
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
if (t->mode == V4L2_TUNER_RADIO)
freq = freq / 1000;
@@ -95,7 +106,7 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
tuner_reg[1] = (unsigned char)(N>>8);
tuner_reg[2] = (unsigned char) N;
tuner_reg[3] = 0x40;
- tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+ tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
tuner_reg[5] = (tda827x_analog[i].spd << 6) + (tda827x_analog[i].div1p5 <<5) +
(tda827x_analog[i].bs <<3) + tda827x_analog[i].bp;
tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
@@ -146,8 +157,9 @@ static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
static void tda827x_agcf(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char data[] = {0x80, 0x0c};
- struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
i2c_transfer(c->adapter, &msg, 1);
}
@@ -234,7 +246,8 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
u32 N;
int i;
struct tuner *t = i2c_get_clientdata(c);
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+ struct tda8290_priv *priv = t->priv;
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
tda827xa_lna_gain( c, 1);
msleep(10);
@@ -271,7 +284,7 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
tuner_reg[1] = 0xff;
tuner_reg[2] = 0xe0;
tuner_reg[3] = 0;
- tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+ tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
msg.len = 5;
i2c_transfer(c->adapter, &msg, 1);
@@ -311,15 +324,16 @@ static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
i2c_transfer(c->adapter, &msg, 1);
tuner_reg[0] = 0xc0;
- tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
+ tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
i2c_transfer(c->adapter, &msg, 1);
}
static void tda827xa_agcf(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char data[] = {0x80, 0x2c};
- struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
.flags = 0, .len = 2};
i2c_transfer(c->adapter, &msg, 1);
}
@@ -347,8 +361,9 @@ static void tda8290_i2c_bridge(struct i2c_client *c, int close)
static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char soft_reset[] = { 0x00, 0x00 };
- unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode };
+ unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode };
unsigned char expert_mode[] = { 0x01, 0x80 };
unsigned char agc_out_on[] = { 0x02, 0x00 };
unsigned char gainset_off[] = { 0x28, 0x14 };
@@ -375,18 +390,18 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
i2c_master_send(c, soft_reset, 2);
msleep(1);
- expert_mode[1] = t->tda8290_easy_mode + 0x80;
+ expert_mode[1] = priv->tda8290_easy_mode + 0x80;
i2c_master_send(c, expert_mode, 2);
i2c_master_send(c, gainset_off, 2);
i2c_master_send(c, if_agc_spd, 2);
- if (t->tda8290_easy_mode & 0x60)
+ if (priv->tda8290_easy_mode & 0x60)
i2c_master_send(c, adc_head_9, 2);
else
i2c_master_send(c, adc_head_6, 2);
i2c_master_send(c, pll_bw_nom, 2);
tda8290_i2c_bridge(c, 1);
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
tda827xa_tune(c, ifc, freq);
else
tda827x_tune(c, ifc, freq);
@@ -418,7 +433,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
if ((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
agc_stat, pll_stat & 0x80);
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
tda827xa_agcf(c);
else
tda827x_agcf(c);
@@ -437,7 +452,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
}
/* l/ l' deadlock? */
- if(t->tda8290_easy_mode & 0x60) {
+ if(priv->tda8290_easy_mode & 0x60) {
i2c_master_send(c, &addr_adc_sat, 1);
i2c_master_recv(c, &adc_sat, 1);
i2c_master_send(c, &addr_pll_stat, 1);
@@ -459,41 +474,42 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
static void set_audio(struct tuner *t)
{
+ struct tda8290_priv *priv = t->priv;
char* mode;
- t->tda827x_lpsel = 0;
+ priv->tda827x_lpsel = 0;
if (t->std & V4L2_STD_MN) {
- t->sgIF = 92;
- t->tda8290_easy_mode = 0x01;
- t->tda827x_lpsel = 1;
+ priv->sgIF = 92;
+ priv->tda8290_easy_mode = 0x01;
+ priv->tda827x_lpsel = 1;
mode = "MN";
} else if (t->std & V4L2_STD_B) {
- t->sgIF = 108;
- t->tda8290_easy_mode = 0x02;
+ priv->sgIF = 108;
+ priv->tda8290_easy_mode = 0x02;
mode = "B";
} else if (t->std & V4L2_STD_GH) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x04;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x04;
mode = "GH";
} else if (t->std & V4L2_STD_PAL_I) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x08;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x08;
mode = "I";
} else if (t->std & V4L2_STD_DK) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x10;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
mode = "DK";
} else if (t->std & V4L2_STD_SECAM_L) {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x20;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x20;
mode = "L";
} else if (t->std & V4L2_STD_SECAM_LC) {
- t->sgIF = 20;
- t->tda8290_easy_mode = 0x40;
+ priv->sgIF = 20;
+ priv->tda8290_easy_mode = 0x40;
mode = "LC";
} else {
- t->sgIF = 124;
- t->tda8290_easy_mode = 0x10;
+ priv->sgIF = 124;
+ priv->tda8290_easy_mode = 0x10;
mode = "xx";
}
tuner_dbg("setting tda8290 to system %s\n", mode);
@@ -502,9 +518,10 @@ static void set_audio(struct tuner *t)
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
set_audio(t);
- tda8290_tune(c, t->sgIF, freq);
+ tda8290_tune(c, priv->sgIF, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -528,13 +545,14 @@ static int has_signal(struct i2c_client *c)
static void standby(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char cb1[] = { 0x30, 0xD0 };
unsigned char tda8290_standby[] = { 0x00, 0x02 };
unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
tda8290_i2c_bridge(c, 1);
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
cb1[1] = 0x90;
i2c_transfer(c->adapter, &msg, 1);
tda8290_i2c_bridge(c, 0);
@@ -560,13 +578,14 @@ static void tda8290_init_if(struct i2c_client *c)
static void tda8290_init_tuner(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
+ struct tda8290_priv *priv = t->priv;
unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
- struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+ struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
.buf=tda8275_init, .len = 14};
- if (t->tda827x_ver != 0)
+ if (priv->tda827x_ver != 0)
msg.buf = tda8275a_init;
tda8290_i2c_bridge(c, 1);
@@ -576,14 +595,36 @@ static void tda8290_init_tuner(struct i2c_client *c)
/*---------------------------------------------------------------------*/
+static void tda8290_release(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ kfree(t->priv);
+ t->priv = NULL;
+}
+
+static struct tuner_operations tda8290_tuner_ops = {
+ .set_tv_freq = set_tv_freq,
+ .set_radio_freq = set_radio_freq,
+ .has_signal = has_signal,
+ .standby = standby,
+ .release = tda8290_release,
+};
+
int tda8290_init(struct i2c_client *c)
{
+ struct tda8290_priv *priv = NULL;
struct tuner *t = i2c_get_clientdata(c);
u8 data;
int i, ret, tuners_found;
u32 tuner_addrs;
struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
+ priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ t->priv = priv;
+
tda8290_i2c_bridge(c, 1);
/* probe for tuner chip */
tuners_found = 0;
@@ -618,7 +659,7 @@ int tda8290_init(struct i2c_client *c)
tuner_addrs = tuner_addrs & 0xff;
tuner_info ("setting tuner address to %x\n", tuner_addrs);
}
- t->tda827x_addr = tuner_addrs;
+ priv->tda827x_addr = tuner_addrs;
msg.addr = tuner_addrs;
tda8290_i2c_bridge(c, 1);
@@ -627,18 +668,16 @@ int tda8290_init(struct i2c_client *c)
tuner_warn ("TDA827x access failed!\n");
if ((data & 0x3c) == 0) {
strlcpy(c->name, "tda8290+75", sizeof(c->name));
- t->tda827x_ver = 0;
+ priv->tda827x_ver = 0;
} else {
strlcpy(c->name, "tda8290+75a", sizeof(c->name));
- t->tda827x_ver = 2;
+ priv->tda827x_ver = 2;
}
tuner_info("type set to %s\n", c->name);
- t->set_tv_freq = set_tv_freq;
- t->set_radio_freq = set_radio_freq;
- t->has_signal = has_signal;
- t->standby = standby;
- t->tda827x_lpsel = 0;
+ memcpy(&t->ops, &tda8290_tuner_ops, sizeof(struct tuner_operations));
+
+ priv->tda827x_lpsel = 0;
t->mode = V4L2_TUNER_ANALOG_TV;
tda8290_init_tuner(c);
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index fde576f1101c..a8f773274fe3 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -11,6 +11,7 @@
#include <media/v4l2-common.h>
#include <media/tuner.h>
+#include "tuner-driver.h"
/* Chips:
@@ -29,6 +30,9 @@
printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+struct tda9887_priv {
+ unsigned char data[4];
+};
/* ---------------------------------------------------------------------- */
@@ -508,10 +512,11 @@ static int tda9887_status(struct tuner *t)
static void tda9887_configure(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
+ struct tda9887_priv *priv = t->priv;
int rc;
- memset(t->tda9887_data,0,sizeof(t->tda9887_data));
- tda9887_set_tvnorm(t,t->tda9887_data);
+ memset(priv->data,0,sizeof(priv->data));
+ tda9887_set_tvnorm(t,priv->data);
/* A note on the port settings:
These settings tend to depend on the specifics of the board.
@@ -526,22 +531,22 @@ static void tda9887_configure(struct i2c_client *client)
the ports should be set to active (0), but, again, that may
differ depending on the precise hardware configuration.
*/
- t->tda9887_data[1] |= cOutputPort1Inactive;
- t->tda9887_data[1] |= cOutputPort2Inactive;
+ priv->data[1] |= cOutputPort1Inactive;
+ priv->data[1] |= cOutputPort2Inactive;
- tda9887_set_config(t,t->tda9887_data);
- tda9887_set_insmod(t,t->tda9887_data);
+ tda9887_set_config(t,priv->data);
+ tda9887_set_insmod(t,priv->data);
if (t->mode == T_STANDBY) {
- t->tda9887_data[1] |= cForcedMuteAudioON;
+ priv->data[1] |= cForcedMuteAudioON;
}
tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
- t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+ priv->data[1],priv->data[2],priv->data[3]);
if (tuner_debug > 1)
- dump_write_message(t, t->tda9887_data);
+ dump_write_message(t, priv->data);
- if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
+ if (4 != (rc = i2c_master_send(&t->i2c,priv->data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
if (tuner_debug > 2) {
@@ -555,7 +560,8 @@ static void tda9887_configure(struct i2c_client *client)
static void tda9887_tuner_status(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
- tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
+ struct tda9887_priv *priv = t->priv;
+ tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
}
static int tda9887_get_afc(struct i2c_client *client)
@@ -586,20 +592,39 @@ static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
tda9887_configure(client);
}
+static void tda9887_release(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ kfree(t->priv);
+ t->priv = NULL;
+}
+
+static struct tuner_operations tda9887_tuner_ops = {
+ .set_tv_freq = tda9887_set_freq,
+ .set_radio_freq = tda9887_set_freq,
+ .standby = tda9887_standby,
+ .tuner_status = tda9887_tuner_status,
+ .get_afc = tda9887_get_afc,
+ .release = tda9887_release,
+};
+
int tda9887_tuner_init(struct i2c_client *c)
{
+ struct tda9887_priv *priv = NULL;
struct tuner *t = i2c_get_clientdata(c);
+ priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+ t->priv = priv;
+
strlcpy(c->name, "tda9887", sizeof(c->name));
tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
t->i2c.driver->driver.name);
- t->set_tv_freq = tda9887_set_freq;
- t->set_radio_freq = tda9887_set_freq;
- t->standby = tda9887_standby;
- t->tuner_status = tda9887_tuner_status;
- t->get_afc = tda9887_get_afc;
+ memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
return 0;
}
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
new file mode 100644
index 000000000000..ae105c2cd0ac
--- /dev/null
+++ b/drivers/media/video/tea5761.c
@@ -0,0 +1,243 @@
+/*
+ * For Philips TEA5761 FM Chip
+ * I2C address is allways 0x20 (0x10 at 7-bit mode).
+ *
+ * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNUv2 General Public License
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include "tuner-driver.h"
+
+#define PREFIX "TEA5761 "
+
+/* from tuner-core.c */
+extern int tuner_debug;
+
+/*****************************************************************************/
+
+/***************************
+ * TEA5761HN I2C registers *
+ ***************************/
+
+/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
+
+ /* first byte for reading */
+#define TEA5761_INTREG_IFFLAG 0x10
+#define TEA5761_INTREG_LEVFLAG 0x8
+#define TEA5761_INTREG_FRRFLAG 0x2
+#define TEA5761_INTREG_BLFLAG 0x1
+
+ /* second byte for reading / byte for writing */
+#define TEA5761_INTREG_IFMSK 0x10
+#define TEA5761_INTREG_LEVMSK 0x8
+#define TEA5761_INTREG_FRMSK 0x2
+#define TEA5761_INTREG_BLMSK 0x1
+
+/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
+
+ /* First byte */
+#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */
+
+ /* Bits 0-5 for divider MSB */
+
+ /* Second byte */
+ /* Bits 0-7 for divider LSB */
+
+/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
+
+ /* first byte */
+
+#define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */
+#define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */
+#define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */
+#define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
+#define TEA5761_TNCTRL_AFM 0x04
+#define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */
+#define TEA5761_TNCTRL_SNC 0x01
+
+ /* second byte */
+
+#define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */
+#define TEA5761_TNCTRL_SSL_1 0x40
+#define TEA5761_TNCTRL_SSL_0 0x20
+#define TEA5761_TNCTRL_HLSI 0x10
+#define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */
+#define TEA5761_TNCTRL_SWP 0x04
+#define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
+#define TEA5761_TNCTRL_AHLSI 0x01
+
+/* FRQCHECK - Read: bytes 6 and 7 */
+ /* First byte */
+
+ /* Bits 0-5 for divider MSB */
+
+ /* Second byte */
+ /* Bits 0-7 for divider LSB */
+
+/* TUNCHECK - Read: bytes 8 and 9 */
+
+ /* First byte */
+#define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */
+#define TEA5761_TUNCHECK_TUNTO 0x01
+
+ /* Second byte */
+#define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */
+#define TEA5761_TUNCHECK_LD 0x08
+#define TEA5761_TUNCHECK_STEREO 0x04
+
+/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
+
+ /* All zero = no test mode */
+
+/* MANID - Read: bytes 12 and 13 */
+
+ /* First byte - should be 0x10 */
+#define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */
+#define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */
+
+ /* Second byte - Should be 0x2b */
+
+#define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */
+#define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */
+
+/* Chip ID - Read: bytes 14 and 15 */
+
+ /* First byte - should be 0x57 */
+
+ /* Second byte - should be 0x61 */
+
+/*****************************************************************************/
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ tuner_warn("This tuner doesn't support TV freq.\n");
+}
+
+#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
+static void tea5761_status_dump(unsigned char *buffer)
+{
+ unsigned int div, frq;
+
+ div = ((buffer[2] & 0x3f) << 8) | buffer[3];
+
+ frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */
+
+ printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+ frq / 1000, frq % 1000, div);
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
+ unsigned div;
+ int rc;
+
+ tuner_dbg (PREFIX "radio freq counter %d\n", frq);
+
+ if (t->mode == T_STANDBY) {
+ tuner_dbg("TEA5761 set to standby mode\n");
+ buffer[5] |= TEA5761_TNCTRL_MU;
+ } else {
+ buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+ }
+
+
+ if (t->audmode == V4L2_TUNER_MODE_MONO) {
+ tuner_dbg("TEA5761 set to mono\n");
+ buffer[5] |= TEA5761_TNCTRL_MST;
+;
+ } else {
+ tuner_dbg("TEA5761 set to stereo\n");
+ }
+
+ div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+ buffer[1] = (div >> 8) & 0x3f;
+ buffer[2] = div & 0xff;
+
+ if (tuner_debug)
+ tea5761_status_dump(buffer);
+
+ if (7 != (rc = i2c_master_send(c, buffer, 7)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+}
+
+static int tea5761_signal(struct i2c_client *c)
+{
+ unsigned char buffer[16];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ memset(buffer, 0, sizeof(buffer));
+ if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ return ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+}
+
+static int tea5761_stereo(struct i2c_client *c)
+{
+ unsigned char buffer[16];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ memset(buffer, 0, sizeof(buffer));
+ if (16 != (rc = i2c_master_recv(c, buffer, 16)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ rc = buffer[9] & TEA5761_TUNCHECK_STEREO;
+
+ tuner_dbg("TEA5761 radio ST GET = %02x\n", rc);
+
+ return (rc ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+int tea5761_autodetection(struct i2c_client *c)
+{
+ unsigned char buffer[16];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ if (16 != (rc = i2c_master_recv(c, buffer, 16))) {
+ tuner_warn("it is not a TEA5761. Received %i chars.\n", rc);
+ return EINVAL;
+ }
+
+ if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
+ tuner_warn("Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
+ return EINVAL;
+ }
+ tuner_warn("TEA5761 detected.\n");
+ return 0;
+}
+
+static struct tuner_operations tea5761_tuner_ops = {
+ .set_tv_freq = set_tv_freq,
+ .set_radio_freq = set_radio_freq,
+ .has_signal = tea5761_signal,
+ .is_stereo = tea5761_stereo,
+};
+
+int tea5761_tuner_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ if (tea5761_autodetection(c) == EINVAL)
+ return EINVAL;
+
+ tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5761HN FM Radio");
+ strlcpy(c->name, "tea5761", sizeof(c->name));
+
+ memcpy(&t->ops, &tea5761_tuner_ops, sizeof(struct tuner_operations));
+
+ return (0);
+}
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index d1c41781ccc4..4985d47a508f 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -13,7 +13,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <linux/delay.h>
-#include <media/tuner.h>
+#include "tuner-driver.h"
#define PREFIX "TEA5767 "
@@ -343,6 +343,14 @@ int tea5767_autodetection(struct i2c_client *c)
return 0;
}
+static struct tuner_operations tea5767_tuner_ops = {
+ .set_tv_freq = set_tv_freq,
+ .set_radio_freq = set_radio_freq,
+ .has_signal = tea5767_signal,
+ .is_stereo = tea5767_stereo,
+ .standby = tea5767_standby,
+};
+
int tea5767_tuner_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
@@ -350,11 +358,7 @@ int tea5767_tuner_init(struct i2c_client *c)
tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
strlcpy(c->name, "tea5767", sizeof(c->name));
- t->set_tv_freq = set_tv_freq;
- t->set_radio_freq = set_radio_freq;
- t->has_signal = tea5767_signal;
- t->is_stereo = tea5767_stereo;
- t->standby = tea5767_standby;
+ memcpy(&t->ops, &tea5767_tuner_ops, sizeof(struct tuner_operations));
return (0);
}
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 505591a7abe9..e646465464a1 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -20,11 +20,15 @@
#include <media/tuner.h>
#include <media/v4l2-common.h>
+#include "tuner-driver.h"
#define UNSET (-1U)
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
+#ifdef CONFIG_TUNER_TEA5761
+ 0x10,
+#endif
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
@@ -77,7 +81,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n");
return;
}
- if (NULL == t->set_tv_freq) {
+ if (NULL == t->ops.set_tv_freq) {
tuner_warn ("Tuner has no way to set tv freq\n");
return;
}
@@ -92,7 +96,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
else
freq = tv_range[1] * 16;
}
- t->set_tv_freq(c, freq);
+ t->ops.set_tv_freq(c, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -103,7 +107,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
tuner_warn ("tuner type not set\n");
return;
}
- if (NULL == t->set_radio_freq) {
+ if (NULL == t->ops.set_radio_freq) {
tuner_warn ("tuner has no way to set radio frequency\n");
return;
}
@@ -119,7 +123,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
freq = radio_range[1] * 16000;
}
- t->set_radio_freq(c, freq);
+ t->ops.set_radio_freq(c, freq);
}
static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -174,6 +178,14 @@ static void set_type(struct i2c_client *c, unsigned int type,
return;
}
+ /* discard private data, in case set_type() was previously called */
+ if (t->ops.release)
+ t->ops.release(c);
+ else {
+ kfree(t->priv);
+ t->priv = NULL;
+ }
+
switch (t->type) {
case TUNER_MT2032:
microtune_init(c);
@@ -189,6 +201,16 @@ static void set_type(struct i2c_client *c, unsigned int type,
}
t->mode_mask = T_RADIO;
break;
+#ifdef CONFIG_TUNER_TEA5761
+ case TUNER_TEA5761:
+ if (tea5761_tuner_init(c) == EINVAL) {
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+ return;
+ }
+ t->mode_mask = T_RADIO;
+ break;
+#endif
case TUNER_PHILIPS_FMD1216ME_MK3:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
@@ -408,11 +430,11 @@ static void tuner_status(struct i2c_client *client)
tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std);
if (t->mode != V4L2_TUNER_RADIO)
return;
- if (t->has_signal) {
- tuner_info("Signal strength: %d\n", t->has_signal(client));
+ if (t->ops.has_signal) {
+ tuner_info("Signal strength: %d\n", t->ops.has_signal(client));
}
- if (t->is_stereo) {
- tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no");
+ if (t->ops.is_stereo) {
+ tuner_info("Stereo: %s\n", t->ops.is_stereo(client) ? "yes" : "no");
}
}
@@ -437,10 +459,9 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
i2c_set_clientdata(&t->i2c, t);
t->type = UNSET;
- t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
- t->tuner_status = tuner_status;
+ t->ops.tuner_status = tuner_status;
if (show_i2c) {
unsigned char buffer[16];
@@ -460,6 +481,19 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
/* autodetection code based on the i2c addr */
if (!no_autodetect) {
switch (addr) {
+#ifdef CONFIG_TUNER_TEA5761
+ case 0x10:
+ if (tea5761_autodetection(&t->i2c) != EINVAL) {
+ t->type = TUNER_TEA5761;
+ t->mode_mask = T_RADIO;
+ t->mode = T_STANDBY;
+ t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+ default_mode_mask &= ~T_RADIO;
+
+ goto register_client;
+ }
+ break;
+#endif
case 0x42:
case 0x43:
case 0x4a:
@@ -533,6 +567,11 @@ static int tuner_detach(struct i2c_client *client)
return err;
}
+ if (t->ops.release)
+ t->ops.release(client);
+ else {
+ kfree(t->priv);
+ }
kfree(t);
return 0;
}
@@ -553,8 +592,8 @@ static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode,
if (check_mode(t, cmd) == EINVAL) {
t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
+ if (t->ops.standby)
+ t->ops.standby (client);
return EINVAL;
}
return 0;
@@ -602,8 +641,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
t->mode = T_STANDBY;
- if (t->standby)
- t->standby (client);
+ if (t->ops.standby)
+ t->ops.standby (client);
break;
#ifdef CONFIG_VIDEO_V4L1
case VIDIOCSAUDIO:
@@ -662,10 +701,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
if (V4L2_TUNER_RADIO == t->mode) {
- if (t->has_signal)
- vt->signal = t->has_signal(client);
- if (t->is_stereo) {
- if (t->is_stereo(client))
+ if (t->ops.has_signal)
+ vt->signal = t->ops.has_signal(client);
+ if (t->ops.is_stereo) {
+ if (t->ops.is_stereo(client))
vt->flags |=
VIDEO_TUNER_STEREO_ON;
else
@@ -693,8 +732,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (check_v4l2(t) == EINVAL)
return 0;
- if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
- va->mode = t->is_stereo(client)
+ if (V4L2_TUNER_RADIO == t->mode && t->ops.is_stereo)
+ va->mode = t->ops.is_stereo(client)
? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
return 0;
}
@@ -759,8 +798,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2();
tuner->type = t->mode;
- if (t->get_afc)
- tuner->afc=t->get_afc(client);
+ if (t->ops.get_afc)
+ tuner->afc=t->ops.get_afc(client);
if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) {
@@ -770,13 +809,13 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
/* radio mode */
- if (t->has_signal)
- tuner->signal = t->has_signal(client);
+ if (t->ops.has_signal)
+ tuner->signal = t->ops.has_signal(client);
tuner->rxsubchans =
V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- if (t->is_stereo) {
- tuner->rxsubchans = t->is_stereo(client) ?
+ if (t->ops.is_stereo) {
+ tuner->rxsubchans = t->ops.is_stereo(client) ?
V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
}
@@ -804,8 +843,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
case VIDIOC_LOG_STATUS:
- if (t->tuner_status)
- t->tuner_status(client);
+ if (t->ops.tuner_status)
+ t->ops.tuner_status(client);
break;
}
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
new file mode 100644
index 000000000000..0334a9125077
--- /dev/null
+++ b/drivers/media/video/tuner-driver.h
@@ -0,0 +1,107 @@
+/*
+ tuner-driver.h - interface for different tuners
+
+ Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
+ minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+ 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 __TUNER_HW_H__
+#define __TUNER_HW_H__
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+extern unsigned const int tuner_count;
+
+struct tuner_operations {
+ void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
+ void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
+ int (*has_signal)(struct i2c_client *c);
+ int (*is_stereo)(struct i2c_client *c);
+ int (*get_afc)(struct i2c_client *c);
+ void (*tuner_status)(struct i2c_client *c);
+ void (*standby)(struct i2c_client *c);
+ void (*release)(struct i2c_client *c);
+};
+
+struct tuner {
+ /* device */
+ struct i2c_client i2c;
+
+ unsigned int type; /* chip type */
+
+ unsigned int mode;
+ unsigned int mode_mask; /* Combination of allowable modes */
+
+ unsigned int tv_freq; /* keep track of the current settings */
+ unsigned int radio_freq;
+ u16 last_div;
+ unsigned int audmode;
+ v4l2_std_id std;
+
+ int using_v4l2;
+ void *priv;
+
+ /* used by tda9887 */
+ unsigned int tda9887_config;
+
+ unsigned int config;
+ int (*tuner_callback) (void *dev, int command,int arg);
+
+ struct tuner_operations ops;
+};
+
+/* ------------------------------------------------------------------------ */
+
+extern int default_tuner_init(struct i2c_client *c);
+
+extern int tda9887_tuner_init(struct i2c_client *c);
+
+extern int microtune_init(struct i2c_client *c);
+
+extern int tda8290_init(struct i2c_client *c);
+extern int tda8290_probe(struct i2c_client *c);
+
+extern int tea5761_tuner_init(struct i2c_client *c);
+extern int tea5761_autodetection(struct i2c_client *c);
+
+extern int tea5767_autodetection(struct i2c_client *c);
+extern int tea5767_tuner_init(struct i2c_client *c);
+
+/* ------------------------------------------------------------------------ */
+
+#define tuner_warn(fmt, arg...) do {\
+ printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+ extern int tuner_debug; \
+ if (tuner_debug) \
+ printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+
+#endif /* __TUNER_HW_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index c40b92ce1fad..2d57e8bc0db3 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -8,6 +8,8 @@
#include <linux/videodev.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
+#include <media/tuner-types.h>
+#include "tuner-driver.h"
static int offset = 0;
module_param(offset, int, 0664);
@@ -54,9 +56,9 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
sound 2 33.16 - -
NICAM 33.05 33.05 39.80
*/
-#define PHILIPS_MF_SET_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_PAL_L 0x03 // France
-#define PHILIPS_MF_SET_PAL_L2 0x02 // L'
+#define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */
+#define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */
/* Control byte */
@@ -207,11 +209,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
/* 0x04 -> ??? PAL others / SECAM others ??? */
cb &= ~0x03;
if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
- cb |= PHILIPS_MF_SET_PAL_L;
+ cb |= PHILIPS_MF_SET_STD_L;
else if (t->std & V4L2_STD_SECAM_LC)
- cb |= PHILIPS_MF_SET_PAL_L2;
+ cb |= PHILIPS_MF_SET_STD_LC;
else /* V4L2_STD_B|V4L2_STD_GH */
- cb |= PHILIPS_MF_SET_BG;
+ cb |= PHILIPS_MF_SET_STD_BG;
break;
case TUNER_TEMIC_4046FM5:
@@ -479,6 +481,13 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
}
+static struct tuner_operations simple_tuner_ops = {
+ .set_tv_freq = default_set_tv_freq,
+ .set_radio_freq = default_set_radio_freq,
+ .has_signal = tuner_signal,
+ .is_stereo = tuner_stereo,
+};
+
int default_tuner_init(struct i2c_client *c)
{
struct tuner *t = i2c_get_clientdata(c);
@@ -487,11 +496,7 @@ int default_tuner_init(struct i2c_client *c)
t->type, tuners[t->type].name);
strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
- t->set_tv_freq = default_set_tv_freq;
- t->set_radio_freq = default_set_radio_freq;
- t->has_signal = tuner_signal;
- t->is_stereo = tuner_stereo;
- t->standby = NULL;
+ memcpy(&t->ops, &simple_tuner_ops, sizeof(struct tuner_operations));
return 0;
}
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 74c3e6f96f1a..417f642b4359 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -594,19 +594,19 @@ static struct tuner_params tuner_philips_pal_mk_params[] = {
},
};
-/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
+/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
-static struct tuner_range tuner_philips_atsc_ranges[] = {
+static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+ { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
{ 16 * 999.99 , 0x8e, 0x30, },
};
-static struct tuner_params tuner_philips_atsc_params[] = {
+static struct tuner_params tuner_philips_fcv1236d_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_atsc_ranges,
- .count = ARRAY_SIZE(tuner_philips_atsc_ranges),
+ .ranges = tuner_philips_fcv1236d_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
},
};
@@ -1296,9 +1296,9 @@ struct tunertype tuners[] = {
.count = ARRAY_SIZE(tuner_philips_pal_mk_params),
},
[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
- .name = "Philips 1236D ATSC/NTSC dual in",
- .params = tuner_philips_atsc_params,
- .count = ARRAY_SIZE(tuner_philips_atsc_params),
+ .name = "Philips FCV1236D ATSC/NTSC dual in",
+ .params = tuner_philips_fcv1236d_params,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_params),
},
[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
.name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1463,6 +1463,10 @@ struct tunertype tuners[] = {
.name = "Philips TDA988[5,6,7] IF PLL Demodulator",
/* see tda9887.c for details */
},
+ [TUNER_TEA5761] = { /* Philips RADIO */
+ .name = "Philips TEA5761 FM Radio",
+ /* see tea5767.c for details */
+ },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index c9bf9dbc2ea3..cffb011590e3 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -271,7 +271,7 @@ static int chip_thread(void *data)
struct CHIPDESC *desc = chiplist + chip->type;
v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
-
+ set_freezable();
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (!kthread_should_stop())
@@ -290,7 +290,7 @@ static int chip_thread(void *data)
desc->checkmode(chip);
/* schedule next check */
- mod_timer(&chip->wt, jiffies+2*HZ);
+ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
}
v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
@@ -1770,7 +1770,7 @@ static int chip_command(struct i2c_client *client,
desc->setmode(chip,VIDEO_SOUND_MONO);
if (chip->prevmode != VIDEO_SOUND_MONO)
chip->prevmode = -1; /* reset previous mode */
- mod_timer(&chip->wt, jiffies+2*HZ);
+ mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
/* the thread will call checkmode() later */
}
break;
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index a1136da74ba8..fdc3def437b1 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -183,7 +183,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Silicon TDA8275C1 8290 FM"},
{ TUNER_ABSENT, "Thompson DTT757"},
/* 80-89 */
- { TUNER_ABSENT, "Philips FQ1216LME MK3"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
@@ -490,7 +490,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+2] & 0x7f;
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tvee->audio_processor = audioIC[audioic].id;
else
tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -523,7 +523,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
to indicate 4052 mux was removed in favor of using MSP
inputs directly. */
audioic = eeprom_data[i+1] & 0x7f;
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tvee->audio_processor = audioIC[audioic].id;
else
tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -678,7 +678,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tveeprom_info("audio processor is unknown (no idx)\n");
tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
} else {
- if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+ if (audioic < ARRAY_SIZE(audioIC))
tveeprom_info("audio processor is %s (idx %d)\n",
audioIC[audioic].name,audioic);
else
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index d5ec05f56adf..e2f1c972754b 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -1006,7 +1006,7 @@ static int tvp5150_command(struct i2c_client *c,
{
struct v4l2_control *ctrl = arg;
u8 i, n;
- n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+ n = ARRAY_SIZE(tvp5150_qctrl);
for (i = 0; i < n; i++)
if (ctrl->id == tvp5150_qctrl[i].id) {
if (ctrl->value <
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index abe214619092..491505d6fdee 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -236,7 +236,7 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
input_dev->name = "Konicawc snapshot button";
input_dev->phys = cam->input_physname;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_KEY);
input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index ec0ff2247f06..dd1a6d6bbc9e 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -100,7 +100,7 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
input_dev->name = "QCM button";
input_dev->phys = cam->input_physname;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &dev->dev;
+ input_dev->dev.parent = &dev->dev;
input_dev->evbit[0] = BIT(EV_KEY);
input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
@@ -439,7 +439,7 @@ static int qcm_sensor_init(struct uvd *uvd)
int ret;
int i;
- for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+ for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
CHECK_RET(ret, qcm_stv_setb(uvd->dev,
regval_table[i].reg,
regval_table[i].val));
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 982b115193f8..ff555129c82f 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -42,7 +42,6 @@
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
-#include <linux/proc_fs.h>
#include <linux/mutex.h>
#include "usbvideo.h"
@@ -417,11 +416,6 @@ struct vicam_camera {
u8 open_count;
u8 bulkEndpoint;
int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
- struct proc_dir_entry *proc_dir;
-#endif
-
};
static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
@@ -1065,175 +1059,6 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
- int count, int *eof, int value)
-{
- char *out = page;
- int len;
-
- out += sprintf(out, "%d",value);
-
- len = out - page;
- len -= off;
- if (len < count) {
- *eof = 1;
- if (len <= 0)
- return 0;
- } else
- len = count;
-
- *start = page + off;
- return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return vicam_read_helper(page,start,off,count,eof,
- ((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- return vicam_read_helper(page,start,off,count,eof,
- ((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- u16 stmp;
- char kbuf[8];
- struct vicam_camera *cam = (struct vicam_camera *) data;
-
- if (count > 6)
- return -EINVAL;
-
- if (copy_from_user(kbuf, buffer, count))
- return -EFAULT;
-
- stmp = (u16) simple_strtoul(kbuf, NULL, 10);
- if (stmp < 4 || stmp > 32000)
- return -EINVAL;
-
- cam->shutter_speed = stmp;
-
- return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
- unsigned long count, void *data)
-{
- u16 gtmp;
- char kbuf[8];
-
- struct vicam_camera *cam = (struct vicam_camera *) data;
-
- if (count > 4)
- return -EINVAL;
-
- if (copy_from_user(kbuf, buffer, count))
- return -EFAULT;
-
- gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
- if (gtmp > 255)
- return -EINVAL;
- cam->gain = gtmp;
-
- return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
- vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
- if (vicam_proc_root)
- vicam_proc_root->owner = THIS_MODULE;
- else
- printk(KERN_ERR
- "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
- if (vicam_proc_root)
- remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
- char name[64];
- struct proc_dir_entry *ent;
-
- DBG(KERN_INFO "vicam: creating proc entry\n");
-
- if (!vicam_proc_root || !cam) {
- printk(KERN_INFO
- "vicam: could not create proc entry, %s pointer is null.\n",
- (!cam ? "camera" : "root"));
- return;
- }
-
- sprintf(name, "video%d", cam->vdev.minor);
-
- cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
- if ( !cam->proc_dir )
- return; // FIXME: We should probably return an error here
-
- ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
- cam->proc_dir);
- if (ent) {
- ent->data = cam;
- ent->read_proc = vicam_read_proc_shutter;
- ent->write_proc = vicam_write_proc_shutter;
- ent->size = 64;
- }
-
- ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
- cam->proc_dir);
- if (ent) {
- ent->data = cam;
- ent->read_proc = vicam_read_proc_gain;
- ent->write_proc = vicam_write_proc_gain;
- ent->size = 64;
- }
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
- struct vicam_camera *cam = (struct vicam_camera *) ptr;
- char name[16];
-
- if ( !cam->proc_dir )
- return;
-
- sprintf(name, "video%d", cam->vdev.minor);
- remove_proc_entry("shutter", cam->proc_dir);
- remove_proc_entry("gain", cam->proc_dir);
- remove_proc_entry(name,vicam_proc_root);
- cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
static const struct file_operations vicam_fops = {
.owner = THIS_MODULE,
.open = vicam_open,
@@ -1305,13 +1130,12 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
}
if ((cam =
- kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+ kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING
"could not allocate kernel memory for vicam_camera struct\n");
return -ENOMEM;
}
- memset(cam, 0, sizeof (struct vicam_camera));
cam->shutter_speed = 15;
@@ -1330,8 +1154,6 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
return -EIO;
}
- vicam_create_proc_entry(cam);
-
printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
usb_set_intfdata (intf, cam);
@@ -1363,8 +1185,6 @@ vicam_disconnect(struct usb_interface *intf)
cam->udev = NULL;
- vicam_destroy_proc_entry(cam);
-
/* the only thing left to do is synchronize with
* our close/release function on who should release
* the camera memory. if there are any users using the
@@ -1390,7 +1210,6 @@ usb_vicam_init(void)
{
int retval;
DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
- vicam_create_proc_root();
retval = usb_register(&vicam_driver);
if (retval)
printk(KERN_WARNING "usb_register failed!\n");
@@ -1404,7 +1223,6 @@ usb_vicam_exit(void)
"ViCam-based WebCam driver shutdown\n");
usb_deregister(&vicam_driver);
- vicam_destroy_proc_root();
}
module_init(usb_vicam_init);
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 51ab265d566a..380564cd3317 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -79,7 +79,7 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.Interface = -1,
.Codec = CODEC_SAA7113,
.VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
+ .VideoNorm = V4L2_STD_NTSC,
.AudioChannels = 1,
.Radio = 0,
.vbi = 1,
@@ -311,8 +311,8 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.vbi = 1,
.Tuner = 1,
.TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = -1,
- .Y_Offset = -1,
+ .X_Offset = 0x80,
+ .Y_Offset = 0x16,
.ModelString = "Hauppauge WinTV USB (PAL/SECAM L)",
},
[HPG_WINTV_PAL_D_K] = {
@@ -586,7 +586,7 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.Radio = 0,
.vbi = 1,
.Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
+ .TunerType = TUNER_LG_PAL_NEW_TAPC,
.X_Offset = 0,
.Y_Offset = 3,
.Dvi_yuv_override = 1,
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 7df071eb0a3b..5b1e346df206 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -1742,7 +1742,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
format = ISOC_MODE_YUV420;
}
value[0] = 0x0A; //TODO: See the effect of the filter
- value[1] = format;
+ value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR |
@@ -1831,10 +1831,10 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
frameRate = FRAMERATE_MAX;
}
- if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+ if (usbvision->tvnormId & V4L2_STD_625_50) {
frameDrop = frameRate * 32 / 25 - 1;
}
- else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+ else if (usbvision->tvnormId & V4L2_STD_525_60) {
frameDrop = frameRate * 32 / 30 - 1;
}
@@ -2067,7 +2067,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
}
- if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+ if (usbvision->tvnormId & V4L2_STD_PAL) {
value[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20;
@@ -2076,7 +2076,7 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
value[5] = 0x00; //0x0060 -> 96 Input video h offset
value[6] = 0x16;
value[7] = 0x00; //0x0016 -> 22 Input video v offset
- } else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+ } else if (usbvision->tvnormId & V4L2_STD_SECAM) {
value[0] = 0xC0;
value[1] = 0x02; //0x02C0 -> 704 Input video line length
value[2] = 0x20;
@@ -2537,7 +2537,9 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
{
- int mode[4];
+ /* inputs #0 and #3 are constant for every SAA711x. */
+ /* inputs #1 and #2 are variable for SAA7111 and SAA7113 */
+ int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3};
int audio[]= {1, 0, 0, 0};
struct v4l2_routing route;
//channel 0 is TV with audiochannel 1 (tuner mono)
@@ -2547,10 +2549,6 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
usbvision->ctl_input = channel;
- route.input = SAA7115_COMPOSITE1;
- route.output = 0;
- call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
- call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
// set the new channel
// Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
@@ -2558,28 +2556,27 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
switch (usbvision_device_data[usbvision->DevModel].Codec) {
case CODEC_SAA7113:
- if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices. Use SwitchSVideoInput parameter when loading the module.
- mode[2] = 1;
+ mode[1] = SAA7115_COMPOSITE2;
+ if (SwitchSVideoInput) {
+ /* To handle problems with S-Video Input for
+ * some devices. Use SwitchSVideoInput
+ * parameter when loading the module.*/
+ mode[2] = SAA7115_COMPOSITE1;
}
else {
- mode[2] = 7;
- }
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- mode[0] = 0; mode[1] = 2; mode[3] = 3; // Special for four input devices
- }
- else {
- mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+ mode[2] = SAA7115_SVIDEO1;
}
break;
case CODEC_SAA7111:
- mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
- break;
default:
- mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+ /* modes for saa7111 */
+ mode[1] = SAA7115_COMPOSITE1;
+ mode[2] = SAA7115_SVIDEO1;
+ break;
}
route.input = mode[channel];
+ route.output = 0;
call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
- usbvision->channel = channel;
usbvision_set_audio(usbvision, audio[channel]);
return 0;
}
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index aa3258bbb4af..868b6886fe7f 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -36,7 +36,8 @@
* - use submit_urb for all setup packets
* - Fix memory settings for nt1004. It is 4 times as big as the
* nt1003 memory.
- * - Add audio on endpoint 3 for nt1004 chip. Seems impossible, needs a codec interface. Which one?
+ * - Add audio on endpoint 3 for nt1004 chip.
+ * Seems impossible, needs a codec interface. Which one?
* - Clean up the driver.
* - optimization for performance.
* - Add Videotext capability (VBI). Working on it.....
@@ -77,7 +78,8 @@
#include "usbvision.h"
#include "usbvision-cards.h"
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\
+ Dwaine Garden <DwaineGarden@rogers.com>"
#define DRIVER_NAME "usbvision"
#define DRIVER_ALIAS "USBVision"
#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
@@ -85,20 +87,25 @@
#define USBVISION_DRIVER_VERSION_MAJOR 0
#define USBVISION_DRIVER_VERSION_MINOR 9
#define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
+USBVISION_DRIVER_VERSION_MINOR,\
+USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
#ifdef USBVISION_DEBUG
#define PDEBUG(level, fmt, args...) \
- if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+ if (video_debug & (level)) \
+ info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
+ ## args)
#else
#define PDEBUG(level, fmt, args...) do {} while(0)
#endif
-#define DBG_IOCTL 1<<0
#define DBG_IO 1<<1
#define DBG_PROBE 1<<2
#define DBG_MMAP 1<<3
@@ -108,7 +115,8 @@
#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
-static int usbvision_nr = 0; // sequential number of usbvision device
+/* sequential number of usbvision device */
+static int usbvision_nr = 0;
static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" },
@@ -121,55 +129,32 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
};
-/* supported tv norms */
-static struct usbvision_tvnorm tvnorms[] = {
- {
- .name = "PAL",
- .id = V4L2_STD_PAL,
- }, {
- .name = "NTSC",
- .id = V4L2_STD_NTSC,
- }, {
- .name = "SECAM",
- .id = V4L2_STD_SECAM,
- }, {
- .name = "PAL-M",
- .id = V4L2_STD_PAL_M,
- }
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
-// Function prototypes
+/* Function prototypes */
static void usbvision_release(struct usb_usbvision *usbvision);
-// Default initalization of device driver parameters
-static int isocMode = ISOC_MODE_COMPRESS; // Set the default format for ISOC endpoint
-static int video_debug = 0; // Set the default Debug Mode of the device driver
-static int PowerOnAtOpen = 1; // Set the default device to power on at startup
-static int video_nr = -1; // Sequential Number of Video Device
-static int radio_nr = -1; // Sequential Number of Radio Device
-static int vbi_nr = -1; // Sequential Number of VBI Device
-
-// Grab parameters for the device driver
-
-#if defined(module_param) // Showing parameters under SYSFS
+/* Default initalization of device driver parameters */
+/* Set the default format for ISOC endpoint */
+static int isocMode = ISOC_MODE_COMPRESS;
+/* Set the default Debug Mode of the device driver */
+static int video_debug = 0;
+/* Set the default device to power on at startup */
+static int PowerOnAtOpen = 1;
+/* Sequential Number of Video Device */
+static int video_nr = -1;
+/* Sequential Number of Radio Device */
+static int radio_nr = -1;
+/* Sequential Number of VBI Device */
+static int vbi_nr = -1;
+
+/* Grab parameters for the device driver */
+
+/* Showing parameters under SYSFS */
module_param(isocMode, int, 0444);
module_param(video_debug, int, 0444);
module_param(PowerOnAtOpen, int, 0444);
module_param(video_nr, int, 0444);
module_param(radio_nr, int, 0444);
module_param(vbi_nr, int, 0444);
-#else // Old Style
-MODULE_PARAM(isocMode, "i");
-MODULE_PARM(video_debug, "i"); // Grab the Debug Mode of the device driver
-MODULE_PARM(adjustCompression, "i"); // Grab the compression to be adaptive
-MODULE_PARM(PowerOnAtOpen, "i"); // Grab the device to power on at startup
-MODULE_PARM(SwitchSVideoInput, "i"); // To help people with Black and White output with using s-video input. Some cables and input device are wired differently.
-MODULE_PARM(video_nr, "i"); // video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
-MODULE_PARM(radio_nr, "i"); // radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
-MODULE_PARM(vbi_nr, "i"); // vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
-#endif
MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");
@@ -187,19 +172,21 @@ MODULE_VERSION(USBVISION_VERSION_STRING);
MODULE_ALIAS(DRIVER_ALIAS);
-/****************************************************************************************/
-/* SYSFS Code - Copied from the stv680.c usb module. */
-/* Device information is located at /sys/class/video4linux/video0 */
-/* Device parameters information is located at /sys/module/usbvision */
-/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber */
-/****************************************************************************************/
+/*****************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module. */
+/* Device information is located at /sys/class/video4linux/video0 */
+/* Device parameters information is located at /sys/module/usbvision */
+/* Device USB Information is located at */
+/* /sys/bus/usb/drivers/USBVision Video Grabber */
+/*****************************************************************************/
#define YES_NO(x) ((x) ? "Yes" : "No")
static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
return video_get_drvdata(vdev);
}
@@ -211,15 +198,18 @@ static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t show_model(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+ return sprintf(buf, "%s\n",
+ usbvision_device_data[usbvision->DevModel].ModelString);
}
static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
static ssize_t show_hue(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_HUE;
@@ -232,7 +222,8 @@ static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
static ssize_t show_contrast(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_CONTRAST;
@@ -245,7 +236,8 @@ static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
static ssize_t show_brightness(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_BRIGHTNESS;
@@ -258,7 +250,8 @@ static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
static ssize_t show_saturation(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_SATURATION;
@@ -271,23 +264,28 @@ static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
static ssize_t show_streaming(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->streaming==Stream_On?1:0));
}
static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
static ssize_t show_compression(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+ return sprintf(buf, "%s\n",
+ YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
}
static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
static ssize_t show_device_bridge(struct class_device *cd, char *buf)
{
- struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+ struct video_device *vdev =
+ container_of(cd, struct video_device, class_dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%d\n", usbvision->bridgeType);
}
@@ -376,7 +374,8 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
static int usbvision_v4l2_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "open");
@@ -390,7 +389,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
/* Allocate memory for the scratch ring buffer */
errCode = usbvision_scratch_alloc(usbvision);
if (isocMode==ISOC_MODE_COMPRESS) {
- /* Allocate intermediate decompression buffers only if needed */
+ /* Allocate intermediate decompression buffers
+ only if needed */
errCode = usbvision_decompress_alloc(usbvision);
}
if (errCode) {
@@ -421,11 +421,10 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
if (!errCode) {
usbvision_begin_streaming(usbvision);
errCode = usbvision_init_isoc(usbvision);
- /* device needs to be initialized before isoc transfer */
+ /* device must be initialized before isoc transfer */
usbvision_muxsel(usbvision,0);
usbvision->user++;
- }
- else {
+ } else {
if (PowerOnAtOpen) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
@@ -456,7 +455,8 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file)
static int usbvision_v4l2_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
PDEBUG(DBG_IO, "close");
down(&usbvision->lock);
@@ -473,7 +473,8 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
usbvision->user--;
if (PowerOnAtOpen) {
- /* power off in a little while to avoid off/on every close/open short sequences */
+ /* power off in a little while
+ to avoid off/on every close/open short sequences */
usbvision_set_powerOffTimer(usbvision);
usbvision->initialized = 0;
}
@@ -498,583 +499,612 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
* This is part of Video 4 Linux API. The procedure handles ioctl() calls.
*
*/
-static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision))
- return -EFAULT;
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode;
- switch (cmd) {
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (errCode < 0) {
+ err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
+ __FUNCTION__, errCode);
+ return errCode;
+ }
+ return 0;
+}
-#ifdef CONFIG_VIDEO_ADV_DEBUG
- /* ioctls to allow direct acces to the NT100x registers */
- case VIDIOC_DBG_G_REGISTER:
- case VIDIOC_DBG_S_REGISTER:
- {
- struct v4l2_register *reg = arg;
- int errCode;
-
- if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
- return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- /* NT100x has a 8-bit register space */
- if (cmd == VIDIOC_DBG_G_REGISTER)
- errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
- else
- errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
- if (errCode < 0) {
- err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
- cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
- return errCode;
- }
- if (cmd == VIDIOC_DBG_S_REGISTER)
- reg->val = (u8)errCode;
+static int vidioc_s_register (struct file *file, void *priv,
+ struct v4l2_register *reg)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int errCode;
- PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
- cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
- (unsigned int)reg->reg, (unsigned int)reg->val);
- return 0;
- }
+ if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return -EINVAL;
+ /* NT100x has a 8-bit register space */
+ reg->val = (u8)usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+ if (reg->val < 0) {
+ err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
+ __FUNCTION__, errCode);
+ return errCode;
+ }
+ return 0;
+}
#endif
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *vc=arg;
-
- memset(vc, 0, sizeof(*vc));
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
- sizeof(vc->card));
- strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
- sizeof(vc->bus_info));
- vc->version = USBVISION_DRIVER_VERSION;
- vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_AUDIO |
- V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING |
- (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
- PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
- return 0;
- }
- case VIDIOC_ENUMINPUT:
- {
- struct v4l2_input *vi = arg;
- int chan;
-
- if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
- return -EINVAL;
- if (usbvision->have_tuner) {
- chan = vi->index;
- }
- else {
- chan = vi->index + 1; //skip Television string
- }
- switch(chan) {
- case 0:
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "White Video Input");
- }
- else {
- strcpy(vi->name, "Television");
- vi->type = V4L2_INPUT_TYPE_TUNER;
- vi->audioset = 1;
- vi->tuner = chan;
- vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
- }
- break;
- case 1:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "Green Video Input");
- }
- else {
- strcpy(vi->name, "Composite Video Input");
- }
- vi->std = V4L2_STD_PAL;
- break;
- case 2:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
- strcpy(vi->name, "Yellow Video Input");
- }
- else {
- strcpy(vi->name, "S-Video Input");
- }
- vi->std = V4L2_STD_PAL;
- break;
- case 3:
- vi->type = V4L2_INPUT_TYPE_CAMERA;
- strcpy(vi->name, "Red Video Input");
- vi->std = V4L2_STD_PAL;
- break;
- }
- PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
- vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
- return 0;
- }
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
- unsigned int i;
- int ret;
-
- i = e->index;
- if (i >= TVNORMS)
- return -EINVAL;
- ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
- tvnorms[e->index].name);
- e->index = i;
- if (ret < 0)
- return ret;
- return 0;
+
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *vc)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+
+ strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+ strlcpy(vc->card,
+ usbvision_device_data[usbvision->DevModel].ModelString,
+ sizeof(vc->card));
+ strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+ sizeof(vc->bus_info));
+ vc->version = USBVISION_DRIVER_VERSION;
+ vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+ return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *vi)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int chan;
+
+ if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+ return -EINVAL;
+ if (usbvision->have_tuner) {
+ chan = vi->index;
+ } else {
+ chan = vi->index + 1; /*skip Television string*/
+ }
+ /* Determine the requested input characteristics
+ specific for each usbvision card model */
+ switch(chan) {
+ case 0:
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "White Video Input");
+ } else {
+ strcpy(vi->name, "Television");
+ vi->type = V4L2_INPUT_TYPE_TUNER;
+ vi->audioset = 1;
+ vi->tuner = chan;
+ vi->std = USBVISION_NORMS;
}
- case VIDIOC_G_INPUT:
- {
- int *input = arg;
- *input = usbvision->ctl_input;
- return 0;
+ break;
+ case 1:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Green Video Input");
+ } else {
+ strcpy(vi->name, "Composite Video Input");
}
- case VIDIOC_S_INPUT:
- {
- int *input = arg;
- if ((*input >= usbvision->video_inputs) || (*input < 0) )
- return -EINVAL;
- usbvision->ctl_input = *input;
-
- down(&usbvision->lock);
- usbvision_muxsel(usbvision, usbvision->ctl_input);
- usbvision_set_input(usbvision);
- usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
- up(&usbvision->lock);
- return 0;
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 2:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ strcpy(vi->name, "Yellow Video Input");
+ } else {
+ strcpy(vi->name, "S-Video Input");
}
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+ vi->std = V4L2_STD_PAL;
+ break;
+ case 3:
+ vi->type = V4L2_INPUT_TYPE_CAMERA;
+ strcpy(vi->name, "Red Video Input");
+ vi->std = V4L2_STD_PAL;
+ break;
+ }
+ return 0;
+}
- *id = usbvision->tvnorm->id;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
- return 0;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
- unsigned int i;
-
- for (i = 0; i < TVNORMS; i++)
- if (*id == tvnorms[i].id)
- break;
- if (i == TVNORMS)
- for (i = 0; i < TVNORMS; i++)
- if (*id & tvnorms[i].id)
- break;
- if (i == TVNORMS)
- return -EINVAL;
-
- down(&usbvision->lock);
- usbvision->tvnorm = &tvnorms[i];
-
- call_i2c_clients(usbvision, VIDIOC_S_STD,
- &usbvision->tvnorm->id);
+ *input = usbvision->ctl_input;
+ return 0;
+}
- up(&usbvision->lock);
+static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- if (!usbvision->have_tuner || vt->index) // Only tuner 0
- return -EINVAL;
- strcpy(vt->name, "Television");
- /* Let clients fill in the remainder of this struct */
- call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || vt->index)
- return -EINVAL;
- /* let clients handle this */
- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
- return 0;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *freq = arg;
-
- freq->tuner = 0; // Only one tuner
- freq->type = V4L2_TUNER_ANALOG_TV;
- freq->frequency = usbvision->freq;
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *freq = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || freq->tuner)
- return -EINVAL;
-
- usbvision->freq = freq->frequency;
- call_i2c_clients(usbvision, cmd, freq);
- PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *v = arg;
- memset(v,0, sizeof(v));
- strcpy(v->name, "TV");
- PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
- return 0;
- }
- case VIDIOC_S_AUDIO:
- {
- struct v4l2_audio *v = arg;
- if(v->index) {
- return -EINVAL;
- }
- PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- int id=ctrl->id;
+ if ((input >= usbvision->video_inputs) || (input < 0) )
+ return -EINVAL;
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
+ down(&usbvision->lock);
+ usbvision_muxsel(usbvision, input);
+ usbvision_set_input(usbvision);
+ usbvision_set_output(usbvision,
+ usbvision->curwidth,
+ usbvision->curheight);
+ up(&usbvision->lock);
+ return 0;
+}
- call_i2c_clients(usbvision, cmd, arg);
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ usbvision->tvnormId=*id;
- if (ctrl->type)
- return 0;
- else
- return -EINVAL;
+ down(&usbvision->lock);
+ call_i2c_clients(usbvision, VIDIOC_S_STD,
+ &usbvision->tvnormId);
+ up(&usbvision->lock);
+ /* propagate the change to the decoder */
+ usbvision_muxsel(usbvision, usbvision->ctl_input);
- PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
- PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
+ return 0;
+}
- PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
- return 0;
- }
- case VIDIOC_REQBUFS:
- {
- struct v4l2_requestbuffers *vr = arg;
- int ret;
+static int vidioc_g_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+ if (!usbvision->have_tuner || vt->index) // Only tuner 0
+ return -EINVAL;
+ if(usbvision->radio) {
+ strcpy(vt->name, "Radio");
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strcpy(vt->name, "Television");
+ }
+ /* Let clients fill in the remainder of this struct */
+ call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
- // Check input validity : the user must do a VIDEO CAPTURE and MMAP method.
- if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (vr->memory != V4L2_MEMORY_MMAP))
- return -EINVAL;
+ return 0;
+}
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
- return ret;
- }
+static int vidioc_s_tuner (struct file *file, void *priv,
+ struct v4l2_tuner *vt)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
- vr->count = usbvision_frames_alloc(usbvision,vr->count);
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || vt->index)
+ return -EINVAL;
+ /* let clients handle this */
+ call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
- usbvision->curFrame = NULL;
+ return 0;
+}
- PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
- return 0;
- }
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *vb = arg;
- struct usbvision_frame *frame;
+static int vidioc_g_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- // FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called)
+ freq->tuner = 0; // Only one tuner
+ if(usbvision->radio) {
+ freq->type = V4L2_TUNER_RADIO;
+ } else {
+ freq->type = V4L2_TUNER_ANALOG_TV;
+ }
+ freq->frequency = usbvision->freq;
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
- if(vb->index>=usbvision->num_frames) {
- return -EINVAL;
- }
- // Updating the corresponding frame state
- vb->flags = 0;
- frame = &usbvision->frame[vb->index];
- if(frame->grabstate >= FrameState_Ready)
- vb->flags |= V4L2_BUF_FLAG_QUEUED;
- if(frame->grabstate >= FrameState_Done)
- vb->flags |= V4L2_BUF_FLAG_DONE;
- if(frame->grabstate == FrameState_Unused)
- vb->flags |= V4L2_BUF_FLAG_MAPPED;
- vb->memory = V4L2_MEMORY_MMAP;
-
- vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->field = V4L2_FIELD_NONE;
- vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
- vb->timestamp = usbvision->frame[vb->index].timestamp;
- vb->sequence = usbvision->frame[vb->index].sequence;
- return 0;
- }
- case VIDIOC_QBUF:
- {
- struct v4l2_buffer *vb = arg;
- struct usbvision_frame *frame;
- unsigned long lock_flags;
-
- // FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
- if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
- return -EINVAL;
- }
- if(vb->index>=usbvision->num_frames) {
- return -EINVAL;
- }
+ return 0;
+}
- frame = &usbvision->frame[vb->index];
+static int vidioc_s_frequency (struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- if (frame->grabstate != FrameState_Unused) {
- return -EAGAIN;
- }
+ // Only no or one tuner for now
+ if (!usbvision->have_tuner || freq->tuner)
+ return -EINVAL;
- /* Mark it as ready and enqueue frame */
- frame->grabstate = FrameState_Ready;
- frame->scanstate = ScanState_Scanning;
- frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+ usbvision->freq = freq->frequency;
+ call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
- vb->flags &= ~V4L2_BUF_FLAG_DONE;
+ return 0;
+}
- /* set v4l2_format index */
- frame->v4l2_format = usbvision->palette;
+static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+ memset(a,0,sizeof(*a));
+ if(usbvision->radio) {
+ strcpy(a->name,"Radio");
+ } else {
+ strcpy(a->name, "TV");
+ }
- PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
- return 0;
- }
- case VIDIOC_DQBUF:
- {
- struct v4l2_buffer *vb = arg;
- int ret;
- struct usbvision_frame *f;
- unsigned long lock_flags;
-
- if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (list_empty(&(usbvision->outqueue))) {
- if (usbvision->streaming == Stream_Idle)
- return -EINVAL;
- ret = wait_event_interruptible
- (usbvision->wait_frame,
- !list_empty(&(usbvision->outqueue)));
- if (ret)
- return ret;
- }
+ return 0;
+}
- spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
- f = list_entry(usbvision->outqueue.next,
- struct usbvision_frame, frame);
- list_del(usbvision->outqueue.next);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
- f->grabstate = FrameState_Unused;
-
- vb->memory = V4L2_MEMORY_MMAP;
- vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
- vb->index = f->index;
- vb->sequence = f->sequence;
- vb->timestamp = f->timestamp;
- vb->field = V4L2_FIELD_NONE;
- vb->bytesused = f->scanlength;
-
- return 0;
- }
- case VIDIOC_STREAMON:
- {
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+static int vidioc_s_audio (struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ if(a->index) {
+ return -EINVAL;
+ }
- usbvision->streaming = Stream_On;
+ return 0;
+}
- call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int id=ctrl->id;
- PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
+ memset(ctrl,0,sizeof(*ctrl));
+ ctrl->id=id;
- return 0;
- }
- case VIDIOC_STREAMOFF:
- {
- int *type = arg;
- int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if(usbvision->streaming == Stream_On) {
- usbvision_stream_interrupt(usbvision);
- // Stop all video streamings
- call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
- }
- usbvision_empty_framequeues(usbvision);
+ call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
- PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
- return 0;
- }
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *vfd = arg;
+ if (!ctrl->type)
+ return -EINVAL;
- if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
- return -EINVAL;
- }
- vfd->flags = 0;
- vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
- vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
- memset(vfd->reserved, 0, sizeof(vfd->reserved));
- return 0;
- }
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *vf = arg;
-
- switch (vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- vf->fmt.pix.width = usbvision->curwidth;
- vf->fmt.pix.height = usbvision->curheight;
- vf->fmt.pix.pixelformat = usbvision->palette.format;
- vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
- vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
- default:
- PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
- return -EINVAL;
- }
- return 0;
- }
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *vf = arg;
- int formatIdx,ret;
-
- switch(vf->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- {
- /* Find requested format in available ones */
- for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
- if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
- usbvision->palette = usbvision_v4l2_format[formatIdx];
- break;
- }
- }
- /* robustness */
- if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
- return -EINVAL;
- }
- RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
- RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
-
- vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
-
- if(cmd == VIDIOC_TRY_FMT) {
- PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
-
- /* stop io in case it is already in progress */
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
- return ret;
- }
- usbvision_frames_free(usbvision);
- usbvision_empty_framequeues(usbvision);
-
- usbvision->curFrame = NULL;
-
- // by now we are committed to the new data...
- down(&usbvision->lock);
- usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
- up(&usbvision->lock);
-
- PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
- vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
- return 0;
- }
- default:
- return -EINVAL;
- }
- }
- default:
- return -ENOIOCTLCMD;
+ return 0;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+
+ return 0;
+}
+
+static int vidioc_reqbufs (struct file *file,
+ void *priv, struct v4l2_requestbuffers *vr)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+
+ RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+ /* Check input validity:
+ the user must do a VIDEO CAPTURE and MMAP method. */
+ if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+ (vr->memory != V4L2_MEMORY_MMAP))
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
}
+
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+ vr->count = usbvision_frames_alloc(usbvision,vr->count);
+
+ usbvision->curFrame = NULL;
+
return 0;
}
-static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_querybuf (struct file *file,
+ void *priv, struct v4l2_buffer *vb)
{
- return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usbvision_frame *frame;
+
+ /* FIXME : must control
+ that buffers are mapped (VIDIOC_REQBUFS has been called) */
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+ /* Updating the corresponding frame state */
+ vb->flags = 0;
+ frame = &usbvision->frame[vb->index];
+ if(frame->grabstate >= FrameState_Ready)
+ vb->flags |= V4L2_BUF_FLAG_QUEUED;
+ if(frame->grabstate >= FrameState_Done)
+ vb->flags |= V4L2_BUF_FLAG_DONE;
+ if(frame->grabstate == FrameState_Unused)
+ vb->flags |= V4L2_BUF_FLAG_MAPPED;
+ vb->memory = V4L2_MEMORY_MMAP;
+
+ vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->field = V4L2_FIELD_NONE;
+ vb->length = usbvision->curwidth*
+ usbvision->curheight*
+ usbvision->palette.bytes_per_pixel;
+ vb->timestamp = usbvision->frame[vb->index].timestamp;
+ vb->sequence = usbvision->frame[vb->index].sequence;
+ return 0;
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usbvision_frame *frame;
+ unsigned long lock_flags;
+
+ /* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+ if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+ if(vb->index>=usbvision->num_frames) {
+ return -EINVAL;
+ }
+
+ frame = &usbvision->frame[vb->index];
+
+ if (frame->grabstate != FrameState_Unused) {
+ return -EAGAIN;
+ }
+
+ /* Mark it as ready and enqueue frame */
+ frame->grabstate = FrameState_Ready;
+ frame->scanstate = ScanState_Scanning;
+ frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+
+ vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ /* set v4l2_format index */
+ frame->v4l2_format = usbvision->palette;
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ return 0;
}
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+ struct usbvision_frame *f;
+ unsigned long lock_flags;
+
+ if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (list_empty(&(usbvision->outqueue))) {
+ if (usbvision->streaming == Stream_Idle)
+ return -EINVAL;
+ ret = wait_event_interruptible
+ (usbvision->wait_frame,
+ !list_empty(&(usbvision->outqueue)));
+ if (ret)
+ return ret;
+ }
+
+ spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+ f = list_entry(usbvision->outqueue.next,
+ struct usbvision_frame, frame);
+ list_del(usbvision->outqueue.next);
+ spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+ f->grabstate = FrameState_Unused;
+
+ vb->memory = V4L2_MEMORY_MMAP;
+ vb->flags = V4L2_BUF_FLAG_MAPPED |
+ V4L2_BUF_FLAG_QUEUED |
+ V4L2_BUF_FLAG_DONE;
+ vb->index = f->index;
+ vb->sequence = f->sequence;
+ vb->timestamp = f->timestamp;
+ vb->field = V4L2_FIELD_NONE;
+ vb->bytesused = f->scanlength;
+
+ return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ usbvision->streaming = Stream_On;
+ call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+ return 0;
+}
+
+static int vidioc_streamoff(struct file *file,
+ void *priv, enum v4l2_buf_type type)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if(usbvision->streaming == Stream_On) {
+ usbvision_stream_interrupt(usbvision);
+ /* Stop all video streamings */
+ call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+ }
+ usbvision_empty_framequeues(usbvision);
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *vfd)
+{
+ if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+ return -EINVAL;
+ }
+ vfd->flags = 0;
+ vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+ vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+ memset(vfd->reserved, 0, sizeof(vfd->reserved));
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ vf->fmt.pix.width = usbvision->curwidth;
+ vf->fmt.pix.height = usbvision->curheight;
+ vf->fmt.pix.pixelformat = usbvision->palette.format;
+ vf->fmt.pix.bytesperline =
+ usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+ vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+
+ return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int formatIdx;
+
+ /* Find requested format in available ones */
+ for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+ if(vf->fmt.pix.pixelformat ==
+ usbvision_v4l2_format[formatIdx].format) {
+ usbvision->palette = usbvision_v4l2_format[formatIdx];
+ break;
+ }
+ }
+ /* robustness */
+ if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+ return -EINVAL;
+ }
+ RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+ RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+ vf->fmt.pix.bytesperline = vf->fmt.pix.width*
+ usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *vf)
+{
+ struct video_device *dev = video_devdata(file);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
+ int ret;
+
+ if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+ return ret;
+ }
+
+ /* stop io in case it is already in progress */
+ if(usbvision->streaming == Stream_On) {
+ if ((ret = usbvision_stream_interrupt(usbvision)))
+ return ret;
+ }
+ usbvision_frames_free(usbvision);
+ usbvision_empty_framequeues(usbvision);
+
+ usbvision->curFrame = NULL;
+
+ /* by now we are committed to the new data... */
+ down(&usbvision->lock);
+ usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+ up(&usbvision->lock);
+
+ return 0;
+}
static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int noblock = file->f_flags & O_NONBLOCK;
unsigned long lock_flags;
int ret,i;
struct usbvision_frame *frame;
- PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+ PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+ (unsigned long)count, noblock);
if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
return -EFAULT;
- /* This entry point is compatible with the mmap routines so that a user can do either
- VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+ /* This entry point is compatible with the mmap routines
+ so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
+ to get frames or call read on the device. */
if(!usbvision->num_frames) {
- /* First, allocate some frames to work with if this has not been done with
- VIDIOC_REQBUF */
+ /* First, allocate some frames to work with
+ if this has not been done with VIDIOC_REQBUF */
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
@@ -1086,21 +1116,24 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
}
- /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+ /* Then, enqueue as many frames as possible
+ (like a user of VIDIOC_QBUF would do) */
for(i=0;i<usbvision->num_frames;i++) {
frame = &usbvision->frame[i];
if(frame->grabstate == FrameState_Unused) {
/* Mark it as ready and enqueue frame */
frame->grabstate = FrameState_Ready;
frame->scanstate = ScanState_Scanning;
- frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
+ /* Accumulated in usbvision_parse_data() */
+ frame->scanlength = 0;
/* set v4l2_format index */
frame->v4l2_format = usbvision->palette;
spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
list_add_tail(&frame->frame, &usbvision->inqueue);
- spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+ spin_unlock_irqrestore(&usbvision->queue_lock,
+ lock_flags);
}
}
@@ -1128,8 +1161,9 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
return 0;
}
- PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
- frame->index, frame->bytes_read, frame->scanlength);
+ PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
+ __FUNCTION__,
+ frame->index, frame->bytes_read, frame->scanlength);
/* copy bytes to user space; we allow for partials reads */
if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
@@ -1140,10 +1174,11 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
}
frame->bytes_read += count;
- PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
- (unsigned long)count, frame->bytes_read);
+ PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
+ __FUNCTION__,
+ (unsigned long)count, frame->bytes_read);
- // For now, forget the frame if it has not been read in one shot.
+ /* For now, forget the frame if it has not been read in one shot. */
/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */
frame->bytes_read = 0;
@@ -1162,7 +1197,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
u32 i;
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
PDEBUG(DBG_MMAP, "mmap");
@@ -1180,11 +1216,13 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
}
for (i = 0; i < usbvision->num_frames; i++) {
- if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+ if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
+ vma->vm_pgoff)
break;
}
if (i == usbvision->num_frames) {
- PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+ PDEBUG(DBG_MMAP,
+ "mmap: user supplied mapping address is out of range");
up(&usbvision->lock);
return -EINVAL;
}
@@ -1218,8 +1256,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
static int usbvision_radio_open(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
- struct v4l2_frequency freq;
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "%s:", __FUNCTION__);
@@ -1249,8 +1287,6 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
// If so far no errors then we shall start the radio
usbvision->radio = 1;
call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
- freq.frequency = 1517; //SWR3 @ 94.8MHz
- call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
usbvision->user++;
}
@@ -1270,7 +1306,8 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
static int usbvision_radio_close(struct inode *inode, struct file *file)
{
struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+ struct usb_usbvision *usbvision =
+ (struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
PDEBUG(DBG_IO, "");
@@ -1304,149 +1341,6 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
return errCode;
}
-static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- struct video_device *dev = video_devdata(file);
- struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision))
- return -EIO;
-
- switch (cmd) {
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *vc=arg;
-
- memset(vc, 0, sizeof(*vc));
- strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
- strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
- sizeof(vc->card));
- strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
- sizeof(vc->bus_info));
- vc->version = USBVISION_DRIVER_VERSION;
- vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
- PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
- return 0;
- }
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *ctrl = arg;
- int id=ctrl->id;
-
- memset(ctrl,0,sizeof(*ctrl));
- ctrl->id=id;
-
- call_i2c_clients(usbvision, cmd, arg);
- PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-
- if (ctrl->type)
- return 0;
- else
- return -EINVAL;
-
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
- PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
-
- call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
- PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
- return 0;
- }
- case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *t = arg;
-
- if (t->index > 0)
- return -EINVAL;
-
- memset(t,0,sizeof(*t));
- strcpy(t->name, "Radio");
- t->type = V4L2_TUNER_RADIO;
-
- /* Let clients fill in the remainder of this struct */
- call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
- PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
- return 0;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner *vt = arg;
-
- // Only no or one tuner for now
- if (!usbvision->have_tuner || vt->index)
- return -EINVAL;
- /* let clients handle this */
- call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
- PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
- return 0;
- }
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
-
- memset(a,0,sizeof(*a));
- strcpy(a->name,"Radio");
- PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
- return 0;
- }
- case VIDIOC_S_AUDIO:
- case VIDIOC_S_INPUT:
- case VIDIOC_S_STD:
- return 0;
-
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- memset(f,0,sizeof(*f));
-
- f->type = V4L2_TUNER_RADIO;
- f->frequency = usbvision->freq;
- call_i2c_clients(usbvision, cmd, f);
- PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
- return 0;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- if (f->tuner != 0)
- return -EINVAL;
- usbvision->freq = f->frequency;
- call_i2c_clients(usbvision, cmd, f);
- PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
- return 0;
- }
- default:
- {
- PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
- return -ENOIOCTLCMD;
- }
- }
- return 0;
-}
-
-
-static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
-}
-
-
/*
* Here comes the stuff for vbi on usbvision based devices
*
@@ -1454,21 +1348,21 @@ static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
static int usbvision_vbi_open(struct inode *inode, struct file *file)
{
/* TODO */
- return -EINVAL;
+ return -ENODEV;
}
static int usbvision_vbi_close(struct inode *inode, struct file *file)
{
/* TODO */
- return -EINVAL;
+ return -ENODEV;
}
static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
/* TODO */
- return -EINVAL;
+ return -ENOIOCTLCMD;
}
static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
@@ -1489,8 +1383,11 @@ static const struct file_operations usbvision_fops = {
.release = usbvision_v4l2_close,
.read = usbvision_v4l2_read,
.mmap = usbvision_v4l2_mmap,
- .ioctl = usbvision_v4l2_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
+/* .poll = video_poll, */
+ .mmap = usbvision_v4l2_mmap,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_video_template = {
.owner = THIS_MODULE,
@@ -1500,6 +1397,39 @@ static struct video_device usbvision_video_template = {
.name = "usbvision-video",
.release = video_device_release,
.minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_g_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/* .vidiocgmbuf = vidiocgmbuf, */
+#endif
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vidioc_g_register,
+ .vidioc_s_register = vidioc_s_register,
+#endif
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
};
@@ -1508,8 +1438,9 @@ static const struct file_operations usbvision_radio_fops = {
.owner = THIS_MODULE,
.open = usbvision_radio_open,
.release = usbvision_radio_close,
- .ioctl = usbvision_radio_ioctl,
+ .ioctl = video_ioctl2,
.llseek = no_llseek,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_radio_template=
@@ -1518,12 +1449,27 @@ static struct video_device usbvision_radio_template=
.type = VID_TYPE_TUNER,
.hardware = VID_HARDWARE_USBVISION,
.fops = &usbvision_radio_fops,
- .release = video_device_release,
.name = "usbvision-radio",
+ .release = video_device_release,
.minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_g_audio = vidioc_s_audio,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
};
-
// vbi template
static const struct file_operations usbvision_vbi_fops = {
.owner = THIS_MODULE,
@@ -1531,6 +1477,7 @@ static const struct file_operations usbvision_vbi_fops = {
.release = usbvision_vbi_close,
.ioctl = usbvision_vbi_ioctl,
.llseek = no_llseek,
+ .compat_ioctl = v4l_compat_ioctl32,
};
static struct video_device usbvision_vbi_template=
@@ -1574,11 +1521,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
{
// vbi Device:
if (usbvision->vbi) {
- PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]",
+ usbvision->vbi->minor & 0x1f);
if (usbvision->vbi->minor != -1) {
video_unregister_device(usbvision->vbi);
- }
- else {
+ } else {
video_device_release(usbvision->vbi);
}
usbvision->vbi = NULL;
@@ -1586,11 +1533,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
// Radio Device:
if (usbvision->rdev) {
- PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]",
+ usbvision->rdev->minor & 0x1f);
if (usbvision->rdev->minor != -1) {
video_unregister_device(usbvision->rdev);
- }
- else {
+ } else {
video_device_release(usbvision->rdev);
}
usbvision->rdev = NULL;
@@ -1598,11 +1545,11 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
// Video Device:
if (usbvision->vdev) {
- PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+ PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]",
+ usbvision->vdev->minor & 0x1f);
if (usbvision->vdev->minor != -1) {
video_unregister_device(usbvision->vdev);
- }
- else {
+ } else {
video_device_release(usbvision->vdev);
}
usbvision->vdev = NULL;
@@ -1613,37 +1560,52 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision)
static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
{
// Video Device:
- usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+ usbvision->vdev = usbvision_vdev_init(usbvision,
+ &usbvision_video_template,
+ "USBVision Video");
if (usbvision->vdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+ if (video_register_device(usbvision->vdev,
+ VFL_TYPE_GRABBER,
+ video_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n",
+ usbvision->nr,usbvision->vdev->minor & 0x1f);
// Radio Device:
if (usbvision_device_data[usbvision->DevModel].Radio) {
// usbvision has radio
- usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+ usbvision->rdev = usbvision_vdev_init(usbvision,
+ &usbvision_radio_template,
+ "USBVision Radio");
if (usbvision->rdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+ if (video_register_device(usbvision->rdev,
+ VFL_TYPE_RADIO,
+ radio_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n",
+ usbvision->nr, usbvision->rdev->minor & 0x1f);
}
// vbi Device:
if (usbvision_device_data[usbvision->DevModel].vbi) {
- usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+ usbvision->vbi = usbvision_vdev_init(usbvision,
+ &usbvision_vbi_template,
+ "USBVision VBI");
if (usbvision->vdev == NULL) {
goto err_exit;
}
- if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+ if (video_register_device(usbvision->vbi,
+ VFL_TYPE_VBI,
+ vbi_nr)<0) {
goto err_exit;
}
- printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
+ printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n",
+ usbvision->nr,usbvision->vbi->minor & 0x1f);
}
// all done
return 0;
@@ -1657,7 +1619,8 @@ static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
/*
* usbvision_alloc()
*
- * This code allocates the struct usb_usbvision. It is filled with default values.
+ * This code allocates the struct usb_usbvision.
+ * It is filled with default values.
*
* Returns NULL on error, a pointer to usb_usbvision else.
*
@@ -1666,7 +1629,8 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev)
{
struct usb_usbvision *usbvision;
- if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
+ if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
+ NULL) {
goto err_exit;
}
@@ -1728,11 +1692,11 @@ static void usbvision_release(struct usb_usbvision *usbvision)
}
-/******************************** usb interface *****************************************/
+/*********************** usb interface **********************************/
static void usbvision_configure_video(struct usb_usbvision *usbvision)
{
- int model,i;
+ int model;
if (usbvision == NULL)
return;
@@ -1741,25 +1705,23 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
- usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2;
+ usbvision->Vin_Reg2_Preset =
+ usbvision_device_data[usbvision->DevModel].Vin_Reg2;
} else {
usbvision->Vin_Reg2_Preset = 0;
}
- for (i = 0; i < TVNORMS; i++)
- if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
- break;
- if (i == TVNORMS)
- i = 0;
- usbvision->tvnorm = &tvnorms[i]; /* set default norm */
+ usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
usbvision->ctl_input = 0;
/* This should be here to make i2c clients to be able to register */
- usbvision_audio_off(usbvision); //first switch off audio
+ /* first switch off audio */
+ usbvision_audio_off(usbvision);
if (!PowerOnAtOpen) {
- usbvision_power_on(usbvision); //and then power up the noisy tuner
+ /* and then power up the noisy tuner */
+ usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
}
}
@@ -1796,18 +1758,22 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
if (usbvision_device_data[model].Interface >= 0) {
interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
- }
- else {
+ } else {
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
}
endpoint = &interface->endpoint[1].desc;
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
- err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
- err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
+ if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+ USB_ENDPOINT_XFER_ISOC) {
+ err("%s: interface %d. has non-ISO endpoint!",
+ __FUNCTION__, ifnum);
+ err("%s: Endpoint attributes %d",
+ __FUNCTION__, endpoint->bmAttributes);
return -ENODEV;
}
- if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
- err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+ if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+ USB_DIR_OUT) {
+ err("%s: interface %d. has ISO OUT endpoint!",
+ __FUNCTION__, ifnum);
return -ENODEV;
}
@@ -1818,11 +1784,9 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
if (dev->descriptor.bNumConfigurations > 1) {
usbvision->bridgeType = BRIDGE_NT1004;
- }
- else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
+ } else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
usbvision->bridgeType = BRIDGE_NT1005;
- }
- else {
+ } else {
usbvision->bridgeType = BRIDGE_NT1003;
}
PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
@@ -1919,11 +1883,11 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
up(&usbvision->lock);
if (usbvision->user) {
- printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
+ printk(KERN_INFO "%s: In use, disconnect pending\n",
+ __FUNCTION__);
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
- }
- else {
+ } else {
usbvision_release(usbvision);
}
@@ -1950,7 +1914,6 @@ static int __init usbvision_init(void)
PDEBUG(DBG_PROBE, "");
- PDEBUG(DBG_IOCTL, "IOCTL debugging is enabled [video]");
PDEBUG(DBG_IO, "IO debugging is enabled [video]");
PDEBUG(DBG_PROBE, "PROBE debugging is enabled [video]");
PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index c759d00d7014..c5b6c501c869 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -221,6 +221,8 @@ enum {
#define I2C_USB_ADAP_MAX 16
+#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M)
+
/* ----------------------------------------------------------------- */
/* usbvision video structures */
/* ----------------------------------------------------------------- */
@@ -301,14 +303,6 @@ struct usbvision_frame_header {
__u16 frameHeight; /* 10 - 11 after endian correction*/
};
-/* tvnorms */
-struct usbvision_tvnorm {
- char *name;
- v4l2_std_id id;
- /* mode for saa7113h */
- int mode;
-};
-
struct usbvision_frame {
char *data; /* Frame buffer */
struct usbvision_frame_header isocHeader; /* Header from stream */
@@ -386,7 +380,6 @@ struct usb_usbvision {
int tuner_type;
int tuner_addr;
int bridgeType; // NT1003, NT1004, NT1005
- int channel;
int radio;
int video_inputs; // # of inputs
unsigned long freq;
@@ -441,7 +434,7 @@ struct usb_usbvision {
struct v4l2_capability vcap; /* Video capabilities */
unsigned int ctl_input; /* selected input */
- struct usbvision_tvnorm *tvnorm; /* selected tv norm */
+ v4l2_std_id tvnormId; /* selected tv norm */
unsigned char video_endp; /* 0x82 for USBVISION devices based */
// Decompression stuff:
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 13ee550d3215..d2915d3530ea 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -939,16 +939,25 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc
When no more controls are available 0 is returned. */
u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
{
- u32 ctrl_class;
+ u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
const u32 *pctrl;
- /* if no query is desired, then just return the control ID */
- if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
- return id;
if (ctrl_classes == NULL)
return 0;
+
+ /* if no query is desired, then check if the ID is part of ctrl_classes */
+ if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+ /* find class */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find control ID */
+ while (*pctrl && *pctrl != id) pctrl++;
+ return *pctrl ? id : 0;
+ }
id &= V4L2_CTRL_ID_MASK;
- ctrl_class = V4L2_CTRL_ID2CLASS(id);
id++; /* select next control */
/* find first class that matches (or is greater than) the class of
the ID */
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index fcc5467e7636..e617925ba31e 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -47,6 +47,7 @@ static int videobuf_dvb_thread(void *data)
int err;
dprintk("dvb thread started\n");
+ set_freezable();
videobuf_read_start(&dvb->dvbq);
for (;;) {
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 0c658b74f2c4..a0c1647a2ba4 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2077,12 +2077,10 @@ static int vino_wait_for_frame(struct vino_channel_settings *vcs)
init_waitqueue_entry(&wait, current);
/* add ourselves into wait queue */
add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
- /* and set current state */
- set_current_state(TASK_INTERRUPTIBLE);
/* to ensure that schedule_timeout will return immediately
- * if VINO interrupt was triggred meanwhile */
- schedule_timeout(HZ / 10);
+ * if VINO interrupt was triggered meanwhile */
+ schedule_timeout_interruptible(msecs_to_jiffies(100));
if (signal_pending(current))
err = -EINTR;
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index f7e1d1910374..f6d3a9460ccc 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/random.h>
#include <linux/version.h>
+#include <linux/mutex.h>
#include <linux/videodev2.h>
#include <linux/dma-mapping.h>
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -145,9 +146,6 @@ struct vivi_buffer {
struct vivi_fmt *fmt;
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr;
-#endif
};
struct vivi_dmaqueue {
@@ -168,7 +166,7 @@ static LIST_HEAD(vivi_devlist);
struct vivi_dev {
struct list_head vivi_devlist;
- struct semaphore lock;
+ struct mutex lock;
int users;
@@ -232,68 +230,13 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-#ifdef CONFIG_VIVI_SCATTER
-static void prep_to_addr(struct sg_to_addr to_addr[],
- struct videobuf_buffer *vb)
-{
- int i, pos=0;
-
- for (i=0;i<vb->dma.nr_pages;i++) {
- to_addr[i].sg=&vb->dma.sglist[i];
- to_addr[i].pos=pos;
- pos += vb->dma.sglist[i].length;
- }
-}
-
-static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
- int p1=0,p2=pages-1,p3=pages/2;
-
- /* Sanity test */
- BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
- while (p1+1<p2) {
- if (pos < to_addr[p3].pos) {
- p2=p3;
- } else {
- p1=p3;
- }
- p3=(p1+p2)/2;
- }
- if (pos >= to_addr[p2].pos)
- p1=p2;
-
- return (p1);
-}
-#endif
-#ifdef CONFIG_VIVI_SCATTER
-static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
- int hmax, int line, char *timestr)
-#else
static void gen_line(char *basep,int inipos,int wmax,
int hmax, int line, char *timestr)
-#endif
{
int w,i,j,pos=inipos,y;
char *p,*s;
u8 chr,r,g,b,color;
-#ifdef CONFIG_VIVI_SCATTER
- int pgpos,oldpg;
- char *basep;
- struct page *pg;
-
- unsigned long flags;
- spinlock_t spinlock;
-
- spin_lock_init(&spinlock);
-
- /* Get first addr pointed to pixel position */
- oldpg=get_addr_pos(pos,pages,to_addr);
- pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
- spin_lock_irqsave(&spinlock,flags);
- basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-#endif
/* We will just duplicate the second pixel at the packet */
wmax/=2;
@@ -305,18 +248,7 @@ static void gen_line(char *basep,int inipos,int wmax,
b=bars[w*7/wmax][2];
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
- kunmap_atomic(basep, KM_BOUNCE_READ);
- basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
switch (color) {
case 0:
@@ -361,23 +293,7 @@ static void gen_line(char *basep,int inipos,int wmax,
pos=inipos+j*2;
for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
- pgpos=get_addr_pos(pos,pages,to_addr);
- if (pgpos!=oldpg) {
- pg=pfn_to_page(sg_dma_address(
- to_addr[pgpos].sg)
- >> PAGE_SHIFT);
- kunmap_atomic(basep,
- KM_BOUNCE_READ);
- basep= kmap_atomic(pg,
- KM_BOUNCE_READ)+
- to_addr[pgpos].sg->offset;
- oldpg=pgpos;
- }
- p=basep+pos-to_addr[pgpos].pos;
-#else
p=basep+pos;
-#endif
y=TO_Y(r,g,b);
@@ -402,12 +318,7 @@ static void gen_line(char *basep,int inipos,int wmax,
end:
-#ifdef CONFIG_VIVI_SCATTER
- kunmap_atomic(basep, KM_BOUNCE_READ);
- spin_unlock_irqrestore(&spinlock,flags);
-#else
return;
-#endif
}
static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
{
@@ -415,35 +326,16 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
-#ifdef CONFIG_VIVI_SCATTER
- struct sg_to_addr *to_addr=buf->to_addr;
- struct videobuf_buffer *vb=&buf->vb;
-#else
char *tmpbuf;
-#endif
-
-#ifdef CONFIG_VIVI_SCATTER
- /* Test if DMA mapping is ready */
- if (!sg_dma_address(&vb->dma.sglist[0]))
- return;
-
- prep_to_addr(to_addr,vb);
- /* Check if there is enough memory */
- BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
-#else
if (buf->vb.dma.varea) {
tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
} else {
tmpbuf=buf->vb.dma.vmalloc;
}
-#endif
for (h=0;h<hmax;h++) {
-#ifdef CONFIG_VIVI_SCATTER
- gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
-#else
if (buf->vb.dma.varea) {
gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
/* FIXME: replacing to __copy_to_user */
@@ -452,7 +344,6 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
} else {
gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
}
-#endif
pos += wmax*2;
}
@@ -573,6 +464,7 @@ static int vivi_thread(void *data)
dprintk(1,"thread started\n");
mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
+ set_freezable();
for (;;) {
vivi_sleep(dma_q);
@@ -717,11 +609,6 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
if (in_interrupt())
BUG();
-#ifdef CONFIG_VIVI_SCATTER
- /*FIXME: Maybe a spinlock is required here */
- kfree(buf->to_addr);
- buf->to_addr=NULL;
-#endif
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_unmap(vq, &buf->vb.dma);
@@ -767,12 +654,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
buf->vb.state = STATE_PREPARED;
-#ifdef CONFIG_VIVI_SCATTER
- if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
- rc=-ENOMEM;
- goto fail;
- }
-#endif
return 0;
fail:
@@ -837,40 +718,6 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
-#ifdef CONFIG_VIVI_SCATTER
-static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
- int direction)
-{
- int i;
-
- dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
- BUG_ON(direction == DMA_NONE);
-
- for (i = 0; i < nents; i++ ) {
- BUG_ON(!sg[i].page);
-
- sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
- }
-
- return nents;
-}
-
-static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
-{
- dprintk(1,"%s\n",__FUNCTION__);
- return 0;
-}
-
-static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
- int direction)
-{
-// dprintk(1,"%s\n",__FUNCTION__);
-
-// flush_write_buffers();
- return 0;
-}
-#endif
static struct videobuf_queue_ops vivi_video_qops = {
.buf_setup = buffer_setup,
@@ -892,16 +739,16 @@ static struct videobuf_queue_ops vivi_video_qops = {
static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
{
/* is it free? */
- down(&dev->lock);
+ mutex_lock(&dev->lock);
if (dev->resources) {
/* no, someone else uses it */
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
dev->resources =1;
dprintk(1,"res: get\n");
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return 1;
}
@@ -912,10 +759,10 @@ static int res_locked(struct vivi_dev *dev)
static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
{
- down(&dev->lock);
+ mutex_lock(&dev->lock);
dev->resources = 0;
dprintk(1,"res: put\n");
- up(&dev->lock);
+ mutex_lock(&dev->lock);
}
/* ------------------------------------------------------------------
@@ -1259,19 +1106,11 @@ static int vivi_open(struct inode *inode, struct file *file)
sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
dev->h,dev->m,dev->s,(dev->us+500)/1000);
-#ifdef CONFIG_VIVI_SCATTER
- videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
- NULL, NULL,
- fh->type,
- V4L2_FIELD_INTERLACED,
- sizeof(struct vivi_buffer),fh);
-#else
videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
NULL, NULL,
fh->type,
V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer),fh);
-#endif
return 0;
}
@@ -1422,7 +1261,7 @@ static int __init vivi_init(void)
init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
dev->vidq.timeout.function = vivi_vid_timeout;
dev->vidq.timeout.data = (unsigned long)dev;
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 8f6741a28a47..1bf4cbec6a87 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -321,12 +321,14 @@ static int wm8739_probe(struct i2c_adapter *adapter)
static int wm8739_detach(struct i2c_client *client)
{
+ struct wm8739_state *state = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
if (err)
return err;
+ kfree(state);
kfree(client);
return 0;
}
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 4df5d30d4d09..9f7e894ef962 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -222,12 +222,14 @@ static int wm8775_probe(struct i2c_adapter *adapter)
static int wm8775_detach(struct i2c_client *client)
{
+ struct wm8775_state *state = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
if (err) {
return err;
}
+ kfree(state);
kfree(client);
return 0;
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index 47cd93f9c7de..edb00293cd59 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,6 +1,6 @@
config USB_ZC0301
tristate "USB ZC0301[P] Image Processor and Control Chip support"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2
---help---
Say Y here if you want support for cameras based on the ZC0301 or
ZC0301P Image Processors and Control Chips.
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index 710f12eb9126..a2de50efa31a 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -36,6 +36,7 @@
#include <linux/rwsem.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/kref.h>
#include "zc0301_sensor.h"
@@ -98,7 +99,7 @@ struct zc0301_module_param {
u16 frame_timeout;
};
-static DECLARE_RWSEM(zc0301_disconnect);
+static DECLARE_RWSEM(zc0301_dev_lock);
struct zc0301_device {
struct video_device* v4ldev;
@@ -121,12 +122,14 @@ struct zc0301_device {
struct zc0301_module_param module_param;
+ struct kref kref;
enum zc0301_dev_state state;
u8 users;
- struct mutex dev_mutex, fileop_mutex;
+ struct completion probe;
+ struct mutex open_mutex, fileop_mutex;
spinlock_t queue_lock;
- wait_queue_head_t open, wait_frame, wait_stream;
+ wait_queue_head_t wait_open, wait_frame, wait_stream;
};
/*****************************************************************************/
@@ -156,8 +159,8 @@ do { \
else if ((level) == 2) \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
+ __FILE__, __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -166,8 +169,8 @@ do { \
if ((level) == 1 || (level) == 2) \
pr_info("zc0301: " fmt "\n", ## args); \
else if ((level) == 3) \
- pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__, \
- __LINE__ , ## args); \
+ pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
+ __FUNCTION__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -183,8 +186,8 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+ __LINE__ , ## args)
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index f1120551c70c..703b741e46df 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -49,11 +49,11 @@
#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
"Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
+#define ZC0301_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.07"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 7)
+#define ZC0301_MODULE_VERSION "1:1.10"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 10)
/*****************************************************************************/
@@ -573,7 +573,8 @@ static int zc0301_init(struct zc0301_device* cam)
int err = 0;
if (!(cam->state & DEV_INITIALIZED)) {
- init_waitqueue_head(&cam->open);
+ mutex_init(&cam->open_mutex);
+ init_waitqueue_head(&cam->wait_open);
qctrl = s->qctrl;
rect = &(s->cropcap.defrect);
cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
@@ -634,59 +635,73 @@ static int zc0301_init(struct zc0301_device* cam)
return 0;
}
+/*****************************************************************************/
-static void zc0301_release_resources(struct zc0301_device* cam)
+static void zc0301_release_resources(struct kref *kref)
{
+ struct zc0301_device *cam = container_of(kref, struct zc0301_device,
+ kref);
DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
video_set_drvdata(cam->v4ldev, NULL);
video_unregister_device(cam->v4ldev);
+ usb_put_dev(cam->usbdev);
kfree(cam->control_buffer);
+ kfree(cam);
}
-/*****************************************************************************/
static int zc0301_open(struct inode* inode, struct file* filp)
{
struct zc0301_device* cam;
int err = 0;
- /*
- This is the only safe way to prevent race conditions with
- disconnect
- */
- if (!down_read_trylock(&zc0301_disconnect))
+ if (!down_read_trylock(&zc0301_dev_lock))
return -ERESTARTSYS;
cam = video_get_drvdata(video_devdata(filp));
- if (mutex_lock_interruptible(&cam->dev_mutex)) {
- up_read(&zc0301_disconnect);
+ if (wait_for_completion_interruptible(&cam->probe)) {
+ up_read(&zc0301_dev_lock);
return -ERESTARTSYS;
}
+ kref_get(&cam->kref);
+
+ if (mutex_lock_interruptible(&cam->open_mutex)) {
+ kref_put(&cam->kref, zc0301_release_resources);
+ up_read(&zc0301_dev_lock);
+ return -ERESTARTSYS;
+ }
+
+ if (cam->state & DEV_DISCONNECTED) {
+ DBG(1, "Device not present");
+ err = -ENODEV;
+ goto out;
+ }
+
if (cam->users) {
DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+ DBG(3, "Simultaneous opens are not supported");
if ((filp->f_flags & O_NONBLOCK) ||
(filp->f_flags & O_NDELAY)) {
err = -EWOULDBLOCK;
goto out;
}
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->state & DEV_DISCONNECTED
+ DBG(2, "A blocking open() has been requested. Wait for the "
+ "device to be released...");
+ up_read(&zc0301_dev_lock);
+ err = wait_event_interruptible_exclusive(cam->wait_open,
+ (cam->state & DEV_DISCONNECTED)
|| !cam->users);
- if (err) {
- up_read(&zc0301_disconnect);
- return err;
- }
+ down_read(&zc0301_dev_lock);
+ if (err)
+ goto out;
if (cam->state & DEV_DISCONNECTED) {
- up_read(&zc0301_disconnect);
- return -ENODEV;
+ err = -ENODEV;
+ goto out;
}
- mutex_lock(&cam->dev_mutex);
}
-
if (cam->state & DEV_MISCONFIGURED) {
err = zc0301_init(cam);
if (err) {
@@ -711,36 +726,32 @@ static int zc0301_open(struct inode* inode, struct file* filp)
DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
out:
- mutex_unlock(&cam->dev_mutex);
- up_read(&zc0301_disconnect);
+ mutex_unlock(&cam->open_mutex);
+ if (err)
+ kref_put(&cam->kref, zc0301_release_resources);
+ up_read(&zc0301_dev_lock);
return err;
}
static int zc0301_release(struct inode* inode, struct file* filp)
{
- struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+ struct zc0301_device* cam;
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+ down_write(&zc0301_dev_lock);
- zc0301_stop_transfer(cam);
+ cam = video_get_drvdata(video_devdata(filp));
+ zc0301_stop_transfer(cam);
zc0301_release_buffers(cam);
-
- if (cam->state & DEV_DISCONNECTED) {
- zc0301_release_resources(cam);
- usb_put_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
cam->users--;
- wake_up_interruptible_nr(&cam->open, 1);
+ wake_up_interruptible_nr(&cam->wait_open, 1);
DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
- mutex_unlock(&cam->dev_mutex);
+ kref_put(&cam->kref, zc0301_release_resources);
+
+ up_write(&zc0301_dev_lock);
return 0;
}
@@ -775,7 +786,7 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
DBG(3, "Close and open the device again to choose the read "
"method");
mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
+ return -EBUSY;
}
if (cam->io == IO_NONE) {
@@ -953,7 +964,12 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
return -EIO;
}
- if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+ if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+ mutex_unlock(&cam->fileop_mutex);
+ return -EACCES;
+ }
+
+ if (cam->io != IO_MMAP ||
size != PAGE_ALIGN(cam->frame[0].buf.length)) {
mutex_unlock(&cam->fileop_mutex);
return -EINVAL;
@@ -984,7 +1000,6 @@ static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
vma->vm_ops = &zc0301_vm_ops;
vma->vm_private_data = &cam->frame[i];
-
zc0301_vm_open(vma);
mutex_unlock(&cam->fileop_mutex);
@@ -1211,7 +1226,7 @@ zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_CROP failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (!s->set_crop) {
@@ -1434,7 +1449,7 @@ zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_S_FMT failed. "
"Unmap the buffers first.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -1544,14 +1559,14 @@ zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
if (cam->io == IO_READ) {
DBG(3, "Close and open the device again to choose the mmap "
"I/O method");
- return -EINVAL;
+ return -EBUSY;
}
for (i = 0; i < cam->nbuffers; i++)
if (cam->frame[i].vma_use_count) {
DBG(3, "VIDIOC_REQBUFS failed. "
"Previous buffers are still mapped.");
- return -EINVAL;
+ return -EBUSY;
}
if (cam->stream == STREAM_ON)
@@ -1699,9 +1714,6 @@ zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
return -EINVAL;
- if (list_empty(&cam->inqueue))
- return -EINVAL;
-
cam->stream = STREAM_ON;
DBG(3, "Stream on");
@@ -1949,8 +1961,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
goto fail;
}
- mutex_init(&cam->dev_mutex);
-
DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
@@ -1982,7 +1992,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->v4ldev->release = video_device_release;
video_set_drvdata(cam->v4ldev, cam);
- mutex_lock(&cam->dev_mutex);
+ init_completion(&cam->probe);
err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
video_nr[dev_nr]);
@@ -1992,7 +2002,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "Free /dev/videoX node not found");
video_nr[dev_nr] = -1;
dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
goto fail;
}
@@ -2004,8 +2014,10 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
usb_set_intfdata(intf, cam);
+ kref_init(&cam->kref);
+ usb_get_dev(cam->usbdev);
- mutex_unlock(&cam->dev_mutex);
+ complete_all(&cam->probe);
return 0;
@@ -2022,40 +2034,31 @@ fail:
static void zc0301_usb_disconnect(struct usb_interface* intf)
{
- struct zc0301_device* cam = usb_get_intfdata(intf);
-
- if (!cam)
- return;
+ struct zc0301_device* cam;
- down_write(&zc0301_disconnect);
+ down_write(&zc0301_dev_lock);
- mutex_lock(&cam->dev_mutex);
+ cam = usb_get_intfdata(intf);
DBG(2, "Disconnecting %s...", cam->v4ldev->name);
- wake_up_interruptible_all(&cam->open);
-
if (cam->users) {
DBG(2, "Device /dev/video%d is open! Deregistration and "
- "memory deallocation are deferred on close.",
+ "memory deallocation are deferred.",
cam->v4ldev->minor);
cam->state |= DEV_MISCONFIGURED;
zc0301_stop_transfer(cam);
cam->state |= DEV_DISCONNECTED;
wake_up_interruptible(&cam->wait_frame);
wake_up(&cam->wait_stream);
- usb_get_dev(cam->usbdev);
- } else {
+ } else
cam->state |= DEV_DISCONNECTED;
- zc0301_release_resources(cam);
- }
- mutex_unlock(&cam->dev_mutex);
+ wake_up_interruptible_all(&cam->wait_open);
- if (!cam->users)
- kfree(cam);
+ kref_put(&cam->kref, zc0301_release_resources);
- up_write(&zc0301_disconnect);
+ up_write(&zc0301_dev_lock);
}
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index 3efb92a0d0da..24b0dfba357e 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -327,6 +327,7 @@ static struct zc0301_sensor pas202bcb = {
.height = 480,
.pixelformat = V4L2_PIX_FMT_JPEG,
.priv = 8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
},
};
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
index 5784b1d1491c..9519aba3612e 100644
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -157,6 +157,7 @@ static struct zc0301_sensor pb0330 = {
.height = 480,
.pixelformat = V4L2_PIX_FMT_JPEG,
.priv = 8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
},
};
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 44e82cff9319..70fe6fc6cdd5 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -23,7 +23,7 @@
#define _ZC0301_SENSOR_H_
#include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/errno.h>
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index cf0ed6cbb0e3..17118a490f81 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -183,14 +183,7 @@ static const int zoran_num_formats =
(sizeof(zoran_formats) / sizeof(struct zoran_format));
// RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-#if !defined(CONFIG_BIGPHYS_AREA)
-//#undef CONFIG_BIGPHYS_AREA
-#define BUZ_USE_HIMEM
-#endif
-#if defined(CONFIG_BIGPHYS_AREA)
-# include <linux/bigphysarea.h>
-#endif
extern int *zr_debug;
@@ -250,7 +243,6 @@ static void jpg_fbuffer_free(struct file *file);
* Linux with the necessary memory left over).
*/
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
static unsigned long
get_high_mem (unsigned long size)
{
@@ -314,7 +306,6 @@ get_high_mem (unsigned long size)
return hi_mem_ph;
}
-#endif
static int
v4l_fbuffer_alloc (struct file *file)
@@ -323,9 +314,7 @@ v4l_fbuffer_alloc (struct file *file)
struct zoran *zr = fh->zr;
int i, off;
unsigned char *mem;
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
unsigned long pmem = 0;
-#endif
/* we might have old buffers lying around... */
if (fh->v4l_buffers.ready_to_be_freed) {
@@ -369,39 +358,6 @@ v4l_fbuffer_alloc (struct file *file)
ZR_DEVNAME(zr), i, (unsigned long) mem,
virt_to_bus(mem));
} else {
-#if defined(CONFIG_BIGPHYS_AREA)
- /* Use bigphysarea_alloc_pages */
-
- int n =
- (fh->v4l_buffers.buffer_size + PAGE_SIZE -
- 1) / PAGE_SIZE;
-
- mem =
- (unsigned char *) bigphysarea_alloc_pages(n, 0,
- GFP_KERNEL);
- if (mem == 0) {
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n",
- ZR_DEVNAME(zr), i);
- v4l_fbuffer_free(file);
- return -ENOBUFS;
- }
- fh->v4l_buffers.buffer[i].fbuffer = mem;
- fh->v4l_buffers.buffer[i].fbuffer_phys =
- virt_to_phys(mem);
- fh->v4l_buffers.buffer[i].fbuffer_bus =
- virt_to_bus(mem);
- dprintk(4,
- KERN_INFO
- "%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
- ZR_DEVNAME(zr), i, (unsigned) mem,
- (unsigned) virt_to_bus(mem));
-
- /* Zero out the allocated memory */
- memset(fh->v4l_buffers.buffer[i].fbuffer, 0,
- fh->v4l_buffers.buffer_size);
-#elif defined(BUZ_USE_HIMEM)
/* Use high memory which has been left at boot time */
@@ -441,20 +397,6 @@ v4l_fbuffer_alloc (struct file *file)
fh->v4l_buffers.buffer[i].fbuffer_bus =
pmem + i * fh->v4l_buffers.buffer_size;
}
-#else
- /* No bigphysarea present, usage of high memory disabled,
- * but user wants buffers of more than MAX_KMALLOC_MEM */
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n",
- ZR_DEVNAME(zr));
- dprintk(1,
- KERN_ERR
- "%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n",
- ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers,
- fh->v4l_buffers.buffer_size >> 10);
- return -ENOBUFS;
-#endif
}
}
@@ -485,11 +427,6 @@ v4l_fbuffer_free (struct file *file)
ClearPageReserved(MAP_NR(mem + off));
kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
}
-#if defined(CONFIG_BIGPHYS_AREA)
- else
- bigphysarea_free_pages((void *) fh->v4l_buffers.
- buffer[i].fbuffer);
-#endif
fh->v4l_buffers.buffer[i].fbuffer = NULL;
}
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index b5d3364c94c7..6f1892585cbb 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -92,6 +92,7 @@ static struct usb_device_id device_table[] = {
{USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
{USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
{USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
+ {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
{} /* Terminating entry */
};
@@ -792,6 +793,7 @@ static int zr364xx_probe(struct usb_interface *intf,
{
struct usb_device *udev = interface_to_usbdev(intf);
struct zr364xx_camera *cam = NULL;
+ int err;
DBG("probing...");
@@ -799,12 +801,11 @@ static int zr364xx_probe(struct usb_interface *intf,
info("model %04x:%04x detected", udev->descriptor.idVendor,
udev->descriptor.idProduct);
- if ((cam =
- kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) {
+ cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
+ if (cam == NULL) {
info("cam: out of memory !");
- return -ENODEV;
+ return -ENOMEM;
}
- memset(cam, 0x00, sizeof(struct zr364xx_camera));
/* save the init method used by this camera */
cam->method = id->driver_info;
@@ -812,7 +813,7 @@ static int zr364xx_probe(struct usb_interface *intf,
if (cam->vdev == NULL) {
info("cam->vdev: out of memory !");
kfree(cam);
- return -ENODEV;
+ return -ENOMEM;
}
memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
video_set_drvdata(cam->vdev, cam);
@@ -858,12 +859,13 @@ static int zr364xx_probe(struct usb_interface *intf,
cam->brightness = 64;
mutex_init(&cam->lock);
- if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+ err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (err) {
info("video_register_device failed");
video_device_release(cam->vdev);
kfree(cam->buffer);
kfree(cam);
- return -ENODEV;
+ return err;
}
usb_set_intfdata(intf, cam);
@@ -905,7 +907,7 @@ static struct usb_driver zr364xx_driver = {
static int __init zr364xx_init(void)
{
int retval;
- retval = usb_register(&zr364xx_driver) < 0;
+ retval = usb_register(&zr364xx_driver);
if (retval)
info("usb_register failed!");
else
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index c88cc75ab49b..4494e0fd36c6 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -37,6 +37,7 @@ config FUSION_FC
LSIFC929
LSIFC929X
LSIFC929XL
+ Brocade FC 410/420
config FUSION_SAS
tristate "Fusion MPT ScsiHost drivers for SAS"
diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
deleted file mode 100644
index bb2bf5aa0b62..000000000000
--- a/drivers/message/fusion/linux_compat.h
+++ /dev/null
@@ -1,9 +0,0 @@
-/* drivers/message/fusion/linux_compat.h */
-
-#ifndef FUSION_LINUX_COMPAT_H
-#define FUSION_LINUX_COMPAT_H
-
-#include <linux/version.h>
-#include <scsi/scsi_device.h>
-
-#endif /* _LINUX_COMPAT_H */
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 75223bf24ae8..6a92e3d118fe 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi.h
* Title: MPI Message independent structures and definitions
* Creation Date: July 27, 2000
*
- * mpi.h Version: 01.05.12
+ * mpi.h Version: 01.05.13
*
* Version History
* ---------------
@@ -78,6 +78,7 @@
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
+ * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -108,7 +109,7 @@
/* Note: The major versions of 0xe0 through 0xff are reserved */
/* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT (0x0E)
+#define MPI_HEADER_VERSION_UNIT (0x10)
#define MPI_HEADER_VERSION_DEV (0x00)
#define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index 0e4c8e77a81d..eda769730e39 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi_cnfg.h
* Title: MPI Config message, structures, and Pages
* Creation Date: July 27, 2000
*
- * mpi_cnfg.h Version: 01.05.13
+ * mpi_cnfg.h Version: 01.05.15
*
* Version History
* ---------------
@@ -293,6 +293,21 @@
* Added more AccessStatus values for SAS Device Page 0.
* Added bit for SATA Asynchronous Notification Support in
* Flags field of SAS Device Page 0.
+ * 02-28-07 01.05.14 Added ExtFlags field to Manufacturing Page 4.
+ * Added Disable SMART Polling for CapabilitiesFlags of
+ * IOC Page 6.
+ * Added Disable SMART Polling to DeviceSettings of BIOS
+ * Page 1.
+ * Added Multi-Port Domain bit for DiscoveryStatus field
+ * of SAS IO Unit Page.
+ * Added Multi-Port Domain Illegal flag for SAS IO Unit
+ * Page 1 AdditionalControlFlags field.
+ * 05-24-07 01.05.15 Added Hide Physical Disks with Non-Integrated RAID
+ * Metadata bit to Manufacturing Page 4 ExtFlags field.
+ * Added Internal Connector to End Device Present bit to
+ * Expander Page 0 Flags field.
+ * Fixed define for
+ * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
* --------------------------------------------------------------------------
*/
@@ -639,7 +654,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
U8 InfoSize1; /* 0Bh */
U8 InquirySize; /* 0Ch */
U8 Flags; /* 0Dh */
- U16 Reserved2; /* 0Eh */
+ U16 ExtFlags; /* 0Eh */
U8 InquiryData[56]; /* 10h */
U32 ISVolumeSettings; /* 48h */
U32 IMEVolumeSettings; /* 4Ch */
@@ -658,7 +673,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
} CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
-#define MPI_MANUFACTURING4_PAGEVERSION (0x04)
+#define MPI_MANUFACTURING4_PAGEVERSION (0x05)
/* defines for the Flags field */
#define MPI_MANPAGE4_FORCE_BAD_BLOCK_TABLE (0x80)
@@ -670,6 +685,12 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
#define MPI_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x02)
#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01)
+/* defines for the ExtFlags field */
+#define MPI_MANPAGE4_EXTFLAGS_HIDE_NON_IR_METADATA (0x0008)
+#define MPI_MANPAGE4_EXTFLAGS_SAS_CACHE_DISABLE (0x0004)
+#define MPI_MANPAGE4_EXTFLAGS_SATA_CACHE_DISABLE (0x0002)
+#define MPI_MANPAGE4_EXTFLAGS_LEGACY_MODE (0x0001)
+
#ifndef MPI_MANPAGE5_NUM_FORCEWWID
#define MPI_MANPAGE5_NUM_FORCEWWID (1)
@@ -781,7 +802,7 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_9
} CONFIG_PAGE_MANUFACTURING_9, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_9,
ManufacturingPage9_t, MPI_POINTER pManufacturingPage9_t;
-#define MPI_MANUFACTURING6_PAGEVERSION (0x00)
+#define MPI_MANUFACTURING9_PAGEVERSION (0x00)
typedef struct _CONFIG_PAGE_MANUFACTURING_10
@@ -1138,6 +1159,8 @@ typedef struct _CONFIG_PAGE_IOC_6
/* IOC Page 6 Capabilities Flags */
+#define MPI_IOCPAGE6_CAP_FLAGS_DISABLE_SMART_POLLING (0x00000008)
+
#define MPI_IOCPAGE6_CAP_FLAGS_MASK_METADATA_SIZE (0x00000006)
#define MPI_IOCPAGE6_CAP_FLAGS_64MB_METADATA_SIZE (0x00000000)
#define MPI_IOCPAGE6_CAP_FLAGS_512MB_METADATA_SIZE (0x00000002)
@@ -1208,6 +1231,7 @@ typedef struct _CONFIG_PAGE_BIOS_1
#define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008)
/* values for the DeviceSettings field */
+#define MPI_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010)
#define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008)
#define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004)
#define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002)
@@ -2281,11 +2305,11 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0
typedef struct _CONFIG_PAGE_RAID_VOL_1
{
CONFIG_PAGE_HEADER Header; /* 00h */
- U8 VolumeID; /* 01h */
- U8 VolumeBus; /* 02h */
- U8 VolumeIOC; /* 03h */
- U8 Reserved0; /* 04h */
- U8 GUID[24]; /* 05h */
+ U8 VolumeID; /* 04h */
+ U8 VolumeBus; /* 05h */
+ U8 VolumeIOC; /* 06h */
+ U8 Reserved0; /* 07h */
+ U8 GUID[24]; /* 08h */
U8 Name[32]; /* 20h */
U64 WWID; /* 40h */
U32 Reserved1; /* 48h */
@@ -2340,7 +2364,7 @@ typedef struct _RAID_PHYS_DISK0_STATUS
} RAID_PHYS_DISK0_STATUS, MPI_POINTER PTR_RAID_PHYS_DISK0_STATUS,
RaidPhysDiskStatus_t, MPI_POINTER pRaidPhysDiskStatus_t;
-/* RAID Volume 2 IM Physical Disk DiskStatus flags */
+/* RAID Physical Disk PhysDiskStatus flags */
#define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x01)
#define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED (0x02)
@@ -2544,6 +2568,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0
#define MPI_SAS_IOUNIT0_DS_TABLE_LINK (0x00000400)
#define MPI_SAS_IOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800)
#define MPI_SAS_IOUNIT0_DS_MAX_SATA_TARGETS (0x00001000)
+#define MPI_SAS_IOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000)
typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA
@@ -2607,6 +2632,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
/* values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI_SAS_IOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080)
#define MPI_SAS_IOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
#define MPI_SAS_IOUNIT1_ACONTROL_HIDE_NONZERO_ATTACHED_PHY_IDENT (0x0020)
#define MPI_SAS_IOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010)
@@ -2734,6 +2760,7 @@ typedef struct _CONFIG_PAGE_SAS_EXPANDER_0
#define MPI_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800)
/* values for SAS Expander Page 0 Flags field */
+#define MPI_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x04)
#define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x02)
#define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x01)
@@ -2774,7 +2801,7 @@ typedef struct _CONFIG_PAGE_SAS_EXPANDER_1
/* see mpi_sas.h for values for SAS Expander Page 1 AttachedDeviceInfo values */
/* values for SAS Expander Page 1 DiscoveryInfo field */
-#define MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY DISABLED (0x04)
+#define MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04)
#define MPI_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02)
#define MPI_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01)
@@ -2895,11 +2922,11 @@ typedef struct _CONFIG_PAGE_SAS_PHY_0
U8 AttachedPhyIdentifier; /* 16h */
U8 Reserved2; /* 17h */
U32 AttachedDeviceInfo; /* 18h */
- U8 ProgrammedLinkRate; /* 20h */
- U8 HwLinkRate; /* 21h */
- U8 ChangeCount; /* 22h */
- U8 Flags; /* 23h */
- U32 PhyInfo; /* 24h */
+ U8 ProgrammedLinkRate; /* 1Ch */
+ U8 HwLinkRate; /* 1Dh */
+ U8 ChangeCount; /* 1Eh */
+ U8 Flags; /* 1Fh */
+ U32 PhyInfo; /* 20h */
} CONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0,
SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t;
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index ddc7ae029dd3..a1f479057ea3 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -3,28 +3,28 @@
MPI Header File Change History
==============================
- Copyright (c) 2000-2006 LSI Logic Corporation.
+ Copyright (c) 2000-2007 LSI Logic Corporation.
---------------------------------------
- Header Set Release Version: 01.05.14
- Header Set Release Date: 10-11-06
+ Header Set Release Version: 01.05.16
+ Header Set Release Date: 05-24-07
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi.h 01.05.12 01.05.11
- mpi_ioc.h 01.05.12 01.05.11
- mpi_cnfg.h 01.05.13 01.05.12
- mpi_init.h 01.05.08 01.05.07
+ mpi.h 01.05.13 01.05.12
+ mpi_ioc.h 01.05.14 01.05.13
+ mpi_cnfg.h 01.05.15 01.05.14
+ mpi_init.h 01.05.09 01.05.09
mpi_targ.h 01.05.06 01.05.06
mpi_fc.h 01.05.01 01.05.01
mpi_lan.h 01.05.01 01.05.01
- mpi_raid.h 01.05.02 01.05.02
+ mpi_raid.h 01.05.03 01.05.03
mpi_tool.h 01.05.03 01.05.03
mpi_inb.h 01.05.01 01.05.01
- mpi_sas.h 01.05.04 01.05.03
+ mpi_sas.h 01.05.04 01.05.04
mpi_type.h 01.05.02 01.05.02
- mpi_history.txt 01.05.14 01.05.13
+ mpi_history.txt 01.05.14 01.05.14
* Date Version Description
@@ -95,6 +95,7 @@ mpi.h
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
* 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* 10-11-06 01.05.12 Bumped MPI_HEADER_VERSION_UNIT.
+ * 05-24-07 01.05.13 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
mpi_ioc.h
@@ -191,6 +192,13 @@ mpi_ioc.h
* data structure.
* Added new ImageType values for FWDownload and FWUpload
* requests.
+ * 02-28-07 01.05.13 Added MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT for SAS
+ * Broadcast Event Data (replacing _RESERVED2).
+ * For Discovery Error Event Data DiscoveryStatus field,
+ * replaced _MULTPL_PATHS with _UNSUPPORTED_DEVICE and
+ * added _MULTI_PORT_DOMAIN.
+ * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
+ * Added Common Boot Block type to FWUpload Request.
* --------------------------------------------------------------------------
mpi_cnfg.h
@@ -473,6 +481,21 @@ mpi_cnfg.h
* Added more AccessStatus values for SAS Device Page 0.
* Added bit for SATA Asynchronous Notification Support in
* Flags field of SAS Device Page 0.
+ * 02-28-07 01.05.14 Added ExtFlags field to Manufacturing Page 4.
+ * Added Disable SMART Polling for CapabilitiesFlags of
+ * IOC Page 6.
+ * Added Disable SMART Polling to DeviceSettings of BIOS
+ * Page 1.
+ * Added Multi-Port Domain bit for DiscoveryStatus field
+ * of SAS IO Unit Page.
+ * Added Multi-Port Domain Illegal flag for SAS IO Unit
+ * Page 1 AdditionalControlFlags field.
+ * 05-24-07 01.05.15 Added Hide Physical Disks with Non-Integrated RAID
+ * Metadata bit to Manufacturing Page 4 ExtFlags field.
+ * Added Internal Connector to End Device Present bit to
+ * Expander Page 0 Flags field.
+ * Fixed define for
+ * MPI_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED.
* --------------------------------------------------------------------------
mpi_init.h
@@ -517,6 +540,8 @@ mpi_init.h
* unique in the first 32 characters.
* 03-27-06 01.05.07 Added Task Management type of Clear ACA.
* 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA.
+ * 02-28-07 01.05.09 Defined two new MsgFlags bits for SCSI Task Management
+ * Request: Do Not Send Task IU and Soft Reset Option.
* --------------------------------------------------------------------------
mpi_targ.h
@@ -571,7 +596,7 @@ mpi_fc.h
* 11-02-00 01.01.01 Original release for post 1.0 work
* 12-04-00 01.01.02 Added messages for Common Transport Send and
* Primitive Send.
- * 01-09-01 01.01.03 Modified some of the new flags to have an MPI prefix
+ * 01-09-01 01.01.03 Modifed some of the new flags to have an MPI prefix
* and modified the FcPrimitiveSend flags.
* 01-25-01 01.01.04 Move InitiatorIndex in LinkServiceRsp reply to a larger
* field.
@@ -634,6 +659,8 @@ mpi_raid.h
* 08-19-04 01.05.01 Original release for MPI v1.5.
* 01-15-05 01.05.02 Added defines for the two new RAID Actions for
* _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
+ * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
+ * associated defines.
* --------------------------------------------------------------------------
mpi_tool.h
@@ -682,7 +709,22 @@ mpi_type.h
mpi_history.txt Parts list history
-Filename 01.05.13 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
+Filename 01.05.15 01.05.15
+---------- -------- --------
+mpi.h 01.05.12 01.05.13
+mpi_ioc.h 01.05.13 01.05.14
+mpi_cnfg.h 01.05.14 01.05.15
+mpi_init.h 01.05.09 01.05.09
+mpi_targ.h 01.05.06 01.05.06
+mpi_fc.h 01.05.01 01.05.01
+mpi_lan.h 01.05.01 01.05.01
+mpi_raid.h 01.05.03 01.05.03
+mpi_tool.h 01.05.03 01.05.03
+mpi_inb.h 01.05.01 01.05.01
+mpi_sas.h 01.05.04 01.05.04
+mpi_type.h 01.05.02 01.05.02
+
+Filename 01.05.14 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
---------- -------- -------- -------- -------- -------- --------
mpi.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07
mpi_ioc.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08
diff --git a/drivers/message/fusion/lsi/mpi_inb.h b/drivers/message/fusion/lsi/mpi_inb.h
deleted file mode 100644
index ff167309ba27..000000000000
--- a/drivers/message/fusion/lsi/mpi_inb.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (c) 2003-2004 LSI Logic Corporation.
- *
- *
- * Name: mpi_inb.h
- * Title: MPI Inband structures and definitions
- * Creation Date: September 30, 2003
- *
- * mpi_inb.h Version: 01.05.01
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 05-11-04 01.03.01 Original release.
- * 08-19-04 01.05.01 Original release for MPI v1.5.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI_INB_H
-#define MPI_INB_H
-
-/******************************************************************************
-*
-* I n b a n d M e s s a g e s
-*
-*******************************************************************************/
-
-
-/****************************************************************************/
-/* Inband Buffer Post Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_BUFFER_POST_REQUEST
-{
- U8 Reserved1; /* 00h */
- U8 BufferCount; /* 01h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- SGE_TRANS_SIMPLE_UNION SGL; /* 10h */
-} MSG_INBAND_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REQUEST,
- MpiInbandBufferPostRequest_t , MPI_POINTER pMpiInbandBufferPostRequest_t;
-
-
-typedef struct _WWN_FC_FORMAT
-{
- U64 NodeName; /* 00h */
- U64 PortName; /* 08h */
-} WWN_FC_FORMAT, MPI_POINTER PTR_WWN_FC_FORMAT,
- WwnFcFormat_t, MPI_POINTER pWwnFcFormat_t;
-
-typedef struct _WWN_SAS_FORMAT
-{
- U64 WorldWideID; /* 00h */
- U32 Reserved1; /* 08h */
- U32 Reserved2; /* 0Ch */
-} WWN_SAS_FORMAT, MPI_POINTER PTR_WWN_SAS_FORMAT,
- WwnSasFormat_t, MPI_POINTER pWwnSasFormat_t;
-
-typedef union _WWN_INBAND_FORMAT
-{
- WWN_FC_FORMAT Fc;
- WWN_SAS_FORMAT Sas;
-} WWN_INBAND_FORMAT, MPI_POINTER PTR_WWN_INBAND_FORMAT,
- WwnInbandFormat, MPI_POINTER pWwnInbandFormat;
-
-
-/* Inband Buffer Post reply message */
-
-typedef struct _MSG_INBAND_BUFFER_POST_REPLY
-{
- U16 Reserved1; /* 00h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
- U32 TransferLength; /* 14h */
- U32 TransactionContext; /* 18h */
- WWN_INBAND_FORMAT Wwn; /* 1Ch */
- U32 IOCIdentifier[4]; /* 2Ch */
-} MSG_INBAND_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REPLY,
- MpiInbandBufferPostReply_t, MPI_POINTER pMpiInbandBufferPostReply_t;
-
-
-/****************************************************************************/
-/* Inband Send Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_SEND_REQUEST
-{
- U16 Reserved1; /* 00h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- WWN_INBAND_FORMAT Wwn; /* 10h */
- U32 Reserved5; /* 20h */
- SGE_IO_UNION SGL; /* 24h */
-} MSG_INBAND_SEND_REQUEST, MPI_POINTER PTR_MSG_INBAND_SEND_REQUEST,
- MpiInbandSendRequest_t , MPI_POINTER pMpiInbandSendRequest_t;
-
-
-/* Inband Send reply message */
-
-typedef struct _MSG_INBAND_SEND_REPLY
-{
- U16 Reserved1; /* 00h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
- U32 ResponseLength; /* 14h */
-} MSG_INBAND_SEND_REPLY, MPI_POINTER PTR_MSG_INBAND_SEND_REPLY,
- MpiInbandSendReply_t, MPI_POINTER pMpiInbandSendReply_t;
-
-
-/****************************************************************************/
-/* Inband Response Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_RSP_REQUEST
-{
- U16 Reserved1; /* 00h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- WWN_INBAND_FORMAT Wwn; /* 10h */
- U32 IOCIdentifier[4]; /* 20h */
- U32 ResponseLength; /* 30h */
- SGE_IO_UNION SGL; /* 34h */
-} MSG_INBAND_RSP_REQUEST, MPI_POINTER PTR_MSG_INBAND_RSP_REQUEST,
- MpiInbandRspRequest_t , MPI_POINTER pMpiInbandRspRequest_t;
-
-
-/* Inband Response reply message */
-
-typedef struct _MSG_INBAND_RSP_REPLY
-{
- U16 Reserved1; /* 00h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
-} MSG_INBAND_RSP_REPLY, MPI_POINTER PTR_MSG_INBAND_RSP_REPLY,
- MpiInbandRspReply_t, MPI_POINTER pMpiInbandRspReply_t;
-
-
-/****************************************************************************/
-/* Inband Abort Request */
-/****************************************************************************/
-
-typedef struct _MSG_INBAND_ABORT_REQUEST
-{
- U8 Reserved1; /* 00h */
- U8 AbortType; /* 01h */
- U8 ChainOffset; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U32 Reserved4; /* 0Ch */
- U32 ContextToAbort; /* 10h */
-} MSG_INBAND_ABORT_REQUEST, MPI_POINTER PTR_MSG_INBAND_ABORT_REQUEST,
- MpiInbandAbortRequest_t , MPI_POINTER pMpiInbandAbortRequest_t;
-
-#define MPI_INBAND_ABORT_TYPE_ALL_BUFFERS (0x00)
-#define MPI_INBAND_ABORT_TYPE_EXACT_BUFFER (0x01)
-#define MPI_INBAND_ABORT_TYPE_SEND_REQUEST (0x02)
-#define MPI_INBAND_ABORT_TYPE_RESPONSE_REQUEST (0x03)
-
-
-/* Inband Abort reply message */
-
-typedef struct _MSG_INBAND_ABORT_REPLY
-{
- U8 Reserved1; /* 00h */
- U8 AbortType; /* 01h */
- U8 MsgLength; /* 02h */
- U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
- U8 Reserved3; /* 06h */
- U8 MsgFlags; /* 07h */
- U32 MsgContext; /* 08h */
- U16 Reserved4; /* 0Ch */
- U16 IOCStatus; /* 0Eh */
- U32 IOCLogInfo; /* 10h */
-} MSG_INBAND_ABORT_REPLY, MPI_POINTER PTR_MSG_INBAND_ABORT_REPLY,
- MpiInbandAbortReply_t, MPI_POINTER pMpiInbandAbortReply_t;
-
-
-#endif
-
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index ec9dff2249a7..3a02615f12d6 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi_init.h
* Title: MPI initiator mode messages and structures
* Creation Date: June 8, 2000
*
- * mpi_init.h Version: 01.05.08
+ * mpi_init.h Version: 01.05.09
*
* Version History
* ---------------
@@ -54,6 +54,8 @@
* unique in the first 32 characters.
* 03-27-06 01.05.07 Added Task Management type of Clear ACA.
* 10-11-06 01.05.08 Shortened define for Task Management type of Clear ACA.
+ * 02-28-07 01.05.09 Defined two new MsgFlags bits for SCSI Task Management
+ * Request: Do Not Send Task IU and Soft Reset Option.
* --------------------------------------------------------------------------
*/
@@ -432,10 +434,14 @@ typedef struct _MSG_SCSI_TASK_MGMT
#define MPI_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
/* MsgFlags bits */
+#define MPI_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01)
+
#define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00)
#define MPI_SCSITASKMGMT_MSGFLAGS_LIP_RESET_OPTION (0x02)
#define MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION (0x04)
+#define MPI_SCSITASKMGMT_MSGFLAGS_SOFT_RESET_OPTION (0x08)
+
/* SCSI Task Management Reply */
typedef struct _MSG_SCSI_TASK_MGMT_REPLY
{
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index 6c33e3353375..b1893d185bc4 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2006 LSI Logic Corporation.
+ * Copyright (c) 2000-2007 LSI Logic Corporation.
*
*
* Name: mpi_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: August 11, 2000
*
- * mpi_ioc.h Version: 01.05.12
+ * mpi_ioc.h Version: 01.05.14
*
* Version History
* ---------------
@@ -106,6 +106,13 @@
* data structure.
* Added new ImageType values for FWDownload and FWUpload
* requests.
+ * 02-28-07 01.05.13 Added MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT for SAS
+ * Broadcast Event Data (replacing _RESERVED2).
+ * For Discovery Error Event Data DiscoveryStatus field,
+ * replaced _MULTPL_PATHS with _UNSUPPORTED_DEVICE and
+ * added _MULTI_PORT_DOMAIN.
+ * 05-24-07 01.05.14 Added Common Boot Block type to FWDownload Request.
+ * Added Common Boot Block type to FWUpload Request.
* --------------------------------------------------------------------------
*/
@@ -792,7 +799,7 @@ typedef struct _EVENT_DATA_SAS_BROADCAST_PRIMITIVE
#define MPI_EVENT_PRIMITIVE_CHANGE (0x01)
#define MPI_EVENT_PRIMITIVE_EXPANDER (0x03)
-#define MPI_EVENT_PRIMITIVE_RESERVED2 (0x04)
+#define MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04)
#define MPI_EVENT_PRIMITIVE_RESERVED3 (0x05)
#define MPI_EVENT_PRIMITIVE_RESERVED4 (0x06)
#define MPI_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07)
@@ -857,8 +864,9 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR
#define MPI_EVENT_DSCVRY_ERR_DS_SMP_CRC_ERROR (0x00000100)
#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_SUBTRACTIVE (0x00000200)
#define MPI_EVENT_DSCVRY_ERR_DS_TABLE_TO_TABLE (0x00000400)
-#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800)
+#define MPI_EVENT_DSCVRY_ERR_DS_UNSUPPORTED_DEVICE (0x00000800)
#define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000)
+#define MPI_EVENT_DSCVRY_ERR_DS_MULTI_PORT_DOMAIN (0x00002000)
/* SAS SMP Error Event data */
@@ -990,6 +998,7 @@ typedef struct _MSG_FW_DOWNLOAD
#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07)
#define MPI_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08)
#define MPI_FW_DOWNLOAD_ITYPE_MEGARAID (0x09)
+#define MPI_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
typedef struct _FWDownloadTCSGE
@@ -1038,17 +1047,18 @@ typedef struct _MSG_FW_UPLOAD
} MSG_FW_UPLOAD, MPI_POINTER PTR_MSG_FW_UPLOAD,
FWUpload_t, MPI_POINTER pFWUpload_t;
-#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00)
-#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01)
-#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02)
-#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03)
-#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04)
-#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05)
-#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING (0x06)
-#define MPI_FW_UPLOAD_ITYPE_CONFIG_1 (0x07)
-#define MPI_FW_UPLOAD_ITYPE_CONFIG_2 (0x08)
-#define MPI_FW_UPLOAD_ITYPE_MEGARAID (0x09)
-#define MPI_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
+#define MPI_FW_UPLOAD_ITYPE_FW_IOC_MEM (0x00)
+#define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01)
+#define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02)
+#define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03)
+#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04)
+#define MPI_FW_UPLOAD_ITYPE_FW_BACKUP (0x05)
+#define MPI_FW_UPLOAD_ITYPE_MANUFACTURING (0x06)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_1 (0x07)
+#define MPI_FW_UPLOAD_ITYPE_CONFIG_2 (0x08)
+#define MPI_FW_UPLOAD_ITYPE_MEGARAID (0x09)
+#define MPI_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
+#define MPI_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
typedef struct _FWUploadTCSGE
{
diff --git a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h
index 802255d2747c..32819b1ec8ec 100644
--- a/drivers/message/fusion/lsi/mpi_raid.h
+++ b/drivers/message/fusion/lsi/mpi_raid.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2001-2005 LSI Logic Corporation.
+ * Copyright (c) 2001-2007 LSI Logic Corporation.
*
*
* Name: mpi_raid.h
* Title: MPI RAID message and structures
* Creation Date: February 27, 2001
*
- * mpi_raid.h Version: 01.05.02
+ * mpi_raid.h Version: 01.05.03
*
* Version History
* ---------------
@@ -32,6 +32,8 @@
* 08-19-04 01.05.01 Original release for MPI v1.5.
* 01-15-05 01.05.02 Added defines for the two new RAID Actions for
* _SET_RESYNC_RATE and _SET_DATA_SCRUB_RATE.
+ * 02-28-07 01.05.03 Added new RAID Action, Device FW Update Mode, and
+ * associated defines.
* --------------------------------------------------------------------------
*/
@@ -90,6 +92,7 @@ typedef struct _MSG_RAID_ACTION
#define MPI_RAID_ACTION_INACTIVATE_VOLUME (0x12)
#define MPI_RAID_ACTION_SET_RESYNC_RATE (0x13)
#define MPI_RAID_ACTION_SET_DATA_SCRUB_RATE (0x14)
+#define MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15)
/* ActionDataWord defines for use with MPI_RAID_ACTION_CREATE_VOLUME action */
#define MPI_RAID_ACTION_ADATA_DO_NOT_SYNC (0x00000001)
@@ -111,6 +114,10 @@ typedef struct _MSG_RAID_ACTION
/* ActionDataWord defines for use with MPI_RAID_ACTION_SET_DATA_SCRUB_RATE action */
#define MPI_RAID_ACTION_ADATA_DATA_SCRUB_RATE_MASK (0x000000FF)
+/* ActionDataWord defines for use with MPI_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */
+#define MPI_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x00000001)
+#define MPI_RAID_ACTION_ADATA_MASK_FW_UPDATE_TIMEOUT (0x0000FF00)
+#define MPI_RAID_ACTION_ADATA_SHIFT_FW_UPDATE_TIMEOUT (8)
/* RAID Action reply message */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5021d1a2a1d4..04f75e24dcec 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -64,6 +64,7 @@
#endif
#include "mptbase.h"
+#include "lsi/mpi_log_fc.h"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define my_NAME "Fusion MPT base driver"
@@ -160,6 +161,7 @@ static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum);
static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
static void mpt_timer_expired(unsigned long data);
+static void mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
@@ -1130,6 +1132,248 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp)
return -1;
}
+/**
+ * mpt_get_product_name - returns product string
+ * @vendor: pci vendor id
+ * @device: pci device id
+ * @revision: pci revision id
+ * @prod_name: string returned
+ *
+ * Returns product string displayed when driver loads,
+ * in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
+ *
+ **/
+static void
+mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
+{
+ char *product_str = NULL;
+
+ if (vendor == PCI_VENDOR_ID_BROCADE) {
+ switch (device)
+ {
+ case MPI_MANUFACTPAGE_DEVICEID_FC949E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "BRE040 A0";
+ break;
+ case 0x01:
+ product_str = "BRE040 A1";
+ break;
+ default:
+ product_str = "BRE040";
+ break;
+ }
+ break;
+ }
+ goto out;
+ }
+
+ switch (device)
+ {
+ case MPI_MANUFACTPAGE_DEVICEID_FC909:
+ product_str = "LSIFC909 B1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC919:
+ product_str = "LSIFC919 B0";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC929:
+ product_str = "LSIFC929 B0";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC919X:
+ if (revision < 0x80)
+ product_str = "LSIFC919X A0";
+ else
+ product_str = "LSIFC919XL A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC929X:
+ if (revision < 0x80)
+ product_str = "LSIFC929X A0";
+ else
+ product_str = "LSIFC929XL A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC939X:
+ product_str = "LSIFC939X A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC949X:
+ product_str = "LSIFC949X A1";
+ break;
+ case MPI_MANUFACTPAGE_DEVICEID_FC949E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSIFC949E A0";
+ break;
+ case 0x01:
+ product_str = "LSIFC949E A1";
+ break;
+ default:
+ product_str = "LSIFC949E";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_53C1030:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSI53C1030 A0";
+ break;
+ case 0x01:
+ product_str = "LSI53C1030 B0";
+ break;
+ case 0x03:
+ product_str = "LSI53C1030 B1";
+ break;
+ case 0x07:
+ product_str = "LSI53C1030 B2";
+ break;
+ case 0x08:
+ product_str = "LSI53C1030 C0";
+ break;
+ case 0x80:
+ product_str = "LSI53C1030T A0";
+ break;
+ case 0x83:
+ product_str = "LSI53C1030T A2";
+ break;
+ case 0x87:
+ product_str = "LSI53C1030T A3";
+ break;
+ case 0xc1:
+ product_str = "LSI53C1020A A1";
+ break;
+ default:
+ product_str = "LSI53C1030";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
+ switch (revision)
+ {
+ case 0x03:
+ product_str = "LSI53C1035 A2";
+ break;
+ case 0x04:
+ product_str = "LSI53C1035 B0";
+ break;
+ default:
+ product_str = "LSI53C1035";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1064:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1064 A1";
+ break;
+ case 0x01:
+ product_str = "LSISAS1064 A2";
+ break;
+ case 0x02:
+ product_str = "LSISAS1064 A3";
+ break;
+ case 0x03:
+ product_str = "LSISAS1064 A4";
+ break;
+ default:
+ product_str = "LSISAS1064";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1064E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1064E A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1064E B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1064E B1";
+ break;
+ case 0x04:
+ product_str = "LSISAS1064E B2";
+ break;
+ case 0x08:
+ product_str = "LSISAS1064E B3";
+ break;
+ default:
+ product_str = "LSISAS1064E";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1068:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1068 A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1068 B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1068 B1";
+ break;
+ default:
+ product_str = "LSISAS1068";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1068E:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1068E A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1068E B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1068E B1";
+ break;
+ case 0x04:
+ product_str = "LSISAS1068E B2";
+ break;
+ case 0x08:
+ product_str = "LSISAS1068E B3";
+ break;
+ default:
+ product_str = "LSISAS1068E";
+ break;
+ }
+ break;
+ case MPI_MANUFACTPAGE_DEVID_SAS1078:
+ switch (revision)
+ {
+ case 0x00:
+ product_str = "LSISAS1078 A0";
+ break;
+ case 0x01:
+ product_str = "LSISAS1078 B0";
+ break;
+ case 0x02:
+ product_str = "LSISAS1078 C0";
+ break;
+ case 0x03:
+ product_str = "LSISAS1078 C1";
+ break;
+ case 0x04:
+ product_str = "LSISAS1078 C2";
+ break;
+ default:
+ product_str = "LSISAS1078";
+ break;
+ }
+ break;
+ }
+
+ out:
+ if (product_str)
+ sprintf(prod_name, "%s", product_str);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* mpt_attach - Install a PCI intelligent MPT adapter.
@@ -1273,23 +1517,23 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
}
- if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
- ioc->prod_name = "LSIFC909";
- ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
- ioc->prod_name = "LSIFC929";
- ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
- ioc->prod_name = "LSIFC919";
- ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+ mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
+
+ switch (pdev->device)
+ {
+ case MPI_MANUFACTPAGE_DEVICEID_FC939X:
+ case MPI_MANUFACTPAGE_DEVICEID_FC949X:
+ ioc->errata_flag_1064 = 1;
+ case MPI_MANUFACTPAGE_DEVICEID_FC909:
+ case MPI_MANUFACTPAGE_DEVICEID_FC929:
+ case MPI_MANUFACTPAGE_DEVICEID_FC919:
+ case MPI_MANUFACTPAGE_DEVICEID_FC949E:
ioc->bus_type = FC;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVICEID_FC929X:
if (revision < XL_929) {
- ioc->prod_name = "LSIFC929X";
/* 929X Chip Fix. Set Split transactions level
* for PCIX. Set MOST bits to zero.
*/
@@ -1297,75 +1541,46 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
pcixcmd &= 0x8F;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
} else {
- ioc->prod_name = "LSIFC929XL";
/* 929XL Chip Fix. Set MMRBC to 0x08.
*/
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
pcixcmd |= 0x08;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
}
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
- ioc->prod_name = "LSIFC919X";
ioc->bus_type = FC;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVICEID_FC919X:
/* 919X Chip Fix. Set Split transactions level
* for PCIX. Set MOST bits to zero.
*/
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
pcixcmd &= 0x8F;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
- ioc->prod_name = "LSIFC939X";
- ioc->bus_type = FC;
- ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
- ioc->prod_name = "LSIFC949X";
- ioc->bus_type = FC;
- ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
- ioc->prod_name = "LSIFC949E";
ioc->bus_type = FC;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
- ioc->prod_name = "LSI53C1030";
- ioc->bus_type = SPI;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVID_53C1030:
/* 1030 Chip Fix. Disable Split transactions
* for PCIX. Set MOST bits to zero if Rev < C0( = 8).
*/
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
if (revision < C0_1030) {
pci_read_config_byte(pdev, 0x6a, &pcixcmd);
pcixcmd &= 0x8F;
pci_write_config_byte(pdev, 0x6a, pcixcmd);
}
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
- ioc->prod_name = "LSI53C1035";
+
+ case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
ioc->bus_type = SPI;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
- ioc->prod_name = "LSISAS1064";
- ioc->bus_type = SAS;
- ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
- ioc->prod_name = "LSISAS1068";
- ioc->bus_type = SAS;
+ break;
+
+ case MPI_MANUFACTPAGE_DEVID_SAS1064:
+ case MPI_MANUFACTPAGE_DEVID_SAS1068:
ioc->errata_flag_1064 = 1;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
- ioc->prod_name = "LSISAS1064E";
- ioc->bus_type = SAS;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
- ioc->prod_name = "LSISAS1068E";
- ioc->bus_type = SAS;
- }
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
- ioc->prod_name = "LSISAS1078";
+
+ case MPI_MANUFACTPAGE_DEVID_SAS1064E:
+ case MPI_MANUFACTPAGE_DEVID_SAS1068E:
+ case MPI_MANUFACTPAGE_DEVID_SAS1078:
ioc->bus_type = SAS;
}
@@ -1879,6 +2094,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
}
GetIoUnitPage2(ioc);
+ mpt_get_manufacturing_pg_0(ioc);
}
/*
@@ -2137,8 +2353,8 @@ MptDisplayIocCapabilities(MPT_ADAPTER *ioc)
int i = 0;
printk(KERN_INFO "%s: ", ioc->name);
- if (ioc->prod_name && strlen(ioc->prod_name) > 3)
- printk("%s: ", ioc->prod_name+3);
+ if (ioc->prod_name)
+ printk("%s: ", ioc->prod_name);
printk("Capabilities={");
if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
@@ -5189,6 +5405,49 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc)
return;
}
+static void
+mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
+{
+ CONFIGPARMS cfg;
+ ConfigPageHeader_t hdr;
+ dma_addr_t buf_dma;
+ ManufacturingPage0_t *pbuf = NULL;
+
+ memset(&cfg, 0 , sizeof(CONFIGPARMS));
+ memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+ hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+ cfg.cfghdr.hdr = &hdr;
+ cfg.physAddr = -1;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.timeout = 10;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ if (!cfg.cfghdr.hdr->PageLength)
+ goto out;
+
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+ pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+ if (!pbuf)
+ goto out;
+
+ cfg.physAddr = buf_dma;
+
+ if (mpt_config(ioc, &cfg) != 0)
+ goto out;
+
+ memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
+ memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
+ memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
+
+ out:
+
+ if (pbuf)
+ pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/**
* SendEventNotification - Send EventNotification (on or off) request to adapter
@@ -6349,14 +6608,37 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
static void
mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
{
- static char *subcl_str[8] = {
- "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer",
- "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info"
- };
- u8 subcl = (log_info >> 24) & 0x7;
+ char *desc = "unknown";
+
+ switch (log_info & 0xFF000000) {
+ case MPI_IOCLOGINFO_FC_INIT_BASE:
+ desc = "FCP Initiator";
+ break;
+ case MPI_IOCLOGINFO_FC_TARGET_BASE:
+ desc = "FCP Target";
+ break;
+ case MPI_IOCLOGINFO_FC_LAN_BASE:
+ desc = "LAN";
+ break;
+ case MPI_IOCLOGINFO_FC_MSG_BASE:
+ desc = "MPI Message Layer";
+ break;
+ case MPI_IOCLOGINFO_FC_LINK_BASE:
+ desc = "FC Link";
+ break;
+ case MPI_IOCLOGINFO_FC_CTX_BASE:
+ desc = "Context Manager";
+ break;
+ case MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET:
+ desc = "Invalid Field Offset";
+ break;
+ case MPI_IOCLOGINFO_FC_STATE_CHANGE:
+ desc = "State Change Info";
+ break;
+ }
- printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}\n",
- ioc->name, log_info, subcl_str[subcl]);
+ printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubClass={%s}, Value=(0x%06x)\n",
+ ioc->name, log_info, desc, (log_info & 0xFFFFFF));
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 165f81d16d00..98eb9c688e17 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -75,8 +75,8 @@
#define COPYRIGHT "Copyright (c) 1999-2007 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.04.04"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.04"
+#define MPT_LINUX_VERSION_COMMON "3.04.05"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.05"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -537,7 +537,14 @@ typedef struct _MPT_ADAPTER
int id; /* Unique adapter id N {0,1,2,...} */
int pci_irq; /* This irq */
char name[MPT_NAME_LENGTH]; /* "iocN" */
- char *prod_name; /* "LSIFC9x9" */
+ char prod_name[MPT_NAME_LENGTH]; /* "LSIFC9x9" */
+ char board_name[16];
+ char board_assembly[16];
+ char board_tracer[16];
+ u16 nvdata_version_persistent;
+ u16 nvdata_version_default;
+ u8 io_missing_delay;
+ u8 device_missing_delay;
SYSIF_REGS __iomem *chip; /* == c8817000 (mmap) */
SYSIF_REGS __iomem *pio_chip; /* Programmed IO (downloadboot) */
u8 bus_type;
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 9d0f30478e46..58e6c319cc76 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -5,7 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index f7e72c5e47de..180b3c156247 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index 0caaf6403993..f2ebaa9992fe 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -43,7 +43,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include "linux_compat.h" /* linux-2.6 tweaks */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -131,6 +130,7 @@ static struct scsi_host_template mptfc_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mptscsih_host_attrs,
};
/****************************************************************************
@@ -154,6 +154,8 @@ static struct pci_device_id mptfc_pci_table[] = {
PCI_ANY_ID, PCI_ANY_ID },
{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,
PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_VENDOR_ID_BROCADE, MPI_MANUFACTPAGE_DEVICEID_FC949E,
+ PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 7dd34bd28efc..7e8a90cb484e 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -5,7 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 2000-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h
index fe438bf119f6..8d08c2bed24a 100644
--- a/drivers/message/fusion/mptlan.h
+++ b/drivers/message/fusion/mptlan.h
@@ -5,7 +5,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 2000-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 1d2d03f77894..d50664640512 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
* Copyright (c) 2005-2007 Dell
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1119,6 +1119,7 @@ static struct scsi_host_template mptsas_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mptscsih_host_attrs,
};
static int mptsas_get_linkerrors(struct sas_phy *phy)
@@ -1390,6 +1391,11 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
goto out_free_consistent;
}
+ ioc->nvdata_version_persistent =
+ le16_to_cpu(buffer->NvdataVersionPersistent);
+ ioc->nvdata_version_default =
+ le16_to_cpu(buffer->NvdataVersionDefault);
+
for (i = 0; i < port_info->num_phys; i++) {
mptsas_print_phy_data(&buffer->PhyData[i]);
port_info->phy_info[i].phy_id = i;
@@ -1410,6 +1416,63 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
}
static int
+mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
+{
+ ConfigExtendedPageHeader_t hdr;
+ CONFIGPARMS cfg;
+ SasIOUnitPage1_t *buffer;
+ dma_addr_t dma_handle;
+ int error;
+ u16 device_missing_delay;
+
+ memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
+ memset(&cfg, 0, sizeof(CONFIGPARMS));
+
+ cfg.cfghdr.ehdr = &hdr;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+ cfg.timeout = 10;
+ cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+ cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+ cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
+ cfg.cfghdr.ehdr->PageNumber = 1;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+ goto out;
+ if (!hdr.ExtPageLength) {
+ error = -ENXIO;
+ goto out;
+ }
+
+ buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+ &dma_handle);
+ if (!buffer) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ cfg.physAddr = dma_handle;
+ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+ error = mpt_config(ioc, &cfg);
+ if (error)
+ goto out_free_consistent;
+
+ ioc->io_missing_delay =
+ le16_to_cpu(buffer->IODeviceMissingDelay);
+ device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
+ ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
+ (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
+ device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+
+ out_free_consistent:
+ pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+ buffer, dma_handle);
+ out:
+ return error;
+}
+
+static int
mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
u32 form, u32 form_specific)
{
@@ -1990,6 +2053,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
if (error)
goto out_free_port_info;
+ mptsas_sas_io_unit_pg1(ioc);
mutex_lock(&ioc->sas_topology_mutex);
ioc->handle = hba->phy_info[0].handle;
port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
@@ -3237,6 +3301,8 @@ static struct pci_driver mptsas_driver = {
static int __init
mptsas_init(void)
{
+ int error;
+
show_mptmod_ver(my_NAME, my_VERSION);
mptsas_transport_template =
@@ -3260,7 +3326,11 @@ mptsas_init(void)
": Registered for IOC reset notifications\n"));
}
- return pci_register_driver(&mptsas_driver);
+ error = pci_register_driver(&mptsas_driver);
+ if (error)
+ sas_release_transport(mptsas_transport_template);
+
+ return error;
}
static void __exit
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 3bd94f11e7d6..fd3aa2619f42 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -44,7 +44,6 @@
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include "linux_compat.h" /* linux-2.6 tweaks */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -260,30 +259,13 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt,
/* Map the data portion, if any.
* sges_left = 0 if no data transfer.
*/
- if ( (sges_left = SCpnt->use_sg) ) {
- sges_left = pci_map_sg(ioc->pcidev,
- (struct scatterlist *) SCpnt->request_buffer,
- SCpnt->use_sg,
- SCpnt->sc_data_direction);
- if (sges_left == 0)
- return FAILED;
- } else if (SCpnt->request_bufflen) {
- SCpnt->SCp.dma_handle = pci_map_single(ioc->pcidev,
- SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- dsgprintk((MYIOC_s_INFO_FMT "SG: non-SG for %p, len=%d\n",
- ioc->name, SCpnt, SCpnt->request_bufflen));
- mptscsih_add_sge((char *) &pReq->SGL,
- 0xD1000000|MPT_SGE_FLAGS_ADDRESSING|sgdir|SCpnt->request_bufflen,
- SCpnt->SCp.dma_handle);
-
- return SUCCESS;
- }
+ sges_left = scsi_dma_map(SCpnt);
+ if (sges_left < 0)
+ return FAILED;
/* Handle the SG case.
*/
- sg = (struct scatterlist *) SCpnt->request_buffer;
+ sg = scsi_sglist(SCpnt);
sg_done = 0;
sgeOffset = sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION);
chainSge = NULL;
@@ -465,7 +447,12 @@ mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
MPT_FRAME_HDR *mf;
SEPRequest_t *SEPMsg;
- if (ioc->bus_type == FC)
+ if (ioc->bus_type != SAS)
+ return;
+
+ /* Not supported for hidden raid components
+ */
+ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
return;
if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
@@ -662,7 +649,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
scsi_state = pScsiReply->SCSIState;
scsi_status = pScsiReply->SCSIStatus;
xfer_cnt = le32_to_cpu(pScsiReply->TransferCount);
- sc->resid = sc->request_bufflen - xfer_cnt;
+ scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
log_info = le32_to_cpu(pScsiReply->IOCLogInfo);
/*
@@ -767,7 +754,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
break;
case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
- sc->resid = sc->request_bufflen - xfer_cnt;
+ scsi_set_resid(sc, scsi_bufflen(sc) - xfer_cnt);
if((xfer_cnt==0)||(sc->underflow > xfer_cnt))
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
@@ -816,7 +803,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
break;
case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
- sc->resid=0;
+ scsi_set_resid(sc, 0);
case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */
case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */
sc->result = (DID_OK << 16) | scsi_status;
@@ -899,23 +886,18 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
scsi_state, scsi_status, log_info));
dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
- "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
- sc->device->host->host_no, sc->device->channel, sc->device->id,
- sc->device->lun, sc->resid, sc->request_bufflen,
- xfer_cnt));
+ "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
+ sc->device->host->host_no,
+ sc->device->channel, sc->device->id,
+ sc->device->lun, scsi_get_resid(sc),
+ scsi_bufflen(sc), xfer_cnt));
}
#endif
} /* end of address reply case */
/* Unmap the DMA buffers, if any. */
- if (sc->use_sg) {
- pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer,
- sc->use_sg, sc->sc_data_direction);
- } else if (sc->request_bufflen) {
- pci_unmap_single(ioc->pcidev, sc->SCp.dma_handle,
- sc->request_bufflen, sc->sc_data_direction);
- }
+ scsi_dma_unmap(sc);
sc->scsi_done(sc); /* Issue the command callback */
@@ -970,17 +952,8 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
/* Set status, free OS resources (SG DMA buffers)
* Do OS callback
*/
- if (SCpnt->use_sg) {
- pci_unmap_sg(ioc->pcidev,
- (struct scatterlist *) SCpnt->request_buffer,
- SCpnt->use_sg,
- SCpnt->sc_data_direction);
- } else if (SCpnt->request_bufflen) {
- pci_unmap_single(ioc->pcidev,
- SCpnt->SCp.dma_handle,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- }
+ scsi_dma_unmap(SCpnt);
+
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
@@ -1023,14 +996,19 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
if (mf == NULL)
continue;
+ /* If the device is a hidden raid component, then its
+ * expected that the mf->function will be RAID_SCSI_IO
+ */
+ if (vdevice->vtarget->tflags &
+ MPT_TARGET_FLAGS_RAID_COMPONENT && mf->Function !=
+ MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)
+ continue;
+
int_to_scsilun(vdevice->lun, &lun);
if ((mf->Bus != vdevice->vtarget->channel) ||
(mf->TargetID != vdevice->vtarget->id) ||
memcmp(lun.scsi_lun, mf->LUN, 8))
continue;
- dsprintk(( "search_running: found (sc=%p, mf = %p) "
- "channel %d id %d, lun %d \n", hd->ScsiLookup[ii],
- mf, mf->Bus, mf->TargetID, vdevice->lun));
/* Cleanup
*/
@@ -1039,19 +1017,12 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
if ((unsigned char *)mf != sc->host_scribble)
continue;
- if (sc->use_sg) {
- pci_unmap_sg(hd->ioc->pcidev,
- (struct scatterlist *) sc->request_buffer,
- sc->use_sg,
- sc->sc_data_direction);
- } else if (sc->request_bufflen) {
- pci_unmap_single(hd->ioc->pcidev,
- sc->SCp.dma_handle,
- sc->request_bufflen,
- sc->sc_data_direction);
- }
+ scsi_dma_unmap(sc);
sc->host_scribble = NULL;
sc->result = DID_NO_CONNECT << 16;
+ dsprintk(( "search_running: found (sc=%p, mf = %p) "
+ "channel %d id %d, lun %d \n", sc, mf,
+ vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun));
sc->scsi_done(sc);
}
}
@@ -1380,10 +1351,10 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
* will be no data transfer! GRRRRR...
*/
if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
- datalen = SCpnt->request_bufflen;
+ datalen = scsi_bufflen(SCpnt);
scsidir = MPI_SCSIIO_CONTROL_READ; /* DATA IN (host<--ioc<--dev) */
} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
- datalen = SCpnt->request_bufflen;
+ datalen = scsi_bufflen(SCpnt);
scsidir = MPI_SCSIIO_CONTROL_WRITE; /* DATA OUT (host-->ioc-->dev) */
} else {
datalen = 0;
@@ -1768,20 +1739,45 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
u32 ctx2abort;
int scpnt_idx;
int retval;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
ulong sn = SCpnt->serial_number;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
SCpnt->result = DID_RESET << 16;
SCpnt->scsi_done(SCpnt);
- dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: "
- "Can't locate host! (sc=%p)\n",
- SCpnt));
+ dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
+ "host! (sc=%p)\n", SCpnt));
return FAILED;
}
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting task abort! (sc=%p)\n",
+ ioc->name, SCpnt);
+ scsi_print_command(SCpnt);
+
+ vdevice = SCpnt->device->hostdata;
+ if (!vdevice || !vdevice->vtarget) {
+ dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
+ "deleted (sc=%p)\n", ioc->name, SCpnt));
+ SCpnt->result = DID_NO_CONNECT << 16;
+ SCpnt->scsi_done(SCpnt);
+ retval = 0;
+ goto out;
+ }
+
+ /* Task aborts are not supported for hidden raid components.
+ */
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+ dtmprintk((MYIOC_s_DEBUG_FMT "task abort: hidden raid "
+ "component (sc=%p)\n", ioc->name, SCpnt));
+ SCpnt->result = DID_RESET << 16;
+ retval = FAILED;
+ goto out;
+ }
+
/* Find this command
*/
if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) {
@@ -1790,21 +1786,20 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
*/
SCpnt->result = DID_RESET << 16;
dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
- "Command not in the active list! (sc=%p)\n",
- hd->ioc->name, SCpnt));
- return SUCCESS;
+ "Command not in the active list! (sc=%p)\n", ioc->name,
+ SCpnt));
+ retval = 0;
+ goto out;
}
- if (hd->resetPending)
- return FAILED;
+ if (hd->resetPending) {
+ retval = FAILED;
+ goto out;
+ }
if (hd->timeouts < -1)
hd->timeouts++;
- printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n",
- hd->ioc->name, SCpnt);
- scsi_print_command(SCpnt);
-
/* Most important! Set TaskMsgContext to SCpnt's MsgContext!
* (the IO to be ABORT'd)
*
@@ -1817,18 +1812,17 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
hd->abortSCpnt = SCpnt;
- vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK,
- vdev->vtarget->channel, vdev->vtarget->id, vdev->lun,
- ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
+ vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun,
+ ctx2abort, mptscsih_get_tm_timeout(ioc));
if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
SCpnt->serial_number == sn)
retval = FAILED;
- printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
- hd->ioc->name,
- ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+ out:
+ printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
if (retval == 0)
return SUCCESS;
@@ -1850,32 +1844,47 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt)
{
MPT_SCSI_HOST *hd;
int retval;
- VirtDevice *vdev;
+ VirtDevice *vdevice;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: "
- "Can't locate host! (sc=%p)\n",
- SCpnt));
+ dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt));
return FAILED;
}
- if (hd->resetPending)
- return FAILED;
-
- printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n",
- hd->ioc->name, SCpnt);
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting target reset! (sc=%p)\n",
+ ioc->name, SCpnt);
scsi_print_command(SCpnt);
- vdev = SCpnt->device->hostdata;
+ if (hd->resetPending) {
+ retval = FAILED;
+ goto out;
+ }
+
+ vdevice = SCpnt->device->hostdata;
+ if (!vdevice || !vdevice->vtarget) {
+ retval = 0;
+ goto out;
+ }
+
+ /* Target reset to hidden raid component is not supported
+ */
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
+ retval = FAILED;
+ goto out;
+ }
+
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
- vdev->vtarget->channel, vdev->vtarget->id,
- 0, 0, mptscsih_get_tm_timeout(hd->ioc));
+ vdevice->vtarget->channel, vdevice->vtarget->id, 0, 0,
+ mptscsih_get_tm_timeout(ioc));
- printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n",
- hd->ioc->name,
- ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+ out:
+ printk (MYIOC_s_INFO_FMT "target reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
if (retval == 0)
return SUCCESS;
@@ -1899,18 +1908,19 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
MPT_SCSI_HOST *hd;
int retval;
VirtDevice *vdev;
+ MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
*/
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: "
- "Can't locate host! (sc=%p)\n",
- SCpnt ) );
+ dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt ));
return FAILED;
}
- printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n",
- hd->ioc->name, SCpnt);
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting bus reset! (sc=%p)\n",
+ ioc->name, SCpnt);
scsi_print_command(SCpnt);
if (hd->timeouts < -1)
@@ -1918,11 +1928,10 @@ mptscsih_bus_reset(struct scsi_cmnd * SCpnt)
vdev = SCpnt->device->hostdata;
retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS,
- vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(hd->ioc));
+ vdev->vtarget->channel, 0, 0, 0, mptscsih_get_tm_timeout(ioc));
- printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n",
- hd->ioc->name,
- ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
+ printk(MYIOC_s_INFO_FMT "bus reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
if (retval == 0)
return SUCCESS;
@@ -1943,37 +1952,38 @@ int
mptscsih_host_reset(struct scsi_cmnd *SCpnt)
{
MPT_SCSI_HOST * hd;
- int status = SUCCESS;
+ int retval;
+ MPT_ADAPTER *ioc;
/* If we can't locate the host to reset, then we failed. */
if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
- dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
- "Can't locate host! (sc=%p)\n",
- SCpnt ) );
+ dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
+ "locate host! (sc=%p)\n", SCpnt));
return FAILED;
}
- printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n",
- hd->ioc->name, SCpnt);
+ ioc = hd->ioc;
+ printk(MYIOC_s_INFO_FMT "attempting host reset! (sc=%p)\n",
+ ioc->name, SCpnt);
/* If our attempts to reset the host failed, then return a failed
* status. The host will be taken off line by the SCSI mid-layer.
*/
- if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){
- status = FAILED;
+ if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0) {
+ retval = FAILED;
} else {
/* Make sure TM pending is cleared and TM state is set to
* NONE.
*/
+ retval = 0;
hd->tmPending = 0;
hd->tmState = TM_STATE_NONE;
}
- dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: "
- "Status = %s\n",
- (status == SUCCESS) ? "SUCCESS" : "FAILED" ) );
+ printk(MYIOC_s_INFO_FMT "host reset: %s (sc=%p)\n",
+ ioc->name, ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
- return status;
+ return retval;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -3150,6 +3160,16 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
{
INTERNAL_CMD iocmd;
+ /* Ignore hidden raid components, this is handled when the command
+ * is sent to the volume
+ */
+ if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
+ return;
+
+ if (vdevice->vtarget->type != TYPE_DISK || vdevice->vtarget->deleted ||
+ !vdevice->configured_lun)
+ return;
+
/* Following parameters will not change
* in this routine.
*/
@@ -3164,11 +3184,162 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
iocmd.id = vdevice->vtarget->id;
iocmd.lun = vdevice->lun;
- if ((vdevice->vtarget->type == TYPE_DISK) &&
- (vdevice->configured_lun))
- mptscsih_do_cmd(hd, &iocmd);
+ mptscsih_do_cmd(hd, &iocmd);
}
+static ssize_t
+mptscsih_version_fw_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
+ (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+ (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+ (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+ ioc->facts.FWVersion.Word & 0x000000FF);
+}
+static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
+
+static ssize_t
+mptscsih_version_bios_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+ (ioc->biosVersion & 0xFF000000) >> 24,
+ (ioc->biosVersion & 0x00FF0000) >> 16,
+ (ioc->biosVersion & 0x0000FF00) >> 8,
+ ioc->biosVersion & 0x000000FF);
+}
+static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
+
+static ssize_t
+mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
+}
+static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
+
+static ssize_t
+mptscsih_version_product_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
+}
+static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
+ mptscsih_version_product_show, NULL);
+
+static ssize_t
+mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02xh\n",
+ ioc->nvdata_version_persistent);
+}
+static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
+ mptscsih_version_nvdata_persistent_show, NULL);
+
+static ssize_t
+mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
+}
+static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
+ mptscsih_version_nvdata_default_show, NULL);
+
+static ssize_t
+mptscsih_board_name_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
+}
+static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
+
+static ssize_t
+mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
+}
+static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
+ mptscsih_board_assembly_show, NULL);
+
+static ssize_t
+mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
+}
+static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
+ mptscsih_board_tracer_show, NULL);
+
+static ssize_t
+mptscsih_io_delay_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
+}
+static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
+ mptscsih_io_delay_show, NULL);
+
+static ssize_t
+mptscsih_device_delay_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ MPT_ADAPTER *ioc = hd->ioc;
+
+ return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
+}
+static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
+ mptscsih_device_delay_show, NULL);
+
+struct class_device_attribute *mptscsih_host_attrs[] = {
+ &class_device_attr_version_fw,
+ &class_device_attr_version_bios,
+ &class_device_attr_version_mpi,
+ &class_device_attr_version_product,
+ &class_device_attr_version_nvdata_persistent,
+ &class_device_attr_version_nvdata_default,
+ &class_device_attr_board_name,
+ &class_device_attr_board_assembly,
+ &class_device_attr_board_tracer,
+ &class_device_attr_io_delay,
+ &class_device_attr_device_delay,
+ NULL,
+};
+EXPORT_SYMBOL(mptscsih_host_attrs);
+
EXPORT_SYMBOL(mptscsih_remove);
EXPORT_SYMBOL(mptscsih_shutdown);
#ifdef CONFIG_PM
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 843c01a6aa0e..67b088db2f10 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -6,7 +6,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -129,3 +129,4 @@ extern void mptscsih_timer_expired(unsigned long data);
extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
+extern struct class_device_attribute *mptscsih_host_attrs[];
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 37bf65348372..947fe2901800 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -4,7 +4,7 @@
* running LSI Logic Fusion MPT (Message Passing Technology) firmware.
*
* Copyright (c) 1999-2007 LSI Logic Corporation
- * (mailto:mpt_linux_developer@lsi.com)
+ * (mailto:DL-MPTFusionLinux@lsi.com)
*
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -44,7 +44,6 @@
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include "linux_compat.h" /* linux-2.6 tweaks */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -822,6 +821,7 @@ static struct scsi_host_template mptspi_driver_template = {
.max_sectors = 8192,
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mptscsih_host_attrs,
};
static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
@@ -1524,6 +1524,8 @@ static struct pci_driver mptspi_driver = {
static int __init
mptspi_init(void)
{
+ int error;
+
show_mptmod_ver(my_NAME, my_VERSION);
mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions);
@@ -1544,7 +1546,11 @@ mptspi_init(void)
": Registered for IOC reset notifications\n"));
}
- return pci_register_driver(&mptspi_driver);
+ error = pci_register_driver(&mptspi_driver);
+ if (error)
+ spi_release_transport(mptspi_transport_template);
+
+ return error;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig
index f4ac21e5771e..5afa0e393ecf 100644
--- a/drivers/message/i2o/Kconfig
+++ b/drivers/message/i2o/Kconfig
@@ -1,9 +1,6 @@
-menu "I2O device support"
- depends on PCI
-
-config I2O
- tristate "I2O support"
+menuconfig I2O
+ tristate "I2O device support"
depends on PCI
---help---
The Intelligent Input/Output (I2O) architecture allows hardware
@@ -25,9 +22,10 @@ config I2O
If unsure, say N.
+if I2O
+
config I2O_LCT_NOTIFY_ON_CHANGES
bool "Enable LCT notification"
- depends on I2O
default y
---help---
Only say N here if you have a I2O controller from SUN. The SUN
@@ -39,7 +37,6 @@ config I2O_LCT_NOTIFY_ON_CHANGES
config I2O_EXT_ADAPTEC
bool "Enable Adaptec extensions"
- depends on I2O
default y
---help---
Say Y for support of raidutils for Adaptec I2O controllers. You also
@@ -57,7 +54,7 @@ config I2O_EXT_ADAPTEC_DMA64
config I2O_CONFIG
tristate "I2O Configuration support"
- depends on I2O
+ depends on VIRT_TO_BUS
---help---
Say Y for support of the configuration interface for the I2O adapters.
If you have a RAID controller from Adaptec and you want to use the
@@ -78,7 +75,6 @@ config I2O_CONFIG_OLD_IOCTL
config I2O_BUS
tristate "I2O Bus Adapter OSM"
- depends on I2O
---help---
Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM
provides access to the busses on the I2O controller. The main purpose
@@ -89,7 +85,7 @@ config I2O_BUS
config I2O_BLOCK
tristate "I2O Block OSM"
- depends on I2O && BLOCK
+ depends on BLOCK
---help---
Include support for the I2O Block OSM. The Block OSM presents disk
and other structured block devices to the operating system. If you
@@ -102,7 +98,7 @@ config I2O_BLOCK
config I2O_SCSI
tristate "I2O SCSI OSM"
- depends on I2O && SCSI
+ depends on SCSI
---help---
Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
I2O controller. You can use both the SCSI and Block OSM together if
@@ -114,7 +110,6 @@ config I2O_SCSI
config I2O_PROC
tristate "I2O /proc support"
- depends on I2O
---help---
If you say Y here and to "/proc file system support", you will be
able to read I2O related information from the virtual directory
@@ -123,5 +118,4 @@ config I2O_PROC
To compile this support as a module, choose M here: the
module will be called i2o_proc.
-endmenu
-
+endif # I2O
diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c
index 8abe45e49ad7..ce62d8bfe1c8 100644
--- a/drivers/message/i2o/debug.c
+++ b/drivers/message/i2o/debug.c
@@ -24,7 +24,7 @@ void i2o_report_status(const char *severity, const char *str,
if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
return; // No status in this reply
- printk(KERN_DEBUG "%s%s: ", severity, str);
+ printk("%s%s: ", severity, str);
if (cmd < 0x1F) // Utility cmd
i2o_report_util_cmd(cmd);
@@ -32,7 +32,7 @@ void i2o_report_status(const char *severity, const char *str,
else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd
i2o_report_exec_cmd(cmd);
else
- printk(KERN_DEBUG "Cmd = %0#2x, ", cmd); // Other cmds
+ printk("Cmd = %0#2x, ", cmd); // Other cmds
if (msg[0] & MSG_FAIL) {
i2o_report_fail_status(req_status, msg);
@@ -44,7 +44,7 @@ void i2o_report_status(const char *severity, const char *str,
if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
i2o_report_common_dsc(detailed_status);
else
- printk(KERN_DEBUG " / DetailedStatus = %0#4x.\n",
+ printk(" / DetailedStatus = %0#4x.\n",
detailed_status);
}
@@ -89,10 +89,10 @@ static void i2o_report_fail_status(u8 req_status, u32 * msg)
};
if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
- printk(KERN_DEBUG "TRANSPORT_UNKNOWN_FAILURE (%0#2x).\n",
+ printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x).\n",
req_status);
else
- printk(KERN_DEBUG "TRANSPORT_%s.\n",
+ printk("TRANSPORT_%s.\n",
FAIL_STATUS[req_status & 0x0F]);
/* Dump some details */
@@ -104,7 +104,7 @@ static void i2o_report_fail_status(u8 req_status, u32 * msg)
printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n",
msg[5] >> 16, msg[5] & 0xFFF);
- printk(KERN_ERR " Severity: 0x%02X ", (msg[4] >> 16) & 0xFF);
+ printk(KERN_ERR " Severity: 0x%02X\n", (msg[4] >> 16) & 0xFF);
if (msg[4] & (1 << 16))
printk(KERN_DEBUG "(FormatError), "
"this msg can never be delivered/processed.\n");
@@ -142,9 +142,9 @@ static void i2o_report_common_status(u8 req_status)
};
if (req_status >= ARRAY_SIZE(REPLY_STATUS))
- printk(KERN_DEBUG "RequestStatus = %0#2x", req_status);
+ printk("RequestStatus = %0#2x", req_status);
else
- printk(KERN_DEBUG "%s", REPLY_STATUS[req_status]);
+ printk("%s", REPLY_STATUS[req_status]);
}
/*
@@ -187,10 +187,10 @@ static void i2o_report_common_dsc(u16 detailed_status)
};
if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
- printk(KERN_DEBUG " / DetailedStatus = %0#4x.\n",
+ printk(" / DetailedStatus = %0#4x.\n",
detailed_status);
else
- printk(KERN_DEBUG " / %s.\n", COMMON_DSC[detailed_status]);
+ printk(" / %s.\n", COMMON_DSC[detailed_status]);
}
/*
@@ -200,49 +200,49 @@ static void i2o_report_util_cmd(u8 cmd)
{
switch (cmd) {
case I2O_CMD_UTIL_NOP:
- printk(KERN_DEBUG "UTIL_NOP, ");
+ printk("UTIL_NOP, ");
break;
case I2O_CMD_UTIL_ABORT:
- printk(KERN_DEBUG "UTIL_ABORT, ");
+ printk("UTIL_ABORT, ");
break;
case I2O_CMD_UTIL_CLAIM:
- printk(KERN_DEBUG "UTIL_CLAIM, ");
+ printk("UTIL_CLAIM, ");
break;
case I2O_CMD_UTIL_RELEASE:
- printk(KERN_DEBUG "UTIL_CLAIM_RELEASE, ");
+ printk("UTIL_CLAIM_RELEASE, ");
break;
case I2O_CMD_UTIL_CONFIG_DIALOG:
- printk(KERN_DEBUG "UTIL_CONFIG_DIALOG, ");
+ printk("UTIL_CONFIG_DIALOG, ");
break;
case I2O_CMD_UTIL_DEVICE_RESERVE:
- printk(KERN_DEBUG "UTIL_DEVICE_RESERVE, ");
+ printk("UTIL_DEVICE_RESERVE, ");
break;
case I2O_CMD_UTIL_DEVICE_RELEASE:
- printk(KERN_DEBUG "UTIL_DEVICE_RELEASE, ");
+ printk("UTIL_DEVICE_RELEASE, ");
break;
case I2O_CMD_UTIL_EVT_ACK:
- printk(KERN_DEBUG "UTIL_EVENT_ACKNOWLEDGE, ");
+ printk("UTIL_EVENT_ACKNOWLEDGE, ");
break;
case I2O_CMD_UTIL_EVT_REGISTER:
- printk(KERN_DEBUG "UTIL_EVENT_REGISTER, ");
+ printk("UTIL_EVENT_REGISTER, ");
break;
case I2O_CMD_UTIL_LOCK:
- printk(KERN_DEBUG "UTIL_LOCK, ");
+ printk("UTIL_LOCK, ");
break;
case I2O_CMD_UTIL_LOCK_RELEASE:
- printk(KERN_DEBUG "UTIL_LOCK_RELEASE, ");
+ printk("UTIL_LOCK_RELEASE, ");
break;
case I2O_CMD_UTIL_PARAMS_GET:
- printk(KERN_DEBUG "UTIL_PARAMS_GET, ");
+ printk("UTIL_PARAMS_GET, ");
break;
case I2O_CMD_UTIL_PARAMS_SET:
- printk(KERN_DEBUG "UTIL_PARAMS_SET, ");
+ printk("UTIL_PARAMS_SET, ");
break;
case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
- printk(KERN_DEBUG "UTIL_REPLY_FAULT_NOTIFY, ");
+ printk("UTIL_REPLY_FAULT_NOTIFY, ");
break;
default:
- printk(KERN_DEBUG "Cmd = %0#2x, ", cmd);
+ printk("Cmd = %0#2x, ", cmd);
}
}
@@ -253,106 +253,106 @@ static void i2o_report_exec_cmd(u8 cmd)
{
switch (cmd) {
case I2O_CMD_ADAPTER_ASSIGN:
- printk(KERN_DEBUG "EXEC_ADAPTER_ASSIGN, ");
+ printk("EXEC_ADAPTER_ASSIGN, ");
break;
case I2O_CMD_ADAPTER_READ:
- printk(KERN_DEBUG "EXEC_ADAPTER_READ, ");
+ printk("EXEC_ADAPTER_READ, ");
break;
case I2O_CMD_ADAPTER_RELEASE:
- printk(KERN_DEBUG "EXEC_ADAPTER_RELEASE, ");
+ printk("EXEC_ADAPTER_RELEASE, ");
break;
case I2O_CMD_BIOS_INFO_SET:
- printk(KERN_DEBUG "EXEC_BIOS_INFO_SET, ");
+ printk("EXEC_BIOS_INFO_SET, ");
break;
case I2O_CMD_BOOT_DEVICE_SET:
- printk(KERN_DEBUG "EXEC_BOOT_DEVICE_SET, ");
+ printk("EXEC_BOOT_DEVICE_SET, ");
break;
case I2O_CMD_CONFIG_VALIDATE:
- printk(KERN_DEBUG "EXEC_CONFIG_VALIDATE, ");
+ printk("EXEC_CONFIG_VALIDATE, ");
break;
case I2O_CMD_CONN_SETUP:
- printk(KERN_DEBUG "EXEC_CONN_SETUP, ");
+ printk("EXEC_CONN_SETUP, ");
break;
case I2O_CMD_DDM_DESTROY:
- printk(KERN_DEBUG "EXEC_DDM_DESTROY, ");
+ printk("EXEC_DDM_DESTROY, ");
break;
case I2O_CMD_DDM_ENABLE:
- printk(KERN_DEBUG "EXEC_DDM_ENABLE, ");
+ printk("EXEC_DDM_ENABLE, ");
break;
case I2O_CMD_DDM_QUIESCE:
- printk(KERN_DEBUG "EXEC_DDM_QUIESCE, ");
+ printk("EXEC_DDM_QUIESCE, ");
break;
case I2O_CMD_DDM_RESET:
- printk(KERN_DEBUG "EXEC_DDM_RESET, ");
+ printk("EXEC_DDM_RESET, ");
break;
case I2O_CMD_DDM_SUSPEND:
- printk(KERN_DEBUG "EXEC_DDM_SUSPEND, ");
+ printk("EXEC_DDM_SUSPEND, ");
break;
case I2O_CMD_DEVICE_ASSIGN:
- printk(KERN_DEBUG "EXEC_DEVICE_ASSIGN, ");
+ printk("EXEC_DEVICE_ASSIGN, ");
break;
case I2O_CMD_DEVICE_RELEASE:
- printk(KERN_DEBUG "EXEC_DEVICE_RELEASE, ");
+ printk("EXEC_DEVICE_RELEASE, ");
break;
case I2O_CMD_HRT_GET:
- printk(KERN_DEBUG "EXEC_HRT_GET, ");
+ printk("EXEC_HRT_GET, ");
break;
case I2O_CMD_ADAPTER_CLEAR:
- printk(KERN_DEBUG "EXEC_IOP_CLEAR, ");
+ printk("EXEC_IOP_CLEAR, ");
break;
case I2O_CMD_ADAPTER_CONNECT:
- printk(KERN_DEBUG "EXEC_IOP_CONNECT, ");
+ printk("EXEC_IOP_CONNECT, ");
break;
case I2O_CMD_ADAPTER_RESET:
- printk(KERN_DEBUG "EXEC_IOP_RESET, ");
+ printk("EXEC_IOP_RESET, ");
break;
case I2O_CMD_LCT_NOTIFY:
- printk(KERN_DEBUG "EXEC_LCT_NOTIFY, ");
+ printk("EXEC_LCT_NOTIFY, ");
break;
case I2O_CMD_OUTBOUND_INIT:
- printk(KERN_DEBUG "EXEC_OUTBOUND_INIT, ");
+ printk("EXEC_OUTBOUND_INIT, ");
break;
case I2O_CMD_PATH_ENABLE:
- printk(KERN_DEBUG "EXEC_PATH_ENABLE, ");
+ printk("EXEC_PATH_ENABLE, ");
break;
case I2O_CMD_PATH_QUIESCE:
- printk(KERN_DEBUG "EXEC_PATH_QUIESCE, ");
+ printk("EXEC_PATH_QUIESCE, ");
break;
case I2O_CMD_PATH_RESET:
- printk(KERN_DEBUG "EXEC_PATH_RESET, ");
+ printk("EXEC_PATH_RESET, ");
break;
case I2O_CMD_STATIC_MF_CREATE:
- printk(KERN_DEBUG "EXEC_STATIC_MF_CREATE, ");
+ printk("EXEC_STATIC_MF_CREATE, ");
break;
case I2O_CMD_STATIC_MF_RELEASE:
- printk(KERN_DEBUG "EXEC_STATIC_MF_RELEASE, ");
+ printk("EXEC_STATIC_MF_RELEASE, ");
break;
case I2O_CMD_STATUS_GET:
- printk(KERN_DEBUG "EXEC_STATUS_GET, ");
+ printk("EXEC_STATUS_GET, ");
break;
case I2O_CMD_SW_DOWNLOAD:
- printk(KERN_DEBUG "EXEC_SW_DOWNLOAD, ");
+ printk("EXEC_SW_DOWNLOAD, ");
break;
case I2O_CMD_SW_UPLOAD:
- printk(KERN_DEBUG "EXEC_SW_UPLOAD, ");
+ printk("EXEC_SW_UPLOAD, ");
break;
case I2O_CMD_SW_REMOVE:
- printk(KERN_DEBUG "EXEC_SW_REMOVE, ");
+ printk("EXEC_SW_REMOVE, ");
break;
case I2O_CMD_SYS_ENABLE:
- printk(KERN_DEBUG "EXEC_SYS_ENABLE, ");
+ printk("EXEC_SYS_ENABLE, ");
break;
case I2O_CMD_SYS_MODIFY:
- printk(KERN_DEBUG "EXEC_SYS_MODIFY, ");
+ printk("EXEC_SYS_MODIFY, ");
break;
case I2O_CMD_SYS_QUIESCE:
- printk(KERN_DEBUG "EXEC_SYS_QUIESCE, ");
+ printk("EXEC_SYS_QUIESCE, ");
break;
case I2O_CMD_SYS_TAB_SET:
- printk(KERN_DEBUG "EXEC_SYS_TAB_SET, ");
+ printk("EXEC_SYS_TAB_SET, ");
break;
default:
- printk(KERN_DEBUG "Cmd = %#02x, ", cmd);
+ printk("Cmd = %#02x, ", cmd);
}
}
@@ -361,28 +361,28 @@ void i2o_debug_state(struct i2o_controller *c)
printk(KERN_INFO "%s: State = ", c->name);
switch (((i2o_status_block *) c->status_block.virt)->iop_state) {
case 0x01:
- printk(KERN_DEBUG "INIT\n");
+ printk("INIT\n");
break;
case 0x02:
- printk(KERN_DEBUG "RESET\n");
+ printk("RESET\n");
break;
case 0x04:
- printk(KERN_DEBUG "HOLD\n");
+ printk("HOLD\n");
break;
case 0x05:
- printk(KERN_DEBUG "READY\n");
+ printk("READY\n");
break;
case 0x08:
- printk(KERN_DEBUG "OPERATIONAL\n");
+ printk("OPERATIONAL\n");
break;
case 0x10:
- printk(KERN_DEBUG "FAILED\n");
+ printk("FAILED\n");
break;
case 0x11:
- printk(KERN_DEBUG "FAULTED\n");
+ printk("FAULTED\n");
break;
default:
- printk(KERN_DEBUG "%x (unknown !!)\n",
+ printk("%x (unknown !!)\n",
((i2o_status_block *) c->status_block.virt)->iop_state);
}
};
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c
index b9df143e4ff1..489d7c5c4965 100644
--- a/drivers/message/i2o/device.c
+++ b/drivers/message/i2o/device.c
@@ -62,7 +62,7 @@ int i2o_device_claim(struct i2o_device *dev)
{
int rc = 0;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY);
if (!rc)
@@ -72,7 +72,7 @@ int i2o_device_claim(struct i2o_device *dev)
pr_debug("i2o: claim of device %d failed %d\n",
dev->lct_data.tid, rc);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return rc;
}
@@ -96,7 +96,7 @@ int i2o_device_claim_release(struct i2o_device *dev)
int tries;
int rc = 0;
- down(&dev->lock);
+ mutex_lock(&dev->lock);
/*
* If the controller takes a nonblocking approach to
@@ -118,7 +118,7 @@ int i2o_device_claim_release(struct i2o_device *dev)
pr_debug("i2o: claim release of device %d failed %d\n",
dev->lct_data.tid, rc);
- up(&dev->lock);
+ mutex_unlock(&dev->lock);
return rc;
}
@@ -198,7 +198,7 @@ static struct i2o_device *i2o_device_alloc(void)
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&dev->list);
- init_MUTEX(&dev->lock);
+ mutex_init(&dev->lock);
dev->device.bus = &i2o_bus_type;
dev->device.release = &i2o_device_release;
@@ -326,7 +326,7 @@ int i2o_device_parse_lct(struct i2o_controller *c)
u16 table_size;
u32 buf;
- down(&c->lct_lock);
+ mutex_lock(&c->lct_lock);
kfree(c->lct);
@@ -335,7 +335,7 @@ int i2o_device_parse_lct(struct i2o_controller *c)
lct = c->lct = kmalloc(table_size * 4, GFP_KERNEL);
if (!lct) {
- up(&c->lct_lock);
+ mutex_unlock(&c->lct_lock);
return -ENOMEM;
}
@@ -408,7 +408,7 @@ int i2o_device_parse_lct(struct i2o_controller *c)
i2o_device_remove(dev);
}
- up(&c->lct_lock);
+ mutex_unlock(&c->lct_lock);
return 0;
}
@@ -485,7 +485,7 @@ int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
u8 *resblk; /* 8 bytes for header */
int rc;
- resblk = kmalloc(buflen + 8, GFP_KERNEL | GFP_ATOMIC);
+ resblk = kmalloc(buflen + 8, GFP_KERNEL);
if (!resblk)
return -ENOMEM;
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 5278aad92bc4..8c83ee3b0920 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -131,8 +131,10 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
int rc = 0;
wait = i2o_exec_wait_alloc();
- if (!wait)
+ if (!wait) {
+ i2o_msg_nop(c, msg);
return -ENOMEM;
+ }
if (tcntxt == 0xffffffff)
tcntxt = 0x80000000;
@@ -337,6 +339,8 @@ static int i2o_exec_probe(struct device *dev)
rc = device_create_file(dev, &dev_attr_product_id);
if (rc) goto err_vid;
+ i2o_dev->iop->exec = i2o_dev;
+
return 0;
err_vid:
@@ -537,7 +541,7 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
struct device *dev;
struct i2o_message *msg;
- down(&c->lct_lock);
+ mutex_lock(&c->lct_lock);
dev = &c->pdev->dev;
@@ -561,7 +565,7 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
i2o_msg_post(c, msg);
- up(&c->lct_lock);
+ mutex_unlock(&c->lct_lock);
return 0;
};
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index b17c4b2bc9ef..988c8ce47f58 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -215,7 +215,7 @@ static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id)
struct i2o_message *msg;
msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg) == I2O_QUEUE_EMPTY)
+ if (IS_ERR(msg))
return PTR_ERR(msg);
msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
@@ -1171,8 +1171,7 @@ static int __init i2o_block_init(void)
/* Allocate request mempool and slab */
size = sizeof(struct i2o_block_request);
i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
- SLAB_HWCACHE_ALIGN, NULL,
- NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!i2o_blk_req_pool.slab) {
osm_err("can't init request slab\n");
rc = -ENOMEM;
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 8ba275a12773..84e046e94f5f 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -554,8 +554,6 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
return -ENXIO;
}
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-
sb = c->status_block.virt;
if (get_user(size, &user_msg[0])) {
@@ -573,24 +571,30 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
size <<= 2; // Convert to bytes
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ rcode = -EFAULT;
/* Copy in the user's I2O command */
if (copy_from_user(msg, user_msg, size)) {
osm_warn("unable to copy user message\n");
- return -EFAULT;
+ goto out;
}
i2o_dump_message(msg);
if (get_user(reply_size, &user_reply[0]) < 0)
- return -EFAULT;
+ goto out;
reply_size >>= 16;
reply_size <<= 2;
+ rcode = -ENOMEM;
reply = kzalloc(reply_size, GFP_KERNEL);
if (!reply) {
printk(KERN_WARNING "%s: Could not allocate reply buffer\n",
c->name);
- return -ENOMEM;
+ goto out;
}
sg_offset = (msg->u.head[0] >> 4) & 0x0f;
@@ -661,13 +665,14 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
}
rcode = i2o_msg_post_wait(c, msg, 60);
+ msg = NULL;
if (rcode) {
reply[4] = ((u32) rcode) << 24;
goto sg_list_cleanup;
}
if (sg_offset) {
- u32 msg[I2O_OUTBOUND_MSG_FRAME_SIZE];
+ u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
// TODO 64bit fix
@@ -675,7 +680,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
int sg_size;
// re-acquire the original message to handle correctly the sg copy operation
- memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
+ memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
// get user msg size in u32s
if (get_user(size, &user_msg[0])) {
rcode = -EFAULT;
@@ -684,7 +689,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
size = size >> 16;
size *= 4;
/* Copy in the user's I2O command */
- if (copy_from_user(msg, user_msg, size)) {
+ if (copy_from_user(rmsg, user_msg, size)) {
rcode = -EFAULT;
goto sg_list_cleanup;
}
@@ -692,7 +697,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
(size - sg_offset * 4) / sizeof(struct sg_simple_element);
// TODO 64bit fix
- sg = (struct sg_simple_element *)(msg + sg_offset);
+ sg = (struct sg_simple_element *)(rmsg + sg_offset);
for (j = 0; j < sg_count; j++) {
/* Copy out the SG list to user's buffer if necessary */
if (!
@@ -714,7 +719,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
}
}
- sg_list_cleanup:
+sg_list_cleanup:
/* Copy back the reply to user space */
if (reply_size) {
// we wrote our own values for context - now restore the user supplied ones
@@ -723,7 +728,6 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
"%s: Could not copy message context FROM user\n",
c->name);
rcode = -EFAULT;
- goto sg_list_cleanup;
}
if (copy_to_user(user_reply, reply, reply_size)) {
printk(KERN_WARNING
@@ -731,12 +735,14 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
rcode = -EFAULT;
}
}
-
for (i = 0; i < sg_index; i++)
i2o_dma_free(&c->pdev->dev, &sg_list[i]);
- cleanup:
+cleanup:
kfree(reply);
+out:
+ if (msg)
+ i2o_msg_nop(c, msg);
return rcode;
}
@@ -793,8 +799,6 @@ static int i2o_cfg_passthru(unsigned long arg)
return -ENXIO;
}
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
-
sb = c->status_block.virt;
if (get_user(size, &user_msg[0]))
@@ -810,12 +814,17 @@ static int i2o_cfg_passthru(unsigned long arg)
size <<= 2; // Convert to bytes
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ rcode = -EFAULT;
/* Copy in the user's I2O command */
if (copy_from_user(msg, user_msg, size))
- return -EFAULT;
+ goto out;
if (get_user(reply_size, &user_reply[0]) < 0)
- return -EFAULT;
+ goto out;
reply_size >>= 16;
reply_size <<= 2;
@@ -824,7 +833,8 @@ static int i2o_cfg_passthru(unsigned long arg)
if (!reply) {
printk(KERN_WARNING "%s: Could not allocate reply buffer\n",
c->name);
- return -ENOMEM;
+ rcode = -ENOMEM;
+ goto out;
}
sg_offset = (msg->u.head[0] >> 4) & 0x0f;
@@ -891,13 +901,14 @@ static int i2o_cfg_passthru(unsigned long arg)
}
rcode = i2o_msg_post_wait(c, msg, 60);
+ msg = NULL;
if (rcode) {
reply[4] = ((u32) rcode) << 24;
goto sg_list_cleanup;
}
if (sg_offset) {
- u32 msg[128];
+ u32 rmsg[128];
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
// TODO 64bit fix
@@ -905,7 +916,7 @@ static int i2o_cfg_passthru(unsigned long arg)
int sg_size;
// re-acquire the original message to handle correctly the sg copy operation
- memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
+ memset(&rmsg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
// get user msg size in u32s
if (get_user(size, &user_msg[0])) {
rcode = -EFAULT;
@@ -914,7 +925,7 @@ static int i2o_cfg_passthru(unsigned long arg)
size = size >> 16;
size *= 4;
/* Copy in the user's I2O command */
- if (copy_from_user(msg, user_msg, size)) {
+ if (copy_from_user(rmsg, user_msg, size)) {
rcode = -EFAULT;
goto sg_list_cleanup;
}
@@ -922,7 +933,7 @@ static int i2o_cfg_passthru(unsigned long arg)
(size - sg_offset * 4) / sizeof(struct sg_simple_element);
// TODO 64bit fix
- sg = (struct sg_simple_element *)(msg + sg_offset);
+ sg = (struct sg_simple_element *)(rmsg + sg_offset);
for (j = 0; j < sg_count; j++) {
/* Copy out the SG list to user's buffer if necessary */
if (!
@@ -944,7 +955,7 @@ static int i2o_cfg_passthru(unsigned long arg)
}
}
- sg_list_cleanup:
+sg_list_cleanup:
/* Copy back the reply to user space */
if (reply_size) {
// we wrote our own values for context - now restore the user supplied ones
@@ -964,8 +975,11 @@ static int i2o_cfg_passthru(unsigned long arg)
for (i = 0; i < sg_index; i++)
kfree(sg_list[i]);
- cleanup:
+cleanup:
kfree(reply);
+out:
+ if (msg)
+ i2o_msg_nop(c, msg);
return rcode;
}
#endif
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index 1045c8a518bb..aa6fb9429d58 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -377,12 +377,8 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
osm_err("SCSI error %08x\n", error);
dev = &c->pdev->dev;
- if (cmd->use_sg)
- dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
- else if (cmd->SCp.dma_handle)
- dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen,
- cmd->sc_data_direction);
+
+ scsi_dma_unmap(cmd);
cmd->scsi_done(cmd);
@@ -664,21 +660,15 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
if (sgl_offset != SGL_OFFSET_0) {
/* write size of data addressed by SGL */
- *mptr++ = cpu_to_le32(SCpnt->request_bufflen);
+ *mptr++ = cpu_to_le32(scsi_bufflen(SCpnt));
/* Now fill in the SGList and command */
- if (SCpnt->use_sg) {
- if (!i2o_dma_map_sg(c, SCpnt->request_buffer,
- SCpnt->use_sg,
+
+ if (scsi_sg_count(SCpnt)) {
+ if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt),
SCpnt->sc_data_direction, &mptr))
goto nomem;
- } else {
- SCpnt->SCp.dma_handle =
- i2o_dma_map_single(c, SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction, &mptr);
- if (dma_mapping_error(SCpnt->SCp.dma_handle))
- goto nomem;
}
}
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index 3305c12372a2..a1ec16a075c6 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -1067,7 +1067,7 @@ struct i2o_controller *i2o_iop_alloc(void)
INIT_LIST_HEAD(&c->devices);
spin_lock_init(&c->lock);
- init_MUTEX(&c->lct_lock);
+ mutex_init(&c->lct_lock);
device_initialize(&c->device);
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 75f401d52fda..b4ed57e02729 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -200,9 +200,8 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
{
struct mcp *mcp;
- mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL);
+ mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
if (mcp) {
- memset(mcp, 0, sizeof(struct mcp) + size);
spin_lock_init(&mcp->lock);
mcp->attached_device.parent = parent;
mcp->attached_device.bus = &mcp_bus_type;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 149810a084f5..e03f1bcd4f9f 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -484,12 +484,11 @@ static int ucb1x00_probe(struct mcp *mcp)
goto err_disable;
}
- ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
+ ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
ret = -ENOMEM;
if (!ucb)
goto err_disable;
- memset(ucb, 0, sizeof(struct ucb1x00));
ucb->cdev.class = &ucb1x00_class;
ucb->cdev.dev = &mcp->attached_device;
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 38e815a2e871..fdbaa776f249 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -209,6 +209,7 @@ static int ucb1x00_thread(void *_ts)
DECLARE_WAITQUEUE(wait, tsk);
int valid = 0;
+ set_freezable();
add_wait_queue(&ts->irq_wait, &wait);
while (!kthread_should_stop()) {
unsigned int x, y, p;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index bd601efa7bd1..aaaa61ea4217 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -2,11 +2,15 @@
# Misc strange devices
#
-menu "Misc devices"
+menuconfig MISC_DEVICES
+ bool "Misc devices"
+ default y
+
+if MISC_DEVICES
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
- depends on X86 && PCI && EXPERIMENTAL
+ depends on X86 && PCI && INPUT && EXPERIMENTAL
---help---
This option enables device driver support for in-band access to the
IBM RSA (Condor) service processor in eServer xSeries systems.
@@ -146,6 +150,7 @@ config THINKPAD_ACPI
depends on X86 && ACPI
select BACKLIGHT_CLASS_DEVICE
select HWMON
+ select NVRAM
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -192,4 +197,17 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here.
-endmenu
+config THINKPAD_ACPI_INPUT_ENABLED
+ bool "Enable input layer support by default"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Enables hot key handling over the input layer by default. If unset,
+ the driver does not enable any hot key handling by default, and also
+ starts up with a mostly empty keymap.
+
+ If you are not sure, say Y here. Say N to retain the deprecated
+ behavior of ibm-acpi, and thinkpad-acpi for kernels up to 2.6.21.
+
+
+endif # MISC_DEVICES
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 4f9060a2a2f2..f75306059971 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -737,8 +737,7 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
struct device_attribute dev_attr_##_name = { \
.attr = { \
.name = __stringify(_name), \
- .mode = 0, \
- .owner = THIS_MODULE }, \
+ .mode = 0 }, \
.show = NULL, \
.store = NULL, \
}
@@ -980,10 +979,9 @@ static int asus_hotk_add(struct acpi_device *device)
printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
ASUS_LAPTOP_VERSION);
- hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+ hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
if (!hotk)
return -ENOMEM;
- memset(hotk, 0, sizeof(struct asus_hotk));
hotk->handle = device->handle;
strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index 07a085ccbd5b..6497872df524 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -18,7 +18,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
@@ -41,18 +41,16 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
return NULL;
- cmd = kmalloc(sizeof(struct command), GFP_KERNEL);
+ cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
if (cmd == NULL)
return NULL;
- memset(cmd, 0, sizeof(*cmd));
- cmd->buffer = kmalloc(buffer_size, GFP_KERNEL);
+ cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
if (cmd->buffer == NULL) {
kfree(cmd);
return NULL;
}
- memset(cmd->buffer, 0, buffer_size);
cmd->buffer_size = buffer_size;
kobject_init(&cmd->kobj);
@@ -72,7 +70,7 @@ struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_s
static void free_command(struct kobject *kobj)
{
struct command *cmd = to_command(kobj);
-
+
list_del(&cmd->queue_node);
atomic_dec(&command_count);
dbg("command count: %d\n", atomic_read(&command_count));
@@ -113,14 +111,14 @@ static inline void do_exec_command(struct service_processor *sp)
exec_next_command(sp);
}
}
-
+
/**
* exec_command
* send a command to a service processor
* Commands are executed sequentially. One command (sp->current_command)
* is sent to the service processor. Once the interrupt handler gets a
* message of type command_response, the message is copied into
- * the current commands buffer,
+ * the current commands buffer,
*/
void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
{
@@ -160,7 +158,7 @@ static void exec_next_command(struct service_processor *sp)
}
}
-/**
+/**
* Sleep until a command has failed or a response has been received
* and the command status been updated by the interrupt handler.
* (see receive_response).
@@ -182,8 +180,8 @@ void ibmasm_receive_command_response(struct service_processor *sp, void *respons
{
struct command *cmd = sp->current_command;
- if (!sp->current_command)
- return;
+ if (!sp->current_command)
+ return;
memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size));
cmd->status = IBMASM_CMD_COMPLETE;
diff --git a/drivers/misc/ibmasm/dot_command.c b/drivers/misc/ibmasm/dot_command.c
index 13c52f866e2e..3dd2dfb8da17 100644
--- a/drivers/misc/ibmasm/dot_command.c
+++ b/drivers/misc/ibmasm/dot_command.c
@@ -17,7 +17,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
@@ -44,11 +44,11 @@ void ibmasm_receive_message(struct service_processor *sp, void *message, int mes
size = message_size;
switch (header->type) {
- case sp_event:
+ case sp_event:
ibmasm_receive_event(sp, message, size);
break;
case sp_command_response:
- ibmasm_receive_command_response(sp, message, size);
+ ibmasm_receive_command_response(sp, message, size);
break;
case sp_heartbeat:
ibmasm_receive_heartbeat(sp, message, size);
@@ -95,7 +95,7 @@ int ibmasm_send_driver_vpd(struct service_processor *sp)
strcat(vpd_data, IBMASM_DRIVER_VPD);
vpd_data[10] = 0;
vpd_data[15] = 0;
-
+
ibmasm_exec_command(sp, command);
ibmasm_wait_for_response(command, IBMASM_CMD_TIMEOUT_NORMAL);
@@ -118,7 +118,7 @@ struct os_state_command {
* During driver init this function is called with os state "up".
* This causes the service processor to start sending heartbeats the
* driver.
- * During driver exit the function is called with os state "down",
+ * During driver exit the function is called with os state "down",
* causing the service processor to stop the heartbeats.
*/
int ibmasm_send_os_state(struct service_processor *sp, int os_state)
diff --git a/drivers/misc/ibmasm/dot_command.h b/drivers/misc/ibmasm/dot_command.h
index 2d21c2741b6a..6cbba1afef35 100644
--- a/drivers/misc/ibmasm/dot_command.h
+++ b/drivers/misc/ibmasm/dot_command.h
@@ -17,7 +17,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
diff --git a/drivers/misc/ibmasm/event.c b/drivers/misc/ibmasm/event.c
index fe1e819235a4..fda6a4d3bf23 100644
--- a/drivers/misc/ibmasm/event.c
+++ b/drivers/misc/ibmasm/event.c
@@ -18,7 +18,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
@@ -51,7 +51,7 @@ static void wake_up_event_readers(struct service_processor *sp)
* event readers.
* There is no reader marker in the buffer, therefore readers are
* responsible for keeping up with the writer, or they will loose events.
- */
+ */
void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int data_size)
{
struct event_buffer *buffer = sp->event_buffer;
@@ -77,13 +77,13 @@ void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int
static inline int event_available(struct event_buffer *b, struct event_reader *r)
{
- return (r->next_serial_number < b->next_serial_number);
+ return (r->next_serial_number < b->next_serial_number);
}
/**
* get_next_event
* Called by event readers (initiated from user space through the file
- * system).
+ * system).
* Sleeps until a new event is available.
*/
int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader)
diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c
index 7fd7a43e38de..3036e785b3e4 100644
--- a/drivers/misc/ibmasm/heartbeat.c
+++ b/drivers/misc/ibmasm/heartbeat.c
@@ -18,7 +18,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
diff --git a/drivers/misc/ibmasm/i2o.h b/drivers/misc/ibmasm/i2o.h
index 958c957a5e75..bf2c738d2b72 100644
--- a/drivers/misc/ibmasm/i2o.h
+++ b/drivers/misc/ibmasm/i2o.h
@@ -17,7 +17,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
@@ -26,9 +26,9 @@ struct i2o_header {
u8 version;
u8 message_flags;
u16 message_size;
- u8 target;
+ u8 target;
u8 initiator_and_target;
- u8 initiator;
+ u8 initiator;
u8 function;
u32 initiator_context;
};
@@ -64,12 +64,12 @@ static inline unsigned short outgoing_message_size(unsigned int data_size)
size = sizeof(struct i2o_header) + data_size;
i2o_size = size / sizeof(u32);
-
+
if (size % sizeof(u32))
i2o_size++;
return i2o_size;
-}
+}
static inline u32 incoming_data_size(struct i2o_message *i2o_message)
{
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index 48d5abebfc30..de860bc6d3f5 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -18,7 +18,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
@@ -58,8 +58,8 @@ static inline char *get_timestamp(char *buf)
return buf;
}
-#define IBMASM_CMD_PENDING 0
-#define IBMASM_CMD_COMPLETE 1
+#define IBMASM_CMD_PENDING 0
+#define IBMASM_CMD_COMPLETE 1
#define IBMASM_CMD_FAILED 2
#define IBMASM_CMD_TIMEOUT_NORMAL 45
@@ -163,55 +163,55 @@ struct service_processor {
};
/* command processing */
-extern struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size);
-extern void ibmasm_exec_command(struct service_processor *sp, struct command *cmd);
-extern void ibmasm_wait_for_response(struct command *cmd, int timeout);
-extern void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size);
+struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size);
+void ibmasm_exec_command(struct service_processor *sp, struct command *cmd);
+void ibmasm_wait_for_response(struct command *cmd, int timeout);
+void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size);
/* event processing */
-extern int ibmasm_event_buffer_init(struct service_processor *sp);
-extern void ibmasm_event_buffer_exit(struct service_processor *sp);
-extern void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int data_size);
-extern void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader);
-extern void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader);
-extern int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader);
-extern void ibmasm_cancel_next_event(struct event_reader *reader);
+int ibmasm_event_buffer_init(struct service_processor *sp);
+void ibmasm_event_buffer_exit(struct service_processor *sp);
+void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int data_size);
+void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader);
+void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader);
+int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader);
+void ibmasm_cancel_next_event(struct event_reader *reader);
/* heartbeat - from SP to OS */
-extern void ibmasm_register_panic_notifier(void);
-extern void ibmasm_unregister_panic_notifier(void);
-extern int ibmasm_heartbeat_init(struct service_processor *sp);
-extern void ibmasm_heartbeat_exit(struct service_processor *sp);
-extern void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size_t size);
+void ibmasm_register_panic_notifier(void);
+void ibmasm_unregister_panic_notifier(void);
+int ibmasm_heartbeat_init(struct service_processor *sp);
+void ibmasm_heartbeat_exit(struct service_processor *sp);
+void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size_t size);
/* reverse heartbeat - from OS to SP */
-extern void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
-extern int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
-extern void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb);
+void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
+int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
+void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb);
/* dot commands */
-extern void ibmasm_receive_message(struct service_processor *sp, void *data, int data_size);
-extern int ibmasm_send_driver_vpd(struct service_processor *sp);
-extern int ibmasm_send_os_state(struct service_processor *sp, int os_state);
+void ibmasm_receive_message(struct service_processor *sp, void *data, int data_size);
+int ibmasm_send_driver_vpd(struct service_processor *sp);
+int ibmasm_send_os_state(struct service_processor *sp, int os_state);
/* low level message processing */
-extern int ibmasm_send_i2o_message(struct service_processor *sp);
-extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id);
+int ibmasm_send_i2o_message(struct service_processor *sp);
+irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id);
/* remote console */
-extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
-extern int ibmasm_init_remote_input_dev(struct service_processor *sp);
-extern void ibmasm_free_remote_input_dev(struct service_processor *sp);
+void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
+int ibmasm_init_remote_input_dev(struct service_processor *sp);
+void ibmasm_free_remote_input_dev(struct service_processor *sp);
/* file system */
-extern int ibmasmfs_register(void);
-extern void ibmasmfs_unregister(void);
-extern void ibmasmfs_add_sp(struct service_processor *sp);
+int ibmasmfs_register(void);
+void ibmasmfs_unregister(void);
+void ibmasmfs_add_sp(struct service_processor *sp);
/* uart */
#ifdef CONFIG_SERIAL_8250
-extern void ibmasm_register_uart(struct service_processor *sp);
-extern void ibmasm_unregister_uart(struct service_processor *sp);
+void ibmasm_register_uart(struct service_processor *sp);
+void ibmasm_unregister_uart(struct service_processor *sp);
#else
#define ibmasm_register_uart(sp) do { } while(0)
#define ibmasm_unregister_uart(sp) do { } while(0)
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index c436d3de8b8b..22a7e8ba211d 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -17,12 +17,12 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
/*
- * Parts of this code are based on an article by Jonathan Corbet
+ * Parts of this code are based on an article by Jonathan Corbet
* that appeared in Linux Weekly News.
*/
@@ -55,22 +55,22 @@
* For each service processor the following files are created:
*
* command: execute dot commands
- * write: execute a dot command on the service processor
- * read: return the result of a previously executed dot command
+ * write: execute a dot command on the service processor
+ * read: return the result of a previously executed dot command
*
* events: listen for service processor events
- * read: sleep (interruptible) until an event occurs
+ * read: sleep (interruptible) until an event occurs
* write: wakeup sleeping event listener
*
* reverse_heartbeat: send a heartbeat to the service processor
- * read: sleep (interruptible) until the reverse heartbeat fails
+ * read: sleep (interruptible) until the reverse heartbeat fails
* write: wakeup sleeping heartbeat listener
*
* remote_video/width
* remote_video/height
* remote_video/width: control remote display settings
- * write: set value
- * read: read value
+ * write: set value
+ * read: read value
*/
#include <linux/fs.h>
@@ -155,7 +155,7 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
static struct dentry *ibmasmfs_create_file (struct super_block *sb,
struct dentry *parent,
- const char *name,
+ const char *name,
const struct file_operations *fops,
void *data,
int mode)
@@ -261,7 +261,7 @@ static int command_file_close(struct inode *inode, struct file *file)
struct ibmasmfs_command_data *command_data = file->private_data;
if (command_data->command)
- command_put(command_data->command);
+ command_put(command_data->command);
kfree(command_data);
return 0;
@@ -348,7 +348,7 @@ static ssize_t command_file_write(struct file *file, const char __user *ubuff, s
static int event_file_open(struct inode *inode, struct file *file)
{
struct ibmasmfs_event_data *event_data;
- struct service_processor *sp;
+ struct service_processor *sp;
if (!inode->i_private)
return -ENODEV;
@@ -563,17 +563,16 @@ static ssize_t remote_settings_file_write(struct file *file, const char __user *
if (*offset != 0)
return 0;
- buff = kmalloc (count + 1, GFP_KERNEL);
+ buff = kzalloc (count + 1, GFP_KERNEL);
if (!buff)
return -ENOMEM;
- memset(buff, 0x0, count + 1);
if (copy_from_user(buff, ubuff, count)) {
kfree(buff);
return -EFAULT;
}
-
+
value = simple_strtoul(buff, NULL, 10);
writel(value, address);
kfree(buff);
diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c
index a3c589b7cbfa..4b2398e27fd5 100644
--- a/drivers/misc/ibmasm/lowlevel.c
+++ b/drivers/misc/ibmasm/lowlevel.c
@@ -17,7 +17,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
diff --git a/drivers/misc/ibmasm/lowlevel.h b/drivers/misc/ibmasm/lowlevel.h
index e5ed59c589aa..766766523a60 100644
--- a/drivers/misc/ibmasm/lowlevel.h
+++ b/drivers/misc/ibmasm/lowlevel.h
@@ -17,7 +17,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
@@ -48,9 +48,9 @@
#define INTR_CONTROL_REGISTER 0x13A4
#define SCOUT_COM_A_BASE 0x0000
-#define SCOUT_COM_B_BASE 0x0100
-#define SCOUT_COM_C_BASE 0x0200
-#define SCOUT_COM_D_BASE 0x0300
+#define SCOUT_COM_B_BASE 0x0100
+#define SCOUT_COM_C_BASE 0x0200
+#define SCOUT_COM_D_BASE 0x0300
static inline int sp_interrupt_pending(void __iomem *base_address)
{
@@ -86,12 +86,12 @@ static inline void disable_sp_interrupts(void __iomem *base_address)
static inline void enable_uart_interrupts(void __iomem *base_address)
{
- ibmasm_enable_interrupts(base_address, UART_INTR_MASK);
+ ibmasm_enable_interrupts(base_address, UART_INTR_MASK);
}
static inline void disable_uart_interrupts(void __iomem *base_address)
{
- ibmasm_disable_interrupts(base_address, UART_INTR_MASK);
+ ibmasm_disable_interrupts(base_address, UART_INTR_MASK);
}
#define valid_mfa(mfa) ( (mfa) != NO_MFAS_AVAILABLE )
@@ -111,7 +111,7 @@ static inline u32 get_mfa_outbound(void __iomem *base_address)
static inline void set_mfa_outbound(void __iomem *base_address, u32 mfa)
{
- writel(mfa, base_address + OUTBOUND_QUEUE_PORT);
+ writel(mfa, base_address + OUTBOUND_QUEUE_PORT);
}
static inline u32 get_mfa_inbound(void __iomem *base_address)
@@ -126,7 +126,7 @@ static inline u32 get_mfa_inbound(void __iomem *base_address)
static inline void set_mfa_inbound(void __iomem *base_address, u32 mfa)
{
- writel(mfa, base_address + INBOUND_QUEUE_PORT);
+ writel(mfa, base_address + INBOUND_QUEUE_PORT);
}
static inline struct i2o_message *get_i2o_message(void __iomem *base_address, u32 mfa)
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index 2f3bddfab937..4f9d4a9da983 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -18,9 +18,9 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
- * This driver is based on code originally written by Pete Reynolds
+ * This driver is based on code originally written by Pete Reynolds
* and others.
*
*/
@@ -30,13 +30,13 @@
*
* 1) When loaded it sends a message to the service processor,
* indicating that an OS is * running. This causes the service processor
- * to send periodic heartbeats to the OS.
+ * to send periodic heartbeats to the OS.
*
* 2) Answers the periodic heartbeats sent by the service processor.
* Failure to do so would result in system reboot.
*
* 3) Acts as a pass through for dot commands sent from user applications.
- * The interface for this is the ibmasmfs file system.
+ * The interface for this is the ibmasmfs file system.
*
* 4) Allows user applications to register for event notification. Events
* are sent to the driver through interrupts. They can be read from user
@@ -77,13 +77,12 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
/* vnc client won't work without bus-mastering */
pci_set_master(pdev);
- sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
+ sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
if (sp == NULL) {
dev_err(&pdev->dev, "Failed to allocate memory\n");
result = -ENOMEM;
goto error_kmalloc;
}
- memset(sp, 0, sizeof(struct service_processor));
spin_lock_init(&sp->lock);
INIT_LIST_HEAD(&sp->command_queue);
@@ -105,7 +104,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
}
sp->irq = pdev->irq;
- sp->base_address = ioremap(pci_resource_start(pdev, 0),
+ sp->base_address = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (sp->base_address == 0) {
dev_err(sp->dev, "Failed to ioremap pci memory\n");
diff --git a/drivers/misc/ibmasm/r_heartbeat.c b/drivers/misc/ibmasm/r_heartbeat.c
index f8fdb2d5417e..bec9e2c44bef 100644
--- a/drivers/misc/ibmasm/r_heartbeat.c
+++ b/drivers/misc/ibmasm/r_heartbeat.c
@@ -16,7 +16,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
@@ -36,10 +36,10 @@ static struct {
unsigned char command[3];
} rhb_dot_cmd = {
.header = {
- .type = sp_read,
+ .type = sp_read,
.command_size = 3,
.data_size = 0,
- .status = 0
+ .status = 0
},
.command = { 4, 3, 6 }
};
@@ -76,9 +76,9 @@ int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_
if (cmd->status != IBMASM_CMD_COMPLETE)
times_failed++;
- wait_event_interruptible_timeout(rhb->wait,
+ wait_event_interruptible_timeout(rhb->wait,
rhb->stopped,
- REVERSE_HEARTBEAT_TIMEOUT * HZ);
+ REVERSE_HEARTBEAT_TIMEOUT * HZ);
if (signal_pending(current) || rhb->stopped) {
result = -EINTR;
diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c
index a40fda6c402c..0550ce075fc4 100644
--- a/drivers/misc/ibmasm/remote.c
+++ b/drivers/misc/ibmasm/remote.c
@@ -28,11 +28,10 @@
#include "ibmasm.h"
#include "remote.h"
-static int xmax = 1600;
-static int ymax = 1200;
+#define MOUSE_X_MAX 1600
+#define MOUSE_Y_MAX 1200
-
-static unsigned short xlate_high[XLATE_SIZE] = {
+static const unsigned short xlate_high[XLATE_SIZE] = {
[KEY_SYM_ENTER & 0xff] = KEY_ENTER,
[KEY_SYM_KPSLASH & 0xff] = KEY_KPSLASH,
[KEY_SYM_KPSTAR & 0xff] = KEY_KPASTERISK,
@@ -81,7 +80,8 @@ static unsigned short xlate_high[XLATE_SIZE] = {
[KEY_SYM_NUM_LOCK & 0xff] = KEY_NUMLOCK,
[KEY_SYM_SCR_LOCK & 0xff] = KEY_SCROLLLOCK,
};
-static unsigned short xlate[XLATE_SIZE] = {
+
+static const unsigned short xlate[XLATE_SIZE] = {
[NO_KEYCODE] = KEY_RESERVED,
[KEY_SYM_SPACE] = KEY_SPACE,
[KEY_SYM_TILDE] = KEY_GRAVE, [KEY_SYM_BKTIC] = KEY_GRAVE,
@@ -133,19 +133,16 @@ static unsigned short xlate[XLATE_SIZE] = {
[KEY_SYM_Z] = KEY_Z, [KEY_SYM_z] = KEY_Z,
};
-static char remote_mouse_name[] = "ibmasm RSA I remote mouse";
-static char remote_keybd_name[] = "ibmasm RSA I remote keyboard";
-
static void print_input(struct remote_input *input)
{
if (input->type == INPUT_TYPE_MOUSE) {
unsigned char buttons = input->mouse_buttons;
dbg("remote mouse movement: (x,y)=(%d,%d)%s%s%s%s\n",
input->data.mouse.x, input->data.mouse.y,
- (buttons)?" -- buttons:":"",
- (buttons & REMOTE_BUTTON_LEFT)?"left ":"",
- (buttons & REMOTE_BUTTON_MIDDLE)?"middle ":"",
- (buttons & REMOTE_BUTTON_RIGHT)?"right":""
+ (buttons) ? " -- buttons:" : "",
+ (buttons & REMOTE_BUTTON_LEFT) ? "left " : "",
+ (buttons & REMOTE_BUTTON_MIDDLE) ? "middle " : "",
+ (buttons & REMOTE_BUTTON_RIGHT) ? "right" : ""
);
} else {
dbg("remote keypress (code, flag, down):"
@@ -180,7 +177,7 @@ static void send_keyboard_event(struct input_dev *dev,
key = xlate_high[code & 0xff];
else
key = xlate[code];
- input_report_key(dev, key, (input->data.keyboard.key_down) ? 1 : 0);
+ input_report_key(dev, key, input->data.keyboard.key_down);
input_sync(dev);
}
@@ -228,20 +225,22 @@ int ibmasm_init_remote_input_dev(struct service_processor *sp)
mouse_dev->id.vendor = pdev->vendor;
mouse_dev->id.product = pdev->device;
mouse_dev->id.version = 1;
+ mouse_dev->dev.parent = sp->dev;
mouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
mouse_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) |
BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
set_bit(BTN_TOUCH, mouse_dev->keybit);
- mouse_dev->name = remote_mouse_name;
- input_set_abs_params(mouse_dev, ABS_X, 0, xmax, 0, 0);
- input_set_abs_params(mouse_dev, ABS_Y, 0, ymax, 0, 0);
+ mouse_dev->name = "ibmasm RSA I remote mouse";
+ input_set_abs_params(mouse_dev, ABS_X, 0, MOUSE_X_MAX, 0, 0);
+ input_set_abs_params(mouse_dev, ABS_Y, 0, MOUSE_Y_MAX, 0, 0);
- mouse_dev->id.bustype = BUS_PCI;
+ keybd_dev->id.bustype = BUS_PCI;
keybd_dev->id.vendor = pdev->vendor;
keybd_dev->id.product = pdev->device;
- mouse_dev->id.version = 2;
+ keybd_dev->id.version = 2;
+ keybd_dev->dev.parent = sp->dev;
keybd_dev->evbit[0] = BIT(EV_KEY);
- keybd_dev->name = remote_keybd_name;
+ keybd_dev->name = "ibmasm RSA I remote keyboard";
for (i = 0; i < XLATE_SIZE; i++) {
if (xlate_high[i])
diff --git a/drivers/misc/ibmasm/remote.h b/drivers/misc/ibmasm/remote.h
index b7076a8442d2..72acf5af7a2a 100644
--- a/drivers/misc/ibmasm/remote.h
+++ b/drivers/misc/ibmasm/remote.h
@@ -18,7 +18,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
* Orignally written by Pete Reynolds
*/
@@ -73,7 +73,7 @@ struct keyboard_input {
-struct remote_input {
+struct remote_input {
union {
struct mouse_input mouse;
struct keyboard_input keyboard;
@@ -85,7 +85,7 @@ struct remote_input {
unsigned char pad3;
};
-#define mouse_addr(sp) (sp->base_address + CONDOR_MOUSE_DATA)
+#define mouse_addr(sp) (sp->base_address + CONDOR_MOUSE_DATA)
#define display_width(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESX)
#define display_height(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_RESY)
#define display_depth(sp) (mouse_addr(sp) + CONDOR_INPUT_DISPLAY_BITS)
@@ -93,7 +93,7 @@ struct remote_input {
#define vnc_status(sp) (mouse_addr(sp) + CONDOR_OUTPUT_VNC_STATUS)
#define isr_control(sp) (mouse_addr(sp) + CONDOR_MOUSE_ISR_CONTROL)
-#define mouse_interrupt_pending(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS)
+#define mouse_interrupt_pending(sp) readl(mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS)
#define clear_mouse_interrupt(sp) writel(0, mouse_addr(sp) + CONDOR_MOUSE_ISR_STATUS)
#define enable_mouse_interrupts(sp) writel(1, mouse_addr(sp) + CONDOR_MOUSE_ISR_CONTROL)
#define disable_mouse_interrupts(sp) writel(0, mouse_addr(sp) + CONDOR_MOUSE_ISR_CONTROL)
diff --git a/drivers/misc/ibmasm/uart.c b/drivers/misc/ibmasm/uart.c
index 9783caf49696..93baa350d698 100644
--- a/drivers/misc/ibmasm/uart.c
+++ b/drivers/misc/ibmasm/uart.c
@@ -18,7 +18,7 @@
*
* Copyright (C) IBM Corporation, 2004
*
- * Author: Max Asböck <amax@us.ibm.com>
+ * Author: Max Asböck <amax@us.ibm.com>
*
*/
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 41e901f53e7c..932a415197b3 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -23,6 +23,8 @@
* msi-laptop.c - MSI S270 laptop support. This laptop is sold under
* various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
*
+ * Driver also supports S271, S420 models.
+ *
* This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
*
* lcd_level - Screen brightness: contains a single integer in the
@@ -281,25 +283,56 @@ static struct platform_device *msipf_device;
/* Initialization */
+static int dmi_check_cb(struct dmi_system_id *id)
+{
+ printk("msi-laptop: Identified laptop model '%s'.\n", id->ident);
+ return 0;
+}
+
static struct dmi_system_id __initdata msi_dmi_table[] = {
{
.ident = "MSI S270",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
- }
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
+ DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "MSI S271",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-1058"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0581"),
+ DMI_MATCH(DMI_BOARD_NAME, "MS-1058")
+ },
+ .callback = dmi_check_cb
+ },
+ {
+ .ident = "MSI S420",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-1412"),
+ DMI_MATCH(DMI_BOARD_VENDOR, "MSI"),
+ DMI_MATCH(DMI_BOARD_NAME, "MS-1412")
+ },
+ .callback = dmi_check_cb
},
{
.ident = "Medion MD96100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
- }
+ DMI_MATCH(DMI_PRODUCT_VERSION, "0131"),
+ DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR INT'L CO.,LTD")
+ },
+ .callback = dmi_check_cb
},
{ }
};
-
static int __init msi_init(void)
{
int ret;
@@ -394,3 +427,8 @@ MODULE_AUTHOR("Lennart Poettering");
MODULE_DESCRIPTION("MSI Laptop Support");
MODULE_VERSION(MSI_DRIVER_VERSION);
MODULE_LICENSE("GPL");
+
+MODULE_ALIAS("dmi:*:svnMICRO-STARINT'LCO.,LTD:pnMS-1013:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
+MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1058:pvr0581:rvnMSI:rnMS-1058:*:ct10:*");
+MODULE_ALIAS("dmi:*:svnMicro-StarInternational:pnMS-1412:*:rvnMSI:rnMS-1412:*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
+MODULE_ALIAS("dmi:*:svnNOTEBOOK:pnSAM2000:pvr0131*:cvnMICRO-STARINT'LCO.,LTD:ct10:*");
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 8ee0321ef1c8..303e48ca0e8a 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -142,43 +142,124 @@ struct sony_laptop_keypress {
int key;
};
-/* Correspondance table between sonypi events and input layer events */
-static struct {
- int sonypiev;
- int inputev;
-} sony_laptop_inputkeys[] = {
- { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
- { SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
- { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
- { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
- { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
- { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
- { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
- { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
- { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
- { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
- { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
- { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
- { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
- { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
- { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
- { SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
- { SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
- { SONYPI_EVENT_FNKEY_D, KEY_FN_D },
- { SONYPI_EVENT_FNKEY_E, KEY_FN_E },
- { SONYPI_EVENT_FNKEY_F, KEY_FN_F },
- { SONYPI_EVENT_FNKEY_S, KEY_FN_S },
- { SONYPI_EVENT_FNKEY_B, KEY_FN_B },
- { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
- { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
- { SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
- { SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
- { SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
- { SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
- { SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
- { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
- { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
- { 0, 0 },
+/* Correspondance table between sonypi events
+ * and input layer indexes in the keymap
+ */
+static int sony_laptop_input_index[] = {
+ -1, /* no event */
+ -1, /* SONYPI_EVENT_JOGDIAL_DOWN */
+ -1, /* SONYPI_EVENT_JOGDIAL_UP */
+ -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+ -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+ -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */
+ -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */
+ 0, /* SONYPI_EVENT_CAPTURE_PRESSED */
+ 1, /* SONYPI_EVENT_CAPTURE_RELEASED */
+ 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+ 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+ 4, /* SONYPI_EVENT_FNKEY_ESC */
+ 5, /* SONYPI_EVENT_FNKEY_F1 */
+ 6, /* SONYPI_EVENT_FNKEY_F2 */
+ 7, /* SONYPI_EVENT_FNKEY_F3 */
+ 8, /* SONYPI_EVENT_FNKEY_F4 */
+ 9, /* SONYPI_EVENT_FNKEY_F5 */
+ 10, /* SONYPI_EVENT_FNKEY_F6 */
+ 11, /* SONYPI_EVENT_FNKEY_F7 */
+ 12, /* SONYPI_EVENT_FNKEY_F8 */
+ 13, /* SONYPI_EVENT_FNKEY_F9 */
+ 14, /* SONYPI_EVENT_FNKEY_F10 */
+ 15, /* SONYPI_EVENT_FNKEY_F11 */
+ 16, /* SONYPI_EVENT_FNKEY_F12 */
+ 17, /* SONYPI_EVENT_FNKEY_1 */
+ 18, /* SONYPI_EVENT_FNKEY_2 */
+ 19, /* SONYPI_EVENT_FNKEY_D */
+ 20, /* SONYPI_EVENT_FNKEY_E */
+ 21, /* SONYPI_EVENT_FNKEY_F */
+ 22, /* SONYPI_EVENT_FNKEY_S */
+ 23, /* SONYPI_EVENT_FNKEY_B */
+ 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */
+ 25, /* SONYPI_EVENT_PKEY_P1 */
+ 26, /* SONYPI_EVENT_PKEY_P2 */
+ 27, /* SONYPI_EVENT_PKEY_P3 */
+ 28, /* SONYPI_EVENT_BACK_PRESSED */
+ -1, /* SONYPI_EVENT_LID_CLOSED */
+ -1, /* SONYPI_EVENT_LID_OPENED */
+ 29, /* SONYPI_EVENT_BLUETOOTH_ON */
+ 30, /* SONYPI_EVENT_BLUETOOTH_OFF */
+ 31, /* SONYPI_EVENT_HELP_PRESSED */
+ 32, /* SONYPI_EVENT_FNKEY_ONLY */
+ 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+ 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */
+ 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+ 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+ 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+ 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
+ 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+ 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+ 41, /* SONYPI_EVENT_ZOOM_PRESSED */
+ 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
+ 43, /* SONYPI_EVENT_MEYE_FACE */
+ 44, /* SONYPI_EVENT_MEYE_OPPOSITE */
+ 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */
+ 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */
+ -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */
+ -1, /* SONYPI_EVENT_BATTERY_INSERT */
+ -1, /* SONYPI_EVENT_BATTERY_REMOVE */
+ -1, /* SONYPI_EVENT_FNKEY_RELEASED */
+ 47, /* SONYPI_EVENT_WIRELESS_ON */
+ 48, /* SONYPI_EVENT_WIRELESS_OFF */
+};
+
+static int sony_laptop_input_keycode_map[] = {
+ KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */
+ KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */
+ KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+ KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+ KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */
+ KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */
+ KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */
+ KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */
+ KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */
+ KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */
+ KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */
+ KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */
+ KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */
+ KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */
+ KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */
+ KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */
+ KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */
+ KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */
+ KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */
+ KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */
+ KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */
+ KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */
+ KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */
+ KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */
+ KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
+ KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */
+ KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */
+ KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */
+ KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */
+ KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */
+ KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */
+ KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */
+ KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */
+ KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+ KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
+ KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+ KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+ KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+ KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+ KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+ KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+ KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */
+ BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+ KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */
+ KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */
+ KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
+ KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
+ KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
+ KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */
};
/* release buttons after a short delay if pressed */
@@ -202,7 +283,6 @@ static void sony_laptop_report_input_event(u8 event)
struct input_dev *jog_dev = sony_laptop_input.jog_dev;
struct input_dev *key_dev = sony_laptop_input.key_dev;
struct sony_laptop_keypress kp = { NULL };
- int i;
if (event == SONYPI_EVENT_FNKEY_RELEASED) {
/* Nothing, not all VAIOs generate this event */
@@ -231,17 +311,22 @@ static void sony_laptop_report_input_event(u8 event)
break;
default:
- for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
- if (event == sony_laptop_inputkeys[i].sonypiev) {
+ if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
+ dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
+ break;
+ }
+ if (sony_laptop_input_index[event] != -1) {
+ kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+ if (kp.key != KEY_UNKNOWN)
kp.dev = key_dev;
- kp.key = sony_laptop_inputkeys[i].inputev;
- break;
- }
+ }
break;
}
if (kp.dev) {
input_report_key(kp.dev, kp.key, 1);
+ /* we emit the scancode so we can always remap the key */
+ input_event(kp.dev, EV_MSC, MSC_SCAN, event);
input_sync(kp.dev);
kfifo_put(sony_laptop_input.fifo,
(unsigned char *)&kp, sizeof(kp));
@@ -296,11 +381,18 @@ static int sony_laptop_setup_input(void)
key_dev->id.vendor = PCI_VENDOR_ID_SONY;
/* Initialize the Input Drivers: special keys */
- key_dev->evbit[0] = BIT(EV_KEY);
- for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
- if (sony_laptop_inputkeys[i].inputev)
- set_bit(sony_laptop_inputkeys[i].inputev,
- key_dev->keybit);
+ set_bit(EV_KEY, key_dev->evbit);
+ set_bit(EV_MSC, key_dev->evbit);
+ set_bit(MSC_SCAN, key_dev->mscbit);
+ key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
+ key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
+ key_dev->keycode = &sony_laptop_input_keycode_map;
+ for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
+ if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
+ set_bit(sony_laptop_input_keycode_map[i],
+ key_dev->keybit);
+ }
+ }
error = input_register_device(key_dev);
if (error)
@@ -487,6 +579,14 @@ SNC_HANDLE_NAMES(audiopower_set, "AZPW");
SNC_HANDLE_NAMES(lanpower_get, "GLNP");
SNC_HANDLE_NAMES(lanpower_set, "LNPW");
+SNC_HANDLE_NAMES(lidstate_get, "GLID");
+
+SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
+SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
+
+SNC_HANDLE_NAMES(gainbass_get, "GMGB");
+SNC_HANDLE_NAMES(gainbass_set, "CMGB");
+
SNC_HANDLE_NAMES(PID_get, "GPID");
SNC_HANDLE_NAMES(CTR_get, "GCTR");
@@ -507,6 +607,12 @@ static struct sony_nc_value sony_nc_values[] = {
boolean_validate, 0),
SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
boolean_validate, 1),
+ SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
+ boolean_validate, 0),
+ SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
+ boolean_validate, 0),
+ SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
+ boolean_validate, 0),
/* unknown methods */
SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
@@ -689,13 +795,116 @@ static struct backlight_ops sony_backlight_ops = {
};
/*
+ * New SNC-only Vaios event mapping to driver known keys
+ */
+struct sony_nc_event {
+ u8 data;
+ u8 event;
+};
+
+static struct sony_nc_event *sony_nc_events;
+
+/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
+ * for Fn keys
+ */
+static int sony_nc_C_enable(struct dmi_system_id *id)
+{
+ int result = 0;
+
+ printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident);
+
+ sony_nc_events = id->driver_data;
+
+ if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0
+ || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) {
+ printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some "
+ "functionalities may be missing\n");
+ return 1;
+ }
+ return 0;
+}
+
+static struct sony_nc_event sony_C_events[] = {
+ { 0x81, SONYPI_EVENT_FNKEY_F1 },
+ { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x85, SONYPI_EVENT_FNKEY_F5 },
+ { 0x05, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x86, SONYPI_EVENT_FNKEY_F6 },
+ { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x87, SONYPI_EVENT_FNKEY_F7 },
+ { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x8A, SONYPI_EVENT_FNKEY_F10 },
+ { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0x8C, SONYPI_EVENT_FNKEY_F12 },
+ { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
+ { 0, 0 },
+};
+
+/* SNC-only model map */
+struct dmi_system_id sony_nc_ids[] = {
+ {
+ .ident = "Sony Vaio FE Series",
+ .callback = sony_nc_C_enable,
+ .driver_data = sony_C_events,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"),
+ },
+ },
+ {
+ .ident = "Sony Vaio C Series",
+ .callback = sony_nc_C_enable,
+ .driver_data = sony_C_events,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
+ },
+ },
+ { }
+};
+
+/*
* ACPI callbacks
*/
static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
{
- dprintk("sony_acpi_notify, event: %d\n", event);
- sony_laptop_report_input_event(event);
- acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
+ struct sony_nc_event *evmap;
+ u32 ev = event;
+ int result;
+
+ if (ev == 0x92) {
+ /* read the key pressed from EC.GECR
+ * A call to SN07 with 0x0202 will do it as well respecting
+ * the current protocol on different OSes
+ *
+ * Note: the path for GECR may be
+ * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends)
+ * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR)
+ *
+ * TODO: we may want to do the same for the older GHKE -need
+ * dmi list- so this snippet may become one more callback.
+ */
+ if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0)
+ dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev);
+ else
+ ev = result & 0xFF;
+ }
+
+ if (sony_nc_events)
+ for (evmap = sony_nc_events; evmap->event; evmap++) {
+ if (evmap->data == ev) {
+ ev = evmap->event;
+ break;
+ }
+ }
+
+ dprintk("sony_acpi_notify, event: 0x%.2x\n", ev);
+ sony_laptop_report_input_event(ev);
+ acpi_bus_generate_event(sony_nc_acpi_device, 1, ev);
}
static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -732,6 +941,10 @@ static int sony_nc_resume(struct acpi_device *device)
break;
}
}
+
+ /* re-initialize models with specific requirements */
+ dmi_check_system(sony_nc_ids);
+
return 0;
}
@@ -750,6 +963,15 @@ static int sony_nc_add(struct acpi_device *device)
sony_nc_acpi_handle = device->handle;
+ /* read device status */
+ result = acpi_bus_get_status(device);
+ /* bail IFF the above call was successful and the device is not present */
+ if (!result && !device->status.present) {
+ dprintk("Device not present\n");
+ result = -ENODEV;
+ goto outwalk;
+ }
+
if (debug) {
status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
1, sony_walk_callback, NULL, NULL);
@@ -760,6 +982,15 @@ static int sony_nc_add(struct acpi_device *device)
}
}
+ /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1
+ * should be respected as we already checked for the device presence above */
+ if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
+ dprintk("Invoking _INI\n");
+ if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
+ NULL, NULL)))
+ dprintk("_INI Method failed\n");
+ }
+
/* setup input devices and helper fifo */
result = sony_laptop_setup_input();
if (result) {
@@ -772,7 +1003,7 @@ static int sony_nc_add(struct acpi_device *device)
ACPI_DEVICE_NOTIFY,
sony_acpi_notify, NULL);
if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
+ printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status);
result = -ENODEV;
goto outinput;
}
@@ -795,6 +1026,9 @@ static int sony_nc_add(struct acpi_device *device)
}
+ /* initialize models with specific requirements */
+ dmi_check_system(sony_nc_ids);
+
result = sony_pf_add();
if (result)
goto outbacklight;
@@ -908,7 +1142,9 @@ static struct acpi_driver sony_nc_driver = {
#define SONYPI_DEVICE_TYPE2 0x00000002
#define SONYPI_DEVICE_TYPE3 0x00000004
-#define SONY_PIC_EV_MASK 0xff
+#define SONYPI_TYPE1_OFFSET 0x04
+#define SONYPI_TYPE2_OFFSET 0x12
+#define SONYPI_TYPE3_OFFSET 0x12
struct sony_pic_ioport {
struct acpi_resource_io io;
@@ -922,6 +1158,7 @@ struct sony_pic_irq {
struct sony_pic_dev {
int model;
+ u16 evport_offset;
u8 camera_power;
u8 bluetooth_power;
u8 wwan_power;
@@ -1917,7 +2154,8 @@ end:
*/
static int sony_pic_disable(struct acpi_device *device)
{
- if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL)))
+ if (ACPI_FAILURE(acpi_evaluate_object(device->handle,
+ "_DIS", NULL, NULL)))
return -ENXIO;
dprintk("Device disabled\n");
@@ -1998,20 +2236,17 @@ end:
static irqreturn_t sony_pic_irq(int irq, void *dev_id)
{
int i, j;
- u32 port_val = 0;
u8 ev = 0;
u8 data_mask = 0;
u8 device_event = 0;
struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
- acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
- dev->cur_ioport->io.address_length);
- ev = port_val & SONY_PIC_EV_MASK;
- data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+ ev = inb_p(dev->cur_ioport->io.minimum);
+ data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
- dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
- port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+ dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
+ ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
if (ev == 0x00 || ev == 0xff)
return IRQ_HANDLED;
@@ -2102,6 +2337,20 @@ static int sony_pic_add(struct acpi_device *device)
spic_dev.model = sony_pic_detect_device_type();
mutex_init(&spic_dev.lock);
+ /* model specific characteristics */
+ switch(spic_dev.model) {
+ case SONYPI_DEVICE_TYPE1:
+ spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
+ break;
+ case SONYPI_DEVICE_TYPE3:
+ spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
+ break;
+ case SONYPI_DEVICE_TYPE2:
+ default:
+ spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
+ break;
+ }
+
/* read _PRS resources */
result = sony_pic_possible_resources(device);
if (result) {
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 95c0b96e83f2..f15a58f7403f 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,8 +21,8 @@
* 02110-1301, USA.
*/
-#define IBM_VERSION "0.14"
-#define TPACPI_SYSFS_VERSION 0x000100
+#define IBM_VERSION "0.15"
+#define TPACPI_SYSFS_VERSION 0x010000
/*
* Changelog:
@@ -92,6 +92,29 @@ MODULE_LICENSE("GPL");
/* Please remove this in year 2009 */
MODULE_ALIAS("ibm_acpi");
+/*
+ * DMI matching for module autoloading
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ *
+ * Only models listed in thinkwiki will be supported, so add yours
+ * if it is not there yet.
+ */
+#define IBM_BIOS_MODULE_ALIAS(__type) \
+ MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
+
+/* Non-ancient thinkpads */
+MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
+MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+
+/* Ancient thinkpad BIOSes have to be identified by
+ * BIOS type or model number, and there are far less
+ * BIOS types than model numbers... */
+IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
+IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
+IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+
#define __unused __attribute__ ((unused))
/****************************************************************************
@@ -106,7 +129,7 @@ MODULE_ALIAS("ibm_acpi");
* ACPI basic handles
*/
-static acpi_handle root_handle = NULL;
+static acpi_handle root_handle;
#define IBM_HANDLE(object, parent, paths...) \
static acpi_handle object##_handle; \
@@ -487,19 +510,36 @@ static char *next_cmd(char **cmds)
/****************************************************************************
****************************************************************************
*
- * Device model: hwmon and platform
+ * Device model: input, hwmon and platform
*
****************************************************************************
****************************************************************************/
-static struct platform_device *tpacpi_pdev = NULL;
-static struct class_device *tpacpi_hwmon = NULL;
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct input_dev *tpacpi_inputdev;
+
+
+static int tpacpi_resume_handler(struct platform_device *pdev)
+{
+ struct ibm_struct *ibm, *itmp;
+
+ list_for_each_entry_safe(ibm, itmp,
+ &tpacpi_all_drivers,
+ all_drivers) {
+ if (ibm->resume)
+ (ibm->resume)();
+ }
+
+ return 0;
+}
static struct platform_driver tpacpi_pdriver = {
.driver = {
.name = IBM_DRVR_NAME,
.owner = THIS_MODULE,
},
+ .resume = tpacpi_resume_handler,
};
@@ -677,9 +717,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
printk(IBM_INFO "%s\n", IBM_URL);
- if (ibm_thinkpad_ec_found)
- printk(IBM_INFO "ThinkPad EC firmware %s\n",
- ibm_thinkpad_ec_found);
+ printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+ (thinkpad_id.bios_version_str) ?
+ thinkpad_id.bios_version_str : "unknown",
+ (thinkpad_id.ec_version_str) ?
+ thinkpad_id.ec_version_str : "unknown");
+
+ if (thinkpad_id.vendor && thinkpad_id.model_str)
+ printk(IBM_INFO "%s %s\n",
+ (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
+ "IBM" : ((thinkpad_id.vendor ==
+ PCI_VENDOR_ID_LENOVO) ?
+ "Lenovo" : "Unknown vendor"),
+ thinkpad_id.model_str);
return 0;
}
@@ -704,16 +754,28 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
*/
static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
+static u32 hotkey_all_mask;
+static u32 hotkey_reserved_mask;
+
+static u16 *hotkey_keycode_map;
-static struct attribute_set *hotkey_dev_attributes = NULL;
+static struct attribute_set *hotkey_dev_attributes;
+
+static int hotkey_get_wlsw(int *status)
+{
+ if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
+ return -EIO;
+ return 0;
+}
/* sysfs hotkey enable ------------------------------------------------- */
static ssize_t hotkey_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
res = hotkey_get(&status, &mask);
if (res)
@@ -727,7 +789,8 @@ static ssize_t hotkey_enable_store(struct device *dev,
const char *buf, size_t count)
{
unsigned long t;
- int res, status, mask;
+ int res, status;
+ u32 mask;
if (parse_strtoul(buf, 1, &t))
return -EINVAL;
@@ -748,13 +811,14 @@ static ssize_t hotkey_mask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
res = hotkey_get(&status, &mask);
if (res)
return res;
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
}
static ssize_t hotkey_mask_store(struct device *dev,
@@ -762,9 +826,10 @@ static ssize_t hotkey_mask_store(struct device *dev,
const char *buf, size_t count)
{
unsigned long t;
- int res, status, mask;
+ int res, status;
+ u32 mask;
- if (parse_strtoul(buf, 0xffff, &t))
+ if (parse_strtoul(buf, 0xffffffffUL, &t))
return -EINVAL;
res = hotkey_get(&status, &mask);
@@ -794,26 +859,123 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
}
static struct device_attribute dev_attr_hotkey_bios_mask =
__ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
+/* sysfs hotkey all_mask ----------------------------------------------- */
+static ssize_t hotkey_all_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_all_mask =
+ __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
+
+/* sysfs hotkey recommended_mask --------------------------------------- */
+static ssize_t hotkey_recommended_mask_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+ hotkey_all_mask & ~hotkey_reserved_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_recommended_mask =
+ __ATTR(hotkey_recommended_mask, S_IRUGO,
+ hotkey_recommended_mask_show, NULL);
+
+/* sysfs hotkey radio_sw ----------------------------------------------- */
+static ssize_t hotkey_radio_sw_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, s;
+ res = hotkey_get_wlsw(&s);
+ if (res < 0)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_radio_sw =
+ __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+
/* --------------------------------------------------------------------- */
static struct attribute *hotkey_mask_attributes[] = {
&dev_attr_hotkey_mask.attr,
&dev_attr_hotkey_bios_enabled.attr,
&dev_attr_hotkey_bios_mask.attr,
+ &dev_attr_hotkey_all_mask.attr,
+ &dev_attr_hotkey_recommended_mask.attr,
};
static int __init hotkey_init(struct ibm_init_struct *iibm)
{
- int res;
+
+ static u16 ibm_keycode_map[] __initdata = {
+ /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+ KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
+ KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+ KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
+ /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
+ KEY_UNKNOWN, /* 0x0D: FN+INSERT */
+ KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+ KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
+ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+ KEY_RESERVED, /* 0x10: FN+END (brightness down) */
+ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
+ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
+ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
+ KEY_RESERVED, /* 0x14: VOLUME UP */
+ KEY_RESERVED, /* 0x15: VOLUME DOWN */
+ KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
+ /* (assignments unknown, please report if found) */
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ };
+ static u16 lenovo_keycode_map[] __initdata = {
+ /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+ KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
+ KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+ KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
+ /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+ KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
+ KEY_UNKNOWN, /* 0x0D: FN+INSERT */
+ KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+ KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
+ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+ KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
+ KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
+ KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
+ KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
+ KEY_RESERVED, /* 0x14: VOLUME UP */
+ KEY_RESERVED, /* 0x15: VOLUME DOWN */
+ KEY_RESERVED, /* 0x16: MUTE */
+ KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
+ /* (assignments unknown, please report if found) */
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+ };
+
+#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0])
+
+ int res, i;
+ int status;
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
+ BUG_ON(!tpacpi_inputdev);
+
IBM_ACPIHANDLE_INIT(hkey);
mutex_init(&hotkey_mutex);
@@ -824,7 +986,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
str_supported(tp_features.hotkey));
if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(4, NULL);
+ hotkey_dev_attributes = create_attr_set(7, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
res = add_to_attr_set(hotkey_dev_attributes,
@@ -840,19 +1002,92 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
str_supported(tp_features.hotkey_mask));
+ if (tp_features.hotkey_mask) {
+ /* MHKA available in A31, R40, R40e, T4x, X31, and later */
+ if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+ "MHKA", "qd"))
+ hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+ }
+
res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
if (!res && tp_features.hotkey_mask) {
res = add_many_to_attr_set(hotkey_dev_attributes,
hotkey_mask_attributes,
ARRAY_SIZE(hotkey_mask_attributes));
}
+
+ /* Not all thinkpads have a hardware radio switch */
+ if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+ tp_features.hotkey_wlsw = 1;
+ printk(IBM_INFO
+ "radio switch found; radios are %s\n",
+ enabled(status, 0));
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_radio_sw.attr);
+ }
+
if (!res)
res = register_attr_set_with_sysfs(
hotkey_dev_attributes,
&tpacpi_pdev->dev.kobj);
+ if (res)
+ return res;
+
+ /* Set up key map */
+
+ hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
+ GFP_KERNEL);
+ if (!hotkey_keycode_map) {
+ printk(IBM_ERR "failed to allocate memory for key map\n");
+ return -ENOMEM;
+ }
+
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "using Lenovo default hot key map\n");
+ memcpy(hotkey_keycode_map, &lenovo_keycode_map,
+ TPACPI_HOTKEY_MAP_SIZE);
+ } else {
+ dbg_printk(TPACPI_DBG_INIT,
+ "using IBM default hot key map\n");
+ memcpy(hotkey_keycode_map, &ibm_keycode_map,
+ TPACPI_HOTKEY_MAP_SIZE);
+ }
+#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
+ for (i = 0; i < 12; i++)
+ hotkey_keycode_map[i] = KEY_UNKNOWN;
+#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
+
+ set_bit(EV_KEY, tpacpi_inputdev->evbit);
+ set_bit(EV_MSC, tpacpi_inputdev->evbit);
+ set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
+ tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+ tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+ tpacpi_inputdev->keycode = hotkey_keycode_map;
+ for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+ if (hotkey_keycode_map[i] != KEY_RESERVED) {
+ set_bit(hotkey_keycode_map[i],
+ tpacpi_inputdev->keybit);
+ } else {
+ if (i < sizeof(hotkey_reserved_mask)*8)
+ hotkey_reserved_mask |= 1 << i;
+ }
+ }
+
+ if (tp_features.hotkey_wlsw) {
+ set_bit(EV_SW, tpacpi_inputdev->evbit);
+ set_bit(SW_RADIO, tpacpi_inputdev->swbit);
+ }
+
+#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
+ dbg_printk(TPACPI_DBG_INIT,
+ "enabling hot key handling\n");
+ res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
+ | hotkey_orig_mask);
if (res)
return res;
+#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
}
return (tp_features.hotkey)? 0 : 1;
@@ -875,22 +1110,101 @@ static void hotkey_exit(void)
}
}
+static void tpacpi_input_send_key(unsigned int scancode,
+ unsigned int keycode)
+{
+ if (keycode != KEY_RESERVED) {
+ input_report_key(tpacpi_inputdev, keycode, 1);
+ if (keycode == KEY_UNKNOWN)
+ input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+ scancode);
+ input_sync(tpacpi_inputdev);
+
+ input_report_key(tpacpi_inputdev, keycode, 0);
+ if (keycode == KEY_UNKNOWN)
+ input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+ scancode);
+ input_sync(tpacpi_inputdev);
+ }
+}
+
+static void tpacpi_input_send_radiosw(void)
+{
+ int wlsw;
+
+ if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+ input_report_switch(tpacpi_inputdev,
+ SW_RADIO, !!wlsw);
+}
+
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
{
- int hkey;
+ u32 hkey;
+ unsigned int keycode, scancode;
+ int sendacpi = 1;
+
+ if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+ if (tpacpi_inputdev->users > 0) {
+ switch (hkey >> 12) {
+ case 1:
+ /* 0x1000-0x1FFF: key presses */
+ scancode = hkey & 0xfff;
+ if (scancode > 0 && scancode < 0x21) {
+ scancode--;
+ keycode = hotkey_keycode_map[scancode];
+ tpacpi_input_send_key(scancode, keycode);
+ sendacpi = (keycode == KEY_RESERVED
+ || keycode == KEY_UNKNOWN);
+ } else {
+ printk(IBM_ERR
+ "hotkey 0x%04x out of range for keyboard map\n",
+ hkey);
+ }
+ break;
+ case 5:
+ /* 0x5000-0x5FFF: LID */
+ /* we don't handle it through this path, just
+ * eat up known LID events */
+ if (hkey != 0x5001 && hkey != 0x5002) {
+ printk(IBM_ERR
+ "unknown LID-related hotkey event: 0x%04x\n",
+ hkey);
+ }
+ break;
+ case 7:
+ /* 0x7000-0x7FFF: misc */
+ if (tp_features.hotkey_wlsw && hkey == 0x7000) {
+ tpacpi_input_send_radiosw();
+ sendacpi = 0;
+ break;
+ }
+ /* fallthrough to default */
+ default:
+ /* case 2: dock-related */
+ /* 0x2305 - T43 waking up due to bay lever eject while aslept */
+ /* case 3: ultra-bay related. maybe bay in dock? */
+ /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
+ printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey);
+ }
+ }
- if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
- acpi_bus_generate_event(ibm->acpi->device, event, hkey);
- else {
- printk(IBM_ERR "unknown hotkey event %d\n", event);
+ if (sendacpi)
+ acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+ } else {
+ printk(IBM_ERR "unknown hotkey notification event %d\n", event);
acpi_bus_generate_event(ibm->acpi->device, event, 0);
}
}
+static void hotkey_resume(void)
+{
+ tpacpi_input_send_radiosw();
+}
+
/*
* Call with hotkey_mutex held
*/
-static int hotkey_get(int *status, int *mask)
+static int hotkey_get(int *status, u32 *mask)
{
if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
return -EIO;
@@ -905,7 +1219,7 @@ static int hotkey_get(int *status, int *mask)
/*
* Call with hotkey_mutex held
*/
-static int hotkey_set(int status, int mask)
+static int hotkey_set(int status, u32 mask)
{
int i;
@@ -926,7 +1240,8 @@ static int hotkey_set(int status, int mask)
/* procfs -------------------------------------------------------------- */
static int hotkey_read(char *p)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
int len = 0;
if (!tp_features.hotkey) {
@@ -944,7 +1259,7 @@ static int hotkey_read(char *p)
len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
if (tp_features.hotkey_mask) {
- len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+ len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
len += sprintf(p + len,
"commands:\tenable, disable, reset, <mask>\n");
} else {
@@ -957,7 +1272,8 @@ static int hotkey_read(char *p)
static int hotkey_write(char *buf)
{
- int res, status, mask;
+ int res, status;
+ u32 mask;
char *cmd;
int do_cmd = 0;
@@ -1012,6 +1328,7 @@ static struct ibm_struct hotkey_driver_data = {
.read = hotkey_read,
.write = hotkey_write,
.exit = hotkey_exit,
+ .resume = hotkey_resume,
.acpi = &ibm_hotkey_acpidriver,
};
@@ -1770,7 +2087,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
.type = ACPI_SYSTEM_NOTIFY,
},
{
- .hid = IBM_PCI_HID,
+ /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
+ * We just use it to get notifications of dock hotplug
+ * in very old thinkpads */
+ .hid = PCI_ROOT_HID_STRING,
.notify = dock_notify,
.handle = &pci_handle,
.type = ACPI_SYSTEM_NOTIFY,
@@ -1829,7 +2149,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
static void dock_notify(struct ibm_struct *ibm, u32 event)
{
int docked = dock_docked();
- int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+ int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING);
if (event == 1 && !pci) /* 570 */
acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
@@ -2389,7 +2709,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
- if (ibm_thinkpad_ec_found && experimental) {
+ if (thinkpad_id.ec_model) {
/*
* Direct EC access mode: sensors at registers
* 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
@@ -2533,6 +2853,8 @@ static int thermal_get_sensor(int idx, s32 *value)
snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
return -EIO;
+ if (t > 127 || t < -127)
+ t = TP_EC_THERMAL_TMP_NA;
*value = t * 1000;
return 0;
}
@@ -2671,22 +2993,39 @@ static struct ibm_struct ecdump_driver_data = {
* Backlight/brightness subdriver
*/
-static struct backlight_device *ibm_backlight_device = NULL;
+static struct backlight_device *ibm_backlight_device;
static struct backlight_ops ibm_backlight_data = {
.get_brightness = brightness_get,
.update_status = brightness_update_status,
};
+static struct mutex brightness_mutex;
+
static int __init brightness_init(struct ibm_init_struct *iibm)
{
int b;
vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+ mutex_init(&brightness_mutex);
+
+ if (!brightness_mode) {
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
+ brightness_mode = 2;
+ else
+ brightness_mode = 3;
+
+ dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+ brightness_mode);
+ }
+
+ if (brightness_mode > 3)
+ return -EINVAL;
+
b = brightness_get(NULL);
if (b < 0)
- return b;
+ return 1;
ibm_backlight_device = backlight_device_register(
TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2722,34 +3061,79 @@ static int brightness_update_status(struct backlight_device *bd)
bd->props.brightness : 0);
}
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
static int brightness_get(struct backlight_device *bd)
{
- u8 level;
- if (!acpi_ec_read(brightness_offset, &level))
- return -EIO;
+ u8 lec = 0, lcmos = 0, level = 0;
- level &= 0x7;
+ if (brightness_mode & 1) {
+ if (!acpi_ec_read(brightness_offset, &lec))
+ return -EIO;
+ lec &= 7;
+ level = lec;
+ };
+ if (brightness_mode & 2) {
+ lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+ & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+ >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+ level = lcmos;
+ }
+
+ if (brightness_mode == 3 && lec != lcmos) {
+ printk(IBM_ERR
+ "CMOS NVRAM (%u) and EC (%u) do not agree "
+ "on display brightness level\n",
+ (unsigned int) lcmos,
+ (unsigned int) lec);
+ return -EIO;
+ }
return level;
}
static int brightness_set(int value)
{
- int cmos_cmd, inc, i;
- int current_value = brightness_get(NULL);
+ int cmos_cmd, inc, i, res;
+ int current_value;
+
+ if (value > 7)
+ return -EINVAL;
- value &= 7;
+ res = mutex_lock_interruptible(&brightness_mutex);
+ if (res < 0)
+ return res;
+
+ current_value = brightness_get(NULL);
+ if (current_value < 0) {
+ res = current_value;
+ goto errout;
+ }
- cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+ cmos_cmd = value > current_value ?
+ TP_CMOS_BRIGHTNESS_UP :
+ TP_CMOS_BRIGHTNESS_DOWN;
inc = value > current_value ? 1 : -1;
+
+ res = 0;
for (i = current_value; i != value; i += inc) {
- if (issue_thinkpad_cmos_command(cmos_cmd))
- return -EIO;
- if (!acpi_ec_write(brightness_offset, i + inc))
- return -EIO;
+ if ((brightness_mode & 2) &&
+ issue_thinkpad_cmos_command(cmos_cmd)) {
+ res = -EIO;
+ goto errout;
+ }
+ if ((brightness_mode & 1) &&
+ !acpi_ec_write(brightness_offset, i + inc)) {
+ res = -EIO;
+ goto errout;;
+ }
}
- return 0;
+errout:
+ mutex_unlock(&brightness_mutex);
+ return res;
}
static int brightness_read(char *p)
@@ -3273,20 +3657,19 @@ static int __init fan_init(struct ibm_init_struct *iibm)
* Enable for TP-1Y (T43), TP-78 (R51e),
* TP-76 (R52), TP-70 (T43, R52), which are known
* to be buggy. */
- if (fan_control_initial_status == 0x07 &&
- ibm_thinkpad_ec_found &&
- ((ibm_thinkpad_ec_found[0] == '1' &&
- ibm_thinkpad_ec_found[1] == 'Y') ||
- (ibm_thinkpad_ec_found[0] == '7' &&
- (ibm_thinkpad_ec_found[1] == '6' ||
- ibm_thinkpad_ec_found[1] == '8' ||
- ibm_thinkpad_ec_found[1] == '0'))
- )) {
- printk(IBM_NOTICE
- "fan_init: initial fan status is "
- "unknown, assuming it is in auto "
- "mode\n");
- tp_features.fan_ctrl_status_undef = 1;
+ if (fan_control_initial_status == 0x07) {
+ switch (thinkpad_id.ec_model) {
+ case 0x5931: /* TP-1Y */
+ case 0x3837: /* TP-78 */
+ case 0x3637: /* TP-76 */
+ case 0x3037: /* TP-70 */
+ printk(IBM_NOTICE
+ "fan_init: initial fan status is "
+ "unknown, assuming it is in auto "
+ "mode\n");
+ tp_features.fan_ctrl_status_undef = 1;
+ ;;
+ }
}
} else {
printk(IBM_ERR
@@ -3474,7 +3857,7 @@ static void fan_watchdog_fire(struct work_struct *ignored)
static void fan_watchdog_reset(void)
{
- static int fan_watchdog_active = 0;
+ static int fan_watchdog_active;
if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
return;
@@ -3877,7 +4260,7 @@ static struct ibm_struct fan_driver_data = {
****************************************************************************/
/* /proc support */
-static struct proc_dir_entry *proc_dir = NULL;
+static struct proc_dir_entry *proc_dir;
/* Subdriver registry */
static LIST_HEAD(tpacpi_all_drivers);
@@ -4020,13 +4403,30 @@ static void ibm_exit(struct ibm_struct *ibm)
/* Probing */
-static char *ibm_thinkpad_ec_found = NULL;
-
-static char* __init check_dmi_for_ec(void)
+static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
{
struct dmi_device *dev = NULL;
char ec_fw_string[18];
+ if (!tp)
+ return;
+
+ memset(tp, 0, sizeof(*tp));
+
+ if (dmi_name_in_vendors("IBM"))
+ tp->vendor = PCI_VENDOR_ID_IBM;
+ else if (dmi_name_in_vendors("LENOVO"))
+ tp->vendor = PCI_VENDOR_ID_LENOVO;
+ else
+ return;
+
+ tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
+ GFP_KERNEL);
+ if (!tp->bios_version_str)
+ return;
+ tp->bios_model = tp->bios_version_str[0]
+ | (tp->bios_version_str[1] << 8);
+
/*
* ThinkPad T23 or newer, A31 or newer, R50e or newer,
* X32 or newer, all Z series; Some models must have an
@@ -4040,10 +4440,20 @@ static char* __init check_dmi_for_ec(void)
ec_fw_string) == 1) {
ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
- return kstrdup(ec_fw_string, GFP_KERNEL);
+
+ tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+ tp->ec_model = ec_fw_string[0]
+ | (ec_fw_string[1] << 8);
+ break;
}
}
- return NULL;
+
+ tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
+ GFP_KERNEL);
+ if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+ kfree(tp->model_str);
+ tp->model_str = NULL;
+ }
}
static int __init probe_for_thinkpad(void)
@@ -4057,7 +4467,7 @@ static int __init probe_for_thinkpad(void)
* Non-ancient models have better DMI tagging, but very old models
* don't.
*/
- is_thinkpad = dmi_name_in_vendors("ThinkPad");
+ is_thinkpad = (thinkpad_id.model_str != NULL);
/* ec is required because many other handles are relative to it */
IBM_ACPIHANDLE_INIT(ec);
@@ -4073,7 +4483,7 @@ static int __init probe_for_thinkpad(void)
* false positives a damn great deal
*/
if (!is_thinkpad)
- is_thinkpad = dmi_name_in_vendors("IBM");
+ is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
if (!is_thinkpad && !force_load)
return -ENODEV;
@@ -4185,10 +4595,13 @@ static u32 dbg_level;
module_param_named(debug, dbg_level, uint, 0);
static int force_load;
-module_param(force_load, int, 0);
+module_param(force_load, bool, 0);
static int fan_control_allowed;
-module_param_named(fan_control, fan_control_allowed, int, 0);
+module_param_named(fan_control, fan_control_allowed, bool, 0);
+
+static int brightness_mode;
+module_param_named(brightness_mode, brightness_mode, int, 0);
#define IBM_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0)
@@ -4216,12 +4629,16 @@ static int __init thinkpad_acpi_module_init(void)
int ret, i;
/* Driver-level probe */
+
+ get_thinkpad_model_data(&thinkpad_id);
ret = probe_for_thinkpad();
- if (ret)
+ if (ret) {
+ thinkpad_acpi_module_exit();
return ret;
+ }
/* Driver initialization */
- ibm_thinkpad_ec_found = check_dmi_for_ec();
+
IBM_ACPIHANDLE_INIT(ecrd);
IBM_ACPIHANDLE_INIT(ecwr);
@@ -4265,6 +4682,22 @@ static int __init thinkpad_acpi_module_init(void)
thinkpad_acpi_module_exit();
return ret;
}
+ tpacpi_inputdev = input_allocate_device();
+ if (!tpacpi_inputdev) {
+ printk(IBM_ERR "unable to allocate input device\n");
+ thinkpad_acpi_module_exit();
+ return -ENOMEM;
+ } else {
+ /* Prepare input device, but don't register */
+ tpacpi_inputdev->name = "ThinkPad Extra Buttons";
+ tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
+ tpacpi_inputdev->id.bustype = BUS_HOST;
+ tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
+ thinkpad_id.vendor :
+ PCI_VENDOR_ID_IBM;
+ tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
+ tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
+ }
for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
ret = ibm_init(&ibms_init[i]);
if (ret >= 0 && *ibms_init[i].param)
@@ -4274,6 +4707,14 @@ static int __init thinkpad_acpi_module_init(void)
return ret;
}
}
+ ret = input_register_device(tpacpi_inputdev);
+ if (ret < 0) {
+ printk(IBM_ERR "unable to register input device\n");
+ thinkpad_acpi_module_exit();
+ return ret;
+ } else {
+ tp_features.input_device_registered = 1;
+ }
return 0;
}
@@ -4290,6 +4731,13 @@ static void thinkpad_acpi_module_exit(void)
dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
+ if (tpacpi_inputdev) {
+ if (tp_features.input_device_registered)
+ input_unregister_device(tpacpi_inputdev);
+ else
+ input_free_device(tpacpi_inputdev);
+ }
+
if (tpacpi_hwmon)
hwmon_device_unregister(tpacpi_hwmon);
@@ -4302,7 +4750,9 @@ static void thinkpad_acpi_module_exit(void)
if (proc_dir)
remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
- kfree(ibm_thinkpad_ec_found);
+ kfree(thinkpad_id.bios_version_str);
+ kfree(thinkpad_id.ec_version_str);
+ kfree(thinkpad_id.model_str);
}
module_init(thinkpad_acpi_module_init);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 72d62f2dabb9..b7a4a888cc8b 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -32,6 +32,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/nvram.h>
#include <linux/proc_fs.h>
#include <linux/sysfs.h>
#include <linux/backlight.h>
@@ -39,6 +40,7 @@
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/input.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
@@ -48,6 +50,7 @@
#include <acpi/acpi_drivers.h>
#include <acpi/acnamesp.h>
+#include <linux/pci_ids.h>
/****************************************************************************
* Main driver
@@ -78,6 +81,11 @@
#define TP_CMOS_BRIGHTNESS_UP 4
#define TP_CMOS_BRIGHTNESS_DOWN 5
+/* ThinkPad CMOS NVRAM constants */
+#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
+#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
+#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
+
#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -98,9 +106,13 @@ static const char *str_supported(int is_supported);
#define vdbg_printk(a_dbg_level, format, arg...)
#endif
+/* Input IDs */
+#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM
+#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
+#define TPACPI_HKEY_INPUT_VERSION 0x4101
+
/* ACPI HIDs */
#define IBM_HKEY_HID "IBM0068"
-#define IBM_PCI_HID "PNP0A03"
/* ACPI helpers */
static int __must_check acpi_evalf(acpi_handle handle,
@@ -161,6 +173,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
static struct platform_device *tpacpi_pdev;
static struct class_device *tpacpi_hwmon;
static struct platform_driver tpacpi_pdriver;
+static struct input_dev *tpacpi_inputdev;
static int tpacpi_create_driver_attributes(struct device_driver *drv);
static void tpacpi_remove_driver_attributes(struct device_driver *drv);
@@ -168,9 +181,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv);
static int experimental;
static u32 dbg_level;
static int force_load;
-static char *ibm_thinkpad_ec_found;
-static char* check_dmi_for_ec(void);
static int thinkpad_acpi_module_init(void);
static void thinkpad_acpi_module_exit(void);
@@ -197,6 +208,7 @@ struct ibm_struct {
int (*read) (char *);
int (*write) (char *);
void (*exit) (void);
+ void (*resume) (void);
struct list_head all_drivers;
@@ -228,12 +240,29 @@ static struct {
u16 bluetooth:1;
u16 hotkey:1;
u16 hotkey_mask:1;
+ u16 hotkey_wlsw:1;
u16 light:1;
u16 light_status:1;
u16 wan:1;
u16 fan_ctrl_status_undef:1;
+ u16 input_device_registered:1;
} tp_features;
+struct thinkpad_id_data {
+ unsigned int vendor; /* ThinkPad vendor:
+ * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
+
+ char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
+ char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
+
+ u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+ u16 ec_model;
+
+ char *model_str;
+};
+
+static struct thinkpad_id_data thinkpad_id;
+
static struct list_head tpacpi_all_drivers;
static struct ibm_init_struct ibms_init[];
@@ -300,6 +329,7 @@ static int bluetooth_write(char *buf);
static struct backlight_device *ibm_backlight_device;
static int brightness_offset = 0x31;
+static int brightness_mode;
static int brightness_init(struct ibm_init_struct *iibm);
static void brightness_exit(void);
@@ -415,14 +445,14 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc);
*/
static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
static struct mutex hotkey_mutex;
static int hotkey_init(struct ibm_init_struct *iibm);
static void hotkey_exit(void);
-static int hotkey_get(int *status, int *mask);
-static int hotkey_set(int status, int mask);
+static int hotkey_get(int *status, u32 *mask);
+static int hotkey_set(int status, u32 mask);
static void hotkey_notify(struct ibm_struct *ibm, u32 event);
static int hotkey_read(char *p);
static int hotkey_write(char *buf);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index cbd4b6e3e17c..93fe2e5dd616 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -414,13 +414,12 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
return ERR_PTR(-ENOSPC);
__set_bit(devidx, dev_use);
- md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+ md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
if (!md) {
ret = -ENOMEM;
goto out;
}
- memset(md, 0, sizeof(struct mmc_blk_data));
/*
* Set the read-only status based on the supported commands
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 4fb2089dc690..b53dac8d1b69 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
#include <linux/blkdev.h>
+#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/mmc/card.h>
@@ -44,11 +45,7 @@ static int mmc_queue_thread(void *d)
struct mmc_queue *mq = d;
struct request_queue *q = mq->queue;
- /*
- * Set iothread to ensure that we aren't put to sleep by
- * the process freezing. We handle suspension ourselves.
- */
- current->flags |= PF_MEMALLOC|PF_NOFREEZE;
+ current->flags |= PF_MEMALLOC;
down(&mq->thread_sem);
do {
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 28c881895ab7..15aab374127e 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -903,8 +903,10 @@ static int __init at91_mci_probe(struct platform_device *pdev)
/*
* Add host to MMC layer
*/
- if (host->board->det_pin)
+ if (host->board->det_pin) {
host->present = !at91_get_gpio_value(host->board->det_pin);
+ device_init_wakeup(&pdev->dev, 1);
+ }
else
host->present = -1;
@@ -940,6 +942,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
host = mmc_priv(mmc);
if (host->present != -1) {
+ device_init_wakeup(&pdev->dev, 0);
free_irq(host->board->det_pin, host);
cancel_delayed_work(&host->mmc->detect);
}
@@ -966,8 +969,12 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct at91mci_host *host = mmc_priv(mmc);
int ret = 0;
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(host->board->det_pin);
+
if (mmc)
ret = mmc_suspend_host(mmc, state);
@@ -977,8 +984,12 @@ static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
static int at91_mci_resume(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
+ struct at91mci_host *host = mmc_priv(mmc);
int ret = 0;
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(host->board->det_pin);
+
if (mmc)
ret = mmc_resume_host(mmc);
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
index 1b163220df2b..df17c281278a 100644
--- a/drivers/mmc/host/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
@@ -1,25 +1,3 @@
-#undef MMC_STRPCL
-#undef MMC_STAT
-#undef MMC_CLKRT
-#undef MMC_SPI
-#undef MMC_CMDAT
-#undef MMC_RESTO
-#undef MMC_RDTO
-#undef MMC_BLKLEN
-#undef MMC_NOB
-#undef MMC_PRTBUF
-#undef MMC_I_MASK
-#undef END_CMD_RES
-#undef PRG_DONE
-#undef DATA_TRAN_DONE
-#undef MMC_I_REG
-#undef MMC_CMD
-#undef MMC_ARGH
-#undef MMC_ARGL
-#undef MMC_RES
-#undef MMC_RXFIFO
-#undef MMC_TXFIFO
-
#define MMC_STRPCL 0x0000
#define STOP_CLOCK (1 << 0)
#define START_CLOCK (2 << 0)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 10d15c39d003..4a24db028d87 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1024,6 +1024,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+ intmask &= ~SDHCI_INT_ERROR;
+
if (intmask & SDHCI_INT_BUS_POWER) {
printk(KERN_ERR "%s: Card is consuming too much power!\n",
mmc_hostname(host->mmc));
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7400f4bc114f..a6c870480b8a 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -107,6 +107,7 @@
#define SDHCI_INT_CARD_INSERT 0x00000040
#define SDHCI_INT_CARD_REMOVE 0x00000080
#define SDHCI_INT_CARD_INT 0x00000100
+#define SDHCI_INT_ERROR 0x00008000
#define SDHCI_INT_TIMEOUT 0x00010000
#define SDHCI_INT_CRC 0x00020000
#define SDHCI_INT_END_BIT 0x00040000
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index a8a158708293..74d9d30edabd 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -16,6 +16,7 @@
#include <linux/mtd/mtd.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
+#include <linux/freezer.h>
#include <linux/spinlock.h>
#include <linux/hdreg.h>
#include <linux/init.h>
@@ -79,7 +80,7 @@ static int mtd_blktrans_thread(void *arg)
struct request_queue *rq = tr->blkcore_priv->rq;
/* we might get involved when memory gets low, so use PF_MEMALLOC */
- current->flags |= PF_MEMALLOC | PF_NOFREEZE;
+ current->flags |= PF_MEMALLOC;
spin_lock_irq(rq->queue_lock);
while (!kthread_should_stop()) {
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 555d594d1811..1cb22bfae750 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -33,6 +33,7 @@
#include <linux/moduleparam.h>
#include <linux/stringify.h>
#include <linux/stat.h>
+#include <linux/log2.h>
#include "ubi.h"
/* Maximum length of the 'mtd=' parameter */
@@ -369,7 +370,7 @@ static int attach_by_scanning(struct ubi_device *ubi)
out_wl:
ubi_wl_close(ubi);
out_vtbl:
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
out_si:
ubi_scan_destroy_si(si);
return err;
@@ -422,8 +423,7 @@ static int io_init(struct ubi_device *ubi)
ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
/* Make sure minimal I/O unit is power of 2 */
- if (ubi->min_io_size == 0 ||
- (ubi->min_io_size & (ubi->min_io_size - 1))) {
+ if (!is_power_of_2(ubi->min_io_size)) {
ubi_err("bad min. I/O unit");
return -EINVAL;
}
@@ -593,8 +593,6 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
if (err)
goto out_detach;
- ubi_devices_cnt += 1;
-
ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
ubi_msg("MTD device name: \"%s\"", ubi->mtd->name);
ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20);
@@ -624,12 +622,13 @@ static int attach_mtd_dev(const char *mtd_dev, int vid_hdr_offset,
wake_up_process(ubi->bgt_thread);
}
+ ubi_devices_cnt += 1;
return 0;
out_detach:
ubi_eba_close(ubi);
ubi_wl_close(ubi);
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
out_free:
kfree(ubi);
out_mtd:
@@ -650,7 +649,7 @@ static void detach_mtd_dev(struct ubi_device *ubi)
uif_close(ubi);
ubi_eba_close(ubi);
ubi_wl_close(ubi);
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
put_mtd_device(ubi->mtd);
kfree(ubi_devices[ubi_num]);
ubi_devices[ubi_num] = NULL;
@@ -686,13 +685,6 @@ static int __init ubi_init(void)
struct mtd_dev_param *p = &mtd_dev_param[i];
cond_resched();
-
- if (!p->name) {
- dbg_err("empty name");
- err = -EINVAL;
- goto out_detach;
- }
-
err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
if (err)
goto out_detach;
@@ -799,7 +791,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
/* Get rid of the final newline */
if (buf[len - 1] == '\n')
- buf[len - 1] = 0;
+ buf[len - 1] = '\0';
for (i = 0; i < 3; i++)
tokens[i] = strsep(&pbuf, ",");
@@ -809,9 +801,6 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
return -EINVAL;
}
- if (tokens[0] == '\0')
- return -EINVAL;
-
p = &mtd_dev_param[mtd_devs];
strcpy(&p->name[0], tokens[0]);
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 6612eb79bf17..fe4da1e96c52 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -64,6 +64,7 @@ static struct ubi_device *major_to_device(int major)
if (ubi_devices[i] && ubi_devices[i]->major == major)
return ubi_devices[i];
BUG();
+ return NULL;
}
/**
@@ -153,7 +154,7 @@ static int vol_cdev_release(struct inode *inode, struct file *file)
ubi_warn("update of volume %d not finished, volume is damaged",
vol->vol_id);
vol->updating = 0;
- kfree(vol->upd_buf);
+ vfree(vol->upd_buf);
}
ubi_close_volume(desc);
@@ -232,7 +233,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
tbuf_size = vol->usable_leb_size;
if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size);
- tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+ tbuf = vmalloc(tbuf_size);
if (!tbuf)
return -ENOMEM;
@@ -271,7 +272,7 @@ static ssize_t vol_cdev_read(struct file *file, __user char *buf, size_t count,
len = count > tbuf_size ? tbuf_size : count;
} while (count);
- kfree(tbuf);
+ vfree(tbuf);
return err ? err : count_save - count;
}
@@ -320,7 +321,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
tbuf_size = vol->usable_leb_size;
if (count < tbuf_size)
tbuf_size = ALIGN(count, ubi->min_io_size);
- tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+ tbuf = vmalloc(tbuf_size);
if (!tbuf)
return -ENOMEM;
@@ -355,7 +356,7 @@ static ssize_t vol_cdev_direct_write(struct file *file, const char __user *buf,
len = count > tbuf_size ? tbuf_size : count;
}
- kfree(tbuf);
+ vfree(tbuf);
return err ? err : count_save - count;
}
@@ -397,6 +398,7 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf,
vol->corrupted = 1;
}
vol->checked = 1;
+ ubi_gluebi_updated(vol);
revoke_exclusive(desc, UBI_READWRITE);
}
@@ -413,19 +415,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_device *ubi = vol->ubi;
void __user *argp = (void __user *)arg;
- if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
- _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
- return -ENOTTY;
-
- if (_IOC_DIR(cmd) && _IOC_READ)
- err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) && _IOC_WRITE)
- err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
- if (err)
- return -EFAULT;
-
switch (cmd) {
-
/* Volume update command */
case UBI_IOCVOLUP:
{
@@ -471,7 +461,7 @@ static int vol_cdev_ioctl(struct inode *inode, struct file *file,
{
int32_t lnum;
- err = __get_user(lnum, (__user int32_t *)argp);
+ err = get_user(lnum, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
@@ -587,17 +577,6 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_volume_desc *desc;
void __user *argp = (void __user *)arg;
- if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
- _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
- return -ENOTTY;
-
- if (_IOC_DIR(cmd) && _IOC_READ)
- err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
- else if (_IOC_DIR(cmd) && _IOC_WRITE)
- err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
- if (err)
- return -EFAULT;
-
if (!capable(CAP_SYS_RESOURCE))
return -EPERM;
@@ -612,7 +591,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_mkvol_req req;
dbg_msg("create volume");
- err = __copy_from_user(&req, argp,
+ err = copy_from_user(&req, argp,
sizeof(struct ubi_mkvol_req));
if (err) {
err = -EFAULT;
@@ -629,7 +608,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
if (err)
break;
- err = __put_user(req.vol_id, (__user int32_t *)argp);
+ err = put_user(req.vol_id, (__user int32_t *)argp);
if (err)
err = -EFAULT;
@@ -642,7 +621,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
int vol_id;
dbg_msg("remove volume");
- err = __get_user(vol_id, (__user int32_t *)argp);
+ err = get_user(vol_id, (__user int32_t *)argp);
if (err) {
err = -EFAULT;
break;
@@ -669,7 +648,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct ubi_rsvol_req req;
dbg_msg("re-size volume");
- err = __copy_from_user(&req, argp,
+ err = copy_from_user(&req, argp,
sizeof(struct ubi_rsvol_req));
if (err) {
err = -EFAULT;
@@ -707,7 +686,7 @@ static int ubi_cdev_ioctl(struct inode *inode, struct file *file,
struct file_operations ubi_cdev_operations = {
.owner = THIS_MODULE,
.ioctl = ubi_cdev_ioctl,
- .llseek = no_llseek
+ .llseek = no_llseek,
};
/* UBI volume character device operations */
@@ -718,5 +697,5 @@ struct file_operations ubi_vol_cdev_operations = {
.llseek = vol_cdev_llseek,
.read = vol_cdev_read,
.write = vol_cdev_write,
- .ioctl = vol_cdev_ioctl
+ .ioctl = vol_cdev_ioctl,
};
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 86364221fafe..310341e5cd43 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -35,12 +35,12 @@
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
{
dbg_msg("erase counter header dump:");
- dbg_msg("magic %#08x", ubi32_to_cpu(ec_hdr->magic));
+ dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic));
dbg_msg("version %d", (int)ec_hdr->version);
- dbg_msg("ec %llu", (long long)ubi64_to_cpu(ec_hdr->ec));
- dbg_msg("vid_hdr_offset %d", ubi32_to_cpu(ec_hdr->vid_hdr_offset));
- dbg_msg("data_offset %d", ubi32_to_cpu(ec_hdr->data_offset));
- dbg_msg("hdr_crc %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
+ dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec));
+ dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset));
+ dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset));
+ dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc));
dbg_msg("erase counter header hexdump:");
ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
}
@@ -52,20 +52,20 @@ void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{
dbg_msg("volume identifier header dump:");
- dbg_msg("magic %08x", ubi32_to_cpu(vid_hdr->magic));
+ dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic));
dbg_msg("version %d", (int)vid_hdr->version);
dbg_msg("vol_type %d", (int)vid_hdr->vol_type);
dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag);
dbg_msg("compat %d", (int)vid_hdr->compat);
- dbg_msg("vol_id %d", ubi32_to_cpu(vid_hdr->vol_id));
- dbg_msg("lnum %d", ubi32_to_cpu(vid_hdr->lnum));
- dbg_msg("leb_ver %u", ubi32_to_cpu(vid_hdr->leb_ver));
- dbg_msg("data_size %d", ubi32_to_cpu(vid_hdr->data_size));
- dbg_msg("used_ebs %d", ubi32_to_cpu(vid_hdr->used_ebs));
- dbg_msg("data_pad %d", ubi32_to_cpu(vid_hdr->data_pad));
+ dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id));
+ dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum));
+ dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver));
+ dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size));
+ dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs));
+ dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad));
dbg_msg("sqnum %llu",
- (unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
- dbg_msg("hdr_crc %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
+ (unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+ dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc));
dbg_msg("volume identifier header hexdump:");
}
@@ -91,7 +91,7 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
if (vol->name_len <= UBI_VOL_NAME_MAX &&
strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
- dbg_msg("name %s", vol->name);
+ dbg_msg("name %s", vol->name);
} else {
dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
vol->name[0], vol->name[1], vol->name[2],
@@ -106,30 +106,30 @@ void ubi_dbg_dump_vol_info(const struct ubi_volume *vol)
*/
void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
{
- int name_len = ubi16_to_cpu(r->name_len);
+ int name_len = be16_to_cpu(r->name_len);
dbg_msg("volume table record %d dump:", idx);
- dbg_msg("reserved_pebs %d", ubi32_to_cpu(r->reserved_pebs));
- dbg_msg("alignment %d", ubi32_to_cpu(r->alignment));
- dbg_msg("data_pad %d", ubi32_to_cpu(r->data_pad));
+ dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs));
+ dbg_msg("alignment %d", be32_to_cpu(r->alignment));
+ dbg_msg("data_pad %d", be32_to_cpu(r->data_pad));
dbg_msg("vol_type %d", (int)r->vol_type);
dbg_msg("upd_marker %d", (int)r->upd_marker);
dbg_msg("name_len %d", name_len);
if (r->name[0] == '\0') {
- dbg_msg("name NULL");
+ dbg_msg("name NULL");
return;
}
if (name_len <= UBI_VOL_NAME_MAX &&
strnlen(&r->name[0], name_len + 1) == name_len) {
- dbg_msg("name %s", &r->name[0]);
+ dbg_msg("name %s", &r->name[0]);
} else {
dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
r->name[0], r->name[1], r->name[2], r->name[3],
r->name[4]);
}
- dbg_msg("crc %#08x", ubi32_to_cpu(r->crc));
+ dbg_msg("crc %#08x", be32_to_cpu(r->crc));
}
/**
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index f816ad9a36c0..ff8f39548cd8 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -52,7 +52,6 @@ struct ubi_scan_volume;
struct ubi_scan_leb;
struct ubi_mkvol_req;
-void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
@@ -66,7 +65,6 @@ void ubi_dbg_hexdump(const void *buf, int size);
#define dbg_msg(fmt, ...) ({})
#define ubi_dbg_dump_stack() ({})
-#define ubi_dbg_print(func, fmt, ...) ({})
#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
#define ubi_dbg_dump_vol_info(vol) ({})
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 74002945b71b..7c5e29eaf118 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -368,7 +368,7 @@ int ubi_eba_read_leb(struct ubi_device *ubi, int vol_id, int lnum, void *buf,
int err, pnum, scrub = 0, idx = vol_id2idx(ubi, vol_id);
struct ubi_vid_hdr *vid_hdr;
struct ubi_volume *vol = ubi->volumes[idx];
- uint32_t crc, crc1;
+ uint32_t uninitialized_var(crc);
err = leb_read_lock(ubi, vol_id, lnum);
if (err)
@@ -425,10 +425,10 @@ retry:
} else if (err == UBI_IO_BITFLIPS)
scrub = 1;
- ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs));
- ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size));
+ ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
+ ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
- crc = ubi32_to_cpu(vid_hdr->data_crc);
+ crc = be32_to_cpu(vid_hdr->data_crc);
ubi_free_vid_hdr(ubi, vid_hdr);
}
@@ -451,7 +451,7 @@ retry:
}
if (check) {
- crc1 = crc32(UBI_CRC32_INIT, buf, len);
+ uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len);
if (crc1 != crc) {
ubi_warn("CRC error: calculated %#08x, must be %#08x",
crc1, crc);
@@ -518,13 +518,13 @@ retry:
goto out_put;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
if (err)
goto write_error;
data_size = offset + len;
- new_buf = kmalloc(data_size, GFP_KERNEL);
+ new_buf = vmalloc(data_size);
if (!new_buf) {
err = -ENOMEM;
goto out_put;
@@ -535,7 +535,7 @@ retry:
if (offset > 0) {
err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
if (err && err != UBI_IO_BITFLIPS) {
- kfree(new_buf);
+ vfree(new_buf);
goto out_put;
}
}
@@ -544,11 +544,11 @@ retry:
err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
if (err) {
- kfree(new_buf);
+ vfree(new_buf);
goto write_error;
}
- kfree(new_buf);
+ vfree(new_buf);
ubi_free_vid_hdr(ubi, vid_hdr);
vol->eba_tbl[lnum] = new_pnum;
@@ -634,11 +634,11 @@ int ubi_eba_write_leb(struct ubi_device *ubi, int vol_id, int lnum,
}
vid_hdr->vol_type = UBI_VID_DYNAMIC;
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -692,7 +692,7 @@ write_error:
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -748,17 +748,17 @@ int ubi_eba_write_leb_st(struct ubi_device *ubi, int vol_id, int lnum,
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, data_size);
vid_hdr->vol_type = UBI_VID_STATIC;
- vid_hdr->data_size = cpu_to_ubi32(data_size);
- vid_hdr->used_ebs = cpu_to_ubi32(used_ebs);
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->used_ebs = cpu_to_be32(used_ebs);
+ vid_hdr->data_crc = cpu_to_be32(crc);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -813,7 +813,7 @@ write_error:
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -854,17 +854,17 @@ int ubi_eba_atomic_leb_change(struct ubi_device *ubi, int vol_id, int lnum,
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
- vid_hdr->vol_id = cpu_to_ubi32(vol_id);
- vid_hdr->lnum = cpu_to_ubi32(lnum);
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+ vid_hdr->vol_id = cpu_to_be32(vol_id);
+ vid_hdr->lnum = cpu_to_be32(lnum);
vid_hdr->compat = ubi_get_compat(ubi, vol_id);
- vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+ vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
crc = crc32(UBI_CRC32_INIT, buf, len);
- vid_hdr->vol_type = UBI_VID_STATIC;
- vid_hdr->data_size = cpu_to_ubi32(len);
+ vid_hdr->vol_type = UBI_VID_DYNAMIC;
+ vid_hdr->data_size = cpu_to_be32(len);
vid_hdr->copy_flag = 1;
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_crc = cpu_to_be32(crc);
retry:
pnum = ubi_wl_get_peb(ubi, dtype);
@@ -891,11 +891,13 @@ retry:
goto write_error;
}
- err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
- if (err) {
- ubi_free_vid_hdr(ubi, vid_hdr);
- leb_write_unlock(ubi, vol_id, lnum);
- return err;
+ if (vol->eba_tbl[lnum] >= 0) {
+ err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+ if (err) {
+ ubi_free_vid_hdr(ubi, vid_hdr);
+ leb_write_unlock(ubi, vol_id, lnum);
+ return err;
+ }
}
vol->eba_tbl[lnum] = pnum;
@@ -924,7 +926,7 @@ write_error:
return err;
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
ubi_msg("try another PEB");
goto retry;
}
@@ -965,19 +967,19 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
uint32_t crc;
void *buf, *buf1 = NULL;
- vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- lnum = ubi32_to_cpu(vid_hdr->lnum);
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
if (vid_hdr->vol_type == UBI_VID_STATIC) {
- data_size = ubi32_to_cpu(vid_hdr->data_size);
+ data_size = be32_to_cpu(vid_hdr->data_size);
aldata_size = ALIGN(data_size, ubi->min_io_size);
} else
data_size = aldata_size =
- ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad);
+ ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
- buf = kmalloc(aldata_size, GFP_KERNEL);
+ buf = vmalloc(aldata_size);
if (!buf)
return -ENOMEM;
@@ -987,7 +989,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/
err = leb_write_lock(ubi, vol_id, lnum);
if (err) {
- kfree(buf);
+ vfree(buf);
return err;
}
@@ -1054,10 +1056,10 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
*/
if (data_size > 0) {
vid_hdr->copy_flag = 1;
- vid_hdr->data_size = cpu_to_ubi32(data_size);
- vid_hdr->data_crc = cpu_to_ubi32(crc);
+ vid_hdr->data_size = cpu_to_be32(data_size);
+ vid_hdr->data_crc = cpu_to_be32(crc);
}
- vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+ vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
if (err)
@@ -1082,7 +1084,7 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
* We've written the data and are going to read it back to make
* sure it was written correctly.
*/
- buf1 = kmalloc(aldata_size, GFP_KERNEL);
+ buf1 = vmalloc(aldata_size);
if (!buf1) {
err = -ENOMEM;
goto out_unlock;
@@ -1111,15 +1113,15 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to,
vol->eba_tbl[lnum] = to;
leb_write_unlock(ubi, vol_id, lnum);
- kfree(buf);
- kfree(buf1);
+ vfree(buf);
+ vfree(buf1);
return 0;
out_unlock:
leb_write_unlock(ubi, vol_id, lnum);
- kfree(buf);
- kfree(buf1);
+ vfree(buf);
+ vfree(buf1);
return err;
}
@@ -1147,7 +1149,7 @@ int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (ubi_devices_cnt == 0) {
ltree_slab = kmem_cache_create("ubi_ltree_slab",
sizeof(struct ltree_entry), 0,
- 0, &ltree_entry_ctor, NULL);
+ 0, &ltree_entry_ctor);
if (!ltree_slab)
return -ENOMEM;
}
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index fc9478d605ff..41ff74c60e14 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -282,7 +282,6 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
mtd->flags = MTD_WRITEABLE;
mtd->writesize = ubi->min_io_size;
mtd->owner = THIS_MODULE;
- mtd->size = vol->usable_leb_size * vol->reserved_pebs;
mtd->erasesize = vol->usable_leb_size;
mtd->read = gluebi_read;
mtd->write = gluebi_write;
@@ -290,6 +289,15 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol)
mtd->get_device = gluebi_get_device;
mtd->put_device = gluebi_put_device;
+ /*
+ * 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.
+ */
+ if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+ mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+
if (add_mtd_device(mtd)) {
ubi_err("cannot not add MTD device\n");
kfree(mtd->name);
@@ -321,3 +329,20 @@ int ubi_destroy_gluebi(struct ubi_volume *vol)
kfree(mtd->name);
return 0;
}
+
+/**
+ * ubi_gluebi_updated - UBI volume was updated notifier.
+ * @vol: volume description object
+ *
+ * This function is called every time an UBI volume is updated. This function
+ * does nothing if volume @vol is dynamic, and changes MTD device size if the
+ * volume is static. This is needed because static volumes cannot be read past
+ * data they contain.
+ */
+void ubi_gluebi_updated(struct ubi_volume *vol)
+{
+ struct mtd_info *mtd = &vol->gluebi_mtd;
+
+ if (vol->vol_type == UBI_STATIC_VOLUME)
+ mtd->size = vol->used_bytes;
+}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 438914d05151..b0d8f4cede97 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -125,9 +125,9 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
* o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
* correctable bit-flips were detected; this is harmless but may indicate
* that this eraseblock may become bad soon (but do not have to);
- * o %-EBADMSG if the MTD subsystem reported about data data integrity
- * problems, for example it can me an ECC error in case of NAND; this most
- * probably means that the data is corrupted;
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ * example it can be an ECC error in case of NAND; this most probably means
+ * that the data is corrupted;
* o %-EIO if some I/O error occurred;
* o other negative error codes in case of other errors.
*/
@@ -298,7 +298,7 @@ retry:
memset(&ei, 0, sizeof(struct erase_info));
ei.mtd = ubi->mtd;
- ei.addr = pnum * ubi->peb_size;
+ ei.addr = (loff_t)pnum * ubi->peb_size;
ei.len = ubi->peb_size;
ei.callback = erase_callback;
ei.priv = (unsigned long)&wq;
@@ -382,7 +382,7 @@ static int torture_peb(const struct ubi_device *ubi, int pnum)
void *buf;
int err, i, patt_count;
- buf = kmalloc(ubi->peb_size, GFP_KERNEL);
+ buf = vmalloc(ubi->peb_size);
if (!buf)
return -ENOMEM;
@@ -437,7 +437,7 @@ out:
* physical eraseblock which means something is wrong with it.
*/
err = -EIO;
- kfree(buf);
+ vfree(buf);
return err;
}
@@ -557,9 +557,9 @@ static int validate_ec_hdr(const struct ubi_device *ubi,
long long ec;
int vid_hdr_offset, leb_start;
- ec = ubi64_to_cpu(ec_hdr->ec);
- vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset);
- leb_start = ubi32_to_cpu(ec_hdr->data_offset);
+ ec = be64_to_cpu(ec_hdr->ec);
+ vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
+ leb_start = be32_to_cpu(ec_hdr->data_offset);
if (ec_hdr->version != UBI_VERSION) {
ubi_err("node with incompatible UBI version found: "
@@ -640,7 +640,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
read_err = err;
}
- magic = ubi32_to_cpu(ec_hdr->magic);
+ magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
/*
* The magic field is wrong. Let's check if we have read all
@@ -684,7 +684,7 @@ int ubi_io_read_ec_hdr(const struct ubi_device *ubi, int pnum,
}
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
if (verbose) {
@@ -729,12 +729,12 @@ int ubi_io_write_ec_hdr(const struct ubi_device *ubi, int pnum,
dbg_io("write EC header to PEB %d", pnum);
ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
- ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC);
+ ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
ec_hdr->version = UBI_VERSION;
- ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset);
- ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start);
+ ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
+ ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- ec_hdr->hdr_crc = cpu_to_ubi32(crc);
+ ec_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
if (err)
@@ -757,13 +757,13 @@ static int validate_vid_hdr(const struct ubi_device *ubi,
{
int vol_type = vid_hdr->vol_type;
int copy_flag = vid_hdr->copy_flag;
- int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- int lnum = ubi32_to_cpu(vid_hdr->lnum);
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int lnum = be32_to_cpu(vid_hdr->lnum);
int compat = vid_hdr->compat;
- int data_size = ubi32_to_cpu(vid_hdr->data_size);
- int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
- int data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+ int data_size = be32_to_cpu(vid_hdr->data_size);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
+ int data_crc = be32_to_cpu(vid_hdr->data_crc);
int usable_leb_size = ubi->leb_size - data_pad;
if (copy_flag != 0 && copy_flag != 1) {
@@ -914,7 +914,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
read_err = err;
}
- magic = ubi32_to_cpu(vid_hdr->magic);
+ magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
/*
* If we have read all 0xFF bytes, the VID header probably does
@@ -957,7 +957,7 @@ int ubi_io_read_vid_hdr(const struct ubi_device *ubi, int pnum,
}
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) {
if (verbose) {
@@ -1007,10 +1007,10 @@ int ubi_io_write_vid_hdr(const struct ubi_device *ubi, int pnum,
if (err)
return err > 0 ? -EINVAL: err;
- vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC);
+ vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
vid_hdr->version = UBI_VERSION;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
- vid_hdr->hdr_crc = cpu_to_ubi32(crc);
+ vid_hdr->hdr_crc = cpu_to_be32(crc);
err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
if (err)
@@ -1060,7 +1060,7 @@ static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum,
int err;
uint32_t magic;
- magic = ubi32_to_cpu(ec_hdr->magic);
+ magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
ubi_err("bad magic %#08x, must be %#08x",
magic, UBI_EC_HDR_MAGIC);
@@ -1105,7 +1105,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum)
goto exit;
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
ubi_err("paranoid check failed for PEB %d", pnum);
@@ -1137,7 +1137,7 @@ static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum,
int err;
uint32_t magic;
- magic = ubi32_to_cpu(vid_hdr->magic);
+ magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
magic, pnum, UBI_VID_HDR_MAGIC);
@@ -1187,7 +1187,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
goto exit;
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
- hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+ hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
@@ -1224,9 +1224,10 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
void *buf;
loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
- buf = kzalloc(len, GFP_KERNEL);
+ buf = vmalloc(len);
if (!buf)
return -ENOMEM;
+ memset(buf, 0, len);
err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
if (err && err != -EUCLEAN) {
@@ -1242,7 +1243,7 @@ static int paranoid_check_all_ff(const struct ubi_device *ubi, int pnum,
goto fail;
}
- kfree(buf);
+ vfree(buf);
return 0;
fail:
@@ -1252,7 +1253,7 @@ fail:
err = 1;
error:
ubi_dbg_dump_stack();
- kfree(buf);
+ vfree(buf);
return err;
}
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index d352c4575c3d..4a458e83e4e9 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -37,14 +37,9 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
{
const struct ubi_device *ubi;
- if (!try_module_get(THIS_MODULE))
- return -ENODEV;
-
if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
- !ubi_devices[ubi_num]) {
- module_put(THIS_MODULE);
+ !ubi_devices[ubi_num])
return -ENODEV;
- }
ubi = ubi_devices[ubi_num];
di->ubi_num = ubi->ubi_num;
@@ -52,7 +47,6 @@ int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
di->min_io_size = ubi->min_io_size;
di->ro_mode = ubi->ro_mode;
di->cdev = MKDEV(ubi->major, 0);
- module_put(THIS_MODULE);
return 0;
}
EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -319,9 +313,14 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
offset + len > vol->usable_leb_size)
return -EINVAL;
- if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 &&
- offset + len > vol->last_eb_bytes)
- return -EINVAL;
+ if (vol->vol_type == UBI_STATIC_VOLUME) {
+ if (vol->used_ebs == 0)
+ /* Empty static UBI volume */
+ return 0;
+ if (lnum == vol->used_ebs - 1 &&
+ offset + len > vol->last_eb_bytes)
+ return -EINVAL;
+ }
if (vol->upd_marker)
return -EBADF;
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index 38d4e6757dc7..9e2338c8e2cf 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -67,7 +67,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
if (vol->vol_type != UBI_STATIC_VOLUME)
return 0;
- buf = kmalloc(vol->usable_leb_size, GFP_KERNEL);
+ buf = vmalloc(vol->usable_leb_size);
if (!buf)
return -ENOMEM;
@@ -87,7 +87,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
}
}
- kfree(buf);
+ vfree(buf);
return err;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 473f3200b868..94ee54934411 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -24,7 +24,7 @@
* This unit is responsible for scanning the flash media, checking UBI
* headers and providing complete information about the UBI flash image.
*
- * The scanning information is reoresented by a &struct ubi_scan_info' object.
+ * The scanning information is represented by a &struct ubi_scan_info' object.
* Information about found volumes is represented by &struct ubi_scan_volume
* objects which are kept in volume RB-tree with root at the @volumes field.
* The RB-tree is indexed by the volume ID.
@@ -55,8 +55,19 @@ static int paranoid_check_si(const struct ubi_device *ubi,
static struct ubi_ec_hdr *ech;
static struct ubi_vid_hdr *vidh;
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
- struct list_head *list)
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @si: scanning information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ * @list: the list to add to
+ *
+ * This function adds physical eraseblock @pnum to free, erase, corrupted or
+ * alien lists. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+ struct list_head *list)
{
struct ubi_scan_leb *seb;
@@ -121,9 +132,9 @@ static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr,
const struct ubi_scan_volume *sv, int pnum)
{
int vol_type = vid_hdr->vol_type;
- int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+ int vol_id = be32_to_cpu(vid_hdr->vol_id);
+ int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ int data_pad = be32_to_cpu(vid_hdr->data_pad);
if (sv->leb_count != 0) {
int sv_vol_type;
@@ -189,7 +200,7 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
struct ubi_scan_volume *sv;
struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
- ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id));
+ ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
/* Walk the volume RB-tree to look if this volume is already present */
while (*p) {
@@ -211,11 +222,10 @@ static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id,
return ERR_PTR(-ENOMEM);
sv->highest_lnum = sv->leb_count = 0;
- si->max_sqnum = 0;
sv->vol_id = vol_id;
sv->root = RB_ROOT;
- sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
- sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+ sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+ sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
sv->compat = vid_hdr->compat;
sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
: UBI_STATIC_VOLUME;
@@ -257,10 +267,10 @@ static int compare_lebs(const struct ubi_device *ubi,
int len, err, second_is_newer, bitflips = 0, corrupted = 0;
uint32_t data_crc, crc;
struct ubi_vid_hdr *vidh = NULL;
- unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum);
+ unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
if (seb->sqnum == 0 && sqnum2 == 0) {
- long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver);
+ long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
/*
* UBI constantly increases the logical eraseblock version
@@ -344,8 +354,8 @@ static int compare_lebs(const struct ubi_device *ubi,
/* Read the data of the copy and check the CRC */
- len = ubi32_to_cpu(vid_hdr->data_size);
- buf = kmalloc(len, GFP_KERNEL);
+ len = be32_to_cpu(vid_hdr->data_size);
+ buf = vmalloc(len);
if (!buf) {
err = -ENOMEM;
goto out_free_vidh;
@@ -355,7 +365,7 @@ static int compare_lebs(const struct ubi_device *ubi,
if (err && err != UBI_IO_BITFLIPS)
goto out_free_buf;
- data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+ data_crc = be32_to_cpu(vid_hdr->data_crc);
crc = crc32(UBI_CRC32_INIT, buf, len);
if (crc != data_crc) {
dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
@@ -368,7 +378,7 @@ static int compare_lebs(const struct ubi_device *ubi,
bitflips = !!err;
}
- kfree(buf);
+ vfree(buf);
ubi_free_vid_hdr(ubi, vidh);
if (second_is_newer)
@@ -379,7 +389,7 @@ static int compare_lebs(const struct ubi_device *ubi,
return second_is_newer | (bitflips << 1) | (corrupted << 2);
out_free_buf:
- kfree(buf);
+ vfree(buf);
out_free_vidh:
ubi_free_vid_hdr(ubi, vidh);
ubi_assert(err < 0);
@@ -396,8 +406,12 @@ out_free_vidh:
* @vid_hdr: the volume identifier header
* @bitflips: if bit-flips were detected when this physical eraseblock was read
*
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
*/
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
@@ -410,10 +424,10 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
struct ubi_scan_leb *seb;
struct rb_node **p, *parent = NULL;
- vol_id = ubi32_to_cpu(vid_hdr->vol_id);
- lnum = ubi32_to_cpu(vid_hdr->lnum);
- sqnum = ubi64_to_cpu(vid_hdr->sqnum);
- leb_ver = ubi32_to_cpu(vid_hdr->leb_ver);
+ vol_id = be32_to_cpu(vid_hdr->vol_id);
+ lnum = be32_to_cpu(vid_hdr->lnum);
+ sqnum = be64_to_cpu(vid_hdr->sqnum);
+ leb_ver = be32_to_cpu(vid_hdr->leb_ver);
dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
@@ -422,6 +436,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (IS_ERR(sv) < 0)
return PTR_ERR(sv);
+ if (si->max_sqnum < sqnum)
+ si->max_sqnum = sqnum;
+
/*
* Walk the RB-tree of logical eraseblocks of volume @vol_id to look
* if this is the first instance of this logical eraseblock or not.
@@ -492,11 +509,11 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
return err;
if (cmp_res & 4)
- err = ubi_scan_add_to_list(si, seb->pnum,
- seb->ec, &si->corr);
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->corr);
else
- err = ubi_scan_add_to_list(si, seb->pnum,
- seb->ec, &si->erase);
+ err = add_to_list(si, seb->pnum, seb->ec,
+ &si->erase);
if (err)
return err;
@@ -508,7 +525,7 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (sv->highest_lnum == lnum)
sv->last_data_size =
- ubi32_to_cpu(vid_hdr->data_size);
+ be32_to_cpu(vid_hdr->data_size);
return 0;
} else {
@@ -517,11 +534,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
* previously.
*/
if (cmp_res & 4)
- return ubi_scan_add_to_list(si, pnum, ec,
- &si->corr);
+ return add_to_list(si, pnum, ec, &si->corr);
else
- return ubi_scan_add_to_list(si, pnum, ec,
- &si->erase);
+ return add_to_list(si, pnum, ec, &si->erase);
}
}
@@ -547,12 +562,9 @@ int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
if (sv->highest_lnum <= lnum) {
sv->highest_lnum = lnum;
- sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size);
+ sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
}
- if (si->max_sqnum < sqnum)
- si->max_sqnum = sqnum;
-
sv->leb_count += 1;
rb_link_node(&seb->u.rb, parent, p);
rb_insert_color(&seb->u.rb, &sv->root);
@@ -674,7 +686,7 @@ int ubi_scan_erase_peb(const struct ubi_device *ubi,
return -EINVAL;
}
- ec_hdr->ec = cpu_to_ubi64(ec);
+ ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_sync_erase(ubi, pnum, 0);
if (err < 0)
@@ -754,7 +766,7 @@ struct ubi_scan_leb *ubi_scan_get_free_peb(const struct ubi_device *ubi,
* @si: scanning information
* @pnum: the physical eraseblock number
*
- * This function returns a zero if the physical eraseblock was succesfully
+ * This function returns a zero if the physical eraseblock was successfully
* handled and a negative error code in case of failure.
*/
static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
@@ -783,8 +795,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BITFLIPS)
bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY)
- return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
- &si->erase);
+ return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
else if (err == UBI_IO_BAD_EC_HDR) {
/*
* We have to also look at the VID header, possibly it is not
@@ -806,7 +817,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
return -EINVAL;
}
- ec = ubi64_to_cpu(ech->ec);
+ ec = be64_to_cpu(ech->ec);
if (ec > UBI_MAX_ERASECOUNTER) {
/*
* Erase counter overflow. The EC headers have 64 bits
@@ -832,28 +843,28 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
else if (err == UBI_IO_BAD_VID_HDR ||
(err == UBI_IO_PEB_FREE && ec_corr)) {
/* VID header is corrupted */
- err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+ err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
goto adjust_mean_ec;
} else if (err == UBI_IO_PEB_FREE) {
/* No VID header - the physical eraseblock is free */
- err = ubi_scan_add_to_list(si, pnum, ec, &si->free);
+ err = add_to_list(si, pnum, ec, &si->free);
if (err)
return err;
goto adjust_mean_ec;
}
- vol_id = ubi32_to_cpu(vidh->vol_id);
+ vol_id = be32_to_cpu(vidh->vol_id);
if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
- int lnum = ubi32_to_cpu(vidh->lnum);
+ int lnum = be32_to_cpu(vidh->lnum);
/* Unsupported internal volume */
switch (vidh->compat) {
case UBI_COMPAT_DELETE:
ubi_msg("\"delete\" compatible internal volume %d:%d"
" found, remove it", vol_id, lnum);
- err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+ err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
break;
@@ -868,7 +879,7 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum
case UBI_COMPAT_PRESERVE:
ubi_msg("\"preserve\" compatible internal volume %d:%d"
" found", vol_id, lnum);
- err = ubi_scan_add_to_list(si, pnum, ec, &si->alien);
+ err = add_to_list(si, pnum, ec, &si->alien);
if (err)
return err;
si->alien_peb_count += 1;
@@ -1109,7 +1120,7 @@ static int paranoid_check_si(const struct ubi_device *ubi,
uint8_t *buf;
/*
- * At first, check that scanning information is ok.
+ * At first, check that scanning information is OK.
*/
ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
int leb_count = 0;
@@ -1249,12 +1260,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
goto bad_vid_hdr;
}
- if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) {
+ if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
ubi_err("bad sqnum %llu", seb->sqnum);
goto bad_vid_hdr;
}
- if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) {
+ if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
ubi_err("bad vol_id %d", sv->vol_id);
goto bad_vid_hdr;
}
@@ -1264,22 +1275,22 @@ static int paranoid_check_si(const struct ubi_device *ubi,
goto bad_vid_hdr;
}
- if (seb->lnum != ubi32_to_cpu(vidh->lnum)) {
+ if (seb->lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad lnum %d", seb->lnum);
goto bad_vid_hdr;
}
- if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) {
+ if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
ubi_err("bad used_ebs %d", sv->used_ebs);
goto bad_vid_hdr;
}
- if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) {
+ if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
ubi_err("bad data_pad %d", sv->data_pad);
goto bad_vid_hdr;
}
- if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) {
+ if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
ubi_err("bad leb_ver %u", seb->leb_ver);
goto bad_vid_hdr;
}
@@ -1288,12 +1299,12 @@ static int paranoid_check_si(const struct ubi_device *ubi,
if (!last_seb)
continue;
- if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) {
+ if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
ubi_err("bad highest_lnum %d", sv->highest_lnum);
goto bad_vid_hdr;
}
- if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) {
+ if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
ubi_err("bad last_data_size %d", sv->last_data_size);
goto bad_vid_hdr;
}
@@ -1310,8 +1321,10 @@ static int paranoid_check_si(const struct ubi_device *ubi,
memset(buf, 1, ubi->peb_count);
for (pnum = 0; pnum < ubi->peb_count; pnum++) {
err = ubi_io_is_bad(ubi, pnum);
- if (err < 0)
+ if (err < 0) {
+ kfree(buf);
return err;
+ }
else if (err)
buf[pnum] = 0;
}
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 3949f6192c76..140e82e26534 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -147,8 +147,6 @@ static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
list_add_tail(&seb->u.list, list);
}
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
- struct list_head *list);
int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
int bitflips);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index feb647f108f0..5959f91be240 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -35,6 +35,7 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/string.h>
+#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
#include <mtd/ubi-header.h>
@@ -374,9 +375,11 @@ void ubi_calculate_reserved(struct ubi_device *ubi);
#ifdef CONFIG_MTD_UBI_GLUEBI
int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
int ubi_destroy_gluebi(struct ubi_volume *vol);
+void ubi_gluebi_updated(struct ubi_volume *vol);
#else
#define ubi_create_gluebi(ubi, vol) 0
#define ubi_destroy_gluebi(vol) 0
+#define ubi_gluebi_updated(vol)
#endif
/* eba.c */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 8925b977e3dc..0efc586a8328 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -150,7 +150,7 @@ int ubi_start_update(struct ubi_device *ubi, int vol_id, long long bytes)
vol->updating = 0;
}
- vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL);
+ vol->upd_buf = vmalloc(ubi->leb_size);
if (!vol->upd_buf)
return -ENOMEM;
@@ -339,7 +339,7 @@ int ubi_more_update_data(struct ubi_device *ubi, int vol_id,
err = ubi_wl_flush(ubi);
if (err == 0) {
err = to_write;
- kfree(vol->upd_buf);
+ vfree(vol->upd_buf);
vol->updating = 0;
}
}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 622d0d18952c..ea0d5c825ab4 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -228,7 +228,7 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
for (i = 0; i < ubi->vtbl_slots; i++)
if (ubi->volumes[i] &&
ubi->volumes[i]->name_len == req->name_len &&
- strcmp(ubi->volumes[i]->name, req->name) == 0) {
+ !strcmp(ubi->volumes[i]->name, req->name)) {
dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
goto out_unlock;
}
@@ -243,7 +243,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Reserve physical eraseblocks */
if (vol->reserved_pebs > ubi->avail_pebs) {
dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
- spin_unlock(&ubi->volumes_lock);
err = -ENOSPC;
goto out_unlock;
}
@@ -281,7 +280,8 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
} else {
bytes = vol->used_bytes;
vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
@@ -320,10 +320,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req)
/* Fill volume table record */
memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
- vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs);
- vtbl_rec.alignment = cpu_to_ubi32(vol->alignment);
- vtbl_rec.data_pad = cpu_to_ubi32(vol->data_pad);
- vtbl_rec.name_len = cpu_to_ubi16(vol->name_len);
+ vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
+ vtbl_rec.alignment = cpu_to_be32(vol->alignment);
+ vtbl_rec.data_pad = cpu_to_be32(vol->data_pad);
+ vtbl_rec.name_len = cpu_to_be16(vol->name_len);
if (vol->vol_type == UBI_DYNAMIC_VOLUME)
vtbl_rec.vol_type = UBI_VID_DYNAMIC;
else
@@ -352,6 +352,7 @@ out_acc:
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
+ ubi->volumes[vol_id] = NULL;
out_unlock:
spin_unlock(&ubi->volumes_lock);
kfree(vol);
@@ -368,6 +369,7 @@ out_sysfs:
spin_lock(&ubi->volumes_lock);
ubi->rsvd_pebs -= vol->reserved_pebs;
ubi->avail_pebs += vol->reserved_pebs;
+ ubi->volumes[vol_id] = NULL;
spin_unlock(&ubi->volumes_lock);
volume_sysfs_close(vol);
return err;
@@ -503,7 +505,7 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
/* Change volume table record */
memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
- vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs);
+ vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
if (err)
goto out_acc;
@@ -537,7 +539,8 @@ int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs)
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
}
paranoid_check_volumes(ubi);
@@ -643,21 +646,33 @@ void ubi_free_volume(struct ubi_device *ubi, int vol_id)
* @ubi: UBI device description object
* @vol_id: volume ID
*/
-static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
+static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
{
int idx = vol_id2idx(ubi, vol_id);
int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
- const struct ubi_volume *vol = ubi->volumes[idx];
+ const struct ubi_volume *vol;
long long n;
const char *name;
- reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+ spin_lock(&ubi->volumes_lock);
+ reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+ vol = ubi->volumes[idx];
if (!vol) {
if (reserved_pebs) {
ubi_err("no volume info, but volume exists");
goto fail;
}
+ spin_unlock(&ubi->volumes_lock);
+ return;
+ }
+
+ if (vol->exclusive) {
+ /*
+ * The volume may be being created at the moment, do not check
+ * it (e.g., it may be in the middle of ubi_create_volume().
+ */
+ spin_unlock(&ubi->volumes_lock);
return;
}
@@ -726,7 +741,7 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
goto fail;
}
- n = vol->used_ebs * vol->usable_leb_size;
+ n = (long long)vol->used_ebs * vol->usable_leb_size;
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
if (vol->corrupted != 0) {
ubi_err("corrupted dynamic volume");
@@ -765,9 +780,9 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
}
}
- alignment = ubi32_to_cpu(ubi->vtbl[vol_id].alignment);
- data_pad = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad);
- name_len = ubi16_to_cpu(ubi->vtbl[vol_id].name_len);
+ alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment);
+ data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
+ name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len);
upd_marker = ubi->vtbl[vol_id].upd_marker;
name = &ubi->vtbl[vol_id].name[0];
if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
@@ -782,12 +797,14 @@ static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
goto fail;
}
+ spin_unlock(&ubi->volumes_lock);
return;
fail:
- ubi_err("paranoid check failed");
+ ubi_err("paranoid check failed for volume %d", vol_id);
ubi_dbg_dump_vol_info(vol);
ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+ spin_unlock(&ubi->volumes_lock);
BUG();
}
@@ -800,10 +817,8 @@ static void paranoid_check_volumes(struct ubi_device *ubi)
int i;
mutex_lock(&ubi->vtbl_mutex);
- spin_lock(&ubi->volumes_lock);
for (i = 0; i < ubi->vtbl_slots; i++)
paranoid_check_volume(ubi, i);
- spin_unlock(&ubi->volumes_lock);
mutex_unlock(&ubi->vtbl_mutex);
}
#endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index b6fd6bbd941e..bc5df50813d6 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -93,12 +93,9 @@ int ubi_change_vtbl_record(struct ubi_device *ubi, int idx,
vtbl_rec = &empty_vtbl_record;
else {
crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
- vtbl_rec->crc = cpu_to_ubi32(crc);
+ vtbl_rec->crc = cpu_to_be32(crc);
}
- dbg_msg("change record %d", idx);
- ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
-
mutex_lock(&ubi->vtbl_mutex);
memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
@@ -141,18 +138,18 @@ static int vtbl_check(const struct ubi_device *ubi,
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
- reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
- alignment = ubi32_to_cpu(vtbl[i].alignment);
- data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+ reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ alignment = be32_to_cpu(vtbl[i].alignment);
+ data_pad = be32_to_cpu(vtbl[i].data_pad);
upd_marker = vtbl[i].upd_marker;
vol_type = vtbl[i].vol_type;
- name_len = ubi16_to_cpu(vtbl[i].name_len);
+ name_len = be16_to_cpu(vtbl[i].name_len);
name = &vtbl[i].name[0];
crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
- if (ubi32_to_cpu(vtbl[i].crc) != crc) {
+ if (be32_to_cpu(vtbl[i].crc) != crc) {
ubi_err("bad CRC at record %u: %#08x, not %#08x",
- i, crc, ubi32_to_cpu(vtbl[i].crc));
+ i, crc, be32_to_cpu(vtbl[i].crc));
ubi_dbg_dump_vtbl_record(&vtbl[i], i);
return 1;
}
@@ -225,8 +222,8 @@ static int vtbl_check(const struct ubi_device *ubi,
/* Checks that all names are unique */
for (i = 0; i < ubi->vtbl_slots - 1; i++) {
for (n = i + 1; n < ubi->vtbl_slots; n++) {
- int len1 = ubi16_to_cpu(vtbl[i].name_len);
- int len2 = ubi16_to_cpu(vtbl[n].name_len);
+ int len1 = be16_to_cpu(vtbl[i].name_len);
+ int len2 = be16_to_cpu(vtbl[n].name_len);
if (len1 > 0 && len1 == len2 &&
!strncmp(vtbl[i].name, vtbl[n].name, len1)) {
@@ -288,13 +285,13 @@ retry:
}
vid_hdr->vol_type = UBI_VID_DYNAMIC;
- vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID);
+ vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
vid_hdr->data_size = vid_hdr->used_ebs =
- vid_hdr->data_pad = cpu_to_ubi32(0);
- vid_hdr->lnum = cpu_to_ubi32(copy);
- vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum);
- vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0);
+ vid_hdr->data_pad = cpu_to_be32(0);
+ vid_hdr->lnum = cpu_to_be32(copy);
+ vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+ vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
/* The EC header is already there, write the VID header */
err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
@@ -317,14 +314,15 @@ retry:
return err;
write_error:
- kfree(new_seb);
- /* May be this physical eraseblock went bad, try to pick another one */
- if (++tries <= 5) {
- err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec,
- &si->corr);
- if (!err)
- goto retry;
+ if (err == -EIO && ++tries <= 5) {
+ /*
+ * Probably this physical eraseblock went bad, try to pick
+ * another one.
+ */
+ list_add_tail(&new_seb->u.list, &si->corr);
+ goto retry;
}
+ kfree(new_seb);
out_free:
ubi_free_vid_hdr(ubi, vid_hdr);
return err;
@@ -380,11 +378,12 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
/* Read both LEB 0 and LEB 1 into memory */
ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
- leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+ leb[seb->lnum] = vmalloc(ubi->vtbl_size);
if (!leb[seb->lnum]) {
err = -ENOMEM;
goto out_free;
}
+ memset(leb[seb->lnum], 0, ubi->vtbl_size);
err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
ubi->vtbl_size);
@@ -415,7 +414,7 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
}
/* Both LEB 1 and LEB 2 are OK and consistent */
- kfree(leb[1]);
+ vfree(leb[1]);
return leb[0];
} else {
/* LEB 0 is corrupted or does not exist */
@@ -436,13 +435,13 @@ static struct ubi_vtbl_record *process_lvol(const struct ubi_device *ubi,
goto out_free;
ubi_msg("volume table was restored");
- kfree(leb[0]);
+ vfree(leb[0]);
return leb[1];
}
out_free:
- kfree(leb[0]);
- kfree(leb[1]);
+ vfree(leb[0]);
+ vfree(leb[1]);
return ERR_PTR(err);
}
@@ -460,9 +459,10 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
int i;
struct ubi_vtbl_record *vtbl;
- vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+ vtbl = vmalloc(ubi->vtbl_size);
if (!vtbl)
return ERR_PTR(-ENOMEM);
+ memset(vtbl, 0, ubi->vtbl_size);
for (i = 0; i < ubi->vtbl_slots; i++)
memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
@@ -472,7 +472,7 @@ static struct ubi_vtbl_record *create_empty_lvol(const struct ubi_device *ubi,
err = create_vtbl(ubi, si, i, vtbl);
if (err) {
- kfree(vtbl);
+ vfree(vtbl);
return ERR_PTR(err);
}
}
@@ -500,19 +500,19 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
for (i = 0; i < ubi->vtbl_slots; i++) {
cond_resched();
- if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0)
+ if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
continue; /* Empty record */
vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
if (!vol)
return -ENOMEM;
- vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
- vol->alignment = ubi32_to_cpu(vtbl[i].alignment);
- vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+ vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+ vol->alignment = be32_to_cpu(vtbl[i].alignment);
+ vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
- vol->name_len = ubi16_to_cpu(vtbl[i].name_len);
+ vol->name_len = be16_to_cpu(vtbl[i].name_len);
vol->usable_leb_size = ubi->leb_size - vol->data_pad;
memcpy(vol->name, vtbl[i].name, vol->name_len);
vol->name[vol->name_len] = '\0';
@@ -531,7 +531,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->usable_leb_size;
- vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)vol->used_ebs * vol->usable_leb_size;
continue;
}
@@ -561,7 +562,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
}
vol->used_ebs = sv->used_ebs;
- vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size;
+ vol->used_bytes =
+ (long long)(vol->used_ebs - 1) * vol->usable_leb_size;
vol->used_bytes += sv->last_data_size;
vol->last_eb_bytes = sv->last_data_size;
}
@@ -578,7 +580,8 @@ static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si,
vol->usable_leb_size = ubi->leb_size;
vol->used_ebs = vol->reserved_pebs;
vol->last_eb_bytes = vol->reserved_pebs;
- vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad);
+ vol->used_bytes =
+ (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
vol->vol_id = UBI_LAYOUT_VOL_ID;
ubi_assert(!ubi->volumes[i]);
@@ -718,7 +721,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
int i, err;
struct ubi_scan_volume *sv;
- empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b);
+ empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
/*
* The number of supported volumes is limited by the eraseblock size
@@ -783,7 +786,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si)
return 0;
out_free:
- kfree(ubi->vtbl);
+ vfree(ubi->vtbl);
for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
if (ubi->volumes[i]) {
kfree(ubi->volumes[i]);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 9ecaf77eca9e..a5a9b8d87302 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -667,7 +667,7 @@ static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int tortur
dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
- ec_hdr->ec = cpu_to_ubi64(ec);
+ ec_hdr->ec = cpu_to_be64(ec);
err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
if (err)
@@ -1060,9 +1060,8 @@ out_unlock:
static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int cancel)
{
- int err;
struct ubi_wl_entry *e = wl_wrk->e;
- int pnum = e->pnum;
+ int pnum = e->pnum, err, need;
if (cancel) {
dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1097,62 +1096,70 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
kfree(wl_wrk);
kmem_cache_free(wl_entries_slab, e);
- if (err != -EIO) {
+ if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+ err == -EBUSY) {
+ int err1;
+
+ /* Re-schedule the LEB for erasure */
+ err1 = schedule_erase(ubi, e, 0);
+ if (err1) {
+ err = err1;
+ goto out_ro;
+ }
+ return err;
+ } else if (err != -EIO) {
/*
* If this is not %-EIO, we have no idea what to do. Scheduling
* this physical eraseblock for erasure again would cause
* errors again and again. Well, lets switch to RO mode.
*/
- ubi_ro_mode(ubi);
- return err;
+ goto out_ro;
}
/* It is %-EIO, the PEB went bad */
if (!ubi->bad_allowed) {
ubi_err("bad physical eraseblock %d detected", pnum);
- ubi_ro_mode(ubi);
- err = -EIO;
- } else {
- int need;
-
- spin_lock(&ubi->volumes_lock);
- need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
- if (need > 0) {
- need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
- ubi->avail_pebs -= need;
- ubi->rsvd_pebs += need;
- ubi->beb_rsvd_pebs += need;
- if (need > 0)
- ubi_msg("reserve more %d PEBs", need);
- }
+ goto out_ro;
+ }
- if (ubi->beb_rsvd_pebs == 0) {
- spin_unlock(&ubi->volumes_lock);
- ubi_err("no reserved physical eraseblocks");
- ubi_ro_mode(ubi);
- return -EIO;
- }
+ spin_lock(&ubi->volumes_lock);
+ need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+ if (need > 0) {
+ need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+ ubi->avail_pebs -= need;
+ ubi->rsvd_pebs += need;
+ ubi->beb_rsvd_pebs += need;
+ if (need > 0)
+ ubi_msg("reserve more %d PEBs", need);
+ }
+ if (ubi->beb_rsvd_pebs == 0) {
spin_unlock(&ubi->volumes_lock);
- ubi_msg("mark PEB %d as bad", pnum);
+ ubi_err("no reserved physical eraseblocks");
+ goto out_ro;
+ }
- err = ubi_io_mark_bad(ubi, pnum);
- if (err) {
- ubi_ro_mode(ubi);
- return err;
- }
+ spin_unlock(&ubi->volumes_lock);
+ ubi_msg("mark PEB %d as bad", pnum);
- spin_lock(&ubi->volumes_lock);
- ubi->beb_rsvd_pebs -= 1;
- ubi->bad_peb_count += 1;
- ubi->good_peb_count -= 1;
- ubi_calculate_reserved(ubi);
- if (ubi->beb_rsvd_pebs == 0)
- ubi_warn("last PEB from the reserved pool was used");
- spin_unlock(&ubi->volumes_lock);
- }
+ err = ubi_io_mark_bad(ubi, pnum);
+ if (err)
+ goto out_ro;
+
+ spin_lock(&ubi->volumes_lock);
+ ubi->beb_rsvd_pebs -= 1;
+ ubi->bad_peb_count += 1;
+ ubi->good_peb_count -= 1;
+ ubi_calculate_reserved(ubi);
+ if (ubi->beb_rsvd_pebs == 0)
+ ubi_warn("last PEB from the reserved pool was used");
+ spin_unlock(&ubi->volumes_lock);
+
+ return err;
+out_ro:
+ ubi_ro_mode(ubi);
return err;
}
@@ -1346,6 +1353,7 @@ static int ubi_thread(void *u)
ubi_msg("background thread \"%s\" started, PID %d",
ubi->bgt_name, current->pid);
+ set_freezable();
for (;;) {
int err;
@@ -1444,7 +1452,7 @@ int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si)
if (ubi_devices_cnt == 0) {
wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab",
sizeof(struct ubi_wl_entry),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!wl_entries_slab)
return -ENOMEM;
}
@@ -1633,7 +1641,7 @@ static int paranoid_check_ec(const struct ubi_device *ubi, int pnum, int ec)
goto out_free;
}
- read_ec = ubi64_to_cpu(ec_hdr->ec);
+ read_ec = be64_to_cpu(ec_hdr->ec);
if (ec != read_ec) {
ubi_err("paranoid check failed for PEB %d", pnum);
ubi_err("read EC is %lld, should be %d", read_ec, ec);
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index da1a22c13865..ab18343e58ef 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -990,7 +990,7 @@ static void elmc_rcv_int(struct net_device *dev)
if (skb != NULL) {
skb_reserve(skb, 2); /* 16 byte alignment */
skb_put(skb,totlen);
- eth_copy_and_sum(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen,0);
+ skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 0877fc372f4b..e89ace109a5d 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -333,9 +333,9 @@ static int lance_rx (struct net_device *dev)
skb_reserve (skb, 2); /* 16 byte align */
skb_put (skb, len); /* make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *)&(ib->rx_buf [lp->rx_new][0]),
- len, 0);
+ len);
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 58bbc3e6d0de..e970e64bf966 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -26,7 +26,6 @@
TODO:
* Test Tx checksumming thoroughly
- * Implement dev->tx_timeout
Low priority TODO:
* Complete reset on PciErr
@@ -1218,6 +1217,30 @@ static int cp_close (struct net_device *dev)
return 0;
}
+static void cp_tx_timeout(struct net_device *dev)
+{
+ struct cp_private *cp = netdev_priv(dev);
+ unsigned long flags;
+ int rc;
+
+ printk(KERN_WARNING "%s: Transmit timeout, status %2x %4x %4x %4x\n",
+ dev->name, cpr8(Cmd), cpr16(CpCmd),
+ cpr16(IntrStatus), cpr16(IntrMask));
+
+ spin_lock_irqsave(&cp->lock, flags);
+
+ cp_stop_hw(cp);
+ cp_clean_rings(cp);
+ rc = cp_init_rings(cp);
+ cp_start_hw(cp);
+
+ netif_wake_queue(dev);
+
+ spin_unlock_irqrestore(&cp->lock, flags);
+
+ return;
+}
+
#ifdef BROKEN
static int cp_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -1799,7 +1822,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
void __iomem *regs;
resource_size_t pciaddr;
unsigned int addr_len, i, pci_using_dac;
- u8 pci_rev;
#ifndef MODULE
static int version_printed;
@@ -1807,13 +1829,11 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
printk("%s", version);
#endif
- pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
-
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
- pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
+ pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->revision < 0x20) {
dev_err(&pdev->dev,
"This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
- pdev->vendor, pdev->device, pci_rev);
+ pdev->vendor, pdev->device, pdev->revision);
dev_err(&pdev->dev, "Try the \"8139too\" driver instead.\n");
return -ENODEV;
}
@@ -1923,10 +1943,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
dev->change_mtu = cp_change_mtu;
#endif
dev->ethtool_ops = &cp_ethtool_ops;
-#if 0
dev->tx_timeout = cp_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-#endif
#if CP_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index a844b1fe2dc4..327eaa7b4999 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -931,7 +931,6 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
int i, addr_len, option;
void __iomem *ioaddr;
static int board_idx = -1;
- u8 pci_rev;
assert (pdev != NULL);
assert (ent != NULL);
@@ -949,13 +948,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
}
#endif
- pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
-
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
- pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
+ pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pdev->revision >= 0x20) {
dev_info(&pdev->dev,
"This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
- pdev->vendor, pdev->device, pci_rev);
+ pdev->vendor, pdev->device, pdev->revision);
dev_info(&pdev->dev,
"Use the \"8139cp\" driver for improved performance and stability.\n");
}
@@ -2017,7 +2014,7 @@ no_early_rx:
#if RX_BUF_IDX == 3
wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
#else
- eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
+ skb_copy_to_linear_data (skb, &rx_ring[ring_offset + 4], pkt_size);
#endif
skb_put (skb, pkt_size);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index b941c74a06c4..f8a602caabcb 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -5,6 +5,7 @@
menuconfig NETDEVICES
default y if UML
+ depends on NET
bool "Network device support"
---help---
You can say N here if you don't intend to connect your Linux box to
@@ -25,6 +26,14 @@ menuconfig NETDEVICES
# that for each of the symbols.
if NETDEVICES
+config NETDEVICES_MULTIQUEUE
+ bool "Netdevice multiple hardware queue support"
+ ---help---
+ Say Y here if you want to allow the network stack to use multiple
+ hardware TX queues on an ethernet device.
+
+ Most people will say N here.
+
config IFB
tristate "Intermediate Functional Block support"
depends on NET_CLS_ACT
@@ -74,6 +83,16 @@ config BONDING
To compile this driver as a module, choose M here: the module
will be called bonding.
+config MACVLAN
+ tristate "MAC-VLAN support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ This allows one to create virtual interfaces that map packets to
+ or from specific MAC addresses to a particular interface.
+
+ To compile this driver as a module, choose M here: the module
+ will be called macvlan.
+
config EQUALIZER
tristate "EQL (serial line load balancing) support"
---help---
@@ -187,7 +206,7 @@ config MII
config MACB
tristate "Atmel MACB support"
depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263
- select MII
+ select PHYLIB
help
The Atmel MACB ethernet interface is found on many AT32 and AT91
parts. Say Y to include support for the MACB chip.
@@ -387,22 +406,6 @@ config ATARILANCE
on the AMD Lance chipset: RieblCard (with or without battery), or
PAMCard VME (also the version by Rhotron, with different addresses).
-config ATARI_BIONET
- tristate "BioNet-100 support"
- depends on ATARI && ATARI_ACSI && BROKEN
- help
- Say Y to include support for BioData's BioNet-100 Ethernet adapter
- for the ACSI port. The driver works (has to work...) with a polled
- I/O scheme, so it's rather slow :-(
-
-config ATARI_PAMSNET
- tristate "PAMsNet support"
- depends on ATARI && ATARI_ACSI && BROKEN
- help
- Say Y to include support for the PAMsNet Ethernet adapter for the
- ACSI port ("ACSI node"). The driver works (has to work...) with a
- polled I/O scheme, so it's rather slow :-(
-
config SUN3LANCE
tristate "Sun3/Sun3x on-board LANCE support"
depends on SUN3 || SUN3X
@@ -586,6 +589,12 @@ config CASSINI
Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also
<http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf>
+config SUNVNET
+ tristate "Sun Virtual Network support"
+ depends on SUN_LDOMS
+ help
+ Support for virtual network devices under Sun Logical Domains.
+
config NET_VENDOR_3COM
bool "3COM cards"
depends on ISA || EISA || MCA || PCI
@@ -830,6 +839,50 @@ config ULTRA32
<file:Documentation/networking/net-modules.txt>. The module
will be called smc-ultra32.
+config BFIN_MAC
+ tristate "Blackfin 536/537 on-chip mac support"
+ depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
+ select CRC32
+ select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
+ help
+ This is the driver for blackfin on-chip mac device. Say Y if you want it
+ compiled into the kernel. This driver is also available as a module
+ ( = code which can be inserted in and removed from the running kernel
+ whenever you want). The module will be called bfin_mac.
+
+config BFIN_MAC_USE_L1
+ bool "Use L1 memory for rx/tx packets"
+ depends on BFIN_MAC && BF537
+ default y
+ help
+ To get maximum network performace, you should use L1 memory as rx/tx buffers.
+ Say N here if you want to reserve L1 memory for other uses.
+
+config BFIN_TX_DESC_NUM
+ int "Number of transmit buffer packets"
+ depends on BFIN_MAC
+ range 6 10 if BFIN_MAC_USE_L1
+ range 10 100
+ default "10"
+ help
+ Set the number of buffer packets used in driver.
+
+config BFIN_RX_DESC_NUM
+ int "Number of receive buffer packets"
+ depends on BFIN_MAC
+ range 20 100 if BFIN_MAC_USE_L1
+ range 20 800
+ default "20"
+ help
+ Set the number of buffer packets used in driver.
+
+config BFIN_MAC_RMII
+ bool "RMII PHY Interface (EXPERIMENTAL)"
+ depends on BFIN_MAC && EXPERIMENTAL
+ default n
+ help
+ Use Reduced PHY MII Interface
+
config SMC9194
tristate "SMC 9194 support"
depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
@@ -877,7 +930,7 @@ config NET_NETX
config DM9000
tristate "DM9000 support"
- depends on ARM || MIPS
+ depends on ARM || BLACKFIN || MIPS
select CRC32
select MII
---help---
@@ -2478,6 +2531,18 @@ source "drivers/atm/Kconfig"
source "drivers/s390/net/Kconfig"
+config XEN_NETDEV_FRONTEND
+ tristate "Xen network device frontend driver"
+ depends on XEN
+ default y
+ help
+ The network device frontend driver allows the kernel to
+ access network devices exported exported by a virtual
+ machine containing a physical network device driver. The
+ frontend driver is intended for unprivileged guest domains;
+ if you are compiling a kernel for a Xen guest, you almost
+ certainly want to enable this.
+
config ISERIES_VETH
tristate "iSeries Virtual Ethernet driver support"
depends on PPC_ISERIES
@@ -2784,6 +2849,19 @@ config PPPOATM
which can lead to bad results if the ATM peer loses state and
changes its encapsulation unilaterally.
+config PPPOL2TP
+ tristate "PPP over L2TP (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && PPP
+ help
+ Support for PPP-over-L2TP socket family. L2TP is a protocol
+ used by ISPs and enterprises to tunnel PPP traffic over UDP
+ tunnels. L2TP is replacing PPTP for VPN uses.
+
+ This kernel component handles only L2TP data packets: a
+ userland daemon handles L2TP the control protocol (tunnel
+ and session setup). One such daemon is OpenL2TP
+ (http://openl2tp.sourceforge.net/).
+
config SLIP
tristate "SLIP (serial line) support"
---help---
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 1bbcbedad04a..336af0635df8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SUNBMAC) += sunbmac.o
obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o
obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o
obj-$(CONFIG_CASSINI) += cassini.o
+obj-$(CONFIG_SUNVNET) += sunvnet.o
obj-$(CONFIG_MACE) += mace.o
obj-$(CONFIG_BMAC) += bmac.o
@@ -121,12 +122,16 @@ obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+obj-$(CONFIG_PPPOL2TP) += pppox.o pppol2tp.o
obj-$(CONFIG_SLIP) += slip.o
obj-$(CONFIG_SLHC) += slhc.o
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
+obj-$(CONFIG_MACVLAN) += macvlan.o
obj-$(CONFIG_DE600) += de600.o
obj-$(CONFIG_DE620) += de620.o
obj-$(CONFIG_LANCE) += lance.o
@@ -172,14 +177,13 @@ obj-$(CONFIG_ZORRO8390) += zorro8390.o
obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
obj-$(CONFIG_EQUALIZER) += eql.o
+obj-$(CONFIG_LGUEST_GUEST) += lguest_net.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
obj-$(CONFIG_DECLANCE) += declance.o
obj-$(CONFIG_ATARILANCE) += atarilance.o
-obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o
-obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o
obj-$(CONFIG_A2065) += a2065.o
obj-$(CONFIG_HYDRA) += hydra.o
obj-$(CONFIG_ARIADNE) += ariadne.o
@@ -197,6 +201,7 @@ obj-$(CONFIG_S2IO) += s2io.o
obj-$(CONFIG_MYRI10GE) += myri10ge/
obj-$(CONFIG_SMC91X) += smc91x.o
obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
obj-$(CONFIG_DM9000) += dm9000.o
obj-$(CONFIG_FEC_8XX) += fec_8xx/
obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 1c3e293fbaf7..3b79c6cf21a3 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -75,8 +75,6 @@ extern struct net_device *atarilance_probe(int unit);
extern struct net_device *sun3lance_probe(int unit);
extern struct net_device *sun3_82586_probe(int unit);
extern struct net_device *apne_probe(int unit);
-extern struct net_device *bionet_probe(int unit);
-extern struct net_device *pamsnet_probe(int unit);
extern struct net_device *cs89x0_probe(int unit);
extern struct net_device *hplance_probe(int unit);
extern struct net_device *bagetlance_probe(int unit);
@@ -264,12 +262,6 @@ static struct devprobe2 m68k_probes[] __initdata = {
#ifdef CONFIG_APNE /* A1200 PCMCIA NE2000 */
{apne_probe, 0},
#endif
-#ifdef CONFIG_ATARI_BIONET /* Atari Bionet Ethernet board */
- {bionet_probe, 0},
-#endif
-#ifdef CONFIG_ATARI_PAMSNET /* Atari PAMsNet Ethernet board */
- {pamsnet_probe, 0},
-#endif
#ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */
{mvme147lance_probe, 0},
#endif
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 81d5a374042a..a45de6975bfe 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -322,9 +322,9 @@ static int lance_rx (struct net_device *dev)
skb_reserve (skb, 2); /* 16 byte align */
skb_put (skb, len); /* make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *)&(ib->rx_buf [lp->rx_new][0]),
- len, 0);
+ len);
skb->protocol = eth_type_trans (skb, dev);
netif_rx (skb);
dev->last_rx = jiffies;
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index a241ae7855a3..bc5a38a6705f 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -746,7 +746,7 @@ static int ariadne_rx(struct net_device *dev)
skb_reserve(skb,2); /* 16 byte align */
skb_put(skb,pkt_len); /* Make room */
- eth_copy_and_sum(skb, (char *)priv->rx_buff[entry], pkt_len,0);
+ skb_copy_to_linear_data(skb, (char *)priv->rx_buff[entry], pkt_len);
skb->protocol=eth_type_trans(skb,dev);
#if 0
printk(KERN_DEBUG "RX pkt type 0x%04x from ",
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index 5bf2d33887ac..f9cc2b621fe2 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -43,6 +43,7 @@ config ARM_AT91_ETHER
config EP93XX_ETH
tristate "EP93xx Ethernet support"
depends on ARM && ARCH_EP93XX
+ select MII
help
This is a driver for the ethernet hardware included in EP93xx CPUs.
Say Y if you are building a kernel for EP93xx based devices.
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index 2438c5bff237..f6ece1d43f6e 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -258,7 +258,7 @@ static int ep93xx_rx(struct net_device *dev, int *budget)
skb_reserve(skb, 2);
dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr,
length, DMA_FROM_DEVICE);
- eth_copy_and_sum(skb, ep->rx_buf[entry], length, 0);
+ skb_copy_to_linear_data(skb, ep->rx_buf[entry], length);
skb_put(skb, length);
skb->protocol = eth_type_trans(skb, dev);
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index f21148e7b579..80f33b6d5713 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -36,7 +36,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
@@ -75,7 +74,7 @@ static void ether1_timeout(struct net_device *dev);
/* ------------------------------------------------------------------------- */
-static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
#define BUS_16 16
#define BUS_8 8
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index da713500654d..3805506a3ab8 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -51,7 +51,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
@@ -69,7 +68,7 @@
#include <asm/ecard.h>
#include <asm/io.h>
-static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+static char version[] __devinitdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
#include "ether3.h"
@@ -464,7 +463,7 @@ static void ether3_setmulticastlist(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
/* promiscuous mode */
priv(dev)->regs.config1 |= CFG1_RECVPROMISC;
- } else if (dev->flags & IFF_ALLMULTI) {
+ } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI;
} else
priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD;
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index 769ba69451f4..0d37d9d1fd78 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -31,7 +31,6 @@
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
deleted file mode 100644
index 3d87bd2b4194..000000000000
--- a/drivers/net/atari_bionet.c
+++ /dev/null
@@ -1,675 +0,0 @@
-/* bionet.c BioNet-100 device driver for linux68k.
- *
- * Version: @(#)bionet.c 1.0 02/06/96
- *
- * Author: Hartmut Laue <laue@ifk-mp.uni-kiel.de>
- * and Torsten Narjes <narjes@ifk-mp.uni-kiel.de>
- *
- * Little adaptions for integration into pl7 by Roman Hodek
- *
- * Some changes in bionet_poll_rx by Karl-Heinz Lohner
- *
- What is it ?
- ------------
- This driver controls the BIONET-100 LAN-Adapter which connects
- an ATARI ST/TT via the ACSI-port to an Ethernet-based network.
-
- This version can be compiled as a loadable module (See the
- compile command at the bottom of this file).
- At load time, you can optionally set the debugging level and the
- fastest response time on the command line of 'insmod'.
-
- 'bionet_debug'
- controls the amount of diagnostic messages:
- 0 : no messages
- >0 : see code for meaning of printed messages
-
- 'bionet_min_poll_time' (always >=1)
- gives the time (in jiffies) between polls. Low values
- increase the system load (beware!)
-
- When loaded, a net device with the name 'bio0' becomes available,
- which can be controlled with the usual 'ifconfig' command.
-
- It is possible to compile this driver into the kernel like other
- (net) drivers. For this purpose, some source files (e.g. config-files
- makefiles, Space.c) must be changed accordingly. (You may refer to
- other drivers how to do it.) In this case, the device will be detected
- at boot time and (probably) appear as 'eth0'.
-
- This code is based on several sources:
- - The driver code for a parallel port ethernet adapter by
- Donald Becker (see file 'atp.c' from the PC linux distribution)
- - The ACSI code by Roman Hodek for the ATARI-ACSI harddisk support
- and DMA handling.
- - Very limited information about moving packets in and out of the
- BIONET-adapter from the TCP package for TOS by BioData GmbH.
-
- Theory of Operation
- -------------------
- Because the ATARI DMA port is usually shared between several
- devices (eg. harddisk, floppy) we cannot block the ACSI bus
- while waiting for interrupts. Therefore we use a polling mechanism
- to fetch packets from the adapter. For the same reason, we send
- packets without checking that the previous packet has been sent to
- the LAN. We rely on the higher levels of the networking code to detect
- missing packets and resend them.
-
- Before we access the ATARI DMA controller, we check if another
- process is using the DMA. If not, we lock the DMA, perform one or
- more packet transfers and unlock the DMA before returning.
- We do not use 'stdma_lock' unconditionally because it is unclear
- if the networking code can be set to sleep, which will happen if
- another (possibly slow) device is using the DMA controller.
-
- The polling is done via timer interrupts which periodically
- 'simulate' an interrupt from the Ethernet adapter. The time (in jiffies)
- between polls varies depending on an estimate of the net activity.
- The allowed range is given by the variable 'bionet_min_poll_time'
- for the lower (fastest) limit and the constant 'MAX_POLL_TIME'
- for the higher (slowest) limit.
-
- Whenever a packet arrives, we switch to fastest response by setting
- the polling time to its lowest limit. If the following poll fails,
- because no packets have arrived, we increase the time for the next
- poll. When the net activity is low, the polling time effectively
- stays at its maximum value, resulting in the lowest load for the
- machine.
- */
-
-#define MAX_POLL_TIME 10
-
-static char version[] =
- "bionet.c:v1.0 06-feb-96 (c) Hartmut Laue.\n";
-
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-#include <linux/bitops.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/setup.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_acsi.h>
-#include <asm/atari_stdma.h>
-
-
-/* use 0 for production, 1 for verification, >2 for debug
- */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-/*
- * Global variable 'bionet_debug'. Can be set at load time by 'insmod'
- */
-unsigned int bionet_debug = NET_DEBUG;
-module_param(bionet_debug, int, 0);
-MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)");
-MODULE_LICENSE("GPL");
-
-static unsigned int bionet_min_poll_time = 2;
-
-
-/* Information that need to be kept for each board.
- */
-struct net_local {
- struct net_device_stats stats;
- long open_time; /* for debugging */
- int poll_time; /* polling time varies with net load */
-};
-
-static struct nic_pkt_s { /* packet format */
- unsigned char status;
- unsigned char dummy;
- unsigned char l_lo, l_hi;
- unsigned char buffer[3000];
-} *nic_packet;
-unsigned char *phys_nic_packet;
-
-/* Index to functions, as function prototypes.
- */
-static int bionet_open(struct net_device *dev);
-static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void bionet_poll_rx(struct net_device *);
-static int bionet_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
-static void bionet_tick(unsigned long);
-
-static DEFINE_TIMER(bionet_timer, bionet_tick, 0, 0);
-
-#define STRAM_ADDR(a) (((a) & 0xff000000) == 0)
-
-/* The following routines access the ethernet board connected to the
- * ACSI port via the st_dma chip.
- */
-#define NODE_ADR 0x60
-
-#define C_READ 8
-#define C_WRITE 0x0a
-#define C_GETEA 0x0f
-#define C_SETCR 0x0e
-
-static int
-sendcmd(unsigned int a0, unsigned int mod, unsigned int cmd) {
- unsigned int c;
-
- dma_wd.dma_mode_status = (mod | ((a0) ? 2 : 0) | 0x88);
- dma_wd.fdc_acces_seccount = cmd;
- dma_wd.dma_mode_status = (mod | 0x8a);
-
- if( !acsi_wait_for_IRQ(HZ/2) ) /* wait for cmd ack */
- return -1; /* timeout */
-
- c = dma_wd.fdc_acces_seccount;
- return (c & 0xff);
-}
-
-
-static void
-set_status(int cr) {
- sendcmd(0,0x100,NODE_ADR | C_SETCR); /* CMD: SET CR */
- sendcmd(1,0x100,cr);
-
- dma_wd.dma_mode_status = 0x80;
-}
-
-static int
-get_status(unsigned char *adr) {
- int i,c;
-
- DISABLE_IRQ();
- c = sendcmd(0,0x00,NODE_ADR | C_GETEA); /* CMD: GET ETH ADR*/
- if( c < 0 ) goto gsend;
-
- /* now read status bytes */
-
- for (i=0; i<6; i++) {
- dma_wd.fdc_acces_seccount = 0; /* request next byte */
-
- if( !acsi_wait_for_IRQ(HZ/2) ) { /* wait for cmd ack */
- c = -1;
- goto gsend; /* timeout */
- }
- c = dma_wd.fdc_acces_seccount;
- *adr++ = (unsigned char)c;
- }
- c = 1;
-gsend:
- dma_wd.dma_mode_status = 0x80;
- return c;
-}
-
-static irqreturn_t
-bionet_intr(int irq, void *data) {
- return IRQ_HANDLED;
-}
-
-
-static int
-get_frame(unsigned long paddr, int odd) {
- int c;
- unsigned long flags;
-
- DISABLE_IRQ();
- local_irq_save(flags);
-
- dma_wd.dma_mode_status = 0x9a;
- dma_wd.dma_mode_status = 0x19a;
- dma_wd.dma_mode_status = 0x9a;
- dma_wd.fdc_acces_seccount = 0x04; /* sector count (was 5) */
- dma_wd.dma_lo = (unsigned char)paddr;
- paddr >>= 8;
- dma_wd.dma_md = (unsigned char)paddr;
- paddr >>= 8;
- dma_wd.dma_hi = (unsigned char)paddr;
- local_irq_restore(flags);
-
- c = sendcmd(0,0x00,NODE_ADR | C_READ); /* CMD: READ */
- if( c < 128 ) goto rend;
-
- /* now read block */
-
- c = sendcmd(1,0x00,odd); /* odd flag for address shift */
- dma_wd.dma_mode_status = 0x0a;
-
- if( !acsi_wait_for_IRQ(100) ) { /* wait for DMA to complete */
- c = -1;
- goto rend;
- }
- dma_wd.dma_mode_status = 0x8a;
- dma_wd.dma_mode_status = 0x18a;
- dma_wd.dma_mode_status = 0x8a;
- c = dma_wd.fdc_acces_seccount;
-
- dma_wd.dma_mode_status = 0x88;
- c = dma_wd.fdc_acces_seccount;
- c = 1;
-
-rend:
- dma_wd.dma_mode_status = 0x80;
- udelay(40);
- acsi_wait_for_noIRQ(20);
- return c;
-}
-
-
-static int
-hardware_send_packet(unsigned long paddr, int cnt) {
- unsigned int c;
- unsigned long flags;
-
- DISABLE_IRQ();
- local_irq_save(flags);
-
- dma_wd.dma_mode_status = 0x19a;
- dma_wd.dma_mode_status = 0x9a;
- dma_wd.dma_mode_status = 0x19a;
- dma_wd.dma_lo = (unsigned char)paddr;
- paddr >>= 8;
- dma_wd.dma_md = (unsigned char)paddr;
- paddr >>= 8;
- dma_wd.dma_hi = (unsigned char)paddr;
-
- dma_wd.fdc_acces_seccount = 0x4; /* sector count */
- local_irq_restore(flags);
-
- c = sendcmd(0,0x100,NODE_ADR | C_WRITE); /* CMD: WRITE */
- c = sendcmd(1,0x100,cnt&0xff);
- c = sendcmd(1,0x100,cnt>>8);
-
- /* now write block */
-
- dma_wd.dma_mode_status = 0x10a; /* DMA enable */
- if( !acsi_wait_for_IRQ(100) ) /* wait for DMA to complete */
- goto end;
-
- dma_wd.dma_mode_status = 0x19a; /* DMA disable ! */
- c = dma_wd.fdc_acces_seccount;
-
-end:
- c = sendcmd(1,0x100,0);
- c = sendcmd(1,0x100,0);
-
- dma_wd.dma_mode_status = 0x180;
- udelay(40);
- acsi_wait_for_noIRQ(20);
- return( c & 0x02);
-}
-
-
-/* Check for a network adaptor of this type, and return '0' if one exists.
- */
-struct net_device * __init bionet_probe(int unit)
-{
- struct net_device *dev;
- unsigned char station_addr[6];
- static unsigned version_printed;
- static int no_more_found; /* avoid "Probing for..." printed 4 times */
- int i;
- int err;
-
- if (!MACH_IS_ATARI || no_more_found)
- return ERR_PTR(-ENODEV);
-
- dev = alloc_etherdev(sizeof(struct net_local));
- if (!dev)
- return ERR_PTR(-ENOMEM);
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
- SET_MODULE_OWNER(dev);
-
- printk("Probing for BioNet 100 Adapter...\n");
-
- stdma_lock(bionet_intr, NULL);
- i = get_status(station_addr); /* Read the station address PROM. */
- ENABLE_IRQ();
- stdma_release();
-
- /* Check the first three octets of the S.A. for the manufactor's code.
- */
-
- if( i < 0
- || station_addr[0] != 'B'
- || station_addr[1] != 'I'
- || station_addr[2] != 'O' ) {
- no_more_found = 1;
- printk( "No BioNet 100 found.\n" );
- free_netdev(dev);
- return ERR_PTR(-ENODEV);
- }
-
- if (bionet_debug > 0 && version_printed++ == 0)
- printk(version);
-
- printk("%s: %s found, eth-addr: %02x-%02x-%02x:%02x-%02x-%02x.\n",
- dev->name, "BioNet 100",
- station_addr[0], station_addr[1], station_addr[2],
- station_addr[3], station_addr[4], station_addr[5]);
-
- /* Initialize the device structure. */
-
- nic_packet = (struct nic_pkt_s *)acsi_buffer;
- phys_nic_packet = (unsigned char *)phys_acsi_buffer;
- if (bionet_debug > 0) {
- printk("nic_packet at 0x%p, phys at 0x%p\n",
- nic_packet, phys_nic_packet );
- }
-
- dev->open = bionet_open;
- dev->stop = bionet_close;
- dev->hard_start_xmit = bionet_send_packet;
- dev->get_stats = net_get_stats;
-
- /* Fill in the fields of the device structure with ethernet-generic
- * values. This should be in a common file instead of per-driver.
- */
-
- for (i = 0; i < ETH_ALEN; i++) {
-#if 0
- dev->broadcast[i] = 0xff;
-#endif
- dev->dev_addr[i] = station_addr[i];
- }
- err = register_netdev(dev);
- if (!err)
- return dev;
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
-
- This routine should set everything up anew at each open, even
- registers that "should" only need to be set once at boot, so that
- there is non-reboot way to recover if something goes wrong.
- */
-static int
-bionet_open(struct net_device *dev) {
- struct net_local *lp = netdev_priv(dev);
-
- if (bionet_debug > 0)
- printk("bionet_open\n");
- stdma_lock(bionet_intr, NULL);
-
- /* Reset the hardware here.
- */
- set_status(4);
- lp->open_time = 0; /*jiffies*/
- lp->poll_time = MAX_POLL_TIME;
-
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
- stdma_release();
- bionet_timer.data = (long)dev;
- bionet_timer.expires = jiffies + lp->poll_time;
- add_timer(&bionet_timer);
- return 0;
-}
-
-static int
-bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
-
- /* Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
- local_irq_save(flags);
-
- if (stdma_islocked()) {
- local_irq_restore(flags);
- lp->stats.tx_errors++;
- }
- else {
- int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned long buf = virt_to_phys(skb->data);
- int stat;
-
- stdma_lock(bionet_intr, NULL);
- local_irq_restore(flags);
- if( !STRAM_ADDR(buf+length-1) ) {
- skb_copy_from_linear_data(skb, nic_packet->buffer,
- length);
- buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer;
- }
-
- if (bionet_debug >1) {
- u_char *data = nic_packet->buffer, *p;
- int i;
-
- printk( "%s: TX pkt type 0x%4x from ", dev->name,
- ((u_short *)data)[6]);
-
- for( p = &data[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++,i != 5 ? ":" : "" );
- printk(" to ");
-
- for( p = data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
-
- printk( "%s: ", dev->name );
- printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
- " %02x%02x%02x%02x len %d\n",
- data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
- data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
- data[28], data[29], data[30], data[31], data[32], data[33],
- length );
- }
- dma_cache_maintenance(buf, length, 1);
-
- stat = hardware_send_packet(buf, length);
- ENABLE_IRQ();
- stdma_release();
-
- dev->trans_start = jiffies;
- dev->tbusy = 0;
- lp->stats.tx_packets++;
- lp->stats.tx_bytes+=length;
- }
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/* We have a good packet(s), get it/them out of the buffers.
- */
-static void
-bionet_poll_rx(struct net_device *dev) {
- struct net_local *lp = netdev_priv(dev);
- int boguscount = 10;
- int pkt_len, status;
- unsigned long flags;
-
- local_irq_save(flags);
- /* ++roman: Take care at locking the ST-DMA... This must be done with ints
- * off, since otherwise an int could slip in between the question and the
- * locking itself, and then we'd go to sleep... And locking itself is
- * necessary to keep the floppy_change timer from working with ST-DMA
- * registers. */
- if (stdma_islocked()) {
- local_irq_restore(flags);
- return;
- }
- stdma_lock(bionet_intr, NULL);
- DISABLE_IRQ();
- local_irq_restore(flags);
-
- if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++;
-
- while(boguscount--) {
- status = get_frame((unsigned long)phys_nic_packet, 0);
-
- if( status == 0 ) break;
-
- /* Good packet... */
-
- dma_cache_maintenance((unsigned long)phys_nic_packet, 1520, 0);
-
- pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo;
-
- lp->poll_time = bionet_min_poll_time; /* fast poll */
- if( pkt_len >= 60 && pkt_len <= 1520 ) {
- /* ^^^^ war 1514 KHL */
- /* Malloc up new buffer.
- */
- struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 );
- if (skb == NULL) {
- printk("%s: Memory squeeze, dropping packet.\n",
- dev->name);
- lp->stats.rx_dropped++;
- break;
- }
-
- skb_reserve( skb, 2 ); /* 16 Byte align */
- skb_put( skb, pkt_len ); /* make room */
-
- /* 'skb->data' points to the start of sk_buff data area.
- */
- skb_copy_to_linear_data(skb, nic_packet->buffer,
- pkt_len);
- skb->protocol = eth_type_trans( skb, dev );
- netif_rx(skb);
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
-
- /* If any worth-while packets have been received, dev_rint()
- has done a mark_bh(INET_BH) for us and will work on them
- when we get to the bottom-half routine.
- */
-
- if (bionet_debug >1) {
- u_char *data = nic_packet->buffer, *p;
- int i;
-
- printk( "%s: RX pkt type 0x%4x from ", dev->name,
- ((u_short *)data)[6]);
-
-
- for( p = &data[6], i = 0; i < 6; i++ )
- printk("%02x%s", *p++,i != 5 ? ":" : "" );
- printk(" to ");
- for( p = data, i = 0; i < 6; i++ )
- printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
-
- printk( "%s: ", dev->name );
- printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
- " %02x%02x%02x%02x len %d\n",
- data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19],
- data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27],
- data[28], data[29], data[30], data[31], data[32], data[33],
- pkt_len );
- }
- }
- else {
- printk(" Packet has wrong length: %04d bytes\n", pkt_len);
- lp->stats.rx_errors++;
- }
- }
- stdma_release();
- ENABLE_IRQ();
- return;
-}
-
-/* bionet_tick: called by bionet_timer. Reads packets from the adapter,
- * passes them to the higher layers and restarts the timer.
- */
-static void
-bionet_tick(unsigned long data) {
- struct net_device *dev = (struct net_device *)data;
- struct net_local *lp = netdev_priv(dev);
-
- if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 )
- printk("bionet_tick: %ld\n", lp->open_time);
-
- if( !stdma_islocked() ) bionet_poll_rx(dev);
-
- bionet_timer.expires = jiffies + lp->poll_time;
- add_timer(&bionet_timer);
-}
-
-/* The inverse routine to bionet_open().
- */
-static int
-bionet_close(struct net_device *dev) {
- struct net_local *lp = netdev_priv(dev);
-
- if (bionet_debug > 0)
- printk("bionet_close, open_time=%ld\n", lp->open_time);
- del_timer(&bionet_timer);
- stdma_lock(bionet_intr, NULL);
-
- set_status(0);
- lp->open_time = 0;
-
- dev->tbusy = 1;
- dev->start = 0;
-
- stdma_release();
- return 0;
-}
-
-/* Get the current statistics.
- This may be called with the card open or closed.
- */
-static struct net_device_stats *net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
-
-#ifdef MODULE
-
-static struct net_device *bio_dev;
-
-int init_module(void)
-{
- bio_dev = bionet_probe(-1);
- if (IS_ERR(bio_dev))
- return PTR_ERR(bio_dev);
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_netdev(bio_dev);
- free_netdev(bio_dev);
-}
-
-#endif /* MODULE */
-
-/* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include
- -b m68k-linuxaout -Wall -Wstrict-prototypes -O2
- -fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c bionet.c"
- * version-control: t
- * kept-new-versions: 5
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
deleted file mode 100644
index f7356374a2e7..000000000000
--- a/drivers/net/atari_pamsnet.c
+++ /dev/null
@@ -1,878 +0,0 @@
-/* atari_pamsnet.c PAMsNet device driver for linux68k.
- *
- * Version: @(#)PAMsNet.c 0.2ß 03/31/96
- *
- * Author: Torsten Lang <Torsten.Lang@ap.physik.uni-giessen.de>
- * <Torsten.Lang@jung.de>
- *
- * This driver is based on my driver PAMSDMA.c for MiNT-Net and
- * on the driver bionet.c written by
- * Hartmut Laue <laue@ifk-mp.uni-kiel.de>
- * and Torsten Narjes <narjes@ifk-mp.uni-kiel.de>
- *
- * Little adaptions for integration into pl7 by Roman Hodek
- *
- What is it ?
- ------------
- This driver controls the PAMsNet LAN-Adapter which connects
- an ATARI ST/TT via the ACSI-port to an Ethernet-based network.
-
- This version can be compiled as a loadable module (See the
- compile command at the bottom of this file).
- At load time, you can optionally set the debugging level and the
- fastest response time on the command line of 'insmod'.
-
- 'pamsnet_debug'
- controls the amount of diagnostic messages:
- 0 : no messages
- >0 : see code for meaning of printed messages
-
- 'pamsnet_min_poll_time' (always >=1)
- gives the time (in jiffies) between polls. Low values
- increase the system load (beware!)
-
- When loaded, a net device with the name 'eth?' becomes available,
- which can be controlled with the usual 'ifconfig' command.
-
- It is possible to compile this driver into the kernel like other
- (net) drivers. For this purpose, some source files (e.g. config-files
- makefiles, Space.c) must be changed accordingly. (You may refer to
- other drivers how to do it.) In this case, the device will be detected
- at boot time and (probably) appear as 'eth0'.
-
- Theory of Operation
- -------------------
- Because the ATARI DMA port is usually shared between several
- devices (eg. harddisk, floppy) we cannot block the ACSI bus
- while waiting for interrupts. Therefore we use a polling mechanism
- to fetch packets from the adapter. For the same reason, we send
- packets without checking that the previous packet has been sent to
- the LAN. We rely on the higher levels of the networking code to detect
- missing packets and resend them.
-
- Before we access the ATARI DMA controller, we check if another
- process is using the DMA. If not, we lock the DMA, perform one or
- more packet transfers and unlock the DMA before returning.
- We do not use 'stdma_lock' unconditionally because it is unclear
- if the networking code can be set to sleep, which will happen if
- another (possibly slow) device is using the DMA controller.
-
- The polling is done via timer interrupts which periodically
- 'simulate' an interrupt from the Ethernet adapter. The time (in jiffies)
- between polls varies depending on an estimate of the net activity.
- The allowed range is given by the variable 'bionet_min_poll_time'
- for the lower (fastest) limit and the constant 'MAX_POLL_TIME'
- for the higher (slowest) limit.
-
- Whenever a packet arrives, we switch to fastest response by setting
- the polling time to its lowest limit. If the following poll fails,
- because no packets have arrived, we increase the time for the next
- poll. When the net activity is low, the polling time effectively
- stays at its maximum value, resulting in the lowest load for the
- machine.
- */
-
-#define MAX_POLL_TIME 10
-
-static char *version =
- "pamsnet.c:v0.2beta 30-mar-96 (c) Torsten Lang.\n";
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/bitops.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/errno.h>
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/atari_stdma.h>
-#include <asm/atari_acsi.h>
-
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/init.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#undef READ
-#undef WRITE
-
-/* use 0 for production, 1 for verification, >2 for debug
- */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-/*
- * Global variable 'pamsnet_debug'. Can be set at load time by 'insmod'
- */
-unsigned int pamsnet_debug = NET_DEBUG;
-module_param(pamsnet_debug, int, 0);
-MODULE_PARM_DESC(pamsnet_debug, "pamsnet debug enable (0-1)");
-MODULE_LICENSE("GPL");
-
-static unsigned int pamsnet_min_poll_time = 2;
-
-
-/* Information that need to be kept for each board.
- */
-struct net_local {
- struct net_device_stats stats;
- long open_time; /* for debugging */
- int poll_time; /* polling time varies with net load */
-};
-
-static struct nic_pkt_s { /* packet format */
- unsigned char buffer[2048];
-} *nic_packet = 0;
-unsigned char *phys_nic_packet;
-
-typedef unsigned char HADDR[6]; /* 6-byte hardware address of lance */
-
-/* Index to functions, as function prototypes.
- */
-static void start (int target);
-static int stop (int target);
-static int testpkt (int target);
-static int sendpkt (int target, unsigned char *buffer, int length);
-static int receivepkt (int target, unsigned char *buffer);
-static int inquiry (int target, unsigned char *buffer);
-static HADDR *read_hw_addr(int target, unsigned char *buffer);
-static void setup_dma (void *address, unsigned rw_flag, int num_blocks);
-static int send_first (int target, unsigned char byte);
-static int send_1_5 (int lun, unsigned char *command, int dma);
-static int get_status (void);
-static int calc_received (void *start_address);
-
-static int pamsnet_open(struct net_device *dev);
-static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev);
-static void pamsnet_poll_rx(struct net_device *);
-static int pamsnet_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
-static void pamsnet_tick(unsigned long);
-
-static irqreturn_t pamsnet_intr(int irq, void *data);
-
-static DEFINE_TIMER(pamsnet_timer, pamsnet_tick, 0, 0);
-
-#define STRAM_ADDR(a) (((a) & 0xff000000) == 0)
-
-typedef struct
-{
- unsigned char reserved1[0x38];
- HADDR hwaddr;
- unsigned char reserved2[0x1c2];
-} DMAHWADDR;
-
-/*
- * Definitions of commands understood by the PAMs DMA adaptor.
- *
- * In general the DMA adaptor uses LUN 0, 5, 6 and 7 on one ID changeable
- * by the PAM's Net software.
- *
- * LUN 0 works as a harddisk. You can boot the PAM's Net driver there.
- * LUN 5 works as a harddisk and lets you access the RAM and some I/O HW
- * area. In sector 0, bytes 0x38-0x3d you find the ethernet HW address
- * of the adaptor.
- * LUN 6 works as a harddisk and lets you access the firmware ROM.
- * LUN 7 lets you send and receive packets.
- *
- * Some commands like the INQUIRY command work identical on all used LUNs.
- *
- * UNKNOWN1 seems to read some data.
- * Command length is 6 bytes.
- * UNKNOWN2 seems to read some data (command byte 1 must be !=0). The
- * following bytes seem to be something like an allocation length.
- * Command length is 6 bytes.
- * READPKT reads a packet received by the DMA adaptor.
- * Command length is 6 bytes.
- * WRITEPKT sends a packet transferred by the following DMA phase. The length
- * of the packet is transferred in command bytes 3 and 4.
- * The adaptor automatically replaces the src hw address in an ethernet
- * packet by its own hw address.
- * Command length is 6 bytes.
- * INQUIRY has the same function as the INQUIRY command supported by harddisks
- * and other SCSI devices. It lets you detect which device you found
- * at a given address.
- * Command length is 6 bytes.
- * START initializes the DMA adaptor. After this command it is able to send
- * and receive packets. There is no status byte returned!
- * Command length is 1 byte.
- * NUMPKTS gives back the number of received packets waiting in the queue in
- * the status byte.
- * Command length is 1 byte.
- * UNKNOWN3
- * UNKNOWN4 Function of these three commands is unknown.
- * UNKNOWN5 The command length of these three commands is 1 byte.
- * DESELECT immediately deselects the DMA adaptor. May important with interrupt
- * driven operation.
- * Command length is 1 byte.
- * STOP resets the DMA adaptor. After this command packets can no longer
- * be received or transferred.
- * Command length is 6 byte.
- */
-
-enum {UNKNOWN1=3, READPKT=8, UNKNOWN2, WRITEPKT=10, INQUIRY=18, START,
- NUMPKTS=22, UNKNOWN3, UNKNOWN4, UNKNOWN5, DESELECT, STOP};
-
-#define READSECTOR READPKT
-#define WRITESECTOR WRITEPKT
-
-u_char *inquire8="MV PAM's NET/GK";
-
-#define DMALOW dma_wd.dma_lo
-#define DMAMID dma_wd.dma_md
-#define DMAHIGH dma_wd.dma_hi
-#define DACCESS dma_wd.fdc_acces_seccount
-
-#define MFP_GPIP mfp.par_dt_reg
-
-/* Some useful functions */
-
-#define INT (!(MFP_GPIP & 0x20))
-#define DELAY ({MFP_GPIP; MFP_GPIP; MFP_GPIP;})
-#define WRITEMODE(value) \
- ({ u_short dummy = value; \
- __asm__ volatile("movew %0, 0xFFFF8606" : : "d"(dummy)); \
- DELAY; \
- })
-#define WRITEBOTH(value1, value2) \
- ({ u_long dummy = (u_long)(value1)<<16 | (u_short)(value2); \
- __asm__ volatile("movel %0, 0xFFFF8604" : : "d"(dummy)); \
- DELAY; \
- })
-
-/* Definitions for DMODE */
-
-#define READ 0x000
-#define WRITE 0x100
-
-#define DMA_FDC 0x080
-#define DMA_ACSI 0x000
-
-#define DMA_DISABLE 0x040
-
-#define SEC_COUNT 0x010
-#define DMA_WINDOW 0x000
-
-#define REG_ACSI 0x008
-#define REG_FDC 0x000
-
-#define A1 0x002
-
-/* Timeout constants */
-
-#define TIMEOUTCMD HZ/2 /* ca. 500ms */
-#define TIMEOUTDMA HZ /* ca. 1s */
-#define COMMAND_DELAY 500 /* ca. 0.5ms */
-
-unsigned rw;
-int lance_target = -1;
-int if_up = 0;
-
-/* The following routines access the ethernet board connected to the
- * ACSI port via the st_dma chip.
- */
-
-/* The following lowlevel routines work on physical addresses only and assume
- * that eventually needed buffers are
- * - completely located in ST RAM
- * - are contigous in the physical address space
- */
-
-/* Setup the DMA counter */
-
-static void
-setup_dma (void *address, unsigned rw_flag, int num_blocks)
-{
- WRITEMODE((unsigned) rw_flag | DMA_FDC | SEC_COUNT | REG_ACSI |
- A1);
- WRITEMODE((unsigned)(rw_flag ^ WRITE) | DMA_FDC | SEC_COUNT | REG_ACSI |
- A1);
- WRITEMODE((unsigned) rw_flag | DMA_FDC | SEC_COUNT | REG_ACSI |
- A1);
- DMALOW = (unsigned char)((unsigned long)address & 0xFF);
- DMAMID = (unsigned char)(((unsigned long)address >> 8) & 0xFF);
- DMAHIGH = (unsigned char)(((unsigned long)address >> 16) & 0xFF);
- WRITEBOTH((unsigned)num_blocks & 0xFF,
- rw_flag | DMA_FDC | DMA_WINDOW | REG_ACSI | A1);
- rw = rw_flag;
-}
-
-/* Send the first byte of an command block */
-
-static int
-send_first (int target, unsigned char byte)
-{
- rw = READ;
- acsi_delay_end(COMMAND_DELAY);
- /*
- * wake up ACSI
- */
- WRITEMODE(DMA_FDC | DMA_WINDOW | REG_ACSI);
- /*
- * write command byte
- */
- WRITEBOTH((target << 5) | (byte & 0x1F), DMA_FDC |
- DMA_WINDOW | REG_ACSI | A1);
- return (!acsi_wait_for_IRQ(TIMEOUTCMD));
-}
-
-/* Send the rest of an command block */
-
-static int
-send_1_5 (int lun, unsigned char *command, int dma)
-{
- int i, j;
-
- for (i=0; i<5; i++) {
- WRITEBOTH((!i ? (((lun & 0x7) << 5) | (command[i] & 0x1F))
- : command[i]),
- rw | REG_ACSI | DMA_WINDOW |
- ((i < 4) ? DMA_FDC
- : (dma ? DMA_ACSI
- : DMA_FDC)) | A1);
- if (i < 4 && (j = !acsi_wait_for_IRQ(TIMEOUTCMD)))
- return (j);
- }
- return (0);
-}
-
-/* Read a status byte */
-
-static int
-get_status (void)
-{
- WRITEMODE(DMA_FDC | DMA_WINDOW | REG_ACSI | A1);
- acsi_delay_start();
- return ((int)(DACCESS & 0xFF));
-}
-
-/* Calculate the number of received bytes */
-
-static int
-calc_received (void *start_address)
-{
- return (int)(
- (((unsigned long)DMAHIGH << 16) | ((unsigned)DMAMID << 8) | DMALOW)
- - (unsigned long)start_address);
-}
-
-/* The following midlevel routines still work on physical addresses ... */
-
-/* start() starts the PAM's DMA adaptor */
-
-static void
-start (int target)
-{
- send_first(target, START);
-}
-
-/* stop() stops the PAM's DMA adaptor and returns a value of zero in case of success */
-
-static int
-stop (int target)
-{
- int ret = -1;
- unsigned char cmd_buffer[5];
-
- if (send_first(target, STOP))
- goto bad;
- cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] =
- cmd_buffer[3] = cmd_buffer[4] = 0;
- if (send_1_5(7, cmd_buffer, 0) ||
- !acsi_wait_for_IRQ(TIMEOUTDMA) ||
- get_status())
- goto bad;
- ret = 0;
-bad:
- return (ret);
-}
-
-/* testpkt() returns the number of received packets waiting in the queue */
-
-static int
-testpkt(int target)
-{
- int ret = -1;
-
- if (send_first(target, NUMPKTS))
- goto bad;
- ret = get_status();
-bad:
- return (ret);
-}
-
-/* inquiry() returns 0 when PAM's DMA found, -1 when timeout, -2 otherwise */
-/* Please note: The buffer is for internal use only but must be defined! */
-
-static int
-inquiry (int target, unsigned char *buffer)
-{
- int ret = -1;
- unsigned char *vbuffer = phys_to_virt((unsigned long)buffer);
- unsigned char cmd_buffer[5];
-
- if (send_first(target, INQUIRY))
- goto bad;
- setup_dma(buffer, READ, 1);
- vbuffer[8] = vbuffer[27] = 0; /* Avoid confusion with previous read data */
- cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0;
- cmd_buffer[3] = 48;
- if (send_1_5(5, cmd_buffer, 1) ||
- !acsi_wait_for_IRQ(TIMEOUTDMA) ||
- get_status() ||
- (calc_received(buffer) < 32))
- goto bad;
- dma_cache_maintenance((unsigned long)(buffer+8), 20, 0);
- if (memcmp(inquire8, vbuffer+8, 20))
- goto bad;
- ret = 0;
-bad:
- if (!!NET_DEBUG) {
- vbuffer[8+20]=0;
- printk("inquiry of target %d: %s\n", target, vbuffer+8);
- }
- return (ret);
-}
-
-/*
- * read_hw_addr() reads the sector containing the hwaddr and returns
- * a pointer to it (virtual address!) or 0 in case of an error
- */
-
-static HADDR
-*read_hw_addr(int target, unsigned char *buffer)
-{
- HADDR *ret = 0;
- unsigned char cmd_buffer[5];
-
- if (send_first(target, READSECTOR))
- goto bad;
- setup_dma(buffer, READ, 1);
- cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0;
- cmd_buffer[3] = 1;
- if (send_1_5(5, cmd_buffer, 1) ||
- !acsi_wait_for_IRQ(TIMEOUTDMA) ||
- get_status())
- goto bad;
- ret = phys_to_virt((unsigned long)&(((DMAHWADDR *)buffer)->hwaddr));
- dma_cache_maintenance((unsigned long)buffer, 512, 0);
-bad:
- return (ret);
-}
-
-static irqreturn_t
-pamsnet_intr(int irq, void *data)
-{
- return IRQ_HANDLED;
-}
-
-/* receivepkt() loads a packet to a given buffer and returns its length */
-
-static int
-receivepkt (int target, unsigned char *buffer)
-{
- int ret = -1;
- unsigned char cmd_buffer[5];
-
- if (send_first(target, READPKT))
- goto bad;
- setup_dma(buffer, READ, 3);
- cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0;
- cmd_buffer[3] = 3;
- if (send_1_5(7, cmd_buffer, 1) ||
- !acsi_wait_for_IRQ(TIMEOUTDMA) ||
- get_status())
- goto bad;
- ret = calc_received(buffer);
-bad:
- return (ret);
-}
-
-/* sendpkt() sends a packet and returns a value of zero when the packet was sent
- successfully */
-
-static int
-sendpkt (int target, unsigned char *buffer, int length)
-{
- int ret = -1;
- unsigned char cmd_buffer[5];
-
- if (send_first(target, WRITEPKT))
- goto bad;
- setup_dma(buffer, WRITE, 3);
- cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[4] = 0;
- cmd_buffer[2] = length >> 8;
- cmd_buffer[3] = length & 0xFF;
- if (send_1_5(7, cmd_buffer, 1) ||
- !acsi_wait_for_IRQ(TIMEOUTDMA) ||
- get_status())
- goto bad;
- ret = 0;
-bad:
- return (ret);
-}
-
-/* The following higher level routines work on virtual addresses and convert them to
- * physical addresses when passed to the lowlevel routines. It's up to the higher level
- * routines to copy data from Alternate RAM to ST RAM if neccesary!
- */
-
-/* Check for a network adaptor of this type, and return '0' if one exists.
- */
-
-struct net_device * __init pamsnet_probe (int unit)
-{
- struct net_device *dev;
- int i;
- HADDR *hwaddr;
- int err;
-
- unsigned char station_addr[6];
- static unsigned version_printed;
- /* avoid "Probing for..." printed 4 times - the driver is supporting only one adapter now! */
- static int no_more_found;
-
- if (no_more_found)
- return ERR_PTR(-ENODEV);
- no_more_found = 1;
-
- dev = alloc_etherdev(sizeof(struct net_local));
- if (!dev)
- return ERR_PTR(-ENOMEM);
- if (unit >= 0) {
- sprintf(dev->name, "eth%d", unit);
- netdev_boot_setup_check(dev);
- }
- SET_MODULE_OWNER(dev);
-
- printk("Probing for PAM's Net/GK Adapter...\n");
-
- /* Allocate the DMA buffer here since we need it for probing! */
-
- nic_packet = (struct nic_pkt_s *)acsi_buffer;
- phys_nic_packet = (unsigned char *)phys_acsi_buffer;
- if (pamsnet_debug > 0) {
- printk("nic_packet at 0x%p, phys at 0x%p\n",
- nic_packet, phys_nic_packet );
- }
-
- stdma_lock(pamsnet_intr, NULL);
- DISABLE_IRQ();
-
- for (i=0; i<8; i++) {
- /* Do two inquiries to cover cases with strange equipment on previous ID */
- /* blocking the ACSI bus (like the SLMC804 laser printer controller... */
- inquiry(i, phys_nic_packet);
- if (!inquiry(i, phys_nic_packet)) {
- lance_target = i;
- break;
- }
- }
-
- if (!!NET_DEBUG)
- printk("ID: %d\n",i);
-
- if (lance_target >= 0) {
- if (!(hwaddr = read_hw_addr(lance_target, phys_nic_packet)))
- lance_target = -1;
- else
- memcpy (station_addr, hwaddr, ETH_ALEN);
- }
-
- ENABLE_IRQ();
- stdma_release();
-
- if (lance_target < 0) {
- printk("No PAM's Net/GK found.\n");
- free_netdev(dev);
- return ERR_PTR(-ENODEV);
- }
-
- if (pamsnet_debug > 0 && version_printed++ == 0)
- printk(version);
-
- printk("%s: %s found on target %01d, eth-addr: %02x:%02x:%02x:%02x:%02x:%02x.\n",
- dev->name, "PAM's Net/GK", lance_target,
- station_addr[0], station_addr[1], station_addr[2],
- station_addr[3], station_addr[4], station_addr[5]);
-
- /* Initialize the device structure. */
- dev->open = pamsnet_open;
- dev->stop = pamsnet_close;
- dev->hard_start_xmit = pamsnet_send_packet;
- dev->get_stats = net_get_stats;
-
- /* Fill in the fields of the device structure with ethernet-generic
- * values. This should be in a common file instead of per-driver.
- */
-
- for (i = 0; i < ETH_ALEN; i++) {
-#if 0
- dev->broadcast[i] = 0xff;
-#endif
- dev->dev_addr[i] = station_addr[i];
- }
- err = register_netdev(dev);
- if (!err)
- return dev;
-
- free_netdev(dev);
- return ERR_PTR(err);
-}
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
-
- This routine should set everything up anew at each open, even
- registers that "should" only need to be set once at boot, so that
- there is non-reboot way to recover if something goes wrong.
- */
-static int
-pamsnet_open(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- if (pamsnet_debug > 0)
- printk("pamsnet_open\n");
- stdma_lock(pamsnet_intr, NULL);
- DISABLE_IRQ();
-
- /* Reset the hardware here.
- */
- if (!if_up)
- start(lance_target);
- if_up = 1;
- lp->open_time = 0; /*jiffies*/
- lp->poll_time = MAX_POLL_TIME;
-
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
- ENABLE_IRQ();
- stdma_release();
- pamsnet_timer.data = (long)dev;
- pamsnet_timer.expires = jiffies + lp->poll_time;
- add_timer(&pamsnet_timer);
- return 0;
-}
-
-static int
-pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- unsigned long flags;
-
- /* Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
- local_irq_save(flags);
-
- if (stdma_islocked()) {
- local_irq_restore(flags);
- lp->stats.tx_errors++;
- }
- else {
- int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned long buf = virt_to_phys(skb->data);
- int stat;
-
- stdma_lock(pamsnet_intr, NULL);
- DISABLE_IRQ();
-
- local_irq_restore(flags);
- if( !STRAM_ADDR(buf+length-1) ) {
- skb_copy_from_linear_data(skb, nic_packet->buffer,
- length);
- buf = (unsigned long)phys_nic_packet;
- }
-
- dma_cache_maintenance(buf, length, 1);
-
- stat = sendpkt(lance_target, (unsigned char *)buf, length);
- ENABLE_IRQ();
- stdma_release();
-
- dev->trans_start = jiffies;
- dev->tbusy = 0;
- lp->stats.tx_packets++;
- lp->stats.tx_bytes+=length;
- }
- dev_kfree_skb(skb);
-
- return 0;
-}
-
-/* We have a good packet(s), get it/them out of the buffers.
- */
-static void
-pamsnet_poll_rx(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- int boguscount;
- int pkt_len;
- struct sk_buff *skb;
- unsigned long flags;
-
- local_irq_save(flags);
- /* ++roman: Take care at locking the ST-DMA... This must be done with ints
- * off, since otherwise an int could slip in between the question and the
- * locking itself, and then we'd go to sleep... And locking itself is
- * necessary to keep the floppy_change timer from working with ST-DMA
- * registers. */
- if (stdma_islocked()) {
- local_irq_restore(flags);
- return;
- }
- stdma_lock(pamsnet_intr, NULL);
- DISABLE_IRQ();
- local_irq_restore(flags);
-
- boguscount = testpkt(lance_target);
- if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++;
-
- while(boguscount--) {
- pkt_len = receivepkt(lance_target, phys_nic_packet);
-
- if( pkt_len < 60 ) break;
-
- /* Good packet... */
-
- dma_cache_maintenance((unsigned long)phys_nic_packet, pkt_len, 0);
-
- lp->poll_time = pamsnet_min_poll_time; /* fast poll */
- if( pkt_len >= 60 && pkt_len <= 2048 ) {
- if (pkt_len > 1514)
- pkt_len = 1514;
-
- /* Malloc up new buffer.
- */
- skb = alloc_skb(pkt_len, GFP_ATOMIC);
- if (skb == NULL) {
- printk("%s: Memory squeeze, dropping packet.\n",
- dev->name);
- lp->stats.rx_dropped++;
- break;
- }
- skb->len = pkt_len;
- skb->dev = dev;
-
- /* 'skb->data' points to the start of sk_buff data area.
- */
- skb_copy_to_linear_data(skb, nic_packet->buffer,
- pkt_len);
- netif_rx(skb);
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes+=pkt_len;
- }
- }
-
- /* If any worth-while packets have been received, dev_rint()
- has done a mark_bh(INET_BH) for us and will work on them
- when we get to the bottom-half routine.
- */
-
- ENABLE_IRQ();
- stdma_release();
- return;
-}
-
-/* pamsnet_tick: called by pamsnet_timer. Reads packets from the adapter,
- * passes them to the higher layers and restarts the timer.
- */
-static void
-pamsnet_tick(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct net_local *lp = netdev_priv(dev);
-
- if( pamsnet_debug > 0 && (lp->open_time++ & 7) == 8 )
- printk("pamsnet_tick: %ld\n", lp->open_time);
-
- pamsnet_poll_rx(dev);
-
- pamsnet_timer.expires = jiffies + lp->poll_time;
- add_timer(&pamsnet_timer);
-}
-
-/* The inverse routine to pamsnet_open().
- */
-static int
-pamsnet_close(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
-
- if (pamsnet_debug > 0)
- printk("pamsnet_close, open_time=%ld\n", lp->open_time);
- del_timer(&pamsnet_timer);
- stdma_lock(pamsnet_intr, NULL);
- DISABLE_IRQ();
-
- if (if_up)
- stop(lance_target);
- if_up = 0;
-
- lp->open_time = 0;
-
- dev->tbusy = 1;
- dev->start = 0;
-
- ENABLE_IRQ();
- stdma_release();
- return 0;
-}
-
-/* Get the current statistics.
- This may be called with the card open or closed.
- */
-static struct net_device_stats *net_get_stats(struct net_device *dev)
-{
- struct net_local *lp = netdev_priv(dev);
- return &lp->stats;
-}
-
-
-#ifdef MODULE
-
-static struct net_device *pam_dev;
-
-int init_module(void)
-{
- pam_dev = pamsnet_probe(-1);
- if (IS_ERR(pam_dev))
- return PTR_ERR(pam_dev);
- return 0;
-}
-
-void cleanup_module(void)
-{
- unregister_netdev(pam_dev);
- free_netdev(pam_dev);
-}
-
-#endif /* MODULE */
-
-/* Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include
- -b m68k-linuxaout -Wall -Wstrict-prototypes -O2
- -fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c atari_pamsnet.c"
- * version-control: t
- * kept-new-versions: 5
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/atl1/atl1.h b/drivers/net/atl1/atl1.h
index b1c6034e68fa..ff4765f6c3de 100644
--- a/drivers/net/atl1/atl1.h
+++ b/drivers/net/atl1/atl1.h
@@ -43,6 +43,7 @@ extern const struct ethtool_ops atl1_ethtool_ops;
struct atl1_adapter;
#define ATL1_MAX_INTR 3
+#define ATL1_MAX_TX_BUF_LEN 0x3000 /* 12288 bytes */
#define ATL1_DEFAULT_TPD 256
#define ATL1_MAX_TPD 1024
@@ -57,29 +58,45 @@ struct atl1_adapter;
#define ATL1_RRD_DESC(R, i) ATL1_GET_DESC(R, i, struct rx_return_desc)
/*
+ * This detached comment is preserved for documentation purposes only.
+ * It was originally attached to some code that got deleted, but seems
+ * important enough to keep around...
+ *
+ * <begin detached comment>
* Some workarounds require millisecond delays and are run during interrupt
* context. Most notably, when establishing link, the phy may need tweaking
* but cannot process phy register reads/writes faster than millisecond
* intervals...and we establish link due to a "link status change" interrupt.
+ * <end detached comment>
+ */
+
+/*
+ * atl1_ring_header represents a single, contiguous block of DMA space
+ * mapped for the three descriptor rings (tpd, rfd, rrd) and the two
+ * message blocks (cmb, smb) described below
*/
+struct atl1_ring_header {
+ void *desc; /* virtual address */
+ dma_addr_t dma; /* physical address*/
+ unsigned int size; /* length in bytes */
+};
/*
- * wrapper around a pointer to a socket buffer,
- * so a DMA handle can be stored along with the buffer
+ * atl1_buffer is wrapper around a pointer to a socket buffer
+ * so a DMA handle can be stored along with the skb
*/
struct atl1_buffer {
- struct sk_buff *skb;
- u16 length;
- u16 alloced;
+ struct sk_buff *skb; /* socket buffer */
+ u16 length; /* rx buffer length */
+ u16 alloced; /* 1 if skb allocated */
dma_addr_t dma;
};
-#define MAX_TX_BUF_LEN 0x3000 /* 12KB */
-
+/* transmit packet descriptor (tpd) ring */
struct atl1_tpd_ring {
- void *desc; /* pointer to the descriptor ring memory */
- dma_addr_t dma; /* physical adress of the descriptor ring */
- u16 size; /* length of descriptor ring in bytes */
+ void *desc; /* descriptor ring virtual address */
+ dma_addr_t dma; /* descriptor ring physical address */
+ u16 size; /* descriptor ring length in bytes */
u16 count; /* number of descriptors in the ring */
u16 hw_idx; /* hardware index */
atomic_t next_to_clean;
@@ -87,36 +104,34 @@ struct atl1_tpd_ring {
struct atl1_buffer *buffer_info;
};
+/* receive free descriptor (rfd) ring */
struct atl1_rfd_ring {
- void *desc;
- dma_addr_t dma;
- u16 size;
- u16 count;
+ void *desc; /* descriptor ring virtual address */
+ dma_addr_t dma; /* descriptor ring physical address */
+ u16 size; /* descriptor ring length in bytes */
+ u16 count; /* number of descriptors in the ring */
atomic_t next_to_use;
u16 next_to_clean;
struct atl1_buffer *buffer_info;
};
+/* receive return descriptor (rrd) ring */
struct atl1_rrd_ring {
- void *desc;
- dma_addr_t dma;
- unsigned int size;
- u16 count;
+ void *desc; /* descriptor ring virtual address */
+ dma_addr_t dma; /* descriptor ring physical address */
+ unsigned int size; /* descriptor ring length in bytes */
+ u16 count; /* number of descriptors in the ring */
u16 next_to_use;
atomic_t next_to_clean;
};
-struct atl1_ring_header {
- void *desc; /* pointer to the descriptor ring memory */
- dma_addr_t dma; /* physical adress of the descriptor ring */
- unsigned int size; /* length of descriptor ring in bytes */
-};
-
+/* coalescing message block (cmb) */
struct atl1_cmb {
struct coals_msg_block *cmb;
dma_addr_t dma;
};
+/* statistics message block (smb) */
struct atl1_smb {
struct stats_msg_block *smb;
dma_addr_t dma;
@@ -141,24 +156,26 @@ struct atl1_sft_stats {
u64 tx_aborted_errors;
u64 tx_window_errors;
u64 tx_carrier_errors;
-
- u64 tx_pause; /* num Pause packet transmitted. */
- u64 excecol; /* num tx packets aborted due to excessive collisions. */
- u64 deffer; /* num deferred tx packets */
- u64 scc; /* num packets subsequently transmitted successfully w/ single prior collision. */
- u64 mcc; /* num packets subsequently transmitted successfully w/ multiple prior collisions. */
+ u64 tx_pause; /* num pause packets transmitted. */
+ u64 excecol; /* num tx packets w/ excessive collisions. */
+ u64 deffer; /* num tx packets deferred */
+ u64 scc; /* num packets subsequently transmitted
+ * successfully w/ single prior collision. */
+ u64 mcc; /* num packets subsequently transmitted
+ * successfully w/ multiple prior collisions. */
u64 latecol; /* num tx packets w/ late collisions. */
- u64 tx_underun; /* num tx packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
- u64 tx_trunc; /* num tx packets truncated due to size exceeding MTU, regardless whether truncated by Selene or not. (The name doesn't really reflect the meaning in this case.) */
+ u64 tx_underun; /* num tx packets aborted due to transmit
+ * FIFO underrun, or TRD FIFO underrun */
+ u64 tx_trunc; /* num tx packets truncated due to size
+ * exceeding MTU, regardless whether truncated
+ * by the chip or not. (The name doesn't really
+ * reflect the meaning in this case.) */
u64 rx_pause; /* num Pause packets received. */
u64 rx_rrd_ov;
u64 rx_trunc;
};
-/* board specific private data structure */
-#define ATL1_REGS_LEN 8
-
-/* Structure containing variables used by the shared code */
+/* hardware structure */
struct atl1_hw {
u8 __iomem *hw_addr;
struct atl1_adapter *back;
@@ -167,24 +184,35 @@ struct atl1_hw {
enum atl1_dma_req_block dmar_block;
enum atl1_dma_req_block dmaw_block;
u8 preamble_len;
- u8 max_retry; /* Retransmission maximum, after which the packet will be discarded */
- u8 jam_ipg; /* IPG to start JAM for collision based flow control in half-duplex mode. In units of 8-bit time */
- u8 ipgt; /* Desired back to back inter-packet gap. The default is 96-bit time */
- u8 min_ifg; /* Minimum number of IFG to enforce in between RX frames. Frame gap below such IFP is dropped */
+ u8 max_retry; /* Retransmission maximum, after which the
+ * packet will be discarded */
+ u8 jam_ipg; /* IPG to start JAM for collision based flow
+ * control in half-duplex mode. In units of
+ * 8-bit time */
+ u8 ipgt; /* Desired back to back inter-packet gap.
+ * The default is 96-bit time */
+ u8 min_ifg; /* Minimum number of IFG to enforce in between
+ * receive frames. Frame gap below such IFP
+ * is dropped */
u8 ipgr1; /* 64bit Carrier-Sense window */
u8 ipgr2; /* 96-bit IPG window */
- u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned burst. Each TPD is 16 bytes long */
- u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned burst. Each RFD is 12 bytes long */
+ u8 tpd_burst; /* Number of TPD to prefetch in cache-aligned
+ * burst. Each TPD is 16 bytes long */
+ u8 rfd_burst; /* Number of RFD to prefetch in cache-aligned
+ * burst. Each RFD is 12 bytes long */
u8 rfd_fetch_gap;
- u8 rrd_burst; /* Threshold number of RRDs that can be retired in a burst. Each RRD is 16 bytes long */
+ u8 rrd_burst; /* Threshold number of RRDs that can be retired
+ * in a burst. Each RRD is 16 bytes long */
u8 tpd_fetch_th;
u8 tpd_fetch_gap;
u16 tx_jumbo_task_th;
- u16 txf_burst; /* Number of data bytes to read in a cache-aligned burst. Each SRAM entry is
- 8 bytes long */
- u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN packets should add 4 bytes */
+ u16 txf_burst; /* Number of data bytes to read in a cache-
+ * aligned burst. Each SRAM entry is 8 bytes */
+ u16 rx_jumbo_th; /* Jumbo packet size for non-VLAN packet. VLAN
+ * packets should add 4 bytes */
u16 rx_jumbo_lkah;
- u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after every 512ns passes. */
+ u16 rrd_ret_timer; /* RRD retirement timer. Decrement by 1 after
+ * every 512ns passes. */
u16 lcol; /* Collision Window */
u16 cmb_tpd;
@@ -194,49 +222,35 @@ struct atl1_hw {
u32 smb_timer;
u16 media_type;
u16 autoneg_advertised;
- u16 pci_cmd_word;
u16 mii_autoneg_adv_reg;
u16 mii_1000t_ctrl_reg;
- u32 mem_rang;
- u32 txcw;
u32 max_frame_size;
u32 min_frame_size;
- u32 mc_filter_type;
- u32 num_mc_addrs;
- u32 collision_delta;
- u32 tx_packet_delta;
- u16 phy_spd_default;
u16 dev_rev;
- u8 revision_id;
/* spi flash */
u8 flash_vendor;
- u8 dma_fairness;
u8 mac_addr[ETH_ALEN];
u8 perm_mac_addr[ETH_ALEN];
- /* bool phy_preamble_sup; */
bool phy_configured;
};
struct atl1_adapter {
- /* OS defined structs */
struct net_device *netdev;
struct pci_dev *pdev;
struct net_device_stats net_stats;
struct atl1_sft_stats soft_stats;
-
struct vlan_group *vlgrp;
u32 rx_buffer_len;
u32 wol;
u16 link_speed;
u16 link_duplex;
spinlock_t lock;
- atomic_t irq_sem;
struct work_struct tx_timeout_task;
struct work_struct link_chg_task;
struct work_struct pcie_dma_to_rst_task;
@@ -244,9 +258,7 @@ struct atl1_adapter {
struct timer_list phy_config_timer;
bool phy_timer_pending;
- bool mac_disabled;
-
- /* All descriptor rings' memory */
+ /* all descriptor rings' memory */
struct atl1_ring_header ring_header;
/* TX */
@@ -259,25 +271,16 @@ struct atl1_adapter {
u64 hw_csum_err;
u64 hw_csum_good;
- u32 gorcl;
- u64 gorcl_old;
-
- /* Interrupt Moderator timer ( 2us resolution) */
- u16 imt;
- /* Interrupt Clear timer (2us resolution) */
- u16 ict;
-
- /* MII interface info */
- struct mii_if_info mii;
+ u16 imt; /* interrupt moderator timer (2us resolution */
+ u16 ict; /* interrupt clear timer (2us resolution */
+ struct mii_if_info mii; /* MII interface info */
/* structs defined in atl1_hw.h */
- u32 bd_number; /* board number */
+ u32 bd_number; /* board number */
bool pci_using_64;
struct atl1_hw hw;
struct atl1_smb smb;
struct atl1_cmb cmb;
-
- u32 pci_state[16];
};
#endif /* _ATL1_H_ */
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index 3bb40dd4a410..fd1e156f1747 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -38,7 +38,7 @@
* TODO:
* Fix TSO; tx performance is horrible with TSO enabled.
* Wake on LAN.
- * Add more ethtool functions, including set ring parameters.
+ * Add more ethtool functions.
* Fix abstruse irq enable/disable condition described here:
* http://marc.theaimsgroup.com/?l=linux-netdev&m=116398508500553&w=2
*
@@ -75,6 +75,7 @@
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/mii.h>
+#include <linux/interrupt.h>
#include <net/checksum.h>
#include <asm/atomic.h>
@@ -118,10 +119,6 @@ static int __devinit atl1_sw_init(struct atl1_adapter *adapter)
{
struct atl1_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
- struct pci_dev *pdev = adapter->pdev;
-
- /* PCI config space info */
- pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
@@ -162,13 +159,70 @@ static int __devinit atl1_sw_init(struct atl1_adapter *adapter)
hw->cmb_tx_timer = 1; /* about 2us */
hw->smb_timer = 100000; /* about 200ms */
- atomic_set(&adapter->irq_sem, 0);
spin_lock_init(&adapter->lock);
spin_lock_init(&adapter->mb_lock);
return 0;
}
+static int mdio_read(struct net_device *netdev, int phy_id, int reg_num)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u16 result;
+
+ atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result);
+
+ return result;
+}
+
+static void mdio_write(struct net_device *netdev, int phy_id, int reg_num,
+ int val)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+
+ atl1_write_phy_reg(&adapter->hw, reg_num, val);
+}
+
+/*
+ * atl1_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ int retval;
+
+ if (!netif_running(netdev))
+ return -EINVAL;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ return retval;
+}
+
+/*
+ * atl1_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ return atl1_mii_ioctl(netdev, ifr, cmd);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
/*
* atl1_setup_mem_resources - allocate Tx / RX descriptor resources
* @adapter: board private structure
@@ -192,19 +246,22 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
goto err_nomem;
}
rfd_ring->buffer_info =
- (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count);
+ (struct atl1_buffer *)(tpd_ring->buffer_info + tpd_ring->count);
- /* real ring DMA buffer */
- ring_header->size = size = sizeof(struct tx_packet_desc) *
- tpd_ring->count
- + sizeof(struct rx_free_desc) * rfd_ring->count
- + sizeof(struct rx_return_desc) * rrd_ring->count
- + sizeof(struct coals_msg_block)
- + sizeof(struct stats_msg_block)
- + 40; /* "40: for 8 bytes align" huh? -- CHS */
+ /* real ring DMA buffer
+ * each ring/block may need up to 8 bytes for alignment, hence the
+ * additional 40 bytes tacked onto the end.
+ */
+ ring_header->size = size =
+ sizeof(struct tx_packet_desc) * tpd_ring->count
+ + sizeof(struct rx_free_desc) * rfd_ring->count
+ + sizeof(struct rx_return_desc) * rrd_ring->count
+ + sizeof(struct coals_msg_block)
+ + sizeof(struct stats_msg_block)
+ + 40;
ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
- &ring_header->dma);
+ &ring_header->dma);
if (unlikely(!ring_header->desc)) {
dev_err(&pdev->dev, "pci_alloc_consistent failed\n");
goto err_nomem;
@@ -218,8 +275,6 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
tpd_ring->dma += offset;
tpd_ring->desc = (u8 *) ring_header->desc + offset;
tpd_ring->size = sizeof(struct tx_packet_desc) * tpd_ring->count;
- atomic_set(&tpd_ring->next_to_use, 0);
- atomic_set(&tpd_ring->next_to_clean, 0);
/* init RFD ring */
rfd_ring->dma = tpd_ring->dma + tpd_ring->size;
@@ -227,9 +282,7 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
rfd_ring->dma += offset;
rfd_ring->desc = (u8 *) tpd_ring->desc + (tpd_ring->size + offset);
rfd_ring->size = sizeof(struct rx_free_desc) * rfd_ring->count;
- rfd_ring->next_to_clean = 0;
- /* rfd_ring->next_to_use = rfd_ring->count - 1; */
- atomic_set(&rfd_ring->next_to_use, 0);
+
/* init RRD ring */
rrd_ring->dma = rfd_ring->dma + rfd_ring->size;
@@ -237,23 +290,22 @@ s32 atl1_setup_ring_resources(struct atl1_adapter *adapter)
rrd_ring->dma += offset;
rrd_ring->desc = (u8 *) rfd_ring->desc + (rfd_ring->size + offset);
rrd_ring->size = sizeof(struct rx_return_desc) * rrd_ring->count;
- rrd_ring->next_to_use = 0;
- atomic_set(&rrd_ring->next_to_clean, 0);
+
/* init CMB */
adapter->cmb.dma = rrd_ring->dma + rrd_ring->size;
offset = (adapter->cmb.dma & 0x7) ? (8 - (adapter->cmb.dma & 0x7)) : 0;
adapter->cmb.dma += offset;
- adapter->cmb.cmb =
- (struct coals_msg_block *) ((u8 *) rrd_ring->desc +
- (rrd_ring->size + offset));
+ adapter->cmb.cmb = (struct coals_msg_block *)
+ ((u8 *) rrd_ring->desc + (rrd_ring->size + offset));
/* init SMB */
adapter->smb.dma = adapter->cmb.dma + sizeof(struct coals_msg_block);
offset = (adapter->smb.dma & 0x7) ? (8 - (adapter->smb.dma & 0x7)) : 0;
adapter->smb.dma += offset;
adapter->smb.smb = (struct stats_msg_block *)
- ((u8 *) adapter->cmb.cmb + (sizeof(struct coals_msg_block) + offset));
+ ((u8 *) adapter->cmb.cmb +
+ (sizeof(struct coals_msg_block) + offset));
return ATL1_SUCCESS;
@@ -262,559 +314,133 @@ err_nomem:
return -ENOMEM;
}
-/*
- * atl1_irq_enable - Enable default interrupt generation settings
- * @adapter: board private structure
- */
-static void atl1_irq_enable(struct atl1_adapter *adapter)
-{
- if (likely(!atomic_dec_and_test(&adapter->irq_sem)))
- iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR);
-}
-
-static void atl1_clear_phy_int(struct atl1_adapter *adapter)
-{
- u16 phy_data;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->lock, flags);
- atl1_read_phy_reg(&adapter->hw, 19, &phy_data);
- spin_unlock_irqrestore(&adapter->lock, flags);
-}
-
-static void atl1_inc_smb(struct atl1_adapter *adapter)
-{
- struct stats_msg_block *smb = adapter->smb.smb;
-
- /* Fill out the OS statistics structure */
- adapter->soft_stats.rx_packets += smb->rx_ok;
- adapter->soft_stats.tx_packets += smb->tx_ok;
- adapter->soft_stats.rx_bytes += smb->rx_byte_cnt;
- adapter->soft_stats.tx_bytes += smb->tx_byte_cnt;
- adapter->soft_stats.multicast += smb->rx_mcast;
- adapter->soft_stats.collisions += (smb->tx_1_col +
- smb->tx_2_col * 2 +
- smb->tx_late_col +
- smb->tx_abort_col *
- adapter->hw.max_retry);
-
- /* Rx Errors */
- adapter->soft_stats.rx_errors += (smb->rx_frag +
- smb->rx_fcs_err +
- smb->rx_len_err +
- smb->rx_sz_ov +
- smb->rx_rxf_ov +
- smb->rx_rrd_ov + smb->rx_align_err);
- adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov;
- adapter->soft_stats.rx_length_errors += smb->rx_len_err;
- adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err;
- adapter->soft_stats.rx_frame_errors += smb->rx_align_err;
- adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov +
- smb->rx_rxf_ov);
-
- adapter->soft_stats.rx_pause += smb->rx_pause;
- adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov;
- adapter->soft_stats.rx_trunc += smb->rx_sz_ov;
-
- /* Tx Errors */
- adapter->soft_stats.tx_errors += (smb->tx_late_col +
- smb->tx_abort_col +
- smb->tx_underrun + smb->tx_trunc);
- adapter->soft_stats.tx_fifo_errors += smb->tx_underrun;
- adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col;
- adapter->soft_stats.tx_window_errors += smb->tx_late_col;
-
- adapter->soft_stats.excecol += smb->tx_abort_col;
- adapter->soft_stats.deffer += smb->tx_defer;
- adapter->soft_stats.scc += smb->tx_1_col;
- adapter->soft_stats.mcc += smb->tx_2_col;
- adapter->soft_stats.latecol += smb->tx_late_col;
- adapter->soft_stats.tx_underun += smb->tx_underrun;
- adapter->soft_stats.tx_trunc += smb->tx_trunc;
- adapter->soft_stats.tx_pause += smb->tx_pause;
-
- adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets;
- adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets;
- adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes;
- adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes;
- adapter->net_stats.multicast = adapter->soft_stats.multicast;
- adapter->net_stats.collisions = adapter->soft_stats.collisions;
- adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors;
- adapter->net_stats.rx_over_errors =
- adapter->soft_stats.rx_missed_errors;
- adapter->net_stats.rx_length_errors =
- adapter->soft_stats.rx_length_errors;
- adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
- adapter->net_stats.rx_frame_errors =
- adapter->soft_stats.rx_frame_errors;
- adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
- adapter->net_stats.rx_missed_errors =
- adapter->soft_stats.rx_missed_errors;
- adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors;
- adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
- adapter->net_stats.tx_aborted_errors =
- adapter->soft_stats.tx_aborted_errors;
- adapter->net_stats.tx_window_errors =
- adapter->soft_stats.tx_window_errors;
- adapter->net_stats.tx_carrier_errors =
- adapter->soft_stats.tx_carrier_errors;
-}
-
-static void atl1_rx_checksum(struct atl1_adapter *adapter,
- struct rx_return_desc *rrd,
- struct sk_buff *skb)
+void atl1_init_ring_ptrs(struct atl1_adapter *adapter)
{
- skb->ip_summed = CHECKSUM_NONE;
-
- if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
- if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
- ERR_FLAG_CODE | ERR_FLAG_OV)) {
- adapter->hw_csum_err++;
- dev_dbg(&adapter->pdev->dev, "rx checksum error\n");
- return;
- }
- }
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
- /* not IPv4 */
- if (!(rrd->pkt_flg & PACKET_FLAG_IPV4))
- /* checksum is invalid, but it's not an IPv4 pkt, so ok */
- return;
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
- /* IPv4 packet */
- if (likely(!(rrd->err_flg &
- (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- adapter->hw_csum_good++;
- return;
- }
+ rfd_ring->next_to_clean = 0;
+ atomic_set(&rfd_ring->next_to_use, 0);
- /* IPv4, but hardware thinks its checksum is wrong */
- dev_dbg(&adapter->pdev->dev,
- "hw csum wrong, pkt_flag:%x, err_flag:%x\n",
- rrd->pkt_flg, rrd->err_flg);
- skb->ip_summed = CHECKSUM_COMPLETE;
- skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
- adapter->hw_csum_err++;
- return;
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
}
/*
- * atl1_alloc_rx_buffers - Replace used receive buffers
- * @adapter: address of board private structure
+ * atl1_clean_rx_ring - Free RFD Buffers
+ * @adapter: board private structure
*/
-static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
-{
- struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct pci_dev *pdev = adapter->pdev;
- struct page *page;
- unsigned long offset;
- struct atl1_buffer *buffer_info, *next_info;
- struct sk_buff *skb;
- u16 num_alloc = 0;
- u16 rfd_next_to_use, next_next;
- struct rx_free_desc *rfd_desc;
-
- next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use);
- if (++next_next == rfd_ring->count)
- next_next = 0;
- buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
- next_info = &rfd_ring->buffer_info[next_next];
-
- while (!buffer_info->alloced && !next_info->alloced) {
- if (buffer_info->skb) {
- buffer_info->alloced = 1;
- goto next;
- }
-
- rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
-
- skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
- if (unlikely(!skb)) { /* Better luck next round */
- adapter->net_stats.rx_dropped++;
- break;
- }
-
- /*
- * Make buffer alignment 2 beyond a 16 byte boundary
- * this will result in a 16 byte aligned IP header after
- * the 14 byte MAC header is removed
- */
- skb_reserve(skb, NET_IP_ALIGN);
-
- buffer_info->alloced = 1;
- buffer_info->skb = skb;
- buffer_info->length = (u16) adapter->rx_buffer_len;
- page = virt_to_page(skb->data);
- offset = (unsigned long)skb->data & ~PAGE_MASK;
- buffer_info->dma = pci_map_page(pdev, page, offset,
- adapter->rx_buffer_len,
- PCI_DMA_FROMDEVICE);
- rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
- rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
- rfd_desc->coalese = 0;
-
-next:
- rfd_next_to_use = next_next;
- if (unlikely(++next_next == rfd_ring->count))
- next_next = 0;
-
- buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
- next_info = &rfd_ring->buffer_info[next_next];
- num_alloc++;
- }
-
- if (num_alloc) {
- /*
- * Force memory writes to complete before letting h/w
- * know there are new descriptors to fetch. (Only
- * applicable for weak-ordered memory model archs,
- * such as IA-64).
- */
- wmb();
- atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use);
- }
- return num_alloc;
-}
-
-static void atl1_intr_rx(struct atl1_adapter *adapter)
+static void atl1_clean_rx_ring(struct atl1_adapter *adapter)
{
- int i, count;
- u16 length;
- u16 rrd_next_to_clean;
- u32 value;
struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
struct atl1_buffer *buffer_info;
- struct rx_return_desc *rrd;
- struct sk_buff *skb;
-
- count = 0;
-
- rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean);
-
- while (1) {
- rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean);
- i = 1;
- if (likely(rrd->xsz.valid)) { /* packet valid */
-chk_rrd:
- /* check rrd status */
- if (likely(rrd->num_buf == 1))
- goto rrd_ok;
-
- /* rrd seems to be bad */
- if (unlikely(i-- > 0)) {
- /* rrd may not be DMAed completely */
- dev_dbg(&adapter->pdev->dev,
- "incomplete RRD DMA transfer\n");
- udelay(1);
- goto chk_rrd;
- }
- /* bad rrd */
- dev_dbg(&adapter->pdev->dev, "bad RRD\n");
- /* see if update RFD index */
- if (rrd->num_buf > 1) {
- u16 num_buf;
- num_buf =
- (rrd->xsz.xsum_sz.pkt_size +
- adapter->rx_buffer_len -
- 1) / adapter->rx_buffer_len;
- if (rrd->num_buf == num_buf) {
- /* clean alloc flag for bad rrd */
- while (rfd_ring->next_to_clean !=
- (rrd->buf_indx + num_buf)) {
- rfd_ring->buffer_info[rfd_ring->
- next_to_clean].alloced = 0;
- if (++rfd_ring->next_to_clean ==
- rfd_ring->count) {
- rfd_ring->
- next_to_clean = 0;
- }
- }
- }
- }
-
- /* update rrd */
- rrd->xsz.valid = 0;
- if (++rrd_next_to_clean == rrd_ring->count)
- rrd_next_to_clean = 0;
- count++;
- continue;
- } else { /* current rrd still not be updated */
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
- break;
- }
-rrd_ok:
- /* clean alloc flag for bad rrd */
- while (rfd_ring->next_to_clean != rrd->buf_indx) {
- rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced =
- 0;
- if (++rfd_ring->next_to_clean == rfd_ring->count)
- rfd_ring->next_to_clean = 0;
+ /* Free all the Rx ring sk_buffs */
+ for (i = 0; i < rfd_ring->count; i++) {
+ buffer_info = &rfd_ring->buffer_info[i];
+ if (buffer_info->dma) {
+ pci_unmap_page(pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_FROMDEVICE);
+ buffer_info->dma = 0;
}
-
- buffer_info = &rfd_ring->buffer_info[rrd->buf_indx];
- if (++rfd_ring->next_to_clean == rfd_ring->count)
- rfd_ring->next_to_clean = 0;
-
- /* update rrd next to clean */
- if (++rrd_next_to_clean == rrd_ring->count)
- rrd_next_to_clean = 0;
- count++;
-
- if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
- if (!(rrd->err_flg &
- (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM
- | ERR_FLAG_LEN))) {
- /* packet error, don't need upstream */
- buffer_info->alloced = 0;
- rrd->xsz.valid = 0;
- continue;
- }
+ if (buffer_info->skb) {
+ dev_kfree_skb(buffer_info->skb);
+ buffer_info->skb = NULL;
}
-
- /* Good Receive */
- pci_unmap_page(adapter->pdev, buffer_info->dma,
- buffer_info->length, PCI_DMA_FROMDEVICE);
- skb = buffer_info->skb;
- length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
-
- skb_put(skb, length - ETHERNET_FCS_SIZE);
-
- /* Receive Checksum Offload */
- atl1_rx_checksum(adapter, rrd, skb);
- skb->protocol = eth_type_trans(skb, adapter->netdev);
-
- if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) {
- u16 vlan_tag = (rrd->vlan_tag >> 4) |
- ((rrd->vlan_tag & 7) << 13) |
- ((rrd->vlan_tag & 8) << 9);
- vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag);
- } else
- netif_rx(skb);
-
- /* let protocol layer free skb */
- buffer_info->skb = NULL;
- buffer_info->alloced = 0;
- rrd->xsz.valid = 0;
-
- adapter->netdev->last_rx = jiffies;
}
- atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
-
- atl1_alloc_rx_buffers(adapter);
+ size = sizeof(struct atl1_buffer) * rfd_ring->count;
+ memset(rfd_ring->buffer_info, 0, size);
- /* update mailbox ? */
- if (count) {
- u32 tpd_next_to_use;
- u32 rfd_next_to_use;
- u32 rrd_next_to_clean;
+ /* Zero out the descriptor ring */
+ memset(rfd_ring->desc, 0, rfd_ring->size);
- spin_lock(&adapter->mb_lock);
+ rfd_ring->next_to_clean = 0;
+ atomic_set(&rfd_ring->next_to_use, 0);
- tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
- rfd_next_to_use =
- atomic_read(&adapter->rfd_ring.next_to_use);
- rrd_next_to_clean =
- atomic_read(&adapter->rrd_ring.next_to_clean);
- value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
- MB_RFD_PROD_INDX_SHIFT) |
- ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
- MB_RRD_CONS_INDX_SHIFT) |
- ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
- MB_TPD_PROD_INDX_SHIFT);
- iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
- spin_unlock(&adapter->mb_lock);
- }
+ rrd_ring->next_to_use = 0;
+ atomic_set(&rrd_ring->next_to_clean, 0);
}
-static void atl1_intr_tx(struct atl1_adapter *adapter)
+/*
+ * atl1_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ */
+static void atl1_clean_tx_ring(struct atl1_adapter *adapter)
{
struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
struct atl1_buffer *buffer_info;
- u16 sw_tpd_next_to_clean;
- u16 cmb_tpd_next_to_clean;
-
- sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean);
- cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);
-
- while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
- struct tx_packet_desc *tpd;
+ struct pci_dev *pdev = adapter->pdev;
+ unsigned long size;
+ unsigned int i;
- tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
- buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
+ /* Free all the Tx ring sk_buffs */
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
if (buffer_info->dma) {
- pci_unmap_page(adapter->pdev, buffer_info->dma,
- buffer_info->length, PCI_DMA_TODEVICE);
+ pci_unmap_page(pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
buffer_info->dma = 0;
}
+ }
+ for (i = 0; i < tpd_ring->count; i++) {
+ buffer_info = &tpd_ring->buffer_info[i];
if (buffer_info->skb) {
- dev_kfree_skb_irq(buffer_info->skb);
+ dev_kfree_skb_any(buffer_info->skb);
buffer_info->skb = NULL;
}
- tpd->buffer_addr = 0;
- tpd->desc.data = 0;
-
- if (++sw_tpd_next_to_clean == tpd_ring->count)
- sw_tpd_next_to_clean = 0;
- }
- atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean);
-
- if (netif_queue_stopped(adapter->netdev)
- && netif_carrier_ok(adapter->netdev))
- netif_wake_queue(adapter->netdev);
-}
-
-static void atl1_check_for_link(struct atl1_adapter *adapter)
-{
- struct net_device *netdev = adapter->netdev;
- u16 phy_data = 0;
-
- spin_lock(&adapter->lock);
- adapter->phy_timer_pending = false;
- atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
- atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
- spin_unlock(&adapter->lock);
-
- /* notify upper layer link down ASAP */
- if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */
- if (netif_carrier_ok(netdev)) { /* old link state: Up */
- dev_info(&adapter->pdev->dev, "%s link is down\n",
- netdev->name);
- adapter->link_speed = SPEED_0;
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- }
}
- schedule_work(&adapter->link_chg_task);
-}
-/*
- * atl1_intr - Interrupt Handler
- * @irq: interrupt number
- * @data: pointer to a network interface device structure
- * @pt_regs: CPU registers structure
- */
-static irqreturn_t atl1_intr(int irq, void *data)
-{
- /*struct atl1_adapter *adapter = ((struct net_device *)data)->priv;*/
- struct atl1_adapter *adapter = netdev_priv(data);
- u32 status;
- u8 update_rx;
- int max_ints = 10;
-
- status = adapter->cmb.cmb->int_stats;
- if (!status)
- return IRQ_NONE;
-
- update_rx = 0;
-
- do {
- /* clear CMB interrupt status at once */
- adapter->cmb.cmb->int_stats = 0;
-
- if (status & ISR_GPHY) /* clear phy status */
- atl1_clear_phy_int(adapter);
-
- /* clear ISR status, and Enable CMB DMA/Disable Interrupt */
- iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR);
-
- /* check if SMB intr */
- if (status & ISR_SMB)
- atl1_inc_smb(adapter);
-
- /* check if PCIE PHY Link down */
- if (status & ISR_PHY_LINKDOWN) {
- dev_dbg(&adapter->pdev->dev, "pcie phy link down %x\n",
- status);
- if (netif_running(adapter->netdev)) { /* reset MAC */
- iowrite32(0, adapter->hw.hw_addr + REG_IMR);
- schedule_work(&adapter->pcie_dma_to_rst_task);
- return IRQ_HANDLED;
- }
- }
-
- /* check if DMA read/write error ? */
- if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
- dev_dbg(&adapter->pdev->dev,
- "pcie DMA r/w error (status = 0x%x)\n",
- status);
- iowrite32(0, adapter->hw.hw_addr + REG_IMR);
- schedule_work(&adapter->pcie_dma_to_rst_task);
- return IRQ_HANDLED;
- }
-
- /* link event */
- if (status & ISR_GPHY) {
- adapter->soft_stats.tx_carrier_errors++;
- atl1_check_for_link(adapter);
- }
-
- /* transmit event */
- if (status & ISR_CMB_TX)
- atl1_intr_tx(adapter);
-
- /* rx exception */
- if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
- ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
- ISR_HOST_RRD_OV | ISR_CMB_RX))) {
- if (status & (ISR_RXF_OV | ISR_RFD_UNRUN |
- ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
- ISR_HOST_RRD_OV))
- dev_dbg(&adapter->pdev->dev,
- "rx exception, ISR = 0x%x\n", status);
- atl1_intr_rx(adapter);
- }
-
- if (--max_ints < 0)
- break;
+ size = sizeof(struct atl1_buffer) * tpd_ring->count;
+ memset(tpd_ring->buffer_info, 0, size);
- } while ((status = adapter->cmb.cmb->int_stats));
+ /* Zero out the descriptor ring */
+ memset(tpd_ring->desc, 0, tpd_ring->size);
- /* re-enable Interrupt */
- iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR);
- return IRQ_HANDLED;
+ atomic_set(&tpd_ring->next_to_use, 0);
+ atomic_set(&tpd_ring->next_to_clean, 0);
}
/*
- * atl1_set_multi - Multicast and Promiscuous mode set
- * @netdev: network interface device structure
+ * atl1_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
*
- * The set_multi entry point is called whenever the multicast address
- * list or the network interface flags are updated. This routine is
- * responsible for configuring the hardware for proper multicast,
- * promiscuous mode, and all-multi behavior.
+ * Free all transmit software resources
*/
-static void atl1_set_multi(struct net_device *netdev)
+void atl1_free_ring_resources(struct atl1_adapter *adapter)
{
- struct atl1_adapter *adapter = netdev_priv(netdev);
- struct atl1_hw *hw = &adapter->hw;
- struct dev_mc_list *mc_ptr;
- u32 rctl;
- u32 hash_value;
+ struct pci_dev *pdev = adapter->pdev;
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_ring_header *ring_header = &adapter->ring_header;
- /* Check for Promiscuous and All Multicast modes */
- rctl = ioread32(hw->hw_addr + REG_MAC_CTRL);
- if (netdev->flags & IFF_PROMISC)
- rctl |= MAC_CTRL_PROMIS_EN;
- else if (netdev->flags & IFF_ALLMULTI) {
- rctl |= MAC_CTRL_MC_ALL_EN;
- rctl &= ~MAC_CTRL_PROMIS_EN;
- } else
- rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+ atl1_clean_tx_ring(adapter);
+ atl1_clean_rx_ring(adapter);
- iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL);
+ kfree(tpd_ring->buffer_info);
+ pci_free_consistent(pdev, ring_header->size, ring_header->desc,
+ ring_header->dma);
- /* clear the old settings from the multicast hash table */
- iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
- iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+ tpd_ring->buffer_info = NULL;
+ tpd_ring->desc = NULL;
+ tpd_ring->dma = 0;
- /* compute mc addresses' hash value ,and put it into hash table */
- for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
- hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr);
- atl1_hash_set(hw, hash_value);
- }
+ rfd_ring->buffer_info = NULL;
+ rfd_ring->desc = NULL;
+ rfd_ring->dma = 0;
+
+ rrd_ring->desc = NULL;
+ rrd_ring->dma = 0;
}
static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter)
@@ -855,6 +481,31 @@ static void atl1_setup_mac_ctrl(struct atl1_adapter *adapter)
iowrite32(value, hw->hw_addr + REG_MAC_CTRL);
}
+/*
+ * atl1_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_set_mac(struct net_device *netdev, void *p)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct sockaddr *addr = p;
+
+ if (netif_running(netdev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+ atl1_set_mac_addr(&adapter->hw);
+ return 0;
+}
+
static u32 atl1_check_link(struct atl1_adapter *adapter)
{
struct atl1_hw *hw = &adapter->hw;
@@ -962,6 +613,103 @@ static u32 atl1_check_link(struct atl1_adapter *adapter)
return ATL1_SUCCESS;
}
+static void atl1_check_for_link(struct atl1_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u16 phy_data = 0;
+
+ spin_lock(&adapter->lock);
+ adapter->phy_timer_pending = false;
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ atl1_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+ spin_unlock(&adapter->lock);
+
+ /* notify upper layer link down ASAP */
+ if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */
+ if (netif_carrier_ok(netdev)) { /* old link state: Up */
+ dev_info(&adapter->pdev->dev, "%s link is down\n",
+ netdev->name);
+ adapter->link_speed = SPEED_0;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ }
+ schedule_work(&adapter->link_chg_task);
+}
+
+/*
+ * atl1_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated. This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl1_set_multi(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ struct dev_mc_list *mc_ptr;
+ u32 rctl;
+ u32 hash_value;
+
+ /* Check for Promiscuous and All Multicast modes */
+ rctl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ if (netdev->flags & IFF_PROMISC)
+ rctl |= MAC_CTRL_PROMIS_EN;
+ else if (netdev->flags & IFF_ALLMULTI) {
+ rctl |= MAC_CTRL_MC_ALL_EN;
+ rctl &= ~MAC_CTRL_PROMIS_EN;
+ } else
+ rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+
+ iowrite32(rctl, hw->hw_addr + REG_MAC_CTRL);
+
+ /* clear the old settings from the multicast hash table */
+ iowrite32(0, hw->hw_addr + REG_RX_HASH_TABLE);
+ iowrite32(0, (hw->hw_addr + REG_RX_HASH_TABLE) + (1 << 2));
+
+ /* compute mc addresses' hash value ,and put it into hash table */
+ for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+ hash_value = atl1_hash_mc_addr(hw, mc_ptr->dmi_addr);
+ atl1_hash_set(hw, hash_value);
+ }
+}
+
+/*
+ * atl1_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ int old_mtu = netdev->mtu;
+ int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+
+ if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+ (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+ dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
+ return -EINVAL;
+ }
+
+ adapter->hw.max_frame_size = max_frame;
+ adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3;
+ adapter->rx_buffer_len = (max_frame + 7) & ~7;
+ adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8;
+
+ netdev->mtu = new_mtu;
+ if ((old_mtu != new_mtu) && netif_running(netdev)) {
+ atl1_down(adapter);
+ atl1_up(adapter);
+ }
+
+ return 0;
+}
+
static void set_flow_ctrl_old(struct atl1_adapter *adapter)
{
u32 hi, lo, value;
@@ -974,7 +722,7 @@ static void set_flow_ctrl_old(struct atl1_adapter *adapter)
lo = value * 7 / 8;
value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
- ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
/* RRD Flow Control */
@@ -984,7 +732,7 @@ static void set_flow_ctrl_old(struct atl1_adapter *adapter)
if (lo < 2)
lo = 2;
value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
- ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
iowrite32(value, adapter->hw.hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
}
@@ -1001,7 +749,7 @@ static void set_flow_ctrl_new(struct atl1_hw *hw)
if (hi < lo)
hi = lo + 16;
value = ((hi & RXQ_RXF_PAUSE_TH_HI_MASK) << RXQ_RXF_PAUSE_TH_HI_SHIFT) |
- ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
+ ((lo & RXQ_RXF_PAUSE_TH_LO_MASK) << RXQ_RXF_PAUSE_TH_LO_SHIFT);
iowrite32(value, hw->hw_addr + REG_RXQ_RXF_PAUSE_THRESH);
/* RRD Flow Control */
@@ -1013,7 +761,7 @@ static void set_flow_ctrl_new(struct atl1_hw *hw)
if (hi < lo)
hi = lo + 3;
value = ((hi & RXQ_RRD_PAUSE_TH_HI_MASK) << RXQ_RRD_PAUSE_TH_HI_SHIFT) |
- ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
+ ((lo & RXQ_RRD_PAUSE_TH_LO_MASK) << RXQ_RRD_PAUSE_TH_LO_SHIFT);
iowrite32(value, hw->hw_addr + REG_RXQ_RRD_PAUSE_THRESH);
}
@@ -1062,7 +810,8 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
value <<= 16;
value += adapter->rfd_ring.count;
iowrite32(value, hw->hw_addr + REG_DESC_RFD_RRD_RING_SIZE);
- iowrite32(adapter->tpd_ring.count, hw->hw_addr + REG_DESC_TPD_RING_SIZE);
+ iowrite32(adapter->tpd_ring.count, hw->hw_addr +
+ REG_DESC_TPD_RING_SIZE);
/* Load Ptr */
iowrite32(1, hw->hw_addr + REG_LOAD_PTR);
@@ -1070,31 +819,31 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
/* config Mailbox */
value = ((atomic_read(&adapter->tpd_ring.next_to_use)
& MB_TPD_PROD_INDX_MASK) << MB_TPD_PROD_INDX_SHIFT) |
- ((atomic_read(&adapter->rrd_ring.next_to_clean)
- & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) |
- ((atomic_read(&adapter->rfd_ring.next_to_use)
- & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT);
+ ((atomic_read(&adapter->rrd_ring.next_to_clean)
+ & MB_RRD_CONS_INDX_MASK) << MB_RRD_CONS_INDX_SHIFT) |
+ ((atomic_read(&adapter->rfd_ring.next_to_use)
+ & MB_RFD_PROD_INDX_MASK) << MB_RFD_PROD_INDX_SHIFT);
iowrite32(value, hw->hw_addr + REG_MAILBOX);
/* config IPG/IFG */
value = (((u32) hw->ipgt & MAC_IPG_IFG_IPGT_MASK)
<< MAC_IPG_IFG_IPGT_SHIFT) |
- (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK)
- << MAC_IPG_IFG_MIFG_SHIFT) |
- (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK)
- << MAC_IPG_IFG_IPGR1_SHIFT) |
- (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK)
- << MAC_IPG_IFG_IPGR2_SHIFT);
+ (((u32) hw->min_ifg & MAC_IPG_IFG_MIFG_MASK)
+ << MAC_IPG_IFG_MIFG_SHIFT) |
+ (((u32) hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK)
+ << MAC_IPG_IFG_IPGR1_SHIFT) |
+ (((u32) hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK)
+ << MAC_IPG_IFG_IPGR2_SHIFT);
iowrite32(value, hw->hw_addr + REG_MAC_IPG_IFG);
/* config Half-Duplex Control */
value = ((u32) hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) |
- (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK)
- << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
- MAC_HALF_DUPLX_CTRL_EXC_DEF_EN |
- (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
- (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK)
- << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
+ (((u32) hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK)
+ << MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) |
+ MAC_HALF_DUPLX_CTRL_EXC_DEF_EN |
+ (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) |
+ (((u32) hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK)
+ << MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT);
iowrite32(value, hw->hw_addr + REG_MAC_HALF_DUPLX_CTRL);
/* set Interrupt Moderator Timer */
@@ -1110,10 +859,10 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
/* jumbo size & rrd retirement timer */
value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK)
<< RXQ_JMBOSZ_TH_SHIFT) |
- (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK)
- << RXQ_JMBO_LKAH_SHIFT) |
- (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK)
- << RXQ_RRD_TIMER_SHIFT);
+ (((u32) hw->rx_jumbo_lkah & RXQ_JMBO_LKAH_MASK)
+ << RXQ_JMBO_LKAH_SHIFT) |
+ (((u32) hw->rrd_ret_timer & RXQ_RRD_TIMER_MASK)
+ << RXQ_RRD_TIMER_SHIFT);
iowrite32(value, hw->hw_addr + REG_RXQ_JMBOSZ_RRDTIM);
/* Flow Control */
@@ -1132,35 +881,36 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
/* config TXQ */
value = (((u32) hw->tpd_burst & TXQ_CTRL_TPD_BURST_NUM_MASK)
<< TXQ_CTRL_TPD_BURST_NUM_SHIFT) |
- (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK)
- << TXQ_CTRL_TXF_BURST_NUM_SHIFT) |
- (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK)
- << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE | TXQ_CTRL_EN;
+ (((u32) hw->txf_burst & TXQ_CTRL_TXF_BURST_NUM_MASK)
+ << TXQ_CTRL_TXF_BURST_NUM_SHIFT) |
+ (((u32) hw->tpd_fetch_th & TXQ_CTRL_TPD_FETCH_TH_MASK)
+ << TXQ_CTRL_TPD_FETCH_TH_SHIFT) | TXQ_CTRL_ENH_MODE |
+ TXQ_CTRL_EN;
iowrite32(value, hw->hw_addr + REG_TXQ_CTRL);
/* min tpd fetch gap & tx jumbo packet size threshold for taskoffload */
value = (((u32) hw->tx_jumbo_task_th & TX_JUMBO_TASK_TH_MASK)
- << TX_JUMBO_TASK_TH_SHIFT) |
- (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK)
- << TX_TPD_MIN_IPG_SHIFT);
+ << TX_JUMBO_TASK_TH_SHIFT) |
+ (((u32) hw->tpd_fetch_gap & TX_TPD_MIN_IPG_MASK)
+ << TX_TPD_MIN_IPG_SHIFT);
iowrite32(value, hw->hw_addr + REG_TX_JUMBO_TASK_TH_TPD_IPG);
/* config RXQ */
value = (((u32) hw->rfd_burst & RXQ_CTRL_RFD_BURST_NUM_MASK)
- << RXQ_CTRL_RFD_BURST_NUM_SHIFT) |
- (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK)
- << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) |
- (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK)
- << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) |
- RXQ_CTRL_CUT_THRU_EN | RXQ_CTRL_EN;
+ << RXQ_CTRL_RFD_BURST_NUM_SHIFT) |
+ (((u32) hw->rrd_burst & RXQ_CTRL_RRD_BURST_THRESH_MASK)
+ << RXQ_CTRL_RRD_BURST_THRESH_SHIFT) |
+ (((u32) hw->rfd_fetch_gap & RXQ_CTRL_RFD_PREF_MIN_IPG_MASK)
+ << RXQ_CTRL_RFD_PREF_MIN_IPG_SHIFT) | RXQ_CTRL_CUT_THRU_EN |
+ RXQ_CTRL_EN;
iowrite32(value, hw->hw_addr + REG_RXQ_CTRL);
/* config DMA Engine */
value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
- << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
- ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
- << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
- DMA_CTRL_DMAR_EN | DMA_CTRL_DMAW_EN;
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
+ ((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+ << DMA_CTRL_DMAR_BURST_LEN_SHIFT) | DMA_CTRL_DMAR_EN |
+ DMA_CTRL_DMAW_EN;
value |= (u32) hw->dma_ord;
if (atl1_rcb_128 == hw->rcb_value)
value |= DMA_CTRL_RCB_VALUE;
@@ -1190,56 +940,495 @@ static u32 atl1_configure(struct atl1_adapter *adapter)
}
/*
+ * atl1_pcie_patch - Patch for PCIE module
+ */
+static void atl1_pcie_patch(struct atl1_adapter *adapter)
+{
+ u32 value;
+
+ /* much vendor magic here */
+ value = 0x6500;
+ iowrite32(value, adapter->hw.hw_addr + 0x12FC);
+ /* pcie flow control mode change */
+ value = ioread32(adapter->hw.hw_addr + 0x1008);
+ value |= 0x8000;
+ iowrite32(value, adapter->hw.hw_addr + 0x1008);
+}
+
+/*
+ * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400
+ * on PCI Command register is disable.
+ * The function enable this bit.
+ * Brackett, 2006/03/15
+ */
+static void atl1_via_workaround(struct atl1_adapter *adapter)
+{
+ unsigned long value;
+
+ value = ioread16(adapter->hw.hw_addr + PCI_COMMAND);
+ if (value & PCI_COMMAND_INTX_DISABLE)
+ value &= ~PCI_COMMAND_INTX_DISABLE;
+ iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND);
+}
+
+/*
+ * atl1_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static void atl1_irq_enable(struct atl1_adapter *adapter)
+{
+ iowrite32(IMR_NORMAL_MASK, adapter->hw.hw_addr + REG_IMR);
+ ioread32(adapter->hw.hw_addr + REG_IMR);
+}
+
+/*
* atl1_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
*/
static void atl1_irq_disable(struct atl1_adapter *adapter)
{
- atomic_inc(&adapter->irq_sem);
iowrite32(0, adapter->hw.hw_addr + REG_IMR);
ioread32(adapter->hw.hw_addr + REG_IMR);
synchronize_irq(adapter->pdev->irq);
}
-static void atl1_vlan_rx_register(struct net_device *netdev,
- struct vlan_group *grp)
+static void atl1_clear_phy_int(struct atl1_adapter *adapter)
{
- struct atl1_adapter *adapter = netdev_priv(netdev);
+ u16 phy_data;
unsigned long flags;
- u32 ctrl;
spin_lock_irqsave(&adapter->lock, flags);
- /* atl1_irq_disable(adapter); */
- adapter->vlgrp = grp;
+ atl1_read_phy_reg(&adapter->hw, 19, &phy_data);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
- if (grp) {
- /* enable VLAN tag insert/strip */
- ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
- ctrl |= MAC_CTRL_RMV_VLAN;
- iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
- } else {
- /* disable VLAN tag insert/strip */
- ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
- ctrl &= ~MAC_CTRL_RMV_VLAN;
- iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+static void atl1_inc_smb(struct atl1_adapter *adapter)
+{
+ struct stats_msg_block *smb = adapter->smb.smb;
+
+ /* Fill out the OS statistics structure */
+ adapter->soft_stats.rx_packets += smb->rx_ok;
+ adapter->soft_stats.tx_packets += smb->tx_ok;
+ adapter->soft_stats.rx_bytes += smb->rx_byte_cnt;
+ adapter->soft_stats.tx_bytes += smb->tx_byte_cnt;
+ adapter->soft_stats.multicast += smb->rx_mcast;
+ adapter->soft_stats.collisions += (smb->tx_1_col + smb->tx_2_col * 2 +
+ smb->tx_late_col + smb->tx_abort_col * adapter->hw.max_retry);
+
+ /* Rx Errors */
+ adapter->soft_stats.rx_errors += (smb->rx_frag + smb->rx_fcs_err +
+ smb->rx_len_err + smb->rx_sz_ov + smb->rx_rxf_ov +
+ smb->rx_rrd_ov + smb->rx_align_err);
+ adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov;
+ adapter->soft_stats.rx_length_errors += smb->rx_len_err;
+ adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err;
+ adapter->soft_stats.rx_frame_errors += smb->rx_align_err;
+ adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov +
+ smb->rx_rxf_ov);
+
+ adapter->soft_stats.rx_pause += smb->rx_pause;
+ adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov;
+ adapter->soft_stats.rx_trunc += smb->rx_sz_ov;
+
+ /* Tx Errors */
+ adapter->soft_stats.tx_errors += (smb->tx_late_col +
+ smb->tx_abort_col + smb->tx_underrun + smb->tx_trunc);
+ adapter->soft_stats.tx_fifo_errors += smb->tx_underrun;
+ adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col;
+ adapter->soft_stats.tx_window_errors += smb->tx_late_col;
+
+ adapter->soft_stats.excecol += smb->tx_abort_col;
+ adapter->soft_stats.deffer += smb->tx_defer;
+ adapter->soft_stats.scc += smb->tx_1_col;
+ adapter->soft_stats.mcc += smb->tx_2_col;
+ adapter->soft_stats.latecol += smb->tx_late_col;
+ adapter->soft_stats.tx_underun += smb->tx_underrun;
+ adapter->soft_stats.tx_trunc += smb->tx_trunc;
+ adapter->soft_stats.tx_pause += smb->tx_pause;
+
+ adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets;
+ adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets;
+ adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes;
+ adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes;
+ adapter->net_stats.multicast = adapter->soft_stats.multicast;
+ adapter->net_stats.collisions = adapter->soft_stats.collisions;
+ adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors;
+ adapter->net_stats.rx_over_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.rx_length_errors =
+ adapter->soft_stats.rx_length_errors;
+ adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors;
+ adapter->net_stats.rx_frame_errors =
+ adapter->soft_stats.rx_frame_errors;
+ adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors;
+ adapter->net_stats.rx_missed_errors =
+ adapter->soft_stats.rx_missed_errors;
+ adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors;
+ adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors;
+ adapter->net_stats.tx_aborted_errors =
+ adapter->soft_stats.tx_aborted_errors;
+ adapter->net_stats.tx_window_errors =
+ adapter->soft_stats.tx_window_errors;
+ adapter->net_stats.tx_carrier_errors =
+ adapter->soft_stats.tx_carrier_errors;
+}
+
+/*
+ * atl1_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ */
+static struct net_device_stats *atl1_get_stats(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ return &adapter->net_stats;
+}
+
+static void atl1_update_mailbox(struct atl1_adapter *adapter)
+{
+ unsigned long flags;
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+ u32 value;
+
+ spin_lock_irqsave(&adapter->mb_lock, flags);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean);
+
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+
+ spin_unlock_irqrestore(&adapter->mb_lock, flags);
+}
+
+static void atl1_clean_alloc_flag(struct atl1_adapter *adapter,
+ struct rx_return_desc *rrd, u16 offset)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+
+ while (rfd_ring->next_to_clean != (rrd->buf_indx + offset)) {
+ rfd_ring->buffer_info[rfd_ring->next_to_clean].alloced = 0;
+ if (++rfd_ring->next_to_clean == rfd_ring->count) {
+ rfd_ring->next_to_clean = 0;
+ }
}
+}
- /* atl1_irq_enable(adapter); */
- spin_unlock_irqrestore(&adapter->lock, flags);
+static void atl1_update_rfd_index(struct atl1_adapter *adapter,
+ struct rx_return_desc *rrd)
+{
+ u16 num_buf;
+
+ num_buf = (rrd->xsz.xsum_sz.pkt_size + adapter->rx_buffer_len - 1) /
+ adapter->rx_buffer_len;
+ if (rrd->num_buf == num_buf)
+ /* clean alloc flag for bad rrd */
+ atl1_clean_alloc_flag(adapter, rrd, num_buf);
}
-static void atl1_restore_vlan(struct atl1_adapter *adapter)
+static void atl1_rx_checksum(struct atl1_adapter *adapter,
+ struct rx_return_desc *rrd, struct sk_buff *skb)
{
- atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+ struct pci_dev *pdev = adapter->pdev;
+
+ skb->ip_summed = CHECKSUM_NONE;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
+ ERR_FLAG_CODE | ERR_FLAG_OV)) {
+ adapter->hw_csum_err++;
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "rx checksum error\n");
+ return;
+ }
+ }
+
+ /* not IPv4 */
+ if (!(rrd->pkt_flg & PACKET_FLAG_IPV4))
+ /* checksum is invalid, but it's not an IPv4 pkt, so ok */
+ return;
+
+ /* IPv4 packet */
+ if (likely(!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM)))) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ adapter->hw_csum_good++;
+ return;
+ }
+
+ /* IPv4, but hardware thinks its checksum is wrong */
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "hw csum wrong, pkt_flag:%x, err_flag:%x\n",
+ rrd->pkt_flg, rrd->err_flg);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = htons(rrd->xsz.xsum_sz.rx_chksum);
+ adapter->hw_csum_err++;
+ return;
+}
+
+/*
+ * atl1_alloc_rx_buffers - Replace used receive buffers
+ * @adapter: address of board private structure
+ */
+static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter)
+{
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct pci_dev *pdev = adapter->pdev;
+ struct page *page;
+ unsigned long offset;
+ struct atl1_buffer *buffer_info, *next_info;
+ struct sk_buff *skb;
+ u16 num_alloc = 0;
+ u16 rfd_next_to_use, next_next;
+ struct rx_free_desc *rfd_desc;
+
+ next_next = rfd_next_to_use = atomic_read(&rfd_ring->next_to_use);
+ if (++next_next == rfd_ring->count)
+ next_next = 0;
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+
+ while (!buffer_info->alloced && !next_info->alloced) {
+ if (buffer_info->skb) {
+ buffer_info->alloced = 1;
+ goto next;
+ }
+
+ rfd_desc = ATL1_RFD_DESC(rfd_ring, rfd_next_to_use);
+
+ skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);
+ if (unlikely(!skb)) { /* Better luck next round */
+ adapter->net_stats.rx_dropped++;
+ break;
+ }
+
+ /*
+ * Make buffer alignment 2 beyond a 16 byte boundary
+ * this will result in a 16 byte aligned IP header after
+ * the 14 byte MAC header is removed
+ */
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ buffer_info->alloced = 1;
+ buffer_info->skb = skb;
+ buffer_info->length = (u16) adapter->rx_buffer_len;
+ page = virt_to_page(skb->data);
+ offset = (unsigned long)skb->data & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(pdev, page, offset,
+ adapter->rx_buffer_len,
+ PCI_DMA_FROMDEVICE);
+ rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+ rfd_desc->buf_len = cpu_to_le16(adapter->rx_buffer_len);
+ rfd_desc->coalese = 0;
+
+next:
+ rfd_next_to_use = next_next;
+ if (unlikely(++next_next == rfd_ring->count))
+ next_next = 0;
+
+ buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+ next_info = &rfd_ring->buffer_info[next_next];
+ num_alloc++;
+ }
+
+ if (num_alloc) {
+ /*
+ * Force memory writes to complete before letting h/w
+ * know there are new descriptors to fetch. (Only
+ * applicable for weak-ordered memory model archs,
+ * such as IA-64).
+ */
+ wmb();
+ atomic_set(&rfd_ring->next_to_use, (int)rfd_next_to_use);
+ }
+ return num_alloc;
+}
+
+static void atl1_intr_rx(struct atl1_adapter *adapter)
+{
+ int i, count;
+ u16 length;
+ u16 rrd_next_to_clean;
+ u32 value;
+ struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
+ struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
+ struct atl1_buffer *buffer_info;
+ struct rx_return_desc *rrd;
+ struct sk_buff *skb;
+
+ count = 0;
+
+ rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean);
+
+ while (1) {
+ rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean);
+ i = 1;
+ if (likely(rrd->xsz.valid)) { /* packet valid */
+chk_rrd:
+ /* check rrd status */
+ if (likely(rrd->num_buf == 1))
+ goto rrd_ok;
+
+ /* rrd seems to be bad */
+ if (unlikely(i-- > 0)) {
+ /* rrd may not be DMAed completely */
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev,
+ "incomplete RRD DMA transfer\n");
+ udelay(1);
+ goto chk_rrd;
+ }
+ /* bad rrd */
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev,
+ "bad RRD\n");
+ /* see if update RFD index */
+ if (rrd->num_buf > 1)
+ atl1_update_rfd_index(adapter, rrd);
+
+ /* update rrd */
+ rrd->xsz.valid = 0;
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+ continue;
+ } else { /* current rrd still not be updated */
+
+ break;
+ }
+rrd_ok:
+ /* clean alloc flag for bad rrd */
+ atl1_clean_alloc_flag(adapter, rrd, 0);
+
+ buffer_info = &rfd_ring->buffer_info[rrd->buf_indx];
+ if (++rfd_ring->next_to_clean == rfd_ring->count)
+ rfd_ring->next_to_clean = 0;
+
+ /* update rrd next to clean */
+ if (++rrd_next_to_clean == rrd_ring->count)
+ rrd_next_to_clean = 0;
+ count++;
+
+ if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
+ if (!(rrd->err_flg &
+ (ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM
+ | ERR_FLAG_LEN))) {
+ /* packet error, don't need upstream */
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+ continue;
+ }
+ }
+
+ /* Good Receive */
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_FROMDEVICE);
+ skb = buffer_info->skb;
+ length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
+
+ skb_put(skb, length - ETHERNET_FCS_SIZE);
+
+ /* Receive Checksum Offload */
+ atl1_rx_checksum(adapter, rrd, skb);
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+ if (adapter->vlgrp && (rrd->pkt_flg & PACKET_FLAG_VLAN_INS)) {
+ u16 vlan_tag = (rrd->vlan_tag >> 4) |
+ ((rrd->vlan_tag & 7) << 13) |
+ ((rrd->vlan_tag & 8) << 9);
+ vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag);
+ } else
+ netif_rx(skb);
+
+ /* let protocol layer free skb */
+ buffer_info->skb = NULL;
+ buffer_info->alloced = 0;
+ rrd->xsz.valid = 0;
+
+ adapter->netdev->last_rx = jiffies;
+ }
+
+ atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
+
+ atl1_alloc_rx_buffers(adapter);
+
+ /* update mailbox ? */
+ if (count) {
+ u32 tpd_next_to_use;
+ u32 rfd_next_to_use;
+ u32 rrd_next_to_clean;
+
+ spin_lock(&adapter->mb_lock);
+
+ tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
+ rfd_next_to_use =
+ atomic_read(&adapter->rfd_ring.next_to_use);
+ rrd_next_to_clean =
+ atomic_read(&adapter->rrd_ring.next_to_clean);
+ value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
+ MB_RFD_PROD_INDX_SHIFT) |
+ ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
+ MB_RRD_CONS_INDX_SHIFT) |
+ ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
+ MB_TPD_PROD_INDX_SHIFT);
+ iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
+ spin_unlock(&adapter->mb_lock);
+ }
+}
+
+static void atl1_intr_tx(struct atl1_adapter *adapter)
+{
+ struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
+ struct atl1_buffer *buffer_info;
+ u16 sw_tpd_next_to_clean;
+ u16 cmb_tpd_next_to_clean;
+
+ sw_tpd_next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+ cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);
+
+ while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
+ struct tx_packet_desc *tpd;
+
+ tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
+ buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
+ if (buffer_info->dma) {
+ pci_unmap_page(adapter->pdev, buffer_info->dma,
+ buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = 0;
+ }
+
+ if (buffer_info->skb) {
+ dev_kfree_skb_irq(buffer_info->skb);
+ buffer_info->skb = NULL;
+ }
+ tpd->buffer_addr = 0;
+ tpd->desc.data = 0;
+
+ if (++sw_tpd_next_to_clean == tpd_ring->count)
+ sw_tpd_next_to_clean = 0;
+ }
+ atomic_set(&tpd_ring->next_to_clean, sw_tpd_next_to_clean);
+
+ if (netif_queue_stopped(adapter->netdev)
+ && netif_carrier_ok(adapter->netdev))
+ netif_wake_queue(adapter->netdev);
}
static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring)
{
u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
- return ((next_to_clean >
- next_to_use) ? next_to_clean - next_to_use -
- 1 : tpd_ring->count + next_to_clean - next_to_use - 1);
+ return ((next_to_clean > next_to_use) ?
+ next_to_clean - next_to_use - 1 :
+ tpd_ring->count + next_to_clean - next_to_use - 1);
}
static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
@@ -1262,9 +1451,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
iph->tot_len = 0;
iph->check = 0;
tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
- iph->daddr, 0,
- IPPROTO_TCP,
- 0);
+ iph->daddr, 0, IPPROTO_TCP, 0);
ipofst = skb_network_offset(skb);
if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
@@ -1272,7 +1459,8 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
tso->tsopl |= (iph->ihl &
CSUM_PARAM_IPHL_MASK) << CSUM_PARAM_IPHL_SHIFT;
tso->tsopl |= (tcp_hdrlen(skb) &
- TSO_PARAM_TCPHDRLEN_MASK) << TSO_PARAM_TCPHDRLEN_SHIFT;
+ TSO_PARAM_TCPHDRLEN_MASK) <<
+ TSO_PARAM_TCPHDRLEN_SHIFT;
tso->tsopl |= (skb_shinfo(skb)->gso_size &
TSO_PARAM_MSS_MASK) << TSO_PARAM_MSS_SHIFT;
tso->tsopl |= 1 << TSO_PARAM_IPCKSUM_SHIFT;
@@ -1285,7 +1473,7 @@ static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
}
static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
- struct csum_param *csum)
+ struct csum_param *csum)
{
u8 css, cso;
@@ -1293,7 +1481,7 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
cso = skb_transport_offset(skb);
css = cso + skb->csum_offset;
if (unlikely(cso & 0x1)) {
- dev_dbg(&adapter->pdev->dev,
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev,
"payload offset not an even number\n");
return -1;
}
@@ -1308,8 +1496,8 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
return true;
}
-static void atl1_tx_map(struct atl1_adapter *adapter,
- struct sk_buff *skb, bool tcp_seg)
+static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
+ bool tcp_seg)
{
/* We enter this function holding a spinlock. */
struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
@@ -1346,26 +1534,25 @@ static void atl1_tx_map(struct atl1_adapter *adapter,
if (first_buf_len > proto_hdr_len) {
len12 = first_buf_len - proto_hdr_len;
- m = (len12 + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ m = (len12 + ATL1_MAX_TX_BUF_LEN - 1) /
+ ATL1_MAX_TX_BUF_LEN;
for (i = 0; i < m; i++) {
buffer_info =
&tpd_ring->buffer_info[tpd_next_to_use];
buffer_info->skb = NULL;
buffer_info->length =
- (MAX_TX_BUF_LEN >=
- len12) ? MAX_TX_BUF_LEN : len12;
+ (ATL1_MAX_TX_BUF_LEN >=
+ len12) ? ATL1_MAX_TX_BUF_LEN : len12;
len12 -= buffer_info->length;
page = virt_to_page(skb->data +
- (proto_hdr_len +
- i * MAX_TX_BUF_LEN));
+ (proto_hdr_len +
+ i * ATL1_MAX_TX_BUF_LEN));
offset = (unsigned long)(skb->data +
- (proto_hdr_len +
- i * MAX_TX_BUF_LEN)) &
- ~PAGE_MASK;
- buffer_info->dma =
- pci_map_page(adapter->pdev, page, offset,
- buffer_info->length,
- PCI_DMA_TODEVICE);
+ (proto_hdr_len +
+ i * ATL1_MAX_TX_BUF_LEN)) & ~PAGE_MASK;
+ buffer_info->dma = pci_map_page(adapter->pdev,
+ page, offset, buffer_info->length,
+ PCI_DMA_TODEVICE);
if (++tpd_next_to_use == tpd_ring->count)
tpd_next_to_use = 0;
}
@@ -1376,8 +1563,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter,
page = virt_to_page(skb->data);
offset = (unsigned long)skb->data & ~PAGE_MASK;
buffer_info->dma = pci_map_page(adapter->pdev, page,
- offset, first_buf_len,
- PCI_DMA_TODEVICE);
+ offset, first_buf_len, PCI_DMA_TODEVICE);
if (++tpd_next_to_use == tpd_ring->count)
tpd_next_to_use = 0;
}
@@ -1389,19 +1575,19 @@ static void atl1_tx_map(struct atl1_adapter *adapter,
frag = &skb_shinfo(skb)->frags[f];
lenf = frag->size;
- m = (lenf + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ m = (lenf + ATL1_MAX_TX_BUF_LEN - 1) / ATL1_MAX_TX_BUF_LEN;
for (i = 0; i < m; i++) {
buffer_info = &tpd_ring->buffer_info[tpd_next_to_use];
if (unlikely(buffer_info->skb))
BUG();
buffer_info->skb = NULL;
- buffer_info->length =
- (lenf > MAX_TX_BUF_LEN) ? MAX_TX_BUF_LEN : lenf;
+ buffer_info->length = (lenf > ATL1_MAX_TX_BUF_LEN) ?
+ ATL1_MAX_TX_BUF_LEN : lenf;
lenf -= buffer_info->length;
- buffer_info->dma =
- pci_map_page(adapter->pdev, frag->page,
- frag->page_offset + i * MAX_TX_BUF_LEN,
- buffer_info->length, PCI_DMA_TODEVICE);
+ buffer_info->dma = pci_map_page(adapter->pdev,
+ frag->page,
+ frag->page_offset + (i * ATL1_MAX_TX_BUF_LEN),
+ buffer_info->length, PCI_DMA_TODEVICE);
if (++tpd_next_to_use == tpd_ring->count)
tpd_next_to_use = 0;
@@ -1413,7 +1599,7 @@ static void atl1_tx_map(struct atl1_adapter *adapter,
}
static void atl1_tx_queue(struct atl1_adapter *adapter, int count,
- union tpd_descr *descr)
+ union tpd_descr *descr)
{
/* We enter this function holding a spinlock. */
struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
@@ -1457,31 +1643,6 @@ static void atl1_tx_queue(struct atl1_adapter *adapter, int count,
atomic_set(&tpd_ring->next_to_use, (int)tpd_next_to_use);
}
-static void atl1_update_mailbox(struct atl1_adapter *adapter)
-{
- unsigned long flags;
- u32 tpd_next_to_use;
- u32 rfd_next_to_use;
- u32 rrd_next_to_clean;
- u32 value;
-
- spin_lock_irqsave(&adapter->mb_lock, flags);
-
- tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
- rfd_next_to_use = atomic_read(&adapter->rfd_ring.next_to_use);
- rrd_next_to_clean = atomic_read(&adapter->rrd_ring.next_to_clean);
-
- value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
- MB_RFD_PROD_INDX_SHIFT) |
- ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
- MB_RRD_CONS_INDX_SHIFT) |
- ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
- MB_TPD_PROD_INDX_SHIFT);
- iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
-
- spin_unlock_irqrestore(&adapter->mb_lock, flags);
-}
-
static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct atl1_adapter *adapter = netdev_priv(netdev);
@@ -1517,8 +1678,8 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
for (f = 0; f < nr_frags; f++) {
frag_size = skb_shinfo(skb)->frags[f].size;
if (frag_size)
- count +=
- (frag_size + MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ count += (frag_size + ATL1_MAX_TX_BUF_LEN - 1) /
+ ATL1_MAX_TX_BUF_LEN;
}
/* mss will be nonzero if we're doing segment offload (TSO/GSO) */
@@ -1534,7 +1695,8 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* need additional TPD ? */
if (proto_hdr_len != len)
count += (len - proto_hdr_len +
- MAX_TX_BUF_LEN - 1) / MAX_TX_BUF_LEN;
+ ATL1_MAX_TX_BUF_LEN - 1) /
+ ATL1_MAX_TX_BUF_LEN;
}
}
@@ -1542,7 +1704,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (!spin_trylock(&adapter->lock)) {
/* Can't get lock - tell upper layer to requeue */
local_irq_restore(flags);
- dev_dbg(&adapter->pdev->dev, "tx locked\n");
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev, "tx locked\n");
return NETDEV_TX_LOCKED;
}
@@ -1550,7 +1712,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* not enough descriptors */
netif_stop_queue(netdev);
spin_unlock_irqrestore(&adapter->lock, flags);
- dev_dbg(&adapter->pdev->dev, "tx busy\n");
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev, "tx busy\n");
return NETDEV_TX_BUSY;
}
@@ -1592,131 +1754,208 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
/*
- * atl1_get_stats - Get System Network Statistics
- * @netdev: network interface device structure
- *
- * Returns the address of the device statistics structure.
- * The statistics are actually updated from the timer callback.
+ * atl1_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
*/
-static struct net_device_stats *atl1_get_stats(struct net_device *netdev)
+static irqreturn_t atl1_intr(int irq, void *data)
{
- struct atl1_adapter *adapter = netdev_priv(netdev);
- return &adapter->net_stats;
-}
+ struct atl1_adapter *adapter = netdev_priv(data);
+ u32 status;
+ u8 update_rx;
+ int max_ints = 10;
-/*
- * atl1_clean_rx_ring - Free RFD Buffers
- * @adapter: board private structure
- */
-static void atl1_clean_rx_ring(struct atl1_adapter *adapter)
-{
- struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
- struct atl1_buffer *buffer_info;
- struct pci_dev *pdev = adapter->pdev;
- unsigned long size;
- unsigned int i;
+ status = adapter->cmb.cmb->int_stats;
+ if (!status)
+ return IRQ_NONE;
- /* Free all the Rx ring sk_buffs */
- for (i = 0; i < rfd_ring->count; i++) {
- buffer_info = &rfd_ring->buffer_info[i];
- if (buffer_info->dma) {
- pci_unmap_page(pdev,
- buffer_info->dma,
- buffer_info->length,
- PCI_DMA_FROMDEVICE);
- buffer_info->dma = 0;
+ update_rx = 0;
+
+ do {
+ /* clear CMB interrupt status at once */
+ adapter->cmb.cmb->int_stats = 0;
+
+ if (status & ISR_GPHY) /* clear phy status */
+ atl1_clear_phy_int(adapter);
+
+ /* clear ISR status, and Enable CMB DMA/Disable Interrupt */
+ iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR);
+
+ /* check if SMB intr */
+ if (status & ISR_SMB)
+ atl1_inc_smb(adapter);
+
+ /* check if PCIE PHY Link down */
+ if (status & ISR_PHY_LINKDOWN) {
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev,
+ "pcie phy link down %x\n", status);
+ if (netif_running(adapter->netdev)) { /* reset MAC */
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
+ }
}
- if (buffer_info->skb) {
- dev_kfree_skb(buffer_info->skb);
- buffer_info->skb = NULL;
+
+ /* check if DMA read/write error ? */
+ if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev,
+ "pcie DMA r/w error (status = 0x%x)\n",
+ status);
+ iowrite32(0, adapter->hw.hw_addr + REG_IMR);
+ schedule_work(&adapter->pcie_dma_to_rst_task);
+ return IRQ_HANDLED;
}
- }
- size = sizeof(struct atl1_buffer) * rfd_ring->count;
- memset(rfd_ring->buffer_info, 0, size);
+ /* link event */
+ if (status & ISR_GPHY) {
+ adapter->soft_stats.tx_carrier_errors++;
+ atl1_check_for_link(adapter);
+ }
- /* Zero out the descriptor ring */
- memset(rfd_ring->desc, 0, rfd_ring->size);
+ /* transmit event */
+ if (status & ISR_CMB_TX)
+ atl1_intr_tx(adapter);
- rfd_ring->next_to_clean = 0;
- atomic_set(&rfd_ring->next_to_use, 0);
+ /* rx exception */
+ if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+ ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+ ISR_HOST_RRD_OV | ISR_CMB_RX))) {
+ if (status & (ISR_RXF_OV | ISR_RFD_UNRUN |
+ ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
+ ISR_HOST_RRD_OV))
+ dev_printk(KERN_DEBUG, &adapter->pdev->dev,
+ "rx exception, ISR = 0x%x\n", status);
+ atl1_intr_rx(adapter);
+ }
- rrd_ring->next_to_use = 0;
- atomic_set(&rrd_ring->next_to_clean, 0);
+ if (--max_ints < 0)
+ break;
+
+ } while ((status = adapter->cmb.cmb->int_stats));
+
+ /* re-enable Interrupt */
+ iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR);
+ return IRQ_HANDLED;
}
/*
- * atl1_clean_tx_ring - Free Tx Buffers
- * @adapter: board private structure
+ * atl1_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
*/
-static void atl1_clean_tx_ring(struct atl1_adapter *adapter)
+static void atl1_watchdog(unsigned long data)
{
- struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
- struct atl1_buffer *buffer_info;
- struct pci_dev *pdev = adapter->pdev;
- unsigned long size;
- unsigned int i;
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
- /* Free all the Tx ring sk_buffs */
- for (i = 0; i < tpd_ring->count; i++) {
- buffer_info = &tpd_ring->buffer_info[i];
- if (buffer_info->dma) {
- pci_unmap_page(pdev, buffer_info->dma,
- buffer_info->length, PCI_DMA_TODEVICE);
- buffer_info->dma = 0;
- }
- }
+ /* Reset the timer */
+ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
- for (i = 0; i < tpd_ring->count; i++) {
- buffer_info = &tpd_ring->buffer_info[i];
- if (buffer_info->skb) {
- dev_kfree_skb_any(buffer_info->skb);
- buffer_info->skb = NULL;
- }
- }
+/*
+ * atl1_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1_phy_config(unsigned long data)
+{
+ struct atl1_adapter *adapter = (struct atl1_adapter *)data;
+ struct atl1_hw *hw = &adapter->hw;
+ unsigned long flags;
- size = sizeof(struct atl1_buffer) * tpd_ring->count;
- memset(tpd_ring->buffer_info, 0, size);
+ spin_lock_irqsave(&adapter->lock, flags);
+ adapter->phy_timer_pending = false;
+ atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
+ atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg);
+ atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
- /* Zero out the descriptor ring */
- memset(tpd_ring->desc, 0, tpd_ring->size);
+/*
+ * atl1_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl1_tx_timeout(struct net_device *netdev)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ /* Do the reset outside of interrupt context */
+ schedule_work(&adapter->tx_timeout_task);
+}
- atomic_set(&tpd_ring->next_to_use, 0);
- atomic_set(&tpd_ring->next_to_clean, 0);
+/*
+ * Orphaned vendor comment left intact here:
+ * <vendor comment>
+ * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
+ * will assert. We do soft reset <0x1400=1> according
+ * with the SPEC. BUT, it seemes that PCIE or DMA
+ * state-machine will not be reset. DMAR_TO_INT will
+ * assert again and again.
+ * </vendor comment>
+ */
+static void atl1_tx_timeout_task(struct work_struct *work)
+{
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, tx_timeout_task);
+ struct net_device *netdev = adapter->netdev;
+
+ netif_device_detach(netdev);
+ atl1_down(adapter);
+ atl1_up(adapter);
+ netif_device_attach(netdev);
}
/*
- * atl1_free_ring_resources - Free Tx / RX descriptor Resources
- * @adapter: board private structure
- *
- * Free all transmit software resources
+ * atl1_link_chg_task - deal with link change event Out of interrupt context
*/
-void atl1_free_ring_resources(struct atl1_adapter *adapter)
+static void atl1_link_chg_task(struct work_struct *work)
{
- struct pci_dev *pdev = adapter->pdev;
- struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
- struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
- struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
- struct atl1_ring_header *ring_header = &adapter->ring_header;
+ struct atl1_adapter *adapter =
+ container_of(work, struct atl1_adapter, link_chg_task);
+ unsigned long flags;
- atl1_clean_tx_ring(adapter);
- atl1_clean_rx_ring(adapter);
+ spin_lock_irqsave(&adapter->lock, flags);
+ atl1_check_link(adapter);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
- kfree(tpd_ring->buffer_info);
- pci_free_consistent(pdev, ring_header->size, ring_header->desc,
- ring_header->dma);
+static void atl1_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ unsigned long flags;
+ u32 ctrl;
- tpd_ring->buffer_info = NULL;
- tpd_ring->desc = NULL;
- tpd_ring->dma = 0;
+ spin_lock_irqsave(&adapter->lock, flags);
+ /* atl1_irq_disable(adapter); */
+ adapter->vlgrp = grp;
- rfd_ring->buffer_info = NULL;
- rfd_ring->desc = NULL;
- rfd_ring->dma = 0;
+ if (grp) {
+ /* enable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl |= MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ } else {
+ /* disable VLAN tag insert/strip */
+ ctrl = ioread32(adapter->hw.hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_RMV_VLAN;
+ iowrite32(ctrl, adapter->hw.hw_addr + REG_MAC_CTRL);
+ }
- rrd_ring->desc = NULL;
- rrd_ring->dma = 0;
+ /* atl1_irq_enable(adapter); */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+}
+
+static void atl1_restore_vlan(struct atl1_adapter *adapter)
+{
+ atl1_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+}
+
+int atl1_reset(struct atl1_adapter *adapter)
+{
+ int ret;
+
+ ret = atl1_reset_hw(&adapter->hw);
+ if (ret != ATL1_SUCCESS)
+ return ret;
+ return atl1_init_hw(&adapter->hw);
}
s32 atl1_up(struct atl1_adapter *adapter)
@@ -1727,6 +1966,7 @@ s32 atl1_up(struct atl1_adapter *adapter)
/* hardware has been reset, we need to reload some things */
atl1_set_multi(netdev);
+ atl1_init_ring_ptrs(adapter);
atl1_restore_vlan(adapter);
err = atl1_alloc_rx_buffers(adapter);
if (unlikely(!err)) /* no RX BUFFER allocated */
@@ -1754,11 +1994,6 @@ s32 atl1_up(struct atl1_adapter *adapter)
atl1_check_link(adapter);
return 0;
- /* FIXME: unreachable code! -- CHS */
- /* free irq disable any interrupt */
- iowrite32(0, adapter->hw.hw_addr + REG_IMR);
- free_irq(adapter->pdev->irq, netdev);
-
err_up:
pci_disable_msi(adapter->pdev);
/* free rx_buffers */
@@ -1790,172 +2025,6 @@ void atl1_down(struct atl1_adapter *adapter)
}
/*
- * atl1_change_mtu - Change the Maximum Transfer Unit
- * @netdev: network interface device structure
- * @new_mtu: new value for maximum frame size
- *
- * Returns 0 on success, negative on failure
- */
-static int atl1_change_mtu(struct net_device *netdev, int new_mtu)
-{
- struct atl1_adapter *adapter = netdev_priv(netdev);
- int old_mtu = netdev->mtu;
- int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
-
- if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
- (max_frame > MAX_JUMBO_FRAME_SIZE)) {
- dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
- return -EINVAL;
- }
-
- adapter->hw.max_frame_size = max_frame;
- adapter->hw.tx_jumbo_task_th = (max_frame + 7) >> 3;
- adapter->rx_buffer_len = (max_frame + 7) & ~7;
- adapter->hw.rx_jumbo_th = adapter->rx_buffer_len / 8;
-
- netdev->mtu = new_mtu;
- if ((old_mtu != new_mtu) && netif_running(netdev)) {
- atl1_down(adapter);
- atl1_up(adapter);
- }
-
- return 0;
-}
-
-/*
- * atl1_set_mac - Change the Ethernet Address of the NIC
- * @netdev: network interface device structure
- * @p: pointer to an address structure
- *
- * Returns 0 on success, negative on failure
- */
-static int atl1_set_mac(struct net_device *netdev, void *p)
-{
- struct atl1_adapter *adapter = netdev_priv(netdev);
- struct sockaddr *addr = p;
-
- if (netif_running(netdev))
- return -EBUSY;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EADDRNOTAVAIL;
-
- memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
-
- atl1_set_mac_addr(&adapter->hw);
- return 0;
-}
-
-/*
- * atl1_watchdog - Timer Call-back
- * @data: pointer to netdev cast into an unsigned long
- */
-static void atl1_watchdog(unsigned long data)
-{
- struct atl1_adapter *adapter = (struct atl1_adapter *)data;
-
- /* Reset the timer */
- mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
-}
-
-static int mdio_read(struct net_device *netdev, int phy_id, int reg_num)
-{
- struct atl1_adapter *adapter = netdev_priv(netdev);
- u16 result;
-
- atl1_read_phy_reg(&adapter->hw, reg_num & 0x1f, &result);
-
- return result;
-}
-
-static void mdio_write(struct net_device *netdev, int phy_id, int reg_num, int val)
-{
- struct atl1_adapter *adapter = netdev_priv(netdev);
-
- atl1_write_phy_reg(&adapter->hw, reg_num, val);
-}
-
-/*
- * atl1_mii_ioctl -
- * @netdev:
- * @ifreq:
- * @cmd:
- */
-static int atl1_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
-{
- struct atl1_adapter *adapter = netdev_priv(netdev);
- unsigned long flags;
- int retval;
-
- if (!netif_running(netdev))
- return -EINVAL;
-
- spin_lock_irqsave(&adapter->lock, flags);
- retval = generic_mii_ioctl(&adapter->mii, if_mii(ifr), cmd, NULL);
- spin_unlock_irqrestore(&adapter->lock, flags);
-
- return retval;
-}
-
-/*
- * atl1_ioctl -
- * @netdev:
- * @ifreq:
- * @cmd:
- */
-static int atl1_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
-{
- switch (cmd) {
- case SIOCGMIIPHY:
- case SIOCGMIIREG:
- case SIOCSMIIREG:
- return atl1_mii_ioctl(netdev, ifr, cmd);
- default:
- return -EOPNOTSUPP;
- }
-}
-
-/*
- * atl1_tx_timeout - Respond to a Tx Hang
- * @netdev: network interface device structure
- */
-static void atl1_tx_timeout(struct net_device *netdev)
-{
- struct atl1_adapter *adapter = netdev_priv(netdev);
- /* Do the reset outside of interrupt context */
- schedule_work(&adapter->tx_timeout_task);
-}
-
-/*
- * atl1_phy_config - Timer Call-back
- * @data: pointer to netdev cast into an unsigned long
- */
-static void atl1_phy_config(unsigned long data)
-{
- struct atl1_adapter *adapter = (struct atl1_adapter *)data;
- struct atl1_hw *hw = &adapter->hw;
- unsigned long flags;
-
- spin_lock_irqsave(&adapter->lock, flags);
- adapter->phy_timer_pending = false;
- atl1_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg);
- atl1_write_phy_reg(hw, MII_AT001_CR, hw->mii_1000t_ctrl_reg);
- atl1_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN);
- spin_unlock_irqrestore(&adapter->lock, flags);
-}
-
-int atl1_reset(struct atl1_adapter *adapter)
-{
- int ret;
-
- ret = atl1_reset_hw(&adapter->hw);
- if (ret != ATL1_SUCCESS)
- return ret;
- return atl1_init_hw(&adapter->hw);
-}
-
-/*
* atl1_open - Called when a network interface is made active
* @netdev: network interface device structure
*
@@ -2007,77 +2076,113 @@ static int atl1_close(struct net_device *netdev)
return 0;
}
-#ifdef CONFIG_NET_POLL_CONTROLLER
-static void atl1_poll_controller(struct net_device *netdev)
-{
- disable_irq(netdev->irq);
- atl1_intr(netdev->irq, netdev);
- enable_irq(netdev->irq);
-}
-#endif
-
-/*
- * If TPD Buffer size equal to 0, PCIE DMAR_TO_INT
- * will assert. We do soft reset <0x1400=1> according
- * with the SPEC. BUT, it seemes that PCIE or DMA
- * state-machine will not be reset. DMAR_TO_INT will
- * assert again and again.
- */
-static void atl1_tx_timeout_task(struct work_struct *work)
+#ifdef CONFIG_PM
+static int atl1_suspend(struct pci_dev *pdev, pm_message_t state)
{
- struct atl1_adapter *adapter =
- container_of(work, struct atl1_adapter, tx_timeout_task);
- struct net_device *netdev = adapter->netdev;
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ struct atl1_hw *hw = &adapter->hw;
+ u32 ctrl = 0;
+ u32 wufc = adapter->wol;
netif_device_detach(netdev);
- atl1_down(adapter);
- atl1_up(adapter);
- netif_device_attach(netdev);
-}
+ if (netif_running(netdev))
+ atl1_down(adapter);
-/*
- * atl1_link_chg_task - deal with link change event Out of interrupt context
- */
-static void atl1_link_chg_task(struct work_struct *work)
-{
- struct atl1_adapter *adapter =
- container_of(work, struct atl1_adapter, link_chg_task);
- unsigned long flags;
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
+ if (ctrl & BMSR_LSTATUS)
+ wufc &= ~ATL1_WUFC_LNKC;
- spin_lock_irqsave(&adapter->lock, flags);
- atl1_check_link(adapter);
- spin_unlock_irqrestore(&adapter->lock, flags);
+ /* reduce speed to 10/100M */
+ if (wufc) {
+ atl1_phy_enter_power_saving(hw);
+ /* if resume, let driver to re- setup link */
+ hw->phy_configured = false;
+ atl1_set_mac_addr(hw);
+ atl1_set_multi(netdev);
+
+ ctrl = 0;
+ /* turn on magic packet wol */
+ if (wufc & ATL1_WUFC_MAG)
+ ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+
+ /* turn on Link change WOL */
+ if (wufc & ATL1_WUFC_LNKC)
+ ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
+ iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
+
+ /* turn on all-multi mode if wake on multicast is enabled */
+ ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL);
+ ctrl &= ~MAC_CTRL_DBG;
+ ctrl &= ~MAC_CTRL_PROMIS_EN;
+ if (wufc & ATL1_WUFC_MC)
+ ctrl |= MAC_CTRL_MC_ALL_EN;
+ else
+ ctrl &= ~MAC_CTRL_MC_ALL_EN;
+
+ /* turn on broadcast mode if wake on-BC is enabled */
+ if (wufc & ATL1_WUFC_BC)
+ ctrl |= MAC_CTRL_BC_EN;
+ else
+ ctrl &= ~MAC_CTRL_BC_EN;
+
+ /* enable RX */
+ ctrl |= MAC_CTRL_RX_EN;
+ iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ } else {
+ iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+ }
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
}
-/*
- * atl1_pcie_patch - Patch for PCIE module
- */
-static void atl1_pcie_patch(struct atl1_adapter *adapter)
+static int atl1_resume(struct pci_dev *pdev)
{
- u32 value;
- value = 0x6500;
- iowrite32(value, adapter->hw.hw_addr + 0x12FC);
- /* pcie flow control mode change */
- value = ioread32(adapter->hw.hw_addr + 0x1008);
- value |= 0x8000;
- iowrite32(value, adapter->hw.hw_addr + 0x1008);
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct atl1_adapter *adapter = netdev_priv(netdev);
+ u32 ret_val;
+
+ pci_set_power_state(pdev, 0);
+ pci_restore_state(pdev);
+
+ ret_val = pci_enable_device(pdev);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
+ atl1_reset(adapter);
+
+ if (netif_running(netdev))
+ atl1_up(adapter);
+ netif_device_attach(netdev);
+
+ atl1_via_workaround(adapter);
+
+ return 0;
}
+#else
+#define atl1_suspend NULL
+#define atl1_resume NULL
+#endif
-/*
- * When ACPI resume on some VIA MotherBoard, the Interrupt Disable bit/0x400
- * on PCI Command register is disable.
- * The function enable this bit.
- * Brackett, 2006/03/15
- */
-static void atl1_via_workaround(struct atl1_adapter *adapter)
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void atl1_poll_controller(struct net_device *netdev)
{
- unsigned long value;
-
- value = ioread16(adapter->hw.hw_addr + PCI_COMMAND);
- if (value & PCI_COMMAND_INTX_DISABLE)
- value &= ~PCI_COMMAND_INTX_DISABLE;
- iowrite32(value, adapter->hw.hw_addr + PCI_COMMAND);
+ disable_irq(netdev->irq);
+ atl1_intr(netdev->irq, netdev);
+ enable_irq(netdev->irq);
}
+#endif
/*
* atl1_probe - Device Initialization Routine
@@ -2091,7 +2196,7 @@ static void atl1_via_workaround(struct atl1_adapter *adapter)
* and a hardware reset occur.
*/
static int __devinit atl1_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
struct net_device *netdev;
struct atl1_adapter *adapter;
@@ -2145,7 +2250,7 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
}
/* get device revision number */
adapter->hw.dev_rev = ioread16(adapter->hw.hw_addr +
- (REG_MASTER_CTRL + 2));
+ (REG_MASTER_CTRL + 2));
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
/* set default ring resource counts */
@@ -2298,7 +2403,8 @@ static void __devexit atl1_remove(struct pci_dev *pdev)
* address, we need to save the permanent one.
*/
if (memcmp(adapter->hw.mac_addr, adapter->hw.perm_mac_addr, ETH_ALEN)) {
- memcpy(adapter->hw.mac_addr, adapter->hw.perm_mac_addr, ETH_ALEN);
+ memcpy(adapter->hw.mac_addr, adapter->hw.perm_mac_addr,
+ ETH_ALEN);
atl1_set_mac_addr(&adapter->hw);
}
@@ -2310,112 +2416,11 @@ static void __devexit atl1_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-#ifdef CONFIG_PM
-static int atl1_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct net_device *netdev = pci_get_drvdata(pdev);
- struct atl1_adapter *adapter = netdev_priv(netdev);
- struct atl1_hw *hw = &adapter->hw;
- u32 ctrl = 0;
- u32 wufc = adapter->wol;
-
- netif_device_detach(netdev);
- if (netif_running(netdev))
- atl1_down(adapter);
-
- atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
- atl1_read_phy_reg(hw, MII_BMSR, (u16 *) & ctrl);
- if (ctrl & BMSR_LSTATUS)
- wufc &= ~ATL1_WUFC_LNKC;
-
- /* reduce speed to 10/100M */
- if (wufc) {
- atl1_phy_enter_power_saving(hw);
- /* if resume, let driver to re- setup link */
- hw->phy_configured = false;
- atl1_set_mac_addr(hw);
- atl1_set_multi(netdev);
-
- ctrl = 0;
- /* turn on magic packet wol */
- if (wufc & ATL1_WUFC_MAG)
- ctrl = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
-
- /* turn on Link change WOL */
- if (wufc & ATL1_WUFC_LNKC)
- ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN);
- iowrite32(ctrl, hw->hw_addr + REG_WOL_CTRL);
-
- /* turn on all-multi mode if wake on multicast is enabled */
- ctrl = ioread32(hw->hw_addr + REG_MAC_CTRL);
- ctrl &= ~MAC_CTRL_DBG;
- ctrl &= ~MAC_CTRL_PROMIS_EN;
- if (wufc & ATL1_WUFC_MC)
- ctrl |= MAC_CTRL_MC_ALL_EN;
- else
- ctrl &= ~MAC_CTRL_MC_ALL_EN;
-
- /* turn on broadcast mode if wake on-BC is enabled */
- if (wufc & ATL1_WUFC_BC)
- ctrl |= MAC_CTRL_BC_EN;
- else
- ctrl &= ~MAC_CTRL_BC_EN;
-
- /* enable RX */
- ctrl |= MAC_CTRL_RX_EN;
- iowrite32(ctrl, hw->hw_addr + REG_MAC_CTRL);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- pci_enable_wake(pdev, PCI_D3cold, 1); /* 4 == D3 cold */
- } else {
- iowrite32(0, hw->hw_addr + REG_WOL_CTRL);
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */
- }
-
- pci_save_state(pdev);
- pci_disable_device(pdev);
-
- pci_set_power_state(pdev, PCI_D3hot);
-
- return 0;
-}
-
-static int atl1_resume(struct pci_dev *pdev)
-{
- struct net_device *netdev = pci_get_drvdata(pdev);
- struct atl1_adapter *adapter = netdev_priv(netdev);
- u32 ret_val;
-
- pci_set_power_state(pdev, 0);
- pci_restore_state(pdev);
-
- ret_val = pci_enable_device(pdev);
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_enable_wake(pdev, PCI_D3cold, 0);
-
- iowrite32(0, adapter->hw.hw_addr + REG_WOL_CTRL);
- atl1_reset(adapter);
-
- if (netif_running(netdev))
- atl1_up(adapter);
- netif_device_attach(netdev);
-
- atl1_via_workaround(adapter);
-
- return 0;
-}
-#else
-#define atl1_suspend NULL
-#define atl1_resume NULL
-#endif
-
static struct pci_driver atl1_driver = {
.name = atl1_driver_name,
.id_table = atl1_pci_tbl,
.probe = atl1_probe,
.remove = __devexit_p(atl1_remove),
- /* Power Managment Hooks */
- /* probably broken right now -- CHS */
.suspend = atl1_suspend,
.resume = atl1_resume
};
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index c27cfcef45fa..e86b3691765b 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -1205,8 +1205,8 @@ static int au1000_rx(struct net_device *dev)
continue;
}
skb_reserve(skb, 2); /* 16 byte IP header align */
- eth_copy_and_sum(skb,
- (unsigned char *)pDB->vaddr, frmlen, 0);
+ skb_copy_to_linear_data(skb,
+ (unsigned char *)pDB->vaddr, frmlen);
skb_put(skb, frmlen);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb); /* pass the packet to upper layers */
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index d19874bf0706..1d882360b34d 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -459,7 +459,7 @@ static int ax_open(struct net_device *dev)
struct ei_device *ei_local = netdev_priv(dev);
int ret;
- dev_dbg(ax->dev, "%s: open\n", dev->name);
+ dev_dbg(&ax->dev->dev, "%s: open\n", dev->name);
ret = request_irq(dev->irq, ax_ei_interrupt, 0, dev->name, dev);
if (ret)
@@ -492,7 +492,7 @@ static int ax_close(struct net_device *dev)
struct ax_device *ax = to_ax_dev(dev);
struct ei_device *ei_local = netdev_priv(dev);
- dev_dbg(ax->dev, "%s: close\n", dev->name);
+ dev_dbg(&ax->dev->dev, "%s: close\n", dev->name);
/* turn the phy off */
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 96fb0ec905a7..37f1b6ff5c12 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1519,14 +1519,13 @@ static void b44_setup_pseudo_magicp(struct b44 *bp)
u8 *pwol_pattern;
u8 pwol_mask[B44_PMASK_SIZE];
- pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
+ pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
if (!pwol_pattern) {
printk(KERN_ERR PFX "Memory not available for WOL\n");
return;
}
/* Ipv4 magic packet pattern - pattern 0.*/
- memset(pwol_pattern, 0, B44_PATTERN_SIZE);
memset(pwol_mask, 0, B44_PMASK_SIZE);
plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
B44_ETHIPV4UDP_HLEN);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
new file mode 100644
index 000000000000..9a08d656f1ce
--- /dev/null
+++ b/drivers/net/bfin_mac.c
@@ -0,0 +1,1009 @@
+/*
+ * File: drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ * Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ * Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2, 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 ; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/portmux.h>
+
+#include "bfin_mac.h"
+
+#define DRV_NAME "bfin_mac"
+#define DRV_VERSION "1.1"
+#define DRV_AUTHOR "Bryan Wu, Luke Yang"
+#define DRV_DESC "Blackfin BF53[67] on-chip Ethernet MAC driver"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);
+
+#if defined(CONFIG_BFIN_MAC_USE_L1)
+# define bfin_mac_alloc(dma_handle, size) l1_data_sram_zalloc(size)
+# define bfin_mac_free(dma_handle, ptr) l1_data_sram_free(ptr)
+#else
+# define bfin_mac_alloc(dma_handle, size) \
+ dma_alloc_coherent(NULL, size, dma_handle, GFP_KERNEL)
+# define bfin_mac_free(dma_handle, ptr) \
+ dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle)
+#endif
+
+#define PKT_BUF_SZ 1580
+
+#define MAX_TIMEOUT_CNT 500
+
+/* pointers to maintain transmit list */
+static struct net_dma_desc_tx *tx_list_head;
+static struct net_dma_desc_tx *tx_list_tail;
+static struct net_dma_desc_rx *rx_list_head;
+static struct net_dma_desc_rx *rx_list_tail;
+static struct net_dma_desc_rx *current_rx_ptr;
+static struct net_dma_desc_tx *current_tx_ptr;
+static struct net_dma_desc_tx *tx_desc;
+static struct net_dma_desc_rx *rx_desc;
+
+static void desc_list_free(void)
+{
+ struct net_dma_desc_rx *r;
+ struct net_dma_desc_tx *t;
+ int i;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+ dma_addr_t dma_handle = 0;
+#endif
+
+ if (tx_desc) {
+ t = tx_list_head;
+ for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+ if (t) {
+ if (t->skb) {
+ dev_kfree_skb(t->skb);
+ t->skb = NULL;
+ }
+ t = t->next;
+ }
+ }
+ bfin_mac_free(dma_handle, tx_desc);
+ }
+
+ if (rx_desc) {
+ r = rx_list_head;
+ for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+ if (r) {
+ if (r->skb) {
+ dev_kfree_skb(r->skb);
+ r->skb = NULL;
+ }
+ r = r->next;
+ }
+ }
+ bfin_mac_free(dma_handle, rx_desc);
+ }
+}
+
+static int desc_list_init(void)
+{
+ int i;
+ struct sk_buff *new_skb;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+ /*
+ * This dma_handle is useless in Blackfin dma_alloc_coherent().
+ * The real dma handler is the return value of dma_alloc_coherent().
+ */
+ dma_addr_t dma_handle;
+#endif
+
+ tx_desc = bfin_mac_alloc(&dma_handle,
+ sizeof(struct net_dma_desc_tx) *
+ CONFIG_BFIN_TX_DESC_NUM);
+ if (tx_desc == NULL)
+ goto init_error;
+
+ rx_desc = bfin_mac_alloc(&dma_handle,
+ sizeof(struct net_dma_desc_rx) *
+ CONFIG_BFIN_RX_DESC_NUM);
+ if (rx_desc == NULL)
+ goto init_error;
+
+ /* init tx_list */
+ tx_list_head = tx_list_tail = tx_desc;
+
+ for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+ struct net_dma_desc_tx *t = tx_desc + i;
+ struct dma_descriptor *a = &(t->desc_a);
+ struct dma_descriptor *b = &(t->desc_b);
+
+ /*
+ * disable DMA
+ * read from memory WNR = 0
+ * wordsize is 32 bits
+ * 6 half words is desc size
+ * large desc flow
+ */
+ a->config = WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+ a->start_addr = (unsigned long)t->packet;
+ a->x_count = 0;
+ a->next_dma_desc = b;
+
+ /*
+ * enabled DMA
+ * write to memory WNR = 1
+ * wordsize is 32 bits
+ * disable interrupt
+ * 6 half words is desc size
+ * large desc flow
+ */
+ b->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+ b->start_addr = (unsigned long)(&(t->status));
+ b->x_count = 0;
+
+ t->skb = NULL;
+ tx_list_tail->desc_b.next_dma_desc = a;
+ tx_list_tail->next = t;
+ tx_list_tail = t;
+ }
+ tx_list_tail->next = tx_list_head; /* tx_list is a circle */
+ tx_list_tail->desc_b.next_dma_desc = &(tx_list_head->desc_a);
+ current_tx_ptr = tx_list_head;
+
+ /* init rx_list */
+ rx_list_head = rx_list_tail = rx_desc;
+
+ for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+ struct net_dma_desc_rx *r = rx_desc + i;
+ struct dma_descriptor *a = &(r->desc_a);
+ struct dma_descriptor *b = &(r->desc_b);
+
+ /* allocate a new skb for next time receive */
+ new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+ if (!new_skb) {
+ printk(KERN_NOTICE DRV_NAME
+ ": init: low on mem - packet dropped\n");
+ goto init_error;
+ }
+ skb_reserve(new_skb, 2);
+ r->skb = new_skb;
+
+ /*
+ * enabled DMA
+ * write to memory WNR = 1
+ * wordsize is 32 bits
+ * disable interrupt
+ * 6 half words is desc size
+ * large desc flow
+ */
+ a->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+ /* since RXDWA is enabled */
+ a->start_addr = (unsigned long)new_skb->data - 2;
+ a->x_count = 0;
+ a->next_dma_desc = b;
+
+ /*
+ * enabled DMA
+ * write to memory WNR = 1
+ * wordsize is 32 bits
+ * enable interrupt
+ * 6 half words is desc size
+ * large desc flow
+ */
+ b->config = DMAEN | WNR | WDSIZE_32 | DI_EN |
+ NDSIZE_6 | DMAFLOW_LARGE;
+ b->start_addr = (unsigned long)(&(r->status));
+ b->x_count = 0;
+
+ rx_list_tail->desc_b.next_dma_desc = a;
+ rx_list_tail->next = r;
+ rx_list_tail = r;
+ }
+ rx_list_tail->next = rx_list_head; /* rx_list is a circle */
+ rx_list_tail->desc_b.next_dma_desc = &(rx_list_head->desc_a);
+ current_rx_ptr = rx_list_head;
+
+ return 0;
+
+init_error:
+ desc_list_free();
+ printk(KERN_ERR DRV_NAME ": kmalloc failed\n");
+ return -ENOMEM;
+}
+
+
+/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
+
+/* Set FER regs to MUX in Ethernet pins */
+static int setup_pin_mux(int action)
+{
+#if defined(CONFIG_BFIN_MAC_RMII)
+ u16 pin_req[] = P_RMII0;
+#else
+ u16 pin_req[] = P_MII0;
+#endif
+
+ if (action) {
+ if (peripheral_request_list(pin_req, DRV_NAME)) {
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+ return -EFAULT;
+ }
+ } else
+ peripheral_free_list(pin_req);
+
+ return 0;
+}
+
+/* Wait until the previous MDC/MDIO transaction has completed */
+static void poll_mdc_done(void)
+{
+ int timeout_cnt = MAX_TIMEOUT_CNT;
+
+ /* poll the STABUSY bit */
+ while ((bfin_read_EMAC_STAADD()) & STABUSY) {
+ mdelay(10);
+ if (timeout_cnt-- < 0) {
+ printk(KERN_ERR DRV_NAME
+ ": wait MDC/MDIO transaction to complete timeout\n");
+ break;
+ }
+ }
+}
+
+/* Read an off-chip register in a PHY through the MDC/MDIO port */
+static u16 read_phy_reg(u16 PHYAddr, u16 RegAddr)
+{
+ poll_mdc_done();
+ /* read mode */
+ bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
+ SET_REGAD(RegAddr) |
+ STABUSY);
+ poll_mdc_done();
+
+ return (u16) bfin_read_EMAC_STADAT();
+}
+
+/* Write an off-chip register in a PHY through the MDC/MDIO port */
+static void raw_write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
+{
+ bfin_write_EMAC_STADAT(Data);
+
+ /* write mode */
+ bfin_write_EMAC_STAADD(SET_PHYAD(PHYAddr) |
+ SET_REGAD(RegAddr) |
+ STAOP |
+ STABUSY);
+
+ poll_mdc_done();
+}
+
+static void write_phy_reg(u16 PHYAddr, u16 RegAddr, u32 Data)
+{
+ poll_mdc_done();
+ raw_write_phy_reg(PHYAddr, RegAddr, Data);
+}
+
+/* set up the phy */
+static void bf537mac_setphy(struct net_device *dev)
+{
+ u16 phydat;
+ struct bf537mac_local *lp = netdev_priv(dev);
+
+ /* Program PHY registers */
+ pr_debug("start setting up phy\n");
+
+ /* issue a reset */
+ raw_write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, 0x8000);
+
+ /* wait half a second */
+ msleep(500);
+
+ phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
+
+ /* advertise flow control supported */
+ phydat = read_phy_reg(lp->PhyAddr, PHYREG_ANAR);
+ phydat |= (1 << 10);
+ write_phy_reg(lp->PhyAddr, PHYREG_ANAR, phydat);
+
+ phydat = 0;
+ if (lp->Negotiate)
+ phydat |= 0x1000; /* enable auto negotiation */
+ else {
+ if (lp->FullDuplex)
+ phydat |= (1 << 8); /* full duplex */
+ else
+ phydat &= (~(1 << 8)); /* half duplex */
+
+ if (!lp->Port10)
+ phydat |= (1 << 13); /* 100 Mbps */
+ else
+ phydat &= (~(1 << 13)); /* 10 Mbps */
+ }
+
+ if (lp->Loopback)
+ phydat |= (1 << 14); /* enable TX->RX loopback */
+
+ write_phy_reg(lp->PhyAddr, PHYREG_MODECTL, phydat);
+ msleep(500);
+
+ phydat = read_phy_reg(lp->PhyAddr, PHYREG_MODECTL);
+ /* check for SMSC PHY */
+ if ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID1) == 0x7) &&
+ ((read_phy_reg(lp->PhyAddr, PHYREG_PHYID2) & 0xfff0) == 0xC0A0)) {
+ /*
+ * we have SMSC PHY so reqest interrupt
+ * on link down condition
+ */
+
+ /* enable interrupts */
+ write_phy_reg(lp->PhyAddr, 30, 0x0ff);
+ }
+}
+
+/**************************************************************************/
+void setup_system_regs(struct net_device *dev)
+{
+ int phyaddr;
+ unsigned short sysctl, phydat;
+ u32 opmode;
+ struct bf537mac_local *lp = netdev_priv(dev);
+ int count = 0;
+
+ phyaddr = lp->PhyAddr;
+
+ /* Enable PHY output */
+ if (!(bfin_read_VR_CTL() & PHYCLKOE))
+ bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
+
+ /* MDC = 2.5 MHz */
+ sysctl = SET_MDCDIV(24);
+ /* Odd word alignment for Receive Frame DMA word */
+ /* Configure checksum support and rcve frame word alignment */
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+ sysctl |= RXDWA | RXCKS;
+#else
+ sysctl |= RXDWA;
+#endif
+ bfin_write_EMAC_SYSCTL(sysctl);
+ /* auto negotiation on */
+ /* full duplex */
+ /* 100 Mbps */
+ phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET;
+ write_phy_reg(phyaddr, PHYREG_MODECTL, phydat);
+
+ /* test if full duplex supported */
+ do {
+ msleep(100);
+ phydat = read_phy_reg(phyaddr, PHYREG_MODESTAT);
+ if (count > 30) {
+ printk(KERN_NOTICE DRV_NAME ": Link is down\n");
+ printk(KERN_NOTICE DRV_NAME
+ "please check your network connection\n");
+ break;
+ }
+ count++;
+ } while (!(phydat & 0x0004));
+
+ phydat = read_phy_reg(phyaddr, PHYREG_ANLPAR);
+
+ if ((phydat & 0x0100) || (phydat & 0x0040)) {
+ opmode = FDMODE;
+ } else {
+ opmode = 0;
+ printk(KERN_INFO DRV_NAME
+ ": Network is set to half duplex\n");
+ }
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+ opmode |= RMII; /* For Now only 100MBit are supported */
+#endif
+
+ bfin_write_EMAC_OPMODE(opmode);
+
+ bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
+
+ /* Initialize the TX DMA channel registers */
+ bfin_write_DMA2_X_COUNT(0);
+ bfin_write_DMA2_X_MODIFY(4);
+ bfin_write_DMA2_Y_COUNT(0);
+ bfin_write_DMA2_Y_MODIFY(0);
+
+ /* Initialize the RX DMA channel registers */
+ bfin_write_DMA1_X_COUNT(0);
+ bfin_write_DMA1_X_MODIFY(4);
+ bfin_write_DMA1_Y_COUNT(0);
+ bfin_write_DMA1_Y_MODIFY(0);
+}
+
+void setup_mac_addr(u8 * mac_addr)
+{
+ u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]);
+ u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]);
+
+ /* this depends on a little-endian machine */
+ bfin_write_EMAC_ADDRLO(addr_low);
+ bfin_write_EMAC_ADDRHI(addr_hi);
+}
+
+static void adjust_tx_list(void)
+{
+ int timeout_cnt = MAX_TIMEOUT_CNT;
+
+ if (tx_list_head->status.status_word != 0
+ && current_tx_ptr != tx_list_head) {
+ goto adjust_head; /* released something, just return; */
+ }
+
+ /*
+ * if nothing released, check wait condition
+ * current's next can not be the head,
+ * otherwise the dma will not stop as we want
+ */
+ if (current_tx_ptr->next->next == tx_list_head) {
+ while (tx_list_head->status.status_word == 0) {
+ mdelay(10);
+ if (tx_list_head->status.status_word != 0
+ || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {
+ goto adjust_head;
+ }
+ if (timeout_cnt-- < 0) {
+ printk(KERN_ERR DRV_NAME
+ ": wait for adjust tx list head timeout\n");
+ break;
+ }
+ }
+ if (tx_list_head->status.status_word != 0) {
+ goto adjust_head;
+ }
+ }
+
+ return;
+
+adjust_head:
+ do {
+ tx_list_head->desc_a.config &= ~DMAEN;
+ tx_list_head->status.status_word = 0;
+ if (tx_list_head->skb) {
+ dev_kfree_skb(tx_list_head->skb);
+ tx_list_head->skb = NULL;
+ } else {
+ printk(KERN_ERR DRV_NAME
+ ": no sk_buff in a transmitted frame!\n");
+ }
+ tx_list_head = tx_list_head->next;
+ } while (tx_list_head->status.status_word != 0
+ && current_tx_ptr != tx_list_head);
+ return;
+
+}
+
+static int bf537mac_hard_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ unsigned int data;
+
+ current_tx_ptr->skb = skb;
+
+ /*
+ * Is skb->data always 16-bit aligned?
+ * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)?
+ */
+ if ((((unsigned int)(skb->data)) & 0x02) == 2) {
+ /* move skb->data to current_tx_ptr payload */
+ data = (unsigned int)(skb->data) - 2;
+ *((unsigned short *)data) = (unsigned short)(skb->len);
+ current_tx_ptr->desc_a.start_addr = (unsigned long)data;
+ /* this is important! */
+ blackfin_dcache_flush_range(data, (data + (skb->len)) + 2);
+
+ } else {
+ *((unsigned short *)(current_tx_ptr->packet)) =
+ (unsigned short)(skb->len);
+ memcpy((char *)(current_tx_ptr->packet + 2), skb->data,
+ (skb->len));
+ current_tx_ptr->desc_a.start_addr =
+ (unsigned long)current_tx_ptr->packet;
+ if (current_tx_ptr->status.status_word != 0)
+ current_tx_ptr->status.status_word = 0;
+ blackfin_dcache_flush_range((unsigned int)current_tx_ptr->
+ packet,
+ (unsigned int)(current_tx_ptr->
+ packet + skb->len) +
+ 2);
+ }
+
+ /* enable this packet's dma */
+ current_tx_ptr->desc_a.config |= DMAEN;
+
+ /* tx dma is running, just return */
+ if (bfin_read_DMA2_IRQ_STATUS() & 0x08)
+ goto out;
+
+ /* tx dma is not running */
+ bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a));
+ /* dma enabled, read from memory, size is 6 */
+ bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config);
+ /* Turn on the EMAC tx */
+ bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
+
+out:
+ adjust_tx_list();
+ current_tx_ptr = current_tx_ptr->next;
+ dev->trans_start = jiffies;
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += (skb->len);
+ return 0;
+}
+
+static void bf537mac_rx(struct net_device *dev)
+{
+ struct sk_buff *skb, *new_skb;
+ struct bf537mac_local *lp = netdev_priv(dev);
+ unsigned short len;
+
+ /* allocate a new skb for next time receive */
+ skb = current_rx_ptr->skb;
+ new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+ if (!new_skb) {
+ printk(KERN_NOTICE DRV_NAME
+ ": rx: low on mem - packet dropped\n");
+ lp->stats.rx_dropped++;
+ goto out;
+ }
+ /* reserve 2 bytes for RXDWA padding */
+ skb_reserve(new_skb, 2);
+ current_rx_ptr->skb = new_skb;
+ current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
+
+ len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
+ skb_put(skb, len);
+ blackfin_dcache_invalidate_range((unsigned long)skb->head,
+ (unsigned long)skb->tail);
+
+ dev->last_rx = jiffies;
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+ skb->csum = current_rx_ptr->status.ip_payload_csum;
+ skb->ip_summed = CHECKSUM_PARTIAL;
+#endif
+
+ netif_rx(skb);
+ lp->stats.rx_packets++;
+ lp->stats.rx_bytes += len;
+ current_rx_ptr->status.status_word = 0x00000000;
+ current_rx_ptr = current_rx_ptr->next;
+
+out:
+ return;
+}
+
+/* interrupt routine to handle rx and error signal */
+static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ int number = 0;
+
+get_one_packet:
+ if (current_rx_ptr->status.status_word == 0) {
+ /* no more new packet received */
+ if (number == 0) {
+ if (current_rx_ptr->next->status.status_word != 0) {
+ current_rx_ptr = current_rx_ptr->next;
+ goto real_rx;
+ }
+ }
+ bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() |
+ DMA_DONE | DMA_ERR);
+ return IRQ_HANDLED;
+ }
+
+real_rx:
+ bf537mac_rx(dev);
+ number++;
+ goto get_one_packet;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void bf537mac_poll(struct net_device *dev)
+{
+ disable_irq(IRQ_MAC_RX);
+ bf537mac_interrupt(IRQ_MAC_RX, dev);
+ enable_irq(IRQ_MAC_RX);
+}
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+
+static void bf537mac_reset(void)
+{
+ unsigned int opmode;
+
+ opmode = bfin_read_EMAC_OPMODE();
+ opmode &= (~RE);
+ opmode &= (~TE);
+ /* Turn off the EMAC */
+ bfin_write_EMAC_OPMODE(opmode);
+}
+
+/*
+ * Enable Interrupts, Receive, and Transmit
+ */
+static int bf537mac_enable(struct net_device *dev)
+{
+ u32 opmode;
+
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ /* Set RX DMA */
+ bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
+ bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
+
+ /* Wait MII done */
+ poll_mdc_done();
+
+ /* We enable only RX here */
+ /* ASTP : Enable Automatic Pad Stripping
+ PR : Promiscuous Mode for test
+ PSF : Receive frames with total length less than 64 bytes.
+ FDMODE : Full Duplex Mode
+ LB : Internal Loopback for test
+ RE : Receiver Enable */
+ opmode = bfin_read_EMAC_OPMODE();
+ if (opmode & FDMODE)
+ opmode |= PSF;
+ else
+ opmode |= DRO | DC | PSF;
+ opmode |= RE;
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+ opmode |= RMII; /* For Now only 100MBit are supported */
+#ifdef CONFIG_BF_REV_0_2
+ opmode |= TE;
+#endif
+#endif
+ /* Turn on the EMAC rx */
+ bfin_write_EMAC_OPMODE(opmode);
+
+ return 0;
+}
+
+/* Our watchdog timed out. Called by the networking layer */
+static void bf537mac_timeout(struct net_device *dev)
+{
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ bf537mac_reset();
+
+ /* reset tx queue */
+ tx_list_tail = tx_list_head->next;
+
+ bf537mac_enable(dev);
+
+ /* We can accept TX packets again */
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
+/*
+ * Get the current statistics.
+ * This may be called with the card open or closed.
+ */
+static struct net_device_stats *bf537mac_query_statistics(struct net_device
+ *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ return &lp->stats;
+}
+
+/*
+ * This routine will, depending on the values passed to it,
+ * either make it accept multicast packets, go into
+ * promiscuous mode (for TCPDUMP and cousins) or accept
+ * a select set of multicast packets
+ */
+static void bf537mac_set_multicast_list(struct net_device *dev)
+{
+ u32 sysctl;
+
+ if (dev->flags & IFF_PROMISC) {
+ printk(KERN_INFO "%s: set to promisc mode\n", dev->name);
+ sysctl = bfin_read_EMAC_OPMODE();
+ sysctl |= RAF;
+ bfin_write_EMAC_OPMODE(sysctl);
+ } else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+ /* accept all multicast */
+ sysctl = bfin_read_EMAC_OPMODE();
+ sysctl |= PAM;
+ bfin_write_EMAC_OPMODE(sysctl);
+ } else {
+ /* clear promisc or multicast mode */
+ sysctl = bfin_read_EMAC_OPMODE();
+ sysctl &= ~(RAF | PAM);
+ bfin_write_EMAC_OPMODE(sysctl);
+ }
+}
+
+/*
+ * this puts the device in an inactive state
+ */
+static void bf537mac_shutdown(struct net_device *dev)
+{
+ /* Turn off the EMAC */
+ bfin_write_EMAC_OPMODE(0x00000000);
+ /* Turn off the EMAC RX DMA */
+ bfin_write_DMA1_CONFIG(0x0000);
+ bfin_write_DMA2_CONFIG(0x0000);
+}
+
+/*
+ * Open and Initialize the interface
+ *
+ * Set up everything, reset the card, etc..
+ */
+static int bf537mac_open(struct net_device *dev)
+{
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ /*
+ * Check that the address is valid. If its not, refuse
+ * to bring the device up. The user must specify an
+ * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
+ */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ printk(KERN_WARNING DRV_NAME ": no valid ethernet hw addr\n");
+ return -EINVAL;
+ }
+
+ /* initial rx and tx list */
+ desc_list_init();
+
+ bf537mac_setphy(dev);
+ setup_system_regs(dev);
+ bf537mac_reset();
+ bf537mac_enable(dev);
+
+ pr_debug("hardware init finished\n");
+ netif_start_queue(dev);
+ netif_carrier_on(dev);
+
+ return 0;
+}
+
+/*
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world. Caused by
+ * an 'ifconfig ethX down'
+ */
+static int bf537mac_close(struct net_device *dev)
+{
+ pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ /* clear everything */
+ bf537mac_shutdown(dev);
+
+ /* free the rx/tx buffers */
+ desc_list_free();
+
+ return 0;
+}
+
+static int __init bf537mac_probe(struct net_device *dev)
+{
+ struct bf537mac_local *lp = netdev_priv(dev);
+ int retval;
+
+ /* Grab the MAC address in the MAC */
+ *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
+ *(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
+
+ /* probe mac */
+ /*todo: how to proble? which is revision_register */
+ bfin_write_EMAC_ADDRLO(0x12345678);
+ if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
+ pr_debug("can't detect bf537 mac!\n");
+ retval = -ENODEV;
+ goto err_out;
+ }
+
+ /* set the GPIO pins to Ethernet mode */
+ retval = setup_pin_mux(1);
+
+ if (retval)
+ return retval;
+
+ /*Is it valid? (Did bootloader initialize it?) */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ /* Grab the MAC from the board somehow - this is done in the
+ arch/blackfin/mach-bf537/boards/eth_mac.c */
+ get_bf537_ether_addr(dev->dev_addr);
+ }
+
+ /* If still not valid, get a random one */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ random_ether_addr(dev->dev_addr);
+ }
+
+ setup_mac_addr(dev->dev_addr);
+
+ /* Fill in the fields of the device structure with ethernet values. */
+ ether_setup(dev);
+
+ dev->open = bf537mac_open;
+ dev->stop = bf537mac_close;
+ dev->hard_start_xmit = bf537mac_hard_start_xmit;
+ dev->tx_timeout = bf537mac_timeout;
+ dev->get_stats = bf537mac_query_statistics;
+ dev->set_multicast_list = bf537mac_set_multicast_list;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ dev->poll_controller = bf537mac_poll;
+#endif
+
+ /* fill in some of the fields */
+ lp->version = 1;
+ lp->PhyAddr = 0x01;
+ lp->CLKIN = 25;
+ lp->FullDuplex = 0;
+ lp->Negotiate = 1;
+ lp->FlowControl = 0;
+ spin_lock_init(&lp->lock);
+
+ /* now, enable interrupts */
+ /* register irq handler */
+ if (request_irq
+ (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ "BFIN537_MAC_RX", dev)) {
+ printk(KERN_WARNING DRV_NAME
+ ": Unable to attach BlackFin MAC RX interrupt\n");
+ return -EBUSY;
+ }
+
+ /* Enable PHY output early */
+ if (!(bfin_read_VR_CTL() & PHYCLKOE))
+ bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
+
+ retval = register_netdev(dev);
+ if (retval == 0) {
+ /* now, print out the card info, in a short format.. */
+ printk(KERN_INFO "%s: Version %s, %s\n",
+ DRV_NAME, DRV_VERSION, DRV_DESC);
+ }
+
+err_out:
+ return retval;
+}
+
+static int bfin_mac_probe(struct platform_device *pdev)
+{
+ struct net_device *ndev;
+
+ ndev = alloc_etherdev(sizeof(struct bf537mac_local));
+ if (!ndev) {
+ printk(KERN_WARNING DRV_NAME ": could not allocate device\n");
+ return -ENOMEM;
+ }
+
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ platform_set_drvdata(pdev, ndev);
+
+ if (bf537mac_probe(ndev) != 0) {
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+ printk(KERN_WARNING DRV_NAME ": not found\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int bfin_mac_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ unregister_netdev(ndev);
+
+ free_irq(IRQ_MAC_RX, ndev);
+
+ free_netdev(ndev);
+
+ setup_pin_mux(0);
+
+ return 0;
+}
+
+static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+static int bfin_mac_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver bfin_mac_driver = {
+ .probe = bfin_mac_probe,
+ .remove = bfin_mac_remove,
+ .resume = bfin_mac_resume,
+ .suspend = bfin_mac_suspend,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init bfin_mac_init(void)
+{
+ return platform_driver_register(&bfin_mac_driver);
+}
+
+module_init(bfin_mac_init);
+
+static void __exit bfin_mac_cleanup(void)
+{
+ platform_driver_unregister(&bfin_mac_driver);
+}
+
+module_exit(bfin_mac_cleanup);
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
new file mode 100644
index 000000000000..af87189b85fa
--- /dev/null
+++ b/drivers/net/bfin_mac.h
@@ -0,0 +1,132 @@
+/*
+ * File: drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ * Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ * Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software ; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation ; either version 2, 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 ; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * PHY REGISTER NAMES
+ */
+#define PHYREG_MODECTL 0x0000
+#define PHYREG_MODESTAT 0x0001
+#define PHYREG_PHYID1 0x0002
+#define PHYREG_PHYID2 0x0003
+#define PHYREG_ANAR 0x0004
+#define PHYREG_ANLPAR 0x0005
+#define PHYREG_ANER 0x0006
+#define PHYREG_NSR 0x0010
+#define PHYREG_LBREMR 0x0011
+#define PHYREG_REC 0x0012
+#define PHYREG_10CFG 0x0013
+#define PHYREG_PHY1_1 0x0014
+#define PHYREG_PHY1_2 0x0015
+#define PHYREG_PHY2 0x0016
+#define PHYREG_TW_1 0x0017
+#define PHYREG_TW_2 0x0018
+#define PHYREG_TEST 0x0019
+
+#define PHY_RESET 0x8000
+#define PHY_ANEG_EN 0x1000
+#define PHY_DUPLEX 0x0100
+#define PHY_SPD_SET 0x2000
+
+#define BFIN_MAC_CSUM_OFFLOAD
+
+struct dma_descriptor {
+ struct dma_descriptor *next_dma_desc;
+ unsigned long start_addr;
+ unsigned short config;
+ unsigned short x_count;
+};
+
+struct status_area_rx {
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+ unsigned short ip_hdr_csum; /* ip header checksum */
+ /* ip payload(udp or tcp or others) checksum */
+ unsigned short ip_payload_csum;
+#endif
+ unsigned long status_word; /* the frame status word */
+};
+
+struct status_area_tx {
+ unsigned long status_word; /* the frame status word */
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_rx {
+ struct net_dma_desc_rx *next;
+ struct sk_buff *skb;
+ struct dma_descriptor desc_a;
+ struct dma_descriptor desc_b;
+ struct status_area_rx status;
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_tx {
+ struct net_dma_desc_tx *next;
+ struct sk_buff *skb;
+ struct dma_descriptor desc_a;
+ struct dma_descriptor desc_b;
+ unsigned char packet[1560];
+ struct status_area_tx status;
+};
+
+struct bf537mac_local {
+ /*
+ * these are things that the kernel wants me to keep, so users
+ * can find out semi-useless statistics of how well the card is
+ * performing
+ */
+ struct net_device_stats stats;
+
+ int version;
+
+ int FlowEnabled; /* record if data flow is active */
+ int EtherIntIVG; /* IVG for the ethernet interrupt */
+ int RXIVG; /* IVG for the RX completion */
+ int TXIVG; /* IVG for the TX completion */
+ int PhyAddr; /* PHY address */
+ int OpMode; /* set these bits n the OPMODE regs */
+ int Port10; /* set port speed to 10 Mbit/s */
+ int GenChksums; /* IP checksums to be calculated */
+ int NoRcveLnth; /* dont insert recv length at start of buffer */
+ int StripPads; /* remove trailing pad bytes */
+ int FullDuplex; /* set full duplex mode */
+ int Negotiate; /* enable auto negotiation */
+ int Loopback; /* loopback at the PHY */
+ int Cache; /* Buffers may be cached */
+ int FlowControl; /* flow control active */
+ int CLKIN; /* clock in value in MHZ */
+ unsigned short IntMask; /* interrupt mask */
+ unsigned char Mac[6]; /* MAC address of the board */
+ spinlock_t lock;
+};
+
+extern void get_bf537_ether_addr(char *addr);
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index ce3ed67a878e..a729da061bbb 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -54,8 +54,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.5.11"
-#define DRV_MODULE_RELDATE "June 4, 2007"
+#define DRV_MODULE_VERSION "1.6.3"
+#define DRV_MODULE_RELDATE "July 16, 2007"
#define RUN_AT(x) (jiffies + (x))
@@ -126,91 +126,102 @@ static struct pci_device_id bnx2_pci_tbl[] = {
static struct flash_spec flash_table[] =
{
+#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
+#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
/* Slow EEPROM */
{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
- 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+ BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
"EEPROM - slow"},
/* Expansion entry 0001 */
{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 0001"},
/* Saifun SA25F010 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
"Non-buffered flash (128kB)"},
/* Saifun SA25F020 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
"Non-buffered flash (256kB)"},
/* Expansion entry 0100 */
{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 0100"},
/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
- 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
"Entry 0101: ST M45PE10 (128kB non-bufferred)"},
/* Entry 0110: ST M45PE20 (non-buffered flash)*/
{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
- 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
"Entry 0110: ST M45PE20 (256kB non-bufferred)"},
/* Saifun SA25F005 (non-buffered flash) */
/* strap, cfg1, & write1 need updates */
{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
"Non-buffered flash (64kB)"},
/* Fast EEPROM */
{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
- 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+ BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
"EEPROM - fast"},
/* Expansion entry 1001 */
{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1001"},
/* Expansion entry 1010 */
{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1010"},
/* ATMEL AT45DB011B (buffered flash) */
{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
"Buffered flash (128kB)"},
/* Expansion entry 1100 */
{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1100"},
/* Expansion entry 1101 */
{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
- 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+ NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1101"},
/* Ateml Expansion entry 1110 */
{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
"Entry 1110 (Atmel)"},
/* ATMEL AT45DB021B (buffered flash) */
{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
- 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+ BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
"Buffered flash (256kB)"},
};
+static struct flash_spec flash_5709 = {
+ .flags = BNX2_NV_BUFFERED,
+ .page_bits = BCM5709_FLASH_PAGE_BITS,
+ .page_size = BCM5709_FLASH_PAGE_SIZE,
+ .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
+ .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
+ .name = "5709 Buffered flash (256kB)",
+};
+
MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
static inline u32 bnx2_tx_avail(struct bnx2 *bp)
@@ -550,6 +561,9 @@ bnx2_report_fw_link(struct bnx2 *bp)
{
u32 fw_link_status = 0;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return;
+
if (bp->link_up) {
u32 bmsr;
@@ -601,12 +615,21 @@ bnx2_report_fw_link(struct bnx2 *bp)
REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
}
+static char *
+bnx2_xceiver_str(struct bnx2 *bp)
+{
+ return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
+ ((bp->phy_flags & PHY_SERDES_FLAG) ? "Remote Copper" :
+ "Copper"));
+}
+
static void
bnx2_report_link(struct bnx2 *bp)
{
if (bp->link_up) {
netif_carrier_on(bp->dev);
- printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name);
+ printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
+ bnx2_xceiver_str(bp));
printk("%d Mbps ", bp->line_speed);
@@ -630,7 +653,8 @@ bnx2_report_link(struct bnx2 *bp)
}
else {
netif_carrier_off(bp->dev);
- printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
+ printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
+ bnx2_xceiver_str(bp));
}
bnx2_report_fw_link(bp);
@@ -1100,6 +1124,9 @@ bnx2_set_link(struct bnx2 *bp)
return 0;
}
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return 0;
+
link_up = bp->link_up;
bnx2_enable_bmsr1(bp);
@@ -1210,12 +1237,74 @@ bnx2_phy_get_pause_adv(struct bnx2 *bp)
return adv;
}
+static int bnx2_fw_sync(struct bnx2 *, u32, int);
+
static int
-bnx2_setup_serdes_phy(struct bnx2 *bp)
+bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
+{
+ u32 speed_arg = 0, pause_adv;
+
+ pause_adv = bnx2_phy_get_pause_adv(bp);
+
+ if (bp->autoneg & AUTONEG_SPEED) {
+ speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
+ if (bp->advertising & ADVERTISED_10baseT_Half)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
+ if (bp->advertising & ADVERTISED_10baseT_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
+ if (bp->advertising & ADVERTISED_100baseT_Half)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
+ if (bp->advertising & ADVERTISED_100baseT_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
+ if (bp->advertising & ADVERTISED_1000baseT_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
+ if (bp->advertising & ADVERTISED_2500baseX_Full)
+ speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
+ } else {
+ if (bp->req_line_speed == SPEED_2500)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
+ else if (bp->req_line_speed == SPEED_1000)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
+ else if (bp->req_line_speed == SPEED_100) {
+ if (bp->req_duplex == DUPLEX_FULL)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
+ else
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
+ } else if (bp->req_line_speed == SPEED_10) {
+ if (bp->req_duplex == DUPLEX_FULL)
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
+ else
+ speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
+ }
+ }
+
+ if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
+ speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
+ if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))
+ speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
+
+ if (port == PORT_TP)
+ speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
+ BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
+
+ REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);
+
+ spin_unlock_bh(&bp->phy_lock);
+ bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
+ spin_lock_bh(&bp->phy_lock);
+
+ return 0;
+}
+
+static int
+bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
{
u32 adv, bmcr;
u32 new_adv = 0;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return (bnx2_setup_remote_phy(bp, port));
+
if (!(bp->autoneg & AUTONEG_SPEED)) {
u32 new_bmcr;
int force_link_down = 0;
@@ -1323,7 +1412,9 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
}
#define ETHTOOL_ALL_FIBRE_SPEED \
- (ADVERTISED_1000baseT_Full)
+ (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ? \
+ (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
+ (ADVERTISED_1000baseT_Full)
#define ETHTOOL_ALL_COPPER_SPEED \
(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
@@ -1335,6 +1426,188 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
+static void
+bnx2_set_default_remote_link(struct bnx2 *bp)
+{
+ u32 link;
+
+ if (bp->phy_port == PORT_TP)
+ link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);
+ else
+ link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);
+
+ if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
+ bp->req_line_speed = 0;
+ bp->autoneg |= AUTONEG_SPEED;
+ bp->advertising = ADVERTISED_Autoneg;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
+ bp->advertising |= ADVERTISED_10baseT_Half;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
+ bp->advertising |= ADVERTISED_10baseT_Full;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
+ bp->advertising |= ADVERTISED_100baseT_Half;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
+ bp->advertising |= ADVERTISED_100baseT_Full;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
+ bp->advertising |= ADVERTISED_1000baseT_Full;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
+ bp->advertising |= ADVERTISED_2500baseX_Full;
+ } else {
+ bp->autoneg = 0;
+ bp->advertising = 0;
+ bp->req_duplex = DUPLEX_FULL;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
+ bp->req_line_speed = SPEED_10;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
+ bp->req_duplex = DUPLEX_HALF;
+ }
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
+ bp->req_line_speed = SPEED_100;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
+ bp->req_duplex = DUPLEX_HALF;
+ }
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
+ bp->req_line_speed = SPEED_1000;
+ if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
+ bp->req_line_speed = SPEED_2500;
+ }
+}
+
+static void
+bnx2_set_default_link(struct bnx2 *bp)
+{
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return bnx2_set_default_remote_link(bp);
+
+ bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
+ bp->req_line_speed = 0;
+ if (bp->phy_flags & PHY_SERDES_FLAG) {
+ u32 reg;
+
+ bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
+
+ reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
+ reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
+ if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
+ bp->autoneg = 0;
+ bp->req_line_speed = bp->line_speed = SPEED_1000;
+ bp->req_duplex = DUPLEX_FULL;
+ }
+ } else
+ bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
+}
+
+static void
+bnx2_send_heart_beat(struct bnx2 *bp)
+{
+ u32 msg;
+ u32 addr;
+
+ spin_lock(&bp->indirect_lock);
+ msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
+ addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
+ REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
+ REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
+ spin_unlock(&bp->indirect_lock);
+}
+
+static void
+bnx2_remote_phy_event(struct bnx2 *bp)
+{
+ u32 msg;
+ u8 link_up = bp->link_up;
+ u8 old_port;
+
+ msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
+
+ if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
+ bnx2_send_heart_beat(bp);
+
+ msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
+
+ if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
+ bp->link_up = 0;
+ else {
+ u32 speed;
+
+ bp->link_up = 1;
+ speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
+ bp->duplex = DUPLEX_FULL;
+ switch (speed) {
+ case BNX2_LINK_STATUS_10HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_10FULL:
+ bp->line_speed = SPEED_10;
+ break;
+ case BNX2_LINK_STATUS_100HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_100BASE_T4:
+ case BNX2_LINK_STATUS_100FULL:
+ bp->line_speed = SPEED_100;
+ break;
+ case BNX2_LINK_STATUS_1000HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_1000FULL:
+ bp->line_speed = SPEED_1000;
+ break;
+ case BNX2_LINK_STATUS_2500HALF:
+ bp->duplex = DUPLEX_HALF;
+ case BNX2_LINK_STATUS_2500FULL:
+ bp->line_speed = SPEED_2500;
+ break;
+ default:
+ bp->line_speed = 0;
+ break;
+ }
+
+ spin_lock(&bp->phy_lock);
+ bp->flow_ctrl = 0;
+ if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
+ (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
+ if (bp->duplex == DUPLEX_FULL)
+ bp->flow_ctrl = bp->req_flow_ctrl;
+ } else {
+ if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
+ bp->flow_ctrl |= FLOW_CTRL_TX;
+ if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
+ bp->flow_ctrl |= FLOW_CTRL_RX;
+ }
+
+ old_port = bp->phy_port;
+ if (msg & BNX2_LINK_STATUS_SERDES_LINK)
+ bp->phy_port = PORT_FIBRE;
+ else
+ bp->phy_port = PORT_TP;
+
+ if (old_port != bp->phy_port)
+ bnx2_set_default_link(bp);
+
+ spin_unlock(&bp->phy_lock);
+ }
+ if (bp->link_up != link_up)
+ bnx2_report_link(bp);
+
+ bnx2_set_mac_link(bp);
+}
+
+static int
+bnx2_set_remote_link(struct bnx2 *bp)
+{
+ u32 evt_code;
+
+ evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);
+ switch (evt_code) {
+ case BNX2_FW_EVT_CODE_LINK_EVENT:
+ bnx2_remote_phy_event(bp);
+ break;
+ case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
+ default:
+ bnx2_send_heart_beat(bp);
+ break;
+ }
+ return 0;
+}
+
static int
bnx2_setup_copper_phy(struct bnx2 *bp)
{
@@ -1433,13 +1706,13 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
}
static int
-bnx2_setup_phy(struct bnx2 *bp)
+bnx2_setup_phy(struct bnx2 *bp, u8 port)
{
if (bp->loopback == MAC_LOOPBACK)
return 0;
if (bp->phy_flags & PHY_SERDES_FLAG) {
- return (bnx2_setup_serdes_phy(bp));
+ return (bnx2_setup_serdes_phy(bp, port));
}
else {
return (bnx2_setup_copper_phy(bp));
@@ -1659,6 +1932,9 @@ bnx2_init_phy(struct bnx2 *bp)
REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ goto setup_phy;
+
bnx2_read_phy(bp, MII_PHYSID1, &val);
bp->phy_id = val << 16;
bnx2_read_phy(bp, MII_PHYSID2, &val);
@@ -1676,7 +1952,9 @@ bnx2_init_phy(struct bnx2 *bp)
rc = bnx2_init_copper_phy(bp);
}
- bnx2_setup_phy(bp);
+setup_phy:
+ if (!rc)
+ rc = bnx2_setup_phy(bp, bp->phy_port);
return rc;
}
@@ -1984,6 +2262,9 @@ bnx2_phy_int(struct bnx2 *bp)
bnx2_set_link(bp);
spin_unlock(&bp->phy_lock);
}
+ if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_TIMER_ABORT))
+ bnx2_set_remote_link(bp);
+
}
static void
@@ -2297,6 +2578,7 @@ bnx2_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct bnx2 *bp = netdev_priv(dev);
+ struct status_block *sblk = bp->status_blk;
/* When using INTx, it is possible for the interrupt to arrive
* at the CPU before the status block posted prior to the
@@ -2304,7 +2586,7 @@ bnx2_interrupt(int irq, void *dev_instance)
* When using MSI, the MSI message will always complete after
* the status block write.
*/
- if ((bp->status_blk->status_idx == bp->last_status_idx) &&
+ if ((sblk->status_idx == bp->last_status_idx) &&
(REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
return IRQ_NONE;
@@ -2313,16 +2595,25 @@ bnx2_interrupt(int irq, void *dev_instance)
BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
+ /* Read back to deassert IRQ immediately to avoid too many
+ * spurious interrupts.
+ */
+ REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
+
/* Return here if interrupt is shared and is disabled. */
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;
- netif_rx_schedule(dev);
+ if (netif_rx_schedule_prep(dev)) {
+ bp->last_status_idx = sblk->status_idx;
+ __netif_rx_schedule(dev);
+ }
return IRQ_HANDLED;
}
-#define STATUS_ATTN_EVENTS STATUS_ATTN_BITS_LINK_STATE
+#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
+ STATUS_ATTN_BITS_TIMER_ABORT)
static inline int
bnx2_has_work(struct bnx2 *bp)
@@ -3009,7 +3300,7 @@ bnx2_enable_nvram_write(struct bnx2 *bp)
val = REG_RD(bp, BNX2_MISC_CFG);
REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
- if (!bp->flash_info->buffered) {
+ if (bp->flash_info->flags & BNX2_NV_WREN) {
int j;
REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
@@ -3069,7 +3360,7 @@ bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
u32 cmd;
int j;
- if (bp->flash_info->buffered)
+ if (bp->flash_info->flags & BNX2_NV_BUFFERED)
/* Buffered flash, no erase needed */
return 0;
@@ -3112,8 +3403,8 @@ bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
/* Build the command word. */
cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
- /* Calculate an offset of a buffered flash. */
- if (bp->flash_info->buffered) {
+ /* Calculate an offset of a buffered flash, not needed for 5709. */
+ if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
offset = ((offset / bp->flash_info->page_size) <<
bp->flash_info->page_bits) +
(offset % bp->flash_info->page_size);
@@ -3159,8 +3450,8 @@ bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
/* Build the command word. */
cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
- /* Calculate an offset of a buffered flash. */
- if (bp->flash_info->buffered) {
+ /* Calculate an offset of a buffered flash, not needed for 5709. */
+ if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
offset = ((offset / bp->flash_info->page_size) <<
bp->flash_info->page_bits) +
(offset % bp->flash_info->page_size);
@@ -3198,15 +3489,19 @@ static int
bnx2_init_nvram(struct bnx2 *bp)
{
u32 val;
- int j, entry_count, rc;
+ int j, entry_count, rc = 0;
struct flash_spec *flash;
+ if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+ bp->flash_info = &flash_5709;
+ goto get_flash_size;
+ }
+
/* Determine the selected interface. */
val = REG_RD(bp, BNX2_NVM_CFG1);
entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
- rc = 0;
if (val & 0x40000000) {
/* Flash interface has been reconfigured */
@@ -3262,6 +3557,7 @@ bnx2_init_nvram(struct bnx2 *bp)
return -ENODEV;
}
+get_flash_size:
val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
if (val)
@@ -3426,7 +3722,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
buf = align_buf;
}
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
flash_buffer = kmalloc(264, GFP_KERNEL);
if (flash_buffer == NULL) {
rc = -ENOMEM;
@@ -3459,7 +3755,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
bnx2_enable_nvram_access(bp);
cmd_flags = BNX2_NVM_COMMAND_FIRST;
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
int j;
/* Read the whole page into the buffer
@@ -3487,7 +3783,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
/* Loop to write back the buffer data from page_start to
* data_start */
i = 0;
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
/* Erase the page */
if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
goto nvram_write_end;
@@ -3511,7 +3807,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
/* Loop to write the new data from data_start to data_end */
for (addr = data_start; addr < data_end; addr += 4, i += 4) {
if ((addr == page_end - 4) ||
- ((bp->flash_info->buffered) &&
+ ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
(addr == data_end - 4))) {
cmd_flags |= BNX2_NVM_COMMAND_LAST;
@@ -3528,7 +3824,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
/* Loop to write back the buffer data from data_end
* to page_end */
- if (bp->flash_info->buffered == 0) {
+ if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
for (addr = data_end; addr < page_end;
addr += 4, i += 4) {
@@ -3562,6 +3858,36 @@ nvram_write_end:
return rc;
}
+static void
+bnx2_init_remote_phy(struct bnx2 *bp)
+{
+ u32 val;
+
+ bp->phy_flags &= ~REMOTE_PHY_CAP_FLAG;
+ if (!(bp->phy_flags & PHY_SERDES_FLAG))
+ return;
+
+ val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
+ if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
+ return;
+
+ if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
+ if (netif_running(bp->dev)) {
+ val = BNX2_DRV_ACK_CAP_SIGNATURE |
+ BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
+ REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
+ val);
+ }
+ bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
+
+ val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
+ if (val & BNX2_LINK_STATUS_SERDES_LINK)
+ bp->phy_port = PORT_FIBRE;
+ else
+ bp->phy_port = PORT_TP;
+ }
+}
+
static int
bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
{
@@ -3642,6 +3968,12 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
if (rc)
return rc;
+ spin_lock_bh(&bp->phy_lock);
+ bnx2_init_remote_phy(bp);
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ bnx2_set_default_remote_link(bp);
+ spin_unlock_bh(&bp->phy_lock);
+
if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
/* Adjust the voltage regular to two steps lower. The default
* of this register is 0x0000000e. */
@@ -3791,7 +4123,7 @@ bnx2_init_chip(struct bnx2 *bp)
if (CHIP_NUM(bp) == CHIP_NUM_5708)
REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
else
- REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+ REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
if (CHIP_ID(bp) == CHIP_ID_5706_A1)
@@ -3811,10 +4143,6 @@ bnx2_init_chip(struct bnx2 *bp)
REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
- if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
- BNX2_PORT_FEATURE_ASF_ENABLED)
- bp->flags |= ASF_ENABLE_FLAG;
-
/* Initialize the receive filter. */
bnx2_set_rx_mode(bp->dev);
@@ -3826,7 +4154,7 @@ bnx2_init_chip(struct bnx2 *bp)
rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
0);
- REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 0x5ffffff);
+ REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
udelay(20);
@@ -4069,8 +4397,8 @@ bnx2_init_nic(struct bnx2 *bp)
spin_lock_bh(&bp->phy_lock);
bnx2_init_phy(bp);
- spin_unlock_bh(&bp->phy_lock);
bnx2_set_link(bp);
+ spin_unlock_bh(&bp->phy_lock);
return 0;
}
@@ -4600,6 +4928,9 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
static void
bnx2_5708_serdes_timer(struct bnx2 *bp)
{
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return;
+
if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) {
bp->serdes_an_pending = 0;
return;
@@ -4631,7 +4962,6 @@ static void
bnx2_timer(unsigned long data)
{
struct bnx2 *bp = (struct bnx2 *) data;
- u32 msg;
if (!netif_running(bp->dev))
return;
@@ -4639,8 +4969,7 @@ bnx2_timer(unsigned long data)
if (atomic_read(&bp->intr_sem) != 0)
goto bnx2_restart_timer;
- msg = (u32) ++bp->fw_drv_pulse_wr_seq;
- REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg);
+ bnx2_send_heart_beat(bp);
bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
@@ -5083,17 +5412,25 @@ static int
bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnx2 *bp = netdev_priv(dev);
+ int support_serdes = 0, support_copper = 0;
cmd->supported = SUPPORTED_Autoneg;
- if (bp->phy_flags & PHY_SERDES_FLAG) {
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+ support_serdes = 1;
+ support_copper = 1;
+ } else if (bp->phy_port == PORT_FIBRE)
+ support_serdes = 1;
+ else
+ support_copper = 1;
+
+ if (support_serdes) {
cmd->supported |= SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE;
if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
cmd->supported |= SUPPORTED_2500baseX_Full;
- cmd->port = PORT_FIBRE;
}
- else {
+ if (support_copper) {
cmd->supported |= SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
@@ -5101,9 +5438,10 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_1000baseT_Full |
SUPPORTED_TP;
- cmd->port = PORT_TP;
}
+ spin_lock_bh(&bp->phy_lock);
+ cmd->port = bp->phy_port;
cmd->advertising = bp->advertising;
if (bp->autoneg & AUTONEG_SPEED) {
@@ -5121,6 +5459,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->speed = -1;
cmd->duplex = -1;
}
+ spin_unlock_bh(&bp->phy_lock);
cmd->transceiver = XCVR_INTERNAL;
cmd->phy_address = bp->phy_addr;
@@ -5136,6 +5475,15 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
u8 req_duplex = bp->req_duplex;
u16 req_line_speed = bp->req_line_speed;
u32 advertising = bp->advertising;
+ int err = -EINVAL;
+
+ spin_lock_bh(&bp->phy_lock);
+
+ if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
+ goto err_out_unlock;
+
+ if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG))
+ goto err_out_unlock;
if (cmd->autoneg == AUTONEG_ENABLE) {
autoneg |= AUTONEG_SPEED;
@@ -5148,44 +5496,41 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
(cmd->advertising == ADVERTISED_100baseT_Half) ||
(cmd->advertising == ADVERTISED_100baseT_Full)) {
- if (bp->phy_flags & PHY_SERDES_FLAG)
- return -EINVAL;
+ if (cmd->port == PORT_FIBRE)
+ goto err_out_unlock;
advertising = cmd->advertising;
} else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
- if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
- return -EINVAL;
- } else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
+ if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ||
+ (cmd->port == PORT_TP))
+ goto err_out_unlock;
+ } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
advertising = cmd->advertising;
- }
- else if (cmd->advertising == ADVERTISED_1000baseT_Half) {
- return -EINVAL;
- }
+ else if (cmd->advertising == ADVERTISED_1000baseT_Half)
+ goto err_out_unlock;
else {
- if (bp->phy_flags & PHY_SERDES_FLAG) {
+ if (cmd->port == PORT_FIBRE)
advertising = ETHTOOL_ALL_FIBRE_SPEED;
- }
- else {
+ else
advertising = ETHTOOL_ALL_COPPER_SPEED;
- }
}
advertising |= ADVERTISED_Autoneg;
}
else {
- if (bp->phy_flags & PHY_SERDES_FLAG) {
+ if (cmd->port == PORT_FIBRE) {
if ((cmd->speed != SPEED_1000 &&
cmd->speed != SPEED_2500) ||
(cmd->duplex != DUPLEX_FULL))
- return -EINVAL;
+ goto err_out_unlock;
if (cmd->speed == SPEED_2500 &&
!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
- return -EINVAL;
- }
- else if (cmd->speed == SPEED_1000) {
- return -EINVAL;
+ goto err_out_unlock;
}
+ else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
+ goto err_out_unlock;
+
autoneg &= ~AUTONEG_SPEED;
req_line_speed = cmd->speed;
req_duplex = cmd->duplex;
@@ -5197,13 +5542,12 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
bp->req_line_speed = req_line_speed;
bp->req_duplex = req_duplex;
- spin_lock_bh(&bp->phy_lock);
-
- bnx2_setup_phy(bp);
+ err = bnx2_setup_phy(bp, cmd->port);
+err_out_unlock:
spin_unlock_bh(&bp->phy_lock);
- return 0;
+ return err;
}
static void
@@ -5214,11 +5558,7 @@ bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
strcpy(info->driver, DRV_MODULE_NAME);
strcpy(info->version, DRV_MODULE_VERSION);
strcpy(info->bus_info, pci_name(bp->pdev));
- info->fw_version[0] = ((bp->fw_ver & 0xff000000) >> 24) + '0';
- info->fw_version[2] = ((bp->fw_ver & 0xff0000) >> 16) + '0';
- info->fw_version[4] = ((bp->fw_ver & 0xff00) >> 8) + '0';
- info->fw_version[1] = info->fw_version[3] = '.';
- info->fw_version[5] = 0;
+ strcpy(info->fw_version, bp->fw_version);
}
#define BNX2_REGDUMP_LEN (32 * 1024)
@@ -5330,6 +5670,14 @@ bnx2_nway_reset(struct net_device *dev)
spin_lock_bh(&bp->phy_lock);
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+ int rc;
+
+ rc = bnx2_setup_remote_phy(bp, bp->phy_port);
+ spin_unlock_bh(&bp->phy_lock);
+ return rc;
+ }
+
/* Force a link down visible on the other side */
if (bp->phy_flags & PHY_SERDES_FLAG) {
bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
@@ -5450,8 +5798,9 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
bp->stats_ticks = USEC_PER_SEC;
}
- if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
- bp->stats_ticks &= 0xffff00;
+ if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
+ bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
+ bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
if (netif_running(bp->dev)) {
bnx2_netif_stop(bp);
@@ -5543,7 +5892,7 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
spin_lock_bh(&bp->phy_lock);
- bnx2_setup_phy(bp);
+ bnx2_setup_phy(bp, bp->phy_port);
spin_unlock_bh(&bp->phy_lock);
@@ -5882,7 +6231,7 @@ bnx2_set_tx_csum(struct net_device *dev, u32 data)
struct bnx2 *bp = netdev_priv(dev);
if (CHIP_NUM(bp) == CHIP_NUM_5709)
- return (ethtool_op_set_tx_hw_csum(dev, data));
+ return (ethtool_op_set_tx_ipv6_csum(dev, data));
else
return (ethtool_op_set_tx_csum(dev, data));
}
@@ -5939,6 +6288,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG: {
u32 mii_regval;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return -EOPNOTSUPP;
+
if (!netif_running(dev))
return -EAGAIN;
@@ -5955,6 +6307,9 @@ bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+ return -EOPNOTSUPP;
+
if (!netif_running(dev))
return -EAGAIN;
@@ -6116,7 +6471,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
{
struct bnx2 *bp;
unsigned long mem_len;
- int rc;
+ int rc, i, j;
u32 reg;
u64 dma_mask, persist_dma_mask;
@@ -6273,7 +6628,47 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
goto err_out_unmap;
}
- bp->fw_ver = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
+ reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
+ for (i = 0, j = 0; i < 3; i++) {
+ u8 num, k, skip0;
+
+ num = (u8) (reg >> (24 - (i * 8)));
+ for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
+ if (num >= k || !skip0 || k == 1) {
+ bp->fw_version[j++] = (num / k) + '0';
+ skip0 = 0;
+ }
+ }
+ if (i != 2)
+ bp->fw_version[j++] = '.';
+ }
+ if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
+ BNX2_PORT_FEATURE_ASF_ENABLED) {
+ bp->flags |= ASF_ENABLE_FLAG;
+
+ for (i = 0; i < 30; i++) {
+ reg = REG_RD_IND(bp, bp->shmem_base +
+ BNX2_BC_STATE_CONDITION);
+ if (reg & BNX2_CONDITION_MFW_RUN_MASK)
+ break;
+ msleep(10);
+ }
+ }
+ reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
+ reg &= BNX2_CONDITION_MFW_RUN_MASK;
+ if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
+ reg != BNX2_CONDITION_MFW_RUN_NONE) {
+ int i;
+ u32 addr = REG_RD_IND(bp, bp->shmem_base + BNX2_MFW_VER_PTR);
+
+ bp->fw_version[j++] = ' ';
+ for (i = 0; i < 3; i++) {
+ reg = REG_RD_IND(bp, addr + i * 4);
+ reg = swab32(reg);
+ memcpy(&bp->fw_version[j], &reg, 4);
+ j += 4;
+ }
+ }
reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
bp->mac_addr[0] = (u8) (reg >> 8);
@@ -6302,7 +6697,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->rx_ticks_int = 18;
bp->rx_ticks = 18;
- bp->stats_ticks = 1000000 & 0xffff00;
+ bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
bp->timer_interval = HZ;
bp->current_interval = HZ;
@@ -6315,7 +6710,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
bp->phy_flags |= PHY_SERDES_FLAG;
+ bp->phy_port = PORT_TP;
if (bp->phy_flags & PHY_SERDES_FLAG) {
+ bp->phy_port = PORT_FIBRE;
bp->flags |= NO_WOL_FLAG;
if (CHIP_NUM(bp) != CHIP_NUM_5706) {
bp->phy_addr = 2;
@@ -6324,6 +6721,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
}
+ bnx2_init_remote_phy(bp);
+
} else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
CHIP_NUM(bp) == CHIP_NUM_5708)
bp->phy_flags |= PHY_CRC_FIX_FLAG;
@@ -6363,10 +6762,9 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_8132_BRIDGE,
amd_8132))) {
- u8 rev;
- pci_read_config_byte(amd_8132, PCI_REVISION_ID, &rev);
- if (rev >= 0x10 && rev <= 0x13) {
+ if (amd_8132->revision >= 0x10 &&
+ amd_8132->revision <= 0x13) {
disable_msi = 1;
pci_dev_put(amd_8132);
break;
@@ -6374,23 +6772,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
}
}
- bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
- bp->req_line_speed = 0;
- if (bp->phy_flags & PHY_SERDES_FLAG) {
- bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
-
- reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
- reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
- if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
- bp->autoneg = 0;
- bp->req_line_speed = bp->line_speed = SPEED_1000;
- bp->req_duplex = DUPLEX_FULL;
- }
- }
- else {
- bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
- }
-
+ bnx2_set_default_link(bp);
bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
init_timer(&bp->timer);
@@ -6490,10 +6872,10 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(dev->perm_addr, bp->mac_addr, 6);
bp->name = board_info[ent->driver_data].name;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
if (CHIP_NUM(bp) == CHIP_NUM_5709)
- dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
- else
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ dev->features |= NETIF_F_IPV6_CSUM;
+
#ifdef BCM_VLAN
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 49a5de253b17..102adfe1e923 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6338,6 +6338,8 @@ struct l2_fhdr {
#define RX_COPY_THRESH 92
+#define BNX2_MISC_ENABLE_DEFAULT 0x7ffffff
+
#define DMA_READ_CHANS 5
#define DMA_WRITE_CHANS 3
@@ -6431,6 +6433,11 @@ struct sw_bd {
#define ST_MICRO_FLASH_PAGE_SIZE 256
#define ST_MICRO_FLASH_BASE_TOTAL_SIZE 65536
+#define BCM5709_FLASH_PAGE_BITS 8
+#define BCM5709_FLASH_PHY_PAGE_SIZE (1 << BCM5709_FLASH_PAGE_BITS)
+#define BCM5709_FLASH_BYTE_ADDR_MASK (BCM5709_FLASH_PHY_PAGE_SIZE-1)
+#define BCM5709_FLASH_PAGE_SIZE 256
+
#define NVRAM_TIMEOUT_COUNT 30000
@@ -6447,7 +6454,10 @@ struct flash_spec {
u32 config2;
u32 config3;
u32 write1;
- u32 buffered;
+ u32 flags;
+#define BNX2_NV_BUFFERED 0x00000001
+#define BNX2_NV_TRANSLATE 0x00000002
+#define BNX2_NV_WREN 0x00000004
u32 page_bits;
u32 page_size;
u32 addr_mask;
@@ -6537,6 +6547,7 @@ struct bnx2 {
#define PHY_INT_MODE_AUTO_POLLING_FLAG 0x100
#define PHY_INT_MODE_LINK_READY_FLAG 0x200
#define PHY_DIS_EARLY_DAC_FLAG 0x400
+#define REMOTE_PHY_CAP_FLAG 0x800
u32 mii_bmcr;
u32 mii_bmsr;
@@ -6625,6 +6636,7 @@ struct bnx2 {
u16 req_line_speed;
u8 req_duplex;
+ u8 phy_port;
u8 link_up;
u16 line_speed;
@@ -6656,7 +6668,7 @@ struct bnx2 {
u32 shmem_base;
- u32 fw_ver;
+ char fw_version[32];
int pm_cap;
int pcix_cap;
@@ -6770,7 +6782,7 @@ struct fw_info {
* the firmware has timed out, the driver will assume there is no firmware
* running and there won't be any firmware-driver synchronization during a
* driver reset. */
-#define FW_ACK_TIME_OUT_MS 100
+#define FW_ACK_TIME_OUT_MS 1000
#define BNX2_DRV_RESET_SIGNATURE 0x00000000
@@ -6788,6 +6800,7 @@ struct fw_info {
#define BNX2_DRV_MSG_CODE_DIAG 0x07000000
#define BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL 0x09000000
#define BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN 0x0b000000
+#define BNX2_DRV_MSG_CODE_CMD_SET_LINK 0x10000000
#define BNX2_DRV_MSG_DATA 0x00ff0000
#define BNX2_DRV_MSG_DATA_WAIT0 0x00010000
@@ -6836,6 +6849,7 @@ struct fw_info {
#define BNX2_LINK_STATUS_SERDES_LINK (1<<20)
#define BNX2_LINK_STATUS_PARTNER_AD_2500FULL (1<<21)
#define BNX2_LINK_STATUS_PARTNER_AD_2500HALF (1<<22)
+#define BNX2_LINK_STATUS_HEART_BEAT_EXPIRED (1<<31)
#define BNX2_DRV_PULSE_MB 0x00000010
#define BNX2_DRV_PULSE_SEQ_MASK 0x00007fff
@@ -6845,6 +6859,30 @@ struct fw_info {
* This is used for debugging. */
#define BNX2_DRV_MSG_DATA_PULSE_CODE_ALWAYS_ALIVE 0x00080000
+#define BNX2_DRV_MB_ARG0 0x00000014
+#define BNX2_NETLINK_SET_LINK_SPEED_10HALF (1<<0)
+#define BNX2_NETLINK_SET_LINK_SPEED_10FULL (1<<1)
+#define BNX2_NETLINK_SET_LINK_SPEED_10 \
+ (BNX2_NETLINK_SET_LINK_SPEED_10HALF | \
+ BNX2_NETLINK_SET_LINK_SPEED_10FULL)
+#define BNX2_NETLINK_SET_LINK_SPEED_100HALF (1<<2)
+#define BNX2_NETLINK_SET_LINK_SPEED_100FULL (1<<3)
+#define BNX2_NETLINK_SET_LINK_SPEED_100 \
+ (BNX2_NETLINK_SET_LINK_SPEED_100HALF | \
+ BNX2_NETLINK_SET_LINK_SPEED_100FULL)
+#define BNX2_NETLINK_SET_LINK_SPEED_1GHALF (1<<4)
+#define BNX2_NETLINK_SET_LINK_SPEED_1GFULL (1<<5)
+#define BNX2_NETLINK_SET_LINK_SPEED_2G5HALF (1<<6)
+#define BNX2_NETLINK_SET_LINK_SPEED_2G5FULL (1<<7)
+#define BNX2_NETLINK_SET_LINK_SPEED_10GHALF (1<<8)
+#define BNX2_NETLINK_SET_LINK_SPEED_10GFULL (1<<9)
+#define BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG (1<<10)
+#define BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE (1<<11)
+#define BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE (1<<12)
+#define BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE (1<<13)
+#define BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED (1<<14)
+#define BNX2_NETLINK_SET_LINK_PHY_RESET (1<<15)
+
#define BNX2_DEV_INFO_SIGNATURE 0x00000020
#define BNX2_DEV_INFO_SIGNATURE_MAGIC 0x44564900
#define BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK 0xffffff00
@@ -7006,6 +7044,8 @@ struct fw_info {
#define BNX2_PORT_FEATURE_MBA_VLAN_TAG_MASK 0xffff
#define BNX2_PORT_FEATURE_MBA_VLAN_ENABLE 0x10000
+#define BNX2_MFW_VER_PTR 0x00000014c
+
#define BNX2_BC_STATE_RESET_TYPE 0x000001c0
#define BNX2_BC_STATE_RESET_TYPE_SIG 0x00005254
#define BNX2_BC_STATE_RESET_TYPE_SIG_MASK 0x0000ffff
@@ -7059,12 +7099,42 @@ struct fw_info {
#define BNX2_BC_STATE_ERR_NO_RXP (BNX2_BC_STATE_SIGN | 0x0600)
#define BNX2_BC_STATE_ERR_TOO_MANY_RBUF (BNX2_BC_STATE_SIGN | 0x0700)
+#define BNX2_BC_STATE_CONDITION 0x000001c8
+#define BNX2_CONDITION_MFW_RUN_UNKNOWN 0x00000000
+#define BNX2_CONDITION_MFW_RUN_IPMI 0x00002000
+#define BNX2_CONDITION_MFW_RUN_UMP 0x00004000
+#define BNX2_CONDITION_MFW_RUN_NCSI 0x00006000
+#define BNX2_CONDITION_MFW_RUN_NONE 0x0000e000
+#define BNX2_CONDITION_MFW_RUN_MASK 0x0000e000
+
#define BNX2_BC_STATE_DEBUG_CMD 0x1dc
#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE 0x42440000
#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE_MASK 0xffff0000
#define BNX2_BC_STATE_BC_DBG_CMD_LOOP_CNT_MASK 0xffff
#define BNX2_BC_STATE_BC_DBG_CMD_LOOP_INFINITE 0xffff
+#define BNX2_FW_EVT_CODE_MB 0x354
+#define BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT 0x00000000
+#define BNX2_FW_EVT_CODE_LINK_EVENT 0x00000001
+
+#define BNX2_DRV_ACK_CAP_MB 0x364
+#define BNX2_DRV_ACK_CAP_SIGNATURE 0x35450000
+#define BNX2_CAPABILITY_SIGNATURE_MASK 0xFFFF0000
+
+#define BNX2_FW_CAP_MB 0x368
+#define BNX2_FW_CAP_SIGNATURE 0xaa550000
+#define BNX2_FW_ACK_DRV_SIGNATURE 0x52500000
+#define BNX2_FW_CAP_SIGNATURE_MASK 0xffff0000
+#define BNX2_FW_CAP_REMOTE_PHY_CAPABLE 0x00000001
+#define BNX2_FW_CAP_REMOTE_PHY_PRESENT 0x00000002
+
+#define BNX2_RPHY_SIGNATURE 0x36c
+#define BNX2_RPHY_LOAD_SIGNATURE 0x5a5a5a5a
+
+#define BNX2_RPHY_FLAGS 0x370
+#define BNX2_RPHY_SERDES_LINK 0x374
+#define BNX2_RPHY_COPPER_LINK 0x378
+
#define HOST_VIEW_SHMEM_BASE 0x167c00
#endif
diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
index 7845eaf6f29f..202d4a4ef751 100644
--- a/drivers/net/bsd_comp.c
+++ b/drivers/net/bsd_comp.c
@@ -395,14 +395,13 @@ static void *bsd_alloc (unsigned char *options, int opt_len, int decomp)
* Allocate the main control structure for this instance.
*/
maxmaxcode = MAXCODE(bits);
- db = kmalloc(sizeof (struct bsd_db),
+ db = kzalloc(sizeof (struct bsd_db),
GFP_KERNEL);
if (!db)
{
return NULL;
}
- memset (db, 0, sizeof(struct bsd_db));
/*
* Allocate space for the dictionary. This may be more than one page in
* length.
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 59b9943b077d..f6e4030c73d1 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -3422,21 +3422,19 @@ done:
static void cas_check_pci_invariants(struct cas *cp)
{
struct pci_dev *pdev = cp->pdev;
- u8 rev;
cp->cas_flags = 0;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
(pdev->device == PCI_DEVICE_ID_SUN_CASSINI)) {
- if (rev >= CAS_ID_REVPLUS)
+ if (pdev->revision >= CAS_ID_REVPLUS)
cp->cas_flags |= CAS_FLAG_REG_PLUS;
- if (rev < CAS_ID_REVPLUS02u)
+ if (pdev->revision < CAS_ID_REVPLUS02u)
cp->cas_flags |= CAS_FLAG_TARGET_ABORT;
/* Original Cassini supports HW CSUM, but it's not
* enabled by default as it can trigger TX hangs.
*/
- if (rev < CAS_ID_REV2)
+ if (pdev->revision < CAS_ID_REV2)
cp->cas_flags |= CAS_FLAG_NO_HW_CSUM;
} else {
/* Only sun has original cassini chips. */
@@ -4919,13 +4917,13 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_cmd &= ~PCI_COMMAND_SERR;
pci_cmd |= PCI_COMMAND_PARITY;
pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
- if (pci_set_mwi(pdev))
+ if (pci_try_set_mwi(pdev))
printk(KERN_WARNING PFX "Could not enable MWI for %s\n",
pci_name(pdev));
/*
* On some architectures, the default cache line size set
- * by pci_set_mwi reduces perforamnce. We have to increase
+ * by pci_try_set_mwi reduces perforamnce. We have to increase
* it for this case. To start, we'll print some configuration
* data.
*/
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 8eddd23a3a51..eb508bf8022a 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -39,6 +39,6 @@
/* Firmware version */
#define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 1
+#define FW_VERSION_MINOR 3
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 74ec64a1625d..04e3710c9082 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -250,7 +250,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
np->an_enable = 1;
mii_set_media (dev);
}
- pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
err = register_netdev (dev);
if (err)
@@ -866,9 +865,9 @@ receive_packet (struct net_device *dev)
PCI_DMA_FROMDEVICE);
/* 16 byte align the IP header */
skb_reserve (skb, 2);
- eth_copy_and_sum (skb,
+ skb_copy_to_linear_data (skb,
np->rx_skbuff[entry]->data,
- pkt_len, 0);
+ pkt_len);
skb_put (skb, pkt_len);
pci_dma_sync_single_for_device(np->pdev,
desc->fraginfo &
@@ -879,7 +878,7 @@ receive_packet (struct net_device *dev)
skb->protocol = eth_type_trans (skb, dev);
#if 0
/* Checksum done by hw, but csum value unavailable. */
- if (np->pci_rev_id >= 0x0c &&
+ if (np->pdev->pci_rev_id >= 0x0c &&
!(frame_status & (TCPError | UDPError | IPError))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 814c449c359f..e443065a452e 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -668,7 +668,6 @@ struct netdev_private {
unsigned int rx_flow:1; /* Rx flow control enable */
unsigned int phy_media:1; /* 1: fiber, 0: copper */
unsigned int link_status:1; /* Current link status */
- unsigned char pci_rev_id; /* PCI revision ID */
struct netdev_desc *last_tx; /* Last Tx descriptor used. */
unsigned long cur_rx, old_rx; /* Producer/consumer ring indices */
unsigned long cur_tx, old_tx;
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 264fa0e2e075..c3de81bf090a 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -104,6 +104,18 @@
#define PRINTK(args...) printk(KERN_DEBUG args)
#endif
+#ifdef CONFIG_BLACKFIN
+#define readsb insb
+#define readsw insw
+#define readsl insl
+#define writesb outsb
+#define writesw outsw
+#define writesl outsl
+#define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQF_TRIGGER_HIGH)
+#else
+#define DM9000_IRQ_FLAGS IRQF_SHARED
+#endif
+
/*
* Transmit timeout, default 5 seconds.
*/
@@ -431,6 +443,9 @@ dm9000_probe(struct platform_device *pdev)
db->io_addr = (void __iomem *)base;
db->io_data = (void __iomem *)(base + 4);
+ /* ensure at least we have a default set of IO routines */
+ dm9000_set_io(db, 2);
+
} else {
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -614,7 +629,7 @@ dm9000_open(struct net_device *dev)
PRINTK2("entering dm9000_open\n");
- if (request_irq(dev->irq, &dm9000_interrupt, IRQF_SHARED, dev->name, dev))
+ if (request_irq(dev->irq, &dm9000_interrupt, DM9000_IRQ_FLAGS, dev->name, dev))
return -EAGAIN;
/* Initialize DM9000 board */
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 60673bc292c0..756a6bcb038d 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -34,11 +34,12 @@
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
+#include <linux/rtnetlink.h>
+#include <net/rtnetlink.h>
static int numdummies = 1;
static int dummy_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *dummy_get_stats(struct net_device *dev);
static int dummy_set_address(struct net_device *dev, void *p)
{
@@ -56,13 +57,13 @@ static void set_multicast_list(struct net_device *dev)
{
}
-static void __init dummy_setup(struct net_device *dev)
+static void dummy_setup(struct net_device *dev)
{
/* Initialize the device structure. */
- dev->get_stats = dummy_get_stats;
dev->hard_start_xmit = dummy_xmit;
dev->set_multicast_list = set_multicast_list;
dev->set_mac_address = dummy_set_address;
+ dev->destructor = free_netdev;
/* Fill in device structure with ethernet-generic values. */
ether_setup(dev);
@@ -76,77 +77,80 @@ static void __init dummy_setup(struct net_device *dev)
static int dummy_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct net_device_stats *stats = netdev_priv(dev);
-
- stats->tx_packets++;
- stats->tx_bytes+=skb->len;
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
dev_kfree_skb(skb);
return 0;
}
-static struct net_device_stats *dummy_get_stats(struct net_device *dev)
+static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
{
- return netdev_priv(dev);
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+ return 0;
}
-static struct net_device **dummies;
+static struct rtnl_link_ops dummy_link_ops __read_mostly = {
+ .kind = "dummy",
+ .setup = dummy_setup,
+ .validate = dummy_validate,
+};
/* Number of dummy devices to be set up by this module. */
module_param(numdummies, int, 0);
MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
-static int __init dummy_init_one(int index)
+static int __init dummy_init_one(void)
{
struct net_device *dev_dummy;
int err;
- dev_dummy = alloc_netdev(sizeof(struct net_device_stats),
- "dummy%d", dummy_setup);
-
+ dev_dummy = alloc_netdev(0, "dummy%d", dummy_setup);
if (!dev_dummy)
return -ENOMEM;
- if ((err = register_netdev(dev_dummy))) {
- free_netdev(dev_dummy);
- dev_dummy = NULL;
- } else {
- dummies[index] = dev_dummy;
- }
+ err = dev_alloc_name(dev_dummy, dev_dummy->name);
+ if (err < 0)
+ goto err;
- return err;
-}
+ dev_dummy->rtnl_link_ops = &dummy_link_ops;
+ err = register_netdevice(dev_dummy);
+ if (err < 0)
+ goto err;
+ return 0;
-static void dummy_free_one(int index)
-{
- unregister_netdev(dummies[index]);
- free_netdev(dummies[index]);
+err:
+ free_netdev(dev_dummy);
+ return err;
}
static int __init dummy_init_module(void)
{
int i, err = 0;
- dummies = kmalloc(numdummies * sizeof(void *), GFP_KERNEL);
- if (!dummies)
- return -ENOMEM;
+
+ rtnl_lock();
+ err = __rtnl_link_register(&dummy_link_ops);
+
for (i = 0; i < numdummies && !err; i++)
- err = dummy_init_one(i);
- if (err) {
- i--;
- while (--i >= 0)
- dummy_free_one(i);
- }
+ err = dummy_init_one();
+ if (err < 0)
+ __rtnl_link_unregister(&dummy_link_ops);
+ rtnl_unlock();
+
return err;
}
static void __exit dummy_cleanup_module(void)
{
- int i;
- for (i = 0; i < numdummies; i++)
- dummy_free_one(i);
- kfree(dummies);
+ rtnl_link_unregister(&dummy_link_ops);
}
module_init(dummy_init_module);
module_exit(dummy_cleanup_module);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("dummy");
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 74ea6373c7cd..6b6401e9304e 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -583,7 +583,6 @@ struct nic {
u32 rx_tco_frames;
u32 rx_over_length_errors;
- u8 rev_id;
u16 leds;
u16 eeprom_wc;
u16 eeprom[256];
@@ -937,9 +936,8 @@ static void e100_get_defaults(struct nic *nic)
struct param_range rfds = { .min = 16, .max = 256, .count = 256 };
struct param_range cbs = { .min = 64, .max = 256, .count = 128 };
- pci_read_config_byte(nic->pdev, PCI_REVISION_ID, &nic->rev_id);
/* MAC type is encoded as rev ID; exception: ICH is treated as 82559 */
- nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->rev_id;
+ nic->mac = (nic->flags & ich) ? mac_82559_D101M : nic->pdev->revision;
if(nic->mac == mac_unknown)
nic->mac = mac_82557_D100_A;
@@ -1279,7 +1277,7 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb
if (nic->flags & ich)
goto noloaducode;
- /* Search for ucode match against h/w rev_id */
+ /* Search for ucode match against h/w revision */
for (opts = ucode_opts; opts->mac; opts++) {
int i;
u32 *ucode = opts->ucode;
@@ -2238,7 +2236,7 @@ static void e100_get_regs(struct net_device *netdev,
u32 *buff = p;
int i;
- regs->version = (1 << 24) | nic->rev_id;
+ regs->version = (1 << 24) | nic->pdev->revision;
buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
ioread8(&nic->csr->scb.cmd_lo) << 16 |
ioread16(&nic->csr->scb.status);
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index cf8af928a69c..f48b659e0c2b 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1266,8 +1266,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
hw->device_id = pdev->device;
hw->subsystem_vendor_id = pdev->subsystem_vendor;
hw->subsystem_id = pdev->subsystem_device;
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+ hw->revision_id = pdev->revision;
pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 9800341956a2..3c54014acece 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1801,7 +1801,7 @@ speedo_rx(struct net_device *dev)
#if 1 || USE_IP_CSUM
/* Packet is in one chunk -- we can copy + cksum. */
- eth_copy_and_sum(skb, sp->rx_skbuff[entry]->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb, sp->rx_skbuff[entry]->data, pkt_len);
skb_put(skb, pkt_len);
#else
skb_copy_from_linear_data(sp->rx_skbuff[entry],
@@ -2292,10 +2292,15 @@ static int eepro100_resume(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata (pdev);
struct speedo_private *sp = netdev_priv(dev);
void __iomem *ioaddr = sp->regs;
+ int rc;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
pci_set_master(pdev);
if (!netif_running(dev))
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index f03f070451de..489c8b260dd8 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,13 +39,13 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0067"
+#define DRV_VERSION "EHEA_0071"
-/* EHEA capability flags */
+/* eHEA capability flags */
#define DLPAR_PORT_ADD_REM 1
-#define DLPAR_MEM_ADD 2
-#define DLPAR_MEM_REM 4
-#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM)
+#define DLPAR_MEM_ADD 2
+#define DLPAR_MEM_REM 4
+#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM)
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -113,6 +113,8 @@
/* Memory Regions */
#define EHEA_MR_ACC_CTRL 0x00800000
+#define EHEA_BUSMAP_START 0x8000000000000000ULL
+
#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
/* utility functions */
@@ -186,6 +188,12 @@ struct h_epas {
set to 0 if unused */
};
+struct ehea_busmap {
+ unsigned int entries; /* total number of entries */
+ unsigned int valid_sections; /* number of valid sections */
+ u64 *vaddr;
+};
+
struct ehea_qp;
struct ehea_cq;
struct ehea_eq;
@@ -382,6 +390,8 @@ struct ehea_adapter {
struct ehea_mr mr;
u32 pd; /* protection domain */
u64 max_mc_mac; /* max number of multicast mac addresses */
+ int active_ports;
+ struct list_head list;
};
@@ -431,6 +441,9 @@ struct port_res_cfg {
int max_entries_rq3;
};
+enum ehea_flag_bits {
+ __EHEA_STOP_XFER
+};
void ehea_set_ethtool_ops(struct net_device *netdev);
int ehea_sense_port_attr(struct ehea_port *port);
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 383144db4d18..4c70a9301c1b 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -79,6 +79,11 @@ MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
static int port_name_cnt = 0;
+static LIST_HEAD(adapter_list);
+u64 ehea_driver_flags = 0;
+struct workqueue_struct *ehea_driver_wq;
+struct work_struct ehea_rereg_mr_task;
+
static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
const struct of_device_id *id);
@@ -238,13 +243,17 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
| EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
- rwqe->sg_list[0].vaddr = (u64)skb->data;
+ rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
rwqe->sg_list[0].len = packet_size;
rwqe->data_segments = 1;
index++;
index &= max_index_mask;
+
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
+ goto out;
}
+
q_skba->index = index;
/* Ring doorbell */
@@ -253,7 +262,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr,
ehea_update_rq2a(pr->qp, i);
else
ehea_update_rq3a(pr->qp, i);
-
+out:
return ret;
}
@@ -457,6 +466,8 @@ static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
cqe->vlan_tag);
else
netif_receive_skb(skb);
+
+ dev->last_rx = jiffies;
} else {
pr->p_stats.poll_receive_errors++;
port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -1321,7 +1332,7 @@ static void write_swqe2_TSO(struct sk_buff *skb,
sg1entry->len = skb_data_size - headersize;
tmp_addr = (u64)(skb->data + headersize);
- sg1entry->vaddr = tmp_addr;
+ sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++;
}
} else
@@ -1352,7 +1363,7 @@ static void write_swqe2_nonTSO(struct sk_buff *skb,
sg1entry->l_key = lkey;
sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
- sg1entry->vaddr = tmp_addr;
+ sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++;
}
} else {
@@ -1391,7 +1402,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
sg1entry->len = frag->size;
tmp_addr = (u64)(page_address(frag->page)
+ frag->page_offset);
- sg1entry->vaddr = tmp_addr;
+ sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++;
sg1entry_contains_frag_data = 1;
}
@@ -1406,7 +1417,7 @@ static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
tmp_addr = (u64)(page_address(frag->page)
+ frag->page_offset);
- sgentry->vaddr = tmp_addr;
+ sgentry->vaddr = ehea_map_vaddr(tmp_addr);
swqe->descriptors++;
}
}
@@ -1424,7 +1435,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
port->logical_port_id,
reg_type, port->mac_addr, 0, hcallid);
if (hret != H_SUCCESS) {
- ehea_error("reg_dereg_bcmc failed (tagged)");
+ ehea_error("%sregistering bc address failed (tagged)",
+ hcallid == H_REG_BCMC ? "" : "de");
ret = -EIO;
goto out_herr;
}
@@ -1435,7 +1447,8 @@ static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
port->logical_port_id,
reg_type, port->mac_addr, 0, hcallid);
if (hret != H_SUCCESS) {
- ehea_error("reg_dereg_bcmc failed (vlan)");
+ ehea_error("%sregistering bc address failed (vlan)",
+ hcallid == H_REG_BCMC ? "" : "de");
ret = -EIO;
}
out_herr:
@@ -1878,6 +1891,9 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
ehea_dump(swqe, 512, "swqe");
}
+ if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
+ goto out;
+
ehea_post_swqe(pr->qp, swqe);
pr->tx_packets++;
@@ -1892,7 +1908,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
dev->trans_start = jiffies;
spin_unlock(&pr->xmit_lock);
-
+out:
return NETDEV_TX_OK;
}
@@ -2158,7 +2174,6 @@ static int ehea_up(struct net_device *dev)
{
int ret, i;
struct ehea_port *port = netdev_priv(dev);
- u64 mac_addr = 0;
if (port->state == EHEA_PORT_UP)
return 0;
@@ -2177,18 +2192,10 @@ static int ehea_up(struct net_device *dev)
goto out_clean_pr;
}
- ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
- if (ret) {
- ret = -EIO;
- ehea_error("out_clean_pr");
- goto out_clean_pr;
- }
- mac_addr = (*(u64*)dev->dev_addr) >> 16;
-
ret = ehea_reg_interrupts(dev);
if (ret) {
- ehea_error("out_dereg_bc");
- goto out_dereg_bc;
+ ehea_error("reg_interrupts failed. ret:%d", ret);
+ goto out_clean_pr;
}
for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
@@ -2214,12 +2221,12 @@ static int ehea_up(struct net_device *dev)
out_free_irqs:
ehea_free_interrupts(dev);
-out_dereg_bc:
- ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
-
out_clean_pr:
ehea_clean_all_portres(port);
out:
+ if (ret)
+ ehea_info("Failed starting %s. ret=%i", dev->name, ret);
+
return ret;
}
@@ -2258,9 +2265,13 @@ static int ehea_down(struct net_device *dev)
&port->port_res[i].d_netdev->state))
msleep(1);
- ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
- ret = ehea_clean_all_portres(port);
port->state = EHEA_PORT_DOWN;
+
+ ret = ehea_clean_all_portres(port);
+ if (ret)
+ ehea_info("Failed freeing resources for %s. ret=%i",
+ dev->name, ret);
+
return ret;
}
@@ -2292,15 +2303,11 @@ static void ehea_reset_port(struct work_struct *work)
netif_stop_queue(dev);
netif_poll_disable(dev);
- ret = ehea_down(dev);
- if (ret)
- ehea_error("ehea_down failed. not all resources are freed");
+ ehea_down(dev);
ret = ehea_up(dev);
- if (ret) {
- ehea_error("Reset device %s failed: ret=%d", dev->name, ret);
+ if (ret)
goto out;
- }
if (netif_msg_timer(port))
ehea_info("Device %s resetted successfully", dev->name);
@@ -2312,6 +2319,88 @@ out:
return;
}
+static void ehea_rereg_mrs(struct work_struct *work)
+{
+ int ret, i;
+ struct ehea_adapter *adapter;
+
+ ehea_info("LPAR memory enlarged - re-initializing driver");
+
+ list_for_each_entry(adapter, &adapter_list, list)
+ if (adapter->active_ports) {
+ /* Shutdown all ports */
+ for (i = 0; i < EHEA_MAX_PORTS; i++) {
+ struct ehea_port *port = adapter->port[i];
+
+ if (port) {
+ struct net_device *dev = port->netdev;
+
+ if (dev->flags & IFF_UP) {
+ ehea_info("stopping %s",
+ dev->name);
+ down(&port->port_lock);
+ netif_stop_queue(dev);
+ netif_poll_disable(dev);
+ ehea_down(dev);
+ up(&port->port_lock);
+ }
+ }
+ }
+
+ /* Unregister old memory region */
+ ret = ehea_rem_mr(&adapter->mr);
+ if (ret) {
+ ehea_error("unregister MR failed - driver"
+ " inoperable!");
+ goto out;
+ }
+ }
+
+ ehea_destroy_busmap();
+
+ ret = ehea_create_busmap();
+ if (ret)
+ goto out;
+
+ clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
+
+ list_for_each_entry(adapter, &adapter_list, list)
+ if (adapter->active_ports) {
+ /* Register new memory region */
+ ret = ehea_reg_kernel_mr(adapter, &adapter->mr);
+ if (ret) {
+ ehea_error("register MR failed - driver"
+ " inoperable!");
+ goto out;
+ }
+
+ /* Restart all ports */
+ for (i = 0; i < EHEA_MAX_PORTS; i++) {
+ struct ehea_port *port = adapter->port[i];
+
+ if (port) {
+ struct net_device *dev = port->netdev;
+
+ if (dev->flags & IFF_UP) {
+ ehea_info("restarting %s",
+ dev->name);
+ down(&port->port_lock);
+
+ ret = ehea_up(dev);
+ if (!ret) {
+ netif_poll_enable(dev);
+ netif_wake_queue(dev);
+ }
+
+ up(&port->port_lock);
+ }
+ }
+ }
+ }
+out:
+ return;
+}
+
static void ehea_tx_watchdog(struct net_device *dev)
{
struct ehea_port *port = netdev_priv(dev);
@@ -2557,12 +2646,18 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
INIT_WORK(&port->reset_task, ehea_reset_port);
+ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+ if (ret) {
+ ret = -EIO;
+ goto out_unreg_port;
+ }
+
ehea_set_ethtool_ops(dev);
ret = register_netdev(dev);
if (ret) {
ehea_error("register_netdev failed. ret=%d", ret);
- goto out_unreg_port;
+ goto out_dereg_bc;
}
ret = ehea_get_jumboframe_status(port, &jumbo);
@@ -2573,8 +2668,13 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
ehea_info("%s: Jumbo frames are %sabled", dev->name,
jumbo == 1 ? "en" : "dis");
+ adapter->active_ports++;
+
return port;
+out_dereg_bc:
+ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
out_unreg_port:
ehea_unregister_port(port);
@@ -2594,8 +2694,10 @@ static void ehea_shutdown_single_port(struct ehea_port *port)
{
unregister_netdev(port->netdev);
ehea_unregister_port(port);
+ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
kfree(port->mc_list);
free_netdev(port->netdev);
+ port->adapter->active_ports--;
}
static int ehea_setup_ports(struct ehea_adapter *adapter)
@@ -2788,6 +2890,8 @@ static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
goto out;
}
+ list_add(&adapter->list, &adapter_list);
+
adapter->ebus_dev = dev;
adapter_handle = of_get_property(dev->ofdev.node, "ibm,hea-handle",
@@ -2891,7 +2995,10 @@ static int __devexit ehea_remove(struct ibmebus_dev *dev)
ehea_destroy_eq(adapter->neq);
ehea_remove_adapter_mr(adapter);
+ list_del(&adapter->list);
+
kfree(adapter);
+
return 0;
}
@@ -2939,9 +3046,18 @@ int __init ehea_module_init(void)
printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
DRV_VERSION);
+ ehea_driver_wq = create_workqueue("ehea_driver_wq");
+
+ INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs);
+
ret = check_module_parm();
if (ret)
goto out;
+
+ ret = ehea_create_busmap();
+ if (ret)
+ goto out;
+
ret = ibmebus_register_driver(&ehea_driver);
if (ret) {
ehea_error("failed registering eHEA device driver on ebus");
@@ -2965,6 +3081,7 @@ static void __exit ehea_module_exit(void)
{
driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
ibmebus_unregister_driver(&ehea_driver);
+ ehea_destroy_busmap();
}
module_init(ehea_module_init);
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index d17a45a7e717..89b63531ff26 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -60,6 +60,9 @@ static inline u32 get_longbusy_msecs(int long_busy_ret_code)
}
}
+/* Number of pages which can be registered at once by H_REGISTER_HEA_RPAGES */
+#define EHEA_MAX_RPAGE 512
+
/* Notification Event Queue (NEQ) Entry bit masks */
#define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7)
#define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47)
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index 29eaa46948b0..a36fa6c23fdf 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -31,6 +31,13 @@
#include "ehea_phyp.h"
#include "ehea_qmr.h"
+
+struct ehea_busmap ehea_bmap = { 0, 0, NULL };
+extern u64 ehea_driver_flags;
+extern struct workqueue_struct *ehea_driver_wq;
+extern struct work_struct ehea_rereg_mr_task;
+
+
static void *hw_qpageit_get_inc(struct hw_queue *queue)
{
void *retvalue = hw_qeit_get(queue);
@@ -547,18 +554,84 @@ int ehea_destroy_qp(struct ehea_qp *qp)
return 0;
}
+int ehea_create_busmap( void )
+{
+ u64 vaddr = EHEA_BUSMAP_START;
+ unsigned long abs_max_pfn = 0;
+ unsigned long sec_max_pfn;
+ int i;
+
+ /*
+ * Sections are not in ascending order -> Loop over all sections and
+ * find the highest PFN to compute the required map size.
+ */
+ ehea_bmap.valid_sections = 0;
+
+ for (i = 0; i < NR_MEM_SECTIONS; i++)
+ if (valid_section_nr(i)) {
+ sec_max_pfn = section_nr_to_pfn(i);
+ if (sec_max_pfn > abs_max_pfn)
+ abs_max_pfn = sec_max_pfn;
+ ehea_bmap.valid_sections++;
+ }
+
+ ehea_bmap.entries = abs_max_pfn / EHEA_PAGES_PER_SECTION + 1;
+ ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr));
+
+ if (!ehea_bmap.vaddr)
+ return -ENOMEM;
+
+ for (i = 0 ; i < ehea_bmap.entries; i++) {
+ unsigned long pfn = section_nr_to_pfn(i);
+
+ if (pfn_valid(pfn)) {
+ ehea_bmap.vaddr[i] = vaddr;
+ vaddr += EHEA_SECTSIZE;
+ } else
+ ehea_bmap.vaddr[i] = 0;
+ }
+
+ return 0;
+}
+
+void ehea_destroy_busmap( void )
+{
+ vfree(ehea_bmap.vaddr);
+}
+
+u64 ehea_map_vaddr(void *caddr)
+{
+ u64 mapped_addr;
+ unsigned long index = __pa(caddr) >> SECTION_SIZE_BITS;
+
+ if (likely(index < ehea_bmap.entries)) {
+ mapped_addr = ehea_bmap.vaddr[index];
+ if (likely(mapped_addr))
+ mapped_addr |= (((unsigned long)caddr)
+ & (EHEA_SECTSIZE - 1));
+ else
+ mapped_addr = -1;
+ } else
+ mapped_addr = -1;
+
+ if (unlikely(mapped_addr == -1))
+ if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
+ queue_work(ehea_driver_wq, &ehea_rereg_mr_task);
+
+ return mapped_addr;
+}
+
int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
{
- int i, k, ret;
- u64 hret, pt_abs, start, end, nr_pages;
- u32 acc_ctrl = EHEA_MR_ACC_CTRL;
+ int ret;
u64 *pt;
+ void *pg;
+ u64 hret, pt_abs, i, j, m, mr_len;
+ u32 acc_ctrl = EHEA_MR_ACC_CTRL;
- start = KERNELBASE;
- end = (u64)high_memory;
- nr_pages = (end - start) / EHEA_PAGESIZE;
+ mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE;
- pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ pt = kzalloc(EHEA_MAX_RPAGE * sizeof(u64), GFP_KERNEL);
if (!pt) {
ehea_error("no mem");
ret = -ENOMEM;
@@ -566,7 +639,8 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
}
pt_abs = virt_to_abs(pt);
- hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
+ hret = ehea_h_alloc_resource_mr(adapter->handle,
+ EHEA_BUSMAP_START, mr_len,
acc_ctrl, adapter->pd,
&mr->handle, &mr->lkey);
if (hret != H_SUCCESS) {
@@ -575,49 +649,43 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr)
goto out;
}
- mr->vaddr = KERNELBASE;
- k = 0;
-
- while (nr_pages > 0) {
- if (nr_pages > 1) {
- u64 num_pages = min(nr_pages, (u64)512);
- for (i = 0; i < num_pages; i++)
- pt[i] = virt_to_abs((void*)(((u64)start) +
- ((k++) *
- EHEA_PAGESIZE)));
-
- hret = ehea_h_register_rpage_mr(adapter->handle,
- mr->handle, 0,
- 0, (u64)pt_abs,
- num_pages);
- nr_pages -= num_pages;
- } else {
- u64 abs_adr = virt_to_abs((void*)(((u64)start) +
- (k * EHEA_PAGESIZE)));
-
- hret = ehea_h_register_rpage_mr(adapter->handle,
- mr->handle, 0,
- 0, abs_adr,1);
- nr_pages--;
- }
-
- if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
- ehea_h_free_resource(adapter->handle,
- mr->handle, FORCE_FREE);
- ehea_error("register_rpage_mr failed");
- ret = -EIO;
- goto out;
+ for (i = 0 ; i < ehea_bmap.entries; i++)
+ if (ehea_bmap.vaddr[i]) {
+ void *sectbase = __va(i << SECTION_SIZE_BITS);
+ unsigned long k = 0;
+
+ for (j = 0; j < (PAGES_PER_SECTION / EHEA_MAX_RPAGE);
+ j++) {
+
+ for (m = 0; m < EHEA_MAX_RPAGE; m++) {
+ pg = sectbase + ((k++) * EHEA_PAGESIZE);
+ pt[m] = virt_to_abs(pg);
+ }
+
+ hret = ehea_h_register_rpage_mr(adapter->handle,
+ mr->handle,
+ 0, 0, pt_abs,
+ EHEA_MAX_RPAGE);
+ if ((hret != H_SUCCESS)
+ && (hret != H_PAGE_REGISTERED)) {
+ ehea_h_free_resource(adapter->handle,
+ mr->handle,
+ FORCE_FREE);
+ ehea_error("register_rpage_mr failed");
+ ret = -EIO;
+ goto out;
+ }
+ }
}
- }
if (hret != H_SUCCESS) {
- ehea_h_free_resource(adapter->handle, mr->handle,
- FORCE_FREE);
- ehea_error("register_rpage failed for last page");
+ ehea_h_free_resource(adapter->handle, mr->handle, FORCE_FREE);
+ ehea_error("registering mr failed");
ret = -EIO;
goto out;
}
+ mr->vaddr = EHEA_BUSMAP_START;
mr->adapter = adapter;
ret = 0;
out:
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index c0eb3e03a102..b71f8452a5e3 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -36,8 +36,14 @@
* page size of ehea hardware queues
*/
-#define EHEA_PAGESHIFT 12
-#define EHEA_PAGESIZE 4096UL
+#define EHEA_PAGESHIFT 12
+#define EHEA_PAGESIZE (1UL << EHEA_PAGESHIFT)
+#define EHEA_SECTSIZE (1UL << 24)
+#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> PAGE_SHIFT)
+
+#if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE
+#error eHEA module can't work if kernel sectionsize < ehea sectionsize
+#endif
/* Some abbreviations used here:
*
@@ -372,4 +378,8 @@ int ehea_rem_mr(struct ehea_mr *mr);
void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle);
+int ehea_create_busmap( void );
+void ehea_destroy_busmap( void );
+u64 ehea_map_vaddr(void *caddr);
+
#endif /* __EHEA_QMR_H__ */
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 5e517946f46a..119778401e48 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1201,7 +1201,7 @@ static int epic_rx(struct net_device *dev, int budget)
ep->rx_ring[entry].bufaddr,
ep->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, ep->rx_skbuff[entry]->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb, ep->rx_skbuff[entry]->data, pkt_len);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(ep->pci_dev,
ep->rx_ring[entry].bufaddr,
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index abe9b089c610..ff9f177d7157 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1727,8 +1727,8 @@ static int netdev_rx(struct net_device *dev)
/* Call copy + cksum if available. */
#if ! defined(__alpha__)
- eth_copy_and_sum(skb,
- np->cur_rx->skbuff->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb,
+ np->cur_rx->skbuff->data, pkt_len);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 255b09124e11..03023dd17829 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -648,7 +648,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
fep->stats.rx_dropped++;
} else {
skb_put(skb,pkt_len-4); /* Make room */
- eth_copy_and_sum(skb, data, pkt_len-4, 0);
+ skb_copy_to_linear_data(skb, data, pkt_len-4);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
}
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 42ba1c012ee2..6d1d50a19783 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -550,6 +550,8 @@ union ring_type {
/* PHY defines */
#define PHY_OUI_MARVELL 0x5043
#define PHY_OUI_CICADA 0x03f1
+#define PHY_OUI_VITESSE 0x01c1
+#define PHY_OUI_REALTEK 0x01c1
#define PHYID1_OUI_MASK 0x03ff
#define PHYID1_OUI_SHFT 6
#define PHYID2_OUI_MASK 0xfc00
@@ -557,12 +559,36 @@ union ring_type {
#define PHYID2_MODEL_MASK 0x03f0
#define PHY_MODEL_MARVELL_E3016 0x220
#define PHY_MARVELL_E3016_INITMASK 0x0300
-#define PHY_INIT1 0x0f000
-#define PHY_INIT2 0x0e00
-#define PHY_INIT3 0x01000
-#define PHY_INIT4 0x0200
-#define PHY_INIT5 0x0004
-#define PHY_INIT6 0x02000
+#define PHY_CICADA_INIT1 0x0f000
+#define PHY_CICADA_INIT2 0x0e00
+#define PHY_CICADA_INIT3 0x01000
+#define PHY_CICADA_INIT4 0x0200
+#define PHY_CICADA_INIT5 0x0004
+#define PHY_CICADA_INIT6 0x02000
+#define PHY_VITESSE_INIT_REG1 0x1f
+#define PHY_VITESSE_INIT_REG2 0x10
+#define PHY_VITESSE_INIT_REG3 0x11
+#define PHY_VITESSE_INIT_REG4 0x12
+#define PHY_VITESSE_INIT_MSK1 0xc
+#define PHY_VITESSE_INIT_MSK2 0x0180
+#define PHY_VITESSE_INIT1 0x52b5
+#define PHY_VITESSE_INIT2 0xaf8a
+#define PHY_VITESSE_INIT3 0x8
+#define PHY_VITESSE_INIT4 0x8f8a
+#define PHY_VITESSE_INIT5 0xaf86
+#define PHY_VITESSE_INIT6 0x8f86
+#define PHY_VITESSE_INIT7 0xaf82
+#define PHY_VITESSE_INIT8 0x0100
+#define PHY_VITESSE_INIT9 0x8f82
+#define PHY_VITESSE_INIT10 0x0
+#define PHY_REALTEK_INIT_REG1 0x1f
+#define PHY_REALTEK_INIT_REG2 0x19
+#define PHY_REALTEK_INIT_REG3 0x13
+#define PHY_REALTEK_INIT1 0x0000
+#define PHY_REALTEK_INIT2 0x8e00
+#define PHY_REALTEK_INIT3 0x0001
+#define PHY_REALTEK_INIT4 0xad17
+
#define PHY_GIGABIT 0x0100
#define PHY_TIMEOUT 0x1
@@ -1096,6 +1122,28 @@ static int phy_init(struct net_device *dev)
return PHY_ERROR;
}
}
+ 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 (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;
+ }
+ }
/* set advertise register */
reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
@@ -1141,14 +1189,14 @@ static int phy_init(struct net_device *dev)
/* phy vendor specific configuration */
if ((np->phy_oui == PHY_OUI_CICADA) && (phyinterface & PHY_RGMII) ) {
phy_reserved = mii_rw(dev, np->phyaddr, MII_RESV1, MII_READ);
- phy_reserved &= ~(PHY_INIT1 | PHY_INIT2);
- phy_reserved |= (PHY_INIT3 | PHY_INIT4);
+ phy_reserved &= ~(PHY_CICADA_INIT1 | PHY_CICADA_INIT2);
+ phy_reserved |= (PHY_CICADA_INIT3 | PHY_CICADA_INIT4);
if (mii_rw(dev, np->phyaddr, MII_RESV1, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
phy_reserved = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
- phy_reserved |= PHY_INIT5;
+ phy_reserved |= PHY_CICADA_INIT5;
if (mii_rw(dev, np->phyaddr, MII_NCONFIG, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
@@ -1156,12 +1204,106 @@ static int phy_init(struct net_device *dev)
}
if (np->phy_oui == PHY_OUI_CICADA) {
phy_reserved = mii_rw(dev, np->phyaddr, MII_SREVISION, MII_READ);
- phy_reserved |= PHY_INIT6;
+ phy_reserved |= PHY_CICADA_INIT6;
if (mii_rw(dev, np->phyaddr, MII_SREVISION, phy_reserved)) {
printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
}
+ if (np->phy_oui == PHY_OUI_VITESSE) {
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT1)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT2)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
+ phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
+ phy_reserved |= PHY_VITESSE_INIT3;
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, 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_VITESSE_INIT_REG2, PHY_VITESSE_INIT4)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT5)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
+ phy_reserved &= ~PHY_VITESSE_INIT_MSK1;
+ phy_reserved |= PHY_VITESSE_INIT3;
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, 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_VITESSE_INIT_REG2, PHY_VITESSE_INIT6)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG2, PHY_VITESSE_INIT7)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, MII_READ);
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG4, phy_reserved)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ phy_reserved = mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, MII_READ);
+ phy_reserved &= ~PHY_VITESSE_INIT_MSK2;
+ phy_reserved |= PHY_VITESSE_INIT8;
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG3, 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_VITESSE_INIT_REG2, PHY_VITESSE_INIT9)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ if (mii_rw(dev, np->phyaddr, PHY_VITESSE_INIT_REG1, PHY_VITESSE_INIT10)) {
+ printk(KERN_INFO "%s: phy init failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
+ 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 (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;
+ }
+ }
+
/* some phys clear out pause advertisment on reset, set it back */
mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg);
@@ -4995,12 +5137,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
goto out_unmap;
np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
}
- np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
- np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+ np->rx_skb = kcalloc(np->rx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
+ np->tx_skb = kcalloc(np->tx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
if (!np->rx_skb || !np->tx_skb)
goto out_freering;
- memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
- memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
dev->open = nv_open;
dev->stop = nv_close;
@@ -5084,15 +5224,13 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->wolenabled = 0;
if (id->driver_data & DEV_HAS_POWER_CNTRL) {
- u8 revision_id;
- pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id);
/* take phy and nic out of low power mode */
powerstate = readl(base + NvRegPowerState2);
powerstate &= ~NVREG_POWERSTATE2_POWERUP_MASK;
if ((id->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
id->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) &&
- revision_id >= 0xA3)
+ pci_dev->revision >= 0xA3)
powerstate |= NVREG_POWERSTATE2_POWERUP_REV_A3;
writel(powerstate, base + NvRegPowerState2);
}
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index d7a1a58de766..f92690555dd9 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -420,8 +420,18 @@ static phy_interface_t gfar_get_interface(struct net_device *dev)
if (ecntrl & ECNTRL_REDUCED_MODE) {
if (ecntrl & ECNTRL_REDUCED_MII_MODE)
return PHY_INTERFACE_MODE_RMII;
- else
+ else {
+ phy_interface_t interface = priv->einfo->interface;
+
+ /*
+ * This isn't autodetected right now, so it must
+ * be set by the device tree or platform code.
+ */
+ if (interface == PHY_INTERFACE_MODE_RGMII_ID)
+ return PHY_INTERFACE_MODE_RGMII_ID;
+
return PHY_INTERFACE_MODE_RGMII;
+ }
}
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index 5dd34a1a7b89..ac3596f45dd8 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -31,7 +31,6 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <asm/ocp.h>
#include <linux/crc32.h>
#include <linux/mii.h>
#include <linux/phy.h>
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 2521b111b3a5..15254dc7876a 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1575,8 +1575,8 @@ static int hamachi_rx(struct net_device *dev)
PCI_DMA_FROMDEVICE);
/* Call copy + cksum if available. */
#if 1 || USE_IP_COPYSUM
- eth_copy_and_sum(skb,
- hmp->rx_skbuff[entry]->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb,
+ hmp->rx_skbuff[entry]->data, pkt_len);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len), hmp->rx_ring_dma
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 84aa2117c0ee..355c6cf3d112 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -320,7 +320,7 @@ static int eppconfig(struct baycom_state *bc)
sprintf(portarg, "%ld", bc->pdev->port->base);
printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
- return call_usermodehelper(eppconfig_path, argv, envp, 1);
+ return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC);
}
/* ---------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 3be8c5047599..205f09672492 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -453,8 +453,8 @@ static int __init setup_adapter(int card_base, int type, int n)
int scc_base = card_base + hw[type].scc_offset;
char *chipnames[] = CHIPNAMES;
- /* Allocate memory */
- info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
+ /* Initialize what is necessary for write_scc and write_scc_data */
+ info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
if (!info) {
printk(KERN_ERR "dmascc: "
"could not allocate memory for %s at %#3x\n",
@@ -462,8 +462,6 @@ static int __init setup_adapter(int card_base, int type, int n)
goto out;
}
- /* Initialize what is necessary for write_scc and write_scc_data */
- memset(info, 0, sizeof(struct scc_info));
info->dev[0] = alloc_netdev(0, "", dev_setup);
if (!info->dev[0]) {
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 6ec3d500f334..d96eb7229548 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1337,7 +1337,7 @@ const char * buf, size_t count)
#define ATTR(_name, _mode) \
struct attribute veth_##_name##_attr = { \
- .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \
+ .name = __stringify(_name), .mode = _mode, \
};
static ATTR(active, 0644);
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 07b4c0d7a75c..f5c3598e59af 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -136,13 +136,14 @@ resched:
}
-static void __init ifb_setup(struct net_device *dev)
+static void ifb_setup(struct net_device *dev)
{
/* Initialize the device structure. */
dev->get_stats = ifb_get_stats;
dev->hard_start_xmit = ifb_xmit;
dev->open = &ifb_open;
dev->stop = &ifb_close;
+ dev->destructor = free_netdev;
/* Fill in device structure with ethernet-generic values. */
ether_setup(dev);
@@ -197,12 +198,6 @@ static struct net_device_stats *ifb_get_stats(struct net_device *dev)
return stats;
}
-static struct net_device **ifbs;
-
-/* Number of ifb devices to be set up by this module. */
-module_param(numifbs, int, 0);
-MODULE_PARM_DESC(numifbs, "Number of ifb devices");
-
static int ifb_close(struct net_device *dev)
{
struct ifb_private *dp = netdev_priv(dev);
@@ -226,6 +221,28 @@ static int ifb_open(struct net_device *dev)
return 0;
}
+static int ifb_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+ return 0;
+}
+
+static struct rtnl_link_ops ifb_link_ops __read_mostly = {
+ .kind = "ifb",
+ .priv_size = sizeof(struct ifb_private),
+ .setup = ifb_setup,
+ .validate = ifb_validate,
+};
+
+/* Number of ifb devices to be set up by this module. */
+module_param(numifbs, int, 0);
+MODULE_PARM_DESC(numifbs, "Number of ifb devices");
+
static int __init ifb_init_one(int index)
{
struct net_device *dev_ifb;
@@ -237,49 +254,44 @@ static int __init ifb_init_one(int index)
if (!dev_ifb)
return -ENOMEM;
- if ((err = register_netdev(dev_ifb))) {
- free_netdev(dev_ifb);
- dev_ifb = NULL;
- } else {
- ifbs[index] = dev_ifb;
- }
+ err = dev_alloc_name(dev_ifb, dev_ifb->name);
+ if (err < 0)
+ goto err;
- return err;
-}
+ dev_ifb->rtnl_link_ops = &ifb_link_ops;
+ err = register_netdevice(dev_ifb);
+ if (err < 0)
+ goto err;
+ return 0;
-static void ifb_free_one(int index)
-{
- unregister_netdev(ifbs[index]);
- free_netdev(ifbs[index]);
+err:
+ free_netdev(dev_ifb);
+ return err;
}
static int __init ifb_init_module(void)
{
- int i, err = 0;
- ifbs = kmalloc(numifbs * sizeof(void *), GFP_KERNEL);
- if (!ifbs)
- return -ENOMEM;
+ int i, err;
+
+ rtnl_lock();
+ err = __rtnl_link_register(&ifb_link_ops);
+
for (i = 0; i < numifbs && !err; i++)
err = ifb_init_one(i);
- if (err) {
- i--;
- while (--i >= 0)
- ifb_free_one(i);
- }
+ if (err)
+ __rtnl_link_unregister(&ifb_link_ops);
+ rtnl_unlock();
return err;
}
static void __exit ifb_cleanup_module(void)
{
- int i;
-
- for (i = 0; i < numifbs; i++)
- ifb_free_one(i);
- kfree(ifbs);
+ rtnl_link_unregister(&ifb_link_ops);
}
module_init(ifb_init_module);
module_exit(ifb_cleanup_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jamal Hadi Salim");
+MODULE_ALIAS_RTNL_LINK("ifb");
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 829da9a1d113..2098d0af8ff5 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -155,6 +155,15 @@ config KINGSUN_DONGLE
To compile it as a module, choose M here: the module will be called
kingsun-sir.
+config EP7211_DONGLE
+ tristate "EP7211 I/R support"
+ depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+ help
+ Say Y here if you want to build support for the Cirrus logic
+ EP7211 chipset's infrared module.
+
+
+
comment "Old SIR device drivers"
config IRPORT_SIR
@@ -355,7 +364,7 @@ config WINBOND_FIR
config TOSHIBA_FIR
tristate "Toshiba Type-O IR Port"
- depends on IRDA && PCI && !64BIT
+ depends on IRDA && PCI && !64BIT && VIRT_TO_BUS
help
Say Y here if you want to build support for the Toshiba Type-O IR
and Donau oboe chipsets. These chipsets are used by the Toshiba
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 233a2f923730..2808ef5c7b79 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o
obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
+obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o
obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
# The SIR helper module
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c
new file mode 100644
index 000000000000..831572429bb9
--- /dev/null
+++ b/drivers/net/irda/ep7211-sir.c
@@ -0,0 +1,89 @@
+/*
+ * IR port driver for the Cirrus Logic EP7211 processor.
+ *
+ * Copyright 2001, Blue Mug Inc. All rights reserved.
+ * Copyright 2007, Samuel Ortiz <samuel@sortiz.org>
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "sir-dev.h"
+
+#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000 /* 1 ms */
+
+static int ep7211_open(struct sir_dev *dev);
+static int ep7211_close(struct sir_dev *dev);
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed);
+static int ep7211_reset(struct sir_dev *dev);
+
+static struct dongle_driver ep7211 = {
+ .owner = THIS_MODULE,
+ .driver_name = "EP7211 IR driver",
+ .type = IRDA_EP7211_DONGLE,
+ .open = ep7211_open,
+ .close = ep7211_close,
+ .reset = ep7211_reset,
+ .set_speed = ep7211_change_speed,
+};
+
+static int __init ep7211_sir_init(void)
+{
+ return irda_register_dongle(&ep7211);
+}
+
+static void __exit ep7211_sir_cleanup(void)
+{
+ irda_unregister_dongle(&ep7211);
+}
+
+static int ep7211_open(struct sir_dev *dev)
+{
+ unsigned int syscon;
+
+ /* Turn on the SIR encoder. */
+ syscon = clps_readl(SYSCON1);
+ syscon |= SYSCON1_SIREN;
+ clps_writel(syscon, SYSCON1);
+
+ return 0;
+}
+
+static int ep7211_close(struct sir_dev *dev)
+{
+ unsigned int syscon;
+
+ /* Turn off the SIR encoder. */
+ syscon = clps_readl(SYSCON1);
+ syscon &= ~SYSCON1_SIREN;
+ clps_writel(syscon, SYSCON1);
+
+ return 0;
+}
+
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed)
+{
+ return 0;
+}
+
+static int ep7211_reset(struct sir_dev *dev)
+{
+ return 0;
+}
+
+MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>");
+MODULE_DESCRIPTION("EP7211 IR dongle driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */
+
+module_init(ep7211_sir_init);
+module_exit(ep7211_sir_cleanup);
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 3078c419cb02..20732458f5ac 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -164,14 +164,13 @@ irport_open(int i, unsigned int iobase, unsigned int irq)
/* Allocate memory if needed */
if (self->tx_buff.truesize > 0) {
- self->tx_buff.head = kmalloc(self->tx_buff.truesize,
+ self->tx_buff.head = kzalloc(self->tx_buff.truesize,
GFP_KERNEL);
if (self->tx_buff.head == NULL) {
IRDA_ERROR("%s(), can't allocate memory for "
"transmit buffer!\n", __FUNCTION__);
goto err_out4;
}
- memset(self->tx_buff.head, 0, self->tx_buff.truesize);
}
self->tx_buff.data = self->tx_buff.head;
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index ad1857364d51..6f5f697ec9f8 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -505,10 +505,9 @@ static int irtty_open(struct tty_struct *tty)
}
/* allocate private device info block */
- priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
goto out_put;
- memset(priv, 0, sizeof(*priv));
priv->magic = IRTTY_MAGIC;
priv->tty = tty;
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index 217429122e79..bdd5c979bead 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -4,7 +4,7 @@
* Version: 0.1.1
* Description: Irda KingSun/DonShine USB Dongle
* Status: Experimental
-* Author: Alex Villac�s Lasso <a_villacis@palosanto.com>
+* Author: Alex Villacís Lasso <a_villacis@palosanto.com>
*
* Based on stir4200 and mcs7780 drivers, with (strange?) differences
*
@@ -652,6 +652,6 @@ static void __exit kingsun_cleanup(void)
}
module_exit(kingsun_cleanup);
-MODULE_AUTHOR("Alex Villac�s Lasso <a_villacis@palosanto.com>");
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index bf78ef1120ad..0538ca9ce058 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -44,6 +44,7 @@ MODULE_LICENSE("GPL");
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -1660,8 +1661,8 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id)
idev = ndev->priv;
spin_lock_init(&idev->lock);
- init_MUTEX(&idev->sem);
- down(&idev->sem);
+ mutex_init(&idev->mtx);
+ mutex_lock(&idev->mtx);
idev->pdev = pdev;
if (vlsi_irda_init(ndev) < 0)
@@ -1689,12 +1690,12 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id)
IRDA_MESSAGE("%s: registered device %s\n", drivername, ndev->name);
pci_set_drvdata(pdev, ndev);
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
return 0;
out_freedev:
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
free_netdev(ndev);
out_disable:
pci_disable_device(pdev);
@@ -1716,12 +1717,12 @@ static void __devexit vlsi_irda_remove(struct pci_dev *pdev)
unregister_netdev(ndev);
idev = ndev->priv;
- down(&idev->sem);
+ mutex_lock(&idev->mtx);
if (idev->proc_entry) {
remove_proc_entry(ndev->name, vlsi_proc_root);
idev->proc_entry = NULL;
}
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
free_netdev(ndev);
@@ -1751,7 +1752,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
return 0;
}
idev = ndev->priv;
- down(&idev->sem);
+ mutex_lock(&idev->mtx);
if (pdev->current_state != 0) { /* already suspended */
if (state.event > pdev->current_state) { /* simply go deeper */
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -1759,7 +1760,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
}
else
IRDA_ERROR("%s - %s: invalid suspend request %u -> %u\n", __FUNCTION__, pci_name(pdev), pdev->current_state, state.event);
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
return 0;
}
@@ -1775,7 +1776,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state)
pci_set_power_state(pdev, pci_choose_state(pdev, state));
pdev->current_state = state.event;
idev->resume_ok = 1;
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
return 0;
}
@@ -1790,9 +1791,9 @@ static int vlsi_irda_resume(struct pci_dev *pdev)
return 0;
}
idev = ndev->priv;
- down(&idev->sem);
+ mutex_lock(&idev->mtx);
if (pdev->current_state == 0) {
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
IRDA_WARNING("%s - %s: already resumed\n",
__FUNCTION__, pci_name(pdev));
return 0;
@@ -1814,7 +1815,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev)
* device and independently resume_ok should catch any garbage config.
*/
IRDA_WARNING("%s - hm, nothing to resume?\n", __FUNCTION__);
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
return 0;
}
@@ -1824,7 +1825,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev)
netif_device_attach(ndev);
}
idev->resume_ok = 0;
- up(&idev->sem);
+ mutex_unlock(&idev->mtx);
return 0;
}
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index 2d3b773d8e35..ca12a6096419 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -728,7 +728,7 @@ typedef struct vlsi_irda_dev {
struct timeval last_rx;
spinlock_t lock;
- struct semaphore sem;
+ struct mutex mtx;
u8 resume_ok;
struct proc_dir_entry *proc_entry;
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 347d50cd77d4..0433c41f9029 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -822,10 +822,9 @@ static int veth_init_connection(u8 rlp)
|| ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
return 0;
- cnx = kmalloc(sizeof(*cnx), GFP_KERNEL);
+ cnx = kzalloc(sizeof(*cnx), GFP_KERNEL);
if (! cnx)
return -ENOMEM;
- memset(cnx, 0, sizeof(*cnx));
cnx->remote_lp = rlp;
spin_lock_init(&cnx->lock);
@@ -852,14 +851,13 @@ static int veth_init_connection(u8 rlp)
if (rc != 0)
return rc;
- msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
+ msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
if (! msgs) {
veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
return -ENOMEM;
}
cnx->msgs = msgs;
- memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
for (i = 0; i < VETH_NUMBUFFERS; i++) {
msgs[i].token = i;
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index d5f694fc4a21..d9ce1aef148a 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -111,7 +111,7 @@ static int ixpdev_rx(struct net_device *dev, int *budget)
skb = dev_alloc_skb(desc->pkt_length + 2);
if (likely(skb != NULL)) {
skb_reserve(skb, 2);
- eth_copy_and_sum(skb, buf, desc->pkt_length, 0);
+ skb_copy_to_linear_data(skb, buf, desc->pkt_length);
skb_put(skb, desc->pkt_length);
skb->protocol = eth_type_trans(skb, nds[desc->channel]);
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index 0fe96c85828b..a4e5fab12628 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -533,11 +533,10 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
dev->base_addr = ioaddr;
/* Make certain the data structures used by the LANCE are aligned and DMAble. */
- lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+ lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
if(lp==NULL)
return -ENODEV;
if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
- memset(lp, 0, sizeof(*lp));
dev->priv = lp;
lp->name = chipname;
lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE,
@@ -1186,9 +1185,9 @@ lance_rx(struct net_device *dev)
}
skb_reserve(skb,2); /* 16 byte align */
skb_put(skb,pkt_len); /* Make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *)isa_bus_to_virt((lp->rx_ring[entry].base & 0x00ffffff)),
- pkt_len,0);
+ pkt_len);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c
new file mode 100644
index 000000000000..112778652f7d
--- /dev/null
+++ b/drivers/net/lguest_net.c
@@ -0,0 +1,354 @@
+/* A simple network driver for lguest.
+ *
+ * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> 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 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
+ */
+//#define DEBUG
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/mm_types.h>
+#include <linux/io.h>
+#include <linux/lguest_bus.h>
+
+#define SHARED_SIZE PAGE_SIZE
+#define MAX_LANS 4
+#define NUM_SKBS 8
+
+struct lguestnet_info
+{
+ /* The shared page(s). */
+ struct lguest_net *peer;
+ unsigned long peer_phys;
+ unsigned long mapsize;
+
+ /* The lguest_device I come from */
+ struct lguest_device *lgdev;
+
+ /* My peerid. */
+ unsigned int me;
+
+ /* Receive queue. */
+ struct sk_buff *skb[NUM_SKBS];
+ struct lguest_dma dma[NUM_SKBS];
+};
+
+/* How many bytes left in this page. */
+static unsigned int rest_of_page(void *data)
+{
+ return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
+}
+
+/* Simple convention: offset 4 * peernum. */
+static unsigned long peer_key(struct lguestnet_info *info, unsigned peernum)
+{
+ return info->peer_phys + 4 * peernum;
+}
+
+static void skb_to_dma(const struct sk_buff *skb, unsigned int headlen,
+ struct lguest_dma *dma)
+{
+ unsigned int i, seg;
+
+ for (i = seg = 0; i < headlen; seg++, i += rest_of_page(skb->data+i)) {
+ dma->addr[seg] = virt_to_phys(skb->data + i);
+ dma->len[seg] = min((unsigned)(headlen - i),
+ rest_of_page(skb->data + i));
+ }
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, seg++) {
+ const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+ /* Should not happen with MTU less than 64k - 2 * PAGE_SIZE. */
+ if (seg == LGUEST_MAX_DMA_SECTIONS) {
+ printk("Woah dude! Megapacket!\n");
+ break;
+ }
+ dma->addr[seg] = page_to_phys(f->page) + f->page_offset;
+ dma->len[seg] = f->size;
+ }
+ if (seg < LGUEST_MAX_DMA_SECTIONS)
+ dma->len[seg] = 0;
+}
+
+/* We overload multicast bit to show promiscuous mode. */
+#define PROMISC_BIT 0x01
+
+static void lguestnet_set_multicast(struct net_device *dev)
+{
+ struct lguestnet_info *info = netdev_priv(dev);
+
+ if ((dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) || dev->mc_count)
+ info->peer[info->me].mac[0] |= PROMISC_BIT;
+ else
+ info->peer[info->me].mac[0] &= ~PROMISC_BIT;
+}
+
+static int promisc(struct lguestnet_info *info, unsigned int peer)
+{
+ return info->peer[peer].mac[0] & PROMISC_BIT;
+}
+
+static int mac_eq(const unsigned char mac[ETH_ALEN],
+ struct lguestnet_info *info, unsigned int peer)
+{
+ /* Ignore multicast bit, which peer turns on to mean promisc. */
+ if ((info->peer[peer].mac[0] & (~PROMISC_BIT)) != mac[0])
+ return 0;
+ return memcmp(mac+1, info->peer[peer].mac+1, ETH_ALEN-1) == 0;
+}
+
+static void transfer_packet(struct net_device *dev,
+ struct sk_buff *skb,
+ unsigned int peernum)
+{
+ struct lguestnet_info *info = netdev_priv(dev);
+ struct lguest_dma dma;
+
+ skb_to_dma(skb, skb_headlen(skb), &dma);
+ pr_debug("xfer length %04x (%u)\n", htons(skb->len), skb->len);
+
+ lguest_send_dma(peer_key(info, peernum), &dma);
+ if (dma.used_len != skb->len) {
+ dev->stats.tx_carrier_errors++;
+ pr_debug("Bad xfer to peer %i: %i of %i (dma %p/%i)\n",
+ peernum, dma.used_len, skb->len,
+ (void *)dma.addr[0], dma.len[0]);
+ } else {
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+ }
+}
+
+static int unused_peer(const struct lguest_net peer[], unsigned int num)
+{
+ return peer[num].mac[0] == 0;
+}
+
+static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned int i;
+ int broadcast;
+ struct lguestnet_info *info = netdev_priv(dev);
+ const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
+
+ pr_debug("%s: xmit %02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, dest[0],dest[1],dest[2],dest[3],dest[4],dest[5]);
+
+ broadcast = is_multicast_ether_addr(dest);
+ for (i = 0; i < info->mapsize/sizeof(struct lguest_net); i++) {
+ if (i == info->me || unused_peer(info->peer, i))
+ continue;
+
+ if (!broadcast && !promisc(info, i) && !mac_eq(dest, info, i))
+ continue;
+
+ pr_debug("lguestnet %s: sending from %i to %i\n",
+ dev->name, info->me, i);
+ transfer_packet(dev, skb, i);
+ }
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+/* Find a new skb to put in this slot in shared mem. */
+static int fill_slot(struct net_device *dev, unsigned int slot)
+{
+ struct lguestnet_info *info = netdev_priv(dev);
+ /* Try to create and register a new one. */
+ info->skb[slot] = netdev_alloc_skb(dev, ETH_HLEN + ETH_DATA_LEN);
+ if (!info->skb[slot]) {
+ printk("%s: could not fill slot %i\n", dev->name, slot);
+ return -ENOMEM;
+ }
+
+ skb_to_dma(info->skb[slot], ETH_HLEN + ETH_DATA_LEN, &info->dma[slot]);
+ wmb();
+ /* Now we tell hypervisor it can use the slot. */
+ info->dma[slot].used_len = 0;
+ return 0;
+}
+
+static irqreturn_t lguestnet_rcv(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct lguestnet_info *info = netdev_priv(dev);
+ unsigned int i, done = 0;
+
+ for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+ unsigned int length;
+ struct sk_buff *skb;
+
+ length = info->dma[i].used_len;
+ if (length == 0)
+ continue;
+
+ done++;
+ skb = info->skb[i];
+ fill_slot(dev, i);
+
+ if (length < ETH_HLEN || length > ETH_HLEN + ETH_DATA_LEN) {
+ pr_debug(KERN_WARNING "%s: unbelievable skb len: %i\n",
+ dev->name, length);
+ dev_kfree_skb(skb);
+ continue;
+ }
+
+ skb_put(skb, length);
+ skb->protocol = eth_type_trans(skb, dev);
+ /* This is a reliable transport. */
+ if (dev->features & NETIF_F_NO_CSUM)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+ ntohs(skb->protocol), skb->len, skb->pkt_type);
+
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+ netif_rx(skb);
+ }
+ return done ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int lguestnet_open(struct net_device *dev)
+{
+ int i;
+ struct lguestnet_info *info = netdev_priv(dev);
+
+ /* Set up our MAC address */
+ memcpy(info->peer[info->me].mac, dev->dev_addr, ETH_ALEN);
+
+ /* Turn on promisc mode if needed */
+ lguestnet_set_multicast(dev);
+
+ for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+ if (fill_slot(dev, i) != 0)
+ goto cleanup;
+ }
+ if (lguest_bind_dma(peer_key(info,info->me), info->dma,
+ NUM_SKBS, lgdev_irq(info->lgdev)) != 0)
+ goto cleanup;
+ return 0;
+
+cleanup:
+ while (--i >= 0)
+ dev_kfree_skb(info->skb[i]);
+ return -ENOMEM;
+}
+
+static int lguestnet_close(struct net_device *dev)
+{
+ unsigned int i;
+ struct lguestnet_info *info = netdev_priv(dev);
+
+ /* Clear all trace: others might deliver packets, we'll ignore it. */
+ memset(&info->peer[info->me], 0, sizeof(info->peer[info->me]));
+
+ /* Deregister sg lists. */
+ lguest_unbind_dma(peer_key(info, info->me), info->dma);
+ for (i = 0; i < ARRAY_SIZE(info->dma); i++)
+ dev_kfree_skb(info->skb[i]);
+ return 0;
+}
+
+static int lguestnet_probe(struct lguest_device *lgdev)
+{
+ int err, irqf = IRQF_SHARED;
+ struct net_device *dev;
+ struct lguestnet_info *info;
+ struct lguest_device_desc *desc = &lguest_devices[lgdev->index];
+
+ pr_debug("lguest_net: probing for device %i\n", lgdev->index);
+
+ dev = alloc_etherdev(sizeof(struct lguestnet_info));
+ if (!dev)
+ return -ENOMEM;
+
+ SET_MODULE_OWNER(dev);
+
+ /* Ethernet defaults with some changes */
+ ether_setup(dev);
+ dev->set_mac_address = NULL;
+
+ dev->dev_addr[0] = 0x02; /* set local assignment bit (IEEE802) */
+ dev->dev_addr[1] = 0x00;
+ memcpy(&dev->dev_addr[2], &lguest_data.guestid, 2);
+ dev->dev_addr[4] = 0x00;
+ dev->dev_addr[5] = 0x00;
+
+ dev->open = lguestnet_open;
+ dev->stop = lguestnet_close;
+ dev->hard_start_xmit = lguestnet_start_xmit;
+
+ /* Turning on/off promisc will call dev->set_multicast_list.
+ * We don't actually support multicast yet */
+ dev->set_multicast_list = lguestnet_set_multicast;
+ SET_NETDEV_DEV(dev, &lgdev->dev);
+ if (desc->features & LGUEST_NET_F_NOCSUM)
+ dev->features = NETIF_F_SG|NETIF_F_NO_CSUM;
+
+ info = netdev_priv(dev);
+ info->mapsize = PAGE_SIZE * desc->num_pages;
+ info->peer_phys = ((unsigned long)desc->pfn << PAGE_SHIFT);
+ info->lgdev = lgdev;
+ info->peer = lguest_map(info->peer_phys, desc->num_pages);
+ if (!info->peer) {
+ err = -ENOMEM;
+ goto free;
+ }
+
+ /* This stores our peerid (upper bits reserved for future). */
+ info->me = (desc->features & (info->mapsize-1));
+
+ err = register_netdev(dev);
+ if (err) {
+ pr_debug("lguestnet: registering device failed\n");
+ goto unmap;
+ }
+
+ if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+ irqf |= IRQF_SAMPLE_RANDOM;
+ if (request_irq(lgdev_irq(lgdev), lguestnet_rcv, irqf, "lguestnet",
+ dev) != 0) {
+ pr_debug("lguestnet: cannot get irq %i\n", lgdev_irq(lgdev));
+ goto unregister;
+ }
+
+ pr_debug("lguestnet: registered device %s\n", dev->name);
+ lgdev->private = dev;
+ return 0;
+
+unregister:
+ unregister_netdev(dev);
+unmap:
+ lguest_unmap(info->peer);
+free:
+ free_netdev(dev);
+ return err;
+}
+
+static struct lguest_driver lguestnet_drv = {
+ .name = "lguestnet",
+ .owner = THIS_MODULE,
+ .device_type = LGUEST_DEVICE_T_NET,
+ .probe = lguestnet_probe,
+};
+
+static __init int lguestnet_init(void)
+{
+ return register_lguest_driver(&lguestnet_drv);
+}
+module_init(lguestnet_init);
+
+MODULE_DESCRIPTION("Lguest network driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 26a3b45a4a34..62c1c6262feb 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -608,7 +608,7 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
MODULE_LICENSE("GPL");
-int
+int __init
init_module(void)
{
net_debug = debug;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 0e04f7ac3f2e..a4bb0264180a 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -17,13 +17,12 @@
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
-#include <linux/mii.h>
-#include <linux/mutex.h>
#include <linux/dma-mapping.h>
-#include <linux/ethtool.h>
#include <linux/platform_device.h>
+#include <linux/phy.h>
#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
#include "macb.h"
@@ -85,172 +84,202 @@ static void __init macb_get_hwaddr(struct macb *bp)
memcpy(bp->dev->dev_addr, addr, sizeof(addr));
}
-static void macb_enable_mdio(struct macb *bp)
+static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
{
- unsigned long flags;
- u32 reg;
-
- spin_lock_irqsave(&bp->lock, flags);
- reg = macb_readl(bp, NCR);
- reg |= MACB_BIT(MPE);
- macb_writel(bp, NCR, reg);
- macb_writel(bp, IER, MACB_BIT(MFD));
- spin_unlock_irqrestore(&bp->lock, flags);
-}
-
-static void macb_disable_mdio(struct macb *bp)
-{
- unsigned long flags;
- u32 reg;
-
- spin_lock_irqsave(&bp->lock, flags);
- reg = macb_readl(bp, NCR);
- reg &= ~MACB_BIT(MPE);
- macb_writel(bp, NCR, reg);
- macb_writel(bp, IDR, MACB_BIT(MFD));
- spin_unlock_irqrestore(&bp->lock, flags);
-}
-
-static int macb_mdio_read(struct net_device *dev, int phy_id, int location)
-{
- struct macb *bp = netdev_priv(dev);
+ struct macb *bp = bus->priv;
int value;
- mutex_lock(&bp->mdio_mutex);
-
- macb_enable_mdio(bp);
macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
| MACB_BF(RW, MACB_MAN_READ)
- | MACB_BF(PHYA, phy_id)
- | MACB_BF(REGA, location)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, regnum)
| MACB_BF(CODE, MACB_MAN_CODE)));
- wait_for_completion(&bp->mdio_complete);
+ /* wait for end of transfer */
+ while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
+ cpu_relax();
value = MACB_BFEXT(DATA, macb_readl(bp, MAN));
- macb_disable_mdio(bp);
- mutex_unlock(&bp->mdio_mutex);
return value;
}
-static void macb_mdio_write(struct net_device *dev, int phy_id,
- int location, int val)
+static int macb_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
{
- struct macb *bp = netdev_priv(dev);
-
- dev_dbg(&bp->pdev->dev, "mdio_write %02x:%02x <- %04x\n",
- phy_id, location, val);
-
- mutex_lock(&bp->mdio_mutex);
- macb_enable_mdio(bp);
+ struct macb *bp = bus->priv;
macb_writel(bp, MAN, (MACB_BF(SOF, MACB_MAN_SOF)
| MACB_BF(RW, MACB_MAN_WRITE)
- | MACB_BF(PHYA, phy_id)
- | MACB_BF(REGA, location)
+ | MACB_BF(PHYA, mii_id)
+ | MACB_BF(REGA, regnum)
| MACB_BF(CODE, MACB_MAN_CODE)
- | MACB_BF(DATA, val)));
+ | MACB_BF(DATA, value)));
- wait_for_completion(&bp->mdio_complete);
+ /* wait for end of transfer */
+ while (!MACB_BFEXT(IDLE, macb_readl(bp, NSR)))
+ cpu_relax();
- macb_disable_mdio(bp);
- mutex_unlock(&bp->mdio_mutex);
+ return 0;
}
-static int macb_phy_probe(struct macb *bp)
+static int macb_mdio_reset(struct mii_bus *bus)
{
- int phy_address;
- u16 phyid1, phyid2;
+ return 0;
+}
- for (phy_address = 0; phy_address < 32; phy_address++) {
- phyid1 = macb_mdio_read(bp->dev, phy_address, MII_PHYSID1);
- phyid2 = macb_mdio_read(bp->dev, phy_address, MII_PHYSID2);
+static void macb_handle_link_change(struct net_device *dev)
+{
+ struct macb *bp = netdev_priv(dev);
+ struct phy_device *phydev = bp->phy_dev;
+ unsigned long flags;
- if (phyid1 != 0xffff && phyid1 != 0x0000
- && phyid2 != 0xffff && phyid2 != 0x0000)
- break;
+ int status_change = 0;
+
+ spin_lock_irqsave(&bp->lock, flags);
+
+ if (phydev->link) {
+ if ((bp->speed != phydev->speed) ||
+ (bp->duplex != phydev->duplex)) {
+ u32 reg;
+
+ reg = macb_readl(bp, NCFGR);
+ reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+
+ if (phydev->duplex)
+ reg |= MACB_BIT(FD);
+ if (phydev->speed)
+ reg |= MACB_BIT(SPD);
+
+ macb_writel(bp, NCFGR, reg);
+
+ bp->speed = phydev->speed;
+ bp->duplex = phydev->duplex;
+ status_change = 1;
+ }
}
- if (phy_address == 32)
- return -ENODEV;
+ if (phydev->link != bp->link) {
+ if (phydev->link)
+ netif_schedule(dev);
+ else {
+ bp->speed = 0;
+ bp->duplex = -1;
+ }
+ bp->link = phydev->link;
- dev_info(&bp->pdev->dev,
- "detected PHY at address %d (ID %04x:%04x)\n",
- phy_address, phyid1, phyid2);
+ status_change = 1;
+ }
- bp->mii.phy_id = phy_address;
- return 0;
+ spin_unlock_irqrestore(&bp->lock, flags);
+
+ if (status_change) {
+ if (phydev->link)
+ printk(KERN_INFO "%s: link up (%d/%s)\n",
+ dev->name, phydev->speed,
+ DUPLEX_FULL == phydev->duplex ? "Full":"Half");
+ else
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ }
}
-static void macb_set_media(struct macb *bp, int media)
+/* based on au1000_eth. c*/
+static int macb_mii_probe(struct net_device *dev)
{
- u32 reg;
+ struct macb *bp = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ struct eth_platform_data *pdata;
+ int phy_addr;
- spin_lock_irq(&bp->lock);
- reg = macb_readl(bp, NCFGR);
- reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
- if (media & (ADVERTISE_100HALF | ADVERTISE_100FULL))
- reg |= MACB_BIT(SPD);
- if (media & ADVERTISE_FULL)
- reg |= MACB_BIT(FD);
- macb_writel(bp, NCFGR, reg);
- spin_unlock_irq(&bp->lock);
+ /* find the first phy */
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ if (bp->mii_bus.phy_map[phy_addr]) {
+ phydev = bp->mii_bus.phy_map[phy_addr];
+ break;
+ }
+ }
+
+ if (!phydev) {
+ printk (KERN_ERR "%s: no PHY found\n", dev->name);
+ return -1;
+ }
+
+ pdata = bp->pdev->dev.platform_data;
+ /* TODO : add pin_irq */
+
+ /* attach the mac to the phy */
+ if (pdata && pdata->is_rmii) {
+ phydev = phy_connect(dev, phydev->dev.bus_id,
+ &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII);
+ } else {
+ phydev = phy_connect(dev, phydev->dev.bus_id,
+ &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII);
+ }
+
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ /* mask with MAC supported features */
+ phydev->supported &= PHY_BASIC_FEATURES;
+
+ phydev->advertising = phydev->supported;
+
+ bp->link = 0;
+ bp->speed = 0;
+ bp->duplex = -1;
+ bp->phy_dev = phydev;
+
+ return 0;
}
-static void macb_check_media(struct macb *bp, int ok_to_print, int init_media)
+static int macb_mii_init(struct macb *bp)
{
- struct mii_if_info *mii = &bp->mii;
- unsigned int old_carrier, new_carrier;
- int advertise, lpa, media, duplex;
+ struct eth_platform_data *pdata;
+ int err = -ENXIO, i;
- /* if forced media, go no further */
- if (mii->force_media)
- return;
+ /* Enable managment port */
+ macb_writel(bp, NCR, MACB_BIT(MPE));
- /* check current and old link status */
- old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
- new_carrier = (unsigned int) mii_link_ok(mii);
+ bp->mii_bus.name = "MACB_mii_bus",
+ bp->mii_bus.read = &macb_mdio_read,
+ bp->mii_bus.write = &macb_mdio_write,
+ bp->mii_bus.reset = &macb_mdio_reset,
+ bp->mii_bus.id = bp->pdev->id,
+ bp->mii_bus.priv = bp,
+ bp->mii_bus.dev = &bp->dev->dev;
+ pdata = bp->pdev->dev.platform_data;
- /* if carrier state did not change, assume nothing else did */
- if (!init_media && old_carrier == new_carrier)
- return;
+ if (pdata)
+ bp->mii_bus.phy_mask = pdata->phy_mask;
- /* no carrier, nothing much to do */
- if (!new_carrier) {
- netif_carrier_off(mii->dev);
- printk(KERN_INFO "%s: link down\n", mii->dev->name);
- return;
+ bp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ if (!bp->mii_bus.irq) {
+ err = -ENOMEM;
+ goto err_out;
}
- /*
- * we have carrier, see who's on the other end
- */
- netif_carrier_on(mii->dev);
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ bp->mii_bus.irq[i] = PHY_POLL;
- /* get MII advertise and LPA values */
- if (!init_media && mii->advertising) {
- advertise = mii->advertising;
- } else {
- advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
- mii->advertising = advertise;
- }
- lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
+ platform_set_drvdata(bp->dev, &bp->mii_bus);
- /* figure out media and duplex from advertise and LPA values */
- media = mii_nway_result(lpa & advertise);
- duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+ if (mdiobus_register(&bp->mii_bus))
+ goto err_out_free_mdio_irq;
- if (ok_to_print)
- printk(KERN_INFO "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n",
- mii->dev->name,
- media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? "100" : "10",
- duplex ? "full" : "half", lpa);
+ if (macb_mii_probe(bp->dev) != 0) {
+ goto err_out_unregister_bus;
+ }
- mii->full_duplex = duplex;
+ return 0;
- /* Let the MAC know about the new link state */
- macb_set_media(bp, media);
+err_out_unregister_bus:
+ mdiobus_unregister(&bp->mii_bus);
+err_out_free_mdio_irq:
+ kfree(bp->mii_bus.irq);
+err_out:
+ return err;
}
static void macb_update_stats(struct macb *bp)
@@ -265,16 +294,6 @@ static void macb_update_stats(struct macb *bp)
*p += __raw_readl(reg);
}
-static void macb_periodic_task(struct work_struct *work)
-{
- struct macb *bp = container_of(work, struct macb, periodic_task.work);
-
- macb_update_stats(bp);
- macb_check_media(bp, 1, 0);
-
- schedule_delayed_work(&bp->periodic_task, HZ);
-}
-
static void macb_tx(struct macb *bp)
{
unsigned int tail;
@@ -519,9 +538,6 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
spin_lock(&bp->lock);
while (status) {
- if (status & MACB_BIT(MFD))
- complete(&bp->mdio_complete);
-
/* close possible race with dev_close */
if (unlikely(!netif_running(dev))) {
macb_writel(bp, IDR, ~0UL);
@@ -535,7 +551,8 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
* until we have processed the buffers
*/
macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
- dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n");
+ dev_dbg(&bp->pdev->dev,
+ "scheduling RX softirq\n");
__netif_rx_schedule(dev);
}
}
@@ -765,7 +782,7 @@ static void macb_init_hw(struct macb *bp)
macb_writel(bp, TBQP, bp->tx_ring_dma);
/* Enable TX and RX */
- macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE));
+ macb_writel(bp, NCR, MACB_BIT(RE) | MACB_BIT(TE) | MACB_BIT(MPE));
/* Enable interrupts */
macb_writel(bp, IER, (MACB_BIT(RCOMP)
@@ -776,18 +793,126 @@ static void macb_init_hw(struct macb *bp)
| MACB_BIT(TCOMP)
| MACB_BIT(ISR_ROVR)
| MACB_BIT(HRESP)));
+
}
-static void macb_init_phy(struct net_device *dev)
+/*
+ * The hash address register is 64 bits long and takes up two
+ * locations in the memory map. The least significant bits are stored
+ * in EMAC_HSL and the most significant bits in EMAC_HSH.
+ *
+ * The unicast hash enable and the multicast hash enable bits in the
+ * network configuration register enable the reception of hash matched
+ * frames. The destination address is reduced to a 6 bit index into
+ * the 64 bit hash register using the following hash function. The
+ * hash function is an exclusive or of every sixth bit of the
+ * destination address.
+ *
+ * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47]
+ * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46]
+ * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45]
+ * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44]
+ * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43]
+ * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42]
+ *
+ * da[0] represents the least significant bit of the first byte
+ * received, that is, the multicast/unicast indicator, and da[47]
+ * represents the most significant bit of the last byte received. If
+ * the hash index, hi[n], points to a bit that is set in the hash
+ * register then the frame will be matched according to whether the
+ * frame is multicast or unicast. A multicast match will be signalled
+ * if the multicast hash enable bit is set, da[0] is 1 and the hash
+ * index points to a bit set in the hash register. A unicast match
+ * will be signalled if the unicast hash enable bit is set, da[0] is 0
+ * and the hash index points to a bit set in the hash register. To
+ * receive all multicast frames, the hash register should be set with
+ * all ones and the multicast hash enable bit should be set in the
+ * network configuration register.
+ */
+
+static inline int hash_bit_value(int bitnr, __u8 *addr)
{
+ if (addr[bitnr / 8] & (1 << (bitnr % 8)))
+ return 1;
+ return 0;
+}
+
+/*
+ * Return the hash index value for the specified address.
+ */
+static int hash_get_index(__u8 *addr)
+{
+ int i, j, bitval;
+ int hash_index = 0;
+
+ for (j = 0; j < 6; j++) {
+ for (i = 0, bitval = 0; i < 8; i++)
+ bitval ^= hash_bit_value(i*6 + j, addr);
+
+ hash_index |= (bitval << j);
+ }
+
+ return hash_index;
+}
+
+/*
+ * Add multicast addresses to the internal multicast-hash table.
+ */
+static void macb_sethashtable(struct net_device *dev)
+{
+ struct dev_mc_list *curr;
+ unsigned long mc_filter[2];
+ unsigned int i, bitnr;
+ struct macb *bp = netdev_priv(dev);
+
+ mc_filter[0] = mc_filter[1] = 0;
+
+ curr = dev->mc_list;
+ for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
+ if (!curr) break; /* unexpected end of list */
+
+ bitnr = hash_get_index(curr->dmi_addr);
+ mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
+ }
+
+ macb_writel(bp, HRB, mc_filter[0]);
+ macb_writel(bp, HRT, mc_filter[1]);
+}
+
+/*
+ * Enable/Disable promiscuous and multicast modes.
+ */
+static void macb_set_rx_mode(struct net_device *dev)
+{
+ unsigned long cfg;
struct macb *bp = netdev_priv(dev);
- /* Set some reasonable default settings */
- macb_mdio_write(dev, bp->mii.phy_id, MII_ADVERTISE,
- ADVERTISE_CSMA | ADVERTISE_ALL);
- macb_mdio_write(dev, bp->mii.phy_id, MII_BMCR,
- (BMCR_SPEED100 | BMCR_ANENABLE
- | BMCR_ANRESTART | BMCR_FULLDPLX));
+ cfg = macb_readl(bp, NCFGR);
+
+ if (dev->flags & IFF_PROMISC)
+ /* Enable promiscuous mode */
+ cfg |= MACB_BIT(CAF);
+ else if (dev->flags & (~IFF_PROMISC))
+ /* Disable promiscuous mode */
+ cfg &= ~MACB_BIT(CAF);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /* Enable all multicast mode */
+ macb_writel(bp, HRB, -1);
+ macb_writel(bp, HRT, -1);
+ cfg |= MACB_BIT(NCFGR_MTI);
+ } else if (dev->mc_count > 0) {
+ /* Enable specific multicasts */
+ macb_sethashtable(dev);
+ cfg |= MACB_BIT(NCFGR_MTI);
+ } else if (dev->flags & (~IFF_ALLMULTI)) {
+ /* Disable all multicast mode */
+ macb_writel(bp, HRB, 0);
+ macb_writel(bp, HRT, 0);
+ cfg &= ~MACB_BIT(NCFGR_MTI);
+ }
+
+ macb_writel(bp, NCFGR, cfg);
}
static int macb_open(struct net_device *dev)
@@ -797,6 +922,10 @@ static int macb_open(struct net_device *dev)
dev_dbg(&bp->pdev->dev, "open\n");
+ /* if the phy is not yet register, retry later*/
+ if (!bp->phy_dev)
+ return -EAGAIN;
+
if (!is_valid_ether_addr(dev->dev_addr))
return -EADDRNOTAVAIL;
@@ -810,12 +939,11 @@ static int macb_open(struct net_device *dev)
macb_init_rings(bp);
macb_init_hw(bp);
- macb_init_phy(dev);
- macb_check_media(bp, 1, 1);
- netif_start_queue(dev);
+ /* schedule a link state check */
+ phy_start(bp->phy_dev);
- schedule_delayed_work(&bp->periodic_task, HZ);
+ netif_start_queue(dev);
return 0;
}
@@ -825,10 +953,11 @@ static int macb_close(struct net_device *dev)
struct macb *bp = netdev_priv(dev);
unsigned long flags;
- cancel_rearming_delayed_work(&bp->periodic_task);
-
netif_stop_queue(dev);
+ if (bp->phy_dev)
+ phy_stop(bp->phy_dev);
+
spin_lock_irqsave(&bp->lock, flags);
macb_reset_hw(bp);
netif_carrier_off(dev);
@@ -845,6 +974,9 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
struct net_device_stats *nstat = &bp->stats;
struct macb_stats *hwstat = &bp->hw_stats;
+ /* read stats from hardware */
+ macb_update_stats(bp);
+
/* Convert HW stats into netdevice stats */
nstat->rx_errors = (hwstat->rx_fcs_errors +
hwstat->rx_align_errors +
@@ -882,18 +1014,27 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct macb *bp = netdev_priv(dev);
+ struct phy_device *phydev = bp->phy_dev;
- return mii_ethtool_gset(&bp->mii, cmd);
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_ethtool_gset(phydev, cmd);
}
static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct macb *bp = netdev_priv(dev);
+ struct phy_device *phydev = bp->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
- return mii_ethtool_sset(&bp->mii, cmd);
+ return phy_ethtool_sset(phydev, cmd);
}
-static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+static void macb_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
{
struct macb *bp = netdev_priv(dev);
@@ -902,104 +1043,34 @@ static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *inf
strcpy(info->bus_info, bp->pdev->dev.bus_id);
}
-static int macb_nway_reset(struct net_device *dev)
-{
- struct macb *bp = netdev_priv(dev);
- return mii_nway_restart(&bp->mii);
-}
-
static struct ethtool_ops macb_ethtool_ops = {
.get_settings = macb_get_settings,
.set_settings = macb_set_settings,
.get_drvinfo = macb_get_drvinfo,
- .nway_reset = macb_nway_reset,
.get_link = ethtool_op_get_link,
};
static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct macb *bp = netdev_priv(dev);
+ struct phy_device *phydev = bp->phy_dev;
if (!netif_running(dev))
return -EINVAL;
- return generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL);
-}
-
-static ssize_t macb_mii_show(const struct device *_dev, char *buf,
- unsigned long addr)
-{
- struct net_device *dev = to_net_dev(_dev);
- struct macb *bp = netdev_priv(dev);
- ssize_t ret = -EINVAL;
-
- if (netif_running(dev)) {
- int value;
- value = macb_mdio_read(dev, bp->mii.phy_id, addr);
- ret = sprintf(buf, "0x%04x\n", (uint16_t)value);
- }
-
- return ret;
-}
-
-#define MII_ENTRY(name, addr) \
-static ssize_t show_##name(struct device *_dev, \
- struct device_attribute *attr, \
- char *buf) \
-{ \
- return macb_mii_show(_dev, buf, addr); \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
-
-MII_ENTRY(bmcr, MII_BMCR);
-MII_ENTRY(bmsr, MII_BMSR);
-MII_ENTRY(physid1, MII_PHYSID1);
-MII_ENTRY(physid2, MII_PHYSID2);
-MII_ENTRY(advertise, MII_ADVERTISE);
-MII_ENTRY(lpa, MII_LPA);
-MII_ENTRY(expansion, MII_EXPANSION);
-
-static struct attribute *macb_mii_attrs[] = {
- &dev_attr_bmcr.attr,
- &dev_attr_bmsr.attr,
- &dev_attr_physid1.attr,
- &dev_attr_physid2.attr,
- &dev_attr_advertise.attr,
- &dev_attr_lpa.attr,
- &dev_attr_expansion.attr,
- NULL,
-};
-
-static struct attribute_group macb_mii_group = {
- .name = "mii",
- .attrs = macb_mii_attrs,
-};
-
-static void macb_unregister_sysfs(struct net_device *net)
-{
- struct device *_dev = &net->dev;
+ if (!phydev)
+ return -ENODEV;
- sysfs_remove_group(&_dev->kobj, &macb_mii_group);
+ return phy_mii_ioctl(phydev, if_mii(rq), cmd);
}
-static int macb_register_sysfs(struct net_device *net)
-{
- struct device *_dev = &net->dev;
- int ret;
-
- ret = sysfs_create_group(&_dev->kobj, &macb_mii_group);
- if (ret)
- printk(KERN_WARNING
- "%s: sysfs mii attribute registration failed: %d\n",
- net->name, ret);
- return ret;
-}
static int __devinit macb_probe(struct platform_device *pdev)
{
struct eth_platform_data *pdata;
struct resource *regs;
struct net_device *dev;
struct macb *bp;
+ struct phy_device *phydev;
unsigned long pclk_hz;
u32 config;
int err = -ENXIO;
@@ -1073,6 +1144,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->stop = macb_close;
dev->hard_start_xmit = macb_start_xmit;
dev->get_stats = macb_get_stats;
+ dev->set_multicast_list = macb_set_rx_mode;
dev->do_ioctl = macb_ioctl;
dev->poll = macb_poll;
dev->weight = 64;
@@ -1080,10 +1152,6 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->base_addr = regs->start;
- INIT_DELAYED_WORK(&bp->periodic_task, macb_periodic_task);
- mutex_init(&bp->mdio_mutex);
- init_completion(&bp->mdio_complete);
-
/* Set MII management clock divider */
pclk_hz = clk_get_rate(bp->pclk);
if (pclk_hz <= 20000000)
@@ -1096,20 +1164,9 @@ static int __devinit macb_probe(struct platform_device *pdev)
config = MACB_BF(CLK, MACB_CLK_DIV64);
macb_writel(bp, NCFGR, config);
- bp->mii.dev = dev;
- bp->mii.mdio_read = macb_mdio_read;
- bp->mii.mdio_write = macb_mdio_write;
- bp->mii.phy_id_mask = 0x1f;
- bp->mii.reg_num_mask = 0x1f;
-
macb_get_hwaddr(bp);
- err = macb_phy_probe(bp);
- if (err) {
- dev_err(&pdev->dev, "Failed to detect PHY, aborting.\n");
- goto err_out_free_irq;
- }
-
pdata = pdev->dev.platform_data;
+
if (pdata && pdata->is_rmii)
#if defined(CONFIG_ARCH_AT91)
macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
@@ -1131,9 +1188,11 @@ static int __devinit macb_probe(struct platform_device *pdev)
goto err_out_free_irq;
}
- platform_set_drvdata(pdev, dev);
+ if (macb_mii_init(bp) != 0) {
+ goto err_out_unregister_netdev;
+ }
- macb_register_sysfs(dev);
+ platform_set_drvdata(pdev, dev);
printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d "
"(%02x:%02x:%02x:%02x:%02x:%02x)\n",
@@ -1141,8 +1200,15 @@ static int __devinit macb_probe(struct platform_device *pdev)
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ phydev = bp->phy_dev;
+ printk(KERN_INFO "%s: attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s, irq=%d)\n",
+ dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+
return 0;
+err_out_unregister_netdev:
+ unregister_netdev(dev);
err_out_free_irq:
free_irq(dev->irq, dev);
err_out_iounmap:
@@ -1153,7 +1219,9 @@ err_out_disable_clocks:
clk_put(bp->hclk);
#endif
clk_disable(bp->pclk);
+#ifndef CONFIG_ARCH_AT91
err_out_put_pclk:
+#endif
clk_put(bp->pclk);
err_out_free_dev:
free_netdev(dev);
@@ -1171,7 +1239,8 @@ static int __devexit macb_remove(struct platform_device *pdev)
if (dev) {
bp = netdev_priv(dev);
- macb_unregister_sysfs(dev);
+ mdiobus_unregister(&bp->mii_bus);
+ kfree(bp->mii_bus.irq);
unregister_netdev(dev);
free_irq(dev->irq, dev);
iounmap(bp->regs);
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index b3bb2182edd1..4e3283ebd97c 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -383,11 +383,11 @@ struct macb {
unsigned int rx_pending, tx_pending;
- struct delayed_work periodic_task;
-
- struct mutex mdio_mutex;
- struct completion mdio_complete;
- struct mii_if_info mii;
+ struct mii_bus mii_bus;
+ struct phy_device *phy_dev;
+ unsigned int link;
+ unsigned int speed;
+ unsigned int duplex;
};
#endif /* _MACB_H */
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
new file mode 100644
index 000000000000..dc74d006e01f
--- /dev/null
+++ b/drivers/net/macvlan.c
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * The code this is based on carried the following copyright notice:
+ * ---
+ * (C) Copyright 2001-2006
+ * Alex Zeffertt, Cambridge Broadband Ltd, ajz@cambridgebroadband.com
+ * Re-worked by Ben Greear <greearb@candelatech.com>
+ * ---
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_arp.h>
+#include <linux/if_link.h>
+#include <linux/if_macvlan.h>
+#include <net/rtnetlink.h>
+
+#define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE)
+
+struct macvlan_port {
+ struct net_device *dev;
+ struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
+ struct list_head vlans;
+};
+
+struct macvlan_dev {
+ struct net_device *dev;
+ struct list_head list;
+ struct hlist_node hlist;
+ struct macvlan_port *port;
+ struct net_device *lowerdev;
+};
+
+
+static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
+ const unsigned char *addr)
+{
+ struct macvlan_dev *vlan;
+ struct hlist_node *n;
+
+ hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[addr[5]], hlist) {
+ if (!compare_ether_addr(vlan->dev->dev_addr, addr))
+ return vlan;
+ }
+ return NULL;
+}
+
+static void macvlan_broadcast(struct sk_buff *skb,
+ const struct macvlan_port *port)
+{
+ const struct ethhdr *eth = eth_hdr(skb);
+ const struct macvlan_dev *vlan;
+ struct hlist_node *n;
+ struct net_device *dev;
+ struct sk_buff *nskb;
+ unsigned int i;
+
+ for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
+ hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
+ dev = vlan->dev;
+ if (unlikely(!(dev->flags & IFF_UP)))
+ continue;
+
+ nskb = skb_clone(skb, GFP_ATOMIC);
+ if (nskb == NULL) {
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
+ continue;
+ }
+
+ dev->stats.rx_bytes += skb->len + ETH_HLEN;
+ dev->stats.rx_packets++;
+ dev->stats.multicast++;
+ dev->last_rx = jiffies;
+
+ nskb->dev = dev;
+ if (!compare_ether_addr(eth->h_dest, dev->broadcast))
+ nskb->pkt_type = PACKET_BROADCAST;
+ else
+ nskb->pkt_type = PACKET_MULTICAST;
+
+ netif_rx(nskb);
+ }
+ }
+}
+
+/* called under rcu_read_lock() from netif_receive_skb */
+static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
+{
+ const struct ethhdr *eth = eth_hdr(skb);
+ const struct macvlan_port *port;
+ const struct macvlan_dev *vlan;
+ struct net_device *dev;
+
+ port = rcu_dereference(skb->dev->macvlan_port);
+ if (port == NULL)
+ return skb;
+
+ if (is_multicast_ether_addr(eth->h_dest)) {
+ macvlan_broadcast(skb, port);
+ return skb;
+ }
+
+ vlan = macvlan_hash_lookup(port, eth->h_dest);
+ if (vlan == NULL)
+ return skb;
+
+ dev = vlan->dev;
+ if (unlikely(!(dev->flags & IFF_UP))) {
+ kfree_skb(skb);
+ return NULL;
+ }
+
+ skb = skb_share_check(skb, GFP_ATOMIC);
+ if (skb == NULL) {
+ dev->stats.rx_errors++;
+ dev->stats.rx_dropped++;
+ return NULL;
+ }
+
+ dev->stats.rx_bytes += skb->len + ETH_HLEN;
+ dev->stats.rx_packets++;
+ dev->last_rx = jiffies;
+
+ skb->dev = dev;
+ skb->pkt_type = PACKET_HOST;
+
+ netif_rx(skb);
+ return NULL;
+}
+
+static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ unsigned int len = skb->len;
+ int ret;
+
+ skb->dev = vlan->lowerdev;
+ ret = dev_queue_xmit(skb);
+
+ if (likely(ret == NET_XMIT_SUCCESS)) {
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += len;
+ } else {
+ dev->stats.tx_errors++;
+ dev->stats.tx_aborted_errors++;
+ }
+ return NETDEV_TX_OK;
+}
+
+static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, void *daddr, void *saddr,
+ unsigned len)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ return lowerdev->hard_header(skb, lowerdev, type, daddr,
+ saddr ? : dev->dev_addr, len);
+}
+
+static int macvlan_open(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port = vlan->port;
+ struct net_device *lowerdev = vlan->lowerdev;
+ int err;
+
+ err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
+ if (err < 0)
+ return err;
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(lowerdev, 1);
+
+ hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
+ return 0;
+}
+
+static int macvlan_stop(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ dev_mc_unsync(lowerdev, dev);
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(lowerdev, -1);
+
+ dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+
+ hlist_del_rcu(&vlan->hlist);
+ synchronize_rcu();
+ return 0;
+}
+
+static void macvlan_change_rx_flags(struct net_device *dev, int change)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ if (change & IFF_ALLMULTI)
+ dev_set_allmulti(lowerdev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+}
+
+static void macvlan_set_multicast_list(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+
+ dev_mc_sync(vlan->lowerdev, dev);
+}
+
+static int macvlan_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+
+ if (new_mtu < 68 || vlan->lowerdev->mtu < new_mtu)
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/*
+ * macvlan network devices have devices nesting below it and are a special
+ * "super class" of normal network devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key macvlan_netdev_xmit_lock_key;
+
+#define MACVLAN_FEATURES \
+ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
+ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
+ NETIF_F_TSO_ECN | NETIF_F_TSO6)
+
+#define MACVLAN_STATE_MASK \
+ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
+
+static int macvlan_init(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ const struct net_device *lowerdev = vlan->lowerdev;
+
+ dev->state = (dev->state & ~MACVLAN_STATE_MASK) |
+ (lowerdev->state & MACVLAN_STATE_MASK);
+ dev->features = lowerdev->features & MACVLAN_FEATURES;
+ dev->iflink = lowerdev->ifindex;
+
+ lockdep_set_class(&dev->_xmit_lock, &macvlan_netdev_xmit_lock_key);
+ return 0;
+}
+
+static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ snprintf(drvinfo->driver, 32, "macvlan");
+ snprintf(drvinfo->version, 32, "0.1");
+}
+
+static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
+{
+ const struct macvlan_dev *vlan = netdev_priv(dev);
+ struct net_device *lowerdev = vlan->lowerdev;
+
+ if (lowerdev->ethtool_ops->get_rx_csum == NULL)
+ return 0;
+ return lowerdev->ethtool_ops->get_rx_csum(lowerdev);
+}
+
+static const struct ethtool_ops macvlan_ethtool_ops = {
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = macvlan_ethtool_get_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_tso = ethtool_op_get_tso,
+ .get_ufo = ethtool_op_get_ufo,
+ .get_sg = ethtool_op_get_sg,
+ .get_drvinfo = macvlan_ethtool_get_drvinfo,
+};
+
+static void macvlan_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+
+ dev->init = macvlan_init;
+ dev->open = macvlan_open;
+ dev->stop = macvlan_stop;
+ dev->change_mtu = macvlan_change_mtu;
+ dev->change_rx_flags = macvlan_change_rx_flags;
+ dev->set_multicast_list = macvlan_set_multicast_list;
+ dev->hard_header = macvlan_hard_header;
+ dev->hard_start_xmit = macvlan_hard_start_xmit;
+ dev->destructor = free_netdev;
+ dev->ethtool_ops = &macvlan_ethtool_ops;
+ dev->tx_queue_len = 0;
+}
+
+static int macvlan_port_create(struct net_device *dev)
+{
+ struct macvlan_port *port;
+ unsigned int i;
+
+ if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK)
+ return -EINVAL;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (port == NULL)
+ return -ENOMEM;
+
+ port->dev = dev;
+ INIT_LIST_HEAD(&port->vlans);
+ for (i = 0; i < MACVLAN_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&port->vlan_hash[i]);
+ rcu_assign_pointer(dev->macvlan_port, port);
+ return 0;
+}
+
+static void macvlan_port_destroy(struct net_device *dev)
+{
+ struct macvlan_port *port = dev->macvlan_port;
+
+ rcu_assign_pointer(dev->macvlan_port, NULL);
+ synchronize_rcu();
+ kfree(port);
+}
+
+static void macvlan_transfer_operstate(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ const struct net_device *lowerdev = vlan->lowerdev;
+
+ if (lowerdev->operstate == IF_OPER_DORMANT)
+ netif_dormant_on(dev);
+ else
+ netif_dormant_off(dev);
+
+ if (netif_carrier_ok(lowerdev)) {
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ } else {
+ if (netif_carrier_ok(lowerdev))
+ netif_carrier_off(dev);
+ }
+}
+
+static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+ return 0;
+}
+
+static int macvlan_newlink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port;
+ struct net_device *lowerdev;
+ int err;
+
+ if (!tb[IFLA_LINK])
+ return -EINVAL;
+
+ lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+ if (lowerdev == NULL)
+ return -ENODEV;
+
+ if (!tb[IFLA_MTU])
+ dev->mtu = lowerdev->mtu;
+ else if (dev->mtu > lowerdev->mtu)
+ return -EINVAL;
+
+ if (!tb[IFLA_ADDRESS])
+ random_ether_addr(dev->dev_addr);
+
+ if (lowerdev->macvlan_port == NULL) {
+ err = macvlan_port_create(lowerdev);
+ if (err < 0)
+ return err;
+ }
+ port = lowerdev->macvlan_port;
+
+ vlan->lowerdev = lowerdev;
+ vlan->dev = dev;
+ vlan->port = port;
+
+ err = register_netdevice(dev);
+ if (err < 0)
+ return err;
+
+ list_add_tail(&vlan->list, &port->vlans);
+ macvlan_transfer_operstate(dev);
+ return 0;
+}
+
+static void macvlan_dellink(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port = vlan->port;
+
+ list_del(&vlan->list);
+ unregister_netdevice(dev);
+
+ if (list_empty(&port->vlans))
+ macvlan_port_destroy(dev);
+}
+
+static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
+ .kind = "macvlan",
+ .priv_size = sizeof(struct macvlan_dev),
+ .setup = macvlan_setup,
+ .validate = macvlan_validate,
+ .newlink = macvlan_newlink,
+ .dellink = macvlan_dellink,
+};
+
+static int macvlan_device_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct macvlan_dev *vlan, *next;
+ struct macvlan_port *port;
+
+ port = dev->macvlan_port;
+ if (port == NULL)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_CHANGE:
+ list_for_each_entry(vlan, &port->vlans, list)
+ macvlan_transfer_operstate(vlan->dev);
+ break;
+ case NETDEV_FEAT_CHANGE:
+ list_for_each_entry(vlan, &port->vlans, list) {
+ vlan->dev->features = dev->features & MACVLAN_FEATURES;
+ netdev_features_change(vlan->dev);
+ }
+ break;
+ case NETDEV_UNREGISTER:
+ list_for_each_entry_safe(vlan, next, &port->vlans, list)
+ macvlan_dellink(vlan->dev);
+ break;
+ }
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block macvlan_notifier_block __read_mostly = {
+ .notifier_call = macvlan_device_event,
+};
+
+static int __init macvlan_init_module(void)
+{
+ int err;
+
+ register_netdevice_notifier(&macvlan_notifier_block);
+ macvlan_handle_frame_hook = macvlan_handle_frame;
+
+ err = rtnl_link_register(&macvlan_link_ops);
+ if (err < 0)
+ goto err1;
+ return 0;
+err1:
+ macvlan_handle_frame_hook = macvlan_handle_frame;
+ unregister_netdevice_notifier(&macvlan_notifier_block);
+ return err;
+}
+
+static void __exit macvlan_cleanup_module(void)
+{
+ rtnl_link_unregister(&macvlan_link_ops);
+ macvlan_handle_frame_hook = NULL;
+ unregister_netdevice_notifier(&macvlan_notifier_block);
+}
+
+module_init(macvlan_init_module);
+module_exit(macvlan_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
+MODULE_DESCRIPTION("Driver for MAC address based VLANs");
+MODULE_ALIAS_RTNL_LINK("macvlan");
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
index 1bb088aeaf71..6b32ec94b3a8 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/mlx4/catas.c
@@ -30,41 +30,133 @@
* SOFTWARE.
*/
+#include <linux/workqueue.h>
+
#include "mlx4.h"
-void mlx4_handle_catas_err(struct mlx4_dev *dev)
+enum {
+ MLX4_CATAS_POLL_INTERVAL = 5 * HZ,
+};
+
+static DEFINE_SPINLOCK(catas_lock);
+
+static LIST_HEAD(catas_list);
+static struct workqueue_struct *catas_wq;
+static struct work_struct catas_work;
+
+static int internal_err_reset = 1;
+module_param(internal_err_reset, int, 0644);
+MODULE_PARM_DESC(internal_err_reset,
+ "Reset device on internal errors if non-zero (default 1)");
+
+static void dump_err_buf(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
int i;
- mlx4_err(dev, "Catastrophic error detected:\n");
+ mlx4_err(dev, "Internal error detected:\n");
for (i = 0; i < priv->fw.catas_size; ++i)
mlx4_err(dev, " buf[%02x]: %08x\n",
i, swab32(readl(priv->catas_err.map + i)));
+}
- mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+static void poll_catas(unsigned long dev_ptr)
+{
+ struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ if (readl(priv->catas_err.map)) {
+ dump_err_buf(dev);
+
+ mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+
+ if (internal_err_reset) {
+ spin_lock(&catas_lock);
+ list_add(&priv->catas_err.list, &catas_list);
+ spin_unlock(&catas_lock);
+
+ queue_work(catas_wq, &catas_work);
+ }
+ } else
+ mod_timer(&priv->catas_err.timer,
+ round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
}
-void mlx4_map_catas_buf(struct mlx4_dev *dev)
+static void catas_reset(struct work_struct *work)
+{
+ struct mlx4_priv *priv, *tmppriv;
+ struct mlx4_dev *dev;
+
+ LIST_HEAD(tlist);
+ int ret;
+
+ spin_lock_irq(&catas_lock);
+ list_splice_init(&catas_list, &tlist);
+ spin_unlock_irq(&catas_lock);
+
+ list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
+ ret = mlx4_restart_one(priv->dev.pdev);
+ dev = &priv->dev;
+ if (ret)
+ mlx4_err(dev, "Reset failed (%d)\n", ret);
+ else
+ mlx4_dbg(dev, "Reset succeeded\n");
+ }
+}
+
+void mlx4_start_catas_poll(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
unsigned long addr;
+ INIT_LIST_HEAD(&priv->catas_err.list);
+ init_timer(&priv->catas_err.timer);
+ priv->catas_err.map = NULL;
+
addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) +
priv->fw.catas_offset;
priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
- if (!priv->catas_err.map)
- mlx4_warn(dev, "Failed to map catastrophic error buffer at 0x%lx\n",
+ if (!priv->catas_err.map) {
+ mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n",
addr);
+ return;
+ }
+ priv->catas_err.timer.data = (unsigned long) dev;
+ priv->catas_err.timer.function = poll_catas;
+ priv->catas_err.timer.expires =
+ round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL);
+ add_timer(&priv->catas_err.timer);
}
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev)
+void mlx4_stop_catas_poll(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
+ del_timer_sync(&priv->catas_err.timer);
+
if (priv->catas_err.map)
iounmap(priv->catas_err.map);
+
+ spin_lock_irq(&catas_lock);
+ list_del(&priv->catas_err.list);
+ spin_unlock_irq(&catas_lock);
+}
+
+int __init mlx4_catas_init(void)
+{
+ INIT_WORK(&catas_work, catas_reset);
+
+ catas_wq = create_singlethread_workqueue("mlx4_err");
+ if (!catas_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx4_catas_cleanup(void)
+{
+ destroy_workqueue(catas_wq);
}
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
index c1f81a993f5d..a9f31753661a 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/mlx4/cmd.c
@@ -246,8 +246,6 @@ void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param)
context->result = mlx4_status_to_errno(status);
context->out_param = out_param;
- context->token += priv->cmd.token_mask + 1;
-
complete(&context->done);
}
@@ -264,6 +262,7 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
spin_lock(&cmd->context_lock);
BUG_ON(cmd->free_head < 0);
context = &cmd->context[cmd->free_head];
+ context->token += cmd->token_mask + 1;
cmd->free_head = context->next;
spin_unlock(&cmd->context_lock);
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 27a82cecd693..2095c843fa15 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -89,14 +89,12 @@ struct mlx4_eq_context {
(1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \
(1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
(1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \
- (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR) | \
(1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \
(1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \
(1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \
(1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \
(1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \
(1ull << MLX4_EVENT_TYPE_CMD))
-#define MLX4_CATAS_EVENT_MASK (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)
struct mlx4_eqe {
u8 reserved1;
@@ -264,7 +262,7 @@ static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr)
writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
return IRQ_RETVAL(work);
@@ -281,14 +279,6 @@ static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr)
return IRQ_HANDLED;
}
-static irqreturn_t mlx4_catas_interrupt(int irq, void *dev_ptr)
-{
- mlx4_handle_catas_err(dev_ptr);
-
- /* MSI-X vectors always belong to us */
- return IRQ_HANDLED;
-}
-
static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
int eq_num)
{
@@ -490,11 +480,9 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
if (eq_table->have_irq)
free_irq(dev->pdev->irq, dev);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
if (eq_table->eq[i].have_irq)
free_irq(eq_table->eq[i].irq, eq_table->eq + i);
- if (eq_table->eq[MLX4_EQ_CATAS].have_irq)
- free_irq(eq_table->eq[MLX4_EQ_CATAS].irq, dev);
}
static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev)
@@ -598,32 +586,19 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
if (dev->flags & MLX4_FLAG_MSI_X) {
static const char *eq_name[] = {
[MLX4_EQ_COMP] = DRV_NAME " (comp)",
- [MLX4_EQ_ASYNC] = DRV_NAME " (async)",
- [MLX4_EQ_CATAS] = DRV_NAME " (catas)"
+ [MLX4_EQ_ASYNC] = DRV_NAME " (async)"
};
- err = mlx4_create_eq(dev, 1, MLX4_EQ_CATAS,
- &priv->eq_table.eq[MLX4_EQ_CATAS]);
- if (err)
- goto err_out_async;
-
- for (i = 0; i < MLX4_EQ_CATAS; ++i) {
+ for (i = 0; i < MLX4_NUM_EQ; ++i) {
err = request_irq(priv->eq_table.eq[i].irq,
mlx4_msi_x_interrupt,
0, eq_name[i], priv->eq_table.eq + i);
if (err)
- goto err_out_catas;
+ goto err_out_async;
priv->eq_table.eq[i].have_irq = 1;
}
- err = request_irq(priv->eq_table.eq[MLX4_EQ_CATAS].irq,
- mlx4_catas_interrupt, 0,
- eq_name[MLX4_EQ_CATAS], dev);
- if (err)
- goto err_out_catas;
-
- priv->eq_table.eq[MLX4_EQ_CATAS].have_irq = 1;
} else {
err = request_irq(dev->pdev->irq, mlx4_interrupt,
IRQF_SHARED, DRV_NAME, dev);
@@ -639,22 +614,11 @@ int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
eq_set_ci(&priv->eq_table.eq[i], 1);
- if (dev->flags & MLX4_FLAG_MSI_X) {
- err = mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 0,
- priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
- if (err)
- mlx4_warn(dev, "MAP_EQ for catas EQ %d failed (%d)\n",
- priv->eq_table.eq[MLX4_EQ_CATAS].eqn, err);
- }
-
return 0;
-err_out_catas:
- mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
-
err_out_async:
mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
@@ -675,19 +639,13 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
int i;
- if (dev->flags & MLX4_FLAG_MSI_X)
- mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 1,
- priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-
mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
mlx4_free_irqs(dev);
- for (i = 0; i < MLX4_EQ_CATAS; ++i)
+ for (i = 0; i < MLX4_NUM_EQ; ++i)
mlx4_free_eq(dev, &priv->eq_table.eq[i]);
- if (dev->flags & MLX4_FLAG_MSI_X)
- mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
mlx4_unmap_clr_int(dev);
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index d2b065351e45..c45cbe43a0c4 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -138,6 +138,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
#define QUERY_DEV_CAP_ACK_DELAY_OFFSET 0x35
#define QUERY_DEV_CAP_MTU_WIDTH_OFFSET 0x36
#define QUERY_DEV_CAP_VL_PORT_OFFSET 0x37
+#define QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET 0x38
#define QUERY_DEV_CAP_MAX_GID_OFFSET 0x3b
#define QUERY_DEV_CAP_RATE_SUPPORT_OFFSET 0x3c
#define QUERY_DEV_CAP_MAX_PKEY_OFFSET 0x3f
@@ -220,6 +221,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->local_ca_ack_delay = field & 0x1f;
MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
dev_cap->num_ports = field & 0xf;
+ MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET);
+ dev_cap->max_msg_sz = 1 << (field & 0x1f);
MLX4_GET(stat_rate, outbox, QUERY_DEV_CAP_RATE_SUPPORT_OFFSET);
dev_cap->stat_rate_support = stat_rate;
MLX4_GET(dev_cap->flags, outbox, QUERY_DEV_CAP_FLAGS_OFFSET);
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
index 296254ac27c1..7e1dd9e25cfb 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/mlx4/fw.h
@@ -60,6 +60,7 @@ struct mlx4_dev_cap {
int max_rdma_global;
int local_ca_ack_delay;
int num_ports;
+ u32 max_msg_sz;
int max_mtu[MLX4_MAX_PORTS + 1];
int max_port_width[MLX4_MAX_PORTS + 1];
int max_vl[MLX4_MAX_PORTS + 1];
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c
index 9ae951bf6aa6..be5d9e90ccf2 100644
--- a/drivers/net/mlx4/intf.c
+++ b/drivers/net/mlx4/intf.c
@@ -142,6 +142,7 @@ int mlx4_register_device(struct mlx4_dev *dev)
mlx4_add_device(intf, priv);
mutex_unlock(&intf_mutex);
+ mlx4_start_catas_poll(dev);
return 0;
}
@@ -151,6 +152,7 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_interface *intf;
+ mlx4_stop_catas_poll(dev);
mutex_lock(&intf_mutex);
list_for_each_entry(intf, &intf_list, list)
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index c3da2a2f5431..4dc9dc19b716 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -78,7 +78,7 @@ static const char mlx4_version[] __devinitdata =
static struct mlx4_profile default_profile = {
.num_qp = 1 << 16,
.num_srq = 1 << 16,
- .rdmarc_per_qp = 4,
+ .rdmarc_per_qp = 1 << 4,
.num_cq = 1 << 16,
.num_mcg = 1 << 13,
.num_mpt = 1 << 17,
@@ -154,6 +154,7 @@ static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev
dev->caps.reserved_uars = dev_cap->reserved_uars;
dev->caps.reserved_pds = dev_cap->reserved_pds;
dev->caps.mtt_entry_sz = MLX4_MTT_ENTRY_PER_SEG * dev_cap->mtt_entry_sz;
+ dev->caps.max_msg_sz = dev_cap->max_msg_sz;
dev->caps.page_size_cap = ~(u32) (dev_cap->min_page_sz - 1);
dev->caps.flags = dev_cap->flags;
dev->caps.stat_rate_support = dev_cap->stat_rate_support;
@@ -582,13 +583,11 @@ static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
goto err_pd_table_free;
}
- mlx4_map_catas_buf(dev);
-
err = mlx4_init_eq_table(dev);
if (err) {
mlx4_err(dev, "Failed to initialize "
"event queue table, aborting.\n");
- goto err_catas_buf;
+ goto err_mr_table_free;
}
err = mlx4_cmd_use_events(dev);
@@ -658,8 +657,7 @@ err_cmd_poll:
err_eq_table_free:
mlx4_cleanup_eq_table(dev);
-err_catas_buf:
- mlx4_unmap_catas_buf(dev);
+err_mr_table_free:
mlx4_cleanup_mr_table(dev);
err_pd_table_free:
@@ -835,9 +833,6 @@ err_cleanup:
mlx4_cleanup_cq_table(dev);
mlx4_cmd_use_polling(dev);
mlx4_cleanup_eq_table(dev);
-
- mlx4_unmap_catas_buf(dev);
-
mlx4_cleanup_mr_table(dev);
mlx4_cleanup_pd_table(dev);
mlx4_cleanup_uar_table(dev);
@@ -884,9 +879,6 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
mlx4_cleanup_cq_table(dev);
mlx4_cmd_use_polling(dev);
mlx4_cleanup_eq_table(dev);
-
- mlx4_unmap_catas_buf(dev);
-
mlx4_cleanup_mr_table(dev);
mlx4_cleanup_pd_table(dev);
@@ -907,6 +899,12 @@ static void __devexit mlx4_remove_one(struct pci_dev *pdev)
}
}
+int mlx4_restart_one(struct pci_dev *pdev)
+{
+ mlx4_remove_one(pdev);
+ return mlx4_init_one(pdev, NULL);
+}
+
static struct pci_device_id mlx4_pci_table[] = {
{ PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
{ PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
@@ -929,6 +927,10 @@ static int __init mlx4_init(void)
{
int ret;
+ ret = mlx4_catas_init();
+ if (ret)
+ return ret;
+
ret = pci_register_driver(&mlx4_driver);
return ret < 0 ? ret : 0;
}
@@ -936,6 +938,7 @@ static int __init mlx4_init(void)
static void __exit mlx4_cleanup(void)
{
pci_unregister_driver(&mlx4_driver);
+ mlx4_catas_cleanup();
}
module_init(mlx4_init);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 3d3b6d24d8d3..be304a7c2c91 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -37,7 +37,9 @@
#ifndef MLX4_H
#define MLX4_H
+#include <linux/mutex.h>
#include <linux/radix-tree.h>
+#include <linux/timer.h>
#include <linux/mlx4/device.h>
#include <linux/mlx4/doorbell.h>
@@ -66,7 +68,6 @@ enum {
enum {
MLX4_EQ_ASYNC,
MLX4_EQ_COMP,
- MLX4_EQ_CATAS,
MLX4_NUM_EQ
};
@@ -247,7 +248,8 @@ struct mlx4_mcg_table {
struct mlx4_catas_err {
u32 __iomem *map;
- int size;
+ struct timer_list timer;
+ struct list_head list;
};
struct mlx4_priv {
@@ -310,9 +312,11 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev);
void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
-void mlx4_map_catas_buf(struct mlx4_dev *dev);
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev);
-
+void mlx4_start_catas_poll(struct mlx4_dev *dev);
+void mlx4_stop_catas_poll(struct mlx4_dev *dev);
+int mlx4_catas_init(void);
+void mlx4_catas_cleanup(void);
+int mlx4_restart_one(struct pci_dev *pdev);
int mlx4_register_device(struct mlx4_dev *dev);
void mlx4_unregister_device(struct mlx4_dev *dev);
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type,
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 492cfaaaa75c..19b48c71cf7f 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -277,3 +277,24 @@ void mlx4_cleanup_qp_table(struct mlx4_dev *dev)
mlx4_CONF_SPECIAL_QP(dev, 0);
mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap);
}
+
+int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
+ struct mlx4_qp_context *context)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ err = mlx4_cmd_box(dev, 0, mailbox->dma, qp->qpn, 0,
+ MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A);
+ if (!err)
+ memcpy(context, mailbox->buf + 8, sizeof *context);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_qp_query);
+
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index 2134f83aed87..b061c86d6839 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -102,6 +102,13 @@ static int mlx4_ARM_SRQ(struct mlx4_dev *dev, int srq_num, int limit_watermark)
MLX4_CMD_TIME_CLASS_B);
}
+static int mlx4_QUERY_SRQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
+ int srq_num)
+{
+ return mlx4_cmd_box(dev, 0, mailbox->dma, srq_num, 0, MLX4_CMD_QUERY_SRQ,
+ MLX4_CMD_TIME_CLASS_A);
+}
+
int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
u64 db_rec, struct mlx4_srq *srq)
{
@@ -205,6 +212,29 @@ int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark
}
EXPORT_SYMBOL_GPL(mlx4_srq_arm);
+int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct mlx4_srq_context *srq_context;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+
+ srq_context = mailbox->buf;
+
+ err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn);
+ if (err)
+ goto err_out;
+ *limit_watermark = srq_context->limit_watermark;
+
+err_out:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_srq_query);
+
int __devinit mlx4_init_srq_table(struct mlx4_dev *dev)
{
struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e1732c164a40..deca65330b0f 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1060,7 +1060,6 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
struct myri10ge_tx_buf *tx = &mgp->tx;
struct sk_buff *skb;
int idx, len;
- int limit = 0;
while (tx->pkt_done != mcp_index) {
idx = tx->done & tx->mask;
@@ -1091,11 +1090,6 @@ static inline void myri10ge_tx_done(struct myri10ge_priv *mgp, int mcp_index)
bus), len,
PCI_DMA_TODEVICE);
}
-
- /* limit potential for livelock by only handling
- * 2 full tx rings per call */
- if (unlikely(++limit > 2 * tx->mask))
- break;
}
/* start the queue if we've stopped it */
if (netif_queue_stopped(mgp->dev)
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 460a08718c69..6bb48ba80964 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -671,7 +671,7 @@ static ssize_t natsemi_show_##_name(struct device *dev, \
#define NATSEMI_CREATE_FILE(_dev, _name) \
device_create_file(&_dev->dev, &dev_attr_##_name)
#define NATSEMI_REMOVE_FILE(_dev, _name) \
- device_create_file(&_dev->dev, &dev_attr_##_name)
+ device_remove_file(&_dev->dev, &dev_attr_##_name)
NATSEMI_ATTR(dspcfg_workaround);
@@ -2357,8 +2357,8 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
np->rx_dma[entry],
buflen,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb,
- np->rx_skbuff[entry]->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb,
+ np->rx_skbuff[entry]->data, pkt_len);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(np->pci_dev,
np->rx_dma[entry],
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index 995c0a5d4066..cfdeaf7aa163 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -669,10 +669,15 @@ static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state)
static int ne2k_pci_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
+ int rc;
pci_set_power_state(pdev, 0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
NS8390_init(dev, 1);
netif_device_attach(dev);
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 56f8197b953b..b703ccfe040b 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -54,8 +54,6 @@ static char netxen_nic_driver_string[] = "NetXen Network Driver version "
#define NETXEN_ADAPTER_UP_MAGIC 777
#define NETXEN_NIC_PEG_TUNE 0
-u8 nx_p2_id = NX_P2_C0;
-
#define DMA_32BIT_MASK 0x00000000ffffffffULL
#define DMA_35BIT_MASK 0x00000007ffffffffULL
@@ -307,8 +305,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_disable_pdev;
pci_set_master(pdev);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &nx_p2_id);
- if (nx_p2_id == NX_P2_C1 &&
+ if (pdev->revision == NX_P2_C1 &&
(pci_set_dma_mask(pdev, DMA_35BIT_MASK) == 0) &&
(pci_set_consistent_dma_mask(pdev, DMA_35BIT_MASK) == 0)) {
pci_using_dac = 1;
@@ -552,7 +549,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
adapter->ahw.pdev = pdev;
adapter->proc_cmd_buf_counter = 0;
- adapter->ahw.revision_id = nx_p2_id;
+ adapter->ahw.revision_id = pdev->revision;
/* make sure Window == 1 */
netxen_nic_pci_change_crbwindow(adapter, 1);
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 3d5b4232f65f..22a3b3dc7d89 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -670,14 +670,10 @@ static void ni5010_set_multicast_list(struct net_device *dev)
PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
- if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI) {
+ if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI || dev->mc_list) {
dev->flags |= IFF_PROMISC;
outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
- } else if (dev->mc_list) {
- /* Sorry, multicast not supported */
- PRINTK((KERN_DEBUG "%s: No multicast, entering broadcast mode\n", dev->name));
- outb(RMD_BROADCAST, EDLC_RMODE);
} else {
PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 8dbd6d1900b5..5e7999db2096 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -936,7 +936,7 @@ static void ni52_rcv_int(struct net_device *dev)
{
skb_reserve(skb,2);
skb_put(skb,totlen);
- eth_copy_and_sum(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen,0);
+ skb_copy_to_linear_data(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 3818edf0ac18..4ef5fe345191 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -1096,7 +1096,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0)
#ifdef RCV_VIA_SKB
if( (unsigned long) (skb->data + R_BUF_SIZE) > 0x1000000) {
skb_put(skb,len);
- eth_copy_and_sum(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len,0);
+ skb_copy_to_linear_data(skb, (unsigned char *)(p->recv_skb[p->rmdnum]->data),len);
}
else {
struct sk_buff *skb1 = p->recv_skb[p->rmdnum];
@@ -1108,7 +1108,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0)
}
#else
skb_put(skb,len);
- eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
+ skb_copy_to_linear_data(skb, (unsigned char *) p->recvbounce[p->rmdnum],len);
#endif
p->stats.rx_packets++;
p->stats.rx_bytes += len;
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 104aab3c957f..ea80e6cb3dec 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1582,7 +1582,7 @@ static void ns83820_set_multicast(struct net_device *ndev)
else
and_mask &= ~(RFCR_AAU | RFCR_AAM);
- if (ndev->flags & IFF_ALLMULTI)
+ if (ndev->flags & IFF_ALLMULTI || ndev->mc_count)
or_mask |= RFCR_AAM;
else
and_mask &= ~RFCR_AAM;
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index df8998b4f37e..3cdbe118200b 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1567,7 +1567,7 @@ static void netdrv_rx_interrupt (struct net_device *dev,
if (skb) {
skb_reserve (skb, 2); /* 16 byte align the IP fields. */
- eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
+ skb_copy_to_linear_data (skb, &rx_ring[ring_offset + 4], pkt_size);
skb_put (skb, pkt_size);
skb->protocol = eth_type_trans (skb, dev);
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 0d1c7a41c9c6..ea9414c4d900 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -147,7 +147,7 @@ static int com20020_probe(struct pcmcia_device *p_dev)
DEBUG(0, "com20020_attach()\n");
/* Create new network device */
- info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
+ info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
if (!info)
goto fail_alloc_info;
@@ -155,7 +155,6 @@ static int com20020_probe(struct pcmcia_device *p_dev)
if (!dev)
goto fail_alloc_dev;
- memset(info, 0, sizeof(struct com20020_dev_t));
lp = dev->priv;
lp->timeout = timeout;
lp->backplane = backplane;
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 4ecb8ca5a992..4eafa4f42cff 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -146,9 +146,8 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
DEBUG(0, "ibmtr_attach()\n");
/* Create new token-ring device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) return -ENOMEM;
- memset(info,0,sizeof(*info));
dev = alloc_trdev(sizeof(struct tok_info));
if (!dev) {
kfree(info);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 9c171a7390e2..465485a3fbc6 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -1235,9 +1235,9 @@ static void pcnet32_rx_entry(struct net_device *dev,
lp->rx_dma_addr[entry],
pkt_len,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *)(lp->rx_skbuff[entry]->data),
- pkt_len, 0);
+ pkt_len);
pci_dma_sync_single_for_device(lp->pci_dev,
lp->rx_dma_addr[entry],
pkt_len,
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 596222b260d6..6a5385647911 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -21,6 +21,10 @@
/* Vitesse Extended Control Register 1 */
#define MII_VSC8244_EXT_CON1 0x17
#define MII_VSC8244_EXTCON1_INIT 0x0000
+#define MII_VSC8244_EXTCON1_TX_SKEW_MASK 0x0c00
+#define MII_VSC8244_EXTCON1_RX_SKEW_MASK 0x0300
+#define MII_VSC8244_EXTCON1_TX_SKEW 0x0800
+#define MII_VSC8244_EXTCON1_RX_SKEW 0x0200
/* Vitesse Interrupt Mask Register */
#define MII_VSC8244_IMASK 0x19
@@ -39,7 +43,7 @@
/* Vitesse Auxiliary Control/Status Register */
#define MII_VSC8244_AUX_CONSTAT 0x1c
-#define MII_VSC8244_AUXCONSTAT_INIT 0x0004
+#define MII_VSC8244_AUXCONSTAT_INIT 0x0000
#define MII_VSC8244_AUXCONSTAT_DUPLEX 0x0020
#define MII_VSC8244_AUXCONSTAT_SPEED 0x0018
#define MII_VSC8244_AUXCONSTAT_GBIT 0x0010
@@ -51,6 +55,7 @@ MODULE_LICENSE("GPL");
static int vsc824x_config_init(struct phy_device *phydev)
{
+ int extcon;
int err;
err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
@@ -58,14 +63,34 @@ static int vsc824x_config_init(struct phy_device *phydev)
if (err < 0)
return err;
- err = phy_write(phydev, MII_VSC8244_EXT_CON1,
- MII_VSC8244_EXTCON1_INIT);
+ extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
+
+ if (extcon < 0)
+ return err;
+
+ extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
+ MII_VSC8244_EXTCON1_RX_SKEW_MASK);
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+ extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
+ MII_VSC8244_EXTCON1_RX_SKEW);
+
+ err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
+
return err;
}
static int vsc824x_ack_interrupt(struct phy_device *phydev)
{
- int err = phy_read(phydev, MII_VSC8244_ISTAT);
+ int err = 0;
+
+ /*
+ * Don't bother to ACK the interrupts if interrupts
+ * are disabled. The 824x cannot clear the interrupts
+ * if they are disabled.
+ */
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ err = phy_read(phydev, MII_VSC8244_ISTAT);
return (err < 0) ? err : 0;
}
@@ -77,8 +102,19 @@ static int vsc824x_config_intr(struct phy_device *phydev)
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
err = phy_write(phydev, MII_VSC8244_IMASK,
MII_VSC8244_IMASK_MASK);
- else
+ else {
+ /*
+ * The Vitesse PHY cannot clear the interrupt
+ * once it has disabled them, so we clear them first
+ */
+ err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+ if (err)
+ return err;
+
err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+ }
+
return err;
}
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index caabbc408c34..27f5b904f48e 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -159,12 +159,11 @@ ppp_asynctty_open(struct tty_struct *tty)
int err;
err = -ENOMEM;
- ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+ ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (ap == 0)
goto out;
/* initialize the asyncppp structure */
- memset(ap, 0, sizeof(*ap));
ap->tty = tty;
ap->mru = PPP_MRU;
spin_lock_init(&ap->xmit_lock);
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index 72c8d6628f58..eb98b661efba 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -121,12 +121,11 @@ static void *z_comp_alloc(unsigned char *options, int opt_len)
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
return NULL;
- state = kmalloc(sizeof(*state),
+ state = kzalloc(sizeof(*state),
GFP_KERNEL);
if (state == NULL)
return NULL;
- memset (state, 0, sizeof (struct ppp_deflate_state));
state->strm.next_in = NULL;
state->w_size = w_size;
state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
@@ -341,11 +340,10 @@ static void *z_decomp_alloc(unsigned char *options, int opt_len)
if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
return NULL;
- state = kmalloc(sizeof(*state), GFP_KERNEL);
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
return NULL;
- memset (state, 0, sizeof (struct ppp_deflate_state));
state->w_size = w_size;
state->strm.next_out = NULL;
state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 3ef0092dc09c..ef3325b69233 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -2684,8 +2684,7 @@ static void __exit ppp_cleanup(void)
if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
printk(KERN_ERR "PPP: removing module but units remain!\n");
cardmap_destroy(&all_ppp_units);
- if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
- printk(KERN_ERR "PPP: failed to unregister PPP device\n");
+ unregister_chrdev(PPP_MAJOR, "ppp");
device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
class_destroy(ppp_class);
}
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
index d5bdd2574659..f79cf87a2bff 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp_mppe.c
@@ -200,11 +200,10 @@ static void *mppe_alloc(unsigned char *options, int optlen)
|| options[0] != CI_MPPE || options[1] != CILEN_MPPE)
goto out;
- state = kmalloc(sizeof(*state), GFP_KERNEL);
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
if (state == NULL)
goto out;
- memset(state, 0, sizeof(*state));
state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(state->arc4)) {
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 5918fab38349..ce64032a465a 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -207,13 +207,12 @@ ppp_sync_open(struct tty_struct *tty)
struct syncppp *ap;
int err;
- ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+ ap = kzalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM;
if (ap == 0)
goto out;
/* initialize the syncppp structure */
- memset(ap, 0, sizeof(*ap));
ap->tty = tty;
ap->mru = PPP_MRU;
spin_lock_init(&ap->xmit_lock);
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
new file mode 100644
index 000000000000..f87176055d0e
--- /dev/null
+++ b/drivers/net/pppol2tp.c
@@ -0,0 +1,2496 @@
+/*****************************************************************************
+ * Linux PPP over L2TP (PPPoX/PPPoL2TP) Sockets
+ *
+ * PPPoX --- Generic PPP encapsulation socket family
+ * PPPoL2TP --- PPP over L2TP (RFC 2661)
+ *
+ * Version: 1.0.0
+ *
+ * Authors: Martijn van Oosterhout <kleptog@svana.org>
+ * James Chapman (jchapman@katalix.com)
+ * Contributors:
+ * Michal Ostrowski <mostrows@speakeasy.net>
+ * Arnaldo Carvalho de Melo <acme@xconectiva.com.br>
+ * David S. Miller (davem@redhat.com)
+ *
+ * License:
+ * 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 driver handles only L2TP data frames; control frames are handled by a
+ * userspace application.
+ *
+ * To send data in an L2TP session, userspace opens a PPPoL2TP socket and
+ * attaches it to a bound UDP socket with local tunnel_id / session_id and
+ * peer tunnel_id / session_id set. Data can then be sent or received using
+ * regular socket sendmsg() / recvmsg() calls. Kernel parameters of the socket
+ * can be read or modified using ioctl() or [gs]etsockopt() calls.
+ *
+ * When a PPPoL2TP socket is connected with local and peer session_id values
+ * zero, the socket is treated as a special tunnel management socket.
+ *
+ * Here's example userspace code to create a socket for sending/receiving data
+ * over an L2TP session:-
+ *
+ * struct sockaddr_pppol2tp sax;
+ * int fd;
+ * int session_fd;
+ *
+ * fd = socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OL2TP);
+ *
+ * sax.sa_family = AF_PPPOX;
+ * sax.sa_protocol = PX_PROTO_OL2TP;
+ * sax.pppol2tp.fd = tunnel_fd; // bound UDP socket
+ * sax.pppol2tp.addr.sin_addr.s_addr = addr->sin_addr.s_addr;
+ * sax.pppol2tp.addr.sin_port = addr->sin_port;
+ * sax.pppol2tp.addr.sin_family = AF_INET;
+ * sax.pppol2tp.s_tunnel = tunnel_id;
+ * sax.pppol2tp.s_session = session_id;
+ * sax.pppol2tp.d_tunnel = peer_tunnel_id;
+ * sax.pppol2tp.d_session = peer_session_id;
+ *
+ * session_fd = connect(fd, (struct sockaddr *)&sax, sizeof(sax));
+ *
+ * A pppd plugin that allows PPP traffic to be carried over L2TP using
+ * this driver is available from the OpenL2TP project at
+ * http://openl2tp.sourceforge.net.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/jiffies.h>
+
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/inetdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/if_pppox.h>
+#include <linux/if_pppol2tp.h>
+#include <net/sock.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#include <linux/file.h>
+#include <linux/hash.h>
+#include <linux/sort.h>
+#include <linux/proc_fs.h>
+#include <net/dst.h>
+#include <net/ip.h>
+#include <net/udp.h>
+#include <net/xfrm.h>
+
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+
+
+#define PPPOL2TP_DRV_VERSION "V1.0"
+
+/* L2TP header constants */
+#define L2TP_HDRFLAG_T 0x8000
+#define L2TP_HDRFLAG_L 0x4000
+#define L2TP_HDRFLAG_S 0x0800
+#define L2TP_HDRFLAG_O 0x0200
+#define L2TP_HDRFLAG_P 0x0100
+
+#define L2TP_HDR_VER_MASK 0x000F
+#define L2TP_HDR_VER 0x0002
+
+/* Space for UDP, L2TP and PPP headers */
+#define PPPOL2TP_HEADER_OVERHEAD 40
+
+/* Just some random numbers */
+#define L2TP_TUNNEL_MAGIC 0x42114DDA
+#define L2TP_SESSION_MAGIC 0x0C04EB7D
+
+#define PPPOL2TP_HASH_BITS 4
+#define PPPOL2TP_HASH_SIZE (1 << PPPOL2TP_HASH_BITS)
+
+/* Default trace flags */
+#define PPPOL2TP_DEFAULT_DEBUG_FLAGS 0
+
+#define PRINTK(_mask, _type, _lvl, _fmt, args...) \
+ do { \
+ if ((_mask) & (_type)) \
+ printk(_lvl "PPPOL2TP: " _fmt, ##args); \
+ } while(0)
+
+/* Number of bytes to build transmit L2TP headers.
+ * Unfortunately the size is different depending on whether sequence numbers
+ * are enabled.
+ */
+#define PPPOL2TP_L2TP_HDR_SIZE_SEQ 10
+#define PPPOL2TP_L2TP_HDR_SIZE_NOSEQ 6
+
+struct pppol2tp_tunnel;
+
+/* Describes a session. It is the sk_user_data field in the PPPoL2TP
+ * socket. Contains information to determine incoming packets and transmit
+ * outgoing ones.
+ */
+struct pppol2tp_session
+{
+ int magic; /* should be
+ * L2TP_SESSION_MAGIC */
+ int owner; /* pid that opened the socket */
+
+ struct sock *sock; /* Pointer to the session
+ * PPPoX socket */
+ struct sock *tunnel_sock; /* Pointer to the tunnel UDP
+ * socket */
+
+ struct pppol2tp_addr tunnel_addr; /* Description of tunnel */
+
+ struct pppol2tp_tunnel *tunnel; /* back pointer to tunnel
+ * context */
+
+ char name[20]; /* "sess xxxxx/yyyyy", where
+ * x=tunnel_id, y=session_id */
+ int mtu;
+ int mru;
+ int flags; /* accessed by PPPIOCGFLAGS.
+ * Unused. */
+ unsigned recv_seq:1; /* expect receive packets with
+ * sequence numbers? */
+ unsigned send_seq:1; /* send packets with sequence
+ * numbers? */
+ unsigned lns_mode:1; /* behave as LNS? LAC enables
+ * sequence numbers under
+ * control of LNS. */
+ int debug; /* bitmask of debug message
+ * categories */
+ int reorder_timeout; /* configured reorder timeout
+ * (in jiffies) */
+ u16 nr; /* session NR state (receive) */
+ u16 ns; /* session NR state (send) */
+ struct sk_buff_head reorder_q; /* receive reorder queue */
+ struct pppol2tp_ioc_stats stats;
+ struct hlist_node hlist; /* Hash list node */
+};
+
+/* The sk_user_data field of the tunnel's UDP socket. It contains info to track
+ * all the associated sessions so incoming packets can be sorted out
+ */
+struct pppol2tp_tunnel
+{
+ int magic; /* Should be L2TP_TUNNEL_MAGIC */
+ rwlock_t hlist_lock; /* protect session_hlist */
+ struct hlist_head session_hlist[PPPOL2TP_HASH_SIZE];
+ /* hashed list of sessions,
+ * hashed by id */
+ int debug; /* bitmask of debug message
+ * categories */
+ char name[12]; /* "tunl xxxxx" */
+ struct pppol2tp_ioc_stats stats;
+
+ void (*old_sk_destruct)(struct sock *);
+
+ struct sock *sock; /* Parent socket */
+ struct list_head list; /* Keep a list of all open
+ * prepared sockets */
+
+ atomic_t ref_count;
+};
+
+/* Private data stored for received packets in the skb.
+ */
+struct pppol2tp_skb_cb {
+ u16 ns;
+ u16 nr;
+ u16 has_seq;
+ u16 length;
+ unsigned long expires;
+};
+
+#define PPPOL2TP_SKB_CB(skb) ((struct pppol2tp_skb_cb *) &skb->cb[sizeof(struct inet_skb_parm)])
+
+static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
+static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel);
+
+static atomic_t pppol2tp_tunnel_count;
+static atomic_t pppol2tp_session_count;
+static struct ppp_channel_ops pppol2tp_chan_ops = { pppol2tp_xmit , NULL };
+static struct proto_ops pppol2tp_ops;
+static LIST_HEAD(pppol2tp_tunnel_list);
+static DEFINE_RWLOCK(pppol2tp_tunnel_list_lock);
+
+/* Helpers to obtain tunnel/session contexts from sockets.
+ */
+static inline struct pppol2tp_session *pppol2tp_sock_to_session(struct sock *sk)
+{
+ struct pppol2tp_session *session;
+
+ if (sk == NULL)
+ return NULL;
+
+ session = (struct pppol2tp_session *)(sk->sk_user_data);
+ if (session == NULL)
+ return NULL;
+
+ BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+
+ return session;
+}
+
+static inline struct pppol2tp_tunnel *pppol2tp_sock_to_tunnel(struct sock *sk)
+{
+ struct pppol2tp_tunnel *tunnel;
+
+ if (sk == NULL)
+ return NULL;
+
+ tunnel = (struct pppol2tp_tunnel *)(sk->sk_user_data);
+ if (tunnel == NULL)
+ return NULL;
+
+ BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
+
+ return tunnel;
+}
+
+/* Tunnel reference counts. Incremented per session that is added to
+ * the tunnel.
+ */
+static inline void pppol2tp_tunnel_inc_refcount(struct pppol2tp_tunnel *tunnel)
+{
+ atomic_inc(&tunnel->ref_count);
+}
+
+static inline void pppol2tp_tunnel_dec_refcount(struct pppol2tp_tunnel *tunnel)
+{
+ if (atomic_dec_and_test(&tunnel->ref_count))
+ pppol2tp_tunnel_free(tunnel);
+}
+
+/* Session hash list.
+ * The session_id SHOULD be random according to RFC2661, but several
+ * L2TP implementations (Cisco and Microsoft) use incrementing
+ * session_ids. So we do a real hash on the session_id, rather than a
+ * simple bitmask.
+ */
+static inline struct hlist_head *
+pppol2tp_session_id_hash(struct pppol2tp_tunnel *tunnel, u16 session_id)
+{
+ unsigned long hash_val = (unsigned long) session_id;
+ return &tunnel->session_hlist[hash_long(hash_val, PPPOL2TP_HASH_BITS)];
+}
+
+/* Lookup a session by id
+ */
+static struct pppol2tp_session *
+pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id)
+{
+ struct hlist_head *session_list =
+ pppol2tp_session_id_hash(tunnel, session_id);
+ struct pppol2tp_session *session;
+ struct hlist_node *walk;
+
+ read_lock(&tunnel->hlist_lock);
+ hlist_for_each_entry(session, walk, session_list, hlist) {
+ if (session->tunnel_addr.s_session == session_id) {
+ read_unlock(&tunnel->hlist_lock);
+ return session;
+ }
+ }
+ read_unlock(&tunnel->hlist_lock);
+
+ return NULL;
+}
+
+/* Lookup a tunnel by id
+ */
+static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id)
+{
+ struct pppol2tp_tunnel *tunnel = NULL;
+
+ read_lock(&pppol2tp_tunnel_list_lock);
+ list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) {
+ if (tunnel->stats.tunnel_id == tunnel_id) {
+ read_unlock(&pppol2tp_tunnel_list_lock);
+ return tunnel;
+ }
+ }
+ read_unlock(&pppol2tp_tunnel_list_lock);
+
+ return NULL;
+}
+
+/*****************************************************************************
+ * Receive data handling
+ *****************************************************************************/
+
+/* Queue a skb in order. We come here only if the skb has an L2TP sequence
+ * number.
+ */
+static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
+{
+ struct sk_buff *skbp;
+ u16 ns = PPPOL2TP_SKB_CB(skb)->ns;
+
+ spin_lock(&session->reorder_q.lock);
+ skb_queue_walk(&session->reorder_q, skbp) {
+ if (PPPOL2TP_SKB_CB(skbp)->ns > ns) {
+ __skb_insert(skb, skbp->prev, skbp, &session->reorder_q);
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n",
+ session->name, ns, PPPOL2TP_SKB_CB(skbp)->ns,
+ skb_queue_len(&session->reorder_q));
+ session->stats.rx_oos_packets++;
+ goto out;
+ }
+ }
+
+ __skb_queue_tail(&session->reorder_q, skb);
+
+out:
+ spin_unlock(&session->reorder_q.lock);
+}
+
+/* Dequeue a single skb.
+ */
+static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
+{
+ struct pppol2tp_tunnel *tunnel = session->tunnel;
+ int length = PPPOL2TP_SKB_CB(skb)->length;
+ struct sock *session_sock = NULL;
+
+ /* We're about to requeue the skb, so unlink it and return resources
+ * to its current owner (a socket receive buffer).
+ */
+ skb_unlink(skb, &session->reorder_q);
+ skb_orphan(skb);
+
+ tunnel->stats.rx_packets++;
+ tunnel->stats.rx_bytes += length;
+ session->stats.rx_packets++;
+ session->stats.rx_bytes += length;
+
+ if (PPPOL2TP_SKB_CB(skb)->has_seq) {
+ /* Bump our Nr */
+ session->nr++;
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: updated nr to %hu\n", session->name, session->nr);
+ }
+
+ /* If the socket is bound, send it in to PPP's input queue. Otherwise
+ * queue it on the session socket.
+ */
+ session_sock = session->sock;
+ if (session_sock->sk_state & PPPOX_BOUND) {
+ struct pppox_sock *po;
+ PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+ "%s: recv %d byte data frame, passing to ppp\n",
+ session->name, length);
+
+ /* We need to forget all info related to the L2TP packet
+ * gathered in the skb as we are going to reuse the same
+ * skb for the inner packet.
+ * Namely we need to:
+ * - reset xfrm (IPSec) information as it applies to
+ * the outer L2TP packet and not to the inner one
+ * - release the dst to force a route lookup on the inner
+ * IP packet since skb->dst currently points to the dst
+ * of the UDP tunnel
+ * - reset netfilter information as it doesn't apply
+ * to the inner packet either
+ */
+ secpath_reset(skb);
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ nf_reset(skb);
+
+ po = pppox_sk(session_sock);
+ ppp_input(&po->chan, skb);
+ } else {
+ PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
+ "%s: socket not bound\n", session->name);
+
+ /* Not bound. Nothing we can do, so discard. */
+ session->stats.rx_errors++;
+ kfree_skb(skb);
+ }
+
+ sock_put(session->sock);
+}
+
+/* Dequeue skbs from the session's reorder_q, subject to packet order.
+ * Skbs that have been in the queue for too long are simply discarded.
+ */
+static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
+{
+ struct sk_buff *skb;
+ struct sk_buff *tmp;
+
+ /* If the pkt at the head of the queue has the nr that we
+ * expect to send up next, dequeue it and any other
+ * in-sequence packets behind it.
+ */
+ spin_lock(&session->reorder_q.lock);
+ skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
+ if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) {
+ session->stats.rx_seq_discards++;
+ session->stats.rx_errors++;
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: oos pkt %hu len %d discarded (too old), "
+ "waiting for %hu, reorder_q_len=%d\n",
+ session->name, PPPOL2TP_SKB_CB(skb)->ns,
+ PPPOL2TP_SKB_CB(skb)->length, session->nr,
+ skb_queue_len(&session->reorder_q));
+ __skb_unlink(skb, &session->reorder_q);
+ kfree_skb(skb);
+ continue;
+ }
+
+ if (PPPOL2TP_SKB_CB(skb)->has_seq) {
+ if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: holding oos pkt %hu len %d, "
+ "waiting for %hu, reorder_q_len=%d\n",
+ session->name, PPPOL2TP_SKB_CB(skb)->ns,
+ PPPOL2TP_SKB_CB(skb)->length, session->nr,
+ skb_queue_len(&session->reorder_q));
+ goto out;
+ }
+ }
+ spin_unlock(&session->reorder_q.lock);
+ pppol2tp_recv_dequeue_skb(session, skb);
+ spin_lock(&session->reorder_q.lock);
+ }
+
+out:
+ spin_unlock(&session->reorder_q.lock);
+}
+
+/* Internal receive frame. Do the real work of receiving an L2TP data frame
+ * here. The skb is not on a list when we get here.
+ * Returns 0 if the packet was a data packet and was successfully passed on.
+ * Returns 1 if the packet was not a good data packet and could not be
+ * forwarded. All such packets are passed up to userspace to deal with.
+ */
+static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb)
+{
+ struct pppol2tp_session *session = NULL;
+ struct pppol2tp_tunnel *tunnel;
+ unsigned char *ptr;
+ u16 hdrflags;
+ u16 tunnel_id, session_id;
+ int length;
+ struct udphdr *uh;
+
+ tunnel = pppol2tp_sock_to_tunnel(sock);
+ if (tunnel == NULL)
+ goto error;
+
+ /* Short packet? */
+ if (skb->len < sizeof(struct udphdr)) {
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
+ "%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
+ goto error;
+ }
+
+ /* Point to L2TP header */
+ ptr = skb->data + sizeof(struct udphdr);
+
+ /* Get L2TP header flags */
+ hdrflags = ntohs(*(__be16*)ptr);
+
+ /* Trace packet contents, if enabled */
+ if (tunnel->debug & PPPOL2TP_MSG_DATA) {
+ printk(KERN_DEBUG "%s: recv: ", tunnel->name);
+
+ for (length = 0; length < 16; length++)
+ printk(" %02X", ptr[length]);
+ printk("\n");
+ }
+
+ /* Get length of L2TP packet */
+ uh = (struct udphdr *) skb_transport_header(skb);
+ length = ntohs(uh->len) - sizeof(struct udphdr);
+
+ /* Too short? */
+ if (length < 12) {
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
+ "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length);
+ goto error;
+ }
+
+ /* If type is control packet, it is handled by userspace. */
+ if (hdrflags & L2TP_HDRFLAG_T) {
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+ "%s: recv control packet, len=%d\n", tunnel->name, length);
+ goto error;
+ }
+
+ /* Skip flags */
+ ptr += 2;
+
+ /* If length is present, skip it */
+ if (hdrflags & L2TP_HDRFLAG_L)
+ ptr += 2;
+
+ /* Extract tunnel and session ID */
+ tunnel_id = ntohs(*(__be16 *) ptr);
+ ptr += 2;
+ session_id = ntohs(*(__be16 *) ptr);
+ ptr += 2;
+
+ /* Find the session context */
+ session = pppol2tp_session_find(tunnel, session_id);
+ if (!session) {
+ /* Not found? Pass to userspace to deal with */
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
+ "%s: no socket found (%hu/%hu). Passing up.\n",
+ tunnel->name, tunnel_id, session_id);
+ goto error;
+ }
+ sock_hold(session->sock);
+
+ /* The ref count on the socket was increased by the above call since
+ * we now hold a pointer to the session. Take care to do sock_put()
+ * when exiting this function from now on...
+ */
+
+ /* Handle the optional sequence numbers. If we are the LAC,
+ * enable/disable sequence numbers under the control of the LNS. If
+ * no sequence numbers present but we were expecting them, discard
+ * frame.
+ */
+ if (hdrflags & L2TP_HDRFLAG_S) {
+ u16 ns, nr;
+ ns = ntohs(*(__be16 *) ptr);
+ ptr += 2;
+ nr = ntohs(*(__be16 *) ptr);
+ ptr += 2;
+
+ /* Received a packet with sequence numbers. If we're the LNS,
+ * check if we sre sending sequence numbers and if not,
+ * configure it so.
+ */
+ if ((!session->lns_mode) && (!session->send_seq)) {
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,
+ "%s: requested to enable seq numbers by LNS\n",
+ session->name);
+ session->send_seq = -1;
+ }
+
+ /* Store L2TP info in the skb */
+ PPPOL2TP_SKB_CB(skb)->ns = ns;
+ PPPOL2TP_SKB_CB(skb)->nr = nr;
+ PPPOL2TP_SKB_CB(skb)->has_seq = 1;
+
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: recv data ns=%hu, nr=%hu, session nr=%hu\n",
+ session->name, ns, nr, session->nr);
+ } else {
+ /* No sequence numbers.
+ * If user has configured mandatory sequence numbers, discard.
+ */
+ if (session->recv_seq) {
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,
+ "%s: recv data has no seq numbers when required. "
+ "Discarding\n", session->name);
+ session->stats.rx_seq_discards++;
+ session->stats.rx_errors++;
+ goto discard;
+ }
+
+ /* If we're the LAC and we're sending sequence numbers, the
+ * LNS has requested that we no longer send sequence numbers.
+ * If we're the LNS and we're sending sequence numbers, the
+ * LAC is broken. Discard the frame.
+ */
+ if ((!session->lns_mode) && (session->send_seq)) {
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_INFO,
+ "%s: requested to disable seq numbers by LNS\n",
+ session->name);
+ session->send_seq = 0;
+ } else if (session->send_seq) {
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_WARNING,
+ "%s: recv data has no seq numbers when required. "
+ "Discarding\n", session->name);
+ session->stats.rx_seq_discards++;
+ session->stats.rx_errors++;
+ goto discard;
+ }
+
+ /* Store L2TP info in the skb */
+ PPPOL2TP_SKB_CB(skb)->has_seq = 0;
+ }
+
+ /* If offset bit set, skip it. */
+ if (hdrflags & L2TP_HDRFLAG_O)
+ ptr += 2 + ntohs(*(__be16 *) ptr);
+
+ skb_pull(skb, ptr - skb->data);
+
+ /* Skip PPP header, if present. In testing, Microsoft L2TP clients
+ * don't send the PPP header (PPP header compression enabled), but
+ * other clients can include the header. So we cope with both cases
+ * here. The PPP header is always FF03 when using L2TP.
+ *
+ * Note that skb->data[] isn't dereferenced from a u16 ptr here since
+ * the field may be unaligned.
+ */
+ if ((skb->data[0] == 0xff) && (skb->data[1] == 0x03))
+ skb_pull(skb, 2);
+
+ /* Prepare skb for adding to the session's reorder_q. Hold
+ * packets for max reorder_timeout or 1 second if not
+ * reordering.
+ */
+ PPPOL2TP_SKB_CB(skb)->length = length;
+ PPPOL2TP_SKB_CB(skb)->expires = jiffies +
+ (session->reorder_timeout ? session->reorder_timeout : HZ);
+
+ /* Add packet to the session's receive queue. Reordering is done here, if
+ * enabled. Saved L2TP protocol info is stored in skb->sb[].
+ */
+ if (PPPOL2TP_SKB_CB(skb)->has_seq) {
+ if (session->reorder_timeout != 0) {
+ /* Packet reordering enabled. Add skb to session's
+ * reorder queue, in order of ns.
+ */
+ pppol2tp_recv_queue_skb(session, skb);
+ } else {
+ /* Packet reordering disabled. Discard out-of-sequence
+ * packets
+ */
+ if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
+ session->stats.rx_seq_discards++;
+ session->stats.rx_errors++;
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: oos pkt %hu len %d discarded, "
+ "waiting for %hu, reorder_q_len=%d\n",
+ session->name, PPPOL2TP_SKB_CB(skb)->ns,
+ PPPOL2TP_SKB_CB(skb)->length, session->nr,
+ skb_queue_len(&session->reorder_q));
+ goto discard;
+ }
+ skb_queue_tail(&session->reorder_q, skb);
+ }
+ } else {
+ /* No sequence numbers. Add the skb to the tail of the
+ * reorder queue. This ensures that it will be
+ * delivered after all previous sequenced skbs.
+ */
+ skb_queue_tail(&session->reorder_q, skb);
+ }
+
+ /* Try to dequeue as many skbs from reorder_q as we can. */
+ pppol2tp_recv_dequeue(session);
+
+ return 0;
+
+discard:
+ kfree_skb(skb);
+ sock_put(session->sock);
+
+ return 0;
+
+error:
+ return 1;
+}
+
+/* UDP encapsulation receive handler. See net/ipv4/udp.c.
+ * Return codes:
+ * 0 : success.
+ * <0: error
+ * >0: skb should be passed up to userspace as UDP.
+ */
+static int pppol2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
+{
+ struct pppol2tp_tunnel *tunnel;
+
+ tunnel = pppol2tp_sock_to_tunnel(sk);
+ if (tunnel == NULL)
+ goto pass_up;
+
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+ "%s: received %d bytes\n", tunnel->name, skb->len);
+
+ if (pppol2tp_recv_core(sk, skb))
+ goto pass_up;
+
+ return 0;
+
+pass_up:
+ return 1;
+}
+
+/* Receive message. This is the recvmsg for the PPPoL2TP socket.
+ */
+static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t len,
+ int flags)
+{
+ int err;
+ struct sk_buff *skb;
+ struct sock *sk = sock->sk;
+
+ err = -EIO;
+ if (sk->sk_state & PPPOX_BOUND)
+ goto end;
+
+ msg->msg_namelen = 0;
+
+ err = 0;
+ skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+ flags & MSG_DONTWAIT, &err);
+ if (skb) {
+ err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data,
+ skb->len);
+ if (err < 0)
+ goto do_skb_free;
+ err = skb->len;
+ }
+do_skb_free:
+ kfree_skb(skb);
+end:
+ return err;
+}
+
+/************************************************************************
+ * Transmit handling
+ ***********************************************************************/
+
+/* Tell how big L2TP headers are for a particular session. This
+ * depends on whether sequence numbers are being used.
+ */
+static inline int pppol2tp_l2tp_header_len(struct pppol2tp_session *session)
+{
+ if (session->send_seq)
+ return PPPOL2TP_L2TP_HDR_SIZE_SEQ;
+
+ return PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
+}
+
+/* Build an L2TP header for the session into the buffer provided.
+ */
+static void pppol2tp_build_l2tp_header(struct pppol2tp_session *session,
+ void *buf)
+{
+ __be16 *bufp = buf;
+ u16 flags = L2TP_HDR_VER;
+
+ if (session->send_seq)
+ flags |= L2TP_HDRFLAG_S;
+
+ /* Setup L2TP header.
+ * FIXME: Can this ever be unaligned? Is direct dereferencing of
+ * 16-bit header fields safe here for all architectures?
+ */
+ *bufp++ = htons(flags);
+ *bufp++ = htons(session->tunnel_addr.d_tunnel);
+ *bufp++ = htons(session->tunnel_addr.d_session);
+ if (session->send_seq) {
+ *bufp++ = htons(session->ns);
+ *bufp++ = 0;
+ session->ns++;
+ PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
+ "%s: updated ns to %hu\n", session->name, session->ns);
+ }
+}
+
+/* This is the sendmsg for the PPPoL2TP pppol2tp_session socket. We come here
+ * when a user application does a sendmsg() on the session socket. L2TP and
+ * PPP headers must be inserted into the user's data.
+ */
+static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
+ size_t total_len)
+{
+ static const unsigned char ppph[2] = { 0xff, 0x03 };
+ struct sock *sk = sock->sk;
+ struct inet_sock *inet;
+ __wsum csum = 0;
+ struct sk_buff *skb;
+ int error;
+ int hdr_len;
+ struct pppol2tp_session *session;
+ struct pppol2tp_tunnel *tunnel;
+ struct udphdr *uh;
+ unsigned int len;
+
+ error = -ENOTCONN;
+ if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
+ goto error;
+
+ /* Get session and tunnel contexts */
+ error = -EBADF;
+ session = pppol2tp_sock_to_session(sk);
+ if (session == NULL)
+ goto error;
+
+ tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
+ if (tunnel == NULL)
+ goto error;
+
+ /* What header length is configured for this session? */
+ hdr_len = pppol2tp_l2tp_header_len(session);
+
+ /* Allocate a socket buffer */
+ error = -ENOMEM;
+ skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
+ sizeof(struct udphdr) + hdr_len +
+ sizeof(ppph) + total_len,
+ 0, GFP_KERNEL);
+ if (!skb)
+ goto error;
+
+ /* Reserve space for headers. */
+ skb_reserve(skb, NET_SKB_PAD);
+ skb_reset_network_header(skb);
+ skb_reserve(skb, sizeof(struct iphdr));
+ skb_reset_transport_header(skb);
+
+ /* Build UDP header */
+ inet = inet_sk(session->tunnel_sock);
+ uh = (struct udphdr *) skb->data;
+ uh->source = inet->sport;
+ uh->dest = inet->dport;
+ uh->len = htons(hdr_len + sizeof(ppph) + total_len);
+ uh->check = 0;
+ skb_put(skb, sizeof(struct udphdr));
+
+ /* Build L2TP header */
+ pppol2tp_build_l2tp_header(session, skb->data);
+ skb_put(skb, hdr_len);
+
+ /* Add PPP header */
+ skb->data[0] = ppph[0];
+ skb->data[1] = ppph[1];
+ skb_put(skb, 2);
+
+ /* Copy user data into skb */
+ error = memcpy_fromiovec(skb->data, m->msg_iov, total_len);
+ if (error < 0) {
+ kfree_skb(skb);
+ goto error;
+ }
+ skb_put(skb, total_len);
+
+ /* Calculate UDP checksum if configured to do so */
+ if (session->tunnel_sock->sk_no_check != UDP_CSUM_NOXMIT)
+ csum = udp_csum_outgoing(sk, skb);
+
+ /* Debug */
+ if (session->send_seq)
+ PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+ "%s: send %Zd bytes, ns=%hu\n", session->name,
+ total_len, session->ns - 1);
+ else
+ PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+ "%s: send %Zd bytes\n", session->name, total_len);
+
+ if (session->debug & PPPOL2TP_MSG_DATA) {
+ int i;
+ unsigned char *datap = skb->data;
+
+ printk(KERN_DEBUG "%s: xmit:", session->name);
+ for (i = 0; i < total_len; i++) {
+ printk(" %02X", *datap++);
+ if (i == 15) {
+ printk(" ...");
+ break;
+ }
+ }
+ printk("\n");
+ }
+
+ /* Queue the packet to IP for output */
+ len = skb->len;
+ error = ip_queue_xmit(skb, 1);
+
+ /* Update stats */
+ if (error >= 0) {
+ tunnel->stats.tx_packets++;
+ tunnel->stats.tx_bytes += len;
+ session->stats.tx_packets++;
+ session->stats.tx_bytes += len;
+ } else {
+ tunnel->stats.tx_errors++;
+ session->stats.tx_errors++;
+ }
+
+error:
+ return error;
+}
+
+/* Transmit function called by generic PPP driver. Sends PPP frame
+ * over PPPoL2TP socket.
+ *
+ * This is almost the same as pppol2tp_sendmsg(), but rather than
+ * being called with a msghdr from userspace, it is called with a skb
+ * from the kernel.
+ *
+ * The supplied skb from ppp doesn't have enough headroom for the
+ * insertion of L2TP, UDP and IP headers so we need to allocate more
+ * headroom in the skb. This will create a cloned skb. But we must be
+ * careful in the error case because the caller will expect to free
+ * the skb it supplied, not our cloned skb. So we take care to always
+ * leave the original skb unfreed if we return an error.
+ */
+static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+ static const u8 ppph[2] = { 0xff, 0x03 };
+ struct sock *sk = (struct sock *) chan->private;
+ struct sock *sk_tun;
+ int hdr_len;
+ struct pppol2tp_session *session;
+ struct pppol2tp_tunnel *tunnel;
+ int rc;
+ int headroom;
+ int data_len = skb->len;
+ struct inet_sock *inet;
+ __wsum csum = 0;
+ struct sk_buff *skb2 = NULL;
+ struct udphdr *uh;
+ unsigned int len;
+
+ if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
+ goto abort;
+
+ /* Get session and tunnel contexts from the socket */
+ session = pppol2tp_sock_to_session(sk);
+ if (session == NULL)
+ goto abort;
+
+ sk_tun = session->tunnel_sock;
+ if (sk_tun == NULL)
+ goto abort;
+ tunnel = pppol2tp_sock_to_tunnel(sk_tun);
+ if (tunnel == NULL)
+ goto abort;
+
+ /* What header length is configured for this session? */
+ hdr_len = pppol2tp_l2tp_header_len(session);
+
+ /* Check that there's enough headroom in the skb to insert IP,
+ * UDP and L2TP and PPP headers. If not enough, expand it to
+ * make room. Note that a new skb (or a clone) is
+ * allocated. If we return an error from this point on, make
+ * sure we free the new skb but do not free the original skb
+ * since that is done by the caller for the error case.
+ */
+ headroom = NET_SKB_PAD + sizeof(struct iphdr) +
+ sizeof(struct udphdr) + hdr_len + sizeof(ppph);
+ if (skb_headroom(skb) < headroom) {
+ skb2 = skb_realloc_headroom(skb, headroom);
+ if (skb2 == NULL)
+ goto abort;
+ } else
+ skb2 = skb;
+
+ /* Check that the socket has room */
+ if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf)
+ skb_set_owner_w(skb2, sk_tun);
+ else
+ goto discard;
+
+ /* Setup PPP header */
+ skb_push(skb2, sizeof(ppph));
+ skb2->data[0] = ppph[0];
+ skb2->data[1] = ppph[1];
+
+ /* Setup L2TP header */
+ skb_push(skb2, hdr_len);
+ pppol2tp_build_l2tp_header(session, skb2->data);
+
+ /* Setup UDP header */
+ inet = inet_sk(sk_tun);
+ skb_push(skb2, sizeof(struct udphdr));
+ skb_reset_transport_header(skb2);
+ uh = (struct udphdr *) skb2->data;
+ uh->source = inet->sport;
+ uh->dest = inet->dport;
+ uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len);
+ uh->check = 0;
+
+ /* Calculate UDP checksum if configured to do so */
+ if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT)
+ csum = udp_csum_outgoing(sk_tun, skb2);
+
+ /* Debug */
+ if (session->send_seq)
+ PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+ "%s: send %d bytes, ns=%hu\n", session->name,
+ data_len, session->ns - 1);
+ else
+ PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG,
+ "%s: send %d bytes\n", session->name, data_len);
+
+ if (session->debug & PPPOL2TP_MSG_DATA) {
+ int i;
+ unsigned char *datap = skb2->data;
+
+ printk(KERN_DEBUG "%s: xmit:", session->name);
+ for (i = 0; i < data_len; i++) {
+ printk(" %02X", *datap++);
+ if (i == 31) {
+ printk(" ...");
+ break;
+ }
+ }
+ printk("\n");
+ }
+
+ memset(&(IPCB(skb2)->opt), 0, sizeof(IPCB(skb2)->opt));
+ IPCB(skb2)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+ IPSKB_REROUTED);
+ nf_reset(skb2);
+
+ /* Get routing info from the tunnel socket */
+ dst_release(skb2->dst);
+ skb2->dst = sk_dst_get(sk_tun);
+
+ /* Queue the packet to IP for output */
+ len = skb2->len;
+ rc = ip_queue_xmit(skb2, 1);
+
+ /* Update stats */
+ if (rc >= 0) {
+ tunnel->stats.tx_packets++;
+ tunnel->stats.tx_bytes += len;
+ session->stats.tx_packets++;
+ session->stats.tx_bytes += len;
+ } else {
+ tunnel->stats.tx_errors++;
+ session->stats.tx_errors++;
+ }
+
+ /* Free the original skb */
+ kfree_skb(skb);
+
+ return 1;
+
+discard:
+ /* Free the new skb. Caller will free original skb. */
+ if (skb2 != skb)
+ kfree_skb(skb2);
+abort:
+ return 0;
+}
+
+/*****************************************************************************
+ * Session (and tunnel control) socket create/destroy.
+ *****************************************************************************/
+
+/* When the tunnel UDP socket is closed, all the attached sockets need to go
+ * too.
+ */
+static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel)
+{
+ int hash;
+ struct hlist_node *walk;
+ struct hlist_node *tmp;
+ struct pppol2tp_session *session;
+ struct sock *sk;
+
+ if (tunnel == NULL)
+ BUG();
+
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: closing all sessions...\n", tunnel->name);
+
+ write_lock(&tunnel->hlist_lock);
+ for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) {
+again:
+ hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
+ session = hlist_entry(walk, struct pppol2tp_session, hlist);
+
+ sk = session->sock;
+
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: closing session\n", session->name);
+
+ hlist_del_init(&session->hlist);
+
+ /* Since we should hold the sock lock while
+ * doing any unbinding, we need to release the
+ * lock we're holding before taking that lock.
+ * Hold a reference to the sock so it doesn't
+ * disappear as we're jumping between locks.
+ */
+ sock_hold(sk);
+ write_unlock(&tunnel->hlist_lock);
+ lock_sock(sk);
+
+ if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+ pppox_unbind_sock(sk);
+ sk->sk_state = PPPOX_DEAD;
+ sk->sk_state_change(sk);
+ }
+
+ /* Purge any queued data */
+ skb_queue_purge(&sk->sk_receive_queue);
+ skb_queue_purge(&sk->sk_write_queue);
+ skb_queue_purge(&session->reorder_q);
+
+ release_sock(sk);
+ sock_put(sk);
+
+ /* Now restart from the beginning of this hash
+ * chain. We always remove a session from the
+ * list so we are guaranteed to make forward
+ * progress.
+ */
+ write_lock(&tunnel->hlist_lock);
+ goto again;
+ }
+ }
+ write_unlock(&tunnel->hlist_lock);
+}
+
+/* Really kill the tunnel.
+ * Come here only when all sessions have been cleared from the tunnel.
+ */
+static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel)
+{
+ /* Remove from socket list */
+ write_lock(&pppol2tp_tunnel_list_lock);
+ list_del_init(&tunnel->list);
+ write_unlock(&pppol2tp_tunnel_list_lock);
+
+ atomic_dec(&pppol2tp_tunnel_count);
+ kfree(tunnel);
+}
+
+/* Tunnel UDP socket destruct hook.
+ * The tunnel context is deleted only when all session sockets have been
+ * closed.
+ */
+static void pppol2tp_tunnel_destruct(struct sock *sk)
+{
+ struct pppol2tp_tunnel *tunnel;
+
+ tunnel = pppol2tp_sock_to_tunnel(sk);
+ if (tunnel == NULL)
+ goto end;
+
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: closing...\n", tunnel->name);
+
+ /* Close all sessions */
+ pppol2tp_tunnel_closeall(tunnel);
+
+ /* No longer an encapsulation socket. See net/ipv4/udp.c */
+ (udp_sk(sk))->encap_type = 0;
+ (udp_sk(sk))->encap_rcv = NULL;
+
+ /* Remove hooks into tunnel socket */
+ tunnel->sock = NULL;
+ sk->sk_destruct = tunnel->old_sk_destruct;
+ sk->sk_user_data = NULL;
+
+ /* Call original (UDP) socket descructor */
+ if (sk->sk_destruct != NULL)
+ (*sk->sk_destruct)(sk);
+
+ pppol2tp_tunnel_dec_refcount(tunnel);
+
+end:
+ return;
+}
+
+/* Really kill the session socket. (Called from sock_put() if
+ * refcnt == 0.)
+ */
+static void pppol2tp_session_destruct(struct sock *sk)
+{
+ struct pppol2tp_session *session = NULL;
+
+ if (sk->sk_user_data != NULL) {
+ struct pppol2tp_tunnel *tunnel;
+
+ session = pppol2tp_sock_to_session(sk);
+ if (session == NULL)
+ goto out;
+
+ /* Don't use pppol2tp_sock_to_tunnel() here to
+ * get the tunnel context because the tunnel
+ * socket might have already been closed (its
+ * sk->sk_user_data will be NULL) so use the
+ * session's private tunnel ptr instead.
+ */
+ tunnel = session->tunnel;
+ if (tunnel != NULL) {
+ BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
+
+ /* If session_id is zero, this is a null
+ * session context, which was created for a
+ * socket that is being used only to manage
+ * tunnels.
+ */
+ if (session->tunnel_addr.s_session != 0) {
+ /* Delete the session socket from the
+ * hash
+ */
+ write_lock(&tunnel->hlist_lock);
+ hlist_del_init(&session->hlist);
+ write_unlock(&tunnel->hlist_lock);
+
+ atomic_dec(&pppol2tp_session_count);
+ }
+
+ /* This will delete the tunnel context if this
+ * is the last session on the tunnel.
+ */
+ session->tunnel = NULL;
+ session->tunnel_sock = NULL;
+ pppol2tp_tunnel_dec_refcount(tunnel);
+ }
+ }
+
+ kfree(session);
+out:
+ return;
+}
+
+/* Called when the PPPoX socket (session) is closed.
+ */
+static int pppol2tp_release(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+ int error;
+
+ if (!sk)
+ return 0;
+
+ error = -EBADF;
+ lock_sock(sk);
+ if (sock_flag(sk, SOCK_DEAD) != 0)
+ goto error;
+
+ pppox_unbind_sock(sk);
+
+ /* Signal the death of the socket. */
+ sk->sk_state = PPPOX_DEAD;
+ sock_orphan(sk);
+ sock->sk = NULL;
+
+ /* Purge any queued data */
+ skb_queue_purge(&sk->sk_receive_queue);
+ skb_queue_purge(&sk->sk_write_queue);
+
+ release_sock(sk);
+
+ /* This will delete the session context via
+ * pppol2tp_session_destruct() if the socket's refcnt drops to
+ * zero.
+ */
+ sock_put(sk);
+
+ return 0;
+
+error:
+ release_sock(sk);
+ return error;
+}
+
+/* Internal function to prepare a tunnel (UDP) socket to have PPPoX
+ * sockets attached to it.
+ */
+static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
+ int *error)
+{
+ int err;
+ struct socket *sock = NULL;
+ struct sock *sk;
+ struct pppol2tp_tunnel *tunnel;
+ struct sock *ret = NULL;
+
+ /* Get the tunnel UDP socket from the fd, which was opened by
+ * the userspace L2TP daemon.
+ */
+ err = -EBADF;
+ sock = sockfd_lookup(fd, &err);
+ if (!sock) {
+ PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
+ "tunl %hu: sockfd_lookup(fd=%d) returned %d\n",
+ tunnel_id, fd, err);
+ goto err;
+ }
+
+ /* Quick sanity checks */
+ err = -ESOCKTNOSUPPORT;
+ if (sock->type != SOCK_DGRAM) {
+ PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
+ "tunl %hu: fd %d wrong type, got %d, expected %d\n",
+ tunnel_id, fd, sock->type, SOCK_DGRAM);
+ goto err;
+ }
+ err = -EAFNOSUPPORT;
+ if (sock->ops->family != AF_INET) {
+ PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
+ "tunl %hu: fd %d wrong family, got %d, expected %d\n",
+ tunnel_id, fd, sock->ops->family, AF_INET);
+ goto err;
+ }
+
+ err = -ENOTCONN;
+ sk = sock->sk;
+
+ /* Check if this socket has already been prepped */
+ tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data;
+ if (tunnel != NULL) {
+ /* User-data field already set */
+ err = -EBUSY;
+ BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
+
+ /* This socket has already been prepped */
+ ret = tunnel->sock;
+ goto out;
+ }
+
+ /* This socket is available and needs prepping. Create a new tunnel
+ * context and init it.
+ */
+ sk->sk_user_data = tunnel = kzalloc(sizeof(struct pppol2tp_tunnel), GFP_KERNEL);
+ if (sk->sk_user_data == NULL) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ tunnel->magic = L2TP_TUNNEL_MAGIC;
+ sprintf(&tunnel->name[0], "tunl %hu", tunnel_id);
+
+ tunnel->stats.tunnel_id = tunnel_id;
+ tunnel->debug = PPPOL2TP_DEFAULT_DEBUG_FLAGS;
+
+ /* Hook on the tunnel socket destructor so that we can cleanup
+ * if the tunnel socket goes away.
+ */
+ tunnel->old_sk_destruct = sk->sk_destruct;
+ sk->sk_destruct = &pppol2tp_tunnel_destruct;
+
+ tunnel->sock = sk;
+ sk->sk_allocation = GFP_ATOMIC;
+
+ /* Misc init */
+ rwlock_init(&tunnel->hlist_lock);
+
+ /* Add tunnel to our list */
+ INIT_LIST_HEAD(&tunnel->list);
+ write_lock(&pppol2tp_tunnel_list_lock);
+ list_add(&tunnel->list, &pppol2tp_tunnel_list);
+ write_unlock(&pppol2tp_tunnel_list_lock);
+ atomic_inc(&pppol2tp_tunnel_count);
+
+ /* Bump the reference count. The tunnel context is deleted
+ * only when this drops to zero.
+ */
+ pppol2tp_tunnel_inc_refcount(tunnel);
+
+ /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
+ (udp_sk(sk))->encap_type = UDP_ENCAP_L2TPINUDP;
+ (udp_sk(sk))->encap_rcv = pppol2tp_udp_encap_recv;
+
+ ret = tunnel->sock;
+
+ *error = 0;
+out:
+ if (sock)
+ sockfd_put(sock);
+
+ return ret;
+
+err:
+ *error = err;
+ goto out;
+}
+
+static struct proto pppol2tp_sk_proto = {
+ .name = "PPPOL2TP",
+ .owner = THIS_MODULE,
+ .obj_size = sizeof(struct pppox_sock),
+};
+
+/* socket() handler. Initialize a new struct sock.
+ */
+static int pppol2tp_create(struct socket *sock)
+{
+ int error = -ENOMEM;
+ struct sock *sk;
+
+ sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1);
+ if (!sk)
+ goto out;
+
+ sock_init_data(sock, sk);
+
+ sock->state = SS_UNCONNECTED;
+ sock->ops = &pppol2tp_ops;
+
+ sk->sk_backlog_rcv = pppol2tp_recv_core;
+ sk->sk_protocol = PX_PROTO_OL2TP;
+ sk->sk_family = PF_PPPOX;
+ sk->sk_state = PPPOX_NONE;
+ sk->sk_type = SOCK_STREAM;
+ sk->sk_destruct = pppol2tp_session_destruct;
+
+ error = 0;
+
+out:
+ return error;
+}
+
+/* connect() handler. Attach a PPPoX socket to a tunnel UDP socket
+ */
+static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
+ int sockaddr_len, int flags)
+{
+ struct sock *sk = sock->sk;
+ struct sockaddr_pppol2tp *sp = (struct sockaddr_pppol2tp *) uservaddr;
+ struct pppox_sock *po = pppox_sk(sk);
+ struct sock *tunnel_sock = NULL;
+ struct pppol2tp_session *session = NULL;
+ struct pppol2tp_tunnel *tunnel;
+ struct dst_entry *dst;
+ int error = 0;
+
+ lock_sock(sk);
+
+ error = -EINVAL;
+ if (sp->sa_protocol != PX_PROTO_OL2TP)
+ goto end;
+
+ /* Check for already bound sockets */
+ error = -EBUSY;
+ if (sk->sk_state & PPPOX_CONNECTED)
+ goto end;
+
+ /* We don't supporting rebinding anyway */
+ error = -EALREADY;
+ if (sk->sk_user_data)
+ goto end; /* socket is already attached */
+
+ /* Don't bind if s_tunnel is 0 */
+ error = -EINVAL;
+ if (sp->pppol2tp.s_tunnel == 0)
+ goto end;
+
+ /* Special case: prepare tunnel socket if s_session and
+ * d_session is 0. Otherwise look up tunnel using supplied
+ * tunnel id.
+ */
+ if ((sp->pppol2tp.s_session == 0) && (sp->pppol2tp.d_session == 0)) {
+ tunnel_sock = pppol2tp_prepare_tunnel_socket(sp->pppol2tp.fd,
+ sp->pppol2tp.s_tunnel,
+ &error);
+ if (tunnel_sock == NULL)
+ goto end;
+
+ tunnel = tunnel_sock->sk_user_data;
+ } else {
+ tunnel = pppol2tp_tunnel_find(sp->pppol2tp.s_tunnel);
+
+ /* Error if we can't find the tunnel */
+ error = -ENOENT;
+ if (tunnel == NULL)
+ goto end;
+
+ tunnel_sock = tunnel->sock;
+ }
+
+ /* Check that this session doesn't already exist */
+ error = -EEXIST;
+ session = pppol2tp_session_find(tunnel, sp->pppol2tp.s_session);
+ if (session != NULL)
+ goto end;
+
+ /* Allocate and initialize a new session context. */
+ session = kzalloc(sizeof(struct pppol2tp_session), GFP_KERNEL);
+ if (session == NULL) {
+ error = -ENOMEM;
+ goto end;
+ }
+
+ skb_queue_head_init(&session->reorder_q);
+
+ session->magic = L2TP_SESSION_MAGIC;
+ session->owner = current->pid;
+ session->sock = sk;
+ session->tunnel = tunnel;
+ session->tunnel_sock = tunnel_sock;
+ session->tunnel_addr = sp->pppol2tp;
+ sprintf(&session->name[0], "sess %hu/%hu",
+ session->tunnel_addr.s_tunnel,
+ session->tunnel_addr.s_session);
+
+ session->stats.tunnel_id = session->tunnel_addr.s_tunnel;
+ session->stats.session_id = session->tunnel_addr.s_session;
+
+ INIT_HLIST_NODE(&session->hlist);
+
+ /* Inherit debug options from tunnel */
+ session->debug = tunnel->debug;
+
+ /* Default MTU must allow space for UDP/L2TP/PPP
+ * headers.
+ */
+ session->mtu = session->mru = 1500 - PPPOL2TP_HEADER_OVERHEAD;
+
+ /* If PMTU discovery was enabled, use the MTU that was discovered */
+ dst = sk_dst_get(sk);
+ if (dst != NULL) {
+ u32 pmtu = dst_mtu(__sk_dst_get(sk));
+ if (pmtu != 0)
+ session->mtu = session->mru = pmtu -
+ PPPOL2TP_HEADER_OVERHEAD;
+ dst_release(dst);
+ }
+
+ /* Special case: if source & dest session_id == 0x0000, this socket is
+ * being created to manage the tunnel. Don't add the session to the
+ * session hash list, just set up the internal context for use by
+ * ioctl() and sockopt() handlers.
+ */
+ if ((session->tunnel_addr.s_session == 0) &&
+ (session->tunnel_addr.d_session == 0)) {
+ error = 0;
+ sk->sk_user_data = session;
+ goto out_no_ppp;
+ }
+
+ /* Get tunnel context from the tunnel socket */
+ tunnel = pppol2tp_sock_to_tunnel(tunnel_sock);
+ if (tunnel == NULL) {
+ error = -EBADF;
+ goto end;
+ }
+
+ /* Right now, because we don't have a way to push the incoming skb's
+ * straight through the UDP layer, the only header we need to worry
+ * about is the L2TP header. This size is different depending on
+ * whether sequence numbers are enabled for the data channel.
+ */
+ po->chan.hdrlen = PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
+
+ po->chan.private = sk;
+ po->chan.ops = &pppol2tp_chan_ops;
+ po->chan.mtu = session->mtu;
+
+ error = ppp_register_channel(&po->chan);
+ if (error)
+ goto end;
+
+ /* This is how we get the session context from the socket. */
+ sk->sk_user_data = session;
+
+ /* Add session to the tunnel's hash list */
+ write_lock(&tunnel->hlist_lock);
+ hlist_add_head(&session->hlist,
+ pppol2tp_session_id_hash(tunnel,
+ session->tunnel_addr.s_session));
+ write_unlock(&tunnel->hlist_lock);
+
+ atomic_inc(&pppol2tp_session_count);
+
+out_no_ppp:
+ pppol2tp_tunnel_inc_refcount(tunnel);
+ sk->sk_state = PPPOX_CONNECTED;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: created\n", session->name);
+
+end:
+ release_sock(sk);
+
+ if (error != 0)
+ PRINTK(session ? session->debug : -1, PPPOL2TP_MSG_CONTROL, KERN_WARNING,
+ "%s: connect failed: %d\n", session->name, error);
+
+ return error;
+}
+
+/* getname() support.
+ */
+static int pppol2tp_getname(struct socket *sock, struct sockaddr *uaddr,
+ int *usockaddr_len, int peer)
+{
+ int len = sizeof(struct sockaddr_pppol2tp);
+ struct sockaddr_pppol2tp sp;
+ int error = 0;
+ struct pppol2tp_session *session;
+
+ error = -ENOTCONN;
+ if (sock->sk->sk_state != PPPOX_CONNECTED)
+ goto end;
+
+ session = pppol2tp_sock_to_session(sock->sk);
+ if (session == NULL) {
+ error = -EBADF;
+ goto end;
+ }
+
+ sp.sa_family = AF_PPPOX;
+ sp.sa_protocol = PX_PROTO_OL2TP;
+ memcpy(&sp.pppol2tp, &session->tunnel_addr,
+ sizeof(struct pppol2tp_addr));
+
+ memcpy(uaddr, &sp, len);
+
+ *usockaddr_len = len;
+
+ error = 0;
+
+end:
+ return error;
+}
+
+/****************************************************************************
+ * ioctl() handlers.
+ *
+ * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP
+ * sockets. However, in order to control kernel tunnel features, we allow
+ * userspace to create a special "tunnel" PPPoX socket which is used for
+ * control only. Tunnel PPPoX sockets have session_id == 0 and simply allow
+ * the user application to issue L2TP setsockopt(), getsockopt() and ioctl()
+ * calls.
+ ****************************************************************************/
+
+/* Session ioctl helper.
+ */
+static int pppol2tp_session_ioctl(struct pppol2tp_session *session,
+ unsigned int cmd, unsigned long arg)
+{
+ struct ifreq ifr;
+ int err = 0;
+ struct sock *sk = session->sock;
+ int val = (int) arg;
+
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG,
+ "%s: pppol2tp_session_ioctl(cmd=%#x, arg=%#lx)\n",
+ session->name, cmd, arg);
+
+ sock_hold(sk);
+
+ switch (cmd) {
+ case SIOCGIFMTU:
+ err = -ENXIO;
+ if (!(sk->sk_state & PPPOX_CONNECTED))
+ break;
+
+ err = -EFAULT;
+ if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq)))
+ break;
+ ifr.ifr_mtu = session->mtu;
+ if (copy_to_user((void __user *) arg, &ifr, sizeof(struct ifreq)))
+ break;
+
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get mtu=%d\n", session->name, session->mtu);
+ err = 0;
+ break;
+
+ case SIOCSIFMTU:
+ err = -ENXIO;
+ if (!(sk->sk_state & PPPOX_CONNECTED))
+ break;
+
+ err = -EFAULT;
+ if (copy_from_user(&ifr, (void __user *) arg, sizeof(struct ifreq)))
+ break;
+
+ session->mtu = ifr.ifr_mtu;
+
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set mtu=%d\n", session->name, session->mtu);
+ err = 0;
+ break;
+
+ case PPPIOCGMRU:
+ err = -ENXIO;
+ if (!(sk->sk_state & PPPOX_CONNECTED))
+ break;
+
+ err = -EFAULT;
+ if (put_user(session->mru, (int __user *) arg))
+ break;
+
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get mru=%d\n", session->name, session->mru);
+ err = 0;
+ break;
+
+ case PPPIOCSMRU:
+ err = -ENXIO;
+ if (!(sk->sk_state & PPPOX_CONNECTED))
+ break;
+
+ err = -EFAULT;
+ if (get_user(val,(int __user *) arg))
+ break;
+
+ session->mru = val;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set mru=%d\n", session->name, session->mru);
+ err = 0;
+ break;
+
+ case PPPIOCGFLAGS:
+ err = -EFAULT;
+ if (put_user(session->flags, (int __user *) arg))
+ break;
+
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get flags=%d\n", session->name, session->flags);
+ err = 0;
+ break;
+
+ case PPPIOCSFLAGS:
+ err = -EFAULT;
+ if (get_user(val, (int __user *) arg))
+ break;
+ session->flags = val;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set flags=%d\n", session->name, session->flags);
+ err = 0;
+ break;
+
+ case PPPIOCGL2TPSTATS:
+ err = -ENXIO;
+ if (!(sk->sk_state & PPPOX_CONNECTED))
+ break;
+
+ if (copy_to_user((void __user *) arg, &session->stats,
+ sizeof(session->stats)))
+ break;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get L2TP stats\n", session->name);
+ err = 0;
+ break;
+
+ default:
+ err = -ENOSYS;
+ break;
+ }
+
+ sock_put(sk);
+
+ return err;
+}
+
+/* Tunnel ioctl helper.
+ *
+ * Note the special handling for PPPIOCGL2TPSTATS below. If the ioctl data
+ * specifies a session_id, the session ioctl handler is called. This allows an
+ * application to retrieve session stats via a tunnel socket.
+ */
+static int pppol2tp_tunnel_ioctl(struct pppol2tp_tunnel *tunnel,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ struct sock *sk = tunnel->sock;
+ struct pppol2tp_ioc_stats stats_req;
+
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_DEBUG,
+ "%s: pppol2tp_tunnel_ioctl(cmd=%#x, arg=%#lx)\n", tunnel->name,
+ cmd, arg);
+
+ sock_hold(sk);
+
+ switch (cmd) {
+ case PPPIOCGL2TPSTATS:
+ err = -ENXIO;
+ if (!(sk->sk_state & PPPOX_CONNECTED))
+ break;
+
+ if (copy_from_user(&stats_req, (void __user *) arg,
+ sizeof(stats_req))) {
+ err = -EFAULT;
+ break;
+ }
+ if (stats_req.session_id != 0) {
+ /* resend to session ioctl handler */
+ struct pppol2tp_session *session =
+ pppol2tp_session_find(tunnel, stats_req.session_id);
+ if (session != NULL)
+ err = pppol2tp_session_ioctl(session, cmd, arg);
+ else
+ err = -EBADR;
+ break;
+ }
+#ifdef CONFIG_XFRM
+ tunnel->stats.using_ipsec = (sk->sk_policy[0] || sk->sk_policy[1]) ? 1 : 0;
+#endif
+ if (copy_to_user((void __user *) arg, &tunnel->stats,
+ sizeof(tunnel->stats))) {
+ err = -EFAULT;
+ break;
+ }
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get L2TP stats\n", tunnel->name);
+ err = 0;
+ break;
+
+ default:
+ err = -ENOSYS;
+ break;
+ }
+
+ sock_put(sk);
+
+ return err;
+}
+
+/* Main ioctl() handler.
+ * Dispatch to tunnel or session helpers depending on the socket.
+ */
+static int pppol2tp_ioctl(struct socket *sock, unsigned int cmd,
+ unsigned long arg)
+{
+ struct sock *sk = sock->sk;
+ struct pppol2tp_session *session;
+ struct pppol2tp_tunnel *tunnel;
+ int err;
+
+ if (!sk)
+ return 0;
+
+ err = -EBADF;
+ if (sock_flag(sk, SOCK_DEAD) != 0)
+ goto end;
+
+ err = -ENOTCONN;
+ if ((sk->sk_user_data == NULL) ||
+ (!(sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND))))
+ goto end;
+
+ /* Get session context from the socket */
+ err = -EBADF;
+ session = pppol2tp_sock_to_session(sk);
+ if (session == NULL)
+ goto end;
+
+ /* Special case: if session's session_id is zero, treat ioctl as a
+ * tunnel ioctl
+ */
+ if ((session->tunnel_addr.s_session == 0) &&
+ (session->tunnel_addr.d_session == 0)) {
+ err = -EBADF;
+ tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
+ if (tunnel == NULL)
+ goto end;
+
+ err = pppol2tp_tunnel_ioctl(tunnel, cmd, arg);
+ goto end;
+ }
+
+ err = pppol2tp_session_ioctl(session, cmd, arg);
+
+end:
+ return err;
+}
+
+/*****************************************************************************
+ * setsockopt() / getsockopt() support.
+ *
+ * The PPPoX socket is created for L2TP sessions: tunnels have their own UDP
+ * sockets. In order to control kernel tunnel features, we allow userspace to
+ * create a special "tunnel" PPPoX socket which is used for control only.
+ * Tunnel PPPoX sockets have session_id == 0 and simply allow the user
+ * application to issue L2TP setsockopt(), getsockopt() and ioctl() calls.
+ *****************************************************************************/
+
+/* Tunnel setsockopt() helper.
+ */
+static int pppol2tp_tunnel_setsockopt(struct sock *sk,
+ struct pppol2tp_tunnel *tunnel,
+ int optname, int val)
+{
+ int err = 0;
+
+ switch (optname) {
+ case PPPOL2TP_SO_DEBUG:
+ tunnel->debug = val;
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set debug=%x\n", tunnel->name, tunnel->debug);
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ return err;
+}
+
+/* Session setsockopt helper.
+ */
+static int pppol2tp_session_setsockopt(struct sock *sk,
+ struct pppol2tp_session *session,
+ int optname, int val)
+{
+ int err = 0;
+
+ switch (optname) {
+ case PPPOL2TP_SO_RECVSEQ:
+ if ((val != 0) && (val != 1)) {
+ err = -EINVAL;
+ break;
+ }
+ session->recv_seq = val ? -1 : 0;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set recv_seq=%d\n", session->name,
+ session->recv_seq);
+ break;
+
+ case PPPOL2TP_SO_SENDSEQ:
+ if ((val != 0) && (val != 1)) {
+ err = -EINVAL;
+ break;
+ }
+ session->send_seq = val ? -1 : 0;
+ {
+ struct sock *ssk = session->sock;
+ struct pppox_sock *po = pppox_sk(ssk);
+ po->chan.hdrlen = val ? PPPOL2TP_L2TP_HDR_SIZE_SEQ :
+ PPPOL2TP_L2TP_HDR_SIZE_NOSEQ;
+ }
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set send_seq=%d\n", session->name, session->send_seq);
+ break;
+
+ case PPPOL2TP_SO_LNSMODE:
+ if ((val != 0) && (val != 1)) {
+ err = -EINVAL;
+ break;
+ }
+ session->lns_mode = val ? -1 : 0;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set lns_mode=%d\n", session->name,
+ session->lns_mode);
+ break;
+
+ case PPPOL2TP_SO_DEBUG:
+ session->debug = val;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set debug=%x\n", session->name, session->debug);
+ break;
+
+ case PPPOL2TP_SO_REORDERTO:
+ session->reorder_timeout = msecs_to_jiffies(val);
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: set reorder_timeout=%d\n", session->name,
+ session->reorder_timeout);
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ return err;
+}
+
+/* Main setsockopt() entry point.
+ * Does API checks, then calls either the tunnel or session setsockopt
+ * handler, according to whether the PPPoL2TP socket is a for a regular
+ * session or the special tunnel type.
+ */
+static int pppol2tp_setsockopt(struct socket *sock, int level, int optname,
+ char __user *optval, int optlen)
+{
+ struct sock *sk = sock->sk;
+ struct pppol2tp_session *session = sk->sk_user_data;
+ struct pppol2tp_tunnel *tunnel;
+ int val;
+ int err;
+
+ if (level != SOL_PPPOL2TP)
+ return udp_prot.setsockopt(sk, level, optname, optval, optlen);
+
+ if (optlen < sizeof(int))
+ return -EINVAL;
+
+ if (get_user(val, (int __user *)optval))
+ return -EFAULT;
+
+ err = -ENOTCONN;
+ if (sk->sk_user_data == NULL)
+ goto end;
+
+ /* Get session context from the socket */
+ err = -EBADF;
+ session = pppol2tp_sock_to_session(sk);
+ if (session == NULL)
+ goto end;
+
+ /* Special case: if session_id == 0x0000, treat as operation on tunnel
+ */
+ if ((session->tunnel_addr.s_session == 0) &&
+ (session->tunnel_addr.d_session == 0)) {
+ err = -EBADF;
+ tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
+ if (tunnel == NULL)
+ goto end;
+
+ err = pppol2tp_tunnel_setsockopt(sk, tunnel, optname, val);
+ } else
+ err = pppol2tp_session_setsockopt(sk, session, optname, val);
+
+ err = 0;
+
+end:
+ return err;
+}
+
+/* Tunnel getsockopt helper. Called with sock locked.
+ */
+static int pppol2tp_tunnel_getsockopt(struct sock *sk,
+ struct pppol2tp_tunnel *tunnel,
+ int optname, int __user *val)
+{
+ int err = 0;
+
+ switch (optname) {
+ case PPPOL2TP_SO_DEBUG:
+ *val = tunnel->debug;
+ PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get debug=%x\n", tunnel->name, tunnel->debug);
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ return err;
+}
+
+/* Session getsockopt helper. Called with sock locked.
+ */
+static int pppol2tp_session_getsockopt(struct sock *sk,
+ struct pppol2tp_session *session,
+ int optname, int __user *val)
+{
+ int err = 0;
+
+ switch (optname) {
+ case PPPOL2TP_SO_RECVSEQ:
+ *val = session->recv_seq;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get recv_seq=%d\n", session->name, *val);
+ break;
+
+ case PPPOL2TP_SO_SENDSEQ:
+ *val = session->send_seq;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get send_seq=%d\n", session->name, *val);
+ break;
+
+ case PPPOL2TP_SO_LNSMODE:
+ *val = session->lns_mode;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get lns_mode=%d\n", session->name, *val);
+ break;
+
+ case PPPOL2TP_SO_DEBUG:
+ *val = session->debug;
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get debug=%d\n", session->name, *val);
+ break;
+
+ case PPPOL2TP_SO_REORDERTO:
+ *val = (int) jiffies_to_msecs(session->reorder_timeout);
+ PRINTK(session->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
+ "%s: get reorder_timeout=%d\n", session->name, *val);
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ }
+
+ return err;
+}
+
+/* Main getsockopt() entry point.
+ * Does API checks, then calls either the tunnel or session getsockopt
+ * handler, according to whether the PPPoX socket is a for a regular session
+ * or the special tunnel type.
+ */
+static int pppol2tp_getsockopt(struct socket *sock, int level,
+ int optname, char __user *optval, int __user *optlen)
+{
+ struct sock *sk = sock->sk;
+ struct pppol2tp_session *session = sk->sk_user_data;
+ struct pppol2tp_tunnel *tunnel;
+ int val, len;
+ int err;
+
+ if (level != SOL_PPPOL2TP)
+ return udp_prot.getsockopt(sk, level, optname, optval, optlen);
+
+ if (get_user(len, (int __user *) optlen))
+ return -EFAULT;
+
+ len = min_t(unsigned int, len, sizeof(int));
+
+ if (len < 0)
+ return -EINVAL;
+
+ err = -ENOTCONN;
+ if (sk->sk_user_data == NULL)
+ goto end;
+
+ /* Get the session context */
+ err = -EBADF;
+ session = pppol2tp_sock_to_session(sk);
+ if (session == NULL)
+ goto end;
+
+ /* Special case: if session_id == 0x0000, treat as operation on tunnel */
+ if ((session->tunnel_addr.s_session == 0) &&
+ (session->tunnel_addr.d_session == 0)) {
+ err = -EBADF;
+ tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock);
+ if (tunnel == NULL)
+ goto end;
+
+ err = pppol2tp_tunnel_getsockopt(sk, tunnel, optname, &val);
+ } else
+ err = pppol2tp_session_getsockopt(sk, session, optname, &val);
+
+ err = -EFAULT;
+ if (put_user(len, (int __user *) optlen))
+ goto end;
+
+ if (copy_to_user((void __user *) optval, &val, len))
+ goto end;
+
+ err = 0;
+end:
+ return err;
+}
+
+/*****************************************************************************
+ * /proc filesystem for debug
+ *****************************************************************************/
+
+#ifdef CONFIG_PROC_FS
+
+#include <linux/seq_file.h>
+
+struct pppol2tp_seq_data {
+ struct pppol2tp_tunnel *tunnel; /* current tunnel */
+ struct pppol2tp_session *session; /* NULL means get first session in tunnel */
+};
+
+static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, struct pppol2tp_session *curr)
+{
+ struct pppol2tp_session *session = NULL;
+ struct hlist_node *walk;
+ int found = 0;
+ int next = 0;
+ int i;
+
+ read_lock(&tunnel->hlist_lock);
+ for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) {
+ hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) {
+ if (curr == NULL) {
+ found = 1;
+ goto out;
+ }
+ if (session == curr) {
+ next = 1;
+ continue;
+ }
+ if (next) {
+ found = 1;
+ goto out;
+ }
+ }
+ }
+out:
+ read_unlock(&tunnel->hlist_lock);
+ if (!found)
+ session = NULL;
+
+ return session;
+}
+
+static struct pppol2tp_tunnel *next_tunnel(struct pppol2tp_tunnel *curr)
+{
+ struct pppol2tp_tunnel *tunnel = NULL;
+
+ read_lock(&pppol2tp_tunnel_list_lock);
+ if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) {
+ goto out;
+ }
+ tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list);
+out:
+ read_unlock(&pppol2tp_tunnel_list_lock);
+
+ return tunnel;
+}
+
+static void *pppol2tp_seq_start(struct seq_file *m, loff_t *offs)
+{
+ struct pppol2tp_seq_data *pd = SEQ_START_TOKEN;
+ loff_t pos = *offs;
+
+ if (!pos)
+ goto out;
+
+ BUG_ON(m->private == NULL);
+ pd = m->private;
+
+ if (pd->tunnel == NULL) {
+ if (!list_empty(&pppol2tp_tunnel_list))
+ pd->tunnel = list_entry(pppol2tp_tunnel_list.next, struct pppol2tp_tunnel, list);
+ } else {
+ pd->session = next_session(pd->tunnel, pd->session);
+ if (pd->session == NULL) {
+ pd->tunnel = next_tunnel(pd->tunnel);
+ }
+ }
+
+ /* NULL tunnel and session indicates end of list */
+ if ((pd->tunnel == NULL) && (pd->session == NULL))
+ pd = NULL;
+
+out:
+ return pd;
+}
+
+static void *pppol2tp_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return NULL;
+}
+
+static void pppol2tp_seq_stop(struct seq_file *p, void *v)
+{
+ /* nothing to do */
+}
+
+static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
+{
+ struct pppol2tp_tunnel *tunnel = v;
+
+ seq_printf(m, "\nTUNNEL '%s', %c %d\n",
+ tunnel->name,
+ (tunnel == tunnel->sock->sk_user_data) ? 'Y':'N',
+ atomic_read(&tunnel->ref_count) - 1);
+ seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n",
+ tunnel->debug,
+ tunnel->stats.tx_packets, tunnel->stats.tx_bytes,
+ tunnel->stats.tx_errors,
+ tunnel->stats.rx_packets, tunnel->stats.rx_bytes,
+ tunnel->stats.rx_errors);
+}
+
+static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
+{
+ struct pppol2tp_session *session = v;
+
+ seq_printf(m, " SESSION '%s' %08X/%d %04X/%04X -> "
+ "%04X/%04X %d %c\n",
+ session->name,
+ ntohl(session->tunnel_addr.addr.sin_addr.s_addr),
+ ntohs(session->tunnel_addr.addr.sin_port),
+ session->tunnel_addr.s_tunnel,
+ session->tunnel_addr.s_session,
+ session->tunnel_addr.d_tunnel,
+ session->tunnel_addr.d_session,
+ session->sock->sk_state,
+ (session == session->sock->sk_user_data) ?
+ 'Y' : 'N');
+ seq_printf(m, " %d/%d/%c/%c/%s %08x %u\n",
+ session->mtu, session->mru,
+ session->recv_seq ? 'R' : '-',
+ session->send_seq ? 'S' : '-',
+ session->lns_mode ? "LNS" : "LAC",
+ session->debug,
+ jiffies_to_msecs(session->reorder_timeout));
+ seq_printf(m, " %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n",
+ session->nr, session->ns,
+ session->stats.tx_packets,
+ session->stats.tx_bytes,
+ session->stats.tx_errors,
+ session->stats.rx_packets,
+ session->stats.rx_bytes,
+ session->stats.rx_errors);
+}
+
+static int pppol2tp_seq_show(struct seq_file *m, void *v)
+{
+ struct pppol2tp_seq_data *pd = v;
+
+ /* display header on line 1 */
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(m, "PPPoL2TP driver info, " PPPOL2TP_DRV_VERSION "\n");
+ seq_puts(m, "TUNNEL name, user-data-ok session-count\n");
+ seq_puts(m, " debug tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
+ seq_puts(m, " SESSION name, addr/port src-tid/sid "
+ "dest-tid/sid state user-data-ok\n");
+ seq_puts(m, " mtu/mru/rcvseq/sendseq/lns debug reorderto\n");
+ seq_puts(m, " nr/ns tx-pkts/bytes/errs rx-pkts/bytes/errs\n");
+ goto out;
+ }
+
+ /* Show the tunnel or session context.
+ */
+ if (pd->session == NULL)
+ pppol2tp_seq_tunnel_show(m, pd->tunnel);
+ else
+ pppol2tp_seq_session_show(m, pd->session);
+
+out:
+ return 0;
+}
+
+static struct seq_operations pppol2tp_seq_ops = {
+ .start = pppol2tp_seq_start,
+ .next = pppol2tp_seq_next,
+ .stop = pppol2tp_seq_stop,
+ .show = pppol2tp_seq_show,
+};
+
+/* Called when our /proc file is opened. We allocate data for use when
+ * iterating our tunnel / session contexts and store it in the private
+ * data of the seq_file.
+ */
+static int pppol2tp_proc_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *m;
+ struct pppol2tp_seq_data *pd;
+ int ret = 0;
+
+ ret = seq_open(file, &pppol2tp_seq_ops);
+ if (ret < 0)
+ goto out;
+
+ m = file->private_data;
+
+ /* Allocate and fill our proc_data for access later */
+ ret = -ENOMEM;
+ m->private = kzalloc(sizeof(struct pppol2tp_seq_data), GFP_KERNEL);
+ if (m->private == NULL)
+ goto out;
+
+ pd = m->private;
+ ret = 0;
+
+out:
+ return ret;
+}
+
+/* Called when /proc file access completes.
+ */
+static int pppol2tp_proc_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+
+ kfree(m->private);
+ m->private = NULL;
+
+ return seq_release(inode, file);
+}
+
+static struct file_operations pppol2tp_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = pppol2tp_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = pppol2tp_proc_release,
+};
+
+static struct proc_dir_entry *pppol2tp_proc;
+
+#endif /* CONFIG_PROC_FS */
+
+/*****************************************************************************
+ * Init and cleanup
+ *****************************************************************************/
+
+static struct proto_ops pppol2tp_ops = {
+ .family = AF_PPPOX,
+ .owner = THIS_MODULE,
+ .release = pppol2tp_release,
+ .bind = sock_no_bind,
+ .connect = pppol2tp_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .getname = pppol2tp_getname,
+ .poll = datagram_poll,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = pppol2tp_setsockopt,
+ .getsockopt = pppol2tp_getsockopt,
+ .sendmsg = pppol2tp_sendmsg,
+ .recvmsg = pppol2tp_recvmsg,
+ .mmap = sock_no_mmap,
+ .ioctl = pppox_ioctl,
+};
+
+static struct pppox_proto pppol2tp_proto = {
+ .create = pppol2tp_create,
+ .ioctl = pppol2tp_ioctl
+};
+
+static int __init pppol2tp_init(void)
+{
+ int err;
+
+ err = proto_register(&pppol2tp_sk_proto, 0);
+ if (err)
+ goto out;
+ err = register_pppox_proto(PX_PROTO_OL2TP, &pppol2tp_proto);
+ if (err)
+ goto out_unregister_pppol2tp_proto;
+
+#ifdef CONFIG_PROC_FS
+ pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net);
+ if (!pppol2tp_proc) {
+ err = -ENOMEM;
+ goto out_unregister_pppox_proto;
+ }
+ pppol2tp_proc->proc_fops = &pppol2tp_proc_fops;
+#endif /* CONFIG_PROC_FS */
+ printk(KERN_INFO "PPPoL2TP kernel driver, %s\n",
+ PPPOL2TP_DRV_VERSION);
+
+out:
+ return err;
+
+out_unregister_pppox_proto:
+ unregister_pppox_proto(PX_PROTO_OL2TP);
+out_unregister_pppol2tp_proto:
+ proto_unregister(&pppol2tp_sk_proto);
+ goto out;
+}
+
+static void __exit pppol2tp_exit(void)
+{
+ unregister_pppox_proto(PX_PROTO_OL2TP);
+
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("pppol2tp", proc_net);
+#endif
+ proto_unregister(&pppol2tp_sk_proto);
+}
+
+module_init(pppol2tp_init);
+module_exit(pppol2tp_exit);
+
+MODULE_AUTHOR("Martijn van Oosterhout <kleptog@svana.org>,"
+ "James Chapman <jchapman@katalix.com>");
+MODULE_DESCRIPTION("PPP over L2TP over UDP");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(PPPOL2TP_DRV_VERSION);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 982a9010c7a9..bb6896ae3151 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2338,7 +2338,7 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
{
struct skb_shared_info *info = skb_shinfo(skb);
unsigned int cur_frag, entry;
- struct TxDesc *txd;
+ struct TxDesc * uninitialized_var(txd);
entry = tp->cur_tx;
for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index fa29a403a247..afef6c0c59fe 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -796,12 +796,14 @@ static void free_shared_mem(struct s2io_nic *nic)
struct mac_info *mac_control;
struct config_param *config;
int lst_size, lst_per_page;
- struct net_device *dev = nic->dev;
+ struct net_device *dev;
int page_num = 0;
if (!nic)
return;
+ dev = nic->dev;
+
mac_control = &nic->mac_control;
config = &nic->config;
@@ -1135,7 +1137,7 @@ static int init_nic(struct s2io_nic *nic)
* SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
*/
if ((nic->device_type == XFRAME_I_DEVICE) &&
- (get_xena_rev_id(nic->pdev) < 4))
+ (nic->pdev->revision < 4))
writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);
val64 = readq(&bar0->tx_fifo_partition_0);
@@ -1873,7 +1875,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == FALSE) {
- if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
+ if ((!herc && (sp->pdev->revision >= 4)) || herc) {
if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
} else {
@@ -1881,7 +1883,7 @@ static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
ret = 1;
}
} else {
- if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
+ if ((!herc && (sp->pdev->revision >= 4)) || herc) {
if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
@@ -7076,23 +7078,6 @@ static void s2io_link(struct s2io_nic * sp, int link)
}
/**
- * get_xena_rev_id - to identify revision ID of xena.
- * @pdev : PCI Dev structure
- * Description:
- * Function to identify the Revision ID of xena.
- * Return value:
- * returns the revision ID of the device.
- */
-
-static int get_xena_rev_id(struct pci_dev *pdev)
-{
- u8 id = 0;
- int ret;
- ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id);
- return id;
-}
-
-/**
* s2io_init_pci -Initialization of PCI and PCI-X configuration registers .
* @sp : private member of the device structure, which is a pointer to the
* s2io_nic structure.
@@ -7550,7 +7535,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
s2io_vpd_read(sp);
DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n");
DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
- sp->product_name, get_xena_rev_id(sp->pdev));
+ sp->product_name, pdev->revision);
DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
s2io_driver_version);
DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 58592780f519..3887fe63a908 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -1033,7 +1033,6 @@ static void s2io_set_link(struct work_struct *work);
static int s2io_set_swapper(struct s2io_nic * sp);
static void s2io_card_down(struct s2io_nic *nic);
static int s2io_card_up(struct s2io_nic *nic);
-static int get_xena_rev_id(struct pci_dev *pdev);
static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit,
int bit_state);
static int s2io_add_isr(struct s2io_nic * sp);
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index ad94358ece89..7dae4d404978 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -690,9 +690,9 @@ static int lan_saa9730_rx(struct net_device *dev)
lp->stats.rx_packets++;
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *) pData,
- len, 0);
+ len);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
@@ -940,15 +940,14 @@ static void lan_saa9730_set_multicast(struct net_device *dev)
CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
&lp->lan_saa9730_regs->CamCtl);
} else {
- if (dev->flags & IFF_ALLMULTI) {
+ if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
/* accept all multicast packets */
- writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
- CAM_CONTROL_BROAD_ACC,
- &lp->lan_saa9730_regs->CamCtl);
- } else {
/*
* Will handle the multicast stuff later. -carstenl
*/
+ writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
+ CAM_CONTROL_BROAD_ACC,
+ &lp->lan_saa9730_regs->CamCtl);
}
}
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 2106becf6990..384b4685e977 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -320,7 +320,7 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp
skb_put(skb, len);
/* Copy out of kseg1 to avoid silly cache flush. */
- eth_copy_and_sum(skb, pkt_pointer + 2, len, 0);
+ skb_copy_to_linear_data(skb, pkt_pointer + 2, len);
skb->protocol = eth_type_trans(skb, dev);
/* We don't want to receive our own packets */
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index e886e8d7cfdf..4c3d98ff4cd4 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -600,10 +600,9 @@ static int __init shaper_init(void)
return -ENODEV;
alloc_size = sizeof(*dev) * shapers;
- devs = kmalloc(alloc_size, GFP_KERNEL);
+ devs = kzalloc(alloc_size, GFP_KERNEL);
if (!devs)
return -ENOMEM;
- memset(devs, 0, alloc_size);
for (i = 0; i < shapers; i++) {
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index bc8de48da313..ec2ad9f0efa2 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -548,7 +548,7 @@ static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
if (skb) {
skb_reserve(skb, NET_IP_ALIGN);
- eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
+ skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
*sk_buff = skb;
sis190_give_to_asic(desc, rx_buf_sz);
ret = 0;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index a2f32151559e..13f08a390e1f 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -692,6 +692,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
u16 reg;
+ u32 rx_reg;
int i;
const u8 *addr = hw->dev[port]->dev_addr;
@@ -768,11 +769,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
/* Configure Rx MAC FIFO */
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
- reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+ rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
if (hw->chip_id == CHIP_ID_YUKON_EX)
- reg |= GMF_RX_OVER_ON;
+ rx_reg |= GMF_RX_OVER_ON;
- sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+ sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
/* Flush Rx MAC FIFO on any flow control or error */
sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 786d4b9c07ec..8b6478663a56 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -740,7 +740,7 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
pci_set_master(pdev);
/* enable MWI -- it vastly improves Rx performance on sparc64 */
- pci_set_mwi(pdev);
+ pci_try_set_mwi(pdev);
#ifdef ZEROCOPY
/* Starfire can do TCP/UDP checksumming */
@@ -1456,7 +1456,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
pci_dma_sync_single_for_cpu(np->pci_dev,
np->rx_info[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_info[entry].skb->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb, np->rx_info[entry].skb->data, pkt_len);
pci_dma_sync_single_for_device(np->pci_dev,
np->rx_info[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index a123ea87893b..b77ab6e8fd35 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -777,7 +777,7 @@ static void sun3_82586_rcv_int(struct net_device *dev)
{
skb_reserve(skb,2);
skb_put(skb,totlen);
- eth_copy_and_sum(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen,0);
+ skb_copy_to_linear_data(skb,(char *) p->base+swab32((unsigned long) rbd->buffer),totlen);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
p->stats.rx_packets++;
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 791e081fdc15..f1548c033327 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -853,10 +853,9 @@ static int lance_rx( struct net_device *dev )
skb_reserve( skb, 2 ); /* 16 byte align */
skb_put( skb, pkt_len ); /* Make room */
-// skb_copy_to_linear_data(skb, PKTBUF_ADDR(head), pkt_len);
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
PKTBUF_ADDR(head),
- pkt_len, 0);
+ pkt_len);
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 2ad8d58dee3b..b3e0158def4f 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -860,7 +860,7 @@ static void bigmac_rx(struct bigmac *bp)
sbus_dma_sync_single_for_cpu(bp->bigmac_sdev,
this->rx_addr, len,
SBUS_DMA_FROMDEVICE);
- eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0);
+ skb_copy_to_linear_data(copy_skb, (unsigned char *)skb->data, len);
sbus_dma_sync_single_for_device(bp->bigmac_sdev,
this->rx_addr, len,
SBUS_DMA_FROMDEVICE);
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index e1f912d04043..af0c9831074c 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -397,7 +397,6 @@ struct netdev_private {
unsigned char phys[MII_CNT]; /* MII device addresses, only first one used. */
struct pci_dev *pci_dev;
void __iomem *base;
- unsigned char pci_rev_id;
};
/* The station address location in the EEPROM. */
@@ -544,8 +543,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
dev->change_mtu = &change_mtu;
pci_set_drvdata(pdev, dev);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
-
i = register_netdev(dev);
if (i)
goto err_out_unmap_rx;
@@ -828,7 +825,7 @@ static int netdev_open(struct net_device *dev)
iowrite8(100, ioaddr + RxDMAPollPeriod);
iowrite8(127, ioaddr + TxDMAPollPeriod);
/* Fix DFE-580TX packet drop issue */
- if (np->pci_rev_id >= 0x14)
+ if (np->pci_dev->revision >= 0x14)
iowrite8(0x01, ioaddr + DebugCtrl1);
netif_start_queue(dev);
@@ -1194,7 +1191,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
hw_frame_id = ioread8(ioaddr + TxFrameId);
}
- if (np->pci_rev_id >= 0x14) {
+ if (np->pci_dev->revision >= 0x14) {
spin_lock(&np->lock);
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
int entry = np->dirty_tx % TX_RING_SIZE;
@@ -1313,7 +1310,7 @@ static void rx_poll(unsigned long data)
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len);
pci_dma_sync_single_for_device(np->pci_dev,
desc->frag[0].addr,
np->rx_buf_sz,
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 15146a119230..8b35f13318ea 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3095,12 +3095,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
#ifdef CONFIG_SPARC
hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
- if (hp->hm_revision == 0xff) {
- unsigned char prev;
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &prev);
- hp->hm_revision = 0xc0 | (prev & 0x0f);
- }
+ if (hp->hm_revision == 0xff)
+ hp->hm_revision = 0xc0 | (pdev->revision & 0x0f);
#else
/* works with this on non-sparc hosts */
hp->hm_revision = 0x20;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 42722530ab24..053b7cb0d944 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -549,9 +549,9 @@ static void lance_rx_dvma(struct net_device *dev)
skb_reserve(skb, 2); /* 16 byte align */
skb_put(skb, len); /* make room */
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
(unsigned char *)&(ib->rx_buf [entry][0]),
- len, 0);
+ len);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index fa70e0b78af7..1b65ae8a1c7c 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -439,8 +439,8 @@ static void qe_rx(struct sunqe *qep)
} else {
skb_reserve(skb, 2);
skb_put(skb, len);
- eth_copy_and_sum(skb, (unsigned char *) this_qbuf,
- len, 0);
+ skb_copy_to_linear_data(skb, (unsigned char *) this_qbuf,
+ len);
skb->protocol = eth_type_trans(skb, qep->dev);
netif_rx(skb);
qep->dev->last_rx = jiffies;
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
new file mode 100644
index 000000000000..61f98251feab
--- /dev/null
+++ b/drivers/net/sunvnet.c
@@ -0,0 +1,1295 @@
+/* sunvnet.c: Sun LDOM Virtual Network Driver.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/mutex.h>
+
+#include <asm/vio.h>
+#include <asm/ldc.h>
+
+#include "sunvnet.h"
+
+#define DRV_MODULE_NAME "sunvnet"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.0"
+#define DRV_MODULE_RELDATE "June 25, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun LDOM virtual network driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+/* Ordered from largest major to lowest */
+static struct vio_version vnet_versions[] = {
+ { .major = 1, .minor = 0 },
+};
+
+static inline u32 vnet_tx_dring_avail(struct vio_dring_state *dr)
+{
+ return vio_dring_avail(dr, VNET_TX_RING_SIZE);
+}
+
+static int vnet_handle_unknown(struct vnet_port *port, void *arg)
+{
+ struct vio_msg_tag *pkt = arg;
+
+ printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n",
+ pkt->type, pkt->stype, pkt->stype_env, pkt->sid);
+ printk(KERN_ERR PFX "Resetting connection.\n");
+
+ ldc_disconnect(port->vio.lp);
+
+ return -ECONNRESET;
+}
+
+static int vnet_send_attr(struct vio_driver_state *vio)
+{
+ struct vnet_port *port = to_vnet_port(vio);
+ struct net_device *dev = port->vp->dev;
+ struct vio_net_attr_info pkt;
+ int i;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.tag.type = VIO_TYPE_CTRL;
+ pkt.tag.stype = VIO_SUBTYPE_INFO;
+ pkt.tag.stype_env = VIO_ATTR_INFO;
+ pkt.tag.sid = vio_send_sid(vio);
+ pkt.xfer_mode = VIO_DRING_MODE;
+ pkt.addr_type = VNET_ADDR_ETHERMAC;
+ pkt.ack_freq = 0;
+ for (i = 0; i < 6; i++)
+ pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8);
+ pkt.mtu = ETH_FRAME_LEN;
+
+ viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] "
+ "ackfreq[%u] mtu[%llu]\n",
+ pkt.xfer_mode, pkt.addr_type,
+ (unsigned long long) pkt.addr,
+ pkt.ack_freq,
+ (unsigned long long) pkt.mtu);
+
+ return vio_ldc_send(vio, &pkt, sizeof(pkt));
+}
+
+static int handle_attr_info(struct vio_driver_state *vio,
+ struct vio_net_attr_info *pkt)
+{
+ viodbg(HS, "GOT NET ATTR INFO xmode[0x%x] atype[0x%x] addr[%llx] "
+ "ackfreq[%u] mtu[%llu]\n",
+ pkt->xfer_mode, pkt->addr_type,
+ (unsigned long long) pkt->addr,
+ pkt->ack_freq,
+ (unsigned long long) pkt->mtu);
+
+ pkt->tag.sid = vio_send_sid(vio);
+
+ if (pkt->xfer_mode != VIO_DRING_MODE ||
+ pkt->addr_type != VNET_ADDR_ETHERMAC ||
+ pkt->mtu != ETH_FRAME_LEN) {
+ viodbg(HS, "SEND NET ATTR NACK\n");
+
+ pkt->tag.stype = VIO_SUBTYPE_NACK;
+
+ (void) vio_ldc_send(vio, pkt, sizeof(*pkt));
+
+ return -ECONNRESET;
+ } else {
+ viodbg(HS, "SEND NET ATTR ACK\n");
+
+ pkt->tag.stype = VIO_SUBTYPE_ACK;
+
+ return vio_ldc_send(vio, pkt, sizeof(*pkt));
+ }
+
+}
+
+static int handle_attr_ack(struct vio_driver_state *vio,
+ struct vio_net_attr_info *pkt)
+{
+ viodbg(HS, "GOT NET ATTR ACK\n");
+
+ return 0;
+}
+
+static int handle_attr_nack(struct vio_driver_state *vio,
+ struct vio_net_attr_info *pkt)
+{
+ viodbg(HS, "GOT NET ATTR NACK\n");
+
+ return -ECONNRESET;
+}
+
+static int vnet_handle_attr(struct vio_driver_state *vio, void *arg)
+{
+ struct vio_net_attr_info *pkt = arg;
+
+ switch (pkt->tag.stype) {
+ case VIO_SUBTYPE_INFO:
+ return handle_attr_info(vio, pkt);
+
+ case VIO_SUBTYPE_ACK:
+ return handle_attr_ack(vio, pkt);
+
+ case VIO_SUBTYPE_NACK:
+ return handle_attr_nack(vio, pkt);
+
+ default:
+ return -ECONNRESET;
+ }
+}
+
+static void vnet_handshake_complete(struct vio_driver_state *vio)
+{
+ struct vio_dring_state *dr;
+
+ dr = &vio->drings[VIO_DRIVER_RX_RING];
+ dr->snd_nxt = dr->rcv_nxt = 1;
+
+ dr = &vio->drings[VIO_DRIVER_TX_RING];
+ dr->snd_nxt = dr->rcv_nxt = 1;
+}
+
+/* The hypervisor interface that implements copying to/from imported
+ * memory from another domain requires that copies are done to 8-byte
+ * aligned buffers, and that the lengths of such copies are also 8-byte
+ * multiples.
+ *
+ * So we align skb->data to an 8-byte multiple and pad-out the data
+ * area so we can round the copy length up to the next multiple of
+ * 8 for the copy.
+ *
+ * The transmitter puts the actual start of the packet 6 bytes into
+ * the buffer it sends over, so that the IP headers after the ethernet
+ * header are aligned properly. These 6 bytes are not in the descriptor
+ * length, they are simply implied. This offset is represented using
+ * the VNET_PACKET_SKIP macro.
+ */
+static struct sk_buff *alloc_and_align_skb(struct net_device *dev,
+ unsigned int len)
+{
+ struct sk_buff *skb = netdev_alloc_skb(dev, len+VNET_PACKET_SKIP+8+8);
+ unsigned long addr, off;
+
+ if (unlikely(!skb))
+ return NULL;
+
+ addr = (unsigned long) skb->data;
+ off = ((addr + 7UL) & ~7UL) - addr;
+ if (off)
+ skb_reserve(skb, off);
+
+ return skb;
+}
+
+static int vnet_rx_one(struct vnet_port *port, unsigned int len,
+ struct ldc_trans_cookie *cookies, int ncookies)
+{
+ struct net_device *dev = port->vp->dev;
+ unsigned int copy_len;
+ struct sk_buff *skb;
+ int err;
+
+ err = -EMSGSIZE;
+ if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) {
+ dev->stats.rx_length_errors++;
+ goto out_dropped;
+ }
+
+ skb = alloc_and_align_skb(dev, len);
+ err = -ENOMEM;
+ if (unlikely(!skb)) {
+ dev->stats.rx_missed_errors++;
+ goto out_dropped;
+ }
+
+ copy_len = (len + VNET_PACKET_SKIP + 7U) & ~7U;
+ skb_put(skb, copy_len);
+ err = ldc_copy(port->vio.lp, LDC_COPY_IN,
+ skb->data, copy_len, 0,
+ cookies, ncookies);
+ if (unlikely(err < 0)) {
+ dev->stats.rx_frame_errors++;
+ goto out_free_skb;
+ }
+
+ skb_pull(skb, VNET_PACKET_SKIP);
+ skb_trim(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+
+ netif_rx(skb);
+
+ return 0;
+
+out_free_skb:
+ kfree_skb(skb);
+
+out_dropped:
+ dev->stats.rx_dropped++;
+ return err;
+}
+
+static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr,
+ u32 start, u32 end, u8 vio_dring_state)
+{
+ struct vio_dring_data hdr = {
+ .tag = {
+ .type = VIO_TYPE_DATA,
+ .stype = VIO_SUBTYPE_ACK,
+ .stype_env = VIO_DRING_DATA,
+ .sid = vio_send_sid(&port->vio),
+ },
+ .dring_ident = dr->ident,
+ .start_idx = start,
+ .end_idx = end,
+ .state = vio_dring_state,
+ };
+ int err, delay;
+
+ hdr.seq = dr->snd_nxt;
+ delay = 1;
+ do {
+ err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr));
+ if (err > 0) {
+ dr->snd_nxt++;
+ break;
+ }
+ udelay(delay);
+ if ((delay <<= 1) > 128)
+ delay = 128;
+ } while (err == -EAGAIN);
+
+ return err;
+}
+
+static u32 next_idx(u32 idx, struct vio_dring_state *dr)
+{
+ if (++idx == dr->num_entries)
+ idx = 0;
+ return idx;
+}
+
+static u32 prev_idx(u32 idx, struct vio_dring_state *dr)
+{
+ if (idx == 0)
+ idx = dr->num_entries - 1;
+ else
+ idx--;
+
+ return idx;
+}
+
+static struct vio_net_desc *get_rx_desc(struct vnet_port *port,
+ struct vio_dring_state *dr,
+ u32 index)
+{
+ struct vio_net_desc *desc = port->vio.desc_buf;
+ int err;
+
+ err = ldc_get_dring_entry(port->vio.lp, desc, dr->entry_size,
+ (index * dr->entry_size),
+ dr->cookies, dr->ncookies);
+ if (err < 0)
+ return ERR_PTR(err);
+
+ return desc;
+}
+
+static int put_rx_desc(struct vnet_port *port,
+ struct vio_dring_state *dr,
+ struct vio_net_desc *desc,
+ u32 index)
+{
+ int err;
+
+ err = ldc_put_dring_entry(port->vio.lp, desc, dr->entry_size,
+ (index * dr->entry_size),
+ dr->cookies, dr->ncookies);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int vnet_walk_rx_one(struct vnet_port *port,
+ struct vio_dring_state *dr,
+ u32 index, int *needs_ack)
+{
+ struct vio_net_desc *desc = get_rx_desc(port, dr, index);
+ struct vio_driver_state *vio = &port->vio;
+ int err;
+
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+
+ viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%lx:%lx]\n",
+ desc->hdr.state, desc->hdr.ack,
+ desc->size, desc->ncookies,
+ desc->cookies[0].cookie_addr,
+ desc->cookies[0].cookie_size);
+
+ if (desc->hdr.state != VIO_DESC_READY)
+ return 1;
+ err = vnet_rx_one(port, desc->size, desc->cookies, desc->ncookies);
+ if (err == -ECONNRESET)
+ return err;
+ desc->hdr.state = VIO_DESC_DONE;
+ err = put_rx_desc(port, dr, desc, index);
+ if (err < 0)
+ return err;
+ *needs_ack = desc->hdr.ack;
+ return 0;
+}
+
+static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr,
+ u32 start, u32 end)
+{
+ struct vio_driver_state *vio = &port->vio;
+ int ack_start = -1, ack_end = -1;
+
+ end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr);
+
+ viodbg(DATA, "vnet_walk_rx start[%08x] end[%08x]\n", start, end);
+
+ while (start != end) {
+ int ack = 0, err = vnet_walk_rx_one(port, dr, start, &ack);
+ if (err == -ECONNRESET)
+ return err;
+ if (err != 0)
+ break;
+ if (ack_start == -1)
+ ack_start = start;
+ ack_end = start;
+ start = next_idx(start, dr);
+ if (ack && start != end) {
+ err = vnet_send_ack(port, dr, ack_start, ack_end,
+ VIO_DRING_ACTIVE);
+ if (err == -ECONNRESET)
+ return err;
+ ack_start = -1;
+ }
+ }
+ if (unlikely(ack_start == -1))
+ ack_start = ack_end = prev_idx(start, dr);
+ return vnet_send_ack(port, dr, ack_start, ack_end, VIO_DRING_STOPPED);
+}
+
+static int vnet_rx(struct vnet_port *port, void *msgbuf)
+{
+ struct vio_dring_data *pkt = msgbuf;
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING];
+ struct vio_driver_state *vio = &port->vio;
+
+ viodbg(DATA, "vnet_rx stype_env[%04x] seq[%016lx] rcv_nxt[%016lx]\n",
+ pkt->tag.stype_env, pkt->seq, dr->rcv_nxt);
+
+ if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
+ return 0;
+ if (unlikely(pkt->seq != dr->rcv_nxt)) {
+ printk(KERN_ERR PFX "RX out of sequence seq[0x%lx] "
+ "rcv_nxt[0x%lx]\n", pkt->seq, dr->rcv_nxt);
+ return 0;
+ }
+
+ dr->rcv_nxt++;
+
+ /* XXX Validate pkt->start_idx and pkt->end_idx XXX */
+
+ return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx);
+}
+
+static int idx_is_pending(struct vio_dring_state *dr, u32 end)
+{
+ u32 idx = dr->cons;
+ int found = 0;
+
+ while (idx != dr->prod) {
+ if (idx == end) {
+ found = 1;
+ break;
+ }
+ idx = next_idx(idx, dr);
+ }
+ return found;
+}
+
+static int vnet_ack(struct vnet_port *port, void *msgbuf)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct vio_dring_data *pkt = msgbuf;
+ struct net_device *dev;
+ struct vnet *vp;
+ u32 end;
+
+ if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA))
+ return 0;
+
+ end = pkt->end_idx;
+ if (unlikely(!idx_is_pending(dr, end)))
+ return 0;
+
+ dr->cons = next_idx(end, dr);
+
+ vp = port->vp;
+ dev = vp->dev;
+ if (unlikely(netif_queue_stopped(dev) &&
+ vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr)))
+ return 1;
+
+ return 0;
+}
+
+static int vnet_nack(struct vnet_port *port, void *msgbuf)
+{
+ /* XXX just reset or similar XXX */
+ return 0;
+}
+
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+ struct vio_net_mcast_info *pkt = msgbuf;
+
+ if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+ printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+ "[%02x:%02x:%04x:%08x]\n",
+ port->vp->dev->name,
+ pkt->tag.type,
+ pkt->tag.stype,
+ pkt->tag.stype_env,
+ pkt->tag.sid);
+
+ return 0;
+}
+
+static void maybe_tx_wakeup(struct vnet *vp)
+{
+ struct net_device *dev = vp->dev;
+
+ netif_tx_lock(dev);
+ if (likely(netif_queue_stopped(dev))) {
+ struct vnet_port *port;
+ int wake = 1;
+
+ list_for_each_entry(port, &vp->port_list, list) {
+ struct vio_dring_state *dr;
+
+ dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ if (vnet_tx_dring_avail(dr) <
+ VNET_TX_WAKEUP_THRESH(dr)) {
+ wake = 0;
+ break;
+ }
+ }
+ if (wake)
+ netif_wake_queue(dev);
+ }
+ netif_tx_unlock(dev);
+}
+
+static void vnet_event(void *arg, int event)
+{
+ struct vnet_port *port = arg;
+ struct vio_driver_state *vio = &port->vio;
+ unsigned long flags;
+ int tx_wakeup, err;
+
+ spin_lock_irqsave(&vio->lock, flags);
+
+ if (unlikely(event == LDC_EVENT_RESET ||
+ event == LDC_EVENT_UP)) {
+ vio_link_state_change(vio, event);
+ spin_unlock_irqrestore(&vio->lock, flags);
+
+ if (event == LDC_EVENT_RESET)
+ vio_port_up(vio);
+ return;
+ }
+
+ if (unlikely(event != LDC_EVENT_DATA_READY)) {
+ printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+ spin_unlock_irqrestore(&vio->lock, flags);
+ return;
+ }
+
+ tx_wakeup = err = 0;
+ while (1) {
+ union {
+ struct vio_msg_tag tag;
+ u64 raw[8];
+ } msgbuf;
+
+ err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf));
+ if (unlikely(err < 0)) {
+ if (err == -ECONNRESET)
+ vio_conn_reset(vio);
+ break;
+ }
+ if (err == 0)
+ break;
+ viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n",
+ msgbuf.tag.type,
+ msgbuf.tag.stype,
+ msgbuf.tag.stype_env,
+ msgbuf.tag.sid);
+ err = vio_validate_sid(vio, &msgbuf.tag);
+ if (err < 0)
+ break;
+
+ if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) {
+ if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) {
+ err = vnet_rx(port, &msgbuf);
+ } else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) {
+ err = vnet_ack(port, &msgbuf);
+ if (err > 0)
+ tx_wakeup |= err;
+ } else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK) {
+ err = vnet_nack(port, &msgbuf);
+ }
+ } else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
+ if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+ err = handle_mcast(port, &msgbuf);
+ else
+ err = vio_control_pkt_engine(vio, &msgbuf);
+ if (err)
+ break;
+ } else {
+ err = vnet_handle_unknown(port, &msgbuf);
+ }
+ if (err == -ECONNRESET)
+ break;
+ }
+ spin_unlock(&vio->lock);
+ if (unlikely(tx_wakeup && err != -ECONNRESET))
+ maybe_tx_wakeup(port->vp);
+ local_irq_restore(flags);
+}
+
+static int __vnet_tx_trigger(struct vnet_port *port)
+{
+ struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ struct vio_dring_data hdr = {
+ .tag = {
+ .type = VIO_TYPE_DATA,
+ .stype = VIO_SUBTYPE_INFO,
+ .stype_env = VIO_DRING_DATA,
+ .sid = vio_send_sid(&port->vio),
+ },
+ .dring_ident = dr->ident,
+ .start_idx = dr->prod,
+ .end_idx = (u32) -1,
+ };
+ int err, delay;
+
+ hdr.seq = dr->snd_nxt;
+ delay = 1;
+ do {
+ err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr));
+ if (err > 0) {
+ dr->snd_nxt++;
+ break;
+ }
+ udelay(delay);
+ if ((delay <<= 1) > 128)
+ delay = 128;
+ } while (err == -EAGAIN);
+
+ return err;
+}
+
+struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb)
+{
+ unsigned int hash = vnet_hashfn(skb->data);
+ struct hlist_head *hp = &vp->port_hash[hash];
+ struct hlist_node *n;
+ struct vnet_port *port;
+
+ hlist_for_each_entry(port, n, hp, hash) {
+ if (!compare_ether_addr(port->raddr, skb->data))
+ return port;
+ }
+ port = NULL;
+ if (!list_empty(&vp->port_list))
+ port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+ return port;
+}
+
+struct vnet_port *tx_port_find(struct vnet *vp, struct sk_buff *skb)
+{
+ struct vnet_port *ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp->lock, flags);
+ ret = __tx_port_find(vp, skb);
+ spin_unlock_irqrestore(&vp->lock, flags);
+
+ return ret;
+}
+
+static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct vnet *vp = netdev_priv(dev);
+ struct vnet_port *port = tx_port_find(vp, skb);
+ struct vio_dring_state *dr;
+ struct vio_net_desc *d;
+ unsigned long flags;
+ unsigned int len;
+ void *tx_buf;
+ int i, err;
+
+ if (unlikely(!port))
+ goto out_dropped;
+
+ spin_lock_irqsave(&port->vio.lock, flags);
+
+ dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ if (unlikely(vnet_tx_dring_avail(dr) < 2)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+
+ /* This is a hard error, log it. */
+ printk(KERN_ERR PFX "%s: BUG! Tx Ring full when "
+ "queue awake!\n", dev->name);
+ dev->stats.tx_errors++;
+ }
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+ d = vio_dring_cur(dr);
+
+ tx_buf = port->tx_bufs[dr->prod].buf;
+ skb_copy_from_linear_data(skb, tx_buf + VNET_PACKET_SKIP, skb->len);
+
+ len = skb->len;
+ if (len < ETH_ZLEN) {
+ len = ETH_ZLEN;
+ memset(tx_buf+VNET_PACKET_SKIP+skb->len, 0, len - skb->len);
+ }
+
+ d->hdr.ack = VIO_ACK_ENABLE;
+ d->size = len;
+ d->ncookies = port->tx_bufs[dr->prod].ncookies;
+ for (i = 0; i < d->ncookies; i++)
+ d->cookies[i] = port->tx_bufs[dr->prod].cookies[i];
+
+ /* This has to be a non-SMP write barrier because we are writing
+ * to memory which is shared with the peer LDOM.
+ */
+ wmb();
+
+ d->hdr.state = VIO_DESC_READY;
+
+ err = __vnet_tx_trigger(port);
+ if (unlikely(err < 0)) {
+ printk(KERN_INFO PFX "%s: TX trigger error %d\n",
+ dev->name, err);
+ d->hdr.state = VIO_DESC_FREE;
+ dev->stats.tx_carrier_errors++;
+ goto out_dropped_unlock;
+ }
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += skb->len;
+
+ dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1);
+ if (unlikely(vnet_tx_dring_avail(dr) < 2)) {
+ netif_stop_queue(dev);
+ if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr))
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+
+ dev_kfree_skb(skb);
+
+ dev->trans_start = jiffies;
+ return NETDEV_TX_OK;
+
+out_dropped_unlock:
+ spin_unlock_irqrestore(&port->vio.lock, flags);
+
+out_dropped:
+ dev_kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+}
+
+static void vnet_tx_timeout(struct net_device *dev)
+{
+ /* XXX Implement me XXX */
+}
+
+static int vnet_open(struct net_device *dev)
+{
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int vnet_close(struct net_device *dev)
+{
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+
+ return 0;
+}
+
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+ struct vnet_mcast_entry *m;
+
+ for (m = vp->mcast_list; m; m = m->next) {
+ if (!memcmp(m->addr, addr, ETH_ALEN))
+ return m;
+ }
+ return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+ struct dev_addr_list *p;
+
+ for (p = dev->mc_list; p; p = p->next) {
+ struct vnet_mcast_entry *m;
+
+ m = __vnet_mc_find(vp, p->dmi_addr);
+ if (m) {
+ m->hit = 1;
+ continue;
+ }
+
+ if (!m) {
+ m = kzalloc(sizeof(*m), GFP_ATOMIC);
+ if (!m)
+ continue;
+ memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+ m->hit = 1;
+
+ m->next = vp->mcast_list;
+ vp->mcast_list = m;
+ }
+ }
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+ struct vio_net_mcast_info info;
+ struct vnet_mcast_entry *m, **pp;
+ int n_addrs;
+
+ memset(&info, 0, sizeof(info));
+
+ info.tag.type = VIO_TYPE_CTRL;
+ info.tag.stype = VIO_SUBTYPE_INFO;
+ info.tag.stype_env = VNET_MCAST_INFO;
+ info.tag.sid = vio_send_sid(&port->vio);
+ info.set = 1;
+
+ n_addrs = 0;
+ for (m = vp->mcast_list; m; m = m->next) {
+ if (m->sent)
+ continue;
+ m->sent = 1;
+ memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+ m->addr, ETH_ALEN);
+ if (++n_addrs == VNET_NUM_MCAST) {
+ info.count = n_addrs;
+
+ (void) vio_ldc_send(&port->vio, &info,
+ sizeof(info));
+ n_addrs = 0;
+ }
+ }
+ if (n_addrs) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+ }
+
+ info.set = 0;
+
+ n_addrs = 0;
+ pp = &vp->mcast_list;
+ while ((m = *pp) != NULL) {
+ if (m->hit) {
+ m->hit = 0;
+ pp = &m->next;
+ continue;
+ }
+
+ memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+ m->addr, ETH_ALEN);
+ if (++n_addrs == VNET_NUM_MCAST) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info,
+ sizeof(info));
+ n_addrs = 0;
+ }
+
+ *pp = m->next;
+ kfree(m);
+ }
+ if (n_addrs) {
+ info.count = n_addrs;
+ (void) vio_ldc_send(&port->vio, &info, sizeof(info));
+ }
+}
+
+static void vnet_set_rx_mode(struct net_device *dev)
+{
+ struct vnet *vp = netdev_priv(dev);
+ struct vnet_port *port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp->lock, flags);
+ if (!list_empty(&vp->port_list)) {
+ port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+ if (port->switch_port) {
+ __update_mc_list(vp, dev);
+ __send_mc_list(vp, port);
+ }
+ }
+ spin_unlock_irqrestore(&vp->lock, flags);
+}
+
+static int vnet_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu != ETH_DATA_LEN)
+ return -EINVAL;
+
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static int vnet_set_mac_addr(struct net_device *dev, void *p)
+{
+ return -EINVAL;
+}
+
+static void vnet_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_MODULE_NAME);
+ strcpy(info->version, DRV_MODULE_VERSION);
+}
+
+static u32 vnet_get_msglevel(struct net_device *dev)
+{
+ struct vnet *vp = netdev_priv(dev);
+ return vp->msg_enable;
+}
+
+static void vnet_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct vnet *vp = netdev_priv(dev);
+ vp->msg_enable = value;
+}
+
+static const struct ethtool_ops vnet_ethtool_ops = {
+ .get_drvinfo = vnet_get_drvinfo,
+ .get_msglevel = vnet_get_msglevel,
+ .set_msglevel = vnet_set_msglevel,
+ .get_link = ethtool_op_get_link,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+};
+
+static void vnet_port_free_tx_bufs(struct vnet_port *port)
+{
+ struct vio_dring_state *dr;
+ int i;
+
+ dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+ if (dr->base) {
+ ldc_free_exp_dring(port->vio.lp, dr->base,
+ (dr->entry_size * dr->num_entries),
+ dr->cookies, dr->ncookies);
+ dr->base = NULL;
+ dr->entry_size = 0;
+ dr->num_entries = 0;
+ dr->pending = 0;
+ dr->ncookies = 0;
+ }
+
+ for (i = 0; i < VNET_TX_RING_SIZE; i++) {
+ void *buf = port->tx_bufs[i].buf;
+
+ if (!buf)
+ continue;
+
+ ldc_unmap(port->vio.lp,
+ port->tx_bufs[i].cookies,
+ port->tx_bufs[i].ncookies);
+
+ kfree(buf);
+ port->tx_bufs[i].buf = NULL;
+ }
+}
+
+static int __devinit vnet_port_alloc_tx_bufs(struct vnet_port *port)
+{
+ struct vio_dring_state *dr;
+ unsigned long len;
+ int i, err, ncookies;
+ void *dring;
+
+ for (i = 0; i < VNET_TX_RING_SIZE; i++) {
+ void *buf = kzalloc(ETH_FRAME_LEN + 8, GFP_KERNEL);
+ int map_len = (ETH_FRAME_LEN + 7) & ~7;
+
+ err = -ENOMEM;
+ if (!buf) {
+ printk(KERN_ERR "TX buffer allocation failure\n");
+ goto err_out;
+ }
+ err = -EFAULT;
+ if ((unsigned long)buf & (8UL - 1)) {
+ printk(KERN_ERR "TX buffer misaligned\n");
+ kfree(buf);
+ goto err_out;
+ }
+
+ err = ldc_map_single(port->vio.lp, buf, map_len,
+ port->tx_bufs[i].cookies, 2,
+ (LDC_MAP_SHADOW |
+ LDC_MAP_DIRECT |
+ LDC_MAP_RW));
+ if (err < 0) {
+ kfree(buf);
+ goto err_out;
+ }
+ port->tx_bufs[i].buf = buf;
+ port->tx_bufs[i].ncookies = err;
+ }
+
+ dr = &port->vio.drings[VIO_DRIVER_TX_RING];
+
+ len = (VNET_TX_RING_SIZE *
+ (sizeof(struct vio_net_desc) +
+ (sizeof(struct ldc_trans_cookie) * 2)));
+
+ ncookies = VIO_MAX_RING_COOKIES;
+ dring = ldc_alloc_exp_dring(port->vio.lp, len,
+ dr->cookies, &ncookies,
+ (LDC_MAP_SHADOW |
+ LDC_MAP_DIRECT |
+ LDC_MAP_RW));
+ if (IS_ERR(dring)) {
+ err = PTR_ERR(dring);
+ goto err_out;
+ }
+
+ dr->base = dring;
+ dr->entry_size = (sizeof(struct vio_net_desc) +
+ (sizeof(struct ldc_trans_cookie) * 2));
+ dr->num_entries = VNET_TX_RING_SIZE;
+ dr->prod = dr->cons = 0;
+ dr->pending = VNET_TX_RING_SIZE;
+ dr->ncookies = ncookies;
+
+ return 0;
+
+err_out:
+ vnet_port_free_tx_bufs(port);
+
+ return err;
+}
+
+static LIST_HEAD(vnet_list);
+static DEFINE_MUTEX(vnet_list_mutex);
+
+static struct vnet * __devinit vnet_new(const u64 *local_mac)
+{
+ struct net_device *dev;
+ struct vnet *vp;
+ int err, i;
+
+ dev = alloc_etherdev(sizeof(*vp));
+ if (!dev) {
+ printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
+
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+ vp = netdev_priv(dev);
+
+ spin_lock_init(&vp->lock);
+ vp->dev = dev;
+
+ INIT_LIST_HEAD(&vp->port_list);
+ for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
+ INIT_HLIST_HEAD(&vp->port_hash[i]);
+ INIT_LIST_HEAD(&vp->list);
+ vp->local_mac = *local_mac;
+
+ dev->open = vnet_open;
+ dev->stop = vnet_close;
+ dev->set_multicast_list = vnet_set_rx_mode;
+ dev->set_mac_address = vnet_set_mac_addr;
+ dev->tx_timeout = vnet_tx_timeout;
+ dev->ethtool_ops = &vnet_ethtool_ops;
+ dev->watchdog_timeo = VNET_TX_TIMEOUT;
+ dev->change_mtu = vnet_change_mtu;
+ dev->hard_start_xmit = vnet_start_xmit;
+
+ err = register_netdev(dev);
+ if (err) {
+ printk(KERN_ERR PFX "Cannot register net device, "
+ "aborting.\n");
+ goto err_out_free_dev;
+ }
+
+ printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
+
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+ list_add(&vp->list, &vnet_list);
+
+ return vp;
+
+err_out_free_dev:
+ free_netdev(dev);
+
+ return ERR_PTR(err);
+}
+
+static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
+{
+ struct vnet *iter, *vp;
+
+ mutex_lock(&vnet_list_mutex);
+ vp = NULL;
+ list_for_each_entry(iter, &vnet_list, list) {
+ if (iter->local_mac == *local_mac) {
+ vp = iter;
+ break;
+ }
+ }
+ if (!vp)
+ vp = vnet_new(local_mac);
+ mutex_unlock(&vnet_list_mutex);
+
+ return vp;
+}
+
+static const char *local_mac_prop = "local-mac-address";
+
+static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
+ u64 port_node)
+{
+ const u64 *local_mac = NULL;
+ u64 a;
+
+ mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
+ u64 target = mdesc_arc_target(hp, a);
+ const char *name;
+
+ name = mdesc_get_property(hp, target, "name", NULL);
+ if (!name || strcmp(name, "network"))
+ continue;
+
+ local_mac = mdesc_get_property(hp, target,
+ local_mac_prop, NULL);
+ if (local_mac)
+ break;
+ }
+ if (!local_mac)
+ return ERR_PTR(-ENODEV);
+
+ return vnet_find_or_create(local_mac);
+}
+
+static struct ldc_channel_config vnet_ldc_cfg = {
+ .event = vnet_event,
+ .mtu = 64,
+ .mode = LDC_MODE_UNRELIABLE,
+};
+
+static struct vio_driver_ops vnet_vio_ops = {
+ .send_attr = vnet_send_attr,
+ .handle_attr = vnet_handle_attr,
+ .handshake_complete = vnet_handshake_complete,
+};
+
+static void print_version(void)
+{
+ static int version_printed;
+
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+}
+
+const char *remote_macaddr_prop = "remote-mac-address";
+
+static int __devinit vnet_port_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ struct mdesc_handle *hp;
+ struct vnet_port *port;
+ unsigned long flags;
+ struct vnet *vp;
+ const u64 *rmac;
+ int len, i, err, switch_port;
+
+ print_version();
+
+ hp = mdesc_grab();
+
+ vp = vnet_find_parent(hp, vdev->mp);
+ if (IS_ERR(vp)) {
+ printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+ err = PTR_ERR(vp);
+ goto err_out_put_mdesc;
+ }
+
+ rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
+ err = -ENODEV;
+ if (!rmac) {
+ printk(KERN_ERR PFX "Port lacks %s property.\n",
+ remote_macaddr_prop);
+ goto err_out_put_mdesc;
+ }
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!port) {
+ printk(KERN_ERR PFX "Cannot allocate vnet_port.\n");
+ goto err_out_put_mdesc;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff;
+
+ port->vp = vp;
+
+ err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK,
+ vnet_versions, ARRAY_SIZE(vnet_versions),
+ &vnet_vio_ops, vp->dev->name);
+ if (err)
+ goto err_out_free_port;
+
+ err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port);
+ if (err)
+ goto err_out_free_port;
+
+ err = vnet_port_alloc_tx_bufs(port);
+ if (err)
+ goto err_out_free_ldc;
+
+ INIT_HLIST_NODE(&port->hash);
+ INIT_LIST_HEAD(&port->list);
+
+ switch_port = 0;
+ if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
+ switch_port = 1;
+ port->switch_port = switch_port;
+
+ spin_lock_irqsave(&vp->lock, flags);
+ if (switch_port)
+ list_add(&port->list, &vp->port_list);
+ else
+ list_add_tail(&port->list, &vp->port_list);
+ hlist_add_head(&port->hash, &vp->port_hash[vnet_hashfn(port->raddr)]);
+ spin_unlock_irqrestore(&vp->lock, flags);
+
+ dev_set_drvdata(&vdev->dev, port);
+
+ printk(KERN_INFO "%s: PORT ( remote-mac ", vp->dev->name);
+ for (i = 0; i < 6; i++)
+ printk("%2.2x%c", port->raddr[i], i == 5 ? ' ' : ':');
+ if (switch_port)
+ printk("switch-port ");
+ printk(")\n");
+
+ vio_port_up(&port->vio);
+
+ mdesc_release(hp);
+
+ return 0;
+
+err_out_free_ldc:
+ vio_ldc_free(&port->vio);
+
+err_out_free_port:
+ kfree(port);
+
+err_out_put_mdesc:
+ mdesc_release(hp);
+ return err;
+}
+
+static int vnet_port_remove(struct vio_dev *vdev)
+{
+ struct vnet_port *port = dev_get_drvdata(&vdev->dev);
+
+ if (port) {
+ struct vnet *vp = port->vp;
+ unsigned long flags;
+
+ del_timer_sync(&port->vio.timer);
+
+ spin_lock_irqsave(&vp->lock, flags);
+ list_del(&port->list);
+ hlist_del(&port->hash);
+ spin_unlock_irqrestore(&vp->lock, flags);
+
+ vnet_port_free_tx_bufs(port);
+ vio_ldc_free(&port->vio);
+
+ dev_set_drvdata(&vdev->dev, NULL);
+
+ kfree(port);
+ }
+ return 0;
+}
+
+static struct vio_device_id vnet_port_match[] = {
+ {
+ .type = "vnet-port",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(vio, vnet_port_match);
+
+static struct vio_driver vnet_port_driver = {
+ .id_table = vnet_port_match,
+ .probe = vnet_port_probe,
+ .remove = vnet_port_remove,
+ .driver = {
+ .name = "vnet_port",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init vnet_init(void)
+{
+ return vio_register_driver(&vnet_port_driver);
+}
+
+static void __exit vnet_exit(void)
+{
+ vio_unregister_driver(&vnet_port_driver);
+}
+
+module_init(vnet_init);
+module_exit(vnet_exit);
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
new file mode 100644
index 000000000000..d347a5bf24b0
--- /dev/null
+++ b/drivers/net/sunvnet.h
@@ -0,0 +1,83 @@
+#ifndef _SUNVNET_H
+#define _SUNVNET_H
+
+#define DESC_NCOOKIES(entry_size) \
+ ((entry_size) - sizeof(struct vio_net_desc))
+
+/* length of time before we decide the hardware is borked,
+ * and dev->tx_timeout() should be called to fix the problem
+ */
+#define VNET_TX_TIMEOUT (5 * HZ)
+
+#define VNET_TX_RING_SIZE 512
+#define VNET_TX_WAKEUP_THRESH(dr) ((dr)->pending / 4)
+
+/* VNET packets are sent in buffers with the first 6 bytes skipped
+ * so that after the ethernet header the IPv4/IPv6 headers are aligned
+ * properly.
+ */
+#define VNET_PACKET_SKIP 6
+
+struct vnet_tx_entry {
+ void *buf;
+ unsigned int ncookies;
+ struct ldc_trans_cookie cookies[2];
+};
+
+struct vnet;
+struct vnet_port {
+ struct vio_driver_state vio;
+
+ struct hlist_node hash;
+ u8 raddr[ETH_ALEN];
+ u8 switch_port;
+ u8 __pad;
+
+ struct vnet *vp;
+
+ struct vnet_tx_entry tx_bufs[VNET_TX_RING_SIZE];
+
+ struct list_head list;
+};
+
+static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio)
+{
+ return container_of(vio, struct vnet_port, vio);
+}
+
+#define VNET_PORT_HASH_SIZE 16
+#define VNET_PORT_HASH_MASK (VNET_PORT_HASH_SIZE - 1)
+
+static inline unsigned int vnet_hashfn(u8 *mac)
+{
+ unsigned int val = mac[4] ^ mac[5];
+
+ return val & (VNET_PORT_HASH_MASK);
+}
+
+struct vnet_mcast_entry {
+ u8 addr[ETH_ALEN];
+ u8 sent;
+ u8 hit;
+ struct vnet_mcast_entry *next;
+};
+
+struct vnet {
+ /* Protects port_list and port_hash. */
+ spinlock_t lock;
+
+ struct net_device *dev;
+
+ u32 msg_enable;
+
+ struct list_head port_list;
+
+ struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
+
+ struct vnet_mcast_entry *mcast_list;
+
+ struct list_head list;
+ u64 local_mac;
+};
+
+#endif /* _SUNVNET_H */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 75655add3f34..7f94ca930988 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -626,7 +626,7 @@ static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
return -ENODEV;
}
#else
-static int __devinit tc35815_read_plat_dev_addr(struct device *dev)
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
{
return -ENODEV;
}
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 2f3184184ad9..887b9a5cfe48 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.77"
-#define DRV_MODULE_RELDATE "May 31, 2007"
+#define DRV_MODULE_VERSION "3.79"
+#define DRV_MODULE_RELDATE "July 18, 2007"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -721,6 +721,44 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
return ret;
}
+static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
+{
+ u32 phy;
+
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+ (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
+ return;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 ephy;
+
+ if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &ephy)) {
+ tg3_writephy(tp, MII_TG3_EPHY_TEST,
+ ephy | MII_TG3_EPHY_SHADOW_EN);
+ if (!tg3_readphy(tp, MII_TG3_EPHYTST_MISCCTRL, &phy)) {
+ if (enable)
+ phy |= MII_TG3_EPHYTST_MISCCTRL_MDIX;
+ else
+ phy &= ~MII_TG3_EPHYTST_MISCCTRL_MDIX;
+ tg3_writephy(tp, MII_TG3_EPHYTST_MISCCTRL, phy);
+ }
+ tg3_writephy(tp, MII_TG3_EPHY_TEST, ephy);
+ }
+ } else {
+ phy = MII_TG3_AUXCTL_MISC_RDSEL_MISC |
+ MII_TG3_AUXCTL_SHDWSEL_MISC;
+ if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, phy) &&
+ !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy)) {
+ if (enable)
+ phy |= MII_TG3_AUXCTL_MISC_FORCE_AMDIX;
+ else
+ phy &= ~MII_TG3_AUXCTL_MISC_FORCE_AMDIX;
+ phy |= MII_TG3_AUXCTL_MISC_WREN;
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
+ }
+ }
+}
+
static void tg3_phy_set_wirespeed(struct tg3 *tp)
{
u32 val;
@@ -1045,23 +1083,11 @@ out:
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- u32 phy_reg;
-
/* adjust output voltage */
tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x12);
-
- if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phy_reg)) {
- u32 phy_reg2;
-
- tg3_writephy(tp, MII_TG3_EPHY_TEST,
- phy_reg | MII_TG3_EPHY_SHADOW_EN);
- /* Enable auto-MDIX */
- if (!tg3_readphy(tp, 0x10, &phy_reg2))
- tg3_writephy(tp, 0x10, phy_reg2 | 0x4000);
- tg3_writephy(tp, MII_TG3_EPHY_TEST, phy_reg);
- }
}
+ tg3_phy_toggle_automdix(tp, 1);
tg3_phy_set_wirespeed(tp);
return 0;
}
@@ -1162,6 +1188,19 @@ static void tg3_frob_aux_power(struct tg3 *tp)
}
}
+static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed)
+{
+ if (tp->led_ctrl == LED_CTRL_MODE_PHY_2)
+ return 1;
+ else if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411) {
+ if (speed != SPEED_10)
+ return 1;
+ } else if (speed == SPEED_10)
+ return 1;
+
+ return 0;
+}
+
static int tg3_setup_phy(struct tg3 *, int);
#define RESET_KIND_SHUTDOWN 0
@@ -1320,9 +1359,17 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
else
mac_mode = MAC_MODE_PORT_MODE_MII;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
- !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
- mac_mode |= MAC_MODE_LINK_POLARITY;
+ mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
+ ASIC_REV_5700) {
+ u32 speed = (tp->tg3_flags &
+ TG3_FLAG_WOL_SPEED_100MB) ?
+ SPEED_100 : SPEED_10;
+ if (tg3_5700_link_polarity(tp, speed))
+ mac_mode |= MAC_MODE_LINK_POLARITY;
+ else
+ mac_mode &= ~MAC_MODE_LINK_POLARITY;
+ }
} else {
mac_mode = MAC_MODE_PORT_MODE_TBI;
}
@@ -1990,15 +2037,12 @@ relink:
if (tp->link_config.active_duplex == DUPLEX_HALF)
tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
- tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
- if ((tp->led_ctrl == LED_CTRL_MODE_PHY_2) ||
- (current_link_up == 1 &&
- tp->link_config.active_speed == SPEED_10))
- tp->mac_mode |= MAC_MODE_LINK_POLARITY;
- } else {
- if (current_link_up == 1)
+ if (current_link_up == 1 &&
+ tg3_5700_link_polarity(tp, tp->link_config.active_speed))
tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+ else
+ tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
}
/* ??? Without this setting Netgear GA302T PHY does not
@@ -2639,6 +2683,9 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
tw32_f(MAC_MODE, (tp->mac_mode | MAC_MODE_SEND_CONFIGS));
udelay(40);
+
+ tw32_f(MAC_MODE, tp->mac_mode);
+ udelay(40);
}
out:
@@ -2698,10 +2745,6 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
else
current_link_up = tg3_setup_fiber_by_hand(tp, mac_status);
- tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
- tw32_f(MAC_MODE, tp->mac_mode);
- udelay(40);
-
tp->hw_status->status =
(SD_STATUS_UPDATED |
(tp->hw_status->status & ~SD_STATUS_LINK_CHG));
@@ -3512,9 +3555,9 @@ static inline int tg3_irq_sync(struct tg3 *tp)
*/
static inline void tg3_full_lock(struct tg3 *tp, int irq_sync)
{
+ spin_lock_bh(&tp->lock);
if (irq_sync)
tg3_irq_quiesce(tp);
- spin_lock_bh(&tp->lock);
}
static inline void tg3_full_unlock(struct tg3 *tp)
@@ -4804,6 +4847,59 @@ static int tg3_poll_fw(struct tg3 *tp)
return 0;
}
+/* Save PCI command register before chip reset */
+static void tg3_save_pci_state(struct tg3 *tp)
+{
+ u32 val;
+
+ pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
+ tp->pci_cmd = val;
+}
+
+/* Restore PCI state after chip reset */
+static void tg3_restore_pci_state(struct tg3 *tp)
+{
+ u32 val;
+
+ /* Re-enable indirect register accesses. */
+ pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+ tp->misc_host_ctrl);
+
+ /* Set MAX PCI retry to zero. */
+ val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+ (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+ val |= PCISTATE_RETRY_SAME_DMA;
+ pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
+
+ pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+
+ /* Make sure PCI-X relaxed ordering bit is clear. */
+ pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
+ val &= ~PCIX_CAPS_RELAXED_ORDERING;
+ pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
+
+ if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
+ u32 val;
+
+ /* Chip reset on 5780 will reset MSI enable bit,
+ * so need to restore it.
+ */
+ if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+ u16 ctrl;
+
+ pci_read_config_word(tp->pdev,
+ tp->msi_cap + PCI_MSI_FLAGS,
+ &ctrl);
+ pci_write_config_word(tp->pdev,
+ tp->msi_cap + PCI_MSI_FLAGS,
+ ctrl | PCI_MSI_FLAGS_ENABLE);
+ val = tr32(MSGINT_MODE);
+ tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
+ }
+ }
+}
+
static void tg3_stop_fw(struct tg3 *);
/* tp->lock is held. */
@@ -4820,6 +4916,12 @@ static int tg3_chip_reset(struct tg3 *tp)
*/
tp->nvram_lock_cnt = 0;
+ /* GRC_MISC_CFG core clock reset will clear the memory
+ * enable bit in PCI register 4 and the MSI enable bit
+ * on some chips, so we save relevant registers here.
+ */
+ tg3_save_pci_state(tp);
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
@@ -4918,50 +5020,14 @@ static int tg3_chip_reset(struct tg3 *tp)
pci_write_config_dword(tp->pdev, 0xd8, 0xf5000);
}
- /* Re-enable indirect register accesses. */
- pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
- tp->misc_host_ctrl);
-
- /* Set MAX PCI retry to zero. */
- val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
- if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
- (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
- val |= PCISTATE_RETRY_SAME_DMA;
- pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
-
- pci_restore_state(tp->pdev);
+ tg3_restore_pci_state(tp);
tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
- /* Make sure PCI-X relaxed ordering bit is clear. */
- pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
- val &= ~PCIX_CAPS_RELAXED_ORDERING;
- pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
-
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
- u32 val;
-
- /* Chip reset on 5780 will reset MSI enable bit,
- * so need to restore it.
- */
- if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
- u16 ctrl;
-
- pci_read_config_word(tp->pdev,
- tp->msi_cap + PCI_MSI_FLAGS,
- &ctrl);
- pci_write_config_word(tp->pdev,
- tp->msi_cap + PCI_MSI_FLAGS,
- ctrl | PCI_MSI_FLAGS_ENABLE);
- val = tr32(MSGINT_MODE);
- tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
- }
-
+ val = 0;
+ if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
val = tr32(MEMARB_MODE);
- tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
-
- } else
- tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+ tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
tg3_stop_fw(tp);
@@ -6444,6 +6510,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE |
MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE;
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
+ !(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+ tp->mac_mode |= MAC_MODE_LINK_POLARITY;
tw32_f(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR);
udelay(40);
@@ -8271,7 +8341,7 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
- ethtool_op_set_tx_hw_csum(dev, data);
+ ethtool_op_set_tx_ipv6_csum(dev, data);
else
ethtool_op_set_tx_csum(dev, data);
@@ -8805,7 +8875,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
return 0;
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
- MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY;
+ MAC_MODE_PORT_INT_LPBACK;
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ mac_mode |= MAC_MODE_LINK_POLARITY;
if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
mac_mode |= MAC_MODE_PORT_MODE_MII;
else
@@ -8824,19 +8896,18 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
phytest | MII_TG3_EPHY_SHADOW_EN);
if (!tg3_readphy(tp, 0x1b, &phy))
tg3_writephy(tp, 0x1b, phy & ~0x20);
- if (!tg3_readphy(tp, 0x10, &phy))
- tg3_writephy(tp, 0x10, phy & ~0x4000);
tg3_writephy(tp, MII_TG3_EPHY_TEST, phytest);
}
val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100;
} else
val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED1000;
+ tg3_phy_toggle_automdix(tp, 0);
+
tg3_writephy(tp, MII_BMCR, val);
udelay(40);
- mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
- MAC_MODE_LINK_POLARITY;
+ mac_mode = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x1800);
mac_mode |= MAC_MODE_PORT_MODE_MII;
@@ -8849,8 +8920,11 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
udelay(10);
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
- if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
- mac_mode &= ~MAC_MODE_LINK_POLARITY;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
+ if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)
+ mac_mode &= ~MAC_MODE_LINK_POLARITY;
+ else if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5411)
+ mac_mode |= MAC_MODE_LINK_POLARITY;
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_LNK3_LED_MODE);
}
@@ -9116,10 +9190,10 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
/* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
__tg3_set_rx_mode(dev);
- tg3_full_unlock(tp);
-
if (netif_running(dev))
tg3_netif_start(tp);
+
+ tg3_full_unlock(tp);
}
#endif
@@ -9410,11 +9484,13 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
case FLASH_5755VENDOR_ATMEL_FLASH_1:
case FLASH_5755VENDOR_ATMEL_FLASH_2:
case FLASH_5755VENDOR_ATMEL_FLASH_3:
+ case FLASH_5755VENDOR_ATMEL_FLASH_5:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
tp->tg3_flags2 |= TG3_FLG2_FLASH;
tp->nvram_pagesize = 264;
- if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1)
+ if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 ||
+ nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5)
tp->nvram_size = (protect ? 0x3e200 : 0x80000);
else if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_2)
tp->nvram_size = (protect ? 0x1f200 : 0x40000);
@@ -10498,11 +10574,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
continue;
}
if (pci_id->rev != PCI_ANY_ID) {
- u8 rev;
-
- pci_read_config_byte(bridge, PCI_REVISION_ID,
- &rev);
- if (rev > pci_id->rev)
+ if (bridge->revision > pci_id->rev)
continue;
}
if (bridge->subordinate &&
@@ -11929,7 +12001,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
*/
if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
- pci_save_state(tp->pdev);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
}
@@ -11944,12 +12015,11 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
* checksumming.
*/
if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
- dev->features |= NETIF_F_HW_CSUM;
- else
- dev->features |= NETIF_F_IP_CSUM;
- dev->features |= NETIF_F_SG;
+ dev->features |= NETIF_F_IPV6_CSUM;
+
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
} else
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
@@ -11959,12 +12029,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_coal(tp);
- /* Now that we have fully setup the chip, save away a snapshot
- * of the PCI config space. We need to restore this after
- * GRC_MISC_CFG core clock resets and some resume events.
- */
- pci_save_state(tp->pdev);
-
pci_set_drvdata(pdev, dev);
err = register_netdev(dev);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index bd9f4f428e5b..5c21f49026c9 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -1467,6 +1467,7 @@
#define FLASH_5755VENDOR_ATMEL_FLASH_2 0x03400002
#define FLASH_5755VENDOR_ATMEL_FLASH_3 0x03400000
#define FLASH_5755VENDOR_ATMEL_FLASH_4 0x00000003
+#define FLASH_5755VENDOR_ATMEL_FLASH_5 0x02000003
#define FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ 0x03c00003
#define FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ 0x03c00002
#define FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ 0x03000003
@@ -1642,6 +1643,11 @@
#define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */
+#define MII_TG3_AUXCTL_MISC_WREN 0x8000
+#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200
+#define MII_TG3_AUXCTL_MISC_RDSEL_MISC 0x7000
+#define MII_TG3_AUXCTL_SHDWSEL_MISC 0x0007
+
#define MII_TG3_AUX_STAT 0x19 /* auxilliary status register */
#define MII_TG3_AUX_STAT_LPASS 0x0004
#define MII_TG3_AUX_STAT_SPDMASK 0x0700
@@ -1667,6 +1673,9 @@
#define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */
#define MII_TG3_EPHY_SHADOW_EN 0x80
+#define MII_TG3_EPHYTST_MISCCTRL 0x10 /* 5906 EPHY misc ctrl shadow register */
+#define MII_TG3_EPHYTST_MISCCTRL_MDIX 0x4000
+
#define MII_TG3_TEST1 0x1e
#define MII_TG3_TEST1_TRIM_EN 0x0010
#define MII_TG3_TEST1_CRC_EN 0x8000
@@ -2336,6 +2345,7 @@ struct tg3 {
#define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */
u32 led_ctrl;
+ u32 pci_cmd;
char board_part_number[24];
char fw_ver[16];
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 106dc1ef0acb..74eb12107e68 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -533,7 +533,6 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
struct net_device *dev;
TLanPrivateInfo *priv;
- u8 pci_rev;
u16 device_id;
int reg, rc = -ENODEV;
@@ -577,8 +576,6 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
goto err_out_free_dev;
}
- pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev);
-
for ( reg= 0; reg <= 5; reg ++ ) {
if (pci_resource_flags(pdev, reg) & IORESOURCE_IO) {
pci_io_base = pci_resource_start(pdev, reg);
@@ -595,7 +592,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
dev->base_addr = pci_io_base;
dev->irq = pdev->irq;
- priv->adapterRev = pci_rev;
+ priv->adapterRev = pdev->revision;
pci_set_master(pdev);
pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 58d7e5d452fa..f83bb5cb0d3d 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3692,7 +3692,6 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
__u16 rcode, correlator;
int err = 0;
__u8 xframe = 1;
- __u16 tx_fstatus;
rmf->vl = SWAP_BYTES(rmf->vl);
if(rx_status & FCB_RX_STATUS_DA_MATCHED)
@@ -3783,7 +3782,9 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
}
break;
- case TX_FORWARD:
+ case TX_FORWARD: {
+ __u16 uninitialized_var(tx_fstatus);
+
if((rcode = smctr_rcv_tx_forward(dev, rmf))
!= POSITIVE_ACK)
{
@@ -3811,6 +3812,7 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size,
}
}
break;
+ }
/* Received MAC Frames Processed by CRS/REM/RPS. */
case RSP:
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 42fca26afc50..09902891a6e6 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -2134,7 +2134,7 @@ srom_search(struct net_device *dev, struct pci_dev *pdev)
u_short vendor, status;
u_int irq = 0, device;
u_long iobase = 0; /* Clear upper 32 bits in Alphas */
- int i, j, cfrv;
+ int i, j;
struct de4x5_private *lp = netdev_priv(dev);
struct list_head *walk;
@@ -2150,7 +2150,6 @@ srom_search(struct net_device *dev, struct pci_dev *pdev)
/* Get the chip configuration revision register */
pb = this_dev->bus->number;
- pci_read_config_dword(this_dev, PCI_REVISION_ID, &cfrv);
/* Set the device number information */
lp->device = PCI_SLOT(this_dev->devfn);
@@ -2158,7 +2157,8 @@ srom_search(struct net_device *dev, struct pci_dev *pdev)
/* Set the chipset information */
if (is_DC2114x) {
- device = ((cfrv & CFRV_RN) < DC2114x_BRK ? DC21142 : DC21143);
+ device = ((this_dev->revision & CFRV_RN) < DC2114x_BRK
+ ? DC21142 : DC21143);
}
lp->chipset = device;
@@ -2254,7 +2254,7 @@ static int __devinit de4x5_pci_probe (struct pci_dev *pdev,
}
/* Get the chip configuration revision register */
- pci_read_config_dword(pdev, PCI_REVISION_ID, &lp->cfrv);
+ lp->cfrv = pdev->revision;
/* Set the device number information */
lp->device = dev_num;
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 4ed67ff0e81e..dab74feb44bc 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -181,11 +181,12 @@
udelay(5);
#define __CHK_IO_SIZE(pci_id, dev_rev) \
- (( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x02000030) ) ? \
+ (( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x30) ) ? \
DM9102A_IO_SIZE: DM9102_IO_SIZE)
-#define CHK_IO_SIZE(pci_dev, dev_rev) \
- (__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, dev_rev))
+#define CHK_IO_SIZE(pci_dev) \
+ (__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, \
+ (pci_dev)->revision))
/* Sten Check */
#define DEVICE net_device
@@ -205,7 +206,7 @@ struct rx_desc {
struct dmfe_board_info {
u32 chip_id; /* Chip vendor/Device ID */
- u32 chip_revision; /* Chip revision */
+ u8 chip_revision; /* Chip revision */
struct DEVICE *next_dev; /* next device */
struct pci_dev *pdev; /* PCI device */
spinlock_t lock;
@@ -359,7 +360,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
{
struct dmfe_board_info *db; /* board information structure */
struct net_device *dev;
- u32 dev_rev, pci_pmr;
+ u32 pci_pmr;
int i, err;
DMFE_DBUG(0, "dmfe_init_one()", 0);
@@ -392,10 +393,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
goto err_out_disable;
}
- /* Read Chip revision */
- pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
-
- if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev, dev_rev)) ) {
+ if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev)) ) {
printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n");
err = -ENODEV;
goto err_out_disable;
@@ -433,7 +431,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
db->chip_id = ent->driver_data;
db->ioaddr = pci_resource_start(pdev, 0);
- db->chip_revision = dev_rev;
+ db->chip_revision = pdev->revision;
db->wol_mode = 0;
db->pdev = pdev;
@@ -455,7 +453,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
pci_read_config_dword(pdev, 0x50, &pci_pmr);
pci_pmr &= 0x70000;
- if ( (pci_pmr == 0x10000) && (dev_rev == 0x02000031) )
+ if ( (pci_pmr == 0x10000) && (db->chip_revision == 0x31) )
db->chip_type = 1; /* DM9102A E3 */
else
db->chip_type = 0;
@@ -553,7 +551,7 @@ static int dmfe_open(struct DEVICE *dev)
/* CR6 operation mode decision */
if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
- (db->chip_revision >= 0x02000030) ) {
+ (db->chip_revision >= 0x30) ) {
db->cr6_data |= DMFE_TXTH_256;
db->cr0_data = CR0_DEFAULT;
db->dm910x_chk_mode=4; /* Enter the normal mode */
@@ -1199,9 +1197,9 @@ static void dmfe_timer(unsigned long data)
tmp_cr12 = inb(db->ioaddr + DCR12); /* DM9102/DM9102A */
if ( ((db->chip_id == PCI_DM9102_ID) &&
- (db->chip_revision == 0x02000030)) ||
+ (db->chip_revision == 0x30)) ||
((db->chip_id == PCI_DM9132_ID) &&
- (db->chip_revision == 0x02000010)) ) {
+ (db->chip_revision == 0x10)) ) {
/* DM9102A Chip */
if (tmp_cr12 & 2)
link_ok = 0;
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index ea896777bcaf..53efd6694e75 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -197,8 +197,8 @@ int tulip_poll(struct net_device *dev, int *budget)
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__)
- eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data,
- pkt_len, 0);
+ skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data,
+ pkt_len);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
@@ -420,8 +420,8 @@ static int tulip_rx(struct net_device *dev)
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__)
- eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data,
- pkt_len, 0);
+ skb_copy_to_linear_data(skb, tp->rx_buffers[entry].skb->data,
+ pkt_len);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 041af63f2811..f87d76981ab7 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1155,7 +1155,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev,
/* set or disable MWI in the standard PCI command bit.
* Check for the case where mwi is desired but not available
*/
- if (csr0 & MWI) pci_set_mwi(pdev);
+ if (csr0 & MWI) pci_try_set_mwi(pdev);
else pci_clear_mwi(pdev);
/* read result from hardware (in case bit refused to enable) */
@@ -1238,7 +1238,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
};
static int last_irq;
static int multiport_cnt; /* For four-port boards w/one EEPROM */
- u8 chip_rev;
int i, irq;
unsigned short sum;
unsigned char *ee_data;
@@ -1274,10 +1273,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (pdev->vendor == 0x1282 && pdev->device == 0x9100)
{
- u32 dev_rev;
/* Read Chip revision */
- pci_read_config_dword(pdev, PCI_REVISION_ID, &dev_rev);
- if(dev_rev < 0x02000030)
+ if (pdev->revision < 0x30)
{
printk(KERN_ERR PFX "skipping early DM9100 with Crc bug (use dmfe)\n");
return -ENODEV;
@@ -1360,8 +1357,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (!ioaddr)
goto err_out_free_res;
- pci_read_config_byte (pdev, PCI_REVISION_ID, &chip_rev);
-
/*
* initialize private data structure 'tp'
* it is zeroed and aligned in alloc_etherdev
@@ -1382,7 +1377,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tp->flags = tulip_tbl[chip_idx].flags;
tp->pdev = pdev;
tp->base_addr = ioaddr;
- tp->revision = chip_rev;
+ tp->revision = pdev->revision;
tp->csr0 = csr0;
spin_lock_init(&tp->lock);
spin_lock_init(&tp->mii_lock);
@@ -1399,7 +1394,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tulip_mwi_config (pdev, dev);
#else
/* MWI is broken for DC21143 rev 65... */
- if (chip_idx == DC21143 && chip_rev == 65)
+ if (chip_idx == DC21143 && pdev->revision == 65)
tp->csr0 &= ~MWI;
#endif
@@ -1640,7 +1635,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
#else
"Port"
#endif
- " %#llx,", dev->name, chip_name, chip_rev,
+ " %#llx,", dev->name, chip_name, pdev->revision,
(unsigned long long) pci_resource_start(pdev, TULIP_BAR));
pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 38f3b99716b8..5824f6a35495 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1232,7 +1232,7 @@ static int netdev_rx(struct net_device *dev)
pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry],
np->rx_skbuff[entry]->len,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb, np->rx_skbuff[entry]->data, pkt_len);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry],
np->rx_skbuff[entry]->len,
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 2470b1ee33c0..16a54e6b8d4f 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -205,7 +205,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
{
struct net_device *dev = NULL;
struct xircom_private *private;
- unsigned char chip_rev;
unsigned long flags;
unsigned short tmp16;
enter("xircom_probe");
@@ -224,8 +223,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
pci_read_config_word (pdev,PCI_STATUS, &tmp16);
pci_write_config_word (pdev, PCI_STATUS,tmp16);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
-
if (!request_region(pci_resource_start(pdev, 0), 128, "xircom_cb")) {
printk(KERN_ERR "xircom_probe: failed to allocate io-region\n");
return -ENODEV;
@@ -286,7 +283,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
goto reg_fail;
}
- printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
+ printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, pdev->revision, pdev->irq);
/* start the transmitter to get a heartbeat */
/* TODO: send 2 dummy packets here */
transceiver_voodoo(private);
@@ -1208,7 +1205,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri
goto out;
}
skb_reserve(skb, 2);
- eth_copy_and_sum(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len, 0);
+ skb_copy_to_linear_data(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index f64172927377..fc439f333350 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -524,7 +524,6 @@ static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_devi
int chip_idx = id->driver_data;
long ioaddr;
int i;
- u8 chip_rev;
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
@@ -620,9 +619,8 @@ static int __devinit xircom_init_one(struct pci_dev *pdev, const struct pci_devi
if (register_netdev(dev))
goto err_out_cleardev;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &chip_rev);
printk(KERN_INFO "%s: %s rev %d at %#3lx,",
- dev->name, xircom_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+ dev->name, xircom_tbl[chip_idx].chip_name, pdev->revision, ioaddr);
for (i = 0; i < 6; i++)
printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
printk(", IRQ %d.\n", dev->irq);
@@ -1242,8 +1240,8 @@ xircom_rx(struct net_device *dev)
&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
skb_reserve(skb, 2); /* 16 byte align the IP header */
#if ! defined(__alpha__)
- eth_copy_and_sum(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
- pkt_len, 0);
+ skb_copy_to_linear_data(skb, bus_to_virt(tp->rx_ring[entry].buffer1),
+ pkt_len);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a2c6caaaae93..62b2b3005019 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -432,6 +432,7 @@ static void tun_setup(struct net_device *dev)
init_waitqueue_head(&tun->read_wait);
tun->owner = -1;
+ tun->group = -1;
SET_MODULE_OWNER(dev);
dev->open = tun_net_open;
@@ -467,8 +468,11 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
return -EBUSY;
/* Check permissions */
- if (tun->owner != -1 &&
- current->euid != tun->owner && !capable(CAP_NET_ADMIN))
+ if (((tun->owner != -1 &&
+ current->euid != tun->owner) ||
+ (tun->group != -1 &&
+ current->egid != tun->group)) &&
+ !capable(CAP_NET_ADMIN))
return -EPERM;
}
else if (__dev_get_by_name(ifr->ifr_name))
@@ -610,6 +614,13 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file,
DBG(KERN_INFO "%s: owner set to %d\n", tun->dev->name, tun->owner);
break;
+ case TUNSETGROUP:
+ /* Set group of the device */
+ tun->group= (gid_t) arg;
+
+ DBG(KERN_INFO "%s: group set to %d\n", tun->dev->name, tun->group);
+ break;
+
case TUNSETLINK:
/* Only allow setting the type when the interface is down */
if (tun->dev->flags & IFF_UP) {
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 15b2fb8aa492..03587205546e 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1703,7 +1703,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
pci_dma_sync_single_for_cpu(tp->pdev, dma_addr,
PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(new_skb, skb->data, pkt_len, 0);
+ skb_copy_to_linear_data(new_skb, skb->data, pkt_len);
pci_dma_sync_single_for_device(tp->pdev, dma_addr,
PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
@@ -2267,12 +2267,6 @@ need_resume:
typhoon_resume(pdev);
return -EBUSY;
}
-
-static int
-typhoon_enable_wake(struct pci_dev *pdev, pci_power_t state, int enable)
-{
- return pci_enable_wake(pdev, state, enable);
-}
#endif
static int __devinit
@@ -2636,7 +2630,6 @@ static struct pci_driver typhoon_driver = {
#ifdef CONFIG_PM
.suspend = typhoon_suspend,
.resume = typhoon_resume,
- .enable_wake = typhoon_enable_wake,
#endif
};
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 86e90c59d551..76752d84a30f 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -255,7 +255,7 @@ static void catc_rx_done(struct urb *urb)
if (!(skb = dev_alloc_skb(pkt_len)))
return;
- eth_copy_and_sum(skb, pkt_start + pkt_offset, pkt_len, 0);
+ skb_copy_to_linear_data(skb, pkt_start + pkt_offset, pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, catc->netdev);
diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c
index bc62b012602b..943988ed01d8 100644
--- a/drivers/net/usb/cdc_subset.c
+++ b/drivers/net/usb/cdc_subset.c
@@ -305,6 +305,9 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x8086, 0x07d3), // "blob" bootloader
.driver_info = (unsigned long) &blob_info,
}, {
+ USB_DEVICE (0x1286, 0x8001), // "blob" bootloader
+ .driver_info = (unsigned long) &blob_info,
+}, {
// Linux Ethernet/RNDIS gadget on pxa210/25x/26x, second config
// e.g. Gumstix, current OpenZaurus, ...
USB_DEVICE_VER (0x0525, 0xa4a2, 0x0203, 0x0203),
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 60d29440f316..524dc5f5e46d 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -635,7 +635,7 @@ static void kaweth_usb_receive(struct urb *urb)
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
+ skb_copy_to_linear_data(skb, kaweth->rx_buf + 2, pkt_len);
skb_put(skb, pkt_len);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index adea290a9d5e..f51c2c138f10 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -622,7 +622,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
struct net_device *dev;
struct rhine_private *rp;
int i, rc;
- u8 pci_rev;
u32 quirks;
long pioaddr;
long memaddr;
@@ -642,27 +641,25 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
printk(version);
#endif
- pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
-
io_size = 256;
phy_id = 0;
quirks = 0;
name = "Rhine";
- if (pci_rev < VTunknown0) {
+ if (pdev->revision < VTunknown0) {
quirks = rqRhineI;
io_size = 128;
}
- else if (pci_rev >= VT6102) {
+ else if (pdev->revision >= VT6102) {
quirks = rqWOL | rqForceReset;
- if (pci_rev < VT6105) {
+ if (pdev->revision < VT6105) {
name = "Rhine II";
quirks |= rqStatusWBRace; /* Rhine-II exclusive */
}
else {
phy_id = 1; /* Integrated PHY, phy_id fixed to 1 */
- if (pci_rev >= VT6105_B0)
+ if (pdev->revision >= VT6105_B0)
quirks |= rq6patterns;
- if (pci_rev < VT6105M)
+ if (pdev->revision < VT6105M)
name = "Rhine III";
else
name = "Rhine III (Management Adapter)";
@@ -1492,9 +1489,9 @@ static int rhine_rx(struct net_device *dev, int limit)
rp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb,
+ skb_copy_to_linear_data(skb,
rp->rx_skbuff[entry]->data,
- pkt_len, 0);
+ pkt_len);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(rp->pdev,
rp->rx_skbuff_dma[entry],
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index b670b97bcfde..f331843d1102 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -890,8 +890,7 @@ static void __devinit velocity_init_info(struct pci_dev *pdev,
static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
{
- if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
- return -EIO;
+ vptr->rev_id = pdev->revision;
pci_set_master(pdev);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 4fc8681bc110..a3df09ee729f 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -61,7 +61,7 @@ config COSA
#
config LANMEDIA
tristate "LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards"
- depends on PCI
+ depends on PCI && VIRT_TO_BUS
---help---
Driver for the following Lan Media family of serial boards:
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 6b63b350cd52..8ead774d14c8 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -315,12 +315,11 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
return -ENODEV;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "c101: unable to allocate memory\n");
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
card->dev = alloc_hdlcdev(card);
if (!card->dev) {
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 9ef49ce148b2..26058b4f8f36 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -572,13 +572,11 @@ static int cosa_probe(int base, int irq, int dma)
sprintf(cosa->name, "cosa%d", cosa->num);
/* Initialize the per-channel data */
- cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels,
- GFP_KERNEL);
+ cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL);
if (!cosa->chan) {
err = -ENOMEM;
goto err_out3;
}
- memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels);
for (i=0; i<cosa->nchannels; i++) {
cosa->chan[i].cosa = cosa;
cosa->chan[i].num = i;
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 6e5f1c898517..a0e8611ad8e8 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -113,12 +113,10 @@ static int __init cycx_init(void)
/* Verify number of cards and allocate adapter data space */
cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS);
cycx_ncards = max_t(int, cycx_ncards, 1);
- cycx_card_array = kmalloc(sizeof(struct cycx_device) * cycx_ncards,
- GFP_KERNEL);
+ cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL);
if (!cycx_card_array)
goto out;
- memset(cycx_card_array, 0, sizeof(struct cycx_device) * cycx_ncards);
/* Register adapters with WAN router */
for (cnt = 0; cnt < cycx_ncards; ++cnt) {
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index 016b3ff3ea5e..a8af28b273d3 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -376,11 +376,10 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
}
/* allocate and initialize private data */
- chan = kmalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
+ chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
if (!chan)
return -ENOMEM;
- memset(chan, 0, sizeof(*chan));
strcpy(chan->name, conf->name);
chan->card = card;
chan->link = conf->port;
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index dca024471455..50d2f9108dca 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -890,12 +890,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
struct dscc4_dev_priv *root;
int i, ret = -ENOMEM;
- root = kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
+ root = kcalloc(dev_per_card, sizeof(*root), GFP_KERNEL);
if (!root) {
printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME);
goto err_out;
}
- memset(root, 0, dev_per_card*sizeof(*root));
for (i = 0; i < dev_per_card; i++) {
root[i].dev = alloc_hdlcdev(root + i);
@@ -903,12 +902,11 @@ static int dscc4_found1(struct pci_dev *pdev, void __iomem *ioaddr)
goto err_free_dev;
}
- ppriv = kmalloc(sizeof(*ppriv), GFP_KERNEL);
+ ppriv = kzalloc(sizeof(*ppriv), GFP_KERNEL);
if (!ppriv) {
printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);
goto err_free_dev;
}
- memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
ppriv->root = root;
spin_lock_init(&ppriv->lock);
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 58a53b6d9b42..12dae8e24844 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2476,13 +2476,12 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Allocate driver private data */
- card = kmalloc(sizeof (struct fst_card_info), GFP_KERNEL);
+ card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
if (card == NULL) {
printk_err("FarSync card found but insufficient memory for"
" driver storage\n");
return -ENOMEM;
}
- memset(card, 0, sizeof (struct fst_card_info));
/* Try to enable the device */
if ((err = pci_enable_device(pdev)) != 0) {
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index 9ba3e4ee6ec7..bf5f8d9b5c83 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -231,11 +231,10 @@ static struct sv11_device *sv11_init(int iobase, int irq)
return NULL;
}
- sv = kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
+ sv = kzalloc(sizeof(struct sv11_device), GFP_KERNEL);
if(!sv)
goto fail3;
- memset(sv, 0, sizeof(*sv));
sv->if_ptr=&sv->netdev;
sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup);
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 5c322dfb79f6..cbdf0b748bde 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -351,12 +351,11 @@ static int __init n2_run(unsigned long io, unsigned long irq,
return -ENODEV;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "n2: unable to allocate memory\n");
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 999bf71937ca..99fee2f1d019 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -2833,6 +2833,8 @@ static int clock_rate_calc(uclong rate, uclong clock, int *br_io)
int br, tc;
int br_pwr, error;
+ *br_io = 0;
+
if (rate == 0)
return (0);
@@ -3439,7 +3441,6 @@ static int __devinit
cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int first_time = 1;
- ucchar cpc_rev_id;
int err, eeprom_outdated = 0;
ucshort device_id;
pc300_t *card;
@@ -3455,7 +3456,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if ((err = pci_enable_device(pdev)) < 0)
return err;
- card = kmalloc(sizeof(pc300_t), GFP_KERNEL);
+ card = kzalloc(sizeof(pc300_t), GFP_KERNEL);
if (card == NULL) {
printk("PC300 found at RAM 0x%016llx, "
"but could not allocate card structure.\n",
@@ -3463,7 +3464,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
err = -ENOMEM;
goto err_disable_dev;
}
- memset(card, 0, sizeof(pc300_t));
err = -ENODEV;
@@ -3480,7 +3480,6 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
card->hw.falcsize = pci_resource_len(pdev, 4);
card->hw.plxphys = pci_resource_start(pdev, 5);
card->hw.plxsize = pci_resource_len(pdev, 5);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &cpc_rev_id);
switch (device_id) {
case PCI_DEVICE_ID_PC300_RX_1:
@@ -3498,7 +3497,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
#ifdef PC300_DEBUG_PCI
printk("cpc (bus=0x0%x,pci_id=0x%x,", pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n", cpc_rev_id, card->hw.irq);
+ printk("rev_id=%d) IRQ%d\n", pdev->revision, card->hw.irq);
printk("cpc:found ramaddr=0x%08lx plxaddr=0x%08lx "
"ctladdr=0x%08lx falcaddr=0x%08lx\n",
card->hw.ramphys, card->hw.plxphys, card->hw.scaphys,
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
index aff05dba720a..6353cb5c658d 100644
--- a/drivers/net/wan/pc300too.c
+++ b/drivers/net/wan/pc300too.c
@@ -311,7 +311,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
card_t *card;
- u8 rev_id;
u32 __iomem *p;
int i;
u32 ramsize;
@@ -335,14 +334,13 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
return i;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "pc300: unable to allocate memory\n");
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
pci_set_drvdata(pdev, card);
if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
@@ -366,7 +364,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
return -ENOMEM;
}
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
pci_resource_len(pdev, 3) < 16384) {
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index ca06a00d9d86..092e51d89036 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -289,7 +289,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
card_t *card;
- u8 rev_id;
u32 __iomem *p;
int i;
u32 ramsize;
@@ -313,14 +312,13 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
return i;
}
- card = kmalloc(sizeof(card_t), GFP_KERNEL);
+ card = kzalloc(sizeof(card_t), GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "pci200syn: unable to allocate memory\n");
pci_release_regions(pdev);
pci_disable_device(pdev);
return -ENOBUFS;
}
- memset(card, 0, sizeof(card_t));
pci_set_drvdata(pdev, card);
card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
@@ -330,7 +328,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
return -ENOMEM;
}
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
if (pci_resource_len(pdev, 0) != PCI200SYN_PLX_SIZE ||
pci_resource_len(pdev, 2) != PCI200SYN_SCA_SIZE ||
pci_resource_len(pdev, 3) < 16384) {
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 35eded7ffb2d..1cc18e787a65 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -595,8 +595,8 @@ recv_frame( struct net_device *dev )
u32 crc = CRC32_INITIAL;
- unsigned framelen, frameno, ack;
- unsigned is_first, frame_ok;
+ unsigned framelen = 0, frameno, ack;
+ unsigned is_first, frame_ok = 0;
if( check_fhdr( ioaddr, &framelen, &frameno, &ack, &is_first, &crc ) ) {
frame_ok = framelen > 4
@@ -604,8 +604,7 @@ recv_frame( struct net_device *dev )
: skip_tail( ioaddr, framelen, crc );
if( frame_ok )
interpret_ack( dev, ack );
- } else
- frame_ok = 0;
+ }
outb( inb( ioaddr + CSR0 ) ^ CT_ZER, ioaddr + CSR0 );
if( frame_ok ) {
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 6a485f0556f4..792e588d7d61 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -1196,10 +1196,9 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r
if (read)
{
- temp = kmalloc(mem.len, GFP_KERNEL);
+ temp = kzalloc(mem.len, GFP_KERNEL);
if (!temp)
return(-ENOMEM);
- memset(temp, 0, mem.len);
sdla_read(dev, mem.addr, temp, mem.len);
if(copy_to_user(mem.data, temp, mem.len))
{
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 131358108c5a..11276bf3149f 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -270,11 +270,10 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
return NULL;
}
- b = kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
+ b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL);
if(!b)
goto fail3;
- memset(b, 0, sizeof(*b));
if (!(b->dev[0]= slvl_alloc(iobase, irq)))
goto fail2;
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index c73601574334..3c78f9856380 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -599,7 +599,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
}
alloc_size = sizeof(card_t) + ports * sizeof(port_t);
- card = kmalloc(alloc_size, GFP_KERNEL);
+ card = kzalloc(alloc_size, GFP_KERNEL);
if (card == NULL) {
printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
pci_name(pdev));
@@ -607,7 +607,6 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
pci_disable_device(pdev);
return -ENOBUFS;
}
- memset(card, 0, alloc_size);
pci_set_drvdata(pdev, card);
card->pdev = pdev;
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 1c9edd97accd..c48b1cc63fd5 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -786,14 +786,12 @@ static int __init init_x25_asy(void)
printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
"(dynamic channels, max=%d).\n", x25_asy_maxdev );
- x25_asy_devs = kmalloc(sizeof(struct net_device *)*x25_asy_maxdev,
- GFP_KERNEL);
+ x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL);
if (!x25_asy_devs) {
printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
"array! Uaargh! (-> No X.25 available)\n");
return -ENOMEM;
}
- memset(x25_asy_devs, 0, sizeof(struct net_device *)*x25_asy_maxdev);
return tty_register_ldisc(N_X25, &x25_ldisc);
}
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 2d3a180dada0..ee1cc14db389 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -52,6 +52,8 @@
#include "airo.h"
+#define DRV_NAME "airo"
+
#ifdef CONFIG_PCI
static struct pci_device_id card_ids[] = {
{ 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
@@ -71,7 +73,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state);
static int airo_pci_resume(struct pci_dev *pdev);
static struct pci_driver airo_driver = {
- .name = "airo",
+ .name = DRV_NAME,
.id_table = card_ids,
.probe = airo_pci_probe,
.remove = __devexit_p(airo_pci_remove),
@@ -1092,7 +1094,7 @@ static int get_dec_u16( char *buffer, int *start, int limit );
static void OUT4500( struct airo_info *, u16 register, u16 value );
static unsigned short IN4500( struct airo_info *, u16 register );
static u16 setup_card(struct airo_info*, u8 *mac, int lock);
-static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock );
+static int enable_MAC(struct airo_info *ai, int lock);
static void disable_MAC(struct airo_info *ai, int lock);
static void enable_interrupts(struct airo_info*);
static void disable_interrupts(struct airo_info*);
@@ -1250,7 +1252,7 @@ static int flashputbuf(struct airo_info *ai);
static int flashrestart(struct airo_info *ai,struct net_device *dev);
#define airo_print(type, name, fmt, args...) \
- { printk(type "airo(%s): " fmt "\n", name, ##args); }
+ printk(type DRV_NAME "(%s): " fmt "\n", name, ##args)
#define airo_print_info(name, fmt, args...) \
airo_print(KERN_INFO, name, fmt, ##args)
@@ -1926,28 +1928,54 @@ static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
return rc;
}
+static void try_auto_wep(struct airo_info *ai)
+{
+ if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) {
+ ai->expires = RUN_AT(3*HZ);
+ wake_up_interruptible(&ai->thr_wait);
+ }
+}
+
static int airo_open(struct net_device *dev) {
- struct airo_info *info = dev->priv;
- Resp rsp;
+ struct airo_info *ai = dev->priv;
+ int rc = 0;
- if (test_bit(FLAG_FLASHING, &info->flags))
+ if (test_bit(FLAG_FLASHING, &ai->flags))
return -EIO;
/* Make sure the card is configured.
* Wireless Extensions may postpone config changes until the card
* is open (to pipeline changes and speed-up card setup). If
* those changes are not yet commited, do it now - Jean II */
- if (test_bit (FLAG_COMMIT, &info->flags)) {
- disable_MAC(info, 1);
- writeConfigRid(info, 1);
+ if (test_bit(FLAG_COMMIT, &ai->flags)) {
+ disable_MAC(ai, 1);
+ writeConfigRid(ai, 1);
}
- if (info->wifidev != dev) {
+ if (ai->wifidev != dev) {
+ clear_bit(JOB_DIE, &ai->jobs);
+ ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
+ if (IS_ERR(ai->airo_thread_task))
+ return (int)PTR_ERR(ai->airo_thread_task);
+
+ rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
+ dev->name, dev);
+ if (rc) {
+ airo_print_err(dev->name,
+ "register interrupt %d failed, rc %d",
+ dev->irq, rc);
+ set_bit(JOB_DIE, &ai->jobs);
+ kthread_stop(ai->airo_thread_task);
+ return rc;
+ }
+
/* Power on the MAC controller (which may have been disabled) */
- clear_bit(FLAG_RADIO_DOWN, &info->flags);
- enable_interrupts(info);
+ clear_bit(FLAG_RADIO_DOWN, &ai->flags);
+ enable_interrupts(ai);
+
+ try_auto_wep(ai);
}
- enable_MAC(info, &rsp, 1);
+ enable_MAC(ai, 1);
netif_start_queue(dev);
return 0;
@@ -2338,14 +2366,13 @@ static int airo_set_mac_address(struct net_device *dev, void *p)
{
struct airo_info *ai = dev->priv;
struct sockaddr *addr = p;
- Resp rsp;
readConfigRid(ai, 1);
memcpy (ai->config.macAddr, addr->sa_data, dev->addr_len);
set_bit (FLAG_COMMIT, &ai->flags);
disable_MAC(ai, 1);
writeConfigRid (ai, 1);
- enable_MAC(ai, &rsp, 1);
+ enable_MAC(ai, 1);
memcpy (ai->dev->dev_addr, addr->sa_data, dev->addr_len);
if (ai->wifidev)
memcpy (ai->wifidev->dev_addr, addr->sa_data, dev->addr_len);
@@ -2392,6 +2419,11 @@ static int airo_close(struct net_device *dev) {
disable_MAC(ai, 1);
#endif
disable_interrupts( ai );
+
+ free_irq(dev->irq, dev);
+
+ set_bit(JOB_DIE, &ai->jobs);
+ kthread_stop(ai->airo_thread_task);
}
return 0;
}
@@ -2403,7 +2435,6 @@ void stop_airo_card( struct net_device *dev, int freeres )
set_bit(FLAG_RADIO_DOWN, &ai->flags);
disable_MAC(ai, 1);
disable_interrupts(ai);
- free_irq( dev->irq, dev );
takedown_proc_entry( dev, ai );
if (test_bit(FLAG_REGISTERED, &ai->flags)) {
unregister_netdev( dev );
@@ -2414,9 +2445,6 @@ void stop_airo_card( struct net_device *dev, int freeres )
}
clear_bit(FLAG_REGISTERED, &ai->flags);
}
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
-
/*
* Clean out tx queue
*/
@@ -2554,8 +2582,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
* 2) Map PCI memory for issueing commands.
* 3) Allocate memory (shared) to send and receive ethernet frames.
*/
-static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
- const char *name)
+static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
{
unsigned long mem_start, mem_len, aux_start, aux_len;
int rc = -1;
@@ -2569,35 +2596,35 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
aux_start = pci_resource_start(pci, 2);
aux_len = AUXMEMSIZE;
- if (!request_mem_region(mem_start, mem_len, name)) {
- airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
- (int)mem_start, (int)mem_len, name);
+ if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
+ airo_print_err("", "Couldn't get region %x[%x]",
+ (int)mem_start, (int)mem_len);
goto out;
}
- if (!request_mem_region(aux_start, aux_len, name)) {
- airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
- (int)aux_start, (int)aux_len, name);
+ if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
+ airo_print_err("", "Couldn't get region %x[%x]",
+ (int)aux_start, (int)aux_len);
goto free_region1;
}
ai->pcimem = ioremap(mem_start, mem_len);
if (!ai->pcimem) {
- airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
- (int)mem_start, (int)mem_len, name);
+ airo_print_err("", "Couldn't map region %x[%x]",
+ (int)mem_start, (int)mem_len);
goto free_region2;
}
ai->pciaux = ioremap(aux_start, aux_len);
if (!ai->pciaux) {
- airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
- (int)aux_start, (int)aux_len, name);
+ airo_print_err("", "Couldn't map region %x[%x]",
+ (int)aux_start, (int)aux_len);
goto free_memmap;
}
/* Reserve PKTSIZE for each fid and 2K for the Rids */
ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
if (!ai->shared) {
- airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d",
- PCI_SHARED_LEN);
+ airo_print_err("", "Couldn't alloc_consistent %d",
+ PCI_SHARED_LEN);
goto free_auxmap;
}
@@ -2742,7 +2769,7 @@ static int airo_networks_allocate(struct airo_info *ai)
kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
GFP_KERNEL);
if (!ai->networks) {
- airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
+ airo_print_warn("", "Out of memory allocating beacons");
return -ENOMEM;
}
@@ -2770,7 +2797,6 @@ static int airo_test_wpa_capable(struct airo_info *ai)
{
int status;
CapabilityRid cap_rid;
- const char *name = ai->dev->name;
status = readCapabilityRid(ai, &cap_rid, 1);
if (status != SUCCESS) return 0;
@@ -2778,12 +2804,12 @@ static int airo_test_wpa_capable(struct airo_info *ai)
/* Only firmware versions 5.30.17 or better can do WPA */
if ((cap_rid.softVer > 0x530)
|| ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
- airo_print_info(name, "WPA is supported.");
+ airo_print_info("", "WPA is supported.");
return 1;
}
/* No WPA support */
- airo_print_info(name, "WPA unsupported (only firmware versions 5.30.17"
+ airo_print_info("", "WPA unsupported (only firmware versions 5.30.17"
" and greater support WPA. Detected %s)", cap_rid.prodVer);
return 0;
}
@@ -2797,23 +2823,19 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
int i, rc;
/* Create the network device object. */
- dev = alloc_etherdev(sizeof(*ai));
- if (!dev) {
+ dev = alloc_netdev(sizeof(*ai), "", ether_setup);
+ if (!dev) {
airo_print_err("", "Couldn't alloc_etherdev");
return NULL;
- }
- if (dev_alloc_name(dev, dev->name) < 0) {
- airo_print_err("", "Couldn't get name!");
- goto err_out_free;
}
ai = dev->priv;
ai->wifidev = NULL;
- ai->flags = 0;
+ ai->flags = 1 << FLAG_RADIO_DOWN;
ai->jobs = 0;
ai->dev = dev;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
- airo_print_dbg(dev->name, "Found an MPI350 card");
+ airo_print_dbg("", "Found an MPI350 card");
set_bit(FLAG_MPI, &ai->flags);
}
spin_lock_init(&ai->aux_lock);
@@ -2821,14 +2843,11 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai->config.len = 0;
ai->pci = pci;
init_waitqueue_head (&ai->thr_wait);
- ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
- if (IS_ERR(ai->airo_thread_task))
- goto err_out_free;
ai->tfm = NULL;
add_airo_dev(ai);
if (airo_networks_allocate (ai))
- goto err_out_thr;
+ goto err_out_free;
airo_networks_initialize (ai);
/* The Airo-specific entries in the device structure. */
@@ -2851,27 +2870,22 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
dev->base_addr = port;
SET_NETDEV_DEV(dev, dmdev);
+ SET_MODULE_OWNER(dev);
reset_card (dev, 1);
msleep(400);
- rc = request_irq( dev->irq, airo_interrupt, IRQF_SHARED, dev->name, dev );
- if (rc) {
- airo_print_err(dev->name, "register interrupt %d failed, rc %d",
- irq, rc);
- goto err_out_nets;
- }
if (!is_pcmcia) {
- if (!request_region( dev->base_addr, 64, dev->name )) {
+ if (!request_region(dev->base_addr, 64, DRV_NAME)) {
rc = -EBUSY;
airo_print_err(dev->name, "Couldn't request region");
- goto err_out_irq;
+ goto err_out_nets;
}
}
if (test_bit(FLAG_MPI,&ai->flags)) {
- if (mpi_map_card(ai, pci, dev->name)) {
- airo_print_err(dev->name, "Could not map memory");
+ if (mpi_map_card(ai, pci)) {
+ airo_print_err("", "Could not map memory");
goto err_out_res;
}
}
@@ -2899,6 +2913,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai->bssListRidLen = sizeof(BSSListRid) - sizeof(BSSListRidExtra);
}
+ strcpy(dev->name, "eth%d");
rc = register_netdev(dev);
if (rc) {
airo_print_err(dev->name, "Couldn't register_netdev");
@@ -2921,8 +2936,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
if (setup_proc_entry(dev, dev->priv) < 0)
goto err_out_wifi;
- netif_start_queue(dev);
- SET_MODULE_OWNER(dev);
return dev;
err_out_wifi:
@@ -2940,14 +2953,9 @@ err_out_map:
err_out_res:
if (!is_pcmcia)
release_region( dev->base_addr, 64 );
-err_out_irq:
- free_irq(dev->irq, dev);
err_out_nets:
airo_networks_free(ai);
-err_out_thr:
del_airo_dev(ai);
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
err_out_free:
free_netdev(dev);
return NULL;
@@ -3078,7 +3086,8 @@ static int airo_thread(void *data) {
struct net_device *dev = data;
struct airo_info *ai = dev->priv;
int locked;
-
+
+ set_freezable();
while(1) {
/* make swsusp happy with our thread */
try_to_freeze();
@@ -3529,9 +3538,11 @@ static u16 IN4500( struct airo_info *ai, u16 reg ) {
return rc;
}
-static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
+static int enable_MAC(struct airo_info *ai, int lock)
+{
int rc;
- Cmd cmd;
+ Cmd cmd;
+ Resp rsp;
/* FLAG_RADIO_OFF : Radio disabled via /proc or Wireless Extensions
* FLAG_RADIO_DOWN : Radio disabled via "ifconfig ethX down"
@@ -3547,7 +3558,7 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
if (!test_bit(FLAG_ENABLED, &ai->flags)) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_ENABLE;
- rc = issuecommand(ai, &cmd, rsp);
+ rc = issuecommand(ai, &cmd, &rsp);
if (rc == SUCCESS)
set_bit(FLAG_ENABLED, &ai->flags);
} else
@@ -3557,8 +3568,12 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) {
up(&ai->sem);
if (rc)
- airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d",
- __FUNCTION__, rc);
+ airo_print_err(ai->dev->name, "Cannot enable MAC");
+ else if ((rsp.status & 0xFF00) != 0) {
+ airo_print_err(ai->dev->name, "Bad MAC enable reason=%x, "
+ "rid=%x, offset=%d", rsp.rsp0, rsp.rsp1, rsp.rsp2);
+ rc = ERROR;
+ }
return rc;
}
@@ -3902,12 +3917,9 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
if ( status != SUCCESS ) return ERROR;
}
- status = enable_MAC(ai, &rsp, lock);
- if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) {
- airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x,"
- " offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 );
+ status = enable_MAC(ai, lock);
+ if (status != SUCCESS)
return ERROR;
- }
/* Grab the initial wep key, we gotta save it for auto_wep */
rc = readWepKeyRid(ai, &wkr, 1, lock);
@@ -3919,10 +3931,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
rc = readWepKeyRid(ai, &wkr, 0, lock);
} while(lastindex != wkr.kindex);
- if (auto_wep) {
- ai->expires = RUN_AT(3*HZ);
- wake_up_interruptible(&ai->thr_wait);
- }
+ try_auto_wep(ai);
return SUCCESS;
}
@@ -4004,7 +4013,7 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
}
if ( !(max_tries--) ) {
airo_print_err(ai->dev->name,
- "airo: BAP setup error too many retries\n");
+ "BAP setup error too many retries\n");
return ERROR;
}
// -- PC4500 missed it, try again
@@ -5152,7 +5161,6 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
struct net_device *dev = dp->data;
struct airo_info *ai = dev->priv;
SsidRid SSID_rid;
- Resp rsp;
int i;
int offset = 0;
@@ -5177,7 +5185,7 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
SSID_rid.len = sizeof(SSID_rid);
disable_MAC(ai, 1);
writeSsidRid(ai, &SSID_rid, 1);
- enable_MAC(ai, &rsp, 1);
+ enable_MAC(ai, 1);
}
static inline u8 hexVal(char c) {
@@ -5193,7 +5201,6 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
struct net_device *dev = dp->data;
struct airo_info *ai = dev->priv;
APListRid APList_rid;
- Resp rsp;
int i;
if ( !data->writelen ) return;
@@ -5218,18 +5225,17 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
}
disable_MAC(ai, 1);
writeAPListRid(ai, &APList_rid, 1);
- enable_MAC(ai, &rsp, 1);
+ enable_MAC(ai, 1);
}
/* This function wraps PC4500_writerid with a MAC disable */
static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
int len, int dummy ) {
int rc;
- Resp rsp;
disable_MAC(ai, 1);
rc = PC4500_writerid(ai, rid, rid_data, len, 1);
- enable_MAC(ai, &rsp, 1);
+ enable_MAC(ai, 1);
return rc;
}
@@ -5260,7 +5266,6 @@ static int set_wep_key(struct airo_info *ai, u16 index,
const char *key, u16 keylen, int perm, int lock ) {
static const unsigned char macaddr[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
WepKeyRid wkr;
- Resp rsp;
memset(&wkr, 0, sizeof(wkr));
if (keylen == 0) {
@@ -5280,7 +5285,7 @@ static int set_wep_key(struct airo_info *ai, u16 index,
if (perm) disable_MAC(ai, lock);
writeWepKeyRid(ai, &wkr, perm, lock);
- if (perm) enable_MAC(ai, &rsp, lock);
+ if (perm) enable_MAC(ai, lock);
return 0;
}
@@ -5548,7 +5553,6 @@ static int proc_close( struct inode *inode, struct file *file )
changed. */
static void timer_func( struct net_device *dev ) {
struct airo_info *apriv = dev->priv;
- Resp rsp;
/* We don't have a link so try changing the authtype */
readConfigRid(apriv, 0);
@@ -5575,7 +5579,7 @@ static void timer_func( struct net_device *dev ) {
}
set_bit (FLAG_COMMIT, &apriv->flags);
writeConfigRid(apriv, 0);
- enable_MAC(apriv, &rsp, 0);
+ enable_MAC(apriv, 0);
up(&apriv->sem);
/* Schedule check to see if the change worked */
@@ -5597,8 +5601,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
else
dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
- if (!dev)
+ if (!dev) {
+ pci_disable_device(pdev);
return -ENODEV;
+ }
pci_set_drvdata(pdev, dev);
return 0;
@@ -5610,6 +5616,8 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev)
airo_print_info(dev->name, "Unregistering...");
stop_airo_card(dev, 1);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
}
static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -5646,7 +5654,6 @@ static int airo_pci_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct airo_info *ai = dev->priv;
- Resp rsp;
pci_power_t prev_state = pdev->current_state;
pci_set_power_state(pdev, PCI_D0);
@@ -5679,7 +5686,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
ai->APList = NULL;
}
writeConfigRid(ai, 0);
- enable_MAC(ai, &rsp, 0);
+ enable_MAC(ai, 0);
ai->power = PMSG_ON;
netif_device_attach(dev);
netif_wake_queue(dev);
@@ -5903,7 +5910,6 @@ static int airo_set_essid(struct net_device *dev,
char *extra)
{
struct airo_info *local = dev->priv;
- Resp rsp;
SsidRid SSID_rid; /* SSIDs */
/* Reload the list of current SSID */
@@ -5935,7 +5941,7 @@ static int airo_set_essid(struct net_device *dev,
/* Write it to the card */
disable_MAC(local, 1);
writeSsidRid(local, &SSID_rid, 1);
- enable_MAC(local, &rsp, 1);
+ enable_MAC(local, 1);
return 0;
}
@@ -6000,7 +6006,7 @@ static int airo_set_wap(struct net_device *dev,
memcpy(APList_rid.ap[0], awrq->sa_data, ETH_ALEN);
disable_MAC(local, 1);
writeAPListRid(local, &APList_rid, 1);
- enable_MAC(local, &rsp, 1);
+ enable_MAC(local, 1);
}
return 0;
}
@@ -7454,7 +7460,6 @@ static int airo_config_commit(struct net_device *dev,
char *extra) /* NULL */
{
struct airo_info *local = dev->priv;
- Resp rsp;
if (!test_bit (FLAG_COMMIT, &local->flags))
return 0;
@@ -7479,7 +7484,7 @@ static int airo_config_commit(struct net_device *dev,
if (down_interruptible(&local->sem))
return -ERESTARTSYS;
writeConfigRid(local, 0);
- enable_MAC(local, &rsp, 0);
+ enable_MAC(local, 0);
if (test_bit (FLAG_RESET, &local->flags))
airo_set_promisc(local);
else
@@ -7746,7 +7751,6 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
unsigned char *iobuf;
int len;
struct airo_info *ai = dev->priv;
- Resp rsp;
if (test_bit(FLAG_FLASHING, &ai->flags))
return -EIO;
@@ -7758,7 +7762,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
if (test_bit(FLAG_COMMIT, &ai->flags)) {
disable_MAC (ai, 1);
writeConfigRid (ai, 1);
- enable_MAC (ai, &rsp, 1);
+ enable_MAC(ai, 1);
}
break;
case AIROGSLIST: ridcode = RID_SSID; break;
@@ -7815,7 +7819,6 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
struct airo_info *ai = dev->priv;
int ridcode;
int enabled;
- Resp rsp;
static int (* writer)(struct airo_info *, u16 rid, const void *, int, int);
unsigned char *iobuf;
@@ -7849,7 +7852,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
* same with MAC off
*/
case AIROPMACON:
- if (enable_MAC(ai, &rsp, 1) != 0)
+ if (enable_MAC(ai, 1) != 0)
return -EIO;
return 0;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index ef6b253a92ce..c5d6753a55ea 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -3741,10 +3741,8 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
&bcm->board_type);
if (err)
goto err_iounmap;
- err = bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID,
- &bcm->board_revision);
- if (err)
- goto err_iounmap;
+
+ bcm->board_revision = bcm->pci_dev->revision;
err = bcm43xx_chipset_attach(bcm);
if (err)
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index 0cd48d151f5e..7da3664b8515 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -453,8 +453,6 @@ static struct pci_driver prism2_pci_drv_id = {
.suspend = prism2_pci_suspend,
.resume = prism2_pci_resume,
#endif /* CONFIG_PM */
- /* Linux 2.4.6 added save_state and enable_wake that are not used here
- */
};
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index 0183df757b3e..040dc3e36410 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -613,9 +613,6 @@ static struct pci_driver prism2_plx_drv_id = {
.id_table = prism2_plx_id_table,
.probe = prism2_plx_probe,
.remove = prism2_plx_remove,
- .suspend = NULL,
- .resume = NULL,
- .enable_wake = NULL
};
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index d51daf87450f..8990585bd228 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -1768,7 +1768,8 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
if (priv->stop_rf_kill) {
priv->stop_rf_kill = 0;
- queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill,
+ round_jiffies(HZ));
}
deferred = 1;
@@ -2098,7 +2099,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
/* Make sure the RF Kill check timer is running */
priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill);
- queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill, round_jiffies(HZ));
}
static void isr_scan_complete(struct ipw2100_priv *priv, u32 status)
@@ -4233,7 +4234,8 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
/* Make sure the RF_KILL check timer is running */
priv->stop_rf_kill = 0;
cancel_delayed_work(&priv->rf_kill);
- queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill,
+ round_jiffies(HZ));
} else
schedule_reset(priv);
}
@@ -5969,7 +5971,8 @@ static void ipw2100_rf_kill(struct work_struct *work)
if (rf_kill_active(priv)) {
IPW_DEBUG_RF_KILL("RF Kill active, rescheduling GPIO check\n");
if (!priv->stop_rf_kill)
- queue_delayed_work(priv->workqueue, &priv->rf_kill, HZ);
+ queue_delayed_work(priv->workqueue, &priv->rf_kill,
+ round_jiffies(HZ));
goto exit_unlock;
}
@@ -7865,10 +7868,10 @@ static int ipw2100_wx_set_powermode(struct net_device *dev,
goto done;
}
- if ((mode < 1) || (mode > POWER_MODES))
+ if ((mode < 0) || (mode > POWER_MODES))
mode = IPW_POWER_AUTO;
- if (priv->power_mode != mode)
+ if (IPW_POWER_LEVEL(priv->power_mode) != mode)
err = ipw2100_set_power_mode(priv, mode);
done:
mutex_unlock(&priv->action_mutex);
@@ -7899,7 +7902,7 @@ static int ipw2100_wx_get_powermode(struct net_device *dev,
break;
case IPW_POWER_AUTO:
snprintf(extra, MAX_POWER_STRING,
- "Power save level: %d (Auto)", 0);
+ "Power save level: %d (Auto)", level);
break;
default:
timeout = timeout_duration[level - 1] / 1000;
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 7cb2052a55a5..61497c467467 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -70,7 +70,7 @@
#define VQ
#endif
-#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ
+#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
#define DRV_VERSION IPW2200_VERSION
@@ -1751,7 +1751,7 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio)
/* Make sure the RF_KILL check timer is running */
cancel_delayed_work(&priv->rf_kill);
queue_delayed_work(priv->workqueue, &priv->rf_kill,
- 2 * HZ);
+ round_jiffies(2 * HZ));
} else
queue_work(priv->workqueue, &priv->up);
}
@@ -2506,7 +2506,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
break;
}
- param = cpu_to_le32(mode);
+ param = cpu_to_le32(param);
return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
&param);
}
@@ -4690,7 +4690,8 @@ static void ipw_rx_notification(struct ipw_priv *priv,
else if (priv->config & CFG_BACKGROUND_SCAN
&& priv->status & STATUS_ASSOCIATED)
queue_delayed_work(priv->workqueue,
- &priv->request_scan, HZ);
+ &priv->request_scan,
+ round_jiffies(HZ));
/* Send an empty event to user space.
* We don't send the received data on the event because
@@ -9567,6 +9568,7 @@ static int ipw_wx_set_power(struct net_device *dev,
priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
else
priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+
err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
if (err) {
IPW_DEBUG_WX("failed setting power mode.\n");
@@ -9603,22 +9605,19 @@ static int ipw_wx_set_powermode(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
int mode = *(int *)extra;
int err;
+
mutex_lock(&priv->mutex);
- if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
+ if ((mode < 1) || (mode > IPW_POWER_LIMIT))
mode = IPW_POWER_AC;
- priv->power_mode = mode;
- } else {
- priv->power_mode = IPW_POWER_ENABLED | mode;
- }
- if (priv->power_mode != mode) {
+ if (IPW_POWER_LEVEL(priv->power_mode) != mode) {
err = ipw_send_power_mode(priv, mode);
-
if (err) {
IPW_DEBUG_WX("failed setting power mode.\n");
mutex_unlock(&priv->mutex);
return err;
}
+ priv->power_mode = IPW_POWER_ENABLED | mode;
}
mutex_unlock(&priv->mutex);
return 0;
@@ -10554,7 +10553,7 @@ static irqreturn_t ipw_isr(int irq, void *data)
spin_lock(&priv->irq_lock);
if (!(priv->status & STATUS_INT_ENABLED)) {
- /* Shared IRQ */
+ /* IRQ is disabled */
goto none;
}
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 13f6528abb00..4a8f5dc70239 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -240,7 +240,7 @@ static int wlan_cmd_802_11_enable_rsn(wlan_private * priv,
if (*enable)
penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
else
- penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+ penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
}
lbs_deb_leave(LBS_DEB_CMD);
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 4a59306a3f05..9f366242c392 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -613,6 +613,7 @@ static int wlan_service_main_thread(void *data)
init_waitqueue_entry(&wait, current);
+ set_freezable();
for (;;) {
lbs_deb_thread( "main-thread 111: intcounter=%d "
"currenttxskb=%p dnld_sent=%d\n",
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 88d9d2d787d5..769c86fb9509 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -439,7 +439,6 @@ static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb)
ret = 0;
done:
- skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */
lbs_deb_leave_args(LBS_DEB_RX, "ret %d", ret);
return ret;
}
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h
deleted file mode 100644
index 8b137891791f..000000000000
--- a/drivers/net/wireless/libertas/version.h
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index f42b796b5e47..2fcc3bf21081 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -1719,9 +1719,6 @@ static int wlan_set_encodeext(struct net_device *dev,
pkey->type = KEY_TYPE_ID_TKIP;
} else if (alg == IW_ENCODE_ALG_CCMP) {
pkey->type = KEY_TYPE_ID_AES;
- } else {
- ret = -EINVAL;
- goto out;
}
/* If WPA isn't enabled yet, do that now */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 283be4a70524..585f5996d292 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1853,7 +1853,6 @@ prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl;
struct mac_entry *entry;
- struct list_head *ptr;
struct sockaddr *addr = (struct sockaddr *) extra;
if (addr->sa_family != ARPHRD_ETHER)
@@ -1861,11 +1860,9 @@ prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
if (down_interruptible(&acl->sem))
return -ERESTARTSYS;
- for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, _list);
-
+ list_for_each_entry(entry, &acl->mac_list, _list) {
if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) {
- list_del(ptr);
+ list_del(&entry->_list);
acl->size--;
kfree(entry);
up(&acl->sem);
@@ -1883,7 +1880,6 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl;
struct mac_entry *entry;
- struct list_head *ptr;
struct sockaddr *dst = (struct sockaddr *) extra;
dwrq->length = 0;
@@ -1891,9 +1887,7 @@ prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
if (down_interruptible(&acl->sem))
return -ERESTARTSYS;
- for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, _list);
-
+ list_for_each_entry(entry, &acl->mac_list, _list) {
memcpy(dst->sa_data, entry->addr, ETH_ALEN);
dst->sa_family = ARPHRD_ETHER;
dwrq->length++;
@@ -1960,7 +1954,6 @@ prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
static int
prism54_mac_accept(struct islpci_acl *acl, char *mac)
{
- struct list_head *ptr;
struct mac_entry *entry;
int res = 0;
@@ -1972,8 +1965,7 @@ prism54_mac_accept(struct islpci_acl *acl, char *mac)
return 1;
}
- for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) {
- entry = list_entry(ptr, struct mac_entry, _list);
+ list_for_each_entry(entry, &acl->mac_list, _list) {
if (memcmp(entry->addr, mac, ETH_ALEN) == 0) {
res = 1;
break;
@@ -2216,11 +2208,9 @@ prism54_wpa_bss_ie_init(islpci_private *priv)
void
prism54_wpa_bss_ie_clean(islpci_private *priv)
{
- struct list_head *ptr, *n;
+ struct islpci_bss_wpa_ie *bss, *n;
- list_for_each_safe(ptr, n, &priv->bss_wpa_list) {
- struct islpci_bss_wpa_ie *bss;
- bss = list_entry(ptr, struct islpci_bss_wpa_ie, list);
+ list_for_each_entry_safe(bss, n, &priv->bss_wpa_list, list) {
kfree(bss);
}
}
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index 3dcb13bb7d57..af2e4f2405f2 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -87,7 +87,6 @@ static struct pci_driver prism54_driver = {
.remove = prism54_remove,
.suspend = prism54_suspend,
.resume = prism54_resume,
- /* .enable_wake ; we don't support this yet */
};
/******************************************************************************
@@ -167,8 +166,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_master(pdev);
/* enable MWI */
- if (!pci_set_mwi(pdev))
- printk(KERN_INFO "%s: pci_set_mwi(pdev) succeeded\n", DRV_NAME);
+ pci_try_set_mwi(pdev);
/* setup the network device interface and its structure */
if (!(ndev = islpci_setup(pdev))) {
diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c
index e25a09f1b068..efc41207780e 100644
--- a/drivers/net/wireless/rtl8187_rtl8225.c
+++ b/drivers/net/wireless/rtl8187_rtl8225.c
@@ -67,7 +67,7 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data)
msleep(2);
}
-static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, u16 data)
+static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data)
{
struct rtl8187_priv *priv = dev->priv;
u16 reg80, reg82, reg84;
@@ -106,7 +106,7 @@ void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data)
struct rtl8187_priv *priv = dev->priv;
if (priv->asic_rev)
- rtl8225_write_8051(dev, addr, data);
+ rtl8225_write_8051(dev, addr, cpu_to_le16(data));
else
rtl8225_write_bitbang(dev, addr, data);
}
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index ce9230b2f630..c8b5c2271938 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1011,7 +1011,7 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev,
} else {
skb->dev = dev;
skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */
- eth_copy_and_sum(skb, (unsigned char *)&sig.daddr, 12, 0);
+ skb_copy_to_linear_data(skb, (unsigned char *)&sig.daddr, 12);
wl3501_receive(this, skb->data, pkt_len);
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, dev);
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 5b624bfc01a6..c39f1984b84d 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -49,8 +49,9 @@ void zd_chip_clear(struct zd_chip *chip)
ZD_MEMCLEAR(chip, sizeof(*chip));
}
-static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
+static int scnprint_mac_oui(struct zd_chip *chip, char *buffer, size_t size)
{
+ u8 *addr = zd_usb_to_netdev(&chip->usb)->dev_addr;
return scnprintf(buffer, size, "%02x-%02x-%02x",
addr[0], addr[1], addr[2]);
}
@@ -61,10 +62,10 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
int i = 0;
i = scnprintf(buffer, size, "zd1211%s chip ",
- chip->is_zd1211b ? "b" : "");
+ zd_chip_is_zd1211b(chip) ? "b" : "");
i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " ");
- i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
+ i += scnprint_mac_oui(chip, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " ");
i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type,
@@ -366,64 +367,9 @@ error:
return r;
}
-static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr,
- const zd_addr_t *addr)
-{
- int r;
- u32 parts[2];
-
- r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2);
- if (r) {
- dev_dbg_f(zd_chip_dev(chip),
- "error: couldn't read e2p macs. Error number %d\n", r);
- return r;
- }
-
- mac_addr[0] = parts[0];
- mac_addr[1] = parts[0] >> 8;
- mac_addr[2] = parts[0] >> 16;
- mac_addr[3] = parts[0] >> 24;
- mac_addr[4] = parts[1];
- mac_addr[5] = parts[1] >> 8;
-
- return 0;
-}
-
-static int read_e2p_mac_addr(struct zd_chip *chip)
-{
- static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 };
-
- ZD_ASSERT(mutex_is_locked(&chip->mutex));
- return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr);
-}
-
/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and
* CR_MAC_ADDR_P2 must be overwritten
*/
-void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr)
-{
- mutex_lock(&chip->mutex);
- memcpy(mac_addr, chip->e2p_mac, ETH_ALEN);
- mutex_unlock(&chip->mutex);
-}
-
-static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
-{
- static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 };
- return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr);
-}
-
-int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
-{
- int r;
-
- dev_dbg_f(zd_chip_dev(chip), "\n");
- mutex_lock(&chip->mutex);
- r = read_mac_addr(chip, mac_addr);
- mutex_unlock(&chip->mutex);
- return r;
-}
-
int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
{
int r;
@@ -444,12 +390,6 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
-#ifdef DEBUG
- {
- u8 tmp[ETH_ALEN];
- read_mac_addr(chip, tmp);
- }
-#endif /* DEBUG */
mutex_unlock(&chip->mutex);
return r;
}
@@ -809,7 +749,7 @@ out:
static int hw_reset_phy(struct zd_chip *chip)
{
- return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) :
+ return zd_chip_is_zd1211b(chip) ? zd1211b_hw_reset_phy(chip) :
zd1211_hw_reset_phy(chip);
}
@@ -874,7 +814,7 @@ static int hw_init_hmac(struct zd_chip *chip)
if (r)
return r;
- return chip->is_zd1211b ?
+ return zd_chip_is_zd1211b(chip) ?
zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
}
@@ -1136,8 +1076,15 @@ static int read_fw_regs_offset(struct zd_chip *chip)
return 0;
}
+/* Read mac address using pre-firmware interface */
+int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr)
+{
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ return zd_usb_read_fw(&chip->usb, E2P_MAC_ADDR_P1, addr,
+ ETH_ALEN);
+}
-int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
+int zd_chip_init_hw(struct zd_chip *chip)
{
int r;
u8 rf_type;
@@ -1145,7 +1092,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
dev_dbg_f(zd_chip_dev(chip), "\n");
mutex_lock(&chip->mutex);
- chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0;
#ifdef DEBUG
r = test_init(chip);
@@ -1201,10 +1147,6 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
goto out;
#endif /* DEBUG */
- r = read_e2p_mac_addr(chip);
- if (r)
- goto out;
-
r = read_cal_int_tables(chip);
if (r)
goto out;
@@ -1259,7 +1201,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
r = update_pwr_int(chip, channel);
if (r)
return r;
- if (chip->is_zd1211b) {
+ if (zd_chip_is_zd1211b(chip)) {
static const struct zd_ioreq16 ioreqs[] = {
{ CR69, 0x28 },
{},
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 79d0288c193a..f4698576ab71 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -704,7 +704,6 @@ struct zd_chip {
struct mutex mutex;
/* Base address of FW_REG_ registers */
zd_addr_t fw_regs_base;
- u8 e2p_mac[ETH_ALEN];
/* EepSetPoint in the vendor driver */
u8 pwr_cal_values[E2P_CHANNEL_COUNT];
/* integration values in the vendor driver */
@@ -715,7 +714,7 @@ struct zd_chip {
unsigned int pa_type:4,
patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
new_phy_layout:1, al2230s_bit:1,
- is_zd1211b:1, supports_tx_led:1;
+ supports_tx_led:1;
};
static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
@@ -734,9 +733,15 @@ void zd_chip_init(struct zd_chip *chip,
struct net_device *netdev,
struct usb_interface *intf);
void zd_chip_clear(struct zd_chip *chip);
-int zd_chip_init_hw(struct zd_chip *chip, u8 device_type);
+int zd_chip_read_mac_addr_fw(struct zd_chip *chip, u8 *addr);
+int zd_chip_init_hw(struct zd_chip *chip);
int zd_chip_reset(struct zd_chip *chip);
+static inline int zd_chip_is_zd1211b(struct zd_chip *chip)
+{
+ return chip->usb.is_zd1211b;
+}
+
static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values,
const zd_addr_t *addresses,
unsigned int count)
@@ -825,8 +830,6 @@ static inline u8 _zd_chip_get_channel(struct zd_chip *chip)
}
u8 zd_chip_get_channel(struct zd_chip *chip);
int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain);
-void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr);
-int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr);
int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr);
int zd_chip_switch_radio_on(struct zd_chip *chip);
int zd_chip_switch_radio_off(struct zd_chip *chip);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 6753d240c168..f6c487aa8246 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -86,38 +86,46 @@ out:
return r;
}
-int zd_mac_init_hw(struct zd_mac *mac, u8 device_type)
+int zd_mac_preinit_hw(struct zd_mac *mac)
{
int r;
- struct zd_chip *chip = &mac->chip;
u8 addr[ETH_ALEN];
+
+ r = zd_chip_read_mac_addr_fw(&mac->chip, addr);
+ if (r)
+ return r;
+
+ memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
+ return 0;
+}
+
+int zd_mac_init_hw(struct zd_mac *mac)
+{
+ int r;
+ struct zd_chip *chip = &mac->chip;
u8 default_regdomain;
r = zd_chip_enable_int(chip);
if (r)
goto out;
- r = zd_chip_init_hw(chip, device_type);
+ r = zd_chip_init_hw(chip);
if (r)
goto disable_int;
- zd_get_e2p_mac_addr(chip, addr);
- r = zd_write_mac_addr(chip, addr);
- if (r)
- goto disable_int;
ZD_ASSERT(!irqs_disabled());
- spin_lock_irq(&mac->lock);
- memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
- spin_unlock_irq(&mac->lock);
r = zd_read_regdomain(chip, &default_regdomain);
if (r)
goto disable_int;
if (!zd_regdomain_supported(default_regdomain)) {
- dev_dbg_f(zd_mac_dev(mac),
- "Regulatory Domain %#04x is not supported.\n",
- default_regdomain);
- r = -EINVAL;
- goto disable_int;
+ /* The vendor driver overrides the regulatory domain and
+ * allowed channel registers and unconditionally restricts
+ * available channels to 1-11 everywhere. Match their
+ * questionable behaviour only for regdomains which we don't
+ * recognise. */
+ dev_warn(zd_mac_dev(mac), "Unrecognised regulatory domain: "
+ "%#04x. Defaulting to FCC.\n", default_regdomain);
+ default_regdomain = ZD_REGDOMAIN_FCC;
}
spin_lock_irq(&mac->lock);
mac->regdomain = mac->default_regdomain = default_regdomain;
@@ -164,14 +172,25 @@ int zd_mac_open(struct net_device *netdev)
{
struct zd_mac *mac = zd_netdev_mac(netdev);
struct zd_chip *chip = &mac->chip;
+ struct zd_usb *usb = &chip->usb;
int r;
+ if (!usb->initialized) {
+ r = zd_usb_init_hw(usb);
+ if (r)
+ goto out;
+ }
+
tasklet_enable(&mac->rx_tasklet);
r = zd_chip_enable_int(chip);
if (r < 0)
goto out;
+ r = zd_write_mac_addr(chip, netdev->dev_addr);
+ if (r)
+ goto disable_int;
+
r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
if (r < 0)
goto disable_int;
@@ -251,9 +270,11 @@ int zd_mac_set_mac_address(struct net_device *netdev, void *p)
dev_dbg_f(zd_mac_dev(mac),
"Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
- r = zd_write_mac_addr(chip, addr->sa_data);
- if (r)
- return r;
+ if (netdev->flags & IFF_UP) {
+ r = zd_write_mac_addr(chip, addr->sa_data);
+ if (r)
+ return r;
+ }
spin_lock_irqsave(&mac->lock, flags);
memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
@@ -855,7 +876,7 @@ static int fill_ctrlset(struct zd_mac *mac,
/* ZD1211B: Computing the length difference this way, gives us
* flexibility to compute the packet length.
*/
- cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ?
+ cs->packet_length = cpu_to_le16(zd_chip_is_zd1211b(&mac->chip) ?
packet_length - frag_len : packet_length);
/*
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index faf4c7828d4e..9f9344eb50f9 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -189,7 +189,8 @@ int zd_mac_init(struct zd_mac *mac,
struct usb_interface *intf);
void zd_mac_clear(struct zd_mac *mac);
-int zd_mac_init_hw(struct zd_mac *mac, u8 device_type);
+int zd_mac_preinit_hw(struct zd_mac *mac);
+int zd_mac_init_hw(struct zd_mac *mac);
int zd_mac_open(struct net_device *netdev);
int zd_mac_stop(struct net_device *netdev);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
index 7407409b60b1..abe5d38f7f4d 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -34,7 +34,7 @@ static const char * const rfs[] = {
[AL2210_RF] = "AL2210_RF",
[MAXIM_NEW_RF] = "MAXIM_NEW_RF",
[UW2453_RF] = "UW2453_RF",
- [UNKNOWN_A_RF] = "UNKNOWN_A_RF",
+ [AL2230S_RF] = "AL2230S_RF",
[RALINK_RF] = "RALINK_RF",
[INTERSIL_RF] = "INTERSIL_RF",
[RF2959_RF] = "RF2959_RF",
@@ -77,6 +77,7 @@ int zd_rf_init_hw(struct zd_rf *rf, u8 type)
r = zd_rf_init_rf2959(rf);
break;
case AL2230_RF:
+ case AL2230S_RF:
r = zd_rf_init_al2230(rf);
break;
case AL7230B_RF:
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index c6dfd8227f6e..30502f26b71c 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -26,7 +26,7 @@
#define AL2210_RF 0x7
#define MAXIM_NEW_RF 0x8
#define UW2453_RF 0x9
-#define UNKNOWN_A_RF 0xa
+#define AL2230S_RF 0xa
#define RALINK_RF 0xb
#define INTERSIL_RF 0xc
#define RF2959_RF 0xd
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index e7a4ecf7b6e2..006774de3202 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -21,6 +21,8 @@
#include "zd_usb.h"
#include "zd_chip.h"
+#define IS_AL2230S(chip) ((chip)->al2230s_bit || (chip)->rf.type == AL2230S_RF)
+
static const u32 zd1211_al2230_table[][3] = {
RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
@@ -176,7 +178,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
if (r)
return r;
- if (chip->al2230s_bit) {
+ if (IS_AL2230S(chip)) {
r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
ARRAY_SIZE(ioreqs_init_al2230s));
if (r)
@@ -188,7 +190,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
return r;
/* improve band edge for AL2230S */
- if (chip->al2230s_bit)
+ if (IS_AL2230S(chip))
r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS);
else
r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS);
@@ -314,7 +316,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
if (r)
return r;
- if (chip->al2230s_bit) {
+ if (IS_AL2230S(chip)) {
r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s,
ARRAY_SIZE(ioreqs_init_al2230s));
if (r)
@@ -328,7 +330,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
if (r)
return r;
- if (chip->al2230s_bit)
+ if (IS_AL2230S(chip))
r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS);
else
r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS);
@@ -422,7 +424,7 @@ int zd_rf_init_al2230(struct zd_rf *rf)
struct zd_chip *chip = zd_rf_to_chip(rf);
rf->switch_radio_off = al2230_switch_radio_off;
- if (chip->is_zd1211b) {
+ if (zd_chip_is_zd1211b(chip)) {
rf->init_hw = zd1211b_al2230_init_hw;
rf->set_channel = zd1211b_al2230_set_channel;
rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index f4e8b6ada854..73d0bb26f810 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -473,7 +473,7 @@ int zd_rf_init_al7230b(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
- if (chip->is_zd1211b) {
+ if (zd_chip_is_zd1211b(chip)) {
rf->init_hw = zd1211b_al7230b_init_hw;
rf->switch_radio_on = zd1211b_al7230b_switch_radio_on;
rf->set_channel = zd1211b_al7230b_set_channel;
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index 2d736bdf707c..cc70d40684ea 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -265,7 +265,7 @@ int zd_rf_init_rf2959(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
- if (chip->is_zd1211b) {
+ if (zd_chip_is_zd1211b(chip)) {
dev_err(zd_chip_dev(chip),
"RF2959 is currently not supported for ZD1211B"
" devices\n");
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
index 414e40d571ab..857dcf3eae61 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
@@ -486,7 +486,7 @@ static int uw2453_switch_radio_on(struct zd_rf *rf)
if (r)
return r;
- if (chip->is_zd1211b)
+ if (zd_chip_is_zd1211b(chip))
ioreqs[1].value = 0x7f;
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 740a2194fdde..a9c339ef116a 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -15,7 +15,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <asm/unaligned.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -26,6 +25,7 @@
#include <linux/usb.h>
#include <linux/workqueue.h>
#include <net/ieee80211.h>
+#include <asm/unaligned.h>
#include "zd_def.h"
#include "zd_netdev.h"
@@ -71,6 +71,9 @@ static struct usb_device_id usb_ids[] = {
{ USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
/* "Driverless" devices that need ejecting */
{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
@@ -195,26 +198,27 @@ static u16 get_word(const void *data, u16 offset)
return le16_to_cpu(p[offset]);
}
-static char *get_fw_name(char *buffer, size_t size, u8 device_type,
+static char *get_fw_name(struct zd_usb *usb, char *buffer, size_t size,
const char* postfix)
{
scnprintf(buffer, size, "%s%s",
- device_type == DEVICE_ZD1211B ?
+ usb->is_zd1211b ?
FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX,
postfix);
return buffer;
}
-static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
+static int handle_version_mismatch(struct zd_usb *usb,
const struct firmware *ub_fw)
{
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
const struct firmware *ur_fw = NULL;
int offset;
int r = 0;
char fw_name[128];
r = request_fw_file(&ur_fw,
- get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
+ get_fw_name(usb, fw_name, sizeof(fw_name), "ur"),
&udev->dev);
if (r)
goto error;
@@ -237,11 +241,12 @@ error:
return r;
}
-static int upload_firmware(struct usb_device *udev, u8 device_type)
+static int upload_firmware(struct zd_usb *usb)
{
int r;
u16 fw_bcdDevice;
u16 bcdDevice;
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
const struct firmware *ub_fw = NULL;
const struct firmware *uph_fw = NULL;
char fw_name[128];
@@ -249,7 +254,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
bcdDevice = get_bcdDevice(udev);
r = request_fw_file(&ub_fw,
- get_fw_name(fw_name, sizeof(fw_name), device_type, "ub"),
+ get_fw_name(usb, fw_name, sizeof(fw_name), "ub"),
&udev->dev);
if (r)
goto error;
@@ -264,7 +269,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
dev_warn(&udev->dev, "device has old bootcode, please "
"report success or failure\n");
- r = handle_version_mismatch(udev, device_type, ub_fw);
+ r = handle_version_mismatch(usb, ub_fw);
if (r)
goto error;
} else {
@@ -275,7 +280,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
r = request_fw_file(&uph_fw,
- get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"),
+ get_fw_name(usb, fw_name, sizeof(fw_name), "uphr"),
&udev->dev);
if (r)
goto error;
@@ -294,6 +299,30 @@ error:
return r;
}
+/* Read data from device address space using "firmware interface" which does
+ * not require firmware to be loaded. */
+int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len)
+{
+ int r;
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+
+ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_REQ_FIRMWARE_READ_DATA, USB_DIR_IN | 0x40, addr, 0,
+ data, len, 5000);
+ if (r < 0) {
+ dev_err(&udev->dev,
+ "read over firmware interface failed: %d\n", r);
+ return r;
+ } else if (r != len) {
+ dev_err(&udev->dev,
+ "incomplete read over firmware interface: %d/%d\n",
+ r, len);
+ return -EIO;
+ }
+
+ return 0;
+}
+
#define urb_dev(urb) (&(urb)->dev->dev)
static inline void handle_regs_int(struct urb *urb)
@@ -920,9 +949,42 @@ static int eject_installer(struct usb_interface *intf)
return 0;
}
+int zd_usb_init_hw(struct zd_usb *usb)
+{
+ int r;
+ struct zd_mac *mac = zd_usb_to_mac(usb);
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ r = upload_firmware(usb);
+ if (r) {
+ dev_err(zd_usb_dev(usb),
+ "couldn't load firmware. Error number %d\n", r);
+ return r;
+ }
+
+ r = usb_reset_configuration(zd_usb_to_usbdev(usb));
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "couldn't reset configuration. Error number %d\n", r);
+ return r;
+ }
+
+ r = zd_mac_init_hw(mac);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "couldn't initialize mac. Error number %d\n", r);
+ return r;
+ }
+
+ usb->initialized = 1;
+ return 0;
+}
+
static int probe(struct usb_interface *intf, const struct usb_device_id *id)
{
int r;
+ struct zd_usb *usb;
struct usb_device *udev = interface_to_usbdev(intf);
struct net_device *netdev = NULL;
@@ -950,26 +1012,10 @@ static int probe(struct usb_interface *intf, const struct usb_device_id *id)
goto error;
}
- r = upload_firmware(udev, id->driver_info);
- if (r) {
- dev_err(&intf->dev,
- "couldn't load firmware. Error number %d\n", r);
- goto error;
- }
+ usb = &zd_netdev_mac(netdev)->chip.usb;
+ usb->is_zd1211b = (id->driver_info == DEVICE_ZD1211B) != 0;
- r = usb_reset_configuration(udev);
- if (r) {
- dev_dbg_f(&intf->dev,
- "couldn't reset configuration. Error number %d\n", r);
- goto error;
- }
-
- /* At this point the interrupt endpoint is not generally enabled. We
- * save the USB bandwidth until the network device is opened. But
- * notify that the initialization of the MAC will require the
- * interrupts to be temporary enabled.
- */
- r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info);
+ r = zd_mac_preinit_hw(zd_netdev_mac(netdev));
if (r) {
dev_dbg_f(&intf->dev,
"couldn't initialize mac. Error number %d\n", r);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 506ea6a74393..961a7a12ad68 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -188,6 +188,7 @@ struct zd_usb {
struct zd_usb_rx rx;
struct zd_usb_tx tx;
struct usb_interface *intf;
+ u8 is_zd1211b:1, initialized:1;
};
#define zd_usb_dev(usb) (&usb->intf->dev)
@@ -236,6 +237,8 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
+int zd_usb_read_fw(struct zd_usb *usb, zd_addr_t addr, u8 *data, u16 len);
+
extern struct workqueue_struct *zd_workqueue;
#endif /* _ZD_USB_H */
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
new file mode 100644
index 000000000000..489f69c5d6ca
--- /dev/null
+++ b/drivers/net/xen-netfront.c
@@ -0,0 +1,1863 @@
+/*
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, XenSource 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; 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/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <net/ip.h>
+
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <xen/interface/io/netif.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/grant_table.h>
+
+static struct ethtool_ops xennet_ethtool_ops;
+
+struct netfront_cb {
+ struct page *page;
+ unsigned offset;
+};
+
+#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb))
+
+#define RX_COPY_THRESHOLD 256
+
+#define GRANT_INVALID_REF 0
+
+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+
+struct netfront_info {
+ struct list_head list;
+ struct net_device *netdev;
+
+ struct net_device_stats stats;
+
+ struct xen_netif_tx_front_ring tx;
+ struct xen_netif_rx_front_ring rx;
+
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+
+ unsigned int evtchn;
+
+ /* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+ unsigned rx_min_target, rx_max_target, rx_target;
+ struct sk_buff_head rx_batch;
+
+ struct timer_list rx_refill_timer;
+
+ /*
+ * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
+ * are linked from tx_skb_freelist through skb_entry.link.
+ *
+ * NB. Freelist index entries are always going to be less than
+ * PAGE_OFFSET, whereas pointers to skbs will always be equal or
+ * greater than PAGE_OFFSET: we use this property to distinguish
+ * them.
+ */
+ union skb_entry {
+ struct sk_buff *skb;
+ unsigned link;
+ } tx_skbs[NET_TX_RING_SIZE];
+ grant_ref_t gref_tx_head;
+ grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+ unsigned tx_skb_freelist;
+
+ struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
+ grant_ref_t gref_rx_head;
+ grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
+ struct xenbus_device *xbdev;
+ int tx_ring_ref;
+ int rx_ring_ref;
+
+ unsigned long rx_pfn_array[NET_RX_RING_SIZE];
+ struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
+ struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+};
+
+struct netfront_rx_info {
+ struct xen_netif_rx_response rx;
+ struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+};
+
+/*
+ * Access macros for acquiring freeing slots in tx_skbs[].
+ */
+
+static void add_id_to_freelist(unsigned *head, union skb_entry *list,
+ unsigned short id)
+{
+ list[id].link = *head;
+ *head = id;
+}
+
+static unsigned short get_id_from_freelist(unsigned *head,
+ union skb_entry *list)
+{
+ unsigned int id = *head;
+ *head = list[id].link;
+ return id;
+}
+
+static int xennet_rxidx(RING_IDX idx)
+{
+ return idx & (NET_RX_RING_SIZE - 1);
+}
+
+static struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
+ RING_IDX ri)
+{
+ int i = xennet_rxidx(ri);
+ struct sk_buff *skb = np->rx_skbs[i];
+ np->rx_skbs[i] = NULL;
+ return skb;
+}
+
+static grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
+ RING_IDX ri)
+{
+ int i = xennet_rxidx(ri);
+ grant_ref_t ref = np->grant_rx_ref[i];
+ np->grant_rx_ref[i] = GRANT_INVALID_REF;
+ return ref;
+}
+
+#ifdef CONFIG_SYSFS
+static int xennet_sysfs_addif(struct net_device *netdev);
+static void xennet_sysfs_delif(struct net_device *netdev);
+#else /* !CONFIG_SYSFS */
+#define xennet_sysfs_addif(dev) (0)
+#define xennet_sysfs_delif(dev) do { } while (0)
+#endif
+
+static int xennet_can_sg(struct net_device *dev)
+{
+ return dev->features & NETIF_F_SG;
+}
+
+
+static void rx_refill_timeout(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ netif_rx_schedule(dev);
+}
+
+static int netfront_tx_slot_available(struct netfront_info *np)
+{
+ return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
+ (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
+}
+
+static void xennet_maybe_wake_tx(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+
+ if (unlikely(netif_queue_stopped(dev)) &&
+ netfront_tx_slot_available(np) &&
+ likely(netif_running(dev)))
+ netif_wake_queue(dev);
+}
+
+static void xennet_alloc_rx_buffers(struct net_device *dev)
+{
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct page *page;
+ int i, batch_target, notify;
+ RING_IDX req_prod = np->rx.req_prod_pvt;
+ struct xen_memory_reservation reservation;
+ grant_ref_t ref;
+ unsigned long pfn;
+ void *vaddr;
+ int nr_flips;
+ struct xen_netif_rx_request *req;
+
+ if (unlikely(!netif_carrier_ok(dev)))
+ return;
+
+ /*
+ * Allocate skbuffs greedily, even though we batch updates to the
+ * receive ring. This creates a less bursty demand on the memory
+ * allocator, so should reduce the chance of failed allocation requests
+ * both for ourself and for other kernel subsystems.
+ */
+ batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
+ for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
+ skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD,
+ GFP_ATOMIC | __GFP_NOWARN);
+ if (unlikely(!skb))
+ goto no_skb;
+
+ page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+ if (!page) {
+ kfree_skb(skb);
+no_skb:
+ /* Any skbuffs queued for refill? Force them out. */
+ if (i != 0)
+ goto refill;
+ /* Could not allocate any skbuffs. Try again later. */
+ mod_timer(&np->rx_refill_timer,
+ jiffies + (HZ/10));
+ break;
+ }
+
+ skb_shinfo(skb)->frags[0].page = page;
+ skb_shinfo(skb)->nr_frags = 1;
+ __skb_queue_tail(&np->rx_batch, skb);
+ }
+
+ /* Is the batch large enough to be worthwhile? */
+ if (i < (np->rx_target/2)) {
+ if (req_prod > np->rx.sring->req_prod)
+ goto push;
+ return;
+ }
+
+ /* Adjust our fill target if we risked running out of buffers. */
+ if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
+ ((np->rx_target *= 2) > np->rx_max_target))
+ np->rx_target = np->rx_max_target;
+
+ refill:
+ for (nr_flips = i = 0; ; i++) {
+ skb = __skb_dequeue(&np->rx_batch);
+ if (skb == NULL)
+ break;
+
+ skb->dev = dev;
+
+ id = xennet_rxidx(req_prod + i);
+
+ BUG_ON(np->rx_skbs[id]);
+ np->rx_skbs[id] = skb;
+
+ ref = gnttab_claim_grant_reference(&np->gref_rx_head);
+ BUG_ON((signed short)ref < 0);
+ np->grant_rx_ref[id] = ref;
+
+ pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
+ vaddr = page_address(skb_shinfo(skb)->frags[0].page);
+
+ req = RING_GET_REQUEST(&np->rx, req_prod + i);
+ gnttab_grant_foreign_access_ref(ref,
+ np->xbdev->otherend_id,
+ pfn_to_mfn(pfn),
+ 0);
+
+ req->id = id;
+ req->gref = ref;
+ }
+
+ if (nr_flips != 0) {
+ reservation.extent_start = np->rx_pfn_array;
+ reservation.nr_extents = nr_flips;
+ reservation.extent_order = 0;
+ reservation.address_bits = 0;
+ reservation.domid = DOMID_SELF;
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* After all PTEs have been zapped, flush the TLB. */
+ np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
+ UVMF_TLB_FLUSH|UVMF_ALL;
+
+ /* Give away a batch of pages. */
+ np->rx_mcl[i].op = __HYPERVISOR_memory_op;
+ np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
+ np->rx_mcl[i].args[1] = (unsigned long)&reservation;
+
+ /* Zap PTEs and give away pages in one big
+ * multicall. */
+ (void)HYPERVISOR_multicall(np->rx_mcl, i+1);
+
+ /* Check return status of HYPERVISOR_memory_op(). */
+ if (unlikely(np->rx_mcl[i].result != i))
+ panic("Unable to reduce memory reservation\n");
+ } else {
+ if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
+ &reservation) != i)
+ panic("Unable to reduce memory reservation\n");
+ }
+ } else {
+ wmb(); /* barrier so backend seens requests */
+ }
+
+ /* Above is a suitable barrier to ensure backend will see requests. */
+ np->rx.req_prod_pvt = req_prod + i;
+ push:
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+ if (notify)
+ notify_remote_via_irq(np->netdev->irq);
+}
+
+static int xennet_open(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+
+ memset(&np->stats, 0, sizeof(np->stats));
+
+ spin_lock_bh(&np->rx_lock);
+ if (netif_carrier_ok(dev)) {
+ xennet_alloc_rx_buffers(dev);
+ np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
+ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+ netif_rx_schedule(dev);
+ }
+ spin_unlock_bh(&np->rx_lock);
+
+ xennet_maybe_wake_tx(dev);
+
+ return 0;
+}
+
+static void xennet_tx_buf_gc(struct net_device *dev)
+{
+ RING_IDX cons, prod;
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+
+ BUG_ON(!netif_carrier_ok(dev));
+
+ do {
+ prod = np->tx.sring->rsp_prod;
+ rmb(); /* Ensure we see responses up to 'rp'. */
+
+ for (cons = np->tx.rsp_cons; cons != prod; cons++) {
+ struct xen_netif_tx_response *txrsp;
+
+ txrsp = RING_GET_RESPONSE(&np->tx, cons);
+ if (txrsp->status == NETIF_RSP_NULL)
+ continue;
+
+ id = txrsp->id;
+ skb = np->tx_skbs[id].skb;
+ if (unlikely(gnttab_query_foreign_access(
+ np->grant_tx_ref[id]) != 0)) {
+ printk(KERN_ALERT "xennet_tx_buf_gc: warning "
+ "-- grant still in use by backend "
+ "domain.\n");
+ BUG();
+ }
+ gnttab_end_foreign_access_ref(
+ np->grant_tx_ref[id], GNTMAP_readonly);
+ gnttab_release_grant_reference(
+ &np->gref_tx_head, np->grant_tx_ref[id]);
+ np->grant_tx_ref[id] = GRANT_INVALID_REF;
+ add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
+ dev_kfree_skb_irq(skb);
+ }
+
+ np->tx.rsp_cons = prod;
+
+ /*
+ * Set a new event, then check for race with update of tx_cons.
+ * Note that it is essential to schedule a callback, no matter
+ * how few buffers are pending. Even if there is space in the
+ * transmit ring, higher layers may be blocked because too much
+ * data is outstanding: in such cases notification from Xen is
+ * likely to be the only kick that we'll get.
+ */
+ np->tx.sring->rsp_event =
+ prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
+ mb(); /* update shared area */
+ } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
+
+ xennet_maybe_wake_tx(dev);
+}
+
+static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
+ struct xen_netif_tx_request *tx)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ char *data = skb->data;
+ unsigned long mfn;
+ RING_IDX prod = np->tx.req_prod_pvt;
+ int frags = skb_shinfo(skb)->nr_frags;
+ unsigned int offset = offset_in_page(data);
+ unsigned int len = skb_headlen(skb);
+ unsigned int id;
+ grant_ref_t ref;
+ int i;
+
+ /* While the header overlaps a page boundary (including being
+ larger than a page), split it it into page-sized chunks. */
+ while (len > PAGE_SIZE - offset) {
+ tx->size = PAGE_SIZE - offset;
+ tx->flags |= NETTXF_more_data;
+ len -= tx->size;
+ data += tx->size;
+ offset = 0;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+ tx = RING_GET_REQUEST(&np->tx, prod++);
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+
+ mfn = virt_to_mfn(data);
+ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+ mfn, GNTMAP_readonly);
+
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = offset;
+ tx->size = len;
+ tx->flags = 0;
+ }
+
+ /* Grant backend access to each skb fragment page. */
+ for (i = 0; i < frags; i++) {
+ skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+ tx->flags |= NETTXF_more_data;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb_get(skb);
+ tx = RING_GET_REQUEST(&np->tx, prod++);
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+
+ mfn = pfn_to_mfn(page_to_pfn(frag->page));
+ gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+ mfn, GNTMAP_readonly);
+
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = frag->page_offset;
+ tx->size = frag->size;
+ tx->flags = 0;
+ }
+
+ np->tx.req_prod_pvt = prod;
+}
+
+static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ unsigned short id;
+ struct netfront_info *np = netdev_priv(dev);
+ struct xen_netif_tx_request *tx;
+ struct xen_netif_extra_info *extra;
+ char *data = skb->data;
+ RING_IDX i;
+ grant_ref_t ref;
+ unsigned long mfn;
+ int notify;
+ int frags = skb_shinfo(skb)->nr_frags;
+ unsigned int offset = offset_in_page(data);
+ unsigned int len = skb_headlen(skb);
+
+ frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+ if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
+ printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
+ frags);
+ dump_stack();
+ goto drop;
+ }
+
+ spin_lock_irq(&np->tx_lock);
+
+ if (unlikely(!netif_carrier_ok(dev) ||
+ (frags > 1 && !xennet_can_sg(dev)) ||
+ netif_needs_gso(dev, skb))) {
+ spin_unlock_irq(&np->tx_lock);
+ goto drop;
+ }
+
+ i = np->tx.req_prod_pvt;
+
+ id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+ np->tx_skbs[id].skb = skb;
+
+ tx = RING_GET_REQUEST(&np->tx, i);
+
+ tx->id = id;
+ ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
+ mfn = virt_to_mfn(data);
+ gnttab_grant_foreign_access_ref(
+ ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+ tx->gref = np->grant_tx_ref[id] = ref;
+ tx->offset = offset;
+ tx->size = len;
+ extra = NULL;
+
+ tx->flags = 0;
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ /* local packet? */
+ tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
+ else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+ /* remote but checksummed. */
+ tx->flags |= NETTXF_data_validated;
+
+ if (skb_shinfo(skb)->gso_size) {
+ struct xen_netif_extra_info *gso;
+
+ gso = (struct xen_netif_extra_info *)
+ RING_GET_REQUEST(&np->tx, ++i);
+
+ if (extra)
+ extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+ else
+ tx->flags |= NETTXF_extra_info;
+
+ gso->u.gso.size = skb_shinfo(skb)->gso_size;
+ gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+ gso->u.gso.pad = 0;
+ gso->u.gso.features = 0;
+
+ gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+ gso->flags = 0;
+ extra = gso;
+ }
+
+ np->tx.req_prod_pvt = i + 1;
+
+ xennet_make_frags(skb, dev, tx);
+ tx->size = skb->len;
+
+ RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
+ if (notify)
+ notify_remote_via_irq(np->netdev->irq);
+
+ xennet_tx_buf_gc(dev);
+
+ if (!netfront_tx_slot_available(np))
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&np->tx_lock);
+
+ np->stats.tx_bytes += skb->len;
+ np->stats.tx_packets++;
+
+ return 0;
+
+ drop:
+ np->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static int xennet_close(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ netif_stop_queue(np->netdev);
+ return 0;
+}
+
+static struct net_device_stats *xennet_get_stats(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ return &np->stats;
+}
+
+static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
+ grant_ref_t ref)
+{
+ int new = xennet_rxidx(np->rx.req_prod_pvt);
+
+ BUG_ON(np->rx_skbs[new]);
+ np->rx_skbs[new] = skb;
+ np->grant_rx_ref[new] = ref;
+ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
+ RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
+ np->rx.req_prod_pvt++;
+}
+
+static int xennet_get_extras(struct netfront_info *np,
+ struct xen_netif_extra_info *extras,
+ RING_IDX rp)
+
+{
+ struct xen_netif_extra_info *extra;
+ struct device *dev = &np->netdev->dev;
+ RING_IDX cons = np->rx.rsp_cons;
+ int err = 0;
+
+ do {
+ struct sk_buff *skb;
+ grant_ref_t ref;
+
+ if (unlikely(cons + 1 == rp)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Missing extra info\n");
+ err = -EBADR;
+ break;
+ }
+
+ extra = (struct xen_netif_extra_info *)
+ RING_GET_RESPONSE(&np->rx, ++cons);
+
+ if (unlikely(!extra->type ||
+ extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Invalid extra type: %d\n",
+ extra->type);
+ err = -EINVAL;
+ } else {
+ memcpy(&extras[extra->type - 1], extra,
+ sizeof(*extra));
+ }
+
+ skb = xennet_get_rx_skb(np, cons);
+ ref = xennet_get_rx_ref(np, cons);
+ xennet_move_rx_slot(np, skb, ref);
+ } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+ np->rx.rsp_cons = cons;
+ return err;
+}
+
+static int xennet_get_responses(struct netfront_info *np,
+ struct netfront_rx_info *rinfo, RING_IDX rp,
+ struct sk_buff_head *list)
+{
+ struct xen_netif_rx_response *rx = &rinfo->rx;
+ struct xen_netif_extra_info *extras = rinfo->extras;
+ struct device *dev = &np->netdev->dev;
+ RING_IDX cons = np->rx.rsp_cons;
+ struct sk_buff *skb = xennet_get_rx_skb(np, cons);
+ grant_ref_t ref = xennet_get_rx_ref(np, cons);
+ int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+ int frags = 1;
+ int err = 0;
+ unsigned long ret;
+
+ if (rx->flags & NETRXF_extra_info) {
+ err = xennet_get_extras(np, extras, rp);
+ cons = np->rx.rsp_cons;
+ }
+
+ for (;;) {
+ if (unlikely(rx->status < 0 ||
+ rx->offset + rx->status > PAGE_SIZE)) {
+ if (net_ratelimit())
+ dev_warn(dev, "rx->offset: %x, size: %u\n",
+ rx->offset, rx->status);
+ xennet_move_rx_slot(np, skb, ref);
+ err = -EINVAL;
+ goto next;
+ }
+
+ /*
+ * This definitely indicates a bug, either in this driver or in
+ * the backend driver. In future this should flag the bad
+ * situation to the system controller to reboot the backed.
+ */
+ if (ref == GRANT_INVALID_REF) {
+ if (net_ratelimit())
+ dev_warn(dev, "Bad rx response id %d.\n",
+ rx->id);
+ err = -EINVAL;
+ goto next;
+ }
+
+ ret = gnttab_end_foreign_access_ref(ref, 0);
+ BUG_ON(!ret);
+
+ gnttab_release_grant_reference(&np->gref_rx_head, ref);
+
+ __skb_queue_tail(list, skb);
+
+next:
+ if (!(rx->flags & NETRXF_more_data))
+ break;
+
+ if (cons + frags == rp) {
+ if (net_ratelimit())
+ dev_warn(dev, "Need more frags\n");
+ err = -ENOENT;
+ break;
+ }
+
+ rx = RING_GET_RESPONSE(&np->rx, cons + frags);
+ skb = xennet_get_rx_skb(np, cons + frags);
+ ref = xennet_get_rx_ref(np, cons + frags);
+ frags++;
+ }
+
+ if (unlikely(frags > max)) {
+ if (net_ratelimit())
+ dev_warn(dev, "Too many frags\n");
+ err = -E2BIG;
+ }
+
+ if (unlikely(err))
+ np->rx.rsp_cons = cons + frags;
+
+ return err;
+}
+
+static int xennet_set_skb_gso(struct sk_buff *skb,
+ struct xen_netif_extra_info *gso)
+{
+ if (!gso->u.gso.size) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "GSO size must not be zero.\n");
+ return -EINVAL;
+ }
+
+ /* Currently only TCPv4 S.O. is supported. */
+ if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "Bad GSO type %d.\n", gso->u.gso.type);
+ return -EINVAL;
+ }
+
+ skb_shinfo(skb)->gso_size = gso->u.gso.size;
+ skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+ /* Header must be checked, and gso_segs computed. */
+ skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+ skb_shinfo(skb)->gso_segs = 0;
+
+ return 0;
+}
+
+static RING_IDX xennet_fill_frags(struct netfront_info *np,
+ struct sk_buff *skb,
+ struct sk_buff_head *list)
+{
+ struct skb_shared_info *shinfo = skb_shinfo(skb);
+ int nr_frags = shinfo->nr_frags;
+ RING_IDX cons = np->rx.rsp_cons;
+ skb_frag_t *frag = shinfo->frags + nr_frags;
+ struct sk_buff *nskb;
+
+ while ((nskb = __skb_dequeue(list))) {
+ struct xen_netif_rx_response *rx =
+ RING_GET_RESPONSE(&np->rx, ++cons);
+
+ frag->page = skb_shinfo(nskb)->frags[0].page;
+ frag->page_offset = rx->offset;
+ frag->size = rx->status;
+
+ skb->data_len += rx->status;
+
+ skb_shinfo(nskb)->nr_frags = 0;
+ kfree_skb(nskb);
+
+ frag++;
+ nr_frags++;
+ }
+
+ shinfo->nr_frags = nr_frags;
+ return cons;
+}
+
+static int skb_checksum_setup(struct sk_buff *skb)
+{
+ struct iphdr *iph;
+ unsigned char *th;
+ int err = -EPROTO;
+
+ if (skb->protocol != htons(ETH_P_IP))
+ goto out;
+
+ iph = (void *)skb->data;
+ th = skb->data + 4 * iph->ihl;
+ if (th >= skb_tail_pointer(skb))
+ goto out;
+
+ skb->csum_start = th - skb->head;
+ switch (iph->protocol) {
+ case IPPROTO_TCP:
+ skb->csum_offset = offsetof(struct tcphdr, check);
+ break;
+ case IPPROTO_UDP:
+ skb->csum_offset = offsetof(struct udphdr, check);
+ break;
+ default:
+ if (net_ratelimit())
+ printk(KERN_ERR "Attempting to checksum a non-"
+ "TCP/UDP packet, dropping a protocol"
+ " %d packet", iph->protocol);
+ goto out;
+ }
+
+ if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
+ goto out;
+
+ err = 0;
+
+out:
+ return err;
+}
+
+static int handle_incoming_queue(struct net_device *dev,
+ struct sk_buff_head *rxq)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ int packets_dropped = 0;
+ struct sk_buff *skb;
+
+ while ((skb = __skb_dequeue(rxq)) != NULL) {
+ struct page *page = NETFRONT_SKB_CB(skb)->page;
+ void *vaddr = page_address(page);
+ unsigned offset = NETFRONT_SKB_CB(skb)->offset;
+
+ memcpy(skb->data, vaddr + offset,
+ skb_headlen(skb));
+
+ if (page != skb_shinfo(skb)->frags[0].page)
+ __free_page(page);
+
+ /* Ethernet work: Delayed to here as it peeks the header. */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (skb_checksum_setup(skb)) {
+ kfree_skb(skb);
+ packets_dropped++;
+ np->stats.rx_errors++;
+ continue;
+ }
+ }
+
+ np->stats.rx_packets++;
+ np->stats.rx_bytes += skb->len;
+
+ /* Pass it up. */
+ netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ }
+
+ return packets_dropped;
+}
+
+static int xennet_poll(struct net_device *dev, int *pbudget)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ struct sk_buff *skb;
+ struct netfront_rx_info rinfo;
+ struct xen_netif_rx_response *rx = &rinfo.rx;
+ struct xen_netif_extra_info *extras = rinfo.extras;
+ RING_IDX i, rp;
+ int work_done, budget, more_to_do = 1;
+ struct sk_buff_head rxq;
+ struct sk_buff_head errq;
+ struct sk_buff_head tmpq;
+ unsigned long flags;
+ unsigned int len;
+ int err;
+
+ spin_lock(&np->rx_lock);
+
+ if (unlikely(!netif_carrier_ok(dev))) {
+ spin_unlock(&np->rx_lock);
+ return 0;
+ }
+
+ skb_queue_head_init(&rxq);
+ skb_queue_head_init(&errq);
+ skb_queue_head_init(&tmpq);
+
+ budget = *pbudget;
+ if (budget > dev->quota)
+ budget = dev->quota;
+ rp = np->rx.sring->rsp_prod;
+ rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+ i = np->rx.rsp_cons;
+ work_done = 0;
+ while ((i != rp) && (work_done < budget)) {
+ memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
+ memset(extras, 0, sizeof(rinfo.extras));
+
+ err = xennet_get_responses(np, &rinfo, rp, &tmpq);
+
+ if (unlikely(err)) {
+err:
+ while ((skb = __skb_dequeue(&tmpq)))
+ __skb_queue_tail(&errq, skb);
+ np->stats.rx_errors++;
+ i = np->rx.rsp_cons;
+ continue;
+ }
+
+ skb = __skb_dequeue(&tmpq);
+
+ if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+ struct xen_netif_extra_info *gso;
+ gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
+ if (unlikely(xennet_set_skb_gso(skb, gso))) {
+ __skb_queue_head(&tmpq, skb);
+ np->rx.rsp_cons += skb_queue_len(&tmpq);
+ goto err;
+ }
+ }
+
+ NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
+ NETFRONT_SKB_CB(skb)->offset = rx->offset;
+
+ len = rx->status;
+ if (len > RX_COPY_THRESHOLD)
+ len = RX_COPY_THRESHOLD;
+ skb_put(skb, len);
+
+ if (rx->status > len) {
+ skb_shinfo(skb)->frags[0].page_offset =
+ rx->offset + len;
+ skb_shinfo(skb)->frags[0].size = rx->status - len;
+ skb->data_len = rx->status - len;
+ } else {
+ skb_shinfo(skb)->frags[0].page = NULL;
+ skb_shinfo(skb)->nr_frags = 0;
+ }
+
+ i = xennet_fill_frags(np, skb, &tmpq);
+
+ /*
+ * Truesize approximates the size of true data plus
+ * any supervisor overheads. Adding hypervisor
+ * overheads has been shown to significantly reduce
+ * achievable bandwidth with the default receive
+ * buffer size. It is therefore not wise to account
+ * for it here.
+ *
+ * After alloc_skb(RX_COPY_THRESHOLD), truesize is set
+ * to RX_COPY_THRESHOLD + the supervisor
+ * overheads. Here, we add the size of the data pulled
+ * in xennet_fill_frags().
+ *
+ * We also adjust for any unused space in the main
+ * data area by subtracting (RX_COPY_THRESHOLD -
+ * len). This is especially important with drivers
+ * which split incoming packets into header and data,
+ * using only 66 bytes of the main data area (see the
+ * e1000 driver for example.) On such systems,
+ * without this last adjustement, our achievable
+ * receive throughout using the standard receive
+ * buffer size was cut by 25%(!!!).
+ */
+ skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
+ skb->len += skb->data_len;
+
+ if (rx->flags & NETRXF_csum_blank)
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ else if (rx->flags & NETRXF_data_validated)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ __skb_queue_tail(&rxq, skb);
+
+ np->rx.rsp_cons = ++i;
+ work_done++;
+ }
+
+ while ((skb = __skb_dequeue(&errq)))
+ kfree_skb(skb);
+
+ work_done -= handle_incoming_queue(dev, &rxq);
+
+ /* If we get a callback with very few responses, reduce fill target. */
+ /* NB. Note exponential increase, linear decrease. */
+ if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
+ ((3*np->rx_target) / 4)) &&
+ (--np->rx_target < np->rx_min_target))
+ np->rx_target = np->rx_min_target;
+
+ xennet_alloc_rx_buffers(dev);
+
+ *pbudget -= work_done;
+ dev->quota -= work_done;
+
+ if (work_done < budget) {
+ local_irq_save(flags);
+
+ RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
+ if (!more_to_do)
+ __netif_rx_complete(dev);
+
+ local_irq_restore(flags);
+ }
+
+ spin_unlock(&np->rx_lock);
+
+ return more_to_do;
+}
+
+static int xennet_change_mtu(struct net_device *dev, int mtu)
+{
+ int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+ if (mtu > max)
+ return -EINVAL;
+ dev->mtu = mtu;
+ return 0;
+}
+
+static void xennet_release_tx_bufs(struct netfront_info *np)
+{
+ struct sk_buff *skb;
+ int i;
+
+ for (i = 0; i < NET_TX_RING_SIZE; i++) {
+ /* Skip over entries which are actually freelist references */
+ if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET)
+ continue;
+
+ skb = np->tx_skbs[i].skb;
+ gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
+ GNTMAP_readonly);
+ gnttab_release_grant_reference(&np->gref_tx_head,
+ np->grant_tx_ref[i]);
+ np->grant_tx_ref[i] = GRANT_INVALID_REF;
+ add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
+ dev_kfree_skb_irq(skb);
+ }
+}
+
+static void xennet_release_rx_bufs(struct netfront_info *np)
+{
+ struct mmu_update *mmu = np->rx_mmu;
+ struct multicall_entry *mcl = np->rx_mcl;
+ struct sk_buff_head free_list;
+ struct sk_buff *skb;
+ unsigned long mfn;
+ int xfer = 0, noxfer = 0, unused = 0;
+ int id, ref;
+
+ dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
+ __func__);
+ return;
+
+ skb_queue_head_init(&free_list);
+
+ spin_lock_bh(&np->rx_lock);
+
+ for (id = 0; id < NET_RX_RING_SIZE; id++) {
+ ref = np->grant_rx_ref[id];
+ if (ref == GRANT_INVALID_REF) {
+ unused++;
+ continue;
+ }
+
+ skb = np->rx_skbs[id];
+ mfn = gnttab_end_foreign_transfer_ref(ref);
+ gnttab_release_grant_reference(&np->gref_rx_head, ref);
+ np->grant_rx_ref[id] = GRANT_INVALID_REF;
+
+ if (0 == mfn) {
+ skb_shinfo(skb)->nr_frags = 0;
+ dev_kfree_skb(skb);
+ noxfer++;
+ continue;
+ }
+
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* Remap the page. */
+ struct page *page = skb_shinfo(skb)->frags[0].page;
+ unsigned long pfn = page_to_pfn(page);
+ void *vaddr = page_address(page);
+
+ MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
+ mfn_pte(mfn, PAGE_KERNEL),
+ 0);
+ mcl++;
+ mmu->ptr = ((u64)mfn << PAGE_SHIFT)
+ | MMU_MACHPHYS_UPDATE;
+ mmu->val = pfn;
+ mmu++;
+
+ set_phys_to_machine(pfn, mfn);
+ }
+ __skb_queue_tail(&free_list, skb);
+ xfer++;
+ }
+
+ dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
+ __func__, xfer, noxfer, unused);
+
+ if (xfer) {
+ if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+ /* Do all the remapping work and M2P updates. */
+ MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
+ 0, DOMID_SELF);
+ mcl++;
+ HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
+ }
+ }
+
+ while ((skb = __skb_dequeue(&free_list)) != NULL)
+ dev_kfree_skb(skb);
+
+ spin_unlock_bh(&np->rx_lock);
+}
+
+static void xennet_uninit(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ xennet_release_tx_bufs(np);
+ xennet_release_rx_bufs(np);
+ gnttab_free_grant_references(np->gref_tx_head);
+ gnttab_free_grant_references(np->gref_rx_head);
+}
+
+static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
+{
+ int i, err;
+ struct net_device *netdev;
+ struct netfront_info *np;
+
+ netdev = alloc_etherdev(sizeof(struct netfront_info));
+ if (!netdev) {
+ printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
+ __func__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ np = netdev_priv(netdev);
+ np->xbdev = dev;
+
+ spin_lock_init(&np->tx_lock);
+ spin_lock_init(&np->rx_lock);
+
+ skb_queue_head_init(&np->rx_batch);
+ np->rx_target = RX_DFL_MIN_TARGET;
+ np->rx_min_target = RX_DFL_MIN_TARGET;
+ np->rx_max_target = RX_MAX_TARGET;
+
+ init_timer(&np->rx_refill_timer);
+ np->rx_refill_timer.data = (unsigned long)netdev;
+ np->rx_refill_timer.function = rx_refill_timeout;
+
+ /* Initialise tx_skbs as a free chain containing every entry. */
+ np->tx_skb_freelist = 0;
+ for (i = 0; i < NET_TX_RING_SIZE; i++) {
+ np->tx_skbs[i].link = i+1;
+ np->grant_tx_ref[i] = GRANT_INVALID_REF;
+ }
+
+ /* Clear out rx_skbs */
+ for (i = 0; i < NET_RX_RING_SIZE; i++) {
+ np->rx_skbs[i] = NULL;
+ np->grant_rx_ref[i] = GRANT_INVALID_REF;
+ }
+
+ /* A grant for every tx ring slot */
+ if (gnttab_alloc_grant_references(TX_MAX_TARGET,
+ &np->gref_tx_head) < 0) {
+ printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+ /* A grant for every rx ring slot */
+ if (gnttab_alloc_grant_references(RX_MAX_TARGET,
+ &np->gref_rx_head) < 0) {
+ printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
+ err = -ENOMEM;
+ goto exit_free_tx;
+ }
+
+ netdev->open = xennet_open;
+ netdev->hard_start_xmit = xennet_start_xmit;
+ netdev->stop = xennet_close;
+ netdev->get_stats = xennet_get_stats;
+ netdev->poll = xennet_poll;
+ netdev->uninit = xennet_uninit;
+ netdev->change_mtu = xennet_change_mtu;
+ netdev->weight = 64;
+ netdev->features = NETIF_F_IP_CSUM;
+
+ SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &dev->dev);
+
+ np->netdev = netdev;
+
+ netif_carrier_off(netdev);
+
+ return netdev;
+
+ exit_free_tx:
+ gnttab_free_grant_references(np->gref_tx_head);
+ exit:
+ free_netdev(netdev);
+ return ERR_PTR(err);
+}
+
+/**
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures and the ring buffers for communication with the backend, and
+ * inform the backend of the appropriate details for those.
+ */
+static int __devinit netfront_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err;
+ struct net_device *netdev;
+ struct netfront_info *info;
+
+ netdev = xennet_create_dev(dev);
+ if (IS_ERR(netdev)) {
+ err = PTR_ERR(netdev);
+ xenbus_dev_fatal(dev, err, "creating netdev");
+ return err;
+ }
+
+ info = netdev_priv(netdev);
+ dev->dev.driver_data = info;
+
+ err = register_netdev(info->netdev);
+ if (err) {
+ printk(KERN_WARNING "%s: register_netdev err=%d\n",
+ __func__, err);
+ goto fail;
+ }
+
+ err = xennet_sysfs_addif(info->netdev);
+ if (err) {
+ unregister_netdev(info->netdev);
+ printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
+ __func__, err);
+ goto fail;
+ }
+
+ return 0;
+
+ fail:
+ free_netdev(netdev);
+ dev->dev.driver_data = NULL;
+ return err;
+}
+
+static void xennet_end_access(int ref, void *page)
+{
+ /* This frees the page as a side-effect */
+ if (ref != GRANT_INVALID_REF)
+ gnttab_end_foreign_access(ref, 0, (unsigned long)page);
+}
+
+static void xennet_disconnect_backend(struct netfront_info *info)
+{
+ /* Stop old i/f to prevent errors whilst we rebuild the state. */
+ spin_lock_bh(&info->rx_lock);
+ spin_lock_irq(&info->tx_lock);
+ netif_carrier_off(info->netdev);
+ spin_unlock_irq(&info->tx_lock);
+ spin_unlock_bh(&info->rx_lock);
+
+ if (info->netdev->irq)
+ unbind_from_irqhandler(info->netdev->irq, info->netdev);
+ info->evtchn = info->netdev->irq = 0;
+
+ /* End access and free the pages */
+ xennet_end_access(info->tx_ring_ref, info->tx.sring);
+ xennet_end_access(info->rx_ring_ref, info->rx.sring);
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->tx.sring = NULL;
+ info->rx.sring = NULL;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart. We tear down our netif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int netfront_resume(struct xenbus_device *dev)
+{
+ struct netfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+ xennet_disconnect_backend(info);
+ return 0;
+}
+
+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+{
+ char *s, *e, *macstr;
+ int i;
+
+ macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
+ if (IS_ERR(macstr))
+ return PTR_ERR(macstr);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ mac[i] = simple_strtoul(s, &e, 16);
+ if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
+ kfree(macstr);
+ return -ENOENT;
+ }
+ s = e+1;
+ }
+
+ kfree(macstr);
+ return 0;
+}
+
+static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct netfront_info *np = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&np->tx_lock, flags);
+
+ if (likely(netif_carrier_ok(dev))) {
+ xennet_tx_buf_gc(dev);
+ /* Under tx_lock: protects access to rx shared-ring indexes. */
+ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+ netif_rx_schedule(dev);
+ }
+
+ spin_unlock_irqrestore(&np->tx_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
+{
+ struct xen_netif_tx_sring *txs;
+ struct xen_netif_rx_sring *rxs;
+ int err;
+ struct net_device *netdev = info->netdev;
+
+ info->tx_ring_ref = GRANT_INVALID_REF;
+ info->rx_ring_ref = GRANT_INVALID_REF;
+ info->rx.sring = NULL;
+ info->tx.sring = NULL;
+ netdev->irq = 0;
+
+ err = xen_net_read_mac(dev, netdev->dev_addr);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+ goto fail;
+ }
+
+ txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
+ if (!txs) {
+ err = -ENOMEM;
+ xenbus_dev_fatal(dev, err, "allocating tx ring page");
+ goto fail;
+ }
+ SHARED_RING_INIT(txs);
+ FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(txs));
+ if (err < 0) {
+ free_page((unsigned long)txs);
+ goto fail;
+ }
+
+ info->tx_ring_ref = err;
+ rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
+ if (!rxs) {
+ err = -ENOMEM;
+ xenbus_dev_fatal(dev, err, "allocating rx ring page");
+ goto fail;
+ }
+ SHARED_RING_INIT(rxs);
+ FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
+
+ err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
+ if (err < 0) {
+ free_page((unsigned long)rxs);
+ goto fail;
+ }
+ info->rx_ring_ref = err;
+
+ err = xenbus_alloc_evtchn(dev, &info->evtchn);
+ if (err)
+ goto fail;
+
+ err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
+ IRQF_SAMPLE_RANDOM, netdev->name,
+ netdev);
+ if (err < 0)
+ goto fail;
+ netdev->irq = err;
+ return 0;
+
+ fail:
+ return err;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+ struct netfront_info *info)
+{
+ const char *message;
+ struct xenbus_transaction xbt;
+ int err;
+
+ /* Create shared ring, alloc event channel. */
+ err = setup_netfront(dev, info);
+ if (err)
+ goto out;
+
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ goto destroy_ring;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u",
+ info->tx_ring_ref);
+ if (err) {
+ message = "writing tx ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u",
+ info->rx_ring_ref);
+ if (err) {
+ message = "writing rx ring-ref";
+ goto abort_transaction;
+ }
+ err = xenbus_printf(xbt, dev->nodename,
+ "event-channel", "%u", info->evtchn);
+ if (err) {
+ message = "writing event-channel";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
+ 1);
+ if (err) {
+ message = "writing request-rx-copy";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
+ if (err) {
+ message = "writing feature-rx-notify";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
+ if (err) {
+ message = "writing feature-sg";
+ goto abort_transaction;
+ }
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
+ if (err) {
+ message = "writing feature-gso-tcpv4";
+ goto abort_transaction;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err) {
+ if (err == -EAGAIN)
+ goto again;
+ xenbus_dev_fatal(dev, err, "completing transaction");
+ goto destroy_ring;
+ }
+
+ return 0;
+
+ abort_transaction:
+ xenbus_transaction_end(xbt, 1);
+ xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_ring:
+ xennet_disconnect_backend(info);
+ out:
+ return err;
+}
+
+static int xennet_set_sg(struct net_device *dev, u32 data)
+{
+ if (data) {
+ struct netfront_info *np = netdev_priv(dev);
+ int val;
+
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
+ "%d", &val) < 0)
+ val = 0;
+ if (!val)
+ return -ENOSYS;
+ } else if (dev->mtu > ETH_DATA_LEN)
+ dev->mtu = ETH_DATA_LEN;
+
+ return ethtool_op_set_sg(dev, data);
+}
+
+static int xennet_set_tso(struct net_device *dev, u32 data)
+{
+ if (data) {
+ struct netfront_info *np = netdev_priv(dev);
+ int val;
+
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-gso-tcpv4", "%d", &val) < 0)
+ val = 0;
+ if (!val)
+ return -ENOSYS;
+ }
+
+ return ethtool_op_set_tso(dev, data);
+}
+
+static void xennet_set_features(struct net_device *dev)
+{
+ /* Turn off all GSO bits except ROBUST. */
+ dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
+ dev->features |= NETIF_F_GSO_ROBUST;
+ xennet_set_sg(dev, 0);
+
+ /* We need checksum offload to enable scatter/gather and TSO. */
+ if (!(dev->features & NETIF_F_IP_CSUM))
+ return;
+
+ if (!xennet_set_sg(dev, 1))
+ xennet_set_tso(dev, 1);
+}
+
+static int xennet_connect(struct net_device *dev)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ int i, requeue_idx, err;
+ struct sk_buff *skb;
+ grant_ref_t ref;
+ struct xen_netif_rx_request *req;
+ unsigned int feature_rx_copy;
+
+ err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-rx-copy", "%u", &feature_rx_copy);
+ if (err != 1)
+ feature_rx_copy = 0;
+
+ if (!feature_rx_copy) {
+ dev_info(&dev->dev,
+ "backend does not support copying recieve path");
+ return -ENODEV;
+ }
+
+ err = talk_to_backend(np->xbdev, np);
+ if (err)
+ return err;
+
+ xennet_set_features(dev);
+
+ spin_lock_bh(&np->rx_lock);
+ spin_lock_irq(&np->tx_lock);
+
+ /* Step 1: Discard all pending TX packet fragments. */
+ xennet_release_tx_bufs(np);
+
+ /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
+ for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
+ if (!np->rx_skbs[i])
+ continue;
+
+ skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
+ ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
+ req = RING_GET_REQUEST(&np->rx, requeue_idx);
+
+ gnttab_grant_foreign_access_ref(
+ ref, np->xbdev->otherend_id,
+ pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
+ frags->page)),
+ 0);
+ req->gref = ref;
+ req->id = requeue_idx;
+
+ requeue_idx++;
+ }
+
+ np->rx.req_prod_pvt = requeue_idx;
+
+ /*
+ * Step 3: All public and private state should now be sane. Get
+ * ready to start sending and receiving packets and give the driver
+ * domain a kick because we've probably just requeued some
+ * packets.
+ */
+ netif_carrier_on(np->netdev);
+ notify_remote_via_irq(np->netdev->irq);
+ xennet_tx_buf_gc(dev);
+ xennet_alloc_rx_buffers(dev);
+
+ spin_unlock_irq(&np->tx_lock);
+ spin_unlock_bh(&np->rx_lock);
+
+ return 0;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+ enum xenbus_state backend_state)
+{
+ struct netfront_info *np = dev->dev.driver_data;
+ struct net_device *netdev = np->netdev;
+
+ dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
+
+ switch (backend_state) {
+ case XenbusStateInitialising:
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ case XenbusStateUnknown:
+ case XenbusStateClosed:
+ break;
+
+ case XenbusStateInitWait:
+ if (dev->state != XenbusStateInitialising)
+ break;
+ if (xennet_connect(netdev) != 0)
+ break;
+ xenbus_switch_state(dev, XenbusStateConnected);
+ break;
+
+ case XenbusStateClosing:
+ xenbus_frontend_closed(dev);
+ break;
+ }
+}
+
+static struct ethtool_ops xennet_ethtool_ops =
+{
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = xennet_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = xennet_set_tso,
+ .get_link = ethtool_op_get_link,
+};
+
+#ifdef CONFIG_SYSFS
+static ssize_t show_rxbuf_min(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_min_target);
+}
+
+static ssize_t store_rxbuf_min(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *np = netdev_priv(netdev);
+ char *endp;
+ unsigned long target;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ target = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EBADMSG;
+
+ if (target < RX_MIN_TARGET)
+ target = RX_MIN_TARGET;
+ if (target > RX_MAX_TARGET)
+ target = RX_MAX_TARGET;
+
+ spin_lock_bh(&np->rx_lock);
+ if (target > np->rx_max_target)
+ np->rx_max_target = target;
+ np->rx_min_target = target;
+ if (target > np->rx_target)
+ np->rx_target = target;
+
+ xennet_alloc_rx_buffers(netdev);
+
+ spin_unlock_bh(&np->rx_lock);
+ return len;
+}
+
+static ssize_t show_rxbuf_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_max_target);
+}
+
+static ssize_t store_rxbuf_max(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *np = netdev_priv(netdev);
+ char *endp;
+ unsigned long target;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ target = simple_strtoul(buf, &endp, 0);
+ if (endp == buf)
+ return -EBADMSG;
+
+ if (target < RX_MIN_TARGET)
+ target = RX_MIN_TARGET;
+ if (target > RX_MAX_TARGET)
+ target = RX_MAX_TARGET;
+
+ spin_lock_bh(&np->rx_lock);
+ if (target < np->rx_min_target)
+ np->rx_min_target = target;
+ np->rx_max_target = target;
+ if (target < np->rx_target)
+ np->rx_target = target;
+
+ xennet_alloc_rx_buffers(netdev);
+
+ spin_unlock_bh(&np->rx_lock);
+ return len;
+}
+
+static ssize_t show_rxbuf_cur(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct netfront_info *info = netdev_priv(netdev);
+
+ return sprintf(buf, "%u\n", info->rx_target);
+}
+
+static struct device_attribute xennet_attrs[] = {
+ __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
+ __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
+ __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
+};
+
+static int xennet_sysfs_addif(struct net_device *netdev)
+{
+ int i;
+ int err;
+
+ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
+ err = device_create_file(&netdev->dev,
+ &xennet_attrs[i]);
+ if (err)
+ goto fail;
+ }
+ return 0;
+
+ fail:
+ while (--i >= 0)
+ device_remove_file(&netdev->dev, &xennet_attrs[i]);
+ return err;
+}
+
+static void xennet_sysfs_delif(struct net_device *netdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)
+ device_remove_file(&netdev->dev, &xennet_attrs[i]);
+}
+
+#endif /* CONFIG_SYSFS */
+
+static struct xenbus_device_id netfront_ids[] = {
+ { "vif" },
+ { "" }
+};
+
+
+static int __devexit xennet_remove(struct xenbus_device *dev)
+{
+ struct netfront_info *info = dev->dev.driver_data;
+
+ dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+ unregister_netdev(info->netdev);
+
+ xennet_disconnect_backend(info);
+
+ del_timer_sync(&info->rx_refill_timer);
+
+ xennet_sysfs_delif(info->netdev);
+
+ free_netdev(info->netdev);
+
+ return 0;
+}
+
+static struct xenbus_driver netfront = {
+ .name = "vif",
+ .owner = THIS_MODULE,
+ .ids = netfront_ids,
+ .probe = netfront_probe,
+ .remove = __devexit_p(xennet_remove),
+ .resume = netfront_resume,
+ .otherend_changed = backend_changed,
+};
+
+static int __init netif_init(void)
+{
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ if (is_initial_xendomain())
+ return 0;
+
+ printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
+
+ return xenbus_register_frontend(&netfront);
+}
+module_init(netif_init);
+
+
+static void __exit netif_exit(void)
+{
+ if (is_initial_xendomain())
+ return;
+
+ return xenbus_unregister_driver(&netfront);
+}
+module_exit(netif_exit);
+
+MODULE_DESCRIPTION("Xen virtual network device frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index f2a90a7fa2d6..870c5393c21a 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1137,7 +1137,7 @@ static int yellowfin_rx(struct net_device *dev)
if (skb == NULL)
break;
skb_reserve(skb, 2); /* 16 byte align the IP header */
- eth_copy_and_sum(skb, rx_skb->data, pkt_len, 0);
+ skb_copy_to_linear_data(skb, rx_skb->data, pkt_len);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(yp->pci_dev, desc->addr,
yp->rx_buf_sz,
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 3a0a3a734933..e503c9c98032 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -466,9 +466,8 @@ static struct nubus_dev* __init
parent->base, dir.base);
/* Actually we should probably panic if this fails */
- if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
+ if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->resid = parent->type;
dev->directory = dir.base;
dev->board = board;
@@ -800,9 +799,8 @@ static struct nubus_board* __init nubus_add_board(int slot, int bytelanes)
nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
/* Actually we should probably panic if this fails */
- if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
+ if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
return NULL;
- memset(board, 0, sizeof(*board));
board->fblock = rp;
/* Dump the format block for debugging purposes */
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644
index 000000000000..c03072b12f42
--- /dev/null
+++ b/drivers/of/Kconfig
@@ -0,0 +1,3 @@
+config OF_DEVICE
+ def_bool y
+ depends on OF && (SPARC || PPC_OF)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644
index 000000000000..ab9be5d5255b
--- /dev/null
+++ b/drivers/of/Makefile
@@ -0,0 +1,2 @@
+obj-y = base.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644
index 000000000000..9377f3bc410a
--- /dev/null
+++ b/drivers/of/base.c
@@ -0,0 +1,275 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ * {engebret|bergner}@us.ibm.com
+ *
+ * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+DEFINE_RWLOCK(devtree_lock);
+
+int of_n_addr_cells(struct device_node *np)
+{
+ const int *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return *ip;
+ } while (np->parent);
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+ const int *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return *ip;
+ } while (np->parent);
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp)
+{
+ struct property *pp;
+
+ read_lock(&devtree_lock);
+ for (pp = np->properties; pp != 0; pp = pp->next) {
+ if (of_prop_cmp(pp->name, name) == 0) {
+ if (lenp != 0)
+ *lenp = pp->length;
+ break;
+ }
+ }
+ read_unlock(&devtree_lock);
+
+ return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp = of_find_property(np, name, lenp);
+
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
+{
+ const char* cp;
+ int cplen, l;
+
+ cp = of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+/**
+ * of_get_parent - Get a node's parent if any
+ * @node: Node to get parent
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+ struct device_node *np;
+
+ if (!node)
+ return NULL;
+
+ read_lock(&devtree_lock);
+ np = of_node_get(node->parent);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ * of_get_next_child - Iterate a node childs
+ * @node: parent node
+ * @prev: previous child of the parent node, or NULL to get first
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ read_lock(&devtree_lock);
+ next = prev ? prev->sibling : node->child;
+ for (; next; next = next->sibling)
+ if (of_node_get(next))
+ break;
+ of_node_put(prev);
+ read_unlock(&devtree_lock);
+ return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ * of_find_node_by_path - Find a node matching a full OF path
+ * @path: The full path to match
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+ struct device_node *np = allnodes;
+
+ read_lock(&devtree_lock);
+ for (; np; np = np->allnext) {
+ if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+ && of_node_get(np))
+ break;
+ }
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ * of_find_node_by_name - Find a node by its "name" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @name: The name string to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext)
+ if (np->name && (of_node_cmp(np->name, name) == 0)
+ && of_node_get(np))
+ break;
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ * of_find_node_by_type - Find a node by its "device_type" property
+ * @from: The node to start searching from, or NULL to start searching
+ * the entire device tree. The node you pass will not be
+ * searched, only the next one will; typically, you pass
+ * what the previous call returned. of_node_put() will be
+ * called on from for you.
+ * @type: The type string to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext)
+ if (np->type && (of_node_cmp(np->type, type) == 0)
+ && of_node_get(np))
+ break;
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ * of_find_compatible_node - Find a node based on type and one of the
+ * tokens in its "compatible" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ * will; typically, you pass what the previous call
+ * returned. of_node_put() will be called on it
+ * @type: The type string to match "device_type" or NULL to ignore
+ * @compatible: The string to match to one of the tokens in the device
+ * "compatible" list.
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compatible)
+{
+ struct device_node *np;
+
+ read_lock(&devtree_lock);
+ np = from ? from->allnext : allnodes;
+ for (; np; np = np->allnext) {
+ if (type
+ && !(np->type && (of_node_cmp(np->type, type) == 0)))
+ continue;
+ if (of_device_is_compatible(np, compatible) && of_node_get(np))
+ break;
+ }
+ of_node_put(from);
+ read_unlock(&devtree_lock);
+ return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
new file mode 100644
index 000000000000..6245f060fb77
--- /dev/null
+++ b/drivers/of/device.c
@@ -0,0 +1,131 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @ids: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+ const struct device_node *node)
+{
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+ int match = 1;
+ if (matches->name[0])
+ match &= node->name
+ && !strcmp(matches->name, node->name);
+ if (matches->type[0])
+ match &= node->type
+ && !strcmp(matches->type, node->type);
+ if (matches->compatible[0])
+ match &= of_device_is_compatible(node,
+ matches->compatible);
+ if (match)
+ return matches;
+ matches++;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+ const struct of_device *dev)
+{
+ if (!dev->node)
+ return NULL;
+ return of_match_node(matches, dev->node);
+}
+EXPORT_SYMBOL(of_match_device);
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+ struct device *tmp;
+
+ if (!dev)
+ return NULL;
+ tmp = get_device(&dev->dev);
+ if (tmp)
+ return to_of_device(tmp);
+ else
+ return NULL;
+}
+EXPORT_SYMBOL(of_dev_get);
+
+void of_dev_put(struct of_device *dev)
+{
+ if (dev)
+ put_device(&dev->dev);
+}
+EXPORT_SYMBOL(of_dev_put);
+
+static ssize_t dev_show_devspec(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+ struct of_device *ofdev;
+
+ ofdev = to_of_device(dev);
+ of_node_put(ofdev->node);
+ kfree(ofdev);
+}
+EXPORT_SYMBOL(of_release_dev);
+
+int of_device_register(struct of_device *ofdev)
+{
+ int rc;
+
+ BUG_ON(ofdev->node == NULL);
+
+ rc = device_register(&ofdev->dev);
+ if (rc)
+ return rc;
+
+ rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+ if (rc)
+ device_unregister(&ofdev->dev);
+
+ return rc;
+}
+EXPORT_SYMBOL(of_device_register);
+
+void of_device_unregister(struct of_device *ofdev)
+{
+ device_remove_file(&ofdev->dev, &dev_attr_devspec);
+ device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
new file mode 100644
index 000000000000..864f09fd9f86
--- /dev/null
+++ b/drivers/of/platform.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ * and Arnd Bergmann, IBM Corp.
+ * Merged from powerpc/kernel/of_platform.c and
+ * sparc{,64}/kernel/of_device.c by Stephen Rothwell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *of_drv = to_of_platform_driver(drv);
+ const struct of_device_id *matches = of_drv->match_table;
+
+ if (!matches)
+ return 0;
+
+ return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+ int error = -ENODEV;
+ struct of_platform_driver *drv;
+ struct of_device *of_dev;
+ const struct of_device_id *match;
+
+ drv = to_of_platform_driver(dev->driver);
+ of_dev = to_of_device(dev);
+
+ if (!drv->probe)
+ return error;
+
+ of_dev_get(of_dev);
+
+ match = of_match_device(drv->match_table, of_dev);
+ if (match)
+ error = drv->probe(of_dev, match);
+ if (error)
+ of_dev_put(of_dev);
+
+ return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+ if (dev->driver && drv->remove)
+ drv->remove(of_dev);
+ return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->suspend)
+ error = drv->suspend(of_dev, state);
+ return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+ struct of_device *of_dev = to_of_device(dev);
+ struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+ int error = 0;
+
+ if (dev->driver && drv->resume)
+ error = drv->resume(of_dev);
+ return error;
+}
+
+int of_bus_type_init(struct bus_type *bus, const char *name)
+{
+ bus->name = name;
+ bus->match = of_platform_bus_match;
+ bus->probe = of_platform_device_probe;
+ bus->remove = of_platform_device_remove;
+ bus->suspend = of_platform_device_suspend;
+ bus->resume = of_platform_device_resume;
+ return bus_register(bus);
+}
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index edd6de995726..8134c7e198a5 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -26,8 +26,9 @@
#include <linux/profile.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/oprofile.h>
#include <linux/sched.h>
-
+
#include "oprofile_stats.h"
#include "event_buffer.h"
#include "cpu_buffer.h"
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 9b6a4ebd03e3..5076ed1ebd8f 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -19,28 +19,10 @@ void free_event_buffer(void);
/* wake up the process sleeping on the event file */
void wake_up_buffer_waiter(void);
-
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE ~0UL
-#define CTX_SWITCH_CODE 1
-#define CPU_SWITCH_CODE 2
-#define COOKIE_SWITCH_CODE 3
-#define KERNEL_ENTER_SWITCH_CODE 4
-#define KERNEL_EXIT_SWITCH_CODE 5
-#define MODULE_LOADED_CODE 6
-#define CTX_TGID_CODE 7
-#define TRACE_BEGIN_CODE 8
-#define TRACE_END_CODE 9
-
+
#define INVALID_COOKIE ~0UL
#define NO_COOKIE 0UL
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
-
extern const struct file_operations event_buffer_fops;
/* mutex between sync_cpu_buffers() and the
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index e5162a64018b..2c645170f06e 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -53,9 +53,24 @@ int oprofile_setup(void)
* us missing task deaths and eventually oopsing
* when trying to process the event buffer.
*/
+ if (oprofile_ops.sync_start) {
+ int sync_ret = oprofile_ops.sync_start();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ case -1:
+ goto out3;
+ default:
+ goto out3;
+ }
+ }
+do_generic:
if ((err = sync_start()))
goto out3;
+post_sync:
is_setup = 1;
mutex_unlock(&start_mutex);
return 0;
@@ -118,7 +133,20 @@ out:
void oprofile_shutdown(void)
{
mutex_lock(&start_mutex);
+ if (oprofile_ops.sync_stop) {
+ int sync_ret = oprofile_ops.sync_stop();
+ switch (sync_ret) {
+ case 0:
+ goto post_sync;
+ case 1:
+ goto do_generic;
+ default:
+ goto post_sync;
+ }
+ }
+do_generic:
sync_stop();
+post_sync:
if (oprofile_ops.shutdown)
oprofile_ops.shutdown();
is_setup = 0;
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index a68b3b3761a2..a728a7cd2fc8 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/slab.h>
+#include <linux/dma-mapping.h>
#include <linux/ioport.h>
#include <asm/io.h>
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index 924ef0609460..fc4bde259dc7 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -121,14 +121,14 @@ struct pdcspath_entry pdcspath_entry_##_name = { \
#define PDCS_ATTR(_name, _mode, _show, _store) \
struct subsys_attribute pdcs_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};
#define PATHS_ATTR(_name, _mode, _show, _store) \
struct pdcspath_attribute paths_attr_##_name = { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE}, \
+ .attr = {.name = __stringify(_name), .mode = _mode}, \
.show = _show, \
.store = _store, \
};
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index a708c329675e..38cdf9fa36a7 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -73,6 +73,7 @@
#include <linux/termios.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/delay.h>
#include <asm/io.h>
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index f46c69e4ed82..d449b150930e 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -5,11 +5,9 @@
# Parport configuration.
#
-menu "Parallel port support"
- depends on HAS_IOMEM
-
-config PARPORT
+menuconfig PARPORT
tristate "Parallel port support"
+ depends on HAS_IOMEM
---help---
If you want to use devices connected to your machine's parallel port
(the connector at the computer with 25 holes), e.g. printer, ZIP
@@ -33,9 +31,11 @@ config PARPORT
If unsure, say Y.
+if PARPORT
+
config PARPORT_PC
tristate "PC-style hardware"
- depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
+ depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA)
---help---
You should say Y here if you have a PC-style parallel port. All
IBM PC compatible computers and some Alphas have PC-style
@@ -85,7 +85,7 @@ config PARPORT_PC_PCMCIA
config PARPORT_IP32
tristate "SGI IP32 builtin port (EXPERIMENTAL)"
- depends on SGI_IP32 && PARPORT && EXPERIMENTAL
+ depends on SGI_IP32 && EXPERIMENTAL
select PARPORT_NOT_PC
help
Say Y here if you need support for the parallel port on
@@ -94,7 +94,7 @@ config PARPORT_IP32
config PARPORT_AMIGA
tristate "Amiga builtin port"
- depends on AMIGA && PARPORT
+ depends on AMIGA
select PARPORT_NOT_PC
help
Say Y here if you need support for the parallel port hardware on
@@ -103,7 +103,7 @@ config PARPORT_AMIGA
config PARPORT_MFC3
tristate "Multiface III parallel port"
- depends on ZORRO && PARPORT
+ depends on ZORRO
select PARPORT_NOT_PC
help
Say Y here if you need parallel port support for the MFC3 card.
@@ -112,7 +112,7 @@ config PARPORT_MFC3
config PARPORT_ATARI
tristate "Atari hardware"
- depends on ATARI && PARPORT
+ depends on ATARI
select PARPORT_NOT_PC
help
Say Y here if you need support for the parallel port hardware on
@@ -122,12 +122,11 @@ config PARPORT_ATARI
config PARPORT_GSC
tristate
default GSC
- depends on PARPORT
select PARPORT_NOT_PC
config PARPORT_SUNBPP
tristate "Sparc hardware (EXPERIMENTAL)"
- depends on SBUS && PARPORT && EXPERIMENTAL
+ depends on SBUS && EXPERIMENTAL
select PARPORT_NOT_PC
help
This driver provides support for the bidirectional parallel port
@@ -136,7 +135,6 @@ config PARPORT_SUNBPP
config PARPORT_AX88796
tristate "AX88796 Parallel Port"
- depends on PARPORT
select PARPORT_NOT_PC
help
Say Y here if you need support for the parallel port hardware on
@@ -148,7 +146,6 @@ config PARPORT_AX88796
config PARPORT_1284
bool "IEEE 1284 transfer modes"
- depends on PARPORT
help
If you have a printer that supports status readback or device ID, or
want to use a device that uses enhanced parallel port transfer modes
@@ -159,5 +156,4 @@ config PARPORT_1284
config PARPORT_NOT_PC
bool
-endmenu
-
+endif # PARPORT
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 8b7d84eca05d..802a81d47367 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -105,9 +105,8 @@ static int parport_probe(struct pcmcia_device *link)
DEBUG(0, "parport_attach()\n");
/* Create new parport device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) return -ENOMEM;
- memset(info, 0, sizeof(*info));
link->priv = info;
info->p_dev = link;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 7bfbad57879d..5d58ad55d85c 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2424,7 +2424,6 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
u32 ite8872set;
u32 ite8872_lpt, ite8872_lpthi;
u8 ite8872_irq, type;
- char *fake_name = "parport probe";
int irq;
int i;
@@ -2432,11 +2431,11 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq,
// make sure which one chip
for(i = 0; i < 5; i++) {
- base_res = request_region(inta_addr[i], 0x8, fake_name);
+ base_res = request_region(inta_addr[i], 32, "it887x");
if (base_res) {
int test;
pci_write_config_dword (pdev, 0x60,
- 0xe7000000 | inta_addr[i]);
+ 0xe5000000 | inta_addr[i]);
pci_write_config_dword (pdev, 0x78,
0x00000000 | inta_addr[i]);
test = inb (inta_addr[i]);
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 90ea3b8b99b0..bd6ad8b38168 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -324,10 +324,9 @@ static int __devinit parport_serial_pci_probe (struct pci_dev *dev,
struct parport_serial_private *priv;
int err;
- priv = kmalloc (sizeof *priv, GFP_KERNEL);
+ priv = kzalloc (sizeof *priv, GFP_KERNEL);
if (!priv)
return -ENOMEM;
- memset(priv, 0, sizeof(struct parport_serial_private));
pci_set_drvdata (dev, priv);
err = pci_enable_device (dev);
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index e3beb784406f..006054a40995 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -41,9 +41,7 @@ obj-$(CONFIG_ACPI) += pci-acpi.o
# Cardbus & CompactPCI use setup-bus
obj-$(CONFIG_HOTPLUG) += setup-bus.o
-ifndef CONFIG_X86
-obj-y += syscall.o
-endif
+obj-$(CONFIG_PCI_SYSCALL) += syscall.o
ifeq ($(CONFIG_PCI_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index ddbadd95387e..f6cc0c5b5657 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -211,6 +211,7 @@ typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
+extern int acpiphp_eject_slot (struct acpiphp_slot *slot);
extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot);
extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot);
extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index fa5c0197d571..a0ca63adad5a 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -156,11 +156,15 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
+ int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
/* disable the specified slot */
- return acpiphp_disable_slot(slot->acpi_slot);
+ retval = acpiphp_disable_slot(slot->acpi_slot);
+ if (!retval)
+ retval = acpiphp_eject_slot(slot->acpi_slot);
+ return retval;
}
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 9ef4e989afc4..1e125b56c9a9 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -1282,7 +1282,7 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
/**
* acpiphp_eject_slot - physically eject the slot
*/
-static int acpiphp_eject_slot(struct acpiphp_slot *slot)
+int acpiphp_eject_slot(struct acpiphp_slot *slot)
{
acpi_status status;
struct acpiphp_func *func;
@@ -1368,6 +1368,9 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return;
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
+ return;
+
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
bridge->hpp.t0->cache_line_size);
pci_write_config_byte(dev, PCI_LATENCY_TIMER,
@@ -1502,6 +1505,37 @@ static void handle_bridge_insertion(acpi_handle handle, u32 type)
* ACPI event handlers
*/
+static acpi_status
+count_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *count = (int *)context;
+ struct acpiphp_bridge *bridge;
+
+ bridge = acpiphp_handle_to_bridge(handle);
+ if (bridge)
+ (*count)++;
+ return AE_OK ;
+}
+
+static acpi_status
+check_sub_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ struct acpiphp_bridge *bridge;
+ char objname[64];
+ struct acpi_buffer buffer = { .length = sizeof(objname),
+ .pointer = objname };
+
+ bridge = acpiphp_handle_to_bridge(handle);
+ if (bridge) {
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ dbg("%s: re-enumerating slots under %s\n",
+ __FUNCTION__, objname);
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ acpiphp_check_bridge(bridge);
+ }
+ return AE_OK ;
+}
+
/**
* handle_hotplug_event_bridge - handle ACPI event on bridges
*
@@ -1519,6 +1553,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname };
struct acpi_device *device;
+ int num_sub_bridges = 0;
if (acpi_bus_get_device(handle, &device)) {
/* This bridge must have just been physically inserted */
@@ -1527,7 +1562,12 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
}
bridge = acpiphp_handle_to_bridge(handle);
- if (!bridge) {
+ if (type == ACPI_NOTIFY_BUS_CHECK) {
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, ACPI_UINT32_MAX,
+ count_sub_bridges, &num_sub_bridges, NULL);
+ }
+
+ if (!bridge && !num_sub_bridges) {
err("cannot get bridge info\n");
return;
}
@@ -1538,7 +1578,14 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
case ACPI_NOTIFY_BUS_CHECK:
/* bus re-enumerate */
dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
- acpiphp_check_bridge(bridge);
+ if (bridge) {
+ dbg("%s: re-enumerating slots under %s\n",
+ __FUNCTION__, objname);
+ acpiphp_check_bridge(bridge);
+ }
+ if (num_sub_bridges)
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ ACPI_UINT32_MAX, check_sub_bridges, NULL, NULL);
break;
case ACPI_NOTIFY_DEVICE_CHECK:
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index e7322c25d377..70db38c0ced9 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -106,7 +106,8 @@ static int ibm_get_attention_status(struct hotplug_slot *slot, u8 *status);
static void ibm_handle_events(acpi_handle handle, u32 event, void *context);
static int ibm_get_table_from_acpi(char **bufp);
static ssize_t ibm_read_apci_table(struct kobject *kobj,
- char *buffer, loff_t pos, size_t size);
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t size);
static acpi_status __init ibm_find_acpi_device(acpi_handle handle,
u32 lvl, void *context, void **rv);
static int __init ibm_acpiphp_init(void);
@@ -117,7 +118,6 @@ static struct notification ibm_note;
static struct bin_attribute ibm_apci_table_attr = {
.attr = {
.name = "apci_table",
- .owner = THIS_MODULE,
.mode = S_IRUGO,
},
.read = ibm_read_apci_table,
@@ -358,7 +358,8 @@ read_table_done:
* our solution is to only allow reading the table in all at once
**/
static ssize_t ibm_read_apci_table(struct kobject *kobj,
- char *buffer, loff_t pos, size_t size)
+ struct bin_attribute *bin_attr,
+ char *buffer, loff_t pos, size_t size)
{
int bytes_read = -EINVAL;
char *table = NULL;
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index 684551559d44..ed4d44e3332c 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -35,6 +35,7 @@
#include <linux/smp_lock.h>
#include <asm/atomic.h>
#include <linux/delay.h>
+#include <linux/kthread.h>
#include "cpci_hotplug.h"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
@@ -59,9 +60,8 @@ static int slots;
static atomic_t extracting;
int cpci_debug;
static struct cpci_hp_controller *controller;
-static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */
-static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */
-static int thread_finished = 1;
+static struct task_struct *cpci_thread;
+static int thread_finished;
static int enable_slot(struct hotplug_slot *slot);
static int disable_slot(struct hotplug_slot *slot);
@@ -357,9 +357,7 @@ cpci_hp_intr(int irq, void *data)
controller->ops->disable_irq();
/* Trigger processing by the event thread */
- dbg("Signal event_semaphore");
- up(&event_semaphore);
- dbg("exited cpci_hp_intr");
+ wake_up_process(cpci_thread);
return IRQ_HANDLED;
}
@@ -521,17 +519,12 @@ event_thread(void *data)
{
int rc;
- lock_kernel();
- daemonize("cpci_hp_eventd");
- unlock_kernel();
-
dbg("%s - event thread started", __FUNCTION__);
while (1) {
dbg("event thread sleeping");
- down_interruptible(&event_semaphore);
- dbg("event thread woken, thread_finished = %d",
- thread_finished);
- if (thread_finished || signal_pending(current))
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ if (kthread_should_stop())
break;
do {
rc = check_slots();
@@ -541,18 +534,17 @@ event_thread(void *data)
} else if (rc < 0) {
dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1;
- break;
+ goto out;
}
- } while (atomic_read(&extracting) && !thread_finished);
- if (thread_finished)
+ } while (atomic_read(&extracting) && !kthread_should_stop());
+ if (kthread_should_stop())
break;
/* Re-enable ENUM# interrupt */
dbg("%s - re-enabling irq", __FUNCTION__);
controller->ops->enable_irq();
}
- dbg("%s - event thread signals exit", __FUNCTION__);
- up(&thread_exit);
+ out:
return 0;
}
@@ -562,12 +554,8 @@ poll_thread(void *data)
{
int rc;
- lock_kernel();
- daemonize("cpci_hp_polld");
- unlock_kernel();
-
while (1) {
- if (thread_finished || signal_pending(current))
+ if (kthread_should_stop() || signal_pending(current))
break;
if (controller->ops->query_enum()) {
do {
@@ -578,48 +566,36 @@ poll_thread(void *data)
} else if (rc < 0) {
dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1;
- break;
+ goto out;
}
- } while (atomic_read(&extracting) && !thread_finished);
+ } while (atomic_read(&extracting) && !kthread_should_stop());
}
msleep(100);
}
- dbg("poll thread signals exit");
- up(&thread_exit);
+ out:
return 0;
}
static int
cpci_start_thread(void)
{
- int pid;
-
- /* initialize our semaphores */
- init_MUTEX_LOCKED(&event_semaphore);
- init_MUTEX_LOCKED(&thread_exit);
- thread_finished = 0;
-
if (controller->irq)
- pid = kernel_thread(event_thread, NULL, 0);
+ cpci_thread = kthread_run(event_thread, NULL, "cpci_hp_eventd");
else
- pid = kernel_thread(poll_thread, NULL, 0);
- if (pid < 0) {
+ cpci_thread = kthread_run(poll_thread, NULL, "cpci_hp_polld");
+ if (IS_ERR(cpci_thread)) {
err("Can't start up our thread");
- return -1;
+ return PTR_ERR(cpci_thread);
}
- dbg("Our thread pid = %d", pid);
+ thread_finished = 0;
return 0;
}
static void
cpci_stop_thread(void)
{
+ kthread_stop(cpci_thread);
thread_finished = 1;
- dbg("thread finish command given");
- if (controller->irq)
- up(&event_semaphore);
- dbg("wait for thread to exit");
- down(&thread_exit);
}
int
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 7b1beaad2752..5e9be44817cb 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -45,8 +45,6 @@ extern int cpci_debug;
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
-#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
-
u8 cpci_get_attention_status(struct slot* slot)
{
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 5617cfdadc5c..d590a99930fa 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -796,7 +796,6 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
u8 num_of_slots = 0;
u8 hp_slot = 0;
u8 device;
- u8 rev;
u8 bus_cap;
u16 temp_word;
u16 vendor_id;
@@ -823,9 +822,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
dbg("Vendor ID: %x\n", vendor_id);
- rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
- dbg("revision: %d\n", rev);
- if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) {
+ dbg("revision: %d\n", pdev->revision);
+ if ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!pdev->revision)) {
err(msg_HPC_rev_error);
rc = -ENODEV;
goto err_disable_device;
@@ -836,7 +834,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* For Intel, each SSID bit identifies a PHP capability.
* Also Intel HPC's may have RID=0.
*/
- if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) {
+ if ((pdev->revision > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) {
// TODO: This code can be made to support non-Compaq or Intel subsystem IDs
rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid);
if (rc) {
@@ -870,7 +868,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
switch (subsystem_vid) {
case PCI_VENDOR_ID_COMPAQ:
- if (rev >= 0x13) { /* CIOBX */
+ if (pdev->revision >= 0x13) { /* CIOBX */
ctrl->push_flag = 1;
ctrl->slot_switch_type = 1;
ctrl->push_button = 1;
@@ -1075,7 +1073,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
memcpy(ctrl->pci_bus, pdev->bus, sizeof(*ctrl->pci_bus));
ctrl->bus = pdev->bus->number;
- ctrl->rev = rev;
+ ctrl->rev = pdev->revision;
dbg("bus device function rev: %d %d %d %d\n", ctrl->bus,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev);
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index ccc57627201e..7959c222dc24 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -103,6 +103,7 @@ struct controller {
u8 cap_base;
struct timer_list poll_timer;
volatile int cmd_busy;
+ spinlock_t lock;
};
#define INT_BUTTON_IGNORE 0
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 7f22caa70178..98e541ffef3d 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -197,6 +197,12 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
__FUNCTION__);
return;
}
+ /*
+ * After turning power off, we must wait for at least
+ * 1 second before taking any action that relies on
+ * power having been removed from the slot/adapter.
+ */
+ msleep(1000);
}
}
@@ -615,6 +621,12 @@ int pciehp_disable_slot(struct slot *p_slot)
mutex_unlock(&p_slot->ctrl->crit_sect);
return -EINVAL;
}
+ /*
+ * After turning power off, we must wait for at least
+ * 1 second before taking any action that relies on
+ * power having been removed from the slot/adapter.
+ */
+ msleep(1000);
}
ret = remove_board(p_slot);
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 9aac6a87eb53..016eea94a8a5 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -275,11 +275,19 @@ static inline int pcie_wait_cmd(struct controller *ctrl)
return retval;
}
-static int pcie_write_cmd(struct slot *slot, u16 cmd)
+/**
+ * pcie_write_cmd - Issue controller command
+ * @slot: slot to which the command is issued
+ * @cmd: command value written to slot control register
+ * @mask: bitmask of slot control register to be modified
+ */
+static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
{
struct controller *ctrl = slot->ctrl;
int retval = 0;
u16 slot_status;
+ u16 slot_ctrl;
+ unsigned long flags;
DBG_ENTER_ROUTINE
@@ -299,17 +307,29 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd)
__FUNCTION__);
}
- ctrl->cmd_busy = 1;
- retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
+ spin_lock_irqsave(&ctrl->lock, flags);
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
- goto out;
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
+ goto out_spin_unlock;
}
+ slot_ctrl &= ~mask;
+ slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE);
+
+ ctrl->cmd_busy = 1;
+ retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
+ if (retval)
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+
+ out_spin_unlock:
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+
/*
* Wait for command completion.
*/
- retval = pcie_wait_cmd(ctrl);
+ if (!retval)
+ retval = pcie_wait_cmd(ctrl);
out:
mutex_unlock(&ctrl->ctrl_lock);
DBG_LEAVE_ROUTINE
@@ -502,25 +522,20 @@ static int hpc_get_emi_status(struct slot *slot, u8 *status)
static int hpc_toggle_emi(struct slot *slot)
{
- struct controller *ctrl = slot->ctrl;
- u16 slot_cmd = 0;
- u16 slot_ctrl;
- int rc = 0;
+ u16 slot_cmd;
+ u16 cmd_mask;
+ int rc;
DBG_ENTER_ROUTINE
- rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n",
- __FUNCTION__);
- return rc;
- }
-
- slot_cmd = (slot_ctrl | EMI_CTRL);
- if (!pciehp_poll_mode)
+ slot_cmd = EMI_CTRL;
+ cmd_mask = EMI_CTRL;
+ if (!pciehp_poll_mode) {
slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ cmd_mask = cmd_mask | HP_INTR_ENABLE;
+ }
- pcie_write_cmd(slot, slot_cmd);
+ rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();
DBG_LEAVE_ROUTINE
return rc;
@@ -529,35 +544,32 @@ static int hpc_toggle_emi(struct slot *slot)
static int hpc_set_attention_status(struct slot *slot, u8 value)
{
struct controller *ctrl = slot->ctrl;
- u16 slot_cmd = 0;
- u16 slot_ctrl;
- int rc = 0;
+ u16 slot_cmd;
+ u16 cmd_mask;
+ int rc;
DBG_ENTER_ROUTINE
- rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- return rc;
- }
-
+ cmd_mask = ATTN_LED_CTRL;
switch (value) {
case 0 : /* turn off */
- slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x00C0;
+ slot_cmd = 0x00C0;
break;
case 1: /* turn on */
- slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0040;
+ slot_cmd = 0x0040;
break;
case 2: /* turn blink */
- slot_cmd = (slot_ctrl & ~ATTN_LED_CTRL) | 0x0080;
+ slot_cmd = 0x0080;
break;
default:
return -1;
}
- if (!pciehp_poll_mode)
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ if (!pciehp_poll_mode) {
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ cmd_mask = cmd_mask | HP_INTR_ENABLE;
+ }
- pcie_write_cmd(slot, slot_cmd);
+ rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -570,21 +582,18 @@ static void hpc_set_green_led_on(struct slot *slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
- u16 slot_ctrl;
- int rc = 0;
+ u16 cmd_mask;
DBG_ENTER_ROUTINE
- rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- return;
+ slot_cmd = 0x0100;
+ cmd_mask = PWR_LED_CTRL;
+ if (!pciehp_poll_mode) {
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ cmd_mask = cmd_mask | HP_INTR_ENABLE;
}
- slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
- if (!pciehp_poll_mode)
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- pcie_write_cmd(slot, slot_cmd);
+ pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -596,22 +605,18 @@ static void hpc_set_green_led_off(struct slot *slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
- u16 slot_ctrl;
- int rc = 0;
+ u16 cmd_mask;
DBG_ENTER_ROUTINE
- rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- return;
+ slot_cmd = 0x0300;
+ cmd_mask = PWR_LED_CTRL;
+ if (!pciehp_poll_mode) {
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ cmd_mask = cmd_mask | HP_INTR_ENABLE;
}
- slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300;
-
- if (!pciehp_poll_mode)
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- pcie_write_cmd(slot, slot_cmd);
+ pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -623,22 +628,18 @@ static void hpc_set_green_led_blink(struct slot *slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
- u16 slot_ctrl;
- int rc = 0;
+ u16 cmd_mask;
DBG_ENTER_ROUTINE
- rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- return;
+ slot_cmd = 0x0200;
+ cmd_mask = PWR_LED_CTRL;
+ if (!pciehp_poll_mode) {
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ cmd_mask = cmd_mask | HP_INTR_ENABLE;
}
- slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200;
-
- if (!pciehp_poll_mode)
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- pcie_write_cmd(slot, slot_cmd);
+ pcie_write_cmd(slot, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -669,7 +670,8 @@ static int hpc_power_on_slot(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
- u16 slot_ctrl, slot_status;
+ u16 cmd_mask;
+ u16 slot_status;
int retval = 0;
DBG_ENTER_ROUTINE
@@ -692,23 +694,23 @@ static int hpc_power_on_slot(struct slot * slot)
}
}
- retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (retval) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- return retval;
- }
-
- slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
-
+ slot_cmd = POWER_ON;
+ cmd_mask = PWR_CTRL;
/* Enable detection that we turned off at slot power-off time */
- if (!pciehp_poll_mode)
+ if (!pciehp_poll_mode) {
slot_cmd = slot_cmd |
PWR_FAULT_DETECT_ENABLE |
MRL_DETECT_ENABLE |
PRSN_DETECT_ENABLE |
HP_INTR_ENABLE;
+ cmd_mask = cmd_mask |
+ PWR_FAULT_DETECT_ENABLE |
+ MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE |
+ HP_INTR_ENABLE;
+ }
- retval = pcie_write_cmd(slot, slot_cmd);
+ retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
if (retval) {
err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
@@ -726,21 +728,15 @@ static int hpc_power_off_slot(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
- u16 slot_ctrl;
+ u16 cmd_mask;
int retval = 0;
DBG_ENTER_ROUTINE
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (retval) {
- err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
- return retval;
- }
-
- slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
-
+ slot_cmd = POWER_OFF;
+ cmd_mask = PWR_CTRL;
/*
* If we get MRL or presence detect interrupts now, the isr
* will notice the sticky power-fault bit too and issue power
@@ -748,14 +744,19 @@ static int hpc_power_off_slot(struct slot * slot)
* of command completions, since the power-fault bit remains on
* till the slot is powered on again.
*/
- if (!pciehp_poll_mode)
+ if (!pciehp_poll_mode) {
slot_cmd = (slot_cmd &
~PWR_FAULT_DETECT_ENABLE &
~MRL_DETECT_ENABLE &
~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE;
+ cmd_mask = cmd_mask |
+ PWR_FAULT_DETECT_ENABLE |
+ MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE |
+ HP_INTR_ENABLE;
+ }
- retval = pcie_write_cmd(slot, slot_cmd);
-
+ retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
if (retval) {
err("%s: Write command failed!\n", __FUNCTION__);
return -1;
@@ -775,6 +776,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
u16 temp_word;
int hp_slot = 0; /* only 1 slot per PCI Express port */
int rc = 0;
+ unsigned long flags;
rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
@@ -794,10 +796,12 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
/* Mask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
+ spin_lock_irqsave(&ctrl->lock, flags);
rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
err("%s: Cannot read SLOT_CTRL register\n",
__FUNCTION__);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return IRQ_NONE;
}
@@ -808,8 +812,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
if (rc) {
err("%s: Cannot write to SLOTCTRL register\n",
__FUNCTION__);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return IRQ_NONE;
}
+ spin_unlock_irqrestore(&ctrl->lock, flags);
rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
@@ -859,10 +865,12 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
}
/* Unmask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
+ spin_lock_irqsave(&ctrl->lock, flags);
rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
err("%s: Cannot read SLOTCTRL register\n",
__FUNCTION__);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return IRQ_NONE;
}
@@ -873,8 +881,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
if (rc) {
err("%s: Cannot write to SLOTCTRL register\n",
__FUNCTION__);
+ spin_unlock_irqrestore(&ctrl->lock, flags);
return IRQ_NONE;
}
+ spin_unlock_irqrestore(&ctrl->lock, flags);
rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
@@ -1237,6 +1247,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->ctrl_lock);
+ spin_lock_init(&ctrl->lock);
/* setup wait queue */
init_waitqueue_head(&ctrl->queue);
diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c
index bb3c101c2c5a..deb6b5e35feb 100644
--- a/drivers/pci/hotplug/rpadlpar_core.c
+++ b/drivers/pci/hotplug/rpadlpar_core.c
@@ -159,8 +159,8 @@ static void dlpar_pci_add_bus(struct device_node *dn)
/* Claim new bus resources */
pcibios_claim_one_bus(dev->bus);
- /* ioremap() for child bus, which may or may not succeed */
- remap_bus_range(dev->subordinate);
+ /* Map IO space for child bus, which may or may not succeed */
+ pcibios_map_io_space(dev->subordinate);
/* Add new devices to global lists. Register in proc, sysfs. */
pci_bus_add_devices(phb->bus);
@@ -390,7 +390,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)
} else
pcibios_remove_pci_devices(bus);
- if (unmap_bus_range(bus)) {
+ if (pcibios_unmap_io_space(bus)) {
printk(KERN_ERR "%s: failed to unmap bus range\n",
__FUNCTION__);
return -ERANGE;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index b5ac810404c0..c8062494009f 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -55,8 +55,6 @@ acpi_query_osc (
status = acpi_evaluate_object(handle, "_OSC", &input, &output);
if (ACPI_FAILURE (status)) {
- printk(KERN_DEBUG
- "Evaluate _OSC Set fails. Status = 0x%04x\n", status);
*ret_status = status;
return status;
}
@@ -124,11 +122,9 @@ acpi_run_osc (
in_params[3].buffer.pointer = (u8 *)context;
status = acpi_evaluate_object(handle, "_OSC", &input, &output);
- if (ACPI_FAILURE (status)) {
- printk(KERN_DEBUG
- "Evaluate _OSC Set fails. Status = 0x%04x\n", status);
+ if (ACPI_FAILURE (status))
return status;
- }
+
out_obj = output.pointer;
if (out_obj->type != ACPI_TYPE_BUFFER) {
printk(KERN_DEBUG
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 284e83a527f9..1b7b2812bf2d 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -20,7 +20,7 @@
#include <linux/stat.h>
#include <linux/topology.h>
#include <linux/mm.h>
-
+#include <linux/capability.h>
#include "pci.h"
static int sysfs_initialized; /* = 0 */
@@ -213,7 +213,8 @@ struct device_attribute pci_dev_attrs[] = {
};
static ssize_t
-pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
unsigned int size = 64;
@@ -285,7 +286,8 @@ pci_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
}
static ssize_t
-pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *dev = to_pci_dev(container_of(kobj,struct device,kobj));
unsigned int size = count;
@@ -352,7 +354,8 @@ pci_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
* callback routine (pci_legacy_read).
*/
ssize_t
-pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_read_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_bus *bus = to_pci_bus(container_of(kobj,
struct class_device,
@@ -376,7 +379,8 @@ pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
* callback routine (pci_legacy_write).
*/
ssize_t
-pci_write_legacy_io(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_write_legacy_io(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_bus *bus = to_pci_bus(container_of(kobj,
struct class_device,
@@ -499,7 +503,6 @@ static int pci_create_resource_files(struct pci_dev *pdev)
sprintf(res_attr_name, "resource%d", i);
res_attr->attr.name = res_attr_name;
res_attr->attr.mode = S_IRUSR | S_IWUSR;
- res_attr->attr.owner = THIS_MODULE;
res_attr->size = pci_resource_len(pdev, i);
res_attr->mmap = pci_mmap_resource;
res_attr->private = &pdev->resource[i];
@@ -529,7 +532,8 @@ static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
* writing anything except 0 enables it
*/
static ssize_t
-pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_write_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
@@ -552,7 +556,8 @@ pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
* device corresponding to @kobj.
*/
static ssize_t
-pci_read_rom(struct kobject *kobj, char *buf, loff_t off, size_t count)
+pci_read_rom(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj));
void __iomem *rom;
@@ -582,7 +587,6 @@ static struct bin_attribute pci_config_attr = {
.attr = {
.name = "config",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 256,
.read = pci_read_config,
@@ -593,13 +597,17 @@ static struct bin_attribute pcie_config_attr = {
.attr = {
.name = "config",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 4096,
.read = pci_read_config,
.write = pci_write_config,
};
+int __attribute__ ((weak)) pcibios_add_platform_entries(struct pci_dev *dev)
+{
+ return 0;
+}
+
int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
{
struct bin_attribute *rom_attr = NULL;
@@ -628,7 +636,6 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
rom_attr->attr.name = "rom";
rom_attr->attr.mode = S_IRUSR;
- rom_attr->attr.owner = THIS_MODULE;
rom_attr->read = pci_read_rom;
rom_attr->write = pci_write_rom;
retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
@@ -640,10 +647,14 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
}
}
/* add platform-specific attributes */
- pcibios_add_platform_entries(pdev);
+ if (pcibios_add_platform_entries(pdev))
+ goto err_rom_file;
return 0;
+err_rom_file:
+ if (pci_resource_len(pdev, PCI_ROM_RESOURCE))
+ sysfs_remove_bin_file(&pdev->dev.kobj, rom_attr);
err_rom:
kfree(rom_attr);
err_resource_files:
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index fd47ac0c4730..03fd59e80fef 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -406,6 +406,13 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
return 0;
+ /* find PCI PM capability in list */
+ pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+
+ /* abort if the device doesn't support PM capabilities */
+ if (!pm)
+ return -EIO;
+
/* Validate current state:
* Can enter D0 from any state, but if we can only go deeper
* to sleep if we're already in a low power state
@@ -418,13 +425,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
return 0; /* we're already there */
- /* find PCI PM capability in list */
- pm = pci_find_capability(dev, PCI_CAP_ID_PM);
-
- /* abort if the device doesn't support PM capabilities */
- if (!pm)
- return -EIO;
-
pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
if ((pmc & PCI_PM_CAP_VER_MASK) > 3) {
printk(KERN_DEBUG
@@ -1186,6 +1186,11 @@ int pci_set_mwi(struct pci_dev *dev)
return 0;
}
+int pci_try_set_mwi(struct pci_dev *dev)
+{
+ return 0;
+}
+
void pci_clear_mwi(struct pci_dev *dev)
{
}
@@ -1242,9 +1247,7 @@ pci_set_cacheline_size(struct pci_dev *dev)
* pci_set_mwi - enables memory-write-invalidate PCI transaction
* @dev: the PCI device for which MWI is enabled
*
- * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
- * and then calls @pcibios_set_mwi to do the needed arch specific
- * operations or a generic mwi-prep function.
+ * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND.
*
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/
@@ -1260,7 +1263,8 @@ pci_set_mwi(struct pci_dev *dev)
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (! (cmd & PCI_COMMAND_INVALIDATE)) {
- pr_debug("PCI: Enabling Mem-Wr-Inval for device %s\n", pci_name(dev));
+ pr_debug("PCI: Enabling Mem-Wr-Inval for device %s\n",
+ pci_name(dev));
cmd |= PCI_COMMAND_INVALIDATE;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
@@ -1269,6 +1273,21 @@ pci_set_mwi(struct pci_dev *dev)
}
/**
+ * pci_try_set_mwi - enables memory-write-invalidate PCI transaction
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND.
+ * Callers are not required to check the return value.
+ *
+ * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
+ */
+int pci_try_set_mwi(struct pci_dev *dev)
+{
+ int rc = pci_set_mwi(dev);
+ return rc;
+}
+
+/**
* pci_clear_mwi - disables Memory-Write-Invalidate for device dev
* @dev: the PCI device to disable
*
@@ -1375,6 +1394,164 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
#endif
/**
+ * pcix_get_max_mmrbc - get PCI-X maximum designed memory read byte count
+ * @dev: PCI device to query
+ *
+ * Returns mmrbc: maximum designed memory read count in bytes
+ * or appropriate error value.
+ */
+int pcix_get_max_mmrbc(struct pci_dev *dev)
+{
+ int err, cap;
+ u32 stat;
+
+ cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+ if (!cap)
+ return -EINVAL;
+
+ err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);
+ if (err)
+ return -EINVAL;
+
+ return (stat & PCI_X_STATUS_MAX_READ) >> 12;
+}
+EXPORT_SYMBOL(pcix_get_max_mmrbc);
+
+/**
+ * pcix_get_mmrbc - get PCI-X maximum memory read byte count
+ * @dev: PCI device to query
+ *
+ * Returns mmrbc: maximum memory read count in bytes
+ * or appropriate error value.
+ */
+int pcix_get_mmrbc(struct pci_dev *dev)
+{
+ int ret, cap;
+ u32 cmd;
+
+ cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+ if (!cap)
+ return -EINVAL;
+
+ ret = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);
+ if (!ret)
+ ret = 512 << ((cmd & PCI_X_CMD_MAX_READ) >> 2);
+
+ return ret;
+}
+EXPORT_SYMBOL(pcix_get_mmrbc);
+
+/**
+ * pcix_set_mmrbc - set PCI-X maximum memory read byte count
+ * @dev: PCI device to query
+ * @mmrbc: maximum memory read count in bytes
+ * valid values are 512, 1024, 2048, 4096
+ *
+ * If possible sets maximum memory read byte count, some bridges have erratas
+ * that prevent this.
+ */
+int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc)
+{
+ int cap, err = -EINVAL;
+ u32 stat, cmd, v, o;
+
+ if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
+ goto out;
+
+ v = ffs(mmrbc) - 10;
+
+ cap = pci_find_capability(dev, PCI_CAP_ID_PCIX);
+ if (!cap)
+ goto out;
+
+ err = pci_read_config_dword(dev, cap + PCI_X_STATUS, &stat);
+ if (err)
+ goto out;
+
+ if (v > (stat & PCI_X_STATUS_MAX_READ) >> 21)
+ return -E2BIG;
+
+ err = pci_read_config_dword(dev, cap + PCI_X_CMD, &cmd);
+ if (err)
+ goto out;
+
+ o = (cmd & PCI_X_CMD_MAX_READ) >> 2;
+ if (o != v) {
+ if (v > o && dev->bus &&
+ (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_MMRBC))
+ return -EIO;
+
+ cmd &= ~PCI_X_CMD_MAX_READ;
+ cmd |= v << 2;
+ err = pci_write_config_dword(dev, cap + PCI_X_CMD, cmd);
+ }
+out:
+ return err;
+}
+EXPORT_SYMBOL(pcix_set_mmrbc);
+
+/**
+ * pcie_get_readrq - get PCI Express read request size
+ * @dev: PCI device to query
+ *
+ * Returns maximum memory read request in bytes
+ * or appropriate error value.
+ */
+int pcie_get_readrq(struct pci_dev *dev)
+{
+ int ret, cap;
+ u16 ctl;
+
+ cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!cap)
+ return -EINVAL;
+
+ ret = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
+ if (!ret)
+ ret = 128 << ((ctl & PCI_EXP_DEVCTL_READRQ) >> 12);
+
+ return ret;
+}
+EXPORT_SYMBOL(pcie_get_readrq);
+
+/**
+ * pcie_set_readrq - set PCI Express maximum memory read request
+ * @dev: PCI device to query
+ * @count: maximum memory read count in bytes
+ * valid values are 128, 256, 512, 1024, 2048, 4096
+ *
+ * If possible sets maximum read byte count
+ */
+int pcie_set_readrq(struct pci_dev *dev, int rq)
+{
+ int cap, err = -EINVAL;
+ u16 ctl, v;
+
+ if (rq < 128 || rq > 4096 || (rq & (rq-1)))
+ goto out;
+
+ v = (ffs(rq) - 8) << 12;
+
+ cap = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!cap)
+ goto out;
+
+ err = pci_read_config_word(dev, cap + PCI_EXP_DEVCTL, &ctl);
+ if (err)
+ goto out;
+
+ if ((ctl & PCI_EXP_DEVCTL_READRQ) != v) {
+ ctl &= ~PCI_EXP_DEVCTL_READRQ;
+ ctl |= v;
+ err = pci_write_config_dword(dev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+
+out:
+ return err;
+}
+EXPORT_SYMBOL(pcie_set_readrq);
+
+/**
* pci_select_bars - Make BAR mask from the type of resource
* @dev: the PCI device for which BAR mask is made
* @flags: resource type mask to be selected
@@ -1442,6 +1619,7 @@ EXPORT_SYMBOL(pci_release_selected_regions);
EXPORT_SYMBOL(pci_request_selected_regions);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
+EXPORT_SYMBOL(pci_try_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
EXPORT_SYMBOL_GPL(pci_intx);
EXPORT_SYMBOL(pci_set_dma_mask);
diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
index 3f37a60a6438..c3bde588aa13 100644
--- a/drivers/pci/pcie/aer/Kconfig
+++ b/drivers/pci/pcie/aer/Kconfig
@@ -4,7 +4,7 @@
config PCIEAER
boolean "Root Port Advanced Error Reporting support"
- depends on PCIEPORTBUS && ACPI
+ depends on PCIEPORTBUS
default y
help
This enables PCI Express Root Port Advanced Error Reporting
diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile
index 15a4f40d520b..8da3bd8455a8 100644
--- a/drivers/pci/pcie/aer/Makefile
+++ b/drivers/pci/pcie/aer/Makefile
@@ -4,5 +4,6 @@
obj-$(CONFIG_PCIEAER) += aerdriver.o
-aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdrv_acpi.o
+aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o
+aerdriver-$(CONFIG_ACPI) += aerdrv_acpi.o
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index db6ad8e763ac..ad90a01b0dfc 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -148,16 +148,15 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
{
struct aer_rpc *rpc;
- if (!(rpc = kmalloc(sizeof(struct aer_rpc),
+ if (!(rpc = kzalloc(sizeof(struct aer_rpc),
GFP_KERNEL)))
return NULL;
- memset(rpc, 0, sizeof(struct aer_rpc));
/*
* Initialize Root lock access, e_lock, to Root Error Status Reg,
* Root Error ID Reg, and Root error producer/consumer index.
*/
- rpc->e_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&rpc->e_lock);
rpc->rpd = dev;
INIT_WORK(&rpc->dpc_handler, aer_isr);
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 5cca394d5999..c7ad68b6c6d6 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -19,10 +19,6 @@
#define AER_ERROR_MASK 0x001fffff
#define AER_ERROR(d) (d & AER_ERROR_MASK)
-#define OSC_METHOD_RUN_SUCCESS 0
-#define OSC_METHOD_NOT_SUPPORTED 1
-#define OSC_METHOD_RUN_FAILURE 2
-
/* Root Error Status Register Bits */
#define ROOT_ERR_STATUS_MASKS 0x0f
@@ -121,6 +117,14 @@ extern void aer_delete_rootport(struct aer_rpc *rpc);
extern int aer_init(struct pcie_device *dev);
extern void aer_isr(struct work_struct *work);
extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
-extern int aer_osc_setup(struct pci_dev *dev);
+
+#ifdef CONFIG_ACPI
+extern int aer_osc_setup(struct pcie_device *pciedev);
+#else
+static inline int aer_osc_setup(struct pcie_device *pciedev)
+{
+ return 0;
+}
+#endif
#endif //_AERDRV_H_
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index fa68e89ebec9..1a1eb45a779e 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -20,19 +20,18 @@
/**
* aer_osc_setup - run ACPI _OSC method
+ * @pciedev: pcie_device which AER is being enabled on
*
- * Return:
- * Zero if success. Nonzero for otherwise.
+ * @return: Zero on success. Nonzero otherwise.
*
* Invoked when PCIE bus loads AER service driver. To avoid conflict with
* BIOS AER support requires BIOS to yield AER control to OS native driver.
**/
-int aer_osc_setup(struct pci_dev *dev)
+int aer_osc_setup(struct pcie_device *pciedev)
{
- int retval = OSC_METHOD_RUN_SUCCESS;
- acpi_status status;
- acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
- struct pci_dev *pdev = dev;
+ acpi_status status = AE_NOT_FOUND;
+ struct pci_dev *pdev = pciedev->port;
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&pdev->dev);
struct pci_bus *parent;
while (!handle) {
@@ -50,19 +49,20 @@ int aer_osc_setup(struct pci_dev *dev)
pdev = parent->self;
}
- if (!handle)
- return OSC_METHOD_NOT_SUPPORTED;
+ if (handle) {
+ pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
+ status = pci_osc_control_set(handle,
+ OSC_PCI_EXPRESS_AER_CONTROL |
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ }
- pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
- status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL |
- OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
if (ACPI_FAILURE(status)) {
- if (status == AE_SUPPORT)
- retval = OSC_METHOD_NOT_SUPPORTED;
- else
- retval = OSC_METHOD_RUN_FAILURE;
+ printk(KERN_DEBUG "AER service couldn't init device %s - %s\n",
+ pciedev->device.bus_id,
+ (status == AE_SUPPORT || status == AE_NOT_FOUND) ?
+ "no _OSC support" : "Run ACPI _OSC fails");
+ return -1;
}
- return retval;
+ return 0;
}
-
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 08e13033ced8..92a8469b21ba 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -22,8 +22,6 @@
#include <linux/errno.h>
#include <linux/pm.h>
#include <linux/suspend.h>
-#include <linux/acpi.h>
-#include <linux/pci-acpi.h>
#include <linux/delay.h>
#include "aerdrv.h"
@@ -119,6 +117,21 @@ int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
return 0;
}
+int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
+{
+ int pos;
+ u32 status;
+
+ pos = pci_find_aer_capability(dev);
+ if (!pos)
+ return -EIO;
+
+ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, &status);
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, status);
+
+ return 0;
+}
+
static int find_device_iter(struct device *device, void *data)
{
struct pci_dev *dev;
@@ -733,20 +746,8 @@ void aer_delete_rootport(struct aer_rpc *rpc)
**/
int aer_init(struct pcie_device *dev)
{
- int status;
-
- /* Run _OSC Method */
- status = aer_osc_setup(dev->port);
-
- if(status != OSC_METHOD_RUN_SUCCESS) {
- printk(KERN_DEBUG "%s: AER service init fails - %s\n",
- __FUNCTION__,
- (status == OSC_METHOD_NOT_SUPPORTED) ?
- "No ACPI _OSC support" : "Run ACPI _OSC fails");
-
- if (!forceload)
- return status;
- }
+ if (aer_osc_setup(dev) && !forceload)
+ return -ENXIO;
return AER_SUCCESS;
}
@@ -755,4 +756,5 @@ EXPORT_SYMBOL_GPL(pci_find_aer_capability);
EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
+EXPORT_SYMBOL_GPL(pci_cleanup_aer_correct_error_status);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index e48fcf089621..34b8dae0d90f 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -22,6 +22,18 @@ EXPORT_SYMBOL(pci_root_buses);
LIST_HEAD(pci_devices);
+/*
+ * Some device drivers need know if pci is initiated.
+ * Basically, we think pci is not initiated when there
+ * is no device in list of pci_devices.
+ */
+int no_pci_devices(void)
+{
+ return list_empty(&pci_devices);
+}
+
+EXPORT_SYMBOL(no_pci_devices);
+
#ifdef HAVE_PCI_LEGACY
/**
* pci_create_legacy_files - create legacy I/O port and memory files
@@ -39,7 +51,6 @@ static void pci_create_legacy_files(struct pci_bus *b)
b->legacy_io->attr.name = "legacy_io";
b->legacy_io->size = 0xffff;
b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
- b->legacy_io->attr.owner = THIS_MODULE;
b->legacy_io->read = pci_read_legacy_io;
b->legacy_io->write = pci_write_legacy_io;
class_device_create_bin_file(&b->class_dev, b->legacy_io);
@@ -49,7 +60,6 @@ static void pci_create_legacy_files(struct pci_bus *b)
b->legacy_mem->attr.name = "legacy_mem";
b->legacy_mem->size = 1024*1024;
b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
- b->legacy_mem->attr.owner = THIS_MODULE;
b->legacy_mem->mmap = pci_mmap_legacy_mem;
class_device_create_bin_file(&b->class_dev, b->legacy_mem);
}
@@ -656,7 +666,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
pcibios_assign_all_busses() ? " " :
" (try 'pci=assign-busses')");
printk(KERN_WARNING "Please report the result to "
- "linux-kernel to fix this permanently\n");
+ "<bk@suse.de> to fix this permanently\n");
}
bus = bus->parent;
}
@@ -702,6 +712,7 @@ static int pci_setup_device(struct pci_dev * dev)
dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
+ dev->revision = class & 0xff;
class >>= 8; /* upper 3 bytes */
dev->class = class;
class >>= 8;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 0425a7b7350d..90adc62d07ff 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -11,7 +11,7 @@
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-
+#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include "pci.h"
@@ -480,7 +480,6 @@ static int __init pci_proc_init(void)
__initcall(pci_proc_init);
#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_proc_attach_device);
EXPORT_SYMBOL(pci_proc_detach_bus);
#endif
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 01d8f8a8843c..c559085c89a5 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -587,10 +587,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_v
*/
static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
{
- u8 rev;
-
- pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
- if (rev >= 0x02) {
+ if (dev->revision >= 0x02) {
printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
printk(KERN_WARNING " : booting with the \"noapic\" option.\n");
}
@@ -610,13 +607,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw );
#define AMD8131_NIOAMODE_BIT 0
static void quirk_amd_8131_ioapic(struct pci_dev *dev)
{
- unsigned char revid, tmp;
+ unsigned char tmp;
if (nr_ioapics == 0)
return;
- pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
- if (revid == AMD8131_revA0 || revid == AMD8131_revB0) {
+ if (dev->revision == AMD8131_revA0 || dev->revision == AMD8131_revB0) {
printk(KERN_INFO "Fixing up AMD8131 IOAPIC mode\n");
pci_read_config_byte( dev, AMD8131_MISC, &tmp);
tmp &= ~(1 << AMD8131_NIOAMODE_BIT);
@@ -627,6 +623,22 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_
DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
#endif /* CONFIG_X86_IO_APIC */
+/*
+ * Some settings of MMRBC can lead to data corruption so block changes.
+ * See AMD 8131 HyperTransport PCI-X Tunnel Revision Guide
+ */
+static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
+{
+ unsigned char revid;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
+ if (dev->subordinate && revid <= 0x12) {
+ printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
+ "MMRBC\n", revid);
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_mmrbc);
/*
* FIXME: it is questionable that quirk_via_acpi
@@ -843,10 +855,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, qu
static void quirk_disable_pxb(struct pci_dev *pdev)
{
u16 config;
- u8 rev;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
- if (rev != 0x04) /* Only C0 requires this */
+ if (pdev->revision != 0x04) /* Only C0 requires this */
return;
pci_read_config_word(pdev, 0x40, &config);
if (config & (1<<6)) {
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index d087e0817715..dbbcc04abd1a 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -54,6 +54,49 @@ static void pci_disable_rom(struct pci_dev *pdev)
}
/**
+ * pci_get_rom_size - obtain the actual size of the ROM image
+ * @rom: kernel virtual pointer to image of ROM
+ * @size: size of PCI window
+ * return: size of actual ROM image
+ *
+ * Determine the actual length of the ROM image.
+ * The PCI window size could be much larger than the
+ * actual image size.
+ */
+size_t pci_get_rom_size(void __iomem *rom, size_t size)
+{
+ void __iomem *image;
+ int last_image;
+
+ image = rom;
+ do {
+ void __iomem *pds;
+ /* Standard PCI ROMs start out with these bytes 55 AA */
+ if (readb(image) != 0x55)
+ break;
+ if (readb(image + 1) != 0xAA)
+ break;
+ /* get the PCI data structure and check its signature */
+ pds = image + readw(image + 24);
+ if (readb(pds) != 'P')
+ break;
+ if (readb(pds + 1) != 'C')
+ break;
+ if (readb(pds + 2) != 'I')
+ break;
+ if (readb(pds + 3) != 'R')
+ break;
+ last_image = readb(pds + 21) & 0x80;
+ /* this length is reliable */
+ image += readw(pds + 16) * 512;
+ } while (!last_image);
+
+ /* never return a size larger than the PCI resource window */
+ /* there are known ROMs that get the size wrong */
+ return min((size_t)(image - rom), size);
+}
+
+/**
* pci_map_rom - map a PCI ROM to kernel space
* @pdev: pointer to pci device struct
* @size: pointer to receive size of pci window over ROM
@@ -68,8 +111,6 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
loff_t start;
void __iomem *rom;
- void __iomem *image;
- int last_image;
/*
* IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
@@ -117,33 +158,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
* size is much larger than the actual size of the ROM.
* True size is important if the ROM is going to be copied.
*/
- image = rom;
- do {
- void __iomem *pds;
- /* Standard PCI ROMs start out with these bytes 55 AA */
- if (readb(image) != 0x55)
- break;
- if (readb(image + 1) != 0xAA)
- break;
- /* get the PCI data structure and check its signature */
- pds = image + readw(image + 24);
- if (readb(pds) != 'P')
- break;
- if (readb(pds + 1) != 'C')
- break;
- if (readb(pds + 2) != 'I')
- break;
- if (readb(pds + 3) != 'R')
- break;
- last_image = readb(pds + 21) & 0x80;
- /* this length is reliable */
- image += readw(pds + 16) * 512;
- } while (!last_image);
-
- /* never return a size larger than the PCI resource window */
- /* there are known ROMs that get the size wrong */
- *size = min((size_t)(image - rom), *size);
-
+ *size = pci_get_rom_size(rom, *size);
return rom;
}
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index c13232435dc0..c6e79d01ce3d 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -139,12 +139,14 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
}
/**
- * pci_get_bus_and_slot - locate PCI device from a given PCI slot
+ * pci_get_bus_and_slot - locate PCI device from a given PCI bus & slot
* @bus: number of PCI bus on which desired PCI device resides
* @devfn: encodes number of PCI slot in which the desired PCI
* device resides and the logical device number within that slot
* in case of multi-function devices.
*
+ * Note: the bus/slot search is limited to PCI domain (segment) 0.
+ *
* Given a PCI bus and slot/function number, the desired PCI device
* is located in system global list of PCI devices. If the device
* is found, a pointer to its data structure is returned. If no
@@ -157,7 +159,8 @@ struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
struct pci_dev *dev = NULL;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
- if (dev->bus->number == bus && dev->devfn == devfn)
+ if (pci_domain_nr(dev->bus) == 0 &&
+ (dev->bus->number == bus && dev->devfn == devfn))
return dev;
}
return NULL;
@@ -199,7 +202,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
* can cause some machines to crash. So here we detect and flag that
* situation and bail out early.
*/
- if (unlikely(list_empty(&pci_devices)))
+ if (unlikely(no_pci_devices()))
return NULL;
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
@@ -274,7 +277,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
* can cause some machines to crash. So here we detect and flag that
* situation and bail out early.
*/
- if (unlikely(list_empty(&pci_devices)))
+ if (unlikely(no_pci_devices()))
return NULL;
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 5ec297d7a5b4..5e5191ec8de6 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -34,8 +34,6 @@
#define DBG(x...)
#endif
-#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1))
-
static void pbus_assign_resources_sorted(struct pci_bus *bus)
{
struct pci_dev *dev;
@@ -310,7 +308,7 @@ static void pbus_size_io(struct pci_bus *bus)
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
size = (size & 0xff) + ((size & ~0xffUL) << 2);
#endif
- size = ROUND_UP(size + size1, 4096);
+ size = ALIGN(size + size1, 4096);
if (!size) {
b_res->flags = 0;
return;
@@ -378,11 +376,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long
if (!align)
min_align = align1;
- else if (ROUND_UP(align + min_align, min_align) < align1)
+ else if (ALIGN(align + min_align, min_align) < align1)
min_align = align1 >> 1;
align += aligns[order];
}
- size = ROUND_UP(size, min_align);
+ size = ALIGN(size, min_align);
if (!size) {
b_res->flags = 0;
return 1;
diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c
index 9d37fec27f24..2ac050d7f8cf 100644
--- a/drivers/pci/syscall.c
+++ b/drivers/pci/syscall.c
@@ -23,14 +23,14 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn,
u8 byte;
u16 word;
u32 dword;
- long err, cfg_ret;
+ long err;
+ long cfg_ret;
- err = -EPERM;
if (!capable(CAP_SYS_ADMIN))
- goto error;
+ return -EPERM;
err = -ENODEV;
- dev = pci_find_slot(bus, dfn);
+ dev = pci_get_bus_and_slot(bus, dfn);
if (!dev)
goto error;
@@ -66,7 +66,8 @@ sys_pciconfig_read(unsigned long bus, unsigned long dfn,
case 4:
err = put_user(dword, (unsigned int __user *)buf);
break;
- };
+ }
+ pci_dev_put(dev);
return err;
error:
@@ -83,7 +84,8 @@ error:
case 4:
put_user(-1, (unsigned int __user *)buf);
break;
- };
+ }
+ pci_dev_put(dev);
return err;
}
@@ -101,7 +103,7 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- dev = pci_find_slot(bus, dfn);
+ dev = pci_get_bus_and_slot(bus, dfn);
if (!dev)
return -ENODEV;
@@ -137,8 +139,8 @@ sys_pciconfig_write(unsigned long bus, unsigned long dfn,
default:
err = -EINVAL;
break;
- };
+ }
unlock_kernel();
-
+ pci_dev_put(dev);
return err;
}
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 35f88649d3b7..c0c77f82d051 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -180,14 +180,15 @@ config TCIC
PCMCIA cards are plugged into. If unsure, say N.
config PCMCIA_M8XX
- tristate "MPC8xx PCMCIA support"
- depends on PCMCIA && PPC && 8xx
- select PCCARD_IODYN
- help
- Say Y here to include support for PowerPC 8xx series PCMCIA
- controller.
-
- This driver is also available as a module called m8xx_pcmcia.
+ tristate "MPC8xx PCMCIA support"
+ depends on PCMCIA && PPC && 8xx
+ select PCCARD_IODYN
+ select PCCARD_NONSTATIC
+ help
+ Say Y here to include support for PowerPC 8xx series PCMCIA
+ controller.
+
+ This driver is also available as a module called m8xx_pcmcia.
config HD64465_PCMCIA
tristate "HD64465 host bridge support"
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 50cad3a59a6c..7c93a108f9b8 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -651,6 +651,7 @@ static int pccardd(void *__skt)
add_wait_queue(&skt->thread_wait, &wait);
complete(&skt->thread_done);
+ set_freezable();
for (;;) {
unsigned long flags;
unsigned int events;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 143c6efc478a..a99607142fc8 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1127,6 +1127,34 @@ static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
#endif
+/************************ runtime PM support ***************************/
+
+static int pcmcia_dev_suspend(struct device *dev, pm_message_t state);
+static int pcmcia_dev_resume(struct device *dev);
+
+static int runtime_suspend(struct device *dev)
+{
+ int rc;
+
+ down(&dev->sem);
+ rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
+ up(&dev->sem);
+ if (!rc)
+ dev->power.power_state.event = PM_EVENT_SUSPEND;
+ return rc;
+}
+
+static void runtime_resume(struct device *dev)
+{
+ int rc;
+
+ down(&dev->sem);
+ rc = pcmcia_dev_resume(dev);
+ up(&dev->sem);
+ if (!rc)
+ dev->power.power_state.event = PM_EVENT_ON;
+}
+
/************************ per-device sysfs output ***************************/
#define pcmcia_device_attr(field, test, format) \
@@ -1173,9 +1201,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute
return -EINVAL;
if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
- ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
+ ret = runtime_suspend(dev);
else if (p_dev->suspended && !strncmp(buf, "on", 2))
- dpm_runtime_resume(dev);
+ runtime_resume(dev);
return ret ? ret : count;
}
@@ -1312,10 +1340,10 @@ static int pcmcia_bus_suspend_callback(struct device *dev, void * _data)
struct pcmcia_socket *skt = _data;
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- if (p_dev->socket != skt)
+ if (p_dev->socket != skt || p_dev->suspended)
return 0;
- return dpm_runtime_suspend(dev, PMSG_SUSPEND);
+ return runtime_suspend(dev);
}
static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
@@ -1323,10 +1351,10 @@ static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
struct pcmcia_socket *skt = _data;
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
- if (p_dev->socket != skt)
+ if (p_dev->socket != skt || !p_dev->suspended)
return 0;
- dpm_runtime_resume(dev);
+ runtime_resume(dev);
return 0;
}
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 9721ed7bf502..b01985498460 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -10,7 +10,7 @@
* Further fixes, v2.6 kernel port
* <marcelo.tosatti@cyclades.com>
*
- * Some fixes, additions (C) 2005 Montavista Software, Inc.
+ * Some fixes, additions (C) 2005-2007 Montavista Software, Inc.
* <vbordug@ru.mvista.com>
*
* "The ExCA standard specifies that socket controllers should provide
@@ -40,10 +40,6 @@
#include <linux/fcntl.h>
#include <linux/string.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/system.h>
-
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -51,11 +47,18 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/time.h>
#include <asm/mpc8xx.h>
#include <asm/8xx_immap.h>
#include <asm/irq.h>
+#include <asm/fs_pd.h>
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
@@ -110,7 +113,7 @@ MODULE_LICENSE("Dual MPL/GPL");
#define CONFIG_PCMCIA_SLOT_B
#endif
-#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
+#endif /* !defined(CONFIG_PCMCIA_SLOT_A) && !defined(CONFIG_PCMCIA_SLOT_B) */
#if defined(CONFIG_PCMCIA_SLOT_A) && defined(CONFIG_PCMCIA_SLOT_B)
@@ -143,30 +146,20 @@ MODULE_LICENSE("Dual MPL/GPL");
/* ------------------------------------------------------------------------- */
-#define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */
-#define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */
-#define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */
-
-#define PCMCIA_SCHLVL PCMCIA_INTERRUPT /* Status Change Interrupt Level */
-
+#define PCMCIA_MEM_WIN_BASE 0xe0000000 /* base address for memory window 0 */
+#define PCMCIA_MEM_WIN_SIZE 0x04000000 /* each memory window is 64 MByte */
+#define PCMCIA_IO_WIN_BASE _IO_BASE /* base address for io window 0 */
/* ------------------------------------------------------------------------- */
-/* 2.4.x and newer has this always in HZ */
-#define M8XX_BUSFREQ ((((bd_t *)&(__res))->bi_busfreq))
-
-static int pcmcia_schlvl = PCMCIA_SCHLVL;
+static int pcmcia_schlvl;
static DEFINE_SPINLOCK(events_lock);
-
#define PCMCIA_SOCKET_KEY_5V 1
#define PCMCIA_SOCKET_KEY_LV 2
/* look up table for pgcrx registers */
-static u32 *m8xx_pgcrx[2] = {
- &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcra,
- &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pgcrb
-};
+static u32 *m8xx_pgcrx[2];
/*
* This structure is used to address each window in the PCMCIA controller.
@@ -176,8 +169,8 @@ static u32 *m8xx_pgcrx[2] = {
*/
struct pcmcia_win {
- u32 br;
- u32 or;
+ u32 br;
+ u32 or;
};
/*
@@ -221,22 +214,27 @@ struct pcmcia_win {
/* we keep one lookup table per socket to check flags */
-#define PCMCIA_EVENTS_MAX 5 /* 4 max at a time + termination */
+#define PCMCIA_EVENTS_MAX 5 /* 4 max at a time + termination */
struct event_table {
u32 regbit;
u32 eventbit;
};
+static const char driver_name[] = "m8xx-pcmcia";
+
struct socket_info {
- void (*handler)(void *info, u32 events);
- void *info;
+ void (*handler) (void *info, u32 events);
+ void *info;
u32 slot;
+ pcmconf8xx_t *pcmcia;
+ u32 bus_freq;
+ int hwirq;
socket_state_t state;
struct pccard_mem_map mem_win[PCMCIA_MEM_WIN_NO];
- struct pccard_io_map io_win[PCMCIA_IO_WIN_NO];
+ struct pccard_io_map io_win[PCMCIA_IO_WIN_NO];
struct event_table events[PCMCIA_EVENTS_MAX];
struct pcmcia_socket socket;
};
@@ -250,8 +248,7 @@ static struct socket_info socket[PCMCIA_SOCKETS_NO];
#define M8XX_SIZES_NO 32
-static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] =
-{
+static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] = {
0x00000001, 0x00000002, 0x00000008, 0x00000004,
0x00000080, 0x00000040, 0x00000010, 0x00000020,
0x00008000, 0x00004000, 0x00001000, 0x00002000,
@@ -267,7 +264,7 @@ static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] =
static irqreturn_t m8xx_interrupt(int irq, void *dev);
-#define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */
+#define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */
/* ------------------------------------------------------------------------- */
/* board specific stuff: */
@@ -291,8 +288,9 @@ static int voltage_set(int slot, int vcc, int vpp)
{
u32 reg = 0;
- switch(vcc) {
- case 0: break;
+ switch (vcc) {
+ case 0:
+ break;
case 33:
reg |= BCSR1_PCVCTL4;
break;
@@ -303,11 +301,12 @@ static int voltage_set(int slot, int vcc, int vpp)
return 1;
}
- switch(vpp) {
- case 0: break;
+ switch (vpp) {
+ case 0:
+ break;
case 33:
case 50:
- if(vcc == vpp)
+ if (vcc == vpp)
reg |= BCSR1_PCVCTL6;
else
return 1;
@@ -318,25 +317,29 @@ static int voltage_set(int slot, int vcc, int vpp)
return 1;
}
- if(!((vcc == 50) || (vcc == 0)))
+ if (!((vcc == 50) || (vcc == 0)))
return 1;
/* first, turn off all power */
- out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 | BCSR1_PCVCTL5 | BCSR1_PCVCTL6 | BCSR1_PCVCTL7));
+ out_be32(((u32 *) RPX_CSR_ADDR),
+ in_be32(((u32 *) RPX_CSR_ADDR)) & ~(BCSR1_PCVCTL4 |
+ BCSR1_PCVCTL5 |
+ BCSR1_PCVCTL6 |
+ BCSR1_PCVCTL7));
/* enable new powersettings */
- out_be32(((u32 *)RPX_CSR_ADDR), in_be32(((u32 *)RPX_CSR_ADDR)) | reg);
+ out_be32(((u32 *) RPX_CSR_ADDR), in_be32(((u32 *) RPX_CSR_ADDR)) | reg);
return 0;
}
#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-#define hardware_enable(_slot_) /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_) /* No hardware to enable */
+#define hardware_disable(_slot_) /* No hardware to disable */
-#endif /* CONFIG_RPXCLASSIC */
+#endif /* CONFIG_RPXCLASSIC */
/* FADS Boards from Motorola */
@@ -348,43 +351,45 @@ static int voltage_set(int slot, int vcc, int vpp)
{
u32 reg = 0;
- switch(vcc) {
- case 0:
- break;
- case 33:
- reg |= BCSR1_PCCVCC0;
- break;
- case 50:
- reg |= BCSR1_PCCVCC1;
- break;
- default:
- return 1;
+ switch (vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= BCSR1_PCCVCC0;
+ break;
+ case 50:
+ reg |= BCSR1_PCCVCC1;
+ break;
+ default:
+ return 1;
}
- switch(vpp) {
- case 0:
- break;
- case 33:
- case 50:
- if(vcc == vpp)
- reg |= BCSR1_PCCVPP1;
- else
- return 1;
- break;
- case 120:
- if ((vcc == 33) || (vcc == 50))
- reg |= BCSR1_PCCVPP0;
- else
- return 1;
- default:
+ switch (vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if (vcc == vpp)
+ reg |= BCSR1_PCCVPP1;
+ else
return 1;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= BCSR1_PCCVPP0;
+ else
+ return 1;
+ default:
+ return 1;
}
/* first, turn off all power */
- out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK));
+ out_be32((u32 *) BCSR1,
+ in_be32((u32 *) BCSR1) & ~(BCSR1_PCCVCC_MASK |
+ BCSR1_PCCVPP_MASK));
/* enable new powersettings */
- out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) | reg);
+ out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | reg);
return 0;
}
@@ -393,12 +398,12 @@ static int voltage_set(int slot, int vcc, int vpp)
static void hardware_enable(int slot)
{
- out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~BCSR1_PCCEN);
+ out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) & ~BCSR1_PCCEN);
}
static void hardware_disable(int slot)
{
- out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) | BCSR1_PCCEN);
+ out_be32((u32 *) BCSR1, in_be32((u32 *) BCSR1) | BCSR1_PCCEN);
}
#endif
@@ -408,78 +413,21 @@ static void hardware_disable(int slot)
#if defined(CONFIG_MPC885ADS)
#define PCMCIA_BOARD_MSG "MPC885ADS"
+#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-static int voltage_set(int slot, int vcc, int vpp)
+static inline void hardware_enable(int slot)
{
- u32 reg = 0;
- unsigned *bcsr_io;
-
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
-
- switch(vcc) {
- case 0:
- break;
- case 33:
- reg |= BCSR1_PCCVCC0;
- break;
- case 50:
- reg |= BCSR1_PCCVCC1;
- break;
- default:
- goto out_unmap;
- }
-
- switch(vpp) {
- case 0:
- break;
- case 33:
- case 50:
- if(vcc == vpp)
- reg |= BCSR1_PCCVPP1;
- else
- goto out_unmap;
- break;
- case 120:
- if ((vcc == 33) || (vcc == 50))
- reg |= BCSR1_PCCVPP0;
- else
- goto out_unmap;
- default:
- goto out_unmap;
- }
-
- /* first, turn off all power */
- out_be32(bcsr_io, in_be32(bcsr_io) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK));
-
- /* enable new powersettings */
- out_be32(bcsr_io, in_be32(bcsr_io) | reg);
-
- iounmap(bcsr_io);
- return 0;
-
-out_unmap:
- iounmap(bcsr_io);
- return 1;
+ m8xx_pcmcia_ops.hw_ctrl(slot, 1);
}
-#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-
-static void hardware_enable(int slot)
+static inline void hardware_disable(int slot)
{
- unsigned *bcsr_io;
-
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
- out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_PCCEN);
- iounmap(bcsr_io);
+ m8xx_pcmcia_ops.hw_ctrl(slot, 0);
}
-static void hardware_disable(int slot)
+static inline int voltage_set(int slot, int vcc, int vpp)
{
- unsigned *bcsr_io;
-
- bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
- out_be32(bcsr_io, in_be32(bcsr_io) | BCSR1_PCCEN);
- iounmap(bcsr_io);
+ return m8xx_pcmcia_ops.voltage_set(slot, vcc, vpp);
}
#endif
@@ -495,52 +443,53 @@ static int voltage_set(int slot, int vcc, int vpp)
{
u8 reg = 0;
- switch(vcc) {
- case 0:
- break;
- case 33:
- reg |= CSR2_VCC_33;
- break;
- case 50:
- reg |= CSR2_VCC_50;
- break;
- default:
- return 1;
+ switch (vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= CSR2_VCC_33;
+ break;
+ case 50:
+ reg |= CSR2_VCC_50;
+ break;
+ default:
+ return 1;
}
- switch(vpp) {
- case 0:
- break;
- case 33:
- case 50:
- if(vcc == vpp)
- reg |= CSR2_VPP_VCC;
- else
- return 1;
- break;
- case 120:
- if ((vcc == 33) || (vcc == 50))
- reg |= CSR2_VPP_12;
- else
- return 1;
- default:
+ switch (vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if (vcc == vpp)
+ reg |= CSR2_VPP_VCC;
+ else
return 1;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= CSR2_VPP_12;
+ else
+ return 1;
+ default:
+ return 1;
}
/* first, turn off all power */
- out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK));
+ out_8((u8 *) MBX_CSR2_ADDR,
+ in_8((u8 *) MBX_CSR2_ADDR) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK));
/* enable new powersettings */
- out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) | reg);
+ out_8((u8 *) MBX_CSR2_ADDR, in_8((u8 *) MBX_CSR2_ADDR) | reg);
return 0;
}
#define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V
-#define hardware_enable(_slot_) /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
+#define hardware_enable(_slot_) /* No hardware to enable */
+#define hardware_disable(_slot_) /* No hardware to disable */
-#endif /* CONFIG_MBX */
+#endif /* CONFIG_MBX */
#if defined(CONFIG_PRxK)
#include <asm/cpld.h>
@@ -554,43 +503,46 @@ static int voltage_set(int slot, int vcc, int vpp)
u8 regread;
cpld_regs *ccpld = get_cpld();
- switch(vcc) {
- case 0:
- break;
- case 33:
- reg |= PCMCIA_VCC_33;
- break;
- case 50:
- reg |= PCMCIA_VCC_50;
- break;
- default:
- return 1;
+ switch (vcc) {
+ case 0:
+ break;
+ case 33:
+ reg |= PCMCIA_VCC_33;
+ break;
+ case 50:
+ reg |= PCMCIA_VCC_50;
+ break;
+ default:
+ return 1;
}
- switch(vpp) {
- case 0:
- break;
- case 33:
- case 50:
- if(vcc == vpp)
- reg |= PCMCIA_VPP_VCC;
- else
- return 1;
- break;
- case 120:
- if ((vcc == 33) || (vcc == 50))
- reg |= PCMCIA_VPP_12;
- else
- return 1;
- default:
+ switch (vpp) {
+ case 0:
+ break;
+ case 33:
+ case 50:
+ if (vcc == vpp)
+ reg |= PCMCIA_VPP_VCC;
+ else
return 1;
+ break;
+ case 120:
+ if ((vcc == 33) || (vcc == 50))
+ reg |= PCMCIA_VPP_12;
+ else
+ return 1;
+ default:
+ return 1;
}
reg = reg >> (slot << 2);
regread = in_8(&ccpld->fpga_pc_ctl);
- if (reg != (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
+ if (reg !=
+ (regread & ((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2)))) {
/* enable new powersettings */
- regread = regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >> (slot << 2));
+ regread =
+ regread & ~((PCMCIA_VCC_MASK | PCMCIA_VPP_MASK) >>
+ (slot << 2));
out_8(&ccpld->fpga_pc_ctl, reg | regread);
msleep(100);
}
@@ -599,52 +551,10 @@ static int voltage_set(int slot, int vcc, int vpp)
}
#define socket_get(_slot_) PCMCIA_SOCKET_KEY_LV
-#define hardware_enable(_slot_) /* No hardware to enable */
-#define hardware_disable(_slot_) /* No hardware to disable */
-
-#endif /* CONFIG_PRxK */
-
-static void m8xx_shutdown(void)
-{
- u32 m, i;
- struct pcmcia_win *w;
+#define hardware_enable(_slot_) /* No hardware to enable */
+#define hardware_disable(_slot_) /* No hardware to disable */
- for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
- w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
-
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, M8XX_PCMCIA_MASK(i));
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) & ~M8XX_PCMCIA_MASK(i));
-
- /* turn off interrupt and disable CxOE */
- out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
-
- /* turn off memory windows */
- for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
- out_be32(&w->or, 0); /* set to not valid */
- w++;
- }
-
- /* turn off voltage */
- voltage_set(i, 0, 0);
-
- /* disable external hardware */
- hardware_disable(i);
- }
-
- free_irq(pcmcia_schlvl, NULL);
-}
-
-static struct device_driver m8xx_driver = {
- .name = "m8xx-pcmcia",
- .bus = &platform_bus_type,
- .suspend = pcmcia_socket_dev_suspend,
- .resume = pcmcia_socket_dev_resume,
-};
-
-static struct platform_device m8xx_device = {
- .name = "m8xx-pcmcia",
- .id = 0,
-};
+#endif /* CONFIG_PRxK */
static u32 pending_events[PCMCIA_SOCKETS_NO];
static DEFINE_SPINLOCK(pending_event_lock);
@@ -654,24 +564,25 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
struct socket_info *s;
struct event_table *e;
unsigned int i, events, pscr, pipr, per;
+ pcmconf8xx_t *pcmcia = socket[0].pcmcia;
dprintk("Interrupt!\n");
/* get interrupt sources */
- pscr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr);
- pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr);
- per = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per);
+ pscr = in_be32(&pcmcia->pcmc_pscr);
+ pipr = in_be32(&pcmcia->pcmc_pipr);
+ per = in_be32(&pcmcia->pcmc_per);
- for(i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+ for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
s = &socket[i];
e = &s->events[0];
events = 0;
- while(e->regbit) {
- if(pscr & e->regbit)
+ while (e->regbit) {
+ if (pscr & e->regbit)
events |= e->eventbit;
- e++;
+ e++;
}
/*
@@ -679,13 +590,11 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
* not too nice done,
* we depend on that CD2 is the bit to the left of CD1...
*/
- if(events & SS_DETECT)
- if(((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
- (pipr & M8XX_PCMCIA_CD1(i)))
- {
+ if (events & SS_DETECT)
+ if (((pipr & M8XX_PCMCIA_CD2(i)) >> 1) ^
+ (pipr & M8XX_PCMCIA_CD1(i))) {
events &= ~SS_DETECT;
}
-
#ifdef PCMCIA_GLITCHY_CD
/*
* I've experienced CD problems with my ADS board.
@@ -693,24 +602,23 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
* real change of Card detection.
*/
- if((events & SS_DETECT) &&
- ((pipr &
- (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
- (s->state.Vcc | s->state.Vpp)) {
+ if ((events & SS_DETECT) &&
+ ((pipr &
+ (M8XX_PCMCIA_CD2(i) | M8XX_PCMCIA_CD1(i))) == 0) &&
+ (s->state.Vcc | s->state.Vpp)) {
events &= ~SS_DETECT;
/*printk( "CD glitch workaround - CD = 0x%08x!\n",
- (pipr & (M8XX_PCMCIA_CD2(i)
- | M8XX_PCMCIA_CD1(i))));*/
+ (pipr & (M8XX_PCMCIA_CD2(i)
+ | M8XX_PCMCIA_CD1(i)))); */
}
#endif
/* call the handler */
dprintk("slot %u: events = 0x%02x, pscr = 0x%08x, "
- "pipr = 0x%08x\n",
- i, events, pscr, pipr);
+ "pipr = 0x%08x\n", i, events, pscr, pipr);
- if(events) {
+ if (events) {
spin_lock(&pending_event_lock);
pending_events[i] |= events;
spin_unlock(&pending_event_lock);
@@ -724,7 +632,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
per &= ~M8XX_PCMCIA_RDY_L(0);
per &= ~M8XX_PCMCIA_RDY_L(1);
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, per);
+ out_be32(&pcmcia->pcmc_per, per);
if (events)
pcmcia_parse_events(&socket[i].socket, events);
@@ -732,7 +640,7 @@ static irqreturn_t m8xx_interrupt(int irq, void *dev)
}
/* clear the interrupt sources */
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, pscr);
+ out_be32(&pcmcia->pcmc_pscr, pscr);
dprintk("Interrupt done.\n");
@@ -743,21 +651,21 @@ static u32 m8xx_get_graycode(u32 size)
{
u32 k;
- for(k = 0; k < M8XX_SIZES_NO; k++)
- if(m8xx_size_to_gray[k] == size)
+ for (k = 0; k < M8XX_SIZES_NO; k++)
+ if (m8xx_size_to_gray[k] == size)
break;
- if((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
+ if ((k == M8XX_SIZES_NO) || (m8xx_size_to_gray[k] == -1))
k = -1;
return k;
}
-static u32 m8xx_get_speed(u32 ns, u32 is_io)
+static u32 m8xx_get_speed(u32 ns, u32 is_io, u32 bus_freq)
{
u32 reg, clocks, psst, psl, psht;
- if(!ns) {
+ if (!ns) {
/*
* We get called with IO maps setup to 0ns
@@ -765,10 +673,10 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io)
* They should be 255ns.
*/
- if(is_io)
+ if (is_io)
ns = 255;
else
- ns = 100; /* fast memory if 0 */
+ ns = 100; /* fast memory if 0 */
}
/*
@@ -779,23 +687,23 @@ static u32 m8xx_get_speed(u32 ns, u32 is_io)
/* how we want to adjust the timing - in percent */
-#define ADJ 180 /* 80 % longer accesstime - to be sure */
+#define ADJ 180 /* 80 % longer accesstime - to be sure */
- clocks = ((M8XX_BUSFREQ / 1000) * ns) / 1000;
- clocks = (clocks * ADJ) / (100*1000);
- if(clocks >= PCMCIA_BMT_LIMIT) {
- printk( "Max access time limit reached\n");
- clocks = PCMCIA_BMT_LIMIT-1;
+ clocks = ((bus_freq / 1000) * ns) / 1000;
+ clocks = (clocks * ADJ) / (100 * 1000);
+ if (clocks >= PCMCIA_BMT_LIMIT) {
+ printk("Max access time limit reached\n");
+ clocks = PCMCIA_BMT_LIMIT - 1;
}
- psst = clocks / 7; /* setup time */
- psht = clocks / 7; /* hold time */
- psl = (clocks * 5) / 7; /* strobe length */
+ psst = clocks / 7; /* setup time */
+ psht = clocks / 7; /* hold time */
+ psl = (clocks * 5) / 7; /* strobe length */
psst += clocks - (psst + psht + psl);
- reg = psst << 12;
- reg |= psl << 7;
+ reg = psst << 12;
+ reg |= psl << 7;
reg |= psht << 16;
return reg;
@@ -806,11 +714,12 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
int lsock = container_of(sock, struct socket_info, socket)->slot;
struct socket_info *s = &socket[lsock];
unsigned int pipr, reg;
+ pcmconf8xx_t *pcmcia = s->pcmcia;
- pipr = in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pipr);
+ pipr = in_be32(&pcmcia->pcmc_pipr);
- *value = ((pipr & (M8XX_PCMCIA_CD1(lsock)
- | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
+ *value = ((pipr & (M8XX_PCMCIA_CD1(lsock)
+ | M8XX_PCMCIA_CD2(lsock))) == 0) ? SS_DETECT : 0;
*value |= (pipr & M8XX_PCMCIA_WP(lsock)) ? SS_WRPROT : 0;
if (s->state.flags & SS_IOCARD)
@@ -894,16 +803,16 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
/* read out VS1 and VS2 */
reg = (pipr & M8XX_PCMCIA_VS_MASK(lsock))
- >> M8XX_PCMCIA_VS_SHIFT(lsock);
+ >> M8XX_PCMCIA_VS_SHIFT(lsock);
- if(socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) {
- switch(reg) {
+ if (socket_get(lsock) == PCMCIA_SOCKET_KEY_LV) {
+ switch (reg) {
case 1:
*value |= SS_3VCARD;
- break; /* GND, NC - 3.3V only */
+ break; /* GND, NC - 3.3V only */
case 2:
*value |= SS_XVCARD;
- break; /* NC. GND - x.xV only */
+ break; /* NC. GND - x.xV only */
};
}
@@ -911,27 +820,29 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value)
return 0;
}
-static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
+static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t * state)
{
int lsock = container_of(sock, struct socket_info, socket)->slot;
struct socket_info *s = &socket[lsock];
struct event_table *e;
unsigned int reg;
unsigned long flags;
+ pcmconf8xx_t *pcmcia = socket[0].pcmcia;
- dprintk( "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
- "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
- state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+ dprintk("SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+ "io_irq %d, csc_mask %#2.2x)\n", lsock, state->flags,
+ state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
/* First, set voltage - bail out if invalid */
- if(voltage_set(lsock, state->Vcc, state->Vpp))
+ if (voltage_set(lsock, state->Vcc, state->Vpp))
return -EINVAL;
/* Take care of reset... */
- if(state->flags & SS_RESET)
- out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET); /* active high */
+ if (state->flags & SS_RESET)
+ out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXRESET); /* active high */
else
- out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET);
+ out_be32(M8XX_PGCRX(lsock),
+ in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXRESET);
/* ... and output enable. */
@@ -943,10 +854,11 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
no pullups are present -> the cards act wierd.
So right now the buffers are enabled if the power is on. */
- if(state->Vcc || state->Vpp)
- out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE); /* active low */
+ if (state->Vcc || state->Vpp)
+ out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & ~M8XX_PGCRX_CXOE); /* active low */
else
- out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE);
+ out_be32(M8XX_PGCRX(lsock),
+ in_be32(M8XX_PGCRX(lsock)) | M8XX_PGCRX_CXOE);
/*
* We'd better turn off interrupts before
@@ -963,17 +875,17 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
e = &s->events[0];
reg = 0;
- if(state->csc_mask & SS_DETECT) {
+ if (state->csc_mask & SS_DETECT) {
e->eventbit = SS_DETECT;
reg |= e->regbit = (M8XX_PCMCIA_CD2(lsock)
| M8XX_PCMCIA_CD1(lsock));
e++;
}
- if(state->flags & SS_IOCARD) {
+ if (state->flags & SS_IOCARD) {
/*
* I/O card
*/
- if(state->csc_mask & SS_STSCHG) {
+ if (state->csc_mask & SS_STSCHG) {
e->eventbit = SS_STSCHG;
reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
e++;
@@ -981,8 +893,10 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
/*
* If io_irq is non-zero we should enable irq.
*/
- if(state->io_irq) {
- out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) | mk_int_int_mask(state->io_irq) << 24);
+ if (state->io_irq) {
+ out_be32(M8XX_PGCRX(lsock),
+ in_be32(M8XX_PGCRX(lsock)) |
+ mk_int_int_mask(s->hwirq) << 24);
/*
* Strange thing here:
* The manual does not tell us which interrupt
@@ -993,33 +907,32 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
* have to be cleared in PSCR in the interrupt handler.
*/
reg |= M8XX_PCMCIA_RDY_L(lsock);
- }
- else
- out_be32(M8XX_PGCRX(lsock), in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff);
- }
- else {
+ } else
+ out_be32(M8XX_PGCRX(lsock),
+ in_be32(M8XX_PGCRX(lsock)) & 0x00ffffff);
+ } else {
/*
* Memory card
*/
- if(state->csc_mask & SS_BATDEAD) {
+ if (state->csc_mask & SS_BATDEAD) {
e->eventbit = SS_BATDEAD;
reg |= e->regbit = M8XX_PCMCIA_BVD1(lsock);
e++;
}
- if(state->csc_mask & SS_BATWARN) {
+ if (state->csc_mask & SS_BATWARN) {
e->eventbit = SS_BATWARN;
reg |= e->regbit = M8XX_PCMCIA_BVD2(lsock);
e++;
}
/* What should I trigger on - low/high,raise,fall? */
- if(state->csc_mask & SS_READY) {
+ if (state->csc_mask & SS_READY) {
e->eventbit = SS_READY;
- reg |= e->regbit = 0; //??
+ reg |= e->regbit = 0; //??
e++;
}
}
- e->regbit = 0; /* terminate list */
+ e->regbit = 0; /* terminate list */
/*
* Clear the status changed .
@@ -1027,7 +940,7 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
* Writing ones will clear the bits.
*/
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr, reg);
+ out_be32(&pcmcia->pcmc_pscr, reg);
/*
* Write the mask.
@@ -1036,15 +949,10 @@ static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
* Ones will enable the interrupt.
*/
- /*
- reg |= ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per
- & M8XX_PCMCIA_MASK(lsock);
- */
-
- reg |= in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) &
- (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
-
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per, reg);
+ reg |=
+ in_be32(&pcmcia->
+ pcmc_per) & (M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
+ out_be32(&pcmcia->pcmc_per, reg);
spin_unlock_irqrestore(&events_lock, flags);
@@ -1062,66 +970,68 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
struct socket_info *s = &socket[lsock];
struct pcmcia_win *w;
unsigned int reg, winnr;
+ pcmconf8xx_t *pcmcia = s->pcmcia;
#define M8XX_SIZE (io->stop - io->start + 1)
#define M8XX_BASE (PCMCIA_IO_WIN_BASE + io->start)
- dprintk( "SetIOMap(%d, %d, %#2.2x, %d ns, "
- "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
- io->speed, io->start, io->stop);
+ dprintk("SetIOMap(%d, %d, %#2.2x, %d ns, "
+ "%#4.4x-%#4.4x)\n", lsock, io->map, io->flags,
+ io->speed, io->start, io->stop);
if ((io->map >= PCMCIA_IO_WIN_NO) || (io->start > 0xffff)
|| (io->stop > 0xffff) || (io->stop < io->start))
return -EINVAL;
- if((reg = m8xx_get_graycode(M8XX_SIZE)) == -1)
+ if ((reg = m8xx_get_graycode(M8XX_SIZE)) == -1)
return -EINVAL;
- if(io->flags & MAP_ACTIVE) {
+ if (io->flags & MAP_ACTIVE) {
- dprintk( "io->flags & MAP_ACTIVE\n");
+ dprintk("io->flags & MAP_ACTIVE\n");
winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
- + (lsock * PCMCIA_IO_WIN_NO) + io->map;
+ + (lsock * PCMCIA_IO_WIN_NO) + io->map;
/* setup registers */
- w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+ w = (void *)&pcmcia->pcmc_pbr0;
w += winnr;
- out_be32(&w->or, 0); /* turn off window first */
+ out_be32(&w->or, 0); /* turn off window first */
out_be32(&w->br, M8XX_BASE);
reg <<= 27;
- reg |= M8XX_PCMCIA_POR_IO |(lsock << 2);
+ reg |= M8XX_PCMCIA_POR_IO | (lsock << 2);
- reg |= m8xx_get_speed(io->speed, 1);
+ reg |= m8xx_get_speed(io->speed, 1, s->bus_freq);
- if(io->flags & MAP_WRPROT)
+ if (io->flags & MAP_WRPROT)
reg |= M8XX_PCMCIA_POR_WRPROT;
- if(io->flags & (MAP_16BIT | MAP_AUTOSZ))
+ /*if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) */
+ if (io->flags & MAP_16BIT)
reg |= M8XX_PCMCIA_POR_16BIT;
- if(io->flags & MAP_ACTIVE)
+ if (io->flags & MAP_ACTIVE)
reg |= M8XX_PCMCIA_POR_VALID;
out_be32(&w->or, reg);
dprintk("Socket %u: Mapped io window %u at %#8.8x, "
- "OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
+ "OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
} else {
/* shutdown IO window */
winnr = (PCMCIA_MEM_WIN_NO * PCMCIA_SOCKETS_NO)
- + (lsock * PCMCIA_IO_WIN_NO) + io->map;
+ + (lsock * PCMCIA_IO_WIN_NO) + io->map;
/* setup registers */
- w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+ w = (void *)&pcmcia->pcmc_pbr0;
w += winnr;
- out_be32(&w->or, 0); /* turn off window */
- out_be32(&w->br, 0); /* turn off base address */
+ out_be32(&w->or, 0); /* turn off window */
+ out_be32(&w->br, 0); /* turn off base address */
dprintk("Socket %u: Unmapped io window %u at %#8.8x, "
"OR = %#8.8x.\n", lsock, io->map, w->br, w->or);
@@ -1129,35 +1039,35 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
/* copy the struct and modify the copy */
s->io_win[io->map] = *io;
- s->io_win[io->map].flags &= (MAP_WRPROT
- | MAP_16BIT
- | MAP_ACTIVE);
+ s->io_win[io->map].flags &= (MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
dprintk("SetIOMap exit\n");
return 0;
}
-static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
+static int m8xx_set_mem_map(struct pcmcia_socket *sock,
+ struct pccard_mem_map *mem)
{
int lsock = container_of(sock, struct socket_info, socket)->slot;
struct socket_info *s = &socket[lsock];
struct pcmcia_win *w;
struct pccard_mem_map *old;
unsigned int reg, winnr;
+ pcmconf8xx_t *pcmcia = s->pcmcia;
- dprintk( "SetMemMap(%d, %d, %#2.2x, %d ns, "
- "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
- mem->speed, mem->static_start, mem->card_start);
+ dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
+ "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+ mem->speed, mem->static_start, mem->card_start);
if ((mem->map >= PCMCIA_MEM_WIN_NO)
-// || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
+// || ((mem->s) >= PCMCIA_MEM_WIN_SIZE)
|| (mem->card_start >= 0x04000000)
- || (mem->static_start & 0xfff) /* 4KByte resolution */
- || (mem->card_start & 0xfff))
+ || (mem->static_start & 0xfff) /* 4KByte resolution */
+ ||(mem->card_start & 0xfff))
return -EINVAL;
- if((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) {
- printk( "Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE);
+ if ((reg = m8xx_get_graycode(PCMCIA_MEM_WIN_SIZE)) == -1) {
+ printk("Cannot set size to 0x%08x.\n", PCMCIA_MEM_WIN_SIZE);
return -EINVAL;
}
reg <<= 27;
@@ -1166,50 +1076,47 @@ static int m8xx_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
/* Setup the window in the pcmcia controller */
- w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
+ w = (void *)&pcmcia->pcmc_pbr0;
w += winnr;
reg |= lsock << 2;
- reg |= m8xx_get_speed(mem->speed, 0);
+ reg |= m8xx_get_speed(mem->speed, 0, s->bus_freq);
- if(mem->flags & MAP_ATTRIB)
- reg |= M8XX_PCMCIA_POR_ATTRMEM;
+ if (mem->flags & MAP_ATTRIB)
+ reg |= M8XX_PCMCIA_POR_ATTRMEM;
- if(mem->flags & MAP_WRPROT)
+ if (mem->flags & MAP_WRPROT)
reg |= M8XX_PCMCIA_POR_WRPROT;
- if(mem->flags & MAP_16BIT)
+ if (mem->flags & MAP_16BIT)
reg |= M8XX_PCMCIA_POR_16BIT;
- if(mem->flags & MAP_ACTIVE)
+ if (mem->flags & MAP_ACTIVE)
reg |= M8XX_PCMCIA_POR_VALID;
out_be32(&w->or, reg);
dprintk("Socket %u: Mapped memory window %u at %#8.8x, "
- "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or);
+ "OR = %#8.8x.\n", lsock, mem->map, w->br, w->or);
- if(mem->flags & MAP_ACTIVE) {
+ if (mem->flags & MAP_ACTIVE) {
/* get the new base address */
mem->static_start = PCMCIA_MEM_WIN_BASE +
- (PCMCIA_MEM_WIN_SIZE * winnr)
- + mem->card_start;
+ (PCMCIA_MEM_WIN_SIZE * winnr)
+ + mem->card_start;
}
dprintk("SetMemMap(%d, %d, %#2.2x, %d ns, "
- "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
- mem->speed, mem->static_start, mem->card_start);
+ "%#5.5lx, %#5.5x)\n", lsock, mem->map, mem->flags,
+ mem->speed, mem->static_start, mem->card_start);
/* copy the struct and modify the copy */
old = &s->mem_win[mem->map];
*old = *mem;
- old->flags &= (MAP_ATTRIB
- | MAP_WRPROT
- | MAP_16BIT
- | MAP_ACTIVE);
+ old->flags &= (MAP_ATTRIB | MAP_WRPROT | MAP_16BIT | MAP_ACTIVE);
return 0;
}
@@ -1220,7 +1127,7 @@ static int m8xx_sock_init(struct pcmcia_socket *sock)
pccard_io_map io = { 0, 0, 0, 0, 1 };
pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
- dprintk( "sock_init(%d)\n", s);
+ dprintk("sock_init(%d)\n", s);
m8xx_set_socket(sock, &dead_socket);
for (i = 0; i < PCMCIA_IO_WIN_NO; i++) {
@@ -1236,111 +1143,195 @@ static int m8xx_sock_init(struct pcmcia_socket *sock)
}
-static int m8xx_suspend(struct pcmcia_socket *sock)
+static int m8xx_sock_suspend(struct pcmcia_socket *sock)
{
return m8xx_set_socket(sock, &dead_socket);
}
static struct pccard_operations m8xx_services = {
- .init = m8xx_sock_init,
- .suspend = m8xx_suspend,
+ .init = m8xx_sock_init,
+ .suspend = m8xx_sock_suspend,
.get_status = m8xx_get_status,
.set_socket = m8xx_set_socket,
.set_io_map = m8xx_set_io_map,
.set_mem_map = m8xx_set_mem_map,
};
-static int __init m8xx_init(void)
+static int __init m8xx_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
{
struct pcmcia_win *w;
- unsigned int i,m;
+ unsigned int i, m, hwirq;
+ pcmconf8xx_t *pcmcia;
+ int status;
+ struct device_node *np = ofdev->node;
pcmcia_info("%s\n", version);
- if (driver_register(&m8xx_driver))
- return -1;
+ pcmcia = of_iomap(np, 0);
+ if (pcmcia == NULL)
+ return -EINVAL;
+
+ pcmcia_schlvl = irq_of_parse_and_map(np, 0);
+ hwirq = irq_map[pcmcia_schlvl].hwirq;
+ if (pcmcia_schlvl < 0)
+ return -EINVAL;
+
+ m8xx_pgcrx[0] = &pcmcia->pcmc_pgcra;
+ m8xx_pgcrx[1] = &pcmcia->pcmc_pgcrb;
pcmcia_info(PCMCIA_BOARD_MSG " using " PCMCIA_SLOT_MSG
- " with IRQ %u.\n", pcmcia_schlvl);
+ " with IRQ %u (%d). \n", pcmcia_schlvl, hwirq);
/* Configure Status change interrupt */
- if(request_irq(pcmcia_schlvl, m8xx_interrupt, 0,
- "m8xx_pcmcia", NULL)) {
+ if (request_irq(pcmcia_schlvl, m8xx_interrupt, IRQF_SHARED,
+ driver_name, socket)) {
pcmcia_error("Cannot allocate IRQ %u for SCHLVL!\n",
pcmcia_schlvl);
return -1;
}
- w = (void *) &((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pbr0;
-
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr,
- M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1));
+ w = (void *)&pcmcia->pcmc_pbr0;
- out_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per,
- in_be32(&((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_per) &
- ~(M8XX_PCMCIA_MASK(0)| M8XX_PCMCIA_MASK(1)));
+ out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
+ clrbits32(&pcmcia->pcmc_per, M8XX_PCMCIA_MASK(0) | M8XX_PCMCIA_MASK(1));
-/* connect interrupt and disable CxOE */
+ /* connect interrupt and disable CxOE */
- out_be32(M8XX_PGCRX(0), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16));
- out_be32(M8XX_PGCRX(1), M8XX_PGCRX_CXOE | (mk_int_int_mask(pcmcia_schlvl) << 16));
+ out_be32(M8XX_PGCRX(0),
+ M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
+ out_be32(M8XX_PGCRX(1),
+ M8XX_PGCRX_CXOE | (mk_int_int_mask(hwirq) << 16));
-/* intialize the fixed memory windows */
+ /* intialize the fixed memory windows */
- for(i = 0; i < PCMCIA_SOCKETS_NO; i++){
- for(m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
+ for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+ for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
out_be32(&w->br, PCMCIA_MEM_WIN_BASE +
- (PCMCIA_MEM_WIN_SIZE
- * (m + i * PCMCIA_MEM_WIN_NO)));
+ (PCMCIA_MEM_WIN_SIZE
+ * (m + i * PCMCIA_MEM_WIN_NO)));
- out_be32(&w->or, 0); /* set to not valid */
+ out_be32(&w->or, 0); /* set to not valid */
w++;
}
}
-/* turn off voltage */
+ /* turn off voltage */
voltage_set(0, 0, 0);
voltage_set(1, 0, 0);
-/* Enable external hardware */
+ /* Enable external hardware */
hardware_enable(0);
hardware_enable(1);
- platform_device_register(&m8xx_device);
-
- for (i = 0 ; i < PCMCIA_SOCKETS_NO; i++) {
+ for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
socket[i].slot = i;
socket[i].socket.owner = THIS_MODULE;
- socket[i].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP;
+ socket[i].socket.features =
+ SS_CAP_PCCARD | SS_CAP_MEM_ALIGN | SS_CAP_STATIC_MAP;
socket[i].socket.irq_mask = 0x000;
socket[i].socket.map_size = 0x1000;
socket[i].socket.io_offset = 0;
- socket[i].socket.pci_irq = i ? 7 : 9;
+ socket[i].socket.pci_irq = pcmcia_schlvl;
socket[i].socket.ops = &m8xx_services;
- socket[i].socket.resource_ops = &pccard_iodyn_ops;
+ socket[i].socket.resource_ops = &pccard_nonstatic_ops;
socket[i].socket.cb_dev = NULL;
- socket[i].socket.dev.parent = &m8xx_device.dev;
+ socket[i].socket.dev.parent = &ofdev->dev;
+ socket[i].pcmcia = pcmcia;
+ socket[i].bus_freq = ppc_proc_freq;
+ socket[i].hwirq = hwirq;
+
}
- for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
- pcmcia_register_socket(&socket[i].socket);
+ for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+ status = pcmcia_register_socket(&socket[i].socket);
+ if (status < 0)
+ pcmcia_error("Socket register failed\n");
+ }
return 0;
}
-static void __exit m8xx_exit(void)
+static int m8xx_remove(struct of_device *ofdev)
{
- int i;
+ u32 m, i;
+ struct pcmcia_win *w;
+ pcmconf8xx_t *pcmcia = socket[0].pcmcia;
+
+ for (i = 0; i < PCMCIA_SOCKETS_NO; i++) {
+ w = (void *)&pcmcia->pcmc_pbr0;
+ out_be32(&pcmcia->pcmc_pscr, M8XX_PCMCIA_MASK(i));
+ out_be32(&pcmcia->pcmc_per,
+ in_be32(&pcmcia->pcmc_per) & ~M8XX_PCMCIA_MASK(i));
+
+ /* turn off interrupt and disable CxOE */
+ out_be32(M8XX_PGCRX(i), M8XX_PGCRX_CXOE);
+
+ /* turn off memory windows */
+ for (m = 0; m < PCMCIA_MEM_WIN_NO; m++) {
+ out_be32(&w->or, 0); /* set to not valid */
+ w++;
+ }
+
+ /* turn off voltage */
+ voltage_set(i, 0, 0);
+
+ /* disable external hardware */
+ hardware_disable(i);
+ }
for (i = 0; i < PCMCIA_SOCKETS_NO; i++)
pcmcia_unregister_socket(&socket[i].socket);
- m8xx_shutdown();
+ free_irq(pcmcia_schlvl, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int m8xx_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return pcmcia_socket_dev_suspend(&pdev->dev, state);
+}
+
+static int m8xx_resume(struct platform_device *pdev)
+{
+ return pcmcia_socket_dev_resume(&pdev->dev);
+}
+#else
+#define m8xx_suspend NULL
+#define m8xx_resume NULL
+#endif
- platform_device_unregister(&m8xx_device);
- driver_unregister(&m8xx_driver);
+static struct of_device_id m8xx_pcmcia_match[] = {
+ {
+ .type = "pcmcia",
+ .compatible = "fsl,pq-pcmcia",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
+
+static struct of_platform_driver m8xx_pcmcia_driver = {
+ .name = driver_name,
+ .match_table = m8xx_pcmcia_match,
+ .probe = m8xx_probe,
+ .remove = m8xx_remove,
+ .suspend = m8xx_suspend,
+ .resume = m8xx_resume,
+};
+
+static int __init m8xx_init(void)
+{
+ return of_register_platform_driver(&m8xx_pcmcia_driver);
+}
+
+static void __exit m8xx_exit(void)
+{
+ of_unregister_platform_driver(&m8xx_pcmcia_driver);
}
module_init(m8xx_init);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index a2bb46526b56..b4409002b7f8 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -283,7 +283,9 @@ static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off
return (ret);
}
-static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t pccard_show_cis(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
unsigned int size = 0x200;
@@ -311,7 +313,9 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
return (count);
}
-static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t pccard_store_cis(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
cisdump_t *cis;
@@ -366,7 +370,7 @@ static struct device_attribute *pccard_socket_attributes[] = {
};
static struct bin_attribute pccard_cis_attr = {
- .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE},
+ .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
.size = 0x200,
.read = pccard_show_cis,
.write = pccard_store_cis,
diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig
index 1959cef8e9de..821933f9aa57 100644
--- a/drivers/pnp/Kconfig
+++ b/drivers/pnp/Kconfig
@@ -2,11 +2,9 @@
# Plug and Play configuration
#
-menu "Plug and Play support"
- depends on HAS_IOMEM
-
-config PNP
+menuconfig PNP
bool "Plug and Play support"
+ depends on HAS_IOMEM
depends on ISA || ACPI
---help---
Plug and Play (PnP) is a standard for peripherals which allows those
@@ -22,15 +20,15 @@ config PNP
If unsure, say Y.
+if PNP
+
config PNP_DEBUG
bool "PnP Debug Messages"
- depends on PNP
help
Say Y if you want the Plug and Play Layer to print debug messages.
This is useful if you are developing a PnP driver or troubleshooting.
comment "Protocols"
- depends on PNP
source "drivers/pnp/isapnp/Kconfig"
@@ -38,5 +36,4 @@ source "drivers/pnp/pnpbios/Kconfig"
source "drivers/pnp/pnpacpi/Kconfig"
-endmenu
-
+endif # PNP
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 3e20b1cc7778..8e7b2dd38810 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -35,12 +35,11 @@ void *pnp_alloc(long size)
{
void *result;
- result = kmalloc(size, GFP_KERNEL);
+ result = kzalloc(size, GFP_KERNEL);
if (!result){
printk(KERN_ERR "pnp: Out of Memory\n");
return NULL;
}
- memset(result, 0, size);
return result;
}
diff --git a/drivers/pnp/isapnp/Kconfig b/drivers/pnp/isapnp/Kconfig
index 578651eeb4b0..f1ef36673ad4 100644
--- a/drivers/pnp/isapnp/Kconfig
+++ b/drivers/pnp/isapnp/Kconfig
@@ -3,7 +3,7 @@
#
config ISAPNP
bool "ISA Plug and Play support"
- depends on PNP && ISA
+ depends on ISA
help
Say Y here if you would like support for ISA Plug and Play devices.
Some information is in <file:Documentation/isapnp.txt>.
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index a0b158704ca1..914d00c423ad 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -370,8 +370,6 @@ static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
#if 0
printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);
#endif
- if (type == 0) /* wrong type */
- return -1;
if (*type == 0xff && *size == 0xffff) /* probably invalid data */
return -1;
return 0;
diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig
index fab848cae89d..b986d9fa3b9a 100644
--- a/drivers/pnp/pnpbios/Kconfig
+++ b/drivers/pnp/pnpbios/Kconfig
@@ -3,7 +3,7 @@
#
config PNPBIOS
bool "Plug and Play BIOS support (EXPERIMENTAL)"
- depends on PNP && ISA && X86 && EXPERIMENTAL
+ depends on ISA && X86 && EXPERIMENTAL
default n
---help---
Linux uses the PNPBIOS as defined in "Plug and Play BIOS
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 3a201b77b963..ed112ee16012 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -147,7 +147,7 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
info->location_id, info->serial, info->capabilities);
envp[i] = NULL;
- value = call_usermodehelper (argv [0], argv, envp, 0);
+ value = call_usermodehelper (argv [0], argv, envp, UMH_WAIT_EXEC);
kfree (buf);
kfree (envp);
return 0;
@@ -160,6 +160,7 @@ static int pnp_dock_thread(void * unused)
{
static struct pnp_docking_station_info now;
int docked = -1, d = 0;
+ set_freezable();
while (!unloading)
{
int status;
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index ab9c3e5a7c1d..3f6e176e6ea1 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -16,6 +16,7 @@ config POWER_SUPPLY_DEBUG
config PDA_POWER
tristate "Generic PDA/phone power driver"
+ depends on !S390
help
Say Y here to enable generic power driver for PDAs and phones with
one or two external power supplies (AC/USB) connected to main and
diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
index 042bd950d036..39a90a6f0f80 100644
--- a/drivers/power/apm_power.c
+++ b/drivers/power/apm_power.c
@@ -48,8 +48,6 @@ static void find_main_battery(void)
}
if (!main_battery)
main_battery = batm;
-
- return;
}
static int calculate_time(int status)
@@ -218,7 +216,6 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
}
up(&power_supply_class->sem);
- return;
}
static int __init apm_battery_init(void)
@@ -232,7 +229,6 @@ static int __init apm_battery_init(void)
static void __exit apm_battery_exit(void)
{
apm_get_power_status = NULL;
- return;
}
module_init(apm_battery_init);
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index 00e1ea6f1de2..be7021ee3611 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -254,8 +254,6 @@ static void ds2760_battery_update_status(struct ds2760_device_info *di)
if (di->charge_status != old_charge_status)
power_supply_changed(&di->bat);
-
- return;
}
static void ds2760_battery_work(struct work_struct *work)
@@ -268,8 +266,6 @@ static void ds2760_battery_work(struct work_struct *work)
ds2760_battery_update_status(di);
queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
-
- return;
}
#define to_ds2760_device_info(x) container_of((x), struct ds2760_device_info, \
@@ -283,8 +279,6 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy)
cancel_delayed_work(&di->monitor_work);
queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
-
- return;
}
static int ds2760_battery_get_property(struct power_supply *psy,
@@ -457,7 +451,6 @@ static int __init ds2760_battery_init(void)
static void __exit ds2760_battery_exit(void)
{
platform_driver_unregister(&ds2760_battery_driver);
- return;
}
module_init(ds2760_battery_init);
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 878684df7667..c998e68d060f 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -341,7 +341,6 @@ static void __exit olpc_bat_exit(void)
power_supply_unregister(&olpc_bat);
power_supply_unregister(&olpc_ac);
platform_device_unregister(bat_pdev);
- return;
}
module_init(olpc_bat_init);
diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
index 4e1eb040e148..c058f285be1a 100644
--- a/drivers/power/pda_power.c
+++ b/drivers/power/pda_power.c
@@ -97,36 +97,31 @@ static void update_charger(void)
dev_dbg(dev, "charger off\n");
pdata->set_charge(0);
}
-
- return;
}
-static void supply_timer_func(unsigned long irq)
+static void supply_timer_func(unsigned long power_supply_ptr)
{
- if (ac_irq && irq == ac_irq->start)
- power_supply_changed(&pda_power_supplies[0]);
- else if (usb_irq && irq == usb_irq->start)
- power_supply_changed(&pda_power_supplies[1]);
- return;
+ void *power_supply = (void *)power_supply_ptr;
+
+ power_supply_changed(power_supply);
}
-static void charger_timer_func(unsigned long irq)
+static void charger_timer_func(unsigned long power_supply_ptr)
{
update_charger();
/* Okay, charger set. Now wait a bit before notifying supplicants,
* charge power should stabilize. */
- supply_timer.data = irq;
+ supply_timer.data = power_supply_ptr;
mod_timer(&supply_timer,
jiffies + msecs_to_jiffies(pdata->wait_for_charger));
- return;
}
-static irqreturn_t power_changed_isr(int irq, void *unused)
+static irqreturn_t power_changed_isr(int irq, void *power_supply)
{
/* Wait a bit before reading ac/usb line status and setting charger,
* because ac/usb status readings may lag from irq. */
- charger_timer.data = irq;
+ charger_timer.data = (unsigned long)power_supply;
mod_timer(&charger_timer,
jiffies + msecs_to_jiffies(pdata->wait_for_status));
return IRQ_HANDLED;
@@ -252,7 +247,6 @@ static int __init pda_power_init(void)
static void __exit pda_power_exit(void)
{
platform_driver_unregister(&pda_power_pdrv);
- return;
}
module_init(pda_power_init);
diff --git a/drivers/power/pmu_battery.c b/drivers/power/pmu_battery.c
index 2fea4af0e40a..60a8cf3a0431 100644
--- a/drivers/power/pmu_battery.c
+++ b/drivers/power/pmu_battery.c
@@ -203,8 +203,6 @@ static void __exit pmu_bat_exit(void)
}
power_supply_unregister(&pmu_ac);
platform_device_unregister(bat_pdev);
-
- return;
}
module_init(pmu_bat_init);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index e87ea5156755..a63b75cf75e2 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -46,8 +46,6 @@ static void power_supply_changed_work(struct work_struct *work)
power_supply_update_leds(psy);
kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
-
- return;
}
void power_supply_changed(struct power_supply *psy)
@@ -55,8 +53,6 @@ void power_supply_changed(struct power_supply *psy)
dev_dbg(psy->dev, "%s\n", __FUNCTION__);
schedule_work(&psy->changed_work);
-
- return;
}
int power_supply_am_i_supplied(struct power_supply *psy)
@@ -129,7 +125,6 @@ void power_supply_unregister(struct power_supply *psy)
power_supply_remove_triggers(psy);
power_supply_remove_attrs(psy);
device_unregister(psy->dev);
- return;
}
static int __init power_supply_class_init(void)
@@ -147,7 +142,6 @@ static int __init power_supply_class_init(void)
static void __exit power_supply_class_exit(void)
{
class_destroy(power_supply_class);
- return;
}
EXPORT_SYMBOL_GPL(power_supply_changed);
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c
index 7232490bb595..7f8f3590b02e 100644
--- a/drivers/power/power_supply_leds.c
+++ b/drivers/power/power_supply_leds.c
@@ -40,8 +40,6 @@ static void power_supply_update_bat_leds(struct power_supply *psy)
led_trigger_event(psy->full_trig, LED_OFF);
break;
}
-
- return;
}
static int power_supply_create_bat_triggers(struct power_supply *psy)
@@ -97,7 +95,6 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy)
kfree(psy->full_trig_name);
kfree(psy->charging_trig_name);
kfree(psy->charging_full_trig_name);
- return;
}
/* Generated power specific LEDs triggers. */
@@ -115,8 +112,6 @@ static void power_supply_update_gen_leds(struct power_supply *psy)
led_trigger_event(psy->online_trig, LED_FULL);
else
led_trigger_event(psy->online_trig, LED_OFF);
-
- return;
}
static int power_supply_create_gen_triggers(struct power_supply *psy)
@@ -145,7 +140,6 @@ static void power_supply_remove_gen_triggers(struct power_supply *psy)
{
led_trigger_unregister_simple(psy->online_trig);
kfree(psy->online_trig_name);
- return;
}
/* Choice what triggers to create&update. */
@@ -156,7 +150,6 @@ void power_supply_update_leds(struct power_supply *psy)
power_supply_update_bat_leds(psy);
else
power_supply_update_gen_leds(psy);
- return;
}
int power_supply_create_triggers(struct power_supply *psy)
@@ -172,5 +165,4 @@ void power_supply_remove_triggers(struct power_supply *psy)
power_supply_remove_bat_triggers(psy);
else
power_supply_remove_gen_triggers(psy);
- return;
}
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index c07d4258d347..c7c4574729b1 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -176,8 +176,6 @@ void power_supply_remove_attrs(struct power_supply *psy)
for (i = 0; i < psy->num_properties; i++)
device_remove_file(psy->dev,
&power_supply_attrs[psy->properties[i]]);
-
- return;
}
static char *kstruprdup(const char *str, gfp_t gfp)
diff --git a/drivers/ps3/Makefile b/drivers/ps3/Makefile
index e251d1c1171c..746031de2195 100644
--- a/drivers/ps3/Makefile
+++ b/drivers/ps3/Makefile
@@ -1,3 +1,6 @@
obj-$(CONFIG_PS3_VUART) += vuart.o
-obj-$(CONFIG_PS3_PS3AV) += ps3av.o ps3av_cmd.o
+obj-$(CONFIG_PS3_PS3AV) += ps3av_mod.o
+ps3av_mod-objs += ps3av.o ps3av_cmd.o
+obj-$(CONFIG_PPC_PS3) += sys-manager-core.o
obj-$(CONFIG_PS3_SYS_MANAGER) += sys-manager.o
+obj-$(CONFIG_PS3_STORAGE) += ps3stor_lib.o
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c
index 1393e64335f9..85e21614f868 100644
--- a/drivers/ps3/ps3av.c
+++ b/drivers/ps3/ps3av.c
@@ -1,32 +1,30 @@
/*
- * Copyright (C) 2006 Sony Computer Entertainment Inc.
- * Copyright 2006, 2007 Sony Corporation
+ * PS3 AV backend support.
*
- * AV backend support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
*
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
+ * 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.
+ * 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/delay.h>
#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/kernel.h>
#include <linux/ioctl.h>
#include <asm/firmware.h>
-#include <asm/lv1call.h>
#include <asm/ps3av.h>
#include <asm/ps3.h>
@@ -39,13 +37,12 @@ static int timeout = 5000; /* in msec ( 5 sec ) */
module_param(timeout, int, 0644);
static struct ps3av {
- int available;
struct mutex mutex;
struct work_struct work;
struct completion done;
struct workqueue_struct *wq;
int open_count;
- struct ps3_vuart_port_device *dev;
+ struct ps3_system_bus_device *dev;
int region;
struct ps3av_pkt_av_get_hw_conf av_hw_conf;
@@ -55,11 +52,13 @@ static struct ps3av {
u32 audio_port;
int ps3av_mode;
int ps3av_mode_old;
-} ps3av;
-
-static struct ps3_vuart_port_device ps3av_dev = {
- .match_id = PS3_MATCH_ID_AV_SETTINGS
-};
+ union {
+ struct ps3av_reply_hdr reply_hdr;
+ u8 raw[PS3AV_BUF_SIZE];
+ } recv_buf;
+ void (*flip_ctl)(int on, void *data);
+ void *flip_data;
+} *ps3av;
/* color space */
#define YUV444 PS3AV_CMD_VIDEO_CS_YUV444_8
@@ -169,7 +168,7 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr)
if (hdr->cid & PS3AV_EVENT_CMD_MASK) {
table = ps3av_search_cmd_table(hdr->cid, PS3AV_EVENT_CMD_MASK);
if (table)
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"recv event packet cid:%08x port:0x%x size:%d\n",
hdr->cid, ps3av_event_get_port_id(hdr->cid),
hdr->size);
@@ -182,6 +181,41 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr)
return 0;
}
+
+#define POLLING_INTERVAL 25 /* in msec */
+
+static int ps3av_vuart_write(struct ps3_system_bus_device *dev,
+ const void *buf, unsigned long size)
+{
+ int error;
+ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
+ error = ps3_vuart_write(dev, buf, size);
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
+ return error ? error : size;
+}
+
+static int ps3av_vuart_read(struct ps3_system_bus_device *dev, void *buf,
+ unsigned long size, int timeout)
+{
+ int error;
+ int loopcnt = 0;
+
+ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
+ timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL;
+ while (loopcnt++ <= timeout) {
+ error = ps3_vuart_read(dev, buf, size);
+ if (!error)
+ return size;
+ if (error != -EAGAIN) {
+ printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
+ __func__, error);
+ return error;
+ }
+ msleep(POLLING_INTERVAL);
+ }
+ return -EWOULDBLOCK;
+}
+
static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
struct ps3av_reply_hdr *recv_buf, int write_len,
int read_len)
@@ -190,13 +224,13 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
u32 cmd;
int event;
- if (!ps3av.available)
+ if (!ps3av)
return -ENODEV;
/* send pkt */
- res = ps3av_vuart_write(ps3av.dev, send_buf, write_len);
+ res = ps3av_vuart_write(ps3av->dev, send_buf, write_len);
if (res < 0) {
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"%s: ps3av_vuart_write() failed (result=%d)\n",
__func__, res);
return res;
@@ -206,20 +240,20 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
cmd = send_buf->cid;
do {
/* read header */
- res = ps3av_vuart_read(ps3av.dev, recv_buf, PS3AV_HDR_SIZE,
+ res = ps3av_vuart_read(ps3av->dev, recv_buf, PS3AV_HDR_SIZE,
timeout);
if (res != PS3AV_HDR_SIZE) {
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"%s: ps3av_vuart_read() failed (result=%d)\n",
__func__, res);
return res;
}
/* read body */
- res = ps3av_vuart_read(ps3av.dev, &recv_buf->cid,
+ res = ps3av_vuart_read(ps3av->dev, &recv_buf->cid,
recv_buf->size, timeout);
if (res < 0) {
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"%s: ps3av_vuart_read() failed (result=%d)\n",
__func__, res);
return res;
@@ -230,7 +264,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf,
} while (event);
if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) {
- dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n",
+ dev_dbg(&ps3av->dev->core, "%s: reply err (result=%x)\n",
__func__, recv_buf->cid);
return -EINVAL;
}
@@ -245,7 +279,7 @@ static int ps3av_process_reply_packet(struct ps3av_send_hdr *cmd_buf,
int return_len;
if (recv_buf->version != PS3AV_VERSION) {
- dev_dbg(&ps3av_dev.core, "reply_packet invalid version:%x\n",
+ dev_dbg(&ps3av->dev->core, "reply_packet invalid version:%x\n",
recv_buf->version);
return -EFAULT;
}
@@ -267,16 +301,11 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
struct ps3av_send_hdr *buf)
{
int res = 0;
- static union {
- struct ps3av_reply_hdr reply_hdr;
- u8 raw[PS3AV_BUF_SIZE];
- } recv_buf;
-
u32 *table;
- BUG_ON(!ps3av.available);
+ BUG_ON(!ps3av);
- mutex_lock(&ps3av.mutex);
+ mutex_lock(&ps3av->mutex);
table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK);
BUG_ON(!table);
@@ -288,7 +317,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
ps3av_set_hdr(cid, send_len, buf);
/* send packet via vuart */
- res = ps3av_send_cmd_pkt(buf, &recv_buf.reply_hdr, send_len,
+ res = ps3av_send_cmd_pkt(buf, &ps3av->recv_buf.reply_hdr, send_len,
usr_buf_size);
if (res < 0) {
printk(KERN_ERR
@@ -298,7 +327,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
}
/* process reply packet */
- res = ps3av_process_reply_packet(buf, &recv_buf.reply_hdr,
+ res = ps3av_process_reply_packet(buf, &ps3av->recv_buf.reply_hdr,
usr_buf_size);
if (res < 0) {
printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n",
@@ -306,11 +335,11 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size,
goto err;
}
- mutex_unlock(&ps3av.mutex);
+ mutex_unlock(&ps3av->mutex);
return 0;
err:
- mutex_unlock(&ps3av.mutex);
+ mutex_unlock(&ps3av->mutex);
printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res);
return res;
}
@@ -319,11 +348,11 @@ static int ps3av_set_av_video_mute(u32 mute)
{
int i, num_of_av_port, res;
- num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
- ps3av.av_hw_conf.num_of_avmulti;
+ num_of_av_port = ps3av->av_hw_conf.num_of_hdmi +
+ ps3av->av_hw_conf.num_of_avmulti;
/* video mute on */
for (i = 0; i < num_of_av_port; i++) {
- res = ps3av_cmd_av_video_mute(1, &ps3av.av_port[i], mute);
+ res = ps3av_cmd_av_video_mute(1, &ps3av->av_port[i], mute);
if (res < 0)
return -1;
}
@@ -335,13 +364,13 @@ static int ps3av_set_video_disable_sig(void)
{
int i, num_of_hdmi_port, num_of_av_port, res;
- num_of_hdmi_port = ps3av.av_hw_conf.num_of_hdmi;
- num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
- ps3av.av_hw_conf.num_of_avmulti;
+ num_of_hdmi_port = ps3av->av_hw_conf.num_of_hdmi;
+ num_of_av_port = ps3av->av_hw_conf.num_of_hdmi +
+ ps3av->av_hw_conf.num_of_avmulti;
/* tv mute */
for (i = 0; i < num_of_hdmi_port; i++) {
- res = ps3av_cmd_av_tv_mute(ps3av.av_port[i],
+ res = ps3av_cmd_av_tv_mute(ps3av->av_port[i],
PS3AV_CMD_MUTE_ON);
if (res < 0)
return -1;
@@ -350,11 +379,11 @@ static int ps3av_set_video_disable_sig(void)
/* video mute on */
for (i = 0; i < num_of_av_port; i++) {
- res = ps3av_cmd_av_video_disable_sig(ps3av.av_port[i]);
+ res = ps3av_cmd_av_video_disable_sig(ps3av->av_port[i]);
if (res < 0)
return -1;
if (i < num_of_hdmi_port) {
- res = ps3av_cmd_av_tv_mute(ps3av.av_port[i],
+ res = ps3av_cmd_av_tv_mute(ps3av->av_port[i],
PS3AV_CMD_MUTE_OFF);
if (res < 0)
return -1;
@@ -369,17 +398,17 @@ static int ps3av_set_audio_mute(u32 mute)
{
int i, num_of_av_port, num_of_opt_port, res;
- num_of_av_port = ps3av.av_hw_conf.num_of_hdmi +
- ps3av.av_hw_conf.num_of_avmulti;
- num_of_opt_port = ps3av.av_hw_conf.num_of_spdif;
+ num_of_av_port = ps3av->av_hw_conf.num_of_hdmi +
+ ps3av->av_hw_conf.num_of_avmulti;
+ num_of_opt_port = ps3av->av_hw_conf.num_of_spdif;
for (i = 0; i < num_of_av_port; i++) {
- res = ps3av_cmd_av_audio_mute(1, &ps3av.av_port[i], mute);
+ res = ps3av_cmd_av_audio_mute(1, &ps3av->av_port[i], mute);
if (res < 0)
return -1;
}
for (i = 0; i < num_of_opt_port; i++) {
- res = ps3av_cmd_audio_mute(1, &ps3av.opt_port[i], mute);
+ res = ps3av_cmd_audio_mute(1, &ps3av->opt_port[i], mute);
if (res < 0)
return -1;
}
@@ -394,40 +423,40 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
struct ps3av_pkt_audio_mode audio_mode;
u32 len = 0;
- num_of_audio = ps3av.av_hw_conf.num_of_hdmi +
- ps3av.av_hw_conf.num_of_avmulti +
- ps3av.av_hw_conf.num_of_spdif;
+ num_of_audio = ps3av->av_hw_conf.num_of_hdmi +
+ ps3av->av_hw_conf.num_of_avmulti +
+ ps3av->av_hw_conf.num_of_spdif;
avb_param.num_of_video_pkt = 0;
avb_param.num_of_audio_pkt = PS3AV_AVB_NUM_AUDIO; /* always 0 */
avb_param.num_of_av_video_pkt = 0;
- avb_param.num_of_av_audio_pkt = ps3av.av_hw_conf.num_of_hdmi;
+ avb_param.num_of_av_audio_pkt = ps3av->av_hw_conf.num_of_hdmi;
- vid = video_mode_table[ps3av.ps3av_mode].vid;
+ vid = video_mode_table[ps3av->ps3av_mode].vid;
/* audio mute */
ps3av_set_audio_mute(PS3AV_CMD_MUTE_ON);
/* audio inactive */
- res = ps3av_cmd_audio_active(0, ps3av.audio_port);
+ res = ps3av_cmd_audio_active(0, ps3av->audio_port);
if (res < 0)
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"ps3av_cmd_audio_active OFF failed\n");
/* audio_pkt */
for (i = 0; i < num_of_audio; i++) {
- ps3av_cmd_set_audio_mode(&audio_mode, ps3av.av_port[i], ch, fs,
- word_bits, format, source);
- if (i < ps3av.av_hw_conf.num_of_hdmi) {
+ ps3av_cmd_set_audio_mode(&audio_mode, ps3av->av_port[i], ch,
+ fs, word_bits, format, source);
+ if (i < ps3av->av_hw_conf.num_of_hdmi) {
/* hdmi only */
len += ps3av_cmd_set_av_audio_param(&avb_param.buf[len],
- ps3av.av_port[i],
+ ps3av->av_port[i],
&audio_mode, vid);
}
/* audio_mode pkt should be sent separately */
res = ps3av_cmd_audio_mode(&audio_mode);
if (res < 0)
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"ps3av_cmd_audio_mode failed, port:%x\n", i);
}
@@ -435,15 +464,16 @@ int ps3av_set_audio_mode(u32 ch, u32 fs, u32 word_bits, u32 format, u32 source)
len += offsetof(struct ps3av_pkt_avb_param, buf);
res = ps3av_cmd_avb_param(&avb_param, len);
if (res < 0)
- dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
+ dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
/* audio mute */
ps3av_set_audio_mute(PS3AV_CMD_MUTE_OFF);
/* audio active */
- res = ps3av_cmd_audio_active(1, ps3av.audio_port);
+ res = ps3av_cmd_audio_active(1, ps3av->audio_port);
if (res < 0)
- dev_dbg(&ps3av_dev.core, "ps3av_cmd_audio_active ON failed\n");
+ dev_dbg(&ps3av->dev->core,
+ "ps3av_cmd_audio_active ON failed\n");
return 0;
}
@@ -456,7 +486,7 @@ static int ps3av_set_videomode(void)
ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON);
/* wake up ps3avd to do the actual video mode setting */
- queue_work(ps3av.wq, &ps3av.work);
+ queue_work(ps3av->wq, &ps3av->work);
return 0;
}
@@ -473,8 +503,8 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
avb_param.num_of_video_pkt = PS3AV_AVB_NUM_VIDEO; /* num of head */
avb_param.num_of_audio_pkt = 0;
- avb_param.num_of_av_video_pkt = ps3av.av_hw_conf.num_of_hdmi +
- ps3av.av_hw_conf.num_of_avmulti;
+ avb_param.num_of_av_video_pkt = ps3av->av_hw_conf.num_of_hdmi +
+ ps3av->av_hw_conf.num_of_avmulti;
avb_param.num_of_av_audio_pkt = 0;
/* video signal off */
@@ -484,21 +514,21 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
if (id & PS3AV_MODE_HDCP_OFF) {
res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_HDCP_OFF);
if (res == PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
- dev_dbg(&ps3av_dev.core, "Not supported\n");
+ dev_dbg(&ps3av->dev->core, "Not supported\n");
else if (res)
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"ps3av_cmd_av_hdmi_mode failed\n");
} else if (old_id & PS3AV_MODE_HDCP_OFF) {
res = ps3av_cmd_av_hdmi_mode(PS3AV_CMD_AV_HDMI_MODE_NORMAL);
if (res < 0 && res != PS3AV_STATUS_UNSUPPORTED_HDMI_MODE)
- dev_dbg(&ps3av_dev.core,
+ dev_dbg(&ps3av->dev->core,
"ps3av_cmd_av_hdmi_mode failed\n");
}
/* video_pkt */
for (i = 0; i < avb_param.num_of_video_pkt; i++)
len += ps3av_cmd_set_video_mode(&avb_param.buf[len],
- ps3av.head[i], video_mode->vid,
+ ps3av->head[i], video_mode->vid,
video_mode->fmt, id);
/* av_video_pkt */
for (i = 0; i < avb_param.num_of_av_video_pkt; i++) {
@@ -507,12 +537,12 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
else
av_video_cs = video_mode->cs;
#ifndef PS3AV_HDMI_YUV
- if (ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
- ps3av.av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
+ if (ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_0 ||
+ ps3av->av_port[i] == PS3AV_CMD_AVPORT_HDMI_1)
av_video_cs = RGB8; /* use RGB for HDMI */
#endif
len += ps3av_cmd_set_av_video_cs(&avb_param.buf[len],
- ps3av.av_port[i],
+ ps3av->av_port[i],
video_mode->vid, av_video_cs,
video_mode->aspect, id);
}
@@ -524,7 +554,7 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
"%s: Command failed. Please try your request again. \n",
__func__);
else if (res)
- dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n");
+ dev_dbg(&ps3av->dev->core, "ps3av_cmd_avb_param failed\n");
msleep(1500);
/* av video mute */
@@ -533,8 +563,8 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id)
static void ps3avd(struct work_struct *work)
{
- ps3av_set_videomode_cont(ps3av.ps3av_mode, ps3av.ps3av_mode_old);
- complete(&ps3av.done);
+ ps3av_set_videomode_cont(ps3av->ps3av_mode, ps3av->ps3av_mode_old);
+ complete(&ps3av->done);
}
static int ps3av_vid2table_id(int vid)
@@ -601,7 +631,7 @@ static int ps3av_hdmi_get_vid(struct ps3av_info_monitor *info)
return vid;
}
- if (ps3av.region & PS3AV_REGION_60)
+ if (ps3av->region & PS3AV_REGION_60)
vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
else
vid = PS3AV_DEFAULT_HDMI_VID_REG_50;
@@ -643,16 +673,16 @@ static int ps3av_auto_videomode(struct ps3av_pkt_av_get_hw_conf *av_hw_conf,
vid = PS3AV_DEFAULT_DVI_VID;
} else if (vid == -1) {
/* no HDMI interface or HDMI is off */
- if (ps3av.region & PS3AV_REGION_60)
+ if (ps3av->region & PS3AV_REGION_60)
vid = PS3AV_DEFAULT_AVMULTI_VID_REG_60;
else
vid = PS3AV_DEFAULT_AVMULTI_VID_REG_50;
- if (ps3av.region & PS3AV_REGION_RGB)
+ if (ps3av->region & PS3AV_REGION_RGB)
rgb = PS3AV_MODE_RGB;
} else if (boot) {
/* HDMI: using DEFAULT HDMI_VID while booting up */
info = &monitor_info.info;
- if (ps3av.region & PS3AV_REGION_60) {
+ if (ps3av->region & PS3AV_REGION_60) {
if (info->res_60.res_bits & PS3AV_RESBIT_720x480P)
vid = PS3AV_DEFAULT_HDMI_VID_REG_60;
else if (info->res_50.res_bits & PS3AV_RESBIT_720x576P)
@@ -715,14 +745,14 @@ int ps3av_set_video_mode(u32 id, int boot)
size = ARRAY_SIZE(video_mode_table);
if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) {
- dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id);
+ dev_dbg(&ps3av->dev->core, "%s: error id :%d\n", __func__, id);
return -EINVAL;
}
/* auto mode */
option = id & ~PS3AV_MODE_MASK;
if ((id & PS3AV_MODE_MASK) == 0) {
- id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
+ id = ps3av_auto_videomode(&ps3av->av_hw_conf, boot);
if (id < 1) {
printk(KERN_ERR "%s: invalid id :%d\n", __func__, id);
return -EINVAL;
@@ -731,11 +761,11 @@ int ps3av_set_video_mode(u32 id, int boot)
}
/* set videomode */
- wait_for_completion(&ps3av.done);
- ps3av.ps3av_mode_old = ps3av.ps3av_mode;
- ps3av.ps3av_mode = id;
+ wait_for_completion(&ps3av->done);
+ ps3av->ps3av_mode_old = ps3av->ps3av_mode;
+ ps3av->ps3av_mode = id;
if (ps3av_set_videomode())
- ps3av.ps3av_mode = ps3av.ps3av_mode_old;
+ ps3av->ps3av_mode = ps3av->ps3av_mode_old;
return 0;
}
@@ -744,7 +774,7 @@ EXPORT_SYMBOL_GPL(ps3av_set_video_mode);
int ps3av_get_auto_mode(int boot)
{
- return ps3av_auto_videomode(&ps3av.av_hw_conf, boot);
+ return ps3av_auto_videomode(&ps3av->av_hw_conf, boot);
}
EXPORT_SYMBOL_GPL(ps3av_get_auto_mode);
@@ -772,7 +802,7 @@ EXPORT_SYMBOL_GPL(ps3av_set_mode);
int ps3av_get_mode(void)
{
- return ps3av.ps3av_mode;
+ return ps3av ? ps3av->ps3av_mode : 0;
}
EXPORT_SYMBOL_GPL(ps3av_get_mode);
@@ -842,82 +872,65 @@ int ps3av_audio_mute(int mute)
EXPORT_SYMBOL_GPL(ps3av_audio_mute);
-int ps3av_dev_open(void)
+void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
+ void *flip_data)
{
- int status = 0;
-
- mutex_lock(&ps3av.mutex);
- if (!ps3av.open_count++) {
- status = lv1_gpu_open(0);
- if (status) {
- printk(KERN_ERR "%s: lv1_gpu_open failed %d\n",
- __func__, status);
- ps3av.open_count--;
- }
- }
- mutex_unlock(&ps3av.mutex);
-
- return status;
+ mutex_lock(&ps3av->mutex);
+ ps3av->flip_ctl = flip_ctl;
+ ps3av->flip_data = flip_data;
+ mutex_unlock(&ps3av->mutex);
}
+EXPORT_SYMBOL_GPL(ps3av_register_flip_ctl);
-EXPORT_SYMBOL_GPL(ps3av_dev_open);
-
-int ps3av_dev_close(void)
+void ps3av_flip_ctl(int on)
{
- int status = 0;
-
- mutex_lock(&ps3av.mutex);
- if (ps3av.open_count <= 0) {
- printk(KERN_ERR "%s: GPU already closed\n", __func__);
- status = -1;
- } else if (!--ps3av.open_count) {
- status = lv1_gpu_close();
- if (status)
- printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n",
- __func__, status);
- }
- mutex_unlock(&ps3av.mutex);
-
- return status;
+ mutex_lock(&ps3av->mutex);
+ if (ps3av->flip_ctl)
+ ps3av->flip_ctl(on, ps3av->flip_data);
+ mutex_unlock(&ps3av->mutex);
}
-EXPORT_SYMBOL_GPL(ps3av_dev_close);
-
-static int ps3av_probe(struct ps3_vuart_port_device *dev)
+static int ps3av_probe(struct ps3_system_bus_device *dev)
{
int res;
u32 id;
- dev_dbg(&ps3av_dev.core, "init ...\n");
- dev_dbg(&ps3av_dev.core, " timeout=%d\n", timeout);
+ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
+ dev_dbg(&dev->core, " timeout=%d\n", timeout);
- memset(&ps3av, 0, sizeof(ps3av));
-
- mutex_init(&ps3av.mutex);
- ps3av.ps3av_mode = 0;
- ps3av.dev = dev;
+ if (ps3av) {
+ dev_err(&dev->core, "Only one ps3av device is supported\n");
+ return -EBUSY;
+ }
- INIT_WORK(&ps3av.work, ps3avd);
- init_completion(&ps3av.done);
- complete(&ps3av.done);
- ps3av.wq = create_singlethread_workqueue("ps3avd");
- if (!ps3av.wq)
+ ps3av = kzalloc(sizeof(*ps3av), GFP_KERNEL);
+ if (!ps3av)
return -ENOMEM;
- ps3av.available = 1;
+ mutex_init(&ps3av->mutex);
+ ps3av->ps3av_mode = 0;
+ ps3av->dev = dev;
+
+ INIT_WORK(&ps3av->work, ps3avd);
+ init_completion(&ps3av->done);
+ complete(&ps3av->done);
+ ps3av->wq = create_singlethread_workqueue("ps3avd");
+ if (!ps3av->wq)
+ goto fail;
+
switch (ps3_os_area_get_av_multi_out()) {
case PS3_PARAM_AV_MULTI_OUT_NTSC:
- ps3av.region = PS3AV_REGION_60;
+ ps3av->region = PS3AV_REGION_60;
break;
case PS3_PARAM_AV_MULTI_OUT_PAL_YCBCR:
case PS3_PARAM_AV_MULTI_OUT_SECAM:
- ps3av.region = PS3AV_REGION_50;
+ ps3av->region = PS3AV_REGION_50;
break;
case PS3_PARAM_AV_MULTI_OUT_PAL_RGB:
- ps3av.region = PS3AV_REGION_50 | PS3AV_REGION_RGB;
+ ps3av->region = PS3AV_REGION_50 | PS3AV_REGION_RGB;
break;
default:
- ps3av.region = PS3AV_REGION_60;
+ ps3av->region = PS3AV_REGION_60;
break;
}
@@ -927,39 +940,47 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev)
printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__,
res);
- ps3av_get_hw_conf(&ps3av);
- id = ps3av_auto_videomode(&ps3av.av_hw_conf, 1);
- mutex_lock(&ps3av.mutex);
- ps3av.ps3av_mode = id;
- mutex_unlock(&ps3av.mutex);
+ ps3av_get_hw_conf(ps3av);
+ id = ps3av_auto_videomode(&ps3av->av_hw_conf, 1);
+ mutex_lock(&ps3av->mutex);
+ ps3av->ps3av_mode = id;
+ mutex_unlock(&ps3av->mutex);
- dev_dbg(&ps3av_dev.core, "init...done\n");
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
return 0;
+
+fail:
+ kfree(ps3av);
+ ps3av = NULL;
+ return -ENOMEM;
}
-static int ps3av_remove(struct ps3_vuart_port_device *dev)
+static int ps3av_remove(struct ps3_system_bus_device *dev)
{
- if (ps3av.available) {
+ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
+ if (ps3av) {
ps3av_cmd_fin();
- if (ps3av.wq)
- destroy_workqueue(ps3av.wq);
- ps3av.available = 0;
+ if (ps3av->wq)
+ destroy_workqueue(ps3av->wq);
+ kfree(ps3av);
+ ps3av = NULL;
}
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
return 0;
}
-static void ps3av_shutdown(struct ps3_vuart_port_device *dev)
+static void ps3av_shutdown(struct ps3_system_bus_device *dev)
{
+ dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
ps3av_remove(dev);
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
}
static struct ps3_vuart_port_driver ps3av_driver = {
- .match_id = PS3_MATCH_ID_AV_SETTINGS,
- .core = {
- .name = "ps3_av",
- },
+ .core.match_id = PS3_MATCH_ID_AV_SETTINGS,
+ .core.core.name = "ps3_av",
.probe = ps3av_probe,
.remove = ps3av_remove,
.shutdown = ps3av_shutdown,
@@ -972,6 +993,8 @@ static int ps3av_module_init(void)
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
return -ENODEV;
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
error = ps3_vuart_port_driver_register(&ps3av_driver);
if (error) {
printk(KERN_ERR
@@ -980,20 +1003,21 @@ static int ps3av_module_init(void)
return error;
}
- error = ps3_vuart_port_device_register(&ps3av_dev);
- if (error)
- printk(KERN_ERR
- "%s: ps3_vuart_port_device_register failed %d\n",
- __func__, error);
-
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
return error;
}
static void __exit ps3av_module_exit(void)
{
- device_unregister(&ps3av_dev.core);
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
ps3_vuart_port_driver_unregister(&ps3av_driver);
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
}
subsys_initcall(ps3av_module_init);
module_exit(ps3av_module_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 AV Settings Driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
+MODULE_ALIAS(PS3_MODULE_ALIAS_AV_SETTINGS);
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c
index 0145ea173c42..f72f5ddf18e4 100644
--- a/drivers/ps3/ps3av_cmd.c
+++ b/drivers/ps3/ps3av_cmd.c
@@ -143,6 +143,14 @@ static u32 ps3av_vid_video2av(int vid)
return PS3AV_CMD_AV_VID_480P;
}
+static int ps3av_hdmi_range(void)
+{
+ if (ps3_compare_firmware_version(1, 8, 0) < 0)
+ return 0;
+ else
+ return 1; /* supported */
+}
+
int ps3av_cmd_init(void)
{
int res;
@@ -350,6 +358,10 @@ u32 ps3av_cmd_set_av_video_cs(void *p, u32 avport, int video_vid, int cs_out,
/* should be same as video_mode.video_cs_out */
av_video_cs->av_cs_in = ps3av_cs_video2av(PS3AV_CMD_VIDEO_CS_RGB_8);
av_video_cs->bitlen_out = ps3av_cs_video2av_bitlen(cs_out);
+ if ((id & PS3AV_MODE_WHITE) && ps3av_hdmi_range())
+ av_video_cs->super_white = PS3AV_CMD_AV_SUPER_WHITE_ON;
+ else /* default off */
+ av_video_cs->super_white = PS3AV_CMD_AV_SUPER_WHITE_OFF;
av_video_cs->aspect = aspect;
if (id & PS3AV_MODE_DITHER) {
av_video_cs->dither = PS3AV_CMD_AV_DITHER_ON
@@ -392,6 +404,10 @@ u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt,
video_mode->pitch = video_mode->width * 4; /* line_length */
video_mode->video_out_format = PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT;
video_mode->video_format = ps3av_video_fmt_table[video_fmt].format;
+ if ((id & PS3AV_MODE_COLOR) && ps3av_hdmi_range())
+ video_mode->video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_DISABLE_LUT;
+ else /* default enable */
+ video_mode->video_cl_cnv = PS3AV_CMD_VIDEO_CL_CNV_ENABLE_LUT;
video_mode->video_order = ps3av_video_fmt_table[video_fmt].order;
pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n",
@@ -852,7 +868,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
{
int res;
- ps3fb_flip_ctl(0); /* flip off */
+ ps3av_flip_ctl(0); /* flip off */
/* avb packet */
res = ps3av_do_pkt(PS3AV_CID_AVB_PARAM, send_len, sizeof(*avb),
@@ -866,7 +882,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len)
res);
out:
- ps3fb_flip_ctl(1); /* flip on */
+ ps3av_flip_ctl(1); /* flip on */
return res;
}
@@ -987,34 +1003,3 @@ void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_monitor_info *
| PS3AV_CMD_AV_LAYOUT_176 \
| PS3AV_CMD_AV_LAYOUT_192)
-/************************* vuart ***************************/
-
-#define POLLING_INTERVAL 25 /* in msec */
-
-int ps3av_vuart_write(struct ps3_vuart_port_device *dev, const void *buf,
- unsigned long size)
-{
- int error = ps3_vuart_write(dev, buf, size);
- return error ? error : size;
-}
-
-int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
- unsigned long size, int timeout)
-{
- int error;
- int loopcnt = 0;
-
- timeout = (timeout + POLLING_INTERVAL - 1) / POLLING_INTERVAL;
- while (loopcnt++ <= timeout) {
- error = ps3_vuart_read(dev, buf, size);
- if (!error)
- return size;
- if (error != -EAGAIN) {
- printk(KERN_ERR "%s: ps3_vuart_read failed %d\n",
- __func__, error);
- return error;
- }
- msleep(POLLING_INTERVAL);
- }
- return -EWOULDBLOCK;
-}
diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c
new file mode 100644
index 000000000000..3a9824e3b251
--- /dev/null
+++ b/drivers/ps3/ps3stor_lib.c
@@ -0,0 +1,302 @@
+/*
+ * PS3 Storage Library
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/dma-mapping.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+static int ps3stor_probe_access(struct ps3_storage_device *dev)
+{
+ int res, error;
+ unsigned int i;
+ unsigned long n;
+
+ if (dev->sbd.match_id == PS3_MATCH_ID_STOR_ROM) {
+ /* special case: CD-ROM is assumed always accessible */
+ dev->accessible_regions = 1;
+ return 0;
+ }
+
+ error = -EPERM;
+ for (i = 0; i < dev->num_regions; i++) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: checking accessibility of region %u\n",
+ __func__, __LINE__, i);
+
+ dev->region_idx = i;
+ res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, 0, 1,
+ 0);
+ if (res) {
+ dev_dbg(&dev->sbd.core, "%s:%u: read failed, "
+ "region %u is not accessible\n", __func__,
+ __LINE__, i);
+ continue;
+ }
+
+ dev_dbg(&dev->sbd.core, "%s:%u: region %u is accessible\n",
+ __func__, __LINE__, i);
+ set_bit(i, &dev->accessible_regions);
+
+ /* We can access at least one region */
+ error = 0;
+ }
+ if (error)
+ return error;
+
+ n = hweight_long(dev->accessible_regions);
+ if (n > 1)
+ dev_info(&dev->sbd.core,
+ "%s:%u: %lu accessible regions found. Only the first "
+ "one will be used",
+ __func__, __LINE__, n);
+ dev->region_idx = __ffs(dev->accessible_regions);
+ dev_info(&dev->sbd.core,
+ "First accessible region has index %u start %lu size %lu\n",
+ dev->region_idx, dev->regions[dev->region_idx].start,
+ dev->regions[dev->region_idx].size);
+
+ return 0;
+}
+
+
+/**
+ * ps3stor_setup - Setup a storage device before use
+ * @dev: Pointer to a struct ps3_storage_device
+ * @handler: Pointer to an interrupt handler
+ *
+ * Returns 0 for success, or an error code
+ */
+int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler)
+{
+ int error, res, alignment;
+ enum ps3_dma_page_size page_size;
+
+ error = ps3_open_hv_device(&dev->sbd);
+ if (error) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: ps3_open_hv_device failed %d\n", __func__,
+ __LINE__, error);
+ goto fail;
+ }
+
+ error = ps3_sb_event_receive_port_setup(&dev->sbd, PS3_BINDING_CPU_ANY,
+ &dev->irq);
+ if (error) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: ps3_sb_event_receive_port_setup failed %d\n",
+ __func__, __LINE__, error);
+ goto fail_close_device;
+ }
+
+ error = request_irq(dev->irq, handler, IRQF_DISABLED,
+ dev->sbd.core.driver->name, dev);
+ if (error) {
+ dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n",
+ __func__, __LINE__, error);
+ goto fail_sb_event_receive_port_destroy;
+ }
+
+ alignment = min(__ffs(dev->bounce_size),
+ __ffs((unsigned long)dev->bounce_buf));
+ if (alignment < 12) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: bounce buffer not aligned (%lx at 0x%p)\n",
+ __func__, __LINE__, dev->bounce_size, dev->bounce_buf);
+ error = -EINVAL;
+ goto fail_free_irq;
+ } else if (alignment < 16)
+ page_size = PS3_DMA_4K;
+ else
+ page_size = PS3_DMA_64K;
+ dev->sbd.d_region = &dev->dma_region;
+ ps3_dma_region_init(&dev->sbd, &dev->dma_region, page_size,
+ PS3_DMA_OTHER, dev->bounce_buf, dev->bounce_size);
+ res = ps3_dma_region_create(&dev->dma_region);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: cannot create DMA region\n",
+ __func__, __LINE__);
+ error = -ENOMEM;
+ goto fail_free_irq;
+ }
+
+ dev->bounce_lpar = ps3_mm_phys_to_lpar(__pa(dev->bounce_buf));
+ dev->bounce_dma = dma_map_single(&dev->sbd.core, dev->bounce_buf,
+ dev->bounce_size, DMA_BIDIRECTIONAL);
+ if (!dev->bounce_dma) {
+ dev_err(&dev->sbd.core, "%s:%u: map DMA region failed\n",
+ __func__, __LINE__);
+ error = -ENODEV;
+ goto fail_free_dma;
+ }
+
+ error = ps3stor_probe_access(dev);
+ if (error) {
+ dev_err(&dev->sbd.core, "%s:%u: No accessible regions found\n",
+ __func__, __LINE__);
+ goto fail_unmap_dma;
+ }
+ return 0;
+
+fail_unmap_dma:
+ dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
+ DMA_BIDIRECTIONAL);
+fail_free_dma:
+ ps3_dma_region_free(&dev->dma_region);
+fail_free_irq:
+ free_irq(dev->irq, dev);
+fail_sb_event_receive_port_destroy:
+ ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
+fail_close_device:
+ ps3_close_hv_device(&dev->sbd);
+fail:
+ return error;
+}
+EXPORT_SYMBOL_GPL(ps3stor_setup);
+
+
+/**
+ * ps3stor_teardown - Tear down a storage device after use
+ * @dev: Pointer to a struct ps3_storage_device
+ */
+void ps3stor_teardown(struct ps3_storage_device *dev)
+{
+ int error;
+
+ dma_unmap_single(&dev->sbd.core, dev->bounce_dma, dev->bounce_size,
+ DMA_BIDIRECTIONAL);
+ ps3_dma_region_free(&dev->dma_region);
+
+ free_irq(dev->irq, dev);
+
+ error = ps3_sb_event_receive_port_destroy(&dev->sbd, dev->irq);
+ if (error)
+ dev_err(&dev->sbd.core,
+ "%s:%u: destroy event receive port failed %d\n",
+ __func__, __LINE__, error);
+
+ error = ps3_close_hv_device(&dev->sbd);
+ if (error)
+ dev_err(&dev->sbd.core,
+ "%s:%u: ps3_close_hv_device failed %d\n", __func__,
+ __LINE__, error);
+}
+EXPORT_SYMBOL_GPL(ps3stor_teardown);
+
+
+/**
+ * ps3stor_read_write_sectors - read/write from/to a storage device
+ * @dev: Pointer to a struct ps3_storage_device
+ * @lpar: HV logical partition address
+ * @start_sector: First sector to read/write
+ * @sectors: Number of sectors to read/write
+ * @write: Flag indicating write (non-zero) or read (zero)
+ *
+ * Returns 0 for success, -1 in case of failure to submit the command, or
+ * an LV1 status value in case of other errors
+ */
+u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar,
+ u64 start_sector, u64 sectors, int write)
+{
+ unsigned int region_id = dev->regions[dev->region_idx].id;
+ const char *op = write ? "write" : "read";
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+ __func__, __LINE__, op, sectors, start_sector);
+
+ init_completion(&dev->done);
+ res = write ? lv1_storage_write(dev->sbd.dev_id, region_id,
+ start_sector, sectors, 0, lpar,
+ &dev->tag)
+ : lv1_storage_read(dev->sbd.dev_id, region_id,
+ start_sector, sectors, 0, lpar,
+ &dev->tag);
+ if (res) {
+ dev_dbg(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
+ __LINE__, op, res);
+ return -1;
+ }
+
+ wait_for_completion(&dev->done);
+ if (dev->lv1_status) {
+ dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+ __LINE__, op, dev->lv1_status);
+ return dev->lv1_status;
+ }
+
+ dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, __LINE__,
+ op);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3stor_read_write_sectors);
+
+
+/**
+ * ps3stor_send_command - send a device command to a storage device
+ * @dev: Pointer to a struct ps3_storage_device
+ * @cmd: Command number
+ * @arg1: First command argument
+ * @arg2: Second command argument
+ * @arg3: Third command argument
+ * @arg4: Fourth command argument
+ *
+ * Returns 0 for success, -1 in case of failure to submit the command, or
+ * an LV1 status value in case of other errors
+ */
+u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd, u64 arg1,
+ u64 arg2, u64 arg3, u64 arg4)
+{
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: send device command 0x%lx\n", __func__,
+ __LINE__, cmd);
+
+ init_completion(&dev->done);
+
+ res = lv1_storage_send_device_command(dev->sbd.dev_id, cmd, arg1,
+ arg2, arg3, arg4, &dev->tag);
+ if (res) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: send_device_command 0x%lx failed %d\n",
+ __func__, __LINE__, cmd, res);
+ return -1;
+ }
+
+ wait_for_completion(&dev->done);
+ if (dev->lv1_status) {
+ dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx failed 0x%lx\n",
+ __func__, __LINE__, cmd, dev->lv1_status);
+ return dev->lv1_status;
+ }
+
+ dev_dbg(&dev->sbd.core, "%s:%u: command 0x%lx completed\n", __func__,
+ __LINE__, cmd);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ps3stor_send_command);
+
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 Storage Bus Library");
+MODULE_AUTHOR("Sony Corporation");
diff --git a/drivers/ps3/sys-manager-core.c b/drivers/ps3/sys-manager-core.c
new file mode 100644
index 000000000000..31648f7d9ae1
--- /dev/null
+++ b/drivers/ps3/sys-manager-core.c
@@ -0,0 +1,68 @@
+/*
+ * PS3 System Manager core.
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <asm/ps3.h>
+
+/**
+ * Staticly linked routines that allow late binding of a loaded sys-manager
+ * module.
+ */
+
+static struct ps3_sys_manager_ops ps3_sys_manager_ops;
+
+/**
+ * ps3_register_sys_manager_ops - Bind ps3_sys_manager_ops to a module.
+ * @ops: struct ps3_sys_manager_ops.
+ *
+ * To be called from ps3_sys_manager_probe() and ps3_sys_manager_remove() to
+ * register call back ops for power control. Copies data to the static
+ * variable ps3_sys_manager_ops.
+ */
+
+void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops)
+{
+ BUG_ON(!ops);
+ BUG_ON(!ops->dev);
+ ps3_sys_manager_ops = ops ? *ops : ps3_sys_manager_ops;
+}
+EXPORT_SYMBOL_GPL(ps3_sys_manager_register_ops);
+
+void ps3_sys_manager_power_off(void)
+{
+ if (ps3_sys_manager_ops.power_off)
+ ps3_sys_manager_ops.power_off(ps3_sys_manager_ops.dev);
+
+ printk(KERN_EMERG "System Halted, OK to turn off power\n");
+ local_irq_disable();
+ while (1)
+ (void)0;
+}
+
+void ps3_sys_manager_restart(void)
+{
+ if (ps3_sys_manager_ops.restart)
+ ps3_sys_manager_ops.restart(ps3_sys_manager_ops.dev);
+
+ printk(KERN_EMERG "System Halted, OK to turn off power\n");
+ local_irq_disable();
+ while (1)
+ (void)0;
+}
diff --git a/drivers/ps3/sys-manager.c b/drivers/ps3/sys-manager.c
index 3aa2b0dcc369..8461b08ab9fb 100644
--- a/drivers/ps3/sys-manager.c
+++ b/drivers/ps3/sys-manager.c
@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("PS3 System Manager");
/**
* ps3_sys_manager - PS3 system manager driver.
*
- * The system manager provides an asyncronous system event notification
+ * The system manager provides an asynchronous system event notification
* mechanism for reporting events like thermal alert and button presses to
* guests. It also provides support to control system shutdown and startup.
*
@@ -52,6 +52,7 @@ MODULE_DESCRIPTION("PS3 System Manager");
* @size: Header size in bytes, curently 16.
* @payload_size: Message payload size in bytes.
* @service_id: Message type, one of enum ps3_sys_manager_service_id.
+ * @request_tag: Unique number to identify reply.
*/
struct ps3_sys_manager_header {
@@ -61,29 +62,49 @@ struct ps3_sys_manager_header {
u16 reserved_1;
u32 payload_size;
u16 service_id;
- u16 reserved_2[3];
+ u16 reserved_2;
+ u32 request_tag;
};
+#define dump_sm_header(_h) _dump_sm_header(_h, __func__, __LINE__)
+static void __maybe_unused _dump_sm_header(
+ const struct ps3_sys_manager_header *h, const char *func, int line)
+{
+ pr_debug("%s:%d: version: %xh\n", func, line, h->version);
+ pr_debug("%s:%d: size: %xh\n", func, line, h->size);
+ pr_debug("%s:%d: payload_size: %xh\n", func, line, h->payload_size);
+ pr_debug("%s:%d: service_id: %xh\n", func, line, h->service_id);
+ pr_debug("%s:%d: request_tag: %xh\n", func, line, h->request_tag);
+}
+
/**
- * @PS3_SM_RX_MSG_LEN - System manager received message length.
+ * @PS3_SM_RX_MSG_LEN_MIN - Shortest received message length.
+ * @PS3_SM_RX_MSG_LEN_MAX - Longest received message length.
*
- * Currently all messages received from the system manager are the same length
- * (16 bytes header + 16 bytes payload = 32 bytes). This knowlege is used to
- * simplify the logic.
+ * Currently all messages received from the system manager are either
+ * (16 bytes header + 8 bytes payload = 24 bytes) or (16 bytes header
+ * + 16 bytes payload = 32 bytes). This knowlege is used to simplify
+ * the logic.
*/
enum {
- PS3_SM_RX_MSG_LEN = 32,
+ PS3_SM_RX_MSG_LEN_MIN = 24,
+ PS3_SM_RX_MSG_LEN_MAX = 32,
};
/**
* enum ps3_sys_manager_service_id - Message header service_id.
- * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager.
- * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager.
- * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager.
- * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager.
- * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager.
- * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager.
+ * @PS3_SM_SERVICE_ID_REQUEST: guest --> sys_manager.
+ * @PS3_SM_SERVICE_ID_REQUEST_ERROR: guest <-- sys_manager.
+ * @PS3_SM_SERVICE_ID_COMMAND: guest <-- sys_manager.
+ * @PS3_SM_SERVICE_ID_RESPONSE: guest --> sys_manager.
+ * @PS3_SM_SERVICE_ID_SET_ATTR: guest --> sys_manager.
+ * @PS3_SM_SERVICE_ID_EXTERN_EVENT: guest <-- sys_manager.
+ * @PS3_SM_SERVICE_ID_SET_NEXT_OP: guest --> sys_manager.
+ *
+ * PS3_SM_SERVICE_ID_REQUEST_ERROR is returned for invalid data values in a
+ * a PS3_SM_SERVICE_ID_REQUEST message. It also seems to be returned when
+ * a REQUEST message is sent at the wrong time.
*/
enum ps3_sys_manager_service_id {
@@ -93,6 +114,7 @@ enum ps3_sys_manager_service_id {
PS3_SM_SERVICE_ID_COMMAND = 3,
PS3_SM_SERVICE_ID_EXTERN_EVENT = 4,
PS3_SM_SERVICE_ID_SET_NEXT_OP = 5,
+ PS3_SM_SERVICE_ID_REQUEST_ERROR = 6,
PS3_SM_SERVICE_ID_SET_ATTR = 8,
};
@@ -185,11 +207,21 @@ enum ps3_sys_manager_cmd {
};
/**
+ * ps3_sm_force_power_off - Poweroff helper.
+ *
+ * A global variable used to force a poweroff when the power button has
+ * been pressed irrespective of how init handles the ctrl_alt_del signal.
+ *
+ */
+
+static unsigned int ps3_sm_force_power_off;
+
+/**
* ps3_sys_manager_write - Helper to write a two part message to the vuart.
*
*/
-static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev,
+static int ps3_sys_manager_write(struct ps3_system_bus_device *dev,
const struct ps3_sys_manager_header *header, const void *payload)
{
int result;
@@ -213,15 +245,10 @@ static int ps3_sys_manager_write(struct ps3_vuart_port_device *dev,
*
*/
-static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev,
+static int ps3_sys_manager_send_attr(struct ps3_system_bus_device *dev,
enum ps3_sys_manager_attr attr)
{
- static const struct ps3_sys_manager_header header = {
- .version = 1,
- .size = 16,
- .payload_size = 16,
- .service_id = PS3_SM_SERVICE_ID_SET_ATTR,
- };
+ struct ps3_sys_manager_header header;
struct {
u8 version;
u8 reserved_1[3];
@@ -232,6 +259,12 @@ static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev,
dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, attr);
+ memset(&header, 0, sizeof(header));
+ header.version = 1;
+ header.size = 16;
+ header.payload_size = 16;
+ header.service_id = PS3_SM_SERVICE_ID_SET_ATTR;
+
memset(&payload, 0, sizeof(payload));
payload.version = 1;
payload.attribute = attr;
@@ -245,16 +278,11 @@ static int ps3_sys_manager_send_attr(struct ps3_vuart_port_device *dev,
* Tell the system manager what to do after this lpar is destroyed.
*/
-static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev,
+static int ps3_sys_manager_send_next_op(struct ps3_system_bus_device *dev,
enum ps3_sys_manager_next_op op,
enum ps3_sys_manager_wake_source wake_source)
{
- static const struct ps3_sys_manager_header header = {
- .version = 1,
- .size = 16,
- .payload_size = 16,
- .service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP,
- };
+ struct ps3_sys_manager_header header;
struct {
u8 version;
u8 type;
@@ -268,6 +296,12 @@ static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev,
dev_dbg(&dev->core, "%s:%d: (%xh)\n", __func__, __LINE__, op);
+ memset(&header, 0, sizeof(header));
+ header.version = 1;
+ header.size = 16;
+ header.payload_size = 16;
+ header.service_id = PS3_SM_SERVICE_ID_SET_NEXT_OP;
+
memset(&payload, 0, sizeof(payload));
payload.version = 3;
payload.type = op;
@@ -286,32 +320,35 @@ static int ps3_sys_manager_send_next_op(struct ps3_vuart_port_device *dev,
* the command is then communicated back to the system manager with a response
* message.
*
- * Currently, the only supported request it the 'shutdown self' request.
+ * Currently, the only supported request is the 'shutdown self' request.
*/
-static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *dev)
+static int ps3_sys_manager_send_request_shutdown(
+ struct ps3_system_bus_device *dev)
{
- static const struct ps3_sys_manager_header header = {
- .version = 1,
- .size = 16,
- .payload_size = 16,
- .service_id = PS3_SM_SERVICE_ID_REQUEST,
- };
+ struct ps3_sys_manager_header header;
struct {
u8 version;
u8 type;
u8 gos_id;
u8 reserved_1[13];
- } static const payload = {
- .version = 1,
- .type = 1, /* shutdown */
- .gos_id = 0, /* self */
- };
+ } payload;
BUILD_BUG_ON(sizeof(payload) != 16);
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+ memset(&header, 0, sizeof(header));
+ header.version = 1;
+ header.size = 16;
+ header.payload_size = 16;
+ header.service_id = PS3_SM_SERVICE_ID_REQUEST;
+
+ memset(&payload, 0, sizeof(payload));
+ payload.version = 1;
+ payload.type = 1; /* shutdown */
+ payload.gos_id = 0; /* self */
+
return ps3_sys_manager_write(dev, &header, &payload);
}
@@ -323,15 +360,10 @@ static int ps3_sys_manager_send_request_shutdown(struct ps3_vuart_port_device *d
* failure of a command sent by the system manager.
*/
-static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev,
+static int ps3_sys_manager_send_response(struct ps3_system_bus_device *dev,
u64 status)
{
- static const struct ps3_sys_manager_header header = {
- .version = 1,
- .size = 16,
- .payload_size = 16,
- .service_id = PS3_SM_SERVICE_ID_RESPONSE,
- };
+ struct ps3_sys_manager_header header;
struct {
u8 version;
u8 reserved_1[3];
@@ -344,6 +376,12 @@ static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev,
dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
(status ? "nak" : "ack"));
+ memset(&header, 0, sizeof(header));
+ header.version = 1;
+ header.size = 16;
+ header.payload_size = 16;
+ header.service_id = PS3_SM_SERVICE_ID_RESPONSE;
+
memset(&payload, 0, sizeof(payload));
payload.version = 1;
payload.status = status;
@@ -356,7 +394,7 @@ static int ps3_sys_manager_send_response(struct ps3_vuart_port_device *dev,
*
*/
-static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
+static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev)
{
int result;
struct {
@@ -370,7 +408,7 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
BUILD_BUG_ON(sizeof(event) != 16);
result = ps3_vuart_read(dev, &event, sizeof(event));
- BUG_ON(result);
+ BUG_ON(result && "need to retry here");
if (event.version != 1) {
dev_dbg(&dev->core, "%s:%d: unsupported event version (%u)\n",
@@ -382,11 +420,34 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
case PS3_SM_EVENT_POWER_PRESSED:
dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n",
__func__, __LINE__);
+ ps3_sm_force_power_off = 1;
+ /*
+ * A memory barrier is use here to sync memory since
+ * ps3_sys_manager_final_restart() could be called on
+ * another cpu.
+ */
+ wmb();
+ kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */
break;
case PS3_SM_EVENT_POWER_RELEASED:
dev_dbg(&dev->core, "%s:%d: POWER_RELEASED (%u ms)\n",
__func__, __LINE__, event.value);
- kill_cad_pid(SIGINT, 1);
+ break;
+ case PS3_SM_EVENT_RESET_PRESSED:
+ dev_dbg(&dev->core, "%s:%d: RESET_PRESSED\n",
+ __func__, __LINE__);
+ ps3_sm_force_power_off = 0;
+ /*
+ * A memory barrier is use here to sync memory since
+ * ps3_sys_manager_final_restart() could be called on
+ * another cpu.
+ */
+ wmb();
+ kill_cad_pid(SIGINT, 1); /* ctrl_alt_del */
+ break;
+ case PS3_SM_EVENT_RESET_RELEASED:
+ dev_dbg(&dev->core, "%s:%d: RESET_RELEASED (%u ms)\n",
+ __func__, __LINE__, event.value);
break;
case PS3_SM_EVENT_THERMAL_ALERT:
dev_dbg(&dev->core, "%s:%d: THERMAL_ALERT (zone %u)\n",
@@ -411,7 +472,7 @@ static int ps3_sys_manager_handle_event(struct ps3_vuart_port_device *dev)
* The system manager sends this in reply to a 'request' message from the guest.
*/
-static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev)
+static int ps3_sys_manager_handle_cmd(struct ps3_system_bus_device *dev)
{
int result;
struct {
@@ -425,6 +486,7 @@ static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev)
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
result = ps3_vuart_read(dev, &cmd, sizeof(cmd));
+ BUG_ON(result && "need to retry here");
if(result)
return result;
@@ -448,9 +510,10 @@ static int ps3_sys_manager_handle_cmd(struct ps3_vuart_port_device *dev)
/**
* ps3_sys_manager_handle_msg - First stage msg handler.
*
+ * Can be called directly to manually poll vuart and pump message handler.
*/
-static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev)
+static int ps3_sys_manager_handle_msg(struct ps3_system_bus_device *dev)
{
int result;
struct ps3_sys_manager_header header;
@@ -464,12 +527,17 @@ static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev)
if (header.version != 1) {
dev_dbg(&dev->core, "%s:%d: unsupported header version (%u)\n",
__func__, __LINE__, header.version);
+ dump_sm_header(&header);
goto fail_header;
}
BUILD_BUG_ON(sizeof(header) != 16);
- BUG_ON(header.size != 16);
- BUG_ON(header.payload_size != 16);
+
+ if (header.size != 16 || (header.payload_size != 8
+ && header.payload_size != 16)) {
+ dump_sm_header(&header);
+ BUG();
+ }
switch (header.service_id) {
case PS3_SM_SERVICE_ID_EXTERN_EVENT:
@@ -478,6 +546,11 @@ static int ps3_sys_manager_handle_msg(struct ps3_vuart_port_device *dev)
case PS3_SM_SERVICE_ID_COMMAND:
dev_dbg(&dev->core, "%s:%d: COMMAND\n", __func__, __LINE__);
return ps3_sys_manager_handle_cmd(dev);
+ case PS3_SM_SERVICE_ID_REQUEST_ERROR:
+ dev_dbg(&dev->core, "%s:%d: REQUEST_ERROR\n", __func__,
+ __LINE__);
+ dump_sm_header(&header);
+ break;
default:
dev_dbg(&dev->core, "%s:%d: unknown service_id (%u)\n",
__func__, __LINE__, header.service_id);
@@ -494,45 +567,25 @@ fail_id:
}
/**
- * ps3_sys_manager_work - Asyncronous read handler.
- *
- * Signaled when a complete message arrives at the vuart port.
- */
-
-static void ps3_sys_manager_work(struct work_struct *work)
-{
- struct ps3_vuart_port_device *dev = ps3_vuart_work_to_port_device(work);
-
- ps3_sys_manager_handle_msg(dev);
- ps3_vuart_read_async(dev, ps3_sys_manager_work, PS3_SM_RX_MSG_LEN);
-}
-
-struct {
- struct ps3_vuart_port_device *dev;
-} static drv_priv;
-
-/**
- * ps3_sys_manager_restart - The final platform machine_restart routine.
+ * ps3_sys_manager_final_power_off - The final platform machine_power_off routine.
*
- * This routine never returns. The routine disables asyncronous vuart reads
+ * This routine never returns. The routine disables asynchronous vuart reads
* then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
* the shutdown command sent from the system manager. Soon after the
* acknowledgement is sent the lpar is destroyed by the HV. This routine
- * should only be called from ps3_restart().
+ * should only be called from ps3_power_off() through
+ * ps3_sys_manager_ops.power_off.
*/
-void ps3_sys_manager_restart(void)
+static void ps3_sys_manager_final_power_off(struct ps3_system_bus_device *dev)
{
- struct ps3_vuart_port_device *dev = drv_priv.dev;
-
- BUG_ON(!drv_priv.dev);
+ BUG_ON(!dev);
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
ps3_vuart_cancel_async(dev);
- ps3_sys_manager_send_attr(dev, 0);
- ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT,
+ ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
PS3_SM_WAKE_DEFAULT);
ps3_sys_manager_send_request_shutdown(dev);
@@ -543,26 +596,33 @@ void ps3_sys_manager_restart(void)
}
/**
- * ps3_sys_manager_power_off - The final platform machine_power_off routine.
+ * ps3_sys_manager_final_restart - The final platform machine_restart routine.
*
- * This routine never returns. The routine disables asyncronous vuart reads
+ * This routine never returns. The routine disables asynchronous vuart reads
* then spins calling ps3_sys_manager_handle_msg() to receive and acknowledge
* the shutdown command sent from the system manager. Soon after the
* acknowledgement is sent the lpar is destroyed by the HV. This routine
- * should only be called from ps3_power_off().
+ * should only be called from ps3_restart() through ps3_sys_manager_ops.restart.
*/
-void ps3_sys_manager_power_off(void)
+static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev)
{
- struct ps3_vuart_port_device *dev = drv_priv.dev;
-
- BUG_ON(!drv_priv.dev);
+ BUG_ON(!dev);
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+ /* Check if we got here via a power button event. */
+
+ if (ps3_sm_force_power_off) {
+ dev_dbg(&dev->core, "%s:%d: forcing poweroff\n",
+ __func__, __LINE__);
+ ps3_sys_manager_final_power_off(dev);
+ }
+
ps3_vuart_cancel_async(dev);
- ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_SHUTDOWN,
+ ps3_sys_manager_send_attr(dev, 0);
+ ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT,
PS3_SM_WAKE_DEFAULT);
ps3_sys_manager_send_request_shutdown(dev);
@@ -572,31 +632,60 @@ void ps3_sys_manager_power_off(void)
ps3_sys_manager_handle_msg(dev);
}
-static int ps3_sys_manager_probe(struct ps3_vuart_port_device *dev)
+/**
+ * ps3_sys_manager_work - Asynchronous read handler.
+ *
+ * Signaled when PS3_SM_RX_MSG_LEN_MIN bytes arrive at the vuart port.
+ */
+
+static void ps3_sys_manager_work(struct ps3_system_bus_device *dev)
+{
+ ps3_sys_manager_handle_msg(dev);
+ ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
+}
+
+static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev)
{
int result;
+ struct ps3_sys_manager_ops ops;
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
- BUG_ON(drv_priv.dev);
- drv_priv.dev = dev;
+ ops.power_off = ps3_sys_manager_final_power_off;
+ ops.restart = ps3_sys_manager_final_restart;
+ ops.dev = dev;
+
+ /* ps3_sys_manager_register_ops copies ops. */
+
+ ps3_sys_manager_register_ops(&ops);
result = ps3_sys_manager_send_attr(dev, PS3_SM_ATTR_ALL);
BUG_ON(result);
- result = ps3_vuart_read_async(dev, ps3_sys_manager_work,
- PS3_SM_RX_MSG_LEN);
+ result = ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN);
BUG_ON(result);
return result;
}
+static int ps3_sys_manager_remove(struct ps3_system_bus_device *dev)
+{
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+ return 0;
+}
+
+static void ps3_sys_manager_shutdown(struct ps3_system_bus_device *dev)
+{
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+}
+
static struct ps3_vuart_port_driver ps3_sys_manager = {
- .match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
- .core = {
- .name = "ps3_sys_manager",
- },
+ .core.match_id = PS3_MATCH_ID_SYSTEM_MANAGER,
+ .core.core.name = "ps3_sys_manager",
.probe = ps3_sys_manager_probe,
+ .remove = ps3_sys_manager_remove,
+ .shutdown = ps3_sys_manager_shutdown,
+ .work = ps3_sys_manager_work,
};
static int __init ps3_sys_manager_init(void)
@@ -608,3 +697,6 @@ static int __init ps3_sys_manager_init(void)
}
module_init(ps3_sys_manager_init);
+/* Module remove not supported. */
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER);
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c
index ec2d36a1bc67..bea25a1391ee 100644
--- a/drivers/ps3/vuart.c
+++ b/drivers/ps3/vuart.c
@@ -71,6 +71,34 @@ enum vuart_interrupt_mask {
};
/**
+ * struct ps3_vuart_port_priv - private vuart device data.
+ */
+
+struct ps3_vuart_port_priv {
+ u64 interrupt_mask;
+
+ struct {
+ spinlock_t lock;
+ struct list_head head;
+ } tx_list;
+ struct {
+ struct ps3_vuart_work work;
+ unsigned long bytes_held;
+ spinlock_t lock;
+ struct list_head head;
+ } rx_list;
+ struct ps3_vuart_stats stats;
+};
+
+static struct ps3_vuart_port_priv *to_port_priv(
+ struct ps3_system_bus_device *dev)
+{
+ BUG_ON(!dev);
+ BUG_ON(!dev->driver_priv);
+ return (struct ps3_vuart_port_priv *)dev->driver_priv;
+}
+
+/**
* struct ports_bmp - bitmap indicating ports needing service.
*
* A 256 bit read only bitmap indicating ports needing service. Do not write
@@ -83,31 +111,14 @@ struct ports_bmp {
} __attribute__ ((aligned (32)));
#define dump_ports_bmp(_b) _dump_ports_bmp(_b, __func__, __LINE__)
-static void __attribute__ ((unused)) _dump_ports_bmp(
+static void __maybe_unused _dump_ports_bmp(
const struct ports_bmp* bmp, const char* func, int line)
{
pr_debug("%s:%d: ports_bmp: %016lxh\n", func, line, bmp->status);
}
-static int ps3_vuart_match_id_to_port(enum ps3_match_id match_id,
- unsigned int *port_number)
-{
- switch(match_id) {
- case PS3_MATCH_ID_AV_SETTINGS:
- *port_number = 0;
- return 0;
- case PS3_MATCH_ID_SYSTEM_MANAGER:
- *port_number = 2;
- return 0;
- default:
- WARN_ON(1);
- *port_number = UINT_MAX;
- return -EINVAL;
- };
-}
-
#define dump_port_params(_b) _dump_port_params(_b, __func__, __LINE__)
-static void __attribute__ ((unused)) _dump_port_params(unsigned int port_number,
+static void __maybe_unused _dump_port_params(unsigned int port_number,
const char* func, int line)
{
#if defined(DEBUG)
@@ -144,14 +155,14 @@ struct vuart_triggers {
unsigned long tx;
};
-int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
+int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev,
struct vuart_triggers *trig)
{
int result;
unsigned long size;
unsigned long val;
- result = lv1_get_virtual_uart_param(dev->priv->port_number,
+ result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_TX_TRIGGER, &trig->tx);
if (result) {
@@ -160,7 +171,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
return result;
}
- result = lv1_get_virtual_uart_param(dev->priv->port_number,
+ result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_BUF_SIZE, &size);
if (result) {
@@ -169,7 +180,7 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
return result;
}
- result = lv1_get_virtual_uart_param(dev->priv->port_number,
+ result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_TRIGGER, &val);
if (result) {
@@ -186,13 +197,13 @@ int ps3_vuart_get_triggers(struct ps3_vuart_port_device *dev,
return result;
}
-int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
+int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx,
unsigned int rx)
{
int result;
unsigned long size;
- result = lv1_set_virtual_uart_param(dev->priv->port_number,
+ result = lv1_set_virtual_uart_param(dev->port_number,
PARAM_TX_TRIGGER, tx);
if (result) {
@@ -201,7 +212,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
return result;
}
- result = lv1_get_virtual_uart_param(dev->priv->port_number,
+ result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_BUF_SIZE, &size);
if (result) {
@@ -210,7 +221,7 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
return result;
}
- result = lv1_set_virtual_uart_param(dev->priv->port_number,
+ result = lv1_set_virtual_uart_param(dev->port_number,
PARAM_RX_TRIGGER, size - rx);
if (result) {
@@ -225,10 +236,12 @@ int ps3_vuart_set_triggers(struct ps3_vuart_port_device *dev, unsigned int tx,
return result;
}
-static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
+static int ps3_vuart_get_rx_bytes_waiting(struct ps3_system_bus_device *dev,
u64 *bytes_waiting)
{
- int result = lv1_get_virtual_uart_param(dev->priv->port_number,
+ int result;
+
+ result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_RX_BYTES, bytes_waiting);
if (result)
@@ -240,17 +253,24 @@ static int ps3_vuart_get_rx_bytes_waiting(struct ps3_vuart_port_device *dev,
return result;
}
-static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
+/**
+ * ps3_vuart_set_interrupt_mask - Enable/disable the port interrupt sources.
+ * @dev: The struct ps3_system_bus_device instance.
+ * @bmp: Logical OR of enum vuart_interrupt_mask values. A zero bit disables.
+ */
+
+static int ps3_vuart_set_interrupt_mask(struct ps3_system_bus_device *dev,
unsigned long mask)
{
int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
dev_dbg(&dev->core, "%s:%d: %lxh\n", __func__, __LINE__, mask);
- dev->priv->interrupt_mask = mask;
+ priv->interrupt_mask = mask;
- result = lv1_set_virtual_uart_param(dev->priv->port_number,
- PARAM_INTERRUPT_MASK, dev->priv->interrupt_mask);
+ result = lv1_set_virtual_uart_param(dev->port_number,
+ PARAM_INTERRUPT_MASK, priv->interrupt_mask);
if (result)
dev_dbg(&dev->core, "%s:%d: interrupt_mask failed: %s\n",
@@ -259,79 +279,96 @@ static int ps3_vuart_set_interrupt_mask(struct ps3_vuart_port_device *dev,
return result;
}
-static int ps3_vuart_get_interrupt_status(struct ps3_vuart_port_device *dev,
+static int ps3_vuart_get_interrupt_status(struct ps3_system_bus_device *dev,
unsigned long *status)
{
+ int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
u64 tmp;
- int result = lv1_get_virtual_uart_param(dev->priv->port_number,
+
+ result = lv1_get_virtual_uart_param(dev->port_number,
PARAM_INTERRUPT_STATUS, &tmp);
if (result)
dev_dbg(&dev->core, "%s:%d: interrupt_status failed: %s\n",
__func__, __LINE__, ps3_result(result));
- *status = tmp & dev->priv->interrupt_mask;
+ *status = tmp & priv->interrupt_mask;
dev_dbg(&dev->core, "%s:%d: m %lxh, s %lxh, m&s %lxh\n",
- __func__, __LINE__, dev->priv->interrupt_mask, tmp, *status);
+ __func__, __LINE__, priv->interrupt_mask, tmp, *status);
return result;
}
-int ps3_vuart_enable_interrupt_tx(struct ps3_vuart_port_device *dev)
+int ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev)
{
- return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0
- : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+
+ return (priv->interrupt_mask & INTERRUPT_MASK_TX) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
| INTERRUPT_MASK_TX);
}
-int ps3_vuart_enable_interrupt_rx(struct ps3_vuart_port_device *dev)
+int ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev)
{
- return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0
- : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+
+ return (priv->interrupt_mask & INTERRUPT_MASK_RX) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
| INTERRUPT_MASK_RX);
}
-int ps3_vuart_enable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+int ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev)
{
- return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
- : ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+
+ return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT) ? 0
+ : ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
| INTERRUPT_MASK_DISCONNECT);
}
-int ps3_vuart_disable_interrupt_tx(struct ps3_vuart_port_device *dev)
+int ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev)
{
- return (dev->priv->interrupt_mask & INTERRUPT_MASK_TX)
- ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+
+ return (priv->interrupt_mask & INTERRUPT_MASK_TX)
+ ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
& ~INTERRUPT_MASK_TX) : 0;
}
-int ps3_vuart_disable_interrupt_rx(struct ps3_vuart_port_device *dev)
+int ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev)
{
- return (dev->priv->interrupt_mask & INTERRUPT_MASK_RX)
- ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+
+ return (priv->interrupt_mask & INTERRUPT_MASK_RX)
+ ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
& ~INTERRUPT_MASK_RX) : 0;
}
-int ps3_vuart_disable_interrupt_disconnect(struct ps3_vuart_port_device *dev)
+int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev)
{
- return (dev->priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
- ? ps3_vuart_set_interrupt_mask(dev, dev->priv->interrupt_mask
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+
+ return (priv->interrupt_mask & INTERRUPT_MASK_DISCONNECT)
+ ? ps3_vuart_set_interrupt_mask(dev, priv->interrupt_mask
& ~INTERRUPT_MASK_DISCONNECT) : 0;
}
/**
* ps3_vuart_raw_write - Low level write helper.
+ * @dev: The struct ps3_system_bus_device instance.
*
* Do not call ps3_vuart_raw_write directly, use ps3_vuart_write.
*/
-static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
+static int ps3_vuart_raw_write(struct ps3_system_bus_device *dev,
const void* buf, unsigned int bytes, unsigned long *bytes_written)
{
int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
- result = lv1_write_virtual_uart(dev->priv->port_number,
+ result = lv1_write_virtual_uart(dev->port_number,
ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_written);
if (result) {
@@ -340,28 +377,30 @@ static int ps3_vuart_raw_write(struct ps3_vuart_port_device *dev,
return result;
}
- dev->priv->stats.bytes_written += *bytes_written;
+ priv->stats.bytes_written += *bytes_written;
dev_dbg(&dev->core, "%s:%d: wrote %lxh/%xh=>%lxh\n", __func__, __LINE__,
- *bytes_written, bytes, dev->priv->stats.bytes_written);
+ *bytes_written, bytes, priv->stats.bytes_written);
return result;
}
/**
* ps3_vuart_raw_read - Low level read helper.
+ * @dev: The struct ps3_system_bus_device instance.
*
* Do not call ps3_vuart_raw_read directly, use ps3_vuart_read.
*/
-static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
+static int ps3_vuart_raw_read(struct ps3_system_bus_device *dev, void *buf,
unsigned int bytes, unsigned long *bytes_read)
{
int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
dev_dbg(&dev->core, "%s:%d: %xh\n", __func__, __LINE__, bytes);
- result = lv1_read_virtual_uart(dev->priv->port_number,
+ result = lv1_read_virtual_uart(dev->port_number,
ps3_mm_phys_to_lpar(__pa(buf)), bytes, bytes_read);
if (result) {
@@ -370,25 +409,27 @@ static int ps3_vuart_raw_read(struct ps3_vuart_port_device *dev, void* buf,
return result;
}
- dev->priv->stats.bytes_read += *bytes_read;
+ priv->stats.bytes_read += *bytes_read;
dev_dbg(&dev->core, "%s:%d: read %lxh/%xh=>%lxh\n", __func__, __LINE__,
- *bytes_read, bytes, dev->priv->stats.bytes_read);
+ *bytes_read, bytes, priv->stats.bytes_read);
return result;
}
/**
* ps3_vuart_clear_rx_bytes - Discard bytes received.
+ * @dev: The struct ps3_system_bus_device instance.
* @bytes: Max byte count to discard, zero = all pending.
*
* Used to clear pending rx interrupt source. Will not block.
*/
-void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
+void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev,
unsigned int bytes)
{
int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
u64 bytes_waiting;
void* tmp;
@@ -418,8 +459,9 @@ void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
/* Don't include these bytes in the stats. */
- dev->priv->stats.bytes_read -= bytes_waiting;
+ priv->stats.bytes_read -= bytes_waiting;
}
+EXPORT_SYMBOL_GPL(ps3_vuart_clear_rx_bytes);
/**
* struct list_buffer - An element for a port device fifo buffer list.
@@ -435,6 +477,7 @@ struct list_buffer {
/**
* ps3_vuart_write - the entry point for writing data to a port
+ * @dev: The struct ps3_system_bus_device instance.
*
* If the port is idle on entry as much of the incoming data is written to
* the port as the port will accept. Otherwise a list buffer is created
@@ -442,25 +485,26 @@ struct list_buffer {
* then enqueued for transmision via the transmit interrupt.
*/
-int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
+int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf,
unsigned int bytes)
{
static unsigned long dbg_number;
int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
unsigned long flags;
struct list_buffer *lb;
dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
bytes, bytes);
- spin_lock_irqsave(&dev->priv->tx_list.lock, flags);
+ spin_lock_irqsave(&priv->tx_list.lock, flags);
- if (list_empty(&dev->priv->tx_list.head)) {
+ if (list_empty(&priv->tx_list.head)) {
unsigned long bytes_written;
result = ps3_vuart_raw_write(dev, buf, bytes, &bytes_written);
- spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
+ spin_unlock_irqrestore(&priv->tx_list.lock, flags);
if (result) {
dev_dbg(&dev->core,
@@ -478,7 +522,7 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
bytes -= bytes_written;
buf += bytes_written;
} else
- spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
+ spin_unlock_irqrestore(&priv->tx_list.lock, flags);
lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_KERNEL);
@@ -491,29 +535,86 @@ int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
lb->tail = lb->data + bytes;
lb->dbg_number = ++dbg_number;
- spin_lock_irqsave(&dev->priv->tx_list.lock, flags);
- list_add_tail(&lb->link, &dev->priv->tx_list.head);
+ spin_lock_irqsave(&priv->tx_list.lock, flags);
+ list_add_tail(&lb->link, &priv->tx_list.head);
ps3_vuart_enable_interrupt_tx(dev);
- spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
+ spin_unlock_irqrestore(&priv->tx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: queued buf_%lu, %xh bytes\n",
__func__, __LINE__, lb->dbg_number, bytes);
return 0;
}
+EXPORT_SYMBOL_GPL(ps3_vuart_write);
+
+/**
+ * ps3_vuart_queue_rx_bytes - Queue waiting bytes into the buffer list.
+ * @dev: The struct ps3_system_bus_device instance.
+ * @bytes_queued: Number of bytes queued to the buffer list.
+ *
+ * Must be called with priv->rx_list.lock held.
+ */
+
+static int ps3_vuart_queue_rx_bytes(struct ps3_system_bus_device *dev,
+ u64 *bytes_queued)
+{
+ static unsigned long dbg_number;
+ int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+ struct list_buffer *lb;
+ u64 bytes;
+
+ *bytes_queued = 0;
+
+ result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
+ BUG_ON(result);
+
+ if (result)
+ return -EIO;
+
+ if (!bytes)
+ return 0;
+
+ /* Add some extra space for recently arrived data. */
+
+ bytes += 128;
+
+ lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
+
+ if (!lb)
+ return -ENOMEM;
+
+ ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
+
+ lb->head = lb->data;
+ lb->tail = lb->data + bytes;
+ lb->dbg_number = ++dbg_number;
+
+ list_add_tail(&lb->link, &priv->rx_list.head);
+ priv->rx_list.bytes_held += bytes;
+
+ dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",
+ __func__, __LINE__, lb->dbg_number, bytes);
+
+ *bytes_queued = bytes;
+
+ return 0;
+}
/**
- * ps3_vuart_read - the entry point for reading data from a port
+ * ps3_vuart_read - The entry point for reading data from a port.
*
- * If enough bytes to satisfy the request are held in the buffer list those
- * bytes are dequeued and copied to the caller's buffer. Emptied list buffers
- * are retiered. If the request cannot be statified by bytes held in the list
- * buffers -EAGAIN is returned.
+ * Queue data waiting at the port, and if enough bytes to satisfy the request
+ * are held in the buffer list those bytes are dequeued and copied to the
+ * caller's buffer. Emptied list buffers are retiered. If the request cannot
+ * be statified by bytes held in the list buffers -EAGAIN is returned.
*/
-int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf,
unsigned int bytes)
{
+ int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
unsigned long flags;
struct list_buffer *lb, *n;
unsigned long bytes_read;
@@ -521,30 +622,37 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
dev_dbg(&dev->core, "%s:%d: %u(%xh) bytes\n", __func__, __LINE__,
bytes, bytes);
- spin_lock_irqsave(&dev->priv->rx_list.lock, flags);
+ spin_lock_irqsave(&priv->rx_list.lock, flags);
- if (dev->priv->rx_list.bytes_held < bytes) {
- spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
- dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
- __func__, __LINE__,
- bytes - dev->priv->rx_list.bytes_held);
- return -EAGAIN;
+ /* Queue rx bytes here for polled reads. */
+
+ while (priv->rx_list.bytes_held < bytes) {
+ u64 tmp;
+
+ result = ps3_vuart_queue_rx_bytes(dev, &tmp);
+ if (result || !tmp) {
+ dev_dbg(&dev->core, "%s:%d: starved for %lxh bytes\n",
+ __func__, __LINE__,
+ bytes - priv->rx_list.bytes_held);
+ spin_unlock_irqrestore(&priv->rx_list.lock, flags);
+ return -EAGAIN;
+ }
}
- list_for_each_entry_safe(lb, n, &dev->priv->rx_list.head, link) {
+ list_for_each_entry_safe(lb, n, &priv->rx_list.head, link) {
bytes_read = min((unsigned int)(lb->tail - lb->head), bytes);
memcpy(buf, lb->head, bytes_read);
buf += bytes_read;
bytes -= bytes_read;
- dev->priv->rx_list.bytes_held -= bytes_read;
+ priv->rx_list.bytes_held -= bytes_read;
if (bytes_read < lb->tail - lb->head) {
lb->head += bytes_read;
dev_dbg(&dev->core, "%s:%d: buf_%lu: dequeued %lxh "
"bytes\n", __func__, __LINE__, lb->dbg_number,
bytes_read);
- spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
+ spin_unlock_irqrestore(&priv->rx_list.lock, flags);
return 0;
}
@@ -556,16 +664,32 @@ int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
kfree(lb);
}
- spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
+ spin_unlock_irqrestore(&priv->rx_list.lock, flags);
return 0;
}
+EXPORT_SYMBOL_GPL(ps3_vuart_read);
-int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
- unsigned int bytes)
+/**
+ * ps3_vuart_work - Asynchronous read handler.
+ */
+
+static void ps3_vuart_work(struct work_struct *work)
+{
+ struct ps3_system_bus_device *dev =
+ ps3_vuart_work_to_system_bus_dev(work);
+ struct ps3_vuart_port_driver *drv =
+ ps3_system_bus_dev_to_vuart_drv(dev);
+
+ BUG_ON(!drv);
+ drv->work(dev);
+}
+
+int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes)
{
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
unsigned long flags;
- if(dev->priv->work.trigger) {
+ if (priv->rx_list.work.trigger) {
dev_dbg(&dev->core, "%s:%d: warning, multiple calls\n",
__func__, __LINE__);
return -EAGAIN;
@@ -573,30 +697,32 @@ int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
BUG_ON(!bytes);
- PREPARE_WORK(&dev->priv->work.work, func);
+ PREPARE_WORK(&priv->rx_list.work.work, ps3_vuart_work);
- spin_lock_irqsave(&dev->priv->work.lock, flags);
- if(dev->priv->rx_list.bytes_held >= bytes) {
+ spin_lock_irqsave(&priv->rx_list.lock, flags);
+ if (priv->rx_list.bytes_held >= bytes) {
dev_dbg(&dev->core, "%s:%d: schedule_work %xh bytes\n",
__func__, __LINE__, bytes);
- schedule_work(&dev->priv->work.work);
- spin_unlock_irqrestore(&dev->priv->work.lock, flags);
+ schedule_work(&priv->rx_list.work.work);
+ spin_unlock_irqrestore(&priv->rx_list.lock, flags);
return 0;
}
- dev->priv->work.trigger = bytes;
- spin_unlock_irqrestore(&dev->priv->work.lock, flags);
+ priv->rx_list.work.trigger = bytes;
+ spin_unlock_irqrestore(&priv->rx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d: waiting for %u(%xh) bytes\n", __func__,
__LINE__, bytes, bytes);
return 0;
}
+EXPORT_SYMBOL_GPL(ps3_vuart_read_async);
-void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev)
+void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev)
{
- dev->priv->work.trigger = 0;
+ to_port_priv(dev)->rx_list.work.trigger = 0;
}
+EXPORT_SYMBOL_GPL(ps3_vuart_cancel_async);
/**
* ps3_vuart_handle_interrupt_tx - third stage transmit interrupt handler
@@ -606,18 +732,19 @@ void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev)
* adjusts the final list buffer state for a partial write.
*/
-static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
+static int ps3_vuart_handle_interrupt_tx(struct ps3_system_bus_device *dev)
{
int result = 0;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
unsigned long flags;
struct list_buffer *lb, *n;
unsigned long bytes_total = 0;
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
- spin_lock_irqsave(&dev->priv->tx_list.lock, flags);
+ spin_lock_irqsave(&priv->tx_list.lock, flags);
- list_for_each_entry_safe(lb, n, &dev->priv->tx_list.head, link) {
+ list_for_each_entry_safe(lb, n, &priv->tx_list.head, link) {
unsigned long bytes_written;
@@ -651,7 +778,7 @@ static int ps3_vuart_handle_interrupt_tx(struct ps3_vuart_port_device *dev)
ps3_vuart_disable_interrupt_tx(dev);
port_full:
- spin_unlock_irqrestore(&dev->priv->tx_list.lock, flags);
+ spin_unlock_irqrestore(&priv->tx_list.lock, flags);
dev_dbg(&dev->core, "%s:%d wrote %lxh bytes total\n",
__func__, __LINE__, bytes_total);
return result;
@@ -665,60 +792,37 @@ port_full:
* buffer list. Buffer list data is dequeued via ps3_vuart_read.
*/
-static int ps3_vuart_handle_interrupt_rx(struct ps3_vuart_port_device *dev)
+static int ps3_vuart_handle_interrupt_rx(struct ps3_system_bus_device *dev)
{
- static unsigned long dbg_number;
- int result = 0;
+ int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
unsigned long flags;
- struct list_buffer *lb;
- unsigned long bytes;
+ u64 bytes;
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
- result = ps3_vuart_get_rx_bytes_waiting(dev, &bytes);
-
- if (result)
- return -EIO;
-
- BUG_ON(!bytes);
-
- /* Add some extra space for recently arrived data. */
-
- bytes += 128;
-
- lb = kmalloc(sizeof(struct list_buffer) + bytes, GFP_ATOMIC);
+ spin_lock_irqsave(&priv->rx_list.lock, flags);
+ result = ps3_vuart_queue_rx_bytes(dev, &bytes);
- if (!lb)
- return -ENOMEM;
-
- ps3_vuart_raw_read(dev, lb->data, bytes, &bytes);
-
- lb->head = lb->data;
- lb->tail = lb->data + bytes;
- lb->dbg_number = ++dbg_number;
-
- spin_lock_irqsave(&dev->priv->rx_list.lock, flags);
- list_add_tail(&lb->link, &dev->priv->rx_list.head);
- dev->priv->rx_list.bytes_held += bytes;
- spin_unlock_irqrestore(&dev->priv->rx_list.lock, flags);
-
- dev_dbg(&dev->core, "%s:%d: buf_%lu: queued %lxh bytes\n",
- __func__, __LINE__, lb->dbg_number, bytes);
+ if (result) {
+ spin_unlock_irqrestore(&priv->rx_list.lock, flags);
+ return result;
+ }
- spin_lock_irqsave(&dev->priv->work.lock, flags);
- if(dev->priv->work.trigger
- && dev->priv->rx_list.bytes_held >= dev->priv->work.trigger) {
+ if (priv->rx_list.work.trigger && priv->rx_list.bytes_held
+ >= priv->rx_list.work.trigger) {
dev_dbg(&dev->core, "%s:%d: schedule_work %lxh bytes\n",
- __func__, __LINE__, dev->priv->work.trigger);
- dev->priv->work.trigger = 0;
- schedule_work(&dev->priv->work.work);
+ __func__, __LINE__, priv->rx_list.work.trigger);
+ priv->rx_list.work.trigger = 0;
+ schedule_work(&priv->rx_list.work.work);
}
- spin_unlock_irqrestore(&dev->priv->work.lock, flags);
- return 0;
+
+ spin_unlock_irqrestore(&priv->rx_list.lock, flags);
+ return result;
}
static int ps3_vuart_handle_interrupt_disconnect(
- struct ps3_vuart_port_device *dev)
+ struct ps3_system_bus_device *dev)
{
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
BUG_ON("no support");
@@ -733,9 +837,10 @@ static int ps3_vuart_handle_interrupt_disconnect(
* stage handler after one iteration.
*/
-static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
+static int ps3_vuart_handle_port_interrupt(struct ps3_system_bus_device *dev)
{
int result;
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
unsigned long status;
result = ps3_vuart_get_interrupt_status(dev, &status);
@@ -747,21 +852,21 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
status);
if (status & INTERRUPT_MASK_DISCONNECT) {
- dev->priv->stats.disconnect_interrupts++;
+ priv->stats.disconnect_interrupts++;
result = ps3_vuart_handle_interrupt_disconnect(dev);
if (result)
ps3_vuart_disable_interrupt_disconnect(dev);
}
if (status & INTERRUPT_MASK_TX) {
- dev->priv->stats.tx_interrupts++;
+ priv->stats.tx_interrupts++;
result = ps3_vuart_handle_interrupt_tx(dev);
if (result)
ps3_vuart_disable_interrupt_tx(dev);
}
if (status & INTERRUPT_MASK_RX) {
- dev->priv->stats.rx_interrupts++;
+ priv->stats.rx_interrupts++;
result = ps3_vuart_handle_interrupt_rx(dev);
if (result)
ps3_vuart_disable_interrupt_rx(dev);
@@ -771,11 +876,11 @@ static int ps3_vuart_handle_port_interrupt(struct ps3_vuart_port_device *dev)
}
struct vuart_bus_priv {
- const struct ports_bmp bmp;
+ struct ports_bmp *bmp;
unsigned int virq;
struct semaphore probe_mutex;
int use_count;
- struct ps3_vuart_port_device *devices[PORT_COUNT];
+ struct ps3_system_bus_device *devices[PORT_COUNT];
} static vuart_bus_priv;
/**
@@ -788,17 +893,16 @@ struct vuart_bus_priv {
static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
{
- struct vuart_bus_priv *bus_priv;
+ struct vuart_bus_priv *bus_priv = _private;
- BUG_ON(!_private);
- bus_priv = (struct vuart_bus_priv *)_private;
+ BUG_ON(!bus_priv);
while (1) {
unsigned int port;
- dump_ports_bmp(&bus_priv->bmp);
+ dump_ports_bmp(bus_priv->bmp);
- port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp.status);
+ port = (BITS_PER_LONG - 1) - __ilog2(bus_priv->bmp->status);
if (port == BITS_PER_LONG)
break;
@@ -812,100 +916,144 @@ static irqreturn_t ps3_vuart_irq_handler(int irq, void *_private)
return IRQ_HANDLED;
}
-static int ps3_vuart_match(struct device *_dev, struct device_driver *_drv)
+static int ps3_vuart_bus_interrupt_get(void)
{
int result;
- struct ps3_vuart_port_driver *drv = to_ps3_vuart_port_driver(_drv);
- struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
- result = dev->match_id == drv->match_id;
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ vuart_bus_priv.use_count++;
+
+ BUG_ON(vuart_bus_priv.use_count > 2);
+
+ if (vuart_bus_priv.use_count != 1) {
+ return 0;
+ }
+
+ BUG_ON(vuart_bus_priv.bmp);
+
+ vuart_bus_priv.bmp = kzalloc(sizeof(struct ports_bmp), GFP_KERNEL);
+
+ if (!vuart_bus_priv.bmp) {
+ pr_debug("%s:%d: kzalloc failed.\n", __func__, __LINE__);
+ result = -ENOMEM;
+ goto fail_bmp_malloc;
+ }
+
+ result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY, vuart_bus_priv.bmp,
+ &vuart_bus_priv.virq);
+
+ if (result) {
+ pr_debug("%s:%d: ps3_vuart_irq_setup failed (%d)\n",
+ __func__, __LINE__, result);
+ result = -EPERM;
+ goto fail_alloc_irq;
+ }
+
+ result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler,
+ IRQF_DISABLED, "vuart", &vuart_bus_priv);
- dev_info(&dev->core, "%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__,
- __LINE__, dev->match_id, dev->core.bus_id, drv->match_id,
- drv->core.name, (result ? "match" : "miss"));
+ if (result) {
+ pr_debug("%s:%d: request_irq failed (%d)\n",
+ __func__, __LINE__, result);
+ goto fail_request_irq;
+ }
+ pr_debug(" <- %s:%d: ok\n", __func__, __LINE__);
return result;
+
+fail_request_irq:
+ ps3_vuart_irq_destroy(vuart_bus_priv.virq);
+ vuart_bus_priv.virq = NO_IRQ;
+fail_alloc_irq:
+ kfree(vuart_bus_priv.bmp);
+ vuart_bus_priv.bmp = NULL;
+fail_bmp_malloc:
+ vuart_bus_priv.use_count--;
+ pr_debug(" <- %s:%d: failed\n", __func__, __LINE__);
+ return result;
+}
+
+static int ps3_vuart_bus_interrupt_put(void)
+{
+ pr_debug(" -> %s:%d\n", __func__, __LINE__);
+
+ vuart_bus_priv.use_count--;
+
+ BUG_ON(vuart_bus_priv.use_count < 0);
+
+ if (vuart_bus_priv.use_count != 0)
+ return 0;
+
+ free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
+
+ ps3_vuart_irq_destroy(vuart_bus_priv.virq);
+ vuart_bus_priv.virq = NO_IRQ;
+
+ kfree(vuart_bus_priv.bmp);
+ vuart_bus_priv.bmp = NULL;
+
+ pr_debug(" <- %s:%d\n", __func__, __LINE__);
+ return 0;
}
-static int ps3_vuart_probe(struct device *_dev)
+static int ps3_vuart_probe(struct ps3_system_bus_device *dev)
{
int result;
- unsigned int port_number;
- struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
- struct ps3_vuart_port_driver *drv =
- to_ps3_vuart_port_driver(_dev->driver);
+ struct ps3_vuart_port_driver *drv;
+ struct ps3_vuart_port_priv *priv = NULL;
dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+ drv = ps3_system_bus_dev_to_vuart_drv(dev);
+
+ dev_dbg(&dev->core, "%s:%d: (%s)\n", __func__, __LINE__,
+ drv->core.core.name);
+
BUG_ON(!drv);
- down(&vuart_bus_priv.probe_mutex);
+ if (dev->port_number >= PORT_COUNT) {
+ BUG();
+ return -EINVAL;
+ }
- /* Setup vuart_bus_priv.devices[]. */
+ down(&vuart_bus_priv.probe_mutex);
- result = ps3_vuart_match_id_to_port(dev->match_id,
- &port_number);
+ result = ps3_vuart_bus_interrupt_get();
- if (result) {
- dev_dbg(&dev->core, "%s:%d: unknown match_id (%d)\n",
- __func__, __LINE__, dev->match_id);
- result = -EINVAL;
- goto fail_match;
- }
+ if (result)
+ goto fail_setup_interrupt;
- if (vuart_bus_priv.devices[port_number]) {
+ if (vuart_bus_priv.devices[dev->port_number]) {
dev_dbg(&dev->core, "%s:%d: port busy (%d)\n", __func__,
- __LINE__, port_number);
+ __LINE__, dev->port_number);
result = -EBUSY;
- goto fail_match;
+ goto fail_busy;
}
- vuart_bus_priv.devices[port_number] = dev;
+ vuart_bus_priv.devices[dev->port_number] = dev;
- /* Setup dev->priv. */
+ /* Setup dev->driver_priv. */
- dev->priv = kzalloc(sizeof(struct ps3_vuart_port_priv), GFP_KERNEL);
+ dev->driver_priv = kzalloc(sizeof(struct ps3_vuart_port_priv),
+ GFP_KERNEL);
- if (!dev->priv) {
+ if (!dev->driver_priv) {
result = -ENOMEM;
- goto fail_alloc;
+ goto fail_dev_malloc;
}
- dev->priv->port_number = port_number;
-
- INIT_LIST_HEAD(&dev->priv->tx_list.head);
- spin_lock_init(&dev->priv->tx_list.lock);
+ priv = to_port_priv(dev);
- INIT_LIST_HEAD(&dev->priv->rx_list.head);
- spin_lock_init(&dev->priv->rx_list.lock);
+ INIT_LIST_HEAD(&priv->tx_list.head);
+ spin_lock_init(&priv->tx_list.lock);
- INIT_WORK(&dev->priv->work.work, NULL);
- spin_lock_init(&dev->priv->work.lock);
- dev->priv->work.trigger = 0;
- dev->priv->work.dev = dev;
+ INIT_LIST_HEAD(&priv->rx_list.head);
+ spin_lock_init(&priv->rx_list.lock);
- if (++vuart_bus_priv.use_count == 1) {
-
- result = ps3_vuart_irq_setup(PS3_BINDING_CPU_ANY,
- (void*)&vuart_bus_priv.bmp.status, &vuart_bus_priv.virq);
-
- if (result) {
- dev_dbg(&dev->core,
- "%s:%d: ps3_vuart_irq_setup failed (%d)\n",
- __func__, __LINE__, result);
- result = -EPERM;
- goto fail_alloc_irq;
- }
-
- result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler,
- IRQF_DISABLED, "vuart", &vuart_bus_priv);
-
- if (result) {
- dev_info(&dev->core, "%s:%d: request_irq failed (%d)\n",
- __func__, __LINE__, result);
- goto fail_request_irq;
- }
- }
+ INIT_WORK(&priv->rx_list.work.work, NULL);
+ priv->rx_list.work.trigger = 0;
+ priv->rx_list.work.dev = dev;
/* clear stale pending interrupts */
@@ -936,150 +1084,158 @@ static int ps3_vuart_probe(struct device *_dev)
fail_probe:
ps3_vuart_set_interrupt_mask(dev, 0);
-fail_request_irq:
- ps3_vuart_irq_destroy(vuart_bus_priv.virq);
- vuart_bus_priv.virq = NO_IRQ;
-fail_alloc_irq:
- --vuart_bus_priv.use_count;
- kfree(dev->priv);
- dev->priv = NULL;
-fail_alloc:
- vuart_bus_priv.devices[port_number] = NULL;
-fail_match:
+ kfree(dev->driver_priv);
+ dev->driver_priv = NULL;
+fail_dev_malloc:
+ vuart_bus_priv.devices[dev->port_number] = NULL;
+fail_busy:
+ ps3_vuart_bus_interrupt_put();
+fail_setup_interrupt:
up(&vuart_bus_priv.probe_mutex);
- dev_dbg(&dev->core, "%s:%d failed\n", __func__, __LINE__);
+ dev_dbg(&dev->core, "%s:%d: failed\n", __func__, __LINE__);
return result;
}
-static int ps3_vuart_remove(struct device *_dev)
+/**
+ * ps3_vuart_cleanup - common cleanup helper.
+ * @dev: The struct ps3_system_bus_device instance.
+ *
+ * Cleans interrupts and HV resources. Must be called with
+ * vuart_bus_priv.probe_mutex held. Used by ps3_vuart_remove and
+ * ps3_vuart_shutdown. After this call, polled reading will still work.
+ */
+
+static int ps3_vuart_cleanup(struct ps3_system_bus_device *dev)
{
- struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
- struct ps3_vuart_port_driver *drv =
- to_ps3_vuart_port_driver(_dev->driver);
+ dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+
+ ps3_vuart_cancel_async(dev);
+ ps3_vuart_set_interrupt_mask(dev, 0);
+ ps3_vuart_bus_interrupt_put();
+ return 0;
+}
+
+/**
+ * ps3_vuart_remove - Completely clean the device instance.
+ * @dev: The struct ps3_system_bus_device instance.
+ *
+ * Cleans all memory, interrupts and HV resources. After this call the
+ * device can no longer be used.
+ */
+
+static int ps3_vuart_remove(struct ps3_system_bus_device *dev)
+{
+ struct ps3_vuart_port_priv *priv = to_port_priv(dev);
+ struct ps3_vuart_port_driver *drv;
+
+ BUG_ON(!dev);
down(&vuart_bus_priv.probe_mutex);
- dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
- dev->core.bus_id);
+ dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
+ dev->match_id);
- BUG_ON(vuart_bus_priv.use_count < 1);
+ if (!dev->core.driver) {
+ dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
+ __LINE__);
+ up(&vuart_bus_priv.probe_mutex);
+ return 0;
+ }
- if (drv->remove)
- drv->remove(dev);
- else
- dev_dbg(&dev->core, "%s:%d: %s no remove method\n", __func__,
- __LINE__, dev->core.bus_id);
+ drv = ps3_system_bus_dev_to_vuart_drv(dev);
- vuart_bus_priv.devices[dev->priv->port_number] = NULL;
+ BUG_ON(!drv);
- if (--vuart_bus_priv.use_count == 0) {
+ if (drv->remove) {
+ drv->remove(dev);
+ } else {
+ dev_dbg(&dev->core, "%s:%d: no remove method\n", __func__,
+ __LINE__);
BUG();
- free_irq(vuart_bus_priv.virq, &vuart_bus_priv);
- ps3_vuart_irq_destroy(vuart_bus_priv.virq);
- vuart_bus_priv.virq = NO_IRQ;
}
- kfree(dev->priv);
- dev->priv = NULL;
+ ps3_vuart_cleanup(dev);
+
+ vuart_bus_priv.devices[dev->port_number] = NULL;
+ kfree(priv);
+ priv = NULL;
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
up(&vuart_bus_priv.probe_mutex);
return 0;
}
-static void ps3_vuart_shutdown(struct device *_dev)
-{
- struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
- struct ps3_vuart_port_driver *drv =
- to_ps3_vuart_port_driver(_dev->driver);
-
- dev_dbg(&dev->core, "%s:%d: %s\n", __func__, __LINE__,
- dev->core.bus_id);
-
- if (drv->shutdown)
- drv->shutdown(dev);
- else
- dev_dbg(&dev->core, "%s:%d: %s no shutdown method\n", __func__,
- __LINE__, dev->core.bus_id);
-}
-
/**
- * ps3_vuart_bus - The vuart bus instance.
+ * ps3_vuart_shutdown - Cleans interrupts and HV resources.
+ * @dev: The struct ps3_system_bus_device instance.
*
- * The vuart is managed as a bus that port devices connect to.
+ * Cleans interrupts and HV resources. After this call the
+ * device can still be used in polling mode. This behavior required
+ * by sys-manager to be able to complete the device power operation
+ * sequence.
*/
-struct bus_type ps3_vuart_bus = {
- .name = "ps3_vuart",
- .match = ps3_vuart_match,
- .probe = ps3_vuart_probe,
- .remove = ps3_vuart_remove,
- .shutdown = ps3_vuart_shutdown,
-};
-
-int __init ps3_vuart_bus_init(void)
+static int ps3_vuart_shutdown(struct ps3_system_bus_device *dev)
{
- int result;
+ struct ps3_vuart_port_driver *drv;
- pr_debug("%s:%d:\n", __func__, __LINE__);
+ BUG_ON(!dev);
- if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
- return -ENODEV;
+ down(&vuart_bus_priv.probe_mutex);
- init_MUTEX(&vuart_bus_priv.probe_mutex);
- result = bus_register(&ps3_vuart_bus);
- BUG_ON(result);
+ dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__,
+ dev->match_id);
- return result;
-}
+ if (!dev->core.driver) {
+ dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__,
+ __LINE__);
+ up(&vuart_bus_priv.probe_mutex);
+ return 0;
+ }
-void __exit ps3_vuart_bus_exit(void)
-{
- pr_debug("%s:%d:\n", __func__, __LINE__);
- bus_unregister(&ps3_vuart_bus);
-}
+ drv = ps3_system_bus_dev_to_vuart_drv(dev);
-core_initcall(ps3_vuart_bus_init);
-module_exit(ps3_vuart_bus_exit);
+ BUG_ON(!drv);
-/**
- * ps3_vuart_port_release_device - Remove a vuart port device.
- */
+ if (drv->shutdown)
+ drv->shutdown(dev);
+ else if (drv->remove) {
+ dev_dbg(&dev->core, "%s:%d: no shutdown, calling remove\n",
+ __func__, __LINE__);
+ drv->remove(dev);
+ } else {
+ dev_dbg(&dev->core, "%s:%d: no shutdown method\n", __func__,
+ __LINE__);
+ BUG();
+ }
-static void ps3_vuart_port_release_device(struct device *_dev)
-{
-#if defined(DEBUG)
- struct ps3_vuart_port_device *dev = to_ps3_vuart_port_device(_dev);
+ ps3_vuart_cleanup(dev);
- dev_dbg(&dev->core, "%s:%d\n", __func__, __LINE__);
+ dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
- BUG_ON(dev->priv && "forgot to free");
- memset(&dev->core, 0, sizeof(dev->core));
-#endif
+ up(&vuart_bus_priv.probe_mutex);
+ return 0;
}
-/**
- * ps3_vuart_port_device_register - Add a vuart port device.
- */
-
-int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev)
+static int __init ps3_vuart_bus_init(void)
{
- static unsigned int dev_count = 1;
-
- BUG_ON(dev->priv && "forgot to free");
+ pr_debug("%s:%d:\n", __func__, __LINE__);
- dev->core.parent = NULL;
- dev->core.bus = &ps3_vuart_bus;
- dev->core.release = ps3_vuart_port_release_device;
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return -ENODEV;
- snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "vuart_%02x",
- dev_count++);
+ init_MUTEX(&vuart_bus_priv.probe_mutex);
- dev_dbg(&dev->core, "%s:%d register\n", __func__, __LINE__);
+ return 0;
+}
- return device_register(&dev->core);
+static void __exit ps3_vuart_bus_exit(void)
+{
+ pr_debug("%s:%d:\n", __func__, __LINE__);
}
-EXPORT_SYMBOL_GPL(ps3_vuart_port_device_register);
+core_initcall(ps3_vuart_bus_init);
+module_exit(ps3_vuart_bus_exit);
/**
* ps3_vuart_port_driver_register - Add a vuart port device driver.
@@ -1089,12 +1245,18 @@ int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv)
{
int result;
- pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
- drv->core.bus = &ps3_vuart_bus;
- result = driver_register(&drv->core);
+ pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name);
+
+ BUG_ON(!drv->core.match_id);
+ BUG_ON(!drv->core.core.name);
+
+ drv->core.probe = ps3_vuart_probe;
+ drv->core.remove = ps3_vuart_remove;
+ drv->core.shutdown = ps3_vuart_shutdown;
+
+ result = ps3_system_bus_driver_register(&drv->core);
return result;
}
-
EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
/**
@@ -1103,8 +1265,7 @@ EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_register);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv)
{
- pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.name);
- driver_unregister(&drv->core);
+ pr_debug("%s:%d: (%s)\n", __func__, __LINE__, drv->core.core.name);
+ ps3_system_bus_driver_unregister(&drv->core);
}
-
EXPORT_SYMBOL_GPL(ps3_vuart_port_driver_unregister);
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
index 1be992d568c8..eb7f6d94a890 100644
--- a/drivers/ps3/vuart.h
+++ b/drivers/ps3/vuart.h
@@ -34,29 +34,7 @@ struct ps3_vuart_stats {
struct ps3_vuart_work {
struct work_struct work;
unsigned long trigger;
- spinlock_t lock;
- struct ps3_vuart_port_device* dev; /* to convert work to device */
-};
-
-/**
- * struct ps3_vuart_port_priv - private vuart device data.
- */
-
-struct ps3_vuart_port_priv {
- unsigned int port_number;
- u64 interrupt_mask;
-
- struct {
- spinlock_t lock;
- struct list_head head;
- } tx_list;
- struct {
- unsigned long bytes_held;
- spinlock_t lock;
- struct list_head head;
- } rx_list;
- struct ps3_vuart_stats stats;
- struct ps3_vuart_work work;
+ struct ps3_system_bus_device *dev; /* to convert work to device */
};
/**
@@ -64,32 +42,30 @@ struct ps3_vuart_port_priv {
*/
struct ps3_vuart_port_driver {
- enum ps3_match_id match_id;
- struct device_driver core;
- int (*probe)(struct ps3_vuart_port_device *);
- int (*remove)(struct ps3_vuart_port_device *);
- void (*shutdown)(struct ps3_vuart_port_device *);
- int (*tx_event)(struct ps3_vuart_port_device *dev);
- int (*rx_event)(struct ps3_vuart_port_device *dev);
- int (*disconnect_event)(struct ps3_vuart_port_device *dev);
- /* int (*suspend)(struct ps3_vuart_port_device *, pm_message_t); */
- /* int (*resume)(struct ps3_vuart_port_device *); */
+ struct ps3_system_bus_driver core;
+ int (*probe)(struct ps3_system_bus_device *);
+ int (*remove)(struct ps3_system_bus_device *);
+ void (*shutdown)(struct ps3_system_bus_device *);
+ void (*work)(struct ps3_system_bus_device *);
+ /* int (*tx_event)(struct ps3_system_bus_device *dev); */
+ /* int (*rx_event)(struct ps3_system_bus_device *dev); */
+ /* int (*disconnect_event)(struct ps3_system_bus_device *dev); */
+ /* int (*suspend)(struct ps3_system_bus_device *, pm_message_t); */
+ /* int (*resume)(struct ps3_system_bus_device *); */
};
int ps3_vuart_port_driver_register(struct ps3_vuart_port_driver *drv);
void ps3_vuart_port_driver_unregister(struct ps3_vuart_port_driver *drv);
-static inline struct ps3_vuart_port_driver *to_ps3_vuart_port_driver(
- struct device_driver *_drv)
-{
- return container_of(_drv, struct ps3_vuart_port_driver, core);
-}
-static inline struct ps3_vuart_port_device *to_ps3_vuart_port_device(
- struct device *_dev)
+static inline struct ps3_vuart_port_driver *
+ ps3_system_bus_dev_to_vuart_drv(struct ps3_system_bus_device *_dev)
{
- return container_of(_dev, struct ps3_vuart_port_device, core);
+ struct ps3_system_bus_driver *sbd =
+ ps3_system_bus_dev_to_system_bus_drv(_dev);
+ BUG_ON(!sbd);
+ return container_of(sbd, struct ps3_vuart_port_driver, core);
}
-static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device(
+static inline struct ps3_system_bus_device *ps3_vuart_work_to_system_bus_dev(
struct work_struct *_work)
{
struct ps3_vuart_work *vw = container_of(_work, struct ps3_vuart_work,
@@ -97,14 +73,13 @@ static inline struct ps3_vuart_port_device *ps3_vuart_work_to_port_device(
return vw->dev;
}
-int ps3_vuart_write(struct ps3_vuart_port_device *dev, const void* buf,
- unsigned int bytes);
-int ps3_vuart_read(struct ps3_vuart_port_device *dev, void* buf,
+int ps3_vuart_write(struct ps3_system_bus_device *dev, const void *buf,
unsigned int bytes);
-int ps3_vuart_read_async(struct ps3_vuart_port_device *dev, work_func_t func,
+int ps3_vuart_read(struct ps3_system_bus_device *dev, void *buf,
unsigned int bytes);
-void ps3_vuart_cancel_async(struct ps3_vuart_port_device *dev);
-void ps3_vuart_clear_rx_bytes(struct ps3_vuart_port_device *dev,
+int ps3_vuart_read_async(struct ps3_system_bus_device *dev, unsigned int bytes);
+void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev);
+void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev,
unsigned int bytes);
#endif
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index f935c1f71a58..44420723a359 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -297,11 +297,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
struct rio_switch *rswitch;
int result, rdid;
- rdev = kmalloc(sizeof(struct rio_dev), GFP_KERNEL);
+ rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL);
if (!rdev)
goto out;
- memset(rdev, 0, sizeof(struct rio_dev));
rdev->net = net;
rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,
&result);
@@ -801,9 +800,8 @@ static struct rio_net __devinit *rio_alloc_net(struct rio_mport *port)
{
struct rio_net *net;
- net = kmalloc(sizeof(struct rio_net), GFP_KERNEL);
+ net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
if (net) {
- memset(net, 0, sizeof(struct rio_net));
INIT_LIST_HEAD(&net->node);
INIT_LIST_HEAD(&net->devices);
INIT_LIST_HEAD(&net->mports);
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index eed91434417d..659e31164cf0 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -67,7 +67,8 @@ struct device_attribute rio_dev_attrs[] = {
};
static ssize_t
-rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+rio_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct rio_dev *dev =
to_rio_dev(container_of(kobj, struct device, kobj));
@@ -137,7 +138,8 @@ rio_read_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
}
static ssize_t
-rio_write_config(struct kobject *kobj, char *buf, loff_t off, size_t count)
+rio_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct rio_dev *dev =
to_rio_dev(container_of(kobj, struct device, kobj));
@@ -197,7 +199,6 @@ static struct bin_attribute rio_config_attr = {
.attr = {
.name = "config",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 0x200000,
.read = rio_read_config,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4e4c10a7fd3a..9d8d40d5c8f7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -10,7 +10,6 @@ config RTC_LIB
config RTC_CLASS
tristate "RTC class"
- depends on EXPERIMENTAL
default n
select RTC_LIB
help
@@ -39,6 +38,9 @@ config RTC_HCTOSYS_DEVICE
clock, usually rtc0. Initialization is done when the system
starts up, and when it resumes from a low power state.
+ The driver for this RTC device must be loaded before late_initcall
+ functions run, so it must usually be statically linked.
+
This clock should be battery-backed, so that it reads the correct
time when the system boots from a power-off state. Otherwise, your
system will need an external clock source (like an NTP server).
@@ -119,7 +121,7 @@ config RTC_DRV_TEST
will be called rtc-test.
comment "I2C RTC drivers"
- depends on RTC_CLASS
+ depends on RTC_CLASS && I2C
config RTC_DRV_DS1307
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
@@ -160,11 +162,11 @@ config RTC_DRV_MAX6900
will be called rtc-max6900.
config RTC_DRV_RS5C372
- tristate "Ricoh RS5C372A/B"
+ tristate "Ricoh RS5C372A/B, RV5C386, RV5C387A"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for the
- Ricoh RS5C372A and RS5C372B RTC chips.
+ Ricoh RS5C372A, RS5C372B, RV5C386, and RV5C387A RTC chips.
This driver can also be built as a module. If so, the module
will be called rtc-rs5c372.
@@ -213,12 +215,40 @@ config RTC_DRV_PCF8583
This driver can also be built as a module. If so, the module
will be called rtc-pcf8583.
+config RTC_DRV_M41T80
+ tristate "ST M41T80 series RTC"
+ depends on RTC_CLASS && I2C
+ help
+ If you say Y here you will get support for the
+ ST M41T80 RTC chips series. Currently following chips are
+ supported: M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85
+ and M41ST87.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-m41t80.
+
+config RTC_DRV_M41T80_WDT
+ bool "ST M41T80 series RTC watchdog timer"
+ depends on RTC_DRV_M41T80
+ help
+ If you say Y here you will get support for the
+ watchdog timer in ST M41T80 RTC chips series.
+
+config RTC_DRV_TWL92330
+ boolean "TI TWL92330/Menelaus"
+ depends on RTC_CLASS && I2C && MENELAUS
+ help
+ If you say yes here you get support for the RTC on the
+ TWL92330 "Menelaus" power mangement chip, used with OMAP2
+ platforms. The support is integrated with the rest of
+ the Menelaus driver; it's not separate module.
+
comment "SPI RTC drivers"
- depends on RTC_CLASS
+ depends on RTC_CLASS && SPI_MASTER
config RTC_DRV_RS5C348
tristate "Ricoh RS5C348A/B"
- depends on RTC_CLASS && SPI
+ depends on RTC_CLASS && SPI_MASTER
help
If you say yes here you get support for the
Ricoh RS5C348A and RS5C348B RTC chips.
@@ -228,7 +258,7 @@ config RTC_DRV_RS5C348
config RTC_DRV_MAX6902
tristate "Maxim 6902"
- depends on RTC_CLASS && SPI
+ depends on RTC_CLASS && SPI_MASTER
help
If you say yes here you will get support for the
Maxim MAX6902 SPI RTC chip.
@@ -246,7 +276,7 @@ comment "Platform RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
- || M32R || ATARI || POWERPC || MIPS)
+ || M32R || ATARI || PPC || MIPS)
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.
@@ -262,6 +292,12 @@ config RTC_DRV_CMOS
This driver can also be built as a module. If so, the module
will be called rtc-cmos.
+config RTC_DRV_DS1216
+ tristate "Dallas DS1216"
+ depends on RTC_CLASS && SNI_RM
+ help
+ If you say yes here you get support for the Dallas DS1216 RTC chips.
+
config RTC_DRV_DS1553
tristate "Dallas DS1553"
depends on RTC_CLASS
@@ -272,6 +308,16 @@ config RTC_DRV_DS1553
This driver can also be built as a module. If so, the module
will be called rtc-ds1553.
+config RTC_DRV_STK17TA8
+ tristate "Simtek STK17TA8"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Simtek STK17TA8 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-stk17ta8.
+
config RTC_DRV_DS1742
tristate "Dallas DS1742/1743"
depends on RTC_CLASS
@@ -292,6 +338,16 @@ config RTC_DRV_M48T86
This driver can also be built as a module. If so, the module
will be called rtc-m48t86.
+config RTC_DRV_M48T59
+ tristate "ST M48T59"
+ depends on RTC_CLASS
+ help
+ If you say Y here you will get support for the
+ ST M48T59 RTC chip.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-m48t59".
+
config RTC_DRV_V3020
tristate "EM Microelectronic V3020"
depends on RTC_CLASS
@@ -351,7 +407,7 @@ config RTC_DRV_SA1100
config RTC_DRV_SH
tristate "SuperH On-Chip RTC"
- depends on RTC_CLASS && SUPERH
+ depends on RTC_CLASS && SUPERH && (CPU_SH3 || CPU_SH4)
help
Say Y here to enable support for the on-chip RTC found in
most SuperH processors.
@@ -379,6 +435,13 @@ config RTC_DRV_PL031
To compile this driver as a module, choose M here: the
module will be called rtc-pl031.
+config RTC_DRV_AT32AP700X
+ tristate "AT32AP700X series RTC"
+ depends on RTC_CLASS && PLATFORM_AT32AP
+ help
+ Driver for the internal RTC (Realtime Clock) on Atmel AVR32
+ AT32AP700x family processors.
+
config RTC_DRV_AT91RM9200
tristate "AT91RM9200"
depends on RTC_CLASS && ARCH_AT91RM9200
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index a1afbc236073..7ede9e725360 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_AT32AP700X) += rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
@@ -28,8 +29,10 @@ obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
+obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
+obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
@@ -41,3 +44,5 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
+obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
+obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
new file mode 100644
index 000000000000..2999214ca534
--- /dev/null
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -0,0 +1,317 @@
+/*
+ * An RTC driver for the AVR32 AT32AP700x processor series.
+ *
+ * Copyright (C) 2007 Atmel 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/io.h>
+
+/*
+ * This is a bare-bones RTC. It runs during most system sleep states, but has
+ * no battery backup and gets reset during system restart. It must be
+ * initialized from an external clock (network, I2C, etc) before it can be of
+ * much use.
+ *
+ * The alarm functionality is limited by the hardware, not supporting
+ * periodic interrupts.
+ */
+
+#define RTC_CTRL 0x00
+#define RTC_CTRL_EN 0
+#define RTC_CTRL_PCLR 1
+#define RTC_CTRL_TOPEN 2
+#define RTC_CTRL_PSEL 8
+
+#define RTC_VAL 0x04
+
+#define RTC_TOP 0x08
+
+#define RTC_IER 0x10
+#define RTC_IER_TOPI 0
+
+#define RTC_IDR 0x14
+#define RTC_IDR_TOPI 0
+
+#define RTC_IMR 0x18
+#define RTC_IMR_TOPI 0
+
+#define RTC_ISR 0x1c
+#define RTC_ISR_TOPI 0
+
+#define RTC_ICR 0x20
+#define RTC_ICR_TOPI 0
+
+#define RTC_BIT(name) (1 << RTC_##name)
+#define RTC_BF(name, value) ((value) << RTC_##name)
+
+#define rtc_readl(dev, reg) \
+ __raw_readl((dev)->regs + RTC_##reg)
+#define rtc_writel(dev, reg, value) \
+ __raw_writel((value), (dev)->regs + RTC_##reg)
+
+struct rtc_at32ap700x {
+ struct rtc_device *rtc;
+ void __iomem *regs;
+ unsigned long alarm_time;
+ unsigned long irq;
+ /* Protect against concurrent register access. */
+ spinlock_t lock;
+};
+
+static int at32_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+ struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+ unsigned long now;
+
+ now = rtc_readl(rtc, VAL);
+ rtc_time_to_tm(now, tm);
+
+ return 0;
+}
+
+static int at32_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+ unsigned long now;
+ int ret;
+
+ ret = rtc_tm_to_time(tm, &now);
+ if (ret == 0)
+ rtc_writel(rtc, VAL, now);
+
+ return ret;
+}
+
+static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+
+ rtc_time_to_tm(rtc->alarm_time, &alrm->time);
+ alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
+
+ return 0;
+}
+
+static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+ unsigned long rtc_unix_time;
+ unsigned long alarm_unix_time;
+ int ret;
+
+ rtc_unix_time = rtc_readl(rtc, VAL);
+
+ ret = rtc_tm_to_time(&alrm->time, &alarm_unix_time);
+ if (ret)
+ return ret;
+
+ if (alarm_unix_time < rtc_unix_time)
+ return -EINVAL;
+
+ spin_lock_irq(&rtc->lock);
+ rtc->alarm_time = alarm_unix_time;
+ rtc_writel(rtc, TOP, rtc->alarm_time);
+ if (alrm->pending)
+ rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+ | RTC_BIT(CTRL_TOPEN));
+ else
+ rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+ & ~RTC_BIT(CTRL_TOPEN));
+ spin_unlock_irq(&rtc->lock);
+
+ return ret;
+}
+
+static int at32_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
+ int ret = 0;
+
+ spin_lock_irq(&rtc->lock);
+
+ switch (cmd) {
+ case RTC_AIE_ON:
+ if (rtc_readl(rtc, VAL) > rtc->alarm_time) {
+ ret = -EINVAL;
+ break;
+ }
+ rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+ | RTC_BIT(CTRL_TOPEN));
+ rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
+ rtc_writel(rtc, IER, RTC_BIT(IER_TOPI));
+ break;
+ case RTC_AIE_OFF:
+ rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+ & ~RTC_BIT(CTRL_TOPEN));
+ rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
+ rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ spin_unlock_irq(&rtc->lock);
+
+ return ret;
+}
+
+static irqreturn_t at32_rtc_interrupt(int irq, void *dev_id)
+{
+ struct rtc_at32ap700x *rtc = (struct rtc_at32ap700x *)dev_id;
+ unsigned long isr = rtc_readl(rtc, ISR);
+ unsigned long events = 0;
+ int ret = IRQ_NONE;
+
+ spin_lock(&rtc->lock);
+
+ if (isr & RTC_BIT(ISR_TOPI)) {
+ rtc_writel(rtc, ICR, RTC_BIT(ICR_TOPI));
+ rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
+ rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
+ & ~RTC_BIT(CTRL_TOPEN));
+ rtc_writel(rtc, VAL, rtc->alarm_time);
+ events = RTC_AF | RTC_IRQF;
+ rtc_update_irq(rtc->rtc, 1, events);
+ ret = IRQ_HANDLED;
+ }
+
+ spin_unlock(&rtc->lock);
+
+ return ret;
+}
+
+static struct rtc_class_ops at32_rtc_ops = {
+ .ioctl = at32_rtc_ioctl,
+ .read_time = at32_rtc_readtime,
+ .set_time = at32_rtc_settime,
+ .read_alarm = at32_rtc_readalarm,
+ .set_alarm = at32_rtc_setalarm,
+};
+
+static int __init at32_rtc_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ struct rtc_at32ap700x *rtc;
+ int irq = -1;
+ int ret;
+
+ rtc = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL);
+ if (!rtc) {
+ dev_dbg(&pdev->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_dbg(&pdev->dev, "no mmio resource defined\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_dbg(&pdev->dev, "could not get irq\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc);
+ if (ret) {
+ dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
+ goto out;
+ }
+
+ rtc->irq = irq;
+ rtc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!rtc->regs) {
+ ret = -ENOMEM;
+ dev_dbg(&pdev->dev, "could not map I/O memory\n");
+ goto out_free_irq;
+ }
+ spin_lock_init(&rtc->lock);
+
+ /*
+ * Maybe init RTC: count from zero at 1 Hz, disable wrap irq.
+ *
+ * Do not reset VAL register, as it can hold an old time
+ * from last JTAG reset.
+ */
+ if (!(rtc_readl(rtc, CTRL) & RTC_BIT(CTRL_EN))) {
+ rtc_writel(rtc, CTRL, RTC_BIT(CTRL_PCLR));
+ rtc_writel(rtc, IDR, RTC_BIT(IDR_TOPI));
+ rtc_writel(rtc, CTRL, RTC_BF(CTRL_PSEL, 0xe)
+ | RTC_BIT(CTRL_EN));
+ }
+
+ rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &at32_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ dev_dbg(&pdev->dev, "could not register rtc device\n");
+ ret = PTR_ERR(rtc->rtc);
+ goto out_iounmap;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n",
+ (unsigned long)rtc->regs, rtc->irq);
+
+ return 0;
+
+out_iounmap:
+ iounmap(rtc->regs);
+out_free_irq:
+ free_irq(irq, rtc);
+out:
+ kfree(rtc);
+ return ret;
+}
+
+static int __exit at32_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
+
+ free_irq(rtc->irq, rtc);
+ iounmap(rtc->regs);
+ rtc_device_unregister(rtc->rtc);
+ kfree(rtc);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+MODULE_ALIAS("at32ap700x_rtc");
+
+static struct platform_driver at32_rtc_driver = {
+ .remove = __exit_p(at32_rtc_remove),
+ .driver = {
+ .name = "at32ap700x_rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at32_rtc_init(void)
+{
+ return platform_driver_probe(&at32_rtc_driver, at32_rtc_probe);
+}
+module_init(at32_rtc_init);
+
+static void __exit at32_rtc_exit(void)
+{
+ platform_driver_unregister(&at32_rtc_driver);
+}
+module_exit(at32_rtc_exit);
+
+MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
+MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index e24ea82dc35b..5d760bb6c2cd 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -235,7 +235,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
return 0;
}
-static int cmos_set_freq(struct device *dev, int freq)
+static int cmos_irq_set_freq(struct device *dev, int freq)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
int f;
@@ -259,6 +259,34 @@ static int cmos_set_freq(struct device *dev, int freq)
return 0;
}
+static int cmos_irq_set_state(struct device *dev, int enabled)
+{
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+ unsigned char rtc_control, rtc_intr;
+ unsigned long flags;
+
+ if (!is_valid_irq(cmos->irq))
+ return -ENXIO;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+
+ if (enabled)
+ rtc_control |= RTC_PIE;
+ else
+ rtc_control &= ~RTC_PIE;
+
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+
+ rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+ rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ if (is_intr(rtc_intr))
+ rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return 0;
+}
+
#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
static int
@@ -360,7 +388,8 @@ static const struct rtc_class_ops cmos_rtc_ops = {
.read_alarm = cmos_read_alarm,
.set_alarm = cmos_set_alarm,
.proc = cmos_procfs,
- .irq_set_freq = cmos_set_freq,
+ .irq_set_freq = cmos_irq_set_freq,
+ .irq_set_state = cmos_irq_set_state,
};
/*----------------------------------------------------------------*/
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index f4e5f0040ff7..304535942de2 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -341,6 +341,8 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
case RTC_IRQP_READ:
if (ops->irq_set_freq)
err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
+ else
+ err = -ENOTTY;
break;
case RTC_IRQP_SET:
diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c
new file mode 100644
index 000000000000..83efb88f8f23
--- /dev/null
+++ b/drivers/rtc/rtc-ds1216.c
@@ -0,0 +1,226 @@
+/*
+ * Dallas DS1216 RTC driver
+ *
+ * Copyright (c) 2007 Thomas Bogendoerfer
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/bcd.h>
+
+#define DRV_VERSION "0.1"
+
+struct ds1216_regs {
+ u8 tsec;
+ u8 sec;
+ u8 min;
+ u8 hour;
+ u8 wday;
+ u8 mday;
+ u8 month;
+ u8 year;
+};
+
+#define DS1216_HOUR_1224 (1 << 7)
+#define DS1216_HOUR_AMPM (1 << 5)
+
+struct ds1216_priv {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr;
+ size_t size;
+ unsigned long baseaddr;
+};
+
+static const u8 magic[] = {
+ 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c
+};
+
+/*
+ * Read the 64 bit we'd like to have - It a series
+ * of 64 bits showing up in the LSB of the base register.
+ *
+ */
+static void ds1216_read(u8 __iomem *ioaddr, u8 *buf)
+{
+ unsigned char c;
+ int i, j;
+
+ for (i = 0; i < 8; i++) {
+ c = 0;
+ for (j = 0; j < 8; j++)
+ c |= (readb(ioaddr) & 0x1) << j;
+ buf[i] = c;
+ }
+}
+
+static void ds1216_write(u8 __iomem *ioaddr, const u8 *buf)
+{
+ unsigned char c;
+ int i, j;
+
+ for (i = 0; i < 8; i++) {
+ c = buf[i];
+ for (j = 0; j < 8; j++) {
+ writeb(c, ioaddr);
+ c = c >> 1;
+ }
+ }
+}
+
+static void ds1216_switch_ds_to_clock(u8 __iomem *ioaddr)
+{
+ /* Reset magic pointer */
+ readb(ioaddr);
+ /* Write 64 bit magic to DS1216 */
+ ds1216_write(ioaddr, magic);
+}
+
+static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1216_priv *priv = platform_get_drvdata(pdev);
+ struct ds1216_regs regs;
+
+ ds1216_switch_ds_to_clock(priv->ioaddr);
+ ds1216_read(priv->ioaddr, (u8 *)&regs);
+
+ tm->tm_sec = BCD2BIN(regs.sec);
+ tm->tm_min = BCD2BIN(regs.min);
+ if (regs.hour & DS1216_HOUR_1224) {
+ /* AM/PM mode */
+ tm->tm_hour = BCD2BIN(regs.hour & 0x1f);
+ if (regs.hour & DS1216_HOUR_AMPM)
+ tm->tm_hour += 12;
+ } else
+ tm->tm_hour = BCD2BIN(regs.hour & 0x3f);
+ tm->tm_wday = (regs.wday & 7) - 1;
+ tm->tm_mday = BCD2BIN(regs.mday & 0x3f);
+ tm->tm_mon = BCD2BIN(regs.month & 0x1f);
+ tm->tm_year = BCD2BIN(regs.year);
+ if (tm->tm_year < 70)
+ tm->tm_year += 100;
+ return 0;
+}
+
+static int ds1216_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1216_priv *priv = platform_get_drvdata(pdev);
+ struct ds1216_regs regs;
+
+ ds1216_switch_ds_to_clock(priv->ioaddr);
+ ds1216_read(priv->ioaddr, (u8 *)&regs);
+
+ regs.tsec = 0; /* clear 0.1 and 0.01 seconds */
+ regs.sec = BIN2BCD(tm->tm_sec);
+ regs.min = BIN2BCD(tm->tm_min);
+ regs.hour &= DS1216_HOUR_1224;
+ if (regs.hour && tm->tm_hour > 12) {
+ regs.hour |= DS1216_HOUR_AMPM;
+ tm->tm_hour -= 12;
+ }
+ regs.hour |= BIN2BCD(tm->tm_hour);
+ regs.wday &= ~7;
+ regs.wday |= tm->tm_wday;
+ regs.mday = BIN2BCD(tm->tm_mday);
+ regs.month = BIN2BCD(tm->tm_mon);
+ regs.year = BIN2BCD(tm->tm_year % 100);
+
+ ds1216_switch_ds_to_clock(priv->ioaddr);
+ ds1216_write(priv->ioaddr, (u8 *)&regs);
+ return 0;
+}
+
+static const struct rtc_class_ops ds1216_rtc_ops = {
+ .read_time = ds1216_rtc_read_time,
+ .set_time = ds1216_rtc_set_time,
+};
+
+static int __devinit ds1216_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ struct ds1216_priv *priv;
+ int ret = 0;
+ u8 dummy[8];
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ priv = kzalloc(sizeof *priv, GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->size = res->end - res->start + 1;
+ if (!request_mem_region(res->start, priv->size, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ priv->baseaddr = res->start;
+ priv->ioaddr = ioremap(priv->baseaddr, priv->size);
+ if (!priv->ioaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ rtc = rtc_device_register("ds1216", &pdev->dev,
+ &ds1216_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ priv->rtc = rtc;
+ platform_set_drvdata(pdev, priv);
+
+ /* dummy read to get clock into a known state */
+ ds1216_read(priv->ioaddr, dummy);
+ return 0;
+
+out:
+ if (priv->rtc)
+ rtc_device_unregister(priv->rtc);
+ if (priv->ioaddr)
+ iounmap(priv->ioaddr);
+ if (priv->baseaddr)
+ release_mem_region(priv->baseaddr, priv->size);
+ kfree(priv);
+ return ret;
+}
+
+static int __devexit ds1216_rtc_remove(struct platform_device *pdev)
+{
+ struct ds1216_priv *priv = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(priv->rtc);
+ iounmap(priv->ioaddr);
+ release_mem_region(priv->baseaddr, priv->size);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver ds1216_rtc_platform_driver = {
+ .driver = {
+ .name = "rtc-ds1216",
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1216_rtc_probe,
+ .remove = __devexit_p(ds1216_rtc_remove),
+};
+
+static int __init ds1216_rtc_init(void)
+{
+ return platform_driver_register(&ds1216_rtc_platform_driver);
+}
+
+static void __exit ds1216_rtc_exit(void)
+{
+ platform_driver_unregister(&ds1216_rtc_platform_driver);
+}
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_DESCRIPTION("DS1216 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ds1216_rtc_init);
+module_exit(ds1216_rtc_exit);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 3f0f7b8fa813..5158a625671f 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -24,29 +24,29 @@
* setting the date and time), Linux can ignore the non-clock features.
* That's a natural job for a factory or repair bench.
*
- * If the I2C "force" mechanism is used, we assume the chip is a ds1337.
- * (Much better would be board-specific tables of I2C devices, along with
- * the platform_data drivers would use to sort such issues out.)
+ * This is currently a simple no-alarms driver. If your board has the
+ * alarm irq wired up on a ds1337 or ds1339, and you want to use that,
+ * then look at the rtc-rs5c372 driver for code to steal...
*/
enum ds_type {
- unknown = 0,
- ds_1307, /* or ds1338, ... */
- ds_1337, /* or ds1339, ... */
- ds_1340, /* or st m41t00, ... */
+ ds_1307,
+ ds_1337,
+ ds_1338,
+ ds_1339,
+ ds_1340,
+ m41t00,
// rs5c372 too? different address...
};
-static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
-
/* RTC registers don't differ much, except for the century flag */
#define DS1307_REG_SECS 0x00 /* 00-59 */
# define DS1307_BIT_CH 0x80
+# define DS1340_BIT_nEOSC 0x80
#define DS1307_REG_MIN 0x01 /* 00-59 */
#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
+# define DS1307_BIT_12HR 0x40 /* in REG_HOUR */
+# define DS1307_BIT_PM 0x20 /* in REG_HOUR */
# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
#define DS1307_REG_WDAY 0x03 /* 01-07 */
@@ -56,11 +56,12 @@ I2C_CLIENT_INSMOD;
#define DS1307_REG_YEAR 0x06 /* 00-99 */
/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
- * start at 7, and they differ a lot. Only control and status matter for RTC;
- * be careful using them.
+ * start at 7, and they differ a LOT. Only control and status matter for
+ * basic RTC date and time functionality; be careful using them.
*/
-#define DS1307_REG_CONTROL 0x07
+#define DS1307_REG_CONTROL 0x07 /* or ds1338 */
# define DS1307_BIT_OUT 0x80
+# define DS1338_BIT_OSF 0x20
# define DS1307_BIT_SQWE 0x10
# define DS1307_BIT_RS1 0x02
# define DS1307_BIT_RS0 0x01
@@ -71,6 +72,13 @@ I2C_CLIENT_INSMOD;
# define DS1337_BIT_INTCN 0x04
# define DS1337_BIT_A2IE 0x02
# define DS1337_BIT_A1IE 0x01
+#define DS1340_REG_CONTROL 0x07
+# define DS1340_BIT_OUT 0x80
+# define DS1340_BIT_FT 0x40
+# define DS1340_BIT_CALIB_SIGN 0x20
+# define DS1340_M_CALIBRATION 0x1f
+#define DS1340_REG_FLAG 0x09
+# define DS1340_BIT_OSF 0x80
#define DS1337_REG_STATUS 0x0f
# define DS1337_BIT_OSF 0x80
# define DS1337_BIT_A2I 0x02
@@ -84,21 +92,63 @@ struct ds1307 {
u8 regs[8];
enum ds_type type;
struct i2c_msg msg[2];
- struct i2c_client client;
+ struct i2c_client *client;
+ struct i2c_client dev;
struct rtc_device *rtc;
};
+struct chip_desc {
+ char name[9];
+ unsigned nvram56:1;
+ unsigned alarm:1;
+ enum ds_type type;
+};
+
+static const struct chip_desc chips[] = { {
+ .name = "ds1307",
+ .type = ds_1307,
+ .nvram56 = 1,
+}, {
+ .name = "ds1337",
+ .type = ds_1337,
+ .alarm = 1,
+}, {
+ .name = "ds1338",
+ .type = ds_1338,
+ .nvram56 = 1,
+}, {
+ .name = "ds1339",
+ .type = ds_1339,
+ .alarm = 1,
+}, {
+ .name = "ds1340",
+ .type = ds_1340,
+}, {
+ .name = "m41t00",
+ .type = m41t00,
+}, };
+
+static inline const struct chip_desc *find_chip(const char *s)
+{
+ unsigned i;
+
+ for (i = 0; i < ARRAY_SIZE(chips); i++)
+ if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0)
+ return &chips[i];
+ return NULL;
+}
static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
int tmp;
- /* read the RTC registers all at once */
+ /* read the RTC date and time registers all at once */
ds1307->msg[1].flags = I2C_M_RD;
ds1307->msg[1].len = 7;
- tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2);
+ tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent),
+ ds1307->msg, 2);
if (tmp != 2) {
dev_err(dev, "%s error %d\n", "read", tmp);
return -EIO;
@@ -129,7 +179,8 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
t->tm_hour, t->tm_mday,
t->tm_mon, t->tm_year, t->tm_wday);
- return 0;
+ /* initial clock setting can be undefined */
+ return rtc_valid_tm(t);
}
static int ds1307_set_time(struct device *dev, struct rtc_time *t)
@@ -157,11 +208,18 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
tmp = t->tm_year - 100;
buf[DS1307_REG_YEAR] = BIN2BCD(tmp);
- if (ds1307->type == ds_1337)
+ switch (ds1307->type) {
+ case ds_1337:
+ case ds_1339:
buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
- else if (ds1307->type == ds_1340)
+ break;
+ case ds_1340:
buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
| DS1340_BIT_CENTURY;
+ break;
+ default:
+ break;
+ }
ds1307->msg[1].flags = 0;
ds1307->msg[1].len = 8;
@@ -170,7 +228,8 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
"write", buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6]);
- result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1);
+ result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent),
+ &ds1307->msg[1], 1);
if (result != 1) {
dev_err(dev, "%s error %d\n", "write", tmp);
return -EIO;
@@ -185,25 +244,29 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
static struct i2c_driver ds1307_driver;
-static int __devinit
-ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
+static int __devinit ds1307_probe(struct i2c_client *client)
{
struct ds1307 *ds1307;
int err = -ENODEV;
- struct i2c_client *client;
int tmp;
-
- if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
+ const struct chip_desc *chip;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+
+ chip = find_chip(client->name);
+ if (!chip) {
+ dev_err(&client->dev, "unknown chip type '%s'\n",
+ client->name);
+ return -ENODEV;
}
- client = &ds1307->client;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &ds1307_driver;
- client->flags = 0;
+ if (!i2c_check_functionality(adapter,
+ I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return -EIO;
+
+ if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
+ return -ENOMEM;
+ ds1307->client = client;
i2c_set_clientdata(client, ds1307);
ds1307->msg[0].addr = client->addr;
@@ -216,14 +279,16 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
ds1307->msg[1].len = sizeof(ds1307->regs);
ds1307->msg[1].buf = ds1307->regs;
- /* HACK: "force" implies "needs ds1337-style-oscillator setup" */
- if (kind >= 0) {
- ds1307->type = ds_1337;
+ ds1307->type = chip->type;
+ switch (ds1307->type) {
+ case ds_1337:
+ case ds_1339:
ds1307->reg_addr = DS1337_REG_CONTROL;
ds1307->msg[1].len = 2;
- tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+ /* get registers that the "rtc" read below won't read... */
+ tmp = i2c_transfer(adapter, ds1307->msg, 2);
if (tmp != 2) {
pr_debug("read error %d\n", tmp);
err = -EIO;
@@ -233,19 +298,26 @@ ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
ds1307->reg_addr = 0;
ds1307->msg[1].len = sizeof(ds1307->regs);
- /* oscillator is off; need to turn it on */
- if ((ds1307->regs[0] & DS1337_BIT_nEOSC)
- || (ds1307->regs[1] & DS1337_BIT_OSF)) {
- printk(KERN_ERR "no ds1337 oscillator code\n");
- goto exit_free;
+ /* oscillator off? turn it on, so clock can tick. */
+ if (ds1307->regs[0] & DS1337_BIT_nEOSC)
+ i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
+ ds1307->regs[0] & ~DS1337_BIT_nEOSC);
+
+ /* oscillator fault? clear flag, and warn */
+ if (ds1307->regs[1] & DS1337_BIT_OSF) {
+ i2c_smbus_write_byte_data(client, DS1337_REG_STATUS,
+ ds1307->regs[1] & ~DS1337_BIT_OSF);
+ dev_warn(&client->dev, "SET TIME!\n");
}
- } else
- ds1307->type = ds_1307;
+ break;
+ default:
+ break;
+ }
read_rtc:
/* read RTC registers */
- tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+ tmp = i2c_transfer(adapter, ds1307->msg, 2);
if (tmp != 2) {
pr_debug("read error %d\n", tmp);
err = -EIO;
@@ -257,72 +329,80 @@ read_rtc:
* still a few values that are clearly out-of-range.
*/
tmp = ds1307->regs[DS1307_REG_SECS];
- if (tmp & DS1307_BIT_CH) {
- if (ds1307->type && ds1307->type != ds_1307) {
- pr_debug("not a ds1307?\n");
- goto exit_free;
- }
- ds1307->type = ds_1307;
-
- /* this partial initialization should work for ds1307,
- * ds1338, ds1340, st m41t00, and more.
+ switch (ds1307->type) {
+ case ds_1340:
+ /* FIXME read register with DS1340_BIT_OSF, use that to
+ * trigger the "set time" warning (*after* restarting the
+ * oscillator!) instead of this weaker ds1307/m41t00 test.
*/
- dev_warn(&client->dev, "oscillator started; SET TIME!\n");
- i2c_smbus_write_byte_data(client, 0, 0);
- goto read_rtc;
+ case ds_1307:
+ case m41t00:
+ /* clock halted? turn it on, so clock can tick. */
+ if (tmp & DS1307_BIT_CH) {
+ i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+ dev_warn(&client->dev, "SET TIME!\n");
+ goto read_rtc;
+ }
+ break;
+ case ds_1338:
+ /* clock halted? turn it on, so clock can tick. */
+ if (tmp & DS1307_BIT_CH)
+ i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+
+ /* oscillator fault? clear flag, and warn */
+ if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
+ i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL,
+ ds1307->regs[DS1337_REG_CONTROL]
+ & ~DS1338_BIT_OSF);
+ dev_warn(&client->dev, "SET TIME!\n");
+ goto read_rtc;
+ }
+ break;
+ case ds_1337:
+ case ds_1339:
+ break;
}
+
+ tmp = ds1307->regs[DS1307_REG_SECS];
tmp = BCD2BIN(tmp & 0x7f);
if (tmp > 60)
- goto exit_free;
+ goto exit_bad;
tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
if (tmp > 60)
- goto exit_free;
+ goto exit_bad;
tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
if (tmp == 0 || tmp > 31)
- goto exit_free;
+ goto exit_bad;
tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
if (tmp == 0 || tmp > 12)
- goto exit_free;
+ goto exit_bad;
- /* force into in 24 hour mode (most chips) or
- * disable century bit (ds1340)
- */
tmp = ds1307->regs[DS1307_REG_HOUR];
- if (tmp & (1 << 6)) {
- if (tmp & (1 << 5))
- tmp = BCD2BIN(tmp & 0x1f) + 12;
- else
- tmp = BCD2BIN(tmp);
- i2c_smbus_write_byte_data(client,
- DS1307_REG_HOUR,
- BIN2BCD(tmp));
- }
-
- /* FIXME chips like 1337 can generate alarm irqs too; those are
- * worth exposing through the API (especially when the irq is
- * wakeup-capable).
- */
-
switch (ds1307->type) {
- case unknown:
- strlcpy(client->name, "unknown", I2C_NAME_SIZE);
- break;
- case ds_1307:
- strlcpy(client->name, "ds1307", I2C_NAME_SIZE);
- break;
- case ds_1337:
- strlcpy(client->name, "ds1337", I2C_NAME_SIZE);
- break;
case ds_1340:
- strlcpy(client->name, "ds1340", I2C_NAME_SIZE);
+ case m41t00:
+ /* NOTE: ignores century bits; fix before deploying
+ * systems that will run through year 2100.
+ */
break;
- }
+ default:
+ if (!(tmp & DS1307_BIT_12HR))
+ break;
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client)))
- goto exit_free;
+ /* Be sure we're in 24 hour mode. Multi-master systems
+ * take note...
+ */
+ tmp = BCD2BIN(tmp & 0x1f);
+ if (tmp == 12)
+ tmp = 0;
+ if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
+ tmp += 12;
+ i2c_smbus_write_byte_data(client,
+ DS1307_REG_HOUR,
+ BIN2BCD(tmp));
+ }
ds1307->rtc = rtc_device_register(client->name, &client->dev,
&ds13xx_rtc_ops, THIS_MODULE);
@@ -330,46 +410,40 @@ read_rtc:
err = PTR_ERR(ds1307->rtc);
dev_err(&client->dev,
"unable to register the class device\n");
- goto exit_detach;
+ goto exit_free;
}
return 0;
-exit_detach:
- i2c_detach_client(client);
+exit_bad:
+ dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+ "bogus register",
+ ds1307->regs[0], ds1307->regs[1],
+ ds1307->regs[2], ds1307->regs[3],
+ ds1307->regs[4], ds1307->regs[5],
+ ds1307->regs[6]);
+
exit_free:
kfree(ds1307);
-exit:
return err;
}
-static int __devinit
-ds1307_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
- return 0;
- return i2c_probe(adapter, &addr_data, ds1307_detect);
-}
-
-static int __devexit ds1307_detach_client(struct i2c_client *client)
+static int __devexit ds1307_remove(struct i2c_client *client)
{
- int err;
struct ds1307 *ds1307 = i2c_get_clientdata(client);
rtc_device_unregister(ds1307->rtc);
- if ((err = i2c_detach_client(client)))
- return err;
kfree(ds1307);
return 0;
}
static struct i2c_driver ds1307_driver = {
.driver = {
- .name = "ds1307",
+ .name = "rtc-ds1307",
.owner = THIS_MODULE,
},
- .attach_adapter = ds1307_attach_adapter,
- .detach_client = __devexit_p(ds1307_detach_client),
+ .probe = ds1307_probe,
+ .remove = __devexit_p(ds1307_remove),
};
static int __init ds1307_init(void)
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index afa64c7fa2e2..46da5714932c 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -258,8 +258,9 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
.ioctl = ds1553_rtc_ioctl,
};
-static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
- loff_t pos, size_t size)
+static ssize_t ds1553_nvram_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
{
struct platform_device *pdev =
to_platform_device(container_of(kobj, struct device, kobj));
@@ -272,8 +273,9 @@ static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
return count;
}
-static ssize_t ds1553_nvram_write(struct kobject *kobj, char *buf,
- loff_t pos, size_t size)
+static ssize_t ds1553_nvram_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
{
struct platform_device *pdev =
to_platform_device(container_of(kobj, struct device, kobj));
@@ -290,7 +292,6 @@ static struct bin_attribute ds1553_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUGO,
- .owner = THIS_MODULE,
},
.size = RTC_OFFSET,
.read = ds1553_nvram_read,
@@ -406,7 +407,7 @@ static __init int ds1553_init(void)
static __exit void ds1553_exit(void)
{
- return platform_driver_unregister(&ds1553_rtc_driver);
+ platform_driver_unregister(&ds1553_rtc_driver);
}
module_init(ds1553_init);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index d68288b389dc..b2e5481ba3b6 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -127,8 +127,9 @@ static const struct rtc_class_ops ds1742_rtc_ops = {
.set_time = ds1742_rtc_set_time,
};
-static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
- loff_t pos, size_t size)
+static ssize_t ds1742_nvram_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
{
struct platform_device *pdev =
to_platform_device(container_of(kobj, struct device, kobj));
@@ -141,8 +142,9 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
return count;
}
-static ssize_t ds1742_nvram_write(struct kobject *kobj, char *buf,
- loff_t pos, size_t size)
+static ssize_t ds1742_nvram_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
{
struct platform_device *pdev =
to_platform_device(container_of(kobj, struct device, kobj));
@@ -159,7 +161,6 @@ static struct bin_attribute ds1742_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUGO,
- .owner = THIS_MODULE,
},
.read = ds1742_nvram_read,
.write = ds1742_nvram_write,
@@ -262,7 +263,7 @@ static __init int ds1742_init(void)
static __exit void ds1742_exit(void)
{
- return platform_driver_unregister(&ds1742_rtc_driver);
+ platform_driver_unregister(&ds1742_rtc_driver);
}
module_init(ds1742_init);
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
new file mode 100644
index 000000000000..80c4a8463065
--- /dev/null
+++ b/drivers/rtc/rtc-m41t80.c
@@ -0,0 +1,917 @@
+/*
+ * I2C client/driver for the ST M41T80 family of i2c rtc chips.
+ *
+ * Author: Alexander Bigga <ab@mycable.de>
+ *
+ * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2006 (c) mycable GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#ifdef CONFIG_RTC_DRV_M41T80_WDT
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#endif
+
+#define M41T80_REG_SSEC 0
+#define M41T80_REG_SEC 1
+#define M41T80_REG_MIN 2
+#define M41T80_REG_HOUR 3
+#define M41T80_REG_WDAY 4
+#define M41T80_REG_DAY 5
+#define M41T80_REG_MON 6
+#define M41T80_REG_YEAR 7
+#define M41T80_REG_ALARM_MON 0xa
+#define M41T80_REG_ALARM_DAY 0xb
+#define M41T80_REG_ALARM_HOUR 0xc
+#define M41T80_REG_ALARM_MIN 0xd
+#define M41T80_REG_ALARM_SEC 0xe
+#define M41T80_REG_FLAGS 0xf
+#define M41T80_REG_SQW 0x13
+
+#define M41T80_DATETIME_REG_SIZE (M41T80_REG_YEAR + 1)
+#define M41T80_ALARM_REG_SIZE \
+ (M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON)
+
+#define M41T80_SEC_ST (1 << 7) /* ST: Stop Bit */
+#define M41T80_ALMON_AFE (1 << 7) /* AFE: AF Enable Bit */
+#define M41T80_ALMON_SQWE (1 << 6) /* SQWE: SQW Enable Bit */
+#define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
+#define M41T80_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */
+#define M41T80_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */
+
+#define M41T80_FEATURE_HT (1 << 0)
+#define M41T80_FEATURE_BL (1 << 1)
+
+#define DRV_VERSION "0.05"
+
+struct m41t80_chip_info {
+ const char *name;
+ u8 features;
+};
+
+static const struct m41t80_chip_info m41t80_chip_info_tbl[] = {
+ {
+ .name = "m41t80",
+ .features = 0,
+ },
+ {
+ .name = "m41t81",
+ .features = M41T80_FEATURE_HT,
+ },
+ {
+ .name = "m41t81s",
+ .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
+ },
+ {
+ .name = "m41t82",
+ .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
+ },
+ {
+ .name = "m41t83",
+ .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
+ },
+ {
+ .name = "m41st84",
+ .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
+ },
+ {
+ .name = "m41st85",
+ .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
+ },
+ {
+ .name = "m41st87",
+ .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
+ },
+};
+
+struct m41t80_data {
+ const struct m41t80_chip_info *chip;
+ struct rtc_device *rtc;
+};
+
+static int m41t80_get_datetime(struct i2c_client *client,
+ struct rtc_time *tm)
+{
+ u8 buf[M41T80_DATETIME_REG_SIZE], dt_addr[1] = { M41T80_REG_SEC };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = dt_addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC,
+ .buf = buf + M41T80_REG_SEC,
+ },
+ };
+
+ if (i2c_transfer(client->adapter, msgs, 2) < 0) {
+ dev_err(&client->dev, "read error\n");
+ return -EIO;
+ }
+
+ tm->tm_sec = BCD2BIN(buf[M41T80_REG_SEC] & 0x7f);
+ tm->tm_min = BCD2BIN(buf[M41T80_REG_MIN] & 0x7f);
+ tm->tm_hour = BCD2BIN(buf[M41T80_REG_HOUR] & 0x3f);
+ tm->tm_mday = BCD2BIN(buf[M41T80_REG_DAY] & 0x3f);
+ tm->tm_wday = buf[M41T80_REG_WDAY] & 0x07;
+ tm->tm_mon = BCD2BIN(buf[M41T80_REG_MON] & 0x1f) - 1;
+
+ /* assume 20YY not 19YY, and ignore the Century Bit */
+ tm->tm_year = BCD2BIN(buf[M41T80_REG_YEAR]) + 100;
+ return 0;
+}
+
+/* Sets the given date and time to the real time clock. */
+static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+ u8 wbuf[1 + M41T80_DATETIME_REG_SIZE];
+ u8 *buf = &wbuf[1];
+ u8 dt_addr[1] = { M41T80_REG_SEC };
+ struct i2c_msg msgs_in[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = dt_addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC,
+ .buf = buf + M41T80_REG_SEC,
+ },
+ };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1 + M41T80_DATETIME_REG_SIZE,
+ .buf = wbuf,
+ },
+ };
+
+ /* Read current reg values into buf[1..7] */
+ if (i2c_transfer(client->adapter, msgs_in, 2) < 0) {
+ dev_err(&client->dev, "read error\n");
+ return -EIO;
+ }
+
+ wbuf[0] = 0; /* offset into rtc's regs */
+ /* Merge time-data and register flags into buf[0..7] */
+ buf[M41T80_REG_SSEC] = 0;
+ buf[M41T80_REG_SEC] =
+ BIN2BCD(tm->tm_sec) | (buf[M41T80_REG_SEC] & ~0x7f);
+ buf[M41T80_REG_MIN] =
+ BIN2BCD(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f);
+ buf[M41T80_REG_HOUR] =
+ BIN2BCD(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f) ;
+ buf[M41T80_REG_WDAY] =
+ (tm->tm_wday & 0x07) | (buf[M41T80_REG_WDAY] & ~0x07);
+ buf[M41T80_REG_DAY] =
+ BIN2BCD(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f);
+ buf[M41T80_REG_MON] =
+ BIN2BCD(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f);
+ /* assume 20YY not 19YY */
+ buf[M41T80_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
+
+ if (i2c_transfer(client->adapter, msgs, 1) != 1) {
+ dev_err(&client->dev, "write error\n");
+ return -EIO;
+ }
+ return 0;
+}
+
+#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct m41t80_data *clientdata = i2c_get_clientdata(client);
+ u8 reg;
+
+ if (clientdata->chip->features & M41T80_FEATURE_BL) {
+ reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
+ seq_printf(seq, "battery\t\t: %s\n",
+ (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok");
+ }
+ return 0;
+}
+#else
+#define m41t80_rtc_proc NULL
+#endif
+
+static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return m41t80_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return m41t80_set_datetime(to_i2c_client(dev), tm);
+}
+
+#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
+static int
+m41t80_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int rc;
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ case RTC_AIE_ON:
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
+ if (rc < 0)
+ goto err;
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ rc &= ~M41T80_ALMON_AFE;
+ break;
+ case RTC_AIE_ON:
+ rc |= M41T80_ALMON_AFE;
+ break;
+ }
+ if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0)
+ goto err;
+ return 0;
+err:
+ return -EIO;
+}
+#else
+#define m41t80_rtc_ioctl NULL
+#endif
+
+static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 wbuf[1 + M41T80_ALARM_REG_SIZE];
+ u8 *buf = &wbuf[1];
+ u8 *reg = buf - M41T80_REG_ALARM_MON;
+ u8 dt_addr[1] = { M41T80_REG_ALARM_MON };
+ struct i2c_msg msgs_in[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = dt_addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = M41T80_ALARM_REG_SIZE,
+ .buf = buf,
+ },
+ };
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1 + M41T80_ALARM_REG_SIZE,
+ .buf = wbuf,
+ },
+ };
+
+ if (i2c_transfer(client->adapter, msgs_in, 2) < 0) {
+ dev_err(&client->dev, "read error\n");
+ return -EIO;
+ }
+ reg[M41T80_REG_ALARM_MON] &= ~(0x1f | M41T80_ALMON_AFE);
+ reg[M41T80_REG_ALARM_DAY] = 0;
+ reg[M41T80_REG_ALARM_HOUR] &= ~(0x3f | 0x80);
+ reg[M41T80_REG_ALARM_MIN] = 0;
+ reg[M41T80_REG_ALARM_SEC] = 0;
+
+ wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */
+ reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ?
+ BIN2BCD(t->time.tm_sec) : 0x80;
+ reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ?
+ BIN2BCD(t->time.tm_min) : 0x80;
+ reg[M41T80_REG_ALARM_HOUR] |= t->time.tm_hour >= 0 ?
+ BIN2BCD(t->time.tm_hour) : 0x80;
+ reg[M41T80_REG_ALARM_DAY] |= t->time.tm_mday >= 0 ?
+ BIN2BCD(t->time.tm_mday) : 0x80;
+ if (t->time.tm_mon >= 0)
+ reg[M41T80_REG_ALARM_MON] |= BIN2BCD(t->time.tm_mon + 1);
+ else
+ reg[M41T80_REG_ALARM_DAY] |= 0x40;
+
+ if (i2c_transfer(client->adapter, msgs, 1) != 1) {
+ dev_err(&client->dev, "write error\n");
+ return -EIO;
+ }
+
+ if (t->enabled) {
+ reg[M41T80_REG_ALARM_MON] |= M41T80_ALMON_AFE;
+ if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
+ reg[M41T80_REG_ALARM_MON]) < 0) {
+ dev_err(&client->dev, "write error\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 buf[M41T80_ALARM_REG_SIZE + 1]; /* all alarm regs and flags */
+ u8 dt_addr[1] = { M41T80_REG_ALARM_MON };
+ u8 *reg = buf - M41T80_REG_ALARM_MON;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = dt_addr,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = M41T80_ALARM_REG_SIZE + 1,
+ .buf = buf,
+ },
+ };
+
+ if (i2c_transfer(client->adapter, msgs, 2) < 0) {
+ dev_err(&client->dev, "read error\n");
+ return -EIO;
+ }
+ t->time.tm_sec = -1;
+ t->time.tm_min = -1;
+ t->time.tm_hour = -1;
+ t->time.tm_mday = -1;
+ t->time.tm_mon = -1;
+ if (!(reg[M41T80_REG_ALARM_SEC] & 0x80))
+ t->time.tm_sec = BCD2BIN(reg[M41T80_REG_ALARM_SEC] & 0x7f);
+ if (!(reg[M41T80_REG_ALARM_MIN] & 0x80))
+ t->time.tm_min = BCD2BIN(reg[M41T80_REG_ALARM_MIN] & 0x7f);
+ if (!(reg[M41T80_REG_ALARM_HOUR] & 0x80))
+ t->time.tm_hour = BCD2BIN(reg[M41T80_REG_ALARM_HOUR] & 0x3f);
+ if (!(reg[M41T80_REG_ALARM_DAY] & 0x80))
+ t->time.tm_mday = BCD2BIN(reg[M41T80_REG_ALARM_DAY] & 0x3f);
+ if (!(reg[M41T80_REG_ALARM_DAY] & 0x40))
+ t->time.tm_mon = BCD2BIN(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1;
+ t->time.tm_year = -1;
+ t->time.tm_wday = -1;
+ t->time.tm_yday = -1;
+ t->time.tm_isdst = -1;
+ t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE);
+ t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF);
+ return 0;
+}
+
+static struct rtc_class_ops m41t80_rtc_ops = {
+ .read_time = m41t80_rtc_read_time,
+ .set_time = m41t80_rtc_set_time,
+ .read_alarm = m41t80_rtc_read_alarm,
+ .set_alarm = m41t80_rtc_set_alarm,
+ .proc = m41t80_rtc_proc,
+ .ioctl = m41t80_rtc_ioctl,
+};
+
+#if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE)
+static ssize_t m41t80_sysfs_show_flags(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
+ if (val < 0)
+ return -EIO;
+ return sprintf(buf, "%#x\n", val);
+}
+static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL);
+
+static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
+ if (val < 0)
+ return -EIO;
+ val = (val >> 4) & 0xf;
+ switch (val) {
+ case 0:
+ break;
+ case 1:
+ val = 32768;
+ break;
+ default:
+ val = 32768 >> val;
+ }
+ return sprintf(buf, "%d\n", val);
+}
+static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int almon, sqw;
+ int val = simple_strtoul(buf, NULL, 0);
+
+ if (val) {
+ if (!is_power_of_2(val))
+ return -EINVAL;
+ val = ilog2(val);
+ if (val == 15)
+ val = 1;
+ else if (val < 14)
+ val = 15 - val;
+ else
+ return -EINVAL;
+ }
+ /* disable SQW, set SQW frequency & re-enable */
+ almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
+ if (almon < 0)
+ return -EIO;
+ sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
+ if (sqw < 0)
+ return -EIO;
+ sqw = (sqw & 0x0f) | (val << 4);
+ if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
+ almon & ~M41T80_ALMON_SQWE) < 0 ||
+ i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0)
+ return -EIO;
+ if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
+ almon | M41T80_ALMON_SQWE) < 0)
+ return -EIO;
+ return count;
+}
+static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR,
+ m41t80_sysfs_show_sqwfreq, m41t80_sysfs_set_sqwfreq);
+
+static struct attribute *attrs[] = {
+ &dev_attr_flags.attr,
+ &dev_attr_sqwfreq.attr,
+ NULL,
+};
+static struct attribute_group attr_group = {
+ .attrs = attrs,
+};
+
+static int m41t80_sysfs_register(struct device *dev)
+{
+ return sysfs_create_group(&dev->kobj, &attr_group);
+}
+#else
+static int m41t80_sysfs_register(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_RTC_DRV_M41T80_WDT
+/*
+ *****************************************************************************
+ *
+ * Watchdog Driver
+ *
+ *****************************************************************************
+ */
+static struct i2c_client *save_client;
+
+/* Default margin */
+#define WD_TIMO 60 /* 1..31 seconds */
+
+static int wdt_margin = WD_TIMO;
+module_param(wdt_margin, int, 0);
+MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 60s)");
+
+static unsigned long wdt_is_open;
+static int boot_flag;
+
+/**
+ * wdt_ping:
+ *
+ * Reload counter one with the watchdog timeout. We don't bother reloading
+ * the cascade counter.
+ */
+static void wdt_ping(void)
+{
+ unsigned char i2c_data[2];
+ struct i2c_msg msgs1[1] = {
+ {
+ .addr = save_client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = i2c_data,
+ },
+ };
+ i2c_data[0] = 0x09; /* watchdog register */
+
+ if (wdt_margin > 31)
+ i2c_data[1] = (wdt_margin & 0xFC) | 0x83; /* resolution = 4s */
+ else
+ /*
+ * WDS = 1 (0x80), mulitplier = WD_TIMO, resolution = 1s (0x02)
+ */
+ i2c_data[1] = wdt_margin<<2 | 0x82;
+
+ i2c_transfer(save_client->adapter, msgs1, 1);
+}
+
+/**
+ * wdt_disable:
+ *
+ * disables watchdog.
+ */
+static void wdt_disable(void)
+{
+ unsigned char i2c_data[2], i2c_buf[0x10];
+ struct i2c_msg msgs0[2] = {
+ {
+ .addr = save_client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = i2c_data,
+ },
+ {
+ .addr = save_client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = i2c_buf,
+ },
+ };
+ struct i2c_msg msgs1[1] = {
+ {
+ .addr = save_client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = i2c_data,
+ },
+ };
+
+ i2c_data[0] = 0x09;
+ i2c_transfer(save_client->adapter, msgs0, 2);
+
+ i2c_data[0] = 0x09;
+ i2c_data[1] = 0x00;
+ i2c_transfer(save_client->adapter, msgs1, 1);
+}
+
+/**
+ * wdt_write:
+ * @file: file handle to the watchdog
+ * @buf: buffer to write (unused as data does not matter here
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal. Any
+ * write of data will do, as we we don't define content meaning.
+ */
+static ssize_t wdt_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ /* Can't seek (pwrite) on this device
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+ */
+ if (count) {
+ wdt_ping();
+ return 1;
+ }
+ return 0;
+}
+
+static ssize_t wdt_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return 0;
+}
+
+/**
+ * wdt_ioctl:
+ * @inode: inode of the device
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features. We only actually usefully support
+ * querying capabilities and current status.
+ */
+static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int new_margin, rv;
+ static struct watchdog_info ident = {
+ .options = WDIOF_POWERUNDER | WDIOF_KEEPALIVEPING |
+ WDIOF_SETTIMEOUT,
+ .firmware_version = 1,
+ .identity = "M41T80 WTD"
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info __user *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(boot_flag, (int __user *)arg);
+ case WDIOC_KEEPALIVE:
+ wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int __user *)arg))
+ return -EFAULT;
+ /* Arbitrary, can't find the card's limits */
+ if (new_margin < 1 || new_margin > 124)
+ return -EINVAL;
+ wdt_margin = new_margin;
+ wdt_ping();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(wdt_margin, (int __user *)arg);
+
+ case WDIOC_SETOPTIONS:
+ if (copy_from_user(&rv, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ if (rv & WDIOS_DISABLECARD) {
+ printk(KERN_INFO
+ "rtc-m41t80: disable watchdog\n");
+ wdt_disable();
+ }
+
+ if (rv & WDIOS_ENABLECARD) {
+ printk(KERN_INFO
+ "rtc-m41t80: enable watchdog\n");
+ wdt_ping();
+ }
+
+ return -EINVAL;
+ }
+ return -ENOTTY;
+}
+
+/**
+ * wdt_open:
+ * @inode: inode of device
+ * @file: file handle to device
+ *
+ */
+static int wdt_open(struct inode *inode, struct file *file)
+{
+ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+ if (test_and_set_bit(0, &wdt_is_open))
+ return -EBUSY;
+ /*
+ * Activate
+ */
+ wdt_is_open = 1;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+/**
+ * wdt_close:
+ * @inode: inode to board
+ * @file: file handle to board
+ *
+ */
+static int wdt_release(struct inode *inode, struct file *file)
+{
+ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR)
+ clear_bit(0, &wdt_is_open);
+ return 0;
+}
+
+/**
+ * notify_sys:
+ * @this: our notifier block
+ * @code: the event being reported
+ * @unused: unused
+ *
+ * Our notifier is called on system shutdowns. We want to turn the card
+ * off at reboot otherwise the machine will reboot again during memory
+ * test or worse yet during the following fsck. This would suck, in fact
+ * trust me - if it happens it does suck.
+ */
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ /* Disable Watchdog */
+ wdt_disable();
+ return NOTIFY_DONE;
+}
+
+static const struct file_operations wdt_fops = {
+ .owner = THIS_MODULE,
+ .read = wdt_read,
+ .ioctl = wdt_ioctl,
+ .write = wdt_write,
+ .open = wdt_open,
+ .release = wdt_release,
+};
+
+static struct miscdevice wdt_dev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdt_fops,
+};
+
+/*
+ * The WDT card needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+static struct notifier_block wdt_notifier = {
+ .notifier_call = wdt_notify_sys,
+};
+#endif /* CONFIG_RTC_DRV_M41T80_WDT */
+
+/*
+ *****************************************************************************
+ *
+ * Driver Interface
+ *
+ *****************************************************************************
+ */
+static int m41t80_probe(struct i2c_client *client)
+{
+ int i, rc = 0;
+ struct rtc_device *rtc = NULL;
+ struct rtc_time tm;
+ const struct m41t80_chip_info *chip;
+ struct m41t80_data *clientdata = NULL;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
+ | I2C_FUNC_SMBUS_BYTE_DATA)) {
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ dev_info(&client->dev,
+ "chip found, driver version " DRV_VERSION "\n");
+
+ chip = NULL;
+ for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) {
+ if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) {
+ chip = &m41t80_chip_info_tbl[i];
+ break;
+ }
+ }
+ if (!chip) {
+ dev_err(&client->dev, "%s is not supported\n", client->name);
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL);
+ if (!clientdata) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ rtc = rtc_device_register(client->name, &client->dev,
+ &m41t80_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ rc = PTR_ERR(rtc);
+ rtc = NULL;
+ goto exit;
+ }
+
+ clientdata->rtc = rtc;
+ clientdata->chip = chip;
+ i2c_set_clientdata(client, clientdata);
+
+ /* Make sure HT (Halt Update) bit is cleared */
+ rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR);
+ if (rc < 0)
+ goto ht_err;
+
+ if (rc & M41T80_ALHOUR_HT) {
+ if (chip->features & M41T80_FEATURE_HT) {
+ m41t80_get_datetime(client, &tm);
+ dev_info(&client->dev, "HT bit was set!\n");
+ dev_info(&client->dev,
+ "Power Down at "
+ "%04i-%02i-%02i %02i:%02i:%02i\n",
+ tm.tm_year + 1900,
+ tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,
+ tm.tm_min, tm.tm_sec);
+ }
+ if (i2c_smbus_write_byte_data(client,
+ M41T80_REG_ALARM_HOUR,
+ rc & ~M41T80_ALHOUR_HT) < 0)
+ goto ht_err;
+ }
+
+ /* Make sure ST (stop) bit is cleared */
+ rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC);
+ if (rc < 0)
+ goto st_err;
+
+ if (rc & M41T80_SEC_ST) {
+ if (i2c_smbus_write_byte_data(client, M41T80_REG_SEC,
+ rc & ~M41T80_SEC_ST) < 0)
+ goto st_err;
+ }
+
+ rc = m41t80_sysfs_register(&client->dev);
+ if (rc)
+ goto exit;
+
+#ifdef CONFIG_RTC_DRV_M41T80_WDT
+ if (chip->features & M41T80_FEATURE_HT) {
+ rc = misc_register(&wdt_dev);
+ if (rc)
+ goto exit;
+ rc = register_reboot_notifier(&wdt_notifier);
+ if (rc) {
+ misc_deregister(&wdt_dev);
+ goto exit;
+ }
+ save_client = client;
+ }
+#endif
+ return 0;
+
+st_err:
+ rc = -EIO;
+ dev_err(&client->dev, "Can't clear ST bit\n");
+ goto exit;
+ht_err:
+ rc = -EIO;
+ dev_err(&client->dev, "Can't clear HT bit\n");
+ goto exit;
+
+exit:
+ if (rtc)
+ rtc_device_unregister(rtc);
+ kfree(clientdata);
+ return rc;
+}
+
+static int m41t80_remove(struct i2c_client *client)
+{
+ struct m41t80_data *clientdata = i2c_get_clientdata(client);
+ struct rtc_device *rtc = clientdata->rtc;
+
+#ifdef CONFIG_RTC_DRV_M41T80_WDT
+ if (clientdata->chip->features & M41T80_FEATURE_HT) {
+ misc_deregister(&wdt_dev);
+ unregister_reboot_notifier(&wdt_notifier);
+ }
+#endif
+ if (rtc)
+ rtc_device_unregister(rtc);
+ kfree(clientdata);
+
+ return 0;
+}
+
+static struct i2c_driver m41t80_driver = {
+ .driver = {
+ .name = "m41t80",
+ },
+ .probe = m41t80_probe,
+ .remove = m41t80_remove,
+};
+
+static int __init m41t80_rtc_init(void)
+{
+ return i2c_add_driver(&m41t80_driver);
+}
+
+static void __exit m41t80_rtc_exit(void)
+{
+ i2c_del_driver(&m41t80_driver);
+}
+
+MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");
+MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(m41t80_rtc_init);
+module_exit(m41t80_rtc_exit);
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
new file mode 100644
index 000000000000..33b752350ab5
--- /dev/null
+++ b/drivers/rtc/rtc-m48t59.c
@@ -0,0 +1,491 @@
+/*
+ * ST M48T59 RTC driver
+ *
+ * Copyright (c) 2007 Wind River Systems, Inc.
+ *
+ * Author: Mark Zhan <rongkai.zhan@windriver.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/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/rtc/m48t59.h>
+#include <linux/bcd.h>
+
+#ifndef NO_IRQ
+#define NO_IRQ (-1)
+#endif
+
+#define M48T59_READ(reg) pdata->read_byte(dev, reg)
+#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val)
+
+#define M48T59_SET_BITS(mask, reg) \
+ M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
+#define M48T59_CLEAR_BITS(mask, reg) \
+ M48T59_WRITE((M48T59_READ(reg) & ~(mask)), (reg))
+
+struct m48t59_private {
+ void __iomem *ioaddr;
+ unsigned int size; /* iomem size */
+ unsigned int irq;
+ struct rtc_device *rtc;
+ spinlock_t lock; /* serialize the NVRAM and RTC access */
+};
+
+/*
+ * This is the generic access method when the chip is memory-mapped
+ */
+static void
+m48t59_mem_writeb(struct device *dev, u32 ofs, u8 val)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+
+ writeb(val, m48t59->ioaddr+ofs);
+}
+
+static u8
+m48t59_mem_readb(struct device *dev, u32 ofs)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+
+ return readb(m48t59->ioaddr+ofs);
+}
+
+/*
+ * NOTE: M48T59 only uses BCD mode
+ */
+static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ unsigned long flags;
+ u8 val;
+
+ spin_lock_irqsave(&m48t59->lock, flags);
+ /* Issue the READ command */
+ M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
+
+ tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR));
+ /* tm_mon is 0-11 */
+ tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1;
+ tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY));
+
+ val = M48T59_READ(M48T59_WDAY);
+ if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
+ dev_dbg(dev, "Century bit is enabled\n");
+ tm->tm_year += 100; /* one century */
+ }
+
+ tm->tm_wday = BCD2BIN(val & 0x07);
+ tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_HOUR) & 0x3F);
+ tm->tm_min = BCD2BIN(M48T59_READ(M48T59_MIN) & 0x7F);
+ tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_SEC) & 0x7F);
+
+ /* Clear the READ bit */
+ M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL);
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+
+ dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n",
+ tm->tm_year + 1900, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return 0;
+}
+
+static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ unsigned long flags;
+ u8 val = 0;
+
+ dev_dbg(dev, "RTC set time %04d-%02d-%02d %02d/%02d/%02d\n",
+ tm->tm_year + 1900, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ spin_lock_irqsave(&m48t59->lock, flags);
+ /* Issue the WRITE command */
+ M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
+
+ M48T59_WRITE((BIN2BCD(tm->tm_sec) & 0x7F), M48T59_SEC);
+ M48T59_WRITE((BIN2BCD(tm->tm_min) & 0x7F), M48T59_MIN);
+ M48T59_WRITE((BIN2BCD(tm->tm_hour) & 0x3F), M48T59_HOUR);
+ M48T59_WRITE((BIN2BCD(tm->tm_mday) & 0x3F), M48T59_MDAY);
+ /* tm_mon is 0-11 */
+ M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
+ M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
+
+ if (tm->tm_year/100)
+ val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
+ val |= (BIN2BCD(tm->tm_wday) & 0x07);
+ M48T59_WRITE(val, M48T59_WDAY);
+
+ /* Clear the WRITE bit */
+ M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+ return 0;
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ struct rtc_time *tm = &alrm->time;
+ unsigned long flags;
+ u8 val;
+
+ /* If no irq, we don't support ALARM */
+ if (m48t59->irq == NO_IRQ)
+ return -EIO;
+
+ spin_lock_irqsave(&m48t59->lock, flags);
+ /* Issue the READ command */
+ M48T59_SET_BITS(M48T59_CNTL_READ, M48T59_CNTL);
+
+ tm->tm_year = BCD2BIN(M48T59_READ(M48T59_YEAR));
+ /* tm_mon is 0-11 */
+ tm->tm_mon = BCD2BIN(M48T59_READ(M48T59_MONTH)) - 1;
+
+ val = M48T59_READ(M48T59_WDAY);
+ if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB))
+ tm->tm_year += 100; /* one century */
+
+ tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_ALARM_DATE));
+ tm->tm_hour = BCD2BIN(M48T59_READ(M48T59_ALARM_HOUR));
+ tm->tm_min = BCD2BIN(M48T59_READ(M48T59_ALARM_MIN));
+ tm->tm_sec = BCD2BIN(M48T59_READ(M48T59_ALARM_SEC));
+
+ /* Clear the READ bit */
+ M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL);
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+
+ dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n",
+ tm->tm_year + 1900, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return 0;
+}
+
+/*
+ * Set alarm time and date in RTC
+ */
+static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ struct rtc_time *tm = &alrm->time;
+ u8 mday, hour, min, sec;
+ unsigned long flags;
+
+ /* If no irq, we don't support ALARM */
+ if (m48t59->irq == NO_IRQ)
+ return -EIO;
+
+ /*
+ * 0xff means "always match"
+ */
+ mday = tm->tm_mday;
+ mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff;
+ if (mday == 0xff)
+ mday = M48T59_READ(M48T59_MDAY);
+
+ hour = tm->tm_hour;
+ hour = (hour < 24) ? BIN2BCD(hour) : 0x00;
+
+ min = tm->tm_min;
+ min = (min < 60) ? BIN2BCD(min) : 0x00;
+
+ sec = tm->tm_sec;
+ sec = (sec < 60) ? BIN2BCD(sec) : 0x00;
+
+ spin_lock_irqsave(&m48t59->lock, flags);
+ /* Issue the WRITE command */
+ M48T59_SET_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
+
+ M48T59_WRITE(mday, M48T59_ALARM_DATE);
+ M48T59_WRITE(hour, M48T59_ALARM_HOUR);
+ M48T59_WRITE(min, M48T59_ALARM_MIN);
+ M48T59_WRITE(sec, M48T59_ALARM_SEC);
+
+ /* Clear the WRITE bit */
+ M48T59_CLEAR_BITS(M48T59_CNTL_WRITE, M48T59_CNTL);
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+
+ dev_dbg(dev, "RTC set alarm time %04d-%02d-%02d %02d/%02d/%02d\n",
+ tm->tm_year + 1900, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int m48t59_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&m48t59->lock, flags);
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm interrupt off */
+ M48T59_WRITE(0x00, M48T59_INTR);
+ break;
+ case RTC_AIE_ON: /* alarm interrupt on */
+ M48T59_WRITE(M48T59_INTR_AFE, M48T59_INTR);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+
+ return ret;
+}
+
+static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ unsigned long flags;
+ u8 val;
+
+ spin_lock_irqsave(&m48t59->lock, flags);
+ val = M48T59_READ(M48T59_FLAGS);
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+
+ seq_printf(seq, "battery\t\t: %s\n",
+ (val & M48T59_FLAGS_BF) ? "low" : "normal");
+ return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id)
+{
+ struct device *dev = (struct device *)dev_id;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ u8 event;
+
+ spin_lock(&m48t59->lock);
+ event = M48T59_READ(M48T59_FLAGS);
+ spin_unlock(&m48t59->lock);
+
+ if (event & M48T59_FLAGS_AF) {
+ rtc_update_irq(m48t59->rtc, 1, (RTC_AF | RTC_IRQF));
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static const struct rtc_class_ops m48t59_rtc_ops = {
+ .ioctl = m48t59_rtc_ioctl,
+ .read_time = m48t59_rtc_read_time,
+ .set_time = m48t59_rtc_set_time,
+ .read_alarm = m48t59_rtc_readalarm,
+ .set_alarm = m48t59_rtc_setalarm,
+ .proc = m48t59_rtc_proc,
+};
+
+static ssize_t m48t59_nvram_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ ssize_t cnt = 0;
+ unsigned long flags;
+
+ for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+ spin_lock_irqsave(&m48t59->lock, flags);
+ *buf++ = M48T59_READ(cnt);
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+ }
+
+ return cnt;
+}
+
+static ssize_t m48t59_nvram_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+ ssize_t cnt = 0;
+ unsigned long flags;
+
+ for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
+ spin_lock_irqsave(&m48t59->lock, flags);
+ M48T59_WRITE(*buf++, cnt);
+ spin_unlock_irqrestore(&m48t59->lock, flags);
+ }
+
+ return cnt;
+}
+
+static struct bin_attribute m48t59_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .read = m48t59_nvram_read,
+ .write = m48t59_nvram_write,
+};
+
+static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
+{
+ struct m48t59_plat_data *pdata = pdev->dev.platform_data;
+ struct m48t59_private *m48t59 = NULL;
+ struct resource *res;
+ int ret = -ENOMEM;
+
+ /* This chip could be memory-mapped or I/O-mapped */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (!res)
+ return -EINVAL;
+ }
+
+ if (res->flags & IORESOURCE_IO) {
+ /* If we are I/O-mapped, the platform should provide
+ * the operations accessing chip registers.
+ */
+ if (!pdata || !pdata->write_byte || !pdata->read_byte)
+ return -EINVAL;
+ } else if (res->flags & IORESOURCE_MEM) {
+ /* we are memory-mapped */
+ if (!pdata) {
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ /* Ensure we only kmalloc platform data once */
+ pdev->dev.platform_data = pdata;
+ }
+
+ /* Try to use the generic memory read/write ops */
+ if (!pdata->write_byte)
+ pdata->write_byte = m48t59_mem_writeb;
+ if (!pdata->read_byte)
+ pdata->read_byte = m48t59_mem_readb;
+ }
+
+ m48t59 = kzalloc(sizeof(*m48t59), GFP_KERNEL);
+ if (!m48t59)
+ return -ENOMEM;
+
+ m48t59->size = res->end - res->start + 1;
+ m48t59->ioaddr = ioremap(res->start, m48t59->size);
+ if (!m48t59->ioaddr)
+ goto out;
+
+ /* Try to get irq number. We also can work in
+ * the mode without IRQ.
+ */
+ m48t59->irq = platform_get_irq(pdev, 0);
+ if (m48t59->irq < 0)
+ m48t59->irq = NO_IRQ;
+
+ if (m48t59->irq != NO_IRQ) {
+ ret = request_irq(m48t59->irq, m48t59_rtc_interrupt,
+ IRQF_SHARED, "rtc-m48t59", &pdev->dev);
+ if (ret)
+ goto out;
+ }
+
+ m48t59->rtc = rtc_device_register("m48t59", &pdev->dev,
+ &m48t59_rtc_ops, THIS_MODULE);
+ if (IS_ERR(m48t59->rtc)) {
+ ret = PTR_ERR(m48t59->rtc);
+ goto out;
+ }
+
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
+ if (ret)
+ goto out;
+
+ spin_lock_init(&m48t59->lock);
+ platform_set_drvdata(pdev, m48t59);
+ return 0;
+
+out:
+ if (!IS_ERR(m48t59->rtc))
+ rtc_device_unregister(m48t59->rtc);
+ if (m48t59->irq != NO_IRQ)
+ free_irq(m48t59->irq, &pdev->dev);
+ if (m48t59->ioaddr)
+ iounmap(m48t59->ioaddr);
+ if (m48t59)
+ kfree(m48t59);
+ return ret;
+}
+
+static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
+{
+ struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
+ if (!IS_ERR(m48t59->rtc))
+ rtc_device_unregister(m48t59->rtc);
+ if (m48t59->ioaddr)
+ iounmap(m48t59->ioaddr);
+ if (m48t59->irq != NO_IRQ)
+ free_irq(m48t59->irq, &pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(m48t59);
+ return 0;
+}
+
+static struct platform_driver m48t59_rtc_platdrv = {
+ .driver = {
+ .name = "rtc-m48t59",
+ .owner = THIS_MODULE,
+ },
+ .probe = m48t59_rtc_probe,
+ .remove = __devexit_p(m48t59_rtc_remove),
+};
+
+static int __init m48t59_rtc_init(void)
+{
+ return platform_driver_register(&m48t59_rtc_platdrv);
+}
+
+static void __exit m48t59_rtc_exit(void)
+{
+ platform_driver_unregister(&m48t59_rtc_platdrv);
+}
+
+module_init(m48t59_rtc_init);
+module_exit(m48t59_rtc_exit);
+
+MODULE_AUTHOR("Mark Zhan <rongkai.zhan@windriver.com>");
+MODULE_DESCRIPTION("M48T59 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index eee4ee5bb75a..a1cd448639c9 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -31,17 +31,24 @@
#define MAX6900_REG_DW 5 /* day of week 1-7 */
#define MAX6900_REG_YR 6 /* year 00-99 */
#define MAX6900_REG_CT 7 /* control */
-#define MAX6900_REG_LEN 8
+ /* register 8 is undocumented */
+#define MAX6900_REG_CENTURY 9 /* century */
+#define MAX6900_REG_LEN 10
+
+#define MAX6900_BURST_LEN 8 /* can burst r/w first 8 regs */
#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */
+
/*
* register read/write commands
*/
#define MAX6900_REG_CONTROL_WRITE 0x8e
-#define MAX6900_REG_BURST_READ 0xbf
-#define MAX6900_REG_BURST_WRITE 0xbe
+#define MAX6900_REG_CENTURY_WRITE 0x92
+#define MAX6900_REG_CENTURY_READ 0x93
#define MAX6900_REG_RESERVED_READ 0x96
+#define MAX6900_REG_BURST_WRITE 0xbe
+#define MAX6900_REG_BURST_READ 0xbf
#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */
@@ -58,19 +65,32 @@ static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
{
- u8 reg_addr[1] = { MAX6900_REG_BURST_READ };
- struct i2c_msg msgs[2] = {
+ u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ };
+ u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
+ struct i2c_msg msgs[4] = {
{
.addr = client->addr,
.flags = 0, /* write */
- .len = sizeof(reg_addr),
- .buf = reg_addr
+ .len = sizeof(reg_burst_read),
+ .buf = reg_burst_read
},
{
.addr = client->addr,
.flags = I2C_M_RD,
- .len = MAX6900_REG_LEN,
+ .len = MAX6900_BURST_LEN,
.buf = buf
+ },
+ {
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(reg_century_read),
+ .buf = reg_century_read
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf[MAX6900_REG_CENTURY]),
+ .buf = &buf[MAX6900_REG_CENTURY]
}
};
int rc;
@@ -86,33 +106,58 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
{
- u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE };
- struct i2c_msg msgs[1] = {
+ u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
+ struct i2c_msg century_msgs[1] = {
{
.addr = client->addr,
.flags = 0, /* write */
- .len = MAX6900_REG_LEN + 1,
- .buf = i2c_buf
+ .len = sizeof(i2c_century_buf),
+ .buf = i2c_century_buf
+ }
+ };
+ u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
+ struct i2c_msg burst_msgs[1] = {
+ {
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(i2c_burst_buf),
+ .buf = i2c_burst_buf
}
};
int rc;
- memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN);
+ /*
+ * We have to make separate calls to i2c_transfer because of
+ * the need to delay after each write to the chip. Also,
+ * we write the century byte first, since we set the write-protect
+ * bit as part of the burst write.
+ */
+ i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
+ rc = i2c_transfer(client->adapter, century_msgs,
+ ARRAY_SIZE(century_msgs));
+ if (rc != ARRAY_SIZE(century_msgs))
+ goto write_failed;
+ msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
- rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (rc != ARRAY_SIZE(msgs)) {
- dev_err(&client->dev, "%s: register write failed\n",
- __FUNCTION__);
- return -EIO;
- }
+ memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
+
+ rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs));
+ if (rc != ARRAY_SIZE(burst_msgs))
+ goto write_failed;
msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+
return 0;
+
+write_failed:
+ dev_err(&client->dev, "%s: register write failed\n",
+ __FUNCTION__);
+ return -EIO;
}
static int max6900_i2c_validate_client(struct i2c_client *client)
{
u8 regs[MAX6900_REG_LEN];
- u8 zero_mask[MAX6900_REG_LEN] = {
+ u8 zero_mask[] = {
0x80, /* seconds */
0x80, /* minutes */
0x40, /* hours */
@@ -134,7 +179,7 @@ static int max6900_i2c_validate_client(struct i2c_client *client)
if (rc < 0)
return rc;
- for (i = 0; i < MAX6900_REG_LEN; ++i) {
+ for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
if (regs[i] & zero_mask[i])
return -ENODEV;
}
@@ -156,7 +201,8 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
- tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100;
+ tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
+ BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
return 0;
@@ -189,9 +235,11 @@ static int max6900_i2c_set_time(struct i2c_client *client,
regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
- regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
- regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; /* set write protect */
+ regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100);
+ regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100);
+ /* set write protect */
+ regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
rc = max6900_i2c_write_regs(client, regs);
if (rc < 0)
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 09bbe575647b..6b67b5097927 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -13,13 +13,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
-#define DRV_VERSION "0.4"
-
-/* Addresses to scan */
-static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD;
+#define DRV_VERSION "0.5"
/*
@@ -88,9 +82,6 @@ struct rs5c372 {
unsigned has_irq:1;
char buf[17];
char *regs;
-
- /* on conversion to a "new style" i2c driver, this vanishes */
- struct i2c_client dev;
};
static int rs5c_get_regs(struct rs5c372 *rs5c)
@@ -483,25 +474,35 @@ static int rs5c_sysfs_register(struct device *dev)
return err;
}
+static void rs5c_sysfs_unregister(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_trim);
+ device_remove_file(dev, &dev_attr_osc);
+}
+
#else
static int rs5c_sysfs_register(struct device *dev)
{
return 0;
}
+
+static void rs5c_sysfs_unregister(struct device *dev)
+{
+ /* nothing */
+}
#endif /* SYSFS */
static struct i2c_driver rs5c372_driver;
-static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
+static int rs5c372_probe(struct i2c_client *client)
{
int err = 0;
- struct i2c_client *client;
struct rs5c372 *rs5c372;
struct rtc_time tm;
- dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+ dev_dbg(&client->dev, "%s\n", __FUNCTION__);
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
}
@@ -514,35 +515,22 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
rs5c372->regs=&rs5c372->buf[1];
- /* On conversion to a "new style" i2c driver, we'll be handed
- * the i2c_client (we won't create it)
- */
- client = &rs5c372->dev;
rs5c372->client = client;
-
- /* I2C client */
- client->addr = address;
- client->driver = &rs5c372_driver;
- client->adapter = adapter;
-
- strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE);
-
i2c_set_clientdata(client, rs5c372);
- /* Inform the i2c layer */
- if ((err = i2c_attach_client(client)))
- goto exit_kfree;
-
err = rs5c_get_regs(rs5c372);
if (err < 0)
- goto exit_detach;
+ goto exit_kfree;
- /* For "new style" drivers, irq is in i2c_client and chip type
- * info comes from i2c_client.dev.platform_data. Meanwhile:
- *
- * STICK BOARD-SPECIFIC SETUP CODE RIGHT HERE
- */
- if (rs5c372->type == rtc_undef) {
+ if (strcmp(client->name, "rs5c372a") == 0)
+ rs5c372->type = rtc_rs5c372a;
+ else if (strcmp(client->name, "rs5c372b") == 0)
+ rs5c372->type = rtc_rs5c372b;
+ else if (strcmp(client->name, "rv5c386") == 0)
+ rs5c372->type = rtc_rv5c386;
+ else if (strcmp(client->name, "rv5c387a") == 0)
+ rs5c372->type = rtc_rv5c387a;
+ else {
rs5c372->type = rtc_rs5c372b;
dev_warn(&client->dev, "assuming rs5c372b\n");
}
@@ -567,7 +555,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
break;
default:
dev_err(&client->dev, "unknown RTC type\n");
- goto exit_detach;
+ goto exit_kfree;
}
/* if the oscillator lost power and no other software (like
@@ -601,7 +589,7 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
if ((i2c_master_send(client, buf, 3)) != 3) {
dev_err(&client->dev, "setup error\n");
- goto exit_detach;
+ goto exit_kfree;
}
rs5c372->regs[RS5C_REG_CTRL1] = buf[1];
rs5c372->regs[RS5C_REG_CTRL2] = buf[2];
@@ -621,14 +609,14 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
rs5c372->time24 ? "24hr" : "am/pm"
);
- /* FIXME when client->irq exists, use it to register alarm irq */
+ /* REVISIT use client->irq to register alarm irq ... */
rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name,
&client->dev, &rs5c372_rtc_ops, THIS_MODULE);
if (IS_ERR(rs5c372->rtc)) {
err = PTR_ERR(rs5c372->rtc);
- goto exit_detach;
+ goto exit_kfree;
}
err = rs5c_sysfs_register(&client->dev);
@@ -640,9 +628,6 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
exit_devreg:
rtc_device_unregister(rs5c372->rtc);
-exit_detach:
- i2c_detach_client(client);
-
exit_kfree:
kfree(rs5c372);
@@ -650,24 +635,12 @@ exit:
return err;
}
-static int rs5c372_attach(struct i2c_adapter *adapter)
+static int rs5c372_remove(struct i2c_client *client)
{
- return i2c_probe(adapter, &addr_data, rs5c372_probe);
-}
-
-static int rs5c372_detach(struct i2c_client *client)
-{
- int err;
struct rs5c372 *rs5c372 = i2c_get_clientdata(client);
- if (rs5c372->rtc)
- rtc_device_unregister(rs5c372->rtc);
-
- /* REVISIT properly destroy the sysfs files ... */
-
- if ((err = i2c_detach_client(client)))
- return err;
-
+ rtc_device_unregister(rs5c372->rtc);
+ rs5c_sysfs_unregister(&client->dev);
kfree(rs5c372);
return 0;
}
@@ -676,8 +649,8 @@ static struct i2c_driver rs5c372_driver = {
.driver = {
.name = "rtc-rs5c372",
},
- .attach_adapter = &rs5c372_attach,
- .detach_client = &rs5c372_detach,
+ .probe = rs5c372_probe,
+ .remove = rs5c372_remove,
};
static __init int rs5c372_init(void)
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
new file mode 100644
index 000000000000..f10d3facecbe
--- /dev/null
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -0,0 +1,420 @@
+/*
+ * A RTC driver for the Simtek STK17TA8
+ *
+ * By Thomas Hommel <thomas.hommel@gefanuc.com>
+ *
+ * Based on the DS1553 driver from
+ * 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/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE 0x20000
+#define RTC_OFFSET 0x1fff0
+
+#define RTC_FLAGS (RTC_OFFSET + 0)
+#define RTC_CENTURY (RTC_OFFSET + 1)
+#define RTC_SECONDS_ALARM (RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM (RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM (RTC_OFFSET + 4)
+#define RTC_DATE_ALARM (RTC_OFFSET + 5)
+#define RTC_INTERRUPTS (RTC_OFFSET + 6)
+#define RTC_WATCHDOG (RTC_OFFSET + 7)
+#define RTC_CALIBRATION (RTC_OFFSET + 8)
+#define RTC_SECONDS (RTC_OFFSET + 9)
+#define RTC_MINUTES (RTC_OFFSET + 10)
+#define RTC_HOURS (RTC_OFFSET + 11)
+#define RTC_DAY (RTC_OFFSET + 12)
+#define RTC_DATE (RTC_OFFSET + 13)
+#define RTC_MONTH (RTC_OFFSET + 14)
+#define RTC_YEAR (RTC_OFFSET + 15)
+
+#define RTC_SECONDS_MASK 0x7f
+#define RTC_DAY_MASK 0x07
+#define RTC_CAL_MASK 0x3f
+
+/* Bits in the Calibration register */
+#define RTC_STOP 0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF 0x40
+#define RTC_FLAGS_PF 0x20
+#define RTC_WRITE 0x02
+#define RTC_READ 0x01
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AIE 0x40
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr;
+ unsigned long baseaddr;
+ unsigned long last_jiffies;
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ u8 flags;
+
+ flags = readb(pdata->ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+
+ writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+ writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
+
+ writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+ return 0;
+}
+
+static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned int year, month, day, hour, minute, second, week;
+ unsigned int century;
+ u8 flags;
+
+ /* give enough time to update RTC in case of continuous read */
+ if (pdata->last_jiffies == jiffies)
+ msleep(1);
+ pdata->last_jiffies = jiffies;
+
+ flags = readb(pdata->ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_READ, ioaddr + RTC_FLAGS);
+ second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+ minute = readb(ioaddr + RTC_MINUTES);
+ hour = readb(ioaddr + RTC_HOURS);
+ day = readb(ioaddr + RTC_DATE);
+ week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+ month = readb(ioaddr + RTC_MONTH);
+ year = readb(ioaddr + RTC_YEAR);
+ century = readb(ioaddr + RTC_CENTURY);
+ writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
+ tm->tm_sec = BCD2BIN(second);
+ tm->tm_min = BCD2BIN(minute);
+ tm->tm_hour = BCD2BIN(hour);
+ tm->tm_mday = BCD2BIN(day);
+ tm->tm_wday = BCD2BIN(week);
+ tm->tm_mon = BCD2BIN(month) - 1;
+ /* year is 1900 + tm->tm_year */
+ tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, tm);
+ }
+ return 0;
+}
+
+static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long irqflags;
+ u8 flags;
+
+ spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags);
+
+ flags = readb(ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+
+ writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_mday),
+ ioaddr + RTC_DATE_ALARM);
+ writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_hour),
+ ioaddr + RTC_HOURS_ALARM);
+ writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_min),
+ ioaddr + RTC_MINUTES_ALARM);
+ writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_sec),
+ ioaddr + RTC_SECONDS_ALARM);
+ writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
+ readb(ioaddr + RTC_FLAGS); /* clear interrupts */
+ writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+ spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags);
+}
+
+static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ pdata->alrm_mday = alrm->time.tm_mday;
+ pdata->alrm_hour = alrm->time.tm_hour;
+ pdata->alrm_min = alrm->time.tm_min;
+ pdata->alrm_sec = alrm->time.tm_sec;
+ if (alrm->enabled)
+ pdata->irqen |= RTC_AF;
+ stk17ta8_rtc_update_alarm(pdata);
+ return 0;
+}
+
+static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+ alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+ alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+ alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+ alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+ return 0;
+}
+
+static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long events = RTC_IRQF;
+
+ /* read and clear interrupt */
+ if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+ return IRQ_NONE;
+ if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+ events |= RTC_UF;
+ else
+ events |= RTC_AF;
+ rtc_update_irq(pdata->rtc, 1, events);
+ return IRQ_HANDLED;
+}
+
+static void stk17ta8_rtc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq >= 0) {
+ pdata->irqen = 0;
+ stk17ta8_rtc_update_alarm(pdata);
+ }
+}
+
+static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ pdata->irqen &= ~RTC_AF;
+ stk17ta8_rtc_update_alarm(pdata);
+ break;
+ case RTC_AIE_ON:
+ pdata->irqen |= RTC_AF;
+ stk17ta8_rtc_update_alarm(pdata);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops stk17ta8_rtc_ops = {
+ .read_time = stk17ta8_rtc_read_time,
+ .set_time = stk17ta8_rtc_set_time,
+ .read_alarm = stk17ta8_rtc_read_alarm,
+ .set_alarm = stk17ta8_rtc_set_alarm,
+ .release = stk17ta8_rtc_release,
+ .ioctl = stk17ta8_rtc_ioctl,
+};
+
+static ssize_t stk17ta8_nvram_read(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ *buf++ = readb(ioaddr + pos++);
+ return count;
+}
+
+static ssize_t stk17ta8_nvram_write(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ writeb(*buf++, ioaddr + pos++);
+ return count;
+}
+
+static struct bin_attribute stk17ta8_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = RTC_OFFSET,
+ .read = stk17ta8_nvram_read,
+ .write = stk17ta8_nvram_write,
+};
+
+static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ unsigned int cal;
+ unsigned int flags;
+ struct rtc_plat_data *pdata;
+ void __iomem *ioaddr = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ pdata->irq = -1;
+ if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+ if (!ioaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ioaddr;
+ pdata->irq = platform_get_irq(pdev, 0);
+
+ /* turn RTC on if it was not on */
+ cal = readb(ioaddr + RTC_CALIBRATION);
+ if (cal & RTC_STOP) {
+ cal &= RTC_CAL_MASK;
+ flags = readb(ioaddr + RTC_FLAGS);
+ writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+ writeb(cal, ioaddr + RTC_CALIBRATION);
+ writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+ }
+ if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+ if (pdata->irq >= 0) {
+ writeb(0, ioaddr + RTC_INTERRUPTS);
+ if (request_irq(pdata->irq, stk17ta8_rtc_interrupt,
+ IRQF_DISABLED | IRQF_SHARED,
+ pdev->name, pdev) < 0) {
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &stk17ta8_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+ if (ret)
+ goto out;
+ return 0;
+ out:
+ if (pdata->rtc)
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ if (ioaddr)
+ iounmap(ioaddr);
+ if (pdata->baseaddr)
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0) {
+ writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+ free_irq(pdata->irq, pdev);
+ }
+ iounmap(pdata->ioaddr);
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver stk17ta8_rtc_driver = {
+ .probe = stk17ta8_rtc_probe,
+ .remove = __devexit_p(stk17ta8_rtc_remove),
+ .driver = {
+ .name = "stk17ta8",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int stk17ta8_init(void)
+{
+ return platform_driver_register(&stk17ta8_rtc_driver);
+}
+
+static __exit void stk17ta8_exit(void)
+{
+ return platform_driver_unregister(&stk17ta8_rtc_driver);
+}
+
+module_init(stk17ta8_init);
+module_exit(stk17ta8_exit);
+
+MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>");
+MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index af7596ef29e2..ce2f78de7a80 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -17,10 +17,11 @@
* 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/err.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/irq.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
@@ -30,25 +31,11 @@
#include <asm/div64.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/vr41xx/irq.h>
MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
MODULE_LICENSE("GPL");
-#define RTC1_TYPE1_START 0x0b0000c0UL
-#define RTC1_TYPE1_END 0x0b0000dfUL
-#define RTC2_TYPE1_START 0x0b0001c0UL
-#define RTC2_TYPE1_END 0x0b0001dfUL
-
-#define RTC1_TYPE2_START 0x0f000100UL
-#define RTC1_TYPE2_END 0x0f00011fUL
-#define RTC2_TYPE2_START 0x0f000120UL
-#define RTC2_TYPE2_END 0x0f00013fUL
-
-#define RTC1_SIZE 0x20
-#define RTC2_SIZE 0x20
-
/* RTC 1 registers */
#define ETIMELREG 0x00
#define ETIMEMREG 0x02
@@ -98,13 +85,8 @@ static char rtc_name[] = "RTC";
static unsigned long periodic_frequency;
static unsigned long periodic_count;
static unsigned int alarm_enabled;
-
-struct resource rtc_resource[2] = {
- { .name = rtc_name,
- .flags = IORESOURCE_MEM, },
- { .name = rtc_name,
- .flags = IORESOURCE_MEM, },
-};
+static int aie_irq = -1;
+static int pie_irq = -1;
static inline unsigned long read_elapsed_second(void)
{
@@ -150,8 +132,8 @@ static void vr41xx_rtc_release(struct device *dev)
spin_unlock_irq(&rtc_lock);
- disable_irq(ELAPSEDTIME_IRQ);
- disable_irq(RTCLONG1_IRQ);
+ disable_irq(aie_irq);
+ disable_irq(pie_irq);
}
static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time)
@@ -209,14 +191,14 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
spin_lock_irq(&rtc_lock);
if (alarm_enabled)
- disable_irq(ELAPSEDTIME_IRQ);
+ disable_irq(aie_irq);
rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15));
rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1));
rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17));
if (wkalrm->enabled)
- enable_irq(ELAPSEDTIME_IRQ);
+ enable_irq(aie_irq);
alarm_enabled = wkalrm->enabled;
@@ -234,7 +216,7 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
spin_lock_irq(&rtc_lock);
if (!alarm_enabled) {
- enable_irq(ELAPSEDTIME_IRQ);
+ enable_irq(aie_irq);
alarm_enabled = 1;
}
@@ -244,17 +226,17 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
spin_lock_irq(&rtc_lock);
if (alarm_enabled) {
- disable_irq(ELAPSEDTIME_IRQ);
+ disable_irq(aie_irq);
alarm_enabled = 0;
}
spin_unlock_irq(&rtc_lock);
break;
case RTC_PIE_ON:
- enable_irq(RTCLONG1_IRQ);
+ enable_irq(pie_irq);
break;
case RTC_PIE_OFF:
- disable_irq(RTCLONG1_IRQ);
+ disable_irq(pie_irq);
break;
case RTC_IRQP_READ:
return put_user(periodic_frequency, (unsigned long __user *)arg);
@@ -331,31 +313,37 @@ static const struct rtc_class_ops vr41xx_rtc_ops = {
static int __devinit rtc_probe(struct platform_device *pdev)
{
+ struct resource *res;
struct rtc_device *rtc;
- unsigned int irq;
int retval;
- if (pdev->num_resources != 2)
+ if (pdev->num_resources != 4)
return -EBUSY;
- rtc1_base = ioremap(pdev->resource[0].start, RTC1_SIZE);
- if (rtc1_base == NULL)
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
return -EBUSY;
- rtc2_base = ioremap(pdev->resource[1].start, RTC2_SIZE);
- if (rtc2_base == NULL) {
- iounmap(rtc1_base);
- rtc1_base = NULL;
+ rtc1_base = ioremap(res->start, res->end - res->start + 1);
+ if (!rtc1_base)
return -EBUSY;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ retval = -EBUSY;
+ goto err_rtc1_iounmap;
+ }
+
+ rtc2_base = ioremap(res->start, res->end - res->start + 1);
+ if (!rtc2_base) {
+ retval = -EBUSY;
+ goto err_rtc1_iounmap;
}
rtc = rtc_device_register(rtc_name, &pdev->dev, &vr41xx_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
- iounmap(rtc1_base);
- iounmap(rtc2_base);
- rtc1_base = NULL;
- rtc2_base = NULL;
- return PTR_ERR(rtc);
+ retval = PTR_ERR(rtc);
+ goto err_iounmap_all;
}
spin_lock_irq(&rtc_lock);
@@ -368,35 +356,50 @@ static int __devinit rtc_probe(struct platform_device *pdev)
spin_unlock_irq(&rtc_lock);
- irq = ELAPSEDTIME_IRQ;
- retval = request_irq(irq, elapsedtime_interrupt, IRQF_DISABLED,
- "elapsed_time", pdev);
- if (retval == 0) {
- irq = RTCLONG1_IRQ;
- retval = request_irq(irq, rtclong1_interrupt, IRQF_DISABLED,
- "rtclong1", pdev);
+ aie_irq = platform_get_irq(pdev, 0);
+ if (aie_irq < 0 || aie_irq >= NR_IRQS) {
+ retval = -EBUSY;
+ goto err_device_unregister;
}
- if (retval < 0) {
- printk(KERN_ERR "rtc: IRQ%d is busy\n", irq);
- rtc_device_unregister(rtc);
- if (irq == RTCLONG1_IRQ)
- free_irq(ELAPSEDTIME_IRQ, NULL);
- iounmap(rtc1_base);
- iounmap(rtc2_base);
- rtc1_base = NULL;
- rtc2_base = NULL;
- return retval;
- }
+ retval = request_irq(aie_irq, elapsedtime_interrupt, IRQF_DISABLED,
+ "elapsed_time", pdev);
+ if (retval < 0)
+ goto err_device_unregister;
+
+ pie_irq = platform_get_irq(pdev, 1);
+ if (pie_irq < 0 || pie_irq >= NR_IRQS)
+ goto err_free_irq;
+
+ retval = request_irq(pie_irq, rtclong1_interrupt, IRQF_DISABLED,
+ "rtclong1", pdev);
+ if (retval < 0)
+ goto err_free_irq;
platform_set_drvdata(pdev, rtc);
- disable_irq(ELAPSEDTIME_IRQ);
- disable_irq(RTCLONG1_IRQ);
+ disable_irq(aie_irq);
+ disable_irq(pie_irq);
printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n");
return 0;
+
+err_free_irq:
+ free_irq(aie_irq, pdev);
+
+err_device_unregister:
+ rtc_device_unregister(rtc);
+
+err_iounmap_all:
+ iounmap(rtc2_base);
+ rtc2_base = NULL;
+
+err_rtc1_iounmap:
+ iounmap(rtc1_base);
+ rtc1_base = NULL;
+
+ return retval;
}
static int __devexit rtc_remove(struct platform_device *pdev)
@@ -404,23 +407,21 @@ static int __devexit rtc_remove(struct platform_device *pdev)
struct rtc_device *rtc;
rtc = platform_get_drvdata(pdev);
- if (rtc != NULL)
+ if (rtc)
rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
- free_irq(ELAPSEDTIME_IRQ, NULL);
- free_irq(RTCLONG1_IRQ, NULL);
- if (rtc1_base != NULL)
+ free_irq(aie_irq, pdev);
+ free_irq(pie_irq, pdev);
+ if (rtc1_base)
iounmap(rtc1_base);
- if (rtc2_base != NULL)
+ if (rtc2_base)
iounmap(rtc2_base);
return 0;
}
-static struct platform_device *rtc_platform_device;
-
static struct platform_driver rtc_platform_driver = {
.probe = rtc_probe,
.remove = __devexit_p(rtc_remove),
@@ -432,55 +433,12 @@ static struct platform_driver rtc_platform_driver = {
static int __init vr41xx_rtc_init(void)
{
- int retval;
-
- switch (current_cpu_data.cputype) {
- case CPU_VR4111:
- case CPU_VR4121:
- rtc_resource[0].start = RTC1_TYPE1_START;
- rtc_resource[0].end = RTC1_TYPE1_END;
- rtc_resource[1].start = RTC2_TYPE1_START;
- rtc_resource[1].end = RTC2_TYPE1_END;
- break;
- case CPU_VR4122:
- case CPU_VR4131:
- case CPU_VR4133:
- rtc_resource[0].start = RTC1_TYPE2_START;
- rtc_resource[0].end = RTC1_TYPE2_END;
- rtc_resource[1].start = RTC2_TYPE2_START;
- rtc_resource[1].end = RTC2_TYPE2_END;
- break;
- default:
- return -ENODEV;
- break;
- }
-
- rtc_platform_device = platform_device_alloc("RTC", -1);
- if (rtc_platform_device == NULL)
- return -ENOMEM;
-
- retval = platform_device_add_resources(rtc_platform_device,
- rtc_resource, ARRAY_SIZE(rtc_resource));
-
- if (retval == 0)
- retval = platform_device_add(rtc_platform_device);
-
- if (retval < 0) {
- platform_device_put(rtc_platform_device);
- return retval;
- }
-
- retval = platform_driver_register(&rtc_platform_driver);
- if (retval < 0)
- platform_device_unregister(rtc_platform_device);
-
- return retval;
+ return platform_driver_register(&rtc_platform_driver);
}
static void __exit vr41xx_rtc_exit(void)
{
platform_driver_unregister(&rtc_platform_driver);
- platform_device_unregister(rtc_platform_device);
}
module_init(vr41xx_rtc_init);
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 513d1a611aab..b3fae357ca49 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -9,6 +9,9 @@
*
* based on a lot of other RTC drivers.
*
+ * Information and datasheet:
+ * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
+ *
* 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.
@@ -26,7 +29,7 @@
* 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 explicitely set the probe parameter.
+ * unknown chips, the user must explicitly set the probe parameter.
*/
static unsigned short normal_i2c[] = { I2C_CLIENT_END };
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 6a89cefe99bb..0c67258fb9ec 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -291,7 +291,7 @@ dasd_parse_keyword( char *parsestring ) {
dasd_page_cache =
kmem_cache_create("dasd_page_cache", PAGE_SIZE,
PAGE_SIZE, SLAB_CACHE_DMA,
- NULL, NULL );
+ NULL);
if (!dasd_page_cache)
MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
"fixed buffer mode disabled.");
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 1340451ea408..35765f6a86e0 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -747,14 +747,9 @@ dcssblk_check_params(void)
static void __exit
dcssblk_exit(void)
{
- int rc;
-
PRINT_DEBUG("DCSSBLOCK EXIT...\n");
s390_root_dev_unregister(dcssblk_root_dev);
- rc = unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
- if (rc) {
- PRINT_ERR("unregister_blkdev() failed!\n");
- }
+ unregister_blkdev(dcssblk_major, DCSSBLK_NAME);
PRINT_DEBUG("...finished!\n");
}
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 66102a184322..3f36cb3910ee 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -164,3 +164,10 @@ config MONWRITER
help
Character device driver for writing z/VM monitor service records
+config S390_VMUR
+ tristate "z/VM unit record device driver"
+ depends on S390
+ default "m"
+ help
+ Character device driver for z/VM reader, puncher and printer.
+
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index c210784bdf46..130de19916f2 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
obj-$(CONFIG_MONREADER) += monreader.o
obj-$(CONFIG_MONWRITER) += monwriter.o
+obj-$(CONFIG_S390_VMUR) += vmur.o
zcore_mod-objs := sclp_sdias.o zcore.o
obj-$(CONFIG_ZFCPDUMP) += zcore_mod.o
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index e765875e8db2..80e7a537e7d2 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -131,10 +131,9 @@ tape_34xx_schedule_work(struct tape_device *device, enum tape_op op)
{
struct tape_34xx_work *p;
- if ((p = kmalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
+ if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
return -ENOMEM;
- memset(p, 0, sizeof(*p));
INIT_WORK(&p->work, tape_34xx_work_handler);
p->device = tape_get_device_reference(device);
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 82e6a6b253eb..2f419b0ea628 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2004,2005 IBM Corporation
+ * Copyright IBM Corp. 2004,2007
* Interface implementation for communication with the z/VM control program
- * Author(s): Christian Borntraeger <cborntra@de.ibm.com>
+ * Author(s): Christian Borntraeger <borntraeger@de.ibm.com>
*
*
* z/VMs CP offers the possibility to issue commands via the diagnose code 8
@@ -22,9 +22,11 @@
#include "vmcp.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>");
+MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>");
MODULE_DESCRIPTION("z/VM CP interface");
+#define PRINTK_HEADER "vmcp: "
+
static debug_info_t *vmcp_debug;
static int vmcp_open(struct inode *inode, struct file *file)
@@ -40,7 +42,7 @@ static int vmcp_open(struct inode *inode, struct file *file)
session->bufsize = PAGE_SIZE;
session->response = NULL;
session->resp_size = 0;
- init_MUTEX(&session->mutex);
+ mutex_init(&session->mutex);
file->private_data = session;
return nonseekable_open(inode, file);
}
@@ -57,37 +59,37 @@ static int vmcp_release(struct inode *inode, struct file *file)
}
static ssize_t
-vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos)
+vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos)
{
size_t tocopy;
struct vmcp_session *session;
session = (struct vmcp_session *)file->private_data;
- if (down_interruptible(&session->mutex))
+ if (mutex_lock_interruptible(&session->mutex))
return -ERESTARTSYS;
if (!session->response) {
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
return 0;
}
if (*ppos > session->resp_size) {
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
return 0;
}
tocopy = min(session->resp_size - (size_t) (*ppos), count);
- tocopy = min(tocopy,session->bufsize - (size_t) (*ppos));
+ tocopy = min(tocopy, session->bufsize - (size_t) (*ppos));
if (copy_to_user(buff, session->response + (*ppos), tocopy)) {
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
return -EFAULT;
}
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
*ppos += tocopy;
return tocopy;
}
static ssize_t
-vmcp_write(struct file *file, const char __user * buff, size_t count,
- loff_t * ppos)
+vmcp_write(struct file *file, const char __user *buff, size_t count,
+ loff_t *ppos)
{
char *cmd;
struct vmcp_session *session;
@@ -103,24 +105,23 @@ vmcp_write(struct file *file, const char __user * buff, size_t count,
}
cmd[count] = '\0';
session = (struct vmcp_session *)file->private_data;
- if (down_interruptible(&session->mutex)) {
+ if (mutex_lock_interruptible(&session->mutex)) {
kfree(cmd);
return -ERESTARTSYS;
}
if (!session->response)
session->response = (char *)__get_free_pages(GFP_KERNEL
- | __GFP_REPEAT | GFP_DMA,
+ | __GFP_REPEAT | GFP_DMA,
get_order(session->bufsize));
if (!session->response) {
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
kfree(cmd);
return -ENOMEM;
}
debug_text_event(vmcp_debug, 1, cmd);
- session->resp_size = cpcmd(cmd, session->response,
- session->bufsize,
- &session->resp_code);
- up(&session->mutex);
+ session->resp_size = cpcmd(cmd, session->response, session->bufsize,
+ &session->resp_code);
+ mutex_unlock(&session->mutex);
kfree(cmd);
*ppos = 0; /* reset the file pointer after a command */
return count;
@@ -145,12 +146,12 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int temp;
session = (struct vmcp_session *)file->private_data;
- if (down_interruptible(&session->mutex))
+ if (mutex_lock_interruptible(&session->mutex))
return -ERESTARTSYS;
switch (cmd) {
case VMCP_GETCODE:
temp = session->resp_code;
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
return put_user(temp, (int __user *)arg);
case VMCP_SETBUF:
free_pages((unsigned long)session->response,
@@ -161,14 +162,14 @@ static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
session->bufsize = PAGE_SIZE;
temp = -EINVAL;
}
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
return temp;
case VMCP_GETSIZE:
temp = session->resp_size;
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
return put_user(temp, (int __user *)arg);
default:
- up(&session->mutex);
+ mutex_unlock(&session->mutex);
return -ENOIOCTLCMD;
}
}
@@ -180,7 +181,7 @@ static const struct file_operations vmcp_fops = {
.read = vmcp_read,
.write = vmcp_write,
.unlocked_ioctl = vmcp_ioctl,
- .compat_ioctl = vmcp_ioctl
+ .compat_ioctl = vmcp_ioctl,
};
static struct miscdevice vmcp_dev = {
@@ -194,26 +195,38 @@ static int __init vmcp_init(void)
int ret;
if (!MACHINE_IS_VM) {
- printk(KERN_WARNING
- "z/VM CP interface is only available under z/VM\n");
+ PRINT_WARN("z/VM CP interface is only available under z/VM\n");
return -ENODEV;
}
- ret = misc_register(&vmcp_dev);
- if (!ret)
- printk(KERN_INFO "z/VM CP interface loaded\n");
- else
- printk(KERN_WARNING
- "z/VM CP interface not loaded. Could not register misc device.\n");
vmcp_debug = debug_register("vmcp", 1, 1, 240);
- debug_register_view(vmcp_debug, &debug_hex_ascii_view);
- return ret;
+ if (!vmcp_debug) {
+ PRINT_ERR("z/VM CP interface not loaded. Could not register "
+ "debug feature\n");
+ return -ENOMEM;
+ }
+ ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view);
+ if (ret) {
+ PRINT_ERR("z/VM CP interface not loaded. Could not register "
+ "debug feature view. Error code: %d\n", ret);
+ debug_unregister(vmcp_debug);
+ return ret;
+ }
+ ret = misc_register(&vmcp_dev);
+ if (ret) {
+ PRINT_ERR("z/VM CP interface not loaded. Could not register "
+ "misc device. Error code: %d\n", ret);
+ debug_unregister(vmcp_debug);
+ return ret;
+ }
+ PRINT_INFO("z/VM CP interface loaded\n");
+ return 0;
}
static void __exit vmcp_exit(void)
{
- WARN_ON(misc_deregister(&vmcp_dev) != 0);
+ misc_deregister(&vmcp_dev);
debug_unregister(vmcp_debug);
- printk(KERN_INFO "z/VM CP interface unloaded.\n");
+ PRINT_INFO("z/VM CP interface unloaded.\n");
}
module_init(vmcp_init);
diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h
index 8a5975f3dad7..6a993948e188 100644
--- a/drivers/s390/char/vmcp.h
+++ b/drivers/s390/char/vmcp.h
@@ -12,8 +12,8 @@
* The idea of this driver is based on cpint from Neale Ferguson
*/
-#include <asm/semaphore.h>
#include <linux/ioctl.h>
+#include <linux/mutex.h>
#define VMCP_GETCODE _IOR(0x10, 1, int)
#define VMCP_SETBUF _IOW(0x10, 2, int)
@@ -26,5 +26,5 @@ struct vmcp_session {
int resp_code;
/* As we use copy_from/to_user, which might *
* sleep and cannot use a spinlock */
- struct semaphore mutex;
+ struct mutex mutex;
};
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
new file mode 100644
index 000000000000..e90b0f846195
--- /dev/null
+++ b/drivers/s390/char/vmur.c
@@ -0,0 +1,906 @@
+/*
+ * Linux driver for System z and s390 unit record devices
+ * (z/VM virtual punch, reader, printer)
+ *
+ * Copyright IBM Corp. 2001, 2007
+ * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
+ * Michael Holzheu <holzheu@de.ibm.com>
+ * Frank Munzert <munzert@de.ibm.com>
+ */
+
+#include <linux/cdev.h>
+
+#include <asm/uaccess.h>
+#include <asm/cio.h>
+#include <asm/ccwdev.h>
+#include <asm/debug.h>
+
+#include "vmur.h"
+
+/*
+ * Driver overview
+ *
+ * Unit record device support is implemented as a character device driver.
+ * We can fit at least 16 bits into a device minor number and use the
+ * simple method of mapping a character device number with minor abcd
+ * to the unit record device with devno abcd.
+ * I/O to virtual unit record devices is handled as follows:
+ * Reads: Diagnose code 0x14 (input spool file manipulation)
+ * is used to read spool data page-wise.
+ * Writes: The CCW used is WRITE_CCW_CMD (0x01). The device's record length
+ * is available by reading sysfs attr reclen. Each write() to the device
+ * must specify an integral multiple (maximal 511) of reclen.
+ */
+
+static char ur_banner[] = "z/VM virtual unit record device driver";
+
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("s390 z/VM virtual unit record device driver");
+MODULE_LICENSE("GPL");
+
+#define PRINTK_HEADER "vmur: "
+
+static dev_t ur_first_dev_maj_min;
+static struct class *vmur_class;
+static struct debug_info *vmur_dbf;
+
+/* We put the device's record length (for writes) in the driver_info field */
+static struct ccw_device_id ur_ids[] = {
+ { CCWDEV_CU_DI(READER_PUNCH_DEVTYPE, 80) },
+ { CCWDEV_CU_DI(PRINTER_DEVTYPE, 132) },
+ { /* end of list */ }
+};
+
+MODULE_DEVICE_TABLE(ccw, ur_ids);
+
+static int ur_probe(struct ccw_device *cdev);
+static void ur_remove(struct ccw_device *cdev);
+static int ur_set_online(struct ccw_device *cdev);
+static int ur_set_offline(struct ccw_device *cdev);
+
+static struct ccw_driver ur_driver = {
+ .name = "vmur",
+ .owner = THIS_MODULE,
+ .ids = ur_ids,
+ .probe = ur_probe,
+ .remove = ur_remove,
+ .set_online = ur_set_online,
+ .set_offline = ur_set_offline,
+};
+
+/*
+ * Allocation, freeing, getting and putting of urdev structures
+ */
+static struct urdev *urdev_alloc(struct ccw_device *cdev)
+{
+ struct urdev *urd;
+
+ urd = kzalloc(sizeof(struct urdev), GFP_KERNEL);
+ if (!urd)
+ return NULL;
+ urd->cdev = cdev;
+ urd->reclen = cdev->id.driver_info;
+ ccw_device_get_id(cdev, &urd->dev_id);
+ mutex_init(&urd->io_mutex);
+ mutex_init(&urd->open_mutex);
+ return urd;
+}
+
+static void urdev_free(struct urdev *urd)
+{
+ kfree(urd);
+}
+
+/*
+ * This is how the character device driver gets a reference to a
+ * ur device. When this call returns successfully, a reference has
+ * been taken (by get_device) on the underlying kobject. The recipient
+ * of this urdev pointer must eventually drop it with urdev_put(urd)
+ * which does the corresponding put_device().
+ */
+static struct urdev *urdev_get_from_devno(u16 devno)
+{
+ char bus_id[16];
+ struct ccw_device *cdev;
+
+ sprintf(bus_id, "0.0.%04x", devno);
+ cdev = get_ccwdev_by_busid(&ur_driver, bus_id);
+ if (!cdev)
+ return NULL;
+
+ return cdev->dev.driver_data;
+}
+
+static void urdev_put(struct urdev *urd)
+{
+ put_device(&urd->cdev->dev);
+}
+
+/*
+ * Low-level functions to do I/O to a ur device.
+ * alloc_chan_prog
+ * do_ur_io
+ * ur_int_handler
+ *
+ * alloc_chan_prog allocates and builds the channel program
+ *
+ * do_ur_io issues the channel program to the device and blocks waiting
+ * on a completion event it publishes at urd->io_done. The function
+ * serialises itself on the device's mutex so that only one I/O
+ * is issued at a time (and that I/O is synchronous).
+ *
+ * ur_int_handler catches the "I/O done" interrupt, writes the
+ * subchannel status word into the scsw member of the urdev structure
+ * and complete()s the io_done to wake the waiting do_ur_io.
+ *
+ * The caller of do_ur_io is responsible for kfree()ing the channel program
+ * address pointer that alloc_chan_prog returned.
+ */
+
+
+/*
+ * alloc_chan_prog
+ * The channel program we use is write commands chained together
+ * with a final NOP CCW command-chained on (which ensures that CE and DE
+ * are presented together in a single interrupt instead of as separate
+ * interrupts unless an incorrect length indication kicks in first). The
+ * data length in each CCW is reclen. The caller must ensure that count
+ * is an integral multiple of reclen.
+ * The channel program pointer returned by this function must be freed
+ * with kfree. The caller is responsible for checking that
+ * count/reclen is not ridiculously large.
+ */
+static struct ccw1 *alloc_chan_prog(char *buf, size_t count, size_t reclen)
+{
+ size_t num_ccws;
+ struct ccw1 *cpa;
+ int i;
+
+ TRACE("alloc_chan_prog(%p, %zu, %zu)\n", buf, count, reclen);
+
+ /*
+ * We chain a NOP onto the writes to force CE+DE together.
+ * That means we allocate room for CCWs to cover count/reclen
+ * records plus a NOP.
+ */
+ num_ccws = count / reclen + 1;
+ cpa = kmalloc(num_ccws * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+ if (!cpa)
+ return NULL;
+
+ for (i = 0; count; i++) {
+ cpa[i].cmd_code = WRITE_CCW_CMD;
+ cpa[i].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
+ cpa[i].count = reclen;
+ cpa[i].cda = __pa(buf);
+ buf += reclen;
+ count -= reclen;
+ }
+ /* The following NOP CCW forces CE+DE to be presented together */
+ cpa[i].cmd_code = CCW_CMD_NOOP;
+ cpa[i].flags = 0;
+ cpa[i].count = 0;
+ cpa[i].cda = 0;
+
+ return cpa;
+}
+
+static int do_ur_io(struct urdev *urd, struct ccw1 *cpa)
+{
+ int rc;
+ struct ccw_device *cdev = urd->cdev;
+ DECLARE_COMPLETION(event);
+
+ TRACE("do_ur_io: cpa=%p\n", cpa);
+
+ rc = mutex_lock_interruptible(&urd->io_mutex);
+ if (rc)
+ return rc;
+
+ urd->io_done = &event;
+
+ spin_lock_irq(get_ccwdev_lock(cdev));
+ rc = ccw_device_start(cdev, cpa, 1, 0, 0);
+ spin_unlock_irq(get_ccwdev_lock(cdev));
+
+ TRACE("do_ur_io: ccw_device_start returned %d\n", rc);
+ if (rc)
+ goto out;
+
+ wait_for_completion(&event);
+ TRACE("do_ur_io: I/O complete\n");
+ rc = 0;
+
+out:
+ mutex_unlock(&urd->io_mutex);
+ return rc;
+}
+
+/*
+ * ur interrupt handler, called from the ccw_device layer
+ */
+static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm,
+ struct irb *irb)
+{
+ struct urdev *urd;
+
+ TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n",
+ intparm, irb->scsw.cstat, irb->scsw.dstat, irb->scsw.count);
+
+ if (!intparm) {
+ TRACE("ur_int_handler: unsolicited interrupt\n");
+ return;
+ }
+ urd = cdev->dev.driver_data;
+ /* On special conditions irb is an error pointer */
+ if (IS_ERR(irb))
+ urd->io_request_rc = PTR_ERR(irb);
+ else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+ urd->io_request_rc = 0;
+ else
+ urd->io_request_rc = -EIO;
+
+ complete(urd->io_done);
+}
+
+/*
+ * reclen sysfs attribute - The record length to be used for write CCWs
+ */
+static ssize_t ur_attr_reclen_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct urdev *urd = dev->driver_data;
+
+ return sprintf(buf, "%zu\n", urd->reclen);
+}
+
+static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL);
+
+static int ur_create_attributes(struct device *dev)
+{
+ return device_create_file(dev, &dev_attr_reclen);
+}
+
+static void ur_remove_attributes(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_reclen);
+}
+
+/*
+ * diagnose code 0x210 - retrieve device information
+ * cc=0 normal completion, we have a real device
+ * cc=1 CP paging error
+ * cc=2 The virtual device exists, but is not associated with a real device
+ * cc=3 Invalid device address, or the virtual device does not exist
+ */
+static int get_urd_class(struct urdev *urd)
+{
+ static struct diag210 ur_diag210;
+ int cc;
+
+ ur_diag210.vrdcdvno = urd->dev_id.devno;
+ ur_diag210.vrdclen = sizeof(struct diag210);
+
+ cc = diag210(&ur_diag210);
+ switch (cc) {
+ case 0:
+ return -ENOTSUPP;
+ case 2:
+ return ur_diag210.vrdcvcla; /* virtual device class */
+ case 3:
+ return -ENODEV;
+ default:
+ return -EIO;
+ }
+}
+
+/*
+ * Allocation and freeing of urfile structures
+ */
+static struct urfile *urfile_alloc(struct urdev *urd)
+{
+ struct urfile *urf;
+
+ urf = kzalloc(sizeof(struct urfile), GFP_KERNEL);
+ if (!urf)
+ return NULL;
+ urf->urd = urd;
+
+ TRACE("urfile_alloc: urd=%p urf=%p rl=%zu\n", urd, urf,
+ urf->dev_reclen);
+
+ return urf;
+}
+
+static void urfile_free(struct urfile *urf)
+{
+ TRACE("urfile_free: urf=%p urd=%p\n", urf, urf->urd);
+ kfree(urf);
+}
+
+/*
+ * The fops implementation of the character device driver
+ */
+static ssize_t do_write(struct urdev *urd, const char __user *udata,
+ size_t count, size_t reclen, loff_t *ppos)
+{
+ struct ccw1 *cpa;
+ char *buf;
+ int rc;
+
+ /* Data buffer must be under 2GB line for fmt1 CCWs: hence GFP_DMA */
+ buf = kmalloc(count, GFP_KERNEL | GFP_DMA);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, udata, count)) {
+ rc = -EFAULT;
+ goto fail_kfree_buf;
+ }
+
+ cpa = alloc_chan_prog(buf, count, reclen);
+ if (!cpa) {
+ rc = -ENOMEM;
+ goto fail_kfree_buf;
+ }
+
+ rc = do_ur_io(urd, cpa);
+ if (rc)
+ goto fail_kfree_cpa;
+
+ if (urd->io_request_rc) {
+ rc = urd->io_request_rc;
+ goto fail_kfree_cpa;
+ }
+ *ppos += count;
+ rc = count;
+fail_kfree_cpa:
+ kfree(cpa);
+fail_kfree_buf:
+ kfree(buf);
+ return rc;
+}
+
+static ssize_t ur_write(struct file *file, const char __user *udata,
+ size_t count, loff_t *ppos)
+{
+ struct urfile *urf = file->private_data;
+
+ TRACE("ur_write: count=%zu\n", count);
+
+ if (count == 0)
+ return 0;
+
+ if (count % urf->dev_reclen)
+ return -EINVAL; /* count must be a multiple of reclen */
+
+ if (count > urf->dev_reclen * MAX_RECS_PER_IO)
+ count = urf->dev_reclen * MAX_RECS_PER_IO;
+
+ return do_write(urf->urd, udata, count, urf->dev_reclen, ppos);
+}
+
+static int do_diag_14(unsigned long rx, unsigned long ry1,
+ unsigned long subcode)
+{
+ register unsigned long _ry1 asm("2") = ry1;
+ register unsigned long _ry2 asm("3") = subcode;
+ int rc = 0;
+
+ asm volatile(
+#ifdef CONFIG_64BIT
+ " sam31\n"
+ " diag %2,2,0x14\n"
+ " sam64\n"
+#else
+ " diag %2,2,0x14\n"
+#endif
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (rc), "+d" (_ry2)
+ : "d" (rx), "d" (_ry1)
+ : "cc");
+
+ TRACE("diag 14: subcode=0x%lx, cc=%i\n", subcode, rc);
+ return rc;
+}
+
+/*
+ * diagnose code 0x14 subcode 0x0028 - position spool file to designated
+ * record
+ * cc=0 normal completion
+ * cc=2 no file active on the virtual reader or device not ready
+ * cc=3 record specified is beyond EOF
+ */
+static int diag_position_to_record(int devno, int record)
+{
+ int cc;
+
+ cc = do_diag_14(record, devno, 0x28);
+ switch (cc) {
+ case 0:
+ return 0;
+ case 2:
+ return -ENOMEDIUM;
+ case 3:
+ return -ENODATA; /* position beyond end of file */
+ default:
+ return -EIO;
+ }
+}
+
+/*
+ * diagnose code 0x14 subcode 0x0000 - read next spool file buffer
+ * cc=0 normal completion
+ * cc=1 EOF reached
+ * cc=2 no file active on the virtual reader, and no file eligible
+ * cc=3 file already active on the virtual reader or specified virtual
+ * reader does not exist or is not a reader
+ */
+static int diag_read_file(int devno, char *buf)
+{
+ int cc;
+
+ cc = do_diag_14((unsigned long) buf, devno, 0x00);
+ switch (cc) {
+ case 0:
+ return 0;
+ case 1:
+ return -ENODATA;
+ case 2:
+ return -ENOMEDIUM;
+ default:
+ return -EIO;
+ }
+}
+
+static ssize_t diag14_read(struct file *file, char __user *ubuf, size_t count,
+ loff_t *offs)
+{
+ size_t len, copied, res;
+ char *buf;
+ int rc;
+ u16 reclen;
+ struct urdev *urd;
+
+ urd = ((struct urfile *) file->private_data)->urd;
+ reclen = ((struct urfile *) file->private_data)->file_reclen;
+
+ rc = diag_position_to_record(urd->dev_id.devno, *offs / PAGE_SIZE + 1);
+ if (rc == -ENODATA)
+ return 0;
+ if (rc)
+ return rc;
+
+ len = min((size_t) PAGE_SIZE, count);
+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ copied = 0;
+ res = (size_t) (*offs % PAGE_SIZE);
+ do {
+ rc = diag_read_file(urd->dev_id.devno, buf);
+ if (rc == -ENODATA) {
+ break;
+ }
+ if (rc)
+ goto fail;
+ if (reclen)
+ *((u16 *) &buf[FILE_RECLEN_OFFSET]) = reclen;
+ len = min(count - copied, PAGE_SIZE - res);
+ if (copy_to_user(ubuf + copied, buf + res, len)) {
+ rc = -EFAULT;
+ goto fail;
+ }
+ res = 0;
+ copied += len;
+ } while (copied != count);
+
+ *offs += copied;
+ rc = copied;
+fail:
+ kfree(buf);
+ return rc;
+}
+
+static ssize_t ur_read(struct file *file, char __user *ubuf, size_t count,
+ loff_t *offs)
+{
+ struct urdev *urd;
+ int rc;
+
+ TRACE("ur_read: count=%zu ppos=%li\n", count, (unsigned long) *offs);
+
+ if (count == 0)
+ return 0;
+
+ urd = ((struct urfile *) file->private_data)->urd;
+ rc = mutex_lock_interruptible(&urd->io_mutex);
+ if (rc)
+ return rc;
+ rc = diag14_read(file, ubuf, count, offs);
+ mutex_unlock(&urd->io_mutex);
+ return rc;
+}
+
+/*
+ * diagnose code 0x14 subcode 0x0fff - retrieve next file descriptor
+ * cc=0 normal completion
+ * cc=1 no files on reader queue or no subsequent file
+ * cc=2 spid specified is invalid
+ */
+static int diag_read_next_file_info(struct file_control_block *buf, int spid)
+{
+ int cc;
+
+ cc = do_diag_14((unsigned long) buf, spid, 0xfff);
+ switch (cc) {
+ case 0:
+ return 0;
+ default:
+ return -ENODATA;
+ }
+}
+
+static int verify_device(struct urdev *urd)
+{
+ struct file_control_block fcb;
+ char *buf;
+ int rc;
+
+ switch (urd->class) {
+ case DEV_CLASS_UR_O:
+ return 0; /* no check needed here */
+ case DEV_CLASS_UR_I:
+ /* check for empty reader device (beginning of chain) */
+ rc = diag_read_next_file_info(&fcb, 0);
+ if (rc)
+ return rc;
+
+ /* open file on virtual reader */
+ buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ rc = diag_read_file(urd->dev_id.devno, buf);
+ kfree(buf);
+
+ if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
+ return rc;
+ return 0;
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static int get_file_reclen(struct urdev *urd)
+{
+ struct file_control_block fcb;
+ int rc;
+
+ switch (urd->class) {
+ case DEV_CLASS_UR_O:
+ return 0;
+ case DEV_CLASS_UR_I:
+ rc = diag_read_next_file_info(&fcb, 0);
+ if (rc)
+ return rc;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ if (fcb.file_stat & FLG_CP_DUMP)
+ return 0;
+
+ return fcb.rec_len;
+}
+
+static int ur_open(struct inode *inode, struct file *file)
+{
+ u16 devno;
+ struct urdev *urd;
+ struct urfile *urf;
+ unsigned short accmode;
+ int rc;
+
+ accmode = file->f_flags & O_ACCMODE;
+
+ if (accmode == O_RDWR)
+ return -EACCES;
+
+ /*
+ * We treat the minor number as the devno of the ur device
+ * to find in the driver tree.
+ */
+ devno = MINOR(file->f_dentry->d_inode->i_rdev);
+
+ urd = urdev_get_from_devno(devno);
+ if (!urd)
+ return -ENXIO;
+
+ if (file->f_flags & O_NONBLOCK) {
+ if (!mutex_trylock(&urd->open_mutex)) {
+ rc = -EBUSY;
+ goto fail_put;
+ }
+ } else {
+ if (mutex_lock_interruptible(&urd->open_mutex)) {
+ rc = -ERESTARTSYS;
+ goto fail_put;
+ }
+ }
+
+ TRACE("ur_open\n");
+
+ if (((accmode == O_RDONLY) && (urd->class != DEV_CLASS_UR_I)) ||
+ ((accmode == O_WRONLY) && (urd->class != DEV_CLASS_UR_O))) {
+ TRACE("ur_open: unsupported dev class (%d)\n", urd->class);
+ rc = -EACCES;
+ goto fail_unlock;
+ }
+
+ rc = verify_device(urd);
+ if (rc)
+ goto fail_unlock;
+
+ urf = urfile_alloc(urd);
+ if (!urf) {
+ rc = -ENOMEM;
+ goto fail_unlock;
+ }
+
+ urf->dev_reclen = urd->reclen;
+ rc = get_file_reclen(urd);
+ if (rc < 0)
+ goto fail_urfile_free;
+ urf->file_reclen = rc;
+ file->private_data = urf;
+ return 0;
+
+fail_urfile_free:
+ urfile_free(urf);
+fail_unlock:
+ mutex_unlock(&urd->open_mutex);
+fail_put:
+ urdev_put(urd);
+ return rc;
+}
+
+static int ur_release(struct inode *inode, struct file *file)
+{
+ struct urfile *urf = file->private_data;
+
+ TRACE("ur_release\n");
+ mutex_unlock(&urf->urd->open_mutex);
+ urdev_put(urf->urd);
+ urfile_free(urf);
+ return 0;
+}
+
+static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
+{
+ loff_t newpos;
+
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY)
+ return -ESPIPE; /* seek allowed only for reader */
+ if (offset % PAGE_SIZE)
+ return -ESPIPE; /* only multiples of 4K allowed */
+ switch (whence) {
+ case 0: /* SEEK_SET */
+ newpos = offset;
+ break;
+ case 1: /* SEEK_CUR */
+ newpos = file->f_pos + offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+ file->f_pos = newpos;
+ return newpos;
+}
+
+static struct file_operations ur_fops = {
+ .owner = THIS_MODULE,
+ .open = ur_open,
+ .release = ur_release,
+ .read = ur_read,
+ .write = ur_write,
+ .llseek = ur_llseek,
+};
+
+/*
+ * ccw_device infrastructure:
+ * ur_probe gets its own ref to the device (i.e. get_device),
+ * creates the struct urdev, the device attributes, sets up
+ * the interrupt handler and validates the virtual unit record device.
+ * ur_remove removes the device attributes, frees the struct urdev
+ * and drops (put_device) the ref to the device we got in ur_probe.
+ */
+static int ur_probe(struct ccw_device *cdev)
+{
+ struct urdev *urd;
+ int rc;
+
+ TRACE("ur_probe: cdev=%p state=%d\n", cdev, *(int *) cdev->private);
+
+ if (!get_device(&cdev->dev))
+ return -ENODEV;
+
+ urd = urdev_alloc(cdev);
+ if (!urd) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ rc = ur_create_attributes(&cdev->dev);
+ if (rc) {
+ rc = -ENOMEM;
+ goto fail;
+ }
+ cdev->dev.driver_data = urd;
+ cdev->handler = ur_int_handler;
+
+ /* validate virtual unit record device */
+ urd->class = get_urd_class(urd);
+ if (urd->class < 0) {
+ rc = urd->class;
+ goto fail;
+ }
+ if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) {
+ rc = -ENOTSUPP;
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ urdev_free(urd);
+ put_device(&cdev->dev);
+ return rc;
+}
+
+static void ur_remove(struct ccw_device *cdev)
+{
+ struct urdev *urd = cdev->dev.driver_data;
+
+ TRACE("ur_remove\n");
+ if (cdev->online)
+ ur_set_offline(cdev);
+ ur_remove_attributes(&cdev->dev);
+ urdev_free(urd);
+ put_device(&cdev->dev);
+}
+
+static int ur_set_online(struct ccw_device *cdev)
+{
+ struct urdev *urd;
+ int minor, major, rc;
+ char node_id[16];
+
+ TRACE("ur_set_online: cdev=%p state=%d\n", cdev,
+ *(int *) cdev->private);
+
+ if (!try_module_get(ur_driver.owner))
+ return -EINVAL;
+
+ urd = (struct urdev *) cdev->dev.driver_data;
+ minor = urd->dev_id.devno;
+ major = MAJOR(ur_first_dev_maj_min);
+
+ urd->char_device = cdev_alloc();
+ if (!urd->char_device) {
+ rc = -ENOMEM;
+ goto fail_module_put;
+ }
+
+ cdev_init(urd->char_device, &ur_fops);
+ urd->char_device->dev = MKDEV(major, minor);
+ urd->char_device->owner = ur_fops.owner;
+
+ rc = cdev_add(urd->char_device, urd->char_device->dev, 1);
+ if (rc)
+ goto fail_free_cdev;
+ if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) {
+ if (urd->class == DEV_CLASS_UR_I)
+ sprintf(node_id, "vmrdr-%s", cdev->dev.bus_id);
+ if (urd->class == DEV_CLASS_UR_O)
+ sprintf(node_id, "vmpun-%s", cdev->dev.bus_id);
+ } else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) {
+ sprintf(node_id, "vmprt-%s", cdev->dev.bus_id);
+ } else {
+ rc = -ENOTSUPP;
+ goto fail_free_cdev;
+ }
+
+ urd->device = device_create(vmur_class, NULL, urd->char_device->dev,
+ "%s", node_id);
+ if (IS_ERR(urd->device)) {
+ rc = PTR_ERR(urd->device);
+ TRACE("ur_set_online: device_create rc=%d\n", rc);
+ goto fail_free_cdev;
+ }
+
+ return 0;
+
+fail_free_cdev:
+ cdev_del(urd->char_device);
+fail_module_put:
+ module_put(ur_driver.owner);
+
+ return rc;
+}
+
+static int ur_set_offline(struct ccw_device *cdev)
+{
+ struct urdev *urd;
+
+ TRACE("ur_set_offline: cdev=%p cdev->private=%p state=%d\n",
+ cdev, cdev->private, *(int *) cdev->private);
+ urd = (struct urdev *) cdev->dev.driver_data;
+ device_destroy(vmur_class, urd->char_device->dev);
+ cdev_del(urd->char_device);
+ module_put(ur_driver.owner);
+
+ return 0;
+}
+
+/*
+ * Module initialisation and cleanup
+ */
+static int __init ur_init(void)
+{
+ int rc;
+ dev_t dev;
+
+ if (!MACHINE_IS_VM) {
+ PRINT_ERR("%s is only available under z/VM.\n", ur_banner);
+ return -ENODEV;
+ }
+
+ vmur_dbf = debug_register("vmur", 4, 1, 4 * sizeof(long));
+ if (!vmur_dbf)
+ return -ENOMEM;
+ rc = debug_register_view(vmur_dbf, &debug_sprintf_view);
+ if (rc)
+ goto fail_free_dbf;
+
+ debug_set_level(vmur_dbf, 6);
+
+ rc = ccw_driver_register(&ur_driver);
+ if (rc)
+ goto fail_free_dbf;
+
+ rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur");
+ if (rc) {
+ PRINT_ERR("alloc_chrdev_region failed: err = %d\n", rc);
+ goto fail_unregister_driver;
+ }
+ ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0);
+
+ vmur_class = class_create(THIS_MODULE, "vmur");
+ if (IS_ERR(vmur_class)) {
+ rc = PTR_ERR(vmur_class);
+ goto fail_unregister_region;
+ }
+ PRINT_INFO("%s loaded.\n", ur_banner);
+ return 0;
+
+fail_unregister_region:
+ unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);
+fail_unregister_driver:
+ ccw_driver_unregister(&ur_driver);
+fail_free_dbf:
+ debug_unregister(vmur_dbf);
+ return rc;
+}
+
+static void __exit ur_exit(void)
+{
+ class_destroy(vmur_class);
+ unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);
+ ccw_driver_unregister(&ur_driver);
+ debug_unregister(vmur_dbf);
+ PRINT_INFO("%s unloaded.\n", ur_banner);
+}
+
+module_init(ur_init);
+module_exit(ur_exit);
diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h
new file mode 100644
index 000000000000..16d0a4e38e40
--- /dev/null
+++ b/drivers/s390/char/vmur.h
@@ -0,0 +1,104 @@
+/*
+ * Linux driver for System z and s390 unit record devices
+ * (z/VM virtual punch, reader, printer)
+ *
+ * Copyright IBM Corp. 2001, 2007
+ * Authors: Malcolm Beattie <beattiem@uk.ibm.com>
+ * Michael Holzheu <holzheu@de.ibm.com>
+ * Frank Munzert <munzert@de.ibm.com>
+ */
+
+#ifndef _VMUR_H_
+#define _VMUR_H_
+
+#define DEV_CLASS_UR_I 0x20 /* diag210 unit record input device class */
+#define DEV_CLASS_UR_O 0x10 /* diag210 unit record output device class */
+/*
+ * we only support z/VM's default unit record devices:
+ * both in SPOOL directory control statement and in CP DEFINE statement
+ * RDR defaults to 2540 reader
+ * PUN defaults to 2540 punch
+ * PRT defaults to 1403 printer
+ */
+#define READER_PUNCH_DEVTYPE 0x2540
+#define PRINTER_DEVTYPE 0x1403
+
+/* z/VM spool file control block SFBLOK */
+struct file_control_block {
+ char reserved_1[8];
+ char user_owner[8];
+ char user_orig[8];
+ __s32 data_recs;
+ __s16 rec_len;
+ __s16 file_num;
+ __u8 file_stat;
+ __u8 dev_type;
+ char reserved_2[6];
+ char file_name[12];
+ char file_type[12];
+ char create_date[8];
+ char create_time[8];
+ char reserved_3[6];
+ __u8 file_class;
+ __u8 sfb_lok;
+ __u64 distr_code;
+ __u32 reserved_4;
+ __u8 current_starting_copy_number;
+ __u8 sfblock_cntrl_flags;
+ __u8 reserved_5;
+ __u8 more_status_flags;
+ char rest[200];
+} __attribute__ ((packed));
+
+#define FLG_CP_DUMP 0x10
+
+/*
+ * A struct urdev is created for each ur device that is made available
+ * via the ccw_device driver model.
+ */
+struct urdev {
+ struct ccw_device *cdev; /* Backpointer to ccw device */
+ struct mutex io_mutex; /* Serialises device IO */
+ struct mutex open_mutex; /* Serialises access to device */
+ struct completion *io_done; /* do_ur_io waits; irq completes */
+ struct device *device;
+ struct cdev *char_device;
+ struct ccw_dev_id dev_id; /* device id */
+ size_t reclen; /* Record length for *write* CCWs */
+ int class; /* VM device class */
+ int io_request_rc; /* return code from I/O request */
+};
+
+/*
+ * A struct urfile is allocated at open() time for each device and
+ * freed on release().
+ */
+struct urfile {
+ struct urdev *urd;
+ unsigned int flags;
+ size_t dev_reclen;
+ __u16 file_reclen;
+};
+
+/*
+ * Device major/minor definitions.
+ */
+
+#define UR_MAJOR 0 /* get dynamic major */
+/*
+ * We map minor numbers directly to device numbers (0-FFFF) for simplicity.
+ * This avoids having to allocate (and manage) slot numbers.
+ */
+#define NUM_MINORS 65536
+
+/* Limiting each I/O to 511 records limits chan prog to 4KB (511 r/w + 1 NOP) */
+#define MAX_RECS_PER_IO 511
+#define WRITE_CCW_CMD 0x01
+
+#define TRACE(x...) debug_sprintf_event(vmur_dbf, 1, x)
+#define CCWDEV_CU_DI(cutype, di) \
+ CCW_DEVICE(cutype, 0x00), .driver_info = (di)
+
+#define FILE_RECLEN_OFFSET 4064 /* reclen offset in spool data block */
+
+#endif /* _VMUR_H_ */
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index ac289e6eadfe..b57d93d986c0 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -141,8 +141,9 @@ static int s390_vary_chpid(struct chp_id chpid, int on)
/*
* Channel measurement related functions
*/
-static ssize_t chp_measurement_chars_read(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t chp_measurement_chars_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct channel_path *chp;
unsigned int size;
@@ -165,7 +166,6 @@ static struct bin_attribute chp_measurement_chars_attr = {
.attr = {
.name = "measurement_chars",
.mode = S_IRUSR,
- .owner = THIS_MODULE,
},
.size = sizeof(struct cmg_chars),
.read = chp_measurement_chars_read,
@@ -193,8 +193,9 @@ static void chp_measurement_copy_block(struct cmg_entry *buf,
} while (reference_buf.values[0] != buf->values[0]);
}
-static ssize_t chp_measurement_read(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t chp_measurement_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct channel_path *chp;
struct channel_subsystem *css;
@@ -217,7 +218,6 @@ static struct bin_attribute chp_measurement_attr = {
.attr = {
.name = "measurement",
.mode = S_IRUSR,
- .owner = THIS_MODULE,
},
.size = sizeof(struct cmg_entry),
.read = chp_measurement_read,
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 6b264bdb5bfb..001682e70f67 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -272,7 +272,7 @@ modalias_show (struct device *dev, struct device_attribute *attr, char *buf)
struct ccw_device_id *id = &(cdev->id);
int len;
- len = snprint_alias(buf, PAGE_SIZE, id, "\n") + 1;
+ len = snprint_alias(buf, PAGE_SIZE, id, "\n");
return len > PAGE_SIZE ? PAGE_SIZE : len;
}
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index e70aeb7a3781..ed026a1dc324 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -166,9 +166,9 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
{
char dbf_text[15];
- if (ccq == 0 || ccq == 32 || ccq == 96)
+ if (ccq == 0 || ccq == 32)
return 0;
- if (ccq == 97)
+ if (ccq == 96 || ccq == 97)
return 1;
/*notify devices immediately*/
sprintf(dbf_text,"%d", ccq);
@@ -2306,8 +2306,8 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
if (!ssqd_area) {
QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
"SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
- irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
- CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
+ irq_ptr->qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
+ CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
irq_ptr->is_qebsm = 0;
irq_ptr->sch_token = 0;
@@ -2328,8 +2328,8 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \
"SIGAs for sch 0.%x.%x.\n", result,
irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
- qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
- CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
+ qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
+ CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
irq_ptr->is_qebsm = 0;
goto out;
@@ -2340,8 +2340,8 @@ qdio_get_ssqd_information(struct qdio_irq *irq_ptr)
"is 0x%x. Using all SIGAs for sch 0.%x.%x.\n",
ssqd_area->response.code,
irq_ptr->schid.ssid, irq_ptr->schid.sch_no);
- qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY ||
- CHSC_FLAG_SIGA_OUTPUT_NECESSARY ||
+ qdioac = CHSC_FLAG_SIGA_INPUT_NECESSARY |
+ CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
CHSC_FLAG_SIGA_SYNC_NECESSARY; /* all flags set */
irq_ptr->is_qebsm = 0;
goto out;
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 348bb7b82771..023455a0b34a 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -317,8 +317,8 @@ claw_probe(struct ccwgroup_device *cgdev)
CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
return -ENOMEM;
}
- privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
- privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL);
+ privptr->p_mtc_envelope= kzalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
+ privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL);
if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
probe_error(cgdev);
put_device(&cgdev->dev);
@@ -327,8 +327,6 @@ claw_probe(struct ccwgroup_device *cgdev)
CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
return -ENOMEM;
}
- memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE);
- memset(privptr->p_env, 0x00, sizeof(struct claw_env));
memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
@@ -3924,7 +3922,7 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
ccw_device_get_id(cdev, &dev_id);
p_ch->devno = dev_id.devno;
- if ((p_ch->irb = kmalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
+ if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "%s Out of memory in %s for irb\n",
p_ch->id,__FUNCTION__);
#ifdef FUNCTRACE
@@ -3933,7 +3931,6 @@ add_channel(struct ccw_device *cdev,int i,struct claw_privbk *privptr)
#endif
return -ENOMEM;
}
- memset(p_ch->irb, 0, sizeof (struct irb));
#ifdef FUNCTRACE
printk(KERN_INFO "%s:%s Exit on line %d\n",
cdev->dev.bus_id,__FUNCTION__,__LINE__);
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index b34eb82edd98..ec18bae05df0 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -211,6 +211,10 @@ struct qeth_perf_stats {
/* initial values when measuring starts */
unsigned long initial_rx_packets;
unsigned long initial_tx_packets;
+ /* inbound scatter gather data */
+ unsigned int sg_skbs_rx;
+ unsigned int sg_frags_rx;
+ unsigned int sg_alloc_page_rx;
};
/* Routing stuff */
@@ -341,6 +345,9 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
#define QETH_IP_HEADER_SIZE 40
+/* large receive scatter gather copy break */
+#define QETH_RX_SG_CB (PAGE_SIZE >> 1)
+
struct qeth_hdr_layer3 {
__u8 id;
__u8 flags;
@@ -771,6 +778,7 @@ struct qeth_card_options {
int layer2;
enum qeth_large_send_types large_send;
int performance_stats;
+ int rx_sg_cb;
};
/*
@@ -828,6 +836,7 @@ struct qeth_card {
int (*orig_hard_header)(struct sk_buff *,struct net_device *,
unsigned short,void *,void *,unsigned);
struct qeth_osn_info osn_info;
+ atomic_t force_alloc_skb;
};
struct qeth_card_list_struct {
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 86b0c44165c1..57f69434fbf9 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -1054,6 +1054,7 @@ qeth_set_intial_options(struct qeth_card *card)
else
card->options.layer2 = 0;
card->options.performance_stats = 0;
+ card->options.rx_sg_cb = QETH_RX_SG_CB;
}
/**
@@ -1934,6 +1935,7 @@ qeth_send_control_data(struct qeth_card *card, int len,
atomic_inc(&reply->received);
wake_up(&reply->wait_q);
}
+ cpu_relax();
};
rc = reply->rc;
qeth_put_reply(reply);
@@ -2258,6 +2260,89 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
return skb;
}
+static inline int
+qeth_create_skb_frag(struct qdio_buffer_element *element,
+ struct sk_buff **pskb,
+ int offset, int *pfrag, int data_len)
+{
+ struct page *page = virt_to_page(element->addr);
+ if (*pfrag == 0) {
+ /* the upper protocol layers assume that there is data in the
+ * skb itself. Copy a small amount (64 bytes) to make them
+ * happy. */
+ *pskb = dev_alloc_skb(64 + QETH_FAKE_LL_LEN_ETH);
+ if (!(*pskb))
+ return -ENOMEM;
+ skb_reserve(*pskb, QETH_FAKE_LL_LEN_ETH);
+ if (data_len <= 64) {
+ memcpy(skb_put(*pskb, data_len), element->addr + offset,
+ data_len);
+ } else {
+ get_page(page);
+ memcpy(skb_put(*pskb, 64), element->addr + offset, 64);
+ skb_fill_page_desc(*pskb, *pfrag, page, offset + 64,
+ data_len - 64);
+ (*pskb)->data_len += data_len - 64;
+ (*pskb)->len += data_len - 64;
+ (*pskb)->truesize += data_len - 64;
+ }
+ } else {
+ get_page(page);
+ skb_fill_page_desc(*pskb, *pfrag, page, offset, data_len);
+ (*pskb)->data_len += data_len;
+ (*pskb)->len += data_len;
+ (*pskb)->truesize += data_len;
+ }
+ (*pfrag)++;
+ return 0;
+}
+
+static inline struct qeth_buffer_pool_entry *
+qeth_find_free_buffer_pool_entry(struct qeth_card *card)
+{
+ struct list_head *plh;
+ struct qeth_buffer_pool_entry *entry;
+ int i, free;
+ struct page *page;
+
+ if (list_empty(&card->qdio.in_buf_pool.entry_list))
+ return NULL;
+
+ list_for_each(plh, &card->qdio.in_buf_pool.entry_list) {
+ entry = list_entry(plh, struct qeth_buffer_pool_entry, list);
+ free = 1;
+ for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
+ if (page_count(virt_to_page(entry->elements[i])) > 1) {
+ free = 0;
+ break;
+ }
+ }
+ if (free) {
+ list_del_init(&entry->list);
+ return entry;
+ }
+ }
+
+ /* no free buffer in pool so take first one and swap pages */
+ entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
+ struct qeth_buffer_pool_entry, list);
+ for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) {
+ if (page_count(virt_to_page(entry->elements[i])) > 1) {
+ page = alloc_page(GFP_ATOMIC|GFP_DMA);
+ if (!page) {
+ return NULL;
+ } else {
+ free_page((unsigned long)entry->elements[i]);
+ entry->elements[i] = page_address(page);
+ if (card->options.performance_stats)
+ card->perf_stats.sg_alloc_page_rx++;
+ }
+ }
+ }
+ list_del_init(&entry->list);
+ return entry;
+}
+
static struct sk_buff *
qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
struct qdio_buffer_element **__element, int *__offset,
@@ -2269,6 +2354,8 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
int skb_len;
void *data_ptr;
int data_len;
+ int use_rx_sg = 0;
+ int frag = 0;
QETH_DBF_TEXT(trace,6,"nextskb");
/* qeth_hdr must not cross element boundaries */
@@ -2293,23 +2380,43 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
if (!skb_len)
return NULL;
- if (card->options.fake_ll){
- if(card->dev->type == ARPHRD_IEEE802_TR){
- if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_TR, *hdr)))
- goto no_mem;
- skb_reserve(skb,QETH_FAKE_LL_LEN_TR);
+ if ((skb_len >= card->options.rx_sg_cb) &&
+ (!(card->info.type == QETH_CARD_TYPE_OSN)) &&
+ (!atomic_read(&card->force_alloc_skb))) {
+ use_rx_sg = 1;
+ } else {
+ if (card->options.fake_ll) {
+ if (card->dev->type == ARPHRD_IEEE802_TR) {
+ if (!(skb = qeth_get_skb(skb_len +
+ QETH_FAKE_LL_LEN_TR, *hdr)))
+ goto no_mem;
+ skb_reserve(skb, QETH_FAKE_LL_LEN_TR);
+ } else {
+ if (!(skb = qeth_get_skb(skb_len +
+ QETH_FAKE_LL_LEN_ETH, *hdr)))
+ goto no_mem;
+ skb_reserve(skb, QETH_FAKE_LL_LEN_ETH);
+ }
} else {
- if (!(skb = qeth_get_skb(skb_len+QETH_FAKE_LL_LEN_ETH, *hdr)))
+ skb = qeth_get_skb(skb_len, *hdr);
+ if (!skb)
goto no_mem;
- skb_reserve(skb,QETH_FAKE_LL_LEN_ETH);
}
- } else if (!(skb = qeth_get_skb(skb_len, *hdr)))
- goto no_mem;
+ }
+
data_ptr = element->addr + offset;
while (skb_len) {
data_len = min(skb_len, (int)(element->length - offset));
- if (data_len)
- memcpy(skb_put(skb, data_len), data_ptr, data_len);
+ if (data_len) {
+ if (use_rx_sg) {
+ if (qeth_create_skb_frag(element, &skb, offset,
+ &frag, data_len))
+ goto no_mem;
+ } else {
+ memcpy(skb_put(skb, data_len), data_ptr,
+ data_len);
+ }
+ }
skb_len -= data_len;
if (skb_len){
if (qeth_is_last_sbale(element)){
@@ -2331,6 +2438,10 @@ qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
}
*__element = element;
*__offset = offset;
+ if (use_rx_sg && card->options.performance_stats) {
+ card->perf_stats.sg_skbs_rx++;
+ card->perf_stats.sg_frags_rx += skb_shinfo(skb)->nr_frags;
+ }
return skb;
no_mem:
if (net_ratelimit()){
@@ -2608,28 +2719,15 @@ qeth_process_inbound_buffer(struct qeth_card *card,
}
}
-static struct qeth_buffer_pool_entry *
-qeth_get_buffer_pool_entry(struct qeth_card *card)
-{
- struct qeth_buffer_pool_entry *entry;
-
- QETH_DBF_TEXT(trace, 6, "gtbfplen");
- if (!list_empty(&card->qdio.in_buf_pool.entry_list)) {
- entry = list_entry(card->qdio.in_buf_pool.entry_list.next,
- struct qeth_buffer_pool_entry, list);
- list_del_init(&entry->list);
- return entry;
- }
- return NULL;
-}
-
-static void
+static int
qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
{
struct qeth_buffer_pool_entry *pool_entry;
int i;
-
- pool_entry = qeth_get_buffer_pool_entry(card);
+
+ pool_entry = qeth_find_free_buffer_pool_entry(card);
+ if (!pool_entry)
+ return 1;
/*
* since the buffer is accessed only from the input_tasklet
* there shouldn't be a need to synchronize; also, since we use
@@ -2648,6 +2746,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
buf->buffer->element[i].flags = 0;
}
buf->state = QETH_QDIO_BUF_EMPTY;
+ return 0;
}
static void
@@ -2682,6 +2781,7 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
int count;
int i;
int rc;
+ int newcount = 0;
QETH_DBF_TEXT(trace,6,"queinbuf");
count = (index < queue->next_buf_to_init)?
@@ -2692,9 +2792,27 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
/* only requeue at a certain threshold to avoid SIGAs */
if (count >= QETH_IN_BUF_REQUEUE_THRESHOLD(card)){
for (i = queue->next_buf_to_init;
- i < queue->next_buf_to_init + count; ++i)
- qeth_init_input_buffer(card,
- &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]);
+ i < queue->next_buf_to_init + count; ++i) {
+ if (qeth_init_input_buffer(card,
+ &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q])) {
+ break;
+ } else {
+ newcount++;
+ }
+ }
+
+ if (newcount < count) {
+ /* we are in memory shortage so we switch back to
+ traditional skb allocation and drop packages */
+ if (atomic_cmpxchg(&card->force_alloc_skb, 0, 1))
+ printk(KERN_WARNING
+ "qeth: switch to alloc skb\n");
+ count = newcount;
+ } else {
+ if (atomic_cmpxchg(&card->force_alloc_skb, 1, 0))
+ printk(KERN_WARNING "qeth: switch to sg\n");
+ }
+
/*
* according to old code it should be avoided to requeue all
* 128 buffers in order to benefit from PCI avoidance.
@@ -6494,6 +6612,7 @@ qeth_hardsetup_card(struct qeth_card *card)
QETH_DBF_TEXT(setup, 2, "hrdsetup");
+ atomic_set(&card->force_alloc_skb, 0);
retry:
if (retries < 3){
PRINT_WARN("Retrying to do IDX activates.\n");
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index 89d56c8ecdd2..f1ff165a5e05 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -212,6 +212,12 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
" Skb fragments sent in SG mode : %u\n\n",
card->perf_stats.sg_skbs_sent,
card->perf_stats.sg_frags_sent);
+ seq_printf(s, " Skbs received in SG mode : %u\n"
+ " Skb fragments received in SG mode : %u\n"
+ " Page allocations for rx SG mode : %u\n\n",
+ card->perf_stats.sg_skbs_rx,
+ card->perf_stats.sg_frags_rx,
+ card->perf_stats.sg_alloc_page_rx);
seq_printf(s, " large_send tx (in Kbytes) : %u\n"
" large_send count : %u\n\n",
card->perf_stats.large_send_bytes >> 10,
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 65ffc21afc37..bb0287ad1aac 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -991,7 +991,7 @@ static struct attribute_group qeth_osn_device_attr_group = {
#define QETH_DEVICE_ATTR(_id,_name,_mode,_show,_store) \
struct device_attribute dev_attr_##_id = { \
- .attr = {.name=__stringify(_name), .mode=_mode, .owner=THIS_MODULE },\
+ .attr = {.name=__stringify(_name), .mode=_mode, },\
.show = _show, \
.store = _store, \
};
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 821cde65e369..ab5ec1feaf4e 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -259,21 +259,21 @@ zfcp_module_init(void)
size = sizeof(struct zfcp_fsf_req_qtcb);
align = calc_alignment(size);
zfcp_data.fsf_req_qtcb_cache =
- kmem_cache_create("zfcp_fsf", size, align, 0, NULL, NULL);
+ kmem_cache_create("zfcp_fsf", size, align, 0, NULL);
if (!zfcp_data.fsf_req_qtcb_cache)
goto out;
size = sizeof(struct fsf_status_read_buffer);
align = calc_alignment(size);
zfcp_data.sr_buffer_cache =
- kmem_cache_create("zfcp_sr", size, align, 0, NULL, NULL);
+ kmem_cache_create("zfcp_sr", size, align, 0, NULL);
if (!zfcp_data.sr_buffer_cache)
goto out_sr_cache;
size = sizeof(struct zfcp_gid_pn_data);
align = calc_alignment(size);
zfcp_data.gid_pn_cache =
- kmem_cache_create("zfcp_gid", size, align, 0, NULL, NULL);
+ kmem_cache_create("zfcp_gid", size, align, 0, NULL);
if (!zfcp_data.gid_pn_cache)
goto out_gid_cache;
@@ -815,9 +815,7 @@ zfcp_get_adapter_by_busid(char *bus_id)
struct zfcp_unit *
zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
{
- struct zfcp_unit *unit, *tmp_unit;
- unsigned int scsi_lun;
- int found;
+ struct zfcp_unit *unit;
/*
* check that there is no unit with this FCP_LUN already in list
@@ -863,22 +861,10 @@ zfcp_unit_enqueue(struct zfcp_port *port, fcp_lun_t fcp_lun)
}
zfcp_unit_get(unit);
+ unit->scsi_lun = scsilun_to_int((struct scsi_lun *)&unit->fcp_lun);
- scsi_lun = 0;
- found = 0;
write_lock_irq(&zfcp_data.config_lock);
- list_for_each_entry(tmp_unit, &port->unit_list_head, list) {
- if (tmp_unit->scsi_lun != scsi_lun) {
- found = 1;
- break;
- }
- scsi_lun++;
- }
- unit->scsi_lun = scsi_lun;
- if (found)
- list_add_tail(&unit->list, &tmp_unit->list);
- else
- list_add_tail(&unit->list, &port->unit_list_head);
+ list_add_tail(&unit->list, &port->unit_list_head);
atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &unit->status);
atomic_set_mask(ZFCP_STATUS_COMMON_RUNNING, &unit->status);
write_unlock_irq(&zfcp_data.config_lock);
@@ -1540,15 +1526,12 @@ zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool)
* zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request
* @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed
*/
-static void
-zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
+static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
{
- if ((gid_pn->ct.pool != 0))
+ if (gid_pn->ct.pool)
mempool_free(gid_pn, gid_pn->ct.pool);
else
- kfree(gid_pn);
-
- return;
+ kfree(gid_pn);
}
/**
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 22649639230b..b36dfc40d9fa 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -126,6 +126,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list)
#define ZFCP_MIN_OUTPUT_THRESHOLD 1 /* ignored by QDIO layer */
#define QDIO_SCSI_QFMT 1 /* 1 for FSF */
+#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
/********************* FSF SPECIFIC DEFINES *********************************/
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index aef66bc2b6ca..d8cd75ce2d9a 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1626,7 +1626,7 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
{
struct zfcp_erp_add_work *p;
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p) {
ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
"the FCP-LUN 0x%Lx connected to "
@@ -1639,7 +1639,6 @@ zfcp_erp_schedule_work(struct zfcp_unit *unit)
}
zfcp_unit_get(unit);
- memset(p, 0, sizeof(*p));
atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
INIT_WORK(&p->work, zfcp_erp_scsi_scan);
p->unit = unit;
@@ -1986,6 +1985,10 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
failed_openfcp:
zfcp_close_fsf(erp_action->adapter);
failed_qdio:
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK |
+ ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
+ ZFCP_STATUS_ADAPTER_XPORT_OK,
+ &erp_action->adapter->status);
out:
return retval;
}
@@ -2167,6 +2170,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
sleep *= 2;
}
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
+ &adapter->status);
+
if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK,
&adapter->status)) {
ZFCP_LOG_INFO("error: exchange of configuration data for "
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 0eb31e162b15..b240800b78d7 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1930,7 +1930,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req)
skip_fsfstatus:
send_els->status = retval;
- if (send_els->handler != 0)
+ if (send_els->handler)
send_els->handler(send_els->handler_data);
return retval;
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index bdf5782b8a7a..c408badd2ae9 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -47,103 +47,56 @@ static int zfcp_qdio_handler_error_check(struct zfcp_adapter *,
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO
/*
- * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
- * array in the adapter struct.
- * Cur_buf is the pointer array and count can be any number of required
- * buffers, the page-fitting arithmetic is done entirely within this funciton.
+ * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array
+ * in the adapter struct sbuf is the pointer array.
*
- * returns: number of buffers allocated
* locks: must only be called with zfcp_data.config_sema taken
*/
-static int
-zfcp_qdio_buffers_enqueue(struct qdio_buffer **cur_buf, int count)
+static void
+zfcp_qdio_buffers_dequeue(struct qdio_buffer **sbuf)
{
- int buf_pos;
- int qdio_buffers_per_page;
- int page_pos = 0;
- struct qdio_buffer *first_in_page = NULL;
-
- qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
- ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
-
- for (buf_pos = 0; buf_pos < count; buf_pos++) {
- if (page_pos == 0) {
- cur_buf[buf_pos] = (struct qdio_buffer *)
- get_zeroed_page(GFP_KERNEL);
- if (cur_buf[buf_pos] == NULL) {
- ZFCP_LOG_INFO("error: allocation of "
- "QDIO buffer failed \n");
- goto out;
- }
- first_in_page = cur_buf[buf_pos];
- } else {
- cur_buf[buf_pos] = first_in_page + page_pos;
+ int pos;
- }
- /* was initialised to zero */
- page_pos++;
- page_pos %= qdio_buffers_per_page;
- }
- out:
- return buf_pos;
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE)
+ free_page((unsigned long) sbuf[pos]);
}
/*
- * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array
- * in the adapter struct cur_buf is the pointer array and count can be any
- * number of buffers in the array that should be freed starting from buffer 0
+ * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
+ * array in the adapter struct.
+ * Cur_buf is the pointer array
*
+ * returns: zero on success else -ENOMEM
* locks: must only be called with zfcp_data.config_sema taken
*/
-static void
-zfcp_qdio_buffers_dequeue(struct qdio_buffer **cur_buf, int count)
+static int
+zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbuf)
{
- int buf_pos;
- int qdio_buffers_per_page;
-
- qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
- ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
+ int pos;
- for (buf_pos = 0; buf_pos < count; buf_pos += qdio_buffers_per_page)
- free_page((unsigned long) cur_buf[buf_pos]);
- return;
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) {
+ sbuf[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL);
+ if (!sbuf[pos]) {
+ zfcp_qdio_buffers_dequeue(sbuf);
+ return -ENOMEM;
+ }
+ }
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++)
+ if (pos % QBUFF_PER_PAGE)
+ sbuf[pos] = sbuf[pos - 1] + 1;
+ return 0;
}
/* locks: must only be called with zfcp_data.config_sema taken */
int
zfcp_qdio_allocate_queues(struct zfcp_adapter *adapter)
{
- int buffer_count;
- int retval = 0;
+ int ret;
- buffer_count =
- zfcp_qdio_buffers_enqueue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
- ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for request "
- "queue\n", buffer_count);
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- buffer_count);
- retval = -ENOMEM;
- goto out;
- }
-
- buffer_count =
- zfcp_qdio_buffers_enqueue(&(adapter->response_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
- ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for response "
- "queue", buffer_count);
- zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
- buffer_count);
- ZFCP_LOG_TRACE("freeing request_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- retval = -ENOMEM;
- goto out;
- }
- out:
- return retval;
+ ret = zfcp_qdio_buffers_enqueue(adapter->request_queue.buffer);
+ if (ret)
+ return ret;
+ return zfcp_qdio_buffers_enqueue(adapter->response_queue.buffer);
}
/* locks: must only be called with zfcp_data.config_sema taken */
@@ -151,12 +104,10 @@ void
zfcp_qdio_free_queues(struct zfcp_adapter *adapter)
{
ZFCP_LOG_TRACE("freeing request_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
+ zfcp_qdio_buffers_dequeue(adapter->request_queue.buffer);
ZFCP_LOG_TRACE("freeing response_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
+ zfcp_qdio_buffers_dequeue(adapter->response_queue.buffer);
}
int
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index a54e4140683a..e821a155b658 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -7,6 +7,7 @@
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/kmod.h>
+#include <linux/reboot.h>
#include <asm/oplib.h>
#include <asm/ebus.h>
@@ -170,8 +171,6 @@ static void get_current_temps(struct bbc_cpu_temperature *tp)
static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
{
static int shutting_down = 0;
- static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
char *type = "???";
s8 val = -1;
@@ -195,7 +194,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
shutting_down = 1;
- if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
+ if (orderly_poweroff(true) < 0)
printk(KERN_CRIT "envctrl: shutdown execution failed\n");
}
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 178155bf9db6..fbadd4d761f3 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -156,10 +156,9 @@ struct bbc_i2c_client *bbc_i2c_attach(struct linux_ebus_child *echild)
if (!bp)
return NULL;
- client = kmalloc(sizeof(*client), GFP_KERNEL);
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return NULL;
- memset(client, 0, sizeof(*client));
client->bp = bp;
client->echild = echild;
client->bus = echild->resource[0].start;
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index 022e869c44dd..7b5773d88212 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -24,6 +24,7 @@
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/smp_lock.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/ebus.h>
#include <asm/oplib.h>
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 8328acab47fd..dadabef116b6 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -26,6 +26,7 @@
#include <linux/ioport.h>
#include <linux/miscdevice.h>
#include <linux/kmod.h>
+#include <linux/reboot.h>
#include <asm/ebus.h>
#include <asm/uaccess.h>
@@ -966,10 +967,6 @@ static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type)
static void envctrl_do_shutdown(void)
{
static int inprog = 0;
- static char *envp[] = {
- "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = {
- "/sbin/shutdown", "-h", "now", NULL };
int ret;
if (inprog != 0)
@@ -977,7 +974,7 @@ static void envctrl_do_shutdown(void)
inprog = 1;
printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
- ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
+ ret = orderly_poweroff(true);
if (ret < 0) {
printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n");
inprog = 0; /* unlikely to succeed, but we could try again */
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 512857a23169..5157a2abc58d 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -619,8 +619,7 @@ static void __exit jsflash_cleanup_module(void)
jsf0.busy = 0;
misc_deregister(&jsf_dev);
- if (unregister_blkdev(JSFD_MAJOR, "jsfd") != 0)
- printk("jsfd: cleanup_module failed\n");
+ unregister_blkdev(JSFD_MAJOR, "jsfd");
blk_cleanup_queue(jsf_queue);
}
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 6afc7e5df0d4..26b1d2a17ed2 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -656,12 +656,9 @@ static int vfc_probe(void)
if (!cards)
return -ENODEV;
- vfc_dev_lst = kmalloc(sizeof(struct vfc_dev *) *
- (cards+1),
- GFP_KERNEL);
+ vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
if (vfc_dev_lst == NULL)
return -ENOMEM;
- memset(vfc_dev_lst, 0, sizeof(struct vfc_dev *) * (cards + 1));
vfc_dev_lst[cards] = NULL;
ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 002643392d42..2553629ec15d 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -33,6 +33,7 @@ struct sbus_bus *sbus_root;
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
+ struct dev_archdata *sd;
unsigned long base;
const void *pval;
int len, err;
@@ -67,6 +68,10 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
sbus_fill_device_irq(sdev);
+ sd = &sdev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &sdev->ofdev;
+
sdev->ofdev.node = dp;
if (sdev->parent)
sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index eb766c3af1c8..efd9d8d3a890 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -4,7 +4,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
Modifications By: Tom Couch <linuxraid@amcc.com>
- Copyright (C) 2004-2006 Applied Micro Circuits Corporation.
+ Copyright (C) 2004-2007 Applied Micro Circuits 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
@@ -69,6 +69,8 @@
2.26.02.008 - Free irq handler in __twa_shutdown().
Serialize reset code.
Add support for 9650SE controllers.
+ 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
+ 2.26.02.010 - Add support for 9690SA controllers.
*/
#include <linux/module.h>
@@ -92,7 +94,7 @@
#include "3w-9xxx.h"
/* Globals */
-#define TW_DRIVER_VERSION "2.26.02.008"
+#define TW_DRIVER_VERSION "2.26.02.010"
static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
static unsigned int twa_device_extension_count;
static int twa_major = -1;
@@ -124,11 +126,11 @@ static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
unsigned short *fw_on_ctlr_branch,
unsigned short *fw_on_ctlr_build,
u32 *init_connect_result);
-static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
+static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
@@ -683,7 +685,7 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
full_command_packet = &tw_ioctl->firmware_command;
/* Load request id and sglist for both command types */
- twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+ twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
@@ -700,10 +702,10 @@ static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int
if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
/* Now we need to reset the board */
printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
- tw_dev->host->host_no, TW_DRIVER, 0xc,
+ tw_dev->host->host_no, TW_DRIVER, 0x37,
cmd);
retval = TW_IOCTL_ERROR_OS_EIO;
- twa_reset_device_extension(tw_dev, 1);
+ twa_reset_device_extension(tw_dev);
goto out3;
}
@@ -890,7 +892,9 @@ static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
}
if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
- if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!test_bit(TW_IN_RESET, &tw_dev->flags)))
+ if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) &&
+ (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) ||
+ (!test_bit(TW_IN_RESET, &tw_dev->flags)))
TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
}
@@ -935,8 +939,7 @@ static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
unsigned long before;
int retval = 1;
- if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) ||
- (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) {
+ if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) {
before = jiffies;
while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
@@ -1160,13 +1163,12 @@ static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
}
/* Allocate event info space */
- tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);
+ tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
if (!tw_dev->event_queue[0]) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
goto out;
}
- memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
for (i = 0; i < TW_Q_LENGTH; i++) {
tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
@@ -1196,7 +1198,6 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
u32 status_reg_value;
TW_Response_Queue response_que;
TW_Command_Full *full_command_packet;
- TW_Command *command_packet;
TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
int handled = 0;
@@ -1274,7 +1275,6 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
request_id = TW_RESID_OUT(response_que.response_id);
full_command_packet = tw_dev->command_packet_virt[request_id];
error = 0;
- command_packet = &full_command_packet->command.oldcommand;
/* Check for command packet errors */
if (full_command_packet->command.newcommand.status != 0) {
if (tw_dev->srb[request_id] != 0) {
@@ -1306,22 +1306,26 @@ static irqreturn_t twa_interrupt(int irq, void *dev_instance)
wake_up(&tw_dev->ioctl_wqueue);
}
} else {
+ struct scsi_cmnd *cmd;
+
+ cmd = tw_dev->srb[request_id];
+
twa_scsiop_execute_scsi_complete(tw_dev, request_id);
/* If no error command was a success */
if (error == 0) {
- tw_dev->srb[request_id]->result = (DID_OK << 16);
+ cmd->result = (DID_OK << 16);
}
/* If error, command failed */
if (error == 1) {
/* Ask for a host reset */
- tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+ cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
}
/* Report residual bytes for single sgl */
- if ((tw_dev->srb[request_id]->use_sg <= 1) && (full_command_packet->command.newcommand.status == 0)) {
- if (full_command_packet->command.newcommand.sg_list[0].length < tw_dev->srb[request_id]->request_bufflen)
- tw_dev->srb[request_id]->resid = tw_dev->srb[request_id]->request_bufflen - full_command_packet->command.newcommand.sg_list[0].length;
+ if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) {
+ if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id]))
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length);
}
/* Now complete the io */
@@ -1349,11 +1353,15 @@ twa_interrupt_bail:
} /* End twa_interrupt() */
/* This function will load the request id and various sgls for ioctls */
-static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
{
TW_Command *oldcommand;
TW_Command_Apache *newcommand;
TW_SG_Entry *sgl;
+ unsigned int pae = 0;
+
+ if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
+ pae = 1;
if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
newcommand = &full_command_packet->command.newcommand;
@@ -1369,12 +1377,14 @@ static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, d
if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
/* Load the sg list */
- sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
+ if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)
+ sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
+ else
+ sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
sgl->length = cpu_to_le32(length);
- if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
- oldcommand->size += 1;
+ oldcommand->size += pae;
}
}
} /* End twa_load_sgl() */
@@ -1384,52 +1394,20 @@ static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
{
int use_sg;
struct scsi_cmnd *cmd = tw_dev->srb[request_id];
- struct pci_dev *pdev = tw_dev->tw_pci_dev;
- int retval = 0;
-
- if (cmd->use_sg == 0)
- goto out;
-
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
- if (use_sg == 0) {
+ use_sg = scsi_dma_map(cmd);
+ if (!use_sg)
+ return 0;
+ else if (use_sg < 0) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
- goto out;
+ return 0;
}
cmd->SCp.phase = TW_PHASE_SGLIST;
cmd->SCp.have_data_in = use_sg;
- retval = use_sg;
-out:
- return retval;
-} /* End twa_map_scsi_sg_data() */
-/* This function will perform a pci-dma map for a single buffer */
-static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id)
-{
- dma_addr_t mapping;
- struct scsi_cmnd *cmd = tw_dev->srb[request_id];
- struct pci_dev *pdev = tw_dev->tw_pci_dev;
- dma_addr_t retval = 0;
-
- if (cmd->request_bufflen == 0) {
- retval = 0;
- goto out;
- }
-
- mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL);
-
- if (mapping == 0) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page");
- goto out;
- }
-
- cmd->SCp.phase = TW_PHASE_SINGLE;
- cmd->SCp.have_data_in = mapping;
- retval = mapping;
-out:
- return retval;
-} /* End twa_map_scsi_single_data() */
+ return use_sg;
+} /* End twa_map_scsi_sg_data() */
/* This function will poll for a response interrupt of a request */
static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
@@ -1535,7 +1513,8 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id,
command_que_value = tw_dev->command_packet_phys[request_id];
/* For 9650SE write low 4 bytes first */
- if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+ if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+ (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
command_que_value += TW_COMMAND_OFFSET;
writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
}
@@ -1566,7 +1545,8 @@ static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id,
TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
goto out;
} else {
- if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+ if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+ (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
/* Now write upper 4 bytes */
writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
} else {
@@ -1590,7 +1570,7 @@ out:
} /* End twa_post_command_packet() */
/* This function will reset a device extension */
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
{
int i = 0;
int retval = 1;
@@ -1748,7 +1728,7 @@ static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
mutex_lock(&tw_dev->ioctl_lock);
/* Now reset the card and some of the device extension data */
- if (twa_reset_device_extension(tw_dev, 0)) {
+ if (twa_reset_device_extension(tw_dev)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
goto out;
}
@@ -1815,15 +1795,13 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
u32 num_sectors = 0x0;
int i, sg_count;
struct scsi_cmnd *srb = NULL;
- struct scatterlist *sglist = NULL;
- dma_addr_t buffaddr = 0x0;
+ struct scatterlist *sglist = NULL, *sg;
int retval = 1;
if (tw_dev->srb[request_id]) {
- if (tw_dev->srb[request_id]->request_buffer) {
- sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
- }
srb = tw_dev->srb[request_id];
+ if (scsi_sglist(srb))
+ sglist = scsi_sglist(srb);
}
/* Initialize command packet */
@@ -1856,32 +1834,12 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
if (!sglistarg) {
/* Map sglist from scsi layer to cmd packet */
- if (tw_dev->srb[request_id]->use_sg == 0) {
- if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
- command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]);
- command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH);
- if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)
- memcpy(tw_dev->generic_buffer_virt[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen);
- } else {
- buffaddr = twa_map_scsi_single_data(tw_dev, request_id);
- if (buffaddr == 0)
- goto out;
-
- command_packet->sg_list[0].address = TW_CPU_TO_SGL(buffaddr);
- command_packet->sg_list[0].length = cpu_to_le32(tw_dev->srb[request_id]->request_bufflen);
- }
- command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), 1));
-
- if (command_packet->sg_list[0].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
- TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
- goto out;
- }
- }
- if (tw_dev->srb[request_id]->use_sg > 0) {
- if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
- if (tw_dev->srb[request_id]->sc_data_direction == DMA_TO_DEVICE || tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL) {
- struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+ if (scsi_sg_count(srb)) {
+ if ((scsi_sg_count(srb) == 1) &&
+ (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) {
+ if (srb->sc_data_direction == DMA_TO_DEVICE || srb->sc_data_direction == DMA_BIDIRECTIONAL) {
+ struct scatterlist *sg = scsi_sglist(srb);
char *buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
memcpy(tw_dev->generic_buffer_virt[request_id], buf, sg->length);
kunmap_atomic(buf - sg->offset, KM_IRQ0);
@@ -1893,16 +1851,16 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
if (sg_count == 0)
goto out;
- for (i = 0; i < sg_count; i++) {
- command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(&sglist[i]));
- command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(&sglist[i]));
+ scsi_for_each_sg(srb, sg, sg_count, i) {
+ command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg));
+ command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
goto out;
}
}
}
- command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), tw_dev->srb[request_id]->use_sg));
+ command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id])));
}
} else {
/* Internal cdb post */
@@ -1932,7 +1890,7 @@ static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id,
/* Update SG statistics */
if (srb) {
- tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+ tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
tw_dev->max_sgl_entries = tw_dev->sgl_entries;
}
@@ -1951,16 +1909,13 @@ out:
/* This function completes an execute scsi operation */
static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
{
- if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH &&
- (tw_dev->srb[request_id]->sc_data_direction == DMA_FROM_DEVICE ||
- tw_dev->srb[request_id]->sc_data_direction == DMA_BIDIRECTIONAL)) {
- if (tw_dev->srb[request_id]->use_sg == 0) {
- memcpy(tw_dev->srb[request_id]->request_buffer,
- tw_dev->generic_buffer_virt[request_id],
- tw_dev->srb[request_id]->request_bufflen);
- }
- if (tw_dev->srb[request_id]->use_sg == 1) {
- struct scatterlist *sg = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+ struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+
+ if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH &&
+ (cmd->sc_data_direction == DMA_FROM_DEVICE ||
+ cmd->sc_data_direction == DMA_BIDIRECTIONAL)) {
+ if (scsi_sg_count(cmd) == 1) {
+ struct scatterlist *sg = scsi_sglist(tw_dev->srb[request_id]);
char *buf;
unsigned long flags = 0;
local_irq_save(flags);
@@ -2017,16 +1972,8 @@ static char *twa_string_lookup(twa_message_type *table, unsigned int code)
static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
{
struct scsi_cmnd *cmd = tw_dev->srb[request_id];
- struct pci_dev *pdev = tw_dev->tw_pci_dev;
- switch(cmd->SCp.phase) {
- case TW_PHASE_SINGLE:
- pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
- break;
- case TW_PHASE_SGLIST:
- pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
- break;
- }
+ scsi_dma_unmap(cmd);
} /* End twa_unmap_scsi_data() */
/* scsi_host_template initializer */
@@ -2063,11 +2010,14 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
pci_set_master(pdev);
- retval = pci_set_dma_mask(pdev, sizeof(dma_addr_t) > 4 ? DMA_64BIT_MASK : DMA_32BIT_MASK);
- if (retval) {
- TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
- goto out_disable_device;
- }
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
+ || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)
+ || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+ TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+ retval = -ENODEV;
+ goto out_disable_device;
+ }
host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
if (!host) {
@@ -2115,7 +2065,8 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
goto out_iounmap;
/* Set host specific parameters */
- if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE)
+ if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+ (pdev->device == PCI_DEVICE_ID_3WARE_9690SA))
host->max_id = TW_MAX_UNITS_9650SE;
else
host->max_id = TW_MAX_UNITS;
@@ -2222,6 +2173,8 @@ static struct pci_device_id twa_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ }
};
MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index 7901517d4513..d14a9479e389 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -4,7 +4,7 @@
Written By: Adam Radford <linuxraid@amcc.com>
Modifications By: Tom Couch <linuxraid@amcc.com>
- Copyright (C) 2004-2006 Applied Micro Circuits Corporation.
+ Copyright (C) 2004-2007 Applied Micro Circuits 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
@@ -419,6 +419,9 @@ static twa_message_type twa_error_table[] = {
#ifndef PCI_DEVICE_ID_3WARE_9650SE
#define PCI_DEVICE_ID_3WARE_9650SE 0x1004
#endif
+#ifndef PCI_DEVICE_ID_3WARE_9690SA
+#define PCI_DEVICE_ID_3WARE_9690SA 0x1005
+#endif
/* Bitmask macros to eliminate bitfields */
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 656bdb1352d8..c7995fc216e8 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -1273,57 +1273,24 @@ static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
int use_sg;
dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
-
- if (cmd->use_sg == 0)
- return 0;
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
-
- if (use_sg == 0) {
+ use_sg = scsi_dma_map(cmd);
+ if (use_sg < 0) {
printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
return 0;
}
cmd->SCp.phase = TW_PHASE_SGLIST;
cmd->SCp.have_data_in = use_sg;
-
+
return use_sg;
} /* End tw_map_scsi_sg_data() */
-static u32 tw_map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- dma_addr_t mapping;
-
- dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
-
- if (cmd->request_bufflen == 0)
- return 0;
-
- mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, DMA_BIDIRECTIONAL);
-
- if (mapping == 0) {
- printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
- return 0;
- }
-
- cmd->SCp.phase = TW_PHASE_SINGLE;
- cmd->SCp.have_data_in = mapping;
-
- return mapping;
-} /* End tw_map_scsi_single_data() */
-
static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
{
dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
- switch(cmd->SCp.phase) {
- case TW_PHASE_SINGLE:
- pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
- break;
- case TW_PHASE_SGLIST:
- pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
- break;
- }
+ scsi_dma_unmap(cmd);
} /* End tw_unmap_scsi_data() */
/* This function will reset a device extension */
@@ -1499,27 +1466,16 @@ static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id,
void *buf;
unsigned int transfer_len;
unsigned long flags = 0;
+ struct scatterlist *sg = scsi_sglist(cmd);
- if (cmd->use_sg) {
- struct scatterlist *sg =
- (struct scatterlist *)cmd->request_buffer;
- local_irq_save(flags);
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- transfer_len = min(sg->length, len);
- } else {
- buf = cmd->request_buffer;
- transfer_len = min(cmd->request_bufflen, len);
- }
+ local_irq_save(flags);
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ transfer_len = min(sg->length, len);
memcpy(buf, data, transfer_len);
-
- if (cmd->use_sg) {
- struct scatterlist *sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- local_irq_restore(flags);
- }
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
}
/* This function is called by the isr to complete an inquiry command */
@@ -1764,19 +1720,20 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
{
TW_Command *command_packet;
unsigned long command_que_value;
- u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+ u32 lba = 0x0, num_sectors = 0x0;
int i, use_sg;
struct scsi_cmnd *srb;
- struct scatterlist *sglist;
+ struct scatterlist *sglist, *sg;
dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
- if (tw_dev->srb[request_id]->request_buffer == NULL) {
+ srb = tw_dev->srb[request_id];
+
+ sglist = scsi_sglist(srb);
+ if (!sglist) {
printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
return 1;
}
- sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
- srb = tw_dev->srb[request_id];
/* Initialize command packet */
command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
@@ -1819,33 +1776,18 @@ static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
command_packet->byte8.io.lba = lba;
command_packet->byte6.block_count = num_sectors;
- /* Do this if there are no sg list entries */
- if (tw_dev->srb[request_id]->use_sg == 0) {
- dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
- buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
- if (buffaddr == 0)
- return 1;
+ use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+ if (!use_sg)
+ return 1;
- command_packet->byte8.io.sgl[0].address = buffaddr;
- command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+ scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) {
+ command_packet->byte8.io.sgl[i].address = sg_dma_address(sg);
+ command_packet->byte8.io.sgl[i].length = sg_dma_len(sg);
command_packet->size+=2;
}
- /* Do this if we have multiple sg list entries */
- if (tw_dev->srb[request_id]->use_sg > 0) {
- use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
- if (use_sg == 0)
- return 1;
-
- for (i=0;i<use_sg; i++) {
- command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
- command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
- command_packet->size+=2;
- }
- }
-
/* Update SG statistics */
- tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+ tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]);
if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
tw_dev->max_sgl_entries = tw_dev->sgl_entries;
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index cb02656eb54c..71ff3fbfce12 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -267,8 +267,6 @@ NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata,
offset = max_offset;
}
if(XFERP < min_xferp) {
- printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
- XFERP, min_xferp);
XFERP = min_xferp;
}
return (offset & 0x0f) | (XFERP & 0x07)<<4;
@@ -585,16 +583,8 @@ NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp,
struct NCR_700_command_slot *slot)
{
if(SCp->sc_data_direction != DMA_NONE &&
- SCp->sc_data_direction != DMA_BIDIRECTIONAL) {
- if(SCp->use_sg) {
- dma_unmap_sg(hostdata->dev, SCp->request_buffer,
- SCp->use_sg, SCp->sc_data_direction);
- } else {
- dma_unmap_single(hostdata->dev, slot->dma_handle,
- SCp->request_bufflen,
- SCp->sc_data_direction);
- }
- }
+ SCp->sc_data_direction != DMA_BIDIRECTIONAL)
+ scsi_dma_unmap(SCp);
}
STATIC inline void
@@ -661,7 +651,6 @@ NCR_700_chip_setup(struct Scsi_Host *host)
{
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)host->hostdata[0];
- __u32 dcntl_extra = 0;
__u8 min_period;
__u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
@@ -686,13 +675,14 @@ NCR_700_chip_setup(struct Scsi_Host *host)
burst_disable = BURST_DISABLE;
break;
}
- dcntl_extra = COMPAT_700_MODE;
+ hostdata->dcntl_extra |= COMPAT_700_MODE;
- NCR_700_writeb(dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(hostdata->dcntl_extra, host, DCNTL_REG);
NCR_700_writeb(burst_length | hostdata->dmode_extra,
host, DMODE_710_REG);
- NCR_700_writeb(burst_disable | (hostdata->differential ?
- DIFF : 0), host, CTEST7_REG);
+ NCR_700_writeb(burst_disable | hostdata->ctest7_extra |
+ (hostdata->differential ? DIFF : 0),
+ host, CTEST7_REG);
NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG);
NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY
| AUTO_ATN, host, SCNTL0_REG);
@@ -727,13 +717,13 @@ NCR_700_chip_setup(struct Scsi_Host *host)
* of spec: sync divider 2, async divider 3 */
DEBUG(("53c700: sync 2 async 3\n"));
NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock/2;
} else if(hostdata->clock > 50 && hostdata->clock <= 75) {
/* sync divider 1.5, async divider 3 */
DEBUG(("53c700: sync 1.5 async 3\n"));
NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock*2;
hostdata->sync_clock /= 3;
@@ -741,18 +731,18 @@ NCR_700_chip_setup(struct Scsi_Host *host)
/* sync divider 1, async divider 2 */
DEBUG(("53c700: sync 1 async 2\n"));
NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_2_0 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock;
} else if(hostdata->clock > 25 && hostdata->clock <=37) {
/* sync divider 1, async divider 1.5 */
DEBUG(("53c700: sync 1 async 1.5\n"));
NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_5 | hostdata->dcntl_extra, host, DCNTL_REG);
hostdata->sync_clock = hostdata->clock;
} else {
DEBUG(("53c700: sync 1 async 1\n"));
NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
- NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG);
+ NCR_700_writeb(ASYNC_DIV_1_0 | hostdata->dcntl_extra, host, DCNTL_REG);
/* sync divider 1, async divider 1 */
hostdata->sync_clock = hostdata->clock;
}
@@ -1263,14 +1253,13 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
host->host_no, pun, lun, NCR_700_condition[i],
NCR_700_phase[j], dsp - hostdata->pScript);
if(SCp != NULL) {
- scsi_print_command(SCp);
+ struct scatterlist *sg;
- if(SCp->use_sg) {
- for(i = 0; i < SCp->use_sg + 1; i++) {
- printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->request_buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
- }
+ scsi_print_command(SCp);
+ scsi_for_each_sg(SCp, sg, scsi_sg_count(SCp) + 1, i) {
+ printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, sg->length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
}
- }
+ }
NCR_700_internal_bus_reset(host);
} else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) {
printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n",
@@ -1844,8 +1833,8 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
}
/* sanity check: some of the commands generated by the mid-layer
* have an eccentric idea of their sc_data_direction */
- if(!SCp->use_sg && !SCp->request_bufflen
- && SCp->sc_data_direction != DMA_NONE) {
+ if(!scsi_sg_count(SCp) && !scsi_bufflen(SCp) &&
+ SCp->sc_data_direction != DMA_NONE) {
#ifdef NCR_700_DEBUG
printk("53c700: Command");
scsi_print_command(SCp);
@@ -1887,31 +1876,15 @@ NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
int i;
int sg_count;
dma_addr_t vPtr = 0;
+ struct scatterlist *sg;
__u32 count = 0;
- if(SCp->use_sg) {
- sg_count = dma_map_sg(hostdata->dev,
- SCp->request_buffer, SCp->use_sg,
- direction);
- } else {
- vPtr = dma_map_single(hostdata->dev,
- SCp->request_buffer,
- SCp->request_bufflen,
- direction);
- count = SCp->request_bufflen;
- slot->dma_handle = vPtr;
- sg_count = 1;
- }
-
+ sg_count = scsi_dma_map(SCp);
+ BUG_ON(sg_count < 0);
- for(i = 0; i < sg_count; i++) {
-
- if(SCp->use_sg) {
- struct scatterlist *sg = SCp->request_buffer;
-
- vPtr = sg_dma_address(&sg[i]);
- count = sg_dma_len(&sg[i]);
- }
+ scsi_for_each_sg(SCp, sg, sg_count, i) {
+ vPtr = sg_dma_address(sg);
+ count = sg_dma_len(sg);
slot->SG[i].ins = bS_to_host(move_ins | count);
DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n",
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index 841e1bb27d57..e06bdfeab420 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -177,6 +177,7 @@ struct NCR_700_command_slot {
__u8 state;
#define NCR_700_FLAG_AUTOSENSE 0x01
__u8 flags;
+ __u8 pad1[2]; /* Needed for m68k where min alignment is 2 bytes */
int tag;
__u32 resume_offset;
struct scsi_cmnd *cmnd;
@@ -196,6 +197,8 @@ struct NCR_700_Host_Parameters {
void __iomem *base; /* the base for the port (copied to host) */
struct device *dev;
__u32 dmode_extra; /* adjustable bus settings */
+ __u32 dcntl_extra; /* adjustable bus settings */
+ __u32 ctest7_extra; /* adjustable bus settings */
__u32 differential:1; /* if we are differential */
#ifdef CONFIG_53C700_LE_ON_BE
/* This option is for HP only. Set it if your chip is wired for
@@ -352,6 +355,7 @@ struct NCR_700_Host_Parameters {
#define SEL_TIMEOUT_DISABLE 0x10 /* 710 only */
#define DFP 0x08
#define EVP 0x04
+#define CTEST7_TT1 0x02
#define DIFF 0x01
#define CTEST6_REG 0x1A
#define TEMP_REG 0x1C
@@ -385,6 +389,7 @@ struct NCR_700_Host_Parameters {
#define SOFTWARE_RESET 0x01
#define COMPAT_700_MODE 0x01
#define SCRPTS_16BITS 0x20
+#define EA_710 0x20
#define ASYNC_DIV_2_0 0x00
#define ASYNC_DIV_1_5 0x40
#define ASYNC_DIV_1_0 0x80
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
deleted file mode 100644
index 93b41f45638a..000000000000
--- a/drivers/scsi/53c7xx.c
+++ /dev/null
@@ -1,6102 +0,0 @@
-/*
- * 53c710 driver. Modified from Drew Eckhardts driver
- * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
- * Check out PERM_OPTIONS and EXPECTED_CLOCK, which may be defined in the
- * relevant machine specific file (eg. mvme16x.[ch], amiga7xx.[ch]).
- * There are also currently some defines at the top of 53c7xx.scr.
- * The chip type is #defined in script_asm.pl, as well as the Makefile.
- * Host scsi ID expected to be 7 - see NCR53c7x0_init().
- *
- * I have removed the PCI code and some of the 53c8xx specific code -
- * simply to make this file smaller and easier to manage.
- *
- * MVME16x issues:
- * Problems trying to read any chip registers in NCR53c7x0_init(), as they
- * may never have been set by 16xBug (eg. If kernel has come in over tftp).
- */
-
-/*
- * Adapted for Linux/m68k Amiga platforms for the A4000T/A4091 and
- * WarpEngine SCSI controllers.
- * By Alan Hourihane <alanh@fairlite.demon.co.uk>
- * Thanks to Richard Hirst for making it possible with the MVME additions
- */
-
-/*
- * 53c710 rev 0 doesn't support add with carry. Rev 1 and 2 does. To
- * overcome this problem you can define FORCE_DSA_ALIGNMENT, which ensures
- * that the DSA address is always xxxxxx00. If disconnection is not allowed,
- * then the script only ever tries to add small (< 256) positive offsets to
- * DSA, so lack of carry isn't a problem. FORCE_DSA_ALIGNMENT can, of course,
- * be defined for all chip revisions at a small cost in memory usage.
- */
-
-#define FORCE_DSA_ALIGNMENT
-
-/*
- * Selection timer does not always work on the 53c710, depending on the
- * timing at the last disconnect, if this is a problem for you, try
- * using validids as detailed below.
- *
- * Options for the NCR7xx driver
- *
- * noasync:0 - disables sync and asynchronous negotiation
- * nosync:0 - disables synchronous negotiation (does async)
- * nodisconnect:0 - disables disconnection
- * validids:0x?? - Bitmask field that disallows certain ID's.
- * - e.g. 0x03 allows ID 0,1
- * - 0x1F allows ID 0,1,2,3,4
- * opthi:n - replace top word of options with 'n'
- * optlo:n - replace bottom word of options with 'n'
- * - ALWAYS SPECIFY opthi THEN optlo <<<<<<<<<<
- */
-
-/*
- * PERM_OPTIONS are driver options which will be enabled for all NCR boards
- * in the system at driver initialization time.
- *
- * Don't THINK about touching these in PERM_OPTIONS :
- * OPTION_MEMORY_MAPPED
- * 680x0 doesn't have an IO map!
- *
- * OPTION_DEBUG_TEST1
- * Test 1 does bus mastering and interrupt tests, which will help weed
- * out brain damaged main boards.
- *
- * Other PERM_OPTIONS settings are listed below. Note the actual options
- * required are set in the relevant file (mvme16x.c, amiga7xx.c, etc):
- *
- * OPTION_NO_ASYNC
- * Don't negotiate for asynchronous transfers on the first command
- * when OPTION_ALWAYS_SYNCHRONOUS is set. Useful for dain bramaged
- * devices which do something bad rather than sending a MESSAGE
- * REJECT back to us like they should if they can't cope.
- *
- * OPTION_SYNCHRONOUS
- * Enable support for synchronous transfers. Target negotiated
- * synchronous transfers will be responded to. To initiate
- * a synchronous transfer request, call
- *
- * request_synchronous (hostno, target)
- *
- * from within KGDB.
- *
- * OPTION_ALWAYS_SYNCHRONOUS
- * Negotiate for synchronous transfers with every target after
- * driver initialization or a SCSI bus reset. This is a bit dangerous,
- * since there are some dain bramaged SCSI devices which will accept
- * SDTR messages but keep talking asynchronously.
- *
- * OPTION_DISCONNECT
- * Enable support for disconnect/reconnect. To change the
- * default setting on a given host adapter, call
- *
- * request_disconnect (hostno, allow)
- *
- * where allow is non-zero to allow, 0 to disallow.
- *
- * If you really want to run 10MHz FAST SCSI-II transfers, you should
- * know that the NCR driver currently ignores parity information. Most
- * systems do 5MHz SCSI fine. I've seen a lot that have problems faster
- * than 8MHz. To play it safe, we only request 5MHz transfers.
- *
- * If you'd rather get 10MHz transfers, edit sdtr_message and change
- * the fourth byte from 50 to 25.
- */
-
-/*
- * Sponsored by
- * iX Multiuser Multitasking Magazine
- * Hannover, Germany
- * hm@ix.de
- *
- * Copyright 1993, 1994, 1995 Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@PoohSticks.ORG
- * +1 (303) 786-7975
- *
- * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
- *
- * For more information, please consult
- *
- * NCR53C810
- * SCSI I/O Processor
- * Programmer's Guide
- *
- * NCR 53C810
- * PCI-SCSI I/O Processor
- * Data Manual
- *
- * NCR 53C810/53C820
- * PCI-SCSI I/O Processor Design In Guide
- *
- * For literature on Symbios Logic Inc. formerly NCR, SCSI,
- * and Communication products please call (800) 334-5454 or
- * (719) 536-3300.
- *
- * PCI BIOS Specification Revision
- * PCI Local Bus Specification
- * PCI System Design Guide
- *
- * PCI Special Interest Group
- * M/S HF3-15A
- * 5200 N.E. Elam Young Parkway
- * Hillsboro, Oregon 97124-6497
- * +1 (503) 696-2000
- * +1 (800) 433-5177
- */
-
-/*
- * Design issues :
- * The cumulative latency needed to propagate a read/write request
- * through the file system, buffer cache, driver stacks, SCSI host, and
- * SCSI device is ultimately the limiting factor in throughput once we
- * have a sufficiently fast host adapter.
- *
- * So, to maximize performance we want to keep the ratio of latency to data
- * transfer time to a minimum by
- * 1. Minimizing the total number of commands sent (typical command latency
- * including drive and bus mastering host overhead is as high as 4.5ms)
- * to transfer a given amount of data.
- *
- * This is accomplished by placing no arbitrary limit on the number
- * of scatter/gather buffers supported, since we can transfer 1K
- * per scatter/gather buffer without Eric's cluster patches,
- * 4K with.
- *
- * 2. Minimizing the number of fatal interrupts serviced, since
- * fatal interrupts halt the SCSI I/O processor. Basically,
- * this means offloading the practical maximum amount of processing
- * to the SCSI chip.
- *
- * On the NCR53c810/820/720, this is accomplished by using
- * interrupt-on-the-fly signals when commands complete,
- * and only handling fatal errors and SDTR / WDTR messages
- * in the host code.
- *
- * On the NCR53c710, interrupts are generated as on the NCR53c8x0,
- * only the lack of a interrupt-on-the-fly facility complicates
- * things. Also, SCSI ID registers and commands are
- * bit fielded rather than binary encoded.
- *
- * On the NCR53c700 and NCR53c700-66, operations that are done via
- * indirect, table mode on the more advanced chips must be
- * replaced by calls through a jump table which
- * acts as a surrogate for the DSA. Unfortunately, this
- * will mean that we must service an interrupt for each
- * disconnect/reconnect.
- *
- * 3. Eliminating latency by pipelining operations at the different levels.
- *
- * This driver allows a configurable number of commands to be enqueued
- * for each target/lun combination (experimentally, I have discovered
- * that two seems to work best) and will ultimately allow for
- * SCSI-II tagged queuing.
- *
- *
- * Architecture :
- * This driver is built around a Linux queue of commands waiting to
- * be executed, and a shared Linux/NCR array of commands to start. Commands
- * are transferred to the array by the run_process_issue_queue() function
- * which is called whenever a command completes.
- *
- * As commands are completed, the interrupt routine is triggered,
- * looks for commands in the linked list of completed commands with
- * valid status, removes these commands from a list of running commands,
- * calls the done routine, and flags their target/luns as not busy.
- *
- * Due to limitations in the intelligence of the NCR chips, certain
- * concessions are made. In many cases, it is easier to dynamically
- * generate/fix-up code rather than calculate on the NCR at run time.
- * So, code is generated or fixed up for
- *
- * - Handling data transfers, using a variable number of MOVE instructions
- * interspersed with CALL MSG_IN, WHEN MSGIN instructions.
- *
- * The DATAIN and DATAOUT routines are separate, so that an incorrect
- * direction can be trapped, and space isn't wasted.
- *
- * It may turn out that we're better off using some sort
- * of table indirect instruction in a loop with a variable
- * sized table on the NCR53c710 and newer chips.
- *
- * - Checking for reselection (NCR53c710 and better)
- *
- * - Handling the details of SCSI context switches (NCR53c710 and better),
- * such as reprogramming appropriate synchronous parameters,
- * removing the dsa structure from the NCR's queue of outstanding
- * commands, etc.
- *
- */
-
-#include <linux/module.h>
-
-
-#include <linux/types.h>
-#include <asm/setup.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/time.h>
-#include <linux/blkdev.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <asm/pgtable.h>
-
-#ifdef CONFIG_AMIGA
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/irq.h>
-
-#define BIG_ENDIAN
-#define NO_IO_SPACE
-#endif
-
-#ifdef CONFIG_MVME16x
-#include <asm/mvme16xhw.h>
-
-#define BIG_ENDIAN
-#define NO_IO_SPACE
-#define VALID_IDS
-#endif
-
-#ifdef CONFIG_BVME6000
-#include <asm/bvme6000hw.h>
-
-#define BIG_ENDIAN
-#define NO_IO_SPACE
-#define VALID_IDS
-#endif
-
-#include "scsi.h"
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_transport_spi.h>
-#include "53c7xx.h"
-#include <linux/stat.h>
-#include <linux/stddef.h>
-
-#ifdef NO_IO_SPACE
-/*
- * The following make the definitions in 53c7xx.h (write8, etc) smaller,
- * we don't have separate i/o space anyway.
- */
-#undef inb
-#undef outb
-#undef inw
-#undef outw
-#undef inl
-#undef outl
-#define inb(x) 1
-#define inw(x) 1
-#define inl(x) 1
-#define outb(x,y) 1
-#define outw(x,y) 1
-#define outl(x,y) 1
-#endif
-
-static int check_address (unsigned long addr, int size);
-static void dump_events (struct Scsi_Host *host, int count);
-static Scsi_Cmnd * return_outstanding_commands (struct Scsi_Host *host,
- int free, int issue);
-static void hard_reset (struct Scsi_Host *host);
-static void ncr_scsi_reset (struct Scsi_Host *host);
-static void print_lots (struct Scsi_Host *host);
-static void set_synchronous (struct Scsi_Host *host, int target, int sxfer,
- int scntl3, int now_connected);
-static int datapath_residual (struct Scsi_Host *host);
-static const char * sbcl_to_phase (int sbcl);
-static void print_progress (Scsi_Cmnd *cmd);
-static void print_queues (struct Scsi_Host *host);
-static void process_issue_queue (unsigned long flags);
-static int shutdown (struct Scsi_Host *host);
-static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
-static int disable (struct Scsi_Host *host);
-static int NCR53c7xx_run_tests (struct Scsi_Host *host);
-static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id);
-static void NCR53c7x0_intfly (struct Scsi_Host *host);
-static int ncr_halt (struct Scsi_Host *host);
-static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
- *cmd);
-static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
-static void print_dsa (struct Scsi_Host *host, u32 *dsa,
- const char *prefix);
-static int print_insn (struct Scsi_Host *host, const u32 *insn,
- const char *prefix, int kernel);
-
-static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
-static void NCR53c7x0_init_fixup (struct Scsi_Host *host);
-static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
- NCR53c7x0_cmd *cmd);
-static void NCR53c7x0_soft_reset (struct Scsi_Host *host);
-
-/* Size of event list (per host adapter) */
-static int track_events = 0;
-static struct Scsi_Host *first_host = NULL; /* Head of list of NCR boards */
-static struct scsi_host_template *the_template = NULL;
-
-/* NCR53c710 script handling code */
-
-#include "53c7xx_d.h"
-#ifdef A_int_debug_sync
-#define DEBUG_SYNC_INTR A_int_debug_sync
-#endif
-int NCR53c7xx_script_len = sizeof (SCRIPT);
-int NCR53c7xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;
-#ifdef FORCE_DSA_ALIGNMENT
-int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
-#endif
-
-static char *setup_strings[] =
- {"","","","","","","",""};
-
-#define MAX_SETUP_STRINGS ARRAY_SIZE(setup_strings)
-#define SETUP_BUFFER_SIZE 200
-static char setup_buffer[SETUP_BUFFER_SIZE];
-static char setup_used[MAX_SETUP_STRINGS];
-
-void ncr53c7xx_setup (char *str, int *ints)
-{
- int i;
- char *p1, *p2;
-
- p1 = setup_buffer;
- *p1 = '\0';
- if (str)
- strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
- setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
- p1 = setup_buffer;
- i = 0;
- while (*p1 && (i < MAX_SETUP_STRINGS)) {
- p2 = strchr(p1, ',');
- if (p2) {
- *p2 = '\0';
- if (p1 != p2)
- setup_strings[i] = p1;
- p1 = p2 + 1;
- i++;
- }
- else {
- setup_strings[i] = p1;
- break;
- }
- }
- for (i=0; i<MAX_SETUP_STRINGS; i++)
- setup_used[i] = 0;
-}
-
-
-/* check_setup_strings() returns index if key found, 0 if not
- */
-
-static int check_setup_strings(char *key, int *flags, int *val, char *buf)
-{
-int x;
-char *cp;
-
- for (x=0; x<MAX_SETUP_STRINGS; x++) {
- if (setup_used[x])
- continue;
- if (!strncmp(setup_strings[x], key, strlen(key)))
- break;
- if (!strncmp(setup_strings[x], "next", strlen("next")))
- return 0;
- }
- if (x == MAX_SETUP_STRINGS)
- return 0;
- setup_used[x] = 1;
- cp = setup_strings[x] + strlen(key);
- *val = -1;
- if (*cp != ':')
- return ++x;
- cp++;
- if ((*cp >= '0') && (*cp <= '9')) {
- *val = simple_strtoul(cp,NULL,0);
- }
- return ++x;
-}
-
-
-
-/*
- * KNOWN BUGS :
- * - There is some sort of conflict when the PPP driver is compiled with
- * support for 16 channels?
- *
- * - On systems which predate the 1.3.x initialization order change,
- * the NCR driver will cause Cannot get free page messages to appear.
- * These are harmless, but I don't know of an easy way to avoid them.
- *
- * - With OPTION_DISCONNECT, on two systems under unknown circumstances,
- * we get a PHASE MISMATCH with DSA set to zero (suggests that we
- * are occurring somewhere in the reselection code) where
- * DSP=some value DCMD|DBC=same value.
- *
- * Closer inspection suggests that we may be trying to execute
- * some portion of the DSA?
- * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
- * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
- * scsi0 : no current command : unexpected phase MSGIN.
- * DSP=0x1c46cc, DCMD|DBC=0x1c46ac, DSA=0x0
- * DSPS=0x0, TEMP=0x1c3e70, DMODE=0x80
- * scsi0 : DSP->
- * 001c46cc : 0x001c46cc 0x00000000
- * 001c46d4 : 0x001c5ea0 0x000011f8
- *
- * Changed the print code in the phase_mismatch handler so
- * that we call print_lots to try to diagnose this.
- *
- */
-
-/*
- * Possible future direction of architecture for max performance :
- *
- * We're using a single start array for the NCR chip. This is
- * sub-optimal, because we cannot add a command which would conflict with
- * an executing command to this start queue, and therefore must insert the
- * next command for a given I/T/L combination after the first has completed;
- * incurring our interrupt latency between SCSI commands.
- *
- * To allow further pipelining of the NCR and host CPU operation, we want
- * to set things up so that immediately on termination of a command destined
- * for a given LUN, we get that LUN busy again.
- *
- * To do this, we need to add a 32 bit pointer to which is jumped to
- * on completion of a command. If no new command is available, this
- * would point to the usual DSA issue queue select routine.
- *
- * If one were, it would point to a per-NCR53c7x0_cmd select routine
- * which starts execution immediately, inserting the command at the head
- * of the start queue if the NCR chip is selected or reselected.
- *
- * We would change so that we keep a list of outstanding commands
- * for each unit, rather than a single running_list. We'd insert
- * a new command into the right running list; if the NCR didn't
- * have something running for that yet, we'd put it in the
- * start queue as well. Some magic needs to happen to handle the
- * race condition between the first command terminating before the
- * new one is written.
- *
- * Potential for profiling :
- * Call do_gettimeofday(struct timeval *tv) to get 800ns resolution.
- */
-
-
-/*
- * TODO :
- * 1. To support WIDE transfers, not much needs to happen. We
- * should do CHMOVE instructions instead of MOVEs when
- * we have scatter/gather segments of uneven length. When
- * we do this, we need to handle the case where we disconnect
- * between segments.
- *
- * 2. Currently, when Icky things happen we do a FATAL(). Instead,
- * we want to do an integrity check on the parts of the NCR hostdata
- * structure which were initialized at boot time; FATAL() if that
- * fails, and otherwise try to recover. Keep track of how many
- * times this has happened within a single SCSI command; if it
- * gets excessive, then FATAL().
- *
- * 3. Parity checking is currently disabled, and a few things should
- * happen here now that we support synchronous SCSI transfers :
- * 1. On soft-reset, we shoould set the EPC (Enable Parity Checking)
- * and AAP (Assert SATN/ on parity error) bits in SCNTL0.
- *
- * 2. We should enable the parity interrupt in the SIEN0 register.
- *
- * 3. intr_phase_mismatch() needs to believe that message out is
- * always an "acceptable" phase to have a mismatch in. If
- * the old phase was MSG_IN, we should send a MESSAGE PARITY
- * error. If the old phase was something else, we should send
- * a INITIATOR_DETECTED_ERROR message. Note that this could
- * cause a RESTORE POINTERS message; so we should handle that
- * correctly first. Instead, we should probably do an
- * initiator_abort.
- *
- * 4. MPEE bit of CTEST4 should be set so we get interrupted if
- * we detect an error.
- *
- *
- * 5. The initial code has been tested on the NCR53c810. I don't
- * have access to NCR53c700, 700-66 (Forex boards), NCR53c710
- * (NCR Pentium systems), NCR53c720, NCR53c820, or NCR53c825 boards to
- * finish development on those platforms.
- *
- * NCR53c820/825/720 - need to add wide transfer support, including WDTR
- * negotiation, programming of wide transfer capabilities
- * on reselection and table indirect selection.
- *
- * NCR53c710 - need to add fatal interrupt or GEN code for
- * command completion signaling. Need to modify all
- * SDID, SCID, etc. registers, and table indirect select code
- * since these use bit fielded (ie 1<<target) instead of
- * binary encoded target ids. Need to accommodate
- * different register mappings, probably scan through
- * the SCRIPT code and change the non SFBR register operand
- * of all MOVE instructions.
- *
- * It is rather worse than this actually, the 710 corrupts
- * both TEMP and DSA when you do a MOVE MEMORY. This
- * screws you up all over the place. MOVE MEMORY 4 with a
- * destination of DSA seems to work OK, which helps some.
- * Richard Hirst richard@sleepie.demon.co.uk
- *
- * NCR53c700/700-66 - need to add code to refix addresses on
- * every nexus change, eliminate all table indirect code,
- * very messy.
- *
- * 6. The NCR53c7x0 series is very popular on other platforms that
- * could be running Linux - ie, some high performance AMIGA SCSI
- * boards use it.
- *
- * So, I should include #ifdef'd code so that it is
- * compatible with these systems.
- *
- * Specifically, the little Endian assumptions I made in my
- * bit fields need to change, and if the NCR doesn't see memory
- * the right way, we need to provide options to reverse words
- * when the scripts are relocated.
- *
- * 7. Use vremap() to access memory mapped boards.
- */
-
-/*
- * Allow for simultaneous existence of multiple SCSI scripts so we
- * can have a single driver binary for all of the family.
- *
- * - one for NCR53c700 and NCR53c700-66 chips (not yet supported)
- * - one for rest (only the NCR53c810, 815, 820, and 825 are currently
- * supported)
- *
- * So that we only need two SCSI scripts, we need to modify things so
- * that we fixup register accesses in READ/WRITE instructions, and
- * we'll also have to accommodate the bit vs. binary encoding of IDs
- * with the 7xx chips.
- */
-
-#define ROUNDUP(adr,type) \
- ((void *) (((long) (adr) + sizeof(type) - 1) & ~(sizeof(type) - 1)))
-
-
-/*
- * Function: issue_to_cmd
- *
- * Purpose: convert jump instruction in issue array to NCR53c7x0_cmd
- * structure pointer.
- *
- * Inputs; issue - pointer to start of NOP or JUMP instruction
- * in issue array.
- *
- * Returns: pointer to command on success; 0 if opcode is NOP.
- */
-
-static inline struct NCR53c7x0_cmd *
-issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
- u32 *issue)
-{
- return (issue[0] != hostdata->NOP_insn) ?
- /*
- * If the IF TRUE bit is set, it's a JUMP instruction. The
- * operand is a bus pointer to the dsa_begin routine for this DSA. The
- * dsa field of the NCR53c7x0_cmd structure starts with the
- * DSA code template. By converting to a virtual address,
- * subtracting the code template size, and offset of the
- * dsa field, we end up with a pointer to the start of the
- * structure (alternatively, we could use the
- * dsa_cmnd field, an anachronism from when we weren't
- * sure what the relationship between the NCR structures
- * and host structures were going to be.
- */
- (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) -
- (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
- offsetof(struct NCR53c7x0_cmd, dsa))
- /* If the IF TRUE bit is not set, it's a NOP */
- : NULL;
-}
-
-
-/*
- * FIXME: we should junk these, in favor of synchronous_want and
- * wide_want in the NCR53c7x0_hostdata structure.
- */
-
-/* Template for "preferred" synchronous transfer parameters. */
-
-static const unsigned char sdtr_message[] = {
-#ifdef CONFIG_SCSI_NCR53C7xx_FAST
- EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */
-#else
- EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */
-#endif
-};
-
-/* Template to request asynchronous transfers */
-
-static const unsigned char async_message[] = {
- EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */
-};
-
-/* Template for "preferred" WIDE transfer parameters */
-
-static const unsigned char wdtr_message[] = {
- EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */
-};
-
-#if 0
-/*
- * Function : struct Scsi_Host *find_host (int host)
- *
- * Purpose : KGDB support function which translates a host number
- * to a host structure.
- *
- * Inputs : host - number of SCSI host
- *
- * Returns : NULL on failure, pointer to host structure on success.
- */
-
-static struct Scsi_Host *
-find_host (int host) {
- struct Scsi_Host *h;
- for (h = first_host; h && h->host_no != host; h = h->next);
- if (!h) {
- printk (KERN_ALERT "scsi%d not found\n", host);
- return NULL;
- } else if (h->hostt != the_template) {
- printk (KERN_ALERT "scsi%d is not a NCR board\n", host);
- return NULL;
- }
- return h;
-}
-
-#if 0
-/*
- * Function : request_synchronous (int host, int target)
- *
- * Purpose : KGDB interface which will allow us to negotiate for
- * synchronous transfers. This ill be replaced with a more
- * integrated function; perhaps a new entry in the scsi_host
- * structure, accessible via an ioctl() or perhaps /proc/scsi.
- *
- * Inputs : host - number of SCSI host; target - number of target.
- *
- * Returns : 0 when negotiation has been setup for next SCSI command,
- * -1 on failure.
- */
-
-static int
-request_synchronous (int host, int target) {
- struct Scsi_Host *h;
- struct NCR53c7x0_hostdata *hostdata;
- unsigned long flags;
- if (target < 0) {
- printk (KERN_ALERT "target %d is bogus\n", target);
- return -1;
- }
- if (!(h = find_host (host)))
- return -1;
- else if (h->this_id == target) {
- printk (KERN_ALERT "target %d is host ID\n", target);
- return -1;
- }
- else if (target >= h->max_id) {
- printk (KERN_ALERT "target %d exceeds maximum of %d\n", target,
- h->max_id);
- return -1;
- }
- hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0];
-
- local_irq_save(flags);
- if (hostdata->initiate_sdtr & (1 << target)) {
- local_irq_restore(flags);
- printk (KERN_ALERT "target %d already doing SDTR\n", target);
- return -1;
- }
- hostdata->initiate_sdtr |= (1 << target);
- local_irq_restore(flags);
- return 0;
-}
-#endif
-
-/*
- * Function : request_disconnect (int host, int on_or_off)
- *
- * Purpose : KGDB support function, tells us to allow or disallow
- * disconnections.
- *
- * Inputs : host - number of SCSI host; on_or_off - non-zero to allow,
- * zero to disallow.
- *
- * Returns : 0 on success, * -1 on failure.
- */
-
-static int
-request_disconnect (int host, int on_or_off) {
- struct Scsi_Host *h;
- struct NCR53c7x0_hostdata *hostdata;
- if (!(h = find_host (host)))
- return -1;
- hostdata = (struct NCR53c7x0_hostdata *) h->hostdata[0];
- if (on_or_off)
- hostdata->options |= OPTION_DISCONNECT;
- else
- hostdata->options &= ~OPTION_DISCONNECT;
- return 0;
-}
-#endif
-
-/*
- * Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host)
- *
- * Purpose : Initialize internal structures, as required on startup, or
- * after a SCSI bus reset.
- *
- * Inputs : host - pointer to this host adapter's structure
- */
-
-static void
-NCR53c7x0_driver_init (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int i, j;
- u32 *ncrcurrent;
-
- for (i = 0; i < 16; ++i) {
- hostdata->request_sense[i] = 0;
- for (j = 0; j < 8; ++j)
- hostdata->busy[i][j] = 0;
- set_synchronous (host, i, /* sxfer */ 0, hostdata->saved_scntl3, 0);
- }
- hostdata->issue_queue = NULL;
- hostdata->running_list = hostdata->finished_queue =
- hostdata->ncrcurrent = NULL;
- for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, ncrcurrent += 2) {
- ncrcurrent[0] = hostdata->NOP_insn;
- ncrcurrent[1] = 0xdeadbeef;
- }
- ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
- ncrcurrent[1] = (u32) virt_to_bus (hostdata->script) +
- hostdata->E_wait_reselect;
- hostdata->reconnect_dsa_head = 0;
- hostdata->addr_reconnect_dsa_head = (u32)
- virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
- hostdata->expecting_iid = 0;
- hostdata->expecting_sto = 0;
- if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS)
- hostdata->initiate_sdtr = 0xffff;
- else
- hostdata->initiate_sdtr = 0;
- hostdata->talked_to = 0;
- hostdata->idle = 1;
-}
-
-/*
- * Function : static int clock_to_ccf_710 (int clock)
- *
- * Purpose : Return the clock conversion factor for a given SCSI clock.
- *
- * Inputs : clock - SCSI clock expressed in Hz.
- *
- * Returns : ccf on success, -1 on failure.
- */
-
-static int
-clock_to_ccf_710 (int clock) {
- if (clock <= 16666666)
- return -1;
- if (clock <= 25000000)
- return 2; /* Divide by 1.0 */
- else if (clock <= 37500000)
- return 1; /* Divide by 1.5 */
- else if (clock <= 50000000)
- return 0; /* Divide by 2.0 */
- else if (clock <= 66000000)
- return 3; /* Divide by 3.0 */
- else
- return -1;
-}
-
-/*
- * Function : static int NCR53c7x0_init (struct Scsi_Host *host)
- *
- * Purpose : initialize the internal structures for a given SCSI host
- *
- * Inputs : host - pointer to this host adapter's structure
- *
- * Preconditions : when this function is called, the chip_type
- * field of the hostdata structure MUST have been set.
- *
- * Returns : 0 on success, -1 on failure.
- */
-
-int
-NCR53c7x0_init (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- int i, ccf;
- unsigned char revision;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- /*
- * There are some things which we need to know about in order to provide
- * a semblance of support. Print 'em if they aren't what we expect,
- * otherwise don't add to the noise.
- *
- * -1 means we don't know what to expect.
- */
- int val, flags;
- char buf[32];
- int expected_id = -1;
- int expected_clock = -1;
- int uninitialized = 0;
-#ifdef NO_IO_SPACE
- int expected_mapping = OPTION_MEMORY_MAPPED;
-#else
- int expected_mapping = OPTION_IO_MAPPED;
-#endif
- for (i=0;i<7;i++)
- hostdata->valid_ids[i] = 1; /* Default all ID's to scan */
-
- /* Parse commandline flags */
- if (check_setup_strings("noasync",&flags,&val,buf))
- {
- hostdata->options |= OPTION_NO_ASYNC;
- hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
- }
-
- if (check_setup_strings("nosync",&flags,&val,buf))
- {
- hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
- }
-
- if (check_setup_strings("nodisconnect",&flags,&val,buf))
- hostdata->options &= ~OPTION_DISCONNECT;
-
- if (check_setup_strings("validids",&flags,&val,buf))
- {
- for (i=0;i<7;i++)
- hostdata->valid_ids[i] = val & (1<<i);
- }
-
- if ((i = check_setup_strings("next",&flags,&val,buf)))
- {
- while (i)
- setup_used[--i] = 1;
- }
-
- if (check_setup_strings("opthi",&flags,&val,buf))
- hostdata->options = (long long)val << 32;
- if (check_setup_strings("optlo",&flags,&val,buf))
- hostdata->options |= val;
-
- NCR53c7x0_local_setup(host);
- switch (hostdata->chip) {
- case 710:
- case 770:
- hostdata->dstat_sir_intr = NCR53c7x0_dstat_sir_intr;
- hostdata->init_save_regs = NULL;
- hostdata->dsa_fixup = NCR53c7xx_dsa_fixup;
- hostdata->init_fixup = NCR53c7x0_init_fixup;
- hostdata->soft_reset = NCR53c7x0_soft_reset;
- hostdata->run_tests = NCR53c7xx_run_tests;
- expected_clock = hostdata->scsi_clock;
- expected_id = 7;
- break;
- default:
- printk ("scsi%d : chip type of %d is not supported yet, detaching.\n",
- host->host_no, hostdata->chip);
- scsi_unregister (host);
- return -1;
- }
-
- /* Assign constants accessed by NCR */
- hostdata->NCR53c7xx_zero = 0;
- hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
- hostdata->NCR53c7xx_msg_abort = ABORT;
- hostdata->NCR53c7xx_msg_nop = NOP;
- hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
- if (expected_mapping == -1 ||
- (hostdata->options & (OPTION_MEMORY_MAPPED)) !=
- (expected_mapping & OPTION_MEMORY_MAPPED))
- printk ("scsi%d : using %s mapped access\n", host->host_no,
- (hostdata->options & OPTION_MEMORY_MAPPED) ? "memory" :
- "io");
-
- hostdata->dmode = (hostdata->chip == 700 || hostdata->chip == 70066) ?
- DMODE_REG_00 : DMODE_REG_10;
- hostdata->istat = ((hostdata->chip / 100) == 8) ?
- ISTAT_REG_800 : ISTAT_REG_700;
-
-/* We have to assume that this may be the first access to the chip, so
- * we must set EA in DCNTL. */
-
- NCR53c7x0_write8 (DCNTL_REG, DCNTL_10_EA|DCNTL_10_COM);
-
-
-/* Only the ISTAT register is readable when the NCR is running, so make
- sure it's halted. */
- ncr_halt(host);
-
-/*
- * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
- * as does the 710 with one bit per SCSI ID. Conversely, the NCR
- * uses a normal, 3 bit binary representation of these values.
- *
- * Get the rest of the NCR documentation, and FIND OUT where the change
- * was.
- */
-
-#if 0
- /* May not be able to do this - chip my not have been set up yet */
- tmp = hostdata->this_id_mask = NCR53c7x0_read8(SCID_REG);
- for (host->this_id = 0; tmp != 1; tmp >>=1, ++host->this_id);
-#else
- host->this_id = 7;
-#endif
-
-/*
- * Note : we should never encounter a board setup for ID0. So,
- * if we see ID0, assume that it was uninitialized and set it
- * to the industry standard 7.
- */
- if (!host->this_id) {
- printk("scsi%d : initiator ID was %d, changing to 7\n",
- host->host_no, host->this_id);
- host->this_id = 7;
- hostdata->this_id_mask = 1 << 7;
- uninitialized = 1;
- };
-
- if (expected_id == -1 || host->this_id != expected_id)
- printk("scsi%d : using initiator ID %d\n", host->host_no,
- host->this_id);
-
- /*
- * Save important registers to allow a soft reset.
- */
-
- /*
- * CTEST7 controls cache snooping, burst mode, and support for
- * external differential drivers. This isn't currently used - the
- * default value may not be optimal anyway.
- * Even worse, it may never have been set up since reset.
- */
- hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
- revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
- switch (revision) {
- case 1: revision = 0; break;
- case 2: revision = 1; break;
- case 4: revision = 2; break;
- case 8: revision = 3; break;
- default: revision = 255; break;
- }
- printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
-
- if ((revision == 0 || revision == 255) && (hostdata->options & (OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS)))
- {
- printk ("scsi%d: Disabling sync working and disconnect/reselect\n",
- host->host_no);
- hostdata->options &= ~(OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS);
- }
-
- /*
- * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
- * on 800 series chips, it allows for a totem-pole IRQ driver.
- * NOTE saved_dcntl currently overwritten in init function.
- * The value read here may be garbage anyway, MVME16x board at least
- * does not initialise chip if kernel arrived via tftp.
- */
-
- hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG);
-
- /*
- * DMODE controls DMA burst length, and on 700 series chips,
- * 286 mode and bus width
- * NOTE: On MVME16x, chip may have been reset, so this could be a
- * power-on/reset default value.
- */
- hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode);
-
- /*
- * Now that burst length and enabled/disabled status is known,
- * clue the user in on it.
- */
-
- ccf = clock_to_ccf_710 (expected_clock);
-
- for (i = 0; i < 16; ++i)
- hostdata->cmd_allocated[i] = 0;
-
- if (hostdata->init_save_regs)
- hostdata->init_save_regs (host);
- if (hostdata->init_fixup)
- hostdata->init_fixup (host);
-
- if (!the_template) {
- the_template = host->hostt;
- first_host = host;
- }
-
- /*
- * Linux SCSI drivers have always been plagued with initialization
- * problems - some didn't work with the BIOS disabled since they expected
- * initialization from it, some didn't work when the networking code
- * was enabled and registers got scrambled, etc.
- *
- * To avoid problems like this, in the future, we will do a soft
- * reset on the SCSI chip, taking it back to a sane state.
- */
-
- hostdata->soft_reset (host);
-
-#if 1
- hostdata->debug_count_limit = -1;
-#else
- hostdata->debug_count_limit = 1;
-#endif
- hostdata->intrs = -1;
- hostdata->resets = -1;
- memcpy ((void *) hostdata->synchronous_want, (void *) sdtr_message,
- sizeof (hostdata->synchronous_want));
-
- NCR53c7x0_driver_init (host);
-
- if (request_irq(host->irq, NCR53c7x0_intr, IRQF_SHARED, "53c7xx", host))
- {
- printk("scsi%d : IRQ%d not free, detaching\n",
- host->host_no, host->irq);
- goto err_unregister;
- }
-
- if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
- (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
- /* XXX Should disable interrupts, etc. here */
- goto err_free_irq;
- } else {
- if (host->io_port) {
- host->n_io_port = 128;
- if (!request_region (host->io_port, host->n_io_port, "ncr53c7xx"))
- goto err_free_irq;
- }
- }
-
- if (NCR53c7x0_read8 (SBCL_REG) & SBCL_BSY) {
- printk ("scsi%d : bus wedge, doing SCSI reset\n", host->host_no);
- hard_reset (host);
- }
- return 0;
-
- err_free_irq:
- free_irq(host->irq, NCR53c7x0_intr);
- err_unregister:
- scsi_unregister(host);
- return -1;
-}
-
-/*
- * Function : int ncr53c7xx_init(struct scsi_host_template *tpnt, int board, int chip,
- * unsigned long base, int io_port, int irq, int dma, long long options,
- * int clock);
- *
- * Purpose : initializes a NCR53c7,8x0 based on base addresses,
- * IRQ, and DMA channel.
- *
- * Inputs : tpnt - Template for this SCSI adapter, board - board level
- * product, chip - 710
- *
- * Returns : 0 on success, -1 on failure.
- *
- */
-
-int
-ncr53c7xx_init (struct scsi_host_template *tpnt, int board, int chip,
- unsigned long base, int io_port, int irq, int dma,
- long long options, int clock)
-{
- struct Scsi_Host *instance;
- struct NCR53c7x0_hostdata *hostdata;
- char chip_str[80];
- int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0,
- schedule_size = 0, ok = 0;
- void *tmp;
- unsigned long page;
-
- switch (chip) {
- case 710:
- case 770:
- schedule_size = (tpnt->can_queue + 1) * 8 /* JUMP instruction size */;
- script_len = NCR53c7xx_script_len;
- dsa_len = NCR53c7xx_dsa_len;
- options |= OPTION_INTFLY;
- sprintf (chip_str, "NCR53c%d", chip);
- break;
- default:
- printk("scsi-ncr53c7xx : unsupported SCSI chip %d\n", chip);
- return -1;
- }
-
- printk("scsi-ncr53c7xx : %s at memory 0x%lx, io 0x%x, irq %d",
- chip_str, base, io_port, irq);
- if (dma == DMA_NONE)
- printk("\n");
- else
- printk(", dma %d\n", dma);
-
- if (options & OPTION_DEBUG_PROBE_ONLY) {
- printk ("scsi-ncr53c7xx : probe only enabled, aborting initialization\n");
- return -1;
- }
-
- max_cmd_size = sizeof(struct NCR53c7x0_cmd) + dsa_len +
- /* Size of dynamic part of command structure : */
- 2 * /* Worst case : we don't know if we need DATA IN or DATA out */
- ( 2 * /* Current instructions per scatter/gather segment */
- tpnt->sg_tablesize +
- 3 /* Current startup / termination required per phase */
- ) *
- 8 /* Each instruction is eight bytes */;
-
- /* Allocate fixed part of hostdata, dynamic part to hold appropriate
- SCSI SCRIPT(tm) plus a single, maximum-sized NCR53c7x0_cmd structure.
-
- We need a NCR53c7x0_cmd structure for scan_scsis() when we are
- not loaded as a module, and when we're loaded as a module, we
- can't use a non-dynamically allocated structure because modules
- are vmalloc()'d, which can allow structures to cross page
- boundaries and breaks our physical/virtual address assumptions
- for DMA.
-
- So, we stick it past the end of our hostdata structure.
-
- ASSUMPTION :
- Regardless of how many simultaneous SCSI commands we allow,
- the probe code only executes a _single_ instruction at a time,
- so we only need one here, and don't need to allocate NCR53c7x0_cmd
- structures for each target until we are no longer in scan_scsis
- and kmalloc() has become functional (memory_init() happens
- after all device driver initialization).
- */
-
- size = sizeof(struct NCR53c7x0_hostdata) + script_len +
- /* Note that alignment will be guaranteed, since we put the command
- allocated at probe time after the fixed-up SCSI script, which
- consists of 32 bit words, aligned on a 32 bit boundary. But
- on a 64bit machine we need 8 byte alignment for hostdata->free, so
- we add in another 4 bytes to take care of potential misalignment
- */
- (sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size;
-
- page = __get_free_pages(GFP_ATOMIC,1);
- if(page==0)
- {
- printk(KERN_ERR "53c7xx: out of memory.\n");
- return -ENOMEM;
- }
-#ifdef FORCE_DSA_ALIGNMENT
- /*
- * 53c710 rev.0 doesn't have an add-with-carry instruction.
- * Ensure we allocate enough memory to force DSA alignment.
- */
- size += 256;
-#endif
- /* Size should be < 8K, so we can fit it in two pages. */
- if (size > 8192) {
- printk(KERN_ERR "53c7xx: hostdata > 8K\n");
- return -1;
- }
-
- instance = scsi_register (tpnt, 4);
- if (!instance)
- {
- free_page(page);
- return -1;
- }
- instance->hostdata[0] = page;
- memset((void *)instance->hostdata[0], 0, 8192);
- cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
- cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
- kernel_set_cachemode((void *)instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
-
- /* FIXME : if we ever support an ISA NCR53c7xx based board, we
- need to check if the chip is running in a 16 bit mode, and if so
- unregister it if it is past the 16M (0x1000000) mark */
-
- hostdata = (struct NCR53c7x0_hostdata *)instance->hostdata[0];
- hostdata->size = size;
- hostdata->script_count = script_len / sizeof(u32);
- hostdata->board = board;
- hostdata->chip = chip;
-
- /*
- * Being memory mapped is more desirable, since
- *
- * - Memory accesses may be faster.
- *
- * - The destination and source address spaces are the same for
- * all instructions, meaning we don't have to twiddle dmode or
- * any other registers.
- *
- * So, we try for memory mapped, and if we don't get it,
- * we go for port mapped, and that failing we tell the user
- * it can't work.
- */
-
- if (base) {
- instance->base = base;
- /* Check for forced I/O mapping */
- if (!(options & OPTION_IO_MAPPED)) {
- options |= OPTION_MEMORY_MAPPED;
- ok = 1;
- }
- } else {
- options &= ~OPTION_MEMORY_MAPPED;
- }
-
- if (io_port) {
- instance->io_port = io_port;
- options |= OPTION_IO_MAPPED;
- ok = 1;
- } else {
- options &= ~OPTION_IO_MAPPED;
- }
-
- if (!ok) {
- printk ("scsi%d : not initializing, no I/O or memory mapping known \n",
- instance->host_no);
- scsi_unregister (instance);
- return -1;
- }
- instance->irq = irq;
- instance->dma_channel = dma;
-
- hostdata->options = options;
- hostdata->dsa_len = dsa_len;
- hostdata->max_cmd_size = max_cmd_size;
- hostdata->num_cmds = 1;
- hostdata->scsi_clock = clock;
- /* Initialize single command */
- tmp = (hostdata->script + hostdata->script_count);
-#ifdef FORCE_DSA_ALIGNMENT
- {
- void *t = ROUNDUP(tmp, void *);
- if (((u32)t & 0xff) > CmdPageStart)
- t = (void *)((u32)t + 255);
- t = (void *)(((u32)t & ~0xff) + CmdPageStart);
- hostdata->free = t;
-#if 0
- printk ("scsi: Registered size increased by 256 to %d\n", size);
- printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
- printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
- (u32)tmp, (u32)t);
-#endif
- }
-#else
- hostdata->free = ROUNDUP(tmp, void *);
-#endif
- hostdata->free->real = tmp;
- hostdata->free->size = max_cmd_size;
- hostdata->free->free = NULL;
- hostdata->free->next = NULL;
- hostdata->extra_allocate = 0;
-
- /* Allocate command start code space */
- hostdata->schedule = (chip == 700 || chip == 70066) ?
- NULL : (u32 *) ((char *)hostdata->free + max_cmd_size);
-
-/*
- * For diagnostic purposes, we don't really care how fast things blaze.
- * For profiling, we want to access the 800ns resolution system clock,
- * using a 'C' call on the host processor.
- *
- * Therefore, there's no need for the NCR chip to directly manipulate
- * this data, and we should put it wherever is most convenient for
- * Linux.
- */
- if (track_events)
- hostdata->events = (struct NCR53c7x0_event *) (track_events ?
- vmalloc (sizeof (struct NCR53c7x0_event) * track_events) : NULL);
- else
- hostdata->events = NULL;
-
- if (hostdata->events) {
- memset ((void *) hostdata->events, 0, sizeof(struct NCR53c7x0_event) *
- track_events);
- hostdata->event_size = track_events;
- hostdata->event_index = 0;
- } else
- hostdata->event_size = 0;
-
- return NCR53c7x0_init(instance);
-}
-
-
-/*
- * Function : static void NCR53c7x0_init_fixup (struct Scsi_Host *host)
- *
- * Purpose : copy and fixup the SCSI SCRIPTS(tm) code for this device.
- *
- * Inputs : host - pointer to this host adapter's structure
- *
- */
-
-static void
-NCR53c7x0_init_fixup (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned char tmp;
- int i, ncr_to_memory, memory_to_ncr;
- u32 base;
- NCR53c7x0_local_setup(host);
-
-
- /* XXX - NOTE : this code MUST be made endian aware */
- /* Copy code into buffer that was allocated at detection time. */
- memcpy ((void *) hostdata->script, (void *) SCRIPT,
- sizeof(SCRIPT));
- /* Fixup labels */
- for (i = 0; i < PATCHES; ++i)
- hostdata->script[LABELPATCHES[i]] +=
- virt_to_bus(hostdata->script);
- /* Fixup addresses of constants that used to be EXTERNAL */
-
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_abort)));
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_reject)));
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero,
- virt_to_bus(&(hostdata->NCR53c7xx_zero)));
- patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink,
- virt_to_bus(&(hostdata->NCR53c7xx_sink)));
- patch_abs_32 (hostdata->script, 0, NOP_insn,
- virt_to_bus(&(hostdata->NOP_insn)));
- patch_abs_32 (hostdata->script, 0, schedule,
- virt_to_bus((void *) hostdata->schedule));
-
- /* Fixup references to external variables: */
- for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i)
- hostdata->script[EXTERNAL_PATCHES[i].offset] +=
- virt_to_bus(EXTERNAL_PATCHES[i].address);
-
- /*
- * Fixup absolutes set at boot-time.
- *
- * All non-code absolute variables suffixed with "dsa_" and "int_"
- * are constants, and need no fixup provided the assembler has done
- * it for us (I don't know what the "real" NCR assembler does in
- * this case, my assembler does the right magic).
- */
-
- patch_abs_rwri_data (hostdata->script, 0, dsa_save_data_pointer,
- Ent_dsa_code_save_data_pointer - Ent_dsa_zero);
- patch_abs_rwri_data (hostdata->script, 0, dsa_restore_pointers,
- Ent_dsa_code_restore_pointers - Ent_dsa_zero);
- patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
- Ent_dsa_code_check_reselect - Ent_dsa_zero);
-
- /*
- * Just for the hell of it, preserve the settings of
- * Burst Length and Enable Read Line bits from the DMODE
- * register. Make sure SCRIPTS start automagically.
- */
-
-#if defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
- /* We know better what we want than 16xBug does! */
- tmp = DMODE_10_BL_8 | DMODE_10_FC2;
-#else
- tmp = NCR53c7x0_read8(DMODE_REG_10);
- tmp &= (DMODE_BL_MASK | DMODE_10_FC2 | DMODE_10_FC1 | DMODE_710_PD |
- DMODE_710_UO);
-#endif
-
- if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
- base = (u32) host->io_port;
- memory_to_ncr = tmp|DMODE_800_DIOM;
- ncr_to_memory = tmp|DMODE_800_SIOM;
- } else {
- base = virt_to_bus((void *)host->base);
- memory_to_ncr = ncr_to_memory = tmp;
- }
-
- /* SCRATCHB_REG_10 == SCRATCHA_REG_800, as it happens */
- patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800);
- patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG);
- patch_abs_32 (hostdata->script, 0, addr_dsa, base + DSA_REG);
-
- /*
- * I needed some variables in the script to be accessible to
- * both the NCR chip and the host processor. For these variables,
- * I made the arbitrary decision to store them directly in the
- * hostdata structure rather than in the RELATIVE area of the
- * SCRIPTS.
- */
-
-
- patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_memory, tmp);
- patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_ncr, memory_to_ncr);
- patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
-
- patch_abs_32 (hostdata->script, 0, msg_buf,
- virt_to_bus((void *)&(hostdata->msg_buf)));
- patch_abs_32 (hostdata->script, 0, reconnect_dsa_head,
- virt_to_bus((void *)&(hostdata->reconnect_dsa_head)));
- patch_abs_32 (hostdata->script, 0, addr_reconnect_dsa_head,
- virt_to_bus((void *)&(hostdata->addr_reconnect_dsa_head)));
- patch_abs_32 (hostdata->script, 0, reselected_identify,
- virt_to_bus((void *)&(hostdata->reselected_identify)));
-/* reselected_tag is currently unused */
-#if 0
- patch_abs_32 (hostdata->script, 0, reselected_tag,
- virt_to_bus((void *)&(hostdata->reselected_tag)));
-#endif
-
- patch_abs_32 (hostdata->script, 0, test_dest,
- virt_to_bus((void*)&hostdata->test_dest));
- patch_abs_32 (hostdata->script, 0, test_src,
- virt_to_bus(&hostdata->test_source));
- patch_abs_32 (hostdata->script, 0, saved_dsa,
- virt_to_bus((void *)&hostdata->saved2_dsa));
- patch_abs_32 (hostdata->script, 0, emulfly,
- virt_to_bus((void *)&hostdata->emulated_intfly));
-
- patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
- (unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
-
-/* These are for event logging; the ncr_event enum contains the
- actual interrupt numbers. */
-#ifdef A_int_EVENT_SELECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT, (u32) EVENT_SELECT);
-#endif
-#ifdef A_int_EVENT_DISCONNECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_DISCONNECT, (u32) EVENT_DISCONNECT);
-#endif
-#ifdef A_int_EVENT_RESELECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT, (u32) EVENT_RESELECT);
-#endif
-#ifdef A_int_EVENT_COMPLETE
- patch_abs_32 (hostdata->script, 0, int_EVENT_COMPLETE, (u32) EVENT_COMPLETE);
-#endif
-#ifdef A_int_EVENT_IDLE
- patch_abs_32 (hostdata->script, 0, int_EVENT_IDLE, (u32) EVENT_IDLE);
-#endif
-#ifdef A_int_EVENT_SELECT_FAILED
- patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT_FAILED,
- (u32) EVENT_SELECT_FAILED);
-#endif
-#ifdef A_int_EVENT_BEFORE_SELECT
- patch_abs_32 (hostdata->script, 0, int_EVENT_BEFORE_SELECT,
- (u32) EVENT_BEFORE_SELECT);
-#endif
-#ifdef A_int_EVENT_RESELECT_FAILED
- patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT_FAILED,
- (u32) EVENT_RESELECT_FAILED);
-#endif
-
- /*
- * Make sure the NCR and Linux code agree on the location of
- * certain fields.
- */
-
- hostdata->E_accept_message = Ent_accept_message;
- hostdata->E_command_complete = Ent_command_complete;
- hostdata->E_cmdout_cmdout = Ent_cmdout_cmdout;
- hostdata->E_data_transfer = Ent_data_transfer;
- hostdata->E_debug_break = Ent_debug_break;
- hostdata->E_dsa_code_template = Ent_dsa_code_template;
- hostdata->E_dsa_code_template_end = Ent_dsa_code_template_end;
- hostdata->E_end_data_transfer = Ent_end_data_transfer;
- hostdata->E_initiator_abort = Ent_initiator_abort;
- hostdata->E_msg_in = Ent_msg_in;
- hostdata->E_other_transfer = Ent_other_transfer;
- hostdata->E_other_in = Ent_other_in;
- hostdata->E_other_out = Ent_other_out;
- hostdata->E_reject_message = Ent_reject_message;
- hostdata->E_respond_message = Ent_respond_message;
- hostdata->E_select = Ent_select;
- hostdata->E_select_msgout = Ent_select_msgout;
- hostdata->E_target_abort = Ent_target_abort;
-#ifdef Ent_test_0
- hostdata->E_test_0 = Ent_test_0;
-#endif
- hostdata->E_test_1 = Ent_test_1;
- hostdata->E_test_2 = Ent_test_2;
-#ifdef Ent_test_3
- hostdata->E_test_3 = Ent_test_3;
-#endif
- hostdata->E_wait_reselect = Ent_wait_reselect;
- hostdata->E_dsa_code_begin = Ent_dsa_code_begin;
-
- hostdata->dsa_cmdout = A_dsa_cmdout;
- hostdata->dsa_cmnd = A_dsa_cmnd;
- hostdata->dsa_datain = A_dsa_datain;
- hostdata->dsa_dataout = A_dsa_dataout;
- hostdata->dsa_end = A_dsa_end;
- hostdata->dsa_msgin = A_dsa_msgin;
- hostdata->dsa_msgout = A_dsa_msgout;
- hostdata->dsa_msgout_other = A_dsa_msgout_other;
- hostdata->dsa_next = A_dsa_next;
- hostdata->dsa_select = A_dsa_select;
- hostdata->dsa_start = Ent_dsa_code_template - Ent_dsa_zero;
- hostdata->dsa_status = A_dsa_status;
- hostdata->dsa_jump_dest = Ent_dsa_code_fix_jump - Ent_dsa_zero +
- 8 /* destination operand */;
-
- /* sanity check */
- if (A_dsa_fields_start != Ent_dsa_code_template_end -
- Ent_dsa_zero)
- printk("scsi%d : NCR dsa_fields start is %d not %d\n",
- host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end -
- Ent_dsa_zero);
-
- printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
- virt_to_bus(hostdata->script), hostdata->script);
-}
-
-/*
- * Function : static int NCR53c7xx_run_tests (struct Scsi_Host *host)
- *
- * Purpose : run various verification tests on the NCR chip,
- * including interrupt generation, and proper bus mastering
- * operation.
- *
- * Inputs : host - a properly initialized Scsi_Host structure
- *
- * Preconditions : the NCR chip must be in a halted state.
- *
- * Returns : 0 if all tests were successful, -1 on error.
- *
- */
-
-static int
-NCR53c7xx_run_tests (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long timeout;
- u32 start;
- int failed, i;
- unsigned long flags;
- NCR53c7x0_local_setup(host);
-
- /* The NCR chip _must_ be idle to run the test scripts */
-
- local_irq_save(flags);
- if (!hostdata->idle) {
- printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
-
- /*
- * Check for functional interrupts, this could work as an
- * autoprobe routine.
- */
-
- if ((hostdata->options & OPTION_DEBUG_TEST1) &&
- hostdata->state != STATE_DISABLED) {
- hostdata->idle = 0;
- hostdata->test_running = 1;
- hostdata->test_completed = -1;
- hostdata->test_dest = 0;
- hostdata->test_source = 0xdeadbeef;
- start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
- hostdata->state = STATE_RUNNING;
- printk ("scsi%d : test 1", host->host_no);
- NCR53c7x0_write32 (DSP_REG, start);
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
- DCNTL_STD);
- printk (" started\n");
- local_irq_restore(flags);
-
- /*
- * This is currently a .5 second timeout, since (in theory) no slow
- * board will take that long. In practice, we've seen one
- * pentium which occassionally fails with this, but works with
- * 10 times as much?
- */
-
- timeout = jiffies + 5 * HZ / 10;
- while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
- barrier();
-
- failed = 1;
- if (hostdata->test_completed == -1)
- printk ("scsi%d : driver test 1 timed out%s\n",host->host_no ,
- (hostdata->test_dest == 0xdeadbeef) ?
- " due to lost interrupt.\n"
- " Please verify that the correct IRQ is being used for your board,\n"
- : "");
- else if (hostdata->test_completed != 1)
- printk ("scsi%d : test 1 bad interrupt value (%d)\n",
- host->host_no, hostdata->test_completed);
- else
- failed = (hostdata->test_dest != 0xdeadbeef);
-
- if (hostdata->test_dest != 0xdeadbeef) {
- printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
- " probable cache invalidation problem. Please configure caching\n"
- " as write-through or disabled\n",
- host->host_no, hostdata->test_dest);
- }
-
- if (failed) {
- printk ("scsi%d : DSP = 0x%p (script at 0x%p, start at 0x%x)\n",
- host->host_no, bus_to_virt(NCR53c7x0_read32(DSP_REG)),
- hostdata->script, start);
- printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
- NCR53c7x0_read32(DSPS_REG));
- local_irq_restore(flags);
- return -1;
- }
- hostdata->test_running = 0;
- }
-
- if ((hostdata->options & OPTION_DEBUG_TEST2) &&
- hostdata->state != STATE_DISABLED) {
- u32 dsa[48];
- unsigned char identify = IDENTIFY(0, 0);
- unsigned char cmd[6];
- unsigned char data[36];
- unsigned char status = 0xff;
- unsigned char msg = 0xff;
-
- cmd[0] = INQUIRY;
- cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
- cmd[4] = sizeof(data);
-
- dsa[2] = 1;
- dsa[3] = virt_to_bus(&identify);
- dsa[4] = 6;
- dsa[5] = virt_to_bus(&cmd);
- dsa[6] = sizeof(data);
- dsa[7] = virt_to_bus(&data);
- dsa[8] = 1;
- dsa[9] = virt_to_bus(&status);
- dsa[10] = 1;
- dsa[11] = virt_to_bus(&msg);
-
- for (i = 0; i < 6; ++i) {
-#ifdef VALID_IDS
- if (!hostdata->valid_ids[i])
- continue;
-#endif
- local_irq_disable();
- if (!hostdata->idle) {
- printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
-
- /* 710: bit mapped scsi ID, async */
- dsa[0] = (1 << i) << 16;
- hostdata->idle = 0;
- hostdata->test_running = 2;
- hostdata->test_completed = -1;
- start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
- hostdata->state = STATE_RUNNING;
- NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
- NCR53c7x0_write32 (DSP_REG, start);
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
- DCNTL_SSM | DCNTL_STD);
- local_irq_restore(flags);
-
- timeout = jiffies + 5 * HZ; /* arbitrary */
- while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
- barrier();
-
- NCR53c7x0_write32 (DSA_REG, 0);
-
- if (hostdata->test_completed == 2) {
- data[35] = 0;
- printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n",
- host->host_no, i, data + 8);
- printk ("scsi%d : status ", host->host_no);
- scsi_print_status (status);
- printk ("\nscsi%d : message ", host->host_no);
- spi_print_msg(&msg);
- printk ("\n");
- } else if (hostdata->test_completed == 3) {
- printk("scsi%d : test 2 no connection with target %d\n",
- host->host_no, i);
- if (!hostdata->idle) {
- printk("scsi%d : not idle\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
- } else if (hostdata->test_completed == -1) {
- printk ("scsi%d : test 2 timed out\n", host->host_no);
- local_irq_restore(flags);
- return -1;
- }
- hostdata->test_running = 0;
- }
- }
-
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * Function : static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : copy the NCR53c8xx dsa structure into cmd's dsa buffer,
- * performing all necessary relocation.
- *
- * Inputs : cmd, a NCR53c7x0_cmd structure with a dsa area large
- * enough to hold the NCR53c8xx dsa.
- */
-
-static void
-NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
- Scsi_Cmnd *c = cmd->cmd;
- struct Scsi_Host *host = c->device->host;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int i;
-
- memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
- hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
-
- /*
- * Note : within the NCR 'C' code, dsa points to the _start_
- * of the DSA structure, and _not_ the offset of dsa_zero within
- * that structure used to facilitate shorter signed offsets
- * for the 8 bit ALU.
- *
- * The implications of this are that
- *
- * - 32 bit A_dsa_* absolute values require an additional
- * dsa_zero added to their value to be correct, since they are
- * relative to dsa_zero which is in essentially a separate
- * space from the code symbols.
- *
- * - All other symbols require no special treatment.
- */
-
- patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_lun, c->device->lun);
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
- Ent_dsa_code_template + A_dsa_next);
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->device->id].script));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->device->id].sscf_710));
- patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_target, 1 << c->device->id);
- /* XXX - new pointer stuff */
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_saved_residual, virt_to_bus(&cmd->saved_residual));
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_residual, virt_to_bus(&cmd->residual));
-
- /* XXX - new start stuff */
-
- patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
- dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
-}
-
-/*
- * Function : run_process_issue_queue (void)
- *
- * Purpose : insure that the coroutine is running and will process our
- * request. process_issue_queue_running is checked/set here (in an
- * inline function) rather than in process_issue_queue itself to reduce
- * the chances of stack overflow.
- *
- */
-
-static volatile int process_issue_queue_running = 0;
-
-static __inline__ void
-run_process_issue_queue(void) {
- unsigned long flags;
- local_irq_save(flags);
- if (!process_issue_queue_running) {
- process_issue_queue_running = 1;
- process_issue_queue(flags);
- /*
- * process_issue_queue_running is cleared in process_issue_queue
- * once it can't do more work, and process_issue_queue exits with
- * interrupts disabled.
- */
- }
- local_irq_restore(flags);
-}
-
-/*
- * Function : static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int
- * result)
- *
- * Purpose : mark SCSI command as finished, OR'ing the host portion
- * of the result word into the result field of the corresponding
- * Scsi_Cmnd structure, and removing it from the internal queues.
- *
- * Inputs : cmd - command, result - entire result field
- *
- * Preconditions : the NCR chip should be in a halted state when
- * abnormal_finished is run, since it modifies structures which
- * the NCR expects to have exclusive access to.
- */
-
-static void
-abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
- Scsi_Cmnd *c = cmd->cmd;
- struct Scsi_Host *host = c->device->host;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- int left, found;
- volatile struct NCR53c7x0_cmd * linux_search;
- volatile struct NCR53c7x0_cmd * volatile *linux_prev;
- volatile u32 *ncr_prev, *ncrcurrent, ncr_search;
-
-#if 0
- printk ("scsi%d: abnormal finished\n", host->host_no);
-#endif
-
- local_irq_save(flags);
- found = 0;
- /*
- * Traverse the NCR issue array until we find a match or run out
- * of instructions. Instructions in the NCR issue array are
- * either JUMP or NOP instructions, which are 2 words in length.
- */
-
-
- for (found = 0, left = host->can_queue, ncrcurrent = hostdata->schedule;
- left > 0; --left, ncrcurrent += 2)
- {
- if (issue_to_cmd (host, hostdata, (u32 *) ncrcurrent) == cmd)
- {
- ncrcurrent[0] = hostdata->NOP_insn;
- ncrcurrent[1] = 0xdeadbeef;
- ++found;
- break;
- }
- }
-
- /*
- * Traverse the NCR reconnect list of DSA structures until we find
- * a pointer to this dsa or have found too many command structures.
- * We let prev point at the next field of the previous element or
- * head of the list, so we don't do anything different for removing
- * the head element.
- */
-
- for (left = host->can_queue,
- ncr_search = hostdata->reconnect_dsa_head,
- ncr_prev = &hostdata->reconnect_dsa_head;
- left >= 0 && ncr_search &&
- ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start)
- != (char *) cmd->dsa;
- ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) +
- hostdata->dsa_next), ncr_search = *ncr_prev, --left);
-
- if (left < 0)
- printk("scsi%d: loop detected in ncr reconncect list\n",
- host->host_no);
- else if (ncr_search) {
- if (found)
- printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
- host->host_no, c->pid);
- else {
- volatile u32 * next = (u32 *)
- ((char *)bus_to_virt(ncr_search) + hostdata->dsa_next);
- *ncr_prev = *next;
-/* If we're at the tail end of the issue queue, update that pointer too. */
- found = 1;
- }
- }
-
- /*
- * Traverse the host running list until we find this command or discover
- * we have too many elements, pointing linux_prev at the next field of the
- * linux_previous element or head of the list, search at this element.
- */
-
- for (left = host->can_queue, linux_search = hostdata->running_list,
- linux_prev = &hostdata->running_list;
- left >= 0 && linux_search && linux_search != cmd;
- linux_prev = &(linux_search->next),
- linux_search = linux_search->next, --left);
-
- if (left < 0)
- printk ("scsi%d: loop detected in host running list for scsi pid %ld\n",
- host->host_no, c->pid);
- else if (linux_search) {
- *linux_prev = linux_search->next;
- --hostdata->busy[c->device->id][c->device->lun];
- }
-
- /* Return the NCR command structure to the free list */
- cmd->next = hostdata->free;
- hostdata->free = cmd;
- c->host_scribble = NULL;
-
- /* And return */
- c->result = result;
- c->scsi_done(c);
-
- local_irq_restore(flags);
- run_process_issue_queue();
-}
-
-/*
- * Function : static void intr_break (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : Handler for breakpoint interrupts from a SCSI script
- *
- * Inputs : host - pointer to this host adapter's structure,
- * cmd - pointer to the command (if any) dsa was pointing
- * to.
- *
- */
-
-static void
-intr_break (struct Scsi_Host *host, struct
- NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_break *bp;
-#if 0
- Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
-#endif
- u32 *dsp;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- NCR53c7x0_local_setup(host);
-
- /*
- * Find the break point corresponding to this address, and
- * dump the appropriate debugging information to standard
- * output.
- */
- local_irq_save(flags);
- dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
- for (bp = hostdata->breakpoints; bp && bp->address != dsp;
- bp = bp->next);
- if (!bp)
- panic("scsi%d : break point interrupt from %p with no breakpoint!",
- host->host_no, dsp);
-
- /*
- * Configure the NCR chip for manual start mode, so that we can
- * point the DSP register at the instruction that follows the
- * INT int_debug_break instruction.
- */
-
- NCR53c7x0_write8 (hostdata->dmode,
- NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
-
- /*
- * And update the DSP register, using the size of the old
- * instruction in bytes.
- */
-
- local_irq_restore(flags);
-}
-/*
- * Function : static void print_synchronous (const char *prefix,
- * const unsigned char *msg)
- *
- * Purpose : print a pretty, user and machine parsable representation
- * of a SDTR message, including the "real" parameters, data
- * clock so we can tell transfer rate at a glance.
- *
- * Inputs ; prefix - text to prepend, msg - SDTR message (5 bytes)
- */
-
-static void
-print_synchronous (const char *prefix, const unsigned char *msg) {
- if (msg[4]) {
- int Hz = 1000000000 / (msg[3] * 4);
- int integer = Hz / 1000000;
- int fraction = (Hz - (integer * 1000000)) / 10000;
- printk ("%speriod %dns offset %d %d.%02dMHz %s SCSI%s\n",
- prefix, (int) msg[3] * 4, (int) msg[4], integer, fraction,
- (((msg[3] * 4) < 200) ? "FAST" : "synchronous"),
- (((msg[3] * 4) < 200) ? "-II" : ""));
- } else
- printk ("%sasynchronous SCSI\n", prefix);
-}
-
-/*
- * Function : static void set_synchronous (struct Scsi_Host *host,
- * int target, int sxfer, int scntl3, int now_connected)
- *
- * Purpose : reprogram transfers between the selected SCSI initiator and
- * target with the given register values; in the indirect
- * select operand, reselection script, and chip registers.
- *
- * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
- * sxfer and scntl3 - NCR registers. now_connected - if non-zero,
- * we should reprogram the registers now too.
- *
- * NOTE: For 53c710, scntl3 is actually used for SCF bits from
- * SBCL, as we don't have a SCNTL3.
- */
-
-static void
-set_synchronous (struct Scsi_Host *host, int target, int sxfer, int scntl3,
- int now_connected) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- u32 *script;
- NCR53c7x0_local_setup(host);
-
- /* These are eight bit registers */
- sxfer &= 0xff;
- scntl3 &= 0xff;
-
- hostdata->sync[target].sxfer_sanity = sxfer;
- hostdata->sync[target].scntl3_sanity = scntl3;
-
-/*
- * HARD CODED : synchronous script is EIGHT words long. This
- * must agree with 53c7.8xx.h
- */
-
- if ((hostdata->chip != 700) && (hostdata->chip != 70066)) {
- hostdata->sync[target].select_indirect = (1 << target) << 16 |
- (sxfer << 8);
- hostdata->sync[target].sscf_710 = scntl3;
-
- script = (u32 *) hostdata->sync[target].script;
-
- /* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
- script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
- DCMD_RWRI_OP_MOVE) << 24) |
- (SBCL_REG << 16) | (scntl3 << 8);
- script[1] = 0;
- script += 2;
-
- script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
- DCMD_RWRI_OP_MOVE) << 24) |
- (SXFER_REG << 16) | (sxfer << 8);
- script[1] = 0;
- script += 2;
-
-#ifdef DEBUG_SYNC_INTR
- if (hostdata->options & OPTION_DEBUG_DISCONNECT) {
- script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_INT) << 24) | DBC_TCI_TRUE;
- script[1] = DEBUG_SYNC_INTR;
- script += 2;
- }
-#endif
-
- script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_RETURN) << 24) | DBC_TCI_TRUE;
- script[1] = 0;
- script += 2;
- }
-
- if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS)
- printk ("scsi%d : target %d sync parameters are sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, target, sxfer, scntl3);
-
- if (now_connected) {
- NCR53c7x0_write8(SBCL_REG, scntl3);
- NCR53c7x0_write8(SXFER_REG, sxfer);
- }
-}
-
-
-/*
- * Function : static int asynchronous (struct Scsi_Host *host, int target)
- *
- * Purpose : reprogram between the selected SCSI Host adapter and target
- * (assumed to be currently connected) for asynchronous transfers.
- *
- * Inputs : host - SCSI host structure, target - numeric target ID.
- *
- * Preconditions : the NCR chip should be in one of the halted states
- */
-
-static void
-asynchronous (struct Scsi_Host *host, int target) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- NCR53c7x0_local_setup(host);
- set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
- 1);
- printk ("scsi%d : setting target %d to asynchronous SCSI\n",
- host->host_no, target);
-}
-
-/*
- * XXX - do we want to go out of our way (ie, add extra code to selection
- * in the NCR53c710/NCR53c720 script) to reprogram the synchronous
- * conversion bits, or can we be content in just setting the
- * sxfer bits? I chose to do so [richard@sleepie.demon.co.uk]
- */
-
-/* Table for NCR53c8xx synchronous values */
-
-/* This table is also correct for 710, allowing that scf=4 is equivalent
- * of SSCF=0 (ie use DCNTL, divide by 3) for a 50.01-66.00MHz clock.
- * For any other clock values, we cannot use entries with SCF values of
- * 4. I guess that for a 66MHz clock, the slowest it will set is 2MHz,
- * and for a 50MHz clock, the slowest will be 2.27Mhz. Should check
- * that a device doesn't try and negotiate sync below these limits!
- */
-
-static const struct {
- int div; /* Total clock divisor * 10 */
- unsigned char scf; /* */
- unsigned char tp; /* 4 + tp = xferp divisor */
-} syncs[] = {
-/* div scf tp div scf tp div scf tp */
- { 40, 1, 0}, { 50, 1, 1}, { 60, 1, 2},
- { 70, 1, 3}, { 75, 2, 1}, { 80, 1, 4},
- { 90, 1, 5}, { 100, 1, 6}, { 105, 2, 3},
- { 110, 1, 7}, { 120, 2, 4}, { 135, 2, 5},
- { 140, 3, 3}, { 150, 2, 6}, { 160, 3, 4},
- { 165, 2, 7}, { 180, 3, 5}, { 200, 3, 6},
- { 210, 4, 3}, { 220, 3, 7}, { 240, 4, 4},
- { 270, 4, 5}, { 300, 4, 6}, { 330, 4, 7}
-};
-
-/*
- * Function : static void synchronous (struct Scsi_Host *host, int target,
- * char *msg)
- *
- * Purpose : reprogram transfers between the selected SCSI initiator and
- * target for synchronous SCSI transfers such that the synchronous
- * offset is less than that requested and period at least as long
- * as that requested. Also modify *msg such that it contains
- * an appropriate response.
- *
- * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
- * msg - synchronous transfer request.
- */
-
-
-static void
-synchronous (struct Scsi_Host *host, int target, char *msg) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int desire, divisor, i, limit;
- unsigned char scntl3, sxfer;
-/* The diagnostic message fits on one line, even with max. width integers */
- char buf[80];
-
-/* Desired transfer clock in Hz */
- desire = 1000000000L / (msg[3] * 4);
-/* Scale the available SCSI clock by 10 so we get tenths */
- divisor = (hostdata->scsi_clock * 10) / desire;
-
-/* NCR chips can handle at most an offset of 8 */
- if (msg[4] > 8)
- msg[4] = 8;
-
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk("scsi%d : optimal synchronous divisor of %d.%01d\n",
- host->host_no, divisor / 10, divisor % 10);
-
- limit = ARRAY_SIZE(syncs) - 1;
- for (i = 0; (i < limit) && (divisor > syncs[i].div); ++i);
-
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk("scsi%d : selected synchronous divisor of %d.%01d\n",
- host->host_no, syncs[i].div / 10, syncs[i].div % 10);
-
- msg[3] = ((1000000000L / hostdata->scsi_clock) * syncs[i].div / 10 / 4);
-
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk("scsi%d : selected synchronous period of %dns\n", host->host_no,
- msg[3] * 4);
-
- scntl3 = syncs[i].scf;
- sxfer = (msg[4] << SXFER_MO_SHIFT) | (syncs[i].tp << 4);
- if (hostdata->options & OPTION_DEBUG_SDTR)
- printk ("scsi%d : sxfer=0x%x scntl3=0x%x\n",
- host->host_no, (int) sxfer, (int) scntl3);
- set_synchronous (host, target, sxfer, scntl3, 1);
- sprintf (buf, "scsi%d : setting target %d to ", host->host_no, target);
- print_synchronous (buf, msg);
-}
-
-/*
- * Function : static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : Handler for INT generated instructions for the
- * NCR53c810/820 SCSI SCRIPT
- *
- * Inputs : host - pointer to this host adapter's structure,
- * cmd - pointer to the command (if any) dsa was pointing
- * to.
- *
- */
-
-static int
-NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct
- NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- int print;
- Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- u32 dsps,*dsp; /* Argument of the INT instruction */
-
- NCR53c7x0_local_setup(host);
- dsps = NCR53c7x0_read32(DSPS_REG);
- dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
-
- /* RGH 150597: Frig. Commands which fail with Check Condition are
- * Flagged as successful - hack dsps to indicate check condition */
-#if 0
- /* RGH 200597: Need to disable for BVME6000, as it gets Check Conditions
- * and then dies. Seems to handle Check Condition at startup, but
- * not mid kernel build. */
- if (dsps == A_int_norm_emulateintfly && cmd && cmd->result == 2)
- dsps = A_int_err_check_condition;
-#endif
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
-
- switch (dsps) {
- case A_int_msg_1:
- print = 1;
- switch (hostdata->msg_buf[0]) {
- /*
- * Unless we've initiated synchronous negotiation, I don't
- * think that this should happen.
- */
- case MESSAGE_REJECT:
- hostdata->dsp = hostdata->script + hostdata->E_accept_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
- printk ("scsi%d : target %d rejected SDTR\n", host->host_no,
- c->device->id);
- cmd->flags &= ~CMD_FLAG_SDTR;
- asynchronous (host, c->device->id);
- print = 0;
- }
- break;
- case INITIATE_RECOVERY:
- printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
- host->host_no);
- /* Fall through to default */
- hostdata->dsp = hostdata->script + hostdata->E_reject_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- break;
- default:
- printk ("scsi%d : unsupported message, rejecting\n",
- host->host_no);
- hostdata->dsp = hostdata->script + hostdata->E_reject_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- }
- if (print) {
- printk ("scsi%d : received message", host->host_no);
- if (c)
- printk (" from target %d lun %d ", c->device->id, c->device->lun);
- spi_print_msg((unsigned char *) hostdata->msg_buf);
- printk("\n");
- }
-
- return SPECIFIC_INT_NOTHING;
-
-
- case A_int_msg_sdtr:
-/*
- * At this point, hostdata->msg_buf contains
- * 0 EXTENDED MESSAGE
- * 1 length
- * 2 SDTR
- * 3 period * 4ns
- * 4 offset
- */
-
- if (cmd) {
- char buf[80];
- sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->device->id,
- (cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
- print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
-
- /*
- * Initiator initiated, won't happen unless synchronous
- * transfers are enabled. If we get a SDTR message in
- * response to our SDTR, we should program our parameters
- * such that
- * offset <= requested offset
- * period >= requested period
- */
- if (cmd->flags & CMD_FLAG_SDTR) {
- cmd->flags &= ~CMD_FLAG_SDTR;
- if (hostdata->msg_buf[4])
- synchronous (host, c->device->id, (unsigned char *)
- hostdata->msg_buf);
- else
- asynchronous (host, c->device->id);
- hostdata->dsp = hostdata->script + hostdata->E_accept_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- } else {
- if (hostdata->options & OPTION_SYNCHRONOUS) {
- cmd->flags |= CMD_FLAG_DID_SDTR;
- synchronous (host, c->device->id, (unsigned char *)
- hostdata->msg_buf);
- } else {
- hostdata->msg_buf[4] = 0; /* 0 offset = async */
- asynchronous (host, c->device->id);
- }
- patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
- patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
- virt_to_bus ((void *)&hostdata->msg_buf));
- hostdata->dsp = hostdata->script +
- hostdata->E_respond_message / sizeof(u32);
- hostdata->dsp_changed = 1;
- }
- return SPECIFIC_INT_NOTHING;
- }
- /* Fall through to abort if we couldn't find a cmd, and
- therefore a dsa structure to twiddle */
- case A_int_msg_wdtr:
- hostdata->dsp = hostdata->script + hostdata->E_reject_message /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- case A_int_err_unexpected_phase:
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : unexpected phase\n", host->host_no);
- return SPECIFIC_INT_ABORT;
- case A_int_err_selected:
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : selected by target %d\n", host->host_no,
- (int) NCR53c7x0_read8(SDID_REG_800) &7);
- else
- printk ("scsi%d : selected by target LCRC=0x%02x\n", host->host_no,
- (int) NCR53c7x0_read8(LCRC_REG_10));
- hostdata->dsp = hostdata->script + hostdata->E_target_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- case A_int_err_unexpected_reselect:
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : unexpected reselect by target %d lun %d\n",
- host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & 7,
- hostdata->reselected_identify & 7);
- else
- printk ("scsi%d : unexpected reselect LCRC=0x%02x\n", host->host_no,
- (int) NCR53c7x0_read8(LCRC_REG_10));
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
-/*
- * Since contingent allegiance conditions are cleared by the next
- * command issued to a target, we must issue a REQUEST SENSE
- * command after receiving a CHECK CONDITION status, before
- * another command is issued.
- *
- * Since this NCR53c7x0_cmd will be freed after use, we don't
- * care if we step on the various fields, so modify a few things.
- */
- case A_int_err_check_condition:
-#if 0
- if (hostdata->options & OPTION_DEBUG_INTR)
-#endif
- printk ("scsi%d : CHECK CONDITION\n", host->host_no);
- if (!c) {
- printk("scsi%d : CHECK CONDITION with no SCSI command\n",
- host->host_no);
- return SPECIFIC_INT_PANIC;
- }
-
- /*
- * FIXME : this uses the normal one-byte selection message.
- * We may want to renegotiate for synchronous & WIDE transfers
- * since these could be the crux of our problem.
- *
- hostdata->NOP_insn* FIXME : once SCSI-II tagged queuing is implemented, we'll
- * have to set this up so that the rest of the DSA
- * agrees with this being an untagged queue'd command.
- */
-
- patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
-
- /*
- * Modify the table indirect for COMMAND OUT phase, since
- * Request Sense is a six byte command.
- */
-
- patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
-
- /*
- * The CDB is now mirrored in our local non-cached
- * structure, but keep the old structure up to date as well,
- * just in case anyone looks at it.
- */
-
- /*
- * XXX Need to worry about data buffer alignment/cache state
- * XXX here, but currently never get A_int_err_check_condition,
- * XXX so ignore problem for now.
- */
- cmd->cmnd[0] = c->cmnd[0] = REQUEST_SENSE;
- cmd->cmnd[0] = c->cmnd[1] &= 0xe0; /* Zero all but LUN */
- cmd->cmnd[0] = c->cmnd[2] = 0;
- cmd->cmnd[0] = c->cmnd[3] = 0;
- cmd->cmnd[0] = c->cmnd[4] = sizeof(c->sense_buffer);
- cmd->cmnd[0] = c->cmnd[5] = 0;
-
- /*
- * Disable dataout phase, and program datain to transfer to the
- * sense buffer, and add a jump to other_transfer after the
- * command so overflow/underrun conditions are detected.
- */
-
- patch_dsa_32 (cmd->dsa, dsa_dataout, 0,
- virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
- patch_dsa_32 (cmd->dsa, dsa_datain, 0,
- virt_to_bus(cmd->data_transfer_start));
- cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
- DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
- cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
-
- cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
-
- /*
- * Currently, this command is flagged as completed, ie
- * it has valid status and message data. Reflag it as
- * incomplete. Q - need to do something so that original
- * status, etc are used.
- */
-
- cmd->result = cmd->cmd->result = 0xffff;
-
- /*
- * Restart command as a REQUEST SENSE.
- */
- hostdata->dsp = (u32 *) hostdata->script + hostdata->E_select /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- return SPECIFIC_INT_NOTHING;
- case A_int_debug_break:
- return SPECIFIC_INT_BREAK;
- case A_int_norm_aborted:
- hostdata->dsp = (u32 *) hostdata->schedule;
- hostdata->dsp_changed = 1;
- if (cmd)
- abnormal_finished (cmd, DID_ERROR << 16);
- return SPECIFIC_INT_NOTHING;
- case A_int_norm_emulateintfly:
- NCR53c7x0_intfly(host);
- return SPECIFIC_INT_NOTHING;
- case A_int_test_1:
- case A_int_test_2:
- hostdata->idle = 1;
- hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk("scsi%d : test%d complete\n", host->host_no,
- hostdata->test_completed);
- return SPECIFIC_INT_NOTHING;
-#ifdef A_int_debug_reselected_ok
- case A_int_debug_reselected_ok:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- /*
- * Note - this dsa is not based on location relative to
- * the command structure, but to location relative to the
- * DSA register
- */
- u32 *dsa;
- dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
-
- printk("scsi%d : reselected_ok (DSA = 0x%x (virt 0x%p)\n",
- host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
- printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt(cmd->saved_data_pointer));
- print_insn (host, hostdata->script + Ent_reselected_ok /
- sizeof(u32), "", 1);
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, NCR53c7x0_read8(SXFER_REG),
- NCR53c7x0_read8(SCNTL3_REG_800));
- else
- printk ("scsi%d : sxfer=0x%x, cannot read SBCL\n",
- host->host_no, NCR53c7x0_read8(SXFER_REG));
- if (c) {
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script, "", 1);
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script + 2, "", 1);
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_reselect_check
- case A_int_debug_reselect_check:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- u32 *dsa;
-#if 0
- u32 *code;
-#endif
- /*
- * Note - this dsa is not based on location relative to
- * the command structure, but to location relative to the
- * DSA register
- */
- dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
- printk("scsi%d : reselected_check_next (DSA = 0x%lx (virt 0x%p))\n",
- host->host_no, virt_to_bus(dsa), dsa);
- if (dsa) {
- printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
-#if 0
- printk("scsi%d : template code :\n", host->host_no);
- for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero)
- / sizeof(u32); code < (dsa + Ent_dsa_zero / sizeof(u32));
- code += print_insn (host, code, "", 1));
-#endif
- }
- print_insn (host, hostdata->script + Ent_reselected_ok /
- sizeof(u32), "", 1);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_dsa_schedule
- case A_int_debug_dsa_schedule:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- u32 *dsa;
- /*
- * Note - this dsa is not based on location relative to
- * the command structure, but to location relative to the
- * DSA register
- */
- dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
- printk("scsi%d : dsa_schedule (old DSA = 0x%lx (virt 0x%p))\n",
- host->host_no, virt_to_bus(dsa), dsa);
- if (dsa)
- printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
- " (temp was 0x%x (virt 0x%p))\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer),
- NCR53c7x0_read32 (TEMP_REG),
- bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_scheduled
- case A_int_debug_scheduled:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : new I/O 0x%x (virt 0x%p) scheduled\n",
- host->host_no, NCR53c7x0_read32(DSA_REG),
- bus_to_virt(NCR53c7x0_read32(DSA_REG)));
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_idle
- case A_int_debug_idle:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : idle\n", host->host_no);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_cmd
- case A_int_debug_cmd:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : command sent\n");
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_dsa_loaded
- case A_int_debug_dsa_loaded:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- printk("scsi%d : DSA loaded with 0x%x (virt 0x%p)\n", host->host_no,
- NCR53c7x0_read32(DSA_REG),
- bus_to_virt(NCR53c7x0_read32(DSA_REG)));
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_reselected
- case A_int_debug_reselected:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- if ((hostdata->chip / 100) == 8)
- printk("scsi%d : reselected by target %d lun %d\n",
- host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & ~0x80,
- (int) hostdata->reselected_identify & 7);
- else
- printk("scsi%d : reselected by LCRC=0x%02x lun %d\n",
- host->host_no, (int) NCR53c7x0_read8(LCRC_REG_10),
- (int) hostdata->reselected_identify & 7);
- print_queues(host);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_disconnect_msg
- case A_int_debug_disconnect_msg:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
- if (c)
- printk("scsi%d : target %d lun %d disconnecting\n",
- host->host_no, c->device->id, c->device->lun);
- else
- printk("scsi%d : unknown target disconnecting\n",
- host->host_no);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_disconnected
- case A_int_debug_disconnected:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- printk ("scsi%d : disconnected, new queues are\n",
- host->host_no);
- print_queues(host);
-#if 0
- /* Not valid on ncr53c710! */
- printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, NCR53c7x0_read8(SXFER_REG),
- NCR53c7x0_read8(SCNTL3_REG_800));
-#endif
- if (c) {
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script, "", 1);
- print_insn (host, (u32 *)
- hostdata->sync[c->device->id].script + 2, "", 1);
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_panic
- case A_int_debug_panic:
- printk("scsi%d : int_debug_panic received\n", host->host_no);
- print_lots (host);
- return SPECIFIC_INT_PANIC;
-#endif
-#ifdef A_int_debug_saved
- case A_int_debug_saved:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
- print_progress (c);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_restored
- case A_int_debug_restored:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT)) {
- if (cmd) {
- int size;
- printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
- host->host_no, cmd->saved_data_pointer, bus_to_virt (
- cmd->saved_data_pointer));
- size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer), "", 1);
- size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
- print_progress (c);
- }
-#if 0
- printk ("scsi%d : datapath residual %d\n",
- host->host_no, datapath_residual (host)) ;
-#endif
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_sync
- case A_int_debug_sync:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
- unsigned char sxfer = NCR53c7x0_read8 (SXFER_REG), scntl3;
- if ((hostdata->chip / 100) == 8) {
- scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
- if (c) {
- if (sxfer != hostdata->sync[c->device->id].sxfer_sanity ||
- scntl3 != hostdata->sync[c->device->id].scntl3_sanity) {
- printk ("scsi%d : sync sanity check failed sxfer=0x%x, scntl3=0x%x",
- host->host_no, sxfer, scntl3);
- NCR53c7x0_write8 (SXFER_REG, sxfer);
- NCR53c7x0_write8 (SCNTL3_REG_800, scntl3);
- }
- } else
- printk ("scsi%d : unknown command sxfer=0x%x, scntl3=0x%x\n",
- host->host_no, (int) sxfer, (int) scntl3);
- } else {
- if (c) {
- if (sxfer != hostdata->sync[c->device->id].sxfer_sanity) {
- printk ("scsi%d : sync sanity check failed sxfer=0x%x",
- host->host_no, sxfer);
- NCR53c7x0_write8 (SXFER_REG, sxfer);
- NCR53c7x0_write8 (SBCL_REG,
- hostdata->sync[c->device->id].sscf_710);
- }
- } else
- printk ("scsi%d : unknown command sxfer=0x%x\n",
- host->host_no, (int) sxfer);
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_datain
- case A_int_debug_datain:
- if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
- OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
- int size;
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : In do_datain (%s) sxfer=0x%x, scntl3=0x%x\n"
- " datapath residual=%d\n",
- host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
- (int) NCR53c7x0_read8(SXFER_REG),
- (int) NCR53c7x0_read8(SCNTL3_REG_800),
- datapath_residual (host)) ;
- else
- printk ("scsi%d : In do_datain (%s) sxfer=0x%x\n"
- " datapath residual=%d\n",
- host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
- (int) NCR53c7x0_read8(SXFER_REG),
- datapath_residual (host)) ;
- print_insn (host, dsp, "", 1);
- size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
- print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
- }
- return SPECIFIC_INT_RESTART;
-#endif
-#ifdef A_int_debug_check_dsa
- case A_int_debug_check_dsa:
- if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
- int sdid;
- int tmp;
- char *where;
- if (hostdata->chip / 100 == 8)
- sdid = NCR53c7x0_read8 (SDID_REG_800) & 15;
- else {
- tmp = NCR53c7x0_read8 (SDID_REG_700);
- if (!tmp)
- panic ("SDID_REG_700 = 0");
- tmp >>= 1;
- sdid = 0;
- while (tmp) {
- tmp >>= 1;
- sdid++;
- }
- }
- where = dsp - NCR53c7x0_insn_size(NCR53c7x0_read8
- (DCMD_REG)) == hostdata->script +
- Ent_select_check_dsa / sizeof(u32) ?
- "selection" : "reselection";
- if (c && sdid != c->device->id) {
- printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
- host->host_no, sdid, c->device->id, where);
- print_lots(host);
- dump_events (host, 20);
- return SPECIFIC_INT_PANIC;
- }
- }
- return SPECIFIC_INT_RESTART;
-#endif
- default:
- if ((dsps & 0xff000000) == 0x03000000) {
- printk ("scsi%d : misc debug interrupt 0x%x\n",
- host->host_no, dsps);
- return SPECIFIC_INT_RESTART;
- } else if ((dsps & 0xff000000) == 0x05000000) {
- if (hostdata->events) {
- struct NCR53c7x0_event *event;
- ++hostdata->event_index;
- if (hostdata->event_index >= hostdata->event_size)
- hostdata->event_index = 0;
- event = (struct NCR53c7x0_event *) hostdata->events +
- hostdata->event_index;
- event->event = (enum ncr_event) dsps;
- event->dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
- if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
- if (hostdata->chip / 100 == 8)
- event->target = NCR53c7x0_read8(SSID_REG_800);
- else {
- unsigned char tmp, sdid;
- tmp = NCR53c7x0_read8 (SDID_REG_700);
- if (!tmp)
- panic ("SDID_REG_700 = 0");
- tmp >>= 1;
- sdid = 0;
- while (tmp) {
- tmp >>= 1;
- sdid++;
- }
- event->target = sdid;
- }
- }
- else
- event->target = 255;
-
- if (event->event == EVENT_RESELECT)
- event->lun = hostdata->reselected_identify & 0xf;
- else if (c)
- event->lun = c->device->lun;
- else
- event->lun = 255;
- do_gettimeofday(&(event->time));
- if (c) {
- event->pid = c->pid;
- memcpy ((void *) event->cmnd, (void *) c->cmnd,
- sizeof (event->cmnd));
- } else {
- event->pid = -1;
- }
- }
- return SPECIFIC_INT_RESTART;
- }
-
- printk ("scsi%d : unknown user interrupt 0x%x\n",
- host->host_no, (unsigned) dsps);
- return SPECIFIC_INT_PANIC;
- }
-}
-
-/*
- * XXX - the stock NCR assembler won't output the scriptu.h file,
- * which undefine's all #define'd CPP symbols from the script.h
- * file, which will create problems if you use multiple scripts
- * with the same symbol names.
- *
- * If you insist on using NCR's assembler, you could generate
- * scriptu.h from script.h using something like
- *
- * grep #define script.h | \
- * sed 's/#define[ ][ ]*\([_a-zA-Z][_a-zA-Z0-9]*\).*$/#undefine \1/' \
- * > scriptu.h
- */
-
-#include "53c7xx_u.h"
-
-/* XXX - add alternate script handling code here */
-
-
-/*
- * Function : static void NCR537xx_soft_reset (struct Scsi_Host *host)
- *
- * Purpose : perform a soft reset of the NCR53c7xx chip
- *
- * Inputs : host - pointer to this host adapter's structure
- *
- * Preconditions : NCR53c7x0_init must have been called for this
- * host.
- *
- */
-
-static void
-NCR53c7x0_soft_reset (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- NCR53c7x0_local_setup(host);
-
- local_irq_save(flags);
-
- /* Disable scsi chip and s/w level 7 ints */
-
-#ifdef CONFIG_MVME16x
- if (MACH_IS_MVME16x)
- {
- volatile unsigned long v;
-
- v = *(volatile unsigned long *)0xfff4006c;
- v &= ~0x8000;
- *(volatile unsigned long *)0xfff4006c = v;
- v = *(volatile unsigned long *)0xfff4202c;
- v &= ~0x10;
- *(volatile unsigned long *)0xfff4202c = v;
- }
-#endif
- /* Anything specific for your hardware? */
-
- /*
- * Do a soft reset of the chip so that everything is
- * reinitialized to the power-on state.
- *
- * Basically follow the procedure outlined in the NCR53c700
- * data manual under Chapter Six, How to Use, Steps Necessary to
- * Start SCRIPTS, with the exception of actually starting the
- * script and setting up the synchronous transfer gunk.
- */
-
- /* Should we reset the scsi bus here??????????????????? */
-
- NCR53c7x0_write8(ISTAT_REG_700, ISTAT_10_SRST);
- NCR53c7x0_write8(ISTAT_REG_700, 0);
-
- /*
- * saved_dcntl is set up in NCR53c7x0_init() before it is overwritten
- * here. We should have some better way of working out the CF bit
- * setting..
- */
-
- hostdata->saved_dcntl = DCNTL_10_EA|DCNTL_10_COM;
- if (hostdata->scsi_clock > 50000000)
- hostdata->saved_dcntl |= DCNTL_700_CF_3;
- else
- if (hostdata->scsi_clock > 37500000)
- hostdata->saved_dcntl |= DCNTL_700_CF_2;
-#if 0
- else
- /* Any clocks less than 37.5MHz? */
-#endif
-
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
- else
- NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
- /* Following disables snooping - snooping is not required, as non-
- * cached pages are used for shared data, and appropriate use is
- * made of cache_push/cache_clear. Indeed, for 68060
- * enabling snooping causes disk corruption of ext2fs free block
- * bitmaps and the like. If you have a 68060 with snooping hardwared
- * on, then you need to enable CONFIG_060_WRITETHROUGH.
- */
- NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
- /* Actually burst of eight, according to my 53c710 databook */
- NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
- NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
- NCR53c7x0_write8(SBCL_REG, 0);
- NCR53c7x0_write8(SCNTL1_REG, SCNTL1_ESR_700);
- NCR53c7x0_write8(SCNTL0_REG, ((hostdata->options & OPTION_PARITY) ?
- SCNTL0_EPC : 0) | SCNTL0_EPG_700 | SCNTL0_ARB1 | SCNTL0_ARB2);
-
- /*
- * Enable all interrupts, except parity which we only want when
- * the user requests it.
- */
-
- NCR53c7x0_write8(DIEN_REG, DIEN_700_BF |
- DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
-
- NCR53c7x0_write8(SIEN_REG_700, ((hostdata->options & OPTION_PARITY) ?
- SIEN_PAR : 0) | SIEN_700_STO | SIEN_RST | SIEN_UDC |
- SIEN_SGE | SIEN_MA);
-
-#ifdef CONFIG_MVME16x
- if (MACH_IS_MVME16x)
- {
- volatile unsigned long v;
-
- /* Enable scsi chip and s/w level 7 ints */
- v = *(volatile unsigned long *)0xfff40080;
- v = (v & ~(0xf << 28)) | (4 << 28);
- *(volatile unsigned long *)0xfff40080 = v;
- v = *(volatile unsigned long *)0xfff4006c;
- v |= 0x8000;
- *(volatile unsigned long *)0xfff4006c = v;
- v = *(volatile unsigned long *)0xfff4202c;
- v = (v & ~0xff) | 0x10 | 4;
- *(volatile unsigned long *)0xfff4202c = v;
- }
-#endif
- /* Anything needed for your hardware? */
- local_irq_restore(flags);
-}
-
-
-/*
- * Function static struct NCR53c7x0_cmd *allocate_cmd (Scsi_Cmnd *cmd)
- *
- * Purpose : Return the first free NCR53c7x0_cmd structure (which are
- * reused in a LIFO manner to minimize cache thrashing).
- *
- * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
- * structures for this device, do so. Attempt to complete all scheduled
- * allocations using get_zeroed_page(), putting NCR53c7x0_cmd structures on
- * the free list. Teach programmers not to drink and hack.
- *
- * Inputs : cmd - SCSI command
- *
- * Returns : NCR53c7x0_cmd structure allocated on behalf of cmd;
- * NULL on failure.
- */
-
-static void
-my_free_page (void *addr, int dummy)
-{
- /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
- * XXX may be invalid (CONFIG_060_WRITETHROUGH)
- */
- kernel_set_cachemode((void *)addr, 4096, IOMAP_FULL_CACHING);
- free_page ((u32)addr);
-}
-
-static struct NCR53c7x0_cmd *
-allocate_cmd (Scsi_Cmnd *cmd) {
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- u32 real; /* Real address */
- int size; /* Size of *tmp */
- struct NCR53c7x0_cmd *tmp;
- unsigned long flags;
-
- if (hostdata->options & OPTION_DEBUG_ALLOCATION)
- printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
- " target = %d, lun = %d, %s\n",
- host->host_no, hostdata->num_cmds, host->can_queue,
- cmd->device->id, cmd->device->lun, (hostdata->cmd_allocated[cmd->device->id] &
- (1 << cmd->device->lun)) ? "already allocated" : "not allocated");
-
-/*
- * If we have not yet reserved commands for this I_T_L nexus, and
- * the device exists (as indicated by permanent Scsi_Cmnd structures
- * being allocated under 1.3.x, or being outside of scan_scsis in
- * 1.2.x), do so now.
- */
- if (!(hostdata->cmd_allocated[cmd->device->id] & (1 << cmd->device->lun)) &&
- cmd->device && cmd->device->has_cmdblocks) {
- if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
- hostdata->extra_allocate += host->cmd_per_lun;
- hostdata->cmd_allocated[cmd->device->id] |= (1 << cmd->device->lun);
- }
-
- for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate,
- ++hostdata->num_cmds) {
- /* historically, kmalloc has returned unaligned addresses; pad so we
- have enough room to ROUNDUP */
- size = hostdata->max_cmd_size + sizeof (void *);
-#ifdef FORCE_DSA_ALIGNMENT
- /*
- * 53c710 rev.0 doesn't have an add-with-carry instruction.
- * Ensure we allocate enough memory to force alignment.
- */
- size += 256;
-#endif
-/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
-
- if (size > 4096) {
- printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
- return NULL;
- }
- real = get_zeroed_page(GFP_ATOMIC);
- if (real == 0)
- return NULL;
- cache_push(virt_to_phys((void *)real), 4096);
- cache_clear(virt_to_phys((void *)real), 4096);
- kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER);
- tmp = ROUNDUP(real, void *);
-#ifdef FORCE_DSA_ALIGNMENT
- {
- if (((u32)tmp & 0xff) > CmdPageStart)
- tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
- tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
-#if 0
- printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
- size, real, (u32)tmp);
-#endif
- }
-#endif
- tmp->real = (void *)real;
- tmp->size = size;
- tmp->free = ((void (*)(void *, int)) my_free_page);
- local_irq_save(flags);
- tmp->next = hostdata->free;
- hostdata->free = tmp;
- local_irq_restore(flags);
- }
- local_irq_save(flags);
- tmp = (struct NCR53c7x0_cmd *) hostdata->free;
- if (tmp) {
- hostdata->free = tmp->next;
- }
- local_irq_restore(flags);
- if (!tmp)
- printk ("scsi%d : can't allocate command for target %d lun %d\n",
- host->host_no, cmd->device->id, cmd->device->lun);
- return tmp;
-}
-
-/*
- * Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd)
- *
- *
- * Purpose : allocate a NCR53c7x0_cmd structure, initialize it based on the
- * Scsi_Cmnd structure passed in cmd, including dsa and Linux field
- * initialization, and dsa code relocation.
- *
- * Inputs : cmd - SCSI command
- *
- * Returns : NCR53c7x0_cmd structure corresponding to cmd,
- * NULL on failure.
- */
-static struct NCR53c7x0_cmd *
-create_cmd (Scsi_Cmnd *cmd) {
- NCR53c7x0_local_declare();
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- struct NCR53c7x0_cmd *tmp; /* NCR53c7x0_cmd structure for this command */
- int datain, /* Number of instructions per phase */
- dataout;
- int data_transfer_instructions, /* Count of dynamic instructions */
- i; /* Counter */
- u32 *cmd_datain, /* Address of datain/dataout code */
- *cmd_dataout; /* Incremented as we assemble */
-#ifdef notyet
- unsigned char *msgptr; /* Current byte in select message */
- int msglen; /* Length of whole select message */
-#endif
- unsigned long flags;
- u32 exp_select_indirect; /* Used in sanity check */
- NCR53c7x0_local_setup(cmd->device->host);
-
- if (!(tmp = allocate_cmd (cmd)))
- return NULL;
-
- /*
- * Copy CDB and initialised result fields from Scsi_Cmnd to NCR53c7x0_cmd.
- * We do this because NCR53c7x0_cmd may have a special cache mode
- * selected to cope with lack of bus snooping, etc.
- */
-
- memcpy(tmp->cmnd, cmd->cmnd, 12);
- tmp->result = cmd->result;
-
- /*
- * Decide whether we need to generate commands for DATA IN,
- * DATA OUT, neither, or both based on the SCSI command
- */
-
- switch (cmd->cmnd[0]) {
- /* These commands do DATA IN */
- case INQUIRY:
- case MODE_SENSE:
- case READ_6:
- case READ_10:
- case READ_CAPACITY:
- case REQUEST_SENSE:
- case READ_BLOCK_LIMITS:
- case READ_TOC:
- datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
- dataout = 0;
- break;
- /* These commands do DATA OUT */
- case MODE_SELECT:
- case WRITE_6:
- case WRITE_10:
-#if 0
- printk("scsi%d : command is ", host->host_no);
- __scsi_print_command(cmd->cmnd);
-#endif
-#if 0
- printk ("scsi%d : %d scatter/gather segments\n", host->host_no,
- cmd->use_sg);
-#endif
- datain = 0;
- dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
-#if 0
- hostdata->options |= OPTION_DEBUG_INTR;
-#endif
- break;
- /*
- * These commands do no data transfer, we should force an
- * interrupt if a data phase is attempted on them.
- */
- case TEST_UNIT_READY:
- case ALLOW_MEDIUM_REMOVAL:
- case START_STOP:
- datain = dataout = 0;
- break;
- /*
- * We don't know about these commands, so generate code to handle
- * both DATA IN and DATA OUT phases. More efficient to identify them
- * and add them to the above cases.
- */
- default:
- printk("scsi%d : datain+dataout for command ", host->host_no);
- __scsi_print_command(cmd->cmnd);
- datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
- }
-
- /*
- * New code : so that active pointers work correctly regardless
- * of where the saved data pointer is at, we want to immediately
- * enter the dynamic code after selection, and on a non-data
- * phase perform a CALL to the non-data phase handler, with
- * returns back to this address.
- *
- * If a phase mismatch is encountered in the middle of a
- * Block MOVE instruction, we want to _leave_ that instruction
- * unchanged as the current case is, modify a temporary buffer,
- * and point the active pointer (TEMP) at that.
- *
- * Furthermore, we want to implement a saved data pointer,
- * set by the SAVE_DATA_POINTERs message.
- *
- * So, the data transfer segments will change to
- * CALL data_transfer, WHEN NOT data phase
- * MOVE x, x, WHEN data phase
- * ( repeat )
- * JUMP other_transfer
- */
-
- data_transfer_instructions = datain + dataout;
-
- /*
- * When we perform a request sense, we overwrite various things,
- * including the data transfer code. Make sure we have enough
- * space to do that.
- */
-
- if (data_transfer_instructions < 2)
- data_transfer_instructions = 2;
-
-
- /*
- * The saved data pointer is set up so that a RESTORE POINTERS message
- * will start the data transfer over at the beginning.
- */
-
- tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
- hostdata->E_data_transfer;
-
- /*
- * Initialize Linux specific fields.
- */
-
- tmp->cmd = cmd;
- tmp->next = NULL;
- tmp->flags = 0;
- tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next -
- hostdata->dsa_start;
- tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
-
- /*
- * Calculate addresses of dynamic code to fill in DSA
- */
-
- tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end -
- hostdata->dsa_start) / sizeof(u32);
- tmp->data_transfer_end = tmp->data_transfer_start +
- 2 * data_transfer_instructions;
-
- cmd_datain = datain ? tmp->data_transfer_start : NULL;
- cmd_dataout = dataout ? (datain ? cmd_datain + 2 * datain : tmp->
- data_transfer_start) : NULL;
-
- /*
- * Fill in the NCR53c7x0_cmd structure as follows
- * dsa, with fixed up DSA code
- * datain code
- * dataout code
- */
-
- /* Copy template code into dsa and perform all necessary fixups */
- if (hostdata->dsa_fixup)
- hostdata->dsa_fixup(tmp);
-
- patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
- /*
- * XXX is this giving 53c710 access to the Scsi_Cmnd in some way?
- * Do we need to change it for caching reasons?
- */
- patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
-
- if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
-
- exp_select_indirect = ((1 << cmd->device->id) << 16) |
- (hostdata->sync[cmd->device->id].sxfer_sanity << 8);
-
- if (hostdata->sync[cmd->device->id].select_indirect !=
- exp_select_indirect) {
- printk ("scsi%d : sanity check failed select_indirect=0x%x\n",
- host->host_no, hostdata->sync[cmd->device->id].select_indirect);
- FATAL(host);
-
- }
- }
-
- patch_dsa_32(tmp->dsa, dsa_select, 0,
- hostdata->sync[cmd->device->id].select_indirect);
-
- /*
- * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
- * different commands; although it should be trivial to do them
- * both at the same time.
- */
- if (hostdata->initiate_wdtr & (1 << cmd->device->id)) {
- memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
- sizeof(wdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
- local_irq_save(flags);
- hostdata->initiate_wdtr &= ~(1 << cmd->device->id);
- local_irq_restore(flags);
- } else if (hostdata->initiate_sdtr & (1 << cmd->device->id)) {
- memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
- sizeof(sdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
- tmp->flags |= CMD_FLAG_SDTR;
- local_irq_save(flags);
- hostdata->initiate_sdtr &= ~(1 << cmd->device->id);
- local_irq_restore(flags);
-
- }
-#if 1
- else if (!(hostdata->talked_to & (1 << cmd->device->id)) &&
- !(hostdata->options & OPTION_NO_ASYNC)) {
-
- memcpy ((void *) (tmp->select + 1), (void *) async_message,
- sizeof(async_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
- tmp->flags |= CMD_FLAG_SDTR;
- }
-#endif
- else
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
-
- hostdata->talked_to |= (1 << cmd->device->id);
- tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
- IDENTIFY (1, cmd->device->lun) : IDENTIFY (0, cmd->device->lun);
- patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
- patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
- patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd));
- patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
- virt_to_bus (cmd_dataout)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
- patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ?
- virt_to_bus (cmd_datain)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
- /*
- * XXX - need to make endian aware, should use separate variables
- * for both status and message bytes.
- */
- patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
-/*
- * FIXME : these only works for little endian. We probably want to
- * provide message and status fields in the NCR53c7x0_cmd
- * structure, and assign them to cmd->result when we're done.
- */
-#ifdef BIG_ENDIAN
- patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 2);
- patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result) + 3);
-#else
- patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 1);
- patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result));
-#endif
- patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
-
- /*
- * Generate code for zero or more of the DATA IN, DATA OUT phases
- * in the format
- *
- * CALL data_transfer, WHEN NOT phase
- * MOVE first buffer length, first buffer address, WHEN phase
- * ...
- * MOVE last buffer length, last buffer address, WHEN phase
- * JUMP other_transfer
- */
-
-/*
- * See if we're getting to data transfer by generating an unconditional
- * interrupt.
- */
-#if 0
- if (datain) {
- cmd_datain[0] = 0x98080000;
- cmd_datain[1] = 0x03ffd00d;
- cmd_datain += 2;
- }
-#endif
-
-/*
- * XXX - I'm undecided whether all of this nonsense is faster
- * in the long run, or whether I should just go and implement a loop
- * on the NCR chip using table indirect mode?
- *
- * In any case, this is how it _must_ be done for 53c700/700-66 chips,
- * so this stays even when we come up with something better.
- *
- * When we're limited to 1 simultaneous command, no overlapping processing,
- * we're seeing 630K/sec, with 7% CPU usage on a slow Syquest 45M
- * drive.
- *
- * Not bad, not good. We'll see.
- */
-
- tmp->bounce.len = 0; /* Assume aligned buffer */
-
- for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
- cmd_dataout += 4, ++i) {
- u32 vbuf = cmd->use_sg
- ? (u32)page_address(((struct scatterlist *)cmd->request_buffer)[i].page)+
- ((struct scatterlist *)cmd->request_buffer)[i].offset
- : (u32)(cmd->request_buffer);
- u32 bbuf = virt_to_bus((void *)vbuf);
- u32 count = cmd->use_sg ?
- ((struct scatterlist *)cmd->request_buffer)[i].length :
- cmd->request_bufflen;
-
- /*
- * If we have buffers which are not aligned with 16 byte cache
- * lines, then we just hope nothing accesses the other parts of
- * those cache lines while the transfer is in progress. That would
- * fill the cache, and subsequent reads of the dma data would pick
- * up the wrong thing.
- * XXX We need a bounce buffer to handle that correctly.
- */
-
- if (((bbuf & 15) || (count & 15)) && (datain || dataout))
- {
- /* Bounce buffer needed */
- if (cmd->use_sg)
- printk ("53c7xx: Non-aligned buffer with use_sg\n");
- else if (datain && dataout)
- printk ("53c7xx: Non-aligned buffer with datain && dataout\n");
- else if (count > 256)
- printk ("53c7xx: Non-aligned transfer > 256 bytes\n");
- else
- {
- if (datain)
- {
- tmp->bounce.len = count;
- tmp->bounce.addr = vbuf;
- bbuf = virt_to_bus(tmp->bounce.buf);
- tmp->bounce.buf[0] = 0xff;
- tmp->bounce.buf[1] = 0xfe;
- tmp->bounce.buf[2] = 0xfd;
- tmp->bounce.buf[3] = 0xfc;
- }
- if (dataout)
- {
- memcpy ((void *)tmp->bounce.buf, (void *)vbuf, count);
- bbuf = virt_to_bus(tmp->bounce.buf);
- }
- }
- }
-
- if (datain) {
- cache_clear(virt_to_phys((void *)vbuf), count);
- /* CALL other_in, WHEN NOT DATA_IN */
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
- DCMD_TCI_IO) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_datain[1] = virt_to_bus (hostdata->script) +
- hostdata->E_other_in;
- /* MOVE count, buf, WHEN DATA_IN */
- cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
- << 24) | count;
- cmd_datain[3] = bbuf;
-#if 0
- print_insn (host, cmd_datain, "dynamic ", 1);
- print_insn (host, cmd_datain + 2, "dynamic ", 1);
-#endif
- }
- if (dataout) {
- cache_push(virt_to_phys((void *)vbuf), count);
- /* CALL other_out, WHEN NOT DATA_OUT */
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_out;
- /* MOVE count, buf, WHEN DATA+OUT */
- cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
- | count;
- cmd_dataout[3] = bbuf;
-#if 0
- print_insn (host, cmd_dataout, "dynamic ", 1);
- print_insn (host, cmd_dataout + 2, "dynamic ", 1);
-#endif
- }
- }
-
- /*
- * Install JUMP instructions after the data transfer routines to return
- * control to the do_other_transfer routines.
- */
-
-
- if (datain) {
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_datain[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
-#if 0
- print_insn (host, cmd_datain, "dynamic jump ", 1);
-#endif
- cmd_datain += 2;
- }
-#if 0
- if (datain) {
- cmd_datain[0] = 0x98080000;
- cmd_datain[1] = 0x03ffdeed;
- cmd_datain += 2;
- }
-#endif
- if (dataout) {
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
-#if 0
- print_insn (host, cmd_dataout, "dynamic jump ", 1);
-#endif
- cmd_dataout += 2;
- }
-
- return tmp;
-}
-
-/*
- * Function : int NCR53c7xx_queue_command (Scsi_Cmnd *cmd,
- * void (*done)(Scsi_Cmnd *))
- *
- * Purpose : enqueues a SCSI command
- *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- * a pointer to the command descriptor.
- *
- * Returns : 0
- *
- * Side effects :
- * cmd is added to the per instance driver issue_queue, with major
- * twiddling done to the host specific fields of cmd. If the
- * process_issue_queue coroutine isn't running, it is restarted.
- *
- * NOTE : we use the host_scribble field of the Scsi_Cmnd structure to
- * hold our own data, and pervert the ptr field of the SCp field
- * to create a linked list.
- */
-
-int
-NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- unsigned long flags;
- Scsi_Cmnd *tmp;
-
- cmd->scsi_done = done;
- cmd->host_scribble = NULL;
- cmd->SCp.ptr = NULL;
- cmd->SCp.buffer = NULL;
-
-#ifdef VALID_IDS
- /* Ignore commands on invalid IDs */
- if (!hostdata->valid_ids[cmd->device->id]) {
- printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
- cmd->device->id, cmd->device->lun);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- return 0;
- }
-#endif
-
- local_irq_save(flags);
- if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY))
- || ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
- !(hostdata->debug_lun_limit[cmd->device->id] & (1 << cmd->device->lun)))
-#ifdef LINUX_1_2
- || cmd->device->id > 7
-#else
- || cmd->device->id >= host->max_id
-#endif
- || cmd->device->id == host->this_id
- || hostdata->state == STATE_DISABLED) {
- printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
- cmd->device->id, cmd->device->lun);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- local_irq_restore(flags);
- return 0;
- }
-
- if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
- (hostdata->debug_count_limit == 0)) {
- printk("scsi%d : maximum commands exceeded\n", host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- local_irq_restore(flags);
- return 0;
- }
-
- if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
- switch (cmd->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
- host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
- done(cmd);
- local_irq_restore(flags);
- return 0;
- }
- }
-
- if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
- hostdata->debug_count_limit != -1)
- --hostdata->debug_count_limit;
-
- cmd->result = 0xffff; /* The NCR will overwrite message
- and status with valid data */
- cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
-
- /*
- * REQUEST SENSE commands are inserted at the head of the queue
- * so that we do not clear the contingent allegiance condition
- * they may be looking at.
- */
-
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->SCp.ptr;
- tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
- tmp->SCp.ptr = (unsigned char *) cmd;
- }
- local_irq_restore(flags);
- run_process_issue_queue();
- return 0;
-}
-
-/*
- * Function : void to_schedule_list (struct Scsi_Host *host,
- * struct NCR53c7x0_hostdata * hostdata, Scsi_Cmnd *cmd)
- *
- * Purpose : takes a SCSI command which was just removed from the
- * issue queue, and deals with it by inserting it in the first
- * free slot in the schedule list or by terminating it immediately.
- *
- * Inputs :
- * host - SCSI host adapter; hostdata - hostdata structure for
- * this adapter; cmd - a pointer to the command; should have
- * the host_scribble field initialized to point to a valid
- *
- * Side effects :
- * cmd is added to the per instance schedule list, with minor
- * twiddling done to the host specific fields of cmd.
- *
- */
-
-static __inline__ void
-to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
- struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- Scsi_Cmnd *tmp = cmd->cmd;
- unsigned long flags;
- /* dsa start is negative, so subtraction is used */
- volatile u32 *ncrcurrent;
-
- int i;
- NCR53c7x0_local_setup(host);
-#if 0
- printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no,
- virt_to_bus(hostdata->dsa), hostdata->dsa);
-#endif
-
- local_irq_save(flags);
-
- /*
- * Work around race condition : if an interrupt fired and we
- * got disabled forget about this command.
- */
-
- if (hostdata->state == STATE_DISABLED) {
- printk("scsi%d : driver disabled\n", host->host_no);
- tmp->result = (DID_BAD_TARGET << 16);
- cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
- hostdata->free = cmd;
- tmp->scsi_done(tmp);
- local_irq_restore(flags);
- return;
- }
-
- for (i = host->can_queue, ncrcurrent = hostdata->schedule;
- i > 0 && ncrcurrent[0] != hostdata->NOP_insn;
- --i, ncrcurrent += 2 /* JUMP instructions are two words */);
-
- if (i > 0) {
- ++hostdata->busy[tmp->device->id][tmp->device->lun];
- cmd->next = hostdata->running_list;
- hostdata->running_list = cmd;
-
- /* Restore this instruction to a NOP once the command starts */
- cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
- sizeof(u32)] = (u32) virt_to_bus ((void *)ncrcurrent);
- /* Replace the current jump operand. */
- ncrcurrent[1] =
- virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
- hostdata->E_dsa_code_template;
- /* Replace the NOP instruction with a JUMP */
- ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- } else {
- printk ("scsi%d: no free slot\n", host->host_no);
- disable(host);
- tmp->result = (DID_ERROR << 16);
- cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
- hostdata->free = cmd;
- tmp->scsi_done(tmp);
- local_irq_restore(flags);
- return;
- }
-
- /*
- * If the NCR chip is in an idle state, start it running the scheduler
- * immediately. Otherwise, signal the chip to jump to schedule as
- * soon as it is idle.
- */
-
- if (hostdata->idle) {
- hostdata->idle = 0;
- hostdata->state = STATE_RUNNING;
- NCR53c7x0_write32 (DSP_REG, virt_to_bus ((void *)hostdata->schedule));
- if (hostdata->options & OPTION_DEBUG_TRACE)
- NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
- DCNTL_SSM | DCNTL_STD);
- } else {
- NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
- }
-
- local_irq_restore(flags);
-}
-
-/*
- * Function : busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata
- * *hostdata, Scsi_Cmnd *cmd)
- *
- * Purpose : decide if we can pass the given SCSI command on to the
- * device in question or not.
- *
- * Returns : non-zero when we're busy, 0 when we aren't.
- */
-
-static __inline__ int
-busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
- Scsi_Cmnd *cmd) {
- /* FIXME : in the future, this needs to accommodate SCSI-II tagged
- queuing, and we may be able to play with fairness here a bit.
- */
- return hostdata->busy[cmd->device->id][cmd->device->lun];
-}
-
-/*
- * Function : process_issue_queue (void)
- *
- * Purpose : transfer commands from the issue queue to NCR start queue
- * of each NCR53c7/8xx in the system, avoiding kernel stack
- * overflows when the scsi_done() function is invoked recursively.
- *
- * NOTE : process_issue_queue exits with interrupts *disabled*, so the
- * caller must reenable them if it desires.
- *
- * NOTE : process_issue_queue should be called from both
- * NCR53c7x0_queue_command() and from the interrupt handler
- * after command completion in case NCR53c7x0_queue_command()
- * isn't invoked again but we've freed up resources that are
- * needed.
- */
-
-static void
-process_issue_queue (unsigned long flags) {
- Scsi_Cmnd *tmp, *prev;
- struct Scsi_Host *host;
- struct NCR53c7x0_hostdata *hostdata;
- int done;
-
- /*
- * We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set process_issue_queue_running to 0 and exit.
- *
- * Interrupts are enabled before doing various other internal
- * instructions, after we've decided that we need to run through
- * the loop again.
- *
- */
-
- do {
- local_irq_disable(); /* Freeze request queues */
- done = 1;
- for (host = first_host; host && host->hostt == the_template;
- host = host->next) {
- hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
- local_irq_disable();
- if (hostdata->issue_queue) {
- if (hostdata->state == STATE_DISABLED) {
- tmp = (Scsi_Cmnd *) hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
- tmp->result = (DID_BAD_TARGET << 16);
- if (tmp->host_scribble) {
- ((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
- hostdata->free;
- hostdata->free =
- (struct NCR53c7x0_cmd *)tmp->host_scribble;
- tmp->host_scribble = NULL;
- }
- tmp->scsi_done (tmp);
- done = 0;
- } else
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
- prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
- tmp->SCp.ptr)
- if (!tmp->host_scribble ||
- !busyp (host, hostdata, tmp)) {
- if (prev)
- prev->SCp.ptr = tmp->SCp.ptr;
- else
- hostdata->issue_queue = (Scsi_Cmnd *)
- tmp->SCp.ptr;
- tmp->SCp.ptr = NULL;
- if (tmp->host_scribble) {
- if (hostdata->options & OPTION_DEBUG_QUEUES)
- printk ("scsi%d : moving command for target %d lun %d to start list\n",
- host->host_no, tmp->device->id, tmp->device->lun);
-
-
- to_schedule_list (host, hostdata,
- (struct NCR53c7x0_cmd *)
- tmp->host_scribble);
- } else {
- if (((tmp->result & 0xff) == 0xff) ||
- ((tmp->result & 0xff00) == 0xff00)) {
- printk ("scsi%d : danger Will Robinson!\n",
- host->host_no);
- tmp->result = DID_ERROR << 16;
- disable (host);
- }
- tmp->scsi_done(tmp);
- }
- done = 0;
- } /* if target/lun is not busy */
- } /* if hostdata->issue_queue */
- if (!done)
- local_irq_restore(flags);
- } /* for host */
- } while (!done);
- process_issue_queue_running = 0;
-}
-
-/*
- * Function : static void intr_scsi (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : handle all SCSI interrupts, indicated by the setting
- * of the SIP bit in the ISTAT register.
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- */
-
-static void
-intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- unsigned char sstat0_sist0, sist1, /* Registers */
- fatal; /* Did a fatal interrupt
- occur ? */
-
- NCR53c7x0_local_setup(host);
-
- fatal = 0;
-
- sstat0_sist0 = NCR53c7x0_read8(SSTAT0_REG);
- sist1 = 0;
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
- sstat0_sist0, sist1);
-
- /* 250ms selection timeout */
- if (sstat0_sist0 & SSTAT0_700_STO) {
- fatal = 1;
- if (hostdata->options & OPTION_DEBUG_INTR) {
- printk ("scsi%d : Selection Timeout\n", host->host_no);
- if (cmd) {
- printk("scsi%d : target %d, lun %d, command ",
- host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
- __scsi_print_command (cmd->cmd->cmnd);
- printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
- NCR53c7x0_read32(DSP_REG),
- bus_to_virt(NCR53c7x0_read32(DSP_REG)));
- } else {
- printk("scsi%d : no command\n", host->host_no);
- }
- }
-/*
- * XXX - question : how do we want to handle the Illegal Instruction
- * interrupt, which may occur before or after the Selection Timeout
- * interrupt?
- */
-
- if (1) {
- hostdata->idle = 1;
- hostdata->expecting_sto = 0;
-
- if (hostdata->test_running) {
- hostdata->test_running = 0;
- hostdata->test_completed = 3;
- } else if (cmd) {
- abnormal_finished(cmd, DID_BAD_TARGET << 16);
- }
-#if 0
- hostdata->intrs = 0;
-#endif
- }
- }
-
-/*
- * FIXME : in theory, we can also get a UDC when a STO occurs.
- */
- if (sstat0_sist0 & SSTAT0_UDC) {
- fatal = 1;
- if (cmd) {
- printk("scsi%d : target %d lun %d unexpected disconnect\n",
- host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
- print_lots (host);
- abnormal_finished(cmd, DID_ERROR << 16);
- } else
- printk("scsi%d : unexpected disconnect (no command)\n",
- host->host_no);
-
- hostdata->dsp = (u32 *) hostdata->schedule;
- hostdata->dsp_changed = 1;
- }
-
- /* SCSI PARITY error */
- if (sstat0_sist0 & SSTAT0_PAR) {
- fatal = 1;
- if (cmd && cmd->cmd) {
- printk("scsi%d : target %d lun %d parity error.\n",
- host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
- abnormal_finished (cmd, DID_PARITY << 16);
- } else
- printk("scsi%d : parity error\n", host->host_no);
- /* Should send message out, parity error */
-
- /* XXX - Reduce synchronous transfer rate! */
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- /* SCSI GROSS error */
- }
-
- if (sstat0_sist0 & SSTAT0_SGE) {
- fatal = 1;
- printk("scsi%d : gross error, saved2_dsa = 0x%x\n", host->host_no,
- (unsigned int)hostdata->saved2_dsa);
- print_lots (host);
-
- /*
- * A SCSI gross error may occur when we have
- *
- * - A synchronous offset which causes the SCSI FIFO to be overwritten.
- *
- * - A REQ which causes the maximum synchronous offset programmed in
- * the SXFER register to be exceeded.
- *
- * - A phase change with an outstanding synchronous offset.
- *
- * - Residual data in the synchronous data FIFO, with a transfer
- * other than a synchronous receive is started.$#
- */
-
-
- /* XXX Should deduce synchronous transfer rate! */
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- /* Phase mismatch */
- }
-
- if (sstat0_sist0 & SSTAT0_MA) {
- fatal = 1;
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : SSTAT0_MA\n", host->host_no);
- intr_phase_mismatch (host, cmd);
- }
-
-#if 0
- if (sstat0_sist0 & SIST0_800_RSL)
- printk ("scsi%d : Oh no Mr. Bill!\n", host->host_no);
-#endif
-
-/*
- * If a fatal SCSI interrupt occurs, we must insure that the DMA and
- * SCSI FIFOs were flushed.
- */
-
- if (fatal) {
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
-
- if (!(hostdata->dstat & DSTAT_DFE)) {
- printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
- /*
- * Really need to check this code for 710 RGH.
- * Havn't seen any problems, but maybe we should FLUSH before
- * clearing sometimes.
- */
- NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
- while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
- ;
- hostdata->dstat |= DSTAT_DFE;
- }
- }
-}
-
-#ifdef CYCLIC_TRACE
-
-/*
- * The following implements a cyclic log of instructions executed, if you turn
- * TRACE on. It will also print the log for you. Very useful when debugging
- * 53c710 support, possibly not really needed any more.
- */
-
-u32 insn_log[4096];
-u32 insn_log_index = 0;
-
-void log1 (u32 i)
-{
- insn_log[insn_log_index++] = i;
- if (insn_log_index == 4096)
- insn_log_index = 0;
-}
-
-void log_insn (u32 *ip)
-{
- log1 ((u32)ip);
- log1 (*ip);
- log1 (*(ip+1));
- if (((*ip >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
- log1 (*(ip+2));
-}
-
-void dump_log(void)
-{
- int cnt = 0;
- int i = insn_log_index;
- int size;
- struct Scsi_Host *host = first_host;
-
- while (cnt < 4096) {
- printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4);
- if (++i == 4096)
- i = 0;
- cnt++;
- if (((insn_log[i] >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
- size = 3;
- else
- size = 2;
- while (size--) {
- printk ("%08x ", insn_log[i]);
- if (++i == 4096)
- i = 0;
- cnt++;
- }
- printk ("\n");
- }
-}
-#endif
-
-
-/*
- * Function : static void NCR53c7x0_intfly (struct Scsi_Host *host)
- *
- * Purpose : Scan command queue for specified host, looking for completed
- * commands.
- *
- * Inputs : Scsi_Host pointer.
- *
- * This is called from the interrupt handler, when a simulated INTFLY
- * interrupt occurs.
- */
-
-static void
-NCR53c7x0_intfly (struct Scsi_Host *host)
-{
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata; /* host->hostdata[0] */
- struct NCR53c7x0_cmd *cmd, /* command which halted */
- **cmd_prev_ptr;
- unsigned long flags;
- char search_found = 0; /* Got at least one ? */
-
- hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
- NCR53c7x0_local_setup(host);
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : INTFLY\n", host->host_no);
-
- /*
- * Traverse our list of running commands, and look
- * for those with valid (non-0xff ff) status and message
- * bytes encoded in the result which signify command
- * completion.
- */
-
- local_irq_save(flags);
-restart:
- for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)&(hostdata->running_list),
- cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
- cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
- cmd = (struct NCR53c7x0_cmd *) cmd->next)
- {
- Scsi_Cmnd *tmp;
-
- if (!cmd) {
- printk("scsi%d : very weird.\n", host->host_no);
- break;
- }
-
- if (!(tmp = cmd->cmd)) {
- printk("scsi%d : weird. NCR53c7x0_cmd has no Scsi_Cmnd\n",
- host->host_no);
- continue;
- }
- /* Copy the result over now; may not be complete,
- * but subsequent tests may as well be done on
- * cached memory.
- */
- tmp->result = cmd->result;
-
- if (((tmp->result & 0xff) == 0xff) ||
- ((tmp->result & 0xff00) == 0xff00))
- continue;
-
- search_found = 1;
-
- if (cmd->bounce.len)
- memcpy ((void *)cmd->bounce.addr,
- (void *)cmd->bounce.buf, cmd->bounce.len);
-
- /* Important - remove from list _before_ done is called */
- if (cmd_prev_ptr)
- *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
-
- --hostdata->busy[tmp->device->id][tmp->device->lun];
- cmd->next = hostdata->free;
- hostdata->free = cmd;
-
- tmp->host_scribble = NULL;
-
- if (hostdata->options & OPTION_DEBUG_INTR) {
- printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ",
- host->host_no, tmp->pid, tmp->device->id, tmp->device->lun, tmp->result);
- __scsi_print_command (tmp->cmnd);
- }
-
- tmp->scsi_done(tmp);
- goto restart;
- }
- local_irq_restore(flags);
-
- if (!search_found) {
- printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
- host->host_no);
- } else {
- run_process_issue_queue();
- }
- return;
-}
-
-/*
- * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id)
- *
- * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
- * the same IRQ line.
- *
- * Inputs : Since we're using the IRQF_DISABLED interrupt handler
- * semantics, irq indicates the interrupt which invoked
- * this handler.
- *
- * On the 710 we simualte an INTFLY with a script interrupt, and the
- * script interrupt handler will call back to this function.
- */
-
-static irqreturn_t
-NCR53c7x0_intr (int irq, void *dev_id)
-{
- NCR53c7x0_local_declare();
- struct Scsi_Host *host; /* Host we are looking at */
- unsigned char istat; /* Values of interrupt regs */
- struct NCR53c7x0_hostdata *hostdata; /* host->hostdata[0] */
- struct NCR53c7x0_cmd *cmd; /* command which halted */
- u32 *dsa; /* DSA */
- int handled = 0;
-
-#ifdef NCR_DEBUG
- char buf[80]; /* Debugging sprintf buffer */
- size_t buflen; /* Length of same */
-#endif
-
- host = (struct Scsi_Host *)dev_id;
- hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
- NCR53c7x0_local_setup(host);
-
- /*
- * Only read istat once per loop, since reading it again will unstack
- * interrupts
- */
-
- while ((istat = NCR53c7x0_read8(hostdata->istat)) & (ISTAT_SIP|ISTAT_DIP)) {
- handled = 1;
- hostdata->dsp_changed = 0;
- hostdata->dstat_valid = 0;
- hostdata->state = STATE_HALTED;
-
- if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK)
- printk ("scsi%d : SCSI FIFO not empty\n", host->host_no);
-
- /*
- * NCR53c700 and NCR53c700-66 change the current SCSI
- * process, hostdata->ncrcurrent, in the Linux driver so
- * cmd = hostdata->ncrcurrent.
- *
- * With other chips, we must look through the commands
- * executing and find the command structure which
- * corresponds to the DSA register.
- */
-
- if (hostdata->options & OPTION_700) {
- cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent;
- } else {
- dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
- for (cmd = (struct NCR53c7x0_cmd *) hostdata->running_list;
- cmd && (dsa + (hostdata->dsa_start / sizeof(u32))) != cmd->dsa;
- cmd = (struct NCR53c7x0_cmd *)(cmd->next))
- ;
- }
- if (hostdata->options & OPTION_DEBUG_INTR) {
- if (cmd) {
- printk("scsi%d : interrupt for pid %lu, id %d, lun %d ",
- host->host_no, cmd->cmd->pid, (int) cmd->cmd->device->id,
- (int) cmd->cmd->device->lun);
- __scsi_print_command (cmd->cmd->cmnd);
- } else {
- printk("scsi%d : no active command\n", host->host_no);
- }
- }
-
- if (istat & ISTAT_SIP) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : ISTAT_SIP\n", host->host_no);
- intr_scsi (host, cmd);
- }
-
- if (istat & ISTAT_DIP) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : ISTAT_DIP\n", host->host_no);
- intr_dma (host, cmd);
- }
-
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
-
- if (!(hostdata->dstat & DSTAT_DFE)) {
- printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
- /* Really need to check this out for 710 RGH */
- NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
- while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
- ;
- hostdata->dstat |= DSTAT_DFE;
- }
-
- if (!hostdata->idle && hostdata->state == STATE_HALTED) {
- if (!hostdata->dsp_changed)
- hostdata->dsp = (u32 *)bus_to_virt(NCR53c7x0_read32(DSP_REG));
-#if 0
- printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n",
- host->host_no, virt_to_bus(hostdata->dsp), hostdata->dsp);
-#endif
-
- hostdata->state = STATE_RUNNING;
- NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
- if (hostdata->options & OPTION_DEBUG_TRACE) {
-#ifdef CYCLIC_TRACE
- log_insn (hostdata->dsp);
-#else
- print_insn (host, hostdata->dsp, "t ", 1);
-#endif
- NCR53c7x0_write8 (DCNTL_REG,
- hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD);
- }
- }
- }
- return IRQ_HANDLED;
-}
-
-
-/*
- * Function : static int abort_connected (struct Scsi_Host *host)
- *
- * Purpose : Assuming that the NCR SCSI processor is currently
- * halted, break the currently established nexus. Clean
- * up of the NCR53c7x0_cmd and Scsi_Cmnd structures should
- * be done on receipt of the abort interrupt.
- *
- * Inputs : host - SCSI host
- *
- */
-
-static int
-abort_connected (struct Scsi_Host *host) {
-#ifdef NEW_ABORT
- NCR53c7x0_local_declare();
-#endif
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
-/* FIXME : this probably should change for production kernels; at the
- least, counter should move to a per-host structure. */
- static int counter = 5;
-#ifdef NEW_ABORT
- int sstat, phase, offset;
- u32 *script;
- NCR53c7x0_local_setup(host);
-#endif
-
- if (--counter <= 0) {
- disable(host);
- return 0;
- }
-
- printk ("scsi%d : DANGER : abort_connected() called \n",
- host->host_no);
-
-#ifdef NEW_ABORT
-
-/*
- * New strategy : Rather than using a generic abort routine,
- * we'll specifically try to source or sink the appropriate
- * amount of data for the phase we're currently in (taking into
- * account the current synchronous offset)
- */
-
- sstat = NCR53c8x0_read8 (SSTAT2_REG);
- offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
- phase = sstat & SSTAT2_PHASE_MASK;
-
-/*
- * SET ATN
- * MOVE source_or_sink, WHEN CURRENT PHASE
- * < repeat for each outstanding byte >
- * JUMP send_abort_message
- */
-
- script = hostdata->abort_script = kmalloc (
- 8 /* instruction size */ * (
- 1 /* set ATN */ +
- (!offset ? 1 : offset) /* One transfer per outstanding byte */ +
- 1 /* send abort message */),
- GFP_ATOMIC);
-
-
-#else /* def NEW_ABORT */
- hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
- sizeof(u32);
-#endif /* def NEW_ABORT */
- hostdata->dsp_changed = 1;
-
-/* XXX - need to flag the command as aborted after the abort_connected
- code runs
- */
- return 0;
-}
-
-/*
- * Function : static int datapath_residual (Scsi_Host *host)
- *
- * Purpose : return residual data count of what's in the chip.
- *
- * Inputs : host - SCSI host
- */
-
-static int
-datapath_residual (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- int count, synchronous, sstat;
- unsigned int ddir;
-
- NCR53c7x0_local_setup(host);
- /* COMPAT : the 700 and 700-66 need to use DFIFO_00_BO_MASK */
- count = ((NCR53c7x0_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
- (NCR53c7x0_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
- synchronous = NCR53c7x0_read8 (SXFER_REG) & SXFER_MO_MASK;
- /* COMPAT : DDIR is elsewhere on non-'8xx chips. */
- ddir = NCR53c7x0_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
-
- if (ddir) {
- /* Receive */
- if (synchronous)
- count += (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
- else
- if (NCR53c7x0_read8 (SSTAT1_REG) & SSTAT1_ILF)
- ++count;
- } else {
- /* Send */
- sstat = NCR53c7x0_read8 (SSTAT1_REG);
- if (sstat & SSTAT1_OLF)
- ++count;
- if (synchronous && (sstat & SSTAT1_ORF))
- ++count;
- }
- return count;
-}
-
-/*
- * Function : static const char * sbcl_to_phase (int sbcl)_
- *
- * Purpose : Convert SBCL register to user-parsable phase representation
- *
- * Inputs : sbcl - value of sbcl register
- */
-
-
-static const char *
-sbcl_to_phase (int sbcl) {
- switch (sbcl & SBCL_PHASE_MASK) {
- case SBCL_PHASE_DATAIN:
- return "DATAIN";
- case SBCL_PHASE_DATAOUT:
- return "DATAOUT";
- case SBCL_PHASE_MSGIN:
- return "MSGIN";
- case SBCL_PHASE_MSGOUT:
- return "MSGOUT";
- case SBCL_PHASE_CMDOUT:
- return "CMDOUT";
- case SBCL_PHASE_STATIN:
- return "STATUSIN";
- default:
- return "unknown";
- }
-}
-
-/*
- * Function : static const char * sstat2_to_phase (int sstat)_
- *
- * Purpose : Convert SSTAT2 register to user-parsable phase representation
- *
- * Inputs : sstat - value of sstat register
- */
-
-
-static const char *
-sstat2_to_phase (int sstat) {
- switch (sstat & SSTAT2_PHASE_MASK) {
- case SSTAT2_PHASE_DATAIN:
- return "DATAIN";
- case SSTAT2_PHASE_DATAOUT:
- return "DATAOUT";
- case SSTAT2_PHASE_MSGIN:
- return "MSGIN";
- case SSTAT2_PHASE_MSGOUT:
- return "MSGOUT";
- case SSTAT2_PHASE_CMDOUT:
- return "CMDOUT";
- case SSTAT2_PHASE_STATIN:
- return "STATUSIN";
- default:
- return "unknown";
- }
-}
-
-/*
- * Function : static void intr_phase_mismatch (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : Handle phase mismatch interrupts
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- *
- * Side effects : The abort_connected() routine is called or the NCR chip
- * is restarted, jumping to the command_complete entry point, or
- * patching the address and transfer count of the current instruction
- * and calling the msg_in entry point as appropriate.
- */
-
-static void
-intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- u32 dbc_dcmd, *dsp, *dsp_next;
- unsigned char dcmd, sbcl;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int residual;
- enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action =
- ACTION_ABORT_PRINT;
- const char *where = NULL;
-
- NCR53c7x0_local_setup(host);
-
- /*
- * Corrective action is based on where in the SCSI SCRIPT(tm) the error
- * occurred, as well as which SCSI phase we are currently in.
- */
- dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
-
- /*
- * Fetch the current instruction, and remove the operands for easier
- * interpretation.
- */
- dbc_dcmd = NCR53c7x0_read32(DBC_REG);
- dcmd = (dbc_dcmd & 0xff000000) >> 24;
- /*
- * Like other processors, the NCR adjusts the instruction pointer before
- * instruction decode. Set the DSP address back to what it should
- * be for this instruction based on its size (2 or 3 32 bit words).
- */
- dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
-
-
- /*
- * Read new SCSI phase from the SBCL lines. Since all of our code uses
- * a WHEN conditional instead of an IF conditional, we don't need to
- * wait for a new REQ.
- */
- sbcl = NCR53c7x0_read8(SBCL_REG) & SBCL_PHASE_MASK;
-
- if (!cmd) {
- action = ACTION_ABORT_PRINT;
- where = "no current command";
- /*
- * The way my SCSI SCRIPTS(tm) are architected, recoverable phase
- * mismatches should only occur where we're doing a multi-byte
- * BMI instruction. Specifically, this means
- *
- * - select messages (a SCSI-I target may ignore additional messages
- * after the IDENTIFY; any target may reject a SDTR or WDTR)
- *
- * - command out (targets may send a message to signal an error
- * condition, or go into STATUSIN after they've decided
- * they don't like the command.
- *
- * - reply_message (targets may reject a multi-byte message in the
- * middle)
- *
- * - data transfer routines (command completion with buffer space
- * left, disconnect message, or error message)
- */
- } else if (((dsp >= cmd->data_transfer_start &&
- dsp < cmd->data_transfer_end)) || dsp == (cmd->residual + 2)) {
- if ((dcmd & (DCMD_TYPE_MASK|DCMD_BMI_OP_MASK|DCMD_BMI_INDIRECT|
- DCMD_BMI_MSG|DCMD_BMI_CD)) == (DCMD_TYPE_BMI|
- DCMD_BMI_OP_MOVE_I)) {
- residual = datapath_residual (host);
- if (hostdata->options & OPTION_DEBUG_DISCONNECT)
- printk ("scsi%d : handling residual transfer (+ %d bytes from DMA FIFO)\n",
- host->host_no, residual);
-
- /*
- * The first instruction is a CALL to the alternate handler for
- * this data transfer phase, so we can do calls to
- * munge_msg_restart as we would if control were passed
- * from normal dynamic code.
- */
- if (dsp != cmd->residual + 2) {
- cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
- ((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd->residual[1] = virt_to_bus(hostdata->script)
- + ((dcmd & DCMD_BMI_IO)
- ? hostdata->E_other_in : hostdata->E_other_out);
- }
-
- /*
- * The second instruction is the a data transfer block
- * move instruction, reflecting the pointer and count at the
- * time of the phase mismatch.
- */
- cmd->residual[2] = dbc_dcmd + residual;
- cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
-
- /*
- * The third and final instruction is a jump to the instruction
- * which follows the instruction which had to be 'split'
- */
- if (dsp != cmd->residual + 2) {
- cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->residual[5] = virt_to_bus(dsp_next);
- }
-
- /*
- * For the sake of simplicity, transfer control to the
- * conditional CALL at the start of the residual buffer.
- */
- hostdata->dsp = cmd->residual;
- hostdata->dsp_changed = 1;
- action = ACTION_CONTINUE;
- } else {
- where = "non-BMI dynamic DSA code";
- action = ACTION_ABORT_PRINT;
- }
- } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4 + 2)) {
- /* RGH 290697: Added +2 above, to compensate for the script
- * instruction which disables the selection timer. */
- /* Release ATN */
- NCR53c7x0_write8 (SOCL_REG, 0);
- switch (sbcl) {
- /*
- * Some devices (SQ555 come to mind) grab the IDENTIFY message
- * sent on selection, and decide to go into COMMAND OUT phase
- * rather than accepting the rest of the messages or rejecting
- * them. Handle these devices gracefully.
- */
- case SBCL_PHASE_CMDOUT:
- hostdata->dsp = dsp + 2 /* two _words_ */;
- hostdata->dsp_changed = 1;
- printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n",
- host->host_no, cmd->cmd->device->id);
- cmd->flags &= ~CMD_FLAG_SDTR;
- action = ACTION_CONTINUE;
- break;
- case SBCL_PHASE_MSGIN:
- hostdata->dsp = hostdata->script + hostdata->E_msg_in /
- sizeof(u32);
- hostdata->dsp_changed = 1;
- action = ACTION_CONTINUE;
- break;
- default:
- where="select message out";
- action = ACTION_ABORT_PRINT;
- }
- /*
- * Some SCSI devices will interpret a command as they read the bytes
- * off the SCSI bus, and may decide that the command is Bogus before
- * they've read the entire command off the bus.
- */
- } else if (dsp == hostdata->script + hostdata->E_cmdout_cmdout / sizeof
- (u32)) {
- hostdata->dsp = hostdata->script + hostdata->E_data_transfer /
- sizeof (u32);
- hostdata->dsp_changed = 1;
- action = ACTION_CONTINUE;
- /* FIXME : we need to handle message reject, etc. within msg_respond. */
-#ifdef notyet
- } else if (dsp == hostdata->script + hostdata->E_reply_message) {
- switch (sbcl) {
- /* Any other phase mismatches abort the currently executing command. */
-#endif
- } else {
- where = "unknown location";
- action = ACTION_ABORT_PRINT;
- }
-
- /* Flush DMA FIFO */
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
- if (!(hostdata->dstat & DSTAT_DFE)) {
- /* Really need to check this out for 710 RGH */
- NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
- while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
- hostdata->dstat |= DSTAT_DFE;
- }
-
- switch (action) {
- case ACTION_ABORT_PRINT:
- printk("scsi%d : %s : unexpected phase %s.\n",
- host->host_no, where ? where : "unknown location",
- sbcl_to_phase(sbcl));
- print_lots (host);
- /* Fall through to ACTION_ABORT */
- case ACTION_ABORT:
- abort_connected (host);
- break;
- case ACTION_CONTINUE:
- break;
- }
-
-#if 0
- if (hostdata->dsp_changed) {
- printk("scsi%d: new dsp 0x%p\n", host->host_no, hostdata->dsp);
- print_insn (host, hostdata->dsp, "", 1);
- }
-#endif
-}
-
-/*
- * Function : static void intr_bf (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : handle BUS FAULT interrupts
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- */
-
-static void
-intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- u32 *dsp,
- *next_dsp, /* Current dsp */
- *dsa,
- dbc_dcmd; /* DCMD (high eight bits) + DBC */
- char *reason = NULL;
- /* Default behavior is for a silent error, with a retry until we've
- exhausted retries. */
- enum {MAYBE, ALWAYS, NEVER} retry = MAYBE;
- int report = 0;
- NCR53c7x0_local_setup(host);
-
- dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
- next_dsp = bus_to_virt (NCR53c7x0_read32(DSP_REG));
- dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
-/* FIXME - check chip type */
- dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
-
- /*
- * Bus faults can be caused by either a Bad Address or
- * Target Abort. We should check the Received Target Abort
- * bit of the PCI status register and Master Abort Bit.
- *
- * - Master Abort bit indicates that no device claimed
- * the address with DEVSEL within five clocks
- *
- * - Target Abort bit indicates that a target claimed it,
- * but changed its mind once it saw the byte enables.
- *
- */
-
- /* 53c710, not PCI system */
- report = 1;
- reason = "Unknown";
-
-#ifndef notyet
- report = 1;
-#endif
- if (report && reason)
- {
- printk(KERN_ALERT "scsi%d : BUS FAULT reason = %s\n",
- host->host_no, reason ? reason : "unknown");
- print_lots (host);
- }
-
-#ifndef notyet
- retry = NEVER;
-#endif
-
- /*
- * TODO : we should attempt to recover from any spurious bus
- * faults. After X retries, we should figure that things are
- * sufficiently wedged, and call NCR53c7xx_reset.
- *
- * This code should only get executed once we've decided that we
- * cannot retry.
- */
-
- if (retry == NEVER) {
- printk(KERN_ALERT " mail richard@sleepie.demon.co.uk\n");
- FATAL (host);
- }
-}
-
-/*
- * Function : static void intr_dma (struct Scsi_Host *host,
- * struct NCR53c7x0_cmd *cmd)
- *
- * Purpose : handle all DMA interrupts, indicated by the setting
- * of the DIP bit in the ISTAT register.
- *
- * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
- * may be NULL.
- */
-
-static void
-intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned char dstat; /* DSTAT */
- u32 *dsp,
- *next_dsp, /* Current dsp */
- *dsa,
- dbc_dcmd; /* DCMD (high eight bits) + DBC */
- int tmp;
- unsigned long flags;
- NCR53c7x0_local_setup(host);
-
- if (!hostdata->dstat_valid) {
- hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
- hostdata->dstat_valid = 1;
- }
-
- dstat = hostdata->dstat;
-
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
-
- dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
- next_dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
- dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
-/* XXX - check chip type */
- dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
-
- /*
- * DSTAT_ABRT is the aborted interrupt. This is set whenever the
- * SCSI chip is aborted.
- *
- * With NCR53c700 and NCR53c700-66 style chips, we should only
- * get this when the chip is currently running the accept
- * reselect/select code and we have set the abort bit in the
- * ISTAT register.
- *
- */
-
- if (dstat & DSTAT_ABRT) {
-#if 0
- /* XXX - add code here to deal with normal abort */
- if ((hostdata->options & OPTION_700) && (hostdata->state ==
- STATE_ABORTING)) {
- } else
-#endif
- {
- printk(KERN_ALERT "scsi%d : unexpected abort interrupt at\n"
- " ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "s ", 1);
- FATAL (host);
- }
- }
-
- /*
- * DSTAT_SSI is the single step interrupt. Should be generated
- * whenever we have single stepped or are tracing.
- */
-
- if (dstat & DSTAT_SSI) {
- if (hostdata->options & OPTION_DEBUG_TRACE) {
- /* Don't print instr. until we write DSP at end of intr function */
- } else if (hostdata->options & OPTION_DEBUG_SINGLE) {
- print_insn (host, dsp, "s ", 0);
- local_irq_save(flags);
-/* XXX - should we do this, or can we get away with writing dsp? */
-
- NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) &
- ~DCNTL_SSM) | DCNTL_STD);
- local_irq_restore(flags);
- } else {
- printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
- " ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "", 1);
- printk(KERN_ALERT " mail drew@PoohSticks.ORG\n");
- FATAL (host);
- }
- }
-
- /*
- * DSTAT_IID / DSTAT_OPC (same bit, same meaning, only the name
- * is different) is generated whenever an illegal instruction is
- * encountered.
- *
- * XXX - we may want to emulate INTFLY here, so we can use
- * the same SCSI SCRIPT (tm) for NCR53c710 through NCR53c810
- * chips.
- */
-
- if (dstat & DSTAT_OPC) {
- /*
- * Ascertain if this IID interrupts occurred before or after a STO
- * interrupt. Since the interrupt handling code now leaves
- * DSP unmodified until _after_ all stacked interrupts have been
- * processed, reading the DSP returns the original DSP register.
- * This means that if dsp lies between the select code, and
- * message out following the selection code (where the IID interrupt
- * would have to have occurred by due to the implicit wait for REQ),
- * we have an IID interrupt resulting from a STO condition and
- * can ignore it.
- */
-
- if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
- (dsp <= (hostdata->script + hostdata->E_select_msgout /
- sizeof(u32) + 8))) || (hostdata->test_running == 2)) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : ignoring DSTAT_IID for SSTAT_STO\n",
- host->host_no);
- if (hostdata->expecting_iid) {
- hostdata->expecting_iid = 0;
- hostdata->idle = 1;
- if (hostdata->test_running == 2) {
- hostdata->test_running = 0;
- hostdata->test_completed = 3;
- } else if (cmd)
- abnormal_finished (cmd, DID_BAD_TARGET << 16);
- } else {
- hostdata->expecting_sto = 1;
- }
- /*
- * We can't guarantee we'll be able to execute the WAIT DISCONNECT
- * instruction within the 3.4us of bus free and arbitration delay
- * that a target can RESELECT in and assert REQ after we've dropped
- * ACK. If this happens, we'll get an illegal instruction interrupt.
- * Doing away with the WAIT DISCONNECT instructions broke everything,
- * so instead I'll settle for moving one WAIT DISCONNECT a few
- * instructions closer to the CLEAR ACK before it to minimize the
- * chances of this happening, and handle it if it occurs anyway.
- *
- * Simply continue with what we were doing, and control should
- * be transferred to the schedule routine which will ultimately
- * pass control onto the reselection or selection (not yet)
- * code.
- */
- } else if (dbc_dcmd == 0x48000000 && (NCR53c7x0_read8 (SBCL_REG) &
- SBCL_REQ)) {
- if (!(hostdata->options & OPTION_NO_PRINT_RACE))
- {
- printk("scsi%d: REQ before WAIT DISCONNECT IID\n",
- host->host_no);
- hostdata->options |= OPTION_NO_PRINT_RACE;
- }
- } else {
- printk(KERN_ALERT "scsi%d : invalid instruction\n", host->host_no);
- print_lots (host);
- printk(KERN_ALERT " mail Richard@sleepie.demon.co.uk with ALL\n"
- " boot messages and diagnostic output\n");
- FATAL (host);
- }
- }
-
- /*
- * DSTAT_BF are bus fault errors. DSTAT_800_BF is valid for 710 also.
- */
-
- if (dstat & DSTAT_800_BF) {
- intr_bf (host, cmd);
- }
-
-
- /*
- * DSTAT_SIR interrupts are generated by the execution of
- * the INT instruction. Since the exact values available
- * are determined entirely by the SCSI script running,
- * and are local to a particular script, a unique handler
- * is called for each script.
- */
-
- if (dstat & DSTAT_SIR) {
- if (hostdata->options & OPTION_DEBUG_INTR)
- printk ("scsi%d : DSTAT_SIR\n", host->host_no);
- switch ((tmp = hostdata->dstat_sir_intr (host, cmd))) {
- case SPECIFIC_INT_NOTHING:
- case SPECIFIC_INT_RESTART:
- break;
- case SPECIFIC_INT_ABORT:
- abort_connected(host);
- break;
- case SPECIFIC_INT_PANIC:
- printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "", 1);
- printk(KERN_ALERT " dstat_sir_intr() returned SPECIFIC_INT_PANIC\n");
- FATAL (host);
- break;
- case SPECIFIC_INT_BREAK:
- intr_break (host, cmd);
- break;
- default:
- printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
- print_insn (host, dsp, KERN_ALERT "", 1);
- printk(KERN_ALERT" dstat_sir_intr() returned unknown value %d\n",
- tmp);
- FATAL (host);
- }
- }
-}
-
-/*
- * Function : static int print_insn (struct Scsi_Host *host,
- * u32 *insn, int kernel)
- *
- * Purpose : print numeric representation of the instruction pointed
- * to by insn to the debugging or kernel message buffer
- * as appropriate.
- *
- * If desired, a user level program can interpret this
- * information.
- *
- * Inputs : host, insn - host, pointer to instruction, prefix -
- * string to prepend, kernel - use printk instead of debugging buffer.
- *
- * Returns : size, in u32s, of instruction printed.
- */
-
-/*
- * FIXME: should change kernel parameter so that it takes an ENUM
- * specifying severity - either KERN_ALERT or KERN_PANIC so
- * all panic messages are output with the same severity.
- */
-
-static int
-print_insn (struct Scsi_Host *host, const u32 *insn,
- const char *prefix, int kernel) {
- char buf[160], /* Temporary buffer and pointer. ICKY
- arbitrary length. */
-
-
- *tmp;
- unsigned char dcmd; /* dcmd register for *insn */
- int size;
-
- /*
- * Check to see if the instruction pointer is not bogus before
- * indirecting through it; avoiding red-zone at start of
- * memory.
- *
- * FIXME: icky magic needs to happen here on non-intel boxes which
- * don't have kernel memory mapped in like this. Might be reasonable
- * to use vverify()?
- */
-
- if (virt_to_phys((void *)insn) < PAGE_SIZE ||
- virt_to_phys((void *)(insn + 8)) > virt_to_phys(high_memory) ||
- ((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
- virt_to_phys((void *)(insn + 12)) > virt_to_phys(high_memory))) {
- size = 0;
- sprintf (buf, "%s%p: address out of range\n",
- prefix, insn);
- } else {
-/*
- * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
- * it should take const void * as argument.
- */
-#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
- sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
- (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
- insn[0], insn[1], bus_to_virt (insn[1]));
-#else
- /* Remove virtual addresses to reduce output, as they are the same */
- sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x",
- (prefix ? prefix : ""), (u32)insn, ((u32)insn -
- (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4,
- insn[0], insn[1]);
-#endif
- tmp = buf + strlen(buf);
- if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
-#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
- sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
- bus_to_virt(insn[2]));
-#else
- /* Remove virtual addr to reduce output, as it is the same */
- sprintf (tmp, " 0x%08x\n", insn[2]);
-#endif
- size = 3;
- } else {
- sprintf (tmp, "\n");
- size = 2;
- }
- }
-
- if (kernel)
- printk ("%s", buf);
-#ifdef NCR_DEBUG
- else {
- size_t len = strlen(buf);
- debugger_kernel_write(host, buf, len);
- }
-#endif
- return size;
-}
-
-/*
- * Function : int NCR53c7xx_abort (Scsi_Cmnd *cmd)
- *
- * Purpose : Abort an errant SCSI command, doing all necessary
- * cleanup of the issue_queue, running_list, shared Linux/NCR
- * dsa issue and reconnect queues.
- *
- * Inputs : cmd - command to abort, code - entire result field
- *
- * Returns : 0 on success, -1 on failure.
- */
-
-int
-NCR53c7xx_abort (Scsi_Cmnd *cmd) {
- NCR53c7x0_local_declare();
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
- host->hostdata[0] : NULL;
- unsigned long flags;
- struct NCR53c7x0_cmd *curr, **prev;
- Scsi_Cmnd *me, **last;
-#if 0
- static long cache_pid = -1;
-#endif
-
-
- if (!host) {
- printk ("Bogus SCSI command pid %ld; no host structure\n",
- cmd->pid);
- return SCSI_ABORT_ERROR;
- } else if (!hostdata) {
- printk ("Bogus SCSI host %d; no hostdata\n", host->host_no);
- return SCSI_ABORT_ERROR;
- }
- NCR53c7x0_local_setup(host);
-
-/*
- * CHECK : I don't think that reading ISTAT will unstack any interrupts,
- * since we need to write the INTF bit to clear it, and SCSI/DMA
- * interrupts don't clear until we read SSTAT/SIST and DSTAT registers.
- *
- * See that this is the case. Appears to be correct on the 710, at least.
- *
- * I suspect that several of our failures may be coming from a new fatal
- * interrupt (possibly due to a phase mismatch) happening after we've left
- * the interrupt handler, but before the PIC has had the interrupt condition
- * cleared.
- */
-
- if (NCR53c7x0_read8(hostdata->istat) & (ISTAT_DIP|ISTAT_SIP)) {
- printk ("scsi%d : dropped interrupt for command %ld\n", host->host_no,
- cmd->pid);
- NCR53c7x0_intr (host->irq, NULL, NULL);
- return SCSI_ABORT_BUSY;
- }
-
- local_irq_save(flags);
-#if 0
- if (cache_pid == cmd->pid)
- panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
- else
- cache_pid = cmd->pid;
-#endif
-
-
-/*
- * The command could be hiding in the issue_queue. This would be very
- * nice, as commands can't be moved from the high level driver's issue queue
- * into the shared queue until an interrupt routine is serviced, and this
- * moving is atomic.
- *
- * If this is the case, we don't have to worry about anything - we simply
- * pull the command out of the old queue, and call it aborted.
- */
-
- for (me = (Scsi_Cmnd *) hostdata->issue_queue,
- last = (Scsi_Cmnd **) &(hostdata->issue_queue);
- me && me != cmd; last = (Scsi_Cmnd **)&(me->SCp.ptr),
- me = (Scsi_Cmnd *)me->SCp.ptr);
-
- if (me) {
- *last = (Scsi_Cmnd *) me->SCp.ptr;
- if (me->host_scribble) {
- ((struct NCR53c7x0_cmd *)me->host_scribble)->next = hostdata->free;
- hostdata->free = (struct NCR53c7x0_cmd *) me->host_scribble;
- me->host_scribble = NULL;
- }
- cmd->result = DID_ABORT << 16;
- cmd->scsi_done(cmd);
- printk ("scsi%d : found command %ld in Linux issue queue\n",
- host->host_no, me->pid);
- local_irq_restore(flags);
- run_process_issue_queue();
- return SCSI_ABORT_SUCCESS;
- }
-
-/*
- * That failing, the command could be in our list of already executing
- * commands. If this is the case, drastic measures are called for.
- */
-
- for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list,
- prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
- curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **)
- &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
-
- if (curr) {
- if ((curr->result & 0xff) != 0xff && (curr->result & 0xff00) != 0xff00) {
- cmd->result = curr->result;
- if (prev)
- *prev = (struct NCR53c7x0_cmd *) curr->next;
- curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
- cmd->host_scribble = NULL;
- hostdata->free = curr;
- cmd->scsi_done(cmd);
- printk ("scsi%d : found finished command %ld in running list\n",
- host->host_no, cmd->pid);
- local_irq_restore(flags);
- return SCSI_ABORT_NOT_RUNNING;
- } else {
- printk ("scsi%d : DANGER : command running, can not abort.\n",
- cmd->device->host->host_no);
- local_irq_restore(flags);
- return SCSI_ABORT_BUSY;
- }
- }
-
-/*
- * And if we couldn't find it in any of our queues, it must have been
- * a dropped interrupt.
- */
-
- curr = (struct NCR53c7x0_cmd *) cmd->host_scribble;
- if (curr) {
- curr->next = hostdata->free;
- hostdata->free = curr;
- cmd->host_scribble = NULL;
- }
-
- if (curr == NULL || ((curr->result & 0xff00) == 0xff00) ||
- ((curr->result & 0xff) == 0xff)) {
- printk ("scsi%d : did this command ever run?\n", host->host_no);
- cmd->result = DID_ABORT << 16;
- } else {
- printk ("scsi%d : probably lost INTFLY, normal completion\n",
- host->host_no);
- cmd->result = curr->result;
-/*
- * FIXME : We need to add an additional flag which indicates if a
- * command was ever counted as BUSY, so if we end up here we can
- * decrement the busy count if and only if it is necessary.
- */
- --hostdata->busy[cmd->device->id][cmd->device->lun];
- }
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
-
-/*
- * We need to run process_issue_queue since termination of this command
- * may allow another queued command to execute first?
- */
- return SCSI_ABORT_NOT_RUNNING;
-}
-
-/*
- * Function : int NCR53c7xx_reset (Scsi_Cmnd *cmd)
- *
- * Purpose : perform a hard reset of the SCSI bus and NCR
- * chip.
- *
- * Inputs : cmd - command which caused the SCSI RESET
- *
- * Returns : 0 on success.
- */
-
-int
-NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- int found = 0;
- struct NCR53c7x0_cmd * c;
- Scsi_Cmnd *tmp;
- /*
- * When we call scsi_done(), it's going to wake up anything sleeping on the
- * resources which were in use by the aborted commands, and we'll start to
- * get new commands.
- *
- * We can't let this happen until after we've re-initialized the driver
- * structures, and can't reinitialize those structures until after we've
- * dealt with their contents.
- *
- * So, we need to find all of the commands which were running, stick
- * them on a linked list of completed commands (we'll use the host_scribble
- * pointer), do our reinitialization, and then call the done function for
- * each command.
- */
- Scsi_Cmnd *nuke_list = NULL;
- struct Scsi_Host *host = cmd->device->host;
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
-
- NCR53c7x0_local_setup(host);
- local_irq_save(flags);
- ncr_halt (host);
- print_lots (host);
- dump_events (host, 30);
- ncr_scsi_reset (host);
- for (tmp = nuke_list = return_outstanding_commands (host, 1 /* free */,
- 0 /* issue */ ); tmp; tmp = (Scsi_Cmnd *) tmp->SCp.buffer)
- if (tmp == cmd) {
- found = 1;
- break;
- }
-
- /*
- * If we didn't find the command which caused this reset in our running
- * list, then we've lost it. See that it terminates normally anyway.
- */
- if (!found) {
- c = (struct NCR53c7x0_cmd *) cmd->host_scribble;
- if (c) {
- cmd->host_scribble = NULL;
- c->next = hostdata->free;
- hostdata->free = c;
- } else
- printk ("scsi%d: lost command %ld\n", host->host_no, cmd->pid);
- cmd->SCp.buffer = (struct scatterlist *) nuke_list;
- nuke_list = cmd;
- }
-
- NCR53c7x0_driver_init (host);
- hostdata->soft_reset (host);
- if (hostdata->resets == 0)
- disable(host);
- else if (hostdata->resets != -1)
- --hostdata->resets;
- local_irq_restore(flags);
- for (; nuke_list; nuke_list = tmp) {
- tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
- nuke_list->result = DID_RESET << 16;
- nuke_list->scsi_done (nuke_list);
- }
- local_irq_restore(flags);
- return SCSI_RESET_SUCCESS;
-}
-
-/*
- * The NCR SDMS bios follows Annex A of the SCSI-CAM draft, and
- * therefore shares the scsicam_bios_param function.
- */
-
-/*
- * Function : int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn)
- *
- * Purpose : convert instructions stored at NCR pointer into data
- * pointer offset.
- *
- * Inputs : cmd - SCSI command; insn - pointer to instruction. Either current
- * DSP, or saved data pointer.
- *
- * Returns : offset on success, -1 on failure.
- */
-
-
-static int
-insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) cmd->device->host->hostdata[0];
- struct NCR53c7x0_cmd *ncmd =
- (struct NCR53c7x0_cmd *) cmd->host_scribble;
- int offset = 0, buffers;
- struct scatterlist *segment;
- char *ptr;
- int found = 0;
-
-/*
- * With the current code implementation, if the insn is inside dynamically
- * generated code, the data pointer will be the instruction preceding
- * the next transfer segment.
- */
-
- if (!check_address ((unsigned long) ncmd, sizeof (struct NCR53c7x0_cmd)) &&
- ((insn >= ncmd->data_transfer_start &&
- insn < ncmd->data_transfer_end) ||
- (insn >= ncmd->residual &&
- insn < (ncmd->residual +
- sizeof(ncmd->residual))))) {
- ptr = bus_to_virt(insn[3]);
-
- if ((buffers = cmd->use_sg)) {
- for (offset = 0,
- segment = (struct scatterlist *) cmd->request_buffer;
- buffers && !((found = ((ptr >= (char *)page_address(segment->page)+segment->offset) &&
- (ptr < ((char *)page_address(segment->page)+segment->offset+segment->length)))));
- --buffers, offset += segment->length, ++segment)
-#if 0
- printk("scsi%d: comparing 0x%p to 0x%p\n",
- cmd->device->host->host_no, saved, page_address(segment->page+segment->offset));
-#else
- ;
-#endif
- offset += ptr - ((char *)page_address(segment->page)+segment->offset);
- } else {
- found = 1;
- offset = ptr - (char *) (cmd->request_buffer);
- }
- } else if ((insn >= hostdata->script +
- hostdata->E_data_transfer / sizeof(u32)) &&
- (insn <= hostdata->script +
- hostdata->E_end_data_transfer / sizeof(u32))) {
- found = 1;
- offset = 0;
- }
- return found ? offset : -1;
-}
-
-
-
-/*
- * Function : void print_progress (Scsi_Cmnd *cmd)
- *
- * Purpose : print the current location of the saved data pointer
- *
- * Inputs : cmd - command we are interested in
- *
- */
-
-static void
-print_progress (Scsi_Cmnd *cmd) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_cmd *ncmd =
- (struct NCR53c7x0_cmd *) cmd->host_scribble;
- int offset, i;
- char *where;
- u32 *ptr;
- NCR53c7x0_local_setup (cmd->device->host);
-
- if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0)
- {
- printk("\nNCR53c7x0_cmd fields:\n");
- printk(" bounce.len=0x%x, addr=0x%0x, buf[]=0x%02x %02x %02x %02x\n",
- ncmd->bounce.len, ncmd->bounce.addr, ncmd->bounce.buf[0],
- ncmd->bounce.buf[1], ncmd->bounce.buf[2], ncmd->bounce.buf[3]);
- printk(" result=%04x, cdb[0]=0x%02x\n", ncmd->result, ncmd->cmnd[0]);
- }
-
- for (i = 0; i < 2; ++i) {
- if (check_address ((unsigned long) ncmd,
- sizeof (struct NCR53c7x0_cmd)) == -1)
- continue;
- if (!i) {
- where = "saved";
- ptr = bus_to_virt(ncmd->saved_data_pointer);
- } else {
- where = "active";
- ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
- NCR53c7x0_insn_size (NCR53c7x0_read8 (DCMD_REG)) *
- sizeof(u32));
- }
- offset = insn_to_offset (cmd, ptr);
-
- if (offset != -1)
- printk ("scsi%d : %s data pointer at offset %d\n",
- cmd->device->host->host_no, where, offset);
- else {
- int size;
- printk ("scsi%d : can't determine %s data pointer offset\n",
- cmd->device->host->host_no, where);
- if (ncmd) {
- size = print_insn (cmd->device->host,
- bus_to_virt(ncmd->saved_data_pointer), "", 1);
- print_insn (cmd->device->host,
- bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
- "", 1);
- }
- }
- }
-}
-
-
-static void
-print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int i, len;
- char *ptr;
- Scsi_Cmnd *cmd;
-
- if (check_address ((unsigned long) dsa, hostdata->dsa_end -
- hostdata->dsa_start) == -1) {
- printk("scsi%d : bad dsa virt 0x%p\n", host->host_no, dsa);
- return;
- }
- printk("%sscsi%d : dsa at phys 0x%lx (virt 0x%p)\n"
- " + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
- prefix ? prefix : "",
- host->host_no, virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
- dsa[hostdata->dsa_msgout / sizeof(u32)],
- dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
- bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
-
- /*
- * Only print messages if they're sane in length so we don't
- * blow the kernel printk buffer on something which won't buy us
- * anything.
- */
-
- if (dsa[hostdata->dsa_msgout / sizeof(u32)] <
- sizeof (hostdata->free->select))
- for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
- ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
- i > 0 && !check_address ((unsigned long) ptr, 1);
- ptr += len, i -= len) {
- printk(" ");
- len = spi_print_msg(ptr);
- printk("\n");
- if (!len)
- break;
- }
-
- printk(" + %d : select_indirect = 0x%x\n",
- hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
- cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
- printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
- (u32) virt_to_bus(cmd));
- /* XXX Maybe we should access cmd->host_scribble->result here. RGH */
- if (cmd) {
- printk(" result = 0x%x, target = %d, lun = %d, cmd = ",
- cmd->result, cmd->device->id, cmd->device->lun);
- __scsi_print_command(cmd->cmnd);
- } else
- printk("\n");
- printk(" + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
- dsa[hostdata->dsa_next / sizeof(u32)]);
- if (cmd) {
- printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
- " script : ",
- host->host_no, cmd->device->id,
- hostdata->sync[cmd->device->id].sxfer_sanity,
- hostdata->sync[cmd->device->id].scntl3_sanity);
- for (i = 0; i < (sizeof(hostdata->sync[cmd->device->id].script) / 4); ++i)
- printk ("0x%x ", hostdata->sync[cmd->device->id].script[i]);
- printk ("\n");
- print_progress (cmd);
- }
-}
-/*
- * Function : void print_queues (Scsi_Host *host)
- *
- * Purpose : print the contents of the NCR issue and reconnect queues
- *
- * Inputs : host - SCSI host we are interested in
- *
- */
-
-static void
-print_queues (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- u32 *dsa, *next_dsa;
- volatile u32 *ncrcurrent;
- int left;
- Scsi_Cmnd *cmd, *next_cmd;
- unsigned long flags;
-
- printk ("scsi%d : issue queue\n", host->host_no);
-
- for (left = host->can_queue, cmd = (Scsi_Cmnd *) hostdata->issue_queue;
- left >= 0 && cmd;
- cmd = next_cmd) {
- next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
- local_irq_save(flags);
- if (cmd->host_scribble) {
- if (check_address ((unsigned long) (cmd->host_scribble),
- sizeof (cmd->host_scribble)) == -1)
- printk ("scsi%d: scsi pid %ld bad pointer to NCR53c7x0_cmd\n",
- host->host_no, cmd->pid);
- /* print_dsa does sanity check on address, no need to check */
- else
- print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
- -> dsa, "");
- } else
- printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
- host->host_no, cmd->pid, cmd->device->id, cmd->device->lun);
- local_irq_restore(flags);
- }
-
- if (left <= 0) {
- printk ("scsi%d : loop detected in issue queue\n",
- host->host_no);
- }
-
- /*
- * Traverse the NCR reconnect and start DSA structures, printing out
- * each element until we hit the end or detect a loop. Currently,
- * the reconnect structure is a linked list; and the start structure
- * is an array. Eventually, the reconnect structure will become a
- * list as well, since this simplifies the code.
- */
-
- printk ("scsi%d : schedule dsa array :\n", host->host_no);
- for (left = host->can_queue, ncrcurrent = hostdata->schedule;
- left > 0; ncrcurrent += 2, --left)
- if (ncrcurrent[0] != hostdata->NOP_insn)
-/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
- print_dsa (host, bus_to_virt (ncrcurrent[1] -
- (hostdata->E_dsa_code_begin -
- hostdata->E_dsa_code_template)), "");
- printk ("scsi%d : end schedule dsa array\n", host->host_no);
-
- printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
-
- for (left = host->can_queue,
- dsa = bus_to_virt (hostdata->reconnect_dsa_head);
- left >= 0 && dsa;
- dsa = next_dsa) {
- local_irq_save(flags);
- if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
- printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
- dsa);
- next_dsa = NULL;
- }
- else
- {
- next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
- print_dsa (host, dsa, "");
- }
- local_irq_restore(flags);
- }
- printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
- if (left < 0)
- printk("scsi%d: possible loop in ncr reconnect list\n",
- host->host_no);
-}
-
-static void
-print_lots (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
- unsigned char dcmd, sbcl;
- int i, size;
- NCR53c7x0_local_setup(host);
-
- if ((dsp_next = bus_to_virt(NCR53c7x0_read32 (DSP_REG)))) {
- dbc_dcmd = NCR53c7x0_read32(DBC_REG);
- dcmd = (dbc_dcmd & 0xff000000) >> 24;
- dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
- dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
- sbcl = NCR53c7x0_read8 (SBCL_REG);
-
- /*
- * For the 53c710, the following will report value 0 for SCNTL3
- * and STEST0 - we don't have these registers.
- */
- printk ("scsi%d : DCMD|DBC=0x%x, DNAD=0x%x (virt 0x%p)\n"
- " DSA=0x%lx (virt 0x%p)\n"
- " DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
- " SXFER=0x%x, SCNTL3=0x%x\n"
- " %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
- " SCRATCH=0x%x, saved2_dsa=0x%0lx\n",
- host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
- bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
- virt_to_bus(dsa), dsa,
- NCR53c7x0_read32(DSPS_REG), NCR53c7x0_read32(TEMP_REG),
- bus_to_virt (NCR53c7x0_read32(TEMP_REG)),
- (int) NCR53c7x0_read8(hostdata->dmode),
- (int) NCR53c7x0_read8(SXFER_REG),
- ((hostdata->chip / 100) == 8) ?
- (int) NCR53c7x0_read8(SCNTL3_REG_800) : 0,
- (sbcl & SBCL_BSY) ? "BSY " : "",
- (sbcl & SBCL_SEL) ? "SEL " : "",
- (sbcl & SBCL_REQ) ? "REQ " : "",
- sstat2_to_phase(NCR53c7x0_read8 (((hostdata->chip / 100) == 8) ?
- SSTAT1_REG : SSTAT2_REG)),
- (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ?
- SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
- ((hostdata->chip / 100) == 8) ? NCR53c7x0_read8 (STEST0_REG_800) :
- NCR53c7x0_read32(SCRATCHA_REG_800),
- hostdata->saved2_dsa);
- printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no,
- virt_to_bus(dsp), dsp);
- for (i = 6; i > 0; --i, dsp += size)
- size = print_insn (host, dsp, "", 1);
- if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
- if ((hostdata->chip / 100) == 8)
- printk ("scsi%d : connected (SDID=0x%x, SSID=0x%x)\n",
- host->host_no, NCR53c7x0_read8 (SDID_REG_800),
- NCR53c7x0_read8 (SSID_REG_800));
- else
- printk ("scsi%d : connected (SDID=0x%x)\n",
- host->host_no, NCR53c7x0_read8 (SDID_REG_700));
- print_dsa (host, dsa, "");
- }
-
-#if 1
- print_queues (host);
-#endif
- }
-}
-
-/*
- * Function : static int shutdown (struct Scsi_Host *host)
- *
- * Purpose : does a clean (we hope) shutdown of the NCR SCSI
- * chip. Use prior to dumping core, unloading the NCR driver,
- *
- * Returns : 0 on success
- */
-static int
-shutdown (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- NCR53c7x0_local_setup(host);
- local_irq_save(flags);
-/* Get in a state where we can reset the SCSI bus */
- ncr_halt (host);
- ncr_scsi_reset (host);
- hostdata->soft_reset(host);
-
- disable (host);
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * Function : void ncr_scsi_reset (struct Scsi_Host *host)
- *
- * Purpose : reset the SCSI bus.
- */
-
-static void
-ncr_scsi_reset (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- NCR53c7x0_local_setup(host);
- local_irq_save(flags);
- NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
- udelay(25); /* Minimum amount of time to assert RST */
- NCR53c7x0_write8(SCNTL1_REG, 0);
- local_irq_restore(flags);
-}
-
-/*
- * Function : void hard_reset (struct Scsi_Host *host)
- *
- */
-
-static void
-hard_reset (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- local_irq_save(flags);
- ncr_scsi_reset(host);
- NCR53c7x0_driver_init (host);
- if (hostdata->soft_reset)
- hostdata->soft_reset (host);
- local_irq_restore(flags);
-}
-
-
-/*
- * Function : Scsi_Cmnd *return_outstanding_commands (struct Scsi_Host *host,
- * int free, int issue)
- *
- * Purpose : return a linked list (using the SCp.buffer field as next,
- * so we don't perturb hostdata. We don't use a field of the
- * NCR53c7x0_cmd structure since we may not have allocated one
- * for the command causing the reset.) of Scsi_Cmnd structures that
- * had propagated below the Linux issue queue level. If free is set,
- * free the NCR53c7x0_cmd structures which are associated with
- * the Scsi_Cmnd structures, and clean up any internal
- * NCR lists that the commands were on. If issue is set,
- * also return commands in the issue queue.
- *
- * Returns : linked list of commands
- *
- * NOTE : the caller should insure that the NCR chip is halted
- * if the free flag is set.
- */
-
-static Scsi_Cmnd *
-return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- struct NCR53c7x0_cmd *c;
- int i;
- u32 *ncrcurrent;
- Scsi_Cmnd *list = NULL, *tmp;
- for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c;
- c = (struct NCR53c7x0_cmd *) c->next) {
- if (c->cmd->SCp.buffer) {
- printk ("scsi%d : loop detected in running list!\n", host->host_no);
- break;
- } else {
- printk ("Duh? Bad things happening in the NCR driver\n");
- break;
- }
-
- c->cmd->SCp.buffer = (struct scatterlist *) list;
- list = c->cmd;
- if (free) {
- c->next = hostdata->free;
- hostdata->free = c;
- }
- }
-
- if (free) {
- for (i = 0, ncrcurrent = (u32 *) hostdata->schedule;
- i < host->can_queue; ++i, ncrcurrent += 2) {
- ncrcurrent[0] = hostdata->NOP_insn;
- ncrcurrent[1] = 0xdeadbeef;
- }
- hostdata->ncrcurrent = NULL;
- }
-
- if (issue) {
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; tmp = tmp->next) {
- if (tmp->SCp.buffer) {
- printk ("scsi%d : loop detected in issue queue!\n",
- host->host_no);
- break;
- }
- tmp->SCp.buffer = (struct scatterlist *) list;
- list = tmp;
- }
- if (free)
- hostdata->issue_queue = NULL;
-
- }
- return list;
-}
-
-/*
- * Function : static int disable (struct Scsi_Host *host)
- *
- * Purpose : disables the given NCR host, causing all commands
- * to return a driver error. Call this so we can unload the
- * module during development and try again. Eventually,
- * we should be able to find clean workarounds for these
- * problems.
- *
- * Inputs : host - hostadapter to twiddle
- *
- * Returns : 0 on success.
- */
-
-static int
-disable (struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- unsigned long flags;
- Scsi_Cmnd *nuke_list, *tmp;
- local_irq_save(flags);
- if (hostdata->state != STATE_HALTED)
- ncr_halt (host);
- nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
- hard_reset (host);
- hostdata->state = STATE_DISABLED;
- local_irq_restore(flags);
- printk ("scsi%d : nuking commands\n", host->host_no);
- for (; nuke_list; nuke_list = tmp) {
- tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
- nuke_list->result = DID_ERROR << 16;
- nuke_list->scsi_done(nuke_list);
- }
- printk ("scsi%d : done. \n", host->host_no);
- printk (KERN_ALERT "scsi%d : disabled. Unload and reload\n",
- host->host_no);
- return 0;
-}
-
-/*
- * Function : static int ncr_halt (struct Scsi_Host *host)
- *
- * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
- *
- * Inputs : host - SCSI chip to halt
- *
- * Returns : 0 on success
- */
-
-static int
-ncr_halt (struct Scsi_Host *host) {
- NCR53c7x0_local_declare();
- unsigned long flags;
- unsigned char istat, tmp;
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- int stage;
- NCR53c7x0_local_setup(host);
-
- local_irq_save(flags);
- /* Stage 0 : eat all interrupts
- Stage 1 : set ABORT
- Stage 2 : eat all but abort interrupts
- Stage 3 : eat all interrupts
- */
- for (stage = 0;;) {
- if (stage == 1) {
- NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
- ++stage;
- }
- istat = NCR53c7x0_read8 (hostdata->istat);
- if (istat & ISTAT_SIP) {
- tmp = NCR53c7x0_read8(SSTAT0_REG);
- } else if (istat & ISTAT_DIP) {
- tmp = NCR53c7x0_read8(DSTAT_REG);
- if (stage == 2) {
- if (tmp & DSTAT_ABRT) {
- NCR53c7x0_write8(hostdata->istat, 0);
- ++stage;
- } else {
- printk(KERN_ALERT "scsi%d : could not halt NCR chip\n",
- host->host_no);
- disable (host);
- }
- }
- }
- if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
- if (stage == 0)
- ++stage;
- else if (stage == 3)
- break;
- }
- }
- hostdata->state = STATE_HALTED;
- local_irq_restore(flags);
-#if 0
- print_lots (host);
-#endif
- return 0;
-}
-
-/*
- * Function: event_name (int event)
- *
- * Purpose: map event enum into user-readable strings.
- */
-
-static const char *
-event_name (int event) {
- switch (event) {
- case EVENT_NONE: return "none";
- case EVENT_ISSUE_QUEUE: return "to issue queue";
- case EVENT_START_QUEUE: return "to start queue";
- case EVENT_SELECT: return "selected";
- case EVENT_DISCONNECT: return "disconnected";
- case EVENT_RESELECT: return "reselected";
- case EVENT_COMPLETE: return "completed";
- case EVENT_IDLE: return "idle";
- case EVENT_SELECT_FAILED: return "select failed";
- case EVENT_BEFORE_SELECT: return "before select";
- case EVENT_RESELECT_FAILED: return "reselect failed";
- default: return "unknown";
- }
-}
-
-/*
- * Function : void dump_events (struct Scsi_Host *host, count)
- *
- * Purpose : print last count events which have occurred.
- */
-static void
-dump_events (struct Scsi_Host *host, int count) {
- struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata[0];
- struct NCR53c7x0_event event;
- int i;
- unsigned long flags;
- if (hostdata->events) {
- if (count > hostdata->event_size)
- count = hostdata->event_size;
- for (i = hostdata->event_index; count > 0;
- i = (i ? i - 1 : hostdata->event_size -1), --count) {
-/*
- * By copying the event we're currently examining with interrupts
- * disabled, we can do multiple printk(), etc. operations and
- * still be guaranteed that they're happening on the same
- * event structure.
- */
- local_irq_save(flags);
-#if 0
- event = hostdata->events[i];
-#else
- memcpy ((void *) &event, (void *) &(hostdata->events[i]),
- sizeof(event));
-#endif
-
- local_irq_restore(flags);
- printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
- host->host_no, event_name (event.event), count,
- (long) event.time.tv_sec, (long) event.time.tv_usec,
- event.target, event.lun);
- if (event.dsa)
- printk (" event for dsa 0x%lx (virt 0x%p)\n",
- virt_to_bus(event.dsa), event.dsa);
- if (event.pid != -1) {
- printk (" event for pid %ld ", event.pid);
- __scsi_print_command (event.cmnd);
- }
- }
- }
-}
-
-/*
- * Function: check_address
- *
- * Purpose: Check to see if a possibly corrupt pointer will fault the
- * kernel.
- *
- * Inputs: addr - address; size - size of area
- *
- * Returns: 0 if area is OK, -1 on error.
- *
- * NOTES: should be implemented in terms of vverify on kernels
- * that have it.
- */
-
-static int
-check_address (unsigned long addr, int size) {
- return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ? -1 : 0);
-}
-
-#ifdef MODULE
-int
-NCR53c7x0_release(struct Scsi_Host *host) {
- struct NCR53c7x0_hostdata *hostdata =
- (struct NCR53c7x0_hostdata *) host->hostdata[0];
- struct NCR53c7x0_cmd *cmd, *tmp;
- shutdown (host);
- if (host->irq != SCSI_IRQ_NONE)
- {
- int irq_count;
- struct Scsi_Host *tmp;
- for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
- if (tmp->hostt == the_template && tmp->irq == host->irq)
- ++irq_count;
- if (irq_count == 1)
- free_irq(host->irq, NULL);
- }
- if (host->dma_channel != DMA_NONE)
- free_dma(host->dma_channel);
- if (host->io_port)
- release_region(host->io_port, host->n_io_port);
-
- for (cmd = (struct NCR53c7x0_cmd *) hostdata->free; cmd; cmd = tmp,
- --hostdata->num_cmds) {
- tmp = (struct NCR53c7x0_cmd *) cmd->next;
- /*
- * If we're going to loop, try to stop it to get a more accurate
- * count of the leaked commands.
- */
- cmd->next = NULL;
- if (cmd->free)
- cmd->free ((void *) cmd->real, cmd->size);
- }
- if (hostdata->num_cmds)
- printk ("scsi%d : leaked %d NCR53c7x0_cmd structures\n",
- host->host_no, hostdata->num_cmds);
-
- vfree(hostdata->events);
-
- /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
- * XXX may be invalid (CONFIG_060_WRITETHROUGH)
- */
- kernel_set_cachemode((void *)hostdata, 8192, IOMAP_FULL_CACHING);
- free_pages ((u32)hostdata, 1);
- return 1;
-}
-#endif /* def MODULE */
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
deleted file mode 100644
index 218f3b901537..000000000000
--- a/drivers/scsi/53c7xx.h
+++ /dev/null
@@ -1,1608 +0,0 @@
-/*
- * 53c710 driver. Modified from Drew Eckhardts driver
- * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * I have left the code for the 53c8xx family in here, because it didn't
- * seem worth removing it. The possibility of IO_MAPPED chips rather
- * than MEMORY_MAPPED remains, in case someone wants to add support for
- * 53c710 chips on Intel PCs (some older machines have them on the
- * motherboard).
- *
- * NOTE THERE MAY BE PROBLEMS WITH CASTS IN read8 AND Co.
- */
-
-/*
- * NCR 53c{7,8}0x0 driver, header file
- *
- * Sponsored by
- * iX Multiuser Multitasking Magazine
- * Hannover, Germany
- * hm@ix.de
- *
- * Copyright 1993, 1994, 1995 Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@PoohSticks.ORG
- * +1 (303) 786-7975
- *
- * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
- *
- * PRE-ALPHA
- *
- * For more information, please consult
- *
- * NCR 53C700/53C700-66
- * SCSI I/O Processor
- * Data Manual
- *
- * NCR 53C810
- * PCI-SCSI I/O Processor
- * Data Manual
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * +1 (719) 578-3400
- *
- * Toll free literature number
- * +1 (800) 334-5454
- *
- */
-
-#ifndef NCR53c710_H
-#define NCR53c710_H
-
-#ifndef HOSTS_C
-
-/* SCSI control 0 rw, default = 0xc0 */
-#define SCNTL0_REG 0x00
-#define SCNTL0_ARB1 0x80 /* 0 0 = simple arbitration */
-#define SCNTL0_ARB2 0x40 /* 1 1 = full arbitration */
-#define SCNTL0_STRT 0x20 /* Start Sequence */
-#define SCNTL0_WATN 0x10 /* Select with ATN */
-#define SCNTL0_EPC 0x08 /* Enable parity checking */
-/* Bit 2 is reserved on 800 series chips */
-#define SCNTL0_EPG_700 0x04 /* Enable parity generation */
-#define SCNTL0_AAP 0x02 /* ATN/ on parity error */
-#define SCNTL0_TRG 0x01 /* Target mode */
-
-/* SCSI control 1 rw, default = 0x00 */
-
-#define SCNTL1_REG 0x01
-#define SCNTL1_EXC 0x80 /* Extra Clock Cycle of Data setup */
-#define SCNTL1_ADB 0x40 /* contents of SODL on bus */
-#define SCNTL1_ESR_700 0x20 /* Enable SIOP response to selection
- and reselection */
-#define SCNTL1_DHP_800 0x20 /* Disable halt on parity error or ATN
- target mode only */
-#define SCNTL1_CON 0x10 /* Connected */
-#define SCNTL1_RST 0x08 /* SCSI RST/ */
-#define SCNTL1_AESP 0x04 /* Force bad parity */
-#define SCNTL1_SND_700 0x02 /* Start SCSI send */
-#define SCNTL1_IARB_800 0x02 /* Immediate Arbitration, start
- arbitration immediately after
- busfree is detected */
-#define SCNTL1_RCV_700 0x01 /* Start SCSI receive */
-#define SCNTL1_SST_800 0x01 /* Start SCSI transfer */
-
-/* SCSI control 2 rw, */
-
-#define SCNTL2_REG_800 0x02
-#define SCNTL2_800_SDU 0x80 /* SCSI disconnect unexpected */
-
-/* SCSI control 3 rw */
-
-#define SCNTL3_REG_800 0x03
-#define SCNTL3_800_SCF_SHIFT 4
-#define SCNTL3_800_SCF_MASK 0x70
-#define SCNTL3_800_SCF2 0x40 /* Synchronous divisor */
-#define SCNTL3_800_SCF1 0x20 /* 0x00 = SCLK/3 */
-#define SCNTL3_800_SCF0 0x10 /* 0x10 = SCLK/1 */
- /* 0x20 = SCLK/1.5
- 0x30 = SCLK/2
- 0x40 = SCLK/3 */
-
-#define SCNTL3_800_CCF_SHIFT 0
-#define SCNTL3_800_CCF_MASK 0x07
-#define SCNTL3_800_CCF2 0x04 /* 0x00 50.01 to 66 */
-#define SCNTL3_800_CCF1 0x02 /* 0x01 16.67 to 25 */
-#define SCNTL3_800_CCF0 0x01 /* 0x02 25.01 - 37.5
- 0x03 37.51 - 50
- 0x04 50.01 - 66 */
-
-/*
- * SCSI destination ID rw - the appropriate bit is set for the selected
- * target ID. This is written by the SCSI SCRIPTS processor.
- * default = 0x00
- */
-#define SDID_REG_700 0x02
-#define SDID_REG_800 0x06
-
-#define GP_REG_800 0x07 /* General purpose IO */
-#define GP_800_IO1 0x02
-#define GP_800_IO2 0x01
-
-/* SCSI interrupt enable rw, default = 0x00 */
-#define SIEN_REG_700 0x03
-#define SIEN0_REG_800 0x40
-#define SIEN_MA 0x80 /* Phase mismatch (ini) or ATN (tgt) */
-#define SIEN_FC 0x40 /* Function complete */
-#define SIEN_700_STO 0x20 /* Selection or reselection timeout */
-#define SIEN_800_SEL 0x20 /* Selected */
-#define SIEN_700_SEL 0x10 /* Selected or reselected */
-#define SIEN_800_RESEL 0x10 /* Reselected */
-#define SIEN_SGE 0x08 /* SCSI gross error */
-#define SIEN_UDC 0x04 /* Unexpected disconnect */
-#define SIEN_RST 0x02 /* SCSI RST/ received */
-#define SIEN_PAR 0x01 /* Parity error */
-
-/*
- * SCSI chip ID rw
- * NCR53c700 :
- * When arbitrating, the highest bit is used, when reselection or selection
- * occurs, the chip responds to all IDs for which a bit is set.
- * default = 0x00
- * NCR53c810 :
- * Uses bit mapping
- */
-#define SCID_REG 0x04
-/* Bit 7 is reserved on 800 series chips */
-#define SCID_800_RRE 0x40 /* Enable response to reselection */
-#define SCID_800_SRE 0x20 /* Enable response to selection */
-/* Bits four and three are reserved on 800 series chips */
-#define SCID_800_ENC_MASK 0x07 /* Encoded SCSI ID */
-
-/* SCSI transfer rw, default = 0x00 */
-#define SXFER_REG 0x05
-#define SXFER_DHP 0x80 /* Disable halt on parity */
-
-#define SXFER_TP2 0x40 /* Transfer period msb */
-#define SXFER_TP1 0x20
-#define SXFER_TP0 0x10 /* lsb */
-#define SXFER_TP_MASK 0x70
-/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
-#define SXFER_TP_SHIFT 5
-#define SXFER_TP_4 0x00 /* Divisors */
-#define SXFER_TP_5 0x10<<1
-#define SXFER_TP_6 0x20<<1
-#define SXFER_TP_7 0x30<<1
-#define SXFER_TP_8 0x40<<1
-#define SXFER_TP_9 0x50<<1
-#define SXFER_TP_10 0x60<<1
-#define SXFER_TP_11 0x70<<1
-
-#define SXFER_MO3 0x08 /* Max offset msb */
-#define SXFER_MO2 0x04
-#define SXFER_MO1 0x02
-#define SXFER_MO0 0x01 /* lsb */
-#define SXFER_MO_MASK 0x0f
-#define SXFER_MO_SHIFT 0
-
-/*
- * SCSI output data latch rw
- * The contents of this register are driven onto the SCSI bus when
- * the Assert Data Bus bit of the SCNTL1 register is set and
- * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
- */
-#define SODL_REG_700 0x06
-#define SODL_REG_800 0x54
-
-
-/*
- * SCSI output control latch rw, default = 0
- * Note that when the chip is being manually programmed as an initiator,
- * the MSG, CD, and IO bits must be set correctly for the phase the target
- * is driving the bus in. Otherwise no data transfer will occur due to
- * phase mismatch.
- */
-
-#define SOCL_REG 0x07
-#define SOCL_REQ 0x80 /* REQ */
-#define SOCL_ACK 0x40 /* ACK */
-#define SOCL_BSY 0x20 /* BSY */
-#define SOCL_SEL 0x10 /* SEL */
-#define SOCL_ATN 0x08 /* ATN */
-#define SOCL_MSG 0x04 /* MSG */
-#define SOCL_CD 0x02 /* C/D */
-#define SOCL_IO 0x01 /* I/O */
-
-/*
- * SCSI first byte received latch ro
- * This register contains the first byte received during a block MOVE
- * SCSI SCRIPTS instruction, including
- *
- * Initiator mode Target mode
- * Message in Command
- * Status Message out
- * Data in Data out
- *
- * It also contains the selecting or reselecting device's ID and our
- * ID.
- *
- * Note that this is the register the various IF conditionals can
- * operate on.
- */
-#define SFBR_REG 0x08
-
-/*
- * SCSI input data latch ro
- * In initiator mode, data is latched into this register on the rising
- * edge of REQ/. In target mode, data is latched on the rising edge of
- * ACK/
- */
-#define SIDL_REG_700 0x09
-#define SIDL_REG_800 0x50
-
-/*
- * SCSI bus data lines ro
- * This register reflects the instantaneous status of the SCSI data
- * lines. Note that SCNTL0 must be set to disable parity checking,
- * otherwise reading this register will latch new parity.
- */
-#define SBDL_REG_700 0x0a
-#define SBDL_REG_800 0x58
-
-#define SSID_REG_800 0x0a
-#define SSID_800_VAL 0x80 /* Exactly two bits asserted at sel */
-#define SSID_800_ENCID_MASK 0x07 /* Device which performed operation */
-
-
-/*
- * SCSI bus control lines rw,
- * instantaneous readout of control lines
- */
-#define SBCL_REG 0x0b
-#define SBCL_REQ 0x80 /* REQ ro */
-#define SBCL_ACK 0x40 /* ACK ro */
-#define SBCL_BSY 0x20 /* BSY ro */
-#define SBCL_SEL 0x10 /* SEL ro */
-#define SBCL_ATN 0x08 /* ATN ro */
-#define SBCL_MSG 0x04 /* MSG ro */
-#define SBCL_CD 0x02 /* C/D ro */
-#define SBCL_IO 0x01 /* I/O ro */
-#define SBCL_PHASE_CMDOUT SBCL_CD
-#define SBCL_PHASE_DATAIN SBCL_IO
-#define SBCL_PHASE_DATAOUT 0
-#define SBCL_PHASE_MSGIN (SBCL_CD|SBCL_IO|SBCL_MSG)
-#define SBCL_PHASE_MSGOUT (SBCL_CD|SBCL_MSG)
-#define SBCL_PHASE_STATIN (SBCL_CD|SBCL_IO)
-#define SBCL_PHASE_MASK (SBCL_CD|SBCL_IO|SBCL_MSG)
-/*
- * Synchronous SCSI Clock Control bits
- * 0 - set by DCNTL
- * 1 - SCLK / 1.0
- * 2 - SCLK / 1.5
- * 3 - SCLK / 2.0
- */
-#define SBCL_SSCF1 0x02 /* wo, -66 only */
-#define SBCL_SSCF0 0x01 /* wo, -66 only */
-#define SBCL_SSCF_MASK 0x03
-
-/*
- * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
- * insure that 10 clocks elapse between the two
- */
-/* DMA status ro */
-#define DSTAT_REG 0x0c
-#define DSTAT_DFE 0x80 /* DMA FIFO empty */
-#define DSTAT_800_MDPE 0x40 /* Master Data Parity Error */
-#define DSTAT_800_BF 0x20 /* Bus Fault */
-#define DSTAT_ABRT 0x10 /* Aborted - set on error */
-#define DSTAT_SSI 0x08 /* SCRIPTS single step interrupt */
-#define DSTAT_SIR 0x04 /* SCRIPTS interrupt received -
- set when INT instruction is
- executed */
-#define DSTAT_WTD 0x02 /* Watchdog timeout detected */
-#define DSTAT_OPC 0x01 /* Illegal instruction */
-#define DSTAT_800_IID 0x01 /* Same thing, different name */
-
-
-/* NCR53c800 moves this stuff into SIST0 */
-#define SSTAT0_REG 0x0d /* SCSI status 0 ro */
-#define SIST0_REG_800 0x42
-#define SSTAT0_MA 0x80 /* ini : phase mismatch,
- * tgt : ATN/ asserted
- */
-#define SSTAT0_CMP 0x40 /* function complete */
-#define SSTAT0_700_STO 0x20 /* Selection or reselection timeout */
-#define SIST0_800_SEL 0x20 /* Selected */
-#define SSTAT0_700_SEL 0x10 /* Selected or reselected */
-#define SIST0_800_RSL 0x10 /* Reselected */
-#define SSTAT0_SGE 0x08 /* SCSI gross error */
-#define SSTAT0_UDC 0x04 /* Unexpected disconnect */
-#define SSTAT0_RST 0x02 /* SCSI RST/ received */
-#define SSTAT0_PAR 0x01 /* Parity error */
-
-/* And uses SSTAT0 for what was SSTAT1 */
-
-#define SSTAT1_REG 0x0e /* SCSI status 1 ro */
-#define SSTAT1_ILF 0x80 /* SIDL full */
-#define SSTAT1_ORF 0x40 /* SODR full */
-#define SSTAT1_OLF 0x20 /* SODL full */
-#define SSTAT1_AIP 0x10 /* Arbitration in progress */
-#define SSTAT1_LOA 0x08 /* Lost arbitration */
-#define SSTAT1_WOA 0x04 /* Won arbitration */
-#define SSTAT1_RST 0x02 /* Instant readout of RST/ */
-#define SSTAT1_SDP 0x01 /* Instant readout of SDP/ */
-
-#define SSTAT2_REG 0x0f /* SCSI status 2 ro */
-#define SSTAT2_FF3 0x80 /* number of bytes in synchronous */
-#define SSTAT2_FF2 0x40 /* data FIFO */
-#define SSTAT2_FF1 0x20
-#define SSTAT2_FF0 0x10
-#define SSTAT2_FF_MASK 0xf0
-#define SSTAT2_FF_SHIFT 4
-
-/*
- * Latched signals, latched on the leading edge of REQ/ for initiators,
- * ACK/ for targets.
- */
-#define SSTAT2_SDP 0x08 /* SDP */
-#define SSTAT2_MSG 0x04 /* MSG */
-#define SSTAT2_CD 0x02 /* C/D */
-#define SSTAT2_IO 0x01 /* I/O */
-#define SSTAT2_PHASE_CMDOUT SSTAT2_CD
-#define SSTAT2_PHASE_DATAIN SSTAT2_IO
-#define SSTAT2_PHASE_DATAOUT 0
-#define SSTAT2_PHASE_MSGIN (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
-#define SSTAT2_PHASE_MSGOUT (SSTAT2_CD|SSTAT2_MSG)
-#define SSTAT2_PHASE_STATIN (SSTAT2_CD|SSTAT2_IO)
-#define SSTAT2_PHASE_MASK (SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
-
-
-/* NCR53c700-66 only */
-#define SCRATCHA_REG_00 0x10 /* through 0x13 Scratch A rw */
-/* NCR53c710 and higher */
-#define DSA_REG 0x10 /* DATA structure address */
-
-#define CTEST0_REG_700 0x14 /* Chip test 0 ro */
-#define CTEST0_REG_800 0x18 /* Chip test 0 rw, general purpose */
-/* 0x80 - 0x04 are reserved */
-#define CTEST0_700_RTRG 0x02 /* Real target mode */
-#define CTEST0_700_DDIR 0x01 /* Data direction, 1 =
- * SCSI bus to host, 0 =
- * host to SCSI.
- */
-
-#define CTEST1_REG_700 0x15 /* Chip test 1 ro */
-#define CTEST1_REG_800 0x19 /* Chip test 1 ro */
-#define CTEST1_FMT3 0x80 /* Identify which byte lanes are empty */
-#define CTEST1_FMT2 0x40 /* in the DMA FIFO */
-#define CTEST1_FMT1 0x20
-#define CTEST1_FMT0 0x10
-
-#define CTEST1_FFL3 0x08 /* Identify which bytes lanes are full */
-#define CTEST1_FFL2 0x04 /* in the DMA FIFO */
-#define CTEST1_FFL1 0x02
-#define CTEST1_FFL0 0x01
-
-#define CTEST2_REG_700 0x16 /* Chip test 2 ro */
-#define CTEST2_REG_800 0x1a /* Chip test 2 ro */
-
-#define CTEST2_800_DDIR 0x80 /* 1 = SCSI->host */
-#define CTEST2_800_SIGP 0x40 /* A copy of SIGP in ISTAT.
- Reading this register clears */
-#define CTEST2_800_CIO 0x20 /* Configured as IO */.
-#define CTEST2_800_CM 0x10 /* Configured as memory */
-
-/* 0x80 - 0x40 are reserved on 700 series chips */
-#define CTEST2_700_SOFF 0x20 /* SCSI Offset Compare,
- * As an initiator, this bit is
- * one when the synchronous offset
- * is zero, as a target this bit
- * is one when the synchronous
- * offset is at the maximum
- * defined in SXFER
- */
-#define CTEST2_700_SFP 0x10 /* SCSI FIFO parity bit,
- * reading CTEST3 unloads a byte
- * from the FIFO and sets this
- */
-#define CTEST2_700_DFP 0x08 /* DMA FIFO parity bit,
- * reading CTEST6 unloads a byte
- * from the FIFO and sets this
- */
-#define CTEST2_TEOP 0x04 /* SCSI true end of process,
- * indicates a totally finished
- * transfer
- */
-#define CTEST2_DREQ 0x02 /* Data request signal */
-/* 0x01 is reserved on 700 series chips */
-#define CTEST2_800_DACK 0x01
-
-/*
- * Chip test 3 ro
- * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
- * check SSTAT2 FIFO full bits to determine size. Note that a GROSS
- * error results if a read is attempted on this register. Also note
- * that 16 and 32 bit reads of this register will cause corruption.
- */
-#define CTEST3_REG_700 0x17
-/* Chip test 3 rw */
-#define CTEST3_REG_800 0x1b
-#define CTEST3_800_V3 0x80 /* Chip revision */
-#define CTEST3_800_V2 0x40
-#define CTEST3_800_V1 0x20
-#define CTEST3_800_V0 0x10
-#define CTEST3_800_FLF 0x08 /* Flush DMA FIFO */
-#define CTEST3_800_CLF 0x04 /* Clear DMA FIFO */
-#define CTEST3_800_FM 0x02 /* Fetch mode pin */
-/* bit 0 is reserved on 800 series chips */
-
-#define CTEST4_REG_700 0x18 /* Chip test 4 rw */
-#define CTEST4_REG_800 0x21 /* Chip test 4 rw */
-/* 0x80 is reserved on 700 series chips */
-#define CTEST4_800_BDIS 0x80 /* Burst mode disable */
-#define CTEST4_ZMOD 0x40 /* High impedance mode */
-#define CTEST4_SZM 0x20 /* SCSI bus high impedance */
-#define CTEST4_700_SLBE 0x10 /* SCSI loopback enabled */
-#define CTEST4_800_SRTM 0x10 /* Shadow Register Test Mode */
-#define CTEST4_700_SFWR 0x08 /* SCSI FIFO write enable,
- * redirects writes from SODL
- * to the SCSI FIFO.
- */
-#define CTEST4_800_MPEE 0x08 /* Enable parity checking
- during master cycles on PCI
- bus */
-
-/*
- * These bits send the contents of the CTEST6 register to the appropriate
- * byte lane of the 32 bit DMA FIFO. Normal operation is zero, otherwise
- * the high bit means the low two bits select the byte lane.
- */
-#define CTEST4_FBL2 0x04
-#define CTEST4_FBL1 0x02
-#define CTEST4_FBL0 0x01
-#define CTEST4_FBL_MASK 0x07
-#define CTEST4_FBL_0 0x04 /* Select DMA FIFO byte lane 0 */
-#define CTEST4_FBL_1 0x05 /* Select DMA FIFO byte lane 1 */
-#define CTEST4_FBL_2 0x06 /* Select DMA FIFO byte lane 2 */
-#define CTEST4_FBL_3 0x07 /* Select DMA FIFO byte lane 3 */
-#define CTEST4_800_SAVE (CTEST4_800_BDIS)
-
-
-#define CTEST5_REG_700 0x19 /* Chip test 5 rw */
-#define CTEST5_REG_800 0x22 /* Chip test 5 rw */
-/*
- * Clock Address Incrementor. When set, it increments the
- * DNAD register to the next bus size boundary. It automatically
- * resets itself when the operation is complete.
- */
-#define CTEST5_ADCK 0x80
-/*
- * Clock Byte Counter. When set, it decrements the DBC register to
- * the next bus size boundary.
- */
-#define CTEST5_BBCK 0x40
-/*
- * Reset SCSI Offset. Setting this bit to 1 clears the current offset
- * pointer in the SCSI synchronous offset counter (SSTAT). This bit
- * is set to 1 if a SCSI Gross Error Condition occurs. The offset should
- * be cleared when a synchronous transfer fails. When written, it is
- * automatically cleared after the SCSI synchronous offset counter is
- * reset.
- */
-/* Bit 5 is reserved on 800 series chips */
-#define CTEST5_700_ROFF 0x20
-/*
- * Master Control for Set or Reset pulses. When 1, causes the low
- * four bits of register to set when set, 0 causes the low bits to
- * clear when set.
- */
-#define CTEST5_MASR 0x10
-#define CTEST5_DDIR 0x08 /* DMA direction */
-/*
- * Bits 2-0 are reserved on 800 series chips
- */
-#define CTEST5_700_EOP 0x04 /* End of process */
-#define CTEST5_700_DREQ 0x02 /* Data request */
-#define CTEST5_700_DACK 0x01 /* Data acknowledge */
-
-/*
- * Chip test 6 rw - writing to this register writes to the byte
- * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
- * register.
- */
-#define CTEST6_REG_700 0x1a
-#define CTEST6_REG_800 0x23
-
-#define CTEST7_REG 0x1b /* Chip test 7 rw */
-/* 0x80 - 0x40 are reserved on NCR53c700 and NCR53c700-66 chips */
-#define CTEST7_10_CDIS 0x80 /* Cache burst disable */
-#define CTEST7_10_SC1 0x40 /* Snoop control bits */
-#define CTEST7_10_SC0 0x20
-#define CTEST7_10_SC_MASK 0x60
-/* 0x20 is reserved on the NCR53c700 */
-#define CTEST7_0060_FM 0x20 /* Fetch mode */
-#define CTEST7_STD 0x10 /* Selection timeout disable */
-#define CTEST7_DFP 0x08 /* DMA FIFO parity bit for CTEST6 */
-#define CTEST7_EVP 0x04 /* 1 = host bus even parity, 0 = odd */
-#define CTEST7_10_TT1 0x02 /* Transfer type */
-#define CTEST7_00_DC 0x02 /* Set to drive DC low during instruction
- fetch */
-#define CTEST7_DIFF 0x01 /* Differential mode */
-
-#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
-
-
-#define TEMP_REG 0x1c /* through 0x1f Temporary stack rw */
-
-#define DFIFO_REG 0x20 /* DMA FIFO rw */
-/*
- * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
- * moved into the CTEST8 register.
- */
-#define DFIFO_00_FLF 0x80 /* Flush DMA FIFO to memory */
-#define DFIFO_00_CLF 0x40 /* Clear DMA and SCSI FIFOs */
-#define DFIFO_BO6 0x40
-#define DFIFO_BO5 0x20
-#define DFIFO_BO4 0x10
-#define DFIFO_BO3 0x08
-#define DFIFO_BO2 0x04
-#define DFIFO_BO1 0x02
-#define DFIFO_BO0 0x01
-#define DFIFO_10_BO_MASK 0x7f /* 7 bit counter */
-#define DFIFO_00_BO_MASK 0x3f /* 6 bit counter */
-
-/*
- * Interrupt status rw
- * Note that this is the only register which can be read while SCSI
- * SCRIPTS are being executed.
- */
-#define ISTAT_REG_700 0x21
-#define ISTAT_REG_800 0x14
-#define ISTAT_ABRT 0x80 /* Software abort, write
- *1 to abort, wait for interrupt. */
-/* 0x40 and 0x20 are reserved on NCR53c700 and NCR53c700-66 chips */
-#define ISTAT_10_SRST 0x40 /* software reset */
-#define ISTAT_10_SIGP 0x20 /* signal script */
-/* 0x10 is reserved on NCR53c700 series chips */
-#define ISTAT_800_SEM 0x10 /* semaphore */
-#define ISTAT_CON 0x08 /* 1 when connected */
-#define ISTAT_800_INTF 0x04 /* Interrupt on the fly */
-#define ISTAT_700_PRE 0x04 /* Pointer register empty.
- * Set to 1 when DSPS and DSP
- * registers are empty in pipeline
- * mode, always set otherwise.
- */
-#define ISTAT_SIP 0x02 /* SCSI interrupt pending from
- * SCSI portion of SIOP see
- * SSTAT0
- */
-#define ISTAT_DIP 0x01 /* DMA interrupt pending
- * see DSTAT
- */
-
-/* NCR53c700-66 and NCR53c710 only */
-#define CTEST8_REG 0x22 /* Chip test 8 rw */
-#define CTEST8_0066_EAS 0x80 /* Enable alternate SCSI clock,
- * ie read from SCLK/ rather than CLK/
- */
-#define CTEST8_0066_EFM 0x40 /* Enable fetch and master outputs */
-#define CTEST8_0066_GRP 0x20 /* Generate Receive Parity for
- * pass through. This insures that
- * bad parity won't reach the host
- * bus.
- */
-#define CTEST8_0066_TE 0x10 /* TolerANT enable. Enable
- * active negation, should only
- * be used for slow SCSI
- * non-differential.
- */
-#define CTEST8_0066_HSC 0x08 /* Halt SCSI clock */
-#define CTEST8_0066_SRA 0x04 /* Shorten REQ/ACK filtering,
- * must be set for fast SCSI-II
- * speeds.
- */
-#define CTEST8_0066_DAS 0x02 /* Disable automatic target/initiator
- * switching.
- */
-#define CTEST8_0066_LDE 0x01 /* Last disconnect enable.
- * The status of pending
- * disconnect is maintained by
- * the core, eliminating
- * the possibility of missing a
- * selection or reselection
- * while waiting to fetch a
- * WAIT DISCONNECT opcode.
- */
-
-#define CTEST8_10_V3 0x80 /* Chip revision */
-#define CTEST8_10_V2 0x40
-#define CTEST8_10_V1 0x20
-#define CTEST8_10_V0 0x10
-#define CTEST8_10_V_MASK 0xf0
-#define CTEST8_10_FLF 0x08 /* Flush FIFOs */
-#define CTEST8_10_CLF 0x04 /* Clear FIFOs */
-#define CTEST8_10_FM 0x02 /* Fetch pin mode */
-#define CTEST8_10_SM 0x01 /* Snoop pin mode */
-
-
-/*
- * The CTEST9 register may be used to differentiate between a
- * NCR53c700 and a NCR53c710.
- *
- * Write 0xff to this register.
- * Read it.
- * If the contents are 0xff, it is a NCR53c700
- * If the contents are 0x00, it is a NCR53c700-66 first revision
- * If the contents are some other value, it is some other NCR53c700-66
- */
-#define CTEST9_REG_00 0x23 /* Chip test 9 ro */
-#define LCRC_REG_10 0x23
-
-/*
- * 0x24 through 0x27 are the DMA byte counter register. Instructions
- * write their high 8 bits into the DCMD register, the low 24 bits into
- * the DBC register.
- *
- * Function is dependent on the command type being executed.
- */
-
-
-#define DBC_REG 0x24
-/*
- * For Block Move Instructions, DBC is a 24 bit quantity representing
- * the number of bytes to transfer.
- * For Transfer Control Instructions, DBC is bit fielded as follows :
- */
-/* Bits 20 - 23 should be clear */
-#define DBC_TCI_TRUE (1 << 19) /* Jump when true */
-#define DBC_TCI_COMPARE_DATA (1 << 18) /* Compare data */
-#define DBC_TCI_COMPARE_PHASE (1 << 17) /* Compare phase with DCMD field */
-#define DBC_TCI_WAIT_FOR_VALID (1 << 16) /* Wait for REQ */
-/* Bits 8 - 15 are reserved on some implementations ? */
-#define DBC_TCI_MASK_MASK 0xff00 /* Mask for data compare */
-#define DBC_TCI_MASK_SHIFT 8
-#define DBC_TCI_DATA_MASK 0xff /* Data to be compared */
-#define DBC_TCI_DATA_SHIFT 0
-
-#define DBC_RWRI_IMMEDIATE_MASK 0xff00 /* Immediate data */
-#define DBC_RWRI_IMMEDIATE_SHIFT 8 /* Amount to shift */
-#define DBC_RWRI_ADDRESS_MASK 0x3f0000 /* Register address */
-#define DBC_RWRI_ADDRESS_SHIFT 16
-
-
-/*
- * DMA command r/w
- */
-#define DCMD_REG 0x27
-#define DCMD_TYPE_MASK 0xc0 /* Masks off type */
-#define DCMD_TYPE_BMI 0x00 /* Indicates a Block Move instruction */
-#define DCMD_BMI_IO 0x01 /* I/O, CD, and MSG bits selecting */
-#define DCMD_BMI_CD 0x02 /* the phase for the block MOVE */
-#define DCMD_BMI_MSG 0x04 /* instruction */
-
-#define DCMD_BMI_OP_MASK 0x18 /* mask for opcode */
-#define DCMD_BMI_OP_MOVE_T 0x00 /* MOVE */
-#define DCMD_BMI_OP_MOVE_I 0x08 /* MOVE Initiator */
-
-#define DCMD_BMI_INDIRECT 0x20 /* Indirect addressing */
-
-#define DCMD_TYPE_TCI 0x80 /* Indicates a Transfer Control
- instruction */
-#define DCMD_TCI_IO 0x01 /* I/O, CD, and MSG bits selecting */
-#define DCMD_TCI_CD 0x02 /* the phase for the block MOVE */
-#define DCMD_TCI_MSG 0x04 /* instruction */
-#define DCMD_TCI_OP_MASK 0x38 /* mask for opcode */
-#define DCMD_TCI_OP_JUMP 0x00 /* JUMP */
-#define DCMD_TCI_OP_CALL 0x08 /* CALL */
-#define DCMD_TCI_OP_RETURN 0x10 /* RETURN */
-#define DCMD_TCI_OP_INT 0x18 /* INT */
-
-#define DCMD_TYPE_RWRI 0x40 /* Indicates I/O or register Read/Write
- instruction */
-#define DCMD_RWRI_OPC_MASK 0x38 /* Opcode mask */
-#define DCMD_RWRI_OPC_WRITE 0x28 /* Write SFBR to register */
-#define DCMD_RWRI_OPC_READ 0x30 /* Read register to SFBR */
-#define DCMD_RWRI_OPC_MODIFY 0x38 /* Modify in place */
-
-#define DCMD_RWRI_OP_MASK 0x07
-#define DCMD_RWRI_OP_MOVE 0x00
-#define DCMD_RWRI_OP_SHL 0x01
-#define DCMD_RWRI_OP_OR 0x02
-#define DCMD_RWRI_OP_XOR 0x03
-#define DCMD_RWRI_OP_AND 0x04
-#define DCMD_RWRI_OP_SHR 0x05
-#define DCMD_RWRI_OP_ADD 0x06
-#define DCMD_RWRI_OP_ADDC 0x07
-
-#define DCMD_TYPE_MMI 0xc0 /* Indicates a Memory Move instruction
- (three words) */
-
-
-#define DNAD_REG 0x28 /* through 0x2b DMA next address for
- data */
-#define DSP_REG 0x2c /* through 0x2f DMA SCRIPTS pointer rw */
-#define DSPS_REG 0x30 /* through 0x33 DMA SCRIPTS pointer
- save rw */
-#define DMODE_REG_00 0x34 /* DMA mode rw */
-#define DMODE_00_BL1 0x80 /* Burst length bits */
-#define DMODE_00_BL0 0x40
-#define DMODE_BL_MASK 0xc0
-/* Burst lengths (800) */
-#define DMODE_BL_2 0x00 /* 2 transfer */
-#define DMODE_BL_4 0x40 /* 4 transfers */
-#define DMODE_BL_8 0x80 /* 8 transfers */
-#define DMODE_BL_16 0xc0 /* 16 transfers */
-
-#define DMODE_10_BL_1 0x00 /* 1 transfer */
-#define DMODE_10_BL_2 0x40 /* 2 transfers */
-#define DMODE_10_BL_4 0x80 /* 4 transfers */
-#define DMODE_10_BL_8 0xc0 /* 8 transfers */
-#define DMODE_10_FC2 0x20 /* Driven to FC2 pin */
-#define DMODE_10_FC1 0x10 /* Driven to FC1 pin */
-#define DMODE_710_PD 0x08 /* Program/data on FC0 pin */
-#define DMODE_710_UO 0x02 /* User prog. output */
-
-#define DMODE_700_BW16 0x20 /* Host buswidth = 16 */
-#define DMODE_700_286 0x10 /* 286 mode */
-#define DMODE_700_IOM 0x08 /* Transfer to IO port */
-#define DMODE_700_FAM 0x04 /* Fixed address mode */
-#define DMODE_700_PIPE 0x02 /* Pipeline mode disables
- * automatic fetch / exec
- */
-#define DMODE_MAN 0x01 /* Manual start mode,
- * requires a 1 to be written
- * to the start DMA bit in the DCNTL
- * register to run scripts
- */
-
-#define DMODE_700_SAVE ( DMODE_00_BL_MASK | DMODE_00_BW16 | DMODE_00_286 )
-
-/* NCR53c800 series only */
-#define SCRATCHA_REG_800 0x34 /* through 0x37 Scratch A rw */
-/* NCR53c710 only */
-#define SCRATCHB_REG_10 0x34 /* through 0x37 scratch B rw */
-
-#define DMODE_REG_10 0x38 /* DMA mode rw, NCR53c710 and newer */
-#define DMODE_800_SIOM 0x20 /* Source IO = 1 */
-#define DMODE_800_DIOM 0x10 /* Destination IO = 1 */
-#define DMODE_800_ERL 0x08 /* Enable Read Line */
-
-/* 35-38 are reserved on 700 and 700-66 series chips */
-#define DIEN_REG 0x39 /* DMA interrupt enable rw */
-/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
-#define DIEN_800_MDPE 0x40 /* Master data parity error */
-#define DIEN_800_BF 0x20 /* BUS fault */
-#define DIEN_700_BF 0x20 /* BUS fault */
-#define DIEN_ABRT 0x10 /* Enable aborted interrupt */
-#define DIEN_SSI 0x08 /* Enable single step interrupt */
-#define DIEN_SIR 0x04 /* Enable SCRIPTS INT command
- * interrupt
- */
-/* 0x02 is reserved on 800 series chips */
-#define DIEN_700_WTD 0x02 /* Enable watchdog timeout interrupt */
-#define DIEN_700_OPC 0x01 /* Enable illegal instruction
- * interrupt
- */
-#define DIEN_800_IID 0x01 /* Same meaning, different name */
-
-/*
- * DMA watchdog timer rw
- * set in 16 CLK input periods.
- */
-#define DWT_REG 0x3a
-
-/* DMA control rw */
-#define DCNTL_REG 0x3b
-#define DCNTL_700_CF1 0x80 /* Clock divisor bits */
-#define DCNTL_700_CF0 0x40
-#define DCNTL_700_CF_MASK 0xc0
-/* Clock divisors Divisor SCLK range (MHZ) */
-#define DCNTL_700_CF_2 0x00 /* 2.0 37.51-50.00 */
-#define DCNTL_700_CF_1_5 0x40 /* 1.5 25.01-37.50 */
-#define DCNTL_700_CF_1 0x80 /* 1.0 16.67-25.00 */
-#define DCNTL_700_CF_3 0xc0 /* 3.0 50.01-66.67 (53c700-66) */
-
-#define DCNTL_700_S16 0x20 /* Load scripts 16 bits at a time */
-#define DCNTL_SSM 0x10 /* Single step mode */
-#define DCNTL_700_LLM 0x08 /* Low level mode, can only be set
- * after selection */
-#define DCNTL_800_IRQM 0x08 /* Totem pole IRQ pin */
-#define DCNTL_STD 0x04 /* Start DMA / SCRIPTS */
-/* 0x02 is reserved */
-#define DCNTL_00_RST 0x01 /* Software reset, resets everything
- * but 286 mode bit in DMODE. On the
- * NCR53c710, this bit moved to CTEST8
- */
-#define DCNTL_10_COM 0x01 /* 700 software compatibility mode */
-#define DCNTL_10_EA 0x20 /* Enable Ack - needed for MVME16x */
-
-#define DCNTL_700_SAVE ( DCNTL_CF_MASK | DCNTL_S16)
-
-
-/* NCR53c700-66 only */
-#define SCRATCHB_REG_00 0x3c /* through 0x3f scratch b rw */
-#define SCRATCHB_REG_800 0x5c /* through 0x5f scratch b rw */
-/* NCR53c710 only */
-#define ADDER_REG_10 0x3c /* Adder, NCR53c710 only */
-
-#define SIEN1_REG_800 0x41
-#define SIEN1_800_STO 0x04 /* selection/reselection timeout */
-#define SIEN1_800_GEN 0x02 /* general purpose timer */
-#define SIEN1_800_HTH 0x01 /* handshake to handshake */
-
-#define SIST1_REG_800 0x43
-#define SIST1_800_STO 0x04 /* selection/reselection timeout */
-#define SIST1_800_GEN 0x02 /* general purpose timer */
-#define SIST1_800_HTH 0x01 /* handshake to handshake */
-
-#define SLPAR_REG_800 0x44 /* Parity */
-
-#define MACNTL_REG_800 0x46 /* Memory access control */
-#define MACNTL_800_TYP3 0x80
-#define MACNTL_800_TYP2 0x40
-#define MACNTL_800_TYP1 0x20
-#define MACNTL_800_TYP0 0x10
-#define MACNTL_800_DWR 0x08
-#define MACNTL_800_DRD 0x04
-#define MACNTL_800_PSCPT 0x02
-#define MACNTL_800_SCPTS 0x01
-
-#define GPCNTL_REG_800 0x47 /* General Purpose Pin Control */
-
-/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
-#define STIME0_REG_800 0x48 /* SCSI Timer Register 0 */
-#define STIME0_800_HTH_MASK 0xf0 /* Handshake to Handshake timeout */
-#define STIME0_800_HTH_SHIFT 4
-#define STIME0_800_SEL_MASK 0x0f /* Selection timeout */
-#define STIME0_800_SEL_SHIFT 0
-
-#define STIME1_REG_800 0x49
-#define STIME1_800_GEN_MASK 0x0f /* General purpose timer */
-
-#define RESPID_REG_800 0x4a /* Response ID, bit fielded. 8
- bits on narrow chips, 16 on WIDE */
-
-#define STEST0_REG_800 0x4c
-#define STEST0_800_SLT 0x08 /* Selection response logic test */
-#define STEST0_800_ART 0x04 /* Arbitration priority encoder test */
-#define STEST0_800_SOZ 0x02 /* Synchronous offset zero */
-#define STEST0_800_SOM 0x01 /* Synchronous offset maximum */
-
-#define STEST1_REG_800 0x4d
-#define STEST1_800_SCLK 0x80 /* Disable SCSI clock */
-
-#define STEST2_REG_800 0x4e
-#define STEST2_800_SCE 0x80 /* Enable SOCL/SODL */
-#define STEST2_800_ROF 0x40 /* Reset SCSI sync offset */
-#define STEST2_800_SLB 0x10 /* Enable SCSI loopback mode */
-#define STEST2_800_SZM 0x08 /* SCSI high impedance mode */
-#define STEST2_800_EXT 0x02 /* Extend REQ/ACK filter 30 to 60ns */
-#define STEST2_800_LOW 0x01 /* SCSI low level mode */
-
-#define STEST3_REG_800 0x4f
-#define STEST3_800_TE 0x80 /* Enable active negation */
-#define STEST3_800_STR 0x40 /* SCSI FIFO test read */
-#define STEST3_800_HSC 0x20 /* Halt SCSI clock */
-#define STEST3_800_DSI 0x10 /* Disable single initiator response */
-#define STEST3_800_TTM 0x04 /* Time test mode */
-#define STEST3_800_CSF 0x02 /* Clear SCSI FIFO */
-#define STEST3_800_STW 0x01 /* SCSI FIFO test write */
-
-#define OPTION_PARITY 0x1 /* Enable parity checking */
-#define OPTION_TAGGED_QUEUE 0x2 /* Enable SCSI-II tagged queuing */
-#define OPTION_700 0x8 /* Always run NCR53c700 scripts */
-#define OPTION_INTFLY 0x10 /* Use INTFLY interrupts */
-#define OPTION_DEBUG_INTR 0x20 /* Debug interrupts */
-#define OPTION_DEBUG_INIT_ONLY 0x40 /* Run initialization code and
- simple test code, return
- DID_NO_CONNECT if any SCSI
- commands are attempted. */
-#define OPTION_DEBUG_READ_ONLY 0x80 /* Return DID_ERROR if any
- SCSI write is attempted */
-#define OPTION_DEBUG_TRACE 0x100 /* Animated trace mode, print
- each address and instruction
- executed to debug buffer. */
-#define OPTION_DEBUG_SINGLE 0x200 /* stop after executing one
- instruction */
-#define OPTION_SYNCHRONOUS 0x400 /* Enable sync SCSI. */
-#define OPTION_MEMORY_MAPPED 0x800 /* NCR registers have valid
- memory mapping */
-#define OPTION_IO_MAPPED 0x1000 /* NCR registers have valid
- I/O mapping */
-#define OPTION_DEBUG_PROBE_ONLY 0x2000 /* Probe only, don't even init */
-#define OPTION_DEBUG_TESTS_ONLY 0x4000 /* Probe, init, run selected tests */
-#define OPTION_DEBUG_TEST0 0x08000 /* Run test 0 */
-#define OPTION_DEBUG_TEST1 0x10000 /* Run test 1 */
-#define OPTION_DEBUG_TEST2 0x20000 /* Run test 2 */
-#define OPTION_DEBUG_DUMP 0x40000 /* Dump commands */
-#define OPTION_DEBUG_TARGET_LIMIT 0x80000 /* Only talk to target+luns specified */
-#define OPTION_DEBUG_NCOMMANDS_LIMIT 0x100000 /* Limit the number of commands */
-#define OPTION_DEBUG_SCRIPT 0x200000 /* Print when checkpoints are passed */
-#define OPTION_DEBUG_FIXUP 0x400000 /* print fixup values */
-#define OPTION_DEBUG_DSA 0x800000
-#define OPTION_DEBUG_CORRUPTION 0x1000000 /* Detect script corruption */
-#define OPTION_DEBUG_SDTR 0x2000000 /* Debug SDTR problem */
-#define OPTION_DEBUG_MISMATCH 0x4000000 /* Debug phase mismatches */
-#define OPTION_DISCONNECT 0x8000000 /* Allow disconnect */
-#define OPTION_DEBUG_DISCONNECT 0x10000000
-#define OPTION_ALWAYS_SYNCHRONOUS 0x20000000 /* Negotiate sync. transfers
- on power up */
-#define OPTION_DEBUG_QUEUES 0x80000000
-#define OPTION_DEBUG_ALLOCATION 0x100000000LL
-#define OPTION_DEBUG_SYNCHRONOUS 0x200000000LL /* Sanity check SXFER and
- SCNTL3 registers */
-#define OPTION_NO_ASYNC 0x400000000LL /* Don't automagically send
- SDTR for async transfers when
- we haven't been told to do
- a synchronous transfer. */
-#define OPTION_NO_PRINT_RACE 0x800000000LL /* Don't print message when
- the reselect/WAIT DISCONNECT
- race condition hits */
-#if !defined(PERM_OPTIONS)
-#define PERM_OPTIONS 0
-#endif
-
-/*
- * Some data which is accessed by the NCR chip must be 4-byte aligned.
- * For some hosts the default is less than that (eg. 68K uses 2-byte).
- * Alignment has only been forced where it is important; also if one
- * 32 bit structure field is aligned then it is assumed that following
- * 32 bit fields are also aligned. Take care when adding fields
- * which are other than 32 bit.
- */
-
-struct NCR53c7x0_synchronous {
- u32 select_indirect /* Value used for indirect selection */
- __attribute__ ((aligned (4)));
- u32 sscf_710; /* Used to set SSCF bits for 710 */
- u32 script[8]; /* Size ?? Script used when target is
- reselected */
- unsigned char synchronous_want[5]; /* Per target desired SDTR */
-/*
- * Set_synchronous programs these, select_indirect and current settings after
- * int_debug_should show a match.
- */
- unsigned char sxfer_sanity, scntl3_sanity;
-};
-
-#define CMD_FLAG_SDTR 1 /* Initiating synchronous
- transfer negotiation */
-#define CMD_FLAG_WDTR 2 /* Initiating wide transfer
- negotiation */
-#define CMD_FLAG_DID_SDTR 4 /* did SDTR */
-#define CMD_FLAG_DID_WDTR 8 /* did WDTR */
-
-struct NCR53c7x0_table_indirect {
- u32 count;
- void *address;
-};
-
-enum ncr_event {
- EVENT_NONE = 0,
-/*
- * Order is IMPORTANT, since these must correspond to the event interrupts
- * in 53c7,8xx.scr
- */
-
- EVENT_ISSUE_QUEUE = 0x5000000, /* 0 Command was added to issue queue */
- EVENT_START_QUEUE, /* 1 Command moved to start queue */
- EVENT_SELECT, /* 2 Command completed selection */
- EVENT_DISCONNECT, /* 3 Command disconnected */
- EVENT_RESELECT, /* 4 Command reselected */
- EVENT_COMPLETE, /* 5 Command completed */
- EVENT_IDLE, /* 6 */
- EVENT_SELECT_FAILED, /* 7 */
- EVENT_BEFORE_SELECT, /* 8 */
- EVENT_RESELECT_FAILED /* 9 */
-};
-
-struct NCR53c7x0_event {
- enum ncr_event event; /* What type of event */
- unsigned char target;
- unsigned char lun;
- struct timeval time;
- u32 *dsa; /* What's in the DSA register now (virt) */
-/*
- * A few things from that SCSI pid so we know what happened after
- * the Scsi_Cmnd structure in question may have disappeared.
- */
- unsigned long pid; /* The SCSI PID which caused this
- event */
- unsigned char cmnd[12];
-};
-
-/*
- * Things in the NCR53c7x0_cmd structure are split into two parts :
- *
- * 1. A fixed portion, for things which are not accessed directly by static NCR
- * code (ie, are referenced only by the Linux side of the driver,
- * or only by dynamically generated code).
- *
- * 2. The DSA portion, for things which are accessed directly by static NCR
- * code.
- *
- * This is a little ugly, but it
- * 1. Avoids conflicts between the NCR code's picture of the structure, and
- * Linux code's idea of what it looks like.
- *
- * 2. Minimizes the pain in the Linux side of the code needed
- * to calculate real dsa locations for things, etc.
- *
- */
-
-struct NCR53c7x0_cmd {
- void *real; /* Real, unaligned address for
- free function */
- void (* free)(void *, int); /* Command to deallocate; NULL
- for structures allocated with
- scsi_register, etc. */
- Scsi_Cmnd *cmd; /* Associated Scsi_Cmnd
- structure, Scsi_Cmnd points
- at NCR53c7x0_cmd using
- host_scribble structure */
-
- int size; /* scsi_malloc'd size of this
- structure */
-
- int flags; /* CMD_* flags */
-
- unsigned char cmnd[12]; /* CDB, copied from Scsi_Cmnd */
- int result; /* Copy to Scsi_Cmnd when done */
-
- struct { /* Private non-cached bounce buffer */
- unsigned char buf[256];
- u32 addr;
- u32 len;
- } bounce;
-
-/*
- * SDTR and WIDE messages are an either/or affair
- * in this message, since we will go into message out and send
- * _the whole mess_ without dropping out of message out to
- * let the target go into message in after sending the first
- * message.
- */
-
- unsigned char select[11]; /* Select message, includes
- IDENTIFY
- (optional) QUEUE TAG
- (optional) SDTR or WDTR
- */
-
-
- volatile struct NCR53c7x0_cmd *next; /* Linux maintained lists (free,
- running, eventually finished */
-
-
- u32 *data_transfer_start; /* Start of data transfer routines */
- u32 *data_transfer_end; /* Address after end of data transfer o
- routines */
-/*
- * The following three fields were moved from the DSA proper to here
- * since only dynamically generated NCR code refers to them, meaning
- * we don't need dsa_* absolutes, and it is simpler to let the
- * host code refer to them directly.
- */
-
-/*
- * HARD CODED : residual and saved_residual need to agree with the sizes
- * used in NCR53c7,8xx.scr.
- *
- * FIXME: we want to consider the case where we have odd-length
- * scatter/gather buffers and a WIDE transfer, in which case
- * we'll need to use the CHAIN MOVE instruction. Ick.
- */
- u32 residual[6] __attribute__ ((aligned (4)));
- /* Residual data transfer which
- allows pointer code to work
- right.
-
- [0-1] : Conditional call to
- appropriate other transfer
- routine.
- [2-3] : Residual block transfer
- instruction.
- [4-5] : Jump to instruction
- after splice.
- */
- u32 saved_residual[6]; /* Copy of old residual, so we
- can get another partial
- transfer and still recover
- */
-
- u32 saved_data_pointer; /* Saved data pointer */
-
- u32 dsa_next_addr; /* _Address_ of dsa_next field
- in this dsa for RISCy
- style constant. */
-
- u32 dsa_addr; /* Address of dsa; RISCy style
- constant */
-
- u32 dsa[0]; /* Variable length (depending
- on host type, number of scatter /
- gather buffers, etc). */
-};
-
-struct NCR53c7x0_break {
- u32 *address, old_instruction[2];
- struct NCR53c7x0_break *next;
- unsigned char old_size; /* Size of old instruction */
-};
-
-/* Indicates that the NCR is not executing code */
-#define STATE_HALTED 0
-/*
- * Indicates that the NCR is executing the wait for select / reselect
- * script. Only used when running NCR53c700 compatible scripts, only
- * state during which an ABORT is _not_ considered an error condition.
- */
-#define STATE_WAITING 1
-/* Indicates that the NCR is executing other code. */
-#define STATE_RUNNING 2
-/*
- * Indicates that the NCR was being aborted.
- */
-#define STATE_ABORTING 3
-/* Indicates that the NCR was successfully aborted. */
-#define STATE_ABORTED 4
-/* Indicates that the NCR has been disabled due to a fatal error */
-#define STATE_DISABLED 5
-
-/*
- * Where knowledge of SCSI SCRIPT(tm) specified values are needed
- * in an interrupt handler, an interrupt handler exists for each
- * different SCSI script so we don't have name space problems.
- *
- * Return values of these handlers are as follows :
- */
-#define SPECIFIC_INT_NOTHING 0 /* don't even restart */
-#define SPECIFIC_INT_RESTART 1 /* restart at the next instruction */
-#define SPECIFIC_INT_ABORT 2 /* recoverable error, abort cmd */
-#define SPECIFIC_INT_PANIC 3 /* unrecoverable error, panic */
-#define SPECIFIC_INT_DONE 4 /* normal command completion */
-#define SPECIFIC_INT_BREAK 5 /* break point encountered */
-
-struct NCR53c7x0_hostdata {
- int size; /* Size of entire Scsi_Host
- structure */
- int board; /* set to board type, useful if
- we have host specific things,
- ie, a general purpose I/O
- bit is being used to enable
- termination, etc. */
-
- int chip; /* set to chip type; 700-66 is
- 700-66, rest are last three
- digits of part number */
-
- char valid_ids[8]; /* Valid SCSI ID's for adapter */
-
- u32 *dsp; /* dsp to restart with after
- all stacked interrupts are
- handled. */
-
- unsigned dsp_changed:1; /* Has dsp changed within this
- set of stacked interrupts ? */
-
- unsigned char dstat; /* Most recent value of dstat */
- unsigned dstat_valid:1;
-
- unsigned expecting_iid:1; /* Expect IID interrupt */
- unsigned expecting_sto:1; /* Expect STO interrupt */
-
- /*
- * The code stays cleaner if we use variables with function
- * pointers and offsets that are unique for the different
- * scripts rather than having a slew of switch(hostdata->chip)
- * statements.
- *
- * It also means that the #defines from the SCSI SCRIPTS(tm)
- * don't have to be visible outside of the script-specific
- * instructions, preventing name space pollution.
- */
-
- void (* init_fixup)(struct Scsi_Host *host);
- void (* init_save_regs)(struct Scsi_Host *host);
- void (* dsa_fixup)(struct NCR53c7x0_cmd *cmd);
- void (* soft_reset)(struct Scsi_Host *host);
- int (* run_tests)(struct Scsi_Host *host);
-
- /*
- * Called when DSTAT_SIR is set, indicating an interrupt generated
- * by the INT instruction, where values are unique for each SCSI
- * script. Should return one of the SPEC_* values.
- */
-
- int (* dstat_sir_intr)(struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
-
- int dsa_len; /* Size of DSA structure */
-
- /*
- * Location of DSA fields for the SCSI SCRIPT corresponding to this
- * chip.
- */
-
- s32 dsa_start;
- s32 dsa_end;
- s32 dsa_next;
- s32 dsa_prev;
- s32 dsa_cmnd;
- s32 dsa_select;
- s32 dsa_msgout;
- s32 dsa_cmdout;
- s32 dsa_dataout;
- s32 dsa_datain;
- s32 dsa_msgin;
- s32 dsa_msgout_other;
- s32 dsa_write_sync;
- s32 dsa_write_resume;
- s32 dsa_check_reselect;
- s32 dsa_status;
- s32 dsa_saved_pointer;
- s32 dsa_jump_dest;
-
- /*
- * Important entry points that generic fixup code needs
- * to know about, fixed up.
- */
-
- s32 E_accept_message;
- s32 E_command_complete;
- s32 E_data_transfer;
- s32 E_dsa_code_template;
- s32 E_dsa_code_template_end;
- s32 E_end_data_transfer;
- s32 E_msg_in;
- s32 E_initiator_abort;
- s32 E_other_transfer;
- s32 E_other_in;
- s32 E_other_out;
- s32 E_target_abort;
- s32 E_debug_break;
- s32 E_reject_message;
- s32 E_respond_message;
- s32 E_select;
- s32 E_select_msgout;
- s32 E_test_0;
- s32 E_test_1;
- s32 E_test_2;
- s32 E_test_3;
- s32 E_dsa_zero;
- s32 E_cmdout_cmdout;
- s32 E_wait_reselect;
- s32 E_dsa_code_begin;
-
- long long options; /* Bitfielded set of options enabled */
- volatile u32 test_completed; /* Test completed */
- int test_running; /* Test currently running */
- s32 test_source
- __attribute__ ((aligned (4)));
- volatile s32 test_dest;
-
- volatile int state; /* state of driver, only used for
- OPTION_700 */
-
- unsigned char dmode; /*
- * set to the address of the DMODE
- * register for this chip.
- */
- unsigned char istat; /*
- * set to the address of the ISTAT
- * register for this chip.
- */
-
- int scsi_clock; /*
- * SCSI clock in HZ. 0 may be used
- * for unknown, although this will
- * disable synchronous negotiation.
- */
-
- volatile int intrs; /* Number of interrupts */
- volatile int resets; /* Number of SCSI resets */
- unsigned char saved_dmode;
- unsigned char saved_ctest4;
- unsigned char saved_ctest7;
- unsigned char saved_dcntl;
- unsigned char saved_scntl3;
-
- unsigned char this_id_mask;
-
- /* Debugger information */
- struct NCR53c7x0_break *breakpoints, /* Linked list of all break points */
- *breakpoint_current; /* Current breakpoint being stepped
- through, NULL if we are running
- normally. */
-#ifdef NCR_DEBUG
- int debug_size; /* Size of debug buffer */
- volatile int debug_count; /* Current data count */
- volatile char *debug_buf; /* Output ring buffer */
- volatile char *debug_write; /* Current write pointer */
- volatile char *debug_read; /* Current read pointer */
-#endif /* def NCR_DEBUG */
-
- /* XXX - primitive debugging junk, remove when working ? */
- int debug_print_limit; /* Number of commands to print
- out exhaustive debugging
- information for if
- OPTION_DEBUG_DUMP is set */
-
- unsigned char debug_lun_limit[16]; /* If OPTION_DEBUG_TARGET_LIMIT
- set, puke if commands are sent
- to other target/lun combinations */
-
- int debug_count_limit; /* Number of commands to execute
- before puking to limit debugging
- output */
-
-
- volatile unsigned idle:1; /* set to 1 if idle */
-
- /*
- * Table of synchronous+wide transfer parameters set on a per-target
- * basis.
- */
-
- volatile struct NCR53c7x0_synchronous sync[16]
- __attribute__ ((aligned (4)));
-
- volatile Scsi_Cmnd *issue_queue
- __attribute__ ((aligned (4)));
- /* waiting to be issued by
- Linux driver */
- volatile struct NCR53c7x0_cmd *running_list;
- /* commands running, maintained
- by Linux driver */
-
- volatile struct NCR53c7x0_cmd *ncrcurrent; /* currently connected
- nexus, ONLY valid for
- NCR53c700/NCR53c700-66
- */
-
- volatile struct NCR53c7x0_cmd *spare; /* pointer to spare,
- allocated at probe time,
- which we can use for
- initialization */
- volatile struct NCR53c7x0_cmd *free;
- int max_cmd_size; /* Maximum size of NCR53c7x0_cmd
- based on number of
- scatter/gather segments, etc.
- */
- volatile int num_cmds; /* Number of commands
- allocated */
- volatile int extra_allocate;
- volatile unsigned char cmd_allocated[16]; /* Have we allocated commands
- for this target yet? If not,
- do so ASAP */
- volatile unsigned char busy[16][8]; /* number of commands
- executing on each target
- */
- /*
- * Eventually, I'll switch to a coroutine for calling
- * cmd->done(cmd), etc. so that we can overlap interrupt
- * processing with this code for maximum performance.
- */
-
- volatile struct NCR53c7x0_cmd *finished_queue;
-
- /* Shared variables between SCRIPT and host driver */
- volatile u32 *schedule
- __attribute__ ((aligned (4))); /* Array of JUMPs to dsa_begin
- routines of various DSAs.
- When not in use, replace
- with jump to next slot */
-
-
- volatile unsigned char msg_buf[16]; /* buffer for messages
- other than the command
- complete message */
-
- /* Per-target default synchronous and WIDE messages */
- volatile unsigned char synchronous_want[16][5];
- volatile unsigned char wide_want[16][4];
-
- /* Bit fielded set of targets we want to speak synchronously with */
- volatile u16 initiate_sdtr;
- /* Bit fielded set of targets we want to speak wide with */
- volatile u16 initiate_wdtr;
- /* Bit fielded list of targets we've talked to. */
- volatile u16 talked_to;
-
- /* Array of bit-fielded lun lists that we need to request_sense */
- volatile unsigned char request_sense[16];
-
- u32 addr_reconnect_dsa_head
- __attribute__ ((aligned (4))); /* RISCy style constant,
- address of following */
- volatile u32 reconnect_dsa_head;
- /* Data identifying nexus we are trying to match during reselection */
- volatile unsigned char reselected_identify; /* IDENTIFY message */
- volatile unsigned char reselected_tag; /* second byte of queue tag
- message or 0 */
-
- /* These were static variables before we moved them */
-
- s32 NCR53c7xx_zero
- __attribute__ ((aligned (4)));
- s32 NCR53c7xx_sink;
- u32 NOP_insn;
- char NCR53c7xx_msg_reject;
- char NCR53c7xx_msg_abort;
- char NCR53c7xx_msg_nop;
-
- /*
- * Following item introduced by RGH to support NCRc710, which is
- * VERY brain-dead when it come to memory moves
- */
-
- /* DSA save area used only by the NCR chip */
- volatile unsigned long saved2_dsa
- __attribute__ ((aligned (4)));
-
- volatile unsigned long emulated_intfly
- __attribute__ ((aligned (4)));
-
- volatile int event_size, event_index;
- volatile struct NCR53c7x0_event *events;
-
- /* If we need to generate code to kill off the currently connected
- command, this is where we do it. Should have a BMI instruction
- to source or sink the current data, followed by a JUMP
- to abort_connected */
-
- u32 *abort_script;
-
- int script_count; /* Size of script in words */
- u32 script[0]; /* Relocated SCSI script */
-
-};
-
-#define SCSI_IRQ_NONE 255
-#define DMA_NONE 255
-#define IRQ_AUTO 254
-#define DMA_AUTO 254
-
-#define BOARD_GENERIC 0
-
-#define NCR53c7x0_insn_size(insn) \
- (((insn) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI ? 3 : 2)
-
-
-#define NCR53c7x0_local_declare() \
- volatile unsigned char *NCR53c7x0_address_memory; \
- unsigned int NCR53c7x0_address_io; \
- int NCR53c7x0_memory_mapped
-
-#define NCR53c7x0_local_setup(host) \
- NCR53c7x0_address_memory = (void *) (host)->base; \
- NCR53c7x0_address_io = (unsigned int) (host)->io_port; \
- NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) \
- host->hostdata[0])-> options & OPTION_MEMORY_MAPPED
-
-#ifdef BIG_ENDIAN
-/* These could be more efficient, given that we are always memory mapped,
- * but they don't give the same problems as the write macros, so leave
- * them. */
-#ifdef __mc68000__
-#define NCR53c7x0_read8(address) \
- ((unsigned int)raw_inb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) )
-
-#define NCR53c7x0_read16(address) \
- ((unsigned int)raw_inw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)))
-#else
-#define NCR53c7x0_read8(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) : \
- inb(NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_read16(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) : \
- inw(NCR53c7x0_address_io + (address)))
-#endif /* mc68000 */
-#else
-#define NCR53c7x0_read8(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readb((u32)NCR53c7x0_address_memory + (u32)(address)) : \
- inb(NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_read16(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int)readw((u32)NCR53c7x0_address_memory + (u32)(address)) : \
- inw(NCR53c7x0_address_io + (address)))
-#endif
-
-#ifdef __mc68000__
-#define NCR53c7x0_read32(address) \
- ((unsigned int) raw_inl((u32)NCR53c7x0_address_memory + (u32)(address)))
-#else
-#define NCR53c7x0_read32(address) \
- (NCR53c7x0_memory_mapped ? \
- (unsigned int) readl((u32)NCR53c7x0_address_memory + (u32)(address)) : \
- inl(NCR53c7x0_address_io + (address)))
-#endif /* mc68000*/
-
-#ifdef BIG_ENDIAN
-/* If we are big-endian, then we are not Intel, so probably don't have
- * an i/o map as well as a memory map. So, let's assume memory mapped.
- * Also, I am having terrible problems trying to persuade the compiler
- * not to lay down code which does a read after write for these macros.
- * If you remove 'volatile' from writeb() and friends it is ok....
- */
-
-#define NCR53c7x0_write8(address,value) \
- *(volatile unsigned char *) \
- ((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) = (value)
-
-#define NCR53c7x0_write16(address,value) \
- *(volatile unsigned short *) \
- ((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) = (value)
-
-#define NCR53c7x0_write32(address,value) \
- *(volatile unsigned long *) \
- ((u32)NCR53c7x0_address_memory + ((u32)(address))) = (value)
-
-#else
-
-#define NCR53c7x0_write8(address,value) \
- (NCR53c7x0_memory_mapped ? \
- ({writeb((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
- outb((value), NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_write16(address,value) \
- (NCR53c7x0_memory_mapped ? \
- ({writew((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
- outw((value), NCR53c7x0_address_io + (address)))
-
-#define NCR53c7x0_write32(address,value) \
- (NCR53c7x0_memory_mapped ? \
- ({writel((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) : \
- outl((value), NCR53c7x0_address_io + (address)))
-
-#endif
-
-/* Patch arbitrary 32 bit words in the script */
-#define patch_abs_32(script, offset, symbol, value) \
- for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
- (u32)); ++i) { \
- (script)[A_##symbol##_used[i] - (offset)] += (value); \
- if (hostdata->options & OPTION_DEBUG_FIXUP) \
- printk("scsi%d : %s reference %d at 0x%x in %s is now 0x%x\n",\
- host->host_no, #symbol, i, A_##symbol##_used[i] - \
- (int)(offset), #script, (script)[A_##symbol##_used[i] - \
- (offset)]); \
- }
-
-/* Patch read/write instruction immediate field */
-#define patch_abs_rwri_data(script, offset, symbol, value) \
- for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
- (u32)); ++i) \
- (script)[A_##symbol##_used[i] - (offset)] = \
- ((script)[A_##symbol##_used[i] - (offset)] & \
- ~DBC_RWRI_IMMEDIATE_MASK) | \
- (((value) << DBC_RWRI_IMMEDIATE_SHIFT) & \
- DBC_RWRI_IMMEDIATE_MASK)
-
-/* Patch transfer control instruction data field */
-#define patch_abs_tci_data(script, offset, symbol, value) \
- for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
- (u32)); ++i) \
- (script)[A_##symbol##_used[i] - (offset)] = \
- ((script)[A_##symbol##_used[i] - (offset)] & \
- ~DBC_TCI_DATA_MASK) | \
- (((value) << DBC_TCI_DATA_SHIFT) & \
- DBC_TCI_DATA_MASK)
-
-/* Patch field in dsa structure (assignment should be +=?) */
-#define patch_dsa_32(dsa, symbol, word, value) \
- { \
- (dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32) \
- + (word)] = (value); \
- if (hostdata->options & OPTION_DEBUG_DSA) \
- printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
- #dsa, #symbol, hostdata->##symbol, \
- (word), (u32) (value)); \
- }
-
-/* Paranoid people could use panic() here. */
-#define FATAL(host) shutdown((host));
-
-extern int ncr53c7xx_init(struct scsi_host_template *tpnt, int board, int chip,
- unsigned long base, int io_port, int irq, int dma,
- long long options, int clock);
-
-#endif /* NCR53c710_C */
-#endif /* NCR53c710_H */
diff --git a/drivers/scsi/53c7xx.scr b/drivers/scsi/53c7xx.scr
deleted file mode 100644
index 9c5694a2da8a..000000000000
--- a/drivers/scsi/53c7xx.scr
+++ /dev/null
@@ -1,1591 +0,0 @@
-#undef DEBUG
-#undef EVENTS
-#undef NO_SELECTION_TIMEOUT
-#define BIG_ENDIAN
-
-; 53c710 driver. Modified from Drew Eckhardts driver
-; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
-;
-; I have left the script for the 53c8xx family in here, as it is likely
-; to be useful to see what I changed when bug hunting.
-
-; NCR 53c810 driver, main script
-; Sponsored by
-; iX Multiuser Multitasking Magazine
-; hm@ix.de
-;
-; Copyright 1993, 1994, 1995 Drew Eckhardt
-; Visionary Computing
-; (Unix and Linux consulting and custom programming)
-; drew@PoohSticks.ORG
-; +1 (303) 786-7975
-;
-; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
-;
-; PRE-ALPHA
-;
-; For more information, please consult
-;
-; NCR 53C810
-; PCI-SCSI I/O Processor
-; Data Manual
-;
-; NCR 53C710
-; SCSI I/O Processor
-; Programmers Guide
-;
-; NCR Microelectronics
-; 1635 Aeroplaza Drive
-; Colorado Springs, CO 80916
-; 1+ (719) 578-3400
-;
-; Toll free literature number
-; +1 (800) 334-5454
-;
-; IMPORTANT : This code is self modifying due to the limitations of
-; the NCR53c7,8xx series chips. Persons debugging this code with
-; the remote debugger should take this into account, and NOT set
-; breakpoints in modified instructions.
-;
-; Design:
-; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard
-; microcontroller using a simple instruction set.
-;
-; So, to minimize the effects of interrupt latency, and to maximize
-; throughput, this driver offloads the practical maximum amount
-; of processing to the SCSI chip while still maintaining a common
-; structure.
-;
-; Where tradeoffs were needed between efficiency on the older
-; chips and the newer NCR53c800 series, the NCR53c800 series
-; was chosen.
-;
-; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
-; automate SCSI transfers without host processor intervention, this
-; isn't the case with the NCR53c710 and newer chips which allow
-;
-; - reads and writes to the internal registers from within the SCSI
-; scripts, allowing the SCSI SCRIPTS(tm) code to save processor
-; state so that multiple threads of execution are possible, and also
-; provide an ALU for loop control, etc.
-;
-; - table indirect addressing for some instructions. This allows
-; pointers to be located relative to the DSA ((Data Structure
-; Address) register.
-;
-; These features make it possible to implement a mailbox style interface,
-; where the same piece of code is run to handle I/O for multiple threads
-; at once minimizing our need to relocate code. Since the NCR53c700/
-; NCR53c800 series have a unique combination of features, making a
-; a standard ingoing/outgoing mailbox system, costly, I've modified it.
-;
-; - Mailboxes are a mixture of code and data. This lets us greatly
-; simplify the NCR53c810 code and do things that would otherwise
-; not be possible.
-;
-; The saved data pointer is now implemented as follows :
-;
-; Control flow has been architected such that if control reaches
-; munge_save_data_pointer, on a restore pointers message or
-; reconnection, a jump to the address formerly in the TEMP register
-; will allow the SCSI command to resume execution.
-;
-
-;
-; Note : the DSA structures must be aligned on 32 bit boundaries,
-; since the source and destination of MOVE MEMORY instructions
-; must share the same alignment and this is the alignment of the
-; NCR registers.
-;
-
-; For some systems (MVME166, for example) dmode is always the same, so don't
-; waste time writing it
-
-#if 1
-#define DMODE_MEMORY_TO_NCR
-#define DMODE_MEMORY_TO_MEMORY
-#define DMODE_NCR_TO_MEMORY
-#else
-#define DMODE_MEMORY_TO_NCR MOVE dmode_memory_to_ncr TO DMODE
-#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE
-#define DMODE_NCR_TO_MEMORY MOVE dmode_ncr_to_memory TO DMODE
-#endif
-
-ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa
-ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa
-ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address
- ; for current dsa
-ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target
- ; sync routine
-ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target
- ; sscf value (53c710)
-ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa
-ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
- ; saved data pointer
-ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command
- ; current residual code
-ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
- ; saved residual code
-ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand
-ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to
-ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value
-
-;
-; Once a device has initiated reselection, we need to compare it
-; against the singly linked list of commands which have disconnected
-; and are pending reselection. These commands are maintained in
-; an unordered singly linked list of DSA structures, through the
-; DSA pointers at their 'centers' headed by the reconnect_dsa_head
-; pointer.
-;
-; To avoid complications in removing commands from the list,
-; I minimize the amount of expensive (at eight operations per
-; addition @ 500-600ns each) pointer operations which must
-; be done in the NCR driver by precomputing them on the
-; host processor during dsa structure generation.
-;
-; The fixed-up per DSA code knows how to recognize the nexus
-; associated with the corresponding SCSI command, and modifies
-; the source and destination pointers for the MOVE MEMORY
-; instruction which is executed when reselected_ok is called
-; to remove the command from the list. Similarly, DSA is
-; loaded with the address of the next DSA structure and
-; reselected_check_next is called if a failure occurs.
-;
-; Perhaps more concisely, the net effect of the mess is
-;
-; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head,
-; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
-; src = &dsa->next;
-; if (target_id == dsa->id && target_lun == dsa->lun) {
-; *dest = *src;
-; break;
-; }
-; }
-;
-; if (!dsa)
-; error (int_err_unexpected_reselect);
-; else
-; longjmp (dsa->jump_resume, 0);
-;
-;
-
-#if (CHIP != 700) && (CHIP != 70066)
-; Define DSA structure used for mailboxes
-ENTRY dsa_code_template
-dsa_code_template:
-ENTRY dsa_code_begin
-dsa_code_begin:
-; RGH: Don't care about TEMP and DSA here
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- MOVE MEMORY 4, addr_scratch, saved_dsa
- ; We are about to go and select the device, so must set SSCF bits
- MOVE MEMORY 4, dsa_sscf_710, addr_scratch
-#ifdef BIG_ENDIAN
- MOVE SCRATCH3 TO SFBR
-#else
- MOVE SCRATCH0 TO SFBR
-#endif
- MOVE SFBR TO SBCL
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#else
- CALL scratch_to_dsa
-#endif
- CALL select
-; Handle the phase mismatch which may have resulted from the
-; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN
-; may or may not be necessary, and we should update script_asm.pl
-; to handle multiple pieces.
- CLEAR ATN
- CLEAR ACK
-
-; Replace second operand with address of JUMP instruction dest operand
-; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c.
-ENTRY dsa_code_fix_jump
-dsa_code_fix_jump:
- MOVE MEMORY 4, NOP_insn, 0
- JUMP select_done
-
-; wrong_dsa loads the DSA register with the value of the dsa_next
-; field.
-;
-wrong_dsa:
-#if (CHIP == 710)
-; NOTE DSA is corrupt when we arrive here!
-#endif
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the destination address is the address of the OLD
-; next pointer.
-;
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
- DMODE_MEMORY_TO_NCR
-;
-; Move the _contents_ of the next pointer into the DSA register as
-; the next I_T_L or I_T_L_Q tupple to check against the established
-; nexus.
-;
- MOVE MEMORY 4, dsa_temp_next, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- MOVE MEMORY 4, addr_scratch, saved_dsa
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#else
- CALL scratch_to_dsa
-#endif
- JUMP reselected_check_next
-
-ABSOLUTE dsa_save_data_pointer = 0
-ENTRY dsa_code_save_data_pointer
-dsa_code_save_data_pointer:
-#if (CHIP == 710)
- ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
- ; We MUST return with DSA correct
- MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
- CLEAR ACK
-#ifdef DEBUG
- INT int_debug_saved
-#endif
- MOVE MEMORY 4, saved_dsa, addr_dsa
- JUMP jump_temp
-#else
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer
- DMODE_MEMORY_TO_MEMORY
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
- CLEAR ACK
-#ifdef DEBUG
- INT int_debug_saved
-#endif
- RETURN
-#endif
-ABSOLUTE dsa_restore_pointers = 0
-ENTRY dsa_code_restore_pointers
-dsa_code_restore_pointers:
-#if (CHIP == 710)
- ; TEMP and DSA are corrupt when we get here, but who cares!
- MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
- CLEAR ACK
- ; Restore DSA, note we don't care about TEMP
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#ifdef DEBUG
- INT int_debug_restored
-#endif
- JUMP jump_temp
-#else
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp
- DMODE_MEMORY_TO_MEMORY
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
- CLEAR ACK
-#ifdef DEBUG
- INT int_debug_restored
-#endif
- RETURN
-#endif
-
-ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines whether or not the current target and
-; lun match the current DSA
-ENTRY dsa_code_check_reselect
-dsa_code_check_reselect:
-#if (CHIP == 710)
- /* Arrives here with DSA correct */
- /* Assumes we are always ID 7 */
- MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set
- JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
-#else
- MOVE SSID TO SFBR ; SSID contains 3 bit target ID
-; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
- JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
-#endif
-;
-; Hack - move to scratch first, since SFBR is not writeable
-; via the CPU and hence a MOVE MEMORY instruction.
-;
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 1, reselected_identify, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#ifdef BIG_ENDIAN
- ; BIG ENDIAN ON MVME16x
- MOVE SCRATCH3 TO SFBR
-#else
- MOVE SCRATCH0 TO SFBR
-#endif
-; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
-; Are you sure about that? richard@sleepie.demon.co.uk
- JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the source address is the address of this dsa's
-; next pointer.
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
- CALL reselected_ok
-#if (CHIP == 710)
-; Restore DSA following memory moves in reselected_ok
-; dsa_temp_sync doesn't really care about DSA, but it has an
-; optional debug INT so a valid DSA is a good idea.
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
- CALL dsa_temp_sync
-; Release ACK on the IDENTIFY message _after_ we've set the synchronous
-; transfer parameters!
- CLEAR ACK
-; Implicitly restore pointers on reselection, so a RETURN
-; will transfer control back to the right spot.
- CALL REL (dsa_code_restore_pointers)
- RETURN
-ENTRY dsa_zero
-dsa_zero:
-ENTRY dsa_code_template_end
-dsa_code_template_end:
-
-; Perform sanity check for dsa_fields_start == dsa_code_template_end -
-; dsa_zero, puke.
-
-ABSOLUTE dsa_fields_start = 0 ; Sanity marker
- ; pad 48 bytes (fix this RSN)
-ABSOLUTE dsa_next = 48 ; len 4 Next DSA
- ; del 4 Previous DSA address
-ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread.
-ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for
- ; table indirect select
-ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for
- ; select message
-ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for
- ; command
-ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout
-ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain
-ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin
-ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte
-ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out
- ; (Synchronous transfer negotiation, etc).
-ABSOLUTE dsa_end = 112
-
-ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next),
- ; terminated by a call to JUMP wait_reselect
-
-; Linked lists of DSA structures
-ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect
-ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
- ; address of reconnect_dsa_head
-
-; These select the source and destination of a MOVE MEMORY instruction
-ABSOLUTE dmode_memory_to_memory = 0x0
-ABSOLUTE dmode_memory_to_ncr = 0x0
-ABSOLUTE dmode_ncr_to_memory = 0x0
-
-ABSOLUTE addr_scratch = 0x0
-ABSOLUTE addr_temp = 0x0
-#if (CHIP == 710)
-ABSOLUTE saved_dsa = 0x0
-ABSOLUTE emulfly = 0x0
-ABSOLUTE addr_dsa = 0x0
-#endif
-#endif /* CHIP != 700 && CHIP != 70066 */
-
-; Interrupts -
-; MSB indicates type
-; 0 handle error condition
-; 1 handle message
-; 2 handle normal condition
-; 3 debugging interrupt
-; 4 testing interrupt
-; Next byte indicates specific error
-
-; XXX not yet implemented, I'm not sure if I want to -
-; Next byte indicates the routine the error occurred in
-; The LSB indicates the specific place the error occurred
-
-ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered
-ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED)
-ABSOLUTE int_err_unexpected_reselect = 0x00020000
-ABSOLUTE int_err_check_condition = 0x00030000
-ABSOLUTE int_err_no_phase = 0x00040000
-ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received
-ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received
-ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message
- ; received
-
-ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram
- ; registers.
-ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established
-ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
-ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected
-ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa
-ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset.
-ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly
-ABSOLUTE int_debug_break = 0x03000000 ; Break point
-#ifdef DEBUG
-ABSOLUTE int_debug_scheduled = 0x03010000 ; new I/O scheduled
-ABSOLUTE int_debug_idle = 0x03020000 ; scheduler is idle
-ABSOLUTE int_debug_dsa_loaded = 0x03030000 ; dsa reloaded
-ABSOLUTE int_debug_reselected = 0x03040000 ; NCR reselected
-ABSOLUTE int_debug_head = 0x03050000 ; issue head overwritten
-ABSOLUTE int_debug_disconnected = 0x03060000 ; disconnected
-ABSOLUTE int_debug_disconnect_msg = 0x03070000 ; got message to disconnect
-ABSOLUTE int_debug_dsa_schedule = 0x03080000 ; in dsa_schedule
-ABSOLUTE int_debug_reselect_check = 0x03090000 ; Check for reselection of DSA
-ABSOLUTE int_debug_reselected_ok = 0x030a0000 ; Reselection accepted
-#endif
-ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver
-#ifdef DEBUG
-ABSOLUTE int_debug_saved = 0x030c0000 ; save/restore pointers
-ABSOLUTE int_debug_restored = 0x030d0000
-ABSOLUTE int_debug_sync = 0x030e0000 ; Sanity check synchronous
- ; parameters.
-ABSOLUTE int_debug_datain = 0x030f0000 ; going into data in phase
- ; now.
-ABSOLUTE int_debug_check_dsa = 0x03100000 ; Sanity check DSA against
- ; SDID.
-#endif
-
-ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete
-ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete
-ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete
-
-
-; These should start with 0x05000000, with low bits incrementing for
-; each one.
-
-#ifdef EVENTS
-ABSOLUTE int_EVENT_SELECT = 0
-ABSOLUTE int_EVENT_DISCONNECT = 0
-ABSOLUTE int_EVENT_RESELECT = 0
-ABSOLUTE int_EVENT_COMPLETE = 0
-ABSOLUTE int_EVENT_IDLE = 0
-ABSOLUTE int_EVENT_SELECT_FAILED = 0
-ABSOLUTE int_EVENT_BEFORE_SELECT = 0
-ABSOLUTE int_EVENT_RESELECT_FAILED = 0
-#endif
-
-ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message
-ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message
-ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source
-ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in
-ABSOLUTE NOP_insn = 0 ; NOP instruction
-
-; Pointer to message, potentially multi-byte
-ABSOLUTE msg_buf = 0
-
-; Pointer to holding area for reselection information
-ABSOLUTE reselected_identify = 0
-ABSOLUTE reselected_tag = 0
-
-; Request sense command pointer, it's a 6 byte command, should
-; be constant for all commands since we always want 16 bytes of
-; sense and we don't need to change any fields as we did under
-; SCSI-I when we actually cared about the LUN field.
-;EXTERNAL NCR53c7xx_sense ; Request sense command
-
-#if (CHIP != 700) && (CHIP != 70066)
-; dsa_schedule
-; PURPOSE : after a DISCONNECT message has been received, and pointers
-; saved, insert the current DSA structure at the head of the
-; disconnected queue and fall through to the scheduler.
-;
-; CALLS : OK
-;
-; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
-; of disconnected commands
-;
-; MODIFIES : SCRATCH, reconnect_dsa_head
-;
-; EXITS : always passes control to schedule
-
-ENTRY dsa_schedule
-dsa_schedule:
-#ifdef DEBUG
- INT int_debug_dsa_schedule
-#endif
-
-;
-; Calculate the address of the next pointer within the DSA
-; structure of the command that is currently disconnecting
-;
-#if (CHIP == 710)
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- MOVE SCRATCH0 + dsa_next TO SCRATCH0
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-; Point the next field of this DSA structure at the current disconnected
-; list
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
- DMODE_MEMORY_TO_MEMORY
-dsa_schedule_insert:
- MOVE MEMORY 4, reconnect_dsa_head, 0
-
-; And update the head pointer.
-#if (CHIP == 710)
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
- DMODE_MEMORY_TO_MEMORY
-/* Temporarily, see what happens. */
-#ifndef ORIGINAL
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- CLEAR ACK
-#endif
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
- WAIT DISCONNECT
-#ifdef EVENTS
- INT int_EVENT_DISCONNECT;
-#endif
-#ifdef DEBUG
- INT int_debug_disconnected
-#endif
- JUMP schedule
-#endif
-
-;
-; select
-;
-; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
-; On success, the current DSA structure is removed from the issue
-; queue. Usually, this is entered as a fall-through from schedule,
-; although the contingent allegiance handling code will write
-; the select entry address to the DSP to restart a command as a
-; REQUEST SENSE. A message is sent (usually IDENTIFY, although
-; additional SDTR or WDTR messages may be sent). COMMAND OUT
-; is handled.
-;
-; INPUTS : DSA - SCSI command, issue_dsa_head
-;
-; CALLS : NOT OK
-;
-; MODIFIES : SCRATCH, issue_dsa_head
-;
-; EXITS : on reselection or selection, go to select_failed
-; otherwise, RETURN so control is passed back to
-; dsa_begin.
-;
-
-ENTRY select
-select:
-
-#ifdef EVENTS
- INT int_EVENT_BEFORE_SELECT
-#endif
-
-#ifdef DEBUG
- INT int_debug_scheduled
-#endif
- CLEAR TARGET
-
-; XXX
-;
-; In effect, SELECTION operations are backgrounded, with execution
-; continuing until code which waits for REQ or a fatal interrupt is
-; encountered.
-;
-; So, for more performance, we could overlap the code which removes
-; the command from the NCRs issue queue with the selection, but
-; at this point I don't want to deal with the error recovery.
-;
-
-#if (CHIP != 700) && (CHIP != 70066)
-#if (CHIP == 710)
- ; Enable selection timer
-#ifdef NO_SELECTION_TIMEOUT
- MOVE CTEST7 & 0xff TO CTEST7
-#else
- MOVE CTEST7 & 0xef TO CTEST7
-#endif
-#endif
- SELECT ATN FROM dsa_select, select_failed
- JUMP select_msgout, WHEN MSG_OUT
-ENTRY select_msgout
-select_msgout:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
- MOVE FROM dsa_msgout, WHEN MSG_OUT
-#else
-ENTRY select_msgout
- SELECT ATN 0, select_failed
-select_msgout:
- MOVE 0, 0, WHEN MSGOUT
-#endif
-
-#ifdef EVENTS
- INT int_EVENT_SELECT
-#endif
- RETURN
-
-;
-; select_done
-;
-; PURPOSE: continue on to normal data transfer; called as the exit
-; point from dsa_begin.
-;
-; INPUTS: dsa
-;
-; CALLS: OK
-;
-;
-
-select_done:
-#if (CHIP == 710)
-; NOTE DSA is corrupt when we arrive here!
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-
-#ifdef DEBUG
-ENTRY select_check_dsa
-select_check_dsa:
- INT int_debug_check_dsa
-#endif
-
-; After a successful selection, we should get either a CMD phase or
-; some transfer request negotiation message.
-
- JUMP cmdout, WHEN CMD
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
-
-select_msg_in:
- CALL msg_in, WHEN MSG_IN
- JUMP select_msg_in, WHEN MSG_IN
-
-cmdout:
- INT int_err_unexpected_phase, WHEN NOT CMD
-#if (CHIP == 700)
- INT int_norm_selected
-#endif
-ENTRY cmdout_cmdout
-cmdout_cmdout:
-#if (CHIP != 700) && (CHIP != 70066)
- MOVE FROM dsa_cmdout, WHEN CMD
-#else
- MOVE 0, 0, WHEN CMD
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-
-;
-; data_transfer
-; other_out
-; other_in
-; other_transfer
-;
-; PURPOSE : handle the main data transfer for a SCSI command in
-; several parts. In the first part, data_transfer, DATA_IN
-; and DATA_OUT phases are allowed, with the user provided
-; code (usually dynamically generated based on the scatter/gather
-; list associated with a SCSI command) called to handle these
-; phases.
-;
-; After control has passed to one of the user provided
-; DATA_IN or DATA_OUT routines, back calls are made to
-; other_transfer_in or other_transfer_out to handle non-DATA IN
-; and DATA OUT phases respectively, with the state of the active
-; data pointer being preserved in TEMP.
-;
-; On completion, the user code passes control to other_transfer
-; which causes DATA_IN and DATA_OUT to result in unexpected_phase
-; interrupts so that data overruns may be trapped.
-;
-; INPUTS : DSA - SCSI command
-;
-; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
-; other_transfer
-;
-; MODIFIES : SCRATCH
-;
-; EXITS : if STATUS IN is detected, signifying command completion,
-; the NCR jumps to command_complete. If MSG IN occurs, a
-; CALL is made to msg_in. Otherwise, other_transfer runs in
-; an infinite loop.
-;
-
-ENTRY data_transfer
-data_transfer:
- JUMP cmdout_cmdout, WHEN CMD
- CALL msg_in, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- JUMP do_dataout, WHEN DATA_OUT
- JUMP do_datain, WHEN DATA_IN
- JUMP command_complete, WHEN STATUS
- JUMP data_transfer
-ENTRY end_data_transfer
-end_data_transfer:
-
-;
-; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain
-; should be fixed up whenever the nexus changes so it can point to the
-; correct routine for that command.
-;
-
-#if (CHIP != 700) && (CHIP != 70066)
-; Nasty jump to dsa->dataout
-do_dataout:
-#if (CHIP == 710)
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- MOVE SCRATCH0 + dsa_dataout TO SCRATCH0
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
- DMODE_MEMORY_TO_MEMORY
-dataout_to_jump:
- MOVE MEMORY 4, 0, dataout_jump + 4
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-dataout_jump:
- JUMP 0
-
-; Nasty jump to dsa->dsain
-do_datain:
-#if (CHIP == 710)
- MOVE MEMORY 4, saved_dsa, addr_scratch
-#else
- CALL dsa_to_scratch
-#endif
- MOVE SCRATCH0 + dsa_datain TO SCRATCH0
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
- DMODE_MEMORY_TO_MEMORY
-ENTRY datain_to_jump
-datain_to_jump:
- MOVE MEMORY 4, 0, datain_jump + 4
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-#ifdef DEBUG
- INT int_debug_datain
-#endif
-datain_jump:
- JUMP 0
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-
-
-; Note that other_out and other_in loop until a non-data phase
-; is discovered, so we only execute return statements when we
-; can go on to the next data phase block move statement.
-
-ENTRY other_out
-other_out:
-#if 0
- INT 0x03ffdead
-#endif
- INT int_err_unexpected_phase, WHEN CMD
- JUMP msg_in_restart, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- INT int_err_unexpected_phase, WHEN DATA_IN
- JUMP command_complete, WHEN STATUS
- JUMP other_out, WHEN NOT DATA_OUT
-#if (CHIP == 710)
-; TEMP should be OK, as we got here from a call in the user dataout code.
-#endif
- RETURN
-
-ENTRY other_in
-other_in:
-#if 0
- INT 0x03ffdead
-#endif
- INT int_err_unexpected_phase, WHEN CMD
- JUMP msg_in_restart, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- INT int_err_unexpected_phase, WHEN DATA_OUT
- JUMP command_complete, WHEN STATUS
- JUMP other_in, WHEN NOT DATA_IN
-#if (CHIP == 710)
-; TEMP should be OK, as we got here from a call in the user datain code.
-#endif
- RETURN
-
-
-ENTRY other_transfer
-other_transfer:
- INT int_err_unexpected_phase, WHEN CMD
- CALL msg_in, WHEN MSG_IN
- INT int_err_unexpected_phase, WHEN MSG_OUT
- INT int_err_unexpected_phase, WHEN DATA_OUT
- INT int_err_unexpected_phase, WHEN DATA_IN
- JUMP command_complete, WHEN STATUS
- JUMP other_transfer
-
-;
-; msg_in_restart
-; msg_in
-; munge_msg
-;
-; PURPOSE : process messages from a target. msg_in is called when the
-; caller hasn't read the first byte of the message. munge_message
-; is called when the caller has read the first byte of the message,
-; and left it in SFBR. msg_in_restart is called when the caller
-; hasn't read the first byte of the message, and wishes RETURN
-; to transfer control back to the address of the conditional
-; CALL instruction rather than to the instruction after it.
-;
-; Various int_* interrupts are generated when the host system
-; needs to intervene, as is the case with SDTR, WDTR, and
-; INITIATE RECOVERY messages.
-;
-; When the host system handles one of these interrupts,
-; it can respond by reentering at reject_message,
-; which rejects the message and returns control to
-; the caller of msg_in or munge_msg, accept_message
-; which clears ACK and returns control, or reply_message
-; which sends the message pointed to by the DSA
-; msgout_other table indirect field.
-;
-; DISCONNECT messages are handled by moving the command
-; to the reconnect_dsa_queue.
-#if (CHIP == 710)
-; NOTE: DSA should be valid when we get here - we cannot save both it
-; and TEMP in this routine.
-#endif
-;
-; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
-; only)
-;
-; CALLS : NO. The TEMP register isn't backed up to allow nested calls.
-;
-; MODIFIES : SCRATCH, DSA on DISCONNECT
-;
-; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
-; and normal return from message handlers running under
-; Linux, control is returned to the caller. Receipt
-; of DISCONNECT messages pass control to dsa_schedule.
-;
-ENTRY msg_in_restart
-msg_in_restart:
-; XXX - hackish
-;
-; Since it's easier to debug changes to the statically
-; compiled code, rather than the dynamically generated
-; stuff, such as
-;
-; MOVE x, y, WHEN data_phase
-; CALL other_z, WHEN NOT data_phase
-; MOVE x, y, WHEN data_phase
-;
-; I'd like to have certain routines (notably the message handler)
-; restart on the conditional call rather than the next instruction.
-;
-; So, subtract 8 from the return address
-
- MOVE TEMP0 + 0xf8 TO TEMP0
- MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
- MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
- MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
-
-ENTRY msg_in
-msg_in:
- MOVE 1, msg_buf, WHEN MSG_IN
-
-munge_msg:
- JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE
- JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message
-;
-; XXX - I've seen a handful of broken SCSI devices which fail to issue
-; a SAVE POINTERS message before disconnecting in the middle of
-; a transfer, assuming that the DATA POINTER will be implicitly
-; restored.
-;
-; Historically, I've often done an implicit save when the DISCONNECT
-; message is processed. We may want to consider having the option of
-; doing that here.
-;
- JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER
- JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS
- JUMP munge_disconnect, IF 0x04 ; DISCONNECT
- INT int_msg_1, IF 0x07 ; MESSAGE REJECT
- INT int_msg_1, IF 0x0f ; INITIATE RECOVERY
-#ifdef EVENTS
- INT int_EVENT_SELECT_FAILED
-#endif
- JUMP reject_message
-
-munge_2:
- JUMP reject_message
-;
-; The SCSI standard allows targets to recover from transient
-; error conditions by backing up the data pointer with a
-; RESTORE POINTERS message.
-;
-; So, we must save and restore the _residual_ code as well as
-; the current instruction pointer. Because of this messiness,
-; it is simpler to put dynamic code in the dsa for this and to
-; just do a simple jump down there.
-;
-
-munge_save_data_pointer:
-#if (CHIP == 710)
- ; We have something in TEMP here, so first we must save that
- MOVE TEMP0 TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE TEMP1 TO SFBR
- MOVE SFBR TO SCRATCH1
- MOVE TEMP2 TO SFBR
- MOVE SFBR TO SCRATCH2
- MOVE TEMP3 TO SFBR
- MOVE SFBR TO SCRATCH3
- MOVE MEMORY 4, addr_scratch, jump_temp + 4
- ; Now restore DSA
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
- MOVE DSA0 + dsa_save_data_pointer TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH1
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH2
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH3
-
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
- DMODE_MEMORY_TO_MEMORY
-jump_dsa_save:
- JUMP 0
-
-munge_restore_pointers:
-#if (CHIP == 710)
- ; The code at dsa_restore_pointers will RETURN, but we don't care
- ; about TEMP here, as it will overwrite it anyway.
-#endif
- MOVE DSA0 + dsa_restore_pointers TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH1
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH2
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
- MOVE SFBR TO SCRATCH3
-
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
- DMODE_MEMORY_TO_MEMORY
-jump_dsa_restore:
- JUMP 0
-
-
-munge_disconnect:
-#ifdef DEBUG
- INT int_debug_disconnect_msg
-#endif
-
-/*
- * Before, we overlapped processing with waiting for disconnect, but
- * debugging was beginning to appear messy. Temporarily move things
- * to just before the WAIT DISCONNECT.
- */
-
-#ifdef ORIGINAL
-#if (CHIP == 710)
-; Following clears Unexpected Disconnect bit. What do we do?
-#else
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- CLEAR ACK
-#endif
-
-#if (CHIP != 700) && (CHIP != 70066)
- JUMP dsa_schedule
-#else
- WAIT DISCONNECT
- INT int_norm_disconnected
-#endif
-
-munge_extended:
- CLEAR ACK
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
- MOVE 1, msg_buf + 1, WHEN MSG_IN
- JUMP munge_extended_2, IF 0x02
- JUMP munge_extended_3, IF 0x03
- JUMP reject_message
-
-munge_extended_2:
- CLEAR ACK
- MOVE 1, msg_buf + 2, WHEN MSG_IN
- JUMP reject_message, IF NOT 0x02 ; Must be WDTR
- CLEAR ACK
- MOVE 1, msg_buf + 3, WHEN MSG_IN
- INT int_msg_wdtr
-
-munge_extended_3:
- CLEAR ACK
- MOVE 1, msg_buf + 2, WHEN MSG_IN
- JUMP reject_message, IF NOT 0x01 ; Must be SDTR
- CLEAR ACK
- MOVE 2, msg_buf + 3, WHEN MSG_IN
- INT int_msg_sdtr
-
-ENTRY reject_message
-reject_message:
- SET ATN
- CLEAR ACK
- MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
- RETURN
-
-ENTRY accept_message
-accept_message:
- CLEAR ATN
- CLEAR ACK
- RETURN
-
-ENTRY respond_message
-respond_message:
- SET ATN
- CLEAR ACK
- MOVE FROM dsa_msgout_other, WHEN MSG_OUT
- RETURN
-
-;
-; command_complete
-;
-; PURPOSE : handle command termination when STATUS IN is detected by reading
-; a status byte followed by a command termination message.
-;
-; Normal termination results in an INTFLY instruction, and
-; the host system can pick out which command terminated by
-; examining the MESSAGE and STATUS buffers of all currently
-; executing commands;
-;
-; Abnormal (CHECK_CONDITION) termination results in an
-; int_err_check_condition interrupt so that a REQUEST SENSE
-; command can be issued out-of-order so that no other command
-; clears the contingent allegiance condition.
-;
-;
-; INPUTS : DSA - command
-;
-; CALLS : OK
-;
-; EXITS : On successful termination, control is passed to schedule.
-; On abnormal termination, the user will usually modify the
-; DSA fields and corresponding buffers and return control
-; to select.
-;
-
-ENTRY command_complete
-command_complete:
- MOVE FROM dsa_status, WHEN STATUS
-#if (CHIP != 700) && (CHIP != 70066)
- MOVE SFBR TO SCRATCH0 ; Save status
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-ENTRY command_complete_msgin
-command_complete_msgin:
- MOVE FROM dsa_msgin, WHEN MSG_IN
-; Indicate that we should be expecting a disconnect
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#else
- ; Above code cleared the Unexpected Disconnect bit, what do we do?
-#endif
- CLEAR ACK
-#if (CHIP != 700) && (CHIP != 70066)
- WAIT DISCONNECT
-
-;
-; The SCSI specification states that when a UNIT ATTENTION condition
-; is pending, as indicated by a CHECK CONDITION status message,
-; the target shall revert to asynchronous transfers. Since
-; synchronous transfers parameters are maintained on a per INITIATOR/TARGET
-; basis, and returning control to our scheduler could work on a command
-; running on another lun on that target using the old parameters, we must
-; interrupt the host processor to get them changed, or change them ourselves.
-;
-; Once SCSI-II tagged queueing is implemented, things will be even more
-; hairy, since contingent allegiance conditions exist on a per-target/lun
-; basis, and issuing a new command with a different tag would clear it.
-; In these cases, we must interrupt the host processor to get a request
-; added to the HEAD of the queue with the request sense command, or we
-; must automatically issue the request sense command.
-
-#if 0
- MOVE SCRATCH0 TO SFBR
- JUMP command_failed, IF 0x02
-#endif
-#if (CHIP == 710)
-#if defined(MVME16x_INTFLY)
-; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software
-; interrupt (SW7). We can use SCRATCH, as we are about to jump to
-; schedule, which corrupts it anyway. Will probably remove this later,
-; but want to check performance effects first.
-
-#define INTFLY_ADDR 0xfff40070
-
- MOVE 0 TO SCRATCH0
- MOVE 0x80 TO SCRATCH1
- MOVE 0 TO SCRATCH2
- MOVE 0 TO SCRATCH3
- MOVE MEMORY 4, addr_scratch, INTFLY_ADDR
-#else
- INT int_norm_emulateintfly
-#endif
-#else
- INTFLY
-#endif
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-#ifdef EVENTS
- INT int_EVENT_COMPLETE
-#endif
-#if (CHIP != 700) && (CHIP != 70066)
- JUMP schedule
-command_failed:
- INT int_err_check_condition
-#else
- INT int_norm_command_complete
-#endif
-
-;
-; wait_reselect
-;
-; PURPOSE : This is essentially the idle routine, where control lands
-; when there are no new processes to schedule. wait_reselect
-; waits for reselection, selection, and new commands.
-;
-; When a successful reselection occurs, with the aid
-; of fixed up code in each DSA, wait_reselect walks the
-; reconnect_dsa_queue, asking each dsa if the target ID
-; and LUN match its.
-;
-; If a match is found, a call is made back to reselected_ok,
-; which through the miracles of self modifying code, extracts
-; the found DSA from the reconnect_dsa_queue and then
-; returns control to the DSAs thread of execution.
-;
-; INPUTS : NONE
-;
-; CALLS : OK
-;
-; MODIFIES : DSA,
-;
-; EXITS : On successful reselection, control is returned to the
-; DSA which called reselected_ok. If the WAIT RESELECT
-; was interrupted by a new commands arrival signaled by
-; SIG_P, control is passed to schedule. If the NCR is
-; selected, the host system is interrupted with an
-; int_err_selected which is usually responded to by
-; setting DSP to the target_abort address.
-
-ENTRY wait_reselect
-wait_reselect:
-#ifdef EVENTS
- int int_EVENT_IDLE
-#endif
-#ifdef DEBUG
- int int_debug_idle
-#endif
- WAIT RESELECT wait_reselect_failed
-
-reselected:
-#ifdef EVENTS
- int int_EVENT_RESELECT
-#endif
- CLEAR TARGET
- DMODE_MEMORY_TO_MEMORY
- ; Read all data needed to reestablish the nexus -
- MOVE 1, reselected_identify, WHEN MSG_IN
- ; We used to CLEAR ACK here.
-#if (CHIP != 700) && (CHIP != 70066)
-#ifdef DEBUG
- int int_debug_reselected
-#endif
-
- ; Point DSA at the current head of the disconnected queue.
- DMODE_MEMORY_TO_NCR
- MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- MOVE MEMORY 4, addr_scratch, saved_dsa
-#else
- CALL scratch_to_dsa
-#endif
-
- ; Fix the update-next pointer so that the reconnect_dsa_head
- ; pointer is the one that will be updated if this DSA is a hit
- ; and we remove it from the queue.
-
- MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-
-ENTRY reselected_check_next
-reselected_check_next:
-#ifdef DEBUG
- INT int_debug_reselect_check
-#endif
- ; Check for a NULL pointer.
- MOVE DSA0 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- MOVE DSA1 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- MOVE DSA2 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- MOVE DSA3 TO SFBR
- JUMP reselected_not_end, IF NOT 0
- INT int_err_unexpected_reselect
-
-reselected_not_end:
- ;
- ; XXX the ALU is only eight bits wide, and the assembler
- ; wont do the dirt work for us. As long as dsa_check_reselect
- ; is negative, we need to sign extend with 1 bits to the full
- ; 32 bit width of the address.
- ;
- ; A potential work around would be to have a known alignment
- ; of the DSA structure such that the base address plus
- ; dsa_check_reselect doesn't require carrying from bytes
- ; higher than the LSB.
- ;
-
- MOVE DSA0 TO SFBR
- MOVE SFBR + dsa_check_reselect TO SCRATCH0
- MOVE DSA1 TO SFBR
- MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
- MOVE DSA2 TO SFBR
- MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
- MOVE DSA3 TO SFBR
- MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
-
- DMODE_NCR_TO_MEMORY
- MOVE MEMORY 4, addr_scratch, reselected_check + 4
- DMODE_MEMORY_TO_MEMORY
-#if (CHIP == 710)
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-#endif
-reselected_check:
- JUMP 0
-
-
-;
-;
-#if (CHIP == 710)
-; We have problems here - the memory move corrupts TEMP and DSA. This
-; routine is called from DSA code, and patched from many places. Scratch
-; is probably free when it is called.
-; We have to:
-; copy temp to scratch, one byte at a time
-; write scratch to patch a jump in place of the return
-; do the move memory
-; jump to the patched in return address
-; DSA is corrupt when we get here, and can be left corrupt
-
-ENTRY reselected_ok
-reselected_ok:
- MOVE TEMP0 TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE TEMP1 TO SFBR
- MOVE SFBR TO SCRATCH1
- MOVE TEMP2 TO SFBR
- MOVE SFBR TO SCRATCH2
- MOVE TEMP3 TO SFBR
- MOVE SFBR TO SCRATCH3
- MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
-reselected_ok_patch:
- MOVE MEMORY 4, 0, 0
-reselected_ok_jump:
- JUMP 0
-#else
-ENTRY reselected_ok
-reselected_ok:
-reselected_ok_patch:
- MOVE MEMORY 4, 0, 0 ; Patched : first word
- ; is address of
- ; successful dsa_next
- ; Second word is last
- ; unsuccessful dsa_next,
- ; starting with
- ; dsa_reconnect_head
- ; We used to CLEAR ACK here.
-#ifdef DEBUG
- INT int_debug_reselected_ok
-#endif
-#ifdef DEBUG
- INT int_debug_check_dsa
-#endif
- RETURN ; Return control to where
-#endif
-#else
- INT int_norm_reselected
-#endif /* (CHIP != 700) && (CHIP != 70066) */
-
-selected:
- INT int_err_selected;
-
-;
-; A select or reselect failure can be caused by one of two conditions :
-; 1. SIG_P was set. This will be the case if the user has written
-; a new value to a previously NULL head of the issue queue.
-;
-; 2. The NCR53c810 was selected or reselected by another device.
-;
-; 3. The bus was already busy since we were selected or reselected
-; before starting the command.
-
-wait_reselect_failed:
-#ifdef EVENTS
- INT int_EVENT_RESELECT_FAILED
-#endif
-; Check selected bit.
-#if (CHIP == 710)
- ; Must work out how to tell if we are selected....
-#else
- MOVE SIST0 & 0x20 TO SFBR
- JUMP selected, IF 0x20
-#endif
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
- JUMP schedule, IF 0x40
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
- MOVE ISTAT & 0x08 TO SFBR
- JUMP reselected, IF 0x08
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-#if 0
- JUMP schedule
-#else
- INT int_debug_panic
-#endif
-
-
-select_failed:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
-#ifdef EVENTS
- int int_EVENT_SELECT_FAILED
-#endif
-; Otherwise, mask the selected and reselected bits off SIST0
-#if (CHIP ==710)
- ; Let's assume we don't get selected for now
- MOVE SSTAT0 & 0x10 TO SFBR
-#else
- MOVE SIST0 & 0x30 TO SFBR
- JUMP selected, IF 0x20
-#endif
- JUMP reselected, IF 0x10
-; If SIGP is set, the user just gave us another command, and
-; we should restart or return to the scheduler.
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
- JUMP select, IF 0x40
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
-; FIXME: is this really necessary?
- MOVE ISTAT & 0x08 TO SFBR
- JUMP reselected, IF 0x08
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-#if 0
- JUMP schedule
-#else
- INT int_debug_panic
-#endif
-
-;
-; test_1
-; test_2
-;
-; PURPOSE : run some verification tests on the NCR. test_1
-; copies test_src to test_dest and interrupts the host
-; processor, testing for cache coherency and interrupt
-; problems in the processes.
-;
-; test_2 runs a command with offsets relative to the
-; DSA on entry, and is useful for miscellaneous experimentation.
-;
-
-; Verify that interrupts are working correctly and that we don't
-; have a cache invalidation problem.
-
-ABSOLUTE test_src = 0, test_dest = 0
-ENTRY test_1
-test_1:
- MOVE MEMORY 4, test_src, test_dest
- INT int_test_1
-
-;
-; Run arbitrary commands, with test code establishing a DSA
-;
-
-ENTRY test_2
-test_2:
- CLEAR TARGET
-#if (CHIP == 710)
- ; Enable selection timer
-#ifdef NO_SELECTION_TIMEOUT
- MOVE CTEST7 & 0xff TO CTEST7
-#else
- MOVE CTEST7 & 0xef TO CTEST7
-#endif
-#endif
- SELECT ATN FROM 0, test_2_fail
- JUMP test_2_msgout, WHEN MSG_OUT
-ENTRY test_2_msgout
-test_2_msgout:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
- MOVE FROM 8, WHEN MSG_OUT
- MOVE FROM 16, WHEN CMD
- MOVE FROM 24, WHEN DATA_IN
- MOVE FROM 32, WHEN STATUS
- MOVE FROM 40, WHEN MSG_IN
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- CLEAR ACK
- WAIT DISCONNECT
-test_2_fail:
-#if (CHIP == 710)
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-#endif
- INT int_test_2
-
-ENTRY debug_break
-debug_break:
- INT int_debug_break
-
-;
-; initiator_abort
-; target_abort
-;
-; PURPOSE : Abort the currently established nexus from with initiator
-; or target mode.
-;
-;
-
-ENTRY target_abort
-target_abort:
- SET TARGET
- DISCONNECT
- CLEAR TARGET
- JUMP schedule
-
-ENTRY initiator_abort
-initiator_abort:
- SET ATN
-;
-; The SCSI-I specification says that targets may go into MSG out at
-; their leisure upon receipt of the ATN single. On all versions of the
-; specification, we can't change phases until REQ transitions true->false,
-; so we need to sink/source one byte of data to allow the transition.
-;
-; For the sake of safety, we'll only source one byte of data in all
-; cases, but to accommodate the SCSI-I dain bramage, we'll sink an
-; arbitrary number of bytes.
- JUMP spew_cmd, WHEN CMD
- JUMP eat_msgin, WHEN MSG_IN
- JUMP eat_datain, WHEN DATA_IN
- JUMP eat_status, WHEN STATUS
- JUMP spew_dataout, WHEN DATA_OUT
- JUMP sated
-spew_cmd:
- MOVE 1, NCR53c7xx_zero, WHEN CMD
- JUMP sated
-eat_msgin:
- MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
- JUMP eat_msgin, WHEN MSG_IN
- JUMP sated
-eat_status:
- MOVE 1, NCR53c7xx_sink, WHEN STATUS
- JUMP eat_status, WHEN STATUS
- JUMP sated
-eat_datain:
- MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
- JUMP eat_datain, WHEN DATA_IN
- JUMP sated
-spew_dataout:
- MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
-sated:
-#if (CHIP != 710)
- MOVE SCNTL2 & 0x7f TO SCNTL2
-#endif
- MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
- WAIT DISCONNECT
- INT int_norm_aborted
-
-#if (CHIP != 710)
-;
-; dsa_to_scratch
-; scratch_to_dsa
-;
-; PURPOSE :
-; The NCR chips cannot do a move memory instruction with the DSA register
-; as the source or destination. So, we provide a couple of subroutines
-; that let us switch between the DSA register and scratch register.
-;
-; Memory moves to/from the DSPS register also don't work, but we
-; don't use them.
-;
-;
-
-
-dsa_to_scratch:
- MOVE DSA0 TO SFBR
- MOVE SFBR TO SCRATCH0
- MOVE DSA1 TO SFBR
- MOVE SFBR TO SCRATCH1
- MOVE DSA2 TO SFBR
- MOVE SFBR TO SCRATCH2
- MOVE DSA3 TO SFBR
- MOVE SFBR TO SCRATCH3
- RETURN
-
-scratch_to_dsa:
- MOVE SCRATCH0 TO SFBR
- MOVE SFBR TO DSA0
- MOVE SCRATCH1 TO SFBR
- MOVE SFBR TO DSA1
- MOVE SCRATCH2 TO SFBR
- MOVE SFBR TO DSA2
- MOVE SCRATCH3 TO SFBR
- MOVE SFBR TO DSA3
- RETURN
-#endif
-
-#if (CHIP == 710)
-; Little patched jump, used to overcome problems with TEMP getting
-; corrupted on memory moves.
-
-jump_temp:
- JUMP 0
-#endif
diff --git a/drivers/scsi/53c7xx_d.h_shipped b/drivers/scsi/53c7xx_d.h_shipped
deleted file mode 100644
index 21d31b08ec31..000000000000
--- a/drivers/scsi/53c7xx_d.h_shipped
+++ /dev/null
@@ -1,2874 +0,0 @@
-/* DO NOT EDIT - Generated automatically by script_asm.pl */
-static u32 SCRIPT[] = {
-/*
-
-
-
-
-
-; 53c710 driver. Modified from Drew Eckhardts driver
-; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
-;
-; I have left the script for the 53c8xx family in here, as it is likely
-; to be useful to see what I changed when bug hunting.
-
-; NCR 53c810 driver, main script
-; Sponsored by
-; iX Multiuser Multitasking Magazine
-; hm@ix.de
-;
-; Copyright 1993, 1994, 1995 Drew Eckhardt
-; Visionary Computing
-; (Unix and Linux consulting and custom programming)
-; drew@PoohSticks.ORG
-; +1 (303) 786-7975
-;
-; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
-;
-; PRE-ALPHA
-;
-; For more information, please consult
-;
-; NCR 53C810
-; PCI-SCSI I/O Processor
-; Data Manual
-;
-; NCR 53C710
-; SCSI I/O Processor
-; Programmers Guide
-;
-; NCR Microelectronics
-; 1635 Aeroplaza Drive
-; Colorado Springs, CO 80916
-; 1+ (719) 578-3400
-;
-; Toll free literature number
-; +1 (800) 334-5454
-;
-; IMPORTANT : This code is self modifying due to the limitations of
-; the NCR53c7,8xx series chips. Persons debugging this code with
-; the remote debugger should take this into account, and NOT set
-; breakpoints in modified instructions.
-;
-; Design:
-; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard
-; microcontroller using a simple instruction set.
-;
-; So, to minimize the effects of interrupt latency, and to maximize
-; throughput, this driver offloads the practical maximum amount
-; of processing to the SCSI chip while still maintaining a common
-; structure.
-;
-; Where tradeoffs were needed between efficiency on the older
-; chips and the newer NCR53c800 series, the NCR53c800 series
-; was chosen.
-;
-; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
-; automate SCSI transfers without host processor intervention, this
-; isn't the case with the NCR53c710 and newer chips which allow
-;
-; - reads and writes to the internal registers from within the SCSI
-; scripts, allowing the SCSI SCRIPTS(tm) code to save processor
-; state so that multiple threads of execution are possible, and also
-; provide an ALU for loop control, etc.
-;
-; - table indirect addressing for some instructions. This allows
-; pointers to be located relative to the DSA ((Data Structure
-; Address) register.
-;
-; These features make it possible to implement a mailbox style interface,
-; where the same piece of code is run to handle I/O for multiple threads
-; at once minimizing our need to relocate code. Since the NCR53c700/
-; NCR53c800 series have a unique combination of features, making a
-; a standard ingoing/outgoing mailbox system, costly, I've modified it.
-;
-; - Mailboxes are a mixture of code and data. This lets us greatly
-; simplify the NCR53c810 code and do things that would otherwise
-; not be possible.
-;
-; The saved data pointer is now implemented as follows :
-;
-; Control flow has been architected such that if control reaches
-; munge_save_data_pointer, on a restore pointers message or
-; reconnection, a jump to the address formerly in the TEMP register
-; will allow the SCSI command to resume execution.
-;
-
-;
-; Note : the DSA structures must be aligned on 32 bit boundaries,
-; since the source and destination of MOVE MEMORY instructions
-; must share the same alignment and this is the alignment of the
-; NCR registers.
-;
-
-; For some systems (MVME166, for example) dmode is always the same, so don't
-; waste time writing it
-
-
-
-
-
-
-
-
-
-
-
-ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa
-ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa
-ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address
- ; for current dsa
-ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target
- ; sync routine
-ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target
- ; sscf value (53c710)
-ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa
-ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
- ; saved data pointer
-ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command
- ; current residual code
-ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
- ; saved residual code
-ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand
-ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to
-ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value
-
-;
-; Once a device has initiated reselection, we need to compare it
-; against the singly linked list of commands which have disconnected
-; and are pending reselection. These commands are maintained in
-; an unordered singly linked list of DSA structures, through the
-; DSA pointers at their 'centers' headed by the reconnect_dsa_head
-; pointer.
-;
-; To avoid complications in removing commands from the list,
-; I minimize the amount of expensive (at eight operations per
-; addition @ 500-600ns each) pointer operations which must
-; be done in the NCR driver by precomputing them on the
-; host processor during dsa structure generation.
-;
-; The fixed-up per DSA code knows how to recognize the nexus
-; associated with the corresponding SCSI command, and modifies
-; the source and destination pointers for the MOVE MEMORY
-; instruction which is executed when reselected_ok is called
-; to remove the command from the list. Similarly, DSA is
-; loaded with the address of the next DSA structure and
-; reselected_check_next is called if a failure occurs.
-;
-; Perhaps more concisely, the net effect of the mess is
-;
-; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head,
-; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
-; src = &dsa->next;
-; if (target_id == dsa->id && target_lun == dsa->lun) {
-; *dest = *src;
-; break;
-; }
-; }
-;
-; if (!dsa)
-; error (int_err_unexpected_reselect);
-; else
-; longjmp (dsa->jump_resume, 0);
-;
-;
-
-
-; Define DSA structure used for mailboxes
-ENTRY dsa_code_template
-dsa_code_template:
-ENTRY dsa_code_begin
-dsa_code_begin:
-; RGH: Don't care about TEMP and DSA here
-
- MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
-
-at 0x00000000 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, saved_dsa
-
-at 0x00000003 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- ; We are about to go and select the device, so must set SSCF bits
- MOVE MEMORY 4, dsa_sscf_710, addr_scratch
-
-at 0x00000006 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- MOVE SCRATCH3 TO SFBR
-
-at 0x00000009 : */ 0x72370000,0x00000000,
-/*
-
-
-
- MOVE SFBR TO SBCL
-
-at 0x0000000b : */ 0x6a0b0000,0x00000000,
-/*
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000000d : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- CALL select
-
-at 0x00000010 : */ 0x88080000,0x000001f8,
-/*
-; Handle the phase mismatch which may have resulted from the
-; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN
-; may or may not be necessary, and we should update script_asm.pl
-; to handle multiple pieces.
- CLEAR ATN
-
-at 0x00000012 : */ 0x60000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x00000014 : */ 0x60000040,0x00000000,
-/*
-
-; Replace second operand with address of JUMP instruction dest operand
-; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c.
-ENTRY dsa_code_fix_jump
-dsa_code_fix_jump:
- MOVE MEMORY 4, NOP_insn, 0
-
-at 0x00000016 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- JUMP select_done
-
-at 0x00000019 : */ 0x80080000,0x00000230,
-/*
-
-; wrong_dsa loads the DSA register with the value of the dsa_next
-; field.
-;
-wrong_dsa:
-
-; NOTE DSA is corrupt when we arrive here!
-
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the destination address is the address of the OLD
-; next pointer.
-;
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
-
-at 0x0000001b : */ 0xc0000004,0x00000000,0x000007ec,
-/*
-
-;
-; Move the _contents_ of the next pointer into the DSA register as
-; the next I_T_L or I_T_L_Q tupple to check against the established
-; nexus.
-;
- MOVE MEMORY 4, dsa_temp_next, addr_scratch
-
-at 0x0000001e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, saved_dsa
-
-at 0x00000021 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000024 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- JUMP reselected_check_next
-
-at 0x00000027 : */ 0x80080000,0x000006f0,
-/*
-
-ABSOLUTE dsa_save_data_pointer = 0
-ENTRY dsa_code_save_data_pointer
-dsa_code_save_data_pointer:
-
- ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
- ; We MUST return with DSA correct
- MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
-
-at 0x00000029 : */ 0xc0000004,0x000009c8,0x00000000,
-/*
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
-
-at 0x0000002c : */ 0xc0000018,0x00000000,0x00000000,
-/*
- CLEAR ACK
-
-at 0x0000002f : */ 0x60000040,0x00000000,
-/*
-
-
-
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000031 : */ 0xc0000004,0x00000000,0x00000000,
-/*
- JUMP jump_temp
-
-at 0x00000034 : */ 0x80080000,0x000009c4,
-/*
-
-ABSOLUTE dsa_restore_pointers = 0
-ENTRY dsa_code_restore_pointers
-dsa_code_restore_pointers:
-
- ; TEMP and DSA are corrupt when we get here, but who cares!
- MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
-
-at 0x00000036 : */ 0xc0000004,0x00000000,0x000009c8,
-/*
-; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
- MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
-
-at 0x00000039 : */ 0xc0000018,0x00000000,0x00000000,
-/*
- CLEAR ACK
-
-at 0x0000003c : */ 0x60000040,0x00000000,
-/*
- ; Restore DSA, note we don't care about TEMP
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000003e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- JUMP jump_temp
-
-at 0x00000041 : */ 0x80080000,0x000009c4,
-/*
-
-
-ABSOLUTE dsa_check_reselect = 0
-; dsa_check_reselect determines whether or not the current target and
-; lun match the current DSA
-ENTRY dsa_code_check_reselect
-dsa_code_check_reselect:
-
-
-
- MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set
-
-at 0x00000043 : */ 0x72230000,0x00000000,
-/*
- JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
-
-at 0x00000045 : */ 0x80848000,0x00ffff50,
-/*
-
-
-
-
-
-;
-; Hack - move to scratch first, since SFBR is not writeable
-; via the CPU and hence a MOVE MEMORY instruction.
-;
-
- MOVE MEMORY 1, reselected_identify, addr_scratch
-
-at 0x00000047 : */ 0xc0000001,0x00000000,0x00000000,
-/*
-
-
- ; BIG ENDIAN ON MVME16x
- MOVE SCRATCH3 TO SFBR
-
-at 0x0000004a : */ 0x72370000,0x00000000,
-/*
-
-
-
-; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
-; Are you sure about that? richard@sleepie.demon.co.uk
- JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
-
-at 0x0000004c : */ 0x8084f800,0x00ffff34,
-/*
-; Patch the MOVE MEMORY INSTRUCTION such that
-; the source address is the address of this dsa's
-; next pointer.
- MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
-
-at 0x0000004e : */ 0xc0000004,0x00000000,0x000007e8,
-/*
- CALL reselected_ok
-
-at 0x00000051 : */ 0x88080000,0x00000798,
-/*
-
-; Restore DSA following memory moves in reselected_ok
-; dsa_temp_sync doesn't really care about DSA, but it has an
-; optional debug INT so a valid DSA is a good idea.
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000053 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- CALL dsa_temp_sync
-
-at 0x00000056 : */ 0x88080000,0x00000000,
-/*
-; Release ACK on the IDENTIFY message _after_ we've set the synchronous
-; transfer parameters!
- CLEAR ACK
-
-at 0x00000058 : */ 0x60000040,0x00000000,
-/*
-; Implicitly restore pointers on reselection, so a RETURN
-; will transfer control back to the right spot.
- CALL REL (dsa_code_restore_pointers)
-
-at 0x0000005a : */ 0x88880000,0x00ffff68,
-/*
- RETURN
-
-at 0x0000005c : */ 0x90080000,0x00000000,
-/*
-ENTRY dsa_zero
-dsa_zero:
-ENTRY dsa_code_template_end
-dsa_code_template_end:
-
-; Perform sanity check for dsa_fields_start == dsa_code_template_end -
-; dsa_zero, puke.
-
-ABSOLUTE dsa_fields_start = 0 ; Sanity marker
- ; pad 48 bytes (fix this RSN)
-ABSOLUTE dsa_next = 48 ; len 4 Next DSA
- ; del 4 Previous DSA address
-ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread.
-ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for
- ; table indirect select
-ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for
- ; select message
-ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for
- ; command
-ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout
-ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain
-ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin
-ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte
-ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out
- ; (Synchronous transfer negotiation, etc).
-ABSOLUTE dsa_end = 112
-
-ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next),
- ; terminated by a call to JUMP wait_reselect
-
-; Linked lists of DSA structures
-ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect
-ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
- ; address of reconnect_dsa_head
-
-; These select the source and destination of a MOVE MEMORY instruction
-ABSOLUTE dmode_memory_to_memory = 0x0
-ABSOLUTE dmode_memory_to_ncr = 0x0
-ABSOLUTE dmode_ncr_to_memory = 0x0
-
-ABSOLUTE addr_scratch = 0x0
-ABSOLUTE addr_temp = 0x0
-
-ABSOLUTE saved_dsa = 0x0
-ABSOLUTE emulfly = 0x0
-ABSOLUTE addr_dsa = 0x0
-
-
-
-; Interrupts -
-; MSB indicates type
-; 0 handle error condition
-; 1 handle message
-; 2 handle normal condition
-; 3 debugging interrupt
-; 4 testing interrupt
-; Next byte indicates specific error
-
-; XXX not yet implemented, I'm not sure if I want to -
-; Next byte indicates the routine the error occurred in
-; The LSB indicates the specific place the error occurred
-
-ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered
-ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED)
-ABSOLUTE int_err_unexpected_reselect = 0x00020000
-ABSOLUTE int_err_check_condition = 0x00030000
-ABSOLUTE int_err_no_phase = 0x00040000
-ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received
-ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received
-ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message
- ; received
-
-ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram
- ; registers.
-ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established
-ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
-ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected
-ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa
-ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset.
-ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly
-ABSOLUTE int_debug_break = 0x03000000 ; Break point
-
-ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver
-
-
-ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete
-ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete
-ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete
-
-
-; These should start with 0x05000000, with low bits incrementing for
-; each one.
-
-
-
-ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message
-ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message
-ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source
-ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in
-ABSOLUTE NOP_insn = 0 ; NOP instruction
-
-; Pointer to message, potentially multi-byte
-ABSOLUTE msg_buf = 0
-
-; Pointer to holding area for reselection information
-ABSOLUTE reselected_identify = 0
-ABSOLUTE reselected_tag = 0
-
-; Request sense command pointer, it's a 6 byte command, should
-; be constant for all commands since we always want 16 bytes of
-; sense and we don't need to change any fields as we did under
-; SCSI-I when we actually cared about the LUN field.
-;EXTERNAL NCR53c7xx_sense ; Request sense command
-
-
-; dsa_schedule
-; PURPOSE : after a DISCONNECT message has been received, and pointers
-; saved, insert the current DSA structure at the head of the
-; disconnected queue and fall through to the scheduler.
-;
-; CALLS : OK
-;
-; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
-; of disconnected commands
-;
-; MODIFIES : SCRATCH, reconnect_dsa_head
-;
-; EXITS : always passes control to schedule
-
-ENTRY dsa_schedule
-dsa_schedule:
-
-
-
-
-;
-; Calculate the address of the next pointer within the DSA
-; structure of the command that is currently disconnecting
-;
-
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x0000005e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- MOVE SCRATCH0 + dsa_next TO SCRATCH0
-
-at 0x00000061 : */ 0x7e343000,0x00000000,
-/*
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
-
-at 0x00000063 : */ 0x7f350000,0x00000000,
-/*
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
-
-at 0x00000065 : */ 0x7f360000,0x00000000,
-/*
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-at 0x00000067 : */ 0x7f370000,0x00000000,
-/*
-
-; Point the next field of this DSA structure at the current disconnected
-; list
-
- MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
-
-at 0x00000069 : */ 0xc0000004,0x00000000,0x000001b8,
-/*
-
-dsa_schedule_insert:
- MOVE MEMORY 4, reconnect_dsa_head, 0
-
-at 0x0000006c : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-; And update the head pointer.
-
- ; Read what should be the current DSA from memory - actual DSA
- ; register is probably corrupt
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x0000006f : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
- MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
-
-at 0x00000072 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-
-
- CLEAR ACK
-
-at 0x00000075 : */ 0x60000040,0x00000000,
-/*
-
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x00000077 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- WAIT DISCONNECT
-
-at 0x0000007a : */ 0x48000000,0x00000000,
-/*
-
-
-
-
-
-
- JUMP schedule
-
-at 0x0000007c : */ 0x80080000,0x00000000,
-/*
-
-
-;
-; select
-;
-; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
-; On success, the current DSA structure is removed from the issue
-; queue. Usually, this is entered as a fall-through from schedule,
-; although the contingent allegiance handling code will write
-; the select entry address to the DSP to restart a command as a
-; REQUEST SENSE. A message is sent (usually IDENTIFY, although
-; additional SDTR or WDTR messages may be sent). COMMAND OUT
-; is handled.
-;
-; INPUTS : DSA - SCSI command, issue_dsa_head
-;
-; CALLS : NOT OK
-;
-; MODIFIES : SCRATCH, issue_dsa_head
-;
-; EXITS : on reselection or selection, go to select_failed
-; otherwise, RETURN so control is passed back to
-; dsa_begin.
-;
-
-ENTRY select
-select:
-
-
-
-
-
-
-
-
- CLEAR TARGET
-
-at 0x0000007e : */ 0x60000200,0x00000000,
-/*
-
-; XXX
-;
-; In effect, SELECTION operations are backgrounded, with execution
-; continuing until code which waits for REQ or a fatal interrupt is
-; encountered.
-;
-; So, for more performance, we could overlap the code which removes
-; the command from the NCRs issue queue with the selection, but
-; at this point I don't want to deal with the error recovery.
-;
-
-
-
- ; Enable selection timer
-
-
-
- MOVE CTEST7 & 0xef TO CTEST7
-
-at 0x00000080 : */ 0x7c1bef00,0x00000000,
-/*
-
-
- SELECT ATN FROM dsa_select, select_failed
-
-at 0x00000082 : */ 0x4300003c,0x00000828,
-/*
- JUMP select_msgout, WHEN MSG_OUT
-
-at 0x00000084 : */ 0x860b0000,0x00000218,
-/*
-ENTRY select_msgout
-select_msgout:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x00000086 : */ 0x7a1b1000,0x00000000,
-/*
-
- MOVE FROM dsa_msgout, WHEN MSG_OUT
-
-at 0x00000088 : */ 0x1e000000,0x00000040,
-/*
-
-
-
-
-
-
-
-
-
-
- RETURN
-
-at 0x0000008a : */ 0x90080000,0x00000000,
-/*
-
-;
-; select_done
-;
-; PURPOSE: continue on to normal data transfer; called as the exit
-; point from dsa_begin.
-;
-; INPUTS: dsa
-;
-; CALLS: OK
-;
-;
-
-select_done:
-
-; NOTE DSA is corrupt when we arrive here!
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000008c : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-
-
-
-
-; After a successful selection, we should get either a CMD phase or
-; some transfer request negotiation message.
-
- JUMP cmdout, WHEN CMD
-
-at 0x0000008f : */ 0x820b0000,0x0000025c,
-/*
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
-
-at 0x00000091 : */ 0x9f030000,0x00000000,
-/*
-
-select_msg_in:
- CALL msg_in, WHEN MSG_IN
-
-at 0x00000093 : */ 0x8f0b0000,0x0000041c,
-/*
- JUMP select_msg_in, WHEN MSG_IN
-
-at 0x00000095 : */ 0x870b0000,0x0000024c,
-/*
-
-cmdout:
- INT int_err_unexpected_phase, WHEN NOT CMD
-
-at 0x00000097 : */ 0x9a030000,0x00000000,
-/*
-
-
-
-ENTRY cmdout_cmdout
-cmdout_cmdout:
-
- MOVE FROM dsa_cmdout, WHEN CMD
-
-at 0x00000099 : */ 0x1a000000,0x00000048,
-/*
-
-
-
-
-;
-; data_transfer
-; other_out
-; other_in
-; other_transfer
-;
-; PURPOSE : handle the main data transfer for a SCSI command in
-; several parts. In the first part, data_transfer, DATA_IN
-; and DATA_OUT phases are allowed, with the user provided
-; code (usually dynamically generated based on the scatter/gather
-; list associated with a SCSI command) called to handle these
-; phases.
-;
-; After control has passed to one of the user provided
-; DATA_IN or DATA_OUT routines, back calls are made to
-; other_transfer_in or other_transfer_out to handle non-DATA IN
-; and DATA OUT phases respectively, with the state of the active
-; data pointer being preserved in TEMP.
-;
-; On completion, the user code passes control to other_transfer
-; which causes DATA_IN and DATA_OUT to result in unexpected_phase
-; interrupts so that data overruns may be trapped.
-;
-; INPUTS : DSA - SCSI command
-;
-; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
-; other_transfer
-;
-; MODIFIES : SCRATCH
-;
-; EXITS : if STATUS IN is detected, signifying command completion,
-; the NCR jumps to command_complete. If MSG IN occurs, a
-; CALL is made to msg_in. Otherwise, other_transfer runs in
-; an infinite loop.
-;
-
-ENTRY data_transfer
-data_transfer:
- JUMP cmdout_cmdout, WHEN CMD
-
-at 0x0000009b : */ 0x820b0000,0x00000264,
-/*
- CALL msg_in, WHEN MSG_IN
-
-at 0x0000009d : */ 0x8f0b0000,0x0000041c,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x0000009f : */ 0x9e0b0000,0x00000000,
-/*
- JUMP do_dataout, WHEN DATA_OUT
-
-at 0x000000a1 : */ 0x800b0000,0x000002a4,
-/*
- JUMP do_datain, WHEN DATA_IN
-
-at 0x000000a3 : */ 0x810b0000,0x000002fc,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000a5 : */ 0x830b0000,0x0000065c,
-/*
- JUMP data_transfer
-
-at 0x000000a7 : */ 0x80080000,0x0000026c,
-/*
-ENTRY end_data_transfer
-end_data_transfer:
-
-;
-; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain
-; should be fixed up whenever the nexus changes so it can point to the
-; correct routine for that command.
-;
-
-
-; Nasty jump to dsa->dataout
-do_dataout:
-
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x000000a9 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- MOVE SCRATCH0 + dsa_dataout TO SCRATCH0
-
-at 0x000000ac : */ 0x7e345000,0x00000000,
-/*
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
-
-at 0x000000ae : */ 0x7f350000,0x00000000,
-/*
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
-
-at 0x000000b0 : */ 0x7f360000,0x00000000,
-/*
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-at 0x000000b2 : */ 0x7f370000,0x00000000,
-/*
-
- MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
-
-at 0x000000b4 : */ 0xc0000004,0x00000000,0x000002e0,
-/*
-
-dataout_to_jump:
- MOVE MEMORY 4, 0, dataout_jump + 4
-
-at 0x000000b7 : */ 0xc0000004,0x00000000,0x000002f8,
-/*
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000000ba : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-dataout_jump:
- JUMP 0
-
-at 0x000000bd : */ 0x80080000,0x00000000,
-/*
-
-; Nasty jump to dsa->dsain
-do_datain:
-
- MOVE MEMORY 4, saved_dsa, addr_scratch
-
-at 0x000000bf : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
- MOVE SCRATCH0 + dsa_datain TO SCRATCH0
-
-at 0x000000c2 : */ 0x7e345400,0x00000000,
-/*
- MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
-
-at 0x000000c4 : */ 0x7f350000,0x00000000,
-/*
- MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
-
-at 0x000000c6 : */ 0x7f360000,0x00000000,
-/*
- MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
-
-at 0x000000c8 : */ 0x7f370000,0x00000000,
-/*
-
- MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
-
-at 0x000000ca : */ 0xc0000004,0x00000000,0x00000338,
-/*
-
-ENTRY datain_to_jump
-datain_to_jump:
- MOVE MEMORY 4, 0, datain_jump + 4
-
-at 0x000000cd : */ 0xc0000004,0x00000000,0x00000350,
-/*
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000000d0 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-datain_jump:
- JUMP 0
-
-at 0x000000d3 : */ 0x80080000,0x00000000,
-/*
-
-
-
-; Note that other_out and other_in loop until a non-data phase
-; is discovered, so we only execute return statements when we
-; can go on to the next data phase block move statement.
-
-ENTRY other_out
-other_out:
-
-
-
- INT int_err_unexpected_phase, WHEN CMD
-
-at 0x000000d5 : */ 0x9a0b0000,0x00000000,
-/*
- JUMP msg_in_restart, WHEN MSG_IN
-
-at 0x000000d7 : */ 0x870b0000,0x000003fc,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x000000d9 : */ 0x9e0b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_IN
-
-at 0x000000db : */ 0x990b0000,0x00000000,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000dd : */ 0x830b0000,0x0000065c,
-/*
- JUMP other_out, WHEN NOT DATA_OUT
-
-at 0x000000df : */ 0x80030000,0x00000354,
-/*
-
-; TEMP should be OK, as we got here from a call in the user dataout code.
-
- RETURN
-
-at 0x000000e1 : */ 0x90080000,0x00000000,
-/*
-
-ENTRY other_in
-other_in:
-
-
-
- INT int_err_unexpected_phase, WHEN CMD
-
-at 0x000000e3 : */ 0x9a0b0000,0x00000000,
-/*
- JUMP msg_in_restart, WHEN MSG_IN
-
-at 0x000000e5 : */ 0x870b0000,0x000003fc,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x000000e7 : */ 0x9e0b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_OUT
-
-at 0x000000e9 : */ 0x980b0000,0x00000000,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000eb : */ 0x830b0000,0x0000065c,
-/*
- JUMP other_in, WHEN NOT DATA_IN
-
-at 0x000000ed : */ 0x81030000,0x0000038c,
-/*
-
-; TEMP should be OK, as we got here from a call in the user datain code.
-
- RETURN
-
-at 0x000000ef : */ 0x90080000,0x00000000,
-/*
-
-
-ENTRY other_transfer
-other_transfer:
- INT int_err_unexpected_phase, WHEN CMD
-
-at 0x000000f1 : */ 0x9a0b0000,0x00000000,
-/*
- CALL msg_in, WHEN MSG_IN
-
-at 0x000000f3 : */ 0x8f0b0000,0x0000041c,
-/*
- INT int_err_unexpected_phase, WHEN MSG_OUT
-
-at 0x000000f5 : */ 0x9e0b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_OUT
-
-at 0x000000f7 : */ 0x980b0000,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN DATA_IN
-
-at 0x000000f9 : */ 0x990b0000,0x00000000,
-/*
- JUMP command_complete, WHEN STATUS
-
-at 0x000000fb : */ 0x830b0000,0x0000065c,
-/*
- JUMP other_transfer
-
-at 0x000000fd : */ 0x80080000,0x000003c4,
-/*
-
-;
-; msg_in_restart
-; msg_in
-; munge_msg
-;
-; PURPOSE : process messages from a target. msg_in is called when the
-; caller hasn't read the first byte of the message. munge_message
-; is called when the caller has read the first byte of the message,
-; and left it in SFBR. msg_in_restart is called when the caller
-; hasn't read the first byte of the message, and wishes RETURN
-; to transfer control back to the address of the conditional
-; CALL instruction rather than to the instruction after it.
-;
-; Various int_* interrupts are generated when the host system
-; needs to intervene, as is the case with SDTR, WDTR, and
-; INITIATE RECOVERY messages.
-;
-; When the host system handles one of these interrupts,
-; it can respond by reentering at reject_message,
-; which rejects the message and returns control to
-; the caller of msg_in or munge_msg, accept_message
-; which clears ACK and returns control, or reply_message
-; which sends the message pointed to by the DSA
-; msgout_other table indirect field.
-;
-; DISCONNECT messages are handled by moving the command
-; to the reconnect_dsa_queue.
-
-; NOTE: DSA should be valid when we get here - we cannot save both it
-; and TEMP in this routine.
-
-;
-; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
-; only)
-;
-; CALLS : NO. The TEMP register isn't backed up to allow nested calls.
-;
-; MODIFIES : SCRATCH, DSA on DISCONNECT
-;
-; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
-; and normal return from message handlers running under
-; Linux, control is returned to the caller. Receipt
-; of DISCONNECT messages pass control to dsa_schedule.
-;
-ENTRY msg_in_restart
-msg_in_restart:
-; XXX - hackish
-;
-; Since it's easier to debug changes to the statically
-; compiled code, rather than the dynamically generated
-; stuff, such as
-;
-; MOVE x, y, WHEN data_phase
-; CALL other_z, WHEN NOT data_phase
-; MOVE x, y, WHEN data_phase
-;
-; I'd like to have certain routines (notably the message handler)
-; restart on the conditional call rather than the next instruction.
-;
-; So, subtract 8 from the return address
-
- MOVE TEMP0 + 0xf8 TO TEMP0
-
-at 0x000000ff : */ 0x7e1cf800,0x00000000,
-/*
- MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
-
-at 0x00000101 : */ 0x7f1dff00,0x00000000,
-/*
- MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
-
-at 0x00000103 : */ 0x7f1eff00,0x00000000,
-/*
- MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
-
-at 0x00000105 : */ 0x7f1fff00,0x00000000,
-/*
-
-ENTRY msg_in
-msg_in:
- MOVE 1, msg_buf, WHEN MSG_IN
-
-at 0x00000107 : */ 0x0f000001,0x00000000,
-/*
-
-munge_msg:
- JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE
-
-at 0x00000109 : */ 0x800c0001,0x00000574,
-/*
- JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message
-
-at 0x0000010b : */ 0x800cdf20,0x00000464,
-/*
-;
-; XXX - I've seen a handful of broken SCSI devices which fail to issue
-; a SAVE POINTERS message before disconnecting in the middle of
-; a transfer, assuming that the DATA POINTER will be implicitly
-; restored.
-;
-; Historically, I've often done an implicit save when the DISCONNECT
-; message is processed. We may want to consider having the option of
-; doing that here.
-;
- JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER
-
-at 0x0000010d : */ 0x800c0002,0x0000046c,
-/*
- JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS
-
-at 0x0000010f : */ 0x800c0003,0x00000518,
-/*
- JUMP munge_disconnect, IF 0x04 ; DISCONNECT
-
-at 0x00000111 : */ 0x800c0004,0x0000056c,
-/*
- INT int_msg_1, IF 0x07 ; MESSAGE REJECT
-
-at 0x00000113 : */ 0x980c0007,0x01020000,
-/*
- INT int_msg_1, IF 0x0f ; INITIATE RECOVERY
-
-at 0x00000115 : */ 0x980c000f,0x01020000,
-/*
-
-
-
- JUMP reject_message
-
-at 0x00000117 : */ 0x80080000,0x00000604,
-/*
-
-munge_2:
- JUMP reject_message
-
-at 0x00000119 : */ 0x80080000,0x00000604,
-/*
-;
-; The SCSI standard allows targets to recover from transient
-; error conditions by backing up the data pointer with a
-; RESTORE POINTERS message.
-;
-; So, we must save and restore the _residual_ code as well as
-; the current instruction pointer. Because of this messiness,
-; it is simpler to put dynamic code in the dsa for this and to
-; just do a simple jump down there.
-;
-
-munge_save_data_pointer:
-
- ; We have something in TEMP here, so first we must save that
- MOVE TEMP0 TO SFBR
-
-at 0x0000011b : */ 0x721c0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x0000011d : */ 0x6a340000,0x00000000,
-/*
- MOVE TEMP1 TO SFBR
-
-at 0x0000011f : */ 0x721d0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x00000121 : */ 0x6a350000,0x00000000,
-/*
- MOVE TEMP2 TO SFBR
-
-at 0x00000123 : */ 0x721e0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x00000125 : */ 0x6a360000,0x00000000,
-/*
- MOVE TEMP3 TO SFBR
-
-at 0x00000127 : */ 0x721f0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x00000129 : */ 0x6a370000,0x00000000,
-/*
- MOVE MEMORY 4, addr_scratch, jump_temp + 4
-
-at 0x0000012b : */ 0xc0000004,0x00000000,0x000009c8,
-/*
- ; Now restore DSA
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x0000012e : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
- MOVE DSA0 + dsa_save_data_pointer TO SFBR
-
-at 0x00000131 : */ 0x76100000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x00000133 : */ 0x6a340000,0x00000000,
-/*
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
-
-at 0x00000135 : */ 0x7711ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x00000137 : */ 0x6a350000,0x00000000,
-/*
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
-
-at 0x00000139 : */ 0x7712ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x0000013b : */ 0x6a360000,0x00000000,
-/*
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
-
-at 0x0000013d : */ 0x7713ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x0000013f : */ 0x6a370000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
-
-at 0x00000141 : */ 0xc0000004,0x00000000,0x00000514,
-/*
-
-jump_dsa_save:
- JUMP 0
-
-at 0x00000144 : */ 0x80080000,0x00000000,
-/*
-
-munge_restore_pointers:
-
- ; The code at dsa_restore_pointers will RETURN, but we don't care
- ; about TEMP here, as it will overwrite it anyway.
-
- MOVE DSA0 + dsa_restore_pointers TO SFBR
-
-at 0x00000146 : */ 0x76100000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x00000148 : */ 0x6a340000,0x00000000,
-/*
- MOVE DSA1 + 0xff TO SFBR WITH CARRY
-
-at 0x0000014a : */ 0x7711ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x0000014c : */ 0x6a350000,0x00000000,
-/*
- MOVE DSA2 + 0xff TO SFBR WITH CARRY
-
-at 0x0000014e : */ 0x7712ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x00000150 : */ 0x6a360000,0x00000000,
-/*
- MOVE DSA3 + 0xff TO SFBR WITH CARRY
-
-at 0x00000152 : */ 0x7713ff00,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x00000154 : */ 0x6a370000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
-
-at 0x00000156 : */ 0xc0000004,0x00000000,0x00000568,
-/*
-
-jump_dsa_restore:
- JUMP 0
-
-at 0x00000159 : */ 0x80080000,0x00000000,
-/*
-
-
-munge_disconnect:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- JUMP dsa_schedule
-
-at 0x0000015b : */ 0x80080000,0x00000178,
-/*
-
-
-
-
-
-munge_extended:
- CLEAR ACK
-
-at 0x0000015d : */ 0x60000040,0x00000000,
-/*
- INT int_err_unexpected_phase, WHEN NOT MSG_IN
-
-at 0x0000015f : */ 0x9f030000,0x00000000,
-/*
- MOVE 1, msg_buf + 1, WHEN MSG_IN
-
-at 0x00000161 : */ 0x0f000001,0x00000001,
-/*
- JUMP munge_extended_2, IF 0x02
-
-at 0x00000163 : */ 0x800c0002,0x000005a4,
-/*
- JUMP munge_extended_3, IF 0x03
-
-at 0x00000165 : */ 0x800c0003,0x000005d4,
-/*
- JUMP reject_message
-
-at 0x00000167 : */ 0x80080000,0x00000604,
-/*
-
-munge_extended_2:
- CLEAR ACK
-
-at 0x00000169 : */ 0x60000040,0x00000000,
-/*
- MOVE 1, msg_buf + 2, WHEN MSG_IN
-
-at 0x0000016b : */ 0x0f000001,0x00000002,
-/*
- JUMP reject_message, IF NOT 0x02 ; Must be WDTR
-
-at 0x0000016d : */ 0x80040002,0x00000604,
-/*
- CLEAR ACK
-
-at 0x0000016f : */ 0x60000040,0x00000000,
-/*
- MOVE 1, msg_buf + 3, WHEN MSG_IN
-
-at 0x00000171 : */ 0x0f000001,0x00000003,
-/*
- INT int_msg_wdtr
-
-at 0x00000173 : */ 0x98080000,0x01000000,
-/*
-
-munge_extended_3:
- CLEAR ACK
-
-at 0x00000175 : */ 0x60000040,0x00000000,
-/*
- MOVE 1, msg_buf + 2, WHEN MSG_IN
-
-at 0x00000177 : */ 0x0f000001,0x00000002,
-/*
- JUMP reject_message, IF NOT 0x01 ; Must be SDTR
-
-at 0x00000179 : */ 0x80040001,0x00000604,
-/*
- CLEAR ACK
-
-at 0x0000017b : */ 0x60000040,0x00000000,
-/*
- MOVE 2, msg_buf + 3, WHEN MSG_IN
-
-at 0x0000017d : */ 0x0f000002,0x00000003,
-/*
- INT int_msg_sdtr
-
-at 0x0000017f : */ 0x98080000,0x01010000,
-/*
-
-ENTRY reject_message
-reject_message:
- SET ATN
-
-at 0x00000181 : */ 0x58000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x00000183 : */ 0x60000040,0x00000000,
-/*
- MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
-
-at 0x00000185 : */ 0x0e000001,0x00000000,
-/*
- RETURN
-
-at 0x00000187 : */ 0x90080000,0x00000000,
-/*
-
-ENTRY accept_message
-accept_message:
- CLEAR ATN
-
-at 0x00000189 : */ 0x60000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x0000018b : */ 0x60000040,0x00000000,
-/*
- RETURN
-
-at 0x0000018d : */ 0x90080000,0x00000000,
-/*
-
-ENTRY respond_message
-respond_message:
- SET ATN
-
-at 0x0000018f : */ 0x58000008,0x00000000,
-/*
- CLEAR ACK
-
-at 0x00000191 : */ 0x60000040,0x00000000,
-/*
- MOVE FROM dsa_msgout_other, WHEN MSG_OUT
-
-at 0x00000193 : */ 0x1e000000,0x00000068,
-/*
- RETURN
-
-at 0x00000195 : */ 0x90080000,0x00000000,
-/*
-
-;
-; command_complete
-;
-; PURPOSE : handle command termination when STATUS IN is detected by reading
-; a status byte followed by a command termination message.
-;
-; Normal termination results in an INTFLY instruction, and
-; the host system can pick out which command terminated by
-; examining the MESSAGE and STATUS buffers of all currently
-; executing commands;
-;
-; Abnormal (CHECK_CONDITION) termination results in an
-; int_err_check_condition interrupt so that a REQUEST SENSE
-; command can be issued out-of-order so that no other command
-; clears the contingent allegiance condition.
-;
-;
-; INPUTS : DSA - command
-;
-; CALLS : OK
-;
-; EXITS : On successful termination, control is passed to schedule.
-; On abnormal termination, the user will usually modify the
-; DSA fields and corresponding buffers and return control
-; to select.
-;
-
-ENTRY command_complete
-command_complete:
- MOVE FROM dsa_status, WHEN STATUS
-
-at 0x00000197 : */ 0x1b000000,0x00000060,
-/*
-
- MOVE SFBR TO SCRATCH0 ; Save status
-
-at 0x00000199 : */ 0x6a340000,0x00000000,
-/*
-
-ENTRY command_complete_msgin
-command_complete_msgin:
- MOVE FROM dsa_msgin, WHEN MSG_IN
-
-at 0x0000019b : */ 0x1f000000,0x00000058,
-/*
-; Indicate that we should be expecting a disconnect
-
-
-
- ; Above code cleared the Unexpected Disconnect bit, what do we do?
-
- CLEAR ACK
-
-at 0x0000019d : */ 0x60000040,0x00000000,
-/*
-
- WAIT DISCONNECT
-
-at 0x0000019f : */ 0x48000000,0x00000000,
-/*
-
-;
-; The SCSI specification states that when a UNIT ATTENTION condition
-; is pending, as indicated by a CHECK CONDITION status message,
-; the target shall revert to asynchronous transfers. Since
-; synchronous transfers parameters are maintained on a per INITIATOR/TARGET
-; basis, and returning control to our scheduler could work on a command
-; running on another lun on that target using the old parameters, we must
-; interrupt the host processor to get them changed, or change them ourselves.
-;
-; Once SCSI-II tagged queueing is implemented, things will be even more
-; hairy, since contingent allegiance conditions exist on a per-target/lun
-; basis, and issuing a new command with a different tag would clear it.
-; In these cases, we must interrupt the host processor to get a request
-; added to the HEAD of the queue with the request sense command, or we
-; must automatically issue the request sense command.
-
-
-
-
-
-
-
- INT int_norm_emulateintfly
-
-at 0x000001a1 : */ 0x98080000,0x02060000,
-/*
-
-
-
-
-
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000001a3 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
-
- JUMP schedule
-
-at 0x000001a6 : */ 0x80080000,0x00000000,
-/*
-command_failed:
- INT int_err_check_condition
-
-at 0x000001a8 : */ 0x98080000,0x00030000,
-/*
-
-
-
-
-;
-; wait_reselect
-;
-; PURPOSE : This is essentially the idle routine, where control lands
-; when there are no new processes to schedule. wait_reselect
-; waits for reselection, selection, and new commands.
-;
-; When a successful reselection occurs, with the aid
-; of fixed up code in each DSA, wait_reselect walks the
-; reconnect_dsa_queue, asking each dsa if the target ID
-; and LUN match its.
-;
-; If a match is found, a call is made back to reselected_ok,
-; which through the miracles of self modifying code, extracts
-; the found DSA from the reconnect_dsa_queue and then
-; returns control to the DSAs thread of execution.
-;
-; INPUTS : NONE
-;
-; CALLS : OK
-;
-; MODIFIES : DSA,
-;
-; EXITS : On successful reselection, control is returned to the
-; DSA which called reselected_ok. If the WAIT RESELECT
-; was interrupted by a new commands arrival signaled by
-; SIG_P, control is passed to schedule. If the NCR is
-; selected, the host system is interrupted with an
-; int_err_selected which is usually responded to by
-; setting DSP to the target_abort address.
-
-ENTRY wait_reselect
-wait_reselect:
-
-
-
-
-
-
- WAIT RESELECT wait_reselect_failed
-
-at 0x000001aa : */ 0x50000000,0x00000800,
-/*
-
-reselected:
-
-
-
- CLEAR TARGET
-
-at 0x000001ac : */ 0x60000200,0x00000000,
-/*
-
- ; Read all data needed to reestablish the nexus -
- MOVE 1, reselected_identify, WHEN MSG_IN
-
-at 0x000001ae : */ 0x0f000001,0x00000000,
-/*
- ; We used to CLEAR ACK here.
-
-
-
-
-
- ; Point DSA at the current head of the disconnected queue.
-
- MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
-
-at 0x000001b0 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, saved_dsa
-
-at 0x000001b3 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-
-
- ; Fix the update-next pointer so that the reconnect_dsa_head
- ; pointer is the one that will be updated if this DSA is a hit
- ; and we remove it from the queue.
-
- MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
-
-at 0x000001b6 : */ 0xc0000004,0x00000000,0x000007ec,
-/*
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000001b9 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-
-ENTRY reselected_check_next
-reselected_check_next:
-
-
-
- ; Check for a NULL pointer.
- MOVE DSA0 TO SFBR
-
-at 0x000001bc : */ 0x72100000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001be : */ 0x80040000,0x00000738,
-/*
- MOVE DSA1 TO SFBR
-
-at 0x000001c0 : */ 0x72110000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001c2 : */ 0x80040000,0x00000738,
-/*
- MOVE DSA2 TO SFBR
-
-at 0x000001c4 : */ 0x72120000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001c6 : */ 0x80040000,0x00000738,
-/*
- MOVE DSA3 TO SFBR
-
-at 0x000001c8 : */ 0x72130000,0x00000000,
-/*
- JUMP reselected_not_end, IF NOT 0
-
-at 0x000001ca : */ 0x80040000,0x00000738,
-/*
- INT int_err_unexpected_reselect
-
-at 0x000001cc : */ 0x98080000,0x00020000,
-/*
-
-reselected_not_end:
- ;
- ; XXX the ALU is only eight bits wide, and the assembler
- ; wont do the dirt work for us. As long as dsa_check_reselect
- ; is negative, we need to sign extend with 1 bits to the full
- ; 32 bit width of the address.
- ;
- ; A potential work around would be to have a known alignment
- ; of the DSA structure such that the base address plus
- ; dsa_check_reselect doesn't require carrying from bytes
- ; higher than the LSB.
- ;
-
- MOVE DSA0 TO SFBR
-
-at 0x000001ce : */ 0x72100000,0x00000000,
-/*
- MOVE SFBR + dsa_check_reselect TO SCRATCH0
-
-at 0x000001d0 : */ 0x6e340000,0x00000000,
-/*
- MOVE DSA1 TO SFBR
-
-at 0x000001d2 : */ 0x72110000,0x00000000,
-/*
- MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
-
-at 0x000001d4 : */ 0x6f35ff00,0x00000000,
-/*
- MOVE DSA2 TO SFBR
-
-at 0x000001d6 : */ 0x72120000,0x00000000,
-/*
- MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
-
-at 0x000001d8 : */ 0x6f36ff00,0x00000000,
-/*
- MOVE DSA3 TO SFBR
-
-at 0x000001da : */ 0x72130000,0x00000000,
-/*
- MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
-
-at 0x000001dc : */ 0x6f37ff00,0x00000000,
-/*
-
-
- MOVE MEMORY 4, addr_scratch, reselected_check + 4
-
-at 0x000001de : */ 0xc0000004,0x00000000,0x00000794,
-/*
-
-
- ; Time to correct DSA following memory move
- MOVE MEMORY 4, saved_dsa, addr_dsa
-
-at 0x000001e1 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-
-reselected_check:
- JUMP 0
-
-at 0x000001e4 : */ 0x80080000,0x00000000,
-/*
-
-
-;
-;
-
-; We have problems here - the memory move corrupts TEMP and DSA. This
-; routine is called from DSA code, and patched from many places. Scratch
-; is probably free when it is called.
-; We have to:
-; copy temp to scratch, one byte at a time
-; write scratch to patch a jump in place of the return
-; do the move memory
-; jump to the patched in return address
-; DSA is corrupt when we get here, and can be left corrupt
-
-ENTRY reselected_ok
-reselected_ok:
- MOVE TEMP0 TO SFBR
-
-at 0x000001e6 : */ 0x721c0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH0
-
-at 0x000001e8 : */ 0x6a340000,0x00000000,
-/*
- MOVE TEMP1 TO SFBR
-
-at 0x000001ea : */ 0x721d0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH1
-
-at 0x000001ec : */ 0x6a350000,0x00000000,
-/*
- MOVE TEMP2 TO SFBR
-
-at 0x000001ee : */ 0x721e0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH2
-
-at 0x000001f0 : */ 0x6a360000,0x00000000,
-/*
- MOVE TEMP3 TO SFBR
-
-at 0x000001f2 : */ 0x721f0000,0x00000000,
-/*
- MOVE SFBR TO SCRATCH3
-
-at 0x000001f4 : */ 0x6a370000,0x00000000,
-/*
- MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
-
-at 0x000001f6 : */ 0xc0000004,0x00000000,0x000007f4,
-/*
-reselected_ok_patch:
- MOVE MEMORY 4, 0, 0
-
-at 0x000001f9 : */ 0xc0000004,0x00000000,0x00000000,
-/*
-reselected_ok_jump:
- JUMP 0
-
-at 0x000001fc : */ 0x80080000,0x00000000,
-/*
-
-
-
-
-
-selected:
- INT int_err_selected;
-
-at 0x000001fe : */ 0x98080000,0x00010000,
-/*
-
-;
-; A select or reselect failure can be caused by one of two conditions :
-; 1. SIG_P was set. This will be the case if the user has written
-; a new value to a previously NULL head of the issue queue.
-;
-; 2. The NCR53c810 was selected or reselected by another device.
-;
-; 3. The bus was already busy since we were selected or reselected
-; before starting the command.
-
-wait_reselect_failed:
-
-
-
-; Check selected bit.
-
- ; Must work out how to tell if we are selected....
-
-
-
-
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
-
-at 0x00000200 : */ 0x74164000,0x00000000,
-/*
- JUMP schedule, IF 0x40
-
-at 0x00000202 : */ 0x800c0040,0x00000000,
-/*
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
- MOVE ISTAT & 0x08 TO SFBR
-
-at 0x00000204 : */ 0x74210800,0x00000000,
-/*
- JUMP reselected, IF 0x08
-
-at 0x00000206 : */ 0x800c0008,0x000006b0,
-/*
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-
-
-
- INT int_debug_panic
-
-at 0x00000208 : */ 0x98080000,0x030b0000,
-/*
-
-
-
-select_failed:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x0000020a : */ 0x7a1b1000,0x00000000,
-/*
-
-
-
-
-; Otherwise, mask the selected and reselected bits off SIST0
-
- ; Let's assume we don't get selected for now
- MOVE SSTAT0 & 0x10 TO SFBR
-
-at 0x0000020c : */ 0x740d1000,0x00000000,
-/*
-
-
-
-
- JUMP reselected, IF 0x10
-
-at 0x0000020e : */ 0x800c0010,0x000006b0,
-/*
-; If SIGP is set, the user just gave us another command, and
-; we should restart or return to the scheduler.
-; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
- MOVE CTEST2 & 0x40 TO SFBR
-
-at 0x00000210 : */ 0x74164000,0x00000000,
-/*
- JUMP select, IF 0x40
-
-at 0x00000212 : */ 0x800c0040,0x000001f8,
-/*
-; Check connected bit.
-; FIXME: this needs to change if we support target mode
-; FIXME: is this really necessary?
- MOVE ISTAT & 0x08 TO SFBR
-
-at 0x00000214 : */ 0x74210800,0x00000000,
-/*
- JUMP reselected, IF 0x08
-
-at 0x00000216 : */ 0x800c0008,0x000006b0,
-/*
-; FIXME : Something bogus happened, and we shouldn't fail silently.
-
-
-
- INT int_debug_panic
-
-at 0x00000218 : */ 0x98080000,0x030b0000,
-/*
-
-
-;
-; test_1
-; test_2
-;
-; PURPOSE : run some verification tests on the NCR. test_1
-; copies test_src to test_dest and interrupts the host
-; processor, testing for cache coherency and interrupt
-; problems in the processes.
-;
-; test_2 runs a command with offsets relative to the
-; DSA on entry, and is useful for miscellaneous experimentation.
-;
-
-; Verify that interrupts are working correctly and that we don't
-; have a cache invalidation problem.
-
-ABSOLUTE test_src = 0, test_dest = 0
-ENTRY test_1
-test_1:
- MOVE MEMORY 4, test_src, test_dest
-
-at 0x0000021a : */ 0xc0000004,0x00000000,0x00000000,
-/*
- INT int_test_1
-
-at 0x0000021d : */ 0x98080000,0x04000000,
-/*
-
-;
-; Run arbitrary commands, with test code establishing a DSA
-;
-
-ENTRY test_2
-test_2:
- CLEAR TARGET
-
-at 0x0000021f : */ 0x60000200,0x00000000,
-/*
-
- ; Enable selection timer
-
-
-
- MOVE CTEST7 & 0xef TO CTEST7
-
-at 0x00000221 : */ 0x7c1bef00,0x00000000,
-/*
-
-
- SELECT ATN FROM 0, test_2_fail
-
-at 0x00000223 : */ 0x43000000,0x000008dc,
-/*
- JUMP test_2_msgout, WHEN MSG_OUT
-
-at 0x00000225 : */ 0x860b0000,0x0000089c,
-/*
-ENTRY test_2_msgout
-test_2_msgout:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x00000227 : */ 0x7a1b1000,0x00000000,
-/*
-
- MOVE FROM 8, WHEN MSG_OUT
-
-at 0x00000229 : */ 0x1e000000,0x00000008,
-/*
- MOVE FROM 16, WHEN CMD
-
-at 0x0000022b : */ 0x1a000000,0x00000010,
-/*
- MOVE FROM 24, WHEN DATA_IN
-
-at 0x0000022d : */ 0x19000000,0x00000018,
-/*
- MOVE FROM 32, WHEN STATUS
-
-at 0x0000022f : */ 0x1b000000,0x00000020,
-/*
- MOVE FROM 40, WHEN MSG_IN
-
-at 0x00000231 : */ 0x1f000000,0x00000028,
-/*
-
-
-
- CLEAR ACK
-
-at 0x00000233 : */ 0x60000040,0x00000000,
-/*
- WAIT DISCONNECT
-
-at 0x00000235 : */ 0x48000000,0x00000000,
-/*
-test_2_fail:
-
- ; Disable selection timer
- MOVE CTEST7 | 0x10 TO CTEST7
-
-at 0x00000237 : */ 0x7a1b1000,0x00000000,
-/*
-
- INT int_test_2
-
-at 0x00000239 : */ 0x98080000,0x04010000,
-/*
-
-ENTRY debug_break
-debug_break:
- INT int_debug_break
-
-at 0x0000023b : */ 0x98080000,0x03000000,
-/*
-
-;
-; initiator_abort
-; target_abort
-;
-; PURPOSE : Abort the currently established nexus from with initiator
-; or target mode.
-;
-;
-
-ENTRY target_abort
-target_abort:
- SET TARGET
-
-at 0x0000023d : */ 0x58000200,0x00000000,
-/*
- DISCONNECT
-
-at 0x0000023f : */ 0x48000000,0x00000000,
-/*
- CLEAR TARGET
-
-at 0x00000241 : */ 0x60000200,0x00000000,
-/*
- JUMP schedule
-
-at 0x00000243 : */ 0x80080000,0x00000000,
-/*
-
-ENTRY initiator_abort
-initiator_abort:
- SET ATN
-
-at 0x00000245 : */ 0x58000008,0x00000000,
-/*
-;
-; The SCSI-I specification says that targets may go into MSG out at
-; their leisure upon receipt of the ATN single. On all versions of the
-; specification, we can't change phases until REQ transitions true->false,
-; so we need to sink/source one byte of data to allow the transition.
-;
-; For the sake of safety, we'll only source one byte of data in all
-; cases, but to accommodate the SCSI-I dain bramage, we'll sink an
-; arbitrary number of bytes.
- JUMP spew_cmd, WHEN CMD
-
-at 0x00000247 : */ 0x820b0000,0x0000094c,
-/*
- JUMP eat_msgin, WHEN MSG_IN
-
-at 0x00000249 : */ 0x870b0000,0x0000095c,
-/*
- JUMP eat_datain, WHEN DATA_IN
-
-at 0x0000024b : */ 0x810b0000,0x0000098c,
-/*
- JUMP eat_status, WHEN STATUS
-
-at 0x0000024d : */ 0x830b0000,0x00000974,
-/*
- JUMP spew_dataout, WHEN DATA_OUT
-
-at 0x0000024f : */ 0x800b0000,0x000009a4,
-/*
- JUMP sated
-
-at 0x00000251 : */ 0x80080000,0x000009ac,
-/*
-spew_cmd:
- MOVE 1, NCR53c7xx_zero, WHEN CMD
-
-at 0x00000253 : */ 0x0a000001,0x00000000,
-/*
- JUMP sated
-
-at 0x00000255 : */ 0x80080000,0x000009ac,
-/*
-eat_msgin:
- MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
-
-at 0x00000257 : */ 0x0f000001,0x00000000,
-/*
- JUMP eat_msgin, WHEN MSG_IN
-
-at 0x00000259 : */ 0x870b0000,0x0000095c,
-/*
- JUMP sated
-
-at 0x0000025b : */ 0x80080000,0x000009ac,
-/*
-eat_status:
- MOVE 1, NCR53c7xx_sink, WHEN STATUS
-
-at 0x0000025d : */ 0x0b000001,0x00000000,
-/*
- JUMP eat_status, WHEN STATUS
-
-at 0x0000025f : */ 0x830b0000,0x00000974,
-/*
- JUMP sated
-
-at 0x00000261 : */ 0x80080000,0x000009ac,
-/*
-eat_datain:
- MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
-
-at 0x00000263 : */ 0x09000001,0x00000000,
-/*
- JUMP eat_datain, WHEN DATA_IN
-
-at 0x00000265 : */ 0x810b0000,0x0000098c,
-/*
- JUMP sated
-
-at 0x00000267 : */ 0x80080000,0x000009ac,
-/*
-spew_dataout:
- MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
-
-at 0x00000269 : */ 0x08000001,0x00000000,
-/*
-sated:
-
-
-
- MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
-
-at 0x0000026b : */ 0x0e000001,0x00000000,
-/*
- WAIT DISCONNECT
-
-at 0x0000026d : */ 0x48000000,0x00000000,
-/*
- INT int_norm_aborted
-
-at 0x0000026f : */ 0x98080000,0x02040000,
-/*
-
-
-
-
-; Little patched jump, used to overcome problems with TEMP getting
-; corrupted on memory moves.
-
-jump_temp:
- JUMP 0
-
-at 0x00000271 : */ 0x80080000,0x00000000,
-};
-
-#define A_NCR53c7xx_msg_abort 0x00000000
-static u32 A_NCR53c7xx_msg_abort_used[] __attribute((unused)) = {
- 0x0000026c,
-};
-
-#define A_NCR53c7xx_msg_reject 0x00000000
-static u32 A_NCR53c7xx_msg_reject_used[] __attribute((unused)) = {
- 0x00000186,
-};
-
-#define A_NCR53c7xx_sink 0x00000000
-static u32 A_NCR53c7xx_sink_used[] __attribute((unused)) = {
- 0x00000258,
- 0x0000025e,
- 0x00000264,
-};
-
-#define A_NCR53c7xx_zero 0x00000000
-static u32 A_NCR53c7xx_zero_used[] __attribute((unused)) = {
- 0x00000254,
- 0x0000026a,
-};
-
-#define A_NOP_insn 0x00000000
-static u32 A_NOP_insn_used[] __attribute((unused)) = {
- 0x00000017,
-};
-
-#define A_addr_dsa 0x00000000
-static u32 A_addr_dsa_used[] __attribute((unused)) = {
- 0x0000000f,
- 0x00000026,
- 0x00000033,
- 0x00000040,
- 0x00000055,
- 0x00000079,
- 0x0000008e,
- 0x000000bc,
- 0x000000d2,
- 0x00000130,
- 0x000001a5,
- 0x000001bb,
- 0x000001e3,
-};
-
-#define A_addr_reconnect_dsa_head 0x00000000
-static u32 A_addr_reconnect_dsa_head_used[] __attribute((unused)) = {
- 0x000001b7,
-};
-
-#define A_addr_scratch 0x00000000
-static u32 A_addr_scratch_used[] __attribute((unused)) = {
- 0x00000002,
- 0x00000004,
- 0x00000008,
- 0x00000020,
- 0x00000022,
- 0x00000049,
- 0x00000060,
- 0x0000006a,
- 0x00000071,
- 0x00000073,
- 0x000000ab,
- 0x000000b5,
- 0x000000c1,
- 0x000000cb,
- 0x0000012c,
- 0x00000142,
- 0x00000157,
- 0x000001b2,
- 0x000001b4,
- 0x000001df,
- 0x000001f7,
-};
-
-#define A_addr_temp 0x00000000
-static u32 A_addr_temp_used[] __attribute((unused)) = {
-};
-
-#define A_dmode_memory_to_memory 0x00000000
-static u32 A_dmode_memory_to_memory_used[] __attribute((unused)) = {
-};
-
-#define A_dmode_memory_to_ncr 0x00000000
-static u32 A_dmode_memory_to_ncr_used[] __attribute((unused)) = {
-};
-
-#define A_dmode_ncr_to_memory 0x00000000
-static u32 A_dmode_ncr_to_memory_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_check_reselect 0x00000000
-static u32 A_dsa_check_reselect_used[] __attribute((unused)) = {
- 0x000001d0,
-};
-
-#define A_dsa_cmdout 0x00000048
-static u32 A_dsa_cmdout_used[] __attribute((unused)) = {
- 0x0000009a,
-};
-
-#define A_dsa_cmnd 0x00000038
-static u32 A_dsa_cmnd_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_datain 0x00000054
-static u32 A_dsa_datain_used[] __attribute((unused)) = {
- 0x000000c2,
-};
-
-#define A_dsa_dataout 0x00000050
-static u32 A_dsa_dataout_used[] __attribute((unused)) = {
- 0x000000ac,
-};
-
-#define A_dsa_end 0x00000070
-static u32 A_dsa_end_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_fields_start 0x00000000
-static u32 A_dsa_fields_start_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_msgin 0x00000058
-static u32 A_dsa_msgin_used[] __attribute((unused)) = {
- 0x0000019c,
-};
-
-#define A_dsa_msgout 0x00000040
-static u32 A_dsa_msgout_used[] __attribute((unused)) = {
- 0x00000089,
-};
-
-#define A_dsa_msgout_other 0x00000068
-static u32 A_dsa_msgout_other_used[] __attribute((unused)) = {
- 0x00000194,
-};
-
-#define A_dsa_next 0x00000030
-static u32 A_dsa_next_used[] __attribute((unused)) = {
- 0x00000061,
-};
-
-#define A_dsa_restore_pointers 0x00000000
-static u32 A_dsa_restore_pointers_used[] __attribute((unused)) = {
- 0x00000146,
-};
-
-#define A_dsa_save_data_pointer 0x00000000
-static u32 A_dsa_save_data_pointer_used[] __attribute((unused)) = {
- 0x00000131,
-};
-
-#define A_dsa_select 0x0000003c
-static u32 A_dsa_select_used[] __attribute((unused)) = {
- 0x00000082,
-};
-
-#define A_dsa_sscf_710 0x00000000
-static u32 A_dsa_sscf_710_used[] __attribute((unused)) = {
- 0x00000007,
-};
-
-#define A_dsa_status 0x00000060
-static u32 A_dsa_status_used[] __attribute((unused)) = {
- 0x00000198,
-};
-
-#define A_dsa_temp_addr_array_value 0x00000000
-static u32 A_dsa_temp_addr_array_value_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_temp_addr_dsa_value 0x00000000
-static u32 A_dsa_temp_addr_dsa_value_used[] __attribute((unused)) = {
- 0x00000001,
-};
-
-#define A_dsa_temp_addr_new_value 0x00000000
-static u32 A_dsa_temp_addr_new_value_used[] __attribute((unused)) = {
-};
-
-#define A_dsa_temp_addr_next 0x00000000
-static u32 A_dsa_temp_addr_next_used[] __attribute((unused)) = {
- 0x0000001c,
- 0x0000004f,
-};
-
-#define A_dsa_temp_addr_residual 0x00000000
-static u32 A_dsa_temp_addr_residual_used[] __attribute((unused)) = {
- 0x0000002d,
- 0x0000003b,
-};
-
-#define A_dsa_temp_addr_saved_pointer 0x00000000
-static u32 A_dsa_temp_addr_saved_pointer_used[] __attribute((unused)) = {
- 0x0000002b,
- 0x00000037,
-};
-
-#define A_dsa_temp_addr_saved_residual 0x00000000
-static u32 A_dsa_temp_addr_saved_residual_used[] __attribute((unused)) = {
- 0x0000002e,
- 0x0000003a,
-};
-
-#define A_dsa_temp_lun 0x00000000
-static u32 A_dsa_temp_lun_used[] __attribute((unused)) = {
- 0x0000004c,
-};
-
-#define A_dsa_temp_next 0x00000000
-static u32 A_dsa_temp_next_used[] __attribute((unused)) = {
- 0x0000001f,
-};
-
-#define A_dsa_temp_sync 0x00000000
-static u32 A_dsa_temp_sync_used[] __attribute((unused)) = {
- 0x00000057,
-};
-
-#define A_dsa_temp_target 0x00000000
-static u32 A_dsa_temp_target_used[] __attribute((unused)) = {
- 0x00000045,
-};
-
-#define A_emulfly 0x00000000
-static u32 A_emulfly_used[] __attribute((unused)) = {
-};
-
-#define A_int_debug_break 0x03000000
-static u32 A_int_debug_break_used[] __attribute((unused)) = {
- 0x0000023c,
-};
-
-#define A_int_debug_panic 0x030b0000
-static u32 A_int_debug_panic_used[] __attribute((unused)) = {
- 0x00000209,
- 0x00000219,
-};
-
-#define A_int_err_check_condition 0x00030000
-static u32 A_int_err_check_condition_used[] __attribute((unused)) = {
- 0x000001a9,
-};
-
-#define A_int_err_no_phase 0x00040000
-static u32 A_int_err_no_phase_used[] __attribute((unused)) = {
-};
-
-#define A_int_err_selected 0x00010000
-static u32 A_int_err_selected_used[] __attribute((unused)) = {
- 0x000001ff,
-};
-
-#define A_int_err_unexpected_phase 0x00000000
-static u32 A_int_err_unexpected_phase_used[] __attribute((unused)) = {
- 0x00000092,
- 0x00000098,
- 0x000000a0,
- 0x000000d6,
- 0x000000da,
- 0x000000dc,
- 0x000000e4,
- 0x000000e8,
- 0x000000ea,
- 0x000000f2,
- 0x000000f6,
- 0x000000f8,
- 0x000000fa,
- 0x00000160,
-};
-
-#define A_int_err_unexpected_reselect 0x00020000
-static u32 A_int_err_unexpected_reselect_used[] __attribute((unused)) = {
- 0x000001cd,
-};
-
-#define A_int_msg_1 0x01020000
-static u32 A_int_msg_1_used[] __attribute((unused)) = {
- 0x00000114,
- 0x00000116,
-};
-
-#define A_int_msg_sdtr 0x01010000
-static u32 A_int_msg_sdtr_used[] __attribute((unused)) = {
- 0x00000180,
-};
-
-#define A_int_msg_wdtr 0x01000000
-static u32 A_int_msg_wdtr_used[] __attribute((unused)) = {
- 0x00000174,
-};
-
-#define A_int_norm_aborted 0x02040000
-static u32 A_int_norm_aborted_used[] __attribute((unused)) = {
- 0x00000270,
-};
-
-#define A_int_norm_command_complete 0x02020000
-static u32 A_int_norm_command_complete_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_disconnected 0x02030000
-static u32 A_int_norm_disconnected_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_emulateintfly 0x02060000
-static u32 A_int_norm_emulateintfly_used[] __attribute((unused)) = {
- 0x000001a2,
-};
-
-#define A_int_norm_reselect_complete 0x02010000
-static u32 A_int_norm_reselect_complete_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_reset 0x02050000
-static u32 A_int_norm_reset_used[] __attribute((unused)) = {
-};
-
-#define A_int_norm_select_complete 0x02000000
-static u32 A_int_norm_select_complete_used[] __attribute((unused)) = {
-};
-
-#define A_int_test_1 0x04000000
-static u32 A_int_test_1_used[] __attribute((unused)) = {
- 0x0000021e,
-};
-
-#define A_int_test_2 0x04010000
-static u32 A_int_test_2_used[] __attribute((unused)) = {
- 0x0000023a,
-};
-
-#define A_int_test_3 0x04020000
-static u32 A_int_test_3_used[] __attribute((unused)) = {
-};
-
-#define A_msg_buf 0x00000000
-static u32 A_msg_buf_used[] __attribute((unused)) = {
- 0x00000108,
- 0x00000162,
- 0x0000016c,
- 0x00000172,
- 0x00000178,
- 0x0000017e,
-};
-
-#define A_reconnect_dsa_head 0x00000000
-static u32 A_reconnect_dsa_head_used[] __attribute((unused)) = {
- 0x0000006d,
- 0x00000074,
- 0x000001b1,
-};
-
-#define A_reselected_identify 0x00000000
-static u32 A_reselected_identify_used[] __attribute((unused)) = {
- 0x00000048,
- 0x000001af,
-};
-
-#define A_reselected_tag 0x00000000
-static u32 A_reselected_tag_used[] __attribute((unused)) = {
-};
-
-#define A_saved_dsa 0x00000000
-static u32 A_saved_dsa_used[] __attribute((unused)) = {
- 0x00000005,
- 0x0000000e,
- 0x00000023,
- 0x00000025,
- 0x00000032,
- 0x0000003f,
- 0x00000054,
- 0x0000005f,
- 0x00000070,
- 0x00000078,
- 0x0000008d,
- 0x000000aa,
- 0x000000bb,
- 0x000000c0,
- 0x000000d1,
- 0x0000012f,
- 0x000001a4,
- 0x000001b5,
- 0x000001ba,
- 0x000001e2,
-};
-
-#define A_schedule 0x00000000
-static u32 A_schedule_used[] __attribute((unused)) = {
- 0x0000007d,
- 0x000001a7,
- 0x00000203,
- 0x00000244,
-};
-
-#define A_test_dest 0x00000000
-static u32 A_test_dest_used[] __attribute((unused)) = {
- 0x0000021c,
-};
-
-#define A_test_src 0x00000000
-static u32 A_test_src_used[] __attribute((unused)) = {
- 0x0000021b,
-};
-
-#define Ent_accept_message 0x00000624
-#define Ent_cmdout_cmdout 0x00000264
-#define Ent_command_complete 0x0000065c
-#define Ent_command_complete_msgin 0x0000066c
-#define Ent_data_transfer 0x0000026c
-#define Ent_datain_to_jump 0x00000334
-#define Ent_debug_break 0x000008ec
-#define Ent_dsa_code_begin 0x00000000
-#define Ent_dsa_code_check_reselect 0x0000010c
-#define Ent_dsa_code_fix_jump 0x00000058
-#define Ent_dsa_code_restore_pointers 0x000000d8
-#define Ent_dsa_code_save_data_pointer 0x000000a4
-#define Ent_dsa_code_template 0x00000000
-#define Ent_dsa_code_template_end 0x00000178
-#define Ent_dsa_schedule 0x00000178
-#define Ent_dsa_zero 0x00000178
-#define Ent_end_data_transfer 0x000002a4
-#define Ent_initiator_abort 0x00000914
-#define Ent_msg_in 0x0000041c
-#define Ent_msg_in_restart 0x000003fc
-#define Ent_other_in 0x0000038c
-#define Ent_other_out 0x00000354
-#define Ent_other_transfer 0x000003c4
-#define Ent_reject_message 0x00000604
-#define Ent_reselected_check_next 0x000006f0
-#define Ent_reselected_ok 0x00000798
-#define Ent_respond_message 0x0000063c
-#define Ent_select 0x000001f8
-#define Ent_select_msgout 0x00000218
-#define Ent_target_abort 0x000008f4
-#define Ent_test_1 0x00000868
-#define Ent_test_2 0x0000087c
-#define Ent_test_2_msgout 0x0000089c
-#define Ent_wait_reselect 0x000006a8
-static u32 LABELPATCHES[] __attribute((unused)) = {
- 0x00000011,
- 0x0000001a,
- 0x0000001d,
- 0x00000028,
- 0x0000002a,
- 0x00000035,
- 0x00000038,
- 0x00000042,
- 0x00000050,
- 0x00000052,
- 0x0000006b,
- 0x00000083,
- 0x00000085,
- 0x00000090,
- 0x00000094,
- 0x00000096,
- 0x0000009c,
- 0x0000009e,
- 0x000000a2,
- 0x000000a4,
- 0x000000a6,
- 0x000000a8,
- 0x000000b6,
- 0x000000b9,
- 0x000000cc,
- 0x000000cf,
- 0x000000d8,
- 0x000000de,
- 0x000000e0,
- 0x000000e6,
- 0x000000ec,
- 0x000000ee,
- 0x000000f4,
- 0x000000fc,
- 0x000000fe,
- 0x0000010a,
- 0x0000010c,
- 0x0000010e,
- 0x00000110,
- 0x00000112,
- 0x00000118,
- 0x0000011a,
- 0x0000012d,
- 0x00000143,
- 0x00000158,
- 0x0000015c,
- 0x00000164,
- 0x00000166,
- 0x00000168,
- 0x0000016e,
- 0x0000017a,
- 0x000001ab,
- 0x000001b8,
- 0x000001bf,
- 0x000001c3,
- 0x000001c7,
- 0x000001cb,
- 0x000001e0,
- 0x000001f8,
- 0x00000207,
- 0x0000020f,
- 0x00000213,
- 0x00000217,
- 0x00000224,
- 0x00000226,
- 0x00000248,
- 0x0000024a,
- 0x0000024c,
- 0x0000024e,
- 0x00000250,
- 0x00000252,
- 0x00000256,
- 0x0000025a,
- 0x0000025c,
- 0x00000260,
- 0x00000262,
- 0x00000266,
- 0x00000268,
-};
-
-static struct {
- u32 offset;
- void *address;
-} EXTERNAL_PATCHES[] __attribute((unused)) = {
-};
-
-static u32 INSTRUCTIONS __attribute((unused)) = 290;
-static u32 PATCHES __attribute((unused)) = 78;
-static u32 EXTERNAL_PATCHES_LEN __attribute((unused)) = 0;
diff --git a/drivers/scsi/53c7xx_u.h_shipped b/drivers/scsi/53c7xx_u.h_shipped
deleted file mode 100644
index 7b337174e228..000000000000
--- a/drivers/scsi/53c7xx_u.h_shipped
+++ /dev/null
@@ -1,102 +0,0 @@
-#undef A_NCR53c7xx_msg_abort
-#undef A_NCR53c7xx_msg_reject
-#undef A_NCR53c7xx_sink
-#undef A_NCR53c7xx_zero
-#undef A_NOP_insn
-#undef A_addr_dsa
-#undef A_addr_reconnect_dsa_head
-#undef A_addr_scratch
-#undef A_addr_temp
-#undef A_dmode_memory_to_memory
-#undef A_dmode_memory_to_ncr
-#undef A_dmode_ncr_to_memory
-#undef A_dsa_check_reselect
-#undef A_dsa_cmdout
-#undef A_dsa_cmnd
-#undef A_dsa_datain
-#undef A_dsa_dataout
-#undef A_dsa_end
-#undef A_dsa_fields_start
-#undef A_dsa_msgin
-#undef A_dsa_msgout
-#undef A_dsa_msgout_other
-#undef A_dsa_next
-#undef A_dsa_restore_pointers
-#undef A_dsa_save_data_pointer
-#undef A_dsa_select
-#undef A_dsa_sscf_710
-#undef A_dsa_status
-#undef A_dsa_temp_addr_array_value
-#undef A_dsa_temp_addr_dsa_value
-#undef A_dsa_temp_addr_new_value
-#undef A_dsa_temp_addr_next
-#undef A_dsa_temp_addr_residual
-#undef A_dsa_temp_addr_saved_pointer
-#undef A_dsa_temp_addr_saved_residual
-#undef A_dsa_temp_lun
-#undef A_dsa_temp_next
-#undef A_dsa_temp_sync
-#undef A_dsa_temp_target
-#undef A_emulfly
-#undef A_int_debug_break
-#undef A_int_debug_panic
-#undef A_int_err_check_condition
-#undef A_int_err_no_phase
-#undef A_int_err_selected
-#undef A_int_err_unexpected_phase
-#undef A_int_err_unexpected_reselect
-#undef A_int_msg_1
-#undef A_int_msg_sdtr
-#undef A_int_msg_wdtr
-#undef A_int_norm_aborted
-#undef A_int_norm_command_complete
-#undef A_int_norm_disconnected
-#undef A_int_norm_emulateintfly
-#undef A_int_norm_reselect_complete
-#undef A_int_norm_reset
-#undef A_int_norm_select_complete
-#undef A_int_test_1
-#undef A_int_test_2
-#undef A_int_test_3
-#undef A_msg_buf
-#undef A_reconnect_dsa_head
-#undef A_reselected_identify
-#undef A_reselected_tag
-#undef A_saved_dsa
-#undef A_schedule
-#undef A_test_dest
-#undef A_test_src
-#undef Ent_accept_message
-#undef Ent_cmdout_cmdout
-#undef Ent_command_complete
-#undef Ent_command_complete_msgin
-#undef Ent_data_transfer
-#undef Ent_datain_to_jump
-#undef Ent_debug_break
-#undef Ent_dsa_code_begin
-#undef Ent_dsa_code_check_reselect
-#undef Ent_dsa_code_fix_jump
-#undef Ent_dsa_code_restore_pointers
-#undef Ent_dsa_code_save_data_pointer
-#undef Ent_dsa_code_template
-#undef Ent_dsa_code_template_end
-#undef Ent_dsa_schedule
-#undef Ent_dsa_zero
-#undef Ent_end_data_transfer
-#undef Ent_initiator_abort
-#undef Ent_msg_in
-#undef Ent_msg_in_restart
-#undef Ent_other_in
-#undef Ent_other_out
-#undef Ent_other_transfer
-#undef Ent_reject_message
-#undef Ent_reselected_check_next
-#undef Ent_reselected_ok
-#undef Ent_respond_message
-#undef Ent_select
-#undef Ent_select_msgout
-#undef Ent_target_abort
-#undef Ent_test_1
-#undef Ent_test_2
-#undef Ent_test_2_msgout
-#undef Ent_wait_reselect
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 96f4cab07614..9b206176f717 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -304,18 +304,10 @@ static struct BusLogic_CCB *BusLogic_AllocateCCB(struct BusLogic_HostAdapter
static void BusLogic_DeallocateCCB(struct BusLogic_CCB *CCB)
{
struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter;
- struct scsi_cmnd *cmd = CCB->Command;
- if (cmd->use_sg != 0) {
- pci_unmap_sg(HostAdapter->PCI_Device,
- (struct scatterlist *)cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen != 0) {
- pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer,
- CCB->DataLength, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(CCB->Command);
pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer,
- CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
+ CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
CCB->Command = NULL;
CCB->Status = BusLogic_CCB_Free;
@@ -2648,7 +2640,8 @@ static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapt
*/
if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) {
struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[CCB->TargetID];
- struct SCSI_Inquiry *InquiryResult = (struct SCSI_Inquiry *) Command->request_buffer;
+ struct SCSI_Inquiry *InquiryResult =
+ (struct SCSI_Inquiry *) scsi_sglist(Command);
TargetFlags->TargetExists = true;
TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue;
TargetFlags->WideTransfersSupported = InquiryResult->WBus16;
@@ -2819,9 +2812,8 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
int CDB_Length = Command->cmd_len;
int TargetID = Command->device->id;
int LogicalUnit = Command->device->lun;
- void *BufferPointer = Command->request_buffer;
- int BufferLength = Command->request_bufflen;
- int SegmentCount = Command->use_sg;
+ int BufferLength = scsi_bufflen(Command);
+ int Count;
struct BusLogic_CCB *CCB;
/*
SCSI REQUEST_SENSE commands will be executed automatically by the Host
@@ -2851,36 +2843,35 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
return 0;
}
}
+
/*
Initialize the fields in the BusLogic Command Control Block (CCB).
*/
- if (SegmentCount == 0 && BufferLength != 0) {
- CCB->Opcode = BusLogic_InitiatorCCB;
- CCB->DataLength = BufferLength;
- CCB->DataPointer = pci_map_single(HostAdapter->PCI_Device,
- BufferPointer, BufferLength,
- Command->sc_data_direction);
- } else if (SegmentCount != 0) {
- struct scatterlist *ScatterList = (struct scatterlist *) BufferPointer;
- int Segment, Count;
-
- Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount,
- Command->sc_data_direction);
+ Count = scsi_dma_map(Command);
+ BUG_ON(Count < 0);
+ if (Count) {
+ struct scatterlist *sg;
+ int i;
+
CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment);
if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
CCB->DataPointer = (unsigned int) CCB->DMA_Handle + ((unsigned long) &CCB->ScatterGatherList - (unsigned long) CCB);
else
CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList);
- for (Segment = 0; Segment < Count; Segment++) {
- CCB->ScatterGatherList[Segment].SegmentByteCount = sg_dma_len(ScatterList + Segment);
- CCB->ScatterGatherList[Segment].SegmentDataPointer = sg_dma_address(ScatterList + Segment);
+
+ scsi_for_each_sg(Command, sg, Count, i) {
+ CCB->ScatterGatherList[i].SegmentByteCount =
+ sg_dma_len(sg);
+ CCB->ScatterGatherList[i].SegmentDataPointer =
+ sg_dma_address(sg);
}
- } else {
+ } else if (!Count) {
CCB->Opcode = BusLogic_InitiatorCCB;
CCB->DataLength = BufferLength;
CCB->DataPointer = 0;
}
+
switch (CDB[0]) {
case READ_6:
case READ_10:
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index eb46cb0e3cb7..d2b3898b750a 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -10,6 +10,7 @@ config RAID_ATTRS
config SCSI
tristate "SCSI device support"
depends on BLOCK
+ select SCSI_DMA if HAS_DMA
---help---
If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
any other SCSI device under Linux, say Y and make sure that you know
@@ -29,6 +30,10 @@ config SCSI
However, do not compile this as a module if your root file system
(the one containing the directory /) is located on a SCSI device.
+config SCSI_DMA
+ bool
+ default n
+
config SCSI_TGT
tristate "SCSI target support"
depends on SCSI && EXPERIMENTAL
@@ -277,7 +282,7 @@ config SCSI_ISCSI_ATTRS
config SCSI_SAS_ATTRS
tristate "SAS Transport Attributes"
- depends on SCSI
+ depends on SCSI && BLK_DEV_BSG
help
If you wish to export transport-specific information about
each attached SAS device to sysfs, say Y.
@@ -286,8 +291,12 @@ source "drivers/scsi/libsas/Kconfig"
endmenu
-menu "SCSI low-level drivers"
+menuconfig SCSI_LOWLEVEL
+ bool "SCSI low-level drivers"
depends on SCSI!=n
+ default y
+
+if SCSI_LOWLEVEL
config ISCSI_TCP
tristate "iSCSI Initiator over TCP/IP"
@@ -478,7 +487,7 @@ source "drivers/scsi/aic94xx/Kconfig"
# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
tristate "Adaptec I2O RAID support "
- depends on !64BIT && SCSI && PCI
+ depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
help
This driver supports all of Adaptec's I2O based RAID controllers as
well as the DPT SmartRaid V cards. This is an Adaptec maintained
@@ -540,7 +549,7 @@ config SCSI_HPTIOP
config SCSI_BUSLOGIC
tristate "BusLogic SCSI support"
- depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API
+ depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API && VIRT_TO_BUS
---help---
This is support for BusLogic MultiMaster and FlashPoint SCSI Host
Adapters. Consult the SCSI-HOWTO, available from
@@ -739,7 +748,7 @@ config SCSI_GENERIC_NCR53C400
config SCSI_IBMMCA
tristate "IBMMCA SCSI support"
- depends on MCA_LEGACY && SCSI
+ depends on MCA && SCSI
---help---
This is support for the IBM SCSI adapter found in many of the PS/2
series computers. These machines have an MCA bus, so you need to
@@ -1007,6 +1016,11 @@ config SCSI_STEX
To compile this driver as a module, choose M here: the
module will be called stex.
+config 53C700_BE_BUS
+ bool
+ depends on SCSI_A4000T || SCSI_ZORRO7XX || MVME16x_SCSI || BVME6000_SCSI
+ default y
+
config SCSI_SYM53C8XX_2
tristate "SYM53C8XX Version 2 SCSI support"
depends on PCI && SCSI
@@ -1611,13 +1625,25 @@ config FASTLANE_SCSI
If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
one in the near future, say Y to this question. Otherwise, say N.
-config SCSI_AMIGA7XX
- bool "Amiga NCR53c710 SCSI support (EXPERIMENTAL)"
- depends on AMIGA && SCSI && EXPERIMENTAL && BROKEN
+config SCSI_A4000T
+ tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)"
+ depends on AMIGA && SCSI && EXPERIMENTAL
+ select SCSI_SPI_ATTRS
help
- Support for various NCR53c710-based SCSI controllers on the Amiga.
+ If you have an Amiga 4000T and have SCSI devices connected to the
+ built-in SCSI controller, say Y. Otherwise, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called a4000t.
+
+config SCSI_ZORRO7XX
+ tristate "Zorro NCR53c710 SCSI support (EXPERIMENTAL)"
+ depends on ZORRO && SCSI && EXPERIMENTAL
+ select SCSI_SPI_ATTRS
+ help
+ Support for various NCR53c710-based SCSI controllers on Zorro
+ expansion boards for the Amiga.
This includes:
- - the builtin SCSI controller on the Amiga 4000T,
- the Amiga 4091 Zorro III SCSI-2 controller,
- the MacroSystem Development's WarpEngine Amiga SCSI-2 controller
(info at
@@ -1625,10 +1651,6 @@ config SCSI_AMIGA7XX
- the SCSI controller on the Phase5 Blizzard PowerUP 603e+
accelerator card for the Amiga 1200,
- the SCSI controller on the GVP Turbo 040/060 accelerator.
- Note that all of the above SCSI controllers, except for the builtin
- SCSI controller on the Amiga 4000T, reside on the Zorro expansion
- bus, so you also have to enable Zorro bus support if you want to use
- them.
config OKTAGON_SCSI
tristate "BSC Oktagon SCSI support (EXPERIMENTAL)"
@@ -1712,8 +1734,8 @@ config MVME147_SCSI
single-board computer.
config MVME16x_SCSI
- bool "NCR53C710 SCSI driver for MVME16x"
- depends on MVME16x && SCSI && BROKEN
+ tristate "NCR53C710 SCSI driver for MVME16x"
+ depends on MVME16x && SCSI
select SCSI_SPI_ATTRS
help
The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
@@ -1721,22 +1743,14 @@ config MVME16x_SCSI
will want to say Y to this question.
config BVME6000_SCSI
- bool "NCR53C710 SCSI driver for BVME6000"
- depends on BVME6000 && SCSI && BROKEN
+ tristate "NCR53C710 SCSI driver for BVME6000"
+ depends on BVME6000 && SCSI
select SCSI_SPI_ATTRS
help
The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
SCSI controller chip. Almost everyone using one of these boards
will want to say Y to this question.
-config SCSI_NCR53C7xx_FAST
- bool "allow FAST-SCSI [10MHz]"
- depends on SCSI_AMIGA7XX || MVME16x_SCSI || BVME6000_SCSI
- help
- This will enable 10MHz FAST-SCSI transfers with your host
- adapter. Some systems have problems with that speed, so it's safest
- to say N here.
-
config SUN3_SCSI
tristate "Sun3 NCR5380 SCSI"
depends on SUN3 && SCSI
@@ -1766,8 +1780,6 @@ config SCSI_SUNESP
To compile this driver as a module, choose M here: the
module will be called esp.
-# bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
-
config ZFCP
tristate "FCP host bus adapter driver for IBM eServer zSeries"
depends on S390 && QDIO && SCSI
@@ -1792,7 +1804,7 @@ config SCSI_SRP
To compile this driver as a module, choose M here: the
module will be called libsrp.
-endmenu
+endif # SCSI_LOWLEVEL
source "drivers/scsi/pcmcia/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index b1b632791580..86a7ba7bad63 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -37,7 +37,8 @@ obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
-obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
+obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o
+obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o
@@ -53,8 +54,8 @@ obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o
obj-$(CONFIG_MAC_SCSI) += mac_scsi.o
obj-$(CONFIG_SCSI_MAC_ESP) += mac_esp.o NCR53C9x.o
obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o
-obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o
-obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o
+obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o
+obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o
obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o
obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o
obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
@@ -89,7 +90,6 @@ obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
-obj-$(CONFIG_SCSI_FD_8xx) += seagate.o
obj-$(CONFIG_SCSI_T128) += t128.o
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
obj-$(CONFIG_SCSI_DTC3280) += dtc.o
@@ -132,6 +132,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
obj-$(CONFIG_SCSI_STEX) += stex.o
+obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_ARM) += arm/
@@ -148,9 +149,9 @@ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
obj-$(CONFIG_SCSI_WAIT_SCAN) += scsi_wait_scan.o
scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
- scsicam.o scsi_error.o scsi_lib.o \
- scsi_scan.o scsi_sysfs.o \
- scsi_devinfo.o
+ scsicam.o scsi_error.o scsi_lib.o
+scsi_mod-$(CONFIG_SCSI_DMA) += scsi_lib_dma.o
+scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o
scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
@@ -168,10 +169,8 @@ NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o
oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
# Files generated that shall be removed upon make clean
-clean-files := 53c7xx_d.h 53c700_d.h \
- 53c7xx_u.h 53c700_u.h
+clean-files := 53c700_d.h 53c700_u.h
-$(obj)/53c7xx.o: $(obj)/53c7xx_d.h $(obj)/53c7xx_u.h
$(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h
# If you want to play with the firmware, uncomment
@@ -179,11 +178,6 @@ $(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h
ifdef GENERATE_FIRMWARE
-$(obj)/53c7xx_d.h: $(src)/53c7xx.scr $(src)/script_asm.pl
- $(CPP) -traditional -DCHIP=710 - < $< | grep -v '^#' | $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h)
-
-$(obj)/53c7xx_u.h: $(obj)/53c7xx_d.h
-
$(obj)/53c700_d.h: $(src)/53c700.scr $(src)/script_asm.pl
$(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) < $<
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 88ea5a1fb606..f8e449a98d29 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -347,7 +347,7 @@ static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, i
if((r & bit) == val)
return 0;
if(!in_interrupt())
- yield();
+ cond_resched();
else
cpu_relax();
}
@@ -357,7 +357,7 @@ static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, i
static struct {
unsigned char value;
const char *name;
-} phases[] = {
+} phases[] __maybe_unused = {
{PHASE_DATAOUT, "DATAOUT"},
{PHASE_DATAIN, "DATAIN"},
{PHASE_CMDOUT, "CMDOUT"},
@@ -575,7 +575,8 @@ static irqreturn_t __init probe_intr(int irq, void *dev_id)
* Locks: none, irqs must be enabled on entry
*/
-static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
+static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
+ int possible)
{
NCR5380_local_declare();
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
@@ -629,7 +630,8 @@ static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
* Locks: none
*/
-static void __init NCR5380_print_options(struct Scsi_Host *instance)
+static void __init __maybe_unused
+NCR5380_print_options(struct Scsi_Host *instance)
{
printk(" generic options"
#ifdef AUTOPROBE_IRQ
@@ -703,8 +705,8 @@ char *lprint_command(unsigned char *cmd, char *pos, char *buffer, int len);
static
char *lprint_opcode(int opcode, char *pos, char *buffer, int length);
-static
-int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset, int length, int inout)
+static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
+ char *buffer, char **start, off_t offset, int length, int inout)
{
char *pos = buffer;
struct NCR5380_hostdata *hostdata;
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index 713a108c02ef..bccf13f71532 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -299,7 +299,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance);
static irqreturn_t NCR5380_intr(int irq, void *dev_id);
#endif
static void NCR5380_main(struct work_struct *work);
-static void NCR5380_print_options(struct Scsi_Host *instance);
+static void __maybe_unused NCR5380_print_options(struct Scsi_Host *instance);
#ifdef NDEBUG
static void NCR5380_print_phase(struct Scsi_Host *instance);
static void NCR5380_print(struct Scsi_Host *instance);
@@ -307,8 +307,8 @@ static void NCR5380_print(struct Scsi_Host *instance);
static int NCR5380_abort(Scsi_Cmnd * cmd);
static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
-static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
-off_t offset, int length, int inout);
+static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance,
+ char *buffer, char **start, off_t offset, int length, int inout);
static void NCR5380_reselect(struct Scsi_Host *instance);
static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 8b5334c56f0a..79b4df158140 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -95,6 +95,8 @@ enum {
/* The master ring of all esp hosts we are managing in this driver. */
static struct NCR_ESP *espchain;
int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
irqreturn_t esp_intr(int irq, void *dev_id);
@@ -524,6 +526,7 @@ void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
/* Eat any bitrot in the chip and we are done... */
trash = esp_read(eregs->esp_intrpt);
}
+EXPORT_SYMBOL(esp_bootup_reset);
/* Allocate structure and insert basic data such as SCSI chip frequency
* data and a pointer to the device
@@ -772,6 +775,7 @@ const char *esp_info(struct Scsi_Host *host)
panic("Bogon ESP revision");
};
}
+EXPORT_SYMBOL(esp_info);
/* From Wolfgang Stanglmeier's NCR scsi driver. */
struct info_str
@@ -902,6 +906,7 @@ int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t off
*start = buffer;
return esp_host_info(esp, buffer, offset, length);
}
+EXPORT_SYMBOL(esp_proc_info);
static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
@@ -3535,6 +3540,7 @@ state_machine:
if(esp->dma_irq_exit)
esp->dma_irq_exit(esp);
}
+EXPORT_SYMBOL(esp_handle);
#ifndef CONFIG_SMP
irqreturn_t esp_intr(int irq, void *dev_id)
@@ -3606,11 +3612,10 @@ out:
int esp_slave_alloc(struct scsi_device *SDptr)
{
struct esp_device *esp_dev =
- kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+ kzalloc(sizeof(struct esp_device), GFP_ATOMIC);
if (!esp_dev)
return -ENOMEM;
- memset(esp_dev, 0, sizeof(struct esp_device));
SDptr->hostdata = esp_dev;
return 0;
}
@@ -3632,6 +3637,7 @@ void esp_release(void)
esps_in_use--;
esps_running = esps_in_use;
}
+EXPORT_SYMBOL(esp_release);
#endif
EXPORT_SYMBOL(esp_abort);
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 7c0b17f86903..eda8c48f6be7 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -698,7 +698,7 @@ static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
int i;
VDEB(printk("NCR53c406a_queue called\n"));
- DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->target, SCpnt->lun, SCpnt->request_bufflen));
+ DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->target, SCpnt->lun, scsi_bufflen(SCpnt)));
#if 0
VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
@@ -785,8 +785,8 @@ static void NCR53c406a_intr(void *dev_id)
unsigned char status, int_reg;
#if USE_PIO
unsigned char pio_status;
- struct scatterlist *sglist;
- unsigned int sgcount;
+ struct scatterlist *sg;
+ int i;
#endif
VDEB(printk("NCR53c406a_intr called\n"));
@@ -866,22 +866,18 @@ static void NCR53c406a_intr(void *dev_id)
current_SC->SCp.phase = data_out;
VDEB(printk("NCR53c406a: Data-Out phase\n"));
outb(FLUSH_FIFO, CMD_REG);
- LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */
#if USE_DMA /* No s/g support for DMA */
- NCR53c406a_dma_write(current_SC->request_buffer, current_SC->request_bufflen);
+ NCR53c406a_dma_write(scsi_sglist(current_SC),
+ scsdi_bufflen(current_SC));
+
#endif /* USE_DMA */
outb(TRANSFER_INFO | DMA_OP, CMD_REG);
#if USE_PIO
- if (!current_SC->use_sg) /* Don't use scatter-gather */
- NCR53c406a_pio_write(current_SC->request_buffer, current_SC->request_bufflen);
- else { /* use scatter-gather */
- sgcount = current_SC->use_sg;
- sglist = current_SC->request_buffer;
- while (sgcount--) {
- NCR53c406a_pio_write(page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
- }
+ scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
+ NCR53c406a_pio_write(page_address(sg->page) + sg->offset,
+ sg->length);
+ }
REG0;
#endif /* USE_PIO */
}
@@ -893,22 +889,17 @@ static void NCR53c406a_intr(void *dev_id)
current_SC->SCp.phase = data_in;
VDEB(printk("NCR53c406a: Data-In phase\n"));
outb(FLUSH_FIFO, CMD_REG);
- LOAD_DMA_COUNT(current_SC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */
#if USE_DMA /* No s/g support for DMA */
- NCR53c406a_dma_read(current_SC->request_buffer, current_SC->request_bufflen);
+ NCR53c406a_dma_read(scsi_sglist(current_SC),
+ scsdi_bufflen(current_SC));
#endif /* USE_DMA */
outb(TRANSFER_INFO | DMA_OP, CMD_REG);
#if USE_PIO
- if (!current_SC->use_sg) /* Don't use scatter-gather */
- NCR53c406a_pio_read(current_SC->request_buffer, current_SC->request_bufflen);
- else { /* Use scatter-gather */
- sgcount = current_SC->use_sg;
- sglist = current_SC->request_buffer;
- while (sgcount--) {
- NCR53c406a_pio_read(page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
- }
+ scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) {
+ NCR53c406a_pio_read(page_address(sg->page) + sg->offset,
+ sg->length);
+ }
REG0;
#endif /* USE_PIO */
}
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index f12864abed2f..3a8089705feb 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -181,13 +181,12 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
struct Scsi_Host *host;
int ret;
- hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+ hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host"
"data, detatching\n", siop);
return -ENOMEM;
}
- memset(hostdata, 0, sizeof(*hostdata));
if (!request_region(region, 64, "NCR_D700")) {
printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n",
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index 778844c3544a..a8bbdc2273b8 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -148,11 +148,10 @@ NCR_Q720_probe(struct device *dev)
__u32 base_addr, mem_size;
void __iomem *mem_base;
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
- memset(p, 0, sizeof(*p));
pos2 = mca_device_read_pos(mca_dev, 2);
/* enable device */
pos2 |= NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE;
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 7f4241bfb9c4..f608d4a1d6da 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -19,27 +19,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -75,6 +54,8 @@
* 9/28/04 Christoph Hellwig <hch@lst.de>
* - merge the two source files
* - remove internal queueing code
+ * 14/06/07 Alan Cox <alan@redhat.com>
+ * - Grand cleanup and Linuxisation
*/
#include <linux/module.h>
@@ -102,14 +83,12 @@
#include "a100u2w.h"
-#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
-#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
+static struct orc_scb *__orc_alloc_scb(struct orc_host * host);
+static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb);
-static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
-static void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
+static struct orc_nvram nvram, *nvramp = &nvram;
-static NVRAM nvram, *nvramp = &nvram;
-static UCHAR dftNvRam[64] =
+static u8 default_nvram[64] =
{
/*----------header -------------*/
0x01, /* 0x00: Sub System Vendor ID 0 */
@@ -158,823 +137,882 @@ static UCHAR dftNvRam[64] =
};
-/***************************************************************************/
-static void waitForPause(unsigned amount)
-{
- ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
- while (time_before_eq(jiffies, the_time))
- cpu_relax();
-}
-
-/***************************************************************************/
-static UCHAR waitChipReady(ORC_HCS * hcsp)
+static u8 wait_chip_ready(struct orc_host * host)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */
+ if (inb(host->base + ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */
return 1;
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100);
}
return 0;
}
-/***************************************************************************/
-static UCHAR waitFWReady(ORC_HCS * hcsp)
+static u8 wait_firmware_ready(struct orc_host * host)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) /* Wait READY set */
+ if (inb(host->base + ORC_HSTUS) & RREADY) /* Wait READY set */
return 1;
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp)
+static u8 wait_scsi_reset_done(struct orc_host * host)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */
+ if (!(inb(host->base + ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */
return 1;
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static UCHAR waitHDOoff(ORC_HCS * hcsp)
+static u8 wait_HDO_off(struct orc_host * host)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO)) /* Wait HDO off */
+ if (!(inb(host->base + ORC_HCTRL) & HDO)) /* Wait HDO off */
return 1;
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData)
+static u8 wait_hdi_set(struct orc_host * host, u8 * data)
{
int i;
for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */
- if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
+ if ((*data = inb(host->base + ORC_HSTUS)) & HDI)
return 1; /* Wait HDI set */
- waitForPause(100); /* wait 100ms before try again */
+ mdelay(100); /* wait 100ms before try again */
}
return 0;
}
/***************************************************************************/
-static unsigned short get_FW_version(ORC_HCS * hcsp)
+static unsigned short orc_read_fwrev(struct orc_host * host)
{
- UCHAR bData;
- union {
- unsigned short sVersion;
- unsigned char cVersion[2];
- } Version;
-
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION);
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ u16 version;
+ u8 data;
+
+ outb(ORC_CMD_VERSION, host->base + ORC_HDATA);
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ version = inb(host->base + ORC_HDATA);
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ version |= inb(host->base + ORC_HDATA) << 8;
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
- return (Version.sVersion);
+ return version;
}
/***************************************************************************/
-static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value)
+static u8 orc_nv_write(struct orc_host * host, unsigned char address, unsigned char value)
{
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM); /* Write command */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(ORC_CMD_SET_NVM, host->base + ORC_HDATA); /* Write command */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(address, host->base + ORC_HDATA); /* Write address */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, value); /* Write value */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(value, host->base + ORC_HDATA); /* Write value */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
return 1;
}
/***************************************************************************/
-static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn)
+static u8 orc_nv_read(struct orc_host * host, u8 address, u8 *ptr)
{
- unsigned char bData;
+ unsigned char data;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM); /* Write command */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(ORC_CMD_GET_NVM, host->base + ORC_HDATA); /* Write command */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, address); /* Write address */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(address, host->base + ORC_HDATA); /* Write address */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- *pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ *ptr = inb(host->base + ORC_HDATA);
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
return 1;
+
}
-/***************************************************************************/
-static void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+/**
+ * orc_exec_sb - Queue an SCB with the HA
+ * @host: host adapter the SCB belongs to
+ * @scb: SCB to queue for execution
+ */
+
+static void orc_exec_scb(struct orc_host * host, struct orc_scb * scb)
{
- scbp->SCB_Status = ORCSCB_POST;
- ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx);
- return;
+ scb->status = ORCSCB_POST;
+ outb(scb->scbidx, host->base + ORC_PQUEUE);
}
-/***********************************************************************
- Read SCSI H/A configuration parameters from serial EEPROM
-************************************************************************/
-static int se2_rd_all(ORC_HCS * hcsp)
+/**
+ * se2_rd_all - read SCSI parameters from EEPROM
+ * @host: Host whose EEPROM is being loaded
+ *
+ * Read SCSI H/A configuration parameters from serial EEPROM
+ */
+
+static int se2_rd_all(struct orc_host * host)
{
int i;
- UCHAR *np, chksum = 0;
+ u8 *np, chksum = 0;
- np = (UCHAR *) nvramp;
+ np = (u8 *) nvramp;
for (i = 0; i < 64; i++, np++) { /* <01> */
- if (get_NVRAM(hcsp, (unsigned char) i, np) == 0)
+ if (orc_nv_read(host, (u8) i, np) == 0)
return -1;
-// *np++ = get_NVRAM(hcsp, (unsigned char ) i);
}
-/*------ Is ckecksum ok ? ------*/
- np = (UCHAR *) nvramp;
+ /*------ Is ckecksum ok ? ------*/
+ np = (u8 *) nvramp;
for (i = 0; i < 63; i++)
chksum += *np++;
- if (nvramp->CheckSum != (UCHAR) chksum)
+ if (nvramp->CheckSum != (u8) chksum)
return -1;
return 1;
}
-/************************************************************************
- Update SCSI H/A configuration parameters from serial EEPROM
-*************************************************************************/
-static void se2_update_all(ORC_HCS * hcsp)
+/**
+ * se2_update_all - update the EEPROM
+ * @host: Host whose EEPROM is being updated
+ *
+ * Update changed bytes in the EEPROM image.
+ */
+
+static void se2_update_all(struct orc_host * host)
{ /* setup default pattern */
int i;
- UCHAR *np, *np1, chksum = 0;
+ u8 *np, *np1, chksum = 0;
/* Calculate checksum first */
- np = (UCHAR *) dftNvRam;
+ np = (u8 *) default_nvram;
for (i = 0; i < 63; i++)
chksum += *np++;
*np = chksum;
- np = (UCHAR *) dftNvRam;
- np1 = (UCHAR *) nvramp;
+ np = (u8 *) default_nvram;
+ np1 = (u8 *) nvramp;
for (i = 0; i < 64; i++, np++, np1++) {
- if (*np != *np1) {
- set_NVRAM(hcsp, (unsigned char) i, *np);
- }
+ if (*np != *np1)
+ orc_nv_write(host, (u8) i, *np);
}
- return;
}
-/*************************************************************************
- Function name : read_eeprom
-**************************************************************************/
-static void read_eeprom(ORC_HCS * hcsp)
+/**
+ * read_eeprom - load EEPROM
+ * @host: Host EEPROM to read
+ *
+ * Read the EEPROM for a given host. If it is invalid or fails
+ * the restore the defaults and use them.
+ */
+
+static void read_eeprom(struct orc_host * host)
{
- if (se2_rd_all(hcsp) != 1) {
- se2_update_all(hcsp); /* setup default pattern */
- se2_rd_all(hcsp); /* load again */
+ if (se2_rd_all(host) != 1) {
+ se2_update_all(host); /* setup default pattern */
+ se2_rd_all(host); /* load again */
}
}
-/***************************************************************************/
-static UCHAR load_FW(ORC_HCS * hcsp)
+/**
+ * orc_load_firmware - initialise firmware
+ * @host: Host to set up
+ *
+ * Load the firmware from the EEPROM into controller SRAM. This
+ * is basically a 4K block copy and then a 4K block read to check
+ * correctness. The rest is convulted by the indirect interfaces
+ * in the hardware
+ */
+
+static u8 orc_load_firmware(struct orc_host * host)
{
- U32 dData;
- USHORT wBIOSAddress;
- USHORT i;
- UCHAR *pData, bData;
-
-
- bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG);
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG); /* Enable EEPROM programming */
- ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00);
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00);
- if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) {
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */
+ u32 data32;
+ u16 bios_addr;
+ u16 i;
+ u8 *data32_ptr, data;
+
+
+ /* Set up the EEPROM for access */
+
+ data = inb(host->base + ORC_GCFG);
+ outb(data | EEPRG, host->base + ORC_GCFG); /* Enable EEPROM programming */
+ outb(0x00, host->base + ORC_EBIOSADR2);
+ outw(0x0000, host->base + ORC_EBIOSADR0);
+ if (inb(host->base + ORC_EBIOSDATA) != 0x55) {
+ outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */
return 0;
}
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01);
- if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) {
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */
+ outw(0x0001, host->base + ORC_EBIOSADR0);
+ if (inb(host->base + ORC_EBIOSDATA) != 0xAA) {
+ outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */
return 0;
}
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Enable SRAM programming */
- pData = (UCHAR *) & dData;
- dData = 0; /* Initial FW address to 0 */
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10);
- *pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11);
- *(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12);
- *(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
- ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2));
- ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData); /* Write FW address */
-
- wBIOSAddress = (USHORT) dData; /* FW code locate at BIOS address + ? */
- for (i = 0, pData = (UCHAR *) & dData; /* Download the code */
+
+ outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Enable SRAM programming */
+ data32_ptr = (u8 *) & data32;
+ data32 = 0; /* Initial FW address to 0 */
+ outw(0x0010, host->base + ORC_EBIOSADR0);
+ *data32_ptr = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
+ outw(0x0011, host->base + ORC_EBIOSADR0);
+ *(data32_ptr + 1) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
+ outw(0x0012, host->base + ORC_EBIOSADR0);
+ *(data32_ptr + 2) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
+ outw(*(data32_ptr + 2), host->base + ORC_EBIOSADR2);
+ outl(data32, host->base + ORC_FWBASEADR); /* Write FW address */
+
+ /* Copy the code from the BIOS to the SRAM */
+
+ bios_addr = (u16) data32; /* FW code locate at BIOS address + ? */
+ for (i = 0, data32_ptr = (u8 *) & data32; /* Download the code */
i < 0x1000; /* Firmware code size = 4K */
- i++, wBIOSAddress++) {
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
- *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
+ i++, bios_addr++) {
+ outw(bios_addr, host->base + ORC_EBIOSADR0);
+ *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
if ((i % 4) == 3) {
- ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData); /* Write every 4 bytes */
- pData = (UCHAR *) & dData;
+ outl(data32, host->base + ORC_RISCRAM); /* Write every 4 bytes */
+ data32_ptr = (u8 *) & data32;
}
}
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD); /* Reset program count 0 */
- wBIOSAddress -= 0x1000; /* Reset the BIOS adddress */
- for (i = 0, pData = (UCHAR *) & dData; /* Check the code */
+ /* Go back and check they match */
+
+ outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Reset program count 0 */
+ bios_addr -= 0x1000; /* Reset the BIOS adddress */
+ for (i = 0, data32_ptr = (u8 *) & data32; /* Check the code */
i < 0x1000; /* Firmware code size = 4K */
- i++, wBIOSAddress++) {
- ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
- *pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA); /* Read from BIOS */
+ i++, bios_addr++) {
+ outw(bios_addr, host->base + ORC_EBIOSADR0);
+ *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */
if ((i % 4) == 3) {
- if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) {
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /*Disable EEPROM programming */
+ if (inl(host->base + ORC_RISCRAM) != data32) {
+ outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */
+ outb(data, host->base + ORC_GCFG); /*Disable EEPROM programming */
return 0;
}
- pData = (UCHAR *) & dData;
+ data32_ptr = (u8 *) & data32;
}
}
- ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST); /* Reset program to 0 */
- ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData); /* Disable EEPROM programming */
+
+ /* Success */
+ outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */
+ outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */
return 1;
}
/***************************************************************************/
-static void setup_SCBs(ORC_HCS * hcsp)
+static void setup_SCBs(struct orc_host * host)
{
- ORC_SCB *pVirScb;
+ struct orc_scb *scb;
int i;
- ESCB *pVirEscb;
- dma_addr_t pPhysEscb;
+ struct orc_extended_scb *escb;
+ dma_addr_t escb_phys;
- /* Setup SCB HCS_Base and SCB Size registers */
- ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, ORC_MAXQUEUE); /* Total number of SCBs */
- /* SCB HCS_Base address 0 */
- ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray);
- /* SCB HCS_Base address 1 */
- ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray);
+ /* Setup SCB base and SCB Size registers */
+ outb(ORC_MAXQUEUE, host->base + ORC_SCBSIZE); /* Total number of SCBs */
+ /* SCB base address 0 */
+ outl(host->scb_phys, host->base + ORC_SCBBASE0);
+ /* SCB base address 1 */
+ outl(host->scb_phys, host->base + ORC_SCBBASE1);
/* setup scatter list address with one buffer */
- pVirScb = hcsp->HCS_virScbArray;
- pVirEscb = hcsp->HCS_virEscbArray;
+ scb = host->scb_virt;
+ escb = host->escb_virt;
for (i = 0; i < ORC_MAXQUEUE; i++) {
- pPhysEscb = (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
- pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
- pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
- pVirScb->SCB_EScb = pVirEscb;
- pVirScb->SCB_ScbIdx = i;
- pVirScb++;
- pVirEscb++;
+ escb_phys = (host->escb_phys + (sizeof(struct orc_extended_scb) * i));
+ scb->sg_addr = (u32) escb_phys;
+ scb->sense_addr = (u32) escb_phys;
+ scb->escb = escb;
+ scb->scbidx = i;
+ scb++;
+ escb++;
}
-
- return;
}
-/***************************************************************************/
-static void initAFlag(ORC_HCS * hcsp)
+/**
+ * init_alloc_map - initialise allocation map
+ * @host: host map to configure
+ *
+ * Initialise the allocation maps for this device. If the device
+ * is not quiescent the caller must hold the allocation lock
+ */
+
+static void init_alloc_map(struct orc_host * host)
{
- UCHAR i, j;
+ u8 i, j;
for (i = 0; i < MAX_CHANNELS; i++) {
for (j = 0; j < 8; j++) {
- hcsp->BitAllocFlag[i][j] = 0xffffffff;
+ host->allocation_map[i][j] = 0xffffffff;
}
}
}
-/***************************************************************************/
-static int init_orchid(ORC_HCS * hcsp)
+/**
+ * init_orchid - initialise the host adapter
+ * @host:host adapter to initialise
+ *
+ * Initialise the controller and if neccessary load the firmware.
+ *
+ * Returns -1 if the initialisation fails.
+ */
+
+static int init_orchid(struct orc_host * host)
{
- UBYTE *readBytep;
- USHORT revision;
- UCHAR i;
-
- initAFlag(hcsp);
- ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF); /* Disable all interrupt */
- if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) { /* Orchid is ready */
- revision = get_FW_version(hcsp);
+ u8 *ptr;
+ u16 revision;
+ u8 i;
+
+ init_alloc_map(host);
+ outb(0xFF, host->base + ORC_GIMSK); /* Disable all interrupts */
+
+ if (inb(host->base + ORC_HSTUS) & RREADY) { /* Orchid is ready */
+ revision = orc_read_fwrev(host);
if (revision == 0xFFFF) {
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */
- if (waitChipReady(hcsp) == 0)
- return (-1);
- load_FW(hcsp); /* Download FW */
- setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0); /* clear HOSTSTOP */
- if (waitFWReady(hcsp) == 0)
- return (-1);
+ outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */
+ if (wait_chip_ready(host) == 0)
+ return -1;
+ orc_load_firmware(host); /* Download FW */
+ setup_SCBs(host); /* Setup SCB base and SCB Size registers */
+ outb(0x00, host->base + ORC_HCTRL); /* clear HOSTSTOP */
+ if (wait_firmware_ready(host) == 0)
+ return -1;
/* Wait for firmware ready */
} else {
- setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */
+ setup_SCBs(host); /* Setup SCB base and SCB Size registers */
}
} else { /* Orchid is not Ready */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST); /* Reset Host Adapter */
- if (waitChipReady(hcsp) == 0)
- return (-1);
- load_FW(hcsp); /* Download FW */
- setup_SCBs(hcsp); /* Setup SCB HCS_Base and SCB Size registers */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO); /* Do Hardware Reset & */
+ outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */
+ if (wait_chip_ready(host) == 0)
+ return -1;
+ orc_load_firmware(host); /* Download FW */
+ setup_SCBs(host); /* Setup SCB base and SCB Size registers */
+ outb(HDO, host->base + ORC_HCTRL); /* Do Hardware Reset & */
/* clear HOSTSTOP */
- if (waitFWReady(hcsp) == 0) /* Wait for firmware ready */
- return (-1);
+ if (wait_firmware_ready(host) == 0) /* Wait for firmware ready */
+ return -1;
}
-/*------------- get serial EEProm settting -------*/
-
- read_eeprom(hcsp);
-
- if (nvramp->Revision != 1)
- return (-1);
+ /* Load an EEProm copy into RAM */
+ /* Assumes single threaded at this point */
+ read_eeprom(host);
- hcsp->HCS_SCSI_ID = nvramp->SCSI0Id;
- hcsp->HCS_BIOS = nvramp->BIOSConfig1;
- hcsp->HCS_MaxTar = MAX_TARGETS;
- readBytep = (UCHAR *) & (nvramp->Target00Config);
- for (i = 0; i < 16; readBytep++, i++) {
- hcsp->TargetFlag[i] = *readBytep;
- hcsp->MaximumTags[i] = ORC_MAXTAGS;
- } /* for */
+ if (nvramp->revision != 1)
+ return -1;
- if (nvramp->SCSI0Config & NCC_BUSRESET) { /* Reset SCSI bus */
- hcsp->HCS_Flags |= HCF_SCSI_RESET;
+ host->scsi_id = nvramp->scsi_id;
+ host->BIOScfg = nvramp->BIOSConfig1;
+ host->max_targets = MAX_TARGETS;
+ ptr = (u8 *) & (nvramp->Target00Config);
+ for (i = 0; i < 16; ptr++, i++) {
+ host->target_flag[i] = *ptr;
+ host->max_tags[i] = ORC_MAXTAGS;
}
- ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB); /* enable RP FIFO interrupt */
- return (0);
+
+ if (nvramp->SCSI0Config & NCC_BUSRESET)
+ host->flags |= HCF_SCSI_RESET;
+ outb(0xFB, host->base + ORC_GIMSK); /* enable RP FIFO interrupt */
+ return 0;
}
-/*****************************************************************************
- Function name : orc_reset_scsi_bus
- Description : Reset registers, reset a hanging bus and
- kill active and disconnected commands for target w/o soft reset
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int orc_reset_scsi_bus(ORC_HCS * pHCB)
+/**
+ * orc_reset_scsi_bus - perform bus reset
+ * @host: host being reset
+ *
+ * Perform a full bus reset on the adapter.
+ */
+
+static int orc_reset_scsi_bus(struct orc_host * host)
{ /* I need Host Control Block Information */
- ULONG flags;
+ unsigned long flags;
- spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
+ spin_lock_irqsave(&host->allocation_lock, flags);
- initAFlag(pHCB);
+ init_alloc_map(host);
/* reset scsi bus */
- ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST);
- if (waitSCSIRSTdone(pHCB) == 0) {
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+ outb(SCSIRST, host->base + ORC_HCTRL);
+ /* FIXME: We can spend up to a second with the lock held and
+ interrupts off here */
+ if (wait_scsi_reset_done(host) == 0) {
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return FAILED;
} else {
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return SUCCESS;
}
}
-/*****************************************************************************
- Function name : orc_device_reset
- Description : Reset registers, reset a hanging bus and
- kill active and disconnected commands for target w/o soft reset
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int orc_device_reset(ORC_HCS * pHCB, struct scsi_cmnd *SCpnt, unsigned int target)
+/**
+ * orc_device_reset - device reset handler
+ * @host: host to reset
+ * @cmd: command causing the reset
+ * @target; target device
+ *
+ * Reset registers, reset a hanging bus and kill active and disconnected
+ * commands for target w/o soft reset
+ */
+
+static int orc_device_reset(struct orc_host * host, struct scsi_cmnd *cmd, unsigned int target)
{ /* I need Host Control Block Information */
- ORC_SCB *pScb;
- ESCB *pVirEscb;
- ORC_SCB *pVirScb;
- UCHAR i;
- ULONG flags;
+ struct orc_scb *scb;
+ struct orc_extended_scb *escb;
+ struct orc_scb *host_scb;
+ u8 i;
+ unsigned long flags;
- spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
- pScb = (ORC_SCB *) NULL;
- pVirEscb = (ESCB *) NULL;
+ spin_lock_irqsave(&(host->allocation_lock), flags);
+ scb = (struct orc_scb *) NULL;
+ escb = (struct orc_extended_scb *) NULL;
/* setup scatter list address with one buffer */
- pVirScb = pHCB->HCS_virScbArray;
+ host_scb = host->scb_virt;
+
+ /* FIXME: is this safe if we then fail to issue the reset or race
+ a completion ? */
+ init_alloc_map(host);
- initAFlag(pHCB);
- /* device reset */
+ /* Find the scb corresponding to the command */
for (i = 0; i < ORC_MAXQUEUE; i++) {
- pVirEscb = pVirScb->SCB_EScb;
- if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt))
+ escb = host_scb->escb;
+ if (host_scb->status && escb->srb == cmd)
break;
- pVirScb++;
+ host_scb++;
}
if (i == ORC_MAXQUEUE) {
- printk("Unable to Reset - No SCB Found\n");
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+ printk(KERN_ERR "Unable to Reset - No SCB Found\n");
+ spin_unlock_irqrestore(&(host->allocation_lock), flags);
return FAILED;
}
- if ((pScb = orc_alloc_scb(pHCB)) == NULL) {
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+
+ /* Allocate a new SCB for the reset command to the firmware */
+ if ((scb = __orc_alloc_scb(host)) == NULL) {
+ /* Can't happen.. */
+ spin_unlock_irqrestore(&(host->allocation_lock), flags);
return FAILED;
}
- pScb->SCB_Opcode = ORC_BUSDEVRST;
- pScb->SCB_Target = target;
- pScb->SCB_HaStat = 0;
- pScb->SCB_TaStat = 0;
- pScb->SCB_Status = 0x0;
- pScb->SCB_Link = 0xFF;
- pScb->SCB_Reserved0 = 0;
- pScb->SCB_Reserved1 = 0;
- pScb->SCB_XferLen = 0;
- pScb->SCB_SGLen = 0;
-
- pVirEscb->SCB_Srb = NULL;
- pVirEscb->SCB_Srb = SCpnt;
- orc_exec_scb(pHCB, pScb); /* Start execute SCB */
- spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+
+ /* Reset device is handled by the firmare, we fill in an SCB and
+ fire it at the controller, it does the rest */
+ scb->opcode = ORC_BUSDEVRST;
+ scb->target = target;
+ scb->hastat = 0;
+ scb->tastat = 0;
+ scb->status = 0x0;
+ scb->link = 0xFF;
+ scb->reserved0 = 0;
+ scb->reserved1 = 0;
+ scb->xferlen = 0;
+ scb->sg_len = 0;
+
+ escb->srb = NULL;
+ escb->srb = cmd;
+ orc_exec_scb(host, scb); /* Start execute SCB */
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return SUCCESS;
}
+/**
+ * __orc_alloc_scb - allocate an SCB
+ * @host: host to allocate from
+ *
+ * Allocate an SCB and return a pointer to the SCB object. NULL
+ * is returned if no SCB is free. The caller must already hold
+ * the allocator lock at this point.
+ */
-/***************************************************************************/
-static ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp)
+
+static struct orc_scb *__orc_alloc_scb(struct orc_host * host)
{
- ORC_SCB *pTmpScb;
- UCHAR Ch;
- ULONG idx;
- UCHAR index;
- UCHAR i;
+ u8 channel;
+ unsigned long idx;
+ u8 index;
+ u8 i;
- Ch = hcsp->HCS_Index;
+ channel = host->index;
for (i = 0; i < 8; i++) {
for (index = 0; index < 32; index++) {
- if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) {
- hcsp->BitAllocFlag[Ch][i] &= ~(1 << index);
+ if ((host->allocation_map[channel][i] >> index) & 0x01) {
+ host->allocation_map[channel][i] &= ~(1 << index);
break;
}
}
idx = index + 32 * i;
- pTmpScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB)));
- return (pTmpScb);
+ /* Translate the index to a structure instance */
+ return (struct orc_scb *) ((unsigned long) host->scb_virt + (idx * sizeof(struct orc_scb)));
}
- return (NULL);
+ return NULL;
}
-static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp)
+/**
+ * orc_alloc_scb - allocate an SCB
+ * @host: host to allocate from
+ *
+ * Allocate an SCB and return a pointer to the SCB object. NULL
+ * is returned if no SCB is free.
+ */
+
+static struct orc_scb *orc_alloc_scb(struct orc_host * host)
{
- ORC_SCB *pTmpScb;
- ULONG flags;
+ struct orc_scb *scb;
+ unsigned long flags;
- spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
- pTmpScb = __orc_alloc_scb(hcsp);
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
- return (pTmpScb);
+ spin_lock_irqsave(&host->allocation_lock, flags);
+ scb = __orc_alloc_scb(host);
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
+ return scb;
}
+/**
+ * orc_release_scb - release an SCB
+ * @host: host owning the SCB
+ * @scb: SCB that is now free
+ *
+ * Called to return a completed SCB to the allocation pool. Before
+ * calling the SCB must be out of use on both the host and the HA.
+ */
-/***************************************************************************/
-static void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+static void orc_release_scb(struct orc_host *host, struct orc_scb *scb)
{
- ULONG flags;
- UCHAR Index;
- UCHAR i;
- UCHAR Ch;
-
- spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
- Ch = hcsp->HCS_Index;
- Index = scbp->SCB_ScbIdx;
- i = Index / 32;
- Index %= 32;
- hcsp->BitAllocFlag[Ch][i] |= (1 << Index);
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+ unsigned long flags;
+ u8 index, i, channel;
+
+ spin_lock_irqsave(&(host->allocation_lock), flags);
+ channel = host->index; /* Channel */
+ index = scb->scbidx;
+ i = index / 32;
+ index %= 32;
+ host->allocation_map[channel][i] |= (1 << index);
+ spin_unlock_irqrestore(&(host->allocation_lock), flags);
}
-/*****************************************************************************
- Function name : abort_SCB
- Description : Abort a queued command.
- (commands that are on the bus can't be aborted easily)
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb)
+/**
+ * orchid_abort_scb - abort a command
+ *
+ * Abort a queued command that has been passed to the firmware layer
+ * if possible. This is all handled by the firmware. We aks the firmware
+ * and it either aborts the command or fails
+ */
+
+static int orchid_abort_scb(struct orc_host * host, struct orc_scb * scb)
{
- unsigned char bData, bStatus;
+ unsigned char data, status;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB); /* Write command */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(ORC_CMD_ABORT_SCB, host->base + ORC_HDATA); /* Write command */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx); /* Write address */
- ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
- if (waitHDOoff(hcsp) == 0) /* Wait HDO off */
+ outb(scb->scbidx, host->base + ORC_HDATA); /* Write address */
+ outb(HDO, host->base + ORC_HCTRL);
+ if (wait_HDO_off(host) == 0) /* Wait HDO off */
return 0;
- if (waitHDIset(hcsp, &bData) == 0) /* Wait HDI set */
+ if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */
return 0;
- bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
- ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData); /* Clear HDI */
+ status = inb(host->base + ORC_HDATA);
+ outb(data, host->base + ORC_HSTUS); /* Clear HDI */
- if (bStatus == 1) /* 0 - Successfully */
+ if (status == 1) /* 0 - Successfully */
return 0; /* 1 - Fail */
return 1;
}
-/*****************************************************************************
- Function name : inia100_abort
- Description : Abort a queued command.
- (commands that are on the bus can't be aborted easily)
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int orc_abort_srb(ORC_HCS * hcsp, struct scsi_cmnd *SCpnt)
+static int inia100_abort_cmd(struct orc_host * host, struct scsi_cmnd *cmd)
{
- ESCB *pVirEscb;
- ORC_SCB *pVirScb;
- UCHAR i;
- ULONG flags;
+ struct orc_extended_scb *escb;
+ struct orc_scb *scb;
+ u8 i;
+ unsigned long flags;
- spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+ spin_lock_irqsave(&(host->allocation_lock), flags);
- pVirScb = hcsp->HCS_virScbArray;
+ scb = host->scb_virt;
- for (i = 0; i < ORC_MAXQUEUE; i++, pVirScb++) {
- pVirEscb = pVirScb->SCB_EScb;
- if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) {
- if (pVirScb->SCB_TagMsg == 0) {
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
- return FAILED;
+ /* Walk the queue until we find the SCB that belongs to the command
+ block. This isn't a performance critical path so a walk in the park
+ here does no harm */
+
+ for (i = 0; i < ORC_MAXQUEUE; i++, scb++) {
+ escb = scb->escb;
+ if (scb->status && escb->srb == cmd) {
+ if (scb->tag_msg == 0) {
+ goto out;
} else {
- if (abort_SCB(hcsp, pVirScb)) {
- pVirEscb->SCB_Srb = NULL;
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+ /* Issue an ABORT to the firmware */
+ if (orchid_abort_scb(host, scb)) {
+ escb->srb = NULL;
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return SUCCESS;
- } else {
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
- return FAILED;
- }
+ } else
+ goto out;
}
}
}
- spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+out:
+ spin_unlock_irqrestore(&host->allocation_lock, flags);
return FAILED;
}
-/***********************************************************************
- Routine Description:
- This is the interrupt service routine for the Orchid SCSI adapter.
- It reads the interrupt register to determine if the adapter is indeed
- the source of the interrupt and clears the interrupt at the device.
- Arguments:
- HwDeviceExtension - HBA miniport driver's adapter data storage
- Return Value:
-***********************************************************************/
-static void orc_interrupt(
- ORC_HCS * hcsp
-)
+/**
+ * orc_interrupt - IRQ processing
+ * @host: Host causing the interrupt
+ *
+ * This function is called from the IRQ handler and protected
+ * by the host lock. While the controller reports that there are
+ * scb's for processing we pull them off the controller, turn the
+ * index into a host address pointer to the scb and call the scb
+ * handler.
+ *
+ * Returns IRQ_HANDLED if any SCBs were processed, IRQ_NONE otherwise
+ */
+
+static irqreturn_t orc_interrupt(struct orc_host * host)
{
- BYTE bScbIdx;
- ORC_SCB *pScb;
+ u8 scb_index;
+ struct orc_scb *scb;
- if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) {
- return; // 0;
+ /* Check if we have an SCB queued for servicing */
+ if (inb(host->base + ORC_RQUEUECNT) == 0)
+ return IRQ_NONE;
- }
do {
- bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE);
-
- pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx));
- pScb->SCB_Status = 0x0;
-
- inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb);
- } while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT));
- return; //1;
-
+ /* Get the SCB index of the SCB to service */
+ scb_index = inb(host->base + ORC_RQUEUE);
+
+ /* Translate it back to a host pointer */
+ scb = (struct orc_scb *) ((unsigned long) host->scb_virt + (unsigned long) (sizeof(struct orc_scb) * scb_index));
+ scb->status = 0x0;
+ /* Process the SCB */
+ inia100_scb_handler(host, scb);
+ } while (inb(host->base + ORC_RQUEUECNT));
+ return IRQ_HANDLED;
} /* End of I1060Interrupt() */
-/*****************************************************************************
- Function name : inia100BuildSCB
- Description :
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, struct scsi_cmnd * SCpnt)
+/**
+ * inia100_build_scb - build SCB
+ * @host: host owing the control block
+ * @scb: control block to use
+ * @cmd: Mid layer command
+ *
+ * Build a host adapter control block from the SCSI mid layer command
+ */
+
+static void inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struct scsi_cmnd * cmd)
{ /* Create corresponding SCB */
- struct scatterlist *pSrbSG;
- ORC_SG *pSG; /* Pointer to SG list */
+ struct scatterlist *sg;
+ struct orc_sgent *sgent; /* Pointer to SG list */
int i, count_sg;
- ESCB *pEScb;
-
- pEScb = pSCB->SCB_EScb;
- pEScb->SCB_Srb = SCpnt;
- pSG = NULL;
-
- pSCB->SCB_Opcode = ORC_EXECSCSI;
- pSCB->SCB_Flags = SCF_NO_DCHK; /* Clear done bit */
- pSCB->SCB_Target = SCpnt->device->id;
- pSCB->SCB_Lun = SCpnt->device->lun;
- pSCB->SCB_Reserved0 = 0;
- pSCB->SCB_Reserved1 = 0;
- pSCB->SCB_SGLen = 0;
-
- if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) {
- pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];
- if (SCpnt->use_sg) {
- pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
- count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- pSCB->SCB_SGLen = (U32) (count_sg * 8);
- for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) {
- pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG);
- pSG->SG_Len = (U32) sg_dma_len(pSrbSG);
- }
- } else if (SCpnt->request_bufflen != 0) {/* Non SG */
- pSCB->SCB_SGLen = 0x8;
- SCpnt->SCp.dma_handle = pci_map_single(pHCB->pdev,
- SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- pSG->SG_Ptr = (U32) SCpnt->SCp.dma_handle;
- pSG->SG_Len = (U32) SCpnt->request_bufflen;
- } else {
- pSCB->SCB_SGLen = 0;
- pSG->SG_Ptr = 0;
- pSG->SG_Len = 0;
+ struct orc_extended_scb *escb;
+
+ /* Links between the escb, scb and Linux scsi midlayer cmd */
+ escb = scb->escb;
+ escb->srb = cmd;
+ sgent = NULL;
+
+ /* Set up the SCB to do a SCSI command block */
+ scb->opcode = ORC_EXECSCSI;
+ scb->flags = SCF_NO_DCHK; /* Clear done bit */
+ scb->target = cmd->device->id;
+ scb->lun = cmd->device->lun;
+ scb->reserved0 = 0;
+ scb->reserved1 = 0;
+ scb->sg_len = 0;
+
+ scb->xferlen = (u32) scsi_bufflen(cmd);
+ sgent = (struct orc_sgent *) & escb->sglist[0];
+
+ count_sg = scsi_dma_map(cmd);
+ BUG_ON(count_sg < 0);
+
+ /* Build the scatter gather lists */
+ if (count_sg) {
+ scb->sg_len = (u32) (count_sg * 8);
+ scsi_for_each_sg(cmd, sg, count_sg, i) {
+ sgent->base = (u32) sg_dma_address(sg);
+ sgent->length = (u32) sg_dma_len(sg);
+ sgent++;
}
+ } else {
+ scb->sg_len = 0;
+ sgent->base = 0;
+ sgent->length = 0;
}
- pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;
- pSCB->SCB_HaStat = 0;
- pSCB->SCB_TaStat = 0;
- pSCB->SCB_Link = 0xFF;
- pSCB->SCB_SenseLen = SENSE_SIZE;
- pSCB->SCB_CDBLen = SCpnt->cmd_len;
- if (pSCB->SCB_CDBLen >= IMAX_CDB) {
- printk("max cdb length= %x\b", SCpnt->cmd_len);
- pSCB->SCB_CDBLen = IMAX_CDB;
+ scb->sg_addr = (u32) scb->sense_addr;
+ scb->hastat = 0;
+ scb->tastat = 0;
+ scb->link = 0xFF;
+ scb->sense_len = SENSE_SIZE;
+ scb->cdb_len = cmd->cmd_len;
+ if (scb->cdb_len >= IMAX_CDB) {
+ printk("max cdb length= %x\b", cmd->cmd_len);
+ scb->cdb_len = IMAX_CDB;
}
- pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
- if (SCpnt->device->tagged_supported) { /* Tag Support */
- pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
+ scb->ident = cmd->device->lun | DISC_ALLOW;
+ if (cmd->device->tagged_supported) { /* Tag Support */
+ scb->tag_msg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
} else {
- pSCB->SCB_TagMsg = 0; /* No tag support */
+ scb->tag_msg = 0; /* No tag support */
}
- memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen);
- return;
+ memcpy(&scb->cdb[0], &cmd->cmnd, scb->cdb_len);
}
-/*****************************************************************************
- Function name : inia100_queue
- Description : Queue a command and setup interrupts for a free bus.
- Input : pHCB - Pointer to host adapter structure
- Output : None.
- Return : pSRB - Pointer to SCSI request block.
-*****************************************************************************/
-static int inia100_queue(struct scsi_cmnd * SCpnt, void (*done) (struct scsi_cmnd *))
+/**
+ * inia100_queue - queue command with host
+ * @cmd: Command block
+ * @done: Completion function
+ *
+ * Called by the mid layer to queue a command. Process the command
+ * block, build the host specific scb structures and if there is room
+ * queue the command down to the controller
+ */
+
+static int inia100_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
{
- register ORC_SCB *pSCB;
- ORC_HCS *pHCB; /* Point to Host adapter control block */
+ struct orc_scb *scb;
+ struct orc_host *host; /* Point to Host adapter control block */
- pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
- SCpnt->scsi_done = done;
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ cmd->scsi_done = done;
/* Get free SCSI control block */
- if ((pSCB = orc_alloc_scb(pHCB)) == NULL)
+ if ((scb = orc_alloc_scb(host)) == NULL)
return SCSI_MLQUEUE_HOST_BUSY;
- inia100BuildSCB(pHCB, pSCB, SCpnt);
- orc_exec_scb(pHCB, pSCB); /* Start execute SCB */
-
- return (0);
+ inia100_build_scb(host, scb, cmd);
+ orc_exec_scb(host, scb); /* Start execute SCB */
+ return 0;
}
/*****************************************************************************
Function name : inia100_abort
Description : Abort a queued command.
(commands that are on the bus can't be aborted easily)
- Input : pHCB - Pointer to host adapter structure
+ Input : host - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
-static int inia100_abort(struct scsi_cmnd * SCpnt)
+static int inia100_abort(struct scsi_cmnd * cmd)
{
- ORC_HCS *hcsp;
+ struct orc_host *host;
- hcsp = (ORC_HCS *) SCpnt->device->host->hostdata;
- return orc_abort_srb(hcsp, SCpnt);
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ return inia100_abort_cmd(host, cmd);
}
/*****************************************************************************
Function name : inia100_reset
Description : Reset registers, reset a hanging bus and
kill active and disconnected commands for target w/o soft reset
- Input : pHCB - Pointer to host adapter structure
+ Input : host - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
-static int inia100_bus_reset(struct scsi_cmnd * SCpnt)
+static int inia100_bus_reset(struct scsi_cmnd * cmd)
{ /* I need Host Control Block Information */
- ORC_HCS *pHCB;
- pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
- return orc_reset_scsi_bus(pHCB);
+ struct orc_host *host;
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ return orc_reset_scsi_bus(host);
}
/*****************************************************************************
Function name : inia100_device_reset
Description : Reset the device
- Input : pHCB - Pointer to host adapter structure
+ Input : host - Pointer to host adapter structure
Output : None.
Return : pSRB - Pointer to SCSI request block.
*****************************************************************************/
-static int inia100_device_reset(struct scsi_cmnd * SCpnt)
+static int inia100_device_reset(struct scsi_cmnd * cmd)
{ /* I need Host Control Block Information */
- ORC_HCS *pHCB;
- pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
- return orc_device_reset(pHCB, SCpnt, scmd_id(SCpnt));
+ struct orc_host *host;
+ host = (struct orc_host *) cmd->device->host->hostdata;
+ return orc_device_reset(host, cmd, scmd_id(cmd));
}
-/*****************************************************************************
- Function name : inia100SCBPost
- Description : This is callback routine be called when orc finish one
- SCSI command.
- Input : pHCB - Pointer to host adapter control block.
- pSCB - Pointer to SCSI control block.
- Output : None.
- Return : None.
-*****************************************************************************/
-static void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
+/**
+ * inia100_scb_handler - interrupt callback
+ * @host: Host causing the interrupt
+ * @scb: SCB the controller returned as needing processing
+ *
+ * Perform completion processing on a control block. Do the conversions
+ * from host to SCSI midlayer error coding, save any sense data and
+ * the complete with the midlayer and recycle the scb.
+ */
+
+static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb)
{
- struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */
- ORC_HCS *pHCB;
- ORC_SCB *pSCB;
- ESCB *pEScb;
-
- pHCB = (ORC_HCS *) pHcb;
- pSCB = (ORC_SCB *) pScb;
- pEScb = pSCB->SCB_EScb;
- if ((pSRB = (struct scsi_cmnd *) pEScb->SCB_Srb) == 0) {
- printk("inia100SCBPost: SRB pointer is empty\n");
- orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ struct scsi_cmnd *cmd; /* Pointer to SCSI request block */
+ struct orc_extended_scb *escb;
+
+ escb = scb->escb;
+ if ((cmd = (struct scsi_cmnd *) escb->srb) == NULL) {
+ printk(KERN_ERR "inia100_scb_handler: SRB pointer is empty\n");
+ orc_release_scb(host, scb); /* Release SCB for current channel */
return;
}
- pEScb->SCB_Srb = NULL;
+ escb->srb = NULL;
- switch (pSCB->SCB_HaStat) {
+ switch (scb->hastat) {
case 0x0:
case 0xa: /* Linked command complete without error and linked normally */
case 0xb: /* Linked command complete without error interrupt generated */
- pSCB->SCB_HaStat = 0;
+ scb->hastat = 0;
break;
case 0x11: /* Selection time out-The initiator selection or target
reselection was not complete within the SCSI Time out period */
- pSCB->SCB_HaStat = DID_TIME_OUT;
+ scb->hastat = DID_TIME_OUT;
break;
case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
phase sequence was requested by the target. The host adapter
will generate a SCSI Reset Condition, notifying the host with
a SCRD interrupt */
- pSCB->SCB_HaStat = DID_RESET;
+ scb->hastat = DID_RESET;
break;
case 0x1a: /* SCB Aborted. 07/21/98 */
- pSCB->SCB_HaStat = DID_ABORT;
+ scb->hastat = DID_ABORT;
break;
case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
@@ -984,46 +1022,41 @@ static void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */
default:
- printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
- pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */
+ printk(KERN_DEBUG "inia100: %x %x\n", scb->hastat, scb->tastat);
+ scb->hastat = DID_ERROR; /* Couldn't find any better */
break;
}
- if (pSCB->SCB_TaStat == 2) { /* Check condition */
- memcpy((unsigned char *) &pSRB->sense_buffer[0],
- (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE);
+ if (scb->tastat == 2) { /* Check condition */
+ memcpy((unsigned char *) &cmd->sense_buffer[0],
+ (unsigned char *) &escb->sglist[0], SENSE_SIZE);
}
- pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
-
- if (pSRB->use_sg) {
- pci_unmap_sg(pHCB->pdev,
- (struct scatterlist *)pSRB->request_buffer,
- pSRB->use_sg, pSRB->sc_data_direction);
- } else if (pSRB->request_bufflen != 0) {
- pci_unmap_single(pHCB->pdev, pSRB->SCp.dma_handle,
- pSRB->request_bufflen,
- pSRB->sc_data_direction);
- }
-
- pSRB->scsi_done(pSRB); /* Notify system DONE */
-
- orc_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ cmd->result = scb->tastat | (scb->hastat << 16);
+ scsi_dma_unmap(cmd);
+ cmd->scsi_done(cmd); /* Notify system DONE */
+ orc_release_scb(host, scb); /* Release SCB for current channel */
}
-/*
- * Interrupt handler (main routine of the driver)
+/**
+ * inia100_intr - interrupt handler
+ * @irqno: Interrupt value
+ * @devid: Host adapter
+ *
+ * Entry point for IRQ handling. All the real work is performed
+ * by orc_interrupt.
*/
static irqreturn_t inia100_intr(int irqno, void *devid)
{
- struct Scsi_Host *host = (struct Scsi_Host *)devid;
- ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
+ struct Scsi_Host *shost = (struct Scsi_Host *)devid;
+ struct orc_host *host = (struct orc_host *)shost->hostdata;
unsigned long flags;
+ irqreturn_t res;
- spin_lock_irqsave(host->host_lock, flags);
- orc_interrupt(pHcb);
- spin_unlock_irqrestore(host->host_lock, flags);
+ spin_lock_irqsave(shost->host_lock, flags);
+ res = orc_interrupt(host);
+ spin_unlock_irqrestore(shost->host_lock, flags);
- return IRQ_HANDLED;
+ return res;
}
static struct scsi_host_template inia100_template = {
@@ -1044,12 +1077,12 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct Scsi_Host *shost;
- ORC_HCS *pHCB;
+ struct orc_host *host;
unsigned long port, bios;
int error = -ENODEV;
u32 sz;
- unsigned long dBiosAdr;
- char *pbBiosAdr;
+ unsigned long biosaddr;
+ char *bios_phys;
if (pci_enable_device(pdev))
goto out;
@@ -1068,55 +1101,55 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev,
}
/* <02> read from base address + 0x50 offset to get the bios value. */
- bios = ORC_RDWORD(port, 0x50);
+ bios = inw(port + 0x50);
- shost = scsi_host_alloc(&inia100_template, sizeof(ORC_HCS));
+ shost = scsi_host_alloc(&inia100_template, sizeof(struct orc_host));
if (!shost)
goto out_release_region;
- pHCB = (ORC_HCS *)shost->hostdata;
- pHCB->pdev = pdev;
- pHCB->HCS_Base = port;
- pHCB->HCS_BIOS = bios;
- spin_lock_init(&pHCB->BitAllocFlagLock);
+ host = (struct orc_host *)shost->hostdata;
+ host->pdev = pdev;
+ host->base = port;
+ host->BIOScfg = bios;
+ spin_lock_init(&host->allocation_lock);
/* Get total memory needed for SCB */
- sz = ORC_MAXQUEUE * sizeof(ORC_SCB);
- pHCB->HCS_virScbArray = pci_alloc_consistent(pdev, sz,
- &pHCB->HCS_physScbArray);
- if (!pHCB->HCS_virScbArray) {
+ sz = ORC_MAXQUEUE * sizeof(struct orc_scb);
+ host->scb_virt = pci_alloc_consistent(pdev, sz,
+ &host->scb_phys);
+ if (!host->scb_virt) {
printk("inia100: SCB memory allocation error\n");
goto out_host_put;
}
- memset(pHCB->HCS_virScbArray, 0, sz);
+ memset(host->scb_virt, 0, sz);
/* Get total memory needed for ESCB */
- sz = ORC_MAXQUEUE * sizeof(ESCB);
- pHCB->HCS_virEscbArray = pci_alloc_consistent(pdev, sz,
- &pHCB->HCS_physEscbArray);
- if (!pHCB->HCS_virEscbArray) {
+ sz = ORC_MAXQUEUE * sizeof(struct orc_extended_scb);
+ host->escb_virt = pci_alloc_consistent(pdev, sz,
+ &host->escb_phys);
+ if (!host->escb_virt) {
printk("inia100: ESCB memory allocation error\n");
goto out_free_scb_array;
}
- memset(pHCB->HCS_virEscbArray, 0, sz);
+ memset(host->escb_virt, 0, sz);
- dBiosAdr = pHCB->HCS_BIOS;
- dBiosAdr = (dBiosAdr << 4);
- pbBiosAdr = phys_to_virt(dBiosAdr);
- if (init_orchid(pHCB)) { /* Initialize orchid chip */
+ biosaddr = host->BIOScfg;
+ biosaddr = (biosaddr << 4);
+ bios_phys = phys_to_virt(biosaddr);
+ if (init_orchid(host)) { /* Initialize orchid chip */
printk("inia100: initial orchid fail!!\n");
goto out_free_escb_array;
}
- shost->io_port = pHCB->HCS_Base;
+ shost->io_port = host->base;
shost->n_io_port = 0xff;
shost->can_queue = ORC_MAXQUEUE;
shost->unique_id = shost->io_port;
- shost->max_id = pHCB->HCS_MaxTar;
+ shost->max_id = host->max_targets;
shost->max_lun = 16;
- shost->irq = pHCB->HCS_Intr = pdev->irq;
- shost->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
+ shost->irq = pdev->irq;
+ shost->this_id = host->scsi_id; /* Assign HCS index */
shost->sg_tablesize = TOTAL_SG_ENTRY;
/* Initial orc chip */
@@ -1137,36 +1170,36 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev,
scsi_scan_host(shost);
return 0;
- out_free_irq:
+out_free_irq:
free_irq(shost->irq, shost);
- out_free_escb_array:
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
- pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
- out_free_scb_array:
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
- pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
- out_host_put:
+out_free_escb_array:
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
+ host->escb_virt, host->escb_phys);
+out_free_scb_array:
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb),
+ host->scb_virt, host->scb_phys);
+out_host_put:
scsi_host_put(shost);
- out_release_region:
+out_release_region:
release_region(port, 256);
- out_disable_device:
+out_disable_device:
pci_disable_device(pdev);
- out:
+out:
return error;
}
static void __devexit inia100_remove_one(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
- ORC_HCS *pHCB = (ORC_HCS *)shost->hostdata;
+ struct orc_host *host = (struct orc_host *)shost->hostdata;
scsi_remove_host(shost);
free_irq(shost->irq, shost);
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
- pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
- pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
- pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb),
+ host->escb_virt, host->escb_phys);
+ pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb),
+ host->scb_virt, host->scb_phys);
release_region(shost->io_port, 256);
scsi_host_put(shost);
diff --git a/drivers/scsi/a100u2w.h b/drivers/scsi/a100u2w.h
index 6f542d2600ea..d40e0c528198 100644
--- a/drivers/scsi/a100u2w.h
+++ b/drivers/scsi/a100u2w.h
@@ -18,27 +18,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -50,30 +29,19 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- */
-
-/*
+ *
* Revision History:
* 06/18/98 HL, Initial production Version 1.02
* 12/19/98 bv, Use spinlocks for 2.1.95 and up
* 06/25/02 Doug Ledford <dledford@redhat.com>
* - This and the i60uscsi.h file are almost identical,
* merged them into a single header used by both .c files.
+ * 14/06/07 Alan Cox <alan@redhat.com>
+ * - Grand cleanup and Linuxisation
*/
#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d"
-#define ULONG unsigned long
-#define USHORT unsigned short
-#define UCHAR unsigned char
-#define BYTE unsigned char
-#define WORD unsigned short
-#define DWORD unsigned long
-#define UBYTE unsigned char
-#define UWORD unsigned short
-#define UDWORD unsigned long
-#define U32 u32
-
#if 1
#define ORC_MAXQUEUE 245
#define ORC_MAXTAGS 64
@@ -90,10 +58,10 @@
/************************************************************************/
/* Scatter-Gather Element Structure */
/************************************************************************/
-typedef struct ORC_SG_Struc {
- U32 SG_Ptr; /* Data Pointer */
- U32 SG_Len; /* Data Length */
-} ORC_SG;
+struct orc_sgent {
+ u32 base; /* Data Pointer */
+ u32 length; /* Data Length */
+};
/* SCSI related definition */
#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */
@@ -165,42 +133,45 @@ typedef struct ORC_SG_Struc {
#define ORC_PRGMCTR1 0xE3 /* RISC program counter */
#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */
-typedef struct orc_extended_scb { /* Extended SCB */
- ORC_SG ESCB_SGList[TOTAL_SG_ENTRY]; /*0 Start of SG list */
- struct scsi_cmnd *SCB_Srb; /*50 SRB Pointer */
-} ESCB;
+struct orc_extended_scb { /* Extended SCB */
+ struct orc_sgent sglist[TOTAL_SG_ENTRY]; /*0 Start of SG list */
+ struct scsi_cmnd *srb; /*50 SRB Pointer */
+};
/***********************************************************************
SCSI Control Block
+
+ 0x40 bytes long, the last 8 are user bytes
************************************************************************/
-typedef struct orc_scb { /* Scsi_Ctrl_Blk */
- UBYTE SCB_Opcode; /*00 SCB command code&residual */
- UBYTE SCB_Flags; /*01 SCB Flags */
- UBYTE SCB_Target; /*02 Target Id */
- UBYTE SCB_Lun; /*03 Lun */
- U32 SCB_Reserved0; /*04 Reserved for ORCHID must 0 */
- U32 SCB_XferLen; /*08 Data Transfer Length */
- U32 SCB_Reserved1; /*0C Reserved for ORCHID must 0 */
- U32 SCB_SGLen; /*10 SG list # * 8 */
- U32 SCB_SGPAddr; /*14 SG List Buf physical Addr */
- U32 SCB_SGPAddrHigh; /*18 SG Buffer high physical Addr */
- UBYTE SCB_HaStat; /*1C Host Status */
- UBYTE SCB_TaStat; /*1D Target Status */
- UBYTE SCB_Status; /*1E SCB status */
- UBYTE SCB_Link; /*1F Link pointer, default 0xFF */
- UBYTE SCB_SenseLen; /*20 Sense Allocation Length */
- UBYTE SCB_CDBLen; /*21 CDB Length */
- UBYTE SCB_Ident; /*22 Identify */
- UBYTE SCB_TagMsg; /*23 Tag Message */
- UBYTE SCB_CDB[IMAX_CDB]; /*24 SCSI CDBs */
- UBYTE SCB_ScbIdx; /*3C Index for this ORCSCB */
- U32 SCB_SensePAddr; /*34 Sense Buffer physical Addr */
-
- ESCB *SCB_EScb; /*38 Extended SCB Pointer */
-#ifndef ALPHA
- UBYTE SCB_Reserved2[4]; /*3E Reserved for Driver use */
+struct orc_scb { /* Scsi_Ctrl_Blk */
+ u8 opcode; /*00 SCB command code&residual */
+ u8 flags; /*01 SCB Flags */
+ u8 target; /*02 Target Id */
+ u8 lun; /*03 Lun */
+ u32 reserved0; /*04 Reserved for ORCHID must 0 */
+ u32 xferlen; /*08 Data Transfer Length */
+ u32 reserved1; /*0C Reserved for ORCHID must 0 */
+ u32 sg_len; /*10 SG list # * 8 */
+ u32 sg_addr; /*14 SG List Buf physical Addr */
+ u32 sg_addrhigh; /*18 SG Buffer high physical Addr */
+ u8 hastat; /*1C Host Status */
+ u8 tastat; /*1D Target Status */
+ u8 status; /*1E SCB status */
+ u8 link; /*1F Link pointer, default 0xFF */
+ u8 sense_len; /*20 Sense Allocation Length */
+ u8 cdb_len; /*21 CDB Length */
+ u8 ident; /*22 Identify */
+ u8 tag_msg; /*23 Tag Message */
+ u8 cdb[IMAX_CDB]; /*24 SCSI CDBs */
+ u8 scbidx; /*3C Index for this ORCSCB */
+ u32 sense_addr; /*34 Sense Buffer physical Addr */
+
+ struct orc_extended_scb *escb; /*38 Extended SCB Pointer */
+ /* 64bit pointer or 32bit pointer + reserved ? */
+#ifndef CONFIG_64BIT
+ u8 reserved2[4]; /*3E Reserved for Driver use */
#endif
-} ORC_SCB;
+};
/* Opcodes of ORCSCB_Opcode */
#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */
@@ -239,13 +210,13 @@ typedef struct orc_scb { /* Scsi_Ctrl_Blk */
Target Device Control Structure
**********************************************************************/
-typedef struct ORC_Tar_Ctrl_Struc {
- UBYTE TCS_DrvDASD; /* 6 */
- UBYTE TCS_DrvSCSI; /* 7 */
- UBYTE TCS_DrvHead; /* 8 */
- UWORD TCS_DrvFlags; /* 4 */
- UBYTE TCS_DrvSector; /* 7 */
-} ORC_TCS;
+struct orc_target {
+ u8 TCS_DrvDASD; /* 6 */
+ u8 TCS_DrvSCSI; /* 7 */
+ u8 TCS_DrvHead; /* 8 */
+ u16 TCS_DrvFlags; /* 4 */
+ u8 TCS_DrvSector; /* 7 */
+};
/* Bit Definition for TCF_DrvFlags */
#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */
@@ -255,32 +226,23 @@ typedef struct ORC_Tar_Ctrl_Struc {
/***********************************************************************
Host Adapter Control Structure
************************************************************************/
-typedef struct ORC_Ha_Ctrl_Struc {
- USHORT HCS_Base; /* 00 */
- UBYTE HCS_Index; /* 02 */
- UBYTE HCS_Intr; /* 04 */
- UBYTE HCS_SCSI_ID; /* 06 H/A SCSI ID */
- UBYTE HCS_BIOS; /* 07 BIOS configuration */
-
- UBYTE HCS_Flags; /* 0B */
- UBYTE HCS_HAConfig1; /* 1B SCSI0MAXTags */
- UBYTE HCS_MaxTar; /* 1B SCSI0MAXTags */
-
- USHORT HCS_Units; /* Number of units this adapter */
- USHORT HCS_AFlags; /* Adapter info. defined flags */
- ULONG HCS_Timeout; /* Adapter timeout value */
- ORC_SCB *HCS_virScbArray; /* 28 Virtual Pointer to SCB array */
- dma_addr_t HCS_physScbArray; /* Scb Physical address */
- ESCB *HCS_virEscbArray; /* Virtual pointer to ESCB Scatter list */
- dma_addr_t HCS_physEscbArray; /* scatter list Physical address */
- UBYTE TargetFlag[16]; /* 30 target configuration, TCF_EN_TAG */
- UBYTE MaximumTags[16]; /* 40 ORC_MAX_SCBS */
- UBYTE ActiveTags[16][16]; /* 50 */
- ORC_TCS HCS_Tcs[16]; /* 28 */
- U32 BitAllocFlag[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */
- spinlock_t BitAllocFlagLock;
+struct orc_host {
+ unsigned long base; /* Base address */
+ u8 index; /* Index (Channel)*/
+ u8 scsi_id; /* H/A SCSI ID */
+ u8 BIOScfg; /*BIOS configuration */
+ u8 flags;
+ u8 max_targets; /* SCSI0MAXTags */
+ struct orc_scb *scb_virt; /* Virtual Pointer to SCB array */
+ dma_addr_t scb_phys; /* Scb Physical address */
+ struct orc_extended_scb *escb_virt; /* Virtual pointer to ESCB Scatter list */
+ dma_addr_t escb_phys; /* scatter list Physical address */
+ u8 target_flag[16]; /* target configuration, TCF_EN_TAG */
+ u8 max_tags[16]; /* ORC_MAX_SCBS */
+ u32 allocation_map[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */
+ spinlock_t allocation_lock;
struct pci_dev *pdev;
-} ORC_HCS;
+};
/* Bit Definition for HCS_Flags */
@@ -301,79 +263,79 @@ typedef struct ORC_Ha_Ctrl_Struc {
#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */
#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */
-typedef struct _NVRAM {
+struct orc_nvram {
/*----------header ---------------*/
- UCHAR SubVendorID0; /* 00 - Sub Vendor ID */
- UCHAR SubVendorID1; /* 00 - Sub Vendor ID */
- UCHAR SubSysID0; /* 02 - Sub System ID */
- UCHAR SubSysID1; /* 02 - Sub System ID */
- UCHAR SubClass; /* 04 - Sub Class */
- UCHAR VendorID0; /* 05 - Vendor ID */
- UCHAR VendorID1; /* 05 - Vendor ID */
- UCHAR DeviceID0; /* 07 - Device ID */
- UCHAR DeviceID1; /* 07 - Device ID */
- UCHAR Reserved0[2]; /* 09 - Reserved */
- UCHAR Revision; /* 0B - Revision of data structure */
+ u8 SubVendorID0; /* 00 - Sub Vendor ID */
+ u8 SubVendorID1; /* 00 - Sub Vendor ID */
+ u8 SubSysID0; /* 02 - Sub System ID */
+ u8 SubSysID1; /* 02 - Sub System ID */
+ u8 SubClass; /* 04 - Sub Class */
+ u8 VendorID0; /* 05 - Vendor ID */
+ u8 VendorID1; /* 05 - Vendor ID */
+ u8 DeviceID0; /* 07 - Device ID */
+ u8 DeviceID1; /* 07 - Device ID */
+ u8 Reserved0[2]; /* 09 - Reserved */
+ u8 revision; /* 0B - revision of data structure */
/* ----Host Adapter Structure ---- */
- UCHAR NumOfCh; /* 0C - Number of SCSI channel */
- UCHAR BIOSConfig1; /* 0D - BIOS configuration 1 */
- UCHAR BIOSConfig2; /* 0E - BIOS boot channel&target ID */
- UCHAR BIOSConfig3; /* 0F - BIOS configuration 3 */
+ u8 NumOfCh; /* 0C - Number of SCSI channel */
+ u8 BIOSConfig1; /* 0D - BIOS configuration 1 */
+ u8 BIOSConfig2; /* 0E - BIOS boot channel&target ID */
+ u8 BIOSConfig3; /* 0F - BIOS configuration 3 */
/* ----SCSI channel Structure ---- */
/* from "CTRL-I SCSI Host Adapter SetUp menu " */
- UCHAR SCSI0Id; /* 10 - Channel 0 SCSI ID */
- UCHAR SCSI0Config; /* 11 - Channel 0 SCSI configuration */
- UCHAR SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */
- UCHAR SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */
- UCHAR ReservedforChannel0[2]; /* 14 - Reserved */
+ u8 scsi_id; /* 10 - Channel 0 SCSI ID */
+ u8 SCSI0Config; /* 11 - Channel 0 SCSI configuration */
+ u8 SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */
+ u8 SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */
+ u8 ReservedforChannel0[2]; /* 14 - Reserved */
/* ----SCSI target Structure ---- */
/* from "CTRL-I SCSI device SetUp menu " */
- UCHAR Target00Config; /* 16 - Channel 0 Target 0 config */
- UCHAR Target01Config; /* 17 - Channel 0 Target 1 config */
- UCHAR Target02Config; /* 18 - Channel 0 Target 2 config */
- UCHAR Target03Config; /* 19 - Channel 0 Target 3 config */
- UCHAR Target04Config; /* 1A - Channel 0 Target 4 config */
- UCHAR Target05Config; /* 1B - Channel 0 Target 5 config */
- UCHAR Target06Config; /* 1C - Channel 0 Target 6 config */
- UCHAR Target07Config; /* 1D - Channel 0 Target 7 config */
- UCHAR Target08Config; /* 1E - Channel 0 Target 8 config */
- UCHAR Target09Config; /* 1F - Channel 0 Target 9 config */
- UCHAR Target0AConfig; /* 20 - Channel 0 Target A config */
- UCHAR Target0BConfig; /* 21 - Channel 0 Target B config */
- UCHAR Target0CConfig; /* 22 - Channel 0 Target C config */
- UCHAR Target0DConfig; /* 23 - Channel 0 Target D config */
- UCHAR Target0EConfig; /* 24 - Channel 0 Target E config */
- UCHAR Target0FConfig; /* 25 - Channel 0 Target F config */
-
- UCHAR SCSI1Id; /* 26 - Channel 1 SCSI ID */
- UCHAR SCSI1Config; /* 27 - Channel 1 SCSI configuration */
- UCHAR SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */
- UCHAR SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */
- UCHAR ReservedforChannel1[2]; /* 2A - Reserved */
+ u8 Target00Config; /* 16 - Channel 0 Target 0 config */
+ u8 Target01Config; /* 17 - Channel 0 Target 1 config */
+ u8 Target02Config; /* 18 - Channel 0 Target 2 config */
+ u8 Target03Config; /* 19 - Channel 0 Target 3 config */
+ u8 Target04Config; /* 1A - Channel 0 Target 4 config */
+ u8 Target05Config; /* 1B - Channel 0 Target 5 config */
+ u8 Target06Config; /* 1C - Channel 0 Target 6 config */
+ u8 Target07Config; /* 1D - Channel 0 Target 7 config */
+ u8 Target08Config; /* 1E - Channel 0 Target 8 config */
+ u8 Target09Config; /* 1F - Channel 0 Target 9 config */
+ u8 Target0AConfig; /* 20 - Channel 0 Target A config */
+ u8 Target0BConfig; /* 21 - Channel 0 Target B config */
+ u8 Target0CConfig; /* 22 - Channel 0 Target C config */
+ u8 Target0DConfig; /* 23 - Channel 0 Target D config */
+ u8 Target0EConfig; /* 24 - Channel 0 Target E config */
+ u8 Target0FConfig; /* 25 - Channel 0 Target F config */
+
+ u8 SCSI1Id; /* 26 - Channel 1 SCSI ID */
+ u8 SCSI1Config; /* 27 - Channel 1 SCSI configuration */
+ u8 SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */
+ u8 SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */
+ u8 ReservedforChannel1[2]; /* 2A - Reserved */
/* ----SCSI target Structure ---- */
/* from "CTRL-I SCSI device SetUp menu " */
- UCHAR Target10Config; /* 2C - Channel 1 Target 0 config */
- UCHAR Target11Config; /* 2D - Channel 1 Target 1 config */
- UCHAR Target12Config; /* 2E - Channel 1 Target 2 config */
- UCHAR Target13Config; /* 2F - Channel 1 Target 3 config */
- UCHAR Target14Config; /* 30 - Channel 1 Target 4 config */
- UCHAR Target15Config; /* 31 - Channel 1 Target 5 config */
- UCHAR Target16Config; /* 32 - Channel 1 Target 6 config */
- UCHAR Target17Config; /* 33 - Channel 1 Target 7 config */
- UCHAR Target18Config; /* 34 - Channel 1 Target 8 config */
- UCHAR Target19Config; /* 35 - Channel 1 Target 9 config */
- UCHAR Target1AConfig; /* 36 - Channel 1 Target A config */
- UCHAR Target1BConfig; /* 37 - Channel 1 Target B config */
- UCHAR Target1CConfig; /* 38 - Channel 1 Target C config */
- UCHAR Target1DConfig; /* 39 - Channel 1 Target D config */
- UCHAR Target1EConfig; /* 3A - Channel 1 Target E config */
- UCHAR Target1FConfig; /* 3B - Channel 1 Target F config */
- UCHAR reserved[3]; /* 3C - Reserved */
+ u8 Target10Config; /* 2C - Channel 1 Target 0 config */
+ u8 Target11Config; /* 2D - Channel 1 Target 1 config */
+ u8 Target12Config; /* 2E - Channel 1 Target 2 config */
+ u8 Target13Config; /* 2F - Channel 1 Target 3 config */
+ u8 Target14Config; /* 30 - Channel 1 Target 4 config */
+ u8 Target15Config; /* 31 - Channel 1 Target 5 config */
+ u8 Target16Config; /* 32 - Channel 1 Target 6 config */
+ u8 Target17Config; /* 33 - Channel 1 Target 7 config */
+ u8 Target18Config; /* 34 - Channel 1 Target 8 config */
+ u8 Target19Config; /* 35 - Channel 1 Target 9 config */
+ u8 Target1AConfig; /* 36 - Channel 1 Target A config */
+ u8 Target1BConfig; /* 37 - Channel 1 Target B config */
+ u8 Target1CConfig; /* 38 - Channel 1 Target C config */
+ u8 Target1DConfig; /* 39 - Channel 1 Target D config */
+ u8 Target1EConfig; /* 3A - Channel 1 Target E config */
+ u8 Target1FConfig; /* 3B - Channel 1 Target F config */
+ u8 reserved[3]; /* 3C - Reserved */
/* ---------- CheckSum ---------- */
- UCHAR CheckSum; /* 3F - Checksum of NVRam */
-} NVRAM, *PNVRAM;
+ u8 CheckSum; /* 3F - Checksum of NVRam */
+};
/* Bios Configuration for nvram->BIOSConfig1 */
#define NBC_BIOSENABLE 0x01 /* BIOS enable */
@@ -407,10 +369,3 @@ typedef struct _NVRAM {
#define NCC_RESET_TIME 0x0A /* SCSI RESET recovering time */
#define NTC_DEFAULT (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE)
-#define ORC_RD(x,y) (UCHAR)(inb( (int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-#define ORC_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-#define ORC_RDLONG(x,y) (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-
-#define ORC_WR( adr,data) outb( (UCHAR)(data), (int)(adr))
-#define ORC_WRSHORT(adr,data) outw( (UWORD)(data), (int)(adr))
-#define ORC_WRLONG( adr,data) outl( (ULONG)(data), (int)(adr))
diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c
new file mode 100644
index 000000000000..0c758d1452ba
--- /dev/null
+++ b/drivers/scsi/a4000t.c
@@ -0,0 +1,144 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ * Amiga Technologies A4000T SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+
+static struct scsi_host_template a4000t_scsi_driver_template = {
+ .name = "A4000T builtin SCSI",
+ .proc_name = "A4000t",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct platform_device *a4000t_scsi_device;
+
+#define A4000T_SCSI_ADDR 0xdd0040
+
+static int __devinit a4000t_probe(struct device *dev)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+
+ if (!(MACH_IS_AMIGA && AMIGAHW_PRESENT(A4000_SCSI)))
+ goto out;
+
+ if (!request_mem_region(A4000T_SCSI_ADDR, 0x1000,
+ "A4000T builtin SCSI"))
+ goto out;
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "a4000t-scsi: Failed to allocate host data\n");
+ goto out_release;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ hostdata->base = (void __iomem *)ZTWO_VADDR(A4000T_SCSI_ADDR);
+ hostdata->clock = 50;
+ hostdata->chip710 = 1;
+ hostdata->dmode_extra = DMODE_FC2;
+ hostdata->dcntl_extra = EA_710;
+
+ /* and register the chip */
+ host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata, dev);
+ if (!host) {
+ printk(KERN_ERR "a4000t-scsi: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+
+ host->this_id = 7;
+ host->base = A4000T_SCSI_ADDR;
+ host->irq = IRQ_AMIGA_PORTS;
+
+ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi",
+ host)) {
+ printk(KERN_ERR "a4000t-scsi: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ dev_set_drvdata(dev, host);
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ kfree(hostdata);
+ out_release:
+ release_mem_region(A4000T_SCSI_ADDR, 0x1000);
+ out:
+ return -ENODEV;
+}
+
+static __devexit int a4000t_device_remove(struct device *dev)
+{
+ struct Scsi_Host *host = dev_get_drvdata(dev);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ scsi_remove_host(host);
+
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+ release_mem_region(A4000T_SCSI_ADDR, 0x1000);
+
+ return 0;
+}
+
+static struct device_driver a4000t_scsi_driver = {
+ .name = "a4000t-scsi",
+ .bus = &platform_bus_type,
+ .probe = a4000t_probe,
+ .remove = __devexit_p(a4000t_device_remove),
+};
+
+static int __init a4000t_scsi_init(void)
+{
+ int err;
+
+ err = driver_register(&a4000t_scsi_driver);
+ if (err)
+ return err;
+
+ a4000t_scsi_device = platform_device_register_simple("a4000t-scsi",
+ -1, NULL, 0);
+ if (IS_ERR(a4000t_scsi_device)) {
+ driver_unregister(&a4000t_scsi_driver);
+ return PTR_ERR(a4000t_scsi_device);
+ }
+
+ return err;
+}
+
+static void __exit a4000t_scsi_exit(void)
+{
+ platform_device_unregister(a4000t_scsi_device);
+ driver_unregister(&a4000t_scsi_driver);
+}
+
+module_init(a4000t_scsi_init);
+module_exit(a4000t_scsi_exit);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 8dcfe4ec35c2..a26baab09dbf 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -169,6 +169,18 @@ int acbsize = -1;
module_param(acbsize, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
+int update_interval = 30 * 60;
+module_param(update_interval, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync updates issued to adapter.");
+
+int check_interval = 24 * 60 * 60;
+module_param(check_interval, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks.");
+
+int check_reset = 1;
+module_param(check_reset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the adapter.");
+
int expose_physicals = -1;
module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on");
@@ -312,11 +324,10 @@ int aac_get_containers(struct aac_dev *dev)
if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
- fsa_dev_ptr = kmalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
+ fsa_dev_ptr = kzalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers,
GFP_KERNEL);
if (!fsa_dev_ptr)
return -ENOMEM;
- memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
dev->fsa_dev = fsa_dev_ptr;
dev->maximum_num_containers = maximum_num_containers;
@@ -344,21 +355,16 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne
{
void *buf;
int transfer_len;
- struct scatterlist *sg = scsicmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(scsicmd);
+
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ transfer_len = min(sg->length, len + offset);
- if (scsicmd->use_sg) {
- buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- transfer_len = min(sg->length, len + offset);
- } else {
- buf = scsicmd->request_buffer;
- transfer_len = min(scsicmd->request_bufflen, len + offset);
- }
transfer_len -= offset;
if (buf && transfer_len > 0)
memcpy(buf + offset, data, transfer_len);
- if (scsicmd->use_sg)
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
}
@@ -451,7 +457,7 @@ static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
{
struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
- if (fsa_dev_ptr[scmd_id(scsicmd)].valid)
+ if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1))
return aac_scsi_cmd(scsicmd);
scsicmd->result = DID_NO_CONNECT << 16;
@@ -459,18 +465,18 @@ static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd)
return 0;
}
-static int _aac_probe_container2(void * context, struct fib * fibptr)
+static void _aac_probe_container2(void * context, struct fib * fibptr)
{
struct fsa_dev_info *fsa_dev_ptr;
int (*callback)(struct scsi_cmnd *);
struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context;
- if (!aac_valid_context(scsicmd, fibptr))
- return 0;
- fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev;
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
scsicmd->SCp.Status = 0;
+ fsa_dev_ptr = fibptr->dev->fsa_dev;
if (fsa_dev_ptr) {
struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr);
fsa_dev_ptr += scmd_id(scsicmd);
@@ -493,10 +499,11 @@ static int _aac_probe_container2(void * context, struct fib * fibptr)
aac_fib_free(fibptr);
callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr);
scsicmd->SCp.ptr = NULL;
- return (*callback)(scsicmd);
+ (*callback)(scsicmd);
+ return;
}
-static int _aac_probe_container1(void * context, struct fib * fibptr)
+static void _aac_probe_container1(void * context, struct fib * fibptr)
{
struct scsi_cmnd * scsicmd;
struct aac_mount * dresp;
@@ -506,13 +513,14 @@ static int _aac_probe_container1(void * context, struct fib * fibptr)
dresp = (struct aac_mount *) fib_data(fibptr);
dresp->mnt[0].capacityhigh = 0;
if ((le32_to_cpu(dresp->status) != ST_OK) ||
- (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE))
- return _aac_probe_container2(context, fibptr);
+ (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
+ _aac_probe_container2(context, fibptr);
+ return;
+ }
scsicmd = (struct scsi_cmnd *) context;
- scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL;
if (!aac_valid_context(scsicmd, fibptr))
- return 0;
+ return;
aac_fib_init(fibptr);
@@ -527,21 +535,18 @@ static int _aac_probe_container1(void * context, struct fib * fibptr)
sizeof(struct aac_query_mount),
FsaNormal,
0, 1,
- (fib_callback) _aac_probe_container2,
+ _aac_probe_container2,
(void *) scsicmd);
/*
* Check that the command queued to the controller
*/
- if (status == -EINPROGRESS) {
+ if (status == -EINPROGRESS)
scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
- return 0;
- }
- if (status < 0) {
+ else if (status < 0) {
/* Inherit results from VM_NameServe, if any */
dresp->status = cpu_to_le32(ST_OK);
- return _aac_probe_container2(context, fibptr);
+ _aac_probe_container2(context, fibptr);
}
- return 0;
}
static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *))
@@ -566,7 +571,7 @@ static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(stru
sizeof(struct aac_query_mount),
FsaNormal,
0, 1,
- (fib_callback) _aac_probe_container1,
+ _aac_probe_container1,
(void *) scsicmd);
/*
* Check that the command queued to the controller
@@ -620,7 +625,7 @@ int aac_probe_container(struct aac_dev *dev, int cid)
return -ENOMEM;
}
scsicmd->list.next = NULL;
- scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))_aac_probe_container1;
+ scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1;
scsicmd->device = scsidev;
scsidev->sdev_state = 0;
@@ -746,6 +751,101 @@ static void setinqstr(struct aac_dev *dev, void *data, int tindex)
inqstrcpy ("V1.0", str->prl);
}
+static void get_container_serial_callback(void *context, struct fib * fibptr)
+{
+ struct aac_get_serial_resp * get_serial_reply;
+ struct scsi_cmnd * scsicmd;
+
+ BUG_ON(fibptr == NULL);
+
+ scsicmd = (struct scsi_cmnd *) context;
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
+
+ get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
+ /* Failure is irrelevant, using default value instead */
+ if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
+ char sp[13];
+ /* EVPD bit set */
+ sp[0] = INQD_PDT_DA;
+ sp[1] = scsicmd->cmnd[2];
+ sp[2] = 0;
+ sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
+ le32_to_cpu(get_serial_reply->uid));
+ aac_internal_transfer(scsicmd, sp, 0, sizeof(sp));
+ }
+
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ scsicmd->scsi_done(scsicmd);
+}
+
+/**
+ * aac_get_container_serial - get container serial, none blocking.
+ */
+static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
+{
+ int status;
+ struct aac_get_serial *dinfo;
+ struct fib * cmd_fibcontext;
+ struct aac_dev * dev;
+
+ dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+
+ if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+ return -ENOMEM;
+
+ aac_fib_init(cmd_fibcontext);
+ dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
+
+ dinfo->command = cpu_to_le32(VM_ContainerConfig);
+ dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
+ dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
+
+ status = aac_fib_send(ContainerCommand,
+ cmd_fibcontext,
+ sizeof (struct aac_get_serial),
+ FsaNormal,
+ 0, 1,
+ (fib_callback) get_container_serial_callback,
+ (void *) scsicmd);
+
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+
+ printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
+ aac_fib_complete(cmd_fibcontext);
+ aac_fib_free(cmd_fibcontext);
+ return -1;
+}
+
+/* Function: setinqserial
+ *
+ * Arguments: [1] pointer to void [1] int
+ *
+ * Purpose: Sets SCSI Unit Serial number.
+ * This is a fake. We should read a proper
+ * serial number from the container. <SuSE>But
+ * without docs it's quite hard to do it :-)
+ * So this will have to do in the meantime.</SuSE>
+ */
+
+static int setinqserial(struct aac_dev *dev, void *data, int cid)
+{
+ /*
+ * This breaks array migration.
+ */
+ return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
+ le32_to_cpu(dev->adapter_info.serial[0]), cid);
+}
+
static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
u8 a_sense_code, u8 incorrect_length,
u8 bit_pointer, u16 field_pointer,
@@ -825,7 +925,7 @@ static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u3
readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
readcmd->count = cpu_to_le32(count<<9);
readcmd->cid = cpu_to_le16(scmd_id(cmd));
- readcmd->flags = cpu_to_le16(1);
+ readcmd->flags = cpu_to_le16(IO_TYPE_READ);
readcmd->bpTotal = 0;
readcmd->bpComplete = 0;
@@ -904,7 +1004,7 @@ static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32
(void *) cmd);
}
-static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
{
u16 fibsize;
struct aac_raw_io *writecmd;
@@ -914,7 +1014,9 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
writecmd->count = cpu_to_le32(count<<9);
writecmd->cid = cpu_to_le16(scmd_id(cmd));
- writecmd->flags = 0;
+ writecmd->flags = fua ?
+ cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) :
+ cpu_to_le16(IO_TYPE_WRITE);
writecmd->bpTotal = 0;
writecmd->bpComplete = 0;
@@ -933,7 +1035,7 @@ static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u
(void *) cmd);
}
-static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
{
u16 fibsize;
struct aac_write64 *writecmd;
@@ -964,7 +1066,7 @@ static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba,
(void *) cmd);
}
-static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count)
+static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua)
{
u16 fibsize;
struct aac_write *writecmd;
@@ -1041,7 +1143,7 @@ static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd)
struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
aac_build_sg64(cmd, (struct sgmap64*) &srbcmd->sg);
- srbcmd->count = cpu_to_le32(cmd->request_bufflen);
+ srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
@@ -1069,7 +1171,7 @@ static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd)
struct aac_srb * srbcmd = aac_scsi_common(fib, cmd);
aac_build_sg(cmd, (struct sgmap*)&srbcmd->sg);
- srbcmd->count = cpu_to_le32(cmd->request_bufflen);
+ srbcmd->count = cpu_to_le32(scsi_bufflen(cmd));
memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len);
@@ -1172,6 +1274,7 @@ int aac_get_adapter_info(struct aac_dev* dev)
}
if (!dev->in_reset) {
+ char buffer[16];
tmp = le32_to_cpu(dev->adapter_info.kernelrev);
printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
dev->name,
@@ -1192,16 +1295,23 @@ int aac_get_adapter_info(struct aac_dev* dev)
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.biosbuild));
- if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
- printk(KERN_INFO "%s%d: serial %x\n",
- dev->name, dev->id,
- le32_to_cpu(dev->adapter_info.serial[0]));
+ buffer[0] = '\0';
+ if (aac_show_serial_number(
+ shost_to_class(dev->scsi_host_ptr), buffer))
+ printk(KERN_INFO "%s%d: serial %s",
+ dev->name, dev->id, buffer);
if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) {
printk(KERN_INFO "%s%d: TSID %.*s\n",
dev->name, dev->id,
(int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid),
dev->supplement_adapter_info.VpdInfo.Tsid);
}
+ if (!check_reset ||
+ (dev->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_IGNORE_RESET))) {
+ printk(KERN_INFO "%s%d: Reset Adapter Ignored\n",
+ dev->name, dev->id);
+ }
}
dev->nondasd_support = 0;
@@ -1332,7 +1442,7 @@ static void io_callback(void *context, struct fib * fibptr)
if (!aac_valid_context(scsicmd, fibptr))
return;
- dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+ dev = fibptr->dev;
cid = scmd_id(scsicmd);
if (nblank(dprintk(x))) {
@@ -1371,16 +1481,9 @@ static void io_callback(void *context, struct fib * fibptr)
}
BUG_ON(fibptr == NULL);
-
- if(scsicmd->use_sg)
- pci_unmap_sg(dev->pdev,
- (struct scatterlist *)scsicmd->request_buffer,
- scsicmd->use_sg,
- scsicmd->sc_data_direction);
- else if(scsicmd->request_bufflen)
- pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
+
+ scsi_dma_unmap(scsicmd);
+
readreply = (struct aac_read_reply *)fib_data(fibptr);
if (le32_to_cpu(readreply->status) == ST_OK)
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
@@ -1498,6 +1601,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
{
u64 lba;
u32 count;
+ int fua;
int status;
struct aac_dev *dev;
struct fib * cmd_fibcontext;
@@ -1512,6 +1616,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
count = scsicmd->cmnd[4];
if (count == 0)
count = 256;
+ fua = 0;
} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd)));
@@ -1524,6 +1629,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+ fua = scsicmd->cmnd[1] & 0x8;
} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd)));
@@ -1531,10 +1637,12 @@ static int aac_write(struct scsi_cmnd * scsicmd)
| (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
| (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+ fua = scsicmd->cmnd[1] & 0x8;
} else {
dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd)));
lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+ fua = scsicmd->cmnd[1] & 0x8;
}
dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
smp_processor_id(), (unsigned long long)lba, jiffies));
@@ -1549,7 +1657,7 @@ static int aac_write(struct scsi_cmnd * scsicmd)
return 0;
}
- status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count);
+ status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua);
/*
* Check that the command queued to the controller
@@ -1592,7 +1700,7 @@ static void synchronize_callback(void *context, struct fib *fibptr)
COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
else {
struct scsi_device *sdev = cmd->device;
- struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+ struct aac_dev *dev = fibptr->dev;
u32 cid = sdev_id(sdev);
printk(KERN_WARNING
"synchronize_callback: synchronize failed, status = %d\n",
@@ -1699,7 +1807,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd)
int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
{
- u32 cid = 0;
+ u32 cid;
struct Scsi_Host *host = scsicmd->device->host;
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
@@ -1711,15 +1819,15 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* Test does not apply to ID 16, the pseudo id for the controller
* itself.
*/
- if (scmd_id(scsicmd) != host->this_id) {
- if ((scmd_channel(scsicmd) == CONTAINER_CHANNEL)) {
- if((scmd_id(scsicmd) >= dev->maximum_num_containers) ||
+ cid = scmd_id(scsicmd);
+ if (cid != host->this_id) {
+ if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) {
+ if((cid >= dev->maximum_num_containers) ||
(scsicmd->device->lun != 0)) {
scsicmd->result = DID_NO_CONNECT << 16;
scsicmd->scsi_done(scsicmd);
return 0;
}
- cid = scmd_id(scsicmd);
/*
* If the target container doesn't exist, it may have
@@ -1782,9 +1890,52 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
{
struct inquiry_data inq_data;
- dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scmd_id(scsicmd)));
+ dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
memset(&inq_data, 0, sizeof (struct inquiry_data));
+ if (scsicmd->cmnd[1] & 0x1 ) {
+ char *arr = (char *)&inq_data;
+
+ /* EVPD bit set */
+ arr[0] = (scmd_id(scsicmd) == host->this_id) ?
+ INQD_PDT_PROC : INQD_PDT_DA;
+ if (scsicmd->cmnd[2] == 0) {
+ /* supported vital product data pages */
+ arr[3] = 2;
+ arr[4] = 0x0;
+ arr[5] = 0x80;
+ arr[1] = scsicmd->cmnd[2];
+ aac_internal_transfer(scsicmd, &inq_data, 0,
+ sizeof(inq_data));
+ scsicmd->result = DID_OK << 16 |
+ COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+ } else if (scsicmd->cmnd[2] == 0x80) {
+ /* unit serial number page */
+ arr[3] = setinqserial(dev, &arr[4],
+ scmd_id(scsicmd));
+ arr[1] = scsicmd->cmnd[2];
+ aac_internal_transfer(scsicmd, &inq_data, 0,
+ sizeof(inq_data));
+ return aac_get_container_serial(scsicmd);
+ } else {
+ /* vpd page not implemented */
+ scsicmd->result = DID_OK << 16 |
+ COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+ ILLEGAL_REQUEST,
+ SENCODE_INVALID_CDB_FIELD,
+ ASENCODE_NO_SENSE, 0, 7, 2, 0);
+ memcpy(scsicmd->sense_buffer,
+ &dev->fsa_dev[cid].sense_data,
+ (sizeof(dev->fsa_dev[cid].sense_data) >
+ sizeof(scsicmd->sense_buffer))
+ ? sizeof(scsicmd->sense_buffer)
+ : sizeof(dev->fsa_dev[cid].sense_data));
+ }
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */
inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
inq_data.inqd_len = 31;
@@ -1794,7 +1945,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
* Set the Vendor, Product, and Revision Level
* see: <vendor>.c i.e. aac.c
*/
- if (scmd_id(scsicmd) == host->this_id) {
+ if (cid == host->this_id) {
setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types));
inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
@@ -1886,15 +2037,29 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case MODE_SENSE:
{
- char mode_buf[4];
+ char mode_buf[7];
+ int mode_buf_length = 4;
dprintk((KERN_DEBUG "MODE SENSE command.\n"));
mode_buf[0] = 3; /* Mode data length */
mode_buf[1] = 0; /* Medium type - default */
- mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */
+ mode_buf[2] = 0; /* Device-specific param,
+ bit 8: 0/1 = write enabled/protected
+ bit 4: 0/1 = FUA enabled */
+ if (dev->raw_io_interface)
+ mode_buf[2] = 0x10;
mode_buf[3] = 0; /* Block descriptor length */
-
- aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
+ if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
+ ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
+ mode_buf[0] = 6;
+ mode_buf[4] = 8;
+ mode_buf[5] = 1;
+ mode_buf[6] = 0x04; /* WCE */
+ mode_buf_length = 7;
+ if (mode_buf_length > scsicmd->cmnd[4])
+ mode_buf_length = scsicmd->cmnd[4];
+ }
+ aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length);
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
@@ -1902,18 +2067,33 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
}
case MODE_SENSE_10:
{
- char mode_buf[8];
+ char mode_buf[11];
+ int mode_buf_length = 8;
dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
mode_buf[0] = 0; /* Mode data length (MSB) */
mode_buf[1] = 6; /* Mode data length (LSB) */
mode_buf[2] = 0; /* Medium type - default */
- mode_buf[3] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */
+ mode_buf[3] = 0; /* Device-specific param,
+ bit 8: 0/1 = write enabled/protected
+ bit 4: 0/1 = FUA enabled */
+ if (dev->raw_io_interface)
+ mode_buf[3] = 0x10;
mode_buf[4] = 0; /* reserved */
mode_buf[5] = 0; /* reserved */
mode_buf[6] = 0; /* Block descriptor length (MSB) */
mode_buf[7] = 0; /* Block descriptor length (LSB) */
- aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf));
+ if (((scsicmd->cmnd[2] & 0x3f) == 8) ||
+ ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) {
+ mode_buf[1] = 9;
+ mode_buf[8] = 8;
+ mode_buf[9] = 1;
+ mode_buf[10] = 0x04; /* WCE */
+ mode_buf_length = 11;
+ if (mode_buf_length > scsicmd->cmnd[8])
+ mode_buf_length = scsicmd->cmnd[8];
+ }
+ aac_internal_transfer(scsicmd, mode_buf, 0, mode_buf_length);
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
@@ -2028,7 +2208,7 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
}
else return -EINVAL;
- qd.valid = fsa_dev_ptr[qd.cnum].valid;
+ qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
qd.locked = fsa_dev_ptr[qd.cnum].locked;
qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
@@ -2136,28 +2316,21 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
if (!aac_valid_context(scsicmd, fibptr))
return;
- dev = (struct aac_dev *)scsicmd->device->host->hostdata;
-
BUG_ON(fibptr == NULL);
+ dev = fibptr->dev;
+
srbreply = (struct aac_srb_reply *) fib_data(fibptr);
scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */
/*
* Calculate resid for sg
*/
-
- scsicmd->resid = scsicmd->request_bufflen -
- le32_to_cpu(srbreply->data_xfer_length);
-
- if(scsicmd->use_sg)
- pci_unmap_sg(dev->pdev,
- (struct scatterlist *)scsicmd->request_buffer,
- scsicmd->use_sg,
- scsicmd->sc_data_direction);
- else if(scsicmd->request_bufflen)
- pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
+
+ scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
+ - le32_to_cpu(srbreply->data_xfer_length));
+
+ scsi_dma_unmap(scsicmd);
/*
* First check the fib status
@@ -2233,7 +2406,7 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
break;
case SRB_STATUS_BUSY:
- scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+ scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
break;
case SRB_STATUS_BUS_RESET:
@@ -2343,34 +2516,33 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
{
struct aac_dev *dev;
unsigned long byte_count = 0;
+ int nseg;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
// Get rid of old data
psg->count = 0;
psg->sg[0].addr = 0;
- psg->sg[0].count = 0;
- if (scsicmd->use_sg) {
+ psg->sg[0].count = 0;
+
+ nseg = scsi_dma_map(scsicmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
struct scatterlist *sg;
int i;
- int sg_count;
- sg = (struct scatterlist *) scsicmd->request_buffer;
- sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
- scsicmd->sc_data_direction);
- psg->count = cpu_to_le32(sg_count);
+ psg->count = cpu_to_le32(nseg);
- for (i = 0; i < sg_count; i++) {
+ scsi_for_each_sg(scsicmd, sg, nseg, i) {
psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
byte_count += sg_dma_len(sg);
- sg++;
}
/* hba wants the size to be exact */
- if(byte_count > scsicmd->request_bufflen){
- u32 temp = le32_to_cpu(psg->sg[i-1].count) -
- (byte_count - scsicmd->request_bufflen);
+ if (byte_count > scsi_bufflen(scsicmd)) {
+ u32 temp = le32_to_cpu(psg->sg[i-1].count) -
+ (byte_count - scsi_bufflen(scsicmd));
psg->sg[i-1].count = cpu_to_le32(temp);
- byte_count = scsicmd->request_bufflen;
+ byte_count = scsi_bufflen(scsicmd);
}
/* Check for command underflow */
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
@@ -2378,18 +2550,6 @@ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
byte_count, scsicmd->underflow);
}
}
- else if(scsicmd->request_bufflen) {
- u32 addr;
- scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
- scsicmd->request_buffer,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
- addr = scsicmd->SCp.dma_handle;
- psg->count = cpu_to_le32(1);
- psg->sg[0].addr = cpu_to_le32(addr);
- psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);
- byte_count = scsicmd->request_bufflen;
- }
return byte_count;
}
@@ -2399,6 +2559,7 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
struct aac_dev *dev;
unsigned long byte_count = 0;
u64 addr;
+ int nseg;
dev = (struct aac_dev *)scsicmd->device->host->hostdata;
// Get rid of old data
@@ -2406,31 +2567,28 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
psg->sg[0].addr[0] = 0;
psg->sg[0].addr[1] = 0;
psg->sg[0].count = 0;
- if (scsicmd->use_sg) {
+
+ nseg = scsi_dma_map(scsicmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
struct scatterlist *sg;
int i;
- int sg_count;
- sg = (struct scatterlist *) scsicmd->request_buffer;
- sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
- scsicmd->sc_data_direction);
-
- for (i = 0; i < sg_count; i++) {
+ scsi_for_each_sg(scsicmd, sg, nseg, i) {
int count = sg_dma_len(sg);
addr = sg_dma_address(sg);
psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff);
psg->sg[i].addr[1] = cpu_to_le32(addr>>32);
psg->sg[i].count = cpu_to_le32(count);
byte_count += count;
- sg++;
}
- psg->count = cpu_to_le32(sg_count);
+ psg->count = cpu_to_le32(nseg);
/* hba wants the size to be exact */
- if(byte_count > scsicmd->request_bufflen){
- u32 temp = le32_to_cpu(psg->sg[i-1].count) -
- (byte_count - scsicmd->request_bufflen);
+ if (byte_count > scsi_bufflen(scsicmd)) {
+ u32 temp = le32_to_cpu(psg->sg[i-1].count) -
+ (byte_count - scsi_bufflen(scsicmd));
psg->sg[i-1].count = cpu_to_le32(temp);
- byte_count = scsicmd->request_bufflen;
+ byte_count = scsi_bufflen(scsicmd);
}
/* Check for command underflow */
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
@@ -2438,26 +2596,13 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p
byte_count, scsicmd->underflow);
}
}
- else if(scsicmd->request_bufflen) {
- scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
- scsicmd->request_buffer,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
- addr = scsicmd->SCp.dma_handle;
- psg->count = cpu_to_le32(1);
- psg->sg[0].addr[0] = cpu_to_le32(addr & 0xffffffff);
- psg->sg[0].addr[1] = cpu_to_le32(addr >> 32);
- psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);
- byte_count = scsicmd->request_bufflen;
- }
return byte_count;
}
static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg)
{
- struct Scsi_Host *host = scsicmd->device->host;
- struct aac_dev *dev = (struct aac_dev *)host->hostdata;
unsigned long byte_count = 0;
+ int nseg;
// Get rid of old data
psg->count = 0;
@@ -2467,16 +2612,14 @@ static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw*
psg->sg[0].addr[1] = 0;
psg->sg[0].count = 0;
psg->sg[0].flags = 0;
- if (scsicmd->use_sg) {
+
+ nseg = scsi_dma_map(scsicmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
struct scatterlist *sg;
int i;
- int sg_count;
- sg = (struct scatterlist *) scsicmd->request_buffer;
-
- sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
- scsicmd->sc_data_direction);
- for (i = 0; i < sg_count; i++) {
+ scsi_for_each_sg(scsicmd, sg, nseg, i) {
int count = sg_dma_len(sg);
u64 addr = sg_dma_address(sg);
psg->sg[i].next = 0;
@@ -2486,15 +2629,14 @@ static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw*
psg->sg[i].count = cpu_to_le32(count);
psg->sg[i].flags = 0;
byte_count += count;
- sg++;
}
- psg->count = cpu_to_le32(sg_count);
+ psg->count = cpu_to_le32(nseg);
/* hba wants the size to be exact */
- if(byte_count > scsicmd->request_bufflen){
- u32 temp = le32_to_cpu(psg->sg[i-1].count) -
- (byte_count - scsicmd->request_bufflen);
+ if (byte_count > scsi_bufflen(scsicmd)) {
+ u32 temp = le32_to_cpu(psg->sg[i-1].count) -
+ (byte_count - scsi_bufflen(scsicmd));
psg->sg[i-1].count = cpu_to_le32(temp);
- byte_count = scsicmd->request_bufflen;
+ byte_count = scsi_bufflen(scsicmd);
}
/* Check for command underflow */
if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
@@ -2502,24 +2644,6 @@ static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw*
byte_count, scsicmd->underflow);
}
}
- else if(scsicmd->request_bufflen) {
- int count;
- u64 addr;
- scsicmd->SCp.dma_handle = pci_map_single(dev->pdev,
- scsicmd->request_buffer,
- scsicmd->request_bufflen,
- scsicmd->sc_data_direction);
- addr = scsicmd->SCp.dma_handle;
- count = scsicmd->request_bufflen;
- psg->count = cpu_to_le32(1);
- psg->sg[0].next = 0;
- psg->sg[0].prev = 0;
- psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32));
- psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff));
- psg->sg[0].count = cpu_to_le32(count);
- psg->sg[0].flags = 0;
- byte_count = scsicmd->request_bufflen;
- }
return byte_count;
}
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index c81edf36913f..400d03403cd5 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,8 +12,8 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2437
-# define AAC_DRIVER_BRANCH "-mh4"
+# define AAC_DRIVER_BUILD 2447
+# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -464,12 +464,12 @@ struct adapter_ops
int (*adapter_restart)(struct aac_dev *dev, int bled);
/* Transport operations */
int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
- irqreturn_t (*adapter_intr)(int irq, void *dev_id);
+ irq_handler_t adapter_intr;
/* Packet operations */
int (*adapter_deliver)(struct fib * fib);
int (*adapter_bounds)(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba);
int (*adapter_read)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count);
- int (*adapter_write)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count);
+ int (*adapter_write)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua);
int (*adapter_scsi)(struct fib * fib, struct scsi_cmnd * cmd);
/* Administrative operations */
int (*adapter_comm)(struct aac_dev * dev, int comm);
@@ -860,10 +860,12 @@ struct aac_supplement_adapter_info
__le32 FlashFirmwareBootBuild;
u8 MfgPcbaSerialNo[12];
u8 MfgWWNName[8];
- __le32 MoreFeatureBits;
+ __le32 SupportedOptions2;
__le32 ReservedGrowth[1];
};
#define AAC_FEATURE_FALCON 0x00000010
+#define AAC_OPTION_MU_RESET 0x00000001
+#define AAC_OPTION_IGNORE_RESET 0x00000002
#define AAC_SIS_VERSION_V3 3
#define AAC_SIS_SLOT_UNKNOWN 0xFF
@@ -1054,8 +1056,8 @@ struct aac_dev
#define aac_adapter_read(fib,cmd,lba,count) \
((fib)->dev)->a_ops.adapter_read(fib,cmd,lba,count)
-#define aac_adapter_write(fib,cmd,lba,count) \
- ((fib)->dev)->a_ops.adapter_write(fib,cmd,lba,count)
+#define aac_adapter_write(fib,cmd,lba,count,fua) \
+ ((fib)->dev)->a_ops.adapter_write(fib,cmd,lba,count,fua)
#define aac_adapter_scsi(fib,cmd) \
((fib)->dev)->a_ops.adapter_scsi(fib,cmd)
@@ -1213,6 +1215,9 @@ struct aac_write64
__le32 block;
__le16 pad;
__le16 flags;
+#define IO_TYPE_WRITE 0x00000000
+#define IO_TYPE_READ 0x00000001
+#define IO_SUREWRITE 0x00000008
struct sgmap64 sg; // Must be last in struct because it is variable
};
struct aac_write_reply
@@ -1257,6 +1262,19 @@ struct aac_synchronize_reply {
u8 data[16];
};
+#define CT_PAUSE_IO 65
+#define CT_RELEASE_IO 66
+struct aac_pause {
+ __le32 command; /* VM_ContainerConfig */
+ __le32 type; /* CT_PAUSE_IO */
+ __le32 timeout; /* 10ms ticks */
+ __le32 min;
+ __le32 noRescan;
+ __le32 parm3;
+ __le32 parm4;
+ __le32 count; /* sizeof(((struct aac_pause_reply *)NULL)->data) */
+};
+
struct aac_srb
{
__le32 function;
@@ -1549,6 +1567,20 @@ struct aac_get_name_resp {
u8 data[16];
};
+#define CT_CID_TO_32BITS_UID 165
+struct aac_get_serial {
+ __le32 command; /* VM_ContainerConfig */
+ __le32 type; /* CT_CID_TO_32BITS_UID */
+ __le32 cid;
+};
+
+struct aac_get_serial_resp {
+ __le32 dummy0;
+ __le32 dummy1;
+ __le32 status; /* CT_OK */
+ __le32 uid;
+};
+
/*
* The following command is sent to shut down each container.
*/
@@ -1804,6 +1836,10 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev);
int aac_scsi_cmd(struct scsi_cmnd *cmd);
int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
+#ifndef shost_to_class
+#define shost_to_class(shost) &shost->shost_classdev
+#endif
+ssize_t aac_show_serial_number(struct class_device *class_dev, char *buf);
int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg);
int aac_rx_init(struct aac_dev *dev);
int aac_rkt_init(struct aac_dev *dev);
@@ -1813,6 +1849,7 @@ int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
+int aac_reset_adapter(struct aac_dev * dev, int forced);
int aac_check_health(struct aac_dev * dev);
int aac_command_thread(void *data);
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
@@ -1832,3 +1869,6 @@ extern int aif_timeout;
extern int expose_physicals;
extern int aac_reset_devices;
extern int aac_commit;
+extern int update_interval;
+extern int check_interval;
+extern int check_reset;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 9aca57eda943..bb870906b4cf 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -80,7 +80,11 @@ static int fib_map_alloc(struct aac_dev *dev)
void aac_fib_map_free(struct aac_dev *dev)
{
- pci_free_consistent(dev->pdev, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), dev->hw_fib_va, dev->hw_fib_pa);
+ pci_free_consistent(dev->pdev,
+ dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
+ dev->hw_fib_va, dev->hw_fib_pa);
+ dev->hw_fib_va = NULL;
+ dev->hw_fib_pa = 0;
}
/**
@@ -1021,7 +1025,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
}
-static int _aac_reset_adapter(struct aac_dev *aac)
+static int _aac_reset_adapter(struct aac_dev *aac, int forced)
{
int index, quirks;
int retval;
@@ -1029,25 +1033,32 @@ static int _aac_reset_adapter(struct aac_dev *aac)
struct scsi_device *dev;
struct scsi_cmnd *command;
struct scsi_cmnd *command_list;
+ int jafo = 0;
/*
* Assumptions:
- * - host is locked.
+ * - host is locked, unless called by the aacraid thread.
+ * (a matter of convenience, due to legacy issues surrounding
+ * eh_host_adapter_reset).
* - in_reset is asserted, so no new i/o is getting to the
* card.
- * - The card is dead.
+ * - The card is dead, or will be very shortly ;-/ so no new
+ * commands are completing in the interrupt service.
*/
host = aac->scsi_host_ptr;
scsi_block_requests(host);
aac_adapter_disable_int(aac);
- spin_unlock_irq(host->host_lock);
- kthread_stop(aac->thread);
+ if (aac->thread->pid != current->pid) {
+ spin_unlock_irq(host->host_lock);
+ kthread_stop(aac->thread);
+ jafo = 1;
+ }
/*
* If a positive health, means in a known DEAD PANIC
* state and the adapter could be reset to `try again'.
*/
- retval = aac_adapter_restart(aac, aac_adapter_check_health(aac));
+ retval = aac_adapter_restart(aac, forced ? 0 : aac_adapter_check_health(aac));
if (retval)
goto out;
@@ -1080,8 +1091,6 @@ static int _aac_reset_adapter(struct aac_dev *aac)
* case.
*/
aac_fib_map_free(aac);
- aac->hw_fib_va = NULL;
- aac->hw_fib_pa = 0;
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
aac->comm_addr = NULL;
aac->comm_phys = 0;
@@ -1091,12 +1100,12 @@ static int _aac_reset_adapter(struct aac_dev *aac)
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
- if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
goto out;
} else {
- if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
- ((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
goto out;
}
if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
@@ -1104,10 +1113,12 @@ static int _aac_reset_adapter(struct aac_dev *aac)
if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
goto out;
- aac->thread = kthread_run(aac_command_thread, aac, aac->name);
- if (IS_ERR(aac->thread)) {
- retval = PTR_ERR(aac->thread);
- goto out;
+ if (jafo) {
+ aac->thread = kthread_run(aac_command_thread, aac, aac->name);
+ if (IS_ERR(aac->thread)) {
+ retval = PTR_ERR(aac->thread);
+ goto out;
+ }
}
(void)aac_get_adapter_info(aac);
quirks = aac_get_driver_ident(index)->quirks;
@@ -1150,7 +1161,98 @@ static int _aac_reset_adapter(struct aac_dev *aac)
out:
aac->in_reset = 0;
scsi_unblock_requests(host);
- spin_lock_irq(host->host_lock);
+ if (jafo) {
+ spin_lock_irq(host->host_lock);
+ }
+ return retval;
+}
+
+int aac_reset_adapter(struct aac_dev * aac, int forced)
+{
+ unsigned long flagv = 0;
+ int retval;
+ struct Scsi_Host * host;
+
+ if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
+ return -EBUSY;
+
+ if (aac->in_reset) {
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+ return -EBUSY;
+ }
+ aac->in_reset = 1;
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+
+ /*
+ * Wait for all commands to complete to this specific
+ * target (block maximum 60 seconds). Although not necessary,
+ * it does make us a good storage citizen.
+ */
+ host = aac->scsi_host_ptr;
+ scsi_block_requests(host);
+ if (forced < 2) for (retval = 60; retval; --retval) {
+ struct scsi_device * dev;
+ struct scsi_cmnd * command;
+ int active = 0;
+
+ __shost_for_each_device(dev, host) {
+ spin_lock_irqsave(&dev->list_lock, flagv);
+ list_for_each_entry(command, &dev->cmd_list, list) {
+ if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
+ active++;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->list_lock, flagv);
+ if (active)
+ break;
+
+ }
+ /*
+ * We can exit If all the commands are complete
+ */
+ if (active == 0)
+ break;
+ ssleep(1);
+ }
+
+ /* Quiesce build, flush cache, write through mode */
+ aac_send_shutdown(aac);
+ spin_lock_irqsave(host->host_lock, flagv);
+ retval = _aac_reset_adapter(aac, forced);
+ spin_unlock_irqrestore(host->host_lock, flagv);
+
+ if (retval == -ENODEV) {
+ /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */
+ struct fib * fibctx = aac_fib_alloc(aac);
+ if (fibctx) {
+ struct aac_pause *cmd;
+ int status;
+
+ aac_fib_init(fibctx);
+
+ cmd = (struct aac_pause *) fib_data(fibctx);
+
+ cmd->command = cpu_to_le32(VM_ContainerConfig);
+ cmd->type = cpu_to_le32(CT_PAUSE_IO);
+ cmd->timeout = cpu_to_le32(1);
+ cmd->min = cpu_to_le32(1);
+ cmd->noRescan = cpu_to_le32(1);
+ cmd->count = cpu_to_le32(0);
+
+ status = aac_fib_send(ContainerCommand,
+ fibctx,
+ sizeof(struct aac_pause),
+ FsaNormal,
+ -2 /* Timeout silently */, 1,
+ NULL, NULL);
+
+ if (status >= 0)
+ aac_fib_complete(fibctx);
+ aac_fib_free(fibctx);
+ }
+ }
+
return retval;
}
@@ -1270,10 +1372,15 @@ int aac_check_health(struct aac_dev * aac)
printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
+ if (!check_reset || (aac->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_IGNORE_RESET)))
+ goto out;
host = aac->scsi_host_ptr;
- spin_lock_irqsave(host->host_lock, flagv);
- BlinkLED = _aac_reset_adapter(aac);
- spin_unlock_irqrestore(host->host_lock, flagv);
+ if (aac->thread->pid != current->pid)
+ spin_lock_irqsave(host->host_lock, flagv);
+ BlinkLED = _aac_reset_adapter(aac, 0);
+ if (aac->thread->pid != current->pid)
+ spin_unlock_irqrestore(host->host_lock, flagv);
return BlinkLED;
out:
@@ -1300,6 +1407,9 @@ int aac_command_thread(void *data)
struct aac_fib_context *fibctx;
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
+ unsigned long next_jiffies = jiffies + HZ;
+ unsigned long next_check_jiffies = next_jiffies;
+ long difference = HZ;
/*
* We can only have one thread per adapter for AIF's.
@@ -1368,7 +1478,7 @@ int aac_command_thread(void *data)
cpu_to_le32(AifCmdJobProgress))) {
aac_handle_aif(dev, fib);
}
-
+
time_now = jiffies/HZ;
/*
@@ -1507,11 +1617,79 @@ int aac_command_thread(void *data)
* There are no more AIF's
*/
spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
- schedule();
+
+ /*
+ * Background activity
+ */
+ if ((time_before(next_check_jiffies,next_jiffies))
+ && ((difference = next_check_jiffies - jiffies) <= 0)) {
+ next_check_jiffies = next_jiffies;
+ if (aac_check_health(dev) == 0) {
+ difference = ((long)(unsigned)check_interval)
+ * HZ;
+ next_check_jiffies = jiffies + difference;
+ } else if (!dev->queues)
+ break;
+ }
+ if (!time_before(next_check_jiffies,next_jiffies)
+ && ((difference = next_jiffies - jiffies) <= 0)) {
+ struct timeval now;
+ int ret;
+
+ /* Don't even try to talk to adapter if its sick */
+ ret = aac_check_health(dev);
+ if (!ret && !dev->queues)
+ break;
+ next_check_jiffies = jiffies
+ + ((long)(unsigned)check_interval)
+ * HZ;
+ do_gettimeofday(&now);
+
+ /* Synchronize our watches */
+ if (((1000000 - (1000000 / HZ)) > now.tv_usec)
+ && (now.tv_usec > (1000000 / HZ)))
+ difference = (((1000000 - now.tv_usec) * HZ)
+ + 500000) / 1000000;
+ else if (ret == 0) {
+ struct fib *fibptr;
+
+ if ((fibptr = aac_fib_alloc(dev))) {
+ u32 * info;
+
+ aac_fib_init(fibptr);
+
+ info = (u32 *) fib_data(fibptr);
+ if (now.tv_usec > 500000)
+ ++now.tv_sec;
+
+ *info = cpu_to_le32(now.tv_sec);
+
+ (void)aac_fib_send(SendHostTime,
+ fibptr,
+ sizeof(*info),
+ FsaNormal,
+ 1, 1,
+ NULL,
+ NULL);
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ }
+ difference = (long)(unsigned)update_interval*HZ;
+ } else {
+ /* retry shortly */
+ difference = 10 * HZ;
+ }
+ next_jiffies = jiffies + difference;
+ if (time_before(next_check_jiffies,next_jiffies))
+ difference = next_check_jiffies - jiffies;
+ }
+ if (difference <= 0)
+ difference = 1;
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(difference);
if (kthread_should_stop())
break;
- set_current_state(TASK_INTERRUPTIBLE);
}
if (dev->queues)
remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 5c487ff096c7..d76e1a8cb93a 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -39,10 +39,8 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <linux/dma-mapping.h>
#include <linux/syscalls.h>
#include <linux/delay.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <asm/semaphore.h>
@@ -223,12 +221,12 @@ static struct aac_driver_ident aac_drivers[] = {
{ aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
{ aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
{ aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
- { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell PERC2/QC */
+ { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */
{ aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
{ aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
{ aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
- { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */
+ { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */
{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */
{ aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec NEMER/ARK Catch All */
};
@@ -403,10 +401,6 @@ static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
static int aac_slave_configure(struct scsi_device *sdev)
{
- if (sdev_channel(sdev) == CONTAINER_CHANNEL) {
- sdev->skip_ms_page_8 = 1;
- sdev->skip_ms_page_3f = 1;
- }
if ((sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
if (expose_physicals == 0)
@@ -450,6 +444,43 @@ static int aac_slave_configure(struct scsi_device *sdev)
return 0;
}
+/**
+ * aac_change_queue_depth - alter queue depths
+ * @sdev: SCSI device we are considering
+ * @depth: desired queue depth
+ *
+ * Alters queue depths for target device based on the host adapter's
+ * total capacity and the queue depth supported by the target device.
+ */
+
+static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
+{
+ if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
+ (sdev_channel(sdev) == CONTAINER_CHANNEL)) {
+ struct scsi_device * dev;
+ struct Scsi_Host *host = sdev->host;
+ unsigned num = 0;
+
+ __shost_for_each_device(dev, host) {
+ if (dev->tagged_supported && (dev->type == TYPE_DISK) &&
+ (sdev_channel(dev) == CONTAINER_CHANNEL))
+ ++num;
+ ++num;
+ }
+ if (num >= host->can_queue)
+ num = host->can_queue - 1;
+ if (depth > (host->can_queue - num))
+ depth = host->can_queue - num;
+ if (depth > 256)
+ depth = 256;
+ else if (depth < 2)
+ depth = 2;
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
+ } else
+ scsi_adjust_queue_depth(sdev, 0, 1);
+ return sdev->queue_depth;
+}
+
static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
{
struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
@@ -548,6 +579,14 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
ssleep(1);
}
printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
+ /*
+ * This adapter needs a blind reset, only do so for Adapters that
+ * support a register, instead of a commanded, reset.
+ */
+ if ((aac->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_MU_RESET|AAC_OPTION_IGNORE_RESET)) ==
+ le32_to_cpu(AAC_OPTION_MU_RESET))
+ aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */
return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */
}
@@ -731,15 +770,21 @@ static ssize_t aac_show_bios_version(struct class_device *class_dev,
return len;
}
-static ssize_t aac_show_serial_number(struct class_device *class_dev,
- char *buf)
+ssize_t aac_show_serial_number(struct class_device *class_dev, char *buf)
{
struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
int len = 0;
if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
- len = snprintf(buf, PAGE_SIZE, "%x\n",
+ len = snprintf(buf, PAGE_SIZE, "%06X\n",
le32_to_cpu(dev->adapter_info.serial[0]));
+ if (len &&
+ !memcmp(&dev->supplement_adapter_info.MfgPcbaSerialNo[
+ sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo)+2-len],
+ buf, len))
+ len = snprintf(buf, PAGE_SIZE, "%.*s\n",
+ (int)sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo),
+ dev->supplement_adapter_info.MfgPcbaSerialNo);
return len;
}
@@ -755,6 +800,31 @@ static ssize_t aac_show_max_id(struct class_device *class_dev, char *buf)
class_to_shost(class_dev)->max_id);
}
+static ssize_t aac_store_reset_adapter(struct class_device *class_dev,
+ const char *buf, size_t count)
+{
+ int retval = -EACCES;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return retval;
+ retval = aac_reset_adapter((struct aac_dev*)class_to_shost(class_dev)->hostdata, buf[0] == '!');
+ if (retval >= 0)
+ retval = count;
+ return retval;
+}
+
+static ssize_t aac_show_reset_adapter(struct class_device *class_dev,
+ char *buf)
+{
+ struct aac_dev *dev = (struct aac_dev*)class_to_shost(class_dev)->hostdata;
+ int len, tmp;
+
+ tmp = aac_adapter_check_health(dev);
+ if ((tmp == 0) && dev->in_reset)
+ tmp = -EBUSY;
+ len = snprintf(buf, PAGE_SIZE, "0x%x", tmp);
+ return len;
+}
static struct class_device_attribute aac_model = {
.attr = {
@@ -812,6 +882,14 @@ static struct class_device_attribute aac_max_id = {
},
.show = aac_show_max_id,
};
+static struct class_device_attribute aac_reset = {
+ .attr = {
+ .name = "reset_host",
+ .mode = S_IWUSR|S_IRUGO,
+ },
+ .store = aac_store_reset_adapter,
+ .show = aac_show_reset_adapter,
+};
static struct class_device_attribute *aac_attrs[] = {
&aac_model,
@@ -822,6 +900,7 @@ static struct class_device_attribute *aac_attrs[] = {
&aac_serial_number,
&aac_max_channel,
&aac_max_id,
+ &aac_reset,
NULL
};
@@ -848,6 +927,7 @@ static struct scsi_host_template aac_driver_template = {
.bios_param = aac_biosparm,
.shost_attrs = aac_attrs,
.slave_configure = aac_slave_configure,
+ .change_queue_depth = aac_change_queue_depth,
.eh_abort_handler = aac_eh_abort,
.eh_host_reset_handler = aac_eh_reset,
.can_queue = AAC_NUM_IO_FIB,
@@ -1086,7 +1166,7 @@ static int __init aac_init(void)
{
int error;
- printk(KERN_INFO "Adaptec %s driver (%s)\n",
+ printk(KERN_INFO "Adaptec %s driver %s\n",
AAC_DRIVERNAME, aac_driver_version);
error = pci_register_driver(&aac_pci_driver);
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index ae978a373c56..ebc65b9fea92 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -464,21 +464,24 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled)
{
u32 var;
- if (bled)
- printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
- dev->name, dev->id, bled);
- else {
- bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
- 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
- if (!bled && (var != 0x00000001))
- bled = -EINVAL;
- }
- if (bled && (bled != -ETIMEDOUT))
- bled = aac_adapter_sync_cmd(dev, IOP_RESET,
- 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+ if (!(dev->supplement_adapter_info.SupportedOptions2 &
+ le32_to_cpu(AAC_OPTION_MU_RESET)) || (bled >= 0) || (bled == -2)) {
+ if (bled)
+ printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n",
+ dev->name, dev->id, bled);
+ else {
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
+ if (!bled && (var != 0x00000001))
+ bled = -EINVAL;
+ }
+ if (bled && (bled != -ETIMEDOUT))
+ bled = aac_adapter_sync_cmd(dev, IOP_RESET,
+ 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
- if (bled && (bled != -ETIMEDOUT))
- return -EINVAL;
+ if (bled && (bled != -ETIMEDOUT))
+ return -EINVAL;
+ }
if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */
rx_writel(dev, MUnit.reserved2, 3);
msleep(5000); /* Delay 5 seconds */
@@ -596,7 +599,7 @@ int _aac_rx_init(struct aac_dev *dev)
}
msleep(1);
}
- if (restart)
+ if (restart && aac_commit)
aac_commit = 1;
/*
* Fill in the common function dispatch table.
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 9b3303b64113..2b6689709e53 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -798,7 +798,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
-#include "advansys.h"
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif /* CONFIG_PCI */
@@ -2014,7 +2013,7 @@ STATIC int AscSgListToQueue(int);
STATIC void AscEnableIsaDma(uchar);
#endif /* CONFIG_ISA */
STATIC ASC_DCNT AscGetMaxDmaCount(ushort);
-
+static const char *advansys_info(struct Scsi_Host *shp);
/*
* --- Adv Library Constants and Macros
@@ -3970,10 +3969,6 @@ STATIC ushort asc_bus[ASC_NUM_BUS] __initdata = {
ASC_IS_PCI,
};
-/*
- * Used with the LILO 'advansys' option to eliminate or
- * limit I/O port probing at boot time, cf. advansys_setup().
- */
STATIC int asc_iopflag = ASC_FALSE;
STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
@@ -4055,10 +4050,6 @@ STATIC void asc_prt_hex(char *f, uchar *, int);
#endif /* ADVANSYS_DEBUG */
-/*
- * --- Linux 'struct scsi_host_template' and advansys_setup() Functions
- */
-
#ifdef CONFIG_PROC_FS
/*
* advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
@@ -4080,7 +4071,7 @@ STATIC void asc_prt_hex(char *f, uchar *, int);
* if 'prtbuf' is too small it will not be overwritten. Instead the
* user just won't get all the available statistics.
*/
-int
+static int
advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
off_t offset, int length, int inout)
{
@@ -4296,7 +4287,7 @@ advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
* it must not call SCSI mid-level functions including scsi_malloc()
* and scsi_free().
*/
-int __init
+static int __init
advansys_detect(struct scsi_host_template *tpnt)
{
static int detect_called = ASC_FALSE;
@@ -5428,7 +5419,7 @@ advansys_detect(struct scsi_host_template *tpnt)
*
* Release resources allocated for a single AdvanSys adapter.
*/
-int
+static int
advansys_release(struct Scsi_Host *shp)
{
asc_board_t *boardp;
@@ -5475,7 +5466,7 @@ advansys_release(struct Scsi_Host *shp)
* Note: The information line should not exceed ASC_INFO_SIZE bytes,
* otherwise the static 'info' array will be overrun.
*/
-const char *
+static const char *
advansys_info(struct Scsi_Host *shp)
{
static char info[ASC_INFO_SIZE];
@@ -5568,7 +5559,7 @@ advansys_info(struct Scsi_Host *shp)
* This function always returns 0. Command return status is saved
* in the 'scp' result field.
*/
-int
+static int
advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
{
struct Scsi_Host *shp;
@@ -5656,7 +5647,7 @@ advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
* sleeping is allowed and no locking other than for host structures is
* required. Returns SUCCESS or FAILED.
*/
-int
+static int
advansys_reset(struct scsi_cmnd *scp)
{
struct Scsi_Host *shp;
@@ -5841,7 +5832,7 @@ advansys_reset(struct scsi_cmnd *scp)
* ip[1]: sectors
* ip[2]: cylinders
*/
-int
+static int
advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int ip[])
{
@@ -5875,82 +5866,6 @@ advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
}
/*
- * advansys_setup()
- *
- * This function is called from init/main.c at boot time.
- * It it passed LILO parameters that can be set from the
- * LILO command line or in /etc/lilo.conf.
- *
- * It is used by the AdvanSys driver to either disable I/O
- * port scanning or to limit scanning to 1 - 4 I/O ports.
- * Regardless of the option setting EISA and PCI boards
- * will still be searched for and detected. This option
- * only affects searching for ISA and VL boards.
- *
- * If ADVANSYS_DEBUG is defined the driver debug level may
- * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port.
- *
- * Examples:
- * 1. Eliminate I/O port scanning:
- * boot: linux advansys=
- * or
- * boot: linux advansys=0x0
- * 2. Limit I/O port scanning to one I/O port:
- * boot: linux advansys=0x110
- * 3. Limit I/O port scanning to four I/O ports:
- * boot: linux advansys=0x110,0x210,0x230,0x330
- * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and
- * set the driver debug level to 2.
- * boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2
- *
- * ints[0] - number of arguments
- * ints[1] - first argument
- * ints[2] - second argument
- * ...
- */
-void __init
-advansys_setup(char *str, int *ints)
-{
- int i;
-
- if (asc_iopflag == ASC_TRUE) {
- printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n");
- return;
- }
-
- asc_iopflag = ASC_TRUE;
-
- if (ints[0] > ASC_NUM_IOPORT_PROBE) {
-#ifdef ADVANSYS_DEBUG
- if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) &&
- (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) {
- asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf;
- } else {
-#endif /* ADVANSYS_DEBUG */
- printk("AdvanSys SCSI: only %d I/O ports accepted\n",
- ASC_NUM_IOPORT_PROBE);
-#ifdef ADVANSYS_DEBUG
- }
-#endif /* ADVANSYS_DEBUG */
- }
-
-#ifdef ADVANSYS_DEBUG
- ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]);
- for (i = 1; i < ints[0]; i++) {
- ASC_DBG2(1, " ints[%d] 0x%x", i, ints[i]);
- }
- ASC_DBG(1, "\n");
-#endif /* ADVANSYS_DEBUG */
-
- for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) {
- asc_ioport[i-1] = ints[i];
- ASC_DBG2(1, "advansys_setup: asc_ioport[%d] 0x%x\n",
- i - 1, asc_ioport[i-1]);
- }
-}
-
-
-/*
* --- Loadable Driver Support
*/
diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
deleted file mode 100644
index 8ee7fb16a725..000000000000
--- a/drivers/scsi/advansys.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
- *
- * Copyright (c) 1995-2000 Advanced System Products, Inc.
- * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
- * All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that redistributions of source
- * code retain the above copyright notice and this comment without
- * modification.
- *
- * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
- * changed its name to ConnectCom Solutions, Inc.
- *
- */
-
-#ifndef _ADVANSYS_H
-#define _ADVANSYS_H
-
-/*
- * struct scsi_host_template function prototypes.
- */
-int advansys_detect(struct scsi_host_template *);
-int advansys_release(struct Scsi_Host *);
-const char *advansys_info(struct Scsi_Host *);
-int advansys_queuecommand(struct scsi_cmnd *, void (* done)(struct scsi_cmnd *));
-int advansys_reset(struct scsi_cmnd *);
-int advansys_biosparam(struct scsi_device *, struct block_device *,
- sector_t, int[]);
-static int advansys_slave_configure(struct scsi_device *);
-
-/* init/main.c setup function */
-void advansys_setup(char *, int *);
-
-#endif /* _ADVANSYS_H */
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 4b4d1233ce8a..85f2394ffc3e 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -240,6 +240,7 @@
#include <linux/io.h>
#include <linux/blkdev.h>
#include <asm/system.h>
+#include <linux/completion.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/wait.h>
@@ -253,7 +254,6 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/list.h>
-#include <asm/semaphore.h>
#include <scsi/scsicam.h>
#include "scsi.h"
@@ -551,7 +551,7 @@ struct aha152x_hostdata {
*/
struct aha152x_scdata {
Scsi_Cmnd *next; /* next sc in queue */
- struct semaphore *sem; /* semaphore to block on */
+ struct completion *done;/* semaphore to block on */
unsigned char cmd_len;
unsigned char cmnd[MAX_COMMAND_SIZE];
unsigned short use_sg;
@@ -608,7 +608,7 @@ struct aha152x_scdata {
#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble)
#define SCNEXT(SCpnt) SCDATA(SCpnt)->next
-#define SCSEM(SCpnt) SCDATA(SCpnt)->sem
+#define SCSEM(SCpnt) SCDATA(SCpnt)->done
#define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset))
@@ -969,7 +969,8 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt)
/*
* Queue a command and setup interrupts for a free bus.
*/
-static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, void (*done)(Scsi_Cmnd *))
+static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
+ int phase, void (*done)(Scsi_Cmnd *))
{
struct Scsi_Host *shpnt = SCpnt->device->host;
unsigned long flags;
@@ -1013,7 +1014,7 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int p
}
SCNEXT(SCpnt) = NULL;
- SCSEM(SCpnt) = sem;
+ SCSEM(SCpnt) = complete;
/* setup scratch area
SCp.ptr : buffer pointer
@@ -1084,9 +1085,9 @@ static void reset_done(Scsi_Cmnd *SCpnt)
DPRINTK(debug_eh, INFO_LEAD "reset_done called\n", CMDINFO(SCpnt));
#endif
if(SCSEM(SCpnt)) {
- up(SCSEM(SCpnt));
+ complete(SCSEM(SCpnt));
} else {
- printk(KERN_ERR "aha152x: reset_done w/o semaphore\n");
+ printk(KERN_ERR "aha152x: reset_done w/o completion\n");
}
}
@@ -1139,21 +1140,6 @@ static int aha152x_abort(Scsi_Cmnd *SCpnt)
return FAILED;
}
-static void timer_expired(unsigned long p)
-{
- Scsi_Cmnd *SCp = (Scsi_Cmnd *)p;
- struct semaphore *sem = SCSEM(SCp);
- struct Scsi_Host *shpnt = SCp->device->host;
- unsigned long flags;
-
- /* remove command from issue queue */
- DO_LOCK(flags);
- remove_SC(&ISSUE_SC, SCp);
- DO_UNLOCK(flags);
-
- up(sem);
-}
-
/*
* Reset a device
*
@@ -1161,14 +1147,14 @@ static void timer_expired(unsigned long p)
static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
{
struct Scsi_Host *shpnt = SCpnt->device->host;
- DECLARE_MUTEX_LOCKED(sem);
- struct timer_list timer;
+ DECLARE_COMPLETION(done);
int ret, issued, disconnected;
unsigned char old_cmd_len = SCpnt->cmd_len;
unsigned short old_use_sg = SCpnt->use_sg;
void *old_buffer = SCpnt->request_buffer;
unsigned old_bufflen = SCpnt->request_bufflen;
unsigned long flags;
+ unsigned long timeleft;
#if defined(AHA152X_DEBUG)
if(HOSTDATA(shpnt)->debug & debug_eh) {
@@ -1192,15 +1178,15 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
SCpnt->request_buffer = NULL;
SCpnt->request_bufflen = 0;
- init_timer(&timer);
- timer.data = (unsigned long) SCpnt;
- timer.expires = jiffies + 100*HZ; /* 10s */
- timer.function = (void (*)(unsigned long)) timer_expired;
+ aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
- aha152x_internal_queue(SCpnt, &sem, resetting, reset_done);
- add_timer(&timer);
- down(&sem);
- del_timer(&timer);
+ timeleft = wait_for_completion_timeout(&done, 100*HZ);
+ if (!timeleft) {
+ /* remove command from issue queue */
+ DO_LOCK(flags);
+ remove_SC(&ISSUE_SC, SCpnt);
+ DO_UNLOCK(flags);
+ }
SCpnt->cmd_len = old_cmd_len;
SCpnt->use_sg = old_use_sg;
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index d7af9c63a04d..e4a4f3a965d9 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -271,20 +271,8 @@ static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
continue;
}
sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
- if (SCtmp->use_sg) {
- /* We used scatter-gather.
- Do the unmapping dance. */
- dma_unmap_sg (&edev->dev,
- (struct scatterlist *) SCtmp->request_buffer,
- SCtmp->use_sg,
- SCtmp->sc_data_direction);
- } else {
- dma_unmap_single (&edev->dev,
- sgptr->buf_dma_addr,
- SCtmp->request_bufflen,
- DMA_BIDIRECTIONAL);
- }
-
+ scsi_dma_unmap(SCtmp);
+
/* Free the sg block */
dma_free_coherent (&edev->dev,
sizeof (struct aha1740_sg),
@@ -349,11 +337,9 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
unchar target = scmd_id(SCpnt);
struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
unsigned long flags;
- void *buff = SCpnt->request_buffer;
- int bufflen = SCpnt->request_bufflen;
dma_addr_t sg_dma;
struct aha1740_sg *sgptr;
- int ecbno;
+ int ecbno, nseg;
DEB(int i);
if(*cmd == REQUEST_SENSE) {
@@ -423,24 +409,23 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
}
sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
sgptr->sg_dma_addr = sg_dma;
-
- if (SCpnt->use_sg) {
- struct scatterlist * sgpnt;
+
+ nseg = scsi_dma_map(SCpnt);
+ BUG_ON(nseg < 0);
+ if (nseg) {
+ struct scatterlist *sg;
struct aha1740_chain * cptr;
- int i, count;
+ int i;
DEB(unsigned char * ptr);
host->ecb[ecbno].sg = 1; /* SCSI Initiator Command
* w/scatter-gather*/
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
cptr = sgptr->sg_chain;
- count = dma_map_sg (&host->edev->dev, sgpnt, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- for(i=0; i < count; i++) {
- cptr[i].datalen = sg_dma_len (sgpnt + i);
- cptr[i].dataptr = sg_dma_address (sgpnt + i);
+ scsi_for_each_sg(SCpnt, sg, nseg, i) {
+ cptr[i].datalen = sg_dma_len (sg);
+ cptr[i].dataptr = sg_dma_address (sg);
}
- host->ecb[ecbno].datalen = count*sizeof(struct aha1740_chain);
+ host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain);
host->ecb[ecbno].dataptr = sg_dma;
#ifdef DEBUG
printk("cptr %x: ",cptr);
@@ -448,11 +433,8 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
for(i=0;i<24;i++) printk("%02x ", ptr[i]);
#endif
} else {
- host->ecb[ecbno].datalen = bufflen;
- sgptr->buf_dma_addr = dma_map_single (&host->edev->dev,
- buff, bufflen,
- DMA_BIDIRECTIONAL);
- host->ecb[ecbno].dataptr = sgptr->buf_dma_addr;
+ host->ecb[ecbno].datalen = 0;
+ host->ecb[ecbno].dataptr = 0;
}
host->ecb[ecbno].lun = SCpnt->device->lun;
host->ecb[ecbno].ses = 1; /* Suppress underrun errors */
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 6054881f21f1..286ab83116f9 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -376,21 +376,10 @@ static __inline void
ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
{
struct scsi_cmnd *cmd;
- int direction;
cmd = scb->io_ctx;
- direction = cmd->sc_data_direction;
ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE);
- if (cmd->use_sg != 0) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(ahd->dev_softc, sg, cmd->use_sg, direction);
- } else if (cmd->request_bufflen != 0) {
- pci_unmap_single(ahd->dev_softc,
- scb->platform_data->buf_busaddr,
- cmd->request_bufflen, direction);
- }
+ scsi_dma_unmap(cmd);
}
/******************************** Macros **************************************/
@@ -1422,6 +1411,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
u_int col_idx;
uint16_t mask;
unsigned long flags;
+ int nseg;
ahd_lock(ahd, &flags);
@@ -1494,18 +1484,17 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
ahd_set_residual(scb, 0);
ahd_set_sense_residual(scb, 0);
scb->sg_count = 0;
- if (cmd->use_sg != 0) {
- void *sg;
- struct scatterlist *cur_seg;
- u_int nseg;
- int dir;
-
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- dir = cmd->sc_data_direction;
- nseg = pci_map_sg(ahd->dev_softc, cur_seg,
- cmd->use_sg, dir);
+
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (nseg > 0) {
+ void *sg = scb->sg_list;
+ struct scatterlist *cur_seg;
+ int i;
+
scb->platform_data->xfer_len = 0;
- for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) {
+
+ scsi_for_each_sg(cmd, cur_seg, nseg, i) {
dma_addr_t addr;
bus_size_t len;
@@ -1513,22 +1502,8 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
len = sg_dma_len(cur_seg);
scb->platform_data->xfer_len += len;
sg = ahd_sg_setup(ahd, scb, sg, addr, len,
- /*last*/nseg == 1);
+ i == (nseg - 1));
}
- } else if (cmd->request_bufflen != 0) {
- void *sg;
- dma_addr_t addr;
- int dir;
-
- sg = scb->sg_list;
- dir = cmd->sc_data_direction;
- addr = pci_map_single(ahd->dev_softc,
- cmd->request_buffer,
- cmd->request_bufflen, dir);
- scb->platform_data->xfer_len = cmd->request_bufflen;
- scb->platform_data->buf_busaddr = addr;
- sg = ahd_sg_setup(ahd, scb, sg, addr,
- cmd->request_bufflen, /*last*/TRUE);
}
LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index ad9761b237dc..853998be1474 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -781,7 +781,7 @@ int ahd_get_transfer_dir(struct scb *scb)
static __inline
void ahd_set_residual(struct scb *scb, u_long resid)
{
- scb->io_ctx->resid = resid;
+ scsi_set_resid(scb->io_ctx, resid);
}
static __inline
@@ -793,7 +793,7 @@ void ahd_set_sense_residual(struct scb *scb, u_long resid)
static __inline
u_long ahd_get_residual(struct scb *scb)
{
- return (scb->io_ctx->resid);
+ return scsi_get_resid(scb->io_ctx);
}
static __inline
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 660f26e23a38..1803ab6fc21c 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -402,18 +402,8 @@ ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
cmd = scb->io_ctx;
ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE);
- if (cmd->use_sg != 0) {
- struct scatterlist *sg;
-
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (cmd->request_bufflen != 0) {
- pci_unmap_single(ahc->dev_softc,
- scb->platform_data->buf_busaddr,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+
+ scsi_dma_unmap(cmd);
}
static __inline int
@@ -1381,6 +1371,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
struct ahc_tmode_tstate *tstate;
uint16_t mask;
struct scb_tailq *untagged_q = NULL;
+ int nseg;
/*
* Schedule us to run later. The only reason we are not
@@ -1472,23 +1463,21 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
ahc_set_residual(scb, 0);
ahc_set_sense_residual(scb, 0);
scb->sg_count = 0;
- if (cmd->use_sg != 0) {
+
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (nseg > 0) {
struct ahc_dma_seg *sg;
struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
- int nseg;
+ int i;
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg,
- cmd->sc_data_direction);
- end_seg = cur_seg + nseg;
/* Copy the segments into the SG list. */
sg = scb->sg_list;
/*
* The sg_count may be larger than nseg if
* a transfer crosses a 32bit page.
- */
- while (cur_seg < end_seg) {
+ */
+ scsi_for_each_sg(cmd, cur_seg, nseg, i) {
dma_addr_t addr;
bus_size_t len;
int consumed;
@@ -1499,7 +1488,6 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
sg, addr, len);
sg += consumed;
scb->sg_count += consumed;
- cur_seg++;
}
sg--;
sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
@@ -1516,33 +1504,6 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
*/
scb->hscb->dataptr = scb->sg_list->addr;
scb->hscb->datacnt = scb->sg_list->len;
- } else if (cmd->request_bufflen != 0) {
- struct ahc_dma_seg *sg;
- dma_addr_t addr;
-
- sg = scb->sg_list;
- addr = pci_map_single(ahc->dev_softc,
- cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- scb->platform_data->buf_busaddr = addr;
- scb->sg_count = ahc_linux_map_seg(ahc, scb,
- sg, addr,
- cmd->request_bufflen);
- sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
-
- /*
- * Reset the sg list pointer.
- */
- scb->hscb->sgptr =
- ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
-
- /*
- * Copy the first SG into the "current"
- * data pointer area.
- */
- scb->hscb->dataptr = sg->addr;
- scb->hscb->datacnt = sg->len;
} else {
scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL);
scb->hscb->dataptr = 0;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index 8fee7edc6eb3..b48dab447bde 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -751,7 +751,7 @@ int ahc_get_transfer_dir(struct scb *scb)
static __inline
void ahc_set_residual(struct scb *scb, u_long resid)
{
- scb->io_ctx->resid = resid;
+ scsi_set_resid(scb->io_ctx, resid);
}
static __inline
@@ -763,7 +763,7 @@ void ahc_set_sense_residual(struct scb *scb, u_long resid)
static __inline
u_long ahc_get_residual(struct scb *scb)
{
- return (scb->io_ctx->resid);
+ return scsi_get_resid(scb->io_ctx);
}
static __inline
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index a988d5abf702..4998bb850c49 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -2690,17 +2690,8 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
struct aic7xxx_scb *scbp;
unsigned char queue_depth;
- if (cmd->use_sg > 1)
- {
- struct scatterlist *sg;
+ scsi_dma_unmap(cmd);
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(p->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
- }
- else if (cmd->request_bufflen)
- pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
- cmd->request_bufflen,
- cmd->sc_data_direction);
if (scb->flags & SCB_SENSE)
{
pci_unmap_single(p->pdev,
@@ -3869,7 +3860,7 @@ aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
* the mid layer didn't check residual data counts to see if the
* command needs retried.
*/
- cmd->resid = scb->sg_length - actual;
+ scsi_set_resid(cmd, scb->sg_length - actual);
aic7xxx_status(cmd) = hscb->target_status;
}
}
@@ -6581,7 +6572,7 @@ aic7xxx_slave_alloc(struct scsi_device *SDptr)
struct aic7xxx_host *p = (struct aic7xxx_host *)SDptr->host->hostdata;
struct aic_dev_data *aic_dev;
- aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC | GFP_KERNEL);
+ aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_KERNEL);
if(!aic_dev)
return 1;
/*
@@ -10137,6 +10128,7 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
struct scsi_device *sdptr = cmd->device;
unsigned char tindex = TARGET_INDEX(cmd);
struct request *req = cmd->request;
+ int use_sg;
mask = (0x01 << tindex);
hscb = scb->hscb;
@@ -10209,8 +10201,10 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
- if (cmd->use_sg)
- {
+ use_sg = scsi_dma_map(cmd);
+ BUG_ON(use_sg < 0);
+
+ if (use_sg) {
struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */
/*
@@ -10219,11 +10213,11 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
* differences and the kernel SG list uses virtual addresses where
* we need physical addresses.
*/
- int i, use_sg;
+ int i;
- sg = (struct scatterlist *)cmd->request_buffer;
scb->sg_length = 0;
- use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
+
+
/*
* Copy the segments into the SG array. NOTE!!! - We used to
* have the first entry both in the data_pointer area and the first
@@ -10231,10 +10225,9 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
* entry in both places, but now we download the address of
* scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
*/
- for (i = 0; i < use_sg; i++)
- {
- unsigned int len = sg_dma_len(sg+i);
- scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
+ scsi_for_each_sg(cmd, sg, use_sg, i) {
+ unsigned int len = sg_dma_len(sg);
+ scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg));
scb->sg_list[i].length = cpu_to_le32(len);
scb->sg_length += len;
}
@@ -10244,33 +10237,13 @@ static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
scb->sg_count = i;
hscb->SG_segment_count = i;
hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
- }
- else
- {
- if (cmd->request_bufflen)
- {
- unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- aic7xxx_mapping(cmd) = address;
- scb->sg_list[0].address = cpu_to_le32(address);
- scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
- scb->sg_count = 1;
- scb->sg_length = cmd->request_bufflen;
- hscb->SG_segment_count = 1;
- hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
- hscb->data_count = scb->sg_list[0].length;
- hscb->data_pointer = scb->sg_list[0].address;
- }
- else
- {
+ } else {
scb->sg_count = 0;
scb->sg_length = 0;
hscb->SG_segment_count = 0;
hscb->SG_list_pointer = 0;
hscb->data_count = 0;
hscb->data_pointer = 0;
- }
}
}
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index c520e5b41fb5..3dce618bf414 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -126,7 +126,7 @@ static inline int asd_init_sata(struct domain_device *dev)
if (w76 & 0x100) /* NCQ? */
qdepth = (w75 & 0x1F) + 1;
asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
- (1<<qdepth)-1);
+ (1ULL<<qdepth)-1);
asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
}
if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 27852b43b904..ab00aecc5466 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -81,6 +81,9 @@ static struct scsi_host_template aic94xx_sht = {
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
+ .slave_alloc = sas_slave_alloc,
+ .target_destroy = sas_target_destroy,
+ .ioctl = sas_ioctl,
};
static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
@@ -223,13 +226,8 @@ static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
{
int err, i;
- err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID,
- &asd_ha->revision_id);
- if (err) {
- asd_printk("couldn't read REVISION ID register of %s\n",
- pci_name(asd_ha->pcidev));
- goto Err;
- }
+ asd_ha->revision_id = asd_ha->pcidev->revision;
+
err = -ENODEV;
if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
asd_printk("%s is revision %s (%X), which is not supported\n",
@@ -467,7 +465,7 @@ static int asd_create_global_caches(void)
sizeof(struct asd_dma_tok),
0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!asd_dma_token_cache) {
asd_printk("couldn't create dma token cache\n");
return -ENOMEM;
@@ -479,7 +477,7 @@ static int asd_create_global_caches(void)
sizeof(struct asd_ascb),
0,
SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!asd_ascb_cache) {
asd_printk("couldn't create ascb cache\n");
goto Err;
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index e2ad5bed9403..d5d8caba3560 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -74,8 +74,13 @@ static inline int asd_map_scatterlist(struct sas_task *task,
return 0;
}
- num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ /* STP tasks come from libata which has already mapped
+ * the SG list */
+ if (sas_protocol_ata(task->task_proto))
+ num_sg = task->num_scatter;
+ else
+ num_sg = pci_map_sg(asd_ha->pcidev, task->scatter,
+ task->num_scatter, task->data_dir);
if (num_sg == 0)
return -ENOMEM;
@@ -120,8 +125,9 @@ static inline int asd_map_scatterlist(struct sas_task *task,
return 0;
err_unmap:
- pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ if (sas_protocol_ata(task->task_proto))
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
return res;
}
@@ -142,8 +148,9 @@ static inline void asd_unmap_scatterlist(struct asd_ascb *ascb)
}
asd_free_coherent(asd_ha, ascb->sg_arr);
- pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
- task->data_dir);
+ if (task->task_proto != SAS_PROTOCOL_STP)
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
}
/* ---------- Task complete tasklet ---------- */
@@ -391,7 +398,6 @@ static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
scb->ata_task.fis = task->ata_task.fis;
- scb->ata_task.fis.fis_type = 0x27;
if (likely(!task->ata_task.device_control_reg_update))
scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
deleted file mode 100644
index d5d3c4d5a253..000000000000
--- a/drivers/scsi/amiga7xx.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
- * Amiga MacroSystemUS WarpEngine SCSI controller.
- * Amiga Technologies A4000T SCSI controller.
- * Amiga Technologies/DKB A4091 SCSI controller.
- *
- * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
- * plus modifications of the 53c7xx.c driver to support the Amiga.
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-#include <linux/zorro.h>
-#include <linux/stat.h>
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/amigaints.h>
-#include <asm/amigahw.h>
-#include <asm/dma.h>
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "53c7xx.h"
-#include "amiga7xx.h"
-
-
-static int amiga7xx_register_one(struct scsi_host_template *tpnt,
- unsigned long address)
-{
- long long options;
- int clock;
-
- if (!request_mem_region(address, 0x1000, "ncr53c710"))
- return 0;
-
- address = (unsigned long)z_ioremap(address, 0x1000);
- options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 | OPTION_INTFLY |
- OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS |
- OPTION_DISCONNECT;
- clock = 50000000; /* 50 MHz SCSI Clock */
- ncr53c7xx_init(tpnt, 0, 710, address, 0, IRQ_AMIGA_PORTS, DMA_NONE,
- options, clock);
- return 1;
-}
-
-
-#ifdef CONFIG_ZORRO
-
-static struct {
- zorro_id id;
- unsigned long offset;
- int absolute; /* offset is absolute address */
-} amiga7xx_table[] = {
- { .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, .offset = 0xf40000,
- .absolute = 1 },
- { .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, .offset = 0x40000 },
- { .id = ZORRO_PROD_CBM_A4091_1, .offset = 0x800000 },
- { .id = ZORRO_PROD_CBM_A4091_2, .offset = 0x800000 },
- { .id = ZORRO_PROD_GVP_GFORCE_040_060, .offset = 0x40000 },
- { 0 }
-};
-
-static int __init amiga7xx_zorro_detect(struct scsi_host_template *tpnt)
-{
- int num = 0, i;
- struct zorro_dev *z = NULL;
- unsigned long address;
-
- while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
- for (i = 0; amiga7xx_table[i].id; i++)
- if (z->id == amiga7xx_table[i].id)
- break;
- if (!amiga7xx_table[i].id)
- continue;
- if (amiga7xx_table[i].absolute)
- address = amiga7xx_table[i].offset;
- else
- address = z->resource.start + amiga7xx_table[i].offset;
- num += amiga7xx_register_one(tpnt, address);
- }
- return num;
-}
-
-#endif /* CONFIG_ZORRO */
-
-
-int __init amiga7xx_detect(struct scsi_host_template *tpnt)
-{
- static unsigned char called = 0;
- int num = 0;
-
- if (called || !MACH_IS_AMIGA)
- return 0;
-
- tpnt->proc_name = "Amiga7xx";
-
- if (AMIGAHW_PRESENT(A4000_SCSI))
- num += amiga7xx_register_one(tpnt, 0xdd0040);
-
-#ifdef CONFIG_ZORRO
- num += amiga7xx_zorro_detect(tpnt);
-#endif
-
- called = 1;
- return num;
-}
-
-static int amiga7xx_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "Amiga NCR53c710 SCSI",
- .detect = amiga7xx_detect,
- .release = amiga7xx_release,
- .queuecommand = NCR53c7xx_queue_command,
- .abort = NCR53c7xx_abort,
- .reset = NCR53c7xx_reset,
- .can_queue = 24,
- .this_id = 7,
- .sg_tablesize = 63,
- .cmd_per_lun = 3,
- .use_clustering = DISABLE_CLUSTERING
-};
-
-
-#include "scsi_module.c"
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
deleted file mode 100644
index 7cd63a996886..000000000000
--- a/drivers/scsi/amiga7xx.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef AMIGA7XX_H
-
-#include <linux/types.h>
-
-int amiga7xx_detect(struct scsi_host_template *);
-const char *NCR53c7x0_info(void);
-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (struct Scsi_Host *);
-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id);
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 3
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 24
-#endif
-
-#include <scsi/scsicam.h>
-
-#endif /* AMIGA7XX_H */
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index aff96db9ccf6..f0b8bf4534f0 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -48,9 +48,10 @@ struct class_device_attribute;
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 288
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.14"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
+#define ARCMSR_MAX_XFER_SECTORS_B 4096
#define ARCMSR_MAX_TARGETID 17
#define ARCMSR_MAX_TARGETLUN 8
#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
@@ -469,4 +470,3 @@ extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
extern struct class_device_attribute *arcmsr_host_attrs[];
extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
-
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 03bfed61bffc..06c0dce3b839 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -59,8 +59,9 @@
struct class_device_attribute *arcmsr_host_attrs[];
static ssize_t
-arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+arcmsr_sysfs_iop_message_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
@@ -105,8 +106,9 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
}
static ssize_t
-arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+arcmsr_sysfs_iop_message_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
@@ -152,8 +154,9 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
}
static ssize_t
-arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
@@ -188,7 +191,6 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
.attr = {
.name = "mu_read",
.mode = S_IRUSR ,
- .owner = THIS_MODULE,
},
.size = 1032,
.read = arcmsr_sysfs_iop_message_read,
@@ -198,7 +200,6 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
.attr = {
.name = "mu_write",
.mode = S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 1032,
.write = arcmsr_sysfs_iop_message_write,
@@ -208,7 +209,6 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
.attr = {
.name = "mu_clear",
.mode = S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 1,
.write = arcmsr_sysfs_iop_message_clear,
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 8b46158cc045..0ddfc21e9f7d 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -57,6 +57,7 @@
#include <linux/dma-mapping.h>
#include <linux/timer.h>
#include <linux/pci.h>
+#include <linux/aer.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -71,7 +72,7 @@
#include "arcmsr.h"
MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ARCMSR_DRIVER_VERSION);
@@ -93,7 +94,9 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
-
+static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state);
+static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
@@ -104,7 +107,8 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_de
static struct scsi_host_template arcmsr_scsi_host_template = {
.module = THIS_MODULE,
- .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION,
+ .name = "ARCMSR ARECA SATA/SAS RAID HOST Adapter"
+ ARCMSR_DRIVER_VERSION,
.info = arcmsr_info,
.queuecommand = arcmsr_queue_command,
.eh_abort_handler = arcmsr_abort,
@@ -119,6 +123,10 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = arcmsr_host_attrs,
};
+static struct pci_error_handlers arcmsr_pci_error_handlers = {
+ .error_detected = arcmsr_pci_error_detected,
+ .slot_reset = arcmsr_pci_slot_reset,
+};
static struct pci_device_id arcmsr_device_id_table[] = {
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
@@ -144,7 +152,8 @@ static struct pci_driver arcmsr_pci_driver = {
.id_table = arcmsr_device_id_table,
.probe = arcmsr_probe,
.remove = arcmsr_remove,
- .shutdown = arcmsr_shutdown
+ .shutdown = arcmsr_shutdown,
+ .err_handler = &arcmsr_pci_error_handlers,
};
static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
@@ -328,6 +337,8 @@ static int arcmsr_probe(struct pci_dev *pdev,
arcmsr_iop_init(acb);
pci_set_drvdata(pdev, host);
+ if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
+ host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B;
error = scsi_add_host(host, &pdev->dev);
if (error)
@@ -338,6 +349,7 @@ static int arcmsr_probe(struct pci_dev *pdev,
goto out_free_sysfs;
scsi_scan_host(host);
+ pci_enable_pcie_error_reporting(pdev);
return 0;
out_free_sysfs:
out_free_irq:
@@ -369,19 +381,9 @@ static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
{
- struct AdapterControlBlock *acb = ccb->acb;
struct scsi_cmnd *pcmd = ccb->pcmd;
- if (pcmd->use_sg != 0) {
- struct scatterlist *sl;
-
- sl = (struct scatterlist *)pcmd->request_buffer;
- pci_unmap_sg(acb->pdev, sl, pcmd->use_sg, pcmd->sc_data_direction);
- }
- else if (pcmd->request_bufflen != 0)
- pci_unmap_single(acb->pdev,
- pcmd->SCp.dma_handle,
- pcmd->request_bufflen, pcmd->sc_data_direction);
+ scsi_dma_unmap(pcmd);
}
static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
@@ -498,7 +500,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg=acb->pmu;
+ struct MessageUnit __iomem *reg = acb->pmu;
writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
if (arcmsr_wait_msgint_ready(acb))
@@ -551,6 +553,7 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
int8_t *psge = (int8_t *)&arcmsr_cdb->u;
uint32_t address_lo, address_hi;
int arccdbsize = 0x30;
+ int nseg;
ccb->pcmd = pcmd;
memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
@@ -561,20 +564,20 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
- if (pcmd->use_sg) {
- int length, sgcount, i, cdb_sgcount = 0;
- struct scatterlist *sl;
-
- /* Get Scatter Gather List from scsiport. */
- sl = (struct scatterlist *) pcmd->request_buffer;
- sgcount = pci_map_sg(acb->pdev, sl, pcmd->use_sg,
- pcmd->sc_data_direction);
+
+ nseg = scsi_dma_map(pcmd);
+ BUG_ON(nseg < 0);
+
+ if (nseg) {
+ int length, i, cdb_sgcount = 0;
+ struct scatterlist *sg;
+
/* map stor port SG list to our iop SG List. */
- for (i = 0; i < sgcount; i++) {
+ scsi_for_each_sg(pcmd, sg, nseg, i) {
/* Get the physical address of the current data pointer */
- length = cpu_to_le32(sg_dma_len(sl));
- address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl)));
- address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl)));
+ length = cpu_to_le32(sg_dma_len(sg));
+ address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg)));
+ address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg)));
if (address_hi == 0) {
struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
@@ -591,32 +594,12 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
psge += sizeof (struct SG64ENTRY);
arccdbsize += sizeof (struct SG64ENTRY);
}
- sl++;
cdb_sgcount++;
}
arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
- arcmsr_cdb->DataLength = pcmd->request_bufflen;
+ arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
if ( arccdbsize > 256)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
- } else if (pcmd->request_bufflen) {
- dma_addr_t dma_addr;
- dma_addr = pci_map_single(acb->pdev, pcmd->request_buffer,
- pcmd->request_bufflen, pcmd->sc_data_direction);
- pcmd->SCp.dma_handle = dma_addr;
- address_lo = cpu_to_le32(dma_addr_lo32(dma_addr));
- address_hi = cpu_to_le32(dma_addr_hi32(dma_addr));
- if (address_hi == 0) {
- struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
- pdma_sg->address = address_lo;
- pdma_sg->length = pcmd->request_bufflen;
- } else {
- struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
- pdma_sg->addresshigh = address_hi;
- pdma_sg->address = address_lo;
- pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR;
- }
- arcmsr_cdb->sgcount = 1;
- arcmsr_cdb->DataLength = pcmd->request_bufflen;
}
if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
@@ -747,7 +730,7 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
int id, lun;
/*
****************************************************************
- ** areca cdb command done
+ ** areca cdb command done
****************************************************************
*/
while (1) {
@@ -758,20 +741,20 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
(flag_ccb << 5));
if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd=ccb->pcmd;
+ struct scsi_cmnd *abortcmd = ccb->pcmd;
if (abortcmd) {
abortcmd->result |= DID_ABORT >> 16;
arcmsr_ccb_complete(ccb, 1);
printk(KERN_NOTICE
- "arcmsr%d: ccb='0x%p' isr got aborted command \n"
+ "arcmsr%d: ccb ='0x%p' isr got aborted command \n"
, acb->host->host_no, ccb);
}
continue;
}
printk(KERN_NOTICE
- "arcmsr%d: isr get an illegal ccb command done acb='0x%p'"
- "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x"
- " ccboutstandingcount=%d \n"
+ "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'"
+ "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
+ " ccboutstandingcount = %d \n"
, acb->host->host_no
, acb
, ccb
@@ -791,7 +774,7 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
switch(ccb->arcmsr_cdb.DeviceStatus) {
case ARCMSR_DEV_SELECT_TIMEOUT: {
acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_TIME_OUT << 16;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
arcmsr_ccb_complete(ccb, 1);
}
break;
@@ -810,8 +793,8 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
break;
default:
printk(KERN_NOTICE
- "arcmsr%d: scsi id=%d lun=%d"
- " isr get command error done,"
+ "arcmsr%d: scsi id = %d lun = %d"
+ " isr get command error done, "
"but got unknown DeviceStatus = 0x%x \n"
, acb->host->host_no
, id
@@ -848,24 +831,21 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
struct CMD_MESSAGE_FIELD *pcmdmessagefld;
int retvalue = 0, transfer_len = 0;
char *buffer;
+ struct scatterlist *sg;
uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
(uint32_t ) cmd->cmnd[6] << 16 |
(uint32_t ) cmd->cmnd[7] << 8 |
(uint32_t ) cmd->cmnd[8];
/* 4 bytes: Areca io control code */
- if (cmd->use_sg) {
- struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- if (cmd->use_sg > 1) {
- retvalue = ARCMSR_MESSAGE_FAIL;
- goto message_out;
- }
- transfer_len += sg->length;
- } else {
- buffer = cmd->request_buffer;
- transfer_len = cmd->request_bufflen;
+ sg = scsi_sglist(cmd);
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ if (scsi_sg_count(cmd) > 1) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
}
+ transfer_len += sg->length;
+
if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
retvalue = ARCMSR_MESSAGE_FAIL;
goto message_out;
@@ -1057,12 +1037,9 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_
retvalue = ARCMSR_MESSAGE_FAIL;
}
message_out:
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ sg = scsi_sglist(cmd);
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- }
return retvalue;
}
@@ -1085,6 +1062,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
case INQUIRY: {
unsigned char inqdata[36];
char *buffer;
+ struct scatterlist *sg;
if (cmd->device->lun) {
cmd->result = (DID_TIME_OUT << 16);
@@ -1096,7 +1074,7 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
inqdata[1] = 0;
/* rem media bit & Dev Type Modifier */
inqdata[2] = 0;
- /* ISO,ECMA,& ANSI versions */
+ /* ISO, ECMA, & ANSI versions */
inqdata[4] = 31;
/* length of additional data */
strncpy(&inqdata[8], "Areca ", 8);
@@ -1104,21 +1082,14 @@ static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
strncpy(&inqdata[16], "RAID controller ", 16);
/* Product Identification */
strncpy(&inqdata[32], "R001", 4); /* Product Revision */
- if (cmd->use_sg) {
- struct scatterlist *sg;
- sg = (struct scatterlist *) cmd->request_buffer;
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- } else {
- buffer = cmd->request_buffer;
- }
+ sg = scsi_sglist(cmd);
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+
memcpy(buffer, inqdata, sizeof(inqdata));
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ sg = scsi_sglist(cmd);
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- sg = (struct scatterlist *) cmd->request_buffer;
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- }
cmd->scsi_done(cmd);
}
break;
@@ -1153,7 +1124,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
, acb->host->host_no);
return SCSI_MLQUEUE_HOST_BUSY;
}
- if(target == 16) {
+ if (target == 16) {
/* virtual device for iop message transfer */
arcmsr_handle_virtual_command(acb, cmd);
return 0;
@@ -1166,7 +1137,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
printk(KERN_NOTICE
"arcmsr%d: block 'read/write'"
"command with gone raid volume"
- " Cmd=%2x, TargetId=%d, Lun=%d \n"
+ " Cmd = %2x, TargetId = %d, Lun = %d \n"
, acb->host->host_no
, cmd->cmnd[0]
, target, lun);
@@ -1257,7 +1228,7 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
(ccb == poll_ccb)) {
printk(KERN_NOTICE
- "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'"
+ "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
" poll command abort successfully \n"
, acb->host->host_no
, ccb->pcmd->device->id
@@ -1270,8 +1241,8 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
}
printk(KERN_NOTICE
"arcmsr%d: polling get an illegal ccb"
- " command done ccb='0x%p'"
- "ccboutstandingcount=%d \n"
+ " command done ccb ='0x%p'"
+ "ccboutstandingcount = %d \n"
, acb->host->host_no
, ccb
, atomic_read(&acb->ccboutstandingcount));
@@ -1288,7 +1259,7 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
switch(ccb->arcmsr_cdb.DeviceStatus) {
case ARCMSR_DEV_SELECT_TIMEOUT: {
acb->devstate[id][lun] = ARECA_RAID_GONE;
- ccb->pcmd->result = DID_TIME_OUT << 16;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
arcmsr_ccb_complete(ccb, 1);
}
break;
@@ -1307,7 +1278,7 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
break;
default:
printk(KERN_NOTICE
- "arcmsr%d: scsi id=%d lun=%d"
+ "arcmsr%d: scsi id = %d lun = %d"
" polling and getting command error done"
"but got unknown DeviceStatus = 0x%x \n"
, acb->host->host_no
@@ -1322,6 +1293,94 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
}
}
}
+static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb)
+{
+ int i = 0, found = 0;
+ int id, lun;
+ uint32_t flag_ccb, outbound_intstatus;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ /*clear and abort all outbound posted Q*/
+
+ while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
+(i++ < 256)){
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
+(flag_ccb << 5));
+ if (ccb){
+ if ((ccb->acb != acb)||(ccb->startdone != \
+ARCMSR_CCB_START)){
+ printk(KERN_NOTICE "arcmsr%d: polling get \
+an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n",
+ acb->host->host_no, ccb,
+ atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id = %d \
+ lun = %d""polling and \
+ getting command error \
+ done""but got unknown \
+ DeviceStatus = 0x%x \n",
+ acb->host->host_no, id,
+ lun, ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ found = 1;
+ }
+ }
+ if (found){
+ outbound_intstatus = readl(&reg->outbound_intstatus) & \
+ acb->outbound_int_enable;
+ writel(outbound_intstatus, &reg->outbound_intstatus);
+ /*clear interrupt*/
+ }
+ return;
+}
+
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
@@ -1355,7 +1414,6 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb)
static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
struct CommandControlBlock *ccb;
uint32_t intmask_org;
int i = 0;
@@ -1368,21 +1426,17 @@ static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
/* disable all outbound interrupt */
intmask_org = arcmsr_disable_outbound_ints(acb);
/* clear all outbound posted Q */
- for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
- readl(&reg->outbound_queueport);
+ arcmsr_done4_abort_postqueue(acb);
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
ccb = acb->pccb_pool[i];
- if ((ccb->startdone == ARCMSR_CCB_START) ||
- (ccb->startdone == ARCMSR_CCB_ABORTED)) {
+ if (ccb->startdone == ARCMSR_CCB_START) {
ccb->startdone = ARCMSR_CCB_ABORTED;
- ccb->pcmd->result = DID_ABORT << 16;
- arcmsr_ccb_complete(ccb, 1);
}
}
/* enable all outbound interrupt */
arcmsr_enable_outbound_ints(acb, intmask_org);
}
- atomic_set(&acb->ccboutstandingcount, 0);
+
}
static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
@@ -1428,10 +1482,9 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
int i = 0;
printk(KERN_NOTICE
- "arcmsr%d: abort device command of scsi id=%d lun=%d \n",
+ "arcmsr%d: abort device command of scsi id = %d lun = %d \n",
acb->host->host_no, cmd->device->id, cmd->device->lun);
acb->num_aborts++;
-
/*
************************************************
** the all interrupt service routine is locked
@@ -1486,10 +1539,306 @@ static const char *arcmsr_info(struct Scsi_Host *host)
type = "X-TYPE";
break;
}
- sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
+ sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
type, raid6 ? "( RAID6 capable)" : "",
ARCMSR_DRIVER_VERSION);
return buf;
}
+static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host;
+ struct AdapterControlBlock *acb;
+ uint8_t bus, dev_fun;
+ int error;
+
+ error = pci_enable_device(pdev);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+ pci_set_master(pdev);
+
+ host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \
+(struct AdapterControlBlock));
+ if (!host)
+ return PCI_ERS_RESULT_DISCONNECT;
+ acb = (struct AdapterControlBlock *)host->hostdata;
+ memset(acb, 0, sizeof (struct AdapterControlBlock));
+
+ error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (error) {
+ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (error) {
+ printk(KERN_WARNING
+ "scsi%d: No suitable DMA mask available\n",
+ host->host_no);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ }
+ bus = pdev->bus->number;
+ dev_fun = pdev->devfn;
+ acb = (struct AdapterControlBlock *) host->hostdata;
+ memset(acb, 0, sizeof(struct AdapterControlBlock));
+ acb->pdev = pdev;
+ acb->host = host;
+ host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+ host->max_lun = ARCMSR_MAX_TARGETLUN;
+ host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
+ host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
+ host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
+ host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
+ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
+ host->this_id = ARCMSR_SCSI_INITIATOR_ID;
+ host->unique_id = (bus << 8) | dev_fun;
+ host->irq = pdev->irq;
+ error = pci_request_regions(pdev, "arcmsr");
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ acb->pmu = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!acb->pmu) {
+ printk(KERN_NOTICE "arcmsr%d: memory"
+ " mapping region fail \n", acb->host->host_no);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_RQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
+ INIT_LIST_HEAD(&acb->ccb_free_list);
+
+ error = arcmsr_alloc_ccb_pool(acb);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ error = request_irq(pdev->irq, arcmsr_do_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ arcmsr_iop_init(acb);
+ if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
+ host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B;
+
+ pci_set_drvdata(pdev, host);
+
+ error = scsi_add_host(host, &pdev->dev);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ error = arcmsr_alloc_sysfs_attr(acb);
+ if (error)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ scsi_scan_host(host);
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ /*clear and abort all outbound posted Q*/
+ int i = 0, found = 0;
+ int id, lun;
+ uint32_t flag_ccb, outbound_intstatus;
+
+ while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
+ (i++ < 256)){
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset
+ + (flag_ccb << 5));
+ if (ccb){
+ if ((ccb->acb != acb)||(ccb->startdone !=
+ ARCMSR_CCB_START)){
+ printk(KERN_NOTICE "arcmsr%d: polling \
+ get an illegal ccb"" command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n",
+ acb->host->host_no, ccb,
+ atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] ==
+ ARECA_RAID_GONE)
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi \
+ id = %d lun = %d"
+ " polling and \
+ getting command \
+ error done"
+ "but got unknown \
+ DeviceStatus = 0x%x \n"
+ , acb->host->host_no,
+ id, lun,
+ ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ found = 1;
+ }
+ }
+ if (found){
+ outbound_intstatus = readl(&reg->outbound_intstatus) &
+ acb->outbound_int_enable;
+ writel(outbound_intstatus, &reg->outbound_intstatus);
+ /*clear interrupt*/
+ }
+ return;
+}
+
+
+static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ /*clear and abort all outbound posted Q*/
+ int i = 0, found = 0;
+ int id, lun;
+ uint32_t flag_ccb, outbound_intstatus;
+
+ while (((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) &&
+ (i++ < 256)){
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
+ (flag_ccb << 5));
+ if (ccb){
+ if ((ccb->acb != acb)||(ccb->startdone !=
+ ARCMSR_CCB_START)){
+ printk(KERN_NOTICE
+ "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n",
+ acb->host->host_no, ccb,
+ atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_ABORTED:
+
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] =
+ ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+
+ default:
+ printk(KERN_NOTICE "arcmsr%d: \
+ scsi id = %d lun = %d"
+ " polling and \
+ getting command error done"
+ "but got unknown \
+ DeviceStatus = 0x%x \n"
+ , acb->host->host_no,
+ id, lun, ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] =
+ ARECA_RAID_GONE;
+ ccb->pcmd->result =
+ DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ found = 1;
+ }
+ }
+ if (found){
+ outbound_intstatus = readl(&reg->outbound_intstatus) &
+ acb->outbound_int_enable;
+ writel(outbound_intstatus, &reg->outbound_intstatus);
+ /*clear interrupt*/
+ }
+ return;
+}
+
+static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ switch (state) {
+ case pci_channel_io_frozen:
+ arcmsr_pci_ers_need_reset_forepart(pdev);
+ return PCI_ERS_RESULT_NEED_RESET;
+ case pci_channel_io_perm_failure:
+ arcmsr_pci_ers_disconnect_forepart(pdev);
+ return PCI_ERS_RESULT_DISCONNECT;
+ break;
+ default:
+ return PCI_ERS_RESULT_NEED_RESET;
+ }
+}
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index cf9a21cea6d9..49d838e90a24 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -24,7 +24,7 @@
#define CUMANASCSI_PUBLIC_RELEASE 1
-#define NCR5380_implementation_fields int port, ctrl
+#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
#define NCR5380_local_declare() struct Scsi_Host *_instance
#define NCR5380_setup(instance) _instance = instance
#define NCR5380_read(reg) cumanascsi_read(_instance, reg)
@@ -33,6 +33,11 @@
#define NCR5380_queue_command cumanascsi_queue_command
#define NCR5380_proc_info cumanascsi_proc_info
+#define NCR5380_implementation_fields \
+ unsigned ctrl; \
+ void __iomem *base; \
+ void __iomem *dma
+
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
@@ -47,192 +52,162 @@ const char *cumanascsi_info(struct Scsi_Host *spnt)
return "";
}
-#ifdef NOT_EFFICIENT
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
-#define STAT(p) inb((p)+1)
-#define IN(p) inb((p))
-#define OUT(v,p) outb((v), (p))
-#else
-#define CTRL(p,v) (p[-2308] = (*ctrl = (v)))
-#define STAT(p) (p[4])
-#define IN(p) (*(p))
-#define IN2(p) ((unsigned short)(*(volatile unsigned long *)(p)))
-#define OUT(v,p) (*(p) = (v))
-#define OUT2(v,p) (*((volatile unsigned long *)(p)) = (v))
-#endif
-#define L(v) (((v)<<16)|((v) & 0x0000ffff))
-#define H(v) (((v)>>16)|((v) & 0xffff0000))
+#define CTRL 0x16fc
+#define STAT 0x2004
+#define L(v) (((v)<<16)|((v) & 0x0000ffff))
+#define H(v) (((v)>>16)|((v) & 0xffff0000))
static inline int
-NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len)
{
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
- int oldctrl = *ctrl;
unsigned long *laddr;
-#ifdef NOT_EFFICIENT
- int iobase = instance->io_port;
- int dma_io = iobase & ~(0x3C0000>>2);
-#else
- volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
- volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+ void __iomem *dma = priv(host)->dma + 0x2000;
if(!len) return 0;
- CTRL(iobase, 0x02);
+ writeb(0x02, priv(host)->base + CTRL);
laddr = (unsigned long *)addr;
while(len >= 32)
{
- int status;
+ unsigned int status;
unsigned long v;
- status = STAT(iobase);
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(!(status & 0x40))
continue;
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
- v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+ v=*laddr++; writew(L(v), dma); writew(H(v), dma);
len -= 32;
if(len == 0)
break;
}
addr = (unsigned char *)laddr;
- CTRL(iobase, 0x12);
+ writeb(0x12, priv(host)->base + CTRL);
+
while(len > 0)
{
- int status;
- status = STAT(iobase);
+ unsigned int status;
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- OUT(*addr++, dma_io);
+ writeb(*addr++, dma);
if(--len == 0)
break;
}
- status = STAT(iobase);
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- OUT(*addr++, dma_io);
+ writeb(*addr++, dma);
if(--len == 0)
break;
}
}
end:
- CTRL(iobase, oldctrl|0x40);
+ writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
return len;
}
static inline int
-NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len)
{
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
- int oldctrl = *ctrl;
unsigned long *laddr;
-#ifdef NOT_EFFICIENT
- int iobase = instance->io_port;
- int dma_io = iobase & ~(0x3C0000>>2);
-#else
- volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
- volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+ void __iomem *dma = priv(host)->dma + 0x2000;
if(!len) return 0;
- CTRL(iobase, 0x00);
+ writeb(0x00, priv(host)->base + CTRL);
laddr = (unsigned long *)addr;
while(len >= 32)
{
- int status;
- status = STAT(iobase);
+ unsigned int status;
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(!(status & 0x40))
continue;
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
- *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
+ *laddr++ = readw(dma) | (readw(dma) << 16);
len -= 32;
if(len == 0)
break;
}
addr = (unsigned char *)laddr;
- CTRL(iobase, 0x10);
+ writeb(0x10, priv(host)->base + CTRL);
+
while(len > 0)
{
- int status;
- status = STAT(iobase);
+ unsigned int status;
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- *addr++ = IN(dma_io);
+ *addr++ = readb(dma);
if(--len == 0)
break;
}
- status = STAT(iobase);
+ status = readb(priv(host)->base + STAT);
if(status & 0x80)
goto end;
if(status & 0x40)
{
- *addr++ = IN(dma_io);
+ *addr++ = readb(dma);
if(--len == 0)
break;
}
}
end:
- CTRL(iobase, oldctrl|0x40);
+ writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
return len;
}
-#undef STAT
-#undef CTRL
-#undef IN
-#undef OUT
+static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
+{
+ void __iomem *base = priv(host)->base;
+ unsigned char val;
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
+ writeb(0, base + CTRL);
-static char cumanascsi_read(struct Scsi_Host *instance, int reg)
-{
- unsigned int iobase = instance->io_port;
- int i;
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+ val = readb(base + 0x2100 + (reg << 2));
- CTRL(iobase, 0);
- i = inb(iobase + 64 + reg);
- CTRL(iobase, 0x40);
+ priv(host)->ctrl = 0x40;
+ writeb(0x40, base + CTRL);
- return i;
+ return val;
}
-static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
+static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
{
- int iobase = instance->io_port;
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+ void __iomem *base = priv(host)->base;
- CTRL(iobase, 0);
- outb(value, iobase + 64 + reg);
- CTRL(iobase, 0x40);
-}
+ writeb(0, base + CTRL);
-#undef CTRL
+ writeb(value, base + 0x2100 + (reg << 2));
+
+ priv(host)->ctrl = 0x40;
+ writeb(0x40, base + CTRL);
+}
#include "../NCR5380.c"
@@ -256,32 +231,46 @@ static int __devinit
cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
{
struct Scsi_Host *host;
- int ret = -ENOMEM;
+ int ret;
- host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
- if (!host)
+ ret = ecard_request_resources(ec);
+ if (ret)
goto out;
- host->io_port = ecard_address(ec, ECARD_IOC, ECARD_SLOW) + 0x800;
+ host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
+ if (!host) {
+ ret = -ENOMEM;
+ goto out_release;
+ }
+
+ priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
+ ecard_resource_len(ec, ECARD_RES_IOCSLOW));
+ priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+ ecard_resource_len(ec, ECARD_RES_MEMC));
+ if (!priv(host)->base || !priv(host)->dma) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+
host->irq = ec->irq;
NCR5380_init(host, 0);
+ priv(host)->ctrl = 0;
+ writeb(0, priv(host)->base + CTRL);
+
host->n_io_port = 255;
if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
ret = -EBUSY;
- goto out_free;
+ goto out_unmap;
}
- ((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
- outb(0x00, host->io_port - 577);
-
ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, host->irq, ret);
- goto out_release;
+ goto out_unmap;
}
printk("scsi%d: at port 0x%08lx irq %d",
@@ -301,10 +290,12 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
out_free_irq:
free_irq(host->irq, host);
- out_release:
- release_region(host->io_port, host->n_io_port);
- out_free:
+ out_unmap:
+ iounmap(priv(host)->base);
+ iounmap(priv(host)->dma);
scsi_host_put(host);
+ out_release:
+ ecard_release_resources(ec);
out:
return ret;
}
@@ -318,8 +309,10 @@ static void __devexit cumanascsi1_remove(struct expansion_card *ec)
scsi_remove_host(host);
free_irq(host->irq, host);
NCR5380_exit(host);
- release_region(host->io_port, host->n_io_port);
+ iounmap(priv(host)->base);
+ iounmap(priv(host)->dma);
scsi_host_put(host);
+ ecard_release_resources(ec);
}
static const struct ecard_id cumanascsi1_cids[] = {
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
index 378e7af0c5d6..5265a9884338 100644
--- a/drivers/scsi/arm/ecoscsi.c
+++ b/drivers/scsi/arm/ecoscsi.c
@@ -34,35 +34,25 @@
#include "../scsi.h"
#include <scsi/scsi_host.h>
-#define NCR5380_implementation_fields int port, ctrl
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
+#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
-#define NCR5380_read(reg) ecoscsi_read(_instance, reg)
-#define NCR5380_write(reg, value) ecoscsi_write(_instance, reg, value)
+#define NCR5380_local_declare() void __iomem *_base
+#define NCR5380_setup(host) _base = priv(host)->base
+
+#define NCR5380_read(reg) ({ writeb(reg | 8, _base); readb(_base + 4); })
+#define NCR5380_write(reg, value) ({ writeb(reg | 8, _base); writeb(value, _base + 4); })
#define NCR5380_intr ecoscsi_intr
#define NCR5380_queue_command ecoscsi_queue_command
#define NCR5380_proc_info ecoscsi_proc_info
+#define NCR5380_implementation_fields \
+ void __iomem *base
+
#include "../NCR5380.h"
#define ECOSCSI_PUBLIC_RELEASE 1
-static char ecoscsi_read(struct Scsi_Host *instance, int reg)
-{
- int iobase = instance->io_port;
- outb(reg | 8, iobase);
- return inb(iobase + 1);
-}
-
-static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
- int iobase = instance->io_port;
- outb(reg | 8, iobase);
- outb(value, iobase + 1);
-}
-
/*
* Function : ecoscsi_setup(char *str, int *ints)
*
@@ -82,73 +72,6 @@ const char * ecoscsi_info (struct Scsi_Host *spnt)
return "";
}
-#if 0
-#define STAT(p) inw(p + 144)
-
-static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
- int len)
-{
- int iobase = host->io_port;
-printk("writing %p len %d\n",addr, len);
- if(!len) return -1;
-
- while(1)
- {
- int status;
- while(((status = STAT(iobase)) & 0x100)==0);
- }
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
- int len)
-{
- int iobase = host->io_port;
- int iobase2= host->io_port + 0x100;
- unsigned char *start = addr;
- int s;
-printk("reading %p len %d\n",addr, len);
- outb(inb(iobase + 128), iobase + 135);
- while(len > 0)
- {
- int status,b,i, timeout;
- timeout = 0x07FFFFFF;
- while(((status = STAT(iobase)) & 0x100)==0)
- {
- timeout--;
- if(status & 0x200 || !timeout)
- {
- printk("status = %p\n",status);
- outb(0, iobase + 135);
- return 1;
- }
- }
- if(len >= 128)
- {
- for(i=0; i<64; i++)
- {
- b = inw(iobase + 136);
- *addr++ = b;
- *addr++ = b>>8;
- }
- len -= 128;
- }
- else
- {
- b = inw(iobase + 136);
- *addr ++ = b;
- len -= 1;
- if(len)
- *addr ++ = b>>8;
- len -= 1;
- }
- }
- outb(0, iobase + 135);
- printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
- return 1;
-}
-#endif
-#undef STAT
-
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
@@ -173,25 +96,36 @@ static struct Scsi_Host *host;
static int __init ecoscsi_init(void)
{
+ void __iomem *_base;
+ int ret;
- host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
- if (!host)
- return 0;
+ if (!request_mem_region(0x33a0000, 4096, "ecoscsi")) {
+ ret = -EBUSY;
+ goto out;
+ }
- host->io_port = 0x80ce8000;
- host->n_io_port = 144;
- host->irq = IRQ_NONE;
+ _base = ioremap(0x33a0000, 4096);
+ if (!_base) {
+ ret = -ENOMEM;
+ goto out_release;
+ }
- if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
- goto unregister_scsi;
+ NCR5380_write(MODE_REG, 0x20); /* Is it really SCSI? */
+ if (NCR5380_read(MODE_REG) != 0x20) /* Write to a reg. */
+ goto out_unmap;
- ecoscsi_write(host, MODE_REG, 0x20); /* Is it really SCSI? */
- if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg. */
- goto release_reg;
+ NCR5380_write(MODE_REG, 0x00); /* it back. */
+ if (NCR5380_read(MODE_REG) != 0x00)
+ goto out_unmap;
- ecoscsi_write(host, MODE_REG, 0x00 ); /* it back. */
- if (ecoscsi_read(host, MODE_REG) != 0x00)
- goto release_reg;
+ host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
+ if (!host) {
+ ret = -ENOMEM;
+ goto out_unmap;
+ }
+
+ priv(host)->base = _base;
+ host->irq = IRQ_NONE;
NCR5380_init(host, 0);
@@ -206,24 +140,20 @@ static int __init ecoscsi_init(void)
scsi_scan_host(host);
return 0;
-release_reg:
- release_region(host->io_port, host->n_io_port);
-unregister_scsi:
- scsi_host_put(host);
- return -ENODEV;
+ out_unmap:
+ iounmap(_base);
+ out_release:
+ release_mem_region(0x33a0000, 4096);
+ out:
+ return ret;
}
static void __exit ecoscsi_exit(void)
{
scsi_remove_host(host);
-
- if (shpnt->irq != IRQ_NONE)
- free_irq(shpnt->irq, NULL);
NCR5380_exit(host);
- if (shpnt->io_port)
- release_region(shpnt->io_port, shpnt->n_io_port);
-
scsi_host_put(host);
+ release_mem_region(0x33a0000, 4096);
return 0;
}
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index c21b8392c928..849cdf89f7bb 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -23,15 +23,18 @@
#define OAKSCSI_PUBLIC_RELEASE 1
-#define NCR5380_read(reg) oakscsi_read(_instance, reg)
-#define NCR5380_write(reg, value) oakscsi_write(_instance, reg, value)
+#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
+#define NCR5380_local_declare() void __iomem *_base
+#define NCR5380_setup(host) _base = priv(host)->base
+
+#define NCR5380_read(reg) readb(_base + ((reg) << 2))
+#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
#define NCR5380_intr oakscsi_intr
#define NCR5380_queue_command oakscsi_queue_command
#define NCR5380_proc_info oakscsi_proc_info
-#define NCR5380_implementation_fields int port, ctrl
-#define NCR5380_local_declare() struct Scsi_Host *_instance
-#define NCR5380_setup(instance) _instance = instance
+#define NCR5380_implementation_fields \
+ void __iomem *base
#define BOARD_NORMAL 0
#define BOARD_NCR53C400 1
@@ -39,60 +42,62 @@
#include "../NCR5380.h"
#undef START_DMA_INITIATOR_RECEIVE_REG
-#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
+#define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
const char * oakscsi_info (struct Scsi_Host *spnt)
{
return "";
}
-#define STAT(p) inw(p + 144)
-extern void inswb(int from, void *to, int len);
+#define STAT ((128 + 16) << 2)
+#define DATA ((128 + 8) << 2)
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
int len)
{
- int iobase = instance->io_port;
+ void __iomem *base = priv(instance)->base;
+
printk("writing %p len %d\n",addr, len);
if(!len) return -1;
while(1)
{
int status;
- while(((status = STAT(iobase)) & 0x100)==0);
+ while (((status = readw(base + STAT)) & 0x100)==0);
}
}
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
int len)
{
- int iobase = instance->io_port;
+ void __iomem *base = priv(instance)->base;
printk("reading %p len %d\n", addr, len);
while(len > 0)
{
- int status, timeout;
+ unsigned int status, timeout;
unsigned long b;
timeout = 0x01FFFFFF;
- while(((status = STAT(iobase)) & 0x100)==0)
+ while (((status = readw(base + STAT)) & 0x100)==0)
{
timeout--;
if(status & 0x200 || !timeout)
{
- printk("status = %08X\n",status);
+ printk("status = %08X\n", status);
return 1;
}
}
+
if(len >= 128)
{
- inswb(iobase + 136, addr, 128);
+ readsw(base + DATA, addr, 128);
addr += 128;
len -= 128;
}
else
{
- b = (unsigned long) inw(iobase + 136);
+ b = (unsigned long) readw(base + DATA);
*addr ++ = b;
len -= 1;
if(len)
@@ -103,10 +108,8 @@ printk("reading %p len %d\n", addr, len);
return 0;
}
-#define oakscsi_read(instance,reg) (inb((instance)->io_port + (reg)))
-#define oakscsi_write(instance,reg,val) (outb((val), (instance)->io_port + (reg)))
-
#undef STAT
+#undef DATA
#include "../NCR5380.c"
@@ -132,18 +135,26 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
struct Scsi_Host *host;
int ret = -ENOMEM;
- host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
- if (!host)
+ ret = ecard_request_resources(ec);
+ if (ret)
goto out;
- host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+ host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
+ if (!host) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+ ecard_resource_len(ec, ECARD_RES_MEMC));
+ if (!priv(host)->base) {
+ ret = -ENOMEM;
+ goto unreg;
+ }
+
host->irq = IRQ_NONE;
host->n_io_port = 255;
- ret = -EBUSY;
- if (!request_region (host->io_port, host->n_io_port, "Oak SCSI"))
- goto unreg;
-
NCR5380_init(host, 0);
printk("scsi%d: at port 0x%08lx irqs disabled",
@@ -156,15 +167,17 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
ret = scsi_add_host(host, &ec->dev);
if (ret)
- goto out_release;
+ goto out_unmap;
scsi_scan_host(host);
goto out;
- out_release:
- release_region(host->io_port, host->n_io_port);
+ out_unmap:
+ iounmap(priv(host)->base);
unreg:
scsi_host_put(host);
+ release:
+ ecard_release_resources(ec);
out:
return ret;
}
@@ -177,8 +190,9 @@ static void __devexit oakscsi_remove(struct expansion_card *ec)
scsi_remove_host(host);
NCR5380_exit(host);
- release_region(host->io_port, host->n_io_port);
+ iounmap(priv(host)->base);
scsi_host_put(host);
+ ecard_release_resources(ec);
}
static const struct ecard_id oakscsi_cids[] = {
diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
deleted file mode 100644
index 599b400a3c43..000000000000
--- a/drivers/scsi/bvme6000.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
- *
- * Based on work by Alan Hourihane
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-#include <linux/zorro.h>
-
-#include <asm/setup.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/bvme6000hw.h>
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "53c7xx.h"
-#include "bvme6000.h"
-
-#include<linux/stat.h>
-
-
-int bvme6000_scsi_detect(struct scsi_host_template *tpnt)
-{
- static unsigned char called = 0;
- int clock;
- long long options;
-
- if (called)
- return 0;
- if (!MACH_IS_BVME6000)
- return 0;
-
- tpnt->proc_name = "BVME6000";
-
- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
-
- clock = 40000000; /* 66MHz SCSI Clock */
-
- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE,
- 0, BVME_IRQ_SCSI, DMA_NONE,
- options, clock);
- called = 1;
- return 1;
-}
-
-static int bvme6000_scsi_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "BVME6000 NCR53c710 SCSI",
- .detect = bvme6000_scsi_detect,
- .release = bvme6000_scsi_release,
- .queuecommand = NCR53c7xx_queue_command,
- .abort = NCR53c7xx_abort,
- .reset = NCR53c7xx_reset,
- .can_queue = 24,
- .this_id = 7,
- .sg_tablesize = 63,
- .cmd_per_lun = 3,
- .use_clustering = DISABLE_CLUSTERING
-};
-
-
-#include "scsi_module.c"
diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
deleted file mode 100644
index ea3e4b2b9220..000000000000
--- a/drivers/scsi/bvme6000.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef BVME6000_SCSI_H
-#define BVME6000_SCSI_H
-
-#include <linux/types.h>
-
-int bvme6000_scsi_detect(struct scsi_host_template *);
-const char *NCR53c7x0_info(void);
-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (struct Scsi_Host *);
-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id);
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 3
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 24
-#endif
-
-#include <scsi/scsicam.h>
-
-#endif /* BVME6000_SCSI_H */
diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c
new file mode 100644
index 000000000000..cac354086737
--- /dev/null
+++ b/drivers/scsi/bvme6000_scsi.c
@@ -0,0 +1,136 @@
+/*
+ * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane and Kars de Jong
+ *
+ * Rewritten to use 53c700.c by Richard Hirst <richard@sleepie.demon.co.uk>
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/bvme6000hw.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Richard Hirst <richard@sleepie.demon.co.uk>");
+MODULE_DESCRIPTION("BVME6000 NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+static struct scsi_host_template bvme6000_scsi_driver_template = {
+ .name = "BVME6000 NCR53c710 SCSI",
+ .proc_name = "BVME6000",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct platform_device *bvme6000_scsi_device;
+
+static __devinit int
+bvme6000_probe(struct device *dev)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+
+ if (!MACH_IS_BVME6000)
+ goto out;
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "bvme6000-scsi: "
+ "Failed to allocate host data\n");
+ goto out;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ hostdata->base = (void __iomem *)BVME_NCR53C710_BASE;
+ hostdata->clock = 40; /* XXX - depends on the CPU clock! */
+ hostdata->chip710 = 1;
+ hostdata->dmode_extra = DMODE_FC2;
+ hostdata->dcntl_extra = EA_710;
+ hostdata->ctest7_extra = CTEST7_TT1;
+
+ /* and register the chip */
+ host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, dev);
+ if (!host) {
+ printk(KERN_ERR "bvme6000-scsi: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+ host->base = BVME_NCR53C710_BASE;
+ host->this_id = 7;
+ host->irq = BVME_IRQ_SCSI;
+ if (request_irq(BVME_IRQ_SCSI, NCR_700_intr, 0, "bvme6000-scsi",
+ host)) {
+ printk(KERN_ERR "bvme6000-scsi: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ dev_set_drvdata(dev, host);
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ kfree(hostdata);
+ out:
+ return -ENODEV;
+}
+
+static __devexit int
+bvme6000_device_remove(struct device *dev)
+{
+ struct Scsi_Host *host = dev_get_drvdata(dev);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ scsi_remove_host(host);
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+
+ return 0;
+}
+
+static struct device_driver bvme6000_scsi_driver = {
+ .name = "bvme6000-scsi",
+ .bus = &platform_bus_type,
+ .probe = bvme6000_probe,
+ .remove = __devexit_p(bvme6000_device_remove),
+};
+
+static int __init bvme6000_scsi_init(void)
+{
+ int err;
+
+ err = driver_register(&bvme6000_scsi_driver);
+ if (err)
+ return err;
+
+ bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi",
+ -1, NULL, 0);
+ if (IS_ERR(bvme6000_scsi_device)) {
+ driver_unregister(&bvme6000_scsi_driver);
+ return PTR_ERR(bvme6000_scsi_device);
+ }
+
+ return 0;
+}
+
+static void __exit bvme6000_scsi_exit(void)
+{
+ platform_device_unregister(bvme6000_scsi_device);
+ driver_unregister(&bvme6000_scsi_driver);
+}
+
+module_init(bvme6000_scsi_init);
+module_exit(bvme6000_scsi_exit);
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 564ea90ed3a0..7b8a3457b696 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -979,6 +979,7 @@ static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
+ int nseg;
enum dma_data_direction dir = cmd->sc_data_direction;
dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
cmd->pid, dcb->target_id, dcb->target_lun);
@@ -1000,27 +1001,30 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
srb->end_message = 0;
- if (dir == PCI_DMA_NONE || !cmd->request_buffer) {
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+
+ if (dir == PCI_DMA_NONE || !nseg) {
dprintkdbg(DBG_0,
"build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n",
- cmd->bufflen, cmd->request_buffer,
- cmd->use_sg, srb->segment_x[0].address);
- } else if (cmd->use_sg) {
+ cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd),
+ srb->segment_x[0].address);
+ } else {
int i;
- u32 reqlen = cmd->request_bufflen;
- struct scatterlist *sl = (struct scatterlist *)
- cmd->request_buffer;
+ u32 reqlen = scsi_bufflen(cmd);
+ struct scatterlist *sg;
struct SGentry *sgp = srb->segment_x;
- srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg,
- dir);
+
+ srb->sg_count = nseg;
+
dprintkdbg(DBG_0,
- "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
- reqlen, cmd->request_buffer, cmd->use_sg,
- srb->sg_count);
+ "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
+ reqlen, scsi_sglist(cmd), scsi_sg_count(cmd),
+ srb->sg_count);
- for (i = 0; i < srb->sg_count; i++) {
- u32 busaddr = (u32)sg_dma_address(&sl[i]);
- u32 seglen = (u32)sl[i].length;
+ scsi_for_each_sg(cmd, sg, srb->sg_count, i) {
+ u32 busaddr = (u32)sg_dma_address(sg);
+ u32 seglen = (u32)sg->length;
sgp[i].address = busaddr;
sgp[i].length = seglen;
srb->total_xfer_length += seglen;
@@ -1050,23 +1054,6 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n",
srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
- } else {
- srb->total_xfer_length = cmd->request_bufflen;
- srb->sg_count = 1;
- srb->segment_x[0].address =
- pci_map_single(dcb->acb->dev, cmd->request_buffer,
- srb->total_xfer_length, dir);
-
- /* Fixup for WIDE padding - make sure length is even */
- if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2)
- srb->total_xfer_length++;
-
- srb->segment_x[0].length = srb->total_xfer_length;
-
- dprintkdbg(DBG_0,
- "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n",
- srb->total_xfer_length, cmd->request_buffer,
- cmd->use_sg, srb->segment_x[0].address);
}
srb->request_length = srb->total_xfer_length;
@@ -2128,7 +2115,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
/*clear_fifo(acb, "DOP1"); */
/* KG: What is this supposed to be useful for? WIDE padding stuff? */
if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC
- && srb->cmd->request_bufflen % 2) {
+ && scsi_bufflen(srb->cmd) % 2) {
d_left_counter = 0;
dprintkl(KERN_INFO,
"data_out_phase0: Discard 1 byte (0x%02x)\n",
@@ -2159,7 +2146,7 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
sg_update_list(srb, d_left_counter);
/* KG: Most ugly hack! Apparently, this works around a chip bug */
if ((srb->segment_x[srb->sg_index].length ==
- diff && srb->cmd->use_sg)
+ diff && scsi_sg_count(srb->cmd))
|| ((oldxferred & ~PAGE_MASK) ==
(PAGE_SIZE - diff))
) {
@@ -2289,19 +2276,15 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
unsigned char *virt, *base = NULL;
unsigned long flags = 0;
size_t len = left_io;
+ size_t offset = srb->request_length - left_io;
+
+ local_irq_save(flags);
+ /* Assumption: it's inside one page as it's at most 4 bytes and
+ I just assume it's on a 4-byte boundary */
+ base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
+ srb->sg_count, &offset, &len);
+ virt = base + offset;
- if (srb->cmd->use_sg) {
- size_t offset = srb->request_length - left_io;
- local_irq_save(flags);
- /* Assumption: it's inside one page as it's at most 4 bytes and
- I just assume it's on a 4-byte boundary */
- base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
- srb->sg_count, &offset, &len);
- virt = base + offset;
- } else {
- virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
- len = left_io;
- }
left_io -= len;
while (len) {
@@ -2341,10 +2324,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
}
- if (srb->cmd->use_sg) {
- scsi_kunmap_atomic_sg(base);
- local_irq_restore(flags);
- }
+ scsi_kunmap_atomic_sg(base);
+ local_irq_restore(flags);
}
/*printk(" %08x", *(u32*)(bus_to_virt (addr))); */
/*srb->total_xfer_length = 0; */
@@ -2455,7 +2436,7 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
*/
srb->state |= SRB_DATA_XFER;
DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
- if (srb->cmd->use_sg) { /* with S/G */
+ if (scsi_sg_count(srb->cmd)) { /* with S/G */
io_dir |= DMACMD_SG;
DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
srb->sg_bus_addr +
@@ -2513,18 +2494,14 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
unsigned char *virt, *base = NULL;
unsigned long flags = 0;
size_t len = left_io;
+ size_t offset = srb->request_length - left_io;
+
+ local_irq_save(flags);
+ /* Again, max 4 bytes */
+ base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd),
+ srb->sg_count, &offset, &len);
+ virt = base + offset;
- if (srb->cmd->use_sg) {
- size_t offset = srb->request_length - left_io;
- local_irq_save(flags);
- /* Again, max 4 bytes */
- base = scsi_kmap_atomic_sg((struct scatterlist *)srb->cmd->request_buffer,
- srb->sg_count, &offset, &len);
- virt = base + offset;
- } else {
- virt = srb->cmd->request_buffer + srb->cmd->request_bufflen - left_io;
- len = left_io;
- }
left_io -= len;
while (len--) {
@@ -2536,10 +2513,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
sg_subtract_one(srb);
}
- if (srb->cmd->use_sg) {
- scsi_kunmap_atomic_sg(base);
- local_irq_restore(flags);
- }
+ scsi_kunmap_atomic_sg(base);
+ local_irq_restore(flags);
}
if (srb->dcb->sync_period & WIDE_SYNC) {
if (ln % 2) {
@@ -3295,7 +3270,8 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
{
struct scsi_cmnd *cmd = srb->cmd;
enum dma_data_direction dir = cmd->sc_data_direction;
- if (cmd->use_sg && dir != PCI_DMA_NONE) {
+
+ if (scsi_sg_count(cmd) && dir != PCI_DMA_NONE) {
/* unmap DC395x SG list */
dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
srb->sg_bus_addr, SEGMENTX_LEN);
@@ -3303,16 +3279,9 @@ static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
SEGMENTX_LEN,
PCI_DMA_TODEVICE);
dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
- cmd->use_sg, cmd->request_buffer);
+ scsi_sg_count(cmd), scsi_bufflen(cmd));
/* unmap the sg segments */
- pci_unmap_sg(acb->dev,
- (struct scatterlist *)cmd->request_buffer,
- cmd->use_sg, dir);
- } else if (cmd->request_buffer && dir != PCI_DMA_NONE) {
- dprintkdbg(DBG_SG, "pci_unmap_srb: buffer=%08x(%05x)\n",
- srb->segment_x[0].address, cmd->request_bufflen);
- pci_unmap_single(acb->dev, srb->segment_x[0].address,
- cmd->request_bufflen, dir);
+ scsi_dma_unmap(cmd);
}
}
@@ -3352,8 +3321,8 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
srb->cmd->device->id, srb->cmd->device->lun);
dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
- srb, cmd->use_sg, srb->sg_index, srb->sg_count,
- cmd->request_buffer);
+ srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
+ scsi_sgtalbe(cmd));
status = srb->target_status;
if (srb->flag & AUTO_REQSENSE) {
dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
@@ -3482,16 +3451,10 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
}
}
- if (dir != PCI_DMA_NONE) {
- if (cmd->use_sg)
- pci_dma_sync_sg_for_cpu(acb->dev,
- (struct scatterlist *)cmd->
- request_buffer, cmd->use_sg, dir);
- else if (cmd->request_buffer)
- pci_dma_sync_single_for_cpu(acb->dev,
- srb->segment_x[0].address,
- cmd->request_bufflen, dir);
- }
+ if (dir != PCI_DMA_NONE && scsi_sg_count(cmd))
+ pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), dir);
+
ckc_only = 0;
/* Check Error Conditions */
ckc_e:
@@ -3500,19 +3463,15 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
unsigned char *base = NULL;
struct ScsiInqData *ptr;
unsigned long flags = 0;
+ struct scatterlist* sg = scsi_sglist(cmd);
+ size_t offset = 0, len = sizeof(struct ScsiInqData);
- if (cmd->use_sg) {
- struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
- size_t offset = 0, len = sizeof(struct ScsiInqData);
-
- local_irq_save(flags);
- base = scsi_kmap_atomic_sg(sg, cmd->use_sg, &offset, &len);
- ptr = (struct ScsiInqData *)(base + offset);
- } else
- ptr = (struct ScsiInqData *)(cmd->request_buffer);
+ local_irq_save(flags);
+ base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len);
+ ptr = (struct ScsiInqData *)(base + offset);
if (!ckc_only && (cmd->result & RES_DID) == 0
- && cmd->cmnd[2] == 0 && cmd->request_bufflen >= 8
+ && cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8
&& dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
dcb->inquiry7 = ptr->Flags;
@@ -3527,14 +3486,12 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
}
}
- if (cmd->use_sg) {
- scsi_kunmap_atomic_sg(base);
- local_irq_restore(flags);
- }
+ scsi_kunmap_atomic_sg(base);
+ local_irq_restore(flags);
}
/* Here is the info for Doug Gilbert's sg3 ... */
- cmd->resid = srb->total_xfer_length;
+ scsi_set_resid(cmd, srb->total_xfer_length);
/* This may be interpreted by sb. or not ... */
cmd->SCp.this_residual = srb->total_xfer_length;
cmd->SCp.buffers_residual = 0;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 8c7d2bbf9b1a..2e2362d787ca 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -2078,12 +2078,13 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
u32 *lenptr;
int direction;
int scsidir;
+ int nseg;
u32 len;
u32 reqlen;
s32 rcode;
memset(msg, 0 , sizeof(msg));
- len = cmd->request_bufflen;
+ len = scsi_bufflen(cmd);
direction = 0x00000000;
scsidir = 0x00000000; // DATA NO XFER
@@ -2140,21 +2141,21 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
lenptr=mptr++; /* Remember me - fill in when we know */
reqlen = 14; // SINGLE SGE
/* Now fill in the SGList and command */
- if(cmd->use_sg) {
- struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
- int sg_count = pci_map_sg(pHba->pDev, sg, cmd->use_sg,
- cmd->sc_data_direction);
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
+ struct scatterlist *sg;
len = 0;
- for(i = 0 ; i < sg_count; i++) {
+ scsi_for_each_sg(cmd, sg, nseg, i) {
*mptr++ = direction|0x10000000|sg_dma_len(sg);
len+=sg_dma_len(sg);
*mptr++ = sg_dma_address(sg);
- sg++;
+ /* Make this an end of list */
+ if (i == nseg - 1)
+ mptr[-2] = direction|0xD0000000|sg_dma_len(sg);
}
- /* Make this an end of list */
- mptr[-2] = direction|0xD0000000|sg_dma_len(sg-1);
reqlen = mptr - msg;
*lenptr = len;
@@ -2163,16 +2164,8 @@ static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_d
len, cmd->underflow);
}
} else {
- *lenptr = len = cmd->request_bufflen;
- if(len == 0) {
- reqlen = 12;
- } else {
- *mptr++ = 0xD0000000|direction|cmd->request_bufflen;
- *mptr++ = pci_map_single(pHba->pDev,
- cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ *lenptr = len = 0;
+ reqlen = 12;
}
/* Stick the headers on */
@@ -2232,7 +2225,7 @@ static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
hba_status = detailed_status >> 8;
// calculate resid for sg
- cmd->resid = cmd->request_bufflen - readl(reply+5);
+ scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+5));
pHba = (adpt_hba*) cmd->device->host->hostdata[0];
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 2d38025861a5..a83e9f150b97 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1609,8 +1609,9 @@ static int eata2x_detect(struct scsi_host_template *tpnt)
static void map_dma(unsigned int i, struct hostdata *ha)
{
- unsigned int k, count, pci_dir;
- struct scatterlist *sgpnt;
+ unsigned int k, pci_dir;
+ int count;
+ struct scatterlist *sg;
struct mscp *cpp;
struct scsi_cmnd *SCpnt;
@@ -1625,38 +1626,19 @@ static void map_dma(unsigned int i, struct hostdata *ha)
cpp->sense_len = sizeof SCpnt->sense_buffer;
- if (!SCpnt->use_sg) {
-
- /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
- if (!SCpnt->request_bufflen)
- pci_dir = PCI_DMA_BIDIRECTIONAL;
-
- if (SCpnt->request_buffer)
- cpp->data_address = H2DEV(pci_map_single(ha->pdev,
- SCpnt->
- request_buffer,
- SCpnt->
- request_bufflen,
- pci_dir));
-
- cpp->data_len = H2DEV(SCpnt->request_bufflen);
- return;
- }
-
- sgpnt = (struct scatterlist *)SCpnt->request_buffer;
- count = pci_map_sg(ha->pdev, sgpnt, SCpnt->use_sg, pci_dir);
-
- for (k = 0; k < count; k++) {
- cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
- cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
+ count = scsi_dma_map(SCpnt);
+ BUG_ON(count < 0);
+ scsi_for_each_sg(SCpnt, sg, count, k) {
+ cpp->sglist[k].address = H2DEV(sg_dma_address(sg));
+ cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg));
}
cpp->sg = 1;
cpp->data_address = H2DEV(pci_map_single(ha->pdev, cpp->sglist,
- SCpnt->use_sg *
+ scsi_sg_count(SCpnt) *
sizeof(struct sg_list),
pci_dir));
- cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
+ cpp->data_len = H2DEV((scsi_sg_count(SCpnt) * sizeof(struct sg_list)));
}
static void unmap_dma(unsigned int i, struct hostdata *ha)
@@ -1673,9 +1655,7 @@ static void unmap_dma(unsigned int i, struct hostdata *ha)
pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr),
DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_unmap_sg(ha->pdev, SCpnt->request_buffer, SCpnt->use_sg,
- pci_dir);
+ scsi_dma_unmap(SCpnt);
if (!DEV2H(cpp->data_len))
pci_dir = PCI_DMA_BIDIRECTIONAL;
@@ -1700,9 +1680,9 @@ static void sync_dma(unsigned int i, struct hostdata *ha)
DEV2H(cpp->sense_len),
PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_dma_sync_sg_for_cpu(ha->pdev, SCpnt->request_buffer,
- SCpnt->use_sg, pci_dir);
+ if (scsi_sg_count(SCpnt))
+ pci_dma_sync_sg_for_cpu(ha->pdev, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt), pci_dir);
if (!DEV2H(cpp->data_len))
pci_dir = PCI_DMA_BIDIRECTIONAL;
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 71caf2ded6ba..77b06a983fa7 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -324,17 +324,14 @@ static void esp_reset_esp(struct esp *esp)
static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd)
{
struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd);
- struct scatterlist *sg = cmd->request_buffer;
+ struct scatterlist *sg = scsi_sglist(cmd);
int dir = cmd->sc_data_direction;
int total, i;
if (dir == DMA_NONE)
return;
- BUG_ON(cmd->use_sg == 0);
-
- spriv->u.num_sg = esp->ops->map_sg(esp, sg,
- cmd->use_sg, dir);
+ spriv->u.num_sg = esp->ops->map_sg(esp, sg, scsi_sg_count(cmd), dir);
spriv->cur_residue = sg_dma_len(sg);
spriv->cur_sg = sg;
@@ -407,8 +404,7 @@ static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd)
if (dir == DMA_NONE)
return;
- esp->ops->unmap_sg(esp, cmd->request_buffer,
- spriv->u.num_sg, dir);
+ esp->ops->unmap_sg(esp, scsi_sglist(cmd), spriv->u.num_sg, dir);
}
static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent)
@@ -921,7 +917,7 @@ static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent)
static int esp_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
struct scsi_device *dev = cmd->device;
- struct esp *esp = host_to_esp(dev->host);
+ struct esp *esp = shost_priv(dev->host);
struct esp_cmd_priv *spriv;
struct esp_cmd_entry *ent;
@@ -2357,7 +2353,7 @@ EXPORT_SYMBOL(scsi_esp_unregister);
static int esp_slave_alloc(struct scsi_device *dev)
{
- struct esp *esp = host_to_esp(dev->host);
+ struct esp *esp = shost_priv(dev->host);
struct esp_target_data *tp = &esp->target[dev->id];
struct esp_lun_data *lp;
@@ -2381,7 +2377,7 @@ static int esp_slave_alloc(struct scsi_device *dev)
static int esp_slave_configure(struct scsi_device *dev)
{
- struct esp *esp = host_to_esp(dev->host);
+ struct esp *esp = shost_priv(dev->host);
struct esp_target_data *tp = &esp->target[dev->id];
int goal_tags, queue_depth;
@@ -2423,7 +2419,7 @@ static void esp_slave_destroy(struct scsi_device *dev)
static int esp_eh_abort_handler(struct scsi_cmnd *cmd)
{
- struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp *esp = shost_priv(cmd->device->host);
struct esp_cmd_entry *ent, *tmp;
struct completion eh_done;
unsigned long flags;
@@ -2539,7 +2535,7 @@ out_failure:
static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd)
{
- struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp *esp = shost_priv(cmd->device->host);
struct completion eh_reset;
unsigned long flags;
@@ -2575,7 +2571,7 @@ static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd)
/* All bets are off, reset the entire device. */
static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd)
{
- struct esp *esp = host_to_esp(cmd->device->host);
+ struct esp *esp = shost_priv(cmd->device->host);
unsigned long flags;
spin_lock_irqsave(esp->host->host_lock, flags);
@@ -2615,7 +2611,7 @@ EXPORT_SYMBOL(scsi_esp_template);
static void esp_get_signalling(struct Scsi_Host *host)
{
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
enum spi_signal_type type;
if (esp->flags & ESP_FLAG_DIFFERENTIAL)
@@ -2629,7 +2625,7 @@ static void esp_get_signalling(struct Scsi_Host *host)
static void esp_set_offset(struct scsi_target *target, int offset)
{
struct Scsi_Host *host = dev_to_shost(target->dev.parent);
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id];
tp->nego_goal_offset = offset;
@@ -2639,7 +2635,7 @@ static void esp_set_offset(struct scsi_target *target, int offset)
static void esp_set_period(struct scsi_target *target, int period)
{
struct Scsi_Host *host = dev_to_shost(target->dev.parent);
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id];
tp->nego_goal_period = period;
@@ -2649,7 +2645,7 @@ static void esp_set_period(struct scsi_target *target, int period)
static void esp_set_width(struct scsi_target *target, int width)
{
struct Scsi_Host *host = dev_to_shost(target->dev.parent);
- struct esp *esp = host_to_esp(host);
+ struct esp *esp = shost_priv(host);
struct esp_target_data *tp = &esp->target[target->id];
tp->nego_goal_width = (width ? 1 : 0);
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index 8d4a6690401f..856e38b14861 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -220,7 +220,7 @@
#define ESP_BUSID_RESELID 0x10
#define ESP_BUSID_CTR32BIT 0x40
-#define ESP_BUS_TIMEOUT 250 /* In milli-seconds */
+#define ESP_BUS_TIMEOUT 275 /* In milli-seconds */
#define ESP_TIMEO_CONST 8192
#define ESP_NEG_DEFP(mhz, cfact) \
((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
@@ -517,8 +517,6 @@ struct esp {
struct sbus_dma *dma;
};
-#define host_to_esp(host) ((struct esp *)(host)->hostdata)
-
/* A front-end driver for the ESP chip should do the following in
* it's device probe routine:
* 1) Allocate the host and private area using scsi_host_alloc()
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index 5d4ea6f77953..36169d597e98 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -410,6 +410,8 @@ static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id );
static char * fdomain = NULL;
module_param(fdomain, charp, 0);
+#ifndef PCMCIA
+
static unsigned long addresses[] = {
0xc8000,
0xca000,
@@ -426,6 +428,8 @@ static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+#endif /* !PCMCIA */
+
/*
READ THIS BEFORE YOU ADD A SIGNATURE!
@@ -458,6 +462,8 @@ static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
*/
+#ifndef PCMCIA
+
static struct signature {
const char *signature;
int sig_offset;
@@ -503,6 +509,8 @@ static struct signature {
#define SIGNATURE_COUNT ARRAY_SIZE(signatures)
+#endif /* !PCMCIA */
+
static void print_banner( struct Scsi_Host *shpnt )
{
if (!shpnt) return; /* This won't ever happen */
@@ -633,6 +641,8 @@ static int fdomain_test_loopback( void )
return 0;
}
+#ifndef PCMCIA
+
/* fdomain_get_irq assumes that we have a valid MCA ID for a
TMC-1660/TMC-1680 Future Domain board. Now, check to be sure the
bios_base matches these ports. If someone was unlucky enough to have
@@ -667,7 +677,6 @@ static int fdomain_get_irq( int base )
static int fdomain_isa_detect( int *irq, int *iobase )
{
-#ifndef PCMCIA
int i, j;
int base = 0xdeadbeef;
int flag = 0;
@@ -786,11 +795,22 @@ found:
*iobase = base;
return 1; /* success */
-#else
- return 0;
-#endif
}
+#else /* PCMCIA */
+
+static int fdomain_isa_detect( int *irq, int *iobase )
+{
+ if (irq)
+ *irq = 0;
+ if (iobase)
+ *iobase = 0;
+ return 0;
+}
+
+#endif /* !PCMCIA */
+
+
/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int*
iobase) This function gets the Interrupt Level and I/O base address from
the PCI configuration registers. */
@@ -1345,16 +1365,15 @@ static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
#if ERRORS_ONLY
if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
- if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
+ char *buf = scsi_sglist(current_SC);
+ if ((unsigned char)(*(buf + 2)) & 0x0f) {
unsigned char key;
unsigned char code;
unsigned char qualifier;
- key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
- & 0x0f;
- code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
- qualifier = (unsigned char)(*((char *)current_SC->request_buffer
- + 13));
+ key = (unsigned char)(*(buf + 2)) & 0x0f;
+ code = (unsigned char)(*(buf + 12));
+ qualifier = (unsigned char)(*(buf + 13));
if (key != UNIT_ATTENTION
&& !(key == NOT_READY
@@ -1405,8 +1424,8 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
SCpnt->target,
*(unsigned char *)SCpnt->cmnd,
- SCpnt->use_sg,
- SCpnt->request_bufflen );
+ scsi_sg_count(SCpnt),
+ scsi_bufflen(SCpnt));
#endif
fdomain_make_bus_idle();
@@ -1416,20 +1435,19 @@ static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
/* Initialize static data */
- if (current_SC->use_sg) {
- current_SC->SCp.buffer =
- (struct scatterlist *)current_SC->request_buffer;
- current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
- current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
- current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
+ if (scsi_sg_count(current_SC)) {
+ current_SC->SCp.buffer = scsi_sglist(current_SC);
+ current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page)
+ + current_SC->SCp.buffer->offset;
+ 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 = (char *)current_SC->request_buffer;
- current_SC->SCp.this_residual = current_SC->request_bufflen;
- current_SC->SCp.buffer = NULL;
- current_SC->SCp.buffers_residual = 0;
+ current_SC->SCp.ptr = 0;
+ current_SC->SCp.this_residual = 0;
+ current_SC->SCp.buffer = NULL;
+ current_SC->SCp.buffers_residual = 0;
}
-
-
+
current_SC->SCp.Status = 0;
current_SC->SCp.Message = 0;
current_SC->SCp.have_data_in = 0;
@@ -1472,8 +1490,8 @@ static void print_info(struct scsi_cmnd *SCpnt)
SCpnt->SCp.phase,
SCpnt->device->id,
*(unsigned char *)SCpnt->cmnd,
- SCpnt->use_sg,
- SCpnt->request_bufflen );
+ scsi_sg_count(SCpnt),
+ scsi_bufflen(SCpnt));
printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
SCpnt->SCp.sent_command,
SCpnt->SCp.have_data_in,
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 60446b88f721..d0b95ce0ba00 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -876,7 +876,7 @@ static int __init gdth_search_pci(gdth_pci_str *pcistr)
/* Vortex only makes RAID controllers.
* We do not really want to specify all 550 ids here, so wildcard match.
*/
-static struct pci_device_id gdthtable[] __attribute_used__ = {
+static struct pci_device_id gdthtable[] __maybe_unused = {
{PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID},
{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID},
{PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC_XSCALE,PCI_ANY_ID,PCI_ANY_ID},
@@ -1955,7 +1955,7 @@ static int __init gdth_search_drives(int hanum)
for (j = 0; j < 12; ++j)
rtc[j] = CMOS_READ(j);
} while (rtc[0] != CMOS_READ(0));
- spin_lock_irqrestore(&rtc_lock, flags);
+ spin_unlock_irqrestore(&rtc_lock, flags);
TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
*(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
/* 3. send to controller firmware */
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index bec83cbee59a..0e579ca45814 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -339,20 +339,8 @@ static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag)
scp = hba->reqs[tag].scp;
- if (HPT_SCP(scp)->mapped) {
- if (scp->use_sg)
- pci_unmap_sg(hba->pcidev,
- (struct scatterlist *)scp->request_buffer,
- scp->use_sg,
- scp->sc_data_direction
- );
- else
- pci_unmap_single(hba->pcidev,
- HPT_SCP(scp)->dma_handle,
- scp->request_bufflen,
- scp->sc_data_direction
- );
- }
+ if (HPT_SCP(scp)->mapped)
+ scsi_dma_unmap(scp);
switch (le32_to_cpu(req->header.result)) {
case IOP_RESULT_SUCCESS:
@@ -448,43 +436,26 @@ static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg)
{
struct Scsi_Host *host = scp->device->host;
struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata;
- struct scatterlist *sglist = (struct scatterlist *)scp->request_buffer;
-
- /*
- * though we'll not get non-use_sg fields anymore,
- * keep use_sg checking anyway
- */
- if (scp->use_sg) {
- int idx;
-
- HPT_SCP(scp)->sgcnt = pci_map_sg(hba->pcidev,
- sglist, scp->use_sg,
- scp->sc_data_direction);
- HPT_SCP(scp)->mapped = 1;
- BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors);
-
- for (idx = 0; idx < HPT_SCP(scp)->sgcnt; idx++) {
- psg[idx].pci_address =
- cpu_to_le64(sg_dma_address(&sglist[idx]));
- psg[idx].size = cpu_to_le32(sg_dma_len(&sglist[idx]));
- psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ?
- cpu_to_le32(1) : 0;
- }
+ struct scatterlist *sg;
+ int idx, nseg;
+
+ nseg = scsi_dma_map(scp);
+ BUG_ON(nseg < 0);
+ if (!nseg)
+ return 0;
- return HPT_SCP(scp)->sgcnt;
- } else {
- HPT_SCP(scp)->dma_handle = pci_map_single(
- hba->pcidev,
- scp->request_buffer,
- scp->request_bufflen,
- scp->sc_data_direction
- );
- HPT_SCP(scp)->mapped = 1;
- psg->pci_address = cpu_to_le64(HPT_SCP(scp)->dma_handle);
- psg->size = cpu_to_le32(scp->request_bufflen);
- psg->eot = cpu_to_le32(1);
- return 1;
+ HPT_SCP(scp)->sgcnt = nseg;
+ HPT_SCP(scp)->mapped = 1;
+
+ BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors);
+
+ scsi_for_each_sg(scp, sg, HPT_SCP(scp)->sgcnt, idx) {
+ psg[idx].pci_address = cpu_to_le64(sg_dma_address(sg));
+ psg[idx].size = cpu_to_le32(sg_dma_len(sg));
+ psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ?
+ cpu_to_le32(1) : 0;
}
+ return HPT_SCP(scp)->sgcnt;
}
static int hptiop_queuecommand(struct scsi_cmnd *scp,
@@ -529,9 +500,8 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
req = (struct hpt_iop_request_scsi_command *)_req->req_virt;
/* build S/G table */
- if (scp->request_bufflen)
- sg_count = hptiop_buildsgl(scp, req->sg_list);
- else
+ sg_count = hptiop_buildsgl(scp, req->sg_list);
+ if (!sg_count)
HPT_SCP(scp)->mapped = 0;
req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT);
@@ -540,7 +510,7 @@ static int hptiop_queuecommand(struct scsi_cmnd *scp,
req->header.context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT |
(u32)_req->index);
req->header.context_hi32 = 0;
- req->dataxfer_length = cpu_to_le32(scp->request_bufflen);
+ req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp));
req->channel = scp->device->channel;
req->target = scp->device->id;
req->lun = scp->device->lun;
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 0e57fb6964d5..4275d1b04ced 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -31,14 +31,21 @@
#include <linux/mca.h>
#include <linux/spinlock.h>
#include <linux/init.h>
-#include <linux/mca-legacy.h>
#include <asm/system.h>
#include <asm/io.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
-#include "ibmmca.h"
+
+/* Common forward declarations for all Linux-versions: */
+static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int ibmmca_abort (Scsi_Cmnd *);
+static int ibmmca_host_reset (Scsi_Cmnd *);
+static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
+static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout);
+
+
/* current version of this driver-source: */
#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac"
@@ -65,11 +72,11 @@
#define IM_DEBUG_CMD_DEVICE TYPE_TAPE
/* relative addresses of hardware registers on a subsystem */
-#define IM_CMD_REG(hi) (hosts[(hi)]->io_port) /*Command Interface, (4 bytes long) */
-#define IM_ATTN_REG(hi) (hosts[(hi)]->io_port+4) /*Attention (1 byte) */
-#define IM_CTR_REG(hi) (hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */
-#define IM_INTR_REG(hi) (hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */
-#define IM_STAT_REG(hi) (hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */
+#define IM_CMD_REG(h) ((h)->io_port) /*Command Interface, (4 bytes long) */
+#define IM_ATTN_REG(h) ((h)->io_port+4) /*Attention (1 byte) */
+#define IM_CTR_REG(h) ((h)->io_port+5) /*Basic Control (1 byte) */
+#define IM_INTR_REG(h) ((h)->io_port+6) /*Interrupt Status (1 byte, r/o) */
+#define IM_STAT_REG(h) ((h)->io_port+7) /*Basic Status (1 byte, read only) */
/* basic I/O-port of first adapter */
#define IM_IO_PORT 0x3540
@@ -266,30 +273,36 @@ static int global_adapter_speed = 0; /* full speed by default */
if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); }
-/*list of supported subsystems */
-struct subsys_list_struct {
- unsigned short mca_id;
- char *description;
-};
-
/* types of different supported hardware that goes to hostdata special */
#define IBM_SCSI2_FW 0
#define IBM_7568_WCACHE 1
#define IBM_EXP_UNIT 2
#define IBM_SCSI_WCACHE 3
#define IBM_SCSI 4
+#define IBM_INTEGSCSI 5
/* other special flags for hostdata structure */
#define FORCED_DETECTION 100
#define INTEGRATED_SCSI 101
/* List of possible IBM-SCSI-adapters */
-static struct subsys_list_struct subsys_list[] = {
- {0x8efc, "IBM SCSI-2 F/W Adapter"}, /* special = 0 */
- {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"}, /* special = 1 */
- {0x8ef8, "IBM Expansion Unit SCSI Controller"}, /* special = 2 */
- {0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */
- {0x8efe, "IBM SCSI Adapter"}, /* special = 4 */
+static short ibmmca_id_table[] = {
+ 0x8efc,
+ 0x8efd,
+ 0x8ef8,
+ 0x8eff,
+ 0x8efe,
+ /* No entry for integrated SCSI, that's part of the register */
+ 0
+};
+
+static const char *ibmmca_description[] = {
+ "IBM SCSI-2 F/W Adapter", /* special = 0 */
+ "IBM 7568 Industrial Computer SCSI Adapter w/Cache", /* special = 1 */
+ "IBM Expansion Unit SCSI Controller", /* special = 2 */
+ "IBM SCSI Adapter w/Cache", /* special = 3 */
+ "IBM SCSI Adapter", /* special = 4 */
+ "IBM Integrated SCSI Controller", /* special = 5 */
};
/* Max number of logical devices (can be up from 0 to 14). 15 is the address
@@ -375,30 +388,30 @@ struct ibmmca_hostdata {
};
/* macros to access host data structure */
-#define subsystem_pun(hi) (hosts[(hi)]->this_id)
-#define subsystem_maxid(hi) (hosts[(hi)]->max_id)
-#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)
-#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)
-#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)
-#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag)
-#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt)
-#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result)
-#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)
-#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)
-#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
-#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount)
-#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block)
-#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
-#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)
-#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)
-#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)
-#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size)
-#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed)
-#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[2])
-#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[3])
-#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[4])
-#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[5])
-#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[6])
+#define subsystem_pun(h) ((h)->this_id)
+#define subsystem_maxid(h) ((h)->max_id)
+#define ld(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_ld)
+#define get_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_ldn)
+#define get_scsi(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_scsi)
+#define local_checking_phase_flag(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_local_checking_phase_flag)
+#define got_interrupt(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_got_interrupt)
+#define stat_result(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_stat_result)
+#define reset_status(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_reset_status)
+#define last_scsi_command(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_command)
+#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
+#define last_scsi_blockcount(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_blockcount)
+#define last_scsi_logical_block(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_logical_block)
+#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type)
+#define next_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_next_ldn)
+#define IBM_DS(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_IBM_DS)
+#define special(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_special)
+#define subsystem_connector_size(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_connector_size)
+#define adapter_speed(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_adapter_speed)
+#define pos2(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[2])
+#define pos3(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[3])
+#define pos4(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[4])
+#define pos5(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[5])
+#define pos6(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[6])
/* Define a arbitrary number as subsystem-marker-type. This number is, as
described in the ANSI-SCSI-standard, not occupied by other device-types. */
@@ -459,11 +472,6 @@ MODULE_LICENSE("GPL");
/*counter of concurrent disk read/writes, to turn on/off disk led */
static int disk_rw_in_progress = 0;
-/* host information */
-static int found = 0;
-static struct Scsi_Host *hosts[IM_MAX_HOSTS + 1] = {
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
-};
static unsigned int pos[8]; /* whole pos register-line for diagnosis */
/* Taking into account the additions, made by ZP Gu.
* This selects now the preset value from the configfile and
@@ -474,70 +482,68 @@ static char ibm_ansi_order = 1;
static char ibm_ansi_order = 0;
#endif
-static void issue_cmd(int, unsigned long, unsigned char);
+static void issue_cmd(struct Scsi_Host *, unsigned long, unsigned char);
static void internal_done(Scsi_Cmnd * cmd);
-static void check_devices(int, int);
-static int immediate_assign(int, unsigned int, unsigned int, unsigned int, unsigned int);
-static int immediate_feature(int, unsigned int, unsigned int);
+static void check_devices(struct Scsi_Host *, int);
+static int immediate_assign(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, unsigned int);
+static int immediate_feature(struct Scsi_Host *, unsigned int, unsigned int);
#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(int, unsigned int);
+static int immediate_reset(struct Scsi_Host *, unsigned int);
#endif
-static int device_inquiry(int, int);
-static int read_capacity(int, int);
-static int get_pos_info(int);
+static int device_inquiry(struct Scsi_Host *, int);
+static int read_capacity(struct Scsi_Host *, int);
+static int get_pos_info(struct Scsi_Host *);
static char *ti_p(int);
static char *ti_l(int);
static char *ibmrate(unsigned int, int);
static int probe_display(int);
-static int probe_bus_mode(int);
-static int device_exists(int, int, int *, int *);
-static struct Scsi_Host *ibmmca_register(struct scsi_host_template *, int, int, int, char *);
+static int probe_bus_mode(struct Scsi_Host *);
+static int device_exists(struct Scsi_Host *, int, int *, int *);
static int option_setup(char *);
/* local functions needed for proc_info */
-static int ldn_access_load(int, int);
-static int ldn_access_total_read_write(int);
+static int ldn_access_load(struct Scsi_Host *, int);
+static int ldn_access_total_read_write(struct Scsi_Host *);
static irqreturn_t interrupt_handler(int irq, void *dev_id)
{
- int host_index, ihost_index;
unsigned int intr_reg;
unsigned int cmd_result;
unsigned int ldn;
+ unsigned long flags;
Scsi_Cmnd *cmd;
int lastSCSI;
- struct Scsi_Host *dev = dev_id;
+ struct device *dev = dev_id;
+ struct Scsi_Host *shpnt = dev_get_drvdata(dev);
- spin_lock(dev->host_lock);
- /* search for one adapter-response on shared interrupt */
- for (host_index = 0; hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST); host_index++);
- /* return if some other device on this IRQ caused the interrupt */
- if (!hosts[host_index]) {
- spin_unlock(dev->host_lock);
+ spin_lock_irqsave(shpnt->host_lock, flags);
+
+ if(!(inb(IM_STAT_REG(shpnt)) & IM_INTR_REQUEST)) {
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_NONE;
}
/* the reset-function already did all the job, even ints got
renabled on the subsystem, so just return */
- if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) {
- reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
- spin_unlock(dev->host_lock);
+ if ((reset_status(shpnt) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(shpnt) == IM_RESET_FINISHED_OK_NO_INT)) {
+ reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
/*must wait for attention reg not busy, then send EOI to subsystem */
while (1) {
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
cpu_relax();
}
- ihost_index = host_index;
+
/*get command result and logical device */
- intr_reg = (unsigned char) (inb(IM_INTR_REG(ihost_index)));
+ intr_reg = (unsigned char) (inb(IM_INTR_REG(shpnt)));
cmd_result = intr_reg & 0xf0;
ldn = intr_reg & 0x0f;
/* get the last_scsi_command here */
- lastSCSI = last_scsi_command(ihost_index)[ldn];
- outb(IM_EOI | ldn, IM_ATTN_REG(ihost_index));
+ lastSCSI = last_scsi_command(shpnt)[ldn];
+ outb(IM_EOI | ldn, IM_ATTN_REG(shpnt));
/*these should never happen (hw fails, or a local programming bug) */
if (!global_command_error_excuse) {
@@ -547,38 +553,38 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
case IM_SOFTWARE_SEQUENCING_ERROR:
case IM_CMD_ERROR:
printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n");
- printk(KERN_ERR " Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(ihost_index)[ldn].scb.enable);
- if (ld(ihost_index)[ldn].cmd)
- printk("%ld/%ld,", (long) (ld(ihost_index)[ldn].cmd->request_bufflen), (long) (ld(ihost_index)[ldn].scb.sys_buf_length));
+ printk(KERN_ERR " Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(shpnt)[ldn].scb.enable);
+ if (ld(shpnt)[ldn].cmd)
+ printk("%ld/%ld,", (long) (scsi_bufflen(ld(shpnt)[ldn].cmd)), (long) (ld(shpnt)[ldn].scb.sys_buf_length));
else
printk("none,");
- if (ld(ihost_index)[ldn].cmd)
- printk("Blocksize=%d", ld(ihost_index)[ldn].scb.u2.blk.length);
+ if (ld(shpnt)[ldn].cmd)
+ printk("Blocksize=%d", ld(shpnt)[ldn].scb.u2.blk.length);
else
printk("Blocksize=none");
- printk(", host=0x%x, ldn=0x%x\n", ihost_index, ldn);
- if (ld(ihost_index)[ldn].cmd) {
- printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u2.blk.count);
- printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u1.log_blk_adr);
+ printk(", host=%p, ldn=0x%x\n", shpnt, ldn);
+ if (ld(shpnt)[ldn].cmd) {
+ printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(shpnt)[ldn], ld(shpnt)[ldn].scb.u2.blk.count);
+ printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(shpnt)[ldn], ld(shpnt)[ldn].scb.u1.log_blk_adr);
}
printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
/* if errors appear, enter this section to give detailed info */
printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n");
- printk(KERN_ERR " Command Type................: %x\n", last_scsi_type(ihost_index)[ldn]);
- printk(KERN_ERR " Attention Register..........: %x\n", inb(IM_ATTN_REG(ihost_index)));
- printk(KERN_ERR " Basic Control Register......: %x\n", inb(IM_CTR_REG(ihost_index)));
+ printk(KERN_ERR " Command Type................: %x\n", last_scsi_type(shpnt)[ldn]);
+ printk(KERN_ERR " Attention Register..........: %x\n", inb(IM_ATTN_REG(shpnt)));
+ printk(KERN_ERR " Basic Control Register......: %x\n", inb(IM_CTR_REG(shpnt)));
printk(KERN_ERR " Interrupt Status Register...: %x\n", intr_reg);
- printk(KERN_ERR " Basic Status Register.......: %x\n", inb(IM_STAT_REG(ihost_index)));
- if ((last_scsi_type(ihost_index)[ldn] == IM_SCB) || (last_scsi_type(ihost_index)[ldn] == IM_LONG_SCB)) {
- printk(KERN_ERR " SCB-Command.................: %x\n", ld(ihost_index)[ldn].scb.command);
- printk(KERN_ERR " SCB-Enable..................: %x\n", ld(ihost_index)[ldn].scb.enable);
- printk(KERN_ERR " SCB-logical block address...: %lx\n", ld(ihost_index)[ldn].scb.u1.log_blk_adr);
- printk(KERN_ERR " SCB-system buffer address...: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_adr);
- printk(KERN_ERR " SCB-system buffer length....: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_length);
- printk(KERN_ERR " SCB-tsb address.............: %lx\n", ld(ihost_index)[ldn].scb.tsb_adr);
- printk(KERN_ERR " SCB-Chain address...........: %lx\n", ld(ihost_index)[ldn].scb.scb_chain_adr);
- printk(KERN_ERR " SCB-block count.............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.count);
- printk(KERN_ERR " SCB-block length............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.length);
+ printk(KERN_ERR " Basic Status Register.......: %x\n", inb(IM_STAT_REG(shpnt)));
+ if ((last_scsi_type(shpnt)[ldn] == IM_SCB) || (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB)) {
+ printk(KERN_ERR " SCB-Command.................: %x\n", ld(shpnt)[ldn].scb.command);
+ printk(KERN_ERR " SCB-Enable..................: %x\n", ld(shpnt)[ldn].scb.enable);
+ printk(KERN_ERR " SCB-logical block address...: %lx\n", ld(shpnt)[ldn].scb.u1.log_blk_adr);
+ printk(KERN_ERR " SCB-system buffer address...: %lx\n", ld(shpnt)[ldn].scb.sys_buf_adr);
+ printk(KERN_ERR " SCB-system buffer length....: %lx\n", ld(shpnt)[ldn].scb.sys_buf_length);
+ printk(KERN_ERR " SCB-tsb address.............: %lx\n", ld(shpnt)[ldn].scb.tsb_adr);
+ printk(KERN_ERR " SCB-Chain address...........: %lx\n", ld(shpnt)[ldn].scb.scb_chain_adr);
+ printk(KERN_ERR " SCB-block count.............: %x\n", ld(shpnt)[ldn].scb.u2.blk.count);
+ printk(KERN_ERR " SCB-block length............: %x\n", ld(shpnt)[ldn].scb.u2.blk.length);
}
printk(KERN_ERR " Send this report to the maintainer.\n");
panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result);
@@ -600,72 +606,73 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
}
}
/* if no panic appeared, increase the interrupt-counter */
- IBM_DS(ihost_index).total_interrupts++;
+ IBM_DS(shpnt).total_interrupts++;
/*only for local checking phase */
- if (local_checking_phase_flag(ihost_index)) {
- stat_result(ihost_index) = cmd_result;
- got_interrupt(ihost_index) = 1;
- reset_status(ihost_index) = IM_RESET_FINISHED_OK;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- spin_unlock(dev->host_lock);
+ if (local_checking_phase_flag(shpnt)) {
+ stat_result(shpnt) = cmd_result;
+ got_interrupt(shpnt) = 1;
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
/* handling of commands coming from upper level of scsi driver */
- if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) {
+ if (last_scsi_type(shpnt)[ldn] == IM_IMM_CMD) {
/* verify ldn, and may handle rare reset immediate command */
- if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS) && (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) {
+ if ((reset_status(shpnt) == IM_RESET_IN_PROGRESS) && (last_scsi_command(shpnt)[ldn] == IM_RESET_IMM_CMD)) {
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- reset_status(ihost_index) = IM_RESET_FINISHED_FAIL;
+ reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
} else {
/*reset disk led counter, turn off disk led */
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
}
- stat_result(ihost_index) = cmd_result;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- last_scsi_type(ihost_index)[ldn] = 0;
- spin_unlock(dev->host_lock);
+ stat_result(shpnt) = cmd_result;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ last_scsi_type(shpnt)[ldn] = 0;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
- } else if (last_scsi_command(ihost_index)[ldn] == IM_ABORT_IMM_CMD) {
+ } else if (last_scsi_command(shpnt)[ldn] == IM_ABORT_IMM_CMD) {
/* react on SCSI abort command */
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
#endif
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- cmd = ld(ihost_index)[ldn].cmd;
- ld(ihost_index)[ldn].cmd = NULL;
+ cmd = ld(shpnt)[ldn].cmd;
+ ld(shpnt)[ldn].cmd = NULL;
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
cmd->result = DID_NO_CONNECT << 16;
else
cmd->result = DID_ABORT << 16;
- stat_result(ihost_index) = cmd_result;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- last_scsi_type(ihost_index)[ldn] = 0;
+ stat_result(shpnt) = cmd_result;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ last_scsi_type(shpnt)[ldn] = 0;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd); /* should be the internal_done */
- spin_unlock(dev->host_lock);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
} else {
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
- reset_status(ihost_index) = IM_RESET_FINISHED_OK;
- stat_result(ihost_index) = cmd_result;
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- spin_unlock(dev->host_lock);
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
+ stat_result(shpnt) = cmd_result;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
}
- last_scsi_command(ihost_index)[ldn] = NO_SCSI;
- last_scsi_type(ihost_index)[ldn] = 0;
- cmd = ld(ihost_index)[ldn].cmd;
- ld(ihost_index)[ldn].cmd = NULL;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI;
+ last_scsi_type(shpnt)[ldn] = 0;
+ cmd = ld(shpnt)[ldn].cmd;
+ ld(shpnt)[ldn].cmd = NULL;
#ifdef IM_DEBUG_TIMEOUT
if (cmd) {
if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) {
+ spin_unlock_irqsave(shpnt->host_lock, flags);
printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->device->lun);
return IRQ_HANDLED;
}
@@ -674,15 +681,15 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
/*if no command structure, just return, else clear cmd */
if (!cmd)
{
- spin_unlock(dev->host_lock);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
#ifdef IM_DEBUG_INT
- printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(ihost_index)[ldn].tsb.dev_status, ld(ihost_index)[ldn].tsb.cmd_status, ld(ihost_index)[ldn].tsb.dev_error, ld(ihost_index)[ldn].tsb.cmd_error);
+ printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(shpnt)[ldn].tsb.dev_status, ld(shpnt)[ldn].tsb.cmd_status, ld(shpnt)[ldn].tsb.dev_error, ld(shpnt)[ldn].tsb.cmd_error);
#endif
/*if this is end of media read/write, may turn off PS/2 disk led */
- if ((ld(ihost_index)[ldn].device_type != TYPE_NO_LUN) && (ld(ihost_index)[ldn].device_type != TYPE_NO_DEVICE)) {
+ if ((ld(shpnt)[ldn].device_type != TYPE_NO_LUN) && (ld(shpnt)[ldn].device_type != TYPE_NO_DEVICE)) {
/* only access this, if there was a valid device addressed */
if (--disk_rw_in_progress == 0)
PS2_DISK_LED_OFF();
@@ -693,8 +700,8 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
* adapters do not support CMD_TERMINATED, TASK_SET_FULL and
* ACA_ACTIVE as returning statusbyte information. (ML) */
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
- cmd->result = (unsigned char) (ld(ihost_index)[ldn].tsb.dev_status & 0x1e);
- IBM_DS(ihost_index).total_errors++;
+ cmd->result = (unsigned char) (ld(shpnt)[ldn].tsb.dev_status & 0x1e);
+ IBM_DS(shpnt).total_errors++;
} else
cmd->result = 0;
/* write device status into cmd->result, and call done function */
@@ -705,24 +712,25 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id)
cmd->result |= DID_OK << 16;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd);
- spin_unlock(dev->host_lock);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
return IRQ_HANDLED;
}
-static void issue_cmd(int host_index, unsigned long cmd_reg, unsigned char attn_reg)
+static void issue_cmd(struct Scsi_Host *shpnt, unsigned long cmd_reg,
+ unsigned char attn_reg)
{
unsigned long flags;
/* must wait for attention reg not busy */
while (1) {
- spin_lock_irqsave(hosts[host_index]->host_lock, flags);
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ spin_lock_irqsave(shpnt->host_lock, flags);
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
- spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
}
/* write registers and enable system interrupts */
- outl(cmd_reg, IM_CMD_REG(host_index));
- outb(attn_reg, IM_ATTN_REG(host_index));
- spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
+ outl(cmd_reg, IM_CMD_REG(shpnt));
+ outb(attn_reg, IM_ATTN_REG(shpnt));
+ spin_unlock_irqrestore(shpnt->host_lock, flags);
}
static void internal_done(Scsi_Cmnd * cmd)
@@ -732,34 +740,34 @@ static void internal_done(Scsi_Cmnd * cmd)
}
/* SCSI-SCB-command for device_inquiry */
-static int device_inquiry(int host_index, int ldn)
+static int device_inquiry(struct Scsi_Host *shpnt, int ldn)
{
int retr;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
- scb = &(ld(host_index)[ldn].scb);
- tsb = &(ld(host_index)[ldn].tsb);
- buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
- ld(host_index)[ldn].tsb.dev_status = 0; /* prepare statusblock */
+ scb = &(ld(shpnt)[ldn].scb);
+ tsb = &(ld(shpnt)[ldn].tsb);
+ buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
+ ld(shpnt)[ldn].tsb.dev_status = 0; /* prepare statusblock */
for (retr = 0; retr < 3; retr++) {
/* fill scb with inquiry command */
scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_command(shpnt)[ldn] = IM_DEVICE_INQUIRY_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_SCB;
scb->sys_buf_adr = isa_virt_to_bus(buf);
scb->sys_buf_length = 255; /* maximum bufferlength gives max info */
scb->tsb_adr = isa_virt_to_bus(tsb);
/* issue scb to passed ldn, and busy wait for interrupt */
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
- while (!got_interrupt(host_index))
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
+ while (!got_interrupt(shpnt))
barrier();
/*if command successful, break */
- if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+ if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
/*if all three retries failed, return "no device at this ldn" */
@@ -769,34 +777,34 @@ static int device_inquiry(int host_index, int ldn)
return 1;
}
-static int read_capacity(int host_index, int ldn)
+static int read_capacity(struct Scsi_Host *shpnt, int ldn)
{
int retr;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
- scb = &(ld(host_index)[ldn].scb);
- tsb = &(ld(host_index)[ldn].tsb);
- buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
- ld(host_index)[ldn].tsb.dev_status = 0;
+ scb = &(ld(shpnt)[ldn].scb);
+ tsb = &(ld(shpnt)[ldn].tsb);
+ buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
+ ld(shpnt)[ldn].tsb.dev_status = 0;
for (retr = 0; retr < 3; retr++) {
/*fill scb with read capacity command */
scb->command = IM_READ_CAPACITY_CMD;
scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_command(shpnt)[ldn] = IM_READ_CAPACITY_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_SCB;
scb->sys_buf_adr = isa_virt_to_bus(buf);
scb->sys_buf_length = 8;
scb->tsb_adr = isa_virt_to_bus(tsb);
/*issue scb to passed ldn, and busy wait for interrupt */
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
- while (!got_interrupt(host_index))
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
+ while (!got_interrupt(shpnt))
barrier();
/*if got capacity, get block length and return one device found */
- if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+ if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
/*if all three retries failed, return "no device at this ldn" */
@@ -806,39 +814,39 @@ static int read_capacity(int host_index, int ldn)
return 1;
}
-static int get_pos_info(int host_index)
+static int get_pos_info(struct Scsi_Host *shpnt)
{
int retr;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
- scb = &(ld(host_index)[MAX_LOG_DEV].scb);
- tsb = &(ld(host_index)[MAX_LOG_DEV].tsb);
- buf = (unsigned char *) (&(ld(host_index)[MAX_LOG_DEV].buf));
- ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0;
+ scb = &(ld(shpnt)[MAX_LOG_DEV].scb);
+ tsb = &(ld(shpnt)[MAX_LOG_DEV].tsb);
+ buf = (unsigned char *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
+ ld(shpnt)[MAX_LOG_DEV].tsb.dev_status = 0;
for (retr = 0; retr < 3; retr++) {
/*fill scb with get_pos_info command */
scb->command = IM_GET_POS_INFO_CMD;
scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
- last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
- last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB;
+ last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
+ last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_SCB;
scb->sys_buf_adr = isa_virt_to_bus(buf);
- if (special(host_index) == IBM_SCSI2_FW)
+ if (special(shpnt) == IBM_SCSI2_FW)
scb->sys_buf_length = 256; /* get all info from F/W adapter */
else
scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */
scb->tsb_adr = isa_virt_to_bus(tsb);
/*issue scb to ldn=15, and busy wait for interrupt */
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
/* FIXME: timeout */
- while (!got_interrupt(host_index))
+ while (!got_interrupt(shpnt))
barrier();
/*if got POS-stuff, get block length and return one device found */
- if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+ if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
/* if all three retries failed, return "no device at this ldn" */
@@ -851,14 +859,16 @@ static int get_pos_info(int host_index)
/* SCSI-immediate-command for assign. This functions maps/unmaps specific
ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, unsigned int ldn, unsigned int operation)
+static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun,
+ unsigned int lun, unsigned int ldn,
+ unsigned int operation)
{
int retr;
unsigned long imm_cmd;
for (retr = 0; retr < 3; retr++) {
/* select mutation level of the SCSI-adapter */
- switch (special(host_index)) {
+ switch (special(shpnt)) {
case IBM_SCSI2_FW:
imm_cmd = (unsigned long) (IM_ASSIGN_IMM_CMD);
imm_cmd |= (unsigned long) ((lun & 7) << 24);
@@ -867,7 +877,7 @@ static int immediate_assign(int host_index, unsigned int pun, unsigned int lun,
imm_cmd |= (unsigned long) ((ldn & 15) << 16);
break;
default:
- imm_cmd = inl(IM_CMD_REG(host_index));
+ imm_cmd = inl(IM_CMD_REG(shpnt));
imm_cmd &= (unsigned long) (0xF8000000); /* keep reserved bits */
imm_cmd |= (unsigned long) (IM_ASSIGN_IMM_CMD);
imm_cmd |= (unsigned long) ((lun & 7) << 24);
@@ -876,15 +886,15 @@ static int immediate_assign(int host_index, unsigned int pun, unsigned int lun,
imm_cmd |= (unsigned long) ((ldn & 15) << 16);
break;
}
- last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
- last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
- got_interrupt(host_index) = 0;
- issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
- while (!got_interrupt(host_index))
+ last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
+ last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
+ got_interrupt(shpnt) = 0;
+ issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+ while (!got_interrupt(shpnt))
barrier();
/*if command successful, break */
- if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
if (retr >= 3)
@@ -893,7 +903,7 @@ static int immediate_assign(int host_index, unsigned int pun, unsigned int lun,
return 1;
}
-static int immediate_feature(int host_index, unsigned int speed, unsigned int timeout)
+static int immediate_feature(struct Scsi_Host *shpnt, unsigned int speed, unsigned int timeout)
{
int retr;
unsigned long imm_cmd;
@@ -903,16 +913,16 @@ static int immediate_feature(int host_index, unsigned int speed, unsigned int ti
imm_cmd = IM_FEATURE_CTR_IMM_CMD;
imm_cmd |= (unsigned long) ((speed & 0x7) << 29);
imm_cmd |= (unsigned long) ((timeout & 0x1fff) << 16);
- last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
- last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
- got_interrupt(host_index) = 0;
+ last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
+ last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD;
+ got_interrupt(shpnt) = 0;
/* we need to run into command errors in order to probe for the
* right speed! */
global_command_error_excuse = 1;
- issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+ issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
/* FIXME: timeout */
- while (!got_interrupt(host_index))
+ while (!got_interrupt(shpnt))
barrier();
if (global_command_error_excuse == CMD_FAIL) {
global_command_error_excuse = 0;
@@ -920,7 +930,7 @@ static int immediate_feature(int host_index, unsigned int speed, unsigned int ti
} else
global_command_error_excuse = 0;
/*if command successful, break */
- if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
if (retr >= 3)
@@ -930,35 +940,35 @@ static int immediate_feature(int host_index, unsigned int speed, unsigned int ti
}
#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-static int immediate_reset(int host_index, unsigned int ldn)
+static int immediate_reset(struct Scsi_Host *shpnt, unsigned int ldn)
{
int retries;
int ticks;
unsigned long imm_command;
for (retries = 0; retries < 3; retries++) {
- imm_command = inl(IM_CMD_REG(host_index));
+ imm_command = inl(IM_CMD_REG(shpnt));
imm_command &= (unsigned long) (0xFFFF0000); /* keep reserved bits */
imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
- last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD;
- last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
- got_interrupt(host_index) = 0;
- reset_status(host_index) = IM_RESET_IN_PROGRESS;
- issue_cmd(host_index, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
+ last_scsi_command(shpnt)[ldn] = IM_RESET_IMM_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
+ got_interrupt(shpnt) = 0;
+ reset_status(shpnt) = IM_RESET_IN_PROGRESS;
+ issue_cmd(shpnt, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
ticks = IM_RESET_DELAY * HZ;
- while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) {
+ while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks) {
udelay((1 + 999 / HZ) * 1000);
barrier();
}
/* if reset did not complete, just complain */
if (!ticks) {
printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
- reset_status(host_index) = IM_RESET_FINISHED_OK;
+ reset_status(shpnt) = IM_RESET_FINISHED_OK;
/* did not work, finish */
return 1;
}
/*if command successful, break */
- if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
if (retries >= 3)
@@ -1060,35 +1070,35 @@ static int probe_display(int what)
return 0;
}
-static int probe_bus_mode(int host_index)
+static int probe_bus_mode(struct Scsi_Host *shpnt)
{
struct im_pos_info *info;
int num_bus = 0;
int ldn;
- info = (struct im_pos_info *) (&(ld(host_index)[MAX_LOG_DEV].buf));
- if (get_pos_info(host_index)) {
+ info = (struct im_pos_info *) (&(ld(shpnt)[MAX_LOG_DEV].buf));
+ if (get_pos_info(shpnt)) {
if (info->connector_size & 0xf000)
- subsystem_connector_size(host_index) = 16;
+ subsystem_connector_size(shpnt) = 16;
else
- subsystem_connector_size(host_index) = 32;
+ subsystem_connector_size(shpnt) = 32;
num_bus |= (info->pos_4b & 8) >> 3;
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- if ((special(host_index) == IBM_SCSI_WCACHE) || (special(host_index) == IBM_7568_WCACHE)) {
+ if ((special(shpnt) == IBM_SCSI_WCACHE) || (special(shpnt) == IBM_7568_WCACHE)) {
if (!((info->cache_stat >> ldn) & 1))
- ld(host_index)[ldn].cache_flag = 0;
+ ld(shpnt)[ldn].cache_flag = 0;
}
if (!((info->retry_stat >> ldn) & 1))
- ld(host_index)[ldn].retry_flag = 0;
+ ld(shpnt)[ldn].retry_flag = 0;
}
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: SCSI-Cache bits: ");
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- printk("%d", ld(host_index)[ldn].cache_flag);
+ printk("%d", ld(shpnt)[ldn].cache_flag);
}
printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- printk("%d", ld(host_index)[ldn].retry_flag);
+ printk("%d", ld(shpnt)[ldn].retry_flag);
}
printk("\n");
#endif
@@ -1097,7 +1107,7 @@ static int probe_bus_mode(int host_index)
}
/* probing scsi devices */
-static void check_devices(int host_index, int adaptertype)
+static void check_devices(struct Scsi_Host *shpnt, int adaptertype)
{
int id, lun, ldn, ticks;
int count_devices; /* local counter for connected device */
@@ -1108,24 +1118,24 @@ static void check_devices(int host_index, int adaptertype)
/* assign default values to certain variables */
ticks = 0;
count_devices = 0;
- IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */
- IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */
- next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
+ IBM_DS(shpnt).dyn_flag = 0; /* normally no need for dynamical ldn management */
+ IBM_DS(shpnt).total_errors = 0; /* set errorcounter to 0 */
+ next_ldn(shpnt) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
/* initialize the very important driver-informational arrays/structs */
- memset(ld(host_index), 0, sizeof(ld(host_index)));
+ memset(ld(shpnt), 0, sizeof(ld(shpnt)));
for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
- last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
- last_scsi_type(host_index)[ldn] = 0;
- ld(host_index)[ldn].cache_flag = 1;
- ld(host_index)[ldn].retry_flag = 1;
+ last_scsi_command(shpnt)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
+ last_scsi_type(shpnt)[ldn] = 0;
+ ld(shpnt)[ldn].cache_flag = 1;
+ ld(shpnt)[ldn].retry_flag = 1;
}
- memset(get_ldn(host_index), TYPE_NO_DEVICE, sizeof(get_ldn(host_index))); /* this is essential ! */
- memset(get_scsi(host_index), TYPE_NO_DEVICE, sizeof(get_scsi(host_index))); /* this is essential ! */
+ memset(get_ldn(shpnt), TYPE_NO_DEVICE, sizeof(get_ldn(shpnt))); /* this is essential ! */
+ memset(get_scsi(shpnt), TYPE_NO_DEVICE, sizeof(get_scsi(shpnt))); /* this is essential ! */
for (lun = 0; lun < 8; lun++) {
/* mark the adapter at its pun on all luns */
- get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
- get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
+ get_scsi(shpnt)[subsystem_pun(shpnt)][lun] = TYPE_IBM_SCSI_ADAPTER;
+ get_ldn(shpnt)[subsystem_pun(shpnt)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
ldn is active for all
luns. */
}
@@ -1134,9 +1144,9 @@ static void check_devices(int host_index, int adaptertype)
/* monitor connected on model XX95. */
/* STEP 1: */
- adapter_speed(host_index) = global_adapter_speed;
- speedrun = adapter_speed(host_index);
- while (immediate_feature(host_index, speedrun, adapter_timeout) == 2) {
+ adapter_speed(shpnt) = global_adapter_speed;
+ speedrun = adapter_speed(shpnt);
+ while (immediate_feature(shpnt, speedrun, adapter_timeout) == 2) {
probe_display(1);
if (speedrun == 7)
panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
@@ -1144,30 +1154,30 @@ static void check_devices(int host_index, int adaptertype)
if (speedrun > 7)
speedrun = 7;
}
- adapter_speed(host_index) = speedrun;
+ adapter_speed(shpnt) = speedrun;
/* Get detailed information about the current adapter, necessary for
* device operations: */
- num_bus = probe_bus_mode(host_index);
+ num_bus = probe_bus_mode(shpnt);
/* num_bus contains only valid data for the F/W adapter! */
if (adaptertype == IBM_SCSI2_FW) { /* F/W SCSI adapter: */
/* F/W adapter PUN-space extension evaluation: */
if (num_bus) {
printk(KERN_INFO "IBM MCA SCSI: Separate bus mode (wide-addressing enabled)\n");
- subsystem_maxid(host_index) = 16;
+ subsystem_maxid(shpnt) = 16;
} else {
printk(KERN_INFO "IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
- subsystem_maxid(host_index) = 8;
+ subsystem_maxid(shpnt) = 8;
}
printk(KERN_INFO "IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", ibmrate(speedrun, adaptertype));
} else /* all other IBM SCSI adapters: */
printk(KERN_INFO "IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", ibmrate(speedrun, adaptertype));
/* assign correct PUN device space */
- max_pun = subsystem_maxid(host_index);
+ max_pun = subsystem_maxid(shpnt);
#ifdef IM_DEBUG_PROBE
- printk("IBM MCA SCSI: Current SCSI-host index: %d\n", host_index);
+ printk("IBM MCA SCSI: Current SCSI-host index: %d\n", shpnt);
printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
#else
printk(KERN_INFO "IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", (ibm_ansi_order) ? "ANSI" : "New");
@@ -1177,7 +1187,7 @@ static void check_devices(int host_index, int adaptertype)
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
- immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN); /* remove ldn (wherever) */
+ immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN); /* remove ldn (wherever) */
}
lun = 0; /* default lun is 0 */
#ifndef IM_DEBUG_PROBE
@@ -1196,18 +1206,18 @@ static void check_devices(int host_index, int adaptertype)
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
- if (id != subsystem_pun(host_index)) {
+ if (id != subsystem_pun(shpnt)) {
/* if pun is not the adapter: */
/* set ldn=0 to pun,lun */
- immediate_assign(host_index, id, lun, PROBE_LDN, SET_LDN);
- if (device_inquiry(host_index, PROBE_LDN)) { /* probe device */
- get_scsi(host_index)[id][lun] = (unsigned char) (ld(host_index)[PROBE_LDN].buf[0]);
+ immediate_assign(shpnt, id, lun, PROBE_LDN, SET_LDN);
+ if (device_inquiry(shpnt, PROBE_LDN)) { /* probe device */
+ get_scsi(shpnt)[id][lun] = (unsigned char) (ld(shpnt)[PROBE_LDN].buf[0]);
/* entry, even for NO_LUN */
- if (ld(host_index)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
+ if (ld(shpnt)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
count_devices++; /* a existing device is found */
}
/* remove ldn */
- immediate_assign(host_index, id, lun, PROBE_LDN, REMOVE_LDN);
+ immediate_assign(shpnt, id, lun, PROBE_LDN, REMOVE_LDN);
}
}
#ifndef IM_DEBUG_PROBE
@@ -1227,16 +1237,16 @@ static void check_devices(int host_index, int adaptertype)
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
- if (id != subsystem_pun(host_index)) {
- if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN && get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE) {
+ if (id != subsystem_pun(shpnt)) {
+ if (get_scsi(shpnt)[id][lun] != TYPE_NO_LUN && get_scsi(shpnt)[id][lun] != TYPE_NO_DEVICE) {
/* Only map if accepted type. Always enter for
lun == 0 to get no gaps into ldn-mapping for ldn<7. */
- immediate_assign(host_index, id, lun, ldn, SET_LDN);
- get_ldn(host_index)[id][lun] = ldn; /* map ldn */
- if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
+ immediate_assign(shpnt, id, lun, ldn, SET_LDN);
+ get_ldn(shpnt)[id][lun] = ldn; /* map ldn */
+ if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
printk("resetting device at ldn=%x ... ", ldn);
- immediate_reset(host_index, ldn);
+ immediate_reset(shpnt, ldn);
#endif
ldn++;
} else {
@@ -1244,15 +1254,15 @@ static void check_devices(int host_index, int adaptertype)
* handle it or because it has problems */
if (lun > 0) {
/* remove mapping */
- get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
- immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN);
+ get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
+ immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN);
} else
ldn++;
}
} else if (lun == 0) {
/* map lun == 0, even if no device exists */
- immediate_assign(host_index, id, lun, ldn, SET_LDN);
- get_ldn(host_index)[id][lun] = ldn; /* map ldn */
+ immediate_assign(shpnt, id, lun, ldn, SET_LDN);
+ get_ldn(shpnt)[id][lun] = ldn; /* map ldn */
ldn++;
}
}
@@ -1262,14 +1272,14 @@ static void check_devices(int host_index, int adaptertype)
/* map remaining ldns to non-existing devices */
for (lun = 1; lun < 8 && ldn < MAX_LOG_DEV; lun++)
for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
- if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN || get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE) {
+ if (get_scsi(shpnt)[id][lun] == TYPE_NO_LUN || get_scsi(shpnt)[id][lun] == TYPE_NO_DEVICE) {
probe_display(1);
/* Map remaining ldns only to NON-existing pun,lun
combinations to make sure an inquiry will fail.
For MULTI_LUN, it is needed to avoid adapter autonome
SCSI-remapping. */
- immediate_assign(host_index, id, lun, ldn, SET_LDN);
- get_ldn(host_index)[id][lun] = ldn;
+ immediate_assign(shpnt, id, lun, ldn, SET_LDN);
+ get_ldn(shpnt)[id][lun] = ldn;
ldn++;
}
}
@@ -1292,51 +1302,51 @@ static void check_devices(int host_index, int adaptertype)
for (id = 0; id < max_pun; id++) {
printk("%2d ", id);
for (lun = 0; lun < 8; lun++)
- printk("%2s ", ti_p(get_scsi(host_index)[id][lun]));
+ printk("%2s ", ti_p(get_scsi(shpnt)[id][lun]));
printk(" %2d ", id);
for (lun = 0; lun < 8; lun++)
- printk("%2s ", ti_l(get_ldn(host_index)[id][lun]));
+ printk("%2s ", ti_l(get_ldn(shpnt)[id][lun]));
printk("\n");
}
#endif
/* assign total number of found SCSI-devices to the statistics struct */
- IBM_DS(host_index).total_scsi_devices = count_devices;
+ IBM_DS(shpnt).total_scsi_devices = count_devices;
/* decide for output in /proc-filesystem, if the configuration of
SCSI-devices makes dynamical reassignment of devices necessary */
if (count_devices >= MAX_LOG_DEV)
- IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */
+ IBM_DS(shpnt).dyn_flag = 1; /* dynamical assignment is necessary */
else
- IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */
+ IBM_DS(shpnt).dyn_flag = 0; /* dynamical assignment is not necessary */
/* If no SCSI-devices are assigned, return 1 in order to cause message. */
if (ldn == 0)
printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
/* reset the counters for statistics on the current adapter */
- IBM_DS(host_index).scbs = 0;
- IBM_DS(host_index).long_scbs = 0;
- IBM_DS(host_index).total_accesses = 0;
- IBM_DS(host_index).total_interrupts = 0;
- IBM_DS(host_index).dynamical_assignments = 0;
- memset(IBM_DS(host_index).ldn_access, 0x0, sizeof(IBM_DS(host_index).ldn_access));
- memset(IBM_DS(host_index).ldn_read_access, 0x0, sizeof(IBM_DS(host_index).ldn_read_access));
- memset(IBM_DS(host_index).ldn_write_access, 0x0, sizeof(IBM_DS(host_index).ldn_write_access));
- memset(IBM_DS(host_index).ldn_inquiry_access, 0x0, sizeof(IBM_DS(host_index).ldn_inquiry_access));
- memset(IBM_DS(host_index).ldn_modeselect_access, 0x0, sizeof(IBM_DS(host_index).ldn_modeselect_access));
- memset(IBM_DS(host_index).ldn_assignments, 0x0, sizeof(IBM_DS(host_index).ldn_assignments));
+ IBM_DS(shpnt).scbs = 0;
+ IBM_DS(shpnt).long_scbs = 0;
+ IBM_DS(shpnt).total_accesses = 0;
+ IBM_DS(shpnt).total_interrupts = 0;
+ IBM_DS(shpnt).dynamical_assignments = 0;
+ memset(IBM_DS(shpnt).ldn_access, 0x0, sizeof(IBM_DS(shpnt).ldn_access));
+ memset(IBM_DS(shpnt).ldn_read_access, 0x0, sizeof(IBM_DS(shpnt).ldn_read_access));
+ memset(IBM_DS(shpnt).ldn_write_access, 0x0, sizeof(IBM_DS(shpnt).ldn_write_access));
+ memset(IBM_DS(shpnt).ldn_inquiry_access, 0x0, sizeof(IBM_DS(shpnt).ldn_inquiry_access));
+ memset(IBM_DS(shpnt).ldn_modeselect_access, 0x0, sizeof(IBM_DS(shpnt).ldn_modeselect_access));
+ memset(IBM_DS(shpnt).ldn_assignments, 0x0, sizeof(IBM_DS(shpnt).ldn_assignments));
probe_display(0);
return;
}
-static int device_exists(int host_index, int ldn, int *block_length, int *device_type)
+static int device_exists(struct Scsi_Host *shpnt, int ldn, int *block_length, int *device_type)
{
unsigned char *buf;
/* if no valid device found, return immediately with 0 */
- if (!(device_inquiry(host_index, ldn)))
+ if (!(device_inquiry(shpnt, ldn)))
return 0;
- buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+ buf = (unsigned char *) (&(ld(shpnt)[ldn].buf));
if (*buf == TYPE_ROM) {
*device_type = TYPE_ROM;
*block_length = 2048; /* (standard blocksize for yellow-/red-book) */
@@ -1349,7 +1359,7 @@ static int device_exists(int host_index, int ldn, int *block_length, int *device
}
if (*buf == TYPE_DISK) {
*device_type = TYPE_DISK;
- if (read_capacity(host_index, ldn)) {
+ if (read_capacity(shpnt, ldn)) {
*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
return 1;
} else
@@ -1357,7 +1367,7 @@ static int device_exists(int host_index, int ldn, int *block_length, int *device
}
if (*buf == TYPE_MOD) {
*device_type = TYPE_MOD;
- if (read_capacity(host_index, ldn)) {
+ if (read_capacity(shpnt, ldn)) {
*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
return 1;
} else
@@ -1430,6 +1440,9 @@ static void internal_ibmmca_scsi_setup(char *str, int *ints)
return;
}
+#if 0
+ FIXME NEED TO MOVE TO SYSFS
+
static int ibmmca_getinfo(char *buf, int slot, void *dev_id)
{
struct Scsi_Host *shpnt;
@@ -1480,58 +1493,34 @@ static int ibmmca_getinfo(char *buf, int slot, void *dev_id)
return len;
}
+#endif
-int ibmmca_detect(struct scsi_host_template * scsi_template)
+static struct scsi_host_template ibmmca_driver_template = {
+ .proc_name = "ibmmca",
+ .proc_info = ibmmca_proc_info,
+ .name = "IBM SCSI-Subsystem",
+ .queuecommand = ibmmca_queuecommand,
+ .eh_abort_handler = ibmmca_abort,
+ .eh_host_reset_handler = ibmmca_host_reset,
+ .bios_param = ibmmca_biosparam,
+ .can_queue = 16,
+ .this_id = 7,
+ .sg_tablesize = 16,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+static int ibmmca_probe(struct device *dev)
{
struct Scsi_Host *shpnt;
- int port, id, i, j, k, slot;
- int devices_on_irq_11 = 0;
- int devices_on_irq_14 = 0;
- int IRQ14_registered = 0;
- int IRQ11_registered = 0;
-
- found = 0; /* make absolutely sure, that found is set to 0 */
+ int port, id, i, j, k, irq, enabled, ret = -EINVAL;
+ struct mca_device *mca_dev = to_mca_device(dev);
+ const char *description = ibmmca_description[mca_dev->index];
/* First of all, print the version number of the driver. This is
* important to allow better user bugreports in case of already
* having problems with the MCA_bus probing. */
printk(KERN_INFO "IBM MCA SCSI: Version %s\n", IBMMCA_SCSI_DRIVER_VERSION);
- /* if this is not MCA machine, return "nothing found" */
- if (!MCA_bus) {
- printk(KERN_INFO "IBM MCA SCSI: No Microchannel-bus present --> Aborting.\n" " This machine does not have any IBM MCA-bus\n" " or the MCA-Kernel-support is not enabled!\n");
- return 0;
- }
-
-#ifdef MODULE
- /* If the driver is run as module, read from conf.modules or cmd-line */
- if (boot_options)
- option_setup(boot_options);
-#endif
-
- /* get interrupt request level */
- if (request_irq(IM_IRQ, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
- printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
- return 0;
- } else
- IRQ14_registered++;
-
- /* if ibmmcascsi setup option was passed to kernel, return "found" */
- for (i = 0; i < IM_MAX_HOSTS; i++)
- if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) {
- printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n", io_port[i], scsi_id[i]);
- if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i], FORCED_DETECTION, "forced detected SCSI Adapter"))) {
- for (k = 2; k < 7; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = 0;
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = FORCED_DETECTION;
- mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
- mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(MCA_INTEGSCSI);
- devices_on_irq_14++;
- }
- }
- if (found)
- return found;
-
/* The POS2-register of all PS/2 model SCSI-subsystems has the following
* interpretation of bits:
* Bit 7 - 4 : Chip Revision ID (Release)
@@ -1558,7 +1547,14 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
/* first look for the IBM SCSI integrated subsystem on the motherboard */
for (j = 0; j < 8; j++) /* read the pos-information */
- pos[j] = mca_read_stored_pos(MCA_INTEGSCSI, j);
+ pos[j] = mca_device_read_pos(mca_dev, j);
+ id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
+ enabled = (pos[2] &0x01);
+ if (!enabled) {
+ printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+ printk(KERN_WARNING " SCSI-operations may not work.\n");
+ }
+
/* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but
* if we ignore the settings of all surrounding pos registers, it is not
* completely sufficient to only check pos2 and pos3. */
@@ -1566,232 +1562,137 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
* make sure, we see a real integrated onboard SCSI-interface and no
* internal system information, which gets mapped to some pos registers
* on models 95xx. */
- if ((!pos[0] && !pos[1] && pos[2] > 0 && pos[3] > 0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) || (pos[0] == 0xff && pos[1] == 0xff && pos[2] < 0xff && pos[3] < 0xff && pos[4] == 0xff && pos[5] == 0xff && pos[6] == 0xff && pos[7] == 0xff)) {
- if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
- port = IM_IO_PORT;
- else { /* if disabled, no IRQs will be generated, as the chip won't
- * listen to the incoming commands and will do really nothing,
- * except for listening to the pos-register settings. If this
- * happens, I need to hugely think about it, as one has to
- * write something to the MCA-Bus pos register in order to
- * enable the chip. Normally, IBM-SCSI won't pass the POST,
- * when the chip is disabled (see IBM tech. ref.). */
- port = IM_IO_PORT; /* anyway, set the portnumber and warn */
- printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n" " SCSI-operations may not work.\n");
+ if (mca_dev->slot == MCA_INTEGSCSI &&
+ ((!pos[0] && !pos[1] && pos[2] > 0 &&
+ pos[3] > 0 && !pos[4] && !pos[5] &&
+ !pos[6] && !pos[7]) ||
+ (pos[0] == 0xff && pos[1] == 0xff &&
+ pos[2] < 0xff && pos[3] < 0xff &&
+ pos[4] == 0xff && pos[5] == 0xff &&
+ pos[6] == 0xff && pos[7] == 0xff))) {
+ irq = IM_IRQ;
+ port = IM_IO_PORT;
+ } else {
+ irq = IM_IRQ;
+ port = IM_IO_PORT + ((pos[2] &0x0e) << 2);
+ if ((mca_dev->index == IBM_SCSI2_FW) && (pos[6] != 0)) {
+ printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+ printk(KERN_ERR " Impossible to determine adapter PUN!\n");
+ printk(KERN_ERR " Guessing adapter PUN = 7.\n");
+ id = 7;
+ } else {
+ id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+ if (mca_dev->index == IBM_SCSI2_FW) {
+ id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
+ * for F/W adapters */
+ }
}
- id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
- /* give detailed information on the subsystem. This helps me
- * additionally during debugging and analyzing bug-reports. */
- printk(KERN_INFO "IBM MCA SCSI: IBM Integrated SCSI Controller ffound, io=0x%x, scsi id=%d,\n", port, id);
- printk(KERN_INFO " chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled.");
-
- /* register the found integrated SCSI-subsystem */
- if ((shpnt = ibmmca_register(scsi_template, port, id, INTEGRATED_SCSI, "IBM Integrated SCSI Controller")))
- {
- for (k = 2; k < 7; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
- mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
- mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(MCA_INTEGSCSI);
- devices_on_irq_14++;
+ if ((mca_dev->index == IBM_SCSI2_FW) &&
+ (pos[4] & 0x01) && (pos[6] == 0)) {
+ /* IRQ11 is used by SCSI-2 F/W Adapter/A */
+ printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+ irq = IM_IRQ_FW;
}
}
- /* now look for other adapters in MCA slots, */
- /* determine the number of known IBM-SCSI-subsystem types */
- /* see the pos[2] dependence to get the adapter port-offset. */
- for (i = 0; i < ARRAY_SIZE(subsys_list); i++) {
- /* scan each slot for a fitting adapter id */
- slot = 0; /* start at slot 0 */
- while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
- != MCA_NOTFOUND) { /* scan through all slots */
- for (j = 0; j < 8; j++) /* read the pos-information */
- pos[j] = mca_read_stored_pos(slot, j);
- if ((pos[2] & 1) == 1)
- /* is the subsystem chip enabled ? */
- /* (explanations see above) */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- else {
- /* anyway, set the portnumber and warn */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
- printk(KERN_WARNING " SCSI-operations may not work.\n");
- }
- if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
- printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
- printk(KERN_ERR " Impossible to determine adapter PUN!\n");
- printk(KERN_ERR " Guessing adapter PUN = 7.\n");
- id = 7;
- } else {
- id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
- if (i == IBM_SCSI2_FW) {
- id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
- * for F/W adapters */
- }
- }
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
- /* IRQ11 is used by SCSI-2 F/W Adapter/A */
- printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
- /* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
- printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
- } else
- IRQ11_registered++;
- }
- printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
- if ((pos[2] & 0xf0) == 0xf0)
- printk(KERN_DEBUG" ROM Addr.=off,");
- else
- printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
- printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
-
- /* register the hostadapter */
- if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
- for (k = 2; k < 8; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
- mca_set_adapter_name(slot, subsys_list[i].description);
- mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(slot);
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
- devices_on_irq_11++;
- else
- devices_on_irq_14++;
- }
- slot++; /* advance to next slot */
- } /* advance to next adapter id in the list of IBM-SCSI-subsystems */
- }
- /* now check for SCSI-adapters, mapped to the integrated SCSI
- * area. E.g. a W/Cache in MCA-slot 9(!). Do the check correct here,
- * as this is a known effect on some models 95xx. */
- for (i = 0; i < ARRAY_SIZE(subsys_list); i++) {
- /* scan each slot for a fitting adapter id */
- slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI);
- if (slot != MCA_NOTFOUND) { /* scan through all slots */
- for (j = 0; j < 8; j++) /* read the pos-information */
- pos[j] = mca_read_stored_pos(slot, j);
- if ((pos[2] & 1) == 1) { /* is the subsystem chip enabled ? */
- /* (explanations see above) */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- } else { /* anyway, set the portnumber and warn */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
- printk(KERN_WARNING " SCSI-operations may not work.\n");
- }
- if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
- printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
- printk(KERN_ERR " Impossible to determine adapter PUN!\n");
- printk(KERN_ERR " Guessing adapter PUN = 7.\n");
- id = 7;
- } else {
- id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
- if (i == IBM_SCSI2_FW)
- id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
- * for F/W adapters */
- }
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
- /* IRQ11 is used by SCSI-2 F/W Adapter/A */
- printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
- /* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts))
- printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
- else
- IRQ11_registered++;
- }
- printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
- if ((pos[2] & 0xf0) == 0xf0)
- printk(KERN_DEBUG " ROM Addr.=off,");
- else
- printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
- printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
-
- /* register the hostadapter */
- if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
- for (k = 2; k < 7; k++)
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
- ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
- mca_set_adapter_name(slot, subsys_list[i].description);
- mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
- mca_mark_as_used(slot);
- if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
- devices_on_irq_11++;
- else
- devices_on_irq_14++;
- }
- slot++; /* advance to next slot */
- } /* advance to next adapter id in the list of IBM-SCSI-subsystems */
- }
- if (IRQ11_registered && !devices_on_irq_11)
- free_irq(IM_IRQ_FW, hosts); /* no devices on IRQ 11 */
- if (IRQ14_registered && !devices_on_irq_14)
- free_irq(IM_IRQ, hosts); /* no devices on IRQ 14 */
- if (!devices_on_irq_11 && !devices_on_irq_14)
- printk(KERN_WARNING "IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
- return found; /* return the number of found SCSI hosts. Should be 1 or 0. */
-}
-static struct Scsi_Host *ibmmca_register(struct scsi_host_template * scsi_template, int port, int id, int adaptertype, char *hostname)
-{
- struct Scsi_Host *shpnt;
- int i, j;
- unsigned int ctrl;
+ /* give detailed information on the subsystem. This helps me
+ * additionally during debugging and analyzing bug-reports. */
+ printk(KERN_INFO "IBM MCA SCSI: %s found, io=0x%x, scsi id=%d,\n",
+ description, port, id);
+ if (mca_dev->slot == MCA_INTEGSCSI)
+ printk(KERN_INFO " chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled.");
+ else {
+ if ((pos[2] & 0xf0) == 0xf0)
+ printk(KERN_DEBUG " ROM Addr.=off,");
+ else
+ printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
+
+ printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
+ }
/* check I/O region */
- if (!request_region(port, IM_N_IO_PORT, hostname)) {
+ if (!request_region(port, IM_N_IO_PORT, description)) {
printk(KERN_ERR "IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
- return NULL;
+ goto out_fail;
}
/* register host */
- shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
+ shpnt = scsi_host_alloc(&ibmmca_driver_template,
+ sizeof(struct ibmmca_hostdata));
if (!shpnt) {
printk(KERN_ERR "IBM MCA SCSI: Unable to register host.\n");
- release_region(port, IM_N_IO_PORT);
- return NULL;
+ goto out_release;
+ }
+
+ dev_set_drvdata(dev, shpnt);
+ if(request_irq(irq, interrupt_handler, IRQF_SHARED, description, dev)) {
+ printk(KERN_ERR "IBM MCA SCSI: failed to request interrupt %d\n", irq);
+ goto out_free_host;
}
/* request I/O region */
- hosts[found] = shpnt; /* add new found hostadapter to the list */
- special(found) = adaptertype; /* important assignment or else crash! */
- subsystem_connector_size(found) = 0; /* preset slot-size */
- shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */
+ special(shpnt) = mca_dev->index; /* important assignment or else crash! */
+ subsystem_connector_size(shpnt) = 0; /* preset slot-size */
+ shpnt->irq = irq; /* assign necessary stuff for the adapter */
shpnt->io_port = port;
shpnt->n_io_port = IM_N_IO_PORT;
shpnt->this_id = id;
shpnt->max_id = 8; /* 8 PUNs are default */
/* now, the SCSI-subsystem is connected to Linux */
- ctrl = (unsigned int) (inb(IM_CTR_REG(found))); /* get control-register status */
#ifdef IM_DEBUG_PROBE
+ ctrl = (unsigned int) (inb(IM_CTR_REG(found))); /* get control-register status */
printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", ctrl, inb(IM_STAT_REG(found)));
printk("IBM MCA SCSI: This adapters' POS-registers: ");
for (i = 0; i < 8; i++)
printk("%x ", pos[i]);
printk("\n");
#endif
- reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
+ reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS;
for (i = 0; i < 16; i++) /* reset the tables */
for (j = 0; j < 8; j++)
- get_ldn(found)[i][j] = MAX_LOG_DEV;
+ get_ldn(shpnt)[i][j] = MAX_LOG_DEV;
/* check which logical devices exist */
/* after this line, local interrupting is possible: */
- local_checking_phase_flag(found) = 1;
- check_devices(found, adaptertype); /* call by value, using the global variable hosts */
- local_checking_phase_flag(found) = 0;
- found++; /* now increase index to be prepared for next found subsystem */
+ local_checking_phase_flag(shpnt) = 1;
+ check_devices(shpnt, mca_dev->index); /* call by value, using the global variable hosts */
+ local_checking_phase_flag(shpnt) = 0;
+
/* an ibm mca subsystem has been detected */
- return shpnt;
+
+ for (k = 2; k < 7; k++)
+ ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+ ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
+ mca_device_set_name(mca_dev, description);
+ /* FIXME: NEED TO REPLUMB TO SYSFS
+ mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+ */
+ mca_device_set_claim(mca_dev, 1);
+ if (scsi_add_host(shpnt, dev)) {
+ dev_printk(KERN_ERR, dev, "IBM MCA SCSI: scsi_add_host failed\n");
+ goto out_free_host;
+ }
+ scsi_scan_host(shpnt);
+
+ return 0;
+ out_free_host:
+ scsi_host_put(shpnt);
+ out_release:
+ release_region(port, IM_N_IO_PORT);
+ out_fail:
+ return ret;
}
-static int ibmmca_release(struct Scsi_Host *shpnt)
+static int __devexit ibmmca_remove(struct device *dev)
{
+ struct Scsi_Host *shpnt = dev_get_drvdata(dev);
+ scsi_remove_host(shpnt);
release_region(shpnt->io_port, shpnt->n_io_port);
- if (!(--found))
- free_irq(shpnt->irq, hosts);
+ free_irq(shpnt->irq, dev);
return 0;
}
@@ -1805,33 +1706,24 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
int current_ldn;
int id, lun;
int target;
- int host_index;
int max_pun;
int i;
- struct scatterlist *sl;
+ struct scatterlist *sg;
shpnt = cmd->device->host;
- /* search for the right hostadapter */
- for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
- if (!hosts[host_index]) { /* invalid hostadapter descriptor address */
- cmd->result = DID_NO_CONNECT << 16;
- if (done)
- done(cmd);
- return 0;
- }
- max_pun = subsystem_maxid(host_index);
+ max_pun = subsystem_maxid(shpnt);
if (ibm_ansi_order) {
target = max_pun - 1 - cmd->device->id;
- if ((target <= subsystem_pun(host_index)) && (cmd->device->id <= subsystem_pun(host_index)))
+ if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
target--;
- else if ((target >= subsystem_pun(host_index)) && (cmd->device->id >= subsystem_pun(host_index)))
+ else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
target++;
} else
target = cmd->device->id;
/* if (target,lun) is NO LUN or not existing at all, return error */
- if ((get_scsi(host_index)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(host_index)[target][cmd->device->lun] == TYPE_NO_DEVICE)) {
+ if ((get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_DEVICE)) {
cmd->result = DID_NO_CONNECT << 16;
if (done)
done(cmd);
@@ -1839,16 +1731,16 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
}
/*if (target,lun) unassigned, do further checks... */
- ldn = get_ldn(host_index)[target][cmd->device->lun];
+ ldn = get_ldn(shpnt)[target][cmd->device->lun];
if (ldn >= MAX_LOG_DEV) { /* on invalid ldn do special stuff */
if (ldn > MAX_LOG_DEV) { /* dynamical remapping if ldn unassigned */
- current_ldn = next_ldn(host_index); /* stop-value for one circle */
- while (ld(host_index)[next_ldn(host_index)].cmd) { /* search for a occupied, but not in */
+ current_ldn = next_ldn(shpnt); /* stop-value for one circle */
+ while (ld(shpnt)[next_ldn(shpnt)].cmd) { /* search for a occupied, but not in */
/* command-processing ldn. */
- next_ldn(host_index)++;
- if (next_ldn(host_index) >= MAX_LOG_DEV)
- next_ldn(host_index) = 7;
- if (current_ldn == next_ldn(host_index)) { /* One circle done ? */
+ next_ldn(shpnt)++;
+ if (next_ldn(shpnt) >= MAX_LOG_DEV)
+ next_ldn(shpnt) = 7;
+ if (current_ldn == next_ldn(shpnt)) { /* One circle done ? */
/* no non-processing ldn found */
scmd_printk(KERN_WARNING, cmd,
"IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n"
@@ -1864,56 +1756,56 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
/* unmap non-processing ldn */
for (id = 0; id < max_pun; id++)
for (lun = 0; lun < 8; lun++) {
- if (get_ldn(host_index)[id][lun] == next_ldn(host_index)) {
- get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
- get_scsi(host_index)[id][lun] = TYPE_NO_DEVICE;
+ if (get_ldn(shpnt)[id][lun] == next_ldn(shpnt)) {
+ get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE;
+ get_scsi(shpnt)[id][lun] = TYPE_NO_DEVICE;
/* unmap entry */
}
}
/* set reduced interrupt_handler-mode for checking */
- local_checking_phase_flag(host_index) = 1;
+ local_checking_phase_flag(shpnt) = 1;
/* map found ldn to pun,lun */
- get_ldn(host_index)[target][cmd->device->lun] = next_ldn(host_index);
+ get_ldn(shpnt)[target][cmd->device->lun] = next_ldn(shpnt);
/* change ldn to the right value, that is now next_ldn */
- ldn = next_ldn(host_index);
+ ldn = next_ldn(shpnt);
/* unassign all ldns (pun,lun,ldn does not matter for remove) */
- immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+ immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
/* set only LDN for remapped device */
- immediate_assign(host_index, target, cmd->device->lun, ldn, SET_LDN);
+ immediate_assign(shpnt, target, cmd->device->lun, ldn, SET_LDN);
/* get device information for ld[ldn] */
- if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
- ld(host_index)[ldn].cmd = NULL; /* To prevent panic set 0, because
+ if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) {
+ ld(shpnt)[ldn].cmd = NULL; /* To prevent panic set 0, because
devices that were not assigned,
should have nothing in progress. */
- get_scsi(host_index)[target][cmd->device->lun] = ld(host_index)[ldn].device_type;
+ get_scsi(shpnt)[target][cmd->device->lun] = ld(shpnt)[ldn].device_type;
/* increase assignment counters for statistics in /proc */
- IBM_DS(host_index).dynamical_assignments++;
- IBM_DS(host_index).ldn_assignments[ldn]++;
+ IBM_DS(shpnt).dynamical_assignments++;
+ IBM_DS(shpnt).ldn_assignments[ldn]++;
} else
/* panic here, because a device, found at boottime has
vanished */
panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", ldn, target, cmd->device->lun);
/* unassign again all ldns (pun,lun,ldn does not matter for remove) */
- immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+ immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN);
/* remap all ldns, as written in the pun/lun table */
lun = 0;
#ifdef CONFIG_SCSI_MULTI_LUN
for (lun = 0; lun < 8; lun++)
#endif
for (id = 0; id < max_pun; id++) {
- if (get_ldn(host_index)[id][lun] <= MAX_LOG_DEV)
- immediate_assign(host_index, id, lun, get_ldn(host_index)[id][lun], SET_LDN);
+ if (get_ldn(shpnt)[id][lun] <= MAX_LOG_DEV)
+ immediate_assign(shpnt, id, lun, get_ldn(shpnt)[id][lun], SET_LDN);
}
/* set back to normal interrupt_handling */
- local_checking_phase_flag(host_index) = 0;
+ local_checking_phase_flag(shpnt) = 0;
#ifdef IM_DEBUG_PROBE
/* Information on syslog terminal */
printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", ldn, target, cmd->device->lun);
#endif
/* increase next_ldn for next dynamical assignment */
- next_ldn(host_index)++;
- if (next_ldn(host_index) >= MAX_LOG_DEV)
- next_ldn(host_index) = 7;
+ next_ldn(shpnt)++;
+ if (next_ldn(shpnt) >= MAX_LOG_DEV)
+ next_ldn(shpnt) = 7;
} else { /* wall against Linux accesses to the subsystem adapter */
cmd->result = DID_BAD_TARGET << 16;
if (done)
@@ -1923,34 +1815,32 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
}
/*verify there is no command already in progress for this log dev */
- if (ld(host_index)[ldn].cmd)
+ if (ld(shpnt)[ldn].cmd)
panic("IBM MCA SCSI: cmd already in progress for this ldn.\n");
/*save done in cmd, and save cmd for the interrupt handler */
cmd->scsi_done = done;
- ld(host_index)[ldn].cmd = cmd;
+ ld(shpnt)[ldn].cmd = cmd;
/*fill scb information independent of the scsi command */
- scb = &(ld(host_index)[ldn].scb);
- ld(host_index)[ldn].tsb.dev_status = 0;
+ scb = &(ld(shpnt)[ldn].scb);
+ ld(shpnt)[ldn].tsb.dev_status = 0;
scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
- scb->tsb_adr = isa_virt_to_bus(&(ld(host_index)[ldn].tsb));
+ scb->tsb_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].tsb));
scsi_cmd = cmd->cmnd[0];
- if (cmd->use_sg) {
- i = cmd->use_sg;
- sl = (struct scatterlist *) (cmd->request_buffer);
- if (i > 16)
- panic("IBM MCA SCSI: scatter-gather list too long.\n");
- while (--i >= 0) {
- ld(host_index)[ldn].sge[i].address = (void *) (isa_page_to_bus(sl[i].page) + sl[i].offset);
- ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
+ if (scsi_sg_count(cmd)) {
+ BUG_ON(scsi_sg_count(cmd) > 16);
+
+ scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
+ ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg->page) + sg->offset);
+ ld(shpnt)[ldn].sge[i].byte_length = sg->length;
}
scb->enable |= IM_POINTER_TO_LIST;
- scb->sys_buf_adr = isa_virt_to_bus(&(ld(host_index)[ldn].sge[0]));
- scb->sys_buf_length = cmd->use_sg * sizeof(struct im_sge);
+ scb->sys_buf_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].sge[0]));
+ scb->sys_buf_length = scsi_sg_count(cmd) * sizeof(struct im_sge);
} else {
- scb->sys_buf_adr = isa_virt_to_bus(cmd->request_buffer);
+ scb->sys_buf_adr = isa_virt_to_bus(scsi_sglist(cmd));
/* recent Linux midlevel SCSI places 1024 byte for inquiry
* command. Far too much for old PS/2 hardware. */
switch (scsi_cmd) {
@@ -1961,16 +1851,16 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
case REQUEST_SENSE:
case MODE_SENSE:
case MODE_SELECT:
- if (cmd->request_bufflen > 255)
+ if (scsi_bufflen(cmd) > 255)
scb->sys_buf_length = 255;
else
- scb->sys_buf_length = cmd->request_bufflen;
+ scb->sys_buf_length = scsi_bufflen(cmd);
break;
case TEST_UNIT_READY:
scb->sys_buf_length = 0;
break;
default:
- scb->sys_buf_length = cmd->request_bufflen;
+ scb->sys_buf_length = scsi_bufflen(cmd);
break;
}
}
@@ -1982,16 +1872,16 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
/* for specific device-type debugging: */
#ifdef IM_DEBUG_CMD_SPEC_DEV
- if (ld(host_index)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
- printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(host_index)[ldn].device_type, scsi_cmd, ldn);
+ if (ld(shpnt)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
+ printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(shpnt)[ldn].device_type, scsi_cmd, ldn);
#endif
/* for possible panics store current command */
- last_scsi_command(host_index)[ldn] = scsi_cmd;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_command(shpnt)[ldn] = scsi_cmd;
+ last_scsi_type(shpnt)[ldn] = IM_SCB;
/* update statistical info */
- IBM_DS(host_index).total_accesses++;
- IBM_DS(host_index).ldn_access[ldn]++;
+ IBM_DS(shpnt).total_accesses++;
+ IBM_DS(shpnt).ldn_access[ldn]++;
switch (scsi_cmd) {
case READ_6:
@@ -2003,17 +1893,17 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
/* Distinguish between disk and other devices. Only disks (that are the
most frequently accessed devices) should be supported by the
IBM-SCSI-Subsystem commands. */
- switch (ld(host_index)[ldn].device_type) {
+ switch (ld(shpnt)[ldn].device_type) {
case TYPE_DISK: /* for harddisks enter here ... */
case TYPE_MOD: /* ... try it also for MO-drives (send flames as */
/* you like, if this won't work.) */
if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) {
/* read command preparations */
scb->enable |= IM_READ_CONTROL;
- IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
+ IBM_DS(shpnt).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
} else { /* write command preparations */
- IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat. */
+ IBM_DS(shpnt).ldn_write_access[ldn]++; /* increase write-count on ldn stat. */
scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
}
if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) {
@@ -2023,9 +1913,9 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | (((unsigned) cmd->cmnd[4]) << 8) | (((unsigned) cmd->cmnd[3]) << 16) | (((unsigned) cmd->cmnd[2]) << 24);
scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | (((unsigned) cmd->cmnd[7]) << 8);
}
- last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr;
- last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count;
- scb->u2.blk.length = ld(host_index)[ldn].block_length;
+ last_scsi_logical_block(shpnt)[ldn] = scb->u1.log_blk_adr;
+ last_scsi_blockcount(shpnt)[ldn] = scb->u2.blk.count;
+ scb->u2.blk.length = ld(shpnt)[ldn].block_length;
break;
/* for other devices, enter here. Other types are not known by
Linux! TYPE_NO_LUN is forbidden as valid device. */
@@ -2046,14 +1936,14 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
scb->enable |= IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
/* Read/write on this non-disk devices is also displayworthy,
so flash-up the LED/display. */
break;
}
break;
case INQUIRY:
- IBM_DS(host_index).ldn_inquiry_access[ldn]++;
+ IBM_DS(shpnt).ldn_inquiry_access[ldn]++;
scb->command = IM_DEVICE_INQUIRY_CMD;
scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.log_blk_adr = 0;
@@ -2064,7 +1954,7 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
scb->u1.log_blk_adr = 0;
scb->u1.scsi_cmd_length = 6;
memcpy(scb->u2.scsi_command, cmd->cmnd, 6);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
break;
case READ_CAPACITY:
/* the length of system memory buffer must be exactly 8 bytes */
@@ -2081,12 +1971,12 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
/* Commands that need write-only-mode (system -> device): */
case MODE_SELECT:
case MODE_SELECT_10:
- IBM_DS(host_index).ldn_modeselect_access[ldn]++;
+ IBM_DS(shpnt).ldn_modeselect_access[ldn]++;
scb->command = IM_OTHER_SCSI_CMD_CMD;
scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled */
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
break;
/* For other commands, read-only is useful. Most other commands are
running without an input-data-block. */
@@ -2095,19 +1985,19 @@ static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
- last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ last_scsi_type(shpnt)[ldn] = IM_LONG_SCB;
break;
}
/*issue scb command, and return */
if (++disk_rw_in_progress == 1)
PS2_DISK_LED_ON(shpnt->host_no, target);
- if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB) {
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
- IBM_DS(host_index).long_scbs++;
+ if (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB) {
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
+ IBM_DS(shpnt).long_scbs++;
} else {
- issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
- IBM_DS(host_index).scbs++;
+ issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn);
+ IBM_DS(shpnt).scbs++;
}
return 0;
}
@@ -2122,7 +2012,6 @@ static int __ibmmca_abort(Scsi_Cmnd * cmd)
unsigned int ldn;
void (*saved_done) (Scsi_Cmnd *);
int target;
- int host_index;
int max_pun;
unsigned long imm_command;
@@ -2131,35 +2020,23 @@ static int __ibmmca_abort(Scsi_Cmnd * cmd)
#endif
shpnt = cmd->device->host;
- /* search for the right hostadapter */
- for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
- if (!hosts[host_index]) { /* invalid hostadapter descriptor address */
- cmd->result = DID_NO_CONNECT << 16;
- if (cmd->scsi_done)
- (cmd->scsi_done) (cmd);
- shpnt = cmd->device->host;
-#ifdef IM_DEBUG_PROBE
- printk(KERN_DEBUG "IBM MCA SCSI: Abort adapter selection failed!\n");
-#endif
- return SUCCESS;
- }
- max_pun = subsystem_maxid(host_index);
+ max_pun = subsystem_maxid(shpnt);
if (ibm_ansi_order) {
target = max_pun - 1 - cmd->device->id;
- if ((target <= subsystem_pun(host_index)) && (cmd->device->id <= subsystem_pun(host_index)))
+ if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt)))
target--;
- else if ((target >= subsystem_pun(host_index)) && (cmd->device->id >= subsystem_pun(host_index)))
+ else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt)))
target++;
} else
target = cmd->device->id;
/* get logical device number, and disable system interrupts */
printk(KERN_WARNING "IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", target, cmd->device->lun);
- ldn = get_ldn(host_index)[target][cmd->device->lun];
+ ldn = get_ldn(shpnt)[target][cmd->device->lun];
/*if cmd for this ldn has already finished, no need to abort */
- if (!ld(host_index)[ldn].cmd) {
+ if (!ld(shpnt)[ldn].cmd) {
return SUCCESS;
}
@@ -2170,20 +2047,20 @@ static int __ibmmca_abort(Scsi_Cmnd * cmd)
saved_done = cmd->scsi_done;
cmd->scsi_done = internal_done;
cmd->SCp.Status = 0;
- last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD;
- last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
- imm_command = inl(IM_CMD_REG(host_index));
+ last_scsi_command(shpnt)[ldn] = IM_ABORT_IMM_CMD;
+ last_scsi_type(shpnt)[ldn] = IM_IMM_CMD;
+ imm_command = inl(IM_CMD_REG(shpnt));
imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */
imm_command |= (unsigned long) (IM_ABORT_IMM_CMD);
/* must wait for attention reg not busy */
/* FIXME - timeout, politeness */
while (1) {
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
}
/* write registers and enable system interrupts */
- outl(imm_command, IM_CMD_REG(host_index));
- outb(IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
+ outl(imm_command, IM_CMD_REG(shpnt));
+ outb(IM_IMM_CMD | ldn, IM_ATTN_REG(shpnt));
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort queued to adapter...\n");
#endif
@@ -2202,7 +2079,7 @@ static int __ibmmca_abort(Scsi_Cmnd * cmd)
cmd->result |= DID_ABORT << 16;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd);
- ld(host_index)[ldn].cmd = NULL;
+ ld(shpnt)[ldn].cmd = NULL;
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort finished with success.\n");
#endif
@@ -2211,7 +2088,7 @@ static int __ibmmca_abort(Scsi_Cmnd * cmd)
cmd->result |= DID_NO_CONNECT << 16;
if (cmd->scsi_done)
(cmd->scsi_done) (cmd);
- ld(host_index)[ldn].cmd = NULL;
+ ld(shpnt)[ldn].cmd = NULL;
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort failed.\n");
#endif
@@ -2236,71 +2113,65 @@ static int __ibmmca_host_reset(Scsi_Cmnd * cmd)
struct Scsi_Host *shpnt;
Scsi_Cmnd *cmd_aid;
int ticks, i;
- int host_index;
unsigned long imm_command;
BUG_ON(cmd == NULL);
ticks = IM_RESET_DELAY * HZ;
shpnt = cmd->device->host;
- /* search for the right hostadapter */
- for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
-
- if (!hosts[host_index]) /* invalid hostadapter descriptor address */
- return FAILED;
- if (local_checking_phase_flag(host_index)) {
+ if (local_checking_phase_flag(shpnt)) {
printk(KERN_WARNING "IBM MCA SCSI: unable to reset while checking devices.\n");
return FAILED;
}
/* issue reset immediate command to subsystem, and wait for interrupt */
printk("IBM MCA SCSI: resetting all devices.\n");
- reset_status(host_index) = IM_RESET_IN_PROGRESS;
- last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD;
- last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
- imm_command = inl(IM_CMD_REG(host_index));
+ reset_status(shpnt) = IM_RESET_IN_PROGRESS;
+ last_scsi_command(shpnt)[0xf] = IM_RESET_IMM_CMD;
+ last_scsi_type(shpnt)[0xf] = IM_IMM_CMD;
+ imm_command = inl(IM_CMD_REG(shpnt));
imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */
imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
/* must wait for attention reg not busy */
while (1) {
- if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+ if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY))
break;
spin_unlock_irq(shpnt->host_lock);
yield();
spin_lock_irq(shpnt->host_lock);
}
/*write registers and enable system interrupts */
- outl(imm_command, IM_CMD_REG(host_index));
- outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index));
+ outl(imm_command, IM_CMD_REG(shpnt));
+ outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(shpnt));
/* wait for interrupt finished or intr_stat register to be set, as the
* interrupt will not be executed, while we are in here! */
/* FIXME: This is really really icky we so want a sleeping version of this ! */
- while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(host_index)) & 0x8f) != 0x8f)) {
+ while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(shpnt)) & 0x8f) != 0x8f)) {
udelay((1 + 999 / HZ) * 1000);
barrier();
}
/* if reset did not complete, just return an error */
if (!ticks) {
printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
- reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+ reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
return FAILED;
}
- if ((inb(IM_INTR_REG(host_index)) & 0x8f) == 0x8f) {
+ if ((inb(IM_INTR_REG(shpnt)) & 0x8f) == 0x8f) {
/* analysis done by this routine and not by the intr-routine */
- if (inb(IM_INTR_REG(host_index)) == 0xaf)
- reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT;
- else if (inb(IM_INTR_REG(host_index)) == 0xcf)
- reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+ if (inb(IM_INTR_REG(shpnt)) == 0xaf)
+ reset_status(shpnt) = IM_RESET_FINISHED_OK_NO_INT;
+ else if (inb(IM_INTR_REG(shpnt)) == 0xcf)
+ reset_status(shpnt) = IM_RESET_FINISHED_FAIL;
else /* failed, 4get it */
- reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
- outb(IM_EOI | 0xf, IM_ATTN_REG(host_index));
+ reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
+ outb(IM_EOI | 0xf, IM_ATTN_REG(shpnt));
}
/* if reset failed, just return an error */
- if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
+ if (reset_status(shpnt) == IM_RESET_FINISHED_FAIL) {
printk(KERN_ERR "IBM MCA SCSI: reset failed.\n");
return FAILED;
}
@@ -2308,9 +2179,9 @@ static int __ibmmca_host_reset(Scsi_Cmnd * cmd)
/* so reset finished ok - call outstanding done's, and return success */
printk(KERN_INFO "IBM MCA SCSI: Reset successfully completed.\n");
for (i = 0; i < MAX_LOG_DEV; i++) {
- cmd_aid = ld(host_index)[i].cmd;
+ cmd_aid = ld(shpnt)[i].cmd;
if (cmd_aid && cmd_aid->scsi_done) {
- ld(host_index)[i].cmd = NULL;
+ ld(shpnt)[i].cmd = NULL;
cmd_aid->result = DID_RESET << 16;
}
}
@@ -2351,46 +2222,46 @@ static int ibmmca_biosparam(struct scsi_device *sdev, struct block_device *bdev,
}
/* calculate percentage of total accesses on a ldn */
-static int ldn_access_load(int host_index, int ldn)
+static int ldn_access_load(struct Scsi_Host *shpnt, int ldn)
{
- if (IBM_DS(host_index).total_accesses == 0)
+ if (IBM_DS(shpnt).total_accesses == 0)
return (0);
- if (IBM_DS(host_index).ldn_access[ldn] == 0)
+ if (IBM_DS(shpnt).ldn_access[ldn] == 0)
return (0);
- return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses;
+ return (IBM_DS(shpnt).ldn_access[ldn] * 100) / IBM_DS(shpnt).total_accesses;
}
/* calculate total amount of r/w-accesses */
-static int ldn_access_total_read_write(int host_index)
+static int ldn_access_total_read_write(struct Scsi_Host *shpnt)
{
int a;
int i;
a = 0;
for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(host_index).ldn_read_access[i] + IBM_DS(host_index).ldn_write_access[i];
+ a += IBM_DS(shpnt).ldn_read_access[i] + IBM_DS(shpnt).ldn_write_access[i];
return (a);
}
-static int ldn_access_total_inquiry(int host_index)
+static int ldn_access_total_inquiry(struct Scsi_Host *shpnt)
{
int a;
int i;
a = 0;
for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(host_index).ldn_inquiry_access[i];
+ a += IBM_DS(shpnt).ldn_inquiry_access[i];
return (a);
}
-static int ldn_access_total_modeselect(int host_index)
+static int ldn_access_total_modeselect(struct Scsi_Host *shpnt)
{
int a;
int i;
a = 0;
for (i = 0; i <= MAX_LOG_DEV; i++)
- a += IBM_DS(host_index).ldn_modeselect_access[i];
+ a += IBM_DS(shpnt).ldn_modeselect_access[i];
return (a);
}
@@ -2398,19 +2269,14 @@ static int ldn_access_total_modeselect(int host_index)
static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
{
int len = 0;
- int i, id, lun, host_index;
+ int i, id, lun;
unsigned long flags;
int max_pun;
- for (i = 0; hosts[i] && hosts[i] != shpnt; i++);
- spin_lock_irqsave(hosts[i]->host_lock, flags); /* Check it */
- host_index = i;
- if (!shpnt) {
- len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter");
- return len;
- }
- max_pun = subsystem_maxid(host_index);
+ spin_lock_irqsave(shpnt->host_lock, flags); /* Check it */
+
+ max_pun = subsystem_maxid(shpnt);
len += sprintf(buffer + len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION);
len += sprintf(buffer + len, " SCSI Access-Statistics:\n");
@@ -2421,40 +2287,40 @@ static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start,
len += sprintf(buffer + len, " Multiple LUN probing.....: No\n");
#endif
len += sprintf(buffer + len, " This Hostnumber..........: %d\n", shpnt->host_no);
- len += sprintf(buffer + len, " Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(host_index)));
+ len += sprintf(buffer + len, " Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(shpnt)));
len += sprintf(buffer + len, " (Shared) IRQ.............: %d\n", IM_IRQ);
- len += sprintf(buffer + len, " Total Interrupts.........: %d\n", IBM_DS(host_index).total_interrupts);
- len += sprintf(buffer + len, " Total SCSI Accesses......: %d\n", IBM_DS(host_index).total_accesses);
- len += sprintf(buffer + len, " Total short SCBs.........: %d\n", IBM_DS(host_index).scbs);
- len += sprintf(buffer + len, " Total long SCBs..........: %d\n", IBM_DS(host_index).long_scbs);
- len += sprintf(buffer + len, " Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(host_index));
- len += sprintf(buffer + len, " Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(host_index));
- len += sprintf(buffer + len, " Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(host_index));
- len += sprintf(buffer + len, " Total SCSI other cmds..: %d\n", IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index)
- - ldn_access_total_modeselect(host_index)
- - ldn_access_total_inquiry(host_index));
- len += sprintf(buffer + len, " Total SCSI command fails.: %d\n\n", IBM_DS(host_index).total_errors);
+ len += sprintf(buffer + len, " Total Interrupts.........: %d\n", IBM_DS(shpnt).total_interrupts);
+ len += sprintf(buffer + len, " Total SCSI Accesses......: %d\n", IBM_DS(shpnt).total_accesses);
+ len += sprintf(buffer + len, " Total short SCBs.........: %d\n", IBM_DS(shpnt).scbs);
+ len += sprintf(buffer + len, " Total long SCBs..........: %d\n", IBM_DS(shpnt).long_scbs);
+ len += sprintf(buffer + len, " Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(shpnt));
+ len += sprintf(buffer + len, " Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(shpnt));
+ len += sprintf(buffer + len, " Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(shpnt));
+ len += sprintf(buffer + len, " Total SCSI other cmds..: %d\n", IBM_DS(shpnt).total_accesses - ldn_access_total_read_write(shpnt)
+ - ldn_access_total_modeselect(shpnt)
+ - ldn_access_total_inquiry(shpnt));
+ len += sprintf(buffer + len, " Total SCSI command fails.: %d\n\n", IBM_DS(shpnt).total_errors);
len += sprintf(buffer + len, " Logical-Device-Number (LDN) Access-Statistics:\n");
len += sprintf(buffer + len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n");
len += sprintf(buffer + len, " -----|--------------|-----------|-----------|--------------\n");
for (i = 0; i <= MAX_LOG_DEV; i++)
- len += sprintf(buffer + len, " %2X | %3d | %8d | %8d | %8d\n", i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i], IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
+ len += sprintf(buffer + len, " %2X | %3d | %8d | %8d | %8d\n", i, ldn_access_load(shpnt, i), IBM_DS(shpnt).ldn_read_access[i], IBM_DS(shpnt).ldn_write_access[i], IBM_DS(shpnt).ldn_assignments[i]);
len += sprintf(buffer + len, " -----------------------------------------------------------\n\n");
len += sprintf(buffer + len, " Dynamical-LDN-Assignment-Statistics:\n");
- len += sprintf(buffer + len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(host_index).total_scsi_devices);
- len += sprintf(buffer + len, " Dynamical Assignment necessary...: %s\n", IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
- len += sprintf(buffer + len, " Next LDN to be assigned..........: 0x%x\n", next_ldn(host_index));
- len += sprintf(buffer + len, " Dynamical assignments done yet...: %d\n", IBM_DS(host_index).dynamical_assignments);
+ len += sprintf(buffer + len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(shpnt).total_scsi_devices);
+ len += sprintf(buffer + len, " Dynamical Assignment necessary...: %s\n", IBM_DS(shpnt).dyn_flag ? "Yes" : "No ");
+ len += sprintf(buffer + len, " Next LDN to be assigned..........: 0x%x\n", next_ldn(shpnt));
+ len += sprintf(buffer + len, " Dynamical assignments done yet...: %d\n", IBM_DS(shpnt).dynamical_assignments);
len += sprintf(buffer + len, "\n Current SCSI-Device-Mapping:\n");
len += sprintf(buffer + len, " Physical SCSI-Device Map Logical SCSI-Device Map\n");
len += sprintf(buffer + len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n");
for (id = 0; id < max_pun; id++) {
len += sprintf(buffer + len, " %2d ", id);
for (lun = 0; lun < 8; lun++)
- len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(host_index)[id][lun]));
+ len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(shpnt)[id][lun]));
len += sprintf(buffer + len, " %2d ", id);
for (lun = 0; lun < 8; lun++)
- len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(host_index)[id][lun]));
+ len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(shpnt)[id][lun]));
len += sprintf(buffer + len, "\n");
}
@@ -2488,20 +2354,31 @@ static int option_setup(char *str)
__setup("ibmmcascsi=", option_setup);
-static struct scsi_host_template driver_template = {
- .proc_name = "ibmmca",
- .proc_info = ibmmca_proc_info,
- .name = "IBM SCSI-Subsystem",
- .detect = ibmmca_detect,
- .release = ibmmca_release,
- .queuecommand = ibmmca_queuecommand,
- .eh_abort_handler = ibmmca_abort,
- .eh_host_reset_handler = ibmmca_host_reset,
- .bios_param = ibmmca_biosparam,
- .can_queue = 16,
- .this_id = 7,
- .sg_tablesize = 16,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
+static struct mca_driver ibmmca_driver = {
+ .id_table = ibmmca_id_table,
+ .driver = {
+ .name = "ibmmca",
+ .bus = &mca_bus_type,
+ .probe = ibmmca_probe,
+ .remove = __devexit_p(ibmmca_remove),
+ },
};
-#include "scsi_module.c"
+
+static int __init ibmmca_init(void)
+{
+#ifdef MODULE
+ /* If the driver is run as module, read from conf.modules or cmd-line */
+ if (boot_options)
+ option_setup(boot_options);
+#endif
+
+ return mca_register_driver_integrated(&ibmmca_driver, MCA_INTEGSCSI);
+}
+
+static void __exit ibmmca_exit(void)
+{
+ mca_unregister_driver(&ibmmca_driver);
+}
+
+module_init(ibmmca_init);
+module_exit(ibmmca_exit);
diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
deleted file mode 100644
index 017ee2fa6d63..000000000000
--- a/drivers/scsi/ibmmca.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Low Level Driver for the IBM Microchannel SCSI Subsystem
- * (Headerfile, see Documentation/scsi/ibmmca.txt for description of the
- * IBM MCA SCSI-driver.
- * For use under the GNU General Public License within the Linux-kernel project.
- * This include file works only correctly with kernel 2.4.0 or higher!!! */
-
-#ifndef _IBMMCA_H
-#define _IBMMCA_H
-
-/* Common forward declarations for all Linux-versions: */
-
-/* Interfaces to the midlevel Linux SCSI driver */
-static int ibmmca_detect (struct scsi_host_template *);
-static int ibmmca_release (struct Scsi_Host *);
-static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int ibmmca_abort (Scsi_Cmnd *);
-static int ibmmca_host_reset (Scsi_Cmnd *);
-static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
-
-#endif /* _IBMMCA_H */
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index b10eefe735c5..5870866abc99 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -173,9 +173,8 @@ static void release_event_pool(struct event_pool *pool,
}
}
if (in_use)
- printk(KERN_WARNING
- "ibmvscsi: releasing event pool with %d "
- "events still in use?\n", in_use);
+ dev_warn(hostdata->dev, "releasing event pool with %d "
+ "events still in use?\n", in_use);
kfree(pool->events);
dma_free_coherent(hostdata->dev,
pool->size * sizeof(*pool->iu_storage),
@@ -210,15 +209,13 @@ static void free_event_struct(struct event_pool *pool,
struct srp_event_struct *evt)
{
if (!valid_event_struct(pool, evt)) {
- printk(KERN_ERR
- "ibmvscsi: Freeing invalid event_struct %p "
- "(not in pool %p)\n", evt, pool->events);
+ dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p "
+ "(not in pool %p)\n", evt, pool->events);
return;
}
if (atomic_inc_return(&evt->free) != 1) {
- printk(KERN_ERR
- "ibmvscsi: Freeing event_struct %p "
- "which is not in use!\n", evt);
+ dev_err(evt->hostdata->dev, "Freeing event_struct %p "
+ "which is not in use!\n", evt);
return;
}
}
@@ -353,20 +350,19 @@ static void unmap_cmd_data(struct srp_cmd *cmd,
}
}
-static int map_sg_list(int num_entries,
- struct scatterlist *sg,
+static int map_sg_list(struct scsi_cmnd *cmd, int nseg,
struct srp_direct_buf *md)
{
int i;
+ struct scatterlist *sg;
u64 total_length = 0;
- for (i = 0; i < num_entries; ++i) {
+ scsi_for_each_sg(cmd, sg, nseg, i) {
struct srp_direct_buf *descr = md + i;
- struct scatterlist *sg_entry = &sg[i];
- descr->va = sg_dma_address(sg_entry);
- descr->len = sg_dma_len(sg_entry);
+ descr->va = sg_dma_address(sg);
+ descr->len = sg_dma_len(sg);
descr->key = 0;
- total_length += sg_dma_len(sg_entry);
+ total_length += sg_dma_len(sg);
}
return total_length;
}
@@ -387,40 +383,37 @@ static int map_sg_data(struct scsi_cmnd *cmd,
int sg_mapped;
u64 total_length = 0;
- struct scatterlist *sg = cmd->request_buffer;
struct srp_direct_buf *data =
(struct srp_direct_buf *) srp_cmd->add_data;
struct srp_indirect_buf *indirect =
(struct srp_indirect_buf *) data;
- sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL);
-
- if (sg_mapped == 0)
+ sg_mapped = scsi_dma_map(cmd);
+ if (!sg_mapped)
+ return 1;
+ else if (sg_mapped < 0)
return 0;
+ else if (sg_mapped > SG_ALL) {
+ printk(KERN_ERR
+ "ibmvscsi: More than %d mapped sg entries, got %d\n",
+ SG_ALL, sg_mapped);
+ return 0;
+ }
set_srp_direction(cmd, srp_cmd, sg_mapped);
/* special case; we can use a single direct descriptor */
if (sg_mapped == 1) {
- data->va = sg_dma_address(&sg[0]);
- data->len = sg_dma_len(&sg[0]);
- data->key = 0;
+ map_sg_list(cmd, sg_mapped, data);
return 1;
}
- if (sg_mapped > SG_ALL) {
- printk(KERN_ERR
- "ibmvscsi: More than %d mapped sg entries, got %d\n",
- SG_ALL, sg_mapped);
- return 0;
- }
-
indirect->table_desc.va = 0;
indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf);
indirect->table_desc.key = 0;
if (sg_mapped <= MAX_INDIRECT_BUFS) {
- total_length = map_sg_list(sg_mapped, sg,
+ total_length = map_sg_list(cmd, sg_mapped,
&indirect->desc_list[0]);
indirect->len = total_length;
return 1;
@@ -429,61 +422,27 @@ static int map_sg_data(struct scsi_cmnd *cmd,
/* get indirect table */
if (!evt_struct->ext_list) {
evt_struct->ext_list = (struct srp_direct_buf *)
- dma_alloc_coherent(dev,
+ dma_alloc_coherent(dev,
SG_ALL * sizeof(struct srp_direct_buf),
&evt_struct->ext_list_token, 0);
if (!evt_struct->ext_list) {
- printk(KERN_ERR
- "ibmvscsi: Can't allocate memory for indirect table\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "Can't allocate memory for indirect table\n");
return 0;
-
}
}
- total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list);
+ total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
indirect->len = total_length;
indirect->table_desc.va = evt_struct->ext_list_token;
indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]);
memcpy(indirect->desc_list, evt_struct->ext_list,
MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
-
return 1;
}
/**
- * map_single_data: - Maps memory and initializes memory decriptor fields
- * @cmd: struct scsi_cmnd with the memory to be mapped
- * @srp_cmd: srp_cmd that contains the memory descriptor
- * @dev: device for which to map dma memory
- *
- * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
- * Returns 1 on success.
-*/
-static int map_single_data(struct scsi_cmnd *cmd,
- struct srp_cmd *srp_cmd, struct device *dev)
-{
- struct srp_direct_buf *data =
- (struct srp_direct_buf *) srp_cmd->add_data;
-
- data->va =
- dma_map_single(dev, cmd->request_buffer,
- cmd->request_bufflen,
- DMA_BIDIRECTIONAL);
- if (dma_mapping_error(data->va)) {
- printk(KERN_ERR
- "ibmvscsi: Unable to map request_buffer for command!\n");
- return 0;
- }
- data->len = cmd->request_bufflen;
- data->key = 0;
-
- set_srp_direction(cmd, srp_cmd, 1);
-
- return 1;
-}
-
-/**
* map_data_for_srp_cmd: - Calls functions to map data for srp cmds
* @cmd: struct scsi_cmnd with the memory to be mapped
* @srp_cmd: srp_cmd that contains the memory descriptor
@@ -503,23 +462,83 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
case DMA_NONE:
return 1;
case DMA_BIDIRECTIONAL:
- printk(KERN_ERR
- "ibmvscsi: Can't map DMA_BIDIRECTIONAL to read/write\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "Can't map DMA_BIDIRECTIONAL to read/write\n");
return 0;
default:
- printk(KERN_ERR
- "ibmvscsi: Unknown data direction 0x%02x; can't map!\n",
- cmd->sc_data_direction);
+ sdev_printk(KERN_ERR, cmd->device,
+ "Unknown data direction 0x%02x; can't map!\n",
+ cmd->sc_data_direction);
return 0;
}
- if (!cmd->request_buffer)
- return 1;
- if (cmd->use_sg)
- return map_sg_data(cmd, evt_struct, srp_cmd, dev);
- return map_single_data(cmd, srp_cmd, dev);
+ return map_sg_data(cmd, evt_struct, srp_cmd, dev);
}
+/**
+ * purge_requests: Our virtual adapter just shut down. purge any sent requests
+ * @hostdata: the adapter
+ */
+static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+{
+ struct srp_event_struct *tmp_evt, *pos;
+ unsigned long flags;
+
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+ list_del(&tmp_evt->list);
+ del_timer(&tmp_evt->timer);
+ if (tmp_evt->cmnd) {
+ tmp_evt->cmnd->result = (error_code << 16);
+ unmap_cmd_data(&tmp_evt->iu.srp.cmd,
+ tmp_evt,
+ tmp_evt->hostdata->dev);
+ if (tmp_evt->cmnd_done)
+ tmp_evt->cmnd_done(tmp_evt->cmnd);
+ } else if (tmp_evt->done)
+ tmp_evt->done(tmp_evt);
+ free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+ }
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_reset_host - Reset the connection to the server
+ * @hostdata: struct ibmvscsi_host_data to reset
+*/
+static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata)
+{
+ scsi_block_requests(hostdata->host);
+ atomic_set(&hostdata->request_limit, 0);
+
+ purge_requests(hostdata, DID_ERROR);
+ if ((ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata)) ||
+ (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0)) ||
+ (vio_enable_interrupts(to_vio_dev(hostdata->dev)))) {
+ atomic_set(&hostdata->request_limit, -1);
+ dev_err(hostdata->dev, "error after reset\n");
+ }
+
+ scsi_unblock_requests(hostdata->host);
+}
+
+/**
+ * ibmvscsi_timeout - Internal command timeout handler
+ * @evt_struct: struct srp_event_struct that timed out
+ *
+ * Called when an internally generated command times out
+*/
+static void ibmvscsi_timeout(struct srp_event_struct *evt_struct)
+{
+ struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+
+ dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n",
+ evt_struct->iu.srp.cmd.opcode);
+
+ ibmvscsi_reset_host(hostdata);
+}
+
+
/* ------------------------------------------------------------
* Routines for sending and receiving SRPs
*/
@@ -527,12 +546,14 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
* ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
* @evt_struct: evt_struct to be sent
* @hostdata: ibmvscsi_host_data of host
+ * @timeout: timeout in seconds - 0 means do not time command
*
* Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
* Note that this routine assumes that host_lock is held for synchronization
*/
static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
- struct ibmvscsi_host_data *hostdata)
+ struct ibmvscsi_host_data *hostdata,
+ unsigned long timeout)
{
u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
int request_status;
@@ -588,12 +609,20 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
*/
list_add_tail(&evt_struct->list, &hostdata->sent);
+ init_timer(&evt_struct->timer);
+ if (timeout) {
+ evt_struct->timer.data = (unsigned long) evt_struct;
+ evt_struct->timer.expires = jiffies + (timeout * HZ);
+ evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout;
+ add_timer(&evt_struct->timer);
+ }
+
if ((rc =
ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
list_del(&evt_struct->list);
+ del_timer(&evt_struct->timer);
- printk(KERN_ERR "ibmvscsi: send error %d\n",
- rc);
+ dev_err(hostdata->dev, "send error %d\n", rc);
atomic_inc(&hostdata->request_limit);
goto send_error;
}
@@ -634,9 +663,8 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
if (unlikely(rsp->opcode != SRP_RSP)) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: bad SRP RSP type %d\n",
- rsp->opcode);
+ dev_warn(evt_struct->hostdata->dev,
+ "bad SRP RSP type %d\n", rsp->opcode);
}
if (cmnd) {
@@ -650,9 +678,9 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
evt_struct->hostdata->dev);
if (rsp->flags & SRP_RSP_FLAG_DOOVER)
- cmnd->resid = rsp->data_out_res_cnt;
+ scsi_set_resid(cmnd, rsp->data_out_res_cnt);
else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
- cmnd->resid = rsp->data_in_res_cnt;
+ scsi_set_resid(cmnd, rsp->data_in_res_cnt);
}
if (evt_struct->cmnd_done)
@@ -697,7 +725,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
srp_cmd->lun = ((u64) lun) << 48;
if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
- printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
+ sdev_printk(KERN_ERR, cmnd->device, "couldn't convert cmd to srp_cmd\n");
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
}
@@ -722,7 +750,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
offsetof(struct srp_indirect_buf, desc_list);
}
- return ibmvscsi_send_srp_event(evt_struct, hostdata);
+ return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
}
/* ------------------------------------------------------------
@@ -744,16 +772,16 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
DMA_BIDIRECTIONAL);
if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
- printk("ibmvscsi: error %d getting adapter info\n",
- evt_struct->xfer_iu->mad.adapter_info.common.status);
+ dev_err(hostdata->dev, "error %d getting adapter info\n",
+ evt_struct->xfer_iu->mad.adapter_info.common.status);
} else {
- printk("ibmvscsi: host srp version: %s, "
- "host partition %s (%d), OS %d, max io %u\n",
- hostdata->madapter_info.srp_version,
- hostdata->madapter_info.partition_name,
- hostdata->madapter_info.partition_number,
- hostdata->madapter_info.os_type,
- hostdata->madapter_info.port_max_txu[0]);
+ dev_info(hostdata->dev, "host srp version: %s, "
+ "host partition %s (%d), OS %d, max io %u\n",
+ hostdata->madapter_info.srp_version,
+ hostdata->madapter_info.partition_name,
+ hostdata->madapter_info.partition_number,
+ hostdata->madapter_info.os_type,
+ hostdata->madapter_info.port_max_txu[0]);
if (hostdata->madapter_info.port_max_txu[0])
hostdata->host->max_sectors =
@@ -761,11 +789,10 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
if (hostdata->madapter_info.os_type == 3 &&
strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
- printk("ibmvscsi: host (Ver. %s) doesn't support large"
- "transfers\n",
- hostdata->madapter_info.srp_version);
- printk("ibmvscsi: limiting scatterlists to %d\n",
- MAX_INDIRECT_BUFS);
+ dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
+ hostdata->madapter_info.srp_version);
+ dev_err(hostdata->dev, "limiting scatterlists to %d\n",
+ MAX_INDIRECT_BUFS);
hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
}
}
@@ -784,19 +811,20 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
{
struct viosrp_adapter_info *req;
struct srp_event_struct *evt_struct;
+ unsigned long flags;
dma_addr_t addr;
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) {
- printk(KERN_ERR "ibmvscsi: couldn't allocate an event "
- "for ADAPTER_INFO_REQ!\n");
+ dev_err(hostdata->dev,
+ "couldn't allocate an event for ADAPTER_INFO_REQ!\n");
return;
}
init_event_struct(evt_struct,
adapter_info_rsp,
VIOSRP_MAD_FORMAT,
- init_timeout * HZ);
+ init_timeout);
req = &evt_struct->iu.mad.adapter_info;
memset(req, 0x00, sizeof(*req));
@@ -809,20 +837,20 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
DMA_BIDIRECTIONAL);
if (dma_mapping_error(req->buffer)) {
- printk(KERN_ERR
- "ibmvscsi: Unable to map request_buffer "
- "for adapter_info!\n");
+ dev_err(hostdata->dev, "Unable to map request_buffer for adapter_info!\n");
free_event_struct(&hostdata->pool, evt_struct);
return;
}
- if (ibmvscsi_send_srp_event(evt_struct, hostdata)) {
- printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n");
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ if (ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2)) {
+ dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n");
dma_unmap_single(hostdata->dev,
addr,
sizeof(hostdata->madapter_info),
DMA_BIDIRECTIONAL);
}
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
};
/**
@@ -839,24 +867,23 @@ static void login_rsp(struct srp_event_struct *evt_struct)
case SRP_LOGIN_RSP: /* it worked! */
break;
case SRP_LOGIN_REJ: /* refused! */
- printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REJ reason %u\n",
- evt_struct->xfer_iu->srp.login_rej.reason);
+ dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n",
+ evt_struct->xfer_iu->srp.login_rej.reason);
/* Login failed. */
atomic_set(&hostdata->request_limit, -1);
return;
default:
- printk(KERN_ERR
- "ibmvscsi: Invalid login response typecode 0x%02x!\n",
- evt_struct->xfer_iu->srp.login_rsp.opcode);
+ dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n",
+ evt_struct->xfer_iu->srp.login_rsp.opcode);
/* Login failed. */
atomic_set(&hostdata->request_limit, -1);
return;
}
- printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
+ dev_info(hostdata->dev, "SRP_LOGIN succeeded\n");
if (evt_struct->xfer_iu->srp.login_rsp.req_lim_delta < 0)
- printk(KERN_ERR "ibmvscsi: Invalid request_limit.\n");
+ dev_err(hostdata->dev, "Invalid request_limit.\n");
/* Now we know what the real request-limit is.
* This value is set rather than added to request_limit because
@@ -885,15 +912,14 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
struct srp_login_req *login;
struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) {
- printk(KERN_ERR
- "ibmvscsi: couldn't allocate an event for login req!\n");
+ dev_err(hostdata->dev, "couldn't allocate an event for login req!\n");
return FAILED;
}
init_event_struct(evt_struct,
login_rsp,
VIOSRP_SRP_FORMAT,
- init_timeout * HZ);
+ init_timeout);
login = &evt_struct->iu.srp.login_req;
memset(login, 0x00, sizeof(struct srp_login_req));
@@ -907,9 +933,9 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
*/
atomic_set(&hostdata->request_limit, 1);
- rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+ rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk("ibmvscsic: sent SRP login\n");
+ dev_info(hostdata->dev, "sent SRP login\n");
return rc;
};
@@ -958,20 +984,20 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
if (!found_evt) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- return FAILED;
+ return SUCCESS;
}
evt = get_event_struct(&hostdata->pool);
if (evt == NULL) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n");
+ sdev_printk(KERN_ERR, cmd->device, "failed to allocate abort event\n");
return FAILED;
}
init_event_struct(evt,
sync_completion,
VIOSRP_SRP_FORMAT,
- init_timeout * HZ);
+ init_timeout);
tsk_mgmt = &evt->iu.srp.tsk_mgmt;
@@ -982,15 +1008,16 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
tsk_mgmt->task_tag = (u64) found_evt;
- printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n",
- tsk_mgmt->lun, tsk_mgmt->task_tag);
+ sdev_printk(KERN_INFO, cmd->device, "aborting command. lun 0x%lx, tag 0x%lx\n",
+ tsk_mgmt->lun, tsk_mgmt->task_tag);
evt->sync_srp = &srp_rsp;
init_completion(&evt->comp);
- rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+ rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
if (rsp_rc != 0) {
- printk(KERN_ERR "ibmvscsi: failed to send abort() event\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "failed to send abort() event. rc=%d\n", rsp_rc);
return FAILED;
}
@@ -999,9 +1026,8 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
/* make sure we got a good response */
if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: abort bad SRP RSP type %d\n",
- srp_rsp.srp.rsp.opcode);
+ sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n",
+ srp_rsp.srp.rsp.opcode);
return FAILED;
}
@@ -1012,10 +1038,9 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
if (rsp_rc) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: abort code %d for task tag 0x%lx\n",
- rsp_rc,
- tsk_mgmt->task_tag);
+ sdev_printk(KERN_WARNING, cmd->device,
+ "abort code %d for task tag 0x%lx\n",
+ rsp_rc, tsk_mgmt->task_tag);
return FAILED;
}
@@ -1034,15 +1059,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
if (found_evt == NULL) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk(KERN_INFO
- "ibmvscsi: aborted task tag 0x%lx completed\n",
- tsk_mgmt->task_tag);
+ sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%lx completed\n",
+ tsk_mgmt->task_tag);
return SUCCESS;
}
- printk(KERN_INFO
- "ibmvscsi: successfully aborted task tag 0x%lx\n",
- tsk_mgmt->task_tag);
+ sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%lx\n",
+ tsk_mgmt->task_tag);
cmd->result = (DID_ABORT << 16);
list_del(&found_evt->list);
@@ -1076,14 +1099,14 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
evt = get_event_struct(&hostdata->pool);
if (evt == NULL) {
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
- printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n");
+ sdev_printk(KERN_ERR, cmd->device, "failed to allocate reset event\n");
return FAILED;
}
init_event_struct(evt,
sync_completion,
VIOSRP_SRP_FORMAT,
- init_timeout * HZ);
+ init_timeout);
tsk_mgmt = &evt->iu.srp.tsk_mgmt;
@@ -1093,15 +1116,16 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
tsk_mgmt->lun = ((u64) lun) << 48;
tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
- printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n",
- tsk_mgmt->lun);
+ sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%lx\n",
+ tsk_mgmt->lun);
evt->sync_srp = &srp_rsp;
init_completion(&evt->comp);
- rsp_rc = ibmvscsi_send_srp_event(evt, hostdata);
+ rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, init_timeout * 2);
spin_unlock_irqrestore(hostdata->host->host_lock, flags);
if (rsp_rc != 0) {
- printk(KERN_ERR "ibmvscsi: failed to send reset event\n");
+ sdev_printk(KERN_ERR, cmd->device,
+ "failed to send reset event. rc=%d\n", rsp_rc);
return FAILED;
}
@@ -1110,9 +1134,8 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
/* make sure we got a good response */
if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: reset bad SRP RSP type %d\n",
- srp_rsp.srp.rsp.opcode);
+ sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n",
+ srp_rsp.srp.rsp.opcode);
return FAILED;
}
@@ -1123,9 +1146,9 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
if (rsp_rc) {
if (printk_ratelimit())
- printk(KERN_WARNING
- "ibmvscsi: reset code %d for task tag 0x%lx\n",
- rsp_rc, tsk_mgmt->task_tag);
+ sdev_printk(KERN_WARNING, cmd->device,
+ "reset code %d for task tag 0x%lx\n",
+ rsp_rc, tsk_mgmt->task_tag);
return FAILED;
}
@@ -1154,32 +1177,30 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
}
/**
- * purge_requests: Our virtual adapter just shut down. purge any sent requests
- * @hostdata: the adapter
- */
-static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
+ * ibmvscsi_eh_host_reset_handler - Reset the connection to the server
+ * @cmd: struct scsi_cmnd having problems
+*/
+static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
{
- struct srp_event_struct *tmp_evt, *pos;
- unsigned long flags;
+ unsigned long wait_switch = 0;
+ struct ibmvscsi_host_data *hostdata =
+ (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
- spin_lock_irqsave(hostdata->host->host_lock, flags);
- list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
- list_del(&tmp_evt->list);
- if (tmp_evt->cmnd) {
- tmp_evt->cmnd->result = (error_code << 16);
- unmap_cmd_data(&tmp_evt->iu.srp.cmd,
- tmp_evt,
- tmp_evt->hostdata->dev);
- if (tmp_evt->cmnd_done)
- tmp_evt->cmnd_done(tmp_evt->cmnd);
- } else {
- if (tmp_evt->done) {
- tmp_evt->done(tmp_evt);
- }
- }
- free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+ dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
+
+ ibmvscsi_reset_host(hostdata);
+
+ for (wait_switch = jiffies + (init_timeout * HZ);
+ time_before(jiffies, wait_switch) &&
+ atomic_read(&hostdata->request_limit) < 2;) {
+
+ msleep(10);
}
- spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+
+ if (atomic_read(&hostdata->request_limit) <= 0)
+ return FAILED;
+
+ return SUCCESS;
}
/**
@@ -1191,6 +1212,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code)
void ibmvscsi_handle_crq(struct viosrp_crq *crq,
struct ibmvscsi_host_data *hostdata)
{
+ long rc;
unsigned long flags;
struct srp_event_struct *evt_struct =
(struct srp_event_struct *)crq->IU_data_ptr;
@@ -1198,27 +1220,25 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
case 0xC0: /* initialization */
switch (crq->format) {
case 0x01: /* Initialization message */
- printk(KERN_INFO "ibmvscsi: partner initialized\n");
+ dev_info(hostdata->dev, "partner initialized\n");
/* Send back a response */
- if (ibmvscsi_send_crq(hostdata,
- 0xC002000000000000LL, 0) == 0) {
+ if ((rc = ibmvscsi_send_crq(hostdata,
+ 0xC002000000000000LL, 0)) == 0) {
/* Now login */
send_srp_login(hostdata);
} else {
- printk(KERN_ERR
- "ibmvscsi: Unable to send init rsp\n");
+ dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc);
}
break;
case 0x02: /* Initialization response */
- printk(KERN_INFO
- "ibmvscsi: partner initialization complete\n");
+ dev_info(hostdata->dev, "partner initialization complete\n");
/* Now login */
send_srp_login(hostdata);
break;
default:
- printk(KERN_ERR "ibmvscsi: unknown crq message type\n");
+ dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format);
}
return;
case 0xFF: /* Hypervisor telling us the connection is closed */
@@ -1226,8 +1246,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
atomic_set(&hostdata->request_limit, 0);
if (crq->format == 0x06) {
/* We need to re-setup the interpartition connection */
- printk(KERN_INFO
- "ibmvscsi: Re-enabling adapter!\n");
+ dev_info(hostdata->dev, "Re-enabling adapter!\n");
purge_requests(hostdata, DID_REQUEUE);
if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
hostdata)) ||
@@ -1235,14 +1254,11 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
- printk(KERN_ERR
- "ibmvscsi: error after"
- " enable\n");
+ dev_err(hostdata->dev, "error after enable\n");
}
} else {
- printk(KERN_INFO
- "ibmvscsi: Virtual adapter failed rc %d!\n",
- crq->format);
+ dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n",
+ crq->format);
purge_requests(hostdata, DID_ERROR);
if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
@@ -1251,8 +1267,7 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
0xC001000000000000LL, 0))) {
atomic_set(&hostdata->request_limit,
-1);
- printk(KERN_ERR
- "ibmvscsi: error after reset\n");
+ dev_err(hostdata->dev, "error after reset\n");
}
}
scsi_unblock_requests(hostdata->host);
@@ -1260,9 +1275,8 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
case 0x80: /* real payload */
break;
default:
- printk(KERN_ERR
- "ibmvscsi: got an invalid message type 0x%02x\n",
- crq->valid);
+ dev_err(hostdata->dev, "got an invalid message type 0x%02x\n",
+ crq->valid);
return;
}
@@ -1271,16 +1285,14 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
* actually sent
*/
if (!valid_event_struct(&hostdata->pool, evt_struct)) {
- printk(KERN_ERR
- "ibmvscsi: returned correlation_token 0x%p is invalid!\n",
+ dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
(void *)crq->IU_data_ptr);
return;
}
if (atomic_read(&evt_struct->free)) {
- printk(KERN_ERR
- "ibmvscsi: received duplicate correlation_token 0x%p!\n",
- (void *)crq->IU_data_ptr);
+ dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
+ (void *)crq->IU_data_ptr);
return;
}
@@ -1288,11 +1300,12 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
&hostdata->request_limit);
+ del_timer(&evt_struct->timer);
+
if (evt_struct->done)
evt_struct->done(evt_struct);
else
- printk(KERN_ERR
- "ibmvscsi: returned done() is NULL; not running it!\n");
+ dev_err(hostdata->dev, "returned done() is NULL; not running it!\n");
/*
* Lock the host_lock before messing with these structures, since we
@@ -1313,20 +1326,20 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
{
struct viosrp_host_config *host_config;
struct srp_event_struct *evt_struct;
+ unsigned long flags;
dma_addr_t addr;
int rc;
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct) {
- printk(KERN_ERR
- "ibmvscsi: could't allocate event for HOST_CONFIG!\n");
+ dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n");
return -1;
}
init_event_struct(evt_struct,
sync_completion,
VIOSRP_MAD_FORMAT,
- init_timeout * HZ);
+ init_timeout);
host_config = &evt_struct->iu.mad.host_config;
@@ -1339,14 +1352,15 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
DMA_BIDIRECTIONAL);
if (dma_mapping_error(host_config->buffer)) {
- printk(KERN_ERR
- "ibmvscsi: dma_mapping error " "getting host config\n");
+ dev_err(hostdata->dev, "dma_mapping error getting host config\n");
free_event_struct(&hostdata->pool, evt_struct);
return -1;
}
init_completion(&evt_struct->comp);
- rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+ spin_lock_irqsave(hostdata->host->host_lock, flags);
+ rc = ibmvscsi_send_srp_event(evt_struct, hostdata, init_timeout * 2);
+ spin_unlock_irqrestore(hostdata->host->host_lock, flags);
if (rc == 0)
wait_for_completion(&evt_struct->comp);
dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL);
@@ -1375,6 +1389,23 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
return 0;
}
+/**
+ * ibmvscsi_change_queue_depth - Change the device's queue depth
+ * @sdev: scsi device struct
+ * @qdepth: depth to set
+ *
+ * Return value:
+ * actual depth set
+ **/
+static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+ if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
+ qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
+
+ scsi_adjust_queue_depth(sdev, 0, qdepth);
+ return sdev->queue_depth;
+}
+
/* ------------------------------------------------------------
* sysfs attributes
*/
@@ -1520,7 +1551,9 @@ static struct scsi_host_template driver_template = {
.queuecommand = ibmvscsi_queuecommand,
.eh_abort_handler = ibmvscsi_eh_abort_handler,
.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+ .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler,
.slave_configure = ibmvscsi_slave_configure,
+ .change_queue_depth = ibmvscsi_change_queue_depth,
.cmd_per_lun = 16,
.can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT,
.this_id = -1,
@@ -1545,7 +1578,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
driver_template.can_queue = max_requests;
host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
if (!host) {
- printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
+ dev_err(&vdev->dev, "couldn't allocate host data\n");
goto scsi_host_alloc_failed;
}
@@ -1559,11 +1592,11 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
if (rc != 0 && rc != H_RESOURCE) {
- printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n");
+ dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc);
goto init_crq_failed;
}
if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) {
- printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n");
+ dev_err(&vdev->dev, "couldn't initialize event pool\n");
goto init_pool_failed;
}
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 77cc1d40f5bb..b19c2e26c2a5 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -45,6 +45,7 @@ struct Scsi_Host;
#define MAX_INDIRECT_BUFS 10
#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100
+#define IBMVSCSI_MAX_CMDS_PER_LUN 64
/* ------------------------------------------------------------
* Data Structures
@@ -69,6 +70,7 @@ struct srp_event_struct {
union viosrp_iu iu;
void (*cmnd_done) (struct scsi_cmnd *);
struct completion comp;
+ struct timer_list timer;
union viosrp_iu *sync_srp;
struct srp_direct_buf *ext_list;
dma_addr_t ext_list_token;
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index d8700aaa6114..9c14e789df5f 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -177,7 +177,7 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
memset(&hostdata->madapter_info, 0x00,
sizeof(hostdata->madapter_info));
- printk(KERN_INFO "rpa_vscsi: SPR_VERSION: %s\n", SRP_VERSION);
+ dev_info(hostdata->dev, "SRP_VERSION: %s\n", SRP_VERSION);
strcpy(hostdata->madapter_info.srp_version, SRP_VERSION);
strncpy(hostdata->madapter_info.partition_name, partition_name,
@@ -232,25 +232,24 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
if (rc == 2) {
/* Adapter is good, but other end is not ready */
- printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+ dev_warn(hostdata->dev, "Partner adapter not ready\n");
retrc = 0;
} else if (rc != 0) {
- printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc);
+ dev_warn(hostdata->dev, "Error %d opening adapter\n", rc);
goto reg_crq_failed;
}
if (request_irq(vdev->irq,
ibmvscsi_handle_event,
0, "ibmvscsi", (void *)hostdata) != 0) {
- printk(KERN_ERR "ibmvscsi: couldn't register irq 0x%x\n",
- vdev->irq);
+ dev_err(hostdata->dev, "couldn't register irq 0x%x\n",
+ vdev->irq);
goto req_irq_failed;
}
rc = vio_enable_interrupts(vdev);
if (rc != 0) {
- printk(KERN_ERR "ibmvscsi: Error %d enabling interrupts!!!\n",
- rc);
+ dev_err(hostdata->dev, "Error %d enabling interrupts!!!\n", rc);
goto req_irq_failed;
}
@@ -294,7 +293,7 @@ int ibmvscsi_reenable_crq_queue(struct crq_queue *queue,
} while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc)));
if (rc)
- printk(KERN_ERR "ibmvscsi: Error %d enabling adapter\n", rc);
+ dev_err(hostdata->dev, "Error %d enabling adapter\n", rc);
return rc;
}
@@ -327,10 +326,9 @@ int ibmvscsi_reset_crq_queue(struct crq_queue *queue,
queue->msg_token, PAGE_SIZE);
if (rc == 2) {
/* Adapter is good, but other end is not ready */
- printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+ dev_warn(hostdata->dev, "Partner adapter not ready\n");
} else if (rc != 0) {
- printk(KERN_WARNING
- "ibmvscsi: couldn't register crq--rc 0x%x\n", rc);
+ dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc);
}
return rc;
}
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 0464c182c577..005d2b05f32d 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -1159,11 +1159,10 @@ static int __imm_attach(struct parport *pb)
init_waitqueue_head(&waiting);
- dev = kmalloc(sizeof(imm_struct), GFP_KERNEL);
+ dev = kzalloc(sizeof(imm_struct), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(imm_struct));
dev->base = -1;
dev->mode = IMM_AUTODETECT;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 7e7635ca78f1..d9dfb69ae031 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -3,7 +3,8 @@
*
* Copyright (c) 1994-1998 Initio Corporation
* Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
- * All rights reserved.
+ * Copyright (c) 2004 Christoph Hellwig <hch@lst.de>
+ * Copyright (c) 2007 Red Hat <alan@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,38 +20,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
*
*************************************************************************
*
@@ -70,14 +39,14 @@
* - Fix memory allocation problem
* 03/04/98 hc - v1.01l
* - Fix tape rewind which will hang the system problem
- * - Set can_queue to tul_num_scb
+ * - Set can_queue to initio_num_scb
* 06/25/98 hc - v1.01m
* - Get it work for kernel version >= 2.1.75
- * - Dynamic assign SCSI bus reset holding time in init_tulip()
+ * - Dynamic assign SCSI bus reset holding time in initio_init()
* 07/02/98 hc - v1.01n
* - Support 0002134A
* 08/07/98 hc - v1.01o
- * - Change the tul_abort_srb routine to use scsi_done. <01>
+ * - Change the initio_abort_srb routine to use scsi_done. <01>
* 09/07/98 hl - v1.02
* - Change the INI9100U define and proc_dir_entry to
* reflect the newer Kernel 2.1.118, but the v1.o1o
@@ -150,23 +119,13 @@
static unsigned int i91u_debug = DEBUG_DEFAULT;
#endif
-#define TUL_RDWORD(x,y) (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
-
-typedef struct PCI_ID_Struc {
- unsigned short vendor_id;
- unsigned short device_id;
-} PCI_ID;
-
-static int tul_num_ch = 4; /* Maximum 4 adapters */
-static int tul_num_scb;
-static int tul_tag_enable = 1;
-static SCB *tul_scb;
+static int initio_tag_enable = 1;
#ifdef DEBUG_i91u
static int setup_debug = 0;
#endif
-static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
+static void i91uSCBPost(u8 * pHcb, u8 * pScb);
/* PCI Devices supported by this driver */
static struct pci_device_id i91u_pci_devices[] = {
@@ -184,74 +143,66 @@ MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
#define DEBUG_STATE 0
#define INT_DISC 0
-/*--- external functions --*/
-static void tul_se2_wait(void);
-
-/*--- forward refrence ---*/
-static SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun);
-static SCB *tul_find_done_scb(HCS * pCurHcb);
-
-static int tulip_main(HCS * pCurHcb);
-
-static int tul_next_state(HCS * pCurHcb);
-static int tul_state_1(HCS * pCurHcb);
-static int tul_state_2(HCS * pCurHcb);
-static int tul_state_3(HCS * pCurHcb);
-static int tul_state_4(HCS * pCurHcb);
-static int tul_state_5(HCS * pCurHcb);
-static int tul_state_6(HCS * pCurHcb);
-static int tul_state_7(HCS * pCurHcb);
-static int tul_xfer_data_in(HCS * pCurHcb);
-static int tul_xfer_data_out(HCS * pCurHcb);
-static int tul_xpad_in(HCS * pCurHcb);
-static int tul_xpad_out(HCS * pCurHcb);
-static int tul_status_msg(HCS * pCurHcb);
-
-static int tul_msgin(HCS * pCurHcb);
-static int tul_msgin_sync(HCS * pCurHcb);
-static int tul_msgin_accept(HCS * pCurHcb);
-static int tul_msgout_reject(HCS * pCurHcb);
-static int tul_msgin_extend(HCS * pCurHcb);
-
-static int tul_msgout_ide(HCS * pCurHcb);
-static int tul_msgout_abort_targ(HCS * pCurHcb);
-static int tul_msgout_abort_tag(HCS * pCurHcb);
-
-static int tul_bus_device_reset(HCS * pCurHcb);
-static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb);
-static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb);
-static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb);
-static int int_tul_busfree(HCS * pCurHcb);
-static int int_tul_scsi_rst(HCS * pCurHcb);
-static int int_tul_bad_seq(HCS * pCurHcb);
-static int int_tul_resel(HCS * pCurHcb);
-static int tul_sync_done(HCS * pCurHcb);
-static int wdtr_done(HCS * pCurHcb);
-static int wait_tulip(HCS * pCurHcb);
-static int tul_wait_done_disc(HCS * pCurHcb);
-static int tul_wait_disc(HCS * pCurHcb);
-static void tulip_scsi(HCS * pCurHcb);
-static int tul_post_scsi_rst(HCS * pCurHcb);
-
-static void tul_se2_ew_en(WORD CurBase);
-static void tul_se2_ew_ds(WORD CurBase);
-static int tul_se2_rd_all(WORD CurBase);
-static void tul_se2_update_all(WORD CurBase); /* setup default pattern */
-static void tul_read_eeprom(WORD CurBase);
-
- /* ---- INTERNAL VARIABLES ---- */
-static HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
-static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
-
-/*NVRAM nvram, *nvramp = &nvram; */
+/*--- forward references ---*/
+static struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun);
+static struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host);
+
+static int tulip_main(struct initio_host * host);
+
+static int initio_next_state(struct initio_host * host);
+static int initio_state_1(struct initio_host * host);
+static int initio_state_2(struct initio_host * host);
+static int initio_state_3(struct initio_host * host);
+static int initio_state_4(struct initio_host * host);
+static int initio_state_5(struct initio_host * host);
+static int initio_state_6(struct initio_host * host);
+static int initio_state_7(struct initio_host * host);
+static int initio_xfer_data_in(struct initio_host * host);
+static int initio_xfer_data_out(struct initio_host * host);
+static int initio_xpad_in(struct initio_host * host);
+static int initio_xpad_out(struct initio_host * host);
+static int initio_status_msg(struct initio_host * host);
+
+static int initio_msgin(struct initio_host * host);
+static int initio_msgin_sync(struct initio_host * host);
+static int initio_msgin_accept(struct initio_host * host);
+static int initio_msgout_reject(struct initio_host * host);
+static int initio_msgin_extend(struct initio_host * host);
+
+static int initio_msgout_ide(struct initio_host * host);
+static int initio_msgout_abort_targ(struct initio_host * host);
+static int initio_msgout_abort_tag(struct initio_host * host);
+
+static int initio_bus_device_reset(struct initio_host * host);
+static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb);
+static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb);
+static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb);
+static int int_initio_busfree(struct initio_host * host);
+static int int_initio_scsi_rst(struct initio_host * host);
+static int int_initio_bad_seq(struct initio_host * host);
+static int int_initio_resel(struct initio_host * host);
+static int initio_sync_done(struct initio_host * host);
+static int wdtr_done(struct initio_host * host);
+static int wait_tulip(struct initio_host * host);
+static int initio_wait_done_disc(struct initio_host * host);
+static int initio_wait_disc(struct initio_host * host);
+static void tulip_scsi(struct initio_host * host);
+static int initio_post_scsi_rst(struct initio_host * host);
+
+static void initio_se2_ew_en(unsigned long base);
+static void initio_se2_ew_ds(unsigned long base);
+static int initio_se2_rd_all(unsigned long base);
+static void initio_se2_update_all(unsigned long base); /* setup default pattern */
+static void initio_read_eeprom(unsigned long base);
+
+/* ---- INTERNAL VARIABLES ---- */
+
static NVRAM i91unvram;
static NVRAM *i91unvramp;
-
-
-static UCHAR i91udftNvRam[64] =
+static u8 i91udftNvRam[64] =
{
-/*----------- header -----------*/
+ /*----------- header -----------*/
0x25, 0xc9, /* Signature */
0x40, /* Size */
0x01, /* Revision */
@@ -289,7 +240,7 @@ static UCHAR i91udftNvRam[64] =
0, 0}; /* - CheckSum - */
-static UCHAR tul_rate_tbl[8] = /* fast 20 */
+static u8 initio_rate_tbl[8] = /* fast 20 */
{
/* nanosecond devide by 4 */
12, /* 50ns, 20M */
@@ -302,53 +253,17 @@ static UCHAR tul_rate_tbl[8] = /* fast 20 */
62 /* 250ns, 4M */
};
-static void tul_do_pause(unsigned amount)
-{ /* Pause for amount jiffies */
+static void initio_do_pause(unsigned amount)
+{
+ /* Pause for amount jiffies */
unsigned long the_time = jiffies + amount;
- while (time_before_eq(jiffies, the_time));
+ while (time_before_eq(jiffies, the_time))
+ cpu_relax();
}
/*-- forward reference --*/
-/*******************************************************************
- Use memeory refresh time ~ 15us * 2
-********************************************************************/
-void tul_se2_wait(void)
-{
-#if 1
- udelay(30);
-#else
- UCHAR readByte;
-
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) == 0x10) {
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) == 0x10)
- break;
- }
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) != 0x10)
- break;
- }
- } else {
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) == 0x10)
- break;
- }
- for (;;) {
- readByte = TUL_RD(0, 0x61);
- if ((readByte & 0x10) != 0x10)
- break;
- }
- }
-#endif
-}
-
-
/******************************************************************
Input: instruction for Serial E2PROM
@@ -379,1174 +294,1019 @@ void tul_se2_wait(void)
******************************************************************/
-static void tul_se2_instr(WORD CurBase, UCHAR instr)
+
+/**
+ * initio_se2_instr - bitbang an instruction
+ * @base: Base of InitIO controller
+ * @instr: Instruction for serial E2PROM
+ *
+ * Bitbang an instruction out to the serial E2Prom
+ */
+
+static void initio_se2_instr(unsigned long base, u8 instr)
{
int i;
- UCHAR b;
+ u8 b;
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO); /* cs+start bit */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK | SE2DO); /* +CLK */
- tul_se2_wait();
+ outb(SE2CS | SE2DO, base + TUL_NVRAM); /* cs+start bit */
+ udelay(30);
+ outb(SE2CS | SE2CLK | SE2DO, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
for (i = 0; i < 8; i++) {
if (instr & 0x80)
- b = SE2CS | SE2DO; /* -CLK+dataBit */
+ b = SE2CS | SE2DO; /* -CLK+dataBit */
else
- b = SE2CS; /* -CLK */
- TUL_WR(CurBase + TUL_NVRAM, b);
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, b | SE2CLK); /* +CLK */
- tul_se2_wait();
+ b = SE2CS; /* -CLK */
+ outb(b, base + TUL_NVRAM);
+ udelay(30);
+ outb(b | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
instr <<= 1;
}
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
- tul_se2_wait();
- return;
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
+ udelay(30);
}
-/******************************************************************
- Function name : tul_se2_ew_en
- Description : Enable erase/write state of serial EEPROM
-******************************************************************/
-void tul_se2_ew_en(WORD CurBase)
+/**
+ * initio_se2_ew_en - Enable erase/write
+ * @base: Base address of InitIO controller
+ *
+ * Enable erase/write state of serial EEPROM
+ */
+void initio_se2_ew_en(unsigned long base)
{
- tul_se2_instr(CurBase, 0x30); /* EWEN */
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- tul_se2_wait();
- return;
+ initio_se2_instr(base, 0x30); /* EWEN */
+ outb(0, base + TUL_NVRAM); /* -CS */
+ udelay(30);
}
-/************************************************************************
- Disable erase/write state of serial EEPROM
-*************************************************************************/
-void tul_se2_ew_ds(WORD CurBase)
+/**
+ * initio_se2_ew_ds - Disable erase/write
+ * @base: Base address of InitIO controller
+ *
+ * Disable erase/write state of serial EEPROM
+ */
+void initio_se2_ew_ds(unsigned long base)
{
- tul_se2_instr(CurBase, 0); /* EWDS */
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- tul_se2_wait();
- return;
+ initio_se2_instr(base, 0); /* EWDS */
+ outb(0, base + TUL_NVRAM); /* -CS */
+ udelay(30);
}
-/******************************************************************
- Input :address of Serial E2PROM
- Output :value stored in Serial E2PROM
-*******************************************************************/
-static USHORT tul_se2_rd(WORD CurBase, ULONG adr)
+/**
+ * initio_se2_rd - read E2PROM word
+ * @base: Base of InitIO controller
+ * @addr: Address of word in E2PROM
+ *
+ * Read a word from the NV E2PROM device
+ */
+static u16 initio_se2_rd(unsigned long base, u8 addr)
{
- UCHAR instr, readByte;
- USHORT readWord;
+ u8 instr, rb;
+ u16 val = 0;
int i;
- instr = (UCHAR) (adr | 0x80);
- tul_se2_instr(CurBase, instr); /* READ INSTR */
- readWord = 0;
+ instr = (u8) (addr | 0x80);
+ initio_se2_instr(base, instr); /* READ INSTR */
for (i = 15; i >= 0; i--) {
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK); /* +CLK */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
+ outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
/* sample data after the following edge of clock */
- readByte = TUL_RD(CurBase, TUL_NVRAM);
- readByte &= SE2DI;
- readWord += (readByte << i);
- tul_se2_wait(); /* 6/20/95 */
+ rb = inb(base + TUL_NVRAM);
+ rb &= SE2DI;
+ val += (rb << i);
+ udelay(30); /* 6/20/95 */
}
- TUL_WR(CurBase + TUL_NVRAM, 0); /* no chip select */
- tul_se2_wait();
- return readWord;
+ outb(0, base + TUL_NVRAM); /* no chip select */
+ udelay(30);
+ return val;
}
-
-/******************************************************************
- Input: new value in Serial E2PROM, address of Serial E2PROM
-*******************************************************************/
-static void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
+/**
+ * initio_se2_wr - read E2PROM word
+ * @base: Base of InitIO controller
+ * @addr: Address of word in E2PROM
+ * @val: Value to write
+ *
+ * Write a word to the NV E2PROM device. Used when recovering from
+ * a problem with the NV.
+ */
+static void initio_se2_wr(unsigned long base, u8 addr, u16 val)
{
- UCHAR readByte;
- UCHAR instr;
+ u8 rb;
+ u8 instr;
int i;
- instr = (UCHAR) (adr | 0x40);
- tul_se2_instr(CurBase, instr); /* WRITE INSTR */
+ instr = (u8) (addr | 0x40);
+ initio_se2_instr(base, instr); /* WRITE INSTR */
for (i = 15; i >= 0; i--) {
- if (writeWord & 0x8000)
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO); /* -CLK+dataBit 1 */
+ if (val & 0x8000)
+ outb(SE2CS | SE2DO, base + TUL_NVRAM); /* -CLK+dataBit 1 */
else
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK+dataBit 0 */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK); /* +CLK */
- tul_se2_wait();
- writeWord <<= 1;
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK+dataBit 0 */
+ udelay(30);
+ outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
+ val <<= 1;
}
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- tul_se2_wait();
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
+ udelay(30);
+ outb(0, base + TUL_NVRAM); /* -CS */
+ udelay(30);
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* +CS */
- tul_se2_wait();
+ outb(SE2CS, base + TUL_NVRAM); /* +CS */
+ udelay(30);
for (;;) {
- TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK); /* +CLK */
- tul_se2_wait();
- TUL_WR(CurBase + TUL_NVRAM, SE2CS); /* -CLK */
- tul_se2_wait();
- if ((readByte = TUL_RD(CurBase, TUL_NVRAM)) & SE2DI)
+ outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */
+ udelay(30);
+ outb(SE2CS, base + TUL_NVRAM); /* -CLK */
+ udelay(30);
+ if ((rb = inb(base + TUL_NVRAM)) & SE2DI)
break; /* write complete */
}
- TUL_WR(CurBase + TUL_NVRAM, 0); /* -CS */
- return;
+ outb(0, base + TUL_NVRAM); /* -CS */
}
+/**
+ * initio_se2_rd_all - read hostadapter NV configuration
+ * @base: Base address of InitIO controller
+ *
+ * Reads the E2PROM data into main memory. Ensures that the checksum
+ * and header marker are valid. Returns 1 on success -1 on error.
+ */
-/***********************************************************************
- Read SCSI H/A configuration parameters from serial EEPROM
-************************************************************************/
-int tul_se2_rd_all(WORD CurBase)
+static int initio_se2_rd_all(unsigned long base)
{
int i;
- ULONG chksum = 0;
- USHORT *np;
+ u16 chksum = 0;
+ u16 *np;
i91unvramp = &i91unvram;
- np = (USHORT *) i91unvramp;
- for (i = 0; i < 32; i++) {
- *np++ = tul_se2_rd(CurBase, i);
- }
+ np = (u16 *) i91unvramp;
+ for (i = 0; i < 32; i++)
+ *np++ = initio_se2_rd(base, i);
-/*--------------------Is signature "ini" ok ? ----------------*/
+ /* Is signature "ini" ok ? */
if (i91unvramp->NVM_Signature != INI_SIGNATURE)
return -1;
-/*---------------------- Is ckecksum ok ? ----------------------*/
- np = (USHORT *) i91unvramp;
+ /* Is ckecksum ok ? */
+ np = (u16 *) i91unvramp;
for (i = 0; i < 31; i++)
chksum += *np++;
- if (i91unvramp->NVM_CheckSum != (USHORT) chksum)
+ if (i91unvramp->NVM_CheckSum != chksum)
return -1;
return 1;
}
-
-/***********************************************************************
- Update SCSI H/A configuration parameters from serial EEPROM
-************************************************************************/
-void tul_se2_update_all(WORD CurBase)
+/**
+ * initio_se2_update_all - Update E2PROM
+ * @base: Base of InitIO controller
+ *
+ * Update the E2PROM by wrting any changes into the E2PROM
+ * chip, rewriting the checksum.
+ */
+static void initio_se2_update_all(unsigned long base)
{ /* setup default pattern */
int i;
- ULONG chksum = 0;
- USHORT *np, *np1;
+ u16 chksum = 0;
+ u16 *np, *np1;
i91unvramp = &i91unvram;
/* Calculate checksum first */
- np = (USHORT *) i91udftNvRam;
+ np = (u16 *) i91udftNvRam;
for (i = 0; i < 31; i++)
chksum += *np++;
- *np = (USHORT) chksum;
- tul_se2_ew_en(CurBase); /* Enable write */
+ *np = chksum;
+ initio_se2_ew_en(base); /* Enable write */
- np = (USHORT *) i91udftNvRam;
- np1 = (USHORT *) i91unvramp;
+ np = (u16 *) i91udftNvRam;
+ np1 = (u16 *) i91unvramp;
for (i = 0; i < 32; i++, np++, np1++) {
- if (*np != *np1) {
- tul_se2_wr(CurBase, i, *np);
- }
+ if (*np != *np1)
+ initio_se2_wr(base, i, *np);
}
-
- tul_se2_ew_ds(CurBase); /* Disable write */
- return;
+ initio_se2_ew_ds(base); /* Disable write */
}
-/*************************************************************************
- Function name : read_eeprom
-**************************************************************************/
-void tul_read_eeprom(WORD CurBase)
-{
- UCHAR gctrl;
-
- i91unvramp = &i91unvram;
-/*------Enable EEProm programming ---*/
- gctrl = TUL_RD(CurBase, TUL_GCTRL);
- TUL_WR(CurBase + TUL_GCTRL, gctrl | TUL_GCTRL_EEPROM_BIT);
- if (tul_se2_rd_all(CurBase) != 1) {
- tul_se2_update_all(CurBase); /* setup default pattern */
- tul_se2_rd_all(CurBase); /* load again */
- }
-/*------ Disable EEProm programming ---*/
- gctrl = TUL_RD(CurBase, TUL_GCTRL);
- TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT);
-} /* read_eeprom */
+/**
+ * initio_read_eeprom - Retrieve configuration
+ * @base: Base of InitIO Host Adapter
+ *
+ * Retrieve the host adapter configuration data from E2Prom. If the
+ * data is invalid then the defaults are used and are also restored
+ * into the E2PROM. This forms the access point for the SCSI driver
+ * into the E2PROM layer, the other functions for the E2PROM are all
+ * internal use.
+ *
+ * Must be called single threaded, uses a shared global area.
+ */
-static int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
- BYTE bBus, BYTE bDevice)
+static void initio_read_eeprom(unsigned long base)
{
- int i, j;
+ u8 gctrl;
- for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
- if (i91u_adpt[i].ADPT_BIOS < wBIOS)
- continue;
- if (i91u_adpt[i].ADPT_BIOS == wBIOS) {
- if (i91u_adpt[i].ADPT_BASE == wBASE) {
- if (i91u_adpt[i].ADPT_Bus != 0xFF)
- return 1;
- } else if (i91u_adpt[i].ADPT_BASE < wBASE)
- continue;
- }
- for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
- i91u_adpt[j].ADPT_BASE = i91u_adpt[j - 1].ADPT_BASE;
- i91u_adpt[j].ADPT_INTR = i91u_adpt[j - 1].ADPT_INTR;
- i91u_adpt[j].ADPT_BIOS = i91u_adpt[j - 1].ADPT_BIOS;
- i91u_adpt[j].ADPT_Bus = i91u_adpt[j - 1].ADPT_Bus;
- i91u_adpt[j].ADPT_Device = i91u_adpt[j - 1].ADPT_Device;
- }
- i91u_adpt[i].ADPT_BASE = wBASE;
- i91u_adpt[i].ADPT_INTR = bInterrupt;
- i91u_adpt[i].ADPT_BIOS = wBIOS;
- i91u_adpt[i].ADPT_Bus = bBus;
- i91u_adpt[i].ADPT_Device = bDevice;
- return 0;
+ i91unvramp = &i91unvram;
+ /* Enable EEProm programming */
+ gctrl = inb(base + TUL_GCTRL);
+ outb(gctrl | TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL);
+ if (initio_se2_rd_all(base) != 1) {
+ initio_se2_update_all(base); /* setup default pattern */
+ initio_se2_rd_all(base); /* load again */
}
- return 1;
+ /* Disable EEProm programming */
+ gctrl = inb(base + TUL_GCTRL);
+ outb(gctrl & ~TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL);
}
-static void init_i91uAdapter_table(void)
-{
- int i;
-
- for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) { /* Initialize adapter structure */
- i91u_adpt[i].ADPT_BIOS = 0xffff;
- i91u_adpt[i].ADPT_BASE = 0xffff;
- i91u_adpt[i].ADPT_INTR = 0xff;
- i91u_adpt[i].ADPT_Bus = 0xff;
- i91u_adpt[i].ADPT_Device = 0xff;
- }
- return;
-}
+/**
+ * initio_stop_bm - stop bus master
+ * @host: InitIO we are stopping
+ *
+ * Stop any pending DMA operation, aborting the DMA if neccessary
+ */
-static void tul_stop_bm(HCS * pCurHcb)
+static void initio_stop_bm(struct initio_host * host)
{
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+ if (inb(host->addr + TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
+ outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd);
/* wait Abort DMA xfer done */
- while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+ while ((inb(host->addr + TUL_Int) & XABT) == 0)
+ cpu_relax();
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
}
-/***************************************************************************/
-static void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
-{
- pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE; /* Supply base address */
- pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */
- pCurHcb->HCS_Intr = i91u_adpt[ch_idx].ADPT_INTR; /* Supply interrupt line */
- return;
-}
+/**
+ * initio_reset_scsi - Reset SCSI host controller
+ * @host: InitIO host to reset
+ * @seconds: Recovery time
+ *
+ * Perform a full reset of the SCSI subsystem.
+ */
-/***************************************************************************/
-static int tul_reset_scsi(HCS * pCurHcb, int seconds)
+static int initio_reset_scsi(struct initio_host * host, int seconds)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
+ outb(TSC_RST_BUS, host->addr + TUL_SCtrl0);
- while (!((pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt)) & TSS_SCSIRST_INT));
- /* reset tulip chip */
+ while (!((host->jsint = inb(host->addr + TUL_SInt)) & TSS_SCSIRST_INT))
+ cpu_relax();
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, 0);
+ /* reset tulip chip */
+ outb(0, host->addr + TUL_SSignal);
/* Stall for a while, wait for target's firmware ready,make it 2 sec ! */
/* SONY 5200 tape drive won't work if only stall for 1 sec */
- tul_do_pause(seconds * HZ);
-
- TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+ /* FIXME: this is a very long busy wait right now */
+ initio_do_pause(seconds * HZ);
- return (SCSI_RESET_SUCCESS);
+ inb(host->addr + TUL_SInt);
+ return SCSI_RESET_SUCCESS;
}
-/***************************************************************************/
-static int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb,
- BYTE * pbBiosAdr, int seconds)
+/**
+ * initio_init - set up an InitIO host adapter
+ * @host: InitIO host adapter
+ * @num_scbs: Number of SCBS
+ * @bios_addr: BIOS address
+ *
+ * Set up the host adapter and devices according to the configuration
+ * retrieved from the E2PROM.
+ *
+ * Locking: Calls E2PROM layer code which is not re-enterable so must
+ * run single threaded for now.
+ */
+
+static void initio_init(struct initio_host * host, u8 *bios_addr)
{
int i;
- BYTE *pwFlags;
- BYTE *pbHeads;
- SCB *pTmpScb, *pPrevScb = NULL;
-
- pCurHcb->HCS_NumScbs = tul_num_scb;
- pCurHcb->HCS_Semaph = 1;
- spin_lock_init(&pCurHcb->HCS_SemaphLock);
- pCurHcb->HCS_JSStatus0 = 0;
- pCurHcb->HCS_Scb = scbp;
- pCurHcb->HCS_NxtPend = scbp;
- pCurHcb->HCS_NxtAvail = scbp;
- for (i = 0, pTmpScb = scbp; i < tul_num_scb; i++, pTmpScb++) {
- pTmpScb->SCB_TagId = i;
- if (i != 0)
- pPrevScb->SCB_NxtScb = pTmpScb;
- pPrevScb = pTmpScb;
- }
- pPrevScb->SCB_NxtScb = NULL;
- pCurHcb->HCS_ScbEnd = pTmpScb;
- pCurHcb->HCS_FirstAvail = scbp;
- pCurHcb->HCS_LastAvail = pPrevScb;
- spin_lock_init(&pCurHcb->HCS_AvailLock);
- pCurHcb->HCS_FirstPend = NULL;
- pCurHcb->HCS_LastPend = NULL;
- pCurHcb->HCS_FirstBusy = NULL;
- pCurHcb->HCS_LastBusy = NULL;
- pCurHcb->HCS_FirstDone = NULL;
- pCurHcb->HCS_LastDone = NULL;
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
-
- tul_read_eeprom(pCurHcb->HCS_Base);
-/*---------- get H/A configuration -------------*/
+ u8 *flags;
+ u8 *heads;
+
+ /* Get E2Prom configuration */
+ initio_read_eeprom(host->addr);
if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
- pCurHcb->HCS_MaxTar = 8;
+ host->max_tar = 8;
else
- pCurHcb->HCS_MaxTar = 16;
+ host->max_tar = 16;
- pCurHcb->HCS_Config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
+ host->config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
- pCurHcb->HCS_SCSI_ID = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
- pCurHcb->HCS_IdMask = ~(1 << pCurHcb->HCS_SCSI_ID);
+ host->scsi_id = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
+ host->idmask = ~(1 << host->scsi_id);
#ifdef CHK_PARITY
/* Enable parity error response */
- TUL_WR(pCurHcb->HCS_Base + TUL_PCMD, TUL_RD(pCurHcb->HCS_Base, TUL_PCMD) | 0x40);
+ outb(inb(host->addr + TUL_PCMD) | 0x40, host->addr + TUL_PCMD);
#endif
/* Mask all the interrupt */
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+ outb(0x1F, host->addr + TUL_Mask);
- tul_stop_bm(pCurHcb);
+ initio_stop_bm(host);
/* --- Initialize the tulip --- */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_CHIP);
+ outb(TSC_RST_CHIP, host->addr + TUL_SCtrl0);
/* program HBA's SCSI ID */
- TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId, pCurHcb->HCS_SCSI_ID << 4);
+ outb(host->scsi_id << 4, host->addr + TUL_SScsiId);
/* Enable Initiator Mode ,phase latch,alternate sync period mode,
disable SCSI reset */
- if (pCurHcb->HCS_Config & HCC_EN_PAR)
- pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
+ if (host->config & HCC_EN_PAR)
+ host->sconf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
else
- pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_SConf1);
+ host->sconf1 = (TSC_INITDEFAULT);
+ outb(host->sconf1, host->addr + TUL_SConfig);
- /* Enable HW reselect */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+ /* Enable HW reselect */
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, 0);
+ outb(0, host->addr + TUL_SPeriod);
/* selection time out = 250 ms */
- TUL_WR(pCurHcb->HCS_Base + TUL_STimeOut, 153);
+ outb(153, host->addr + TUL_STimeOut);
-/*--------- Enable SCSI terminator -----*/
- TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, (pCurHcb->HCS_Config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)));
- TUL_WR(pCurHcb->HCS_Base + TUL_GCTRL1,
- ((pCurHcb->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pCurHcb->HCS_Base, TUL_GCTRL1) & 0xFE));
+ /* Enable SCSI terminator */
+ outb((host->config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)),
+ host->addr + TUL_XCtrl);
+ outb(((host->config & HCC_AUTO_TERM) >> 4) |
+ (inb(host->addr + TUL_GCTRL1) & 0xFE),
+ host->addr + TUL_GCTRL1);
for (i = 0,
- pwFlags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
- pbHeads = pbBiosAdr + 0x180;
- i < pCurHcb->HCS_MaxTar;
- i++, pwFlags++) {
- pCurHcb->HCS_Tcs[i].TCS_Flags = *pwFlags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
- if (pCurHcb->HCS_Tcs[i].TCS_Flags & TCF_EN_255)
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+ flags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
+ heads = bios_addr + 0x180;
+ i < host->max_tar;
+ i++, flags++) {
+ host->targets[i].flags = *flags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ if (host->targets[i].flags & TCF_EN_255)
+ host->targets[i].drv_flags = TCF_DRV_255_63;
else
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
- pCurHcb->HCS_Tcs[i].TCS_JS_Period = 0;
- pCurHcb->HCS_Tcs[i].TCS_SConfig0 = pCurHcb->HCS_SConf1;
- pCurHcb->HCS_Tcs[i].TCS_DrvHead = *pbHeads++;
- if (pCurHcb->HCS_Tcs[i].TCS_DrvHead == 255)
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+ host->targets[i].drv_flags = 0;
+ host->targets[i].js_period = 0;
+ host->targets[i].sconfig0 = host->sconf1;
+ host->targets[i].heads = *heads++;
+ if (host->targets[i].heads == 255)
+ host->targets[i].drv_flags = TCF_DRV_255_63;
else
- pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
- pCurHcb->HCS_Tcs[i].TCS_DrvSector = *pbHeads++;
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;
- pCurHcb->HCS_ActTags[i] = 0;
- pCurHcb->HCS_MaxTags[i] = 0xFF;
+ host->targets[i].drv_flags = 0;
+ host->targets[i].sectors = *heads++;
+ host->targets[i].flags &= ~TCF_BUSY;
+ host->act_tags[i] = 0;
+ host->max_tags[i] = 0xFF;
} /* for */
printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n",
- pCurHcb->HCS_Base, pCurHcb->HCS_Intr,
- pCurHcb->HCS_BIOS, pCurHcb->HCS_SCSI_ID);
-/*------------------- reset SCSI Bus ---------------------------*/
- if (pCurHcb->HCS_Config & HCC_SCSI_RESET) {
- printk("i91u: Reset SCSI Bus ... \n");
- tul_reset_scsi(pCurHcb, seconds);
+ host->addr, host->irq,
+ host->bios_addr, host->scsi_id);
+ /* Reset SCSI Bus */
+ if (host->config & HCC_SCSI_RESET) {
+ printk(KERN_INFO "i91u: Reset SCSI Bus ... \n");
+ initio_reset_scsi(host, 10);
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCFG1, 0x17);
- TUL_WR(pCurHcb->HCS_Base + TUL_SIntEnable, 0xE9);
- return (0);
+ outb(0x17, host->addr + TUL_SCFG1);
+ outb(0xE9, host->addr + TUL_SIntEnable);
}
-/***************************************************************************/
-static SCB *tul_alloc_scb(HCS * hcsp)
+/**
+ * initio_alloc_scb - Allocate an SCB
+ * @host: InitIO host we are allocating for
+ *
+ * Walk the SCB list for the controller and allocate a free SCB if
+ * one exists.
+ */
+static struct scsi_ctrl_blk *initio_alloc_scb(struct initio_host *host)
{
- SCB *pTmpScb;
- ULONG flags;
- spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
- if ((pTmpScb = hcsp->HCS_FirstAvail) != NULL) {
+ struct scsi_ctrl_blk *scb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->avail_lock, flags);
+ if ((scb = host->first_avail) != NULL) {
#if DEBUG_QUEUE
- printk("find scb at %08lx\n", (ULONG) pTmpScb);
+ printk("find scb at %p\n", scb);
#endif
- if ((hcsp->HCS_FirstAvail = pTmpScb->SCB_NxtScb) == NULL)
- hcsp->HCS_LastAvail = NULL;
- pTmpScb->SCB_NxtScb = NULL;
- pTmpScb->SCB_Status = SCB_RENT;
+ if ((host->first_avail = scb->next) == NULL)
+ host->last_avail = NULL;
+ scb->next = NULL;
+ scb->status = SCB_RENT;
}
- spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
- return (pTmpScb);
+ spin_unlock_irqrestore(&host->avail_lock, flags);
+ return scb;
}
-/***************************************************************************/
-static void tul_release_scb(HCS * hcsp, SCB * scbp)
+/**
+ * initio_release_scb - Release an SCB
+ * @host: InitIO host that owns the SCB
+ * @cmnd: SCB command block being returned
+ *
+ * Return an allocated SCB to the host free list
+ */
+
+static void initio_release_scb(struct initio_host * host, struct scsi_ctrl_blk * cmnd)
{
- ULONG flags;
+ unsigned long flags;
#if DEBUG_QUEUE
- printk("Release SCB %lx; ", (ULONG) scbp);
+ printk("Release SCB %p; ", cmnd);
#endif
- spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
- scbp->SCB_Srb = NULL;
- scbp->SCB_Status = 0;
- scbp->SCB_NxtScb = NULL;
- if (hcsp->HCS_LastAvail != NULL) {
- hcsp->HCS_LastAvail->SCB_NxtScb = scbp;
- hcsp->HCS_LastAvail = scbp;
+ spin_lock_irqsave(&(host->avail_lock), flags);
+ cmnd->srb = NULL;
+ cmnd->status = 0;
+ cmnd->next = NULL;
+ if (host->last_avail != NULL) {
+ host->last_avail->next = cmnd;
+ host->last_avail = cmnd;
} else {
- hcsp->HCS_FirstAvail = scbp;
- hcsp->HCS_LastAvail = scbp;
+ host->first_avail = cmnd;
+ host->last_avail = cmnd;
}
- spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+ spin_unlock_irqrestore(&(host->avail_lock), flags);
}
/***************************************************************************/
-static void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void initio_append_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
#if DEBUG_QUEUE
- printk("Append pend SCB %lx; ", (ULONG) scbp);
+ printk("Append pend SCB %p; ", scbp);
#endif
- scbp->SCB_Status = SCB_PEND;
- scbp->SCB_NxtScb = NULL;
- if (pCurHcb->HCS_LastPend != NULL) {
- pCurHcb->HCS_LastPend->SCB_NxtScb = scbp;
- pCurHcb->HCS_LastPend = scbp;
+ scbp->status = SCB_PEND;
+ scbp->next = NULL;
+ if (host->last_pending != NULL) {
+ host->last_pending->next = scbp;
+ host->last_pending = scbp;
} else {
- pCurHcb->HCS_FirstPend = scbp;
- pCurHcb->HCS_LastPend = scbp;
+ host->first_pending = scbp;
+ host->last_pending = scbp;
}
}
/***************************************************************************/
-static void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void initio_push_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
#if DEBUG_QUEUE
- printk("Push pend SCB %lx; ", (ULONG) scbp);
+ printk("Push pend SCB %p; ", scbp);
#endif
- scbp->SCB_Status = SCB_PEND;
- if ((scbp->SCB_NxtScb = pCurHcb->HCS_FirstPend) != NULL) {
- pCurHcb->HCS_FirstPend = scbp;
+ scbp->status = SCB_PEND;
+ if ((scbp->next = host->first_pending) != NULL) {
+ host->first_pending = scbp;
} else {
- pCurHcb->HCS_FirstPend = scbp;
- pCurHcb->HCS_LastPend = scbp;
+ host->first_pending = scbp;
+ host->last_pending = scbp;
}
}
-/***************************************************************************/
-static SCB *tul_find_first_pend_scb(HCS * pCurHcb)
+static struct scsi_ctrl_blk *initio_find_first_pend_scb(struct initio_host * host)
{
- SCB *pFirstPend;
+ struct scsi_ctrl_blk *first;
- pFirstPend = pCurHcb->HCS_FirstPend;
- while (pFirstPend != NULL) {
- if (pFirstPend->SCB_Opcode != ExecSCSI) {
- return (pFirstPend);
- }
- if (pFirstPend->SCB_TagMsg == 0) {
- if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] == 0) &&
- !(pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
- return (pFirstPend);
- }
+ first = host->first_pending;
+ while (first != NULL) {
+ if (first->opcode != ExecSCSI)
+ return first;
+ if (first->tagmsg == 0) {
+ if ((host->act_tags[first->target] == 0) &&
+ !(host->targets[first->target].flags & TCF_BUSY))
+ return first;
} else {
- if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] >=
- pCurHcb->HCS_MaxTags[pFirstPend->SCB_Target]) |
- (pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
- pFirstPend = pFirstPend->SCB_NxtScb;
+ if ((host->act_tags[first->target] >=
+ host->max_tags[first->target]) |
+ (host->targets[first->target].flags & TCF_BUSY)) {
+ first = first->next;
continue;
}
- return (pFirstPend);
+ return first;
}
- pFirstPend = pFirstPend->SCB_NxtScb;
+ first = first->next;
}
-
-
- return (pFirstPend);
+ return first;
}
-/***************************************************************************/
-static void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
+
+static void initio_unlink_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- SCB *pTmpScb, *pPrevScb;
+ struct scsi_ctrl_blk *tmp, *prev;
#if DEBUG_QUEUE
- printk("unlink pend SCB %lx; ", (ULONG) pCurScb);
+ printk("unlink pend SCB %p; ", scb);
#endif
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;
- while (pTmpScb != NULL) {
- if (pCurScb == pTmpScb) { /* Unlink this SCB */
- if (pTmpScb == pCurHcb->HCS_FirstPend) {
- if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastPend = NULL;
+ prev = tmp = host->first_pending;
+ while (tmp != NULL) {
+ if (scb == tmp) { /* Unlink this SCB */
+ if (tmp == host->first_pending) {
+ if ((host->first_pending = tmp->next) == NULL)
+ host->last_pending = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastPend)
- pCurHcb->HCS_LastPend = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_pending)
+ host->last_pending = prev;
}
- pTmpScb->SCB_NxtScb = NULL;
+ tmp->next = NULL;
break;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
- return;
}
-/***************************************************************************/
-static void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
+
+static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
#if DEBUG_QUEUE
- printk("append busy SCB %lx; ", (ULONG) scbp);
+ printk("append busy SCB %o; ", scbp);
#endif
- if (scbp->SCB_TagMsg)
- pCurHcb->HCS_ActTags[scbp->SCB_Target]++;
+ if (scbp->tagmsg)
+ host->act_tags[scbp->target]++;
else
- pCurHcb->HCS_Tcs[scbp->SCB_Target].TCS_Flags |= TCF_BUSY;
- scbp->SCB_Status = SCB_BUSY;
- scbp->SCB_NxtScb = NULL;
- if (pCurHcb->HCS_LastBusy != NULL) {
- pCurHcb->HCS_LastBusy->SCB_NxtScb = scbp;
- pCurHcb->HCS_LastBusy = scbp;
+ host->targets[scbp->target].flags |= TCF_BUSY;
+ scbp->status = SCB_BUSY;
+ scbp->next = NULL;
+ if (host->last_busy != NULL) {
+ host->last_busy->next = scbp;
+ host->last_busy = scbp;
} else {
- pCurHcb->HCS_FirstBusy = scbp;
- pCurHcb->HCS_LastBusy = scbp;
+ host->first_busy = scbp;
+ host->last_busy = scbp;
}
}
/***************************************************************************/
-static SCB *tul_pop_busy_scb(HCS * pCurHcb)
+static struct scsi_ctrl_blk *initio_pop_busy_scb(struct initio_host * host)
{
- SCB *pTmpScb;
+ struct scsi_ctrl_blk *tmp;
- if ((pTmpScb = pCurHcb->HCS_FirstBusy) != NULL) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
- pTmpScb->SCB_NxtScb = NULL;
- if (pTmpScb->SCB_TagMsg)
- pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+ if ((tmp = host->first_busy) != NULL) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
+ tmp->next = NULL;
+ if (tmp->tagmsg)
+ host->act_tags[tmp->target]--;
else
- pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+ host->targets[tmp->target].flags &= ~TCF_BUSY;
}
#if DEBUG_QUEUE
- printk("Pop busy SCB %lx; ", (ULONG) pTmpScb);
+ printk("Pop busy SCB %p; ", tmp);
#endif
- return (pTmpScb);
+ return tmp;
}
/***************************************************************************/
-static void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
+static void initio_unlink_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- SCB *pTmpScb, *pPrevScb;
+ struct scsi_ctrl_blk *tmp, *prev;
#if DEBUG_QUEUE
- printk("unlink busy SCB %lx; ", (ULONG) pCurScb);
+ printk("unlink busy SCB %p; ", scb);
#endif
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
- while (pTmpScb != NULL) {
- if (pCurScb == pTmpScb) { /* Unlink this SCB */
- if (pTmpScb == pCurHcb->HCS_FirstBusy) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
+ prev = tmp = host->first_busy;
+ while (tmp != NULL) {
+ if (scb == tmp) { /* Unlink this SCB */
+ if (tmp == host->first_busy) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastBusy)
- pCurHcb->HCS_LastBusy = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_busy)
+ host->last_busy = prev;
}
- pTmpScb->SCB_NxtScb = NULL;
- if (pTmpScb->SCB_TagMsg)
- pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+ tmp->next = NULL;
+ if (tmp->tagmsg)
+ host->act_tags[tmp->target]--;
else
- pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+ host->targets[tmp->target].flags &= ~TCF_BUSY;
break;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
return;
}
-/***************************************************************************/
-SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
+struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun)
{
- SCB *pTmpScb, *pPrevScb;
- WORD scbp_tarlun;
+ struct scsi_ctrl_blk *tmp, *prev;
+ u16 scbp_tarlun;
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
- while (pTmpScb != NULL) {
- scbp_tarlun = (pTmpScb->SCB_Lun << 8) | (pTmpScb->SCB_Target);
+ prev = tmp = host->first_busy;
+ while (tmp != NULL) {
+ scbp_tarlun = (tmp->lun << 8) | (tmp->target);
if (scbp_tarlun == tarlun) { /* Unlink this SCB */
break;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
#if DEBUG_QUEUE
- printk("find busy SCB %lx; ", (ULONG) pTmpScb);
+ printk("find busy SCB %p; ", tmp);
#endif
- return (pTmpScb);
+ return tmp;
}
-/***************************************************************************/
-static void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
+static void initio_append_done_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp)
{
-
#if DEBUG_QUEUE
- printk("append done SCB %lx; ", (ULONG) scbp);
+ printk("append done SCB %p; ", scbp);
#endif
- scbp->SCB_Status = SCB_DONE;
- scbp->SCB_NxtScb = NULL;
- if (pCurHcb->HCS_LastDone != NULL) {
- pCurHcb->HCS_LastDone->SCB_NxtScb = scbp;
- pCurHcb->HCS_LastDone = scbp;
+ scbp->status = SCB_DONE;
+ scbp->next = NULL;
+ if (host->last_done != NULL) {
+ host->last_done->next = scbp;
+ host->last_done = scbp;
} else {
- pCurHcb->HCS_FirstDone = scbp;
- pCurHcb->HCS_LastDone = scbp;
+ host->first_done = scbp;
+ host->last_done = scbp;
}
}
-/***************************************************************************/
-SCB *tul_find_done_scb(HCS * pCurHcb)
+struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host)
{
- SCB *pTmpScb;
+ struct scsi_ctrl_blk *tmp;
-
- if ((pTmpScb = pCurHcb->HCS_FirstDone) != NULL) {
- if ((pCurHcb->HCS_FirstDone = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastDone = NULL;
- pTmpScb->SCB_NxtScb = NULL;
+ if ((tmp = host->first_done) != NULL) {
+ if ((host->first_done = tmp->next) == NULL)
+ host->last_done = NULL;
+ tmp->next = NULL;
}
#if DEBUG_QUEUE
- printk("find done SCB %lx; ", (ULONG) pTmpScb);
+ printk("find done SCB %p; ",tmp);
#endif
- return (pTmpScb);
+ return tmp;
}
-/***************************************************************************/
-static int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
+static int initio_abort_srb(struct initio_host * host, struct scsi_cmnd *srbp)
{
- ULONG flags;
- SCB *pTmpScb, *pPrevScb;
+ unsigned long flags;
+ struct scsi_ctrl_blk *tmp, *prev;
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+ spin_lock_irqsave(&host->semaph_lock, flags);
- if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+ if ((host->semaph == 0) && (host->active == NULL)) {
/* disable Jasmin SCSI Int */
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
+ outb(0x1F, host->addr + TUL_Mask);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
+ /* FIXME: synchronize_irq needed ? */
+ tulip_main(host);
+ spin_lock_irqsave(&host->semaph_lock, flags);
+ host->semaph = 1;
+ outb(0x0F, host->addr + TUL_Mask);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_SNOOZE;
}
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend; /* Check Pend queue */
- while (pTmpScb != NULL) {
+ prev = tmp = host->first_pending; /* Check Pend queue */
+ while (tmp != NULL) {
/* 07/27/98 */
- if (pTmpScb->SCB_Srb == srbp) {
- if (pTmpScb == pCurHcb->HCS_ActScb) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ if (tmp->srb == srbp) {
+ if (tmp == host->active) {
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_BUSY;
- } else if (pTmpScb == pCurHcb->HCS_FirstPend) {
- if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastPend = NULL;
+ } else if (tmp == host->first_pending) {
+ if ((host->first_pending = tmp->next) == NULL)
+ host->last_pending = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastPend)
- pCurHcb->HCS_LastPend = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_pending)
+ host->last_pending = prev;
}
- pTmpScb->SCB_HaStat = HOST_ABORTED;
- pTmpScb->SCB_Flags |= SCF_DONE;
- if (pTmpScb->SCB_Flags & SCF_POST)
- (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ tmp->hastat = HOST_ABORTED;
+ tmp->flags |= SCF_DONE;
+ if (tmp->flags & SCF_POST)
+ (*tmp->post) ((u8 *) host, (u8 *) tmp);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_SUCCESS;
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy; /* Check Busy queue */
- while (pTmpScb != NULL) {
-
- if (pTmpScb->SCB_Srb == srbp) {
-
- if (pTmpScb == pCurHcb->HCS_ActScb) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ prev = tmp = host->first_busy; /* Check Busy queue */
+ while (tmp != NULL) {
+ if (tmp->srb == srbp) {
+ if (tmp == host->active) {
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_BUSY;
- } else if (pTmpScb->SCB_TagMsg == 0) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ } else if (tmp->tagmsg == 0) {
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_BUSY;
} else {
- pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
- if (pTmpScb == pCurHcb->HCS_FirstBusy) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
+ host->act_tags[tmp->target]--;
+ if (tmp == host->first_busy) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastBusy)
- pCurHcb->HCS_LastBusy = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_busy)
+ host->last_busy = prev;
}
- pTmpScb->SCB_NxtScb = NULL;
+ tmp->next = NULL;
- pTmpScb->SCB_HaStat = HOST_ABORTED;
- pTmpScb->SCB_Flags |= SCF_DONE;
- if (pTmpScb->SCB_Flags & SCF_POST)
- (*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ tmp->hastat = HOST_ABORTED;
+ tmp->flags |= SCF_DONE;
+ if (tmp->flags & SCF_POST)
+ (*tmp->post) ((u8 *) host, (u8 *) tmp);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return SCSI_ABORT_SUCCESS;
}
}
- pPrevScb = pTmpScb;
- pTmpScb = pTmpScb->SCB_NxtScb;
+ prev = tmp;
+ tmp = tmp->next;
}
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return (SCSI_ABORT_NOT_RUNNING);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
+ return SCSI_ABORT_NOT_RUNNING;
}
/***************************************************************************/
-static int tul_bad_seq(HCS * pCurHcb)
+static int initio_bad_seq(struct initio_host * host)
{
- SCB *pCurScb;
-
- printk("tul_bad_seg c=%d\n", pCurHcb->HCS_Index);
-
- if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
- tul_unlink_busy_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- pCurScb->SCB_TaStat = 0;
- tul_append_done_scb(pCurHcb, pCurScb);
- }
- tul_stop_bm(pCurHcb);
-
- tul_reset_scsi(pCurHcb, 8); /* 7/29/98 */
-
- return (tul_post_scsi_rst(pCurHcb));
-}
-
-#if 0
-
-/************************************************************************/
-static int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
- unsigned int target, unsigned int ResetFlags)
-{
- ULONG flags;
- SCB *pScb;
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- if (ResetFlags & SCSI_RESET_ASYNCHRONOUS) {
-
- if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- /* disable Jasmin SCSI Int */
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- return SCSI_RESET_SNOOZE;
- }
- pScb = pCurHcb->HCS_FirstBusy; /* Check Busy queue */
- while (pScb != NULL) {
- if (pScb->SCB_Srb == pSrb)
- break;
- pScb = pScb->SCB_NxtScb;
- }
- if (pScb == NULL) {
- printk("Unable to Reset - No SCB Found\n");
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return SCSI_RESET_NOT_RUNNING;
- }
- }
- if ((pScb = tul_alloc_scb(pCurHcb)) == NULL) {
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return SCSI_RESET_NOT_RUNNING;
- }
- pScb->SCB_Opcode = BusDevRst;
- pScb->SCB_Flags = SCF_POST;
- pScb->SCB_Target = target;
- pScb->SCB_Mode = 0;
-
- pScb->SCB_Srb = NULL;
- if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
- pScb->SCB_Srb = pSrb;
- }
- tul_push_pend_scb(pCurHcb, pScb); /* push this SCB to Pending queue */
-
- if (pCurHcb->HCS_Semaph == 1) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- /* disable Jasmin SCSI Int */
- pCurHcb->HCS_Semaph = 0;
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ struct scsi_ctrl_blk *scb;
- tulip_main(pCurHcb);
+ printk("initio_bad_seg c=%d\n", host->index);
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+ if ((scb = host->active) != NULL) {
+ initio_unlink_busy_scb(host, scb);
+ scb->hastat = HOST_BAD_PHAS;
+ scb->tastat = 0;
+ initio_append_done_scb(host, scb);
}
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return SCSI_RESET_PENDING;
+ initio_stop_bm(host);
+ initio_reset_scsi(host, 8); /* 7/29/98 */
+ return initio_post_scsi_rst(host);
}
-static int tul_reset_scsi_bus(HCS * pCurHcb)
-{
- ULONG flags;
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- pCurHcb->HCS_Semaph = 0;
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tul_stop_bm(pCurHcb);
-
- tul_reset_scsi(pCurHcb, 2); /* 7/29/98 */
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
- tul_post_scsi_rst(pCurHcb);
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
-
- tulip_main(pCurHcb);
-
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
- return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
-}
-
-#endif /* 0 */
/************************************************************************/
-static void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
+static void initio_exec_scb(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- ULONG flags;
+ unsigned long flags;
- pCurScb->SCB_Mode = 0;
+ scb->mode = 0;
- pCurScb->SCB_SGIdx = 0;
- pCurScb->SCB_SGMax = pCurScb->SCB_SGLen;
+ scb->sgidx = 0;
+ scb->sgmax = scb->sglen;
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+ spin_lock_irqsave(&host->semaph_lock, flags);
- tul_append_pend_scb(pCurHcb, pCurScb); /* Append this SCB to Pending queue */
+ initio_append_pend_scb(host, scb); /* Append this SCB to Pending queue */
/* VVVVV 07/21/98 */
- if (pCurHcb->HCS_Semaph == 1) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
- /* disable Jasmin SCSI Int */
- pCurHcb->HCS_Semaph = 0;
-
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ if (host->semaph == 1) {
+ /* Disable Jasmin SCSI Int */
+ outb(0x1F, host->addr + TUL_Mask);
+ host->semaph = 0;
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
- tulip_main(pCurHcb);
+ tulip_main(host);
- spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
-
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+ spin_lock_irqsave(&host->semaph_lock, flags);
+ host->semaph = 1;
+ outb(0x0F, host->addr + TUL_Mask);
}
- spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+ spin_unlock_irqrestore(&host->semaph_lock, flags);
return;
}
/***************************************************************************/
-static int tul_isr(HCS * pCurHcb)
+static int initio_isr(struct initio_host * host)
{
- /* Enter critical section */
-
- if (TUL_RD(pCurHcb->HCS_Base, TUL_Int) & TSS_INT_PENDING) {
- if (pCurHcb->HCS_Semaph == 1) {
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+ if (inb(host->addr + TUL_Int) & TSS_INT_PENDING) {
+ if (host->semaph == 1) {
+ outb(0x1F, host->addr + TUL_Mask);
/* Disable Tulip SCSI Int */
- pCurHcb->HCS_Semaph = 0;
+ host->semaph = 0;
- tulip_main(pCurHcb);
+ tulip_main(host);
- pCurHcb->HCS_Semaph = 1;
- TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
- return (1);
+ host->semaph = 1;
+ outb(0x0F, host->addr + TUL_Mask);
+ return 1;
}
}
- return (0);
+ return 0;
}
-/***************************************************************************/
-int tulip_main(HCS * pCurHcb)
+static int tulip_main(struct initio_host * host)
{
- SCB *pCurScb;
+ struct scsi_ctrl_blk *scb;
for (;;) {
-
- tulip_scsi(pCurHcb); /* Call tulip_scsi */
-
- while ((pCurScb = tul_find_done_scb(pCurHcb)) != NULL) { /* find done entry */
- if (pCurScb->SCB_TaStat == INI_QUEUE_FULL) {
- pCurHcb->HCS_MaxTags[pCurScb->SCB_Target] =
- pCurHcb->HCS_ActTags[pCurScb->SCB_Target] - 1;
- pCurScb->SCB_TaStat = 0;
- tul_append_pend_scb(pCurHcb, pCurScb);
+ tulip_scsi(host); /* Call tulip_scsi */
+
+ /* Walk the list of completed SCBs */
+ while ((scb = initio_find_done_scb(host)) != NULL) { /* find done entry */
+ if (scb->tastat == INI_QUEUE_FULL) {
+ host->max_tags[scb->target] =
+ host->act_tags[scb->target] - 1;
+ scb->tastat = 0;
+ initio_append_pend_scb(host, scb);
continue;
}
- if (!(pCurScb->SCB_Mode & SCM_RSENS)) { /* not in auto req. sense mode */
- if (pCurScb->SCB_TaStat == 2) {
+ if (!(scb->mode & SCM_RSENS)) { /* not in auto req. sense mode */
+ if (scb->tastat == 2) {
/* clr sync. nego flag */
- if (pCurScb->SCB_Flags & SCF_SENSE) {
- BYTE len;
- len = pCurScb->SCB_SenseLen;
+ if (scb->flags & SCF_SENSE) {
+ u8 len;
+ len = scb->senselen;
if (len == 0)
len = 1;
- pCurScb->SCB_BufLen = pCurScb->SCB_SenseLen;
- pCurScb->SCB_BufPtr = pCurScb->SCB_SensePtr;
- pCurScb->SCB_Flags &= ~(SCF_SG | SCF_DIR); /* for xfer_data_in */
-/* pCurScb->SCB_Flags |= SCF_NO_DCHK; */
- /* so, we won't report worng direction in xfer_data_in,
+ scb->buflen = scb->senselen;
+ scb->bufptr = scb->senseptr;
+ scb->flags &= ~(SCF_SG | SCF_DIR); /* for xfer_data_in */
+ /* so, we won't report wrong direction in xfer_data_in,
and won't report HOST_DO_DU in state_6 */
- pCurScb->SCB_Mode = SCM_RSENS;
- pCurScb->SCB_Ident &= 0xBF; /* Disable Disconnect */
- pCurScb->SCB_TagMsg = 0;
- pCurScb->SCB_TaStat = 0;
- pCurScb->SCB_CDBLen = 6;
- pCurScb->SCB_CDB[0] = SCSICMD_RequestSense;
- pCurScb->SCB_CDB[1] = 0;
- pCurScb->SCB_CDB[2] = 0;
- pCurScb->SCB_CDB[3] = 0;
- pCurScb->SCB_CDB[4] = len;
- pCurScb->SCB_CDB[5] = 0;
- tul_push_pend_scb(pCurHcb, pCurScb);
+ scb->mode = SCM_RSENS;
+ scb->ident &= 0xBF; /* Disable Disconnect */
+ scb->tagmsg = 0;
+ scb->tastat = 0;
+ scb->cdblen = 6;
+ scb->cdb[0] = SCSICMD_RequestSense;
+ scb->cdb[1] = 0;
+ scb->cdb[2] = 0;
+ scb->cdb[3] = 0;
+ scb->cdb[4] = len;
+ scb->cdb[5] = 0;
+ initio_push_pend_scb(host, scb);
break;
}
}
} else { /* in request sense mode */
- if (pCurScb->SCB_TaStat == 2) { /* check contition status again after sending
+ if (scb->tastat == 2) { /* check contition status again after sending
requset sense cmd 0x3 */
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+ scb->hastat = HOST_BAD_PHAS;
}
- pCurScb->SCB_TaStat = 2;
+ scb->tastat = 2;
}
- pCurScb->SCB_Flags |= SCF_DONE;
- if (pCurScb->SCB_Flags & SCF_POST) {
- (*pCurScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pCurScb);
+ scb->flags |= SCF_DONE;
+ if (scb->flags & SCF_POST) {
+ /* FIXME: only one post method and lose casts */
+ (*scb->post) ((u8 *) host, (u8 *) scb);
}
} /* while */
-
/* find_active: */
- if (TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0) & TSS_INT_PENDING)
+ if (inb(host->addr + TUL_SStatus0) & TSS_INT_PENDING)
continue;
-
- if (pCurHcb->HCS_ActScb) { /* return to OS and wait for xfer_done_ISR/Selected_ISR */
+ if (host->active) /* return to OS and wait for xfer_done_ISR/Selected_ISR */
return 1; /* return to OS, enable interrupt */
- }
/* Check pending SCB */
- if (tul_find_first_pend_scb(pCurHcb) == NULL) {
+ if (initio_find_first_pend_scb(host) == NULL)
return 1; /* return to OS, enable interrupt */
- }
} /* End of for loop */
/* statement won't reach here */
}
-
-
-
-/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
-/***************************************************************************/
-/***************************************************************************/
-/***************************************************************************/
-/***************************************************************************/
-
-/***************************************************************************/
-void tulip_scsi(HCS * pCurHcb)
+static void tulip_scsi(struct initio_host * host)
{
- SCB *pCurScb;
- TCS *pCurTcb;
+ struct scsi_ctrl_blk *scb;
+ struct target_control *active_tc;
/* make sure to service interrupt asap */
-
- if ((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0)) & TSS_INT_PENDING) {
-
- pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
- pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* SCSI bus reset detected */
- int_tul_scsi_rst(pCurHcb);
+ if ((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING) {
+ host->phase = host->jsstatus0 & TSS_PH_MASK;
+ host->jsstatus1 = inb(host->addr + TUL_SStatus1);
+ host->jsint = inb(host->addr + TUL_SInt);
+ if (host->jsint & TSS_SCSIRST_INT) { /* SCSI bus reset detected */
+ int_initio_scsi_rst(host);
return;
}
- if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) { /* if selected/reselected interrupt */
- if (int_tul_resel(pCurHcb) == 0)
- tul_next_state(pCurHcb);
+ if (host->jsint & TSS_RESEL_INT) { /* if selected/reselected interrupt */
+ if (int_initio_resel(host) == 0)
+ initio_next_state(host);
return;
}
- if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {
- int_tul_busfree(pCurHcb);
+ if (host->jsint & TSS_SEL_TIMEOUT) {
+ int_initio_busfree(host);
return;
}
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- int_tul_busfree(pCurHcb); /* unexpected bus free or sel timeout */
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ int_initio_busfree(host); /* unexpected bus free or sel timeout */
return;
}
- if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) { /* func complete or Bus service */
- if ((pCurScb = pCurHcb->HCS_ActScb) != NULL)
- tul_next_state(pCurHcb);
+ if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV)) { /* func complete or Bus service */
+ if ((scb = host->active) != NULL)
+ initio_next_state(host);
return;
}
}
- if (pCurHcb->HCS_ActScb != NULL)
+ if (host->active != NULL)
return;
- if ((pCurScb = tul_find_first_pend_scb(pCurHcb)) == NULL)
+ if ((scb = initio_find_first_pend_scb(host)) == NULL)
return;
/* program HBA's SCSI ID & target SCSI ID */
- TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId,
- (pCurHcb->HCS_SCSI_ID << 4) | (pCurScb->SCB_Target & 0x0F));
- if (pCurScb->SCB_Opcode == ExecSCSI) {
- pCurTcb = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+ outb((host->scsi_id << 4) | (scb->target & 0x0F),
+ host->addr + TUL_SScsiId);
+ if (scb->opcode == ExecSCSI) {
+ active_tc = &host->targets[scb->target];
- if (pCurScb->SCB_TagMsg)
- pCurTcb->TCS_DrvFlags |= TCF_DRV_EN_TAG;
+ if (scb->tagmsg)
+ active_tc->drv_flags |= TCF_DRV_EN_TAG;
else
- pCurTcb->TCS_DrvFlags &= ~TCF_DRV_EN_TAG;
+ active_tc->drv_flags &= ~TCF_DRV_EN_TAG;
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
- if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { /* do wdtr negotiation */
- tul_select_atn_stop(pCurHcb, pCurScb);
+ outb(active_tc->js_period, host->addr + TUL_SPeriod);
+ if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { /* do wdtr negotiation */
+ initio_select_atn_stop(host, scb);
} else {
- if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync negotiation */
- tul_select_atn_stop(pCurHcb, pCurScb);
+ if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync negotiation */
+ initio_select_atn_stop(host, scb);
} else {
- if (pCurScb->SCB_TagMsg)
- tul_select_atn3(pCurHcb, pCurScb);
+ if (scb->tagmsg)
+ initio_select_atn3(host, scb);
else
- tul_select_atn(pCurHcb, pCurScb);
+ initio_select_atn(host, scb);
}
}
- if (pCurScb->SCB_Flags & SCF_POLL) {
- while (wait_tulip(pCurHcb) != -1) {
- if (tul_next_state(pCurHcb) == -1)
+ if (scb->flags & SCF_POLL) {
+ while (wait_tulip(host) != -1) {
+ if (initio_next_state(host) == -1)
break;
}
}
- } else if (pCurScb->SCB_Opcode == BusDevRst) {
- tul_select_atn_stop(pCurHcb, pCurScb);
- pCurScb->SCB_NxtStat = 8;
- if (pCurScb->SCB_Flags & SCF_POLL) {
- while (wait_tulip(pCurHcb) != -1) {
- if (tul_next_state(pCurHcb) == -1)
+ } else if (scb->opcode == BusDevRst) {
+ initio_select_atn_stop(host, scb);
+ scb->next_state = 8;
+ if (scb->flags & SCF_POLL) {
+ while (wait_tulip(host) != -1) {
+ if (initio_next_state(host) == -1)
break;
}
}
- } else if (pCurScb->SCB_Opcode == AbortCmd) {
- if (tul_abort_srb(pCurHcb, pCurScb->SCB_Srb) != 0) {
-
-
- tul_unlink_pend_scb(pCurHcb, pCurScb);
-
- tul_release_scb(pCurHcb, pCurScb);
+ } else if (scb->opcode == AbortCmd) {
+ if (initio_abort_srb(host, scb->srb) != 0) {
+ initio_unlink_pend_scb(host, scb);
+ initio_release_scb(host, scb);
} else {
- pCurScb->SCB_Opcode = BusDevRst;
- tul_select_atn_stop(pCurHcb, pCurScb);
- pCurScb->SCB_NxtStat = 8;
+ scb->opcode = BusDevRst;
+ initio_select_atn_stop(host, scb);
+ scb->next_state = 8;
}
-
-/* 08/03/98 */
} else {
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = 0x16; /* bad command */
- tul_append_done_scb(pCurHcb, pCurScb);
+ initio_unlink_pend_scb(host, scb);
+ scb->hastat = 0x16; /* bad command */
+ initio_append_done_scb(host, scb);
}
return;
}
+/**
+ * initio_next_state - Next SCSI state
+ * @host: InitIO host we are processing
+ *
+ * Progress the active command block along the state machine
+ * until we hit a state which we must wait for activity to occur.
+ *
+ * Returns zero or a negative code.
+ */
-/***************************************************************************/
-int tul_next_state(HCS * pCurHcb)
+static int initio_next_state(struct initio_host * host)
{
int next;
- next = pCurHcb->HCS_ActScb->SCB_NxtStat;
+ next = host->active->next_state;
for (;;) {
switch (next) {
case 1:
- next = tul_state_1(pCurHcb);
+ next = initio_state_1(host);
break;
case 2:
- next = tul_state_2(pCurHcb);
+ next = initio_state_2(host);
break;
case 3:
- next = tul_state_3(pCurHcb);
+ next = initio_state_3(host);
break;
case 4:
- next = tul_state_4(pCurHcb);
+ next = initio_state_4(host);
break;
case 5:
- next = tul_state_5(pCurHcb);
+ next = initio_state_5(host);
break;
case 6:
- next = tul_state_6(pCurHcb);
+ next = initio_state_6(host);
break;
case 7:
- next = tul_state_7(pCurHcb);
+ next = initio_state_7(host);
break;
case 8:
- return (tul_bus_device_reset(pCurHcb));
+ return initio_bus_device_reset(host);
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
if (next <= 0)
return next;
@@ -1554,338 +1314,363 @@ int tul_next_state(HCS * pCurHcb)
}
-/***************************************************************************/
-/* sTate after selection with attention & stop */
-int tul_state_1(HCS * pCurHcb)
+/**
+ * initio_state_1 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * Perform SCSI state processing for Select/Attention/Stop
+ */
+
+static int initio_state_1(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
#if DEBUG_STATE
printk("-s1-");
#endif
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- tul_append_busy_scb(pCurHcb, pCurScb);
+ /* Move the SCB from pending to busy */
+ initio_unlink_pend_scb(host, scb);
+ initio_append_busy_scb(host, scb);
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+ outb(active_tc->sconfig0, host->addr + TUL_SConfig );
/* ATN on */
- if (pCurHcb->HCS_Phase == MSG_OUT) {
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, (TSC_EN_BUS_IN | TSC_HW_RESELECT));
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
-
- if (pCurScb->SCB_TagMsg) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
- }
- if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
-
- pCurTcb->TCS_Flags |= TCF_WDTR_DONE;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2); /* Extended msg length */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3); /* Sync request */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1); /* Start from 16 bits */
- } else if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
-
- pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3); /* extended msg length */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1); /* sync request */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET); /* REQ/ACK offset */
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
- return (3);
-}
-
+ if (host->phase == MSG_OUT) {
+ outb(TSC_EN_BUS_IN | TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
+ outb(scb->ident, host->addr + TUL_SFifo);
+
+ if (scb->tagmsg) {
+ outb(scb->tagmsg, host->addr + TUL_SFifo);
+ outb(scb->tagid, host->addr + TUL_SFifo);
+ }
+ if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
+ active_tc->flags |= TCF_WDTR_DONE;
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(2, host->addr + TUL_SFifo); /* Extended msg length */
+ outb(3, host->addr + TUL_SFifo); /* Sync request */
+ outb(1, host->addr + TUL_SFifo); /* Start from 16 bits */
+ } else if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
+ active_tc->flags |= TCF_SYNC_DONE;
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo); /* extended msg length */
+ outb(1, host->addr + TUL_SFifo); /* sync request */
+ outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo);
+ outb(MAX_OFFSET, host->addr + TUL_SFifo); /* REQ/ACK offset */
+ }
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ }
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal);
+ /* Into before CDB xfer */
+ return 3;
+}
+
+
+/**
+ * initio_state_2 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * state after selection with attention
+ * state after selection with attention3
+ */
-/***************************************************************************/
-/* state after selection with attention */
-/* state after selection with attention3 */
-int tul_state_2(HCS * pCurHcb)
+static int initio_state_2(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
#if DEBUG_STATE
printk("-s2-");
#endif
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- tul_append_busy_scb(pCurHcb, pCurScb);
+ initio_unlink_pend_scb(host, scb);
+ initio_append_busy_scb(host, scb);
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+ outb(active_tc->sconfig0, host->addr + TUL_SConfig);
- if (pCurHcb->HCS_JSStatus1 & TSS_CMD_PH_CMP) {
- return (4);
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
- return (3);
+ if (host->jsstatus1 & TSS_CMD_PH_CMP)
+ return 4;
+
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal);
+ /* Into before CDB xfer */
+ return 3;
}
-/***************************************************************************/
-/* state before CDB xfer is done */
-int tul_state_3(HCS * pCurHcb)
+/**
+ * initio_state_3 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * state before CDB xfer is done
+ */
+
+static int initio_state_3(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
int i;
#if DEBUG_STATE
printk("-s3-");
#endif
for (;;) {
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case CMD_OUT: /* Command out phase */
- for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase == CMD_OUT) {
- return (tul_bad_seq(pCurHcb));
- }
- return (4);
+ for (i = 0; i < (int) scb->cdblen; i++)
+ outb(scb->cdb[i], host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ if (host->phase == CMD_OUT)
+ return initio_bad_seq(host);
+ return 4;
case MSG_IN: /* Message in phase */
- pCurScb->SCB_NxtStat = 3;
- if (tul_msgin(pCurHcb) == -1)
- return (-1);
+ scb->next_state = 3;
+ if (initio_msgin(host) == -1)
+ return -1;
break;
case STATUS_IN: /* Status phase */
- if (tul_status_msg(pCurHcb) == -1)
- return (-1);
+ if (initio_status_msg(host) == -1)
+ return -1;
break;
case MSG_OUT: /* Message out phase */
- if (pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP); /* msg nop */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
-
+ if (active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
+ outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
} else {
- pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3); /* ext. msg len */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1); /* sync request */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET); /* REQ/ACK offset */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7));
+ active_tc->flags |= TCF_SYNC_DONE;
+
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo); /* ext. msg len */
+ outb(1, host->addr + TUL_SFifo); /* sync request */
+ outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo);
+ outb(MAX_OFFSET, host->addr + TUL_SFifo); /* REQ/ACK offset */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb(inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7), host->addr + TUL_SSignal);
}
break;
-
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
}
}
+/**
+ * initio_state_4 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * SCSI state machine. State 4
+ */
-/***************************************************************************/
-int tul_state_4(HCS * pCurHcb)
+static int initio_state_4(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
#if DEBUG_STATE
printk("-s4-");
#endif
- if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) {
- return (6); /* Go to state 6 */
+ if ((scb->flags & SCF_DIR) == SCF_NO_XF) {
+ return 6; /* Go to state 6 (After data) */
}
for (;;) {
- if (pCurScb->SCB_BufLen == 0)
- return (6); /* Go to state 6 */
+ if (scb->buflen == 0)
+ return 6;
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case STATUS_IN: /* Status phase */
- if ((pCurScb->SCB_Flags & SCF_DIR) != 0) { /* if direction bit set then report data underrun */
- pCurScb->SCB_HaStat = HOST_DO_DU;
- }
- if ((tul_status_msg(pCurHcb)) == -1)
- return (-1);
+ if ((scb->flags & SCF_DIR) != 0) /* if direction bit set then report data underrun */
+ scb->hastat = HOST_DO_DU;
+ if ((initio_status_msg(host)) == -1)
+ return -1;
break;
case MSG_IN: /* Message in phase */
- pCurScb->SCB_NxtStat = 0x4;
- if (tul_msgin(pCurHcb) == -1)
- return (-1);
+ scb->next_state = 0x4;
+ if (initio_msgin(host) == -1)
+ return -1;
break;
case MSG_OUT: /* Message out phase */
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
- pCurScb->SCB_BufLen = 0;
- pCurScb->SCB_HaStat = HOST_DO_DU;
- if (tul_msgout_ide(pCurHcb) == -1)
- return (-1);
- return (6); /* Go to state 6 */
+ if (host->jsstatus0 & TSS_PAR_ERROR) {
+ scb->buflen = 0;
+ scb->hastat = HOST_DO_DU;
+ if (initio_msgout_ide(host) == -1)
+ return -1;
+ return 6;
} else {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP); /* msg nop */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
+ outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
}
break;
case DATA_IN: /* Data in phase */
- return (tul_xfer_data_in(pCurHcb));
+ return initio_xfer_data_in(host);
case DATA_OUT: /* Data out phase */
- return (tul_xfer_data_out(pCurHcb));
+ return initio_xfer_data_out(host);
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
}
}
-/***************************************************************************/
-/* state after dma xfer done or phase change before xfer done */
-int tul_state_5(HCS * pCurHcb)
+/**
+ * initio_state_5 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * State after dma xfer done or phase change before xfer done
+ */
+
+static int initio_state_5(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
long cnt, xcnt; /* cannot use unsigned !! code: if (xcnt < 0) */
#if DEBUG_STATE
printk("-s5-");
#endif
-/*------ get remaining count -------*/
-
- cnt = TUL_RDLONG(pCurHcb->HCS_Base, TUL_SCnt0) & 0x0FFFFFF;
+ /*------ get remaining count -------*/
+ cnt = inl(host->addr + TUL_SCnt0) & 0x0FFFFFF;
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XCmd) & 0x20) {
+ if (inb(host->addr + TUL_XCmd) & 0x20) {
/* ----------------------- DATA_IN ----------------------------- */
/* check scsi parity error */
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
- pCurScb->SCB_HaStat = HOST_DO_DU;
- }
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* DMA xfer pending, Send STOP */
+ if (host->jsstatus0 & TSS_PAR_ERROR)
+ scb->hastat = HOST_DO_DU;
+ if (inb(host->addr + TUL_XStatus) & XPEND) { /* DMA xfer pending, Send STOP */
/* tell Hardware scsi xfer has been terminated */
- TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, TUL_RD(pCurHcb->HCS_Base, TUL_XCtrl) | 0x80);
+ outb(inb(host->addr + TUL_XCtrl) | 0x80, host->addr + TUL_XCtrl);
/* wait until DMA xfer not pending */
- while (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND);
+ while (inb(host->addr + TUL_XStatus) & XPEND)
+ cpu_relax();
}
} else {
-/*-------- DATA OUT -----------*/
- if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0) {
- if (pCurHcb->HCS_ActTcs->TCS_JS_Period & TSC_WIDE_SCSI)
- cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F) << 1;
+ /*-------- DATA OUT -----------*/
+ if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0) {
+ if (host->active_tc->js_period & TSC_WIDE_SCSI)
+ cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F) << 1;
else
- cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F);
+ cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F);
}
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT);
+ if (inb(host->addr + TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
+ outb(TAX_X_ABT, host->addr + TUL_XCmd);
/* wait Abort DMA xfer done */
- while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+ while ((inb(host->addr + TUL_Int) & XABT) == 0)
+ cpu_relax();
}
- if ((cnt == 1) && (pCurHcb->HCS_Phase == DATA_OUT)) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1) {
- return (-1);
- }
+ if ((cnt == 1) && (host->phase == DATA_OUT)) {
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
cnt = 0;
} else {
- if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0)
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0)
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
}
}
-
if (cnt == 0) {
- pCurScb->SCB_BufLen = 0;
- return (6); /* Go to state 6 */
+ scb->buflen = 0;
+ return 6; /* After Data */
}
/* Update active data pointer */
- xcnt = (long) pCurScb->SCB_BufLen - cnt; /* xcnt== bytes already xferred */
- pCurScb->SCB_BufLen = (U32) cnt; /* cnt == bytes left to be xferred */
- if (pCurScb->SCB_Flags & SCF_SG) {
- register SG *sgp;
- ULONG i;
-
- sgp = &pCurScb->SCB_SGList[pCurScb->SCB_SGIdx];
- for (i = pCurScb->SCB_SGIdx; i < pCurScb->SCB_SGMax; sgp++, i++) {
- xcnt -= (long) sgp->SG_Len;
+ xcnt = (long) scb->buflen - cnt; /* xcnt== bytes already xferred */
+ scb->buflen = (u32) cnt; /* cnt == bytes left to be xferred */
+ if (scb->flags & SCF_SG) {
+ struct sg_entry *sgp;
+ unsigned long i;
+
+ sgp = &scb->sglist[scb->sgidx];
+ for (i = scb->sgidx; i < scb->sgmax; sgp++, i++) {
+ xcnt -= (long) sgp->len;
if (xcnt < 0) { /* this sgp xfer half done */
- xcnt += (long) sgp->SG_Len; /* xcnt == bytes xferred in this sgp */
- sgp->SG_Ptr += (U32) xcnt; /* new ptr to be xfer */
- sgp->SG_Len -= (U32) xcnt; /* new len to be xfer */
- pCurScb->SCB_BufPtr += ((U32) (i - pCurScb->SCB_SGIdx) << 3);
+ xcnt += (long) sgp->len; /* xcnt == bytes xferred in this sgp */
+ sgp->data += (u32) xcnt; /* new ptr to be xfer */
+ sgp->len -= (u32) xcnt; /* new len to be xfer */
+ scb->bufptr += ((u32) (i - scb->sgidx) << 3);
/* new SG table ptr */
- pCurScb->SCB_SGLen = (BYTE) (pCurScb->SCB_SGMax - i);
+ scb->sglen = (u8) (scb->sgmax - i);
/* new SG table len */
- pCurScb->SCB_SGIdx = (WORD) i;
+ scb->sgidx = (u16) i;
/* for next disc and come in this loop */
- return (4); /* Go to state 4 */
+ return 4; /* Go to state 4 */
}
/* else (xcnt >= 0 , i.e. this sgp already xferred */
} /* for */
- return (6); /* Go to state 6 */
+ return 6; /* Go to state 6 */
} else {
- pCurScb->SCB_BufPtr += (U32) xcnt;
+ scb->bufptr += (u32) xcnt;
}
- return (4); /* Go to state 4 */
+ return 4; /* Go to state 4 */
}
-/***************************************************************************/
-/* state after Data phase */
-int tul_state_6(HCS * pCurHcb)
+/**
+ * initio_state_6 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ * State after Data phase
+ */
+
+static int initio_state_6(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
#if DEBUG_STATE
printk("-s6-");
#endif
for (;;) {
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case STATUS_IN: /* Status phase */
- if ((tul_status_msg(pCurHcb)) == -1)
- return (-1);
+ if ((initio_status_msg(host)) == -1)
+ return -1;
break;
case MSG_IN: /* Message in phase */
- pCurScb->SCB_NxtStat = 6;
- if ((tul_msgin(pCurHcb)) == -1)
- return (-1);
+ scb->next_state = 6;
+ if ((initio_msgin(host)) == -1)
+ return -1;
break;
case MSG_OUT: /* Message out phase */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP); /* msg nop */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
+ outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
break;
case DATA_IN: /* Data in phase */
- return (tul_xpad_in(pCurHcb));
+ return initio_xpad_in(host);
case DATA_OUT: /* Data out phase */
- return (tul_xpad_out(pCurHcb));
+ return initio_xpad_out(host);
default:
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
}
}
-/***************************************************************************/
-int tul_state_7(HCS * pCurHcb)
+/**
+ * initio_state_7 - SCSI state machine
+ * @host: InitIO host we are controlling
+ *
+ */
+
+int initio_state_7(struct initio_host * host)
{
int cnt, i;
@@ -1893,1139 +1678,1029 @@ int tul_state_7(HCS * pCurHcb)
printk("-s7-");
#endif
/* flush SCSI FIFO */
- cnt = TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F;
+ cnt = inb(host->addr + TUL_SFifoCnt) & 0x1F;
if (cnt) {
for (i = 0; i < cnt; i++)
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+ inb(host->addr + TUL_SFifo);
}
- switch (pCurHcb->HCS_Phase) {
+ switch (host->phase) {
case DATA_IN: /* Data in phase */
case DATA_OUT: /* Data out phase */
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
default:
- return (6); /* Go to state 6 */
+ return 6; /* Go to state 6 */
}
}
-/***************************************************************************/
-int tul_xfer_data_in(HCS * pCurHcb)
+/**
+ * initio_xfer_data_in - Commence data input
+ * @host: InitIO host in use
+ *
+ * Commence a block of data transfer. The transfer itself will
+ * be managed by the controller and we will get a completion (or
+ * failure) interrupt.
+ */
+static int initio_xfer_data_in(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
- if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DOUT) {
- return (6); /* wrong direction */
- }
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+ if ((scb->flags & SCF_DIR) == SCF_DOUT)
+ return 6; /* wrong direction */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_IN); /* 7/25/95 */
+ outl(scb->buflen, host->addr + TUL_SCnt0);
+ outb(TSC_XF_DMA_IN, host->addr + TUL_SCmd); /* 7/25/95 */
- if (pCurScb->SCB_Flags & SCF_SG) { /* S/G xfer */
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_IN);
+ if (scb->flags & SCF_SG) { /* S/G xfer */
+ outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_SG_IN, host->addr + TUL_XCmd);
} else {
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_IN);
+ outl(scb->buflen, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_X_IN, host->addr + TUL_XCmd);
}
- pCurScb->SCB_NxtStat = 0x5;
- return (0); /* return to OS, wait xfer done , let jas_isr come in */
+ scb->next_state = 0x5;
+ return 0; /* return to OS, wait xfer done , let jas_isr come in */
}
+/**
+ * initio_xfer_data_out - Commence data output
+ * @host: InitIO host in use
+ *
+ * Commence a block of data transfer. The transfer itself will
+ * be managed by the controller and we will get a completion (or
+ * failure) interrupt.
+ */
-/***************************************************************************/
-int tul_xfer_data_out(HCS * pCurHcb)
+static int initio_xfer_data_out(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
- if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DIN) {
- return (6); /* wrong direction */
- }
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_OUT);
+ if ((scb->flags & SCF_DIR) == SCF_DIN)
+ return 6; /* wrong direction */
- if (pCurScb->SCB_Flags & SCF_SG) { /* S/G xfer */
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_OUT);
+ outl(scb->buflen, host->addr + TUL_SCnt0);
+ outb(TSC_XF_DMA_OUT, host->addr + TUL_SCmd);
+
+ if (scb->flags & SCF_SG) { /* S/G xfer */
+ outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_SG_OUT, host->addr + TUL_XCmd);
} else {
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_OUT);
+ outl(scb->buflen, host->addr + TUL_XCntH);
+ outl(scb->bufptr, host->addr + TUL_XAddH);
+ outb(TAX_X_OUT, host->addr + TUL_XCmd);
}
- pCurScb->SCB_NxtStat = 0x5;
- return (0); /* return to OS, wait xfer done , let jas_isr come in */
+ scb->next_state = 0x5;
+ return 0; /* return to OS, wait xfer done , let jas_isr come in */
}
-
-/***************************************************************************/
-int tul_xpad_in(HCS * pCurHcb)
+int initio_xpad_in(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
- if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
- pCurScb->SCB_HaStat = HOST_DO_DU; /* over run */
- }
+ if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
+ scb->hastat = HOST_DO_DU; /* over run */
for (;;) {
- if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+ if (active_tc->js_period & TSC_WIDE_SCSI)
+ outl(2, host->addr + TUL_SCnt0);
else
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+ outl(1, host->addr + TUL_SCnt0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1) {
- return (-1);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ if (host->phase != DATA_IN) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ return 6;
}
- if (pCurHcb->HCS_Phase != DATA_IN) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- return (6);
- }
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+ inb(host->addr + TUL_SFifo);
}
}
-int tul_xpad_out(HCS * pCurHcb)
+int initio_xpad_out(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
- if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
- pCurScb->SCB_HaStat = HOST_DO_DU; /* over run */
- }
+ if ((scb->flags & SCF_DIR) != SCF_NO_DCHK)
+ scb->hastat = HOST_DO_DU; /* over run */
for (;;) {
- if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+ if (active_tc->js_period & TSC_WIDE_SCSI)
+ outl(2, host->addr + TUL_SCnt0);
else
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+ outl(1, host->addr + TUL_SCnt0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- if ((wait_tulip(pCurHcb)) == -1) {
- return (-1);
- }
- if (pCurHcb->HCS_Phase != DATA_OUT) { /* Disable wide CPU to allow read 16 bits */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- return (6);
+ outb(0, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ if ((wait_tulip(host)) == -1)
+ return -1;
+ if (host->phase != DATA_OUT) { /* Disable wide CPU to allow read 16 bits */
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ return 6;
}
}
}
-
-/***************************************************************************/
-int tul_status_msg(HCS * pCurHcb)
+int initio_status_msg(struct initio_host * host)
{ /* status & MSG_IN */
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- BYTE msg;
+ struct scsi_ctrl_blk *scb = host->active;
+ u8 msg;
+
+ outb(TSC_CMD_COMP, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_CMD_COMP);
- if ((wait_tulip(pCurHcb)) == -1) {
- return (-1);
- }
/* get status */
- pCurScb->SCB_TaStat = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+ scb->tastat = inb(host->addr + TUL_SFifo);
- if (pCurHcb->HCS_Phase == MSG_OUT) {
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
- } else {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
- }
- if (pCurHcb->HCS_Phase == MSG_IN) {
- msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
- if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) { /* Parity error */
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_OUT)
- return (tul_bad_seq(pCurHcb));
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ if (host->phase == MSG_OUT) {
+ if (host->jsstatus0 & TSS_PAR_ERROR)
+ outb(MSG_PARITY, host->addr + TUL_SFifo);
+ else
+ outb(MSG_NOP, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
+ }
+ if (host->phase == MSG_IN) {
+ msg = inb(host->addr + TUL_SFifo);
+ if (host->jsstatus0 & TSS_PAR_ERROR) { /* Parity error */
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
+ if (host->phase != MSG_OUT)
+ return initio_bad_seq(host);
+ outb(MSG_PARITY, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
if (msg == 0) { /* Command complete */
- if ((pCurScb->SCB_TaStat & 0x18) == 0x10) { /* No link support */
- return (tul_bad_seq(pCurHcb));
- }
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
- return tul_wait_done_disc(pCurHcb);
+ if ((scb->tastat & 0x18) == 0x10) /* No link support */
+ return initio_bad_seq(host);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return initio_wait_done_disc(host);
}
- if ((msg == MSG_LINK_COMP) || (msg == MSG_LINK_FLAG)) {
- if ((pCurScb->SCB_TaStat & 0x18) == 0x10)
- return (tul_msgin_accept(pCurHcb));
+ if (msg == MSG_LINK_COMP || msg == MSG_LINK_FLAG) {
+ if ((scb->tastat & 0x18) == 0x10)
+ return initio_msgin_accept(host);
}
}
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
-/***************************************************************************/
/* scsi bus free */
-int int_tul_busfree(HCS * pCurHcb)
+int int_initio_busfree(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
+ struct scsi_ctrl_blk *scb = host->active;
- if (pCurScb != NULL) {
- if (pCurScb->SCB_Status & SCB_SELECT) { /* selection timeout */
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = HOST_SEL_TOUT;
- tul_append_done_scb(pCurHcb, pCurScb);
+ if (scb != NULL) {
+ if (scb->status & SCB_SELECT) { /* selection timeout */
+ initio_unlink_pend_scb(host, scb);
+ scb->hastat = HOST_SEL_TOUT;
+ initio_append_done_scb(host, scb);
} else { /* Unexpected bus free */
- tul_unlink_busy_scb(pCurHcb, pCurScb);
- pCurScb->SCB_HaStat = HOST_BUS_FREE;
- tul_append_done_scb(pCurHcb, pCurScb);
+ initio_unlink_busy_scb(host, scb);
+ scb->hastat = HOST_BUS_FREE;
+ initio_append_done_scb(host, scb);
}
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
+ host->active = NULL;
+ host->active_tc = NULL;
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- return (-1);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ return -1;
}
-/***************************************************************************/
-/* scsi bus reset */
-static int int_tul_scsi_rst(HCS * pCurHcb)
+/**
+ * int_initio_scsi_rst - SCSI reset occurred
+ * @host: Host seeing the reset
+ *
+ * A SCSI bus reset has occurred. Clean up any pending transfer
+ * the hardware is doing by DMA and then abort all active and
+ * disconnected commands. The mid layer should sort the rest out
+ * for us
+ */
+
+static int int_initio_scsi_rst(struct initio_host * host)
{
- SCB *pCurScb;
+ struct scsi_ctrl_blk *scb;
int i;
/* if DMA xfer is pending, abort DMA xfer */
- if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & 0x01) {
- TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+ if (inb(host->addr + TUL_XStatus) & 0x01) {
+ outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd);
/* wait Abort DMA xfer done */
- while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & 0x04) == 0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ while ((inb(host->addr + TUL_Int) & 0x04) == 0)
+ cpu_relax();
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
}
/* Abort all active & disconnected scb */
- while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- tul_append_done_scb(pCurHcb, pCurScb);
+ while ((scb = initio_pop_busy_scb(host)) != NULL) {
+ scb->hastat = HOST_BAD_PHAS;
+ initio_append_done_scb(host, scb);
}
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
+ host->active = NULL;
+ host->active_tc = NULL;
/* clr sync nego. done flag */
- for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
- }
- return (-1);
+ for (i = 0; i < host->max_tar; i++)
+ host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ return -1;
}
+/**
+ * int_initio_scsi_resel - Reselection occured
+ * @host: InitIO host adapter
+ *
+ * A SCSI reselection event has been signalled and the interrupt
+ * is now being processed. Work out which command block needs attention
+ * and continue processing that command.
+ */
-/***************************************************************************/
-/* scsi reselection */
-int int_tul_resel(HCS * pCurHcb)
+int int_initio_resel(struct initio_host * host)
{
- SCB *pCurScb;
- TCS *pCurTcb;
- BYTE tag, msg = 0;
- BYTE tar, lun;
+ struct scsi_ctrl_blk *scb;
+ struct target_control *active_tc;
+ u8 tag, msg = 0;
+ u8 tar, lun;
- if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
- if (pCurScb->SCB_Status & SCB_SELECT) { /* if waiting for selection complete */
- pCurScb->SCB_Status &= ~SCB_SELECT;
- }
- pCurHcb->HCS_ActScb = NULL;
+ if ((scb = host->active) != NULL) {
+ /* FIXME: Why check and not just clear ? */
+ if (scb->status & SCB_SELECT) /* if waiting for selection complete */
+ scb->status &= ~SCB_SELECT;
+ host->active = NULL;
}
/* --------- get target id---------------------- */
- tar = TUL_RD(pCurHcb->HCS_Base, TUL_SBusId);
+ tar = inb(host->addr + TUL_SBusId);
/* ------ get LUN from Identify message----------- */
- lun = TUL_RD(pCurHcb->HCS_Base, TUL_SIdent) & 0x0F;
+ lun = inb(host->addr + TUL_SIdent) & 0x0F;
/* 07/22/98 from 0x1F -> 0x0F */
- pCurTcb = &pCurHcb->HCS_Tcs[tar];
- pCurHcb->HCS_ActTcs = pCurTcb;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
-
+ active_tc = &host->targets[tar];
+ host->active_tc = active_tc;
+ outb(active_tc->sconfig0, host->addr + TUL_SConfig);
+ outb(active_tc->js_period, host->addr + TUL_SPeriod);
/* ------------- tag queueing ? ------------------- */
- if (pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG) {
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_IN)
+ if (active_tc->drv_flags & TCF_DRV_EN_TAG) {
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
+ if (host->phase != MSG_IN)
goto no_tag;
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1)
- return (-1);
- msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* Read Tag Message */
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ msg = inb(host->addr + TUL_SFifo); /* Read Tag Message */
- if ((msg < MSG_STAG) || (msg > MSG_OTAG)) /* Is simple Tag */
+ if (msg < MSG_STAG || msg > MSG_OTAG) /* Is simple Tag */
goto no_tag;
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
+ if (initio_msgin_accept(host) == -1)
+ return -1;
- if (pCurHcb->HCS_Phase != MSG_IN)
+ if (host->phase != MSG_IN)
goto no_tag;
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1)
- return (-1);
- tag = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* Read Tag ID */
- pCurScb = pCurHcb->HCS_Scb + tag;
- if ((pCurScb->SCB_Target != tar) || (pCurScb->SCB_Lun != lun)) {
- return tul_msgout_abort_tag(pCurHcb);
- }
- if (pCurScb->SCB_Status != SCB_BUSY) { /* 03/24/95 */
- return tul_msgout_abort_tag(pCurHcb);
- }
- pCurHcb->HCS_ActScb = pCurScb;
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ tag = inb(host->addr + TUL_SFifo); /* Read Tag ID */
+ scb = host->scb + tag;
+ if (scb->target != tar || scb->lun != lun) {
+ return initio_msgout_abort_tag(host);
+ }
+ if (scb->status != SCB_BUSY) { /* 03/24/95 */
+ return initio_msgout_abort_tag(host);
+ }
+ host->active = scb;
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
} else { /* No tag */
no_tag:
- if ((pCurScb = tul_find_busy_scb(pCurHcb, tar | (lun << 8))) == NULL) {
- return tul_msgout_abort_targ(pCurHcb);
+ if ((scb = initio_find_busy_scb(host, tar | (lun << 8))) == NULL) {
+ return initio_msgout_abort_targ(host);
}
- pCurHcb->HCS_ActScb = pCurScb;
- if (!(pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG)) {
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
+ host->active = scb;
+ if (!(active_tc->drv_flags & TCF_DRV_EN_TAG)) {
+ if ((initio_msgin_accept(host)) == -1)
+ return -1;
}
}
return 0;
}
+/**
+ * int_initio_bad_seq - out of phase
+ * @host: InitIO host flagging event
+ *
+ * We have ended up out of phase somehow. Reset the host controller
+ * and throw all our toys out of the pram. Let the midlayer clean up
+ */
-/***************************************************************************/
-static int int_tul_bad_seq(HCS * pCurHcb)
+static int int_initio_bad_seq(struct initio_host * host)
{ /* target wrong phase */
- SCB *pCurScb;
+ struct scsi_ctrl_blk *scb;
int i;
- tul_reset_scsi(pCurHcb, 10);
+ initio_reset_scsi(host, 10);
- while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- tul_append_done_scb(pCurHcb, pCurScb);
- }
- for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ while ((scb = initio_pop_busy_scb(host)) != NULL) {
+ scb->hastat = HOST_BAD_PHAS;
+ initio_append_done_scb(host, scb);
}
- return (-1);
+ for (i = 0; i < host->max_tar; i++)
+ host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ return -1;
}
-/***************************************************************************/
-int tul_msgout_abort_targ(HCS * pCurHcb)
+/**
+ * initio_msgout_abort_targ - abort a tag
+ * @host: InitIO host
+ *
+ * Abort when the target/lun does not match or when our SCB is not
+ * busy. Used by untagged commands.
+ */
+
+static int initio_msgout_abort_targ(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- if (tul_msgin_accept(pCurHcb) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_OUT)
- return (tul_bad_seq(pCurHcb));
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
+ if (initio_msgin_accept(host) == -1)
+ return -1;
+ if (host->phase != MSG_OUT)
+ return initio_bad_seq(host);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+ outb(MSG_ABORT, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
- return tul_wait_disc(pCurHcb);
+ return initio_wait_disc(host);
}
-/***************************************************************************/
-int tul_msgout_abort_tag(HCS * pCurHcb)
+/**
+ * initio_msgout_abort_tag - abort a tag
+ * @host: InitIO host
+ *
+ * Abort when the target/lun does not match or when our SCB is not
+ * busy. Used for tagged commands.
+ */
+
+static int initio_msgout_abort_tag(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- if (tul_msgin_accept(pCurHcb) == -1)
- return (-1);
- if (pCurHcb->HCS_Phase != MSG_OUT)
- return (tul_bad_seq(pCurHcb));
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
+ if (initio_msgin_accept(host) == -1)
+ return -1;
+ if (host->phase != MSG_OUT)
+ return initio_bad_seq(host);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT_TAG);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+ outb(MSG_ABORT_TAG, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
- return tul_wait_disc(pCurHcb);
+ return initio_wait_disc(host);
}
-/***************************************************************************/
-int tul_msgin(HCS * pCurHcb)
+/**
+ * initio_msgin - Message in
+ * @host: InitIO Host
+ *
+ * Process incoming message
+ */
+static int initio_msgin(struct initio_host * host)
{
- TCS *pCurTcb;
+ struct target_control *active_tc;
for (;;) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
-
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if ((wait_tulip(pCurHcb)) == -1)
- return (-1);
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
- switch (TUL_RD(pCurHcb->HCS_Base, TUL_SFifo)) {
+ switch (inb(host->addr + TUL_SFifo)) {
case MSG_DISC: /* Disconnect msg */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
-
- return tul_wait_disc(pCurHcb);
-
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return initio_wait_disc(host);
case MSG_SDP:
case MSG_RESTORE:
case MSG_NOP:
- tul_msgin_accept(pCurHcb);
+ initio_msgin_accept(host);
break;
-
case MSG_REJ: /* Clear ATN first */
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal,
- (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
- pCurTcb = pCurHcb->HCS_ActTcs;
- if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync nego */
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- }
- tul_msgin_accept(pCurHcb);
+ outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)),
+ host->addr + TUL_SSignal);
+ active_tc = host->active_tc;
+ if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) /* do sync nego */
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN),
+ host->addr + TUL_SSignal);
+ initio_msgin_accept(host);
break;
-
case MSG_EXTEND: /* extended msg */
- tul_msgin_extend(pCurHcb);
+ initio_msgin_extend(host);
break;
-
case MSG_IGNOREWIDE:
- tul_msgin_accept(pCurHcb);
+ initio_msgin_accept(host);
break;
-
- /* get */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if (wait_tulip(pCurHcb) == -1)
- return -1;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0); /* put pad */
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* get IGNORE field */
- TUL_RD(pCurHcb->HCS_Base, TUL_SFifo); /* get pad */
-
- tul_msgin_accept(pCurHcb);
- break;
-
case MSG_COMP:
- {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
- return tul_wait_done_disc(pCurHcb);
- }
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return initio_wait_done_disc(host);
default:
- tul_msgout_reject(pCurHcb);
+ initio_msgout_reject(host);
break;
}
- if (pCurHcb->HCS_Phase != MSG_IN)
- return (pCurHcb->HCS_Phase);
+ if (host->phase != MSG_IN)
+ return host->phase;
}
/* statement won't reach here */
}
-
-
-
-/***************************************************************************/
-int tul_msgout_reject(HCS * pCurHcb)
+static int initio_msgout_reject(struct initio_host * host)
{
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
-
- if ((tul_msgin_accept(pCurHcb)) == -1)
- return (-1);
+ if (initio_msgin_accept(host) == -1)
+ return -1;
- if (pCurHcb->HCS_Phase == MSG_OUT) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_REJ); /* Msg reject */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ if (host->phase == MSG_OUT) {
+ outb(MSG_REJ, host->addr + TUL_SFifo); /* Msg reject */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
- return (pCurHcb->HCS_Phase);
+ return host->phase;
}
-
-
-/***************************************************************************/
-int tul_msgout_ide(HCS * pCurHcb)
+static int initio_msgout_ide(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_IDE); /* Initiator Detected Error */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ outb(MSG_IDE, host->addr + TUL_SFifo); /* Initiator Detected Error */
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
-
-/***************************************************************************/
-int tul_msgin_extend(HCS * pCurHcb)
+static int initio_msgin_extend(struct initio_host * host)
{
- BYTE len, idx;
+ u8 len, idx;
- if (tul_msgin_accept(pCurHcb) != MSG_IN)
- return (pCurHcb->HCS_Phase);
+ if (initio_msgin_accept(host) != MSG_IN)
+ return host->phase;
/* Get extended msg length */
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
- len = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
- pCurHcb->HCS_Msg[0] = len;
+ len = inb(host->addr + TUL_SFifo);
+ host->msg[0] = len;
for (idx = 1; len != 0; len--) {
- if ((tul_msgin_accept(pCurHcb)) != MSG_IN)
- return (pCurHcb->HCS_Phase);
- TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
- if (wait_tulip(pCurHcb) == -1)
- return (-1);
- pCurHcb->HCS_Msg[idx++] = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
- }
- if (pCurHcb->HCS_Msg[1] == 1) { /* if it's synchronous data transfer request */
- if (pCurHcb->HCS_Msg[0] != 3) /* if length is not right */
- return (tul_msgout_reject(pCurHcb));
- if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_SYNC_NEGO) { /* Set OFFSET=0 to do async, nego back */
- pCurHcb->HCS_Msg[3] = 0;
+ if ((initio_msgin_accept(host)) != MSG_IN)
+ return host->phase;
+ outl(1, host->addr + TUL_SCnt0);
+ outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd);
+ if (wait_tulip(host) == -1)
+ return -1;
+ host->msg[idx++] = inb(host->addr + TUL_SFifo);
+ }
+ if (host->msg[1] == 1) { /* if it's synchronous data transfer request */
+ u8 r;
+ if (host->msg[0] != 3) /* if length is not right */
+ return initio_msgout_reject(host);
+ if (host->active_tc->flags & TCF_NO_SYNC_NEGO) { /* Set OFFSET=0 to do async, nego back */
+ host->msg[3] = 0;
} else {
- if ((tul_msgin_sync(pCurHcb) == 0) &&
- (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SYNC_DONE)) {
- tul_sync_done(pCurHcb);
- return (tul_msgin_accept(pCurHcb));
+ if (initio_msgin_sync(host) == 0 &&
+ (host->active_tc->flags & TCF_SYNC_DONE)) {
+ initio_sync_done(host);
+ return initio_msgin_accept(host);
}
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- if ((tul_msgin_accept(pCurHcb)) != MSG_OUT)
- return (pCurHcb->HCS_Phase);
+ r = inb(host->addr + TUL_SSignal);
+ outb((r & (TSC_SET_ACK | 7)) | TSC_SET_ATN,
+ host->addr + TUL_SSignal);
+ if (initio_msgin_accept(host) != MSG_OUT)
+ return host->phase;
/* sync msg out */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0);
- tul_sync_done(pCurHcb);
+ initio_sync_done(host);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[3]);
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo);
+ outb(1, host->addr + TUL_SFifo);
+ outb(host->msg[2], host->addr + TUL_SFifo);
+ outb(host->msg[3], host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
- if ((pCurHcb->HCS_Msg[0] != 2) || (pCurHcb->HCS_Msg[1] != 3))
- return (tul_msgout_reject(pCurHcb));
+ if (host->msg[0] != 2 || host->msg[1] != 3)
+ return initio_msgout_reject(host);
/* if it's WIDE DATA XFER REQ */
- if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) {
- pCurHcb->HCS_Msg[2] = 0;
+ if (host->active_tc->flags & TCF_NO_WDTR) {
+ host->msg[2] = 0;
} else {
- if (pCurHcb->HCS_Msg[2] > 2) /* > 32 bits */
- return (tul_msgout_reject(pCurHcb));
- if (pCurHcb->HCS_Msg[2] == 2) { /* == 32 */
- pCurHcb->HCS_Msg[2] = 1;
+ if (host->msg[2] > 2) /* > 32 bits */
+ return initio_msgout_reject(host);
+ if (host->msg[2] == 2) { /* == 32 */
+ host->msg[2] = 1;
} else {
- if ((pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) == 0) {
- wdtr_done(pCurHcb);
- if ((pCurHcb->HCS_ActTcs->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
- return (tul_msgin_accept(pCurHcb));
+ if ((host->active_tc->flags & TCF_NO_WDTR) == 0) {
+ wdtr_done(host);
+ if ((host->active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
+ return initio_msgin_accept(host);
}
}
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+ outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal);
- if (tul_msgin_accept(pCurHcb) != MSG_OUT)
- return (pCurHcb->HCS_Phase);
+ if (initio_msgin_accept(host) != MSG_OUT)
+ return host->phase;
/* WDTR msg out */
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
- return (wait_tulip(pCurHcb));
+ outb(MSG_EXTEND, host->addr + TUL_SFifo);
+ outb(2, host->addr + TUL_SFifo);
+ outb(3, host->addr + TUL_SFifo);
+ outb(host->msg[2], host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
-/***************************************************************************/
-int tul_msgin_sync(HCS * pCurHcb)
+static int initio_msgin_sync(struct initio_host * host)
{
char default_period;
- default_period = tul_rate_tbl[pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SCSI_RATE];
- if (pCurHcb->HCS_Msg[3] > MAX_OFFSET) {
- pCurHcb->HCS_Msg[3] = MAX_OFFSET;
- if (pCurHcb->HCS_Msg[2] < default_period) {
- pCurHcb->HCS_Msg[2] = default_period;
+ default_period = initio_rate_tbl[host->active_tc->flags & TCF_SCSI_RATE];
+ if (host->msg[3] > MAX_OFFSET) {
+ host->msg[3] = MAX_OFFSET;
+ if (host->msg[2] < default_period) {
+ host->msg[2] = default_period;
return 1;
}
- if (pCurHcb->HCS_Msg[2] >= 59) { /* Change to async */
- pCurHcb->HCS_Msg[3] = 0;
- }
+ if (host->msg[2] >= 59) /* Change to async */
+ host->msg[3] = 0;
return 1;
}
/* offset requests asynchronous transfers ? */
- if (pCurHcb->HCS_Msg[3] == 0) {
+ if (host->msg[3] == 0) {
return 0;
}
- if (pCurHcb->HCS_Msg[2] < default_period) {
- pCurHcb->HCS_Msg[2] = default_period;
+ if (host->msg[2] < default_period) {
+ host->msg[2] = default_period;
return 1;
}
- if (pCurHcb->HCS_Msg[2] >= 59) {
- pCurHcb->HCS_Msg[3] = 0;
+ if (host->msg[2] >= 59) {
+ host->msg[3] = 0;
return 1;
}
return 0;
}
-
-/***************************************************************************/
-int wdtr_done(HCS * pCurHcb)
+static int wdtr_done(struct initio_host * host)
{
- pCurHcb->HCS_ActTcs->TCS_Flags &= ~TCF_SYNC_DONE;
- pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_WDTR_DONE;
+ host->active_tc->flags &= ~TCF_SYNC_DONE;
+ host->active_tc->flags |= TCF_WDTR_DONE;
- pCurHcb->HCS_ActTcs->TCS_JS_Period = 0;
- if (pCurHcb->HCS_Msg[2]) { /* if 16 bit */
- pCurHcb->HCS_ActTcs->TCS_JS_Period |= TSC_WIDE_SCSI;
- }
- pCurHcb->HCS_ActTcs->TCS_SConfig0 &= ~TSC_ALT_PERIOD;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+ host->active_tc->js_period = 0;
+ if (host->msg[2]) /* if 16 bit */
+ host->active_tc->js_period |= TSC_WIDE_SCSI;
+ host->active_tc->sconfig0 &= ~TSC_ALT_PERIOD;
+ outb(host->active_tc->sconfig0, host->addr + TUL_SConfig);
+ outb(host->active_tc->js_period, host->addr + TUL_SPeriod);
return 1;
}
-/***************************************************************************/
-int tul_sync_done(HCS * pCurHcb)
+static int initio_sync_done(struct initio_host * host)
{
int i;
- pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_SYNC_DONE;
+ host->active_tc->flags |= TCF_SYNC_DONE;
- if (pCurHcb->HCS_Msg[3]) {
- pCurHcb->HCS_ActTcs->TCS_JS_Period |= pCurHcb->HCS_Msg[3];
+ if (host->msg[3]) {
+ host->active_tc->js_period |= host->msg[3];
for (i = 0; i < 8; i++) {
- if (tul_rate_tbl[i] >= pCurHcb->HCS_Msg[2]) /* pick the big one */
+ if (initio_rate_tbl[i] >= host->msg[2]) /* pick the big one */
break;
}
- pCurHcb->HCS_ActTcs->TCS_JS_Period |= (i << 4);
- pCurHcb->HCS_ActTcs->TCS_SConfig0 |= TSC_ALT_PERIOD;
+ host->active_tc->js_period |= (i << 4);
+ host->active_tc->sconfig0 |= TSC_ALT_PERIOD;
}
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
- TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+ outb(host->active_tc->sconfig0, host->addr + TUL_SConfig);
+ outb(host->active_tc->js_period, host->addr + TUL_SPeriod);
- return (-1);
+ return -1;
}
-int tul_post_scsi_rst(HCS * pCurHcb)
+static int initio_post_scsi_rst(struct initio_host * host)
{
- SCB *pCurScb;
- TCS *pCurTcb;
+ struct scsi_ctrl_blk *scb;
+ struct target_control *active_tc;
int i;
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
- pCurHcb->HCS_Flags = 0;
+ host->active = NULL;
+ host->active_tc = NULL;
+ host->flags = 0;
- while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
- pCurScb->SCB_HaStat = HOST_BAD_PHAS;
- tul_append_done_scb(pCurHcb, pCurScb);
+ while ((scb = initio_pop_busy_scb(host)) != NULL) {
+ scb->hastat = HOST_BAD_PHAS;
+ initio_append_done_scb(host, scb);
}
/* clear sync done flag */
- pCurTcb = &pCurHcb->HCS_Tcs[0];
- for (i = 0; i < pCurHcb->HCS_MaxTar; pCurTcb++, i++) {
- pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+ active_tc = &host->targets[0];
+ for (i = 0; i < host->max_tar; active_tc++, i++) {
+ active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
/* Initialize the sync. xfer register values to an asyn xfer */
- pCurTcb->TCS_JS_Period = 0;
- pCurTcb->TCS_SConfig0 = pCurHcb->HCS_SConf1;
- pCurHcb->HCS_ActTags[0] = 0; /* 07/22/98 */
- pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY; /* 07/22/98 */
+ active_tc->js_period = 0;
+ active_tc->sconfig0 = host->sconf1;
+ host->act_tags[0] = 0; /* 07/22/98 */
+ host->targets[i].flags &= ~TCF_BUSY; /* 07/22/98 */
} /* for */
- return (-1);
+ return -1;
}
-/***************************************************************************/
-void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb)
+static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
- pCurScb->SCB_Status |= SCB_SELECT;
- pCurScb->SCB_NxtStat = 0x1;
- pCurHcb->HCS_ActScb = pCurScb;
- pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SELATNSTOP);
- return;
+ scb->status |= SCB_SELECT;
+ scb->next_state = 0x1;
+ host->active = scb;
+ host->active_tc = &host->targets[scb->target];
+ outb(TSC_SELATNSTOP, host->addr + TUL_SCmd);
}
-/***************************************************************************/
-void tul_select_atn(HCS * pCurHcb, SCB * pCurScb)
+static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
int i;
- pCurScb->SCB_Status |= SCB_SELECT;
- pCurScb->SCB_NxtStat = 0x2;
+ scb->status |= SCB_SELECT;
+ scb->next_state = 0x2;
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
- for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
- pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
- pCurHcb->HCS_ActScb = pCurScb;
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN);
- return;
+ outb(scb->ident, host->addr + TUL_SFifo);
+ for (i = 0; i < (int) scb->cdblen; i++)
+ outb(scb->cdb[i], host->addr + TUL_SFifo);
+ host->active_tc = &host->targets[scb->target];
+ host->active = scb;
+ outb(TSC_SEL_ATN, host->addr + TUL_SCmd);
}
-/***************************************************************************/
-void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb)
+static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb)
{
int i;
- pCurScb->SCB_Status |= SCB_SELECT;
- pCurScb->SCB_NxtStat = 0x2;
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
- for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
- pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
- pCurHcb->HCS_ActScb = pCurScb;
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN3);
- return;
+ scb->status |= SCB_SELECT;
+ scb->next_state = 0x2;
+
+ outb(scb->ident, host->addr + TUL_SFifo);
+ outb(scb->tagmsg, host->addr + TUL_SFifo);
+ outb(scb->tagid, host->addr + TUL_SFifo);
+ for (i = 0; i < scb->cdblen; i++)
+ outb(scb->cdb[i], host->addr + TUL_SFifo);
+ host->active_tc = &host->targets[scb->target];
+ host->active = scb;
+ outb(TSC_SEL_ATN3, host->addr + TUL_SCmd);
}
-/***************************************************************************/
-/* SCSI Bus Device Reset */
-int tul_bus_device_reset(HCS * pCurHcb)
+/**
+ * initio_bus_device_reset - SCSI Bus Device Reset
+ * @host: InitIO host to reset
+ *
+ * Perform a device reset and abort all pending SCBs for the
+ * victim device
+ */
+int initio_bus_device_reset(struct initio_host * host)
{
- SCB *pCurScb = pCurHcb->HCS_ActScb;
- TCS *pCurTcb = pCurHcb->HCS_ActTcs;
- SCB *pTmpScb, *pPrevScb;
- BYTE tar;
+ struct scsi_ctrl_blk *scb = host->active;
+ struct target_control *active_tc = host->active_tc;
+ struct scsi_ctrl_blk *tmp, *prev;
+ u8 tar;
- if (pCurHcb->HCS_Phase != MSG_OUT) {
- return (int_tul_bad_seq(pCurHcb)); /* Unexpected phase */
- }
- tul_unlink_pend_scb(pCurHcb, pCurScb);
- tul_release_scb(pCurHcb, pCurScb);
+ if (host->phase != MSG_OUT)
+ return int_initio_bad_seq(host); /* Unexpected phase */
+
+ initio_unlink_pend_scb(host, scb);
+ initio_release_scb(host, scb);
- tar = pCurScb->SCB_Target; /* target */
- pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
+ tar = scb->target; /* target */
+ active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
/* clr sync. nego & WDTR flags 07/22/98 */
/* abort all SCB with same target */
- pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy; /* Check Busy queue */
- while (pTmpScb != NULL) {
-
- if (pTmpScb->SCB_Target == tar) {
+ prev = tmp = host->first_busy; /* Check Busy queue */
+ while (tmp != NULL) {
+ if (tmp->target == tar) {
/* unlink it */
- if (pTmpScb == pCurHcb->HCS_FirstBusy) {
- if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastBusy = NULL;
+ if (tmp == host->first_busy) {
+ if ((host->first_busy = tmp->next) == NULL)
+ host->last_busy = NULL;
} else {
- pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
- if (pTmpScb == pCurHcb->HCS_LastBusy)
- pCurHcb->HCS_LastBusy = pPrevScb;
+ prev->next = tmp->next;
+ if (tmp == host->last_busy)
+ host->last_busy = prev;
}
- pTmpScb->SCB_HaStat = HOST_ABORTED;
- tul_append_done_scb(pCurHcb, pTmpScb);
+ tmp->hastat = HOST_ABORTED;
+ initio_append_done_scb(host, tmp);
}
/* Previous haven't change */
else {
- pPrevScb = pTmpScb;
+ prev = tmp;
}
- pTmpScb = pTmpScb->SCB_NxtScb;
+ tmp = tmp->next;
}
-
- TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_DEVRST);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
-
- return tul_wait_disc(pCurHcb);
+ outb(MSG_DEVRST, host->addr + TUL_SFifo);
+ outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd);
+ return initio_wait_disc(host);
}
-/***************************************************************************/
-int tul_msgin_accept(HCS * pCurHcb)
+static int initio_msgin_accept(struct initio_host * host)
{
- TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
- return (wait_tulip(pCurHcb));
+ outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd);
+ return wait_tulip(host);
}
-/***************************************************************************/
-int wait_tulip(HCS * pCurHcb)
+static int wait_tulip(struct initio_host * host)
{
- while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
- & TSS_INT_PENDING));
+ while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
+ & TSS_INT_PENDING))
+ cpu_relax();
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
- pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
- pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+ host->jsint = inb(host->addr + TUL_SInt);
+ host->phase = host->jsstatus0 & TSS_PH_MASK;
+ host->jsstatus1 = inb(host->addr + TUL_SStatus1);
- if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) { /* if SCSI bus reset detected */
- return (int_tul_resel(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) { /* if selected/reselected timeout interrupt */
- return (int_tul_busfree(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* if SCSI bus reset detected */
- return (int_tul_scsi_rst(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- if (pCurHcb->HCS_Flags & HCF_EXPECT_DONE_DISC) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
- pCurHcb->HCS_ActScb->SCB_HaStat = 0;
- tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
- pCurHcb->HCS_Flags &= ~HCF_EXPECT_DONE_DISC;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- return (-1);
+ if (host->jsint & TSS_RESEL_INT) /* if SCSI bus reset detected */
+ return int_initio_resel(host);
+ if (host->jsint & TSS_SEL_TIMEOUT) /* if selected/reselected timeout interrupt */
+ return int_initio_busfree(host);
+ if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */
+ return int_initio_scsi_rst(host);
+
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ if (host->flags & HCF_EXPECT_DONE_DISC) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ initio_unlink_busy_scb(host, host->active);
+ host->active->hastat = 0;
+ initio_append_done_scb(host, host->active);
+ host->active = NULL;
+ host->active_tc = NULL;
+ host->flags &= ~HCF_EXPECT_DONE_DISC;
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ return -1;
}
- if (pCurHcb->HCS_Flags & HCF_EXPECT_DISC) {
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- pCurHcb->HCS_ActScb = NULL;
- pCurHcb->HCS_ActTcs = NULL;
- pCurHcb->HCS_Flags &= ~HCF_EXPECT_DISC;
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- return (-1);
+ if (host->flags & HCF_EXPECT_DISC) {
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ host->active = NULL;
+ host->active_tc = NULL;
+ host->flags &= ~HCF_EXPECT_DISC;
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ return -1;
}
- return (int_tul_busfree(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {
- return (pCurHcb->HCS_Phase);
+ return int_initio_busfree(host);
}
- return (pCurHcb->HCS_Phase);
+ /* The old code really does the below. Can probably be removed */
+ if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV))
+ return host->phase;
+ return host->phase;
}
-/***************************************************************************/
-int tul_wait_disc(HCS * pCurHcb)
-{
-
- while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
- & TSS_INT_PENDING));
+static int initio_wait_disc(struct initio_host * host)
+{
+ while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING))
+ cpu_relax();
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+ host->jsint = inb(host->addr + TUL_SInt);
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* if SCSI bus reset detected */
- return (int_tul_scsi_rst(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- pCurHcb->HCS_ActScb = NULL;
- return (-1);
+ if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */
+ return int_initio_scsi_rst(host);
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ host->active = NULL;
+ return -1;
}
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
-/***************************************************************************/
-int tul_wait_done_disc(HCS * pCurHcb)
+static int initio_wait_done_disc(struct initio_host * host)
{
+ while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0))
+ & TSS_INT_PENDING))
+ cpu_relax();
+ host->jsint = inb(host->addr + TUL_SInt);
- while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
- & TSS_INT_PENDING));
-
- pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
-
-
- if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) { /* if SCSI bus reset detected */
- return (int_tul_scsi_rst(pCurHcb));
- }
- if (pCurHcb->HCS_JSInt & TSS_DISC_INT) { /* BUS disconnection */
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO); /* Flush SCSI FIFO */
- TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
- TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT); /* Enable HW reselect */
- tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
+ if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */
+ return int_initio_scsi_rst(host);
+ if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */
+ outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */
+ outb(TSC_INITDEFAULT, host->addr + TUL_SConfig);
+ outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */
+ initio_unlink_busy_scb(host, host->active);
- tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
- pCurHcb->HCS_ActScb = NULL;
- return (-1);
+ initio_append_done_scb(host, host->active);
+ host->active = NULL;
+ return -1;
}
- return (tul_bad_seq(pCurHcb));
+ return initio_bad_seq(host);
}
+/**
+ * i91u_intr - IRQ handler
+ * @irqno: IRQ number
+ * @dev_id: IRQ identifier
+ *
+ * Take the relevant locks and then invoke the actual isr processing
+ * code under the lock.
+ */
+
static irqreturn_t i91u_intr(int irqno, void *dev_id)
{
struct Scsi_Host *dev = dev_id;
unsigned long flags;
+ int r;
spin_lock_irqsave(dev->host_lock, flags);
- tul_isr((HCS *)dev->base);
+ r = initio_isr((struct initio_host *)dev->hostdata);
spin_unlock_irqrestore(dev->host_lock, flags);
- return IRQ_HANDLED;
-}
-
-static int tul_NewReturnNumberOfAdapters(void)
-{
- struct pci_dev *pDev = NULL; /* Start from none */
- int iAdapters = 0;
- long dRegValue;
- WORD wBIOS;
- int i = 0;
-
- init_i91uAdapter_table();
-
- for (i = 0; i < ARRAY_SIZE(i91u_pci_devices); i++)
- {
- while ((pDev = pci_find_device(i91u_pci_devices[i].vendor, i91u_pci_devices[i].device, pDev)) != NULL) {
- if (pci_enable_device(pDev))
- continue;
- pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
- wBIOS = (UWORD) (dRegValue & 0xFF);
- if (((dRegValue & 0xFF00) >> 8) == 0xFF)
- dRegValue = 0;
- wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
- if (pci_set_dma_mask(pDev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING
- "i91u: Could not set 32 bit DMA mask\n");
- continue;
- }
-
- if (Addi91u_into_Adapter_table(wBIOS,
- (pDev->resource[0].start),
- pDev->irq,
- pDev->bus->number,
- (pDev->devfn >> 3)
- ) == 0)
- iAdapters++;
- }
- }
-
- return (iAdapters);
+ if (r)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
}
-static int i91u_detect(struct scsi_host_template * tpnt)
-{
- HCS *pHCB;
- struct Scsi_Host *hreg;
- unsigned long i; /* 01/14/98 */
- int ok = 0, iAdapters;
- ULONG dBiosAdr;
- BYTE *pbBiosAdr;
-
- /* Get total number of adapters in the motherboard */
- iAdapters = tul_NewReturnNumberOfAdapters();
- if (iAdapters == 0) /* If no tulip founded, return */
- return (0);
-
- tul_num_ch = (iAdapters > tul_num_ch) ? tul_num_ch : iAdapters;
- /* Update actually channel number */
- if (tul_tag_enable) { /* 1.01i */
- tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;
- } else {
- tul_num_scb = MAX_TARGETS + 3; /* 1-tape, 1-CD_ROM, 1- extra */
- } /* Update actually SCBs per adapter */
-
- /* Get total memory needed for HCS */
- i = tul_num_ch * sizeof(HCS);
- memset((unsigned char *) &tul_hcs[0], 0, i); /* Initialize tul_hcs 0 */
- /* Get total memory needed for SCB */
-
- for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
- i = tul_num_ch * tul_num_scb * sizeof(SCB);
- if ((tul_scb = kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
- break;
- }
- if (tul_scb == NULL) {
- printk("i91u: SCB memory allocation error\n");
- return (0);
- }
- memset((unsigned char *) tul_scb, 0, i);
- for (i = 0, pHCB = &tul_hcs[0]; /* Get pointer for control block */
- i < tul_num_ch;
- i++, pHCB++) {
- get_tulipPCIConfig(pHCB, i);
-
- dBiosAdr = pHCB->HCS_BIOS;
- dBiosAdr = (dBiosAdr << 4);
-
- pbBiosAdr = phys_to_virt(dBiosAdr);
-
- init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);
- request_region(pHCB->HCS_Base, 256, "i91u"); /* Register */
-
- pHCB->HCS_Index = i; /* 7/29/98 */
- hreg = scsi_register(tpnt, sizeof(HCS));
- if(hreg == NULL) {
- release_region(pHCB->HCS_Base, 256);
- return 0;
- }
- hreg->io_port = pHCB->HCS_Base;
- hreg->n_io_port = 0xff;
- hreg->can_queue = tul_num_scb; /* 03/05/98 */
- hreg->unique_id = pHCB->HCS_Base;
- hreg->max_id = pHCB->HCS_MaxTar;
- hreg->max_lun = 32; /* 10/21/97 */
- hreg->irq = pHCB->HCS_Intr;
- hreg->this_id = pHCB->HCS_SCSI_ID; /* Assign HCS index */
- hreg->base = (unsigned long)pHCB;
- hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */
-
- /* Initial tulip chip */
- ok = request_irq(pHCB->HCS_Intr, i91u_intr, IRQF_DISABLED | IRQF_SHARED, "i91u", hreg);
- if (ok < 0) {
- printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);
- return 0;
- }
- }
-
- tpnt->this_id = -1;
- tpnt->can_queue = 1;
-
- return 1;
-}
+/**
+ * initio_build_scb - Build the mappings and SCB
+ * @host: InitIO host taking the command
+ * @cblk: Firmware command block
+ * @cmnd: SCSI midlayer command block
+ *
+ * Translate the abstract SCSI command into a firmware command block
+ * suitable for feeding to the InitIO host controller. This also requires
+ * we build the scatter gather lists and ensure they are mapped properly.
+ */
-static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, struct scsi_cmnd * SCpnt)
+static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * cblk, struct scsi_cmnd * cmnd)
{ /* Create corresponding SCB */
- struct scatterlist *pSrbSG;
- SG *pSG; /* Pointer to SG list */
- int i;
- long TotalLen;
+ struct scatterlist *sglist;
+ struct sg_entry *sg; /* Pointer to SG list */
+ int i, nseg;
+ long total_len;
dma_addr_t dma_addr;
- pSCB->SCB_Post = i91uSCBPost; /* i91u's callback routine */
- pSCB->SCB_Srb = SCpnt;
- pSCB->SCB_Opcode = ExecSCSI;
- pSCB->SCB_Flags = SCF_POST; /* After SCSI done, call post routine */
- pSCB->SCB_Target = SCpnt->device->id;
- pSCB->SCB_Lun = SCpnt->device->lun;
- pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
-
- pSCB->SCB_Flags |= SCF_SENSE; /* Turn on auto request sense */
- dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->sense_buffer,
- SENSE_SIZE, DMA_FROM_DEVICE);
- pSCB->SCB_SensePtr = cpu_to_le32((u32)dma_addr);
- pSCB->SCB_SenseLen = cpu_to_le32(SENSE_SIZE);
- SCpnt->SCp.ptr = (char *)(unsigned long)dma_addr;
+ /* Fill in the command headers */
+ cblk->post = i91uSCBPost; /* i91u's callback routine */
+ cblk->srb = cmnd;
+ cblk->opcode = ExecSCSI;
+ cblk->flags = SCF_POST; /* After SCSI done, call post routine */
+ cblk->target = cmnd->device->id;
+ cblk->lun = cmnd->device->lun;
+ cblk->ident = cmnd->device->lun | DISC_ALLOW;
- pSCB->SCB_CDBLen = SCpnt->cmd_len;
- pSCB->SCB_HaStat = 0;
- pSCB->SCB_TaStat = 0;
- memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);
+ cblk->flags |= SCF_SENSE; /* Turn on auto request sense */
- if (SCpnt->device->tagged_supported) { /* Tag Support */
- pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
+ /* Map the sense buffer into bus memory */
+ dma_addr = dma_map_single(&host->pci_dev->dev, cmnd->sense_buffer,
+ SENSE_SIZE, DMA_FROM_DEVICE);
+ cblk->senseptr = cpu_to_le32((u32)dma_addr);
+ cblk->senselen = cpu_to_le32(SENSE_SIZE);
+ cmnd->SCp.ptr = (char *)(unsigned long)dma_addr;
+ cblk->cdblen = cmnd->cmd_len;
+
+ /* Clear the returned status */
+ cblk->hastat = 0;
+ cblk->tastat = 0;
+ /* Command the command */
+ memcpy(&cblk->cdb[0], &cmnd->cmnd, cmnd->cmd_len);
+
+ /* Set up tags */
+ if (cmnd->device->tagged_supported) { /* Tag Support */
+ cblk->tagmsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */
} else {
- pSCB->SCB_TagMsg = 0; /* No tag support */
+ cblk->tagmsg = 0; /* No tag support */
}
+
/* todo handle map_sg error */
- if (SCpnt->use_sg) {
- dma_addr = dma_map_single(&pHCB->pci_dev->dev, &pSCB->SCB_SGList[0],
- sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+ nseg = scsi_dma_map(cmnd);
+ BUG_ON(nseg < 0);
+ if (nseg) {
+ dma_addr = dma_map_single(&host->pci_dev->dev, &cblk->sglist[0],
+ sizeof(struct sg_entry) * TOTAL_SG_ENTRY,
DMA_BIDIRECTIONAL);
- pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
- SCpnt->SCp.dma_handle = dma_addr;
-
- pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
- pSCB->SCB_SGLen = dma_map_sg(&pHCB->pci_dev->dev, pSrbSG,
- SCpnt->use_sg, SCpnt->sc_data_direction);
-
- pSCB->SCB_Flags |= SCF_SG; /* Turn on SG list flag */
- for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0]; /* 1.01g */
- i < pSCB->SCB_SGLen; i++, pSG++, pSrbSG++) {
- pSG->SG_Ptr = cpu_to_le32((u32)sg_dma_address(pSrbSG));
- TotalLen += pSG->SG_Len = cpu_to_le32((u32)sg_dma_len(pSrbSG));
+ cblk->bufptr = cpu_to_le32((u32)dma_addr);
+ cmnd->SCp.dma_handle = dma_addr;
+
+
+ cblk->flags |= SCF_SG; /* Turn on SG list flag */
+ total_len = 0;
+ sg = &cblk->sglist[0];
+ scsi_for_each_sg(cmnd, sglist, cblk->sglen, i) {
+ sg->data = cpu_to_le32((u32)sg_dma_address(sglist));
+ total_len += sg->len = cpu_to_le32((u32)sg_dma_len(sglist));
}
- pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?
- TotalLen : SCpnt->request_bufflen;
- } else if (SCpnt->request_bufflen) { /* Non SG */
- dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->request_buffer,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- SCpnt->SCp.dma_handle = dma_addr;
- pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
- pSCB->SCB_BufLen = cpu_to_le32((u32)SCpnt->request_bufflen);
- pSCB->SCB_SGLen = 0;
- } else {
- pSCB->SCB_BufLen = 0;
- pSCB->SCB_SGLen = 0;
+ cblk->buflen = (scsi_bufflen(cmnd) > total_len) ?
+ total_len : scsi_bufflen(cmnd);
+ } else { /* No data transfer required */
+ cblk->buflen = 0;
+ cblk->sglen = 0;
}
}
+/**
+ * i91u_queuecommand - Queue a new command if possible
+ * @cmd: SCSI command block from the mid layer
+ * @done: Completion handler
+ *
+ * Attempts to queue a new command with the host adapter. Will return
+ * zero if successful or indicate a host busy condition if not (which
+ * will cause the mid layer to call us again later with the command)
+ */
+
static int i91u_queuecommand(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
- HCS *pHCB = (HCS *) cmd->device->host->base;
- register SCB *pSCB;
+ struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata;
+ struct scsi_ctrl_blk *cmnd;
cmd->scsi_done = done;
- pSCB = tul_alloc_scb(pHCB);
- if (!pSCB)
+ cmnd = initio_alloc_scb(host);
+ if (!cmnd)
return SCSI_MLQUEUE_HOST_BUSY;
- i91uBuildSCB(pHCB, pSCB, cmd);
- tul_exec_scb(pHCB, pSCB);
+ initio_build_scb(host, cmnd, cmd);
+ initio_exec_scb(host, cmnd);
return 0;
}
-#if 0 /* no new EH yet */
-/*
- * Abort a queued command
- * (commands that are on the bus can't be aborted easily)
- */
-static int i91u_abort(struct scsi_cmnd * SCpnt)
-{
- HCS *pHCB;
-
- pHCB = (HCS *) SCpnt->device->host->base;
- return tul_abort_srb(pHCB, SCpnt);
-}
-
-/*
- * Reset registers, reset a hanging bus and
- * kill active and disconnected commands for target w/o soft reset
+/**
+ * i91u_bus_reset - reset the SCSI bus
+ * @cmnd: Command block we want to trigger the reset for
+ *
+ * Initiate a SCSI bus reset sequence
*/
-static int i91u_reset(struct scsi_cmnd * SCpnt, unsigned int reset_flags)
-{ /* I need Host Control Block Information */
- HCS *pHCB;
-
- pHCB = (HCS *) SCpnt->device->host->base;
- if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
- return tul_reset_scsi_bus(pHCB);
- else
- return tul_device_reset(pHCB, SCpnt, SCpnt->device->id, reset_flags);
-}
-#endif
-
-static int i91u_bus_reset(struct scsi_cmnd * SCpnt)
+static int i91u_bus_reset(struct scsi_cmnd * cmnd)
{
- HCS *pHCB;
+ struct initio_host *host;
- pHCB = (HCS *) SCpnt->device->host->base;
+ host = (struct initio_host *) cmnd->device->host->hostdata;
- spin_lock_irq(SCpnt->device->host->host_lock);
- tul_reset_scsi(pHCB, 0);
- spin_unlock_irq(SCpnt->device->host->host_lock);
+ spin_lock_irq(cmnd->device->host->host_lock);
+ initio_reset_scsi(host, 0);
+ spin_unlock_irq(cmnd->device->host->host_lock);
return SUCCESS;
}
-/*
- * Return the "logical geometry"
+/**
+ * i91u_biospararm - return the "logical geometry
+ * @sdev: SCSI device
+ * @dev; Matching block device
+ * @capacity: Sector size of drive
+ * @info_array: Return space for BIOS geometry
+ *
+ * Map the device geometry in a manner compatible with the host
+ * controller BIOS behaviour.
+ *
+ * FIXME: limited to 2^32 sector devices.
*/
+
static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
sector_t capacity, int *info_array)
{
- HCS *pHcb; /* Point to Host adapter control block */
- TCS *pTcb;
+ struct initio_host *host; /* Point to Host adapter control block */
+ struct target_control *tc;
- pHcb = (HCS *) sdev->host->base;
- pTcb = &pHcb->HCS_Tcs[sdev->id];
+ host = (struct initio_host *) sdev->host->hostdata;
+ tc = &host->targets[sdev->id];
- if (pTcb->TCS_DrvHead) {
- info_array[0] = pTcb->TCS_DrvHead;
- info_array[1] = pTcb->TCS_DrvSector;
- info_array[2] = (unsigned long)capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+ if (tc->heads) {
+ info_array[0] = tc->heads;
+ info_array[1] = tc->sectors;
+ info_array[2] = (unsigned long)capacity / tc->heads / tc->sectors;
} else {
- if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
+ if (tc->drv_flags & TCF_DRV_255_63) {
info_array[0] = 255;
info_array[1] = 63;
info_array[2] = (unsigned long)capacity / 255 / 63;
@@ -3047,7 +2722,16 @@ static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
return 0;
}
-static void i91u_unmap_cmnd(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
+/**
+ * i91u_unmap_scb - Unmap a command
+ * @pci_dev: PCI device the command is for
+ * @cmnd: The command itself
+ *
+ * Unmap any PCI mapping/IOMMU resources allocated when the command
+ * was mapped originally as part of initio_build_scb
+ */
+
+static void i91u_unmap_scb(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
{
/* auto sense buffer */
if (cmnd->SCp.ptr) {
@@ -3058,65 +2742,63 @@ static void i91u_unmap_cmnd(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
}
/* request buffer */
- if (cmnd->use_sg) {
+ if (scsi_sg_count(cmnd)) {
dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
- sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+ sizeof(struct sg_entry) * TOTAL_SG_ENTRY,
DMA_BIDIRECTIONAL);
- dma_unmap_sg(&pci_dev->dev, cmnd->request_buffer,
- cmnd->use_sg,
- cmnd->sc_data_direction);
- } else if (cmnd->request_bufflen) {
- dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
- cmnd->request_bufflen,
- cmnd->sc_data_direction);
+ scsi_dma_unmap(cmnd);
}
}
-/*****************************************************************************
- Function name : i91uSCBPost
- Description : This is callback routine be called when tulip finish one
- SCSI command.
- Input : pHCB - Pointer to host adapter control block.
- pSCB - Pointer to SCSI control block.
- Output : None.
- Return : None.
-*****************************************************************************/
-static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
-{
- struct scsi_cmnd *pSRB; /* Pointer to SCSI request block */
- HCS *pHCB;
- SCB *pSCB;
+/**
+ * i91uSCBPost - SCSI callback
+ * @host: Pointer to host adapter control block.
+ * @cmnd: Pointer to SCSI control block.
+ *
+ * This is callback routine be called when tulip finish one
+ * SCSI command.
+ */
- pHCB = (HCS *) pHcb;
- pSCB = (SCB *) pScb;
- if ((pSRB = pSCB->SCB_Srb) == 0) {
- printk("i91uSCBPost: SRB pointer is empty\n");
+static void i91uSCBPost(u8 * host_mem, u8 * cblk_mem)
+{
+ struct scsi_cmnd *cmnd; /* Pointer to SCSI request block */
+ struct initio_host *host;
+ struct scsi_ctrl_blk *cblk;
- tul_release_scb(pHCB, pSCB); /* Release SCB for current channel */
+ host = (struct initio_host *) host_mem;
+ cblk = (struct scsi_ctrl_blk *) cblk_mem;
+ if ((cmnd = cblk->srb) == NULL) {
+ printk(KERN_ERR "i91uSCBPost: SRB pointer is empty\n");
+ WARN_ON(1);
+ initio_release_scb(host, cblk); /* Release SCB for current channel */
return;
}
- switch (pSCB->SCB_HaStat) {
+
+ /*
+ * Remap the firmware error status into a mid layer one
+ */
+ switch (cblk->hastat) {
case 0x0:
case 0xa: /* Linked command complete without error and linked normally */
case 0xb: /* Linked command complete without error interrupt generated */
- pSCB->SCB_HaStat = 0;
+ cblk->hastat = 0;
break;
case 0x11: /* Selection time out-The initiator selection or target
reselection was not complete within the SCSI Time out period */
- pSCB->SCB_HaStat = DID_TIME_OUT;
+ cblk->hastat = DID_TIME_OUT;
break;
case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus
phase sequence was requested by the target. The host adapter
will generate a SCSI Reset Condition, notifying the host with
a SCRD interrupt */
- pSCB->SCB_HaStat = DID_RESET;
+ cblk->hastat = DID_RESET;
break;
case 0x1a: /* SCB Aborted. 07/21/98 */
- pSCB->SCB_HaStat = DID_ABORT;
+ cblk->hastat = DID_ABORT;
break;
case 0x12: /* Data overrun/underrun-The target attempted to transfer more data
@@ -3126,49 +2808,196 @@ static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
case 0x16: /* Invalid SCB Operation Code. */
default:
- printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
- pSCB->SCB_HaStat = DID_ERROR; /* Couldn't find any better */
+ printk("ini9100u: %x %x\n", cblk->hastat, cblk->tastat);
+ cblk->hastat = DID_ERROR; /* Couldn't find any better */
break;
}
- pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+ cmnd->result = cblk->tastat | (cblk->hastat << 16);
+ WARN_ON(cmnd == NULL);
+ i91u_unmap_scb(host->pci_dev, cmnd);
+ cmnd->scsi_done(cmnd); /* Notify system DONE */
+ initio_release_scb(host, cblk); /* Release SCB for current channel */
+}
+
+static struct scsi_host_template initio_template = {
+ .proc_name = "INI9100U",
+ .name = "Initio INI-9X00U/UW SCSI device driver",
+ .queuecommand = i91u_queuecommand,
+ .eh_bus_reset_handler = i91u_bus_reset,
+ .bios_param = i91u_biosparam,
+ .can_queue = MAX_TARGETS * i91u_MAXQUEUE,
+ .this_id = 1,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+static int initio_probe_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct Scsi_Host *shost;
+ struct initio_host *host;
+ u32 reg;
+ u16 bios_seg;
+ struct scsi_ctrl_blk *scb, *tmp, *prev = NULL /* silence gcc */;
+ int num_scb, i, error;
+
+ error = pci_enable_device(pdev);
+ if (error)
+ return error;
+
+ pci_read_config_dword(pdev, 0x44, (u32 *) & reg);
+ bios_seg = (u16) (reg & 0xFF);
+ if (((reg & 0xFF00) >> 8) == 0xFF)
+ reg = 0;
+ bios_seg = (bios_seg << 8) + ((u16) ((reg & 0xFF00) >> 8));
+
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+ printk(KERN_WARNING "i91u: Could not set 32 bit DMA mask\n");
+ error = -ENODEV;
+ goto out_disable_device;
+ }
+ shost = scsi_host_alloc(&initio_template, sizeof(struct initio_host));
+ if (!shost) {
+ printk(KERN_WARNING "initio: Could not allocate host structure.\n");
+ error = -ENOMEM;
+ goto out_disable_device;
+ }
+ host = (struct initio_host *)shost->hostdata;
+ memset(host, 0, sizeof(struct initio_host));
- if (pSRB == NULL) {
- printk("pSRB is NULL\n");
+ if (!request_region(host->addr, 256, "i91u")) {
+ printk(KERN_WARNING "initio: I/O port range 0x%x is busy.\n", host->addr);
+ error = -ENODEV;
+ goto out_host_put;
}
- i91u_unmap_cmnd(pHCB->pci_dev, pSRB);
- pSRB->scsi_done(pSRB); /* Notify system DONE */
+ if (initio_tag_enable) /* 1.01i */
+ num_scb = MAX_TARGETS * i91u_MAXQUEUE;
+ else
+ num_scb = MAX_TARGETS + 3; /* 1-tape, 1-CD_ROM, 1- extra */
- tul_release_scb(pHCB, pSCB); /* Release SCB for current channel */
-}
+ for (; num_scb >= MAX_TARGETS + 3; num_scb--) {
+ i = num_scb * sizeof(struct scsi_ctrl_blk);
+ if ((scb = kzalloc(i, GFP_DMA)) != NULL)
+ break;
+ }
+
+ if (!scb) {
+ printk(KERN_WARNING "initio: Cannot allocate SCB array.\n");
+ error = -ENOMEM;
+ goto out_release_region;
+ }
-/*
- * Release ressources
+ host->num_scbs = num_scb;
+ host->scb = scb;
+ host->next_pending = scb;
+ host->next_avail = scb;
+ for (i = 0, tmp = scb; i < num_scb; i++, tmp++) {
+ tmp->tagid = i;
+ if (i != 0)
+ prev->next = tmp;
+ prev = tmp;
+ }
+ prev->next = NULL;
+ host->scb_end = tmp;
+ host->first_avail = scb;
+ host->last_avail = prev;
+
+ initio_init(host, phys_to_virt(bios_seg << 4));
+
+ host->jsstatus0 = 0;
+
+ shost->io_port = host->addr;
+ shost->n_io_port = 0xff;
+ shost->can_queue = num_scb; /* 03/05/98 */
+ shost->unique_id = host->addr;
+ shost->max_id = host->max_tar;
+ shost->max_lun = 32; /* 10/21/97 */
+ shost->irq = pdev->irq;
+ shost->this_id = host->scsi_id; /* Assign HCS index */
+ shost->base = host->addr;
+ shost->sg_tablesize = TOTAL_SG_ENTRY;
+
+ error = request_irq(pdev->irq, i91u_intr, IRQF_DISABLED|IRQF_SHARED, "i91u", shost);
+ if (error < 0) {
+ printk(KERN_WARNING "initio: Unable to request IRQ %d\n", pdev->irq);
+ goto out_free_scbs;
+ }
+
+ pci_set_drvdata(pdev, shost);
+ host->pci_dev = pdev;
+
+ error = scsi_add_host(shost, &pdev->dev);
+ if (error)
+ goto out_free_irq;
+ scsi_scan_host(shost);
+ return 0;
+out_free_irq:
+ free_irq(pdev->irq, shost);
+out_free_scbs:
+ kfree(host->scb);
+out_release_region:
+ release_region(host->addr, 256);
+out_host_put:
+ scsi_host_put(shost);
+out_disable_device:
+ pci_disable_device(pdev);
+ return error;
+}
+
+/**
+ * initio_remove_one - control shutdown
+ * @pdev: PCI device being released
+ *
+ * Release the resources assigned to this adapter after it has
+ * finished being used.
*/
-static int i91u_release(struct Scsi_Host *hreg)
+
+static void initio_remove_one(struct pci_dev *pdev)
{
- free_irq(hreg->irq, hreg);
- release_region(hreg->io_port, 256);
- return 0;
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct initio_host *s = (struct initio_host *)host->hostdata;
+ scsi_remove_host(host);
+ free_irq(pdev->irq, host);
+ release_region(s->addr, 256);
+ scsi_host_put(host);
+ pci_disable_device(pdev);
}
-MODULE_LICENSE("Dual BSD/GPL");
-
-static struct scsi_host_template driver_template = {
- .proc_name = "INI9100U",
- .name = i91u_REVID,
- .detect = i91u_detect,
- .release = i91u_release,
- .queuecommand = i91u_queuecommand,
-// .abort = i91u_abort,
-// .reset = i91u_reset,
- .eh_bus_reset_handler = i91u_bus_reset,
- .bios_param = i91u_biosparam,
- .can_queue = 1,
- .this_id = 1,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
+
+MODULE_LICENSE("GPL");
+
+static struct pci_device_id initio_pci_tbl[] = {
+ {PCI_VENDOR_ID_INIT, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_INIT, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_INIT, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_INIT, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_DOMEX, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+MODULE_DEVICE_TABLE(pci, initio_pci_tbl);
+
+static struct pci_driver initio_pci_driver = {
+ .name = "initio",
+ .id_table = initio_pci_tbl,
+ .probe = initio_probe_one,
+ .remove = __devexit_p(initio_remove_one),
};
-#include "scsi_module.c"
+static int __init initio_init_driver(void)
+{
+ return pci_register_driver(&initio_pci_driver);
+}
+
+static void __exit initio_exit_driver(void)
+{
+ pci_unregister_driver(&initio_pci_driver);
+}
+
+MODULE_DESCRIPTION("Initio INI-9X00U/UW SCSI device driver");
+MODULE_AUTHOR("Initio Corporation");
+MODULE_LICENSE("GPL");
+
+module_init(initio_init_driver);
+module_exit(initio_exit_driver);
diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h
index acb67a4af2cc..cb48efa81fe2 100644
--- a/drivers/scsi/initio.h
+++ b/drivers/scsi/initio.h
@@ -4,6 +4,8 @@
* Copyright (c) 1994-1998 Initio Corporation
* All rights reserved.
*
+ * Cleanups (c) Copyright 2007 Red Hat <alan@redhat.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -18,27 +20,6 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * --------------------------------------------------------------------------
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Where this Software is combined with software released under the terms of
- * the GNU General Public License ("GPL") and the terms of the GPL would require the
- * combined work to also be released under the terms of the GPL, the terms
- * and conditions of this License will apply in addition to those of the
- * GPL with the exception of any terms or conditions of this License that
- * conflict with, or are expressly prohibited by, the GPL.
- *
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -56,17 +37,6 @@
#include <linux/types.h>
-#define ULONG unsigned long
-#define USHORT unsigned short
-#define UCHAR unsigned char
-#define BYTE unsigned char
-#define WORD unsigned short
-#define DWORD unsigned long
-#define UBYTE unsigned char
-#define UWORD unsigned short
-#define UDWORD unsigned long
-#define U32 u32
-
#define TOTAL_SG_ENTRY 32
#define MAX_SUPPORTED_ADAPTERS 8
#define MAX_OFFSET 15
@@ -368,55 +338,55 @@ typedef struct {
/************************************************************************/
/* Scatter-Gather Element Structure */
/************************************************************************/
-typedef struct SG_Struc {
- U32 SG_Ptr; /* Data Pointer */
- U32 SG_Len; /* Data Length */
-} SG;
+struct sg_entry {
+ u32 data; /* Data Pointer */
+ u32 len; /* Data Length */
+};
/***********************************************************************
SCSI Control Block
************************************************************************/
-typedef struct Scsi_Ctrl_Blk {
- struct Scsi_Ctrl_Blk *SCB_NxtScb;
- UBYTE SCB_Status; /*4 */
- UBYTE SCB_NxtStat; /*5 */
- UBYTE SCB_Mode; /*6 */
- UBYTE SCB_Msgin; /*7 SCB_Res0 */
- UWORD SCB_SGIdx; /*8 */
- UWORD SCB_SGMax; /*A */
+struct scsi_ctrl_blk {
+ struct scsi_ctrl_blk *next;
+ u8 status; /*4 */
+ u8 next_state; /*5 */
+ u8 mode; /*6 */
+ u8 msgin; /*7 SCB_Res0 */
+ u16 sgidx; /*8 */
+ u16 sgmax; /*A */
#ifdef ALPHA
- U32 SCB_Reserved[2]; /*C */
+ u32 reserved[2]; /*C */
#else
- U32 SCB_Reserved[3]; /*C */
+ u32 reserved[3]; /*C */
#endif
- U32 SCB_XferLen; /*18 Current xfer len */
- U32 SCB_TotXLen; /*1C Total xfer len */
- U32 SCB_PAddr; /*20 SCB phy. Addr. */
-
- UBYTE SCB_Opcode; /*24 SCB command code */
- UBYTE SCB_Flags; /*25 SCB Flags */
- UBYTE SCB_Target; /*26 Target Id */
- UBYTE SCB_Lun; /*27 Lun */
- U32 SCB_BufPtr; /*28 Data Buffer Pointer */
- U32 SCB_BufLen; /*2C Data Allocation Length */
- UBYTE SCB_SGLen; /*30 SG list # */
- UBYTE SCB_SenseLen; /*31 Sense Allocation Length */
- UBYTE SCB_HaStat; /*32 */
- UBYTE SCB_TaStat; /*33 */
- UBYTE SCB_CDBLen; /*34 CDB Length */
- UBYTE SCB_Ident; /*35 Identify */
- UBYTE SCB_TagMsg; /*36 Tag Message */
- UBYTE SCB_TagId; /*37 Queue Tag */
- UBYTE SCB_CDB[12]; /*38 */
- U32 SCB_SGPAddr; /*44 SG List/Sense Buf phy. Addr. */
- U32 SCB_SensePtr; /*48 Sense data pointer */
- void (*SCB_Post) (BYTE *, BYTE *); /*4C POST routine */
- struct scsi_cmnd *SCB_Srb; /*50 SRB Pointer */
- SG SCB_SGList[TOTAL_SG_ENTRY]; /*54 Start of SG list */
-} SCB;
-
-/* Bit Definition for SCB_Status */
+ u32 xferlen; /*18 Current xfer len */
+ u32 totxlen; /*1C Total xfer len */
+ u32 paddr; /*20 SCB phy. Addr. */
+
+ u8 opcode; /*24 SCB command code */
+ u8 flags; /*25 SCB Flags */
+ u8 target; /*26 Target Id */
+ u8 lun; /*27 Lun */
+ u32 bufptr; /*28 Data Buffer Pointer */
+ u32 buflen; /*2C Data Allocation Length */
+ u8 sglen; /*30 SG list # */
+ u8 senselen; /*31 Sense Allocation Length */
+ u8 hastat; /*32 */
+ u8 tastat; /*33 */
+ u8 cdblen; /*34 CDB Length */
+ u8 ident; /*35 Identify */
+ u8 tagmsg; /*36 Tag Message */
+ u8 tagid; /*37 Queue Tag */
+ u8 cdb[12]; /*38 */
+ u32 sgpaddr; /*44 SG List/Sense Buf phy. Addr. */
+ u32 senseptr; /*48 Sense data pointer */
+ void (*post) (u8 *, u8 *); /*4C POST routine */
+ struct scsi_cmnd *srb; /*50 SRB Pointer */
+ struct sg_entry sglist[TOTAL_SG_ENTRY]; /*54 Start of SG list */
+};
+
+/* Bit Definition for status */
#define SCB_RENT 0x01
#define SCB_PEND 0x02
#define SCB_CONTIG 0x04 /* Contigent Allegiance */
@@ -425,17 +395,17 @@ typedef struct Scsi_Ctrl_Blk {
#define SCB_DONE 0x20
-/* Opcodes of SCB_Opcode */
+/* Opcodes for opcode */
#define ExecSCSI 0x1
#define BusDevRst 0x2
#define AbortCmd 0x3
-/* Bit Definition for SCB_Mode */
+/* Bit Definition for mode */
#define SCM_RSENS 0x01 /* request sense mode */
-/* Bit Definition for SCB_Flags */
+/* Bit Definition for flags */
#define SCF_DONE 0x01
#define SCF_POST 0x02
#define SCF_SENSE 0x04
@@ -492,15 +462,14 @@ typedef struct Scsi_Ctrl_Blk {
Target Device Control Structure
**********************************************************************/
-typedef struct Tar_Ctrl_Struc {
- UWORD TCS_Flags; /* 0 */
- UBYTE TCS_JS_Period; /* 2 */
- UBYTE TCS_SConfig0; /* 3 */
-
- UWORD TCS_DrvFlags; /* 4 */
- UBYTE TCS_DrvHead; /* 6 */
- UBYTE TCS_DrvSector; /* 7 */
-} TCS;
+struct target_control {
+ u16 flags;
+ u8 js_period;
+ u8 sconfig0;
+ u16 drv_flags;
+ u8 heads;
+ u8 sectors;
+};
/***********************************************************************
Target Device Control Structure
@@ -523,62 +492,53 @@ typedef struct Tar_Ctrl_Struc {
#define TCF_DRV_EN_TAG 0x0800
#define TCF_DRV_255_63 0x0400
-typedef struct I91u_Adpt_Struc {
- UWORD ADPT_BIOS; /* 0 */
- UWORD ADPT_BASE; /* 1 */
- UBYTE ADPT_Bus; /* 2 */
- UBYTE ADPT_Device; /* 3 */
- UBYTE ADPT_INTR; /* 4 */
-} INI_ADPT_STRUCT;
-
-
/***********************************************************************
Host Adapter Control Structure
************************************************************************/
-typedef struct Ha_Ctrl_Struc {
- UWORD HCS_Base; /* 00 */
- UWORD HCS_BIOS; /* 02 */
- UBYTE HCS_Intr; /* 04 */
- UBYTE HCS_SCSI_ID; /* 05 */
- UBYTE HCS_MaxTar; /* 06 */
- UBYTE HCS_NumScbs; /* 07 */
-
- UBYTE HCS_Flags; /* 08 */
- UBYTE HCS_Index; /* 09 */
- UBYTE HCS_HaId; /* 0A */
- UBYTE HCS_Config; /* 0B */
- UWORD HCS_IdMask; /* 0C */
- UBYTE HCS_Semaph; /* 0E */
- UBYTE HCS_Phase; /* 0F */
- UBYTE HCS_JSStatus0; /* 10 */
- UBYTE HCS_JSInt; /* 11 */
- UBYTE HCS_JSStatus1; /* 12 */
- UBYTE HCS_SConf1; /* 13 */
-
- UBYTE HCS_Msg[8]; /* 14 */
- SCB *HCS_NxtAvail; /* 1C */
- SCB *HCS_Scb; /* 20 */
- SCB *HCS_ScbEnd; /* 24 */
- SCB *HCS_NxtPend; /* 28 */
- SCB *HCS_NxtContig; /* 2C */
- SCB *HCS_ActScb; /* 30 */
- TCS *HCS_ActTcs; /* 34 */
-
- SCB *HCS_FirstAvail; /* 38 */
- SCB *HCS_LastAvail; /* 3C */
- SCB *HCS_FirstPend; /* 40 */
- SCB *HCS_LastPend; /* 44 */
- SCB *HCS_FirstBusy; /* 48 */
- SCB *HCS_LastBusy; /* 4C */
- SCB *HCS_FirstDone; /* 50 */
- SCB *HCS_LastDone; /* 54 */
- UBYTE HCS_MaxTags[16]; /* 58 */
- UBYTE HCS_ActTags[16]; /* 68 */
- TCS HCS_Tcs[MAX_TARGETS]; /* 78 */
- spinlock_t HCS_AvailLock;
- spinlock_t HCS_SemaphLock;
+struct initio_host {
+ u16 addr; /* 00 */
+ u16 bios_addr; /* 02 */
+ u8 irq; /* 04 */
+ u8 scsi_id; /* 05 */
+ u8 max_tar; /* 06 */
+ u8 num_scbs; /* 07 */
+
+ u8 flags; /* 08 */
+ u8 index; /* 09 */
+ u8 ha_id; /* 0A */
+ u8 config; /* 0B */
+ u16 idmask; /* 0C */
+ u8 semaph; /* 0E */
+ u8 phase; /* 0F */
+ u8 jsstatus0; /* 10 */
+ u8 jsint; /* 11 */
+ u8 jsstatus1; /* 12 */
+ u8 sconf1; /* 13 */
+
+ u8 msg[8]; /* 14 */
+ struct scsi_ctrl_blk *next_avail; /* 1C */
+ struct scsi_ctrl_blk *scb; /* 20 */
+ struct scsi_ctrl_blk *scb_end; /* 24 */ /*UNUSED*/
+ struct scsi_ctrl_blk *next_pending; /* 28 */
+ struct scsi_ctrl_blk *next_contig; /* 2C */ /*UNUSED*/
+ struct scsi_ctrl_blk *active; /* 30 */
+ struct target_control *active_tc; /* 34 */
+
+ struct scsi_ctrl_blk *first_avail; /* 38 */
+ struct scsi_ctrl_blk *last_avail; /* 3C */
+ struct scsi_ctrl_blk *first_pending; /* 40 */
+ struct scsi_ctrl_blk *last_pending; /* 44 */
+ struct scsi_ctrl_blk *first_busy; /* 48 */
+ struct scsi_ctrl_blk *last_busy; /* 4C */
+ struct scsi_ctrl_blk *first_done; /* 50 */
+ struct scsi_ctrl_blk *last_done; /* 54 */
+ u8 max_tags[16]; /* 58 */
+ u8 act_tags[16]; /* 68 */
+ struct target_control targets[MAX_TARGETS]; /* 78 */
+ spinlock_t avail_lock;
+ spinlock_t semaph_lock;
struct pci_dev *pci_dev;
-} HCS;
+};
/* Bit Definition for HCB_Config */
#define HCC_SCSI_RESET 0x01
@@ -599,47 +559,47 @@ typedef struct Ha_Ctrl_Struc {
*******************************************************************/
typedef struct _NVRAM_SCSI { /* SCSI channel configuration */
- UCHAR NVM_ChSCSIID; /* 0Ch -> Channel SCSI ID */
- UCHAR NVM_ChConfig1; /* 0Dh -> Channel config 1 */
- UCHAR NVM_ChConfig2; /* 0Eh -> Channel config 2 */
- UCHAR NVM_NumOfTarg; /* 0Fh -> Number of SCSI target */
+ u8 NVM_ChSCSIID; /* 0Ch -> Channel SCSI ID */
+ u8 NVM_ChConfig1; /* 0Dh -> Channel config 1 */
+ u8 NVM_ChConfig2; /* 0Eh -> Channel config 2 */
+ u8 NVM_NumOfTarg; /* 0Fh -> Number of SCSI target */
/* SCSI target configuration */
- UCHAR NVM_Targ0Config; /* 10h -> Target 0 configuration */
- UCHAR NVM_Targ1Config; /* 11h -> Target 1 configuration */
- UCHAR NVM_Targ2Config; /* 12h -> Target 2 configuration */
- UCHAR NVM_Targ3Config; /* 13h -> Target 3 configuration */
- UCHAR NVM_Targ4Config; /* 14h -> Target 4 configuration */
- UCHAR NVM_Targ5Config; /* 15h -> Target 5 configuration */
- UCHAR NVM_Targ6Config; /* 16h -> Target 6 configuration */
- UCHAR NVM_Targ7Config; /* 17h -> Target 7 configuration */
- UCHAR NVM_Targ8Config; /* 18h -> Target 8 configuration */
- UCHAR NVM_Targ9Config; /* 19h -> Target 9 configuration */
- UCHAR NVM_TargAConfig; /* 1Ah -> Target A configuration */
- UCHAR NVM_TargBConfig; /* 1Bh -> Target B configuration */
- UCHAR NVM_TargCConfig; /* 1Ch -> Target C configuration */
- UCHAR NVM_TargDConfig; /* 1Dh -> Target D configuration */
- UCHAR NVM_TargEConfig; /* 1Eh -> Target E configuration */
- UCHAR NVM_TargFConfig; /* 1Fh -> Target F configuration */
+ u8 NVM_Targ0Config; /* 10h -> Target 0 configuration */
+ u8 NVM_Targ1Config; /* 11h -> Target 1 configuration */
+ u8 NVM_Targ2Config; /* 12h -> Target 2 configuration */
+ u8 NVM_Targ3Config; /* 13h -> Target 3 configuration */
+ u8 NVM_Targ4Config; /* 14h -> Target 4 configuration */
+ u8 NVM_Targ5Config; /* 15h -> Target 5 configuration */
+ u8 NVM_Targ6Config; /* 16h -> Target 6 configuration */
+ u8 NVM_Targ7Config; /* 17h -> Target 7 configuration */
+ u8 NVM_Targ8Config; /* 18h -> Target 8 configuration */
+ u8 NVM_Targ9Config; /* 19h -> Target 9 configuration */
+ u8 NVM_TargAConfig; /* 1Ah -> Target A configuration */
+ u8 NVM_TargBConfig; /* 1Bh -> Target B configuration */
+ u8 NVM_TargCConfig; /* 1Ch -> Target C configuration */
+ u8 NVM_TargDConfig; /* 1Dh -> Target D configuration */
+ u8 NVM_TargEConfig; /* 1Eh -> Target E configuration */
+ u8 NVM_TargFConfig; /* 1Fh -> Target F configuration */
} NVRAM_SCSI;
typedef struct _NVRAM {
/*----------header ---------------*/
- USHORT NVM_Signature; /* 0,1: Signature */
- UCHAR NVM_Size; /* 2: Size of data structure */
- UCHAR NVM_Revision; /* 3: Revision of data structure */
+ u16 NVM_Signature; /* 0,1: Signature */
+ u8 NVM_Size; /* 2: Size of data structure */
+ u8 NVM_Revision; /* 3: Revision of data structure */
/* ----Host Adapter Structure ---- */
- UCHAR NVM_ModelByte0; /* 4: Model number (byte 0) */
- UCHAR NVM_ModelByte1; /* 5: Model number (byte 1) */
- UCHAR NVM_ModelInfo; /* 6: Model information */
- UCHAR NVM_NumOfCh; /* 7: Number of SCSI channel */
- UCHAR NVM_BIOSConfig1; /* 8: BIOS configuration 1 */
- UCHAR NVM_BIOSConfig2; /* 9: BIOS configuration 2 */
- UCHAR NVM_HAConfig1; /* A: Hoat adapter configuration 1 */
- UCHAR NVM_HAConfig2; /* B: Hoat adapter configuration 2 */
+ u8 NVM_ModelByte0; /* 4: Model number (byte 0) */
+ u8 NVM_ModelByte1; /* 5: Model number (byte 1) */
+ u8 NVM_ModelInfo; /* 6: Model information */
+ u8 NVM_NumOfCh; /* 7: Number of SCSI channel */
+ u8 NVM_BIOSConfig1; /* 8: BIOS configuration 1 */
+ u8 NVM_BIOSConfig2; /* 9: BIOS configuration 2 */
+ u8 NVM_HAConfig1; /* A: Hoat adapter configuration 1 */
+ u8 NVM_HAConfig2; /* B: Hoat adapter configuration 2 */
NVRAM_SCSI NVM_SCSIInfo[2];
- UCHAR NVM_reserved[10];
+ u8 NVM_reserved[10];
/* ---------- CheckSum ---------- */
- USHORT NVM_CheckSum; /* 0x3E, 0x3F: Checksum of NVRam */
+ u16 NVM_CheckSum; /* 0x3E, 0x3F: Checksum of NVRam */
} NVRAM, *PNVRAM;
/* Bios Configuration for nvram->BIOSConfig1 */
@@ -681,19 +641,6 @@ typedef struct _NVRAM {
#define DISC_ALLOW 0xC0 /* Disconnect is allowed */
#define SCSICMD_RequestSense 0x03
-typedef struct _HCSinfo {
- ULONG base;
- UCHAR vec;
- UCHAR bios; /* High byte of BIOS address */
- USHORT BaseAndBios; /* high byte: pHcsInfo->bios,low byte:pHcsInfo->base */
-} HCSINFO;
-
-#define TUL_RD(x,y) (UCHAR)(inb( (int)((ULONG)(x+y)) ))
-#define TUL_RDLONG(x,y) (ULONG)(inl((int)((ULONG)(x+y)) ))
-#define TUL_WR( adr,data) outb( (UCHAR)(data), (int)(adr))
-#define TUL_WRSHORT(adr,data) outw( (UWORD)(data), (int)(adr))
-#define TUL_WRLONG( adr,data) outl( (ULONG)(data), (int)(adr))
-
#define SCSI_ABORT_SNOOZE 0
#define SCSI_ABORT_SUCCESS 1
#define SCSI_ABORT_PENDING 2
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index fa6ff295e568..f142eafb6fc7 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -540,32 +540,6 @@ struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
}
/**
- * ipr_unmap_sglist - Unmap scatterlist if mapped
- * @ioa_cfg: ioa config struct
- * @ipr_cmd: ipr command struct
- *
- * Return value:
- * nothing
- **/
-static void ipr_unmap_sglist(struct ipr_ioa_cfg *ioa_cfg,
- struct ipr_cmnd *ipr_cmd)
-{
- struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
-
- if (ipr_cmd->dma_use_sg) {
- if (scsi_cmd->use_sg > 0) {
- pci_unmap_sg(ioa_cfg->pdev, scsi_cmd->request_buffer,
- scsi_cmd->use_sg,
- scsi_cmd->sc_data_direction);
- } else {
- pci_unmap_single(ioa_cfg->pdev, ipr_cmd->dma_handle,
- scsi_cmd->request_bufflen,
- scsi_cmd->sc_data_direction);
- }
- }
-}
-
-/**
* ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts
* @ioa_cfg: ioa config struct
* @clr_ints: interrupts to clear
@@ -677,7 +651,7 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
scsi_cmd->result |= (DID_ERROR << 16);
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
scsi_cmd->scsi_done(scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
}
@@ -2465,6 +2439,7 @@ restart:
/**
* ipr_read_trace - Dump the adapter trace
* @kobj: kobject struct
+ * @bin_attr: bin_attribute struct
* @buf: buffer
* @off: offset
* @count: buffer size
@@ -2472,8 +2447,9 @@ restart:
* Return value:
* number of bytes printed to buffer
**/
-static ssize_t ipr_read_trace(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t ipr_read_trace(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3166,6 +3142,7 @@ static struct class_device_attribute *ipr_ioa_attrs[] = {
/**
* ipr_read_dump - Dump the adapter
* @kobj: kobject struct
+ * @bin_attr: bin_attribute struct
* @buf: buffer
* @off: offset
* @count: buffer size
@@ -3173,8 +3150,9 @@ static struct class_device_attribute *ipr_ioa_attrs[] = {
* Return value:
* number of bytes printed to buffer
**/
-static ssize_t ipr_read_dump(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t ipr_read_dump(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -3327,6 +3305,7 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)
/**
* ipr_write_dump - Setup dump state of adapter
* @kobj: kobject struct
+ * @bin_attr: bin_attribute struct
* @buf: buffer
* @off: offset
* @count: buffer size
@@ -3334,8 +3313,9 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)
* Return value:
* number of bytes printed to buffer
**/
-static ssize_t ipr_write_dump(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t ipr_write_dump(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *shost = class_to_shost(cdev);
@@ -4292,93 +4272,55 @@ static irqreturn_t ipr_isr(int irq, void *devp)
static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_cmnd *ipr_cmd)
{
- int i;
- struct scatterlist *sglist;
+ int i, nseg;
+ struct scatterlist *sg;
u32 length;
u32 ioadl_flags = 0;
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
- length = scsi_cmd->request_bufflen;
-
- if (length == 0)
+ length = scsi_bufflen(scsi_cmd);
+ if (!length)
return 0;
- if (scsi_cmd->use_sg) {
- ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev,
- scsi_cmd->request_buffer,
- scsi_cmd->use_sg,
- scsi_cmd->sc_data_direction);
-
- if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_WRITE;
- ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
- ioarcb->write_data_transfer_length = cpu_to_be32(length);
- ioarcb->write_ioadl_len =
- cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
- } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_READ;
- ioarcb->read_data_transfer_length = cpu_to_be32(length);
- ioarcb->read_ioadl_len =
- cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
- }
-
- sglist = scsi_cmd->request_buffer;
+ nseg = scsi_dma_map(scsi_cmd);
+ if (nseg < 0) {
+ dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+ return -1;
+ }
- if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
- ioadl = ioarcb->add_data.u.ioadl;
- ioarcb->write_ioadl_addr =
- cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
- offsetof(struct ipr_ioarcb, add_data));
- ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
- }
+ ipr_cmd->dma_use_sg = nseg;
- for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
- ioadl[i].flags_and_data_len =
- cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
- ioadl[i].address =
- cpu_to_be32(sg_dma_address(&sglist[i]));
- }
+ if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+ ioarcb->write_data_transfer_length = cpu_to_be32(length);
+ ioarcb->write_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_READ;
+ ioarcb->read_data_transfer_length = cpu_to_be32(length);
+ ioarcb->read_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ }
- if (likely(ipr_cmd->dma_use_sg)) {
- ioadl[i-1].flags_and_data_len |=
- cpu_to_be32(IPR_IOADL_FLAGS_LAST);
- return 0;
- } else
- dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
- } else {
- if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_WRITE;
- ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
- ioarcb->write_data_transfer_length = cpu_to_be32(length);
- ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
- } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
- ioadl_flags = IPR_IOADL_FLAGS_READ;
- ioarcb->read_data_transfer_length = cpu_to_be32(length);
- ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
- }
+ if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->add_data.u.ioadl)) {
+ ioadl = ioarcb->add_data.u.ioadl;
+ ioarcb->write_ioadl_addr =
+ cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
+ offsetof(struct ipr_ioarcb, add_data));
+ ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+ }
- ipr_cmd->dma_handle = pci_map_single(ioa_cfg->pdev,
- scsi_cmd->request_buffer, length,
- scsi_cmd->sc_data_direction);
-
- if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) {
- ioadl = ioarcb->add_data.u.ioadl;
- ioarcb->write_ioadl_addr =
- cpu_to_be32(be32_to_cpu(ioarcb->ioarcb_host_pci_addr) +
- offsetof(struct ipr_ioarcb, add_data));
- ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
- ipr_cmd->dma_use_sg = 1;
- ioadl[0].flags_and_data_len =
- cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST);
- ioadl[0].address = cpu_to_be32(ipr_cmd->dma_handle);
- return 0;
- } else
- dev_err(&ioa_cfg->pdev->dev, "pci_map_single failed!\n");
+ scsi_for_each_sg(scsi_cmd, sg, ipr_cmd->dma_use_sg, i) {
+ ioadl[i].flags_and_data_len =
+ cpu_to_be32(ioadl_flags | sg_dma_len(sg));
+ ioadl[i].address = cpu_to_be32(sg_dma_address(sg));
}
- return -1;
+ ioadl[i-1].flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+ return 0;
}
/**
@@ -4441,7 +4383,7 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
res->needs_sync_complete = 1;
res->in_erp = 0;
}
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
scsi_cmd->scsi_done(scsi_cmd);
}
@@ -4819,7 +4761,7 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
break;
}
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
scsi_cmd->scsi_done(scsi_cmd);
}
@@ -4840,10 +4782,10 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
- scsi_cmd->resid = be32_to_cpu(ipr_cmd->ioasa.residual_data_len);
+ scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->ioasa.residual_data_len));
if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
- ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+ scsi_dma_unmap(ipr_cmd->scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
scsi_cmd->scsi_done(scsi_cmd);
} else
@@ -5367,18 +5309,12 @@ static const u16 ipr_blocked_processors[] = {
**/
static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg)
{
- u8 rev_id;
int i;
- if (ioa_cfg->type == 0x5702) {
- if (pci_read_config_byte(ioa_cfg->pdev, PCI_REVISION_ID,
- &rev_id) == PCIBIOS_SUCCESSFUL) {
- if (rev_id < 4) {
- for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){
- if (__is_processor(ipr_blocked_processors[i]))
- return 1;
- }
- }
+ if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) {
+ for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){
+ if (__is_processor(ipr_blocked_processors[i]))
+ return 1;
}
}
return 0;
@@ -7535,13 +7471,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
else
ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT;
- rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &ioa_cfg->revid);
-
- if (rc != PCIBIOS_SUCCESSFUL) {
- dev_err(&pdev->dev, "Failed to read PCI revision ID\n");
- rc = -EIO;
- goto out_scsi_host_put;
- }
+ ioa_cfg->revid = pdev->revision;
ipr_regs_pci = pci_resource_start(pdev, 0);
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 8b704f73055a..492a51bd6aa8 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -211,19 +211,6 @@ module_param(ips, charp, 0);
#warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
#endif
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-#include <linux/blk.h>
-#include "sd.h"
-#define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
-#define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
-#ifndef __devexit_p
-#define __devexit_p(x) x
-#endif
-#else
-#define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0)
-#define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0)
-#endif
-
#define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \
PCI_DMA_BIDIRECTIONAL : \
@@ -381,24 +368,13 @@ static struct scsi_host_template ips_driver_template = {
.eh_abort_handler = ips_eh_abort,
.eh_host_reset_handler = ips_eh_reset,
.proc_name = "ips",
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
.proc_info = ips_proc_info,
.slave_configure = ips_slave_configure,
-#else
- .proc_info = ips_proc24_info,
- .select_queue_depths = ips_select_queue_depth,
-#endif
.bios_param = ips_biosparam,
.this_id = -1,
.sg_tablesize = IPS_MAX_SG,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- .use_new_eh_code = 1,
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- .highmem_io = 1,
-#endif
};
@@ -731,7 +707,7 @@ ips_release(struct Scsi_Host *sh)
/* free IRQ */
free_irq(ha->irq, ha);
- IPS_REMOVE_HOST(sh);
+ scsi_remove_host(sh);
scsi_host_put(sh);
ips_released_controllers++;
@@ -813,7 +789,6 @@ int ips_eh_abort(struct scsi_cmnd *SC)
ips_ha_t *ha;
ips_copp_wait_item_t *item;
int ret;
- unsigned long cpu_flags;
struct Scsi_Host *host;
METHOD_TRACE("ips_eh_abort", 1);
@@ -830,7 +805,7 @@ int ips_eh_abort(struct scsi_cmnd *SC)
if (!ha->active)
return (FAILED);
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
/* See if the command is on the copp queue */
item = ha->copp_waitlist.head;
@@ -851,7 +826,7 @@ int ips_eh_abort(struct scsi_cmnd *SC)
ret = (FAILED);
}
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
return ret;
}
@@ -1129,7 +1104,7 @@ static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
/* A Reset IOCTL is only sent by the boot CD in extreme cases. */
/* There can never be any system activity ( network or disk ), but check */
/* anyway just as a good practice. */
- pt = (ips_passthru_t *) SC->request_buffer;
+ pt = (ips_passthru_t *) scsi_sglist(SC);
if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
(pt->CoppCP.cmd.reset.adapter_flag == 1)) {
if (ha->scb_activelist.count != 0) {
@@ -1176,18 +1151,10 @@ static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
/* Set bios geometry for the controller */
/* */
/****************************************************************************/
-static int
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-ips_biosparam(Disk * disk, kdev_t dev, int geom[])
-{
- ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata;
- unsigned long capacity = disk->capacity;
-#else
-ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int geom[])
+static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int geom[])
{
ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
-#endif
int heads;
int sectors;
int cylinders;
@@ -1225,70 +1192,6 @@ ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
return (0);
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
-/* ips_proc24_info is a wrapper around ips_proc_info *
- * for compatibility with the 2.4 scsi parameters */
-static int
-ips_proc24_info(char *buffer, char **start, off_t offset, int length,
- int hostno, int func)
-{
- int i;
-
- for (i = 0; i < ips_next_controller; i++) {
- if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
- return ips_proc_info(ips_sh[i], buffer, start,
- offset, length, func);
- }
- }
- return -EINVAL;
-}
-
-/****************************************************************************/
-/* */
-/* Routine Name: ips_select_queue_depth */
-/* */
-/* Routine Description: */
-/* */
-/* Select queue depths for the devices on the contoller */
-/* */
-/****************************************************************************/
-static void
-ips_select_queue_depth(struct Scsi_Host *host, struct scsi_device * scsi_devs)
-{
- struct scsi_device *device;
- ips_ha_t *ha;
- int count = 0;
- int min;
-
- ha = IPS_HA(host);
- min = ha->max_cmds / 4;
-
- for (device = scsi_devs; device; device = device->next) {
- if (device->host == host) {
- if ((device->channel == 0) && (device->type == 0))
- count++;
- }
- }
-
- for (device = scsi_devs; device; device = device->next) {
- if (device->host == host) {
- if ((device->channel == 0) && (device->type == 0)) {
- device->queue_depth =
- (ha->max_cmds - 1) / count;
- if (device->queue_depth < min)
- device->queue_depth = min;
- } else {
- device->queue_depth = 2;
- }
-
- if (device->queue_depth < 2)
- device->queue_depth = 2;
- }
- }
-}
-
-#else
/****************************************************************************/
/* */
/* Routine Name: ips_slave_configure */
@@ -1316,7 +1219,6 @@ ips_slave_configure(struct scsi_device * SDptr)
SDptr->skip_ms_page_3f = 1;
return 0;
}
-#endif
/****************************************************************************/
/* */
@@ -1331,7 +1233,6 @@ static irqreturn_t
do_ipsintr(int irq, void *dev_id)
{
ips_ha_t *ha;
- unsigned long cpu_flags;
struct Scsi_Host *host;
int irqstatus;
@@ -1347,16 +1248,16 @@ do_ipsintr(int irq, void *dev_id)
return IRQ_HANDLED;
}
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
if (!ha->active) {
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
return IRQ_HANDLED;
}
irqstatus = (*ha->func.intr) (ha);
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
/* start the next command */
ips_next(ha, IPS_INTR_ON);
@@ -1606,30 +1507,22 @@ static int ips_is_passthru(struct scsi_cmnd *SC)
if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
(SC->device->channel == 0) &&
(SC->device->id == IPS_ADAPTER_ID) &&
- (SC->device->lun == 0) && SC->request_buffer) {
- if ((!SC->use_sg) && SC->request_bufflen &&
- (((char *) SC->request_buffer)[0] == 'C') &&
- (((char *) SC->request_buffer)[1] == 'O') &&
- (((char *) SC->request_buffer)[2] == 'P') &&
- (((char *) SC->request_buffer)[3] == 'P'))
- return 1;
- else if (SC->use_sg) {
- struct scatterlist *sg = SC->request_buffer;
- char *buffer;
-
- /* kmap_atomic() ensures addressability of the user buffer.*/
- /* local_irq_save() protects the KM_IRQ0 address slot. */
- local_irq_save(flags);
- buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
- buffer[2] == 'P' && buffer[3] == 'P') {
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- local_irq_restore(flags);
- return 1;
- }
- kunmap_atomic(buffer - sg->offset, KM_IRQ0);
- local_irq_restore(flags);
- }
+ (SC->device->lun == 0) && scsi_sglist(SC)) {
+ struct scatterlist *sg = scsi_sglist(SC);
+ char *buffer;
+
+ /* kmap_atomic() ensures addressability of the user buffer.*/
+ /* local_irq_save() protects the KM_IRQ0 address slot. */
+ local_irq_save(flags);
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
+ buffer[2] == 'P' && buffer[3] == 'P') {
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
+ return 1;
+ }
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ local_irq_restore(flags);
}
return 0;
}
@@ -1680,18 +1573,14 @@ ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
{
ips_passthru_t *pt;
int length = 0;
- int ret;
+ int i, ret;
+ struct scatterlist *sg = scsi_sglist(SC);
METHOD_TRACE("ips_make_passthru", 1);
- if (!SC->use_sg) {
- length = SC->request_bufflen;
- } else {
- struct scatterlist *sg = SC->request_buffer;
- int i;
- for (i = 0; i < SC->use_sg; i++)
- length += sg[i].length;
- }
+ scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i)
+ length += sg[i].length;
+
if (length < sizeof (ips_passthru_t)) {
/* wrong size */
DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
@@ -2115,7 +2004,7 @@ ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
METHOD_TRACE("ips_cleanup_passthru", 1);
- if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
+ if ((!scb) || (!scb->scsi_cmd) || (!scsi_sglist(scb->scsi_cmd))) {
DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
ips_name, ha->host_num);
@@ -2730,7 +2619,6 @@ ips_next(ips_ha_t * ha, int intr)
struct scsi_cmnd *q;
ips_copp_wait_item_t *item;
int ret;
- unsigned long cpu_flags = 0;
struct Scsi_Host *host;
METHOD_TRACE("ips_next", 1);
@@ -2742,7 +2630,7 @@ ips_next(ips_ha_t * ha, int intr)
* this command won't time out
*/
if (intr == IPS_INTR_ON)
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
if ((ha->subsys->param[3] & 0x300000)
&& (ha->scb_activelist.count == 0)) {
@@ -2769,14 +2657,14 @@ ips_next(ips_ha_t * ha, int intr)
item = ips_removeq_copp_head(&ha->copp_waitlist);
ha->num_ioctl++;
if (intr == IPS_INTR_ON)
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
scb->scsi_cmd = item->scsi_cmd;
kfree(item);
ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
if (intr == IPS_INTR_ON)
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
switch (ret) {
case IPS_FAILURE:
if (scb->scsi_cmd) {
@@ -2846,7 +2734,7 @@ ips_next(ips_ha_t * ha, int intr)
SC = ips_removeq_wait(&ha->scb_waitlist, q);
if (intr == IPS_INTR_ON)
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags); /* Unlock HA after command is taken off queue */
+ spin_unlock(host->host_lock); /* Unlock HA after command is taken off queue */
SC->result = DID_OK;
SC->host_scribble = NULL;
@@ -2866,41 +2754,26 @@ ips_next(ips_ha_t * ha, int intr)
/* copy in the CDB */
memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
- /* Now handle the data buffer */
- if (SC->use_sg) {
+ scb->sg_count = scsi_dma_map(SC);
+ BUG_ON(scb->sg_count < 0);
+ if (scb->sg_count) {
struct scatterlist *sg;
int i;
- sg = SC->request_buffer;
- scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
- SC->sc_data_direction);
scb->flags |= IPS_SCB_MAP_SG;
- for (i = 0; i < scb->sg_count; i++) {
+
+ scsi_for_each_sg(SC, sg, scb->sg_count, i) {
if (ips_fill_scb_sg_single
- (ha, sg_dma_address(&sg[i]), scb, i,
- sg_dma_len(&sg[i])) < 0)
+ (ha, sg_dma_address(sg), scb, i,
+ sg_dma_len(sg)) < 0)
break;
}
scb->dcdb.transfer_length = scb->data_len;
} else {
- if (SC->request_bufflen) {
- scb->data_busaddr =
- pci_map_single(ha->pcidev,
- SC->request_buffer,
- SC->request_bufflen,
- SC->sc_data_direction);
- scb->flags |= IPS_SCB_MAP_SINGLE;
- ips_fill_scb_sg_single(ha, scb->data_busaddr,
- scb, 0,
- SC->request_bufflen);
- scb->dcdb.transfer_length = scb->data_len;
- } else {
- scb->data_busaddr = 0L;
- scb->sg_len = 0;
- scb->data_len = 0;
- scb->dcdb.transfer_length = 0;
- }
-
+ scb->data_busaddr = 0L;
+ scb->sg_len = 0;
+ scb->data_len = 0;
+ scb->dcdb.transfer_length = 0;
}
scb->dcdb.cmd_attribute =
@@ -2919,7 +2792,7 @@ ips_next(ips_ha_t * ha, int intr)
scb->dcdb.transfer_length = 0;
}
if (intr == IPS_INTR_ON)
- IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+ spin_lock(host->host_lock);
ret = ips_send_cmd(ha, scb);
@@ -2958,7 +2831,7 @@ ips_next(ips_ha_t * ha, int intr)
} /* end while */
if (intr == IPS_INTR_ON)
- IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+ spin_unlock(host->host_lock);
}
/****************************************************************************/
@@ -3377,52 +3250,32 @@ ips_done(ips_ha_t * ha, ips_scb_t * scb)
* the rest of the data and continue.
*/
if ((scb->breakup) || (scb->sg_break)) {
+ struct scatterlist *sg;
+ int sg_dma_index, ips_sg_index = 0;
+
/* we had a data breakup */
scb->data_len = 0;
- if (scb->sg_count) {
- /* S/G request */
- struct scatterlist *sg;
- int ips_sg_index = 0;
- int sg_dma_index;
-
- sg = scb->scsi_cmd->request_buffer;
-
- /* Spin forward to last dma chunk */
- sg_dma_index = scb->breakup;
-
- /* Take care of possible partial on last chunk */
- ips_fill_scb_sg_single(ha,
- sg_dma_address(&sg
- [sg_dma_index]),
- scb, ips_sg_index++,
- sg_dma_len(&sg
- [sg_dma_index]));
-
- for (; sg_dma_index < scb->sg_count;
- sg_dma_index++) {
- if (ips_fill_scb_sg_single
- (ha,
- sg_dma_address(&sg[sg_dma_index]),
- scb, ips_sg_index++,
- sg_dma_len(&sg[sg_dma_index])) < 0)
- break;
+ sg = scsi_sglist(scb->scsi_cmd);
- }
+ /* Spin forward to last dma chunk */
+ sg_dma_index = scb->breakup;
- } else {
- /* Non S/G Request */
- (void) ips_fill_scb_sg_single(ha,
- scb->
- data_busaddr +
- (scb->sg_break *
- ha->max_xfer),
- scb, 0,
- scb->scsi_cmd->
- request_bufflen -
- (scb->sg_break *
- ha->max_xfer));
- }
+ /* Take care of possible partial on last chunk */
+ ips_fill_scb_sg_single(ha,
+ sg_dma_address(&sg[sg_dma_index]),
+ scb, ips_sg_index++,
+ sg_dma_len(&sg[sg_dma_index]));
+
+ for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd);
+ sg_dma_index++) {
+ if (ips_fill_scb_sg_single
+ (ha,
+ sg_dma_address(&sg[sg_dma_index]),
+ scb, ips_sg_index++,
+ sg_dma_len(&sg[sg_dma_index])) < 0)
+ break;
+ }
scb->dcdb.transfer_length = scb->data_len;
scb->dcdb.cmd_attribute |=
@@ -3653,32 +3506,27 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
static void
ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
- if (scmd->use_sg) {
- int i;
- unsigned int min_cnt, xfer_cnt;
- char *cdata = (char *) data;
- unsigned char *buffer;
- unsigned long flags;
- struct scatterlist *sg = scmd->request_buffer;
- for (i = 0, xfer_cnt = 0;
- (i < scmd->use_sg) && (xfer_cnt < count); i++) {
- min_cnt = min(count - xfer_cnt, sg[i].length);
-
- /* kmap_atomic() ensures addressability of the data buffer.*/
- /* local_irq_save() protects the KM_IRQ0 address slot. */
- local_irq_save(flags);
- buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
- memcpy(buffer, &cdata[xfer_cnt], min_cnt);
- kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
- local_irq_restore(flags);
-
- xfer_cnt += min_cnt;
- }
-
- } else {
- unsigned int min_cnt = min(count, scmd->request_bufflen);
- memcpy(scmd->request_buffer, data, min_cnt);
- }
+ int i;
+ unsigned int min_cnt, xfer_cnt;
+ char *cdata = (char *) data;
+ unsigned char *buffer;
+ unsigned long flags;
+ struct scatterlist *sg = scsi_sglist(scmd);
+
+ for (i = 0, xfer_cnt = 0;
+ (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) {
+ min_cnt = min(count - xfer_cnt, sg[i].length);
+
+ /* kmap_atomic() ensures addressability of the data buffer.*/
+ /* local_irq_save() protects the KM_IRQ0 address slot. */
+ local_irq_save(flags);
+ buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+ memcpy(buffer, &cdata[xfer_cnt], min_cnt);
+ kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
+ local_irq_restore(flags);
+
+ xfer_cnt += min_cnt;
+ }
}
/****************************************************************************/
@@ -3691,32 +3539,27 @@ ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
static void
ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
- if (scmd->use_sg) {
- int i;
- unsigned int min_cnt, xfer_cnt;
- char *cdata = (char *) data;
- unsigned char *buffer;
- unsigned long flags;
- struct scatterlist *sg = scmd->request_buffer;
- for (i = 0, xfer_cnt = 0;
- (i < scmd->use_sg) && (xfer_cnt < count); i++) {
- min_cnt = min(count - xfer_cnt, sg[i].length);
-
- /* kmap_atomic() ensures addressability of the data buffer.*/
- /* local_irq_save() protects the KM_IRQ0 address slot. */
- local_irq_save(flags);
- buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
- memcpy(&cdata[xfer_cnt], buffer, min_cnt);
- kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
- local_irq_restore(flags);
-
- xfer_cnt += min_cnt;
- }
-
- } else {
- unsigned int min_cnt = min(count, scmd->request_bufflen);
- memcpy(data, scmd->request_buffer, min_cnt);
- }
+ int i;
+ unsigned int min_cnt, xfer_cnt;
+ char *cdata = (char *) data;
+ unsigned char *buffer;
+ unsigned long flags;
+ struct scatterlist *sg = scsi_sglist(scmd);
+
+ for (i = 0, xfer_cnt = 0;
+ (i < scsi_sg_count(scmd)) && (xfer_cnt < count); i++) {
+ min_cnt = min(count - xfer_cnt, sg[i].length);
+
+ /* kmap_atomic() ensures addressability of the data buffer.*/
+ /* local_irq_save() protects the KM_IRQ0 address slot. */
+ local_irq_save(flags);
+ buffer = kmap_atomic(sg[i].page, KM_IRQ0) + sg[i].offset;
+ memcpy(&cdata[xfer_cnt], buffer, min_cnt);
+ kunmap_atomic(buffer - sg[i].offset, KM_IRQ0);
+ local_irq_restore(flags);
+
+ xfer_cnt += min_cnt;
+ }
}
/****************************************************************************/
@@ -4350,7 +4193,7 @@ ips_rdcap(ips_ha_t * ha, ips_scb_t * scb)
METHOD_TRACE("ips_rdcap", 1);
- if (scb->scsi_cmd->request_bufflen < 8)
+ if (scsi_bufflen(scb->scsi_cmd) < 8)
return (0);
cap.lba =
@@ -4735,8 +4578,7 @@ ips_freescb(ips_ha_t * ha, ips_scb_t * scb)
METHOD_TRACE("ips_freescb", 1);
if (scb->flags & IPS_SCB_MAP_SG)
- pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
- scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb));
+ scsi_dma_unmap(scb->scsi_cmd);
else if (scb->flags & IPS_SCB_MAP_SINGLE)
pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
IPS_DMA_DIR(scb));
@@ -7004,7 +6846,6 @@ ips_register_scsi(int index)
kfree(oldha);
ips_sh[index] = sh;
ips_ha[index] = ha;
- IPS_SCSI_SET_DEVICE(sh, ha);
/* Store away needed values for later use */
sh->io_port = ha->io_addr;
@@ -7016,17 +6857,16 @@ ips_register_scsi(int index)
sh->cmd_per_lun = sh->hostt->cmd_per_lun;
sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
sh->use_clustering = sh->hostt->use_clustering;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
sh->max_sectors = 128;
-#endif
sh->max_id = ha->ntargets;
sh->max_lun = ha->nlun;
sh->max_channel = ha->nbus - 1;
sh->can_queue = ha->max_cmds - 1;
- IPS_ADD_HOST(sh, NULL);
+ scsi_add_host(sh, NULL);
+ scsi_scan_host(sh);
+
return 0;
}
@@ -7069,7 +6909,7 @@ ips_module_init(void)
return -ENODEV;
ips_driver_template.module = THIS_MODULE;
ips_order_controllers();
- if (IPS_REGISTER_HOSTS(&ips_driver_template)) {
+ if (!ips_detect(&ips_driver_template)) {
pci_unregister_driver(&ips_pci_driver);
return -ENODEV;
}
@@ -7087,7 +6927,6 @@ ips_module_init(void)
static void __exit
ips_module_exit(void)
{
- IPS_UNREGISTER_HOSTS(&ips_driver_template);
pci_unregister_driver(&ips_pci_driver);
unregister_reboot_notifier(&ips_notifier);
}
@@ -7148,7 +6987,6 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
uint32_t mem_addr;
uint32_t io_len;
uint32_t mem_len;
- uint8_t revision_id;
uint8_t bus;
uint8_t func;
uint8_t irq;
@@ -7227,23 +7065,16 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
}
}
- /* get the revision ID */
- if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
- IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n");
- return -1;
- }
-
subdevice_id = pci_dev->subsystem_device;
/* found a controller */
- ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
+ ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
if (ha == NULL) {
IPS_PRINTK(KERN_WARNING, pci_dev,
"Unable to allocate temporary ha struct\n");
return -1;
}
- memset(ha, 0, sizeof (ips_ha_t));
ips_sh[index] = NULL;
ips_ha[index] = ha;
@@ -7258,7 +7089,7 @@ ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
ha->mem_ptr = mem_ptr;
ha->ioremap_ptr = ioremap_ptr;
ha->host_num = (uint32_t) index;
- ha->revision_id = revision_id;
+ ha->revision_id = pci_dev->revision;
ha->slot_num = PCI_SLOT(pci_dev->devfn);
ha->device_id = pci_dev->device;
ha->subdevice_id = subdevice_id;
@@ -7443,15 +7274,9 @@ ips_init_phase2(int index)
return SUCCESS;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
MODULE_LICENSE("GPL");
-#endif
-
MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);
-
-#ifdef MODULE_VERSION
MODULE_VERSION(IPS_VER_STRING);
-#endif
/*
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index b726dcc424b1..24123d537c58 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -58,10 +58,6 @@
/*
* Some handy macros
*/
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || defined CONFIG_HIGHIO
- #define IPS_HIGHIO
- #endif
-
#define IPS_HA(x) ((ips_ha_t *) x->hostdata)
#define IPS_COMMAND_ID(ha, scb) (int) (scb - ha->scbs)
#define IPS_IS_TROMBONE(ha) (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
@@ -84,38 +80,8 @@
#define IPS_SGLIST_SIZE(ha) (IPS_USE_ENH_SGLIST(ha) ? \
sizeof(IPS_ENH_SG_LIST) : sizeof(IPS_STD_SG_LIST))
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
- #define pci_set_dma_mask(dev,mask) ( mask > 0xffffffff ? 1:0 )
- #define scsi_set_pci_device(sh,dev) (0)
- #endif
-
- #ifndef IRQ_NONE
- typedef void irqreturn_t;
- #define IRQ_NONE
- #define IRQ_HANDLED
- #define IRQ_RETVAL(x)
- #endif
-
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- #define IPS_REGISTER_HOSTS(SHT) scsi_register_module(MODULE_SCSI_HA,SHT)
- #define IPS_UNREGISTER_HOSTS(SHT) scsi_unregister_module(MODULE_SCSI_HA,SHT)
- #define IPS_ADD_HOST(shost,device)
- #define IPS_REMOVE_HOST(shost)
- #define IPS_SCSI_SET_DEVICE(sh,ha) scsi_set_pci_device(sh, (ha)->pcidev)
- #define IPS_PRINTK(level, pcidev, format, arg...) \
- printk(level "%s %s:" format , "ips" , \
- (pcidev)->slot_name , ## arg)
- #define scsi_host_alloc(sh,size) scsi_register(sh,size)
- #define scsi_host_put(sh) scsi_unregister(sh)
- #else
- #define IPS_REGISTER_HOSTS(SHT) (!ips_detect(SHT))
- #define IPS_UNREGISTER_HOSTS(SHT)
- #define IPS_ADD_HOST(shost,device) do { scsi_add_host(shost,device); scsi_scan_host(shost); } while (0)
- #define IPS_REMOVE_HOST(shost) scsi_remove_host(shost)
- #define IPS_SCSI_SET_DEVICE(sh,ha) do { } while (0)
- #define IPS_PRINTK(level, pcidev, format, arg...) \
+ #define IPS_PRINTK(level, pcidev, format, arg...) \
dev_printk(level , &((pcidev)->dev) , format , ## arg)
- #endif
#define MDELAY(n) \
do { \
@@ -134,7 +100,7 @@
#define pci_dma_hi32(a) ((a >> 16) >> 16)
#define pci_dma_lo32(a) (a & 0xffffffff)
- #if (BITS_PER_LONG > 32) || (defined CONFIG_HIGHMEM64G && defined IPS_HIGHIO)
+ #if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G)
#define IPS_ENABLE_DMA64 (1)
#else
#define IPS_ENABLE_DMA64 (0)
@@ -451,16 +417,10 @@
/*
* Scsi_Host Template
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- static int ips_proc24_info(char *, char **, off_t, int, int, int);
- static void ips_select_queue_depth(struct Scsi_Host *, struct scsi_device *);
- static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
-#else
static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[]);
static int ips_slave_configure(struct scsi_device *SDptr);
-#endif
/*
* Raid Command Formats
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index c9a3abf9e7b6..7829ab1e2fb4 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -29,14 +29,15 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/inet.h>
+#include <linux/file.h>
#include <linux/blkdev.h>
#include <linux/crypto.h>
#include <linux/delay.h>
#include <linux/kfifo.h>
#include <linux/scatterlist.h>
-#include <linux/mutex.h>
#include <net/tcp.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi.h>
#include <scsi/scsi_transport_iscsi.h>
@@ -109,7 +110,7 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
- buf->sg.length = tcp_conn->hdr_size;
+ buf->sg.length += sizeof(u32);
}
static inline int
@@ -211,16 +212,14 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
static int
iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
- int rc;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr;
struct iscsi_session *session = conn->session;
+ struct scsi_cmnd *sc = ctask->sc;
int datasn = be32_to_cpu(rhdr->datasn);
- rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (rc)
- return rc;
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
/*
* setup Data-In byte counter (gets decremented..)
*/
@@ -229,31 +228,36 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
if (tcp_conn->in.datalen == 0)
return 0;
- if (ctask->datasn != datasn)
+ if (tcp_ctask->exp_datasn != datasn) {
+ debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->datasn(%d)\n",
+ __FUNCTION__, tcp_ctask->exp_datasn, datasn);
return ISCSI_ERR_DATASN;
+ }
- ctask->datasn++;
+ tcp_ctask->exp_datasn++;
tcp_ctask->data_offset = be32_to_cpu(rhdr->offset);
- if (tcp_ctask->data_offset + tcp_conn->in.datalen > ctask->total_length)
+ if (tcp_ctask->data_offset + tcp_conn->in.datalen > scsi_bufflen(sc)) {
+ debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n",
+ __FUNCTION__, tcp_ctask->data_offset,
+ tcp_conn->in.datalen, scsi_bufflen(sc));
return ISCSI_ERR_DATA_OFFSET;
+ }
if (rhdr->flags & ISCSI_FLAG_DATA_STATUS) {
- struct scsi_cmnd *sc = ctask->sc;
-
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
if (rhdr->flags & ISCSI_FLAG_DATA_UNDERFLOW) {
int res_count = be32_to_cpu(rhdr->residual_count);
if (res_count > 0 &&
- res_count <= sc->request_bufflen) {
- sc->resid = res_count;
+ res_count <= scsi_bufflen(sc)) {
+ scsi_set_resid(sc, res_count);
sc->result = (DID_OK << 16) | rhdr->cmd_status;
} else
sc->result = (DID_BAD_TARGET << 16) |
rhdr->cmd_status;
} else if (rhdr->flags & ISCSI_FLAG_DATA_OVERFLOW) {
- sc->resid = be32_to_cpu(rhdr->residual_count);
+ scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
sc->result = (DID_OK << 16) | rhdr->cmd_status;
} else
sc->result = (DID_OK << 16) | rhdr->cmd_status;
@@ -281,6 +285,8 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
{
struct iscsi_data *hdr;
struct scsi_cmnd *sc = ctask->sc;
+ int i, sg_count = 0;
+ struct scatterlist *sg;
hdr = &r2t->dtask.hdr;
memset(hdr, 0, sizeof(struct iscsi_data));
@@ -308,39 +314,30 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
sizeof(struct iscsi_hdr));
- if (sc->use_sg) {
- int i, sg_count = 0;
- struct scatterlist *sg = sc->request_buffer;
-
- r2t->sg = NULL;
- for (i = 0; i < sc->use_sg; i++, sg += 1) {
- /* FIXME: prefetch ? */
- if (sg_count + sg->length > r2t->data_offset) {
- int page_offset;
+ sg = scsi_sglist(sc);
+ r2t->sg = NULL;
+ for (i = 0; i < scsi_sg_count(sc); i++, sg += 1) {
+ /* FIXME: prefetch ? */
+ if (sg_count + sg->length > r2t->data_offset) {
+ int page_offset;
- /* sg page found! */
+ /* sg page found! */
- /* offset within this page */
- page_offset = r2t->data_offset - sg_count;
+ /* offset within this page */
+ page_offset = r2t->data_offset - sg_count;
- /* fill in this buffer */
- iscsi_buf_init_sg(&r2t->sendbuf, sg);
- r2t->sendbuf.sg.offset += page_offset;
- r2t->sendbuf.sg.length -= page_offset;
+ /* fill in this buffer */
+ iscsi_buf_init_sg(&r2t->sendbuf, sg);
+ r2t->sendbuf.sg.offset += page_offset;
+ r2t->sendbuf.sg.length -= page_offset;
- /* xmit logic will continue with next one */
- r2t->sg = sg + 1;
- break;
- }
- sg_count += sg->length;
+ /* xmit logic will continue with next one */
+ r2t->sg = sg + 1;
+ break;
}
- BUG_ON(r2t->sg == NULL);
- } else {
- iscsi_buf_init_iov(&r2t->sendbuf,
- (char*)sc->request_buffer + r2t->data_offset,
- r2t->data_count);
- r2t->sg = NULL;
+ sg_count += sg->length;
}
+ BUG_ON(r2t->sg == NULL);
}
/**
@@ -365,17 +362,16 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
return ISCSI_ERR_DATALEN;
}
- if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
+ if (tcp_ctask->exp_datasn != r2tsn){
+ debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->r2tsn(%d)\n",
+ __FUNCTION__, tcp_ctask->exp_datasn, r2tsn);
return ISCSI_ERR_R2TSN;
-
- rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (rc)
- return rc;
-
- /* FIXME: use R2TSN to detect missing R2T */
+ }
/* fill-in new R2T associated with the task */
spin_lock(&session->lock);
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
+
if (!ctask->sc || ctask->mtask ||
session->state != ISCSI_STATE_LOGGED_IN) {
printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in "
@@ -401,11 +397,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
r2t->data_length, session->max_burst);
r2t->data_offset = be32_to_cpu(rhdr->data_offset);
- if (r2t->data_offset + r2t->data_length > ctask->total_length) {
+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) {
spin_unlock(&session->lock);
printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
"offset %u and total length %d\n", r2t->data_length,
- r2t->data_offset, ctask->total_length);
+ r2t->data_offset, scsi_bufflen(ctask->sc));
return ISCSI_ERR_DATALEN;
}
@@ -414,9 +410,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
iscsi_solicit_data_init(conn, ctask, r2t);
- tcp_ctask->exp_r2tsn = r2tsn + 1;
+ tcp_ctask->exp_datasn = r2tsn + 1;
__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR_INIT;
list_move_tail(&ctask->running, &conn->xmitqueue);
scsi_queue_work(session->host, &conn->xmitwork);
@@ -600,7 +596,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
int buf_left = buf_size - (tcp_conn->data_copied + offset);
- int size = min(tcp_conn->in.copy, buf_left);
+ unsigned size = min(tcp_conn->in.copy, buf_left);
int rc;
size = min(size, ctask->data_count);
@@ -609,7 +605,7 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
size, tcp_conn->in.offset, tcp_conn->in.copied);
BUG_ON(size <= 0);
- BUG_ON(tcp_ctask->sent + size > ctask->total_length);
+ BUG_ON(tcp_ctask->sent + size > scsi_bufflen(ctask->sc));
rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
(char*)buf + (offset + tcp_conn->data_copied), size);
@@ -707,25 +703,8 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
BUG_ON((void*)ctask != sc->SCp.ptr);
- /*
- * copying Data-In into the Scsi_Cmnd
- */
- if (!sc->use_sg) {
- i = ctask->data_count;
- rc = iscsi_ctask_copy(tcp_conn, ctask, sc->request_buffer,
- sc->request_bufflen,
- tcp_ctask->data_offset);
- if (rc == -EAGAIN)
- return rc;
- if (conn->datadgst_en)
- iscsi_recv_digest_update(tcp_conn, sc->request_buffer,
- i);
- rc = 0;
- goto done;
- }
-
offset = tcp_ctask->data_offset;
- sg = sc->request_buffer;
+ sg = scsi_sglist(sc);
if (tcp_ctask->data_offset)
for (i = 0; i < tcp_ctask->sg_count; i++)
@@ -734,7 +713,7 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
if (offset < 0)
offset = 0;
- for (i = tcp_ctask->sg_count; i < sc->use_sg; i++) {
+ for (i = tcp_ctask->sg_count; i < scsi_sg_count(sc); i++) {
char *dest;
dest = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
@@ -779,7 +758,6 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
}
BUG_ON(ctask->data_count);
-done:
/* check for non-exceptional status */
if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
@@ -895,11 +873,27 @@ more:
}
}
- if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV) {
+ if (tcp_conn->in_progress == IN_PROGRESS_DDIGEST_RECV &&
+ tcp_conn->in.copy) {
uint32_t recv_digest;
debug_tcp("extra data_recv offset %d copy %d\n",
tcp_conn->in.offset, tcp_conn->in.copy);
+
+ if (!tcp_conn->data_copied) {
+ if (tcp_conn->in.padding) {
+ debug_tcp("padding -> %d\n",
+ tcp_conn->in.padding);
+ memset(pad, 0, tcp_conn->in.padding);
+ sg_init_one(&sg, pad, tcp_conn->in.padding);
+ crypto_hash_update(&tcp_conn->rx_hash,
+ &sg, sg.length);
+ }
+ crypto_hash_final(&tcp_conn->rx_hash,
+ (u8 *) &tcp_conn->in.datadgst);
+ debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+ }
+
rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
if (rc) {
if (rc == -EAGAIN)
@@ -924,8 +918,7 @@ more:
}
if (tcp_conn->in_progress == IN_PROGRESS_DATA_RECV &&
- tcp_conn->in.copy) {
-
+ tcp_conn->in.copy) {
debug_tcp("data_recv offset %d copy %d\n",
tcp_conn->in.offset, tcp_conn->in.copy);
@@ -936,24 +929,32 @@ more:
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return 0;
}
- tcp_conn->in.copy -= tcp_conn->in.padding;
- tcp_conn->in.offset += tcp_conn->in.padding;
- if (conn->datadgst_en) {
- if (tcp_conn->in.padding) {
- debug_tcp("padding -> %d\n",
- tcp_conn->in.padding);
- memset(pad, 0, tcp_conn->in.padding);
- sg_init_one(&sg, pad, tcp_conn->in.padding);
- crypto_hash_update(&tcp_conn->rx_hash,
- &sg, sg.length);
- }
- crypto_hash_final(&tcp_conn->rx_hash,
- (u8 *) &tcp_conn->in.datadgst);
- debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
+
+ if (tcp_conn->in.padding)
+ tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+ else if (conn->datadgst_en)
tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
- tcp_conn->data_copied = 0;
- } else
+ else
+ tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+ tcp_conn->data_copied = 0;
+ }
+
+ if (tcp_conn->in_progress == IN_PROGRESS_PAD_RECV &&
+ tcp_conn->in.copy) {
+ int copylen = min(tcp_conn->in.padding - tcp_conn->data_copied,
+ tcp_conn->in.copy);
+
+ tcp_conn->in.copy -= copylen;
+ tcp_conn->in.offset += copylen;
+ tcp_conn->data_copied += copylen;
+
+ if (tcp_conn->data_copied != tcp_conn->in.padding)
+ tcp_conn->in_progress = IN_PROGRESS_PAD_RECV;
+ else if (conn->datadgst_en)
+ tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+ else
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
+ tcp_conn->data_copied = 0;
}
debug_tcp("f, processed %d from out of %d padding %d\n",
@@ -1215,7 +1216,6 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
struct iscsi_r2t_info *r2t, int left)
{
struct iscsi_data *hdr;
- struct scsi_cmnd *sc = ctask->sc;
int new_offset;
hdr = &r2t->dtask.hdr;
@@ -1245,15 +1245,8 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
if (iscsi_buf_left(&r2t->sendbuf))
return;
- if (sc->use_sg) {
- iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
- r2t->sg += 1;
- } else {
- iscsi_buf_init_iov(&r2t->sendbuf,
- (char*)sc->request_buffer + new_offset,
- r2t->data_count);
- r2t->sg = NULL;
- }
+ iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
+ r2t->sg += 1;
}
static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
@@ -1277,41 +1270,10 @@ static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
static void
iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
{
- struct scsi_cmnd *sc = ctask->sc;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
BUG_ON(__kfifo_len(tcp_ctask->r2tqueue));
-
- tcp_ctask->sent = 0;
- tcp_ctask->sg_count = 0;
-
- if (sc->sc_data_direction == DMA_TO_DEVICE) {
- tcp_ctask->xmstate = XMSTATE_W_HDR;
- tcp_ctask->exp_r2tsn = 0;
- BUG_ON(ctask->total_length == 0);
-
- if (sc->use_sg) {
- struct scatterlist *sg = sc->request_buffer;
-
- iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
- tcp_ctask->sg = sg + 1;
- tcp_ctask->bad_sg = sg + sc->use_sg;
- } else {
- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
- sc->request_buffer,
- sc->request_bufflen);
- tcp_ctask->sg = NULL;
- tcp_ctask->bad_sg = NULL;
- }
- debug_scsi("cmd [itt 0x%x total %d imm_data %d "
- "unsol count %d, unsol offset %d]\n",
- ctask->itt, ctask->total_length, ctask->imm_count,
- ctask->unsol_count, ctask->unsol_offset);
- } else
- tcp_ctask->xmstate = XMSTATE_R_HDR;
-
- iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
- sizeof(struct iscsi_hdr));
+ tcp_ctask->xmstate = XMSTATE_CMD_HDR_INIT;
}
/**
@@ -1324,9 +1286,11 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
* call it again later, or recover. '0' return code means successful
* xmit.
*
- * Management xmit state machine consists of two states:
- * IN_PROGRESS_IMM_HEAD - PDU Header xmit in progress
- * IN_PROGRESS_IMM_DATA - PDU Data xmit in progress
+ * Management xmit state machine consists of these states:
+ * XMSTATE_IMM_HDR_INIT - calculate digest of PDU Header
+ * XMSTATE_IMM_HDR - PDU Header xmit in progress
+ * XMSTATE_IMM_DATA - PDU Data xmit in progress
+ * XMSTATE_IDLE - management PDU is done
**/
static int
iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
@@ -1337,23 +1301,34 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
debug_scsi("mtask deq [cid %d state %x itt 0x%x]\n",
conn->id, tcp_mtask->xmstate, mtask->itt);
- if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) {
- tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR;
- if (mtask->data_count)
+ if (tcp_mtask->xmstate & XMSTATE_IMM_HDR_INIT) {
+ iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
+ sizeof(struct iscsi_hdr));
+
+ if (mtask->data_count) {
tcp_mtask->xmstate |= XMSTATE_IMM_DATA;
+ iscsi_buf_init_iov(&tcp_mtask->sendbuf,
+ (char*)mtask->data,
+ mtask->data_count);
+ }
+
if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE &&
conn->stop_stage != STOP_CONN_RECOVER &&
conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_mtask->headbuf,
(u8*)tcp_mtask->hdrext);
+
+ tcp_mtask->sent = 0;
+ tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR_INIT;
+ tcp_mtask->xmstate |= XMSTATE_IMM_HDR;
+ }
+
+ if (tcp_mtask->xmstate & XMSTATE_IMM_HDR) {
rc = iscsi_sendhdr(conn, &tcp_mtask->headbuf,
mtask->data_count);
- if (rc) {
- tcp_mtask->xmstate |= XMSTATE_IMM_HDR;
- if (mtask->data_count)
- tcp_mtask->xmstate &= ~XMSTATE_IMM_DATA;
+ if (rc)
return rc;
- }
+ tcp_mtask->xmstate &= ~XMSTATE_IMM_HDR;
}
if (tcp_mtask->xmstate & XMSTATE_IMM_DATA) {
@@ -1387,55 +1362,67 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
return 0;
}
-static inline int
-iscsi_send_read_hdr(struct iscsi_conn *conn,
- struct iscsi_tcp_cmd_task *tcp_ctask)
+static int
+iscsi_send_cmd_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
- int rc;
+ struct scsi_cmnd *sc = ctask->sc;
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ int rc = 0;
- tcp_ctask->xmstate &= ~XMSTATE_R_HDR;
- if (conn->hdrdgst_en)
- iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
- (u8*)tcp_ctask->hdrext);
- rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, 0);
- if (!rc) {
- BUG_ON(tcp_ctask->xmstate != XMSTATE_IDLE);
- return 0; /* wait for Data-In */
- }
- tcp_ctask->xmstate |= XMSTATE_R_HDR;
- return rc;
-}
+ if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_INIT) {
+ tcp_ctask->sent = 0;
+ tcp_ctask->sg_count = 0;
+ tcp_ctask->exp_datasn = 0;
-static inline int
-iscsi_send_write_hdr(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask)
-{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- int rc;
+ if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ struct scatterlist *sg = scsi_sglist(sc);
- tcp_ctask->xmstate &= ~XMSTATE_W_HDR;
- if (conn->hdrdgst_en)
- iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
- (u8*)tcp_ctask->hdrext);
- rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
- if (rc) {
- tcp_ctask->xmstate |= XMSTATE_W_HDR;
- return rc;
+ iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
+ tcp_ctask->sg = sg + 1;
+ tcp_ctask->bad_sg = sg + scsi_sg_count(sc);
+
+ debug_scsi("cmd [itt 0x%x total %d imm_data %d "
+ "unsol count %d, unsol offset %d]\n",
+ ctask->itt, scsi_bufflen(sc),
+ ctask->imm_count, ctask->unsol_count,
+ ctask->unsol_offset);
+ }
+
+ iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)ctask->hdr,
+ sizeof(struct iscsi_hdr));
+
+ if (conn->hdrdgst_en)
+ iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
+ (u8*)tcp_ctask->hdrext);
+ tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_INIT;
+ tcp_ctask->xmstate |= XMSTATE_CMD_HDR_XMIT;
}
- if (ctask->imm_count) {
- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
- iscsi_set_padding(tcp_ctask, ctask->imm_count);
+ if (tcp_ctask->xmstate & XMSTATE_CMD_HDR_XMIT) {
+ rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
+ if (rc)
+ return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_CMD_HDR_XMIT;
+
+ if (sc->sc_data_direction != DMA_TO_DEVICE)
+ return 0;
+
+ if (ctask->imm_count) {
+ tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
+ iscsi_set_padding(tcp_ctask, ctask->imm_count);
- if (ctask->conn->datadgst_en) {
- iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
- tcp_ctask->immdigest = 0;
+ if (ctask->conn->datadgst_en) {
+ iscsi_data_digest_init(ctask->conn->dd_data,
+ tcp_ctask);
+ tcp_ctask->immdigest = 0;
+ }
}
- }
- if (ctask->unsol_count)
- tcp_ctask->xmstate |= XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
- return 0;
+ if (ctask->unsol_count)
+ tcp_ctask->xmstate |=
+ XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
+ }
+ return rc;
}
static int
@@ -1624,9 +1611,7 @@ static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
struct iscsi_data_task *dtask;
int left, rc;
- if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR_INIT) {
if (!tcp_ctask->r2t) {
spin_lock_bh(&session->lock);
__kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
@@ -1640,12 +1625,19 @@ send_hdr:
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &r2t->headbuf,
(u8*)dtask->hdrext);
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR_INIT;
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ }
+
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
+ r2t = tcp_ctask->r2t;
+ dtask = &r2t->dtask;
+
rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
- if (rc) {
- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ if (rc)
return rc;
- }
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
if (conn->datadgst_en) {
iscsi_data_digest_init(conn->dd_data, tcp_ctask);
@@ -1677,8 +1669,6 @@ send_hdr:
left = r2t->data_length - r2t->sent;
if (left) {
iscsi_solicit_data_cont(conn, ctask, r2t, left);
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
goto send_hdr;
}
@@ -1693,8 +1683,6 @@ send_hdr:
if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
sizeof(void*))) {
tcp_ctask->r2t = r2t;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
spin_unlock_bh(&session->lock);
goto send_hdr;
}
@@ -1703,6 +1691,46 @@ send_hdr:
return 0;
}
+/**
+ * iscsi_tcp_ctask_xmit - xmit normal PDU task
+ * @conn: iscsi connection
+ * @ctask: iscsi command task
+ *
+ * Notes:
+ * The function can return -EAGAIN in which case caller must
+ * call it again later, or recover. '0' return code means successful
+ * xmit.
+ * The function is devided to logical helpers (above) for the different
+ * xmit stages.
+ *
+ *iscsi_send_cmd_hdr()
+ * XMSTATE_CMD_HDR_INIT - prepare Header and Data buffers Calculate
+ * Header Digest
+ * XMSTATE_CMD_HDR_XMIT - Transmit header in progress
+ *
+ *iscsi_send_padding
+ * XMSTATE_W_PAD - Prepare and send pading
+ * XMSTATE_W_RESEND_PAD - retry send pading
+ *
+ *iscsi_send_digest
+ * XMSTATE_W_RESEND_DATA_DIGEST - Finalize and send Data Digest
+ * XMSTATE_W_RESEND_DATA_DIGEST - retry sending digest
+ *
+ *iscsi_send_unsol_hdr
+ * XMSTATE_UNS_INIT - prepare un-solicit data header and digest
+ * XMSTATE_UNS_HDR - send un-solicit header
+ *
+ *iscsi_send_unsol_pdu
+ * XMSTATE_UNS_DATA - send un-solicit data in progress
+ *
+ *iscsi_send_sol_pdu
+ * XMSTATE_SOL_HDR_INIT - solicit data header and digest initialize
+ * XMSTATE_SOL_HDR - send solicit header
+ * XMSTATE_SOL_DATA - send solicit data
+ *
+ *iscsi_tcp_ctask_xmit
+ * XMSTATE_IMM_DATA - xmit managment data (??)
+ **/
static int
iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
@@ -1712,20 +1740,11 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
debug_scsi("ctask deq [cid %d xmstate %x itt 0x%x]\n",
conn->id, tcp_ctask->xmstate, ctask->itt);
- /*
- * serialize with TMF AbortTask
- */
- if (ctask->mtask)
+ rc = iscsi_send_cmd_hdr(conn, ctask);
+ if (rc)
return rc;
-
- if (tcp_ctask->xmstate & XMSTATE_R_HDR)
- return iscsi_send_read_hdr(conn, tcp_ctask);
-
- if (tcp_ctask->xmstate & XMSTATE_W_HDR) {
- rc = iscsi_send_write_hdr(conn, ctask);
- if (rc)
- return rc;
- }
+ if (ctask->sc->sc_data_direction != DMA_TO_DEVICE)
+ return 0;
if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) {
rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
@@ -1810,18 +1829,22 @@ tcp_conn_alloc_fail:
static void
iscsi_tcp_release_conn(struct iscsi_conn *conn)
{
+ struct iscsi_session *session = conn->session;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ struct socket *sock = tcp_conn->sock;
- if (!tcp_conn->sock)
+ if (!sock)
return;
- sock_hold(tcp_conn->sock->sk);
+ sock_hold(sock->sk);
iscsi_conn_restore_callbacks(tcp_conn);
- sock_put(tcp_conn->sock->sk);
+ sock_put(sock->sk);
- sock_release(tcp_conn->sock);
+ spin_lock_bh(&session->lock);
tcp_conn->sock = NULL;
conn->recv_lock = NULL;
+ spin_unlock_bh(&session->lock);
+ sockfd_put(sock);
}
static void
@@ -1852,6 +1875,46 @@ iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
}
+static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock,
+ char *buf, int *port,
+ int (*getname)(struct socket *, struct sockaddr *,
+ int *addrlen))
+{
+ struct sockaddr_storage *addr;
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
+ int rc = 0, len;
+
+ addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+ if (!addr)
+ return -ENOMEM;
+
+ if (getname(sock, (struct sockaddr *) addr, &len)) {
+ rc = -ENODEV;
+ goto free_addr;
+ }
+
+ switch (addr->ss_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in *)addr;
+ spin_lock_bh(&conn->session->lock);
+ sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+ *port = be16_to_cpu(sin->sin_port);
+ spin_unlock_bh(&conn->session->lock);
+ break;
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *)addr;
+ spin_lock_bh(&conn->session->lock);
+ sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr));
+ *port = be16_to_cpu(sin6->sin6_port);
+ spin_unlock_bh(&conn->session->lock);
+ break;
+ }
+free_addr:
+ kfree(addr);
+ return rc;
+}
+
static int
iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
@@ -1869,10 +1932,24 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err);
return -EEXIST;
}
+ /*
+ * copy these values now because if we drop the session
+ * userspace may still want to query the values since we will
+ * be using them for the reconnect
+ */
+ err = iscsi_tcp_get_addr(conn, sock, conn->portal_address,
+ &conn->portal_port, kernel_getpeername);
+ if (err)
+ goto free_socket;
+
+ err = iscsi_tcp_get_addr(conn, sock, conn->local_address,
+ &conn->local_port, kernel_getsockname);
+ if (err)
+ goto free_socket;
err = iscsi_conn_bind(cls_session, cls_conn, is_leading);
if (err)
- return err;
+ goto free_socket;
/* bind iSCSI connection and socket */
tcp_conn->sock = sock;
@@ -1896,25 +1973,19 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
* set receive state machine into initial state
*/
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
-
return 0;
+
+free_socket:
+ sockfd_put(sock);
+ return err;
}
/* called with host lock */
static void
-iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
- char *data, uint32_t data_size)
+iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
{
struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data;
-
- iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
- sizeof(struct iscsi_hdr));
- tcp_mtask->xmstate = XMSTATE_IMM_HDR;
- tcp_mtask->sent = 0;
-
- if (mtask->data_count)
- iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data,
- mtask->data_count);
+ tcp_mtask->xmstate = XMSTATE_IMM_HDR_INIT;
}
static int
@@ -2026,41 +2097,18 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
enum iscsi_param param, char *buf)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct inet_sock *inet;
- struct ipv6_pinfo *np;
- struct sock *sk;
int len;
switch(param) {
case ISCSI_PARAM_CONN_PORT:
- mutex_lock(&conn->xmitmutex);
- if (!tcp_conn->sock) {
- mutex_unlock(&conn->xmitmutex);
- return -EINVAL;
- }
-
- inet = inet_sk(tcp_conn->sock->sk);
- len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport));
- mutex_unlock(&conn->xmitmutex);
+ spin_lock_bh(&conn->session->lock);
+ len = sprintf(buf, "%hu\n", conn->portal_port);
+ spin_unlock_bh(&conn->session->lock);
break;
case ISCSI_PARAM_CONN_ADDRESS:
- mutex_lock(&conn->xmitmutex);
- if (!tcp_conn->sock) {
- mutex_unlock(&conn->xmitmutex);
- return -EINVAL;
- }
-
- sk = tcp_conn->sock->sk;
- if (sk->sk_family == PF_INET) {
- inet = inet_sk(sk);
- len = sprintf(buf, NIPQUAD_FMT "\n",
- NIPQUAD(inet->daddr));
- } else {
- np = inet6_sk(sk);
- len = sprintf(buf, NIP6_FMT "\n", NIP6(np->daddr));
- }
- mutex_unlock(&conn->xmitmutex);
+ spin_lock_bh(&conn->session->lock);
+ len = sprintf(buf, "%s\n", conn->portal_address);
+ spin_unlock_bh(&conn->session->lock);
break;
default:
return iscsi_conn_get_param(cls_conn, param, buf);
@@ -2069,6 +2117,29 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
return len;
}
+static int
+iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+ char *buf)
+{
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ int len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ spin_lock_bh(&session->lock);
+ if (!session->leadconn)
+ len = -ENODEV;
+ else
+ len = sprintf(buf, "%s\n",
+ session->leadconn->local_address);
+ spin_unlock_bh(&session->lock);
+ break;
+ default:
+ return iscsi_host_get_param(shost, param, buf);
+ }
+ return len;
+}
+
static void
iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
{
@@ -2096,6 +2167,7 @@ iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
static struct iscsi_cls_session *
iscsi_tcp_session_create(struct iscsi_transport *iscsit,
struct scsi_transport_template *scsit,
+ uint16_t cmds_max, uint16_t qdepth,
uint32_t initial_cmdsn, uint32_t *hostno)
{
struct iscsi_cls_session *cls_session;
@@ -2103,7 +2175,7 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit,
uint32_t hn;
int cmd_i;
- cls_session = iscsi_session_setup(iscsit, scsit,
+ cls_session = iscsi_session_setup(iscsit, scsit, cmds_max, qdepth,
sizeof(struct iscsi_tcp_cmd_task),
sizeof(struct iscsi_tcp_mgmt_task),
initial_cmdsn, &hn);
@@ -2142,17 +2214,24 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
iscsi_session_teardown(cls_session);
}
+static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
+{
+ blk_queue_dma_alignment(sdev->request_queue, 0);
+ return 0;
+}
+
static struct scsi_host_template iscsi_sht = {
.name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
- .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
+ .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
.sg_tablesize = ISCSI_SG_TABLESIZE,
.max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
.eh_abort_handler = iscsi_eh_abort,
.eh_host_reset_handler = iscsi_eh_host_reset,
.use_clustering = DISABLE_CLUSTERING,
+ .slave_configure = iscsi_tcp_slave_configure,
.proc_name = "iscsi_tcp",
.this_id = -1,
};
@@ -2179,8 +2258,12 @@ static struct iscsi_transport iscsi_tcp_transport = {
ISCSI_EXP_STATSN |
ISCSI_PERSISTENT_PORT |
ISCSI_PERSISTENT_ADDRESS |
- ISCSI_TARGET_NAME |
- ISCSI_TPGT,
+ ISCSI_TARGET_NAME | ISCSI_TPGT |
+ ISCSI_USERNAME | ISCSI_PASSWORD |
+ ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN,
+ .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
+ ISCSI_HOST_INITIATOR_NAME |
+ ISCSI_HOST_NETDEV_NAME,
.host_template = &iscsi_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_conn = 1,
@@ -2197,6 +2280,9 @@ static struct iscsi_transport iscsi_tcp_transport = {
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_conn_start,
.stop_conn = iscsi_tcp_conn_stop,
+ /* iscsi host params */
+ .get_host_param = iscsi_tcp_host_get_param,
+ .set_host_param = iscsi_host_set_param,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_conn_get_stats,
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 32736831790e..7eba44df0a7f 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -29,11 +29,12 @@
#define IN_PROGRESS_HEADER_GATHER 0x1
#define IN_PROGRESS_DATA_RECV 0x2
#define IN_PROGRESS_DDIGEST_RECV 0x3
+#define IN_PROGRESS_PAD_RECV 0x4
/* xmit state machine */
#define XMSTATE_IDLE 0x0
-#define XMSTATE_R_HDR 0x1
-#define XMSTATE_W_HDR 0x2
+#define XMSTATE_CMD_HDR_INIT 0x1
+#define XMSTATE_CMD_HDR_XMIT 0x2
#define XMSTATE_IMM_HDR 0x4
#define XMSTATE_IMM_DATA 0x8
#define XMSTATE_UNS_INIT 0x10
@@ -44,6 +45,8 @@
#define XMSTATE_W_PAD 0x200
#define XMSTATE_W_RESEND_PAD 0x400
#define XMSTATE_W_RESEND_DATA_DIGEST 0x800
+#define XMSTATE_IMM_HDR_INIT 0x1000
+#define XMSTATE_SOL_HDR_INIT 0x2000
#define ISCSI_PAD_LEN 4
#define ISCSI_SG_TABLESIZE SG_ALL
@@ -152,7 +155,7 @@ struct iscsi_tcp_cmd_task {
struct scatterlist *sg; /* per-cmd SG list */
struct scatterlist *bad_sg; /* assert statement */
int sg_count; /* SG's to process */
- uint32_t exp_r2tsn;
+ uint32_t exp_datasn; /* expected target's R2TSN/DataSN */
int data_offset;
struct iscsi_r2t_info *r2t; /* in progress R2T */
struct iscsi_queue r2tpool;
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index 81e497d9eae0..5d231015bb20 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -1,6 +1,6 @@
/* jazz_esp.c: ESP front-end for MIPS JAZZ systems.
*
- * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende)
+ * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende)
*/
#include <linux/kernel.h>
@@ -143,7 +143,7 @@ static int __devinit esp_jazz_probe(struct platform_device *dev)
goto fail;
host->max_id = 8;
- esp = host_to_esp(host);
+ esp = shost_priv(host);
esp->host = host;
esp->dev = dev;
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index 5c32a69e41ba..3126824da36d 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -101,13 +101,12 @@ lasi700_probe(struct parisc_device *dev)
struct NCR_700_Host_Parameters *hostdata;
struct Scsi_Host *host;
- hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+ hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
printk(KERN_ERR "%s: Failed to allocate host data\n",
dev->dev.bus_id);
return -ENOMEM;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
hostdata->dev = &dev->dev;
dma_set_mask(&dev->dev, DMA_32BIT_MASK);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 3f5b9b445b29..4d85ce100192 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/types.h>
-#include <linux/mutex.h>
#include <linux/kfifo.h>
#include <linux/delay.h>
#include <asm/unaligned.h>
@@ -46,27 +45,53 @@ class_to_transport_session(struct iscsi_cls_session *cls_session)
}
EXPORT_SYMBOL_GPL(class_to_transport_session);
-#define INVALID_SN_DELTA 0xffff
+/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
+#define SNA32_CHECK 2147483648UL
-int
-iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
+static int iscsi_sna_lt(u32 n1, u32 n2)
+{
+ return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
+ (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
+}
+
+/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */
+static int iscsi_sna_lte(u32 n1, u32 n2)
+{
+ return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) ||
+ (n1 > n2 && (n2 - n1 < SNA32_CHECK)));
+}
+
+void
+iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
{
uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn);
uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn);
- if (max_cmdsn < exp_cmdsn -1 &&
- max_cmdsn > exp_cmdsn - INVALID_SN_DELTA)
- return ISCSI_ERR_MAX_CMDSN;
- if (max_cmdsn > session->max_cmdsn ||
- max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA)
- session->max_cmdsn = max_cmdsn;
- if (exp_cmdsn > session->exp_cmdsn ||
- exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA)
+ /*
+ * standard specifies this check for when to update expected and
+ * max sequence numbers
+ */
+ if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1))
+ return;
+
+ if (exp_cmdsn != session->exp_cmdsn &&
+ !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn))
session->exp_cmdsn = exp_cmdsn;
- return 0;
+ if (max_cmdsn != session->max_cmdsn &&
+ !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) {
+ session->max_cmdsn = max_cmdsn;
+ /*
+ * if the window closed with IO queued, then kick the
+ * xmit thread
+ */
+ if (!list_empty(&session->leadconn->xmitqueue) ||
+ __kfifo_len(session->leadconn->mgmtqueue))
+ scsi_queue_work(session->host,
+ &session->leadconn->xmitwork);
+ }
}
-EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
+EXPORT_SYMBOL_GPL(iscsi_update_cmdsn);
void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
struct iscsi_data *hdr)
@@ -115,14 +140,17 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
hdr->flags = ISCSI_ATTR_SIMPLE;
int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
hdr->itt = build_itt(ctask->itt, conn->id, session->age);
- hdr->data_length = cpu_to_be32(sc->request_bufflen);
+ hdr->data_length = cpu_to_be32(scsi_bufflen(sc));
hdr->cmdsn = cpu_to_be32(session->cmdsn);
session->cmdsn++;
hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
- memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+ if (sc->cmd_len < MAX_COMMAND_SIZE)
+ memset(&hdr->cdb[sc->cmd_len], 0,
+ MAX_COMMAND_SIZE - sc->cmd_len);
ctask->data_count = 0;
+ ctask->imm_count = 0;
if (sc->sc_data_direction == DMA_TO_DEVICE) {
hdr->flags |= ISCSI_FLAG_CMD_WRITE;
/*
@@ -139,25 +167,24 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
*
* pad_count bytes to be sent as zero-padding
*/
- ctask->imm_count = 0;
ctask->unsol_count = 0;
ctask->unsol_offset = 0;
ctask->unsol_datasn = 0;
if (session->imm_data_en) {
- if (ctask->total_length >= session->first_burst)
+ if (scsi_bufflen(sc) >= session->first_burst)
ctask->imm_count = min(session->first_burst,
conn->max_xmit_dlength);
else
- ctask->imm_count = min(ctask->total_length,
+ ctask->imm_count = min(scsi_bufflen(sc),
conn->max_xmit_dlength);
hton24(ctask->hdr->dlength, ctask->imm_count);
} else
zero_data(ctask->hdr->dlength);
if (!session->initial_r2t_en) {
- ctask->unsol_count = min(session->first_burst,
- ctask->total_length) - ctask->imm_count;
+ ctask->unsol_count = min((session->first_burst),
+ (scsi_bufflen(sc))) - ctask->imm_count;
ctask->unsol_offset = ctask->imm_count;
}
@@ -165,7 +192,6 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
/* No unsolicit Data-Out's */
ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
} else {
- ctask->datasn = 0;
hdr->flags |= ISCSI_FLAG_CMD_FINAL;
zero_data(hdr->dlength);
@@ -174,8 +200,13 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
}
conn->scsicmd_pdus_cnt++;
+
+ debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d "
+ "cmdsn %d win %d]\n",
+ sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
+ conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc),
+ session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
}
-EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu);
/**
* iscsi_complete_command - return command back to scsi-ml
@@ -204,26 +235,12 @@ static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask)
atomic_inc(&ctask->refcount);
}
-static void iscsi_get_ctask(struct iscsi_cmd_task *ctask)
-{
- spin_lock_bh(&ctask->conn->session->lock);
- __iscsi_get_ctask(ctask);
- spin_unlock_bh(&ctask->conn->session->lock);
-}
-
static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
{
if (atomic_dec_and_test(&ctask->refcount))
iscsi_complete_command(ctask);
}
-static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
-{
- spin_lock_bh(&ctask->conn->session->lock);
- __iscsi_put_ctask(ctask);
- spin_unlock_bh(&ctask->conn->session->lock);
-}
-
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
@@ -235,21 +252,15 @@ static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
* iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and
* then completes the command and task.
**/
-static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- struct iscsi_cmd_task *ctask, char *data,
- int datalen)
+static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ struct iscsi_cmd_task *ctask, char *data,
+ int datalen)
{
- int rc;
struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr;
struct iscsi_session *session = conn->session;
struct scsi_cmnd *sc = ctask->sc;
- rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr);
- if (rc) {
- sc->result = DID_ERROR << 16;
- goto out;
- }
-
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr);
conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1;
sc->result = (DID_OK << 16) | rhdr->cmd_status;
@@ -286,14 +297,14 @@ invalid_datalen:
if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) {
int res_count = be32_to_cpu(rhdr->residual_count);
- if (res_count > 0 && res_count <= sc->request_bufflen)
- sc->resid = res_count;
+ if (res_count > 0 && res_count <= scsi_bufflen(sc))
+ scsi_set_resid(sc, res_count);
else
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
} else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW)
sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status;
else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW)
- sc->resid = be32_to_cpu(rhdr->residual_count);
+ scsi_set_resid(sc, be32_to_cpu(rhdr->residual_count));
out:
debug_scsi("done [sc %lx res %d itt 0x%x]\n",
@@ -301,7 +312,6 @@ out:
conn->scsirsp_pdus_cnt++;
__iscsi_put_ctask(ctask);
- return rc;
}
static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
@@ -381,8 +391,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
switch(opcode) {
case ISCSI_OP_SCSI_CMD_RSP:
BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
- rc = iscsi_scsi_cmd_rsp(conn, hdr, ctask, data,
- datalen);
+ iscsi_scsi_cmd_rsp(conn, hdr, ctask, data,
+ datalen);
break;
case ISCSI_OP_SCSI_DATA_IN:
BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
@@ -405,11 +415,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n",
opcode, conn->id, mtask->itt, datalen);
- rc = iscsi_check_assign_cmdsn(session,
- (struct iscsi_nopin*)hdr);
- if (rc)
- goto done;
-
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
switch(opcode) {
case ISCSI_OP_LOGOUT_RSP:
if (datalen) {
@@ -458,10 +464,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
} else if (itt == ~0U) {
- rc = iscsi_check_assign_cmdsn(session,
- (struct iscsi_nopin*)hdr);
- if (rc)
- goto done;
+ iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr);
switch(opcode) {
case ISCSI_OP_NOOP_IN:
@@ -491,7 +494,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
} else
rc = ISCSI_ERR_BAD_ITT;
-done:
return rc;
}
EXPORT_SYMBOL_GPL(__iscsi_complete_pdu);
@@ -578,17 +580,47 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
}
EXPORT_SYMBOL_GPL(iscsi_conn_failure);
+static void iscsi_prep_mtask(struct iscsi_conn *conn,
+ struct iscsi_mgmt_task *mtask)
+{
+ struct iscsi_session *session = conn->session;
+ struct iscsi_hdr *hdr = mtask->hdr;
+ struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
+
+ if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) &&
+ hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
+ nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
+ /*
+ * pre-format CmdSN for outgoing PDU.
+ */
+ nop->cmdsn = cpu_to_be32(session->cmdsn);
+ if (hdr->itt != RESERVED_ITT) {
+ hdr->itt = build_itt(mtask->itt, conn->id, session->age);
+ if (conn->c_stage == ISCSI_CONN_STARTED &&
+ !(hdr->opcode & ISCSI_OP_IMMEDIATE))
+ session->cmdsn++;
+ }
+
+ if (session->tt->init_mgmt_task)
+ session->tt->init_mgmt_task(conn, mtask);
+
+ debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
+ hdr->opcode, hdr->itt, mtask->data_count);
+}
+
static int iscsi_xmit_mtask(struct iscsi_conn *conn)
{
struct iscsi_hdr *hdr = conn->mtask->hdr;
int rc, was_logout = 0;
+ spin_unlock_bh(&conn->session->lock);
if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) {
conn->session->state = ISCSI_STATE_IN_RECOVERY;
iscsi_block_session(session_to_cls(conn->session));
was_logout = 1;
}
rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask);
+ spin_lock_bh(&conn->session->lock);
if (rc)
return rc;
@@ -602,6 +634,45 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
return 0;
}
+static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn)
+{
+ struct iscsi_session *session = conn->session;
+
+ /*
+ * Check for iSCSI window and take care of CmdSN wrap-around
+ */
+ if (!iscsi_sna_lte(session->cmdsn, session->max_cmdsn)) {
+ debug_scsi("iSCSI CmdSN closed. MaxCmdSN %u CmdSN %u\n",
+ session->max_cmdsn, session->cmdsn);
+ return -ENOSPC;
+ }
+ return 0;
+}
+
+static int iscsi_xmit_ctask(struct iscsi_conn *conn)
+{
+ struct iscsi_cmd_task *ctask = conn->ctask;
+ int rc = 0;
+
+ /*
+ * serialize with TMF AbortTask
+ */
+ if (ctask->state == ISCSI_TASK_ABORTING)
+ goto done;
+
+ __iscsi_get_ctask(ctask);
+ spin_unlock_bh(&conn->session->lock);
+ rc = conn->session->tt->xmit_cmd_task(conn, ctask);
+ spin_lock_bh(&conn->session->lock);
+ __iscsi_put_ctask(ctask);
+
+done:
+ if (!rc)
+ /* done with this ctask */
+ conn->ctask = NULL;
+ return rc;
+}
+
/**
* iscsi_data_xmit - xmit any command into the scheduled connection
* @conn: iscsi connection
@@ -613,106 +684,79 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn)
**/
static int iscsi_data_xmit(struct iscsi_conn *conn)
{
- struct iscsi_transport *tt;
int rc = 0;
+ spin_lock_bh(&conn->session->lock);
if (unlikely(conn->suspend_tx)) {
debug_scsi("conn %d Tx suspended!\n", conn->id);
+ spin_unlock_bh(&conn->session->lock);
return -ENODATA;
}
- tt = conn->session->tt;
-
- /*
- * Transmit in the following order:
- *
- * 1) un-finished xmit (ctask or mtask)
- * 2) immediate control PDUs
- * 3) write data
- * 4) SCSI commands
- * 5) non-immediate control PDUs
- *
- * No need to lock around __kfifo_get as long as
- * there's one producer and one consumer.
- */
-
- BUG_ON(conn->ctask && conn->mtask);
if (conn->ctask) {
- iscsi_get_ctask(conn->ctask);
- rc = tt->xmit_cmd_task(conn, conn->ctask);
- iscsi_put_ctask(conn->ctask);
+ rc = iscsi_xmit_ctask(conn);
if (rc)
goto again;
- /* done with this in-progress ctask */
- conn->ctask = NULL;
}
+
if (conn->mtask) {
rc = iscsi_xmit_mtask(conn);
if (rc)
goto again;
}
- /* process immediate first */
- if (unlikely(__kfifo_len(conn->immqueue))) {
- while (__kfifo_get(conn->immqueue, (void*)&conn->mtask,
- sizeof(void*))) {
- spin_lock_bh(&conn->session->lock);
- list_add_tail(&conn->mtask->running,
- &conn->mgmt_run_list);
- spin_unlock_bh(&conn->session->lock);
- rc = iscsi_xmit_mtask(conn);
- if (rc)
- goto again;
- }
+ /*
+ * process mgmt pdus like nops before commands since we should
+ * only have one nop-out as a ping from us and targets should not
+ * overflow us with nop-ins
+ */
+check_mgmt:
+ while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
+ sizeof(void*))) {
+ iscsi_prep_mtask(conn, conn->mtask);
+ list_add_tail(&conn->mtask->running, &conn->mgmt_run_list);
+ rc = iscsi_xmit_mtask(conn);
+ if (rc)
+ goto again;
}
/* process command queue */
- spin_lock_bh(&conn->session->lock);
while (!list_empty(&conn->xmitqueue)) {
+ rc = iscsi_check_cmdsn_window_closed(conn);
+ if (rc) {
+ spin_unlock_bh(&conn->session->lock);
+ return rc;
+ }
/*
* iscsi tcp may readd the task to the xmitqueue to send
* write data
*/
conn->ctask = list_entry(conn->xmitqueue.next,
struct iscsi_cmd_task, running);
+ if (conn->ctask->state == ISCSI_TASK_PENDING) {
+ iscsi_prep_scsi_cmd_pdu(conn->ctask);
+ conn->session->tt->init_cmd_task(conn->ctask);
+ }
conn->ctask->state = ISCSI_TASK_RUNNING;
list_move_tail(conn->xmitqueue.next, &conn->run_list);
- __iscsi_get_ctask(conn->ctask);
- spin_unlock_bh(&conn->session->lock);
-
- rc = tt->xmit_cmd_task(conn, conn->ctask);
-
- spin_lock_bh(&conn->session->lock);
- __iscsi_put_ctask(conn->ctask);
- if (rc) {
- spin_unlock_bh(&conn->session->lock);
+ rc = iscsi_xmit_ctask(conn);
+ if (rc)
goto again;
- }
+ /*
+ * we could continuously get new ctask requests so
+ * we need to check the mgmt queue for nops that need to
+ * be sent to aviod starvation
+ */
+ if (__kfifo_len(conn->mgmtqueue))
+ goto check_mgmt;
}
spin_unlock_bh(&conn->session->lock);
- /* done with this ctask */
- conn->ctask = NULL;
-
- /* process the rest control plane PDUs, if any */
- if (unlikely(__kfifo_len(conn->mgmtqueue))) {
- while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask,
- sizeof(void*))) {
- spin_lock_bh(&conn->session->lock);
- list_add_tail(&conn->mtask->running,
- &conn->mgmt_run_list);
- spin_unlock_bh(&conn->session->lock);
- rc = iscsi_xmit_mtask(conn);
- if (rc)
- goto again;
- }
- }
-
return -ENODATA;
again:
if (unlikely(conn->suspend_tx))
- return -ENODATA;
-
+ rc = -ENODATA;
+ spin_unlock_bh(&conn->session->lock);
return rc;
}
@@ -724,11 +768,9 @@ static void iscsi_xmitworker(struct work_struct *work)
/*
* serialize Xmit worker on a per-connection basis.
*/
- mutex_lock(&conn->xmitmutex);
do {
rc = iscsi_data_xmit(conn);
} while (rc >= 0 || rc == -EAGAIN);
- mutex_unlock(&conn->xmitmutex);
}
enum {
@@ -786,20 +828,23 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
goto fault;
}
- /*
- * Check for iSCSI window and take care of CmdSN wrap-around
- */
- if ((int)(session->max_cmdsn - session->cmdsn) < 0) {
- reason = FAILURE_WINDOW_CLOSED;
- goto reject;
- }
-
conn = session->leadconn;
if (!conn) {
reason = FAILURE_SESSION_FREED;
goto fault;
}
+ /*
+ * We check this here and in data xmit, because if we get to the point
+ * that this check is hitting the window then we have enough IO in
+ * flight and enough IO waiting to be transmitted it is better
+ * to let the scsi/block layer queue up.
+ */
+ if (iscsi_check_cmdsn_window_closed(conn)) {
+ reason = FAILURE_WINDOW_CLOSED;
+ goto reject;
+ }
+
if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
sizeof(void*))) {
reason = FAILURE_OOM;
@@ -814,18 +859,8 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
ctask->conn = conn;
ctask->sc = sc;
INIT_LIST_HEAD(&ctask->running);
- ctask->total_length = sc->request_bufflen;
- iscsi_prep_scsi_cmd_pdu(ctask);
-
- session->tt->init_cmd_task(ctask);
list_add_tail(&ctask->running, &conn->xmitqueue);
- debug_scsi(
- "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d "
- "win %d]\n",
- sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
- conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
- session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
spin_unlock(&session->lock);
scsi_queue_work(host, &conn->xmitwork);
@@ -841,7 +876,7 @@ fault:
printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n",
sc->cmnd[0], reason);
sc->result = (DID_NO_CONNECT << 16);
- sc->resid = sc->request_bufflen;
+ scsi_set_resid(sc, scsi_bufflen(sc));
sc->scsi_done(sc);
return 0;
}
@@ -856,19 +891,16 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth)
}
EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-static int
-iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
- char *data, uint32_t data_size)
+static struct iscsi_mgmt_task *
+__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ char *data, uint32_t data_size)
{
struct iscsi_session *session = conn->session;
- struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr;
struct iscsi_mgmt_task *mtask;
- spin_lock_bh(&session->lock);
- if (session->state == ISCSI_STATE_TERMINATE) {
- spin_unlock_bh(&session->lock);
- return -EPERM;
- }
+ if (session->state == ISCSI_STATE_TERMINATE)
+ return NULL;
+
if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) ||
hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE))
/*
@@ -882,27 +914,11 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE);
BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED);
- nop->exp_statsn = cpu_to_be32(conn->exp_statsn);
if (!__kfifo_get(session->mgmtpool.queue,
- (void*)&mtask, sizeof(void*))) {
- spin_unlock_bh(&session->lock);
- return -ENOSPC;
- }
+ (void*)&mtask, sizeof(void*)))
+ return NULL;
}
- /*
- * pre-format CmdSN for outgoing PDU.
- */
- if (hdr->itt != RESERVED_ITT) {
- hdr->itt = build_itt(mtask->itt, conn->id, session->age);
- nop->cmdsn = cpu_to_be32(session->cmdsn);
- if (conn->c_stage == ISCSI_CONN_STARTED &&
- !(hdr->opcode & ISCSI_OP_IMMEDIATE))
- session->cmdsn++;
- } else
- /* do not advance CmdSN */
- nop->cmdsn = cpu_to_be32(session->cmdsn);
-
if (data_size) {
memcpy(mtask->data, data, data_size);
mtask->data_count = data_size;
@@ -911,38 +927,23 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
INIT_LIST_HEAD(&mtask->running);
memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr));
- if (session->tt->init_mgmt_task)
- session->tt->init_mgmt_task(conn, mtask, data, data_size);
- spin_unlock_bh(&session->lock);
-
- debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n",
- hdr->opcode, hdr->itt, data_size);
-
- /*
- * since send_pdu() could be called at least from two contexts,
- * we need to serialize __kfifo_put, so we don't have to take
- * additional lock on fast data-path
- */
- if (hdr->opcode & ISCSI_OP_IMMEDIATE)
- __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*));
- else
- __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
-
- scsi_queue_work(session->host, &conn->xmitwork);
- return 0;
+ __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*));
+ return mtask;
}
int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size)
{
struct iscsi_conn *conn = cls_conn->dd_data;
- int rc;
-
- mutex_lock(&conn->xmitmutex);
- rc = iscsi_conn_send_generic(conn, hdr, data, data_size);
- mutex_unlock(&conn->xmitmutex);
+ struct iscsi_session *session = conn->session;
+ int err = 0;
- return rc;
+ spin_lock_bh(&session->lock);
+ if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size))
+ err = -EPERM;
+ spin_unlock_bh(&session->lock);
+ scsi_queue_work(session->host, &conn->xmitwork);
+ return err;
}
EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu);
@@ -1027,14 +1028,12 @@ static void iscsi_tmabort_timedout(unsigned long data)
spin_unlock(&session->lock);
}
-/* must be called with the mutex lock */
static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
struct iscsi_cmd_task *ctask)
{
struct iscsi_conn *conn = ctask->conn;
struct iscsi_session *session = conn->session;
struct iscsi_tm *hdr = &conn->tmhdr;
- int rc;
/*
* ctask timed out but session is OK requests must be serialized.
@@ -1047,32 +1046,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
hdr->rtt = ctask->hdr->itt;
hdr->refcmdsn = ctask->hdr->cmdsn;
- rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr,
- NULL, 0);
- if (rc) {
+ ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
+ NULL, 0);
+ if (!ctask->mtask) {
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt,
- rc);
- return rc;
+ debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
+ return -EPERM;
}
+ ctask->state = ISCSI_TASK_ABORTING;
debug_scsi("abort sent [itt 0x%x]\n", ctask->itt);
- spin_lock_bh(&session->lock);
- ctask->mtask = (struct iscsi_mgmt_task *)
- session->mgmt_cmds[get_itt(hdr->itt) -
- ISCSI_MGMT_ITT_OFFSET];
-
if (conn->tmabort_state == TMABORT_INITIAL) {
conn->tmfcmd_pdus_cnt++;
- conn->tmabort_timer.expires = 10*HZ + jiffies;
+ conn->tmabort_timer.expires = 20*HZ + jiffies;
conn->tmabort_timer.function = iscsi_tmabort_timedout;
conn->tmabort_timer.data = (unsigned long)ctask;
add_timer(&conn->tmabort_timer);
debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
}
spin_unlock_bh(&session->lock);
- mutex_unlock(&conn->xmitmutex);
+ scsi_queue_work(session->host, &conn->xmitwork);
/*
* block eh thread until:
@@ -1089,13 +1083,12 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
if (signal_pending(current))
flush_signals(current);
del_timer_sync(&conn->tmabort_timer);
-
- mutex_lock(&conn->xmitmutex);
+ spin_lock_bh(&session->lock);
return 0;
}
/*
- * xmit mutex and session lock must be held
+ * session lock must be held
*/
static struct iscsi_mgmt_task *
iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
@@ -1127,7 +1120,7 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
if (!ctask->mtask)
return -EINVAL;
- if (!iscsi_remove_mgmt_task(conn->immqueue, ctask->mtask->itt))
+ if (!iscsi_remove_mgmt_task(conn->mgmtqueue, ctask->mtask->itt))
list_del(&ctask->mtask->running);
__kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask,
sizeof(void*));
@@ -1136,7 +1129,7 @@ static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
}
/*
- * session lock and xmitmutex must be held
+ * session lock must be held
*/
static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
int err)
@@ -1147,11 +1140,14 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
if (!sc)
return;
- conn->session->tt->cleanup_cmd_task(conn, ctask);
+ if (ctask->state != ISCSI_TASK_PENDING)
+ conn->session->tt->cleanup_cmd_task(conn, ctask);
iscsi_ctask_mtask_cleanup(ctask);
sc->result = err;
- sc->resid = sc->request_bufflen;
+ scsi_set_resid(sc, scsi_bufflen(sc));
+ if (conn->ctask == ctask)
+ conn->ctask = NULL;
/* release ref from queuecommand */
__iscsi_put_ctask(ctask);
}
@@ -1179,7 +1175,6 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
conn->eh_abort_cnt++;
debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
- mutex_lock(&conn->xmitmutex);
spin_lock_bh(&session->lock);
/*
@@ -1192,9 +1187,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
/* ctask completed before time out */
if (!ctask->sc) {
- spin_unlock_bh(&session->lock);
debug_scsi("sc completed while abort in progress\n");
- goto success_rel_mutex;
+ goto success;
}
/* what should we do here ? */
@@ -1204,15 +1198,13 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
goto failed;
}
- if (ctask->state == ISCSI_TASK_PENDING)
- goto success_cleanup;
+ if (ctask->state == ISCSI_TASK_PENDING) {
+ fail_command(conn, ctask, DID_ABORT << 16);
+ goto success;
+ }
conn->tmabort_state = TMABORT_INITIAL;
-
- spin_unlock_bh(&session->lock);
rc = iscsi_exec_abort_task(sc, ctask);
- spin_lock_bh(&session->lock);
-
if (rc || sc->SCp.phase != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
goto failed;
@@ -1220,45 +1212,44 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
switch (conn->tmabort_state) {
case TMABORT_SUCCESS:
- goto success_cleanup;
+ spin_unlock_bh(&session->lock);
+ /*
+ * clean up task if aborted. grab the recv lock as a writer
+ */
+ write_lock_bh(conn->recv_lock);
+ spin_lock(&session->lock);
+ fail_command(conn, ctask, DID_ABORT << 16);
+ spin_unlock(&session->lock);
+ write_unlock_bh(conn->recv_lock);
+ /*
+ * make sure xmit thread is not still touching the
+ * ctask/scsi_cmnd
+ */
+ scsi_flush_work(session->host);
+ goto success_unlocked;
case TMABORT_NOT_FOUND:
if (!ctask->sc) {
/* ctask completed before tmf abort response */
- spin_unlock_bh(&session->lock);
debug_scsi("sc completed while abort in progress\n");
- goto success_rel_mutex;
+ goto success;
}
/* fall through */
default:
/* timedout or failed */
spin_unlock_bh(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
- spin_lock_bh(&session->lock);
- goto failed;
+ goto failed_unlocked;
}
-success_cleanup:
- debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+success:
spin_unlock_bh(&session->lock);
-
- /*
- * clean up task if aborted. we have the xmitmutex so grab
- * the recv lock as a writer
- */
- write_lock_bh(conn->recv_lock);
- spin_lock(&session->lock);
- fail_command(conn, ctask, DID_ABORT << 16);
- spin_unlock(&session->lock);
- write_unlock_bh(conn->recv_lock);
-
-success_rel_mutex:
- mutex_unlock(&conn->xmitmutex);
+success_unlocked:
+ debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
return SUCCESS;
failed:
spin_unlock_bh(&session->lock);
- mutex_unlock(&conn->xmitmutex);
-
+failed_unlocked:
debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
return FAILED;
}
@@ -1339,6 +1330,10 @@ EXPORT_SYMBOL_GPL(iscsi_pool_free);
* iscsi_session_setup - create iscsi cls session and host and session
* @scsit: scsi transport template
* @iscsit: iscsi transport template
+ * @cmds_max: scsi host can queue
+ * @qdepth: scsi host cmds per lun
+ * @cmd_task_size: LLD ctask private data size
+ * @mgmt_task_size: LLD mtask private data size
* @initial_cmdsn: initial CmdSN
* @hostno: host no allocated
*
@@ -1348,6 +1343,7 @@ EXPORT_SYMBOL_GPL(iscsi_pool_free);
struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *iscsit,
struct scsi_transport_template *scsit,
+ uint16_t cmds_max, uint16_t qdepth,
int cmd_task_size, int mgmt_task_size,
uint32_t initial_cmdsn, uint32_t *hostno)
{
@@ -1356,11 +1352,32 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
struct iscsi_cls_session *cls_session;
int cmd_i;
+ if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
+ if (qdepth != 0)
+ printk(KERN_ERR "iscsi: invalid queue depth of %d. "
+ "Queue depth must be between 1 and %d.\n",
+ qdepth, ISCSI_MAX_CMD_PER_LUN);
+ qdepth = ISCSI_DEF_CMD_PER_LUN;
+ }
+
+ if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) ||
+ cmds_max >= ISCSI_MGMT_ITT_OFFSET) {
+ if (cmds_max != 0)
+ printk(KERN_ERR "iscsi: invalid can_queue of %d. "
+ "can_queue must be a power of 2 and between "
+ "2 and %d - setting to %d.\n", cmds_max,
+ ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX);
+ cmds_max = ISCSI_DEF_XMIT_CMDS_MAX;
+ }
+
shost = scsi_host_alloc(iscsit->host_template,
hostdata_privsize(sizeof(*session)));
if (!shost)
return NULL;
+ /* the iscsi layer takes one task for reserve */
+ shost->can_queue = cmds_max - 1;
+ shost->cmd_per_lun = qdepth;
shost->max_id = 1;
shost->max_channel = 0;
shost->max_lun = iscsit->max_lun;
@@ -1374,7 +1391,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
session->host = shost;
session->state = ISCSI_STATE_FREE;
session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
- session->cmds_max = ISCSI_XMIT_CMDS_MAX;
+ session->cmds_max = cmds_max;
session->cmdsn = initial_cmdsn;
session->exp_cmdsn = initial_cmdsn + 1;
session->max_cmdsn = initial_cmdsn + 1;
@@ -1461,7 +1478,14 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+ kfree(session->password);
+ kfree(session->password_in);
+ kfree(session->username);
+ kfree(session->username_in);
kfree(session->targetname);
+ kfree(session->netdev);
+ kfree(session->hwaddress);
+ kfree(session->initiatorname);
iscsi_destroy_session(cls_session);
scsi_host_put(shost);
@@ -1499,11 +1523,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
INIT_LIST_HEAD(&conn->xmitqueue);
/* initialize general immediate & non-immediate PDU commands queue */
- conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
- GFP_KERNEL, NULL);
- if (conn->immqueue == ERR_PTR(-ENOMEM))
- goto immqueue_alloc_fail;
-
conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
GFP_KERNEL, NULL);
if (conn->mgmtqueue == ERR_PTR(-ENOMEM))
@@ -1527,7 +1546,6 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
conn->login_mtask->data = conn->data = data;
init_timer(&conn->tmabort_timer);
- mutex_init(&conn->xmitmutex);
init_waitqueue_head(&conn->ehwait);
return cls_conn;
@@ -1538,8 +1556,6 @@ login_mtask_data_alloc_fail:
login_mtask_alloc_fail:
kfifo_free(conn->mgmtqueue);
mgmtqueue_alloc_fail:
- kfifo_free(conn->immqueue);
-immqueue_alloc_fail:
iscsi_destroy_conn(cls_conn);
return NULL;
}
@@ -1558,10 +1574,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
struct iscsi_session *session = conn->session;
unsigned long flags;
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
- mutex_lock(&conn->xmitmutex);
-
spin_lock_bh(&session->lock);
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
if (session->leadconn == conn) {
/*
@@ -1572,8 +1586,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
spin_unlock_bh(&session->lock);
- mutex_unlock(&conn->xmitmutex);
-
/*
* Block until all in-progress commands for this connection
* time out or fail.
@@ -1610,7 +1622,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
spin_unlock_bh(&session->lock);
- kfifo_free(conn->immqueue);
kfifo_free(conn->mgmtqueue);
iscsi_destroy_conn(cls_conn);
@@ -1671,8 +1682,7 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn)
struct iscsi_mgmt_task *mtask, *tmp;
/* handle pending */
- while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) ||
- __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
+ while (__kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) {
if (mtask == conn->login_mtask)
continue;
debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt);
@@ -1742,12 +1752,12 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
conn->c_stage = ISCSI_CONN_STOPPED;
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
spin_unlock_bh(&session->lock);
+ scsi_flush_work(session->host);
write_lock_bh(conn->recv_lock);
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
write_unlock_bh(conn->recv_lock);
- mutex_lock(&conn->xmitmutex);
/*
* for connection level recovery we should not calculate
* header digest. conn->hdr_size used for optimization
@@ -1771,8 +1781,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
fail_all_commands(conn);
flush_control_queues(session, conn);
spin_unlock_bh(&session->lock);
-
- mutex_unlock(&conn->xmitmutex);
}
void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
@@ -1867,6 +1875,30 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
case ISCSI_PARAM_EXP_STATSN:
sscanf(buf, "%u", &conn->exp_statsn);
break;
+ case ISCSI_PARAM_USERNAME:
+ kfree(session->username);
+ session->username = kstrdup(buf, GFP_KERNEL);
+ if (!session->username)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_USERNAME_IN:
+ kfree(session->username_in);
+ session->username_in = kstrdup(buf, GFP_KERNEL);
+ if (!session->username_in)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_PASSWORD:
+ kfree(session->password);
+ session->password = kstrdup(buf, GFP_KERNEL);
+ if (!session->password)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_PASSWORD_IN:
+ kfree(session->password_in);
+ session->password_in = kstrdup(buf, GFP_KERNEL);
+ if (!session->password_in)
+ return -ENOMEM;
+ break;
case ISCSI_PARAM_TARGET_NAME:
/* this should not change between logins */
if (session->targetname)
@@ -1940,6 +1972,18 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
case ISCSI_PARAM_TPGT:
len = sprintf(buf, "%d\n", session->tpgt);
break;
+ case ISCSI_PARAM_USERNAME:
+ len = sprintf(buf, "%s\n", session->username);
+ break;
+ case ISCSI_PARAM_USERNAME_IN:
+ len = sprintf(buf, "%s\n", session->username_in);
+ break;
+ case ISCSI_PARAM_PASSWORD:
+ len = sprintf(buf, "%s\n", session->password);
+ break;
+ case ISCSI_PARAM_PASSWORD_IN:
+ len = sprintf(buf, "%s\n", session->password_in);
+ break;
default:
return -ENOSYS;
}
@@ -1990,6 +2034,66 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
}
EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
+int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+ char *buf)
+{
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ int len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_NETDEV_NAME:
+ if (!session->netdev)
+ len = sprintf(buf, "%s\n", "default");
+ else
+ len = sprintf(buf, "%s\n", session->netdev);
+ break;
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ if (!session->hwaddress)
+ len = sprintf(buf, "%s\n", "default");
+ else
+ len = sprintf(buf, "%s\n", session->hwaddress);
+ break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ if (!session->initiatorname)
+ len = sprintf(buf, "%s\n", "unknown");
+ else
+ len = sprintf(buf, "%s\n", session->initiatorname);
+ break;
+
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_host_get_param);
+
+int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+ char *buf, int buflen)
+{
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_NETDEV_NAME:
+ if (!session->netdev)
+ session->netdev = kstrdup(buf, GFP_KERNEL);
+ break;
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ if (!session->hwaddress)
+ session->hwaddress = kstrdup(buf, GFP_KERNEL);
+ break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ if (!session->initiatorname)
+ session->initiatorname = kstrdup(buf, GFP_KERNEL);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_host_set_param);
+
MODULE_AUTHOR("Mike Christie");
MODULE_DESCRIPTION("iSCSI library functions");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index aafdc92f8312..3a3c1ac9c6cd 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -30,6 +30,13 @@ config SCSI_SAS_LIBSAS
This provides transport specific helpers for SAS drivers which
use the domain device construct (like the aic94xxx).
+config SCSI_SAS_ATA
+ bool "ATA support for libsas (requires libata)"
+ depends on SCSI_SAS_LIBSAS && ATA
+ help
+ Builds in ATA support into libsas. Will necessitate
+ the loading of libata along with libsas.
+
config SCSI_SAS_LIBSAS_DEBUG
bool "Compile the SAS Domain Transport Attributes in debug mode"
default y
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
index 44d972a3b4bd..fd387b91856e 100644
--- a/drivers/scsi/libsas/Makefile
+++ b/drivers/scsi/libsas/Makefile
@@ -34,3 +34,4 @@ libsas-y += sas_init.o \
sas_discover.o \
sas_expander.o \
sas_scsi_host.o
+libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
new file mode 100644
index 000000000000..ced2de32c511
--- /dev/null
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -0,0 +1,817 @@
+/*
+ * Support for SATA devices on Serial Attached SCSI (SAS) controllers
+ *
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Written by: Darrick J. Wong <djwong@us.ibm.com>, 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 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/scatterlist.h>
+
+#include <scsi/sas_ata.h>
+#include "sas_internal.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+#include "../scsi_transport_api.h"
+#include <scsi/scsi_eh.h>
+
+static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
+{
+ /* Cheesy attempt to translate SAS errors into ATA. Hah! */
+
+ /* transport error */
+ if (ts->resp == SAS_TASK_UNDELIVERED)
+ return AC_ERR_ATA_BUS;
+
+ /* ts->resp == SAS_TASK_COMPLETE */
+ /* task delivered, what happened afterwards? */
+ switch (ts->stat) {
+ case SAS_DEV_NO_RESPONSE:
+ return AC_ERR_TIMEOUT;
+
+ case SAS_INTERRUPTED:
+ case SAS_PHY_DOWN:
+ case SAS_NAK_R_ERR:
+ return AC_ERR_ATA_BUS;
+
+
+ case SAS_DATA_UNDERRUN:
+ /*
+ * Some programs that use the taskfile interface
+ * (smartctl in particular) can cause underrun
+ * problems. Ignore these errors, perhaps at our
+ * peril.
+ */
+ return 0;
+
+ case SAS_DATA_OVERRUN:
+ case SAS_QUEUE_FULL:
+ case SAS_DEVICE_UNKNOWN:
+ case SAS_SG_ERR:
+ return AC_ERR_INVALID;
+
+ case SAM_CHECK_COND:
+ case SAS_OPEN_TO:
+ case SAS_OPEN_REJECT:
+ SAS_DPRINTK("%s: Saw error %d. What to do?\n",
+ __FUNCTION__, ts->stat);
+ return AC_ERR_OTHER;
+
+ case SAS_ABORTED_TASK:
+ return AC_ERR_DEV;
+
+ case SAS_PROTO_RESPONSE:
+ /* This means the ending_fis has the error
+ * value; return 0 here to collect it */
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static void sas_ata_task_done(struct sas_task *task)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+ struct domain_device *dev;
+ struct task_status_struct *stat = &task->task_status;
+ struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf;
+ struct sas_ha_struct *sas_ha;
+ enum ata_completion_errors ac;
+ unsigned long flags;
+
+ if (!qc)
+ goto qc_already_gone;
+
+ dev = qc->ap->private_data;
+ sas_ha = dev->port->ha;
+
+ spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+ if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_GOOD) {
+ ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
+ qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+ dev->sata_dev.sstatus = resp->sstatus;
+ dev->sata_dev.serror = resp->serror;
+ dev->sata_dev.scontrol = resp->scontrol;
+ } else if (stat->stat != SAM_STAT_GOOD) {
+ ac = sas_to_ata_err(stat);
+ if (ac) {
+ SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__,
+ stat->stat);
+ /* We saw a SAS error. Send a vague error. */
+ qc->err_mask = ac;
+ dev->sata_dev.tf.feature = 0x04; /* status err */
+ dev->sata_dev.tf.command = ATA_ERR;
+ }
+ }
+
+ qc->lldd_task = NULL;
+ if (qc->scsicmd)
+ ASSIGN_SAS_TASK(qc->scsicmd, NULL);
+ ata_qc_complete(qc);
+ spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+
+ /*
+ * If the sas_task has an ata qc, a scsi_cmnd and the aborted
+ * flag is set, then we must have come in via the libsas EH
+ * functions. When we exit this function, we need to put the
+ * scsi_cmnd on the list of finished errors. The ata_qc_complete
+ * call cleans up the libata side of things but we're protected
+ * from the scsi_cmnd going away because the scsi_cmnd is owned
+ * by the EH, making libata's call to scsi_done a NOP.
+ */
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (qc->scsicmd && task->task_state_flags & SAS_TASK_STATE_ABORTED)
+ scsi_eh_finish_cmd(qc->scsicmd, &sas_ha->eh_done_q);
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+qc_already_gone:
+ list_del_init(&task->list);
+ sas_free_task(task);
+}
+
+static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
+{
+ int res;
+ struct sas_task *task;
+ struct domain_device *dev = qc->ap->private_data;
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct Scsi_Host *host = sas_ha->core.shost;
+ struct sas_internal *i = to_sas_internal(host->transportt);
+ struct scatterlist *sg;
+ unsigned int num = 0;
+ unsigned int xfer = 0;
+
+ task = sas_alloc_task(GFP_ATOMIC);
+ if (!task)
+ return AC_ERR_SYSTEM;
+ task->dev = dev;
+ task->task_proto = SAS_PROTOCOL_STP;
+ task->task_done = sas_ata_task_done;
+
+ if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+ qc->tf.command == ATA_CMD_FPDMA_READ) {
+ /* Need to zero out the tag libata assigned us */
+ qc->tf.nsect = 0;
+ }
+
+ ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
+ task->uldd_task = qc;
+ if (is_atapi_taskfile(&qc->tf)) {
+ memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
+ task->total_xfer_len = qc->nbytes + qc->pad_len;
+ task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+ } else {
+ ata_for_each_sg(sg, qc) {
+ num++;
+ xfer += sg->length;
+ }
+
+ task->total_xfer_len = xfer;
+ task->num_scatter = num;
+ }
+
+ task->data_dir = qc->dma_dir;
+ task->scatter = qc->__sg;
+ task->ata_task.retry_count = 1;
+ task->task_state_flags = SAS_TASK_STATE_PENDING;
+ qc->lldd_task = task;
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_NCQ:
+ task->ata_task.use_ncq = 1;
+ /* fall through */
+ case ATA_PROT_ATAPI_DMA:
+ case ATA_PROT_DMA:
+ task->ata_task.dma_xfer = 1;
+ break;
+ }
+
+ if (qc->scsicmd)
+ ASSIGN_SAS_TASK(qc->scsicmd, task);
+
+ if (sas_ha->lldd_max_execute_num < 2)
+ res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
+ else
+ res = sas_queue_up(task);
+
+ /* Examine */
+ if (res) {
+ SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+
+ if (qc->scsicmd)
+ ASSIGN_SAS_TASK(qc->scsicmd, NULL);
+ sas_free_task(task);
+ return AC_ERR_SYSTEM;
+ }
+
+ return 0;
+}
+
+static u8 sas_ata_check_status(struct ata_port *ap)
+{
+ struct domain_device *dev = ap->private_data;
+ return dev->sata_dev.tf.command;
+}
+
+static void sas_ata_phy_reset(struct ata_port *ap)
+{
+ struct domain_device *dev = ap->private_data;
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+ int res = 0;
+
+ if (i->dft->lldd_I_T_nexus_reset)
+ res = i->dft->lldd_I_T_nexus_reset(dev);
+
+ if (res)
+ SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
+
+ switch (dev->sata_dev.command_set) {
+ case ATA_COMMAND_SET:
+ SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
+ ap->device[0].class = ATA_DEV_ATA;
+ break;
+ case ATAPI_COMMAND_SET:
+ SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
+ ap->device[0].class = ATA_DEV_ATAPI;
+ break;
+ default:
+ SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
+ __FUNCTION__,
+ dev->sata_dev.command_set);
+ ap->device[0].class = ATA_DEV_UNKNOWN;
+ break;
+ }
+
+ ap->cbl = ATA_CBL_SATA;
+}
+
+static void sas_ata_post_internal(struct ata_queued_cmd *qc)
+{
+ if (qc->flags & ATA_QCFLAG_FAILED)
+ qc->err_mask |= AC_ERR_OTHER;
+
+ if (qc->err_mask) {
+ /*
+ * Find the sas_task and kill it. By this point,
+ * libata has decided to kill the qc, so we needn't
+ * bother with sas_ata_task_done. But we still
+ * ought to abort the task.
+ */
+ struct sas_task *task = qc->lldd_task;
+ unsigned long flags;
+
+ qc->lldd_task = NULL;
+ if (task) {
+ /* Should this be a AT(API) device reset? */
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ task->uldd_task = NULL;
+ __sas_task_abort(task);
+ }
+ }
+}
+
+static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct domain_device *dev = ap->private_data;
+ memcpy(tf, &dev->sata_dev.tf, sizeof (*tf));
+}
+
+static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
+ u32 val)
+{
+ struct domain_device *dev = ap->private_data;
+
+ SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ dev->sata_dev.sstatus = val;
+ break;
+ case SCR_CONTROL:
+ dev->sata_dev.scontrol = val;
+ break;
+ case SCR_ERROR:
+ dev->sata_dev.serror = val;
+ break;
+ case SCR_ACTIVE:
+ dev->sata_dev.ap->sactive = val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
+ u32 *val)
+{
+ struct domain_device *dev = ap->private_data;
+
+ SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+ switch (sc_reg_in) {
+ case SCR_STATUS:
+ *val = dev->sata_dev.sstatus;
+ return 0;
+ case SCR_CONTROL:
+ *val = dev->sata_dev.scontrol;
+ return 0;
+ case SCR_ERROR:
+ *val = dev->sata_dev.serror;
+ return 0;
+ case SCR_ACTIVE:
+ *val = dev->sata_dev.ap->sactive;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct ata_port_operations sas_sata_ops = {
+ .port_disable = ata_port_disable,
+ .check_status = sas_ata_check_status,
+ .check_altstatus = sas_ata_check_status,
+ .dev_select = ata_noop_dev_select,
+ .phy_reset = sas_ata_phy_reset,
+ .post_internal_cmd = sas_ata_post_internal,
+ .tf_read = sas_ata_tf_read,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = sas_ata_qc_issue,
+ .port_start = ata_sas_port_start,
+ .port_stop = ata_sas_port_stop,
+ .scr_read = sas_ata_scr_read,
+ .scr_write = sas_ata_scr_write
+};
+
+static struct ata_port_info sata_port_info = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ,
+ .pio_mask = 0x1f, /* PIO0-4 */
+ .mwdma_mask = 0x07, /* MWDMA0-2 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sas_sata_ops
+};
+
+int sas_ata_init_host_and_port(struct domain_device *found_dev,
+ struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ struct ata_port *ap;
+
+ ata_host_init(&found_dev->sata_dev.ata_host,
+ &ha->pcidev->dev,
+ sata_port_info.flags,
+ &sas_sata_ops);
+ ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host,
+ &sata_port_info,
+ shost);
+ if (!ap) {
+ SAS_DPRINTK("ata_sas_port_alloc failed.\n");
+ return -ENODEV;
+ }
+
+ ap->private_data = found_dev;
+ ap->cbl = ATA_CBL_SATA;
+ ap->scsi_host = shost;
+ found_dev->sata_dev.ap = ap;
+
+ return 0;
+}
+
+void sas_ata_task_abort(struct sas_task *task)
+{
+ struct ata_queued_cmd *qc = task->uldd_task;
+ struct completion *waiting;
+
+ /* Bounce SCSI-initiated commands to the SCSI EH */
+ if (qc->scsicmd) {
+ scsi_req_abort_cmd(qc->scsicmd);
+ scsi_schedule_eh(qc->scsicmd->device->host);
+ return;
+ }
+
+ /* Internal command, fake a timeout and complete. */
+ qc->flags &= ~ATA_QCFLAG_ACTIVE;
+ qc->flags |= ATA_QCFLAG_FAILED;
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ waiting = qc->private_data;
+ complete(waiting);
+}
+
+static void sas_task_timedout(unsigned long _task)
+{
+ struct sas_task *task = (void *) _task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ complete(&task->completion);
+}
+
+static void sas_disc_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->timer))
+ return;
+ complete(&task->completion);
+}
+
+#define SAS_DEV_TIMEOUT 10
+
+/**
+ * sas_execute_task -- Basic task processing for discovery
+ * @task: the task to be executed
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_execute_task(struct sas_task *task, void *buffer, int size,
+ int pci_dma_dir)
+{
+ int res = 0;
+ struct scatterlist *scatter = NULL;
+ struct task_status_struct *ts = &task->task_status;
+ int num_scatter = 0;
+ int retries = 0;
+ struct sas_internal *i =
+ to_sas_internal(task->dev->port->ha->core.shost->transportt);
+
+ if (pci_dma_dir != PCI_DMA_NONE) {
+ scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
+ if (!scatter)
+ goto out;
+
+ sg_init_one(scatter, buffer, size);
+ num_scatter = 1;
+ }
+
+ task->task_proto = task->dev->tproto;
+ task->scatter = scatter;
+ task->num_scatter = num_scatter;
+ task->total_xfer_len = size;
+ task->data_dir = pci_dma_dir;
+ task->task_done = sas_disc_task_done;
+ if (pci_dma_dir != PCI_DMA_NONE &&
+ sas_protocol_ata(task->task_proto)) {
+ task->num_scatter = pci_map_sg(task->dev->port->ha->pcidev,
+ task->scatter,
+ task->num_scatter,
+ task->data_dir);
+ }
+
+ for (retries = 0; retries < 5; retries++) {
+ task->task_state_flags = SAS_TASK_STATE_PENDING;
+ init_completion(&task->completion);
+
+ task->timer.data = (unsigned long) task;
+ task->timer.function = sas_task_timedout;
+ task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+ if (res) {
+ del_timer(&task->timer);
+ SAS_DPRINTK("executing SAS discovery task failed:%d\n",
+ res);
+ goto ex_err;
+ }
+ wait_for_completion(&task->completion);
+ res = -ETASK;
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ int res2;
+ SAS_DPRINTK("task aborted, flags:0x%x\n",
+ task->task_state_flags);
+ res2 = i->dft->lldd_abort_task(task);
+ SAS_DPRINTK("came back from abort task\n");
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ if (res2 == TMF_RESP_FUNC_COMPLETE)
+ continue; /* Retry the task */
+ else
+ goto ex_err;
+ }
+ }
+ if (task->task_status.stat == SAM_BUSY ||
+ task->task_status.stat == SAM_TASK_SET_FULL ||
+ task->task_status.stat == SAS_QUEUE_FULL) {
+ SAS_DPRINTK("task: q busy, sleeping...\n");
+ schedule_timeout_interruptible(HZ);
+ } else if (task->task_status.stat == SAM_CHECK_COND) {
+ struct scsi_sense_hdr shdr;
+
+ if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
+ &shdr)) {
+ SAS_DPRINTK("couldn't normalize sense\n");
+ continue;
+ }
+ if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
+ (shdr.sense_key == 2 && shdr.asc == 4 &&
+ shdr.ascq == 1)) {
+ SAS_DPRINTK("device %016llx LUN: %016llx "
+ "powering up or not ready yet, "
+ "sleeping...\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN));
+
+ schedule_timeout_interruptible(5*HZ);
+ } else if (shdr.sense_key == 1) {
+ res = 0;
+ break;
+ } else if (shdr.sense_key == 5) {
+ break;
+ } else {
+ SAS_DPRINTK("dev %016llx LUN: %016llx "
+ "sense key:0x%x ASC:0x%x ASCQ:0x%x"
+ "\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN),
+ shdr.sense_key,
+ shdr.asc, shdr.ascq);
+ }
+ } else if (task->task_status.resp != SAS_TASK_COMPLETE ||
+ task->task_status.stat != SAM_GOOD) {
+ SAS_DPRINTK("task finished with resp:0x%x, "
+ "stat:0x%x\n",
+ task->task_status.resp,
+ task->task_status.stat);
+ goto ex_err;
+ } else {
+ res = 0;
+ break;
+ }
+ }
+ex_err:
+ if (pci_dma_dir != PCI_DMA_NONE) {
+ if (sas_protocol_ata(task->task_proto))
+ pci_unmap_sg(task->dev->port->ha->pcidev,
+ task->scatter, task->num_scatter,
+ task->data_dir);
+ kfree(scatter);
+ }
+out:
+ return res;
+}
+
+/* ---------- SATA ---------- */
+
+static void sas_get_ata_command_set(struct domain_device *dev)
+{
+ struct dev_to_host_fis *fis =
+ (struct dev_to_host_fis *) dev->frame_rcvd;
+
+ if ((fis->sector_count == 1 && /* ATA */
+ fis->lbal == 1 &&
+ fis->lbam == 0 &&
+ fis->lbah == 0 &&
+ fis->device == 0)
+ ||
+ (fis->sector_count == 0 && /* CE-ATA (mATA) */
+ fis->lbal == 0 &&
+ fis->lbam == 0xCE &&
+ fis->lbah == 0xAA &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATA_COMMAND_SET;
+
+ else if ((fis->interrupt_reason == 1 && /* ATAPI */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x14 &&
+ fis->byte_count_high == 0xEB &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+
+ else if ((fis->sector_count == 1 && /* SEMB */
+ fis->lbal == 1 &&
+ fis->lbam == 0x3C &&
+ fis->lbah == 0xC3 &&
+ fis->device == 0)
+ ||
+ (fis->interrupt_reason == 1 && /* SATA PM */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x69 &&
+ fis->byte_count_high == 0x96 &&
+ (fis->device & ~0x10) == 0))
+
+ /* Treat it as a superset? */
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+}
+
+/**
+ * sas_issue_ata_cmd -- Basic SATA command processing for discovery
+ * @dev: the device to send the command to
+ * @command: the command register
+ * @features: the features register
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
+ u8 features, void *buffer, int size,
+ int pci_dma_dir)
+{
+ int res = 0;
+ struct sas_task *task;
+ struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
+ &dev->frame_rcvd[0];
+
+ res = -ENOMEM;
+ task = sas_alloc_task(GFP_KERNEL);
+ if (!task)
+ goto out;
+
+ task->dev = dev;
+
+ task->ata_task.fis.fis_type = 0x27;
+ task->ata_task.fis.command = command;
+ task->ata_task.fis.features = features;
+ task->ata_task.fis.device = d2h_fis->device;
+ task->ata_task.retry_count = 1;
+
+ res = sas_execute_task(task, buffer, size, pci_dma_dir);
+
+ sas_free_task(task);
+out:
+ return res;
+}
+
+static void sas_sata_propagate_sas_addr(struct domain_device *dev)
+{
+ unsigned long flags;
+ struct asd_sas_port *port = dev->port;
+ struct asd_sas_phy *phy;
+
+ BUG_ON(dev->parent);
+
+ memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_lock_irqsave(&port->phy_list_lock, flags);
+ list_for_each_entry(phy, &port->phy_list, port_phy_el)
+ memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+}
+
+#define ATA_IDENTIFY_DEV 0xEC
+#define ATA_IDENTIFY_PACKET_DEV 0xA1
+#define ATA_SET_FEATURES 0xEF
+#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
+
+/**
+ * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
+ * @dev: STP/SATA device of interest (ATA/ATAPI)
+ *
+ * The LLDD has already been notified of this device, so that we can
+ * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY
+ * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
+ * performance for this device.
+ */
+static int sas_discover_sata_dev(struct domain_device *dev)
+{
+ int res;
+ __le16 *identify_x;
+ u8 command;
+
+ identify_x = kzalloc(512, GFP_KERNEL);
+ if (!identify_x)
+ return -ENOMEM;
+
+ if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
+ dev->sata_dev.identify_device = identify_x;
+ command = ATA_IDENTIFY_DEV;
+ } else {
+ dev->sata_dev.identify_packet_device = identify_x;
+ command = ATA_IDENTIFY_PACKET_DEV;
+ }
+
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ PCI_DMA_FROMDEVICE);
+ if (res)
+ goto out_err;
+
+ /* lives on the media? */
+ if (le16_to_cpu(identify_x[0]) & 4) {
+ /* incomplete response */
+ SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
+ "dev %llx\n", SAS_ADDR(dev->sas_addr));
+ if (!le16_to_cpu(identify_x[83] & (1<<6)))
+ goto cont1;
+ res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
+ ATA_FEATURE_PUP_STBY_SPIN_UP,
+ NULL, 0, PCI_DMA_NONE);
+ if (res)
+ goto cont1;
+
+ schedule_timeout_interruptible(5*HZ); /* More time? */
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ PCI_DMA_FROMDEVICE);
+ if (res)
+ goto out_err;
+ }
+cont1:
+ /* Get WWN */
+ if (dev->port->oob_mode != SATA_OOB_MODE) {
+ memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
+ SAS_ADDR_SIZE);
+ } else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
+ (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
+ == 0x5000) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ dev->sas_addr[2*i] =
+ (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
+ dev->sas_addr[2*i+1] =
+ le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
+ }
+ }
+ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+ if (!dev->parent)
+ sas_sata_propagate_sas_addr(dev);
+
+ /* XXX Hint: register this SATA device with SATL.
+ When this returns, dev->sata_dev->lu is alive and
+ present.
+ sas_satl_register_dev(dev);
+ */
+
+ sas_fill_in_rphy(dev, dev->rphy);
+
+ return 0;
+out_err:
+ dev->sata_dev.identify_packet_device = NULL;
+ dev->sata_dev.identify_device = NULL;
+ kfree(identify_x);
+ return res;
+}
+
+static int sas_discover_sata_pm(struct domain_device *dev)
+{
+ return -ENODEV;
+}
+
+/**
+ * sas_discover_sata -- discover an STP/SATA domain device
+ * @dev: pointer to struct domain_device of interest
+ *
+ * First we notify the LLDD of this device, so we can send frames to
+ * it. Then depending on the type of device we call the appropriate
+ * discover functions. Once device discover is done, we notify the
+ * LLDD so that it can fine-tune its parameters for the device, by
+ * removing it and then adding it. That is, the second time around,
+ * the driver would have certain fields, that it is looking at, set.
+ * Finally we initialize the kobj so that the device can be added to
+ * the system at registration time. Devices directly attached to a HA
+ * port, have no parents. All other devices do, and should have their
+ * "parent" pointer set appropriately before calling this function.
+ */
+int sas_discover_sata(struct domain_device *dev)
+{
+ int res;
+
+ sas_get_ata_command_set(dev);
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ switch (dev->dev_type) {
+ case SATA_DEV:
+ res = sas_discover_sata_dev(dev);
+ break;
+ case SATA_PM:
+ res = sas_discover_sata_pm(dev);
+ break;
+ default:
+ break;
+ }
+ sas_notify_lldd_dev_gone(dev);
+ if (!res) {
+ sas_notify_lldd_dev_found(dev);
+ res = sas_rphy_add(dev->rphy);
+ }
+
+ return res;
+}
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index a65598b1e536..6ac9f61d006a 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -55,149 +55,6 @@ void sas_init_dev(struct domain_device *dev)
}
}
-static void sas_task_timedout(unsigned long _task)
-{
- struct sas_task *task = (void *) _task;
- unsigned long flags;
-
- spin_lock_irqsave(&task->task_state_lock, flags);
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
- task->task_state_flags |= SAS_TASK_STATE_ABORTED;
- spin_unlock_irqrestore(&task->task_state_lock, flags);
-
- complete(&task->completion);
-}
-
-static void sas_disc_task_done(struct sas_task *task)
-{
- if (!del_timer(&task->timer))
- return;
- complete(&task->completion);
-}
-
-#define SAS_DEV_TIMEOUT 10
-
-/**
- * sas_execute_task -- Basic task processing for discovery
- * @task: the task to be executed
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @pci_dma_dir: PCI_DMA_...
- */
-static int sas_execute_task(struct sas_task *task, void *buffer, int size,
- int pci_dma_dir)
-{
- int res = 0;
- struct scatterlist *scatter = NULL;
- struct task_status_struct *ts = &task->task_status;
- int num_scatter = 0;
- int retries = 0;
- struct sas_internal *i =
- to_sas_internal(task->dev->port->ha->core.shost->transportt);
-
- if (pci_dma_dir != PCI_DMA_NONE) {
- scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
- if (!scatter)
- goto out;
-
- sg_init_one(scatter, buffer, size);
- num_scatter = 1;
- }
-
- task->task_proto = task->dev->tproto;
- task->scatter = scatter;
- task->num_scatter = num_scatter;
- task->total_xfer_len = size;
- task->data_dir = pci_dma_dir;
- task->task_done = sas_disc_task_done;
-
- for (retries = 0; retries < 5; retries++) {
- task->task_state_flags = SAS_TASK_STATE_PENDING;
- init_completion(&task->completion);
-
- task->timer.data = (unsigned long) task;
- task->timer.function = sas_task_timedout;
- task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
- add_timer(&task->timer);
-
- res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
- if (res) {
- del_timer(&task->timer);
- SAS_DPRINTK("executing SAS discovery task failed:%d\n",
- res);
- goto ex_err;
- }
- wait_for_completion(&task->completion);
- res = -ETASK;
- if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
- int res2;
- SAS_DPRINTK("task aborted, flags:0x%x\n",
- task->task_state_flags);
- res2 = i->dft->lldd_abort_task(task);
- SAS_DPRINTK("came back from abort task\n");
- if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
- if (res2 == TMF_RESP_FUNC_COMPLETE)
- continue; /* Retry the task */
- else
- goto ex_err;
- }
- }
- if (task->task_status.stat == SAM_BUSY ||
- task->task_status.stat == SAM_TASK_SET_FULL ||
- task->task_status.stat == SAS_QUEUE_FULL) {
- SAS_DPRINTK("task: q busy, sleeping...\n");
- schedule_timeout_interruptible(HZ);
- } else if (task->task_status.stat == SAM_CHECK_COND) {
- struct scsi_sense_hdr shdr;
-
- if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
- &shdr)) {
- SAS_DPRINTK("couldn't normalize sense\n");
- continue;
- }
- if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
- (shdr.sense_key == 2 && shdr.asc == 4 &&
- shdr.ascq == 1)) {
- SAS_DPRINTK("device %016llx LUN: %016llx "
- "powering up or not ready yet, "
- "sleeping...\n",
- SAS_ADDR(task->dev->sas_addr),
- SAS_ADDR(task->ssp_task.LUN));
-
- schedule_timeout_interruptible(5*HZ);
- } else if (shdr.sense_key == 1) {
- res = 0;
- break;
- } else if (shdr.sense_key == 5) {
- break;
- } else {
- SAS_DPRINTK("dev %016llx LUN: %016llx "
- "sense key:0x%x ASC:0x%x ASCQ:0x%x"
- "\n",
- SAS_ADDR(task->dev->sas_addr),
- SAS_ADDR(task->ssp_task.LUN),
- shdr.sense_key,
- shdr.asc, shdr.ascq);
- }
- } else if (task->task_status.resp != SAS_TASK_COMPLETE ||
- task->task_status.stat != SAM_GOOD) {
- SAS_DPRINTK("task finished with resp:0x%x, "
- "stat:0x%x\n",
- task->task_status.resp,
- task->task_status.stat);
- goto ex_err;
- } else {
- res = 0;
- break;
- }
- }
-ex_err:
- if (pci_dma_dir != PCI_DMA_NONE)
- kfree(scatter);
-out:
- return res;
-}
-
/* ---------- Domain device discovery ---------- */
/**
@@ -255,6 +112,7 @@ static int sas_get_port_device(struct asd_sas_port *port)
switch (dev->dev_type) {
case SAS_END_DEV:
+ case SATA_DEV:
rphy = sas_end_device_alloc(port->port);
break;
case EDGE_DEV:
@@ -265,7 +123,6 @@ static int sas_get_port_device(struct asd_sas_port *port)
rphy = sas_expander_alloc(port->port,
SAS_FANOUT_EXPANDER_DEVICE);
break;
- case SATA_DEV:
default:
printk("ERROR: Unidentified device type %d\n", dev->dev_type);
rphy = NULL;
@@ -292,207 +149,15 @@ static int sas_get_port_device(struct asd_sas_port *port)
port->disc.max_level = 0;
dev->rphy = rphy;
- spin_lock(&port->dev_list_lock);
+ spin_lock_irq(&port->dev_list_lock);
list_add_tail(&dev->dev_list_node, &port->dev_list);
- spin_unlock(&port->dev_list_lock);
+ spin_unlock_irq(&port->dev_list_lock);
return 0;
}
/* ---------- Discover and Revalidate ---------- */
-/* ---------- SATA ---------- */
-
-static void sas_get_ata_command_set(struct domain_device *dev)
-{
- struct dev_to_host_fis *fis =
- (struct dev_to_host_fis *) dev->frame_rcvd;
-
- if ((fis->sector_count == 1 && /* ATA */
- fis->lbal == 1 &&
- fis->lbam == 0 &&
- fis->lbah == 0 &&
- fis->device == 0)
- ||
- (fis->sector_count == 0 && /* CE-ATA (mATA) */
- fis->lbal == 0 &&
- fis->lbam == 0xCE &&
- fis->lbah == 0xAA &&
- (fis->device & ~0x10) == 0))
-
- dev->sata_dev.command_set = ATA_COMMAND_SET;
-
- else if ((fis->interrupt_reason == 1 && /* ATAPI */
- fis->lbal == 1 &&
- fis->byte_count_low == 0x14 &&
- fis->byte_count_high == 0xEB &&
- (fis->device & ~0x10) == 0))
-
- dev->sata_dev.command_set = ATAPI_COMMAND_SET;
-
- else if ((fis->sector_count == 1 && /* SEMB */
- fis->lbal == 1 &&
- fis->lbam == 0x3C &&
- fis->lbah == 0xC3 &&
- fis->device == 0)
- ||
- (fis->interrupt_reason == 1 && /* SATA PM */
- fis->lbal == 1 &&
- fis->byte_count_low == 0x69 &&
- fis->byte_count_high == 0x96 &&
- (fis->device & ~0x10) == 0))
-
- /* Treat it as a superset? */
- dev->sata_dev.command_set = ATAPI_COMMAND_SET;
-}
-
-/**
- * sas_issue_ata_cmd -- Basic SATA command processing for discovery
- * @dev: the device to send the command to
- * @command: the command register
- * @features: the features register
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @pci_dma_dir: PCI_DMA_...
- */
-static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
- u8 features, void *buffer, int size,
- int pci_dma_dir)
-{
- int res = 0;
- struct sas_task *task;
- struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
- &dev->frame_rcvd[0];
-
- res = -ENOMEM;
- task = sas_alloc_task(GFP_KERNEL);
- if (!task)
- goto out;
-
- task->dev = dev;
-
- task->ata_task.fis.command = command;
- task->ata_task.fis.features = features;
- task->ata_task.fis.device = d2h_fis->device;
- task->ata_task.retry_count = 1;
-
- res = sas_execute_task(task, buffer, size, pci_dma_dir);
-
- sas_free_task(task);
-out:
- return res;
-}
-
-static void sas_sata_propagate_sas_addr(struct domain_device *dev)
-{
- unsigned long flags;
- struct asd_sas_port *port = dev->port;
- struct asd_sas_phy *phy;
-
- BUG_ON(dev->parent);
-
- memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
- spin_lock_irqsave(&port->phy_list_lock, flags);
- list_for_each_entry(phy, &port->phy_list, port_phy_el)
- memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
- spin_unlock_irqrestore(&port->phy_list_lock, flags);
-}
-
-#define ATA_IDENTIFY_DEV 0xEC
-#define ATA_IDENTIFY_PACKET_DEV 0xA1
-#define ATA_SET_FEATURES 0xEF
-#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
-
-/**
- * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
- * @dev: STP/SATA device of interest (ATA/ATAPI)
- *
- * The LLDD has already been notified of this device, so that we can
- * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY
- * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
- * performance for this device.
- */
-static int sas_discover_sata_dev(struct domain_device *dev)
-{
- int res;
- __le16 *identify_x;
- u8 command;
-
- identify_x = kzalloc(512, GFP_KERNEL);
- if (!identify_x)
- return -ENOMEM;
-
- if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
- dev->sata_dev.identify_device = identify_x;
- command = ATA_IDENTIFY_DEV;
- } else {
- dev->sata_dev.identify_packet_device = identify_x;
- command = ATA_IDENTIFY_PACKET_DEV;
- }
-
- res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
- PCI_DMA_FROMDEVICE);
- if (res)
- goto out_err;
-
- /* lives on the media? */
- if (le16_to_cpu(identify_x[0]) & 4) {
- /* incomplete response */
- SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
- "dev %llx\n", SAS_ADDR(dev->sas_addr));
- if (!le16_to_cpu(identify_x[83] & (1<<6)))
- goto cont1;
- res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
- ATA_FEATURE_PUP_STBY_SPIN_UP,
- NULL, 0, PCI_DMA_NONE);
- if (res)
- goto cont1;
-
- schedule_timeout_interruptible(5*HZ); /* More time? */
- res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
- PCI_DMA_FROMDEVICE);
- if (res)
- goto out_err;
- }
-cont1:
- /* Get WWN */
- if (dev->port->oob_mode != SATA_OOB_MODE) {
- memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
- SAS_ADDR_SIZE);
- } else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
- (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
- == 0x5000) {
- int i;
-
- for (i = 0; i < 4; i++) {
- dev->sas_addr[2*i] =
- (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
- dev->sas_addr[2*i+1] =
- le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
- }
- }
- sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
- if (!dev->parent)
- sas_sata_propagate_sas_addr(dev);
-
- /* XXX Hint: register this SATA device with SATL.
- When this returns, dev->sata_dev->lu is alive and
- present.
- sas_satl_register_dev(dev);
- */
- return 0;
-out_err:
- dev->sata_dev.identify_packet_device = NULL;
- dev->sata_dev.identify_device = NULL;
- kfree(identify_x);
- return res;
-}
-
-static int sas_discover_sata_pm(struct domain_device *dev)
-{
- return -ENODEV;
-}
-
int sas_notify_lldd_dev_found(struct domain_device *dev)
{
int res = 0;
@@ -525,60 +190,6 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
/* ---------- Common/dispatchers ---------- */
-/**
- * sas_discover_sata -- discover an STP/SATA domain device
- * @dev: pointer to struct domain_device of interest
- *
- * First we notify the LLDD of this device, so we can send frames to
- * it. Then depending on the type of device we call the appropriate
- * discover functions. Once device discover is done, we notify the
- * LLDD so that it can fine-tune its parameters for the device, by
- * removing it and then adding it. That is, the second time around,
- * the driver would have certain fields, that it is looking at, set.
- * Finally we initialize the kobj so that the device can be added to
- * the system at registration time. Devices directly attached to a HA
- * port, have no parents. All other devices do, and should have their
- * "parent" pointer set appropriately before calling this function.
- */
-int sas_discover_sata(struct domain_device *dev)
-{
- int res;
-
- sas_get_ata_command_set(dev);
-
- res = sas_notify_lldd_dev_found(dev);
- if (res)
- goto out_err2;
-
- switch (dev->dev_type) {
- case SATA_DEV:
- res = sas_discover_sata_dev(dev);
- break;
- case SATA_PM:
- res = sas_discover_sata_pm(dev);
- break;
- default:
- break;
- }
- if (res)
- goto out_err;
-
- sas_notify_lldd_dev_gone(dev);
- res = sas_notify_lldd_dev_found(dev);
- if (res)
- goto out_err2;
-
- res = sas_rphy_add(dev->rphy);
- if (res)
- goto out_err;
-
- return res;
-
-out_err:
- sas_notify_lldd_dev_gone(dev);
-out_err2:
- return res;
-}
/**
* sas_discover_end_dev -- discover an end device (SSP, etc)
@@ -685,11 +296,14 @@ static void sas_discover_domain(struct work_struct *work)
case FANOUT_DEV:
error = sas_discover_root_expander(dev);
break;
+#ifdef CONFIG_SCSI_SAS_ATA
case SATA_DEV:
case SATA_PM:
error = sas_discover_sata(dev);
break;
+#endif
default:
+ error = -ENXIO;
SAS_DPRINTK("unhandled device %d\n", dev->dev_type);
break;
}
@@ -698,9 +312,9 @@ static void sas_discover_domain(struct work_struct *work)
sas_rphy_free(dev->rphy);
dev->rphy = NULL;
- spin_lock(&port->dev_list_lock);
+ spin_lock_irq(&port->dev_list_lock);
list_del_init(&dev->dev_list_node);
- spin_unlock(&port->dev_list_lock);
+ spin_unlock_irq(&port->dev_list_lock);
kfree(dev); /* not kobject_register-ed yet */
port->port_dev = NULL;
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index e34442e405e8..b500f0c1449c 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -23,6 +23,7 @@
*/
#include <linux/scatterlist.h>
+#include <linux/blkdev.h>
#include "sas_internal.h"
@@ -36,12 +37,6 @@ static int sas_configure_phy(struct domain_device *dev, int phy_id,
u8 *sas_addr, int include);
static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr);
-#if 0
-/* FIXME: smp needs to migrate into the sas class */
-static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t);
-static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t);
-#endif
-
/* ---------- SMP task management ---------- */
static void smp_task_timedout(unsigned long _task)
@@ -218,6 +213,36 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
#define DISCOVER_REQ_SIZE 16
#define DISCOVER_RESP_SIZE 56
+static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
+ u8 *disc_resp, int single)
+{
+ int i, res;
+
+ disc_req[9] = single;
+ for (i = 1 ; i < 3; i++) {
+ struct discover_resp *dr;
+
+ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+ disc_resp, DISCOVER_RESP_SIZE);
+ if (res)
+ return res;
+ /* This is detecting a failure to transmit inital
+ * dev to host FIS as described in section G.5 of
+ * sas-2 r 04b */
+ dr = &((struct smp_resp *)disc_resp)->disc;
+ if (!(dr->attached_dev_type == 0 &&
+ dr->attached_sata_dev))
+ break;
+ /* In order to generate the dev to host FIS, we
+ * send a link reset to the expander port */
+ sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
+ /* Wait for the reset to trigger the negotiation */
+ msleep(500);
+ }
+ sas_set_ex_phy(dev, single, disc_resp);
+ return 0;
+}
+
static int sas_ex_phy_discover(struct domain_device *dev, int single)
{
struct expander_device *ex = &dev->ex_dev;
@@ -238,23 +263,15 @@ static int sas_ex_phy_discover(struct domain_device *dev, int single)
disc_req[1] = SMP_DISCOVER;
if (0 <= single && single < ex->num_phys) {
- disc_req[9] = single;
- res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
- disc_resp, DISCOVER_RESP_SIZE);
- if (res)
- goto out_err;
- sas_set_ex_phy(dev, single, disc_resp);
+ res = sas_ex_phy_discover_helper(dev, disc_req, disc_resp, single);
} else {
int i;
for (i = 0; i < ex->num_phys; i++) {
- disc_req[9] = i;
- res = smp_execute_task(dev, disc_req,
- DISCOVER_REQ_SIZE, disc_resp,
- DISCOVER_RESP_SIZE);
+ res = sas_ex_phy_discover_helper(dev, disc_req,
+ disc_resp, i);
if (res)
goto out_err;
- sas_set_ex_phy(dev, i, disc_resp);
}
}
out_err:
@@ -518,6 +535,8 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
}
+#ifdef CONFIG_SCSI_SAS_ATA
+
#define RPS_REQ_SIZE 16
#define RPS_RESP_SIZE 60
@@ -527,6 +546,7 @@ static int sas_get_report_phy_sata(struct domain_device *dev,
{
int res;
u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
+ u8 *resp = (u8 *)rps_resp;
if (!rps_req)
return -ENOMEM;
@@ -537,9 +557,30 @@ static int sas_get_report_phy_sata(struct domain_device *dev,
res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
rps_resp, RPS_RESP_SIZE);
+ /* 0x34 is the FIS type for the D2H fis. There's a potential
+ * standards cockup here. sas-2 explicitly specifies the FIS
+ * should be encoded so that FIS type is in resp[24].
+ * However, some expanders endian reverse this. Undo the
+ * reversal here */
+ if (!res && resp[27] == 0x34 && resp[24] != 0x34) {
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ int j = 24 + (i*4);
+ u8 a, b;
+ a = resp[j + 0];
+ b = resp[j + 1];
+ resp[j + 0] = resp[j + 3];
+ resp[j + 1] = resp[j + 2];
+ resp[j + 2] = b;
+ resp[j + 3] = a;
+ }
+ }
+
kfree(rps_req);
- return 0;
+ return res;
}
+#endif
static void sas_ex_get_linkrate(struct domain_device *parent,
struct domain_device *child,
@@ -607,6 +648,7 @@ static struct domain_device *sas_ex_discover_end_dev(
}
sas_ex_get_linkrate(parent, child, phy);
+#ifdef CONFIG_SCSI_SAS_ATA
if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
child->dev_type = SATA_DEV;
if (phy->attached_tproto & SAS_PROTO_STP)
@@ -623,16 +665,30 @@ static struct domain_device *sas_ex_discover_end_dev(
}
memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
sizeof(struct dev_to_host_fis));
+
+ rphy = sas_end_device_alloc(phy->port);
+ if (unlikely(!rphy))
+ goto out_free;
+
sas_init_dev(child);
+
+ child->rphy = rphy;
+
+ spin_lock_irq(&parent->port->dev_list_lock);
+ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+ spin_unlock_irq(&parent->port->dev_list_lock);
+
res = sas_discover_sata(child);
if (res) {
SAS_DPRINTK("sas_discover_sata() for device %16llx at "
"%016llx:0x%x returned 0x%x\n",
SAS_ADDR(child->sas_addr),
SAS_ADDR(parent->sas_addr), phy_id, res);
- goto out_free;
+ goto out_list_del;
}
- } else if (phy->attached_tproto & SAS_PROTO_SSP) {
+ } else
+#endif
+ if (phy->attached_tproto & SAS_PROTO_SSP) {
child->dev_type = SAS_END_DEV;
rphy = sas_end_device_alloc(phy->port);
/* FIXME: error handling */
@@ -644,9 +700,9 @@ static struct domain_device *sas_ex_discover_end_dev(
child->rphy = rphy;
sas_fill_in_rphy(child, rphy);
- spin_lock(&parent->port->dev_list_lock);
+ spin_lock_irq(&parent->port->dev_list_lock);
list_add_tail(&child->dev_list_node, &parent->port->dev_list);
- spin_unlock(&parent->port->dev_list_lock);
+ spin_unlock_irq(&parent->port->dev_list_lock);
res = sas_discover_end_dev(child);
if (res) {
@@ -660,6 +716,7 @@ static struct domain_device *sas_ex_discover_end_dev(
SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
phy->attached_tproto, SAS_ADDR(parent->sas_addr),
phy_id);
+ goto out_free;
}
list_add_tail(&child->siblings, &parent_ex->children);
@@ -759,9 +816,9 @@ static struct domain_device *sas_ex_discover_expander(
sas_fill_in_rphy(child, rphy);
sas_rphy_add(rphy);
- spin_lock(&parent->port->dev_list_lock);
+ spin_lock_irq(&parent->port->dev_list_lock);
list_add_tail(&child->dev_list_node, &parent->port->dev_list);
- spin_unlock(&parent->port->dev_list_lock);
+ spin_unlock_irq(&parent->port->dev_list_lock);
res = sas_discover_expander(child);
if (res) {
@@ -1357,31 +1414,6 @@ static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr)
return 0;
}
-#if 0
-#define SMP_BIN_ATTR_NAME "smp_portal"
-
-static void sas_ex_smp_hook(struct domain_device *dev)
-{
- struct expander_device *ex_dev = &dev->ex_dev;
- struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
-
- memset(bin_attr, 0, sizeof(*bin_attr));
-
- bin_attr->attr.name = SMP_BIN_ATTR_NAME;
- bin_attr->attr.owner = THIS_MODULE;
- bin_attr->attr.mode = 0600;
-
- bin_attr->size = 0;
- bin_attr->private = NULL;
- bin_attr->read = smp_portal_read;
- bin_attr->write= smp_portal_write;
- bin_attr->mmap = NULL;
-
- ex_dev->smp_portal_pid = -1;
- init_MUTEX(&ex_dev->smp_sema);
-}
-#endif
-
/**
* sas_discover_expander -- expander discovery
* @ex: pointer to expander domain device
@@ -1843,74 +1875,49 @@ out:
return res;
}
-#if 0
-/* ---------- SMP portal ---------- */
-
-static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
- size_t size)
+int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+ struct request *req)
{
- struct domain_device *dev = to_dom_device(kobj);
- struct expander_device *ex = &dev->ex_dev;
-
- if (offs != 0)
- return -EFBIG;
- else if (size == 0)
- return 0;
+ struct domain_device *dev;
+ int ret, type = rphy->identify.device_type;
+ struct request *rsp = req->next_rq;
- down_interruptible(&ex->smp_sema);
- if (ex->smp_req)
- kfree(ex->smp_req);
- ex->smp_req = kzalloc(size, GFP_USER);
- if (!ex->smp_req) {
- up(&ex->smp_sema);
- return -ENOMEM;
+ if (!rsp) {
+ printk("%s: space for a smp response is missing\n",
+ __FUNCTION__);
+ return -EINVAL;
}
- memcpy(ex->smp_req, buf, size);
- ex->smp_req_size = size;
- ex->smp_portal_pid = current->pid;
- up(&ex->smp_sema);
- return size;
-}
-
-static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs,
- size_t size)
-{
- struct domain_device *dev = to_dom_device(kobj);
- struct expander_device *ex = &dev->ex_dev;
- u8 *smp_resp;
- int res = -EINVAL;
-
- /* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
- * it should be 0.
- */
+ /* seems aic94xx doesn't support */
+ if (!rphy) {
+ printk("%s: can we send a smp request to a host?\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
- down_interruptible(&ex->smp_sema);
- if (!ex->smp_req || ex->smp_portal_pid != current->pid)
- goto out;
+ if (type != SAS_EDGE_EXPANDER_DEVICE &&
+ type != SAS_FANOUT_EXPANDER_DEVICE) {
+ printk("%s: can we send a smp request to a device?\n",
+ __FUNCTION__);
+ return -EINVAL;
+ }
- res = 0;
- if (size == 0)
- goto out;
+ dev = sas_find_dev_by_rphy(rphy);
+ if (!dev) {
+ printk("%s: fail to find a domain_device?\n", __FUNCTION__);
+ return -EINVAL;
+ }
- res = -ENOMEM;
- smp_resp = alloc_smp_resp(size);
- if (!smp_resp)
- goto out;
- res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
- smp_resp, size);
- if (!res) {
- memcpy(buf, smp_resp, size);
- res = size;
+ /* do we need to support multiple segments? */
+ if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+ printk("%s: multiple segments req %u %u, rsp %u %u\n",
+ __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+ rsp->bio->bi_vcnt, rsp->data_len);
+ return -EINVAL;
}
- kfree(smp_resp);
-out:
- kfree(ex->smp_req);
- ex->smp_req = NULL;
- ex->smp_req_size = 0;
- ex->smp_portal_pid = -1;
- up(&ex->smp_sema);
- return res;
+ ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
+ bio_data(rsp->bio), rsp->data_len);
+
+ return ret;
}
-#endif
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 965698c8b7bf..9cd5abe9e714 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -259,6 +259,7 @@ static struct sas_function_template sft = {
.phy_reset = sas_phy_reset,
.set_phy_speed = sas_set_phy_speed,
.get_linkerrors = sas_get_linkerrors,
+ .smp_handler = sas_smp_handler,
};
struct scsi_transport_template *
@@ -292,7 +293,7 @@ EXPORT_SYMBOL_GPL(sas_domain_release_transport);
static int __init sas_class_init(void)
{
sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (!sas_task_cache)
return -ENOMEM;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index a78638df2018..2b8213b1832d 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -39,6 +39,9 @@
#define SAS_DPRINTK(fmt, ...)
#endif
+#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
+#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
+
void sas_scsi_recover_host(struct Scsi_Host *shost);
int sas_show_class(enum sas_class class, char *buf);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index b4b52694497c..7663841eb4cf 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -34,19 +34,19 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_sas.h>
+#include <scsi/sas_ata.h>
#include "../scsi_sas_internal.h"
#include "../scsi_transport_api.h"
#include "../scsi_priv.h"
#include <linux/err.h>
#include <linux/blkdev.h>
+#include <linux/freezer.h>
#include <linux/scatterlist.h>
+#include <linux/libata.h>
/* ---------- SCSI Host glue ---------- */
-#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
-#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
-
static void sas_scsi_task_done(struct sas_task *task)
{
struct task_status_struct *ts = &task->task_status;
@@ -76,8 +76,8 @@ static void sas_scsi_task_done(struct sas_task *task)
hs = DID_NO_CONNECT;
break;
case SAS_DATA_UNDERRUN:
- sc->resid = ts->residual;
- if (sc->request_bufflen - sc->resid < sc->underflow)
+ scsi_set_resid(sc, ts->residual);
+ if (scsi_bufflen(sc) - scsi_get_resid(sc) < sc->underflow)
hs = DID_ERROR;
break;
case SAS_DATA_OVERRUN:
@@ -161,9 +161,9 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
- task->scatter = cmd->request_buffer;
- task->num_scatter = cmd->use_sg;
- task->total_xfer_len = cmd->request_bufflen;
+ task->scatter = scsi_sglist(cmd);
+ task->num_scatter = scsi_sg_count(cmd);
+ task->total_xfer_len = scsi_bufflen(cmd);
task->data_dir = cmd->sc_data_direction;
task->task_done = sas_scsi_task_done;
@@ -171,7 +171,7 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
return task;
}
-static int sas_queue_up(struct sas_task *task)
+int sas_queue_up(struct sas_task *task)
{
struct sas_ha_struct *sas_ha = task->dev->port->ha;
struct scsi_core *core = &sas_ha->core;
@@ -212,6 +212,16 @@ int sas_queuecommand(struct scsi_cmnd *cmd,
struct sas_ha_struct *sas_ha = dev->port->ha;
struct sas_task *task;
+ if (dev_is_sata(dev)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+ res = ata_sas_queuecmd(cmd, scsi_done,
+ dev->sata_dev.ap);
+ spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+ goto out;
+ }
+
res = -ENOMEM;
task = sas_create_task(cmd, dev, GFP_ATOMIC);
if (!task)
@@ -683,6 +693,16 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
return EH_NOT_HANDLED;
}
+int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+ struct domain_device *dev = sdev_to_domain_dev(sdev);
+
+ if (dev_is_sata(dev))
+ return ata_scsi_ioctl(sdev, cmd, arg);
+
+ return -EINVAL;
+}
+
struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
{
struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
@@ -722,10 +742,17 @@ static inline struct domain_device *sas_find_target(struct scsi_target *starget)
int sas_target_alloc(struct scsi_target *starget)
{
struct domain_device *found_dev = sas_find_target(starget);
+ int res;
if (!found_dev)
return -ENODEV;
+ if (dev_is_sata(found_dev)) {
+ res = sas_ata_init_host_and_port(found_dev, starget);
+ if (res)
+ return res;
+ }
+
starget->hostdata = found_dev;
return 0;
}
@@ -740,6 +767,11 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
+ if (dev_is_sata(dev)) {
+ ata_sas_slave_configure(scsi_dev, dev->sata_dev.ap);
+ return 0;
+ }
+
sas_ha = dev->port->ha;
sas_read_port_mode_page(scsi_dev);
@@ -763,6 +795,10 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
void sas_slave_destroy(struct scsi_device *scsi_dev)
{
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+ if (dev_is_sata(dev))
+ ata_port_disable(dev->sata_dev.ap);
}
int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
@@ -868,8 +904,6 @@ static int sas_queue_thread(void *_sas_ha)
{
struct sas_ha_struct *sas_ha = _sas_ha;
- current->flags |= PF_NOFREEZE;
-
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
@@ -981,10 +1015,38 @@ void sas_task_abort(struct sas_task *task)
return;
}
+ if (dev_is_sata(task->dev)) {
+ sas_ata_task_abort(task);
+ return;
+ }
+
scsi_req_abort_cmd(sc);
scsi_schedule_eh(sc->device->host);
}
+int sas_slave_alloc(struct scsi_device *scsi_dev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+ if (dev_is_sata(dev))
+ return ata_sas_port_init(dev->sata_dev.ap);
+
+ return 0;
+}
+
+void sas_target_destroy(struct scsi_target *starget)
+{
+ struct domain_device *found_dev = sas_find_target(starget);
+
+ if (!found_dev)
+ return;
+
+ if (dev_is_sata(found_dev))
+ ata_sas_port_destroy(found_dev->sata_dev.ap);
+
+ return;
+}
+
EXPORT_SYMBOL_GPL(sas_queuecommand);
EXPORT_SYMBOL_GPL(sas_target_alloc);
EXPORT_SYMBOL_GPL(sas_slave_configure);
@@ -998,3 +1060,6 @@ EXPORT_SYMBOL_GPL(sas_phy_reset);
EXPORT_SYMBOL_GPL(sas_phy_enable);
EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
+EXPORT_SYMBOL_GPL(sas_slave_alloc);
+EXPORT_SYMBOL_GPL(sas_target_destroy);
+EXPORT_SYMBOL_GPL(sas_ioctl);
diff --git a/drivers/scsi/lpfc/Makefile b/drivers/scsi/lpfc/Makefile
index d1be465d5f55..1c286707dd5f 100644
--- a/drivers/scsi/lpfc/Makefile
+++ b/drivers/scsi/lpfc/Makefile
@@ -1,7 +1,7 @@
#/*******************************************************************
# * This file is part of the Emulex Linux Device Driver for *
# * Fibre Channel Host Bus Adapters. *
-# * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+# * Copyright (C) 2004-2006 Emulex. All rights reserved. *
# * EMULEX and SLI are trademarks of Emulex. *
# * www.emulex.com *
# * *
@@ -27,4 +27,5 @@ endif
obj-$(CONFIG_SCSI_LPFC) := lpfc.o
lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \
- lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o
+ lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \
+ lpfc_vport.o lpfc_debugfs.o
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 82e8f90c4617..f8f64d6485cd 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -19,8 +19,9 @@
* included with this package. *
*******************************************************************/
-struct lpfc_sli2_slim;
+#include <scsi/scsi_host.h>
+struct lpfc_sli2_slim;
#define LPFC_MAX_TARGET 256 /* max number of targets supported */
#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els
@@ -32,6 +33,20 @@ struct lpfc_sli2_slim;
#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */
#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */
+/*
+ * Following time intervals are used of adjusting SCSI device
+ * queue depths when there are driver resource error or Firmware
+ * resource error.
+ */
+#define QUEUE_RAMP_DOWN_INTERVAL (1 * HZ) /* 1 Second */
+#define QUEUE_RAMP_UP_INTERVAL (300 * HZ) /* 5 minutes */
+
+/* Number of exchanges reserved for discovery to complete */
+#define LPFC_DISC_IOCB_BUFF_COUNT 20
+
+#define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */
+#define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */
+
/* Define macros for 64 bit support */
#define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr)))
#define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32)))
@@ -61,6 +76,11 @@ struct lpfc_dma_pool {
uint32_t current_count;
};
+struct hbq_dmabuf {
+ struct lpfc_dmabuf dbuf;
+ uint32_t tag;
+};
+
/* Priority bit. Set value to exceed low water mark in lpfc_mem. */
#define MEM_PRI 0x100
@@ -90,6 +110,29 @@ typedef struct lpfc_vpd {
uint32_t sli2FwRev;
uint8_t sli2FwName[16];
} rev;
+ struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd2 :24; /* Reserved */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+#else /* __LITTLE_ENDIAN */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t rsvd2 :24; /* Reserved */
+#endif
+ } sli3Feat;
} lpfc_vpd_t;
struct lpfc_scsi_buf;
@@ -122,6 +165,7 @@ struct lpfc_stats {
uint32_t elsRcvRPS;
uint32_t elsRcvRPL;
uint32_t elsXmitFLOGI;
+ uint32_t elsXmitFDISC;
uint32_t elsXmitPLOGI;
uint32_t elsXmitPRLI;
uint32_t elsXmitADISC;
@@ -165,50 +209,186 @@ struct lpfc_sysfs_mbox {
struct lpfcMboxq * mbox;
};
+struct lpfc_hba;
+
+
+enum discovery_state {
+ LPFC_VPORT_UNKNOWN = 0, /* vport state is unknown */
+ LPFC_VPORT_FAILED = 1, /* vport has failed */
+ LPFC_LOCAL_CFG_LINK = 6, /* local NPORT Id configured */
+ LPFC_FLOGI = 7, /* FLOGI sent to Fabric */
+ LPFC_FDISC = 8, /* FDISC sent for vport */
+ LPFC_FABRIC_CFG_LINK = 9, /* Fabric assigned NPORT Id
+ * configured */
+ LPFC_NS_REG = 10, /* Register with NameServer */
+ LPFC_NS_QRY = 11, /* Query NameServer for NPort ID list */
+ LPFC_BUILD_DISC_LIST = 12, /* Build ADISC and PLOGI lists for
+ * device authentication / discovery */
+ LPFC_DISC_AUTH = 13, /* Processing ADISC list */
+ LPFC_VPORT_READY = 32,
+};
+
+enum hba_state {
+ LPFC_LINK_UNKNOWN = 0, /* HBA state is unknown */
+ LPFC_WARM_START = 1, /* HBA state after selective reset */
+ LPFC_INIT_START = 2, /* Initial state after board reset */
+ LPFC_INIT_MBX_CMDS = 3, /* Initialize HBA with mbox commands */
+ LPFC_LINK_DOWN = 4, /* HBA initialized, link is down */
+ LPFC_LINK_UP = 5, /* Link is up - issue READ_LA */
+ LPFC_CLEAR_LA = 6, /* authentication cmplt - issue
+ * CLEAR_LA */
+ LPFC_HBA_READY = 32,
+ LPFC_HBA_ERROR = -1
+};
+
+struct lpfc_vport {
+ struct list_head listentry;
+ struct lpfc_hba *phba;
+ uint8_t port_type;
+#define LPFC_PHYSICAL_PORT 1
+#define LPFC_NPIV_PORT 2
+#define LPFC_FABRIC_PORT 3
+ enum discovery_state port_state;
+
+ uint16_t vpi;
+
+ uint32_t fc_flag; /* FC flags */
+/* Several of these flags are HBA centric and should be moved to
+ * phba->link_flag (e.g. FC_PTP, FC_PUBLIC_LOOP)
+ */
+#define FC_PT2PT 0x1 /* pt2pt with no fabric */
+#define FC_PT2PT_PLOGI 0x2 /* pt2pt initiate PLOGI */
+#define FC_DISC_TMO 0x4 /* Discovery timer running */
+#define FC_PUBLIC_LOOP 0x8 /* Public loop */
+#define FC_LBIT 0x10 /* LOGIN bit in loopinit set */
+#define FC_RSCN_MODE 0x20 /* RSCN cmd rcv'ed */
+#define FC_NLP_MORE 0x40 /* More node to process in node tbl */
+#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */
+#define FC_FABRIC 0x100 /* We are fabric attached */
+#define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */
+#define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */
+#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
+#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
+#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
+#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
+#define FC_RFF_NOT_SUPPORTED 0x40000 /* RFF_ID was rejected by switch */
+#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */
+#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */
+
+ struct list_head fc_nodes;
+
+ /* Keep counters for the number of entries in each list. */
+ uint16_t fc_plogi_cnt;
+ uint16_t fc_adisc_cnt;
+ uint16_t fc_reglogin_cnt;
+ uint16_t fc_prli_cnt;
+ uint16_t fc_unmap_cnt;
+ uint16_t fc_map_cnt;
+ uint16_t fc_npr_cnt;
+ uint16_t fc_unused_cnt;
+ struct serv_parm fc_sparam; /* buffer for our service parameters */
+
+ uint32_t fc_myDID; /* fibre channel S_ID */
+ uint32_t fc_prevDID; /* previous fibre channel S_ID */
+
+ int32_t stopped; /* HBA has not been restarted since last ERATT */
+ uint8_t fc_linkspeed; /* Link speed after last READ_LA */
+
+ uint32_t num_disc_nodes; /*in addition to hba_state */
+
+ uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */
+ uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */
+ struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN];
+ struct lpfc_name fc_nodename; /* fc nodename */
+ struct lpfc_name fc_portname; /* fc portname */
+
+ struct lpfc_work_evt disc_timeout_evt;
+
+ struct timer_list fc_disctmo; /* Discovery rescue timer */
+ uint8_t fc_ns_retry; /* retries for fabric nameserver */
+ uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */
+
+ spinlock_t work_port_lock;
+ uint32_t work_port_events; /* Timeout to be handled */
+#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */
+#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */
+#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */
+
+#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */
+#define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */
+#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timout */
+#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */
+#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */
+
+ struct timer_list fc_fdmitmo;
+ struct timer_list els_tmofunc;
+
+ int unreg_vpi_cmpl;
+
+ uint8_t load_flag;
+#define FC_LOADING 0x1 /* HBA in process of loading drvr */
+#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */
+ char *vname; /* Application assigned name */
+ struct fc_vport *fc_vport;
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct dentry *debug_disc_trc;
+ struct dentry *debug_nodelist;
+ struct dentry *vport_debugfs_root;
+ struct lpfc_disc_trc *disc_trc;
+ atomic_t disc_trc_cnt;
+#endif
+};
+
+struct hbq_s {
+ uint16_t entry_count; /* Current number of HBQ slots */
+ uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */
+ uint32_t hbqPutIdx; /* HBQ slot to use */
+ uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
+};
+
+#define LPFC_MAX_HBQS 16
+/* this matches the possition in the lpfc_hbq_defs array */
+#define LPFC_ELS_HBQ 0
+
struct lpfc_hba {
struct lpfc_sli sli;
+ uint32_t sli_rev; /* SLI2 or SLI3 */
+ uint32_t sli3_options; /* Mask of enabled SLI3 options */
+#define LPFC_SLI3_ENABLED 0x01
+#define LPFC_SLI3_HBQ_ENABLED 0x02
+#define LPFC_SLI3_NPIV_ENABLED 0x04
+#define LPFC_SLI3_VPORT_TEARDOWN 0x08
+ uint32_t iocb_cmd_size;
+ uint32_t iocb_rsp_size;
+
+ enum hba_state link_state;
+ uint32_t link_flag; /* link state flags */
+#define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */
+ /* This flag is set while issuing */
+ /* INIT_LINK mailbox command */
+#define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */
+#define LS_IGNORE_ERATT 0x3 /* intr handler should ignore ERATT */
+
struct lpfc_sli2_slim *slim2p;
+ struct lpfc_dmabuf hbqslimp;
+
dma_addr_t slim2p_mapping;
+
uint16_t pci_cfg_value;
- int32_t hba_state;
-
-#define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */
-#define LPFC_WARM_START 1 /* HBA state after selective reset */
-#define LPFC_INIT_START 2 /* Initial state after board reset */
-#define LPFC_INIT_MBX_CMDS 3 /* Initialize HBA with mbox commands */
-#define LPFC_LINK_DOWN 4 /* HBA initialized, link is down */
-#define LPFC_LINK_UP 5 /* Link is up - issue READ_LA */
-#define LPFC_LOCAL_CFG_LINK 6 /* local NPORT Id configured */
-#define LPFC_FLOGI 7 /* FLOGI sent to Fabric */
-#define LPFC_FABRIC_CFG_LINK 8 /* Fabric assigned NPORT Id
- configured */
-#define LPFC_NS_REG 9 /* Register with NameServer */
-#define LPFC_NS_QRY 10 /* Query NameServer for NPort ID list */
-#define LPFC_BUILD_DISC_LIST 11 /* Build ADISC and PLOGI lists for
- * device authentication / discovery */
-#define LPFC_DISC_AUTH 12 /* Processing ADISC list */
-#define LPFC_CLEAR_LA 13 /* authentication cmplt - issue
- CLEAR_LA */
-#define LPFC_HBA_READY 32
-#define LPFC_HBA_ERROR -1
+ uint8_t work_found;
+#define LPFC_MAX_WORKER_ITERATION 4
- int32_t stopped; /* HBA has not been restarted since last ERATT */
uint8_t fc_linkspeed; /* Link speed after last READ_LA */
uint32_t fc_eventTag; /* event tag for link attention */
- uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */
- uint32_t num_disc_nodes; /*in addition to hba_state */
struct timer_list fc_estabtmo; /* link establishment timer */
- struct timer_list fc_disctmo; /* Discovery rescue timer */
- struct timer_list fc_fdmitmo; /* fdmi timer */
/* These fields used to be binfo */
- struct lpfc_name fc_nodename; /* fc nodename */
- struct lpfc_name fc_portname; /* fc portname */
uint32_t fc_pref_DID; /* preferred D_ID */
- uint8_t fc_pref_ALPA; /* preferred AL_PA */
+ uint8_t fc_pref_ALPA; /* preferred AL_PA */
uint32_t fc_edtov; /* E_D_TOV timer value */
uint32_t fc_arbtov; /* ARB_TOV timer value */
uint32_t fc_ratov; /* R_A_TOV timer value */
@@ -216,61 +396,21 @@ struct lpfc_hba {
uint32_t fc_altov; /* AL_TOV timer value */
uint32_t fc_crtov; /* C_R_TOV timer value */
uint32_t fc_citov; /* C_I_TOV timer value */
- uint32_t fc_myDID; /* fibre channel S_ID */
- uint32_t fc_prevDID; /* previous fibre channel S_ID */
- struct serv_parm fc_sparam; /* buffer for our service parameters */
struct serv_parm fc_fabparam; /* fabric service parameters buffer */
uint8_t alpa_map[128]; /* AL_PA map from READ_LA */
- uint8_t fc_ns_retry; /* retries for fabric nameserver */
- uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */
- uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */
- struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN];
uint32_t lmt;
- uint32_t fc_flag; /* FC flags */
-#define FC_PT2PT 0x1 /* pt2pt with no fabric */
-#define FC_PT2PT_PLOGI 0x2 /* pt2pt initiate PLOGI */
-#define FC_DISC_TMO 0x4 /* Discovery timer running */
-#define FC_PUBLIC_LOOP 0x8 /* Public loop */
-#define FC_LBIT 0x10 /* LOGIN bit in loopinit set */
-#define FC_RSCN_MODE 0x20 /* RSCN cmd rcv'ed */
-#define FC_NLP_MORE 0x40 /* More node to process in node tbl */
-#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */
-#define FC_FABRIC 0x100 /* We are fabric attached */
-#define FC_ESTABLISH_LINK 0x200 /* Reestablish Link */
-#define FC_RSCN_DISCOVERY 0x400 /* Authenticate all devices after RSCN*/
-#define FC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */
-#define FC_LOADING 0x1000 /* HBA in process of loading drvr */
-#define FC_UNLOADING 0x2000 /* HBA in process of unloading drvr */
-#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */
-#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */
-#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */
-#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */
-#define FC_LOOPBACK_MODE 0x40000 /* NPort is in Loopback mode */
- /* This flag is set while issuing */
- /* INIT_LINK mailbox command */
-#define FC_IGNORE_ERATT 0x80000 /* intr handler should ignore ERATT */
uint32_t fc_topology; /* link topology, from LINK INIT */
struct lpfc_stats fc_stat;
- struct list_head fc_nodes;
-
- /* Keep counters for the number of entries in each list. */
- uint16_t fc_plogi_cnt;
- uint16_t fc_adisc_cnt;
- uint16_t fc_reglogin_cnt;
- uint16_t fc_prli_cnt;
- uint16_t fc_unmap_cnt;
- uint16_t fc_map_cnt;
- uint16_t fc_npr_cnt;
- uint16_t fc_unused_cnt;
struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */
uint32_t nport_event_cnt; /* timestamp for nlplist entry */
- uint32_t wwnn[2];
+ uint8_t wwnn[8];
+ uint8_t wwpn[8];
uint32_t RandomData[7];
uint32_t cfg_log_verbose;
@@ -278,6 +418,9 @@ struct lpfc_hba {
uint32_t cfg_nodev_tmo;
uint32_t cfg_devloss_tmo;
uint32_t cfg_hba_queue_depth;
+ uint32_t cfg_peer_port_login;
+ uint32_t cfg_vport_restrict_login;
+ uint32_t cfg_npiv_enable;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
uint32_t cfg_ack0;
@@ -304,22 +447,20 @@ struct lpfc_hba {
lpfc_vpd_t vpd; /* vital product data */
- struct Scsi_Host *host;
struct pci_dev *pcidev;
struct list_head work_list;
uint32_t work_ha; /* Host Attention Bits for WT */
uint32_t work_ha_mask; /* HA Bits owned by WT */
uint32_t work_hs; /* HS stored in case of ERRAT */
uint32_t work_status[2]; /* Extra status from SLIM */
- uint32_t work_hba_events; /* Timeout to be handled */
-#define WORKER_DISC_TMO 0x1 /* Discovery timeout */
-#define WORKER_ELS_TMO 0x2 /* ELS timeout */
-#define WORKER_MBOX_TMO 0x4 /* MBOX timeout */
-#define WORKER_FDMI_TMO 0x8 /* FDMI timeout */
wait_queue_head_t *work_wait;
struct task_struct *worker_thread;
+ struct list_head hbq_buffer_list;
+ uint32_t hbq_count; /* Count of configured HBQs */
+ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */
+
unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */
unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */
void __iomem *slim_memmap_p; /* Kernel memory mapped address for
@@ -334,6 +475,10 @@ struct lpfc_hba {
reg */
void __iomem *HCregaddr; /* virtual address for host ctl reg */
+ struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */
+ uint32_t __iomem *hbq_put; /* Address in SLIM to HBQ put ptrs */
+ uint32_t *hbq_get; /* Host mem address of HBQ get ptrs */
+
int brd_no; /* FC board number */
char SerialNumber[32]; /* adapter Serial Number */
@@ -353,7 +498,6 @@ struct lpfc_hba {
uint8_t soft_wwn_enable;
struct timer_list fcp_poll_timer;
- struct timer_list els_tmofunc;
/*
* stat counters
@@ -370,31 +514,69 @@ struct lpfc_hba {
uint32_t total_scsi_bufs;
struct list_head lpfc_iocb_list;
uint32_t total_iocbq_bufs;
+ spinlock_t hbalock;
/* pci_mem_pools */
struct pci_pool *lpfc_scsi_dma_buf_pool;
struct pci_pool *lpfc_mbuf_pool;
+ struct pci_pool *lpfc_hbq_pool;
struct lpfc_dma_pool lpfc_mbuf_safety_pool;
mempool_t *mbox_mem_pool;
mempool_t *nlp_mem_pool;
struct fc_host_statistics link_stats;
+
+ struct list_head port_list;
+ struct lpfc_vport *pport; /* physical lpfc_vport pointer */
+ uint16_t max_vpi; /* Maximum virtual nports */
+#define LPFC_MAX_VPI 100 /* Max number of VPorts supported */
+ unsigned long *vpi_bmask; /* vpi allocation table */
+
+ /* Data structure used by fabric iocb scheduler */
+ struct list_head fabric_iocb_list;
+ atomic_t fabric_iocb_count;
+ struct timer_list fabric_block_timer;
+ unsigned long bit_flags;
+#define FABRIC_COMANDS_BLOCKED 0
+ atomic_t num_rsrc_err;
+ atomic_t num_cmd_success;
+ unsigned long last_rsrc_error_time;
+ unsigned long last_ramp_down_time;
+ unsigned long last_ramp_up_time;
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct dentry *hba_debugfs_root;
+ atomic_t debugfs_vport_count;
+#endif
+
+ /* Fields used for heart beat. */
+ unsigned long last_completion_time;
+ struct timer_list hb_tmofunc;
+ uint8_t hb_outstanding;
};
+static inline struct Scsi_Host *
+lpfc_shost_from_vport(struct lpfc_vport *vport)
+{
+ return container_of((void *) vport, struct Scsi_Host, hostdata[0]);
+}
+
static inline void
-lpfc_set_loopback_flag(struct lpfc_hba *phba) {
+lpfc_set_loopback_flag(struct lpfc_hba *phba)
+{
if (phba->cfg_topology == FLAGS_LOCAL_LB)
- phba->fc_flag |= FC_LOOPBACK_MODE;
+ phba->link_flag |= LS_LOOPBACK_MODE;
else
- phba->fc_flag &= ~FC_LOOPBACK_MODE;
+ phba->link_flag &= ~LS_LOOPBACK_MODE;
}
-struct rnidrsp {
- void *buf;
- uint32_t uniqueid;
- struct list_head list;
- uint32_t data;
-};
+static inline int
+lpfc_is_link_up(struct lpfc_hba *phba)
+{
+ return phba->link_state == LPFC_LINK_UP ||
+ phba->link_state == LPFC_CLEAR_LA ||
+ phba->link_state == LPFC_HBA_READY;
+}
#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */
+
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 95fe77e816f8..860a52c090f4 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -39,6 +39,7 @@
#include "lpfc_version.h"
#include "lpfc_compat.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
#define LPFC_DEF_DEVLOSS_TMO 30
#define LPFC_MIN_DEVLOSS_TMO 1
@@ -76,116 +77,156 @@ static ssize_t
lpfc_info_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
+
return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host));
}
static ssize_t
lpfc_serialnum_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber);
}
static ssize_t
lpfc_modeldesc_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc);
}
static ssize_t
lpfc_modelname_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName);
}
static ssize_t
lpfc_programtype_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType);
}
static ssize_t
-lpfc_portnum_show(struct class_device *cdev, char *buf)
+lpfc_vportnum_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port);
}
static ssize_t
lpfc_fwrev_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
char fwrev[32];
+
lpfc_decode_firmware_rev(phba, fwrev, 1);
- return snprintf(buf, PAGE_SIZE, "%s\n",fwrev);
+ return snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", fwrev, phba->sli_rev);
}
static ssize_t
lpfc_hdw_show(struct class_device *cdev, char *buf)
{
char hdw[9];
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
lpfc_vpd_t *vp = &phba->vpd;
+
lpfc_jedec_to_ascii(vp->rev.biuRev, hdw);
return snprintf(buf, PAGE_SIZE, "%s\n", hdw);
}
static ssize_t
lpfc_option_rom_version_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion);
}
static ssize_t
lpfc_state_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- int len = 0;
- switch (phba->hba_state) {
- case LPFC_STATE_UNKNOWN:
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int len = 0;
+
+ switch (phba->link_state) {
+ case LPFC_LINK_UNKNOWN:
case LPFC_WARM_START:
case LPFC_INIT_START:
case LPFC_INIT_MBX_CMDS:
case LPFC_LINK_DOWN:
+ case LPFC_HBA_ERROR:
len += snprintf(buf + len, PAGE_SIZE-len, "Link Down\n");
break;
case LPFC_LINK_UP:
- case LPFC_LOCAL_CFG_LINK:
- len += snprintf(buf + len, PAGE_SIZE-len, "Link Up\n");
- break;
- case LPFC_FLOGI:
- case LPFC_FABRIC_CFG_LINK:
- case LPFC_NS_REG:
- case LPFC_NS_QRY:
- case LPFC_BUILD_DISC_LIST:
- case LPFC_DISC_AUTH:
case LPFC_CLEAR_LA:
- len += snprintf(buf + len, PAGE_SIZE-len,
- "Link Up - Discovery\n");
- break;
case LPFC_HBA_READY:
- len += snprintf(buf + len, PAGE_SIZE-len,
- "Link Up - Ready:\n");
+ len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - \n");
+
+ switch (vport->port_state) {
+ len += snprintf(buf + len, PAGE_SIZE-len,
+ "initializing\n");
+ break;
+ case LPFC_LOCAL_CFG_LINK:
+ len += snprintf(buf + len, PAGE_SIZE-len,
+ "Configuring Link\n");
+ break;
+ case LPFC_FDISC:
+ case LPFC_FLOGI:
+ case LPFC_FABRIC_CFG_LINK:
+ case LPFC_NS_REG:
+ case LPFC_NS_QRY:
+ case LPFC_BUILD_DISC_LIST:
+ case LPFC_DISC_AUTH:
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "Discovery\n");
+ break;
+ case LPFC_VPORT_READY:
+ len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n");
+ break;
+
+ case LPFC_VPORT_FAILED:
+ len += snprintf(buf + len, PAGE_SIZE - len, "Failed\n");
+ break;
+
+ case LPFC_VPORT_UNKNOWN:
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "Unknown\n");
+ break;
+ }
+
if (phba->fc_topology == TOPOLOGY_LOOP) {
- if (phba->fc_flag & FC_PUBLIC_LOOP)
+ if (vport->fc_flag & FC_PUBLIC_LOOP)
len += snprintf(buf + len, PAGE_SIZE-len,
" Public Loop\n");
else
len += snprintf(buf + len, PAGE_SIZE-len,
" Private Loop\n");
} else {
- if (phba->fc_flag & FC_FABRIC)
+ if (vport->fc_flag & FC_FABRIC)
len += snprintf(buf + len, PAGE_SIZE-len,
" Fabric\n");
else
@@ -193,29 +234,32 @@ lpfc_state_show(struct class_device *cdev, char *buf)
" Point-2-Point\n");
}
}
+
return len;
}
static ssize_t
lpfc_num_discovered_ports_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->fc_map_cnt +
- phba->fc_unmap_cnt);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ vport->fc_map_cnt + vport->fc_unmap_cnt);
}
static int
-lpfc_issue_lip(struct Scsi_Host *host)
+lpfc_issue_lip(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *pmboxq;
int mbxstatus = MBXERR_ERROR;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
- (phba->fc_flag & FC_BLOCK_MGMT_IO) ||
- (phba->hba_state != LPFC_HBA_READY))
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
+ (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) ||
+ (vport->port_state != LPFC_VPORT_READY))
return -EPERM;
pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
@@ -238,9 +282,7 @@ lpfc_issue_lip(struct Scsi_Host *host)
}
lpfc_set_loopback_flag(phba);
- if (mbxstatus == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (mbxstatus != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
if (mbxstatus == MBXERR_ERROR)
@@ -320,8 +362,10 @@ lpfc_selective_reset(struct lpfc_hba *phba)
static ssize_t
lpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
int status = -EINVAL;
if (strncmp(buf, "selective", sizeof("selective") - 1) == 0)
@@ -336,23 +380,26 @@ lpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count)
static ssize_t
lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
static ssize_t
lpfc_board_mode_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
char * state;
- if (phba->hba_state == LPFC_HBA_ERROR)
+ if (phba->link_state == LPFC_HBA_ERROR)
state = "error";
- else if (phba->hba_state == LPFC_WARM_START)
+ else if (phba->link_state == LPFC_WARM_START)
state = "warm start";
- else if (phba->hba_state == LPFC_INIT_START)
+ else if (phba->link_state == LPFC_INIT_START)
state = "offline";
else
state = "online";
@@ -363,8 +410,9 @@ lpfc_board_mode_show(struct class_device *cdev, char *buf)
static ssize_t
lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct completion online_compl;
int status=0;
@@ -389,11 +437,166 @@ lpfc_board_mode_store(struct class_device *cdev, const char *buf, size_t count)
return -EIO;
}
+int
+lpfc_get_hba_info(struct lpfc_hba *phba,
+ uint32_t *mxri, uint32_t *axri,
+ uint32_t *mrpi, uint32_t *arpi,
+ uint32_t *mvpi, uint32_t *avpi)
+{
+ struct lpfc_sli *psli = &phba->sli;
+ LPFC_MBOXQ_t *pmboxq;
+ MAILBOX_t *pmb;
+ int rc = 0;
+
+ /*
+ * prevent udev from issuing mailbox commands until the port is
+ * configured.
+ */
+ if (phba->link_state < LPFC_LINK_DOWN ||
+ !phba->mbox_mem_pool ||
+ (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+ return 0;
+
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
+ return 0;
+
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmboxq)
+ return 0;
+ memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+
+ pmb = &pmboxq->mb;
+ pmb->mbxCommand = MBX_READ_CONFIG;
+ pmb->mbxOwner = OWN_HOST;
+ pmboxq->context1 = NULL;
+
+ if ((phba->pport->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = MBX_NOT_FINISHED;
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc != MBX_TIMEOUT)
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return 0;
+ }
+
+ if (mrpi)
+ *mrpi = pmb->un.varRdConfig.max_rpi;
+ if (arpi)
+ *arpi = pmb->un.varRdConfig.avail_rpi;
+ if (mxri)
+ *mxri = pmb->un.varRdConfig.max_xri;
+ if (axri)
+ *axri = pmb->un.varRdConfig.avail_xri;
+ if (mvpi)
+ *mvpi = pmb->un.varRdConfig.max_vpi;
+ if (avpi)
+ *avpi = pmb->un.varRdConfig.avail_vpi;
+
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return 1;
+}
+
+static ssize_t
+lpfc_max_rpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_rpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt, acnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_max_xri_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt;
+
+ if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_xri_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt, acnt;
+
+ if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_max_vpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL))
+ return snprintf(buf, PAGE_SIZE, "%d\n", cnt);
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_used_vpi_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ uint32_t cnt, acnt;
+
+ if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt))
+ return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt));
+ return snprintf(buf, PAGE_SIZE, "Unknown\n");
+}
+
+static ssize_t
+lpfc_npiv_info_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
+ if (!(phba->max_vpi))
+ return snprintf(buf, PAGE_SIZE, "NPIV Not Supported\n");
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ return snprintf(buf, PAGE_SIZE, "NPIV Physical\n");
+ return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi);
+}
+
static ssize_t
lpfc_poll_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll);
}
@@ -402,8 +605,9 @@ static ssize_t
lpfc_poll_store(struct class_device *cdev, const char *buf,
size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
uint32_t creg_val;
uint32_t old_val;
int val=0;
@@ -417,7 +621,7 @@ lpfc_poll_store(struct class_device *cdev, const char *buf,
if ((val & 0x3) != val)
return -EINVAL;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
old_val = phba->cfg_poll;
@@ -432,16 +636,16 @@ lpfc_poll_store(struct class_device *cdev, const char *buf,
lpfc_poll_start_timer(phba);
}
} else if (val != 0x0) {
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EINVAL;
}
if (!(val & DISABLE_FCP_RING_INT) &&
(old_val & DISABLE_FCP_RING_INT))
{
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
del_timer(&phba->fcp_poll_timer);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
creg_val = readl(phba->HCregaddr);
creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING);
writel(creg_val, phba->HCregaddr);
@@ -450,7 +654,7 @@ lpfc_poll_store(struct class_device *cdev, const char *buf,
phba->cfg_poll = val;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return strlen(buf);
}
@@ -459,8 +663,9 @@ lpfc_poll_store(struct class_device *cdev, const char *buf,
static ssize_t \
lpfc_##attr##_show(struct class_device *cdev, char *buf) \
{ \
- struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ struct lpfc_hba *phba = vport->phba;\
int val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%d\n",\
@@ -471,8 +676,9 @@ lpfc_##attr##_show(struct class_device *cdev, char *buf) \
static ssize_t \
lpfc_##attr##_show(struct class_device *cdev, char *buf) \
{ \
- struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ struct lpfc_hba *phba = vport->phba;\
int val = 0;\
val = phba->cfg_##attr;\
return snprintf(buf, PAGE_SIZE, "%#x\n",\
@@ -514,8 +720,9 @@ lpfc_##attr##_set(struct lpfc_hba *phba, int val) \
static ssize_t \
lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \
{ \
- struct Scsi_Host *host = class_to_shost(cdev);\
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;\
+ struct Scsi_Host *shost = class_to_shost(cdev);\
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+ struct lpfc_hba *phba = vport->phba;\
int val=0;\
if (!isdigit(buf[0]))\
return -EINVAL;\
@@ -576,7 +783,7 @@ static CLASS_DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL);
static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL);
static CLASS_DEVICE_ATTR(modelname, S_IRUGO, lpfc_modelname_show, NULL);
static CLASS_DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL);
-static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_portnum_show, NULL);
+static CLASS_DEVICE_ATTR(portnum, S_IRUGO, lpfc_vportnum_show, NULL);
static CLASS_DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL);
static CLASS_DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL);
static CLASS_DEVICE_ATTR(state, S_IRUGO, lpfc_state_show, NULL);
@@ -592,6 +799,13 @@ static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
+static CLASS_DEVICE_ATTR(max_vpi, S_IRUGO, lpfc_max_vpi_show, NULL);
+static CLASS_DEVICE_ATTR(used_vpi, S_IRUGO, lpfc_used_vpi_show, NULL);
+static CLASS_DEVICE_ATTR(max_rpi, S_IRUGO, lpfc_max_rpi_show, NULL);
+static CLASS_DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL);
+static CLASS_DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL);
+static CLASS_DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL);
+static CLASS_DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL);
static char *lpfc_soft_wwn_key = "C99G71SL8032A";
@@ -600,8 +814,9 @@ static ssize_t
lpfc_soft_wwn_enable_store(struct class_device *cdev, const char *buf,
size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
unsigned int cnt = count;
/*
@@ -634,8 +849,10 @@ static CLASS_DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL,
static ssize_t
lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+
return snprintf(buf, PAGE_SIZE, "0x%llx\n",
(unsigned long long)phba->cfg_soft_wwpn);
}
@@ -644,8 +861,9 @@ lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
static ssize_t
lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct completion online_compl;
int stat1=0, stat2=0;
unsigned int i, j, cnt=count;
@@ -680,9 +898,9 @@ lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
}
}
phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
- fc_host_port_name(host) = phba->cfg_soft_wwpn;
+ fc_host_port_name(shost) = phba->cfg_soft_wwpn;
if (phba->cfg_soft_wwnn)
- fc_host_node_name(host) = phba->cfg_soft_wwnn;
+ fc_host_node_name(shost) = phba->cfg_soft_wwnn;
dev_printk(KERN_NOTICE, &phba->pcidev->dev,
"lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
@@ -777,6 +995,15 @@ MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:"
static CLASS_DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR,
lpfc_poll_show, lpfc_poll_store);
+int lpfc_sli_mode = 0;
+module_param(lpfc_sli_mode, int, 0);
+MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:"
+ " 0 - auto (SLI-3 if supported),"
+ " 2 - select SLI-2 even on SLI-3 capable HBAs,"
+ " 3 - select SLI-3");
+
+LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
+
/*
# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
# until the timer expires. Value range is [0,255]. Default value is 30.
@@ -790,8 +1017,9 @@ MODULE_PARM_DESC(lpfc_nodev_tmo,
static ssize_t
lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
int val = 0;
val = phba->cfg_devloss_tmo;
return snprintf(buf, PAGE_SIZE, "%d\n",
@@ -832,13 +1060,19 @@ lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
static void
lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport;
+ struct Scsi_Host *shost;
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp)
- if (ndlp->rport)
- ndlp->rport->dev_loss_tmo = phba->cfg_devloss_tmo;
- spin_unlock_irq(phba->host->host_lock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ shost = lpfc_shost_from_vport(vport);
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+ if (ndlp->rport)
+ ndlp->rport->dev_loss_tmo =
+ phba->cfg_devloss_tmo;
+ spin_unlock_irq(shost->host_lock);
+ }
}
static int
@@ -946,6 +1180,33 @@ LPFC_ATTR_R(hba_queue_depth, 8192, 32, 8192,
"Max number of FCP commands we can queue to a lpfc HBA");
/*
+# peer_port_login: This parameter allows/prevents logins
+# between peer ports hosted on the same physical port.
+# When this parameter is set 0 peer ports of same physical port
+# are not allowed to login to each other.
+# When this parameter is set 1 peer ports of same physical port
+# are allowed to login to each other.
+# Default value of this parameter is 0.
+*/
+LPFC_ATTR_R(peer_port_login, 0, 0, 1,
+ "Allow peer ports on the same physical port to login to each "
+ "other.");
+
+/*
+# vport_restrict_login: This parameter allows/prevents logins
+# between Virtual Ports and remote initiators.
+# When this parameter is not set (0) Virtual Ports will accept PLOGIs from
+# other initiators and will attempt to PLOGI all remote ports.
+# When this parameter is set (1) Virtual Ports will reject PLOGIs from
+# remote ports and will not attempt to PLOGI to other initiators.
+# This parameter does not restrict to the physical port.
+# This parameter does not restrict logins to Fabric resident remote ports.
+# Default value of this parameter is 1.
+*/
+LPFC_ATTR_RW(vport_restrict_login, 1, 0, 1,
+ "Restrict virtual ports login to remote initiators.");
+
+/*
# Some disk devices have a "select ID" or "select Target" capability.
# From a protocol standpoint "select ID" usually means select the
# Fibre channel "ALPA". In the FC-AL Profile there is an "informative
@@ -1088,7 +1349,8 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible");
-struct class_device_attribute *lpfc_host_attrs[] = {
+
+struct class_device_attribute *lpfc_hba_attrs[] = {
&class_device_attr_info,
&class_device_attr_serialnum,
&class_device_attr_modeldesc,
@@ -1104,6 +1366,8 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_log_verbose,
&class_device_attr_lpfc_lun_queue_depth,
&class_device_attr_lpfc_hba_queue_depth,
+ &class_device_attr_lpfc_peer_port_login,
+ &class_device_attr_lpfc_vport_restrict_login,
&class_device_attr_lpfc_nodev_tmo,
&class_device_attr_lpfc_devloss_tmo,
&class_device_attr_lpfc_fcp_class,
@@ -1119,9 +1383,17 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_multi_ring_type,
&class_device_attr_lpfc_fdmi_on,
&class_device_attr_lpfc_max_luns,
+ &class_device_attr_lpfc_npiv_enable,
&class_device_attr_nport_evt_cnt,
&class_device_attr_management_version,
&class_device_attr_board_mode,
+ &class_device_attr_max_vpi,
+ &class_device_attr_used_vpi,
+ &class_device_attr_max_rpi,
+ &class_device_attr_used_rpi,
+ &class_device_attr_max_xri,
+ &class_device_attr_used_xri,
+ &class_device_attr_npiv_info,
&class_device_attr_issue_reset,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
@@ -1133,12 +1405,15 @@ struct class_device_attribute *lpfc_host_attrs[] = {
};
static ssize_t
-sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
size_t buf_off;
- struct Scsi_Host *host = class_to_shost(container_of(kobj,
- struct class_device, kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
if ((off + count) > FF_REG_AREA_SIZE)
return -ERANGE;
@@ -1148,30 +1423,31 @@ sysfs_ctlreg_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
if (off % 4 || count % 4 || (unsigned long)buf % 4)
return -EINVAL;
- spin_lock_irq(phba->host->host_lock);
-
- if (!(phba->fc_flag & FC_OFFLINE_MODE)) {
- spin_unlock_irq(phba->host->host_lock);
+ if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
return -EPERM;
}
+ spin_lock_irq(&phba->hbalock);
for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t))
writel(*((uint32_t *)(buf + buf_off)),
phba->ctrl_regs_memmap_p + off + buf_off);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
static ssize_t
-sysfs_ctlreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+sysfs_ctlreg_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
size_t buf_off;
uint32_t * tmp_ptr;
- struct Scsi_Host *host = class_to_shost(container_of(kobj,
- struct class_device, kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
if (off > FF_REG_AREA_SIZE)
return -ERANGE;
@@ -1184,14 +1460,14 @@ sysfs_ctlreg_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
if (off % 4 || count % 4 || (unsigned long)buf % 4)
return -EINVAL;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) {
tmp_ptr = (uint32_t *)(buf + buf_off);
*tmp_ptr = readl(phba->ctrl_regs_memmap_p + off + buf_off);
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
@@ -1200,7 +1476,6 @@ static struct bin_attribute sysfs_ctlreg_attr = {
.attr = {
.name = "ctlreg",
.mode = S_IRUSR | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 256,
.read = sysfs_ctlreg_read,
@@ -1209,7 +1484,7 @@ static struct bin_attribute sysfs_ctlreg_attr = {
static void
-sysfs_mbox_idle (struct lpfc_hba * phba)
+sysfs_mbox_idle(struct lpfc_hba *phba)
{
phba->sysfs_mbox.state = SMBOX_IDLE;
phba->sysfs_mbox.offset = 0;
@@ -1222,12 +1497,15 @@ sysfs_mbox_idle (struct lpfc_hba * phba)
}
static ssize_t
-sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+sysfs_mbox_write(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
- struct Scsi_Host * host =
- class_to_shost(container_of(kobj, struct class_device, kobj));
- struct lpfc_hba * phba = (struct lpfc_hba*)host->hostdata;
- struct lpfcMboxq * mbox = NULL;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfcMboxq *mbox = NULL;
if ((count + off) > MAILBOX_CMD_SIZE)
return -ERANGE;
@@ -1245,7 +1523,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
memset(mbox, 0, sizeof (LPFC_MBOXQ_t));
}
- spin_lock_irq(host->host_lock);
+ spin_lock_irq(&phba->hbalock);
if (off == 0) {
if (phba->sysfs_mbox.mbox)
@@ -1256,9 +1534,9 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
} else {
if (phba->sysfs_mbox.state != SMBOX_WRITING ||
phba->sysfs_mbox.offset != off ||
- phba->sysfs_mbox.mbox == NULL ) {
+ phba->sysfs_mbox.mbox == NULL) {
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EAGAIN;
}
}
@@ -1268,18 +1546,20 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
phba->sysfs_mbox.offset = off + count;
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
static ssize_t
-sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
- struct Scsi_Host *host =
- class_to_shost(container_of(kobj, struct class_device,
- kobj));
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct class_device *cdev = container_of(kobj, struct class_device,
+ kobj);
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
int rc;
if (off > MAILBOX_CMD_SIZE)
@@ -1294,7 +1574,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
if (off && count == 0)
return 0;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
if (off == 0 &&
phba->sysfs_mbox.state == SMBOX_WRITING &&
@@ -1317,12 +1597,12 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
case MBX_SET_MASK:
case MBX_SET_SLIM:
case MBX_SET_DEBUG:
- if (!(phba->fc_flag & FC_OFFLINE_MODE)) {
+ if (!(vport->fc_flag & FC_OFFLINE_MODE)) {
printk(KERN_WARNING "mbox_read:Command 0x%x "
"is illegal in on-line state\n",
phba->sysfs_mbox.mbox->mb.mbxCommand);
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EPERM;
}
case MBX_LOAD_SM:
@@ -1352,48 +1632,48 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
printk(KERN_WARNING "mbox_read: Illegal Command 0x%x\n",
phba->sysfs_mbox.mbox->mb.mbxCommand);
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EPERM;
default:
printk(KERN_WARNING "mbox_read: Unknown Command 0x%x\n",
phba->sysfs_mbox.mbox->mb.mbxCommand);
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EPERM;
}
- if (phba->fc_flag & FC_BLOCK_MGMT_IO) {
+ phba->sysfs_mbox.mbox->vport = vport;
+
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) {
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EAGAIN;
}
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE))){
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli_issue_mbox (phba,
phba->sysfs_mbox.mbox,
MBX_POLL);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
} else {
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli_issue_mbox_wait (phba,
phba->sysfs_mbox.mbox,
lpfc_mbox_tmo_val(phba,
phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
}
if (rc != MBX_SUCCESS) {
if (rc == MBX_TIMEOUT) {
- phba->sysfs_mbox.mbox->mbox_cmpl =
- lpfc_sli_def_mbox_cmpl;
phba->sysfs_mbox.mbox = NULL;
}
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
}
phba->sysfs_mbox.state = SMBOX_READING;
@@ -1402,7 +1682,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
phba->sysfs_mbox.state != SMBOX_READING) {
printk(KERN_WARNING "mbox_read: Bad State\n");
sysfs_mbox_idle(phba);
- spin_unlock_irq(host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return -EAGAIN;
}
@@ -1413,7 +1693,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
if (phba->sysfs_mbox.offset == MAILBOX_CMD_SIZE)
sysfs_mbox_idle(phba);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return count;
}
@@ -1422,7 +1702,6 @@ static struct bin_attribute sysfs_mbox_attr = {
.attr = {
.name = "mbox",
.mode = S_IRUSR | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = MAILBOX_CMD_SIZE,
.read = sysfs_mbox_read,
@@ -1430,35 +1709,35 @@ static struct bin_attribute sysfs_mbox_attr = {
};
int
-lpfc_alloc_sysfs_attr(struct lpfc_hba *phba)
+lpfc_alloc_sysfs_attr(struct lpfc_vport *vport)
{
- struct Scsi_Host *host = phba->host;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
int error;
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &sysfs_ctlreg_attr);
+ error = sysfs_create_bin_file(&shost->shost_classdev.kobj,
+ &sysfs_ctlreg_attr);
if (error)
goto out;
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &sysfs_mbox_attr);
+ error = sysfs_create_bin_file(&shost->shost_classdev.kobj,
+ &sysfs_mbox_attr);
if (error)
goto out_remove_ctlreg_attr;
return 0;
out_remove_ctlreg_attr:
- sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr);
+ sysfs_remove_bin_file(&shost->shost_classdev.kobj, &sysfs_ctlreg_attr);
out:
return error;
}
void
-lpfc_free_sysfs_attr(struct lpfc_hba *phba)
+lpfc_free_sysfs_attr(struct lpfc_vport *vport)
{
- struct Scsi_Host *host = phba->host;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_mbox_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj, &sysfs_ctlreg_attr);
+ sysfs_remove_bin_file(&shost->shost_classdev.kobj, &sysfs_mbox_attr);
+ sysfs_remove_bin_file(&shost->shost_classdev.kobj, &sysfs_ctlreg_attr);
}
@@ -1469,26 +1748,30 @@ lpfc_free_sysfs_attr(struct lpfc_hba *phba)
static void
lpfc_get_host_port_id(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+
/* note: fc_myDID already in cpu endianness */
- fc_host_port_id(shost) = phba->fc_myDID;
+ fc_host_port_id(shost) = vport->fc_myDID;
}
static void
lpfc_get_host_port_type(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
spin_lock_irq(shost->host_lock);
- if (phba->hba_state == LPFC_HBA_READY) {
+ if (vport->port_type == LPFC_NPIV_PORT) {
+ fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
+ } else if (lpfc_is_link_up(phba)) {
if (phba->fc_topology == TOPOLOGY_LOOP) {
- if (phba->fc_flag & FC_PUBLIC_LOOP)
+ if (vport->fc_flag & FC_PUBLIC_LOOP)
fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
else
fc_host_port_type(shost) = FC_PORTTYPE_LPORT;
} else {
- if (phba->fc_flag & FC_FABRIC)
+ if (vport->fc_flag & FC_FABRIC)
fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
else
fc_host_port_type(shost) = FC_PORTTYPE_PTP;
@@ -1502,29 +1785,20 @@ lpfc_get_host_port_type(struct Scsi_Host *shost)
static void
lpfc_get_host_port_state(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
spin_lock_irq(shost->host_lock);
- if (phba->fc_flag & FC_OFFLINE_MODE)
+ if (vport->fc_flag & FC_OFFLINE_MODE)
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
else {
- switch (phba->hba_state) {
- case LPFC_STATE_UNKNOWN:
- case LPFC_WARM_START:
- case LPFC_INIT_START:
- case LPFC_INIT_MBX_CMDS:
+ switch (phba->link_state) {
+ case LPFC_LINK_UNKNOWN:
case LPFC_LINK_DOWN:
fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
break;
case LPFC_LINK_UP:
- case LPFC_LOCAL_CFG_LINK:
- case LPFC_FLOGI:
- case LPFC_FABRIC_CFG_LINK:
- case LPFC_NS_REG:
- case LPFC_NS_QRY:
- case LPFC_BUILD_DISC_LIST:
- case LPFC_DISC_AUTH:
case LPFC_CLEAR_LA:
case LPFC_HBA_READY:
/* Links up, beyond this port_type reports state */
@@ -1545,11 +1819,12 @@ lpfc_get_host_port_state(struct Scsi_Host *shost)
static void
lpfc_get_host_speed(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
spin_lock_irq(shost->host_lock);
- if (phba->hba_state == LPFC_HBA_READY) {
+ if (lpfc_is_link_up(phba)) {
switch(phba->fc_linkspeed) {
case LA_1GHZ_LINK:
fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
@@ -1575,39 +1850,31 @@ lpfc_get_host_speed(struct Scsi_Host *shost)
static void
lpfc_get_host_fabric_name (struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
u64 node_name;
spin_lock_irq(shost->host_lock);
- if ((phba->fc_flag & FC_FABRIC) ||
+ if ((vport->fc_flag & FC_FABRIC) ||
((phba->fc_topology == TOPOLOGY_LOOP) &&
- (phba->fc_flag & FC_PUBLIC_LOOP)))
+ (vport->fc_flag & FC_PUBLIC_LOOP)))
node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
else
/* fabric is local port if there is no F/FL_Port */
- node_name = wwn_to_u64(phba->fc_nodename.u.wwn);
+ node_name = wwn_to_u64(vport->fc_nodename.u.wwn);
spin_unlock_irq(shost->host_lock);
fc_host_fabric_name(shost) = node_name;
}
-static void
-lpfc_get_host_symbolic_name (struct Scsi_Host *shost)
-{
- struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
-
- spin_lock_irq(shost->host_lock);
- lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
- spin_unlock_irq(shost->host_lock);
-}
-
static struct fc_host_statistics *
lpfc_get_stats(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct fc_host_statistics *hs = &phba->link_stats;
struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
LPFC_MBOXQ_t *pmboxq;
@@ -1615,7 +1882,16 @@ lpfc_get_stats(struct Scsi_Host *shost)
unsigned long seconds;
int rc = 0;
- if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+ /*
+ * prevent udev from issuing mailbox commands until the port is
+ * configured.
+ */
+ if (phba->link_state < LPFC_LINK_DOWN ||
+ !phba->mbox_mem_pool ||
+ (phba->sli.sli_flag & LPFC_SLI2_ACTIVE) == 0)
+ return NULL;
+
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
return NULL;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -1627,17 +1903,16 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmb->mbxCommand = MBX_READ_STATUS;
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
}
@@ -1653,18 +1928,17 @@ lpfc_get_stats(struct Scsi_Host *shost)
pmb->mbxCommand = MBX_READ_LNK_STAT;
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
- mempool_free( pmboxq, phba->mbox_mem_pool);
+ if (rc != MBX_TIMEOUT)
+ mempool_free(pmboxq, phba->mbox_mem_pool);
return NULL;
}
@@ -1711,14 +1985,15 @@ lpfc_get_stats(struct Scsi_Host *shost)
static void
lpfc_reset_stats(struct Scsi_Host *shost)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
- struct lpfc_sli *psli = &phba->sli;
- struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_lnk_stat *lso = &psli->lnk_stat_offsets;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
int rc = 0;
- if (phba->fc_flag & FC_BLOCK_MGMT_IO)
+ if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)
return;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -1731,17 +2006,16 @@ lpfc_reset_stats(struct Scsi_Host *shost)
pmb->mbxOwner = OWN_HOST;
pmb->un.varWords[0] = 0x1; /* reset request */
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (rc != MBX_TIMEOUT)
mempool_free(pmboxq, phba->mbox_mem_pool);
return;
}
@@ -1750,17 +2024,16 @@ lpfc_reset_stats(struct Scsi_Host *shost)
pmb->mbxCommand = MBX_READ_LNK_STAT;
pmb->mbxOwner = OWN_HOST;
pmboxq->context1 = NULL;
+ pmboxq->vport = vport;
- if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ if ((vport->fc_flag & FC_OFFLINE_MODE) ||
(!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
else
rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
if (rc != MBX_SUCCESS) {
- if (rc == MBX_TIMEOUT)
- pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- else
+ if (rc != MBX_TIMEOUT)
mempool_free( pmboxq, phba->mbox_mem_pool);
return;
}
@@ -1789,13 +2062,13 @@ lpfc_reset_stats(struct Scsi_Host *shost)
static struct lpfc_nodelist *
lpfc_get_node_by_target(struct scsi_target *starget)
{
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
- struct lpfc_hba *phba = (struct lpfc_hba *) shost->hostdata;
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
struct lpfc_nodelist *ndlp;
spin_lock_irq(shost->host_lock);
/* Search for this, mapped, target ID */
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
starget->id == ndlp->nlp_sid) {
spin_unlock_irq(shost->host_lock);
@@ -1885,8 +2158,66 @@ struct fc_function_template lpfc_transport_functions = {
.get_host_fabric_name = lpfc_get_host_fabric_name,
.show_host_fabric_name = 1,
- .get_host_symbolic_name = lpfc_get_host_symbolic_name,
- .show_host_symbolic_name = 1,
+ /*
+ * The LPFC driver treats linkdown handling as target loss events
+ * so there are no sysfs handlers for link_down_tmo.
+ */
+
+ .get_fc_host_stats = lpfc_get_stats,
+ .reset_fc_host_stats = lpfc_reset_stats,
+
+ .dd_fcrport_size = sizeof(struct lpfc_rport_data),
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+
+ .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+
+ .get_starget_port_id = lpfc_get_starget_port_id,
+ .show_starget_port_id = 1,
+
+ .get_starget_node_name = lpfc_get_starget_node_name,
+ .show_starget_node_name = 1,
+
+ .get_starget_port_name = lpfc_get_starget_port_name,
+ .show_starget_port_name = 1,
+
+ .issue_fc_host_lip = lpfc_issue_lip,
+ .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
+ .terminate_rport_io = lpfc_terminate_rport_io,
+
+ .vport_create = lpfc_vport_create,
+ .vport_delete = lpfc_vport_delete,
+ .dd_fcvport_size = sizeof(struct lpfc_vport *),
+};
+
+struct fc_function_template lpfc_vport_transport_functions = {
+ /* fixed attributes the driver supports */
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+
+ /* dynamic attributes the driver supports */
+ .get_host_port_id = lpfc_get_host_port_id,
+ .show_host_port_id = 1,
+
+ .get_host_port_type = lpfc_get_host_port_type,
+ .show_host_port_type = 1,
+
+ .get_host_port_state = lpfc_get_host_port_state,
+ .show_host_port_state = 1,
+
+ /* active_fc4s is shown but doesn't change (thus no get function) */
+ .show_host_active_fc4s = 1,
+
+ .get_host_speed = lpfc_get_host_speed,
+ .show_host_speed = 1,
+
+ .get_host_fabric_name = lpfc_get_host_fabric_name,
+ .show_host_fabric_name = 1,
/*
* The LPFC driver treats linkdown handling as target loss events
@@ -1915,6 +2246,8 @@ struct fc_function_template lpfc_transport_functions = {
.issue_fc_host_lip = lpfc_issue_lip,
.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
.terminate_rport_io = lpfc_terminate_rport_io,
+
+ .vport_disable = lpfc_vport_disable,
};
void
@@ -1937,6 +2270,9 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
lpfc_max_luns_init(phba, lpfc_max_luns);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
+ lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
+ lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
+ lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
lpfc_use_msi_init(phba, lpfc_use_msi);
lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index b8c2a8862d8c..e19d1a746586 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -23,92 +23,114 @@ typedef int (*node_filter)(struct lpfc_nodelist *ndlp, void *param);
struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
struct lpfc_dmabuf *mp);
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport);
void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
+int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int);
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
-int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *,
- uint32_t);
-void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
-void lpfc_unreg_did(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
+int lpfc_reg_login(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *,
+ LPFC_MBOXQ_t *, uint32_t);
+void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_reg_vpi(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *);
+void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
-
+void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
int lpfc_linkdown(struct lpfc_hba *);
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
+void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
-void lpfc_dequeue_node(struct lpfc_hba *, struct lpfc_nodelist *);
-void lpfc_nlp_set_state(struct lpfc_hba *, struct lpfc_nodelist *, int);
-void lpfc_drop_node(struct lpfc_hba *, struct lpfc_nodelist *);
-void lpfc_set_disctmo(struct lpfc_hba *);
-int lpfc_can_disctmo(struct lpfc_hba *);
-int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *);
+void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int);
+void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *);
+void lpfc_set_disctmo(struct lpfc_vport *);
+int lpfc_can_disctmo(struct lpfc_vport *);
+int lpfc_unreg_rpi(struct lpfc_vport *, struct lpfc_nodelist *);
+void lpfc_unreg_all_rpis(struct lpfc_vport *);
+void lpfc_unreg_default_rpis(struct lpfc_vport *);
+void lpfc_issue_reg_vpi(struct lpfc_hba *, struct lpfc_vport *);
+
int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
- struct lpfc_iocbq *, struct lpfc_nodelist *);
-void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
+ struct lpfc_iocbq *, struct lpfc_nodelist *);
+void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t);
struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *);
int lpfc_nlp_put(struct lpfc_nodelist *);
-struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
-void lpfc_disc_list_loopmap(struct lpfc_hba *);
-void lpfc_disc_start(struct lpfc_hba *);
-void lpfc_disc_flush_list(struct lpfc_hba *);
+struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t);
+void lpfc_disc_list_loopmap(struct lpfc_vport *);
+void lpfc_disc_start(struct lpfc_vport *);
+void lpfc_disc_flush_list(struct lpfc_vport *);
+void lpfc_cleanup_discovery_resources(struct lpfc_vport *);
void lpfc_disc_timeout(unsigned long);
-struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
-struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
+struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
+struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t);
+void lpfc_worker_wake_up(struct lpfc_hba *);
int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
int lpfc_do_work(void *);
-int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
+int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *,
uint32_t);
-int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
+void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *,
+ struct lpfc_nodelist *);
+void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *);
+int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *,
struct serv_parm *, uint32_t);
-int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp);
+int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *);
+int lpfc_els_chk_latt(struct lpfc_vport *);
int lpfc_els_abort_flogi(struct lpfc_hba *);
-int lpfc_initial_flogi(struct lpfc_hba *);
-int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
-int lpfc_issue_els_prli(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
-int lpfc_issue_els_adisc(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
-int lpfc_issue_els_logo(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
-int lpfc_issue_els_scr(struct lpfc_hba *, uint32_t, uint8_t);
+int lpfc_initial_flogi(struct lpfc_vport *);
+int lpfc_initial_fdisc(struct lpfc_vport *);
+int lpfc_issue_els_fdisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t);
+int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t);
+int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *);
+int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t);
int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
-int lpfc_els_rsp_acc(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
+int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
-int lpfc_els_rsp_reject(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
- struct lpfc_nodelist *);
-int lpfc_els_rsp_adisc_acc(struct lpfc_hba *, struct lpfc_iocbq *,
+int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
+ struct lpfc_nodelist *, LPFC_MBOXQ_t *);
+int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
-int lpfc_els_rsp_prli_acc(struct lpfc_hba *, struct lpfc_iocbq *,
+int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *,
struct lpfc_nodelist *);
-void lpfc_cancel_retry_delay_tmo(struct lpfc_hba *, struct lpfc_nodelist *);
+void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *);
void lpfc_els_retry_delay(unsigned long);
void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
+void lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *);
void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
-int lpfc_els_handle_rscn(struct lpfc_hba *);
-int lpfc_els_flush_rscn(struct lpfc_hba *);
-int lpfc_rscn_payload_check(struct lpfc_hba *, uint32_t);
-void lpfc_els_flush_cmd(struct lpfc_hba *);
-int lpfc_els_disc_adisc(struct lpfc_hba *);
-int lpfc_els_disc_plogi(struct lpfc_hba *);
+int lpfc_els_handle_rscn(struct lpfc_vport *);
+void lpfc_els_flush_rscn(struct lpfc_vport *);
+int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t);
+void lpfc_els_flush_cmd(struct lpfc_vport *);
+int lpfc_els_disc_adisc(struct lpfc_vport *);
+int lpfc_els_disc_plogi(struct lpfc_vport *);
void lpfc_els_timeout(unsigned long);
-void lpfc_els_timeout_handler(struct lpfc_hba *);
+void lpfc_els_timeout_handler(struct lpfc_vport *);
+void lpfc_hb_timeout(unsigned long);
+void lpfc_hb_timeout_handler(struct lpfc_hba *);
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
-int lpfc_ns_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
-int lpfc_fdmi_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
+int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t);
+int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int);
void lpfc_fdmi_tmo(unsigned long);
-void lpfc_fdmi_tmo_handler(struct lpfc_hba *);
+void lpfc_fdmi_timeout_handler(struct lpfc_vport *vport);
int lpfc_config_port_prep(struct lpfc_hba *);
int lpfc_config_port_post(struct lpfc_hba *);
@@ -136,16 +158,23 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
+void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
+void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t ,
+ LPFC_MBOXQ_t *);
+struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
+
int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
+void lpfc_stop_vport_timers(struct lpfc_vport *);
void lpfc_poll_timeout(unsigned long ptr);
void lpfc_poll_start_timer(struct lpfc_hba * phba);
void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
+void __lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
void lpfc_reset_barrier(struct lpfc_hba * phba);
@@ -154,6 +183,7 @@ int lpfc_sli_brdkill(struct lpfc_hba *);
int lpfc_sli_brdreset(struct lpfc_hba *);
int lpfc_sli_brdrestart(struct lpfc_hba *);
int lpfc_sli_hba_setup(struct lpfc_hba *);
+int lpfc_sli_host_down(struct lpfc_vport *);
int lpfc_sli_hba_down(struct lpfc_hba *);
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
int lpfc_sli_handle_mb_event(struct lpfc_hba *);
@@ -164,27 +194,36 @@ void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *, uint32_t);
void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
-int lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
+void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_dmabuf *);
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
struct lpfc_sli_ring *,
dma_addr_t);
+int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
+int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
+void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
+struct hbq_dmabuf *lpfc_sli_hbqbuf_find(struct lpfc_hba *, uint32_t);
+int lpfc_sli_hbq_size(void);
int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
struct lpfc_iocbq *);
int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
- uint64_t, lpfc_ctx_cmd);
+ uint64_t, lpfc_ctx_cmd);
int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
- uint64_t, uint32_t, lpfc_ctx_cmd);
+ uint64_t, uint32_t, lpfc_ctx_cmd);
void lpfc_mbox_timeout(unsigned long);
void lpfc_mbox_timeout_handler(struct lpfc_hba *);
-struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t);
-struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, struct lpfc_name *);
+struct lpfc_nodelist *__lpfc_find_node(struct lpfc_vport *, node_filter,
+ void *);
+struct lpfc_nodelist *lpfc_find_node(struct lpfc_vport *, node_filter, void *);
+struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t);
+struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *,
+ struct lpfc_name *);
int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
- uint32_t timeout);
+ uint32_t timeout);
int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
struct lpfc_sli_ring * pring,
@@ -195,25 +234,56 @@ void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba,
struct lpfc_iocbq * cmdiocb,
struct lpfc_iocbq * rspiocb);
+void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *);
+void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t);
+void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *);
+
void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
+void __lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
+void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
/* Function prototypes. */
const char* lpfc_info(struct Scsi_Host *);
-void lpfc_scan_start(struct Scsi_Host *);
int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
void lpfc_get_cfgparam(struct lpfc_hba *);
-int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
-void lpfc_free_sysfs_attr(struct lpfc_hba *);
-extern struct class_device_attribute *lpfc_host_attrs[];
+int lpfc_alloc_sysfs_attr(struct lpfc_vport *);
+void lpfc_free_sysfs_attr(struct lpfc_vport *);
+extern struct class_device_attribute *lpfc_hba_attrs[];
extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions;
+extern struct fc_function_template lpfc_vport_transport_functions;
+extern int lpfc_sli_mode;
-void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
+int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t);
void lpfc_terminate_rport_io(struct fc_rport *);
void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
+struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct fc_vport *);
+int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable);
+void lpfc_mbx_unreg_vpi(struct lpfc_vport *);
+void destroy_port(struct lpfc_vport *);
+int lpfc_get_instance(void);
+void lpfc_host_attrib_init(struct Scsi_Host *);
+
+extern void lpfc_debugfs_initialize(struct lpfc_vport *);
+extern void lpfc_debugfs_terminate(struct lpfc_vport *);
+extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t,
+ uint32_t, uint32_t);
+
+/* Interface exported by fabric iocb scheduler */
+int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
+void lpfc_fabric_abort_vport(struct lpfc_vport *);
+void lpfc_fabric_abort_nport(struct lpfc_nodelist *);
+void lpfc_fabric_abort_hba(struct lpfc_hba *);
+void lpfc_fabric_abort_flogi(struct lpfc_hba *);
+void lpfc_fabric_block_timeout(unsigned long);
+void lpfc_unblock_fabric_iocbs(struct lpfc_hba *);
+void lpfc_adjust_queue_depth(struct lpfc_hba *);
+void lpfc_ramp_down_queue_handler(struct lpfc_hba *);
+void lpfc_ramp_up_queue_handler(struct lpfc_hba *);
+
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5
#define HBA_EVENT_LINK_UP 2
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index 34a9e3bb2614..ae9d6f385a6c 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -40,6 +40,8 @@
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
#include "lpfc_version.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
#define HBA_PORTSPEED_UNKNOWN 0 /* Unknown - transceiver
* incapable of reporting */
@@ -58,25 +60,69 @@ static char *lpfc_release_version = LPFC_DRIVER_VERSION;
/*
* lpfc_ct_unsol_event
*/
+static void
+lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+ struct lpfc_dmabuf *mp, uint32_t size)
+{
+ if (!mp) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no buffer, "
+ "piocbq = %p, status = x%x, mp = %p, size = %d\n",
+ __FUNCTION__, __LINE__,
+ piocbq, piocbq->iocb.ulpStatus, mp, size);
+ }
+
+ printk(KERN_ERR "%s (%d): Ignoring unsolicted CT piocbq = %p, "
+ "buffer = %p, size = %d, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ piocbq, mp, size,
+ piocbq->iocb.ulpStatus);
+
+}
+
+static void
+lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq,
+ struct lpfc_dmabuf *mp, uint32_t size)
+{
+ if (!mp) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no "
+ "HBQ buffer, piocbq = %p, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ piocbq, piocbq->iocb.ulpStatus);
+ } else {
+ lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
+ printk(KERN_ERR "%s (%d): Ignoring unsolicted CT "
+ "piocbq = %p, buffer = %p, size = %d, "
+ "status = x%x\n",
+ __FUNCTION__, __LINE__,
+ piocbq, mp, size, piocbq->iocb.ulpStatus);
+ }
+}
+
void
-lpfc_ct_unsol_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocbq)
+lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocbq)
{
- struct lpfc_iocbq *next_piocbq;
- struct lpfc_dmabuf *pmbuf = NULL;
- struct lpfc_dmabuf *matp, *next_matp;
- uint32_t ctx = 0, size = 0, cnt = 0;
+ struct lpfc_dmabuf *mp = NULL;
IOCB_t *icmd = &piocbq->iocb;
- IOCB_t *save_icmd = icmd;
- int i, go_exit = 0;
- struct list_head head;
+ int i;
+ struct lpfc_iocbq *iocbq;
+ dma_addr_t paddr;
+ uint32_t size;
+ struct lpfc_dmabuf *bdeBuf1 = piocbq->context2;
+ struct lpfc_dmabuf *bdeBuf2 = piocbq->context3;
+
+ piocbq->context2 = NULL;
+ piocbq->context3 = NULL;
- if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) {
+ lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+ } else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
/* Not enough posted buffers; Try posting more buffers */
phba->fc_stat.NoRcvBuf++;
- lpfc_post_buffer(phba, pring, 0, 1);
+ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
+ lpfc_post_buffer(phba, pring, 0, 1);
return;
}
@@ -86,66 +132,56 @@ lpfc_ct_unsol_event(struct lpfc_hba * phba,
if (icmd->ulpBdeCount == 0)
return;
- INIT_LIST_HEAD(&head);
- list_add_tail(&head, &piocbq->list);
-
- list_for_each_entry_safe(piocbq, next_piocbq, &head, list) {
- icmd = &piocbq->iocb;
- if (ctx == 0)
- ctx = (uint32_t) (icmd->ulpContext);
- if (icmd->ulpBdeCount == 0)
- continue;
-
- for (i = 0; i < icmd->ulpBdeCount; i++) {
- matp = lpfc_sli_ringpostbuf_get(phba, pring,
- getPaddr(icmd->un.
- cont64[i].
- addrHigh,
- icmd->un.
- cont64[i].
- addrLow));
- if (!matp) {
- /* Insert lpfc log message here */
- lpfc_post_buffer(phba, pring, cnt, 1);
- go_exit = 1;
- goto ct_unsol_event_exit_piocbq;
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ list_for_each_entry(iocbq, &piocbq->list, list) {
+ icmd = &iocbq->iocb;
+ if (icmd->ulpBdeCount == 0) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no "
+ "BDE, iocbq = %p, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ iocbq, iocbq->iocb.ulpStatus);
+ continue;
}
- /* Typically for Unsolicited CT requests */
- if (!pmbuf) {
- pmbuf = matp;
- INIT_LIST_HEAD(&pmbuf->list);
- } else
- list_add_tail(&matp->list, &pmbuf->list);
-
- size += icmd->un.cont64[i].tus.f.bdeSize;
- cnt++;
+ size = icmd->un.cont64[0].tus.f.bdeSize;
+ lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf1, size);
+ lpfc_in_buf_free(phba, bdeBuf1);
+ if (icmd->ulpBdeCount == 2) {
+ lpfc_ct_ignore_hbq_buffer(phba, piocbq, bdeBuf2,
+ size);
+ lpfc_in_buf_free(phba, bdeBuf2);
+ }
}
+ } else {
+ struct lpfc_iocbq *next;
+
+ list_for_each_entry_safe(iocbq, next, &piocbq->list, list) {
+ icmd = &iocbq->iocb;
+ if (icmd->ulpBdeCount == 0) {
+ printk(KERN_ERR "%s (%d): Unsolited CT, no "
+ "BDE, iocbq = %p, status = x%x\n",
+ __FUNCTION__, __LINE__,
+ iocbq, iocbq->iocb.ulpStatus);
+ continue;
+ }
- icmd->ulpBdeCount = 0;
- }
-
- lpfc_post_buffer(phba, pring, cnt, 1);
- if (save_icmd->ulpStatus) {
- go_exit = 1;
- }
-
-ct_unsol_event_exit_piocbq:
- list_del(&head);
- if (pmbuf) {
- list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) {
- lpfc_mbuf_free(phba, matp->virt, matp->phys);
- list_del(&matp->list);
- kfree(matp);
+ for (i = 0; i < icmd->ulpBdeCount; i++) {
+ paddr = getPaddr(icmd->un.cont64[i].addrHigh,
+ icmd->un.cont64[i].addrLow);
+ mp = lpfc_sli_ringpostbuf_get(phba, pring,
+ paddr);
+ size = icmd->un.cont64[i].tus.f.bdeSize;
+ lpfc_ct_unsol_buffer(phba, piocbq, mp, size);
+ lpfc_in_buf_free(phba, mp);
+ }
+ list_del(&iocbq->list);
+ lpfc_sli_release_iocbq(phba, iocbq);
}
- lpfc_mbuf_free(phba, pmbuf->virt, pmbuf->phys);
- kfree(pmbuf);
}
- return;
}
static void
-lpfc_free_ct_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mlist)
+lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist)
{
struct lpfc_dmabuf *mlast, *next_mlast;
@@ -160,7 +196,7 @@ lpfc_free_ct_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mlist)
}
static struct lpfc_dmabuf *
-lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl,
+lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl,
uint32_t size, int *entries)
{
struct lpfc_dmabuf *mlist = NULL;
@@ -181,7 +217,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl,
INIT_LIST_HEAD(&mp->list);
- if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT))
+ if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) ||
+ cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID))
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
else
mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys));
@@ -201,8 +238,8 @@ lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl,
bpl->tus.f.bdeFlags = BUFF_USE_RCV;
/* build buffer ptr list for IOCB */
- bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
- bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
bpl->tus.f.bdeSize = (uint16_t) cnt;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
bpl++;
@@ -215,24 +252,49 @@ lpfc_alloc_ct_rsp(struct lpfc_hba * phba, int cmdcode, struct ulp_bde64 * bpl,
return mlist;
}
+int
+lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb)
+{
+ struct lpfc_dmabuf *buf_ptr;
+
+ if (ctiocb->context1) {
+ buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
+ lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+ kfree(buf_ptr);
+ ctiocb->context1 = NULL;
+ }
+ if (ctiocb->context2) {
+ lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2);
+ ctiocb->context2 = NULL;
+ }
+
+ if (ctiocb->context3) {
+ buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3;
+ lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
+ kfree(buf_ptr);
+ ctiocb->context1 = NULL;
+ }
+ lpfc_sli_release_iocbq(phba, ctiocb);
+ return 0;
+}
+
static int
-lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
+lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp,
struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp,
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *),
struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry,
- uint32_t tmo)
+ uint32_t tmo, uint8_t retry)
{
-
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
IOCB_t *icmd;
struct lpfc_iocbq *geniocb;
+ int rc;
/* Allocate buffer for command iocb */
- spin_lock_irq(phba->host->host_lock);
geniocb = lpfc_sli_get_iocbq(phba);
- spin_unlock_irq(phba->host->host_lock);
if (geniocb == NULL)
return 1;
@@ -272,31 +334,40 @@ lpfc_gen_req(struct lpfc_hba *phba, struct lpfc_dmabuf *bmp,
icmd->ulpClass = CLASS3;
icmd->ulpContext = ndlp->nlp_rpi;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ /* For GEN_REQUEST64_CR, use the RPI */
+ icmd->ulpCt_h = 0;
+ icmd->ulpCt_l = 0;
+ }
+
/* Issue GEN REQ IOCB for NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0119 Issue GEN REQ IOCB for NPORT x%x "
- "Data: x%x x%x\n", phba->brd_no, icmd->un.ulpWord[5],
- icmd->ulpIoTag, phba->hba_state);
+ "%d (%d):0119 Issue GEN REQ IOCB to NPORT x%x "
+ "Data: x%x x%x\n", phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, icmd->ulpIoTag,
+ vport->port_state);
geniocb->iocb_cmpl = cmpl;
geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
- spin_lock_irq(phba->host->host_lock);
- if (lpfc_sli_issue_iocb(phba, pring, geniocb, 0) == IOCB_ERROR) {
+ geniocb->vport = vport;
+ geniocb->retry = retry;
+ rc = lpfc_sli_issue_iocb(phba, pring, geniocb, 0);
+
+ if (rc == IOCB_ERROR) {
lpfc_sli_release_iocbq(phba, geniocb);
- spin_unlock_irq(phba->host->host_lock);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static int
-lpfc_ct_cmd(struct lpfc_hba *phba, struct lpfc_dmabuf *inmp,
+lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp,
struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp,
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *),
- uint32_t rsp_size)
+ uint32_t rsp_size, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt;
struct lpfc_dmabuf *outmp;
int cnt = 0, status;
@@ -310,8 +381,8 @@ lpfc_ct_cmd(struct lpfc_hba *phba, struct lpfc_dmabuf *inmp,
if (!outmp)
return -ENOMEM;
- status = lpfc_gen_req(phba, bmp, inmp, outmp, cmpl, ndlp, 0,
- cnt+1, 0);
+ status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0,
+ cnt+1, 0, retry);
if (status) {
lpfc_free_ct_rsp(phba, outmp);
return -ENOMEM;
@@ -319,20 +390,35 @@ lpfc_ct_cmd(struct lpfc_hba *phba, struct lpfc_dmabuf *inmp,
return 0;
}
+static struct lpfc_vport *
+lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
+
+ struct lpfc_vport *vport_curr;
+
+ list_for_each_entry(vport_curr, &phba->port_list, listentry) {
+ if ((vport_curr->fc_myDID) &&
+ (vport_curr->fc_myDID == did))
+ return vport_curr;
+ }
+
+ return NULL;
+}
+
static int
-lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
+lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ct_request *Response =
(struct lpfc_sli_ct_request *) mp->virt;
struct lpfc_nodelist *ndlp = NULL;
struct lpfc_dmabuf *mlast, *next_mp;
uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
- uint32_t Did;
- uint32_t CTentry;
+ uint32_t Did, CTentry;
int Cnt;
struct list_head head;
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
+ vport->num_disc_nodes = 0;
list_add_tail(&head, &mp->list);
@@ -350,39 +436,96 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
/* Loop through entire NameServer list of DIDs */
while (Cnt >= sizeof (uint32_t)) {
-
/* Get next DID from NameServer List */
CTentry = *ctptr++;
Did = ((be32_to_cpu(CTentry)) & Mask_DID);
ndlp = NULL;
- if (Did != phba->fc_myDID) {
- /* Check for rscn processing or not */
- ndlp = lpfc_setup_disc_node(phba, Did);
- }
- /* Mark all node table entries that are in the
- Nameserver */
- if (ndlp) {
- /* NameServer Rsp */
- lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0238 Process x%x NameServer"
- " Rsp Data: x%x x%x x%x\n",
- phba->brd_no,
+
+ /*
+ * Check for rscn processing or not
+ * To conserve rpi's, filter out addresses for other
+ * vports on the same physical HBAs.
+ */
+ if ((Did != vport->fc_myDID) &&
+ ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
+ phba->cfg_peer_port_login)) {
+ if ((vport->port_type != LPFC_NPIV_PORT) ||
+ (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
+ (!phba->cfg_vport_restrict_login)) {
+ ndlp = lpfc_setup_disc_node(vport, Did);
+ if (ndlp) {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Parse GID_FTrsp: "
+ "did:x%x flg:x%x x%x",
Did, ndlp->nlp_flag,
- phba->fc_flag,
- phba->fc_rscn_id_cnt);
- } else {
- /* NameServer Rsp */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0239 Skip x%x NameServer "
- "Rsp Data: x%x x%x x%x\n",
- phba->brd_no,
- Did, Size, phba->fc_flag,
- phba->fc_rscn_id_cnt);
+ vport->fc_flag);
+
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY,
+ "%d (%d):0238 Process "
+ "x%x NameServer Rsp"
+ "Data: x%x x%x x%x\n",
+ phba->brd_no,
+ vport->vpi, Did,
+ ndlp->nlp_flag,
+ vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ } else {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Skip1 GID_FTrsp: "
+ "did:x%x flg:x%x cnt:%d",
+ Did, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY,
+ "%d (%d):0239 Skip x%x "
+ "NameServer Rsp Data: "
+ "x%x x%x\n",
+ phba->brd_no,
+ vport->vpi, Did,
+ vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ }
+
+ } else {
+ if (!(vport->fc_flag & FC_RSCN_MODE) ||
+ (lpfc_rscn_payload_check(vport, Did))) {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Query GID_FTrsp: "
+ "did:x%x flg:x%x cnt:%d",
+ Did, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+
+ if (lpfc_ns_cmd(vport,
+ SLI_CTNS_GFF_ID,
+ 0, Did) == 0)
+ vport->num_disc_nodes++;
+ }
+ else {
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_CT,
+ "Skip2 GID_FTrsp: "
+ "did:x%x flg:x%x cnt:%d",
+ Did, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_DISCOVERY,
+ "%d (%d):0245 Skip x%x "
+ "NameServer Rsp Data: "
+ "x%x x%x\n",
+ phba->brd_no,
+ vport->vpi, Did,
+ vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ }
+ }
}
-
if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY)))
goto nsout1;
Cnt -= sizeof (uint32_t);
@@ -393,190 +536,369 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
nsout1:
list_del(&head);
-
- /*
- * The driver has cycled through all Nports in the RSCN payload.
- * Complete the handling by cleaning up and marking the
- * current driver state.
- */
- if (phba->hba_state == LPFC_HBA_READY) {
- lpfc_els_flush_rscn(phba);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
- spin_unlock_irq(phba->host->host_lock);
- }
return 0;
}
-
-
-
static void
-lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
- struct lpfc_sli *psli;
struct lpfc_dmabuf *bmp;
- struct lpfc_dmabuf *inp;
struct lpfc_dmabuf *outp;
- struct lpfc_nodelist *ndlp;
struct lpfc_sli_ct_request *CTrsp;
+ int rc;
- psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
- inp = (struct lpfc_dmabuf *) cmdiocb->context1;
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
-
irsp = &rspiocb->iocb;
- if (irsp->ulpStatus) {
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) {
- goto out;
- }
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GID_FT cmpl: status:x%x/x%x rtry:%d",
+ irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry);
+
+ /* Don't bother processing response if vport is being torn down. */
+ if (vport->load_flag & FC_UNLOADING)
+ goto out;
+
+
+ if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0216 Link event during NS query\n",
+ phba->brd_no, vport->vpi);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ goto out;
+ }
+
+ if (irsp->ulpStatus) {
/* Check for retry */
- if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
- phba->fc_ns_retry++;
+ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
+ if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+ (irsp->un.ulpWord[4] != IOERR_NO_RESOURCES))
+ vport->fc_ns_retry++;
/* CT command is being retried */
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
- if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) ==
- 0) {
- goto out;
- }
- }
+ rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+ vport->fc_ns_retry, 0);
+ if (rc == 0)
+ goto out;
}
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0257 GID_FT Query error: 0x%x 0x%x\n",
+ phba->brd_no, vport->vpi, irsp->ulpStatus,
+ vport->fc_ns_retry);
} else {
/* Good status, continue checking */
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0208 NameServer Rsp "
+ "%d (%d):0208 NameServer Rsp "
"Data: x%x\n",
- phba->brd_no,
- phba->fc_flag);
- lpfc_ns_rsp(phba, outp,
+ phba->brd_no, vport->vpi,
+ vport->fc_flag);
+ lpfc_ns_rsp(vport, outp,
(uint32_t) (irsp->un.genreq64.bdl.bdeSize));
} else if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* NameServer Rsp Error */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0240 NameServer Rsp Error "
+ "%d (%d):0240 NameServer Rsp Error "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
CTrsp->CommandResponse.bits.CmdRsp,
(uint32_t) CTrsp->ReasonCode,
(uint32_t) CTrsp->Explanation,
- phba->fc_flag);
+ vport->fc_flag);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x",
+ (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+ (uint32_t) CTrsp->ReasonCode,
+ (uint32_t) CTrsp->Explanation);
+
} else {
/* NameServer Rsp Error */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0241 NameServer Rsp Error "
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0241 NameServer Rsp Error "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
CTrsp->CommandResponse.bits.CmdRsp,
(uint32_t) CTrsp->ReasonCode,
(uint32_t) CTrsp->Explanation,
- phba->fc_flag);
+ vport->fc_flag);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GID_FT rsp err2 cmd:x%x rsn:x%x exp:x%x",
+ (uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+ (uint32_t) CTrsp->ReasonCode,
+ (uint32_t) CTrsp->Explanation);
}
}
/* Link up / RSCN discovery */
- lpfc_disc_start(phba);
+ if (vport->num_disc_nodes == 0) {
+ /*
+ * The driver has cycled through all Nports in the RSCN payload.
+ * Complete the handling by cleaning up and marking the
+ * current driver state.
+ */
+ if (vport->port_state >= LPFC_DISC_AUTH) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ lpfc_els_flush_rscn(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
+ spin_unlock_irq(shost->host_lock);
+ }
+ else
+ lpfc_els_flush_rscn(vport);
+ }
+
+ lpfc_disc_start(vport);
+ }
out:
- lpfc_free_ct_rsp(phba, outp);
- lpfc_mbuf_free(phba, inp->virt, inp->phys);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- kfree(inp);
- kfree(bmp);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
+void
+lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1;
+ struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2;
+ struct lpfc_sli_ct_request *CTrsp;
+ int did;
+ uint8_t fbits;
+ struct lpfc_nodelist *ndlp;
+
+ did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId;
+ did = be32_to_cpu(did);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "GFF_ID cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], did);
+
+ if (irsp->ulpStatus == IOSTAT_SUCCESS) {
+ /* Good status, continue checking */
+ CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+ fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET];
+
+ if (CTrsp->CommandResponse.bits.CmdRsp ==
+ be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
+ if ((fbits & FC4_FEATURE_INIT) &&
+ !(fbits & FC4_FEATURE_TARGET)) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0245 Skip x%x GFF "
+ "NameServer Rsp Data: (init) "
+ "x%x x%x\n", phba->brd_no,
+ vport->vpi, did, fbits,
+ vport->fc_rscn_id_cnt);
+ goto out;
+ }
+ }
+ }
+ else {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0267 NameServer GFF Rsp"
+ " x%x Error (%d %d) Data: x%x x%x\n",
+ phba->brd_no, vport->vpi, did,
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ vport->fc_flag, vport->fc_rscn_id_cnt)
+ }
+
+ /* This is a target port, unregistered port, or the GFF_ID failed */
+ ndlp = lpfc_setup_disc_node(vport, did);
+ if (ndlp) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0242 Process x%x GFF "
+ "NameServer Rsp Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ did, ndlp->nlp_flag, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
+ } else {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0243 Skip x%x GFF "
+ "NameServer Rsp Data: x%x x%x\n",
+ phba->brd_no, vport->vpi, did,
+ vport->fc_flag, vport->fc_rscn_id_cnt);
+ }
+out:
+ /* Link up / RSCN discovery */
+ if (vport->num_disc_nodes)
+ vport->num_disc_nodes--;
+ if (vport->num_disc_nodes == 0) {
+ /*
+ * The driver has cycled through all Nports in the RSCN payload.
+ * Complete the handling by cleaning up and marking the
+ * current driver state.
+ */
+ if (vport->port_state >= LPFC_DISC_AUTH) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ lpfc_els_flush_rscn(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */
+ spin_unlock_irq(shost->host_lock);
+ }
+ else
+ lpfc_els_flush_rscn(vport);
+ }
+ lpfc_disc_start(vport);
+ }
+ lpfc_ct_free_iocb(phba, cmdiocb);
+ return;
+}
+
+
static void
-lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- struct lpfc_sli *psli;
- struct lpfc_dmabuf *bmp;
+ struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_dmabuf *inp;
struct lpfc_dmabuf *outp;
IOCB_t *irsp;
struct lpfc_sli_ct_request *CTrsp;
+ int cmdcode, rc;
+ uint8_t retry;
+ uint32_t latt;
- psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
inp = (struct lpfc_dmabuf *) cmdiocb->context1;
outp = (struct lpfc_dmabuf *) cmdiocb->context2;
- bmp = (struct lpfc_dmabuf *) cmdiocb->context3;
irsp = &rspiocb->iocb;
+ cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)->
+ CommandResponse.bits.CmdRsp);
CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
+ latt = lpfc_els_chk_latt(vport);
+
/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0209 RFT request completes ulpStatus x%x "
- "CmdRsp x%x\n", phba->brd_no, irsp->ulpStatus,
- CTrsp->CommandResponse.bits.CmdRsp);
+ "%d (%d):0209 RFT request completes, latt %d, "
+ "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
+ phba->brd_no, vport->vpi, latt, irsp->ulpStatus,
+ CTrsp->CommandResponse.bits.CmdRsp,
+ cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
- lpfc_free_ct_rsp(phba, outp);
- lpfc_mbuf_free(phba, inp->virt, inp->phys);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- kfree(inp);
- kfree(bmp);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "CT cmd cmpl: status:x%x/x%x cmd:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
+
+ if (irsp->ulpStatus) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0268 NS cmd %x Error (%d %d)\n",
+ phba->brd_no, vport->vpi, cmdcode,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+
+ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
+ (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)))
+ goto out;
+
+ retry = cmdiocb->retry;
+ if (retry >= LPFC_MAX_NS_RETRY)
+ goto out;
+
+ retry++;
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0216 Retrying NS cmd %x\n",
+ phba->brd_no, vport->vpi, cmdcode);
+ rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
+ if (rc == 0)
+ goto out;
+ }
+
+out:
+ lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
static void
-lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
return;
}
static void
-lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
return;
}
static void
-lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
return;
}
-void
-lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
+static void
+lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- char fwrev[16];
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_vport *vport = cmdiocb->vport;
- lpfc_decode_firmware_rev(phba, fwrev, 0);
+ if (irsp->ulpStatus != IOSTAT_SUCCESS)
+ vport->fc_flag |= FC_RFF_NOT_SUPPORTED;
- sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
- fwrev, lpfc_release_version);
+ lpfc_cmpl_ct_cmd_rft_id(phba, cmdiocb, rspiocb);
return;
}
+int
+lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
+ size_t size)
+{
+ int n;
+ uint8_t *wwn = vport->phba->wwpn;
+
+ n = snprintf(symbol, size,
+ "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ wwn[0], wwn[1], wwn[2], wwn[3],
+ wwn[4], wwn[5], wwn[6], wwn[7]);
+
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ return n;
+
+ if (n < size)
+ n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi);
+
+ if (n < size && vport->vname)
+ n += snprintf(symbol + n, size - n, " VName-%s", vport->vname);
+ return n;
+}
+
+int
+lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol,
+ size_t size)
+{
+ char fwrev[16];
+ int n;
+
+ lpfc_decode_firmware_rev(vport->phba, fwrev, 0);
+
+ n = snprintf(symbol, size, "Emulex %s FV%s DV%s",
+ vport->phba->ModelName, fwrev, lpfc_release_version);
+ return n;
+}
+
/*
* lpfc_ns_cmd
* Description:
@@ -585,55 +907,76 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
* LI_CTNS_RFT_ID
*/
int
-lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
+lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode,
+ uint8_t retry, uint32_t context)
{
+ struct lpfc_nodelist * ndlp;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *mp, *bmp;
struct lpfc_sli_ct_request *CtReq;
struct ulp_bde64 *bpl;
void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *) = NULL;
uint32_t rsp_size = 1024;
+ size_t size;
+ int rc = 0;
+
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) {
+ rc=1;
+ goto ns_cmd_exit;
+ }
/* fill in BDEs for command */
/* Allocate buffer for command payload */
mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
- if (!mp)
+ if (!mp) {
+ rc=2;
goto ns_cmd_exit;
+ }
INIT_LIST_HEAD(&mp->list);
mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys));
- if (!mp->virt)
+ if (!mp->virt) {
+ rc=3;
goto ns_cmd_free_mp;
+ }
/* Allocate buffer for Buffer ptr list */
bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
- if (!bmp)
+ if (!bmp) {
+ rc=4;
goto ns_cmd_free_mpvirt;
+ }
INIT_LIST_HEAD(&bmp->list);
bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys));
- if (!bmp->virt)
+ if (!bmp->virt) {
+ rc=5;
goto ns_cmd_free_bmp;
+ }
/* NameServer Req */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0236 NameServer Req Data: x%x x%x x%x\n",
- phba->brd_no, cmdcode, phba->fc_flag,
- phba->fc_rscn_id_cnt);
+ lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY,
+ "%d (%d):0236 NameServer Req Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, cmdcode, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
bpl = (struct ulp_bde64 *) bmp->virt;
memset(bpl, 0, sizeof(struct ulp_bde64));
- bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
- bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
bpl->tus.f.bdeFlags = 0;
if (cmdcode == SLI_CTNS_GID_FT)
bpl->tus.f.bdeSize = GID_REQUEST_SZ;
+ else if (cmdcode == SLI_CTNS_GFF_ID)
+ bpl->tus.f.bdeSize = GFF_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RFT_ID)
bpl->tus.f.bdeSize = RFT_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RNN_ID)
bpl->tus.f.bdeSize = RNN_REQUEST_SZ;
+ else if (cmdcode == SLI_CTNS_RSPN_ID)
+ bpl->tus.f.bdeSize = RSPN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RSNN_NN)
bpl->tus.f.bdeSize = RSNN_REQUEST_SZ;
else if (cmdcode == SLI_CTNS_RFF_ID)
@@ -654,56 +997,78 @@ lpfc_ns_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_GID_FT);
CtReq->un.gid.Fc4Type = SLI_CTPT_FCP;
- if (phba->hba_state < LPFC_HBA_READY)
- phba->hba_state = LPFC_NS_QRY;
- lpfc_set_disctmo(phba);
+ if (vport->port_state < LPFC_NS_QRY)
+ vport->port_state = LPFC_NS_QRY;
+ lpfc_set_disctmo(vport);
cmpl = lpfc_cmpl_ct_cmd_gid_ft;
rsp_size = FC_MAX_NS_RSP;
break;
+ case SLI_CTNS_GFF_ID:
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_GFF_ID);
+ CtReq->un.gff.PortId = be32_to_cpu(context);
+ cmpl = lpfc_cmpl_ct_cmd_gff_id;
+ break;
+
case SLI_CTNS_RFT_ID:
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RFT_ID);
- CtReq->un.rft.PortId = be32_to_cpu(phba->fc_myDID);
+ CtReq->un.rft.PortId = be32_to_cpu(vport->fc_myDID);
CtReq->un.rft.fcpReg = 1;
cmpl = lpfc_cmpl_ct_cmd_rft_id;
break;
- case SLI_CTNS_RFF_ID:
- CtReq->CommandResponse.bits.CmdRsp =
- be16_to_cpu(SLI_CTNS_RFF_ID);
- CtReq->un.rff.PortId = be32_to_cpu(phba->fc_myDID);
- CtReq->un.rff.feature_res = 0;
- CtReq->un.rff.feature_tgt = 0;
- CtReq->un.rff.type_code = FC_FCP_DATA;
- CtReq->un.rff.feature_init = 1;
- cmpl = lpfc_cmpl_ct_cmd_rff_id;
- break;
-
case SLI_CTNS_RNN_ID:
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RNN_ID);
- CtReq->un.rnn.PortId = be32_to_cpu(phba->fc_myDID);
- memcpy(CtReq->un.rnn.wwnn, &phba->fc_nodename,
+ CtReq->un.rnn.PortId = be32_to_cpu(vport->fc_myDID);
+ memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename,
sizeof (struct lpfc_name));
cmpl = lpfc_cmpl_ct_cmd_rnn_id;
break;
+ case SLI_CTNS_RSPN_ID:
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_RSPN_ID);
+ CtReq->un.rspn.PortId = be32_to_cpu(vport->fc_myDID);
+ size = sizeof(CtReq->un.rspn.symbname);
+ CtReq->un.rspn.len =
+ lpfc_vport_symbolic_port_name(vport,
+ CtReq->un.rspn.symbname, size);
+ cmpl = lpfc_cmpl_ct_cmd_rspn_id;
+ break;
case SLI_CTNS_RSNN_NN:
CtReq->CommandResponse.bits.CmdRsp =
be16_to_cpu(SLI_CTNS_RSNN_NN);
- memcpy(CtReq->un.rsnn.wwnn, &phba->fc_nodename,
+ memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename,
sizeof (struct lpfc_name));
- lpfc_get_hba_sym_node_name(phba, CtReq->un.rsnn.symbname);
- CtReq->un.rsnn.len = strlen(CtReq->un.rsnn.symbname);
+ size = sizeof(CtReq->un.rsnn.symbname);
+ CtReq->un.rsnn.len =
+ lpfc_vport_symbolic_node_name(vport,
+ CtReq->un.rsnn.symbname, size);
cmpl = lpfc_cmpl_ct_cmd_rsnn_nn;
break;
+ case SLI_CTNS_RFF_ID:
+ vport->fc_flag &= ~FC_RFF_NOT_SUPPORTED;
+ CtReq->CommandResponse.bits.CmdRsp =
+ be16_to_cpu(SLI_CTNS_RFF_ID);
+ CtReq->un.rff.PortId = be32_to_cpu(vport->fc_myDID);;
+ CtReq->un.rff.fbits = FC4_FEATURE_INIT;
+ CtReq->un.rff.type_code = FC_FCP_DATA;
+ cmpl = lpfc_cmpl_ct_cmd_rff_id;
+ break;
}
- if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, rsp_size))
+ if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
/* On success, The cmpl function will free the buffers */
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "Issue CT cmd: cmd:x%x did:x%x",
+ cmdcode, ndlp->nlp_DID, 0);
return 0;
+ }
+ rc=6;
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
ns_cmd_free_bmp:
kfree(bmp);
@@ -712,14 +1077,17 @@ ns_cmd_free_mpvirt:
ns_cmd_free_mp:
kfree(mp);
ns_cmd_exit:
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
+ phba->brd_no, vport->vpi, cmdcode, rc, vport->fc_flag,
+ vport->fc_rscn_id_cnt);
return 1;
}
static void
-lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq * rspiocb)
{
- struct lpfc_dmabuf *bmp = cmdiocb->context3;
struct lpfc_dmabuf *inp = cmdiocb->context1;
struct lpfc_dmabuf *outp = cmdiocb->context2;
struct lpfc_sli_ct_request *CTrsp = outp->virt;
@@ -727,48 +1095,60 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba * phba,
struct lpfc_nodelist *ndlp;
uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp;
uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp;
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp = &rspiocb->iocb;
+ uint32_t latt;
+
+ latt = lpfc_els_chk_latt(vport);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+ "FDMI cmpl: status:x%x/x%x latt:%d",
+ irsp->ulpStatus, irsp->un.ulpWord[4], latt);
+
+ if (latt || irsp->ulpStatus) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0229 FDMI cmd %04x failed, latt = %d "
+ "ulpStatus: x%x, rid x%x\n",
+ phba->brd_no, vport->vpi,
+ be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
+ lpfc_ct_free_iocb(phba, cmdiocb);
+ return;
+ }
- ndlp = lpfc_findnode_did(phba, FDMI_DID);
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
/* FDMI rsp failed */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0220 FDMI rsp failed Data: x%x\n",
- phba->brd_no,
- be16_to_cpu(fdmi_cmd));
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0220 FDMI rsp failed Data: x%x\n",
+ phba->brd_no, vport->vpi,
+ be16_to_cpu(fdmi_cmd));
}
switch (be16_to_cpu(fdmi_cmd)) {
case SLI_MGMT_RHBA:
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RPA);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA);
break;
case SLI_MGMT_RPA:
break;
case SLI_MGMT_DHBA:
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DPRT);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT);
break;
case SLI_MGMT_DPRT:
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_RHBA);
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA);
break;
}
-
- lpfc_free_ct_rsp(phba, outp);
- lpfc_mbuf_free(phba, inp->virt, inp->phys);
- lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
- kfree(inp);
- kfree(bmp);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_ct_free_iocb(phba, cmdiocb);
return;
}
+
int
-lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
+lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *mp, *bmp;
struct lpfc_sli_ct_request *CtReq;
struct ulp_bde64 *bpl;
@@ -805,12 +1185,10 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
INIT_LIST_HEAD(&bmp->list);
/* FDMI request */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0218 FDMI Request Data: x%x x%x x%x\n",
- phba->brd_no,
- phba->fc_flag, phba->hba_state, cmdcode);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0218 FDMI Request Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, vport->fc_flag,
+ vport->port_state, cmdcode);
CtReq = (struct lpfc_sli_ct_request *) mp->virt;
@@ -833,11 +1211,11 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
be16_to_cpu(SLI_MGMT_RHBA);
CtReq->CommandResponse.bits.Size = 0;
rh = (REG_HBA *) & CtReq->un.PortID;
- memcpy(&rh->hi.PortName, &phba->fc_sparam.portName,
+ memcpy(&rh->hi.PortName, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
/* One entry (port) per adapter */
rh->rpl.EntryCnt = be32_to_cpu(1);
- memcpy(&rh->rpl.pe, &phba->fc_sparam.portName,
+ memcpy(&rh->rpl.pe, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
/* point to the HBA attribute block */
@@ -853,7 +1231,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
ae->ad.bits.AttrType = be16_to_cpu(NODE_NAME);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES
+ sizeof (struct lpfc_name));
- memcpy(&ae->un.NodeName, &phba->fc_sparam.nodeName,
+ memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName,
sizeof (struct lpfc_name));
ab->EntryCnt++;
size += FOURBYTES + sizeof (struct lpfc_name);
@@ -991,7 +1369,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
pab = (REG_PORT_ATTRIBUTE *) & CtReq->un.PortID;
size = sizeof (struct lpfc_name) + FOURBYTES;
memcpy((uint8_t *) & pab->PortName,
- (uint8_t *) & phba->fc_sparam.portName,
+ (uint8_t *) & vport->fc_sparam.portName,
sizeof (struct lpfc_name));
pab->ab.EntryCnt = 0;
@@ -1053,7 +1431,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size);
ae->ad.bits.AttrType = be16_to_cpu(MAX_FRAME_SIZE);
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4);
- hsp = (struct serv_parm *) & phba->fc_sparam;
+ hsp = (struct serv_parm *) & vport->fc_sparam;
ae->un.MaxFrameSize =
(((uint32_t) hsp->cmn.
bbRcvSizeMsb) << 8) | (uint32_t) hsp->cmn.
@@ -1097,7 +1475,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
CtReq->CommandResponse.bits.Size = 0;
pe = (PORT_ENTRY *) & CtReq->un.PortID;
memcpy((uint8_t *) & pe->PortName,
- (uint8_t *) & phba->fc_sparam.portName,
+ (uint8_t *) & vport->fc_sparam.portName,
sizeof (struct lpfc_name));
size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
break;
@@ -1107,22 +1485,22 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
CtReq->CommandResponse.bits.Size = 0;
pe = (PORT_ENTRY *) & CtReq->un.PortID;
memcpy((uint8_t *) & pe->PortName,
- (uint8_t *) & phba->fc_sparam.portName,
+ (uint8_t *) & vport->fc_sparam.portName,
sizeof (struct lpfc_name));
size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name);
break;
}
bpl = (struct ulp_bde64 *) bmp->virt;
- bpl->addrHigh = le32_to_cpu( putPaddrHigh(mp->phys) );
- bpl->addrLow = le32_to_cpu( putPaddrLow(mp->phys) );
+ bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) );
+ bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) );
bpl->tus.f.bdeFlags = 0;
bpl->tus.f.bdeSize = size;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
cmpl = lpfc_cmpl_ct_cmd_fdmi;
- if (!lpfc_ct_cmd(phba, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP))
+ if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
return 0;
lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
@@ -1134,49 +1512,50 @@ fdmi_cmd_free_mp:
kfree(mp);
fdmi_cmd_exit:
/* Issue FDMI request failed */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0244 Issue FDMI request failed Data: x%x\n",
- phba->brd_no,
- cmdcode);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0244 Issue FDMI request failed Data: x%x\n",
+ phba->brd_no, vport->vpi, cmdcode);
return 1;
}
void
lpfc_fdmi_tmo(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+ struct lpfc_vport *vport = (struct lpfc_vport *)ptr;
+ struct lpfc_hba *phba = vport->phba;
unsigned long iflag;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- if (!(phba->work_hba_events & WORKER_FDMI_TMO)) {
- phba->work_hba_events |= WORKER_FDMI_TMO;
+ spin_lock_irqsave(&vport->work_port_lock, iflag);
+ if (!(vport->work_port_events & WORKER_FDMI_TMO)) {
+ vport->work_port_events |= WORKER_FDMI_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+ spin_lock_irqsave(&phba->hbalock, iflag);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
- spin_unlock_irqrestore(phba->host->host_lock,iflag);
+ else
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
}
void
-lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
+lpfc_fdmi_timeout_handler(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp;
- ndlp = lpfc_findnode_did(phba, FDMI_DID);
+ ndlp = lpfc_findnode_did(vport, FDMI_DID);
if (ndlp) {
- if (init_utsname()->nodename[0] != '\0') {
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
- } else {
- mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
- }
+ if (init_utsname()->nodename[0] != '\0')
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+ else
+ mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
}
return;
}
-
void
-lpfc_decode_firmware_rev(struct lpfc_hba * phba, char *fwrevision, int flag)
+lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag)
{
struct lpfc_sli *psli = &phba->sli;
lpfc_vpd_t *vp = &phba->vpd;
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
new file mode 100644
index 000000000000..673cfe11cc2b
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -0,0 +1,508 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2007 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+#include <linux/version.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_version.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+/* debugfs interface
+ *
+ * To access this interface the user should:
+ * # mkdir /debug
+ * # mount -t debugfs none /debug
+ *
+ * The lpfc debugfs directory hierachy is:
+ * lpfc/lpfcX/vportY
+ * where X is the lpfc hba unique_id
+ * where Y is the vport VPI on that hba
+ *
+ * Debugging services available per vport:
+ * discovery_trace
+ * This is an ACSII readable file that contains a trace of the last
+ * lpfc_debugfs_max_disc_trc events that happened on a specific vport.
+ * See lpfc_debugfs.h for different categories of
+ * discovery events. To enable the discovery trace, the following
+ * module parameters must be set:
+ * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support
+ * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for
+ * EACH vport. X MUST also be a power of 2.
+ * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in
+ * lpfc_debugfs.h .
+ */
+static int lpfc_debugfs_enable = 0;
+module_param(lpfc_debugfs_enable, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
+
+static int lpfc_debugfs_max_disc_trc = 0; /* This MUST be a power of 2 */
+module_param(lpfc_debugfs_max_disc_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
+ "Set debugfs discovery trace depth");
+
+static int lpfc_debugfs_mask_disc_trc = 0;
+module_param(lpfc_debugfs_mask_disc_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
+ "Set debugfs discovery trace mask");
+
+#include <linux/debugfs.h>
+
+/* size of discovery_trace output line */
+#define LPFC_DISC_TRC_ENTRY_SIZE 80
+
+/* nodelist output buffer size */
+#define LPFC_NODELIST_SIZE 8192
+#define LPFC_NODELIST_ENTRY_SIZE 120
+
+struct lpfc_debug {
+ char *buffer;
+ int len;
+};
+
+atomic_t lpfc_debugfs_disc_trc_cnt = ATOMIC_INIT(0);
+unsigned long lpfc_debugfs_start_time = 0L;
+
+static int
+lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
+{
+ int i, index, len, enable;
+ uint32_t ms;
+ struct lpfc_disc_trc *dtp;
+ char buffer[80];
+
+
+ enable = lpfc_debugfs_enable;
+ lpfc_debugfs_enable = 0;
+
+ len = 0;
+ index = (atomic_read(&vport->disc_trc_cnt) + 1) &
+ (lpfc_debugfs_max_disc_trc - 1);
+ for (i = index; i < lpfc_debugfs_max_disc_trc; i++) {
+ dtp = vport->disc_trc + i;
+ if (!dtp->fmt)
+ continue;
+ ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+ snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+ dtp->seq_cnt, ms, dtp->fmt);
+ len += snprintf(buf+len, size-len, buffer,
+ dtp->data1, dtp->data2, dtp->data3);
+ }
+ for (i = 0; i < index; i++) {
+ dtp = vport->disc_trc + i;
+ if (!dtp->fmt)
+ continue;
+ ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+ snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+ dtp->seq_cnt, ms, dtp->fmt);
+ len += snprintf(buf+len, size-len, buffer,
+ dtp->data1, dtp->data2, dtp->data3);
+ }
+
+ lpfc_debugfs_enable = enable;
+ return len;
+}
+
+static int
+lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
+{
+ int len = 0;
+ int cnt;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp;
+ unsigned char *statep, *name;
+
+ cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
+
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (!cnt) {
+ len += snprintf(buf+len, size-len,
+ "Missing Nodelist Entries\n");
+ break;
+ }
+ cnt--;
+ switch (ndlp->nlp_state) {
+ case NLP_STE_UNUSED_NODE:
+ statep = "UNUSED";
+ break;
+ case NLP_STE_PLOGI_ISSUE:
+ statep = "PLOGI ";
+ break;
+ case NLP_STE_ADISC_ISSUE:
+ statep = "ADISC ";
+ break;
+ case NLP_STE_REG_LOGIN_ISSUE:
+ statep = "REGLOG";
+ break;
+ case NLP_STE_PRLI_ISSUE:
+ statep = "PRLI ";
+ break;
+ case NLP_STE_UNMAPPED_NODE:
+ statep = "UNMAP ";
+ break;
+ case NLP_STE_MAPPED_NODE:
+ statep = "MAPPED";
+ break;
+ case NLP_STE_NPR_NODE:
+ statep = "NPR ";
+ break;
+ default:
+ statep = "UNKNOWN";
+ }
+ len += snprintf(buf+len, size-len, "%s DID:x%06x ",
+ statep, ndlp->nlp_DID);
+ name = (unsigned char *)&ndlp->nlp_portname;
+ len += snprintf(buf+len, size-len,
+ "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
+ *name, *(name+1), *(name+2), *(name+3),
+ *(name+4), *(name+5), *(name+6), *(name+7));
+ name = (unsigned char *)&ndlp->nlp_nodename;
+ len += snprintf(buf+len, size-len,
+ "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
+ *name, *(name+1), *(name+2), *(name+3),
+ *(name+4), *(name+5), *(name+6), *(name+7));
+ len += snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ",
+ ndlp->nlp_rpi, ndlp->nlp_flag);
+ if (!ndlp->nlp_type)
+ len += snprintf(buf+len, size-len, "UNKNOWN_TYPE");
+ if (ndlp->nlp_type & NLP_FC_NODE)
+ len += snprintf(buf+len, size-len, "FC_NODE ");
+ if (ndlp->nlp_type & NLP_FABRIC)
+ len += snprintf(buf+len, size-len, "FABRIC ");
+ if (ndlp->nlp_type & NLP_FCP_TARGET)
+ len += snprintf(buf+len, size-len, "FCP_TGT sid:%d ",
+ ndlp->nlp_sid);
+ if (ndlp->nlp_type & NLP_FCP_INITIATOR)
+ len += snprintf(buf+len, size-len, "FCP_INITIATOR");
+ len += snprintf(buf+len, size-len, "\n");
+ }
+ spin_unlock_irq(shost->host_lock);
+ return len;
+}
+#endif
+
+
+inline void
+lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
+ uint32_t data1, uint32_t data2, uint32_t data3)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct lpfc_disc_trc *dtp;
+ int index;
+
+ if (!(lpfc_debugfs_mask_disc_trc & mask))
+ return;
+
+ if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc ||
+ !vport || !vport->disc_trc)
+ return;
+
+ index = atomic_inc_return(&vport->disc_trc_cnt) &
+ (lpfc_debugfs_max_disc_trc - 1);
+ dtp = vport->disc_trc + index;
+ dtp->fmt = fmt;
+ dtp->data1 = data1;
+ dtp->data2 = data2;
+ dtp->data3 = data3;
+ dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_disc_trc_cnt);
+ dtp->jif = jiffies;
+#endif
+ return;
+}
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+static int
+lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_vport *vport = inode->i_private;
+ struct lpfc_debug *debug;
+ int size;
+ int rc = -ENOMEM;
+
+ if (!lpfc_debugfs_max_disc_trc) {
+ rc = -ENOSPC;
+ goto out;
+ }
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ goto out;
+
+ /* Round to page boundry */
+ size = (lpfc_debugfs_max_disc_trc * LPFC_DISC_TRC_ENTRY_SIZE);
+ size = PAGE_ALIGN(size);
+
+ debug->buffer = kmalloc(size, GFP_KERNEL);
+ if (!debug->buffer) {
+ kfree(debug);
+ goto out;
+ }
+
+ debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size);
+ file->private_data = debug;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
+{
+ struct lpfc_vport *vport = inode->i_private;
+ struct lpfc_debug *debug;
+ int rc = -ENOMEM;
+
+ debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+ if (!debug)
+ goto out;
+
+ /* Round to page boundry */
+ debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL);
+ if (!debug->buffer) {
+ kfree(debug);
+ goto out;
+ }
+
+ debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer,
+ LPFC_NODELIST_SIZE);
+ file->private_data = debug;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static loff_t
+lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
+{
+ struct lpfc_debug *debug;
+ loff_t pos = -1;
+
+ debug = file->private_data;
+
+ switch (whence) {
+ case 0:
+ pos = off;
+ break;
+ case 1:
+ pos = file->f_pos + off;
+ break;
+ case 2:
+ pos = debug->len - off;
+ }
+ return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
+}
+
+static ssize_t
+lpfc_debugfs_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct lpfc_debug *debug = file->private_data;
+ return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
+ debug->len);
+}
+
+static int
+lpfc_debugfs_release(struct inode *inode, struct file *file)
+{
+ struct lpfc_debug *debug = file->private_data;
+
+ kfree(debug->buffer);
+ kfree(debug);
+
+ return 0;
+}
+
+#undef lpfc_debugfs_op_disc_trc
+static struct file_operations lpfc_debugfs_op_disc_trc = {
+ .owner = THIS_MODULE,
+ .open = lpfc_debugfs_disc_trc_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_debugfs_read,
+ .release = lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_nodelist
+static struct file_operations lpfc_debugfs_op_nodelist = {
+ .owner = THIS_MODULE,
+ .open = lpfc_debugfs_nodelist_open,
+ .llseek = lpfc_debugfs_lseek,
+ .read = lpfc_debugfs_read,
+ .release = lpfc_debugfs_release,
+};
+
+static struct dentry *lpfc_debugfs_root = NULL;
+static atomic_t lpfc_debugfs_hba_count;
+#endif
+
+inline void
+lpfc_debugfs_initialize(struct lpfc_vport *vport)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct lpfc_hba *phba = vport->phba;
+ char name[64];
+ uint32_t num, i;
+
+ if (!lpfc_debugfs_enable)
+ return;
+
+ if (lpfc_debugfs_max_disc_trc) {
+ num = lpfc_debugfs_max_disc_trc - 1;
+ if (num & lpfc_debugfs_max_disc_trc) {
+ /* Change to be a power of 2 */
+ num = lpfc_debugfs_max_disc_trc;
+ i = 0;
+ while (num > 1) {
+ num = num >> 1;
+ i++;
+ }
+ lpfc_debugfs_max_disc_trc = (1 << i);
+ printk(KERN_ERR
+ "lpfc_debugfs_max_disc_trc changed to %d\n",
+ lpfc_debugfs_max_disc_trc);
+ }
+ }
+
+ if (!lpfc_debugfs_root) {
+ lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
+ atomic_set(&lpfc_debugfs_hba_count, 0);
+ if (!lpfc_debugfs_root)
+ goto debug_failed;
+ }
+
+ snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
+ if (!phba->hba_debugfs_root) {
+ phba->hba_debugfs_root =
+ debugfs_create_dir(name, lpfc_debugfs_root);
+ if (!phba->hba_debugfs_root)
+ goto debug_failed;
+ atomic_inc(&lpfc_debugfs_hba_count);
+ atomic_set(&phba->debugfs_vport_count, 0);
+ }
+
+ snprintf(name, sizeof(name), "vport%d", vport->vpi);
+ if (!vport->vport_debugfs_root) {
+ vport->vport_debugfs_root =
+ debugfs_create_dir(name, phba->hba_debugfs_root);
+ if (!vport->vport_debugfs_root)
+ goto debug_failed;
+ atomic_inc(&phba->debugfs_vport_count);
+ }
+
+ if (!lpfc_debugfs_start_time)
+ lpfc_debugfs_start_time = jiffies;
+
+ vport->disc_trc = kmalloc(
+ (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc),
+ GFP_KERNEL);
+
+ if (!vport->disc_trc)
+ goto debug_failed;
+ memset(vport->disc_trc, 0,
+ (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc));
+
+ snprintf(name, sizeof(name), "discovery_trace");
+ vport->debug_disc_trc =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ vport->vport_debugfs_root,
+ vport, &lpfc_debugfs_op_disc_trc);
+ if (!vport->debug_disc_trc) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0409 Cannot create debugfs",
+ phba->brd_no);
+ goto debug_failed;
+ }
+ snprintf(name, sizeof(name), "nodelist");
+ vport->debug_nodelist =
+ debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+ vport->vport_debugfs_root,
+ vport, &lpfc_debugfs_op_nodelist);
+ if (!vport->debug_nodelist) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0409 Cannot create debugfs",
+ phba->brd_no);
+ goto debug_failed;
+ }
+debug_failed:
+ return;
+#endif
+}
+
+
+inline void
+lpfc_debugfs_terminate(struct lpfc_vport *vport)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+ struct lpfc_hba *phba = vport->phba;
+
+ if (vport->disc_trc) {
+ kfree(vport->disc_trc);
+ vport->disc_trc = NULL;
+ }
+ if (vport->debug_disc_trc) {
+ debugfs_remove(vport->debug_disc_trc); /* discovery_trace */
+ vport->debug_disc_trc = NULL;
+ }
+ if (vport->debug_nodelist) {
+ debugfs_remove(vport->debug_nodelist); /* nodelist */
+ vport->debug_nodelist = NULL;
+ }
+ if (vport->vport_debugfs_root) {
+ debugfs_remove(vport->vport_debugfs_root); /* vportX */
+ vport->vport_debugfs_root = NULL;
+ atomic_dec(&phba->debugfs_vport_count);
+ }
+ if (atomic_read(&phba->debugfs_vport_count) == 0) {
+ debugfs_remove(vport->phba->hba_debugfs_root); /* lpfcX */
+ vport->phba->hba_debugfs_root = NULL;
+ atomic_dec(&lpfc_debugfs_hba_count);
+ if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
+ debugfs_remove(lpfc_debugfs_root); /* lpfc */
+ lpfc_debugfs_root = NULL;
+ }
+ }
+#endif
+}
+
+
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
new file mode 100644
index 000000000000..fffb678426a4
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -0,0 +1,50 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2007 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#ifndef _H_LPFC_DEBUG_FS
+#define _H_LPFC_DEBUG_FS
+
+#ifdef CONFIG_LPFC_DEBUG_FS
+struct lpfc_disc_trc {
+ char *fmt;
+ uint32_t data1;
+ uint32_t data2;
+ uint32_t data3;
+ uint32_t seq_cnt;
+ unsigned long jif;
+};
+#endif
+
+/* Mask for discovery_trace */
+#define LPFC_DISC_TRC_ELS_CMD 0x1 /* Trace ELS commands */
+#define LPFC_DISC_TRC_ELS_RSP 0x2 /* Trace ELS response */
+#define LPFC_DISC_TRC_ELS_UNSOL 0x4 /* Trace ELS rcv'ed */
+#define LPFC_DISC_TRC_ELS_ALL 0x7 /* Trace ELS */
+#define LPFC_DISC_TRC_MBOX_VPORT 0x8 /* Trace vport MBOXs */
+#define LPFC_DISC_TRC_MBOX 0x10 /* Trace other MBOXs */
+#define LPFC_DISC_TRC_MBOX_ALL 0x18 /* Trace all MBOXs */
+#define LPFC_DISC_TRC_CT 0x20 /* Trace disc CT requests */
+#define LPFC_DISC_TRC_DSM 0x40 /* Trace DSM events */
+#define LPFC_DISC_TRC_RPORT 0x80 /* Trace rport events */
+#define LPFC_DISC_TRC_NODE 0x100 /* Trace ndlp state changes */
+
+#define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general
+ * discovery */
+#endif /* H_LPFC_DEBUG_FS */
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 498059f3f7f4..aacac9ac5381 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -36,21 +36,23 @@ enum lpfc_work_type {
LPFC_EVT_WARM_START,
LPFC_EVT_KILL,
LPFC_EVT_ELS_RETRY,
+ LPFC_EVT_DEV_LOSS_DELAY,
+ LPFC_EVT_DEV_LOSS,
};
/* structure used to queue event to the discovery tasklet */
struct lpfc_work_evt {
struct list_head evt_listp;
- void * evt_arg1;
- void * evt_arg2;
+ void *evt_arg1;
+ void *evt_arg2;
enum lpfc_work_type evt;
};
struct lpfc_nodelist {
struct list_head nlp_listp;
- struct lpfc_name nlp_portname; /* port name */
- struct lpfc_name nlp_nodename; /* node name */
+ struct lpfc_name nlp_portname;
+ struct lpfc_name nlp_nodename;
uint32_t nlp_flag; /* entry flags */
uint32_t nlp_DID; /* FC D_ID of entry */
uint32_t nlp_last_elscmd; /* Last ELS cmd sent */
@@ -75,8 +77,9 @@ struct lpfc_nodelist {
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
struct fc_rport *rport; /* Corresponding FC transport
port structure */
- struct lpfc_hba *nlp_phba;
+ struct lpfc_vport *vport;
struct lpfc_work_evt els_retry_evt;
+ struct lpfc_work_evt dev_loss_evt;
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
unsigned long last_q_full_time; /* jiffy of last queue full */
struct kref kref;
@@ -98,7 +101,9 @@ struct lpfc_nodelist {
ACC */
#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from
NPR list */
+#define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */
#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */
+#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */
/* There are 4 different double linked lists nodelist entries can reside on.
* The Port Login (PLOGI) list and Address Discovery (ADISC) list are used
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 638b3cd677bd..33fbc1666946 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -35,38 +35,38 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
+static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
+
static int lpfc_max_els_tries = 3;
-static int
-lpfc_els_chk_latt(struct lpfc_hba * phba)
+int
+lpfc_els_chk_latt(struct lpfc_vport *vport)
{
- struct lpfc_sli *psli;
- LPFC_MBOXQ_t *mbox;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
uint32_t ha_copy;
- int rc;
- psli = &phba->sli;
-
- if ((phba->hba_state >= LPFC_HBA_READY) ||
- (phba->hba_state == LPFC_LINK_DOWN))
+ if (vport->port_state >= LPFC_VPORT_READY ||
+ phba->link_state == LPFC_LINK_DOWN)
return 0;
/* Read the HBA Host Attention Register */
- spin_lock_irq(phba->host->host_lock);
ha_copy = readl(phba->HAregaddr);
- spin_unlock_irq(phba->host->host_lock);
if (!(ha_copy & HA_LATT))
return 0;
/* Pending Link Event during Discovery */
- lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
- "%d:0237 Pending Link Event during "
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0237 Pending Link Event during "
"Discovery: State x%x\n",
- phba->brd_no, phba->hba_state);
+ phba->brd_no, vport->vpi, phba->pport->port_state);
/* CLEAR_LA should re-enable link attention events and
* we should then imediately take a LATT event. The
@@ -74,48 +74,34 @@ lpfc_els_chk_latt(struct lpfc_hba * phba)
* will cleanup any left over in-progress discovery
* events.
*/
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_ABORT_DISCOVERY;
- spin_unlock_irq(phba->host->host_lock);
-
- if (phba->hba_state != LPFC_CLEAR_LA) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, mbox);
- mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox (phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox, phba->mbox_mem_pool);
- phba->hba_state = LPFC_HBA_ERROR;
- }
- }
- }
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_ABORT_DISCOVERY;
+ spin_unlock_irq(shost->host_lock);
- return 1;
+ if (phba->link_state != LPFC_CLEAR_LA)
+ lpfc_issue_clear_la(phba, vport);
+ return 1;
}
static struct lpfc_iocbq *
-lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
- uint16_t cmdSize, uint8_t retry, struct lpfc_nodelist * ndlp,
- uint32_t did, uint32_t elscmd)
+lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
+ uint16_t cmdSize, uint8_t retry,
+ struct lpfc_nodelist *ndlp, uint32_t did,
+ uint32_t elscmd)
{
- struct lpfc_sli_ring *pring;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *elsiocb;
struct lpfc_dmabuf *pcmd, *prsp, *pbuflist;
struct ulp_bde64 *bpl;
IOCB_t *icmd;
- pring = &phba->sli.ring[LPFC_ELS_RING];
- if (phba->hba_state < LPFC_LINK_UP)
- return NULL;
+ if (!lpfc_is_link_up(phba))
+ return NULL;
/* Allocate buffer for command iocb */
- spin_lock_irq(phba->host->host_lock);
elsiocb = lpfc_sli_get_iocbq(phba);
- spin_unlock_irq(phba->host->host_lock);
if (elsiocb == NULL)
return NULL;
@@ -123,14 +109,12 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
/* fill in BDEs for command */
/* Allocate buffer for command payload */
- if (((pcmd = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
+ if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) ||
((pcmd->virt = lpfc_mbuf_alloc(phba,
MEM_PRI, &(pcmd->phys))) == 0)) {
kfree(pcmd);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
return NULL;
}
@@ -138,7 +122,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
/* Allocate buffer for response payload */
if (expectRsp) {
- prsp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ prsp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (prsp)
prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
&prsp->phys);
@@ -146,9 +130,7 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
kfree(prsp);
lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
kfree(pcmd);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
return NULL;
}
INIT_LIST_HEAD(&prsp->list);
@@ -157,14 +139,12 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
}
/* Allocate buffer for Buffer ptr list */
- pbuflist = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL);
+ pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
if (pbuflist)
- pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
- &pbuflist->phys);
+ pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI,
+ &pbuflist->phys);
if (pbuflist == 0 || pbuflist->virt == 0) {
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys);
lpfc_mbuf_free(phba, prsp->virt, prsp->phys);
kfree(pcmd);
@@ -178,20 +158,28 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys);
icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys);
icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BDL;
+ icmd->un.elsreq64.remoteID = did; /* DID */
if (expectRsp) {
- icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64));
- icmd->un.elsreq64.remoteID = did; /* DID */
+ icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64));
icmd->ulpCommand = CMD_ELS_REQUEST64_CR;
icmd->ulpTimeout = phba->fc_ratov * 2;
} else {
- icmd->un.elsreq64.bdl.bdeSize = sizeof (struct ulp_bde64);
+ icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64);
icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX;
}
-
icmd->ulpBdeCount = 1;
icmd->ulpLe = 1;
icmd->ulpClass = CLASS3;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ icmd->un.elsreq64.myID = vport->fc_myDID;
+
+ /* For ELS_REQUEST64_CR, use the VPI by default */
+ icmd->ulpContext = vport->vpi;
+ icmd->ulpCt_h = 0;
+ icmd->ulpCt_l = 1;
+ }
+
bpl = (struct ulp_bde64 *) pbuflist->virt;
bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys));
bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys));
@@ -209,10 +197,12 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
}
/* Save for completion so we can release these resources */
- elsiocb->context1 = lpfc_nlp_get(ndlp);
+ if (elscmd != ELS_CMD_LS_RJT)
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
elsiocb->context2 = pcmd;
elsiocb->context3 = pbuflist;
elsiocb->retry = retry;
+ elsiocb->vport = vport;
elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT;
if (prsp) {
@@ -222,16 +212,16 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
if (expectRsp) {
/* Xmit ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0116 Xmit ELS command x%x to remote "
- "NPORT x%x I/O tag: x%x, HBA state: x%x\n",
- phba->brd_no, elscmd,
- did, elsiocb->iotag, phba->hba_state);
+ "%d (%d):0116 Xmit ELS command x%x to remote "
+ "NPORT x%x I/O tag: x%x, port state: x%x\n",
+ phba->brd_no, vport->vpi, elscmd, did,
+ elsiocb->iotag, vport->port_state);
} else {
/* Xmit ELS response <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0117 Xmit ELS response x%x to remote "
+ "%d (%d):0117 Xmit ELS response x%x to remote "
"NPORT x%x I/O tag: x%x, size: x%x\n",
- phba->brd_no, elscmd,
+ phba->brd_no, vport->vpi, elscmd,
ndlp->nlp_DID, elsiocb->iotag, cmdSize);
}
@@ -240,16 +230,79 @@ lpfc_prep_els_iocb(struct lpfc_hba * phba, uint8_t expectRsp,
static int
-lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
- struct serv_parm *sp, IOCB_t *irsp)
+lpfc_issue_fabric_reglogin(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mbox;
struct lpfc_dmabuf *mp;
+ struct lpfc_nodelist *ndlp;
+ struct serv_parm *sp;
int rc;
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_FABRIC;
- spin_unlock_irq(phba->host->host_lock);
+ sp = &phba->fc_fabparam;
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp)
+ goto fail;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
+
+ vport->port_state = LPFC_FABRIC_CFG_LINK;
+ lpfc_config_link(phba, mbox);
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
+
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+ if (rc == MBX_NOT_FINISHED)
+ goto fail_free_mbox;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ goto fail;
+ rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox,
+ 0);
+ if (rc)
+ goto fail_free_mbox;
+
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
+ mbox->vport = vport;
+ mbox->context2 = lpfc_nlp_get(ndlp);
+
+ rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
+ if (rc == MBX_NOT_FINISHED)
+ goto fail_issue_reg_login;
+
+ return 0;
+
+fail_issue_reg_login:
+ lpfc_nlp_put(ndlp);
+ mp = (struct lpfc_dmabuf *) mbox->context1;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+fail_free_mbox:
+ mempool_free(mbox, phba->mbox_mem_pool);
+
+fail:
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0249 Cannot issue Register Fabric login\n",
+ phba->brd_no, vport->vpi);
+ return -ENXIO;
+}
+
+static int
+lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct serv_parm *sp, IOCB_t *irsp)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *np;
+ struct lpfc_nodelist *next_np;
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_FABRIC;
+ spin_unlock_irq(shost->host_lock);
phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov);
if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */
@@ -258,20 +311,20 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000;
if (phba->fc_topology == TOPOLOGY_LOOP) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PUBLIC_LOOP;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PUBLIC_LOOP;
+ spin_unlock_irq(shost->host_lock);
} else {
/*
* If we are a N-port connected to a Fabric, fixup sparam's so
* logins to devices on remote loops work.
*/
- phba->fc_sparam.cmn.altBbCredit = 1;
+ vport->fc_sparam.cmn.altBbCredit = 1;
}
- phba->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
+ vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name));
- memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
+ memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name));
ndlp->nlp_class_sup = 0;
if (sp->cls1.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -285,68 +338,85 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
sp->cmn.bbRcvSizeLsb;
memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm));
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
-
- phba->hba_state = LPFC_FABRIC_CFG_LINK;
- lpfc_config_link(phba, mbox);
- mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ if (sp->cmn.response_multiple_NPort) {
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
+ "%d:1816 FLOGI NPIV supported, "
+ "response data 0x%x\n",
+ phba->brd_no,
+ sp->cmn.response_multiple_NPort);
+ phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
- if (rc == MBX_NOT_FINISHED)
- goto fail_free_mbox;
-
- mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!mbox)
- goto fail;
+ } else {
+ /* Because we asked f/w for NPIV it still expects us
+ to call reg_vnpid atleast for the physcial host */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
+ "%d:1817 Fabric does not support NPIV "
+ "- configuring single port mode.\n",
+ phba->brd_no);
+ phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
+ }
+ }
- if (lpfc_reg_login(phba, Fabric_DID, (uint8_t *) sp, mbox, 0))
- goto fail_free_mbox;
+ if ((vport->fc_prevDID != vport->fc_myDID) &&
+ !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
- mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login;
- mbox->context2 = lpfc_nlp_get(ndlp);
+ /* If our NportID changed, we need to ensure all
+ * remaining NPORTs get unreg_login'ed.
+ */
+ list_for_each_entry_safe(np, next_np,
+ &vport->fc_nodes, nlp_listp) {
+ if ((np->nlp_state != NLP_STE_NPR_NODE) ||
+ !(np->nlp_flag & NLP_NPR_ADISC))
+ continue;
+ spin_lock_irq(shost->host_lock);
+ np->nlp_flag &= ~NLP_NPR_ADISC;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_unreg_rpi(vport, np);
+ }
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ }
+ }
- rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT | MBX_STOP_IOCB);
- if (rc == MBX_NOT_FINISHED)
- goto fail_issue_reg_login;
+ ndlp->nlp_sid = irsp->un.ulpWord[4] & Mask_DID;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED &&
+ vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) {
+ lpfc_register_new_vport(phba, vport, ndlp);
+ return 0;
+ }
+ lpfc_issue_fabric_reglogin(vport);
return 0;
-
- fail_issue_reg_login:
- lpfc_nlp_put(ndlp);
- mp = (struct lpfc_dmabuf *) mbox->context1;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- fail_free_mbox:
- mempool_free(mbox, phba->mbox_mem_pool);
- fail:
- return -ENXIO;
}
/*
* We FLOGIed into an NPort, initiate pt2pt protocol
*/
static int
-lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
- struct serv_parm *sp)
+lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct serv_parm *sp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
LPFC_MBOXQ_t *mbox;
int rc;
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
phba->fc_edtov = FF_DEF_EDTOV;
phba->fc_ratov = FF_DEF_RATOV;
- rc = memcmp(&phba->fc_portname, &sp->portName,
- sizeof(struct lpfc_name));
+ rc = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(vport->fc_portname));
if (rc >= 0) {
/* This side will initiate the PLOGI */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PT2PT_PLOGI;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT_PLOGI;
+ spin_unlock_irq(shost->host_lock);
/*
* N_Port ID cannot be 0, set our to LocalID the other
@@ -355,7 +425,7 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
/* not equal */
if (rc)
- phba->fc_myDID = PT2PT_LocalID;
+ vport->fc_myDID = PT2PT_LocalID;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!mbox)
@@ -364,15 +434,16 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
rc = lpfc_sli_issue_mbox(phba, mbox,
- MBX_NOWAIT | MBX_STOP_IOCB);
+ MBX_NOWAIT | MBX_STOP_IOCB);
if (rc == MBX_NOT_FINISHED) {
mempool_free(mbox, phba->mbox_mem_pool);
goto fail;
}
lpfc_nlp_put(ndlp);
- ndlp = lpfc_findnode_did(phba, PT2PT_RemoteID);
+ ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID);
if (!ndlp) {
/*
* Cannot find existing Fabric ndlp, so allocate a
@@ -382,28 +453,30 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
if (!ndlp)
goto fail;
- lpfc_nlp_init(phba, ndlp, PT2PT_RemoteID);
+ lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID);
}
memcpy(&ndlp->nlp_portname, &sp->portName,
- sizeof(struct lpfc_name));
+ sizeof(struct lpfc_name));
memcpy(&ndlp->nlp_nodename, &sp->nodeName,
- sizeof(struct lpfc_name));
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ sizeof(struct lpfc_name));
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
} else {
/* This side will wait for the PLOGI */
lpfc_nlp_put(ndlp);
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PT2PT;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT;
+ spin_unlock_irq(shost->host_lock);
/* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
return 0;
- fail:
+fail:
return -ENXIO;
}
@@ -411,6 +484,8 @@ static void
lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp = &rspiocb->iocb;
struct lpfc_nodelist *ndlp = cmdiocb->context1;
struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp;
@@ -418,21 +493,25 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
int rc;
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
+ if (lpfc_els_chk_latt(vport)) {
lpfc_nlp_put(ndlp);
goto out;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "FLOGI cmpl: status:x%x/x%x state:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ vport->port_state);
+
if (irsp->ulpStatus) {
/* Check for retry */
- if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
- /* ELS command is being retried */
+ if (lpfc_els_retry(phba, cmdiocb, rspiocb))
goto out;
- }
+
/* FLOGI failed, so there is no fabric */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
/* If private loop, then allow max outstanding els to be
* LPFC_MAX_DISC_THREADS (32). Scanning in the case of no
@@ -443,11 +522,10 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
/* FLOGI failure */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0100 FLOGI failure Data: x%x x%x x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0100 FLOGI failure Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
irsp->ulpStatus, irsp->un.ulpWord[4],
irsp->ulpTimeout);
goto flogifail;
@@ -463,21 +541,21 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* FLOGI completes successfully */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0101 FLOGI completes sucessfully "
+ "%d (%d):0101 FLOGI completes sucessfully "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
irsp->un.ulpWord[4], sp->cmn.e_d_tov,
sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
- if (phba->hba_state == LPFC_FLOGI) {
+ if (vport->port_state == LPFC_FLOGI) {
/*
* If Common Service Parameters indicate Nport
* we are point to point, if Fport we are Fabric.
*/
if (sp->cmn.fPort)
- rc = lpfc_cmpl_els_flogi_fabric(phba, ndlp, sp, irsp);
+ rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp);
else
- rc = lpfc_cmpl_els_flogi_nport(phba, ndlp, sp);
+ rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp);
if (!rc)
goto out;
@@ -486,14 +564,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
flogifail:
lpfc_nlp_put(ndlp);
- if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT ||
- (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED &&
- irsp->un.ulpWord[4] != IOERR_SLI_DOWN)) {
+ if (!lpfc_error_lost_link(irsp)) {
/* FLOGI failed, so just use loop map to make discovery list */
- lpfc_disc_list_loopmap(phba);
+ lpfc_disc_list_loopmap(vport);
/* Start discovery */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
}
out:
@@ -501,9 +577,10 @@ out:
}
static int
-lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
struct serv_parm *sp;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
@@ -515,9 +592,10 @@ lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
pring = &phba->sli.ring[LPFC_ELS_RING];
- cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_FLOGI);
+ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_FLOGI);
+
if (!elsiocb)
return 1;
@@ -526,8 +604,8 @@ lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
/* For FLOGI request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_FLOGI;
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
sp = (struct serv_parm *) pcmd;
/* Setup CSPs accordingly for Fabric */
@@ -541,16 +619,32 @@ lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
if (sp->cmn.fcphHigh < FC_PH3)
sp->cmn.fcphHigh = FC_PH3;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ sp->cmn.request_multiple_Nport = 1;
+
+ /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */
+ icmd->ulpCt_h = 1;
+ icmd->ulpCt_l = 0;
+ }
+
+ if (phba->fc_topology != TOPOLOGY_LOOP) {
+ icmd->un.elsreq64.myID = 0;
+ icmd->un.elsreq64.fl = 1;
+ }
+
tmo = phba->fc_ratov;
phba->fc_ratov = LPFC_DISC_FLOGI_TMO;
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
phba->fc_ratov = tmo;
phba->fc_stat.elsXmitFLOGI++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi;
- spin_lock_irq(phba->host->host_lock);
- rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue FLOGI: opt:x%x",
+ phba->sli3_options, 0, 0);
+
+ rc = lpfc_issue_fabric_iocb(phba, elsiocb);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -559,7 +653,7 @@ lpfc_issue_els_flogi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
}
int
-lpfc_els_abort_flogi(struct lpfc_hba * phba)
+lpfc_els_abort_flogi(struct lpfc_hba *phba)
{
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *iocb, *next_iocb;
@@ -577,73 +671,99 @@ lpfc_els_abort_flogi(struct lpfc_hba * phba)
* Check the txcmplq for an iocb that matches the nport the driver is
* searching for.
*/
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
icmd = &iocb->iocb;
- if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) {
+ if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
+ icmd->un.elsreq64.bdl.ulpIoTag32) {
ndlp = (struct lpfc_nodelist *)(iocb->context1);
- if (ndlp && (ndlp->nlp_DID == Fabric_DID))
+ if (ndlp && (ndlp->nlp_DID == Fabric_DID)) {
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
int
-lpfc_initial_flogi(struct lpfc_hba *phba)
+lpfc_initial_flogi(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
/* First look for the Fabric ndlp */
- ndlp = lpfc_findnode_did(phba, Fabric_DID);
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return 0;
- lpfc_nlp_init(phba, ndlp, Fabric_DID);
+ lpfc_nlp_init(vport, ndlp, Fabric_DID);
} else {
- lpfc_dequeue_node(phba, ndlp);
+ lpfc_dequeue_node(vport, ndlp);
}
- if (lpfc_issue_els_flogi(phba, ndlp, 0)) {
+ if (lpfc_issue_els_flogi(vport, ndlp, 0)) {
lpfc_nlp_put(ndlp);
}
return 1;
}
+int
+lpfc_initial_fdisc(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp;
+
+ /* First look for the Fabric ndlp */
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp) {
+ /* Cannot find existing Fabric ndlp, so allocate a new one */
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (!ndlp)
+ return 0;
+ lpfc_nlp_init(vport, ndlp, Fabric_DID);
+ } else {
+ lpfc_dequeue_node(vport, ndlp);
+ }
+ if (lpfc_issue_els_fdisc(vport, ndlp, 0)) {
+ lpfc_nlp_put(ndlp);
+ }
+ return 1;
+}
static void
-lpfc_more_plogi(struct lpfc_hba * phba)
+lpfc_more_plogi(struct lpfc_vport *vport)
{
int sentplogi;
+ struct lpfc_hba *phba = vport->phba;
- if (phba->num_disc_nodes)
- phba->num_disc_nodes--;
+ if (vport->num_disc_nodes)
+ vport->num_disc_nodes--;
/* Continue discovery with <num_disc_nodes> PLOGIs to go */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0232 Continue discovery with %d PLOGIs to go "
+ "%d (%d):0232 Continue discovery with %d PLOGIs to go "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->num_disc_nodes, phba->fc_plogi_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi, vport->num_disc_nodes,
+ vport->fc_plogi_cnt, vport->fc_flag, vport->port_state);
/* Check to see if there are more PLOGIs to be sent */
- if (phba->fc_flag & FC_NLP_MORE) {
- /* go thru NPR list and issue any remaining ELS PLOGIs */
- sentplogi = lpfc_els_disc_plogi(phba);
- }
+ if (vport->fc_flag & FC_NLP_MORE)
+ /* go thru NPR nodes and issue any remaining ELS PLOGIs */
+ sentplogi = lpfc_els_disc_plogi(vport);
+
return;
}
static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
+lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
struct lpfc_nodelist *ndlp)
{
+ struct lpfc_vport *vport = ndlp->vport;
struct lpfc_nodelist *new_ndlp;
- uint32_t *lp;
struct serv_parm *sp;
- uint8_t name[sizeof (struct lpfc_name)];
+ uint8_t name[sizeof(struct lpfc_name)];
uint32_t rc;
/* Fabric nodes can have the same WWPN so we don't bother searching
@@ -652,50 +772,51 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, struct lpfc_dmabuf *prsp,
if (ndlp->nlp_type & NLP_FABRIC)
return ndlp;
- lp = (uint32_t *) prsp->virt;
- sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+ sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t));
memset(name, 0, sizeof(struct lpfc_name));
/* Now we find out if the NPort we are logging into, matches the WWPN
* we have for that ndlp. If not, we have some work to do.
*/
- new_ndlp = lpfc_findnode_wwpn(phba, &sp->portName);
+ new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName);
if (new_ndlp == ndlp)
return ndlp;
if (!new_ndlp) {
- rc =
- memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
+ rc = memcmp(&ndlp->nlp_portname, name,
+ sizeof(struct lpfc_name));
if (!rc)
return ndlp;
new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
if (!new_ndlp)
return ndlp;
- lpfc_nlp_init(phba, new_ndlp, ndlp->nlp_DID);
+ lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID);
}
- lpfc_unreg_rpi(phba, new_ndlp);
+ lpfc_unreg_rpi(vport, new_ndlp);
new_ndlp->nlp_DID = ndlp->nlp_DID;
new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
- lpfc_nlp_set_state(phba, new_ndlp, ndlp->nlp_state);
+ lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state);
- /* Move this back to NPR list */
+ /* Move this back to NPR state */
if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
else {
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
}
return new_ndlp;
}
static void
-lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
struct lpfc_dmabuf *prsp;
@@ -705,32 +826,43 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
cmdiocb->context_un.rsp_iocb = rspiocb;
irsp = &rspiocb->iocb;
- ndlp = lpfc_findnode_did(phba, irsp->un.elsreq64.remoteID);
- if (!ndlp)
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "PLOGI cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.elsreq64.remoteID);
+
+ ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
+ if (!ndlp) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0136 PLOGI completes to NPort x%x "
+ "with no ndlp. Data: x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, irsp->un.elsreq64.remoteID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpIoTag);
goto out;
+ }
/* Since ndlp can be freed in the disc state machine, note if this node
* is being used during discovery.
*/
+ spin_lock_irq(shost->host_lock);
disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
- spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
rc = 0;
/* PLOGI completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0102 PLOGI completes to NPort x%x "
+ "%d (%d):0102 PLOGI completes to NPort x%x "
"Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->ulpTimeout, disc, vport->num_disc_nodes);
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
- spin_lock_irq(phba->host->host_lock);
+ if (lpfc_els_chk_latt(vport)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
goto out;
}
@@ -743,56 +875,62 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
/* ELS command is being retried */
if (disc) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
}
goto out;
}
/* PLOGI failed */
+ if (ndlp->nlp_DID == NameServer_DID) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0250 Nameserver login error: "
+ "0x%x / 0x%x\n",
+ phba->brd_no, vport->vpi,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+ }
+
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+ if (lpfc_error_lost_link(irsp)) {
rc = NLP_STE_FREED_NODE;
} else {
- rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_PLOGI);
+ rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PLOGI);
}
} else {
/* Good status, call state machine */
prsp = list_entry(((struct lpfc_dmabuf *)
- cmdiocb->context2)->list.next,
- struct lpfc_dmabuf, list);
- ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
- rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_PLOGI);
+ cmdiocb->context2)->list.next,
+ struct lpfc_dmabuf, list);
+ ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
+ rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PLOGI);
}
- if (disc && phba->num_disc_nodes) {
+ if (disc && vport->num_disc_nodes) {
/* Check to see if there are more PLOGIs to be sent */
- lpfc_more_plogi(phba);
+ lpfc_more_plogi(vport);
- if (phba->num_disc_nodes == 0) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ if (vport->num_disc_nodes == 0) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
- lpfc_can_disctmo(phba);
- if (phba->fc_flag & FC_RSCN_MODE) {
+ lpfc_can_disctmo(vport);
+ if (vport->fc_flag & FC_RSCN_MODE) {
/*
* Check to see if more RSCNs came in while
* we were processing this one.
*/
- if ((phba->fc_rscn_id_cnt == 0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->fc_rscn_id_cnt == 0) &&
+ (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
} else {
- lpfc_els_handle_rscn(phba);
+ lpfc_els_handle_rscn(vport);
}
}
}
@@ -804,8 +942,9 @@ out:
}
int
-lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
+lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
struct serv_parm *sp;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
@@ -813,13 +952,14 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
struct lpfc_sli *psli;
uint8_t *pcmd;
uint16_t cmdsize;
+ int ret;
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did,
- ELS_CMD_PLOGI);
+ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did,
+ ELS_CMD_PLOGI);
if (!elsiocb)
return 1;
@@ -828,8 +968,8 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
/* For PLOGI request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_PLOGI;
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
sp = (struct serv_parm *) pcmd;
if (sp->cmn.fcphLow < FC_PH_4_3)
@@ -838,22 +978,27 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
if (sp->cmn.fcphHigh < FC_PH3)
sp->cmn.fcphHigh = FC_PH3;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue PLOGI: did:x%x",
+ did, 0, 0);
+
phba->fc_stat.elsXmitPLOGI++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi;
- spin_lock_irq(phba->host->host_lock);
- if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
- spin_unlock_irq(phba->host->host_lock);
+ ret = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+
+ if (ret == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_sli *psli;
struct lpfc_nodelist *ndlp;
@@ -864,21 +1009,26 @@ lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
irsp = &(rspiocb->iocb);
ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_PRLI_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "PRLI cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ ndlp->nlp_DID);
/* PRLI completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0103 PRLI completes to NPort x%x "
+ "%d (%d):0103 PRLI completes to NPort x%x "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
+ vport->num_disc_nodes);
- phba->fc_prli_sent--;
+ vport->fc_prli_sent--;
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba))
+ if (lpfc_els_chk_latt(vport))
goto out;
if (irsp->ulpStatus) {
@@ -889,18 +1039,16 @@ lpfc_cmpl_els_prli(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
/* PRLI failed */
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+ if (lpfc_error_lost_link(irsp)) {
goto out;
} else {
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_PRLI);
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PRLI);
}
} else {
/* Good status, call state machine */
- lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI);
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_PRLI);
}
out:
@@ -909,9 +1057,11 @@ out:
}
int
-lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
PRLI *npr;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
@@ -923,9 +1073,9 @@ lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (PRLI));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_PRLI);
+ cmdsize = (sizeof(uint32_t) + sizeof(PRLI));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_PRLI);
if (!elsiocb)
return 1;
@@ -933,9 +1083,9 @@ lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
/* For PRLI request, remainder of payload is service parameters */
- memset(pcmd, 0, (sizeof (PRLI) + sizeof (uint32_t)));
+ memset(pcmd, 0, (sizeof(PRLI) + sizeof(uint32_t)));
*((uint32_t *) (pcmd)) = ELS_CMD_PRLI;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* For PRLI, remainder of payload is PRLI parameter page */
npr = (PRLI *) pcmd;
@@ -955,81 +1105,88 @@ lpfc_issue_els_prli(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
npr->prliType = PRLI_FCP_TYPE;
npr->initiatorFunc = 1;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue PRLI: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
phba->fc_stat.elsXmitPRLI++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_prli;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_PRLI_SND;
+ spin_unlock_irq(shost->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_PRLI_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
- phba->fc_prli_sent++;
+ vport->fc_prli_sent++;
return 0;
}
static void
-lpfc_more_adisc(struct lpfc_hba * phba)
+lpfc_more_adisc(struct lpfc_vport *vport)
{
int sentadisc;
+ struct lpfc_hba *phba = vport->phba;
- if (phba->num_disc_nodes)
- phba->num_disc_nodes--;
+ if (vport->num_disc_nodes)
+ vport->num_disc_nodes--;
/* Continue discovery with <num_disc_nodes> ADISCs to go */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0210 Continue discovery with %d ADISCs to go "
+ "%d (%d):0210 Continue discovery with %d ADISCs to go "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->num_disc_nodes, phba->fc_adisc_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi, vport->num_disc_nodes,
+ vport->fc_adisc_cnt, vport->fc_flag, vport->port_state);
/* Check to see if there are more ADISCs to be sent */
- if (phba->fc_flag & FC_NLP_MORE) {
- lpfc_set_disctmo(phba);
-
- /* go thru NPR list and issue any remaining ELS ADISCs */
- sentadisc = lpfc_els_disc_adisc(phba);
+ if (vport->fc_flag & FC_NLP_MORE) {
+ lpfc_set_disctmo(vport);
+ /* go thru NPR nodes and issue any remaining ELS ADISCs */
+ sentadisc = lpfc_els_disc_adisc(vport);
}
return;
}
static void
-lpfc_rscn_disc(struct lpfc_hba * phba)
+lpfc_rscn_disc(struct lpfc_vport *vport)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ lpfc_can_disctmo(vport);
+
/* RSCN discovery */
- /* go thru NPR list and issue ELS PLOGIs */
- if (phba->fc_npr_cnt) {
- if (lpfc_els_disc_plogi(phba))
+ /* go thru NPR nodes and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ if (lpfc_els_disc_plogi(vport))
return;
- }
- if (phba->fc_flag & FC_RSCN_MODE) {
+
+ if (vport->fc_flag & FC_RSCN_MODE) {
/* Check to see if more RSCNs came in while we were
* processing this one.
*/
- if ((phba->fc_rscn_id_cnt == 0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->fc_rscn_id_cnt == 0) &&
+ (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
} else {
- lpfc_els_handle_rscn(phba);
+ lpfc_els_handle_rscn(vport);
}
}
}
static void
-lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
- struct lpfc_sli *psli;
struct lpfc_nodelist *ndlp;
- LPFC_MBOXQ_t *mbox;
- int disc, rc;
-
- psli = &phba->sli;
+ int disc;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
@@ -1037,27 +1194,32 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
irsp = &(rspiocb->iocb);
ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "ADISC cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ ndlp->nlp_DID);
+
/* Since ndlp can be freed in the disc state machine, note if this node
* is being used during discovery.
*/
+ spin_lock_irq(shost->host_lock);
disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
- spin_lock_irq(phba->host->host_lock);
ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
/* ADISC completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0104 ADISC completes to NPort x%x "
+ "%d (%d):0104 ADISC completes to NPort x%x "
"Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout, disc,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
+ disc, vport->num_disc_nodes);
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
- spin_lock_irq(phba->host->host_lock);
+ if (lpfc_els_chk_latt(vport)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
goto out;
}
@@ -1066,67 +1228,68 @@ lpfc_cmpl_els_adisc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
/* ELS command is being retried */
if (disc) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_set_disctmo(phba);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_set_disctmo(vport);
}
goto out;
}
/* ADISC failed */
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
- ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) &&
- (irsp->un.ulpWord[4] != IOERR_LINK_DOWN) &&
- (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) {
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_ADISC);
+ if (!lpfc_error_lost_link(irsp)) {
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_ADISC);
}
} else {
/* Good status, call state machine */
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_ADISC);
}
- if (disc && phba->num_disc_nodes) {
+ if (disc && vport->num_disc_nodes) {
/* Check to see if there are more ADISCs to be sent */
- lpfc_more_adisc(phba);
+ lpfc_more_adisc(vport);
/* Check to see if we are done with ADISC authentication */
- if (phba->num_disc_nodes == 0) {
- lpfc_can_disctmo(phba);
- /* If we get here, there is nothing left to wait for */
- if ((phba->hba_state < LPFC_HBA_READY) &&
- (phba->hba_state != LPFC_CLEAR_LA)) {
- /* Link up discovery */
- if ((mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL))) {
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, mbox);
- mbox->mbox_cmpl =
- lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox
- (phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(mbox,
- phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].
- flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].
- flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].
- flag &=
- ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state =
- LPFC_HBA_READY;
+ if (vport->num_disc_nodes == 0) {
+ /* If we get here, there is nothing left to ADISC */
+ /*
+ * For NPIV, cmpl_reg_vpi will set port_state to READY,
+ * and continue discovery.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ !(vport->fc_flag & FC_RSCN_MODE)) {
+ lpfc_issue_reg_vpi(phba, vport);
+ goto out;
+ }
+ /*
+ * For SLI2, we need to set port_state to READY
+ * and continue discovery.
+ */
+ if (vport->port_state < LPFC_VPORT_READY) {
+ /* If we get here, there is nothing to ADISC */
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_issue_clear_la(phba, vport);
+
+ if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
+ vport->num_disc_nodes = 0;
+ /* go thru NPR list, issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
+
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &=
+ ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(
+ shost->host_lock);
+ lpfc_can_disctmo(vport);
}
}
+ vport->port_state = LPFC_VPORT_READY;
} else {
- lpfc_rscn_disc(phba);
+ lpfc_rscn_disc(vport);
}
}
}
@@ -1136,23 +1299,22 @@ out:
}
int
-lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
ADISC *ap;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
- struct lpfc_sli_ring *pring;
- struct lpfc_sli *psli;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
uint8_t *pcmd;
uint16_t cmdsize;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
-
- cmdsize = (sizeof (uint32_t) + sizeof (ADISC));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_ADISC);
+ cmdsize = (sizeof(uint32_t) + sizeof(ADISC));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ADISC);
if (!elsiocb)
return 1;
@@ -1161,81 +1323,97 @@ lpfc_issue_els_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
/* For ADISC request, remainder of payload is service parameters */
*((uint32_t *) (pcmd)) = ELS_CMD_ADISC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* Fill in ADISC payload */
ap = (ADISC *) pcmd;
ap->hardAL_PA = phba->fc_pref_ALPA;
- memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
- ap->DID = be32_to_cpu(phba->fc_myDID);
+ memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
+ ap->DID = be32_to_cpu(vport->fc_myDID);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue ADISC: did:x%x",
+ ndlp->nlp_DID, 0, 0);
phba->fc_stat.elsXmitADISC++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_ADISC_SND;
+ spin_unlock_irq(shost->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_ADISC_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_logo(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
IOCB_t *irsp;
struct lpfc_sli *psli;
- struct lpfc_nodelist *ndlp;
psli = &phba->sli;
/* we pass cmdiocb to state machine which needs rspiocb as well */
cmdiocb->context_un.rsp_iocb = rspiocb;
irsp = &(rspiocb->iocb);
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "LOGO cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ ndlp->nlp_DID);
/* LOGO completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0105 LOGO completes to NPort x%x "
+ "%d (%d):0105 LOGO completes to NPort x%x "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, irsp->ulpStatus,
- irsp->un.ulpWord[4], irsp->ulpTimeout,
- phba->num_disc_nodes);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
+ vport->num_disc_nodes);
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba))
+ if (lpfc_els_chk_latt(vport))
goto out;
+ if (ndlp->nlp_flag & NLP_TARGET_REMOVE) {
+ /* NLP_EVT_DEVICE_RM should unregister the RPI
+ * which should abort all outstanding IOs.
+ */
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_DEVICE_RM);
+ goto out;
+ }
+
if (irsp->ulpStatus) {
/* Check for retry */
- if (lpfc_els_retry(phba, cmdiocb, rspiocb)) {
+ if (lpfc_els_retry(phba, cmdiocb, rspiocb))
/* ELS command is being retried */
goto out;
- }
/* LOGO failed */
/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
- if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN))) {
+ if (lpfc_error_lost_link(irsp))
goto out;
- } else {
- lpfc_disc_state_machine(phba, ndlp, cmdiocb,
- NLP_EVT_CMPL_LOGO);
- }
+ else
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_LOGO);
} else {
/* Good status, call state machine.
* This will unregister the rpi if needed.
*/
- lpfc_disc_state_machine(phba, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO);
+ lpfc_disc_state_machine(vport, ndlp, cmdiocb,
+ NLP_EVT_CMPL_LOGO);
}
out:
@@ -1244,75 +1422,91 @@ out:
}
int
-lpfc_issue_els_logo(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
uint8_t retry)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
struct lpfc_sli *psli;
uint8_t *pcmd;
uint16_t cmdsize;
+ int rc;
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING];
- cmdsize = (2 * sizeof (uint32_t)) + sizeof (struct lpfc_name);
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_LOGO);
+ cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name);
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_LOGO);
if (!elsiocb)
return 1;
icmd = &elsiocb->iocb;
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* Fill in LOGO payload */
- *((uint32_t *) (pcmd)) = be32_to_cpu(phba->fc_myDID);
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_portname, sizeof (struct lpfc_name));
+ *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue LOGO: did:x%x",
+ ndlp->nlp_DID, 0, 0);
phba->fc_stat.elsXmitLOGO++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_logo;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_SND;
- if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_unlock_irq(shost->host_lock);
+ rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+
+ if (rc == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_SND;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_cmd(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
IOCB_t *irsp;
irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "ELS cmd cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.elsreq64.remoteID);
+
/* ELS cmd tag <ulpIoTag> completes */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0106 ELS cmd tag x%x completes Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
irsp->ulpIoTag, irsp->ulpStatus,
irsp->un.ulpWord[4], irsp->ulpTimeout);
/* Check to see if link went down during discovery */
- lpfc_els_chk_latt(phba);
+ lpfc_els_chk_latt(vport);
lpfc_els_free_iocb(phba, cmdiocb);
return;
}
int
-lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
+lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
@@ -1323,15 +1517,16 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (SCR));
+ cmdsize = (sizeof(uint32_t) + sizeof(SCR));
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return 1;
- lpfc_nlp_init(phba, ndlp, nportid);
+ lpfc_nlp_init(vport, ndlp, nportid);
+
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_SCR);
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_SCR);
if (!elsiocb) {
lpfc_nlp_put(ndlp);
return 1;
@@ -1341,29 +1536,31 @@ lpfc_issue_els_scr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_SCR;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* For SCR, remainder of payload is SCR parameter page */
- memset(pcmd, 0, sizeof (SCR));
+ memset(pcmd, 0, sizeof(SCR));
((SCR *) pcmd)->Function = SCR_FUNC_FULL;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue SCR: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
phba->fc_stat.elsXmitSCR++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
- spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
return 0;
}
static int
-lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
+lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry)
{
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
@@ -1377,14 +1574,15 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = (sizeof (uint32_t) + sizeof (FARP));
+ cmdsize = (sizeof(uint32_t) + sizeof(FARP));
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return 1;
- lpfc_nlp_init(phba, ndlp, nportid);
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, ndlp,
- ndlp->nlp_DID, ELS_CMD_RNID);
+ lpfc_nlp_init(vport, ndlp, nportid);
+
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_RNID);
if (!elsiocb) {
lpfc_nlp_put(ndlp);
return 1;
@@ -1394,44 +1592,71 @@ lpfc_issue_els_farpr(struct lpfc_hba * phba, uint32_t nportid, uint8_t retry)
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_FARPR;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* Fill in FARPR payload */
fp = (FARP *) (pcmd);
- memset(fp, 0, sizeof (FARP));
+ memset(fp, 0, sizeof(FARP));
lp = (uint32_t *) pcmd;
*lp++ = be32_to_cpu(nportid);
- *lp++ = be32_to_cpu(phba->fc_myDID);
+ *lp++ = be32_to_cpu(vport->fc_myDID);
fp->Rflags = 0;
fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE);
- memcpy(&fp->RportName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&fp->RnodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
- if ((ondlp = lpfc_findnode_did(phba, nportid))) {
+ memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
+ ondlp = lpfc_findnode_did(vport, nportid);
+ if (ondlp) {
memcpy(&fp->OportName, &ondlp->nlp_portname,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
memcpy(&fp->OnodeName, &ondlp->nlp_nodename,
- sizeof (struct lpfc_name));
+ sizeof(struct lpfc_name));
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue FARPR: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
phba->fc_stat.elsXmitFARPR++;
elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd;
- spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
lpfc_els_free_iocb(phba, elsiocb);
return 1;
}
- spin_unlock_irq(phba->host->host_lock);
lpfc_nlp_put(ndlp);
return 0;
}
+static void
+lpfc_end_rscn(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ /*
+ * Check to see if more RSCNs came in while we were
+ * processing this one.
+ */
+ if (vport->fc_rscn_id_cnt ||
+ (vport->fc_flag & FC_RSCN_DISCOVERY) != 0)
+ lpfc_els_handle_rscn(vport);
+ else {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ }
+ }
+}
+
void
-lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp)
+lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_DELAY_TMO;
+ spin_unlock_irq(shost->host_lock);
del_timer_sync(&nlp->nlp_delayfunc);
nlp->nlp_last_elscmd = 0;
@@ -1439,30 +1664,21 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp)
list_del_init(&nlp->els_retry_evt.evt_listp);
if (nlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
nlp->nlp_flag &= ~NLP_NPR_2B_DISC;
- if (phba->num_disc_nodes) {
+ spin_unlock_irq(shost->host_lock);
+ if (vport->num_disc_nodes) {
/* Check to see if there are more
* PLOGIs to be sent
*/
- lpfc_more_plogi(phba);
-
- if (phba->num_disc_nodes == 0) {
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- lpfc_can_disctmo(phba);
- if (phba->fc_flag & FC_RSCN_MODE) {
- /*
- * Check to see if more RSCNs
- * came in while we were
- * processing this one.
- */
- if((phba->fc_rscn_id_cnt==0) &&
- !(phba->fc_flag & FC_RSCN_DISCOVERY)) {
- phba->fc_flag &= ~FC_RSCN_MODE;
- }
- else {
- lpfc_els_handle_rscn(phba);
- }
- }
+ lpfc_more_plogi(vport);
+
+ if (vport->num_disc_nodes == 0) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
+ lpfc_end_rscn(vport);
}
}
}
@@ -1472,18 +1688,19 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_hba *phba, struct lpfc_nodelist * nlp)
void
lpfc_els_retry_delay(unsigned long ptr)
{
- struct lpfc_nodelist *ndlp;
- struct lpfc_hba *phba;
- unsigned long iflag;
- struct lpfc_work_evt *evtp;
-
- ndlp = (struct lpfc_nodelist *)ptr;
- phba = ndlp->nlp_phba;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct lpfc_hba *phba = vport->phba;
+ unsigned long flags;
+ struct lpfc_work_evt *evtp = &ndlp->els_retry_evt;
+
+ ndlp = (struct lpfc_nodelist *) ptr;
+ phba = ndlp->vport->phba;
evtp = &ndlp->els_retry_evt;
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, flags);
if (!list_empty(&evtp->evt_listp)) {
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
@@ -1491,33 +1708,31 @@ lpfc_els_retry_delay(unsigned long ptr)
evtp->evt = LPFC_EVT_ELS_RETRY;
list_add_tail(&evtp->evt_listp, &phba->work_list);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return;
}
void
lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
{
- struct lpfc_hba *phba;
- uint32_t cmd;
- uint32_t did;
- uint8_t retry;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ uint32_t cmd, did, retry;
- phba = ndlp->nlp_phba;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
did = ndlp->nlp_DID;
cmd = ndlp->nlp_last_elscmd;
ndlp->nlp_last_elscmd = 0;
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
return;
}
ndlp->nlp_flag &= ~NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
/*
* If a discovery event readded nlp_delayfunc after timer
* firing and before processing the timer, cancel the
@@ -1528,57 +1743,54 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
switch (cmd) {
case ELS_CMD_FLOGI:
- lpfc_issue_els_flogi(phba, ndlp, retry);
+ lpfc_issue_els_flogi(vport, ndlp, retry);
break;
case ELS_CMD_PLOGI:
- if(!lpfc_issue_els_plogi(phba, ndlp->nlp_DID, retry)) {
+ if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
}
break;
case ELS_CMD_ADISC:
- if (!lpfc_issue_els_adisc(phba, ndlp, retry)) {
+ if (!lpfc_issue_els_adisc(vport, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
}
break;
case ELS_CMD_PRLI:
- if (!lpfc_issue_els_prli(phba, ndlp, retry)) {
+ if (!lpfc_issue_els_prli(vport, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
}
break;
case ELS_CMD_LOGO:
- if (!lpfc_issue_els_logo(phba, ndlp, retry)) {
+ if (!lpfc_issue_els_logo(vport, ndlp, retry)) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
}
break;
+ case ELS_CMD_FDISC:
+ lpfc_issue_els_fdisc(vport, ndlp, retry);
+ break;
}
return;
}
static int
-lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- IOCB_t *irsp;
- struct lpfc_dmabuf *pcmd;
- struct lpfc_nodelist *ndlp;
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
uint32_t *elscmd;
struct ls_rjt stat;
- int retry, maxretry;
- int delay;
- uint32_t cmd;
+ int retry = 0, maxretry = lpfc_max_els_tries, delay = 0;
+ uint32_t cmd = 0;
uint32_t did;
- retry = 0;
- delay = 0;
- maxretry = lpfc_max_els_tries;
- irsp = &rspiocb->iocb;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- cmd = 0;
/* Note: context2 may be 0 for internal driver abort
* of delays ELS command.
@@ -1594,11 +1806,15 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
else {
/* We should only hit this case for retrying PLOGI */
did = irsp->un.elsreq64.remoteID;
- ndlp = lpfc_findnode_did(phba, did);
+ ndlp = lpfc_findnode_did(vport, did);
if (!ndlp && (cmd != ELS_CMD_PLOGI))
return 1;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Retry ELS: wd7:x%x wd4:x%x did:x%x",
+ *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID);
+
switch (irsp->ulpStatus) {
case IOSTAT_FCP_RSP_ERROR:
case IOSTAT_REMOTE_STOP:
@@ -1607,25 +1823,37 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
case IOSTAT_LOCAL_REJECT:
switch ((irsp->un.ulpWord[4] & 0xff)) {
case IOERR_LOOP_OPEN_FAILURE:
- if (cmd == ELS_CMD_PLOGI) {
- if (cmdiocb->retry == 0) {
- delay = 1;
- }
- }
+ if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0)
+ delay = 1000;
retry = 1;
break;
- case IOERR_SEQUENCE_TIMEOUT:
- retry = 1;
+ case IOERR_ILLEGAL_COMMAND:
+ if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
+ (cmd == ELS_CMD_FDISC)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0124 FDISC failed (3/6) retrying...\n",
+ phba->brd_no, vport->vpi);
+ lpfc_mbx_unreg_vpi(vport);
+ retry = 1;
+ /* Always retry for this case */
+ cmdiocb->retry = 0;
+ }
break;
case IOERR_NO_RESOURCES:
- if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
- }
+ retry = 1;
+ if (cmdiocb->retry > 100)
+ delay = 100;
+ maxretry = 250;
+ break;
+
+ case IOERR_ILLEGAL_FRAME:
+ delay = 100;
retry = 1;
break;
+ case IOERR_SEQUENCE_TIMEOUT:
case IOERR_INVALID_RPI:
retry = 1;
break;
@@ -1655,27 +1883,57 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (stat.un.b.lsRjtRsnCodeExp ==
LSEXP_CMD_IN_PROGRESS) {
if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
+ delay = 1000;
maxretry = 48;
}
retry = 1;
break;
}
if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
+ delay = 1000;
maxretry = lpfc_max_els_tries + 1;
retry = 1;
break;
}
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (cmd == ELS_CMD_FDISC) &&
+ (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0125 FDISC Failed (x%x)."
+ " Fabric out of resources\n",
+ phba->brd_no, vport->vpi, stat.un.lsRjtError);
+ lpfc_vport_set_state(vport,
+ FC_VPORT_NO_FABRIC_RSCS);
+ }
break;
case LSRJT_LOGICAL_BSY:
- if (cmd == ELS_CMD_PLOGI) {
- delay = 1;
+ if ((cmd == ELS_CMD_PLOGI) ||
+ (cmd == ELS_CMD_PRLI)) {
+ delay = 1000;
maxretry = 48;
+ } else if (cmd == ELS_CMD_FDISC) {
+ /* Always retry for this case */
+ cmdiocb->retry = 0;
}
retry = 1;
break;
+
+ case LSRJT_LOGICAL_ERR:
+ case LSRJT_PROTOCOL_ERR:
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (cmd == ELS_CMD_FDISC) &&
+ ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
+ (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
+ ) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0123 FDISC Failed (x%x)."
+ " Fabric Detected Bad WWN\n",
+ phba->brd_no, vport->vpi, stat.un.lsRjtError);
+ lpfc_vport_set_state(vport,
+ FC_VPORT_FABRIC_REJ_WWN);
+ }
+ break;
}
break;
@@ -1695,21 +1953,27 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
retry = 0;
}
+ if ((vport->load_flag & FC_UNLOADING) != 0)
+ retry = 0;
+
if (retry) {
/* Retry ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0107 Retry ELS command x%x to remote "
+ "%d (%d):0107 Retry ELS command x%x to remote "
"NPORT x%x Data: x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
cmd, did, cmdiocb->retry, delay);
- if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) {
+ if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
+ ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
+ ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) {
+ /* Don't reset timer for no resources */
+
/* If discovery / RSCN timer is running, reset it */
- if (timer_pending(&phba->fc_disctmo) ||
- (phba->fc_flag & FC_RSCN_MODE)) {
- lpfc_set_disctmo(phba);
- }
+ if (timer_pending(&vport->fc_disctmo) ||
+ (vport->fc_flag & FC_RSCN_MODE))
+ lpfc_set_disctmo(vport);
}
phba->fc_stat.elsXmitRetry++;
@@ -1717,50 +1981,62 @@ lpfc_els_retry(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
phba->fc_stat.elsDelayRetry++;
ndlp->nlp_retry = cmdiocb->retry;
- mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
+ /* delay is specified in milliseconds */
+ mod_timer(&ndlp->nlp_delayfunc,
+ jiffies + msecs_to_jiffies(delay));
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ if (cmd == ELS_CMD_PRLI)
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_REG_LOGIN_ISSUE);
+ else
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_NPR_NODE);
ndlp->nlp_last_elscmd = cmd;
return 1;
}
switch (cmd) {
case ELS_CMD_FLOGI:
- lpfc_issue_els_flogi(phba, ndlp, cmdiocb->retry);
+ lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry);
+ return 1;
+ case ELS_CMD_FDISC:
+ lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_PLOGI:
if (ndlp) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_PLOGI_ISSUE);
}
- lpfc_issue_els_plogi(phba, did, cmdiocb->retry);
+ lpfc_issue_els_plogi(vport, did, cmdiocb->retry);
return 1;
case ELS_CMD_ADISC:
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, cmdiocb->retry);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_PRLI:
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
- lpfc_issue_els_prli(phba, ndlp, cmdiocb->retry);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
+ lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry);
return 1;
case ELS_CMD_LOGO:
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- lpfc_issue_els_logo(phba, ndlp, cmdiocb->retry);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry);
return 1;
}
}
/* No retry ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0108 No retry ELS command x%x to remote NPORT x%x "
- "Data: x%x\n",
- phba->brd_no,
+ "%d (%d):0108 No retry ELS command x%x to remote "
+ "NPORT x%x Data: x%x\n",
+ phba->brd_no, vport->vpi,
cmd, did, cmdiocb->retry);
return 0;
@@ -1795,33 +2071,36 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb)
lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
kfree(buf_ptr);
}
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, elsiocb);
- spin_unlock_irq(phba->host->host_lock);
return 0;
}
static void
-lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- struct lpfc_nodelist *ndlp;
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "ACC LOGO cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
/* ACC to LOGO completes to NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0109 ACC to LOGO completes to NPort x%x "
+ "%d (%d):0109 ACC to LOGO completes to NPort x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
+ phba->brd_no, vport->vpi, ndlp->nlp_DID,
+ ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
switch (ndlp->nlp_state) {
case NLP_STE_UNUSED_NODE: /* node is just allocated */
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case NLP_STE_NPR_NODE: /* NPort Recovery mode */
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
break;
default:
break;
@@ -1830,24 +2109,38 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
return;
}
+void
+lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+
+ pmb->context1 = NULL;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ mempool_free(pmb, phba->mbox_mem_pool);
+ lpfc_nlp_put(ndlp);
+ return;
+}
+
static void
-lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
struct lpfc_iocbq *rspiocb)
{
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL;
+ struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL;
IOCB_t *irsp;
- struct lpfc_nodelist *ndlp;
LPFC_MBOXQ_t *mbox = NULL;
- struct lpfc_dmabuf *mp;
+ struct lpfc_dmabuf *mp = NULL;
irsp = &rspiocb->iocb;
- ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
if (cmdiocb->context_un.mbox)
mbox = cmdiocb->context_un.mbox;
-
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba) || !ndlp) {
+ if (!ndlp || lpfc_els_chk_latt(vport)) {
if (mbox) {
mp = (struct lpfc_dmabuf *) mbox->context1;
if (mp) {
@@ -1859,24 +2152,37 @@ lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "ACC cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4],
+ irsp->un.rcvels.remoteID);
+
/* ELS response tag <ulpIoTag> completes */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0110 ELS response tag x%x completes "
+ "%d (%d):0110 ELS response tag x%x completes "
"Data: x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
- ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
ndlp->nlp_rpi);
if (mbox) {
if ((rspiocb->iocb.ulpStatus == 0)
&& (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
- lpfc_unreg_rpi(phba, ndlp);
- mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+ lpfc_unreg_rpi(vport, ndlp);
mbox->context2 = lpfc_nlp_get(ndlp);
- ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+ mbox->vport = vport;
+ if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) {
+ mbox->mbox_flag |= LPFC_MBX_IMED_UNREG;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+ }
+ else {
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+ ndlp->nlp_prev_state = ndlp->nlp_state;
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_REG_LOGIN_ISSUE);
+ }
if (lpfc_sli_issue_mbox(phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB))
!= MBX_NOT_FINISHED) {
@@ -1886,15 +2192,11 @@ lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
/* NOTE: we should have messages for unsuccessful
reglogin */
} else {
- /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
- if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
- (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
- (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
- if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
- lpfc_drop_node(phba, ndlp);
- ndlp = NULL;
- }
+ /* Do not drop node for lpfc_els_abort'ed ELS cmds */
+ if (!lpfc_error_lost_link(irsp) &&
+ ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+ lpfc_drop_node(vport, ndlp);
+ ndlp = NULL;
}
}
mp = (struct lpfc_dmabuf *) mbox->context1;
@@ -1906,19 +2208,21 @@ lpfc_cmpl_els_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
}
out:
if (ndlp) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_ACC_REGLOGIN;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI);
+ spin_unlock_irq(shost->host_lock);
}
lpfc_els_free_iocb(phba, cmdiocb);
return;
}
int
-lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp,
- LPFC_MBOXQ_t * mbox, uint8_t newnode)
+lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
+ LPFC_MBOXQ_t *mbox, uint8_t newnode)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb;
@@ -1935,23 +2239,30 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
switch (flag) {
case ELS_CMD_ACC:
- cmdsize = sizeof (uint32_t);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ cmdsize = sizeof(uint32_t);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
+ ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_ACC;
+ spin_unlock_irq(shost->host_lock);
return 1;
}
+
icmd = &elsiocb->iocb;
icmd->ulpContext = oldcmd->ulpContext; /* Xri */
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
case ELS_CMD_PLOGI:
- cmdsize = (sizeof (struct serv_parm) + sizeof (uint32_t));
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t));
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
+ ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -1963,12 +2274,16 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
elsiocb->context_un.mbox = mbox;
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
- memcpy(pcmd, &phba->fc_sparam, sizeof (struct serv_parm));
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC PLOGI: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
case ELS_CMD_PRLO:
- cmdsize = sizeof (uint32_t) + sizeof (PRLO);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
+ cmdsize = sizeof(uint32_t) + sizeof(PRLO);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry,
ndlp, ndlp->nlp_DID, ELS_CMD_PRLO);
if (!elsiocb)
return 1;
@@ -1978,10 +2293,14 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt,
- sizeof (uint32_t) + sizeof (PRLO));
+ sizeof(uint32_t) + sizeof(PRLO));
*((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC;
els_pkt_ptr = (ELS_PKT *) pcmd;
els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC PRLO: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
break;
default:
return 1;
@@ -1994,25 +2313,23 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
/* Xmit ELS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+ "%d (%d):0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
"DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
if (ndlp->nlp_flag & NLP_LOGO_ACC) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_LOGO_ACC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc;
} else {
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
}
phba->fc_stat.elsXmitACC++;
- spin_lock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2021,9 +2338,11 @@ lpfc_els_rsp_acc(struct lpfc_hba * phba, uint32_t flag,
}
int
-lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
+ LPFC_MBOXQ_t *mbox)
{
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *icmd;
IOCB_t *oldcmd;
struct lpfc_iocbq *elsiocb;
@@ -2036,9 +2355,9 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = 2 * sizeof (uint32_t);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_LS_RJT);
+ cmdsize = 2 * sizeof(uint32_t);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_LS_RJT);
if (!elsiocb)
return 1;
@@ -2048,22 +2367,30 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
*((uint32_t *) (pcmd)) = rejectError;
+ if (mbox) {
+ elsiocb->context_un.mbox = mbox;
+ elsiocb->context1 = lpfc_nlp_get(ndlp);
+ }
+
/* Xmit ELS RJT <err> response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0129 Xmit ELS RJT x%x response tag x%x xri x%x, "
- "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, rejectError, elsiocb->iotag,
+ "%d (%d):0129 Xmit ELS RJT x%x response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ phba->brd_no, vport->vpi, rejectError, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue LS_RJT: did:x%x flg:x%x err:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
+
phba->fc_stat.elsXmitLSRJT++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
- spin_lock_irq(phba->host->host_lock);
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2072,25 +2399,22 @@ lpfc_els_rsp_reject(struct lpfc_hba * phba, uint32_t rejectError,
}
int
-lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
+ struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
ADISC *ap;
- IOCB_t *icmd;
- IOCB_t *oldcmd;
+ IOCB_t *icmd, *oldcmd;
struct lpfc_iocbq *elsiocb;
- struct lpfc_sli_ring *pring;
- struct lpfc_sli *psli;
uint8_t *pcmd;
uint16_t cmdsize;
int rc;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
-
- cmdsize = sizeof (uint32_t) + sizeof (ADISC);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ cmdsize = sizeof(uint32_t) + sizeof(ADISC);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -2100,28 +2424,30 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
/* Xmit ADISC ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0130 Xmit ADISC ACC response iotag x%x xri: "
+ "%d (%d):0130 Xmit ADISC ACC response iotag x%x xri: "
"x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
ap = (ADISC *) (pcmd);
ap->hardAL_PA = phba->fc_pref_ALPA;
- memcpy(&ap->portName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&ap->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
- ap->DID = be32_to_cpu(phba->fc_myDID);
+ memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
+ ap->DID = be32_to_cpu(vport->fc_myDID);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC ADISC: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
phba->fc_stat.elsXmitACC++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
- spin_lock_irq(phba->host->host_lock);
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2130,9 +2456,10 @@ lpfc_els_rsp_adisc_acc(struct lpfc_hba * phba,
}
int
-lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
+lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb,
struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
PRLI *npr;
lpfc_vpd_t *vpd;
IOCB_t *icmd;
@@ -2147,8 +2474,8 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
- cmdsize = sizeof (uint32_t) + sizeof (PRLI);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry, ndlp,
+ cmdsize = sizeof(uint32_t) + sizeof(PRLI);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)));
if (!elsiocb)
return 1;
@@ -2159,19 +2486,19 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
/* Xmit PRLI ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0131 Xmit PRLI ACC response tag x%x xri x%x, "
+ "%d (%d):0131 Xmit PRLI ACC response tag x%x xri x%x, "
"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
/* For PRLI, remainder of payload is PRLI parameter page */
- memset(pcmd, 0, sizeof (PRLI));
+ memset(pcmd, 0, sizeof(PRLI));
npr = (PRLI *) pcmd;
vpd = &phba->vpd;
@@ -2193,12 +2520,14 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
npr->prliType = PRLI_FCP_TYPE;
npr->initiatorFunc = 1;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC PRLI: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
phba->fc_stat.elsXmitACC++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
- spin_lock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2207,12 +2536,12 @@ lpfc_els_rsp_prli_acc(struct lpfc_hba *phba, struct lpfc_iocbq *oldiocb,
}
static int
-lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
+lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format,
struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
RNID *rn;
- IOCB_t *icmd;
- IOCB_t *oldcmd;
+ IOCB_t *icmd, *oldcmd;
struct lpfc_iocbq *elsiocb;
struct lpfc_sli_ring *pring;
struct lpfc_sli *psli;
@@ -2223,13 +2552,13 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
psli = &phba->sli;
pring = &psli->ring[LPFC_ELS_RING];
- cmdsize = sizeof (uint32_t) + sizeof (uint32_t)
- + (2 * sizeof (struct lpfc_name));
+ cmdsize = sizeof(uint32_t) + sizeof(uint32_t)
+ + (2 * sizeof(struct lpfc_name));
if (format)
- cmdsize += sizeof (RNID_TOP_DISC);
+ cmdsize += sizeof(RNID_TOP_DISC);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -2239,30 +2568,30 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
/* Xmit RNID ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0132 Xmit RNID ACC response tag x%x "
+ "%d (%d):0132 Xmit RNID ACC response tag x%x "
"xri x%x\n",
- phba->brd_no, elsiocb->iotag,
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext);
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t);
+ pcmd += sizeof(uint32_t);
- memset(pcmd, 0, sizeof (RNID));
+ memset(pcmd, 0, sizeof(RNID));
rn = (RNID *) (pcmd);
rn->Format = format;
- rn->CommonLen = (2 * sizeof (struct lpfc_name));
- memcpy(&rn->portName, &phba->fc_portname, sizeof (struct lpfc_name));
- memcpy(&rn->nodeName, &phba->fc_nodename, sizeof (struct lpfc_name));
+ rn->CommonLen = (2 * sizeof(struct lpfc_name));
+ memcpy(&rn->portName, &vport->fc_portname, sizeof(struct lpfc_name));
+ memcpy(&rn->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
switch (format) {
case 0:
rn->SpecificLen = 0;
break;
case RNID_TOPOLOGY_DISC:
- rn->SpecificLen = sizeof (RNID_TOP_DISC);
+ rn->SpecificLen = sizeof(RNID_TOP_DISC);
memcpy(&rn->un.topologyDisc.portName,
- &phba->fc_portname, sizeof (struct lpfc_name));
+ &vport->fc_portname, sizeof(struct lpfc_name));
rn->un.topologyDisc.unitType = RNID_HBA;
rn->un.topologyDisc.physPort = 0;
rn->un.topologyDisc.attachedNodes = 0;
@@ -2273,15 +2602,17 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
break;
}
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
+ "Issue ACC RNID: did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
phba->fc_stat.elsXmitACC++;
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
lpfc_nlp_put(ndlp);
elsiocb->context1 = NULL; /* Don't need ndlp for cmpl,
* it could be freed */
- spin_lock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
- spin_unlock_irq(phba->host->host_lock);
if (rc == IOCB_ERROR) {
lpfc_els_free_iocb(phba, elsiocb);
return 1;
@@ -2290,168 +2621,153 @@ lpfc_els_rsp_rnid_acc(struct lpfc_hba *phba, uint8_t format,
}
int
-lpfc_els_disc_adisc(struct lpfc_hba *phba)
+lpfc_els_disc_adisc(struct lpfc_vport *vport)
{
- int sentadisc;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp, *next_ndlp;
+ int sentadisc = 0;
- sentadisc = 0;
/* go thru NPR nodes and issue any remaining ELS ADISCs */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
(ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
(ndlp->nlp_flag & NLP_NPR_ADISC) != 0) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, 0);
sentadisc++;
- phba->num_disc_nodes++;
- if (phba->num_disc_nodes >=
- phba->cfg_discovery_threads) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ vport->num_disc_nodes++;
+ if (vport->num_disc_nodes >=
+ vport->phba->cfg_discovery_threads) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
break;
}
}
}
if (sentadisc == 0) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
}
return sentadisc;
}
int
-lpfc_els_disc_plogi(struct lpfc_hba * phba)
+lpfc_els_disc_plogi(struct lpfc_vport *vport)
{
- int sentplogi;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp, *next_ndlp;
+ int sentplogi = 0;
- sentplogi = 0;
- /* go thru NPR list and issue any remaining ELS PLOGIs */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
+ /* go thru NPR nodes and issue any remaining ELS PLOGIs */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
(ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
(ndlp->nlp_flag & NLP_DELAY_TMO) == 0 &&
(ndlp->nlp_flag & NLP_NPR_ADISC) == 0) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
sentplogi++;
- phba->num_disc_nodes++;
- if (phba->num_disc_nodes >=
- phba->cfg_discovery_threads) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ vport->num_disc_nodes++;
+ if (vport->num_disc_nodes >=
+ vport->phba->cfg_discovery_threads) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
break;
}
}
}
if (sentplogi == 0) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NLP_MORE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NLP_MORE;
+ spin_unlock_irq(shost->host_lock);
}
return sentplogi;
}
-int
-lpfc_els_flush_rscn(struct lpfc_hba * phba)
+void
+lpfc_els_flush_rscn(struct lpfc_vport *vport)
{
- struct lpfc_dmabuf *mp;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
int i;
- for (i = 0; i < phba->fc_rscn_id_cnt; i++) {
- mp = phba->fc_rscn_id_list[i];
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- phba->fc_rscn_id_list[i] = NULL;
- }
- phba->fc_rscn_id_cnt = 0;
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
- spin_unlock_irq(phba->host->host_lock);
- lpfc_can_disctmo(phba);
- return 0;
+ for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
+ lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]);
+ vport->fc_rscn_id_list[i] = NULL;
+ }
+ spin_lock_irq(shost->host_lock);
+ vport->fc_rscn_id_cnt = 0;
+ vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
}
int
-lpfc_rscn_payload_check(struct lpfc_hba * phba, uint32_t did)
+lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did)
{
D_ID ns_did;
D_ID rscn_did;
- struct lpfc_dmabuf *mp;
uint32_t *lp;
- uint32_t payload_len, cmd, i, match;
+ uint32_t payload_len, i;
+ struct lpfc_hba *phba = vport->phba;
ns_did.un.word = did;
- match = 0;
/* Never match fabric nodes for RSCNs */
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK)
- return(0);
+ return 0;
/* If we are doing a FULL RSCN rediscovery, match everything */
- if (phba->fc_flag & FC_RSCN_DISCOVERY) {
+ if (vport->fc_flag & FC_RSCN_DISCOVERY)
return did;
- }
- for (i = 0; i < phba->fc_rscn_id_cnt; i++) {
- mp = phba->fc_rscn_id_list[i];
- lp = (uint32_t *) mp->virt;
- cmd = *lp++;
- payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
- payload_len -= sizeof (uint32_t); /* take off word 0 */
+ for (i = 0; i < vport->fc_rscn_id_cnt; i++) {
+ lp = vport->fc_rscn_id_list[i]->virt;
+ payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
+ payload_len -= sizeof(uint32_t); /* take off word 0 */
while (payload_len) {
- rscn_did.un.word = *lp++;
- rscn_did.un.word = be32_to_cpu(rscn_did.un.word);
- payload_len -= sizeof (uint32_t);
+ rscn_did.un.word = be32_to_cpu(*lp++);
+ payload_len -= sizeof(uint32_t);
switch (rscn_did.un.b.resv) {
case 0: /* Single N_Port ID effected */
- if (ns_did.un.word == rscn_did.un.word) {
- match = did;
- }
+ if (ns_did.un.word == rscn_did.un.word)
+ return did;
break;
case 1: /* Whole N_Port Area effected */
if ((ns_did.un.b.domain == rscn_did.un.b.domain)
&& (ns_did.un.b.area == rscn_did.un.b.area))
- {
- match = did;
- }
+ return did;
break;
case 2: /* Whole N_Port Domain effected */
if (ns_did.un.b.domain == rscn_did.un.b.domain)
- {
- match = did;
- }
- break;
- case 3: /* Whole Fabric effected */
- match = did;
+ return did;
break;
default:
- /* Unknown Identifier in RSCN list */
+ /* Unknown Identifier in RSCN node */
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0217 Unknown Identifier in "
- "RSCN payload Data: x%x\n",
- phba->brd_no, rscn_did.un.word);
- break;
- }
- if (match) {
- break;
+ "%d (%d):0217 Unknown "
+ "Identifier in RSCN payload "
+ "Data: x%x\n",
+ phba->brd_no, vport->vpi,
+ rscn_did.un.word);
+ case 3: /* Whole Fabric effected */
+ return did;
}
}
}
- return match;
+ return 0;
}
static int
-lpfc_rscn_recovery_check(struct lpfc_hba *phba)
+lpfc_rscn_recovery_check(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp = NULL;
@@ -2459,188 +2775,261 @@ lpfc_rscn_recovery_check(struct lpfc_hba *phba)
* them to NPR state.
*/
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE ||
- lpfc_rscn_payload_check(phba, ndlp->nlp_DID) == 0)
+ lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0)
continue;
- lpfc_disc_state_machine(phba, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RECOVERY);
/*
* Make sure NLP_DELAY_TMO is NOT running after a device
* recovery event.
*/
if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
return 0;
}
static int
-lpfc_els_rcv_rscn(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp, uint8_t newnode)
+lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp, uint8_t newnode)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
- uint32_t *lp;
+ struct lpfc_vport *next_vport;
+ uint32_t *lp, *datap;
IOCB_t *icmd;
- uint32_t payload_len, cmd;
+ uint32_t payload_len, length, nportid, *cmd;
+ int rscn_cnt = vport->fc_rscn_id_cnt;
+ int rscn_id = 0, hba_id = 0;
int i;
icmd = &cmdiocb->iocb;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
- cmd = *lp++;
- payload_len = be32_to_cpu(cmd) & 0xffff; /* payload length */
- payload_len -= sizeof (uint32_t); /* take off word 0 */
- cmd &= ELS_CMD_MASK;
+ payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
+ payload_len -= sizeof(uint32_t); /* take off word 0 */
/* RSCN received */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0214 RSCN received Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0214 RSCN received Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
+ *lp, rscn_cnt);
for (i = 0; i < payload_len/sizeof(uint32_t); i++)
- fc_host_post_event(phba->host, fc_get_event_number(),
+ fc_host_post_event(shost, fc_get_event_number(),
FCH_EVT_RSCN, lp[i]);
/* If we are about to begin discovery, just ACC the RSCN.
* Discovery processing will satisfy it.
*/
- if (phba->hba_state <= LPFC_NS_QRY) {
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
- newnode);
+ if (vport->port_state <= LPFC_NS_QRY) {
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
+ newnode);
return 0;
}
+ /* If this RSCN just contains NPortIDs for other vports on this HBA,
+ * just ACC and ignore it.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ !(phba->cfg_peer_port_login)) {
+ i = payload_len;
+ datap = lp;
+ while (i > 0) {
+ nportid = *datap++;
+ nportid = ((be32_to_cpu(nportid)) & Mask_DID);
+ i -= sizeof(uint32_t);
+ rscn_id++;
+ list_for_each_entry(next_vport, &phba->port_list,
+ listentry) {
+ if (nportid == next_vport->fc_myDID) {
+ hba_id++;
+ break;
+ }
+ }
+ }
+ if (rscn_id == hba_id) {
+ /* ALL NPortIDs in RSCN are on HBA */
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0214 Ignore RSCN Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
+ *lp, rscn_cnt);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN vport: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state,
+ ndlp->nlp_flag);
+
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
+ ndlp, NULL, newnode);
+ return 0;
+ }
+ }
+
/* If we are already processing an RSCN, save the received
* RSCN payload buffer, cmdiocb->context2 to process later.
*/
- if (phba->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
- if ((phba->fc_rscn_id_cnt < FC_MAX_HOLD_RSCN) &&
- !(phba->fc_flag & FC_RSCN_DISCOVERY)) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
- phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd;
-
- /* If we zero, cmdiocb->context2, the calling
- * routine will not try to free it.
- */
- cmdiocb->context2 = NULL;
+ if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) {
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN defer: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+
+ vport->fc_flag |= FC_RSCN_DEFERRED;
+ if ((rscn_cnt < FC_MAX_HOLD_RSCN) &&
+ !(vport->fc_flag & FC_RSCN_DISCOVERY)) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ if (rscn_cnt) {
+ cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt;
+ length = be32_to_cpu(*cmd & ~ELS_CMD_MASK);
+ }
+ if ((rscn_cnt) &&
+ (payload_len + length <= LPFC_BPL_SIZE)) {
+ *cmd &= ELS_CMD_MASK;
+ *cmd |= be32_to_cpu(payload_len + length);
+ memcpy(((uint8_t *)cmd) + length, lp,
+ payload_len);
+ } else {
+ vport->fc_rscn_id_list[rscn_cnt] = pcmd;
+ vport->fc_rscn_id_cnt++;
+ /* If we zero, cmdiocb->context2, the calling
+ * routine will not try to free it.
+ */
+ cmdiocb->context2 = NULL;
+ }
/* Deferred RSCN */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0235 Deferred RSCN "
+ "%d (%d):0235 Deferred RSCN "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->fc_rscn_id_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi,
+ vport->fc_rscn_id_cnt, vport->fc_flag,
+ vport->port_state);
} else {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_RSCN_DISCOVERY;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_DISCOVERY;
+ spin_unlock_irq(shost->host_lock);
/* ReDiscovery RSCN */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0234 ReDiscovery RSCN "
+ "%d (%d):0234 ReDiscovery RSCN "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->fc_rscn_id_cnt,
- phba->fc_flag, phba->hba_state);
+ phba->brd_no, vport->vpi,
+ vport->fc_rscn_id_cnt, vport->fc_flag,
+ vport->port_state);
}
/* Send back ACC */
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
newnode);
/* send RECOVERY event for ALL nodes that match RSCN payload */
- lpfc_rscn_recovery_check(phba);
+ lpfc_rscn_recovery_check(vport);
+ vport->fc_flag &= ~FC_RSCN_DEFERRED;
return 0;
}
- phba->fc_flag |= FC_RSCN_MODE;
- phba->fc_rscn_id_list[phba->fc_rscn_id_cnt++] = pcmd;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RSCN: did:x%x/ste:x%x flg:x%x",
+ ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd;
/*
* If we zero, cmdiocb->context2, the calling routine will
* not try to free it.
*/
cmdiocb->context2 = NULL;
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
/* Send back ACC */
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
/* send RECOVERY event for ALL nodes that match RSCN payload */
- lpfc_rscn_recovery_check(phba);
+ lpfc_rscn_recovery_check(vport);
- return lpfc_els_handle_rscn(phba);
+ return lpfc_els_handle_rscn(vport);
}
int
-lpfc_els_handle_rscn(struct lpfc_hba * phba)
+lpfc_els_handle_rscn(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp;
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Ignore RSCN if the port is being torn down. */
+ if (vport->load_flag & FC_UNLOADING) {
+ lpfc_els_flush_rscn(vport);
+ return 0;
+ }
/* Start timer for RSCN processing */
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
/* RSCN processed */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0215 RSCN processed Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- phba->fc_flag, 0, phba->fc_rscn_id_cnt,
- phba->hba_state);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0215 RSCN processed Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ vport->fc_flag, 0, vport->fc_rscn_id_cnt,
+ vport->port_state);
/* To process RSCN, first compare RSCN data with NameServer */
- phba->fc_ns_retry = 0;
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
+ vport->fc_ns_retry = 0;
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
/* Good ndlp, issue CT Request to NameServer */
- if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT) == 0) {
+ if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0)
/* Wait for NameServer query cmpl before we can
continue */
return 1;
- }
} else {
/* If login to NameServer does not exist, issue one */
/* Good status, issue PLOGI to NameServer */
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (ndlp) {
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ if (ndlp)
/* Wait for NameServer login cmpl before we can
continue */
return 1;
- }
+
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp) {
- lpfc_els_flush_rscn(phba);
+ lpfc_els_flush_rscn(vport);
return 0;
} else {
- lpfc_nlp_init(phba, ndlp, NameServer_DID);
+ lpfc_nlp_init(vport, ndlp, NameServer_DID);
ndlp->nlp_type |= NLP_FABRIC;
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, NameServer_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, NameServer_DID, 0);
/* Wait for NameServer login cmpl before we can
continue */
return 1;
}
}
- lpfc_els_flush_rscn(phba);
+ lpfc_els_flush_rscn(vport);
return 0;
}
static int
-lpfc_els_rcv_flogi(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp, uint8_t newnode)
+lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp, uint8_t newnode)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
uint32_t *lp = (uint32_t *) pcmd->virt;
IOCB_t *icmd = &cmdiocb->iocb;
@@ -2655,7 +3044,7 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
/* FLOGI received */
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
if (phba->fc_topology == TOPOLOGY_LOOP) {
/* We should never receive a FLOGI in loop mode, ignore it */
@@ -2664,33 +3053,34 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
/* An FLOGI ELS command <elsCmd> was received from DID <did> in
Loop Mode */
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d:0113 An FLOGI ELS command x%x was received "
- "from DID x%x in Loop Mode\n",
- phba->brd_no, cmd, did);
+ "%d (%d):0113 An FLOGI ELS command x%x was "
+ "received from DID x%x in Loop Mode\n",
+ phba->brd_no, vport->vpi, cmd, did);
return 1;
}
did = Fabric_DID;
- if ((lpfc_check_sparm(phba, ndlp, sp, CLASS3))) {
+ if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) {
/* For a FLOGI we accept, then if our portname is greater
* then the remote portname we initiate Nport login.
*/
- rc = memcmp(&phba->fc_portname, &sp->portName,
- sizeof (struct lpfc_name));
+ rc = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(struct lpfc_name));
if (!rc) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL)) == 0) {
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
return 1;
- }
+
lpfc_linkdown(phba);
lpfc_init_link(phba, mbox,
phba->cfg_topology,
phba->cfg_link_speed);
mbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
rc = lpfc_sli_issue_mbox
(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
lpfc_set_loopback_flag(phba);
@@ -2699,31 +3089,34 @@ lpfc_els_rcv_flogi(struct lpfc_hba * phba,
}
return 1;
} else if (rc > 0) { /* greater than */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_PT2PT_PLOGI;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT_PLOGI;
+ spin_unlock_irq(shost->host_lock);
}
- phba->fc_flag |= FC_PT2PT;
- phba->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_PT2PT;
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
} else {
/* Reject this request because invalid parameters */
stat.un.b.lsRjtRsvd0 = 0;
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
return 1;
}
/* Send back ACC */
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
return 0;
}
static int
-lpfc_els_rcv_rnid(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -2746,7 +3139,7 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
case 0:
case RNID_TOPOLOGY_DISC:
/* Send back ACC */
- lpfc_els_rsp_rnid_acc(phba, rn->Format, cmdiocb, ndlp);
+ lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp);
break;
default:
/* Reject this request because format not supported */
@@ -2754,14 +3147,15 @@ lpfc_els_rcv_rnid(struct lpfc_hba * phba,
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
}
return 0;
}
static int
-lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
- struct lpfc_nodelist *ndlp)
+lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct ls_rjt stat;
@@ -2770,15 +3164,15 @@ lpfc_els_rcv_lirr(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return 0;
}
static void
lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- struct lpfc_sli_ring *pring;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
MAILBOX_t *mb;
IOCB_t *icmd;
RPS_RSP *rps_rsp;
@@ -2788,8 +3182,6 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
uint16_t xri, status;
uint32_t cmdsize;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING];
mb = &pmb->mb;
ndlp = (struct lpfc_nodelist *) pmb->context2;
@@ -2804,8 +3196,9 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t);
mempool_free(pmb, phba->mbox_mem_pool);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, lpfc_max_els_tries, ndlp,
- ndlp->nlp_DID, ELS_CMD_ACC);
+ elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize,
+ lpfc_max_els_tries, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
lpfc_nlp_put(ndlp);
if (!elsiocb)
return;
@@ -2815,14 +3208,14 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint32_t); /* Skip past command */
+ pcmd += sizeof(uint32_t); /* Skip past command */
rps_rsp = (RPS_RSP *)pcmd;
if (phba->fc_topology != TOPOLOGY_LOOP)
status = 0x10;
else
status = 0x8;
- if (phba->fc_flag & FC_FABRIC)
+ if (phba->pport->fc_flag & FC_FABRIC)
status |= 0x4;
rps_rsp->rsvd1 = 0;
@@ -2836,25 +3229,25 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
/* Xmit ELS RPS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
- "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ "%d (%d):0118 Xmit ELS RPS ACC response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ phba->brd_no, ndlp->vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
-
- if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
lpfc_els_free_iocb(phba, elsiocb);
- }
return;
}
static int
-lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
uint32_t *lp;
uint8_t flag;
LPFC_MBOXQ_t *mbox;
@@ -2868,7 +3261,8 @@ lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -2878,19 +3272,24 @@ lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if ((flag == 0) ||
((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) ||
- ((flag == 2) && (memcmp(&rps->un.portName, &phba->fc_portname,
- sizeof (struct lpfc_name)) == 0))) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC))) {
+ ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname,
+ sizeof(struct lpfc_name)) == 0))) {
+
+ printk("Fix me....\n");
+ dump_stack();
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC);
+ if (mbox) {
lpfc_read_lnk_stat(phba, mbox);
mbox->context1 =
- (void *)((unsigned long)cmdiocb->iocb.ulpContext);
+ (void *)((unsigned long) cmdiocb->iocb.ulpContext);
mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->vport = vport;
mbox->mbox_cmpl = lpfc_els_rsp_rps_acc;
if (lpfc_sli_issue_mbox (phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED) {
+ (MBX_NOWAIT | MBX_STOP_IOCB)) != MBX_NOT_FINISHED)
/* Mbox completion will send ELS Response */
return 0;
- }
+
lpfc_nlp_put(ndlp);
mempool_free(mbox, phba->mbox_mem_pool);
}
@@ -2899,27 +3298,25 @@ lpfc_els_rcv_rps(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return 0;
}
static int
-lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
- struct lpfc_iocbq * oldiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize,
+ struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp)
{
- IOCB_t *icmd;
- IOCB_t *oldcmd;
+ struct lpfc_hba *phba = vport->phba;
+ IOCB_t *icmd, *oldcmd;
RPL_RSP rpl_rsp;
struct lpfc_iocbq *elsiocb;
- struct lpfc_sli_ring *pring;
- struct lpfc_sli *psli;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
uint8_t *pcmd;
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
+ elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp,
+ ndlp->nlp_DID, ELS_CMD_ACC);
- elsiocb = lpfc_prep_els_iocb(phba, 0, cmdsize, oldiocb->retry,
- ndlp, ndlp->nlp_DID, ELS_CMD_ACC);
if (!elsiocb)
return 1;
@@ -2929,7 +3326,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
- pcmd += sizeof (uint16_t);
+ pcmd += sizeof(uint16_t);
*((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize);
pcmd += sizeof(uint16_t);
@@ -2937,8 +3334,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
rpl_rsp.listLen = be32_to_cpu(1);
rpl_rsp.index = 0;
rpl_rsp.port_num_blk.portNum = 0;
- rpl_rsp.port_num_blk.portID = be32_to_cpu(phba->fc_myDID);
- memcpy(&rpl_rsp.port_num_blk.portName, &phba->fc_portname,
+ rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
+ memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
sizeof(struct lpfc_name));
memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
@@ -2946,13 +3343,14 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
/* Xmit ELS RPL ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0120 Xmit ELS RPL ACC response tag x%x xri x%x, "
- "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
- phba->brd_no, elsiocb->iotag,
+ "%d (%d):0120 Xmit ELS RPL ACC response tag x%x "
+ "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+ "rpi x%x\n",
+ phba->brd_no, vport->vpi, elsiocb->iotag,
elsiocb->iocb.ulpContext, ndlp->nlp_DID,
ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- elsiocb->iocb_cmpl = lpfc_cmpl_els_acc;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
phba->fc_stat.elsXmitACC++;
if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
@@ -2963,8 +3361,8 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
}
static int
-lpfc_els_rcv_rpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -2979,7 +3377,8 @@ lpfc_els_rcv_rpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -2996,15 +3395,16 @@ lpfc_els_rcv_rpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
} else {
cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t);
}
- lpfc_els_rsp_rpl_acc(phba, cmdsize, cmdiocb, ndlp);
+ lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp);
return 0;
}
static int
-lpfc_els_rcv_farp(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
@@ -3020,11 +3420,9 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
fp = (FARP *) lp;
/* FARP-REQ received from DID <did> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0601 FARP-REQ received from DID x%x\n",
- phba->brd_no, did);
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0601 FARP-REQ received from DID x%x\n",
+ phba->brd_no, vport->vpi, did);
/* We will only support match on WWPN or WWNN */
if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
@@ -3034,15 +3432,15 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
cnt = 0;
/* If this FARP command is searching for my portname */
if (fp->Mflags & FARP_MATCH_PORT) {
- if (memcmp(&fp->RportName, &phba->fc_portname,
- sizeof (struct lpfc_name)) == 0)
+ if (memcmp(&fp->RportName, &vport->fc_portname,
+ sizeof(struct lpfc_name)) == 0)
cnt = 1;
}
/* If this FARP command is searching for my nodename */
if (fp->Mflags & FARP_MATCH_NODE) {
- if (memcmp(&fp->RnodeName, &phba->fc_nodename,
- sizeof (struct lpfc_name)) == 0)
+ if (memcmp(&fp->RnodeName, &vport->fc_nodename,
+ sizeof(struct lpfc_name)) == 0)
cnt = 1;
}
@@ -3052,28 +3450,28 @@ lpfc_els_rcv_farp(struct lpfc_hba * phba,
/* Log back into the node before sending the FARP. */
if (fp->Rflags & FARP_REQUEST_PLOGI) {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
/* Send a FARP response to that node */
- if (fp->Rflags & FARP_REQUEST_FARPR) {
- lpfc_issue_els_farpr(phba, did, 0);
- }
+ if (fp->Rflags & FARP_REQUEST_FARPR)
+ lpfc_issue_els_farpr(vport, did, 0);
}
}
return 0;
}
static int
-lpfc_els_rcv_farpr(struct lpfc_hba * phba,
- struct lpfc_iocbq * cmdiocb, struct lpfc_nodelist * ndlp)
+lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
uint32_t cmd, did;
+ struct lpfc_hba *phba = vport->phba;
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
@@ -3082,21 +3480,18 @@ lpfc_els_rcv_farpr(struct lpfc_hba * phba,
cmd = *lp++;
/* FARP-RSP received from DID <did> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0600 FARP-RSP received from DID x%x\n",
- phba->brd_no, did);
-
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0600 FARP-RSP received from DID x%x\n",
+ phba->brd_no, vport->vpi, did);
/* ACCEPT the Farp resp request */
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
return 0;
}
static int
-lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_nodelist * fan_ndlp)
+lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_nodelist *fan_ndlp)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -3104,10 +3499,12 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
uint32_t cmd, did;
FAN *fp;
struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_hba *phba = vport->phba;
/* FAN received */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n",
- phba->brd_no);
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0265 FAN received\n",
+ phba->brd_no, vport->vpi);
icmd = &cmdiocb->iocb;
did = icmd->un.elsreq64.remoteID;
@@ -3115,11 +3512,11 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
lp = (uint32_t *)pcmd->virt;
cmd = *lp++;
- fp = (FAN *)lp;
+ fp = (FAN *) lp;
/* FAN received; Fan does not have a reply sequence */
- if (phba->hba_state == LPFC_LOCAL_CFG_LINK) {
+ if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) {
if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName,
sizeof(struct lpfc_name)) != 0) ||
(memcmp(&phba->fc_fabparam.portName, &fp->FportName,
@@ -3130,7 +3527,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
*/
list_for_each_entry_safe(ndlp, next_ndlp,
- &phba->fc_nodes, nlp_listp) {
+ &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state != NLP_STE_NPR_NODE)
continue;
if (ndlp->nlp_type & NLP_FABRIC) {
@@ -3138,24 +3535,24 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
* Clean up old Fabric, Nameserver and
* other NLP_FABRIC logins
*/
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
/* Fail outstanding I/O now since this
* device is marked for PLOGI
*/
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
}
}
- phba->hba_state = LPFC_FLOGI;
- lpfc_set_disctmo(phba);
- lpfc_initial_flogi(phba);
+ vport->port_state = LPFC_FLOGI;
+ lpfc_set_disctmo(vport);
+ lpfc_initial_flogi(vport);
return 0;
}
/* Discovery not needed,
* move the nodes to their original state.
*/
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state != NLP_STE_NPR_NODE)
continue;
@@ -3163,13 +3560,13 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
switch (ndlp->nlp_prev_state) {
case NLP_STE_UNMAPPED_NODE:
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_UNMAPPED_NODE);
break;
case NLP_STE_MAPPED_NODE:
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp,
+ lpfc_nlp_set_state(vport, ndlp,
NLP_STE_MAPPED_NODE);
break;
@@ -3179,7 +3576,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
/* Start discovery - this should just do CLEAR_LA */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
}
return 0;
}
@@ -3187,42 +3584,42 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
void
lpfc_els_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba;
+ struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
+ struct lpfc_hba *phba = vport->phba;
unsigned long iflag;
- phba = (struct lpfc_hba *)ptr;
- if (phba == 0)
- return;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
- phba->work_hba_events |= WORKER_ELS_TMO;
+ spin_lock_irqsave(&vport->work_port_lock, iflag);
+ if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
+ vport->work_port_events |= WORKER_ELS_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
+
+ spin_lock_irqsave(&phba->hbalock, iflag);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ else
+ spin_unlock_irqrestore(&vport->work_port_lock, iflag);
return;
}
void
-lpfc_els_timeout_handler(struct lpfc_hba *phba)
+lpfc_els_timeout_handler(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring;
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
struct lpfc_dmabuf *pcmd;
- uint32_t *elscmd;
- uint32_t els_command=0;
+ uint32_t els_command = 0;
uint32_t timeout;
- uint32_t remote_ID;
+ uint32_t remote_ID = 0xffffffff;
- if (phba == 0)
- return;
- spin_lock_irq(phba->host->host_lock);
/* If the timer is already canceled do nothing */
- if (!(phba->work_hba_events & WORKER_ELS_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->work_port_events & WORKER_ELS_TMO) == 0) {
return;
}
+ spin_lock_irq(&phba->hbalock);
timeout = (uint32_t)(phba->fc_ratov << 1);
pring = &phba->sli.ring[LPFC_ELS_RING];
@@ -3230,63 +3627,70 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
cmd = &piocb->iocb;
- if ((piocb->iocb_flag & LPFC_IO_LIBDFC) ||
- (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN) ||
- (piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)) {
+ if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 ||
+ piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN ||
+ piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN)
continue;
- }
+
+ if (piocb->vport != vport)
+ continue;
+
pcmd = (struct lpfc_dmabuf *) piocb->context2;
- if (pcmd) {
- elscmd = (uint32_t *) (pcmd->virt);
- els_command = *elscmd;
- }
+ if (pcmd)
+ els_command = *(uint32_t *) (pcmd->virt);
- if ((els_command == ELS_CMD_FARP)
- || (els_command == ELS_CMD_FARPR)) {
+ if (els_command == ELS_CMD_FARP ||
+ els_command == ELS_CMD_FARPR ||
+ els_command == ELS_CMD_FDISC)
+ continue;
+
+ if (vport != piocb->vport)
continue;
- }
if (piocb->drvrTimeout > 0) {
- if (piocb->drvrTimeout >= timeout) {
+ if (piocb->drvrTimeout >= timeout)
piocb->drvrTimeout -= timeout;
- } else {
+ else
piocb->drvrTimeout = 0;
- }
continue;
}
- if (cmd->ulpCommand == CMD_GEN_REQUEST64_CR) {
- struct lpfc_nodelist *ndlp;
- ndlp = __lpfc_findnode_rpi(phba, cmd->ulpContext);
- remote_ID = ndlp->nlp_DID;
- } else {
+ remote_ID = 0xffffffff;
+ if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR)
remote_ID = cmd->un.elsreq64.remoteID;
+ else {
+ struct lpfc_nodelist *ndlp;
+ ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext);
+ if (ndlp)
+ remote_ID = ndlp->nlp_DID;
}
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_ELS,
- "%d:0127 ELS timeout Data: x%x x%x x%x x%x\n",
- phba->brd_no, els_command,
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0127 ELS timeout Data: x%x x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi, els_command,
remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
}
- if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
- mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+ spin_unlock_irq(&phba->hbalock);
- spin_unlock_irq(phba->host->host_lock);
+ if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+ mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
}
void
-lpfc_els_flush_cmd(struct lpfc_hba *phba)
+lpfc_els_flush_cmd(struct lpfc_vport *vport)
{
LIST_HEAD(completions);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
struct lpfc_iocbq *tmp_iocb, *piocb;
IOCB_t *cmd = NULL;
- spin_lock_irq(phba->host->host_lock);
+ lpfc_fabric_abort_vport(vport);
+
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
cmd = &piocb->iocb;
@@ -3301,271 +3705,1042 @@ lpfc_els_flush_cmd(struct lpfc_hba *phba)
cmd->ulpCommand == CMD_ABORT_XRI_CN)
continue;
+ if (piocb->vport != vport)
+ continue;
+
list_move_tail(&piocb->list, &completions);
pring->txq_cnt--;
-
}
list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
- cmd = &piocb->iocb;
-
if (piocb->iocb_flag & LPFC_IO_LIBDFC) {
continue;
}
+ if (piocb->vport != vport)
+ continue;
+
lpfc_sli_issue_abort_iotag(phba, pring, piocb);
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
- while(!list_empty(&completions)) {
+ while (!list_empty(&completions)) {
piocb = list_get_first(&completions, struct lpfc_iocbq, list);
cmd = &piocb->iocb;
- list_del(&piocb->list);
+ list_del_init(&piocb->list);
- if (piocb->iocb_cmpl) {
+ if (!piocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, piocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(piocb->iocb_cmpl) (phba, piocb, piocb);
- } else
- lpfc_sli_release_iocbq(phba, piocb);
+ }
}
return;
}
-void
-lpfc_els_unsol_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, struct lpfc_iocbq * elsiocb)
+static void
+lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
{
- struct lpfc_sli *psli;
struct lpfc_nodelist *ndlp;
- struct lpfc_dmabuf *mp;
- uint32_t *lp;
- IOCB_t *icmd;
struct ls_rjt stat;
- uint32_t cmd;
- uint32_t did;
- uint32_t newnode;
- uint32_t drop_cmd = 0; /* by default do NOT drop received cmd */
- uint32_t rjt_err = 0;
-
- psli = &phba->sli;
- icmd = &elsiocb->iocb;
-
- if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) &&
- ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) {
- /* Not enough posted buffers; Try posting more buffers */
- phba->fc_stat.NoRcvBuf++;
- lpfc_post_buffer(phba, pring, 0, 1);
- return;
- }
-
- /* If there are no BDEs associated with this IOCB,
- * there is nothing to do.
- */
- if (icmd->ulpBdeCount == 0)
- return;
+ uint32_t *payload;
+ uint32_t cmd, did, newnode, rjt_err = 0;
+ IOCB_t *icmd = &elsiocb->iocb;
- /* type of ELS cmd is first 32bit word in packet */
- mp = lpfc_sli_ringpostbuf_get(phba, pring, getPaddr(icmd->un.
- cont64[0].
- addrHigh,
- icmd->un.
- cont64[0].addrLow));
- if (mp == 0) {
- drop_cmd = 1;
+ if (vport == NULL || elsiocb->context2 == NULL)
goto dropit;
- }
newnode = 0;
- lp = (uint32_t *) mp->virt;
- cmd = *lp++;
- lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], 1, 1);
+ payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt;
+ cmd = *payload;
+ if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0)
+ lpfc_post_buffer(phba, pring, 1, 1);
+ did = icmd->un.rcvels.remoteID;
if (icmd->ulpStatus) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- drop_cmd = 1;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV Unsol ELS: status:x%x/x%x did:x%x",
+ icmd->ulpStatus, icmd->un.ulpWord[4], did);
goto dropit;
}
/* Check to see if link went down during discovery */
- if (lpfc_els_chk_latt(phba)) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- drop_cmd = 1;
+ if (lpfc_els_chk_latt(vport))
goto dropit;
- }
- did = icmd->un.rcvels.remoteID;
- ndlp = lpfc_findnode_did(phba, did);
+ /* Ignore traffic recevied during vport shutdown. */
+ if (vport->load_flag & FC_UNLOADING)
+ goto dropit;
+
+ ndlp = lpfc_findnode_did(vport, did);
if (!ndlp) {
/* Cannot find existing Fabric ndlp, so allocate a new one */
ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
- if (!ndlp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- drop_cmd = 1;
+ if (!ndlp)
goto dropit;
- }
- lpfc_nlp_init(phba, ndlp, did);
+ lpfc_nlp_init(vport, ndlp, did);
newnode = 1;
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
ndlp->nlp_type |= NLP_FABRIC;
}
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
}
phba->fc_stat.elsRcvFrame++;
if (elsiocb->context1)
lpfc_nlp_put(elsiocb->context1);
elsiocb->context1 = lpfc_nlp_get(ndlp);
- elsiocb->context2 = mp;
+ elsiocb->vport = vport;
if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) {
cmd &= ELS_CMD_MASK;
}
/* ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0112 ELS command x%x received from NPORT x%x "
- "Data: x%x\n", phba->brd_no, cmd, did, phba->hba_state);
+ "%d (%d):0112 ELS command x%x received from NPORT x%x "
+ "Data: x%x\n", phba->brd_no, vport->vpi, cmd, did,
+ vport->port_state);
switch (cmd) {
case ELS_CMD_PLOGI:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PLOGI: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPLOGI++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp);
+
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb,
+ NLP_EVT_RCV_PLOGI);
+
break;
case ELS_CMD_FLOGI:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FLOGI: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFLOGI++;
- lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
+ lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_LOGO:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV LOGO: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvLOGO++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO);
break;
case ELS_CMD_PRLO:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PRLO: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPRLO++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO);
break;
case ELS_CMD_RSCN:
phba->fc_stat.elsRcvRSCN++;
- lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
+ lpfc_els_rcv_rscn(vport, elsiocb, ndlp, newnode);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_ADISC:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV ADISC: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvADISC++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_ADISC);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb,
+ NLP_EVT_RCV_ADISC);
break;
case ELS_CMD_PDISC:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PDISC: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPDISC++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PDISC);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb,
+ NLP_EVT_RCV_PDISC);
break;
case ELS_CMD_FARPR:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FARPR: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFARPR++;
- lpfc_els_rcv_farpr(phba, elsiocb, ndlp);
+ lpfc_els_rcv_farpr(vport, elsiocb, ndlp);
break;
case ELS_CMD_FARP:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FARP: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFARP++;
- lpfc_els_rcv_farp(phba, elsiocb, ndlp);
+ lpfc_els_rcv_farp(vport, elsiocb, ndlp);
break;
case ELS_CMD_FAN:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV FAN: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvFAN++;
- lpfc_els_rcv_fan(phba, elsiocb, ndlp);
+ lpfc_els_rcv_fan(vport, elsiocb, ndlp);
break;
case ELS_CMD_PRLI:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV PRLI: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvPRLI++;
- if (phba->hba_state < LPFC_DISC_AUTH) {
- rjt_err = 1;
+ if (vport->port_state < LPFC_DISC_AUTH) {
+ rjt_err = LSRJT_UNABLE_TPC;
break;
}
- lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
+ lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
break;
case ELS_CMD_LIRR:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV LIRR: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvLIRR++;
- lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
+ lpfc_els_rcv_lirr(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_RPS:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RPS: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvRPS++;
- lpfc_els_rcv_rps(phba, elsiocb, ndlp);
+ lpfc_els_rcv_rps(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_RPL:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RPL: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvRPL++;
- lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
+ lpfc_els_rcv_rpl(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
case ELS_CMD_RNID:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV RNID: did:x%x/ste:x%x flg:x%x",
+ did, vport->port_state, ndlp->nlp_flag);
+
phba->fc_stat.elsRcvRNID++;
- lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
+ lpfc_els_rcv_rnid(vport, elsiocb, ndlp);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
default:
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
+ "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x",
+ cmd, did, vport->port_state);
+
/* Unsupported ELS command, reject */
- rjt_err = 1;
+ rjt_err = LSRJT_INVALID_CMD;
/* Unknown ELS command <elsCmd> received from NPORT <did> */
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d:0115 Unknown ELS command x%x received from "
- "NPORT x%x\n", phba->brd_no, cmd, did);
+ "%d (%d):0115 Unknown ELS command x%x "
+ "received from NPORT x%x\n",
+ phba->brd_no, vport->vpi, cmd, did);
if (newnode)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
break;
}
/* check if need to LS_RJT received ELS cmd */
if (rjt_err) {
- stat.un.b.lsRjtRsvd0 = 0;
- stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
+ memset(&stat, 0, sizeof(stat));
+ stat.un.b.lsRjtRsnCode = rjt_err;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, elsiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
+ NULL);
+ if (newnode)
+ lpfc_drop_node(vport, ndlp);
+ }
+
+ return;
+
+dropit:
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0111 Dropping received ELS cmd "
+ "Data: x%x x%x x%x\n",
+ phba->brd_no, vport ? vport->vpi : 0xffff,
+ icmd->ulpStatus, icmd->un.ulpWord[4],
+ icmd->ulpTimeout);
+ phba->fc_stat.elsRcvDrop++;
+}
+
+static struct lpfc_vport *
+lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
+{
+ struct lpfc_vport *vport;
+
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ if (vport->vpi == vpi)
+ return vport;
+ }
+ return NULL;
+}
+
+void
+lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *elsiocb)
+{
+ struct lpfc_vport *vport = phba->pport;
+ IOCB_t *icmd = &elsiocb->iocb;
+ dma_addr_t paddr;
+ struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2;
+ struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3;
+
+ elsiocb->context2 = NULL;
+ elsiocb->context3 = NULL;
+
+ if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) {
+ lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ);
+ } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT &&
+ (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) {
+ phba->fc_stat.NoRcvBuf++;
+ /* Not enough posted buffers; Try posting more buffers */
+ if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED))
+ lpfc_post_buffer(phba, pring, 0, 1);
+ return;
+ }
+
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX ||
+ icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
+ if (icmd->unsli3.rcvsli3.vpi == 0xffff)
+ vport = phba->pport;
+ else {
+ uint16_t vpi = icmd->unsli3.rcvsli3.vpi;
+ vport = lpfc_find_vport_by_vpid(phba, vpi);
+ }
+ }
+ /* If there are no BDEs associated
+ * with this IOCB, there is nothing to do.
+ */
+ if (icmd->ulpBdeCount == 0)
+ return;
+
+ /* type of ELS cmd is first 32bit word
+ * in packet
+ */
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ elsiocb->context2 = bdeBuf1;
+ } else {
+ paddr = getPaddr(icmd->un.cont64[0].addrHigh,
+ icmd->un.cont64[0].addrLow);
+ elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring,
+ paddr);
}
+ lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
+ /*
+ * The different unsolicited event handlers would tell us
+ * if they are done with "mp" by setting context2 to NULL.
+ */
lpfc_nlp_put(elsiocb->context1);
elsiocb->context1 = NULL;
if (elsiocb->context2) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
+ lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2);
+ elsiocb->context2 = NULL;
}
-dropit:
- /* check if need to drop received ELS cmd */
- if (drop_cmd == 1) {
+
+ /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */
+ if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) &&
+ icmd->ulpBdeCount == 2) {
+ elsiocb->context2 = bdeBuf2;
+ lpfc_els_unsol_buffer(phba, pring, vport, elsiocb);
+ /* free mp if we are done with it */
+ if (elsiocb->context2) {
+ lpfc_in_buf_free(phba, elsiocb->context2);
+ elsiocb->context2 = NULL;
+ }
+ }
+}
+
+void
+lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+ struct lpfc_nodelist *ndlp, *ndlp_fdmi;
+
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
+ if (!ndlp) {
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (!ndlp) {
+ if (phba->fc_topology == TOPOLOGY_LOOP) {
+ lpfc_disc_start(vport);
+ return;
+ }
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0251 NameServer login: no memory\n",
+ phba->brd_no, vport->vpi);
+ return;
+ }
+ lpfc_nlp_init(vport, ndlp, NameServer_DID);
+ ndlp->nlp_type |= NLP_FABRIC;
+ }
+
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+
+ if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
- "%d:0111 Dropping received ELS cmd "
- "Data: x%x x%x x%x\n", phba->brd_no,
- icmd->ulpStatus, icmd->un.ulpWord[4],
- icmd->ulpTimeout);
- phba->fc_stat.elsRcvDrop++;
+ "%d (%d):0252 Cannot issue NameServer login\n",
+ phba->brd_no, vport->vpi);
+ return;
+ }
+
+ if (phba->cfg_fdmi_on) {
+ ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
+ GFP_KERNEL);
+ if (ndlp_fdmi) {
+ lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID);
+ ndlp_fdmi->nlp_type |= NLP_FABRIC;
+ ndlp_fdmi->nlp_state =
+ NLP_STE_PLOGI_ISSUE;
+ lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID,
+ 0);
+ }
+ }
+ return;
+}
+
+static void
+lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ MAILBOX_t *mb = &pmb->mb;
+
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ lpfc_nlp_put(ndlp);
+
+ if (mb->mbxStatus) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0915 Register VPI failed: 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
+
+ switch (mb->mbxStatus) {
+ case 0x11: /* unsupported feature */
+ case 0x9603: /* max_vpi exceeded */
+ /* giving up on vport registration */
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
+ break;
+ default:
+ /* Try to recover from this error */
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ lpfc_initial_fdisc(vport);
+ break;
+ }
+
+ } else {
+ if (vport == phba->pport)
+ lpfc_issue_fabric_reglogin(vport);
+ else
+ lpfc_do_scr_ns_plogi(phba, vport);
}
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
+
+void
+lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp)
+{
+ LPFC_MBOXQ_t *mbox;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox);
+ mbox->vport = vport;
+ mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport;
+ if (lpfc_sli_issue_mbox(phba, mbox,
+ MBX_NOWAIT | MBX_STOP_IOCB)
+ == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0253 Register VPI: Cannot send mbox\n",
+ phba->brd_no, vport->vpi);
+ }
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0254 Register VPI: no memory\n",
+ phba->brd_no, vport->vpi);
+
+ vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+ lpfc_nlp_put(ndlp);
+ }
+}
+
+static void
+lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
+ struct lpfc_nodelist *np;
+ struct lpfc_nodelist *next_np;
+ IOCB_t *irsp = &rspiocb->iocb;
+ struct lpfc_iocbq *piocb;
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0123 FDISC completes. x%x/x%x prevDID: x%x\n",
+ phba->brd_no, vport->vpi,
+ irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
+
+ /* Since all FDISCs are being single threaded, we
+ * must reset the discovery timer for ALL vports
+ * waiting to send FDISC when one completes.
+ */
+ list_for_each_entry(piocb, &phba->fabric_iocb_list, list) {
+ lpfc_set_disctmo(piocb->vport);
+ }
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "FDISC cmpl: status:x%x/x%x prevdid:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
+
+ if (irsp->ulpStatus) {
+ /* Check for retry */
+ if (lpfc_els_retry(phba, cmdiocb, rspiocb))
+ goto out;
+
+ /* FDISC failed */
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0124 FDISC failed. (%d/%d)\n",
+ phba->brd_no, vport->vpi,
+ irsp->ulpStatus, irsp->un.ulpWord[4]);
+
+ if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_nlp_put(ndlp);
+ /* giving up on FDISC. Cancel discovery timer */
+ lpfc_can_disctmo(vport);
+ } else {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_FABRIC;
+ if (vport->phba->fc_topology == TOPOLOGY_LOOP)
+ vport->fc_flag |= FC_PUBLIC_LOOP;
+ spin_unlock_irq(shost->host_lock);
+
+ vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID;
+ lpfc_vport_set_state(vport, FC_VPORT_ACTIVE);
+ if ((vport->fc_prevDID != vport->fc_myDID) &&
+ !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) {
+ /* If our NportID changed, we need to ensure all
+ * remaining NPORTs get unreg_login'ed so we can
+ * issue unreg_vpi.
+ */
+ list_for_each_entry_safe(np, next_np,
+ &vport->fc_nodes, nlp_listp) {
+ if (np->nlp_state != NLP_STE_NPR_NODE
+ || !(np->nlp_flag & NLP_NPR_ADISC))
+ continue;
+ spin_lock_irq(shost->host_lock);
+ np->nlp_flag &= ~NLP_NPR_ADISC;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_unreg_rpi(vport, np);
+ }
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ }
+
+ if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)
+ lpfc_register_new_vport(phba, vport, ndlp);
+ else
+ lpfc_do_scr_ns_plogi(phba, vport);
+
+ lpfc_nlp_put(ndlp); /* Free Fabric ndlp for vports */
+ }
+
+out:
+ lpfc_els_free_iocb(phba, cmdiocb);
+}
+
+int
+lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint8_t retry)
+{
+ struct lpfc_hba *phba = vport->phba;
+ IOCB_t *icmd;
+ struct lpfc_iocbq *elsiocb;
+ struct serv_parm *sp;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+ int did = ndlp->nlp_DID;
+ int rc;
+
+ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did,
+ ELS_CMD_FDISC);
+ if (!elsiocb) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0255 Issue FDISC: no IOCB\n",
+ phba->brd_no, vport->vpi);
+ return 1;
+ }
+
+ icmd = &elsiocb->iocb;
+ icmd->un.elsreq64.myID = 0;
+ icmd->un.elsreq64.fl = 1;
+
+ /* For FDISC, Let FDISC rsp set the NPortID for this VPI */
+ icmd->ulpCt_h = 1;
+ icmd->ulpCt_l = 0;
+
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_FDISC;
+ pcmd += sizeof(uint32_t); /* CSP Word 1 */
+ memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm));
+ sp = (struct serv_parm *) pcmd;
+ /* Setup CSPs accordingly for Fabric */
+ sp->cmn.e_d_tov = 0;
+ sp->cmn.w2.r_a_tov = 0;
+ sp->cls1.classValid = 0;
+ sp->cls2.seqDelivery = 1;
+ sp->cls3.seqDelivery = 1;
+
+ pcmd += sizeof(uint32_t); /* CSP Word 2 */
+ pcmd += sizeof(uint32_t); /* CSP Word 3 */
+ pcmd += sizeof(uint32_t); /* CSP Word 4 */
+ pcmd += sizeof(uint32_t); /* Port Name */
+ memcpy(pcmd, &vport->fc_portname, 8);
+ pcmd += sizeof(uint32_t); /* Node Name */
+ pcmd += sizeof(uint32_t); /* Node Name */
+ memcpy(pcmd, &vport->fc_nodename, 8);
+
+ lpfc_set_disctmo(vport);
+
+ phba->fc_stat.elsXmitFDISC++;
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue FDISC: did:x%x",
+ did, 0, 0);
+
+ rc = lpfc_issue_fabric_iocb(phba, elsiocb);
+ if (rc == IOCB_ERROR) {
+ lpfc_els_free_iocb(phba, elsiocb);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0256 Issue FDISC: Cannot send IOCB\n",
+ phba->brd_no, vport->vpi);
+
+ return 1;
+ }
+ lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
+ vport->port_state = LPFC_FDISC;
+ return 0;
+}
+
+static void
+lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ IOCB_t *irsp;
+
+ irsp = &rspiocb->iocb;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "LOGO npiv cmpl: status:x%x/x%x did:x%x",
+ irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID);
+
+ lpfc_els_free_iocb(phba, cmdiocb);
+ vport->unreg_vpi_cmpl = VPORT_ERROR;
+}
+
+int
+lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ IOCB_t *icmd;
+ struct lpfc_iocbq *elsiocb;
+ uint8_t *pcmd;
+ uint16_t cmdsize;
+
+ cmdsize = 2 * sizeof(uint32_t) + sizeof(struct lpfc_name);
+ elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID,
+ ELS_CMD_LOGO);
+ if (!elsiocb)
+ return 1;
+
+ icmd = &elsiocb->iocb;
+ pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
+ *((uint32_t *) (pcmd)) = ELS_CMD_LOGO;
+ pcmd += sizeof(uint32_t);
+
+ /* Fill in LOGO payload */
+ *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID);
+ pcmd += sizeof(uint32_t);
+ memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Issue LOGO npiv did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
+ elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo;
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_LOGO_SND;
+ spin_unlock_irq(shost->host_lock);
+ if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag &= ~NLP_LOGO_SND;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_els_free_iocb(phba, elsiocb);
+ return 1;
+ }
+ return 0;
+}
+
+void
+lpfc_fabric_block_timeout(unsigned long ptr)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
+ unsigned long iflags;
+ uint32_t tmo_posted;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflags);
+ tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO;
+ if (!tmo_posted)
+ phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags);
+
+ if (!tmo_posted) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (phba->work_wait)
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ }
+}
+
+static void
+lpfc_resume_fabric_iocbs(struct lpfc_hba *phba)
+{
+ struct lpfc_iocbq *iocb;
+ unsigned long iflags;
+ int ret;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ IOCB_t *cmd;
+
+repeat:
+ iocb = NULL;
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ /* Post any pending iocb to the SLI layer */
+ if (atomic_read(&phba->fabric_iocb_count) == 0) {
+ list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb),
+ list);
+ if (iocb)
+ atomic_inc(&phba->fabric_iocb_count);
+ }
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (iocb) {
+ iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
+ iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
+ iocb->iocb_flag |= LPFC_IO_FABRIC;
+
+ lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
+ "Fabric sched1: ste:x%x",
+ iocb->vport->port_state, 0, 0);
+
+ ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+
+ if (ret == IOCB_ERROR) {
+ iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
+ iocb->fabric_iocb_cmpl = NULL;
+ iocb->iocb_flag &= ~LPFC_IO_FABRIC;
+ cmd = &iocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ iocb->iocb_cmpl(phba, iocb, iocb);
+
+ atomic_dec(&phba->fabric_iocb_count);
+ goto repeat;
+ }
+ }
+
+ return;
+}
+
+void
+lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba)
+{
+ clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+
+ lpfc_resume_fabric_iocbs(phba);
+ return;
+}
+
+static void
+lpfc_block_fabric_iocbs(struct lpfc_hba *phba)
+{
+ int blocked;
+
+ blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+ /* Start a timer to unblock fabric
+ * iocbs after 100ms
+ */
+ if (!blocked)
+ mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 );
+
+ return;
+}
+
+static void
+lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ struct ls_rjt stat;
+
+ if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC)
+ BUG();
+
+ switch (rspiocb->iocb.ulpStatus) {
+ case IOSTAT_NPORT_RJT:
+ case IOSTAT_FABRIC_RJT:
+ if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) {
+ lpfc_block_fabric_iocbs(phba);
+ }
+ break;
+
+ case IOSTAT_NPORT_BSY:
+ case IOSTAT_FABRIC_BSY:
+ lpfc_block_fabric_iocbs(phba);
+ break;
+
+ case IOSTAT_LS_RJT:
+ stat.un.lsRjtError =
+ be32_to_cpu(rspiocb->iocb.un.ulpWord[4]);
+ if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) ||
+ (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY))
+ lpfc_block_fabric_iocbs(phba);
+ break;
+ }
+
+ if (atomic_read(&phba->fabric_iocb_count) == 0)
+ BUG();
+
+ cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl;
+ cmdiocb->fabric_iocb_cmpl = NULL;
+ cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC;
+ cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb);
+
+ atomic_dec(&phba->fabric_iocb_count);
+ if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) {
+ /* Post any pending iocbs to HBA */
+ lpfc_resume_fabric_iocbs(phba);
+ }
+}
+
+int
+lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb)
+{
+ unsigned long iflags;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ int ready;
+ int ret;
+
+ if (atomic_read(&phba->fabric_iocb_count) > 1)
+ BUG();
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ ready = atomic_read(&phba->fabric_iocb_count) == 0 &&
+ !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ if (ready) {
+ iocb->fabric_iocb_cmpl = iocb->iocb_cmpl;
+ iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb;
+ iocb->iocb_flag |= LPFC_IO_FABRIC;
+
+ lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD,
+ "Fabric sched2: ste:x%x",
+ iocb->vport->port_state, 0, 0);
+
+ atomic_inc(&phba->fabric_iocb_count);
+ ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0);
+
+ if (ret == IOCB_ERROR) {
+ iocb->iocb_cmpl = iocb->fabric_iocb_cmpl;
+ iocb->fabric_iocb_cmpl = NULL;
+ iocb->iocb_flag &= ~LPFC_IO_FABRIC;
+ atomic_dec(&phba->fabric_iocb_count);
+ }
+ } else {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ list_add_tail(&iocb->list, &phba->fabric_iocb_list);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ ret = IOCB_SUCCESS;
+ }
+ return ret;
+}
+
+
+void lpfc_fabric_abort_vport(struct lpfc_vport *vport)
+{
+ LIST_HEAD(completions);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *tmp_iocb, *piocb;
+ IOCB_t *cmd;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
+ list) {
+
+ if (piocb->vport != vport)
+ continue;
+
+ list_move_tail(&piocb->list, &completions);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp)
+{
+ LIST_HEAD(completions);
+ struct lpfc_hba *phba = ndlp->vport->phba;
+ struct lpfc_iocbq *tmp_iocb, *piocb;
+ struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+ IOCB_t *cmd;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
+ list) {
+ if ((lpfc_check_sli_ndlp(phba, pring, piocb, ndlp))) {
+
+ list_move_tail(&piocb->list, &completions);
+ }
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+void lpfc_fabric_abort_hba(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_iocbq *piocb;
+ IOCB_t *cmd;
+
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&phba->fabric_iocb_list, &completions);
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+
+void lpfc_fabric_abort_flogi(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_iocbq *tmp_iocb, *piocb;
+ IOCB_t *cmd;
+ struct lpfc_nodelist *ndlp;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list,
+ list) {
+
+ cmd = &piocb->iocb;
+ ndlp = (struct lpfc_nodelist *) piocb->context1;
+ if (cmd->ulpCommand == CMD_ELS_REQUEST64_CR &&
+ ndlp != NULL &&
+ ndlp->nlp_DID == Fabric_DID)
+ list_move_tail(&piocb->list, &completions);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ while (!list_empty(&completions)) {
+ piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_del_init(&piocb->list);
+
+ cmd = &piocb->iocb;
+ cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+ cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (piocb->iocb_cmpl) (phba, piocb, piocb);
+ }
+}
+
+
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 61caa8d379e2..f2f4639eab59 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -36,6 +36,8 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
/* AlpaArray for assignment of scsid for scan-down and bind_method */
static uint8_t lpfcAlpaArray[] = {
@@ -54,7 +56,7 @@ static uint8_t lpfcAlpaArray[] = {
0x10, 0x0F, 0x08, 0x04, 0x02, 0x01
};
-static void lpfc_disc_timeout_handler(struct lpfc_hba *);
+static void lpfc_disc_timeout_handler(struct lpfc_vport *);
void
lpfc_terminate_rport_io(struct fc_rport *rport)
@@ -74,14 +76,16 @@ lpfc_terminate_rport_io(struct fc_rport *rport)
return;
}
- phba = ndlp->nlp_phba;
+ phba = ndlp->vport->phba;
+
+ lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT,
+ "rport terminate: sid:x%x did:x%x flg:x%x",
+ ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
- spin_lock_irq(phba->host->host_lock);
if (ndlp->nlp_sid != NLP_NO_SID) {
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
}
- spin_unlock_irq(phba->host->host_lock);
return;
}
@@ -94,105 +98,213 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
{
struct lpfc_rport_data *rdata;
struct lpfc_nodelist * ndlp;
- uint8_t *name;
- int warn_on = 0;
- struct lpfc_hba *phba;
+ struct lpfc_vport *vport;
+ struct lpfc_hba *phba;
+ struct completion devloss_compl;
+ struct lpfc_work_evt *evtp;
rdata = rport->dd_data;
ndlp = rdata->pnode;
if (!ndlp) {
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ if (rport->scsi_target_id != -1) {
printk(KERN_ERR "Cannot find remote node"
- " for rport in dev_loss_tmo_callbk x%x\n",
- rport->port_id);
+ " for rport in dev_loss_tmo_callbk x%x\n",
+ rport->port_id);
+ }
return;
}
- if (ndlp->nlp_state == NLP_STE_MAPPED_NODE)
+ vport = ndlp->vport;
+ phba = vport->phba;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport devlosscb: sid:x%x did:x%x flg:x%x",
+ ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
+
+ init_completion(&devloss_compl);
+ evtp = &ndlp->dev_loss_evt;
+
+ if (!list_empty(&evtp->evt_listp))
+ return;
+
+ spin_lock_irq(&phba->hbalock);
+ evtp->evt_arg1 = ndlp;
+ evtp->evt_arg2 = &devloss_compl;
+ evtp->evt = LPFC_EVT_DEV_LOSS;
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
+
+ spin_unlock_irq(&phba->hbalock);
+
+ wait_for_completion(&devloss_compl);
+
+ return;
+}
+
+/*
+ * This function is called from the worker thread when dev_loss_tmo
+ * expire.
+ */
+void
+lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp)
+{
+ struct lpfc_rport_data *rdata;
+ struct fc_rport *rport;
+ struct lpfc_vport *vport;
+ struct lpfc_hba *phba;
+ uint8_t *name;
+ int warn_on = 0;
+
+ rport = ndlp->rport;
+
+ if (!rport)
+ return;
+
+ rdata = rport->dd_data;
+ name = (uint8_t *) &ndlp->nlp_portname;
+ vport = ndlp->vport;
+ phba = vport->phba;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport devlosstmo:did:x%x type:x%x id:x%x",
+ ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id);
+
+ if (!(vport->load_flag & FC_UNLOADING) &&
+ ndlp->nlp_state == NLP_STE_MAPPED_NODE)
return;
- name = (uint8_t *)&ndlp->nlp_portname;
- phba = ndlp->nlp_phba;
+ if (ndlp->nlp_type & NLP_FABRIC) {
+ int put_node;
+ int put_rport;
- spin_lock_irq(phba->host->host_lock);
+ /* We will clean up these Nodes in linkup */
+ put_node = rdata->pnode != NULL;
+ put_rport = ndlp->rport != NULL;
+ rdata->pnode = NULL;
+ ndlp->rport = NULL;
+ if (put_node)
+ lpfc_nlp_put(ndlp);
+ if (put_rport)
+ put_device(&rport->dev);
+ return;
+ }
if (ndlp->nlp_sid != NLP_NO_SID) {
warn_on = 1;
/* flush the target */
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
}
- if (phba->fc_flag & FC_UNLOADING)
+ if (vport->load_flag & FC_UNLOADING)
warn_on = 0;
- spin_unlock_irq(phba->host->host_lock);
-
if (warn_on) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0203 Devloss timeout on "
+ "%d (%d):0203 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
*name, *(name+1), *(name+2), *(name+3),
*(name+4), *(name+5), *(name+6), *(name+7),
ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0204 Devloss timeout on "
+ "%d (%d):0204 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
*name, *(name+1), *(name+2), *(name+3),
*(name+4), *(name+5), *(name+6), *(name+7),
ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
}
- if (!(phba->fc_flag & FC_UNLOADING) &&
+ if (!(vport->load_flag & FC_UNLOADING) &&
!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
(ndlp->nlp_state != NLP_STE_UNMAPPED_NODE))
- lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+ lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM);
else {
+ int put_node;
+ int put_rport;
+
+ put_node = rdata->pnode != NULL;
+ put_rport = ndlp->rport != NULL;
rdata->pnode = NULL;
ndlp->rport = NULL;
- lpfc_nlp_put(ndlp);
- put_device(&rport->dev);
+ if (put_node)
+ lpfc_nlp_put(ndlp);
+ if (put_rport)
+ put_device(&rport->dev);
}
+}
+
+void
+lpfc_worker_wake_up(struct lpfc_hba *phba)
+{
+ wake_up(phba->work_wait);
return;
}
static void
-lpfc_work_list_done(struct lpfc_hba * phba)
+lpfc_work_list_done(struct lpfc_hba *phba)
{
struct lpfc_work_evt *evtp = NULL;
struct lpfc_nodelist *ndlp;
+ struct lpfc_vport *vport;
int free_evt;
- spin_lock_irq(phba->host->host_lock);
- while(!list_empty(&phba->work_list)) {
+ spin_lock_irq(&phba->hbalock);
+ while (!list_empty(&phba->work_list)) {
list_remove_head((&phba->work_list), evtp, typeof(*evtp),
evt_listp);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
free_evt = 1;
switch (evtp->evt) {
+ case LPFC_EVT_DEV_LOSS_DELAY:
+ free_evt = 0; /* evt is part of ndlp */
+ ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
+ vport = ndlp->vport;
+ if (!vport)
+ break;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport devlossdly:did:x%x flg:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, 0);
+
+ if (!(vport->load_flag & FC_UNLOADING) &&
+ !(ndlp->nlp_flag & NLP_DELAY_TMO) &&
+ !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RM);
+ }
+ break;
case LPFC_EVT_ELS_RETRY:
- ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+ ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1);
lpfc_els_retry_delay_handler(ndlp);
+ free_evt = 0; /* evt is part of ndlp */
+ break;
+ case LPFC_EVT_DEV_LOSS:
+ ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
+ lpfc_nlp_get(ndlp);
+ lpfc_dev_loss_tmo_handler(ndlp);
free_evt = 0;
+ complete((struct completion *)(evtp->evt_arg2));
+ lpfc_nlp_put(ndlp);
break;
case LPFC_EVT_ONLINE:
- if (phba->hba_state < LPFC_LINK_DOWN)
- *(int *)(evtp->evt_arg1) = lpfc_online(phba);
+ if (phba->link_state < LPFC_LINK_DOWN)
+ *(int *) (evtp->evt_arg1) = lpfc_online(phba);
else
- *(int *)(evtp->evt_arg1) = 0;
+ *(int *) (evtp->evt_arg1) = 0;
complete((struct completion *)(evtp->evt_arg2));
break;
case LPFC_EVT_OFFLINE_PREP:
- if (phba->hba_state >= LPFC_LINK_DOWN)
+ if (phba->link_state >= LPFC_LINK_DOWN)
lpfc_offline_prep(phba);
*(int *)(evtp->evt_arg1) = 0;
complete((struct completion *)(evtp->evt_arg2));
@@ -218,33 +330,31 @@ lpfc_work_list_done(struct lpfc_hba * phba)
case LPFC_EVT_KILL:
lpfc_offline(phba);
*(int *)(evtp->evt_arg1)
- = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba);
+ = (phba->pport->stopped)
+ ? 0 : lpfc_sli_brdkill(phba);
lpfc_unblock_mgmt_io(phba);
complete((struct completion *)(evtp->evt_arg2));
break;
}
if (free_evt)
kfree(evtp);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
}
-static void
-lpfc_work_done(struct lpfc_hba * phba)
+void
+lpfc_work_done(struct lpfc_hba *phba)
{
struct lpfc_sli_ring *pring;
- int i;
- uint32_t ha_copy;
- uint32_t control;
- uint32_t work_hba_events;
+ uint32_t ha_copy, status, control, work_port_events;
+ struct lpfc_vport *vport;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
ha_copy = phba->work_ha;
phba->work_ha = 0;
- work_hba_events=phba->work_hba_events;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
if (ha_copy & HA_ERATT)
lpfc_handle_eratt(phba);
@@ -255,66 +365,111 @@ lpfc_work_done(struct lpfc_hba * phba)
if (ha_copy & HA_LATT)
lpfc_handle_latt(phba);
- if (work_hba_events & WORKER_DISC_TMO)
- lpfc_disc_timeout_handler(phba);
-
- if (work_hba_events & WORKER_ELS_TMO)
- lpfc_els_timeout_handler(phba);
-
- if (work_hba_events & WORKER_MBOX_TMO)
- lpfc_mbox_timeout_handler(phba);
-
- if (work_hba_events & WORKER_FDMI_TMO)
- lpfc_fdmi_tmo_handler(phba);
-
- spin_lock_irq(phba->host->host_lock);
- phba->work_hba_events &= ~work_hba_events;
- spin_unlock_irq(phba->host->host_lock);
-
- for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) {
- pring = &phba->sli.ring[i];
- if ((ha_copy & HA_RXATT)
- || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
- if (pring->flag & LPFC_STOP_IOCB_MASK) {
- pring->flag |= LPFC_DEFERRED_RING_EVENT;
- } else {
- lpfc_sli_handle_slow_ring_event(phba, pring,
- (ha_copy &
- HA_RXMASK));
- pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
- }
- /*
- * Turn on Ring interrupts
- */
- spin_lock_irq(phba->host->host_lock);
- control = readl(phba->HCregaddr);
- control |= (HC_R0INT_ENA << i);
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (!scsi_host_get(shost)) {
+ continue;
+ }
+ spin_unlock_irq(&phba->hbalock);
+ work_port_events = vport->work_port_events;
+
+ if (work_port_events & WORKER_DISC_TMO)
+ lpfc_disc_timeout_handler(vport);
+
+ if (work_port_events & WORKER_ELS_TMO)
+ lpfc_els_timeout_handler(vport);
+
+ if (work_port_events & WORKER_HB_TMO)
+ lpfc_hb_timeout_handler(phba);
+
+ if (work_port_events & WORKER_MBOX_TMO)
+ lpfc_mbox_timeout_handler(phba);
+
+ if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
+ lpfc_unblock_fabric_iocbs(phba);
+
+ if (work_port_events & WORKER_FDMI_TMO)
+ lpfc_fdmi_timeout_handler(vport);
+
+ if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
+ lpfc_ramp_down_queue_handler(phba);
+
+ if (work_port_events & WORKER_RAMP_UP_QUEUE)
+ lpfc_ramp_up_queue_handler(phba);
+
+ spin_lock_irq(&vport->work_port_lock);
+ vport->work_port_events &= ~work_port_events;
+ spin_unlock_irq(&vport->work_port_lock);
+ scsi_host_put(shost);
+ spin_lock_irq(&phba->hbalock);
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ pring = &phba->sli.ring[LPFC_ELS_RING];
+ status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING)));
+ status >>= (4*LPFC_ELS_RING);
+ if ((status & HA_RXMASK)
+ || (pring->flag & LPFC_DEFERRED_RING_EVENT)) {
+ if (pring->flag & LPFC_STOP_IOCB_MASK) {
+ pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ } else {
+ lpfc_sli_handle_slow_ring_event(phba, pring,
+ (status &
+ HA_RXMASK));
+ pring->flag &= ~LPFC_DEFERRED_RING_EVENT;
+ }
+ /*
+ * Turn on Ring interrupts
+ */
+ spin_lock_irq(&phba->hbalock);
+ control = readl(phba->HCregaddr);
+ if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
+ control |= (HC_R0INT_ENA << LPFC_ELS_RING);
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
}
+ spin_unlock_irq(&phba->hbalock);
}
-
- lpfc_work_list_done (phba);
-
+ lpfc_work_list_done(phba);
}
static int
-check_work_wait_done(struct lpfc_hba *phba) {
+check_work_wait_done(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct lpfc_sli_ring *pring;
+ int rc = 0;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ if (vport->work_port_events) {
+ rc = 1;
+ goto exit;
+ }
+ }
- spin_lock_irq(phba->host->host_lock);
- if (phba->work_ha ||
- phba->work_hba_events ||
- (!list_empty(&phba->work_list)) ||
+ if (phba->work_ha || (!list_empty(&phba->work_list)) ||
kthread_should_stop()) {
- spin_unlock_irq(phba->host->host_lock);
- return 1;
- } else {
- spin_unlock_irq(phba->host->host_lock);
- return 0;
+ rc = 1;
+ goto exit;
}
+
+ pring = &phba->sli.ring[LPFC_ELS_RING];
+ if (pring->flag & LPFC_DEFERRED_RING_EVENT)
+ rc = 1;
+exit:
+ if (rc)
+ phba->work_found++;
+ else
+ phba->work_found = 0;
+
+ spin_unlock_irq(&phba->hbalock);
+ return rc;
}
+
int
lpfc_do_work(void *p)
{
@@ -324,11 +479,13 @@ lpfc_do_work(void *p)
set_user_nice(current, -20);
phba->work_wait = &work_waitq;
+ phba->work_found = 0;
while (1) {
rc = wait_event_interruptible(work_waitq,
- check_work_wait_done(phba));
+ check_work_wait_done(phba));
+
BUG_ON(rc);
if (kthread_should_stop())
@@ -336,6 +493,17 @@ lpfc_do_work(void *p)
lpfc_work_done(phba);
+ /* If there is alot of slow ring work, like during link up
+ * check_work_wait_done() may cause this thread to not give
+ * up the CPU for very long periods of time. This may cause
+ * soft lockups or other problems. To avoid these situations
+ * give up the CPU here after LPFC_MAX_WORKER_ITERATION
+ * consecutive iterations.
+ */
+ if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) {
+ phba->work_found = 0;
+ schedule();
+ }
}
phba->work_wait = NULL;
return 0;
@@ -347,16 +515,17 @@ lpfc_do_work(void *p)
* embedding it in the IOCB.
*/
int
-lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
+lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2,
uint32_t evt)
{
struct lpfc_work_evt *evtp;
+ unsigned long flags;
/*
* All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will
* be queued to worker thread for processing
*/
- evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_KERNEL);
+ evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_ATOMIC);
if (!evtp)
return 0;
@@ -364,136 +533,210 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2,
evtp->evt_arg2 = arg2;
evtp->evt = evt;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irqsave(&phba->hbalock, flags);
list_add_tail(&evtp->evt_listp, &phba->work_list);
if (phba->work_wait)
- wake_up(phba->work_wait);
- spin_unlock_irq(phba->host->host_lock);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
return 1;
}
-int
-lpfc_linkdown(struct lpfc_hba *phba)
+void
+lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove)
{
- struct lpfc_sli *psli;
- struct lpfc_nodelist *ndlp, *next_ndlp;
- LPFC_MBOXQ_t *mb;
- int rc;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+ int rc;
- psli = &phba->sli;
- /* sysfs or selective reset may call this routine to clean up */
- if (phba->hba_state >= LPFC_LINK_DOWN) {
- if (phba->hba_state == LPFC_LINK_DOWN)
- return 0;
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ continue;
- spin_lock_irq(phba->host->host_lock);
- phba->hba_state = LPFC_LINK_DOWN;
- spin_unlock_irq(phba->host->host_lock);
+ if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN)
+ lpfc_unreg_rpi(vport, ndlp);
+
+ /* Leave Fabric nodes alone on link down */
+ if (!remove && ndlp->nlp_type & NLP_FABRIC)
+ continue;
+ rc = lpfc_disc_state_machine(vport, ndlp, NULL,
+ remove
+ ? NLP_EVT_DEVICE_RM
+ : NLP_EVT_DEVICE_RECOVERY);
}
+ if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) {
+ lpfc_mbx_unreg_vpi(vport);
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ }
+}
+
+static void
+lpfc_linkdown_port(struct lpfc_vport *vport)
+{
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
- fc_host_post_event(phba->host, fc_get_event_number(),
- FCH_EVT_LINKDOWN, 0);
+ fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0);
- /* Clean up any firmware default rpi's */
- if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- lpfc_unreg_did(phba, 0xffffffff, mb);
- mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
- if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
- == MBX_NOT_FINISHED) {
- mempool_free( mb, phba->mbox_mem_pool);
- }
- }
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Link Down: state:x%x rtry:x%x flg:x%x",
+ vport->port_state, vport->fc_ns_retry, vport->fc_flag);
/* Cleanup any outstanding RSCN activity */
- lpfc_els_flush_rscn(phba);
+ lpfc_els_flush_rscn(vport);
/* Cleanup any outstanding ELS commands */
- lpfc_els_flush_cmd(phba);
+ lpfc_els_flush_cmd(vport);
- /*
- * Issue a LINK DOWN event to all nodes.
- */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
- /* free any ndlp's on unused list */
+ lpfc_cleanup_rpis(vport, 0);
+
+ /* free any ndlp's on unused list */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
+ /* free any ndlp's in unused state */
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
- lpfc_drop_node(phba, ndlp);
- else /* otherwise, force node recovery. */
- rc = lpfc_disc_state_machine(phba, ndlp, NULL,
- NLP_EVT_DEVICE_RECOVERY);
+ lpfc_drop_node(vport, ndlp);
+
+ /* Turn off discovery timer if its running */
+ lpfc_can_disctmo(vport);
+}
+
+int
+lpfc_linkdown(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport = phba->pport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_vport *port_iterator;
+ LPFC_MBOXQ_t *mb;
+
+ if (phba->link_state == LPFC_LINK_DOWN) {
+ return 0;
+ }
+ spin_lock_irq(&phba->hbalock);
+ if (phba->link_state > LPFC_LINK_DOWN) {
+ phba->link_state = LPFC_LINK_DOWN;
+ phba->pport->fc_flag &= ~FC_LBIT;
+ }
+ spin_unlock_irq(&phba->hbalock);
+
+ list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+
+ /* Issue a LINK DOWN event to all nodes */
+ lpfc_linkdown_port(port_iterator);
+ }
+
+ /* Clean up any firmware default rpi's */
+ mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mb) {
+ lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb);
+ mb->vport = vport;
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
+ == MBX_NOT_FINISHED) {
+ mempool_free(mb, phba->mbox_mem_pool);
+ }
}
/* Setup myDID for link up if we are in pt2pt mode */
- if (phba->fc_flag & FC_PT2PT) {
- phba->fc_myDID = 0;
- if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
+ if (phba->pport->fc_flag & FC_PT2PT) {
+ phba->pport->fc_myDID = 0;
+ mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mb) {
lpfc_config_link(phba, mb);
- mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
- if (lpfc_sli_issue_mbox
- (phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB))
+ mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mb->vport = vport;
+ if (lpfc_sli_issue_mbox(phba, mb,
+ (MBX_NOWAIT | MBX_STOP_IOCB))
== MBX_NOT_FINISHED) {
- mempool_free( mb, phba->mbox_mem_pool);
+ mempool_free(mb, phba->mbox_mem_pool);
}
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI);
+ spin_unlock_irq(shost->host_lock);
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_LBIT;
- spin_unlock_irq(phba->host->host_lock);
-
- /* Turn off discovery timer if its running */
- lpfc_can_disctmo(phba);
- /* Must process IOCBs on all rings to handle ABORTed I/Os */
return 0;
}
-static int
-lpfc_linkup(struct lpfc_hba *phba)
+static void
+lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport)
{
- struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_nodelist *ndlp;
- fc_host_post_event(phba->host, fc_get_event_number(),
- FCH_EVT_LINKUP, 0);
-
- spin_lock_irq(phba->host->host_lock);
- phba->hba_state = LPFC_LINK_UP;
- phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
- FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);
- phba->fc_flag |= FC_NDISC_ACTIVE;
- phba->fc_ns_retry = 0;
- spin_unlock_irq(phba->host->host_lock);
-
-
- if (phba->fc_flag & FC_LBIT) {
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
- if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) {
- if (ndlp->nlp_type & NLP_FABRIC) {
- /*
- * On Linkup its safe to clean up the
- * ndlp from Fabric connections.
- */
- lpfc_nlp_set_state(phba, ndlp,
- NLP_STE_UNUSED_NODE);
- } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
- /*
- * Fail outstanding IO now since
- * device is marked for PLOGI.
- */
- lpfc_unreg_rpi(phba, ndlp);
- }
- }
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ continue;
+
+ if (ndlp->nlp_type & NLP_FABRIC) {
+ /* On Linkup its safe to clean up the ndlp
+ * from Fabric connections.
+ */
+ if (ndlp->nlp_DID != Fabric_DID)
+ lpfc_unreg_rpi(vport, ndlp);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
+ /* Fail outstanding IO now since device is
+ * marked for PLOGI.
+ */
+ lpfc_unreg_rpi(vport, ndlp);
}
}
+}
- /* free any ndlp's on unused list */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
- nlp_listp) {
+static void
+lpfc_linkup_port(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_hba *phba = vport->phba;
+
+ if ((vport->load_flag & FC_UNLOADING) != 0)
+ return;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "Link Up: top:x%x speed:x%x flg:x%x",
+ phba->fc_topology, phba->fc_linkspeed, phba->link_flag);
+
+ /* If NPIV is not enabled, only bring the physical port up */
+ if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ (vport != phba->pport))
+ return;
+
+ fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKUP, 0);
+
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
+ FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY);
+ vport->fc_flag |= FC_NDISC_ACTIVE;
+ vport->fc_ns_retry = 0;
+ spin_unlock_irq(shost->host_lock);
+
+ if (vport->fc_flag & FC_LBIT)
+ lpfc_linkup_cleanup_nodes(vport);
+
+ /* free any ndlp's in unused state */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
+ nlp_listp)
if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
+}
+
+static int
+lpfc_linkup(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+
+ phba->link_state = LPFC_LINK_UP;
+
+ /* Unblock fabric iocbs if they are blocked */
+ clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
+ del_timer_sync(&phba->fabric_block_timer);
+
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ lpfc_linkup_port(vport);
}
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ lpfc_issue_clear_la(phba, phba->pport);
return 0;
}
@@ -505,14 +748,14 @@ lpfc_linkup(struct lpfc_hba *phba)
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_sli *psli = &phba->sli;
+ MAILBOX_t *mb = &pmb->mb;
uint32_t control;
- psli = &phba->sli;
- mb = &pmb->mb;
/* Since we don't do discovery right now, turn these off here */
psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT;
@@ -522,69 +765,74 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) {
/* CLEAR_LA mbox error <mbxStatus> state <hba_state> */
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d:0320 CLEAR_LA mbxStatus error x%x hba "
+ "%d (%d):0320 CLEAR_LA mbxStatus error x%x hba "
"state x%x\n",
- phba->brd_no, mb->mbxStatus, phba->hba_state);
+ phba->brd_no, vport->vpi, mb->mbxStatus,
+ vport->port_state);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
goto out;
}
- if (phba->fc_flag & FC_ABORT_DISCOVERY)
- goto out;
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ phba->link_state = LPFC_HBA_READY;
- phba->num_disc_nodes = 0;
- /* go thru NPR list and issue ELS PLOGIs */
- if (phba->fc_npr_cnt) {
- lpfc_els_disc_plogi(phba);
- }
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag |= LPFC_PROCESS_LA;
+ control = readl(phba->HCregaddr);
+ control |= HC_LAINT_ENA;
+ writel(control, phba->HCregaddr);
+ readl(phba->HCregaddr); /* flush */
+ spin_unlock_irq(&phba->hbalock);
+ return;
+
+ vport->num_disc_nodes = 0;
+ /* go thru NPR nodes and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
- if (!phba->num_disc_nodes) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_NDISC_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
}
- phba->hba_state = LPFC_HBA_READY;
+ vport->port_state = LPFC_VPORT_READY;
out:
/* Device Discovery completes */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0225 Device Discovery completes\n",
- phba->brd_no);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0225 Device Discovery completes\n",
+ phba->brd_no, vport->vpi);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_ABORT_DISCOVERY;
- if (phba->fc_flag & FC_ESTABLISH_LINK) {
- phba->fc_flag &= ~FC_ESTABLISH_LINK;
- }
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_ABORT_DISCOVERY | FC_ESTABLISH_LINK);
+ spin_unlock_irq(shost->host_lock);
del_timer_sync(&phba->fc_estabtmo);
- lpfc_can_disctmo(phba);
+ lpfc_can_disctmo(vport);
/* turn on Link Attention interrupts */
- spin_lock_irq(phba->host->host_lock);
+
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return;
}
+
static void
lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli = &phba->sli;
- int rc;
+ struct lpfc_vport *vport = pmb->vport;
if (pmb->mb.mbxStatus)
goto out;
@@ -592,154 +840,139 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
mempool_free(pmb, phba->mbox_mem_pool);
if (phba->fc_topology == TOPOLOGY_LOOP &&
- phba->fc_flag & FC_PUBLIC_LOOP &&
- !(phba->fc_flag & FC_LBIT)) {
+ vport->fc_flag & FC_PUBLIC_LOOP &&
+ !(vport->fc_flag & FC_LBIT)) {
/* Need to wait for FAN - use discovery timer
- * for timeout. hba_state is identically
+ * for timeout. port_state is identically
* LPFC_LOCAL_CFG_LINK while waiting for FAN
*/
- lpfc_set_disctmo(phba);
+ lpfc_set_disctmo(vport);
return;
- }
+ }
- /* Start discovery by sending a FLOGI. hba_state is identically
+ /* Start discovery by sending a FLOGI. port_state is identically
* LPFC_FLOGI while waiting for FLOGI cmpl
*/
- phba->hba_state = LPFC_FLOGI;
- lpfc_set_disctmo(phba);
- lpfc_initial_flogi(phba);
+ if (vport->port_state != LPFC_FLOGI) {
+ vport->port_state = LPFC_FLOGI;
+ lpfc_set_disctmo(vport);
+ lpfc_initial_flogi(vport);
+ }
return;
out:
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d:0306 CONFIG_LINK mbxStatus error x%x "
+ "%d (%d):0306 CONFIG_LINK mbxStatus error x%x "
"HBA state x%x\n",
- phba->brd_no, pmb->mb.mbxStatus, phba->hba_state);
+ phba->brd_no, vport->vpi, pmb->mb.mbxStatus,
+ vport->port_state);
- lpfc_linkdown(phba);
+ mempool_free(pmb, phba->mbox_mem_pool);
- phba->hba_state = LPFC_HBA_ERROR;
+ lpfc_linkdown(phba);
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0200 CONFIG_LINK bad hba state x%x\n",
- phba->brd_no, phba->hba_state);
+ "%d (%d):0200 CONFIG_LINK bad hba state x%x\n",
+ phba->brd_no, vport->vpi, vport->port_state);
- lpfc_clear_la(phba, pmb);
- pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(pmb, phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
- }
+ lpfc_issue_clear_la(phba, vport);
return;
}
static void
-lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli = &phba->sli;
MAILBOX_t *mb = &pmb->mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1;
+ struct lpfc_vport *vport = pmb->vport;
/* Check for error */
if (mb->mbxStatus) {
/* READ_SPARAM mbox error <mbxStatus> state <hba_state> */
lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "%d:0319 READ_SPARAM mbxStatus error x%x "
+ "%d (%d):0319 READ_SPARAM mbxStatus error x%x "
"hba state x%x>\n",
- phba->brd_no, mb->mbxStatus, phba->hba_state);
+ phba->brd_no, vport->vpi, mb->mbxStatus,
+ vport->port_state);
lpfc_linkdown(phba);
- phba->hba_state = LPFC_HBA_ERROR;
goto out;
}
- memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt,
+ memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt,
sizeof (struct serv_parm));
if (phba->cfg_soft_wwnn)
- u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
+ u64_to_wwn(phba->cfg_soft_wwnn,
+ vport->fc_sparam.nodeName.u.wwn);
if (phba->cfg_soft_wwpn)
- u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
- memcpy((uint8_t *) & phba->fc_nodename,
- (uint8_t *) & phba->fc_sparam.nodeName,
- sizeof (struct lpfc_name));
- memcpy((uint8_t *) & phba->fc_portname,
- (uint8_t *) & phba->fc_sparam.portName,
- sizeof (struct lpfc_name));
+ u64_to_wwn(phba->cfg_soft_wwpn,
+ vport->fc_sparam.portName.u.wwn);
+ memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+ sizeof(vport->fc_nodename));
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+ sizeof(vport->fc_portname));
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn));
+ memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn));
+ }
+
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
out:
pmb->context1 = NULL;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- if (phba->hba_state != LPFC_CLEAR_LA) {
- lpfc_clear_la(phba, pmb);
- pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB))
- == MBX_NOT_FINISHED) {
- mempool_free( pmb, phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
- }
- } else {
- mempool_free( pmb, phba->mbox_mem_pool);
- }
+ lpfc_issue_clear_la(phba, vport);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
static void
lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
{
- int i;
+ struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox;
+ int i;
struct lpfc_dmabuf *mp;
int rc;
sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
switch (la->UlnkSpeed) {
- case LA_1GHZ_LINK:
- phba->fc_linkspeed = LA_1GHZ_LINK;
- break;
- case LA_2GHZ_LINK:
- phba->fc_linkspeed = LA_2GHZ_LINK;
- break;
- case LA_4GHZ_LINK:
- phba->fc_linkspeed = LA_4GHZ_LINK;
- break;
- case LA_8GHZ_LINK:
- phba->fc_linkspeed = LA_8GHZ_LINK;
- break;
- default:
- phba->fc_linkspeed = LA_UNKNW_LINK;
- break;
+ case LA_1GHZ_LINK:
+ phba->fc_linkspeed = LA_1GHZ_LINK;
+ break;
+ case LA_2GHZ_LINK:
+ phba->fc_linkspeed = LA_2GHZ_LINK;
+ break;
+ case LA_4GHZ_LINK:
+ phba->fc_linkspeed = LA_4GHZ_LINK;
+ break;
+ case LA_8GHZ_LINK:
+ phba->fc_linkspeed = LA_8GHZ_LINK;
+ break;
+ default:
+ phba->fc_linkspeed = LA_UNKNW_LINK;
+ break;
}
phba->fc_topology = la->topology;
+ phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
if (phba->fc_topology == TOPOLOGY_LOOP) {
- /* Get Loop Map information */
+ phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED;
+ /* Get Loop Map information */
if (la->il)
- phba->fc_flag |= FC_LBIT;
+ vport->fc_flag |= FC_LBIT;
- phba->fc_myDID = la->granted_AL_PA;
+ vport->fc_myDID = la->granted_AL_PA;
i = la->un.lilpBde64.tus.f.bdeSize;
if (i == 0) {
@@ -769,29 +1002,35 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
}
/* Link Up Event ALPA map */
lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_LINK_EVENT,
- "%d:1304 Link Up Event "
- "ALPA map Data: x%x "
- "x%x x%x x%x\n",
- phba->brd_no,
- un.pa.wd1, un.pa.wd2,
- un.pa.wd3, un.pa.wd4);
+ KERN_WARNING,
+ LOG_LINK_EVENT,
+ "%d:1304 Link Up Event "
+ "ALPA map Data: x%x "
+ "x%x x%x x%x\n",
+ phba->brd_no,
+ un.pa.wd1, un.pa.wd2,
+ un.pa.wd3, un.pa.wd4);
}
}
}
} else {
- phba->fc_myDID = phba->fc_pref_DID;
- phba->fc_flag |= FC_LBIT;
+ if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
+ if (phba->max_vpi && phba->cfg_npiv_enable &&
+ (phba->sli_rev == 3))
+ phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
+ }
+ vport->fc_myDID = phba->fc_pref_DID;
+ vport->fc_flag |= FC_LBIT;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_linkup(phba);
if (sparam_mbox) {
- lpfc_read_sparam(phba, sparam_mbox);
+ lpfc_read_sparam(phba, sparam_mbox, 0);
+ sparam_mbox->vport = vport;
sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam;
rc = lpfc_sli_issue_mbox(phba, sparam_mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
+ (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED) {
mp = (struct lpfc_dmabuf *) sparam_mbox->context1;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -799,36 +1038,48 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la)
mempool_free(sparam_mbox, phba->mbox_mem_pool);
if (cfglink_mbox)
mempool_free(cfglink_mbox, phba->mbox_mem_pool);
- return;
+ goto out;
}
}
if (cfglink_mbox) {
- phba->hba_state = LPFC_LOCAL_CFG_LINK;
+ vport->port_state = LPFC_LOCAL_CFG_LINK;
lpfc_config_link(phba, cfglink_mbox);
+ cfglink_mbox->vport = vport;
cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link;
rc = lpfc_sli_issue_mbox(phba, cfglink_mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED)
- mempool_free(cfglink_mbox, phba->mbox_mem_pool);
+ (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc != MBX_NOT_FINISHED)
+ return;
+ mempool_free(cfglink_mbox, phba->mbox_mem_pool);
}
+out:
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0263 Discovery Mailbox error: state: 0x%x : %p %p\n",
+ phba->brd_no, vport->vpi,
+ vport->port_state, sparam_mbox, cfglink_mbox);
+
+ lpfc_issue_clear_la(phba, vport);
+ return;
}
static void
-lpfc_mbx_issue_link_down(struct lpfc_hba *phba) {
+lpfc_mbx_issue_link_down(struct lpfc_hba *phba)
+{
uint32_t control;
struct lpfc_sli *psli = &phba->sli;
lpfc_linkdown(phba);
/* turn on Link Attention interrupts - no CLEAR_LA needed */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
}
/*
@@ -838,22 +1089,21 @@ lpfc_mbx_issue_link_down(struct lpfc_hba *phba) {
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
READ_LA_VAR *la;
MAILBOX_t *mb = &pmb->mb;
struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
/* Check for error */
if (mb->mbxStatus) {
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_LINK_EVENT,
+ lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"%d:1307 READ_LA mbox error x%x state x%x\n",
- phba->brd_no,
- mb->mbxStatus, phba->hba_state);
+ phba->brd_no, mb->mbxStatus, vport->port_state);
lpfc_mbx_issue_link_down(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
goto lpfc_mbx_cmpl_read_la_free_mbuf;
}
@@ -861,27 +1111,26 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
memcpy(&phba->alpa_map[0], mp->virt, 128);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
if (la->pb)
- phba->fc_flag |= FC_BYPASSED_MODE;
+ vport->fc_flag |= FC_BYPASSED_MODE;
else
- phba->fc_flag &= ~FC_BYPASSED_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ vport->fc_flag &= ~FC_BYPASSED_MODE;
+ spin_unlock_irq(shost->host_lock);
if (((phba->fc_eventTag + 1) < la->eventTag) ||
- (phba->fc_eventTag == la->eventTag)) {
+ (phba->fc_eventTag == la->eventTag)) {
phba->fc_stat.LinkMultiEvent++;
- if (la->attType == AT_LINK_UP) {
+ if (la->attType == AT_LINK_UP)
if (phba->fc_eventTag != 0)
lpfc_linkdown(phba);
- }
}
phba->fc_eventTag = la->eventTag;
if (la->attType == AT_LINK_UP) {
phba->fc_stat.LinkUp++;
- if (phba->fc_flag & FC_LOOPBACK_MODE) {
+ if (phba->link_flag & LS_LOOPBACK_MODE) {
lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
"%d:1306 Link Up Event in loop back mode "
"x%x received Data: x%x x%x x%x x%x\n",
@@ -903,7 +1152,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
"%d:1305 Link Down Event x%x received "
"Data: x%x x%x x%x\n",
phba->brd_no, la->eventTag, phba->fc_eventTag,
- phba->hba_state, phba->fc_flag);
+ phba->pport->port_state, vport->fc_flag);
lpfc_mbx_issue_link_down(phba);
}
@@ -921,31 +1170,115 @@ lpfc_mbx_cmpl_read_la_free_mbuf:
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
- struct lpfc_nodelist *ndlp;
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
- ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_vport *vport = pmb->vport;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
pmb->context1 = NULL;
/* Good status, call state machine */
- lpfc_disc_state_machine(phba, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
+ lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
lpfc_nlp_put(ndlp);
return;
}
+static void
+lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ switch (mb->mbxStatus) {
+ case 0x0011:
+ case 0x0020:
+ case 0x9700:
+ lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+ "%d (%d):0911 cmpl_unreg_vpi, "
+ "mb status = 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
+ break;
+ }
+ vport->unreg_vpi_cmpl = VPORT_OK;
+ mempool_free(pmb, phba->mbox_mem_pool);
+ /*
+ * This shost reference might have been taken at the beginning of
+ * lpfc_vport_delete()
+ */
+ if (vport->load_flag & FC_UNLOADING)
+ scsi_host_put(shost);
+}
+
+void
+lpfc_mbx_unreg_vpi(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox)
+ return;
+
+ lpfc_unreg_vpi(phba, vport->vpi, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
+ rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ "%d (%d):1800 Could not issue unreg_vpi\n",
+ phba->brd_no, vport->vpi);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ vport->unreg_vpi_cmpl = VPORT_ERROR;
+ }
+}
+
+static void
+lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
+{
+ struct lpfc_vport *vport = pmb->vport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ MAILBOX_t *mb = &pmb->mb;
+
+ switch (mb->mbxStatus) {
+ case 0x0011:
+ case 0x9601:
+ case 0x9602:
+ lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
+ "%d (%d):0912 cmpl_reg_vpi, mb status = 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
+ spin_unlock_irq(shost->host_lock);
+ vport->fc_myDID = 0;
+ goto out;
+ }
+
+ vport->num_disc_nodes = 0;
+ /* go thru NPR list and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
+
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
+ }
+ vport->port_state = LPFC_VPORT_READY;
+
+out:
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return;
+}
+
/*
* This routine handles processing a Fabric REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
@@ -953,20 +1286,14 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
+ struct lpfc_vport *vport = pmb->vport;
+ struct lpfc_vport *next_vport;
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
struct lpfc_nodelist *ndlp;
- struct lpfc_nodelist *ndlp_fdmi;
-
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
pmb->context1 = NULL;
pmb->context2 = NULL;
@@ -977,60 +1304,46 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_nlp_put(ndlp);
- /* FLOGI failed, so just use loop map to make discovery list */
- lpfc_disc_list_loopmap(phba);
+ if (phba->fc_topology == TOPOLOGY_LOOP) {
+ /* FLOGI failed, use loop map to make discovery list */
+ lpfc_disc_list_loopmap(vport);
+
+ /* Start discovery */
+ lpfc_disc_start(vport);
+ return;
+ }
+
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+ "%d (%d):0258 Register Fabric login error: 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
- /* Start discovery */
- lpfc_disc_start(phba);
return;
}
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */
- if (phba->hba_state == LPFC_FABRIC_CFG_LINK) {
- /* This NPort has been assigned an NPort_ID by the fabric as a
- * result of the completed fabric login. Issue a State Change
- * Registration (SCR) ELS request to the fabric controller
- * (SCR_DID) so that this NPort gets RSCN events from the
- * fabric.
- */
- lpfc_issue_els_scr(phba, SCR_DID, 0);
-
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (!ndlp) {
- /* Allocate a new node instance. If the pool is empty,
- * start the discovery process and skip the Nameserver
- * login process. This is attempted again later on.
- * Otherwise, issue a Port Login (PLOGI) to NameServer.
- */
- ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
- if (!ndlp) {
- lpfc_disc_start(phba);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- mempool_free(pmb, phba->mbox_mem_pool);
- return;
- } else {
- lpfc_nlp_init(phba, ndlp, NameServer_DID);
- ndlp->nlp_type |= NLP_FABRIC;
- }
- }
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, NameServer_DID, 0);
- if (phba->cfg_fdmi_on) {
- ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
- GFP_KERNEL);
- if (ndlp_fdmi) {
- lpfc_nlp_init(phba, ndlp_fdmi, FDMI_DID);
- ndlp_fdmi->nlp_type |= NLP_FABRIC;
- ndlp_fdmi->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_issue_els_plogi(phba, FDMI_DID, 0);
+ if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
+ list_for_each_entry(next_vport, &phba->port_list, listentry) {
+ if (next_vport->port_type == LPFC_PHYSICAL_PORT)
+ continue;
+
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
+ lpfc_initial_fdisc(next_vport);
+ else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
+ lpfc_vport_set_state(vport,
+ FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0259 No NPIV Fabric "
+ "support\n",
+ phba->brd_no, vport->vpi);
}
}
+ lpfc_do_scr_ns_plogi(phba, vport);
}
lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -1046,32 +1359,36 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
- struct lpfc_nodelist *ndlp;
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
- ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct lpfc_vport *vport = pmb->vport;
if (mb->mbxStatus) {
+out:
lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(pmb, phba->mbox_mem_pool);
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
- /* RegLogin failed, so just use loop map to make discovery
- list */
- lpfc_disc_list_loopmap(phba);
+ if (phba->fc_topology == TOPOLOGY_LOOP) {
+ /*
+ * RegLogin failed, use loop map to make discovery
+ * list
+ */
+ lpfc_disc_list_loopmap(vport);
- /* Start discovery */
- lpfc_disc_start(phba);
+ /* Start discovery */
+ lpfc_disc_start(vport);
+ return;
+ }
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0260 Register NameServer error: 0x%x\n",
+ phba->brd_no, vport->vpi, mb->mbxStatus);
return;
}
@@ -1079,37 +1396,43 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- if (phba->hba_state < LPFC_HBA_READY) {
- /* Link up discovery requires Fabrib registration. */
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RNN_ID);
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RSNN_NN);
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFT_ID);
- lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFF_ID);
+ if (vport->port_state < LPFC_VPORT_READY) {
+ /* Link up discovery requires Fabric registration. */
+ lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, 0); /* Do this first! */
+ lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0);
+ lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0);
+ lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0);
+ lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0);
+
+ /* Issue SCR just before NameServer GID_FT Query */
+ lpfc_issue_els_scr(vport, SCR_DID, 0);
}
- phba->fc_ns_retry = 0;
+ vport->fc_ns_retry = 0;
/* Good status, issue CT Request to NameServer */
- if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT)) {
+ if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0)) {
/* Cannot issue NameServer Query, so finish up discovery */
- lpfc_disc_start(phba);
+ goto out;
}
lpfc_nlp_put(ndlp);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
static void
-lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- struct fc_rport *rport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct fc_rport *rport;
struct lpfc_rport_data *rdata;
struct fc_rport_identifiers rport_ids;
+ struct lpfc_hba *phba = vport->phba;
/* Remote port has reappeared. Re-register w/ FC transport */
rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
@@ -1125,10 +1448,15 @@ lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
* registered the port.
*/
if (ndlp->rport && ndlp->rport->dd_data &&
- *(struct lpfc_rport_data **) ndlp->rport->dd_data) {
+ ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) {
lpfc_nlp_put(ndlp);
}
- ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport add: did:x%x flg:x%x type x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
+
+ ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids);
if (!rport || !get_device(&rport->dev)) {
dev_printk(KERN_WARNING, &phba->pcidev->dev,
"Warning: fc_remote_port_add failed\n");
@@ -1151,25 +1479,20 @@ lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
fc_remote_port_rolechg(rport, rport_ids.roles);
if ((rport->scsi_target_id != -1) &&
- (rport->scsi_target_id < LPFC_MAX_TARGET)) {
+ (rport->scsi_target_id < LPFC_MAX_TARGET)) {
ndlp->nlp_sid = rport->scsi_target_id;
}
-
return;
}
static void
-lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp)
{
struct fc_rport *rport = ndlp->rport;
- struct lpfc_rport_data *rdata = rport->dd_data;
- if (rport->scsi_target_id == -1) {
- ndlp->rport = NULL;
- rdata->pnode = NULL;
- lpfc_nlp_put(ndlp);
- put_device(&rport->dev);
- }
+ lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT,
+ "rport delete: did:x%x flg:x%x type x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
fc_remote_port_delete(rport);
@@ -1177,42 +1500,46 @@ lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
}
static void
-lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count)
+lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count)
{
- spin_lock_irq(phba->host->host_lock);
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irq(shost->host_lock);
switch (state) {
case NLP_STE_UNUSED_NODE:
- phba->fc_unused_cnt += count;
+ vport->fc_unused_cnt += count;
break;
case NLP_STE_PLOGI_ISSUE:
- phba->fc_plogi_cnt += count;
+ vport->fc_plogi_cnt += count;
break;
case NLP_STE_ADISC_ISSUE:
- phba->fc_adisc_cnt += count;
+ vport->fc_adisc_cnt += count;
break;
case NLP_STE_REG_LOGIN_ISSUE:
- phba->fc_reglogin_cnt += count;
+ vport->fc_reglogin_cnt += count;
break;
case NLP_STE_PRLI_ISSUE:
- phba->fc_prli_cnt += count;
+ vport->fc_prli_cnt += count;
break;
case NLP_STE_UNMAPPED_NODE:
- phba->fc_unmap_cnt += count;
+ vport->fc_unmap_cnt += count;
break;
case NLP_STE_MAPPED_NODE:
- phba->fc_map_cnt += count;
+ vport->fc_map_cnt += count;
break;
case NLP_STE_NPR_NODE:
- phba->fc_npr_cnt += count;
+ vport->fc_npr_cnt += count;
break;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
}
static void
-lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
int old_state, int new_state)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if (new_state == NLP_STE_UNMAPPED_NODE) {
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
@@ -1226,35 +1553,34 @@ lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
/* Transport interface */
if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE ||
old_state == NLP_STE_UNMAPPED_NODE)) {
- phba->nport_event_cnt++;
- lpfc_unregister_remote_port(phba, ndlp);
+ vport->phba->nport_event_cnt++;
+ lpfc_unregister_remote_port(ndlp);
}
if (new_state == NLP_STE_MAPPED_NODE ||
new_state == NLP_STE_UNMAPPED_NODE) {
- phba->nport_event_cnt++;
- /*
- * Tell the fc transport about the port, if we haven't
- * already. If we have, and it's a scsi entity, be
- * sure to unblock any attached scsi devices
- */
- lpfc_register_remote_port(phba, ndlp);
+ vport->phba->nport_event_cnt++;
+ /*
+ * Tell the fc transport about the port, if we haven't
+ * already. If we have, and it's a scsi entity, be
+ * sure to unblock any attached scsi devices
+ */
+ lpfc_register_remote_port(vport, ndlp);
}
-
- /*
- * if we added to Mapped list, but the remote port
- * registration failed or assigned a target id outside
- * our presentable range - move the node to the
- * Unmapped List
- */
+ /*
+ * if we added to Mapped list, but the remote port
+ * registration failed or assigned a target id outside
+ * our presentable range - move the node to the
+ * Unmapped List
+ */
if (new_state == NLP_STE_MAPPED_NODE &&
(!ndlp->rport ||
ndlp->rport->scsi_target_id == -1 ||
ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_TGT_NO_SCSIID;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
}
@@ -1280,61 +1606,74 @@ lpfc_nlp_state_name(char *buffer, size_t size, int state)
}
void
-lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state)
+lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ int state)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
int old_state = ndlp->nlp_state;
char name1[16], name2[16];
- lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0904 NPort state transition x%06x, %s -> %s\n",
- phba->brd_no,
+ lpfc_printf_log(vport->phba, KERN_INFO, LOG_NODE,
+ "%d (%d):0904 NPort state transition x%06x, %s -> %s\n",
+ vport->phba->brd_no, vport->vpi,
ndlp->nlp_DID,
lpfc_nlp_state_name(name1, sizeof(name1), old_state),
lpfc_nlp_state_name(name2, sizeof(name2), state));
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
+ "node statechg did:x%x old:%d ste:%d",
+ ndlp->nlp_DID, old_state, state);
+
if (old_state == NLP_STE_NPR_NODE &&
(ndlp->nlp_flag & NLP_DELAY_TMO) != 0 &&
state != NLP_STE_NPR_NODE)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (old_state == NLP_STE_UNMAPPED_NODE) {
ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID;
ndlp->nlp_type &= ~NLP_FC_NODE;
}
if (list_empty(&ndlp->nlp_listp)) {
- spin_lock_irq(phba->host->host_lock);
- list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes);
+ spin_unlock_irq(shost->host_lock);
} else if (old_state)
- lpfc_nlp_counters(phba, old_state, -1);
+ lpfc_nlp_counters(vport, old_state, -1);
ndlp->nlp_state = state;
- lpfc_nlp_counters(phba, state, 1);
- lpfc_nlp_state_cleanup(phba, ndlp, old_state, state);
+ lpfc_nlp_counters(vport, state, 1);
+ lpfc_nlp_state_cleanup(vport, ndlp, old_state, state);
}
void
-lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
- lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
+ spin_lock_irq(shost->host_lock);
list_del_init(&ndlp->nlp_listp);
- spin_unlock_irq(phba->host->host_lock);
- lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state,
+ NLP_STE_UNUSED_NODE);
}
void
-lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
- lpfc_nlp_counters(phba, ndlp->nlp_state, -1);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
+ spin_lock_irq(shost->host_lock);
list_del_init(&ndlp->nlp_listp);
- spin_unlock_irq(phba->host->host_lock);
+ ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
+ spin_unlock_irq(shost->host_lock);
lpfc_nlp_put(ndlp);
}
@@ -1342,11 +1681,13 @@ lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
* Start / ReStart rescue timer for Discovery / RSCN handling
*/
void
-lpfc_set_disctmo(struct lpfc_hba * phba)
+lpfc_set_disctmo(struct lpfc_vport *vport)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
uint32_t tmo;
- if (phba->hba_state == LPFC_LOCAL_CFG_LINK) {
+ if (vport->port_state == LPFC_LOCAL_CFG_LINK) {
/* For FAN, timeout should be greater then edtov */
tmo = (((phba->fc_edtov + 999) / 1000) + 1);
} else {
@@ -1356,18 +1697,25 @@ lpfc_set_disctmo(struct lpfc_hba * phba)
tmo = ((phba->fc_ratov * 3) + 3);
}
- mod_timer(&phba->fc_disctmo, jiffies + HZ * tmo);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_DISC_TMO;
- spin_unlock_irq(phba->host->host_lock);
+
+ if (!timer_pending(&vport->fc_disctmo)) {
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "set disc timer: tmo:x%x state:x%x flg:x%x",
+ tmo, vport->port_state, vport->fc_flag);
+ }
+
+ mod_timer(&vport->fc_disctmo, jiffies + HZ * tmo);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_DISC_TMO;
+ spin_unlock_irq(shost->host_lock);
/* Start Discovery Timer state <hba_state> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0247 Start Discovery Timer state x%x "
+ "%d (%d):0247 Start Discovery Timer state x%x "
"Data: x%x x%lx x%x x%x\n",
- phba->brd_no,
- phba->hba_state, tmo, (unsigned long)&phba->fc_disctmo,
- phba->fc_plogi_cnt, phba->fc_adisc_cnt);
+ phba->brd_no, vport->vpi, vport->port_state, tmo,
+ (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
return;
}
@@ -1376,23 +1724,34 @@ lpfc_set_disctmo(struct lpfc_hba * phba)
* Cancel rescue timer for Discovery / RSCN handling
*/
int
-lpfc_can_disctmo(struct lpfc_hba * phba)
+lpfc_can_disctmo(struct lpfc_vport *vport)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ unsigned long iflags;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "can disc timer: state:x%x rtry:x%x flg:x%x",
+ vport->port_state, vport->fc_ns_retry, vport->fc_flag);
+
/* Turn off discovery timer if its running */
- if (phba->fc_flag & FC_DISC_TMO) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_DISC_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&phba->fc_disctmo);
- phba->work_hba_events &= ~WORKER_DISC_TMO;
+ if (vport->fc_flag & FC_DISC_TMO) {
+ spin_lock_irqsave(shost->host_lock, iflags);
+ vport->fc_flag &= ~FC_DISC_TMO;
+ spin_unlock_irqrestore(shost->host_lock, iflags);
+ del_timer_sync(&vport->fc_disctmo);
+ spin_lock_irqsave(&vport->work_port_lock, iflags);
+ vport->work_port_events &= ~WORKER_DISC_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, iflags);
}
/* Cancel Discovery Timer state <hba_state> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0248 Cancel Discovery Timer state x%x "
+ "%d (%d):0248 Cancel Discovery Timer state x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->hba_state, phba->fc_flag,
- phba->fc_plogi_cnt, phba->fc_adisc_cnt);
+ phba->brd_no, vport->vpi, vport->port_state,
+ vport->fc_flag, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
return 0;
}
@@ -1402,15 +1761,18 @@ lpfc_can_disctmo(struct lpfc_hba * phba)
* Return true if iocb matches the specified nport
*/
int
-lpfc_check_sli_ndlp(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * iocb, struct lpfc_nodelist * ndlp)
+lpfc_check_sli_ndlp(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *iocb,
+ struct lpfc_nodelist *ndlp)
{
- struct lpfc_sli *psli;
- IOCB_t *icmd;
+ struct lpfc_sli *psli = &phba->sli;
+ IOCB_t *icmd = &iocb->iocb;
+ struct lpfc_vport *vport = ndlp->vport;
+
+ if (iocb->vport != vport)
+ return 0;
- psli = &phba->sli;
- icmd = &iocb->iocb;
if (pring->ringno == LPFC_ELS_RING) {
switch (icmd->ulpCommand) {
case CMD_GEN_REQUEST64_CR:
@@ -1428,7 +1790,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
} else if (pring->ringno == psli->fcp_ring) {
/* Skip match check if waiting to relogin to FCP target */
if ((ndlp->nlp_type & NLP_FCP_TARGET) &&
- (ndlp->nlp_flag & NLP_DELAY_TMO)) {
+ (ndlp->nlp_flag & NLP_DELAY_TMO)) {
return 0;
}
if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) {
@@ -1445,7 +1807,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba,
* associated with nlp_rpi in the LPFC_NODELIST entry.
*/
static int
-lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
struct lpfc_sli *psli;
@@ -1454,6 +1816,8 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
IOCB_t *icmd;
uint32_t rpi, i;
+ lpfc_fabric_abort_nport(ndlp);
+
/*
* Everything that matches on txcmplq will be returned
* by firmware with a no rpi error.
@@ -1465,15 +1829,15 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq,
- list) {
+ list) {
/*
* Check to see if iocb matches the nport we are
* looking for
*/
- if ((lpfc_check_sli_ndlp
- (phba, pring, iocb, ndlp))) {
+ if ((lpfc_check_sli_ndlp(phba, pring, iocb,
+ ndlp))) {
/* It matches, so deque and call compl
with an error */
list_move_tail(&iocb->list,
@@ -1481,22 +1845,22 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
pring->txq_cnt--;
}
}
- spin_unlock_irq(phba->host->host_lock);
-
+ spin_unlock_irq(&phba->hbalock);
}
}
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
icmd = &iocb->iocb;
icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- (iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ (iocb->iocb_cmpl)(phba, iocb, iocb);
+ }
}
return 0;
@@ -1512,19 +1876,22 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
* we are waiting to PLOGI back to the remote NPort.
*/
int
-lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- LPFC_MBOXQ_t *mbox;
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
int rc;
if (ndlp->nlp_rpi) {
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox);
- mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox
- (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED)
- mempool_free( mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
}
lpfc_no_rpi(phba, ndlp);
ndlp->nlp_rpi = 0;
@@ -1533,25 +1900,70 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
return 0;
}
+void
+lpfc_unreg_all_rpis(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+}
+
+void
+lpfc_unreg_default_rpis(struct lpfc_vport *vport)
+{
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mbox;
+ int rc;
+
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (mbox) {
+ lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox);
+ mbox->vport = vport;
+ mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ rc = lpfc_sli_issue_mbox(phba, mbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
+ "%d (%d):1815 Could not issue "
+ "unreg_did (default rpis)\n",
+ phba->brd_no, vport->vpi);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
+ }
+}
+
/*
* Free resources associated with LPFC_NODELIST entry
* so it can be freed.
*/
static int
-lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
- LPFC_MBOXQ_t *mb;
- LPFC_MBOXQ_t *nextmb;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *mb, *nextmb;
struct lpfc_dmabuf *mp;
/* Cleanup node for NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0900 Cleanup node for NPort x%x "
+ "%d (%d):0900 Cleanup node for NPort x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
+ phba->brd_no, vport->vpi, ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
- lpfc_dequeue_node(phba, ndlp);
+ lpfc_dequeue_node(vport, ndlp);
/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
if ((mb = phba->sli.mbox_active)) {
@@ -1562,13 +1974,13 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
}
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
- (ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ (ndlp == (struct lpfc_nodelist *) mb->context2)) {
mp = (struct lpfc_dmabuf *) (mb->context1);
if (mp) {
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ __lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
list_del(&mb->list);
@@ -1576,20 +1988,27 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
lpfc_nlp_put(ndlp);
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_els_abort(phba,ndlp);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = 0;
del_timer_sync(&ndlp->nlp_delayfunc);
if (!list_empty(&ndlp->els_retry_evt.evt_listp))
list_del_init(&ndlp->els_retry_evt.evt_listp);
+ if (!list_empty(&ndlp->dev_loss_evt.evt_listp))
+ list_del_init(&ndlp->dev_loss_evt.evt_listp);
+
+ if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) {
+ list_del_init(&ndlp->dev_loss_evt.evt_listp);
+ complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2));
+ }
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
return 0;
}
@@ -1600,18 +2019,22 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
* machine, defer the free till we reach the end of the state machine.
*/
static void
-lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
struct lpfc_rport_data *rdata;
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
- lpfc_cleanup_node(phba, ndlp);
+ lpfc_cleanup_node(vport, ndlp);
- if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) {
- put_device(&ndlp->rport->dev);
+ /*
+ * We can get here with a non-NULL ndlp->rport because when we
+ * unregister a rport we don't break the rport/node linkage. So if we
+ * do, make sure we don't leaving any dangling pointers behind.
+ */
+ if (ndlp->rport) {
rdata = ndlp->rport->dd_data;
rdata->pnode = NULL;
ndlp->rport = NULL;
@@ -1619,11 +2042,10 @@ lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
}
static int
-lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
+lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint32_t did)
{
- D_ID mydid;
- D_ID ndlpdid;
- D_ID matchdid;
+ D_ID mydid, ndlpdid, matchdid;
if (did == Bcast_DID)
return 0;
@@ -1637,7 +2059,7 @@ lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
return 1;
/* Next check for area/domain identically equals 0 match */
- mydid.un.word = phba->fc_myDID;
+ mydid.un.word = vport->fc_myDID;
if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
return 0;
}
@@ -1669,101 +2091,116 @@ lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
}
/* Search for a nodelist entry */
-struct lpfc_nodelist *
-lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did)
+static struct lpfc_nodelist *
+__lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp;
uint32_t data1;
- spin_lock_irq(phba->host->host_lock);
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
- if (lpfc_matchdid(phba, ndlp, did)) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
+ if (lpfc_matchdid(vport, ndlp, did)) {
data1 = (((uint32_t) ndlp->nlp_state << 24) |
((uint32_t) ndlp->nlp_xri << 16) |
((uint32_t) ndlp->nlp_type << 8) |
((uint32_t) ndlp->nlp_rpi & 0xff));
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0929 FIND node DID "
+ "%d (%d):0929 FIND node DID "
" Data: x%p x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
ndlp, ndlp->nlp_DID,
ndlp->nlp_flag, data1);
- spin_unlock_irq(phba->host->host_lock);
return ndlp;
}
}
- spin_unlock_irq(phba->host->host_lock);
/* FIND node did <did> NOT FOUND */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0932 FIND node did x%x NOT FOUND.\n",
- phba->brd_no, did);
+ "%d (%d):0932 FIND node did x%x NOT FOUND.\n",
+ phba->brd_no, vport->vpi, did);
return NULL;
}
struct lpfc_nodelist *
-lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did)
+lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- ndlp = lpfc_findnode_did(phba, did);
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_findnode_did(vport, did);
+ spin_unlock_irq(shost->host_lock);
+ return ndlp;
+}
+
+struct lpfc_nodelist *
+lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_nodelist *ndlp;
+
+ ndlp = lpfc_findnode_did(vport, did);
if (!ndlp) {
- if ((phba->fc_flag & FC_RSCN_MODE) &&
- ((lpfc_rscn_payload_check(phba, did) == 0)))
+ if ((vport->fc_flag & FC_RSCN_MODE) != 0 &&
+ lpfc_rscn_payload_check(vport, did) == 0)
return NULL;
ndlp = (struct lpfc_nodelist *)
- mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ mempool_alloc(vport->phba->nlp_mem_pool, GFP_KERNEL);
if (!ndlp)
return NULL;
- lpfc_nlp_init(phba, ndlp, did);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_init(vport, ndlp, did);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
return ndlp;
}
- if (phba->fc_flag & FC_RSCN_MODE) {
- if (lpfc_rscn_payload_check(phba, did)) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ if (lpfc_rscn_payload_check(vport, did)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
/* Since this node is marked for discovery,
* delay timeout is not needed.
*/
if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
} else
ndlp = NULL;
} else {
if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE ||
ndlp->nlp_state == NLP_STE_PLOGI_ISSUE)
return NULL;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NPR_2B_DISC;
+ spin_unlock_irq(shost->host_lock);
}
return ndlp;
}
/* Build a list of nodes to discover based on the loopmap */
void
-lpfc_disc_list_loopmap(struct lpfc_hba * phba)
+lpfc_disc_list_loopmap(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
int j;
uint32_t alpa, index;
- if (phba->hba_state <= LPFC_LINK_DOWN) {
+ if (!lpfc_is_link_up(phba))
return;
- }
- if (phba->fc_topology != TOPOLOGY_LOOP) {
+
+ if (phba->fc_topology != TOPOLOGY_LOOP)
return;
- }
/* Check for loop map present or not */
if (phba->alpa_map[0]) {
for (j = 1; j <= phba->alpa_map[0]; j++) {
alpa = phba->alpa_map[j];
-
- if (((phba->fc_myDID & 0xff) == alpa) || (alpa == 0)) {
+ if (((vport->fc_myDID & 0xff) == alpa) || (alpa == 0))
continue;
- }
- lpfc_setup_disc_node(phba, alpa);
+ lpfc_setup_disc_node(vport, alpa);
}
} else {
/* No alpamap, so try all alpa's */
@@ -1776,113 +2213,167 @@ lpfc_disc_list_loopmap(struct lpfc_hba * phba)
else
index = FC_MAXLOOP - j - 1;
alpa = lpfcAlpaArray[index];
- if ((phba->fc_myDID & 0xff) == alpa) {
+ if ((vport->fc_myDID & 0xff) == alpa)
continue;
- }
-
- lpfc_setup_disc_node(phba, alpa);
+ lpfc_setup_disc_node(vport, alpa);
}
}
return;
}
-/* Start Link up / RSCN discovery on NPR list */
void
-lpfc_disc_start(struct lpfc_hba * phba)
+lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport)
{
- struct lpfc_sli *psli;
LPFC_MBOXQ_t *mbox;
- struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *extra_ring = &psli->ring[psli->extra_ring];
+ struct lpfc_sli_ring *fcp_ring = &psli->ring[psli->fcp_ring];
+ struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring];
+ int rc;
+
+ /*
+ * if it's not a physical port or if we already send
+ * clear_la then don't send it.
+ */
+ if ((phba->link_state >= LPFC_CLEAR_LA) ||
+ (vport->port_type != LPFC_PHYSICAL_PORT))
+ return;
+
+ /* Link up discovery */
+ if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) {
+ phba->link_state = LPFC_CLEAR_LA;
+ lpfc_clear_la(phba, mbox);
+ mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
+ mbox->vport = vport;
+ rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT |
+ MBX_STOP_IOCB));
+ if (rc == MBX_NOT_FINISHED) {
+ mempool_free(mbox, phba->mbox_mem_pool);
+ lpfc_disc_flush_list(vport);
+ extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
+ fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
+ next_ring->flag &= ~LPFC_STOP_IOCB_EVENT;
+ phba->link_state = LPFC_HBA_ERROR;
+ }
+ }
+}
+
+/* Reg_vpi to tell firmware to resume normal operations */
+void
+lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *regvpimbox;
+
+ regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (regvpimbox) {
+ lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox);
+ regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi;
+ regvpimbox->vport = vport;
+ if (lpfc_sli_issue_mbox(phba, regvpimbox,
+ (MBX_NOWAIT | MBX_STOP_IOCB))
+ == MBX_NOT_FINISHED) {
+ mempool_free(regvpimbox, phba->mbox_mem_pool);
+ }
+ }
+}
+
+/* Start Link up / RSCN discovery on NPR nodes */
+void
+lpfc_disc_start(struct lpfc_vport *vport)
+{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
uint32_t num_sent;
uint32_t clear_la_pending;
int did_changed;
- int rc;
- psli = &phba->sli;
-
- if (phba->hba_state <= LPFC_LINK_DOWN) {
+ if (!lpfc_is_link_up(phba))
return;
- }
- if (phba->hba_state == LPFC_CLEAR_LA)
+
+ if (phba->link_state == LPFC_CLEAR_LA)
clear_la_pending = 1;
else
clear_la_pending = 0;
- if (phba->hba_state < LPFC_HBA_READY) {
- phba->hba_state = LPFC_DISC_AUTH;
- }
- lpfc_set_disctmo(phba);
+ if (vport->port_state < LPFC_VPORT_READY)
+ vport->port_state = LPFC_DISC_AUTH;
- if (phba->fc_prevDID == phba->fc_myDID) {
+ lpfc_set_disctmo(vport);
+
+ if (vport->fc_prevDID == vport->fc_myDID)
did_changed = 0;
- } else {
+ else
did_changed = 1;
- }
- phba->fc_prevDID = phba->fc_myDID;
- phba->num_disc_nodes = 0;
+
+ vport->fc_prevDID = vport->fc_myDID;
+ vport->num_disc_nodes = 0;
/* Start Discovery state <hba_state> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0202 Start Discovery hba state x%x "
+ "%d (%d):0202 Start Discovery hba state x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, phba->hba_state, phba->fc_flag,
- phba->fc_plogi_cnt, phba->fc_adisc_cnt);
-
- /* If our did changed, we MUST do PLOGI */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) {
- if (ndlp->nlp_state == NLP_STE_NPR_NODE &&
- (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 &&
- did_changed) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
- }
- }
+ phba->brd_no, vport->vpi, vport->port_state,
+ vport->fc_flag, vport->fc_plogi_cnt,
+ vport->fc_adisc_cnt);
/* First do ADISCs - if any */
- num_sent = lpfc_els_disc_adisc(phba);
+ num_sent = lpfc_els_disc_adisc(vport);
if (num_sent)
return;
- if ((phba->hba_state < LPFC_HBA_READY) && (!clear_la_pending)) {
+ /*
+ * For SLI3, cmpl_reg_vpi will set port_state to READY, and
+ * continue discovery.
+ */
+ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
+ !(vport->fc_flag & FC_RSCN_MODE)) {
+ lpfc_issue_reg_vpi(phba, vport);
+ return;
+ }
+
+ /*
+ * For SLI2, we need to set port_state to READY and continue
+ * discovery.
+ */
+ if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) {
/* If we get here, there is nothing to ADISC */
- if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, mbox);
- mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, mbox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free( mbox, phba->mbox_mem_pool);
- lpfc_disc_flush_list(phba);
- psli->ring[(psli->extra_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->fcp_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- psli->ring[(psli->next_ring)].flag &=
- ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
+ if (vport->port_type == LPFC_PHYSICAL_PORT)
+ lpfc_issue_clear_la(phba, vport);
+
+ if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) {
+ vport->num_disc_nodes = 0;
+ /* go thru NPR nodes and issue ELS PLOGIs */
+ if (vport->fc_npr_cnt)
+ lpfc_els_disc_plogi(vport);
+
+ if (!vport->num_disc_nodes) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_NDISC_ACTIVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
}
}
+ vport->port_state = LPFC_VPORT_READY;
} else {
/* Next do PLOGIs - if any */
- num_sent = lpfc_els_disc_plogi(phba);
+ num_sent = lpfc_els_disc_plogi(vport);
if (num_sent)
return;
- if (phba->fc_flag & FC_RSCN_MODE) {
+ if (vport->fc_flag & FC_RSCN_MODE) {
/* Check to see if more RSCNs came in while we
* were processing this one.
*/
- if ((phba->fc_rscn_id_cnt == 0) &&
- (!(phba->fc_flag & FC_RSCN_DISCOVERY))) {
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_RSCN_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ if ((vport->fc_rscn_id_cnt == 0) &&
+ (!(vport->fc_flag & FC_RSCN_DISCOVERY))) {
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_RSCN_MODE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_can_disctmo(vport);
} else
- lpfc_els_handle_rscn(phba);
+ lpfc_els_handle_rscn(vport);
}
}
return;
@@ -1893,7 +2384,7 @@ lpfc_disc_start(struct lpfc_hba * phba)
* ring the match the sppecified nodelist.
*/
static void
-lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
struct lpfc_sli *psli;
@@ -1907,7 +2398,7 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
/* Error matching iocb on txq or txcmplq
* First check the txq.
*/
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
if (iocb->context1 != ndlp) {
continue;
@@ -1927,36 +2418,36 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
continue;
}
icmd = &iocb->iocb;
- if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) ||
- (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) {
+ if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR ||
+ icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX) {
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
icmd = &iocb->iocb;
icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
-
- return;
}
void
-lpfc_disc_flush_list(struct lpfc_hba * phba)
+lpfc_disc_flush_list(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
+ struct lpfc_hba *phba = vport->phba;
- if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) {
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) {
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE ||
ndlp->nlp_state == NLP_STE_ADISC_ISSUE) {
@@ -1967,6 +2458,14 @@ lpfc_disc_flush_list(struct lpfc_hba * phba)
}
}
+void
+lpfc_cleanup_discovery_resources(struct lpfc_vport *vport)
+{
+ lpfc_els_flush_rscn(vport);
+ lpfc_els_flush_cmd(vport);
+ lpfc_disc_flush_list(vport);
+}
+
/*****************************************************************************/
/*
* NAME: lpfc_disc_timeout
@@ -1985,158 +2484,154 @@ lpfc_disc_flush_list(struct lpfc_hba * phba)
void
lpfc_disc_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+ struct lpfc_vport *vport = (struct lpfc_vport *) ptr;
+ struct lpfc_hba *phba = vport->phba;
unsigned long flags = 0;
if (unlikely(!phba))
return;
- spin_lock_irqsave(phba->host->host_lock, flags);
- if (!(phba->work_hba_events & WORKER_DISC_TMO)) {
- phba->work_hba_events |= WORKER_DISC_TMO;
+ if ((vport->work_port_events & WORKER_DISC_TMO) == 0) {
+ spin_lock_irqsave(&vport->work_port_lock, flags);
+ vport->work_port_events |= WORKER_DISC_TMO;
+ spin_unlock_irqrestore(&vport->work_port_lock, flags);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
}
- spin_unlock_irqrestore(phba->host->host_lock, flags);
return;
}
static void
-lpfc_disc_timeout_handler(struct lpfc_hba *phba)
+lpfc_disc_timeout_handler(struct lpfc_vport *vport)
{
- struct lpfc_sli *psli;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_nodelist *ndlp, *next_ndlp;
- LPFC_MBOXQ_t *clearlambox, *initlinkmbox;
+ LPFC_MBOXQ_t *initlinkmbox;
int rc, clrlaerr = 0;
- if (unlikely(!phba))
+ if (!(vport->fc_flag & FC_DISC_TMO))
return;
- if (!(phba->fc_flag & FC_DISC_TMO))
- return;
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_DISC_TMO;
+ spin_unlock_irq(shost->host_lock);
- psli = &phba->sli;
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
+ "disc timeout: state:x%x rtry:x%x flg:x%x",
+ vport->port_state, vport->fc_ns_retry, vport->fc_flag);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_DISC_TMO;
- spin_unlock_irq(phba->host->host_lock);
-
- switch (phba->hba_state) {
+ switch (vport->port_state) {
case LPFC_LOCAL_CFG_LINK:
- /* hba_state is identically LPFC_LOCAL_CFG_LINK while waiting for FAN */
- /* FAN timeout */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_DISCOVERY,
- "%d:0221 FAN timeout\n",
- phba->brd_no);
+ /* port_state is identically LPFC_LOCAL_CFG_LINK while waiting for
+ * FAN
+ */
+ /* FAN timeout */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
+ "%d (%d):0221 FAN timeout\n",
+ phba->brd_no, vport->vpi);
/* Start discovery by sending FLOGI, clean up old rpis */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes,
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
nlp_listp) {
if (ndlp->nlp_state != NLP_STE_NPR_NODE)
continue;
if (ndlp->nlp_type & NLP_FABRIC) {
/* Clean up the ndlp on Fabric connections */
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
} else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) {
/* Fail outstanding IO now since device
* is marked for PLOGI.
*/
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
}
}
- phba->hba_state = LPFC_FLOGI;
- lpfc_set_disctmo(phba);
- lpfc_initial_flogi(phba);
+ if (vport->port_state != LPFC_FLOGI) {
+ vport->port_state = LPFC_FLOGI;
+ lpfc_set_disctmo(vport);
+ lpfc_initial_flogi(vport);
+ }
break;
+ case LPFC_FDISC:
case LPFC_FLOGI:
- /* hba_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
+ /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
/* Initial FLOGI timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0222 Initial FLOGI timeout\n",
- phba->brd_no);
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0222 Initial %s timeout\n",
+ phba->brd_no, vport->vpi,
+ vport->vpi ? "FLOGI" : "FDISC");
/* Assume no Fabric and go on with discovery.
* Check for outstanding ELS FLOGI to abort.
*/
/* FLOGI failed, so just use loop map to make discovery list */
- lpfc_disc_list_loopmap(phba);
+ lpfc_disc_list_loopmap(vport);
/* Start discovery */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
break;
case LPFC_FABRIC_CFG_LINK:
/* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for
NameServer login */
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0223 Timeout while waiting for NameServer "
- "login\n", phba->brd_no);
+ "%d (%d):0223 Timeout while waiting for "
+ "NameServer login\n",
+ phba->brd_no, vport->vpi);
/* Next look for NameServer ndlp */
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
+ ndlp = lpfc_findnode_did(vport, NameServer_DID);
if (ndlp)
lpfc_nlp_put(ndlp);
/* Start discovery */
- lpfc_disc_start(phba);
+ lpfc_disc_start(vport);
break;
case LPFC_NS_QRY:
/* Check for wait for NameServer Rsp timeout */
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0224 NameServer Query timeout "
+ "%d (%d):0224 NameServer Query timeout "
"Data: x%x x%x\n",
- phba->brd_no,
- phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
-
- ndlp = lpfc_findnode_did(phba, NameServer_DID);
- if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
- if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) {
- /* Try it one more time */
- rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT);
- if (rc == 0)
- break;
- }
- phba->fc_ns_retry = 0;
+ phba->brd_no, vport->vpi,
+ vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+
+ if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
+ /* Try it one more time */
+ vport->fc_ns_retry++;
+ rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT,
+ vport->fc_ns_retry, 0);
+ if (rc == 0)
+ break;
}
+ vport->fc_ns_retry = 0;
- /* Nothing to authenticate, so CLEAR_LA right now */
- clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!clearlambox) {
- clrlaerr = 1;
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0226 Device Discovery "
- "completion error\n",
- phba->brd_no);
- phba->hba_state = LPFC_HBA_ERROR;
- break;
- }
-
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, clearlambox);
- clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, clearlambox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(clearlambox, phba->mbox_mem_pool);
- clrlaerr = 1;
- break;
+ /*
+ * Discovery is over.
+ * set port_state to PORT_READY if SLI2.
+ * cmpl_reg_vpi will set port_state to READY for SLI3.
+ */
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ lpfc_issue_reg_vpi(phba, vport);
+ else { /* NPIV Not enabled */
+ lpfc_issue_clear_la(phba, vport);
+ vport->port_state = LPFC_VPORT_READY;
}
/* Setup and issue mailbox INITIALIZE LINK command */
initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!initlinkmbox) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0206 Device Discovery "
+ "%d (%d):0206 Device Discovery "
"completion error\n",
- phba->brd_no);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->brd_no, vport->vpi);
+ phba->link_state = LPFC_HBA_ERROR;
break;
}
@@ -2144,6 +2639,8 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
lpfc_init_link(phba, initlinkmbox, phba->cfg_topology,
phba->cfg_link_speed);
initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0;
+ initlinkmbox->vport = vport;
+ initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
rc = lpfc_sli_issue_mbox(phba, initlinkmbox,
(MBX_NOWAIT | MBX_STOP_IOCB));
lpfc_set_loopback_flag(phba);
@@ -2154,67 +2651,81 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
case LPFC_DISC_AUTH:
/* Node Authentication timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0227 Node Authentication timeout\n",
- phba->brd_no);
- lpfc_disc_flush_list(phba);
- clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!clearlambox) {
- clrlaerr = 1;
- lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0207 Device Discovery "
- "completion error\n",
- phba->brd_no);
- phba->hba_state = LPFC_HBA_ERROR;
- break;
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0227 Node Authentication timeout\n",
+ phba->brd_no, vport->vpi);
+ lpfc_disc_flush_list(vport);
+
+ /*
+ * set port_state to PORT_READY if SLI2.
+ * cmpl_reg_vpi will set port_state to READY for SLI3.
+ */
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ lpfc_issue_reg_vpi(phba, vport);
+ else { /* NPIV Not enabled */
+ lpfc_issue_clear_la(phba, vport);
+ vport->port_state = LPFC_VPORT_READY;
}
- phba->hba_state = LPFC_CLEAR_LA;
- lpfc_clear_la(phba, clearlambox);
- clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la;
- rc = lpfc_sli_issue_mbox(phba, clearlambox,
- (MBX_NOWAIT | MBX_STOP_IOCB));
- if (rc == MBX_NOT_FINISHED) {
- mempool_free(clearlambox, phba->mbox_mem_pool);
- clrlaerr = 1;
+ break;
+
+ case LPFC_VPORT_READY:
+ if (vport->fc_flag & FC_RSCN_MODE) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0231 RSCN timeout Data: x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
+ vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+
+ /* Cleanup any outstanding ELS commands */
+ lpfc_els_flush_cmd(vport);
+
+ lpfc_els_flush_rscn(vport);
+ lpfc_disc_flush_list(vport);
}
break;
+ default:
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0229 Unexpected discovery timeout, "
+ "vport State x%x\n",
+ phba->brd_no, vport->vpi, vport->port_state);
+
+ break;
+ }
+
+ switch (phba->link_state) {
case LPFC_CLEAR_LA:
- /* CLEAR LA timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0228 CLEAR LA timeout\n",
- phba->brd_no);
+ /* CLEAR LA timeout */
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0228 CLEAR LA timeout\n",
+ phba->brd_no, vport->vpi);
clrlaerr = 1;
break;
- case LPFC_HBA_READY:
- if (phba->fc_flag & FC_RSCN_MODE) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0231 RSCN timeout Data: x%x x%x\n",
- phba->brd_no,
- phba->fc_ns_retry, LPFC_MAX_NS_RETRY);
-
- /* Cleanup any outstanding ELS commands */
- lpfc_els_flush_cmd(phba);
+ case LPFC_LINK_UNKNOWN:
+ case LPFC_WARM_START:
+ case LPFC_INIT_START:
+ case LPFC_INIT_MBX_CMDS:
+ case LPFC_LINK_DOWN:
+ case LPFC_LINK_UP:
+ case LPFC_HBA_ERROR:
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0230 Unexpected timeout, hba link "
+ "state x%x\n",
+ phba->brd_no, vport->vpi, phba->link_state);
+ clrlaerr = 1;
+ break;
- lpfc_els_flush_rscn(phba);
- lpfc_disc_flush_list(phba);
- }
+ case LPFC_HBA_READY:
break;
}
if (clrlaerr) {
- lpfc_disc_flush_list(phba);
+ lpfc_disc_flush_list(vport);
psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT;
- phba->hba_state = LPFC_HBA_READY;
+ vport->port_state = LPFC_VPORT_READY;
}
return;
@@ -2227,37 +2738,29 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
* handed off to the SLI layer.
*/
void
-lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
- struct lpfc_sli *psli;
- MAILBOX_t *mb;
- struct lpfc_dmabuf *mp;
- struct lpfc_nodelist *ndlp;
-
- psli = &phba->sli;
- mb = &pmb->mb;
-
- ndlp = (struct lpfc_nodelist *) pmb->context2;
- mp = (struct lpfc_dmabuf *) (pmb->context1);
+ MAILBOX_t *mb = &pmb->mb;
+ struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2;
+ struct lpfc_vport *vport = pmb->vport;
pmb->context1 = NULL;
ndlp->nlp_rpi = mb->un.varWords[0];
ndlp->nlp_type |= NLP_FABRIC;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
- /* Start issuing Fabric-Device Management Interface (FDMI)
- * command to 0xfffffa (FDMI well known port)
+ /*
+ * Start issuing Fabric-Device Management Interface (FDMI) command to
+ * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if
+ * fdmi-on=2 (supporting RPA/hostnmae)
*/
- if (phba->cfg_fdmi_on == 1) {
- lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
- } else {
- /*
- * Delay issuing FDMI command if fdmi-on=2
- * (supporting RPA/hostnmae)
- */
- mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
- }
+
+ if (phba->cfg_fdmi_on == 1)
+ lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
+ else
+ mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
/* Mailbox took a reference to the node */
lpfc_nlp_put(ndlp);
@@ -2283,16 +2786,12 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param)
sizeof(ndlp->nlp_portname)) == 0;
}
-/*
- * Search node lists for a remote port matching filter criteria
- * Caller needs to hold host_lock before calling this routine.
- */
struct lpfc_nodelist *
-__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+__lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
{
struct lpfc_nodelist *ndlp;
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state != NLP_STE_UNUSED_NODE &&
filter(ndlp, param))
return ndlp;
@@ -2302,68 +2801,104 @@ __lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
/*
* Search node lists for a remote port matching filter criteria
- * This routine is used when the caller does NOT have host_lock.
+ * Caller needs to hold host_lock before calling this routine.
*/
struct lpfc_nodelist *
-lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param)
+lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- ndlp = __lpfc_find_node(phba, filter, param);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_find_node(vport, filter, param);
+ spin_unlock_irq(shost->host_lock);
return ndlp;
}
/*
* This routine looks up the ndlp lists for the given RPI. If rpi found it
- * returns the node list pointer else return NULL.
+ * returns the node list element pointer else return NULL.
*/
struct lpfc_nodelist *
-__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi)
+__lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
{
- return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi);
+ return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi);
}
struct lpfc_nodelist *
-lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi)
+lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- ndlp = __lpfc_findnode_rpi(phba, rpi);
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_findnode_rpi(vport, rpi);
+ spin_unlock_irq(shost->host_lock);
return ndlp;
}
/*
* This routine looks up the ndlp lists for the given WWPN. If WWPN found it
- * returns the node list pointer else return NULL.
+ * returns the node element list pointer else return NULL.
*/
struct lpfc_nodelist *
-lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn)
+lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_nodelist *ndlp;
- spin_lock_irq(phba->host->host_lock);
- ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn);
- spin_unlock_irq(phba->host->host_lock);
- return NULL;
+ spin_lock_irq(shost->host_lock);
+ ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn);
+ spin_unlock_irq(shost->host_lock);
+ return ndlp;
}
void
-lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did)
+lpfc_dev_loss_delay(unsigned long ptr)
+{
+ struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
+ struct lpfc_vport *vport = ndlp->vport;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_work_evt *evtp = &ndlp->dev_loss_evt;
+ unsigned long flags;
+
+ evtp = &ndlp->dev_loss_evt;
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (!list_empty(&evtp->evt_listp)) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
+
+ evtp->evt_arg1 = ndlp;
+ evtp->evt = LPFC_EVT_DEV_LOSS_DELAY;
+ list_add_tail(&evtp->evt_listp, &phba->work_list);
+ if (phba->work_wait)
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+}
+
+void
+lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ uint32_t did)
{
memset(ndlp, 0, sizeof (struct lpfc_nodelist));
INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
+ INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp);
init_timer(&ndlp->nlp_delayfunc);
ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
ndlp->nlp_DID = did;
- ndlp->nlp_phba = phba;
+ ndlp->vport = vport;
ndlp->nlp_sid = NLP_NO_SID;
INIT_LIST_HEAD(&ndlp->nlp_listp);
kref_init(&ndlp->kref);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
+ "node init: did:x%x",
+ ndlp->nlp_DID, 0, 0);
+
return;
}
@@ -2372,8 +2907,13 @@ lpfc_nlp_release(struct kref *kref)
{
struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
kref);
- lpfc_nlp_remove(ndlp->nlp_phba, ndlp);
- mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool);
+
+ lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE,
+ "node release: did:x%x flg:x%x type:x%x",
+ ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type);
+
+ lpfc_nlp_remove(ndlp->vport, ndlp);
+ mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool);
}
struct lpfc_nodelist *
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 2623a9bc7775..c2fb59f595f3 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -59,6 +59,12 @@
#define SLI2_IOCB_CMD_R3XTRA_ENTRIES 24
#define SLI2_IOCB_RSP_R3XTRA_ENTRIES 32
+#define SLI2_IOCB_CMD_SIZE 32
+#define SLI2_IOCB_RSP_SIZE 32
+#define SLI3_IOCB_CMD_SIZE 128
+#define SLI3_IOCB_RSP_SIZE 64
+
+
/* Common Transport structures and definitions */
union CtRevisionId {
@@ -79,6 +85,9 @@ union CtCommandResponse {
uint32_t word;
};
+#define FC4_FEATURE_INIT 0x2
+#define FC4_FEATURE_TARGET 0x1
+
struct lpfc_sli_ct_request {
/* Structure is in Big Endian format */
union CtRevisionId RevisionId;
@@ -121,20 +130,6 @@ struct lpfc_sli_ct_request {
uint32_t rsvd[7];
} rft;
- struct rff {
- uint32_t PortId;
- uint8_t reserved[2];
-#ifdef __BIG_ENDIAN_BITFIELD
- uint8_t feature_res:6;
- uint8_t feature_init:1;
- uint8_t feature_tgt:1;
-#else /* __LITTLE_ENDIAN_BITFIELD */
- uint8_t feature_tgt:1;
- uint8_t feature_init:1;
- uint8_t feature_res:6;
-#endif
- uint8_t type_code; /* type=8 for FCP */
- } rff;
struct rnn {
uint32_t PortId; /* For RNN_ID requests */
uint8_t wwnn[8];
@@ -144,15 +139,42 @@ struct lpfc_sli_ct_request {
uint8_t len;
uint8_t symbname[255];
} rsnn;
+ struct rspn { /* For RSPN_ID requests */
+ uint32_t PortId;
+ uint8_t len;
+ uint8_t symbname[255];
+ } rspn;
+ struct gff {
+ uint32_t PortId;
+ } gff;
+ struct gff_acc {
+ uint8_t fbits[128];
+ } gff_acc;
+#define FCP_TYPE_FEATURE_OFFSET 4
+ struct rff {
+ uint32_t PortId;
+ uint8_t reserved[2];
+ uint8_t fbits;
+ uint8_t type_code; /* type=8 for FCP */
+ } rff;
} un;
};
#define SLI_CT_REVISION 1
-#define GID_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 260)
-#define RFT_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 228)
-#define RFF_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 235)
-#define RNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request) - 252)
-#define RSNN_REQUEST_SZ (sizeof(struct lpfc_sli_ct_request))
+#define GID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct gid))
+#define GFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct gff))
+#define RFT_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rft))
+#define RFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rff))
+#define RNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rnn))
+#define RSNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rsnn))
+#define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \
+ sizeof(struct rspn))
/*
* FsType Definitions
@@ -227,6 +249,7 @@ struct lpfc_sli_ct_request {
#define SLI_CTNS_GFT_ID 0x0117
#define SLI_CTNS_GSPN_ID 0x0118
#define SLI_CTNS_GPT_ID 0x011A
+#define SLI_CTNS_GFF_ID 0x011F
#define SLI_CTNS_GID_PN 0x0121
#define SLI_CTNS_GID_NN 0x0131
#define SLI_CTNS_GIP_NN 0x0135
@@ -240,9 +263,9 @@ struct lpfc_sli_ct_request {
#define SLI_CTNS_RNN_ID 0x0213
#define SLI_CTNS_RCS_ID 0x0214
#define SLI_CTNS_RFT_ID 0x0217
-#define SLI_CTNS_RFF_ID 0x021F
#define SLI_CTNS_RSPN_ID 0x0218
#define SLI_CTNS_RPT_ID 0x021A
+#define SLI_CTNS_RFF_ID 0x021F
#define SLI_CTNS_RIP_NN 0x0235
#define SLI_CTNS_RIPA_NN 0x0236
#define SLI_CTNS_RSNN_NN 0x0239
@@ -311,9 +334,9 @@ struct csp {
uint8_t bbCreditlsb; /* FC Word 0, byte 3 */
#ifdef __BIG_ENDIAN_BITFIELD
- uint16_t increasingOffset:1; /* FC Word 1, bit 31 */
+ uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */
uint16_t randomOffset:1; /* FC Word 1, bit 30 */
- uint16_t word1Reserved2:1; /* FC Word 1, bit 29 */
+ uint16_t response_multiple_NPort:1; /* FC Word 1, bit 29 */
uint16_t fPort:1; /* FC Word 1, bit 28 */
uint16_t altBbCredit:1; /* FC Word 1, bit 27 */
uint16_t edtovResolution:1; /* FC Word 1, bit 26 */
@@ -332,9 +355,9 @@ struct csp {
uint16_t edtovResolution:1; /* FC Word 1, bit 26 */
uint16_t altBbCredit:1; /* FC Word 1, bit 27 */
uint16_t fPort:1; /* FC Word 1, bit 28 */
- uint16_t word1Reserved2:1; /* FC Word 1, bit 29 */
+ uint16_t response_multiple_NPort:1; /* FC Word 1, bit 29 */
uint16_t randomOffset:1; /* FC Word 1, bit 30 */
- uint16_t increasingOffset:1; /* FC Word 1, bit 31 */
+ uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */
uint16_t payloadlength:1; /* FC Word 1, bit 16 */
uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */
@@ -1255,7 +1278,9 @@ typedef struct { /* FireFly BIU registers */
#define MBX_KILL_BOARD 0x24
#define MBX_CONFIG_FARP 0x25
#define MBX_BEACON 0x2A
+#define MBX_HEARTBEAT 0x31
+#define MBX_CONFIG_HBQ 0x7C
#define MBX_LOAD_AREA 0x81
#define MBX_RUN_BIU_DIAG64 0x84
#define MBX_CONFIG_PORT 0x88
@@ -1263,6 +1288,10 @@ typedef struct { /* FireFly BIU registers */
#define MBX_READ_RPI64 0x8F
#define MBX_REG_LOGIN64 0x93
#define MBX_READ_LA64 0x95
+#define MBX_REG_VPI 0x96
+#define MBX_UNREG_VPI 0x97
+#define MBX_REG_VNPID 0x96
+#define MBX_UNREG_VNPID 0x97
#define MBX_FLASH_WR_ULA 0x98
#define MBX_SET_DEBUG 0x99
@@ -1335,6 +1364,10 @@ typedef struct { /* FireFly BIU registers */
#define CMD_FCP_TRECEIVE64_CX 0xA1
#define CMD_FCP_TRSP64_CX 0xA3
+#define CMD_IOCB_RCV_SEQ64_CX 0xB5
+#define CMD_IOCB_RCV_ELS64_CX 0xB7
+#define CMD_IOCB_RCV_CONT64_CX 0xBB
+
#define CMD_GEN_REQUEST64_CR 0xC2
#define CMD_GEN_REQUEST64_CX 0xC3
@@ -1561,6 +1594,7 @@ typedef struct {
#define FLAGS_TOPOLOGY_MODE_PT_PT 0x02 /* Attempt pt-pt only */
#define FLAGS_TOPOLOGY_MODE_LOOP 0x04 /* Attempt loop only */
#define FLAGS_TOPOLOGY_MODE_PT_LOOP 0x06 /* Attempt pt-pt then loop */
+#define FLAGS_UNREG_LOGIN_ALL 0x08 /* UNREG_LOGIN all on link down */
#define FLAGS_LIRP_LILP 0x80 /* LIRP / LILP is disabled */
#define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */
@@ -1744,8 +1778,6 @@ typedef struct {
#define LMT_4Gb 0x040
#define LMT_8Gb 0x080
#define LMT_10Gb 0x100
-
-
uint32_t rsvd2;
uint32_t rsvd3;
uint32_t max_xri;
@@ -1754,7 +1786,10 @@ typedef struct {
uint32_t avail_xri;
uint32_t avail_iocb;
uint32_t avail_rpi;
- uint32_t default_rpi;
+ uint32_t max_vpi;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint32_t avail_vpi;
} READ_CONFIG_VAR;
/* Structure for MB Command READ_RCONFIG (12) */
@@ -1818,6 +1853,13 @@ typedef struct {
structure */
struct ulp_bde64 sp64;
} un;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd3;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN_BITFIELD */
+ uint16_t vpi;
+ uint16_t rsvd3;
+#endif
} READ_SPARM_VAR;
/* Structure for MB Command READ_STATUS (14) */
@@ -1918,11 +1960,17 @@ typedef struct {
#ifdef __BIG_ENDIAN_BITFIELD
uint32_t cv:1;
uint32_t rr:1;
- uint32_t rsvd1:29;
+ uint32_t rsvd2:2;
+ uint32_t v3req:1;
+ uint32_t v3rsp:1;
+ uint32_t rsvd1:25;
uint32_t rv:1;
#else /* __LITTLE_ENDIAN_BITFIELD */
uint32_t rv:1;
- uint32_t rsvd1:29;
+ uint32_t rsvd1:25;
+ uint32_t v3rsp:1;
+ uint32_t v3req:1;
+ uint32_t rsvd2:2;
uint32_t rr:1;
uint32_t cv:1;
#endif
@@ -1972,8 +2020,8 @@ typedef struct {
uint8_t sli1FwName[16];
uint32_t sli2FwRev;
uint8_t sli2FwName[16];
- uint32_t rsvd2;
- uint32_t RandomData[7];
+ uint32_t sli3Feat;
+ uint32_t RandomData[6];
} READ_REV_VAR;
/* Structure for MB Command READ_LINK_STAT (18) */
@@ -2013,6 +2061,14 @@ typedef struct {
struct ulp_bde64 sp64;
} un;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN_BITFIELD */
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
+
} REG_LOGIN_VAR;
/* Word 30 contents for REG_LOGIN */
@@ -2037,16 +2093,78 @@ typedef struct {
#ifdef __BIG_ENDIAN_BITFIELD
uint16_t rsvd1;
uint16_t rpi;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t rsvd6;
+ uint16_t vpi;
#else /* __LITTLE_ENDIAN_BITFIELD */
uint16_t rpi;
uint16_t rsvd1;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t vpi;
+ uint16_t rsvd6;
#endif
} UNREG_LOGIN_VAR;
+/* Structure for MB Command REG_VPI (0x96) */
+typedef struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd1;
+ uint32_t rsvd2:8;
+ uint32_t sid:24;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN */
+ uint32_t rsvd1;
+ uint32_t sid:24;
+ uint32_t rsvd2:8;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
+} REG_VPI_VAR;
+
+/* Structure for MB Command UNREG_VPI (0x97) */
+typedef struct {
+ uint32_t rsvd1;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else /* __LITTLE_ENDIAN */
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
+} UNREG_VPI_VAR;
+
/* Structure for MB Command UNREG_D_ID (0x23) */
typedef struct {
uint32_t did;
+ uint32_t rsvd2;
+ uint32_t rsvd3;
+ uint32_t rsvd4;
+ uint32_t rsvd5;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t rsvd6;
+ uint16_t vpi;
+#else
+ uint16_t vpi;
+ uint16_t rsvd6;
+#endif
} UNREG_D_ID_VAR;
/* Structure for MB Command READ_LA (21) */
@@ -2178,13 +2296,240 @@ typedef struct {
#define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */
#define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */
-/* Structure for MB Command CONFIG_PORT (0x88) */
+struct hbq_mask {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint8_t tmatch;
+ uint8_t tmask;
+ uint8_t rctlmatch;
+ uint8_t rctlmask;
+#else /* __LITTLE_ENDIAN */
+ uint8_t rctlmask;
+ uint8_t rctlmatch;
+ uint8_t tmask;
+ uint8_t tmatch;
+#endif
+};
+
+
+/* Structure for MB Command CONFIG_HBQ (7c) */
+
+struct config_hbq_var {
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd1 :7;
+ uint32_t recvNotify :1; /* Receive Notification */
+ uint32_t numMask :8; /* # Mask Entries */
+ uint32_t profile :8; /* Selection Profile */
+ uint32_t rsvd2 :8;
+#else /* __LITTLE_ENDIAN */
+ uint32_t rsvd2 :8;
+ uint32_t profile :8; /* Selection Profile */
+ uint32_t numMask :8; /* # Mask Entries */
+ uint32_t recvNotify :1; /* Receive Notification */
+ uint32_t rsvd1 :7;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t hbqId :16;
+ uint32_t rsvd3 :12;
+ uint32_t ringMask :4;
+#else /* __LITTLE_ENDIAN */
+ uint32_t ringMask :4;
+ uint32_t rsvd3 :12;
+ uint32_t hbqId :16;
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t entry_count :16;
+ uint32_t rsvd4 :8;
+ uint32_t headerLen :8;
+#else /* __LITTLE_ENDIAN */
+ uint32_t headerLen :8;
+ uint32_t rsvd4 :8;
+ uint32_t entry_count :16;
+#endif
+
+ uint32_t hbqaddrLow;
+ uint32_t hbqaddrHigh;
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd5 :31;
+ uint32_t logEntry :1;
+#else /* __LITTLE_ENDIAN */
+ uint32_t logEntry :1;
+ uint32_t rsvd5 :31;
+#endif
+
+ uint32_t rsvd6; /* w7 */
+ uint32_t rsvd7; /* w8 */
+ uint32_t rsvd8; /* w9 */
+
+ struct hbq_mask hbqMasks[6];
+
+
+ union {
+ uint32_t allprofiles[12];
+
+ struct {
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t seqlenoff :16;
+ uint32_t maxlen :16;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t maxlen :16;
+ uint32_t seqlenoff :16;
+ #endif
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd1 :28;
+ uint32_t seqlenbcnt :4;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t seqlenbcnt :4;
+ uint32_t rsvd1 :28;
+ #endif
+ uint32_t rsvd[10];
+ } profile2;
+
+ struct {
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t seqlenoff :16;
+ uint32_t maxlen :16;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t maxlen :16;
+ uint32_t seqlenoff :16;
+ #endif
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t cmdcodeoff :28;
+ uint32_t rsvd1 :12;
+ uint32_t seqlenbcnt :4;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t seqlenbcnt :4;
+ uint32_t rsvd1 :12;
+ uint32_t cmdcodeoff :28;
+ #endif
+ uint32_t cmdmatch[8];
+
+ uint32_t rsvd[2];
+ } profile3;
+
+ struct {
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t seqlenoff :16;
+ uint32_t maxlen :16;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t maxlen :16;
+ uint32_t seqlenoff :16;
+ #endif
+ #ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t cmdcodeoff :28;
+ uint32_t rsvd1 :12;
+ uint32_t seqlenbcnt :4;
+ #else /* __LITTLE_ENDIAN */
+ uint32_t seqlenbcnt :4;
+ uint32_t rsvd1 :12;
+ uint32_t cmdcodeoff :28;
+ #endif
+ uint32_t cmdmatch[8];
+
+ uint32_t rsvd[2];
+ } profile5;
+
+ } profiles;
+};
+
+
+
+/* Structure for MB Command CONFIG_PORT (0x88) */
typedef struct {
- uint32_t pcbLen;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t cBE : 1;
+ uint32_t cET : 1;
+ uint32_t cHpcb : 1;
+ uint32_t cMA : 1;
+ uint32_t sli_mode : 4;
+ uint32_t pcbLen : 24; /* bit 23:0 of memory based port
+ * config block */
+#else /* __LITTLE_ENDIAN */
+ uint32_t pcbLen : 24; /* bit 23:0 of memory based port
+ * config block */
+ uint32_t sli_mode : 4;
+ uint32_t cMA : 1;
+ uint32_t cHpcb : 1;
+ uint32_t cET : 1;
+ uint32_t cBE : 1;
+#endif
+
uint32_t pcbLow; /* bit 31:0 of memory based port config block */
uint32_t pcbHigh; /* bit 63:32 of memory based port config block */
- uint32_t hbainit[5];
+ uint32_t hbainit[6];
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd : 24; /* Reserved */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+#else /* __LITTLE_ENDIAN */
+ uint32_t cmr : 1; /* Configure Max RPIs */
+ uint32_t cmx : 1; /* Configure Max XRIs */
+ uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */
+ uint32_t cinb : 1; /* Enable Interrupt Notification Block */
+ uint32_t chbs : 1; /* Cofigure Host Backing store */
+ uint32_t csah : 1; /* Configure Synchronous Abort Handling */
+ uint32_t ccrp : 1; /* Config Command Ring Polling */
+ uint32_t cmv : 1; /* Configure Max VPIs */
+ uint32_t rsvd : 24; /* Reserved */
+#endif
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd2 : 24; /* Reserved */
+ uint32_t gmv : 1; /* Grant Max VPIs */
+ uint32_t gcrp : 1; /* Grant Command Ring Polling */
+ uint32_t gsah : 1; /* Grant Synchronous Abort Handling */
+ uint32_t ghbs : 1; /* Grant Host Backing Store */
+ uint32_t ginb : 1; /* Grant Interrupt Notification Block */
+ uint32_t gerbm : 1; /* Grant ERBM Request */
+ uint32_t gmx : 1; /* Grant Max XRIs */
+ uint32_t gmr : 1; /* Grant Max RPIs */
+#else /* __LITTLE_ENDIAN */
+ uint32_t gmr : 1; /* Grant Max RPIs */
+ uint32_t gmx : 1; /* Grant Max XRIs */
+ uint32_t gerbm : 1; /* Grant ERBM Request */
+ uint32_t ginb : 1; /* Grant Interrupt Notification Block */
+ uint32_t ghbs : 1; /* Grant Host Backing Store */
+ uint32_t gsah : 1; /* Grant Synchronous Abort Handling */
+ uint32_t gcrp : 1; /* Grant Command Ring Polling */
+ uint32_t gmv : 1; /* Grant Max VPIs */
+ uint32_t rsvd2 : 24; /* Reserved */
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t max_rpi : 16; /* Max RPIs Port should configure */
+ uint32_t max_xri : 16; /* Max XRIs Port should configure */
+#else /* __LITTLE_ENDIAN */
+ uint32_t max_xri : 16; /* Max XRIs Port should configure */
+ uint32_t max_rpi : 16; /* Max RPIs Port should configure */
+#endif
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */
+ uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */
+#else /* __LITTLE_ENDIAN */
+ uint32_t rsvd3 : 16; /* Max HBQs Host expect to configure */
+ uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */
+#endif
+
+ uint32_t rsvd4; /* Reserved */
+
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint32_t rsvd5 : 16; /* Reserved */
+ uint32_t max_vpi : 16; /* Max number of virt N-Ports */
+#else /* __LITTLE_ENDIAN */
+ uint32_t max_vpi : 16; /* Max number of virt N-Ports */
+ uint32_t rsvd5 : 16; /* Reserved */
+#endif
+
} CONFIG_PORT_VAR;
/* SLI-2 Port Control Block */
@@ -2262,33 +2607,40 @@ typedef struct {
#define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t))
typedef union {
- uint32_t varWords[MAILBOX_CMD_WSIZE - 1];
- LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */
- READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */
- WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */
- BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */
- INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */
+ uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/
+ * feature/max ring number
+ */
+ LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */
+ READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */
+ WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */
+ BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */
+ INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */
DOWN_LINK_VAR varDwnLnk; /* cmd = 6 (DOWN_LINK) */
- CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */
- PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */
+ CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */
+ PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */
CONFIG_RING_VAR varCfgRing; /* cmd = 9 (CONFIG_RING) */
RESET_RING_VAR varRstRing; /* cmd = 10 (RESET_RING) */
READ_CONFIG_VAR varRdConfig; /* cmd = 11 (READ_CONFIG) */
READ_RCONF_VAR varRdRConfig; /* cmd = 12 (READ_RCONFIG) */
READ_SPARM_VAR varRdSparm; /* cmd = 13 (READ_SPARM(64)) */
READ_STATUS_VAR varRdStatus; /* cmd = 14 (READ_STATUS) */
- READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */
- READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */
- READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */
- READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */
+ READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */
+ READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */
+ READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */
+ READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */
REG_LOGIN_VAR varRegLogin; /* cmd = 19 (REG_LOGIN(64)) */
UNREG_LOGIN_VAR varUnregLogin; /* cmd = 20 (UNREG_LOGIN) */
- READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */
+ READ_LA_VAR varReadLA; /* cmd = 21 (READ_LA(64)) */
CLEAR_LA_VAR varClearLA; /* cmd = 22 (CLEAR_LA) */
- DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */
- UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */
- CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP) NEW_FEATURE */
- CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */
+ DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */
+ UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */
+ CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP)
+ * NEW_FEATURE
+ */
+ struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */
+ CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */
+ REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */
+ UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */
} MAILVARIANTS;
/*
@@ -2305,14 +2657,27 @@ struct lpfc_pgp {
__le32 rspPutInx;
};
-typedef struct _SLI2_DESC {
- struct lpfc_hgp host[MAX_RINGS];
+struct sli2_desc {
uint32_t unused1[16];
+ struct lpfc_hgp host[MAX_RINGS];
+ struct lpfc_pgp port[MAX_RINGS];
+};
+
+struct sli3_desc {
+ struct lpfc_hgp host[MAX_RINGS];
+ uint32_t reserved[8];
+ uint32_t hbq_put[16];
+};
+
+struct sli3_pgp {
struct lpfc_pgp port[MAX_RINGS];
-} SLI2_DESC;
+ uint32_t hbq_get[16];
+};
typedef union {
- SLI2_DESC s2;
+ struct sli2_desc s2;
+ struct sli3_desc s3;
+ struct sli3_pgp s3_pgp;
} SLI_VAR;
typedef struct {
@@ -2618,6 +2983,25 @@ typedef struct {
uint32_t fcpt_Length; /* transfer ready for IWRITE */
} FCPT_FIELDS64;
+/* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7)
+ or CMD_IOCB_RCV_SEQ64_CX (0xB5) */
+
+struct rcv_sli3 {
+ uint32_t word8Rsvd;
+#ifdef __BIG_ENDIAN_BITFIELD
+ uint16_t vpi;
+ uint16_t word9Rsvd;
+#else /* __LITTLE_ENDIAN */
+ uint16_t word9Rsvd;
+ uint16_t vpi;
+#endif
+ uint32_t word10Rsvd;
+ uint32_t acc_len; /* accumulated length */
+ struct ulp_bde64 bde2;
+};
+
+
+
typedef struct _IOCB { /* IOCB structure */
union {
GENERIC_RSP grsp; /* Generic response */
@@ -2632,8 +3016,8 @@ typedef struct _IOCB { /* IOCB structure */
/* SLI-2 structures */
- struct ulp_bde64 cont64[2]; /* up to 2 64 bit continuation
- bde_64s */
+ struct ulp_bde64 cont64[2]; /* up to 2 64 bit continuation
+ * bde_64s */
ELS_REQUEST64 elsreq64; /* ELS_REQUEST template */
GEN_REQUEST64 genreq64; /* GEN_REQUEST template */
RCV_ELS_REQ64 rcvels64; /* RCV_ELS_REQ template */
@@ -2695,9 +3079,20 @@ typedef struct _IOCB { /* IOCB structure */
uint32_t ulpTimeout:8;
#endif
+ union {
+ struct rcv_sli3 rcvsli3; /* words 8 - 15 */
+ uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */
+ } unsli3;
+
+#define ulpCt_h ulpXS
+#define ulpCt_l ulpFCP2Rcvy
+
+#define IOCB_FCP 1 /* IOCB is used for FCP ELS cmds-ulpRsvByte */
+#define IOCB_IP 2 /* IOCB is used for IP ELS cmds */
#define PARM_UNUSED 0 /* PU field (Word 4) not used */
#define PARM_REL_OFF 1 /* PU field (Word 4) = R. O. */
#define PARM_READ_CHECK 2 /* PU field (Word 4) = Data Transfer Length */
+#define PARM_NPIV_DID 3
#define CLASS1 0 /* Class 1 */
#define CLASS2 1 /* Class 2 */
#define CLASS3 2 /* Class 3 */
@@ -2718,39 +3113,51 @@ typedef struct _IOCB { /* IOCB structure */
#define IOSTAT_RSVD2 0xC
#define IOSTAT_RSVD3 0xD
#define IOSTAT_RSVD4 0xE
-#define IOSTAT_RSVD5 0xF
+#define IOSTAT_NEED_BUFFER 0xF
#define IOSTAT_DRIVER_REJECT 0x10 /* ulpStatus - Driver defined */
#define IOSTAT_DEFAULT 0xF /* Same as rsvd5 for now */
#define IOSTAT_CNT 0x11
} IOCB_t;
+/* Structure used for a single HBQ entry */
+struct lpfc_hbq_entry {
+ struct ulp_bde64 bde;
+ uint32_t buffer_tag;
+};
+
#define SLI1_SLIM_SIZE (4 * 1024)
/* Up to 498 IOCBs will fit into 16k
* 256 (MAILBOX_t) + 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384
*/
-#define SLI2_SLIM_SIZE (16 * 1024)
+#define SLI2_SLIM_SIZE (64 * 1024)
/* Maximum IOCBs that will fit in SLI2 slim */
#define MAX_SLI2_IOCB 498
+#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \
+ (sizeof(MAILBOX_t) + sizeof(PCB_t)))
+
+/* HBQ entries are 4 words each = 4k */
+#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \
+ lpfc_sli_hbq_count())
struct lpfc_sli2_slim {
MAILBOX_t mbx;
PCB_t pcb;
- IOCB_t IOCBs[MAX_SLI2_IOCB];
+ IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE];
};
-/*******************************************************************
-This macro check PCI device to allow special handling for LC HBAs.
-
-Parameters:
-device : struct pci_dev 's device field
-
-return 1 => TRUE
- 0 => FALSE
- *******************************************************************/
+/*
+ * This function checks PCI device to allow special handling for LC HBAs.
+ *
+ * Parameters:
+ * device : struct pci_dev 's device field
+ *
+ * return 1 => TRUE
+ * 0 => FALSE
+ */
static inline int
lpfc_is_LC_HBA(unsigned short device)
{
@@ -2766,3 +3173,16 @@ lpfc_is_LC_HBA(unsigned short device)
else
return 0;
}
+
+/*
+ * Determine if an IOCB failed because of a link event or firmware reset.
+ */
+
+static inline int
+lpfc_error_lost_link(IOCB_t *iocbp)
+{
+ return (iocbp->ulpStatus == IOSTAT_LOCAL_REJECT &&
+ (iocbp->un.ulpWord[4] == IOERR_SLI_ABORTED ||
+ iocbp->un.ulpWord[4] == IOERR_LINK_DOWN ||
+ iocbp->un.ulpWord[4] == IOERR_SLI_DOWN));
+}
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index dcb4ba0ecee1..07bd0dcdf0d6 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -27,6 +27,7 @@
#include <linux/kthread.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
+#include <linux/ctype.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -40,15 +41,20 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
#include "lpfc_version.h"
+#include "lpfc_vport.h"
static int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int);
static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
static int lpfc_post_rcv_buf(struct lpfc_hba *);
static struct scsi_transport_template *lpfc_transport_template = NULL;
+static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
static DEFINE_IDR(lpfc_hba_index);
+
+
/************************************************************************/
/* */
/* lpfc_config_port_prep */
@@ -61,7 +67,7 @@ static DEFINE_IDR(lpfc_hba_index);
/* */
/************************************************************************/
int
-lpfc_config_port_prep(struct lpfc_hba * phba)
+lpfc_config_port_prep(struct lpfc_hba *phba)
{
lpfc_vpd_t *vp = &phba->vpd;
int i = 0, rc;
@@ -75,12 +81,12 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -ENOMEM;
}
mb = &pmb->mb;
- phba->hba_state = LPFC_INIT_MBX_CMDS;
+ phba->link_state = LPFC_INIT_MBX_CMDS;
if (lpfc_is_LC_HBA(phba->pcidev->device)) {
if (init_key) {
@@ -100,9 +106,7 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_MBOX,
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
"%d:0324 Config Port initialization "
"error, mbxCmd x%x READ_NVPARM, "
"mbxStatus x%x\n",
@@ -112,16 +116,18 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
return -ERESTART;
}
memcpy(phba->wwnn, (char *)mb->un.varRDnvp.nodename,
- sizeof (mb->un.varRDnvp.nodename));
+ sizeof(phba->wwnn));
+ memcpy(phba->wwpn, (char *)mb->un.varRDnvp.portname,
+ sizeof(phba->wwpn));
}
+ phba->sli3_options = 0x0;
+
/* Setup and issue mailbox READ REV command */
lpfc_read_rev(phba, pmb);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0439 Adapter failed to init, mbxCmd x%x "
"READ_REV, mbxStatus x%x\n",
phba->brd_no,
@@ -130,6 +136,7 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
return -ERESTART;
}
+
/*
* The value of rr must be 1 since the driver set the cv field to 1.
* This setting requires the FW to set all revision fields.
@@ -144,8 +151,12 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
return -ERESTART;
}
+ if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp)
+ return -EINVAL;
+
/* Save information as VPD data */
vp->rev.rBit = 1;
+ memcpy(&vp->sli3Feat, &mb->un.varRdRev.sli3Feat, sizeof(uint32_t));
vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
memcpy(vp->rev.sli1FwName, (char*) mb->un.varRdRev.sli1FwName, 16);
vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;
@@ -161,6 +172,13 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
vp->rev.postKernRev = mb->un.varRdRev.postKernRev;
vp->rev.opFwRev = mb->un.varRdRev.opFwRev;
+ /* If the sli feature level is less then 9, we must
+ * tear down all RPIs and VPIs on link down if NPIV
+ * is enabled.
+ */
+ if (vp->rev.feaLevelHigh < 9)
+ phba->sli3_options |= LPFC_SLI3_VPORT_TEARDOWN;
+
if (lpfc_is_LC_HBA(phba->pcidev->device))
memcpy(phba->RandomData, (char *)&mb->un.varWords[24],
sizeof (phba->RandomData));
@@ -188,7 +206,7 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
lpfc_sli_pcimem_bcopy(pmb->context2, lpfc_vpd_data + offset,
- mb->un.varDmp.word_cnt);
+ mb->un.varDmp.word_cnt);
offset += mb->un.varDmp.word_cnt;
} while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE);
lpfc_parse_vpd(phba, lpfc_vpd_data, offset);
@@ -212,48 +230,34 @@ out_free_mbox:
/* */
/************************************************************************/
int
-lpfc_config_port_post(struct lpfc_hba * phba)
+lpfc_config_port_post(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb;
struct lpfc_dmabuf *mp;
struct lpfc_sli *psli = &phba->sli;
uint32_t status, timeout;
- int i, j, rc;
+ int i, j;
+ int rc;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -ENOMEM;
}
mb = &pmb->mb;
- lpfc_config_link(phba, pmb);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
- "%d:0447 Adapter failed init, mbxCmd x%x "
- "CONFIG_LINK mbxStatus x%x\n",
- phba->brd_no,
- mb->mbxCommand, mb->mbxStatus);
- phba->hba_state = LPFC_HBA_ERROR;
- mempool_free( pmb, phba->mbox_mem_pool);
- return -EIO;
- }
-
/* Get login parameters for NID. */
- lpfc_read_sparam(phba, pmb);
+ lpfc_read_sparam(phba, pmb, 0);
+ pmb->vport = vport;
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0448 Adapter failed init, mbxCmd x%x "
"READ_SPARM mbxStatus x%x\n",
phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
mp = (struct lpfc_dmabuf *) pmb->context1;
mempool_free( pmb, phba->mbox_mem_pool);
lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -263,25 +267,27 @@ lpfc_config_port_post(struct lpfc_hba * phba)
mp = (struct lpfc_dmabuf *) pmb->context1;
- memcpy(&phba->fc_sparam, mp->virt, sizeof (struct serv_parm));
+ memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
pmb->context1 = NULL;
if (phba->cfg_soft_wwnn)
- u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn);
+ u64_to_wwn(phba->cfg_soft_wwnn,
+ vport->fc_sparam.nodeName.u.wwn);
if (phba->cfg_soft_wwpn)
- u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
- memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,
+ u64_to_wwn(phba->cfg_soft_wwpn,
+ vport->fc_sparam.portName.u.wwn);
+ memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
sizeof (struct lpfc_name));
- memcpy(&phba->fc_portname, &phba->fc_sparam.portName,
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
sizeof (struct lpfc_name));
/* If no serial number in VPD data, use low 6 bytes of WWNN */
/* This should be consolidated into parse_vpd ? - mr */
if (phba->SerialNumber[0] == 0) {
uint8_t *outptr;
- outptr = &phba->fc_nodename.u.s.IEEE[0];
+ outptr = &vport->fc_nodename.u.s.IEEE[0];
for (i = 0; i < 12; i++) {
status = *outptr++;
j = ((status & 0xf0) >> 4);
@@ -303,15 +309,14 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
lpfc_read_config(phba, pmb);
+ pmb->vport = vport;
if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0453 Adapter failed to init, mbxCmd x%x "
"READ_CONFIG, mbxStatus x%x\n",
phba->brd_no,
mb->mbxCommand, mb->mbxStatus);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
mempool_free( pmb, phba->mbox_mem_pool);
return -EIO;
}
@@ -338,9 +343,7 @@ lpfc_config_port_post(struct lpfc_hba * phba)
|| ((phba->cfg_link_speed == LINK_SPEED_10G)
&& !(phba->lmt & LMT_10Gb))) {
/* Reset link speed to auto */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_LINK_EVENT,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
"%d:1302 Invalid speed for this board: "
"Reset link speed to auto: x%x\n",
phba->brd_no,
@@ -348,7 +351,7 @@ lpfc_config_port_post(struct lpfc_hba * phba)
phba->cfg_link_speed = LINK_SPEED_AUTO;
}
- phba->hba_state = LPFC_LINK_DOWN;
+ phba->link_state = LPFC_LINK_DOWN;
/* Only process IOCBs on ring 0 till hba_state is READY */
if (psli->ring[psli->extra_ring].cmdringaddr)
@@ -359,10 +362,11 @@ lpfc_config_port_post(struct lpfc_hba * phba)
psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT;
/* Post receive buffers for desired rings */
- lpfc_post_rcv_buf(phba);
+ if (phba->sli_rev != 3)
+ lpfc_post_rcv_buf(phba);
/* Enable appropriate host interrupts */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
status = readl(phba->HCregaddr);
status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA;
if (psli->num_rings > 0)
@@ -380,22 +384,24 @@ lpfc_config_port_post(struct lpfc_hba * phba)
writel(status, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
/*
* Setup the ring 0 (els) timeout handler
*/
timeout = phba->fc_ratov << 1;
- mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+ mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout);
+ mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ phba->hb_outstanding = 0;
+ phba->last_completion_time = jiffies;
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ pmb->vport = vport;
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
lpfc_set_loopback_flag(phba);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0454 Adapter failed to init, mbxCmd x%x "
"INIT_LINK, mbxStatus x%x\n",
phba->brd_no,
@@ -408,7 +414,7 @@ lpfc_config_port_post(struct lpfc_hba * phba)
writel(0xffffffff, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
if (rc != MBX_BUSY)
mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
@@ -429,18 +435,19 @@ lpfc_config_port_post(struct lpfc_hba * phba)
/* */
/************************************************************************/
int
-lpfc_hba_down_prep(struct lpfc_hba * phba)
+lpfc_hba_down_prep(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport = phba->pport;
+
/* Disable interrupts */
writel(0, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- /* Cleanup potential discovery resources */
- lpfc_els_flush_rscn(phba);
- lpfc_els_flush_cmd(phba);
- lpfc_disc_flush_list(phba);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ lpfc_cleanup_discovery_resources(vport);
+ }
- return (0);
+ return 0;
}
/************************************************************************/
@@ -453,20 +460,24 @@ lpfc_hba_down_prep(struct lpfc_hba * phba)
/* */
/************************************************************************/
int
-lpfc_hba_down_post(struct lpfc_hba * phba)
+lpfc_hba_down_post(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
struct lpfc_dmabuf *mp, *next_mp;
int i;
- /* Cleanup preposted buffers on the ELS ring */
- pring = &psli->ring[LPFC_ELS_RING];
- list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
- list_del(&mp->list);
- pring->postbufq_cnt--;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
+ lpfc_sli_hbqbuf_free_all(phba);
+ else {
+ /* Cleanup preposted buffers on the ELS ring */
+ pring = &psli->ring[LPFC_ELS_RING];
+ list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
+ list_del(&mp->list);
+ pring->postbufq_cnt--;
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
}
for (i = 0; i < psli->num_rings; i++) {
@@ -477,6 +488,119 @@ lpfc_hba_down_post(struct lpfc_hba * phba)
return 0;
}
+/* HBA heart beat timeout handler */
+void
+lpfc_hb_timeout(unsigned long ptr)
+{
+ struct lpfc_hba *phba;
+ unsigned long iflag;
+
+ phba = (struct lpfc_hba *)ptr;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
+ if (!(phba->pport->work_port_events & WORKER_HB_TMO))
+ phba->pport->work_port_events |= WORKER_HB_TMO;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
+
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
+ return;
+}
+
+static void
+lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+{
+ unsigned long drvr_flag;
+
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
+ phba->hb_outstanding = 0;
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) &&
+ !(phba->link_state == LPFC_HBA_ERROR) &&
+ !(phba->pport->fc_flag & FC_UNLOADING))
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ return;
+}
+
+void
+lpfc_hb_timeout_handler(struct lpfc_hba *phba)
+{
+ LPFC_MBOXQ_t *pmboxq;
+ int retval;
+ struct lpfc_sli *psli = &phba->sli;
+
+ if ((phba->link_state == LPFC_HBA_ERROR) ||
+ (phba->pport->fc_flag & FC_UNLOADING) ||
+ (phba->pport->fc_flag & FC_OFFLINE_MODE))
+ return;
+
+ spin_lock_irq(&phba->pport->work_port_lock);
+ /* If the timer is already canceled do nothing */
+ if (!(phba->pport->work_port_events & WORKER_HB_TMO)) {
+ spin_unlock_irq(&phba->pport->work_port_lock);
+ return;
+ }
+
+ if (time_after(phba->last_completion_time + LPFC_HB_MBOX_INTERVAL * HZ,
+ jiffies)) {
+ spin_unlock_irq(&phba->pport->work_port_lock);
+ if (!phba->hb_outstanding)
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ else
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+ return;
+ }
+ spin_unlock_irq(&phba->pport->work_port_lock);
+
+ /* If there is no heart beat outstanding, issue a heartbeat command */
+ if (!phba->hb_outstanding) {
+ pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);
+ if (!pmboxq) {
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ return;
+ }
+
+ lpfc_heart_beat(phba, pmboxq);
+ pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
+ pmboxq->vport = phba->pport;
+ retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT);
+
+ if (retval != MBX_BUSY && retval != MBX_SUCCESS) {
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
+ return;
+ }
+ mod_timer(&phba->hb_tmofunc,
+ jiffies + HZ * LPFC_HB_MBOX_TIMEOUT);
+ phba->hb_outstanding = 1;
+ return;
+ } else {
+ /*
+ * If heart beat timeout called with hb_outstanding set we
+ * need to take the HBA offline.
+ */
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0459 Adapter heartbeat failure, taking "
+ "this port offline.\n", phba->brd_no);
+
+ spin_lock_irq(&phba->hbalock);
+ psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+
+ lpfc_offline_prep(phba);
+ lpfc_offline(phba);
+ lpfc_unblock_mgmt_io(phba);
+ phba->link_state = LPFC_HBA_ERROR;
+ lpfc_hba_down_post(phba);
+ }
+}
+
/************************************************************************/
/* */
/* lpfc_handle_eratt */
@@ -486,11 +610,15 @@ lpfc_hba_down_post(struct lpfc_hba * phba)
/* */
/************************************************************************/
void
-lpfc_handle_eratt(struct lpfc_hba * phba)
+lpfc_handle_eratt(struct lpfc_hba *phba)
{
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *vport = phba->pport;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
+ struct lpfc_vport *port_iterator;
uint32_t event_data;
+ struct Scsi_Host *shost;
+
/* If the pci channel is offline, ignore possible errors,
* since we cannot communicate with the pci card anyway. */
if (pci_channel_offline(phba->pcidev))
@@ -504,10 +632,17 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
"Data: x%x x%x x%x\n",
phba->brd_no, phba->work_hs,
phba->work_status[0], phba->work_status[1]);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_ESTABLISH_LINK;
+ list_for_each_entry(port_iterator, &phba->port_list,
+ listentry) {
+ shost = lpfc_shost_from_vport(port_iterator);
+
+ spin_lock_irq(shost->host_lock);
+ port_iterator->fc_flag |= FC_ESTABLISH_LINK;
+ spin_unlock_irq(shost->host_lock);
+ }
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
/*
* Firmware stops when it triggled erratt with HS_FFER6.
@@ -544,15 +679,18 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
phba->work_status[0], phba->work_status[1]);
event_data = FC_REG_DUMP_EVENT;
- fc_host_post_vendor_event(phba->host, fc_get_event_number(),
+ shost = lpfc_shost_from_vport(vport);
+ fc_host_post_vendor_event(shost, fc_get_event_number(),
sizeof(event_data), (char *) &event_data,
SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
lpfc_offline_prep(phba);
lpfc_offline(phba);
lpfc_unblock_mgmt_io(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
lpfc_hba_down_post(phba);
}
}
@@ -566,9 +704,11 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
/* */
/************************************************************************/
void
-lpfc_handle_latt(struct lpfc_hba * phba)
+lpfc_handle_latt(struct lpfc_hba *phba)
{
- struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *vport = phba->pport;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_vport *port_iterator;
LPFC_MBOXQ_t *pmb;
volatile uint32_t control;
struct lpfc_dmabuf *mp;
@@ -589,20 +729,22 @@ lpfc_handle_latt(struct lpfc_hba * phba)
rc = -EIO;
/* Cleanup any outstanding ELS commands */
- lpfc_els_flush_cmd(phba);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry)
+ lpfc_els_flush_cmd(port_iterator);
psli->slistat.link_event++;
lpfc_read_la(phba, pmb, mp);
pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la;
+ pmb->vport = vport;
rc = lpfc_sli_issue_mbox (phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED)
goto lpfc_handle_latt_free_mbuf;
/* Clear Link Attention in HA REG */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
writel(HA_LATT, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return;
@@ -614,7 +756,7 @@ lpfc_handle_latt_free_pmb:
mempool_free(pmb, phba->mbox_mem_pool);
lpfc_handle_latt_err_exit:
/* Enable Link attention interrupts */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag |= LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control |= HC_LAINT_ENA;
@@ -624,15 +766,13 @@ lpfc_handle_latt_err_exit:
/* Clear Link Attention in HA REG */
writel(HA_LATT, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_linkdown(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/* The other case is an error from issue_mbox */
if (rc == -ENOMEM)
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_MBOX,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
"%d:0300 READ_LA: no buffers\n",
phba->brd_no);
@@ -646,7 +786,7 @@ lpfc_handle_latt_err_exit:
/* */
/************************************************************************/
static int
-lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len)
+lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len)
{
uint8_t lenlo, lenhi;
int Length;
@@ -658,9 +798,7 @@ lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len)
return 0;
/* Vital Product */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
"%d:0455 Vital Product Data: x%x x%x x%x x%x\n",
phba->brd_no,
(uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2],
@@ -785,7 +923,7 @@ lpfc_parse_vpd(struct lpfc_hba * phba, uint8_t * vpd, int len)
}
static void
-lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
+lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp)
{
lpfc_vpd_t *vp;
uint16_t dev_id = phba->pcidev->device;
@@ -943,7 +1081,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
/* Returns the number of buffers NOT posted. */
/**************************************************/
int
-lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
+lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt,
int type)
{
IOCB_t *icmd;
@@ -955,9 +1093,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
/* While there are buffers to post */
while (cnt > 0) {
/* Allocate buffer for command iocb */
- spin_lock_irq(phba->host->host_lock);
iocb = lpfc_sli_get_iocbq(phba);
- spin_unlock_irq(phba->host->host_lock);
if (iocb == NULL) {
pring->missbufcnt = cnt;
return cnt;
@@ -972,9 +1108,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
&mp1->phys);
if (mp1 == 0 || mp1->virt == 0) {
kfree(mp1);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, iocb);
- spin_unlock_irq(phba->host->host_lock);
pring->missbufcnt = cnt;
return cnt;
}
@@ -990,9 +1124,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
kfree(mp2);
lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
kfree(mp1);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_release_iocbq(phba, iocb);
- spin_unlock_irq(phba->host->host_lock);
pring->missbufcnt = cnt;
return cnt;
}
@@ -1018,7 +1150,6 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
icmd->ulpCommand = CMD_QUE_RING_BUF64_CN;
icmd->ulpLe = 1;
- spin_lock_irq(phba->host->host_lock);
if (lpfc_sli_issue_iocb(phba, pring, iocb, 0) == IOCB_ERROR) {
lpfc_mbuf_free(phba, mp1->virt, mp1->phys);
kfree(mp1);
@@ -1030,14 +1161,11 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
}
lpfc_sli_release_iocbq(phba, iocb);
pring->missbufcnt = cnt;
- spin_unlock_irq(phba->host->host_lock);
return cnt;
}
- spin_unlock_irq(phba->host->host_lock);
lpfc_sli_ringpostbuf_put(phba, pring, mp1);
- if (mp2) {
+ if (mp2)
lpfc_sli_ringpostbuf_put(phba, pring, mp2);
- }
}
pring->missbufcnt = 0;
return 0;
@@ -1050,7 +1178,7 @@ lpfc_post_buffer(struct lpfc_hba * phba, struct lpfc_sli_ring * pring, int cnt,
/* */
/************************************************************************/
static int
-lpfc_post_rcv_buf(struct lpfc_hba * phba)
+lpfc_post_rcv_buf(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
@@ -1151,7 +1279,7 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
{
int t;
uint32_t *HashWorking;
- uint32_t *pwwnn = phba->wwnn;
+ uint32_t *pwwnn = (uint32_t *) phba->wwnn;
HashWorking = kmalloc(80 * sizeof(uint32_t), GFP_KERNEL);
if (!HashWorking)
@@ -1170,64 +1298,76 @@ lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit)
}
static void
-lpfc_cleanup(struct lpfc_hba * phba)
+lpfc_cleanup(struct lpfc_vport *vport)
{
struct lpfc_nodelist *ndlp, *next_ndlp;
/* clean up phba - lpfc specific */
- lpfc_can_disctmo(phba);
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+ lpfc_can_disctmo(vport);
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
lpfc_nlp_put(ndlp);
-
- INIT_LIST_HEAD(&phba->fc_nodes);
-
return;
}
static void
lpfc_establish_link_tmo(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
+ struct lpfc_vport *vport = phba->pport;
unsigned long iflag;
-
/* Re-establishing Link, timer expired */
lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
"%d:1300 Re-establishing Link, timer expired "
"Data: x%x x%x\n",
- phba->brd_no, phba->fc_flag, phba->hba_state);
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag &= ~FC_ESTABLISH_LINK;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ phba->brd_no, vport->fc_flag,
+ vport->port_state);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ spin_lock_irqsave(shost->host_lock, iflag);
+ vport->fc_flag &= ~FC_ESTABLISH_LINK;
+ spin_unlock_irqrestore(shost->host_lock, iflag);
+ }
}
-static int
-lpfc_stop_timer(struct lpfc_hba * phba)
+void
+lpfc_stop_vport_timers(struct lpfc_vport *vport)
{
- struct lpfc_sli *psli = &phba->sli;
+ del_timer_sync(&vport->els_tmofunc);
+ del_timer_sync(&vport->fc_fdmitmo);
+ lpfc_can_disctmo(vport);
+ return;
+}
+
+static void
+lpfc_stop_phba_timers(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
del_timer_sync(&phba->fcp_poll_timer);
del_timer_sync(&phba->fc_estabtmo);
- del_timer_sync(&phba->fc_disctmo);
- del_timer_sync(&phba->fc_fdmitmo);
- del_timer_sync(&phba->els_tmofunc);
- psli = &phba->sli;
- del_timer_sync(&psli->mbox_tmo);
- return(1);
+ list_for_each_entry(vport, &phba->port_list, listentry)
+ lpfc_stop_vport_timers(vport);
+ del_timer_sync(&phba->sli.mbox_tmo);
+ del_timer_sync(&phba->fabric_block_timer);
+ phba->hb_outstanding = 0;
+ del_timer_sync(&phba->hb_tmofunc);
+ return;
}
int
-lpfc_online(struct lpfc_hba * phba)
+lpfc_online(struct lpfc_hba *phba)
{
+ struct lpfc_vport *vport = phba->pport;
+
if (!phba)
return 0;
- if (!(phba->fc_flag & FC_OFFLINE_MODE))
+ if (!(vport->fc_flag & FC_OFFLINE_MODE))
return 0;
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"%d:0458 Bring Adapter online\n",
phba->brd_no);
@@ -1243,9 +1383,14 @@ lpfc_online(struct lpfc_hba * phba)
return 1;
}
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_OFFLINE_MODE;
- spin_unlock_irq(phba->host->host_lock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag &= ~FC_OFFLINE_MODE;
+ if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ spin_unlock_irq(shost->host_lock);
+ }
lpfc_unblock_mgmt_io(phba);
return 0;
@@ -1256,9 +1401,9 @@ lpfc_block_mgmt_io(struct lpfc_hba * phba)
{
unsigned long iflag;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag |= FC_BLOCK_MGMT_IO;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
void
@@ -1266,17 +1411,18 @@ lpfc_unblock_mgmt_io(struct lpfc_hba * phba)
{
unsigned long iflag;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag &= ~FC_BLOCK_MGMT_IO;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ phba->sli.sli_flag &= ~LPFC_BLOCK_MGMT_IO;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
void
lpfc_offline_prep(struct lpfc_hba * phba)
{
+ struct lpfc_vport *vport = phba->pport;
struct lpfc_nodelist *ndlp, *next_ndlp;
- if (phba->fc_flag & FC_OFFLINE_MODE)
+ if (vport->fc_flag & FC_OFFLINE_MODE)
return;
lpfc_block_mgmt_io(phba);
@@ -1284,39 +1430,49 @@ lpfc_offline_prep(struct lpfc_hba * phba)
lpfc_linkdown(phba);
/* Issue an unreg_login to all nodes */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp)
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
if (ndlp->nlp_state != NLP_STE_UNUSED_NODE)
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
lpfc_sli_flush_mbox_queue(phba);
}
void
-lpfc_offline(struct lpfc_hba * phba)
+lpfc_offline(struct lpfc_hba *phba)
{
- unsigned long iflag;
+ struct lpfc_vport *vport = phba->pport;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_vport *port_iterator;
- if (phba->fc_flag & FC_OFFLINE_MODE)
+ if (vport->fc_flag & FC_OFFLINE_MODE)
return;
/* stop all timers associated with this hba */
- lpfc_stop_timer(phba);
+ lpfc_stop_phba_timers(phba);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+ port_iterator->work_port_events = 0;
+ }
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
"%d:0460 Bring Adapter offline\n",
phba->brd_no);
/* Bring down the SLI Layer and cleanup. The HBA is offline
now. */
lpfc_sli_hba_down(phba);
- lpfc_cleanup(phba);
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->work_hba_events = 0;
+ spin_lock_irq(&phba->hbalock);
phba->work_ha = 0;
- phba->fc_flag |= FC_OFFLINE_MODE;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ vport->fc_flag |= FC_OFFLINE_MODE;
+ spin_unlock_irq(&phba->hbalock);
+ list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+ shost = lpfc_shost_from_vport(port_iterator);
+
+ lpfc_cleanup(port_iterator);
+ spin_lock_irq(shost->host_lock);
+ vport->work_port_events = 0;
+ vport->fc_flag |= FC_OFFLINE_MODE;
+ spin_unlock_irq(shost->host_lock);
+ }
}
/******************************************************************************
@@ -1326,17 +1482,17 @@ lpfc_offline(struct lpfc_hba * phba)
*
******************************************************************************/
static int
-lpfc_scsi_free(struct lpfc_hba * phba)
+lpfc_scsi_free(struct lpfc_hba *phba)
{
struct lpfc_scsi_buf *sb, *sb_next;
struct lpfc_iocbq *io, *io_next;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
/* Release all the lpfc_scsi_bufs maintained by this host. */
list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) {
list_del(&sb->list);
pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data,
- sb->dma_handle);
+ sb->dma_handle);
kfree(sb);
phba->total_scsi_bufs--;
}
@@ -1348,134 +1504,183 @@ lpfc_scsi_free(struct lpfc_hba * phba)
phba->total_iocbq_bufs--;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
-void lpfc_remove_device(struct lpfc_hba *phba)
-{
- unsigned long iflag;
- lpfc_free_sysfs_attr(phba);
-
- spin_lock_irqsave(phba->host->host_lock, iflag);
- phba->fc_flag |= FC_UNLOADING;
+struct lpfc_vport *
+lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
+{
+ struct lpfc_vport *vport;
+ struct Scsi_Host *shost;
+ int error = 0;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ shost = scsi_host_alloc(&lpfc_template, sizeof(struct lpfc_vport));
+ if (!shost)
+ goto out;
- fc_remove_host(phba->host);
- scsi_remove_host(phba->host);
+ vport = (struct lpfc_vport *) shost->hostdata;
+ vport->phba = phba;
- kthread_stop(phba->worker_thread);
+ vport->load_flag |= FC_LOADING;
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+ shost->unique_id = instance;
+ shost->max_id = LPFC_MAX_TARGET;
+ shost->max_lun = phba->cfg_max_luns;
+ shost->this_id = -1;
+ shost->max_cmd_len = 16;
/*
- * Bring down the SLI Layer. This step disable all interrupts,
- * clears the rings, discards all mailbox commands, and resets
- * the HBA.
+ * Set initial can_queue value since 0 is no longer supported and
+ * scsi_add_host will fail. This will be adjusted later based on the
+ * max xri value determined in hba setup.
*/
- lpfc_sli_hba_down(phba);
- lpfc_sli_brdrestart(phba);
+ shost->can_queue = phba->cfg_hba_queue_depth - 10;
+ if (fc_vport != NULL) {
+ shost->transportt = lpfc_vport_transport_template;
+ vport->port_type = LPFC_NPIV_PORT;
+ } else {
+ shost->transportt = lpfc_transport_template;
+ vport->port_type = LPFC_PHYSICAL_PORT;
+ }
- /* Release the irq reservation */
- free_irq(phba->pcidev->irq, phba);
- pci_disable_msi(phba->pcidev);
+ /* Initialize all internally managed lists. */
+ INIT_LIST_HEAD(&vport->fc_nodes);
+ spin_lock_init(&vport->work_port_lock);
- lpfc_cleanup(phba);
- lpfc_stop_timer(phba);
- phba->work_hba_events = 0;
+ init_timer(&vport->fc_disctmo);
+ vport->fc_disctmo.function = lpfc_disc_timeout;
+ vport->fc_disctmo.data = (unsigned long)vport;
- /*
- * Call scsi_free before mem_free since scsi bufs are released to their
- * corresponding pools here.
- */
- lpfc_scsi_free(phba);
- lpfc_mem_free(phba);
+ init_timer(&vport->fc_fdmitmo);
+ vport->fc_fdmitmo.function = lpfc_fdmi_tmo;
+ vport->fc_fdmitmo.data = (unsigned long)vport;
- /* Free resources associated with SLI2 interface */
- dma_free_coherent(&phba->pcidev->dev, SLI2_SLIM_SIZE,
- phba->slim2p, phba->slim2p_mapping);
+ init_timer(&vport->els_tmofunc);
+ vport->els_tmofunc.function = lpfc_els_timeout;
+ vport->els_tmofunc.data = (unsigned long)vport;
- /* unmap adapter SLIM and Control Registers */
- iounmap(phba->ctrl_regs_memmap_p);
- iounmap(phba->slim_memmap_p);
+ if (fc_vport != NULL) {
+ error = scsi_add_host(shost, &fc_vport->dev);
+ } else {
+ error = scsi_add_host(shost, &phba->pcidev->dev);
+ }
+ if (error)
+ goto out_put_shost;
- pci_release_regions(phba->pcidev);
- pci_disable_device(phba->pcidev);
+ list_add_tail(&vport->listentry, &phba->port_list);
+ return vport;
- idr_remove(&lpfc_hba_index, phba->brd_no);
- scsi_host_put(phba->host);
+out_put_shost:
+ scsi_host_put(shost);
+out:
+ return NULL;
}
-void lpfc_scan_start(struct Scsi_Host *host)
+void
+destroy_port(struct lpfc_vport *vport)
{
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
- if (lpfc_alloc_sysfs_attr(phba))
- goto error;
+ kfree(vport->vname);
- phba->MBslimaddr = phba->slim_memmap_p;
- phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
- phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
- phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
- phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+ lpfc_debugfs_terminate(vport);
+ fc_remove_host(shost);
+ scsi_remove_host(shost);
- if (lpfc_sli_hba_setup(phba))
- goto error;
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&vport->listentry);
+ spin_unlock_irq(&phba->hbalock);
- /*
- * hba setup may have changed the hba_queue_depth so we need to adjust
- * the value of can_queue.
- */
- host->can_queue = phba->cfg_hba_queue_depth - 10;
+ lpfc_cleanup(vport);
return;
+}
+
+int
+lpfc_get_instance(void)
+{
+ int instance = 0;
-error:
- lpfc_remove_device(phba);
+ /* Assign an unused number */
+ if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL))
+ return -1;
+ if (idr_get_new(&lpfc_hba_index, NULL, &instance))
+ return -1;
+ return instance;
}
+/*
+ * Note: there is no scan_start function as adapter initialization
+ * will have asynchronously kicked off the link initialization.
+ */
+
int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ int stat = 0;
- if (!phba->host)
- return 1;
- if (time >= 30 * HZ)
+ spin_lock_irq(shost->host_lock);
+
+ if (vport->fc_flag & FC_UNLOADING) {
+ stat = 1;
+ goto finished;
+ }
+ if (time >= 30 * HZ) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0461 Scanning longer than 30 "
+ "seconds. Continuing initialization\n",
+ phba->brd_no);
+ stat = 1;
+ goto finished;
+ }
+ if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) {
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0465 Link down longer than 15 "
+ "seconds. Continuing initialization\n",
+ phba->brd_no);
+ stat = 1;
goto finished;
+ }
- if (phba->hba_state != LPFC_HBA_READY)
- return 0;
- if (phba->num_disc_nodes || phba->fc_prli_sent)
- return 0;
- if ((phba->fc_map_cnt == 0) && (time < 2 * HZ))
- return 0;
- if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)
- return 0;
- if ((phba->hba_state > LPFC_LINK_DOWN) || (time < 15 * HZ))
- return 0;
+ if (vport->port_state != LPFC_VPORT_READY)
+ goto finished;
+ if (vport->num_disc_nodes || vport->fc_prli_sent)
+ goto finished;
+ if (vport->fc_map_cnt == 0 && time < 2 * HZ)
+ goto finished;
+ if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0)
+ goto finished;
+
+ stat = 1;
finished:
- if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
- spin_lock_irq(shost->host_lock);
- lpfc_poll_start_timer(phba);
- spin_unlock_irq(shost->host_lock);
- }
+ spin_unlock_irq(shost->host_lock);
+ return stat;
+}
+void lpfc_host_attrib_init(struct Scsi_Host *shost)
+{
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
/*
- * set fixed host attributes
- * Must done after lpfc_sli_hba_setup()
+ * Set fixed host attributes. Must done after lpfc_sli_hba_setup().
*/
- fc_host_node_name(shost) = wwn_to_u64(phba->fc_nodename.u.wwn);
- fc_host_port_name(shost) = wwn_to_u64(phba->fc_portname.u.wwn);
+ fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
+ fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
fc_host_supported_classes(shost) = FC_COS_CLASS3;
memset(fc_host_supported_fc4s(shost), 0,
- sizeof(fc_host_supported_fc4s(shost)));
+ sizeof(fc_host_supported_fc4s(shost)));
fc_host_supported_fc4s(shost)[2] = 1;
fc_host_supported_fc4s(shost)[7] = 1;
- lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+ lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost),
+ sizeof fc_host_symbolic_name(shost));
fc_host_supported_speeds(shost) = 0;
if (phba->lmt & LMT_10Gb)
@@ -1488,31 +1693,31 @@ finished:
fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT;
fc_host_maxframe_size(shost) =
- ((((uint32_t) phba->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
- (uint32_t) phba->fc_sparam.cmn.bbRcvSizeLsb);
+ (((uint32_t) vport->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) |
+ (uint32_t) vport->fc_sparam.cmn.bbRcvSizeLsb;
/* This value is also unchanging */
memset(fc_host_active_fc4s(shost), 0,
- sizeof(fc_host_active_fc4s(shost)));
+ sizeof(fc_host_active_fc4s(shost)));
fc_host_active_fc4s(shost)[2] = 1;
fc_host_active_fc4s(shost)[7] = 1;
+ fc_host_max_npiv_vports(shost) = phba->max_vpi;
spin_lock_irq(shost->host_lock);
- phba->fc_flag &= ~FC_LOADING;
+ vport->fc_flag &= ~FC_LOADING;
spin_unlock_irq(shost->host_lock);
-
- return 1;
}
static int __devinit
lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
{
- struct Scsi_Host *host;
- struct lpfc_hba *phba;
- struct lpfc_sli *psli;
+ struct lpfc_vport *vport = NULL;
+ struct lpfc_hba *phba;
+ struct lpfc_sli *psli;
struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
+ struct Scsi_Host *shost = NULL;
unsigned long bar0map_len, bar2map_len;
- int error = -ENODEV, retval;
+ int error = -ENODEV;
int i;
uint16_t iotag;
@@ -1521,67 +1726,49 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (pci_request_regions(pdev, LPFC_DRIVER_NAME))
goto out_disable_device;
- host = scsi_host_alloc(&lpfc_template, sizeof (struct lpfc_hba));
- if (!host)
+ phba = kzalloc(sizeof (struct lpfc_hba), GFP_KERNEL);
+ if (!phba)
goto out_release_regions;
- phba = (struct lpfc_hba*)host->hostdata;
- memset(phba, 0, sizeof (struct lpfc_hba));
- phba->host = host;
+ spin_lock_init(&phba->hbalock);
- phba->fc_flag |= FC_LOADING;
phba->pcidev = pdev;
/* Assign an unused board number */
- if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL))
- goto out_put_host;
+ if ((phba->brd_no = lpfc_get_instance()) < 0)
+ goto out_free_phba;
- error = idr_get_new(&lpfc_hba_index, NULL, &phba->brd_no);
- if (error)
- goto out_put_host;
-
- host->unique_id = phba->brd_no;
+ INIT_LIST_HEAD(&phba->port_list);
+ INIT_LIST_HEAD(&phba->hbq_buffer_list);
+ /*
+ * Get all the module params for configuring this host and then
+ * establish the host.
+ */
+ lpfc_get_cfgparam(phba);
+ phba->max_vpi = LPFC_MAX_VPI;
/* Initialize timers used by driver */
init_timer(&phba->fc_estabtmo);
phba->fc_estabtmo.function = lpfc_establish_link_tmo;
phba->fc_estabtmo.data = (unsigned long)phba;
- init_timer(&phba->fc_disctmo);
- phba->fc_disctmo.function = lpfc_disc_timeout;
- phba->fc_disctmo.data = (unsigned long)phba;
-
- init_timer(&phba->fc_fdmitmo);
- phba->fc_fdmitmo.function = lpfc_fdmi_tmo;
- phba->fc_fdmitmo.data = (unsigned long)phba;
- init_timer(&phba->els_tmofunc);
- phba->els_tmofunc.function = lpfc_els_timeout;
- phba->els_tmofunc.data = (unsigned long)phba;
+
+ init_timer(&phba->hb_tmofunc);
+ phba->hb_tmofunc.function = lpfc_hb_timeout;
+ phba->hb_tmofunc.data = (unsigned long)phba;
+
psli = &phba->sli;
init_timer(&psli->mbox_tmo);
psli->mbox_tmo.function = lpfc_mbox_timeout;
- psli->mbox_tmo.data = (unsigned long)phba;
-
+ psli->mbox_tmo.data = (unsigned long) phba;
init_timer(&phba->fcp_poll_timer);
phba->fcp_poll_timer.function = lpfc_poll_timeout;
- phba->fcp_poll_timer.data = (unsigned long)phba;
-
- /*
- * Get all the module params for configuring this host and then
- * establish the host parameters.
- */
- lpfc_get_cfgparam(phba);
-
- host->max_id = LPFC_MAX_TARGET;
- host->max_lun = phba->cfg_max_luns;
- host->this_id = -1;
-
- INIT_LIST_HEAD(&phba->fc_nodes);
+ phba->fcp_poll_timer.data = (unsigned long) phba;
+ init_timer(&phba->fabric_block_timer);
+ phba->fabric_block_timer.function = lpfc_fabric_block_timeout;
+ phba->fabric_block_timer.data = (unsigned long) phba;
pci_set_master(pdev);
- retval = pci_set_mwi(pdev);
- if (retval)
- dev_printk(KERN_WARNING, &pdev->dev,
- "Warning: pci_set_mwi returned %d\n", retval);
+ pci_try_set_mwi(pdev);
if (pci_set_dma_mask(phba->pcidev, DMA_64BIT_MASK) != 0)
if (pci_set_dma_mask(phba->pcidev, DMA_32BIT_MASK) != 0)
@@ -1623,18 +1810,27 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
memset(phba->slim2p, 0, SLI2_SLIM_SIZE);
+ phba->hbqslimp.virt = dma_alloc_coherent(&phba->pcidev->dev,
+ lpfc_sli_hbq_size(),
+ &phba->hbqslimp.phys,
+ GFP_KERNEL);
+ if (!phba->hbqslimp.virt)
+ goto out_free_slim;
+
+ memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
+
/* Initialize the SLI Layer to run with lpfc HBAs. */
lpfc_sli_setup(phba);
lpfc_sli_queue_setup(phba);
error = lpfc_mem_alloc(phba);
if (error)
- goto out_free_slim;
+ goto out_free_hbqslimp;
/* Initialize and populate the iocb list per host. */
INIT_LIST_HEAD(&phba->lpfc_iocb_list);
for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) {
- iocbq_entry = kmalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
+ iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
if (iocbq_entry == NULL) {
printk(KERN_ERR "%s: only allocated %d iocbs of "
"expected %d count. Unloading driver.\n",
@@ -1643,7 +1839,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_iocbq;
}
- memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq));
iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
if (iotag == 0) {
kfree (iocbq_entry);
@@ -1653,10 +1848,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
error = -ENOMEM;
goto out_free_iocbq;
}
- spin_lock_irq(phba->host->host_lock);
+
+ spin_lock_irq(&phba->hbalock);
list_add(&iocbq_entry->list, &phba->lpfc_iocb_list);
phba->total_iocbq_bufs++;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
}
/* Initialize HBA structure */
@@ -1677,22 +1873,22 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_iocbq;
}
- /*
- * Set initial can_queue value since 0 is no longer supported and
- * scsi_add_host will fail. This will be adjusted later based on the
- * max xri value determined in hba setup.
- */
- host->can_queue = phba->cfg_hba_queue_depth - 10;
-
- /* Tell the midlayer we support 16 byte commands */
- host->max_cmd_len = 16;
-
/* Initialize the list of scsi buffers used by driver for scsi IO. */
spin_lock_init(&phba->scsi_buf_list_lock);
INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list);
- host->transportt = lpfc_transport_template;
- pci_set_drvdata(pdev, host);
+ /* Initialize list of fabric iocbs */
+ INIT_LIST_HEAD(&phba->fabric_iocb_list);
+
+ vport = lpfc_create_port(phba, phba->brd_no, NULL);
+ if (!vport)
+ goto out_kthread_stop;
+
+ shost = lpfc_shost_from_vport(vport);
+ phba->pport = vport;
+ lpfc_debugfs_initialize(vport);
+
+ pci_set_drvdata(pdev, shost);
if (phba->cfg_use_msi) {
error = pci_enable_msi(phba->pcidev);
@@ -1703,38 +1899,68 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
}
error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
- LPFC_DRIVER_NAME, phba);
+ LPFC_DRIVER_NAME, phba);
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0451 Enable interrupt handler failed\n",
phba->brd_no);
- goto out_kthread_stop;
+ goto out_disable_msi;
}
- error = scsi_add_host(host, &pdev->dev);
- if (error)
+ phba->MBslimaddr = phba->slim_memmap_p;
+ phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET;
+ phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET;
+ phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET;
+ phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET;
+
+ if (lpfc_alloc_sysfs_attr(vport))
goto out_free_irq;
- scsi_scan_host(host);
+ if (lpfc_sli_hba_setup(phba))
+ goto out_remove_device;
+
+ /*
+ * hba setup may have changed the hba_queue_depth so we need to adjust
+ * the value of can_queue.
+ */
+ shost->can_queue = phba->cfg_hba_queue_depth - 10;
+
+ lpfc_host_attrib_init(shost);
+
+ if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
+ spin_lock_irq(shost->host_lock);
+ lpfc_poll_start_timer(phba);
+ spin_unlock_irq(shost->host_lock);
+ }
+
+ scsi_scan_host(shost);
return 0;
+out_remove_device:
+ lpfc_free_sysfs_attr(vport);
+ spin_lock_irq(shost->host_lock);
+ vport->fc_flag |= FC_UNLOADING;
+ spin_unlock_irq(shost->host_lock);
out_free_irq:
- lpfc_stop_timer(phba);
- phba->work_hba_events = 0;
+ lpfc_stop_phba_timers(phba);
+ phba->pport->work_port_events = 0;
free_irq(phba->pcidev->irq, phba);
+out_disable_msi:
pci_disable_msi(phba->pcidev);
+ destroy_port(vport);
out_kthread_stop:
kthread_stop(phba->worker_thread);
out_free_iocbq:
list_for_each_entry_safe(iocbq_entry, iocbq_next,
&phba->lpfc_iocb_list, list) {
- spin_lock_irq(phba->host->host_lock);
kfree(iocbq_entry);
phba->total_iocbq_bufs--;
- spin_unlock_irq(phba->host->host_lock);
}
lpfc_mem_free(phba);
+out_free_hbqslimp:
+ dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt,
+ phba->hbqslimp.phys);
out_free_slim:
dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, phba->slim2p,
phba->slim2p_mapping);
@@ -1744,27 +1970,85 @@ out_iounmap_slim:
iounmap(phba->slim_memmap_p);
out_idr_remove:
idr_remove(&lpfc_hba_index, phba->brd_no);
-out_put_host:
- phba->host = NULL;
- scsi_host_put(host);
+out_free_phba:
+ kfree(phba);
out_release_regions:
pci_release_regions(pdev);
out_disable_device:
pci_disable_device(pdev);
out:
pci_set_drvdata(pdev, NULL);
+ if (shost)
+ scsi_host_put(shost);
return error;
}
static void __devexit
lpfc_pci_remove_one(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
- struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_vport *port_iterator;
+ list_for_each_entry(port_iterator, &phba->port_list, listentry)
+ port_iterator->load_flag |= FC_UNLOADING;
+
+ kfree(vport->vname);
+ lpfc_free_sysfs_attr(vport);
+
+ fc_remove_host(shost);
+ scsi_remove_host(shost);
+
+ /*
+ * Bring down the SLI Layer. This step disable all interrupts,
+ * clears the rings, discards all mailbox commands, and resets
+ * the HBA.
+ */
+ lpfc_sli_hba_down(phba);
+ lpfc_sli_brdrestart(phba);
+
+ lpfc_stop_phba_timers(phba);
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&vport->listentry);
+ spin_unlock_irq(&phba->hbalock);
+
- lpfc_remove_device(phba);
+ lpfc_debugfs_terminate(vport);
+ lpfc_cleanup(vport);
+
+ kthread_stop(phba->worker_thread);
+
+ /* Release the irq reservation */
+ free_irq(phba->pcidev->irq, phba);
+ pci_disable_msi(phba->pcidev);
pci_set_drvdata(pdev, NULL);
+ scsi_host_put(shost);
+
+ /*
+ * Call scsi_free before mem_free since scsi bufs are released to their
+ * corresponding pools here.
+ */
+ lpfc_scsi_free(phba);
+ lpfc_mem_free(phba);
+
+ dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), phba->hbqslimp.virt,
+ phba->hbqslimp.phys);
+
+ /* Free resources associated with SLI2 interface */
+ dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE,
+ phba->slim2p, phba->slim2p_mapping);
+
+ /* unmap adapter SLIM and Control Registers */
+ iounmap(phba->ctrl_regs_memmap_p);
+ iounmap(phba->slim_memmap_p);
+
+ idr_remove(&lpfc_hba_index, phba->brd_no);
+
+ kfree(phba);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
}
/**
@@ -1822,10 +2106,13 @@ static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
pci_set_master(pdev);
/* Re-establishing Link */
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag |= FC_ESTABLISH_LINK;
+ spin_lock_irq(host->host_lock);
+ phba->pport->fc_flag |= FC_ESTABLISH_LINK;
+ spin_unlock_irq(host->host_lock);
+
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
/* Take device offline; this will perform cleanup */
@@ -1935,7 +2222,7 @@ static struct pci_driver lpfc_driver = {
.id_table = lpfc_id_table,
.probe = lpfc_pci_probe_one,
.remove = __devexit_p(lpfc_pci_remove_one),
- .err_handler = &lpfc_err_handler,
+ .err_handler = &lpfc_err_handler,
};
static int __init
@@ -1948,11 +2235,15 @@ lpfc_init(void)
lpfc_transport_template =
fc_attach_transport(&lpfc_transport_functions);
- if (!lpfc_transport_template)
+ lpfc_vport_transport_template =
+ fc_attach_transport(&lpfc_vport_transport_functions);
+ if (!lpfc_transport_template || !lpfc_vport_transport_template)
return -ENOMEM;
error = pci_register_driver(&lpfc_driver);
- if (error)
+ if (error) {
fc_release_transport(lpfc_transport_template);
+ fc_release_transport(lpfc_vport_transport_template);
+ }
return error;
}
@@ -1962,6 +2253,7 @@ lpfc_exit(void)
{
pci_unregister_driver(&lpfc_driver);
fc_release_transport(lpfc_transport_template);
+ fc_release_transport(lpfc_vport_transport_template);
}
module_init(lpfc_init);
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 438cbcd9eb13..8a6ceffeabcf 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -30,6 +30,7 @@
#define LOG_SLI 0x800 /* SLI events */
#define LOG_FCP_ERROR 0x1000 /* log errors, not underruns */
#define LOG_LIBDFC 0x2000 /* Libdfc events */
+#define LOG_VPORT 0x4000 /* NPIV events */
#define LOG_ALL_MSG 0xffff /* LOG all messages */
#define lpfc_printf_log(phba, level, mask, fmt, arg...) \
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 8041c3f06f7b..8f42fbfdd29e 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -82,6 +82,22 @@ lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
}
/**********************************************/
+/* lpfc_heart_beat Issue a HEART_BEAT */
+/* mailbox command */
+/**********************************************/
+void
+lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+{
+ MAILBOX_t *mb;
+
+ mb = &pmb->mb;
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+ mb->mbxCommand = MBX_HEARTBEAT;
+ mb->mbxOwner = OWN_HOST;
+ return;
+}
+
+/**********************************************/
/* lpfc_read_la Issue a READ LA */
/* mailbox command */
/**********************************************/
@@ -134,6 +150,7 @@ lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
void
lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
+ struct lpfc_vport *vport = phba->pport;
MAILBOX_t *mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
@@ -147,7 +164,7 @@ lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
mb->un.varCfgLnk.cr_count = phba->cfg_cr_count;
}
- mb->un.varCfgLnk.myId = phba->fc_myDID;
+ mb->un.varCfgLnk.myId = vport->fc_myDID;
mb->un.varCfgLnk.edtov = phba->fc_edtov;
mb->un.varCfgLnk.arbtov = phba->fc_arbtov;
mb->un.varCfgLnk.ratov = phba->fc_ratov;
@@ -239,7 +256,7 @@ lpfc_init_link(struct lpfc_hba * phba,
/* mailbox command */
/**********************************************/
int
-lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi)
{
struct lpfc_dmabuf *mp;
MAILBOX_t *mb;
@@ -270,6 +287,7 @@ lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm);
mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys);
mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys);
+ mb->un.varRdSparm.vpi = vpi;
/* save address for completion */
pmb->context1 = mp;
@@ -282,7 +300,8 @@ lpfc_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
/* mailbox command */
/********************************************/
void
-lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb)
+lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did,
+ LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
@@ -290,6 +309,7 @@ lpfc_unreg_did(struct lpfc_hba * phba, uint32_t did, LPFC_MBOXQ_t * pmb)
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varUnregDID.did = did;
+ mb->un.varUnregDID.vpi = vpi;
mb->mbxCommand = MBX_UNREG_D_ID;
mb->mbxOwner = OWN_HOST;
@@ -335,19 +355,17 @@ lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
/* mailbox command */
/********************************************/
int
-lpfc_reg_login(struct lpfc_hba * phba,
- uint32_t did, uint8_t * param, LPFC_MBOXQ_t * pmb, uint32_t flag)
+lpfc_reg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t did,
+ uint8_t *param, LPFC_MBOXQ_t *pmb, uint32_t flag)
{
+ MAILBOX_t *mb = &pmb->mb;
uint8_t *sparam;
struct lpfc_dmabuf *mp;
- MAILBOX_t *mb;
- struct lpfc_sli *psli;
- psli = &phba->sli;
- mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varRegLogin.rpi = 0;
+ mb->un.varRegLogin.vpi = vpi;
mb->un.varRegLogin.did = did;
mb->un.varWords[30] = flag; /* Set flag to issue action on cmpl */
@@ -359,12 +377,10 @@ lpfc_reg_login(struct lpfc_hba * phba,
kfree(mp);
mb->mbxCommand = MBX_REG_LOGIN64;
/* REG_LOGIN: no buffers */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_MBOX,
- "%d:0302 REG_LOGIN: no buffers Data x%x x%x\n",
- phba->brd_no,
- (uint32_t) did, (uint32_t) flag);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+ "%d (%d):0302 REG_LOGIN: no buffers, DID x%x, "
+ "flag x%x\n",
+ phba->brd_no, vpi, did, flag);
return (1);
}
INIT_LIST_HEAD(&mp->list);
@@ -389,7 +405,8 @@ lpfc_reg_login(struct lpfc_hba * phba,
/* mailbox command */
/**********************************************/
void
-lpfc_unreg_login(struct lpfc_hba * phba, uint32_t rpi, LPFC_MBOXQ_t * pmb)
+lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi,
+ LPFC_MBOXQ_t * pmb)
{
MAILBOX_t *mb;
@@ -398,12 +415,52 @@ lpfc_unreg_login(struct lpfc_hba * phba, uint32_t rpi, LPFC_MBOXQ_t * pmb)
mb->un.varUnregLogin.rpi = (uint16_t) rpi;
mb->un.varUnregLogin.rsvd1 = 0;
+ mb->un.varUnregLogin.vpi = vpi;
mb->mbxCommand = MBX_UNREG_LOGIN;
mb->mbxOwner = OWN_HOST;
return;
}
+/**************************************************/
+/* lpfc_reg_vpi Issue a REG_VPI */
+/* mailbox command */
+/**************************************************/
+void
+lpfc_reg_vpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t sid,
+ LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->mb;
+
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+ mb->un.varRegVpi.vpi = vpi;
+ mb->un.varRegVpi.sid = sid;
+
+ mb->mbxCommand = MBX_REG_VPI;
+ mb->mbxOwner = OWN_HOST;
+ return;
+
+}
+
+/**************************************************/
+/* lpfc_unreg_vpi Issue a UNREG_VNPI */
+/* mailbox command */
+/**************************************************/
+void
+lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb)
+{
+ MAILBOX_t *mb = &pmb->mb;
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+
+ mb->un.varUnregVpi.vpi = vpi;
+
+ mb->mbxCommand = MBX_UNREG_VPI;
+ mb->mbxOwner = OWN_HOST;
+ return;
+
+}
+
static void
lpfc_config_pcb_setup(struct lpfc_hba * phba)
{
@@ -412,14 +469,18 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
PCB_t *pcbp = &phba->slim2p->pcb;
dma_addr_t pdma_addr;
uint32_t offset;
- uint32_t iocbCnt;
+ uint32_t iocbCnt = 0;
int i;
pcbp->maxRing = (psli->num_rings - 1);
- iocbCnt = 0;
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
+
+ pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE:
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE:
+ SLI2_IOCB_RSP_SIZE;
/* A ring MUST have both cmd and rsp entries defined to be
valid */
if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) {
@@ -434,20 +495,18 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
continue;
}
/* Command ring setup for ring */
- pring->cmdringaddr =
- (void *)&phba->slim2p->IOCBs[iocbCnt];
+ pring->cmdringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
pcbp->rdsc[i].cmdEntries = pring->numCiocb;
- offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
- (uint8_t *)phba->slim2p;
+ offset = (uint8_t *) &phba->slim2p->IOCBs[iocbCnt] -
+ (uint8_t *) phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr);
pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr);
iocbCnt += pring->numCiocb;
/* Response ring setup for ring */
- pring->rspringaddr =
- (void *)&phba->slim2p->IOCBs[iocbCnt];
+ pring->rspringaddr = (void *) &phba->slim2p->IOCBs[iocbCnt];
pcbp->rdsc[i].rspEntries = pring->numRiocb;
offset = (uint8_t *)&phba->slim2p->IOCBs[iocbCnt] -
@@ -462,16 +521,108 @@ lpfc_config_pcb_setup(struct lpfc_hba * phba)
void
lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
{
- MAILBOX_t *mb;
-
- mb = &pmb->mb;
+ MAILBOX_t *mb = &pmb->mb;
memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
mb->un.varRdRev.cv = 1;
+ mb->un.varRdRev.v3req = 1; /* Request SLI3 info */
mb->mbxCommand = MBX_READ_REV;
mb->mbxOwner = OWN_HOST;
return;
}
+static void
+lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb,
+ struct lpfc_hbq_init *hbq_desc)
+{
+ hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt;
+ hbqmb->profiles.profile2.maxlen = hbq_desc->maxlen;
+ hbqmb->profiles.profile2.seqlenoff = hbq_desc->seqlenoff;
+}
+
+static void
+lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb,
+ struct lpfc_hbq_init *hbq_desc)
+{
+ hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt;
+ hbqmb->profiles.profile3.maxlen = hbq_desc->maxlen;
+ hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff;
+ hbqmb->profiles.profile3.seqlenoff = hbq_desc->seqlenoff;
+ memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch,
+ sizeof(hbqmb->profiles.profile3.cmdmatch));
+}
+
+static void
+lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb,
+ struct lpfc_hbq_init *hbq_desc)
+{
+ hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt;
+ hbqmb->profiles.profile5.maxlen = hbq_desc->maxlen;
+ hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff;
+ hbqmb->profiles.profile5.seqlenoff = hbq_desc->seqlenoff;
+ memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch,
+ sizeof(hbqmb->profiles.profile5.cmdmatch));
+}
+
+void
+lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
+ uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
+{
+ int i;
+ MAILBOX_t *mb = &pmb->mb;
+ struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
+
+ memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+ hbqmb->entry_count = hbq_desc->entry_count; /* # entries in HBQ */
+ hbqmb->recvNotify = hbq_desc->rn; /* Receive
+ * Notification */
+ hbqmb->numMask = hbq_desc->mask_count; /* # R_CTL/TYPE masks
+ * # in words 0-19 */
+ hbqmb->profile = hbq_desc->profile; /* Selection profile:
+ * 0 = all,
+ * 7 = logentry */
+ hbqmb->ringMask = hbq_desc->ring_mask; /* Binds HBQ to a ring
+ * e.g. Ring0=b0001,
+ * ring2=b0100 */
+ hbqmb->headerLen = hbq_desc->headerLen; /* 0 if not profile 4
+ * or 5 */
+ hbqmb->logEntry = hbq_desc->logEntry; /* Set to 1 if this
+ * HBQ will be used
+ * for LogEntry
+ * buffers */
+ hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) +
+ hbq_entry_index * sizeof(struct lpfc_hbq_entry);
+ hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys);
+
+ mb->mbxCommand = MBX_CONFIG_HBQ;
+ mb->mbxOwner = OWN_HOST;
+
+ /* Copy info for profiles 2,3,5. Other
+ * profiles this area is reserved
+ */
+ if (hbq_desc->profile == 2)
+ lpfc_build_hbq_profile2(hbqmb, hbq_desc);
+ else if (hbq_desc->profile == 3)
+ lpfc_build_hbq_profile3(hbqmb, hbq_desc);
+ else if (hbq_desc->profile == 5)
+ lpfc_build_hbq_profile5(hbqmb, hbq_desc);
+
+ /* Return if no rctl / type masks for this HBQ */
+ if (!hbq_desc->mask_count)
+ return;
+
+ /* Otherwise we setup specific rctl / type masks for this HBQ */
+ for (i = 0; i < hbq_desc->mask_count; i++) {
+ hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch;
+ hbqmb->hbqMasks[i].tmask = hbq_desc->hbqMasks[i].tmask;
+ hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch;
+ hbqmb->hbqMasks[i].rctlmask = hbq_desc->hbqMasks[i].rctlmask;
+ }
+
+ return;
+}
+
+
+
void
lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
{
@@ -514,15 +665,16 @@ lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb)
}
void
-lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
+ MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr;
MAILBOX_t *mb = &pmb->mb;
dma_addr_t pdma_addr;
uint32_t bar_low, bar_high;
size_t offset;
struct lpfc_hgp hgp;
- void __iomem *to_slim;
int i;
+ uint32_t pgp_offset;
memset(pmb, 0, sizeof(LPFC_MBOXQ_t));
mb->mbxCommand = MBX_CONFIG_PORT;
@@ -535,12 +687,29 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr);
mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr);
+ /* If HBA supports SLI=3 ask for it */
+
+ if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
+ mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
+ mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
+ if (phba->max_vpi && phba->cfg_npiv_enable &&
+ phba->vpd.sli3Feat.cmv) {
+ mb->un.varCfgPort.max_vpi = phba->max_vpi;
+ mb->un.varCfgPort.cmv = 1;
+ phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
+ } else
+ mb->un.varCfgPort.max_vpi = phba->max_vpi = 0;
+ } else
+ phba->sli_rev = 2;
+ mb->un.varCfgPort.sli_mode = phba->sli_rev;
+
/* Now setup pcb */
phba->slim2p->pcb.type = TYPE_NATIVE_SLI2;
phba->slim2p->pcb.feature = FEATURE_INITIAL_SLI2;
/* Setup Mailbox pointers */
- phba->slim2p->pcb.mailBoxSize = sizeof(MAILBOX_t);
+ phba->slim2p->pcb.mailBoxSize = offsetof(MAILBOX_t, us) +
+ sizeof(struct sli2_desc);
offset = (uint8_t *)&phba->slim2p->mbx - (uint8_t *)phba->slim2p;
pdma_addr = phba->slim2p_mapping + offset;
phba->slim2p->pcb.mbAddrHigh = putPaddrHigh(pdma_addr);
@@ -568,29 +737,70 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low);
pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high);
+ /*
+ * Set up HGP - Port Memory
+ *
+ * The port expects the host get/put pointers to reside in memory
+ * following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes)
+ * area of SLIM. In SLI-2 mode, there's an additional 16 reserved
+ * words (0x40 bytes). This area is not reserved if HBQs are
+ * configured in SLI-3.
+ *
+ * CR0Put - SLI2(no HBQs) = 0xc0, With HBQs = 0x80
+ * RR0Get 0xc4 0x84
+ * CR1Put 0xc8 0x88
+ * RR1Get 0xcc 0x8c
+ * CR2Put 0xd0 0x90
+ * RR2Get 0xd4 0x94
+ * CR3Put 0xd8 0x98
+ * RR3Get 0xdc 0x9c
+ *
+ * Reserved 0xa0-0xbf
+ * If HBQs configured:
+ * HBQ 0 Put ptr 0xc0
+ * HBQ 1 Put ptr 0xc4
+ * HBQ 2 Put ptr 0xc8
+ * ......
+ * HBQ(M-1)Put Pointer 0xc0+(M-1)*4
+ *
+ */
+
+ if (phba->sli_rev == 3) {
+ phba->host_gp = &mb_slim->us.s3.host[0];
+ phba->hbq_put = &mb_slim->us.s3.hbq_put[0];
+ } else {
+ phba->host_gp = &mb_slim->us.s2.host[0];
+ phba->hbq_put = NULL;
+ }
/* mask off BAR0's flag bits 0 - 3 */
phba->slim2p->pcb.hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) +
- (SLIMOFF*sizeof(uint32_t));
+ (void __iomem *) phba->host_gp -
+ (void __iomem *)phba->MBslimaddr;
if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64)
phba->slim2p->pcb.hgpAddrHigh = bar_high;
else
phba->slim2p->pcb.hgpAddrHigh = 0;
/* write HGP data to SLIM at the required longword offset */
memset(&hgp, 0, sizeof(struct lpfc_hgp));
- to_slim = phba->MBslimaddr + (SLIMOFF*sizeof (uint32_t));
for (i=0; i < phba->sli.num_rings; i++) {
- lpfc_memcpy_to_slim(to_slim, &hgp, sizeof(struct lpfc_hgp));
- to_slim += sizeof (struct lpfc_hgp);
+ lpfc_memcpy_to_slim(phba->host_gp + i, &hgp,
+ sizeof(*phba->host_gp));
}
/* Setup Port Group ring pointer */
- offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
- (uint8_t *)phba->slim2p;
- pdma_addr = phba->slim2p_mapping + offset;
+ if (phba->sli_rev == 3)
+ pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s3_pgp.port -
+ (uint8_t *)phba->slim2p;
+ else
+ pgp_offset = (uint8_t *)&phba->slim2p->mbx.us.s2.port -
+ (uint8_t *)phba->slim2p;
+
+ pdma_addr = phba->slim2p_mapping + pgp_offset;
phba->slim2p->pcb.pgpAddrHigh = putPaddrHigh(pdma_addr);
phba->slim2p->pcb.pgpAddrLow = putPaddrLow(pdma_addr);
+ phba->hbq_get = &phba->slim2p->mbx.us.s3_pgp.hbq_get[0];
/* Use callback routine to setp rings in the pcb */
lpfc_config_pcb_setup(phba);
@@ -606,11 +816,7 @@ lpfc_config_port(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
/* Swap PCB if needed */
lpfc_sli_pcimem_bcopy(&phba->slim2p->pcb, &phba->slim2p->pcb,
- sizeof (PCB_t));
-
- lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
- "%d:0405 Service Level Interface (SLI) 2 selected\n",
- phba->brd_no);
+ sizeof(PCB_t));
}
void
@@ -644,15 +850,23 @@ lpfc_mbox_get(struct lpfc_hba * phba)
LPFC_MBOXQ_t *mbq = NULL;
struct lpfc_sli *psli = &phba->sli;
- list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t,
- list);
- if (mbq) {
+ list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t, list);
+ if (mbq)
psli->mboxq_cnt--;
- }
return mbq;
}
+void
+lpfc_mbox_cmpl_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq)
+{
+ /* This function expects to be called from interupt context */
+ spin_lock(&phba->hbalock);
+ list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl);
+ spin_unlock(&phba->hbalock);
+ return;
+}
+
int
lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
{
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index ec3bbbde6f7a..3594c469494f 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* Portions Copyright (C) 2004-2005 Christoph Hellwig *
@@ -38,10 +38,13 @@
#define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */
#define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */
+
+
int
lpfc_mem_alloc(struct lpfc_hba * phba)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+ int longs;
int i;
phba->lpfc_scsi_dma_buf_pool = pci_pool_create("lpfc_scsi_dma_buf_pool",
@@ -80,10 +83,27 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
if (!phba->nlp_mem_pool)
goto fail_free_mbox_pool;
+ phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool",phba->pcidev,
+ LPFC_BPL_SIZE, 8, 0);
+ if (!phba->lpfc_hbq_pool)
+ goto fail_free_nlp_mem_pool;
+
+ /* vpi zero is reserved for the physical port so add 1 to max */
+ longs = ((phba->max_vpi + 1) + BITS_PER_LONG - 1) / BITS_PER_LONG;
+ phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), GFP_KERNEL);
+ if (!phba->vpi_bmask)
+ goto fail_free_hbq_pool;
+
return 0;
+ fail_free_hbq_pool:
+ lpfc_sli_hbqbuf_free_all(phba);
+ fail_free_nlp_mem_pool:
+ mempool_destroy(phba->nlp_mem_pool);
+ phba->nlp_mem_pool = NULL;
fail_free_mbox_pool:
mempool_destroy(phba->mbox_mem_pool);
+ phba->mbox_mem_pool = NULL;
fail_free_mbuf_pool:
while (i--)
pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
@@ -91,8 +111,10 @@ lpfc_mem_alloc(struct lpfc_hba * phba)
kfree(pool->elements);
fail_free_lpfc_mbuf_pool:
pci_pool_destroy(phba->lpfc_mbuf_pool);
+ phba->lpfc_mbuf_pool = NULL;
fail_free_dma_buf_pool:
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
+ phba->lpfc_scsi_dma_buf_pool = NULL;
fail:
return -ENOMEM;
}
@@ -106,6 +128,9 @@ lpfc_mem_free(struct lpfc_hba * phba)
struct lpfc_dmabuf *mp;
int i;
+ kfree(phba->vpi_bmask);
+ lpfc_sli_hbqbuf_free_all(phba);
+
list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) {
mp = (struct lpfc_dmabuf *) (mbox->context1);
if (mp) {
@@ -115,6 +140,15 @@ lpfc_mem_free(struct lpfc_hba * phba)
list_del(&mbox->list);
mempool_free(mbox, phba->mbox_mem_pool);
}
+ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) {
+ mp = (struct lpfc_dmabuf *) (mbox->context1);
+ if (mp) {
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+ list_del(&mbox->list);
+ mempool_free(mbox, phba->mbox_mem_pool);
+ }
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
if (psli->mbox_active) {
@@ -132,13 +166,21 @@ lpfc_mem_free(struct lpfc_hba * phba)
pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt,
pool->elements[i].phys);
kfree(pool->elements);
+
+ pci_pool_destroy(phba->lpfc_hbq_pool);
mempool_destroy(phba->nlp_mem_pool);
mempool_destroy(phba->mbox_mem_pool);
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
pci_pool_destroy(phba->lpfc_mbuf_pool);
- /* Free the iocb lookup array */
+ phba->lpfc_hbq_pool = NULL;
+ phba->nlp_mem_pool = NULL;
+ phba->mbox_mem_pool = NULL;
+ phba->lpfc_scsi_dma_buf_pool = NULL;
+ phba->lpfc_mbuf_pool = NULL;
+
+ /* Free the iocb lookup array */
kfree(psli->iocbq_lookup);
psli->iocbq_lookup = NULL;
@@ -148,20 +190,23 @@ void *
lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
+ unsigned long iflags;
void *ret;
ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle);
- if (!ret && ( mem_flags & MEM_PRI) && pool->current_count) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ if (!ret && (mem_flags & MEM_PRI) && pool->current_count) {
pool->current_count--;
ret = pool->elements[pool->current_count].virt;
*handle = pool->elements[pool->current_count].phys;
}
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
return ret;
}
void
-lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
+__lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
{
struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool;
@@ -174,3 +219,51 @@ lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
}
return;
}
+
+void
+lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma)
+{
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ __lpfc_mbuf_free(phba, virt, dma);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return;
+}
+
+void *
+lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
+{
+ void *ret;
+ ret = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, handle);
+ return ret;
+}
+
+void
+lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma)
+{
+ pci_pool_free(phba->lpfc_hbq_pool, virt, dma);
+ return;
+}
+
+void
+lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
+{
+ struct hbq_dmabuf *hbq_entry;
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
+ if (hbq_entry->tag == -1) {
+ lpfc_hbq_free(phba, hbq_entry->dbuf.virt,
+ hbq_entry->dbuf.phys);
+ kfree(hbq_entry);
+ } else {
+ lpfc_sli_free_hbq(phba, hbq_entry);
+ }
+ } else {
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ }
+ return;
+}
+
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index b309841e3846..bca2f5c9b4ba 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1,4 +1,4 @@
-/*******************************************************************
+ /*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
* Copyright (C) 2004-2007 Emulex. All rights reserved. *
@@ -35,20 +35,22 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
+#include "lpfc_debugfs.h"
/* Called to verify a rcv'ed ADISC was intended for us. */
static int
-lpfc_check_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
- struct lpfc_name * nn, struct lpfc_name * pn)
+lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_name *nn, struct lpfc_name *pn)
{
/* Compare the ADISC rsp WWNN / WWPN matches our internal node
* table entry for that node.
*/
- if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)) != 0)
+ if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name)))
return 0;
- if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)) != 0)
+ if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name)))
return 0;
/* we match, return success */
@@ -56,11 +58,10 @@ lpfc_check_adisc(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
}
int
-lpfc_check_sparm(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, struct serv_parm * sp,
- uint32_t class)
+lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct serv_parm * sp, uint32_t class)
{
- volatile struct serv_parm *hsp = &phba->fc_sparam;
+ volatile struct serv_parm *hsp = &vport->fc_sparam;
uint16_t hsp_value, ssp_value = 0;
/*
@@ -75,12 +76,14 @@ lpfc_check_sparm(struct lpfc_hba * phba,
hsp->cls1.rcvDataSizeLsb;
ssp_value = (sp->cls1.rcvDataSizeMsb << 8) |
sp->cls1.rcvDataSizeLsb;
+ if (!ssp_value)
+ goto bad_service_param;
if (ssp_value > hsp_value) {
sp->cls1.rcvDataSizeLsb = hsp->cls1.rcvDataSizeLsb;
sp->cls1.rcvDataSizeMsb = hsp->cls1.rcvDataSizeMsb;
}
} else if (class == CLASS1) {
- return 0;
+ goto bad_service_param;
}
if (sp->cls2.classValid) {
@@ -88,12 +91,14 @@ lpfc_check_sparm(struct lpfc_hba * phba,
hsp->cls2.rcvDataSizeLsb;
ssp_value = (sp->cls2.rcvDataSizeMsb << 8) |
sp->cls2.rcvDataSizeLsb;
+ if (!ssp_value)
+ goto bad_service_param;
if (ssp_value > hsp_value) {
sp->cls2.rcvDataSizeLsb = hsp->cls2.rcvDataSizeLsb;
sp->cls2.rcvDataSizeMsb = hsp->cls2.rcvDataSizeMsb;
}
} else if (class == CLASS2) {
- return 0;
+ goto bad_service_param;
}
if (sp->cls3.classValid) {
@@ -101,12 +106,14 @@ lpfc_check_sparm(struct lpfc_hba * phba,
hsp->cls3.rcvDataSizeLsb;
ssp_value = (sp->cls3.rcvDataSizeMsb << 8) |
sp->cls3.rcvDataSizeLsb;
+ if (!ssp_value)
+ goto bad_service_param;
if (ssp_value > hsp_value) {
sp->cls3.rcvDataSizeLsb = hsp->cls3.rcvDataSizeLsb;
sp->cls3.rcvDataSizeMsb = hsp->cls3.rcvDataSizeMsb;
}
} else if (class == CLASS3) {
- return 0;
+ goto bad_service_param;
}
/*
@@ -125,12 +132,22 @@ lpfc_check_sparm(struct lpfc_hba * phba,
memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name));
memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
return 1;
+bad_service_param:
+ lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0207 Device %x "
+ "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
+ "invalid service parameters. Ignoring device.\n",
+ vport->phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
+ sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
+ sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
+ sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
+ sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
+ return 0;
}
static void *
-lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
- struct lpfc_iocbq *cmdiocb,
- struct lpfc_iocbq *rspiocb)
+lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
struct lpfc_dmabuf *pcmd, *prsp;
uint32_t *lp;
@@ -168,32 +185,29 @@ lpfc_check_elscmpl_iocb(struct lpfc_hba * phba,
* routine effectively results in a "software abort".
*/
int
-lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
+lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
{
LIST_HEAD(completions);
- struct lpfc_sli *psli;
- struct lpfc_sli_ring *pring;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
struct lpfc_iocbq *iocb, *next_iocb;
IOCB_t *cmd;
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0205 Abort outstanding I/O on NPort x%x "
+ "%d (%d):0205 Abort outstanding I/O on NPort x%x "
"Data: x%x x%x x%x\n",
- phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
- ndlp->nlp_state, ndlp->nlp_rpi);
+ phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
+ ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
- psli = &phba->sli;
- pring = &psli->ring[LPFC_ELS_RING];
+ lpfc_fabric_abort_nport(ndlp);
/* First check the txq */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
- /* Check to see if iocb matches the nport we are looking
- for */
+ /* Check to see if iocb matches the nport we are looking for */
if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
- /* It matches, so deque and call compl with an
- error */
+ /* It matches, so deque and call compl with anp error */
list_move_tail(&iocb->list, &completions);
pring->txq_cnt--;
}
@@ -201,37 +215,39 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
/* Next check the txcmplq */
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) {
- /* Check to see if iocb matches the nport we are looking
- for */
- if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp))
+ /* Check to see if iocb matches the nport we are looking for */
+ if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) {
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
cmd = &iocb->iocb;
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
/* If we are delaying issuing an ELS command, cancel it */
if (ndlp->nlp_flag & NLP_DELAY_TMO)
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
return 0;
}
static int
-lpfc_rcv_plogi(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- struct lpfc_iocbq *cmdiocb)
+lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_iocbq *cmdiocb)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
IOCB_t *icmd;
@@ -241,14 +257,14 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
int rc;
memset(&stat, 0, sizeof (struct ls_rjt));
- if (phba->hba_state <= LPFC_FLOGI) {
+ if (vport->port_state <= LPFC_FLOGI) {
/* Before responding to PLOGI, check for pt2pt mode.
* If we are pt2pt, with an outstanding FLOGI, abort
* the FLOGI and resend it first.
*/
- if (phba->fc_flag & FC_PT2PT) {
- lpfc_els_abort_flogi(phba);
- if (!(phba->fc_flag & FC_PT2PT_PLOGI)) {
+ if (vport->fc_flag & FC_PT2PT) {
+ lpfc_els_abort_flogi(phba);
+ if (!(vport->fc_flag & FC_PT2PT_PLOGI)) {
/* If the other side is supposed to initiate
* the PLOGI anyway, just ACC it now and
* move on with discovery.
@@ -257,45 +273,42 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
phba->fc_ratov = FF_DEF_RATOV;
/* Start discovery - this should just do
CLEAR_LA */
- lpfc_disc_start(phba);
- } else {
- lpfc_initial_flogi(phba);
- }
+ lpfc_disc_start(vport);
+ } else
+ lpfc_initial_flogi(vport);
} else {
stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb,
- ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
+ ndlp, NULL);
return 0;
}
}
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
lp = (uint32_t *) pcmd->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
- if ((lpfc_check_sparm(phba, ndlp, sp, CLASS3) == 0)) {
+ if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3) == 0)) {
/* Reject this request because invalid parameters */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
return 0;
}
icmd = &cmdiocb->iocb;
/* PLOGI chkparm OK */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
ndlp->nlp_rpi);
- if ((phba->cfg_fcp_class == 2) &&
- (sp->cls2.classValid)) {
+ if (phba->cfg_fcp_class == 2 && sp->cls2.classValid)
ndlp->nlp_fcp_info |= CLASS2;
- } else {
+ else
ndlp->nlp_fcp_info |= CLASS3;
- }
+
ndlp->nlp_class_sup = 0;
if (sp->cls1.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -317,35 +330,37 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
case NLP_STE_PRLI_ISSUE:
case NLP_STE_UNMAPPED_NODE:
case NLP_STE_MAPPED_NODE:
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, 0);
return 1;
}
- if ((phba->fc_flag & FC_PT2PT)
- && !(phba->fc_flag & FC_PT2PT_PLOGI)) {
+ if ((vport->fc_flag & FC_PT2PT) &&
+ !(vport->fc_flag & FC_PT2PT_PLOGI)) {
/* rcv'ed PLOGI decides what our NPortId will be */
- phba->fc_myDID = icmd->un.rcvels.parmRo;
+ vport->fc_myDID = icmd->un.rcvels.parmRo;
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mbox == NULL)
goto out;
lpfc_config_link(phba, mbox);
mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ mbox->vport = vport;
rc = lpfc_sli_issue_mbox
(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
if (rc == MBX_NOT_FINISHED) {
- mempool_free( mbox, phba->mbox_mem_pool);
+ mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
- lpfc_can_disctmo(phba);
+ lpfc_can_disctmo(vport);
}
mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (mbox == NULL)
+ if (!mbox)
goto out;
- if (lpfc_reg_login(phba, icmd->un.rcvels.remoteID,
- (uint8_t *) sp, mbox, 0)) {
- mempool_free( mbox, phba->mbox_mem_pool);
+ rc = lpfc_reg_login(phba, vport->vpi, icmd->un.rcvels.remoteID,
+ (uint8_t *) sp, mbox, 0);
+ if (rc) {
+ mempool_free(mbox, phba->mbox_mem_pool);
goto out;
}
@@ -357,7 +372,10 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
* mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox
* command issued in lpfc_cmpl_els_acc().
*/
+ mbox->vport = vport;
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
+ spin_unlock_irq(shost->host_lock);
/*
* If there is an outstanding PLOGI issued, abort it before
@@ -373,24 +391,41 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
lpfc_els_abort(phba, ndlp);
}
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
+ if ((vport->port_type == LPFC_NPIV_PORT &&
+ phba->cfg_vport_restrict_login)) {
+
+ /* In order to preserve RPIs, we want to cleanup
+ * the default RPI the firmware created to rcv
+ * this ELS request. The only way to do this is
+ * to register, then unregister the RPI.
+ */
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_RM_DFLT_RPI;
+ spin_unlock_irq(shost->host_lock);
+ stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
+ ndlp, mbox);
+ return 1;
+ }
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
return 1;
out:
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
return 0;
}
static int
-lpfc_rcv_padisc(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
+lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
struct lpfc_iocbq *cmdiocb)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_dmabuf *pcmd;
- struct serv_parm *sp;
- struct lpfc_name *pnn, *ppn;
+ struct serv_parm *sp;
+ struct lpfc_name *pnn, *ppn;
struct ls_rjt stat;
ADISC *ap;
IOCB_t *icmd;
@@ -412,13 +447,12 @@ lpfc_rcv_padisc(struct lpfc_hba * phba,
}
icmd = &cmdiocb->iocb;
- if ((icmd->ulpStatus == 0) &&
- (lpfc_check_adisc(phba, ndlp, pnn, ppn))) {
+ if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
if (cmd == ELS_CMD_ADISC) {
- lpfc_els_rsp_adisc_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
} else {
- lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp,
- NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
+ NULL, 0);
}
return 1;
}
@@ -427,55 +461,57 @@ lpfc_rcv_padisc(struct lpfc_hba * phba,
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS;
stat.un.b.vendorUnique = 0;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
/* 1 sec timeout */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return 0;
}
static int
-lpfc_rcv_logo(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- struct lpfc_iocbq *cmdiocb,
- uint32_t els_cmd)
+lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_iocbq *cmdiocb, uint32_t els_cmd)
{
- /* Put ndlp on NPR list with 1 sec timeout for plogi, ACC logo */
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */
/* Only call LOGO ACC for first LOGO, this avoids sending unnecessary
* PLOGIs during LOGO storms from a device.
*/
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_ACC;
+ spin_unlock_irq(shost->host_lock);
if (els_cmd == ELS_CMD_PRLO)
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
else
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
if (!(ndlp->nlp_type & NLP_FABRIC) ||
- (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
+ (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
/* Only try to re-login if this is NOT a Fabric Node */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
} else {
ndlp->nlp_prev_state = ndlp->nlp_state;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
/* The driver has to wait until the ACC completes before it continues
* processing the LOGO. The action will resume in
* lpfc_cmpl_els_logo_acc routine. Since part of processing includes an
@@ -485,9 +521,8 @@ lpfc_rcv_logo(struct lpfc_hba * phba,
}
static void
-lpfc_rcv_prli(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- struct lpfc_iocbq *cmdiocb)
+lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ struct lpfc_iocbq *cmdiocb)
{
struct lpfc_dmabuf *pcmd;
uint32_t *lp;
@@ -501,8 +536,7 @@ lpfc_rcv_prli(struct lpfc_hba * phba,
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
- if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) &&
- (npr->prliType == PRLI_FCP_TYPE)) {
+ if (npr->prliType == PRLI_FCP_TYPE) {
if (npr->initiatorFunc)
ndlp->nlp_type |= NLP_FCP_INITIATOR;
if (npr->targetFunc)
@@ -517,36 +551,42 @@ lpfc_rcv_prli(struct lpfc_hba * phba,
roles |= FC_RPORT_ROLE_FCP_INITIATOR;
if (ndlp->nlp_type & NLP_FCP_TARGET)
roles |= FC_RPORT_ROLE_FCP_TARGET;
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT,
+ "rport rolechg: role:x%x did:x%x flg:x%x",
+ roles, ndlp->nlp_DID, ndlp->nlp_flag);
+
fc_remote_port_rolechg(rport, roles);
}
}
static uint32_t
-lpfc_disc_set_adisc(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp)
+lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
/* Check config parameter use-adisc or FCP-2 */
- if ((phba->cfg_use_adisc == 0) &&
- !(phba->fc_flag & FC_RSCN_MODE)) {
- if (!(ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE))
- return 0;
+ if ((phba->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
+ ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_NPR_ADISC;
+ spin_unlock_irq(shost->host_lock);
+ return 1;
}
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag |= NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
- return 1;
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+ lpfc_unreg_rpi(vport, ndlp);
+ return 0;
}
static uint32_t
-lpfc_disc_illegal(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
-{
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0253 Illegal State Transition: node x%x event x%x, "
- "state x%x Data: x%x x%x\n",
- phba->brd_no,
+lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
+{
+ lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0253 Illegal State Transition: node x%x "
+ "event x%x, state x%x Data: x%x x%x\n",
+ vport->phba->brd_no, vport->vpi,
ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
ndlp->nlp_flag);
return ndlp->nlp_state;
@@ -555,151 +595,162 @@ lpfc_disc_illegal(struct lpfc_hba * phba,
/* Start of Discovery State Machine routines */
static uint32_t
-lpfc_rcv_plogi_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
+ if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_rcv_els_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- lpfc_issue_els_logo(phba, ndlp, 0);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_issue_els_logo(vport, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_ACC;
- spin_unlock_irq(phba->host->host_lock);
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_logo_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_device_rm_unused_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_rcv_plogi_plogi_issue(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
+lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
void *arg, uint32_t evt)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb = arg;
- struct lpfc_dmabuf *pcmd;
- struct serv_parm *sp;
- uint32_t *lp;
+ struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
+ uint32_t *lp = (uint32_t *) pcmd->virt;
+ struct serv_parm *sp = (struct serv_parm *) (lp + 1);
struct ls_rjt stat;
int port_cmp;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- lp = (uint32_t *) pcmd->virt;
- sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
-
memset(&stat, 0, sizeof (struct ls_rjt));
/* For a PLOGI, we only accept if our portname is less
* than the remote portname.
*/
phba->fc_stat.elsLogiCol++;
- port_cmp = memcmp(&phba->fc_portname, &sp->portName,
- sizeof (struct lpfc_name));
+ port_cmp = memcmp(&vport->fc_portname, &sp->portName,
+ sizeof(struct lpfc_name));
if (port_cmp >= 0) {
/* Reject this request because the remote node will accept
ours */
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp,
+ NULL);
} else {
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
- } /* if our portname was less */
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
+ } /* If our portname was less */
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
+ struct ls_rjt stat;
- cmdiocb = (struct lpfc_iocbq *) arg;
+ memset(&stat, 0, sizeof (struct ls_rjt));
+ stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY;
+ stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
+ return ndlp->nlp_state;
+}
- /* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp);
+static uint32_t
+lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
+{
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
+
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(vport->phba, ndlp);
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_els_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* software abort outstanding PLOGI */
lpfc_els_abort(phba, ndlp);
if (evt == NLP_EVT_RCV_LOGO) {
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
} else {
- lpfc_issue_els_logo(phba, ndlp, 0);
+ lpfc_issue_els_logo(vport, ndlp, 0);
}
- /* Put ndlp in npr list set plogi timer for 1 sec */
+ /* Put ndlp in npr state set plogi timer for 1 sec */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb, *rspiocb;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb, *rspiocb;
struct lpfc_dmabuf *pcmd, *prsp, *mp;
uint32_t *lp;
IOCB_t *irsp;
@@ -721,31 +772,26 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- prsp = list_get_first(&pcmd->list,
- struct lpfc_dmabuf,
- list);
- lp = (uint32_t *) prsp->virt;
+ prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list);
+ lp = (uint32_t *) prsp->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
- if (!lpfc_check_sparm(phba, ndlp, sp, CLASS3))
+ if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
goto out;
/* PLOGI chkparm OK */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_ELS,
- "%d:0121 PLOGI chkparm OK "
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (%d):0121 PLOGI chkparm OK "
"Data: x%x x%x x%x x%x\n",
- phba->brd_no,
+ phba->brd_no, vport->vpi,
ndlp->nlp_DID, ndlp->nlp_state,
ndlp->nlp_flag, ndlp->nlp_rpi);
- if ((phba->cfg_fcp_class == 2) &&
- (sp->cls2.classValid)) {
+ if (phba->cfg_fcp_class == 2 && (sp->cls2.classValid))
ndlp->nlp_fcp_info |= CLASS2;
- } else {
+ else
ndlp->nlp_fcp_info |= CLASS3;
- }
+
ndlp->nlp_class_sup = 0;
if (sp->cls1.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -756,16 +802,23 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
if (sp->cls4.classValid)
ndlp->nlp_class_sup |= FC_COS_CLASS4;
ndlp->nlp_maxframe =
- ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) |
- sp->cmn.bbRcvSizeLsb;
+ ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
- if (!(mbox = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL)))
+ mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!mbox) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0133 PLOGI: no memory for reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
goto out;
+ }
- lpfc_unreg_rpi(phba, ndlp);
- if (lpfc_reg_login(phba, irsp->un.elsreq64.remoteID, (uint8_t *) sp,
- mbox, 0) == 0) {
+ lpfc_unreg_rpi(vport, ndlp);
+
+ if (lpfc_reg_login(phba, vport->vpi, irsp->un.elsreq64.remoteID,
+ (uint8_t *) sp, mbox, 0) == 0) {
switch (ndlp->nlp_DID) {
case NameServer_DID:
mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login;
@@ -777,68 +830,104 @@ lpfc_cmpl_plogi_plogi_issue(struct lpfc_hba * phba,
mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
}
mbox->context2 = lpfc_nlp_get(ndlp);
+ mbox->vport = vport;
if (lpfc_sli_issue_mbox(phba, mbox,
(MBX_NOWAIT | MBX_STOP_IOCB))
!= MBX_NOT_FINISHED) {
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_REG_LOGIN_ISSUE);
+ lpfc_nlp_set_state(vport, ndlp,
+ NLP_STE_REG_LOGIN_ISSUE);
return ndlp->nlp_state;
}
lpfc_nlp_put(ndlp);
- mp = (struct lpfc_dmabuf *)mbox->context1;
+ mp = (struct lpfc_dmabuf *) mbox->context1;
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
mempool_free(mbox, phba->mbox_mem_pool);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0134 PLOGI: cannot issue reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
} else {
mempool_free(mbox, phba->mbox_mem_pool);
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0135 PLOGI: cannot format reg_login "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vport->vpi,
+ ndlp->nlp_DID, ndlp->nlp_state,
+ ndlp->nlp_flag, ndlp->nlp_rpi);
}
- out:
+out:
+ if (ndlp->nlp_DID == NameServer_DID) {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0261 Cannot Register NameServer login\n",
+ phba->brd_no, vport->vpi);
+ }
+
/* Free this node since the driver cannot login or has the wrong
sparm */
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_device_rm_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
- }
- else {
+ } else {
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp);
+ lpfc_els_abort(vport->phba, ndlp);
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
static uint32_t
-lpfc_device_recov_plogi_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_plogi_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
/* software abort outstanding PLOGI */
lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb;
/* software abort outstanding ADISC */
@@ -846,34 +935,31 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_hba * phba,
cmdiocb = (struct lpfc_iocbq *) arg;
- if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
+ if (lpfc_rcv_plogi(vport, ndlp, cmdiocb))
return ndlp->nlp_state;
- }
+
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_logo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
@@ -881,42 +967,43 @@ lpfc_rcv_logo_adisc_issue(struct lpfc_hba * phba,
/* software abort outstanding ADISC */
lpfc_els_abort(phba, ndlp);
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_padisc_adisc_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prlo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
/* Treat like rcv logo */
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
ADISC *ap;
@@ -928,101 +1015,112 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if ((irsp->ulpStatus) ||
- (!lpfc_check_adisc(phba, ndlp, &ap->nodeName, &ap->portName))) {
+ (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) {
/* 1 sec timeout */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
- memset(&ndlp->nlp_nodename, 0, sizeof (struct lpfc_name));
- memset(&ndlp->nlp_portname, 0, sizeof (struct lpfc_name));
+ memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name));
+ memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name));
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ lpfc_unreg_rpi(vport, ndlp);
return ndlp->nlp_state;
}
if (ndlp->nlp_type & NLP_FCP_TARGET) {
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
} else {
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_rm_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
- }
- else {
+ } else {
/* software abort outstanding ADISC */
- lpfc_els_abort(phba, ndlp);
+ lpfc_els_abort(vport->phba, ndlp);
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
static uint32_t
-lpfc_device_recov_adisc_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_adisc_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
/* software abort outstanding ADISC */
lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- ndlp->nlp_flag |= NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
-
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_plogi_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
LPFC_MBOXQ_t *mb;
LPFC_MBOXQ_t *nextmb;
struct lpfc_dmabuf *mp;
@@ -1033,12 +1131,13 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
if ((mb = phba->sli.mbox_active)) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
+ lpfc_nlp_put(ndlp);
mb->context2 = NULL;
mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
@@ -1047,61 +1146,61 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc_hba * phba,
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
}
+ lpfc_nlp_put(ndlp);
list_del(&mb->list);
mempool_free(mb, phba->mbox_mem_pool);
}
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_padisc_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_rcv_prlo_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp,
- void *arg, uint32_t evt)
+lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
- LPFC_MBOXQ_t *pmb;
- MAILBOX_t *mb;
- uint32_t did;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+ LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+ MAILBOX_t *mb = &pmb->mb;
+ uint32_t did = mb->un.varWords[1];
- pmb = (LPFC_MBOXQ_t *) arg;
- mb = &pmb->mb;
- did = mb->un.varWords[1];
if (mb->mbxStatus) {
/* RegLogin failed */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_DISCOVERY,
- "%d:0246 RegLogin failed Data: x%x x%x x%x\n",
- phba->brd_no,
- did, mb->mbxStatus, phba->hba_state);
+ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+ "%d (%d):0246 RegLogin failed Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, vport->vpi,
+ did, mb->mbxStatus, vport->port_state);
/*
* If RegLogin failed due to lack of HBA resources do not
@@ -1109,20 +1208,20 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
*/
if (mb->mbxStatus == MBXERR_RPI_FULL) {
ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNUSED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
return ndlp->nlp_state;
}
- /* Put ndlp in npr list set plogi timer for 1 sec */
+ /* Put ndlp in npr state set plogi timer for 1 sec */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
- lpfc_issue_els_logo(phba, ndlp, 0);
+ lpfc_issue_els_logo(vport, ndlp, 0);
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
return ndlp->nlp_state;
}
@@ -1131,91 +1230,99 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
/* Only if we are not a fabric nport do we issue PRLI */
if (!(ndlp->nlp_type & NLP_FABRIC)) {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PRLI_ISSUE);
- lpfc_issue_els_prli(phba, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
+ lpfc_issue_els_prli(vport, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_rm_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
+lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
uint32_t evt)
{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
- }
- else {
- lpfc_drop_node(phba, ndlp);
+ } else {
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
static uint32_t
-lpfc_device_recov_reglogin_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb;
cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* Software abort outstanding PRLI before sending acc */
- lpfc_els_abort(phba, ndlp);
+ lpfc_els_abort(vport->phba, ndlp);
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_padisc_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
@@ -1225,21 +1332,22 @@ lpfc_rcv_padisc_prli_issue(struct lpfc_hba * phba,
* NEXT STATE = PRLI_ISSUE
*/
static uint32_t
-lpfc_rcv_prlo_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prlo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_iocbq *cmdiocb, *rspiocb;
+ struct lpfc_hba *phba = vport->phba;
IOCB_t *irsp;
PRLI *npr;
@@ -1249,8 +1357,12 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus) {
+ if ((vport->port_type == LPFC_NPIV_PORT) &&
+ phba->cfg_vport_restrict_login) {
+ goto out;
+ }
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
return ndlp->nlp_state;
}
@@ -1266,319 +1378,329 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_hba * phba,
if (npr->Retry)
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
}
+ if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
+ (vport->port_type == LPFC_NPIV_PORT) &&
+ phba->cfg_vport_restrict_login) {
+out:
+ spin_lock_irq(shost->host_lock);
+ ndlp->nlp_flag |= NLP_TARGET_REMOVE;
+ spin_unlock_irq(shost->host_lock);
+ lpfc_issue_els_logo(vport, ndlp, 0);
+
+ ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
+ return ndlp->nlp_state;
+ }
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_MAPPED_NODE);
+ if (ndlp->nlp_type & NLP_FCP_TARGET)
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
+ else
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
return ndlp->nlp_state;
}
/*! lpfc_device_rm_prli_issue
- *
- * \pre
- * \post
- * \param phba
- * \param ndlp
- * \param arg
- * \param evt
- * \return uint32_t
- *
- * \b Description:
- * This routine is envoked when we a request to remove a nport we are in the
- * process of PRLIing. We should software abort outstanding prli, unreg
- * login, send a logout. We will change node state to UNUSED_NODE, put it
- * on plogi list so it can be freed when LOGO completes.
- *
- */
+ *
+ * \pre
+ * \post
+ * \param phba
+ * \param ndlp
+ * \param arg
+ * \param evt
+ * \return uint32_t
+ *
+ * \b Description:
+ * This routine is envoked when we a request to remove a nport we are in the
+ * process of PRLIing. We should software abort outstanding prli, unreg
+ * login, send a logout. We will change node state to UNUSED_NODE, put it
+ * on plogi list so it can be freed when LOGO completes.
+ *
+ */
+
static uint32_t
-lpfc_device_rm_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- if(ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
- }
- else {
+ } else {
/* software abort outstanding PLOGI */
- lpfc_els_abort(phba, ndlp);
+ lpfc_els_abort(vport->phba, ndlp);
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
/*! lpfc_device_recov_prli_issue
- *
- * \pre
- * \post
- * \param phba
- * \param ndlp
- * \param arg
- * \param evt
- * \return uint32_t
- *
- * \b Description:
- * The routine is envoked when the state of a device is unknown, like
- * during a link down. We should remove the nodelist entry from the
- * unmapped list, issue a UNREG_LOGIN, do a software abort of the
- * outstanding PRLI command, then free the node entry.
- */
+ *
+ * \pre
+ * \post
+ * \param phba
+ * \param ndlp
+ * \param arg
+ * \param evt
+ * \return uint32_t
+ *
+ * \b Description:
+ * The routine is envoked when the state of a device is unknown, like
+ * during a link down. We should remove the nodelist entry from the
+ * unmapped list, issue a UNREG_LOGIN, do a software abort of the
+ * outstanding PRLI command, then free the node entry.
+ */
static uint32_t
-lpfc_device_recov_prli_issue(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_recov_prli_issue(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_hba *phba = vport->phba;
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
/* software abort outstanding PRLI */
lpfc_els_abort(phba, ndlp);
ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_prli(phba, ndlp, cmdiocb);
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_rcv_prli(vport, ndlp, cmdiocb);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_padisc_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_els_rsp_acc(phba, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_recov_unmap_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_device_recov_unmap_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- lpfc_disc_set_adisc(phba, ndlp);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_plogi_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_plogi(phba, ndlp, cmdiocb);
+ lpfc_rcv_plogi(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_els_rsp_prli_acc(phba, cmdiocb, ndlp);
+ lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_logo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_padisc_mapped_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* flush the target */
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
- ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
- spin_unlock_irq(phba->host->host_lock);
+ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
/* Treat like rcv logo */
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_PRLO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_device_recov_mapped_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_mapped_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg,
+ uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE);
- spin_lock_irq(phba->host->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
- lpfc_disc_set_adisc(phba, ndlp);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_disc_set_adisc(vport, ndlp);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_plogi_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
/* Ignore PLOGI if we have an outstanding LOGO */
- if (ndlp->nlp_flag & NLP_LOGO_SND) {
+ if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) {
return ndlp->nlp_state;
}
- if (lpfc_rcv_plogi(phba, ndlp, cmdiocb)) {
- spin_lock_irq(phba->host->host_lock);
+ if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
}
/* send PLOGI immediately, move to PLOGI issue state */
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prli_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
- struct ls_rjt stat;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
+ struct ls_rjt stat;
memset(&stat, 0, sizeof (struct ls_rjt));
stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
- lpfc_els_rsp_reject(phba, stat.un.lsRjtError, cmdiocb, ndlp);
+ lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
if (ndlp->nlp_flag & NLP_NPR_ADISC) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, 0);
+ spin_unlock_irq(shost->host_lock);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_logo_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- cmdiocb = (struct lpfc_iocbq *) arg;
-
- lpfc_rcv_logo(phba, ndlp, cmdiocb, ELS_CMD_LOGO);
+ lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- lpfc_rcv_padisc(phba, ndlp, cmdiocb);
+ lpfc_rcv_padisc(vport, ndlp, cmdiocb);
/*
* Do not start discovery if discovery is about to start
@@ -1586,53 +1708,52 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
* here will affect the counting of discovery threads.
*/
if (!(ndlp->nlp_flag & NLP_DELAY_TMO) &&
- !(ndlp->nlp_flag & NLP_NPR_2B_DISC)){
+ !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) {
if (ndlp->nlp_flag & NLP_NPR_ADISC) {
+ ndlp->nlp_flag &= ~NLP_NPR_ADISC;
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_ADISC_ISSUE);
- lpfc_issue_els_adisc(phba, ndlp, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE);
+ lpfc_issue_els_adisc(vport, ndlp, 0);
} else {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
- lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE);
- lpfc_issue_els_plogi(phba, ndlp->nlp_DID, 0);
+ lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE);
+ lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0);
}
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_rcv_prlo_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- struct lpfc_iocbq *cmdiocb;
-
- cmdiocb = (struct lpfc_iocbq *) arg;
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+ struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_LOGO_ACC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
- lpfc_els_rsp_acc(phba, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
- if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+ if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) {
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_DELAY_TMO;
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
ndlp->nlp_last_elscmd = ELS_CMD_PLOGI;
} else {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
@@ -1642,15 +1763,15 @@ lpfc_cmpl_plogi_npr_node(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
@@ -1660,25 +1781,24 @@ lpfc_cmpl_prli_npr_node(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_logo_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- lpfc_unreg_rpi(phba, ndlp);
+ lpfc_unreg_rpi(vport, ndlp);
/* This routine does nothing, just return the current state */
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
struct lpfc_iocbq *cmdiocb, *rspiocb;
IOCB_t *irsp;
@@ -1688,28 +1808,25 @@ lpfc_cmpl_adisc_npr_node(struct lpfc_hba * phba,
irsp = &rspiocb->iocb;
if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
return ndlp->nlp_state;
}
static uint32_t
-lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport,
+ struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- LPFC_MBOXQ_t *pmb;
- MAILBOX_t *mb;
-
- pmb = (LPFC_MBOXQ_t *) arg;
- mb = &pmb->mb;
+ LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+ MAILBOX_t *mb = &pmb->mb;
if (!mb->mbxStatus)
ndlp->nlp_rpi = mb->un.varWords[0];
else {
if (ndlp->nlp_flag & NLP_NODEV_REMOVE) {
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
}
@@ -1717,28 +1834,38 @@ lpfc_cmpl_reglogin_npr_node(struct lpfc_hba * phba,
}
static uint32_t
-lpfc_device_rm_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
if (ndlp->nlp_flag & NLP_NPR_2B_DISC) {
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag |= NLP_NODEV_REMOVE;
+ spin_unlock_irq(shost->host_lock);
return ndlp->nlp_state;
}
- lpfc_drop_node(phba, ndlp);
+ lpfc_drop_node(vport, ndlp);
return NLP_STE_FREED_NODE;
}
static uint32_t
-lpfc_device_recov_npr_node(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg,
- uint32_t evt)
+lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
- spin_lock_irq(phba->host->host_lock);
+ struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
+ /* Don't do anything that will mess up processing of the
+ * previous RSCN.
+ */
+ if (vport->fc_flag & FC_RSCN_DEFERRED)
+ return ndlp->nlp_state;
+
+ spin_lock_irq(shost->host_lock);
ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(shost->host_lock);
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
- lpfc_cancel_retry_delay_tmo(phba, ndlp);
+ lpfc_cancel_retry_delay_tmo(vport, ndlp);
}
return ndlp->nlp_state;
}
@@ -1801,7 +1928,7 @@ lpfc_device_recov_npr_node(struct lpfc_hba * phba,
*/
static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
- (struct lpfc_hba *, struct lpfc_nodelist *, void *, uint32_t) = {
+ (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t) = {
/* Action routine Event Current State */
lpfc_rcv_plogi_unused_node, /* RCV_PLOGI UNUSED_NODE */
lpfc_rcv_els_unused_node, /* RCV_PRLI */
@@ -1818,7 +1945,7 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
lpfc_disc_illegal, /* DEVICE_RECOVERY */
lpfc_rcv_plogi_plogi_issue, /* RCV_PLOGI PLOGI_ISSUE */
- lpfc_rcv_els_plogi_issue, /* RCV_PRLI */
+ lpfc_rcv_prli_plogi_issue, /* RCV_PRLI */
lpfc_rcv_logo_plogi_issue, /* RCV_LOGO */
lpfc_rcv_els_plogi_issue, /* RCV_ADISC */
lpfc_rcv_els_plogi_issue, /* RCV_PDISC */
@@ -1917,35 +2044,41 @@ static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT])
};
int
-lpfc_disc_state_machine(struct lpfc_hba * phba,
- struct lpfc_nodelist * ndlp, void *arg, uint32_t evt)
+lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
+ void *arg, uint32_t evt)
{
+ struct lpfc_hba *phba = vport->phba;
uint32_t cur_state, rc;
- uint32_t(*func) (struct lpfc_hba *, struct lpfc_nodelist *, void *,
+ uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
uint32_t);
lpfc_nlp_get(ndlp);
cur_state = ndlp->nlp_state;
/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0211 DSM in event x%x on NPort x%x in state %d "
- "Data: x%x\n",
- phba->brd_no,
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0211 DSM in event x%x on NPort x%x in "
+ "state %d Data: x%x\n",
+ phba->brd_no, vport->vpi,
evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
+ "DSM in: evt:%d ste:%d did:x%x",
+ evt, cur_state, ndlp->nlp_DID);
+
func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt];
- rc = (func) (phba, ndlp, arg, evt);
+ rc = (func) (vport, ndlp, arg, evt);
/* DSM out state <rc> on NPort <nlp_DID> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_DISCOVERY,
- "%d:0212 DSM out state %d on NPort x%x Data: x%x\n",
- phba->brd_no,
- rc, ndlp->nlp_DID, ndlp->nlp_flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
+ "%d (%d):0212 DSM out state %d on NPort x%x "
+ "Data: x%x\n",
+ phba->brd_no, vport->vpi,
+ rc, ndlp->nlp_DID, ndlp->nlp_flag);
+
+ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
+ "DSM out: ste:%d did:x%x flg:x%x",
+ rc, ndlp->nlp_DID, ndlp->nlp_flag);
lpfc_nlp_put(ndlp);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 9a12d05e99e4..8f45bbc42126 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -37,10 +37,158 @@
#include "lpfc.h"
#include "lpfc_logmsg.h"
#include "lpfc_crtn.h"
+#include "lpfc_vport.h"
#define LPFC_RESET_WAIT 2
#define LPFC_ABORT_WAIT 2
+/*
+ * This function is called with no lock held when there is a resource
+ * error in driver or in firmware.
+ */
+void
+lpfc_adjust_queue_depth(struct lpfc_hba *phba)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ atomic_inc(&phba->num_rsrc_err);
+ phba->last_rsrc_error_time = jiffies;
+
+ if ((phba->last_ramp_down_time + QUEUE_RAMP_DOWN_INTERVAL) > jiffies) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
+
+ phba->last_ramp_down_time = jiffies;
+
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ spin_lock_irqsave(&phba->pport->work_port_lock, flags);
+ if ((phba->pport->work_port_events &
+ WORKER_RAMP_DOWN_QUEUE) == 0) {
+ phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE;
+ }
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ return;
+}
+
+/*
+ * This function is called with no lock held when there is a successful
+ * SCSI command completion.
+ */
+static inline void
+lpfc_rampup_queue_depth(struct lpfc_hba *phba,
+ struct scsi_device *sdev)
+{
+ unsigned long flags;
+ atomic_inc(&phba->num_cmd_success);
+
+ if (phba->cfg_lun_queue_depth <= sdev->queue_depth)
+ return;
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) ||
+ ((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) {
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+ return;
+ }
+
+ phba->last_ramp_up_time = jiffies;
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ spin_lock_irqsave(&phba->pport->work_port_lock, flags);
+ if ((phba->pport->work_port_events &
+ WORKER_RAMP_UP_QUEUE) == 0) {
+ phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE;
+ }
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, flags);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ if (phba->work_wait)
+ wake_up(phba->work_wait);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+}
+
+void
+lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct Scsi_Host *host;
+ struct scsi_device *sdev;
+ unsigned long new_queue_depth;
+ unsigned long num_rsrc_err, num_cmd_success;
+
+ num_rsrc_err = atomic_read(&phba->num_rsrc_err);
+ num_cmd_success = atomic_read(&phba->num_cmd_success);
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ host = lpfc_shost_from_vport(vport);
+ if (!scsi_host_get(host))
+ continue;
+
+ spin_unlock_irq(&phba->hbalock);
+
+ shost_for_each_device(sdev, host) {
+ new_queue_depth = sdev->queue_depth * num_rsrc_err /
+ (num_rsrc_err + num_cmd_success);
+ if (!new_queue_depth)
+ new_queue_depth = sdev->queue_depth - 1;
+ else
+ new_queue_depth =
+ sdev->queue_depth - new_queue_depth;
+
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ new_queue_depth);
+ else
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+ new_queue_depth);
+ }
+ spin_lock_irq(&phba->hbalock);
+ scsi_host_put(host);
+ }
+ spin_unlock_irq(&phba->hbalock);
+ atomic_set(&phba->num_rsrc_err, 0);
+ atomic_set(&phba->num_cmd_success, 0);
+}
+
+void
+lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
+{
+ struct lpfc_vport *vport;
+ struct Scsi_Host *host;
+ struct scsi_device *sdev;
+
+ spin_lock_irq(&phba->hbalock);
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ host = lpfc_shost_from_vport(vport);
+ if (!scsi_host_get(host))
+ continue;
+
+ spin_unlock_irq(&phba->hbalock);
+ shost_for_each_device(sdev, host) {
+ if (sdev->ordered_tags)
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ sdev->queue_depth+1);
+ else
+ scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
+ sdev->queue_depth+1);
+ }
+ spin_lock_irq(&phba->hbalock);
+ scsi_host_put(host);
+ }
+ spin_unlock_irq(&phba->hbalock);
+ atomic_set(&phba->num_rsrc_err, 0);
+ atomic_set(&phba->num_cmd_success, 0);
+}
/*
* This routine allocates a scsi buffer, which contains all the necessary
@@ -51,8 +199,9 @@
* and the BPL BDE is setup in the IOCB.
*/
static struct lpfc_scsi_buf *
-lpfc_new_scsi_buf(struct lpfc_hba * phba)
+lpfc_new_scsi_buf(struct lpfc_vport *vport)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_scsi_buf *psb;
struct ulp_bde64 *bpl;
IOCB_t *iocb;
@@ -63,7 +212,6 @@ lpfc_new_scsi_buf(struct lpfc_hba * phba)
if (!psb)
return NULL;
memset(psb, 0, sizeof (struct lpfc_scsi_buf));
- psb->scsi_hba = phba;
/*
* Get memory from the pci pool to map the virt space to pci bus space
@@ -155,7 +303,7 @@ lpfc_get_scsi_buf(struct lpfc_hba * phba)
}
static void
-lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb)
{
unsigned long iflag = 0;
@@ -166,7 +314,7 @@ lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
}
static int
-lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
+lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
{
struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
struct scatterlist *sgel = NULL;
@@ -175,8 +323,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
dma_addr_t physaddr;
uint32_t i, num_bde = 0;
- int datadir = scsi_cmnd->sc_data_direction;
- int dma_error;
+ int nseg, datadir = scsi_cmnd->sc_data_direction;
/*
* There are three possibilities here - use scatter-gather segment, use
@@ -185,26 +332,26 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
* data bde entry.
*/
bpl += 2;
- if (scsi_cmnd->use_sg) {
+ if (scsi_sg_count(scsi_cmnd)) {
/*
* The driver stores the segment count returned from pci_map_sg
* because this a count of dma-mappings used to map the use_sg
* pages. They are not guaranteed to be the same for those
* architectures that implement an IOMMU.
*/
- sgel = (struct scatterlist *)scsi_cmnd->request_buffer;
- lpfc_cmd->seg_cnt = dma_map_sg(&phba->pcidev->dev, sgel,
- scsi_cmnd->use_sg, datadir);
- if (lpfc_cmd->seg_cnt == 0)
+
+ nseg = dma_map_sg(&phba->pcidev->dev, scsi_sglist(scsi_cmnd),
+ scsi_sg_count(scsi_cmnd), datadir);
+ if (unlikely(!nseg))
return 1;
+ lpfc_cmd->seg_cnt = nseg;
if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) {
printk(KERN_ERR "%s: Too many sg segments from "
"dma_map_sg. Config %d, seg_cnt %d",
__FUNCTION__, phba->cfg_sg_seg_cnt,
lpfc_cmd->seg_cnt);
- dma_unmap_sg(&phba->pcidev->dev, sgel,
- lpfc_cmd->seg_cnt, datadir);
+ scsi_dma_unmap(scsi_cmnd);
return 1;
}
@@ -214,7 +361,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
* single scsi command. Just run through the seg_cnt and format
* the bde's.
*/
- for (i = 0; i < lpfc_cmd->seg_cnt; i++) {
+ scsi_for_each_sg(scsi_cmnd, sgel, nseg, i) {
physaddr = sg_dma_address(sgel);
bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr));
bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
@@ -225,34 +372,8 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
bpl->tus.f.bdeFlags = BUFF_USE_RCV;
bpl->tus.w = le32_to_cpu(bpl->tus.w);
bpl++;
- sgel++;
num_bde++;
}
- } else if (scsi_cmnd->request_buffer && scsi_cmnd->request_bufflen) {
- physaddr = dma_map_single(&phba->pcidev->dev,
- scsi_cmnd->request_buffer,
- scsi_cmnd->request_bufflen,
- datadir);
- dma_error = dma_mapping_error(physaddr);
- if (dma_error) {
- lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0718 Unable to dma_map_single "
- "request_buffer: x%x\n",
- phba->brd_no, dma_error);
- return 1;
- }
-
- lpfc_cmd->nonsg_phys = physaddr;
- bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr));
- bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
- bpl->tus.f.bdeSize = scsi_cmnd->request_bufflen;
- if (datadir == DMA_TO_DEVICE)
- bpl->tus.f.bdeFlags = 0;
- else
- bpl->tus.f.bdeFlags = BUFF_USE_RCV;
- bpl->tus.w = le32_to_cpu(bpl->tus.w);
- num_bde = 1;
- bpl++;
}
/*
@@ -266,7 +387,7 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
(num_bde * sizeof (struct ulp_bde64));
iocb_cmd->ulpBdeCount = 1;
iocb_cmd->ulpLe = 1;
- fcp_cmnd->fcpDl = be32_to_cpu(scsi_cmnd->request_bufflen);
+ fcp_cmnd->fcpDl = be32_to_cpu(scsi_bufflen(scsi_cmnd));
return 0;
}
@@ -279,26 +400,20 @@ lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
* a request buffer, but did not request use_sg. There is a third
* case, but it does not require resource deallocation.
*/
- if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
- dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
- psb->seg_cnt, psb->pCmd->sc_data_direction);
- } else {
- if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
- dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
- psb->pCmd->request_bufflen,
- psb->pCmd->sc_data_direction);
- }
- }
+ if (psb->seg_cnt > 0)
+ scsi_dma_unmap(psb->pCmd);
}
static void
-lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
+lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+ struct lpfc_iocbq *rsp_iocb)
{
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
- struct lpfc_hba *phba = lpfc_cmd->scsi_hba;
+ struct lpfc_hba *phba = vport->phba;
uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
+ uint32_t vpi = vport->vpi;
uint32_t resp_info = fcprsp->rspStatus2;
uint32_t scsi_status = fcprsp->rspStatus3;
uint32_t *lp;
@@ -331,9 +446,9 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
logit = LOG_FCP;
lpfc_printf_log(phba, KERN_WARNING, logit,
- "%d:0730 FCP command x%x failed: x%x SNS x%x x%x "
+ "%d (%d):0730 FCP command x%x failed: x%x SNS x%x x%x "
"Data: x%x x%x x%x x%x x%x\n",
- phba->brd_no, cmnd->cmnd[0], scsi_status,
+ phba->brd_no, vpi, cmnd->cmnd[0], scsi_status,
be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
be32_to_cpu(fcprsp->rspResId),
be32_to_cpu(fcprsp->rspSnsLen),
@@ -349,15 +464,16 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
}
}
- cmnd->resid = 0;
+ scsi_set_resid(cmnd, 0);
if (resp_info & RESID_UNDER) {
- cmnd->resid = be32_to_cpu(fcprsp->rspResId);
+ scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0716 FCP Read Underrun, expected %d, "
- "residual %d Data: x%x x%x x%x\n", phba->brd_no,
- be32_to_cpu(fcpcmd->fcpDl), cmnd->resid,
- fcpi_parm, cmnd->cmnd[0], cmnd->underflow);
+ "%d (%d):0716 FCP Read Underrun, expected %d, "
+ "residual %d Data: x%x x%x x%x\n",
+ phba->brd_no, vpi, be32_to_cpu(fcpcmd->fcpDl),
+ scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
+ cmnd->underflow);
/*
* If there is an under run check if under run reported by
@@ -366,15 +482,16 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
*/
if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
fcpi_parm &&
- (cmnd->resid != fcpi_parm)) {
+ (scsi_get_resid(cmnd) != fcpi_parm)) {
lpfc_printf_log(phba, KERN_WARNING,
- LOG_FCP | LOG_FCP_ERROR,
- "%d:0735 FCP Read Check Error and Underrun "
- "Data: x%x x%x x%x x%x\n", phba->brd_no,
- be32_to_cpu(fcpcmd->fcpDl),
- cmnd->resid,
- fcpi_parm, cmnd->cmnd[0]);
- cmnd->resid = cmnd->request_bufflen;
+ LOG_FCP | LOG_FCP_ERROR,
+ "%d (%d):0735 FCP Read Check Error "
+ "and Underrun Data: x%x x%x x%x x%x\n",
+ phba->brd_no, vpi,
+ be32_to_cpu(fcpcmd->fcpDl),
+ scsi_get_resid(cmnd), fcpi_parm,
+ cmnd->cmnd[0]);
+ scsi_set_resid(cmnd, scsi_bufflen(cmnd));
host_status = DID_ERROR;
}
/*
@@ -385,22 +502,23 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
*/
if (!(resp_info & SNS_LEN_VALID) &&
(scsi_status == SAM_STAT_GOOD) &&
- (cmnd->request_bufflen - cmnd->resid) < cmnd->underflow) {
+ (scsi_bufflen(cmnd) - scsi_get_resid(cmnd)
+ < cmnd->underflow)) {
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0717 FCP command x%x residual "
+ "%d (%d):0717 FCP command x%x residual "
"underrun converted to error "
- "Data: x%x x%x x%x\n", phba->brd_no,
- cmnd->cmnd[0], cmnd->request_bufflen,
- cmnd->resid, cmnd->underflow);
-
+ "Data: x%x x%x x%x\n",
+ phba->brd_no, vpi, cmnd->cmnd[0],
+ scsi_bufflen(cmnd),
+ scsi_get_resid(cmnd), cmnd->underflow);
host_status = DID_ERROR;
}
} else if (resp_info & RESID_OVER) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0720 FCP command x%x residual "
+ "%d (%d):0720 FCP command x%x residual "
"overrun error. Data: x%x x%x \n",
- phba->brd_no, cmnd->cmnd[0],
- cmnd->request_bufflen, cmnd->resid);
+ phba->brd_no, vpi, cmnd->cmnd[0],
+ scsi_bufflen(cmnd), scsi_get_resid(cmnd));
host_status = DID_ERROR;
/*
@@ -410,13 +528,14 @@ lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb)
} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
- "%d:0734 FCP Read Check Error Data: "
- "x%x x%x x%x x%x\n", phba->brd_no,
- be32_to_cpu(fcpcmd->fcpDl),
- be32_to_cpu(fcprsp->rspResId),
- fcpi_parm, cmnd->cmnd[0]);
+ "%d (%d):0734 FCP Read Check Error Data: "
+ "x%x x%x x%x x%x\n",
+ phba->brd_no, vpi,
+ be32_to_cpu(fcpcmd->fcpDl),
+ be32_to_cpu(fcprsp->rspResId),
+ fcpi_parm, cmnd->cmnd[0]);
host_status = DID_ERROR;
- cmnd->resid = cmnd->request_bufflen;
+ scsi_set_resid(cmnd, scsi_bufflen(cmnd));
}
out:
@@ -429,9 +548,13 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
{
struct lpfc_scsi_buf *lpfc_cmd =
(struct lpfc_scsi_buf *) pIocbIn->context1;
+ struct lpfc_vport *vport = pIocbIn->vport;
struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
struct lpfc_nodelist *pnode = rdata->pnode;
struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
+ uint32_t vpi = (lpfc_cmd->cur_iocbq.vport
+ ? lpfc_cmd->cur_iocbq.vport->vpi
+ : 0);
int result;
struct scsi_device *sdev, *tmp_sdev;
int depth = 0;
@@ -447,22 +570,31 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
lpfc_cmd->status = IOSTAT_DEFAULT;
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0729 FCP cmd x%x failed <%d/%d> status: "
- "x%x result: x%x Data: x%x x%x\n",
- phba->brd_no, cmd->cmnd[0], cmd->device->id,
- cmd->device->lun, lpfc_cmd->status,
- lpfc_cmd->result, pIocbOut->iocb.ulpContext,
+ "%d (%d):0729 FCP cmd x%x failed <%d/%d> "
+ "status: x%x result: x%x Data: x%x x%x\n",
+ phba->brd_no, vpi, cmd->cmnd[0],
+ cmd->device ? cmd->device->id : 0xffff,
+ cmd->device ? cmd->device->lun : 0xffff,
+ lpfc_cmd->status, lpfc_cmd->result,
+ pIocbOut->iocb.ulpContext,
lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
switch (lpfc_cmd->status) {
case IOSTAT_FCP_RSP_ERROR:
/* Call FCP RSP handler to determine result */
- lpfc_handle_fcp_err(lpfc_cmd,pIocbOut);
+ lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut);
break;
case IOSTAT_NPORT_BSY:
case IOSTAT_FABRIC_BSY:
cmd->result = ScsiResult(DID_BUS_BUSY, 0);
break;
+ case IOSTAT_LOCAL_REJECT:
+ if (lpfc_cmd->result == RJT_UNAVAIL_PERM ||
+ lpfc_cmd->result == IOERR_NO_RESOURCES ||
+ lpfc_cmd->result == RJT_LOGIN_REQUIRED) {
+ cmd->result = ScsiResult(DID_REQUEUE, 0);
+ break;
+ } /* else: fall through */
default:
cmd->result = ScsiResult(DID_ERROR, 0);
break;
@@ -479,11 +611,12 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
uint32_t *lp = (uint32_t *)cmd->sense_buffer;
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0710 Iodone <%d/%d> cmd %p, error x%x "
- "SNS x%x x%x Data: x%x x%x\n",
- phba->brd_no, cmd->device->id,
+ "%d (%d):0710 Iodone <%d/%d> cmd %p, error "
+ "x%x SNS x%x x%x Data: x%x x%x\n",
+ phba->brd_no, vpi, cmd->device->id,
cmd->device->lun, cmd, cmd->result,
- *lp, *(lp + 3), cmd->retries, cmd->resid);
+ *lp, *(lp + 3), cmd->retries,
+ scsi_get_resid(cmd));
}
result = cmd->result;
@@ -496,6 +629,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
return;
}
+
+ if (!result)
+ lpfc_rampup_queue_depth(phba, sdev);
+
if (!result && pnode != NULL &&
((jiffies - pnode->last_ramp_up_time) >
LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
@@ -534,7 +671,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
tmp_sdev->queue_depth - 1);
}
/*
- * The queue depth cannot be lowered any more.
+ * The queue depth cannot be lowered any more.
* Modify the returned error code to store
* the final depth value set by
* scsi_track_queue_full.
@@ -544,8 +681,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
if (depth) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0711 detected queue full - lun queue depth "
- " adjusted to %d.\n", phba->brd_no, depth);
+ "%d (%d):0711 detected queue full - "
+ "lun queue depth adjusted to %d.\n",
+ phba->brd_no, vpi, depth);
}
}
@@ -553,9 +691,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
static void
-lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
- struct lpfc_nodelist *pnode)
+lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
+ struct lpfc_nodelist *pnode)
{
+ struct lpfc_hba *phba = vport->phba;
struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd;
struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd;
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
@@ -592,7 +731,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
* bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first
* data bde entry.
*/
- if (scsi_cmnd->use_sg) {
+ if (scsi_sg_count(scsi_cmnd)) {
if (datadir == DMA_TO_DEVICE) {
iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
iocb_cmd->un.fcpi.fcpi_parm = 0;
@@ -602,23 +741,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
} else {
iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR;
iocb_cmd->ulpPU = PARM_READ_CHECK;
- iocb_cmd->un.fcpi.fcpi_parm =
- scsi_cmnd->request_bufflen;
- fcp_cmnd->fcpCntl3 = READ_DATA;
- phba->fc4InputRequests++;
- }
- } else if (scsi_cmnd->request_buffer && scsi_cmnd->request_bufflen) {
- if (datadir == DMA_TO_DEVICE) {
- iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR;
- iocb_cmd->un.fcpi.fcpi_parm = 0;
- iocb_cmd->ulpPU = 0;
- fcp_cmnd->fcpCntl3 = WRITE_DATA;
- phba->fc4OutputRequests++;
- } else {
- iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR;
- iocb_cmd->ulpPU = PARM_READ_CHECK;
- iocb_cmd->un.fcpi.fcpi_parm =
- scsi_cmnd->request_bufflen;
+ iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd);
fcp_cmnd->fcpCntl3 = READ_DATA;
phba->fc4InputRequests++;
}
@@ -642,15 +765,15 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
piocbq->context1 = lpfc_cmd;
piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl;
piocbq->iocb.ulpTimeout = lpfc_cmd->timeout;
+ piocbq->vport = vport;
}
static int
-lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
+lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport,
struct lpfc_scsi_buf *lpfc_cmd,
unsigned int lun,
uint8_t task_mgmt_cmd)
{
- struct lpfc_sli *psli;
struct lpfc_iocbq *piocbq;
IOCB_t *piocb;
struct fcp_cmnd *fcp_cmnd;
@@ -661,8 +784,9 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
return 0;
}
- psli = &phba->sli;
piocbq = &(lpfc_cmd->cur_iocbq);
+ piocbq->vport = vport;
+
piocb = &piocbq->iocb;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
@@ -688,7 +812,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
piocb->ulpTimeout = lpfc_cmd->timeout;
}
- return (1);
+ return 1;
}
static void
@@ -704,10 +828,11 @@ lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba,
}
static int
-lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
+lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport,
unsigned tgt_id, unsigned int lun,
struct lpfc_rport_data *rdata)
{
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
@@ -716,12 +841,11 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
return FAILED;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
+ ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun,
FCP_TARGET_RESET);
if (!ret)
return FAILED;
- lpfc_cmd->scsi_hba = phba;
iocbq = &lpfc_cmd->cur_iocbq;
iocbqrsp = lpfc_sli_get_iocbq(phba);
@@ -730,10 +854,10 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
/* Issue Target Reset to TGT <num> */
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0702 Issue Target Reset to TGT %d "
+ "%d (%d):0702 Issue Target Reset to TGT %d "
"Data: x%x x%x\n",
- phba->brd_no, tgt_id, rdata->pnode->nlp_rpi,
- rdata->pnode->nlp_flag);
+ phba->brd_no, vport->vpi, tgt_id,
+ rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
ret = lpfc_sli_issue_iocb_wait(phba,
&phba->sli.ring[phba->sli.fcp_ring],
@@ -758,7 +882,8 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
const char *
lpfc_info(struct Scsi_Host *host)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) host->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
int len;
static char lpfcinfobuf[384];
@@ -800,26 +925,22 @@ void lpfc_poll_start_timer(struct lpfc_hba * phba)
void lpfc_poll_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)ptr;
- unsigned long iflag;
-
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
lpfc_sli_poll_fcp_ring (phba);
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_poll_rearm_timer(phba);
}
-
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
}
static int
lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
{
- struct lpfc_hba *phba =
- (struct lpfc_hba *) cmnd->device->host->hostdata;
- struct lpfc_sli *psli = &phba->sli;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
struct lpfc_nodelist *ndlp = rdata->pnode;
struct lpfc_scsi_buf *lpfc_cmd;
@@ -840,11 +961,14 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
cmnd->result = ScsiResult(DID_BUS_BUSY, 0);
goto out_fail_command;
}
- lpfc_cmd = lpfc_get_scsi_buf (phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba);
if (lpfc_cmd == NULL) {
+ lpfc_adjust_queue_depth(phba);
+
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0707 driver's buffer pool is empty, "
- "IO busied\n", phba->brd_no);
+ "%d (%d):0707 driver's buffer pool is empty, "
+ "IO busied\n",
+ phba->brd_no, vport->vpi);
goto out_host_busy;
}
@@ -862,10 +986,10 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
if (err)
goto out_host_busy_free_buf;
- lpfc_scsi_prep_cmnd(phba, lpfc_cmd, ndlp);
+ lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp);
err = lpfc_sli_issue_iocb(phba, &phba->sli.ring[psli->fcp_ring],
- &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
+ &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB);
if (err)
goto out_host_busy_free_buf;
@@ -907,8 +1031,9 @@ lpfc_block_error_handler(struct scsi_cmnd *cmnd)
static int
lpfc_abort_handler(struct scsi_cmnd *cmnd)
{
- struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_sli_ring *pring = &phba->sli.ring[phba->sli.fcp_ring];
struct lpfc_iocbq *iocb;
struct lpfc_iocbq *abtsiocb;
@@ -918,8 +1043,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
int ret = SUCCESS;
lpfc_block_error_handler(cmnd);
- spin_lock_irq(shost->host_lock);
-
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
BUG_ON(!lpfc_cmd);
@@ -956,12 +1079,13 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
icmd->ulpLe = 1;
icmd->ulpClass = cmd->ulpClass;
- if (phba->hba_state >= LPFC_LINK_UP)
+ if (lpfc_is_link_up(phba))
icmd->ulpCommand = CMD_ABORT_XRI_CN;
else
icmd->ulpCommand = CMD_CLOSE_XRI_CN;
abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl;
+ abtsiocb->vport = vport;
if (lpfc_sli_issue_iocb(phba, pring, abtsiocb, 0) == IOCB_ERROR) {
lpfc_sli_release_iocbq(phba, abtsiocb);
ret = FAILED;
@@ -977,9 +1101,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
if (phba->cfg_poll & DISABLE_FCP_RING_INT)
lpfc_sli_poll_fcp_ring (phba);
- spin_unlock_irq(phba->host->host_lock);
- schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ);
- spin_lock_irq(phba->host->host_lock);
+ schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
if (++loop_count
> (2 * phba->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
break;
@@ -988,30 +1110,30 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
if (lpfc_cmd->pCmd == cmnd) {
ret = FAILED;
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0748 abort handler timed out waiting for "
- "abort to complete: ret %#x, ID %d, LUN %d, "
- "snum %#lx\n",
- phba->brd_no, ret, cmnd->device->id,
- cmnd->device->lun, cmnd->serial_number);
+ "%d (%d):0748 abort handler timed out waiting "
+ "for abort to complete: ret %#x, ID %d, "
+ "LUN %d, snum %#lx\n",
+ phba->brd_no, vport->vpi, ret,
+ cmnd->device->id, cmnd->device->lun,
+ cmnd->serial_number);
}
out:
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0749 SCSI Layer I/O Abort Request "
+ "%d (%d):0749 SCSI Layer I/O Abort Request "
"Status x%x ID %d LUN %d snum %#lx\n",
- phba->brd_no, ret, cmnd->device->id,
+ phba->brd_no, vport->vpi, ret, cmnd->device->id,
cmnd->device->lun, cmnd->serial_number);
- spin_unlock_irq(shost->host_lock);
-
return ret;
}
static int
lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
{
- struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_scsi_buf *lpfc_cmd;
struct lpfc_iocbq *iocbq, *iocbqrsp;
struct lpfc_rport_data *rdata = cmnd->device->hostdata;
@@ -1022,28 +1144,26 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
int cnt, loopcnt;
lpfc_block_error_handler(cmnd);
- spin_lock_irq(shost->host_lock);
loopcnt = 0;
/*
* If target is not in a MAPPED state, delay the reset until
* target is rediscovered or devloss timeout expires.
*/
- while ( 1 ) {
+ while (1) {
if (!pnode)
goto out;
if (pnode->nlp_state != NLP_STE_MAPPED_NODE) {
- spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- spin_lock_irq(phba->host->host_lock);
loopcnt++;
rdata = cmnd->device->hostdata;
if (!rdata ||
(loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0721 LUN Reset rport failure:"
- " cnt x%x rdata x%p\n",
- phba->brd_no, loopcnt, rdata);
+ "%d (%d):0721 LUN Reset rport "
+ "failure: cnt x%x rdata x%p\n",
+ phba->brd_no, vport->vpi,
+ loopcnt, rdata);
goto out;
}
pnode = rdata->pnode;
@@ -1054,15 +1174,14 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
break;
}
- lpfc_cmd = lpfc_get_scsi_buf (phba);
+ lpfc_cmd = lpfc_get_scsi_buf(phba);
if (lpfc_cmd == NULL)
goto out;
lpfc_cmd->timeout = 60;
- lpfc_cmd->scsi_hba = phba;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
+ ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, cmnd->device->lun,
FCP_TARGET_RESET);
if (!ret)
goto out_free_scsi_buf;
@@ -1075,8 +1194,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
goto out_free_scsi_buf;
lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
- "%d:0703 Issue target reset to TGT %d LUN %d rpi x%x "
- "nlp_flag x%x\n", phba->brd_no, cmnd->device->id,
+ "%d (%d):0703 Issue target reset to TGT %d LUN %d "
+ "rpi x%x nlp_flag x%x\n",
+ phba->brd_no, vport->vpi, cmnd->device->id,
cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
iocb_status = lpfc_sli_issue_iocb_wait(phba,
@@ -1111,9 +1231,7 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
0, LPFC_CTX_LUN);
loopcnt = 0;
while(cnt) {
- spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
- spin_lock_irq(phba->host->host_lock);
if (++loopcnt
> (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
@@ -1127,8 +1245,9 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd)
if (cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0719 device reset I/O flush failure: cnt x%x\n",
- phba->brd_no, cnt);
+ "%d (%d):0719 device reset I/O flush failure: "
+ "cnt x%x\n",
+ phba->brd_no, vport->vpi, cnt);
ret = FAILED;
}
@@ -1137,21 +1256,21 @@ out_free_scsi_buf:
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0713 SCSI layer issued device reset (%d, %d) "
+ "%d (%d):0713 SCSI layer issued device reset (%d, %d) "
"return x%x status x%x result x%x\n",
- phba->brd_no, cmnd->device->id, cmnd->device->lun,
- ret, cmd_status, cmd_result);
+ phba->brd_no, vport->vpi, cmnd->device->id,
+ cmnd->device->lun, ret, cmd_status, cmd_result);
out:
- spin_unlock_irq(shost->host_lock);
return ret;
}
static int
lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
{
- struct Scsi_Host *shost = cmnd->device->host;
- struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_nodelist *ndlp = NULL;
int match;
int ret = FAILED, i, err_count = 0;
@@ -1159,7 +1278,6 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
struct lpfc_scsi_buf * lpfc_cmd;
lpfc_block_error_handler(cmnd);
- spin_lock_irq(shost->host_lock);
lpfc_cmd = lpfc_get_scsi_buf(phba);
if (lpfc_cmd == NULL)
@@ -1167,7 +1285,6 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
/* The lpfc_cmd storage is reused. Set all loop invariants. */
lpfc_cmd->timeout = 60;
- lpfc_cmd->scsi_hba = phba;
/*
* Since the driver manages a single bus device, reset all
@@ -1177,7 +1294,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
for (i = 0; i < LPFC_MAX_TARGET; i++) {
/* Search for mapped node by target ID */
match = 0;
- list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) {
+ spin_lock_irq(shost->host_lock);
+ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
if (ndlp->nlp_state == NLP_STE_MAPPED_NODE &&
i == ndlp->nlp_sid &&
ndlp->rport) {
@@ -1185,15 +1303,18 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
break;
}
}
+ spin_unlock_irq(shost->host_lock);
if (!match)
continue;
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, i, cmnd->device->lun,
+ ret = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i,
+ cmnd->device->lun,
ndlp->rport->dd_data);
if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0700 Bus Reset on target %d failed\n",
- phba->brd_no, i);
+ "%d (%d):0700 Bus Reset on target %d "
+ "failed\n",
+ phba->brd_no, vport->vpi, i);
err_count++;
break;
}
@@ -1219,9 +1340,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
0, 0, 0, LPFC_CTX_HOST);
loopcnt = 0;
while(cnt) {
- spin_unlock_irq(phba->host->host_lock);
schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
- spin_lock_irq(phba->host->host_lock);
if (++loopcnt
> (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
@@ -1234,25 +1353,24 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd)
if (cnt) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0715 Bus Reset I/O flush failure: cnt x%x left x%x\n",
- phba->brd_no, cnt, i);
+ "%d (%d):0715 Bus Reset I/O flush failure: "
+ "cnt x%x left x%x\n",
+ phba->brd_no, vport->vpi, cnt, i);
ret = FAILED;
}
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_FCP,
- "%d:0714 SCSI layer issued Bus Reset Data: x%x\n",
- phba->brd_no, ret);
+ lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
+ "%d (%d):0714 SCSI layer issued Bus Reset Data: x%x\n",
+ phba->brd_no, vport->vpi, ret);
out:
- spin_unlock_irq(shost->host_lock);
return ret;
}
static int
lpfc_slave_alloc(struct scsi_device *sdev)
{
- struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata;
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
struct lpfc_scsi_buf *scsi_buf = NULL;
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
uint32_t total = 0, i;
@@ -1273,27 +1391,35 @@ lpfc_slave_alloc(struct scsi_device *sdev)
*/
total = phba->total_scsi_bufs;
num_to_alloc = phba->cfg_lun_queue_depth + 2;
- if (total >= phba->cfg_hba_queue_depth) {
+
+ /* Allow some exchanges to be available always to complete discovery */
+ if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0704 At limitation of %d preallocated "
- "command buffers\n", phba->brd_no, total);
+ "%d (%d):0704 At limitation of %d "
+ "preallocated command buffers\n",
+ phba->brd_no, vport->vpi, total);
return 0;
- } else if (total + num_to_alloc > phba->cfg_hba_queue_depth) {
+
+ /* Allow some exchanges to be available always to complete discovery */
+ } else if (total + num_to_alloc >
+ phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
- "%d:0705 Allocation request of %d command "
- "buffers will exceed max of %d. Reducing "
- "allocation request to %d.\n", phba->brd_no,
- num_to_alloc, phba->cfg_hba_queue_depth,
+ "%d (%d):0705 Allocation request of %d "
+ "command buffers will exceed max of %d. "
+ "Reducing allocation request to %d.\n",
+ phba->brd_no, vport->vpi, num_to_alloc,
+ phba->cfg_hba_queue_depth,
(phba->cfg_hba_queue_depth - total));
num_to_alloc = phba->cfg_hba_queue_depth - total;
}
for (i = 0; i < num_to_alloc; i++) {
- scsi_buf = lpfc_new_scsi_buf(phba);
+ scsi_buf = lpfc_new_scsi_buf(vport);
if (!scsi_buf) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0706 Failed to allocate command "
- "buffer\n", phba->brd_no);
+ "%d (%d):0706 Failed to allocate "
+ "command buffer\n",
+ phba->brd_no, vport->vpi);
break;
}
@@ -1308,8 +1434,9 @@ lpfc_slave_alloc(struct scsi_device *sdev)
static int
lpfc_slave_configure(struct scsi_device *sdev)
{
- struct lpfc_hba *phba = (struct lpfc_hba *) sdev->host->hostdata;
- struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
+ struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
+ struct lpfc_hba *phba = vport->phba;
+ struct fc_rport *rport = starget_to_rport(sdev->sdev_target);
if (sdev->tagged_supported)
scsi_activate_tcq(sdev, phba->cfg_lun_queue_depth);
@@ -1340,6 +1467,7 @@ lpfc_slave_destroy(struct scsi_device *sdev)
return;
}
+
struct scsi_host_template lpfc_template = {
.module = THIS_MODULE,
.name = LPFC_DRIVER_NAME,
@@ -1352,11 +1480,10 @@ struct scsi_host_template lpfc_template = {
.slave_configure = lpfc_slave_configure,
.slave_destroy = lpfc_slave_destroy,
.scan_finished = lpfc_scan_finished,
- .scan_start = lpfc_scan_start,
.this_id = -1,
.sg_tablesize = LPFC_SG_SEG_CNT,
.cmd_per_lun = LPFC_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
- .shost_attrs = lpfc_host_attrs,
+ .shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
};
diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h
index cdcd2535803f..31787bb6d53e 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.h
+++ b/drivers/scsi/lpfc/lpfc_scsi.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2004-2005 Emulex. All rights reserved. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
* www.emulex.com *
* *
@@ -110,7 +110,6 @@ struct fcp_cmnd {
struct lpfc_scsi_buf {
struct list_head list;
struct scsi_cmnd *pCmd;
- struct lpfc_hba *scsi_hba;
struct lpfc_rport_data *rdata;
uint32_t timeout;
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index a1e721459e2b..f4d5a6b00fde 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -38,23 +38,25 @@
#include "lpfc_crtn.h"
#include "lpfc_logmsg.h"
#include "lpfc_compat.h"
+#include "lpfc_debugfs.h"
/*
* Define macro to log: Mailbox command x%x cannot issue Data
* This allows multiple uses of lpfc_msgBlk0311
* w/o perturbing log msg utility.
*/
-#define LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag) \
+#define LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag) \
lpfc_printf_log(phba, \
KERN_INFO, \
LOG_MBOX | LOG_SLI, \
- "%d:0311 Mailbox command x%x cannot issue " \
- "Data: x%x x%x x%x\n", \
+ "%d (%d):0311 Mailbox command x%x cannot " \
+ "issue Data: x%x x%x x%x\n", \
phba->brd_no, \
- mb->mbxCommand, \
- phba->hba_state, \
+ pmbox->vport ? pmbox->vport->vpi : 0, \
+ pmbox->mb.mbxCommand, \
+ phba->pport->port_state, \
psli->sli_flag, \
- flag);
+ flag)
/* There are only four IOCB completion types. */
@@ -65,8 +67,26 @@ typedef enum _lpfc_iocb_type {
LPFC_ABORT_IOCB
} lpfc_iocb_type;
-struct lpfc_iocbq *
-lpfc_sli_get_iocbq(struct lpfc_hba * phba)
+ /* SLI-2/SLI-3 provide different sized iocbs. Given a pointer
+ * to the start of the ring, and the slot number of the
+ * desired iocb entry, calc a pointer to that entry.
+ */
+static inline IOCB_t *
+lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+ return (IOCB_t *) (((char *) pring->cmdringaddr) +
+ pring->cmdidx * phba->iocb_cmd_size);
+}
+
+static inline IOCB_t *
+lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
+{
+ return (IOCB_t *) (((char *) pring->rspringaddr) +
+ pring->rspidx * phba->iocb_rsp_size);
+}
+
+static struct lpfc_iocbq *
+__lpfc_sli_get_iocbq(struct lpfc_hba *phba)
{
struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list;
struct lpfc_iocbq * iocbq = NULL;
@@ -75,10 +95,22 @@ lpfc_sli_get_iocbq(struct lpfc_hba * phba)
return iocbq;
}
+struct lpfc_iocbq *
+lpfc_sli_get_iocbq(struct lpfc_hba *phba)
+{
+ struct lpfc_iocbq * iocbq = NULL;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ iocbq = __lpfc_sli_get_iocbq(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+ return iocbq;
+}
+
void
-lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
+__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
- size_t start_clean = (size_t)(&((struct lpfc_iocbq *)NULL)->iocb);
+ size_t start_clean = offsetof(struct lpfc_iocbq, iocb);
/*
* Clean all volatile data fields, preserve iotag and node struct.
@@ -87,6 +119,19 @@ lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
list_add_tail(&iocbq->list, &phba->lpfc_iocb_list);
}
+void
+lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
+{
+ unsigned long iflags;
+
+ /*
+ * Clean all volatile data fields, preserve iotag and node struct.
+ */
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ __lpfc_sli_release_iocbq(phba, iocbq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
/*
* Translate the iocb command to an iocb command type used to decide the final
* disposition of each completed IOCB.
@@ -155,6 +200,9 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
case CMD_RCV_ELS_REQ_CX:
case CMD_RCV_SEQUENCE64_CX:
case CMD_RCV_ELS_REQ64_CX:
+ case CMD_IOCB_RCV_SEQ64_CX:
+ case CMD_IOCB_RCV_ELS64_CX:
+ case CMD_IOCB_RCV_CONT64_CX:
type = LPFC_UNSOL_IOCB;
break;
default:
@@ -166,73 +214,77 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd)
}
static int
-lpfc_sli_ring_map(struct lpfc_hba * phba, LPFC_MBOXQ_t *pmb)
+lpfc_sli_ring_map(struct lpfc_hba *phba)
{
struct lpfc_sli *psli = &phba->sli;
- MAILBOX_t *pmbox = &pmb->mb;
- int i, rc;
+ LPFC_MBOXQ_t *pmb;
+ MAILBOX_t *pmbox;
+ int i, rc, ret = 0;
+ pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb)
+ return -ENOMEM;
+ pmbox = &pmb->mb;
+ phba->link_state = LPFC_INIT_MBX_CMDS;
for (i = 0; i < psli->num_rings; i++) {
- phba->hba_state = LPFC_INIT_MBX_CMDS;
lpfc_config_ring(phba, i, pmb);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
- "%d:0446 Adapter failed to init, "
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0446 Adapter failed to init (%d), "
"mbxCmd x%x CFG_RING, mbxStatus x%x, "
"ring %d\n",
- phba->brd_no,
+ phba->brd_no, rc,
pmbox->mbxCommand,
pmbox->mbxStatus,
i);
- phba->hba_state = LPFC_HBA_ERROR;
- return -ENXIO;
+ phba->link_state = LPFC_HBA_ERROR;
+ ret = -ENXIO;
+ break;
}
}
- return 0;
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return ret;
}
static int
-lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb)
+lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb)
{
list_add_tail(&piocb->list, &pring->txcmplq);
pring->txcmplq_cnt++;
- if (unlikely(pring->ringno == LPFC_ELS_RING))
- mod_timer(&phba->els_tmofunc,
- jiffies + HZ * (phba->fc_ratov << 1));
+ if ((unlikely(pring->ringno == LPFC_ELS_RING)) &&
+ (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
+ (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
+ if (!piocb->vport)
+ BUG();
+ else
+ mod_timer(&piocb->vport->els_tmofunc,
+ jiffies + HZ * (phba->fc_ratov << 1));
+ }
- return (0);
+
+ return 0;
}
static struct lpfc_iocbq *
-lpfc_sli_ringtx_get(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
- struct list_head *dlp;
struct lpfc_iocbq *cmd_iocb;
- dlp = &pring->txq;
- cmd_iocb = NULL;
- list_remove_head((&pring->txq), cmd_iocb,
- struct lpfc_iocbq,
- list);
- if (cmd_iocb) {
- /* If the first ptr is not equal to the list header,
- * deque the IOCBQ_t and return it.
- */
+ list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list);
+ if (cmd_iocb != NULL)
pring->txq_cnt--;
- }
- return (cmd_iocb);
+ return cmd_iocb;
}
static IOCB_t *
lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
uint32_t max_cmd_idx = pring->numCiocb;
- IOCB_t *iocb = NULL;
if ((pring->next_cmdidx == pring->cmdidx) &&
(++pring->next_cmdidx >= max_cmd_idx))
@@ -249,15 +301,17 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
phba->brd_no, pring->ringno,
pring->local_getidx, max_cmd_idx);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/*
* All error attention handlers are posted to
* worker thread
*/
phba->work_ha |= HA_ERATT;
phba->work_hs = HS_FFER3;
+
+ /* hbalock should already be held */
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
return NULL;
}
@@ -266,39 +320,34 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
return NULL;
}
- iocb = IOCB_ENTRY(pring->cmdringaddr, pring->cmdidx);
-
- return iocb;
+ return lpfc_cmd_iocb(phba, pring);
}
uint16_t
-lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
+lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq)
{
- struct lpfc_iocbq ** new_arr;
- struct lpfc_iocbq ** old_arr;
+ struct lpfc_iocbq **new_arr;
+ struct lpfc_iocbq **old_arr;
size_t new_len;
struct lpfc_sli *psli = &phba->sli;
uint16_t iotag;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
iotag = psli->last_iotag;
if(++iotag < psli->iocbq_lookup_len) {
psli->last_iotag = iotag;
psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
iocbq->iotag = iotag;
return iotag;
- }
- else if (psli->iocbq_lookup_len < (0xffff
+ } else if (psli->iocbq_lookup_len < (0xffff
- LPFC_IOCBQ_LOOKUP_INCREMENT)) {
new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT;
- spin_unlock_irq(phba->host->host_lock);
- new_arr = kmalloc(new_len * sizeof (struct lpfc_iocbq *),
+ spin_unlock_irq(&phba->hbalock);
+ new_arr = kzalloc(new_len * sizeof (struct lpfc_iocbq *),
GFP_KERNEL);
if (new_arr) {
- memset((char *)new_arr, 0,
- new_len * sizeof (struct lpfc_iocbq *));
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
old_arr = psli->iocbq_lookup;
if (new_len <= psli->iocbq_lookup_len) {
/* highly unprobable case */
@@ -307,11 +356,11 @@ lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
if(++iotag < psli->iocbq_lookup_len) {
psli->last_iotag = iotag;
psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
iocbq->iotag = iotag;
return iotag;
}
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
if (psli->iocbq_lookup)
@@ -322,13 +371,13 @@ lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
psli->iocbq_lookup_len = new_len;
psli->last_iotag = iotag;
psli->iocbq_lookup[iotag] = iocbq;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
iocbq->iotag = iotag;
kfree(old_arr);
return iotag;
}
} else
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
"%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
@@ -349,7 +398,7 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/*
* Issue iocb command to adapter
*/
- lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, sizeof (IOCB_t));
+ lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, phba->iocb_cmd_size);
wmb();
pring->stats.iocb_cmd++;
@@ -361,20 +410,18 @@ lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (nextiocb->iocb_cmpl)
lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb);
else
- lpfc_sli_release_iocbq(phba, nextiocb);
+ __lpfc_sli_release_iocbq(phba, nextiocb);
/*
* Let the HBA know what IOCB slot will be the next one the
* driver will put a command into.
*/
pring->cmdidx = pring->next_cmdidx;
- writel(pring->cmdidx, phba->MBslimaddr
- + (SLIMOFF + (pring->ringno * 2)) * 4);
+ writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx);
}
static void
-lpfc_sli_update_full_ring(struct lpfc_hba * phba,
- struct lpfc_sli_ring *pring)
+lpfc_sli_update_full_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
int ringno = pring->ringno;
@@ -393,8 +440,7 @@ lpfc_sli_update_full_ring(struct lpfc_hba * phba,
}
static void
-lpfc_sli_update_ring(struct lpfc_hba * phba,
- struct lpfc_sli_ring *pring)
+lpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
int ringno = pring->ringno;
@@ -407,7 +453,7 @@ lpfc_sli_update_ring(struct lpfc_hba * phba,
}
static void
-lpfc_sli_resume_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
+lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
IOCB_t *iocb;
struct lpfc_iocbq *nextiocb;
@@ -420,7 +466,7 @@ lpfc_sli_resume_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
* (d) IOCB processing is not blocked by the outstanding mbox command.
*/
if (pring->txq_cnt &&
- (phba->hba_state > LPFC_LINK_DOWN) &&
+ lpfc_is_link_up(phba) &&
(pring->ringno != phba->sli.fcp_ring ||
phba->sli.sli_flag & LPFC_PROCESS_LA) &&
!(pring->flag & LPFC_STOP_IOCB_MBX)) {
@@ -440,11 +486,15 @@ lpfc_sli_resume_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring)
/* lpfc_sli_turn_on_ring is only called by lpfc_sli_handle_mb_event below */
static void
-lpfc_sli_turn_on_ring(struct lpfc_hba * phba, int ringno)
+lpfc_sli_turn_on_ring(struct lpfc_hba *phba, int ringno)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[ringno] :
+ &phba->slim2p->mbx.us.s2.port[ringno];
+ unsigned long iflags;
/* If the ring is active, flag it */
+ spin_lock_irqsave(&phba->hbalock, iflags);
if (phba->sli.ring[ringno].cmdringaddr) {
if (phba->sli.ring[ringno].flag & LPFC_STOP_IOCB_MBX) {
phba->sli.ring[ringno].flag &= ~LPFC_STOP_IOCB_MBX;
@@ -453,11 +503,176 @@ lpfc_sli_turn_on_ring(struct lpfc_hba * phba, int ringno)
*/
phba->sli.ring[ringno].local_getidx
= le32_to_cpu(pgp->cmdGetInx);
- spin_lock_irq(phba->host->host_lock);
lpfc_sli_resume_iocb(phba, &phba->sli.ring[ringno]);
- spin_unlock_irq(phba->host->host_lock);
}
}
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+}
+
+struct lpfc_hbq_entry *
+lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno)
+{
+ struct hbq_s *hbqp = &phba->hbqs[hbqno];
+
+ if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx &&
+ ++hbqp->next_hbqPutIdx >= hbqp->entry_count)
+ hbqp->next_hbqPutIdx = 0;
+
+ if (unlikely(hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)) {
+ uint32_t raw_index = phba->hbq_get[hbqno];
+ uint32_t getidx = le32_to_cpu(raw_index);
+
+ hbqp->local_hbqGetIdx = getidx;
+
+ if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_SLI | LOG_VPORT,
+ "%d:1802 HBQ %d: local_hbqGetIdx "
+ "%u is > than hbqp->entry_count %u\n",
+ phba->brd_no, hbqno,
+ hbqp->local_hbqGetIdx,
+ hbqp->entry_count);
+
+ phba->link_state = LPFC_HBA_ERROR;
+ return NULL;
+ }
+
+ if (hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)
+ return NULL;
+ }
+
+ return (struct lpfc_hbq_entry *) phba->hbqslimp.virt + hbqp->hbqPutIdx;
+}
+
+void
+lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba)
+{
+ struct lpfc_dmabuf *dmabuf, *next_dmabuf;
+ struct hbq_dmabuf *hbq_buf;
+
+ /* Return all memory used by all HBQs */
+ list_for_each_entry_safe(dmabuf, next_dmabuf,
+ &phba->hbq_buffer_list, list) {
+ hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
+ list_del(&hbq_buf->dbuf.list);
+ lpfc_hbq_free(phba, hbq_buf->dbuf.virt, hbq_buf->dbuf.phys);
+ kfree(hbq_buf);
+ }
+}
+
+static void
+lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
+ struct hbq_dmabuf *hbq_buf)
+{
+ struct lpfc_hbq_entry *hbqe;
+ dma_addr_t physaddr = hbq_buf->dbuf.phys;
+
+ /* Get next HBQ entry slot to use */
+ hbqe = lpfc_sli_next_hbq_slot(phba, hbqno);
+ if (hbqe) {
+ struct hbq_s *hbqp = &phba->hbqs[hbqno];
+
+ hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
+ hbqe->bde.addrLow = le32_to_cpu(putPaddrLow(physaddr));
+ hbqe->bde.tus.f.bdeSize = FCELSSIZE;
+ hbqe->bde.tus.f.bdeFlags = 0;
+ hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w);
+ hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag);
+ /* Sync SLIM */
+ hbqp->hbqPutIdx = hbqp->next_hbqPutIdx;
+ writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno);
+ /* flush */
+ readl(phba->hbq_put + hbqno);
+ list_add_tail(&hbq_buf->dbuf.list, &phba->hbq_buffer_list);
+ }
+}
+
+static struct lpfc_hbq_init lpfc_els_hbq = {
+ .rn = 1,
+ .entry_count = 200,
+ .mask_count = 0,
+ .profile = 0,
+ .ring_mask = 1 << LPFC_ELS_RING,
+ .buffer_count = 0,
+ .init_count = 20,
+ .add_count = 5,
+};
+
+static struct lpfc_hbq_init *lpfc_hbq_defs[] = {
+ &lpfc_els_hbq,
+};
+
+int
+lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
+{
+ uint32_t i, start, end;
+ struct hbq_dmabuf *hbq_buffer;
+
+ start = lpfc_hbq_defs[hbqno]->buffer_count;
+ end = count + lpfc_hbq_defs[hbqno]->buffer_count;
+ if (end > lpfc_hbq_defs[hbqno]->entry_count) {
+ end = lpfc_hbq_defs[hbqno]->entry_count;
+ }
+
+ /* Populate HBQ entries */
+ for (i = start; i < end; i++) {
+ hbq_buffer = kmalloc(sizeof(struct hbq_dmabuf),
+ GFP_KERNEL);
+ if (!hbq_buffer)
+ return 1;
+ hbq_buffer->dbuf.virt = lpfc_hbq_alloc(phba, MEM_PRI,
+ &hbq_buffer->dbuf.phys);
+ if (hbq_buffer->dbuf.virt == NULL)
+ return 1;
+ hbq_buffer->tag = (i | (hbqno << 16));
+ lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer);
+ lpfc_hbq_defs[hbqno]->buffer_count++;
+ }
+ return 0;
+}
+
+int
+lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno)
+{
+ return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
+ lpfc_hbq_defs[qno]->add_count));
+}
+
+int
+lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno)
+{
+ return(lpfc_sli_hbqbuf_fill_hbqs(phba, qno,
+ lpfc_hbq_defs[qno]->init_count));
+}
+
+struct hbq_dmabuf *
+lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag)
+{
+ struct lpfc_dmabuf *d_buf;
+ struct hbq_dmabuf *hbq_buf;
+
+ list_for_each_entry(d_buf, &phba->hbq_buffer_list, list) {
+ hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+ if ((hbq_buf->tag & 0xffff) == tag) {
+ return hbq_buf;
+ }
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
+ "%d:1803 Bad hbq tag. Data: x%x x%x\n",
+ phba->brd_no, tag,
+ lpfc_hbq_defs[tag >> 16]->buffer_count);
+ return NULL;
+}
+
+void
+lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *sp)
+{
+ uint32_t hbqno;
+
+ if (sp) {
+ hbqno = sp->tag >> 16;
+ lpfc_sli_hbq_to_firmware(phba, hbqno, sp);
+ }
}
static int
@@ -511,32 +726,38 @@ lpfc_sli_chk_mbx_command(uint8_t mbxCommand)
case MBX_FLASH_WR_ULA:
case MBX_SET_DEBUG:
case MBX_LOAD_EXP_ROM:
+ case MBX_REG_VPI:
+ case MBX_UNREG_VPI:
+ case MBX_HEARTBEAT:
ret = mbxCommand;
break;
default:
ret = MBX_SHUTDOWN;
break;
}
- return (ret);
+ return ret;
}
static void
-lpfc_sli_wake_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
+lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{
wait_queue_head_t *pdone_q;
+ unsigned long drvr_flag;
/*
* If pdone_q is empty, the driver thread gave up waiting and
* continued running.
*/
pmboxq->mbox_flag |= LPFC_MBX_WAKE;
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
pdone_q = (wait_queue_head_t *) pmboxq->context1;
if (pdone_q)
wake_up_interruptible(pdone_q);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
return;
}
void
-lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
+lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
struct lpfc_dmabuf *mp;
uint16_t rpi;
@@ -553,79 +774,64 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
* If a REG_LOGIN succeeded after node is destroyed or node
* is in re-discovery driver need to cleanup the RPI.
*/
- if (!(phba->fc_flag & FC_UNLOADING) &&
- (pmb->mb.mbxCommand == MBX_REG_LOGIN64) &&
- (!pmb->mb.mbxStatus)) {
+ if (!(phba->pport->load_flag & FC_UNLOADING) &&
+ pmb->mb.mbxCommand == MBX_REG_LOGIN64 &&
+ !pmb->mb.mbxStatus) {
rpi = pmb->mb.un.varWords[0];
- lpfc_unreg_login(phba, rpi, pmb);
- pmb->mbox_cmpl=lpfc_sli_def_mbox_cmpl;
+ lpfc_unreg_login(phba, pmb->mb.un.varRegLogin.vpi, rpi, pmb);
+ pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
if (rc != MBX_NOT_FINISHED)
return;
}
- mempool_free( pmb, phba->mbox_mem_pool);
+ mempool_free(pmb, phba->mbox_mem_pool);
return;
}
int
-lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
+lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
{
- MAILBOX_t *mbox;
MAILBOX_t *pmbox;
LPFC_MBOXQ_t *pmb;
- struct lpfc_sli *psli;
- int i, rc;
- uint32_t process_next;
-
- psli = &phba->sli;
- /* We should only get here if we are in SLI2 mode */
- if (!(phba->sli.sli_flag & LPFC_SLI2_ACTIVE)) {
- return (1);
- }
+ int rc;
+ LIST_HEAD(cmplq);
phba->sli.slistat.mbox_event++;
+ /* Get all completed mailboxe buffers into the cmplq */
+ spin_lock_irq(&phba->hbalock);
+ list_splice_init(&phba->sli.mboxq_cmpl, &cmplq);
+ spin_unlock_irq(&phba->hbalock);
+
/* Get a Mailbox buffer to setup mailbox commands for callback */
- if ((pmb = phba->sli.mbox_active)) {
- pmbox = &pmb->mb;
- mbox = &phba->slim2p->mbx;
+ do {
+ list_remove_head(&cmplq, pmb, LPFC_MBOXQ_t, list);
+ if (pmb == NULL)
+ break;
- /* First check out the status word */
- lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof (uint32_t));
+ pmbox = &pmb->mb;
- /* Sanity check to ensure the host owns the mailbox */
- if (pmbox->mbxOwner != OWN_HOST) {
- /* Lets try for a while */
- for (i = 0; i < 10240; i++) {
- /* First copy command data */
- lpfc_sli_pcimem_bcopy(mbox, pmbox,
- sizeof (uint32_t));
- if (pmbox->mbxOwner == OWN_HOST)
- goto mbout;
+ if (pmbox->mbxCommand != MBX_HEARTBEAT) {
+ if (pmb->vport) {
+ lpfc_debugfs_disc_trc(pmb->vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX cmpl vport: cmd:x%x mb:x%x x%x",
+ (uint32_t)pmbox->mbxCommand,
+ pmbox->un.varWords[0],
+ pmbox->un.varWords[1]);
+ }
+ else {
+ lpfc_debugfs_disc_trc(phba->pport,
+ LPFC_DISC_TRC_MBOX,
+ "MBOX cmpl: cmd:x%x mb:x%x x%x",
+ (uint32_t)pmbox->mbxCommand,
+ pmbox->un.varWords[0],
+ pmbox->un.varWords[1]);
}
- /* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus
- <status> */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_MBOX | LOG_SLI,
- "%d:0304 Stray Mailbox Interrupt "
- "mbxCommand x%x mbxStatus x%x\n",
- phba->brd_no,
- pmbox->mbxCommand,
- pmbox->mbxStatus);
-
- spin_lock_irq(phba->host->host_lock);
- phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
- return (1);
}
- mbout:
- del_timer_sync(&phba->sli.mbox_tmo);
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
-
/*
* It is a fatal error if unknown mbox command completion.
*/
@@ -633,51 +839,50 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
MBX_SHUTDOWN) {
/* Unknow mailbox command compl */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_MBOX | LOG_SLI,
- "%d:0323 Unknown Mailbox command %x Cmpl\n",
- phba->brd_no,
- pmbox->mbxCommand);
- phba->hba_state = LPFC_HBA_ERROR;
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "%d (%d):0323 Unknown Mailbox command "
+ "%x Cmpl\n",
+ phba->brd_no,
+ pmb->vport ? pmb->vport->vpi : 0,
+ pmbox->mbxCommand);
+ phba->link_state = LPFC_HBA_ERROR;
phba->work_hs = HS_FFER3;
lpfc_handle_eratt(phba);
- return (0);
+ continue;
}
- phba->sli.mbox_active = NULL;
if (pmbox->mbxStatus) {
phba->sli.slistat.mbox_stat_err++;
if (pmbox->mbxStatus == MBXERR_NO_RESOURCES) {
/* Mbox cmd cmpl error - RETRYing */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0305 Mbox cmd cmpl error - "
- "RETRYing Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- pmbox->mbxCommand,
- pmbox->mbxStatus,
- pmbox->un.varWords[0],
- phba->hba_state);
+ lpfc_printf_log(phba, KERN_INFO,
+ LOG_MBOX | LOG_SLI,
+ "%d (%d):0305 Mbox cmd cmpl "
+ "error - RETRYing Data: x%x "
+ "x%x x%x x%x\n",
+ phba->brd_no,
+ pmb->vport ? pmb->vport->vpi :0,
+ pmbox->mbxCommand,
+ pmbox->mbxStatus,
+ pmbox->un.varWords[0],
+ pmb->vport->port_state);
pmbox->mbxStatus = 0;
pmbox->mbxOwner = OWN_HOST;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
if (rc == MBX_SUCCESS)
- return (0);
+ continue;
}
}
/* Mailbox cmd <cmd> Cmpl <cmpl> */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0307 Mailbox cmd x%x Cmpl x%p "
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+ "%d (%d):0307 Mailbox cmd x%x Cmpl x%p "
"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n",
phba->brd_no,
+ pmb->vport ? pmb->vport->vpi : 0,
pmbox->mbxCommand,
pmb->mbox_cmpl,
*((uint32_t *) pmbox),
@@ -690,39 +895,35 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
pmbox->un.varWords[6],
pmbox->un.varWords[7]);
- if (pmb->mbox_cmpl) {
- lpfc_sli_pcimem_bcopy(mbox, pmbox, MAILBOX_CMD_SIZE);
+ if (pmb->mbox_cmpl)
pmb->mbox_cmpl(phba,pmb);
- }
- }
-
-
- do {
- process_next = 0; /* by default don't loop */
- spin_lock_irq(phba->host->host_lock);
- phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
-
- /* Process next mailbox command if there is one */
- if ((pmb = lpfc_mbox_get(phba))) {
- spin_unlock_irq(phba->host->host_lock);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if (rc == MBX_NOT_FINISHED) {
- pmb->mb.mbxStatus = MBX_NOT_FINISHED;
- pmb->mbox_cmpl(phba,pmb);
- process_next = 1;
- continue; /* loop back */
- }
- } else {
- spin_unlock_irq(phba->host->host_lock);
- /* Turn on IOCB processing */
- for (i = 0; i < phba->sli.num_rings; i++)
- lpfc_sli_turn_on_ring(phba, i);
- }
-
- } while (process_next);
+ } while (1);
+ return 0;
+}
- return (0);
+static struct lpfc_dmabuf *
+lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
+{
+ struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
+
+ hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
+ if (hbq_entry == NULL)
+ return NULL;
+ list_del(&hbq_entry->dbuf.list);
+ new_hbq_entry = kmalloc(sizeof(struct hbq_dmabuf), GFP_ATOMIC);
+ if (new_hbq_entry == NULL)
+ return &hbq_entry->dbuf;
+ new_hbq_entry->dbuf = hbq_entry->dbuf;
+ new_hbq_entry->tag = -1;
+ hbq_entry->dbuf.virt = lpfc_hbq_alloc(phba, 0, &hbq_entry->dbuf.phys);
+ if (hbq_entry->dbuf.virt == NULL) {
+ kfree(new_hbq_entry);
+ return &hbq_entry->dbuf;
+ }
+ lpfc_sli_free_hbq(phba, hbq_entry);
+ return &new_hbq_entry->dbuf;
}
+
static int
lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *saveq)
@@ -735,7 +936,9 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
match = 0;
irsp = &(saveq->iocb);
if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX)
- || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)) {
+ || (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX)
+ || (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)
+ || (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX)) {
Rctl = FC_ELS_REQ;
Type = FC_ELS_DATA;
} else {
@@ -747,13 +950,24 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* Firmware Workaround */
if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) &&
- (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX)) {
+ (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX ||
+ irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) {
Rctl = FC_ELS_REQ;
Type = FC_ELS_DATA;
w5p->hcsw.Rctl = Rctl;
w5p->hcsw.Type = Type;
}
}
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ if (irsp->ulpBdeCount != 0)
+ saveq->context2 = lpfc_sli_replace_hbqbuff(phba,
+ irsp->un.ulpWord[3]);
+ if (irsp->ulpBdeCount == 2)
+ saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
+ irsp->un.ulpWord[15]);
+ }
+
/* unSolicited Responses */
if (pring->prt[0].profile) {
if (pring->prt[0].lpfc_sli_rcv_unsol_event)
@@ -781,23 +995,21 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/* Unexpected Rctl / Type received */
/* Ring <ringno> handler: unexpected
Rctl <Rctl> Type <Type> received */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_SLI,
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
"%d:0313 Ring %d handler: unexpected Rctl x%x "
- "Type x%x received \n",
+ "Type x%x received\n",
phba->brd_no,
pring->ringno,
Rctl,
Type);
}
- return(1);
+ return 1;
}
static struct lpfc_iocbq *
-lpfc_sli_iocbq_lookup(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * prspiocb)
+lpfc_sli_iocbq_lookup(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *prspiocb)
{
struct lpfc_iocbq *cmd_iocb = NULL;
uint16_t iotag;
@@ -806,7 +1018,7 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba * phba,
if (iotag != 0 && iotag <= phba->sli.last_iotag) {
cmd_iocb = phba->sli.iocbq_lookup[iotag];
- list_del(&cmd_iocb->list);
+ list_del_init(&cmd_iocb->list);
pring->txcmplq_cnt--;
return cmd_iocb;
}
@@ -821,16 +1033,18 @@ lpfc_sli_iocbq_lookup(struct lpfc_hba * phba,
}
static int
-lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
+lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *saveq)
{
- struct lpfc_iocbq * cmdiocbp;
+ struct lpfc_iocbq *cmdiocbp;
int rc = 1;
unsigned long iflag;
/* Based on the iotag field, get the cmd IOCB from the txcmplq */
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+
if (cmdiocbp) {
if (cmdiocbp->iocb_cmpl) {
/*
@@ -846,17 +1060,8 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
saveq->iocb.un.ulpWord[4] =
IOERR_SLI_ABORTED;
}
- spin_unlock_irqrestore(phba->host->host_lock,
- iflag);
- (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
- }
- else {
- spin_unlock_irqrestore(phba->host->host_lock,
- iflag);
- (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
}
+ (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq);
} else
lpfc_sli_release_iocbq(phba, cmdiocbp);
} else {
@@ -870,29 +1075,30 @@ lpfc_sli_process_sol_iocb(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
* Ring <ringno> handler: unexpected completion IoTag
* <IoTag>
*/
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_SLI,
- "%d:0322 Ring %d handler: unexpected "
- "completion IoTag x%x Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- pring->ringno,
- saveq->iocb.ulpIoTag,
- saveq->iocb.ulpStatus,
- saveq->iocb.un.ulpWord[4],
- saveq->iocb.ulpCommand,
- saveq->iocb.ulpContext);
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "%d (%d):0322 Ring %d handler: "
+ "unexpected completion IoTag x%x "
+ "Data: x%x x%x x%x x%x\n",
+ phba->brd_no,
+ cmdiocbp->vport->vpi,
+ pring->ringno,
+ saveq->iocb.ulpIoTag,
+ saveq->iocb.ulpStatus,
+ saveq->iocb.un.ulpWord[4],
+ saveq->iocb.ulpCommand,
+ saveq->iocb.ulpContext);
}
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
return rc;
}
-static void lpfc_sli_rsp_pointers_error(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring)
+static void
+lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
/*
* Ring <ringno> handler: portRspPut <portRspPut> is bigger then
* rsp ring <portRspMax>
@@ -904,7 +1110,7 @@ static void lpfc_sli_rsp_pointers_error(struct lpfc_hba * phba,
le32_to_cpu(pgp->rspPutInx),
pring->numRiocb);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/*
* All error attention handlers are posted to
@@ -912,16 +1118,18 @@ static void lpfc_sli_rsp_pointers_error(struct lpfc_hba * phba,
*/
phba->work_ha |= HA_ERATT;
phba->work_hs = HS_FFER3;
+
+ /* hbalock should already be held */
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
return;
}
-void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
+void lpfc_sli_poll_fcp_ring(struct lpfc_hba *phba)
{
- struct lpfc_sli * psli = &phba->sli;
- struct lpfc_sli_ring * pring = &psli->ring[LPFC_FCP_RING];
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring = &psli->ring[LPFC_FCP_RING];
IOCB_t *irsp = NULL;
IOCB_t *entry = NULL;
struct lpfc_iocbq *cmdiocbq = NULL;
@@ -931,13 +1139,15 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
uint32_t portRspPut, portRspMax;
int type;
uint32_t rsp_cmpl = 0;
- void __iomem *to_slim;
uint32_t ha_copy;
+ unsigned long iflags;
pring->stats.iocb_event++;
- /* The driver assumes SLI-2 mode */
- pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
+
/*
* The next available response entry should never exceed the maximum
@@ -952,15 +1162,13 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
rmb();
while (pring->rspidx != portRspPut) {
-
- entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
-
+ entry = lpfc_resp_iocb(phba, pring);
if (++pring->rspidx >= portRspMax)
pring->rspidx = 0;
lpfc_sli_pcimem_bcopy((uint32_t *) entry,
(uint32_t *) &rspiocbq.iocb,
- sizeof (IOCB_t));
+ phba->iocb_rsp_size);
irsp = &rspiocbq.iocb;
type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK);
pring->stats.iocb_rsp++;
@@ -998,8 +1206,10 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
break;
}
+ spin_lock_irqsave(&phba->hbalock, iflags);
cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring,
&rspiocbq);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
if ((cmdiocbq) && (cmdiocbq->iocb_cmpl)) {
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
&rspiocbq);
@@ -1033,9 +1243,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
* been updated, sync the pgp->rspPutInx and fetch the new port
* response put pointer.
*/
- to_slim = phba->MBslimaddr +
- (SLIMOFF + (pring->ringno * 2) + 1) * 4;
- writeb(pring->rspidx, to_slim);
+ writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
if (pring->rspidx == portRspPut)
portRspPut = le32_to_cpu(pgp->rspPutInx);
@@ -1045,13 +1253,16 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
ha_copy >>= (LPFC_FCP_RING * 4);
if ((rsp_cmpl > 0) && (ha_copy & HA_R0RE_REQ)) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
pring->stats.iocb_rsp_full++;
status = ((CA_R0ATT | CA_R0RE_RSP) << (LPFC_FCP_RING * 4));
writel(status, phba->CAregaddr);
readl(phba->CAregaddr);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
}
if ((ha_copy & HA_R0CE_RSP) &&
(pring->flag & LPFC_CALL_RING_AVAILABLE)) {
+ spin_lock_irqsave(&phba->hbalock, iflags);
pring->flag &= ~LPFC_CALL_RING_AVAILABLE;
pring->stats.iocb_cmd_empty++;
@@ -1062,6 +1273,7 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
if ((pring->lpfc_sli_cmd_available))
(pring->lpfc_sli_cmd_available) (phba, pring);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
}
return;
@@ -1072,10 +1284,12 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
* to check it explicitly.
*/
static int
-lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, uint32_t mask)
+lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring, uint32_t mask)
{
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
IOCB_t *irsp = NULL;
IOCB_t *entry = NULL;
struct lpfc_iocbq *cmdiocbq = NULL;
@@ -1086,9 +1300,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
lpfc_iocb_type type;
unsigned long iflag;
uint32_t rsp_cmpl = 0;
- void __iomem *to_slim;
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
pring->stats.iocb_event++;
/*
@@ -1099,7 +1312,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
portRspPut = le32_to_cpu(pgp->rspPutInx);
if (unlikely(portRspPut >= portRspMax)) {
lpfc_sli_rsp_pointers_error(phba, pring);
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
return 1;
}
@@ -1110,14 +1323,15 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
* structure. The copy involves a byte-swap since the
* network byte order and pci byte orders are different.
*/
- entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
+ entry = lpfc_resp_iocb(phba, pring);
+ phba->last_completion_time = jiffies;
if (++pring->rspidx >= portRspMax)
pring->rspidx = 0;
lpfc_sli_pcimem_bcopy((uint32_t *) entry,
(uint32_t *) &rspiocbq.iocb,
- sizeof (IOCB_t));
+ phba->iocb_rsp_size);
INIT_LIST_HEAD(&(rspiocbq.list));
irsp = &rspiocbq.iocb;
@@ -1126,16 +1340,30 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
rsp_cmpl++;
if (unlikely(irsp->ulpStatus)) {
+ /*
+ * If resource errors reported from HBA, reduce
+ * queuedepths of the SCSI device.
+ */
+ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ lpfc_adjust_queue_depth(phba);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ }
+
/* Rsp ring <ringno> error: IOCB */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0336 Rsp Ring %d error: IOCB Data: "
- "x%x x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no, pring->ringno,
- irsp->un.ulpWord[0], irsp->un.ulpWord[1],
- irsp->un.ulpWord[2], irsp->un.ulpWord[3],
- irsp->un.ulpWord[4], irsp->un.ulpWord[5],
- *(((uint32_t *) irsp) + 6),
- *(((uint32_t *) irsp) + 7));
+ "%d:0336 Rsp Ring %d error: IOCB Data: "
+ "x%x x%x x%x x%x x%x x%x x%x x%x\n",
+ phba->brd_no, pring->ringno,
+ irsp->un.ulpWord[0],
+ irsp->un.ulpWord[1],
+ irsp->un.ulpWord[2],
+ irsp->un.ulpWord[3],
+ irsp->un.ulpWord[4],
+ irsp->un.ulpWord[5],
+ *(((uint32_t *) irsp) + 6),
+ *(((uint32_t *) irsp) + 7));
}
switch (type) {
@@ -1149,7 +1377,8 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"%d:0333 IOCB cmd 0x%x"
" processed. Skipping"
- " completion\n", phba->brd_no,
+ " completion\n",
+ phba->brd_no,
irsp->ulpCommand);
break;
}
@@ -1161,19 +1390,19 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
&rspiocbq);
} else {
- spin_unlock_irqrestore(
- phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock,
+ iflag);
(cmdiocbq->iocb_cmpl)(phba, cmdiocbq,
&rspiocbq);
- spin_lock_irqsave(phba->host->host_lock,
+ spin_lock_irqsave(&phba->hbalock,
iflag);
}
}
break;
case LPFC_UNSOL_IOCB:
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
break;
default:
if (irsp->ulpCommand == CMD_ADAPTER_MSG) {
@@ -1186,11 +1415,13 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
} else {
/* Unknown IOCB command */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0334 Unknown IOCB command "
- "Data: x%x, x%x x%x x%x x%x\n",
- phba->brd_no, type, irsp->ulpCommand,
- irsp->ulpStatus, irsp->ulpIoTag,
- irsp->ulpContext);
+ "%d:0334 Unknown IOCB command "
+ "Data: x%x, x%x x%x x%x x%x\n",
+ phba->brd_no, type,
+ irsp->ulpCommand,
+ irsp->ulpStatus,
+ irsp->ulpIoTag,
+ irsp->ulpContext);
}
break;
}
@@ -1201,9 +1432,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
* been updated, sync the pgp->rspPutInx and fetch the new port
* response put pointer.
*/
- to_slim = phba->MBslimaddr +
- (SLIMOFF + (pring->ringno * 2) + 1) * 4;
- writel(pring->rspidx, to_slim);
+ writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
if (pring->rspidx == portRspPut)
portRspPut = le32_to_cpu(pgp->rspPutInx);
@@ -1228,31 +1457,31 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
return rc;
}
-
int
-lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring, uint32_t mask)
+lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring, uint32_t mask)
{
+ struct lpfc_pgp *pgp = (phba->sli_rev == 3) ?
+ &phba->slim2p->mbx.us.s3_pgp.port[pring->ringno] :
+ &phba->slim2p->mbx.us.s2.port[pring->ringno];
IOCB_t *entry;
IOCB_t *irsp = NULL;
struct lpfc_iocbq *rspiocbp = NULL;
struct lpfc_iocbq *next_iocb;
struct lpfc_iocbq *cmdiocbp;
struct lpfc_iocbq *saveq;
- struct lpfc_pgp *pgp = &phba->slim2p->mbx.us.s2.port[pring->ringno];
uint8_t iocb_cmd_type;
lpfc_iocb_type type;
uint32_t status, free_saveq;
uint32_t portRspPut, portRspMax;
int rc = 1;
unsigned long iflag;
- void __iomem *to_slim;
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ spin_lock_irqsave(&phba->hbalock, iflag);
pring->stats.iocb_event++;
/*
@@ -1266,16 +1495,14 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
* Ring <ringno> handler: portRspPut <portRspPut> is bigger then
* rsp ring <portRspMax>
*/
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_SLI,
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
"%d:0303 Ring %d handler: portRspPut %d "
"is bigger then rsp ring %d\n",
- phba->brd_no,
- pring->ringno, portRspPut, portRspMax);
+ phba->brd_no, pring->ringno, portRspPut,
+ portRspMax);
- phba->hba_state = LPFC_HBA_ERROR;
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ phba->link_state = LPFC_HBA_ERROR;
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
phba->work_hs = HS_FFER3;
lpfc_handle_eratt(phba);
@@ -1298,23 +1525,24 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
* the ulpLe field is set, the entire Command has been
* received.
*/
- entry = IOCB_ENTRY(pring->rspringaddr, pring->rspidx);
- rspiocbp = lpfc_sli_get_iocbq(phba);
+ entry = lpfc_resp_iocb(phba, pring);
+
+ phba->last_completion_time = jiffies;
+ rspiocbp = __lpfc_sli_get_iocbq(phba);
if (rspiocbp == NULL) {
printk(KERN_ERR "%s: out of buffers! Failing "
"completion.\n", __FUNCTION__);
break;
}
- lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, sizeof (IOCB_t));
+ lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb,
+ phba->iocb_rsp_size);
irsp = &rspiocbp->iocb;
if (++pring->rspidx >= portRspMax)
pring->rspidx = 0;
- to_slim = phba->MBslimaddr + (SLIMOFF + (pring->ringno * 2)
- + 1) * 4;
- writel(pring->rspidx, to_slim);
+ writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
if (list_empty(&(pring->iocb_continueq))) {
list_add(&rspiocbp->list, &(pring->iocb_continueq));
@@ -1338,23 +1566,44 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
pring->stats.iocb_rsp++;
+ /*
+ * If resource errors reported from HBA, reduce
+ * queuedepths of the SCSI device.
+ */
+ if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) {
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
+ lpfc_adjust_queue_depth(phba);
+ spin_lock_irqsave(&phba->hbalock, iflag);
+ }
+
if (irsp->ulpStatus) {
/* Rsp ring <ringno> error: IOCB */
- lpfc_printf_log(phba,
- KERN_WARNING,
- LOG_SLI,
- "%d:0328 Rsp Ring %d error: IOCB Data: "
- "x%x x%x x%x x%x x%x x%x x%x x%x\n",
- phba->brd_no,
- pring->ringno,
- irsp->un.ulpWord[0],
- irsp->un.ulpWord[1],
- irsp->un.ulpWord[2],
- irsp->un.ulpWord[3],
- irsp->un.ulpWord[4],
- irsp->un.ulpWord[5],
- *(((uint32_t *) irsp) + 6),
- *(((uint32_t *) irsp) + 7));
+ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
+ "%d:0328 Rsp Ring %d error: "
+ "IOCB Data: "
+ "x%x x%x x%x x%x "
+ "x%x x%x x%x x%x "
+ "x%x x%x x%x x%x "
+ "x%x x%x x%x x%x\n",
+ phba->brd_no,
+ pring->ringno,
+ irsp->un.ulpWord[0],
+ irsp->un.ulpWord[1],
+ irsp->un.ulpWord[2],
+ irsp->un.ulpWord[3],
+ irsp->un.ulpWord[4],
+ irsp->un.ulpWord[5],
+ *(((uint32_t *) irsp) + 6),
+ *(((uint32_t *) irsp) + 7),
+ *(((uint32_t *) irsp) + 8),
+ *(((uint32_t *) irsp) + 9),
+ *(((uint32_t *) irsp) + 10),
+ *(((uint32_t *) irsp) + 11),
+ *(((uint32_t *) irsp) + 12),
+ *(((uint32_t *) irsp) + 13),
+ *(((uint32_t *) irsp) + 14),
+ *(((uint32_t *) irsp) + 15));
}
/*
@@ -1366,17 +1615,17 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK;
type = lpfc_sli_iocb_cmd_type(iocb_cmd_type);
if (type == LPFC_SOL_IOCB) {
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
iflag);
rc = lpfc_sli_process_sol_iocb(phba, pring,
- saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ saveq);
+ spin_lock_irqsave(&phba->hbalock, iflag);
} else if (type == LPFC_UNSOL_IOCB) {
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
iflag);
rc = lpfc_sli_process_unsol_iocb(phba, pring,
- saveq);
- spin_lock_irqsave(phba->host->host_lock, iflag);
+ saveq);
+ spin_lock_irqsave(&phba->hbalock, iflag);
} else if (type == LPFC_ABORT_IOCB) {
if ((irsp->ulpCommand != CMD_XRI_ABORTED_CX) &&
((cmdiocbp =
@@ -1386,15 +1635,15 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
routine */
if (cmdiocbp->iocb_cmpl) {
spin_unlock_irqrestore(
- phba->host->host_lock,
+ &phba->hbalock,
iflag);
(cmdiocbp->iocb_cmpl) (phba,
cmdiocbp, saveq);
spin_lock_irqsave(
- phba->host->host_lock,
+ &phba->hbalock,
iflag);
} else
- lpfc_sli_release_iocbq(phba,
+ __lpfc_sli_release_iocbq(phba,
cmdiocbp);
}
} else if (type == LPFC_UNKNOWN_IOCB) {
@@ -1411,32 +1660,28 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
phba->brd_no, adaptermsg);
} else {
/* Unknown IOCB command */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_SLI,
- "%d:0335 Unknown IOCB command "
- "Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- irsp->ulpCommand,
- irsp->ulpStatus,
- irsp->ulpIoTag,
- irsp->ulpContext);
+ lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
+ "%d:0335 Unknown IOCB "
+ "command Data: x%x "
+ "x%x x%x x%x\n",
+ phba->brd_no,
+ irsp->ulpCommand,
+ irsp->ulpStatus,
+ irsp->ulpIoTag,
+ irsp->ulpContext);
}
}
if (free_saveq) {
- if (!list_empty(&saveq->list)) {
- list_for_each_entry_safe(rspiocbp,
- next_iocb,
- &saveq->list,
- list) {
- list_del(&rspiocbp->list);
- lpfc_sli_release_iocbq(phba,
- rspiocbp);
- }
+ list_for_each_entry_safe(rspiocbp, next_iocb,
+ &saveq->list, list) {
+ list_del(&rspiocbp->list);
+ __lpfc_sli_release_iocbq(phba,
+ rspiocbp);
}
- lpfc_sli_release_iocbq(phba, saveq);
+ __lpfc_sli_release_iocbq(phba, saveq);
}
+ rspiocbp = NULL;
}
/*
@@ -1449,7 +1694,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
}
} /* while (pring->rspidx != portRspPut) */
- if ((rspiocbp != 0) && (mask & HA_R0RE_REQ)) {
+ if ((rspiocbp != NULL) && (mask & HA_R0RE_REQ)) {
/* At least one response entry has been freed */
pring->stats.iocb_rsp_full++;
/* SET RxRE_RSP in Chip Att register */
@@ -1470,24 +1715,25 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
return rc;
}
-int
+void
lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
{
LIST_HEAD(completions);
struct lpfc_iocbq *iocb, *next_iocb;
IOCB_t *cmd = NULL;
- int errcnt;
- errcnt = 0;
+ if (pring->ringno == LPFC_ELS_RING) {
+ lpfc_fabric_abort_hba(phba);
+ }
/* Error everything on txq and txcmplq
* First do the txq.
*/
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
list_splice_init(&pring->txq, &completions);
pring->txq_cnt = 0;
@@ -1495,26 +1741,25 @@ lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring)
list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list)
lpfc_sli_issue_abort_iotag(phba, pring, iocb);
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
while (!list_empty(&completions)) {
iocb = list_get_first(&completions, struct lpfc_iocbq, list);
cmd = &iocb->iocb;
- list_del(&iocb->list);
+ list_del_init(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
-
- return errcnt;
}
int
-lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
+lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask)
{
uint32_t status;
int i = 0;
@@ -1541,7 +1786,8 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
msleep(2500);
if (i == 15) {
- phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
+ /* Do post */
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
lpfc_sli_brdrestart(phba);
}
/* Read the HBA Host Status Register */
@@ -1550,7 +1796,7 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
/* Check to see if any errors occurred during init */
if ((status & HS_FFERM) || (i >= 20)) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
retval = 1;
}
@@ -1559,7 +1805,7 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
#define BARRIER_TEST_PATTERN (0xdeadbeef)
-void lpfc_reset_barrier(struct lpfc_hba * phba)
+void lpfc_reset_barrier(struct lpfc_hba *phba)
{
uint32_t __iomem *resp_buf;
uint32_t __iomem *mbox_buf;
@@ -1584,12 +1830,12 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
hc_copy = readl(phba->HCregaddr);
writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- phba->fc_flag |= FC_IGNORE_ERATT;
+ phba->link_flag |= LS_IGNORE_ERATT;
if (readl(phba->HAregaddr) & HA_ERATT) {
/* Clear Chip error bit */
writel(HA_ERATT, phba->HAregaddr);
- phba->stopped = 1;
+ phba->pport->stopped = 1;
}
mbox = 0;
@@ -1606,7 +1852,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
if (readl(resp_buf + 1) != ~(BARRIER_TEST_PATTERN)) {
if (phba->sli.sli_flag & LPFC_SLI2_ACTIVE ||
- phba->stopped)
+ phba->pport->stopped)
goto restore_hc;
else
goto clear_errat;
@@ -1623,17 +1869,17 @@ clear_errat:
if (readl(phba->HAregaddr) & HA_ERATT) {
writel(HA_ERATT, phba->HAregaddr);
- phba->stopped = 1;
+ phba->pport->stopped = 1;
}
restore_hc:
- phba->fc_flag &= ~FC_IGNORE_ERATT;
+ phba->link_flag &= ~LS_IGNORE_ERATT;
writel(hc_copy, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
}
int
-lpfc_sli_brdkill(struct lpfc_hba * phba)
+lpfc_sli_brdkill(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
LPFC_MBOXQ_t *pmb;
@@ -1645,26 +1891,22 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
psli = &phba->sli;
/* Kill HBA */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_SLI,
- "%d:0329 Kill HBA Data: x%x x%x\n",
- phba->brd_no,
- phba->hba_state,
- psli->sli_flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0329 Kill HBA Data: x%x x%x\n",
+ phba->brd_no, phba->pport->port_state, psli->sli_flag);
if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
GFP_KERNEL)) == 0)
return 1;
/* Disable the error attention */
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
status = readl(phba->HCregaddr);
status &= ~HC_ERINT_ENA;
writel(status, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- phba->fc_flag |= FC_IGNORE_ERATT;
- spin_unlock_irq(phba->host->host_lock);
+ phba->link_flag |= LS_IGNORE_ERATT;
+ spin_unlock_irq(&phba->hbalock);
lpfc_kill_board(phba, pmb);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -1673,9 +1915,9 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
if (retval != MBX_SUCCESS) {
if (retval != MBX_BUSY)
mempool_free(pmb, phba->mbox_mem_pool);
- spin_lock_irq(phba->host->host_lock);
- phba->fc_flag &= ~FC_IGNORE_ERATT;
- spin_unlock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
+ phba->link_flag &= ~LS_IGNORE_ERATT;
+ spin_unlock_irq(&phba->hbalock);
return 1;
}
@@ -1698,22 +1940,22 @@ lpfc_sli_brdkill(struct lpfc_hba * phba)
del_timer_sync(&psli->mbox_tmo);
if (ha_copy & HA_ERATT) {
writel(HA_ERATT, phba->HAregaddr);
- phba->stopped = 1;
+ phba->pport->stopped = 1;
}
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- phba->fc_flag &= ~FC_IGNORE_ERATT;
- spin_unlock_irq(phba->host->host_lock);
+ phba->link_flag &= ~LS_IGNORE_ERATT;
+ spin_unlock_irq(&phba->hbalock);
psli->mbox_active = NULL;
lpfc_hba_down_post(phba);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
- return (ha_copy & HA_ERATT ? 0 : 1);
+ return ha_copy & HA_ERATT ? 0 : 1;
}
int
-lpfc_sli_brdreset(struct lpfc_hba * phba)
+lpfc_sli_brdreset(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
@@ -1725,12 +1967,12 @@ lpfc_sli_brdreset(struct lpfc_hba * phba)
/* Reset HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no,
- phba->hba_state, psli->sli_flag);
+ phba->pport->port_state, psli->sli_flag);
/* perform board reset */
phba->fc_eventTag = 0;
- phba->fc_myDID = 0;
- phba->fc_prevDID = 0;
+ phba->pport->fc_myDID = 0;
+ phba->pport->fc_prevDID = 0;
/* Turn off parity checking and serr during the physical reset */
pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
@@ -1760,12 +2002,12 @@ lpfc_sli_brdreset(struct lpfc_hba * phba)
pring->missbufcnt = 0;
}
- phba->hba_state = LPFC_WARM_START;
+ phba->link_state = LPFC_WARM_START;
return 0;
}
int
-lpfc_sli_brdrestart(struct lpfc_hba * phba)
+lpfc_sli_brdrestart(struct lpfc_hba *phba)
{
MAILBOX_t *mb;
struct lpfc_sli *psli;
@@ -1773,14 +2015,14 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
volatile uint32_t word0;
void __iomem *to_slim;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
psli = &phba->sli;
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
"%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no,
- phba->hba_state, psli->sli_flag);
+ phba->pport->port_state, psli->sli_flag);
word0 = 0;
mb = (MAILBOX_t *) &word0;
@@ -1794,7 +2036,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
readl(to_slim); /* flush */
/* Only skip post after fc_ffinit is completed */
- if (phba->hba_state) {
+ if (phba->pport->port_state) {
skip_post = 1;
word0 = 1; /* This is really setting up word1 */
} else {
@@ -1806,10 +2048,10 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
readl(to_slim); /* flush */
lpfc_sli_brdreset(phba);
- phba->stopped = 0;
- phba->hba_state = LPFC_INIT_START;
+ phba->pport->stopped = 0;
+ phba->link_state = LPFC_INIT_START;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
psli->stats_start = get_seconds();
@@ -1843,14 +2085,11 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
if (i++ >= 20) {
/* Adapter failed to init, timeout, status reg
<status> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0436 Adapter failed to init, "
"timeout, status reg x%x\n",
- phba->brd_no,
- status);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->brd_no, status);
+ phba->link_state = LPFC_HBA_ERROR;
return -ETIMEDOUT;
}
@@ -1859,14 +2098,12 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
/* ERROR: During chipset initialization */
/* Adapter failed to init, chipset, status reg
<status> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0437 Adapter failed to init, "
"chipset, status reg x%x\n",
phba->brd_no,
status);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -EIO;
}
@@ -1879,7 +2116,8 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
}
if (i == 15) {
- phba->hba_state = LPFC_STATE_UNKNOWN; /* Do post */
+ /* Do post */
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
lpfc_sli_brdrestart(phba);
}
/* Read the HBA Host Status Register */
@@ -1890,14 +2128,12 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
if (status & HS_FFERM) {
/* ERROR: During chipset initialization */
/* Adapter failed to init, chipset, status reg <status> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0438 Adapter failed to init, chipset, "
"status reg x%x\n",
phba->brd_no,
status);
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -EIO;
}
@@ -1911,80 +2147,253 @@ lpfc_sli_chipset_init(struct lpfc_hba *phba)
return 0;
}
+static int
+lpfc_sli_hbq_count(void)
+{
+ return ARRAY_SIZE(lpfc_hbq_defs);
+}
+
+static int
+lpfc_sli_hbq_entry_count(void)
+{
+ int hbq_count = lpfc_sli_hbq_count();
+ int count = 0;
+ int i;
+
+ for (i = 0; i < hbq_count; ++i)
+ count += lpfc_hbq_defs[i]->entry_count;
+ return count;
+}
+
int
-lpfc_sli_hba_setup(struct lpfc_hba * phba)
+lpfc_sli_hbq_size(void)
+{
+ return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry);
+}
+
+static int
+lpfc_sli_hbq_setup(struct lpfc_hba *phba)
+{
+ int hbq_count = lpfc_sli_hbq_count();
+ LPFC_MBOXQ_t *pmb;
+ MAILBOX_t *pmbox;
+ uint32_t hbqno;
+ uint32_t hbq_entry_index;
+
+ /* Get a Mailbox buffer to setup mailbox
+ * commands for HBA initialization
+ */
+ pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+
+ if (!pmb)
+ return -ENOMEM;
+
+ pmbox = &pmb->mb;
+
+ /* Initialize the struct lpfc_sli_hbq structure for each hbq */
+ phba->link_state = LPFC_INIT_MBX_CMDS;
+
+ hbq_entry_index = 0;
+ for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
+ phba->hbqs[hbqno].next_hbqPutIdx = 0;
+ phba->hbqs[hbqno].hbqPutIdx = 0;
+ phba->hbqs[hbqno].local_hbqGetIdx = 0;
+ phba->hbqs[hbqno].entry_count =
+ lpfc_hbq_defs[hbqno]->entry_count;
+ lpfc_config_hbq(phba, lpfc_hbq_defs[hbqno], hbq_entry_index,
+ pmb);
+ hbq_entry_index += phba->hbqs[hbqno].entry_count;
+
+ if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
+ /* Adapter failed to init, mbxCmd <cmd> CFG_RING,
+ mbxStatus <status>, ring <num> */
+
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_SLI | LOG_VPORT,
+ "%d:1805 Adapter failed to init. "
+ "Data: x%x x%x x%x\n",
+ phba->brd_no, pmbox->mbxCommand,
+ pmbox->mbxStatus, hbqno);
+
+ phba->link_state = LPFC_HBA_ERROR;
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return ENXIO;
+ }
+ }
+ phba->hbq_count = hbq_count;
+
+ mempool_free(pmb, phba->mbox_mem_pool);
+
+ /* Initially populate or replenish the HBQs */
+ for (hbqno = 0; hbqno < hbq_count; ++hbqno) {
+ if (lpfc_sli_hbqbuf_init_hbqs(phba, hbqno))
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int
+lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode)
{
LPFC_MBOXQ_t *pmb;
uint32_t resetcount = 0, rc = 0, done = 0;
pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
return -ENOMEM;
}
+ phba->sli_rev = sli_mode;
while (resetcount < 2 && !done) {
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
- phba->hba_state = LPFC_STATE_UNKNOWN;
+ spin_unlock_irq(&phba->hbalock);
+ phba->pport->port_state = LPFC_VPORT_UNKNOWN;
lpfc_sli_brdrestart(phba);
msleep(2500);
rc = lpfc_sli_chipset_init(phba);
if (rc)
break;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
resetcount++;
- /* Call pre CONFIG_PORT mailbox command initialization. A value of 0
- * means the call was successful. Any other nonzero value is a failure,
- * but if ERESTART is returned, the driver may reset the HBA and try
- * again.
- */
+ /* Call pre CONFIG_PORT mailbox command initialization. A
+ * value of 0 means the call was successful. Any other
+ * nonzero value is a failure, but if ERESTART is returned,
+ * the driver may reset the HBA and try again.
+ */
rc = lpfc_config_port_prep(phba);
if (rc == -ERESTART) {
- phba->hba_state = 0;
+ phba->link_state = LPFC_LINK_UNKNOWN;
continue;
} else if (rc) {
break;
}
- phba->hba_state = LPFC_INIT_MBX_CMDS;
+ phba->link_state = LPFC_INIT_MBX_CMDS;
lpfc_config_port(phba, pmb);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc == MBX_SUCCESS)
- done = 1;
- else {
+ if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0442 Adapter failed to init, mbxCmd x%x "
"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
phba->brd_no, pmb->mb.mbxCommand,
pmb->mb.mbxStatus, 0);
+ spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
+ spin_unlock_irq(&phba->hbalock);
+ rc = -ENXIO;
+ } else {
+ done = 1;
+ phba->max_vpi = (phba->max_vpi &&
+ pmb->mb.un.varCfgPort.gmv) != 0
+ ? pmb->mb.un.varCfgPort.max_vpi
+ : 0;
+ }
+ }
+
+ if (!done) {
+ rc = -EINVAL;
+ goto do_prep_failed;
+ }
+
+ if ((pmb->mb.un.varCfgPort.sli_mode == 3) &&
+ (!pmb->mb.un.varCfgPort.cMA)) {
+ rc = -ENXIO;
+ goto do_prep_failed;
+ }
+ return rc;
+
+do_prep_failed:
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return rc;
+}
+
+int
+lpfc_sli_hba_setup(struct lpfc_hba *phba)
+{
+ uint32_t rc;
+ int mode = 3;
+
+ switch (lpfc_sli_mode) {
+ case 2:
+ if (phba->cfg_npiv_enable) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d:1824 NPIV enabled: Override lpfc_sli_mode "
+ "parameter (%d) to auto (0).\n",
+ phba->brd_no, lpfc_sli_mode);
+ break;
}
+ mode = 2;
+ break;
+ case 0:
+ case 3:
+ break;
+ default:
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d:1819 Unrecognized lpfc_sli_mode "
+ "parameter: %d.\n",
+ phba->brd_no, lpfc_sli_mode);
+
+ break;
}
- if (!done)
+
+ rc = lpfc_do_config_port(phba, mode);
+ if (rc && lpfc_sli_mode == 3)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d:1820 Unable to select SLI-3. "
+ "Not supported by adapter.\n",
+ phba->brd_no);
+ if (rc && mode != 2)
+ rc = lpfc_do_config_port(phba, 2);
+ if (rc)
goto lpfc_sli_hba_setup_error;
- rc = lpfc_sli_ring_map(phba, pmb);
+ if (phba->sli_rev == 3) {
+ phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
+ phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;
+ phba->sli3_options |= LPFC_SLI3_ENABLED;
+ phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED;
+
+ } else {
+ phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE;
+ phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE;
+ phba->sli3_options = 0;
+ }
+
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0444 Firmware in SLI %x mode. Max_vpi %d\n",
+ phba->brd_no, phba->sli_rev, phba->max_vpi);
+ rc = lpfc_sli_ring_map(phba);
if (rc)
goto lpfc_sli_hba_setup_error;
+ /* Init HBQs */
+
+ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
+ rc = lpfc_sli_hbq_setup(phba);
+ if (rc)
+ goto lpfc_sli_hba_setup_error;
+ }
+
phba->sli.sli_flag |= LPFC_PROCESS_LA;
rc = lpfc_config_port_post(phba);
if (rc)
goto lpfc_sli_hba_setup_error;
- goto lpfc_sli_hba_setup_exit;
+ return rc;
+
lpfc_sli_hba_setup_error:
- phba->hba_state = LPFC_HBA_ERROR;
-lpfc_sli_hba_setup_exit:
- mempool_free(pmb, phba->mbox_mem_pool);
+ phba->link_state = LPFC_HBA_ERROR;
+ lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+ "%d:0445 Firmware initialization failed\n",
+ phba->brd_no);
return rc;
}
@@ -2004,56 +2413,58 @@ lpfc_sli_hba_setup_exit:
void
lpfc_mbox_timeout(unsigned long ptr)
{
- struct lpfc_hba *phba;
+ struct lpfc_hba *phba = (struct lpfc_hba *) ptr;
unsigned long iflag;
+ uint32_t tmo_posted;
- phba = (struct lpfc_hba *)ptr;
- spin_lock_irqsave(phba->host->host_lock, iflag);
- if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
- phba->work_hba_events |= WORKER_MBOX_TMO;
+ spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
+ tmo_posted = phba->pport->work_port_events & WORKER_MBOX_TMO;
+ if (!tmo_posted)
+ phba->pport->work_port_events |= WORKER_MBOX_TMO;
+ spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
+
+ if (!tmo_posted) {
+ spin_lock_irqsave(&phba->hbalock, iflag);
if (phba->work_wait)
- wake_up(phba->work_wait);
+ lpfc_worker_wake_up(phba);
+ spin_unlock_irqrestore(&phba->hbalock, iflag);
}
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
}
void
lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
{
- LPFC_MBOXQ_t *pmbox;
- MAILBOX_t *mb;
+ LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active;
+ MAILBOX_t *mb = &pmbox->mb;
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
- spin_lock_irq(phba->host->host_lock);
- if (!(phba->work_hba_events & WORKER_MBOX_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ if (!(phba->pport->work_port_events & WORKER_MBOX_TMO)) {
return;
}
- pmbox = phba->sli.mbox_active;
- mb = &pmbox->mb;
-
/* Mbox cmd <mbxCommand> timeout */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_MBOX | LOG_SLI,
- "%d:0310 Mailbox command x%x timeout Data: x%x x%x x%p\n",
- phba->brd_no,
- mb->mbxCommand,
- phba->hba_state,
- phba->sli.sli_flag,
- phba->sli.mbox_active);
+ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
+ "%d:0310 Mailbox command x%x timeout Data: x%x x%x "
+ "x%p\n",
+ phba->brd_no,
+ mb->mbxCommand,
+ phba->pport->port_state,
+ phba->sli.sli_flag,
+ phba->sli.mbox_active);
/* Setting state unknown so lpfc_sli_abort_iocb_ring
* would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing
* it to fail all oustanding SCSI IO.
*/
- phba->hba_state = LPFC_STATE_UNKNOWN;
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
- phba->fc_flag |= FC_ESTABLISH_LINK;
+ spin_lock_irq(&phba->pport->work_port_lock);
+ phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+ spin_unlock_irq(&phba->pport->work_port_lock);
+ spin_lock_irq(&phba->hbalock);
+ phba->link_state = LPFC_LINK_UNKNOWN;
+ phba->pport->fc_flag |= FC_ESTABLISH_LINK;
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
- spin_unlock_irq(phba->host->host_lock);
+ spin_unlock_irq(&phba->hbalock);
pring = &psli->ring[psli->fcp_ring];
lpfc_sli_abort_iocb_ring(phba, pring);
@@ -2075,10 +2486,10 @@ lpfc_mbox_timeout_handler(struct lpfc_hba *phba)
}
int
-lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
+lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag)
{
MAILBOX_t *mb;
- struct lpfc_sli *psli;
+ struct lpfc_sli *psli = &phba->sli;
uint32_t status, evtctr;
uint32_t ha_copy;
int i;
@@ -2086,31 +2497,44 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
volatile uint32_t word0, ldata;
void __iomem *to_slim;
+ if (pmbox->mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_def_mbox_cmpl &&
+ pmbox->mbox_cmpl != lpfc_sli_wake_mbox_wait) {
+ if(!pmbox->vport) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_MBOX | LOG_VPORT,
+ "%d:1806 Mbox x%x failed. No vport\n",
+ phba->brd_no,
+ pmbox->mb.mbxCommand);
+ dump_stack();
+ return MBXERR_ERROR;
+ }
+ }
+
+
/* If the PCI channel is in offline state, do not post mbox. */
if (unlikely(pci_channel_offline(phba->pcidev)))
return MBX_NOT_FINISHED;
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
psli = &phba->sli;
- spin_lock_irqsave(phba->host->host_lock, drvr_flag);
-
mb = &pmbox->mb;
status = MBX_SUCCESS;
- if (phba->hba_state == LPFC_HBA_ERROR) {
- spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
+ if (phba->link_state == LPFC_HBA_ERROR) {
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag)
+ return MBX_NOT_FINISHED;
}
if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT &&
!(readl(phba->HCregaddr) & HC_MBINT_ENA)) {
- spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag)
+ return MBX_NOT_FINISHED;
}
if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) {
@@ -2120,20 +2544,18 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
*/
if (flag & MBX_POLL) {
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+ return MBX_NOT_FINISHED;
}
if (!(psli->sli_flag & LPFC_SLI2_ACTIVE)) {
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag)
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+ return MBX_NOT_FINISHED;
}
/* Handle STOP IOCB processing flag. This is only meaningful
@@ -2157,21 +2579,33 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
lpfc_mbox_put(phba, pmbox);
/* Mbox cmd issue - BUSY */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0308 Mbox cmd issue - BUSY Data: x%x x%x x%x x%x\n",
- phba->brd_no,
- mb->mbxCommand,
- phba->hba_state,
- psli->sli_flag,
- flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+ "%d (%d):0308 Mbox cmd issue - BUSY Data: "
+ "x%x x%x x%x x%x\n",
+ phba->brd_no,
+ pmbox->vport ? pmbox->vport->vpi : 0xffffff,
+ mb->mbxCommand, phba->pport->port_state,
+ psli->sli_flag, flag);
psli->slistat.mbox_busy++;
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+
+ if (pmbox->vport) {
+ lpfc_debugfs_disc_trc(pmbox->vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX Bsy vport: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
+ else {
+ lpfc_debugfs_disc_trc(phba->pport,
+ LPFC_DISC_TRC_MBOX,
+ "MBOX Bsy: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
- return (MBX_BUSY);
+ return MBX_BUSY;
}
/* Handle STOP IOCB processing flag. This is only meaningful
@@ -2198,11 +2632,10 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
if (!(psli->sli_flag & LPFC_SLI2_ACTIVE) &&
(mb->mbxCommand != MBX_KILL_BOARD)) {
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irqrestore(phba->host->host_lock,
- drvr_flag);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
/* Mbox command <mbxCommand> cannot issue */
- LOG_MBOX_CANNOT_ISSUE_DATA( phba, mb, psli, flag);
- return (MBX_NOT_FINISHED);
+ LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag);
+ return MBX_NOT_FINISHED;
}
/* timeout active mbox command */
mod_timer(&psli->mbox_tmo, (jiffies +
@@ -2210,15 +2643,29 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
}
/* Mailbox cmd <cmd> issue */
- lpfc_printf_log(phba,
- KERN_INFO,
- LOG_MBOX | LOG_SLI,
- "%d:0309 Mailbox cmd x%x issue Data: x%x x%x x%x\n",
- phba->brd_no,
- mb->mbxCommand,
- phba->hba_state,
- psli->sli_flag,
- flag);
+ lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
+ "%d (%d):0309 Mailbox cmd x%x issue Data: x%x x%x "
+ "x%x\n",
+ phba->brd_no, pmbox->vport ? pmbox->vport->vpi : 0,
+ mb->mbxCommand, phba->pport->port_state,
+ psli->sli_flag, flag);
+
+ if (mb->mbxCommand != MBX_HEARTBEAT) {
+ if (pmbox->vport) {
+ lpfc_debugfs_disc_trc(pmbox->vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX Send vport: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
+ else {
+ lpfc_debugfs_disc_trc(phba->pport,
+ LPFC_DISC_TRC_MBOX,
+ "MBOX Send: cmd:x%x mb:x%x x%x",
+ (uint32_t)mb->mbxCommand,
+ mb->un.varWords[0], mb->un.varWords[1]);
+ }
+ }
psli->slistat.mbox_cmd++;
evtctr = psli->slistat.mbox_event;
@@ -2233,7 +2680,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
if (mb->mbxCommand == MBX_CONFIG_PORT) {
/* copy command data into host mbox for cmpl */
lpfc_sli_pcimem_bcopy(mb, &phba->slim2p->mbx,
- MAILBOX_CMD_SIZE);
+ MAILBOX_CMD_SIZE);
}
/* First copy mbox command data to HBA SLIM, skip past first
@@ -2285,12 +2732,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
/* Wait for command to complete */
while (((word0 & OWN_CHIP) == OWN_CHIP) ||
(!(ha_copy & HA_MBATT) &&
- (phba->hba_state > LPFC_WARM_START))) {
+ (phba->link_state > LPFC_WARM_START))) {
if (i-- <= 0) {
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
drvr_flag);
- return (MBX_NOT_FINISHED);
+ return MBX_NOT_FINISHED;
}
/* Check if we took a mbox interrupt while we were
@@ -2299,12 +2746,12 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
&& (evtctr != psli->slistat.mbox_event))
break;
- spin_unlock_irqrestore(phba->host->host_lock,
+ spin_unlock_irqrestore(&phba->hbalock,
drvr_flag);
msleep(1);
- spin_lock_irqsave(phba->host->host_lock, drvr_flag);
+ spin_lock_irqsave(&phba->hbalock, drvr_flag);
if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
/* First copy command data */
@@ -2335,7 +2782,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
/* copy results back to user */
lpfc_sli_pcimem_bcopy(&phba->slim2p->mbx, mb,
- MAILBOX_CMD_SIZE);
+ MAILBOX_CMD_SIZE);
} else {
/* First copy command data */
lpfc_memcpy_from_slim(mb, phba->MBslimaddr,
@@ -2355,23 +2802,25 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
status = mb->mbxStatus;
}
- spin_unlock_irqrestore(phba->host->host_lock, drvr_flag);
- return (status);
+ spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
+ return status;
}
-static int
-lpfc_sli_ringtx_put(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * piocb)
+/*
+ * Caller needs to hold lock.
+ */
+static void
+__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb)
{
/* Insert the caller's iocb in the txq tail for later processing. */
list_add_tail(&piocb->list, &pring->txq);
pring->txq_cnt++;
- return (0);
}
static struct lpfc_iocbq *
lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- struct lpfc_iocbq ** piocb)
+ struct lpfc_iocbq **piocb)
{
struct lpfc_iocbq * nextiocb;
@@ -2384,13 +2833,29 @@ lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
return nextiocb;
}
+/*
+ * Lockless version of lpfc_sli_issue_iocb.
+ */
int
-lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+__lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct lpfc_iocbq *piocb, uint32_t flag)
{
struct lpfc_iocbq *nextiocb;
IOCB_t *iocb;
+ if (piocb->iocb_cmpl && (!piocb->vport) &&
+ (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) &&
+ (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
+ lpfc_printf_log(phba, KERN_ERR,
+ LOG_SLI | LOG_VPORT,
+ "%d:1807 IOCB x%x failed. No vport\n",
+ phba->brd_no,
+ piocb->iocb.ulpCommand);
+ dump_stack();
+ return IOCB_ERROR;
+ }
+
+
/* If the PCI channel is in offline state, do not post iocbs. */
if (unlikely(pci_channel_offline(phba->pcidev)))
return IOCB_ERROR;
@@ -2398,7 +2863,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
/*
* We should never get an IOCB if we are in a < LINK_DOWN state
*/
- if (unlikely(phba->hba_state < LPFC_LINK_DOWN))
+ if (unlikely(phba->link_state < LPFC_LINK_DOWN))
return IOCB_ERROR;
/*
@@ -2408,7 +2873,7 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
if (unlikely(pring->flag & LPFC_STOP_IOCB_MBX))
goto iocb_busy;
- if (unlikely(phba->hba_state == LPFC_LINK_DOWN)) {
+ if (unlikely(phba->link_state == LPFC_LINK_DOWN)) {
/*
* Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF
* can be issued if the link is not up.
@@ -2436,8 +2901,9 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
* attention events.
*/
} else if (unlikely(pring->ringno == phba->sli.fcp_ring &&
- !(phba->sli.sli_flag & LPFC_PROCESS_LA)))
+ !(phba->sli.sli_flag & LPFC_PROCESS_LA))) {
goto iocb_busy;
+ }
while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) &&
(nextiocb = lpfc_sli_next_iocb(phba, pring, &piocb)))
@@ -2459,13 +2925,28 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
out_busy:
if (!(flag & SLI_IOCB_RET_IOCB)) {
- lpfc_sli_ringtx_put(phba, pring, piocb);
+ __lpfc_sli_ringtx_put(phba, pring, piocb);
return IOCB_SUCCESS;
}
return IOCB_BUSY;
}
+
+int
+lpfc_sli_issue_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb, uint32_t flag)
+{
+ unsigned long iflags;
+ int rc;
+
+ spin_lock_irqsave(&phba->hbalock, iflags);
+ rc = __lpfc_sli_issue_iocb(phba, pring, piocb, flag);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
+
+ return rc;
+}
+
static int
lpfc_extra_ring_setup( struct lpfc_hba *phba)
{
@@ -2504,7 +2985,7 @@ lpfc_extra_ring_setup( struct lpfc_hba *phba)
int
lpfc_sli_setup(struct lpfc_hba *phba)
{
- int i, totiocb = 0;
+ int i, totiocbsize = 0;
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
@@ -2529,6 +3010,12 @@ lpfc_sli_setup(struct lpfc_hba *phba)
pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES;
pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES;
pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES;
+ pring->sizeCiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_CMD_SIZE :
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_RSP_SIZE :
+ SLI2_IOCB_RSP_SIZE;
pring->iotag_ctr = 0;
pring->iotag_max =
(phba->cfg_hba_queue_depth * 2);
@@ -2539,12 +3026,25 @@ lpfc_sli_setup(struct lpfc_hba *phba)
/* numCiocb and numRiocb are used in config_port */
pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES;
pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES;
+ pring->sizeCiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_CMD_SIZE :
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_RSP_SIZE :
+ SLI2_IOCB_RSP_SIZE;
+ pring->iotag_max = phba->cfg_hba_queue_depth;
pring->num_mask = 0;
break;
case LPFC_ELS_RING: /* ring 2 - ELS / CT */
/* numCiocb and numRiocb are used in config_port */
pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES;
pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES;
+ pring->sizeCiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_CMD_SIZE :
+ SLI2_IOCB_CMD_SIZE;
+ pring->sizeRiocb = (phba->sli_rev == 3) ?
+ SLI3_IOCB_RSP_SIZE :
+ SLI2_IOCB_RSP_SIZE;
pring->fast_iotag = 0;
pring->iotag_ctr = 0;
pring->iotag_max = 4096;
@@ -2575,14 +3075,16 @@ lpfc_sli_setup(struct lpfc_hba *phba)
lpfc_ct_unsol_event;
break;
}
- totiocb += (pring->numCiocb + pring->numRiocb);
+ totiocbsize += (pring->numCiocb * pring->sizeCiocb) +
+ (pring->numRiocb * pring->sizeRiocb);
}
- if (totiocb > MAX_SLI2_IOCB) {
+ if (totiocbsize > MAX_SLIM_IOCB_SIZE) {
/* Too many cmd / rsp ring entries in SLI2 SLIM */
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0462 Too many cmd / rsp ring entries in "
- "SLI2 SLIM Data: x%x x%x\n",
- phba->brd_no, totiocb, MAX_SLI2_IOCB);
+ "SLI2 SLIM Data: x%x x%lx\n",
+ phba->brd_no, totiocbsize,
+ (unsigned long) MAX_SLIM_IOCB_SIZE);
}
if (phba->cfg_multi_ring_support == 2)
lpfc_extra_ring_setup(phba);
@@ -2591,15 +3093,16 @@ lpfc_sli_setup(struct lpfc_hba *phba)
}
int
-lpfc_sli_queue_setup(struct lpfc_hba * phba)
+lpfc_sli_queue_setup(struct lpfc_hba *phba)
{
struct lpfc_sli *psli;
struct lpfc_sli_ring *pring;
int i;
psli = &phba->sli;
- spin_lock_irq(phba->host->host_lock);
+ spin_lock_irq(&phba->hbalock);
INIT_LIST_HEAD(&psli->mboxq);
+ INIT_LIST_HEAD(&psli->mboxq_cmpl);
/* Initialize list headers for txq and txcmplq as double linked lists */
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
@@ -2612,15 +3115,73 @@ lpfc_sli_queue_setup(struct lpfc_hba * phba)
INIT_LIST_HEAD(&pring->iocb_continueq);
INIT_LIST_HEAD(&pring->postbufq);
}
- spin_unlock_irq(phba->host->host_lock);
- return (1);
+ spin_unlock_irq(&phba->hbalock);
+ return 1;
}
int
-lpfc_sli_hba_down(struct lpfc_hba * phba)
+lpfc_sli_host_down(struct lpfc_vport *vport)
{
LIST_HEAD(completions);
- struct lpfc_sli *psli;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_sli_ring *pring;
+ struct lpfc_iocbq *iocb, *next_iocb;
+ int i;
+ unsigned long flags = 0;
+ uint16_t prev_pring_flag;
+
+ lpfc_cleanup_discovery_resources(vport);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
+ for (i = 0; i < psli->num_rings; i++) {
+ pring = &psli->ring[i];
+ prev_pring_flag = pring->flag;
+ if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+ pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ /*
+ * Error everything on the txq since these iocbs have not been
+ * given to the FW yet.
+ */
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) {
+ if (iocb->vport != vport)
+ continue;
+ list_move_tail(&iocb->list, &completions);
+ pring->txq_cnt--;
+ }
+
+ /* Next issue ABTS for everything on the txcmplq */
+ list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq,
+ list) {
+ if (iocb->vport != vport)
+ continue;
+ lpfc_sli_issue_abort_iotag(phba, pring, iocb);
+ }
+
+ pring->flag = prev_pring_flag;
+ }
+
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ while (!list_empty(&completions)) {
+ list_remove_head(&completions, iocb, struct lpfc_iocbq, list);
+
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
+ iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
+ iocb->iocb.un.ulpWord[4] = IOERR_SLI_DOWN;
+ (iocb->iocb_cmpl) (phba, iocb, iocb);
+ }
+ }
+ return 1;
+}
+
+int
+lpfc_sli_hba_down(struct lpfc_hba *phba)
+{
+ LIST_HEAD(completions);
+ struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
LPFC_MBOXQ_t *pmb;
struct lpfc_iocbq *iocb;
@@ -2628,13 +3189,15 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
int i;
unsigned long flags = 0;
- psli = &phba->sli;
lpfc_hba_down_prep(phba);
- spin_lock_irqsave(phba->host->host_lock, flags);
+ lpfc_fabric_abort_hba(phba);
+
+ spin_lock_irqsave(&phba->hbalock, flags);
for (i = 0; i < psli->num_rings; i++) {
pring = &psli->ring[i];
- pring->flag |= LPFC_DEFERRED_RING_EVENT;
+ if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */
+ pring->flag |= LPFC_DEFERRED_RING_EVENT;
/*
* Error everything on the txq since these iocbs have not been
@@ -2644,51 +3207,50 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
pring->txq_cnt = 0;
}
- spin_unlock_irqrestore(phba->host->host_lock, flags);
+ spin_unlock_irqrestore(&phba->hbalock, flags);
while (!list_empty(&completions)) {
- iocb = list_get_first(&completions, struct lpfc_iocbq, list);
+ list_remove_head(&completions, iocb, struct lpfc_iocbq, list);
cmd = &iocb->iocb;
- list_del(&iocb->list);
- if (iocb->iocb_cmpl) {
+ if (!iocb->iocb_cmpl)
+ lpfc_sli_release_iocbq(phba, iocb);
+ else {
cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
cmd->un.ulpWord[4] = IOERR_SLI_DOWN;
(iocb->iocb_cmpl) (phba, iocb, iocb);
- } else
- lpfc_sli_release_iocbq(phba, iocb);
+ }
}
/* Return any active mbox cmds */
del_timer_sync(&psli->mbox_tmo);
- spin_lock_irqsave(phba->host->host_lock, flags);
- phba->work_hba_events &= ~WORKER_MBOX_TMO;
+ spin_lock_irqsave(&phba->hbalock, flags);
+
+ spin_lock(&phba->pport->work_port_lock);
+ phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+ spin_unlock(&phba->pport->work_port_lock);
+
if (psli->mbox_active) {
- pmb = psli->mbox_active;
- pmb->mb.mbxStatus = MBX_NOT_FINISHED;
- if (pmb->mbox_cmpl) {
- spin_unlock_irqrestore(phba->host->host_lock, flags);
- pmb->mbox_cmpl(phba,pmb);
- spin_lock_irqsave(phba->host->host_lock, flags);
- }
+ list_add_tail(&psli->mbox_active->list, &completions);
+ psli->mbox_active = NULL;
+ psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
}
- psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
- psli->mbox_active = NULL;
- /* Return any pending mbox cmds */
- while ((pmb = lpfc_mbox_get(phba)) != NULL) {
+ /* Return any pending or completed mbox cmds */
+ list_splice_init(&phba->sli.mboxq, &completions);
+ list_splice_init(&phba->sli.mboxq_cmpl, &completions);
+ INIT_LIST_HEAD(&psli->mboxq);
+ INIT_LIST_HEAD(&psli->mboxq_cmpl);
+
+ spin_unlock_irqrestore(&phba->hbalock, flags);
+
+ while (!list_empty(&completions)) {
+ list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list);
pmb->mb.mbxStatus = MBX_NOT_FINISHED;
if (pmb->mbox_cmpl) {
- spin_unlock_irqrestore(phba->host->host_lock, flags);
pmb->mbox_cmpl(phba,pmb);
- spin_lock_irqsave(phba->host->host_lock, flags);
}
}
-
- INIT_LIST_HEAD(&psli->mboxq);
-
- spin_unlock_irqrestore(phba->host->host_lock, flags);
-
return 1;
}
@@ -2710,14 +3272,15 @@ lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt)
}
int
-lpfc_sli_ringpostbuf_put(struct lpfc_hba * phba, struct lpfc_sli_ring * pring,
- struct lpfc_dmabuf * mp)
+lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_dmabuf *mp)
{
/* Stick struct lpfc_dmabuf at end of postbufq so driver can look it up
later */
+ spin_lock_irq(&phba->hbalock);
list_add_tail(&mp->list, &pring->postbufq);
-
pring->postbufq_cnt++;
+ spin_unlock_irq(&phba->hbalock);
return 0;
}
@@ -2730,14 +3293,17 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
struct list_head *slp = &pring->postbufq;
/* Search postbufq, from the begining, looking for a match on phys */
+ spin_lock_irq(&phba->hbalock);
list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) {
if (mp->phys == phys) {
list_del_init(&mp->list);
pring->postbufq_cnt--;
+ spin_unlock_irq(&phba->hbalock);
return mp;
}
}
+ spin_unlock_irq(&phba->hbalock);
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
"%d:0410 Cannot find virtual addr for mapped buf on "
"ring %d Data x%llx x%p x%p x%x\n",
@@ -2747,92 +3313,110 @@ lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
static void
-lpfc_sli_abort_els_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- IOCB_t *irsp;
+ IOCB_t *irsp = &rspiocb->iocb;
uint16_t abort_iotag, abort_context;
- struct lpfc_iocbq *abort_iocb, *rsp_ab_iocb;
+ struct lpfc_iocbq *abort_iocb;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
abort_iocb = NULL;
- irsp = &rspiocb->iocb;
-
- spin_lock_irq(phba->host->host_lock);
if (irsp->ulpStatus) {
abort_context = cmdiocb->iocb.un.acxri.abortContextTag;
abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag;
+ spin_lock_irq(&phba->hbalock);
if (abort_iotag != 0 && abort_iotag <= phba->sli.last_iotag)
abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
- lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0327 Cannot abort els iocb %p"
- " with tag %x context %x\n",
- phba->brd_no, abort_iocb,
- abort_iotag, abort_context);
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
+ "%d:0327 Cannot abort els iocb %p "
+ "with tag %x context %x, abort status %x, "
+ "abort code %x\n",
+ phba->brd_no, abort_iocb, abort_iotag,
+ abort_context, irsp->ulpStatus,
+ irsp->un.ulpWord[4]);
/*
* make sure we have the right iocbq before taking it
* off the txcmplq and try to call completion routine.
*/
- if (abort_iocb &&
- abort_iocb->iocb.ulpContext == abort_context &&
- abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) {
- list_del(&abort_iocb->list);
+ if (!abort_iocb ||
+ abort_iocb->iocb.ulpContext != abort_context ||
+ (abort_iocb->iocb_flag & LPFC_DRIVER_ABORTED) == 0)
+ spin_unlock_irq(&phba->hbalock);
+ else {
+ list_del_init(&abort_iocb->list);
pring->txcmplq_cnt--;
+ spin_unlock_irq(&phba->hbalock);
- rsp_ab_iocb = lpfc_sli_get_iocbq(phba);
- if (rsp_ab_iocb == NULL)
- lpfc_sli_release_iocbq(phba, abort_iocb);
- else {
- abort_iocb->iocb_flag &=
- ~LPFC_DRIVER_ABORTED;
- rsp_ab_iocb->iocb.ulpStatus =
- IOSTAT_LOCAL_REJECT;
- rsp_ab_iocb->iocb.un.ulpWord[4] =
- IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (abort_iocb->iocb_cmpl)
- (phba, abort_iocb, rsp_ab_iocb);
- spin_lock_irq(phba->host->host_lock);
- lpfc_sli_release_iocbq(phba, rsp_ab_iocb);
- }
+ abort_iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED;
+ abort_iocb->iocb.ulpStatus = IOSTAT_LOCAL_REJECT;
+ abort_iocb->iocb.un.ulpWord[4] = IOERR_SLI_ABORTED;
+ (abort_iocb->iocb_cmpl)(phba, abort_iocb, abort_iocb);
}
}
lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irq(phba->host->host_lock);
+ return;
+}
+
+static void
+lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
+{
+ IOCB_t *irsp = &rspiocb->iocb;
+
+ /* ELS cmd tag <ulpIoTag> completes */
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
+ "%d (X):0133 Ignoring ELS cmd tag x%x completion Data: "
+ "x%x x%x x%x\n",
+ phba->brd_no, irsp->ulpIoTag, irsp->ulpStatus,
+ irsp->un.ulpWord[4], irsp->ulpTimeout);
+ if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR)
+ lpfc_ct_free_iocb(phba, cmdiocb);
+ else
+ lpfc_els_free_iocb(phba, cmdiocb);
return;
}
int
-lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * cmdiocb)
+lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *cmdiocb)
{
+ struct lpfc_vport *vport = cmdiocb->vport;
struct lpfc_iocbq *abtsiocbp;
IOCB_t *icmd = NULL;
IOCB_t *iabt = NULL;
int retval = IOCB_ERROR;
- /* There are certain command types we don't want
- * to abort.
+ /*
+ * There are certain command types we don't want to abort. And we
+ * don't want to abort commands that are already in the process of
+ * being aborted.
*/
icmd = &cmdiocb->iocb;
- if ((icmd->ulpCommand == CMD_ABORT_XRI_CN) ||
- (icmd->ulpCommand == CMD_CLOSE_XRI_CN))
+ if (icmd->ulpCommand == CMD_ABORT_XRI_CN ||
+ icmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+ (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0)
return 0;
- /* If we're unloading, interrupts are disabled so we
- * need to cleanup the iocb here.
+ /* If we're unloading, don't abort iocb on the ELS ring, but change the
+ * callback so that nothing happens when it finishes.
*/
- if (phba->fc_flag & FC_UNLOADING)
+ if ((vport->load_flag & FC_UNLOADING) &&
+ (pring->ringno == LPFC_ELS_RING)) {
+ if (cmdiocb->iocb_flag & LPFC_IO_FABRIC)
+ cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl;
+ else
+ cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl;
goto abort_iotag_exit;
+ }
/* issue ABTS for this IOCB based on iotag */
- abtsiocbp = lpfc_sli_get_iocbq(phba);
+ abtsiocbp = __lpfc_sli_get_iocbq(phba);
if (abtsiocbp == NULL)
return 0;
@@ -2848,7 +3432,7 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
iabt->ulpLe = 1;
iabt->ulpClass = icmd->ulpClass;
- if (phba->hba_state >= LPFC_LINK_UP)
+ if (phba->link_state >= LPFC_LINK_UP)
iabt->ulpCommand = CMD_ABORT_XRI_CN;
else
iabt->ulpCommand = CMD_CLOSE_XRI_CN;
@@ -2856,32 +3440,20 @@ lpfc_sli_issue_abort_iotag(struct lpfc_hba * phba,
abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0339 Abort xri x%x, original iotag x%x, abort "
- "cmd iotag x%x\n",
- phba->brd_no, iabt->un.acxri.abortContextTag,
+ "%d (%d):0339 Abort xri x%x, original iotag x%x, "
+ "abort cmd iotag x%x\n",
+ phba->brd_no, vport->vpi,
+ iabt->un.acxri.abortContextTag,
iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
- retval = lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
+ retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
abort_iotag_exit:
-
- /* If we could not issue an abort dequeue the iocb and handle
- * the completion here.
+ /*
+ * Caller to this routine should check for IOCB_ERROR
+ * and handle it properly. This routine no longer removes
+ * iocb off txcmplq and call compl in case of IOCB_ERROR.
*/
- if (retval == IOCB_ERROR) {
- list_del(&cmdiocb->list);
- pring->txcmplq_cnt--;
-
- if (cmdiocb->iocb_cmpl) {
- icmd->ulpStatus = IOSTAT_LOCAL_REJECT;
- icmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
- spin_unlock_irq(phba->host->host_lock);
- (cmdiocb->iocb_cmpl) (phba, cmdiocb, cmdiocb);
- spin_lock_irq(phba->host->host_lock);
- } else
- lpfc_sli_release_iocbq(phba, cmdiocb);
- }
-
- return 1;
+ return retval;
}
static int
@@ -2930,7 +3502,7 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
int
lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
- uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
+ uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
{
struct lpfc_iocbq *iocbq;
int sum, i;
@@ -2947,14 +3519,10 @@ lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
}
void
-lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
- struct lpfc_iocbq * rspiocb)
+lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
+ struct lpfc_iocbq *rspiocb)
{
- unsigned long iflags;
-
- spin_lock_irqsave(phba->host->host_lock, iflags);
lpfc_sli_release_iocbq(phba, cmdiocb);
- spin_unlock_irqrestore(phba->host->host_lock, iflags);
return;
}
@@ -2972,8 +3540,8 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
for (i = 1; i <= phba->sli.last_iotag; i++) {
iocbq = phba->sli.iocbq_lookup[i];
- if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
- 0, abort_cmd) != 0)
+ if (lpfc_sli_validate_fcp_iocb(iocbq, tgt_id, lun_id, 0,
+ abort_cmd) != 0)
continue;
/* issue ABTS for this IOCB based on iotag */
@@ -2989,8 +3557,9 @@ lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
abtsiocb->iocb.ulpLe = 1;
abtsiocb->iocb.ulpClass = cmd->ulpClass;
+ abtsiocb->vport = phba->pport;
- if (phba->hba_state >= LPFC_LINK_UP)
+ if (lpfc_is_link_up(phba))
abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN;
else
abtsiocb->iocb.ulpCommand = CMD_CLOSE_XRI_CN;
@@ -3016,16 +3585,16 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
wait_queue_head_t *pdone_q;
unsigned long iflags;
- spin_lock_irqsave(phba->host->host_lock, iflags);
+ spin_lock_irqsave(&phba->hbalock, iflags);
cmdiocbq->iocb_flag |= LPFC_IO_WAKE;
if (cmdiocbq->context2 && rspiocbq)
memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb,
&rspiocbq->iocb, sizeof(IOCB_t));
pdone_q = cmdiocbq->context_un.wait_queue;
- spin_unlock_irqrestore(phba->host->host_lock, iflags);
if (pdone_q)
wake_up(pdone_q);
+ spin_unlock_irqrestore(&phba->hbalock, iflags);
return;
}
@@ -3035,11 +3604,12 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
* lpfc_sli_issue_call since the wake routine sets a unique value and by
* definition this is a wait function.
*/
+
int
-lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
- struct lpfc_sli_ring * pring,
- struct lpfc_iocbq * piocb,
- struct lpfc_iocbq * prspiocbq,
+lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
+ struct lpfc_sli_ring *pring,
+ struct lpfc_iocbq *piocb,
+ struct lpfc_iocbq *prspiocbq,
uint32_t timeout)
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
@@ -3071,11 +3641,9 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
retval = lpfc_sli_issue_iocb(phba, pring, piocb, 0);
if (retval == IOCB_SUCCESS) {
timeout_req = timeout * HZ;
- spin_unlock_irq(phba->host->host_lock);
timeleft = wait_event_timeout(done_q,
piocb->iocb_flag & LPFC_IO_WAKE,
timeout_req);
- spin_lock_irq(phba->host->host_lock);
if (piocb->iocb_flag & LPFC_IO_WAKE) {
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
@@ -3117,16 +3685,16 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
}
int
-lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
+lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq,
uint32_t timeout)
{
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q);
int retval;
+ unsigned long flag;
/* The caller must leave context1 empty. */
- if (pmboxq->context1 != 0) {
- return (MBX_NOT_FINISHED);
- }
+ if (pmboxq->context1 != 0)
+ return MBX_NOT_FINISHED;
/* setup wake call as IOCB callback */
pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait;
@@ -3141,6 +3709,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
pmboxq->mbox_flag & LPFC_MBX_WAKE,
timeout * HZ);
+ spin_lock_irqsave(&phba->hbalock, flag);
pmboxq->context1 = NULL;
/*
* if LPFC_MBX_WAKE flag is set the mailbox is completed
@@ -3148,8 +3717,11 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
*/
if (pmboxq->mbox_flag & LPFC_MBX_WAKE)
retval = MBX_SUCCESS;
- else
+ else {
retval = MBX_TIMEOUT;
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ }
+ spin_unlock_irqrestore(&phba->hbalock, flag);
}
return retval;
@@ -3158,14 +3730,27 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
int
lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
{
+ struct lpfc_vport *vport = phba->pport;
int i = 0;
+ uint32_t ha_copy;
- while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !phba->stopped) {
+ while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !vport->stopped) {
if (i++ > LPFC_MBOX_TMO * 1000)
return 1;
- if (lpfc_sli_handle_mb_event(phba) == 0)
- i = 0;
+ /*
+ * Call lpfc_sli_handle_mb_event only if a mailbox cmd
+ * did finish. This way we won't get the misleading
+ * "Stray Mailbox Interrupt" message.
+ */
+ spin_lock_irq(&phba->hbalock);
+ ha_copy = phba->work_ha;
+ phba->work_ha &= ~HA_MBATT;
+ spin_unlock_irq(&phba->hbalock);
+
+ if (ha_copy & HA_MBATT)
+ if (lpfc_sli_handle_mb_event(phba) == 0)
+ i = 0;
msleep(1);
}
@@ -3176,13 +3761,20 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
irqreturn_t
lpfc_intr_handler(int irq, void *dev_id)
{
- struct lpfc_hba *phba;
+ struct lpfc_hba *phba;
uint32_t ha_copy;
uint32_t work_ha_copy;
unsigned long status;
int i;
uint32_t control;
+ MAILBOX_t *mbox, *pmbox;
+ struct lpfc_vport *vport;
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_dmabuf *mp;
+ LPFC_MBOXQ_t *pmb;
+ int rc;
+
/*
* Get the driver's phba structure from the dev_id and
* assume the HBA is not interrupting.
@@ -3204,7 +3796,7 @@ lpfc_intr_handler(int irq, void *dev_id)
*/
/* Ignore all interrupts during initialization. */
- if (unlikely(phba->hba_state < LPFC_LINK_DOWN))
+ if (unlikely(phba->link_state < LPFC_LINK_DOWN))
return IRQ_NONE;
/*
@@ -3212,16 +3804,16 @@ lpfc_intr_handler(int irq, void *dev_id)
* Clear Attention Sources, except Error Attention (to
* preserve status) and Link Attention
*/
- spin_lock(phba->host->host_lock);
+ spin_lock(&phba->hbalock);
ha_copy = readl(phba->HAregaddr);
/* If somebody is waiting to handle an eratt don't process it
* here. The brdkill function will do this.
*/
- if (phba->fc_flag & FC_IGNORE_ERATT)
+ if (phba->link_flag & LS_IGNORE_ERATT)
ha_copy &= ~HA_ERATT;
writel((ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- spin_unlock(phba->host->host_lock);
+ spin_unlock(&phba->hbalock);
if (unlikely(!ha_copy))
return IRQ_NONE;
@@ -3235,36 +3827,41 @@ lpfc_intr_handler(int irq, void *dev_id)
* Turn off Link Attention interrupts
* until CLEAR_LA done
*/
- spin_lock(phba->host->host_lock);
+ spin_lock(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_PROCESS_LA;
control = readl(phba->HCregaddr);
control &= ~HC_LAINT_ENA;
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock(phba->host->host_lock);
+ spin_unlock(&phba->hbalock);
}
else
work_ha_copy &= ~HA_LATT;
}
if (work_ha_copy & ~(HA_ERATT|HA_MBATT|HA_LATT)) {
- for (i = 0; i < phba->sli.num_rings; i++) {
- if (work_ha_copy & (HA_RXATT << (4*i))) {
- /*
- * Turn off Slow Rings interrupts
- */
- spin_lock(phba->host->host_lock);
- control = readl(phba->HCregaddr);
- control &= ~(HC_R0INT_ENA << i);
+ /*
+ * Turn off Slow Rings interrupts, LPFC_ELS_RING is
+ * the only slow ring.
+ */
+ status = (work_ha_copy &
+ (HA_RXMASK << (4*LPFC_ELS_RING)));
+ status >>= (4*LPFC_ELS_RING);
+ if (status & HA_RXMASK) {
+ spin_lock(&phba->hbalock);
+ control = readl(phba->HCregaddr);
+ if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) {
+ control &=
+ ~(HC_R0INT_ENA << LPFC_ELS_RING);
writel(control, phba->HCregaddr);
readl(phba->HCregaddr); /* flush */
- spin_unlock(phba->host->host_lock);
}
+ spin_unlock(&phba->hbalock);
}
}
if (work_ha_copy & HA_ERATT) {
- phba->hba_state = LPFC_HBA_ERROR;
+ phba->link_state = LPFC_HBA_ERROR;
/*
* There was a link/board error. Read the
* status register to retrieve the error event
@@ -3279,14 +3876,108 @@ lpfc_intr_handler(int irq, void *dev_id)
/* Clear Chip error bit */
writel(HA_ERATT, phba->HAregaddr);
readl(phba->HAregaddr); /* flush */
- phba->stopped = 1;
+ phba->pport->stopped = 1;
+ }
+
+ if ((work_ha_copy & HA_MBATT) &&
+ (phba->sli.mbox_active)) {
+ pmb = phba->sli.mbox_active;
+ pmbox = &pmb->mb;
+ mbox = &phba->slim2p->mbx;
+ vport = pmb->vport;
+
+ /* First check out the status word */
+ lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t));
+ if (pmbox->mbxOwner != OWN_HOST) {
+ /*
+ * Stray Mailbox Interrupt, mbxCommand <cmd>
+ * mbxStatus <status>
+ */
+ lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
+ LOG_SLI,
+ "%d (%d):0304 Stray Mailbox "
+ "Interrupt mbxCommand x%x "
+ "mbxStatus x%x\n",
+ phba->brd_no,
+ (vport
+ ? vport->vpi : 0),
+ pmbox->mbxCommand,
+ pmbox->mbxStatus);
+ }
+ phba->last_completion_time = jiffies;
+ del_timer_sync(&phba->sli.mbox_tmo);
+
+ phba->sli.mbox_active = NULL;
+ if (pmb->mbox_cmpl) {
+ lpfc_sli_pcimem_bcopy(mbox, pmbox,
+ MAILBOX_CMD_SIZE);
+ }
+ if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) {
+ pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG;
+
+ lpfc_debugfs_disc_trc(vport,
+ LPFC_DISC_TRC_MBOX_VPORT,
+ "MBOX dflt rpi: : status:x%x rpi:x%x",
+ (uint32_t)pmbox->mbxStatus,
+ pmbox->un.varWords[0], 0);
+
+ if ( !pmbox->mbxStatus) {
+ mp = (struct lpfc_dmabuf *)
+ (pmb->context1);
+ ndlp = (struct lpfc_nodelist *)
+ pmb->context2;
+
+ /* Reg_LOGIN of dflt RPI was successful.
+ * new lets get rid of the RPI using the
+ * same mbox buffer.
+ */
+ lpfc_unreg_login(phba, vport->vpi,
+ pmbox->un.varWords[0], pmb);
+ pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi;
+ pmb->context1 = mp;
+ pmb->context2 = ndlp;
+ pmb->vport = vport;
+ spin_lock(&phba->hbalock);
+ phba->sli.sli_flag &=
+ ~LPFC_SLI_MBOX_ACTIVE;
+ spin_unlock(&phba->hbalock);
+ goto send_current_mbox;
+ }
+ }
+ spin_lock(&phba->pport->work_port_lock);
+ phba->pport->work_port_events &= ~WORKER_MBOX_TMO;
+ spin_unlock(&phba->pport->work_port_lock);
+ lpfc_mbox_cmpl_put(phba, pmb);
+ }
+ if ((work_ha_copy & HA_MBATT) &&
+ (phba->sli.mbox_active == NULL)) {
+send_next_mbox:
+ spin_lock(&phba->hbalock);
+ phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+ pmb = lpfc_mbox_get(phba);
+ spin_unlock(&phba->hbalock);
+send_current_mbox:
+ /* Process next mailbox command if there is one */
+ if (pmb != NULL) {
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc == MBX_NOT_FINISHED) {
+ pmb->mb.mbxStatus = MBX_NOT_FINISHED;
+ lpfc_mbox_cmpl_put(phba, pmb);
+ goto send_next_mbox;
+ }
+ } else {
+ /* Turn on IOCB processing */
+ for (i = 0; i < phba->sli.num_rings; i++)
+ lpfc_sli_turn_on_ring(phba, i);
+ }
+
}
- spin_lock(phba->host->host_lock);
+ spin_lock(&phba->hbalock);
phba->work_ha |= work_ha_copy;
if (phba->work_wait)
- wake_up(phba->work_wait);
- spin_unlock(phba->host->host_lock);
+ lpfc_worker_wake_up(phba);
+ spin_unlock(&phba->hbalock);
}
ha_copy &= ~(phba->work_ha_mask);
@@ -3298,7 +3989,7 @@ lpfc_intr_handler(int irq, void *dev_id)
*/
status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING)));
status >>= (4*LPFC_FCP_RING);
- if (status & HA_RXATT)
+ if (status & HA_RXMASK)
lpfc_sli_handle_fast_ring_event(phba,
&phba->sli.ring[LPFC_FCP_RING],
status);
@@ -3311,7 +4002,7 @@ lpfc_intr_handler(int irq, void *dev_id)
*/
status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING)));
status >>= (4*LPFC_EXTRA_RING);
- if (status & HA_RXATT) {
+ if (status & HA_RXMASK) {
lpfc_sli_handle_fast_ring_event(phba,
&phba->sli.ring[LPFC_EXTRA_RING],
status);
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 41c38d324ab0..76058505795e 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -20,6 +20,7 @@
/* forward declaration for LPFC_IOCB_t's use */
struct lpfc_hba;
+struct lpfc_vport;
/* Define the context types that SLI handles for abort and sums. */
typedef enum _lpfc_ctx_cmd {
@@ -43,10 +44,12 @@ struct lpfc_iocbq {
#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */
#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */
#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */
+#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */
uint8_t abort_count;
uint8_t rsvd2;
uint32_t drvrTimeout; /* driver timeout in seconds */
+ struct lpfc_vport *vport;/* virtual port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
void *context3; /* caller context information */
@@ -56,6 +59,8 @@ struct lpfc_iocbq {
struct lpfcMboxq *mbox;
} context_un;
+ void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
+ struct lpfc_iocbq *);
void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
struct lpfc_iocbq *);
@@ -68,12 +73,14 @@ struct lpfc_iocbq {
#define IOCB_ERROR 2
#define IOCB_TIMEDOUT 3
-#define LPFC_MBX_WAKE 1
+#define LPFC_MBX_WAKE 1
+#define LPFC_MBX_IMED_UNREG 2
typedef struct lpfcMboxq {
/* MBOXQs are used in single linked lists */
struct list_head list; /* ptr to next mailbox command */
MAILBOX_t mb; /* Mailbox cmd */
+ struct lpfc_vport *vport;/* virutal port pointer */
void *context1; /* caller context information */
void *context2; /* caller context information */
@@ -135,6 +142,8 @@ struct lpfc_sli_ring {
uint8_t ringno; /* ring number */
uint16_t numCiocb; /* number of command iocb's per ring */
uint16_t numRiocb; /* number of rsp iocb's per ring */
+ uint16_t sizeCiocb; /* Size of command iocb's in this ring */
+ uint16_t sizeRiocb; /* Size of response iocb's in this ring */
uint32_t fast_iotag; /* max fastlookup based iotag */
uint32_t iotag_ctr; /* keeps track of the next iotag to use */
@@ -165,6 +174,34 @@ struct lpfc_sli_ring {
struct lpfc_sli_ring *);
};
+/* Structure used for configuring rings to a specific profile or rctl / type */
+struct lpfc_hbq_init {
+ uint32_t rn; /* Receive buffer notification */
+ uint32_t entry_count; /* max # of entries in HBQ */
+ uint32_t headerLen; /* 0 if not profile 4 or 5 */
+ uint32_t logEntry; /* Set to 1 if this HBQ used for LogEntry */
+ uint32_t profile; /* Selection profile 0=all, 7=logentry */
+ uint32_t ring_mask; /* Binds HBQ to a ring e.g. Ring0=b0001,
+ * ring2=b0100 */
+ uint32_t hbq_index; /* index of this hbq in ring .HBQs[] */
+
+ uint32_t seqlenoff;
+ uint32_t maxlen;
+ uint32_t seqlenbcnt;
+ uint32_t cmdcodeoff;
+ uint32_t cmdmatch[8];
+ uint32_t mask_count; /* number of mask entries in prt array */
+ struct hbq_mask hbqMasks[6];
+
+ /* Non-config rings fields to keep track of buffer allocations */
+ uint32_t buffer_count; /* number of buffers allocated */
+ uint32_t init_count; /* number to allocate when initialized */
+ uint32_t add_count; /* number to allocate when starved */
+} ;
+
+#define LPFC_MAX_HBQ 16
+
+
/* Structure used to hold SLI statistical counters and info */
struct lpfc_sli_stat {
uint64_t mbox_stat_err; /* Mbox cmds completed status error */
@@ -197,6 +234,7 @@ struct lpfc_sli {
#define LPFC_SLI_MBOX_ACTIVE 0x100 /* HBA mailbox is currently active */
#define LPFC_SLI2_ACTIVE 0x200 /* SLI2 overlay in firmware is active */
#define LPFC_PROCESS_LA 0x400 /* Able to process link attention */
+#define LPFC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */
struct lpfc_sli_ring ring[LPFC_MAX_RING];
int fcp_ring; /* ring used for FCP initiator commands */
@@ -209,6 +247,7 @@ struct lpfc_sli {
uint16_t mboxq_cnt; /* current length of queue */
uint16_t mboxq_max; /* max length */
LPFC_MBOXQ_t *mbox_active; /* active mboxq information */
+ struct list_head mboxq_cmpl;
struct timer_list mbox_tmo; /* Hold clk to timeout active mbox
cmd */
@@ -221,12 +260,6 @@ struct lpfc_sli {
struct lpfc_lnk_stat lnk_stat_offsets;
};
-/* Given a pointer to the start of the ring, and the slot number of
- * the desired iocb entry, calc a pointer to that entry.
- * (assume iocb entry size is 32 bytes, or 8 words)
- */
-#define IOCB_ENTRY(ring,slot) ((IOCB_t *)(((char *)(ring)) + ((slot) * 32)))
-
#define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox
command */
#define LPFC_MBOX_TMO_FLASH_CMD 300 /* Sec tmo for outstanding FLASH write
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 92a9107019d2..a5bc79eef052 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.1.12"
+#define LPFC_DRIVER_VERSION "8.2.1"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
new file mode 100644
index 000000000000..85797dbf5478
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -0,0 +1,523 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_fc.h>
+#include "lpfc_hw.h"
+#include "lpfc_sli.h"
+#include "lpfc_disc.h"
+#include "lpfc_scsi.h"
+#include "lpfc.h"
+#include "lpfc_logmsg.h"
+#include "lpfc_crtn.h"
+#include "lpfc_version.h"
+#include "lpfc_vport.h"
+
+inline void lpfc_vport_set_state(struct lpfc_vport *vport,
+ enum fc_vport_state new_state)
+{
+ struct fc_vport *fc_vport = vport->fc_vport;
+
+ if (fc_vport) {
+ /*
+ * When the transport defines fc_vport_set state we will replace
+ * this code with the following line
+ */
+ /* fc_vport_set_state(fc_vport, new_state); */
+ if (new_state != FC_VPORT_INITIALIZING)
+ fc_vport->vport_last_state = fc_vport->vport_state;
+ fc_vport->vport_state = new_state;
+ }
+
+ /* for all the error states we will set the invternal state to FAILED */
+ switch (new_state) {
+ case FC_VPORT_NO_FABRIC_SUPP:
+ case FC_VPORT_NO_FABRIC_RSCS:
+ case FC_VPORT_FABRIC_LOGOUT:
+ case FC_VPORT_FABRIC_REJ_WWN:
+ case FC_VPORT_FAILED:
+ vport->port_state = LPFC_VPORT_FAILED;
+ break;
+ case FC_VPORT_LINKDOWN:
+ vport->port_state = LPFC_VPORT_UNKNOWN;
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
+static int
+lpfc_alloc_vpi(struct lpfc_hba *phba)
+{
+ int vpi;
+
+ spin_lock_irq(&phba->hbalock);
+ /* Start at bit 1 because vpi zero is reserved for the physical port */
+ vpi = find_next_zero_bit(phba->vpi_bmask, (phba->max_vpi + 1), 1);
+ if (vpi > phba->max_vpi)
+ vpi = 0;
+ else
+ set_bit(vpi, phba->vpi_bmask);
+ spin_unlock_irq(&phba->hbalock);
+ return vpi;
+}
+
+static void
+lpfc_free_vpi(struct lpfc_hba *phba, int vpi)
+{
+ spin_lock_irq(&phba->hbalock);
+ clear_bit(vpi, phba->vpi_bmask);
+ spin_unlock_irq(&phba->hbalock);
+}
+
+static int
+lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport)
+{
+ LPFC_MBOXQ_t *pmb;
+ MAILBOX_t *mb;
+ struct lpfc_dmabuf *mp;
+ int rc;
+
+ pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmb) {
+ return -ENOMEM;
+ }
+ mb = &pmb->mb;
+
+ lpfc_read_sparam(phba, pmb, vport->vpi);
+ /*
+ * Grab buffer pointer and clear context1 so we can use
+ * lpfc_sli_issue_box_wait
+ */
+ mp = (struct lpfc_dmabuf *) pmb->context1;
+ pmb->context1 = NULL;
+
+ pmb->vport = vport;
+ rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
+ if (rc != MBX_SUCCESS) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
+ "%d (%d):1818 VPort failed init, mbxCmd x%x "
+ "READ_SPARM mbxStatus x%x, rc = x%x\n",
+ phba->brd_no, vport->vpi,
+ mb->mbxCommand, mb->mbxStatus, rc);
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ if (rc != MBX_TIMEOUT)
+ mempool_free(pmb, phba->mbox_mem_pool);
+ return -EIO;
+ }
+
+ memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
+ memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName,
+ sizeof (struct lpfc_name));
+ memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
+ sizeof (struct lpfc_name));
+
+ lpfc_mbuf_free(phba, mp->virt, mp->phys);
+ kfree(mp);
+ mempool_free(pmb, phba->mbox_mem_pool);
+
+ return 0;
+}
+
+static int
+lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn,
+ const char *name_type)
+{
+ /* ensure that IEEE format 1 addresses
+ * contain zeros in bits 59-48
+ */
+ if (!((wwn->u.wwn[0] >> 4) == 1 &&
+ ((wwn->u.wwn[0] & 0xf) != 0 || (wwn->u.wwn[1] & 0xf) != 0)))
+ return 1;
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1822 Invalid %s: %02x:%02x:%02x:%02x:"
+ "%02x:%02x:%02x:%02x\n",
+ phba->brd_no, name_type,
+ wwn->u.wwn[0], wwn->u.wwn[1],
+ wwn->u.wwn[2], wwn->u.wwn[3],
+ wwn->u.wwn[4], wwn->u.wwn[5],
+ wwn->u.wwn[6], wwn->u.wwn[7]);
+ return 0;
+}
+
+static int
+lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
+{
+ struct lpfc_vport *vport;
+
+ list_for_each_entry(vport, &phba->port_list, listentry) {
+ if (vport == new_vport)
+ continue;
+ /* If they match, return not unique */
+ if (memcmp(&vport->fc_sparam.portName,
+ &new_vport->fc_sparam.portName,
+ sizeof(struct lpfc_name)) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+int
+lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+ struct lpfc_nodelist *ndlp;
+ struct lpfc_vport *pport =
+ (struct lpfc_vport *) fc_vport->shost->hostdata;
+ struct lpfc_hba *phba = pport->phba;
+ struct lpfc_vport *vport = NULL;
+ int instance;
+ int vpi;
+ int rc = VPORT_ERROR;
+
+ if ((phba->sli_rev < 3) ||
+ !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1808 Create VPORT failed: "
+ "NPIV is not enabled: SLImode:%d\n",
+ phba->brd_no, phba->sli_rev);
+ rc = VPORT_INVAL;
+ goto error_out;
+ }
+
+ vpi = lpfc_alloc_vpi(phba);
+ if (vpi == 0) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1809 Create VPORT failed: "
+ "Max VPORTs (%d) exceeded\n",
+ phba->brd_no, phba->max_vpi);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+
+ /* Assign an unused board number */
+ if ((instance = lpfc_get_instance()) < 0) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1810 Create VPORT failed: Cannot get "
+ "instance number\n", phba->brd_no);
+ lpfc_free_vpi(phba, vpi);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+ vport = lpfc_create_port(phba, instance, fc_vport);
+ if (!vport) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1811 Create VPORT failed: vpi x%x\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+ vport->vpi = vpi;
+ lpfc_debugfs_initialize(vport);
+
+ if (lpfc_vport_sparm(phba, vport)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1813 Create VPORT failed: vpi:%d "
+ "Cannot get sparam\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ destroy_port(vport);
+ rc = VPORT_NORESOURCES;
+ goto error_out;
+ }
+
+ memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8);
+ memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8);
+
+ if (fc_vport->node_name != 0)
+ u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn);
+ if (fc_vport->port_name != 0)
+ u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn);
+
+ memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8);
+ memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8);
+
+ if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") ||
+ !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1821 Create VPORT failed: vpi:%d "
+ "Invalid WWN format\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ destroy_port(vport);
+ rc = VPORT_INVAL;
+ goto error_out;
+ }
+
+ if (!lpfc_unique_wwpn(phba, vport)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1823 Create VPORT failed: vpi:%d "
+ "Duplicate WWN on HBA\n",
+ phba->brd_no, vpi);
+ lpfc_free_vpi(phba, vpi);
+ destroy_port(vport);
+ rc = VPORT_INVAL;
+ goto error_out;
+ }
+
+ *(struct lpfc_vport **)fc_vport->dd_data = vport;
+ vport->fc_vport = fc_vport;
+
+ if ((phba->link_state < LPFC_LINK_UP) ||
+ (phba->fc_topology == TOPOLOGY_LOOP)) {
+ lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+ rc = VPORT_OK;
+ goto out;
+ }
+
+ if (disable) {
+ rc = VPORT_OK;
+ goto out;
+ }
+
+ /* Use the Physical nodes Fabric NDLP to determine if the link is
+ * up and ready to FDISC.
+ */
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
+ lpfc_set_disctmo(vport);
+ lpfc_initial_fdisc(vport);
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0262 No NPIV Fabric "
+ "support\n",
+ phba->brd_no, vport->vpi);
+ }
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ }
+ rc = VPORT_OK;
+
+out:
+ lpfc_host_attrib_init(lpfc_shost_from_vport(vport));
+error_out:
+ return rc;
+}
+
+int
+disable_vport(struct fc_vport *fc_vport)
+{
+ struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL;
+ long timeout;
+
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (ndlp && phba->link_state >= LPFC_LINK_UP) {
+ vport->unreg_vpi_cmpl = VPORT_INVAL;
+ timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+ if (!lpfc_issue_els_npiv_logo(vport, ndlp))
+ while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
+ timeout = schedule_timeout(timeout);
+ }
+
+ lpfc_sli_host_down(vport);
+
+ /* Mark all nodes for discovery so we can remove them by
+ * calling lpfc_cleanup_rpis(vport, 1)
+ */
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+ continue;
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RECOVERY);
+ }
+ lpfc_cleanup_rpis(vport, 1);
+
+ lpfc_stop_vport_timers(vport);
+ lpfc_unreg_all_rpis(vport);
+ lpfc_unreg_default_rpis(vport);
+ /*
+ * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
+ * scsi_host_put() to release the vport.
+ */
+ lpfc_mbx_unreg_vpi(vport);
+
+ lpfc_vport_set_state(vport, FC_VPORT_DISABLED);
+ return VPORT_OK;
+}
+
+int
+enable_vport(struct fc_vport *fc_vport)
+{
+ struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+ struct lpfc_hba *phba = vport->phba;
+ struct lpfc_nodelist *ndlp = NULL;
+
+ if ((phba->link_state < LPFC_LINK_UP) ||
+ (phba->fc_topology == TOPOLOGY_LOOP)) {
+ lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN);
+ return VPORT_OK;
+ }
+
+ vport->load_flag |= FC_LOADING;
+ vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+
+ /* Use the Physical nodes Fabric NDLP to determine if the link is
+ * up and ready to FDISC.
+ */
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) {
+ if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) {
+ lpfc_set_disctmo(vport);
+ lpfc_initial_fdisc(vport);
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
+ lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
+ "%d (%d):0264 No NPIV Fabric "
+ "support\n",
+ phba->brd_no, vport->vpi);
+ }
+ } else {
+ lpfc_vport_set_state(vport, FC_VPORT_FAILED);
+ }
+
+ return VPORT_OK;
+}
+
+int
+lpfc_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+ if (disable)
+ return disable_vport(fc_vport);
+ else
+ return enable_vport(fc_vport);
+}
+
+
+int
+lpfc_vport_delete(struct fc_vport *fc_vport)
+{
+ struct lpfc_nodelist *ndlp = NULL;
+ struct lpfc_nodelist *next_ndlp;
+ struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost;
+ struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
+ struct lpfc_hba *phba = vport->phba;
+ long timeout;
+ int rc = VPORT_ERROR;
+
+ /*
+ * This is a bit of a mess. We want to ensure the shost doesn't get
+ * torn down until we're done with the embedded lpfc_vport structure.
+ *
+ * Beyond holding a reference for this function, we also need a
+ * reference for outstanding I/O requests we schedule during delete
+ * processing. But once we scsi_remove_host() we can no longer obtain
+ * a reference through scsi_host_get().
+ *
+ * So we take two references here. We release one reference at the
+ * bottom of the function -- after delinking the vport. And we
+ * release the other at the completion of the unreg_vpi that get's
+ * initiated after we've disposed of all other resources associated
+ * with the port.
+ */
+ if (!scsi_host_get(shost) || !scsi_host_get(shost))
+ return VPORT_INVAL;
+
+ if (vport->port_type == LPFC_PHYSICAL_PORT) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
+ "%d:1812 vport_delete failed: Cannot delete "
+ "physical host\n", phba->brd_no);
+ goto out;
+ }
+
+ vport->load_flag |= FC_UNLOADING;
+
+ kfree(vport->vname);
+ lpfc_debugfs_terminate(vport);
+ fc_remove_host(lpfc_shost_from_vport(vport));
+ scsi_remove_host(lpfc_shost_from_vport(vport));
+
+ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID);
+ if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE &&
+ phba->link_state >= LPFC_LINK_UP) {
+
+ /* First look for the Fabric ndlp */
+ ndlp = lpfc_findnode_did(vport, Fabric_DID);
+ if (!ndlp) {
+ /* Cannot find existing Fabric ndlp, allocate one */
+ ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+ if (!ndlp)
+ goto skip_logo;
+ lpfc_nlp_init(vport, ndlp, Fabric_DID);
+ } else {
+ lpfc_dequeue_node(vport, ndlp);
+ }
+ vport->unreg_vpi_cmpl = VPORT_INVAL;
+ timeout = msecs_to_jiffies(phba->fc_ratov * 2000);
+ if (!lpfc_issue_els_npiv_logo(vport, ndlp))
+ while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout)
+ timeout = schedule_timeout(timeout);
+ }
+
+skip_logo:
+ lpfc_sli_host_down(vport);
+
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RECOVERY);
+ lpfc_disc_state_machine(vport, ndlp, NULL,
+ NLP_EVT_DEVICE_RM);
+ }
+
+ lpfc_stop_vport_timers(vport);
+ lpfc_unreg_all_rpis(vport);
+ lpfc_unreg_default_rpis(vport);
+ /*
+ * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the
+ * scsi_host_put() to release the vport.
+ */
+ lpfc_mbx_unreg_vpi(vport);
+
+ lpfc_free_vpi(phba, vport->vpi);
+ vport->work_port_events = 0;
+ spin_lock_irq(&phba->hbalock);
+ list_del_init(&vport->listentry);
+ spin_unlock_irq(&phba->hbalock);
+
+ rc = VPORT_OK;
+out:
+ scsi_host_put(shost);
+ return rc;
+}
+
+
+EXPORT_SYMBOL(lpfc_vport_create);
+EXPORT_SYMBOL(lpfc_vport_delete);
diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
new file mode 100644
index 000000000000..f223550f8cba
--- /dev/null
+++ b/drivers/scsi/lpfc/lpfc_vport.h
@@ -0,0 +1,113 @@
+/*******************************************************************
+ * This file is part of the Emulex Linux Device Driver for *
+ * Fibre Channel Host Bus Adapters. *
+ * Copyright (C) 2004-2006 Emulex. All rights reserved. *
+ * EMULEX and SLI are trademarks of Emulex. *
+ * www.emulex.com *
+ * Portions Copyright (C) 2004-2005 Christoph Hellwig *
+ * *
+ * This program is free software; you can redistribute it and/or *
+ * modify it under the terms of version 2 of the GNU General *
+ * Public License as published by the Free Software Foundation. *
+ * This program is distributed in the hope that it will be useful. *
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
+ * TO BE LEGALLY INVALID. See the GNU General Public License for *
+ * more details, a copy of which can be found in the file COPYING *
+ * included with this package. *
+ *******************************************************************/
+
+#ifndef _H_LPFC_VPORT
+#define _H_LPFC_VPORT
+
+/* API version values (each will be an individual bit) */
+#define VPORT_API_VERSION_1 0x01
+
+/* Values returned via lpfc_vport_getinfo() */
+struct vport_info {
+
+ uint32_t api_versions;
+ uint8_t linktype;
+#define VPORT_TYPE_PHYSICAL 0
+#define VPORT_TYPE_VIRTUAL 1
+
+ uint8_t state;
+#define VPORT_STATE_OFFLINE 0
+#define VPORT_STATE_ACTIVE 1
+#define VPORT_STATE_FAILED 2
+
+ uint8_t fail_reason;
+ uint8_t prev_fail_reason;
+#define VPORT_FAIL_UNKNOWN 0
+#define VPORT_FAIL_LINKDOWN 1
+#define VPORT_FAIL_FAB_UNSUPPORTED 2
+#define VPORT_FAIL_FAB_NORESOURCES 3
+#define VPORT_FAIL_FAB_LOGOUT 4
+#define VPORT_FAIL_ADAP_NORESOURCES 5
+
+ uint8_t node_name[8]; /* WWNN */
+ uint8_t port_name[8]; /* WWPN */
+
+ struct Scsi_Host *shost;
+
+/* Following values are valid only on physical links */
+ uint32_t vports_max;
+ uint32_t vports_inuse;
+ uint32_t rpi_max;
+ uint32_t rpi_inuse;
+#define VPORT_CNT_INVALID 0xFFFFFFFF
+};
+
+/* data used in link creation */
+struct vport_data {
+ uint32_t api_version;
+
+ uint32_t options;
+#define VPORT_OPT_AUTORETRY 0x01
+
+ uint8_t node_name[8]; /* WWNN */
+ uint8_t port_name[8]; /* WWPN */
+
+/*
+ * Upon successful creation, vport_shost will point to the new Scsi_Host
+ * structure for the new virtual link.
+ */
+ struct Scsi_Host *vport_shost;
+};
+
+/* API function return codes */
+#define VPORT_OK 0
+#define VPORT_ERROR -1
+#define VPORT_INVAL -2
+#define VPORT_NOMEM -3
+#define VPORT_NORESOURCES -4
+
+int lpfc_vport_create(struct fc_vport *, bool);
+int lpfc_vport_delete(struct fc_vport *);
+int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
+int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
+
+/*
+ * queuecommand VPORT-specific return codes. Specified in the host byte code.
+ * Returned when the virtual link has failed or is not active.
+ */
+#define DID_VPORT_ERROR 0x0f
+
+#define VPORT_INFO 0x1
+#define VPORT_CREATE 0x2
+#define VPORT_DELETE 0x4
+
+struct vport_cmd_tag {
+ uint32_t cmd;
+ struct vport_data cdata;
+ struct vport_info cinfo;
+ void *vport;
+ int vport_num;
+};
+
+void lpfc_vport_set_state(struct lpfc_vport *vport,
+ enum fc_vport_state new_state);
+
+#endif /* H_LPFC_VPORT */
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 5806ede120a4..b12ad7c7c673 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -77,7 +77,7 @@ static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *
for (i = 0; i < cmd->cmd_len; ++i)
printk(" %.2x", cmd->cmnd[i]);
printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
- cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+ scsi_sg_count(cmd), scsi_bufflen(cmd), scsi_sglist(cmd));
}
#endif
@@ -173,8 +173,7 @@ static void mac53c94_start(struct fsc_state *state)
writeb(CMD_SELECT, &regs->command);
state->phase = selecting;
- if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
- set_dma_cmds(state, cmd);
+ set_dma_cmds(state, cmd);
}
static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id)
@@ -262,7 +261,7 @@ static void mac53c94_interrupt(int irq, void *dev_id)
writeb(CMD_NOP, &regs->command);
/* set DMA controller going if any data to transfer */
if ((stat & (STAT_MSG|STAT_CD)) == 0
- && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) {
+ && (scsi_sg_count(cmd) > 0 || scsi_bufflen(cmd))) {
nb = cmd->SCp.this_residual;
if (nb > 0xfff0)
nb = 0xfff0;
@@ -310,14 +309,7 @@ static void mac53c94_interrupt(int irq, void *dev_id)
printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
}
writel(RUN << 16, &dma->control); /* stop dma */
- if (cmd->use_sg != 0) {
- pci_unmap_sg(state->pdev,
- (struct scatterlist *)cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else {
- pci_unmap_single(state->pdev, state->dma_addr,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
/* should check dma status */
writeb(CMD_I_COMPLETE, &regs->command);
state->phase = completing;
@@ -365,47 +357,35 @@ static void cmd_done(struct fsc_state *state, int result)
*/
static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
{
- int i, dma_cmd, total;
+ int i, dma_cmd, total, nseg;
struct scatterlist *scl;
struct dbdma_cmd *dcmds;
dma_addr_t dma_addr;
u32 dma_len;
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+ if (!nseg)
+ return;
+
dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ?
OUTPUT_MORE : INPUT_MORE;
dcmds = state->dma_cmds;
- if (cmd->use_sg > 0) {
- int nseg;
-
- total = 0;
- scl = (struct scatterlist *) cmd->request_buffer;
- nseg = pci_map_sg(state->pdev, scl, cmd->use_sg,
- cmd->sc_data_direction);
- for (i = 0; i < nseg; ++i) {
- dma_addr = sg_dma_address(scl);
- dma_len = sg_dma_len(scl);
- if (dma_len > 0xffff)
- panic("mac53c94: scatterlist element >= 64k");
- total += dma_len;
- st_le16(&dcmds->req_count, dma_len);
- st_le16(&dcmds->command, dma_cmd);
- st_le32(&dcmds->phy_addr, dma_addr);
- dcmds->xfer_status = 0;
- ++scl;
- ++dcmds;
- }
- } else {
- total = cmd->request_bufflen;
- if (total > 0xffff)
- panic("mac53c94: transfer size >= 64k");
- dma_addr = pci_map_single(state->pdev, cmd->request_buffer,
- total, cmd->sc_data_direction);
- state->dma_addr = dma_addr;
- st_le16(&dcmds->req_count, total);
+ total = 0;
+
+ scsi_for_each_sg(cmd, scl, nseg, i) {
+ dma_addr = sg_dma_address(scl);
+ dma_len = sg_dma_len(scl);
+ if (dma_len > 0xffff)
+ panic("mac53c94: scatterlist element >= 64k");
+ total += dma_len;
+ st_le16(&dcmds->req_count, dma_len);
+ st_le16(&dcmds->command, dma_cmd);
st_le32(&dcmds->phy_addr, dma_addr);
dcmds->xfer_status = 0;
++dcmds;
}
+
dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
st_le16(&dcmds[-1].command, dma_cmd);
st_le16(&dcmds->command, DBDMA_STOP);
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 3cce75d70263..3907f6718ede 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -523,10 +523,8 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
/*
* filter the internal and ioctl commands
*/
- if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) {
- return cmd->request_buffer;
- }
-
+ if((cmd->cmnd[0] == MEGA_INTERNAL_CMD))
+ return (scb_t *)cmd->host_scribble;
/*
* We know what channels our logical drives are on - mega_find_card()
@@ -657,22 +655,14 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
case MODE_SENSE: {
char *buf;
+ struct scatterlist *sg;
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ sg = scsi_sglist(cmd);
+ buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
- sg = (struct scatterlist *)cmd->request_buffer;
- buf = kmap_atomic(sg->page, KM_IRQ0) +
- sg->offset;
- } else
- buf = cmd->request_buffer;
memset(buf, 0, cmd->cmnd[4]);
- if (cmd->use_sg) {
- struct scatterlist *sg;
+ kunmap_atomic(buf - sg->offset, KM_IRQ0);
- sg = (struct scatterlist *)cmd->request_buffer;
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
- }
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
@@ -1551,23 +1541,15 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
islogical = adapter->logdrv_chan[cmd->device->channel];
if( cmd->cmnd[0] == INQUIRY && !islogical ) {
- if( cmd->use_sg ) {
- sgl = (struct scatterlist *)
- cmd->request_buffer;
-
- if( sgl->page ) {
- c = *(unsigned char *)
+ sgl = scsi_sglist(cmd);
+ if( sgl->page ) {
+ c = *(unsigned char *)
page_address((&sgl[0])->page) +
(&sgl[0])->offset;
- }
- else {
- printk(KERN_WARNING
- "megaraid: invalid sg.\n");
- c = 0;
- }
- }
- else {
- c = *(u8 *)cmd->request_buffer;
+ } else {
+ printk(KERN_WARNING
+ "megaraid: invalid sg.\n");
+ c = 0;
}
if(IS_RAID_CH(adapter, cmd->device->channel) &&
@@ -1704,30 +1686,14 @@ mega_rundoneq (adapter_t *adapter)
static void
mega_free_scb(adapter_t *adapter, scb_t *scb)
{
- unsigned long length;
-
switch( scb->dma_type ) {
case MEGA_DMA_TYPE_NONE:
break;
- case MEGA_BULK_DATA:
- if (scb->cmd->use_sg == 0)
- length = scb->cmd->request_bufflen;
- else {
- struct scatterlist *sgl =
- (struct scatterlist *)scb->cmd->request_buffer;
- length = sgl->length;
- }
- pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
- length, scb->dma_direction);
- break;
-
case MEGA_SGLIST:
- pci_unmap_sg(adapter->dev, scb->cmd->request_buffer,
- scb->cmd->use_sg, scb->dma_direction);
+ scsi_dma_unmap(scb->cmd);
break;
-
default:
break;
}
@@ -1767,80 +1733,33 @@ __mega_busywait_mbox (adapter_t *adapter)
static int
mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
{
- struct scatterlist *sgl;
- struct page *page;
- unsigned long offset;
- unsigned int length;
+ struct scatterlist *sg;
Scsi_Cmnd *cmd;
int sgcnt;
int idx;
cmd = scb->cmd;
- /* Scatter-gather not used */
- if( cmd->use_sg == 0 || (cmd->use_sg == 1 &&
- !adapter->has_64bit_addr)) {
-
- if (cmd->use_sg == 0) {
- page = virt_to_page(cmd->request_buffer);
- offset = offset_in_page(cmd->request_buffer);
- length = cmd->request_bufflen;
- } else {
- sgl = (struct scatterlist *)cmd->request_buffer;
- page = sgl->page;
- offset = sgl->offset;
- length = sgl->length;
- }
-
- scb->dma_h_bulkdata = pci_map_page(adapter->dev,
- page, offset,
- length,
- scb->dma_direction);
- scb->dma_type = MEGA_BULK_DATA;
-
- /*
- * We need to handle special 64-bit commands that need a
- * minimum of 1 SG
- */
- if( adapter->has_64bit_addr ) {
- scb->sgl64[0].address = scb->dma_h_bulkdata;
- scb->sgl64[0].length = length;
- *buf = (u32)scb->sgl_dma_addr;
- *len = (u32)length;
- return 1;
- }
- else {
- *buf = (u32)scb->dma_h_bulkdata;
- *len = (u32)length;
- }
- return 0;
- }
-
- sgl = (struct scatterlist *)cmd->request_buffer;
-
/*
* Copy Scatter-Gather list info into controller structure.
*
* The number of sg elements returned must not exceed our limit
*/
- sgcnt = pci_map_sg(adapter->dev, sgl, cmd->use_sg,
- scb->dma_direction);
+ sgcnt = scsi_dma_map(cmd);
scb->dma_type = MEGA_SGLIST;
- BUG_ON(sgcnt > adapter->sglen);
+ BUG_ON(sgcnt > adapter->sglen || sgcnt < 0);
*len = 0;
- for( idx = 0; idx < sgcnt; idx++, sgl++ ) {
-
- if( adapter->has_64bit_addr ) {
- scb->sgl64[idx].address = sg_dma_address(sgl);
- *len += scb->sgl64[idx].length = sg_dma_len(sgl);
- }
- else {
- scb->sgl[idx].address = sg_dma_address(sgl);
- *len += scb->sgl[idx].length = sg_dma_len(sgl);
+ scsi_for_each_sg(cmd, sg, sgcnt, idx) {
+ if (adapter->has_64bit_addr) {
+ scb->sgl64[idx].address = sg_dma_address(sg);
+ *len += scb->sgl64[idx].length = sg_dma_len(sg);
+ } else {
+ scb->sgl[idx].address = sg_dma_address(sg);
+ *len += scb->sgl[idx].length = sg_dma_len(sg);
}
}
@@ -3571,7 +3490,7 @@ megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
/*
* The user passthru structure
*/
- upthru = (mega_passthru __user *)MBOX(uioc)->xferaddr;
+ upthru = (mega_passthru __user *)(unsigned long)MBOX(uioc)->xferaddr;
/*
* Copy in the user passthru here.
@@ -3623,7 +3542,7 @@ megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
/*
* Get the user data
*/
- if( copy_from_user(data, (char __user *)uxferaddr,
+ if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr,
pthru->dataxferlen) ) {
rval = (-EFAULT);
goto freemem_and_return;
@@ -3649,7 +3568,7 @@ megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
* Is data going up-stream
*/
if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char __user *)uxferaddr, data,
+ if( copy_to_user((char __user *)(unsigned long) uxferaddr, data,
pthru->dataxferlen) ) {
rval = (-EFAULT);
}
@@ -3702,7 +3621,7 @@ freemem_and_return:
/*
* Get the user data
*/
- if( copy_from_user(data, (char __user *)uxferaddr,
+ if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr,
uioc.xferlen) ) {
pci_free_consistent(pdev,
@@ -3742,7 +3661,7 @@ freemem_and_return:
* Is data going up-stream
*/
if( uioc.xferlen && (uioc.flags & UIOC_RD) ) {
- if( copy_to_user((char __user *)uxferaddr, data,
+ if( copy_to_user((char __user *)(unsigned long) uxferaddr, data,
uioc.xferlen) ) {
rval = (-EFAULT);
@@ -4494,7 +4413,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru)
scmd->device = sdev;
scmd->device->host = adapter->host;
- scmd->request_buffer = (void *)scb;
+ scmd->host_scribble = (void *)scb;
scmd->cmnd[0] = MEGA_INTERNAL_CMD;
scb->state |= SCB_ACTIVE;
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 26e1e6c55654..fef9ac958754 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -21,6 +21,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 04d0b6918c61..c6a53dccc16a 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -454,7 +454,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_master(pdev);
// Allocate the per driver initialization structure
- adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL);
+ adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL);
if (adapter == NULL) {
con_log(CL_ANN, (KERN_WARNING
@@ -462,7 +462,6 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_probe_one;
}
- memset(adapter, 0, sizeof(adapter_t));
// set up PCI related soft state and other pre-known parameters
@@ -746,10 +745,9 @@ megaraid_init_mbox(adapter_t *adapter)
* Allocate and initialize the init data structure for mailbox
* controllers
*/
- raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL);
+ raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL);
if (raid_dev == NULL) return -1;
- memset(raid_dev, 0, sizeof(mraid_device_t));
/*
* Attach the adapter soft state to raid device soft state
@@ -1050,8 +1048,7 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
* since the calling routine does not yet know the number of available
* commands.
*/
- adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS,
- GFP_KERNEL);
+ adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL);
if (adapter->kscb_list == NULL) {
con_log(CL_ANN, (KERN_WARNING
@@ -1059,7 +1056,6 @@ megaraid_alloc_cmd_packets(adapter_t *adapter)
__LINE__));
goto out_free_ibuf;
}
- memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS);
// memory allocation for our command packets
if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
@@ -1378,8 +1374,6 @@ megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
{
struct scatterlist *sgl;
mbox_ccb_t *ccb;
- struct page *page;
- unsigned long offset;
struct scsi_cmnd *scp;
int sgcnt;
int i;
@@ -1388,48 +1382,16 @@ megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
scp = scb->scp;
ccb = (mbox_ccb_t *)scb->ccb;
+ sgcnt = scsi_dma_map(scp);
+ BUG_ON(sgcnt < 0 || sgcnt > adapter->sglen);
+
// no mapping required if no data to be transferred
- if (!scp->request_buffer || !scp->request_bufflen)
+ if (!sgcnt)
return 0;
- if (!scp->use_sg) { /* scatter-gather list not used */
-
- page = virt_to_page(scp->request_buffer);
-
- offset = ((unsigned long)scp->request_buffer & ~PAGE_MASK);
-
- ccb->buf_dma_h = pci_map_page(adapter->pdev, page, offset,
- scp->request_bufflen,
- scb->dma_direction);
- scb->dma_type = MRAID_DMA_WBUF;
-
- /*
- * We need to handle special 64-bit commands that need a
- * minimum of 1 SG
- */
- sgcnt = 1;
- ccb->sgl64[0].address = ccb->buf_dma_h;
- ccb->sgl64[0].length = scp->request_bufflen;
-
- return sgcnt;
- }
-
- sgl = (struct scatterlist *)scp->request_buffer;
-
- // The number of sg elements returned must not exceed our limit
- sgcnt = pci_map_sg(adapter->pdev, sgl, scp->use_sg,
- scb->dma_direction);
-
- if (sgcnt > adapter->sglen) {
- con_log(CL_ANN, (KERN_CRIT
- "megaraid critical: too many sg elements:%d\n",
- sgcnt));
- BUG();
- }
-
scb->dma_type = MRAID_DMA_WSG;
- for (i = 0; i < sgcnt; i++, sgl++) {
+ scsi_for_each_sg(scp, sgl, sgcnt, i) {
ccb->sgl64[i].address = sg_dma_address(sgl);
ccb->sgl64[i].length = sg_dma_len(sgl);
}
@@ -1489,19 +1451,11 @@ mbox_post_cmd(adapter_t *adapter, scb_t *scb)
adapter->outstanding_cmds++;
- if (scb->dma_direction == PCI_DMA_TODEVICE) {
- if (!scb->scp->use_sg) { // sg list not used
- pci_dma_sync_single_for_device(adapter->pdev,
- ccb->buf_dma_h,
- scb->scp->request_bufflen,
- PCI_DMA_TODEVICE);
- }
- else {
- pci_dma_sync_sg_for_device(adapter->pdev,
- scb->scp->request_buffer,
- scb->scp->use_sg, PCI_DMA_TODEVICE);
- }
- }
+ if (scb->dma_direction == PCI_DMA_TODEVICE)
+ pci_dma_sync_sg_for_device(adapter->pdev,
+ scsi_sglist(scb->scp),
+ scsi_sg_count(scb->scp),
+ PCI_DMA_TODEVICE);
mbox->busy = 1; // Set busy
mbox->poll = 0;
@@ -1624,29 +1578,26 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
return scb;
case MODE_SENSE:
- if (scp->use_sg) {
- struct scatterlist *sgl;
- caddr_t vaddr;
+ {
+ struct scatterlist *sgl;
+ caddr_t vaddr;
- sgl = (struct scatterlist *)scp->request_buffer;
- if (sgl->page) {
- vaddr = (caddr_t)
- (page_address((&sgl[0])->page)
- + (&sgl[0])->offset);
+ sgl = scsi_sglist(scp);
+ if (sgl->page) {
+ vaddr = (caddr_t)
+ (page_address((&sgl[0])->page)
+ + (&sgl[0])->offset);
- memset(vaddr, 0, scp->cmnd[4]);
- }
- else {
- con_log(CL_ANN, (KERN_WARNING
- "megaraid mailbox: invalid sg:%d\n",
- __LINE__));
- }
+ memset(vaddr, 0, scp->cmnd[4]);
}
else {
- memset(scp->request_buffer, 0, scp->cmnd[4]);
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid mailbox: invalid sg:%d\n",
+ __LINE__));
}
- scp->result = (DID_OK << 16);
- return NULL;
+ }
+ scp->result = (DID_OK << 16);
+ return NULL;
case INQUIRY:
/*
@@ -1716,7 +1667,7 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
mbox->cmd = MBOXCMD_PASSTHRU64;
scb->dma_direction = scp->sc_data_direction;
- pthru->dataxferlen = scp->request_bufflen;
+ pthru->dataxferlen = scsi_bufflen(scp);
pthru->dataxferaddr = ccb->sgl_dma_h;
pthru->numsge = megaraid_mbox_mksgl(adapter,
scb);
@@ -2050,8 +2001,8 @@ megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb,
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
- if (scp->request_bufflen) {
- pthru->dataxferlen = scp->request_bufflen;
+ if (scsi_bufflen(scp)) {
+ pthru->dataxferlen = scsi_bufflen(scp);
pthru->dataxferaddr = ccb->sgl_dma_h;
pthru->numsge = megaraid_mbox_mksgl(adapter, scb);
}
@@ -2099,8 +2050,8 @@ megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
memcpy(epthru->cdb, scp->cmnd, scp->cmd_len);
- if (scp->request_bufflen) {
- epthru->dataxferlen = scp->request_bufflen;
+ if (scsi_bufflen(scp)) {
+ epthru->dataxferlen = scsi_bufflen(scp);
epthru->dataxferaddr = ccb->sgl_dma_h;
epthru->numsge = megaraid_mbox_mksgl(adapter, scb);
}
@@ -2266,37 +2217,13 @@ megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
ccb = (mbox_ccb_t *)scb->ccb;
- switch (scb->dma_type) {
-
- case MRAID_DMA_WBUF:
- if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
- pci_dma_sync_single_for_cpu(adapter->pdev,
- ccb->buf_dma_h,
- scb->scp->request_bufflen,
+ if (scb->dma_direction == PCI_DMA_FROMDEVICE)
+ pci_dma_sync_sg_for_cpu(adapter->pdev,
+ scsi_sglist(scb->scp),
+ scsi_sg_count(scb->scp),
PCI_DMA_FROMDEVICE);
- }
-
- pci_unmap_page(adapter->pdev, ccb->buf_dma_h,
- scb->scp->request_bufflen, scb->dma_direction);
-
- break;
-
- case MRAID_DMA_WSG:
- if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
- pci_dma_sync_sg_for_cpu(adapter->pdev,
- scb->scp->request_buffer,
- scb->scp->use_sg, PCI_DMA_FROMDEVICE);
- }
-
- pci_unmap_sg(adapter->pdev, scb->scp->request_buffer,
- scb->scp->use_sg, scb->dma_direction);
-
- break;
-
- default:
- break;
- }
+ scsi_dma_unmap(scb->scp);
return;
}
@@ -2399,24 +2326,16 @@ megaraid_mbox_dpc(unsigned long devp)
if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0
&& IS_RAID_CH(raid_dev, scb->dev_channel)) {
- if (scp->use_sg) {
- sgl = (struct scatterlist *)
- scp->request_buffer;
-
- if (sgl->page) {
- c = *(unsigned char *)
+ sgl = scsi_sglist(scp);
+ if (sgl->page) {
+ c = *(unsigned char *)
(page_address((&sgl[0])->page) +
- (&sgl[0])->offset);
- }
- else {
- con_log(CL_ANN, (KERN_WARNING
- "megaraid mailbox: invalid sg:%d\n",
- __LINE__));
- c = 0;
- }
- }
- else {
- c = *(uint8_t *)scp->request_buffer;
+ (&sgl[0])->offset);
+ } else {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid mailbox: invalid sg:%d\n",
+ __LINE__));
+ c = 0;
}
if ((c & 0x1F ) == TYPE_DISK) {
@@ -3572,8 +3491,7 @@ megaraid_cmm_register(adapter_t *adapter)
int i;
// Allocate memory for the base list of scb for management module.
- adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS,
- GFP_KERNEL);
+ adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL);
if (adapter->uscb_list == NULL) {
con_log(CL_ANN, (KERN_WARNING
@@ -3581,7 +3499,6 @@ megaraid_cmm_register(adapter_t *adapter)
__LINE__));
return -1;
}
- memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS);
// Initialize the synchronization parameters for resources for
@@ -3957,7 +3874,7 @@ megaraid_sysfs_alloc_resources(adapter_t *adapter)
megaraid_sysfs_free_resources(adapter);
}
- sema_init(&raid_dev->sysfs_sem, 1);
+ mutex_init(&raid_dev->sysfs_mtx);
init_waitqueue_head(&raid_dev->sysfs_wait_q);
@@ -4058,7 +3975,7 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
/*
* Allow only one read at a time to go through the sysfs attributes
*/
- down(&raid_dev->sysfs_sem);
+ mutex_lock(&raid_dev->sysfs_mtx);
uioc = raid_dev->sysfs_uioc;
mbox64 = raid_dev->sysfs_mbox64;
@@ -4134,7 +4051,7 @@ megaraid_sysfs_get_ldmap(adapter_t *adapter)
del_timer_sync(timerp);
- up(&raid_dev->sysfs_sem);
+ mutex_unlock(&raid_dev->sysfs_mtx);
return rval;
}
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 9de803cebd4b..626459d1e902 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -168,7 +168,7 @@ typedef struct {
* @hw_error : set if FW not responding
* @fast_load : If set, skip physical device scanning
* @channel_class : channel class, RAID or SCSI
- * @sysfs_sem : semaphore to serialize access to sysfs res.
+ * @sysfs_mtx : mutex to serialize access to sysfs res.
* @sysfs_uioc : management packet to issue FW calls from sysfs
* @sysfs_mbox64 : mailbox packet to issue FW calls from sysfs
* @sysfs_buffer : data buffer for FW commands issued from sysfs
@@ -208,7 +208,7 @@ typedef struct {
int hw_error;
int fast_load;
uint8_t channel_class;
- struct semaphore sysfs_sem;
+ struct mutex sysfs_mtx;
uioc_t *sysfs_uioc;
mbox64_t *sysfs_mbox64;
caddr_t sysfs_buffer;
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index 84d9c27133d4..b6587a6d8486 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -890,12 +890,11 @@ mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
if (lld_adp->drvr_type != DRVRTYPE_MBOX)
return (-EINVAL);
- adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
+ adapter = kzalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
if (!adapter)
return -ENOMEM;
- memset(adapter, 0, sizeof(mraid_mmadp_t));
adapter->unique_id = lld_adp->unique_id;
adapter->drvr_type = lld_adp->drvr_type;
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index e2cf12ef3688..ebb948c016bb 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -433,34 +433,15 @@ megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
int sge_count;
struct scatterlist *os_sgl;
- /*
- * Return 0 if there is no data transfer
- */
- if (!scp->request_buffer || !scp->request_bufflen)
- return 0;
+ sge_count = scsi_dma_map(scp);
+ BUG_ON(sge_count < 0);
- if (!scp->use_sg) {
- mfi_sgl->sge32[0].phys_addr = pci_map_single(instance->pdev,
- scp->
- request_buffer,
- scp->
- request_bufflen,
- scp->
- sc_data_direction);
- mfi_sgl->sge32[0].length = scp->request_bufflen;
-
- return 1;
- }
-
- os_sgl = (struct scatterlist *)scp->request_buffer;
- sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
- scp->sc_data_direction);
-
- for (i = 0; i < sge_count; i++, os_sgl++) {
- mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
- mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+ if (sge_count) {
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
+ mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+ }
}
-
return sge_count;
}
@@ -481,35 +462,15 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
int sge_count;
struct scatterlist *os_sgl;
- /*
- * Return 0 if there is no data transfer
- */
- if (!scp->request_buffer || !scp->request_bufflen)
- return 0;
-
- if (!scp->use_sg) {
- mfi_sgl->sge64[0].phys_addr = pci_map_single(instance->pdev,
- scp->
- request_buffer,
- scp->
- request_bufflen,
- scp->
- sc_data_direction);
-
- mfi_sgl->sge64[0].length = scp->request_bufflen;
-
- return 1;
- }
-
- os_sgl = (struct scatterlist *)scp->request_buffer;
- sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
- scp->sc_data_direction);
+ sge_count = scsi_dma_map(scp);
+ BUG_ON(sge_count < 0);
- for (i = 0; i < sge_count; i++, os_sgl++) {
- mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
- mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+ if (sge_count) {
+ scsi_for_each_sg(scp, os_sgl, sge_count, i) {
+ mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
+ mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+ }
}
-
return sge_count;
}
@@ -593,7 +554,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
pthru->cdb_len = scp->cmd_len;
pthru->timeout = 0;
pthru->flags = flags;
- pthru->data_xfer_len = scp->request_bufflen;
+ pthru->data_xfer_len = scsi_bufflen(scp);
memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
@@ -1195,45 +1156,6 @@ megasas_complete_abort(struct megasas_instance *instance,
}
/**
- * megasas_unmap_sgbuf - Unmap SG buffers
- * @instance: Adapter soft state
- * @cmd: Completed command
- */
-static void
-megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
-{
- dma_addr_t buf_h;
- u8 opcode;
-
- if (cmd->scmd->use_sg) {
- pci_unmap_sg(instance->pdev, cmd->scmd->request_buffer,
- cmd->scmd->use_sg, cmd->scmd->sc_data_direction);
- return;
- }
-
- if (!cmd->scmd->request_bufflen)
- return;
-
- opcode = cmd->frame->hdr.cmd;
-
- if ((opcode == MFI_CMD_LD_READ) || (opcode == MFI_CMD_LD_WRITE)) {
- if (IS_DMA64)
- buf_h = cmd->frame->io.sgl.sge64[0].phys_addr;
- else
- buf_h = cmd->frame->io.sgl.sge32[0].phys_addr;
- } else {
- if (IS_DMA64)
- buf_h = cmd->frame->pthru.sgl.sge64[0].phys_addr;
- else
- buf_h = cmd->frame->pthru.sgl.sge32[0].phys_addr;
- }
-
- pci_unmap_single(instance->pdev, buf_h, cmd->scmd->request_bufflen,
- cmd->scmd->sc_data_direction);
- return;
-}
-
-/**
* megasas_complete_cmd - Completes a command
* @instance: Adapter soft state
* @cmd: Command to be completed
@@ -1281,7 +1203,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
atomic_dec(&instance->fw_outstanding);
- megasas_unmap_sgbuf(instance, cmd);
+ scsi_dma_unmap(cmd->scmd);
cmd->scmd->scsi_done(cmd->scmd);
megasas_return_cmd(instance, cmd);
@@ -1329,7 +1251,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
atomic_dec(&instance->fw_outstanding);
- megasas_unmap_sgbuf(instance, cmd);
+ scsi_dma_unmap(cmd->scmd);
cmd->scmd->scsi_done(cmd->scmd);
megasas_return_cmd(instance, cmd);
@@ -1714,15 +1636,13 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
* Allocate the dynamic array first and then allocate individual
* commands.
*/
- instance->cmd_list = kmalloc(sizeof(struct megasas_cmd *) * max_cmd,
- GFP_KERNEL);
+ instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
if (!instance->cmd_list) {
printk(KERN_DEBUG "megasas: out of memory\n");
return -ENOMEM;
}
- memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) * max_cmd);
for (i = 0; i < max_cmd; i++) {
instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index e64d1a19d8d7..651d09b08f2a 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -421,7 +421,7 @@ static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
for (i = 0; i < cmd->cmd_len; ++i)
printk(" %x", cmd->cmnd[i]);
printk(" use_sg=%d buffer=%p bufflen=%u\n",
- cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);
+ scsi_sg_count(cmd), scsi_sglist(cmd), scsi_bufflen(cmd));
}
#endif
if (ms->dma_started)
@@ -602,13 +602,16 @@ static void mesh_done(struct mesh_state *ms, int start_next)
cmd->result += (cmd->SCp.Message << 8);
if (DEBUG_TARGET(cmd)) {
printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
- cmd->result, ms->data_ptr, cmd->request_bufflen);
+ cmd->result, ms->data_ptr, scsi_bufflen(cmd));
+#if 0
+ /* needs to use sg? */
if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
&& cmd->request_buffer != 0) {
unsigned char *b = cmd->request_buffer;
printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
}
+#endif
}
cmd->SCp.this_residual -= ms->data_ptr;
mesh_completed(ms, cmd);
@@ -1265,15 +1268,18 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
dcmds = ms->dma_cmds;
dtot = 0;
if (cmd) {
- cmd->SCp.this_residual = cmd->request_bufflen;
- if (cmd->use_sg > 0) {
- int nseg;
+ int nseg;
+
+ cmd->SCp.this_residual = scsi_bufflen(cmd);
+
+ nseg = scsi_dma_map(cmd);
+ BUG_ON(nseg < 0);
+
+ if (nseg) {
total = 0;
- scl = (struct scatterlist *) cmd->request_buffer;
off = ms->data_ptr;
- nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
- cmd->sc_data_direction);
- for (i = 0; i <nseg; ++i, ++scl) {
+
+ scsi_for_each_sg(cmd, scl, nseg, i) {
u32 dma_addr = sg_dma_address(scl);
u32 dma_len = sg_dma_len(scl);
@@ -1292,16 +1298,6 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
dtot += dma_len - off;
off = 0;
}
- } else if (ms->data_ptr < cmd->request_bufflen) {
- dtot = cmd->request_bufflen - ms->data_ptr;
- if (dtot > 0xffff)
- panic("mesh: transfer size >= 64k");
- st_le16(&dcmds->req_count, dtot);
- /* XXX Use pci DMA API here ... */
- st_le32(&dcmds->phy_addr,
- virt_to_phys(cmd->request_buffer) + ms->data_ptr);
- dcmds->xfer_status = 0;
- ++dcmds;
}
}
if (dtot == 0) {
@@ -1356,18 +1352,14 @@ static void halt_dma(struct mesh_state *ms)
dumplog(ms, ms->conn_tgt);
dumpslog(ms);
#endif /* MESH_DBG */
- } else if (cmd && cmd->request_bufflen != 0 &&
- ms->data_ptr > cmd->request_bufflen) {
+ } else if (cmd && scsi_bufflen(cmd) &&
+ ms->data_ptr > scsi_bufflen(cmd)) {
printk(KERN_DEBUG "mesh: target %d overrun, "
"data_ptr=%x total=%x goes_out=%d\n",
- ms->conn_tgt, ms->data_ptr, cmd->request_bufflen,
+ ms->conn_tgt, ms->data_ptr, scsi_bufflen(cmd),
ms->tgts[ms->conn_tgt].data_goes_out);
}
- if (cmd->use_sg != 0) {
- struct scatterlist *sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- pci_unmap_sg(ms->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
ms->dma_started = 0;
}
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
deleted file mode 100644
index 575fe6f7e0ec..000000000000
--- a/drivers/scsi/mvme16x.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
- *
- * Based on work by Alan Hourihane
- */
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/mvme16xhw.h>
-#include <asm/irq.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "53c7xx.h"
-#include "mvme16x.h"
-
-#include<linux/stat.h>
-
-
-int mvme16x_scsi_detect(struct scsi_host_template *tpnt)
-{
- static unsigned char called = 0;
- int clock;
- long long options;
-
- if (!MACH_IS_MVME16x)
- return 0;
- if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
- printk ("SCSI detection disabled, SCSI chip not present\n");
- return 0;
- }
- if (called)
- return 0;
-
- tpnt->proc_name = "MVME16x";
-
- options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
-
- clock = 66000000; /* 66MHz SCSI Clock */
-
- ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000,
- 0, MVME16x_IRQ_SCSI, DMA_NONE,
- options, clock);
- called = 1;
- return 1;
-}
-
-static int mvme16x_scsi_release(struct Scsi_Host *shost)
-{
- if (shost->irq)
- free_irq(shost->irq, NULL);
- if (shost->dma_channel != 0xff)
- free_dma(shost->dma_channel);
- if (shost->io_port && shost->n_io_port)
- release_region(shost->io_port, shost->n_io_port);
- scsi_unregister(shost);
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .name = "MVME16x NCR53c710 SCSI",
- .detect = mvme16x_scsi_detect,
- .release = mvme16x_scsi_release,
- .queuecommand = NCR53c7xx_queue_command,
- .abort = NCR53c7xx_abort,
- .reset = NCR53c7xx_reset,
- .can_queue = 24,
- .this_id = 7,
- .sg_tablesize = 63,
- .cmd_per_lun = 3,
- .use_clustering = DISABLE_CLUSTERING
-};
-
-
-#include "scsi_module.c"
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
deleted file mode 100644
index 73e33b37a3f8..000000000000
--- a/drivers/scsi/mvme16x.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef MVME16x_SCSI_H
-#define MVME16x_SCSI_H
-
-#include <linux/types.h>
-
-int mvme16x_scsi_detect(struct scsi_host_template *);
-const char *NCR53c7x0_info(void);
-int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int NCR53c7xx_abort(Scsi_Cmnd *);
-int NCR53c7x0_release (struct Scsi_Host *);
-int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id);
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 3
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 24
-#endif
-
-#include <scsi/scsicam.h>
-
-#endif /* MVME16x_SCSI_H */
diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c
new file mode 100644
index 000000000000..1bdddad48571
--- /dev/null
+++ b/drivers/scsi/mvme16x_scsi.c
@@ -0,0 +1,159 @@
+/*
+ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/mvme16xhw.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("MVME16x NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+static struct scsi_host_template mvme16x_scsi_driver_template = {
+ .name = "MVME16x NCR53c710 SCSI",
+ .proc_name = "MVME16x",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct platform_device *mvme16x_scsi_device;
+
+static __devinit int
+mvme16x_probe(struct device *dev)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+
+ if (!MACH_IS_MVME16x)
+ goto out;
+
+ if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
+ printk(KERN_INFO "mvme16x-scsi: detection disabled, "
+ "SCSI chip not present\n");
+ goto out;
+ }
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "mvme16x-scsi: "
+ "Failed to allocate host data\n");
+ goto out;
+ }
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ hostdata->base = (void __iomem *)0xfff47000UL;
+ hostdata->clock = 50; /* XXX - depends on the CPU clock! */
+ hostdata->chip710 = 1;
+ hostdata->dmode_extra = DMODE_FC2;
+ hostdata->dcntl_extra = EA_710;
+ hostdata->ctest7_extra = CTEST7_TT1;
+
+ /* and register the chip */
+ host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, dev);
+ if (!host) {
+ printk(KERN_ERR "mvme16x-scsi: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+ host->this_id = 7;
+ host->base = 0xfff47000UL;
+ host->irq = MVME16x_IRQ_SCSI;
+ if (request_irq(host->irq, NCR_700_intr, 0, "mvme16x-scsi", host)) {
+ printk(KERN_ERR "mvme16x-scsi: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ /* Enable scsi chip ints */
+ {
+ volatile unsigned long v;
+
+ /* Enable scsi interrupts at level 4 in PCCchip2 */
+ v = in_be32(0xfff4202c);
+ v = (v & ~0xff) | 0x10 | 4;
+ out_be32(0xfff4202c, v);
+ }
+
+ dev_set_drvdata(dev, host);
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ kfree(hostdata);
+ out:
+ return -ENODEV;
+}
+
+static __devexit int
+mvme16x_device_remove(struct device *dev)
+{
+ struct Scsi_Host *host = dev_get_drvdata(dev);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ /* Disable scsi chip ints */
+ {
+ volatile unsigned long v;
+
+ v = in_be32(0xfff4202c);
+ v &= ~0x10;
+ out_be32(0xfff4202c, v);
+ }
+ scsi_remove_host(host);
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+
+ return 0;
+}
+
+static struct device_driver mvme16x_scsi_driver = {
+ .name = "mvme16x-scsi",
+ .bus = &platform_bus_type,
+ .probe = mvme16x_probe,
+ .remove = __devexit_p(mvme16x_device_remove),
+};
+
+static int __init mvme16x_scsi_init(void)
+{
+ int err;
+
+ err = driver_register(&mvme16x_scsi_driver);
+ if (err)
+ return err;
+
+ mvme16x_scsi_device = platform_device_register_simple("mvme16x-scsi",
+ -1, NULL, 0);
+ if (IS_ERR(mvme16x_scsi_device)) {
+ driver_unregister(&mvme16x_scsi_driver);
+ return PTR_ERR(mvme16x_scsi_device);
+ }
+
+ return 0;
+}
+
+static void __exit mvme16x_scsi_exit(void)
+{
+ platform_device_unregister(mvme16x_scsi_device);
+ driver_unregister(&mvme16x_scsi_driver);
+}
+
+module_init(mvme16x_scsi_init);
+module_exit(mvme16x_scsi_exit);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index bbf521cbc55d..030ba49f33ff 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -529,43 +529,20 @@ static void __unmap_scsi_data(struct device *dev, struct scsi_cmnd *cmd)
{
switch(cmd->__data_mapped) {
case 2:
- dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
- break;
- case 1:
- dma_unmap_single(dev, cmd->__data_mapping,
- cmd->request_bufflen,
- cmd->sc_data_direction);
+ scsi_dma_unmap(cmd);
break;
}
cmd->__data_mapped = 0;
}
-static u_long __map_scsi_single_data(struct device *dev, struct scsi_cmnd *cmd)
-{
- dma_addr_t mapping;
-
- if (cmd->request_bufflen == 0)
- return 0;
-
- mapping = dma_map_single(dev, cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- cmd->__data_mapped = 1;
- cmd->__data_mapping = mapping;
-
- return mapping;
-}
-
static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
{
int use_sg;
- if (cmd->use_sg == 0)
+ use_sg = scsi_dma_map(cmd);
+ if (!use_sg)
return 0;
- use_sg = dma_map_sg(dev, cmd->request_buffer, cmd->use_sg,
- cmd->sc_data_direction);
cmd->__data_mapped = 2;
cmd->__data_mapping = use_sg;
@@ -573,7 +550,6 @@ static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
}
#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd)
-#define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->dev, cmd)
#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd)
/*==========================================================
@@ -7667,39 +7643,16 @@ fail:
** sizes to the data segment array.
*/
-static int ncr_scatter_no_sglist(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd)
-{
- struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - 1];
- int segment;
-
- cp->data_len = cmd->request_bufflen;
-
- if (cmd->request_bufflen) {
- dma_addr_t baddr = map_scsi_single_data(np, cmd);
- if (baddr) {
- ncr_build_sge(np, data, baddr, cmd->request_bufflen);
- segment = 1;
- } else {
- segment = -2;
- }
- } else {
- segment = 0;
- }
-
- return segment;
-}
-
static int ncr_scatter(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd)
{
int segment = 0;
- int use_sg = (int) cmd->use_sg;
+ int use_sg = scsi_sg_count(cmd);
cp->data_len = 0;
- if (!use_sg)
- segment = ncr_scatter_no_sglist(np, cp, cmd);
- else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
- struct scatterlist *scatter = (struct scatterlist *)cmd->request_buffer;
+ use_sg = map_scsi_sg_data(np, cmd);
+ if (use_sg > 0) {
+ struct scatterlist *sg;
struct scr_tblmove *data;
if (use_sg > MAX_SCATTER) {
@@ -7709,16 +7662,15 @@ static int ncr_scatter(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd)
data = &cp->phys.data[MAX_SCATTER - use_sg];
- for (segment = 0; segment < use_sg; segment++) {
- dma_addr_t baddr = sg_dma_address(&scatter[segment]);
- unsigned int len = sg_dma_len(&scatter[segment]);
+ scsi_for_each_sg(cmd, sg, use_sg, segment) {
+ dma_addr_t baddr = sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
ncr_build_sge(np, &data[segment], baddr, len);
cp->data_len += len;
}
- } else {
+ } else
segment = -2;
- }
return segment;
}
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index f6f561d26bf0..7fed35372150 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -49,10 +49,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
-# include <linux/blk.h>
-#endif
-
#include "nsp32.h"
@@ -199,17 +195,9 @@ static int __init init_nsp32 (void);
static void __exit exit_nsp32 (void);
/* struct struct scsi_host_template */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int);
-#else
-static int nsp32_proc_info (char *, char **, off_t, int, int, int);
-#endif
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
static int nsp32_detect (struct pci_dev *pdev);
-#else
-static int nsp32_detect (struct scsi_host_template *);
-#endif
static int nsp32_queuecommand(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
static const char *nsp32_info (struct Scsi_Host *);
@@ -296,15 +284,7 @@ static struct scsi_host_template nsp32_template = {
.eh_abort_handler = nsp32_eh_abort,
.eh_bus_reset_handler = nsp32_eh_bus_reset,
.eh_host_reset_handler = nsp32_eh_host_reset,
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74))
- .detect = nsp32_detect,
- .release = nsp32_release,
-#endif
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
- .use_new_eh_code = 1,
-#else
/* .highmem_io = 1, */
-#endif
};
#include "nsp32_io.h"
@@ -739,7 +719,7 @@ static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
command = 0;
command |= (TRANSFER_GO | ALL_COUNTER_CLR);
if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
- if (SCpnt->request_bufflen > 0) {
+ if (scsi_bufflen(SCpnt) > 0) {
command |= BM_START;
}
} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
@@ -888,31 +868,28 @@ static int nsp32_reselection(struct scsi_cmnd *SCpnt, unsigned char newlun)
static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
{
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
- struct scatterlist *sgl;
+ struct scatterlist *sg;
nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
int num, i;
u32_le l;
- if (SCpnt->request_bufflen == 0) {
- return TRUE;
- }
-
if (sgt == NULL) {
nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
return FALSE;
}
- if (SCpnt->use_sg) {
- sgl = (struct scatterlist *)SCpnt->request_buffer;
- num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- for (i = 0; i < num; i++) {
+ num = scsi_dma_map(SCpnt);
+ if (!num)
+ return TRUE;
+ else if (num < 0)
+ return FALSE;
+ else {
+ scsi_for_each_sg(SCpnt, sg, num, i) {
/*
* Build nsp32_sglist, substitute sg dma addresses.
*/
- sgt[i].addr = cpu_to_le32(sg_dma_address(sgl));
- sgt[i].len = cpu_to_le32(sg_dma_len(sgl));
- sgl++;
+ sgt[i].addr = cpu_to_le32(sg_dma_address(sg));
+ sgt[i].len = cpu_to_le32(sg_dma_len(sg));
if (le32_to_cpu(sgt[i].len) > 0x10000) {
nsp32_msg(KERN_ERR,
@@ -929,23 +906,6 @@ static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
/* set end mark */
l = le32_to_cpu(sgt[num-1].len);
sgt[num-1].len = cpu_to_le32(l | SGTEND);
-
- } else {
- SCpnt->SCp.have_data_in = pci_map_single(data->Pci,
- SCpnt->request_buffer, SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
-
- sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in);
- sgt[0].len = cpu_to_le32(SCpnt->request_bufflen | SGTEND); /* set end mark */
-
- if (SCpnt->request_bufflen > 0x10000) {
- nsp32_msg(KERN_ERR,
- "can't transfer over 64KB at a time, size=0x%lx", SCpnt->request_bufflen);
- return FALSE;
- }
- nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%lx",
- le32_to_cpu(sgt[0].addr),
- le32_to_cpu(sgt[0].len ));
}
return TRUE;
@@ -962,7 +922,7 @@ static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
"enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x "
"use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
- SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen);
+ scsi_sg_count(SCpnt), scsi_sglist(SCpnt), scsi_bufflen(SCpnt));
if (data->CurrentSC != NULL) {
nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
@@ -994,10 +954,10 @@ static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_
data->CurrentSC = SCpnt;
SCpnt->SCp.Status = CHECK_CONDITION;
SCpnt->SCp.Message = 0;
- SCpnt->resid = SCpnt->request_bufflen;
+ scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
- SCpnt->SCp.ptr = (char *) SCpnt->request_buffer;
- SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+ SCpnt->SCp.ptr = (char *)scsi_sglist(SCpnt);
+ SCpnt->SCp.this_residual = scsi_bufflen(SCpnt);
SCpnt->SCp.buffer = NULL;
SCpnt->SCp.buffers_residual = 0;
@@ -1210,13 +1170,9 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
unsigned long flags;
int ret;
int handled = 0;
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
struct Scsi_Host *host = data->Host;
+
spin_lock_irqsave(host->host_lock, flags);
-#else
- spin_lock_irqsave(&io_request_lock, flags);
-#endif
/*
* IRQ check, then enable IRQ mask
@@ -1312,7 +1268,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
}
if ((auto_stat & DATA_IN_PHASE) &&
- (SCpnt->resid > 0) &&
+ (scsi_get_resid(SCpnt) > 0) &&
((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
printk( "auto+fifo\n");
//nsp32_pio_read(SCpnt);
@@ -1333,7 +1289,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx",
nsp32_read4(base, SAVED_SACK_CNT));
- SCpnt->resid = 0; /* all data transfered! */
+ scsi_set_resid(SCpnt, 0); /* all data transfered! */
}
/*
@@ -1480,11 +1436,7 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
nsp32_write2(base, IRQ_CONTROL, 0);
out2:
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
spin_unlock_irqrestore(host->host_lock, flags);
-#else
- spin_unlock_irqrestore(&io_request_lock, flags);
-#endif
nsp32_dbg(NSP32_DEBUG_INTR, "exit");
@@ -1499,28 +1451,15 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\
} \
} while(0)
-static int nsp32_proc_info(
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- struct Scsi_Host *host,
-#endif
- char *buffer,
- char **start,
- off_t offset,
- int length,
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- int hostno,
-#endif
- int inout)
+
+static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+ off_t offset, int length, int inout)
{
char *pos = buffer;
int thislength;
unsigned long flags;
nsp32_hw_data *data;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
int hostno;
-#else
- struct Scsi_Host *host;
-#endif
unsigned int base;
unsigned char mode_reg;
int id, speed;
@@ -1531,15 +1470,7 @@ static int nsp32_proc_info(
return -EINVAL;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
hostno = host->host_no;
-#else
- /* search this HBA host */
- host = scsi_host_hn_get(hostno);
- if (host == NULL) {
- return -ESRCH;
- }
-#endif
data = (nsp32_hw_data *)host->hostdata;
base = host->io_port;
@@ -1626,25 +1557,8 @@ static void nsp32_scsi_done(struct scsi_cmnd *SCpnt)
nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
unsigned int base = SCpnt->device->host->io_port;
- /*
- * unmap pci
- */
- if (SCpnt->request_bufflen == 0) {
- goto skip;
- }
+ scsi_dma_unmap(SCpnt);
- if (SCpnt->use_sg) {
- pci_unmap_sg(data->Pci,
- (struct scatterlist *)SCpnt->request_buffer,
- SCpnt->use_sg, SCpnt->sc_data_direction);
- } else {
- pci_unmap_single(data->Pci,
- (u32)SCpnt->SCp.have_data_in,
- SCpnt->request_bufflen,
- SCpnt->sc_data_direction);
- }
-
- skip:
/*
* clear TRANSFERCONTROL_BM_START
*/
@@ -1800,7 +1714,7 @@ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
SCpnt->SCp.Message = 0;
nsp32_dbg(NSP32_DEBUG_BUSFREE,
"normal end stat=0x%x resid=0x%x\n",
- SCpnt->SCp.Status, SCpnt->resid);
+ SCpnt->SCp.Status, scsi_get_resid(SCpnt));
SCpnt->result = (DID_OK << 16) |
(SCpnt->SCp.Message << 8) |
(SCpnt->SCp.Status << 0);
@@ -1844,7 +1758,7 @@ static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen
unsigned int restlen, sentlen;
u32_le len, addr;
- nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", SCpnt->resid);
+ nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", scsi_get_resid(SCpnt));
/* adjust saved SACK count with 4 byte start address boundary */
s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3;
@@ -1888,12 +1802,12 @@ static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen
return;
last:
- if (SCpnt->resid < sentlen) {
+ if (scsi_get_resid(SCpnt) < sentlen) {
nsp32_msg(KERN_ERR, "resid underflow");
}
- SCpnt->resid -= sentlen;
- nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", SCpnt->resid);
+ scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) - sentlen);
+ nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", scsi_get_resid(SCpnt));
/* update hostdata and lun */
@@ -2022,7 +1936,7 @@ static void nsp32_restart_autoscsi(struct scsi_cmnd *SCpnt, unsigned short comma
transfer = 0;
transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
- if (SCpnt->request_bufflen > 0) {
+ if (scsi_bufflen(SCpnt) > 0) {
transfer |= BM_START;
}
} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
@@ -2674,17 +2588,7 @@ static void nsp32_sack_negate(nsp32_hw_data *data)
* 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
* 0xc00-0xfff: CardBus status registers
*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
-#define DETECT_OK 0
-#define DETECT_NG 1
-#define PCIDEV pdev
static int nsp32_detect(struct pci_dev *pdev)
-#else
-#define DETECT_OK 1
-#define DETECT_NG 0
-#define PCIDEV (data->Pci)
-static int nsp32_detect(struct scsi_host_template *sht)
-#endif
{
struct Scsi_Host *host; /* registered host structure */
struct resource *res;
@@ -2697,11 +2601,7 @@ static int nsp32_detect(struct scsi_host_template *sht)
/*
* register this HBA as SCSI device
*/
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data));
-#else
- host = scsi_register(sht, sizeof(nsp32_hw_data));
-#endif
if (host == NULL) {
nsp32_msg (KERN_ERR, "failed to scsi register");
goto err;
@@ -2719,9 +2619,6 @@ static int nsp32_detect(struct scsi_host_template *sht)
host->unique_id = data->BaseAddress;
host->n_io_port = data->NumAddress;
host->base = (unsigned long)data->MmioAddress;
-#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,63))
- scsi_set_pci_device(host, PCIDEV);
-#endif
data->Host = host;
spin_lock_init(&(data->Lock));
@@ -2776,7 +2673,7 @@ static int nsp32_detect(struct scsi_host_template *sht)
/*
* setup DMA
*/
- if (pci_set_dma_mask(PCIDEV, DMA_32BIT_MASK) != 0) {
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
goto scsi_unregister;
}
@@ -2784,7 +2681,7 @@ static int nsp32_detect(struct scsi_host_template *sht)
/*
* allocate autoparam DMA resource.
*/
- data->autoparam = pci_alloc_consistent(PCIDEV, sizeof(nsp32_autoparam), &(data->auto_paddr));
+ data->autoparam = pci_alloc_consistent(pdev, sizeof(nsp32_autoparam), &(data->auto_paddr));
if (data->autoparam == NULL) {
nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
goto scsi_unregister;
@@ -2793,7 +2690,7 @@ static int nsp32_detect(struct scsi_host_template *sht)
/*
* allocate scatter-gather DMA resource.
*/
- data->sg_list = pci_alloc_consistent(PCIDEV, NSP32_SG_TABLE_SIZE,
+ data->sg_list = pci_alloc_consistent(pdev, NSP32_SG_TABLE_SIZE,
&(data->sg_paddr));
if (data->sg_list == NULL) {
nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
@@ -2883,16 +2780,14 @@ static int nsp32_detect(struct scsi_host_template *sht)
goto free_irq;
}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- ret = scsi_add_host(host, &PCIDEV->dev);
+ ret = scsi_add_host(host, &pdev->dev);
if (ret) {
nsp32_msg(KERN_ERR, "failed to add scsi host");
goto free_region;
}
scsi_scan_host(host);
-#endif
- pci_set_drvdata(PCIDEV, host);
- return DETECT_OK;
+ pci_set_drvdata(pdev, host);
+ return 0;
free_region:
release_region(host->io_port, host->n_io_port);
@@ -2901,22 +2796,19 @@ static int nsp32_detect(struct scsi_host_template *sht)
free_irq(host->irq, data);
free_sg_list:
- pci_free_consistent(PCIDEV, NSP32_SG_TABLE_SIZE,
+ pci_free_consistent(pdev, NSP32_SG_TABLE_SIZE,
data->sg_list, data->sg_paddr);
free_autoparam:
- pci_free_consistent(PCIDEV, sizeof(nsp32_autoparam),
+ pci_free_consistent(pdev, sizeof(nsp32_autoparam),
data->autoparam, data->auto_paddr);
scsi_unregister:
scsi_host_put(host);
err:
- return DETECT_NG;
+ return 1;
}
-#undef DETECT_OK
-#undef DETECT_NG
-#undef PCIDEV
static int nsp32_release(struct Scsi_Host *host)
{
@@ -3487,15 +3379,6 @@ static int nsp32_resume(struct pci_dev *pdev)
return 0;
}
-/* Enable wake event */
-static int nsp32_enable_wake(struct pci_dev *pdev, pci_power_t state, int enable)
-{
- struct Scsi_Host *host = pci_get_drvdata(pdev);
-
- nsp32_msg(KERN_INFO, "pci-enable_wake: stub, pdev=0x%p, enable=%d, slot=%s, host=0x%p", pdev, enable, pci_name(pdev), host);
-
- return 0;
-}
#endif
/************************************************************************
@@ -3525,11 +3408,7 @@ static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_i
pci_set_master(pdev);
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
ret = nsp32_detect(pdev);
-#else
- ret = scsi_register_host(&nsp32_template);
-#endif
nsp32_msg(KERN_INFO, "irq: %i mmio: %p+0x%lx slot: %s model: %s",
pdev->irq,
@@ -3544,25 +3423,17 @@ static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_i
static void __devexit nsp32_remove(struct pci_dev *pdev)
{
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
struct Scsi_Host *host = pci_get_drvdata(pdev);
-#endif
nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
scsi_remove_host(host);
nsp32_release(host);
scsi_host_put(host);
-#else
- scsi_unregister_host(&nsp32_template);
-#endif
}
-
-
static struct pci_driver nsp32_driver = {
.name = "nsp32",
.id_table = nsp32_pci_table,
@@ -3571,7 +3442,6 @@ static struct pci_driver nsp32_driver = {
#ifdef CONFIG_PM
.suspend = nsp32_suspend,
.resume = nsp32_resume,
- .enable_wake = nsp32_enable_wake,
#endif
};
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index 7dd787f6ab27..fa481b515ead 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -2,9 +2,12 @@
# PCMCIA SCSI adapter configuration
#
-menu "PCMCIA SCSI adapter support"
+menuconfig SCSI_LOWLEVEL_PCMCIA
+ bool "PCMCIA SCSI adapter support"
depends on SCSI!=n && PCMCIA!=n
+if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA
+
config PCMCIA_AHA152X
tristate "Adaptec AHA152X PCMCIA support"
depends on !64BIT
@@ -77,4 +80,4 @@ config PCMCIA_SYM53C500
To compile this driver as a module, choose M here: the
module will be called sym53c500_cs.
-endmenu
+endif # SCSI_LOWLEVEL_PCMCIA
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 370802d24acd..2dd0dc9a9aed 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -106,9 +106,8 @@ static int aha152x_probe(struct pcmcia_device *link)
DEBUG(0, "aha152x_attach()\n");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) return -ENOMEM;
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index c6f8c6e65e05..445cfbbca9b3 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1602,9 +1602,8 @@ static int nsp_cs_probe(struct pcmcia_device *link)
nsp_dbg(NSP_DEBUG_INIT, "in");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) { return -ENOMEM; }
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
data->ScsiInfo = info;
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 697cfb76c3a4..67c5a58d17df 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -162,10 +162,9 @@ static int qlogic_probe(struct pcmcia_device *link)
DEBUG(0, "qlogic_attach()\n");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
link->io.NumPorts1 = 16;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index ffe75c431b25..961839ecfe86 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -370,8 +370,6 @@ SYM53C500_intr(int irq, void *dev_id)
DEB(unsigned char seq_reg;)
unsigned char status, int_reg;
unsigned char pio_status;
- struct scatterlist *sglist;
- unsigned int sgcount;
int port_base = dev->io_port;
struct sym53c500_data *data =
(struct sym53c500_data *)dev->hostdata;
@@ -434,20 +432,19 @@ SYM53C500_intr(int irq, void *dev_id)
switch (status & 0x07) { /* scsi phase */
case 0x00: /* DATA-OUT */
if (int_reg & 0x10) { /* Target requesting info transfer */
+ struct scatterlist *sg;
+ int i;
+
curSC->SCp.phase = data_out;
VDEB(printk("SYM53C500: Data-Out phase\n"));
outb(FLUSH_FIFO, port_base + CMD_REG);
- LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */
outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG);
- if (!curSC->use_sg) /* Don't use scatter-gather */
- SYM53C500_pio_write(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen);
- else { /* use scatter-gather */
- sgcount = curSC->use_sg;
- sglist = curSC->request_buffer;
- while (sgcount--) {
- SYM53C500_pio_write(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
+ SYM53C500_pio_write(fast_pio, port_base,
+ page_address(sg->page) + sg->offset,
+ sg->length);
}
REG0(port_base);
}
@@ -455,20 +452,19 @@ SYM53C500_intr(int irq, void *dev_id)
case 0x01: /* DATA-IN */
if (int_reg & 0x10) { /* Target requesting info transfer */
+ struct scatterlist *sg;
+ int i;
+
curSC->SCp.phase = data_in;
VDEB(printk("SYM53C500: Data-In phase\n"));
outb(FLUSH_FIFO, port_base + CMD_REG);
- LOAD_DMA_COUNT(port_base, curSC->request_bufflen); /* Max transfer size */
+ LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */
outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG);
- if (!curSC->use_sg) /* Don't use scatter-gather */
- SYM53C500_pio_read(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen);
- else { /* Use scatter-gather */
- sgcount = curSC->use_sg;
- sglist = curSC->request_buffer;
- while (sgcount--) {
- SYM53C500_pio_read(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) {
+ SYM53C500_pio_read(fast_pio, port_base,
+ page_address(sg->page) + sg->offset,
+ sg->length);
}
REG0(port_base);
}
@@ -578,7 +574,7 @@ SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n",
SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id,
- SCpnt->device->lun, SCpnt->request_bufflen));
+ SCpnt->device->lun, scsi_bufflen(SCpnt)));
VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i]));
@@ -879,10 +875,9 @@ SYM53C500_probe(struct pcmcia_device *link)
DEBUG(0, "SYM53C500_attach()\n");
/* Create new SCSI device */
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
- memset(info, 0, sizeof(*info));
info->p_dev = link;
link->priv = info;
link->io.NumPorts1 = 16;
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 584ba4d6e038..67b6d76a6c8d 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -129,11 +129,11 @@ static inline int ppa_proc_write(ppa_struct *dev, char *buffer, int length)
if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) {
x = simple_strtoul(buffer + 10, NULL, 0);
dev->recon_tmo = x;
- printk("ppa: recon_tmo set to %ld\n", x);
+ printk(KERN_INFO "ppa: recon_tmo set to %ld\n", x);
return length;
}
- printk("ppa /proc: invalid variable\n");
- return (-EINVAL);
+ printk(KERN_WARNING "ppa /proc: invalid variable\n");
+ return -EINVAL;
}
static int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
@@ -216,7 +216,7 @@ static unsigned char ppa_wait(ppa_struct *dev)
/* Counter expired - Time out occurred */
ppa_fail(dev, DID_TIME_OUT);
- printk("ppa timeout in ppa_wait\n");
+ printk(KERN_WARNING "ppa timeout in ppa_wait\n");
return 0; /* command timed out */
}
@@ -248,7 +248,7 @@ static inline void ecp_sync(ppa_struct *dev)
return;
udelay(5);
}
- printk("ppa: ECP sync failed as data still present in FIFO.\n");
+ printk(KERN_WARNING "ppa: ECP sync failed as data still present in FIFO.\n");
}
}
@@ -328,7 +328,7 @@ static int ppa_out(ppa_struct *dev, char *buffer, int len)
break;
default:
- printk("PPA: bug in ppa_out()\n");
+ printk(KERN_ERR "PPA: bug in ppa_out()\n");
r = 0;
}
return r;
@@ -381,7 +381,7 @@ static int ppa_in(ppa_struct *dev, char *buffer, int len)
break;
default:
- printk("PPA: bug in ppa_ins()\n");
+ printk(KERN_ERR "PPA: bug in ppa_ins()\n");
r = 0;
break;
}
@@ -633,7 +633,7 @@ static void ppa_interrupt(struct work_struct *work)
struct scsi_cmnd *cmd = dev->cur_cmd;
if (!cmd) {
- printk("PPA: bug in ppa_interrupt\n");
+ printk(KERN_ERR "PPA: bug in ppa_interrupt\n");
return;
}
if (ppa_engine(dev, cmd)) {
@@ -646,31 +646,31 @@ static void ppa_interrupt(struct work_struct *work)
case DID_OK:
break;
case DID_NO_CONNECT:
- printk("ppa: no device at SCSI ID %i\n", cmd->device->target);
+ printk(KERN_DEBUG "ppa: no device at SCSI ID %i\n", cmd->device->target);
break;
case DID_BUS_BUSY:
- printk("ppa: BUS BUSY - EPP timeout detected\n");
+ printk(KERN_DEBUG "ppa: BUS BUSY - EPP timeout detected\n");
break;
case DID_TIME_OUT:
- printk("ppa: unknown timeout\n");
+ printk(KERN_DEBUG "ppa: unknown timeout\n");
break;
case DID_ABORT:
- printk("ppa: told to abort\n");
+ printk(KERN_DEBUG "ppa: told to abort\n");
break;
case DID_PARITY:
- printk("ppa: parity error (???)\n");
+ printk(KERN_DEBUG "ppa: parity error (???)\n");
break;
case DID_ERROR:
- printk("ppa: internal driver error\n");
+ printk(KERN_DEBUG "ppa: internal driver error\n");
break;
case DID_RESET:
- printk("ppa: told to reset device\n");
+ printk(KERN_DEBUG "ppa: told to reset device\n");
break;
case DID_BAD_INTR:
- printk("ppa: bad interrupt (???)\n");
+ printk(KERN_WARNING "ppa: bad interrupt (???)\n");
break;
default:
- printk("ppa: bad return code (%02x)\n",
+ printk(KERN_WARNING "ppa: bad return code (%02x)\n",
(cmd->result >> 16) & 0xff);
}
#endif
@@ -724,8 +724,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
if (retv) {
if (time_after(jiffies, dev->jstart + (1 * HZ))) {
- printk
- ("ppa: Parallel port cable is unplugged!!\n");
+ printk(KERN_ERR "ppa: Parallel port cable is unplugged.\n");
ppa_fail(dev, DID_BUS_BUSY);
return 0;
} else {
@@ -755,11 +754,9 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
case 4: /* Phase 4 - Setup scatter/gather buffers */
if (cmd->use_sg) {
/* if many buffers are available, start filling the first */
- cmd->SCp.buffer =
- (struct scatterlist *) cmd->request_buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr =
- page_address(cmd->SCp.buffer->page) +
+ cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
} else {
/* else fill the only available buffer */
@@ -800,7 +797,7 @@ static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
break;
default:
- printk("ppa: Invalid scsi phase\n");
+ printk(KERN_ERR "ppa: Invalid scsi phase\n");
}
return 0;
}
@@ -811,7 +808,7 @@ static int ppa_queuecommand(struct scsi_cmnd *cmd,
ppa_struct *dev = ppa_dev(cmd->device->host);
if (dev->cur_cmd) {
- printk("PPA: bug in ppa_queuecommand\n");
+ printk(KERN_ERR "PPA: bug in ppa_queuecommand\n");
return 0;
}
dev->failed = 0;
@@ -899,7 +896,7 @@ static int device_check(ppa_struct *dev)
/* This routine looks for a device and then attempts to use EPP
to send a command. If all goes as planned then EPP is available. */
- static char cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static u8 cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
int loop, old_mode, status, k, ppb = dev->base;
unsigned char l;
@@ -909,14 +906,14 @@ static int device_check(ppa_struct *dev)
if ((ppb & 0x0007) == 0x0000)
dev->mode = PPA_EPP_32;
- second_pass:
+second_pass:
ppa_connect(dev, CONNECT_EPP_MAYBE);
/* Select SCSI device */
if (!ppa_select(dev, loop)) {
ppa_disconnect(dev);
continue;
}
- printk("ppa: Found device at ID %i, Attempting to use %s\n",
+ printk(KERN_INFO "ppa: Found device at ID %i, Attempting to use %s\n",
loop, PPA_MODE_STRING[dev->mode]);
/* Send SCSI command */
@@ -965,7 +962,7 @@ static int device_check(ppa_struct *dev)
return -EIO;
}
ppa_disconnect(dev);
- printk("ppa: Communication established with ID %i using %s\n",
+ printk(KERN_INFO "ppa: Communication established with ID %i using %s\n",
loop, PPA_MODE_STRING[dev->mode]);
ppa_connect(dev, CONNECT_EPP_MAYBE);
ppa_reset_pulse(ppb);
@@ -1017,10 +1014,9 @@ static int __ppa_attach(struct parport *pb)
int modes, ppb, ppb_hi;
int err = -ENOMEM;
- dev = kmalloc(sizeof(ppa_struct), GFP_KERNEL);
+ dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(ppa_struct));
dev->base = -1;
dev->mode = PPA_AUTODETECT;
dev->recon_tmo = PPA_RECON_TMO;
@@ -1140,7 +1136,7 @@ static struct parport_driver ppa_driver = {
static int __init ppa_driver_init(void)
{
- printk("ppa: Version %s\n", PPA_VERSION);
+ printk(KERN_INFO "ppa: Version %s\n", PPA_VERSION);
return parport_register_driver(&ppa_driver);
}
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
new file mode 100644
index 000000000000..b50f1e14f2a5
--- /dev/null
+++ b/drivers/scsi/ps3rom.c
@@ -0,0 +1,533 @@
+/*
+ * PS3 BD/DVD/CD-ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cdrom.h>
+#include <linux/highmem.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME "ps3rom"
+
+#define BOUNCE_SIZE (64*1024)
+
+#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE / CD_FRAMESIZE)
+
+
+struct ps3rom_private {
+ struct ps3_storage_device *dev;
+ struct scsi_cmnd *curr_cmd;
+};
+
+
+#define LV1_STORAGE_SEND_ATAPI_COMMAND (1)
+
+struct lv1_atapi_cmnd_block {
+ u8 pkt[32]; /* packet command block */
+ u32 pktlen; /* should be 12 for ATAPI 8020 */
+ u32 blocks;
+ u32 block_size;
+ u32 proto; /* transfer mode */
+ u32 in_out; /* transfer direction */
+ u64 buffer; /* parameter except command block */
+ u32 arglen; /* length above */
+};
+
+enum lv1_atapi_proto {
+ NON_DATA_PROTO = 0,
+ PIO_DATA_IN_PROTO = 1,
+ PIO_DATA_OUT_PROTO = 2,
+ DMA_PROTO = 3
+};
+
+enum lv1_atapi_in_out {
+ DIR_WRITE = 0, /* memory -> device */
+ DIR_READ = 1 /* device -> memory */
+};
+
+
+static int ps3rom_slave_configure(struct scsi_device *scsi_dev)
+{
+ struct ps3rom_private *priv = shost_priv(scsi_dev->host);
+ struct ps3_storage_device *dev = priv->dev;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__,
+ __LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel);
+
+ /*
+ * ATAPI SFF8020 devices use MODE_SENSE_10,
+ * so we can prohibit MODE_SENSE_6
+ */
+ scsi_dev->use_10_for_ms = 1;
+
+ /* we don't support {READ,WRITE}_6 */
+ scsi_dev->use_10_for_rw = 1;
+
+ return 0;
+}
+
+/*
+ * copy data from device into scatter/gather buffer
+ */
+static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
+{
+ int k, req_len, act_len, len, active;
+ void *kaddr;
+ struct scatterlist *sgpnt;
+ unsigned int buflen;
+
+ buflen = cmd->request_bufflen;
+ if (!buflen)
+ return 0;
+
+ if (!cmd->request_buffer)
+ return -1;
+
+ sgpnt = cmd->request_buffer;
+ active = 1;
+ for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+ if (active) {
+ kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+ len = sgpnt->length;
+ if ((req_len + len) > buflen) {
+ active = 0;
+ len = buflen - req_len;
+ }
+ memcpy(kaddr + sgpnt->offset, buf + req_len, len);
+ flush_kernel_dcache_page(sgpnt->page);
+ kunmap_atomic(kaddr, KM_IRQ0);
+ act_len += len;
+ }
+ req_len += sgpnt->length;
+ }
+ cmd->resid = req_len - act_len;
+ return 0;
+}
+
+/*
+ * copy data from scatter/gather into device's buffer
+ */
+static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
+{
+ int k, req_len, len, fin;
+ void *kaddr;
+ struct scatterlist *sgpnt;
+ unsigned int buflen;
+
+ buflen = cmd->request_bufflen;
+ if (!buflen)
+ return 0;
+
+ if (!cmd->request_buffer)
+ return -1;
+
+ sgpnt = cmd->request_buffer;
+ for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+ kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+ len = sgpnt->length;
+ if ((req_len + len) > buflen) {
+ len = buflen - req_len;
+ fin = 1;
+ }
+ memcpy(buf + req_len, kaddr + sgpnt->offset, len);
+ kunmap_atomic(kaddr, KM_IRQ0);
+ if (fin)
+ return req_len + len;
+ req_len += sgpnt->length;
+ }
+ return req_len;
+}
+
+static int ps3rom_atapi_request(struct ps3_storage_device *dev,
+ struct scsi_cmnd *cmd)
+{
+ struct lv1_atapi_cmnd_block atapi_cmnd;
+ unsigned char opcode = cmd->cmnd[0];
+ int res;
+ u64 lpar;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__,
+ __LINE__, opcode);
+
+ memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
+ memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
+ atapi_cmnd.pktlen = 12;
+ atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
+ atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+ atapi_cmnd.buffer = dev->bounce_lpar;
+
+ switch (cmd->sc_data_direction) {
+ case DMA_FROM_DEVICE:
+ if (cmd->request_bufflen >= CD_FRAMESIZE)
+ atapi_cmnd.proto = DMA_PROTO;
+ else
+ atapi_cmnd.proto = PIO_DATA_IN_PROTO;
+ atapi_cmnd.in_out = DIR_READ;
+ break;
+
+ case DMA_TO_DEVICE:
+ if (cmd->request_bufflen >= CD_FRAMESIZE)
+ atapi_cmnd.proto = DMA_PROTO;
+ else
+ atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
+ atapi_cmnd.in_out = DIR_WRITE;
+ res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+ if (res < 0)
+ return DID_ERROR << 16;
+ break;
+
+ default:
+ atapi_cmnd.proto = NON_DATA_PROTO;
+ break;
+ }
+
+ lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd));
+ res = lv1_storage_send_device_command(dev->sbd.dev_id,
+ LV1_STORAGE_SEND_ATAPI_COMMAND,
+ lpar, sizeof(atapi_cmnd),
+ atapi_cmnd.buffer,
+ atapi_cmnd.arglen, &dev->tag);
+ if (res == LV1_DENIED_BY_POLICY) {
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: ATAPI command 0x%02x denied by policy\n",
+ __func__, __LINE__, opcode);
+ return DID_ERROR << 16;
+ }
+
+ if (res) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: ATAPI command 0x%02x failed %d\n", __func__,
+ __LINE__, opcode, res);
+ return DID_ERROR << 16;
+ }
+
+ return 0;
+}
+
+static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd)
+{
+ return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 |
+ cmd->cmnd[5];
+}
+
+static inline unsigned int srb10_len(const struct scsi_cmnd *cmd)
+{
+ return cmd->cmnd[7] << 8 | cmd->cmnd[8];
+}
+
+static int ps3rom_read_request(struct ps3_storage_device *dev,
+ struct scsi_cmnd *cmd, u32 start_sector,
+ u32 sectors)
+{
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n",
+ __func__, __LINE__, sectors, start_sector);
+
+ res = lv1_storage_read(dev->sbd.dev_id,
+ dev->regions[dev->region_idx].id, start_sector,
+ sectors, 0, dev->bounce_lpar, &dev->tag);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__,
+ __LINE__, res);
+ return DID_ERROR << 16;
+ }
+
+ return 0;
+}
+
+static int ps3rom_write_request(struct ps3_storage_device *dev,
+ struct scsi_cmnd *cmd, u32 start_sector,
+ u32 sectors)
+{
+ int res;
+
+ dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n",
+ __func__, __LINE__, sectors, start_sector);
+
+ res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+ if (res < 0)
+ return DID_ERROR << 16;
+
+ res = lv1_storage_write(dev->sbd.dev_id,
+ dev->regions[dev->region_idx].id, start_sector,
+ sectors, 0, dev->bounce_lpar, &dev->tag);
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__,
+ __LINE__, res);
+ return DID_ERROR << 16;
+ }
+
+ return 0;
+}
+
+static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct ps3rom_private *priv = shost_priv(cmd->device->host);
+ struct ps3_storage_device *dev = priv->dev;
+ unsigned char opcode;
+ int res;
+
+#ifdef DEBUG
+ scsi_print_command(cmd);
+#endif
+
+ priv->curr_cmd = cmd;
+ cmd->scsi_done = done;
+
+ opcode = cmd->cmnd[0];
+ /*
+ * While we can submit READ/WRITE SCSI commands as ATAPI commands,
+ * it's recommended for various reasons (performance, error handling,
+ * ...) to use lv1_storage_{read,write}() instead
+ */
+ switch (opcode) {
+ case READ_10:
+ res = ps3rom_read_request(dev, cmd, srb10_lba(cmd),
+ srb10_len(cmd));
+ break;
+
+ case WRITE_10:
+ res = ps3rom_write_request(dev, cmd, srb10_lba(cmd),
+ srb10_len(cmd));
+ break;
+
+ default:
+ res = ps3rom_atapi_request(dev, cmd);
+ break;
+ }
+
+ if (res) {
+ memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ cmd->result = res;
+ cmd->sense_buffer[0] = 0x70;
+ cmd->sense_buffer[2] = ILLEGAL_REQUEST;
+ priv->curr_cmd = NULL;
+ cmd->scsi_done(cmd);
+ }
+
+ return 0;
+}
+
+static int decode_lv1_status(u64 status, unsigned char *sense_key,
+ unsigned char *asc, unsigned char *ascq)
+{
+ if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION)
+ return -1;
+
+ *sense_key = (status >> 16) & 0xff;
+ *asc = (status >> 8) & 0xff;
+ *ascq = status & 0xff;
+ return 0;
+}
+
+static irqreturn_t ps3rom_interrupt(int irq, void *data)
+{
+ struct ps3_storage_device *dev = data;
+ struct Scsi_Host *host;
+ struct ps3rom_private *priv;
+ struct scsi_cmnd *cmd;
+ int res;
+ u64 tag, status;
+ unsigned char sense_key, asc, ascq;
+
+ res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+ /*
+ * status = -1 may mean that ATAPI transport completed OK, but
+ * ATAPI command itself resulted CHECK CONDITION
+ * so, upper layer should issue REQUEST_SENSE to check the sense data
+ */
+
+ if (tag != dev->tag)
+ dev_err(&dev->sbd.core,
+ "%s:%u: tag mismatch, got %lx, expected %lx\n",
+ __func__, __LINE__, tag, dev->tag);
+
+ if (res) {
+ dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+ __func__, __LINE__, res, status);
+ return IRQ_HANDLED;
+ }
+
+ host = dev->sbd.core.driver_data;
+ priv = shost_priv(host);
+ cmd = priv->curr_cmd;
+
+ if (!status) {
+ /* OK, completed */
+ if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+ res = fill_from_dev_buffer(cmd, dev->bounce_buf);
+ if (res) {
+ cmd->result = DID_ERROR << 16;
+ goto done;
+ }
+ }
+ cmd->result = DID_OK << 16;
+ goto done;
+ }
+
+ if (cmd->cmnd[0] == REQUEST_SENSE) {
+ /* SCSI spec says request sense should never get error */
+ dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n",
+ __func__, __LINE__);
+ cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION;
+ goto done;
+ }
+
+ if (decode_lv1_status(status, &sense_key, &asc, &ascq)) {
+ cmd->result = DID_ERROR << 16;
+ goto done;
+ }
+
+ cmd->sense_buffer[0] = 0x70;
+ cmd->sense_buffer[2] = sense_key;
+ cmd->sense_buffer[7] = 16 - 6;
+ cmd->sense_buffer[12] = asc;
+ cmd->sense_buffer[13] = ascq;
+ cmd->result = SAM_STAT_CHECK_CONDITION;
+
+done:
+ priv->curr_cmd = NULL;
+ cmd->scsi_done(cmd);
+ return IRQ_HANDLED;
+}
+
+static struct scsi_host_template ps3rom_host_template = {
+ .name = DEVICE_NAME,
+ .slave_configure = ps3rom_slave_configure,
+ .queuecommand = ps3rom_queuecommand,
+ .can_queue = 1,
+ .this_id = 7,
+ .sg_tablesize = SG_ALL,
+ .cmd_per_lun = 1,
+ .emulated = 1, /* only sg driver uses this */
+ .max_sectors = PS3ROM_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+ .module = THIS_MODULE,
+};
+
+
+static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ int error;
+ struct Scsi_Host *host;
+ struct ps3rom_private *priv;
+
+ if (dev->blk_size != CD_FRAMESIZE) {
+ dev_err(&dev->sbd.core,
+ "%s:%u: cannot handle block size %lu\n", __func__,
+ __LINE__, dev->blk_size);
+ return -EINVAL;
+ }
+
+ dev->bounce_size = BOUNCE_SIZE;
+ dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+ if (!dev->bounce_buf)
+ return -ENOMEM;
+
+ error = ps3stor_setup(dev, ps3rom_interrupt);
+ if (error)
+ goto fail_free_bounce;
+
+ host = scsi_host_alloc(&ps3rom_host_template,
+ sizeof(struct ps3rom_private));
+ if (!host) {
+ dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n",
+ __func__, __LINE__);
+ goto fail_teardown;
+ }
+
+ priv = shost_priv(host);
+ dev->sbd.core.driver_data = host;
+ priv->dev = dev;
+
+ /* One device/LUN per SCSI bus */
+ host->max_id = 1;
+ host->max_lun = 1;
+
+ error = scsi_add_host(host, &dev->sbd.core);
+ if (error) {
+ dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n",
+ __func__, __LINE__, error);
+ error = -ENODEV;
+ goto fail_host_put;
+ }
+
+ scsi_scan_host(host);
+ return 0;
+
+fail_host_put:
+ scsi_host_put(host);
+ dev->sbd.core.driver_data = NULL;
+fail_teardown:
+ ps3stor_teardown(dev);
+fail_free_bounce:
+ kfree(dev->bounce_buf);
+ return error;
+}
+
+static int ps3rom_remove(struct ps3_system_bus_device *_dev)
+{
+ struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ struct Scsi_Host *host = dev->sbd.core.driver_data;
+
+ scsi_remove_host(host);
+ ps3stor_teardown(dev);
+ scsi_host_put(host);
+ dev->sbd.core.driver_data = NULL;
+ kfree(dev->bounce_buf);
+ return 0;
+}
+
+static struct ps3_system_bus_driver ps3rom = {
+ .match_id = PS3_MATCH_ID_STOR_ROM,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3rom_probe,
+ .remove = ps3rom_remove
+};
+
+
+static int __init ps3rom_init(void)
+{
+ return ps3_system_bus_driver_register(&ps3rom);
+}
+
+static void __exit ps3rom_exit(void)
+{
+ ps3_system_bus_driver_unregister(&ps3rom);
+}
+
+module_init(ps3rom_init);
+module_exit(ps3rom_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM);
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
index 411663af7bb7..71ddb5db4944 100644
--- a/drivers/scsi/qla2xxx/Makefile
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -1,4 +1,4 @@
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
- qla_dbg.o qla_sup.o qla_attr.o
+ qla_dbg.o qla_sup.o qla_attr.o qla_mid.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 8081b637d97e..1612f9200a52 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -6,13 +6,17 @@
*/
#include "qla_def.h"
+#include <linux/kthread.h>
#include <linux/vmalloc.h>
+int qla24xx_vport_disable(struct fc_vport *, bool);
+
/* SYSFS attributes --------------------------------------------------------- */
static ssize_t
-qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -31,8 +35,9 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
}
static ssize_t
-qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -73,7 +78,6 @@ static struct bin_attribute sysfs_fw_dump_attr = {
.attr = {
.name = "fw_dump",
.mode = S_IRUSR | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 0,
.read = qla2x00_sysfs_read_fw_dump,
@@ -81,8 +85,9 @@ static struct bin_attribute sysfs_fw_dump_attr = {
};
static ssize_t
-qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_read_nvram(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -93,7 +98,7 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
/* Read NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->nvram_base,
+ ha->isp_ops->read_nvram(ha, (uint8_t *)buf, ha->nvram_base,
ha->nvram_size);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -101,8 +106,9 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
}
static ssize_t
-qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_write_nvram(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -113,7 +119,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
return 0;
/* Checksum NVRAM. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
uint32_t *iter;
uint32_t chksum;
@@ -137,7 +143,7 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
/* Write NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
+ ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
@@ -149,7 +155,6 @@ static struct bin_attribute sysfs_nvram_attr = {
.attr = {
.name = "nvram",
.mode = S_IRUSR | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 512,
.read = qla2x00_sysfs_read_nvram,
@@ -157,8 +162,9 @@ static struct bin_attribute sysfs_nvram_attr = {
};
static ssize_t
-qla2x00_sysfs_read_optrom(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_read_optrom(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -176,8 +182,9 @@ qla2x00_sysfs_read_optrom(struct kobject *kobj, char *buf, loff_t off,
}
static ssize_t
-qla2x00_sysfs_write_optrom(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_write_optrom(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -198,16 +205,16 @@ static struct bin_attribute sysfs_optrom_attr = {
.attr = {
.name = "optrom",
.mode = S_IRUSR | S_IWUSR,
- .owner = THIS_MODULE,
},
- .size = OPTROM_SIZE_24XX,
+ .size = 0,
.read = qla2x00_sysfs_read_optrom,
.write = qla2x00_sysfs_write_optrom,
};
static ssize_t
-qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -245,7 +252,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
}
memset(ha->optrom_buffer, 0, ha->optrom_size);
- ha->isp_ops.read_optrom(ha, ha->optrom_buffer, 0,
+ ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0,
ha->optrom_size);
break;
case 2:
@@ -268,7 +275,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, char *buf, loff_t off,
if (ha->optrom_state != QLA_SWRITING)
break;
- ha->isp_ops.write_optrom(ha, ha->optrom_buffer, 0,
+ ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0,
ha->optrom_size);
break;
}
@@ -279,15 +286,15 @@ static struct bin_attribute sysfs_optrom_ctl_attr = {
.attr = {
.name = "optrom_ctl",
.mode = S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 0,
.write = qla2x00_sysfs_write_optrom_ctl,
};
static ssize_t
-qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_read_vpd(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -298,15 +305,17 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
/* Read NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size);
+ ha->isp_ops->read_nvram(ha, (uint8_t *)buf, ha->vpd_base,
+ ha->vpd_size);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return ha->vpd_size;
}
static ssize_t
-qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_write_vpd(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -317,7 +326,7 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off,
/* Write NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
+ ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return count;
@@ -327,7 +336,6 @@ static struct bin_attribute sysfs_vpd_attr = {
.attr = {
.name = "vpd",
.mode = S_IRUSR | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = 0,
.read = qla2x00_sysfs_read_vpd,
@@ -335,8 +343,9 @@ static struct bin_attribute sysfs_vpd_attr = {
};
static ssize_t
-qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+qla2x00_sysfs_read_sfp(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
@@ -375,7 +384,6 @@ static struct bin_attribute sysfs_sfp_attr = {
.attr = {
.name = "sfp",
.mode = S_IRUSR | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = SFP_DEV_SIZE * 2,
.read = qla2x00_sysfs_read_sfp,
@@ -403,7 +411,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
int ret;
for (iter = bin_file_entries; iter->name; iter++) {
- if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+ if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
continue;
ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
@@ -422,7 +430,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
struct sysfs_entry *iter;
for (iter = bin_file_entries; iter->name; iter++) {
- if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+ if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
continue;
sysfs_remove_bin_file(&host->shost_gendev.kobj,
@@ -430,7 +438,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
}
if (ha->beacon_blink_led == 1)
- ha->isp_ops.beacon_off(ha);
+ ha->isp_ops->beacon_off(ha);
}
/* Scsi_Host attributes. */
@@ -448,7 +456,7 @@ qla2x00_fw_version_show(struct class_device *cdev, char *buf)
char fw_str[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
- ha->isp_ops.fw_version_str(ha, fw_str));
+ ha->isp_ops->fw_version_str(ha, fw_str));
}
static ssize_t
@@ -500,7 +508,7 @@ qla2x00_pci_info_show(struct class_device *cdev, char *buf)
char pci_info[30];
return snprintf(buf, PAGE_SIZE, "%s\n",
- ha->isp_ops.pci_info_str(ha, pci_info));
+ ha->isp_ops->pci_info_str(ha, pci_info));
}
static ssize_t
@@ -645,9 +653,9 @@ qla2x00_beacon_store(struct class_device *cdev, const char *buf,
return -EINVAL;
if (val)
- rval = ha->isp_ops.beacon_on(ha);
+ rval = ha->isp_ops->beacon_on(ha);
else
- rval = ha->isp_ops.beacon_off(ha);
+ rval = ha->isp_ops->beacon_off(ha);
if (rval != QLA_SUCCESS)
count = 0;
@@ -891,7 +899,7 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
pfc_host_stat = &ha->fc_host_stat;
memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
sizeof(stat_buf) / 4, mb_stat);
} else if (atomic_read(&ha->loop_state) == LOOP_READY &&
@@ -959,6 +967,122 @@ qla2x00_get_host_port_state(struct Scsi_Host *shost)
fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
}
+static int
+qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
+{
+ int ret = 0;
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha;
+
+ ret = qla24xx_vport_create_req_sanity_check(fc_vport);
+ if (ret) {
+ DEBUG15(printk("qla24xx_vport_create_req_sanity_check failed, "
+ "status %x\n", ret));
+ return (ret);
+ }
+
+ vha = qla24xx_create_vhost(fc_vport);
+ if (vha == NULL) {
+ DEBUG15(printk ("qla24xx_create_vhost failed, vha = %p\n",
+ vha));
+ return FC_VPORT_FAILED;
+ }
+ if (disable) {
+ atomic_set(&vha->vp_state, VP_OFFLINE);
+ fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
+ } else
+ atomic_set(&vha->vp_state, VP_FAILED);
+
+ /* ready to create vport */
+ qla_printk(KERN_INFO, vha, "VP entry id %d assigned.\n", vha->vp_idx);
+
+ /* initialized vport states */
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ vha->vp_err_state= VP_ERR_PORTDWN;
+ vha->vp_prev_err_state= VP_ERR_UNKWN;
+ /* Check if physical ha port is Up */
+ if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+ atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ /* Don't retry or attempt login of this virtual port */
+ DEBUG15(printk ("scsi(%ld): pport loop_state is not UP.\n",
+ vha->host_no));
+ atomic_set(&vha->loop_state, LOOP_DEAD);
+ if (!disable)
+ fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
+ }
+
+ if (scsi_add_host(vha->host, &fc_vport->dev)) {
+ DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
+ vha->host_no, vha->vp_idx));
+ goto vport_create_failed_2;
+ }
+
+ /* initialize attributes */
+ fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
+ fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
+ fc_host_supported_classes(vha->host) =
+ fc_host_supported_classes(ha->host);
+ fc_host_supported_speeds(vha->host) =
+ fc_host_supported_speeds(ha->host);
+
+ qla24xx_vport_disable(fc_vport, disable);
+
+ return 0;
+vport_create_failed_2:
+ qla24xx_disable_vp(vha);
+ qla24xx_deallocate_vp_id(vha);
+ kfree(vha->port_name);
+ kfree(vha->node_name);
+ scsi_host_put(vha->host);
+ return FC_VPORT_FAILED;
+}
+
+int
+qla24xx_vport_delete(struct fc_vport *fc_vport)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha = fc_vport->dd_data;
+
+ qla24xx_disable_vp(vha);
+ qla24xx_deallocate_vp_id(vha);
+
+ down(&ha->vport_sem);
+ ha->cur_vport_count--;
+ clear_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+ up(&ha->vport_sem);
+
+ kfree(vha->node_name);
+ kfree(vha->port_name);
+
+ if (vha->timer_active) {
+ qla2x00_vp_stop_timer(vha);
+ DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p "
+ "has stopped\n",
+ vha->host_no, vha->vp_idx, vha));
+ }
+
+ fc_remove_host(vha->host);
+
+ scsi_remove_host(vha->host);
+
+ scsi_host_put(vha->host);
+
+ return 0;
+}
+
+int
+qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
+{
+ scsi_qla_host_t *vha = fc_vport->dd_data;
+
+ if (disable)
+ qla24xx_disable_vp(vha);
+ else
+ qla24xx_enable_vp(vha);
+
+ return 0;
+}
+
struct fc_function_template qla2xxx_transport_functions = {
.show_host_node_name = 1,
@@ -996,6 +1120,49 @@ struct fc_function_template qla2xxx_transport_functions = {
.issue_fc_host_lip = qla2x00_issue_lip,
.get_fc_host_stats = qla2x00_get_fc_host_stats,
+
+ .vport_create = qla24xx_vport_create,
+ .vport_disable = qla24xx_vport_disable,
+ .vport_delete = qla24xx_vport_delete,
+};
+
+struct fc_function_template qla2xxx_transport_vport_functions = {
+
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+
+ .get_host_port_id = qla2x00_get_host_port_id,
+ .show_host_port_id = 1,
+ .get_host_speed = qla2x00_get_host_speed,
+ .show_host_speed = 1,
+ .get_host_port_type = qla2x00_get_host_port_type,
+ .show_host_port_type = 1,
+ .get_host_symbolic_name = qla2x00_get_host_symbolic_name,
+ .show_host_symbolic_name = 1,
+ .set_host_system_hostname = qla2x00_set_host_system_hostname,
+ .show_host_system_hostname = 1,
+ .get_host_fabric_name = qla2x00_get_host_fabric_name,
+ .show_host_fabric_name = 1,
+ .get_host_port_state = qla2x00_get_host_port_state,
+ .show_host_port_state = 1,
+
+ .dd_fcrport_size = sizeof(struct fc_port *),
+ .show_rport_supported_classes = 1,
+
+ .get_starget_node_name = qla2x00_get_starget_node_name,
+ .show_starget_node_name = 1,
+ .get_starget_port_name = qla2x00_get_starget_port_name,
+ .show_starget_port_name = 1,
+ .get_starget_port_id = qla2x00_get_starget_port_id,
+ .show_starget_port_id = 1,
+
+ .get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo,
+ .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
+ .show_rport_dev_loss_tmo = 1,
+
+ .issue_fc_host_lip = qla2x00_issue_lip,
+ .get_fc_host_stats = qla2x00_get_fc_host_stats,
};
void
@@ -1004,4 +1171,6 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
+ fc_host_max_npiv_vports(ha->host) = MAX_NUM_VPORT_FABRIC;
+ fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
}
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index f6ed6962bc2b..563d18f4ff50 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -37,6 +37,121 @@ qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
return ptr + (ha->response_q_length * sizeof(response_t));
}
+static int
+qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
+ uint32_t cram_size, uint32_t *ext_mem, void **nxt)
+{
+ int rval;
+ uint32_t cnt, stat, timer, risc_address, ext_mem_cnt;
+ uint16_t mb[4];
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ rval = QLA_SUCCESS;
+ risc_address = ext_mem_cnt = 0;
+ memset(mb, 0, sizeof(mb));
+
+ /* Code RAM. */
+ risc_address = 0x20000;
+ WRT_REG_WORD(&reg->mailbox0, MBC_READ_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;
+
+ if (stat == 0x1 || stat == 0x2 ||
+ stat == 0x10 || stat == 0x11) {
+ 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);
+
+ 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_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;
+
+ if (stat == 0x1 || stat == 0x2 ||
+ stat == 0x10 || stat == 0x11) {
+ 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);
+
+ 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;
+ ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
+ } else {
+ rval = QLA_FUNCTION_FAILED;
+ }
+ }
+
+ *nxt = rval == QLA_SUCCESS ? &ext_mem[cnt]: NULL;
+ return rval;
+}
+
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
* @ha: HA context
@@ -633,11 +748,10 @@ void
qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
{
int rval;
- uint32_t cnt, timer;
+ uint32_t cnt;
uint32_t risc_address;
- uint16_t mb[4], wd;
+ uint16_t mb0, wd;
- uint32_t stat;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
uint32_t __iomem *dmp_reg;
uint32_t *iter_reg;
@@ -645,10 +759,9 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
unsigned long flags;
struct qla24xx_fw_dump *fw;
uint32_t ext_mem_cnt;
- void *eft;
+ void *nxt;
risc_address = ext_mem_cnt = 0;
- memset(mb, 0, sizeof(mb));
flags = 0;
if (!hardware_locked)
@@ -701,250 +814,236 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
/* Shadow registers. */
WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
RD_REG_DWORD(&reg->iobase_addr);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0000000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0100000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0200000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0300000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0400000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0500000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg));
-
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
- WRT_REG_DWORD(dmp_reg, 0xB0600000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg));
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
/* Mailbox registers. */
- mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+ mbx_reg = &reg->mailbox0;
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Receive sequence registers. */
iter_reg = fw->rseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Command DMA registers. */
WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Queues. */
iter_reg = fw->req0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 8; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+ dmp_reg = &reg->iobase_q;
for (cnt = 0; cnt < 7; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->resp0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 8; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+ dmp_reg = &reg->iobase_q;
for (cnt = 0; cnt < 7; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->req1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 8; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+ dmp_reg = &reg->iobase_q;
for (cnt = 0; cnt < 7; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt2_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt3_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt4_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
fw->xmt_data_dma_reg[cnt] =
htonl(RD_REG_DWORD(dmp_reg++));
@@ -952,221 +1051,221 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
/* Receive DMA registers. */
iter_reg = fw->rcvt0_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->rcvt1_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* RISC registers. */
iter_reg = fw->risc_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Local memory controller registers. */
iter_reg = fw->lmc_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Fibre Protocol Module registers. */
iter_reg = fw->fpm_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Frame Buffer registers. */
iter_reg = fw->fb_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
- dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+ dmp_reg = &reg->iobase_window;
for (cnt = 0; cnt < 16; cnt++)
*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
@@ -1187,10 +1286,10 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
udelay(100);
/* Wait for firmware to complete NVRAM accesses. */
- mb[0] = (uint32_t) RD_REG_WORD(&reg->mailbox0);
- for (cnt = 10000 ; cnt && mb[0]; cnt--) {
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ for (cnt = 10000 ; cnt && mb0; cnt--) {
udelay(5);
- mb[0] = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
barrier();
}
@@ -1214,110 +1313,717 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
rval = QLA_FUNCTION_TIMEOUT;
}
- /* Memory. */
+ if (rval == QLA_SUCCESS)
+ rval = qla2xxx_dump_memory(ha, fw->code_ram,
+ sizeof(fw->code_ram), fw->ext_mem, &nxt);
+
if (rval == QLA_SUCCESS) {
- /* Code RAM. */
- risc_address = 0x20000;
- WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
- clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+ nxt = qla2xxx_copy_queues(ha, nxt);
+ if (ha->eft)
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
}
- for (cnt = 0; cnt < sizeof(fw->code_ram) / 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;
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_WARNING, ha,
+ "Failed to dump firmware (%x)!!!\n", rval);
+ ha->fw_dumped = 0;
- if (stat == 0x1 || stat == 0x2 ||
- stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
+ } else {
+ qla_printk(KERN_INFO, ha,
+ "Firmware dump saved to temp buffer (%ld/%p).\n",
+ ha->host_no, ha->fw_dump);
+ ha->fw_dumped = 1;
+ }
- mb[0] = RD_REG_WORD(&reg->mailbox0);
- mb[2] = RD_REG_WORD(&reg->mailbox2);
- mb[3] = RD_REG_WORD(&reg->mailbox3);
+qla24xx_fw_dump_failed:
+ if (!hardware_locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
- WRT_REG_DWORD(&reg->hccr,
- HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- break;
- }
+void
+qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
+{
+ int rval;
+ uint32_t cnt;
+ uint32_t risc_address;
+ uint16_t mb0, wd;
- /* 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);
- }
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+ uint32_t __iomem *dmp_reg;
+ uint32_t *iter_reg;
+ uint16_t __iomem *mbx_reg;
+ unsigned long flags;
+ struct qla25xx_fw_dump *fw;
+ uint32_t ext_mem_cnt;
+ void *nxt;
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb[0] & MBS_MASK;
- fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
- } else {
- rval = QLA_FUNCTION_FAILED;
+ risc_address = ext_mem_cnt = 0;
+ flags = 0;
+
+ if (!hardware_locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ if (!ha->fw_dump) {
+ qla_printk(KERN_WARNING, ha,
+ "No buffer available for dump!!!\n");
+ goto qla25xx_fw_dump_failed;
+ }
+
+ if (ha->fw_dumped) {
+ qla_printk(KERN_WARNING, ha,
+ "Firmware has been previously dumped (%p) -- ignoring "
+ "request...\n", ha->fw_dump);
+ goto qla25xx_fw_dump_failed;
+ }
+ fw = &ha->fw_dump->isp.isp25;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
+
+ rval = QLA_SUCCESS;
+ fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
+
+ /* Pause RISC. */
+ if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
+ HCCRX_CLR_HOST_INT);
+ RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
+ WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+ for (cnt = 30000;
+ (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
}
}
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_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+ /* Host interface registers. */
+ dmp_reg = (uint32_t __iomem *)(reg + 0);
+ for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
- for (timer = 6000000; timer; timer--) {
- /* Check for pending interrupts. */
- stat = RD_REG_DWORD(&reg->host_status);
- if (stat & HSRX_RISC_INT) {
- stat &= 0xff;
+ /* Disable interrupts. */
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
- if (stat == 0x1 || stat == 0x2 ||
- stat == 0x10 || stat == 0x11) {
- set_bit(MBX_INTERRUPT,
- &ha->mbx_cmd_flags);
+ /* Shadow registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ RD_REG_DWORD(&reg->iobase_addr);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
- mb[0] = RD_REG_WORD(&reg->mailbox0);
- mb[2] = RD_REG_WORD(&reg->mailbox2);
- mb[3] = RD_REG_WORD(&reg->mailbox3);
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
- WRT_REG_DWORD(&reg->hccr,
- HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- break;
- }
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
- /* Clear this intr; it wasn't a mailbox intr */
- WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
- RD_REG_DWORD(&reg->hccr);
- }
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+ fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+ fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+ fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+ fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+ /* RISC I/O register. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+ RD_REG_DWORD(&reg->iobase_addr);
+ fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+ /* Mailbox registers. */
+ mbx_reg = &reg->mailbox0;
+ for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+ /* Transfer sequence registers. */
+ iter_reg = fw->xseq_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xseq_0_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFC0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFD0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
+ fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Receive sequence registers. */
+ iter_reg = fw->rseq_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->rseq_0_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFC0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
+ fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
+ fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Auxiliary sequence registers. */
+ iter_reg = fw->aseq_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB050);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB060);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB070);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->aseq_0_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0C0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0D0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0E0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->aseq_1_reg) / 4; cnt++)
+ fw->aseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0xB0F0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->aseq_2_reg) / 4; cnt++)
+ fw->aseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Command DMA registers. */
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
+ fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Queues. */
+ iter_reg = fw->req0_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 8; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->resp0_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 8; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->req1_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 8; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ dmp_reg = &reg->iobase_q;
+ for (cnt = 0; cnt < 7; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Transmit DMA registers. */
+ iter_reg = fw->xmt0_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt1_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt2_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt3_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->xmt4_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
+ fw->xmt_data_dma_reg[cnt] =
+ htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Receive DMA registers. */
+ iter_reg = fw->rcvt0_data_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ iter_reg = fw->rcvt1_data_dma_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* RISC registers. */
+ iter_reg = fw->risc_gp_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Local memory controller registers. */
+ iter_reg = fw->lmc_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x3070);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Fibre Protocol Module registers. */
+ iter_reg = fw->fpm_hdw_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Frame Buffer registers. */
+ iter_reg = fw->fb_hdw_reg;
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ WRT_REG_DWORD(&reg->iobase_addr, 0x6F00);
+ dmp_reg = &reg->iobase_window;
+ for (cnt = 0; cnt < 16; cnt++)
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+ /* Reset RISC. */
+ WRT_REG_DWORD(&reg->ctrl_status,
+ CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) &
+ CSRX_DMA_ACTIVE) == 0)
+ break;
+
+ udelay(10);
+ }
+
+ WRT_REG_DWORD(&reg->ctrl_status,
+ CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
+
+ udelay(100);
+ /* Wait for firmware to complete NVRAM accesses. */
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ for (cnt = 10000 ; cnt && mb0; cnt--) {
udelay(5);
+ mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+ barrier();
}
- if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
- rval = mb[0] & MBS_MASK;
- fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
- } else {
- rval = QLA_FUNCTION_FAILED;
+ /* Wait for soft-reset to complete. */
+ for (cnt = 0; cnt < 30000; cnt++) {
+ if ((RD_REG_DWORD(&reg->ctrl_status) &
+ CSRX_ISP_SOFT_RESET) == 0)
+ break;
+
+ udelay(10);
}
+ WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
+ RD_REG_DWORD(&reg->hccr); /* PCI Posting. */
}
+ for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
+ rval == QLA_SUCCESS; cnt--) {
+ if (cnt)
+ udelay(100);
+ else
+ rval = QLA_FUNCTION_TIMEOUT;
+ }
+
+ if (rval == QLA_SUCCESS)
+ rval = qla2xxx_dump_memory(ha, fw->code_ram,
+ sizeof(fw->code_ram), fw->ext_mem, &nxt);
+
if (rval == QLA_SUCCESS) {
- eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]);
+ nxt = qla2xxx_copy_queues(ha, nxt);
if (ha->eft)
- memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size));
+ memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
}
if (rval != QLA_SUCCESS) {
@@ -1332,7 +2038,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
ha->fw_dumped = 1;
}
-qla24xx_fw_dump_failed:
+qla25xx_fw_dump_failed:
if (!hardware_locked)
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
@@ -1411,9 +2117,9 @@ qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd)
printk("0x%02x ", cmd->cmnd[i]);
}
printk("\n seg_cnt=%d, allowed=%d, retries=%d\n",
- cmd->use_sg, cmd->allowed, cmd->retries);
+ scsi_sg_count(cmd), cmd->allowed, cmd->retries);
printk(" request buffer=0x%p, request buffer len=0x%x\n",
- cmd->request_buffer, cmd->request_bufflen);
+ scsi_sglist(cmd), scsi_bufflen(cmd));
printk(" tag=%d, transfersize=0x%x\n",
cmd->tag, cmd->transfersize);
printk(" serial_number=%lx, SP=%p\n", cmd->serial_number, sp);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 5b12278968e0..cca4b0d8253e 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -21,6 +21,7 @@
/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
+/* #define QL_DEBUG_LEVEL_15 */ /* Output NPIV trace msgs */
/*
* Local Macro Definitions.
*/
@@ -30,7 +31,8 @@
defined(QL_DEBUG_LEVEL_7) || defined(QL_DEBUG_LEVEL_8) || \
defined(QL_DEBUG_LEVEL_9) || defined(QL_DEBUG_LEVEL_10) || \
defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \
- defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14)
+ defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14) || \
+ defined(QL_DEBUG_LEVEL_15)
#define QL_DEBUG_ROUTINES
#endif
@@ -125,6 +127,12 @@
#define DEBUG14(x) do {} while (0)
#endif
+#if defined(QL_DEBUG_LEVEL_15)
+#define DEBUG15(x) do {x;} while (0)
+#else
+#define DEBUG15(x) do {} while (0)
+#endif
+
/*
* Firmware Dump structure definition
*/
@@ -205,6 +213,43 @@ struct qla24xx_fw_dump {
uint32_t ext_mem[1];
};
+struct qla25xx_fw_dump {
+ uint32_t host_status;
+ uint32_t host_reg[32];
+ uint32_t shadow_reg[11];
+ uint32_t risc_io_reg;
+ uint16_t mailbox_reg[32];
+ uint32_t xseq_gp_reg[128];
+ uint32_t xseq_0_reg[48];
+ uint32_t xseq_1_reg[16];
+ uint32_t rseq_gp_reg[128];
+ uint32_t rseq_0_reg[32];
+ uint32_t rseq_1_reg[16];
+ uint32_t rseq_2_reg[16];
+ uint32_t aseq_gp_reg[128];
+ uint32_t aseq_0_reg[32];
+ uint32_t aseq_1_reg[16];
+ uint32_t aseq_2_reg[16];
+ uint32_t cmd_dma_reg[16];
+ uint32_t req0_dma_reg[15];
+ uint32_t resp0_dma_reg[15];
+ uint32_t req1_dma_reg[15];
+ uint32_t xmt0_dma_reg[32];
+ uint32_t xmt1_dma_reg[32];
+ uint32_t xmt2_dma_reg[32];
+ uint32_t xmt3_dma_reg[32];
+ uint32_t xmt4_dma_reg[32];
+ uint32_t xmt_data_dma_reg[16];
+ uint32_t rcvt0_data_dma_reg[32];
+ uint32_t rcvt1_data_dma_reg[32];
+ uint32_t risc_gp_reg[128];
+ uint32_t lmc_reg[128];
+ uint32_t fpm_hdw_reg[192];
+ uint32_t fb_hdw_reg[192];
+ uint32_t code_ram[0x2000];
+ uint32_t ext_mem[1];
+};
+
#define EFT_NUM_BUFFERS 4
#define EFT_BYTES_PER_BUFFER 0x4000
#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
@@ -238,5 +283,6 @@ struct qla2xxx_fw_dump {
struct qla2100_fw_dump isp21;
struct qla2300_fw_dump isp23;
struct qla24xx_fw_dump isp24;
+ struct qla25xx_fw_dump isp25;
} isp;
};
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index e8948b679f5b..0c9f36c8a248 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1551,6 +1551,9 @@ typedef struct fc_port {
unsigned long last_queue_full;
unsigned long last_ramp_up;
+
+ struct list_head vp_fcport;
+ uint16_t vp_idx;
} fc_port_t;
/*
@@ -1708,6 +1711,14 @@ struct ct_fdmi_hba_attributes {
#define FDMI_PORT_OS_DEVICE_NAME 5
#define FDMI_PORT_HOST_NAME 6
+#define FDMI_PORT_SPEED_1GB 0x1
+#define FDMI_PORT_SPEED_2GB 0x2
+#define FDMI_PORT_SPEED_10GB 0x4
+#define FDMI_PORT_SPEED_4GB 0x8
+#define FDMI_PORT_SPEED_8GB 0x10
+#define FDMI_PORT_SPEED_16GB 0x20
+#define FDMI_PORT_SPEED_UNKNOWN 0x8000
+
struct ct_fdmi_port_attr {
uint16_t type;
uint16_t len;
@@ -1999,6 +2010,36 @@ struct gid_list_info {
};
#define GID_LIST_SIZE (sizeof(struct gid_list_info) * MAX_FIBRE_DEVICES)
+/* NPIV */
+typedef struct vport_info {
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+ int vp_id;
+ uint16_t loop_id;
+ unsigned long host_no;
+ uint8_t port_id[3];
+ int loop_state;
+} vport_info_t;
+
+typedef struct vport_params {
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+ uint32_t options;
+#define VP_OPTS_RETRY_ENABLE BIT_0
+#define VP_OPTS_VP_DISABLE BIT_1
+} vport_params_t;
+
+/* NPIV - return codes of VP create and modify */
+#define VP_RET_CODE_OK 0
+#define VP_RET_CODE_FATAL 1
+#define VP_RET_CODE_WRONG_ID 2
+#define VP_RET_CODE_WWPN 3
+#define VP_RET_CODE_RESOURCES 4
+#define VP_RET_CODE_NO_MEM 5
+#define VP_RET_CODE_NOT_FOUND 6
+
+#define to_qla_parent(x) (((x)->parent) ? (x)->parent : (x))
+
/*
* ISP operations
*/
@@ -2073,6 +2114,16 @@ struct qla_msix_entry {
uint16_t msix_entry;
};
+#define WATCH_INTERVAL 1 /* number of seconds */
+
+/* NPIV */
+#define MAX_MULTI_ID_LOOP 126
+#define MAX_MULTI_ID_FABRIC 64
+#define MAX_NUM_VPORT_LOOP (MAX_MULTI_ID_LOOP - 1)
+#define MAX_NUM_VPORT_FABRIC (MAX_MULTI_ID_FABRIC - 1)
+#define MAX_NUM_VHBA_LOOP (MAX_MULTI_ID_LOOP - 1)
+#define MAX_NUM_VHBA_FABRIC (MAX_MULTI_ID_FABRIC - 1)
+
/*
* Linux Host Adapter structure
*/
@@ -2108,6 +2159,8 @@ typedef struct scsi_qla_host {
uint32_t msix_enabled :1;
uint32_t disable_serdes :1;
uint32_t gpsc_supported :1;
+ uint32_t vsan_enabled :1;
+ uint32_t npiv_supported :1;
} flags;
atomic_t loop_state;
@@ -2147,6 +2200,7 @@ typedef struct scsi_qla_host {
#define BEACON_BLINK_NEEDED 25
#define REGISTER_FDMI_NEEDED 26
#define FCPORT_UPDATE_NEEDED 27
+#define VP_DPC_NEEDED 28 /* wake up for VP dpc handling */
uint32_t device_flags;
#define DFLG_LOCAL_DEVICES BIT_0
@@ -2155,6 +2209,7 @@ typedef struct scsi_qla_host {
#define SWITCH_FOUND BIT_3
#define DFLG_NO_CABLE BIT_4
+#define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532
uint32_t device_type;
#define DT_ISP2100 BIT_0
#define DT_ISP2200 BIT_1
@@ -2167,8 +2222,11 @@ typedef struct scsi_qla_host {
#define DT_ISP2432 BIT_8
#define DT_ISP5422 BIT_9
#define DT_ISP5432 BIT_10
-#define DT_ISP_LAST (DT_ISP5432 << 1)
+#define DT_ISP2532 BIT_11
+#define DT_ISP_LAST (DT_ISP2532 << 1)
+#define DT_IIDMA BIT_26
+#define DT_FWI2 BIT_27
#define DT_ZIO_SUPPORTED BIT_28
#define DT_OEM_001 BIT_29
#define DT_ISP2200A BIT_30
@@ -2186,12 +2244,16 @@ typedef struct scsi_qla_host {
#define IS_QLA2432(ha) (DT_MASK(ha) & DT_ISP2432)
#define IS_QLA5422(ha) (DT_MASK(ha) & DT_ISP5422)
#define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432)
+#define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
#define IS_QLA24XX(ha) (IS_QLA2422(ha) || IS_QLA2432(ha))
#define IS_QLA54XX(ha) (IS_QLA5422(ha) || IS_QLA5432(ha))
+#define IS_QLA25XX(ha) (IS_QLA2532(ha))
+#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
+#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)
#define IS_ZIO_SUPPORTED(ha) ((ha)->device_type & DT_ZIO_SUPPORTED)
#define IS_OEM_001(ha) ((ha)->device_type & DT_OEM_001)
#define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS)
@@ -2228,7 +2290,7 @@ typedef struct scsi_qla_host {
uint16_t rsp_ring_index; /* Current index. */
uint16_t response_q_length;
- struct isp_operations isp_ops;
+ struct isp_operations *isp_ops;
/* Outstandings ISP commands. */
srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS];
@@ -2237,6 +2299,11 @@ typedef struct scsi_qla_host {
/* ISP configuration data. */
uint16_t loop_id; /* Host adapter loop id */
+ uint16_t switch_cap;
+#define FLOGI_SEQ_DEL BIT_8
+#define FLOGI_MID_SUPPORT BIT_10
+#define FLOGI_VSAN_SUPPORT BIT_12
+#define FLOGI_SP_SUPPORT BIT_13
uint16_t fb_rev;
port_id_t d_id; /* Host adapter port id */
@@ -2247,6 +2314,7 @@ typedef struct scsi_qla_host {
#define PORT_SPEED_1GB 0x00
#define PORT_SPEED_2GB 0x01
#define PORT_SPEED_4GB 0x03
+#define PORT_SPEED_8GB 0x04
uint16_t link_data_rate; /* F/W operating speed */
uint8_t current_topology;
@@ -2344,6 +2412,7 @@ typedef struct scsi_qla_host {
#define MBX_UPDATE_FLASH_ACTIVE 3
struct semaphore mbx_cmd_sem; /* Serialialize mbx access */
+ struct semaphore vport_sem; /* Virtual port synchronization */
struct semaphore mbx_intr_sem; /* Used for completion notification */
uint32_t mbx_flags;
@@ -2428,6 +2497,37 @@ typedef struct scsi_qla_host {
struct fc_host_statistics fc_host_stat;
struct qla_msix_entry msix_entries[QLA_MSIX_ENTRIES];
+
+ struct list_head vp_list; /* list of VP */
+ struct fc_vport *fc_vport; /* holds fc_vport * for each vport */
+ uint8_t vp_idx_map[16];
+ uint16_t num_vhosts; /* number of vports created */
+ uint16_t num_vsans; /* number of vsan created */
+ uint16_t vp_idx; /* vport ID */
+
+ struct scsi_qla_host *parent; /* holds pport */
+ unsigned long vp_flags;
+ struct list_head vp_fcports; /* list of fcports */
+#define VP_IDX_ACQUIRED 0 /* bit no 0 */
+#define VP_CREATE_NEEDED 1
+#define VP_BIND_NEEDED 2
+#define VP_DELETE_NEEDED 3
+#define VP_SCR_NEEDED 4 /* State Change Request registration */
+ atomic_t vp_state;
+#define VP_OFFLINE 0
+#define VP_ACTIVE 1
+#define VP_FAILED 2
+// #define VP_DISABLE 3
+ uint16_t vp_err_state;
+ uint16_t vp_prev_err_state;
+#define VP_ERR_UNKWN 0
+#define VP_ERR_PORTDWN 1
+#define VP_ERR_FAB_UNSUPPORTED 2
+#define VP_ERR_FAB_NORESOURCES 3
+#define VP_ERR_FAB_LOGOUT 4
+#define VP_ERR_ADAP_NORESOURCES 5
+ int max_npiv_vports; /* 63 or 125 per topoloty */
+ int cur_vport_count;
} scsi_qla_host_t;
@@ -2481,6 +2581,7 @@ typedef struct scsi_qla_host {
#define OPTROM_SIZE_2300 0x20000
#define OPTROM_SIZE_2322 0x100000
#define OPTROM_SIZE_24XX 0x100000
+#define OPTROM_SIZE_25XX 0x200000
#include "qla_gbl.h"
#include "qla_dbg.h"
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index a0a722cf4237..99fe49618d61 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -8,14 +8,17 @@
#define __QLA_FW_H
#define MBS_CHECKSUM_ERROR 0x4010
+#define MBS_INVALID_PRODUCT_KEY 0x4020
/*
* Firmware Options.
*/
#define FO1_ENABLE_PUREX BIT_10
#define FO1_DISABLE_LED_CTRL BIT_6
+#define FO1_ENABLE_8016 BIT_0
#define FO2_ENABLE_SEL_CLASS2 BIT_5
#define FO3_NO_ABTS_ON_LINKDOWN BIT_14
+#define FO3_HOLD_STS_IOCB BIT_12
/*
* Port Database structure definition for ISP 24xx.
@@ -69,6 +72,16 @@ struct port_database_24xx {
uint8_t reserved_3[24];
};
+struct vp_database_24xx {
+ uint16_t vp_status;
+ uint8_t options;
+ uint8_t id;
+ uint8_t port_name[WWN_SIZE];
+ uint8_t node_name[WWN_SIZE];
+ uint16_t port_id_low;
+ uint16_t port_id_high;
+};
+
struct nvram_24xx {
/* NVRAM header. */
uint8_t id[4];
@@ -331,7 +344,9 @@ struct init_cb_24xx {
* BIT 10 = Reserved
* BIT 11 = Enable FC-SP Security
* BIT 12 = FC Tape Enable
- * BIT 13-31 = Reserved
+ * BIT 13 = Reserved
+ * BIT 14 = Enable Target PRLI Control
+ * BIT 15-31 = Reserved
*/
uint32_t firmware_options_2;
@@ -353,7 +368,8 @@ struct init_cb_24xx {
* BIT 13 = Data Rate bit 0
* BIT 14 = Data Rate bit 1
* BIT 15 = Data Rate bit 2
- * BIT 16-31 = Reserved
+ * BIT 16 = Enable 75 ohm Termination Select
+ * BIT 17-31 = Reserved
*/
uint32_t firmware_options_3;
@@ -425,6 +441,7 @@ struct cmd_type_7 {
#define TMF_LUN_RESET BIT_12
#define TMF_CLEAR_TASK_SET BIT_10
#define TMF_ABORT_TASK_SET BIT_9
+#define TMF_DSD_LIST_ENABLE BIT_2
#define TMF_READ_DATA BIT_1
#define TMF_WRITE_DATA BIT_0
@@ -579,7 +596,7 @@ struct els_entry_24xx {
#define EST_SOFI3 (1 << 4)
#define EST_SOFI2 (3 << 4)
- uint32_t rx_xchg_address[2]; /* Receive exchange address. */
+ uint32_t rx_xchg_address; /* Receive exchange address. */
uint16_t rx_dsd_count;
uint8_t opcode;
@@ -640,6 +657,7 @@ struct logio_entry_24xx {
uint16_t control_flags; /* Control flags. */
/* Modifiers. */
+#define LCF_INCLUDE_SNS BIT_10 /* Include SNS (FFFFFC) during LOGO. */
#define LCF_FCP2_OVERRIDE BIT_9 /* Set/Reset word 3 of PRLI. */
#define LCF_CLASS_2 BIT_8 /* Enable class 2 during PLOGI. */
#define LCF_FREE_NPORT BIT_7 /* Release NPORT handle after LOGO. */
@@ -769,6 +787,15 @@ struct device_reg_24xx {
#define FA_RISC_CODE_ADDR 0x20000
#define FA_RISC_CODE_SEGMENTS 2
+#define FA_FW_AREA_ADDR 0x40000
+#define FA_VPD_NVRAM_ADDR 0x48000
+#define FA_FEATURE_ADDR 0x4C000
+#define FA_FLASH_DESCR_ADDR 0x50000
+#define FA_HW_EVENT_ADDR 0x54000
+#define FA_BOOT_LOG_ADDR 0x58000
+#define FA_FW_DUMP0_ADDR 0x60000
+#define FA_FW_DUMP1_ADDR 0x70000
+
uint32_t flash_data; /* Flash/NVRAM BIOS data. */
uint32_t ctrl_status; /* Control/Status. */
@@ -849,10 +876,13 @@ struct device_reg_24xx {
#define HCCRX_CLR_RISC_INT 0xA0000000
uint32_t gpiod; /* GPIO Data register. */
+
/* LED update mask. */
#define GPDX_LED_UPDATE_MASK (BIT_20|BIT_19|BIT_18)
/* Data update mask. */
#define GPDX_DATA_UPDATE_MASK (BIT_17|BIT_16)
+ /* Data update mask. */
+#define GPDX_DATA_UPDATE_2_MASK (BIT_28|BIT_27|BIT_26|BIT_17|BIT_16)
/* LED control mask. */
#define GPDX_LED_COLOR_MASK (BIT_4|BIT_3|BIT_2)
/* LED bit values. Color names as
@@ -867,6 +897,8 @@ struct device_reg_24xx {
uint32_t gpioe; /* GPIO Enable register. */
/* Enable update mask. */
#define GPEX_ENABLE_UPDATE_MASK (BIT_17|BIT_16)
+ /* Enable update mask. */
+#define GPEX_ENABLE_UPDATE_2_MASK (BIT_28|BIT_27|BIT_26|BIT_17|BIT_16)
/* Enable. */
#define GPEX_ENABLE (BIT_1|BIT_0)
@@ -906,6 +938,14 @@ struct device_reg_24xx {
uint16_t mailbox29;
uint16_t mailbox30;
uint16_t mailbox31;
+
+ uint32_t iobase_window;
+ uint32_t unused_4[8]; /* Gap. */
+ uint32_t iobase_q;
+ uint32_t unused_5[2]; /* Gap. */
+ uint32_t iobase_select;
+ uint32_t unused_6[2]; /* Gap. */
+ uint32_t iobase_sdata;
};
/* MID Support ***************************************************************/
@@ -962,6 +1002,25 @@ struct mid_db_24xx {
struct mid_db_entry_24xx entries[MAX_MID_VPS];
};
+ /*
+ * 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
+ */
#define VP_CTRL_IOCB_TYPE 0x30 /* Vitual Port Control entry. */
struct vp_ctrl_entry_24xx {
uint8_t entry_type; /* Entry type. */
@@ -974,6 +1033,7 @@ struct vp_ctrl_entry_24xx {
uint16_t vp_idx_failed;
uint16_t comp_status; /* Completion status. */
+#define CS_VCE_IOCB_ERROR 0x01 /* Error processing IOCB */
#define CS_VCE_ACQ_ID_ERROR 0x02 /* Error while acquireing ID. */
#define CS_VCE_BUSY 0x05 /* Firmware not ready to accept cmd. */
@@ -982,24 +1042,34 @@ struct vp_ctrl_entry_24xx {
#define VCE_COMMAND_DISABLE_VPS 0x08 /* Disable VPs. */
#define VCE_COMMAND_DISABLE_VPS_REINIT 0x09 /* Disable VPs and reinit link. */
#define VCE_COMMAND_DISABLE_VPS_LOGO 0x0a /* Disable VPs and LOGO ports. */
+#define VCE_COMMAND_DISABLE_VPS_LOGO_ALL 0x0b /* Disable VPs and LOGO ports. */
uint16_t vp_count;
uint8_t vp_idx_map[16];
-
- uint8_t reserved_4[32];
+ uint16_t flags;
+ struct vf_id id;
+ uint16_t reserved_4;
+ struct vf_hopct hopct;
+ uint8_t reserved_5[8];
};
+/*
+ * Modify Virtual Port Configuration IOCB
+ */
#define VP_CONFIG_IOCB_TYPE 0x31 /* Vitual Port Config entry. */
struct vp_config_entry_24xx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
- uint8_t sys_define; /* System defined. */
+ uint8_t handle_count;
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System handle. */
- uint16_t reserved_1;
+ uint16_t flags;
+#define CS_VF_BIND_VPORTS_TO_VF BIT_0
+#define CS_VF_SET_QOS_OF_VPORTS BIT_1
+#define CS_VF_SET_HOPS_OF_VPORTS BIT_2
uint16_t comp_status; /* Completion status. */
#define CS_VCT_STS_ERROR 0x01 /* Specified VPs were not disabled. */
@@ -1009,27 +1079,29 @@ struct vp_config_entry_24xx {
#define CS_VCT_BUSY 0x05 /* Firmware not ready to accept cmd. */
uint8_t command;
-#define VCT_COMMAND_MOD_VPS 0x00 /* Enable VPs. */
-#define VCT_COMMAND_MOD_ENABLE_VPS 0x08 /* Disable VPs. */
+#define VCT_COMMAND_MOD_VPS 0x00 /* Modify VP configurations. */
+#define VCT_COMMAND_MOD_ENABLE_VPS 0x01 /* Modify configuration & enable VPs. */
uint8_t vp_count;
- uint8_t vp_idx1;
- uint8_t vp_idx2;
+ uint8_t vp_index1;
+ uint8_t vp_index2;
uint8_t options_idx1;
uint8_t hard_address_idx1;
- uint16_t reserved_2;
+ uint16_t reserved_vp1;
uint8_t port_name_idx1[WWN_SIZE];
uint8_t node_name_idx1[WWN_SIZE];
uint8_t options_idx2;
uint8_t hard_address_idx2;
- uint16_t reserved_3;
+ uint16_t reserved_vp2;
uint8_t port_name_idx2[WWN_SIZE];
uint8_t node_name_idx2[WWN_SIZE];
-
- uint8_t reserved_4[8];
+ struct vf_id id;
+ uint16_t reserved_4;
+ struct vf_hopct hopct;
+ uint8_t reserved_5;
};
#define VP_RPT_ID_IOCB_TYPE 0x32 /* Report ID Acquisition entry. */
@@ -1054,5 +1126,30 @@ struct vp_rpt_id_entry_24xx {
uint8_t reserved_4[32];
};
+#define VF_EVFP_IOCB_TYPE 0x26 /* Exchange Virtual Fabric Parameters entry. */
+struct vf_evfp_entry_24xx {
+ uint8_t entry_type; /* Entry type. */
+ uint8_t entry_count; /* Entry count. */
+ uint8_t sys_define; /* System defined. */
+ uint8_t entry_status; /* Entry Status. */
+
+ uint32_t handle; /* System handle. */
+ uint16_t comp_status; /* Completion status. */
+ uint16_t timeout; /* timeout */
+ uint16_t adim_tagging_mode;
+
+ uint16_t vfport_id;
+ uint32_t exch_addr;
+
+ uint16_t nport_handle; /* N_PORT handle. */
+ uint16_t control_flags;
+ uint32_t io_parameter_0;
+ uint32_t io_parameter_1;
+ uint32_t tx_address[2]; /* Data segment 0 address. */
+ uint32_t tx_len; /* Data segment 0 length. */
+ uint32_t rx_address[2]; /* Data segment 1 address. */
+ uint32_t rx_len; /* Data segment 1 length. */
+};
+
/* END MID Support ***********************************************************/
#endif
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 74544ae4b0e2..aa1e41152283 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -17,6 +17,7 @@ extern int qla2x00_initialize_adapter(scsi_qla_host_t *);
extern int qla2100_pci_config(struct scsi_qla_host *);
extern int qla2300_pci_config(struct scsi_qla_host *);
extern int qla24xx_pci_config(scsi_qla_host_t *);
+extern int qla25xx_pci_config(scsi_qla_host_t *);
extern void qla2x00_reset_chip(struct scsi_qla_host *);
extern void qla24xx_reset_chip(struct scsi_qla_host *);
extern int qla2x00_chip_diag(struct scsi_qla_host *);
@@ -62,6 +63,38 @@ extern int ql2xfdmienable;
extern int ql2xallocfwdump;
extern int ql2xextended_error_logging;
extern int ql2xqfullrampup;
+extern int num_hosts;
+
+/*
+ * Global Functions in qla_mid.c source file.
+ */
+extern struct scsi_host_template qla2x00_driver_template;
+extern struct scsi_host_template qla24xx_driver_template;
+extern struct scsi_transport_template *qla2xxx_transport_vport_template;
+extern uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+extern void qla2x00_timer(scsi_qla_host_t *);
+extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long);
+extern void qla2x00_stop_timer(scsi_qla_host_t *);
+extern uint32_t qla24xx_allocate_vp_id(scsi_qla_host_t *);
+extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *);
+extern int qla24xx_disable_vp (scsi_qla_host_t *);
+extern int qla24xx_enable_vp (scsi_qla_host_t *);
+extern void qla2x00_mem_free(scsi_qla_host_t *);
+extern int qla24xx_control_vp(scsi_qla_host_t *, int );
+extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
+extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
+extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
+extern int qla24xx_configure_vhba (scsi_qla_host_t *);
+extern int qla24xx_get_vp_entry(scsi_qla_host_t *, uint16_t, int);
+extern int qla24xx_get_vp_database(scsi_qla_host_t *, uint16_t);
+extern int qla2x00_do_dpc_vp(scsi_qla_host_t *);
+extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
+ struct vp_rpt_id_entry_24xx *);
+extern scsi_qla_host_t * qla24xx_find_vhost_by_name(scsi_qla_host_t *,
+ uint8_t *);
+extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
+extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
+extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *);
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -77,6 +110,10 @@ extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *);
extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
+extern void qla2x00_alert_all_vps(scsi_qla_host_t *, uint16_t *);
+extern void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
+extern void qla2x00_vp_abort_isp(scsi_qla_host_t *);
+extern int qla24xx_vport_delete(struct fc_vport *);
/*
* Global Function Prototypes in qla_iocb.c source file.
@@ -128,7 +165,7 @@ qla2x00_abort_target(fc_port_t *);
extern int
qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
- uint8_t *, uint16_t *);
+ uint8_t *, uint16_t *, uint16_t *);
extern int
qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *);
@@ -245,6 +282,10 @@ extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
uint32_t);
+extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+ uint32_t);
+extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+ uint32_t);
extern int qla2x00_beacon_on(struct scsi_qla_host *);
extern int qla2x00_beacon_off(struct scsi_qla_host *);
@@ -271,6 +312,7 @@ extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *);
extern void qla2100_fw_dump(scsi_qla_host_t *, int);
extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
extern void qla2x00_dump_regs(scsi_qla_host_t *);
extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
@@ -303,6 +345,7 @@ struct class_device_attribute;
extern struct class_device_attribute *qla2x00_host_attrs[];
struct fc_function_template;
extern struct fc_function_template qla2xxx_transport_functions;
+extern struct fc_function_template qla2xxx_transport_vport_functions;
extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *);
extern void qla2x00_init_host_attr(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index ec5b2dd90d6a..b06cbb8580d3 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -88,6 +88,7 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size)
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ ct_pkt->vp_index = ha->vp_idx;
return (ct_pkt);
}
@@ -126,7 +127,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *ha, ms_iocb_entry_t *ms_pkt,
DEBUG2_3(printk("scsi(%ld): %s failed, error status (%x).\n",
ha->host_no, routine, ms_pkt->entry_status));
} else {
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
comp_status = le16_to_cpu(
((struct ct_entry_24xx *)ms_pkt)->comp_status);
else
@@ -179,7 +180,8 @@ qla2x00_ga_nxt(scsi_qla_host_t *ha, fc_port_t *fcport)
/* Issue GA_NXT */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GA_NXT_REQ_SIZE, GA_NXT_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GA_NXT_REQ_SIZE,
+ GA_NXT_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD,
@@ -265,7 +267,8 @@ qla2x00_gid_pt(scsi_qla_host_t *ha, sw_info_t *list)
/* Issue GID_PT */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GID_PT_REQ_SIZE, GID_PT_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GID_PT_REQ_SIZE,
+ GID_PT_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
@@ -337,7 +340,7 @@ qla2x00_gpn_id(scsi_qla_host_t *ha, sw_info_t *list)
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
/* Issue GPN_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GPN_ID_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GPN_ID_REQ_SIZE,
GPN_ID_RSP_SIZE);
/* Prepare CT request */
@@ -398,7 +401,7 @@ qla2x00_gnn_id(scsi_qla_host_t *ha, sw_info_t *list)
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
/* Issue GNN_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GNN_ID_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GNN_ID_REQ_SIZE,
GNN_ID_RSP_SIZE);
/* Prepare CT request */
@@ -472,7 +475,8 @@ qla2x00_rft_id(scsi_qla_host_t *ha)
/* Issue RFT_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RFT_ID_REQ_SIZE, RFT_ID_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RFT_ID_REQ_SIZE,
+ RFT_ID_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD,
@@ -527,7 +531,8 @@ qla2x00_rff_id(scsi_qla_host_t *ha)
/* Issue RFF_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RFF_ID_REQ_SIZE, RFF_ID_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RFF_ID_REQ_SIZE,
+ RFF_ID_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD,
@@ -581,7 +586,8 @@ qla2x00_rnn_id(scsi_qla_host_t *ha)
/* Issue RNN_ID */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RNN_ID_REQ_SIZE, RNN_ID_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RNN_ID_REQ_SIZE,
+ RNN_ID_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD,
@@ -644,7 +650,7 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
/* Issue RSNN_NN */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD,
@@ -1101,7 +1107,7 @@ qla2x00_mgmt_svr_login(scsi_qla_host_t *ha)
if (ha->flags.management_server_logged_in)
return ret;
- ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
+ ha->isp_ops->fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
mb, BIT_1);
if (mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
@@ -1186,6 +1192,7 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size,
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ ct_pkt->vp_index = ha->vp_idx;
return ct_pkt;
}
@@ -1196,7 +1203,7 @@ qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size)
ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
} else {
@@ -1251,7 +1258,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *ha)
/* Issue RHBA */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
- ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
@@ -1371,7 +1378,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *ha)
/* Firmware version */
eiter = (struct ct_fdmi_hba_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION);
- ha->isp_ops.fw_version_str(ha, eiter->a.fw_version);
+ ha->isp_ops->fw_version_str(ha, eiter->a.fw_version);
alen = strlen(eiter->a.fw_version);
alen += (alen & 3) ? (4 - (alen & 3)) : 4;
eiter->len = cpu_to_be16(4 + alen);
@@ -1437,7 +1444,7 @@ qla2x00_fdmi_dhba(scsi_qla_host_t *ha)
/* Issue RPA */
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
DHBA_RSP_SIZE);
/* Prepare CT request */
@@ -1495,7 +1502,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
/* Issue RPA */
/* Prepare common MS IOCB */
/* Request size adjusted after CT preparation */
- ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
+ ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
/* Prepare CT request */
ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
@@ -1525,12 +1532,20 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
eiter->len = __constant_cpu_to_be16(4 + 4);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
- eiter->a.sup_speed = __constant_cpu_to_be32(4);
+ if (IS_QLA25XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
+ FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB);
+ else if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
+ FDMI_PORT_SPEED_4GB);
else if (IS_QLA23XX(ha))
- eiter->a.sup_speed = __constant_cpu_to_be32(2);
+ eiter->a.sup_speed =__constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB);
else
- eiter->a.sup_speed = __constant_cpu_to_be32(1);
+ eiter->a.sup_speed = __constant_cpu_to_be32(
+ FDMI_PORT_SPEED_1GB);
size += 4 + 4;
DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no,
@@ -1541,14 +1556,25 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED);
eiter->len = __constant_cpu_to_be16(4 + 4);
switch (ha->link_data_rate) {
- case 0:
- eiter->a.cur_speed = __constant_cpu_to_be32(1);
+ case PORT_SPEED_1GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_1GB);
+ break;
+ case PORT_SPEED_2GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_2GB);
+ break;
+ case PORT_SPEED_4GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_4GB);
break;
- case 1:
- eiter->a.cur_speed = __constant_cpu_to_be32(2);
+ case PORT_SPEED_8GB:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_8GB);
break;
- case 3:
- eiter->a.cur_speed = __constant_cpu_to_be32(4);
+ default:
+ eiter->a.cur_speed =
+ __constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
break;
}
size += 4 + 4;
@@ -1560,7 +1586,7 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
eiter = (struct ct_fdmi_port_attr *) (entries + size);
eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
eiter->len = __constant_cpu_to_be16(4 + 4);
- max_frame_size = IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
+ max_frame_size = IS_FWI2_CAPABLE(ha) ?
(uint32_t) icb24->frame_payload_size:
(uint32_t) ha->init_cb->frame_payload_size;
eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
@@ -1676,7 +1702,7 @@ qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
@@ -1684,7 +1710,7 @@ qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
memset(list[i].fabric_port_name, 0, WWN_SIZE);
/* Prepare common MS IOCB */
- ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
+ ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
GFPN_ID_RSP_SIZE);
/* Prepare CT request */
@@ -1746,6 +1772,7 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size,
ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+ ct_pkt->vp_index = ha->vp_idx;
return ct_pkt;
}
@@ -1783,7 +1810,7 @@ qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
if (!ha->flags.gpsc_supported)
return QLA_FUNCTION_FAILED;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 2a45aec4ff29..5ec798c2bf13 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -79,20 +79,20 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
- rval = ha->isp_ops.pci_config(ha);
+ rval = ha->isp_ops->pci_config(ha);
if (rval) {
DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
ha->host_no));
return (rval);
}
- ha->isp_ops.reset_chip(ha);
+ ha->isp_ops->reset_chip(ha);
- ha->isp_ops.get_flash_version(ha, ha->request_ring);
+ ha->isp_ops->get_flash_version(ha, ha->request_ring);
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
- ha->isp_ops.nvram_config(ha);
+ ha->isp_ops->nvram_config(ha);
if (ha->flags.disable_serdes) {
/* Mask HBA via NVRAM settings? */
@@ -108,7 +108,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
- rval = ha->isp_ops.chip_diag(ha);
+ rval = ha->isp_ops->chip_diag(ha);
if (rval)
return (rval);
rval = qla2x00_setup_chip(ha);
@@ -129,14 +129,13 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
int
qla2100_pci_config(scsi_qla_host_t *ha)
{
- int ret;
uint16_t w;
uint32_t d;
unsigned long flags;
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- ret = pci_set_mwi(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -164,7 +163,6 @@ qla2100_pci_config(scsi_qla_host_t *ha)
int
qla2300_pci_config(scsi_qla_host_t *ha)
{
- int ret;
uint16_t w;
uint32_t d;
unsigned long flags = 0;
@@ -172,7 +170,7 @@ qla2300_pci_config(scsi_qla_host_t *ha)
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
pci_set_master(ha->pdev);
- ret = pci_set_mwi(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -250,15 +248,13 @@ qla2300_pci_config(scsi_qla_host_t *ha)
int
qla24xx_pci_config(scsi_qla_host_t *ha)
{
- int ret;
uint16_t w;
uint32_t d;
unsigned long flags = 0;
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
- int pcix_cmd_reg, pcie_dctl_reg;
pci_set_master(ha->pdev);
- ret = pci_set_mwi(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -268,35 +264,19 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
- pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
- if (pcix_cmd_reg) {
- uint16_t pcix_cmd;
-
- pcix_cmd_reg += PCI_X_CMD;
- pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
- pcix_cmd &= ~PCI_X_CMD_MAX_READ;
- pcix_cmd |= 0x0008;
- pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
- }
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
+ pcix_set_mmrbc(ha->pdev, 2048);
/* PCIe -- adjust Maximum Read Request Size (2048). */
- pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
- if (pcie_dctl_reg) {
- uint16_t pcie_dctl;
-
- pcie_dctl_reg += PCI_EXP_DEVCTL;
- pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
- pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
- pcie_dctl |= 0x4000;
- pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
- }
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
/* Reset expansion ROM address decode enable */
pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
d &= ~PCI_ROM_ADDRESS_ENABLE;
pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
- pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision);
+ ha->chip_revision = ha->pdev->revision;
/* Get PCI bus information. */
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -307,6 +287,40 @@ qla24xx_pci_config(scsi_qla_host_t *ha)
}
/**
+ * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla25xx_pci_config(scsi_qla_host_t *ha)
+{
+ uint16_t w;
+ uint32_t d;
+
+ pci_set_master(ha->pdev);
+ pci_try_set_mwi(ha->pdev);
+
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+ w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+ /* PCIe -- adjust Maximum Read Request Size (2048). */
+ if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+ pcie_set_readrq(ha->pdev, 2048);
+
+ /* Reset expansion ROM address decode enable */
+ pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
+ d &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+
+ ha->chip_revision = ha->pdev->revision;
+
+ return QLA_SUCCESS;
+}
+
+/**
* qla2x00_isp_firmware() - Choose firmware image.
* @ha: HA context
*
@@ -351,7 +365,7 @@ qla2x00_reset_chip(scsi_qla_host_t *ha)
uint32_t cnt;
uint16_t cmd;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -551,7 +565,7 @@ qla24xx_reset_risc(scsi_qla_host_t *ha)
void
qla24xx_reset_chip(scsi_qla_host_t *ha)
{
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
/* Perform RISC reset. */
qla24xx_reset_risc(ha);
@@ -736,8 +750,10 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
mem_size = (ha->fw_memory_size - 0x11000 + 1) *
sizeof(uint16_t);
- } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
- fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+ } else if (IS_FWI2_CAPABLE(ha)) {
+ fixed_size = IS_QLA25XX(ha) ?
+ offsetof(struct qla25xx_fw_dump, ext_mem):
+ offsetof(struct qla24xx_fw_dump, ext_mem);
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
sizeof(uint32_t);
@@ -879,7 +895,7 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
uint32_t srisc_address = 0;
/* Load firmware sequences */
- rval = ha->isp_ops.load_risc(ha, &srisc_address);
+ rval = ha->isp_ops->load_risc(ha, &srisc_address);
if (rval == QLA_SUCCESS) {
DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
"code.\n", ha->host_no));
@@ -899,6 +915,10 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
&ha->fw_subminor_version,
&ha->fw_attributes, &ha->fw_memory_size);
qla2x00_resize_request_q(ha);
+ ha->flags.npiv_supported = 0;
+ if (IS_QLA24XX(ha) &&
+ (ha->fw_attributes & BIT_2))
+ ha->flags.npiv_supported = 1;
if (ql2xallocfwdump)
qla2x00_alloc_fw_dump(ha);
@@ -1101,6 +1121,8 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
int rval;
unsigned long flags = 0;
int cnt;
+ struct mid_init_cb_24xx *mid_init_cb =
+ (struct mid_init_cb_24xx *) ha->init_cb;
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1124,14 +1146,18 @@ qla2x00_init_rings(scsi_qla_host_t *ha)
/* Initialize response queue entries */
qla2x00_init_response_q_entries(ha);
- ha->isp_ops.config_rings(ha);
+ ha->isp_ops->config_rings(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Update any ISP specific firmware options before initialization. */
- ha->isp_ops.update_fw_options(ha);
+ ha->isp_ops->update_fw_options(ha);
DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
+
+ mid_init_cb->count = MAX_NUM_VPORT_FABRIC;
+ ha->max_npiv_vports = MAX_NUM_VPORT_FABRIC;
+
rval = qla2x00_init_firmware(ha, ha->init_cb_size);
if (rval) {
DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
@@ -1263,6 +1289,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
int rval;
uint16_t loop_id;
uint16_t topo;
+ uint16_t sw_cap;
uint8_t al_pa;
uint8_t area;
uint8_t domain;
@@ -1270,7 +1297,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
/* Get host addresses. */
rval = qla2x00_get_adapter_id(ha,
- &loop_id, &al_pa, &area, &domain, &topo);
+ &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
if (rval != QLA_SUCCESS) {
if (LOOP_TRANSITION(ha) || atomic_read(&ha->loop_down_timer) ||
(rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
@@ -1295,6 +1322,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
/* initialize */
ha->min_external_loopid = SNS_FIRST_LOOP_ID;
ha->operating_mode = LOOP;
+ ha->switch_cap = 0;
switch (topo) {
case 0:
@@ -1307,6 +1335,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
case 1:
DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
ha->host_no));
+ ha->switch_cap = sw_cap;
ha->current_topology = ISP_CFG_FL;
strcpy(connect_type, "(FL_Port)");
break;
@@ -1322,6 +1351,7 @@ qla2x00_configure_hba(scsi_qla_host_t *ha)
case 3:
DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
ha->host_no));
+ ha->switch_cap = sw_cap;
ha->operating_mode = P2P;
ha->current_topology = ISP_CFG_F;
strcpy(connect_type, "(F_Port)");
@@ -1445,7 +1475,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
ha->nvram_base = 0x80;
/* Get NVRAM data and calculate checksum. */
- ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
+ ha->isp_ops->read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
chksum += *ptr++;
@@ -1743,7 +1773,6 @@ qla2x00_rport_del(void *data)
spin_unlock_irqrestore(&fcport->rport_lock, flags);
if (rport)
fc_remote_port_delete(rport);
-
}
/**
@@ -1765,6 +1794,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
/* Setup fcport template structure. */
memset(fcport, 0, sizeof (fc_port_t));
fcport->ha = ha;
+ fcport->vp_idx = ha->vp_idx;
fcport->port_type = FCT_UNKNOWN;
fcport->loop_id = FC_NO_LOOP_ID;
atomic_set(&fcport->state, FCS_UNCONFIGURED);
@@ -1911,6 +1941,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
char *id_iter;
uint16_t loop_id;
uint8_t domain, area, al_pa;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
found_devs = 0;
new_fcport = NULL;
@@ -1942,7 +1973,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
/*
* Mark local devices that were present with FCF_DEVICE_LOST for now.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (atomic_read(&fcport->state) == FCS_ONLINE &&
fcport->port_type != FCT_BROADCAST &&
(fcport->flags & FCF_FABRIC_DEVICE) == 0) {
@@ -1988,6 +2022,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
new_fcport->d_id.b.area = area;
new_fcport->d_id.b.al_pa = al_pa;
new_fcport->loop_id = loop_id;
+ new_fcport->vp_idx = ha->vp_idx;
rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
if (rval2 != QLA_SUCCESS) {
DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
@@ -2003,7 +2038,10 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
/* Check for matching device in port list. */
found = 0;
fcport = NULL;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
@@ -2023,7 +2061,13 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
if (!found) {
/* New device, add to fcports list. */
new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
- list_add_tail(&new_fcport->list, &ha->fcports);
+ if (ha->parent) {
+ new_fcport->ha = ha;
+ new_fcport->vp_idx = ha->vp_idx;
+ list_add_tail(&new_fcport->vp_fcport,
+ &ha->vp_fcports);
+ }
+ list_add_tail(&new_fcport->list, &pha->fcports);
/* Allocate a new replacement fcport. */
fcport = new_fcport;
@@ -2091,7 +2135,7 @@ qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
int rval;
uint16_t port_speed, mb[6];
- if (!IS_QLA24XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return;
switch (be16_to_cpu(fcport->fp_speed)) {
@@ -2199,11 +2243,13 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
void
qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
{
+ scsi_qla_host_t *pha = to_qla_parent(ha);
+
fcport->ha = ha;
fcport->login_retry = 0;
- fcport->port_login_retry_count = ha->port_down_retry_count *
+ fcport->port_login_retry_count = pha->port_down_retry_count *
PORT_RETRY_TIME;
- atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+ atomic_set(&fcport->port_down_timer, pha->port_down_retry_count *
PORT_RETRY_TIME);
fcport->flags &= ~FCF_LOGIN_NEEDED;
@@ -2234,9 +2280,10 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
uint16_t mb[MAILBOX_REGISTER_COUNT];
uint16_t loop_id;
LIST_HEAD(new_fcports);
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/* If FL port exists, then SNS is present */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
loop_id = NPH_F_PORT;
else
loop_id = SNS_FL_PORT;
@@ -2263,11 +2310,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
qla2x00_fdmi_register(ha);
/* Ensure we are logged into the SNS. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
loop_id = NPH_SNS;
else
loop_id = SIMPLE_NAME_SERVER;
- ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff,
+ ha->isp_ops->fabric_login(ha, loop_id, 0xff, 0xff,
0xfc, mb, BIT_1 | BIT_0);
if (mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2(qla_printk(KERN_INFO, ha,
@@ -2307,7 +2354,10 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
* Logout all previous fabric devices marked lost, except
* tape devices.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx !=ha->vp_idx)
+ continue;
+
if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
@@ -2321,7 +2371,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
(fcport->flags & FCF_TAPE_PRESENT) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
- ha->isp_ops.fabric_logout(ha,
+ ha->isp_ops->fabric_logout(ha,
fcport->loop_id,
fcport->d_id.b.domain,
fcport->d_id.b.area,
@@ -2332,13 +2382,16 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
}
/* Starting free loop ID. */
- next_loopid = ha->min_external_loopid;
+ next_loopid = pha->min_external_loopid;
/*
* Scan through our port list and login entries that need to be
* logged in.
*/
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if (atomic_read(&ha->loop_down_timer) ||
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
break;
@@ -2380,11 +2433,18 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
break;
}
- /* Remove device from the new list and add it to DB */
- list_move_tail(&fcport->list, &ha->fcports);
-
/* Login and update database */
qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
+
+ if (ha->parent) {
+ fcport->ha = ha;
+ fcport->vp_idx = ha->vp_idx;
+ list_add_tail(&fcport->vp_fcport,
+ &ha->vp_fcports);
+ list_move_tail(&fcport->list,
+ &ha->parent->fcports);
+ } else
+ list_move_tail(&fcport->list, &ha->fcports);
}
} while (0);
@@ -2428,6 +2488,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
int swl_idx;
int first_dev, last_dev;
port_id_t wrap, nxt_d_id;
+ int vp_index;
+ int empty_vp_index;
+ int found_vp;
+ scsi_qla_host_t *vha;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_SUCCESS;
@@ -2461,13 +2526,13 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
return (QLA_MEMORY_ALLOC_FAILED);
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
-
+ new_fcport->vp_idx = ha->vp_idx;
/* Set start port ID scan at adapter ID. */
first_dev = 1;
last_dev = 0;
/* Starting free loop ID. */
- loop_id = ha->min_external_loopid;
+ loop_id = pha->min_external_loopid;
for (; loop_id <= ha->last_loop_id; loop_id++) {
if (qla2x00_is_reserved_id(ha, loop_id))
continue;
@@ -2521,10 +2586,42 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
break;
}
- /* Bypass if host adapter. */
- if (new_fcport->d_id.b24 == ha->d_id.b24)
+ /* Bypass if same physical adapter. */
+ if (new_fcport->d_id.b24 == pha->d_id.b24)
continue;
+ /* Bypass virtual ports of the same host. */
+ if (pha->num_vhosts) {
+ vp_index = find_next_bit(
+ (unsigned long *)pha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, 1);
+
+ for (;vp_index <= MAX_MULTI_ID_FABRIC;
+ vp_index = find_next_bit(
+ (unsigned long *)pha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, vp_index + 1)) {
+ empty_vp_index = 1;
+ found_vp = 0;
+ list_for_each_entry(vha, &pha->vp_list,
+ vp_list) {
+ if (vp_index == vha->vp_idx) {
+ empty_vp_index = 0;
+ found_vp = 1;
+ break;
+ }
+ }
+
+ if (empty_vp_index)
+ continue;
+
+ if (found_vp &&
+ new_fcport->d_id.b24 == vha->d_id.b24)
+ break;
+ }
+ if (vp_index <= MAX_MULTI_ID_FABRIC)
+ continue;
+ }
+
/* Bypass if same domain and area of adapter. */
if (((new_fcport->d_id.b24 & 0xffff00) ==
(ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
@@ -2537,7 +2634,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
/* Locate matching device in database. */
found = 0;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (new_fcport->vp_idx != fcport->vp_idx)
+ continue;
if (memcmp(new_fcport->port_name, fcport->port_name,
WWN_SIZE))
continue;
@@ -2581,7 +2680,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
(fcport->flags & FCF_TAPE_PRESENT) == 0 &&
fcport->port_type != FCT_INITIATOR &&
fcport->port_type != FCT_BROADCAST) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
fcport->loop_id = FC_NO_LOOP_ID;
@@ -2605,6 +2704,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
}
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
new_fcport->d_id.b24 = nxt_d_id.b24;
+ new_fcport->vp_idx = ha->vp_idx;
}
kfree(swl);
@@ -2637,6 +2737,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
int found;
fc_port_t *fcport;
uint16_t first_loop_id;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_SUCCESS;
@@ -2663,7 +2764,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
/* Check for loop ID being already in use. */
found = 0;
fcport = NULL;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
if (fcport->loop_id == dev->loop_id && fcport != dev) {
/* ID possibly in use */
found++;
@@ -2710,6 +2811,7 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
uint8_t rscn_out_iter;
uint8_t format;
port_id_t d_id;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = QLA_RSCNS_HANDLED;
@@ -2776,7 +2878,10 @@ qla2x00_device_resync(scsi_qla_host_t *ha)
rval = QLA_SUCCESS;
- list_for_each_entry(fcport, &ha->fcports, list) {
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != ha->vp_idx)
+ continue;
+
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
(fcport->d_id.b24 & mask) != d_id.b24 ||
fcport->port_type == FCT_BROADCAST)
@@ -2830,7 +2935,7 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
opts |= BIT_1;
rval = qla2x00_get_port_database(ha, fcport, opts);
if (rval != QLA_SUCCESS) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -2875,7 +2980,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
fcport->d_id.b.area, fcport->d_id.b.al_pa));
/* Login fcport on switch. */
- ha->isp_ops.fabric_login(ha, fcport->loop_id,
+ ha->isp_ops->fabric_login(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb, BIT_0);
if (mb[0] == MBS_PORT_ID_USED) {
@@ -2943,7 +3048,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
* dead.
*/
*next_loopid = fcport->loop_id;
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -2961,7 +3066,7 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
*next_loopid = fcport->loop_id;
- ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa);
fcport->loop_id = FC_NO_LOOP_ID;
@@ -3117,7 +3222,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
qla_printk(KERN_INFO, ha,
"Performing ISP error recovery - ha= %p.\n", ha);
- ha->isp_ops.reset_chip(ha);
+ ha->isp_ops->reset_chip(ha);
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
@@ -3143,9 +3248,9 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- ha->isp_ops.get_flash_version(ha, ha->request_ring);
+ ha->isp_ops->get_flash_version(ha, ha->request_ring);
- ha->isp_ops.nvram_config(ha);
+ ha->isp_ops->nvram_config(ha);
if (!qla2x00_restart_isp(ha)) {
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3160,7 +3265,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->flags.online = 1;
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
@@ -3185,7 +3290,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
* The next call disables the board
* completely.
*/
- ha->isp_ops.reset_adapter(ha);
+ ha->isp_ops->reset_adapter(ha);
ha->flags.online = 0;
clear_bit(ISP_ABORT_RETRY,
&ha->dpc_flags);
@@ -3242,7 +3347,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(ha)) {
ha->flags.online = 0;
- if (!(status = ha->isp_ops.chip_diag(ha))) {
+ if (!(status = ha->isp_ops->chip_diag(ha))) {
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
status = qla2x00_setup_chip(ha);
goto done;
@@ -3334,7 +3439,7 @@ qla2x00_reset_adapter(scsi_qla_host_t *ha)
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
ha->flags.online = 0;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -3351,7 +3456,7 @@ qla24xx_reset_adapter(scsi_qla_host_t *ha)
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
ha->flags.online = 0;
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
@@ -3409,7 +3514,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
/* Get NVRAM data and calculate checksum. */
dptr = (uint32_t *)nv;
- ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
+ ha->isp_ops->read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
ha->nvram_size);
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
chksum += le32_to_cpu(*dptr++);
@@ -3923,7 +4028,7 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
{
int ret, retries;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return;
if (!ha->fw_major_version)
return;
@@ -3940,3 +4045,40 @@ qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
ret = qla2x00_stop_firmware(ha);
}
}
+
+int
+qla24xx_configure_vhba(scsi_qla_host_t *ha)
+{
+ int rval = QLA_SUCCESS;
+ uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+ if (!ha->parent)
+ return -EINVAL;
+
+ rval = qla2x00_fw_ready(ha);
+ if (rval == QLA_SUCCESS) {
+ clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+ qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
+ }
+
+ ha->flags.management_server_logged_in = 0;
+
+ /* Login to SNS first */
+ qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc,
+ mb, BIT_1);
+ if (mb[0] != MBS_COMMAND_COMPLETE) {
+ DEBUG15(qla_printk(KERN_INFO, ha,
+ "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
+ "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
+ mb[0], mb[1], mb[2], mb[6], mb[7]));
+ return (QLA_FUNCTION_FAILED);
+ }
+
+ atomic_set(&ha->loop_down_timer, 0);
+ atomic_set(&ha->loop_state, LOOP_UP);
+ set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+ set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+ rval = qla2x00_loop_resync(ha);
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index d3023338628f..8e3b04464cff 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -104,7 +104,7 @@ static __inline__ void qla2x00_poll(scsi_qla_host_t *);
static inline void
qla2x00_poll(scsi_qla_host_t *ha)
{
- ha->isp_ops.intr_handler(0, ha);
+ ha->isp_ops->intr_handler(0, ha);
}
static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
@@ -163,7 +163,7 @@ static inline int qla2x00_is_reserved_id(scsi_qla_host_t *, uint16_t);
static inline int
qla2x00_is_reserved_id(scsi_qla_host_t *ha, uint16_t loop_id)
{
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
return (loop_id > NPH_LAST_HANDLE);
return ((loop_id > ha->last_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c5b3c610a32a..3a5e78cb6b3f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -155,6 +155,8 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = sp->cmd;
@@ -163,7 +165,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
__constant_cpu_to_le32(COMMAND_TYPE);
/* No data transfer */
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
@@ -177,35 +179,23 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
- if (cmd->use_sg != 0) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
-
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- cont_entry_t *cont_pkt;
-
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- /*
- * Seven DSDs are available in the Continuation
- * Type 0 IOCB.
- */
- cont_pkt = qla2x00_prep_cont_type0_iocb(ha);
- cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
- avail_dsds = 7;
- }
-
- *cur_dsd++ = cpu_to_le32(sg_dma_address(cur_seg));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_seg++;
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ cont_entry_t *cont_pkt;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Seven DSDs are available in the Continuation
+ * Type 0 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type0_iocb(ha);
+ cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
+ avail_dsds = 7;
}
- } else {
- *cur_dsd++ = cpu_to_le32(sp->dma_handle);
- *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+
+ *cur_dsd++ = cpu_to_le32(sg_dma_address(sg));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
}
}
@@ -224,6 +214,8 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = sp->cmd;
@@ -232,7 +224,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
__constant_cpu_to_le32(COMMAND_A64_TYPE);
/* No data transfer */
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
@@ -246,39 +238,26 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
- if (cmd->use_sg != 0) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
-
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- dma_addr_t sle_dma;
- cont_a64_entry_t *cont_pkt;
-
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- /*
- * Five DSDs are available in the Continuation
- * Type 1 IOCB.
- */
- cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
- cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
- avail_dsds = 5;
- }
-
- sle_dma = sg_dma_address(cur_seg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_seg++;
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
+ cont_a64_entry_t *cont_pkt;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Continuation
+ * Type 1 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
+ cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
+ avail_dsds = 5;
}
- } else {
- *cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
}
}
@@ -291,7 +270,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
int
qla2x00_start_scsi(srb_t *sp)
{
- int ret;
+ int ret, nseg;
unsigned long flags;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
@@ -299,7 +278,6 @@ qla2x00_start_scsi(srb_t *sp)
uint32_t index;
uint32_t handle;
cmd_entry_t *cmd_pkt;
- struct scatterlist *sg;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
@@ -337,26 +315,18 @@ qla2x00_start_scsi(srb_t *sp)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
- if (cmd->use_sg) {
- sg = (struct scatterlist *) cmd->request_buffer;
- tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- if (tot_dsds == 0)
- goto queuing_error;
- } else if (cmd->request_bufflen) {
- dma_addr_t req_dma;
-
- req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
- cmd->request_bufflen, cmd->sc_data_direction);
- if (dma_mapping_error(req_dma))
+ if (scsi_sg_count(cmd)) {
+ nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), cmd->sc_data_direction);
+ if (unlikely(!nseg))
goto queuing_error;
+ } else
+ nseg = 0;
- sp->dma_handle = req_dma;
- tot_dsds = 1;
- }
+ tot_dsds = nseg;
/* Calculate the number of request entries needed. */
- req_cnt = ha->isp_ops.calc_req_entries(tot_dsds);
+ req_cnt = ha->isp_ops->calc_req_entries(tot_dsds);
if (ha->req_q_cnt < (req_cnt + 2)) {
cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
if (ha->req_ring_index < cnt)
@@ -391,10 +361,10 @@ qla2x00_start_scsi(srb_t *sp)
/* Load SCSI command packet. */
memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
- cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
+ cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Build IOCB segments */
- ha->isp_ops.build_iocbs(sp, cmd_pkt, tot_dsds);
+ ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds);
/* Set total data segment count. */
cmd_pkt->entry_count = (uint8_t)req_cnt;
@@ -423,14 +393,9 @@ qla2x00_start_scsi(srb_t *sp)
return (QLA_SUCCESS);
queuing_error:
- if (cmd->use_sg && tot_dsds) {
- sg = (struct scatterlist *) cmd->request_buffer;
- pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (tot_dsds) {
- pci_unmap_single(ha->pdev, sp->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return (QLA_FUNCTION_FAILED);
@@ -453,9 +418,10 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
{
mrk_entry_t *mrk;
struct mrk_entry_24xx *mrk24;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
mrk24 = NULL;
- mrk = (mrk_entry_t *)qla2x00_req_pkt(ha);
+ mrk = (mrk_entry_t *)qla2x00_req_pkt(pha);
if (mrk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Marker IOCB.\n",
__func__, ha->host_no));
@@ -466,12 +432,13 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
mrk->entry_type = MARKER_TYPE;
mrk->modifier = type;
if (type != MK_SYNC_ALL) {
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mrk24 = (struct mrk_entry_24xx *) mrk;
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
mrk24->lun[2] = MSB(lun);
host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
+ mrk24->vp_index = ha->vp_idx;
} else {
SET_TARGET_ID(ha, mrk->target, loop_id);
mrk->lun = cpu_to_le16(lun);
@@ -479,7 +446,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
}
wmb();
- qla2x00_isp_cmd(ha);
+ qla2x00_isp_cmd(pha);
return (QLA_SUCCESS);
}
@@ -520,7 +487,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha)
for (timer = HZ; timer; timer--) {
if ((req_cnt + 2) >= ha->req_q_cnt) {
/* Calculate number of free request entries. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
cnt = (uint16_t)RD_REG_DWORD(
&reg->isp24.req_q_out);
else
@@ -594,7 +561,7 @@ qla2x00_isp_cmd(scsi_qla_host_t *ha)
ha->request_ring_ptr++;
/* Set chip new ring index. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, ha->req_ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
} else {
@@ -642,6 +609,8 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
uint32_t *cur_dsd;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = sp->cmd;
@@ -650,7 +619,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
__constant_cpu_to_le32(COMMAND_TYPE_7);
/* No data transfer */
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
cmd_pkt->byte_count = __constant_cpu_to_le32(0);
return;
}
@@ -670,39 +639,27 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
/* Load data segments */
- if (cmd->use_sg != 0) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
-
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- dma_addr_t sle_dma;
- cont_a64_entry_t *cont_pkt;
-
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- /*
- * Five DSDs are available in the Continuation
- * Type 1 IOCB.
- */
- cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
- cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
- avail_dsds = 5;
- }
-
- sle_dma = sg_dma_address(cur_seg);
- *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
- *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_seg++;
+
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
+ cont_a64_entry_t *cont_pkt;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ /*
+ * Five DSDs are available in the Continuation
+ * Type 1 IOCB.
+ */
+ cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
+ cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
+ avail_dsds = 5;
}
- } else {
- *cur_dsd++ = cpu_to_le32(LSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(MSD(sp->dma_handle));
- *cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+
+ sle_dma = sg_dma_address(sg);
+ *cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+ *cur_dsd++ = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
}
}
@@ -716,7 +673,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt,
int
qla24xx_start_scsi(srb_t *sp)
{
- int ret;
+ int ret, nseg;
unsigned long flags;
scsi_qla_host_t *ha;
struct scsi_cmnd *cmd;
@@ -724,7 +681,6 @@ qla24xx_start_scsi(srb_t *sp)
uint32_t index;
uint32_t handle;
struct cmd_type_7 *cmd_pkt;
- struct scatterlist *sg;
uint16_t cnt;
uint16_t req_cnt;
uint16_t tot_dsds;
@@ -762,23 +718,15 @@ qla24xx_start_scsi(srb_t *sp)
goto queuing_error;
/* Map the sg table so we have an accurate count of sg entries needed */
- if (cmd->use_sg) {
- sg = (struct scatterlist *) cmd->request_buffer;
- tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- if (tot_dsds == 0)
- goto queuing_error;
- } else if (cmd->request_bufflen) {
- dma_addr_t req_dma;
-
- req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
- cmd->request_bufflen, cmd->sc_data_direction);
- if (dma_mapping_error(req_dma))
+ if (scsi_sg_count(cmd)) {
+ nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd),
+ scsi_sg_count(cmd), cmd->sc_data_direction);
+ if (unlikely(!nseg))
goto queuing_error;
+ } else
+ nseg = 0;
- sp->dma_handle = req_dma;
- tot_dsds = 1;
- }
+ tot_dsds = nseg;
req_cnt = qla24xx_calc_iocbs(tot_dsds);
if (ha->req_q_cnt < (req_cnt + 2)) {
@@ -813,6 +761,7 @@ qla24xx_start_scsi(srb_t *sp)
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
+ cmd_pkt->vp_index = sp->fcport->vp_idx;
int_to_scsilun(sp->cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
@@ -821,7 +770,7 @@ qla24xx_start_scsi(srb_t *sp)
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb));
- cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
+ cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
/* Build IOCB segments */
qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds);
@@ -853,14 +802,9 @@ qla24xx_start_scsi(srb_t *sp)
return QLA_SUCCESS;
queuing_error:
- if (cmd->use_sg && tot_dsds) {
- sg = (struct scatterlist *) cmd->request_buffer;
- pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (tot_dsds) {
- pci_unmap_single(ha->pdev, sp->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_FUNCTION_FAILED;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index ca463469063d..b8f226ae2633 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -9,7 +9,6 @@
#include <scsi/scsi_tcq.h>
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
-static void qla2x00_async_event(scsi_qla_host_t *, uint16_t *);
static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, void *);
static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
@@ -144,7 +143,7 @@ qla2300_intr_handler(int irq, void *dev_id)
WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
RD_REG_WORD(&reg->hccr);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSR_RISC_INT) == 0)
@@ -244,11 +243,11 @@ qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
* @ha: SCSI driver HA context
* @mb: Mailbox registers (0 - 3)
*/
-static void
+void
qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
{
#define LS_UNKNOWN 2
- static char *link_speeds[5] = { "1", "2", "?", "4", "10" };
+ static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
char *link_speed;
uint16_t handle_cnt;
uint16_t cnt;
@@ -335,9 +334,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
"ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
mb[1], mb[2], mb[3]);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
if (mb[1] == 0 && mb[2] == 0) {
qla_printk(KERN_ERR, ha,
"Unrecoverable Hardware Error: adapter "
@@ -386,6 +385,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
ha->flags.management_server_logged_in = 0;
@@ -422,6 +426,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
ha->flags.management_server_logged_in = 0;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
if (ql2xfdmienable)
@@ -440,6 +449,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
ha->operating_mode = LOOP;
@@ -465,6 +479,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
}
@@ -491,6 +510,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
qla2x00_mark_all_devices_lost(ha, 1);
}
+ if (ha->parent) {
+ atomic_set(&ha->vp_state, VP_FAILED);
+ fc_vport_set_state(ha->fc_vport, FC_VPORT_FAILED);
+ }
+
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
break;
@@ -530,6 +554,10 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
+ /* Check if the Vport has issued a SCR */
+ if (ha->parent && test_bit(VP_SCR_NEEDED, &ha->vp_flags))
+ break;
+
DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
ha->host_no));
DEBUG(printk(KERN_INFO
@@ -573,7 +601,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
"scsi(%ld): [R|Z]IO update completion.\n",
ha->host_no));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
qla24xx_process_response_queue(ha);
else
qla2x00_process_response_queue(ha);
@@ -589,6 +617,9 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->host_no, mb[1], mb[2]));
break;
}
+
+ if (!ha->parent && ha->num_vhosts)
+ qla2x00_alert_all_vps(ha, mb);
}
static void
@@ -792,7 +823,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
sts = (sts_entry_t *) pkt;
sts24 = (struct sts_entry_24xx *) pkt;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
comp_status = le16_to_cpu(sts24->comp_status);
scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
} else {
@@ -841,7 +872,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
fcport = sp->fcport;
sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
sense_len = le32_to_cpu(sts24->sense_len);
rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
resid_len = le32_to_cpu(sts24->rsp_residual_count);
@@ -860,7 +891,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
/* Check for any FCP transport errors. */
if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
/* Sense data lies beyond any FCP RESPONSE data. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
sense_data += rsp_info_len;
if (rsp_info_len > 3 && rsp_info[3]) {
DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
@@ -889,19 +920,19 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
}
if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
resid = resid_len;
- cp->resid = resid;
+ scsi_set_resid(cp, resid);
CMD_RESID_LEN(cp) = resid;
if (!lscsi_status &&
- ((unsigned)(cp->request_bufflen - resid) <
+ ((unsigned)(scsi_bufflen(cp) - resid) <
cp->underflow)) {
qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d:%d): Mid-layer underflow "
- "detected (%x of %x bytes)...returning "
- "error status.\n", ha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- cp->request_bufflen);
+ "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+ "detected (%x of %x bytes)...returning "
+ "error status.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ scsi_bufflen(cp));
cp->result = DID_ERROR << 16;
break;
@@ -959,11 +990,11 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
case CS_DATA_UNDERRUN:
resid = resid_len;
/* Use F/W calculated residual length. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
resid = fw_resid_len;
if (scsi_status & SS_RESIDUAL_UNDER) {
- cp->resid = resid;
+ scsi_set_resid(cp, resid);
CMD_RESID_LEN(cp) = resid;
} else {
DEBUG2(printk(KERN_INFO
@@ -1031,6 +1062,25 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
cp->device->id, cp->device->lun, cp,
cp->serial_number));
+ /*
+ * In case of a Underrun condition, set both the lscsi
+ * status and the completion status to appropriate
+ * values.
+ */
+ if (resid &&
+ ((unsigned)(cp->request_bufflen - resid) <
+ cp->underflow)) {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+ "detected (%x of %x bytes)...returning "
+ "error status.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ cp->request_bufflen));
+
+ cp->result = DID_ERROR << 16 | lscsi_status;
+ }
+
if (sense_len)
DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
CMD_ACTUAL_SNSLEN(cp)));
@@ -1042,26 +1092,26 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
*/
if (!(scsi_status & SS_RESIDUAL_UNDER)) {
DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
- "frame(s) detected (%x of %x bytes)..."
- "retrying command.\n", ha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- cp->request_bufflen));
+ "frame(s) detected (%x of %x bytes)..."
+ "retrying command.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ scsi_bufflen(cp)));
cp->result = DID_BUS_BUSY << 16;
break;
}
/* Handle mid-layer underflow */
- if ((unsigned)(cp->request_bufflen - resid) <
+ if ((unsigned)(scsi_bufflen(cp) - resid) <
cp->underflow) {
qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d:%d): Mid-layer underflow "
- "detected (%x of %x bytes)...returning "
- "error status.\n", ha->host_no,
- cp->device->channel, cp->device->id,
- cp->device->lun, resid,
- cp->request_bufflen);
+ "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+ "detected (%x of %x bytes)...returning "
+ "error status.\n", ha->host_no,
+ cp->device->channel, cp->device->id,
+ cp->device->lun, resid,
+ scsi_bufflen(cp));
cp->result = DID_ERROR << 16;
break;
@@ -1084,7 +1134,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
DEBUG2(printk(KERN_INFO
"PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR "
"status!\n",
- cp->serial_number, cp->request_bufflen, resid_len));
+ cp->serial_number, scsi_bufflen(cp), resid_len));
cp->result = DID_ERROR << 16;
break;
@@ -1135,7 +1185,7 @@ qla2x00_status_entry(scsi_qla_host_t *ha, void *pkt)
case CS_TIMEOUT:
cp->result = DID_BUS_BUSY << 16;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
DEBUG2(printk(KERN_INFO
"scsi(%ld:%d:%d:%d): TIMEOUT status detected "
"0x%x-0x%x\n", ha->host_no, cp->device->channel,
@@ -1204,7 +1254,7 @@ qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt)
}
/* Move sense data. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
host_to_fcp_swap(pkt->data, sizeof(pkt->data));
memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
@@ -1393,6 +1443,10 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
case MS_IOCB_TYPE:
qla24xx_ms_entry(ha, (struct ct_entry_24xx *)pkt);
break;
+ case VP_RPT_ID_IOCB_TYPE:
+ qla24xx_report_id_acquisition(ha,
+ (struct vp_rpt_id_entry_24xx *)pkt);
+ break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@@ -1448,7 +1502,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSRX_RISC_INT) == 0)
@@ -1582,7 +1636,7 @@ qla24xx_msix_default(int irq, void *dev_id)
qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
"Dumping firmware!\n", hccr);
- ha->isp_ops.fw_dump(ha, 1);
+ ha->isp_ops->fw_dump(ha, 1);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
break;
} else if ((stat & HSRX_RISC_INT) == 0)
@@ -1633,7 +1687,7 @@ struct qla_init_msix_entry {
uint16_t entry;
uint16_t index;
const char *name;
- irqreturn_t (*handler)(int, void *);
+ irq_handler_t handler;
};
static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = {
@@ -1704,11 +1758,11 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
int ret;
/* If possible, enable MSI-X. */
- if (!IS_QLA2432(ha))
+ if (!IS_QLA2432(ha) && !IS_QLA2532(ha))
goto skip_msix;
- if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
- !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) {
+ if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
+ !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
ha->chip_revision, ha->fw_attributes));
@@ -1727,7 +1781,7 @@ qla2x00_request_irqs(scsi_qla_host_t *ha)
"MSI-X: Falling back-to INTa mode -- %d.\n", ret);
skip_msix:
- if (!IS_QLA24XX(ha))
+ if (!IS_QLA24XX(ha) && !IS_QLA2532(ha))
goto skip_msi;
ret = pci_enable_msi(ha->pdev);
@@ -1737,7 +1791,7 @@ skip_msix:
}
skip_msi:
- ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
+ ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
if (!ret) {
ha->flags.inta_enabled = 1;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 71e32a248528..d3746ec80a85 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -42,25 +42,29 @@ qla2x00_mbx_sem_timeout(unsigned long data)
* Kernel context.
*/
static int
-qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
+qla2x00_mailbox_command(scsi_qla_host_t *pvha, mbx_cmd_t *mcp)
{
int rval;
unsigned long flags = 0;
- device_reg_t __iomem *reg = ha->iobase;
+ device_reg_t __iomem *reg;
struct timer_list tmp_intr_timer;
uint8_t abort_active;
- uint8_t io_lock_on = ha->flags.init_done;
+ uint8_t io_lock_on;
uint16_t command;
uint16_t *iptr;
uint16_t __iomem *optr;
uint32_t cnt;
uint32_t mboxes;
unsigned long wait_time;
+ scsi_qla_host_t *ha = to_qla_parent(pvha);
+
+ reg = ha->iobase;
+ io_lock_on = ha->flags.init_done;
rval = QLA_SUCCESS;
abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, pvha->host_no));
/*
* Wait for active mailbox commands to finish by waiting at most tov
@@ -86,7 +90,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
spin_lock_irqsave(&ha->hardware_lock, flags);
/* Load mailbox registers. */
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
optr = (uint16_t __iomem *)&reg->isp24.mailbox0;
else
optr = (uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 0);
@@ -150,7 +154,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
else
WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -171,7 +175,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
ha->host_no, command));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
else
WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -224,7 +228,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
uint16_t mb0;
uint32_t ictrl;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mb0 = RD_REG_WORD(&reg->isp24.mailbox0);
ictrl = RD_REG_DWORD(&reg->isp24.ictrl);
} else {
@@ -318,7 +322,7 @@ qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr,
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
- if (MSW(risc_addr) || IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (MSW(risc_addr) || IS_FWI2_CAPABLE(ha)) {
mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
mcp->mb[8] = MSW(risc_addr);
mcp->out_mb = MBX_8|MBX_0;
@@ -332,7 +336,7 @@ qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t risc_addr,
mcp->mb[6] = MSW(MSD(req_dma));
mcp->mb[7] = LSW(MSD(req_dma));
mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[4] = MSW(risc_code_size);
mcp->mb[5] = LSW(risc_code_size);
mcp->out_mb |= MBX_5|MBX_4;
@@ -383,7 +387,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->mb[3] = 0;
@@ -406,7 +410,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
ha->host_no, rval, mcp->mb[0]));
} else {
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
DEBUG11(printk("%s(%ld): done exchanges=%x.\n",
__func__, ha->host_no, mcp->mb[1]));
} else {
@@ -547,7 +551,7 @@ qla2x00_set_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts)
mcp->mb[3] = fwopts[3];
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->in_mb |= MBX_1;
} else {
mcp->mb[10] = fwopts[10];
@@ -660,7 +664,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
mcp->mb[0] = MBC_VERIFY_CHECKSUM;
mcp->out_mb = MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = MSW(risc_addr);
mcp->mb[2] = LSW(risc_addr);
mcp->out_mb |= MBX_2|MBX_1;
@@ -677,8 +681,8 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__,
- ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
- (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1])));
+ ha->host_no, rval, IS_FWI2_CAPABLE(ha) ?
+ (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));
} else {
DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
@@ -735,7 +739,7 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr,
/* Mask reserved bits. */
sts_entry->entry_status &=
- IS_QLA24XX(ha) || IS_QLA54XX(ha) ? RF_MASK_24XX :RF_MASK;
+ IS_FWI2_CAPABLE(ha) ? RF_MASK_24XX :RF_MASK;
}
return rval;
@@ -889,7 +893,7 @@ qla2x00_abort_target(fc_port_t *fcport)
*/
int
qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
- uint8_t *area, uint8_t *domain, uint16_t *top)
+ uint8_t *area, uint8_t *domain, uint16_t *top, uint16_t *sw_cap)
{
int rval;
mbx_cmd_t mc;
@@ -899,8 +903,9 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
ha->host_no));
mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
+ mcp->mb[9] = ha->vp_idx;
mcp->out_mb = MBX_0;
- mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
mcp->tov = 30;
mcp->flags = 0;
rval = qla2x00_mailbox_command(ha, mcp);
@@ -913,6 +918,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
*area = MSB(mcp->mb[2]);
*domain = LSB(mcp->mb[3]);
*top = mcp->mb[6];
+ *sw_cap = mcp->mb[7];
if (rval != QLA_SUCCESS) {
/*EMPTY*/
@@ -1009,7 +1015,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
ha->host_no));
- mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+ if (ha->flags.npiv_supported)
+ mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE;
+ else
+ mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+
mcp->mb[2] = MSW(ha->init_cb_dma);
mcp->mb[3] = LSW(ha->init_cb_dma);
mcp->mb[4] = 0;
@@ -1075,15 +1085,16 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE));
mcp->mb[0] = MBC_GET_PORT_DATABASE;
- if (opt != 0 && !IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (opt != 0 && !IS_FWI2_CAPABLE(ha))
mcp->mb[0] = MBC_ENHANCED_GET_PORT_DATABASE;
mcp->mb[2] = MSW(pd_dma);
mcp->mb[3] = LSW(pd_dma);
mcp->mb[6] = MSW(MSD(pd_dma));
mcp->mb[7] = LSW(MSD(pd_dma));
- mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ mcp->mb[9] = ha->vp_idx;
+ mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = fcport->loop_id;
mcp->mb[10] = opt;
mcp->out_mb |= MBX_10|MBX_1;
@@ -1096,15 +1107,15 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
mcp->mb[1] = fcport->loop_id << 8 | opt;
mcp->out_mb |= MBX_1;
}
- mcp->buf_size = (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
- PORT_DATABASE_24XX_SIZE : PORT_DATABASE_SIZE);
+ mcp->buf_size = IS_FWI2_CAPABLE(ha) ?
+ PORT_DATABASE_24XX_SIZE : PORT_DATABASE_SIZE;
mcp->flags = MBX_DMA_IN;
mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
rval = qla2x00_mailbox_command(ha, mcp);
if (rval != QLA_SUCCESS)
goto gpd_error_out;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
pd24 = (struct port_database_24xx *) pd;
/* Check for logged in state. */
@@ -1259,7 +1270,8 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
ha->host_no));
mcp->mb[0] = MBC_GET_PORT_NAME;
- mcp->out_mb = MBX_1|MBX_0;
+ mcp->mb[9] = ha->vp_idx;
+ mcp->out_mb = MBX_9|MBX_1|MBX_0;
if (HAS_EXTENDED_IDS(ha)) {
mcp->mb[1] = loop_id;
mcp->mb[10] = opt;
@@ -1321,7 +1333,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha)
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
mcp->mb[1] = BIT_6;
mcp->mb[2] = 0;
@@ -1447,6 +1459,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);
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
@@ -1624,7 +1637,7 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+ if (IS_FWI2_CAPABLE(ha))
return qla24xx_login_fabric(ha, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb_ret, opt);
@@ -1701,6 +1714,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);
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
@@ -1807,7 +1821,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha)
ha->host_no));
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
- mcp->mb[1] = IS_QLA24XX(ha) || IS_QLA54XX(ha) ? BIT_3: 0;
+ mcp->mb[1] = IS_FWI2_CAPABLE(ha) ? BIT_3: 0;
mcp->mb[2] = 0;
mcp->mb[3] = 0;
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -1857,13 +1871,14 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
mcp->mb[0] = MBC_GET_ID_LIST;
mcp->out_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[2] = MSW(id_list_dma);
mcp->mb[3] = LSW(id_list_dma);
mcp->mb[6] = MSW(MSD(id_list_dma));
mcp->mb[7] = LSW(MSD(id_list_dma));
mcp->mb[8] = 0;
- mcp->out_mb |= MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
+ mcp->mb[9] = ha->vp_idx;
+ mcp->out_mb |= MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2;
} else {
mcp->mb[1] = MSW(id_list_dma);
mcp->mb[2] = LSW(id_list_dma);
@@ -2048,7 +2063,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
mcp->mb[7] = LSW(MSD(stat_buf_dma));
mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
mcp->in_mb = MBX_0;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
mcp->mb[1] = loop_id;
mcp->mb[4] = 0;
mcp->mb[10] = 0;
@@ -2212,6 +2227,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
abt->port_id[0] = fcport->d_id.b.al_pa;
abt->port_id[1] = fcport->d_id.b.area;
abt->port_id[2] = fcport->d_id.b.domain;
+ abt->vp_index = fcport->vp_idx;
rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n",
@@ -2249,7 +2265,7 @@ qla24xx_abort_target(fc_port_t *fcport)
int rval;
struct tsk_mgmt_cmd *tsk;
dma_addr_t tsk_dma;
- scsi_qla_host_t *ha;
+ scsi_qla_host_t *ha, *pha;
if (fcport == NULL)
return 0;
@@ -2257,7 +2273,8 @@ qla24xx_abort_target(fc_port_t *fcport)
DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no));
ha = fcport->ha;
- tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
+ pha = to_qla_parent(ha);
+ tsk = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &tsk_dma);
if (tsk == NULL) {
DEBUG2_3(printk("%s(%ld): failed to allocate Task Management "
"IOCB.\n", __func__, ha->host_no));
@@ -2273,6 +2290,8 @@ qla24xx_abort_target(fc_port_t *fcport)
tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
+ tsk->p.tsk.vp_index = fcport->vp_idx;
+
rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB "
@@ -2303,7 +2322,7 @@ qla24xx_abort_target(fc_port_t *fcport)
}
atarget_done:
- dma_pool_free(ha->s_dma_pool, tsk, tsk_dma);
+ dma_pool_free(pha->s_dma_pool, tsk, tsk_dma);
return rval;
}
@@ -2315,7 +2334,7 @@ qla2x00_system_error(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2425,7 +2444,7 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2455,7 +2474,7 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2495,7 +2514,7 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ if (!IS_FWI2_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2533,7 +2552,7 @@ qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2576,7 +2595,7 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- if (!IS_QLA24XX(ha))
+ if (!IS_IIDMA_CAPABLE(ha))
return QLA_FUNCTION_FAILED;
DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2610,3 +2629,354 @@ qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
return rval;
}
+
+/*
+ * qla24xx_get_vp_database
+ * Get the VP's database for all configured ports.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * size = size of initialization control block.
+ *
+ * Returns:
+ * qla2x00 local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qla24xx_get_vp_database(scsi_qla_host_t *ha, uint16_t size)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk("scsi(%ld):%s - entered.\n",
+ ha->host_no, __func__));
+
+ mcp->mb[0] = MBC_MID_GET_VP_DATABASE;
+ mcp->mb[2] = MSW(ha->init_cb_dma);
+ mcp->mb[3] = LSW(ha->init_cb_dma);
+ mcp->mb[4] = 0;
+ mcp->mb[5] = 0;
+ mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+ mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+ mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ mcp->buf_size = size;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = MBX_TOV_SECONDS;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3_11(printk("%s(%ld): failed=%x "
+ "mb0=%x.\n",
+ __func__, ha->host_no, rval, mcp->mb[0]));
+ } else {
+ /*EMPTY*/
+ DEBUG11(printk("%s(%ld): done.\n",
+ __func__, ha->host_no));
+ }
+
+ return rval;
+}
+
+int
+qla24xx_get_vp_entry(scsi_qla_host_t *ha, uint16_t size, int vp_id)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_MID_GET_VP_ENTRY;
+ mcp->mb[2] = MSW(ha->init_cb_dma);
+ mcp->mb[3] = LSW(ha->init_cb_dma);
+ mcp->mb[4] = 0;
+ mcp->mb[5] = 0;
+ mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+ mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+ mcp->mb[9] = vp_id;
+ mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->buf_size = size;
+ mcp->flags = MBX_DMA_OUT;
+ mcp->tov = 30;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3_11(printk("qla24xx_get_vp_entry(%ld): failed=%x "
+ "mb0=%x.\n",
+ ha->host_no, rval, mcp->mb[0]));
+ } else {
+ /*EMPTY*/
+ DEBUG11(printk("qla24xx_get_vp_entry(%ld): done.\n",
+ ha->host_no));
+ }
+
+ return rval;
+}
+
+void
+qla24xx_report_id_acquisition(scsi_qla_host_t *ha,
+ struct vp_rpt_id_entry_24xx *rptid_entry)
+{
+ uint8_t 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,"
+ " number of VPs acquired %d\n", __func__, ha->host_no,
+ MSB(rptid_entry->vp_count), LSB(rptid_entry->vp_count)));
+ DEBUG15(printk("%s primary port id %02x%02x%02x\n", __func__,
+ 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);
+ 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),
+ 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)
+ return;
+
+ list_for_each_entry(vha, &ha->vp_list, vp_list)
+ if (vp_idx == vha->vp_idx)
+ break;
+
+ if (!vha)
+ return;
+
+ vha->d_id.b.domain = rptid_entry->port_id[2];
+ vha->d_id.b.area = rptid_entry->port_id[1];
+ vha->d_id.b.al_pa = rptid_entry->port_id[0];
+
+ /*
+ * Cannot configure here as we are still sitting on the
+ * response queue. Handle it in dpc context.
+ */
+ set_bit(VP_IDX_ACQUIRED, &vha->vp_flags);
+ set_bit(VP_DPC_NEEDED, &ha->dpc_flags);
+
+ wake_up_process(ha->dpc_thread);
+ }
+}
+
+/*
+ * qla24xx_modify_vp_config
+ * Change VP configuration for vha
+ *
+ * Input:
+ * vha = adapter block pointer.
+ *
+ * Returns:
+ * qla2xxx local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qla24xx_modify_vp_config(scsi_qla_host_t *vha)
+{
+ int rval;
+ struct vp_config_entry_24xx *vpmod;
+ dma_addr_t vpmod_dma;
+ scsi_qla_host_t *pha;
+
+ /* This can be called by the parent */
+ pha = to_qla_parent(vha);
+
+ vpmod = dma_pool_alloc(pha->s_dma_pool, GFP_KERNEL, &vpmod_dma);
+ if (!vpmod) {
+ DEBUG2_3(printk("%s(%ld): failed to allocate Modify VP "
+ "IOCB.\n", __func__, pha->host_no));
+ return QLA_MEMORY_ALLOC_FAILED;
+ }
+
+ memset(vpmod, 0, sizeof(struct vp_config_entry_24xx));
+ vpmod->entry_type = VP_CONFIG_IOCB_TYPE;
+ vpmod->entry_count = 1;
+ vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS;
+ vpmod->vp_count = 1;
+ vpmod->vp_index1 = vha->vp_idx;
+ vpmod->options_idx1 = BIT_3|BIT_4|BIT_5;
+ memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE);
+ memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE);
+ vpmod->entry_count = 1;
+
+ rval = qla2x00_issue_iocb(pha, vpmod, vpmod_dma, 0);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed to issue VP config IOCB"
+ "(%x).\n", __func__, pha->host_no, rval));
+ } else if (vpmod->comp_status != 0) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- error status (%x).\n", __func__, pha->host_no,
+ vpmod->comp_status));
+ rval = QLA_FUNCTION_FAILED;
+ } else if (vpmod->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- completion status (%x).\n", __func__, pha->host_no,
+ le16_to_cpu(vpmod->comp_status)));
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ /* EMPTY */
+ DEBUG11(printk("%s(%ld): done.\n", __func__, pha->host_no));
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
+ }
+ dma_pool_free(pha->s_dma_pool, vpmod, vpmod_dma);
+
+ return rval;
+}
+
+/*
+ * qla24xx_control_vp
+ * Enable a virtual port for given host
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * vhba = virtual adapter (unused)
+ * index = index number for enabled VP
+ *
+ * Returns:
+ * qla2xxx local function return status code.
+ *
+ * Context:
+ * Kernel context.
+ */
+int
+qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
+{
+ int rval;
+ int map, pos;
+ struct vp_ctrl_entry_24xx *vce;
+ dma_addr_t vce_dma;
+ scsi_qla_host_t *ha = vha->parent;
+ int vp_index = vha->vp_idx;
+
+ DEBUG11(printk("%s(%ld): entered. Enabling index %d\n", __func__,
+ ha->host_no, vp_index));
+
+ if (vp_index == 0 || vp_index >= MAX_MULTI_ID_LOOP)
+ return QLA_PARAMETER_ERROR;
+
+ vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma);
+ if (!vce) {
+ DEBUG2_3(printk("%s(%ld): "
+ "failed to allocate VP Control IOCB.\n", __func__,
+ ha->host_no));
+ return QLA_MEMORY_ALLOC_FAILED;
+ }
+ memset(vce, 0, sizeof(struct vp_ctrl_entry_24xx));
+
+ vce->entry_type = VP_CTRL_IOCB_TYPE;
+ vce->entry_count = 1;
+ vce->command = cpu_to_le16(cmd);
+ vce->vp_count = __constant_cpu_to_le16(1);
+
+ /* index map in firmware starts with 1; decrement index
+ * this is ok as we never use index 0
+ */
+ map = (vp_index - 1) / 8;
+ pos = (vp_index - 1) & 7;
+ down(&ha->vport_sem);
+ vce->vp_idx_map[map] |= 1 << pos;
+ up(&ha->vport_sem);
+
+ rval = qla2x00_issue_iocb(ha, vce, vce_dma, 0);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed to issue VP control IOCB"
+ "(%x).\n", __func__, ha->host_no, rval));
+ printk("%s(%ld): failed to issue VP control IOCB"
+ "(%x).\n", __func__, ha->host_no, rval);
+ } else if (vce->entry_status != 0) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- error status (%x).\n", __func__, ha->host_no,
+ vce->entry_status));
+ printk("%s(%ld): failed to complete IOCB "
+ "-- error status (%x).\n", __func__, ha->host_no,
+ vce->entry_status);
+ rval = QLA_FUNCTION_FAILED;
+ } else if (vce->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
+ DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
+ "-- completion status (%x).\n", __func__, ha->host_no,
+ le16_to_cpu(vce->comp_status)));
+ printk("%s(%ld): failed to complete IOCB "
+ "-- completion status (%x).\n", __func__, ha->host_no,
+ le16_to_cpu(vce->comp_status));
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ DEBUG2(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ dma_pool_free(ha->s_dma_pool, vce, vce_dma);
+
+ return rval;
+}
+
+/*
+ * qla2x00_send_change_request
+ * Receive or disable RSCN request from fabric controller
+ *
+ * Input:
+ * ha = adapter block pointer
+ * format = registration format:
+ * 0 - Reserved
+ * 1 - Fabric detected registration
+ * 2 - N_port detected registration
+ * 3 - Full registration
+ * FF - clear registration
+ * vp_idx = Virtual port index
+ *
+ * Returns:
+ * qla2x00 local function return status code.
+ *
+ * Context:
+ * Kernel Context
+ */
+
+int
+qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format,
+ uint16_t vp_idx)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ /*
+ * This command is implicitly executed by firmware during login for the
+ * physical hosts
+ */
+ if (vp_idx == 0)
+ return QLA_FUNCTION_FAILED;
+
+ mcp->mb[0] = MBC_SEND_CHANGE_REQUEST;
+ mcp->mb[1] = format;
+ mcp->mb[9] = vp_idx;
+ mcp->out_mb = MBX_9|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0|MBX_1;
+ mcp->tov = MBX_TOV_SECONDS;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval == QLA_SUCCESS) {
+ if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
+ rval = BIT_1;
+ }
+ } else
+ rval = BIT_1;
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
new file mode 100644
index 000000000000..54dc415d8b53
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -0,0 +1,497 @@
+/*
+ * QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2005 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/list.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+#include <linux/delay.h>
+
+void qla2x00_vp_stop_timer(scsi_qla_host_t *);
+
+void
+qla2x00_vp_stop_timer(scsi_qla_host_t *vha)
+{
+ if (vha->parent && vha->timer_active) {
+ del_timer_sync(&vha->timer);
+ vha->timer_active = 0;
+ }
+}
+
+uint32_t
+qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
+{
+ uint32_t vp_id;
+ scsi_qla_host_t *ha = vha->parent;
+
+ /* Find an empty slot and assign an vp_id */
+ down(&ha->vport_sem);
+ vp_id = find_first_zero_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC);
+ if (vp_id > MAX_MULTI_ID_FABRIC) {
+ DEBUG15(printk ("vp_id %d is bigger than MAX_MULTI_ID_FABRID\n",
+ vp_id));
+ up(&ha->vport_sem);
+ return vp_id;
+ }
+
+ set_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+ ha->num_vhosts++;
+ vha->vp_idx = vp_id;
+ list_add_tail(&vha->vp_list, &ha->vp_list);
+ up(&ha->vport_sem);
+ return vp_id;
+}
+
+void
+qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
+{
+ uint16_t vp_id;
+ scsi_qla_host_t *ha = vha->parent;
+
+ down(&ha->vport_sem);
+ vp_id = vha->vp_idx;
+ ha->num_vhosts--;
+ clear_bit(vp_id, (unsigned long *)ha->vp_idx_map);
+ list_del(&vha->vp_list);
+ up(&ha->vport_sem);
+}
+
+scsi_qla_host_t *
+qla24xx_find_vhost_by_name(scsi_qla_host_t *ha, uint8_t *port_name)
+{
+ scsi_qla_host_t *vha;
+
+ /* Locate matching device in database. */
+ list_for_each_entry(vha, &ha->vp_list, vp_list) {
+ if (!memcmp(port_name, vha->port_name, WWN_SIZE))
+ return vha;
+ }
+ return NULL;
+}
+
+/*
+ * qla2x00_mark_vp_devices_dead
+ * Updates fcport state when device goes offline.
+ *
+ * Input:
+ * ha = adapter block pointer.
+ * fcport = port structure pointer.
+ *
+ * Return:
+ * None.
+ *
+ * Context:
+ */
+void
+qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
+{
+ fc_port_t *fcport;
+ scsi_qla_host_t *pha = to_qla_parent(vha);
+
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (fcport->vp_idx != vha->vp_idx)
+ continue;
+
+ DEBUG15(printk("scsi(%ld): Marking port dead, "
+ "loop_id=0x%04x :%x\n",
+ vha->host_no, fcport->loop_id, fcport->vp_idx));
+
+ atomic_set(&fcport->state, FCS_DEVICE_DEAD);
+ qla2x00_mark_device_lost(vha, fcport, 0, 0);
+ }
+}
+
+int
+qla24xx_disable_vp(scsi_qla_host_t *vha)
+{
+ int ret;
+
+ ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+
+ /* Delete all vp's fcports from parent's list */
+ qla2x00_mark_vp_devices_dead(vha);
+ atomic_set(&vha->vp_state, VP_FAILED);
+ vha->flags.management_server_logged_in = 0;
+ if (ret == QLA_SUCCESS) {
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_DISABLED);
+ } else {
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
+ return -1;
+ }
+ return 0;
+}
+
+int
+qla24xx_enable_vp(scsi_qla_host_t *vha)
+{
+ int ret;
+ scsi_qla_host_t *ha = vha->parent;
+
+ /* Check if physical ha port is Up */
+ if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+ atomic_read(&ha->loop_state) == LOOP_DEAD ) {
+ vha->vp_err_state = VP_ERR_PORTDWN;
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN);
+ goto enable_failed;
+ }
+
+ /* Initialize the new vport unless it is a persistent port */
+ down(&ha->vport_sem);
+ ret = qla24xx_modify_vp_config(vha);
+ up(&ha->vport_sem);
+
+ if (ret != QLA_SUCCESS) {
+ fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
+ goto enable_failed;
+ }
+
+ DEBUG15(qla_printk(KERN_INFO, ha,
+ "Virtual port with id: %d - Enabled\n", vha->vp_idx));
+ return 0;
+
+enable_failed:
+ DEBUG15(qla_printk(KERN_INFO, ha,
+ "Virtual port with id: %d - Disabled\n", vha->vp_idx));
+ return 1;
+}
+
+/**
+ * qla24xx_modify_vport() - Modifies the virtual fabric port's configuration
+ * @ha: HA context
+ * @vp: pointer to buffer of virtual port parameters.
+ * @ret_code: return error code:
+ *
+ * Returns the virtual port id, or MAX_VSAN_ID, if couldn't create.
+ */
+uint32_t
+qla24xx_modify_vhba(scsi_qla_host_t *ha, vport_params_t *vp, uint32_t *vp_id)
+{
+ scsi_qla_host_t *vha;
+
+ vha = qla24xx_find_vhost_by_name(ha, vp->port_name);
+ if (!vha) {
+ *vp_id = MAX_NUM_VPORT_LOOP;
+ return VP_RET_CODE_WWPN;
+ }
+
+ if (qla24xx_enable_vp(vha)) {
+ scsi_host_put(vha->host);
+ qla2x00_mem_free(vha);
+ *vp_id = MAX_NUM_VPORT_LOOP;
+ return VP_RET_CODE_RESOURCES;
+ }
+
+ *vp_id = vha->vp_idx;
+ return VP_RET_CODE_OK;
+}
+
+void
+qla24xx_configure_vp(scsi_qla_host_t *vha)
+{
+ struct fc_vport *fc_vport;
+ int ret;
+
+ fc_vport = vha->fc_vport;
+
+ DEBUG15(printk("scsi(%ld): %s: change request #3 for this host.\n",
+ vha->host_no, __func__));
+ ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx);
+ if (ret != QLA_SUCCESS) {
+ DEBUG15(qla_printk(KERN_ERR, vha, "Failed to enable receiving"
+ " of RSCN requests: 0x%x\n", ret));
+ return;
+ } else {
+ /* Corresponds to SCR enabled */
+ clear_bit(VP_SCR_NEEDED, &vha->vp_flags);
+ }
+
+ vha->flags.online = 1;
+ if (qla24xx_configure_vhba(vha))
+ return;
+
+ atomic_set(&vha->vp_state, VP_ACTIVE);
+ fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE);
+}
+
+void
+qla2x00_alert_all_vps(scsi_qla_host_t *ha, uint16_t *mb)
+{
+ int i, vp_idx_matched;
+ scsi_qla_host_t *vha;
+
+ if (ha->parent)
+ return;
+
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, 1);
+ for (;i <= MAX_MULTI_ID_FABRIC;
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+ vp_idx_matched = 0;
+
+ list_for_each_entry(vha, &ha->vp_list, vp_list) {
+ if (i == vha->vp_idx) {
+ vp_idx_matched = 1;
+ break;
+ }
+ }
+
+ if (vp_idx_matched) {
+ switch (mb[0]) {
+ case MBA_LIP_OCCURRED:
+ case MBA_LOOP_UP:
+ case MBA_LOOP_DOWN:
+ case MBA_LIP_RESET:
+ case MBA_POINT_TO_POINT:
+ case MBA_CHG_IN_CONNECTION:
+ case MBA_PORT_UPDATE:
+ case MBA_RSCN_UPDATE:
+ DEBUG15(printk("scsi(%ld)%s: Async_event for"
+ " VP[%d], mb = 0x%x, vha=%p\n",
+ vha->host_no, __func__,i, *mb, vha));
+ qla2x00_async_event(vha, mb);
+ break;
+ }
+ }
+ }
+}
+
+void
+qla2x00_vp_abort_isp(scsi_qla_host_t *vha)
+{
+ /*
+ * Physical port will do most of the abort and recovery work. We can
+ * just treat it as a loop down
+ */
+ if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ qla2x00_mark_all_devices_lost(vha, 0);
+ } else {
+ if (!atomic_read(&vha->loop_down_timer))
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+ }
+
+ DEBUG15(printk("scsi(%ld): Scheduling enable of Vport %d...\n",
+ vha->host_no, vha->vp_idx));
+ qla24xx_enable_vp(vha);
+}
+
+int
+qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
+{
+ if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
+ /* VP acquired. complete port configuration */
+ qla24xx_configure_vp(vha);
+ return 0;
+ }
+
+ if (test_and_clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
+ qla2x00_vp_abort_isp(vha);
+
+ if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) &&
+ (!(test_and_set_bit(RESET_ACTIVE, &vha->dpc_flags)))) {
+ clear_bit(RESET_ACTIVE, &vha->dpc_flags);
+ }
+
+ if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
+ if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) {
+ qla2x00_loop_resync(vha);
+ clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags);
+ }
+ }
+
+ return 0;
+}
+
+void
+qla2x00_do_dpc_all_vps(scsi_qla_host_t *ha)
+{
+ int ret;
+ int i, vp_idx_matched;
+ scsi_qla_host_t *vha;
+
+ if (ha->parent)
+ return;
+ if (list_empty(&ha->vp_list))
+ return;
+
+ clear_bit(VP_DPC_NEEDED, &ha->dpc_flags);
+
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, 1);
+ for (;i <= MAX_MULTI_ID_FABRIC;
+ i = find_next_bit((unsigned long *)ha->vp_idx_map,
+ MAX_MULTI_ID_FABRIC + 1, i + 1)) {
+ vp_idx_matched = 0;
+
+ list_for_each_entry(vha, &ha->vp_list, vp_list) {
+ if (i == vha->vp_idx) {
+ vp_idx_matched = 1;
+ break;
+ }
+ }
+
+ if (vp_idx_matched)
+ ret = qla2x00_do_dpc_vp(vha);
+ }
+}
+
+int
+qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha;
+ uint8_t port_name[WWN_SIZE];
+
+ if (fc_vport->roles != FC_PORT_ROLE_FCP_INITIATOR)
+ return VPCERR_UNSUPPORTED;
+
+ /* Check up the F/W and H/W support NPIV */
+ if (!ha->flags.npiv_supported)
+ return VPCERR_UNSUPPORTED;
+
+ /* Check up whether npiv supported switch presented */
+ if (!(ha->switch_cap & FLOGI_MID_SUPPORT))
+ return VPCERR_NO_FABRIC_SUPP;
+
+ /* Check up unique WWPN */
+ u64_to_wwn(fc_vport->port_name, port_name);
+ vha = qla24xx_find_vhost_by_name(ha, port_name);
+ if (vha)
+ return VPCERR_BAD_WWN;
+
+ /* Check up max-npiv-supports */
+ if (ha->num_vhosts > ha->max_npiv_vports) {
+ DEBUG15(printk("scsi(%ld): num_vhosts %d is bigger than "
+ "max_npv_vports %d.\n", ha->host_no,
+ (uint16_t) ha->num_vhosts, (int) ha->max_npiv_vports));
+ return VPCERR_UNSUPPORTED;
+ }
+ return 0;
+}
+
+scsi_qla_host_t *
+qla24xx_create_vhost(struct fc_vport *fc_vport)
+{
+ scsi_qla_host_t *ha = (scsi_qla_host_t *) fc_vport->shost->hostdata;
+ scsi_qla_host_t *vha;
+ struct Scsi_Host *host;
+
+ host = scsi_host_alloc(&qla24xx_driver_template,
+ sizeof(scsi_qla_host_t));
+ if (!host) {
+ printk(KERN_WARNING
+ "qla2xxx: scsi_host_alloc() failed for vport\n");
+ return(NULL);
+ }
+
+ vha = (scsi_qla_host_t *)host->hostdata;
+
+ /* clone the parent hba */
+ memcpy(vha, ha, sizeof (scsi_qla_host_t));
+
+ fc_vport->dd_data = vha;
+
+ vha->node_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
+ if (!vha->node_name)
+ goto create_vhost_failed_1;
+
+ vha->port_name = kmalloc(WWN_SIZE * sizeof(char), GFP_KERNEL);
+ if (!vha->port_name)
+ goto create_vhost_failed_2;
+
+ /* New host info */
+ u64_to_wwn(fc_vport->node_name, vha->node_name);
+ u64_to_wwn(fc_vport->port_name, vha->port_name);
+
+ vha->host = host;
+ vha->host_no = host->host_no;
+ vha->parent = ha;
+ vha->fc_vport = fc_vport;
+ vha->device_flags = 0;
+ vha->instance = num_hosts;
+ vha->vp_idx = qla24xx_allocate_vp_id(vha);
+ if (vha->vp_idx > ha->max_npiv_vports) {
+ DEBUG15(printk("scsi(%ld): Couldn't allocate vp_id.\n",
+ vha->host_no));
+ goto create_vhost_failed_3;
+ }
+ vha->mgmt_svr_loop_id = 10 + vha->vp_idx;
+
+ init_MUTEX(&vha->mbx_cmd_sem);
+ init_MUTEX_LOCKED(&vha->mbx_intr_sem);
+
+ INIT_LIST_HEAD(&vha->list);
+ INIT_LIST_HEAD(&vha->fcports);
+ INIT_LIST_HEAD(&vha->vp_fcports);
+
+ vha->dpc_flags = 0L;
+ set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
+ set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
+
+ /*
+ * To fix the issue of processing a parent's RSCN for the vport before
+ * its SCR is complete.
+ */
+ set_bit(VP_SCR_NEEDED, &vha->vp_flags);
+ atomic_set(&vha->loop_state, LOOP_DOWN);
+ atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
+
+ qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
+
+ host->can_queue = vha->request_q_length + 128;
+ host->this_id = 255;
+ host->cmd_per_lun = 3;
+ host->max_cmd_len = MAX_CMDSZ;
+ host->max_channel = MAX_BUSES - 1;
+ host->max_lun = MAX_LUNS;
+ host->unique_id = vha->instance;
+ host->max_id = MAX_TARGETS_2200;
+ host->transportt = qla2xxx_transport_vport_template;
+
+ DEBUG15(printk("DEBUG: detect vport hba %ld at address = %p\n",
+ vha->host_no, vha));
+
+ vha->flags.init_done = 1;
+ num_hosts++;
+
+ down(&ha->vport_sem);
+ set_bit(vha->vp_idx, (unsigned long *)ha->vp_idx_map);
+ ha->cur_vport_count++;
+ up(&ha->vport_sem);
+
+ return vha;
+
+create_vhost_failed_3:
+ kfree(vha->port_name);
+
+create_vhost_failed_2:
+ kfree(vha->node_name);
+
+create_vhost_failed_1:
+ return NULL;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b98136adaaae..c488996cb958 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -29,8 +29,7 @@ static struct kmem_cache *srb_cachep;
/*
* Ioctl related information.
*/
-static int num_hosts;
-
+int num_hosts;
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xlogintimeout,
@@ -112,7 +111,7 @@ static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
static int qla2x00_change_queue_depth(struct scsi_device *, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
-static struct scsi_host_template qla2x00_driver_template = {
+struct scsi_host_template qla2x00_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla2x00_queuecommand,
@@ -143,7 +142,7 @@ static struct scsi_host_template qla2x00_driver_template = {
.shost_attrs = qla2x00_host_attrs,
};
-static struct scsi_host_template qla24xx_driver_template = {
+struct scsi_host_template qla24xx_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla24xx_queuecommand,
@@ -171,21 +170,21 @@ static struct scsi_host_template qla24xx_driver_template = {
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
+struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
/* TODO Convert to inlines
*
* Timer routines
*/
-#define WATCH_INTERVAL 1 /* number of seconds */
-static void qla2x00_timer(scsi_qla_host_t *);
+void qla2x00_timer(scsi_qla_host_t *);
-static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
void *, unsigned long);
static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
-static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
-static inline void
+__inline__ void
qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
{
init_timer(&ha->timer);
@@ -202,7 +201,7 @@ qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
mod_timer(&ha->timer, jiffies + interval * HZ);
}
-static __inline__ void
+__inline__ void
qla2x00_stop_timer(scsi_qla_host_t *ha)
{
del_timer_sync(&ha->timer);
@@ -213,8 +212,8 @@ static int qla2x00_do_dpc(void *data);
static void qla2x00_rst_aen(scsi_qla_host_t *);
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-static void qla2x00_mem_free(scsi_qla_host_t *ha);
+uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+void qla2x00_mem_free(scsi_qla_host_t *ha);
static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
@@ -266,6 +265,8 @@ qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str)
strcpy(str, "PCIe (");
if (lspeed == 1)
strcat(str, "2.5Gb/s ");
+ else if (lspeed == 2)
+ strcat(str, "5.0Gb/s ");
else
strcat(str, "<unknown> ");
snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
@@ -344,6 +345,12 @@ qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
strcat(str, "[IP] ");
if (ha->fw_attributes & BIT_2)
strcat(str, "[Multi-ID] ");
+ if (ha->fw_attributes & BIT_3)
+ strcat(str, "[SB-2] ");
+ if (ha->fw_attributes & BIT_4)
+ strcat(str, "[T10 CRC] ");
+ if (ha->fw_attributes & BIT_5)
+ strcat(str, "[VI] ");
if (ha->fw_attributes & BIT_13)
strcat(str, "[Experimental]");
return str;
@@ -438,6 +445,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = fc_remote_port_chkready(rport);
if (rval) {
@@ -453,7 +461,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
if (atomic_read(&fcport->state) != FCS_ONLINE) {
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ atomic_read(&pha->loop_state) == LOOP_DEAD) {
cmd->result = DID_NO_CONNECT << 16;
goto qc24_fail_command;
}
@@ -462,7 +470,7 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
spin_unlock_irq(ha->host->host_lock);
- sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
+ sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
if (!sp)
goto qc24_host_busy_lock;
@@ -475,8 +483,8 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
return 0;
qc24_host_busy_free_sp:
- qla2x00_sp_free_dma(ha, sp);
- mempool_free(sp, ha->srb_mempool);
+ qla2x00_sp_free_dma(pha, sp);
+ mempool_free(sp, pha->srb_mempool);
qc24_host_busy_lock:
spin_lock_irq(ha->host->host_lock);
@@ -548,16 +556,17 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
{
int return_status;
unsigned long wait_online;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
- test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
- test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
- ha->dpc_active) && time_before(jiffies, wait_online)) {
+ while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
+ test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
+ test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
+ pha->dpc_active) && time_before(jiffies, wait_online)) {
msleep(1000);
}
- if (ha->flags.online)
+ if (pha->flags.online)
return_status = QLA_SUCCESS;
else
return_status = QLA_FUNCTION_FAILED;
@@ -588,14 +597,15 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
{
int return_status = QLA_SUCCESS;
unsigned long loop_timeout ;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/* wait for 5 min at the max for loop to be ready */
loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while ((!atomic_read(&ha->loop_down_timer) &&
- atomic_read(&ha->loop_state) == LOOP_DOWN) ||
- atomic_read(&ha->loop_state) != LOOP_READY) {
- if (atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ while ((!atomic_read(&pha->loop_down_timer) &&
+ atomic_read(&pha->loop_state) == LOOP_DOWN) ||
+ atomic_read(&pha->loop_state) != LOOP_READY) {
+ if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
return_status = QLA_FUNCTION_FAILED;
break;
}
@@ -650,6 +660,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned long serial;
unsigned long flags;
int wait = 0;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
@@ -663,9 +674,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
serial = cmd->serial_number;
/* Check active list for command command. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
- sp = ha->outstanding_cmds[i];
+ sp = pha->outstanding_cmds[i];
if (sp == NULL)
continue;
@@ -677,8 +688,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
__func__, ha->host_no, sp, serial));
DEBUG3(qla2x00_print_scsi_cmd(cmd));
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (ha->isp_ops.abort_command(ha, sp)) {
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
+ if (ha->isp_ops->abort_command(ha, sp)) {
DEBUG2(printk("%s(%ld): abort_command "
"mbx failed.\n", __func__, ha->host_no));
} else {
@@ -686,11 +697,11 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
"mbx success.\n", __func__, ha->host_no));
wait = 1;
}
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
break;
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
/* Wait for the command to be returned. */
if (wait) {
@@ -731,6 +742,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
srb_t *sp;
struct scsi_cmnd *cmd;
unsigned long flags;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
status = 0;
@@ -739,19 +751,20 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
* array
*/
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
- spin_lock_irqsave(&ha->hardware_lock, flags);
- sp = ha->outstanding_cmds[cnt];
+ spin_lock_irqsave(&pha->hardware_lock, flags);
+ sp = pha->outstanding_cmds[cnt];
if (sp) {
cmd = sp->cmd;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (cmd->device->id == t) {
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
+ if (cmd->device->id == t &&
+ ha->vp_idx == sp->ha->vp_idx) {
if (!qla2x00_eh_wait_on_command(ha, cmd)) {
status = 1;
break;
}
}
} else {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
}
}
return (status);
@@ -782,14 +795,12 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
@@ -810,7 +821,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
#if defined(LOGOUT_AFTER_DEVICE_RESET)
if (ret == SUCCESS) {
if (fcport->flags & FC_FABRIC_DEVICE) {
- ha->isp_ops.fabric_logout(ha, fcport->loop_id);
+ ha->isp_ops->fabric_logout(ha, fcport->loop_id);
qla2x00_mark_device_lost(ha, fcport, 0, 0);
}
}
@@ -912,15 +923,14 @@ static int
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *pha = to_qla_parent(ha);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
@@ -944,7 +954,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
goto eh_bus_reset_done;
/* Flush outstanding commands. */
- if (!qla2x00_eh_wait_for_pending_commands(ha))
+ if (!qla2x00_eh_wait_for_pending_commands(pha))
ret = FAILED;
eh_bus_reset_done:
@@ -974,14 +984,13 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
@@ -1004,21 +1013,24 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
* while dpc is stuck for the mailbox to complete.
*/
qla2x00_wait_for_loop_ready(ha);
- set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
- if (qla2x00_abort_isp(ha)) {
- clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
+ if (qla2x00_abort_isp(pha)) {
+ clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* failed. schedule dpc to try */
- set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+ set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
goto eh_host_reset_lock;
}
- clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* Waiting for our command in done_queue to be returned to OS.*/
- if (qla2x00_eh_wait_for_pending_commands(ha))
+ if (qla2x00_eh_wait_for_pending_commands(pha))
ret = SUCCESS;
+ if (ha->parent)
+ qla2x00_vp_abort_isp(ha);
+
eh_host_reset_lock:
qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
(ret == FAILED) ? "failed" : "succeded");
@@ -1101,7 +1113,7 @@ static int
qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport)
{
/* Abort Target command will clear Reservation */
- return ha->isp_ops.abort_target(reset_fcport);
+ return ha->isp_ops->abort_target(reset_fcport);
}
static int
@@ -1180,8 +1192,8 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
!pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
/* Ok, a 64bit DMA mask is applicable. */
ha->flags.enable_64bit_addressing = 1;
- ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64;
- ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64;
+ ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
+ ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64;
return;
}
}
@@ -1190,6 +1202,193 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
}
+static void
+qla2x00_enable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 1;
+ /* enable risc and host interrupts */
+ WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
+ RD_REG_WORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
+static void
+qla2x00_disable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 0;
+ /* disable risc and host interrupts */
+ WRT_REG_WORD(&reg->ictrl, 0);
+ RD_REG_WORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_enable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 1;
+ WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
+ RD_REG_DWORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_disable_intrs(scsi_qla_host_t *ha)
+{
+ unsigned long flags = 0;
+ struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->interrupts_on = 0;
+ WRT_REG_DWORD(&reg->ictrl, 0);
+ RD_REG_DWORD(&reg->ictrl);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static struct isp_operations qla2100_isp_ops = {
+ .pci_config = qla2100_pci_config,
+ .reset_chip = qla2x00_reset_chip,
+ .chip_diag = qla2x00_chip_diag,
+ .config_rings = qla2x00_config_rings,
+ .reset_adapter = qla2x00_reset_adapter,
+ .nvram_config = qla2x00_nvram_config,
+ .update_fw_options = qla2x00_update_fw_options,
+ .load_risc = qla2x00_load_risc,
+ .pci_info_str = qla2x00_pci_info_str,
+ .fw_version_str = qla2x00_fw_version_str,
+ .intr_handler = qla2100_intr_handler,
+ .enable_intrs = qla2x00_enable_intrs,
+ .disable_intrs = qla2x00_disable_intrs,
+ .abort_command = qla2x00_abort_command,
+ .abort_target = qla2x00_abort_target,
+ .fabric_login = qla2x00_login_fabric,
+ .fabric_logout = qla2x00_fabric_logout,
+ .calc_req_entries = qla2x00_calc_iocbs_32,
+ .build_iocbs = qla2x00_build_scsi_iocbs_32,
+ .prep_ms_iocb = qla2x00_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb,
+ .read_nvram = qla2x00_read_nvram_data,
+ .write_nvram = qla2x00_write_nvram_data,
+ .fw_dump = qla2100_fw_dump,
+ .beacon_on = NULL,
+ .beacon_off = NULL,
+ .beacon_blink = NULL,
+ .read_optrom = qla2x00_read_optrom_data,
+ .write_optrom = qla2x00_write_optrom_data,
+ .get_flash_version = qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla2300_isp_ops = {
+ .pci_config = qla2300_pci_config,
+ .reset_chip = qla2x00_reset_chip,
+ .chip_diag = qla2x00_chip_diag,
+ .config_rings = qla2x00_config_rings,
+ .reset_adapter = qla2x00_reset_adapter,
+ .nvram_config = qla2x00_nvram_config,
+ .update_fw_options = qla2x00_update_fw_options,
+ .load_risc = qla2x00_load_risc,
+ .pci_info_str = qla2x00_pci_info_str,
+ .fw_version_str = qla2x00_fw_version_str,
+ .intr_handler = qla2300_intr_handler,
+ .enable_intrs = qla2x00_enable_intrs,
+ .disable_intrs = qla2x00_disable_intrs,
+ .abort_command = qla2x00_abort_command,
+ .abort_target = qla2x00_abort_target,
+ .fabric_login = qla2x00_login_fabric,
+ .fabric_logout = qla2x00_fabric_logout,
+ .calc_req_entries = qla2x00_calc_iocbs_32,
+ .build_iocbs = qla2x00_build_scsi_iocbs_32,
+ .prep_ms_iocb = qla2x00_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb,
+ .read_nvram = qla2x00_read_nvram_data,
+ .write_nvram = qla2x00_write_nvram_data,
+ .fw_dump = qla2300_fw_dump,
+ .beacon_on = qla2x00_beacon_on,
+ .beacon_off = qla2x00_beacon_off,
+ .beacon_blink = qla2x00_beacon_blink,
+ .read_optrom = qla2x00_read_optrom_data,
+ .write_optrom = qla2x00_write_optrom_data,
+ .get_flash_version = qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla24xx_isp_ops = {
+ .pci_config = qla24xx_pci_config,
+ .reset_chip = qla24xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla24xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla24xx_nvram_config,
+ .update_fw_options = qla24xx_update_fw_options,
+ .load_risc = qla24xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla24xx_intr_handler,
+ .enable_intrs = qla24xx_enable_intrs,
+ .disable_intrs = qla24xx_disable_intrs,
+ .abort_command = qla24xx_abort_command,
+ .abort_target = qla24xx_abort_target,
+ .fabric_login = qla24xx_login_fabric,
+ .fabric_logout = qla24xx_fabric_logout,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = qla24xx_read_nvram_data,
+ .write_nvram = qla24xx_write_nvram_data,
+ .fw_dump = qla24xx_fw_dump,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = qla24xx_beacon_blink,
+ .read_optrom = qla24xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+};
+
+static struct isp_operations qla25xx_isp_ops = {
+ .pci_config = qla25xx_pci_config,
+ .reset_chip = qla24xx_reset_chip,
+ .chip_diag = qla24xx_chip_diag,
+ .config_rings = qla24xx_config_rings,
+ .reset_adapter = qla24xx_reset_adapter,
+ .nvram_config = qla24xx_nvram_config,
+ .update_fw_options = qla24xx_update_fw_options,
+ .load_risc = qla24xx_load_risc,
+ .pci_info_str = qla24xx_pci_info_str,
+ .fw_version_str = qla24xx_fw_version_str,
+ .intr_handler = qla24xx_intr_handler,
+ .enable_intrs = qla24xx_enable_intrs,
+ .disable_intrs = qla24xx_disable_intrs,
+ .abort_command = qla24xx_abort_command,
+ .abort_target = qla24xx_abort_target,
+ .fabric_login = qla24xx_login_fabric,
+ .fabric_logout = qla24xx_fabric_logout,
+ .calc_req_entries = NULL,
+ .build_iocbs = NULL,
+ .prep_ms_iocb = qla24xx_prep_ms_iocb,
+ .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
+ .read_nvram = qla25xx_read_nvram_data,
+ .write_nvram = qla25xx_write_nvram_data,
+ .fw_dump = qla25xx_fw_dump,
+ .beacon_on = qla24xx_beacon_on,
+ .beacon_off = qla24xx_beacon_off,
+ .beacon_blink = qla24xx_beacon_blink,
+ .read_optrom = qla24xx_read_optrom_data,
+ .write_optrom = qla24xx_write_optrom_data,
+ .get_flash_version = qla24xx_get_flash_version,
+};
+
static inline void
qla2x00_set_isp_flags(scsi_qla_host_t *ha)
{
@@ -1234,19 +1433,32 @@ qla2x00_set_isp_flags(scsi_qla_host_t *ha)
case PCI_DEVICE_ID_QLOGIC_ISP2422:
ha->device_type |= DT_ISP2422;
ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP2432:
ha->device_type |= DT_ISP2432;
ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP5422:
ha->device_type |= DT_ISP5422;
+ ha->device_type |= DT_FWI2;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP5432:
ha->device_type |= DT_ISP5432;
+ ha->device_type |= DT_FWI2;
+ ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+ break;
+ case PCI_DEVICE_ID_QLOGIC_ISP2532:
+ ha->device_type |= DT_ISP2532;
+ ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
}
@@ -1319,61 +1531,6 @@ iospace_error_exit:
}
static void
-qla2x00_enable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 1;
- /* enable risc and host interrupts */
- WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
- RD_REG_WORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-}
-
-static void
-qla2x00_disable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 0;
- /* disable risc and host interrupts */
- WRT_REG_WORD(&reg->ictrl, 0);
- RD_REG_WORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_enable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 1;
- WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
- RD_REG_DWORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_disable_intrs(scsi_qla_host_t *ha)
-{
- unsigned long flags = 0;
- struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- ha->interrupts_on = 0;
- WRT_REG_DWORD(&reg->ictrl, 0);
- RD_REG_DWORD(&reg->ictrl);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
qla2xxx_scan_start(struct Scsi_Host *shost)
{
scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
@@ -1418,7 +1575,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
- pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432)
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532)
sht = &qla24xx_driver_template;
host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
if (host == NULL) {
@@ -1435,6 +1593,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->host = host;
ha->host_no = host->host_no;
sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
+ ha->parent = NULL;
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
@@ -1452,7 +1611,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
- ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
+ ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300;
@@ -1461,33 +1620,6 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->max_q_depth = ql2xmaxqdepth;
/* Assign ISP specific operations. */
- ha->isp_ops.pci_config = qla2100_pci_config;
- ha->isp_ops.reset_chip = qla2x00_reset_chip;
- ha->isp_ops.chip_diag = qla2x00_chip_diag;
- ha->isp_ops.config_rings = qla2x00_config_rings;
- ha->isp_ops.reset_adapter = qla2x00_reset_adapter;
- ha->isp_ops.nvram_config = qla2x00_nvram_config;
- ha->isp_ops.update_fw_options = qla2x00_update_fw_options;
- ha->isp_ops.load_risc = qla2x00_load_risc;
- ha->isp_ops.pci_info_str = qla2x00_pci_info_str;
- ha->isp_ops.fw_version_str = qla2x00_fw_version_str;
- ha->isp_ops.intr_handler = qla2100_intr_handler;
- ha->isp_ops.enable_intrs = qla2x00_enable_intrs;
- ha->isp_ops.disable_intrs = qla2x00_disable_intrs;
- ha->isp_ops.abort_command = qla2x00_abort_command;
- ha->isp_ops.abort_target = qla2x00_abort_target;
- ha->isp_ops.fabric_login = qla2x00_login_fabric;
- ha->isp_ops.fabric_logout = qla2x00_fabric_logout;
- ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32;
- ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32;
- ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb;
- ha->isp_ops.prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb;
- ha->isp_ops.read_nvram = qla2x00_read_nvram_data;
- ha->isp_ops.write_nvram = qla2x00_write_nvram_data;
- ha->isp_ops.fw_dump = qla2100_fw_dump;
- ha->isp_ops.read_optrom = qla2x00_read_optrom_data;
- ha->isp_ops.write_optrom = qla2x00_write_optrom_data;
- ha->isp_ops.get_flash_version = qla2x00_get_flash_version;
if (IS_QLA2100(ha)) {
host->max_id = MAX_TARGETS_2100;
ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
@@ -1496,6 +1628,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
host->sg_tablesize = 32;
ha->gid_list_info_size = 4;
+ ha->isp_ops = &qla2100_isp_ops;
} else if (IS_QLA2200(ha)) {
host->max_id = MAX_TARGETS_2200;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1503,59 +1636,39 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
ha->gid_list_info_size = 4;
+ ha->isp_ops = &qla2100_isp_ops;
} else if (IS_QLA23XX(ha)) {
host->max_id = MAX_TARGETS_2200;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
ha->request_q_length = REQUEST_ENTRY_CNT_2200;
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
- ha->isp_ops.pci_config = qla2300_pci_config;
- ha->isp_ops.intr_handler = qla2300_intr_handler;
- ha->isp_ops.fw_dump = qla2300_fw_dump;
- ha->isp_ops.beacon_on = qla2x00_beacon_on;
- ha->isp_ops.beacon_off = qla2x00_beacon_off;
- ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
ha->gid_list_info_size = 6;
if (IS_QLA2322(ha) || IS_QLA6322(ha))
ha->optrom_size = OPTROM_SIZE_2322;
+ ha->isp_ops = &qla2300_isp_ops;
} else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
host->max_id = MAX_TARGETS_2200;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
- ha->init_cb_size = sizeof(struct init_cb_24xx);
- ha->mgmt_svr_loop_id = 10;
- ha->isp_ops.pci_config = qla24xx_pci_config;
- ha->isp_ops.reset_chip = qla24xx_reset_chip;
- ha->isp_ops.chip_diag = qla24xx_chip_diag;
- ha->isp_ops.config_rings = qla24xx_config_rings;
- ha->isp_ops.reset_adapter = qla24xx_reset_adapter;
- ha->isp_ops.nvram_config = qla24xx_nvram_config;
- ha->isp_ops.update_fw_options = qla24xx_update_fw_options;
- ha->isp_ops.load_risc = qla24xx_load_risc;
- ha->isp_ops.pci_info_str = qla24xx_pci_info_str;
- ha->isp_ops.fw_version_str = qla24xx_fw_version_str;
- ha->isp_ops.intr_handler = qla24xx_intr_handler;
- ha->isp_ops.enable_intrs = qla24xx_enable_intrs;
- ha->isp_ops.disable_intrs = qla24xx_disable_intrs;
- ha->isp_ops.abort_command = qla24xx_abort_command;
- ha->isp_ops.abort_target = qla24xx_abort_target;
- ha->isp_ops.fabric_login = qla24xx_login_fabric;
- ha->isp_ops.fabric_logout = qla24xx_fabric_logout;
- ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb;
- ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb;
- ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
- ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
- ha->isp_ops.fw_dump = qla24xx_fw_dump;
- ha->isp_ops.read_optrom = qla24xx_read_optrom_data;
- ha->isp_ops.write_optrom = qla24xx_write_optrom_data;
- ha->isp_ops.beacon_on = qla24xx_beacon_on;
- ha->isp_ops.beacon_off = qla24xx_beacon_off;
- ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
- ha->isp_ops.get_flash_version = qla24xx_get_flash_version;
+ ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+ ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_24XX;
+ ha->isp_ops = &qla24xx_isp_ops;
+ } else if (IS_QLA25XX(ha)) {
+ host->max_id = MAX_TARGETS_2200;
+ ha->mbx_count = MAILBOX_REGISTER_COUNT;
+ ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
+ ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
+ ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
+ ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+ ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
+ ha->gid_list_info_size = 8;
+ ha->optrom_size = OPTROM_SIZE_25XX;
+ ha->isp_ops = &qla25xx_isp_ops;
}
host->can_queue = ha->request_q_length + 128;
@@ -1563,10 +1676,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->instance = num_hosts;
init_MUTEX(&ha->mbx_cmd_sem);
+ init_MUTEX(&ha->vport_sem);
init_MUTEX_LOCKED(&ha->mbx_intr_sem);
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
+ INIT_LIST_HEAD(&ha->vp_list);
+
+ set_bit(0, (unsigned long *) ha->vp_idx_map);
qla2x00_config_dma_addressing(ha);
if (qla2x00_mem_alloc(ha)) {
@@ -1619,11 +1736,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
ha->host_no, ha));
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
spin_lock_irqsave(&ha->hardware_lock, flags);
reg = ha->iobase;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
} else {
@@ -1645,7 +1762,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
pci_set_drvdata(pdev, ha);
@@ -1670,9 +1787,9 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
" ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
qla2x00_version_str, ha->model_number,
ha->model_desc ? ha->model_desc: "", pdev->device,
- ha->isp_ops.pci_info_str(ha, pci_info), pci_name(pdev),
+ ha->isp_ops->pci_info_str(ha, pci_info), pci_name(pdev),
ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
- ha->isp_ops.fw_version_str(ha, fw_str));
+ ha->isp_ops->fw_version_str(ha, fw_str));
return 0;
@@ -1738,7 +1855,7 @@ qla2x00_free_device(scsi_qla_host_t *ha)
/* turn-off interrupts on the card */
if (ha->interrupts_on)
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
qla2x00_mem_free(ha);
@@ -1789,7 +1906,8 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *ha, fc_port_t *fcport,
void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
int do_login, int defer)
{
- if (atomic_read(&fcport->state) == FCS_ONLINE)
+ if (atomic_read(&fcport->state) == FCS_ONLINE &&
+ ha->vp_idx == fcport->vp_idx)
qla2x00_schedule_rport_del(ha, fcport, defer);
/*
@@ -1840,19 +1958,23 @@ void
qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
{
fc_port_t *fcport;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
- list_for_each_entry(fcport, &ha->fcports, list) {
- if (fcport->port_type != FCT_TARGET)
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
continue;
-
/*
* No point in marking the device as lost, if the device is
* already DEAD.
*/
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
continue;
- if (atomic_read(&fcport->state) == FCS_ONLINE)
- qla2x00_schedule_rport_del(ha, fcport, defer);
+ if (atomic_read(&fcport->state) == FCS_ONLINE) {
+ if (defer)
+ qla2x00_schedule_rport_del(ha, fcport, defer);
+ else if (ha->vp_idx == fcport->vp_idx)
+ qla2x00_schedule_rport_del(ha, fcport, defer);
+ }
atomic_set(&fcport->state, FCS_DEVICE_LOST);
}
@@ -1868,7 +1990,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
* 0 = success.
* 1 = failure.
*/
-static uint8_t
+uint8_t
qla2x00_mem_alloc(scsi_qla_host_t *ha)
{
char name[16];
@@ -1920,33 +2042,33 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
continue;
}
- snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
- ha->host_no);
- ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
- DMA_POOL_SIZE, 8, 0);
- if (ha->s_dma_pool == NULL) {
+ /* get consistent memory allocated for init control block */
+ ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
+ ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
+ if (ha->init_cb == NULL) {
qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - s_dma_pool\n");
+ "Memory Allocation failed - init_cb\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
+ memset(ha->init_cb, 0, ha->init_cb_size);
- /* get consistent memory allocated for init control block */
- ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
- &ha->init_cb_dma);
- if (ha->init_cb == NULL) {
+ snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
+ ha->host_no);
+ ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+ DMA_POOL_SIZE, 8, 0);
+ if (ha->s_dma_pool == NULL) {
qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - init_cb\n");
+ "Memory Allocation failed - s_dma_pool\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
- memset(ha->init_cb, 0, ha->init_cb_size);
if (qla2x00_allocate_sp_pool(ha)) {
qla_printk(KERN_WARNING, ha,
@@ -2011,7 +2133,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
}
memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
/*
* Get consistent memory allocated for SFP
* block.
@@ -2052,7 +2174,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
* Input:
* ha = adapter block pointer.
*/
-static void
+void
qla2x00_mem_free(scsi_qla_host_t *ha)
{
struct list_head *fcpl, *fcptemp;
@@ -2088,12 +2210,13 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
- if (ha->init_cb)
- dma_pool_free(ha->s_dma_pool, ha->init_cb, ha->init_cb_dma);
-
if (ha->s_dma_pool)
dma_pool_destroy(ha->s_dma_pool);
+ if (ha->init_cb)
+ dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
+ ha->init_cb, ha->init_cb_dma);
+
if (ha->gid_list)
dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
ha->gid_list_dma);
@@ -2199,6 +2322,7 @@ qla2x00_free_sp_pool( scsi_qla_host_t *ha)
static int
qla2x00_do_dpc(void *data)
{
+ int rval;
scsi_qla_host_t *ha;
fc_port_t *fcport;
uint8_t status;
@@ -2289,7 +2413,7 @@ qla2x00_do_dpc(void *data)
if (fcport->flags & FCF_FABRIC_DEVICE) {
if (fcport->flags &
FCF_TAPE_PRESENT)
- ha->isp_ops.fabric_logout(
+ ha->isp_ops->fabric_logout(
ha, fcport->loop_id,
fcport->d_id.b.domain,
fcport->d_id.b.area,
@@ -2347,7 +2471,7 @@ qla2x00_do_dpc(void *data)
if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
&ha->dpc_flags))) {
- qla2x00_loop_resync(ha);
+ rval = qla2x00_loop_resync(ha);
clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
}
@@ -2369,10 +2493,12 @@ qla2x00_do_dpc(void *data)
}
if (!ha->interrupts_on)
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
- ha->isp_ops.beacon_blink(ha);
+ ha->isp_ops->beacon_blink(ha);
+
+ qla2x00_do_dpc_all_vps(ha);
ha->dpc_active = 0;
} /* End of while(1) */
@@ -2426,13 +2552,7 @@ qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp)
struct scsi_cmnd *cmd = sp->cmd;
if (sp->flags & SRB_DMA_VALID) {
- if (cmd->use_sg) {
- dma_unmap_sg(&ha->pdev->dev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen) {
- dma_unmap_single(&ha->pdev->dev, sp->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
sp->flags &= ~SRB_DMA_VALID;
}
CMD_SP(cmd) = NULL;
@@ -2458,7 +2578,7 @@ qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp)
*
* Context: Interrupt
***************************************************************************/
-static void
+void
qla2x00_timer(scsi_qla_host_t *ha)
{
unsigned long cpu_flags = 0;
@@ -2467,6 +2587,7 @@ qla2x00_timer(scsi_qla_host_t *ha)
int index;
srb_t *sp;
int t;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/*
* Ports - Port down timer.
@@ -2512,23 +2633,29 @@ qla2x00_timer(scsi_qla_host_t *ha)
atomic_set(&ha->loop_state, LOOP_DEAD);
/* Schedule an ISP abort to return any tape commands. */
- spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
- for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
- index++) {
- fc_port_t *sfcp;
-
- sp = ha->outstanding_cmds[index];
- if (!sp)
- continue;
- sfcp = sp->fcport;
- if (!(sfcp->flags & FCF_TAPE_PRESENT))
- continue;
+ /* NPIV - scan physical port only */
+ if (!ha->parent) {
+ spin_lock_irqsave(&ha->hardware_lock,
+ cpu_flags);
+ for (index = 1;
+ index < MAX_OUTSTANDING_COMMANDS;
+ index++) {
+ fc_port_t *sfcp;
+
+ sp = ha->outstanding_cmds[index];
+ if (!sp)
+ continue;
+ sfcp = sp->fcport;
+ if (!(sfcp->flags & FCF_TAPE_PRESENT))
+ continue;
- set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
- break;
+ set_bit(ISP_ABORT_NEEDED,
+ &ha->dpc_flags);
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ cpu_flags);
}
- spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags);
-
set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
start_dpc++;
}
@@ -2572,8 +2699,9 @@ qla2x00_timer(scsi_qla_host_t *ha)
test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
+ test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
- qla2xxx_wake_dpc(ha);
+ qla2xxx_wake_dpc(pha);
qla2x00_restart_timer(ha, WATCH_INTERVAL);
}
@@ -2597,18 +2725,20 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
/* Firmware interface routines. */
-#define FW_BLOBS 5
+#define FW_BLOBS 6
#define FW_ISP21XX 0
#define FW_ISP22XX 1
#define FW_ISP2300 2
#define FW_ISP2322 3
#define FW_ISP24XX 4
+#define FW_ISP25XX 5
#define FW_FILE_ISP21XX "ql2100_fw.bin"
#define FW_FILE_ISP22XX "ql2200_fw.bin"
#define FW_FILE_ISP2300 "ql2300_fw.bin"
#define FW_FILE_ISP2322 "ql2322_fw.bin"
#define FW_FILE_ISP24XX "ql2400_fw.bin"
+#define FW_FILE_ISP25XX "ql2500_fw.bin"
static DECLARE_MUTEX(qla_fw_lock);
@@ -2618,6 +2748,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
{ .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
{ .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
{ .name = FW_FILE_ISP24XX, },
+ { .name = FW_FILE_ISP25XX, },
};
struct fw_blob *
@@ -2636,6 +2767,8 @@ qla2x00_request_firmware(scsi_qla_host_t *ha)
blob = &qla_fw_blobs[FW_ISP2322];
} else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
blob = &qla_fw_blobs[FW_ISP24XX];
+ } else if (IS_QLA25XX(ha)) {
+ blob = &qla_fw_blobs[FW_ISP25XX];
}
down(&qla_fw_lock);
@@ -2679,6 +2812,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
{ 0 },
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -2703,7 +2837,7 @@ qla2x00_module_init(void)
/* Allocate cache for SRBs. */
srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (srb_cachep == NULL) {
printk(KERN_ERR
"qla2xxx: Unable to allocate SRB cache...Failing load!\n");
@@ -2717,14 +2851,24 @@ qla2x00_module_init(void)
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
- if (!qla2xxx_transport_template)
+ if (!qla2xxx_transport_template) {
+ kmem_cache_destroy(srb_cachep);
+ return -ENODEV;
+ }
+ qla2xxx_transport_vport_template =
+ fc_attach_transport(&qla2xxx_transport_vport_functions);
+ if (!qla2xxx_transport_vport_template) {
+ kmem_cache_destroy(srb_cachep);
+ fc_release_transport(qla2xxx_transport_template);
return -ENODEV;
+ }
printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
+ fc_release_transport(qla2xxx_transport_vport_template);
}
return ret;
}
@@ -2739,6 +2883,7 @@ qla2x00_module_exit(void)
qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
+ fc_release_transport(qla2xxx_transport_vport_template);
}
module_init(qla2x00_module_init);
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 206bda093da2..a925a3f179f9 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -766,6 +766,29 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
return ret;
}
+uint8_t *
+qla25xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+ uint32_t bytes)
+{
+ uint32_t i;
+ uint32_t *dwptr;
+
+ /* Dword reads to flash. */
+ dwptr = (uint32_t *)buf;
+ for (i = 0; i < bytes >> 2; i++, naddr++)
+ dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+ flash_data_to_access_addr(FA_VPD_NVRAM_ADDR | naddr)));
+
+ return buf;
+}
+
+int
+qla25xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+ uint32_t bytes)
+{
+ return qla24xx_write_flash_data(ha, (uint32_t *)buf,
+ FA_VPD_NVRAM_ADDR | naddr, bytes >> 2);
+}
static inline void
qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags)
@@ -919,7 +942,7 @@ qla2x00_beacon_off(struct scsi_qla_host *ha)
else
ha->beacon_color_state = QLA_LED_GRN_ON;
- ha->isp_ops.beacon_blink(ha); /* This turns green LED off */
+ ha->isp_ops->beacon_blink(ha); /* This turns green LED off */
ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7;
@@ -1031,7 +1054,7 @@ qla24xx_beacon_off(struct scsi_qla_host *ha)
ha->beacon_blink_led = 0;
ha->beacon_color_state = QLA_LED_ALL_ON;
- ha->isp_ops.beacon_blink(ha); /* Will flip to all off. */
+ ha->isp_ops->beacon_blink(ha); /* Will flip to all off. */
/* Give control back to firmware. */
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1419,7 +1442,7 @@ qla2x00_suspend_hba(struct scsi_qla_host *ha)
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Pause RISC. */
@@ -1705,7 +1728,7 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
{
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with read. */
@@ -1713,7 +1736,7 @@ qla24xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Resume HBA. */
clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
- ha->isp_ops.enable_intrs(ha);
+ ha->isp_ops->enable_intrs(ha);
scsi_unblock_requests(ha->host);
return buf;
@@ -1727,7 +1750,7 @@ qla24xx_write_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
/* Suspend HBA. */
scsi_block_requests(ha->host);
- ha->isp_ops.disable_intrs(ha);
+ ha->isp_ops->disable_intrs(ha);
set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
/* Go with write. */
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index c375a4efbc71..dd1f8ceb79c4 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.07-k7"
+#define QLA2XXX_VERSION "8.02.00-k2"
#define QLA_DRIVER_MAJOR_VER 8
-#define QLA_DRIVER_MINOR_VER 1
-#define QLA_DRIVER_PATCH_VER 7
+#define QLA_DRIVER_MINOR_VER 2
+#define QLA_DRIVER_PATCH_VER 0
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
index 6437d024b0dd..fcc184cd066d 100644
--- a/drivers/scsi/qla4xxx/ql4_dbg.c
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -6,176 +6,9 @@
*/
#include "ql4_def.h"
-#include <scsi/scsi_dbg.h>
-
-#if 0
-
-static void qla4xxx_print_srb_info(struct srb * srb)
-{
- printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
- printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n",
- __func__, srb->cmd, (unsigned long) srb->dma_handle);
- printk("%s: fw_ddb_index = %d, lun = %d\n",
- __func__, srb->fw_ddb_index, srb->cmd->device->lun);
- printk("%s: iocb_tov = %d\n",
- __func__, srb->iocb_tov);
- printk("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n",
- __func__, srb->cc_stat, srb->r_start, srb->u_start);
-}
-
-void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd)
-{
- printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
- printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n",
- cmd->device->channel, cmd->device->id, cmd->device->lun,
- cmd->cmd_len);
- scsi_print_command(cmd);
- printk(" seg_cnt = %d\n", cmd->use_sg);
- printk(" request buffer = 0x%p, request buffer len = 0x%x\n",
- cmd->request_buffer, cmd->request_bufflen);
- if (cmd->use_sg) {
- struct scatterlist *sg;
- sg = (struct scatterlist *)cmd->request_buffer;
- printk(" SG buffer: \n");
- qla4xxx_dump_buffer((caddr_t) sg,
- (cmd->use_sg * sizeof(*sg)));
- }
- printk(" tag = %d, transfersize = 0x%x \n", cmd->tag,
- cmd->transfersize);
- printk(" Pid = %d, SP = 0x%p\n", (int)cmd->pid, cmd->SCp.ptr);
- printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow,
- cmd->sc_data_direction);
- printk(" Current time (jiffies) = 0x%lx, "
- "timeout expires = 0x%lx\n", jiffies, cmd->eh_timeout.expires);
- qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr);
-}
-
-void __dump_registers(struct scsi_qla_host *ha)
-{
- uint8_t i;
- for (i = 0; i < MBOX_REG_COUNT; i++) {
- printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
- readw(&ha->reg->mailbox[i]));
- }
- printk(KERN_INFO "0x%02X flash_address = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, flash_address),
- readw(&ha->reg->flash_address));
- printk(KERN_INFO "0x%02X flash_data = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, flash_data),
- readw(&ha->reg->flash_data));
- printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, ctrl_status),
- readw(&ha->reg->ctrl_status));
- if (is_qla4010(ha)) {
- printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
- readw(&ha->reg->u1.isp4010.nvram));
- }
-
- else if (is_qla4022(ha) | is_qla4032(ha)) {
- printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u1.isp4022.intr_mask),
- readw(&ha->reg->u1.isp4022.intr_mask));
- printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
- readw(&ha->reg->u1.isp4022.nvram));
- printk(KERN_INFO "0x%02X semaphore = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u1.isp4022.semaphore),
- readw(&ha->reg->u1.isp4022.semaphore));
- }
- printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, req_q_in),
- readw(&ha->reg->req_q_in));
- printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, rsp_q_out),
- readw(&ha->reg->rsp_q_out));
- if (is_qla4010(ha)) {
- printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.ext_hw_conf),
- readw(&ha->reg->u2.isp4010.ext_hw_conf));
- printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.port_ctrl),
- readw(&ha->reg->u2.isp4010.port_ctrl));
- printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.port_status),
- readw(&ha->reg->u2.isp4010.port_status));
- printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.req_q_out),
- readw(&ha->reg->u2.isp4010.req_q_out));
- printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
- readw(&ha->reg->u2.isp4010.gp_out));
- printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
- readw(&ha->reg->u2.isp4010.gp_in));
- printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4010.port_err_status),
- readw(&ha->reg->u2.isp4010.port_err_status));
- }
-
- else if (is_qla4022(ha) | is_qla4032(ha)) {
- printk(KERN_INFO "Page 0 Registers:\n");
- printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.ext_hw_conf),
- readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
- printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.port_ctrl),
- readw(&ha->reg->u2.isp4022.p0.port_ctrl));
- printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.port_status),
- readw(&ha->reg->u2.isp4022.p0.port_status));
- printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.gp_out),
- readw(&ha->reg->u2.isp4022.p0.gp_out));
- printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
- readw(&ha->reg->u2.isp4022.p0.gp_in));
- printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p0.port_err_status),
- readw(&ha->reg->u2.isp4022.p0.port_err_status));
- printk(KERN_INFO "Page 1 Registers:\n");
- writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
- &ha->reg->ctrl_status);
- printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
- (uint8_t) offsetof(struct isp_reg,
- u2.isp4022.p1.req_q_out),
- readw(&ha->reg->u2.isp4022.p1.req_q_out));
- writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
- &ha->reg->ctrl_status);
- }
-}
-
-void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha)
-{
- unsigned long flags = 0;
- int i = 0;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- for (i = 1; i < MBOX_REG_COUNT; i++)
- printk(KERN_INFO " Mailbox[%d] = %08x\n", i,
- readw(&ha->reg->mailbox[i]));
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-void qla4xxx_dump_registers(struct scsi_qla_host *ha)
-{
- unsigned long flags = 0;
- spin_lock_irqsave(&ha->hardware_lock, flags);
- __dump_registers(ha);
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
void qla4xxx_dump_buffer(void *b, uint32_t size)
{
@@ -198,4 +31,3 @@ void qla4xxx_dump_buffer(void *b, uint32_t size)
printk(KERN_DEBUG "\n");
}
-#endif /* 0 */
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index 6f4cf2dd2f4a..accaf690eaf0 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -122,8 +122,7 @@
#define ISCSI_IPADDR_SIZE 4 /* IP address size */
#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */
-#define ISCSI_NAME_SIZE 255 /* ISCSI Name size -
- * usually a string */
+#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */
#define LSDW(x) ((u32)((u64)(x)))
#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
@@ -187,9 +186,21 @@ struct srb {
u_long u_start; /* Time when we handed the cmd to F/W */
};
- /*
- * Device Database (DDB) structure
- */
+/*
+ * Asynchronous Event Queue structure
+ */
+struct aen {
+ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+};
+
+struct ql4_aen_log {
+ int count;
+ struct aen entry[MAX_AEN_ENTRIES];
+};
+
+/*
+ * Device Database (DDB) structure
+ */
struct ddb_entry {
struct list_head list; /* ddb list */
struct scsi_qla_host *ha;
@@ -254,13 +265,6 @@ struct ddb_entry {
#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
#define DF_FO_MASKED 3
-/*
- * Asynchronous Event Queue structure
- */
-struct aen {
- uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
-};
-
#include "ql4_fw.h"
#include "ql4_nvram.h"
@@ -270,31 +274,31 @@ struct aen {
*/
struct scsi_qla_host {
/* Linux adapter configuration data */
- struct Scsi_Host *host; /* pointer to host data */
- uint32_t tot_ddbs;
unsigned long flags;
-#define AF_ONLINE 0 /* 0x00000001 */
-#define AF_INIT_DONE 1 /* 0x00000002 */
-#define AF_MBOX_COMMAND 2 /* 0x00000004 */
-#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
-#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */
-#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
-#define AF_LINK_UP 8 /* 0x00000100 */
-#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
-#define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */
-#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */
+#define AF_ONLINE 0 /* 0x00000001 */
+#define AF_INIT_DONE 1 /* 0x00000002 */
+#define AF_MBOX_COMMAND 2 /* 0x00000004 */
+#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
+#define AF_INTERRUPTS_ON 6 /* 0x00000040 */
+#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
+#define AF_LINK_UP 8 /* 0x00000100 */
+#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
+#define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */
unsigned long dpc_flags;
-#define DPC_RESET_HA 1 /* 0x00000002 */
-#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
-#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
-#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
-#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
-#define DPC_ISNS_RESTART 7 /* 0x00000080 */
-#define DPC_AEN 9 /* 0x00000200 */
-#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
+#define DPC_RESET_HA 1 /* 0x00000002 */
+#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
+#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
+#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
+#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
+#define DPC_ISNS_RESTART 7 /* 0x00000080 */
+#define DPC_AEN 9 /* 0x00000200 */
+#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
+
+ struct Scsi_Host *host; /* pointer to host data */
+ uint32_t tot_ddbs;
uint16_t iocb_cnt;
uint16_t iocb_hiwat;
@@ -344,6 +348,7 @@ struct scsi_qla_host {
uint32_t firmware_version[2];
uint32_t patch_number;
uint32_t build_number;
+ uint32_t board_id;
/* --- From Init_FW --- */
/* init_cb_t *init_cb; */
@@ -363,7 +368,6 @@ struct scsi_qla_host {
/* --- From GetFwState --- */
uint32_t firmware_state;
- uint32_t board_id;
uint32_t addl_fw_state;
/* Linux kernel thread */
@@ -414,6 +418,8 @@ struct scsi_qla_host {
uint16_t aen_out;
struct aen aen_q[MAX_AEN_ENTRIES];
+ struct ql4_aen_log aen_log;/* tracks all aens */
+
/* This mutex protects several threads to do mailbox commands
* concurrently.
*/
@@ -585,10 +591,4 @@ static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a)
#define FLUSH_DDB_CHANGED_AENS 1
#define RELOGIN_DDB_CHANGED_AENS 2
-#include "ql4_version.h"
-#include "ql4_glbl.h"
-#include "ql4_dbg.h"
-#include "ql4_inline.h"
-
-
#endif /*_QLA4XXX_H */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
index 4eea8c571916..9bb3d1d2a925 100644
--- a/drivers/scsi/qla4xxx/ql4_fw.h
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -20,143 +20,23 @@
*************************************************************************/
struct port_ctrl_stat_regs {
- __le32 ext_hw_conf; /* 80 x50 R/W */
- __le32 intChipConfiguration; /* 84 x54 */
- __le32 port_ctrl; /* 88 x58 */
- __le32 port_status; /* 92 x5c */
- __le32 HostPrimMACHi; /* 96 x60 */
- __le32 HostPrimMACLow; /* 100 x64 */
- __le32 HostSecMACHi; /* 104 x68 */
- __le32 HostSecMACLow; /* 108 x6c */
- __le32 EPPrimMACHi; /* 112 x70 */
- __le32 EPPrimMACLow; /* 116 x74 */
- __le32 EPSecMACHi; /* 120 x78 */
- __le32 EPSecMACLow; /* 124 x7c */
- __le32 HostPrimIPHi; /* 128 x80 */
- __le32 HostPrimIPMidHi; /* 132 x84 */
- __le32 HostPrimIPMidLow; /* 136 x88 */
- __le32 HostPrimIPLow; /* 140 x8c */
- __le32 HostSecIPHi; /* 144 x90 */
- __le32 HostSecIPMidHi; /* 148 x94 */
- __le32 HostSecIPMidLow; /* 152 x98 */
- __le32 HostSecIPLow; /* 156 x9c */
- __le32 EPPrimIPHi; /* 160 xa0 */
- __le32 EPPrimIPMidHi; /* 164 xa4 */
- __le32 EPPrimIPMidLow; /* 168 xa8 */
- __le32 EPPrimIPLow; /* 172 xac */
- __le32 EPSecIPHi; /* 176 xb0 */
- __le32 EPSecIPMidHi; /* 180 xb4 */
- __le32 EPSecIPMidLow; /* 184 xb8 */
- __le32 EPSecIPLow; /* 188 xbc */
- __le32 IPReassemblyTimeout; /* 192 xc0 */
- __le32 EthMaxFramePayload; /* 196 xc4 */
- __le32 TCPMaxWindowSize; /* 200 xc8 */
- __le32 TCPCurrentTimestampHi; /* 204 xcc */
- __le32 TCPCurrentTimestampLow; /* 208 xd0 */
- __le32 LocalRAMAddress; /* 212 xd4 */
- __le32 LocalRAMData; /* 216 xd8 */
- __le32 PCSReserved1; /* 220 xdc */
- __le32 gp_out; /* 224 xe0 */
- __le32 gp_in; /* 228 xe4 */
- __le32 ProbeMuxAddr; /* 232 xe8 */
- __le32 ProbeMuxData; /* 236 xec */
- __le32 ERMQueueBaseAddr0; /* 240 xf0 */
- __le32 ERMQueueBaseAddr1; /* 244 xf4 */
- __le32 MACConfiguration; /* 248 xf8 */
- __le32 port_err_status; /* 252 xfc COR */
+ __le32 ext_hw_conf; /* 0x50 R/W */
+ __le32 rsrvd0; /* 0x54 */
+ __le32 port_ctrl; /* 0x58 */
+ __le32 port_status; /* 0x5c */
+ __le32 rsrvd1[32]; /* 0x60-0xdf */
+ __le32 gp_out; /* 0xe0 */
+ __le32 gp_in; /* 0xe4 */
+ __le32 rsrvd2[5]; /* 0xe8-0xfb */
+ __le32 port_err_status; /* 0xfc */
};
struct host_mem_cfg_regs {
- __le32 NetRequestQueueOut; /* 80 x50 */
- __le32 NetRequestQueueOutAddrHi; /* 84 x54 */
- __le32 NetRequestQueueOutAddrLow; /* 88 x58 */
- __le32 NetRequestQueueBaseAddrHi; /* 92 x5c */
- __le32 NetRequestQueueBaseAddrLow; /* 96 x60 */
- __le32 NetRequestQueueLength; /* 100 x64 */
- __le32 NetResponseQueueIn; /* 104 x68 */
- __le32 NetResponseQueueInAddrHi; /* 108 x6c */
- __le32 NetResponseQueueInAddrLow; /* 112 x70 */
- __le32 NetResponseQueueBaseAddrHi; /* 116 x74 */
- __le32 NetResponseQueueBaseAddrLow; /* 120 x78 */
- __le32 NetResponseQueueLength; /* 124 x7c */
- __le32 req_q_out; /* 128 x80 */
- __le32 RequestQueueOutAddrHi; /* 132 x84 */
- __le32 RequestQueueOutAddrLow; /* 136 x88 */
- __le32 RequestQueueBaseAddrHi; /* 140 x8c */
- __le32 RequestQueueBaseAddrLow; /* 144 x90 */
- __le32 RequestQueueLength; /* 148 x94 */
- __le32 ResponseQueueIn; /* 152 x98 */
- __le32 ResponseQueueInAddrHi; /* 156 x9c */
- __le32 ResponseQueueInAddrLow; /* 160 xa0 */
- __le32 ResponseQueueBaseAddrHi; /* 164 xa4 */
- __le32 ResponseQueueBaseAddrLow; /* 168 xa8 */
- __le32 ResponseQueueLength; /* 172 xac */
- __le32 NetRxLargeBufferQueueOut; /* 176 xb0 */
- __le32 NetRxLargeBufferQueueBaseAddrHi; /* 180 xb4 */
- __le32 NetRxLargeBufferQueueBaseAddrLow; /* 184 xb8 */
- __le32 NetRxLargeBufferQueueLength; /* 188 xbc */
- __le32 NetRxLargeBufferLength; /* 192 xc0 */
- __le32 NetRxSmallBufferQueueOut; /* 196 xc4 */
- __le32 NetRxSmallBufferQueueBaseAddrHi; /* 200 xc8 */
- __le32 NetRxSmallBufferQueueBaseAddrLow; /* 204 xcc */
- __le32 NetRxSmallBufferQueueLength; /* 208 xd0 */
- __le32 NetRxSmallBufferLength; /* 212 xd4 */
- __le32 HMCReserved0[10]; /* 216 xd8 */
+ __le32 rsrvd0[12]; /* 0x50-0x79 */
+ __le32 req_q_out; /* 0x80 */
+ __le32 rsrvd1[31]; /* 0x84-0xFF */
};
-struct local_ram_cfg_regs {
- __le32 BufletSize; /* 80 x50 */
- __le32 BufletMaxCount; /* 84 x54 */
- __le32 BufletCurrCount; /* 88 x58 */
- __le32 BufletPauseThresholdCount; /* 92 x5c */
- __le32 BufletTCPWinThresholdHi; /* 96 x60 */
- __le32 BufletTCPWinThresholdLow; /* 100 x64 */
- __le32 IPHashTableBaseAddr; /* 104 x68 */
- __le32 IPHashTableSize; /* 108 x6c */
- __le32 TCPHashTableBaseAddr; /* 112 x70 */
- __le32 TCPHashTableSize; /* 116 x74 */
- __le32 NCBAreaBaseAddr; /* 120 x78 */
- __le32 NCBMaxCount; /* 124 x7c */
- __le32 NCBCurrCount; /* 128 x80 */
- __le32 DRBAreaBaseAddr; /* 132 x84 */
- __le32 DRBMaxCount; /* 136 x88 */
- __le32 DRBCurrCount; /* 140 x8c */
- __le32 LRCReserved[28]; /* 144 x90 */
-};
-
-struct prot_stat_regs {
- __le32 MACTxFrameCount; /* 80 x50 R */
- __le32 MACTxByteCount; /* 84 x54 R */
- __le32 MACRxFrameCount; /* 88 x58 R */
- __le32 MACRxByteCount; /* 92 x5c R */
- __le32 MACCRCErrCount; /* 96 x60 R */
- __le32 MACEncErrCount; /* 100 x64 R */
- __le32 MACRxLengthErrCount; /* 104 x68 R */
- __le32 IPTxPacketCount; /* 108 x6c R */
- __le32 IPTxByteCount; /* 112 x70 R */
- __le32 IPTxFragmentCount; /* 116 x74 R */
- __le32 IPRxPacketCount; /* 120 x78 R */
- __le32 IPRxByteCount; /* 124 x7c R */
- __le32 IPRxFragmentCount; /* 128 x80 R */
- __le32 IPDatagramReassemblyCount; /* 132 x84 R */
- __le32 IPV6RxPacketCount; /* 136 x88 R */
- __le32 IPErrPacketCount; /* 140 x8c R */
- __le32 IPReassemblyErrCount; /* 144 x90 R */
- __le32 TCPTxSegmentCount; /* 148 x94 R */
- __le32 TCPTxByteCount; /* 152 x98 R */
- __le32 TCPRxSegmentCount; /* 156 x9c R */
- __le32 TCPRxByteCount; /* 160 xa0 R */
- __le32 TCPTimerExpCount; /* 164 xa4 R */
- __le32 TCPRxAckCount; /* 168 xa8 R */
- __le32 TCPTxAckCount; /* 172 xac R */
- __le32 TCPRxErrOOOCount; /* 176 xb0 R */
- __le32 PSReserved0; /* 180 xb4 */
- __le32 TCPRxWindowProbeUpdateCount; /* 184 xb8 R */
- __le32 ECCErrCorrectionCount; /* 188 xbc R */
- __le32 PSReserved1[16]; /* 192 xc0 */
-};
-
-
/* remote register set (access via PCI memory read/write) */
struct isp_reg {
#define MBOX_REG_COUNT 8
@@ -207,11 +87,7 @@ struct isp_reg {
union {
struct port_ctrl_stat_regs p0;
struct host_mem_cfg_regs p1;
- struct local_ram_cfg_regs p2;
- struct prot_stat_regs p3;
- __le32 r_union[44];
};
-
} __attribute__ ((packed)) isp4022;
} u2;
}; /* 256 x100 */
@@ -296,6 +172,7 @@ static inline uint32_t clr_rmask(uint32_t val)
/* ISP Semaphore definitions */
/* ISP General Purpose Output definitions */
+#define GPOR_TOPCAT_RESET 0x00000004
/* shadow registers (DMA'd from HA to system memory. read only) */
struct shadow_regs {
@@ -337,6 +214,7 @@ union external_hw_config_reg {
/* Mailbox command definitions */
#define MBOX_CMD_ABOUT_FW 0x0009
+#define MBOX_CMD_PING 0x000B
#define MBOX_CMD_LUN_RESET 0x0016
#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E
#define MBOX_CMD_GET_FW_STATUS 0x001F
@@ -364,6 +242,17 @@ union external_hw_config_reg {
#define MBOX_CMD_GET_FW_STATE 0x0069
#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A
#define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087
+#define MBOX_CMD_SET_ACB 0x0088
+#define MBOX_CMD_GET_ACB 0x0089
+#define MBOX_CMD_DISABLE_ACB 0x008A
+#define MBOX_CMD_GET_IPV6_NEIGHBOR_CACHE 0x008B
+#define MBOX_CMD_GET_IPV6_DEST_CACHE 0x008C
+#define MBOX_CMD_GET_IPV6_DEF_ROUTER_LIST 0x008D
+#define MBOX_CMD_GET_IPV6_LCL_PREFIX_LIST 0x008E
+#define MBOX_CMD_SET_IPV6_NEIGHBOR_CACHE 0x0090
+#define MBOX_CMD_GET_IP_ADDR_STATE 0x0091
+#define MBOX_CMD_SEND_IPV6_ROUTER_SOL 0x0092
+#define MBOX_CMD_GET_DB_ENTRY_CURRENT_IP_ADDR 0x0093
/* Mailbox 1 */
#define FW_STATE_READY 0x0000
@@ -409,6 +298,16 @@ union external_hw_config_reg {
#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D
#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F
#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021
+#define MBOX_ASTS_DUPLICATE_IP 0x8025
+#define MBOX_ASTS_ARP_COMPLETE 0x8026
+#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
+#define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028
+#define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029
+#define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B
+#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C
+#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D
+#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E
+
#define ISNS_EVENT_DATA_RECEIVED 0x0000
#define ISNS_EVENT_CONNECTION_OPENED 0x0001
#define ISNS_EVENT_CONNECTION_FAILED 0x0002
@@ -418,137 +317,166 @@ union external_hw_config_reg {
/*************************************************************************/
/* Host Adapter Initialization Control Block (from host) */
-struct init_fw_ctrl_blk {
- uint8_t Version; /* 00 */
- uint8_t Control; /* 01 */
+struct addr_ctrl_blk {
+ uint8_t version; /* 00 */
+ uint8_t control; /* 01 */
- uint16_t FwOptions; /* 02-03 */
+ uint16_t fw_options; /* 02-03 */
#define FWOPT_HEARTBEAT_ENABLE 0x1000
#define FWOPT_SESSION_MODE 0x0040
#define FWOPT_INITIATOR_MODE 0x0020
#define FWOPT_TARGET_MODE 0x0010
- uint16_t ExecThrottle; /* 04-05 */
- uint8_t RetryCount; /* 06 */
- uint8_t RetryDelay; /* 07 */
- uint16_t MaxEthFrPayloadSize; /* 08-09 */
- uint16_t AddFwOptions; /* 0A-0B */
-
- uint8_t HeartbeatInterval; /* 0C */
- uint8_t InstanceNumber; /* 0D */
- uint16_t RES2; /* 0E-0F */
- uint16_t ReqQConsumerIndex; /* 10-11 */
- uint16_t ComplQProducerIndex; /* 12-13 */
- uint16_t ReqQLen; /* 14-15 */
- uint16_t ComplQLen; /* 16-17 */
- uint32_t ReqQAddrLo; /* 18-1B */
- uint32_t ReqQAddrHi; /* 1C-1F */
- uint32_t ComplQAddrLo; /* 20-23 */
- uint32_t ComplQAddrHi; /* 24-27 */
- uint32_t ShadowRegBufAddrLo; /* 28-2B */
- uint32_t ShadowRegBufAddrHi; /* 2C-2F */
-
- uint16_t iSCSIOptions; /* 30-31 */
-
- uint16_t TCPOptions; /* 32-33 */
-
- uint16_t IPOptions; /* 34-35 */
-
- uint16_t MaxPDUSize; /* 36-37 */
- uint16_t RcvMarkerInt; /* 38-39 */
- uint16_t SndMarkerInt; /* 3A-3B */
- uint16_t InitMarkerlessInt; /* 3C-3D */
- uint16_t FirstBurstSize; /* 3E-3F */
- uint16_t DefaultTime2Wait; /* 40-41 */
- uint16_t DefaultTime2Retain; /* 42-43 */
- uint16_t MaxOutStndngR2T; /* 44-45 */
- uint16_t KeepAliveTimeout; /* 46-47 */
- uint16_t PortNumber; /* 48-49 */
- uint16_t MaxBurstSize; /* 4A-4B */
- uint32_t RES4; /* 4C-4F */
- uint8_t IPAddr[4]; /* 50-53 */
- uint8_t RES5[12]; /* 54-5F */
- uint8_t SubnetMask[4]; /* 60-63 */
- uint8_t RES6[12]; /* 64-6F */
- uint8_t GatewayIPAddr[4]; /* 70-73 */
- uint8_t RES7[12]; /* 74-7F */
- uint8_t PriDNSIPAddr[4]; /* 80-83 */
- uint8_t SecDNSIPAddr[4]; /* 84-87 */
- uint8_t RES8[8]; /* 88-8F */
- uint8_t Alias[32]; /* 90-AF */
- uint8_t TargAddr[8]; /* B0-B7 *//* /FIXME: Remove?? */
- uint8_t CHAPNameSecretsTable[8]; /* B8-BF */
- uint8_t EthernetMACAddr[6]; /* C0-C5 */
- uint16_t TargetPortalGroup; /* C6-C7 */
- uint8_t SendScale; /* C8 */
- uint8_t RecvScale; /* C9 */
- uint8_t TypeOfService; /* CA */
- uint8_t Time2Live; /* CB */
- uint16_t VLANPriority; /* CC-CD */
- uint16_t Reserved8; /* CE-CF */
- uint8_t SecIPAddr[4]; /* D0-D3 */
- uint8_t Reserved9[12]; /* D4-DF */
- uint8_t iSNSIPAddr[4]; /* E0-E3 */
- uint16_t iSNSServerPortNumber; /* E4-E5 */
- uint8_t Reserved10[10]; /* E6-EF */
- uint8_t SLPDAIPAddr[4]; /* F0-F3 */
- uint8_t Reserved11[12]; /* F4-FF */
- uint8_t iSCSINameString[256]; /* 100-1FF */
+ uint16_t exec_throttle; /* 04-05 */
+ uint8_t zio_count; /* 06 */
+ uint8_t res0; /* 07 */
+ uint16_t eth_mtu_size; /* 08-09 */
+ uint16_t add_fw_options; /* 0A-0B */
+
+ uint8_t hb_interval; /* 0C */
+ uint8_t inst_num; /* 0D */
+ uint16_t res1; /* 0E-0F */
+ uint16_t rqq_consumer_idx; /* 10-11 */
+ uint16_t compq_producer_idx; /* 12-13 */
+ uint16_t rqq_len; /* 14-15 */
+ uint16_t compq_len; /* 16-17 */
+ uint32_t rqq_addr_lo; /* 18-1B */
+ uint32_t rqq_addr_hi; /* 1C-1F */
+ uint32_t compq_addr_lo; /* 20-23 */
+ uint32_t compq_addr_hi; /* 24-27 */
+ uint32_t shdwreg_addr_lo; /* 28-2B */
+ uint32_t shdwreg_addr_hi; /* 2C-2F */
+
+ uint16_t iscsi_opts; /* 30-31 */
+ uint16_t ipv4_tcp_opts; /* 32-33 */
+ uint16_t ipv4_ip_opts; /* 34-35 */
+
+ uint16_t iscsi_max_pdu_size; /* 36-37 */
+ uint8_t ipv4_tos; /* 38 */
+ uint8_t ipv4_ttl; /* 39 */
+ uint8_t acb_version; /* 3A */
+ uint8_t res2; /* 3B */
+ uint16_t def_timeout; /* 3C-3D */
+ uint16_t iscsi_fburst_len; /* 3E-3F */
+ uint16_t iscsi_def_time2wait; /* 40-41 */
+ uint16_t iscsi_def_time2retain; /* 42-43 */
+ uint16_t iscsi_max_outstnd_r2t; /* 44-45 */
+ uint16_t conn_ka_timeout; /* 46-47 */
+ uint16_t ipv4_port; /* 48-49 */
+ uint16_t iscsi_max_burst_len; /* 4A-4B */
+ uint32_t res5; /* 4C-4F */
+ uint8_t ipv4_addr[4]; /* 50-53 */
+ uint16_t ipv4_vlan_tag; /* 54-55 */
+ uint8_t ipv4_addr_state; /* 56 */
+ uint8_t ipv4_cacheid; /* 57 */
+ uint8_t res6[8]; /* 58-5F */
+ uint8_t ipv4_subnet[4]; /* 60-63 */
+ uint8_t res7[12]; /* 64-6F */
+ uint8_t ipv4_gw_addr[4]; /* 70-73 */
+ uint8_t res8[0xc]; /* 74-7F */
+ uint8_t pri_dns_srvr_ip[4];/* 80-83 */
+ uint8_t sec_dns_srvr_ip[4];/* 84-87 */
+ uint16_t min_eph_port; /* 88-89 */
+ uint16_t max_eph_port; /* 8A-8B */
+ uint8_t res9[4]; /* 8C-8F */
+ uint8_t iscsi_alias[32];/* 90-AF */
+ uint8_t res9_1[0x16]; /* B0-C5 */
+ uint16_t tgt_portal_grp;/* C6-C7 */
+ uint8_t abort_timer; /* C8 */
+ uint8_t ipv4_tcp_wsf; /* C9 */
+ uint8_t res10[6]; /* CA-CF */
+ uint8_t ipv4_sec_ip_addr[4]; /* D0-D3 */
+ uint8_t ipv4_dhcp_vid_len; /* D4 */
+ uint8_t ipv4_dhcp_vid[11]; /* D5-DF */
+ uint8_t res11[20]; /* E0-F3 */
+ uint8_t ipv4_dhcp_alt_cid_len; /* F4 */
+ uint8_t ipv4_dhcp_alt_cid[11]; /* F5-FF */
+ uint8_t iscsi_name[224]; /* 100-1DF */
+ uint8_t res12[32]; /* 1E0-1FF */
+ uint32_t cookie; /* 200-203 */
+ uint16_t ipv6_port; /* 204-205 */
+ uint16_t ipv6_opts; /* 206-207 */
+ uint16_t ipv6_addtl_opts; /* 208-209 */
+ uint16_t ipv6_tcp_opts; /* 20A-20B */
+ uint8_t ipv6_tcp_wsf; /* 20C */
+ uint16_t ipv6_flow_lbl; /* 20D-20F */
+ uint8_t ipv6_gw_addr[16]; /* 210-21F */
+ uint16_t ipv6_vlan_tag; /* 220-221 */
+ uint8_t ipv6_lnk_lcl_addr_state;/* 222 */
+ uint8_t ipv6_addr0_state; /* 223 */
+ uint8_t ipv6_addr1_state; /* 224 */
+ uint8_t ipv6_gw_state; /* 225 */
+ uint8_t ipv6_traffic_class; /* 226 */
+ uint8_t ipv6_hop_limit; /* 227 */
+ uint8_t ipv6_if_id[8]; /* 228-22F */
+ uint8_t ipv6_addr0[16]; /* 230-23F */
+ uint8_t ipv6_addr1[16]; /* 240-24F */
+ uint32_t ipv6_nd_reach_time; /* 250-253 */
+ uint32_t ipv6_nd_rexmit_timer; /* 254-257 */
+ uint32_t ipv6_nd_stale_timeout; /* 258-25B */
+ uint8_t ipv6_dup_addr_detect_count; /* 25C */
+ uint8_t ipv6_cache_id; /* 25D */
+ uint8_t res13[18]; /* 25E-26F */
+ uint32_t ipv6_gw_advrt_mtu; /* 270-273 */
+ uint8_t res14[140]; /* 274-2FF */
+};
+
+struct init_fw_ctrl_blk {
+ struct addr_ctrl_blk pri;
+ struct addr_ctrl_blk sec;
};
/*************************************************************************/
struct dev_db_entry {
- uint8_t options; /* 00 */
+ uint16_t options; /* 00-01 */
#define DDB_OPT_DISC_SESSION 0x10
#define DDB_OPT_TARGET 0x02 /* device is a target */
- uint8_t control; /* 01 */
-
- uint16_t exeThrottle; /* 02-03 */
- uint16_t exeCount; /* 04-05 */
- uint8_t retryCount; /* 06 */
- uint8_t retryDelay; /* 07 */
- uint16_t iSCSIOptions; /* 08-09 */
-
- uint16_t TCPOptions; /* 0A-0B */
-
- uint16_t IPOptions; /* 0C-0D */
-
- uint16_t maxPDUSize; /* 0E-0F */
- uint16_t rcvMarkerInt; /* 10-11 */
- uint16_t sndMarkerInt; /* 12-13 */
- uint16_t iSCSIMaxSndDataSegLen; /* 14-15 */
- uint16_t firstBurstSize; /* 16-17 */
- uint16_t minTime2Wait; /* 18-19 : RA :default_time2wait */
- uint16_t maxTime2Retain; /* 1A-1B */
- uint16_t maxOutstndngR2T; /* 1C-1D */
- uint16_t keepAliveTimeout; /* 1E-1F */
- uint8_t ISID[6]; /* 20-25 big-endian, must be converted
+ uint16_t exec_throttle; /* 02-03 */
+ uint16_t exec_count; /* 04-05 */
+ uint16_t res0; /* 06-07 */
+ uint16_t iscsi_options; /* 08-09 */
+ uint16_t tcp_options; /* 0A-0B */
+ uint16_t ip_options; /* 0C-0D */
+ uint16_t iscsi_max_rcv_data_seg_len; /* 0E-0F */
+ uint32_t res1; /* 10-13 */
+ uint16_t iscsi_max_snd_data_seg_len; /* 14-15 */
+ uint16_t iscsi_first_burst_len; /* 16-17 */
+ uint16_t iscsi_def_time2wait; /* 18-19 */
+ uint16_t iscsi_def_time2retain; /* 1A-1B */
+ uint16_t iscsi_max_outsnd_r2t; /* 1C-1D */
+ uint16_t ka_timeout; /* 1E-1F */
+ uint8_t isid[6]; /* 20-25 big-endian, must be converted
* to little-endian */
- uint16_t TSID; /* 26-27 */
- uint16_t portNumber; /* 28-29 */
- uint16_t maxBurstSize; /* 2A-2B */
- uint16_t taskMngmntTimeout; /* 2C-2D */
- uint16_t reserved1; /* 2E-2F */
- uint8_t ipAddr[0x10]; /* 30-3F */
- uint8_t iSCSIAlias[0x20]; /* 40-5F */
- uint8_t targetAddr[0x20]; /* 60-7F */
- uint8_t userID[0x20]; /* 80-9F */
- uint8_t password[0x20]; /* A0-BF */
- uint8_t iscsiName[0x100]; /* C0-1BF : xxzzy Make this a
+ uint16_t tsid; /* 26-27 */
+ uint16_t port; /* 28-29 */
+ uint16_t iscsi_max_burst_len; /* 2A-2B */
+ uint16_t def_timeout; /* 2C-2D */
+ uint16_t res2; /* 2E-2F */
+ uint8_t ip_addr[0x10]; /* 30-3F */
+ uint8_t iscsi_alias[0x20]; /* 40-5F */
+ uint8_t tgt_addr[0x20]; /* 60-7F */
+ uint16_t mss; /* 80-81 */
+ uint16_t res3; /* 82-83 */
+ uint16_t lcl_port; /* 84-85 */
+ uint8_t ipv4_tos; /* 86 */
+ uint16_t ipv6_flow_lbl; /* 87-89 */
+ uint8_t res4[0x36]; /* 8A-BF */
+ uint8_t iscsi_name[0xE0]; /* C0-19F : xxzzy Make this a
* pointer to a string so we
* don't have to reserve soooo
* much RAM */
- uint16_t ddbLink; /* 1C0-1C1 */
- uint16_t CHAPTableIndex; /* 1C2-1C3 */
- uint16_t TargetPortalGroup; /* 1C4-1C5 */
- uint16_t reserved2[2]; /* 1C6-1C7 */
- uint32_t statSN; /* 1C8-1CB */
- uint32_t expStatSN; /* 1CC-1CF */
- uint16_t reserved3[0x2C]; /* 1D0-1FB */
- uint16_t ddbValidCookie; /* 1FC-1FD */
- uint16_t ddbValidSize; /* 1FE-1FF */
+ uint8_t ipv6_addr[0x10];/* 1A0-1AF */
+ uint8_t res5[0x10]; /* 1B0-1BF */
+ uint16_t ddb_link; /* 1C0-1C1 */
+ uint16_t chap_tbl_idx; /* 1C2-1C3 */
+ uint16_t tgt_portal_grp; /* 1C4-1C5 */
+ uint8_t tcp_xmt_wsf; /* 1C6 */
+ uint8_t tcp_rcv_wsf; /* 1C7 */
+ uint32_t stat_sn; /* 1C8-1CB */
+ uint32_t exp_stat_sn; /* 1CC-1CF */
+ uint8_t res6[0x30]; /* 1D0-1FF */
};
/*************************************************************************/
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 5b00cb04e7c0..a3608e028bf6 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -8,6 +8,9 @@
#ifndef __QLA4x_GBL_H
#define __QLA4x_GBL_H
+struct iscsi_cls_conn;
+
+void qla4xxx_hw_reset(struct scsi_qla_host *ha);
int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a);
int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
@@ -58,11 +61,13 @@ int qla4xxx_get_fw_version(struct scsi_qla_host * ha);
void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
uint32_t intr_status);
int qla4xxx_init_rings(struct scsi_qla_host * ha);
-struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index);
+struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
+ uint32_t index);
void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
uint32_t fw_ddb_index, uint32_t state);
+void qla4xxx_dump_buffer(void *b, uint32_t size);
extern int ql4xextended_error_logging;
extern int ql4xdiscoverywait;
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
index 6365df268612..1e29f51d596b 100644
--- a/drivers/scsi/qla4xxx/ql4_init.c
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
uint32_t fw_ddb_index);
@@ -300,12 +303,12 @@ static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
if (!qla4xxx_fw_ready(ha))
return status;
- set_bit(AF_ONLINE, &ha->flags);
return qla4xxx_get_firmware_status(ha);
}
static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
- uint32_t fw_ddb_index)
+ uint32_t fw_ddb_index,
+ uint32_t *new_tgt)
{
struct dev_db_entry *fw_ddb_entry = NULL;
dma_addr_t fw_ddb_entry_dma;
@@ -313,6 +316,7 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
int found = 0;
uint32_t device_state;
+ *new_tgt = 0;
/* Make sure the dma buffer is valid */
fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
sizeof(*fw_ddb_entry),
@@ -337,7 +341,7 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no,
__func__, fw_ddb_index));
list_for_each_entry(ddb_entry, &ha->ddb_list, list) {
- if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsiName,
+ if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsi_name,
ISCSI_NAME_SIZE) == 0) {
found++;
break;
@@ -348,6 +352,7 @@ static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
"new ddb\n", ha->host_no, __func__,
fw_ddb_index));
+ *new_tgt = 1;
ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
}
@@ -409,26 +414,26 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
}
status = QLA_SUCCESS;
- ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->TSID);
+ ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->tsid);
ddb_entry->task_mgmt_timeout =
- le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
+ le16_to_cpu(fw_ddb_entry->def_timeout);
ddb_entry->CmdSn = 0;
- ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exeThrottle);
+ ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exec_throttle);
ddb_entry->default_relogin_timeout =
- le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
- ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->minTime2Wait);
+ le16_to_cpu(fw_ddb_entry->def_timeout);
+ ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait);
/* Update index in case it changed */
ddb_entry->fw_ddb_index = fw_ddb_index;
ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
- ddb_entry->port = le16_to_cpu(fw_ddb_entry->portNumber);
- ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->TargetPortalGroup);
- memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsiName[0],
+ ddb_entry->port = le16_to_cpu(fw_ddb_entry->port);
+ ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp);
+ memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsi_name[0],
min(sizeof(ddb_entry->iscsi_name),
- sizeof(fw_ddb_entry->iscsiName)));
- memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ipAddr[0],
- min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ipAddr)));
+ sizeof(fw_ddb_entry->iscsi_name)));
+ memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ip_addr[0],
+ min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ip_addr)));
DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
ha->host_no, __func__, fw_ddb_index,
@@ -495,6 +500,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
uint32_t ddb_state;
uint32_t conn_err, err_code;
struct ddb_entry *ddb_entry;
+ uint32_t new_tgt;
dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
@@ -526,8 +532,19 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
"completed "
"or access denied failure\n",
ha->host_no, __func__));
- } else
+ } else {
qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index,
+ NULL, 0, NULL, &next_fw_ddb_index,
+ &ddb_state, &conn_err, NULL, NULL)
+ == QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s:"
+ "get_ddb_entry %d failed\n",
+ ha->host_no,
+ __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+ }
}
if (ddb_state != DDB_DS_SESSION_ACTIVE)
@@ -540,7 +557,7 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
ha->host_no, __func__, fw_ddb_index));
/* Add DDB to internal our ddb list. */
- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
if (ddb_entry == NULL) {
DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
"for device at fw_ddb_index %d\n",
@@ -865,21 +882,20 @@ static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
static void qla4x00_pci_config(struct scsi_qla_host *ha)
{
- uint16_t w, mwi;
+ uint16_t w;
+ int status;
dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
pci_set_master(ha->pdev);
- mwi = 0;
- if (pci_set_mwi(ha->pdev))
- mwi = PCI_COMMAND_INVALIDATE;
+ status = pci_set_mwi(ha->pdev);
/*
* We want to respect framework's setting of PCI configuration space
* command register and also want to make sure that all bits of
* interest to us are properly set in command register.
*/
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
- w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
w &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
}
@@ -911,6 +927,9 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
writel(set_rmask(NVR_WRITE_ENABLE),
&ha->reg->u1.isp4022.nvram);
+ writel(2, &ha->reg->mailbox[6]);
+ readl(&ha->reg->mailbox[6]);
+
writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status);
readl(&ha->reg->ctrl_status);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -958,25 +977,25 @@ static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
return status;
}
-int ql4xxx_lock_drvr_wait(struct scsi_qla_host *ha)
+int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
{
-#define QL4_LOCK_DRVR_WAIT 30
+#define QL4_LOCK_DRVR_WAIT 60
#define QL4_LOCK_DRVR_SLEEP 1
int drvr_wait = QL4_LOCK_DRVR_WAIT;
while (drvr_wait) {
- if (ql4xxx_lock_drvr(ha) == 0) {
+ if (ql4xxx_lock_drvr(a) == 0) {
ssleep(QL4_LOCK_DRVR_SLEEP);
if (drvr_wait) {
DEBUG2(printk("scsi%ld: %s: Waiting for "
- "Global Init Semaphore(%d)...n",
- ha->host_no,
+ "Global Init Semaphore(%d)...\n",
+ a->host_no,
__func__, drvr_wait));
}
drvr_wait -= QL4_LOCK_DRVR_SLEEP;
} else {
DEBUG2(printk("scsi%ld: %s: Global Init Semaphore "
- "acquired.n", ha->host_no, __func__));
+ "acquired\n", a->host_no, __func__));
return QLA_SUCCESS;
}
}
@@ -1125,17 +1144,17 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
/* Initialize the Host adapter request/response queues and firmware */
if (qla4xxx_start_firmware(ha) == QLA_ERROR)
- return status;
+ goto exit_init_hba;
if (qla4xxx_validate_mac_address(ha) == QLA_ERROR)
- return status;
+ goto exit_init_hba;
if (qla4xxx_init_local_data(ha) == QLA_ERROR)
- return status;
+ goto exit_init_hba;
status = qla4xxx_init_firmware(ha);
if (status == QLA_ERROR)
- return status;
+ goto exit_init_hba;
/*
* FW is waiting to get an IP address from DHCP server: Skip building
@@ -1143,12 +1162,12 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
* followed by 0x8014 aen" to trigger the tgt discovery process.
*/
if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)
- return status;
+ goto exit_init_online;
/* Skip device discovery if ip and subnet is zero */
if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 ||
memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0)
- return status;
+ goto exit_init_online;
if (renew_ddb_list == PRESERVE_DDB_LIST) {
/*
@@ -1177,9 +1196,10 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
ha->host_no));
}
- exit_init_hba:
+exit_init_online:
+ set_bit(AF_ONLINE, &ha->flags);
+exit_init_hba:
return status;
-
}
/**
@@ -1193,9 +1213,10 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
uint32_t fw_ddb_index)
{
struct ddb_entry * ddb_entry;
+ uint32_t new_tgt;
/* First allocate a device structure */
- ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index, &new_tgt);
if (ddb_entry == NULL) {
DEBUG2(printk(KERN_WARNING
"scsi%ld: Unable to allocate memory to add "
@@ -1203,6 +1224,18 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
return;
}
+ if (!new_tgt && (ddb_entry->fw_ddb_index != fw_ddb_index)) {
+ /* Target has been bound to a new fw_ddb_index */
+ qla4xxx_free_ddb(ha, ddb_entry);
+ ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: Unable to allocate memory"
+ " to add fw_ddb_index %d\n",
+ ha->host_no, fw_ddb_index));
+ return;
+ }
+ }
if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
QLA_ERROR) {
ha->fw_ddb_index_map[fw_ddb_index] =
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index a216a1781afb..5006ecb3ef5e 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -6,6 +6,10 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
+
#include <scsi/scsi_tcq.h>
@@ -141,11 +145,13 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb,
uint16_t avail_dsds;
struct data_seg_a64 *cur_dsd;
struct scsi_cmnd *cmd;
+ struct scatterlist *sg;
+ int i;
cmd = srb->cmd;
ha = srb->ha;
- if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) {
/* No data being transferred */
cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0);
return;
@@ -154,40 +160,27 @@ static void qla4xxx_build_scsi_iocbs(struct srb *srb,
avail_dsds = COMMAND_SEG;
cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
- /* Load data segments */
- if (cmd->use_sg) {
- struct scatterlist *cur_seg;
- struct scatterlist *end_seg;
-
- cur_seg = (struct scatterlist *)cmd->request_buffer;
- end_seg = cur_seg + tot_dsds;
- while (cur_seg < end_seg) {
- dma_addr_t sle_dma;
-
- /* Allocate additional continuation packets? */
- if (avail_dsds == 0) {
- struct continuation_t1_entry *cont_entry;
-
- cont_entry = qla4xxx_alloc_cont_entry(ha);
- cur_dsd =
- (struct data_seg_a64 *)
- &cont_entry->dataseg[0];
- avail_dsds = CONTINUE_SEG;
- }
-
- sle_dma = sg_dma_address(cur_seg);
- cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
- cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
- cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg));
- avail_dsds--;
-
- cur_dsd++;
- cur_seg++;
+ scsi_for_each_sg(cmd, sg, tot_dsds, i) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ struct continuation_t1_entry *cont_entry;
+
+ cont_entry = qla4xxx_alloc_cont_entry(ha);
+ cur_dsd =
+ (struct data_seg_a64 *)
+ &cont_entry->dataseg[0];
+ avail_dsds = CONTINUE_SEG;
}
- } else {
- cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle));
- cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle));
- cur_dsd->count = cpu_to_le32(cmd->request_bufflen);
+
+ sle_dma = sg_dma_address(sg);
+ cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
+ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
+ cur_dsd->count = cpu_to_le32(sg_dma_len(sg));
+ avail_dsds--;
+
+ cur_dsd++;
}
}
@@ -204,8 +197,8 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
struct scsi_cmnd *cmd = srb->cmd;
struct ddb_entry *ddb_entry;
struct command_t3_entry *cmd_entry;
- struct scatterlist *sg = NULL;
+ int nseg;
uint16_t tot_dsds;
uint16_t req_cnt;
@@ -233,24 +226,11 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
index = (uint32_t)cmd->request->tag;
/* Calculate the number of request entries needed. */
- if (cmd->use_sg) {
- sg = (struct scatterlist *)cmd->request_buffer;
- tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- if (tot_dsds == 0)
- goto queuing_error;
- } else if (cmd->request_bufflen) {
- dma_addr_t req_dma;
-
- req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- if (dma_mapping_error(req_dma))
- goto queuing_error;
-
- srb->dma_handle = req_dma;
- tot_dsds = 1;
- }
+ nseg = scsi_dma_map(cmd);
+ if (nseg < 0)
+ goto queuing_error;
+ tot_dsds = nseg;
+
req_cnt = qla4xxx_calc_request_entries(tot_dsds);
if (ha->req_q_count < (req_cnt + 2)) {
@@ -279,7 +259,7 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
int_to_scsilun(cmd->device->lun, &cmd_entry->lun);
cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn);
- cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen);
+ cmd_entry->ttlByteCnt = cpu_to_le32(scsi_bufflen(cmd));
memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len);
cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds);
cmd_entry->hdr.entryCount = req_cnt;
@@ -289,13 +269,13 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
* transferred, as the data direction bit is sometimed filled
* in when there is no data to be transferred */
cmd_entry->control_flags = CF_NO_DATA;
- if (cmd->request_bufflen) {
+ if (scsi_bufflen(cmd)) {
if (cmd->sc_data_direction == DMA_TO_DEVICE)
cmd_entry->control_flags = CF_WRITE;
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
cmd_entry->control_flags = CF_READ;
- ha->bytes_xfered += cmd->request_bufflen;
+ ha->bytes_xfered += scsi_bufflen(cmd);
if (ha->bytes_xfered & ~0xFFFFF){
ha->total_mbytes_xferred += ha->bytes_xfered >> 20;
ha->bytes_xfered &= 0xFFFFF;
@@ -359,14 +339,9 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
return QLA_SUCCESS;
queuing_error:
+ if (tot_dsds)
+ scsi_dma_unmap(cmd);
- if (cmd->use_sg && tot_dsds) {
- sg = (struct scatterlist *) cmd->request_buffer;
- pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
- cmd->sc_data_direction);
- } else if (tot_dsds)
- pci_unmap_single(ha->pdev, srb->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return QLA_ERROR;
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
index 35b9e36a0e8d..4a154beb0d39 100644
--- a/drivers/scsi/qla4xxx/ql4_isr.c
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
/**
* qla2x00_process_completed_request() - Process a Fast Post response.
@@ -90,9 +93,29 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
break;
}
- if (sts_entry->iscsiFlags &
- (ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER))
- cmd->resid = residual;
+ if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+ cmd->result = DID_ERROR << 16;
+ break;
+ }
+
+ if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) {
+ scsi_set_resid(cmd, residual);
+ if (!scsi_status && ((scsi_bufflen(cmd) - residual) <
+ cmd->underflow)) {
+
+ cmd->result = DID_ERROR << 16;
+
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
+ "Mid-layer Data underrun0, "
+ "xferlen = 0x%x, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ scsi_bufflen(cmd), residual));
+ break;
+ }
+ }
cmd->result = DID_OK << 16 | scsi_status;
@@ -161,7 +184,8 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
case SCS_DATA_UNDERRUN:
case SCS_DATA_OVERRUN:
- if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+ if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) ||
+ (sts_entry->completionStatus == SCS_DATA_OVERRUN)) {
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
"residual = 0x%x\n", ha->host_no,
cmd->device->channel, cmd->device->id,
@@ -171,21 +195,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
break;
}
- if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
- /*
- * Firmware detected a SCSI transport underrun
- * condition
- */
- cmd->resid = residual;
- DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status "
- "detected, xferlen = 0x%x, residual = "
- "0x%x\n",
- ha->host_no, cmd->device->channel,
- cmd->device->id,
- cmd->device->lun, __func__,
- cmd->request_bufflen,
- residual));
- }
+ scsi_set_resid(cmd, residual);
/*
* If there is scsi_status, it takes precedense over
@@ -227,7 +237,7 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
if ((sts_entry->iscsiFlags &
ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
cmd->result = DID_BUS_BUSY << 16;
- } else if ((cmd->request_bufflen - residual) <
+ } else if ((scsi_bufflen(cmd) - residual) <
cmd->underflow) {
/*
* Handle mid-layer underflow???
@@ -242,13 +252,13 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,
* will return DID_ERROR.
*/
DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
- "Mid-layer Data underrun, "
- "xferlen = 0x%x, "
- "residual = 0x%x\n", ha->host_no,
- cmd->device->channel,
- cmd->device->id,
- cmd->device->lun, __func__,
- cmd->request_bufflen, residual));
+ "Mid-layer Data underrun1, "
+ "xferlen = 0x%x, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ scsi_bufflen(cmd), residual));
cmd->result = DID_ERROR << 16;
} else {
@@ -417,6 +427,7 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
uint32_t mbox_status)
{
int i;
+ uint32_t mbox_stat2, mbox_stat3;
if ((mbox_status == MBOX_STS_BUSY) ||
(mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
@@ -437,6 +448,12 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
/* Immediately process the AENs that don't require much work.
* Only queue the database_changed AENs */
+ if (ha->aen_log.count < MAX_AEN_ENTRIES) {
+ for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+ ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] =
+ readl(&ha->reg->mailbox[i]);
+ ha->aen_log.count++;
+ }
switch (mbox_status) {
case MBOX_ASTS_SYSTEM_ERROR:
/* Log Mailbox registers */
@@ -493,6 +510,16 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
mbox_status));
break;
+ case MBOX_ASTS_IP_ADDR_STATE_CHANGED:
+ mbox_stat2 = readl(&ha->reg->mailbox[2]);
+ mbox_stat3 = readl(&ha->reg->mailbox[3]);
+
+ if ((mbox_stat3 == 5) && (mbox_stat2 == 3))
+ set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
+ else if ((mbox_stat3 == 2) && (mbox_stat2 == 5))
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ break;
+
case MBOX_ASTS_MAC_ADDRESS_CHANGED:
case MBOX_ASTS_DNS:
/* No action */
@@ -518,11 +545,6 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
/* Queue AEN information and process it in the DPC
* routine */
if (ha->aen_q_count > 0) {
- /* advance pointer */
- if (ha->aen_in == (MAX_AEN_ENTRIES - 1))
- ha->aen_in = 0;
- else
- ha->aen_in++;
/* decrement available counter */
ha->aen_q_count--;
@@ -542,6 +564,10 @@ static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
ha->aen_q[ha->aen_in].mbox_sts[2],
ha->aen_q[ha->aen_in].mbox_sts[3],
ha->aen_q[ha->aen_in]. mbox_sts[4]));
+ /* advance pointer */
+ ha->aen_in++;
+ if (ha->aen_in == MAX_AEN_ENTRIES)
+ ha->aen_in = 0;
/* The DPC routine will process the aen */
set_bit(DPC_AEN, &ha->dpc_flags);
@@ -724,25 +750,24 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
spin_lock_irqsave(&ha->hardware_lock, flags);
while (ha->aen_out != ha->aen_in) {
- /* Advance pointers for next entry */
- if (ha->aen_out == (MAX_AEN_ENTRIES - 1))
- ha->aen_out = 0;
- else
- ha->aen_out++;
-
- ha->aen_q_count++;
aen = &ha->aen_q[ha->aen_out];
-
/* copy aen information to local structure */
for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
mbox_sts[i] = aen->mbox_sts[i];
+ ha->aen_q_count++;
+ ha->aen_out++;
+
+ if (ha->aen_out == MAX_AEN_ENTRIES)
+ ha->aen_out = 0;
+
spin_unlock_irqrestore(&ha->hardware_lock, flags);
- DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x "
- "mod=%x conerr=%08x \n", ha->host_no, ha->aen_out,
- mbox_sts[0], mbox_sts[2], mbox_sts[3],
- mbox_sts[1], mbox_sts[4]));
+ DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x"
+ " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no,
+ (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)),
+ mbox_sts[0], mbox_sts[1], mbox_sts[2],
+ mbox_sts[3], mbox_sts[4]));
switch (mbox_sts[0]) {
case MBOX_ASTS_DATABASE_CHANGED:
@@ -792,6 +817,5 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
spin_lock_irqsave(&ha->hardware_lock, flags);
}
spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
}
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index f116ff917237..35cd73c72a68 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
/**
@@ -169,84 +172,6 @@ mbox_exit:
return status;
}
-
-#if 0
-
-/**
- * qla4xxx_issue_iocb - issue mailbox iocb command
- * @ha: adapter state pointer.
- * @buffer: buffer pointer.
- * @phys_addr: physical address of buffer.
- * @size: size of buffer.
- *
- * Issues iocbs via mailbox commands.
- * TARGET_QUEUE_LOCK must be released.
- * ADAPTER_STATE_LOCK must be released.
- **/
-int
-qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer,
- dma_addr_t phys_addr, size_t size)
-{
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
- int status;
-
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64;
- mbox_cmd[1] = 0;
- mbox_cmd[2] = LSDW(phys_addr);
- mbox_cmd[3] = MSDW(phys_addr);
- status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
- return status;
-}
-
-int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index,
- uint16_t connection_id,
- uint16_t option)
-{
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
-
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
- mbox_cmd[1] = fw_ddb_index;
- mbox_cmd[2] = connection_id;
- mbox_cmd[3] = LOGOUT_OPTION_RELOGIN;
- if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) !=
- QLA_SUCCESS) {
- DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
- "option %04x failed sts %04X %04X",
- ha->host_no, __func__,
- option, mbox_sts[0], mbox_sts[1]));
- if (mbox_sts[0] == 0x4005)
- DEBUG2(printk("%s reason %04X\n", __func__,
- mbox_sts[1]));
- }
- return QLA_SUCCESS;
-}
-
-int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index)
-{
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
-
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
- mbox_cmd[1] = fw_ddb_index;
- if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) !=
- QLA_SUCCESS)
- return QLA_ERROR;
-
- return QLA_SUCCESS;
-}
-
-#endif /* 0 */
-
/**
* qla4xxx_initialize_fw_cb - initializes firmware control block.
* @ha: Pointer to host adapter structure.
@@ -272,10 +197,13 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
/* Get Initialize Firmware Control Block. */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
dma_free_coherent(&ha->pdev->dev,
sizeof(struct init_fw_ctrl_blk),
@@ -287,51 +215,56 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
qla4xxx_init_rings(ha);
/* Fill in the request and response queue information. */
- init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out);
- init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in);
- init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
- init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
- init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma));
- init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma));
- init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma));
- init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma));
- init_fw_cb->ShadowRegBufAddrLo =
+ init_fw_cb->pri.rqq_consumer_idx = cpu_to_le16(ha->request_out);
+ init_fw_cb->pri.compq_producer_idx = cpu_to_le16(ha->response_in);
+ init_fw_cb->pri.rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
+ init_fw_cb->pri.compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
+ init_fw_cb->pri.rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma));
+ init_fw_cb->pri.rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma));
+ init_fw_cb->pri.compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma));
+ init_fw_cb->pri.compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma));
+ init_fw_cb->pri.shdwreg_addr_lo =
cpu_to_le32(LSDW(ha->shadow_regs_dma));
- init_fw_cb->ShadowRegBufAddrHi =
+ init_fw_cb->pri.shdwreg_addr_hi =
cpu_to_le32(MSDW(ha->shadow_regs_dma));
/* Set up required options. */
- init_fw_cb->FwOptions |=
+ init_fw_cb->pri.fw_options |=
__constant_cpu_to_le16(FWOPT_SESSION_MODE |
FWOPT_INITIATOR_MODE);
- init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
+ init_fw_cb->pri.fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
/* Save some info in adapter structure. */
- ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions);
- ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions);
- ha->heartbeat_interval = init_fw_cb->HeartbeatInterval;
- memcpy(ha->ip_address, init_fw_cb->IPAddr,
- min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
- memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
- min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
- memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
- min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
- memcpy(ha->name_string, init_fw_cb->iSCSINameString,
+ ha->firmware_options = le16_to_cpu(init_fw_cb->pri.fw_options);
+ ha->tcp_options = le16_to_cpu(init_fw_cb->pri.ipv4_tcp_opts);
+ ha->heartbeat_interval = init_fw_cb->pri.hb_interval;
+ memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr)));
+ memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet)));
+ memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr)));
+ memcpy(ha->name_string, init_fw_cb->pri.iscsi_name,
min(sizeof(ha->name_string),
- sizeof(init_fw_cb->iSCSINameString)));
- memcpy(ha->alias, init_fw_cb->Alias,
- min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));
+ sizeof(init_fw_cb->pri.iscsi_name)));
+ /*memcpy(ha->alias, init_fw_cb->Alias,
+ min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/
/* Save Command Line Paramater info */
- ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout);
+ ha->port_down_retry_count = le16_to_cpu(init_fw_cb->pri.conn_ka_timeout);
ha->discovery_wait = ql4xdiscoverywait;
/* Send Initialize Firmware Control Block. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
mbox_cmd[1] = 0;
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) ==
+ mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) ==
QLA_SUCCESS)
status = QLA_SUCCESS;
else {
@@ -368,12 +301,14 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
/* Get Initialize Firmware Control Block. */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
mbox_cmd[2] = LSDW(init_fw_cb_dma);
mbox_cmd[3] = MSDW(init_fw_cb_dma);
+ mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
ha->host_no, __func__));
@@ -384,12 +319,12 @@ int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
}
/* Save IP Address. */
- memcpy(ha->ip_address, init_fw_cb->IPAddr,
- min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
- memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
- min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
- memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
- min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
+ memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr)));
+ memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet)));
+ memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr)));
dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
init_fw_cb, init_fw_cb_dma);
@@ -409,8 +344,10 @@ int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
/* Get firmware version */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_FW_STATE;
- if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 4, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ "
"status %04X\n", ha->host_no, __func__,
@@ -438,8 +375,10 @@ int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
/* Get firmware version */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS;
- if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ "
"status %04X\n", ha->host_no, __func__,
@@ -491,11 +430,14 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
}
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
mbox_cmd[1] = (uint32_t) fw_ddb_index;
mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
- if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) ==
+ mbox_cmd[4] = sizeof(struct dev_db_entry);
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 7, &mbox_cmd[0], &mbox_sts[0]) ==
QLA_ERROR) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed"
" with status 0x%04X\n", ha->host_no, __func__,
@@ -512,11 +454,11 @@ int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
"State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
- mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0],
- fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2],
- fw_ddb_entry->ipAddr[3],
- le16_to_cpu(fw_ddb_entry->portNumber),
- fw_ddb_entry->iscsiName);
+ mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0],
+ fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2],
+ fw_ddb_entry->ip_addr[3],
+ le16_to_cpu(fw_ddb_entry->port),
+ fw_ddb_entry->iscsi_name);
}
if (num_valid_ddb_entries)
*num_valid_ddb_entries = mbox_sts[2];
@@ -571,35 +513,10 @@ int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
mbox_cmd[1] = (uint32_t) fw_ddb_index;
mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
- return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
-}
+ mbox_cmd[4] = sizeof(struct dev_db_entry);
-#if 0
-int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
- uint16_t fw_ddb_index)
-{
- int status = QLA_ERROR;
- uint32_t mbox_cmd[MBOX_REG_COUNT];
- uint32_t mbox_sts[MBOX_REG_COUNT];
-
- /* Do not wait for completion. The firmware will send us an
- * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
- */
- memset(&mbox_cmd, 0, sizeof(mbox_cmd));
- memset(&mbox_sts, 0, sizeof(mbox_sts));
- mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN;
- mbox_cmd[1] = (uint32_t) fw_ddb_index;
- mbox_cmd[2] = 0;
- mbox_cmd[3] = 0;
- mbox_cmd[4] = 0;
- status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]);
- DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n",
- __func__, fw_ddb_index, status, mbox_sts[0],
- mbox_sts[1]);)
-
- return status;
+ return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
}
-#endif /* 0 */
/**
* qla4xxx_get_crash_record - retrieves crash record.
@@ -614,12 +531,14 @@ void qla4xxx_get_crash_record(struct scsi_qla_host * ha)
struct crash_record *crash_record = NULL;
dma_addr_t crash_record_dma = 0;
uint32_t crash_record_size = 0;
+
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_cmd));
/* Get size of crash record. */
mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
- if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n",
ha->host_no, __func__));
@@ -639,11 +558,15 @@ void qla4xxx_get_crash_record(struct scsi_qla_host * ha)
goto exit_get_crash_record;
/* Get Crash Record. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
mbox_cmd[2] = LSDW(crash_record_dma);
mbox_cmd[3] = MSDW(crash_record_dma);
mbox_cmd[4] = crash_record_size;
- if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS)
goto exit_get_crash_record;
@@ -655,7 +578,6 @@ exit_get_crash_record:
crash_record, crash_record_dma);
}
-#if 0
/**
* qla4xxx_get_conn_event_log - retrieves connection event log
* @ha: Pointer to host adapter structure.
@@ -678,7 +600,8 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
/* Get size of crash record. */
mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
- if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS)
goto exit_get_event_log;
@@ -693,10 +616,14 @@ void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
goto exit_get_event_log;
/* Get Crash Record. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
mbox_cmd[2] = LSDW(event_log_dma);
mbox_cmd[3] = MSDW(event_log_dma);
- if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event "
"log!\n", ha->host_no, __func__));
@@ -745,7 +672,6 @@ exit_get_event_log:
dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
event_log_dma);
}
-#endif /* 0 */
/**
* qla4xxx_reset_lun - issues LUN Reset
@@ -773,11 +699,13 @@ int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
*/
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_LUN_RESET;
mbox_cmd[1] = ddb_entry->fw_ddb_index;
mbox_cmd[2] = lun << 8;
mbox_cmd[5] = 0x01; /* Immediate Command Enable */
- qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]);
+
+ qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
status = QLA_ERROR;
@@ -794,12 +722,14 @@ int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_READ_FLASH;
mbox_cmd[1] = LSDW(dma_addr);
mbox_cmd[2] = MSDW(dma_addr);
mbox_cmd[3] = offset;
mbox_cmd[4] = len;
- if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ "
"status %04X %04X, offset %08x, len %08x\n", ha->host_no,
@@ -825,8 +755,10 @@ int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
/* Get firmware version. */
memset(&mbox_cmd, 0, sizeof(mbox_cmd));
memset(&mbox_sts, 0, sizeof(mbox_sts));
+
mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
- if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ "
"status %04X\n", ha->host_no, __func__, mbox_sts[0]));
@@ -855,7 +787,7 @@ static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
mbox_cmd[2] = LSDW(dma_addr);
mbox_cmd[3] = MSDW(dma_addr);
- if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
ha->host_no, __func__, mbox_sts[0]));
@@ -875,7 +807,7 @@ static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index)
mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY;
mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES;
- if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+ if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) !=
QLA_SUCCESS) {
if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) {
*ddb_index = mbox_sts[2];
@@ -918,23 +850,23 @@ int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
if (ret_val != QLA_SUCCESS)
goto qla4xxx_send_tgts_exit;
- memset((void *)fw_ddb_entry->iSCSIAlias, 0,
- sizeof(fw_ddb_entry->iSCSIAlias));
+ memset(fw_ddb_entry->iscsi_alias, 0,
+ sizeof(fw_ddb_entry->iscsi_alias));
- memset((void *)fw_ddb_entry->iscsiName, 0,
- sizeof(fw_ddb_entry->iscsiName));
+ memset(fw_ddb_entry->iscsi_name, 0,
+ sizeof(fw_ddb_entry->iscsi_name));
- memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr));
- memset((void *)fw_ddb_entry->targetAddr, 0,
- sizeof(fw_ddb_entry->targetAddr));
+ memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr));
+ memset(fw_ddb_entry->tgt_addr, 0,
+ sizeof(fw_ddb_entry->tgt_addr));
fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
- fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port));
+ fw_ddb_entry->port = cpu_to_le16(ntohs(port));
- fw_ddb_entry->ipAddr[0] = *ip;
- fw_ddb_entry->ipAddr[1] = *(ip + 1);
- fw_ddb_entry->ipAddr[2] = *(ip + 2);
- fw_ddb_entry->ipAddr[3] = *(ip + 3);
+ fw_ddb_entry->ip_addr[0] = *ip;
+ fw_ddb_entry->ip_addr[1] = *(ip + 1);
+ fw_ddb_entry->ip_addr[2] = *(ip + 2);
+ fw_ddb_entry->ip_addr[3] = *(ip + 3);
ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
index 58afd135aa1d..7fe0482ecf03 100644
--- a/drivers/scsi/qla4xxx/ql4_nvram.c
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -6,6 +6,9 @@
*/
#include "ql4_def.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
static inline void eeprom_cmd(uint32_t cmd, struct scsi_qla_host *ha)
{
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index da21f5fbbf87..b1d565c12c5b 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -10,6 +10,10 @@
#include <scsi/scsicam.h>
#include "ql4_def.h"
+#include "ql4_version.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
/*
* Driver version
@@ -50,12 +54,15 @@ static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
/*
* iSCSI template entry points
*/
-static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
- uint32_t enable, struct sockaddr *dst_addr);
+static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost,
+ enum iscsi_tgt_dscvr type, uint32_t enable,
+ struct sockaddr *dst_addr);
static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
enum iscsi_param param, char *buf);
static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
enum iscsi_param param, char *buf);
+static int qla4xxx_host_get_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag);
static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
@@ -95,16 +102,20 @@ static struct scsi_host_template qla4xxx_driver_template = {
static struct iscsi_transport qla4xxx_iscsi_transport = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
- .param_mask = ISCSI_CONN_PORT |
- ISCSI_CONN_ADDRESS |
- ISCSI_TARGET_NAME |
- ISCSI_TPGT,
+ .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD |
+ CAP_DATA_PATH_OFFLOAD,
+ .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS |
+ ISCSI_TARGET_NAME | ISCSI_TPGT,
+ .host_param_mask = ISCSI_HOST_HWADDRESS |
+ ISCSI_HOST_IPADDRESS |
+ ISCSI_HOST_INITIATOR_NAME,
.sessiondata_size = sizeof(struct ddb_entry),
.host_template = &qla4xxx_driver_template,
.tgt_dscvr = qla4xxx_tgt_dscvr,
.get_conn_param = qla4xxx_conn_get_param,
.get_session_param = qla4xxx_sess_get_param,
+ .get_host_param = qla4xxx_host_get_param,
.start_conn = qla4xxx_conn_start,
.stop_conn = qla4xxx_conn_stop,
.session_recovery_timedout = qla4xxx_recovery_timedout,
@@ -161,6 +172,43 @@ static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag)
printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
}
+static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
+{
+ int i;
+ char *cp = buf;
+
+ for (i = 0; i < len; i++)
+ cp += sprintf(cp, "%02x%c", addr[i],
+ i == (len - 1) ? '\n' : ':');
+ return cp - buf;
+}
+
+
+static int qla4xxx_host_get_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf)
+{
+ struct scsi_qla_host *ha = to_qla_host(shost);
+ int len;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ len = format_addr(buf, ha->my_mac, MAC_ADDR_LEN);
+ break;
+ case ISCSI_HOST_PARAM_IPADDRESS:
+ len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0],
+ ha->ip_address[1], ha->ip_address[2],
+ ha->ip_address[3]);
+ break;
+ case ISCSI_HOST_PARAM_INITIATOR_NAME:
+ len = sprintf(buf, "%s\n", ha->name_string);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+
static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
enum iscsi_param param, char *buf)
{
@@ -208,21 +256,15 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
return len;
}
-static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
- uint32_t enable, struct sockaddr *dst_addr)
+static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost,
+ enum iscsi_tgt_dscvr type, uint32_t enable,
+ struct sockaddr *dst_addr)
{
struct scsi_qla_host *ha;
- struct Scsi_Host *shost;
struct sockaddr_in *addr;
struct sockaddr_in6 *addr6;
int ret = 0;
- shost = scsi_host_lookup(host_no);
- if (IS_ERR(shost)) {
- printk(KERN_ERR "Could not find host no %u\n", host_no);
- return -ENODEV;
- }
-
ha = (struct scsi_qla_host *) shost->hostdata;
switch (type) {
@@ -246,8 +288,6 @@ static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
default:
ret = -ENOSYS;
}
-
- scsi_host_put(shost);
return ret;
}
@@ -369,14 +409,7 @@ static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
struct scsi_cmnd *cmd = srb->cmd;
if (srb->flags & SRB_DMA_VALID) {
- if (cmd->use_sg) {
- pci_unmap_sg(ha->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen) {
- pci_unmap_single(ha->pdev, srb->dma_handle,
- cmd->request_bufflen,
- cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
srb->flags &= ~SRB_DMA_VALID;
}
cmd->SCp.ptr = NULL;
@@ -711,7 +744,7 @@ static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
return stat;
}
-static void qla4xxx_hw_reset(struct scsi_qla_host *ha)
+void qla4xxx_hw_reset(struct scsi_qla_host *ha)
{
uint32_t ctrl_status;
unsigned long flags = 0;
@@ -1081,13 +1114,13 @@ static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
if (ha->timer_active)
qla4xxx_stop_timer(ha);
- /* free extra memory */
- qla4xxx_mem_free(ha);
-
/* Detach interrupts */
if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
free_irq(ha->pdev->irq, ha);
+ /* free extra memory */
+ qla4xxx_mem_free(ha);
+
pci_disable_device(ha->pdev);
}
@@ -1332,6 +1365,11 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
ha = pci_get_drvdata(pdev);
+ qla4xxx_disable_intrs(ha);
+
+ while (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags))
+ ssleep(1);
+
/* remove devs from iscsi_sessions to scsi_devices */
qla4xxx_free_ddb_list(ha);
@@ -1639,7 +1677,7 @@ static int __init qla4xxx_module_init(void)
/* Allocate cache for SRBs. */
srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (srb_cachep == NULL) {
printk(KERN_ERR
"%s: Unable to allocate SRB cache..."
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
index e5183a697d1f..ab984cb89cea 100644
--- a/drivers/scsi/qla4xxx/ql4_version.h
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -5,4 +5,5 @@
* See LICENSE.qla4xxx for copyright and licensing details.
*/
-#define QLA4XXX_DRIVER_VERSION "5.00.07-k1"
+#define QLA4XXX_DRIVER_VERSION "5.01.00-k8"
+
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 2e7db18f5aef..2bfbf26c00ed 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -265,8 +265,6 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
unsigned int message; /* scsi returned message */
unsigned int phase; /* recorded scsi phase */
unsigned int reqlen; /* total length of transfer */
- struct scatterlist *sglist; /* scatter-gather list pointer */
- unsigned int sgcount; /* sg counter */
char *buf;
struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
int qbase = priv->qbase;
@@ -301,9 +299,10 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */
outb(1, qbase + 3); /* clear fifo */
/* note that request_bufflen is the total xfer size when sg is used */
- reqlen = cmd->request_bufflen;
+ reqlen = scsi_bufflen(cmd);
/* note that it won't work if transfers > 16M are requested */
if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */
+ struct scatterlist *sg;
rtrc(2)
outb(reqlen, qbase); /* low-mid xfer cnt */
outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */
@@ -311,23 +310,16 @@ static unsigned int ql_pcmd(struct scsi_cmnd *cmd)
outb(0x90, qbase + 3); /* command do xfer */
/* PIO pseudo DMA to buffer or sglist */
REG1;
- if (!cmd->use_sg)
- ql_pdma(priv, phase, cmd->request_buffer,
- cmd->request_bufflen);
- else {
- sgcount = cmd->use_sg;
- sglist = cmd->request_buffer;
- while (sgcount--) {
- if (priv->qabort) {
- REG0;
- return ((priv->qabort == 1 ?
- DID_ABORT : DID_RESET) << 16);
- }
- buf = page_address(sglist->page) + sglist->offset;
- if (ql_pdma(priv, phase, buf, sglist->length))
- break;
- sglist++;
+
+ scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) {
+ if (priv->qabort) {
+ REG0;
+ return ((priv->qabort == 1 ?
+ DID_ABORT : DID_RESET) << 16);
}
+ buf = page_address(sg->page) + sg->offset;
+ if (ql_pdma(priv, phase, buf, sg->length))
+ break;
}
REG0;
rtrc(2)
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 4c1e31334765..a5de1a829a76 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -288,7 +288,7 @@ int scsi_setup_command_freelist(struct Scsi_Host *shost)
if (!pool->users) {
pool->slab = kmem_cache_create(pool->name,
sizeof(struct scsi_cmnd), 0,
- pool->slab_flags, NULL, NULL);
+ pool->slab_flags, NULL);
if (!pool->slab)
goto fail;
}
@@ -368,7 +368,7 @@ void scsi_log_send(struct scsi_cmnd *cmd)
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
" done = 0x%p, queuecommand 0x%p\n",
- cmd->request_buffer, cmd->request_bufflen,
+ scsi_sglist(cmd), scsi_bufflen(cmd),
cmd->done,
cmd->device->host->hostt->queuecommand);
@@ -1016,52 +1016,6 @@ struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost,
}
EXPORT_SYMBOL(scsi_device_lookup);
-/**
- * scsi_device_cancel - cancel outstanding IO to this device
- * @sdev: Pointer to struct scsi_device
- * @recovery: Boolean instructing function to recover device or not.
- *
- **/
-int scsi_device_cancel(struct scsi_device *sdev, int recovery)
-{
- struct scsi_cmnd *scmd;
- LIST_HEAD(active_list);
- struct list_head *lh, *lh_sf;
- unsigned long flags;
-
- scsi_device_set_state(sdev, SDEV_CANCEL);
-
- spin_lock_irqsave(&sdev->list_lock, flags);
- list_for_each_entry(scmd, &sdev->cmd_list, list) {
- if (scmd->request) {
- /*
- * If we are unable to remove the timer, it means
- * that the command has already timed out or
- * finished.
- */
- if (!scsi_delete_timer(scmd))
- continue;
- list_add_tail(&scmd->eh_entry, &active_list);
- }
- }
- spin_unlock_irqrestore(&sdev->list_lock, flags);
-
- if (!list_empty(&active_list)) {
- list_for_each_safe(lh, lh_sf, &active_list) {
- scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
- list_del_init(lh);
- if (recovery &&
- !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)) {
- scmd->result = (DID_ABORT << 16);
- scsi_finish_command(scmd);
- }
- }
- }
-
- return 0;
-}
-EXPORT_SYMBOL(scsi_device_cancel);
-
MODULE_DESCRIPTION("SCSI core");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 06229f225ee9..4947dfe625a6 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -2405,7 +2405,7 @@ MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
-MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
+MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
@@ -2875,7 +2875,7 @@ static int __init scsi_debug_init(void)
init_all_queued();
- sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
+ sdebug_driver_template.proc_name = sdebug_proc_name;
host_to_add = scsi_debug_add_host;
scsi_debug_add_host = 0;
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 18dd5cc4d7c6..19c44f0781fd 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -128,6 +128,7 @@ static struct {
{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
{"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN},
{"BELKIN", "USB 2 HS-CF", "1.95", BLIST_FORCELUN | BLIST_INQUIRY_36},
+ {"BROWNIE", "1200U3P", NULL, BLIST_NOREPORTLUN},
{"BROWNIE", "1600U3P", NULL, BLIST_NOREPORTLUN},
{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
{"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN | BLIST_INQUIRY_36},
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index e8350c562d24..8a525abda30f 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -18,12 +18,13 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
-#include <linux/slab.h>
#include <linux/kernel.h>
+#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
+#include <linux/scatterlist.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -640,16 +641,8 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
memcpy(scmd->cmnd, cmnd, cmnd_size);
if (copy_sense) {
- gfp_t gfp_mask = GFP_ATOMIC;
-
- if (shost->hostt->unchecked_isa_dma)
- gfp_mask |= __GFP_DMA;
-
- sgl.page = alloc_page(gfp_mask);
- if (!sgl.page)
- return FAILED;
- sgl.offset = 0;
- sgl.length = 252;
+ sg_init_one(&sgl, scmd->sense_buffer,
+ sizeof(scmd->sense_buffer));
scmd->sc_data_direction = DMA_FROM_DEVICE;
scmd->request_bufflen = sgl.length;
@@ -720,18 +713,6 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
/*
- * Last chance to have valid sense data.
- */
- if (copy_sense) {
- if (!SCSI_SENSE_VALID(scmd)) {
- memcpy(scmd->sense_buffer, page_address(sgl.page),
- sizeof(scmd->sense_buffer));
- }
- __free_page(sgl.page);
- }
-
-
- /*
* Restore original data
*/
scmd->request_buffer = old_buffer;
@@ -1536,8 +1517,6 @@ int scsi_error_handler(void *data)
{
struct Scsi_Host *shost = data;
- current->flags |= PF_NOFREEZE;
-
/*
* We use TASK_INTERRUPTIBLE so that the thread is not
* counted against the load average as a running process.
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 1f5a07bf2a75..da63c544919b 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1661,7 +1661,7 @@ int __init scsi_init_queue(void)
scsi_io_context_cache = kmem_cache_create("scsi_io_context",
sizeof(struct scsi_io_context),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!scsi_io_context_cache) {
printk(KERN_ERR "SCSI: can't init scsi io context cache\n");
return -ENOMEM;
@@ -1672,7 +1672,7 @@ int __init scsi_init_queue(void)
int size = sgp->size * sizeof(struct scatterlist);
sgp->slab = kmem_cache_create(sgp->name, size, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!sgp->slab) {
printk(KERN_ERR "SCSI: can't init sg slab %s\n",
sgp->name);
diff --git a/drivers/scsi/scsi_lib_dma.c b/drivers/scsi/scsi_lib_dma.c
new file mode 100644
index 000000000000..ac6855cd2657
--- /dev/null
+++ b/drivers/scsi/scsi_lib_dma.c
@@ -0,0 +1,50 @@
+/*
+ * SCSI library functions depending on DMA
+ */
+
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+/**
+ * scsi_dma_map - perform DMA mapping against command's sg lists
+ * @cmd: scsi command
+ *
+ * Returns the number of sg lists actually used, zero if the sg lists
+ * is NULL, or -ENOMEM if the mapping failed.
+ */
+int scsi_dma_map(struct scsi_cmnd *cmd)
+{
+ int nseg = 0;
+
+ if (scsi_sg_count(cmd)) {
+ struct device *dev = cmd->device->host->shost_gendev.parent;
+
+ nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
+ cmd->sc_data_direction);
+ if (unlikely(!nseg))
+ return -ENOMEM;
+ }
+ return nseg;
+}
+EXPORT_SYMBOL(scsi_dma_map);
+
+/**
+ * scsi_dma_unmap - unmap command's sg lists mapped by scsi_dma_map
+ * @cmd: scsi command
+ */
+void scsi_dma_unmap(struct scsi_cmnd *cmd)
+{
+ if (scsi_sg_count(cmd)) {
+ struct device *dev = cmd->device->host->shost_gendev.parent;
+
+ dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd),
+ cmd->sc_data_direction);
+ }
+}
+EXPORT_SYMBOL(scsi_dma_unmap);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 662577fbe7a8..a86e62f4b3ba 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -703,16 +703,14 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
/**
* scsi_add_lun - allocate and fully initialze a scsi_device
- * @sdevscan: holds information to be stored in the new scsi_device
- * @sdevnew: store the address of the newly allocated scsi_device
+ * @sdev: holds information to be stored in the new scsi_device
* @inq_result: holds the result of a previous INQUIRY to the LUN
* @bflags: black/white list flag
+ * @async: 1 if this device is being scanned asynchronously
*
* Description:
- * Allocate and initialize a scsi_device matching sdevscan. Optionally
- * set fields based on values in *@bflags. If @sdevnew is not
- * NULL, store the address of the new scsi_device in *@sdevnew (needed
- * when scanning a particular LUN).
+ * Initialize the scsi_device @sdev. Optionally set fields based
+ * on values in *@bflags.
*
* Return:
* SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
@@ -752,25 +750,15 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
sdev->rev = (char *) (sdev->inquiry + 32);
if (*bflags & BLIST_ISROM) {
- /*
- * It would be better to modify sdev->type, and set
- * sdev->removable; this can now be done since
- * print_inquiry has gone away.
- */
- inq_result[0] = TYPE_ROM;
- inq_result[1] |= 0x80; /* removable */
- } else if (*bflags & BLIST_NO_ULD_ATTACH)
- sdev->no_uld_attach = 1;
+ sdev->type = TYPE_ROM;
+ sdev->removable = 1;
+ } else {
+ sdev->type = (inq_result[0] & 0x1f);
+ sdev->removable = (inq_result[1] & 0x80) >> 7;
+ }
- switch (sdev->type = (inq_result[0] & 0x1f)) {
+ switch (sdev->type) {
case TYPE_RBC:
- /* RBC devices can return SCSI-3 compliance and yet
- * still not support REPORT LUNS, so make them act as
- * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
- * specifically set */
- if ((*bflags & BLIST_REPORTLUN2) == 0)
- *bflags |= BLIST_NOREPORTLUN;
- /* fall through */
case TYPE_TAPE:
case TYPE_DISK:
case TYPE_PRINTER:
@@ -784,13 +772,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
sdev->writeable = 1;
break;
case TYPE_ROM:
- /* MMC devices can return SCSI-3 compliance and yet
- * still not support REPORT LUNS, so make them act as
- * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
- * specifically set */
- if ((*bflags & BLIST_REPORTLUN2) == 0)
- *bflags |= BLIST_NOREPORTLUN;
- /* fall through */
case TYPE_WORM:
sdev->writeable = 0;
break;
@@ -798,6 +779,15 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
}
+ if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) {
+ /* RBC and MMC devices can return SCSI-3 compliance and yet
+ * still not support REPORT LUNS, so make them act as
+ * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is
+ * specifically set */
+ if ((*bflags & BLIST_REPORTLUN2) == 0)
+ *bflags |= BLIST_NOREPORTLUN;
+ }
+
/*
* For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
* spec says: The device server is capable of supporting the
@@ -815,12 +805,11 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
*/
sdev->inq_periph_qual = (inq_result[0] >> 5) & 7;
- sdev->removable = (0x80 & inq_result[1]) >> 7;
sdev->lockable = sdev->removable;
sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
- if (sdev->scsi_level >= SCSI_3 || (sdev->inquiry_len > 56 &&
- inq_result[56] & 0x04))
+ if (sdev->scsi_level >= SCSI_3 ||
+ (sdev->inquiry_len > 56 && inq_result[56] & 0x04))
sdev->ppr = 1;
if (inq_result[7] & 0x60)
sdev->wdtr = 1;
@@ -833,13 +822,10 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
sdev->inq_periph_qual, inq_result[2] & 0x07,
(inq_result[3] & 0x0f) == 1 ? " CCS" : "");
- /*
- * End sysfs code.
- */
-
if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
!(*bflags & BLIST_NOTQ))
sdev->tagged_supported = 1;
+
/*
* Some devices (Texel CD ROM drives) have handshaking problems
* when used with the Seagate controllers. borken is initialized
@@ -848,6 +834,9 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
if ((*bflags & BLIST_BORKEN) == 0)
sdev->borken = 0;
+ if (*bflags & BLIST_NO_ULD_ATTACH)
+ sdev->no_uld_attach = 1;
+
/*
* Apparently some really broken devices (contrary to the SCSI
* standards) need to be selected without asserting ATN
@@ -872,7 +861,6 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
if (*bflags & BLIST_SINGLELUN)
sdev->single_lun = 1;
-
sdev->use_10_for_rw = 1;
if (*bflags & BLIST_MS_SKIP_PAGE_08)
@@ -1213,7 +1201,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
* Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns
* the integer: 0x0b030a04
**/
-static int scsilun_to_int(struct scsi_lun *scsilun)
+int scsilun_to_int(struct scsi_lun *scsilun)
{
int i;
unsigned int lun;
@@ -1224,6 +1212,7 @@ static int scsilun_to_int(struct scsi_lun *scsilun)
scsilun->scsi_lun[i + 1]) << (i * 8));
return lun;
}
+EXPORT_SYMBOL(scsilun_to_int);
/**
* int_to_scsilun: reverts an int into a scsi_lun
diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c
index 6cfaaa2d0c81..63a30f566f3a 100644
--- a/drivers/scsi/scsi_sysctl.c
+++ b/drivers/scsi/scsi_sysctl.c
@@ -9,6 +9,7 @@
#include <linux/sysctl.h>
#include "scsi_logging.h"
+#include "scsi_priv.h"
static ctl_table scsi_table[] = {
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 67a38a1409ba..34cdce6738a6 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -16,6 +16,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
+#include <scsi/scsi_driver.h>
#include "scsi_priv.h"
#include "scsi_logging.h"
@@ -293,30 +294,18 @@ 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 scsi_host_template *sht = sdev->host->hostt;
int err;
err = scsi_device_quiesce(sdev);
if (err)
return err;
- /* call HLD suspend first */
if (drv && drv->suspend) {
err = drv->suspend(dev, state);
if (err)
return err;
}
- /* then, call host suspend */
- if (sht->suspend) {
- err = sht->suspend(sdev, state);
- if (err) {
- if (drv && drv->resume)
- drv->resume(dev);
- return err;
- }
- }
-
return 0;
}
@@ -324,21 +313,14 @@ static int scsi_bus_resume(struct device * dev)
{
struct device_driver *drv = dev->driver;
struct scsi_device *sdev = to_scsi_device(dev);
- struct scsi_host_template *sht = sdev->host->hostt;
- int err = 0, err2 = 0;
+ int err = 0;
- /* call host resume first */
- if (sht->resume)
- err = sht->resume(sdev);
-
- /* then, call HLD resume */
if (drv && drv->resume)
- err2 = drv->resume(dev);
+ err = drv->resume(dev);
scsi_device_resume(sdev);
- /* favor LLD failure */
- return err ? err : err2;;
+ return err;
}
struct bus_type scsi_bus_type = {
@@ -733,6 +715,7 @@ static int attr_add(struct device *dev, struct device_attribute *attr)
int scsi_sysfs_add_sdev(struct scsi_device *sdev)
{
int error, i;
+ struct request_queue *rq = sdev->request_queue;
if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
return error;
@@ -752,6 +735,17 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
/* take a reference for the sdev_classdev; this is
* released by the sdev_class .release */
get_device(&sdev->sdev_gendev);
+
+ error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
+
+ if (error)
+ sdev_printk(KERN_INFO, sdev,
+ "Failed to register bsg queue, errno=%d\n", error);
+
+ /* we're treating error on bsg register as non-fatal, so pretend
+ * nothing went wrong */
+ error = 0;
+
if (sdev->host->hostt->sdev_attrs) {
for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
error = attr_add(&sdev->sdev_gendev,
@@ -798,6 +792,7 @@ void __scsi_remove_device(struct scsi_device *sdev)
if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
return;
+ bsg_unregister_queue(sdev->request_queue);
class_device_unregister(&sdev->sdev_classdev);
transport_remove_device(dev);
device_del(dev);
@@ -822,7 +817,7 @@ void scsi_remove_device(struct scsi_device *sdev)
}
EXPORT_SYMBOL(scsi_remove_device);
-void __scsi_remove_target(struct scsi_target *starget)
+static void __scsi_remove_target(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
unsigned long flags;
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 2570f48a69c7..371b69c110bc 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -585,7 +585,7 @@ static int __init scsi_tgt_init(void)
scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
sizeof(struct scsi_tgt_cmd),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!scsi_tgt_cmd_cache)
return -ENOMEM;
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index b4d1ece46f78..47057254850d 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1,4 +1,4 @@
-/*
+/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
@@ -19,9 +19,10 @@
*
* ========
*
- * Copyright (C) 2004-2005 James Smart, Emulex Corporation
+ * Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
+ * Add vports, etc
*
*/
#include <linux/module.h>
@@ -37,6 +38,34 @@
#include "scsi_priv.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
+static void fc_vport_sched_delete(struct work_struct *work);
+
+/*
+ * This is a temporary carrier for creating a vport. It will eventually
+ * be replaced by a real message definition for sgio or netlink.
+ *
+ * fc_vport_identifiers: This set of data contains all elements
+ * to uniquely identify and instantiate a FC virtual port.
+ *
+ * Notes:
+ * symbolic_name: The driver is to append the symbolic_name string data
+ * to the symbolic_node_name data that it generates by default.
+ * the resulting combination should then be registered with the switch.
+ * It is expected that things like Xen may stuff a VM title into
+ * this field.
+ */
+struct fc_vport_identifiers {
+ u64 node_name;
+ u64 port_name;
+ u32 roles;
+ bool disable;
+ enum fc_port_type vport_type; /* only FC_PORTTYPE_NPIV allowed */
+ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
+};
+
+static int fc_vport_create(struct Scsi_Host *shost, int channel,
+ struct device *pdev, struct fc_vport_identifiers *ids,
+ struct fc_vport **vport);
/*
* Redefine so that we can have same named attributes in the
@@ -90,10 +119,14 @@ static struct {
{ FC_PORTTYPE_NLPORT, "NLPort (fabric via loop)" },
{ FC_PORTTYPE_LPORT, "LPort (private loop)" },
{ FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection" },
+ { FC_PORTTYPE_NPIV, "NPIV VPORT" },
};
fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
#define FC_PORTTYPE_MAX_NAMELEN 50
+/* Reuse fc_port_type enum function for vport_type */
+#define get_fc_vport_type_name get_fc_port_type_name
+
/* Convert fc_host_event_code values to ascii string name */
static const struct {
@@ -139,6 +172,29 @@ fc_enum_name_search(port_state, fc_port_state, fc_port_state_names)
#define FC_PORTSTATE_MAX_NAMELEN 20
+/* Convert fc_vport_state values to ascii string name */
+static struct {
+ enum fc_vport_state value;
+ char *name;
+} fc_vport_state_names[] = {
+ { FC_VPORT_UNKNOWN, "Unknown" },
+ { FC_VPORT_ACTIVE, "Active" },
+ { FC_VPORT_DISABLED, "Disabled" },
+ { FC_VPORT_LINKDOWN, "Linkdown" },
+ { FC_VPORT_INITIALIZING, "Initializing" },
+ { FC_VPORT_NO_FABRIC_SUPP, "No Fabric Support" },
+ { FC_VPORT_NO_FABRIC_RSCS, "No Fabric Resources" },
+ { FC_VPORT_FABRIC_LOGOUT, "Fabric Logout" },
+ { FC_VPORT_FABRIC_REJ_WWN, "Fabric Rejected WWN" },
+ { FC_VPORT_FAILED, "VPort Failed" },
+};
+fc_enum_name_search(vport_state, fc_vport_state, fc_vport_state_names)
+#define FC_VPORTSTATE_MAX_NAMELEN 24
+
+/* Reuse fc_vport_state enum function for vport_last_state */
+#define get_fc_vport_last_state_name get_fc_vport_state_name
+
+
/* Convert fc_tgtid_binding_type values to ascii string name */
static const struct {
enum fc_tgtid_binding_type value;
@@ -219,16 +275,16 @@ show_fc_fc4s (char *buf, u8 *fc4_list)
}
-/* Convert FC_RPORT_ROLE bit values to ascii string name */
+/* Convert FC_PORT_ROLE bit values to ascii string name */
static const struct {
u32 value;
char *name;
-} fc_remote_port_role_names[] = {
- { FC_RPORT_ROLE_FCP_TARGET, "FCP Target" },
- { FC_RPORT_ROLE_FCP_INITIATOR, "FCP Initiator" },
- { FC_RPORT_ROLE_IP_PORT, "IP Port" },
+} fc_port_role_names[] = {
+ { FC_PORT_ROLE_FCP_TARGET, "FCP Target" },
+ { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" },
+ { FC_PORT_ROLE_IP_PORT, "IP Port" },
};
-fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
+fc_bitfield_name_search(port_roles, fc_port_role_names)
/*
* Define roles that are specific to port_id. Values are relative to ROLE_MASK.
@@ -252,7 +308,8 @@ static void fc_scsi_scan_rport(struct work_struct *work);
*/
#define FC_STARGET_NUM_ATTRS 3
#define FC_RPORT_NUM_ATTRS 10
-#define FC_HOST_NUM_ATTRS 17
+#define FC_VPORT_NUM_ATTRS 9
+#define FC_HOST_NUM_ATTRS 21
struct fc_internal {
struct scsi_transport_template t;
@@ -278,6 +335,10 @@ struct fc_internal {
struct transport_container rport_attr_cont;
struct class_device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS];
struct class_device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1];
+
+ struct transport_container vport_attr_cont;
+ struct class_device_attribute private_vport_attrs[FC_VPORT_NUM_ATTRS];
+ struct class_device_attribute *vport_attrs[FC_VPORT_NUM_ATTRS + 1];
};
#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
@@ -318,7 +379,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
struct Scsi_Host *shost = dev_to_shost(dev);
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
- /*
+ /*
* Set default values easily detected by the midlayer as
* failure cases. The scsi lldd is responsible for initializing
* all transport attributes to valid values per host.
@@ -331,6 +392,7 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
sizeof(fc_host->supported_fc4s));
fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
fc_host->maxframe_size = -1;
+ fc_host->max_npiv_vports = 0;
memset(fc_host->serial_number, 0,
sizeof(fc_host->serial_number));
@@ -348,8 +410,11 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
INIT_LIST_HEAD(&fc_host->rports);
INIT_LIST_HEAD(&fc_host->rport_bindings);
+ INIT_LIST_HEAD(&fc_host->vports);
fc_host->next_rport_number = 0;
fc_host->next_target_id = 0;
+ fc_host->next_vport_number = 0;
+ fc_host->npiv_vports_inuse = 0;
snprintf(fc_host->work_q_name, KOBJ_NAME_LEN, "fc_wq_%d",
shost->host_no);
@@ -388,6 +453,16 @@ static DECLARE_TRANSPORT_CLASS(fc_rport_class,
NULL);
/*
+ * Setup and Remove actions for virtual ports are handled
+ * in the service functions below.
+ */
+static DECLARE_TRANSPORT_CLASS(fc_vport_class,
+ "fc_vports",
+ NULL,
+ NULL,
+ NULL);
+
+/*
* Module Parameters
*/
@@ -585,6 +660,9 @@ static __init int fc_transport_init(void)
error = transport_class_register(&fc_host_class);
if (error)
return error;
+ error = transport_class_register(&fc_vport_class);
+ if (error)
+ return error;
error = transport_class_register(&fc_rport_class);
if (error)
return error;
@@ -596,6 +674,7 @@ static void __exit fc_transport_exit(void)
transport_class_unregister(&fc_transport_class);
transport_class_unregister(&fc_rport_class);
transport_class_unregister(&fc_host_class);
+ transport_class_unregister(&fc_vport_class);
}
/*
@@ -800,9 +879,9 @@ show_fc_rport_roles (struct class_device *cdev, char *buf)
return snprintf(buf, 30, "Unknown Fabric Entity\n");
}
} else {
- if (rport->roles == FC_RPORT_ROLE_UNKNOWN)
+ if (rport->roles == FC_PORT_ROLE_UNKNOWN)
return snprintf(buf, 20, "unknown\n");
- return get_fc_remote_port_roles_names(rport->roles, buf);
+ return get_fc_port_roles_names(rport->roles, buf);
}
}
static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
@@ -857,7 +936,7 @@ static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
/*
* Note: in the target show function we recognize when the remote
- * port is in the hierarchy and do not allow the driver to get
+ * port is in the heirarchy and do not allow the driver to get
* involved in sysfs functions. The driver only gets involved if
* it's the "old" style that doesn't use rports.
*/
@@ -912,6 +991,257 @@ fc_starget_rd_attr(port_id, "0x%06x\n", 20);
/*
+ * FC Virtual Port Attribute Management
+ */
+
+#define fc_vport_show_function(field, format_string, sz, cast) \
+static ssize_t \
+show_fc_vport_##field (struct class_device *cdev, char *buf) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ struct Scsi_Host *shost = vport_to_shost(vport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ if ((i->f->get_vport_##field) && \
+ !(vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))) \
+ i->f->get_vport_##field(vport); \
+ return snprintf(buf, sz, format_string, cast vport->field); \
+}
+
+#define fc_vport_store_function(field) \
+static ssize_t \
+store_fc_vport_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ int val; \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ struct Scsi_Host *shost = vport_to_shost(vport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ char *cp; \
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \
+ return -EBUSY; \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
+ i->f->set_vport_##field(vport, val); \
+ return count; \
+}
+
+#define fc_vport_store_str_function(field, slen) \
+static ssize_t \
+store_fc_vport_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ struct Scsi_Host *shost = vport_to_shost(vport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ unsigned int cnt=count; \
+ \
+ /* count may include a LF at end of string */ \
+ if (buf[cnt-1] == '\n') \
+ cnt--; \
+ if (cnt > ((slen) - 1)) \
+ return -EINVAL; \
+ memcpy(vport->field, buf, cnt); \
+ i->f->set_vport_##field(vport); \
+ return count; \
+}
+
+#define fc_vport_rd_attr(field, format_string, sz) \
+ fc_vport_show_function(field, format_string, sz, ) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_vport_rd_attr_cast(field, format_string, sz, cast) \
+ fc_vport_show_function(field, format_string, sz, (cast)) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_vport_rw_attr(field, format_string, sz) \
+ fc_vport_show_function(field, format_string, sz, ) \
+ fc_vport_store_function(field) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \
+ show_fc_vport_##field, \
+ store_fc_vport_##field)
+
+#define fc_private_vport_show_function(field, format_string, sz, cast) \
+static ssize_t \
+show_fc_vport_##field (struct class_device *cdev, char *buf) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ return snprintf(buf, sz, format_string, cast vport->field); \
+}
+
+#define fc_private_vport_store_u32_function(field) \
+static ssize_t \
+store_fc_vport_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ u32 val; \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ char *cp; \
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \
+ return -EBUSY; \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
+ vport->field = val; \
+ return count; \
+}
+
+
+#define fc_private_vport_rd_attr(field, format_string, sz) \
+ fc_private_vport_show_function(field, format_string, sz, ) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_private_vport_rd_attr_cast(field, format_string, sz, cast) \
+ fc_private_vport_show_function(field, format_string, sz, (cast)) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO, \
+ show_fc_vport_##field, NULL)
+
+#define fc_private_vport_rw_u32_attr(field, format_string, sz) \
+ fc_private_vport_show_function(field, format_string, sz, ) \
+ fc_private_vport_store_u32_function(field) \
+static FC_CLASS_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \
+ show_fc_vport_##field, \
+ store_fc_vport_##field)
+
+
+#define fc_private_vport_rd_enum_attr(title, maxlen) \
+static ssize_t \
+show_fc_vport_##title (struct class_device *cdev, char *buf) \
+{ \
+ struct fc_vport *vport = transport_class_to_vport(cdev); \
+ const char *name; \
+ name = get_fc_##title##_name(vport->title); \
+ if (!name) \
+ return -EINVAL; \
+ return snprintf(buf, maxlen, "%s\n", name); \
+} \
+static FC_CLASS_DEVICE_ATTR(vport, title, S_IRUGO, \
+ show_fc_vport_##title, NULL)
+
+
+#define SETUP_VPORT_ATTRIBUTE_RD(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->private_vport_attrs[count].attr.mode = S_IRUGO; \
+ i->private_vport_attrs[count].store = NULL; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ if (i->f->get_##field) \
+ count++
+ /* NOTE: Above MACRO differs: checks function not show bit */
+
+#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->private_vport_attrs[count].attr.mode = S_IRUGO; \
+ i->private_vport_attrs[count].store = NULL; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ count++
+
+#define SETUP_VPORT_ATTRIBUTE_WR(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ if (i->f->field) \
+ count++
+ /* NOTE: Above MACRO differs: checks function */
+
+#define SETUP_VPORT_ATTRIBUTE_RW(field) \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ if (!i->f->set_vport_##field) { \
+ i->private_vport_attrs[count].attr.mode = S_IRUGO; \
+ i->private_vport_attrs[count].store = NULL; \
+ } \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ count++
+ /* NOTE: Above MACRO differs: does not check show bit */
+
+#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RW(field) \
+{ \
+ i->private_vport_attrs[count] = class_device_attr_vport_##field; \
+ i->vport_attrs[count] = &i->private_vport_attrs[count]; \
+ count++; \
+}
+
+
+/* The FC Transport Virtual Port Attributes: */
+
+/* Fixed Virtual Port Attributes */
+
+/* Dynamic Virtual Port Attributes */
+
+/* Private Virtual Port Attributes */
+
+fc_private_vport_rd_enum_attr(vport_state, FC_VPORTSTATE_MAX_NAMELEN);
+fc_private_vport_rd_enum_attr(vport_last_state, FC_VPORTSTATE_MAX_NAMELEN);
+fc_private_vport_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
+fc_private_vport_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+
+static ssize_t
+show_fc_vport_roles (struct class_device *cdev, char *buf)
+{
+ struct fc_vport *vport = transport_class_to_vport(cdev);
+
+ if (vport->roles == FC_PORT_ROLE_UNKNOWN)
+ return snprintf(buf, 20, "unknown\n");
+ return get_fc_port_roles_names(vport->roles, buf);
+}
+static FC_CLASS_DEVICE_ATTR(vport, roles, S_IRUGO, show_fc_vport_roles, NULL);
+
+fc_private_vport_rd_enum_attr(vport_type, FC_PORTTYPE_MAX_NAMELEN);
+
+fc_private_vport_show_function(symbolic_name, "%s\n",
+ FC_VPORT_SYMBOLIC_NAMELEN + 1, )
+fc_vport_store_str_function(symbolic_name, FC_VPORT_SYMBOLIC_NAMELEN)
+static FC_CLASS_DEVICE_ATTR(vport, symbolic_name, S_IRUGO | S_IWUSR,
+ show_fc_vport_symbolic_name, store_fc_vport_symbolic_name);
+
+static ssize_t
+store_fc_vport_delete(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct fc_vport *vport = transport_class_to_vport(cdev);
+ struct Scsi_Host *shost = vport_to_shost(vport);
+
+ fc_queue_work(shost, &vport->vport_delete_work);
+ return count;
+}
+static FC_CLASS_DEVICE_ATTR(vport, vport_delete, S_IWUSR,
+ NULL, store_fc_vport_delete);
+
+
+/*
+ * Enable/Disable vport
+ * Write "1" to disable, write "0" to enable
+ */
+static ssize_t
+store_fc_vport_disable(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct fc_vport *vport = transport_class_to_vport(cdev);
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ int stat;
+
+ if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))
+ return -EBUSY;
+
+ if (*buf == '0') {
+ if (vport->vport_state != FC_VPORT_DISABLED)
+ return -EALREADY;
+ } else if (*buf == '1') {
+ if (vport->vport_state == FC_VPORT_DISABLED)
+ return -EALREADY;
+ } else
+ return -EINVAL;
+
+ stat = i->f->vport_disable(vport, ((*buf == '0') ? false : true));
+ return stat ? stat : count;
+}
+static FC_CLASS_DEVICE_ATTR(vport, vport_disable, S_IWUSR,
+ NULL, store_fc_vport_disable);
+
+
+/*
* Host Attribute Management
*/
@@ -1003,6 +1333,13 @@ static FC_CLASS_DEVICE_ATTR(host, title, S_IRUGO, show_fc_host_##title, NULL)
if (i->f->show_host_##field) \
count++
+#define SETUP_HOST_ATTRIBUTE_RD_NS(field) \
+ i->private_host_attrs[count] = class_device_attr_host_##field; \
+ i->private_host_attrs[count].attr.mode = S_IRUGO; \
+ i->private_host_attrs[count].store = NULL; \
+ i->host_attrs[count] = &i->private_host_attrs[count]; \
+ count++
+
#define SETUP_HOST_ATTRIBUTE_RW(field) \
i->private_host_attrs[count] = class_device_attr_host_##field; \
if (!i->f->set_host_##field) { \
@@ -1090,6 +1427,7 @@ fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
unsigned long long);
fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
+fc_private_host_rd_attr(max_npiv_vports, "%u\n", 20);
fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
@@ -1210,6 +1548,9 @@ store_fc_private_host_issue_lip(struct class_device *cdev,
static FC_CLASS_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL,
store_fc_private_host_issue_lip);
+fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20);
+
+
/*
* Host Statistics Management
*/
@@ -1285,7 +1626,6 @@ fc_reset_statistics(struct class_device *cdev, const char *buf,
static FC_CLASS_DEVICE_ATTR(host, reset_statistics, S_IWUSR, NULL,
fc_reset_statistics);
-
static struct attribute *fc_statistics_attrs[] = {
&class_device_attr_host_seconds_since_last_reset.attr,
&class_device_attr_host_tx_frames.attr,
@@ -1316,6 +1656,142 @@ static struct attribute_group fc_statistics_group = {
.attrs = fc_statistics_attrs,
};
+
+/* Host Vport Attributes */
+
+static int
+fc_parse_wwn(const char *ns, u64 *nm)
+{
+ unsigned int i, j;
+ u8 wwn[8];
+
+ memset(wwn, 0, sizeof(wwn));
+
+ /* Validate and store the new name */
+ for (i=0, j=0; i < 16; i++) {
+ if ((*ns >= 'a') && (*ns <= 'f'))
+ j = ((j << 4) | ((*ns++ -'a') + 10));
+ else if ((*ns >= 'A') && (*ns <= 'F'))
+ j = ((j << 4) | ((*ns++ -'A') + 10));
+ else if ((*ns >= '0') && (*ns <= '9'))
+ j = ((j << 4) | (*ns++ -'0'));
+ else
+ return -EINVAL;
+ if (i % 2) {
+ wwn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+
+ *nm = wwn_to_u64(wwn);
+
+ return 0;
+}
+
+
+/*
+ * "Short-cut" sysfs variable to create a new vport on a FC Host.
+ * Input is a string of the form "<WWPN>:<WWNN>". Other attributes
+ * will default to a NPIV-based FCP_Initiator; The WWNs are specified
+ * as hex characters, and may *not* contain any prefixes (e.g. 0x, x, etc)
+ */
+static ssize_t
+store_fc_host_vport_create(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct Scsi_Host *shost = transport_class_to_shost(cdev);
+ struct fc_vport_identifiers vid;
+ struct fc_vport *vport;
+ unsigned int cnt=count;
+ int stat;
+
+ memset(&vid, 0, sizeof(vid));
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ /* validate we have enough characters for WWPN */
+ if ((cnt != (16+1+16)) || (buf[16] != ':'))
+ return -EINVAL;
+
+ stat = fc_parse_wwn(&buf[0], &vid.port_name);
+ if (stat)
+ return stat;
+
+ stat = fc_parse_wwn(&buf[17], &vid.node_name);
+ if (stat)
+ return stat;
+
+ vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
+ vid.vport_type = FC_PORTTYPE_NPIV;
+ /* vid.symbolic_name is already zero/NULL's */
+ vid.disable = false; /* always enabled */
+
+ /* we only allow support on Channel 0 !!! */
+ stat = fc_vport_create(shost, 0, &shost->shost_gendev, &vid, &vport);
+ return stat ? stat : count;
+}
+static FC_CLASS_DEVICE_ATTR(host, vport_create, S_IWUSR, NULL,
+ store_fc_host_vport_create);
+
+
+/*
+ * "Short-cut" sysfs variable to delete a vport on a FC Host.
+ * Vport is identified by a string containing "<WWPN>:<WWNN>".
+ * The WWNs are specified as hex characters, and may *not* contain
+ * any prefixes (e.g. 0x, x, etc)
+ */
+static ssize_t
+store_fc_host_vport_delete(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct Scsi_Host *shost = transport_class_to_shost(cdev);
+ struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ struct fc_vport *vport;
+ u64 wwpn, wwnn;
+ unsigned long flags;
+ unsigned int cnt=count;
+ int stat, match;
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ /* validate we have enough characters for WWPN */
+ if ((cnt != (16+1+16)) || (buf[16] != ':'))
+ return -EINVAL;
+
+ stat = fc_parse_wwn(&buf[0], &wwpn);
+ if (stat)
+ return stat;
+
+ stat = fc_parse_wwn(&buf[17], &wwnn);
+ if (stat)
+ return stat;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ match = 0;
+ /* we only allow support on Channel 0 !!! */
+ list_for_each_entry(vport, &fc_host->vports, peers) {
+ if ((vport->channel == 0) &&
+ (vport->port_name == wwpn) && (vport->node_name == wwnn)) {
+ match = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (!match)
+ return -ENODEV;
+
+ stat = fc_vport_terminate(vport);
+ return stat ? stat : count;
+}
+static FC_CLASS_DEVICE_ATTR(host, vport_delete, S_IWUSR, NULL,
+ store_fc_host_vport_delete);
+
+
static int fc_host_match(struct attribute_container *cont,
struct device *dev)
{
@@ -1387,6 +1863,40 @@ static int fc_rport_match(struct attribute_container *cont,
}
+static void fc_vport_dev_release(struct device *dev)
+{
+ struct fc_vport *vport = dev_to_vport(dev);
+ put_device(dev->parent); /* release kobj parent */
+ kfree(vport);
+}
+
+int scsi_is_fc_vport(const struct device *dev)
+{
+ return dev->release == fc_vport_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_fc_vport);
+
+static int fc_vport_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct fc_vport *vport;
+ struct Scsi_Host *shost;
+ struct fc_internal *i;
+
+ if (!scsi_is_fc_vport(dev))
+ return 0;
+ vport = dev_to_vport(dev);
+
+ shost = vport_to_shost(vport);
+ if (!shost->transportt || shost->transportt->host_attrs.ac.class
+ != &fc_host_class.class)
+ return 0;
+
+ i = to_fc_internal(shost->transportt);
+ return &i->vport_attr_cont.ac == cont;
+}
+
+
/**
* fc_timed_out - FC Transport I/O timeout intercept handler
*
@@ -1433,6 +1943,9 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel,
if (rport->scsi_target_id == -1)
continue;
+ 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,
@@ -1472,6 +1985,11 @@ fc_attach_transport(struct fc_function_template *ft)
i->rport_attr_cont.ac.match = fc_rport_match;
transport_container_register(&i->rport_attr_cont);
+ i->vport_attr_cont.ac.attrs = &i->vport_attrs[0];
+ i->vport_attr_cont.ac.class = &fc_vport_class.class;
+ i->vport_attr_cont.ac.match = fc_vport_match;
+ transport_container_register(&i->vport_attr_cont);
+
i->f = ft;
/* Transport uses the shost workq for scsi scanning */
@@ -1480,7 +1998,7 @@ fc_attach_transport(struct fc_function_template *ft)
i->t.eh_timed_out = fc_timed_out;
i->t.user_scan = fc_user_scan;
-
+
/*
* Setup SCSI Target Attributes.
*/
@@ -1505,6 +2023,10 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
+ if (ft->vport_create) {
+ SETUP_HOST_ATTRIBUTE_RD_NS(max_npiv_vports);
+ SETUP_HOST_ATTRIBUTE_RD_NS(npiv_vports_inuse);
+ }
SETUP_HOST_ATTRIBUTE_RD(serial_number);
SETUP_HOST_ATTRIBUTE_RD(port_id);
@@ -1520,6 +2042,10 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
if (ft->issue_fc_host_lip)
SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip);
+ if (ft->vport_create)
+ SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_create);
+ if (ft->vport_delete)
+ SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_delete);
BUG_ON(count > FC_HOST_NUM_ATTRS);
@@ -1545,6 +2071,24 @@ fc_attach_transport(struct fc_function_template *ft)
i->rport_attrs[count] = NULL;
+ /*
+ * Setup Virtual Port Attributes.
+ */
+ count=0;
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_state);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_last_state);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(node_name);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(port_name);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(roles);
+ SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_type);
+ SETUP_VPORT_ATTRIBUTE_RW(symbolic_name);
+ SETUP_VPORT_ATTRIBUTE_WR(vport_delete);
+ SETUP_VPORT_ATTRIBUTE_WR(vport_disable);
+
+ BUG_ON(count > FC_VPORT_NUM_ATTRS);
+
+ i->vport_attrs[count] = NULL;
+
return &i->t;
}
EXPORT_SYMBOL(fc_attach_transport);
@@ -1556,6 +2100,7 @@ void fc_release_transport(struct scsi_transport_template *t)
transport_container_unregister(&i->t.target_attrs);
transport_container_unregister(&i->t.host_attrs);
transport_container_unregister(&i->rport_attr_cont);
+ transport_container_unregister(&i->vport_attr_cont);
kfree(i);
}
@@ -1667,9 +2212,17 @@ fc_flush_devloss(struct Scsi_Host *shost)
void
fc_remove_host(struct Scsi_Host *shost)
{
- struct fc_rport *rport, *next_rport;
+ struct fc_vport *vport = NULL, *next_vport = NULL;
+ struct fc_rport *rport = NULL, *next_rport = NULL;
struct workqueue_struct *work_q;
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+
+ /* Remove any vports */
+ list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers)
+ fc_queue_work(shost, &vport->vport_delete_work);
/* Remove any remote ports */
list_for_each_entry_safe(rport, next_rport,
@@ -1686,6 +2239,8 @@ fc_remove_host(struct Scsi_Host *shost)
fc_queue_work(shost, &rport->rport_delete_work);
}
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
/* flush all scan work items */
scsi_flush_work(shost);
@@ -1744,7 +2299,7 @@ fc_rport_final_delete(struct work_struct *work)
unsigned long flags;
/*
- * if a scan is pending, flush the SCSI Host work_q so that
+ * if a scan is pending, flush the SCSI Host work_q so that
* that we can reclaim the rport scan work element.
*/
if (rport->flags & FC_RPORT_SCAN_PENDING)
@@ -1803,7 +2358,7 @@ fc_rport_final_delete(struct work_struct *work)
* Notes:
* This routine assumes no locks are held on entry.
**/
-struct fc_rport *
+static struct fc_rport *
fc_rport_create(struct Scsi_Host *shost, int channel,
struct fc_rport_identifiers *ids)
{
@@ -1844,7 +2399,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
spin_lock_irqsave(shost->host_lock, flags);
rport->number = fc_host->next_rport_number++;
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
rport->scsi_target_id = fc_host->next_target_id++;
else
rport->scsi_target_id = -1;
@@ -1869,7 +2424,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
transport_add_device(dev);
transport_configure_device(dev);
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
@@ -2003,7 +2558,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
/* was a target, not in roles */
if ((rport->scsi_target_id != -1) &&
- (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)))
+ (!(ids->roles & FC_PORT_ROLE_FCP_TARGET)))
return rport;
/*
@@ -2086,7 +2641,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
memset(rport->dd_data, 0,
fci->f->dd_fcrport_size);
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET) {
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
@@ -2243,11 +2798,11 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
int create = 0;
spin_lock_irqsave(shost->host_lock, flags);
- if (roles & FC_RPORT_ROLE_FCP_TARGET) {
+ if (roles & FC_PORT_ROLE_FCP_TARGET) {
if (rport->scsi_target_id == -1) {
rport->scsi_target_id = fc_host->next_target_id++;
create = 1;
- } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET))
+ } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET))
create = 1;
}
@@ -2294,7 +2849,7 @@ EXPORT_SYMBOL(fc_remote_port_rolechg);
* fc_timeout_deleted_rport - Timeout handler for a deleted remote port,
* which we blocked, and has now failed to return
* in the allotted time.
- *
+ *
* @work: rport target that failed to reappear in the allotted time.
**/
static void
@@ -2317,7 +2872,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
*/
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
(rport->scsi_target_id != -1) &&
- !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+ !(rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
dev_printk(KERN_ERR, &rport->dev,
"blocked FC remote port time out: no longer"
" a FCP target, removing starget\n");
@@ -2367,7 +2922,7 @@ fc_timeout_deleted_rport(struct work_struct *work)
*/
rport->maxframe_size = -1;
rport->supported_classes = FC_COS_UNSPECIFIED;
- rport->roles = FC_RPORT_ROLE_UNKNOWN;
+ rport->roles = FC_PORT_ROLE_UNKNOWN;
rport->port_state = FC_PORTSTATE_NOTPRESENT;
/* remove the identifiers that aren't used in the consisting binding */
@@ -2436,7 +2991,7 @@ fc_scsi_scan_rport(struct work_struct *work)
unsigned long flags;
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
- (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+ (rport->roles & FC_PORT_ROLE_FCP_TARGET)) {
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 1);
}
@@ -2447,7 +3002,227 @@ fc_scsi_scan_rport(struct work_struct *work)
}
-MODULE_AUTHOR("Martin Hicks");
+/**
+ * fc_vport_create - allocates and creates a FC virtual port.
+ * @shost: scsi host the virtual port is connected to.
+ * @channel: Channel on shost port connected to.
+ * @pdev: parent device for vport
+ * @ids: The world wide names, FC4 port roles, etc for
+ * the virtual port.
+ * @ret_vport: The pointer to the created vport.
+ *
+ * Allocates and creates the vport structure, calls the parent host
+ * to instantiate the vport, the completes w/ class and sysfs creation.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+static int
+fc_vport_create(struct Scsi_Host *shost, int channel, struct device *pdev,
+ struct fc_vport_identifiers *ids, struct fc_vport **ret_vport)
+{
+ struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ struct fc_internal *fci = to_fc_internal(shost->transportt);
+ struct fc_vport *vport;
+ struct device *dev;
+ unsigned long flags;
+ size_t size;
+ int error;
+
+ *ret_vport = NULL;
+
+ if ( ! fci->f->vport_create)
+ return -ENOENT;
+
+ size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size);
+ vport = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!vport)) {
+ printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ vport->vport_state = FC_VPORT_UNKNOWN;
+ vport->vport_last_state = FC_VPORT_UNKNOWN;
+ vport->node_name = ids->node_name;
+ vport->port_name = ids->port_name;
+ vport->roles = ids->roles;
+ vport->vport_type = ids->vport_type;
+ if (fci->f->dd_fcvport_size)
+ vport->dd_data = &vport[1];
+ vport->shost = shost;
+ vport->channel = channel;
+ vport->flags = FC_VPORT_CREATING;
+ INIT_WORK(&vport->vport_delete_work, fc_vport_sched_delete);
+
+ spin_lock_irqsave(shost->host_lock, flags);
+
+ if (fc_host->npiv_vports_inuse >= fc_host->max_npiv_vports) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ kfree(vport);
+ return -ENOSPC;
+ }
+ fc_host->npiv_vports_inuse++;
+ vport->number = fc_host->next_vport_number++;
+ list_add_tail(&vport->peers, &fc_host->vports);
+ get_device(&shost->shost_gendev); /* for fc_host->vport list */
+
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ dev = &vport->dev;
+ device_initialize(dev); /* takes self reference */
+ dev->parent = get_device(pdev); /* takes parent reference */
+ dev->release = fc_vport_dev_release;
+ sprintf(dev->bus_id, "vport-%d:%d-%d",
+ shost->host_no, channel, vport->number);
+ transport_setup_device(dev);
+
+ error = device_add(dev);
+ if (error) {
+ printk(KERN_ERR "FC Virtual Port device_add failed\n");
+ goto delete_vport;
+ }
+ transport_add_device(dev);
+ transport_configure_device(dev);
+
+ error = fci->f->vport_create(vport, ids->disable);
+ if (error) {
+ printk(KERN_ERR "FC Virtual Port LLDD Create failed\n");
+ goto delete_vport_all;
+ }
+
+ /*
+ * if the parent isn't the physical adapter's Scsi_Host, ensure
+ * the Scsi_Host at least contains ia symlink to the vport.
+ */
+ if (pdev != &shost->shost_gendev) {
+ error = sysfs_create_link(&shost->shost_gendev.kobj,
+ &dev->kobj, dev->bus_id);
+ if (error)
+ printk(KERN_ERR
+ "%s: Cannot create vport symlinks for "
+ "%s, err=%d\n",
+ __FUNCTION__, dev->bus_id, error);
+ }
+ spin_lock_irqsave(shost->host_lock, flags);
+ vport->flags &= ~FC_VPORT_CREATING;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ dev_printk(KERN_NOTICE, pdev,
+ "%s created via shost%d channel %d\n", dev->bus_id,
+ shost->host_no, channel);
+
+ *ret_vport = vport;
+
+ return 0;
+
+delete_vport_all:
+ transport_remove_device(dev);
+ device_del(dev);
+delete_vport:
+ transport_destroy_device(dev);
+ spin_lock_irqsave(shost->host_lock, flags);
+ list_del(&vport->peers);
+ put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ fc_host->npiv_vports_inuse--;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ put_device(dev->parent);
+ kfree(vport);
+
+ return error;
+}
+
+
+/**
+ * fc_vport_terminate - Admin App or LLDD requests termination of a vport
+ * @vport: fc_vport to be terminated
+ *
+ * Calls the LLDD vport_delete() function, then deallocates and removes
+ * the vport from the shost and object tree.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+int
+fc_vport_terminate(struct fc_vport *vport)
+{
+ struct Scsi_Host *shost = vport_to_shost(vport);
+ struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+ struct device *dev = &vport->dev;
+ unsigned long flags;
+ int stat;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ if (vport->flags & FC_VPORT_CREATING) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return -EBUSY;
+ }
+ if (vport->flags & (FC_VPORT_DEL)) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return -EALREADY;
+ }
+ vport->flags |= FC_VPORT_DELETING;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (i->f->vport_delete)
+ stat = i->f->vport_delete(vport);
+ else
+ stat = -ENOENT;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ vport->flags &= ~FC_VPORT_DELETING;
+ if (!stat) {
+ vport->flags |= FC_VPORT_DELETED;
+ list_del(&vport->peers);
+ fc_host->npiv_vports_inuse--;
+ put_device(&shost->shost_gendev); /* for fc_host->vport list */
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ if (stat)
+ return stat;
+
+ if (dev->parent != &shost->shost_gendev)
+ sysfs_remove_link(&shost->shost_gendev.kobj, dev->bus_id);
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+
+ /*
+ * Removing our self-reference should mean our
+ * release function gets called, which will drop the remaining
+ * parent reference and free the data structure.
+ */
+ put_device(dev); /* for self-reference */
+
+ return 0; /* SUCCESS */
+}
+EXPORT_SYMBOL(fc_vport_terminate);
+
+/**
+ * fc_vport_sched_delete - workq-based delete request for a vport
+ *
+ * @work: vport to be deleted.
+ **/
+static void
+fc_vport_sched_delete(struct work_struct *work)
+{
+ struct fc_vport *vport =
+ container_of(work, struct fc_vport, vport_delete_work);
+ int stat;
+
+ stat = fc_vport_terminate(vport);
+ if (stat)
+ dev_printk(KERN_ERR, vport->dev.parent,
+ "%s: %s could not be deleted created via "
+ "shost%d channel %d - error %d\n", __FUNCTION__,
+ vport->dev.bus_id, vport->shost->host_no,
+ vport->channel, stat);
+}
+
+
+/* Original Author: Martin Hicks */
+MODULE_AUTHOR("James Smart");
MODULE_DESCRIPTION("FC Transport Attributes");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index caf1836bbeca..34c1860a259d 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -30,9 +30,9 @@
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/iscsi_if.h>
-#define ISCSI_SESSION_ATTRS 11
+#define ISCSI_SESSION_ATTRS 15
#define ISCSI_CONN_ATTRS 11
-#define ISCSI_HOST_ATTRS 0
+#define ISCSI_HOST_ATTRS 4
#define ISCSI_TRANSPORT_VERSION "2.0-724"
struct iscsi_internal {
@@ -609,12 +609,10 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi,
int t = done ? NLMSG_DONE : type;
skb = alloc_skb(len, GFP_ATOMIC);
- /*
- * FIXME:
- * user is supposed to react on iferror == -ENOMEM;
- * see iscsi_if_rx().
- */
- BUG_ON(!skb);
+ if (!skb) {
+ printk(KERN_ERR "Could not allocate skb to send reply.\n");
+ return -ENOMEM;
+ }
nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0);
nlh->nlmsg_flags = flags;
@@ -816,6 +814,8 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
uint32_t hostno;
session = transport->create_session(transport, &priv->t,
+ ev->u.c_session.cmds_max,
+ ev->u.c_session.queue_depth,
ev->u.c_session.initial_cmdsn,
&hostno);
if (!session)
@@ -947,15 +947,50 @@ static int
iscsi_tgt_dscvr(struct iscsi_transport *transport,
struct iscsi_uevent *ev)
{
+ struct Scsi_Host *shost;
struct sockaddr *dst_addr;
+ int err;
if (!transport->tgt_dscvr)
return -EINVAL;
+ shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "target discovery could not find host no %u\n",
+ ev->u.tgt_dscvr.host_no);
+ return -ENODEV;
+ }
+
+
dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
- return transport->tgt_dscvr(ev->u.tgt_dscvr.type,
- ev->u.tgt_dscvr.host_no,
- ev->u.tgt_dscvr.enable, dst_addr);
+ err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
+ ev->u.tgt_dscvr.enable, dst_addr);
+ scsi_host_put(shost);
+ return err;
+}
+
+static int
+iscsi_set_host_param(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ char *data = (char*)ev + sizeof(*ev);
+ struct Scsi_Host *shost;
+ int err;
+
+ if (!transport->set_host_param)
+ return -ENOSYS;
+
+ shost = scsi_host_lookup(ev->u.set_host_param.host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "set_host_param could not find host no %u\n",
+ ev->u.set_host_param.host_no);
+ return -ENODEV;
+ }
+
+ err = transport->set_host_param(shost, ev->u.set_host_param.param,
+ data, ev->u.set_host_param.len);
+ scsi_host_put(shost);
+ return err;
}
static int
@@ -1049,8 +1084,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case ISCSI_UEVENT_TGT_DSCVR:
err = iscsi_tgt_dscvr(transport, ev);
break;
+ case ISCSI_UEVENT_SET_HOST_PARAM:
+ err = iscsi_set_host_param(transport, ev);
+ break;
default:
- err = -EINVAL;
+ err = -ENOSYS;
break;
}
@@ -1160,30 +1198,37 @@ iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
/*
* iSCSI session attrs
*/
-#define iscsi_session_attr_show(param) \
+#define iscsi_session_attr_show(param, perm) \
static ssize_t \
show_session_param_##param(struct class_device *cdev, char *buf) \
{ \
struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
struct iscsi_transport *t = session->transport; \
+ \
+ if (perm && !capable(CAP_SYS_ADMIN)) \
+ return -EACCES; \
return t->get_session_param(session, param, buf); \
}
-#define iscsi_session_attr(field, param) \
- iscsi_session_attr_show(param) \
+#define iscsi_session_attr(field, param, perm) \
+ iscsi_session_attr_show(param, perm) \
static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
NULL);
-iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME);
-iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN);
-iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T);
-iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN);
-iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST);
-iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST);
-iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN);
-iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN);
-iscsi_session_attr(erl, ISCSI_PARAM_ERL);
-iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT);
+iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);
+iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);
+iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);
+iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);
+iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);
+iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);
+iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);
+iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);
+iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);
+iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);
+iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
+iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
+iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
+iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
#define iscsi_priv_session_attr_show(field, format) \
static ssize_t \
@@ -1199,6 +1244,28 @@ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
NULL)
iscsi_priv_session_attr(recovery_tmo, "%d");
+/*
+ * iSCSI host attrs
+ */
+#define iscsi_host_attr_show(param) \
+static ssize_t \
+show_host_param_##param(struct class_device *cdev, char *buf) \
+{ \
+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
+ struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
+ return priv->iscsi_transport->get_host_param(shost, param, buf); \
+}
+
+#define iscsi_host_attr(field, param) \
+ iscsi_host_attr_show(param) \
+static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \
+ NULL);
+
+iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);
+iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
+iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
+iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
+
#define SETUP_PRIV_SESSION_RD_ATTR(field) \
do { \
priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
@@ -1222,6 +1289,14 @@ do { \
} \
} while (0)
+#define SETUP_HOST_RD_ATTR(field, param_flag) \
+do { \
+ if (tt->host_param_mask & param_flag) { \
+ priv->host_attrs[count] = &class_device_attr_host_##field; \
+ count++; \
+ } \
+} while (0)
+
static int iscsi_session_match(struct attribute_container *cont,
struct device *dev)
{
@@ -1323,9 +1398,16 @@ iscsi_register_transport(struct iscsi_transport *tt)
priv->t.host_attrs.ac.class = &iscsi_host_class.class;
priv->t.host_attrs.ac.match = iscsi_host_match;
priv->t.host_size = sizeof(struct iscsi_host);
- priv->host_attrs[0] = NULL;
transport_container_register(&priv->t.host_attrs);
+ SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);
+ SETUP_HOST_RD_ATTR(ipaddress, ISCSI_HOST_IPADDRESS);
+ SETUP_HOST_RD_ATTR(hwaddress, ISCSI_HOST_HWADDRESS);
+ SETUP_HOST_RD_ATTR(initiatorname, ISCSI_HOST_INITIATOR_NAME);
+ BUG_ON(count > ISCSI_HOST_ATTRS);
+ priv->host_attrs[count] = NULL;
+ count = 0;
+
/* connection parameters */
priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
priv->conn_cont.ac.class = &iscsi_connection_class.class;
@@ -1364,6 +1446,10 @@ iscsi_register_transport(struct iscsi_transport *tt)
SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
+ SETUP_SESSION_RD_ATTR(password, ISCSI_USERNAME);
+ SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
+ SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
+ SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
BUG_ON(count > ISCSI_SESSION_ATTRS);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index b2ef71a86292..3120f4b3a11a 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -29,6 +29,8 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/bsg.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -40,6 +42,7 @@
struct sas_host_attrs {
struct list_head rphy_list;
struct mutex lock;
+ struct request_queue *q;
u32 next_target_id;
u32 next_expander_id;
int next_port_id;
@@ -152,6 +155,106 @@ static struct {
sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
+static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
+ struct sas_rphy *rphy)
+{
+ struct request *req;
+ int ret;
+ int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
+
+ while (!blk_queue_plugged(q)) {
+ req = elv_next_request(q);
+ if (!req)
+ break;
+
+ blkdev_dequeue_request(req);
+
+ spin_unlock_irq(q->queue_lock);
+
+ handler = to_sas_internal(shost->transportt)->f->smp_handler;
+ ret = handler(shost, rphy, req);
+
+ spin_lock_irq(q->queue_lock);
+
+ req->end_io(req, ret);
+ }
+}
+
+static void sas_host_smp_request(struct request_queue *q)
+{
+ sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL);
+}
+
+static void sas_non_host_smp_request(struct request_queue *q)
+{
+ struct sas_rphy *rphy = q->queuedata;
+ sas_smp_request(q, rphy_to_shost(rphy), rphy);
+}
+
+static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
+{
+ struct request_queue *q;
+ int error;
+ struct device *dev;
+ char namebuf[BUS_ID_SIZE];
+ const char *name;
+
+ if (!to_sas_internal(shost->transportt)->f->smp_handler) {
+ printk("%s can't handle SMP requests\n", shost->hostt->name);
+ return 0;
+ }
+
+ if (rphy) {
+ q = blk_init_queue(sas_non_host_smp_request, NULL);
+ dev = &rphy->dev;
+ name = dev->bus_id;
+ } 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;
+ }
+ if (!q)
+ return -ENOMEM;
+
+ error = bsg_register_queue(q, dev, name);
+ if (error) {
+ blk_cleanup_queue(q);
+ return -ENOMEM;
+ }
+
+ if (rphy)
+ rphy->q = q;
+ else
+ to_sas_host_attrs(shost)->q = q;
+
+ if (rphy)
+ q->queuedata = rphy;
+ else
+ q->queuedata = shost;
+
+ set_bit(QUEUE_FLAG_BIDI, &q->queue_flags);
+
+ return 0;
+}
+
+static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
+{
+ struct request_queue *q;
+
+ if (rphy)
+ q = rphy->q;
+ else
+ q = to_sas_host_attrs(shost)->q;
+
+ if (!q)
+ return;
+
+ bsg_unregister_queue(q);
+ blk_cleanup_queue(q);
+}
+
/*
* SAS host attributes
*/
@@ -167,11 +270,26 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
sas_host->next_target_id = 0;
sas_host->next_expander_id = 0;
sas_host->next_port_id = 0;
+
+ if (sas_bsg_initialize(shost, NULL))
+ dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",
+ shost->host_no);
+
+ return 0;
+}
+
+static int sas_host_remove(struct transport_container *tc, struct device *dev,
+ struct class_device *cdev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+
+ sas_bsg_remove(shost, NULL);
+
return 0;
}
static DECLARE_TRANSPORT_CLASS(sas_host_class,
- "sas_host", sas_host_setup, NULL, NULL);
+ "sas_host", sas_host_setup, sas_host_remove, NULL);
static int sas_host_match(struct attribute_container *cont,
struct device *dev)
@@ -1287,6 +1405,9 @@ int sas_rphy_add(struct sas_rphy *rphy)
return error;
transport_add_device(&rphy->dev);
transport_configure_device(&rphy->dev);
+ if (sas_bsg_initialize(shost, rphy))
+ printk("fail to a bsg device %s\n", rphy->dev.bus_id);
+
mutex_lock(&sas_host->lock);
list_add_tail(&rphy->list, &sas_host->rphy_list);
@@ -1329,6 +1450,8 @@ void sas_rphy_free(struct sas_rphy *rphy)
list_del(&rphy->list);
mutex_unlock(&sas_host->lock);
+ sas_bsg_remove(shost, rphy);
+
transport_destroy_device(dev);
put_device(dev);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3d8c9cb24f91..424d557284a9 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -684,7 +684,7 @@ static int sd_ioctl(struct inode * inode, struct file * filp,
case SCSI_IOCTL_GET_BUS_NUMBER:
return scsi_ioctl(sdp, cmd, p);
default:
- error = scsi_cmd_ioctl(filp, disk, cmd, p);
+ error = scsi_cmd_ioctl(filp, disk->queue, disk, cmd, p);
if (error != -ENOTTY)
return error;
}
@@ -1515,7 +1515,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
if (!scsi_device_online(sdp))
goto out;
- buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL | __GFP_DMA);
+ buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL);
if (!buffer) {
sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory "
"allocation failure.\n");
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index ff62e9708e1c..ce80fa9ad815 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -420,7 +420,7 @@ static inline void borken_wait (void)
#define ULOOP( i ) for (clock = i*8;;)
#define TIMEOUT (!(clock--))
-int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
+static int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
{
struct Scsi_Host *instance;
int i, j;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 0c691a60a756..85d38940a6c9 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1842,7 +1842,7 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
int blk_size = buff_size;
struct page *p = NULL;
- if ((blk_size < 0) || (!sfp))
+ if (blk_size < 0)
return -EFAULT;
if (0 == blk_size)
++blk_size; /* don't know why */
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 018c65f73ac4..d63d229e2323 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -100,7 +100,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
{
struct Scsi_Host * host = NULL;
struct NCR_700_Host_Parameters *hostdata =
- kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
printk(KERN_NOTICE "sim710: %s\n", dev->bus_id);
printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
@@ -110,7 +110,6 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
printk(KERN_ERR "sim710: Failed to allocate host data\n");
goto out;
}
- memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
if(request_region(base_addr, 64, "sim710") == NULL) {
printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n",
@@ -139,6 +138,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
goto out_put_host;
}
+ dev_set_drvdata(dev, host);
scsi_scan_host(host);
return 0;
@@ -156,7 +156,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
static __devexit int
sim710_device_remove(struct device *dev)
{
- struct Scsi_Host *host = dev_to_shost(dev);
+ struct Scsi_Host *host = dev_get_drvdata(dev);
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)host->hostdata[0];
diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c
index a7dfb65fb842..0a6b45b1b003 100644
--- a/drivers/scsi/sni_53c710.c
+++ b/drivers/scsi/sni_53c710.c
@@ -84,7 +84,7 @@ static int __init snirm710_probe(struct platform_device *dev)
hostdata->dev = &dev->dev;
dma_set_mask(&dev->dev, DMA_32BIT_MASK);
- hostdata->base = ioremap_nocache(CPHYSADDR(base), 0x100);
+ hostdata->base = ioremap_nocache(base, 0x100);
hostdata->differential = 0;
hostdata->clock = SNIRM710_CLOCK;
@@ -141,13 +141,7 @@ static struct platform_driver snirm710_driver = {
static int __init snirm710_init(void)
{
- int err;
-
- if ((err = platform_driver_register(&snirm710_driver))) {
- printk(KERN_ERR "Driver registration failed\n");
- return err;
- }
- return 0;
+ return platform_driver_register(&snirm710_driver);
}
static void __exit snirm710_exit(void)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index f9a52af7f5b4..e7b6a7fde1cb 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -175,7 +175,7 @@ static void scsi_cd_put(struct scsi_cd *cd)
* an inode for that to work, and we do not always have one.
*/
-int sr_media_change(struct cdrom_device_info *cdi, int slot)
+static int sr_media_change(struct cdrom_device_info *cdi, int slot)
{
struct scsi_cd *cd = cdi->handle;
int retval;
@@ -885,7 +885,11 @@ static int __init init_sr(void)
rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
if (rc)
return rc;
- return scsi_register_driver(&sr_template.gendrv);
+ rc = scsi_register_driver(&sr_template.gendrv);
+ if (rc)
+ unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
+
+ return rc;
}
static void __exit exit_sr(void)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 55bfeccf68a2..a4f7b8465773 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -3549,7 +3549,8 @@ static int st_ioctl(struct inode *inode, struct file *file,
!capable(CAP_SYS_RAWIO))
i = -EPERM;
else
- i = scsi_cmd_ioctl(file, STp->disk, cmd_in, p);
+ i = scsi_cmd_ioctl(file, STp->disk->queue,
+ STp->disk, cmd_in, p);
if (i != -ENOTTY)
return i;
break;
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 9ac83abc4028..72f6d8015358 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -395,53 +395,34 @@ static struct req_msg *stex_alloc_req(struct st_hba *hba)
static int stex_map_sg(struct st_hba *hba,
struct req_msg *req, struct st_ccb *ccb)
{
- struct pci_dev *pdev = hba->pdev;
struct scsi_cmnd *cmd;
- dma_addr_t dma_handle;
- struct scatterlist *src;
+ struct scatterlist *sg;
struct st_sgtable *dst;
- int i;
+ int i, nseg;
cmd = ccb->cmd;
dst = (struct st_sgtable *)req->variable;
dst->max_sg_count = cpu_to_le16(ST_MAX_SG);
- dst->sz_in_byte = cpu_to_le32(cmd->request_bufflen);
-
- if (cmd->use_sg) {
- int n_elem;
+ dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd));
- src = (struct scatterlist *) cmd->request_buffer;
- n_elem = pci_map_sg(pdev, src,
- cmd->use_sg, cmd->sc_data_direction);
- if (n_elem <= 0)
- return -EIO;
+ nseg = scsi_dma_map(cmd);
+ if (nseg < 0)
+ return -EIO;
+ if (nseg) {
+ ccb->sg_count = nseg;
+ dst->sg_count = cpu_to_le16((u16)nseg);
- ccb->sg_count = n_elem;
- dst->sg_count = cpu_to_le16((u16)n_elem);
-
- for (i = 0; i < n_elem; i++, src++) {
- dst->table[i].count = cpu_to_le32((u32)sg_dma_len(src));
+ scsi_for_each_sg(cmd, sg, nseg, i) {
+ dst->table[i].count = cpu_to_le32((u32)sg_dma_len(sg));
dst->table[i].addr =
- cpu_to_le32(sg_dma_address(src) & 0xffffffff);
+ cpu_to_le32(sg_dma_address(sg) & 0xffffffff);
dst->table[i].addr_hi =
- cpu_to_le32((sg_dma_address(src) >> 16) >> 16);
+ cpu_to_le32((sg_dma_address(sg) >> 16) >> 16);
dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST;
}
dst->table[--i].ctrl |= SG_CF_EOT;
- return 0;
}
- dma_handle = pci_map_single(pdev, cmd->request_buffer,
- cmd->request_bufflen, cmd->sc_data_direction);
- cmd->SCp.dma_handle = dma_handle;
-
- ccb->sg_count = 1;
- dst->sg_count = cpu_to_le16(1);
- dst->table[0].addr = cpu_to_le32(dma_handle & 0xffffffff);
- dst->table[0].addr_hi = cpu_to_le32((dma_handle >> 16) >> 16);
- dst->table[0].count = cpu_to_le32((u32)cmd->request_bufflen);
- dst->table[0].ctrl = SG_CF_EOT | SG_CF_64B | SG_CF_HOST;
-
return 0;
}
@@ -451,24 +432,24 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
size_t lcount;
size_t len;
void *s, *d, *base = NULL;
- if (*count > cmd->request_bufflen)
- *count = cmd->request_bufflen;
+ size_t offset;
+
+ if (*count > scsi_bufflen(cmd))
+ *count = scsi_bufflen(cmd);
lcount = *count;
while (lcount) {
len = lcount;
s = (void *)src;
- if (cmd->use_sg) {
- size_t offset = *count - lcount;
- s += offset;
- base = scsi_kmap_atomic_sg(cmd->request_buffer,
- sg_count, &offset, &len);
- if (base == NULL) {
- *count -= lcount;
- return;
- }
- d = base + offset;
- } else
- d = cmd->request_buffer;
+
+ offset = *count - lcount;
+ s += offset;
+ base = scsi_kmap_atomic_sg(scsi_sglist(cmd),
+ sg_count, &offset, &len);
+ if (!base) {
+ *count -= lcount;
+ return;
+ }
+ d = base + offset;
if (direction == ST_TO_CMD)
memcpy(d, s, len);
@@ -476,30 +457,24 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
memcpy(s, d, len);
lcount -= len;
- if (cmd->use_sg)
- scsi_kunmap_atomic_sg(base);
+ scsi_kunmap_atomic_sg(base);
}
}
static int stex_direct_copy(struct scsi_cmnd *cmd,
const void *src, size_t count)
{
- struct st_hba *hba = (struct st_hba *) &cmd->device->host->hostdata[0];
size_t cp_len = count;
int n_elem = 0;
- if (cmd->use_sg) {
- n_elem = pci_map_sg(hba->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- if (n_elem <= 0)
- return 0;
- }
+ n_elem = scsi_dma_map(cmd);
+ if (n_elem < 0)
+ return 0;
stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
- if (cmd->use_sg)
- pci_unmap_sg(hba->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
+ scsi_dma_unmap(cmd);
+
return cp_len == count;
}
@@ -678,18 +653,6 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
return 0;
}
-static void stex_unmap_sg(struct st_hba *hba, struct scsi_cmnd *cmd)
-{
- if (cmd->sc_data_direction != DMA_NONE) {
- if (cmd->use_sg)
- pci_unmap_sg(hba->pdev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- else
- pci_unmap_single(hba->pdev, cmd->SCp.dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
-}
-
static void stex_scsi_done(struct st_ccb *ccb)
{
struct scsi_cmnd *cmd = ccb->cmd;
@@ -756,8 +719,8 @@ static void stex_ys_commands(struct st_hba *hba,
if (ccb->cmd->cmnd[0] == MGT_CMD &&
resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
- ccb->cmd->request_bufflen =
- le32_to_cpu(*(__le32 *)&resp->variable[0]);
+ scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) -
+ le32_to_cpu(*(__le32 *)&resp->variable[0]));
return;
}
@@ -855,7 +818,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
stex_controller_info(hba, ccb);
- stex_unmap_sg(hba, ccb->cmd);
+ scsi_dma_unmap(ccb->cmd);
stex_scsi_done(ccb);
hba->out_req_cnt--;
} else if (ccb->req_type & PASSTHRU_REQ_TYPE) {
@@ -1028,7 +991,7 @@ static int stex_abort(struct scsi_cmnd *cmd)
}
fail_out:
- stex_unmap_sg(hba, cmd);
+ scsi_dma_unmap(cmd);
hba->wait_ccb->req = NULL; /* nullify the req's future return */
hba->wait_ccb = NULL;
result = FAILED;
diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c
index bbeb2451d32f..2c87db98cdfb 100644
--- a/drivers/scsi/sun_esp.c
+++ b/drivers/scsi/sun_esp.c
@@ -493,7 +493,7 @@ static int __devinit esp_sbus_probe_one(struct device *dev,
goto fail;
host->max_id = (hme ? 16 : 8);
- esp = host_to_esp(host);
+ esp = shost_priv(host);
esp->host = host;
esp->dev = esp_dev;
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 2ca950582bc3..92bfaeafe30d 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -332,8 +332,7 @@ static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
int i;
unsigned long flags = 0;
unsigned char status_reg, pio_int_reg, int_reg;
- struct scatterlist *sglist;
- unsigned int sgcount;
+ struct scatterlist *sg;
unsigned int tot_trans = 0;
/* We search the base address of the host adapter which caused the interrupt */
@@ -429,19 +428,15 @@ static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
{
current_command->SCp.phase = data_out;
outb(FLUSH_FIFO, base + COMMAND_REG);
- sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ sym53c416_set_transfer_counter(base,
+ scsi_bufflen(current_command));
outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
- if(!current_command->use_sg)
- tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
- else
- {
- sgcount = current_command->use_sg;
- sglist = current_command->request_buffer;
- while(sgcount--)
- {
- tot_trans += sym53c416_write(base, SG_ADDRESS(sglist), sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(current_command,
+ sg, scsi_sg_count(current_command), i) {
+ tot_trans += sym53c416_write(base,
+ SG_ADDRESS(sg),
+ sg->length);
}
if(tot_trans < current_command->underflow)
printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
@@ -455,19 +450,16 @@ static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
{
current_command->SCp.phase = data_in;
outb(FLUSH_FIFO, base + COMMAND_REG);
- sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+ sym53c416_set_transfer_counter(base,
+ scsi_bufflen(current_command));
+
outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
- if(!current_command->use_sg)
- tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
- else
- {
- sgcount = current_command->use_sg;
- sglist = current_command->request_buffer;
- while(sgcount--)
- {
- tot_trans += sym53c416_read(base, SG_ADDRESS(sglist), sglist->length);
- sglist++;
- }
+
+ scsi_for_each_sg(current_command,
+ sg, scsi_sg_count(current_command), i) {
+ tot_trans += sym53c416_read(base,
+ SG_ADDRESS(sg),
+ sg->length);
}
if(tot_trans < current_command->underflow)
printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 4d78c7e87cca..15a51459c81f 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -146,41 +146,17 @@ struct sym_ucmd { /* Override the SCSI pointer structure */
static void __unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
{
- int dma_dir = cmd->sc_data_direction;
+ if (SYM_UCMD_PTR(cmd)->data_mapped)
+ scsi_dma_unmap(cmd);
- switch(SYM_UCMD_PTR(cmd)->data_mapped) {
- case 2:
- pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
- break;
- case 1:
- pci_unmap_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
- cmd->request_bufflen, dma_dir);
- break;
- }
SYM_UCMD_PTR(cmd)->data_mapped = 0;
}
-static dma_addr_t __map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
-{
- dma_addr_t mapping;
- int dma_dir = cmd->sc_data_direction;
-
- mapping = pci_map_single(pdev, cmd->request_buffer,
- cmd->request_bufflen, dma_dir);
- if (mapping) {
- SYM_UCMD_PTR(cmd)->data_mapped = 1;
- SYM_UCMD_PTR(cmd)->data_mapping = mapping;
- }
-
- return mapping;
-}
-
static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
{
int use_sg;
- int dma_dir = cmd->sc_data_direction;
- use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
+ use_sg = scsi_dma_map(cmd);
if (use_sg > 0) {
SYM_UCMD_PTR(cmd)->data_mapped = 2;
SYM_UCMD_PTR(cmd)->data_mapping = use_sg;
@@ -191,8 +167,6 @@ static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
#define unmap_scsi_data(np, cmd) \
__unmap_scsi_data(np->s.device, cmd)
-#define map_scsi_single_data(np, cmd) \
- __map_scsi_single_data(np->s.device, cmd)
#define map_scsi_sg_data(np, cmd) \
__map_scsi_sg_data(np->s.device, cmd)
/*
@@ -322,55 +296,20 @@ void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
*/
cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status);
}
- cmd->resid = resid;
+ scsi_set_resid(cmd, resid);
cmd->result = (drv_status << 24) + (cam_status << 16) + scsi_status;
}
-
-/*
- * Build the scatter/gather array for an I/O.
- */
-
-static int sym_scatter_no_sglist(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
-{
- struct sym_tblmove *data = &cp->phys.data[SYM_CONF_MAX_SG-1];
- int segment;
- unsigned int len = cmd->request_bufflen;
-
- if (len) {
- dma_addr_t baddr = map_scsi_single_data(np, cmd);
- if (baddr) {
- if (len & 1) {
- struct sym_tcb *tp = &np->target[cp->target];
- if (tp->head.wval & EWS) {
- len++;
- cp->odd_byte_adjustment++;
- }
- }
- cp->data_len = len;
- sym_build_sge(np, data, baddr, len);
- segment = 1;
- } else {
- segment = -2;
- }
- } else {
- segment = 0;
- }
-
- return segment;
-}
-
static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
{
int segment;
- int use_sg = (int) cmd->use_sg;
+ int use_sg;
cp->data_len = 0;
- if (!use_sg)
- segment = sym_scatter_no_sglist(np, cp, cmd);
- else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
- struct scatterlist *scatter = (struct scatterlist *)cmd->request_buffer;
+ use_sg = map_scsi_sg_data(np, cmd);
+ if (use_sg > 0) {
+ struct scatterlist *sg;
struct sym_tcb *tp = &np->target[cp->target];
struct sym_tblmove *data;
@@ -381,9 +320,9 @@ static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd
data = &cp->phys.data[SYM_CONF_MAX_SG - use_sg];
- for (segment = 0; segment < use_sg; segment++) {
- dma_addr_t baddr = sg_dma_address(&scatter[segment]);
- unsigned int len = sg_dma_len(&scatter[segment]);
+ scsi_for_each_sg(cmd, sg, use_sg, segment) {
+ dma_addr_t baddr = sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
if ((len & 1) && (tp->head.wval & EWS)) {
len++;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
index e022d3c71b59..0f097ba4f712 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -255,7 +255,7 @@ sym_get_cam_status(struct scsi_cmnd *cmd)
*/
static __inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid)
{
- cmd->resid = resid;
+ scsi_set_resid(cmd, resid);
cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f));
}
void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid);
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index e7b85e832eb5..5db1520f8ba9 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -457,28 +457,21 @@ static int dc390_pci_map (struct dc390_srb* pSRB)
error = 1;
DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __FUNCTION__, pcmd->sense_buffer, cmdp->saved_dma_handle));
/* Map SG list */
- } else if (pcmd->use_sg) {
- pSRB->pSegmentList = (struct scatterlist *) pcmd->request_buffer;
- pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, pcmd->use_sg,
- pcmd->sc_data_direction);
+ } else if (scsi_sg_count(pcmd)) {
+ int nseg;
+
+ nseg = scsi_dma_map(pcmd);
+
+ pSRB->pSegmentList = scsi_sglist(pcmd);
+ pSRB->SGcount = nseg;
+
/* TODO: error handling */
- if (!pSRB->SGcount)
+ if (nseg < 0)
error = 1;
DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\
- __FUNCTION__, pcmd->request_buffer, pSRB->SGcount, pcmd->use_sg));
+ __FUNCTION__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd)));
/* Map single segment */
- } else if (pcmd->request_buffer && pcmd->request_bufflen) {
- pSRB->pSegmentList = dc390_sg_build_single(&pSRB->Segmentx, pcmd->request_buffer, pcmd->request_bufflen);
- pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, 1,
- pcmd->sc_data_direction);
- cmdp->saved_dma_handle = sg_dma_address(pSRB->pSegmentList);
-
- /* TODO: error handling */
- if (pSRB->SGcount != 1)
- error = 1;
- DEBUG1(printk("%s(): Mapped request buffer %p at %x\n", __FUNCTION__, pcmd->request_buffer, cmdp->saved_dma_handle));
- /* No mapping !? */
- } else
+ } else
pSRB->SGcount = 0;
return error;
@@ -494,12 +487,10 @@ static void dc390_pci_unmap (struct dc390_srb* pSRB)
if (pSRB->SRBFlag) {
pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE);
DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle));
- } else if (pcmd->use_sg) {
- pci_unmap_sg(pdev, pcmd->request_buffer, pcmd->use_sg, pcmd->sc_data_direction);
- DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n", __FUNCTION__, pcmd->request_buffer, pcmd->use_sg));
- } else if (pcmd->request_buffer && pcmd->request_bufflen) {
- pci_unmap_sg(pdev, &pSRB->Segmentx, 1, pcmd->sc_data_direction);
- DEBUG1(printk("%s(): Unmapped request buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle));
+ } else {
+ scsi_dma_unmap(pcmd);
+ DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n",
+ __FUNCTION__, scsi_sglist(pcmd), scsi_sg_count(pcmd)));
}
}
@@ -1153,9 +1144,9 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
struct scatterlist *psgl;
pSRB->TotalXferredLen = 0;
pSRB->SGIndex = 0;
- if (pcmd->use_sg) {
+ if (scsi_sg_count(pcmd)) {
size_t saved;
- pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
+ pSRB->pSegmentList = scsi_sglist(pcmd);
psgl = pSRB->pSegmentList;
//dc390_pci_sync(pSRB);
@@ -1179,12 +1170,6 @@ dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
- } else if(pcmd->request_buffer) {
- //dc390_pci_sync(pSRB);
-
- sg_dma_len(&pSRB->Segmentx) = pcmd->request_bufflen - pSRB->Saved_Ptr;
- pSRB->SGcount = 1;
- pSRB->pSegmentList = (struct scatterlist *) &pSRB->Segmentx;
} else {
pSRB->SGcount = 0;
printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n");
@@ -1579,7 +1564,8 @@ dc390_Disconnect( struct dc390_acb* pACB )
if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
!(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
{ /* Selection time out */
- pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+ pSRB->AdaptStatus = H_SEL_TIMEOUT;
+ pSRB->TargetStatus = 0;
goto disc1;
}
else if (!(pSRB->SRBState & SRB_DISCONNECT) && (pSRB->SRBState & SRB_COMPLETED))
@@ -1612,7 +1598,7 @@ dc390_Reselect( struct dc390_acb* pACB )
if( !( pACB->scan_devices ) )
{
struct scsi_cmnd *pcmd = pSRB->pcmd;
- pcmd->resid = pcmd->request_bufflen;
+ scsi_set_resid(pcmd, scsi_bufflen(pcmd));
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
dc390_Going_remove(pDCB, pSRB);
dc390_Free_insert(pACB, pSRB);
@@ -1695,7 +1681,6 @@ dc390_RequestSense(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_
pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN));
pSRB->SRBFlag |= AUTO_REQSENSE;
- pSRB->SavedSGCount = pcmd->use_sg;
pSRB->SavedTotXLen = pSRB->TotalXferredLen;
pSRB->AdaptStatus = 0;
pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */
@@ -1728,22 +1713,21 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
{ /* Last command was a Request Sense */
pSRB->SRBFlag &= ~AUTO_REQSENSE;
pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = CHECK_CONDITION << 1;
+ pSRB->TargetStatus = SAM_STAT_CHECK_CONDITION;
//pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status);
- if (status == (CHECK_CONDITION << 1))
+ if (status == SAM_STAT_CHECK_CONDITION)
pcmd->result = MK_RES_LNX(0, DID_BAD_TARGET, 0, /*CHECK_CONDITION*/0);
else /* Retry */
{
if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */)
{
/* Don't retry on TEST_UNIT_READY */
- pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION);
+ pcmd->result = MK_RES_LNX(DRIVER_SENSE, DID_OK, 0, SAM_STAT_CHECK_CONDITION);
REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\
(u32) pcmd->result, (u32) pSRB->TotalXferredLen));
} else {
SET_RES_DRV(pcmd->result, DRIVER_SENSE);
- pcmd->use_sg = pSRB->SavedSGCount;
//pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8);
DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
@@ -1754,7 +1738,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
}
if( status )
{
- if( status_byte(status) == CHECK_CONDITION )
+ if (status == SAM_STAT_CHECK_CONDITION)
{
if (dc390_RequestSense(pACB, pDCB, pSRB)) {
SET_RES_DID(pcmd->result, DID_ERROR);
@@ -1762,22 +1746,14 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
}
return;
}
- else if( status_byte(status) == QUEUE_FULL )
+ else if (status == SAM_STAT_TASK_SET_FULL)
{
scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1);
- pcmd->use_sg = pSRB->SavedSGCount;
DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
pSRB->TotalXferredLen = 0;
SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
}
- else if(status == SCSI_STAT_SEL_TIMEOUT)
- {
- pSRB->AdaptStatus = H_SEL_TIMEOUT;
- pSRB->TargetStatus = 0;
- pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0);
- /* Devices are removed below ... */
- }
- else if (status_byte(status) == BUSY &&
+ else if (status == SAM_STAT_BUSY &&
(pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) &&
pACB->scan_devices)
{
@@ -1795,12 +1771,17 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
else
{ /* Target status == 0 */
status = pSRB->AdaptStatus;
- if(status & H_OVER_UNDER_RUN)
+ if (status == H_OVER_UNDER_RUN)
{
pSRB->TargetStatus = 0;
SET_RES_DID(pcmd->result,DID_OK);
SET_RES_MSG(pcmd->result,pSRB->EndMessage);
}
+ else if (status == H_SEL_TIMEOUT)
+ {
+ pcmd->result = MK_RES(0, DID_NO_CONNECT, 0, 0);
+ /* Devices are removed below ... */
+ }
else if( pSRB->SRBStatus & PARITY_ERROR)
{
//pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0);
@@ -1816,7 +1797,7 @@ dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb*
}
cmd_done:
- pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen;
+ scsi_set_resid(pcmd, scsi_bufflen(pcmd) - pSRB->TotalXferredLen);
dc390_Going_remove (pDCB, pSRB);
/* Add to free list */
@@ -2101,10 +2082,9 @@ static int dc390_slave_alloc(struct scsi_device *scsi_device)
uint id = scsi_device->id;
uint lun = scsi_device->lun;
- pDCB = kmalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
+ pDCB = kzalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
if (!pDCB)
return -ENOMEM;
- memset(pDCB, 0, sizeof(struct dc390_dcb));
if (!pACB->DCBCnt++) {
pACB->pLinkDCB = pDCB;
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index c3d8c80cfb38..77adc54dbd16 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -57,7 +57,6 @@ u8 SGcount;
u8 MsgCnt;
u8 EndMessage;
-u8 SavedSGCount;
u8 MsgInBuf[6];
u8 MsgOutBuf[6];
@@ -258,13 +257,6 @@ struct dc390_srb SRB_array[MAX_SRB_CNT]; /* 50 SRBs */
#define H_BAD_CCB_OR_SG 0x1A
#define H_ABORT 0x0FF
-/*; SCSI Status byte codes*/
-/* The values defined in include/scsi/scsi.h, to be shifted << 1 */
-
-#define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */
-#define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */
-#define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */
-
/* cmd->result */
#define RES_TARGET 0x000000FF /* Target State */
#define RES_TARGET_LNX STATUS_MASK /* Only official ... */
@@ -273,7 +265,7 @@ struct dc390_srb SRB_array[MAX_SRB_CNT]; /* 50 SRBs */
#define RES_DRV 0xFF000000 /* DRIVER_ codes */
#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
-#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)
+#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
#define SET_RES_TARGET(who, tgt) do { who &= ~RES_TARGET; who |= (int)(tgt); } while (0)
#define SET_RES_TARGET_LNX(who, tgt) do { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } while (0)
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 3de08a15de40..9e8232a1f169 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -1111,7 +1111,7 @@ static int u14_34f_detect(struct scsi_host_template *tpnt) {
static void map_dma(unsigned int i, unsigned int j) {
unsigned int data_len = 0;
unsigned int k, count, pci_dir;
- struct scatterlist *sgpnt;
+ struct scatterlist *sg;
struct mscp *cpp;
struct scsi_cmnd *SCpnt;
@@ -1124,33 +1124,28 @@ static void map_dma(unsigned int i, unsigned int j) {
cpp->sense_len = sizeof SCpnt->sense_buffer;
- if (!SCpnt->use_sg) {
-
- /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
- if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL;
-
- if (SCpnt->request_buffer)
- cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
- SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
-
- cpp->data_len = H2DEV(SCpnt->request_bufflen);
- return;
- }
-
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
- count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
-
- for (k = 0; k < count; k++) {
- cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
- cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
- data_len += sgpnt[k].length;
- }
-
- cpp->sg = TRUE;
- cpp->use_sg = SCpnt->use_sg;
- cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
- SCpnt->use_sg * sizeof(struct sg_list), pci_dir));
- cpp->data_len = H2DEV(data_len);
+ if (scsi_bufflen(SCpnt)) {
+ count = scsi_dma_map(SCpnt);
+ BUG_ON(count < 0);
+
+ scsi_for_each_sg(SCpnt, sg, count, k) {
+ cpp->sglist[k].address = H2DEV(sg_dma_address(sg));
+ cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg));
+ data_len += sg->length;
+ }
+
+ cpp->sg = TRUE;
+ cpp->use_sg = scsi_sg_count(SCpnt);
+ cpp->data_address =
+ H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
+ cpp->use_sg * sizeof(struct sg_list),
+ pci_dir));
+ cpp->data_len = H2DEV(data_len);
+
+ } else {
+ pci_dir = PCI_DMA_BIDIRECTIONAL;
+ cpp->data_len = H2DEV(scsi_bufflen(SCpnt));
+ }
}
static void unmap_dma(unsigned int i, unsigned int j) {
@@ -1165,8 +1160,7 @@ static void unmap_dma(unsigned int i, unsigned int j) {
pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
+ scsi_dma_unmap(SCpnt);
if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
@@ -1187,9 +1181,9 @@ static void sync_dma(unsigned int i, unsigned int j) {
pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr),
DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
- if (SCpnt->use_sg)
- pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer,
- SCpnt->use_sg, pci_dir);
+ if (scsi_sg_count(SCpnt))
+ pci_dma_sync_sg_for_cpu(HD(j)->pdev, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt), pci_dir);
if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 56906aba5ee3..c08235d5afc9 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -675,16 +675,15 @@ static const char *ultrastor_info(struct Scsi_Host * shpnt)
static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
{
- struct scatterlist *sl;
+ struct scatterlist *sg;
long transfer_length = 0;
int i, max;
- sl = (struct scatterlist *) SCpnt->request_buffer;
- max = SCpnt->use_sg;
- for (i = 0; i < max; i++) {
- mscp->sglist[i].address = isa_page_to_bus(sl[i].page) + sl[i].offset;
- mscp->sglist[i].num_bytes = sl[i].length;
- transfer_length += sl[i].length;
+ max = scsi_sg_count(SCpnt);
+ scsi_for_each_sg(SCpnt, sg, max, i) {
+ mscp->sglist[i].address = isa_page_to_bus(sg->page) + sg->offset;
+ mscp->sglist[i].num_bytes = sg->length;
+ transfer_length += sg->length;
}
mscp->number_of_sg_list = max;
mscp->transfer_data = isa_virt_to_bus(mscp->sglist);
@@ -730,15 +729,15 @@ static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
my_mscp->target_id = SCpnt->device->id;
my_mscp->ch_no = 0;
my_mscp->lun = SCpnt->device->lun;
- if (SCpnt->use_sg) {
+ if (scsi_sg_count(SCpnt)) {
/* Set scatter/gather flag in SCSI command packet */
my_mscp->sg = TRUE;
build_sg_list(my_mscp, SCpnt);
} else {
/* Unset scatter/gather flag in SCSI command packet */
my_mscp->sg = FALSE;
- my_mscp->transfer_data = isa_virt_to_bus(SCpnt->request_buffer);
- my_mscp->transfer_data_length = SCpnt->request_bufflen;
+ my_mscp->transfer_data = isa_virt_to_bus(scsi_sglist(SCpnt));
+ my_mscp->transfer_data_length = scsi_bufflen(SCpnt);
}
my_mscp->command_link = 0; /*???*/
my_mscp->scsi_command_link_id = 0; /*???*/
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index fa4e08e508ad..b92ff047af38 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -89,6 +89,8 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
+#include <asm/irq.h>
+
#include "wd33c93.h"
#define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns
@@ -1762,7 +1764,7 @@ static char setup_buffer[SETUP_BUFFER_SIZE];
static char setup_used[MAX_SETUP_ARGS];
static int done_setup = 0;
-int
+static int
wd33c93_setup(char *str)
{
int i;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 30be76514c43..d6fd4259c56b 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1091,6 +1091,7 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
unchar *cdb = (unchar *) SCpnt->cmnd;
unchar idlun;
short cdblen;
+ int nseg;
Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
cdblen = SCpnt->cmd_len;
@@ -1106,28 +1107,29 @@ static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
SCpnt->host_scribble = (unchar *) scb;
scb->host = host;
- if (SCpnt->use_sg) {
- struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+ nseg = scsi_sg_count(SCpnt);
+ if (nseg) {
+ struct scatterlist *sg;
unsigned i;
if (SCpnt->device->host->sg_tablesize == SG_NONE) {
panic("wd7000_queuecommand: scatter/gather not supported.\n");
}
- dprintk("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
+ dprintk("Using scatter/gather with %d elements.\n", nseg);
sgb = scb->sgb;
scb->op = 1;
any2scsi(scb->dataptr, (int) sgb);
- any2scsi(scb->maxlen, SCpnt->use_sg * sizeof(Sgb));
+ any2scsi(scb->maxlen, nseg * sizeof(Sgb));
- for (i = 0; i < SCpnt->use_sg; i++) {
- any2scsi(sgb[i].ptr, isa_page_to_bus(sg[i].page) + sg[i].offset);
- any2scsi(sgb[i].len, sg[i].length);
+ scsi_for_each_sg(SCpnt, sg, nseg, i) {
+ any2scsi(sgb[i].ptr, isa_page_to_bus(sg->page) + sg->offset);
+ any2scsi(sgb[i].len, sg->length);
}
} else {
scb->op = 0;
- any2scsi(scb->dataptr, isa_virt_to_bus(SCpnt->request_buffer));
- any2scsi(scb->maxlen, SCpnt->request_bufflen);
+ any2scsi(scb->dataptr, isa_virt_to_bus(scsi_sglist(SCpnt)));
+ any2scsi(scb->maxlen, scsi_bufflen(SCpnt));
}
/* FIXME: drop lock and yield here ? */
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
new file mode 100644
index 000000000000..c822debc2668
--- /dev/null
+++ b/drivers/scsi/zorro7xx.c
@@ -0,0 +1,181 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ * Amiga MacroSystemUS WarpEngine SCSI controller.
+ * Amiga Technologies/DKB A4091 SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ *
+ * Rewritten to use 53c700.c by Kars de Jong <jongk@linux-m68k.org>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/zorro.h>
+#include <asm/amigaints.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("Alan Hourihane <alanh@fairlite.demon.co.uk> / Kars de Jong <jongk@linux-m68k.org>");
+MODULE_DESCRIPTION("Amiga Zorro NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+
+static struct scsi_host_template zorro7xx_scsi_driver_template = {
+ .proc_name = "zorro7xx",
+ .this_id = 7,
+ .module = THIS_MODULE,
+};
+
+static struct zorro_driver_data {
+ const char *name;
+ unsigned long offset;
+ int absolute; /* offset is absolute address */
+} zorro7xx_driver_data[] __devinitdata = {
+ { .name = "PowerUP 603e+", .offset = 0xf40000, .absolute = 1 },
+ { .name = "WarpEngine 40xx", .offset = 0x40000 },
+ { .name = "A4091", .offset = 0x800000 },
+ { .name = "GForce 040/060", .offset = 0x40000 },
+ { 0 }
+};
+
+static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = {
+ {
+ .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[0],
+ },
+ {
+ .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[1],
+ },
+ {
+ .id = ZORRO_PROD_CBM_A4091_1,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[2],
+ },
+ {
+ .id = ZORRO_PROD_CBM_A4091_2,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[2],
+ },
+ {
+ .id = ZORRO_PROD_GVP_GFORCE_040_060,
+ .driver_data = (unsigned long)&zorro7xx_driver_data[3],
+ },
+ { 0 }
+};
+
+static int __devinit zorro7xx_init_one(struct zorro_dev *z,
+ const struct zorro_device_id *ent)
+{
+ struct Scsi_Host * host = NULL;
+ struct NCR_700_Host_Parameters *hostdata;
+ struct zorro_driver_data *zdd;
+ unsigned long board, ioaddr;
+
+ board = zorro_resource_start(z);
+ zdd = (struct zorro_driver_data *)ent->driver_data;
+
+ if (zdd->absolute) {
+ ioaddr = zdd->offset;
+ } else {
+ ioaddr = board + zdd->offset;
+ }
+
+ if (!zorro_request_device(z, zdd->name)) {
+ printk(KERN_ERR "zorro7xx: cannot reserve region 0x%lx, abort\n",
+ board);
+ return -EBUSY;
+ }
+
+ hostdata = kmalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL);
+ if (hostdata == NULL) {
+ printk(KERN_ERR "zorro7xx: Failed to allocate host data\n");
+ goto out_release;
+ }
+
+ memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+ /* Fill in the required pieces of hostdata */
+ if (ioaddr > 0x01000000)
+ hostdata->base = ioremap(ioaddr, zorro_resource_len(z));
+ else
+ hostdata->base = (void __iomem *)ZTWO_VADDR(ioaddr);
+
+ hostdata->clock = 50;
+ hostdata->chip710 = 1;
+
+ /* Settings for at least WarpEngine 40xx */
+ hostdata->ctest7_extra = CTEST7_TT1;
+
+ zorro7xx_scsi_driver_template.name = zdd->name;
+
+ /* and register the chip */
+ host = NCR_700_detect(&zorro7xx_scsi_driver_template, hostdata,
+ &z->dev);
+ if (!host) {
+ printk(KERN_ERR "zorro7xx: No host detected; "
+ "board configuration problem?\n");
+ goto out_free;
+ }
+
+ host->this_id = 7;
+ host->base = ioaddr;
+ host->irq = IRQ_AMIGA_PORTS;
+
+ if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "zorro7xx-scsi",
+ host)) {
+ printk(KERN_ERR "zorro7xx: request_irq failed\n");
+ goto out_put_host;
+ }
+
+ zorro_set_drvdata(z, host);
+ scsi_scan_host(host);
+
+ return 0;
+
+ out_put_host:
+ scsi_host_put(host);
+ out_free:
+ if (ioaddr > 0x01000000)
+ iounmap(hostdata->base);
+ kfree(hostdata);
+ out_release:
+ zorro_release_device(z);
+
+ return -ENODEV;
+}
+
+static __devexit void zorro7xx_remove_one(struct zorro_dev *z)
+{
+ struct Scsi_Host *host = zorro_get_drvdata(z);
+ struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
+
+ scsi_remove_host(host);
+
+ NCR_700_release(host);
+ kfree(hostdata);
+ free_irq(host->irq, host);
+ zorro_release_device(z);
+}
+
+static struct zorro_driver zorro7xx_driver = {
+ .name = "zorro7xx-scsi",
+ .id_table = zorro7xx_zorro_tbl,
+ .probe = zorro7xx_init_one,
+ .remove = __devexit_p(zorro7xx_remove_one),
+};
+
+static int __init zorro7xx_scsi_init(void)
+{
+ return zorro_register_driver(&zorro7xx_driver);
+}
+
+static void __exit zorro7xx_scsi_exit(void)
+{
+ zorro_unregister_driver(&zorro7xx_driver);
+}
+
+module_init(zorro7xx_scsi_init);
+module_exit(zorro7xx_scsi_exit);
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index 68817a7d8c0d..2aa6bfe8fdb3 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -934,8 +934,6 @@ static void change_speed(ser_info_t *info)
/*
* Set up parity check flag
*/
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
if (I_INPCK(info->tty))
info->read_status_mask |= BD_SC_FR | BD_SC_PR;
@@ -1527,11 +1525,6 @@ static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_term
{
ser_info_t *info = (ser_info_t *)tty->driver_data;
- if ( (tty->termios->c_cflag == old_termios->c_cflag)
- && ( RELEVANT_IFLAG(tty->termios->c_iflag)
- == RELEVANT_IFLAG(old_termios->c_iflag)))
- return;
-
change_speed(info);
#ifdef modem_control
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index c84dab083a85..0b3ec38ae614 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2514,12 +2514,18 @@ static int __init serial8250_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
+static int __init serial8250_console_early_setup(void)
+{
+ return serial8250_find_port_for_earlycon();
+}
+
static struct uart_driver serial8250_reg;
static struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
.device = uart_console_device,
.setup = serial8250_console_setup,
+ .early_setup = serial8250_console_early_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &serial8250_reg,
@@ -2533,7 +2539,7 @@ static int __init serial8250_console_init(void)
}
console_initcall(serial8250_console_init);
-static int __init find_port(struct uart_port *p)
+int serial8250_find_port(struct uart_port *p)
{
int line;
struct uart_port *port;
@@ -2546,26 +2552,6 @@ static int __init find_port(struct uart_port *p)
return -ENODEV;
}
-int __init serial8250_start_console(struct uart_port *port, char *options)
-{
- int line;
-
- line = find_port(port);
- if (line < 0)
- return -ENODEV;
-
- add_preferred_console("ttyS", line, options);
- printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n",
- line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port",
- port->iotype == UPIO_MEM ? (unsigned long) port->mapbase :
- (unsigned long) port->iobase, options);
- if (!(serial8250_console.flags & CON_ENABLED)) {
- serial8250_console.flags &= ~CON_PRINTBUFFER;
- register_console(&serial8250_console);
- }
- return line;
-}
-
#define SERIAL8250_CONSOLE &serial8250_console
#else
#define SERIAL8250_CONSOLE NULL
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 7e511199b4c5..947c20507e1f 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -17,13 +17,11 @@
* we locate the device directly by its MMIO or I/O port address.
*
* The user can specify the device directly, e.g.,
- * console=uart,io,0x3f8,9600n8
- * console=uart,mmio,0xff5e0000,115200n8
- * or platform code can call early_uart_console_init() to set
- * the early UART device.
- *
- * After the normal serial driver starts, we try to locate the
- * matching ttyS device and start a console there.
+ * earlycon=uart8250,io,0x3f8,9600n8
+ * earlycon=uart8250,mmio,0xff5e0000,115200n8
+ * or
+ * console=uart8250,io,0x3f8,9600n8
+ * console=uart8250,mmio,0xff5e0000,115200n8
*/
#include <linux/tty.h>
@@ -32,17 +30,21 @@
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
+#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/serial.h>
+#ifdef CONFIG_FIX_EARLYCON_MEM
+#include <asm/pgtable.h>
+#include <asm/fixmap.h>
+#endif
-struct early_uart_device {
+struct early_serial8250_device {
struct uart_port port;
char options[16]; /* e.g., 115200n8 */
unsigned int baud;
};
-static struct early_uart_device early_device __initdata;
-static int early_uart_registered __initdata;
+static struct early_serial8250_device early_device;
static unsigned int __init serial_in(struct uart_port *port, int offset)
{
@@ -80,7 +82,7 @@ static void __init putc(struct uart_port *port, int c)
serial_out(port, UART_TX, c);
}
-static void __init early_uart_write(struct console *console, const char *s, unsigned int count)
+static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count)
{
struct uart_port *port = &early_device.port;
unsigned int ier;
@@ -111,7 +113,7 @@ static unsigned int __init probe_baud(struct uart_port *port)
return (port->uartclk / 16) / quot;
}
-static void __init init_port(struct early_uart_device *device)
+static void __init init_port(struct early_serial8250_device *device)
{
struct uart_port *port = &device->port;
unsigned int divisor;
@@ -130,10 +132,9 @@ static void __init init_port(struct early_uart_device *device)
serial_out(port, UART_LCR, c & ~UART_LCR_DLAB);
}
-static int __init parse_options(struct early_uart_device *device, char *options)
+static int __init parse_options(struct early_serial8250_device *device, char *options)
{
struct uart_port *port = &device->port;
- int mapsize = 64;
int mmio, length;
if (!options)
@@ -143,12 +144,18 @@ static int __init parse_options(struct early_uart_device *device, char *options)
if (!strncmp(options, "mmio,", 5)) {
port->iotype = UPIO_MEM;
port->mapbase = simple_strtoul(options + 5, &options, 0);
- port->membase = ioremap(port->mapbase, mapsize);
+#ifdef CONFIG_FIX_EARLYCON_MEM
+ set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, port->mapbase & PAGE_MASK);
+ port->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
+ port->membase += port->mapbase & ~PAGE_MASK;
+#else
+ port->membase = ioremap(port->mapbase, 64);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
__FUNCTION__, port->mapbase);
return -ENOMEM;
}
+#endif
mmio = 1;
} else if (!strncmp(options, "io,", 3)) {
port->iotype = UPIO_PORT;
@@ -175,9 +182,16 @@ static int __init parse_options(struct early_uart_device *device, char *options)
return 0;
}
-static int __init early_uart_setup(struct console *console, char *options)
+static struct console early_serial8250_console __initdata = {
+ .name = "uart",
+ .write = early_serial8250_write,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
+ .index = -1,
+};
+
+static int __init early_serial8250_setup(char *options)
{
- struct early_uart_device *device = &early_device;
+ struct early_serial8250_device *device = &early_device;
int err;
if (device->port.membase || device->port.iobase)
@@ -190,61 +204,48 @@ static int __init early_uart_setup(struct console *console, char *options)
return 0;
}
-static struct console early_uart_console __initdata = {
- .name = "uart",
- .write = early_uart_write,
- .setup = early_uart_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-static int __init early_uart_console_init(void)
-{
- if (!early_uart_registered) {
- register_console(&early_uart_console);
- early_uart_registered = 1;
- }
- return 0;
-}
-console_initcall(early_uart_console_init);
-
-int __init early_serial_console_init(char *cmdline)
+int __init setup_early_serial8250_console(char *cmdline)
{
char *options;
int err;
- options = strstr(cmdline, "console=uart,");
- if (!options)
- return -ENODEV;
+ options = strstr(cmdline, "uart8250,");
+ if (!options) {
+ options = strstr(cmdline, "uart,");
+ if (!options)
+ return 0;
+ }
options = strchr(cmdline, ',') + 1;
- if ((err = early_uart_setup(NULL, options)) < 0)
+ if ((err = early_serial8250_setup(options)) < 0)
return err;
- return early_uart_console_init();
+
+ register_console(&early_serial8250_console);
+
+ return 0;
}
-static int __init early_uart_console_switch(void)
+int __init serial8250_find_port_for_earlycon(void)
{
- struct early_uart_device *device = &early_device;
+ struct early_serial8250_device *device = &early_device;
struct uart_port *port = &device->port;
- int mmio, line;
+ int line;
+ int ret;
- if (!(early_uart_console.flags & CON_ENABLED))
- return 0;
+ if (!device->port.membase && !device->port.iobase)
+ return -ENODEV;
- /* Try to start the normal driver on a matching line. */
- mmio = (port->iotype == UPIO_MEM);
- line = serial8250_start_console(port, device->options);
+ line = serial8250_find_port(port);
if (line < 0)
- printk("No ttyS device at %s 0x%lx for console\n",
- mmio ? "MMIO" : "I/O port",
- mmio ? port->mapbase :
- (unsigned long) port->iobase);
+ return -ENODEV;
- unregister_console(&early_uart_console);
- if (mmio)
- iounmap(port->membase);
+ ret = update_console_cmdline("uart", 8250,
+ "ttyS", line, device->options);
+ if (ret < 0)
+ ret = update_console_cmdline("uart", 0,
+ "ttyS", line, device->options);
- return 0;
+ return ret;
}
-late_initcall(early_uart_console_switch);
+
+early_param("earlycon", setup_early_serial8250_console);
diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c
index 53e81a44c1a3..2cf0953fe0ec 100644
--- a/drivers/serial/8250_hp300.c
+++ b/drivers/serial/8250_hp300.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/delay.h>
#include <linux/dio.h>
#include <linux/console.h>
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 315ea9916456..18f629706448 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -62,8 +62,22 @@ config SERIAL_8250_CONSOLE
kernel will automatically use the first serial line, /dev/ttyS0, as
system console.
+ you can set that using a kernel command line option such as
+ "console=uart8250,io,0x3f8,9600n8"
+ "console=uart8250,mmio,0xff5e0000,115200n8".
+ and it will switch to normal serial console when correponding port is
+ ready.
+ "earlycon=uart8250,io,0x3f8,9600n8"
+ "earlycon=uart8250,mmio,0xff5e0000,115200n8".
+ it will not only setup early console.
+
If unsure, say N.
+config FIX_EARLYCON_MEM
+ bool
+ depends on X86
+ default y
+
config SERIAL_8250_GSC
tristate
depends on SERIAL_8250 && GSC
@@ -324,6 +338,34 @@ config SERIAL_AMBA_PL011_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
+config SERIAL_SB1250_DUART
+ tristate "BCM1xxx on-chip DUART serial support"
+ depends on SIBYTE_SB1xxx_SOC=y
+ select SERIAL_CORE
+ default y
+ ---help---
+ Support for the asynchronous serial interface (DUART) included in
+ the BCM1250 and derived System-On-a-Chip (SOC) devices. Note that
+ the letter D in DUART stands for "dual", which is how the device
+ is implemented. Depending on the SOC configuration there may be
+ one or more DUARTs available of which all are handled.
+
+ If unsure, say Y. To compile this driver as a module, choose M here:
+ the module will be called sb1250-duart.
+
+config SERIAL_SB1250_DUART_CONSOLE
+ bool "Support for console on a BCM1xxx DUART serial port"
+ depends on SERIAL_SB1250_DUART=y
+ select SERIAL_CORE_CONSOLE
+ default y
+ ---help---
+ If you say Y here, it will be possible to use a serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ If unsure, say Y.
+
config SERIAL_ATMEL
bool "AT91 / AT32 on-chip serial port support"
depends on (ARM && ARCH_AT91) || AVR32
@@ -444,6 +486,36 @@ config SERIAL_DZ_CONSOLE
If unsure, say Y.
+config SERIAL_ZS
+ tristate "DECstation Z85C30 serial support"
+ depends on MACH_DECSTATION
+ select SERIAL_CORE
+ default y
+ ---help---
+ Support for the Zilog 85C350 serial communications controller used
+ for serial ports in newer DECstation systems. These include the
+ DECsystem 5900 and all models of the DECstation and DECsystem 5000
+ systems except from model 200.
+
+ If unsure, say Y. To compile this driver as a module, choose M here:
+ the module will be called zs.
+
+config SERIAL_ZS_CONSOLE
+ bool "Support for console on a DECstation Z85C30 serial port"
+ depends on SERIAL_ZS=y
+ select SERIAL_CORE_CONSOLE
+ default y
+ ---help---
+ If you say Y here, it will be possible to use a serial port as the
+ system console (the system console is the device which receives all
+ kernel messages and warnings and which allows logins in single user
+ mode).
+
+ Note that the firmware uses ttyS1 as the serial console on the
+ Maxine and ttyS3 on the others using this driver.
+
+ If unsure, say Y.
+
config SERIAL_21285
tristate "DC21285 serial port support"
depends on ARM && FOOTBRIDGE
@@ -556,7 +628,7 @@ choice
config SERIAL_BFIN_DMA
bool "DMA mode"
- depends on DMA_UNCACHED_1M
+ depends on DMA_UNCACHED_1M && !KGDB_UART
help
This driver works under DMA mode. If this option is selected, the
blackfin simple dma driver is also enabled.
@@ -599,7 +671,7 @@ config UART0_RTS_PIN
config SERIAL_BFIN_UART1
bool "Enable UART1"
- depends on SERIAL_BFIN && (BF534 || BF536 || BF537)
+ depends on SERIAL_BFIN && (BF534 || BF536 || BF537 || BF54x)
help
Enable UART1
@@ -612,18 +684,58 @@ config BFIN_UART1_CTSRTS
config UART1_CTS_PIN
int "UART1 CTS pin"
- depends on BFIN_UART1_CTSRTS
+ depends on BFIN_UART1_CTSRTS && (BF53x || BF561)
default -1
help
Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
config UART1_RTS_PIN
int "UART1 RTS pin"
- depends on BFIN_UART1_CTSRTS
+ depends on BFIN_UART1_CTSRTS && (BF53x || BF561)
default -1
help
Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+config SERIAL_BFIN_UART2
+ bool "Enable UART2"
+ depends on SERIAL_BFIN && (BF54x)
+ help
+ Enable UART2
+
+config BFIN_UART2_CTSRTS
+ bool "Enable UART2 hardware flow control"
+ depends on SERIAL_BFIN_UART2
+ help
+ Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
+ signal.
+
+config UART2_CTS_PIN
+ int "UART2 CTS pin"
+ depends on BFIN_UART2_CTSRTS
+ default -1
+ help
+ Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config UART2_RTS_PIN
+ int "UART2 RTS pin"
+ depends on BFIN_UART2_CTSRTS
+ default -1
+ help
+ Refer to ./include/asm-blackfin/gpio.h to see the GPIO map.
+
+config SERIAL_BFIN_UART3
+ bool "Enable UART3"
+ depends on SERIAL_BFIN && (BF54x)
+ help
+ Enable UART3
+
+config BFIN_UART3_CTSRTS
+ bool "Enable UART3 hardware flow control"
+ depends on SERIAL_BFIN_UART3
+ help
+ Enable hardware flow control in the driver. Using GPIO emulate the CTS/RTS
+ signal.
+
config SERIAL_IMX
bool "IMX serial port support"
depends on ARM && ARCH_IMX
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 08ad0d978183..af6377d480d7 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_V850E_UART) += v850e_uart.o
obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
obj-$(CONFIG_SERIAL_DZ) += dz.o
+obj-$(CONFIG_SERIAL_ZS) += zs.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
@@ -51,6 +52,7 @@ obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
obj-$(CONFIG_SERIAL_ICOM) += icom.o
obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
+obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 954073c6ce3a..72229df9dc11 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -716,7 +716,7 @@ static int pl011_probe(struct amba_device *dev, void *id)
goto out;
}
- uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+ uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
if (uap == NULL) {
ret = -ENOMEM;
goto out;
@@ -728,7 +728,6 @@ static int pl011_probe(struct amba_device *dev, void *id)
goto free;
}
- memset(uap, 0, sizeof(struct uart_amba_port));
uap->clk = clk_get(&dev->dev, "UARTCLK");
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
index 3320bcd92c0a..4d6b3c56d20e 100644
--- a/drivers/serial/atmel_serial.c
+++ b/drivers/serial/atmel_serial.c
@@ -114,6 +114,7 @@ struct atmel_uart_port {
struct uart_port uart; /* uart */
struct clk *clk; /* uart clock */
unsigned short suspended; /* is port suspended? */
+ int break_active; /* break being received */
};
static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -252,6 +253,7 @@ static void atmel_break_ctl(struct uart_port *port, int break_state)
*/
static void atmel_rx_chars(struct uart_port *port)
{
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
struct tty_struct *tty = port->info->tty;
unsigned int status, ch, flg;
@@ -267,13 +269,29 @@ static void atmel_rx_chars(struct uart_port *port)
* note that the error handling code is
* out of the main execution path
*/
- if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+ if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME
+ | ATMEL_US_OVRE | ATMEL_US_RXBRK)
+ || atmel_port->break_active)) {
UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */
- if (status & ATMEL_US_RXBRK) {
+ if (status & ATMEL_US_RXBRK
+ && !atmel_port->break_active) {
status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */
port->icount.brk++;
+ atmel_port->break_active = 1;
+ UART_PUT_IER(port, ATMEL_US_RXBRK);
if (uart_handle_break(port))
goto ignore_char;
+ } else {
+ /*
+ * This is either the end-of-break
+ * condition or we've received at
+ * least one character without RXBRK
+ * being set. In both cases, the next
+ * RXBRK will indicate start-of-break.
+ */
+ UART_PUT_IDR(port, ATMEL_US_RXBRK);
+ status &= ~ATMEL_US_RXBRK;
+ atmel_port->break_active = 0;
}
if (status & ATMEL_US_PARE)
port->icount.parity++;
@@ -352,6 +370,16 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
/* Interrupt receive */
if (pending & ATMEL_US_RXRDY)
atmel_rx_chars(port);
+ else if (pending & ATMEL_US_RXBRK) {
+ /*
+ * End of break detected. If it came along
+ * with a character, atmel_rx_chars will
+ * handle it.
+ */
+ UART_PUT_CR(port, ATMEL_US_RSTSTA);
+ UART_PUT_IDR(port, ATMEL_US_RXBRK);
+ atmel_port->break_active = 0;
+ }
// TODO: All reads to CSR will clear these interrupts!
if (pending & ATMEL_US_RIIC) port->icount.rng++;
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 22569bd5d821..66c92bc36f3d 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -41,6 +41,11 @@
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
+#ifdef CONFIG_KGDB_UART
+#include <linux/kgdb.h>
+#include <asm/irq_regs.h>
+#endif
+
#include <asm/gpio.h>
#include <asm/mach/bfin_serial_5xx.h>
@@ -81,15 +86,29 @@ static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef CONFIG_BF54x
+ while (!(UART_GET_LSR(uart) & TEMT))
+ continue;
+#endif
+
#ifdef CONFIG_SERIAL_BFIN_DMA
disable_dma(uart->tx_dma_channel);
#else
+#ifdef CONFIG_BF54x
+ /* Waiting for Transmission Finished */
+ while (!(UART_GET_LSR(uart) & TFI))
+ continue;
+ /* Clear TFI bit */
+ UART_PUT_LSR(uart, TFI);
+ UART_CLEAR_IER(uart, ETBEI);
+#else
unsigned short ier;
ier = UART_GET_IER(uart);
ier &= ~ETBEI;
UART_PUT_IER(uart, ier);
#endif
+#endif
}
/*
@@ -102,12 +121,16 @@ static void bfin_serial_start_tx(struct uart_port *port)
#ifdef CONFIG_SERIAL_BFIN_DMA
bfin_serial_dma_tx_chars(uart);
#else
+#ifdef CONFIG_BF54x
+ UART_SET_IER(uart, ETBEI);
+#else
unsigned short ier;
ier = UART_GET_IER(uart);
ier |= ETBEI;
UART_PUT_IER(uart, ier);
bfin_serial_tx_chars(uart);
#endif
+#endif
}
/*
@@ -116,11 +139,18 @@ static void bfin_serial_start_tx(struct uart_port *port)
static void bfin_serial_stop_rx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef CONFIG_BF54x
+ UART_CLEAR_IER(uart, ERBFI);
+#else
unsigned short ier;
ier = UART_GET_IER(uart);
+#ifdef CONFIG_KGDB_UART
+ if (uart->port.line != CONFIG_KGDB_UART_PORT)
+#endif
ier &= ~ERBFI;
UART_PUT_IER(uart, ier);
+#endif
}
/*
@@ -130,6 +160,49 @@ static void bfin_serial_enable_ms(struct uart_port *port)
{
}
+#ifdef CONFIG_KGDB_UART
+static int kgdb_entry_state;
+
+void kgdb_put_debug_char(int chr)
+{
+ struct bfin_serial_port *uart;
+
+ if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
+ uart = &bfin_serial_ports[0];
+ else
+ uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
+
+ while (!(UART_GET_LSR(uart) & THRE)) {
+ __builtin_bfin_ssync();
+ }
+ UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
+ __builtin_bfin_ssync();
+ UART_PUT_CHAR(uart, (unsigned char)chr);
+ __builtin_bfin_ssync();
+}
+
+int kgdb_get_debug_char(void)
+{
+ struct bfin_serial_port *uart;
+ unsigned char chr;
+
+ if (CONFIG_KGDB_UART_PORT<0 || CONFIG_KGDB_UART_PORT>=NR_PORTS)
+ uart = &bfin_serial_ports[0];
+ else
+ uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
+
+ while(!(UART_GET_LSR(uart) & DR)) {
+ __builtin_bfin_ssync();
+ }
+ UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
+ __builtin_bfin_ssync();
+ chr = UART_GET_CHAR(uart);
+ __builtin_bfin_ssync();
+
+ return chr;
+}
+#endif
+
#ifdef CONFIG_SERIAL_BFIN_PIO
static void local_put_char(struct bfin_serial_port *uart, char ch)
{
@@ -152,6 +225,9 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
struct tty_struct *tty = uart->port.info->tty;
unsigned int status, ch, flg;
+#ifdef CONFIG_KGDB_UART
+ struct pt_regs *regs = get_irq_regs();
+#endif
#ifdef BF533_FAMILY
static int in_break = 0;
#endif
@@ -160,6 +236,27 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
ch = UART_GET_CHAR(uart);
uart->port.icount.rx++;
+#ifdef CONFIG_KGDB_UART
+ if (uart->port.line == CONFIG_KGDB_UART_PORT) {
+ if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
+ kgdb_breakkey_pressed(regs);
+ return;
+ } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */
+ kgdb_entry_state = 1;
+ } else if (kgdb_entry_state == 1 && ch == 'q') {
+ kgdb_entry_state = 0;
+ kgdb_breakkey_pressed(regs);
+ return;
+ } else if (ch == 0x3) {/* Ctrl + C */
+ kgdb_entry_state = 0;
+ kgdb_breakkey_pressed(regs);
+ return;
+ } else {
+ kgdb_entry_state = 0;
+ }
+ }
+#endif
+
#ifdef BF533_FAMILY
/* The BF533 family of processors have a nice misbehavior where
* they continuously generate characters for a "single" break.
@@ -250,10 +347,21 @@ static irqreturn_t bfin_serial_rx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
+#ifdef CONFIG_BF54x
+ unsigned short status;
+ spin_lock(&uart->port.lock);
+ status = UART_GET_LSR(uart);
+ while ((UART_GET_IER(uart) & ERBFI) && (status & DR)) {
+ bfin_serial_rx_chars(uart);
+ status = UART_GET_LSR(uart);
+ }
+ spin_unlock(&uart->port.lock);
+#else
spin_lock(&uart->port.lock);
while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_RX_READY)
bfin_serial_rx_chars(uart);
spin_unlock(&uart->port.lock);
+#endif
return IRQ_HANDLED;
}
@@ -261,10 +369,21 @@ static irqreturn_t bfin_serial_tx_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
+#ifdef CONFIG_BF54x
+ unsigned short status;
+ spin_lock(&uart->port.lock);
+ status = UART_GET_LSR(uart);
+ while ((UART_GET_IER(uart) & ETBEI) && (status & THRE)) {
+ bfin_serial_tx_chars(uart);
+ status = UART_GET_LSR(uart);
+ }
+ spin_unlock(&uart->port.lock);
+#else
spin_lock(&uart->port.lock);
while ((UART_GET_IIR(uart) & IIR_STATUS) == IIR_TX_READY)
bfin_serial_tx_chars(uart);
spin_unlock(&uart->port.lock);
+#endif
return IRQ_HANDLED;
}
@@ -275,7 +394,6 @@ static void bfin_serial_do_work(struct work_struct *work)
bfin_serial_mctrl_check(uart);
}
-
#endif
#ifdef CONFIG_SERIAL_BFIN_DMA
@@ -324,9 +442,13 @@ static void bfin_serial_dma_tx_chars(struct bfin_serial_port *uart)
set_dma_x_count(uart->tx_dma_channel, uart->tx_count);
set_dma_x_modify(uart->tx_dma_channel, 1);
enable_dma(uart->tx_dma_channel);
+#ifdef CONFIG_BF54x
+ UART_SET_IER(uart, ETBEI);
+#else
ier = UART_GET_IER(uart);
ier |= ETBEI;
UART_PUT_IER(uart, ier);
+#endif
spin_unlock_irqrestore(&uart->port.lock, flags);
}
@@ -406,9 +528,13 @@ static irqreturn_t bfin_serial_dma_tx_int(int irq, void *dev_id)
if (!(get_dma_curr_irqstat(uart->tx_dma_channel)&DMA_RUN)) {
clear_dma_irqstat(uart->tx_dma_channel);
disable_dma(uart->tx_dma_channel);
+#ifdef CONFIG_BF54x
+ UART_CLEAR_IER(uart, ETBEI);
+#else
ier = UART_GET_IER(uart);
ier &= ~ETBEI;
UART_PUT_IER(uart, ier);
+#endif
xmit->tail = (xmit->tail+uart->tx_count) &(UART_XMIT_SIZE -1);
uart->port.icount.tx+=uart->tx_count;
@@ -571,7 +697,11 @@ static int bfin_serial_startup(struct uart_port *port)
uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
add_timer(&(uart->rx_dma_timer));
#else
+# ifdef CONFIG_KGDB_UART
+ if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq
+# else
if (request_irq
+# endif
(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
"BFIN_UART_RX", uart)) {
printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
@@ -586,7 +716,11 @@ static int bfin_serial_startup(struct uart_port *port)
return -EBUSY;
}
#endif
+#ifdef CONFIG_BF54x
+ UART_SET_IER(uart, ERBFI);
+#else
UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
+#endif
return 0;
}
@@ -601,6 +735,9 @@ static void bfin_serial_shutdown(struct uart_port *port)
free_dma(uart->rx_dma_channel);
del_timer(&(uart->rx_dma_timer));
#else
+#ifdef CONFIG_KGDB_UART
+ if (uart->port.line != CONFIG_KGDB_UART_PORT)
+#endif
free_irq(uart->port.irq, uart);
free_irq(uart->port.irq+1, uart);
#endif
@@ -674,29 +811,41 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
/* Disable UART */
ier = UART_GET_IER(uart);
+#ifdef CONFIG_BF54x
+ UART_CLEAR_IER(uart, 0xF);
+#else
UART_PUT_IER(uart, 0);
+#endif
+#ifndef CONFIG_BF54x
/* Set DLAB in LCR to Access DLL and DLH */
val = UART_GET_LCR(uart);
val |= DLAB;
UART_PUT_LCR(uart, val);
SSYNC();
+#endif
UART_PUT_DLL(uart, quot & 0xFF);
SSYNC();
UART_PUT_DLH(uart, (quot >> 8) & 0xFF);
SSYNC();
+#ifndef CONFIG_BF54x
/* Clear DLAB in LCR to Access THR RBR IER */
val = UART_GET_LCR(uart);
val &= ~DLAB;
UART_PUT_LCR(uart, val);
SSYNC();
+#endif
UART_PUT_LCR(uart, lcr);
/* Enable UART */
+#ifdef CONFIG_BF54x
+ UART_SET_IER(uart, ier);
+#else
UART_PUT_IER(uart, ier);
+#endif
val = UART_GET_GCTL(uart);
val |= UCEN;
@@ -808,15 +957,15 @@ static void __init bfin_serial_init_ports(void)
bfin_serial_resource[i].uart_rts_pin;
#endif
bfin_serial_hw_init(&bfin_serial_ports[i]);
-
}
+
}
#ifdef CONFIG_SERIAL_BFIN_CONSOLE
static void bfin_serial_console_putchar(struct uart_port *port, int ch)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
- while (!(UART_GET_LSR(uart)))
+ while (!(UART_GET_LSR(uart) & THRE))
barrier();
UART_PUT_CHAR(uart, ch);
SSYNC();
@@ -868,18 +1017,22 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
case 2: *bits = 7; break;
case 3: *bits = 8; break;
}
+#ifndef CONFIG_BF54x
/* Set DLAB in LCR to Access DLL and DLH */
val = UART_GET_LCR(uart);
val |= DLAB;
UART_PUT_LCR(uart, val);
+#endif
dll = UART_GET_DLL(uart);
dlh = UART_GET_DLH(uart);
+#ifndef CONFIG_BF54x
/* Clear DLAB in LCR to Access THR RBR IER */
val = UART_GET_LCR(uart);
val &= ~DLAB;
UART_PUT_LCR(uart, val);
+#endif
*baud = get_sclk() / (16*(dll | dlh << 8));
}
@@ -931,6 +1084,10 @@ static int __init bfin_serial_rs_console_init(void)
{
bfin_serial_init_ports();
register_console(&bfin_serial_console);
+#ifdef CONFIG_KGDB_UART
+ kgdb_entry_state = 0;
+ init_kgdb_uart();
+#endif
return 0;
}
console_initcall(bfin_serial_rs_console_init);
@@ -1023,6 +1180,10 @@ static struct platform_driver bfin_serial_driver = {
static int __init bfin_serial_init(void)
{
int ret;
+#ifdef CONFIG_KGDB_UART
+ struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
+ struct termios t;
+#endif
pr_info("Serial: Blackfin serial driver\n");
@@ -1036,6 +1197,21 @@ static int __init bfin_serial_init(void)
uart_unregister_driver(&bfin_serial_reg);
}
}
+#ifdef CONFIG_KGDB_UART
+ if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
+ request_irq(uart->port.irq, bfin_serial_int,
+ IRQF_DISABLED, "BFIN_UART_RX", uart);
+ pr_info("Request irq for kgdb uart port\n");
+ UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
+ __builtin_bfin_ssync();
+ t.c_cflag = CS8|B57600;
+ t.c_iflag = 0;
+ t.c_oflag = 0;
+ t.c_lflag = ICANON;
+ t.c_line = CONFIG_KGDB_UART_PORT;
+ bfin_serial_set_termios(&uart->port, &t, &t);
+ }
+#endif
return ret;
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index b63ff8dd7304..cefde58dbad2 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -678,7 +678,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
}
bdp->cbd_datlen = count;
bdp->cbd_sc |= BD_SC_READY;
- __asm__("eieio");
+ eieio();
/* Get next BD. */
if (bdp->cbd_sc & BD_SC_WRAP)
bdp = pinfo->tx_bd_base;
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index e42faa4e4282..dc1967176fe2 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -1114,8 +1114,8 @@ static int __init imx_serial_init(void)
static void __exit imx_serial_exit(void)
{
- uart_unregister_driver(&imx_reg);
platform_driver_unregister(&serial_imx_driver);
+ uart_unregister_driver(&imx_reg);
}
module_init(imx_serial_init);
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index c3abfb39f316..f3257f708ef9 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -862,6 +862,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios,
up->cflag = termios->c_cflag;
ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port));
+ uart_update_timeout(port, termios->c_cflag, baud);
spin_unlock_irqrestore(&up->port.lock, flags);
}
@@ -1017,6 +1018,8 @@ ip22serial_console_termios(struct console *con, char *options)
}
con->cflag = cflag | CS8; /* 8N1 */
+
+ uart_update_timeout(&ip22zilog_port_table[con->index].port, cflag, baud);
}
static int __init ip22zilog_console_setup(struct console *con, char *options)
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 81792e6eeb2d..6767ee381cd1 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -88,7 +88,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
spin_lock_init(&brd->bd_intr_lock);
/* store which revision we have */
- pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
+ brd->rev = pdev->revision;
brd->irq = pdev->irq;
diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c
index 7ffdaeaf0545..a64d85821996 100644
--- a/drivers/serial/of_serial.c
+++ b/drivers/serial/of_serial.c
@@ -17,6 +17,11 @@
#include <asm/of_platform.h>
#include <asm/prom.h>
+struct of_serial_info {
+ int type;
+ int line;
+};
+
/*
* Fill a struct uart_port for a given device node
*/
@@ -62,6 +67,7 @@ static int __devinit of_platform_serial_setup(struct of_device *ofdev,
static int __devinit of_platform_serial_probe(struct of_device *ofdev,
const struct of_device_id *id)
{
+ struct of_serial_info *info;
struct uart_port port;
int port_type;
int ret;
@@ -69,30 +75,35 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev,
if (of_find_property(ofdev->node, "used-by-rtas", NULL))
return -EBUSY;
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL)
+ return -ENOMEM;
+
port_type = (unsigned long)id->data;
ret = of_platform_serial_setup(ofdev, port_type, &port);
if (ret)
goto out;
switch (port_type) {
- case PORT_UNKNOWN:
- dev_info(&ofdev->dev, "Unknown serial port found, "
- "attempting to use 8250 driver\n");
- /* fallthrough */
case PORT_8250 ... PORT_MAX_8250:
ret = serial8250_register_port(&port);
break;
default:
/* need to add code for these */
+ case PORT_UNKNOWN:
+ dev_info(&ofdev->dev, "Unknown serial port found, ignored\n");
ret = -ENODEV;
break;
}
if (ret < 0)
goto out;
- ofdev->dev.driver_data = (void *)(unsigned long)ret;
+ info->type = port_type;
+ info->line = ret;
+ ofdev->dev.driver_data = info;
return 0;
out:
+ kfree(info);
irq_dispose_mapping(port.irq);
return ret;
}
@@ -102,8 +113,16 @@ out:
*/
static int of_platform_serial_remove(struct of_device *ofdev)
{
- int line = (unsigned long)ofdev->dev.driver_data;
- serial8250_unregister_port(line);
+ struct of_serial_info *info = ofdev->dev.driver_data;
+ switch (info->type) {
+ case PORT_8250 ... PORT_MAX_8250:
+ serial8250_unregister_port(info->line);
+ break;
+ default:
+ /* need to add code for these */
+ break;
+ }
+ kfree(info);
return 0;
}
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 10bc0209cd66..3f26c4b2f322 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -78,7 +78,7 @@
#include <asm/hardware.h>
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
#include <asm/arch/regs-gpio.h>
/* structures */
diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
new file mode 100644
index 000000000000..1d9d7285172a
--- /dev/null
+++ b/drivers/serial/sb1250-duart.c
@@ -0,0 +1,972 @@
+/*
+ * drivers/serial/sb1250-duart.c
+ *
+ * Support for the asynchronous serial interface (DUART) included
+ * in the BCM1250 and derived System-On-a-Chip (SOC) devices.
+ *
+ * Copyright (c) 2007 Maciej W. Rozycki
+ *
+ * Derived from drivers/char/sb1250_duart.c for which the following
+ * copyright applies:
+ *
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 Broadcom 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.
+ *
+ * References:
+ *
+ * "BCM1250/BCM1125/BCM1125H User Manual", Broadcom Corporation
+ */
+
+#if defined(CONFIG_SERIAL_SB1250_DUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <asm/war.h>
+
+#include <asm/sibyte/sb1250.h>
+#include <asm/sibyte/sb1250_uart.h>
+#include <asm/sibyte/swarm.h>
+
+
+#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
+#include <asm/sibyte/bcm1480_regs.h>
+#include <asm/sibyte/bcm1480_int.h>
+
+#define SBD_CHANREGS(line) A_BCM1480_DUART_CHANREG((line), 0)
+#define SBD_CTRLREGS(line) A_BCM1480_DUART_CTRLREG((line), 0)
+#define SBD_INT(line) (K_BCM1480_INT_UART_0 + (line))
+
+#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
+#include <asm/sibyte/sb1250_regs.h>
+#include <asm/sibyte/sb1250_int.h>
+
+#define SBD_CHANREGS(line) A_DUART_CHANREG((line), 0)
+#define SBD_CTRLREGS(line) A_DUART_CTRLREG(0)
+#define SBD_INT(line) (K_INT_UART_0 + (line))
+
+#else
+#error invalid SB1250 UART configuration
+
+#endif
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("BCM1xxx on-chip DUART serial driver");
+MODULE_LICENSE("GPL");
+
+
+#define DUART_MAX_CHIP 2
+#define DUART_MAX_SIDE 2
+
+/*
+ * Per-port state.
+ */
+struct sbd_port {
+ struct sbd_duart *duart;
+ struct uart_port port;
+ unsigned char __iomem *memctrl;
+ int tx_stopped;
+ int initialised;
+};
+
+/*
+ * Per-DUART state for the shared register space.
+ */
+struct sbd_duart {
+ struct sbd_port sport[2];
+ unsigned long mapctrl;
+ atomic_t map_guard;
+};
+
+#define to_sport(uport) container_of(uport, struct sbd_port, port)
+
+static struct sbd_duart sbd_duarts[DUART_MAX_CHIP];
+
+#define __unused __attribute__((__unused__))
+
+
+/*
+ * Reading and writing SB1250 DUART registers.
+ *
+ * There are three register spaces: two per-channel ones and
+ * a shared one. We have to define accessors appropriately.
+ * All registers are 64-bit and all but the Baud Rate Clock
+ * registers only define 8 least significant bits. There is
+ * also a workaround to take into account. Raw accessors use
+ * the full register width, but cooked ones truncate it
+ * intentionally so that the rest of the driver does not care.
+ */
+static u64 __read_sbdchn(struct sbd_port *sport, int reg)
+{
+ void __iomem *csr = sport->port.membase + reg;
+
+ return __raw_readq(csr);
+}
+
+static u64 __read_sbdshr(struct sbd_port *sport, int reg)
+{
+ void __iomem *csr = sport->memctrl + reg;
+
+ return __raw_readq(csr);
+}
+
+static void __write_sbdchn(struct sbd_port *sport, int reg, u64 value)
+{
+ void __iomem *csr = sport->port.membase + reg;
+
+ __raw_writeq(value, csr);
+}
+
+static void __write_sbdshr(struct sbd_port *sport, int reg, u64 value)
+{
+ void __iomem *csr = sport->memctrl + reg;
+
+ __raw_writeq(value, csr);
+}
+
+/*
+ * In bug 1956, we get glitches that can mess up uart registers. This
+ * "read-mode-reg after any register access" is an accepted workaround.
+ */
+static void __war_sbd1956(struct sbd_port *sport)
+{
+ __read_sbdchn(sport, R_DUART_MODE_REG_1);
+ __read_sbdchn(sport, R_DUART_MODE_REG_2);
+}
+
+static unsigned char read_sbdchn(struct sbd_port *sport, int reg)
+{
+ unsigned char retval;
+
+ retval = __read_sbdchn(sport, reg);
+ if (SIBYTE_1956_WAR)
+ __war_sbd1956(sport);
+ return retval;
+}
+
+static unsigned char read_sbdshr(struct sbd_port *sport, int reg)
+{
+ unsigned char retval;
+
+ retval = __read_sbdshr(sport, reg);
+ if (SIBYTE_1956_WAR)
+ __war_sbd1956(sport);
+ return retval;
+}
+
+static void write_sbdchn(struct sbd_port *sport, int reg, unsigned int value)
+{
+ __write_sbdchn(sport, reg, value);
+ if (SIBYTE_1956_WAR)
+ __war_sbd1956(sport);
+}
+
+static void write_sbdshr(struct sbd_port *sport, int reg, unsigned int value)
+{
+ __write_sbdshr(sport, reg, value);
+ if (SIBYTE_1956_WAR)
+ __war_sbd1956(sport);
+}
+
+
+static int sbd_receive_ready(struct sbd_port *sport)
+{
+ return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_RX_RDY;
+}
+
+static int sbd_receive_drain(struct sbd_port *sport)
+{
+ int loops = 10000;
+
+ while (sbd_receive_ready(sport) && loops--)
+ read_sbdchn(sport, R_DUART_RX_HOLD);
+ return loops;
+}
+
+static int __unused sbd_transmit_ready(struct sbd_port *sport)
+{
+ return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY;
+}
+
+static int __unused sbd_transmit_drain(struct sbd_port *sport)
+{
+ int loops = 10000;
+
+ while (!sbd_transmit_ready(sport) && loops--)
+ udelay(2);
+ return loops;
+}
+
+static int sbd_transmit_empty(struct sbd_port *sport)
+{
+ return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_EMT;
+}
+
+static int sbd_line_drain(struct sbd_port *sport)
+{
+ int loops = 10000;
+
+ while (!sbd_transmit_empty(sport) && loops--)
+ udelay(2);
+ return loops;
+}
+
+
+static unsigned int sbd_tx_empty(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ return sbd_transmit_empty(sport) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int sbd_get_mctrl(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+ unsigned int mctrl, status;
+
+ status = read_sbdshr(sport, R_DUART_IN_PORT);
+ status >>= (uport->line) % 2;
+ mctrl = (!(status & M_DUART_IN_PIN0_VAL) ? TIOCM_CTS : 0) |
+ (!(status & M_DUART_IN_PIN4_VAL) ? TIOCM_CAR : 0) |
+ (!(status & M_DUART_RIN0_PIN) ? TIOCM_RNG : 0) |
+ (!(status & M_DUART_IN_PIN2_VAL) ? TIOCM_DSR : 0);
+ return mctrl;
+}
+
+static void sbd_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+ struct sbd_port *sport = to_sport(uport);
+ unsigned int clr = 0, set = 0, mode2;
+
+ if (mctrl & TIOCM_DTR)
+ set |= M_DUART_SET_OPR2;
+ else
+ clr |= M_DUART_CLR_OPR2;
+ if (mctrl & TIOCM_RTS)
+ set |= M_DUART_SET_OPR0;
+ else
+ clr |= M_DUART_CLR_OPR0;
+ clr <<= (uport->line) % 2;
+ set <<= (uport->line) % 2;
+
+ mode2 = read_sbdchn(sport, R_DUART_MODE_REG_2);
+ mode2 &= ~M_DUART_CHAN_MODE;
+ if (mctrl & TIOCM_LOOP)
+ mode2 |= V_DUART_CHAN_MODE_LCL_LOOP;
+ else
+ mode2 |= V_DUART_CHAN_MODE_NORMAL;
+
+ write_sbdshr(sport, R_DUART_CLEAR_OPR, clr);
+ write_sbdshr(sport, R_DUART_SET_OPR, set);
+ write_sbdchn(sport, R_DUART_MODE_REG_2, mode2);
+}
+
+static void sbd_stop_tx(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
+ sport->tx_stopped = 1;
+};
+
+static void sbd_start_tx(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+ unsigned int mask;
+
+ /* Enable tx interrupts. */
+ mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+ mask |= M_DUART_IMR_TX;
+ write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+
+ /* Go!, go!, go!... */
+ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
+ sport->tx_stopped = 0;
+};
+
+static void sbd_stop_rx(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
+};
+
+static void sbd_enable_ms(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ write_sbdchn(sport, R_DUART_AUXCTL_X,
+ M_DUART_CIN_CHNG_ENA | M_DUART_CTS_CHNG_ENA);
+}
+
+static void sbd_break_ctl(struct uart_port *uport, int break_state)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ if (break_state == -1)
+ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_START_BREAK);
+ else
+ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_STOP_BREAK);
+}
+
+
+static void sbd_receive_chars(struct sbd_port *sport)
+{
+ struct uart_port *uport = &sport->port;
+ struct uart_icount *icount;
+ unsigned int status, ch, flag;
+ int count;
+
+ for (count = 16; count; count--) {
+ status = read_sbdchn(sport, R_DUART_STATUS);
+ if (!(status & M_DUART_RX_RDY))
+ break;
+
+ ch = read_sbdchn(sport, R_DUART_RX_HOLD);
+
+ flag = TTY_NORMAL;
+
+ icount = &uport->icount;
+ icount->rx++;
+
+ if (unlikely(status &
+ (M_DUART_RCVD_BRK | M_DUART_FRM_ERR |
+ M_DUART_PARITY_ERR | M_DUART_OVRUN_ERR))) {
+ if (status & M_DUART_RCVD_BRK) {
+ icount->brk++;
+ if (uart_handle_break(uport))
+ continue;
+ } else if (status & M_DUART_FRM_ERR)
+ icount->frame++;
+ else if (status & M_DUART_PARITY_ERR)
+ icount->parity++;
+ if (status & M_DUART_OVRUN_ERR)
+ icount->overrun++;
+
+ status &= uport->read_status_mask;
+ if (status & M_DUART_RCVD_BRK)
+ flag = TTY_BREAK;
+ else if (status & M_DUART_FRM_ERR)
+ flag = TTY_FRAME;
+ else if (status & M_DUART_PARITY_ERR)
+ flag = TTY_PARITY;
+ }
+
+ if (uart_handle_sysrq_char(uport, ch))
+ continue;
+
+ uart_insert_char(uport, status, M_DUART_OVRUN_ERR, ch, flag);
+ }
+
+ tty_flip_buffer_push(uport->info->tty);
+}
+
+static void sbd_transmit_chars(struct sbd_port *sport)
+{
+ struct uart_port *uport = &sport->port;
+ struct circ_buf *xmit = &sport->port.info->xmit;
+ unsigned int mask;
+ int stop_tx;
+
+ /* XON/XOFF chars. */
+ if (sport->port.x_char) {
+ write_sbdchn(sport, R_DUART_TX_HOLD, sport->port.x_char);
+ sport->port.icount.tx++;
+ sport->port.x_char = 0;
+ return;
+ }
+
+ /* If nothing to do or stopped or hardware stopped. */
+ stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port));
+
+ /* Send char. */
+ if (!stop_tx) {
+ write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ sport->port.icount.tx++;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
+ }
+
+ /* Are we are done? */
+ if (stop_tx || uart_circ_empty(xmit)) {
+ /* Disable tx interrupts. */
+ mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+ mask &= ~M_DUART_IMR_TX;
+ write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+ }
+}
+
+static void sbd_status_handle(struct sbd_port *sport)
+{
+ struct uart_port *uport = &sport->port;
+ unsigned int delta;
+
+ delta = read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
+ delta >>= (uport->line) % 2;
+
+ if (delta & (M_DUART_IN_PIN0_VAL << S_DUART_IN_PIN_CHNG))
+ uart_handle_cts_change(uport, !(delta & M_DUART_IN_PIN0_VAL));
+
+ if (delta & (M_DUART_IN_PIN2_VAL << S_DUART_IN_PIN_CHNG))
+ uport->icount.dsr++;
+
+ if (delta & ((M_DUART_IN_PIN2_VAL | M_DUART_IN_PIN0_VAL) <<
+ S_DUART_IN_PIN_CHNG))
+ wake_up_interruptible(&uport->info->delta_msr_wait);
+}
+
+static irqreturn_t sbd_interrupt(int irq, void *dev_id)
+{
+ struct sbd_port *sport = dev_id;
+ struct uart_port *uport = &sport->port;
+ irqreturn_t status = IRQ_NONE;
+ unsigned int intstat;
+ int count;
+
+ for (count = 16; count; count--) {
+ intstat = read_sbdshr(sport,
+ R_DUART_ISRREG((uport->line) % 2));
+ intstat &= read_sbdshr(sport,
+ R_DUART_IMRREG((uport->line) % 2));
+ intstat &= M_DUART_ISR_ALL;
+ if (!intstat)
+ break;
+
+ if (intstat & M_DUART_ISR_RX)
+ sbd_receive_chars(sport);
+ if (intstat & M_DUART_ISR_IN)
+ sbd_status_handle(sport);
+ if (intstat & M_DUART_ISR_TX)
+ sbd_transmit_chars(sport);
+
+ status = IRQ_HANDLED;
+ }
+
+ return status;
+}
+
+
+static int sbd_startup(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+ unsigned int mode1;
+ int ret;
+
+ ret = request_irq(sport->port.irq, sbd_interrupt,
+ IRQF_SHARED, "sb1250-duart", sport);
+ if (ret)
+ return ret;
+
+ /* Clear the receive FIFO. */
+ sbd_receive_drain(sport);
+
+ /* Clear the interrupt registers. */
+ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT);
+ read_sbdshr(sport, R_DUART_INCHREG((uport->line) % 2));
+
+ /* Set rx/tx interrupt to FIFO available. */
+ mode1 = read_sbdchn(sport, R_DUART_MODE_REG_1);
+ mode1 &= ~(M_DUART_RX_IRQ_SEL_RXFULL | M_DUART_TX_IRQ_SEL_TXEMPT);
+ write_sbdchn(sport, R_DUART_MODE_REG_1, mode1);
+
+ /* Disable tx, enable rx. */
+ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_EN);
+ sport->tx_stopped = 1;
+
+ /* Enable interrupts. */
+ write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
+ M_DUART_IMR_IN | M_DUART_IMR_RX);
+
+ return 0;
+}
+
+static void sbd_shutdown(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
+ sport->tx_stopped = 1;
+ free_irq(sport->port.irq, sport);
+}
+
+
+static void sbd_init_port(struct sbd_port *sport)
+{
+ struct uart_port *uport = &sport->port;
+
+ if (sport->initialised)
+ return;
+
+ /* There is no DUART reset feature, so just set some sane defaults. */
+ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_TX);
+ write_sbdchn(sport, R_DUART_CMD, V_DUART_MISC_CMD_RESET_RX);
+ write_sbdchn(sport, R_DUART_MODE_REG_1, V_DUART_BITS_PER_CHAR_8);
+ write_sbdchn(sport, R_DUART_MODE_REG_2, 0);
+ write_sbdchn(sport, R_DUART_FULL_CTL,
+ V_DUART_INT_TIME(0) | V_DUART_SIG_FULL(15));
+ write_sbdchn(sport, R_DUART_OPCR_X, 0);
+ write_sbdchn(sport, R_DUART_AUXCTL_X, 0);
+ write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), 0);
+
+ sport->initialised = 1;
+}
+
+static void sbd_set_termios(struct uart_port *uport, struct ktermios *termios,
+ struct ktermios *old_termios)
+{
+ struct sbd_port *sport = to_sport(uport);
+ unsigned int mode1 = 0, mode2 = 0, aux = 0;
+ unsigned int mode1mask = 0, mode2mask = 0, auxmask = 0;
+ unsigned int oldmode1, oldmode2, oldaux;
+ unsigned int baud, brg;
+ unsigned int command;
+
+ mode1mask |= ~(M_DUART_PARITY_MODE | M_DUART_PARITY_TYPE_ODD |
+ M_DUART_BITS_PER_CHAR);
+ mode2mask |= ~M_DUART_STOP_BIT_LEN_2;
+ auxmask |= ~M_DUART_CTS_CHNG_ENA;
+
+ /* Byte size. */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ case CS6:
+ /* Unsupported, leave unchanged. */
+ mode1mask |= M_DUART_PARITY_MODE;
+ break;
+ case CS7:
+ mode1 |= V_DUART_BITS_PER_CHAR_7;
+ break;
+ case CS8:
+ default:
+ mode1 |= V_DUART_BITS_PER_CHAR_8;
+ break;
+ }
+
+ /* Parity and stop bits. */
+ if (termios->c_cflag & CSTOPB)
+ mode2 |= M_DUART_STOP_BIT_LEN_2;
+ else
+ mode2 |= M_DUART_STOP_BIT_LEN_1;
+ if (termios->c_cflag & PARENB)
+ mode1 |= V_DUART_PARITY_MODE_ADD;
+ else
+ mode1 |= V_DUART_PARITY_MODE_NONE;
+ if (termios->c_cflag & PARODD)
+ mode1 |= M_DUART_PARITY_TYPE_ODD;
+ else
+ mode1 |= M_DUART_PARITY_TYPE_EVEN;
+
+ baud = uart_get_baud_rate(uport, termios, old_termios, 1200, 5000000);
+ brg = V_DUART_BAUD_RATE(baud);
+ /* The actual lower bound is 1221bps, so compensate. */
+ if (brg > M_DUART_CLK_COUNTER)
+ brg = M_DUART_CLK_COUNTER;
+
+ uart_update_timeout(uport, termios->c_cflag, baud);
+
+ uport->read_status_mask = M_DUART_OVRUN_ERR;
+ if (termios->c_iflag & INPCK)
+ uport->read_status_mask |= M_DUART_FRM_ERR |
+ M_DUART_PARITY_ERR;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ uport->read_status_mask |= M_DUART_RCVD_BRK;
+
+ uport->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ uport->ignore_status_mask |= M_DUART_FRM_ERR |
+ M_DUART_PARITY_ERR;
+ if (termios->c_iflag & IGNBRK) {
+ uport->ignore_status_mask |= M_DUART_RCVD_BRK;
+ if (termios->c_iflag & IGNPAR)
+ uport->ignore_status_mask |= M_DUART_OVRUN_ERR;
+ }
+
+ if (termios->c_cflag & CREAD)
+ command = M_DUART_RX_EN;
+ else
+ command = M_DUART_RX_DIS;
+
+ if (termios->c_cflag & CRTSCTS)
+ aux |= M_DUART_CTS_CHNG_ENA;
+ else
+ aux &= ~M_DUART_CTS_CHNG_ENA;
+
+ spin_lock(&uport->lock);
+
+ if (sport->tx_stopped)
+ command |= M_DUART_TX_DIS;
+ else
+ command |= M_DUART_TX_EN;
+
+ oldmode1 = read_sbdchn(sport, R_DUART_MODE_REG_1) & mode1mask;
+ oldmode2 = read_sbdchn(sport, R_DUART_MODE_REG_2) & mode2mask;
+ oldaux = read_sbdchn(sport, R_DUART_AUXCTL_X) & auxmask;
+
+ if (!sport->tx_stopped)
+ sbd_line_drain(sport);
+ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS | M_DUART_RX_DIS);
+
+ write_sbdchn(sport, R_DUART_MODE_REG_1, mode1 | oldmode1);
+ write_sbdchn(sport, R_DUART_MODE_REG_2, mode2 | oldmode2);
+ write_sbdchn(sport, R_DUART_CLK_SEL, brg);
+ write_sbdchn(sport, R_DUART_AUXCTL_X, aux | oldaux);
+
+ write_sbdchn(sport, R_DUART_CMD, command);
+
+ spin_unlock(&uport->lock);
+}
+
+
+static const char *sbd_type(struct uart_port *uport)
+{
+ return "SB1250 DUART";
+}
+
+static void sbd_release_port(struct uart_port *uport)
+{
+ struct sbd_port *sport = to_sport(uport);
+ struct sbd_duart *duart = sport->duart;
+ int map_guard;
+
+ iounmap(sport->memctrl);
+ sport->memctrl = NULL;
+ iounmap(uport->membase);
+ uport->membase = NULL;
+
+ map_guard = atomic_add_return(-1, &duart->map_guard);
+ if (!map_guard)
+ release_mem_region(duart->mapctrl, DUART_CHANREG_SPACING);
+ release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
+}
+
+static int sbd_map_port(struct uart_port *uport)
+{
+ static const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
+ struct sbd_port *sport = to_sport(uport);
+ struct sbd_duart *duart = sport->duart;
+
+ if (!uport->membase)
+ uport->membase = ioremap_nocache(uport->mapbase,
+ DUART_CHANREG_SPACING);
+ if (!uport->membase) {
+ printk(err);
+ return -ENOMEM;
+ }
+
+ if (!sport->memctrl)
+ sport->memctrl = ioremap_nocache(duart->mapctrl,
+ DUART_CHANREG_SPACING);
+ if (!sport->memctrl) {
+ printk(err);
+ iounmap(uport->membase);
+ uport->membase = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int sbd_request_port(struct uart_port *uport)
+{
+ static const char *err = KERN_ERR
+ "sbd: Unable to reserve MMIO resource\n";
+ struct sbd_duart *duart = to_sport(uport)->duart;
+ int map_guard;
+ int ret = 0;
+
+ if (!request_mem_region(uport->mapbase, DUART_CHANREG_SPACING,
+ "sb1250-duart")) {
+ printk(err);
+ return -EBUSY;
+ }
+ map_guard = atomic_add_return(1, &duart->map_guard);
+ if (map_guard == 1) {
+ if (!request_mem_region(duart->mapctrl, DUART_CHANREG_SPACING,
+ "sb1250-duart")) {
+ atomic_add(-1, &duart->map_guard);
+ printk(err);
+ ret = -EBUSY;
+ }
+ }
+ if (!ret) {
+ ret = sbd_map_port(uport);
+ if (ret) {
+ map_guard = atomic_add_return(-1, &duart->map_guard);
+ if (!map_guard)
+ release_mem_region(duart->mapctrl,
+ DUART_CHANREG_SPACING);
+ }
+ }
+ if (ret) {
+ release_mem_region(uport->mapbase, DUART_CHANREG_SPACING);
+ return ret;
+ }
+ return 0;
+}
+
+static void sbd_config_port(struct uart_port *uport, int flags)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ if (flags & UART_CONFIG_TYPE) {
+ if (sbd_request_port(uport))
+ return;
+
+ uport->type = PORT_SB1250_DUART;
+
+ sbd_init_port(sport);
+ }
+}
+
+static int sbd_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_SB1250_DUART)
+ ret = -EINVAL;
+ if (ser->irq != uport->irq)
+ ret = -EINVAL;
+ if (ser->baud_base != uport->uartclk / 16)
+ ret = -EINVAL;
+ return ret;
+}
+
+
+static struct uart_ops sbd_ops = {
+ .tx_empty = sbd_tx_empty,
+ .set_mctrl = sbd_set_mctrl,
+ .get_mctrl = sbd_get_mctrl,
+ .stop_tx = sbd_stop_tx,
+ .start_tx = sbd_start_tx,
+ .stop_rx = sbd_stop_rx,
+ .enable_ms = sbd_enable_ms,
+ .break_ctl = sbd_break_ctl,
+ .startup = sbd_startup,
+ .shutdown = sbd_shutdown,
+ .set_termios = sbd_set_termios,
+ .type = sbd_type,
+ .release_port = sbd_release_port,
+ .request_port = sbd_request_port,
+ .config_port = sbd_config_port,
+ .verify_port = sbd_verify_port,
+};
+
+/* Initialize SB1250 DUART port structures. */
+static void __init sbd_probe_duarts(void)
+{
+ static int probed;
+ int chip, side;
+ int max_lines, line;
+
+ if (probed)
+ return;
+
+ /* Set the number of available units based on the SOC type. */
+ switch (soc_type) {
+ case K_SYS_SOC_TYPE_BCM1x55:
+ case K_SYS_SOC_TYPE_BCM1x80:
+ max_lines = 4;
+ break;
+ default:
+ /* Assume at least two serial ports at the normal address. */
+ max_lines = 2;
+ break;
+ }
+
+ probed = 1;
+
+ for (chip = 0, line = 0; chip < DUART_MAX_CHIP && line < max_lines;
+ chip++) {
+ sbd_duarts[chip].mapctrl = SBD_CTRLREGS(line);
+
+ for (side = 0; side < DUART_MAX_SIDE && line < max_lines;
+ side++, line++) {
+ struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+ struct uart_port *uport = &sport->port;
+
+ sport->duart = &sbd_duarts[chip];
+
+ uport->irq = SBD_INT(line);
+ uport->uartclk = 100000000 / 20 * 16;
+ uport->fifosize = 16;
+ uport->iotype = UPIO_MEM;
+ uport->flags = UPF_BOOT_AUTOCONF;
+ uport->ops = &sbd_ops;
+ uport->line = line;
+ uport->mapbase = SBD_CHANREGS(line);
+ }
+ }
+}
+
+
+#ifdef CONFIG_SERIAL_SB1250_DUART_CONSOLE
+/*
+ * Serial console stuff. Very basic, polling driver for doing serial
+ * console output. The console_sem is held by the caller, so we
+ * shouldn't be interrupted for more console activity.
+ */
+static void sbd_console_putchar(struct uart_port *uport, int ch)
+{
+ struct sbd_port *sport = to_sport(uport);
+
+ sbd_transmit_drain(sport);
+ write_sbdchn(sport, R_DUART_TX_HOLD, ch);
+}
+
+static void sbd_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ int chip = co->index / DUART_MAX_SIDE;
+ int side = co->index % DUART_MAX_SIDE;
+ struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+ struct uart_port *uport = &sport->port;
+ unsigned long flags;
+ unsigned int mask;
+
+ /* Disable transmit interrupts and enable the transmitter. */
+ spin_lock_irqsave(&uport->lock, flags);
+ mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
+ write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2),
+ mask & ~M_DUART_IMR_TX);
+ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_EN);
+ spin_unlock_irqrestore(&uport->lock, flags);
+
+ uart_console_write(&sport->port, s, count, sbd_console_putchar);
+
+ /* Restore transmit interrupts and the transmitter enable. */
+ spin_lock_irqsave(&uport->lock, flags);
+ sbd_line_drain(sport);
+ if (sport->tx_stopped)
+ write_sbdchn(sport, R_DUART_CMD, M_DUART_TX_DIS);
+ write_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2), mask);
+ spin_unlock_irqrestore(&uport->lock, flags);
+}
+
+static int __init sbd_console_setup(struct console *co, char *options)
+{
+ int chip = co->index / DUART_MAX_SIDE;
+ int side = co->index % DUART_MAX_SIDE;
+ struct sbd_port *sport = &sbd_duarts[chip].sport[side];
+ struct uart_port *uport = &sport->port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ int ret;
+
+ if (!sport->duart)
+ return -ENXIO;
+
+ ret = sbd_map_port(uport);
+ if (ret)
+ return ret;
+
+ sbd_init_port(sport);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sbd_reg;
+static struct console sbd_console = {
+ .name = "duart",
+ .write = sbd_console_write,
+ .device = uart_console_device,
+ .setup = sbd_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &sbd_reg
+};
+
+static int __init sbd_serial_console_init(void)
+{
+ sbd_probe_duarts();
+ register_console(&sbd_console);
+
+ return 0;
+}
+
+console_initcall(sbd_serial_console_init);
+
+#define SERIAL_SB1250_DUART_CONSOLE &sbd_console
+#else
+#define SERIAL_SB1250_DUART_CONSOLE NULL
+#endif /* CONFIG_SERIAL_SB1250_DUART_CONSOLE */
+
+
+static struct uart_driver sbd_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "duart",
+ .major = TTY_MAJOR,
+ .minor = SB1250_DUART_MINOR_BASE,
+ .nr = DUART_MAX_CHIP * DUART_MAX_SIDE,
+ .cons = SERIAL_SB1250_DUART_CONSOLE,
+};
+
+/* Set up the driver and register it. */
+static int __init sbd_init(void)
+{
+ int i, ret;
+
+ sbd_probe_duarts();
+
+ ret = uart_register_driver(&sbd_reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < DUART_MAX_CHIP * DUART_MAX_SIDE; i++) {
+ struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
+ struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
+ struct uart_port *uport = &sport->port;
+
+ if (sport->duart)
+ uart_add_one_port(&sbd_reg, uport);
+ }
+
+ return 0;
+}
+
+/* Unload the driver. Unregister stuff, get ready to go away. */
+static void __exit sbd_exit(void)
+{
+ int i;
+
+ for (i = DUART_MAX_CHIP * DUART_MAX_SIDE - 1; i >= 0; i--) {
+ struct sbd_duart *duart = &sbd_duarts[i / DUART_MAX_SIDE];
+ struct sbd_port *sport = &duart->sport[i % DUART_MAX_SIDE];
+ struct uart_port *uport = &sport->port;
+
+ if (sport->duart)
+ uart_remove_one_port(&sbd_reg, uport);
+ }
+
+ uart_unregister_driver(&sbd_reg);
+}
+
+module_init(sbd_init);
+module_exit(sbd_exit);
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 326020f86f75..9c57486c2e7f 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1910,6 +1910,12 @@ uart_set_options(struct uart_port *port, struct console *co,
if (flow == 'r')
termios.c_cflag |= CRTSCTS;
+ /*
+ * some uarts on other side don't support no flow control.
+ * So we set * DTR in host uart to make them happy
+ */
+ port->mctrl |= TIOCM_DTR;
+
port->ops->set_termios(port, &termios, NULL);
co->cflag = termios.c_cflag;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 1f89496d530e..672cd1042539 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -367,7 +367,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
} else {
#ifdef CONFIG_CPU_SUBTYPE_SH7343
/* Nothing */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+ defined(CONFIG_CPU_SUBTYPE_SHX3)
ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
#else
ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index fb04fb5f9843..247fb66bf0f4 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -53,7 +53,12 @@
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7091) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751R)
# define SCSPTR1 0xffe0001c /* 8 bit SCI */
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
@@ -73,7 +78,7 @@
# define SCPDR 0xA4050136 /* 16 bit SCIF */
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
# define SCI_NPORTS 2
# define SCIF_ORER 0x0001 /* overrun error bit */
@@ -168,6 +173,14 @@
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
+# define SCSPTR0 0xffc30020 /* 16 bit SCIF */
+# define SCSPTR1 0xffc40020 /* 16 bit SCIF */
+# define SCSPTR2 0xffc50020 /* 16 bit SCIF */
+# define SCSPTR3 0xffc60020 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001 /* Overrun error bit */
+# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
+# define SCIF_ONLY
#else
# error CPU subtype not defined
#endif
@@ -177,10 +190,15 @@
#define SCI_CTRL_FLAGS_RIE 0x40 /* all */
#define SCI_CTRL_FLAGS_TE 0x20 /* all */
#define SCI_CTRL_FLAGS_RE 0x10 /* all */
-#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
- defined(CONFIG_CPU_SUBTYPE_SH7751) || \
- defined(CONFIG_CPU_SUBTYPE_SH7780) || \
- defined(CONFIG_CPU_SUBTYPE_SH7785)
+#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7091) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7785) || \
+ defined(CONFIG_CPU_SUBTYPE_SHX3)
#define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */
#else
#define SCI_CTRL_FLAGS_REIE 0
@@ -514,8 +532,12 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port)
}
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
- defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7751R) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750R) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7750S) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7091) || \
defined(CONFIG_CPU_SUBTYPE_SH4_202)
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -653,6 +675,18 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
return 1;
}
+#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xffc30000)
+ return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffc40000)
+ return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffc50000)
+ return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffc60000)
+ return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+}
#endif
/*
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index a27e9e92cb5e..41fc61264443 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -759,7 +759,7 @@ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port)
*/
static void sn_sal_console_write(struct console *, const char *, unsigned);
-static int __init sn_sal_console_setup(struct console *, char *);
+static int sn_sal_console_setup(struct console *, char *);
static struct uart_driver sal_console_uart;
extern struct tty_driver *uart_console_device(struct console *, int *);
@@ -1006,7 +1006,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
* here so providing it is easier.
*
*/
-static int __init sn_sal_console_setup(struct console *co, char *options)
+static int sn_sal_console_setup(struct console *co, char *options)
{
return 0;
}
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index b45ba5392dd3..70a09a3d5af0 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -16,9 +16,10 @@
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h>
+#include <linux/serial_core.h>
#include <linux/init.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
#include "suncore.h"
@@ -26,92 +27,60 @@ int sunserial_current_minor = 64;
EXPORT_SYMBOL(sunserial_current_minor);
-void
-sunserial_console_termios(struct console *con)
+int sunserial_console_match(struct console *con, struct device_node *dp,
+ struct uart_driver *drv, int line)
{
- char mode[16], buf[16], *s;
- char mode_prop[] = "ttyX-mode";
- char cd_prop[] = "ttyX-ignore-cd";
- char dtr_prop[] = "ttyX-rts-dtr-off";
- char *ssp_console_modes_prop = "ssp-console-modes";
- int baud, bits, stop, cflag;
- char parity;
- int carrier = 0;
- int rtsdtr = 1;
- int topnd, nd;
-
- if (!serial_console)
- return;
-
- switch (serial_console) {
- case PROMDEV_OTTYA:
- mode_prop[3] = 'a';
- cd_prop[3] = 'a';
- dtr_prop[3] = 'a';
- break;
-
- case PROMDEV_OTTYB:
- mode_prop[3] = 'b';
- cd_prop[3] = 'b';
- dtr_prop[3] = 'b';
- break;
-
- case PROMDEV_ORSC:
-
- nd = prom_pathtoinode("rsc");
- if (!nd) {
- strcpy(mode, "115200,8,n,1,-");
- goto no_options;
- }
+ int off;
- if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
- strcpy(mode, "115200,8,n,1,-");
- goto no_options;
- }
+ if (!con || of_console_device != dp)
+ return 0;
- memset(mode, 0, sizeof(mode));
- prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
- goto no_options;
+ off = 0;
+ if (of_console_options &&
+ *of_console_options == 'b')
+ off = 1;
- default:
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
+ if ((line & 1) != off)
+ return 0;
- topnd = prom_getchild(prom_root_node);
- nd = prom_searchsiblings(topnd, "options");
- if (!nd) {
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
-
- if (!prom_node_has_property(nd, mode_prop)) {
- strcpy(mode, "9600,8,n,1,-");
- goto no_options;
- }
+ con->index = line;
+ drv->cons = con;
+ add_preferred_console(con->name, line, NULL);
- memset(mode, 0, sizeof(mode));
- prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
- if (prom_node_has_property(nd, cd_prop)) {
- memset(buf, 0, sizeof(buf));
- prom_getstring(nd, cd_prop, buf, sizeof(buf));
- if (!strcmp(buf, "false"))
- carrier = 1;
-
- /* XXX: this is unused below. */
- }
+ return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
- if (prom_node_has_property(nd, dtr_prop)) {
- memset(buf, 0, sizeof(buf));
- prom_getstring(nd, dtr_prop, buf, sizeof(buf));
- if (!strcmp(buf, "false"))
- rtsdtr = 0;
+void
+sunserial_console_termios(struct console *con)
+{
+ struct device_node *dp;
+ const char *od, *mode, *s;
+ char mode_prop[] = "ttyX-mode";
+ int baud, bits, stop, cflag;
+ char parity;
- /* XXX: this is unused below. */
+ dp = of_find_node_by_path("/options");
+ od = of_get_property(dp, "output-device", NULL);
+ if (!strcmp(od, "rsc")) {
+ mode = of_get_property(of_console_device,
+ "ssp-console-modes", NULL);
+ if (!mode)
+ mode = "115200,8,n,1,-";
+ } else {
+ char c;
+
+ c = 'a';
+ if (of_console_options)
+ c = *of_console_options;
+
+ mode_prop[3] = c;
+
+ mode = of_get_property(dp, mode_prop, NULL);
+ if (!mode)
+ mode = "9600,8,n,1,-";
}
-no_options:
cflag = CREAD | HUPCL | CLOCAL;
s = mode;
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
index 513916a8ce37..829d7d65d6db 100644
--- a/drivers/serial/suncore.h
+++ b/drivers/serial/suncore.h
@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int);
extern int sunserial_current_minor;
+extern int sunserial_console_match(struct console *, struct device_node *,
+ struct uart_driver *, int);
extern void sunserial_console_termios(struct console *);
#endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index 96557e6dba60..8ff900b09811 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -258,17 +258,7 @@ static void sunhv_stop_tx(struct uart_port *port)
/* port->lock held by caller. */
static void sunhv_start_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->info->xmit;
-
- while (!uart_circ_empty(xmit)) {
- long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
-
- if (status != HV_EOK)
- break;
-
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- }
+ transmit_chars(port);
}
/* port->lock is not held. */
@@ -440,8 +430,16 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
{
struct uart_port *port = sunhv_port;
unsigned long flags;
+ int locked = 1;
+
+ local_irq_save(flags);
+ if (port->sysrq) {
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&port->lock);
+ } else
+ spin_lock(&port->lock);
- spin_lock_irqsave(&port->lock, flags);
while (n > 0) {
unsigned long ra = __pa(con_write_page);
unsigned long page_bytes;
@@ -469,7 +467,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign
ra += written;
}
}
- spin_unlock_irqrestore(&port->lock, flags);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
}
static inline void sunhv_console_putchar(struct uart_port *port, char c)
@@ -488,7 +489,15 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
{
struct uart_port *port = sunhv_port;
unsigned long flags;
- int i;
+ int i, locked = 1;
+
+ local_irq_save(flags);
+ if (port->sysrq) {
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&port->lock);
+ } else
+ spin_lock(&port->lock);
spin_lock_irqsave(&port->lock, flags);
for (i = 0; i < n; i++) {
@@ -496,7 +505,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig
sunhv_console_putchar(port, '\r');
sunhv_console_putchar(port, *s++);
}
- spin_unlock_irqrestore(&port->lock, flags);
+
+ if (locked)
+ spin_unlock(&port->lock);
+ local_irq_restore(flags);
}
static struct console sunhv_console = {
@@ -508,16 +520,6 @@ static struct console sunhv_console = {
.data = &sunhv_reg,
};
-static inline struct console *SUNHV_CONSOLE(void)
-{
- if (con_is_present())
- return NULL;
-
- sunhv_console.index = 0;
-
- return &sunhv_console;
-}
-
static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
{
struct uart_port *port;
@@ -570,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1;
- sunhv_reg.cons = SUNHV_CONSOLE();
+ sunserial_console_match(&sunhv_console, op->node,
+ &sunhv_reg, port->line);
err = uart_add_one_port(&sunhv_reg, port);
if (err)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index deb9ab4b5a0b..bca57bb94939 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -860,22 +860,31 @@ static int num_channels;
static void sunsab_console_putchar(struct uart_port *port, int c)
{
struct uart_sunsab_port *up = (struct uart_sunsab_port *)port;
- unsigned long flags;
-
- spin_lock_irqsave(&up->port.lock, flags);
sunsab_tec_wait(up);
writeb(c, &up->regs->w.tic);
-
- spin_unlock_irqrestore(&up->port.lock, flags);
}
static void sunsab_console_write(struct console *con, const char *s, unsigned n)
{
struct uart_sunsab_port *up = &sunsab_ports[con->index];
+ unsigned long flags;
+ int locked = 1;
+
+ local_irq_save(flags);
+ if (up->port.sysrq) {
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&up->port.lock);
+ } else
+ spin_lock(&up->port.lock);
uart_console_write(&up->port, s, n, sunsab_console_putchar);
sunsab_tec_wait(up);
+
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
}
static int sunsab_console_setup(struct console *con, char *options)
@@ -959,22 +968,6 @@ static struct console sunsab_console = {
static inline struct console *SUNSAB_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < num_channels; i++) {
- int this_minor = sunsab_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == num_channels)
- return NULL;
-
- sunsab_console.index = i;
-
return &sunsab_console;
}
#else
@@ -1071,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
return err;
}
+ sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+ &sunsab_reg, up[0].port.line);
uart_add_one_port(&sunsab_reg, &up[0].port);
+
+ sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+ &sunsab_reg, up[1].port.line);
uart_add_one_port(&sunsab_reg, &up[1].port);
dev_set_drvdata(&op->dev, &up[0]);
@@ -1155,7 +1153,6 @@ static int __init sunsab_init(void)
}
sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
- sunsab_reg.cons = SUNSAB_CONSOLE();
sunserial_current_minor += num_channels;
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 2a63cdba3208..79b13685bdfa 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1288,7 +1288,17 @@ static void sunsu_console_write(struct console *co, const char *s,
unsigned int count)
{
struct uart_sunsu_port *up = &sunsu_ports[co->index];
+ unsigned long flags;
unsigned int ier;
+ int locked = 1;
+
+ local_irq_save(flags);
+ if (up->port.sysrq) {
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&up->port.lock);
+ } else
+ spin_lock(&up->port.lock);
/*
* First save the UER then disable the interrupts
@@ -1304,6 +1314,10 @@ static void sunsu_console_write(struct console *co, const char *s,
*/
wait_for_xmitr(up);
serial_out(up, UART_IER, ier);
+
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
}
/*
@@ -1357,28 +1371,12 @@ static struct console sunsu_console = {
* Register console.
*/
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < num_uart; i++) {
- int this_minor = sunsu_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == num_uart)
- return NULL;
-
- sunsu_console.index = i;
-
return &sunsu_console;
}
#else
-#define SUNSU_CONSOLE(num_uart) (NULL)
+#define SUNSU_CONSOLE() (NULL)
#define sunsu_serial_console_init() do { } while (0)
#endif
@@ -1468,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
up->port.ops = &sunsu_pops;
+ sunserial_console_match(SUNSU_CONSOLE(), dp,
+ &sunsu_reg, up->port.line);
err = uart_add_one_port(&sunsu_reg, &up->port);
if (err)
goto out_unmap;
@@ -1558,7 +1558,6 @@ static int __init sunsu_init(void)
return err;
sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
sunserial_current_minor += num_uart;
- sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
}
err = of_register_driver(&su_driver, &of_bus_type);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 15b6e1cb040b..1d262c0c613f 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -9,7 +9,7 @@
* C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
* work there.
*
- * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -1151,11 +1151,22 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count)
{
struct uart_sunzilog_port *up = &sunzilog_port_table[con->index];
unsigned long flags;
+ int locked = 1;
+
+ local_irq_save(flags);
+ if (up->port.sysrq) {
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&up->port.lock);
+ } else
+ spin_lock(&up->port.lock);
- spin_lock_irqsave(&up->port.lock, flags);
uart_console_write(&up->port, s, count, sunzilog_putchar);
udelay(2);
- spin_unlock_irqrestore(&up->port.lock, flags);
+
+ if (locked)
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
}
static int __init sunzilog_console_setup(struct console *con, char *options)
@@ -1215,23 +1226,6 @@ static struct console sunzilog_console_ops = {
static inline struct console *SUNZILOG_CONSOLE(void)
{
- int i;
-
- if (con_is_present())
- return NULL;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- int this_minor = sunzilog_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == NUM_CHANNELS)
- return NULL;
-
- sunzilog_console_ops.index = i;
- sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
return &sunzilog_console_ops;
}
@@ -1417,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
sunzilog_init_hw(&up[1]);
if (!keyboard_mouse) {
+ if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+ &sunzilog_reg, up[0].port.line))
+ up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[0].port);
if (err) {
of_iounmap(&op->resource[0],
rp, sizeof(struct zilog_layout));
return err;
}
+ if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+ &sunzilog_reg, up[1].port.line))
+ up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[1].port);
if (err) {
uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1520,7 +1520,6 @@ static int __init sunzilog_init(void)
goto out_free_tables;
sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
- sunzilog_reg.cons = SUNZILOG_CONSOLE();
sunserial_current_minor += uart_count;
}
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index cf0e663b42ed..85309acb75f6 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-2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2004-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* Based on drivers/serial/8250.c, by Russell King.
*
@@ -25,12 +25,12 @@
#endif
#include <linux/console.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/ioport.h>
+#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/ioport.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
@@ -38,11 +38,9 @@
#include <linux/tty_flip.h>
#include <asm/io.h>
-#include <asm/vr41xx/irq.h>
#include <asm/vr41xx/siu.h>
#include <asm/vr41xx/vr41xx.h>
-#define SIU_PORTS_MAX 2
#define SIU_BAUD_BASE 1152000
#define SIU_MAJOR 204
#define SIU_MINOR_BASE 82
@@ -60,32 +58,13 @@
#define IRUSESEL 0x02
#define SIRSEL 0x01
-struct siu_port {
- unsigned int type;
- unsigned int irq;
- unsigned long start;
-};
-
-static const struct siu_port siu_type1_ports[] = {
- { .type = PORT_VR41XX_SIU,
- .irq = SIU_IRQ,
- .start = 0x0c000000UL, },
-};
-
-#define SIU_TYPE1_NR_PORTS (sizeof(siu_type1_ports) / sizeof(struct siu_port))
-
-static const struct siu_port siu_type2_ports[] = {
- { .type = PORT_VR41XX_SIU,
- .irq = SIU_IRQ,
- .start = 0x0f000800UL, },
- { .type = PORT_VR41XX_DSIU,
- .irq = DSIU_IRQ,
- .start = 0x0f000820UL, },
+static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
+ [0 ... SIU_PORTS_MAX-1] = {
+ .lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
+ .irq = -1,
+ },
};
-#define SIU_TYPE2_NR_PORTS (sizeof(siu_type2_ports) / sizeof(struct siu_port))
-
-static struct uart_port siu_uart_ports[SIU_PORTS_MAX];
static uint8_t lsr_break_flag[SIU_PORTS_MAX];
#define siu_read(port, offset) readb((port)->membase + (offset))
@@ -110,7 +89,6 @@ void vr41xx_select_siu_interface(siu_interface_t interface)
spin_unlock_irqrestore(&port->lock, flags);
}
-
EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
void vr41xx_use_irda(irda_use_t use)
@@ -132,7 +110,6 @@ void vr41xx_use_irda(irda_use_t use)
spin_unlock_irqrestore(&port->lock, flags);
}
-
EXPORT_SYMBOL_GPL(vr41xx_use_irda);
void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
@@ -166,7 +143,6 @@ void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
spin_unlock_irqrestore(&port->lock, flags);
}
-
EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
static inline void siu_clear_fifo(struct uart_port *port)
@@ -177,21 +153,6 @@ static inline void siu_clear_fifo(struct uart_port *port)
siu_write(port, UART_FCR, 0);
}
-static inline int siu_probe_ports(void)
-{
- switch (current_cpu_data.cputype) {
- case CPU_VR4111:
- case CPU_VR4121:
- return SIU_TYPE1_NR_PORTS;
- case CPU_VR4122:
- case CPU_VR4131:
- case CPU_VR4133:
- return SIU_TYPE2_NR_PORTS;
- }
-
- return 0;
-}
-
static inline unsigned long siu_port_size(struct uart_port *port)
{
switch (port->type) {
@@ -206,21 +167,10 @@ static inline unsigned long siu_port_size(struct uart_port *port)
static inline unsigned int siu_check_type(struct uart_port *port)
{
- switch (current_cpu_data.cputype) {
- case CPU_VR4111:
- case CPU_VR4121:
- if (port->line == 0)
- return PORT_VR41XX_SIU;
- break;
- case CPU_VR4122:
- case CPU_VR4131:
- case CPU_VR4133:
- if (port->line == 0)
- return PORT_VR41XX_SIU;
- else if (port->line == 1)
- return PORT_VR41XX_DSIU;
- break;
- }
+ if (port->line == 0)
+ return PORT_VR41XX_SIU;
+ if (port->line == 1 && port->irq != -1)
+ return PORT_VR41XX_DSIU;
return PORT_UNKNOWN;
}
@@ -751,44 +701,34 @@ static struct uart_ops siu_uart_ops = {
.verify_port = siu_verify_port,
};
-static int siu_init_ports(void)
+static int siu_init_ports(struct platform_device *pdev)
{
- const struct siu_port *siu;
struct uart_port *port;
- int i, num;
+ struct resource *res;
+ int *type = pdev->dev.platform_data;
+ int i;
- switch (current_cpu_data.cputype) {
- case CPU_VR4111:
- case CPU_VR4121:
- siu = siu_type1_ports;
- break;
- case CPU_VR4122:
- case CPU_VR4131:
- case CPU_VR4133:
- siu = siu_type2_ports;
- break;
- default:
+ if (!type)
return 0;
- }
port = siu_uart_ports;
- num = siu_probe_ports();
- for (i = 0; i < num; i++) {
- spin_lock_init(&port->lock);
- port->irq = siu->irq;
+ for (i = 0; i < SIU_PORTS_MAX; i++) {
+ port->type = type[i];
+ if (port->type == PORT_UNKNOWN)
+ continue;
+ port->irq = platform_get_irq(pdev, i);
port->uartclk = SIU_BAUD_BASE * 16;
port->fifosize = 16;
port->regshift = 0;
port->iotype = UPIO_MEM;
port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
- port->type = siu->type;
port->line = i;
- port->mapbase = siu->start;
- siu++;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ port->mapbase = res->start;
port++;
}
- return num;
+ return i;
}
#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
@@ -883,13 +823,9 @@ static struct console siu_console = {
static int __devinit siu_console_init(void)
{
struct uart_port *port;
- int num, i;
-
- num = siu_init_ports();
- if (num <= 0)
- return -ENODEV;
+ int i;
- for (i = 0; i < num; i++) {
+ for (i = 0; i < SIU_PORTS_MAX; i++) {
port = &siu_uart_ports[i];
port->ops = &siu_uart_ops;
}
@@ -920,7 +856,7 @@ static int __devinit siu_probe(struct platform_device *dev)
struct uart_port *port;
int num, i, retval;
- num = siu_init_ports();
+ num = siu_init_ports(dev);
if (num <= 0)
return -ENODEV;
@@ -998,8 +934,6 @@ static int siu_resume(struct platform_device *dev)
return 0;
}
-static struct platform_device *siu_platform_device;
-
static struct platform_driver siu_device_driver = {
.probe = siu_probe,
.remove = __devexit_p(siu_remove),
@@ -1013,29 +947,12 @@ static struct platform_driver siu_device_driver = {
static int __init vr41xx_siu_init(void)
{
- int retval;
-
- siu_platform_device = platform_device_alloc("SIU", -1);
- if (!siu_platform_device)
- return -ENOMEM;
-
- retval = platform_device_add(siu_platform_device);
- if (retval < 0) {
- platform_device_put(siu_platform_device);
- return retval;
- }
-
- retval = platform_driver_register(&siu_device_driver);
- if (retval < 0)
- platform_device_unregister(siu_platform_device);
-
- return retval;
+ return platform_driver_register(&siu_device_driver);
}
static void __exit vr41xx_siu_exit(void)
{
platform_driver_unregister(&siu_device_driver);
- platform_device_unregister(siu_platform_device);
}
module_init(vr41xx_siu_init);
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
new file mode 100644
index 000000000000..65f1294fd27b
--- /dev/null
+++ b/drivers/serial/zs.c
@@ -0,0 +1,1287 @@
+/*
+ * zs.c: Serial port driver for IOASIC DECstations.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ *
+ * DECstation changes
+ * Copyright (C) 1998-2000 Harald Koerfgen
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007 Maciej W. Rozycki
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ *
+ * Note: for IOASIC systems the wiring is as follows:
+ *
+ * mouse/keyboard:
+ * DIN-7 MJ-4 signal SCC
+ * 2 1 TxD <- A.TxD
+ * 3 4 RxD -> A.RxD
+ *
+ * EIA-232/EIA-423:
+ * DB-25 MMJ-6 signal SCC
+ * 2 2 TxD <- B.TxD
+ * 3 5 RxD -> B.RxD
+ * 4 RTS <- ~A.RTS
+ * 5 CTS -> ~B.CTS
+ * 6 6 DSR -> ~A.SYNC
+ * 8 CD -> ~B.DCD
+ * 12 DSRS(DCE) -> ~A.CTS (*)
+ * 15 TxC -> B.TxC
+ * 17 RxC -> B.RxC
+ * 20 1 DTR <- ~A.DTR
+ * 22 RI -> ~A.DCD
+ * 23 DSRS(DTE) <- ~B.RTS
+ *
+ * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
+ * is shared with DSRS(DTE) at pin 23.
+ *
+ * As you can immediately notice the wiring of the RTS, DTR and DSR signals
+ * is a bit odd. This makes the handling of port B unnecessarily
+ * complicated and prevents the use of some automatic modes of operation.
+ */
+
+#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bug.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irqflags.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/system.h>
+
+#include "zs.h"
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
+static char zs_version[] __initdata = "0.10";
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on ZS_NUM_SCCS, so we could support any number of
+ * Z85C30s, but for now...
+ */
+#define ZS_NUM_SCCS 2 /* Max # of ZS chips supported. */
+#define ZS_NUM_CHAN 2 /* 2 channels per chip. */
+#define ZS_CHAN_A 0 /* Index of the channel A. */
+#define ZS_CHAN_B 1 /* Index of the channel B. */
+#define ZS_CHAN_IO_SIZE 8 /* IOMEM space size. */
+#define ZS_CHAN_IO_STRIDE 4 /* Register alignment. */
+#define ZS_CHAN_IO_OFFSET 1 /* The SCC resides on the high byte
+ of the 16-bit IOBUS. */
+#define ZS_CLOCK 7372800 /* Z85C30 PCLK input clock rate. */
+
+#define to_zport(uport) container_of(uport, struct zs_port, port)
+
+struct zs_parms {
+ resource_size_t scc[ZS_NUM_SCCS];
+ int irq[ZS_NUM_SCCS];
+};
+
+static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+
+static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
+ 0, /* write 0 */
+ PAR_SPEC, /* write 1 */
+ 0, /* write 2 */
+ 0, /* write 3 */
+ X16CLK | SB1, /* write 4 */
+ 0, /* write 5 */
+ 0, 0, 0, /* write 6, 7, 8 */
+ MIE | DLC | NV, /* write 9 */
+ NRZ, /* write 10 */
+ TCBR | RCBR, /* write 11 */
+ 0, 0, /* BRG time constant, write 12 + 13 */
+ BRSRC | BRENABL, /* write 14 */
+ 0, /* write 15 */
+};
+
+/*
+ * Debugging.
+ */
+#undef ZS_DEBUG_REGS
+
+
+/*
+ * Reading and writing Z85C30 registers.
+ */
+static void recovery_delay(void)
+{
+ udelay(2);
+}
+
+static u8 read_zsreg(struct zs_port *zport, int reg)
+{
+ void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+ u8 retval;
+
+ if (reg != 0) {
+ writeb(reg & 0xf, control);
+ fast_iob();
+ recovery_delay();
+ }
+ retval = readb(control);
+ recovery_delay();
+ return retval;
+}
+
+static void write_zsreg(struct zs_port *zport, int reg, u8 value)
+{
+ void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+
+ if (reg != 0) {
+ writeb(reg & 0xf, control);
+ fast_iob(); recovery_delay();
+ }
+ writeb(value, control);
+ fast_iob();
+ recovery_delay();
+ return;
+}
+
+static u8 read_zsdata(struct zs_port *zport)
+{
+ void __iomem *data = zport->port.membase +
+ ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+ u8 retval;
+
+ retval = readb(data);
+ recovery_delay();
+ return retval;
+}
+
+static void write_zsdata(struct zs_port *zport, u8 value)
+{
+ void __iomem *data = zport->port.membase +
+ ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+
+ writeb(value, data);
+ fast_iob();
+ recovery_delay();
+ return;
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump(void)
+{
+ struct zs_port *zport;
+ int i, j;
+
+ for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+ zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
+
+ if (!zport->scc)
+ continue;
+
+ for (j = 0; j < 16; j++)
+ printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
+ printk("\n");
+ for (j = 0; j < 16; j++)
+ printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
+ printk("\n\n");
+ }
+}
+#endif
+
+
+static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
+{
+ if (irq)
+ spin_lock_irq(lock);
+ else
+ spin_lock(lock);
+}
+
+static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
+{
+ if (irq)
+ spin_unlock_irq(lock);
+ else
+ spin_unlock(lock);
+}
+
+static int zs_receive_drain(struct zs_port *zport)
+{
+ int loops = 10000;
+
+ while ((read_zsreg(zport, R0) & Rx_CH_AV) && loops--)
+ read_zsdata(zport);
+ return loops;
+}
+
+static int zs_transmit_drain(struct zs_port *zport, int irq)
+{
+ struct zs_scc *scc = zport->scc;
+ int loops = 10000;
+
+ while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && loops--) {
+ zs_spin_unlock_cond_irq(&scc->zlock, irq);
+ udelay(2);
+ zs_spin_lock_cond_irq(&scc->zlock, irq);
+ }
+ return loops;
+}
+
+static int zs_line_drain(struct zs_port *zport, int irq)
+{
+ struct zs_scc *scc = zport->scc;
+ int loops = 10000;
+
+ while (!(read_zsreg(zport, R1) & ALL_SNT) && loops--) {
+ zs_spin_unlock_cond_irq(&scc->zlock, irq);
+ udelay(2);
+ zs_spin_lock_cond_irq(&scc->zlock, irq);
+ }
+ return loops;
+}
+
+
+static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
+{
+ /* Let the current transmission finish. */
+ zs_line_drain(zport, irq);
+ /* Load 'em up. */
+ write_zsreg(zport, R3, regs[3] & ~RxENABLE);
+ write_zsreg(zport, R5, regs[5] & ~TxENAB);
+ write_zsreg(zport, R4, regs[4]);
+ write_zsreg(zport, R9, regs[9]);
+ write_zsreg(zport, R1, regs[1]);
+ write_zsreg(zport, R2, regs[2]);
+ write_zsreg(zport, R10, regs[10]);
+ write_zsreg(zport, R14, regs[14] & ~BRENABL);
+ write_zsreg(zport, R11, regs[11]);
+ write_zsreg(zport, R12, regs[12]);
+ write_zsreg(zport, R13, regs[13]);
+ write_zsreg(zport, R14, regs[14]);
+ write_zsreg(zport, R15, regs[15]);
+ if (regs[3] & RxENABLE)
+ write_zsreg(zport, R3, regs[3]);
+ if (regs[5] & TxENAB)
+ write_zsreg(zport, R5, regs[5]);
+ return;
+}
+
+
+/*
+ * Status handling routines.
+ */
+
+/*
+ * zs_tx_empty() -- get the transmitter empty status
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static unsigned int zs_tx_empty(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ u8 status;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ status = read_zsreg(zport, R1);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ return status & ALL_SNT ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
+ struct zs_port *zport_b)
+{
+ u8 status_a, status_b;
+ unsigned int mctrl;
+
+ status_a = read_zsreg(zport_a, R0);
+ status_b = read_zsreg(zport_b, R0);
+
+ mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
+ ((status_b & DCD) ? TIOCM_CAR : 0) |
+ ((status_a & DCD) ? TIOCM_RNG : 0) |
+ ((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
+
+ return mctrl;
+}
+
+static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
+{
+ struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+
+ return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
+}
+
+static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
+{
+ struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+ unsigned int mmask, mctrl, delta;
+ u8 mask_a, mask_b;
+
+ if (zport == zport_a)
+ return 0;
+
+ mask_a = zport_a->regs[15];
+ mask_b = zport->regs[15];
+
+ mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
+ ((mask_b & DCDIE) ? TIOCM_CAR : 0) |
+ ((mask_a & DCDIE) ? TIOCM_RNG : 0) |
+ ((mask_a & SYNCIE) ? TIOCM_DSR : 0);
+
+ mctrl = zport->mctrl;
+ if (mmask) {
+ mctrl &= ~mmask;
+ mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
+ }
+
+ delta = mctrl ^ zport->mctrl;
+ if (delta)
+ zport->mctrl = mctrl;
+
+ return delta;
+}
+
+static unsigned int zs_get_mctrl(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned int mctrl;
+
+ spin_lock(&scc->zlock);
+ mctrl = zs_raw_get_mctrl(zport);
+ spin_unlock(&scc->zlock);
+
+ return mctrl;
+}
+
+static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+ u8 oldloop, newloop;
+
+ spin_lock(&scc->zlock);
+ if (zport != zport_a) {
+ if (mctrl & TIOCM_DTR)
+ zport_a->regs[5] |= DTR;
+ else
+ zport_a->regs[5] &= ~DTR;
+ if (mctrl & TIOCM_RTS)
+ zport_a->regs[5] |= RTS;
+ else
+ zport_a->regs[5] &= ~RTS;
+ write_zsreg(zport_a, R5, zport_a->regs[5]);
+ }
+
+ /* Rarely modified, so don't poke at hardware unless necessary. */
+ oldloop = zport->regs[14];
+ newloop = oldloop;
+ if (mctrl & TIOCM_LOOP)
+ newloop |= LOOPBAK;
+ else
+ newloop &= ~LOOPBAK;
+ if (newloop != oldloop) {
+ zport->regs[14] = newloop;
+ write_zsreg(zport, R14, zport->regs[14]);
+ }
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_stop_tx(struct zs_port *zport)
+{
+ write_zsreg(zport, R0, RES_Tx_P);
+ zport->tx_stopped = 1;
+}
+
+static void zs_stop_tx(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+
+ spin_lock(&scc->zlock);
+ zs_raw_stop_tx(zport);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *);
+
+static void zs_start_tx(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+
+ spin_lock(&scc->zlock);
+ if (zport->tx_stopped) {
+ zs_transmit_drain(zport, 0);
+ zport->tx_stopped = 0;
+ zs_raw_transmit_chars(zport);
+ }
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_stop_rx(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+ spin_lock(&scc->zlock);
+ zport->regs[15] &= ~BRKIE;
+ zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
+ zport->regs[1] |= RxINT_DISAB;
+
+ if (zport != zport_a) {
+ /* A-side DCD tracks RI and SYNC tracks DSR. */
+ zport_a->regs[15] &= ~(DCDIE | SYNCIE);
+ write_zsreg(zport_a, R15, zport_a->regs[15]);
+ if (!(zport_a->regs[15] & BRKIE)) {
+ zport_a->regs[1] &= ~EXT_INT_ENAB;
+ write_zsreg(zport_a, R1, zport_a->regs[1]);
+ }
+
+ /* This-side DCD tracks DCD and CTS tracks CTS. */
+ zport->regs[15] &= ~(DCDIE | CTSIE);
+ zport->regs[1] &= ~EXT_INT_ENAB;
+ } else {
+ /* DCD tracks RI and SYNC tracks DSR for the B side. */
+ if (!(zport->regs[15] & (DCDIE | SYNCIE)))
+ zport->regs[1] &= ~EXT_INT_ENAB;
+ }
+
+ write_zsreg(zport, R15, zport->regs[15]);
+ write_zsreg(zport, R1, zport->regs[1]);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_enable_ms(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+ if (zport == zport_a)
+ return;
+
+ spin_lock(&scc->zlock);
+
+ /* Clear Ext interrupts if not being handled already. */
+ if (!(zport_a->regs[1] & EXT_INT_ENAB))
+ write_zsreg(zport_a, R0, RES_EXT_INT);
+
+ /* A-side DCD tracks RI and SYNC tracks DSR. */
+ zport_a->regs[1] |= EXT_INT_ENAB;
+ zport_a->regs[15] |= DCDIE | SYNCIE;
+
+ /* This-side DCD tracks DCD and CTS tracks CTS. */
+ zport->regs[15] |= DCDIE | CTSIE;
+
+ zs_raw_xor_mctrl(zport);
+
+ write_zsreg(zport_a, R1, zport_a->regs[1]);
+ write_zsreg(zport_a, R15, zport_a->regs[15]);
+ write_zsreg(zport, R15, zport->regs[15]);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_break_ctl(struct uart_port *uport, int break_state)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ if (break_state == -1)
+ zport->regs[5] |= SND_BRK;
+ else
+ zport->regs[5] &= ~SND_BRK;
+ write_zsreg(zport, R5, zport->regs[5]);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+/*
+ * Interrupt handling routines.
+ */
+#define Rx_BRK 0x0100 /* BREAK event software flag. */
+#define Rx_SYS 0x0200 /* SysRq event software flag. */
+
+static void zs_receive_chars(struct zs_port *zport)
+{
+ struct uart_port *uport = &zport->port;
+ struct zs_scc *scc = zport->scc;
+ struct uart_icount *icount;
+ unsigned int avail, status, ch, flag;
+ int count;
+
+ for (count = 16; count; count--) {
+ spin_lock(&scc->zlock);
+ avail = read_zsreg(zport, R0) & Rx_CH_AV;
+ spin_unlock(&scc->zlock);
+ if (!avail)
+ break;
+
+ spin_lock(&scc->zlock);
+ status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
+ ch = read_zsdata(zport);
+ spin_unlock(&scc->zlock);
+
+ flag = TTY_NORMAL;
+
+ icount = &uport->icount;
+ icount->rx++;
+
+ /* Handle the null char got when BREAK is removed. */
+ if (!ch)
+ status |= zport->tty_break;
+ if (unlikely(status &
+ (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
+ zport->tty_break = 0;
+
+ /* Reset the error indication. */
+ if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
+ spin_lock(&scc->zlock);
+ write_zsreg(zport, R0, ERR_RES);
+ spin_unlock(&scc->zlock);
+ }
+
+ if (status & (Rx_SYS | Rx_BRK)) {
+ icount->brk++;
+ /* SysRq discards the null char. */
+ if (status & Rx_SYS)
+ continue;
+ } else if (status & FRM_ERR)
+ icount->frame++;
+ else if (status & PAR_ERR)
+ icount->parity++;
+ if (status & Rx_OVR)
+ icount->overrun++;
+
+ status &= uport->read_status_mask;
+ if (status & Rx_BRK)
+ flag = TTY_BREAK;
+ else if (status & FRM_ERR)
+ flag = TTY_FRAME;
+ else if (status & PAR_ERR)
+ flag = TTY_PARITY;
+ }
+
+ if (uart_handle_sysrq_char(uport, ch))
+ continue;
+
+ uart_insert_char(uport, status, Rx_OVR, ch, flag);
+ }
+
+ tty_flip_buffer_push(uport->info->tty);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *zport)
+{
+ struct circ_buf *xmit = &zport->port.info->xmit;
+
+ /* XON/XOFF chars. */
+ if (zport->port.x_char) {
+ write_zsdata(zport, zport->port.x_char);
+ zport->port.icount.tx++;
+ zport->port.x_char = 0;
+ return;
+ }
+
+ /* If nothing to do or stopped or hardware stopped. */
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
+ zs_raw_stop_tx(zport);
+ return;
+ }
+
+ /* Send char. */
+ write_zsdata(zport, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ zport->port.icount.tx++;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&zport->port);
+
+ /* Are we are done? */
+ if (uart_circ_empty(xmit))
+ zs_raw_stop_tx(zport);
+}
+
+static void zs_transmit_chars(struct zs_port *zport)
+{
+ struct zs_scc *scc = zport->scc;
+
+ spin_lock(&scc->zlock);
+ zs_raw_transmit_chars(zport);
+ spin_unlock(&scc->zlock);
+}
+
+static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
+{
+ struct uart_port *uport = &zport->port;
+ struct zs_scc *scc = zport->scc;
+ unsigned int delta;
+ u8 status, brk;
+
+ spin_lock(&scc->zlock);
+
+ /* Get status from Read Register 0. */
+ status = read_zsreg(zport, R0);
+
+ if (zport->regs[15] & BRKIE) {
+ brk = status & BRK_ABRT;
+ if (brk && !zport->brk) {
+ spin_unlock(&scc->zlock);
+ if (uart_handle_break(uport))
+ zport->tty_break = Rx_SYS;
+ else
+ zport->tty_break = Rx_BRK;
+ spin_lock(&scc->zlock);
+ }
+ zport->brk = brk;
+ }
+
+ if (zport != zport_a) {
+ delta = zs_raw_xor_mctrl(zport);
+ spin_unlock(&scc->zlock);
+
+ if (delta & TIOCM_CTS)
+ uart_handle_cts_change(uport,
+ zport->mctrl & TIOCM_CTS);
+ if (delta & TIOCM_CAR)
+ uart_handle_dcd_change(uport,
+ zport->mctrl & TIOCM_CAR);
+ if (delta & TIOCM_RNG)
+ uport->icount.dsr++;
+ if (delta & TIOCM_DSR)
+ uport->icount.rng++;
+
+ if (delta)
+ wake_up_interruptible(&uport->info->delta_msr_wait);
+
+ spin_lock(&scc->zlock);
+ }
+
+ /* Clear the status condition... */
+ write_zsreg(zport, R0, RES_EXT_INT);
+
+ spin_unlock(&scc->zlock);
+}
+
+/*
+ * This is the Z85C30 driver's generic interrupt routine.
+ */
+static irqreturn_t zs_interrupt(int irq, void *dev_id)
+{
+ struct zs_scc *scc = dev_id;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+ struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
+ irqreturn_t status = IRQ_NONE;
+ u8 zs_intreg;
+ int count;
+
+ /*
+ * NOTE: The read register 3, which holds the irq status,
+ * does so for both channels on each chip. Although
+ * the status value itself must be read from the A
+ * channel and is only valid when read from channel A.
+ * Yes... broken hardware...
+ */
+ for (count = 16; count; count--) {
+ spin_lock(&scc->zlock);
+ zs_intreg = read_zsreg(zport_a, R3);
+ spin_unlock(&scc->zlock);
+ if (!zs_intreg)
+ break;
+
+ /*
+ * We do not like losing characters, so we prioritise
+ * interrupt sources a little bit differently than
+ * the SCC would, was it allowed to.
+ */
+ if (zs_intreg & CHBRxIP)
+ zs_receive_chars(zport_b);
+ if (zs_intreg & CHARxIP)
+ zs_receive_chars(zport_a);
+ if (zs_intreg & CHBEXT)
+ zs_status_handle(zport_b, zport_a);
+ if (zs_intreg & CHAEXT)
+ zs_status_handle(zport_a, zport_a);
+ if (zs_intreg & CHBTxIP)
+ zs_transmit_chars(zport_b);
+ if (zs_intreg & CHATxIP)
+ zs_transmit_chars(zport_a);
+
+ status = IRQ_HANDLED;
+ }
+
+ return status;
+}
+
+
+/*
+ * Finally, routines used to initialize the serial port.
+ */
+static int zs_startup(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ int irq_guard;
+ int ret;
+
+ irq_guard = atomic_add_return(1, &scc->irq_guard);
+ if (irq_guard == 1) {
+ ret = request_irq(zport->port.irq, zs_interrupt,
+ IRQF_SHARED, "scc", scc);
+ if (ret) {
+ atomic_add(-1, &scc->irq_guard);
+ printk(KERN_ERR "zs: can't get irq %d\n",
+ zport->port.irq);
+ return ret;
+ }
+ }
+
+ spin_lock_irqsave(&scc->zlock, flags);
+
+ /* Clear the receive FIFO. */
+ zs_receive_drain(zport);
+
+ /* Clear the interrupt registers. */
+ write_zsreg(zport, R0, ERR_RES);
+ write_zsreg(zport, R0, RES_Tx_P);
+ /* But Ext only if not being handled already. */
+ if (!(zport->regs[1] & EXT_INT_ENAB))
+ write_zsreg(zport, R0, RES_EXT_INT);
+
+ /* Finally, enable sequencing and interrupts. */
+ zport->regs[1] &= ~RxINT_MASK;
+ zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
+ zport->regs[3] |= RxENABLE;
+ zport->regs[5] |= TxENAB;
+ zport->regs[15] |= BRKIE;
+ write_zsreg(zport, R1, zport->regs[1]);
+ write_zsreg(zport, R3, zport->regs[3]);
+ write_zsreg(zport, R5, zport->regs[5]);
+ write_zsreg(zport, R15, zport->regs[15]);
+
+ /* Record the current state of RR0. */
+ zport->mctrl = zs_raw_get_mctrl(zport);
+ zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
+
+ zport->tx_stopped = 1;
+
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ return 0;
+}
+
+static void zs_shutdown(struct uart_port *uport)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ int irq_guard;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+
+ zport->regs[5] &= ~TxENAB;
+ zport->regs[3] &= ~RxENABLE;
+ write_zsreg(zport, R5, zport->regs[5]);
+ write_zsreg(zport, R3, zport->regs[3]);
+
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ irq_guard = atomic_add_return(-1, &scc->irq_guard);
+ if (!irq_guard)
+ free_irq(zport->port.irq, scc);
+}
+
+
+static void zs_reset(struct zs_port *zport)
+{
+ struct zs_scc *scc = zport->scc;
+ int irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+ if (!scc->initialised) {
+ /* Reset the pointer first, just in case... */
+ read_zsreg(zport, R0);
+ /* And let the current transmission finish. */
+ zs_line_drain(zport, irq);
+ write_zsreg(zport, R9, FHWRES);
+ udelay(10);
+ write_zsreg(zport, R9, 0);
+ scc->initialised = 1;
+ }
+ load_zsregs(zport, zport->regs, irq);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
+ struct ktermios *old_termios)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+ int irq;
+ unsigned int baud, brg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+
+ /* Byte size. */
+ zport->regs[3] &= ~RxNBITS_MASK;
+ zport->regs[5] &= ~TxNBITS_MASK;
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ zport->regs[3] |= Rx5;
+ zport->regs[5] |= Tx5;
+ break;
+ case CS6:
+ zport->regs[3] |= Rx6;
+ zport->regs[5] |= Tx6;
+ break;
+ case CS7:
+ zport->regs[3] |= Rx7;
+ zport->regs[5] |= Tx7;
+ break;
+ case CS8:
+ default:
+ zport->regs[3] |= Rx8;
+ zport->regs[5] |= Tx8;
+ break;
+ }
+
+ /* Parity and stop bits. */
+ zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
+ if (termios->c_cflag & CSTOPB)
+ zport->regs[4] |= SB2;
+ else
+ zport->regs[4] |= SB1;
+ if (termios->c_cflag & PARENB)
+ zport->regs[4] |= PAR_ENA;
+ if (!(termios->c_cflag & PARODD))
+ zport->regs[4] |= PAR_EVEN;
+ switch (zport->clk_mode) {
+ case 64:
+ zport->regs[4] |= X64CLK;
+ break;
+ case 32:
+ zport->regs[4] |= X32CLK;
+ break;
+ case 16:
+ zport->regs[4] |= X16CLK;
+ break;
+ case 1:
+ zport->regs[4] |= X1CLK;
+ break;
+ default:
+ BUG();
+ }
+
+ baud = uart_get_baud_rate(uport, termios, old_termios, 0,
+ uport->uartclk / zport->clk_mode / 4);
+
+ brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
+ zport->regs[12] = brg & 0xff;
+ zport->regs[13] = (brg >> 8) & 0xff;
+
+ uart_update_timeout(uport, termios->c_cflag, baud);
+
+ uport->read_status_mask = Rx_OVR;
+ if (termios->c_iflag & INPCK)
+ uport->read_status_mask |= FRM_ERR | PAR_ERR;
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ uport->read_status_mask |= Rx_BRK;
+
+ uport->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
+ if (termios->c_iflag & IGNBRK) {
+ uport->ignore_status_mask |= Rx_BRK;
+ if (termios->c_iflag & IGNPAR)
+ uport->ignore_status_mask |= Rx_OVR;
+ }
+
+ if (termios->c_cflag & CREAD)
+ zport->regs[3] |= RxENABLE;
+ else
+ zport->regs[3] &= ~RxENABLE;
+
+ if (zport != zport_a) {
+ if (!(termios->c_cflag & CLOCAL)) {
+ zport->regs[15] |= DCDIE;
+ } else
+ zport->regs[15] &= ~DCDIE;
+ if (termios->c_cflag & CRTSCTS) {
+ zport->regs[15] |= CTSIE;
+ } else
+ zport->regs[15] &= ~CTSIE;
+ zs_raw_xor_mctrl(zport);
+ }
+
+ /* Load up the new values. */
+ load_zsregs(zport, zport->regs, irq);
+
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+static const char *zs_type(struct uart_port *uport)
+{
+ return "Z85C30 SCC";
+}
+
+static void zs_release_port(struct uart_port *uport)
+{
+ iounmap(uport->membase);
+ uport->membase = 0;
+ release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+}
+
+static int zs_map_port(struct uart_port *uport)
+{
+ if (!uport->membase)
+ uport->membase = ioremap_nocache(uport->mapbase,
+ ZS_CHAN_IO_SIZE);
+ if (!uport->membase) {
+ printk(KERN_ERR "zs: Cannot map MMIO\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int zs_request_port(struct uart_port *uport)
+{
+ int ret;
+
+ if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
+ printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
+ return -EBUSY;
+ }
+ ret = zs_map_port(uport);
+ if (ret) {
+ release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+ return ret;
+ }
+ return 0;
+}
+
+static void zs_config_port(struct uart_port *uport, int flags)
+{
+ struct zs_port *zport = to_zport(uport);
+
+ if (flags & UART_CONFIG_TYPE) {
+ if (zs_request_port(uport))
+ return;
+
+ uport->type = PORT_ZS;
+
+ zs_reset(zport);
+ }
+}
+
+static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+ struct zs_port *zport = to_zport(uport);
+ int ret = 0;
+
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
+ ret = -EINVAL;
+ if (ser->irq != uport->irq)
+ ret = -EINVAL;
+ if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
+ ret = -EINVAL;
+ return ret;
+}
+
+
+static struct uart_ops zs_ops = {
+ .tx_empty = zs_tx_empty,
+ .set_mctrl = zs_set_mctrl,
+ .get_mctrl = zs_get_mctrl,
+ .stop_tx = zs_stop_tx,
+ .start_tx = zs_start_tx,
+ .stop_rx = zs_stop_rx,
+ .enable_ms = zs_enable_ms,
+ .break_ctl = zs_break_ctl,
+ .startup = zs_startup,
+ .shutdown = zs_shutdown,
+ .set_termios = zs_set_termios,
+ .type = zs_type,
+ .release_port = zs_release_port,
+ .request_port = zs_request_port,
+ .config_port = zs_config_port,
+ .verify_port = zs_verify_port,
+};
+
+/*
+ * Initialize Z85C30 port structures.
+ */
+static int __init zs_probe_sccs(void)
+{
+ static int probed;
+ struct zs_parms zs_parms;
+ int chip, side, irq;
+ int n_chips = 0;
+ int i;
+
+ if (probed)
+ return 0;
+
+ irq = dec_interrupt[DEC_IRQ_SCC0];
+ if (irq >= 0) {
+ zs_parms.scc[n_chips] = IOASIC_SCC0;
+ zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
+ n_chips++;
+ }
+ irq = dec_interrupt[DEC_IRQ_SCC1];
+ if (irq >= 0) {
+ zs_parms.scc[n_chips] = IOASIC_SCC1;
+ zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
+ n_chips++;
+ }
+ if (!n_chips)
+ return -ENXIO;
+
+ probed = 1;
+
+ for (chip = 0; chip < n_chips; chip++) {
+ spin_lock_init(&zs_sccs[chip].zlock);
+ for (side = 0; side < ZS_NUM_CHAN; side++) {
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct uart_port *uport = &zport->port;
+
+ zport->scc = &zs_sccs[chip];
+ zport->clk_mode = 16;
+
+ uport->irq = zs_parms.irq[chip];
+ uport->uartclk = ZS_CLOCK;
+ uport->fifosize = 1;
+ uport->iotype = UPIO_MEM;
+ uport->flags = UPF_BOOT_AUTOCONF;
+ uport->ops = &zs_ops;
+ uport->line = chip * ZS_NUM_CHAN + side;
+ uport->mapbase = dec_kn_slot_base +
+ zs_parms.scc[chip] +
+ (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
+
+ for (i = 0; i < ZS_NUM_REGS; i++)
+ zport->regs[i] = zs_init_regs[i];
+ }
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_ZS_CONSOLE
+static void zs_console_putchar(struct uart_port *uport, int ch)
+{
+ struct zs_port *zport = to_zport(uport);
+ struct zs_scc *scc = zport->scc;
+ int irq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+ if (zs_transmit_drain(zport, irq))
+ write_zsdata(zport, ch);
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void zs_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct zs_scc *scc = zport->scc;
+ unsigned long flags;
+ u8 txint, txenb;
+ int irq;
+
+ /* Disable transmit interrupts and enable the transmitter. */
+ spin_lock_irqsave(&scc->zlock, flags);
+ txint = zport->regs[1];
+ txenb = zport->regs[5];
+ if (txint & TxINT_ENAB) {
+ zport->regs[1] = txint & ~TxINT_ENAB;
+ write_zsreg(zport, R1, zport->regs[1]);
+ }
+ if (!(txenb & TxENAB)) {
+ zport->regs[5] = txenb | TxENAB;
+ write_zsreg(zport, R5, zport->regs[5]);
+ }
+ spin_unlock_irqrestore(&scc->zlock, flags);
+
+ uart_console_write(&zport->port, s, count, zs_console_putchar);
+
+ /* Restore transmit interrupts and the transmitter enable. */
+ spin_lock_irqsave(&scc->zlock, flags);
+ irq = !irqs_disabled_flags(flags);
+ zs_line_drain(zport, irq);
+ if (!(txenb & TxENAB)) {
+ zport->regs[5] &= ~TxENAB;
+ write_zsreg(zport, R5, zport->regs[5]);
+ }
+ if (txint & TxINT_ENAB) {
+ zport->regs[1] |= TxINT_ENAB;
+ write_zsreg(zport, R1, zport->regs[1]);
+ }
+ spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Setup serial console baud/bits/parity. We do two things here:
+ * - construct a cflag setting for the first uart_open()
+ * - initialise the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+static int __init zs_console_setup(struct console *co, char *options)
+{
+ int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+ struct zs_port *zport = &zs_sccs[chip].zport[side];
+ struct uart_port *uport = &zport->port;
+ int baud = 9600;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+ int ret;
+
+ ret = zs_map_port(uport);
+ if (ret)
+ return ret;
+
+ zs_reset(zport);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver zs_reg;
+static struct console zs_console = {
+ .name = "ttyS",
+ .write = zs_console_write,
+ .device = uart_console_device,
+ .setup = zs_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &zs_reg,
+};
+
+/*
+ * Register console.
+ */
+static int __init zs_serial_console_init(void)
+{
+ int ret;
+
+ ret = zs_probe_sccs();
+ if (ret)
+ return ret;
+ register_console(&zs_console);
+
+ return 0;
+}
+
+console_initcall(zs_serial_console_init);
+
+#define SERIAL_ZS_CONSOLE &zs_console
+#else
+#define SERIAL_ZS_CONSOLE NULL
+#endif /* CONFIG_SERIAL_ZS_CONSOLE */
+
+static struct uart_driver zs_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = ZS_NUM_SCCS * ZS_NUM_CHAN,
+ .cons = SERIAL_ZS_CONSOLE,
+};
+
+/* zs_init inits the driver. */
+static int __init zs_init(void)
+{
+ int i, ret;
+
+ pr_info("%s%s\n", zs_name, zs_version);
+
+ /* Find out how many Z85C30 SCCs we have. */
+ ret = zs_probe_sccs();
+ if (ret)
+ return ret;
+
+ ret = uart_register_driver(&zs_reg);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+ struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+ struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+ struct uart_port *uport = &zport->port;
+
+ if (zport->scc)
+ uart_add_one_port(&zs_reg, uport);
+ }
+
+ return 0;
+}
+
+static void __exit zs_exit(void)
+{
+ int i;
+
+ for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
+ struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+ struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+ struct uart_port *uport = &zport->port;
+
+ if (zport->scc)
+ uart_remove_one_port(&zs_reg, uport);
+ }
+
+ uart_unregister_driver(&zs_reg);
+}
+
+module_init(zs_init);
+module_exit(zs_exit);
diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h
new file mode 100644
index 000000000000..aa921b57d827
--- /dev/null
+++ b/drivers/serial/zs.h
@@ -0,0 +1,284 @@
+/*
+ * zs.h: Definitions for the DECstation Z85C30 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004, 2005, 2007 Maciej W. Rozycki
+ */
+#ifndef _SERIAL_ZS_H
+#define _SERIAL_ZS_H
+
+#ifdef __KERNEL__
+
+#define ZS_NUM_REGS 16
+
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct zs_port {
+ struct zs_scc *scc; /* Containing SCC. */
+ struct uart_port port; /* Underlying UART. */
+
+ int clk_mode; /* May be 1, 16, 32, or 64. */
+
+ unsigned int tty_break; /* Set on BREAK condition. */
+ int tx_stopped; /* Output is suspended. */
+
+ unsigned int mctrl; /* State of modem lines. */
+ u8 brk; /* BREAK state from RR0. */
+
+ u8 regs[ZS_NUM_REGS]; /* Channel write registers. */
+};
+
+/*
+ * Per-SCC state for locking and the interrupt handler.
+ */
+struct zs_scc {
+ struct zs_port zport[2];
+ spinlock_t zlock;
+ atomic_t irq_guard;
+ int initialised;
+};
+
+#endif /* __KERNEL__ */
+
+/*
+ * Conversion routines to/from brg time constants from/to bits per second.
+ */
+#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/*
+ * The Zilog register set.
+ */
+
+/* Write Register 0 (Command) */
+#define R0 0 /* Register selects */
+#define R1 1
+#define R2 2
+#define R3 3
+#define R4 4
+#define R5 5
+#define R6 6
+#define R7 7
+#define R8 8
+#define R9 9
+#define R10 10
+#define R11 11
+#define R12 12
+#define R13 13
+#define R14 14
+#define R15 15
+
+#define NULLCODE 0 /* Null Code */
+#define POINT_HIGH 0x8 /* Select upper half of registers */
+#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
+#define SEND_ABORT 0x18 /* HDLC Abort */
+#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
+#define RES_Tx_P 0x28 /* Reset TxINT Pending */
+#define ERR_RES 0x30 /* Error Reset */
+#define RES_H_IUS 0x38 /* Reset highest IUS */
+
+#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
+#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
+#define RES_EOM_L 0xC0 /* Reset EOM latch */
+
+/* Write Register 1 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
+#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
+#define TxINT_ENAB 0x2 /* Tx Int Enable */
+#define PAR_SPEC 0x4 /* Parity is special condition */
+
+#define RxINT_DISAB 0 /* Rx Int Disable */
+#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
+#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */
+#define RxINT_ERR 0x18 /* Int on error only */
+#define RxINT_MASK 0x18
+
+#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
+#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
+#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
+
+/* Write Register 2 (Interrupt Vector) */
+
+/* Write Register 3 (Receive Parameters and Control) */
+#define RxENABLE 0x1 /* Rx Enable */
+#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
+#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
+#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
+#define ENT_HM 0x10 /* Enter Hunt Mode */
+#define AUTO_ENAB 0x20 /* Auto Enables */
+#define Rx5 0x0 /* Rx 5 Bits/Character */
+#define Rx7 0x40 /* Rx 7 Bits/Character */
+#define Rx6 0x80 /* Rx 6 Bits/Character */
+#define Rx8 0xc0 /* Rx 8 Bits/Character */
+#define RxNBITS_MASK 0xc0
+
+/* Write Register 4 (Transmit/Receive Miscellaneous Parameters and Modes) */
+#define PAR_ENA 0x1 /* Parity Enable */
+#define PAR_EVEN 0x2 /* Parity Even/Odd* */
+
+#define SYNC_ENAB 0 /* Sync Modes Enable */
+#define SB1 0x4 /* 1 stop bit/char */
+#define SB15 0x8 /* 1.5 stop bits/char */
+#define SB2 0xc /* 2 stop bits/char */
+#define SB_MASK 0xc
+
+#define MONSYNC 0 /* 8 Bit Sync character */
+#define BISYNC 0x10 /* 16 bit sync character */
+#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
+#define EXTSYNC 0x30 /* External Sync Mode */
+
+#define X1CLK 0x0 /* x1 clock mode */
+#define X16CLK 0x40 /* x16 clock mode */
+#define X32CLK 0x80 /* x32 clock mode */
+#define X64CLK 0xc0 /* x64 clock mode */
+#define XCLK_MASK 0xc0
+
+/* Write Register 5 (Transmit Parameters and Controls) */
+#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
+#define RTS 0x2 /* RTS */
+#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
+#define TxENAB 0x8 /* Tx Enable */
+#define SND_BRK 0x10 /* Send Break */
+#define Tx5 0x0 /* Tx 5 bits (or less)/character */
+#define Tx7 0x20 /* Tx 7 bits/character */
+#define Tx6 0x40 /* Tx 6 bits/character */
+#define Tx8 0x60 /* Tx 8 bits/character */
+#define TxNBITS_MASK 0x60
+#define DTR 0x80 /* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (Transmit Buffer) */
+
+/* Write Register 9 (Master Interrupt Control) */
+#define VIS 1 /* Vector Includes Status */
+#define NV 2 /* No Vector */
+#define DLC 4 /* Disable Lower Chain */
+#define MIE 8 /* Master Interrupt Enable */
+#define STATHI 0x10 /* Status high */
+#define SOFTACK 0x20 /* Software Interrupt Acknowledge */
+#define NORESET 0 /* No reset on write to R9 */
+#define CHRB 0x40 /* Reset channel B */
+#define CHRA 0x80 /* Reset channel A */
+#define FHWRES 0xc0 /* Force hardware reset */
+
+/* Write Register 10 (Miscellaneous Transmitter/Receiver Control Bits) */
+#define BIT6 1 /* 6 bit/8bit sync */
+#define LOOPMODE 2 /* SDLC Loop mode */
+#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
+#define MARKIDLE 8 /* Mark/flag on idle */
+#define GAOP 0x10 /* Go active on poll */
+#define NRZ 0 /* NRZ mode */
+#define NRZI 0x20 /* NRZI mode */
+#define FM1 0x40 /* FM1 (transition = 1) */
+#define FM0 0x60 /* FM0 (transition = 0) */
+#define CRCPS 0x80 /* CRC Preset I/O */
+
+/* Write Register 11 (Clock Mode Control) */
+#define TRxCXT 0 /* TRxC = Xtal output */
+#define TRxCTC 1 /* TRxC = Transmit clock */
+#define TRxCBR 2 /* TRxC = BR Generator Output */
+#define TRxCDP 3 /* TRxC = DPLL output */
+#define TRxCOI 4 /* TRxC O/I */
+#define TCRTxCP 0 /* Transmit clock = RTxC pin */
+#define TCTRxCP 8 /* Transmit clock = TRxC pin */
+#define TCBR 0x10 /* Transmit clock = BR Generator output */
+#define TCDPLL 0x18 /* Transmit clock = DPLL output */
+#define RCRTxCP 0 /* Receive clock = RTxC pin */
+#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
+#define RCBR 0x40 /* Receive clock = BR Generator output */
+#define RCDPLL 0x60 /* Receive clock = DPLL output */
+#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
+
+/* Write Register 12 (Lower Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 13 (Upper Byte of Baud Rate Generator Time Constant) */
+
+/* Write Register 14 (Miscellaneous Control Bits) */
+#define BRENABL 1 /* Baud rate generator enable */
+#define BRSRC 2 /* Baud rate generator source */
+#define DTRREQ 4 /* DTR/Request function */
+#define AUTOECHO 8 /* Auto Echo */
+#define LOOPBAK 0x10 /* Local loopback */
+#define SEARCH 0x20 /* Enter search mode */
+#define RMC 0x40 /* Reset missing clock */
+#define DISDPLL 0x60 /* Disable DPLL */
+#define SSBR 0x80 /* Set DPLL source = BR generator */
+#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
+#define SFMM 0xc0 /* Set FM mode */
+#define SNRZI 0xe0 /* Set NRZI mode */
+
+/* Write Register 15 (External/Status Interrupt Control) */
+#define WR7P_EN 1 /* WR7 Prime SDLC Feature Enable */
+#define ZCIE 2 /* Zero count IE */
+#define DCDIE 8 /* DCD IE */
+#define SYNCIE 0x10 /* Sync/hunt IE */
+#define CTSIE 0x20 /* CTS IE */
+#define TxUIE 0x40 /* Tx Underrun/EOM IE */
+#define BRKIE 0x80 /* Break/Abort IE */
+
+
+/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
+#define Rx_CH_AV 0x1 /* Rx Character Available */
+#define ZCOUNT 0x2 /* Zero count */
+#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
+#define DCD 0x8 /* DCD */
+#define SYNC_HUNT 0x10 /* Sync/hunt */
+#define CTS 0x20 /* CTS */
+#define TxEOM 0x40 /* Tx underrun */
+#define BRK_ABRT 0x80 /* Break/Abort */
+
+/* Read Register 1 (Special Receive Condition Status) */
+#define ALL_SNT 0x1 /* All sent */
+/* Residue Data for 8 Rx bits/char programmed */
+#define RES3 0x8 /* 0/3 */
+#define RES4 0x4 /* 0/4 */
+#define RES5 0xc /* 0/5 */
+#define RES6 0x2 /* 0/6 */
+#define RES7 0xa /* 0/7 */
+#define RES8 0x6 /* 0/8 */
+#define RES18 0xe /* 1/8 */
+#define RES28 0x0 /* 2/8 */
+/* Special Rx Condition Interrupts */
+#define PAR_ERR 0x10 /* Parity Error */
+#define Rx_OVR 0x20 /* Rx Overrun Error */
+#define FRM_ERR 0x40 /* CRC/Framing Error */
+#define END_FR 0x80 /* End of Frame (SDLC) */
+
+/* Read Register 2 (Interrupt Vector (WR2) -- channel A). */
+
+/* Read Register 2 (Modified Interrupt Vector -- channel B). */
+
+/* Read Register 3 (Interrupt Pending Bits -- channel A only). */
+#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
+#define CHBTxIP 0x2 /* Channel B Tx IP */
+#define CHBRxIP 0x4 /* Channel B Rx IP */
+#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
+#define CHATxIP 0x10 /* Channel A Tx IP */
+#define CHARxIP 0x20 /* Channel A Rx IP */
+
+/* Read Register 6 (SDLC FIFO Status and Byte Count LSB) */
+
+/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
+
+/* Read Register 8 (Receive Data) */
+
+/* Read Register 10 (Miscellaneous Status Bits) */
+#define ONLOOP 2 /* On loop */
+#define LOOPSEND 0x10 /* Loop sending */
+#define CLK2MIS 0x40 /* Two clocks missing */
+#define CLK1MIS 0x80 /* One clock missing */
+
+/* Read Register 12 (Lower Byte of Baud Rate Generator Constant (WR12)) */
+
+/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
+
+/* Read Register 15 (External/Status Interrupt Control (WR15)) */
+
+#endif /* _SERIAL_ZS_H */
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c
index 94b229031198..7d873b3b0513 100644
--- a/drivers/sh/superhyway/superhyway.c
+++ b/drivers/sh/superhyway/superhyway.c
@@ -56,11 +56,10 @@ int superhyway_add_device(unsigned long base, struct superhyway_device *sdev,
struct superhyway_device *dev = sdev;
if (!dev) {
- dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct superhyway_device), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- memset(dev, 0, sizeof(struct superhyway_device));
}
dev->bus = bus;
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 2dd6eed50aa0..29fcd6d0301d 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -629,7 +629,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
#endif
/* Set up per-IOC3 data */
- idd = kmalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
+ idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
if (!idd) {
printk(KERN_WARNING
"%s: Failed to allocate IOC3 data for pci_dev %s.\n",
@@ -637,7 +637,6 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
ret = -ENODEV;
goto out_idd;
}
- memset(idd, 0, sizeof(struct ioc3_driver_data));
spin_lock_init(&idd->ir_lock);
spin_lock_init(&idd->gpio_lock);
idd->pdev = pdev;
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 5e3f748f2693..b91571122daa 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -107,6 +107,15 @@ config SPI_IMX
This enables using the Freescale iMX SPI controller in master
mode.
+config SPI_LM70_LLP
+ tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)"
+ depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This driver supports the NS LM70 LLP Evaluation Board,
+ which interfaces to an LM70 temperature sensor using
+ a parallel port.
+
config SPI_MPC52xx_PSC
tristate "Freescale MPC52xx PSC SPI controller"
depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL
@@ -133,6 +142,12 @@ config SPI_OMAP_UWIRE
help
This hooks up to the MicroWire controller on OMAP1 chips.
+config SPI_OMAP24XX
+ tristate "McSPI driver for OMAP24xx"
+ depends on SPI_MASTER && ARCH_OMAP24XX
+ help
+ SPI master controller for OMAP24xx Multichannel SPI
+ (McSPI) modules.
config SPI_PXA2XX
tristate "PXA2xx SSP SPI master"
@@ -145,17 +160,36 @@ config SPI_PXA2XX
config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI"
depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs
config SPI_S3C24XX_GPIO
tristate "Samsung S3C24XX series SPI by GPIO"
- depends on SPI_MASTER && ARCH_S3C2410 && SPI_BITBANG && EXPERIMENTAL
+ depends on SPI_MASTER && ARCH_S3C2410 && EXPERIMENTAL
+ select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs using
GPIO lines to provide the SPI bus. This can be used where
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.
+
+config SPI_TXX9
+ tristate "Toshiba TXx9 SPI controller"
+ depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX
+ help
+ SPI driver for Toshiba TXx9 MIPS SoCs
+
+config SPI_XILINX
+ tristate "Xilinx SPI controller"
+ depends on SPI_MASTER && XILINX_VIRTEX && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This exposes the SPI controller IP from the Xilinx EDK.
+
+ See the "OPB Serial Peripheral Interface (SPI) (v1.00e)"
+ Product Specification document (DS464) for hardware details.
+
#
# Add new SPI master controllers in alphabetical order above this line
#
@@ -187,6 +221,15 @@ config SPI_SPIDEV
Note that this application programming interface is EXPERIMENTAL
and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes.
+config SPI_TLE62X0
+ tristate "Infineon TLE62X0 (for power switching)"
+ depends on SPI_MASTER && SYSFS
+ help
+ SPI driver for Infineon TLE62X0 series line driver chips,
+ such as the TLE6220, TLE6230 and TLE6240. This provides a
+ sysfs interface, with each line presented as a kind of GPIO
+ exposing both switch control and diagnostic feedback.
+
#
# Add new SPI protocol masters in alphabetical order above this line
#
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 5788d867de84..41fbac45c323 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,17 +17,22 @@ obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
+obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
+obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
+obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
+obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
obj-$(CONFIG_SPI_AT25) += at25.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
+obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
diff --git a/drivers/spi/at25.c b/drivers/spi/at25.c
index 8efa07e8b8c2..e007833cca59 100644
--- a/drivers/spi/at25.c
+++ b/drivers/spi/at25.c
@@ -111,7 +111,8 @@ at25_ee_read(
}
static ssize_t
-at25_bin_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+at25_bin_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev;
struct at25_data *at25;
@@ -236,7 +237,8 @@ at25_ee_write(struct at25_data *at25, char *buf, loff_t off, size_t count)
}
static ssize_t
-at25_bin_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+at25_bin_write(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev;
struct at25_data *at25;
@@ -314,7 +316,6 @@ static int at25_probe(struct spi_device *spi)
*/
at25->bin.attr.name = "eeprom";
at25->bin.attr.mode = S_IRUSR;
- at25->bin.attr.owner = THIS_MODULE;
at25->bin.read = at25_bin_read;
at25->bin.size = at25->chip.byte_len;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 8b2601de3630..ad144054da30 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -46,6 +46,7 @@ struct atmel_spi {
struct clk *clk;
struct platform_device *pdev;
unsigned new_1:1;
+ struct spi_device *stay;
u8 stopping;
struct list_head queue;
@@ -62,29 +63,62 @@ struct atmel_spi {
/*
* Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
* they assume that spi slave device state will not change on deselect, so
- * that automagic deselection is OK. Not so! Workaround uses nCSx pins
- * as GPIOs; or newer controllers have CSAAT and friends.
+ * that automagic deselection is OK. ("NPCSx rises if no data is to be
+ * transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer
+ * controllers have CSAAT and friends.
*
- * Since the CSAAT functionality is a bit weird on newer controllers
- * as well, we use GPIO to control nCSx pins on all controllers.
+ * Since the CSAAT functionality is a bit weird on newer controllers as
+ * well, we use GPIO to control nCSx pins on all controllers, updating
+ * MR.PCS to avoid confusing the controller. Using GPIOs also lets us
+ * support active-high chipselects despite the controller's belief that
+ * only active-low devices/systems exists.
+ *
+ * However, at91rm9200 has a second erratum whereby nCS0 doesn't work
+ * right when driven with GPIO. ("Mode Fault does not allow more than one
+ * Master on Chip Select 0.") No workaround exists for that ... so for
+ * nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
+ * and (c) will trigger that first erratum in some cases.
*/
-static inline void cs_activate(struct spi_device *spi)
+static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
{
unsigned gpio = (unsigned) spi->controller_data;
unsigned active = spi->mode & SPI_CS_HIGH;
+ u32 mr;
+
+ mr = spi_readl(as, MR);
+ mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
- dev_dbg(&spi->dev, "activate %u%s\n", gpio, active ? " (high)" : "");
- gpio_set_value(gpio, active);
+ dev_dbg(&spi->dev, "activate %u%s, mr %08x\n",
+ gpio, active ? " (high)" : "",
+ mr);
+
+ if (!(cpu_is_at91rm9200() && spi->chip_select == 0))
+ gpio_set_value(gpio, active);
+ spi_writel(as, MR, mr);
}
-static inline void cs_deactivate(struct spi_device *spi)
+static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
{
unsigned gpio = (unsigned) spi->controller_data;
unsigned active = spi->mode & SPI_CS_HIGH;
+ u32 mr;
- dev_dbg(&spi->dev, "DEactivate %u%s\n", gpio, active ? " (low)" : "");
- gpio_set_value(gpio, !active);
+ /* only deactivate *this* device; sometimes transfers to
+ * another device may be active when this routine is called.
+ */
+ mr = spi_readl(as, MR);
+ if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) {
+ mr = SPI_BFINS(PCS, 0xf, mr);
+ spi_writel(as, MR, mr);
+ }
+
+ dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n",
+ gpio, active ? " (low)" : "",
+ mr);
+
+ if (!(cpu_is_at91rm9200() && spi->chip_select == 0))
+ gpio_set_value(gpio, !active);
}
/*
@@ -140,6 +174,7 @@ static void atmel_spi_next_xfer(struct spi_master *master,
/* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
* mechanism might help avoid the IRQ latency between transfers
+ * (and improve the nCS0 errata handling on at91rm9200 chips)
*
* We're also waiting for ENDRX before we start the next
* transfer because we need to handle some difficult timing
@@ -169,33 +204,62 @@ static void atmel_spi_next_message(struct spi_master *master)
{
struct atmel_spi *as = spi_master_get_devdata(master);
struct spi_message *msg;
- u32 mr;
+ struct spi_device *spi;
BUG_ON(as->current_transfer);
msg = list_entry(as->queue.next, struct spi_message, queue);
+ spi = msg->spi;
- /* Select the chip */
- mr = spi_readl(as, MR);
- mr = SPI_BFINS(PCS, ~(1 << msg->spi->chip_select), mr);
- spi_writel(as, MR, mr);
- cs_activate(msg->spi);
+ dev_dbg(master->cdev.dev, "start message %p for %s\n",
+ msg, spi->dev.bus_id);
+
+ /* select chip if it's not still active */
+ if (as->stay) {
+ if (as->stay != spi) {
+ cs_deactivate(as, as->stay);
+ cs_activate(as, spi);
+ }
+ as->stay = NULL;
+ } else
+ cs_activate(as, spi);
atmel_spi_next_xfer(master, msg);
}
-static void
+/*
+ * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma:
+ * - The buffer is either valid for CPU access, else NULL
+ * - If the buffer is valid, so is its DMA addresss
+ *
+ * This driver manages the dma addresss unless message->is_dma_mapped.
+ */
+static int
atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
{
+ struct device *dev = &as->pdev->dev;
+
xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
- if (xfer->tx_buf)
- xfer->tx_dma = dma_map_single(&as->pdev->dev,
+ if (xfer->tx_buf) {
+ xfer->tx_dma = dma_map_single(dev,
(void *) xfer->tx_buf, xfer->len,
DMA_TO_DEVICE);
- if (xfer->rx_buf)
- xfer->rx_dma = dma_map_single(&as->pdev->dev,
+ if (dma_mapping_error(xfer->tx_dma))
+ return -ENOMEM;
+ }
+ if (xfer->rx_buf) {
+ xfer->rx_dma = dma_map_single(dev,
xfer->rx_buf, xfer->len,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(xfer->tx_dma)) {
+ if (xfer->tx_buf)
+ dma_unmap_single(dev,
+ xfer->tx_dma, xfer->len,
+ DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+ }
+ return 0;
}
static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
@@ -211,9 +275,13 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
static void
atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
- struct spi_message *msg, int status)
+ struct spi_message *msg, int status, int stay)
{
- cs_deactivate(msg->spi);
+ if (!stay || status < 0)
+ cs_deactivate(as, msg->spi);
+ else
+ as->stay = msg->spi;
+
list_del(&msg->queue);
msg->status = status;
@@ -303,7 +371,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
/* Clear any overrun happening while cleaning up */
spi_readl(as, SR);
- atmel_spi_msg_done(master, as, msg, -EIO);
+ atmel_spi_msg_done(master, as, msg, -EIO, 0);
} else if (pending & SPI_BIT(ENDRX)) {
ret = IRQ_HANDLED;
@@ -321,12 +389,13 @@ atmel_spi_interrupt(int irq, void *dev_id)
if (msg->transfers.prev == &xfer->transfer_list) {
/* report completed message */
- atmel_spi_msg_done(master, as, msg, 0);
+ atmel_spi_msg_done(master, as, msg, 0,
+ xfer->cs_change);
} else {
if (xfer->cs_change) {
- cs_deactivate(msg->spi);
+ cs_deactivate(as, msg->spi);
udelay(1);
- cs_activate(msg->spi);
+ cs_activate(as, msg->spi);
}
/*
@@ -350,6 +419,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
return ret;
}
+/* the spi->mode bits understood by this driver: */
#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
static int atmel_spi_setup(struct spi_device *spi)
@@ -388,6 +458,14 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
+ /* see notes above re chipselect */
+ if (cpu_is_at91rm9200()
+ && spi->chip_select == 0
+ && (spi->mode & SPI_CS_HIGH)) {
+ dev_dbg(&spi->dev, "setup: can't be active-high\n");
+ return -EINVAL;
+ }
+
/* speed zero convention is used by some upper layers */
bus_hz = clk_get_rate(as->clk);
if (spi->max_speed_hz) {
@@ -397,8 +475,9 @@ static int atmel_spi_setup(struct spi_device *spi)
scbr = ((bus_hz + spi->max_speed_hz - 1)
/ spi->max_speed_hz);
if (scbr >= (1 << SPI_SCBR_SIZE)) {
- dev_dbg(&spi->dev, "setup: %d Hz too slow, scbr %u\n",
- spi->max_speed_hz, scbr);
+ dev_dbg(&spi->dev,
+ "setup: %d Hz too slow, scbr %u; min %ld Hz\n",
+ spi->max_speed_hz, scbr, bus_hz/255);
return -EINVAL;
}
} else
@@ -423,6 +502,14 @@ static int atmel_spi_setup(struct spi_device *spi)
return ret;
spi->controller_state = (void *)npcs_pin;
gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
+ } else {
+ unsigned long flags;
+
+ spin_lock_irqsave(&as->lock, flags);
+ if (as->stay == spi)
+ as->stay = NULL;
+ cs_deactivate(as, spi);
+ spin_unlock_irqrestore(&as->lock, flags);
}
dev_dbg(&spi->dev,
@@ -464,14 +551,22 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
dev_dbg(&spi->dev, "no protocol options yet\n");
return -ENOPROTOOPT;
}
- }
- /* scrub dcache "early" */
- if (!msg->is_dma_mapped) {
- list_for_each_entry(xfer, &msg->transfers, transfer_list)
- atmel_spi_dma_map_xfer(as, xfer);
+ /*
+ * DMA map early, for performance (empties dcache ASAP) and
+ * better fault reporting. This is a DMA-only driver.
+ *
+ * NOTE that if dma_unmap_single() ever starts to do work on
+ * platforms supported by this driver, we would need to clean
+ * up mappings for previously-mapped transfers.
+ */
+ if (!msg->is_dma_mapped) {
+ if (atmel_spi_dma_map_xfer(as, xfer) < 0)
+ return -ENOMEM;
+ }
}
+#ifdef VERBOSE
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
dev_dbg(controller,
" xfer %p: len %u tx %p/%08x rx %p/%08x\n",
@@ -479,6 +574,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
xfer->tx_buf, xfer->tx_dma,
xfer->rx_buf, xfer->rx_dma);
}
+#endif
msg->status = -EINPROGRESS;
msg->actual_length = 0;
@@ -494,8 +590,21 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
static void atmel_spi_cleanup(struct spi_device *spi)
{
- if (spi->controller_state)
- gpio_free((unsigned int)spi->controller_data);
+ struct atmel_spi *as = spi_master_get_devdata(spi->master);
+ unsigned gpio = (unsigned) spi->controller_data;
+ unsigned long flags;
+
+ if (!spi->controller_state)
+ return;
+
+ spin_lock_irqsave(&as->lock, flags);
+ if (as->stay == spi) {
+ as->stay = NULL;
+ cs_deactivate(as, spi);
+ }
+ spin_unlock_irqrestore(&as->lock, flags);
+
+ gpio_free(gpio);
}
/*-------------------------------------------------------------------------*/
@@ -536,6 +645,10 @@ static int __init atmel_spi_probe(struct platform_device *pdev)
as = spi_master_get_devdata(master);
+ /*
+ * Scratch buffer is used for throwaway rx and tx data.
+ * It's coherent to minimize dcache pollution.
+ */
as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
&as->buffer_dma, GFP_KERNEL);
if (!as->buffer)
diff --git a/drivers/spi/au1550_spi.c b/drivers/spi/au1550_spi.c
index ae2b1af0dba4..c47a650183a1 100644
--- a/drivers/spi/au1550_spi.c
+++ b/drivers/spi/au1550_spi.c
@@ -280,6 +280,9 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)
+
static int au1550_spi_setup(struct spi_device *spi)
{
struct au1550_spi *hw = spi_master_get_devdata(spi->master);
@@ -292,6 +295,12 @@ static int au1550_spi_setup(struct spi_device *spi)
return -EINVAL;
}
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
if (spi->max_speed_hz == 0)
spi->max_speed_hz = hw->freq_max;
if (spi->max_speed_hz > hw->freq_max
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 11f36bef3057..d2a4b2bdb07b 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -270,6 +270,9 @@ static void mpc52xx_psc_spi_work(struct work_struct *work)
spin_unlock_irq(&mps->lock);
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST)
+
static int mpc52xx_psc_spi_setup(struct spi_device *spi)
{
struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
@@ -279,6 +282,12 @@ static int mpc52xx_psc_spi_setup(struct spi_device *spi)
if (spi->bits_per_word%8)
return -EINVAL;
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
new file mode 100644
index 000000000000..6b357cdb9ea3
--- /dev/null
+++ b/drivers/spi/omap2_mcspi.c
@@ -0,0 +1,1081 @@
+/*
+ * OMAP2 McSPI controller driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
+ * Juha Yrjölä <juha.yrjola@nokia.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <linux/spi/spi.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/clock.h>
+
+
+#define OMAP2_MCSPI_MAX_FREQ 48000000
+
+#define OMAP2_MCSPI_REVISION 0x00
+#define OMAP2_MCSPI_SYSCONFIG 0x10
+#define OMAP2_MCSPI_SYSSTATUS 0x14
+#define OMAP2_MCSPI_IRQSTATUS 0x18
+#define OMAP2_MCSPI_IRQENABLE 0x1c
+#define OMAP2_MCSPI_WAKEUPENABLE 0x20
+#define OMAP2_MCSPI_SYST 0x24
+#define OMAP2_MCSPI_MODULCTRL 0x28
+
+/* per-channel banks, 0x14 bytes each, first is: */
+#define OMAP2_MCSPI_CHCONF0 0x2c
+#define OMAP2_MCSPI_CHSTAT0 0x30
+#define OMAP2_MCSPI_CHCTRL0 0x34
+#define OMAP2_MCSPI_TX0 0x38
+#define OMAP2_MCSPI_RX0 0x3c
+
+/* per-register bitmasks: */
+
+#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE (1 << 0)
+#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
+
+#define OMAP2_MCSPI_SYSSTATUS_RESETDONE (1 << 0)
+
+#define OMAP2_MCSPI_MODULCTRL_SINGLE (1 << 0)
+#define OMAP2_MCSPI_MODULCTRL_MS (1 << 2)
+#define OMAP2_MCSPI_MODULCTRL_STEST (1 << 3)
+
+#define OMAP2_MCSPI_CHCONF_PHA (1 << 0)
+#define OMAP2_MCSPI_CHCONF_POL (1 << 1)
+#define OMAP2_MCSPI_CHCONF_CLKD_MASK (0x0f << 2)
+#define OMAP2_MCSPI_CHCONF_EPOL (1 << 6)
+#define OMAP2_MCSPI_CHCONF_WL_MASK (0x1f << 7)
+#define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY (0x01 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY (0x02 << 12)
+#define OMAP2_MCSPI_CHCONF_TRM_MASK (0x03 << 12)
+#define OMAP2_MCSPI_CHCONF_DMAW (1 << 14)
+#define OMAP2_MCSPI_CHCONF_DMAR (1 << 15)
+#define OMAP2_MCSPI_CHCONF_DPE0 (1 << 16)
+#define OMAP2_MCSPI_CHCONF_DPE1 (1 << 17)
+#define OMAP2_MCSPI_CHCONF_IS (1 << 18)
+#define OMAP2_MCSPI_CHCONF_TURBO (1 << 19)
+#define OMAP2_MCSPI_CHCONF_FORCE (1 << 20)
+
+#define OMAP2_MCSPI_CHSTAT_RXS (1 << 0)
+#define OMAP2_MCSPI_CHSTAT_TXS (1 << 1)
+#define OMAP2_MCSPI_CHSTAT_EOT (1 << 2)
+
+#define OMAP2_MCSPI_CHCTRL_EN (1 << 0)
+
+
+/* We have 2 DMA channels per CS, one for RX and one for TX */
+struct omap2_mcspi_dma {
+ int dma_tx_channel;
+ int dma_rx_channel;
+
+ int dma_tx_sync_dev;
+ int dma_rx_sync_dev;
+
+ struct completion dma_tx_completion;
+ struct completion dma_rx_completion;
+};
+
+/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
+ * cache operations; better heuristics consider wordsize and bitrate.
+ */
+#define DMA_MIN_BYTES 8
+
+
+struct omap2_mcspi {
+ struct work_struct work;
+ /* lock protects queue and registers */
+ spinlock_t lock;
+ struct list_head msg_queue;
+ struct spi_master *master;
+ struct clk *ick;
+ struct clk *fck;
+ /* Virtual base address of the controller */
+ void __iomem *base;
+ /* SPI1 has 4 channels, while SPI2 has 2 */
+ struct omap2_mcspi_dma *dma_channels;
+};
+
+struct omap2_mcspi_cs {
+ void __iomem *base;
+ int word_len;
+};
+
+static struct workqueue_struct *omap2_mcspi_wq;
+
+#define MOD_REG_BIT(val, mask, set) do { \
+ if (set) \
+ val |= mask; \
+ else \
+ val &= ~mask; \
+} while (0)
+
+static inline void mcspi_write_reg(struct spi_master *master,
+ int idx, u32 val)
+{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+
+ __raw_writel(val, mcspi->base + idx);
+}
+
+static inline u32 mcspi_read_reg(struct spi_master *master, int idx)
+{
+ struct omap2_mcspi *mcspi = spi_master_get_devdata(master);
+
+ return __raw_readl(mcspi->base + idx);
+}
+
+static inline void mcspi_write_cs_reg(const struct spi_device *spi,
+ int idx, u32 val)
+{
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+
+ __raw_writel(val, cs->base + idx);
+}
+
+static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx)
+{
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+
+ return __raw_readl(cs->base + idx);
+}
+
+static void omap2_mcspi_set_dma_req(const struct spi_device *spi,
+ int is_read, int enable)
+{
+ u32 l, rw;
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+
+ if (is_read) /* 1 is read, 0 write */
+ rw = OMAP2_MCSPI_CHCONF_DMAR;
+ else
+ rw = OMAP2_MCSPI_CHCONF_DMAW;
+
+ MOD_REG_BIT(l, rw, enable);
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+}
+
+static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
+{
+ u32 l;
+
+ l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
+}
+
+static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
+{
+ u32 l;
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ MOD_REG_BIT(l, OMAP2_MCSPI_CHCONF_FORCE, cs_active);
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+}
+
+static void omap2_mcspi_set_master_mode(struct spi_master *master)
+{
+ u32 l;
+
+ /* setup when switching from (reset default) slave mode
+ * to single-channel master mode
+ */
+ l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
+ MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
+ MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
+ MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
+ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
+}
+
+static unsigned
+omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+ struct omap2_mcspi_dma *mcspi_dma;
+ unsigned int count, c;
+ unsigned long base, tx_reg, rx_reg;
+ int word_len, data_type, element_count;
+ u8 * rx;
+ const u8 * tx;
+
+ mcspi = spi_master_get_devdata(spi->master);
+ mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+ count = xfer->len;
+ c = count;
+ word_len = cs->word_len;
+
+ base = (unsigned long) io_v2p(cs->base);
+ tx_reg = base + OMAP2_MCSPI_TX0;
+ rx_reg = base + OMAP2_MCSPI_RX0;
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+
+ if (word_len <= 8) {
+ data_type = OMAP_DMA_DATA_TYPE_S8;
+ element_count = count;
+ } else if (word_len <= 16) {
+ data_type = OMAP_DMA_DATA_TYPE_S16;
+ element_count = count >> 1;
+ } else /* word_len <= 32 */ {
+ data_type = OMAP_DMA_DATA_TYPE_S32;
+ element_count = count >> 2;
+ }
+
+ if (tx != NULL) {
+ omap_set_dma_transfer_params(mcspi_dma->dma_tx_channel,
+ data_type, element_count, 1,
+ OMAP_DMA_SYNC_ELEMENT,
+ mcspi_dma->dma_tx_sync_dev, 0);
+
+ omap_set_dma_dest_params(mcspi_dma->dma_tx_channel, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ tx_reg, 0, 0);
+
+ omap_set_dma_src_params(mcspi_dma->dma_tx_channel, 0,
+ OMAP_DMA_AMODE_POST_INC,
+ xfer->tx_dma, 0, 0);
+ }
+
+ if (rx != NULL) {
+ omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
+ data_type, element_count, 1,
+ OMAP_DMA_SYNC_ELEMENT,
+ mcspi_dma->dma_rx_sync_dev, 1);
+
+ omap_set_dma_src_params(mcspi_dma->dma_rx_channel, 0,
+ OMAP_DMA_AMODE_CONSTANT,
+ rx_reg, 0, 0);
+
+ omap_set_dma_dest_params(mcspi_dma->dma_rx_channel, 0,
+ OMAP_DMA_AMODE_POST_INC,
+ xfer->rx_dma, 0, 0);
+ }
+
+ if (tx != NULL) {
+ omap_start_dma(mcspi_dma->dma_tx_channel);
+ omap2_mcspi_set_dma_req(spi, 0, 1);
+ }
+
+ if (rx != NULL) {
+ omap_start_dma(mcspi_dma->dma_rx_channel);
+ omap2_mcspi_set_dma_req(spi, 1, 1);
+ }
+
+ if (tx != NULL) {
+ wait_for_completion(&mcspi_dma->dma_tx_completion);
+ dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE);
+ }
+
+ if (rx != NULL) {
+ wait_for_completion(&mcspi_dma->dma_rx_completion);
+ dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
+ }
+ return count;
+}
+
+static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(1000);
+ while (!(__raw_readl(reg) & bit)) {
+ if (time_after(jiffies, timeout))
+ return -1;
+ cpu_relax();
+ }
+ return 0;
+}
+
+static unsigned
+omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+ unsigned int count, c;
+ u32 l;
+ void __iomem *base = cs->base;
+ void __iomem *tx_reg;
+ void __iomem *rx_reg;
+ void __iomem *chstat_reg;
+ int word_len;
+
+ mcspi = spi_master_get_devdata(spi->master);
+ count = xfer->len;
+ c = count;
+ word_len = cs->word_len;
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+
+ /* We store the pre-calculated register addresses on stack to speed
+ * up the transfer loop. */
+ tx_reg = base + OMAP2_MCSPI_TX0;
+ rx_reg = base + OMAP2_MCSPI_RX0;
+ chstat_reg = base + OMAP2_MCSPI_CHSTAT0;
+
+ if (word_len <= 8) {
+ u8 *rx;
+ const u8 *tx;
+
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+
+ do {
+ if (tx != NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_TXS) < 0) {
+ dev_err(&spi->dev, "TXS timed out\n");
+ goto out;
+ }
+#ifdef VERBOSE
+ dev_dbg(&spi->dev, "write-%d %02x\n",
+ word_len, *tx);
+#endif
+ __raw_writel(*tx++, tx_reg);
+ }
+ if (rx != NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_RXS) < 0) {
+ dev_err(&spi->dev, "RXS timed out\n");
+ goto out;
+ }
+ /* prevent last RX_ONLY read from triggering
+ * more word i/o: switch to rx+tx
+ */
+ if (c == 0 && tx == NULL)
+ mcspi_write_cs_reg(spi,
+ OMAP2_MCSPI_CHCONF0, l);
+ *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+ dev_dbg(&spi->dev, "read-%d %02x\n",
+ word_len, *(rx - 1));
+#endif
+ }
+ c -= 1;
+ } while (c);
+ } else if (word_len <= 16) {
+ u16 *rx;
+ const u16 *tx;
+
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+ do {
+ if (tx != NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_TXS) < 0) {
+ dev_err(&spi->dev, "TXS timed out\n");
+ goto out;
+ }
+#ifdef VERBOSE
+ dev_dbg(&spi->dev, "write-%d %04x\n",
+ word_len, *tx);
+#endif
+ __raw_writel(*tx++, tx_reg);
+ }
+ if (rx != NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_RXS) < 0) {
+ dev_err(&spi->dev, "RXS timed out\n");
+ goto out;
+ }
+ /* prevent last RX_ONLY read from triggering
+ * more word i/o: switch to rx+tx
+ */
+ if (c == 0 && tx == NULL)
+ mcspi_write_cs_reg(spi,
+ OMAP2_MCSPI_CHCONF0, l);
+ *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+ dev_dbg(&spi->dev, "read-%d %04x\n",
+ word_len, *(rx - 1));
+#endif
+ }
+ c -= 2;
+ } while (c);
+ } else if (word_len <= 32) {
+ u32 *rx;
+ const u32 *tx;
+
+ rx = xfer->rx_buf;
+ tx = xfer->tx_buf;
+ do {
+ if (tx != NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_TXS) < 0) {
+ dev_err(&spi->dev, "TXS timed out\n");
+ goto out;
+ }
+#ifdef VERBOSE
+ dev_dbg(&spi->dev, "write-%d %04x\n",
+ word_len, *tx);
+#endif
+ __raw_writel(*tx++, tx_reg);
+ }
+ if (rx != NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_RXS) < 0) {
+ dev_err(&spi->dev, "RXS timed out\n");
+ goto out;
+ }
+ /* prevent last RX_ONLY read from triggering
+ * more word i/o: switch to rx+tx
+ */
+ if (c == 0 && tx == NULL)
+ mcspi_write_cs_reg(spi,
+ OMAP2_MCSPI_CHCONF0, l);
+ *rx++ = __raw_readl(rx_reg);
+#ifdef VERBOSE
+ dev_dbg(&spi->dev, "read-%d %04x\n",
+ word_len, *(rx - 1));
+#endif
+ }
+ c -= 4;
+ } while (c);
+ }
+
+ /* for TX_ONLY mode, be sure all words have shifted out */
+ if (xfer->rx_buf == NULL) {
+ if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_TXS) < 0) {
+ dev_err(&spi->dev, "TXS timed out\n");
+ } else if (mcspi_wait_for_reg_bit(chstat_reg,
+ OMAP2_MCSPI_CHSTAT_EOT) < 0)
+ dev_err(&spi->dev, "EOT timed out\n");
+ }
+out:
+ return count - c;
+}
+
+/* called only when no transfer is active to this device */
+static int omap2_mcspi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+ struct omap2_mcspi *mcspi;
+ u32 l = 0, div = 0;
+ u8 word_len = spi->bits_per_word;
+
+ mcspi = spi_master_get_devdata(spi->master);
+
+ if (t != NULL && t->bits_per_word)
+ word_len = t->bits_per_word;
+
+ cs->word_len = word_len;
+
+ if (spi->max_speed_hz) {
+ while (div <= 15 && (OMAP2_MCSPI_MAX_FREQ / (1 << div))
+ > spi->max_speed_hz)
+ div++;
+ } else
+ div = 15;
+
+ l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+
+ /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
+ * REVISIT: this controller could support SPI_3WIRE mode.
+ */
+ l &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
+ l |= OMAP2_MCSPI_CHCONF_DPE0;
+
+ /* wordlength */
+ l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
+ l |= (word_len - 1) << 7;
+
+ /* set chipselect polarity; manage with FORCE */
+ if (!(spi->mode & SPI_CS_HIGH))
+ l |= OMAP2_MCSPI_CHCONF_EPOL; /* active-low; normal */
+ else
+ l &= ~OMAP2_MCSPI_CHCONF_EPOL;
+
+ /* set clock divisor */
+ l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
+ l |= div << 2;
+
+ /* set SPI mode 0..3 */
+ if (spi->mode & SPI_CPOL)
+ l |= OMAP2_MCSPI_CHCONF_POL;
+ else
+ l &= ~OMAP2_MCSPI_CHCONF_POL;
+ if (spi->mode & SPI_CPHA)
+ l |= OMAP2_MCSPI_CHCONF_PHA;
+ else
+ l &= ~OMAP2_MCSPI_CHCONF_PHA;
+
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
+
+ dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
+ OMAP2_MCSPI_MAX_FREQ / (1 << div),
+ (spi->mode & SPI_CPHA) ? "trailing" : "leading",
+ (spi->mode & SPI_CPOL) ? "inverted" : "normal");
+
+ return 0;
+}
+
+static void omap2_mcspi_dma_rx_callback(int lch, u16 ch_status, void *data)
+{
+ struct spi_device *spi = data;
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *mcspi_dma;
+
+ mcspi = spi_master_get_devdata(spi->master);
+ mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+ complete(&mcspi_dma->dma_rx_completion);
+
+ /* We must disable the DMA RX request */
+ omap2_mcspi_set_dma_req(spi, 1, 0);
+}
+
+static void omap2_mcspi_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+ struct spi_device *spi = data;
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *mcspi_dma;
+
+ mcspi = spi_master_get_devdata(spi->master);
+ mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
+
+ complete(&mcspi_dma->dma_tx_completion);
+
+ /* We must disable the DMA TX request */
+ omap2_mcspi_set_dma_req(spi, 0, 0);
+}
+
+static int omap2_mcspi_request_dma(struct spi_device *spi)
+{
+ struct spi_master *master = spi->master;
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *mcspi_dma;
+
+ mcspi = spi_master_get_devdata(master);
+ mcspi_dma = mcspi->dma_channels + spi->chip_select;
+
+ if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
+ omap2_mcspi_dma_rx_callback, spi,
+ &mcspi_dma->dma_rx_channel)) {
+ dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
+ return -EAGAIN;
+ }
+
+ if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
+ omap2_mcspi_dma_tx_callback, spi,
+ &mcspi_dma->dma_tx_channel)) {
+ omap_free_dma(mcspi_dma->dma_rx_channel);
+ mcspi_dma->dma_rx_channel = -1;
+ dev_err(&spi->dev, "no TX DMA channel for McSPI\n");
+ return -EAGAIN;
+ }
+
+ init_completion(&mcspi_dma->dma_rx_completion);
+ init_completion(&mcspi_dma->dma_tx_completion);
+
+ return 0;
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
+static int omap2_mcspi_setup(struct spi_device *spi)
+{
+ int ret;
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *mcspi_dma;
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
+ if (spi->bits_per_word == 0)
+ spi->bits_per_word = 8;
+ else if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
+ dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
+ mcspi = spi_master_get_devdata(spi->master);
+ mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+ if (!cs) {
+ cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ cs->base = mcspi->base + spi->chip_select * 0x14;
+ spi->controller_state = cs;
+ }
+
+ if (mcspi_dma->dma_rx_channel == -1
+ || mcspi_dma->dma_tx_channel == -1) {
+ ret = omap2_mcspi_request_dma(spi);
+ if (ret < 0)
+ return ret;
+ }
+
+ clk_enable(mcspi->ick);
+ clk_enable(mcspi->fck);
+ ret = omap2_mcspi_setup_transfer(spi, NULL);
+ clk_disable(mcspi->fck);
+ clk_disable(mcspi->ick);
+
+ return ret;
+}
+
+static void omap2_mcspi_cleanup(struct spi_device *spi)
+{
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *mcspi_dma;
+
+ mcspi = spi_master_get_devdata(spi->master);
+ mcspi_dma = &mcspi->dma_channels[spi->chip_select];
+
+ kfree(spi->controller_state);
+
+ if (mcspi_dma->dma_rx_channel != -1) {
+ omap_free_dma(mcspi_dma->dma_rx_channel);
+ mcspi_dma->dma_rx_channel = -1;
+ }
+ if (mcspi_dma->dma_tx_channel != -1) {
+ omap_free_dma(mcspi_dma->dma_tx_channel);
+ mcspi_dma->dma_tx_channel = -1;
+ }
+}
+
+static void omap2_mcspi_work(struct work_struct *work)
+{
+ struct omap2_mcspi *mcspi;
+
+ mcspi = container_of(work, struct omap2_mcspi, work);
+ spin_lock_irq(&mcspi->lock);
+
+ clk_enable(mcspi->ick);
+ clk_enable(mcspi->fck);
+
+ /* We only enable one channel at a time -- the one whose message is
+ * at the head of the queue -- although this controller would gladly
+ * arbitrate among multiple channels. This corresponds to "single
+ * channel" master mode. As a side effect, we need to manage the
+ * chipselect with the FORCE bit ... CS != channel enable.
+ */
+ while (!list_empty(&mcspi->msg_queue)) {
+ struct spi_message *m;
+ struct spi_device *spi;
+ struct spi_transfer *t = NULL;
+ int cs_active = 0;
+ struct omap2_mcspi_device_config *conf;
+ struct omap2_mcspi_cs *cs;
+ int par_override = 0;
+ int status = 0;
+ u32 chconf;
+
+ m = container_of(mcspi->msg_queue.next, struct spi_message,
+ queue);
+
+ list_del_init(&m->queue);
+ spin_unlock_irq(&mcspi->lock);
+
+ spi = m->spi;
+ conf = spi->controller_data;
+ cs = spi->controller_state;
+
+ omap2_mcspi_set_enable(spi, 1);
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
+ status = -EINVAL;
+ break;
+ }
+ if (par_override || t->speed_hz || t->bits_per_word) {
+ par_override = 1;
+ status = omap2_mcspi_setup_transfer(spi, t);
+ if (status < 0)
+ break;
+ if (!t->speed_hz && !t->bits_per_word)
+ par_override = 0;
+ }
+
+ if (!cs_active) {
+ omap2_mcspi_force_cs(spi, 1);
+ cs_active = 1;
+ }
+
+ chconf = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+ chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
+ if (t->tx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
+ else if (t->rx_buf == NULL)
+ chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
+ mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, chconf);
+
+ if (t->len) {
+ unsigned count;
+
+ /* RX_ONLY mode needs dummy data in TX reg */
+ if (t->tx_buf == NULL)
+ __raw_writel(0, cs->base
+ + OMAP2_MCSPI_TX0);
+
+ if (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)
+ count = omap2_mcspi_txrx_dma(spi, t);
+ else
+ count = omap2_mcspi_txrx_pio(spi, t);
+ m->actual_length += count;
+
+ if (count != t->len) {
+ status = -EIO;
+ break;
+ }
+ }
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ /* ignore the "leave it on after last xfer" hint */
+ if (t->cs_change) {
+ omap2_mcspi_force_cs(spi, 0);
+ cs_active = 0;
+ }
+ }
+
+ /* Restore defaults if they were overriden */
+ if (par_override) {
+ par_override = 0;
+ status = omap2_mcspi_setup_transfer(spi, NULL);
+ }
+
+ if (cs_active)
+ omap2_mcspi_force_cs(spi, 0);
+
+ omap2_mcspi_set_enable(spi, 0);
+
+ m->status = status;
+ m->complete(m->context);
+
+ spin_lock_irq(&mcspi->lock);
+ }
+
+ clk_disable(mcspi->fck);
+ clk_disable(mcspi->ick);
+
+ spin_unlock_irq(&mcspi->lock);
+}
+
+static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct omap2_mcspi *mcspi;
+ unsigned long flags;
+ struct spi_transfer *t;
+
+ m->actual_length = 0;
+ m->status = 0;
+
+ /* reject invalid messages and transfers */
+ if (list_empty(&m->transfers) || !m->complete)
+ return -EINVAL;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ const void *tx_buf = t->tx_buf;
+ void *rx_buf = t->rx_buf;
+ unsigned len = t->len;
+
+ if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
+ || (len && !(rx_buf || tx_buf))
+ || (t->bits_per_word &&
+ ( t->bits_per_word < 4
+ || t->bits_per_word > 32))) {
+ dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
+ t->speed_hz,
+ len,
+ tx_buf ? "tx" : "",
+ rx_buf ? "rx" : "",
+ t->bits_per_word);
+ return -EINVAL;
+ }
+ if (t->speed_hz && t->speed_hz < OMAP2_MCSPI_MAX_FREQ/(1<<16)) {
+ dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
+ t->speed_hz,
+ OMAP2_MCSPI_MAX_FREQ/(1<<16));
+ return -EINVAL;
+ }
+
+ if (m->is_dma_mapped || len < DMA_MIN_BYTES)
+ continue;
+
+ /* Do DMA mapping "early" for better error reporting and
+ * dcache use. Note that if dma_unmap_single() ever starts
+ * to do real work on ARM, we'd need to clean up mappings
+ * for previous transfers on *ALL* exits of this loop...
+ */
+ if (tx_buf != NULL) {
+ t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
+ len, DMA_TO_DEVICE);
+ if (dma_mapping_error(t->tx_dma)) {
+ dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
+ 'T', len);
+ return -EINVAL;
+ }
+ }
+ if (rx_buf != NULL) {
+ t->rx_dma = dma_map_single(&spi->dev, rx_buf, t->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(t->rx_dma)) {
+ dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
+ 'R', len);
+ if (tx_buf != NULL)
+ dma_unmap_single(NULL, t->tx_dma,
+ len, DMA_TO_DEVICE);
+ return -EINVAL;
+ }
+ }
+ }
+
+ mcspi = spi_master_get_devdata(spi->master);
+
+ spin_lock_irqsave(&mcspi->lock, flags);
+ list_add_tail(&m->queue, &mcspi->msg_queue);
+ queue_work(omap2_mcspi_wq, &mcspi->work);
+ spin_unlock_irqrestore(&mcspi->lock, flags);
+
+ return 0;
+}
+
+static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi)
+{
+ struct spi_master *master = mcspi->master;
+ u32 tmp;
+
+ clk_enable(mcspi->ick);
+ clk_enable(mcspi->fck);
+
+ mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
+ OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
+ do {
+ tmp = mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS);
+ } while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
+
+ mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
+ /* (3 << 8) | (2 << 3) | */
+ OMAP2_MCSPI_SYSCONFIG_AUTOIDLE);
+
+ omap2_mcspi_set_master_mode(master);
+
+ clk_disable(mcspi->fck);
+ clk_disable(mcspi->ick);
+ return 0;
+}
+
+static u8 __initdata spi1_rxdma_id [] = {
+ OMAP24XX_DMA_SPI1_RX0,
+ OMAP24XX_DMA_SPI1_RX1,
+ OMAP24XX_DMA_SPI1_RX2,
+ OMAP24XX_DMA_SPI1_RX3,
+};
+
+static u8 __initdata spi1_txdma_id [] = {
+ OMAP24XX_DMA_SPI1_TX0,
+ OMAP24XX_DMA_SPI1_TX1,
+ OMAP24XX_DMA_SPI1_TX2,
+ OMAP24XX_DMA_SPI1_TX3,
+};
+
+static u8 __initdata spi2_rxdma_id[] = {
+ OMAP24XX_DMA_SPI2_RX0,
+ OMAP24XX_DMA_SPI2_RX1,
+};
+
+static u8 __initdata spi2_txdma_id[] = {
+ OMAP24XX_DMA_SPI2_TX0,
+ OMAP24XX_DMA_SPI2_TX1,
+};
+
+static int __init omap2_mcspi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct omap2_mcspi *mcspi;
+ struct resource *r;
+ int status = 0, i;
+ const u8 *rxdma_id, *txdma_id;
+ unsigned num_chipselect;
+
+ switch (pdev->id) {
+ case 1:
+ rxdma_id = spi1_rxdma_id;
+ txdma_id = spi1_txdma_id;
+ num_chipselect = 4;
+ break;
+ case 2:
+ rxdma_id = spi2_rxdma_id;
+ txdma_id = spi2_txdma_id;
+ num_chipselect = 2;
+ break;
+ /* REVISIT omap2430 has a third McSPI ... */
+ default:
+ return -EINVAL;
+ }
+
+ master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
+ if (master == NULL) {
+ dev_dbg(&pdev->dev, "master allocation failed\n");
+ return -ENOMEM;
+ }
+
+ if (pdev->id != -1)
+ master->bus_num = pdev->id;
+
+ master->setup = omap2_mcspi_setup;
+ master->transfer = omap2_mcspi_transfer;
+ master->cleanup = omap2_mcspi_cleanup;
+ master->num_chipselect = num_chipselect;
+
+ dev_set_drvdata(&pdev->dev, master);
+
+ mcspi = spi_master_get_devdata(master);
+ mcspi->master = master;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ status = -ENODEV;
+ goto err1;
+ }
+ if (!request_mem_region(r->start, (r->end - r->start) + 1,
+ pdev->dev.bus_id)) {
+ status = -EBUSY;
+ goto err1;
+ }
+
+ mcspi->base = (void __iomem *) io_p2v(r->start);
+
+ INIT_WORK(&mcspi->work, omap2_mcspi_work);
+
+ spin_lock_init(&mcspi->lock);
+ INIT_LIST_HEAD(&mcspi->msg_queue);
+
+ mcspi->ick = clk_get(&pdev->dev, "mcspi_ick");
+ if (IS_ERR(mcspi->ick)) {
+ dev_dbg(&pdev->dev, "can't get mcspi_ick\n");
+ status = PTR_ERR(mcspi->ick);
+ goto err1a;
+ }
+ mcspi->fck = clk_get(&pdev->dev, "mcspi_fck");
+ if (IS_ERR(mcspi->fck)) {
+ dev_dbg(&pdev->dev, "can't get mcspi_fck\n");
+ status = PTR_ERR(mcspi->fck);
+ goto err2;
+ }
+
+ mcspi->dma_channels = kcalloc(master->num_chipselect,
+ sizeof(struct omap2_mcspi_dma),
+ GFP_KERNEL);
+
+ if (mcspi->dma_channels == NULL)
+ goto err3;
+
+ for (i = 0; i < num_chipselect; i++) {
+ mcspi->dma_channels[i].dma_rx_channel = -1;
+ mcspi->dma_channels[i].dma_rx_sync_dev = rxdma_id[i];
+ mcspi->dma_channels[i].dma_tx_channel = -1;
+ mcspi->dma_channels[i].dma_tx_sync_dev = txdma_id[i];
+ }
+
+ if (omap2_mcspi_reset(mcspi) < 0)
+ goto err4;
+
+ status = spi_register_master(master);
+ if (status < 0)
+ goto err4;
+
+ return status;
+
+err4:
+ kfree(mcspi->dma_channels);
+err3:
+ clk_put(mcspi->fck);
+err2:
+ clk_put(mcspi->ick);
+err1a:
+ release_mem_region(r->start, (r->end - r->start) + 1);
+err1:
+ spi_master_put(master);
+ return status;
+}
+
+static int __exit omap2_mcspi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_dma *dma_channels;
+ struct resource *r;
+
+ master = dev_get_drvdata(&pdev->dev);
+ mcspi = spi_master_get_devdata(master);
+ dma_channels = mcspi->dma_channels;
+
+ clk_put(mcspi->fck);
+ clk_put(mcspi->ick);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(r->start, (r->end - r->start) + 1);
+
+ spi_unregister_master(master);
+ kfree(dma_channels);
+
+ return 0;
+}
+
+static struct platform_driver omap2_mcspi_driver = {
+ .driver = {
+ .name = "omap2_mcspi",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(omap2_mcspi_remove),
+};
+
+
+static int __init omap2_mcspi_init(void)
+{
+ omap2_mcspi_wq = create_singlethread_workqueue(
+ omap2_mcspi_driver.driver.name);
+ if (omap2_mcspi_wq == NULL)
+ return -1;
+ return platform_driver_probe(&omap2_mcspi_driver, omap2_mcspi_probe);
+}
+subsys_initcall(omap2_mcspi_init);
+
+static void __exit omap2_mcspi_exit(void)
+{
+ platform_driver_unregister(&omap2_mcspi_driver);
+
+ destroy_workqueue(omap2_mcspi_wq);
+}
+module_exit(omap2_mcspi_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/omap_uwire.c b/drivers/spi/omap_uwire.c
index 95183e1df525..d275c615a73e 100644
--- a/drivers/spi/omap_uwire.c
+++ b/drivers/spi/omap_uwire.c
@@ -445,10 +445,19 @@ done:
return status;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
static int uwire_setup(struct spi_device *spi)
{
struct uwire_state *ust = spi->controller_state;
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
if (ust == NULL) {
ust = kzalloc(sizeof(*ust), GFP_KERNEL);
if (ust == NULL)
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 9f2c887ffa04..e51311b2da0b 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -1067,6 +1067,9 @@ static int transfer(struct spi_device *spi, struct spi_message *msg)
return 0;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA)
+
static int setup(struct spi_device *spi)
{
struct pxa2xx_spi_chip *chip_info = NULL;
@@ -1093,6 +1096,12 @@ static int setup(struct spi_device *spi)
return -EINVAL;
}
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (!chip) {
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 4831edbae2d5..b05de30b5d9b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -23,6 +23,7 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/cache.h>
+#include <linux/mutex.h>
#include <linux/spi/spi.h>
@@ -185,7 +186,7 @@ struct boardinfo {
};
static LIST_HEAD(board_list);
-static DECLARE_MUTEX(board_lock);
+static DEFINE_MUTEX(board_lock);
/**
@@ -292,9 +293,9 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
bi->n_board_info = n;
memcpy(bi->board_info, info, n * sizeof *info);
- down(&board_lock);
+ mutex_lock(&board_lock);
list_add_tail(&bi->list, &board_list);
- up(&board_lock);
+ mutex_unlock(&board_lock);
return 0;
}
@@ -302,13 +303,12 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
* creates board info from kernel command lines
*/
-static void __init_or_module
-scan_boardinfo(struct spi_master *master)
+static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo *bi;
struct device *dev = master->cdev.dev;
- down(&board_lock);
+ mutex_lock(&board_lock);
list_for_each_entry(bi, &board_list, list) {
struct spi_board_info *chip = bi->board_info;
unsigned n;
@@ -330,7 +330,7 @@ scan_boardinfo(struct spi_master *master)
(void) spi_new_device(master, chip);
}
}
- up(&board_lock);
+ mutex_unlock(&board_lock);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 88425e1af4d3..0c85c984ccb4 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -187,12 +187,10 @@ int spi_bitbang_setup(struct spi_device *spi)
bitbang = spi_master_get_devdata(spi->master);
- /* REVISIT: some systems will want to support devices using lsb-first
- * bit encodings on the wire. In pure software that would be trivial,
- * just bitbang_txrx_le_cphaX() routines shifting the other way, and
- * some hardware controllers also have this support.
+ /* Bitbangers can support SPI_CS_HIGH, SPI_3WIRE, and so on;
+ * add those to master->flags, and provide the other support.
*/
- if ((spi->mode & SPI_LSB_FIRST) != 0)
+ if ((spi->mode & ~(SPI_CPOL|SPI_CPHA|bitbang->flags)) != 0)
return -EINVAL;
if (!cs) {
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 656be4a5094a..aee9ad6f633c 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1163,6 +1163,9 @@ msg_rejected:
return -EINVAL;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
/* On first setup bad values must free chip_data memory since will cause
spi_new_device to fail. Bad value setup from protocol driver are simply not
applied and notified to the calling driver. */
@@ -1174,6 +1177,12 @@ static int setup(struct spi_device *spi)
u32 tmp;
int status = 0;
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
/* Get controller data */
chip_info = spi->controller_data;
@@ -1245,21 +1254,6 @@ static int setup(struct spi_device *spi)
/* SPI mode */
tmp = spi->mode;
- if (tmp & SPI_LSB_FIRST) {
- status = -EINVAL;
- if (first_setup) {
- dev_err(&spi->dev,
- "setup - "
- "HW doesn't support LSB first transfer\n");
- goto err_first_setup;
- } else {
- dev_err(&spi->dev,
- "setup - "
- "HW doesn't support LSB first transfer, "
- "default to MSB first\n");
- spi->mode &= ~SPI_LSB_FIRST;
- }
- }
if (tmp & SPI_CS_HIGH) {
u32_EDIT(chip->control,
SPI_CONTROL_SSPOL, SPI_CONTROL_SSPOL_ACT_HIGH);
diff --git a/drivers/spi/spi_lm70llp.c b/drivers/spi/spi_lm70llp.c
new file mode 100644
index 000000000000..4ea68ac16115
--- /dev/null
+++ b/drivers/spi/spi_lm70llp.c
@@ -0,0 +1,361 @@
+/*
+ * spi_lm70llp.c - driver for lm70llp eval board for the LM70 sensor
+ *
+ * Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/parport.h>
+#include <linux/sysfs.h>
+#include <linux/workqueue.h>
+
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+
+/*
+ * The LM70 communicates with a host processor using a 3-wire variant of
+ * the SPI/Microwire bus interface. This driver specifically supports an
+ * NS LM70 LLP Evaluation Board, interfacing to a PC using its parallel
+ * port to bitbang an SPI-parport bridge. Accordingly, this is an SPI
+ * master controller driver. The hwmon/lm70 driver is a "SPI protocol
+ * driver", layered on top of this one and usable without the lm70llp.
+ *
+ * The LM70 is a temperature sensor chip from National Semiconductor; its
+ * datasheet is available at http://www.national.com/pf/LM/LM70.html
+ *
+ * Also see Documentation/spi/spi-lm70llp. The SPI<->parport code here is
+ * (heavily) based on spi-butterfly by David Brownell.
+ *
+ * The LM70 LLP connects to the PC parallel port in the following manner:
+ *
+ * Parallel LM70 LLP
+ * Port Direction JP2 Header
+ * ----------- --------- ------------
+ * D0 2 - -
+ * D1 3 --> V+ 5
+ * D2 4 --> V+ 5
+ * D3 5 --> V+ 5
+ * D4 6 --> V+ 5
+ * D5 7 --> nCS 8
+ * D6 8 --> SCLK 3
+ * D7 9 --> SI/O 5
+ * GND 25 - GND 7
+ * Select 13 <-- SI/O 1
+ *
+ * Note that parport pin 13 actually gets inverted by the transistor
+ * arrangement which lets either the parport or the LM70 drive the
+ * SI/SO signal.
+ */
+
+#define DRVNAME "spi-lm70llp"
+
+#define lm70_INIT 0xBE
+#define SIO 0x10
+#define nCS 0x20
+#define SCLK 0x40
+
+/*-------------------------------------------------------------------------*/
+
+struct spi_lm70llp {
+ struct spi_bitbang bitbang;
+ struct parport *port;
+ struct pardevice *pd;
+ struct spi_device *spidev_lm70;
+ struct spi_board_info info;
+ struct class_device *cdev;
+};
+
+/* REVISIT : ugly global ; provides "exclusive open" facility */
+static struct spi_lm70llp *lm70llp;
+
+
+/*-------------------------------------------------------------------*/
+
+static inline struct spi_lm70llp *spidev_to_pp(struct spi_device *spi)
+{
+ return spi->controller_data;
+}
+
+/*---------------------- LM70 LLP eval board-specific inlines follow */
+
+/* NOTE: we don't actually need to reread the output values, since they'll
+ * still be what we wrote before. Plus, going through parport builds in
+ * a ~1ms/operation delay; these SPI transfers could easily be faster.
+ */
+
+static inline void deassertCS(struct spi_lm70llp *pp)
+{
+ u8 data = parport_read_data(pp->port);
+ parport_write_data(pp->port, data | nCS);
+}
+
+static inline void assertCS(struct spi_lm70llp *pp)
+{
+ u8 data = parport_read_data(pp->port);
+ parport_write_data(pp->port, data & ~nCS);
+}
+
+static inline void clkHigh(struct spi_lm70llp *pp)
+{
+ u8 data = parport_read_data(pp->port);
+ parport_write_data(pp->port, data | SCLK);
+}
+
+static inline void clkLow(struct spi_lm70llp *pp)
+{
+ u8 data = parport_read_data(pp->port);
+ parport_write_data(pp->port, data & ~SCLK);
+}
+
+/*------------------------- SPI-LM70-specific inlines ----------------------*/
+
+static inline void spidelay(unsigned d)
+{
+ udelay(d);
+}
+
+static inline void setsck(struct spi_device *s, int is_on)
+{
+ struct spi_lm70llp *pp = spidev_to_pp(s);
+
+ if (is_on)
+ clkHigh(pp);
+ else
+ clkLow(pp);
+}
+
+static inline void setmosi(struct spi_device *s, int is_on)
+{
+ /* FIXME update D7 ... this way we can put the chip
+ * into shutdown mode and read the manufacturer ID,
+ * but we can't put it back into operational mode.
+ */
+}
+
+/*
+ * getmiso:
+ * Why do we return 0 when the SIO line is high and vice-versa?
+ * The fact is, the lm70 eval board from NS (which this driver drives),
+ * is wired in just such a way : when the lm70's SIO goes high, a transistor
+ * switches it to low reflecting this on the parport (pin 13), and vice-versa.
+ */
+static inline int getmiso(struct spi_device *s)
+{
+ struct spi_lm70llp *pp = spidev_to_pp(s);
+ return ((SIO == (parport_read_status(pp->port) & SIO)) ? 0 : 1 );
+}
+/*--------------------------------------------------------------------*/
+
+#define EXPAND_BITBANG_TXRX 1
+#include <linux/spi/spi_bitbang.h>
+
+static void lm70_chipselect(struct spi_device *spi, int value)
+{
+ struct spi_lm70llp *pp = spidev_to_pp(spi);
+
+ if (value)
+ assertCS(pp);
+ else
+ deassertCS(pp);
+}
+
+/*
+ * Our actual bitbanger routine.
+ */
+static u32 lm70_txrx(struct spi_device *spi, unsigned nsecs, u32 word, u8 bits)
+{
+ static u32 sio=0;
+ static int first_time=1;
+
+ /* First time: perform SPI bitbang and return the LSB of
+ * the result of the SPI call.
+ */
+ if (first_time) {
+ sio = bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+ first_time=0;
+ return (sio & 0x00ff);
+ }
+ /* Return the MSB of the result of the SPI call */
+ else {
+ first_time=1;
+ return (sio >> 8);
+ }
+}
+
+static void spi_lm70llp_attach(struct parport *p)
+{
+ struct pardevice *pd;
+ struct spi_lm70llp *pp;
+ struct spi_master *master;
+ int status;
+
+ if (lm70llp) {
+ printk(KERN_WARNING
+ "%s: spi_lm70llp instance already loaded. Aborting.\n",
+ DRVNAME);
+ return;
+ }
+
+ /* TODO: this just _assumes_ a lm70 is there ... no probe;
+ * the lm70 driver could verify it, reading the manf ID.
+ */
+
+ master = spi_alloc_master(p->physport->dev, sizeof *pp);
+ if (!master) {
+ status = -ENOMEM;
+ goto out_fail;
+ }
+ pp = spi_master_get_devdata(master);
+
+ master->bus_num = -1; /* dynamic alloc of a bus number */
+ master->num_chipselect = 1;
+
+ /*
+ * SPI and bitbang hookup.
+ */
+ pp->bitbang.master = spi_master_get(master);
+ pp->bitbang.chipselect = lm70_chipselect;
+ pp->bitbang.txrx_word[SPI_MODE_0] = lm70_txrx;
+ pp->bitbang.flags = SPI_3WIRE;
+
+ /*
+ * Parport hookup
+ */
+ pp->port = p;
+ pd = parport_register_device(p, DRVNAME,
+ NULL, NULL, NULL,
+ PARPORT_FLAG_EXCL, pp);
+ if (!pd) {
+ status = -ENOMEM;
+ goto out_free_master;
+ }
+ pp->pd = pd;
+
+ status = parport_claim(pd);
+ if (status < 0)
+ goto out_parport_unreg;
+
+ /*
+ * Start SPI ...
+ */
+ status = spi_bitbang_start(&pp->bitbang);
+ if (status < 0) {
+ printk(KERN_WARNING
+ "%s: spi_bitbang_start failed with status %d\n",
+ DRVNAME, status);
+ goto out_off_and_release;
+ }
+
+ /*
+ * The modalias name MUST match the device_driver name
+ * for the bus glue code to match and subsequently bind them.
+ * We are binding to the generic drivers/hwmon/lm70.c device
+ * driver.
+ */
+ strcpy(pp->info.modalias, "lm70");
+ pp->info.max_speed_hz = 6 * 1000 * 1000;
+ pp->info.chip_select = 0;
+ pp->info.mode = SPI_3WIRE | SPI_MODE_0;
+
+ /* power up the chip, and let the LM70 control SI/SO */
+ parport_write_data(pp->port, lm70_INIT);
+
+ /* Enable access to our primary data structure via
+ * the board info's (void *)controller_data.
+ */
+ pp->info.controller_data = pp;
+ pp->spidev_lm70 = spi_new_device(pp->bitbang.master, &pp->info);
+ if (pp->spidev_lm70)
+ dev_dbg(&pp->spidev_lm70->dev, "spidev_lm70 at %s\n",
+ pp->spidev_lm70->dev.bus_id);
+ else {
+ printk(KERN_WARNING "%s: spi_new_device failed\n", DRVNAME);
+ status = -ENODEV;
+ goto out_bitbang_stop;
+ }
+ pp->spidev_lm70->bits_per_word = 16;
+
+ lm70llp = pp;
+
+ return;
+
+out_bitbang_stop:
+ spi_bitbang_stop(&pp->bitbang);
+out_off_and_release:
+ /* power down */
+ parport_write_data(pp->port, 0);
+ mdelay(10);
+ parport_release(pp->pd);
+out_parport_unreg:
+ parport_unregister_device(pd);
+out_free_master:
+ (void) spi_master_put(master);
+out_fail:
+ pr_info("%s: spi_lm70llp probe fail, status %d\n", DRVNAME, status);
+}
+
+static void spi_lm70llp_detach(struct parport *p)
+{
+ struct spi_lm70llp *pp;
+
+ if (!lm70llp || lm70llp->port != p)
+ return;
+
+ pp = lm70llp;
+ spi_bitbang_stop(&pp->bitbang);
+
+ /* power down */
+ parport_write_data(pp->port, 0);
+ msleep(10);
+
+ parport_release(pp->pd);
+ parport_unregister_device(pp->pd);
+
+ (void) spi_master_put(pp->bitbang.master);
+
+ lm70llp = NULL;
+}
+
+
+static struct parport_driver spi_lm70llp_drv = {
+ .name = DRVNAME,
+ .attach = spi_lm70llp_attach,
+ .detach = spi_lm70llp_detach,
+};
+
+static int __init init_spi_lm70llp(void)
+{
+ return parport_register_driver(&spi_lm70llp_drv);
+}
+module_init(init_spi_lm70llp);
+
+static void __exit cleanup_spi_lm70llp(void)
+{
+ parport_unregister_driver(&spi_lm70llp_drv);
+}
+module_exit(cleanup_spi_lm70llp);
+
+MODULE_AUTHOR("Kaiwan N Billimoria <kaiwan@designergraphix.com>");
+MODULE_DESCRIPTION(
+ "Parport adapter for the National Semiconductor LM70 LLP eval board");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index e9798bf7b8c6..3295cfcc9f20 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -47,6 +47,7 @@ struct mpc83xx_spi_reg {
#define SPMODE_ENABLE (1 << 24)
#define SPMODE_LEN(x) ((x) << 20)
#define SPMODE_PM(x) ((x) << 16)
+#define SPMODE_OP (1 << 14)
/*
* Default for SPI Mode:
@@ -85,6 +86,11 @@ struct mpc83xx_spi {
unsigned nsecs; /* (clock cycle time)/2 */
u32 sysclk;
+ u32 rx_shift; /* RX data reg shift when in qe mode */
+ u32 tx_shift; /* TX data reg shift when in qe mode */
+
+ bool qe_mode;
+
void (*activate_cs) (u8 cs, u8 polarity);
void (*deactivate_cs) (u8 cs, u8 polarity);
};
@@ -103,7 +109,7 @@ static inline u32 mpc83xx_spi_read_reg(__be32 __iomem * reg)
void mpc83xx_spi_rx_buf_##type(u32 data, struct mpc83xx_spi *mpc83xx_spi) \
{ \
type * rx = mpc83xx_spi->rx; \
- *rx++ = (type)data; \
+ *rx++ = (type)(data >> mpc83xx_spi->rx_shift); \
mpc83xx_spi->rx = rx; \
}
@@ -114,7 +120,7 @@ u32 mpc83xx_spi_tx_buf_##type(struct mpc83xx_spi *mpc83xx_spi) \
const type * tx = mpc83xx_spi->tx; \
if (!tx) \
return 0; \
- data = *tx++; \
+ data = *tx++ << mpc83xx_spi->tx_shift; \
mpc83xx_spi->tx = tx; \
return data; \
}
@@ -158,6 +164,12 @@ static void mpc83xx_spi_chipselect(struct spi_device *spi, int value)
if ((mpc83xx_spi->sysclk / spi->max_speed_hz) >= 64) {
u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 64);
+ if (pm > 0x0f) {
+ printk(KERN_WARNING "MPC83xx SPI: SPICLK can't be less then a SYSCLK/1024!\n"
+ "Requested SPICLK is %d Hz. Will use %d Hz instead.\n",
+ spi->max_speed_hz, mpc83xx_spi->sysclk / 1024);
+ pm = 0x0f;
+ }
regval |= SPMODE_PM(pm) | SPMODE_DIV16;
} else {
u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 4);
@@ -197,12 +209,22 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|| ((bits_per_word > 16) && (bits_per_word != 32)))
return -EINVAL;
+ mpc83xx_spi->rx_shift = 0;
+ mpc83xx_spi->tx_shift = 0;
if (bits_per_word <= 8) {
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+ if (mpc83xx_spi->qe_mode) {
+ mpc83xx_spi->rx_shift = 16;
+ mpc83xx_spi->tx_shift = 24;
+ }
} else if (bits_per_word <= 16) {
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u16;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u16;
+ if (mpc83xx_spi->qe_mode) {
+ mpc83xx_spi->rx_shift = 16;
+ mpc83xx_spi->tx_shift = 16;
+ }
} else if (bits_per_word <= 32) {
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u32;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u32;
@@ -232,12 +254,21 @@ int mpc83xx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
static int mpc83xx_spi_setup(struct spi_device *spi)
{
struct spi_bitbang *bitbang;
struct mpc83xx_spi *mpc83xx_spi;
int retval;
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
if (!spi->max_speed_hz)
return -EINVAL;
@@ -371,7 +402,6 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
ret = -ENODEV;
goto free_master;
}
-
mpc83xx_spi = spi_master_get_devdata(master);
mpc83xx_spi->bitbang.master = spi_master_get(master);
mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
@@ -380,9 +410,17 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
mpc83xx_spi->sysclk = pdata->sysclk;
mpc83xx_spi->activate_cs = pdata->activate_cs;
mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
+ mpc83xx_spi->qe_mode = pdata->qe_mode;
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
+ mpc83xx_spi->rx_shift = 0;
+ mpc83xx_spi->tx_shift = 0;
+ if (mpc83xx_spi->qe_mode) {
+ mpc83xx_spi->rx_shift = 16;
+ mpc83xx_spi->tx_shift = 24;
+ }
+
mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup;
init_completion(&mpc83xx_spi->done);
@@ -417,6 +455,9 @@ static int __init mpc83xx_spi_probe(struct platform_device *dev)
/* Enable SPI interface */
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+ if (pdata->qe_mode)
+ regval |= SPMODE_OP;
+
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
ret = spi_bitbang_start(&mpc83xx_spi->bitbang);
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index d5a710f6e445..7071ff8da63e 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -146,6 +146,9 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi,
return 0;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
static int s3c24xx_spi_setup(struct spi_device *spi)
{
int ret;
@@ -153,8 +156,11 @@ static int s3c24xx_spi_setup(struct spi_device *spi)
if (!spi->bits_per_word)
spi->bits_per_word = 8;
- if ((spi->mode & SPI_LSB_FIRST) != 0)
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
return -EINVAL;
+ }
ret = s3c24xx_spi_setupxfer(spi, NULL);
if (ret < 0) {
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c
new file mode 100644
index 000000000000..08e981c40646
--- /dev/null
+++ b/drivers/spi/spi_txx9.c
@@ -0,0 +1,474 @@
+/*
+ * spi_txx9.c - TXx9 SPI controller driver.
+ *
+ * Based on linux/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
+ * Copyright (C) 2000-2001 Toshiba Corporation
+ *
+ * 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)
+ *
+ * Convert to generic SPI framework - Atsushi Nemoto (anemo@mba.ocn.ne.jp)
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <asm/gpio.h>
+
+
+#define SPI_FIFO_SIZE 4
+
+#define TXx9_SPMCR 0x00
+#define TXx9_SPCR0 0x04
+#define TXx9_SPCR1 0x08
+#define TXx9_SPFS 0x0c
+#define TXx9_SPSR 0x14
+#define TXx9_SPDR 0x18
+
+/* SPMCR : SPI Master Control */
+#define TXx9_SPMCR_OPMODE 0xc0
+#define TXx9_SPMCR_CONFIG 0x40
+#define TXx9_SPMCR_ACTIVE 0x80
+#define TXx9_SPMCR_SPSTP 0x02
+#define TXx9_SPMCR_BCLR 0x01
+
+/* SPCR0 : SPI Control 0 */
+#define TXx9_SPCR0_TXIFL_MASK 0xc000
+#define TXx9_SPCR0_RXIFL_MASK 0x3000
+#define TXx9_SPCR0_SIDIE 0x0800
+#define TXx9_SPCR0_SOEIE 0x0400
+#define TXx9_SPCR0_RBSIE 0x0200
+#define TXx9_SPCR0_TBSIE 0x0100
+#define TXx9_SPCR0_IFSPSE 0x0010
+#define TXx9_SPCR0_SBOS 0x0004
+#define TXx9_SPCR0_SPHA 0x0002
+#define TXx9_SPCR0_SPOL 0x0001
+
+/* SPSR : SPI Status */
+#define TXx9_SPSR_TBSI 0x8000
+#define TXx9_SPSR_RBSI 0x4000
+#define TXx9_SPSR_TBS_MASK 0x3800
+#define TXx9_SPSR_RBS_MASK 0x0700
+#define TXx9_SPSR_SPOE 0x0080
+#define TXx9_SPSR_IFSD 0x0008
+#define TXx9_SPSR_SIDLE 0x0004
+#define TXx9_SPSR_STRDY 0x0002
+#define TXx9_SPSR_SRRDY 0x0001
+
+
+struct txx9spi {
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+ spinlock_t lock; /* protect 'queue' */
+ struct list_head queue;
+ wait_queue_head_t waitq;
+ void __iomem *membase;
+ int irq;
+ int baseclk;
+ struct clk *clk;
+ u32 max_speed_hz, min_speed_hz;
+ int last_chipselect;
+ int last_chipselect_val;
+};
+
+static u32 txx9spi_rd(struct txx9spi *c, int reg)
+{
+ return __raw_readl(c->membase + reg);
+}
+static void txx9spi_wr(struct txx9spi *c, u32 val, int reg)
+{
+ __raw_writel(val, c->membase + reg);
+}
+
+static void txx9spi_cs_func(struct spi_device *spi, struct txx9spi *c,
+ int on, unsigned int cs_delay)
+{
+ int val = (spi->mode & SPI_CS_HIGH) ? on : !on;
+ if (on) {
+ /* deselect the chip with cs_change hint in last transfer */
+ if (c->last_chipselect >= 0)
+ gpio_set_value(c->last_chipselect,
+ !c->last_chipselect_val);
+ c->last_chipselect = spi->chip_select;
+ c->last_chipselect_val = val;
+ } else {
+ c->last_chipselect = -1;
+ ndelay(cs_delay); /* CS Hold Time */
+ }
+ gpio_set_value(spi->chip_select, val);
+ ndelay(cs_delay); /* CS Setup Time / CS Recovery Time */
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CS_HIGH|SPI_CPOL|SPI_CPHA)
+
+static int txx9spi_setup(struct spi_device *spi)
+{
+ struct txx9spi *c = spi_master_get_devdata(spi->master);
+ u8 bits_per_word;
+
+ if (spi->mode & ~MODEBITS)
+ return -EINVAL;
+
+ if (!spi->max_speed_hz
+ || spi->max_speed_hz > c->max_speed_hz
+ || spi->max_speed_hz < c->min_speed_hz)
+ return -EINVAL;
+
+ bits_per_word = spi->bits_per_word ? : 8;
+ if (bits_per_word != 8 && bits_per_word != 16)
+ return -EINVAL;
+
+ if (gpio_direction_output(spi->chip_select,
+ !(spi->mode & SPI_CS_HIGH))) {
+ dev_err(&spi->dev, "Cannot setup GPIO for chipselect.\n");
+ return -EINVAL;
+ }
+
+ /* deselect chip */
+ spin_lock(&c->lock);
+ txx9spi_cs_func(spi, c, 0, (NSEC_PER_SEC / 2) / spi->max_speed_hz);
+ spin_unlock(&c->lock);
+
+ return 0;
+}
+
+static irqreturn_t txx9spi_interrupt(int irq, void *dev_id)
+{
+ struct txx9spi *c = dev_id;
+
+ /* disable rx intr */
+ txx9spi_wr(c, txx9spi_rd(c, TXx9_SPCR0) & ~TXx9_SPCR0_RBSIE,
+ TXx9_SPCR0);
+ wake_up(&c->waitq);
+ return IRQ_HANDLED;
+}
+
+static void txx9spi_work_one(struct txx9spi *c, struct spi_message *m)
+{
+ struct spi_device *spi = m->spi;
+ struct spi_transfer *t;
+ unsigned int cs_delay;
+ unsigned int cs_change = 1;
+ int status = 0;
+ u32 mcr;
+ u32 prev_speed_hz = 0;
+ u8 prev_bits_per_word = 0;
+
+ /* CS setup/hold/recovery time in nsec */
+ cs_delay = 100 + (NSEC_PER_SEC / 2) / spi->max_speed_hz;
+
+ mcr = txx9spi_rd(c, TXx9_SPMCR);
+ if (unlikely((mcr & TXx9_SPMCR_OPMODE) == TXx9_SPMCR_ACTIVE)) {
+ dev_err(&spi->dev, "Bad mode.\n");
+ status = -EIO;
+ goto exit;
+ }
+ mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR);
+
+ /* enter config mode */
+ txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
+ txx9spi_wr(c, TXx9_SPCR0_SBOS
+ | ((spi->mode & SPI_CPOL) ? TXx9_SPCR0_SPOL : 0)
+ | ((spi->mode & SPI_CPHA) ? TXx9_SPCR0_SPHA : 0)
+ | 0x08,
+ TXx9_SPCR0);
+
+ list_for_each_entry (t, &m->transfers, transfer_list) {
+ const void *txbuf = t->tx_buf;
+ void *rxbuf = t->rx_buf;
+ u32 data;
+ unsigned int len = t->len;
+ unsigned int wsize;
+ u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
+ u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
+
+ bits_per_word = bits_per_word ? : 8;
+ wsize = bits_per_word >> 3; /* in bytes */
+
+ if (prev_speed_hz != speed_hz
+ || prev_bits_per_word != bits_per_word) {
+ u32 n = (c->baseclk + speed_hz - 1) / speed_hz;
+ if (n < 1)
+ n = 1;
+ else if (n > 0xff)
+ n = 0xff;
+ /* enter config mode */
+ txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR,
+ TXx9_SPMCR);
+ txx9spi_wr(c, (n << 8) | bits_per_word, TXx9_SPCR1);
+ /* enter active mode */
+ txx9spi_wr(c, mcr | TXx9_SPMCR_ACTIVE, TXx9_SPMCR);
+
+ prev_speed_hz = speed_hz;
+ prev_bits_per_word = bits_per_word;
+ }
+
+ if (cs_change)
+ txx9spi_cs_func(spi, c, 1, cs_delay);
+ cs_change = t->cs_change;
+ while (len) {
+ unsigned int count = SPI_FIFO_SIZE;
+ int i;
+ u32 cr0;
+
+ if (len < count * wsize)
+ count = len / wsize;
+ /* now tx must be idle... */
+ while (!(txx9spi_rd(c, TXx9_SPSR) & TXx9_SPSR_SIDLE))
+ cpu_relax();
+ cr0 = txx9spi_rd(c, TXx9_SPCR0);
+ cr0 &= ~TXx9_SPCR0_RXIFL_MASK;
+ cr0 |= (count - 1) << 12;
+ /* enable rx intr */
+ cr0 |= TXx9_SPCR0_RBSIE;
+ txx9spi_wr(c, cr0, TXx9_SPCR0);
+ /* send */
+ for (i = 0; i < count; i++) {
+ if (txbuf) {
+ data = (wsize == 1)
+ ? *(const u8 *)txbuf
+ : *(const u16 *)txbuf;
+ txx9spi_wr(c, data, TXx9_SPDR);
+ txbuf += wsize;
+ } else
+ txx9spi_wr(c, 0, TXx9_SPDR);
+ }
+ /* wait all rx data */
+ wait_event(c->waitq,
+ txx9spi_rd(c, TXx9_SPSR) & TXx9_SPSR_RBSI);
+ /* receive */
+ for (i = 0; i < count; i++) {
+ data = txx9spi_rd(c, TXx9_SPDR);
+ if (rxbuf) {
+ if (wsize == 1)
+ *(u8 *)rxbuf = data;
+ else
+ *(u16 *)rxbuf = data;
+ rxbuf += wsize;
+ }
+ }
+ len -= count * wsize;
+ }
+ m->actual_length += t->len;
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (!cs_change)
+ continue;
+ if (t->transfer_list.next == &m->transfers)
+ break;
+ /* sometimes a short mid-message deselect of the chip
+ * may be needed to terminate a mode or command
+ */
+ txx9spi_cs_func(spi, c, 0, cs_delay);
+ }
+
+exit:
+ m->status = status;
+ m->complete(m->context);
+
+ /* normally deactivate chipselect ... unless no error and
+ * cs_change has hinted that the next message will probably
+ * be for this chip too.
+ */
+ if (!(status == 0 && cs_change))
+ txx9spi_cs_func(spi, c, 0, cs_delay);
+
+ /* enter config mode */
+ txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
+}
+
+static void txx9spi_work(struct work_struct *work)
+{
+ struct txx9spi *c = container_of(work, struct txx9spi, work);
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->lock, flags);
+ while (!list_empty(&c->queue)) {
+ struct spi_message *m;
+
+ m = container_of(c->queue.next, struct spi_message, queue);
+ list_del_init(&m->queue);
+ spin_unlock_irqrestore(&c->lock, flags);
+
+ txx9spi_work_one(c, m);
+
+ spin_lock_irqsave(&c->lock, flags);
+ }
+ spin_unlock_irqrestore(&c->lock, flags);
+}
+
+static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct spi_master *master = spi->master;
+ struct txx9spi *c = spi_master_get_devdata(master);
+ struct spi_transfer *t;
+ unsigned long flags;
+
+ m->actual_length = 0;
+
+ /* check each transfer's parameters */
+ list_for_each_entry (t, &m->transfers, transfer_list) {
+ u32 speed_hz = t->speed_hz ? : spi->max_speed_hz;
+ u8 bits_per_word = t->bits_per_word ? : spi->bits_per_word;
+
+ bits_per_word = bits_per_word ? : 8;
+ if (!t->tx_buf && !t->rx_buf && t->len)
+ return -EINVAL;
+ if (bits_per_word != 8 && bits_per_word != 16)
+ return -EINVAL;
+ if (t->len & ((bits_per_word >> 3) - 1))
+ return -EINVAL;
+ if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz)
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&c->lock, flags);
+ list_add_tail(&m->queue, &c->queue);
+ queue_work(c->workqueue, &c->work);
+ spin_unlock_irqrestore(&c->lock, flags);
+
+ return 0;
+}
+
+static int __init txx9spi_probe(struct platform_device *dev)
+{
+ struct spi_master *master;
+ struct txx9spi *c;
+ struct resource *res;
+ int ret = -ENODEV;
+ u32 mcr;
+
+ master = spi_alloc_master(&dev->dev, sizeof(*c));
+ if (!master)
+ return ret;
+ c = spi_master_get_devdata(master);
+ c->irq = -1;
+ platform_set_drvdata(dev, master);
+
+ INIT_WORK(&c->work, txx9spi_work);
+ spin_lock_init(&c->lock);
+ INIT_LIST_HEAD(&c->queue);
+ init_waitqueue_head(&c->waitq);
+
+ c->clk = clk_get(&dev->dev, "spi-baseclk");
+ if (IS_ERR(c->clk)) {
+ ret = PTR_ERR(c->clk);
+ c->clk = NULL;
+ goto exit;
+ }
+ ret = clk_enable(c->clk);
+ if (ret) {
+ clk_put(c->clk);
+ c->clk = NULL;
+ goto exit;
+ }
+ c->baseclk = clk_get_rate(c->clk);
+ c->min_speed_hz = (c->baseclk + 0xff - 1) / 0xff;
+ c->max_speed_hz = c->baseclk;
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ goto exit;
+ c->membase = ioremap(res->start, res->end - res->start + 1);
+ if (!c->membase)
+ goto exit;
+
+ /* enter config mode */
+ mcr = txx9spi_rd(c, TXx9_SPMCR);
+ mcr &= ~(TXx9_SPMCR_OPMODE | TXx9_SPMCR_SPSTP | TXx9_SPMCR_BCLR);
+ txx9spi_wr(c, mcr | TXx9_SPMCR_CONFIG | TXx9_SPMCR_BCLR, TXx9_SPMCR);
+
+ c->irq = platform_get_irq(dev, 0);
+ if (c->irq < 0)
+ goto exit;
+ ret = request_irq(c->irq, txx9spi_interrupt, 0, dev->name, c);
+ if (ret) {
+ c->irq = -1;
+ goto exit;
+ }
+
+ c->workqueue = create_singlethread_workqueue(master->cdev.dev->bus_id);
+ if (!c->workqueue)
+ goto exit;
+ c->last_chipselect = -1;
+
+ dev_info(&dev->dev, "at %#llx, irq %d, %dMHz\n",
+ (unsigned long long)res->start, c->irq,
+ (c->baseclk + 500000) / 1000000);
+
+ master->bus_num = dev->id;
+ master->setup = txx9spi_setup;
+ master->transfer = txx9spi_transfer;
+ master->num_chipselect = (u16)UINT_MAX; /* any GPIO numbers */
+
+ ret = spi_register_master(master);
+ if (ret)
+ goto exit;
+ return 0;
+exit:
+ if (c->workqueue)
+ destroy_workqueue(c->workqueue);
+ if (c->irq >= 0)
+ free_irq(c->irq, c);
+ if (c->membase)
+ iounmap(c->membase);
+ if (c->clk) {
+ clk_disable(c->clk);
+ clk_put(c->clk);
+ }
+ platform_set_drvdata(dev, NULL);
+ spi_master_put(master);
+ return ret;
+}
+
+static int __exit txx9spi_remove(struct platform_device *dev)
+{
+ struct spi_master *master = spi_master_get(platform_get_drvdata(dev));
+ struct txx9spi *c = spi_master_get_devdata(master);
+
+ spi_unregister_master(master);
+ platform_set_drvdata(dev, NULL);
+ destroy_workqueue(c->workqueue);
+ free_irq(c->irq, c);
+ iounmap(c->membase);
+ clk_disable(c->clk);
+ clk_put(c->clk);
+ spi_master_put(master);
+ return 0;
+}
+
+static struct platform_driver txx9spi_driver = {
+ .remove = __exit_p(txx9spi_remove),
+ .driver = {
+ .name = "txx9spi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init txx9spi_init(void)
+{
+ return platform_driver_probe(&txx9spi_driver, txx9spi_probe);
+}
+subsys_initcall(txx9spi_init);
+
+static void __exit txx9spi_exit(void)
+{
+ platform_driver_unregister(&txx9spi_driver);
+}
+module_exit(txx9spi_exit);
+
+MODULE_DESCRIPTION("TXx9 SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index d04242aee40d..38b60ad0eda0 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -181,7 +181,8 @@ static int spidev_message(struct spidev_data *spidev,
}
if (u_tmp->tx_buf) {
k_tmp->tx_buf = buf;
- if (copy_from_user(buf, (const u8 __user *)u_tmp->tx_buf,
+ if (copy_from_user(buf, (const u8 __user *)
+ (ptrdiff_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
}
@@ -213,7 +214,8 @@ static int spidev_message(struct spidev_data *spidev,
buf = spidev->buffer;
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->rx_buf) {
- if (__copy_to_user((u8 __user *)u_tmp->rx_buf, buf,
+ if (__copy_to_user((u8 __user *)
+ (ptrdiff_t) u_tmp->rx_buf, buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
diff --git a/drivers/spi/tle62x0.c b/drivers/spi/tle62x0.c
new file mode 100644
index 000000000000..6da58ca48b33
--- /dev/null
+++ b/drivers/spi/tle62x0.c
@@ -0,0 +1,328 @@
+/*
+ * tle62x0.c -- support Infineon TLE62x0 driver chips
+ *
+ * Copyright (c) 2007 Simtec Electronics
+ * Ben Dooks, <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/tle62x0.h>
+
+
+#define CMD_READ 0x00
+#define CMD_SET 0xff
+
+#define DIAG_NORMAL 0x03
+#define DIAG_OVERLOAD 0x02
+#define DIAG_OPEN 0x01
+#define DIAG_SHORTGND 0x00
+
+struct tle62x0_state {
+ struct spi_device *us;
+ struct mutex lock;
+ unsigned int nr_gpio;
+ unsigned int gpio_state;
+
+ unsigned char tx_buff[4];
+ unsigned char rx_buff[4];
+};
+
+static int to_gpio_num(struct device_attribute *attr);
+
+static inline int tle62x0_write(struct tle62x0_state *st)
+{
+ unsigned char *buff = st->tx_buff;
+ unsigned int gpio_state = st->gpio_state;
+
+ buff[0] = CMD_SET;
+
+ if (st->nr_gpio == 16) {
+ buff[1] = gpio_state >> 8;
+ buff[2] = gpio_state;
+ } else {
+ buff[1] = gpio_state;
+ }
+
+ dev_dbg(&st->us->dev, "buff %02x,%02x,%02x\n",
+ buff[0], buff[1], buff[2]);
+
+ return spi_write(st->us, buff, (st->nr_gpio == 16) ? 3 : 2);
+}
+
+static inline int tle62x0_read(struct tle62x0_state *st)
+{
+ unsigned char *txbuff = st->tx_buff;
+ struct spi_transfer xfer = {
+ .tx_buf = txbuff,
+ .rx_buf = st->rx_buff,
+ .len = (st->nr_gpio * 2) / 8,
+ };
+ struct spi_message msg;
+
+ txbuff[0] = CMD_READ;
+ txbuff[1] = 0x00;
+ txbuff[2] = 0x00;
+ txbuff[3] = 0x00;
+
+ spi_message_init(&msg);
+ spi_message_add_tail(&xfer, &msg);
+
+ return spi_sync(st->us, &msg);
+}
+
+static unsigned char *decode_fault(unsigned int fault_code)
+{
+ fault_code &= 3;
+
+ switch (fault_code) {
+ case DIAG_NORMAL:
+ return "N";
+ case DIAG_OVERLOAD:
+ return "V";
+ case DIAG_OPEN:
+ return "O";
+ case DIAG_SHORTGND:
+ return "G";
+ }
+
+ return "?";
+}
+
+static ssize_t tle62x0_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tle62x0_state *st = dev_get_drvdata(dev);
+ char *bp = buf;
+ unsigned char *buff = st->rx_buff;
+ unsigned long fault = 0;
+ int ptr;
+ int ret;
+
+ mutex_lock(&st->lock);
+ ret = tle62x0_read(st);
+
+ dev_dbg(dev, "tle62x0_read() returned %d\n", ret);
+
+ for (ptr = 0; ptr < (st->nr_gpio * 2)/8; ptr += 1) {
+ fault <<= 8;
+ fault |= ((unsigned long)buff[ptr]);
+
+ dev_dbg(dev, "byte %d is %02x\n", ptr, buff[ptr]);
+ }
+
+ for (ptr = 0; ptr < st->nr_gpio; ptr++) {
+ bp += sprintf(bp, "%s ", decode_fault(fault >> (ptr * 2)));
+ }
+
+ *bp++ = '\n';
+
+ mutex_unlock(&st->lock);
+ return bp - buf;
+}
+
+static DEVICE_ATTR(status_show, S_IRUGO, tle62x0_status_show, NULL);
+
+static ssize_t tle62x0_gpio_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tle62x0_state *st = dev_get_drvdata(dev);
+ int gpio_num = to_gpio_num(attr);
+ int value;
+
+ mutex_lock(&st->lock);
+ value = (st->gpio_state >> gpio_num) & 1;
+ mutex_unlock(&st->lock);
+
+ return snprintf(buf, PAGE_SIZE, "%d", value);
+}
+
+static ssize_t tle62x0_gpio_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct tle62x0_state *st = dev_get_drvdata(dev);
+ int gpio_num = to_gpio_num(attr);
+ unsigned long val;
+ char *endp;
+
+ val = simple_strtoul(buf, &endp, 0);
+ if (buf == endp)
+ return -EINVAL;
+
+ dev_dbg(dev, "setting gpio %d to %ld\n", gpio_num, val);
+
+ mutex_lock(&st->lock);
+
+ if (val)
+ st->gpio_state |= 1 << gpio_num;
+ else
+ st->gpio_state &= ~(1 << gpio_num);
+
+ tle62x0_write(st);
+ mutex_unlock(&st->lock);
+
+ return len;
+}
+
+static DEVICE_ATTR(gpio1, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio2, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio3, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio4, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio5, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio6, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio7, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio8, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio9, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio10, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio11, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio12, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio13, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio14, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio15, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+static DEVICE_ATTR(gpio16, S_IWUSR|S_IRUGO,
+ tle62x0_gpio_show, tle62x0_gpio_store);
+
+static struct device_attribute *gpio_attrs[] = {
+ [0] = &dev_attr_gpio1,
+ [1] = &dev_attr_gpio2,
+ [2] = &dev_attr_gpio3,
+ [3] = &dev_attr_gpio4,
+ [4] = &dev_attr_gpio5,
+ [5] = &dev_attr_gpio6,
+ [6] = &dev_attr_gpio7,
+ [7] = &dev_attr_gpio8,
+ [8] = &dev_attr_gpio9,
+ [9] = &dev_attr_gpio10,
+ [10] = &dev_attr_gpio11,
+ [11] = &dev_attr_gpio12,
+ [12] = &dev_attr_gpio13,
+ [13] = &dev_attr_gpio14,
+ [14] = &dev_attr_gpio15,
+ [15] = &dev_attr_gpio16
+};
+
+static int to_gpio_num(struct device_attribute *attr)
+{
+ int ptr;
+
+ for (ptr = 0; ptr < ARRAY_SIZE(gpio_attrs); ptr++) {
+ if (gpio_attrs[ptr] == attr)
+ return ptr;
+ }
+
+ return -1;
+}
+
+static int __devinit tle62x0_probe(struct spi_device *spi)
+{
+ struct tle62x0_state *st;
+ struct tle62x0_pdata *pdata;
+ int ptr;
+ int ret;
+
+ pdata = spi->dev.platform_data;
+ if (pdata == NULL) {
+ dev_err(&spi->dev, "no device data specified\n");
+ return -EINVAL;
+ }
+
+ st = kzalloc(sizeof(struct tle62x0_state), GFP_KERNEL);
+ if (st == NULL) {
+ dev_err(&spi->dev, "no memory for device state\n");
+ return -ENOMEM;
+ }
+
+ st->us = spi;
+ st->nr_gpio = pdata->gpio_count;
+ st->gpio_state = pdata->init_state;
+
+ mutex_init(&st->lock);
+
+ ret = device_create_file(&spi->dev, &dev_attr_status_show);
+ if (ret) {
+ dev_err(&spi->dev, "cannot create status attribute\n");
+ goto err_status;
+ }
+
+ for (ptr = 0; ptr < pdata->gpio_count; ptr++) {
+ ret = device_create_file(&spi->dev, gpio_attrs[ptr]);
+ if (ret) {
+ dev_err(&spi->dev, "cannot create gpio attribute\n");
+ goto err_gpios;
+ }
+ }
+
+ /* tle62x0_write(st); */
+ spi_set_drvdata(spi, st);
+ return 0;
+
+ err_gpios:
+ for (; ptr > 0; ptr--)
+ device_remove_file(&spi->dev, gpio_attrs[ptr]);
+
+ device_remove_file(&spi->dev, &dev_attr_status_show);
+
+ err_status:
+ kfree(st);
+ return ret;
+}
+
+static int __devexit tle62x0_remove(struct spi_device *spi)
+{
+ struct tle62x0_state *st = spi_get_drvdata(spi);
+ int ptr;
+
+ for (ptr = 0; ptr < st->nr_gpio; ptr++)
+ device_remove_file(&spi->dev, gpio_attrs[ptr]);
+
+ kfree(st);
+ return 0;
+}
+
+static struct spi_driver tle62x0_driver = {
+ .driver = {
+ .name = "tle62x0",
+ .owner = THIS_MODULE,
+ },
+ .probe = tle62x0_probe,
+ .remove = __devexit_p(tle62x0_remove),
+};
+
+static __init int tle62x0_init(void)
+{
+ return spi_register_driver(&tle62x0_driver);
+}
+
+static __exit void tle62x0_exit(void)
+{
+ spi_unregister_driver(&tle62x0_driver);
+}
+
+module_init(tle62x0_init);
+module_exit(tle62x0_exit);
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("TLE62x0 SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
new file mode 100644
index 000000000000..f0bf9a68e96b
--- /dev/null
+++ b/drivers/spi/xilinx_spi.c
@@ -0,0 +1,434 @@
+/*
+ * xilinx_spi.c
+ *
+ * Xilinx SPI controller driver (master mode only)
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2002-2007 (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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/io.h>
+
+#include <syslib/virtex_devices.h>
+
+#define XILINX_SPI_NAME "xspi"
+
+/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
+ * Product Specification", DS464
+ */
+#define XSPI_CR_OFFSET 0x62 /* 16-bit Control Register */
+
+#define XSPI_CR_ENABLE 0x02
+#define XSPI_CR_MASTER_MODE 0x04
+#define XSPI_CR_CPOL 0x08
+#define XSPI_CR_CPHA 0x10
+#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL)
+#define XSPI_CR_TXFIFO_RESET 0x20
+#define XSPI_CR_RXFIFO_RESET 0x40
+#define XSPI_CR_MANUAL_SSELECT 0x80
+#define XSPI_CR_TRANS_INHIBIT 0x100
+
+#define XSPI_SR_OFFSET 0x67 /* 8-bit Status Register */
+
+#define XSPI_SR_RX_EMPTY_MASK 0x01 /* Receive FIFO is empty */
+#define XSPI_SR_RX_FULL_MASK 0x02 /* Receive FIFO is full */
+#define XSPI_SR_TX_EMPTY_MASK 0x04 /* Transmit FIFO is empty */
+#define XSPI_SR_TX_FULL_MASK 0x08 /* Transmit FIFO is full */
+#define XSPI_SR_MODE_FAULT_MASK 0x10 /* Mode fault error */
+
+#define XSPI_TXD_OFFSET 0x6b /* 8-bit Data Transmit Register */
+#define XSPI_RXD_OFFSET 0x6f /* 8-bit Data Receive Register */
+
+#define XSPI_SSR_OFFSET 0x70 /* 32-bit Slave Select Register */
+
+/* Register definitions as per "OPB IPIF (v3.01c) Product Specification", DS414
+ * IPIF registers are 32 bit
+ */
+#define XIPIF_V123B_DGIER_OFFSET 0x1c /* IPIF global int enable reg */
+#define XIPIF_V123B_GINTR_ENABLE 0x80000000
+
+#define XIPIF_V123B_IISR_OFFSET 0x20 /* IPIF interrupt status reg */
+#define XIPIF_V123B_IIER_OFFSET 0x28 /* IPIF interrupt enable reg */
+
+#define XSPI_INTR_MODE_FAULT 0x01 /* Mode fault error */
+#define XSPI_INTR_SLAVE_MODE_FAULT 0x02 /* Selected as slave while
+ * disabled */
+#define XSPI_INTR_TX_EMPTY 0x04 /* TxFIFO is empty */
+#define XSPI_INTR_TX_UNDERRUN 0x08 /* TxFIFO was underrun */
+#define XSPI_INTR_RX_FULL 0x10 /* RxFIFO is full */
+#define XSPI_INTR_RX_OVERRUN 0x20 /* RxFIFO was overrun */
+
+#define XIPIF_V123B_RESETR_OFFSET 0x40 /* IPIF reset register */
+#define XIPIF_V123B_RESET_MASK 0x0a /* the value to write */
+
+struct xilinx_spi {
+ /* bitbang has to be first */
+ struct spi_bitbang bitbang;
+ struct completion done;
+
+ void __iomem *regs; /* virt. address of the control registers */
+
+ u32 irq;
+
+ u32 speed_hz; /* SCK has a fixed frequency of speed_hz Hz */
+
+ u8 *rx_ptr; /* pointer in the Tx buffer */
+ const u8 *tx_ptr; /* pointer in the Rx buffer */
+ int remaining_bytes; /* the number of bytes left to transfer */
+};
+
+static void xspi_init_hw(void __iomem *regs_base)
+{
+ /* Reset the SPI device */
+ out_be32(regs_base + XIPIF_V123B_RESETR_OFFSET,
+ XIPIF_V123B_RESET_MASK);
+ /* Disable all the interrupts just in case */
+ out_be32(regs_base + XIPIF_V123B_IIER_OFFSET, 0);
+ /* Enable the global IPIF interrupt */
+ out_be32(regs_base + XIPIF_V123B_DGIER_OFFSET,
+ XIPIF_V123B_GINTR_ENABLE);
+ /* Deselect the slave on the SPI bus */
+ out_be32(regs_base + XSPI_SSR_OFFSET, 0xffff);
+ /* Disable the transmitter, enable Manual Slave Select Assertion,
+ * put SPI controller into master mode, and enable it */
+ out_be16(regs_base + XSPI_CR_OFFSET,
+ XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT
+ | XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE);
+}
+
+static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
+{
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+
+ if (is_on == BITBANG_CS_INACTIVE) {
+ /* Deselect the slave on the SPI bus */
+ out_be32(xspi->regs + XSPI_SSR_OFFSET, 0xffff);
+ } else if (is_on == BITBANG_CS_ACTIVE) {
+ /* Set the SPI clock phase and polarity */
+ u16 cr = in_be16(xspi->regs + XSPI_CR_OFFSET)
+ & ~XSPI_CR_MODE_MASK;
+ if (spi->mode & SPI_CPHA)
+ cr |= XSPI_CR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ cr |= XSPI_CR_CPOL;
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+
+ /* We do not check spi->max_speed_hz here as the SPI clock
+ * frequency is not software programmable (the IP block design
+ * parameter)
+ */
+
+ /* Activate the chip select */
+ out_be32(xspi->regs + XSPI_SSR_OFFSET,
+ ~(0x0001 << spi->chip_select));
+ }
+}
+
+/* spi_bitbang requires custom setup_transfer() to be defined if there is a
+ * custom txrx_bufs(). We have nothing to setup here as the SPI IP block
+ * supports just 8 bits per word, and SPI clock can't be changed in software.
+ * Check for 8 bits per word. Chip select delay calculations could be
+ * added here as soon as bitbang_work() can be made aware of the delay value.
+ */
+static int xilinx_spi_setup_transfer(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ u8 bits_per_word;
+ u32 hz;
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+
+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
+ 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);
+ return -EINVAL;
+ }
+
+ if (hz && xspi->speed_hz > hz) {
+ dev_err(&spi->dev, "%s, unsupported clock rate %uHz\n",
+ __FUNCTION__, hz);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA)
+
+static int xilinx_spi_setup(struct spi_device *spi)
+{
+ struct spi_bitbang *bitbang;
+ struct xilinx_spi *xspi;
+ int retval;
+
+ xspi = spi_master_get_devdata(spi->master);
+ bitbang = &xspi->bitbang;
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ if (spi->mode & ~MODEBITS) {
+ dev_err(&spi->dev, "%s, unsupported mode bits %x\n",
+ __FUNCTION__, spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
+ retval = xilinx_spi_setup_transfer(spi, NULL);
+ if (retval < 0)
+ 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);
+
+ return 0;
+}
+
+static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
+{
+ u8 sr;
+
+ /* Fill the Tx FIFO with as many bytes as possible */
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
+ if (xspi->tx_ptr) {
+ out_8(xspi->regs + XSPI_TXD_OFFSET, *xspi->tx_ptr++);
+ } else {
+ out_8(xspi->regs + XSPI_TXD_OFFSET, 0);
+ }
+ xspi->remaining_bytes--;
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ }
+}
+
+static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+ u32 ipif_ier;
+ u16 cr;
+
+ /* We get here with transmitter inhibited */
+
+ xspi->tx_ptr = t->tx_buf;
+ xspi->rx_ptr = t->rx_buf;
+ xspi->remaining_bytes = t->len;
+ INIT_COMPLETION(xspi->done);
+
+ xilinx_spi_fill_tx_fifo(xspi);
+
+ /* Enable the transmit empty interrupt, which we use to determine
+ * progress on the transmission.
+ */
+ ipif_ier = in_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET);
+ out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET,
+ ipif_ier | XSPI_INTR_TX_EMPTY);
+
+ /* Start the transfer by not inhibiting the transmitter any longer */
+ cr = in_be16(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_TRANS_INHIBIT;
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+
+ wait_for_completion(&xspi->done);
+
+ /* Disable the transmit empty interrupt */
+ out_be32(xspi->regs + XIPIF_V123B_IIER_OFFSET, ipif_ier);
+
+ return t->len - xspi->remaining_bytes;
+}
+
+
+/* This driver supports single master mode only. Hence Tx FIFO Empty
+ * is the only interrupt we care about.
+ * Receive FIFO Overrun, Transmit FIFO Underrun, Mode Fault, and Slave Mode
+ * Fault are not to happen.
+ */
+static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
+{
+ struct xilinx_spi *xspi = dev_id;
+ u32 ipif_isr;
+
+ /* Get the IPIF interrupts, and clear them immediately */
+ ipif_isr = in_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ out_be32(xspi->regs + XIPIF_V123B_IISR_OFFSET, ipif_isr);
+
+ if (ipif_isr & XSPI_INTR_TX_EMPTY) { /* Transmission completed */
+ u16 cr;
+ u8 sr;
+
+ /* A transmit has just completed. Process received data and
+ * check for more data to transmit. Always inhibit the
+ * transmitter while the Isr refills the transmit register/FIFO,
+ * or make sure it is stopped if we're done.
+ */
+ cr = in_be16(xspi->regs + XSPI_CR_OFFSET);
+ out_be16(xspi->regs + XSPI_CR_OFFSET,
+ cr | XSPI_CR_TRANS_INHIBIT);
+
+ /* Read out all the data from the Rx FIFO */
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
+ u8 data;
+
+ data = in_8(xspi->regs + XSPI_RXD_OFFSET);
+ if (xspi->rx_ptr) {
+ *xspi->rx_ptr++ = data;
+ }
+ sr = in_8(xspi->regs + XSPI_SR_OFFSET);
+ }
+
+ /* See if there is more data to send */
+ if (xspi->remaining_bytes > 0) {
+ xilinx_spi_fill_tx_fifo(xspi);
+ /* Start the transfer by not inhibiting the
+ * transmitter any longer
+ */
+ out_be16(xspi->regs + XSPI_CR_OFFSET, cr);
+ } else {
+ /* No more data to send.
+ * Indicate the transfer is completed.
+ */
+ complete(&xspi->done);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int __init xilinx_spi_probe(struct platform_device *dev)
+{
+ int ret = 0;
+ struct spi_master *master;
+ struct xilinx_spi *xspi;
+ struct xspi_platform_data *pdata;
+ struct resource *r;
+
+ /* Get resources(memory, IRQ) associated with the device */
+ master = spi_alloc_master(&dev->dev, sizeof(struct xilinx_spi));
+
+ if (master == NULL) {
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(dev, master);
+ pdata = dev->dev.platform_data;
+
+ if (pdata == NULL) {
+ ret = -ENODEV;
+ goto put_master;
+ }
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENODEV;
+ goto put_master;
+ }
+
+ xspi = spi_master_get_devdata(master);
+ xspi->bitbang.master = spi_master_get(master);
+ xspi->bitbang.chipselect = xilinx_spi_chipselect;
+ xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
+ xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs;
+ xspi->bitbang.master->setup = xilinx_spi_setup;
+ init_completion(&xspi->done);
+
+ if (!request_mem_region(r->start,
+ r->end - r->start + 1, XILINX_SPI_NAME)) {
+ ret = -ENXIO;
+ goto put_master;
+ }
+
+ xspi->regs = ioremap(r->start, r->end - r->start + 1);
+ if (xspi->regs == NULL) {
+ ret = -ENOMEM;
+ goto put_master;
+ }
+
+ xspi->irq = platform_get_irq(dev, 0);
+ if (xspi->irq < 0) {
+ ret = -ENXIO;
+ goto unmap_io;
+ }
+
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->num_chipselect;
+ xspi->speed_hz = pdata->speed_hz;
+
+ /* SPI controller initializations */
+ xspi_init_hw(xspi->regs);
+
+ /* Register for SPI Interrupt */
+ ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi);
+ if (ret != 0)
+ goto unmap_io;
+
+ ret = spi_bitbang_start(&xspi->bitbang);
+ if (ret != 0) {
+ dev_err(&dev->dev, "spi_bitbang_start FAILED\n");
+ goto free_irq;
+ }
+
+ dev_info(&dev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n",
+ r->start, (u32)xspi->regs, xspi->irq);
+
+ return ret;
+
+free_irq:
+ free_irq(xspi->irq, xspi);
+unmap_io:
+ iounmap(xspi->regs);
+put_master:
+ spi_master_put(master);
+ return ret;
+}
+
+static int __devexit xilinx_spi_remove(struct platform_device *dev)
+{
+ struct xilinx_spi *xspi;
+ struct spi_master *master;
+
+ master = platform_get_drvdata(dev);
+ xspi = spi_master_get_devdata(master);
+
+ spi_bitbang_stop(&xspi->bitbang);
+ free_irq(xspi->irq, xspi);
+ iounmap(xspi->regs);
+ platform_set_drvdata(dev, 0);
+ spi_master_put(xspi->bitbang.master);
+
+ return 0;
+}
+
+static struct platform_driver xilinx_spi_driver = {
+ .probe = xilinx_spi_probe,
+ .remove = __devexit_p(xilinx_spi_remove),
+ .driver = {
+ .name = XILINX_SPI_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init xilinx_spi_init(void)
+{
+ return platform_driver_register(&xilinx_spi_driver);
+}
+module_init(xilinx_spi_init);
+
+static void __exit xilinx_spi_exit(void)
+{
+ platform_driver_unregister(&xilinx_spi_driver);
+}
+module_exit(xilinx_spi_exit);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("Xilinx SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 967342692211..c899246bd362 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -5,7 +5,6 @@
# Object file lists.
obj-$(CONFIG_TC) += tc.o tc-driver.o
-obj-$(CONFIG_ZS) += zs.o
obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
$(obj)/lk201-map.o: $(obj)/lk201-map.c
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
deleted file mode 100644
index 4fff61b32dcb..000000000000
--- a/drivers/tc/zs.c
+++ /dev/null
@@ -1,2203 +0,0 @@
-/*
- * decserial.c: Serial port driver for IOASIC DECstations.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
- *
- * DECstation changes
- * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Maciej W. Rozycki
- *
- * For the rest of the code the original Copyright applies:
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- *
- * Note: for IOASIC systems the wiring is as follows:
- *
- * mouse/keyboard:
- * DIN-7 MJ-4 signal SCC
- * 2 1 TxD <- A.TxD
- * 3 4 RxD -> A.RxD
- *
- * EIA-232/EIA-423:
- * DB-25 MMJ-6 signal SCC
- * 2 2 TxD <- B.TxD
- * 3 5 RxD -> B.RxD
- * 4 RTS <- ~A.RTS
- * 5 CTS -> ~B.CTS
- * 6 6 DSR -> ~A.SYNC
- * 8 CD -> ~B.DCD
- * 12 DSRS(DCE) -> ~A.CTS (*)
- * 15 TxC -> B.TxC
- * 17 RxC -> B.RxC
- * 20 1 DTR <- ~A.DTR
- * 22 RI -> ~A.DCD
- * 23 DSRS(DTE) <- ~B.RTS
- *
- * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
- * is shared with DSRS(DTE) at pin 23.
- */
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-#include <linux/console.h>
-#endif
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/serial.h>
-#include <asm/dec/system.h>
-
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#ifdef CONFIG_MAGIC_SYSRQ
-#include <linux/sysrq.h>
-#endif
-
-#include "zs.h"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL 2 /* Max number of ZS chips supported */
-#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
-#define CHANNEL_A_NR (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
- /* Number of channel A in the chip */
-#define ZS_CHAN_IO_SIZE 8
-#define ZS_CLOCK 7372800 /* Z8530 RTxC input clock rate */
-
-#define RECOVERY_DELAY udelay(2)
-
-struct zs_parms {
- unsigned long scc0;
- unsigned long scc1;
- int channel_a_offset;
- int channel_b_offset;
- int irq0;
- int irq1;
- int clock;
-};
-
-static struct zs_parms *zs_parms;
-
-#ifdef CONFIG_MACH_DECSTATION
-static struct zs_parms ds_parms = {
- scc0 : IOASIC_SCC0,
- scc1 : IOASIC_SCC1,
- channel_a_offset : 1,
- channel_b_offset : 9,
- irq0 : -1,
- irq1 : -1,
- clock : ZS_CLOCK
-};
-#endif
-
-#ifdef CONFIG_MACH_DECSTATION
-#define DS_BUS_PRESENT (IOASIC)
-#else
-#define DS_BUS_PRESENT 0
-#endif
-
-#define BUS_PRESENT (DS_BUS_PRESENT)
-
-DEFINE_SPINLOCK(zs_lock);
-
-struct dec_zschannel zs_channels[NUM_CHANNELS];
-struct dec_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct dec_serial *zs_chain; /* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-static struct console sercons;
-#endif
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
- !defined(MODULE)
-static unsigned long break_pressed; /* break, really ... */
-#endif
-
-static unsigned char zs_init_regs[16] = {
- 0, /* write 0 */
- 0, /* write 1 */
- 0, /* write 2 */
- 0, /* write 3 */
- (X16CLK), /* write 4 */
- 0, /* write 5 */
- 0, 0, 0, /* write 6, 7, 8 */
- (MIE | DLC | NV), /* write 9 */
- (NRZ), /* write 10 */
- (TCBR | RCBR), /* write 11 */
- 0, 0, /* BRG time constant, write 12 + 13 */
- (BRSRC | BRENABL), /* write 14 */
- 0 /* write 15 */
-};
-
-static struct tty_driver *serial_driver;
-
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL 1
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * Debugging.
- */
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_PARANOIA_CHECK
-
-#undef ZS_DEBUG_REGS
-
-#ifdef SERIAL_DEBUG_THROTTLE
-#define _tty_name(tty,buf) tty_name(tty,buf)
-#endif
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-static void probe_sccs(void);
-static void change_speed(struct dec_serial *info);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(struct dec_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char *badmagic =
- "Warning: bad magic number for serial struct %s in %s\n";
- static const char *badinfo =
- "Warning: null mac_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0 };
-
-/*
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char read_zsreg(struct dec_zschannel *channel,
- unsigned char reg)
-{
- unsigned char retval;
-
- if (reg != 0) {
- *channel->control = reg & 0xf;
- fast_iob(); RECOVERY_DELAY;
- }
- retval = *channel->control;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsreg(struct dec_zschannel *channel,
- unsigned char reg, unsigned char value)
-{
- if (reg != 0) {
- *channel->control = reg & 0xf;
- fast_iob(); RECOVERY_DELAY;
- }
- *channel->control = value;
- fast_iob(); RECOVERY_DELAY;
- return;
-}
-
-static inline unsigned char read_zsdata(struct dec_zschannel *channel)
-{
- unsigned char retval;
-
- retval = *channel->data;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsdata(struct dec_zschannel *channel,
- unsigned char value)
-{
- *channel->data = value;
- fast_iob(); RECOVERY_DELAY;
- return;
-}
-
-static inline void load_zsregs(struct dec_zschannel *channel,
- unsigned char *regs)
-{
-/* ZS_CLEARERR(channel);
- ZS_CLEARFIFO(channel); */
- /* Load 'em up */
- write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
- write_zsreg(channel, R5, regs[R5] & ~TxENAB);
- write_zsreg(channel, R4, regs[R4]);
- write_zsreg(channel, R9, regs[R9]);
- write_zsreg(channel, R1, regs[R1]);
- write_zsreg(channel, R2, regs[R2]);
- write_zsreg(channel, R10, regs[R10]);
- write_zsreg(channel, R11, regs[R11]);
- write_zsreg(channel, R12, regs[R12]);
- write_zsreg(channel, R13, regs[R13]);
- write_zsreg(channel, R14, regs[R14]);
- write_zsreg(channel, R15, regs[R15]);
- write_zsreg(channel, R3, regs[R3]);
- write_zsreg(channel, R5, regs[R5]);
- return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct dec_serial *info, int which, int set)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&zs_lock, flags);
- if (info->zs_channel != info->zs_chan_a) {
- if (set) {
- info->zs_chan_a->curregs[5] |= (which & (RTS | DTR));
- } else {
- info->zs_chan_a->curregs[5] &= ~(which & (RTS | DTR));
- }
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct dec_serial *ss)
-{
- struct dec_zschannel *channel = ss->zs_channel;
- int brg;
-
- /* The baud rate is split up between two 8-bit registers in
- * what is termed 'BRG time constant' format in my docs for
- * the chip, it is a function of the clk rate the chip is
- * receiving which happens to be constant.
- */
- brg = (read_zsreg(channel, 13) << 8);
- brg |= read_zsreg(channel, 12);
- return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct dec_zschannel *zsc)
-{
- write_zsreg(zsc, 0, ERR_RES);
- write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct dec_serial *info, int event)
-{
- info->event |= 1 << event;
- tasklet_schedule(&info->tlet);
-}
-
-static void receive_chars(struct dec_serial *info)
-{
- struct tty_struct *tty = info->tty;
- unsigned char ch, stat, flag;
-
- while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) {
-
- stat = read_zsreg(info->zs_channel, R1);
- ch = read_zsdata(info->zs_channel);
-
- if (!tty && (!info->hook || !info->hook->rx_char))
- continue;
-
- flag = TTY_NORMAL;
- if (info->tty_break) {
- info->tty_break = 0;
- flag = TTY_BREAK;
- if (info->flags & ZILOG_SAK)
- do_SAK(tty);
- /* Ignore the null char got when BREAK is removed. */
- if (ch == 0)
- continue;
- } else {
- if (stat & Rx_OVR) {
- flag = TTY_OVERRUN;
- } else if (stat & FRM_ERR) {
- flag = TTY_FRAME;
- } else if (stat & PAR_ERR) {
- flag = TTY_PARITY;
- }
- if (flag != TTY_NORMAL)
- /* reset the error indication */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- }
-
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
- !defined(MODULE)
- if (break_pressed && info->line == sercons.index) {
- /* Ignore the null char got when BREAK is removed. */
- if (ch == 0)
- continue;
- if (time_before(jiffies, break_pressed + HZ * 5)) {
- handle_sysrq(ch, NULL);
- break_pressed = 0;
- continue;
- }
- break_pressed = 0;
- }
-#endif
-
- if (info->hook && info->hook->rx_char) {
- (*info->hook->rx_char)(ch, flag);
- return;
- }
-
- tty_insert_flip_char(tty, ch, flag);
- }
- if (tty)
- tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct dec_serial *info)
-{
- if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0)
- return;
- info->tx_active = 0;
-
- if (info->x_char) {
- /* Send next char */
- write_zsdata(info->zs_channel, info->x_char);
- info->x_char = 0;
- info->tx_active = 1;
- return;
- }
-
- if ((info->xmit_cnt <= 0) || (info->tty && info->tty->stopped)
- || info->tx_stopped) {
- write_zsreg(info->zs_channel, R0, RES_Tx_P);
- return;
- }
- /* Send char */
- write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- info->tx_active = 1;
-
- if (info->xmit_cnt < WAKEUP_CHARS)
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void status_handle(struct dec_serial *info)
-{
- unsigned char stat;
-
- /* Get status from Read Register 0 */
- stat = read_zsreg(info->zs_channel, R0);
-
- if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
- !defined(MODULE)
- if (info->line == sercons.index) {
- if (!break_pressed)
- break_pressed = jiffies;
- } else
-#endif
- info->tty_break = 1;
- }
-
- if (info->zs_channel != info->zs_chan_a) {
-
- /* Check for DCD transitions */
- if (info->tty && !C_CLOCAL(info->tty) &&
- ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
- if (stat & DCD) {
- wake_up_interruptible(&info->open_wait);
- } else {
- tty_hangup(info->tty);
- }
- }
-
- /* Check for CTS transitions */
- if (info->tty && C_CRTSCTS(info->tty)) {
- if ((stat & CTS) != 0) {
- if (info->tx_stopped) {
- info->tx_stopped = 0;
- if (!info->tx_active)
- transmit_chars(info);
- }
- } else {
- info->tx_stopped = 1;
- }
- }
-
- }
-
- /* Clear status condition... */
- write_zsreg(info->zs_channel, R0, RES_EXT_INT);
- info->read_reg_zero = stat;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
- struct dec_serial *info = (struct dec_serial *) dev_id;
- irqreturn_t status = IRQ_NONE;
- unsigned char zs_intreg;
- int shift;
-
- /* NOTE: The read register 3, which holds the irq status,
- * does so for both channels on each chip. Although
- * the status value itself must be read from the A
- * channel and is only valid when read from channel A.
- * Yes... broken hardware...
- */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
- if (info->zs_chan_a == info->zs_channel)
- shift = 3; /* Channel A */
- else
- shift = 0; /* Channel B */
-
- for (;;) {
- zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
- if ((zs_intreg & CHAN_IRQMASK) == 0)
- break;
-
- status = IRQ_HANDLED;
-
- if (zs_intreg & CHBRxIP) {
- receive_chars(info);
- }
- if (zs_intreg & CHBTxIP) {
- transmit_chars(info);
- }
- if (zs_intreg & CHBEXT) {
- status_handle(info);
- }
- }
-
- /* Why do we need this ? */
- write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
- return status;
-}
-
-#ifdef ZS_DEBUG_REGS
-void zs_dump (void) {
- int i, j;
- for (i = 0; i < zs_channels_found; i++) {
- struct dec_zschannel *ch = &zs_channels[i];
- if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
- for (j = 0; j < 15; j++) {
- printk("W%d = 0x%x\t",
- j, (int)ch->curregs[j]);
- }
- for (j = 0; j < 15; j++) {
- printk("R%d = 0x%x\t",
- j, (int)read_zsreg(ch,j));
- }
- printk("\n\n");
- }
- }
-}
-#endif
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
-#if 1
- spin_lock_irqsave(&zs_lock, flags);
- if (info->zs_channel->curregs[5] & TxENAB) {
- info->zs_channel->curregs[5] &= ~TxENAB;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_start"))
- return;
-
- spin_lock_irqsave(&zs_lock, flags);
-#if 1
- if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
- info->zs_channel->curregs[5] |= TxENAB;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- }
-#else
- if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
- transmit_chars(info);
- }
-#endif
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-
-static void do_softint(unsigned long private_)
-{
- struct dec_serial *info = (struct dec_serial *) private_;
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
- tty_wakeup(tty);
-}
-
-static int zs_startup(struct dec_serial * info)
-{
- unsigned long flags;
-
- if (info->flags & ZILOG_INITIALIZED)
- return 0;
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&zs_lock, flags);
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
-#endif
-
- /*
- * Clear the receive FIFO.
- */
- ZS_CLEARFIFO(info->zs_channel);
- info->xmit_fifo_size = 1;
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
- /*
- * Set the speed of the serial port
- */
- change_speed(info);
-
- /*
- * Turn on RTS and DTR.
- */
- zs_rtsdtr(info, RTS | DTR, 1);
-
- /*
- * Finally, enable sequencing and interrupts
- */
- info->zs_channel->curregs[R1] &= ~RxINT_MASK;
- info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
- EXT_INT_ENAB);
- info->zs_channel->curregs[R3] |= RxENABLE;
- info->zs_channel->curregs[R5] |= TxENAB;
- info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
- write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
- write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
- write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
- write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
-
- /*
- * And clear the interrupt registers again for luck.
- */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
- /* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- info->flags |= ZILOG_INITIALIZED;
- spin_unlock_irqrestore(&zs_lock, flags);
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct dec_serial * info)
-{
- unsigned long flags;
-
- if (!(info->flags & ZILOG_INITIALIZED))
- return;
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d (irq %d)....", info->line,
- info->irq);
-#endif
-
- spin_lock_irqsave(&zs_lock, flags);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- info->zs_channel->curregs[1] = 0;
- write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); /* no interrupts */
-
- info->zs_channel->curregs[3] &= ~RxENABLE;
- write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-
- info->zs_channel->curregs[5] &= ~TxENAB;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- if (!info->tty || C_HUPCL(info->tty)) {
- zs_rtsdtr(info, RTS | DTR, 0);
- }
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- info->flags &= ~ZILOG_INITIALIZED;
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct dec_serial *info)
-{
- unsigned cflag;
- int i;
- int brg, bits;
- unsigned long flags;
-
- if (!info->hook) {
- if (!info->tty || !info->tty->termios)
- return;
- cflag = info->tty->termios->c_cflag;
- if (!info->port)
- return;
- } else {
- cflag = info->hook->cflags;
- }
-
- i = cflag & CBAUD;
- if (i & CBAUDEX) {
- i &= ~CBAUDEX;
- if (i < 1 || i > 2) {
- if (!info->hook)
- info->tty->termios->c_cflag &= ~CBAUDEX;
- else
- info->hook->cflags &= ~CBAUDEX;
- } else
- i += 15;
- }
-
- spin_lock_irqsave(&zs_lock, flags);
- info->zs_baud = baud_table[i];
- if (info->zs_baud) {
- brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
- info->zs_channel->curregs[12] = (brg & 255);
- info->zs_channel->curregs[13] = ((brg >> 8) & 255);
- zs_rtsdtr(info, DTR, 1);
- } else {
- zs_rtsdtr(info, RTS | DTR, 0);
- return;
- }
-
- /* byte size and parity */
- info->zs_channel->curregs[3] &= ~RxNBITS_MASK;
- info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- bits = 7;
- info->zs_channel->curregs[3] |= Rx5;
- info->zs_channel->curregs[5] |= Tx5;
- break;
- case CS6:
- bits = 8;
- info->zs_channel->curregs[3] |= Rx6;
- info->zs_channel->curregs[5] |= Tx6;
- break;
- case CS7:
- bits = 9;
- info->zs_channel->curregs[3] |= Rx7;
- info->zs_channel->curregs[5] |= Tx7;
- break;
- case CS8:
- default: /* defaults to 8 bits */
- bits = 10;
- info->zs_channel->curregs[3] |= Rx8;
- info->zs_channel->curregs[5] |= Tx8;
- break;
- }
-
- info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud);
- info->timeout += HZ/50; /* Add .02 seconds of slop */
-
- info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
- if (cflag & CSTOPB) {
- info->zs_channel->curregs[4] |= SB2;
- } else {
- info->zs_channel->curregs[4] |= SB1;
- }
- if (cflag & PARENB) {
- info->zs_channel->curregs[4] |= PAR_ENA;
- }
- if (!(cflag & PARODD)) {
- info->zs_channel->curregs[4] |= PAR_EVEN;
- }
-
- if (!(cflag & CLOCAL)) {
- if (!(info->zs_channel->curregs[15] & DCDIE))
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
- info->zs_channel->curregs[15] |= DCDIE;
- } else
- info->zs_channel->curregs[15] &= ~DCDIE;
- if (cflag & CRTSCTS) {
- info->zs_channel->curregs[15] |= CTSIE;
- if ((read_zsreg(info->zs_channel, 0) & CTS) == 0)
- info->tx_stopped = 1;
- } else {
- info->zs_channel->curregs[15] &= ~CTSIE;
- info->tx_stopped = 0;
- }
-
- /* Load up the new values */
- load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
- return;
-
- if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
- !info->xmit_buf)
- return;
-
- /* Enable transmitter */
- spin_lock_irqsave(&zs_lock, flags);
- transmit_chars(info);
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- int c, total = 0;
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf)
- return 0;
-
- while (1) {
- spin_lock_irqsave(&zs_lock, flags);
- c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
- SERIAL_XMIT_SIZE - info->xmit_head));
- if (c <= 0)
- break;
-
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt += c;
- spin_unlock_irqrestore(&zs_lock, flags);
- buf += c;
- count -= c;
- total += c;
- }
-
- if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
- && !info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&zs_lock, flags);
- return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
- spin_lock_irq(&zs_lock);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- spin_unlock_irq(&zs_lock);
- tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("throttle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&zs_lock, flags);
- info->x_char = STOP_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&zs_lock, flags);
- }
-
- if (C_CRTSCTS(tty)) {
- zs_rtsdtr(info, RTS, 0);
- }
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_THROTTLE
- char buf[64];
-
- printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&zs_lock, flags);
- if (info->x_char)
- info->x_char = 0;
- else {
- info->x_char = START_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
- }
-
- if (C_CRTSCTS(tty)) {
- zs_rtsdtr(info, RTS, 1);
- }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct dec_serial * info,
- struct serial_struct * retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct dec_serial * info,
- struct serial_struct * new_info)
-{
- struct serial_struct new_serial;
- struct dec_serial old_info;
- int retval = 0;
-
- if (!new_info)
- return -EFAULT;
- copy_from_user(&new_serial,new_info,sizeof(new_serial));
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~ZILOG_USR_MASK) !=
- (info->flags & ~ZILOG_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ZILOG_USR_MASK) |
- (new_serial.flags & ZILOG_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (info->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~ZILOG_FLAGS) |
- (new_serial.flags & ZILOG_FLAGS));
- info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- retval = zs_startup(info);
- return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct dec_serial * info, unsigned int *value)
-{
- unsigned char status;
-
- spin_lock(&zs_lock);
- status = read_zsreg(info->zs_channel, 0);
- spin_unlock_irq(&zs_lock);
- put_user(status,value);
- return 0;
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
- unsigned char control, status_a, status_b;
- unsigned int result;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- if (info->zs_channel == info->zs_chan_a)
- result = 0;
- else {
- spin_lock(&zs_lock);
- control = info->zs_chan_a->curregs[5];
- status_a = read_zsreg(info->zs_chan_a, 0);
- status_b = read_zsreg(info->zs_channel, 0);
- spin_unlock_irq(&zs_lock);
- result = ((control & RTS) ? TIOCM_RTS: 0)
- | ((control & DTR) ? TIOCM_DTR: 0)
- | ((status_b & DCD) ? TIOCM_CAR: 0)
- | ((status_a & DCD) ? TIOCM_RNG: 0)
- | ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0)
- | ((status_b & CTS) ? TIOCM_CTS: 0);
- }
- return result;
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- if (info->zs_channel == info->zs_chan_a)
- return 0;
-
- spin_lock(&zs_lock);
- if (set & TIOCM_RTS)
- info->zs_chan_a->curregs[5] |= RTS;
- if (set & TIOCM_DTR)
- info->zs_chan_a->curregs[5] |= DTR;
- if (clear & TIOCM_RTS)
- info->zs_chan_a->curregs[5] &= ~RTS;
- if (clear & TIOCM_DTR)
- info->zs_chan_a->curregs[5] &= ~DTR;
- write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
- spin_unlock_irq(&zs_lock);
- return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
- struct dec_serial *info = (struct dec_serial *) tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_break"))
- return;
- if (!info->port)
- return;
-
- spin_lock_irqsave(&zs_lock, flags);
- if (break_state == -1)
- info->zs_channel->curregs[5] |= SND_BRK;
- else
- info->zs_channel->curregs[5] &= ~SND_BRK;
- write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) &&
- (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TIOCGSERIAL:
- if (!access_ok(VERIFY_WRITE, (void *)arg,
- sizeof(struct serial_struct)))
- return -EFAULT;
- return get_serial_info(info, (struct serial_struct *)arg);
-
- case TIOCSSERIAL:
- return set_serial_info(info, (struct serial_struct *)arg);
-
- case TIOCSERGETLSR: /* Get line status register */
- if (!access_ok(VERIFY_WRITE, (void *)arg,
- sizeof(unsigned int)))
- return -EFAULT;
- return get_lsr_info(info, (unsigned int *)arg);
-
- case TIOCSERGSTRUCT:
- if (!access_ok(VERIFY_WRITE, (void *)arg,
- sizeof(struct dec_serial)))
- return -EFAULT;
- copy_from_user((struct dec_serial *)arg, info,
- sizeof(struct dec_serial));
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
- struct dec_serial *info = (struct dec_serial *)tty->driver_data;
- int was_stopped;
-
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- was_stopped = info->tx_stopped;
-
- change_speed(info);
-
- if (was_stopped && !info->tx_stopped)
- rs_start(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.
- * Wait for the last remaining data to be sent.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
- unsigned long flags;
-
- if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- spin_lock_irqsave(&zs_lock, flags);
-
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&zs_lock, flags);
- return;
- }
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk("rs_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
- info->count = 1;
- }
- if (--info->count < 0) {
- printk("rs_close: bad serial port count for ttyS%d: %d\n",
- info->line, info->count);
- info->count = 0;
- }
- if (info->count) {
- spin_unlock_irqrestore(&zs_lock, flags);
- return;
- }
- info->flags |= ZILOG_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- tty->closing = 1;
- if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
- tty_wait_until_sent(tty, info->closing_wait);
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receiver and receive interrupts.
- */
- info->zs_channel->curregs[3] &= ~RxENABLE;
- write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
- info->zs_channel->curregs[1] = 0; /* disable any rx ints */
- write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
- ZS_CLEARFIFO(info->zs_channel);
- if (info->flags & ZILOG_INITIALIZED) {
- /*
- * Before we drop DTR, make sure the SCC transmitter
- * has completely drained.
- */
- rs_wait_until_sent(tty, info->timeout);
- }
-
- shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- info->event = 0;
- info->tty = 0;
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
- wake_up_interruptible(&info->close_wait);
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct dec_serial *info = (struct dec_serial *) tty->driver_data;
- unsigned long orig_jiffies;
- int char_time;
-
- if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
- return;
-
- orig_jiffies = jiffies;
- /*
- * Set the check interval to be 1/5 of the estimated time to
- * send a single character, and make it at least 1. The check
- * interval should also be less than the timeout.
- */
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
- char_time = char_time / 5;
- if (char_time == 0)
- char_time = 1;
- if (timeout)
- char_time = min(char_time, timeout);
- while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
- msleep_interruptible(jiffies_to_msecs(char_time));
- if (signal_pending(current))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
- }
- current->state = TASK_RUNNING;
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
- struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- rs_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~ZILOG_NORMAL_ACTIVE;
- info->tty = 0;
- wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct dec_serial *info)
-{
- DECLARE_WAITQUEUE(wait, current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ZILOG_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- return ((info->flags & ZILOG_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- spin_lock(&zs_lock);
- if (!tty_hung_up_p(filp))
- info->count--;
- spin_unlock_irq(&zs_lock);
- info->blocked_open++;
- while (1) {
- spin_lock(&zs_lock);
- if (tty->termios->c_cflag & CBAUD)
- zs_rtsdtr(info, RTS | DTR, 1);
- spin_unlock_irq(&zs_lock);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ZILOG_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (info->flags & ZILOG_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(info->flags & ZILOG_CLOSING) &&
- (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttyS%d, count = %d\n",
- info->line, info->count);
-#endif
- if (retval)
- return retval;
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its ZILOG structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_open(struct tty_struct *tty, struct file * filp)
-{
- struct dec_serial *info;
- int retval, line;
-
- line = tty->index;
- if ((line < 0) || (line >= zs_channels_found))
- return -ENODEV;
- info = zs_soft + line;
-
- if (info->hook)
- return -ENODEV;
-
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s, count = %d\n", tty->name, info->count);
-#endif
-
- info->count++;
- tty->driver_data = info;
- info->tty = tty;
-
- /*
- * If the port is the middle of closing, bail out now
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ZILOG_CLOSING)) {
- if (info->flags & ZILOG_CLOSING)
- interruptible_sleep_on(&info->close_wait);
-#ifdef SERIAL_DO_RESTART
- return ((info->flags & ZILOG_HUP_NOTIFY) ?
- -EAGAIN : -ERESTARTSYS);
-#else
- return -EAGAIN;
-#endif
- }
-
- /*
- * Start up serial port
- */
- retval = zs_startup(info);
- if (retval)
- return retval;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open returning after block_til_ready with %d\n",
- retval);
-#endif
- return retval;
- }
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
- if (sercons.cflag && sercons.index == line) {
- tty->termios->c_cflag = sercons.cflag;
- sercons.cflag = 0;
- change_speed(info);
- }
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open %s successful...", tty->name);
-#endif
-/* tty->low_latency = 1; */
- return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void __init show_serial_version(void)
-{
- printk("DECstation Z8530 serial driver version 0.09\n");
-}
-
-/* Initialize Z8530s zs_channels
- */
-
-static void probe_sccs(void)
-{
- struct dec_serial **pp;
- int i, n, n_chips = 0, n_channels, chip, channel;
- unsigned long flags;
-
- /*
- * did we get here by accident?
- */
- if(!BUS_PRESENT) {
- printk("Not on JUNKIO machine, skipping probe_sccs\n");
- return;
- }
-
- switch(mips_machtype) {
-#ifdef CONFIG_MACH_DECSTATION
- case MACH_DS5000_2X0:
- case MACH_DS5900:
- n_chips = 2;
- zs_parms = &ds_parms;
- zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
- zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
- break;
- case MACH_DS5000_1XX:
- n_chips = 2;
- zs_parms = &ds_parms;
- zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
- zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
- break;
- case MACH_DS5000_XX:
- n_chips = 1;
- zs_parms = &ds_parms;
- zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
- break;
-#endif
- default:
- panic("zs: unsupported bus");
- }
- if (!zs_parms)
- panic("zs: uninitialized parms");
-
- pp = &zs_chain;
-
- n_channels = 0;
-
- for (chip = 0; chip < n_chips; chip++) {
- for (channel = 0; channel <= 1; channel++) {
- /*
- * The sccs reside on the high byte of the 16 bit IOBUS
- */
- zs_channels[n_channels].control =
- (volatile void *)CKSEG1ADDR(dec_kn_slot_base +
- (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
- (0 == channel ? zs_parms->channel_a_offset :
- zs_parms->channel_b_offset));
- zs_channels[n_channels].data =
- zs_channels[n_channels].control + 4;
-
-#ifndef CONFIG_SERIAL_DEC_CONSOLE
- /*
- * We're called early and memory managment isn't up, yet.
- * Thus request_region would fail.
- */
- if (!request_region((unsigned long)
- zs_channels[n_channels].control,
- ZS_CHAN_IO_SIZE, "SCC"))
- panic("SCC I/O region is not free");
-#endif
- zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
- /* HACK alert! */
- if (!(chip & 1))
- zs_soft[n_channels].irq = zs_parms->irq0;
- else
- zs_soft[n_channels].irq = zs_parms->irq1;
-
- /*
- * Identification of channel A. Location of channel A
- * inside chip depends on mapping of internal address
- * the chip decodes channels by.
- * CHANNEL_A_NR returns either 0 (in case of
- * DECstations) or 1 (in case of Baget).
- */
- if (CHANNEL_A_NR == channel)
- zs_soft[n_channels].zs_chan_a =
- &zs_channels[n_channels+1-2*CHANNEL_A_NR];
- else
- zs_soft[n_channels].zs_chan_a =
- &zs_channels[n_channels];
-
- *pp = &zs_soft[n_channels];
- pp = &zs_soft[n_channels].zs_next;
- n_channels++;
- }
- }
-
- *pp = 0;
- zs_channels_found = n_channels;
-
- for (n = 0; n < zs_channels_found; n++) {
- for (i = 0; i < 16; i++) {
- zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i];
- }
- }
-
- spin_lock_irqsave(&zs_lock, flags);
- for (n = 0; n < zs_channels_found; n++) {
- if (n % 2 == 0) {
- write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
- udelay(10);
- write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
- }
- load_zsregs(zs_soft[n].zs_channel,
- zs_soft[n].zs_channel->curregs);
- }
- spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static const struct tty_operations serial_ops = {
- .open = rs_open,
- .close = rs_close,
- .write = rs_write,
- .flush_chars = rs_flush_chars,
- .write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
- .flush_buffer = rs_flush_buffer,
- .ioctl = rs_ioctl,
- .throttle = rs_throttle,
- .unthrottle = rs_unthrottle,
- .set_termios = rs_set_termios,
- .stop = rs_stop,
- .start = rs_start,
- .hangup = rs_hangup,
- .break_ctl = rs_break,
- .wait_until_sent = rs_wait_until_sent,
- .tiocmget = rs_tiocmget,
- .tiocmset = rs_tiocmset,
-};
-
-/* zs_init inits the driver */
-int __init zs_init(void)
-{
- int channel, i;
- struct dec_serial *info;
-
- if(!BUS_PRESENT)
- return -ENODEV;
-
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
- serial_driver = alloc_tty_driver(zs_channels_found);
- if (!serial_driver)
- return -ENOMEM;
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- /* Not all of this is exactly right for us. */
-
- serial_driver->owner = THIS_MODULE;
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- tty_set_operations(serial_driver, &serial_ops);
-
- if (tty_register_driver(serial_driver))
- panic("Couldn't register serial driver");
-
- for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
-
- /* Needed before interrupts are enabled. */
- info->tty = 0;
- info->x_char = 0;
-
- if (info->hook && info->hook->init_info) {
- (*info->hook->init_info)(info);
- continue;
- }
-
- info->magic = SERIAL_MAGIC;
- info->port = (int) info->zs_channel->control;
- info->line = i;
- info->custom_divisor = 16;
- info->close_delay = 50;
- info->closing_wait = 3000;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- tasklet_init(&info->tlet, do_softint, (unsigned long)info);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
- info->line, info->port, info->irq);
- tty_register_device(serial_driver, info->line, NULL);
-
- }
-
- for (channel = 0; channel < zs_channels_found; ++channel) {
- zs_soft[channel].clk_divisor = 16;
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-
- if (request_irq(zs_soft[channel].irq, rs_interrupt, IRQF_SHARED,
- "scc", &zs_soft[channel]))
- printk(KERN_ERR "decserial: can't get irq %d\n",
- zs_soft[channel].irq);
-
- if (zs_soft[channel].hook) {
- zs_startup(&zs_soft[channel]);
- if (zs_soft[channel].hook->init_channel)
- (*zs_soft[channel].hook->init_channel)
- (&zs_soft[channel]);
- }
- }
-
- return 0;
-}
-
-/*
- * polling I/O routines
- */
-static int zs_poll_tx_char(void *handle, unsigned char ch)
-{
- struct dec_serial *info = handle;
- struct dec_zschannel *chan = info->zs_channel;
- int ret;
-
- if(chan) {
- int loops = 10000;
-
- while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
- loops--;
-
- if (loops) {
- write_zsdata(chan, ch);
- ret = 0;
- } else
- ret = -EAGAIN;
-
- return ret;
- } else
- return -ENODEV;
-}
-
-static int zs_poll_rx_char(void *handle)
-{
- struct dec_serial *info = handle;
- struct dec_zschannel *chan = info->zs_channel;
- int ret;
-
- if(chan) {
- int loops = 10000;
-
- while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
- loops--;
-
- if (loops)
- ret = read_zsdata(chan);
- else
- ret = -EAGAIN;
-
- return ret;
- } else
- return -ENODEV;
-}
-
-int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
-{
- struct dec_serial *info = &zs_soft[channel];
-
- if (info->hook) {
- printk("%s: line %d has already a hook registered\n",
- __FUNCTION__, channel);
-
- return 0;
- } else {
- hook->poll_rx_char = zs_poll_rx_char;
- hook->poll_tx_char = zs_poll_tx_char;
- info->hook = hook;
-
- return 1;
- }
-}
-
-int unregister_zs_hook(unsigned int channel)
-{
- struct dec_serial *info = &zs_soft[channel];
-
- if (info->hook) {
- info->hook = NULL;
- return 1;
- } else {
- printk("%s: trying to unregister hook on line %d,"
- " but none is registered\n", __FUNCTION__, channel);
- return 0;
- }
-}
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
- unsigned count)
-{
- struct dec_serial *info;
- int i;
-
- info = zs_soft + co->index;
-
- for (i = 0; i < count; i++, s++) {
- if(*s == '\n')
- zs_poll_tx_char(info, '\r');
- zs_poll_tx_char(info, *s);
- }
-}
-
-static struct tty_driver *serial_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-/*
- * Setup initial baud/bits/parity. We do two things here:
- * - construct a cflag setting for the first rs_open()
- * - initialize the serial port
- * Return non-zero if we didn't find a serial port.
- */
-static int serial_console_setup(struct console *co, char *options)
-{
- struct dec_serial *info;
- int baud = 9600;
- int bits = 8;
- int parity = 'n';
- int cflag = CREAD | HUPCL | CLOCAL;
- int clk_divisor = 16;
- int brg;
- char *s;
- unsigned long flags;
-
- if(!BUS_PRESENT)
- return -ENODEV;
-
- info = zs_soft + co->index;
-
- if (zs_chain == 0)
- probe_sccs();
-
- info->is_cons = 1;
-
- if (options) {
- baud = simple_strtoul(options, NULL, 10);
- s = options;
- while(*s >= '0' && *s <= '9')
- s++;
- if (*s)
- parity = *s++;
- if (*s)
- bits = *s - '0';
- }
-
- /*
- * Now construct a cflag setting.
- */
- switch(baud) {
- case 1200:
- cflag |= B1200;
- break;
- case 2400:
- cflag |= B2400;
- break;
- case 4800:
- cflag |= B4800;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 38400:
- cflag |= B38400;
- break;
- case 57600:
- cflag |= B57600;
- break;
- case 115200:
- cflag |= B115200;
- break;
- case 9600:
- default:
- cflag |= B9600;
- /*
- * Set this to a sane value to prevent a divide error.
- */
- baud = 9600;
- break;
- }
- switch(bits) {
- case 7:
- cflag |= CS7;
- break;
- default:
- case 8:
- cflag |= CS8;
- break;
- }
- switch(parity) {
- case 'o': case 'O':
- cflag |= PARODD;
- break;
- case 'e': case 'E':
- cflag |= PARENB;
- break;
- }
- co->cflag = cflag;
-
- spin_lock_irqsave(&zs_lock, flags);
-
- /*
- * Set up the baud rate generator.
- */
- brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor);
- info->zs_channel->curregs[R12] = (brg & 255);
- info->zs_channel->curregs[R13] = ((brg >> 8) & 255);
-
- /*
- * Set byte size and parity.
- */
- if (bits == 7) {
- info->zs_channel->curregs[R3] |= Rx7;
- info->zs_channel->curregs[R5] |= Tx7;
- } else {
- info->zs_channel->curregs[R3] |= Rx8;
- info->zs_channel->curregs[R5] |= Tx8;
- }
- if (cflag & PARENB) {
- info->zs_channel->curregs[R4] |= PAR_ENA;
- }
- if (!(cflag & PARODD)) {
- info->zs_channel->curregs[R4] |= PAR_EVEN;
- }
- info->zs_channel->curregs[R4] |= SB1;
-
- /*
- * Turn on RTS and DTR.
- */
- zs_rtsdtr(info, RTS | DTR, 1);
-
- /*
- * Finally, enable sequencing.
- */
- info->zs_channel->curregs[R3] |= RxENABLE;
- info->zs_channel->curregs[R5] |= TxENAB;
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->zs_channel, R0, ERR_RES);
- write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
- /*
- * Load up the new values.
- */
- load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
- /* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
- zs_soft[co->index].clk_divisor = clk_divisor;
- zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
-
- spin_unlock_irqrestore(&zs_lock, flags);
-
- return 0;
-}
-
-static struct console sercons = {
- .name = "ttyS",
- .write = serial_console_write,
- .device = serial_console_device,
- .setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-/*
- * Register console.
- */
-void __init zs_serial_console_init(void)
-{
- register_console(&sercons);
-}
-#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
-
-#ifdef CONFIG_KGDB
-struct dec_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
- 9, 0x80, /* reset A side (CHRA) */
- 13, 0, /* set baud rate divisor */
- 12, 1,
- 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
- 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
- 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
- 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
- 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
- struct dec_zschannel *chan = zs_kgdbchan;
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- RECOVERY_DELAY;
- write_zsdata(chan, kgdb_char);
-}
-char getDebugChar(void)
-{
- struct dec_zschannel *chan = zs_kgdbchan;
- while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- eieio(); /*barrier();*/
- return read_zsdata(chan);
-}
-void kgdb_interruptible(int yes)
-{
- struct dec_zschannel *chan = zs_kgdbchan;
- int one, nine;
- nine = read_zsreg(chan, 9);
- if (yes == 1) {
- one = EXT_INT_ENAB|RxINT_ALL;
- nine |= MIE;
- printk("turning serial ints on\n");
- } else {
- one = RxINT_DISAB;
- nine &= ~MIE;
- printk("turning serial ints off\n");
- }
- write_zsreg(chan, 1, one);
- write_zsreg(chan, 9, nine);
-}
-
-static int kgdbhook_init_channel(void *handle)
-{
- return 0;
-}
-
-static void kgdbhook_init_info(void *handle)
-{
-}
-
-static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
-{
- struct dec_serial *info = handle;
-
- if (fl != TTY_NORMAL)
- return;
- if (ch == 0x03 || ch == '$')
- breakpoint();
-}
-
-/* This sets up the serial port we're using, and turns on
- * interrupts for that channel, so kgdb is usable once we're done.
- */
-static inline void kgdb_chaninit(struct dec_zschannel *ms, int intson, int bps)
-{
- int brg;
- int i, x;
- volatile char *sccc = ms->control;
- brg = BPS_TO_BRG(bps, zs_parms->clock/16);
- printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
- for (i = 20000; i != 0; --i) {
- x = *sccc; eieio();
- }
- for (i = 0; i < sizeof(scc_inittab); ++i) {
- write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
- i++;
- }
-}
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1
- * for /dev/ttyb which is determined in setup_arch() from the
- * boot command line flags.
- */
-struct dec_serial_hook zs_kgdbhook = {
- .init_channel = kgdbhook_init_channel,
- .init_info = kgdbhook_init_info,
- .rx_char = kgdbhook_rx_char,
- .cflags = B38400 | CS8 | CLOCAL,
-};
-
-void __init zs_kgdb_hook(int tty_num)
-{
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
- zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
- zs_kgdbchan = zs_soft[tty_num].zs_channel;
- zs_soft[tty_num].change_needed = 0;
- zs_soft[tty_num].clk_divisor = 16;
- zs_soft[tty_num].zs_baud = 38400;
- zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */
- /* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
- printk("KGDB: on channel %d initialized\n", tty_num);
- set_debug_traps(); /* init stub */
-}
-#endif /* ifdef CONFIG_KGDB */
diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h
deleted file mode 100644
index 13512200ceba..000000000000
--- a/drivers/tc/zs.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2004, 2005 Maciej W. Rozycki
- */
-#ifndef _DECSERIAL_H
-#define _DECSERIAL_H
-
-#include <asm/dec/serial.h>
-
-#define NUM_ZSREGS 16
-
-struct serial_struct {
- int type;
- int line;
- int port;
- int irq;
- int flags;
- int xmit_fifo_size;
- int custom_divisor;
- int baud_base;
- unsigned short close_delay;
- char reserved_char[2];
- int hub6;
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- int reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF 0
-#define ZILOG_CLOSING_WAIT_NONE 65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
- on the callout port */
-#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK 0x0030
-#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
- * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct dec_zschannel {
- volatile unsigned char *control;
- volatile unsigned char *data;
-
- /* Current write register values */
- unsigned char curregs[NUM_ZSREGS];
-};
-
-struct dec_serial {
- struct dec_serial *zs_next; /* For IRQ servicing chain. */
- struct dec_zschannel *zs_channel; /* Channel registers. */
- struct dec_zschannel *zs_chan_a; /* A side registers. */
- unsigned char read_reg_zero;
-
- struct dec_serial_hook *hook; /* Hook on this channel. */
- int tty_break; /* Set on BREAK condition. */
- int is_cons; /* Is this our console. */
- int tx_active; /* Char is being xmitted. */
- int tx_stopped; /* Output is suspended. */
-
- /*
- * We need to know the current clock divisor
- * to read the bps rate the chip has currently loaded.
- */
- int clk_divisor; /* May be 1, 16, 32, or 64. */
- int zs_baud;
-
- char change_needed;
-
- int magic;
- int baud_base;
- int port;
- int irq;
- int flags; /* Defined in tty.h. */
- int type; /* UART type. */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int xmit_fifo_size;
- int custom_divisor;
- int x_char; /* XON/XOFF character. */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int line;
- int count; /* # of fds on device. */
- int blocked_open; /* # of blocked opens. */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- struct tasklet_struct tlet;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define FLAG 0x7e
-
-/* Write Register 0 */
-#define R0 0 /* Register selects */
-#define R1 1
-#define R2 2
-#define R3 3
-#define R4 4
-#define R5 5
-#define R6 6
-#define R7 7
-#define R8 8
-#define R9 9
-#define R10 10
-#define R11 11
-#define R12 12
-#define R13 13
-#define R14 14
-#define R15 15
-
-#define NULLCODE 0 /* Null Code */
-#define POINT_HIGH 0x8 /* Select upper half of registers */
-#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
-#define SEND_ABORT 0x18 /* HDLC Abort */
-#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
-#define RES_Tx_P 0x28 /* Reset TxINT Pending */
-#define ERR_RES 0x30 /* Error Reset */
-#define RES_H_IUS 0x38 /* Reset highest IUS */
-
-#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
-#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
-#define RES_EOM_L 0xC0 /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
-#define TxINT_ENAB 0x2 /* Tx Int Enable */
-#define PAR_SPEC 0x4 /* Parity is special condition */
-
-#define RxINT_DISAB 0 /* Rx Int Disable */
-#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
-#define RxINT_ALL 0x10 /* Int on all Rx Characters or error */
-#define RxINT_ERR 0x18 /* Int on error only */
-#define RxINT_MASK 0x18
-
-#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */
-#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */
-#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define RxENABLE 0x1 /* Rx Enable */
-#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
-#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
-#define ENT_HM 0x10 /* Enter Hunt Mode */
-#define AUTO_ENAB 0x20 /* Auto Enables */
-#define Rx5 0x0 /* Rx 5 Bits/Character */
-#define Rx7 0x40 /* Rx 7 Bits/Character */
-#define Rx6 0x80 /* Rx 6 Bits/Character */
-#define Rx8 0xc0 /* Rx 8 Bits/Character */
-#define RxNBITS_MASK 0xc0
-
-/* Write Register 4 */
-
-#define PAR_ENA 0x1 /* Parity Enable */
-#define PAR_EVEN 0x2 /* Parity Even/Odd* */
-
-#define SYNC_ENAB 0 /* Sync Modes Enable */
-#define SB1 0x4 /* 1 stop bit/char */
-#define SB15 0x8 /* 1.5 stop bits/char */
-#define SB2 0xc /* 2 stop bits/char */
-#define SB_MASK 0xc
-
-#define MONSYNC 0 /* 8 Bit Sync character */
-#define BISYNC 0x10 /* 16 bit sync character */
-#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC 0x30 /* External Sync Mode */
-
-#define X1CLK 0x0 /* x1 clock mode */
-#define X16CLK 0x40 /* x16 clock mode */
-#define X32CLK 0x80 /* x32 clock mode */
-#define X64CLK 0xC0 /* x64 clock mode */
-#define XCLK_MASK 0xC0
-
-/* Write Register 5 */
-
-#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
-#define RTS 0x2 /* RTS */
-#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
-#define TxENAB 0x8 /* Tx Enable */
-#define SND_BRK 0x10 /* Send Break */
-#define Tx5 0x0 /* Tx 5 bits (or less)/character */
-#define Tx7 0x20 /* Tx 7 bits/character */
-#define Tx6 0x40 /* Tx 6 bits/character */
-#define Tx8 0x60 /* Tx 8 bits/character */
-#define TxNBITS_MASK 0x60
-#define DTR 0x80 /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define VIS 1 /* Vector Includes Status */
-#define NV 2 /* No Vector */
-#define DLC 4 /* Disable Lower Chain */
-#define MIE 8 /* Master Interrupt Enable */
-#define STATHI 0x10 /* Status high */
-#define SOFTACK 0x20 /* Software Interrupt Acknowledge */
-#define NORESET 0 /* No reset on write to R9 */
-#define CHRB 0x40 /* Reset channel B */
-#define CHRA 0x80 /* Reset channel A */
-#define FHWRES 0xc0 /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define BIT6 1 /* 6 bit/8bit sync */
-#define LOOPMODE 2 /* SDLC Loop mode */
-#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE 8 /* Mark/flag on idle */
-#define GAOP 0x10 /* Go active on poll */
-#define NRZ 0 /* NRZ mode */
-#define NRZI 0x20 /* NRZI mode */
-#define FM1 0x40 /* FM1 (transition = 1) */
-#define FM0 0x60 /* FM0 (transition = 0) */
-#define CRCPS 0x80 /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define TRxCXT 0 /* TRxC = Xtal output */
-#define TRxCTC 1 /* TRxC = Transmit clock */
-#define TRxCBR 2 /* TRxC = BR Generator Output */
-#define TRxCDP 3 /* TRxC = DPLL output */
-#define TRxCOI 4 /* TRxC O/I */
-#define TCRTxCP 0 /* Transmit clock = RTxC pin */
-#define TCTRxCP 8 /* Transmit clock = TRxC pin */
-#define TCBR 0x10 /* Transmit clock = BR Generator output */
-#define TCDPLL 0x18 /* Transmit clock = DPLL output */
-#define RCRTxCP 0 /* Receive clock = RTxC pin */
-#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
-#define RCBR 0x40 /* Receive clock = BR Generator output */
-#define RCDPLL 0x60 /* Receive clock = DPLL output */
-#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define BRENABL 1 /* Baud rate generator enable */
-#define BRSRC 2 /* Baud rate generator source */
-#define DTRREQ 4 /* DTR/Request function */
-#define AUTOECHO 8 /* Auto Echo */
-#define LOOPBAK 0x10 /* Local loopback */
-#define SEARCH 0x20 /* Enter search mode */
-#define RMC 0x40 /* Reset missing clock */
-#define DISDPLL 0x60 /* Disable DPLL */
-#define SSBR 0x80 /* Set DPLL source = BR generator */
-#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
-#define SFMM 0xc0 /* Set FM mode */
-#define SNRZI 0xe0 /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define ZCIE 2 /* Zero count IE */
-#define DCDIE 8 /* DCD IE */
-#define SYNCIE 0x10 /* Sync/hunt IE */
-#define CTSIE 0x20 /* CTS IE */
-#define TxUIE 0x40 /* Tx Underrun/EOM IE */
-#define BRKIE 0x80 /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define Rx_CH_AV 0x1 /* Rx Character Available */
-#define ZCOUNT 0x2 /* Zero count */
-#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
-#define DCD 0x8 /* DCD */
-#define SYNC_HUNT 0x10 /* Sync/hunt */
-#define CTS 0x20 /* CTS */
-#define TxEOM 0x40 /* Tx underrun */
-#define BRK_ABRT 0x80 /* Break/Abort */
-
-/* Read Register 1 */
-#define ALL_SNT 0x1 /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3 0x8 /* 0/3 */
-#define RES4 0x4 /* 0/4 */
-#define RES5 0xc /* 0/5 */
-#define RES6 0x2 /* 0/6 */
-#define RES7 0xa /* 0/7 */
-#define RES8 0x6 /* 0/8 */
-#define RES18 0xe /* 1/8 */
-#define RES28 0x0 /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR 0x10 /* Parity error */
-#define Rx_OVR 0x20 /* Rx Overrun Error */
-#define FRM_ERR 0x40 /* CRC/Framing Error */
-#define END_FR 0x80 /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
-#define CHBTxIP 0x2 /* Channel B Tx IP */
-#define CHBRxIP 0x4 /* Channel B Rx IP */
-#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
-#define CHATxIP 0x10 /* Channel A Tx IP */
-#define CHARxIP 0x20 /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10 (misc status bits) */
-#define ONLOOP 2 /* On loop */
-#define LOOPSEND 0x10 /* Loop sending */
-#define CLK2MIS 0x40 /* Two clocks missing */
-#define CLK1MIS 0x80 /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- } while(0)
-
-#endif /* !(_DECSERIAL_H) */
diff --git a/drivers/telephony/Kconfig b/drivers/telephony/Kconfig
index dd1d6a53f3c0..5f98f673f1b6 100644
--- a/drivers/telephony/Kconfig
+++ b/drivers/telephony/Kconfig
@@ -2,11 +2,9 @@
# Telephony device configuration
#
-menu "Telephony Support"
+menuconfig PHONE
+ tristate "Telephony support"
depends on HAS_IOMEM
-
-config PHONE
- tristate "Linux telephony support"
---help---
Say Y here if you have a telephony card, which for example allows
you to use a regular phone for voice-over-IP applications.
@@ -17,9 +15,11 @@ config PHONE
To compile this driver as a module, choose M here: the
module will be called phonedev.
+if PHONE
+
config PHONE_IXJ
tristate "QuickNet Internet LineJack/PhoneJack support"
- depends on PHONE
+ depends ISA || PCI
---help---
Say M if you have a telephony card manufactured by Quicknet
Technologies, Inc. These include the Internet PhoneJACK and
@@ -44,5 +44,4 @@ config PHONE_IXJ_PCMCIA
cards manufactured by Quicknet Technologies, Inc. This changes the
card initialization code to work with the card manager daemon.
-endmenu
-
+endif # PHONE
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index c7b0a357b04a..49cd9793404f 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -3453,7 +3453,6 @@ static void ixj_write_frame(IXJ *j)
{
int cnt, frame_count, dly;
IXJ_WORD dat;
- BYTES blankword;
frame_count = 0;
if(j->flags.cidplay) {
@@ -3501,6 +3500,8 @@ static void ixj_write_frame(IXJ *j)
}
if (frame_count >= 1) {
if (j->ver.low == 0x12 && j->play_mode && j->flags.play_first_frame) {
+ BYTES blankword;
+
switch (j->play_mode) {
case PLAYBACK_MODE_ULAW:
case PLAYBACK_MODE_ALAW:
@@ -3508,6 +3509,7 @@ static void ixj_write_frame(IXJ *j)
break;
case PLAYBACK_MODE_8LINEAR:
case PLAYBACK_MODE_16LINEAR:
+ default:
blankword.low = blankword.high = 0x00;
break;
case PLAYBACK_MODE_8LINEAR_WSS:
@@ -3531,6 +3533,8 @@ static void ixj_write_frame(IXJ *j)
j->flags.play_first_frame = 0;
} else if (j->play_codec == G723_63 && j->flags.play_first_frame) {
for (cnt = 0; cnt < 24; cnt++) {
+ BYTES blankword;
+
if(cnt == 12) {
blankword.low = 0x02;
blankword.high = 0x00;
@@ -4868,6 +4872,7 @@ static char daa_CR_read(IXJ *j, int cr)
bytes.high = 0xB0 + cr;
break;
case SOP_PU_PULSEDIALING:
+ default:
bytes.high = 0xF0 + cr;
break;
}
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index 3e658dc7c2d8..ff9a29b76336 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -45,11 +45,10 @@ static int ixj_probe(struct pcmcia_device *p_dev)
p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
p_dev->io.IOAddrLines = 3;
p_dev->conf.IntType = INT_MEMORY_AND_IO;
- p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
+ p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
if (!p_dev->priv) {
return -ENOMEM;
}
- memset(p_dev->priv, 0, sizeof(struct ixj_info_t));
return ixj_config(p_dev);
}
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
new file mode 100644
index 000000000000..b778ed71f636
--- /dev/null
+++ b/drivers/uio/Kconfig
@@ -0,0 +1,29 @@
+menu "Userspace I/O"
+ depends on !S390
+
+config UIO
+ tristate "Userspace I/O drivers"
+ default n
+ help
+ Enable this to allow the userspace driver core code to be
+ built. This code allows userspace programs easy access to
+ kernel interrupts and memory locations, allowing some drivers
+ to be written in userspace. Note that a small kernel driver
+ is also required for interrupt handling to work properly.
+
+ If you don't know what to do here, say N.
+
+config UIO_CIF
+ tristate "generic Hilscher CIF Card driver"
+ depends on UIO && PCI
+ default n
+ help
+ Driver for Hilscher CIF DeviceNet and Profibus cards. This
+ driver requires a userspace component that handles all of the
+ heavy lifting and can be found at:
+ http://www.osadl.org/projects/downloads/UIO/user/cif-*
+
+ To compile this driver as a module, choose M here: the module
+ will be called uio_cif.
+
+endmenu
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
new file mode 100644
index 000000000000..7fecfb459da5
--- /dev/null
+++ b/drivers/uio/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_UIO) += uio.o
+obj-$(CONFIG_UIO_CIF) += uio_cif.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
new file mode 100644
index 000000000000..865f32b63b5c
--- /dev/null
+++ b/drivers/uio/uio.c
@@ -0,0 +1,701 @@
+/*
+ * drivers/uio/uio.c
+ *
+ * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * Userspace IO
+ *
+ * Base Functions
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/idr.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/uio_driver.h>
+
+#define UIO_MAX_DEVICES 255
+
+struct uio_device {
+ struct module *owner;
+ struct device *dev;
+ int minor;
+ atomic_t event;
+ struct fasync_struct *async_queue;
+ wait_queue_head_t wait;
+ int vma_count;
+ struct uio_info *info;
+ struct kset map_attr_kset;
+};
+
+static int uio_major;
+static DEFINE_IDR(uio_idr);
+static struct file_operations uio_fops;
+
+/* UIO class infrastructure */
+static struct uio_class {
+ struct kref kref;
+ struct class *class;
+} *uio_class;
+
+/*
+ * attributes
+ */
+
+static struct attribute attr_addr = {
+ .name = "addr",
+ .mode = S_IRUGO,
+};
+
+static struct attribute attr_size = {
+ .name = "size",
+ .mode = S_IRUGO,
+};
+
+static struct attribute* map_attrs[] = {
+ &attr_addr, &attr_size, NULL
+};
+
+static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
+
+ if (strncmp(attr->name,"addr",4) == 0)
+ return sprintf(buf, "0x%lx\n", mem->addr);
+
+ if (strncmp(attr->name,"size",4) == 0)
+ return sprintf(buf, "0x%lx\n", mem->size);
+
+ return -ENODEV;
+}
+
+static void map_attr_release(struct kobject *kobj)
+{
+ /* TODO ??? */
+}
+
+static struct sysfs_ops map_attr_ops = {
+ .show = map_attr_show,
+};
+
+static struct kobj_type map_attr_type = {
+ .release = map_attr_release,
+ .sysfs_ops = &map_attr_ops,
+ .default_attrs = map_attrs,
+};
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uio_device *idev = dev_get_drvdata(dev);
+ if (idev)
+ return sprintf(buf, "%s\n", idev->info->name);
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static ssize_t show_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uio_device *idev = dev_get_drvdata(dev);
+ if (idev)
+ return sprintf(buf, "%s\n", idev->info->version);
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_event(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct uio_device *idev = dev_get_drvdata(dev);
+ if (idev)
+ return sprintf(buf, "%u\n",
+ (unsigned int)atomic_read(&idev->event));
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
+
+static struct attribute *uio_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_version.attr,
+ &dev_attr_event.attr,
+ NULL,
+};
+
+static struct attribute_group uio_attr_grp = {
+ .attrs = uio_attrs,
+};
+
+/*
+ * device functions
+ */
+static int uio_dev_add_attributes(struct uio_device *idev)
+{
+ int ret;
+ int mi;
+ int map_found = 0;
+ struct uio_mem *mem;
+
+ ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
+ if (ret)
+ goto err_group;
+
+ for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+ mem = &idev->info->mem[mi];
+ if (mem->size == 0)
+ break;
+ if (!map_found) {
+ map_found = 1;
+ kobject_set_name(&idev->map_attr_kset.kobj,"maps");
+ idev->map_attr_kset.ktype = &map_attr_type;
+ idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
+ ret = kset_register(&idev->map_attr_kset);
+ if (ret)
+ goto err_remove_group;
+ }
+ kobject_init(&mem->kobj);
+ kobject_set_name(&mem->kobj,"map%d",mi);
+ mem->kobj.parent = &idev->map_attr_kset.kobj;
+ mem->kobj.kset = &idev->map_attr_kset;
+ ret = kobject_add(&mem->kobj);
+ if (ret)
+ goto err_remove_maps;
+ }
+
+ return 0;
+
+err_remove_maps:
+ for (mi--; mi>=0; mi--) {
+ mem = &idev->info->mem[mi];
+ kobject_unregister(&mem->kobj);
+ }
+ kset_unregister(&idev->map_attr_kset); /* Needed ? */
+err_remove_group:
+ sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+err_group:
+ dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
+ return ret;
+}
+
+static void uio_dev_del_attributes(struct uio_device *idev)
+{
+ int mi;
+ struct uio_mem *mem;
+ for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+ mem = &idev->info->mem[mi];
+ if (mem->size == 0)
+ break;
+ kobject_unregister(&mem->kobj);
+ }
+ kset_unregister(&idev->map_attr_kset);
+ sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+}
+
+static int uio_get_minor(struct uio_device *idev)
+{
+ static DEFINE_MUTEX(minor_lock);
+ int retval = -ENOMEM;
+ int id;
+
+ mutex_lock(&minor_lock);
+ if (idr_pre_get(&uio_idr, GFP_KERNEL) == 0)
+ goto exit;
+
+ retval = idr_get_new(&uio_idr, idev, &id);
+ if (retval < 0) {
+ if (retval == -EAGAIN)
+ retval = -ENOMEM;
+ goto exit;
+ }
+ idev->minor = id & MAX_ID_MASK;
+exit:
+ mutex_unlock(&minor_lock);
+ return retval;
+}
+
+static void uio_free_minor(struct uio_device *idev)
+{
+ idr_remove(&uio_idr, idev->minor);
+}
+
+/**
+ * uio_event_notify - trigger an interrupt event
+ * @info: UIO device capabilities
+ */
+void uio_event_notify(struct uio_info *info)
+{
+ struct uio_device *idev = info->uio_dev;
+
+ atomic_inc(&idev->event);
+ wake_up_interruptible(&idev->wait);
+ kill_fasync(&idev->async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL_GPL(uio_event_notify);
+
+/**
+ * uio_interrupt - hardware interrupt handler
+ * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer
+ * @dev_id: Pointer to the devices uio_device structure
+ */
+static irqreturn_t uio_interrupt(int irq, void *dev_id)
+{
+ struct uio_device *idev = (struct uio_device *)dev_id;
+ irqreturn_t ret = idev->info->handler(irq, idev->info);
+
+ if (ret == IRQ_HANDLED)
+ uio_event_notify(idev->info);
+
+ return ret;
+}
+
+struct uio_listener {
+ struct uio_device *dev;
+ s32 event_count;
+};
+
+static int uio_open(struct inode *inode, struct file *filep)
+{
+ struct uio_device *idev;
+ struct uio_listener *listener;
+ int ret = 0;
+
+ idev = idr_find(&uio_idr, iminor(inode));
+ if (!idev)
+ return -ENODEV;
+
+ listener = kmalloc(sizeof(*listener), GFP_KERNEL);
+ if (!listener)
+ return -ENOMEM;
+
+ listener->dev = idev;
+ listener->event_count = atomic_read(&idev->event);
+ filep->private_data = listener;
+
+ if (idev->info->open) {
+ if (!try_module_get(idev->owner))
+ return -ENODEV;
+ ret = idev->info->open(idev->info, inode);
+ module_put(idev->owner);
+ }
+
+ if (ret)
+ kfree(listener);
+
+ return ret;
+}
+
+static int uio_fasync(int fd, struct file *filep, int on)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+
+ return fasync_helper(fd, filep, on, &idev->async_queue);
+}
+
+static int uio_release(struct inode *inode, struct file *filep)
+{
+ int ret = 0;
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+
+ if (idev->info->release) {
+ if (!try_module_get(idev->owner))
+ return -ENODEV;
+ ret = idev->info->release(idev->info, inode);
+ module_put(idev->owner);
+ }
+ if (filep->f_flags & FASYNC)
+ ret = uio_fasync(-1, filep, 0);
+ kfree(listener);
+ return ret;
+}
+
+static unsigned int uio_poll(struct file *filep, poll_table *wait)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+
+ if (idev->info->irq == UIO_IRQ_NONE)
+ return -EIO;
+
+ poll_wait(filep, &idev->wait, wait);
+ if (listener->event_count != atomic_read(&idev->event))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static ssize_t uio_read(struct file *filep, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t retval;
+ s32 event_count;
+
+ if (idev->info->irq == UIO_IRQ_NONE)
+ return -EIO;
+
+ if (count != sizeof(s32))
+ return -EINVAL;
+
+ add_wait_queue(&idev->wait, &wait);
+
+ do {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ event_count = atomic_read(&idev->event);
+ if (event_count != listener->event_count) {
+ if (copy_to_user(buf, &event_count, count))
+ retval = -EFAULT;
+ else {
+ listener->event_count = event_count;
+ retval = count;
+ }
+ break;
+ }
+
+ if (filep->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ } while (1);
+
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&idev->wait, &wait);
+
+ return retval;
+}
+
+static int uio_find_mem_index(struct vm_area_struct *vma)
+{
+ int mi;
+ struct uio_device *idev = vma->vm_private_data;
+
+ for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+ if (idev->info->mem[mi].size == 0)
+ return -1;
+ if (vma->vm_pgoff == mi)
+ return mi;
+ }
+ return -1;
+}
+
+static void uio_vma_open(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ idev->vma_count++;
+}
+
+static void uio_vma_close(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ idev->vma_count--;
+}
+
+static struct page *uio_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ struct page* page = NOPAGE_SIGBUS;
+
+ int mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return page;
+
+ if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
+ page = virt_to_page(idev->info->mem[mi].addr);
+ else
+ page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
+ get_page(page);
+ if (type)
+ *type = VM_FAULT_MINOR;
+ return page;
+}
+
+static struct vm_operations_struct uio_vm_ops = {
+ .open = uio_vma_open,
+ .close = uio_vma_close,
+ .nopage = uio_vma_nopage,
+};
+
+static int uio_mmap_physical(struct vm_area_struct *vma)
+{
+ struct uio_device *idev = vma->vm_private_data;
+ int mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return -EINVAL;
+
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ return remap_pfn_range(vma,
+ vma->vm_start,
+ idev->info->mem[mi].addr >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &uio_vm_ops;
+ uio_vma_open(vma);
+ return 0;
+}
+
+static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+ struct uio_listener *listener = filep->private_data;
+ struct uio_device *idev = listener->dev;
+ int mi;
+ unsigned long requested_pages, actual_pages;
+ int ret = 0;
+
+ if (vma->vm_end < vma->vm_start)
+ return -EINVAL;
+
+ vma->vm_private_data = idev;
+
+ mi = uio_find_mem_index(vma);
+ if (mi < 0)
+ return -EINVAL;
+
+ requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ actual_pages = (idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
+ if (requested_pages > actual_pages)
+ return -EINVAL;
+
+ if (idev->info->mmap) {
+ if (!try_module_get(idev->owner))
+ return -ENODEV;
+ ret = idev->info->mmap(idev->info, vma);
+ module_put(idev->owner);
+ return ret;
+ }
+
+ switch (idev->info->mem[mi].memtype) {
+ case UIO_MEM_PHYS:
+ return uio_mmap_physical(vma);
+ case UIO_MEM_LOGICAL:
+ case UIO_MEM_VIRTUAL:
+ return uio_mmap_logical(vma);
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct file_operations uio_fops = {
+ .owner = THIS_MODULE,
+ .open = uio_open,
+ .release = uio_release,
+ .read = uio_read,
+ .mmap = uio_mmap,
+ .poll = uio_poll,
+ .fasync = uio_fasync,
+};
+
+static int uio_major_init(void)
+{
+ uio_major = register_chrdev(0, "uio", &uio_fops);
+ if (uio_major < 0)
+ return uio_major;
+ return 0;
+}
+
+static void uio_major_cleanup(void)
+{
+ unregister_chrdev(uio_major, "uio");
+}
+
+static int init_uio_class(void)
+{
+ int ret = 0;
+
+ if (uio_class != NULL) {
+ kref_get(&uio_class->kref);
+ goto exit;
+ }
+
+ /* This is the first time in here, set everything up properly */
+ ret = uio_major_init();
+ if (ret)
+ goto exit;
+
+ uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL);
+ if (!uio_class) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ kref_init(&uio_class->kref);
+ uio_class->class = class_create(THIS_MODULE, "uio");
+ if (IS_ERR(uio_class->class)) {
+ ret = IS_ERR(uio_class->class);
+ printk(KERN_ERR "class_create failed for uio\n");
+ goto err_class_create;
+ }
+ return 0;
+
+err_class_create:
+ kfree(uio_class);
+ uio_class = NULL;
+err_kzalloc:
+ uio_major_cleanup();
+exit:
+ return ret;
+}
+
+static void release_uio_class(struct kref *kref)
+{
+ /* Ok, we cheat as we know we only have one uio_class */
+ class_destroy(uio_class->class);
+ kfree(uio_class);
+ uio_major_cleanup();
+ uio_class = NULL;
+}
+
+static void uio_class_destroy(void)
+{
+ if (uio_class)
+ kref_put(&uio_class->kref, release_uio_class);
+}
+
+/**
+ * uio_register_device - register a new userspace IO device
+ * @owner: module that creates the new device
+ * @parent: parent device
+ * @info: UIO device capabilities
+ *
+ * returns zero on success or a negative error code.
+ */
+int __uio_register_device(struct module *owner,
+ struct device *parent,
+ struct uio_info *info)
+{
+ struct uio_device *idev;
+ int ret = 0;
+
+ if (!parent || !info || !info->name || !info->version)
+ return -EINVAL;
+
+ info->uio_dev = NULL;
+
+ ret = init_uio_class();
+ if (ret)
+ return ret;
+
+ idev = kzalloc(sizeof(*idev), GFP_KERNEL);
+ if (!idev) {
+ ret = -ENOMEM;
+ goto err_kzalloc;
+ }
+
+ idev->owner = owner;
+ idev->info = info;
+ init_waitqueue_head(&idev->wait);
+ atomic_set(&idev->event, 0);
+
+ ret = uio_get_minor(idev);
+ if (ret)
+ goto err_get_minor;
+
+ idev->dev = device_create(uio_class->class, parent,
+ MKDEV(uio_major, idev->minor),
+ "uio%d", idev->minor);
+ if (IS_ERR(idev->dev)) {
+ printk(KERN_ERR "UIO: device register failed\n");
+ ret = PTR_ERR(idev->dev);
+ goto err_device_create;
+ }
+ dev_set_drvdata(idev->dev, idev);
+
+ ret = uio_dev_add_attributes(idev);
+ if (ret)
+ goto err_uio_dev_add_attributes;
+
+ info->uio_dev = idev;
+
+ if (idev->info->irq >= 0) {
+ ret = request_irq(idev->info->irq, uio_interrupt,
+ idev->info->irq_flags, idev->info->name, idev);
+ if (ret)
+ goto err_request_irq;
+ }
+
+ return 0;
+
+err_request_irq:
+ uio_dev_del_attributes(idev);
+err_uio_dev_add_attributes:
+ device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+err_device_create:
+ uio_free_minor(idev);
+err_get_minor:
+ kfree(idev);
+err_kzalloc:
+ uio_class_destroy();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__uio_register_device);
+
+/**
+ * uio_unregister_device - unregister a industrial IO device
+ * @info: UIO device capabilities
+ *
+ */
+void uio_unregister_device(struct uio_info *info)
+{
+ struct uio_device *idev;
+
+ if (!info || !info->uio_dev)
+ return;
+
+ idev = info->uio_dev;
+
+ uio_free_minor(idev);
+
+ if (info->irq >= 0)
+ free_irq(info->irq, idev);
+
+ uio_dev_del_attributes(idev);
+
+ dev_set_drvdata(idev->dev, NULL);
+ device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+ kfree(idev);
+ uio_class_destroy();
+
+ return;
+}
+EXPORT_SYMBOL_GPL(uio_unregister_device);
+
+static int __init uio_init(void)
+{
+ return 0;
+}
+
+static void __exit uio_exit(void)
+{
+}
+
+module_init(uio_init)
+module_exit(uio_exit)
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
new file mode 100644
index 000000000000..838bae460831
--- /dev/null
+++ b/drivers/uio/uio_cif.c
@@ -0,0 +1,156 @@
+/*
+ * UIO Hilscher CIF card driver
+ *
+ * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
+ *
+ * Licensed under GPL version 2 only.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+
+#include <asm/io.h>
+
+#ifndef PCI_DEVICE_ID_PLX_9030
+#define PCI_DEVICE_ID_PLX_9030 0x9030
+#endif
+
+#define PLX9030_INTCSR 0x4C
+#define INTSCR_INT1_ENABLE 0x01
+#define INTSCR_INT1_STATUS 0x04
+#define INT1_ENABLED_AND_ACTIVE (INTSCR_INT1_ENABLE | INTSCR_INT1_STATUS)
+
+#define PCI_SUBVENDOR_ID_PEP 0x1518
+#define CIF_SUBDEVICE_PROFIBUS 0x430
+#define CIF_SUBDEVICE_DEVICENET 0x432
+
+
+static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info)
+{
+ void __iomem *plx_intscr = dev_info->mem[0].internal_addr
+ + PLX9030_INTCSR;
+
+ if ((ioread8(plx_intscr) & INT1_ENABLED_AND_ACTIVE)
+ != INT1_ENABLED_AND_ACTIVE)
+ return IRQ_NONE;
+
+ /* Disable interrupt */
+ iowrite8(ioread8(plx_intscr) & ~INTSCR_INT1_ENABLE, plx_intscr);
+ return IRQ_HANDLED;
+}
+
+static int __devinit hilscher_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct uio_info *info;
+
+ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ if (pci_enable_device(dev))
+ goto out_free;
+
+ if (pci_request_regions(dev, "hilscher"))
+ goto out_disable;
+
+ info->mem[0].addr = pci_resource_start(dev, 0);
+ if (!info->mem[0].addr)
+ goto out_release;
+ info->mem[0].internal_addr = ioremap(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+ if (!info->mem[0].internal_addr)
+ goto out_release;
+
+ info->mem[0].size = pci_resource_len(dev, 0);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+ info->mem[1].addr = pci_resource_start(dev, 2);
+ info->mem[1].size = pci_resource_len(dev, 2);
+ info->mem[1].memtype = UIO_MEM_PHYS;
+ switch (id->subdevice) {
+ case CIF_SUBDEVICE_PROFIBUS:
+ info->name = "CIF_Profibus";
+ break;
+ case CIF_SUBDEVICE_DEVICENET:
+ info->name = "CIF_Devicenet";
+ break;
+ default:
+ info->name = "CIF_???";
+ }
+ info->version = "0.0.1";
+ info->irq = dev->irq;
+ info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
+ info->handler = hilscher_handler;
+
+ if (uio_register_device(&dev->dev, info))
+ goto out_unmap;
+
+ pci_set_drvdata(dev, info);
+
+ return 0;
+out_unmap:
+ iounmap(info->mem[0].internal_addr);
+out_release:
+ pci_release_regions(dev);
+out_disable:
+ pci_disable_device(dev);
+out_free:
+ kfree (info);
+ return -ENODEV;
+}
+
+static void hilscher_pci_remove(struct pci_dev *dev)
+{
+ struct uio_info *info = pci_get_drvdata(dev);
+
+ uio_unregister_device(info);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ pci_set_drvdata(dev, NULL);
+ iounmap(info->mem[0].internal_addr);
+
+ kfree (info);
+}
+
+static struct pci_device_id hilscher_pci_ids[] = {
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9030,
+ .subvendor = PCI_SUBVENDOR_ID_PEP,
+ .subdevice = CIF_SUBDEVICE_PROFIBUS,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = PCI_DEVICE_ID_PLX_9030,
+ .subvendor = PCI_SUBVENDOR_ID_PEP,
+ .subdevice = CIF_SUBDEVICE_DEVICENET,
+ },
+ { 0, }
+};
+
+static struct pci_driver hilscher_pci_driver = {
+ .name = "hilscher",
+ .id_table = hilscher_pci_ids,
+ .probe = hilscher_pci_probe,
+ .remove = hilscher_pci_remove,
+};
+
+static int __init hilscher_init_module(void)
+{
+ return pci_register_driver(&hilscher_pci_driver);
+}
+
+static void __exit hilscher_exit_module(void)
+{
+ pci_unregister_driver(&hilscher_pci_driver);
+}
+
+module_init(hilscher_init_module);
+module_exit(hilscher_exit_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 15499b7e33f4..7dd73546bf43 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -2,8 +2,12 @@
# USB device configuration
#
-menu "USB support"
+menuconfig USB_SUPPORT
+ bool "USB support"
depends on HAS_IOMEM
+ default y
+
+if USB_SUPPORT
# Host-side USB depends on having a host controller
# NOTE: dummy_hcd is always an option, but it's ignored here ...
@@ -12,6 +16,7 @@ config USB_ARCH_HAS_HCD
boolean
default y if USB_ARCH_HAS_OHCI
default y if USB_ARCH_HAS_EHCI
+ default y if PCMCIA && !M32R # sl811_cs
default y if ARM # SL-811
default PCI
@@ -130,5 +135,4 @@ source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig"
-endmenu
-
+endif # USB_SUPPORT
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 72464b586990..befff5f9d58c 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
-obj-$(CONFIG_USB_OHCI_AT91) += host/
+obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 8bcf7fe1dd80..02c52f8d5dbf 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -171,7 +171,7 @@ struct cxacru_data {
struct delayed_work poll_work;
u32 card_info[CXINF_MAX];
struct mutex poll_state_serialize;
- int poll_state;
+ enum cxacru_poll_state poll_state;
/* contol handles */
struct mutex cm_serialize;
@@ -226,58 +226,48 @@ static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf)
static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
{
- if (unlikely(value < 0)) {
- return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
- value / 100, -value % 100);
- } else {
- return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
- value / 100, value % 100);
- }
+ return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
+ value / 100, abs(value) % 100);
}
static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
{
- switch (value) {
- case 0: return snprintf(buf, PAGE_SIZE, "no\n");
- case 1: return snprintf(buf, PAGE_SIZE, "yes\n");
- default: return 0;
- }
+ static char *str[] = { "no", "yes" };
+ if (unlikely(value >= ARRAY_SIZE(str)))
+ return snprintf(buf, PAGE_SIZE, "%u\n", value);
+ return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
{
- switch (value) {
- case 1: return snprintf(buf, PAGE_SIZE, "not connected\n");
- case 2: return snprintf(buf, PAGE_SIZE, "connected\n");
- case 3: return snprintf(buf, PAGE_SIZE, "lost\n");
- default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
- }
+ static char *str[] = { NULL, "not connected", "connected", "lost" };
+ if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
+ return snprintf(buf, PAGE_SIZE, "%u\n", value);
+ return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
{
- switch (value) {
- case 0: return snprintf(buf, PAGE_SIZE, "down\n");
- case 1: return snprintf(buf, PAGE_SIZE, "attempting to activate\n");
- case 2: return snprintf(buf, PAGE_SIZE, "training\n");
- case 3: return snprintf(buf, PAGE_SIZE, "channel analysis\n");
- case 4: return snprintf(buf, PAGE_SIZE, "exchange\n");
- case 5: return snprintf(buf, PAGE_SIZE, "up\n");
- case 6: return snprintf(buf, PAGE_SIZE, "waiting\n");
- case 7: return snprintf(buf, PAGE_SIZE, "initialising\n");
- default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
- }
+ static char *str[] = { "down", "attempting to activate",
+ "training", "channel analysis", "exchange", "up",
+ "waiting", "initialising"
+ };
+ if (unlikely(value >= ARRAY_SIZE(str)))
+ return snprintf(buf, PAGE_SIZE, "%u\n", value);
+ return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
{
- switch (value) {
- case 0: return 0;
- case 1: return snprintf(buf, PAGE_SIZE, "ANSI T1.413\n");
- case 2: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.1 (G.DMT)\n");
- case 3: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.2 (G.LITE)\n");
- default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
- }
+ static char *str[] = {
+ NULL,
+ "ANSI T1.413",
+ "ITU-T G.992.1 (G.DMT)",
+ "ITU-T G.992.2 (G.LITE)"
+ };
+ if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
+ return snprintf(buf, PAGE_SIZE, "%u\n", value);
+ return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
/*
@@ -308,11 +298,10 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
struct cxacru_data *instance = usbatm_instance->driver_data;
u32 value = instance->card_info[CXINF_LINE_STARTABLE];
- switch (value) {
- case 0: return snprintf(buf, PAGE_SIZE, "running\n");
- case 1: return snprintf(buf, PAGE_SIZE, "stopped\n");
- default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
- }
+ static char *str[] = { "running", "stopped" };
+ if (unlikely(value >= ARRAY_SIZE(str)))
+ return snprintf(buf, PAGE_SIZE, "%u\n", value);
+ return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
@@ -467,7 +456,7 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
int* actual_length)
{
struct timer_list timer;
- int status;
+ int status = urb->status;
init_timer(&timer);
timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
@@ -475,7 +464,6 @@ static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
timer.function = cxacru_timeout_kill;
add_timer(&timer);
wait_for_completion(done);
- status = urb->status;
del_timer_sync(&timer);
if (actual_length)
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 638b8009b3bc..eb0615abff68 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -612,7 +612,8 @@ static void speedtch_handle_int(struct urb *int_urb)
struct speedtch_instance_data *instance = int_urb->context;
struct usbatm_data *usbatm = instance->usbatm;
unsigned int count = int_urb->actual_length;
- int ret = int_urb->status;
+ int status = int_urb->status;
+ int ret;
/* The magic interrupt for "up state" */
static const unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
@@ -621,8 +622,8 @@ static void speedtch_handle_int(struct urb *int_urb)
atm_dbg(usbatm, "%s entered\n", __func__);
- if (ret < 0) {
- atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+ if (status < 0) {
+ atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status);
goto fail;
}
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 4973e147bc79..a1a1c9d467e0 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1168,6 +1168,7 @@ static int uea_kthread(void *data)
struct uea_softc *sc = data;
int ret = -EAGAIN;
+ set_freezable();
uea_enters(INS_TO_USBDEV(sc));
while (!kthread_should_stop()) {
if (ret < 0 || sc->reset)
@@ -1307,11 +1308,13 @@ static void uea_intr(struct urb *urb)
{
struct uea_softc *sc = urb->context;
struct intr_pkt *intr = urb->transfer_buffer;
+ int status = urb->status;
+
uea_enters(INS_TO_USBDEV(sc));
- if (unlikely(urb->status < 0)) {
+ if (unlikely(status < 0)) {
uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
- urb->status);
+ status);
return;
}
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 11e9b15ca45a..e717f5b1caee 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -257,9 +257,10 @@ static void usbatm_complete(struct urb *urb)
{
struct usbatm_channel *channel = urb->context;
unsigned long flags;
+ int status = urb->status;
vdbg("%s: urb 0x%p, status %d, actual_length %d",
- __func__, urb, urb->status, urb->actual_length);
+ __func__, urb, status, urb->actual_length);
/* usually in_interrupt(), but not always */
spin_lock_irqsave(&channel->lock, flags);
@@ -269,16 +270,16 @@ static void usbatm_complete(struct urb *urb)
spin_unlock_irqrestore(&channel->lock, flags);
- if (unlikely(urb->status) &&
+ if (unlikely(status) &&
(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
- urb->status != -EILSEQ ))
+ status != -EILSEQ ))
{
- if (urb->status == -ESHUTDOWN)
+ if (status == -ESHUTDOWN)
return;
if (printk_ratelimit())
atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
- __func__, urb, urb->status);
+ __func__, urb, status);
/* throttle processing in case of an error */
mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
} else
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 0081c1d12687..fe940e0536e0 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -257,9 +257,10 @@ static void acm_ctrl_irq(struct urb *urb)
struct usb_cdc_notification *dr = urb->transfer_buffer;
unsigned char *data;
int newctrl;
- int status;
+ int retval;
+ int status = urb->status;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -267,10 +268,10 @@ static void acm_ctrl_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
goto exit;
}
@@ -311,10 +312,10 @@ static void acm_ctrl_irq(struct urb *urb)
break;
}
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
/* data interface returns incoming bytes, or we got unthrottled */
@@ -324,7 +325,8 @@ static void acm_read_bulk(struct urb *urb)
struct acm_ru *rcv = urb->context;
struct acm *acm = rcv->instance;
int status = urb->status;
- dbg("Entering acm_read_bulk with status %d", urb->status);
+
+ dbg("Entering acm_read_bulk with status %d", status);
if (!ACM_READY(acm))
return;
@@ -1157,6 +1159,9 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
+ { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
+ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+ },
{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6778f9af7943..5192cd9356de 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -1,5 +1,5 @@
/*
- * usblp.c Version 0.13
+ * usblp.c
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
@@ -61,11 +61,11 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.13"
#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
#define DRIVER_DESC "USB Printer Device Class driver"
#define USBLP_BUF_SIZE 8192
+#define USBLP_BUF_SIZE_IN 1024
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
@@ -127,14 +127,22 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
*/
#define STATUS_BUF_SIZE 8
+/*
+ * Locks down the locking order:
+ * ->wmut locks wstatus.
+ * ->mut locks the whole usblp, except [rw]complete, and thus, by indirection,
+ * [rw]status. We only touch status when we know the side idle.
+ * ->lock locks what interrupt accesses.
+ */
struct usblp {
struct usb_device *dev; /* USB device */
- struct mutex mut; /* locks this struct, especially "dev" */
- char *writebuf; /* write transfer_buffer */
+ struct mutex wmut;
+ struct mutex mut;
+ spinlock_t lock; /* locks rcomplete, wcomplete */
char *readbuf; /* read transfer_buffer */
char *statusbuf; /* status transfer_buffer */
- struct urb *readurb, *writeurb; /* The urbs */
- wait_queue_head_t wait; /* Zzzzz ... */
+ struct usb_anchor urbs;
+ wait_queue_head_t rwait, wwait;
int readcount; /* Counter for reads */
int ifnum; /* Interface number */
struct usb_interface *intf; /* The interface */
@@ -147,8 +155,9 @@ struct usblp {
} protocol[USBLP_MAX_PROTOCOLS];
int current_protocol;
int minor; /* minor number of device */
- int wcomplete; /* writing is completed */
- int rcomplete; /* reading is completed */
+ int wcomplete, rcomplete;
+ int wstatus; /* bytes written or error */
+ int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
@@ -166,9 +175,6 @@ static void usblp_dump(struct usblp *usblp) {
dbg("dev=0x%p", usblp->dev);
dbg("present=%d", usblp->present);
dbg("readbuf=0x%p", usblp->readbuf);
- dbg("writebuf=0x%p", usblp->writebuf);
- dbg("readurb=0x%p", usblp->readurb);
- dbg("writeurb=0x%p", usblp->writeurb);
dbg("readcount=%d", usblp->readcount);
dbg("ifnum=%d", usblp->ifnum);
for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
@@ -178,8 +184,8 @@ static void usblp_dump(struct usblp *usblp) {
}
dbg("current_protocol=%d", usblp->current_protocol);
dbg("minor=%d", usblp->minor);
- dbg("wcomplete=%d", usblp->wcomplete);
- dbg("rcomplete=%d", usblp->rcomplete);
+ dbg("wstatus=%d", usblp->wstatus);
+ dbg("rstatus=%d", usblp->rstatus);
dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir);
@@ -222,6 +228,11 @@ static const struct quirk_printer_struct quirk_printers[] = {
{ 0, 0 }
};
+static int usblp_wwait(struct usblp *usblp, int nonblock);
+static int usblp_wtest(struct usblp *usblp, int nonblock);
+static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock);
+static int usblp_rtest(struct usblp *usblp, int nonblock);
+static int usblp_submit_read(struct usblp *usblp);
static int usblp_select_alts(struct usblp *usblp);
static int usblp_set_protocol(struct usblp *usblp, int protocol);
static int usblp_cache_device_id_string(struct usblp *usblp);
@@ -278,34 +289,50 @@ static int proto_bias = -1;
static void usblp_bulk_read(struct urb *urb)
{
struct usblp *usblp = urb->context;
+ int status = urb->status;
- if (unlikely(!usblp || !usblp->dev || !usblp->used))
- return;
-
- if (unlikely(!usblp->present))
- goto unplug;
- if (unlikely(urb->status))
- warn("usblp%d: nonzero read/write bulk status received: %d",
- usblp->minor, urb->status);
+ if (usblp->present && usblp->used) {
+ if (status)
+ printk(KERN_WARNING "usblp%d: "
+ "nonzero read bulk status received: %d\n",
+ usblp->minor, status);
+ }
+ spin_lock(&usblp->lock);
+ if (status < 0)
+ usblp->rstatus = status;
+ else
+ usblp->rstatus = urb->actual_length;
usblp->rcomplete = 1;
-unplug:
- wake_up_interruptible(&usblp->wait);
+ wake_up(&usblp->rwait);
+ spin_unlock(&usblp->lock);
+
+ usb_free_urb(urb);
}
static void usblp_bulk_write(struct urb *urb)
{
struct usblp *usblp = urb->context;
+ int status = urb->status;
- if (unlikely(!usblp || !usblp->dev || !usblp->used))
- return;
- if (unlikely(!usblp->present))
- goto unplug;
- if (unlikely(urb->status))
- warn("usblp%d: nonzero read/write bulk status received: %d",
- usblp->minor, urb->status);
+ if (usblp->present && usblp->used) {
+ if (status)
+ printk(KERN_WARNING "usblp%d: "
+ "nonzero write bulk status received: %d\n",
+ usblp->minor, status);
+ }
+ spin_lock(&usblp->lock);
+ if (status < 0)
+ usblp->wstatus = status;
+ else
+ usblp->wstatus = urb->actual_length;
usblp->wcomplete = 1;
-unplug:
- wake_up_interruptible(&usblp->wait);
+ wake_up(&usblp->wwait);
+ spin_unlock(&usblp->lock);
+
+ /* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
+ kfree(urb->transfer_buffer);
+ urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */
+ usb_free_urb(urb);
}
/*
@@ -322,7 +349,8 @@ static int usblp_check_status(struct usblp *usblp, int err)
error = usblp_read_status (usblp, usblp->statusbuf);
if (error < 0) {
if (printk_ratelimit())
- err("usblp%d: error %d reading printer status",
+ printk(KERN_ERR
+ "usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
@@ -336,8 +364,10 @@ static int usblp_check_status(struct usblp *usblp, int err)
if (~status & LP_PSELECD)
newerr = 2;
- if (newerr != err)
- info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
+ if (newerr != err) {
+ printk(KERN_INFO "usblp%d: %s\n",
+ usblp->minor, usblp_messages[newerr]);
+ }
return newerr;
}
@@ -345,12 +375,9 @@ static int usblp_check_status(struct usblp *usblp, int err)
static int handle_bidir (struct usblp *usblp)
{
if (usblp->bidir && usblp->used && !usblp->sleeping) {
- usblp->readcount = 0;
- usblp->readurb->dev = usblp->dev;
- if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
+ if (usblp_submit_read(usblp) < 0)
return -EIO;
}
-
return 0;
}
@@ -403,11 +430,9 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->used = 1;
file->private_data = usblp;
- usblp->writeurb->transfer_buffer_length = 0;
usblp->wcomplete = 1; /* we begin writeable */
+ usblp->wstatus = 0;
usblp->rcomplete = 0;
- usblp->writeurb->status = 0;
- usblp->readurb->status = 0;
if (handle_bidir(usblp) < 0) {
usblp->used = 0;
@@ -421,20 +446,17 @@ out:
static void usblp_cleanup (struct usblp *usblp)
{
- info("usblp%d: removed", usblp->minor);
+ printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
+ kfree(usblp->readbuf);
kfree (usblp->device_id_string);
kfree (usblp->statusbuf);
- usb_free_urb(usblp->writeurb);
- usb_free_urb(usblp->readurb);
kfree (usblp);
}
static void usblp_unlink_urbs(struct usblp *usblp)
{
- usb_kill_urb(usblp->writeurb);
- if (usblp->bidir)
- usb_kill_urb(usblp->readurb);
+ usb_kill_anchored_urbs(&usblp->urbs);
}
static int usblp_release(struct inode *inode, struct file *file)
@@ -455,10 +477,18 @@ static int usblp_release(struct inode *inode, struct file *file)
/* No kernel lock - fine */
static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
{
+ int ret;
+ unsigned long flags;
+
struct usblp *usblp = file->private_data;
- poll_wait(file, &usblp->wait, wait);
- return ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
+ /* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */
+ poll_wait(file, &usblp->rwait, wait);
+ poll_wait(file, &usblp->wwait, wait);
+ spin_lock_irqsave(&usblp->lock, flags);
+ ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
| (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+ spin_unlock_irqrestore(&usblp->lock, flags);
+ return ret;
}
static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -632,10 +662,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case LPGETSTATUS:
- if (usblp_read_status(usblp, usblp->statusbuf)) {
+ if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
if (printk_ratelimit())
- err("usblp%d: failed reading printer status",
- usblp->minor);
+ printk(KERN_ERR "usblp%d:"
+ "failed reading printer status (%d)\n",
+ usblp->minor, retval);
retval = -EIO;
goto done;
}
@@ -656,168 +687,304 @@ done:
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- int timeout, intr, rv, err = 0, transfer_length = 0;
- size_t writecount = 0;
+ char *writebuf;
+ struct urb *writeurb;
+ int rv;
+ int transfer_length;
+ ssize_t writecount = 0;
+
+ if (mutex_lock_interruptible(&usblp->wmut)) {
+ rv = -EINTR;
+ goto raise_biglock;
+ }
+ if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0)
+ goto raise_wait;
while (writecount < count) {
- if (!usblp->wcomplete) {
- barrier();
- if (file->f_flags & O_NONBLOCK) {
- writecount += transfer_length;
- return writecount ? writecount : -EAGAIN;
- }
-
- timeout = USBLP_WRITE_TIMEOUT;
-
- rv = wait_event_interruptible_timeout(usblp->wait, usblp->wcomplete || !usblp->present , timeout);
- if (rv < 0)
- return writecount ? writecount : -EINTR;
- }
- intr = mutex_lock_interruptible (&usblp->mut);
- if (intr)
- return writecount ? writecount : -EINTR;
- if (!usblp->present) {
- mutex_unlock (&usblp->mut);
- return -ENODEV;
- }
-
- if (usblp->sleeping) {
- mutex_unlock (&usblp->mut);
- return writecount ? writecount : -ENODEV;
- }
-
- if (usblp->writeurb->status != 0) {
- if (usblp->quirks & USBLP_QUIRK_BIDIR) {
- if (!usblp->wcomplete)
- err("usblp%d: error %d writing to printer",
- usblp->minor, usblp->writeurb->status);
- err = usblp->writeurb->status;
- } else
- err = usblp_check_status(usblp, err);
- mutex_unlock (&usblp->mut);
-
- /* if the fault was due to disconnect, let khubd's
- * call to usblp_disconnect() grab usblp->mut ...
- */
- schedule ();
- continue;
- }
-
- /* We must increment writecount here, and not at the
- * end of the loop. Otherwise, the final loop iteration may
- * be skipped, leading to incomplete printer output.
+ /*
+ * Step 1: Submit next block.
*/
- writecount += transfer_length;
- if (writecount == count) {
- mutex_unlock(&usblp->mut);
- break;
- }
-
- transfer_length=(count - writecount);
- if (transfer_length > USBLP_BUF_SIZE)
+ if ((transfer_length = count - writecount) > USBLP_BUF_SIZE)
transfer_length = USBLP_BUF_SIZE;
- usblp->writeurb->transfer_buffer_length = transfer_length;
-
- if (copy_from_user(usblp->writeurb->transfer_buffer,
+ rv = -ENOMEM;
+ if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
+ goto raise_buf;
+ if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+ goto raise_urb;
+ usb_fill_bulk_urb(writeurb, usblp->dev,
+ usb_sndbulkpipe(usblp->dev,
+ usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+ writebuf, transfer_length, usblp_bulk_write, usblp);
+ usb_anchor_urb(writeurb, &usblp->urbs);
+
+ if (copy_from_user(writebuf,
buffer + writecount, transfer_length)) {
- mutex_unlock(&usblp->mut);
- return writecount ? writecount : -EFAULT;
+ rv = -EFAULT;
+ goto raise_badaddr;
}
- usblp->writeurb->dev = usblp->dev;
+ spin_lock_irq(&usblp->lock);
usblp->wcomplete = 0;
- err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
- if (err) {
+ spin_unlock_irq(&usblp->lock);
+ if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
+ usblp->wstatus = 0;
+ spin_lock_irq(&usblp->lock);
usblp->wcomplete = 1;
- if (err != -ENOMEM)
- count = -EIO;
- else
- count = writecount ? writecount : -ENOMEM;
- mutex_unlock (&usblp->mut);
- break;
+ wake_up(&usblp->wwait);
+ spin_unlock_irq(&usblp->lock);
+ if (rv != -ENOMEM)
+ rv = -EIO;
+ goto raise_submit;
}
- mutex_unlock (&usblp->mut);
+
+ /*
+ * Step 2: Wait for transfer to end, collect results.
+ */
+ rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
+ if (rv < 0) {
+ if (rv == -EAGAIN) {
+ /* Presume that it's going to complete well. */
+ writecount += transfer_length;
+ }
+ /* Leave URB dangling, to be cleaned on close. */
+ goto collect_error;
+ }
+
+ if (usblp->wstatus < 0) {
+ usblp_check_status(usblp, 0);
+ rv = -EIO;
+ goto collect_error;
+ }
+ /*
+ * This is critical: it must be our URB, not other writer's.
+ * The wmut exists mainly to cover us here.
+ */
+ writecount += usblp->wstatus;
}
- return count;
+ mutex_unlock(&usblp->wmut);
+ return writecount;
+
+raise_submit:
+raise_badaddr:
+ usb_unanchor_urb(writeurb);
+ usb_free_urb(writeurb);
+raise_urb:
+ kfree(writebuf);
+raise_buf:
+raise_wait:
+collect_error: /* Out of raise sequence */
+ mutex_unlock(&usblp->wmut);
+raise_biglock:
+ return writecount ? writecount : rv;
}
-static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+/*
+ * Notice that we fail to restart in a few cases: on EFAULT, on restart
+ * error, etc. This is the historical behaviour. In all such cases we return
+ * EIO, and applications loop in order to get the new read going.
+ */
+static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
- int rv, intr;
+ ssize_t count;
+ ssize_t avail;
+ int rv;
if (!usblp->bidir)
return -EINVAL;
- intr = mutex_lock_interruptible (&usblp->mut);
- if (intr)
- return -EINTR;
- if (!usblp->present) {
- count = -ENODEV;
+ rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK));
+ if (rv < 0)
+ return rv;
+
+ if ((avail = usblp->rstatus) < 0) {
+ printk(KERN_ERR "usblp%d: error %d reading from printer\n",
+ usblp->minor, (int)avail);
+ usblp_submit_read(usblp);
+ count = -EIO;
goto done;
}
- if (!usblp->rcomplete) {
- barrier();
+ count = len < avail - usblp->readcount ? len : avail - usblp->readcount;
+ if (count != 0 &&
+ copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) {
+ count = -EFAULT;
+ goto done;
+ }
- if (file->f_flags & O_NONBLOCK) {
- count = -EAGAIN;
- goto done;
- }
- mutex_unlock(&usblp->mut);
- rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
- mutex_lock(&usblp->mut);
- if (rv < 0) {
- count = -EINTR;
+ if ((usblp->readcount += count) == avail) {
+ if (usblp_submit_read(usblp) < 0) {
+ /* We don't want to leak USB return codes into errno. */
+ if (count == 0)
+ count = -EIO;
goto done;
}
}
- if (!usblp->present) {
- count = -ENODEV;
- goto done;
+done:
+ mutex_unlock (&usblp->mut);
+ return count;
+}
+
+/*
+ * Wait for the write path to come idle.
+ * This is called under the ->wmut, so the idle path stays idle.
+ *
+ * Our write path has a peculiar property: it does not buffer like a tty,
+ * but waits for the write to succeed. This allows our ->release to bug out
+ * without waiting for writes to drain. But it obviously does not work
+ * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
+ * select(2) or poll(2) to wait for the buffer to drain before closing.
+ * Alternatively, set blocking mode with fcntl and issue a zero-size write.
+ *
+ * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
+ * to check the return code for timeout expiration, so it had no effect.
+ * Apparently, it was intended to check for error conditons, such as out
+ * of paper. It is going to return when we settle things with CUPS. XXX
+ */
+static int usblp_wwait(struct usblp *usblp, int nonblock)
+{
+ DECLARE_WAITQUEUE(waita, current);
+ int rc;
+
+ add_wait_queue(&usblp->wwait, &waita);
+ for (;;) {
+ if (mutex_lock_interruptible(&usblp->mut)) {
+ rc = -EINTR;
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
+ mutex_unlock(&usblp->mut);
+ break;
+ }
+ mutex_unlock(&usblp->mut);
+ if (rc == 0)
+ break;
+ schedule();
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&usblp->wwait, &waita);
+ return rc;
+}
- if (usblp->sleeping) {
- count = -ENODEV;
- goto done;
+static int usblp_wtest(struct usblp *usblp, int nonblock)
+{
+ unsigned long flags;
+
+ if (!usblp->present)
+ return -ENODEV;
+ if (signal_pending(current))
+ return -EINTR;
+ spin_lock_irqsave(&usblp->lock, flags);
+ if (usblp->wcomplete) {
+ spin_unlock_irqrestore(&usblp->lock, flags);
+ return 0;
}
+ spin_unlock_irqrestore(&usblp->lock, flags);
+ if (usblp->sleeping)
+ return -ENODEV;
+ if (nonblock)
+ return -EAGAIN;
+ return 1;
+}
- if (usblp->readurb->status) {
- err("usblp%d: error %d reading from printer",
- usblp->minor, usblp->readurb->status);
- usblp->readurb->dev = usblp->dev;
- usblp->readcount = 0;
- usblp->rcomplete = 0;
- if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
- dbg("error submitting urb");
- count = -EIO;
- goto done;
+/*
+ * Wait for read bytes to become available. This probably should have been
+ * called usblp_r_lock_and_wait(), because we lock first. But it's a traditional
+ * name for functions which lock and return.
+ *
+ * We do not use wait_event_interruptible because it makes locking iffy.
+ */
+static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock)
+{
+ DECLARE_WAITQUEUE(waita, current);
+ int rc;
+
+ add_wait_queue(&usblp->rwait, &waita);
+ for (;;) {
+ if (mutex_lock_interruptible(&usblp->mut)) {
+ rc = -EINTR;
+ break;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ((rc = usblp_rtest(usblp, nonblock)) < 0) {
+ mutex_unlock(&usblp->mut);
+ break;
+ }
+ if (rc == 0) /* Keep it locked */
+ break;
+ mutex_unlock(&usblp->mut);
+ schedule();
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&usblp->rwait, &waita);
+ return rc;
+}
- count = count < usblp->readurb->actual_length - usblp->readcount ?
- count : usblp->readurb->actual_length - usblp->readcount;
+static int usblp_rtest(struct usblp *usblp, int nonblock)
+{
+ unsigned long flags;
- if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
- count = -EFAULT;
- goto done;
+ if (!usblp->present)
+ return -ENODEV;
+ if (signal_pending(current))
+ return -EINTR;
+ spin_lock_irqsave(&usblp->lock, flags);
+ if (usblp->rcomplete) {
+ spin_unlock_irqrestore(&usblp->lock, flags);
+ return 0;
}
+ spin_unlock_irqrestore(&usblp->lock, flags);
+ if (usblp->sleeping)
+ return -ENODEV;
+ if (nonblock)
+ return -EAGAIN;
+ return 1;
+}
- if ((usblp->readcount += count) == usblp->readurb->actual_length) {
- usblp->readcount = 0;
- usblp->readurb->dev = usblp->dev;
- usblp->rcomplete = 0;
- if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
- count = -EIO;
- goto done;
- }
+/*
+ * Please check ->bidir and other such things outside for now.
+ */
+static int usblp_submit_read(struct usblp *usblp)
+{
+ struct urb *urb;
+ unsigned long flags;
+ int rc;
+
+ rc = -ENOMEM;
+ if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+ goto raise_urb;
+
+ usb_fill_bulk_urb(urb, usblp->dev,
+ usb_rcvbulkpipe(usblp->dev,
+ usblp->protocol[usblp->current_protocol].epread->bEndpointAddress),
+ usblp->readbuf, USBLP_BUF_SIZE_IN,
+ usblp_bulk_read, usblp);
+ usb_anchor_urb(urb, &usblp->urbs);
+
+ spin_lock_irqsave(&usblp->lock, flags);
+ usblp->readcount = 0; /* XXX Why here? */
+ usblp->rcomplete = 0;
+ spin_unlock_irqrestore(&usblp->lock, flags);
+ if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
+ dbg("error submitting urb (%d)", rc);
+ spin_lock_irqsave(&usblp->lock, flags);
+ usblp->rstatus = rc;
+ usblp->rcomplete = 1;
+ spin_unlock_irqrestore(&usblp->lock, flags);
+ goto raise_submit;
}
-done:
- mutex_unlock (&usblp->mut);
- return count;
+ return 0;
+
+raise_submit:
+ usb_unanchor_urb(urb);
+ usb_free_urb(urb);
+raise_urb:
+ return rc;
}
/*
@@ -891,55 +1058,41 @@ static int usblp_probe(struct usb_interface *intf,
/* Malloc and start initializing usblp structure so we can use it
* directly. */
if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
- err("out of memory for usblp");
+ retval = -ENOMEM;
goto abort;
}
usblp->dev = dev;
+ mutex_init(&usblp->wmut);
mutex_init (&usblp->mut);
- init_waitqueue_head(&usblp->wait);
+ spin_lock_init(&usblp->lock);
+ init_waitqueue_head(&usblp->rwait);
+ init_waitqueue_head(&usblp->wwait);
+ init_usb_anchor(&usblp->urbs);
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
usblp->intf = intf;
- usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!usblp->writeurb) {
- err("out of memory");
- goto abort;
- }
- usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!usblp->readurb) {
- err("out of memory");
- goto abort;
- }
-
/* Malloc device ID string buffer to the largest expected length,
* since we can re-query it on an ioctl and a dynamic string
* could change in length. */
if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
- err("out of memory for device_id_string");
+ retval = -ENOMEM;
goto abort;
}
- usblp->writebuf = usblp->readbuf = NULL;
- usblp->writeurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
- usblp->readurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
- /* Malloc write & read buffers. We somewhat wastefully
+ /*
+ * Allocate read buffer. We somewhat wastefully
* malloc both regardless of bidirectionality, because the
- * alternate setting can be changed later via an ioctl. */
- if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
- GFP_KERNEL, &usblp->writeurb->transfer_dma))) {
- err("out of memory for write buf");
- goto abort;
- }
- if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
- GFP_KERNEL, &usblp->readurb->transfer_dma))) {
- err("out of memory for read buf");
+ * alternate setting can be changed later via an ioctl.
+ */
+ if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) {
+ retval = -ENOMEM;
goto abort;
}
/* Allocate buffer for printer status */
usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
if (!usblp->statusbuf) {
- err("out of memory for statusbuf");
+ retval = -ENOMEM;
goto abort;
}
@@ -954,12 +1107,15 @@ static int usblp_probe(struct usb_interface *intf,
dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
+ retval = -ENODEV;
goto abort;
}
/* Setup the selected alternate setting and endpoints. */
- if (usblp_set_protocol(usblp, protocol) < 0)
+ if (usblp_set_protocol(usblp, protocol) < 0) {
+ retval = -ENODEV; /* ->probe isn't ->ioctl */
goto abort;
+ }
/* Retrieve and store the device ID string. */
usblp_cache_device_id_string(usblp);
@@ -977,12 +1133,14 @@ static int usblp_probe(struct usb_interface *intf,
retval = usb_register_dev(intf, &usblp_class);
if (retval) {
- err("Not able to get a minor for this device.");
+ printk(KERN_ERR "usblp: Not able to get a minor"
+ " (base %u, slice default): %d\n",
+ USBLP_MINOR_BASE, retval);
goto abort_intfdata;
}
usblp->minor = intf->minor;
- info("usblp%d: USB %sdirectional printer dev %d "
- "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
+ printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
+ "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
usblp->ifnum,
usblp->protocol[usblp->current_protocol].alt_setting,
@@ -997,19 +1155,12 @@ abort_intfdata:
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
abort:
if (usblp) {
- if (usblp->writebuf)
- usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
- usblp->writebuf, usblp->writeurb->transfer_dma);
- if (usblp->readbuf)
- usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
- usblp->readbuf, usblp->readurb->transfer_dma);
+ kfree(usblp->readbuf);
kfree(usblp->statusbuf);
kfree(usblp->device_id_string);
- usb_free_urb(usblp->writeurb);
- usb_free_urb(usblp->readurb);
kfree(usblp);
}
- return -EIO;
+ return retval;
}
/*
@@ -1078,8 +1229,9 @@ static int usblp_select_alts(struct usblp *usblp)
if (ifd->desc.bInterfaceProtocol == 1) {
epread = NULL;
} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
- info("Disabling reads from problem bidirectional "
- "printer on usblp%d", usblp->minor);
+ printk(KERN_INFO "usblp%d: Disabling reads from "
+ "problematic bidirectional printer\n",
+ usblp->minor);
epread = NULL;
}
@@ -1119,25 +1271,12 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
return -EINVAL;
r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
if (r < 0) {
- err("can't set desired altsetting %d on interface %d",
+ printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
alts, usblp->ifnum);
return r;
}
- usb_fill_bulk_urb(usblp->writeurb, usblp->dev,
- usb_sndbulkpipe(usblp->dev,
- usblp->protocol[protocol].epwrite->bEndpointAddress),
- usblp->writebuf, 0,
- usblp_bulk_write, usblp);
-
usblp->bidir = (usblp->protocol[protocol].epread != NULL);
- if (usblp->bidir)
- usb_fill_bulk_urb(usblp->readurb, usblp->dev,
- usb_rcvbulkpipe(usblp->dev,
- usblp->protocol[protocol].epread->bEndpointAddress),
- usblp->readbuf, USBLP_BUF_SIZE,
- usblp_bulk_read, usblp);
-
usblp->current_protocol = protocol;
dbg("usblp%d set protocol %d", usblp->minor, protocol);
return 0;
@@ -1190,13 +1329,11 @@ static void usblp_disconnect(struct usb_interface *intf)
mutex_lock (&usblp_mutex);
mutex_lock (&usblp->mut);
usblp->present = 0;
+ wake_up(&usblp->wwait);
+ wake_up(&usblp->rwait);
usb_set_intfdata (intf, NULL);
usblp_unlink_urbs(usblp);
- usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
- usblp->writebuf, usblp->writeurb->transfer_dma);
- usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
- usblp->readbuf, usblp->readurb->transfer_dma);
mutex_unlock (&usblp->mut);
if (!usblp->used)
@@ -1211,6 +1348,11 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
/* we take no more IO */
usblp->sleeping = 1;
usblp_unlink_urbs(usblp);
+#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
+ /* not strictly necessary, but just in case */
+ wake_up(&usblp->wwait);
+ wake_up(&usblp->rwait);
+#endif
return 0;
}
@@ -1251,12 +1393,7 @@ static struct usb_driver usblp_driver = {
static int __init usblp_init(void)
{
- int retval;
- retval = usb_register(&usblp_driver);
- if (!retval)
- info(DRIVER_VERSION ": " DRIVER_DESC);
-
- return retval;
+ return usb_register(&usblp_driver);
}
static void __exit usblp_exit(void)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 346fc030c929..97b09f282705 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -86,6 +86,31 @@ 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
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index dd3482328ad2..cb69aa1e02e8 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -85,15 +85,21 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
memcpy(&endpoint->desc, d, n);
INIT_LIST_HEAD(&endpoint->urb_list);
- /* If the bInterval value is outside the legal range,
- * set it to a default value: 32 ms */
+ /* Fix up bInterval values outside the legal range. Use 32 ms if no
+ * proper value can be guessed. */
i = 0; /* i = min, j = max, n = default */
j = 255;
if (usb_endpoint_xfer_int(d)) {
i = 1;
switch (to_usb_device(ddev)->speed) {
case USB_SPEED_HIGH:
- n = 9; /* 32 ms = 2^(9-1) uframes */
+ /* Many device manufacturers are using full-speed
+ * bInterval values in high-speed interrupt endpoint
+ * descriptors. Try to fix those and fall back to a
+ * 32 ms default value otherwise. */
+ n = fls(d->bInterval*8);
+ if (n == 0)
+ n = 9; /* 32 ms = 2^(9-1) uframes */
j = 16;
break;
default: /* USB_SPEED_FULL or _LOW */
@@ -124,6 +130,21 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
endpoint->desc.bInterval = n;
}
+ /* Some buggy low-speed devices have Bulk endpoints, which is
+ * explicitly forbidden by the USB spec. In an attempt to make
+ * them usable, we will try treating them as Interrupt endpoints.
+ */
+ if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&
+ usb_endpoint_xfer_bulk(d)) {
+ dev_warn(ddev, "config %d interface %d altsetting %d "
+ "endpoint 0x%X is Bulk; changing to Interrupt\n",
+ cfgno, inum, asnum, d->bEndpointAddress);
+ endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
+ endpoint->desc.bInterval = 1;
+ if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
+ endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
+ }
+
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
@@ -274,6 +295,7 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
struct usb_descriptor_header *header;
int len, retval;
u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
+ unsigned iad_num = 0;
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
@@ -351,6 +373,20 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
++n;
}
+ } else if (header->bDescriptorType ==
+ USB_DT_INTERFACE_ASSOCIATION) {
+ if (iad_num == USB_MAXIADS) {
+ dev_warn(ddev, "found more Interface "
+ "Association Descriptors "
+ "than allocated for in "
+ "configuration %d\n", cfgno);
+ } else {
+ config->intf_assoc[iad_num] =
+ (struct usb_interface_assoc_descriptor
+ *)header;
+ iad_num++;
+ }
+
} else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG)
dev_warn(ddev, "config %d contains an unexpected "
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 6753ca059ee4..87c794d60aa0 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -102,6 +102,10 @@ static const char *format_config =
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
+static const char *format_iad =
+/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
+ "A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
+
static const char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
"I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
@@ -146,6 +150,7 @@ static const struct class_info clas_info[] =
{USB_CLASS_STILL_IMAGE, "still"},
{USB_CLASS_CSCID, "scard"},
{USB_CLASS_CONTENT_SEC, "c-sec"},
+ {USB_CLASS_VIDEO, "video"},
{-1, "unk."} /* leave as last */
};
@@ -286,6 +291,21 @@ static char *usb_dump_interface(
return start;
}
+static char *usb_dump_iad_descriptor(char *start, char *end,
+ const struct usb_interface_assoc_descriptor *iad)
+{
+ if (start > end)
+ return start;
+ start += sprintf(start, format_iad,
+ iad->bFirstInterface,
+ iad->bInterfaceCount,
+ iad->bFunctionClass,
+ class_decode(iad->bFunctionClass),
+ iad->bFunctionSubClass,
+ iad->bFunctionProtocol);
+ return start;
+}
+
/* TBD:
* 0. TBDs
* 1. marking active interface altsettings (code lists all, but should mark
@@ -322,6 +342,12 @@ static char *usb_dump_config (
if (!config) /* getting these some in 2.3.7; none in 2.3.6 */
return start + sprintf(start, "(null Cfg. desc.)\n");
start = usb_dump_config_descriptor(start, end, &config->desc, active);
+ for (i = 0; i < USB_MAXIADS; i++) {
+ if (config->intf_assoc[i] == NULL)
+ break;
+ start = usb_dump_iad_descriptor(start, end,
+ config->intf_assoc[i]);
+ }
for (i = 0; i < config->desc.bNumInterfaces; i++) {
intfc = config->intf_cache[i];
interface = config->interface[i];
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2619986e5300..654857493a82 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -24,10 +24,12 @@
#include <linux/device.h>
#include <linux/usb.h>
+#include <linux/usb/quirks.h>
#include <linux/workqueue.h>
#include "hcd.h"
#include "usb.h"
+
#ifdef CONFIG_HOTPLUG
/*
@@ -802,18 +804,17 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
udev->state == USB_STATE_SUSPENDED)
goto done;
- /* For devices that don't have a driver, we do a standard suspend. */
- if (udev->dev.driver == NULL) {
+ /* For devices that don't have a driver, we do a generic suspend. */
+ if (udev->dev.driver)
+ udriver = to_usb_device_driver(udev->dev.driver);
+ else {
udev->do_remote_wakeup = 0;
- status = usb_port_suspend(udev);
- goto done;
+ udriver = &usb_generic_driver;
}
-
- udriver = to_usb_device_driver(udev->dev.driver);
status = udriver->suspend(udev, msg);
-done:
- // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ done:
+ dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0)
udev->dev.power.power_state.event = msg.event;
return status;
@@ -825,8 +826,9 @@ static int usb_resume_device(struct usb_device *udev)
struct usb_device_driver *udriver;
int status = 0;
- if (udev->state == USB_STATE_NOTATTACHED ||
- udev->state != USB_STATE_SUSPENDED)
+ if (udev->state == USB_STATE_NOTATTACHED)
+ goto done;
+ if (udev->state != USB_STATE_SUSPENDED && !udev->reset_resume)
goto done;
/* Can't resume it if it doesn't have a driver. */
@@ -835,11 +837,14 @@ static int usb_resume_device(struct usb_device *udev)
goto done;
}
+ if (udev->quirks & USB_QUIRK_RESET_RESUME)
+ udev->reset_resume = 1;
+
udriver = to_usb_device_driver(udev->dev.driver);
status = udriver->resume(udev);
-done:
- // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ done:
+ dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0) {
udev->autoresume_disabled = 0;
udev->dev.power.power_state.event = PM_EVENT_ON;
@@ -877,15 +882,13 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
mark_quiesced(intf);
}
-done:
- // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
- if (status == 0)
- intf->dev.power.power_state.event = msg.event;
+ done:
+ dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
return status;
}
/* Caller has locked intf's usb_device's pm_mutex */
-static int usb_resume_interface(struct usb_interface *intf)
+static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
{
struct usb_driver *driver;
int status = 0;
@@ -905,23 +908,37 @@ static int usb_resume_interface(struct usb_interface *intf)
}
driver = to_usb_driver(intf->dev.driver);
- if (driver->resume) {
- status = driver->resume(intf);
- if (status)
- dev_err(&intf->dev, "%s error %d\n",
- "resume", status);
- else
- mark_active(intf);
+ if (reset_resume) {
+ if (driver->reset_resume) {
+ status = driver->reset_resume(intf);
+ if (status)
+ dev_err(&intf->dev, "%s error %d\n",
+ "reset_resume", status);
+ } else {
+ // status = -EOPNOTSUPP;
+ dev_warn(&intf->dev, "no %s for driver %s?\n",
+ "reset_resume", driver->name);
+ }
} else {
- dev_warn(&intf->dev, "no resume for driver %s?\n",
- driver->name);
- mark_active(intf);
+ if (driver->resume) {
+ status = driver->resume(intf);
+ if (status)
+ dev_err(&intf->dev, "%s error %d\n",
+ "resume", status);
+ } else {
+ // status = -EOPNOTSUPP;
+ dev_warn(&intf->dev, "no %s for driver %s?\n",
+ "resume", driver->name);
+ }
}
done:
- // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0)
- intf->dev.power.power_state.event = PM_EVENT_ON;
+ mark_active(intf);
+
+ /* FIXME: Unbind the driver and reprobe if the resume failed
+ * (not possible if auto_pm is set) */
return status;
}
@@ -958,6 +975,18 @@ static int autosuspend_check(struct usb_device *udev)
"for autosuspend\n");
return -EOPNOTSUPP;
}
+
+ /* Don't allow autosuspend if the device will need
+ * a reset-resume and any of its interface drivers
+ * doesn't include support.
+ */
+ if (udev->quirks & USB_QUIRK_RESET_RESUME) {
+ struct usb_driver *driver;
+
+ driver = to_usb_driver(intf->dev.driver);
+ if (!driver->reset_resume)
+ return -EOPNOTSUPP;
+ }
}
}
@@ -974,7 +1003,7 @@ static int autosuspend_check(struct usb_device *udev)
* or for the past.
*/
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
- suspend_time - jiffies);
+ round_jiffies_relative(suspend_time - jiffies));
}
return -EAGAIN;
}
@@ -1054,14 +1083,21 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
- if (status == 0)
+ if (status == 0) {
+
+ /* Non-root devices don't need to do anything for FREEZE
+ * or PRETHAW. */
+ if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
+ msg.event == PM_EVENT_PRETHAW))
+ goto done;
status = usb_suspend_device(udev, msg);
+ }
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
while (--i >= 0) {
intf = udev->actconfig->interface[i];
- usb_resume_interface(intf);
+ usb_resume_interface(intf, 0);
}
/* Try another autosuspend when the interfaces aren't busy */
@@ -1076,7 +1112,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
}
done:
- // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
return status;
}
@@ -1131,7 +1167,8 @@ static int usb_resume_both(struct usb_device *udev)
status = usb_autoresume_device(parent);
if (status == 0) {
status = usb_resume_device(udev);
- if (status) {
+ if (status || udev->state ==
+ USB_STATE_NOTATTACHED) {
usb_autosuspend_device(parent);
/* It's possible usb_resume_device()
@@ -1152,28 +1189,25 @@ static int usb_resume_both(struct usb_device *udev)
/* We can't progagate beyond the USB subsystem,
* so if a root hub's controller is suspended
* then we're stuck. */
- if (udev->dev.parent->power.power_state.event !=
- PM_EVENT_ON)
- status = -EHOSTUNREACH;
- else
- status = usb_resume_device(udev);
+ status = usb_resume_device(udev);
}
} else {
- /* Needed only for setting udev->dev.power.power_state.event
- * and for possible debugging message. */
+ /* Needed for setting udev->dev.power.power_state.event,
+ * for possible debugging message, and for reset_resume. */
status = usb_resume_device(udev);
}
if (status == 0 && udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
- usb_resume_interface(intf);
+ usb_resume_interface(intf, udev->reset_resume);
}
}
done:
- // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ udev->reset_resume = 0;
return status;
}
@@ -1240,8 +1274,8 @@ void usb_autosuspend_device(struct usb_device *udev)
int status;
status = usb_autopm_do_device(udev, -1);
- // dev_dbg(&udev->dev, "%s: cnt %d\n",
- // __FUNCTION__, udev->pm_usage_cnt);
+ dev_vdbg(&udev->dev, "%s: cnt %d\n",
+ __FUNCTION__, udev->pm_usage_cnt);
}
/**
@@ -1260,8 +1294,8 @@ void usb_autosuspend_device(struct usb_device *udev)
void usb_try_autosuspend_device(struct usb_device *udev)
{
usb_autopm_do_device(udev, 0);
- // dev_dbg(&udev->dev, "%s: cnt %d\n",
- // __FUNCTION__, udev->pm_usage_cnt);
+ dev_vdbg(&udev->dev, "%s: cnt %d\n",
+ __FUNCTION__, udev->pm_usage_cnt);
}
/**
@@ -1288,8 +1322,8 @@ int usb_autoresume_device(struct usb_device *udev)
int status;
status = usb_autopm_do_device(udev, 1);
- // dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
- // __FUNCTION__, status, udev->pm_usage_cnt);
+ dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
+ __FUNCTION__, status, udev->pm_usage_cnt);
return status;
}
@@ -1361,8 +1395,8 @@ void usb_autopm_put_interface(struct usb_interface *intf)
int status;
status = usb_autopm_do_interface(intf, -1);
- // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
- // __FUNCTION__, status, intf->pm_usage_cnt);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+ __FUNCTION__, status, intf->pm_usage_cnt);
}
EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
@@ -1405,8 +1439,8 @@ int usb_autopm_get_interface(struct usb_interface *intf)
int status;
status = usb_autopm_do_interface(intf, 1);
- // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
- // __FUNCTION__, status, intf->pm_usage_cnt);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+ __FUNCTION__, status, intf->pm_usage_cnt);
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1427,8 +1461,8 @@ int usb_autopm_set_interface(struct usb_interface *intf)
int status;
status = usb_autopm_do_interface(intf, 0);
- // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
- // __FUNCTION__, status, intf->pm_usage_cnt);
+ dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+ __FUNCTION__, status, intf->pm_usage_cnt);
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
@@ -1508,8 +1542,15 @@ static int usb_resume(struct device *dev)
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
udev = to_usb_device(dev);
- if (udev->autoresume_disabled)
- return -EPERM;
+
+ /* If autoresume is disabled then we also want to prevent resume
+ * during system wakeup. However, a "persistent-device" reset-resume
+ * after power loss counts as a wakeup event. So allow a
+ * reset-resume to occur if remote wakeup is enabled. */
+ if (udev->autoresume_disabled) {
+ if (!(udev->reset_resume && udev->do_remote_wakeup))
+ return -EPERM;
+ }
return usb_external_resume_device(udev);
}
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 01c857ac27af..5d860bc9b421 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -16,15 +16,15 @@
*/
#include <linux/module.h>
-#include <linux/spinlock.h>
#include <linux/errno.h>
+#include <linux/rwsem.h>
#include <linux/usb.h>
#include "usb.h"
#define MAX_USB_MINORS 256
static const struct file_operations *usb_minors[MAX_USB_MINORS];
-static DEFINE_SPINLOCK(minor_lock);
+static DECLARE_RWSEM(minor_rwsem);
static int usb_open(struct inode * inode, struct file * file)
{
@@ -33,14 +33,11 @@ static int usb_open(struct inode * inode, struct file * file)
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
- spin_lock (&minor_lock);
+ down_read(&minor_rwsem);
c = usb_minors[minor];
- if (!c || !(new_fops = fops_get(c))) {
- spin_unlock(&minor_lock);
- return err;
- }
- spin_unlock(&minor_lock);
+ if (!c || !(new_fops = fops_get(c)))
+ goto done;
old_fops = file->f_op;
file->f_op = new_fops;
@@ -52,6 +49,8 @@ static int usb_open(struct inode * inode, struct file * file)
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
+ done:
+ up_read(&minor_rwsem);
return err;
}
@@ -166,7 +165,7 @@ int usb_register_dev(struct usb_interface *intf,
if (class_driver->fops == NULL)
goto exit;
- spin_lock (&minor_lock);
+ down_write(&minor_rwsem);
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
if (usb_minors[minor])
continue;
@@ -176,7 +175,7 @@ int usb_register_dev(struct usb_interface *intf,
retval = 0;
break;
}
- spin_unlock (&minor_lock);
+ up_write(&minor_rwsem);
if (retval)
goto exit;
@@ -197,9 +196,9 @@ int usb_register_dev(struct usb_interface *intf,
intf->usb_dev = device_create(usb_class->class, &intf->dev,
MKDEV(USB_MAJOR, minor), "%s", temp);
if (IS_ERR(intf->usb_dev)) {
- spin_lock (&minor_lock);
+ down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL;
- spin_unlock (&minor_lock);
+ up_write(&minor_rwsem);
retval = PTR_ERR(intf->usb_dev);
}
exit:
@@ -236,9 +235,9 @@ void usb_deregister_dev(struct usb_interface *intf,
dbg ("removing %d minor", intf->minor);
- spin_lock (&minor_lock);
+ down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL;
- spin_unlock (&minor_lock);
+ up_write(&minor_rwsem);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
@@ -247,5 +246,3 @@ void usb_deregister_dev(struct usb_interface *intf,
destroy_usb_class();
}
EXPORT_SYMBOL(usb_deregister_dev);
-
-
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 9bbcb20e2d94..b2fc2b115256 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -19,6 +19,7 @@
#include <linux/usb.h>
#include "usb.h"
+#include "hcd.h"
static inline const char *plural(int n)
{
@@ -193,16 +194,34 @@ static void generic_disconnect(struct usb_device *udev)
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
- /* USB devices enter SUSPEND state through their hubs, but can be
- * marked for FREEZE as soon as their children are already idled.
- * But those semantics are useless, so we equate the two (sigh).
+ int rc;
+
+ /* Normal USB devices suspend through their upstream port.
+ * Root hubs don't have upstream ports to suspend,
+ * so we have to shut down their downstream HC-to-USB
+ * interfaces manually by doing a bus (or "global") suspend.
*/
- return usb_port_suspend(udev);
+ if (!udev->parent)
+ rc = hcd_bus_suspend(udev);
+ else
+ rc = usb_port_suspend(udev);
+ return rc;
}
static int generic_resume(struct usb_device *udev)
{
- return usb_port_resume(udev);
+ int rc;
+
+ /* Normal USB devices resume/reset through their upstream port.
+ * Root hubs don't have upstream ports to resume or reset,
+ * so we have to start up their downstream HC-to-USB
+ * interfaces manually by doing a bus (or "global") resume.
+ */
+ if (!udev->parent)
+ rc = hcd_bus_resume(udev);
+ else
+ rc = usb_port_resume(udev);
+ return rc;
}
#endif /* CONFIG_PM */
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index edf4300a3f7a..5cf6d5f9acbd 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -207,7 +207,8 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
* We must ignore the FREEZE vs SUSPEND distinction here, because
* otherwise the swsusp will save (and restore) garbage state.
*/
- if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON)
+ if (!(hcd->state == HC_STATE_SUSPENDED ||
+ hcd->state == HC_STATE_HALT))
return -EBUSY;
if (hcd->driver->suspend) {
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8969e42434b9..42ef1d5f6c8a 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -99,12 +99,17 @@ EXPORT_SYMBOL_GPL (usb_bus_list_lock);
/* used for controlling access to virtual root hubs */
static DEFINE_SPINLOCK(hcd_root_hub_lock);
-/* used when updating hcd data */
-static DEFINE_SPINLOCK(hcd_data_lock);
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
/* wait queue for synchronous unlinks */
DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
+static inline int is_root_hub(struct usb_device *udev)
+{
+ return (udev->parent == NULL);
+}
+
/*-------------------------------------------------------------------------*/
/*
@@ -582,10 +587,12 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
- * exceed that limit if HZ is 100. */
+ * exceed that limit if HZ is 100. The math is more clunky than
+ * maybe expected, this is to make sure that all timers for USB devices
+ * fire at the same time to give the CPU a break inbetween */
if (hcd->uses_new_polling ? hcd->poll_rh :
(length == 0 && hcd->status_urb != NULL))
- mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
+ mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
}
EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
@@ -614,8 +621,8 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
urb->hcpriv = hcd; /* indicate it's queued */
if (!hcd->uses_new_polling)
- mod_timer (&hcd->rh_timer, jiffies +
- msecs_to_jiffies(250));
+ mod_timer (&hcd->rh_timer,
+ (jiffies/(HZ/4) + 1) * (HZ/4));
/* If a status change has already occurred, report it ASAP */
else if (hcd->poll_pending)
@@ -901,17 +908,31 @@ EXPORT_SYMBOL (usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
-static void urb_unlink (struct urb *urb)
+static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
/* clear all state linking urb to this dev (and hcd) */
-
- spin_lock_irqsave (&hcd_data_lock, flags);
+ spin_lock_irqsave(&hcd_urb_list_lock, flags);
list_del_init (&urb->urb_list);
- spin_unlock_irqrestore (&hcd_data_lock, flags);
-}
+ spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+ if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+ if (usb_pipecontrol (urb->pipe)
+ && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+ dma_unmap_single (hcd->self.controller, urb->setup_dma,
+ sizeof (struct usb_ctrlrequest),
+ DMA_TO_DEVICE);
+ if (urb->transfer_buffer_length != 0
+ && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+ dma_unmap_single (hcd->self.controller,
+ urb->transfer_dma,
+ urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? DMA_FROM_DEVICE
+ : DMA_TO_DEVICE);
+ }
+}
/* may be called in any context with a valid urb->dev usecount
* caller surrenders "ownership" of urb
@@ -938,7 +959,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
// FIXME: verify that quiescing hc works right (RH cleans up)
- spin_lock_irqsave (&hcd_data_lock, flags);
+ spin_lock_irqsave(&hcd_urb_list_lock, flags);
ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (unlikely (!ep))
@@ -948,24 +969,14 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
else switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
-doit:
list_add_tail (&urb->urb_list, &ep->urb_list);
status = 0;
break;
- case HC_STATE_SUSPENDED:
- /* HC upstream links (register access, wakeup signaling) can work
- * even when the downstream links (and DMA etc) are quiesced; let
- * usbcore talk to the root hub.
- */
- if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
- && urb->dev->parent == NULL)
- goto doit;
- /* FALL THROUGH */
default:
status = -ESHUTDOWN;
break;
}
- spin_unlock_irqrestore (&hcd_data_lock, flags);
+ spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
if (status) {
INIT_LIST_HEAD (&urb->urb_list);
usbmon_urb_submit_error(&hcd->self, urb, status);
@@ -979,7 +990,7 @@ doit:
urb = usb_get_urb (urb);
atomic_inc (&urb->use_count);
- if (urb->dev == hcd->self.root_hub) {
+ if (is_root_hub(urb->dev)) {
/* NOTE: requirement on hub callers (usbfs and the hub
* driver, for now) that URBs' urb->transfer_buffer be
* valid and usb_buffer_{sync,unmap}() not be needed, since
@@ -1014,7 +1025,7 @@ doit:
status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
done:
if (unlikely (status)) {
- urb_unlink (urb);
+ urb_unlink(hcd, urb);
atomic_dec (&urb->use_count);
if (urb->reject)
wake_up (&usb_kill_urb_queue);
@@ -1026,18 +1037,6 @@ done:
/*-------------------------------------------------------------------------*/
-/* called in any context */
-int usb_hcd_get_frame_number (struct usb_device *udev)
-{
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
-
- if (!HC_IS_RUNNING (hcd->state))
- return -ESHUTDOWN;
- return hcd->driver->get_frame_number (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
/* this makes the hcd giveback() the urb more quickly, by kicking it
* off hardware queues (which may take a while) and returning it as
* soon as practical. we've already set up the urb's return status,
@@ -1048,7 +1047,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
{
int value;
- if (urb->dev == hcd->self.root_hub)
+ if (is_root_hub(urb->dev))
value = usb_rh_urb_dequeue (hcd, urb);
else {
@@ -1096,11 +1095,11 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
* that it was submitted. But as a rule it can't know whether or
* not it's already been unlinked ... so we respect the reversed
* lock sequence needed for the usb_hcd_giveback_urb() code paths
- * (urb lock, then hcd_data_lock) in case some other CPU is now
+ * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
* unlinking it.
*/
spin_lock_irqsave (&urb->lock, flags);
- spin_lock (&hcd_data_lock);
+ spin_lock(&hcd_urb_list_lock);
sys = &urb->dev->dev;
hcd = bus_to_hcd(urb->dev->bus);
@@ -1132,17 +1131,16 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
* finish unlinking the initial failed usb_set_address()
* or device descriptor fetch.
*/
- if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
- && hcd->self.root_hub != urb->dev) {
+ if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+ !is_root_hub(urb->dev)) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
- "Controller is probably using the wrong IRQ."
- "\n");
+ "Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
urb->status = status;
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
spin_unlock_irqrestore (&urb->lock, flags);
retval = unlink1 (hcd, urb);
@@ -1151,7 +1149,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
return retval;
done:
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
spin_unlock_irqrestore (&urb->lock, flags);
if (retval != -EIDRM && sys && sys->driver)
dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
@@ -1160,6 +1158,35 @@ done:
/*-------------------------------------------------------------------------*/
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function. The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv). It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+ urb_unlink(hcd, urb);
+ usbmon_urb_complete (&hcd->self, urb);
+ usb_unanchor_urb(urb);
+
+ /* pass ownership to the completion handler */
+ urb->complete (urb);
+ atomic_dec (&urb->use_count);
+ if (unlikely (urb->reject))
+ wake_up (&usb_kill_urb_queue);
+ usb_put_urb (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
/* disables the endpoint: cancels any pending urbs, then synchronizes with
* the hcd to make sure all endpoint state is gone from hardware, and then
* waits until the endpoint's queue is completely drained. use for
@@ -1179,7 +1206,7 @@ void usb_hcd_endpoint_disable (struct usb_device *udev,
/* ep is already gone from udev->ep_{in,out}[]; no more submits */
rescan:
- spin_lock (&hcd_data_lock);
+ spin_lock(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
int tmp;
@@ -1187,7 +1214,7 @@ rescan:
if (urb->status != -EINPROGRESS)
continue;
usb_get_urb (urb);
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
spin_lock (&urb->lock);
tmp = urb->status;
@@ -1216,7 +1243,7 @@ rescan:
/* list contents may have changed */
goto rescan;
}
- spin_unlock (&hcd_data_lock);
+ spin_unlock(&hcd_urb_list_lock);
local_irq_enable ();
/* synchronize with the hardware, so old configuration state
@@ -1233,7 +1260,7 @@ rescan:
* endpoint_disable methods.
*/
while (!list_empty (&ep->urb_list)) {
- spin_lock_irq (&hcd_data_lock);
+ spin_lock_irq(&hcd_urb_list_lock);
/* The list may have changed while we acquired the spinlock */
urb = NULL;
@@ -1242,7 +1269,7 @@ rescan:
urb_list);
usb_get_urb (urb);
}
- spin_unlock_irq (&hcd_data_lock);
+ spin_unlock_irq(&hcd_urb_list_lock);
if (urb) {
usb_kill_urb (urb);
@@ -1253,44 +1280,73 @@ rescan:
/*-------------------------------------------------------------------------*/
+/* called in any context */
+int usb_hcd_get_frame_number (struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ if (!HC_IS_RUNNING (hcd->state))
+ return -ESHUTDOWN;
+ return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
#ifdef CONFIG_PM
-int hcd_bus_suspend (struct usb_bus *bus)
+int hcd_bus_suspend(struct usb_device *rhdev)
{
- struct usb_hcd *hcd;
- int status;
+ struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
+ int status;
+ int old_state = hcd->state;
- hcd = container_of (bus, struct usb_hcd, self);
- if (!hcd->driver->bus_suspend)
- return -ENOENT;
- hcd->state = HC_STATE_QUIESCING;
- status = hcd->driver->bus_suspend (hcd);
- if (status == 0)
+ dev_dbg(&rhdev->dev, "bus %s%s\n",
+ rhdev->auto_pm ? "auto-" : "", "suspend");
+ if (!hcd->driver->bus_suspend) {
+ status = -ENOENT;
+ } else {
+ hcd->state = HC_STATE_QUIESCING;
+ status = hcd->driver->bus_suspend(hcd);
+ }
+ if (status == 0) {
+ usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
hcd->state = HC_STATE_SUSPENDED;
- else
- dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+ } else {
+ hcd->state = old_state;
+ dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"suspend", status);
+ }
return status;
}
-int hcd_bus_resume (struct usb_bus *bus)
+int hcd_bus_resume(struct usb_device *rhdev)
{
- struct usb_hcd *hcd;
- int status;
+ struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
+ int status;
+ int old_state = hcd->state;
- hcd = container_of (bus, struct usb_hcd, self);
+ dev_dbg(&rhdev->dev, "usb %s%s\n",
+ rhdev->auto_pm ? "auto-" : "", "resume");
if (!hcd->driver->bus_resume)
return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
return 0;
+
hcd->state = HC_STATE_RESUMING;
- status = hcd->driver->bus_resume (hcd);
- if (status == 0)
+ status = hcd->driver->bus_resume(hcd);
+ if (status == 0) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+ usb_set_device_state(rhdev, rhdev->actconfig
+ ? USB_STATE_CONFIGURED
+ : USB_STATE_ADDRESS);
hcd->state = HC_STATE_RUNNING;
- else {
- dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+ } else {
+ hcd->state = old_state;
+ dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"resume", status);
- usb_hc_died(hcd);
+ if (status != -ESHUTDOWN)
+ usb_hc_died(hcd);
}
return status;
}
@@ -1371,55 +1427,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
/*-------------------------------------------------------------------------*/
/**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function. The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv). It also released all HCD locks;
- * the device driver won't cause problems if it frees, modifies,
- * or resubmits this URB.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
-{
- int at_root_hub;
-
- at_root_hub = (urb->dev == hcd->self.root_hub);
- urb_unlink (urb);
-
- /* lower level hcd code should use *_dma exclusively if the
- * host controller does DMA */
- if (hcd->self.uses_dma && !at_root_hub) {
- if (usb_pipecontrol (urb->pipe)
- && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
- dma_unmap_single (hcd->self.controller, urb->setup_dma,
- sizeof (struct usb_ctrlrequest),
- DMA_TO_DEVICE);
- if (urb->transfer_buffer_length != 0
- && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
- dma_unmap_single (hcd->self.controller,
- urb->transfer_dma,
- urb->transfer_buffer_length,
- usb_pipein (urb->pipe)
- ? DMA_FROM_DEVICE
- : DMA_TO_DEVICE);
- }
-
- usbmon_urb_complete (&hcd->self, urb);
- /* pass ownership to the completion handler */
- urb->complete (urb);
- atomic_dec (&urb->use_count);
- if (unlikely (urb->reject))
- wake_up (&usb_kill_urb_queue);
- usb_put_urb (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
-
-/*-------------------------------------------------------------------------*/
-
-/**
* usb_hcd_irq - hook IRQs to HCD framework (bus glue)
* @irq: the IRQ being raised
* @__hcd: pointer to the HCD whose IRQ is being signaled
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index ef50fa494e47..b5ebb73c2332 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -364,23 +364,13 @@ extern int usb_find_interface_driver (struct usb_device *dev,
#ifdef CONFIG_PM
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_root_hub_lost_power (struct usb_device *rhdev);
-extern int hcd_bus_suspend (struct usb_bus *bus);
-extern int hcd_bus_resume (struct usb_bus *bus);
+extern int hcd_bus_suspend(struct usb_device *rhdev);
+extern int hcd_bus_resume(struct usb_device *rhdev);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
-
-static inline int hcd_bus_suspend(struct usb_bus *bus)
-{
- return 0;
-}
-
-static inline int hcd_bus_resume (struct usb_bus *bus)
-{
- return 0;
-}
#endif /* CONFIG_PM */
/*
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 24f10a19dbdb..e341a1da517f 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -31,9 +31,16 @@
#include "hcd.h"
#include "hub.h"
+#ifdef CONFIG_USB_PERSIST
+#define USB_PERSIST 1
+#else
+#define USB_PERSIST 0
+#endif
+
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
+ struct kref kref;
struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... with extra space in case of babble */
@@ -66,6 +73,7 @@ struct usb_hub {
unsigned limited_power:1;
unsigned quiescing:1;
unsigned activating:1;
+ unsigned disconnected:1;
unsigned has_indicators:1;
u8 indicator[USB_MAXCHILDREN];
@@ -321,7 +329,7 @@ static void kick_khubd(struct usb_hub *hub)
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
spin_lock_irqsave(&hub_event_lock, flags);
- if (list_empty(&hub->event_list)) {
+ if (!hub->disconnected & list_empty(&hub->event_list)) {
list_add_tail(&hub->event_list, &hub_event_list);
wake_up(&khubd_wait);
}
@@ -330,6 +338,7 @@ static void kick_khubd(struct usb_hub *hub)
void usb_kick_khubd(struct usb_device *hdev)
{
+ /* FIXME: What if hdev isn't bound to the hub driver? */
kick_khubd(hdev_to_hub(hdev));
}
@@ -400,9 +409,10 @@ static void hub_tt_kevent (struct work_struct *work)
struct usb_hub *hub =
container_of(work, struct usb_hub, tt.kevent);
unsigned long flags;
+ int limit = 100;
spin_lock_irqsave (&hub->tt.lock, flags);
- while (!list_empty (&hub->tt.clear_list)) {
+ while (--limit && !list_empty (&hub->tt.clear_list)) {
struct list_head *temp;
struct usb_tt_clear *clear;
struct usb_device *hdev = hub->hdev;
@@ -550,48 +560,68 @@ static int hub_hub_status(struct usb_hub *hub,
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
{
struct usb_device *hdev = hub->hdev;
- int ret;
+ int ret = 0;
- if (hdev->children[port1-1] && set_state) {
+ if (hdev->children[port1-1] && set_state)
usb_set_device_state(hdev->children[port1-1],
USB_STATE_NOTATTACHED);
- }
- ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
+ if (!hub->error)
+ ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
if (ret)
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
- port1, ret);
-
+ port1, ret);
return ret;
}
+/*
+ * Disable a port and mark a logical connnect-change event, so that some
+ * time later khubd will disconnect() any existing usb_device on the port
+ * and will re-enumerate if there actually is a device attached.
+ */
+static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
+{
+ dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
+ hub_port_disable(hub, port1, 1);
+
+ /* FIXME let caller ask to power down the port:
+ * - some devices won't enumerate without a VBUS power cycle
+ * - SRP saves power that way
+ * - ... new call, TBD ...
+ * That's easy if this hub can switch power per-port, and
+ * khubd reactivates the port later (timer, SRP, etc).
+ * Powerdown must be optional, because of reset/DFU.
+ */
+
+ set_bit(port1, hub->change_bits);
+ kick_khubd(hub);
+}
/* caller has locked the hub device */
-static void hub_pre_reset(struct usb_interface *intf)
+static int hub_pre_reset(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
struct usb_device *hdev = hub->hdev;
- int port1;
+ int i;
- for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
- if (hdev->children[port1 - 1]) {
- usb_disconnect(&hdev->children[port1 - 1]);
- if (hub->error == 0)
- hub_port_disable(hub, port1, 0);
- }
+ /* Disconnect all the children */
+ for (i = 0; i < hdev->maxchild; ++i) {
+ if (hdev->children[i])
+ usb_disconnect(&hdev->children[i]);
}
hub_quiesce(hub);
+ return 0;
}
/* caller has locked the hub device */
-static void hub_post_reset(struct usb_interface *intf)
+static int hub_post_reset(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
- hub_activate(hub);
hub_power_on(hub);
+ hub_activate(hub);
+ return 0;
}
-
static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint)
{
@@ -845,43 +875,42 @@ fail:
return ret;
}
+static void hub_release(struct kref *kref)
+{
+ struct usb_hub *hub = container_of(kref, struct usb_hub, kref);
+
+ usb_put_intf(to_usb_interface(hub->intfdev));
+ kfree(hub);
+}
+
static unsigned highspeed_hubs;
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
- struct usb_device *hdev;
+
+ /* Take the hub off the event list and don't let it be added again */
+ spin_lock_irq(&hub_event_lock);
+ list_del_init(&hub->event_list);
+ hub->disconnected = 1;
+ spin_unlock_irq(&hub_event_lock);
/* Disconnect all children and quiesce the hub */
hub->error = 0;
hub_pre_reset(intf);
usb_set_intfdata (intf, NULL);
- hdev = hub->hdev;
- if (hdev->speed == USB_SPEED_HIGH)
+ if (hub->hdev->speed == USB_SPEED_HIGH)
highspeed_hubs--;
usb_free_urb(hub->urb);
- hub->urb = NULL;
-
- spin_lock_irq(&hub_event_lock);
- list_del_init(&hub->event_list);
- spin_unlock_irq(&hub_event_lock);
-
kfree(hub->descriptor);
- hub->descriptor = NULL;
-
kfree(hub->status);
- hub->status = NULL;
-
- if (hub->buffer) {
- usb_buffer_free(hdev, sizeof(*hub->buffer), hub->buffer,
- hub->buffer_dma);
- hub->buffer = NULL;
- }
+ usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer,
+ hub->buffer_dma);
- kfree(hub);
+ kref_put(&hub->kref, hub_release);
}
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -929,10 +958,12 @@ descriptor_error:
return -ENOMEM;
}
+ kref_init(&hub->kref);
INIT_LIST_HEAD(&hub->event_list);
hub->intfdev = &intf->dev;
hub->hdev = hdev;
INIT_DELAYED_WORK(&hub->leds, led_work);
+ usb_get_intf(intf);
usb_set_intfdata (intf, hub);
intf->needs_remote_wakeup = 1;
@@ -982,49 +1013,6 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
}
-/* grab device/port lock, returning index of that port (zero based).
- * protects the upstream link used by this device from concurrent
- * tree operations like suspend, resume, reset, and disconnect, which
- * apply to everything downstream of a given port.
- */
-static int locktree(struct usb_device *udev)
-{
- int t;
- struct usb_device *hdev;
-
- if (!udev)
- return -ENODEV;
-
- /* root hub is always the first lock in the series */
- hdev = udev->parent;
- if (!hdev) {
- usb_lock_device(udev);
- return 0;
- }
-
- /* on the path from root to us, lock everything from
- * top down, dropping parent locks when not needed
- */
- t = locktree(hdev);
- if (t < 0)
- return t;
-
- /* everything is fail-fast once disconnect
- * processing starts
- */
- if (udev->state == USB_STATE_NOTATTACHED) {
- usb_unlock_device(hdev);
- return -ENODEV;
- }
-
- /* when everyone grabs locks top->bottom,
- * non-overlapping work may be concurrent
- */
- usb_lock_device(udev);
- usb_unlock_device(hdev);
- return udev->portnum;
-}
-
static void recursively_mark_NOTATTACHED(struct usb_device *udev)
{
int i;
@@ -1089,46 +1077,6 @@ void usb_set_device_state(struct usb_device *udev,
spin_unlock_irqrestore(&device_state_lock, flags);
}
-
-#ifdef CONFIG_PM
-
-/**
- * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
- * @rhdev: struct usb_device for the root hub
- *
- * 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 all the children of the root hub
- * as NOTATTACHED and marks logical connect-change events on their ports.
- */
-void usb_root_hub_lost_power(struct usb_device *rhdev)
-{
- struct usb_hub *hub;
- int port1;
- unsigned long flags;
-
- dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
-
- /* Make sure no potential wakeup events get lost,
- * by forcing the root hub to be resumed.
- */
- rhdev->dev.power.prev_state.event = PM_EVENT_ON;
-
- spin_lock_irqsave(&device_state_lock, flags);
- hub = hdev_to_hub(rhdev);
- for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
- if (rhdev->children[port1 - 1]) {
- recursively_mark_NOTATTACHED(
- rhdev->children[port1 - 1]);
- set_bit(port1, hub->change_bits);
- }
- }
- spin_unlock_irqrestore(&device_state_lock, flags);
-}
-EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
-
-#endif /* CONFIG_PM */
-
static void choose_address(struct usb_device *udev)
{
int devnum;
@@ -1269,7 +1217,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
#ifdef CONFIG_USB_OTG
#include "otg_whitelist.h"
-static int __usb_port_suspend(struct usb_device *, int port1);
#endif
/**
@@ -1375,11 +1322,11 @@ int usb_new_device(struct usb_device *udev)
* (Includes HNP test device.)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
- err = __usb_port_suspend(udev, udev->bus->otg_port);
+ err = usb_port_suspend(udev);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
- err = -ENODEV;
+ err = -ENOTSUPP;
goto fail;
}
#endif
@@ -1388,6 +1335,10 @@ int usb_new_device(struct usb_device *udev)
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
+ /* Increment the parent's count of unsuspended children */
+ if (udev->parent)
+ usb_autoresume_device(udev->parent);
+
/* Register the device. The device driver is responsible
* for adding the device files to sysfs and for configuring
* the device.
@@ -1395,13 +1346,11 @@ int usb_new_device(struct usb_device *udev)
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
+ if (udev->parent)
+ usb_autosuspend_device(udev->parent);
goto fail;
}
- /* Increment the parent's count of unsuspended children */
- if (udev->parent)
- usb_autoresume_device(udev->parent);
-
exit:
return err;
@@ -1476,9 +1425,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (!(portstatus & USB_PORT_STAT_CONNECTION))
return -ENOTCONN;
- /* bomb out completely if something weird happened */
+ /* bomb out completely if the connection bounced */
if ((portchange & USB_PORT_STAT_C_CONNECTION))
- return -EINVAL;
+ return -ENOTCONN;
/* if we`ve finished resetting, then break out of the loop */
if (!(portstatus & USB_PORT_STAT_RESET) &&
@@ -1557,34 +1506,24 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
return status;
}
-/*
- * Disable a port and mark a logical connnect-change event, so that some
- * time later khubd will disconnect() any existing usb_device on the port
- * and will re-enumerate if there actually is a device attached.
- */
-static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
-{
- dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
- hub_port_disable(hub, port1, 1);
-
- /* FIXME let caller ask to power down the port:
- * - some devices won't enumerate without a VBUS power cycle
- * - SRP saves power that way
- * - ... new call, TBD ...
- * That's easy if this hub can switch power per-port, and
- * khubd reactivates the port later (timer, SRP, etc).
- * Powerdown must be optional, because of reset/DFU.
- */
-
- set_bit(port1, hub->change_bits);
- kick_khubd(hub);
-}
-
#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
/*
+ * usb_port_suspend - suspend a usb device's upstream port
+ * @udev: device that's no longer in active use, not a root hub
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * Suspends a USB device that isn't in active use, conserving power.
+ * Devices may wake out of a suspend, if anything important happens,
+ * using the remote wakeup mechanism. They may also be taken out of
+ * suspend by the host, using usb_port_resume(). It's also routine
+ * to disconnect devices while they are suspended.
+ *
+ * This only affects the USB hardware for a device; its interfaces
+ * (and, for hubs, child devices) must already have been suspended.
+ *
* Selective port suspend reduces power; most suspended devices draw
* less than 500 uA. It's also used in OTG, along with remote wakeup.
* All devices below the suspended port are also suspended.
@@ -1593,11 +1532,35 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
* also support "remote wakeup", where the device can activate the USB
* tree above them to deliver data, such as a keypress or packet. In
* some cases, this wakes the USB host.
+ *
+ * Suspending OTG devices may trigger HNP, if that's been enabled
+ * between a pair of dual-role devices. That will change roles, such
+ * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
+ *
+ * Devices on USB hub ports have only one "suspend" state, corresponding
+ * to ACPI D2, "may cause the device to lose some context".
+ * State transitions include:
+ *
+ * - suspend, resume ... when the VBUS power link stays live
+ * - suspend, disconnect ... VBUS lost
+ *
+ * Once VBUS drop breaks the circuit, the port it's using has to go through
+ * normal re-enumeration procedures, starting with enabling VBUS power.
+ * Other than re-initializing the hub (plug/unplug, except for root hubs),
+ * Linux (2.6) currently has NO mechanisms to initiate that: no khubd
+ * timer, no SRP, no requests through sysfs.
+ *
+ * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
+ * the root hub for their bus goes into global suspend ... so we don't
+ * (falsely) update the device power state to say it suspended.
+ *
+ * Returns 0 on success, else negative errno.
*/
-static int hub_port_suspend(struct usb_hub *hub, int port1,
- struct usb_device *udev)
+int usb_port_suspend(struct usb_device *udev)
{
- int status;
+ struct usb_hub *hub = hdev_to_hub(udev->parent);
+ int port1 = udev->portnum;
+ int status;
// dev_dbg(hub->intfdev, "suspend port %d\n", port1);
@@ -1614,17 +1577,15 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (status)
- dev_dbg(&udev->dev,
- "won't remote wakeup, status %d\n",
- status);
+ dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
+ status);
}
/* see 7.1.7.6 */
status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
if (status) {
- dev_dbg(hub->intfdev,
- "can't suspend port %d, status %d\n",
- port1, status);
+ dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
+ port1, status);
/* paranoia: "should not happen" */
(void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE, USB_RECIP_DEVICE,
@@ -1642,85 +1603,24 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
}
/*
- * Devices on USB hub ports have only one "suspend" state, corresponding
- * to ACPI D2, "may cause the device to lose some context".
- * State transitions include:
- *
- * - suspend, resume ... when the VBUS power link stays live
- * - suspend, disconnect ... VBUS lost
- *
- * Once VBUS drop breaks the circuit, the port it's using has to go through
- * normal re-enumeration procedures, starting with enabling VBUS power.
- * Other than re-initializing the hub (plug/unplug, except for root hubs),
- * Linux (2.6) currently has NO mechanisms to initiate that: no khubd
- * timer, no SRP, no requests through sysfs.
- *
- * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
- * the root hub for their bus goes into global suspend ... so we don't
- * (falsely) update the device power state to say it suspended.
- */
-static int __usb_port_suspend (struct usb_device *udev, int port1)
-{
- int status = 0;
-
- /* caller owns the udev device lock */
- if (port1 < 0)
- return port1;
-
- /* we change the device's upstream USB link,
- * but root hubs have no upstream USB link.
- */
- if (udev->parent)
- status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
- udev);
- else {
- dev_dbg(&udev->dev, "usb %ssuspend\n",
- udev->auto_pm ? "auto-" : "");
- usb_set_device_state(udev, USB_STATE_SUSPENDED);
- }
- return status;
-}
-
-/*
- * usb_port_suspend - suspend a usb device's upstream port
- * @udev: device that's no longer in active use
- * Context: must be able to sleep; device not locked; pm locks held
- *
- * Suspends a USB device that isn't in active use, conserving power.
- * Devices may wake out of a suspend, if anything important happens,
- * using the remote wakeup mechanism. They may also be taken out of
- * suspend by the host, using usb_port_resume(). It's also routine
- * to disconnect devices while they are suspended.
- *
- * This only affects the USB hardware for a device; its interfaces
- * (and, for hubs, child devices) must already have been suspended.
- *
- * Suspending OTG devices may trigger HNP, if that's been enabled
- * between a pair of dual-role devices. That will change roles, such
- * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
- *
- * Returns 0 on success, else negative errno.
- */
-int usb_port_suspend(struct usb_device *udev)
-{
- return __usb_port_suspend(udev, udev->portnum);
-}
-
-/*
* If the USB "suspend" state is in use (rather than "global suspend"),
* many devices will be individually taken out of suspend state using
- * special" resume" signaling. These routines kick in shortly after
+ * special "resume" signaling. This routine kicks in shortly after
* hardware resume signaling is finished, either because of selective
* resume (by host) or remote wakeup (by device) ... now see what changed
* in the tree that's rooted at this device.
+ *
+ * If @udev->reset_resume is set then the device is reset before the
+ * status check is done.
*/
static int finish_port_resume(struct usb_device *udev)
{
- int status;
+ int status = 0;
u16 devstatus;
/* caller owns the udev device lock */
- dev_dbg(&udev->dev, "finish resume\n");
+ dev_dbg(&udev->dev, "finish %sresume\n",
+ udev->reset_resume ? "reset-" : "");
/* usb ch9 identifies four variants of SUSPENDED, based on what
* state the device resumes to. Linux currently won't see the
@@ -1731,22 +1631,30 @@ static int finish_port_resume(struct usb_device *udev)
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
+ /* 10.5.4.5 says not to reset a suspended port if the attached
+ * device is enabled for remote wakeup. Hence the reset
+ * operation is carried out here, after the port has been
+ * resumed.
+ */
+ if (udev->reset_resume)
+ status = usb_reset_device(udev);
+
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
* and device drivers will know about any resume quirks.
*/
- status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
- if (status >= 0)
- status = (status == 2 ? 0 : -ENODEV);
+ if (status == 0) {
+ status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
+ if (status >= 0)
+ status = (status == 2 ? 0 : -ENODEV);
+ }
- if (status)
- dev_dbg(&udev->dev,
- "gone after usb resume? status %d\n",
- status);
- else if (udev->actconfig) {
+ if (status) {
+ dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
+ status);
+ } else if (udev->actconfig) {
le16_to_cpus(&devstatus);
- if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
- && udev->parent) {
+ if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE,
@@ -1759,19 +1667,52 @@ static int finish_port_resume(struct usb_device *udev)
"wakeup, status %d\n", status);
}
status = 0;
-
- } else if (udev->devnum <= 0) {
- dev_dbg(&udev->dev, "bogus resume!\n");
- status = -EINVAL;
}
return status;
}
-static int
-hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
+/*
+ * usb_port_resume - re-activate a suspended usb device's upstream port
+ * @udev: device to re-activate, not a root hub
+ * Context: must be able to sleep; device not locked; pm locks held
+ *
+ * This will re-activate the suspended device, increasing power usage
+ * while letting drivers communicate again with its endpoints.
+ * USB resume explicitly guarantees that the power session between
+ * 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
+ * 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.
+ *
+ * For example, if a host controller doesn't maintain VBUS suspend current
+ * during a system sleep or is reset when the system wakes up, all the USB
+ * power sessions below it will be broken. This is especially troublesome
+ * for mass-storage devices containing mounted filesystems, since the
+ * device will appear to have disconnected and all the memory mappings
+ * 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
+ * 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
+ * asleep, he will have only himself to blame when the filesystem on the
+ * new card is corrupted and the system crashes.
+ *
+ * Returns 0 on success, else negative errno.
+ */
+int usb_port_resume(struct usb_device *udev)
{
- int status;
- u16 portchange, portstatus;
+ struct usb_hub *hub = hdev_to_hub(udev->parent);
+ int port1 = udev->portnum;
+ int status;
+ u16 portchange, portstatus;
+ unsigned mask_flags, want_flags;
/* Skip the initial Clear-Suspend step for a remote wakeup */
status = hub_port_status(hub, port1, &portstatus, &portchange);
@@ -1786,30 +1727,31 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
status = clear_port_feature(hub->hdev,
port1, USB_PORT_FEAT_SUSPEND);
if (status) {
- dev_dbg(hub->intfdev,
- "can't resume port %d, status %d\n",
- port1, status);
+ dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
+ port1, status);
} else {
/* drive resume for at least 20 msec */
- if (udev)
- dev_dbg(&udev->dev, "usb %sresume\n",
- udev->auto_pm ? "auto-" : "");
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ udev->auto_pm ? "auto-" : "");
msleep(25);
-#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
- | USB_PORT_STAT_ENABLE \
- | USB_PORT_STAT_CONNECTION)
-
/* Virtual root hubs can trigger on GET_PORT_STATUS to
* stop resume signaling. Then finish the resume
* sequence.
*/
status = hub_port_status(hub, port1, &portstatus, &portchange);
-SuspendCleared:
- if (status < 0
- || (portstatus & LIVE_FLAGS) != LIVE_FLAGS
- || (portstatus & USB_PORT_STAT_SUSPEND) != 0
- ) {
+
+ SuspendCleared:
+ if (USB_PERSIST && udev->reset_resume)
+ want_flags = USB_PORT_STAT_POWER
+ | USB_PORT_STAT_CONNECTION;
+ else
+ want_flags = USB_PORT_STAT_POWER
+ | USB_PORT_STAT_CONNECTION
+ | USB_PORT_STAT_ENABLE;
+ mask_flags = want_flags | USB_PORT_STAT_SUSPEND;
+
+ if (status < 0 || (portstatus & mask_flags) != want_flags) {
dev_dbg(hub->intfdev,
"port %d status %04x.%04x after resume, %d\n",
port1, portchange, portstatus, status);
@@ -1821,51 +1763,19 @@ SuspendCleared:
USB_PORT_FEAT_C_SUSPEND);
/* TRSMRCY = 10 msec */
msleep(10);
- if (udev)
- status = finish_port_resume(udev);
}
}
- if (status < 0)
- hub_port_logical_disconnect(hub, port1);
clear_bit(port1, hub->busy_bits);
if (!hub->hdev->parent && !hub->busy_bits[0])
usb_enable_root_hub_irq(hub->hdev->bus);
- return status;
-}
-
-/*
- * usb_port_resume - re-activate a suspended usb device's upstream port
- * @udev: device to re-activate
- * Context: must be able to sleep; device not locked; pm locks held
- *
- * This will re-activate the suspended device, increasing power usage
- * while letting drivers communicate again with its endpoints.
- * USB resume explicitly guarantees that the power session between
- * the host and the device is the same as it was when the device
- * suspended.
- *
- * Returns 0 on success, else negative errno.
- */
-int usb_port_resume(struct usb_device *udev)
-{
- int status;
-
- /* we change the device's upstream USB link,
- * but root hubs have no upstream USB link.
- */
- if (udev->parent) {
- // NOTE this fails if parent is also suspended...
- status = hub_port_resume(hdev_to_hub(udev->parent),
- udev->portnum, udev);
- } else {
- dev_dbg(&udev->dev, "usb %sresume\n",
- udev->auto_pm ? "auto-" : "");
+ if (status == 0)
status = finish_port_resume(udev);
- }
- if (status < 0)
+ if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
+ hub_port_logical_disconnect(hub, port1);
+ }
return status;
}
@@ -1892,21 +1802,16 @@ int usb_port_suspend(struct usb_device *udev)
return 0;
}
-static inline int
-finish_port_resume(struct usb_device *udev)
-{
- return 0;
-}
-
-static inline int
-hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
-{
- return 0;
-}
-
int usb_port_resume(struct usb_device *udev)
{
- return 0;
+ int status = 0;
+
+ /* However we may need to do a reset-resume */
+ if (udev->reset_resume) {
+ dev_dbg(&udev->dev, "reset-resume\n");
+ status = usb_reset_device(udev);
+ }
+ return status;
}
static inline int remote_wakeup(struct usb_device *udev)
@@ -1921,7 +1826,6 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
- int status = 0;
/* fail if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@@ -1947,49 +1851,75 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
/* stop khubd and related activity */
hub_quiesce(hub);
-
- /* "global suspend" of the downstream HC-to-USB interface */
- if (!hdev->parent) {
- status = hcd_bus_suspend(hdev->bus);
- if (status != 0) {
- dev_dbg(&hdev->dev, "'global' suspend %d\n", status);
- hub_activate(hub);
- }
- }
- return status;
+ return 0;
}
static int hub_resume(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
- struct usb_device *hdev = hub->hdev;
- int status;
dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
- /* "global resume" of the downstream HC-to-USB interface */
- if (!hdev->parent) {
- struct usb_bus *bus = hdev->bus;
- if (bus) {
- status = hcd_bus_resume (bus);
- if (status) {
- dev_dbg(&intf->dev, "'global' resume %d\n",
- status);
- return status;
+ /* tell khubd to look for changes on this hub */
+ hub_activate(hub);
+ 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;
+
+ 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);
}
- } else
- return -EOPNOTSUPP;
- if (status == 0) {
- /* TRSMRCY = 10 msec */
- msleep(10);
}
}
- /* tell khubd to look for changes on this hub */
hub_activate(hub);
return 0;
}
+/**
+ * usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
+ * @rhdev: struct usb_device for the root hub
+ *
+ * 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.
+ */
+void usb_root_hub_lost_power(struct usb_device *rhdev)
+{
+ dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
+ rhdev->reset_resume = 1;
+}
+EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
+
#else /* CONFIG_PM */
static inline int remote_wakeup(struct usb_device *udev)
@@ -1997,8 +1927,9 @@ static inline int remote_wakeup(struct usb_device *udev)
return 0;
}
-#define hub_suspend NULL
-#define hub_resume NULL
+#define hub_suspend NULL
+#define hub_resume NULL
+#define hub_reset_resume NULL
#endif
@@ -2461,19 +2392,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
return;
}
-#ifdef CONFIG_USB_SUSPEND
- /* If something is connected, but the port is suspended, wake it up. */
- if (portstatus & USB_PORT_STAT_SUSPEND) {
- status = hub_port_resume(hub, port1, NULL);
- if (status < 0) {
- dev_dbg(hub_dev,
- "can't clear suspend on port %d; %d\n",
- port1, status);
- goto done;
- }
- }
-#endif
-
for (i = 0; i < SET_CONFIG_TRIES; i++) {
struct usb_device *udev;
@@ -2584,7 +2502,7 @@ loop:
ep0_reinit(udev);
release_address(udev);
usb_put_dev(udev);
- if (status == -ENOTCONN)
+ if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
@@ -2625,10 +2543,12 @@ static void hub_events(void)
list_del_init(tmp);
hub = list_entry(tmp, struct usb_hub, event_list);
- hdev = hub->hdev;
- intf = to_usb_interface(hub->intfdev);
- hub_dev = &intf->dev;
+ kref_get(&hub->kref);
+ spin_unlock_irq(&hub_event_lock);
+ hdev = hub->hdev;
+ hub_dev = hub->intfdev;
+ intf = to_usb_interface(hub_dev);
dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
hdev->state, hub->descriptor
? hub->descriptor->bNbrPorts
@@ -2637,16 +2557,10 @@ static void hub_events(void)
(u16) hub->change_bits[0],
(u16) hub->event_bits[0]);
- usb_get_intf(intf);
- spin_unlock_irq(&hub_event_lock);
-
/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
- if (locktree(hdev) < 0) {
- usb_put_intf(intf);
- continue;
- }
- if (hub != usb_get_intfdata(intf))
+ usb_lock_device(hdev);
+ if (unlikely(hub->disconnected))
goto loop;
/* If the hub has died, clean up after it */
@@ -2809,13 +2723,14 @@ loop_autopm:
usb_autopm_enable(intf);
loop:
usb_unlock_device(hdev);
- usb_put_intf(intf);
+ kref_put(&hub->kref, hub_release);
} /* end while (1) */
}
static int hub_thread(void *__unused)
{
+ set_freezable();
do {
hub_events();
wait_event_interruptible(khubd_wait,
@@ -2844,6 +2759,7 @@ static struct usb_driver hub_driver = {
.disconnect = hub_disconnect,
.suspend = hub_suspend,
.resume = hub_resume,
+ .reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.ioctl = hub_ioctl,
@@ -2946,6 +2862,11 @@ static int config_descriptors_changed(struct usb_device *udev)
* this from a driver probe() routine after downloading new firmware.
* For calls that might not occur during probe(), drivers should lock
* the device using usb_lock_device_for_reset().
+ *
+ * Locking exception: This routine may also be called from within an
+ * autoresume handler. Such usage won't conflict with other tasks
+ * holding the device lock because these tasks should always call
+ * usb_autopm_resume_device(), thereby preventing any unwanted autoresume.
*/
int usb_reset_device(struct usb_device *udev)
{
@@ -2976,7 +2897,7 @@ int usb_reset_device(struct usb_device *udev)
* Other endpoints will be handled by re-enumeration. */
ep0_reinit(udev);
ret = hub_port_init(parent_hub, udev, port1, i);
- if (ret >= 0)
+ if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
break;
}
clear_bit(port1, parent_hub->busy_bits);
@@ -3092,6 +3013,7 @@ int usb_reset_composite_device(struct usb_device *udev,
drv = to_usb_driver(cintf->dev.driver);
if (drv->pre_reset)
(drv->pre_reset)(cintf);
+ /* FIXME: Unbind if pre_reset returns an error or isn't defined */
}
}
}
@@ -3110,6 +3032,7 @@ int usb_reset_composite_device(struct usb_device *udev,
drv = to_usb_driver(cintf->dev.driver);
if (drv->post_reset)
(drv->post_reset)(cintf);
+ /* FIXME: Unbind if post_reset returns an error or isn't defined */
}
if (cintf != iface)
up(&cintf->dev.sem);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f9fed34bf7d8..25f63f1096b4 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -34,13 +34,14 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
struct completion done;
unsigned long expire;
- int status;
+ int retval;
+ int status = urb->status;
init_completion(&done);
urb->context = &done;
urb->actual_length = 0;
- status = usb_submit_urb(urb, GFP_NOIO);
- if (unlikely(status))
+ retval = usb_submit_urb(urb, GFP_NOIO);
+ if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
@@ -55,15 +56,15 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
urb->transfer_buffer_length);
usb_kill_urb(urb);
- status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+ retval = status == -ENOENT ? -ETIMEDOUT : status;
} else
- status = urb->status;
+ retval = status;
out:
if (actual_length)
*actual_length = urb->actual_length;
usb_free_urb(urb);
- return status;
+ return retval;
}
/*-------------------------------------------------------------------*/
@@ -250,6 +251,7 @@ static void sg_clean (struct usb_sg_request *io)
static void sg_complete (struct urb *urb)
{
struct usb_sg_request *io = urb->context;
+ int status = urb->status;
spin_lock (&io->lock);
@@ -265,21 +267,21 @@ static void sg_complete (struct urb *urb)
*/
if (io->status
&& (io->status != -ECONNRESET
- || urb->status != -ECONNRESET)
+ || status != -ECONNRESET)
&& urb->actual_length) {
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
- urb->status, io->status);
+ status, io->status);
// BUG ();
}
- if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
- int i, found, status;
+ if (io->status == 0 && status && status != -ECONNRESET) {
+ int i, found, retval;
- io->status = urb->status;
+ io->status = status;
/* the previous urbs, and this one, completed already.
* unlink pending urbs so they won't rx/tx bad data.
@@ -290,13 +292,13 @@ static void sg_complete (struct urb *urb)
if (!io->urbs [i] || !io->urbs [i]->dev)
continue;
if (found) {
- status = usb_unlink_urb (io->urbs [i]);
- if (status != -EINPROGRESS
- && status != -ENODEV
- && status != -EBUSY)
+ retval = usb_unlink_urb (io->urbs [i]);
+ if (retval != -EINPROGRESS &&
+ retval != -ENODEV &&
+ retval != -EBUSY)
dev_err (&io->dev->dev,
"%s, unlink --> %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
} else if (urb == io->urbs [i])
found = 1;
}
@@ -404,8 +406,6 @@ int usb_sg_init (
io->urbs [i]->complete = sg_complete;
io->urbs [i]->context = io;
- io->urbs [i]->status = -EINPROGRESS;
- io->urbs [i]->actual_length = 0;
/*
* Some systems need to revert to PIO when DMA is temporarily
@@ -499,7 +499,8 @@ void usb_sg_wait (struct usb_sg_request *io)
/* queue the urbs. */
spin_lock_irq (&io->lock);
- for (i = 0; i < entries && !io->status; i++) {
+ i = 0;
+ while (i < entries && !io->status) {
int retval;
io->urbs [i]->dev = io->dev;
@@ -516,7 +517,6 @@ void usb_sg_wait (struct usb_sg_request *io)
case -ENOMEM:
io->urbs[i]->dev = NULL;
retval = 0;
- i--;
yield ();
break;
@@ -527,6 +527,7 @@ void usb_sg_wait (struct usb_sg_request *io)
* URBs are queued at once; N milliseconds?
*/
case 0:
+ ++i;
cpu_relax ();
break;
@@ -1385,6 +1386,36 @@ struct device_type usb_if_device_type = {
.uevent = usb_if_uevent,
};
+static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
+ struct usb_host_config *config,
+ u8 inum)
+{
+ struct usb_interface_assoc_descriptor *retval = NULL;
+ struct usb_interface_assoc_descriptor *intf_assoc;
+ int first_intf;
+ int last_intf;
+ int i;
+
+ for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {
+ intf_assoc = config->intf_assoc[i];
+ if (intf_assoc->bInterfaceCount == 0)
+ continue;
+
+ first_intf = intf_assoc->bFirstInterface;
+ last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
+ if (inum >= first_intf && inum <= last_intf) {
+ if (!retval)
+ retval = intf_assoc;
+ else
+ dev_err(&dev->dev, "Interface #%d referenced"
+ " by multiple IADs\n", inum);
+ }
+ }
+
+ return retval;
+}
+
+
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
@@ -1531,6 +1562,7 @@ free_interfaces:
intfc = cp->intf_cache[i];
intf->altsetting = intfc->altsetting;
intf->num_altsetting = intfc->num_altsetting;
+ intf->intf_assoc = find_iad(dev, cp, i);
kref_get(&intfc->ref);
alt = usb_altnum_to_altsetting(intf, 0);
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 739f520908aa..aa21b38a31ce 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -30,10 +30,28 @@
static const struct usb_device_id usb_quirk_list[] = {
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+ /* Benq S2W 3300U */
+ { USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Seiko Epson Corp. Perfection 1200 */
+ { USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Seiko Epson Corp - Perfection 1670 */
{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Samsung ML-2510 Series printer */
+ { USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Elsa MicroLink 56k (V.250) */
{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Ultima Electronics Corp.*/
+ { USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ /* Umax [hex] Astra 3400U */
+ { USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+ /* Philips PSC805 audio device */
+ { USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
+
+ /* RIM Blackberry */
+ { USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ { USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+ { USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
{ } /* terminating entry must be last */
};
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index be37c863fdfb..2ab222be8fd1 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -169,6 +169,73 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
+
+#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
+static const char power_group[] = "power";
+#endif
+
+#ifdef CONFIG_USB_PERSIST
+
+static ssize_t
+show_persist(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ return sprintf(buf, "%d\n", udev->persist_enabled);
+}
+
+static ssize_t
+set_persist(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_device *udev = to_usb_device(dev);
+ int value;
+
+ /* Hubs are always enabled for USB_PERSIST */
+ if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+ return -EPERM;
+
+ if (sscanf(buf, "%d", &value) != 1)
+ return -EINVAL;
+ usb_pm_lock(udev);
+ udev->persist_enabled = !!value;
+ usb_pm_unlock(udev);
+ return count;
+}
+
+static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist);
+
+static int add_persist_attributes(struct device *dev)
+{
+ int rc = 0;
+
+ 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);
+ }
+ return rc;
+}
+
+static void remove_persist_attributes(struct device *dev)
+{
+ sysfs_remove_file_from_group(&dev->kobj,
+ &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 */
+
#ifdef CONFIG_USB_SUSPEND
static ssize_t
@@ -276,8 +343,6 @@ set_level(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
-static char power_group[] = "power";
-
static int add_power_attributes(struct device *dev)
{
int rc = 0;
@@ -311,6 +376,7 @@ static void remove_power_attributes(struct device *dev)
#endif /* CONFIG_USB_SUSPEND */
+
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
@@ -375,6 +441,54 @@ static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct usb_device *udev = to_usb_device(
+ container_of(kobj, struct device, kobj));
+ size_t nleft = count;
+ size_t srclen, n;
+
+ usb_lock_device(udev);
+
+ /* The binary attribute begins with the device descriptor */
+ srclen = sizeof(struct usb_device_descriptor);
+ if (off < srclen) {
+ n = min_t(size_t, nleft, srclen - off);
+ memcpy(buf, off + (char *) &udev->descriptor, n);
+ nleft -= n;
+ buf += n;
+ off = 0;
+ } else {
+ off -= srclen;
+ }
+
+ /* Then follows the raw descriptor entry for the current
+ * configuration (config plus subsidiary descriptors).
+ */
+ if (udev->actconfig) {
+ int cfgno = udev->actconfig - udev->config;
+
+ srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+ if (off < srclen) {
+ n = min_t(size_t, nleft, srclen - off);
+ memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+ nleft -= n;
+ }
+ }
+ usb_unlock_device(udev);
+ return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+ .attr = {.name = "descriptors", .mode = 0444},
+ .read = read_descriptors,
+ .size = 18 + 65535, /* dev descr + max-size raw descriptor */
+};
+
int usb_create_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
@@ -384,6 +498,14 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
return retval;
+ retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+ if (retval)
+ goto error;
+
+ retval = add_persist_attributes(dev);
+ if (retval)
+ goto error;
+
retval = add_power_attributes(dev);
if (retval)
goto error;
@@ -421,9 +543,30 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
device_remove_file(dev, &dev_attr_product);
device_remove_file(dev, &dev_attr_serial);
remove_power_attributes(dev);
+ remove_persist_attributes(dev);
+ device_remove_bin_file(dev, &dev_bin_attr_descriptors);
sysfs_remove_group(&dev->kobj, &dev_attr_grp);
}
+/* Interface Accociation Descriptor fields */
+#define usb_intf_assoc_attr(field, format_string) \
+static ssize_t \
+show_iad_##field (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct usb_interface *intf = to_usb_interface (dev); \
+ \
+ return sprintf (buf, format_string, \
+ intf->intf_assoc->field); \
+} \
+static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
+
+usb_intf_assoc_attr (bFirstInterface, "%02x\n")
+usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
+usb_intf_assoc_attr (bFunctionClass, "%02x\n")
+usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
+usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")
+
/* Interface fields */
#define usb_intf_attr(field, format_string) \
static ssize_t \
@@ -487,6 +630,18 @@ static ssize_t show_modalias(struct device *dev,
}
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
+static struct attribute *intf_assoc_attrs[] = {
+ &dev_attr_iad_bFirstInterface.attr,
+ &dev_attr_iad_bInterfaceCount.attr,
+ &dev_attr_iad_bFunctionClass.attr,
+ &dev_attr_iad_bFunctionSubClass.attr,
+ &dev_attr_iad_bFunctionProtocol.attr,
+ NULL,
+};
+static struct attribute_group intf_assoc_attr_grp = {
+ .attrs = intf_assoc_attrs,
+};
+
static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceNumber.attr,
&dev_attr_bAlternateSetting.attr,
@@ -538,6 +693,8 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
retval = device_create_file(dev, &dev_attr_interface);
+ if (intf->intf_assoc)
+ retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
usb_create_intf_ep_files(intf, udev);
return 0;
}
@@ -549,4 +706,5 @@ void usb_remove_sysfs_intf_files(struct usb_interface *intf)
usb_remove_intf_ep_files(intf);
device_remove_file(dev, &dev_attr_interface);
sysfs_remove_group(&dev->kobj, &intf_attr_grp);
+ sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
}
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 94ea9727ff55..be630228461c 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -4,6 +4,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/usb.h>
+#include <linux/wait.h>
#include "hcd.h"
#define to_urb(d) container_of(d, struct urb, kref)
@@ -11,6 +12,10 @@
static void urb_destroy(struct kref *kref)
{
struct urb *urb = to_urb(kref);
+
+ if (urb->transfer_flags & URB_FREE_BUFFER)
+ kfree(urb->transfer_buffer);
+
kfree(urb);
}
@@ -34,6 +39,7 @@ void usb_init_urb(struct urb *urb)
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
spin_lock_init(&urb->lock);
+ INIT_LIST_HEAD(&urb->anchor_list);
}
}
@@ -100,8 +106,60 @@ struct urb * usb_get_urb(struct urb *urb)
kref_get(&urb->kref);
return urb;
}
-
-
+
+/**
+ * usb_anchor_urb - anchors an URB while it is processed
+ * @urb: pointer to the urb to anchor
+ * @anchor: pointer to the anchor
+ *
+ * This can be called to have access to URBs which are to be executed
+ * without bothering to track them
+ */
+void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ usb_get_urb(urb);
+ list_add_tail(&urb->anchor_list, &anchor->urb_list);
+ urb->anchor = anchor;
+ spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_anchor_urb);
+
+/**
+ * usb_unanchor_urb - unanchors an URB
+ * @urb: pointer to the urb to anchor
+ *
+ * Call this to stop the system keeping track of this URB
+ */
+void usb_unanchor_urb(struct urb *urb)
+{
+ unsigned long flags;
+ struct usb_anchor *anchor;
+
+ if (!urb)
+ return;
+
+ anchor = urb->anchor;
+ if (!anchor)
+ return;
+
+ spin_lock_irqsave(&anchor->lock, flags);
+ if (unlikely(anchor != urb->anchor)) {
+ /* we've lost the race to another thread */
+ spin_unlock_irqrestore(&anchor->lock, flags);
+ return;
+ }
+ urb->anchor = NULL;
+ list_del(&urb->anchor_list);
+ spin_unlock_irqrestore(&anchor->lock, flags);
+ usb_put_urb(urb);
+ if (list_empty(&anchor->urb_list))
+ wake_up(&anchor->wait);
+}
+EXPORT_SYMBOL_GPL(usb_unanchor_urb);
+
/*-------------------------------------------------------------------*/
/**
@@ -382,55 +440,57 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* @urb: pointer to urb describing a previously submitted request,
* may be NULL
*
- * This routine cancels an in-progress request. URBs complete only
- * once per submission, and may be canceled only once per submission.
- * Successful cancellation means the requests's completion handler will
- * be called with a status code indicating that the request has been
- * canceled (rather than any other code) and will quickly be removed
- * from host controller data structures.
- *
- * This request is always asynchronous.
- * Success is indicated by returning -EINPROGRESS,
- * at which time the URB will normally have been unlinked but not yet
- * given back to the device driver. When it is called, the completion
- * function will see urb->status == -ECONNRESET. Failure is indicated
- * by any other return value. Unlinking will fail when the URB is not
- * currently "linked" (i.e., it was never submitted, or it was unlinked
- * before, or the hardware is already finished with it), even if the
- * completion handler has not yet run.
+ * This routine cancels an in-progress request. URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
+ *
+ * This request is always asynchronous. Success is indicated by
+ * returning -EINPROGRESS, at which time the URB will probably not yet
+ * have been given back to the device driver. When it is eventually
+ * called, the completion function will see @urb->status == -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
*
* Unlinking and Endpoint Queues:
*
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
* Host Controller Drivers (HCDs) place all the URBs for a particular
* endpoint in a queue. Normally the queue advances as the controller
* hardware processes each request. But when an URB terminates with an
- * error its queue stops, at least until that URB's completion routine
- * returns. It is guaranteed that the queue will not restart until all
- * its unlinked URBs have been fully retired, with their completion
- * routines run, even if that's not until some time after the original
- * completion handler returns. Normally the same behavior and guarantees
- * apply when an URB terminates because it was unlinked; however if an
- * URB is unlinked before the hardware has started to execute it, then
- * its queue is not guaranteed to stop until all the preceding URBs have
- * completed.
- *
- * This means that USB device drivers can safely build deep queues for
- * large or complex transfers, and clean them up reliably after any sort
- * of aborted transfer by unlinking all pending URBs at the first fault.
- *
- * Note that an URB terminating early because a short packet was received
- * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
- * Also, that all unlinks performed in any URB completion handler must
- * be asynchronous.
- *
- * Queues for isochronous endpoints are treated differently, because they
- * advance at fixed rates. Such queues do not stop when an URB is unlinked.
- * An unlinked URB may leave a gap in the stream of packets. It is undefined
- * whether such gaps can be filled in.
- *
- * When a control URB terminates with an error, it is likely that the
- * status stage of the transfer will not take place, even if it is merely
- * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns. It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns. The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
+ *
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO. Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors. Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates. Such queues do not stop when an URB
+ * encounters an error or is unlinked. An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
+ *
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set. By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
+ *
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
*/
int usb_unlink_urb(struct urb *urb)
{
@@ -478,6 +538,48 @@ void usb_kill_urb(struct urb *urb)
spin_unlock_irq(&urb->lock);
}
+/**
+ * usb_kill_anchored_urbs - cancel transfer requests en masse
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be killed starting
+ * from the back of the queue
+ */
+void usb_kill_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);
+ /* we must make sure the URB isn't freed before we kill it*/
+ usb_get_urb(victim);
+ spin_unlock_irq(&anchor->lock);
+ /* this will unanchor the URB */
+ usb_kill_urb(victim);
+ usb_put_urb(victim);
+ spin_lock_irq(&anchor->lock);
+ }
+ spin_unlock_irq(&anchor->lock);
+}
+EXPORT_SYMBOL_GPL(usb_kill_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
+ *
+ * Call this is you want to be sure all an anchor's
+ * URBs have finished
+ */
+int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
+ unsigned int timeout)
+{
+ return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list),
+ msecs_to_jiffies(timeout));
+}
+EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
+
EXPORT_SYMBOL(usb_init_urb);
EXPORT_SYMBOL(usb_alloc_urb);
EXPORT_SYMBOL(usb_free_urb);
@@ -485,4 +587,3 @@ EXPORT_SYMBOL(usb_get_urb);
EXPORT_SYMBOL(usb_submit_urb);
EXPORT_SYMBOL(usb_unlink_urb);
EXPORT_SYMBOL(usb_kill_urb);
-
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 4a6299bd0047..0fee5c66fd64 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -253,6 +253,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.dma_mask = bus->controller->dma_mask;
+ set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
INIT_LIST_HEAD(&dev->ep0.urb_list);
@@ -578,11 +579,12 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
* address (through the pointer provided).
*
* These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
- * to avoid behaviors like using "DMA bounce buffers", or tying down I/O
- * mapping hardware for long idle periods. The implementation varies between
+ * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU
+ * hardware during URB completion/resubmit. The implementation varies between
* platforms, depending on details of how DMA will work to this device.
- * Using these buffers also helps prevent cacheline sharing problems on
- * architectures where CPU caches are not DMA-coherent.
+ * Using these buffers also eliminates cacheline sharing problems on
+ * architectures where CPU caches are not DMA-coherent. On systems without
+ * bus-snooping caches, these buffers are uncached.
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
@@ -607,7 +609,7 @@ void *usb_buffer_alloc(
*
* This reclaims an I/O buffer, letting it be reused. The memory must have
* been allocated using usb_buffer_alloc(), and the parameters must match
- * those provided in that allocation request.
+ * those provided in that allocation request.
*/
void usb_buffer_free(
struct usb_device *dev,
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index bf2eb0dae2ec..ad5fa0338f49 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -52,8 +52,16 @@ static inline void usb_pm_unlock(struct usb_device *udev)
#else
-#define usb_port_suspend(dev) 0
-#define usb_port_resume(dev) 0
+static inline int usb_port_suspend(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int usb_port_resume(struct usb_device *udev)
+{
+ return 0;
+}
+
static inline void usb_pm_lock(struct usb_device *udev) {}
static inline void usb_pm_unlock(struct usb_device *udev) {}
@@ -100,11 +108,13 @@ 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 f771a7cae9ec..767aed5b4bea 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -42,6 +42,20 @@ config USB_GADGET
For more information, see <http://www.linux-usb.org/gadget> and
the kernel DocBook documentation for this API.
+config USB_GADGET_DEBUG
+ boolean "Debugging messages"
+ depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
+ help
+ Many controller and gadget drivers will print some debugging
+ messages if you use this option to ask for those messages.
+
+ Avoid enabling these messages, even if you're actively
+ debugging such a driver. Many drivers will emit so many
+ messages that the driver timings are affected, which will
+ either create new failure modes or remove the one you're
+ trying to track down. Never enable these messages for a
+ production build.
+
config USB_GADGET_DEBUG_FILES
boolean "Debugging information files"
depends on USB_GADGET && PROC_FS
@@ -68,6 +82,27 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
+config USB_GADGET_AMD5536UDC
+ boolean "AMD5536 UDC"
+ depends on PCI
+ select USB_GADGET_DUALSPEED
+ help
+ The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+ It is a USB Highspeed DMA capable USB device controller. Beside ep0
+ it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ The UDC port supports OTG operation, and may be used as a host port
+ if it's not being used to implement peripheral or OTG roles.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "amd5536udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+ tristate
+ depends on USB_GADGET_AMD5536UDC
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@@ -142,6 +177,24 @@ config USB_PXA2XX_SMALL
default y if USB_ETH
default y if USB_G_SERIAL
+config USB_GADGET_M66592
+ boolean "Renesas M66592 USB Peripheral Controller"
+ select USB_GADGET_DUALSPEED
+ help
+ M66592 is a discrete USB peripheral controller chip that
+ supports both full and high speed USB 2.0 data transfers.
+ It has seven configurable endpoints, and endpoint zero.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "m66592_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_M66592
+ tristate
+ depends on USB_GADGET_M66592
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
@@ -208,6 +261,27 @@ config USB_OTG
Select this only if your OMAP board has a Mini-AB connector.
+config USB_GADGET_S3C2410
+ boolean "S3C2410 USB Device Controller"
+ depends on ARCH_S3C2410
+ help
+ Samsung's S3C2410 is an ARM-4 processor with an integrated
+ full speed USB 1.1 device controller. It has 4 configurable
+ endpoints, as well as endpoint zero (for control transfers).
+
+ This driver has been tested on the S3C2410, S3C2412, and
+ S3C2440 processors.
+
+config USB_S3C2410
+ tristate
+ depends on USB_GADGET_S3C2410
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
+config USB_S3C2410_DEBUG
+ boolean "S3C2410 udc debug messages"
+ depends on USB_GADGET_S3C2410
+
config USB_GADGET_AT91
boolean "AT91 USB Device Port"
depends on ARCH_AT91 && !ARCH_AT91SAM9RL
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5db19396631c..1bc0f03550ce 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -1,14 +1,21 @@
#
# USB peripheral controller drivers
#
+ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
+obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
+obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
+obj-$(CONFIG_USB_M66592) += m66592-udc.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644
index 000000000000..714156ca8fe4
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,3454 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde 0 == do not touch RDE, do no start the RDE timer
+ * set_rde 1 == timer function will look whether FIFO has data
+ * set_rde 2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+ (unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+ ep0_string,
+ "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+ "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+ "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+ "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+ "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+ "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+ "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+ "true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+ DBG(dev, "------- Device registers -------\n");
+ DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg));
+ DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl));
+ DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts));
+ DBG(dev, "\n");
+ DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts));
+ DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts));
+ DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+ DBG(dev, "\n");
+ DBG(dev, "USE DMA = %d\n", use_dma);
+ if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBNDU (packet per buffer "
+ "WITHOUT desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+ } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+ DBG(dev, "DMA mode = PPBDU (packet per buffer "
+ "WITH desc. update)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+ }
+ if (use_dma && use_dma_bufferfill_mode) {
+ DBG(dev, "DMA mode = BF (buffer fill mode)\n");
+ dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+ }
+ if (!use_dma) {
+ dev_info(&dev->pdev->dev, "FIFO mode\n");
+ }
+ DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ /* mask all dev interrupts */
+ tmp = AMD_BIT(UDC_DEVINT_SVC) |
+ AMD_BIT(UDC_DEVINT_ENUM) |
+ AMD_BIT(UDC_DEVINT_US) |
+ AMD_BIT(UDC_DEVINT_UR) |
+ AMD_BIT(UDC_DEVINT_ES) |
+ AMD_BIT(UDC_DEVINT_SI) |
+ AMD_BIT(UDC_DEVINT_SOF)|
+ AMD_BIT(UDC_DEVINT_SC);
+ writel(tmp, &dev->regs->irqmsk);
+
+ /* mask all ep interrupts */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ /* enable ep0 irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+ & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "enable device interrupts for setup data\n");
+
+ /* read irq mask */
+ tmp = readl(&dev->regs->irqmsk);
+
+ /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_UR)
+ & AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+ & AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+ writel(tmp, &dev->regs->irqmsk);
+
+ return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+ struct udc *dev;
+ u32 tmp;
+ int i;
+
+ if (!ep || !(ep->in))
+ return -EINVAL;
+
+ dev = ep->dev;
+ ep->txfifo = dev->txfifo;
+
+ /* traverse ep's */
+ for (i = 0; i < ep->num; i++) {
+ if (dev->ep[i].regs) {
+ /* read fifo size */
+ tmp = readl(&dev->ep[i].regs->bufin_framenum);
+ tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+ ep->txfifo += tmp;
+ }
+ }
+ return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+ if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+ DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+ cnak_pending |= 1 << (num);
+ ep->naking = 1;
+ } else
+ cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+ struct udc_ep *ep;
+ struct udc *dev;
+ u32 tmp;
+ unsigned long iflags;
+ u8 udc_csr_epix;
+
+ if (!usbep
+ || usbep->name == ep0_string
+ || !desc
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ dev = ep->dev;
+
+ DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ ep->desc = desc;
+
+ ep->halted = 0;
+
+ /* set traffic type */
+ tmp = readl(&dev->ep[ep->num].regs->ctl);
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+ writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+ /* set max packet size */
+ tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+ ep->ep.maxpacket = desc->wMaxPacketSize;
+ writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+ /* IN ep */
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+ /* set buffer size (tx fifo entries) */
+ tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+ /* double buffering: fifo size = 2 x max packet size */
+ tmp = AMD_ADDBITS(
+ tmp,
+ desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+ / UDC_DWORD_BYTES,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+ /* calc. tx fifo base addr */
+ udc_set_txfifo_addr(ep);
+
+ /* flush fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+ /* set max packet size UDC CSR */
+ tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+ if (use_dma && !ep->in) {
+ /* alloc and init BNA dummy request */
+ ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+ ep->bna_occurred = 0;
+ }
+
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_enabled = 1;
+ }
+
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* max packet */
+ tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+ /* ep number */
+ tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+ /* ep direction */
+ tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+ /* ep type */
+ tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+ /* ep config */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+
+ /*
+ * clear NAK by writing CNAK
+ * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+ */
+ if (!use_dma || ep->in) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ tmp = desc->bEndpointAddress;
+ DBG(dev, "%s enabled\n", usbep->name);
+
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+ u32 tmp;
+
+ VDBG(ep->dev, "ep-%d reset\n", ep->num);
+ ep->desc = NULL;
+ ep->ep.ops = &udc_ep_ops;
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->ep.maxpacket = (u16) ~0;
+ /* set NAK */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 1;
+
+ /* disable interrupt */
+ tmp = readl(&regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp, &regs->ep_irqmsk);
+
+ if (ep->in) {
+ /* unset P and IN bit of potential former DMA */
+ tmp = readl(&ep->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+
+ tmp = readl(&ep->regs->sts);
+ tmp |= AMD_BIT(UDC_EPSTS_IN);
+ writel(tmp, &ep->regs->sts);
+
+ /* flush the fifo */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &ep->regs->ctl);
+
+ }
+ /* reset desc pointer */
+ writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+ struct udc_ep *ep = NULL;
+ unsigned long iflags;
+
+ if (!usbep)
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (usbep->name == ep0_string || !ep->desc)
+ return -EINVAL;
+
+ DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+ empty_req_queue(ep);
+ ep_init(ep->dev->regs, ep);
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+ return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+ struct udc_request *req;
+ struct udc_data_dma *dma_desc;
+ struct udc_ep *ep;
+
+ if (!usbep)
+ return NULL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+
+ VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+ req = kzalloc(sizeof(struct udc_request), gfp);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_DONT_USE;
+ INIT_LIST_HEAD(&req->queue);
+
+ if (ep->dma) {
+ /* ep0 in requests are allocated from data pool here */
+ dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+ &req->td_phys);
+ if (!dma_desc) {
+ kfree(req);
+ return NULL;
+ }
+
+ VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+ "td_phys = %lx\n",
+ req, dma_desc,
+ (unsigned long)req->td_phys);
+ /* prevent from using desc. - set HOST BUSY */
+ dma_desc->status = AMD_ADDBITS(dma_desc->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+ req->td_data = dma_desc;
+ req->td_data_last = NULL;
+ req->chain_len = 1;
+ }
+
+ return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+
+ if (!usbep || !usbreq)
+ return;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ req = container_of(usbreq, struct udc_request, req);
+ VDBG(ep->dev, "free_req req=%p\n", req);
+ BUG_ON(!list_empty(&req->queue));
+ if (req->td_data) {
+ VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+ /* free dma chain if created */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+
+ pci_pool_free(ep->dev->data_requests, req->td_data,
+ req->td_phys);
+ }
+ kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+ if (req) {
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* set next pointer to itself */
+ req->td_data->next = req->td_phys;
+ /* set HOST BUSY */
+ req->td_data->status
+ = AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_DMA_DONE,
+ UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+ pr_debug("bna desc = %p, sts = %08x\n",
+ req->td_data, req->td_data->status);
+#endif
+ }
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+ struct udc_request *req = NULL;
+ struct usb_request *_req = NULL;
+
+ /* alloc the dummy request */
+ _req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+ if (_req) {
+ req = container_of(_req, struct udc_request, req);
+ ep->bna_dummy_req = req;
+ udc_init_bna_dummy(req);
+ }
+ return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+ u8 *req_buf;
+ u32 *buf;
+ int i, j;
+ unsigned bytes = 0;
+ unsigned remaining = 0;
+
+ if (!req || !ep)
+ return;
+
+ req_buf = req->buf + req->actual;
+ prefetch(req_buf);
+ remaining = req->length - req->actual;
+
+ buf = (u32 *) req_buf;
+
+ bytes = ep->ep.maxpacket;
+ if (bytes > remaining)
+ bytes = remaining;
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ writel(*(buf + i), ep->txfifo);
+ }
+
+ /* remaining bytes must be written by byte access */
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+ ep->txfifo);
+ }
+
+ /* dummy write confirm */
+ writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+ int i;
+
+ VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+ for (i = 0; i < dwords; i++) {
+ *(buf + i) = readl(dev->rxfifo);
+ }
+ return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+ int i, j;
+ u32 tmp;
+
+ VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+ /* dwords first */
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+ }
+
+ /* remaining bytes must be read by byte access */
+ if (bytes % UDC_DWORD_BYTES) {
+ tmp = readl(dev->rxfifo);
+ for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+ *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+ tmp = tmp >> UDC_BITS_PER_BYTE;
+ }
+ }
+
+ return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+ u8 *buf;
+ unsigned buf_space;
+ unsigned bytes = 0;
+ unsigned finished = 0;
+
+ /* received number bytes */
+ bytes = readl(&ep->regs->sts);
+ bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+ buf_space = req->req.length - req->req.actual;
+ buf = req->req.buf + req->req.actual;
+ if (bytes > buf_space) {
+ if ((buf_space % ep->ep.maxpacket) != 0) {
+ DBG(ep->dev,
+ "%s: rx %d bytes, rx-buf space = %d bytesn\n",
+ ep->ep.name, bytes, buf_space);
+ req->req.status = -EOVERFLOW;
+ }
+ bytes = buf_space;
+ }
+ req->req.actual += bytes;
+
+ /* last packet ? */
+ if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+ || ((req->req.actual == req->req.length) && !req->req.zero))
+ finished = 1;
+
+ /* read rx fifo bytes */
+ VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+ udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+ return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+ int retval = 0;
+ u32 tmp;
+
+ VDBG(ep->dev, "prep_dma\n");
+ VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+ ep->num, req->td_data);
+
+ /* set buffer pointer */
+ req->td_data->bufptr = req->req.dma;
+
+ /* set last bit */
+ req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+ /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+ if (use_dma_ppb) {
+
+ retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+ if (retval != 0) {
+ if (retval == -ENOMEM)
+ DBG(ep->dev, "Out of DMA memory\n");
+ return retval;
+ }
+ if (ep->in) {
+ if (req->req.length == ep->ep.maxpacket) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+
+ }
+ }
+
+ }
+
+ if (ep->in) {
+ VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+ "maxpacket=%d ep%d\n",
+ use_dma_ppb, req->req.length,
+ ep->ep.maxpacket, ep->num);
+ /*
+ * if bytes < max packet then tx bytes must
+ * be written in packet per buffer mode
+ */
+ if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+ || ep->num == UDC_EP0OUT_IX
+ || ep->num == UDC_EP0IN_IX) {
+ /* write tx bytes */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ req->req.length,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* reset frame num */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ 0,
+ UDC_DMA_IN_STS_FRAMENUM);
+ }
+ /* set HOST BUSY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_BUSY,
+ UDC_DMA_STP_STS_BS);
+ } else {
+ VDBG(ep->dev, "OUT set host ready\n");
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ }
+
+ return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+ struct udc *dev;
+ unsigned halted;
+
+ VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+ dev = ep->dev;
+ /* unmap DMA */
+ if (req->dma_mapping) {
+ if (ep->in)
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_TODEVICE);
+ else
+ pci_unmap_single(dev->pdev,
+ req->req.dma,
+ req->req.length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 0;
+ req->req.dma = DMA_DONT_USE;
+ }
+
+ halted = ep->halted;
+ ep->halted = 1;
+
+ /* set new status if pending */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = sts;
+
+ /* remove from ep queue */
+ list_del_init(&req->queue);
+
+ VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+ &req->req, req->req.length, ep->ep.name, sts);
+
+ spin_unlock(&dev->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dev->lock);
+ ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+ int ret_val = 0;
+ struct udc_data_dma *td;
+ struct udc_data_dma *td_last = NULL;
+ unsigned int i;
+
+ DBG(dev, "free chain req = %p\n", req);
+
+ /* do not free first desc., will be done by free for request */
+ td_last = req->td_data;
+ td = phys_to_virt(td_last->next);
+
+ for (i = 1; i < req->chain_len; i++) {
+
+ pci_pool_free(dev->data_requests, td,
+ (dma_addr_t) td_last->next);
+ td_last = td;
+ td = phys_to_virt(td_last->next);
+ }
+
+ return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+
+ td = req->td_data;
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ }
+
+ return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+ struct udc_data_dma *td;
+ u32 count;
+
+ td = req->td_data;
+ /* received number bytes */
+ count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ td = phys_to_virt(td->next);
+ /* received number bytes */
+ if (td) {
+ count += AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ }
+ }
+
+ return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+ struct udc_ep *ep,
+ struct udc_request *req,
+ unsigned long buf_len, gfp_t gfp_flags
+)
+{
+ unsigned long bytes = req->req.length;
+ unsigned int i;
+ dma_addr_t dma_addr;
+ struct udc_data_dma *td = NULL;
+ struct udc_data_dma *last = NULL;
+ unsigned long txbytes;
+ unsigned create_new_chain = 0;
+ unsigned len;
+
+ VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+ bytes, buf_len);
+ dma_addr = DMA_DONT_USE;
+
+ /* unset L bit in first desc for OUT */
+ if (!ep->in) {
+ req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+ }
+
+ /* alloc only new desc's if not already available */
+ len = req->req.length / ep->ep.maxpacket;
+ if (req->req.length % ep->ep.maxpacket) {
+ len++;
+ }
+
+ if (len > req->chain_len) {
+ /* shorter chain already allocated before */
+ if (req->chain_len > 1) {
+ udc_free_dma_chain(ep->dev, req);
+ }
+ req->chain_len = len;
+ create_new_chain = 1;
+ }
+
+ td = req->td_data;
+ /* gen. required number of descriptors and buffers */
+ for (i = buf_len; i < bytes; i += buf_len) {
+ /* create or determine next desc. */
+ if (create_new_chain) {
+
+ td = pci_pool_alloc(ep->dev->data_requests,
+ gfp_flags, &dma_addr);
+ if (!td)
+ return -ENOMEM;
+
+ td->status = 0;
+ } else if (i == buf_len) {
+ /* first td */
+ td = (struct udc_data_dma *) phys_to_virt(
+ req->td_data->next);
+ td->status = 0;
+ } else {
+ td = (struct udc_data_dma *) phys_to_virt(last->next);
+ td->status = 0;
+ }
+
+
+ if (td)
+ td->bufptr = req->req.dma + i; /* assign buffer */
+ else
+ break;
+
+ /* short packet ? */
+ if ((bytes - i) >= buf_len) {
+ txbytes = buf_len;
+ } else {
+ /* short packet */
+ txbytes = bytes - i;
+ }
+
+ /* link td and assign tx bytes */
+ if (i == buf_len) {
+ if (create_new_chain) {
+ req->td_data->next = dma_addr;
+ } else {
+ /* req->td_data->next = virt_to_phys(td); */
+ }
+ /* write tx bytes */
+ if (ep->in) {
+ /* first desc */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ ep->ep.maxpacket,
+ UDC_DMA_IN_STS_TXBYTES);
+ /* second desc */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ } else {
+ if (create_new_chain) {
+ last->next = dma_addr;
+ } else {
+ /* last->next = virt_to_phys(td); */
+ }
+ if (ep->in) {
+ /* write tx bytes */
+ td->status = AMD_ADDBITS(td->status,
+ txbytes,
+ UDC_DMA_IN_STS_TXBYTES);
+ }
+ }
+ last = td;
+ }
+ /* set last bit */
+ if (td) {
+ td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+ /* last desc. points to itself */
+ req->td_data_last = td;
+ }
+
+ return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+ u32 tmp;
+
+ VDBG(dev, "udc_set_rde()\n");
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* set RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+ int retval = 0;
+ u8 open_rxfifo = 0;
+ unsigned long iflags;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc *dev;
+ u32 tmp;
+
+ /* check the inputs */
+ req = container_of(usbreq, struct udc_request, req);
+
+ if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+ || !list_empty(&req->queue))
+ return -EINVAL;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+
+ VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+ dev = ep->dev;
+
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ /* map dma (usually done before) */
+ if (ep->dma && usbreq->length != 0
+ && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+ VDBG(dev, "DMA map req %p\n", req);
+ if (ep->in)
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_TODEVICE);
+ else
+ usbreq->dma = pci_map_single(dev->pdev,
+ usbreq->buf,
+ usbreq->length,
+ PCI_DMA_FROMDEVICE);
+ req->dma_mapping = 1;
+ }
+
+ VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+ usbep->name, usbreq, usbreq->length,
+ req->td_data, usbreq->buf);
+
+ spin_lock_irqsave(&dev->lock, iflags);
+ usbreq->actual = 0;
+ usbreq->status = -EINPROGRESS;
+ req->dma_done = 0;
+
+ /* on empty queue just do first transfer */
+ if (list_empty(&ep->queue)) {
+ /* zlp */
+ if (usbreq->length == 0) {
+ /* IN zlp's are handled by hardware */
+ complete_req(ep, req, 0);
+ VDBG(dev, "%s: zlp\n", ep->ep.name);
+ /*
+ * if set_config or set_intf is waiting for ack by zlp
+ * then set CSR_DONE
+ */
+ if (dev->set_cfg_not_acked) {
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+ writel(tmp, &dev->regs->ctl);
+ dev->set_cfg_not_acked = 0;
+ }
+ /* setup command is ACK'ed now by zlp */
+ if (dev->waiting_zlp_ack_ep0in) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+ UDC_EP0IN_IX);
+ dev->waiting_zlp_ack_ep0in = 0;
+ }
+ goto finished;
+ }
+ if (ep->dma) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ /* write desc pointer to enable DMA */
+ if (ep->in) {
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+ }
+
+ /* disabled rx dma while descriptor update */
+ if (!ep->in) {
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* clear RDE */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &dev->regs->ctl);
+ open_rxfifo = 1;
+
+ /*
+ * if BNA occurred then let BNA dummy desc.
+ * point to current desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "copy to BNA dummy desc.\n");
+ memcpy(ep->bna_dummy_req->td_data,
+ req->td_data,
+ sizeof(struct udc_data_dma));
+ }
+ }
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* clear NAK by writing CNAK */
+ if (ep->naking) {
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->naking = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+
+ if (ep->in) {
+ /* enable ep irq */
+ tmp = readl(&dev->regs->ep_irqmsk);
+ tmp &= AMD_UNMASK_BIT(ep->num);
+ writel(tmp, &dev->regs->ep_irqmsk);
+ }
+ }
+
+ } else if (ep->dma) {
+
+ /*
+ * prep_dma not used for OUT ep's, this is not possible
+ * for PPB modes, because of chain creation reasons
+ */
+ if (ep->in) {
+ retval = prep_dma(ep, req, gfp);
+ if (retval != 0)
+ goto finished;
+ }
+ }
+ VDBG(dev, "list_add\n");
+ /* add request to ep queue */
+ if (req) {
+
+ list_add_tail(&req->queue, &ep->queue);
+
+ /* open rxfifo if out data queued */
+ if (open_rxfifo) {
+ /* enable DMA */
+ req->dma_going = 1;
+ udc_set_rde(dev);
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 1;
+ }
+ /* stop OUT naking */
+ if (!ep->in) {
+ if (!use_dma && udc_rxfifo_pending) {
+ DBG(dev, "udc_queue(): pending bytes in"
+ "rxfifo after nyet\n");
+ /*
+ * read pending bytes afer nyet:
+ * referring to isr
+ */
+ if (udc_rxfifo_read(ep, req)) {
+ /* finish */
+ complete_req(ep, req, 0);
+ }
+ udc_rxfifo_pending = 0;
+
+ }
+ }
+ }
+
+finished:
+ spin_unlock_irqrestore(&dev->lock, iflags);
+ return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+ struct udc_request *req;
+
+ ep->halted = 1;
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ complete_req(ep, req, -ESHUTDOWN);
+ }
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned halted;
+ unsigned long iflags;
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+ && ep->num != UDC_EP0OUT_IX)))
+ return -EINVAL;
+
+ req = container_of(usbreq, struct udc_request, req);
+
+ spin_lock_irqsave(&ep->dev->lock, iflags);
+ halted = ep->halted;
+ ep->halted = 1;
+ /* request in processing or next one */
+ if (ep->queue.next == &req->queue) {
+ if (ep->dma && req->dma_going) {
+ if (ep->in)
+ ep->cancel_transfer = 1;
+ else {
+ u32 tmp;
+ u32 dma_sts;
+ /* stop potential receive DMA */
+ tmp = readl(&udc->regs->ctl);
+ writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+ &udc->regs->ctl);
+ /*
+ * Cancel transfer later in ISR
+ * if descriptor was touched.
+ */
+ dma_sts = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+ ep->cancel_transfer = 1;
+ else {
+ udc_init_bna_dummy(ep->req);
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ }
+ writel(tmp, &udc->regs->ctl);
+ }
+ }
+ }
+ complete_req(ep, req, -ECONNRESET);
+ ep->halted = halted;
+
+ spin_unlock_irqrestore(&ep->dev->lock, iflags);
+ return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ unsigned long iflags;
+ int retval = 0;
+
+ if (!usbep)
+ return -EINVAL;
+
+ pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+ ep = container_of(usbep, struct udc_ep, ep);
+ if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+ return -EINVAL;
+ if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&udc_stall_spinlock, iflags);
+ /* halt or clear halt */
+ if (halt) {
+ if (ep->num == 0)
+ ep->dev->stall_ep0in = 1;
+ else {
+ /*
+ * set STALL
+ * rxfifo empty not taken into acount
+ */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 1;
+
+ /* setup poll timer */
+ if (!timer_pending(&udc_pollstall_timer)) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ if (!stop_pollstall_timer) {
+ DBG(ep->dev, "start polltimer\n");
+ add_timer(&udc_pollstall_timer);
+ }
+ }
+ }
+ } else {
+ /* ep is halted by set_halt() before */
+ if (ep->halted) {
+ tmp = readl(&ep->regs->ctl);
+ /* clear stall bit */
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+ spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+ return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+ .enable = udc_ep_enable,
+ .disable = udc_ep_disable,
+
+ .alloc_request = udc_alloc_request,
+ .free_request = udc_free_request,
+
+ .queue = udc_queue,
+ .dequeue = udc_dequeue,
+
+ .set_halt = udc_set_halt,
+ /* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+ return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+ struct udc *dev;
+
+ if (!gadget)
+ return -EINVAL;
+ dev = container_of(gadget, struct udc, gadget);
+ udc_remote_wakeup(dev);
+
+ return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+ .wakeup = udc_wakeup,
+ .get_frame = udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+ /* make gadget ep lists */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+ list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+ &dev->gadget.ep_list);
+
+ /* fifo config */
+ dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+ dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+ u32 tmp;
+
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+
+ /* program speed */
+ tmp = readl(&dev->regs->cfg);
+ if (use_fullspeed) {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ } else {
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+ }
+ writel(tmp, &dev->regs->cfg);
+
+ return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "udc_basic_init()\n");
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop poll stall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* disable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+ writel(tmp, &dev->regs->ctl);
+
+ /* enable dynamic CSR programming */
+ tmp = readl(&dev->regs->cfg);
+ tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+ /* set self powered */
+ tmp |= AMD_BIT(UDC_DEVCFG_SP);
+ /* set remote wakeupable */
+ tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+ writel(tmp, &dev->regs->cfg);
+
+ make_ep_lists(dev);
+
+ dev->data_ep_enabled = 0;
+ dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+ struct udc_ep *ep;
+ u32 tmp;
+ u32 reg;
+
+ DBG(dev, "udc_setup_endpoints()\n");
+
+ /* read enum speed */
+ tmp = readl(&dev->regs->sts);
+ tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+ if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+ dev->gadget.speed = USB_SPEED_HIGH;
+ } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+ dev->gadget.speed = USB_SPEED_FULL;
+ }
+
+ /* set basic ep parameters */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ ep = &dev->ep[tmp];
+ ep->dev = dev;
+ ep->ep.name = ep_string[tmp];
+ ep->num = tmp;
+ /* txfifo size is calculated at enable time */
+ ep->txfifo = dev->txfifo;
+
+ /* fifo size */
+ if (tmp < UDC_EPIN_NUM) {
+ ep->fifo_depth = UDC_TXFIFO_SIZE;
+ ep->in = 1;
+ } else {
+ ep->fifo_depth = UDC_RXFIFO_SIZE;
+ ep->in = 0;
+
+ }
+ ep->regs = &dev->ep_regs[tmp];
+ /*
+ * ep will be reset only if ep was not enabled before to avoid
+ * disabling ep interrupts when ENUM interrupt occurs but ep is
+ * not enabled by gadget driver
+ */
+ if (!ep->desc) {
+ ep_init(dev->regs, ep);
+ }
+
+ if (use_dma) {
+ /*
+ * ep->dma is not really used, just to indicate that
+ * DMA is active: remove this
+ * dma regs = dev control regs
+ */
+ ep->dma = &dev->regs->ctl;
+
+ /* nak OUT endpoints until enable - not for ep0 */
+ if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+ && tmp > UDC_EPIN_NUM) {
+ /* set NAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 1;
+
+ }
+ }
+ }
+ /* EP0 max packet */
+ if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+ UDC_FS_EP0OUT_MAX_PKT_SIZE;
+ } else if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+ dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+ }
+
+ /*
+ * with suspend bug workaround, ep0 params for gadget driver
+ * are set at gadget driver bind() call
+ */
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ dev->ep[UDC_EP0IN_IX].halted = 0;
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+ /* init cfg/alt/int */
+ dev->cur_config = 0;
+ dev->cur_intf = 0;
+ dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Connect\n");
+
+ dev->connected = 1;
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+ dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+ dev->connected = 0;
+
+ /* mask interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* REVISIT there doesn't seem to be a point to having this
+ * talk to a tasklet ... do it directly, we already hold
+ * the spinlock needed to process the disconnect.
+ */
+
+ tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+ struct udc *dev = (struct udc *)(*((struct udc **) par));
+ u32 tmp;
+
+ DBG(dev, "Tasklet disconnect\n");
+ spin_lock_irq(&dev->lock);
+
+ if (dev->driver) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* empty queues */
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ }
+
+ /* disable ep0 */
+ ep_init(dev->regs,
+ &dev->ep[UDC_EP0IN_IX]);
+
+
+ if (!soft_reset_occured) {
+ /* init controller by soft reset */
+ udc_soft_reset(dev);
+ soft_reset_occured++;
+ }
+
+ /* re-enable dev interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+ /* back to full speed ? */
+ if (use_fullspeed) {
+ tmp = readl(&dev->regs->cfg);
+ tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+ writel(tmp, &dev->regs->cfg);
+ }
+
+ spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+ unsigned long flags;
+
+ DBG(dev, "Soft reset\n");
+ /*
+ * reset possible waiting interrupts, because int.
+ * status is lost after soft reset,
+ * ep int. status reset
+ */
+ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+ /* device int. status reset */
+ writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+ spin_lock_irqsave(&udc_irq_spinlock, flags);
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ readl(&dev->regs->cfg);
+ spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+ u32 tmp;
+
+ spin_lock_irq(&udc_irq_spinlock);
+
+ if (set_rde > 0) {
+ /*
+ * open the fifo if fifo was filled on last timer call
+ * conditionally
+ */
+ if (set_rde > 1) {
+ /* set RDE to receive setup data */
+ tmp = readl(&udc->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+ writel(tmp, &udc->regs->ctl);
+ set_rde = -1;
+ } else if (readl(&udc->regs->sts)
+ & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ /*
+ * if fifo empty setup polling, do not just
+ * open the fifo
+ */
+ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ } else {
+ /*
+ * fifo contains data now, setup timer for opening
+ * the fifo when timer expires to be able to receive
+ * setup packets, when data packets gets queued by
+ * gadget layer then timer will forced to expire with
+ * set_rde=0 (RDE is set in udc_queue())
+ */
+ set_rde++;
+ /* debug: lhadmot_timer_start = 221070 */
+ udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+
+ } else
+ set_rde = -1; /* RDE was set by udc_queue() */
+ spin_unlock_irq(&udc_irq_spinlock);
+ if (stop_timer)
+ complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+ u32 tmp;
+ /* set stall as long not halted */
+ if (ep->halted == 1) {
+ tmp = readl(&ep->regs->ctl);
+ /* STALL cleared ? */
+ if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+ /*
+ * FIXME: MSC spec requires that stall remains
+ * even on receivng of CLEAR_FEATURE HALT. So
+ * we would set STALL again here to be compliant.
+ * But with current mass storage drivers this does
+ * not work (would produce endless host retries).
+ * So we clear halt on CLEAR_FEATURE.
+ *
+ DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);*/
+
+ /* clear NAK by writing CNAK */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &ep->regs->ctl);
+ ep->halted = 0;
+ UDC_QUEUE_CNAK(ep, ep->num);
+ }
+ }
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+ struct udc_ep *ep;
+ int halted = 0;
+
+ spin_lock_irq(&udc_stall_spinlock);
+ /*
+ * only one IN and OUT endpoints are handled
+ * IN poll stall
+ */
+ ep = &udc->ep[UDC_EPIN_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+ /* OUT poll stall */
+ ep = &udc->ep[UDC_EPOUT_IX];
+ udc_handle_halt_state(ep);
+ if (ep->halted)
+ halted = 1;
+
+ /* setup timer again when still halted */
+ if (!stop_pollstall_timer && halted) {
+ udc_pollstall_timer.expires = jiffies +
+ HZ * UDC_POLLSTALL_TIMER_USECONDS
+ / (1000 * 1000);
+ add_timer(&udc_pollstall_timer);
+ }
+ spin_unlock_irq(&udc_stall_spinlock);
+
+ if (stop_pollstall_timer)
+ complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+ u32 tmp;
+
+ DBG(dev, "activate_control_endpoints\n");
+
+ /* flush fifo */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_F);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* set ep0 directions */
+ dev->ep[UDC_EP0IN_IX].in = 1;
+ dev->ep[UDC_EP0OUT_IX].in = 0;
+
+ /* set buffer size (tx fifo entries) of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+ UDC_EPIN_BUFF_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+ /* set max packet size of EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0_OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_EP_MAX_PKT_SIZE);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+ /* set max packet size of EP0 in UDC CSR */
+ tmp = readl(&dev->csr->ne[0]);
+ if (dev->gadget.speed == USB_SPEED_FULL)
+ tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ else if (dev->gadget.speed == USB_SPEED_HIGH)
+ tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+ UDC_CSR_NE_MAX_PKT);
+ writel(tmp, &dev->csr->ne[0]);
+
+ if (use_dma) {
+ dev->ep[UDC_EP0OUT_IX].td->status |=
+ AMD_BIT(UDC_DMA_OUT_STS_L);
+ /* write dma desc address */
+ writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+ &dev->ep[UDC_EP0OUT_IX].regs->subptr);
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* stop RDE timer */
+ if (timer_pending(&udc_timer)) {
+ set_rde = 0;
+ mod_timer(&udc_timer, jiffies - 1);
+ }
+ /* stop pollstall timer */
+ if (timer_pending(&udc_pollstall_timer)) {
+ mod_timer(&udc_pollstall_timer, jiffies - 1);
+ }
+ /* enable DMA */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+ | AMD_BIT(UDC_DEVCTL_RDE)
+ | AMD_BIT(UDC_DEVCTL_TDE);
+ if (use_dma_bufferfill_mode) {
+ tmp |= AMD_BIT(UDC_DEVCTL_BF);
+ } else if (use_dma_ppb_du) {
+ tmp |= AMD_BIT(UDC_DEVCTL_DU);
+ }
+ writel(tmp, &dev->regs->ctl);
+ }
+
+ /* clear NAK by writing CNAK for EP0IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* clear NAK by writing CNAK for EP0OUT */
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+ activate_control_endpoints(dev);
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ int retval;
+ u32 tmp;
+
+ if (!driver || !driver->bind || !driver->setup
+ || driver->speed != USB_SPEED_HIGH)
+ return -EINVAL;
+ if (!dev)
+ return -ENODEV;
+ if (dev->driver)
+ return -EBUSY;
+
+ driver->driver.bus = NULL;
+ dev->driver = driver;
+ dev->gadget.dev.driver = &driver->driver;
+
+ retval = driver->bind(&dev->gadget);
+
+ /* Some gadget drivers use both ep0 directions.
+ * NOTE: to gadget driver, ep0 is just one endpoint...
+ */
+ dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+ dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+ if (retval) {
+ DBG(dev, "binding to %s returning %d\n",
+ driver->driver.name, retval);
+ dev->driver = NULL;
+ dev->gadget.dev.driver = NULL;
+ return retval;
+ }
+
+ /* get ready for ep0 traffic */
+ setup_ep0(dev);
+
+ /* clear SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+ usb_connect(dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ int tmp;
+
+ /* empty queues and init hardware */
+ udc_basic_init(dev);
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ empty_req_queue(&dev->ep[tmp]);
+ }
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+ spin_unlock(&dev->lock);
+ driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ /* init */
+ udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct udc *dev = udc;
+ unsigned long flags;
+ u32 tmp;
+
+ if (!dev)
+ return -ENODEV;
+ if (!driver || driver != dev->driver || !driver->unbind)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ udc_mask_unused_interrupts(dev);
+ shutdown(dev, driver);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ driver->unbind(&dev->gadget);
+ dev->driver = NULL;
+
+ /* set SD */
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(tmp, &dev->regs->ctl);
+
+
+ DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+ u32 tmp;
+ u32 reg;
+
+ /* check epin's */
+ DBG(dev, "CNAK pending queue processing\n");
+ for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+ if (cnak_pending & (1 << tmp)) {
+ DBG(dev, "CNAK pending for ep%d\n", tmp);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[tmp].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[tmp].regs->ctl);
+ dev->ep[tmp].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+ }
+ }
+ /* ... and ep0out */
+ if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+ DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+ /* clear NAK by writing CNAK */
+ reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ reg |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+ dev->ep[UDC_EP0OUT_IX].num);
+ }
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+ if (use_dma) {
+ /*
+ * only enable RXDMA when no data endpoint enabled
+ * or data is queued
+ */
+ if (!dev->data_ep_enabled || dev->data_ep_queued) {
+ udc_set_rde(dev);
+ } else {
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data endpoints to early)
+ */
+ if (set_rde != 0 && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies + HZ/UDC_RDE_TIMER_DIV;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+ }
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned int count;
+ struct udc_data_dma *td = NULL;
+ unsigned dma_done;
+
+ VDBG(dev, "ep%d irq\n", ep_ix);
+ ep = &dev->ep[ep_ix];
+
+ tmp = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+ ep->num, readl(&ep->regs->desptr));
+ /* clear BNA */
+ writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+ if (!ep->cancel_transfer)
+ ep->bna_occurred = 1;
+ else
+ ep->cancel_transfer = 0;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+ /* clear HE */
+ writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ if (!list_empty(&ep->queue)) {
+
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else {
+ req = NULL;
+ udc_rxfifo_pending = 1;
+ }
+ VDBG(dev, "req = %p\n", req);
+ /* fifo mode */
+ if (!use_dma) {
+
+ /* read fifo */
+ if (req && udc_rxfifo_read(ep, req)) {
+ ret_val = IRQ_HANDLED;
+
+ /* finish */
+ complete_req(ep, req, 0);
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ } else
+ req = NULL;
+ }
+
+ /* DMA */
+ } else if (!ep->cancel_transfer && req != NULL) {
+ ret_val = IRQ_HANDLED;
+
+ /* check for DMA done */
+ if (!use_dma_ppb) {
+ dma_done = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_BS);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ /*
+ * if BNA occurred then recover desc. from
+ * BNA dummy desc.
+ */
+ if (ep->bna_occurred) {
+ VDBG(dev, "Recover desc. from BNA dummy\n");
+ memcpy(req->td_data, ep->bna_dummy_req->td_data,
+ sizeof(struct udc_data_dma));
+ ep->bna_occurred = 0;
+ udc_init_bna_dummy(ep->req);
+ }
+ td = udc_get_last_dma_desc(req);
+ dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+ }
+ if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+ /* buffer fill mode - rx bytes */
+ if (!use_dma_ppb) {
+ /* received number bytes */
+ count = AMD_GETBITS(req->td_data->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ VDBG(dev, "rx bytes=%u\n", count);
+ /* packet per buffer mode - rx bytes */
+ } else {
+ VDBG(dev, "req->td_data=%p\n", req->td_data);
+ VDBG(dev, "last desc = %p\n", td);
+ /* received number bytes */
+ if (use_dma_ppb_du) {
+ /* every desc. counts bytes */
+ count = udc_get_ppbdu_rxbytes(req);
+ } else {
+ /* last desc. counts bytes */
+ count = AMD_GETBITS(td->status,
+ UDC_DMA_OUT_STS_RXBYTES);
+ if (!count && req->req.length
+ == UDC_DMA_MAXPACKET) {
+ /*
+ * on 64k packets the RXBYTES
+ * field is zero
+ */
+ count = UDC_DMA_MAXPACKET;
+ }
+ }
+ VDBG(dev, "last desc rx bytes=%u\n", count);
+ }
+
+ tmp = req->req.length - req->req.actual;
+ if (count > tmp) {
+ if ((tmp % ep->ep.maxpacket) != 0) {
+ DBG(dev, "%s: rx %db, space=%db\n",
+ ep->ep.name, count, tmp);
+ req->req.status = -EOVERFLOW;
+ }
+ count = tmp;
+ }
+ req->req.actual += count;
+ req->dma_going = 0;
+ /* complete request */
+ complete_req(ep, req, 0);
+
+ /* next request */
+ if (!list_empty(&ep->queue) && !ep->halted) {
+ req = list_entry(ep->queue.next,
+ struct udc_request,
+ queue);
+ /*
+ * DMA may be already started by udc_queue()
+ * called by gadget drivers completion
+ * routine. This happens when queue
+ * holds one request only.
+ */
+ if (req->dma_going == 0) {
+ /* next dma */
+ if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+ goto finished;
+ /* write desc pointer */
+ writel(req->td_phys,
+ &ep->regs->desptr);
+ req->dma_going = 1;
+ /* enable DMA */
+ udc_set_rde(dev);
+ }
+ } else {
+ /*
+ * implant BNA dummy descriptor to allow
+ * RXFIFO opening by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &ep->regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ /*
+ * schedule timer for setting RDE if queue
+ * remains empty to allow ep0 packets pass
+ * through
+ */
+ if (set_rde != 0
+ && !timer_pending(&udc_timer)) {
+ udc_timer.expires =
+ jiffies
+ + HZ*UDC_RDE_TIMER_SECONDS;
+ set_rde = 1;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ if (ep->num != UDC_EP0OUT_IX)
+ dev->data_ep_queued = 0;
+ }
+
+ } else {
+ /*
+ * RX DMA must be reenabled for each desc in PPBDU mode
+ * and must be enabled for PPBNDU mode in case of BNA
+ */
+ udc_set_rde(dev);
+ }
+
+ } else if (ep->cancel_transfer) {
+ ret_val = IRQ_HANDLED;
+ ep->cancel_transfer = 0;
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 epsts;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ struct udc_data_dma *td;
+ unsigned dma_done;
+ unsigned len;
+
+ ep = &dev->ep[ep_ix];
+
+ epsts = readl(&ep->regs->sts);
+ if (use_dma) {
+ /* BNA ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+ dev_err(&dev->pdev->dev,
+ "BNA ep%din occured - DESPTR = %08lx \n",
+ ep->num,
+ (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear BNA */
+ writel(epsts, &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+ }
+ /* HE event ? */
+ if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+ dev_err(&dev->pdev->dev,
+ "HE ep%dn occured - DESPTR = %08lx \n",
+ ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+ /* clear HE */
+ writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* DMA completion */
+ if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "TDC set- completion\n");
+ ret_val = IRQ_HANDLED;
+ if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ if (req) {
+ /*
+ * length bytes transfered
+ * check dma done of last desc. in PPBDU mode
+ */
+ if (use_dma_ppb_du) {
+ td = udc_get_last_dma_desc(req);
+ if (td) {
+ dma_done =
+ AMD_GETBITS(td->status,
+ UDC_DMA_IN_STS_BS);
+ /* don't care DMA done */
+ req->req.actual =
+ req->req.length;
+ }
+ } else {
+ /* assume all bytes transferred */
+ req->req.actual = req->req.length;
+ }
+
+ if (req->req.actual == req->req.length) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ req->dma_going = 0;
+ /* further request available ? */
+ if (list_empty(&ep->queue)) {
+ /* disable interrupt */
+ tmp = readl(
+ &dev->regs->ep_irqmsk);
+ tmp |= AMD_BIT(ep->num);
+ writel(tmp,
+ &dev->regs->ep_irqmsk);
+ }
+
+ }
+ }
+ }
+ ep->cancel_transfer = 0;
+
+ }
+ /*
+ * status reg has IN bit set and TDC not set (if TDC was handled,
+ * IN must not be handled (UDC defect) ?
+ */
+ if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+ && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+ ret_val = IRQ_HANDLED;
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+ /* FIFO mode */
+ if (!use_dma) {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ /* DMA */
+ } else if (req && !req->dma_going) {
+ VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+ req, req->td_data);
+ if (req->td_data) {
+
+ req->dma_going = 1;
+
+ /*
+ * unset L bit of first desc.
+ * for chain
+ */
+ if (use_dma_ppb && req->req.length >
+ ep->ep.maxpacket) {
+ req->td_data->status &=
+ AMD_CLEAR_BIT(
+ UDC_DMA_IN_STS_L);
+ }
+
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_IN_STS_BS_HOST_READY,
+ UDC_DMA_IN_STS_BS);
+
+ /* set poll demand bit */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp, &ep->regs->ctl);
+ }
+ }
+
+ }
+ }
+ /* clear status bits */
+ writel(epsts, &ep->regs->sts);
+
+finished:
+ return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ int setup_supported;
+ u32 count;
+ int set = 0;
+ struct udc_ep *ep;
+ struct udc_ep *ep_tmp;
+
+ ep = &dev->ep[UDC_EP0OUT_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ /* check BNA and clear if set */
+ if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+ VDBG(dev, "ep0: BNA set\n");
+ writel(AMD_BIT(UDC_EPSTS_BNA),
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ ep->bna_occurred = 1;
+ ret_val = IRQ_HANDLED;
+ goto finished;
+ }
+
+ /* type of data: SETUP or DATA 0 bytes */
+ tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+ VDBG(dev, "data_typ = %x\n", tmp);
+
+ /* setup data */
+ if (tmp == UDC_EPSTS_OUT_SETUP) {
+ ret_val = IRQ_HANDLED;
+
+ ep->dev->stall_ep0in = 0;
+ dev->waiting_zlp_ack_ep0in = 0;
+
+ /* set NAK for EP0_IN */
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 1;
+ /* get setup data */
+ if (use_dma) {
+
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ setup_data.data[0] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+ setup_data.data[1] =
+ dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td_stp->status =
+ UDC_DMA_STP_STS_BS_HOST_READY;
+ } else {
+ /* read fifo */
+ udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+ }
+
+ /* determine direction of control data */
+ if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ set = 0;
+ } else {
+ dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+ /*
+ * implant BNA dummy descriptor to allow RXFIFO opening
+ * by RDE
+ */
+ if (ep->bna_dummy_req) {
+ /* write desc pointer */
+ writel(ep->bna_dummy_req->td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ ep->bna_occurred = 0;
+ }
+
+ set = 1;
+ dev->ep[UDC_EP0OUT_IX].naking = 1;
+ /*
+ * setup timer for enabling RDE (to not enable
+ * RXFIFO DMA for data to early)
+ */
+ set_rde = 1;
+ if (!timer_pending(&udc_timer)) {
+ udc_timer.expires = jiffies +
+ HZ/UDC_RDE_TIMER_DIV;
+ if (!stop_timer) {
+ add_timer(&udc_timer);
+ }
+ }
+ }
+
+ /*
+ * mass storage reset must be processed here because
+ * next packet may be a CLEAR_FEATURE HALT which would not
+ * clear the stall bit when no STALL handshake was received
+ * before (autostall can cause this)
+ */
+ if (setup_data.data[0] == UDC_MSCRES_DWORD0
+ && setup_data.data[1] == UDC_MSCRES_DWORD1) {
+ DBG(dev, "MSC Reset\n");
+ /*
+ * clear stall bits
+ * only one IN and OUT endpoints are handled
+ */
+ ep_tmp = &udc->ep[UDC_EPIN_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ ep_tmp = &udc->ep[UDC_EPOUT_IX];
+ udc_set_halt(&ep_tmp->ep, 0);
+ }
+
+ /* call gadget with setup data received */
+ spin_unlock(&dev->lock);
+ setup_supported = dev->driver->setup(&dev->gadget,
+ &setup_data.request);
+ spin_lock(&dev->lock);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ /* ep0 in returns data (not zlp) on IN phase */
+ if (setup_supported >= 0 && setup_supported <
+ UDC_EP0IN_MAXPACKET) {
+ /* clear NAK by writing CNAK in EP0_IN */
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ dev->ep[UDC_EP0IN_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+ /* if unsupported request then stall */
+ } else if (setup_supported < 0) {
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+ } else
+ dev->waiting_zlp_ack_ep0in = 1;
+
+
+ /* clear NAK by writing CNAK in EP0_OUT */
+ if (!set) {
+ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+ writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+ dev->ep[UDC_EP0OUT_IX].naking = 0;
+ UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+ }
+
+ if (!use_dma) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR,
+ &dev->ep[UDC_EP0OUT_IX].regs->sts);
+ }
+
+ /* data packet 0 bytes */
+ } else if (tmp == UDC_EPSTS_OUT_DATA) {
+ /* clear OUT bits in ep status */
+ writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+ /* get setup data: only 0 packet */
+ if (use_dma) {
+ /* no req if 0 packet, just reactivate */
+ if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+ VDBG(dev, "ZLP\n");
+
+ /* set HOST READY */
+ dev->ep[UDC_EP0OUT_IX].td->status =
+ AMD_ADDBITS(
+ dev->ep[UDC_EP0OUT_IX].td->status,
+ UDC_DMA_OUT_STS_BS_HOST_READY,
+ UDC_DMA_OUT_STS_BS);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ ret_val = IRQ_HANDLED;
+
+ } else {
+ /* control write */
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ /* re-program desc. pointer for possible ZLPs */
+ writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+ &dev->ep[UDC_EP0OUT_IX].regs->desptr);
+ /* enable RDE */
+ udc_ep0_set_rde(dev);
+ }
+ } else {
+
+ /* received number bytes */
+ count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+ count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+ /* out data for fifo mode not working */
+ count = 0;
+
+ /* 0 packet or real data ? */
+ if (count != 0) {
+ ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+ } else {
+ /* dummy read confirm */
+ readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+ ret_val = IRQ_HANDLED;
+ }
+ }
+ }
+
+ /* check pending CNAKS */
+ if (cnak_pending) {
+ /* CNAk processing when rxfifo empty only */
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ udc_process_cnak_queue(dev);
+ }
+ }
+
+finished:
+ return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ struct udc_ep *ep;
+ struct udc_request *req;
+ unsigned len;
+
+ ep = &dev->ep[UDC_EP0IN_IX];
+
+ /* clear irq */
+ writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+ /* DMA completion */
+ if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+ VDBG(dev, "isr: TDC clear \n");
+ ret_val = IRQ_HANDLED;
+
+ /* clear TDC bit */
+ writel(AMD_BIT(UDC_EPSTS_TDC),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+
+ /* status reg has IN bit set ? */
+ } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+ ret_val = IRQ_HANDLED;
+
+ if (ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ if (dev->stall_ep0in) {
+ DBG(dev, "stall ep0in\n");
+ /* halt ep0in */
+ tmp = readl(&ep->regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ } else {
+ if (!list_empty(&ep->queue)) {
+ /* next request */
+ req = list_entry(ep->queue.next,
+ struct udc_request, queue);
+
+ if (ep->dma) {
+ /* write desc pointer */
+ writel(req->td_phys, &ep->regs->desptr);
+ /* set HOST READY */
+ req->td_data->status =
+ AMD_ADDBITS(
+ req->td_data->status,
+ UDC_DMA_STP_STS_BS_HOST_READY,
+ UDC_DMA_STP_STS_BS);
+
+ /* set poll demand bit */
+ tmp =
+ readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+ tmp |= AMD_BIT(UDC_EPCTL_P);
+ writel(tmp,
+ &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+ /* all bytes will be transferred */
+ req->req.actual = req->req.length;
+
+ /* complete req */
+ complete_req(ep, req, 0);
+
+ } else {
+ /* write fifo */
+ udc_txfifo_write(ep, &req->req);
+
+ /* lengh bytes transfered */
+ len = req->req.length - req->req.actual;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+
+ req->req.actual += len;
+ if (req->req.actual == req->req.length
+ || (len != ep->ep.maxpacket)) {
+ /* complete req */
+ complete_req(ep, req, 0);
+ }
+ }
+
+ }
+ }
+ ep->halted = 0;
+ dev->stall_ep0in = 0;
+ if (!ep->dma) {
+ /* clear IN bit */
+ writel(AMD_BIT(UDC_EPSTS_IN),
+ &dev->ep[UDC_EP0IN_IX].regs->sts);
+ }
+ }
+
+ return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+ irqreturn_t ret_val = IRQ_NONE;
+ u32 tmp;
+ u32 cfg;
+ struct udc_ep *ep;
+ u16 i;
+ u8 udc_csr_epix;
+
+ /* SET_CONFIG irq ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+ ret_val = IRQ_HANDLED;
+
+ /* read config value */
+ tmp = readl(&dev->regs->sts);
+ cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+ DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+ dev->cur_config = cfg;
+ dev->set_cfg_not_acked = 1;
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup_data.request.wValue = dev->cur_config;
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep cfg */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+ UDC_CSR_NE_CFG);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* SET_INTERFACE ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+ ret_val = IRQ_HANDLED;
+
+ dev->set_cfg_not_acked = 1;
+ /* read interface and alt setting values */
+ tmp = readl(&dev->regs->sts);
+ dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+ dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+ /* make usb request for gadget driver */
+ memset(&setup_data, 0 , sizeof(union udc_setup_data));
+ setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+ setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+ setup_data.request.wValue = dev->cur_alt;
+ setup_data.request.wIndex = dev->cur_intf;
+
+ DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+ dev->cur_alt, dev->cur_intf);
+
+ /* programm the NE registers */
+ for (i = 0; i < UDC_EP_NUM; i++) {
+ ep = &dev->ep[i];
+ if (ep->in) {
+
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num;
+
+
+ /* OUT ep */
+ } else {
+ /* ep ix in UDC CSR register space */
+ udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+ }
+
+ /* UDC CSR reg */
+ /* set ep values */
+ tmp = readl(&dev->csr->ne[udc_csr_epix]);
+ /* ep interface */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+ UDC_CSR_NE_INTF);
+ /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+ /* ep alt */
+ tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+ UDC_CSR_NE_ALT);
+ /* write reg */
+ writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+ /* clear stall bits */
+ ep->halted = 0;
+ tmp = readl(&ep->regs->ctl);
+ tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+ writel(tmp, &ep->regs->ctl);
+ }
+
+ /* call gadget zero with setup data received */
+ spin_unlock(&dev->lock);
+ tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+ spin_lock(&dev->lock);
+
+ } /* USB reset */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+ DBG(dev, "USB Reset interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* allow soft reset when suspend occurs */
+ soft_reset_occured = 0;
+
+ dev->waiting_zlp_ack_ep0in = 0;
+ dev->set_cfg_not_acked = 0;
+
+ /* mask not needed interrupts */
+ udc_mask_unused_interrupts(dev);
+
+ /* call gadget to resume and reset configs etc. */
+ spin_unlock(&dev->lock);
+ if (dev->sys_suspended && dev->driver->resume) {
+ dev->driver->resume(&dev->gadget);
+ dev->sys_suspended = 0;
+ }
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* soft reset when rxfifo not empty */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+ && !soft_reset_after_usbreset_occured) {
+ udc_soft_reset(dev);
+ soft_reset_after_usbreset_occured++;
+ }
+
+ /*
+ * DMA reset to kill potential old DMA hw hang,
+ * POLL bit is already reset by ep_init() through
+ * disconnect()
+ */
+ DBG(dev, "DMA machine reset\n");
+ tmp = readl(&dev->regs->cfg);
+ writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+ writel(tmp, &dev->regs->cfg);
+
+ /* put into initial config */
+ udc_basic_init(dev);
+
+ /* enable device setup interrupts */
+ udc_enable_dev_setup_interrupts(dev);
+
+ /* enable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+
+ } /* USB suspend */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+ DBG(dev, "USB Suspend interrupt\n");
+ ret_val = IRQ_HANDLED;
+ if (dev->driver->suspend) {
+ spin_unlock(&dev->lock);
+ dev->sys_suspended = 1;
+ dev->driver->suspend(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ } /* new speed ? */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+ DBG(dev, "ENUM interrupt\n");
+ ret_val = IRQ_HANDLED;
+ soft_reset_after_usbreset_occured = 0;
+
+ /* disable ep0 to empty req queue */
+ empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+ /* link up all endpoints */
+ udc_setup_endpoints(dev);
+ if (dev->gadget.speed == USB_SPEED_HIGH) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "high");
+ } else if (dev->gadget.speed == USB_SPEED_FULL) {
+ dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+ "full");
+ }
+
+ /* init ep 0 */
+ activate_control_endpoints(dev);
+
+ /* enable ep0 interrupts */
+ udc_enable_ep0_interrupts(dev);
+ }
+ /* session valid change interrupt */
+ if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+ DBG(dev, "USB SVC interrupt\n");
+ ret_val = IRQ_HANDLED;
+
+ /* check that session is not valid to detect disconnect */
+ tmp = readl(&dev->regs->sts);
+ if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+ /* disable suspend interrupt */
+ tmp = readl(&dev->regs->irqmsk);
+ tmp |= AMD_BIT(UDC_DEVINT_US);
+ writel(tmp, &dev->regs->irqmsk);
+ DBG(dev, "USB Disconnect (session valid low)\n");
+ /* cleanup on disconnect */
+ usb_disconnect(udc);
+ }
+
+ }
+
+ return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+ struct udc *dev = pdev;
+ u32 reg;
+ u16 i;
+ u32 ep_irq;
+ irqreturn_t ret_val = IRQ_NONE;
+
+ spin_lock(&dev->lock);
+
+ /* check for ep irq */
+ reg = readl(&dev->regs->ep_irqsts);
+ if (reg) {
+ if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+ ret_val |= udc_control_out_isr(dev);
+ if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+ ret_val |= udc_control_in_isr(dev);
+
+ /*
+ * data endpoint
+ * iterate ep's
+ */
+ for (i = 1; i < UDC_EP_NUM; i++) {
+ ep_irq = 1 << i;
+ if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+ continue;
+
+ /* clear irq status */
+ writel(ep_irq, &dev->regs->ep_irqsts);
+
+ /* irq for out ep ? */
+ if (i > UDC_EPIN_NUM)
+ ret_val |= udc_data_out_isr(dev, i);
+ else
+ ret_val |= udc_data_in_isr(dev, i);
+ }
+
+ }
+
+
+ /* check for dev irq */
+ reg = readl(&dev->regs->irqsts);
+ if (reg) {
+ /* clear irq */
+ writel(reg, &dev->regs->irqsts);
+ ret_val |= udc_dev_isr(dev, reg);
+ }
+
+
+ spin_unlock(&dev->lock);
+ return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+ struct amd5536udc *dev = dev_get_drvdata(pdev);
+ kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+ /* remove timer */
+ stop_timer++;
+ if (timer_pending(&udc_timer))
+ wait_for_completion(&on_exit);
+ if (udc_timer.data)
+ del_timer_sync(&udc_timer);
+ /* remove pollstall timer */
+ stop_pollstall_timer++;
+ if (timer_pending(&udc_pollstall_timer))
+ wait_for_completion(&on_pollstall_exit);
+ if (udc_pollstall_timer.data)
+ del_timer_sync(&udc_pollstall_timer);
+ udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+ struct udc *dev;
+
+ dev = pci_get_drvdata(pdev);
+
+ /* gadget driver must not be registered */
+ BUG_ON(dev->driver != NULL);
+
+ /* dma pool cleanup */
+ if (dev->data_requests)
+ pci_pool_destroy(dev->data_requests);
+
+ if (dev->stp_requests) {
+ /* cleanup DMA desc's for ep0in */
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td_stp,
+ dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ pci_pool_free(dev->stp_requests,
+ dev->ep[UDC_EP0OUT_IX].td,
+ dev->ep[UDC_EP0OUT_IX].td_phys);
+
+ pci_pool_destroy(dev->stp_requests);
+ }
+
+ /* reset controller */
+ writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+ if (dev->irq_registered)
+ free_irq(pdev->irq, dev);
+ if (dev->regs)
+ iounmap(dev->regs);
+ if (dev->mem_region)
+ release_mem_region(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (dev->active)
+ pci_disable_device(pdev);
+
+ device_unregister(&dev->gadget.dev);
+ pci_set_drvdata(pdev, NULL);
+
+ udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td_data;
+ int retval;
+
+ /* consistent DMA mode setting ? */
+ if (use_dma_ppb) {
+ use_dma_bufferfill_mode = 0;
+ } else {
+ use_dma_ppb_du = 0;
+ use_dma_bufferfill_mode = 1;
+ }
+
+ /* DMA setup */
+ dev->data_requests = dma_pool_create("data_requests", NULL,
+ sizeof(struct udc_data_dma), 0, 0);
+ if (!dev->data_requests) {
+ DBG(dev, "can't get request data pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+
+ /* EP0 in dma regs = dev control regs */
+ dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+ /* dma desc for setup data */
+ dev->stp_requests = dma_pool_create("setup requests", NULL,
+ sizeof(struct udc_stp_dma), 0, 0);
+ if (!dev->stp_requests) {
+ DBG(dev, "can't get stp request pool\n");
+ retval = -ENOMEM;
+ goto finished;
+ }
+ /* setup */
+ td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+ if (td_stp == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+ /* data: 0 packets !? */
+ td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+ &dev->ep[UDC_EP0OUT_IX].td_phys);
+ if (td_data == NULL) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ dev->ep[UDC_EP0OUT_IX].td = td_data;
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+ struct pci_dev *pdev,
+ const struct pci_device_id *id
+)
+{
+ struct udc *dev;
+ unsigned long resource;
+ unsigned long len;
+ int retval = 0;
+
+ /* one udc only */
+ if (udc) {
+ dev_dbg(&pdev->dev, "already probed\n");
+ return -EBUSY;
+ }
+
+ /* init */
+ dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+ if (!dev) {
+ retval = -ENOMEM;
+ goto finished;
+ }
+ memset(dev, 0, sizeof(struct udc));
+
+ /* pci setup */
+ if (pci_enable_device(pdev) < 0) {
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev->active = 1;
+
+ /* PCI resource allocation */
+ resource = pci_resource_start(pdev, 0);
+ len = pci_resource_len(pdev, 0);
+
+ if (!request_mem_region(resource, len, name)) {
+ dev_dbg(&pdev->dev, "pci device used already\n");
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->mem_region = 1;
+
+ dev->virt_addr = ioremap_nocache(resource, len);
+ if (dev->virt_addr == NULL) {
+ dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+ retval = -EFAULT;
+ goto finished;
+ }
+
+ if (!pdev->irq) {
+ dev_err(&dev->pdev->dev, "irq not set\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+
+ if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+ dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+ retval = -EBUSY;
+ goto finished;
+ }
+ dev->irq_registered = 1;
+
+ pci_set_drvdata(pdev, dev);
+
+ /* chip revision */
+ dev->chiprev = 0;
+
+ pci_set_master(pdev);
+ pci_set_mwi(pdev);
+
+ /* chip rev for Hs AMD5536 */
+ pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
+ /* init dma pools */
+ if (use_dma) {
+ retval = init_dma_pools(dev);
+ if (retval != 0)
+ goto finished;
+ }
+
+ dev->phys_addr = resource;
+ dev->irq = pdev->irq;
+ dev->pdev = pdev;
+ dev->gadget.dev.parent = &pdev->dev;
+ dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ /* general probing */
+ if (udc_probe(dev) == 0)
+ return 0;
+
+finished:
+ if (dev)
+ udc_pci_remove(pdev);
+ return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+ char tmp[128];
+ u32 reg;
+ int retval;
+
+ /* mark timer as not initialized */
+ udc_timer.data = 0;
+ udc_pollstall_timer.data = 0;
+
+ /* device struct setup */
+ spin_lock_init(&dev->lock);
+ dev->gadget.ops = &udc_ops;
+
+ strcpy(dev->gadget.dev.bus_id, "gadget");
+ dev->gadget.dev.release = gadget_release;
+ dev->gadget.name = name;
+ dev->gadget.name = name;
+ dev->gadget.is_dualspeed = 1;
+
+ /* udc csr registers base */
+ dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+ /* dev registers base */
+ dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+ /* ep registers base */
+ dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+ /* fifo's base */
+ dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+ dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+ /* init registers, interrupts, ... */
+ startup_registers(dev);
+
+ dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+ snprintf(tmp, sizeof tmp, "%d", dev->irq);
+ dev_info(&dev->pdev->dev,
+ "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+ tmp, dev->phys_addr, dev->chiprev,
+ (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+ strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+ if (dev->chiprev == UDC_HSA0_REV) {
+ dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+ retval = -ENODEV;
+ goto finished;
+ }
+ dev_info(&dev->pdev->dev,
+ "driver version: %s(for Geode5536 B1)\n", tmp);
+ udc = dev;
+
+ retval = device_register(&dev->gadget.dev);
+ if (retval)
+ goto finished;
+
+ /* timer init */
+ init_timer(&udc_timer);
+ udc_timer.function = udc_timer_function;
+ udc_timer.data = 1;
+ /* timer pollstall init */
+ init_timer(&udc_pollstall_timer);
+ udc_pollstall_timer.function = udc_pollstall_timer_function;
+ udc_pollstall_timer.data = 1;
+
+ /* set SD */
+ reg = readl(&dev->regs->ctl);
+ reg |= AMD_BIT(UDC_DEVCTL_SD);
+ writel(reg, &dev->regs->ctl);
+
+ /* print dev register info */
+ print_regs(dev);
+
+ return 0;
+
+finished:
+ return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+ unsigned long flags;
+ u32 tmp;
+
+ DBG(dev, "UDC initiates remote wakeup\n");
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ tmp = readl(&dev->regs->ctl);
+ tmp |= AMD_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+ tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+ writel(tmp, &dev->regs->ctl);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+ .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+ .class_mask = 0xffffffff,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+ .name = (char *) name,
+ .id_table = pci_id,
+ .probe = udc_pci_probe,
+ .remove = udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+ return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+ pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644
index 000000000000..4bbabbbfc93f
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS 1
+#define UDC_RDE_TIMER_DIV 10
+#define UDC_POLLSTALL_TIMER_USECONDS 500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0 0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16
+
+#define UDC_SETCONFIG_DWORD1 0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0 0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS 16
+
+#define UDC_SETINTF_DWORD1 0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS 0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0 0x0000ff21
+#define UDC_MSCRES_DWORD1 0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR 0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK 0x0000000f
+#define UDC_CSR_NE_NUM_OFS 0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK 0x00000010
+#define UDC_CSR_NE_DIR_OFS 4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK 0x00000060
+#define UDC_CSR_NE_TYPE_OFS 5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK 0x00000780
+#define UDC_CSR_NE_CFG_OFS 7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK 0x00007800
+#define UDC_CSR_NE_INTF_OFS 11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK 0x00078000
+#define UDC_CSR_NE_ALT_OFS 15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS 19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR 0x400
+
+#define UDC_DEVCFG_SOFTRESET 31
+#define UDC_DEVCFG_HNPSFEN 30
+#define UDC_DEVCFG_DMARST 29
+#define UDC_DEVCFG_SET_DESC 18
+#define UDC_DEVCFG_CSR_PRG 17
+#define UDC_DEVCFG_STATUS 7
+#define UDC_DEVCFG_DIR 6
+#define UDC_DEVCFG_PI 5
+#define UDC_DEVCFG_SS 4
+#define UDC_DEVCFG_SP 3
+#define UDC_DEVCFG_RWKP 2
+
+#define UDC_DEVCFG_SPD_MASK 0x3
+#define UDC_DEVCFG_SPD_OFS 0
+#define UDC_DEVCFG_SPD_HS 0x0
+#define UDC_DEVCFG_SPD_FS 0x1
+#define UDC_DEVCFG_SPD_LS 0x2
+/*#define UDC_DEVCFG_SPD_FS 0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR 0x404
+
+#define UDC_DEVCTL_THLEN_MASK 0xff000000
+#define UDC_DEVCTL_THLEN_OFS 24
+
+#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS 16
+
+#define UDC_DEVCTL_CSR_DONE 13
+#define UDC_DEVCTL_DEVNAK 12
+#define UDC_DEVCTL_SD 10
+#define UDC_DEVCTL_MODE 9
+#define UDC_DEVCTL_BREN 8
+#define UDC_DEVCTL_THE 7
+#define UDC_DEVCTL_BF 6
+#define UDC_DEVCTL_BE 5
+#define UDC_DEVCTL_DU 4
+#define UDC_DEVCTL_TDE 3
+#define UDC_DEVCTL_RDE 2
+#define UDC_DEVCTL_RES 0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR 0x408
+
+#define UDC_DEVSTS_TS_MASK 0xfffc0000
+#define UDC_DEVSTS_TS_OFS 18
+
+#define UDC_DEVSTS_SESSVLD 17
+#define UDC_DEVSTS_PHY_ERROR 16
+#define UDC_DEVSTS_RXFIFO_EMPTY 15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS 13
+#define UDC_DEVSTS_ENUM_SPEED_FULL 1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH 0
+
+#define UDC_DEVSTS_SUSP 12
+
+#define UDC_DEVSTS_ALT_MASK 0x00000f00
+#define UDC_DEVSTS_ALT_OFS 8
+
+#define UDC_DEVSTS_INTF_MASK 0x000000f0
+#define UDC_DEVSTS_INTF_OFS 4
+
+#define UDC_DEVSTS_CFG_MASK 0x0000000f
+#define UDC_DEVSTS_CFG_OFS 0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR 0x40c
+
+#define UDC_DEVINT_SVC 7
+#define UDC_DEVINT_ENUM 6
+#define UDC_DEVINT_SOF 5
+#define UDC_DEVINT_US 4
+#define UDC_DEVINT_UR 3
+#define UDC_DEVINT_ES 2
+#define UDC_DEVINT_SI 1
+#define UDC_DEVINT_SC 0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR 0x410
+
+#define UDC_DEVINT_MSK 0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR 0x414
+
+#define UDC_EPINT_OUT_MASK 0xffff0000
+#define UDC_EPINT_OUT_OFS 16
+#define UDC_EPINT_IN_MASK 0x0000ffff
+#define UDC_EPINT_IN_OFS 0
+
+#define UDC_EPINT_IN_EP0 0
+#define UDC_EPINT_IN_EP1 1
+#define UDC_EPINT_IN_EP2 2
+#define UDC_EPINT_IN_EP3 3
+#define UDC_EPINT_OUT_EP0 16
+#define UDC_EPINT_OUT_EP1 17
+#define UDC_EPINT_OUT_EP2 18
+#define UDC_EPINT_OUT_EP3 19
+
+#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR 0x418
+
+#define UDC_EPINT_OUT_MSK_MASK 0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS 16
+#define UDC_EPINT_IN_MSK_MASK 0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS 0
+
+#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE 0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR 0x0
+#define UDC_EPIN_REGS_ADDR 0x0
+#define UDC_EPOUT_REGS_ADDR 0x200
+
+#define UDC_EPCTL_ADDR 0x0
+
+#define UDC_EPCTL_RRDY 9
+#define UDC_EPCTL_CNAK 8
+#define UDC_EPCTL_SNAK 7
+#define UDC_EPCTL_NAK 6
+
+#define UDC_EPCTL_ET_MASK 0x00000030
+#define UDC_EPCTL_ET_OFS 4
+#define UDC_EPCTL_ET_CONTROL 0
+#define UDC_EPCTL_ET_ISO 1
+#define UDC_EPCTL_ET_BULK 2
+#define UDC_EPCTL_ET_INTERRUPT 3
+
+#define UDC_EPCTL_P 3
+#define UDC_EPCTL_SN 2
+#define UDC_EPCTL_F 1
+#define UDC_EPCTL_S 0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR 0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS 11
+
+#define UDC_EPSTS_TDC 10
+#define UDC_EPSTS_HE 9
+#define UDC_EPSTS_BNA 7
+#define UDC_EPSTS_IN 6
+
+#define UDC_EPSTS_OUT_MASK 0x00000030
+#define UDC_EPSTS_OUT_OFS 4
+#define UDC_EPSTS_OUT_DATA 1
+#define UDC_EPSTS_OUT_DATA_CLEAR 0x10
+#define UDC_EPSTS_OUT_SETUP 2
+#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20
+#define UDC_EPSTS_OUT_CLEAR 0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR 0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS 0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE 32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE 32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT 2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE 256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE 32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE 32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS 0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS 16
+#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS 0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE 64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE 64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE 64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS 16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS 16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS 20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS 24
+#define UDC_DMA_STP_STS_RX_MASK 0x30000000
+#define UDC_DMA_STP_STS_RX_OFS 28
+#define UDC_DMA_STP_STS_BS_MASK 0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS 30
+#define UDC_DMA_STP_STS_BS_HOST_READY 0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY 1
+#define UDC_DMA_STP_STS_BS_DMA_DONE 2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY 3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS 0
+#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS 0
+#define UDC_DMA_IN_STS_L 27
+#define UDC_DMA_IN_STS_TX_MASK 0x30000000
+#define UDC_DMA_IN_STS_TX_OFS 28
+#define UDC_DMA_IN_STS_BS_MASK 0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS 30
+#define UDC_DMA_IN_STS_BS_HOST_READY 0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY 1
+#define UDC_DMA_IN_STS_BS_DMA_DONE 2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY 3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS 0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0
+#define UDC_DMA_OUT_STS_L 27
+#define UDC_DMA_OUT_STS_RX_MASK 0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS 28
+#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS 30
+#define UDC_DMA_OUT_STS_BS_HOST_READY 0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE 2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET 1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET 65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE (~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR 0x10
+#define UDC_EP_DESPTR_ADDR 0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM 32
+#define UDC_EPIN_NUM 16
+#define UDC_EPIN_NUM_USED 5
+#define UDC_EPOUT_NUM 16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM 9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS 12
+
+#define UDC_EP0OUT_IX 16
+#define UDC_EP0IN_IX 0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR 0x800
+#define UDC_RXFIFO_SIZE 0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR 0xc00
+#define UDC_TXFIFO_SIZE 0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX 1
+#define UDC_EPIN_IX 2
+#define UDC_EPOUT_IX 18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES 4
+#define UDC_BITS_PER_BYTE_SHIFT 3
+#define UDC_BYTE_MASK 0xff
+#define UDC_BITS_PER_BYTE 8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+ /* sca - setup command address */
+ u32 sca;
+
+ /* ep ne's */
+ u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+ /* device configuration */
+ u32 cfg;
+
+ /* device control */
+ u32 ctl;
+
+ /* device status */
+ u32 sts;
+
+ /* device interrupt */
+ u32 irqsts;
+
+ /* device interrupt mask */
+ u32 irqmsk;
+
+ /* endpoint interrupt */
+ u32 ep_irqsts;
+
+ /* endpoint interrupt mask */
+ u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+ /* endpoint control */
+ u32 ctl;
+
+ /* endpoint status */
+ u32 sts;
+
+ /* endpoint buffer size in/ receive packet frame number out */
+ u32 bufin_framenum;
+
+ /* endpoint buffer size out/max packet size */
+ u32 bufout_maxpkt;
+
+ /* endpoint setup buffer pointer */
+ u32 subptr;
+
+ /* endpoint data descriptor pointer */
+ u32 desptr;
+
+ /* reserverd */
+ u32 reserved;
+
+ /* write/read confirmation */
+ u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* first setup word */
+ u32 data12;
+ /* second setup word */
+ u32 data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+ /* status quadlet */
+ u32 status;
+ /* reserved */
+ u32 _reserved;
+ /* buffer pointer */
+ u32 bufptr;
+ /* next descriptor pointer */
+ u32 next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+ /* embedded gadget ep */
+ struct usb_request req;
+
+ /* flags */
+ unsigned dma_going : 1,
+ dma_mapping : 1,
+ dma_done : 1;
+ /* phys. address */
+ dma_addr_t td_phys;
+ /* first dma desc. of chain */
+ struct udc_data_dma *td_data;
+ /* last dma desc. of chain */
+ struct udc_data_dma *td_data_last;
+ struct list_head queue;
+
+ /* chain length */
+ unsigned chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+ struct usb_ep ep;
+ struct udc_ep_regs __iomem *regs;
+ u32 __iomem *txfifo;
+ u32 __iomem *dma;
+ dma_addr_t td_phys;
+ dma_addr_t td_stp_dma;
+ struct udc_stp_dma *td_stp;
+ struct udc_data_dma *td;
+ /* temp request */
+ struct udc_request *req;
+ unsigned req_used;
+ unsigned req_completed;
+ /* dummy DMA desc for BNA dummy */
+ struct udc_request *bna_dummy_req;
+ unsigned bna_occurred;
+
+ /* NAK state */
+ unsigned naking;
+
+ struct udc *dev;
+
+ /* queue for requests */
+ struct list_head queue;
+ const struct usb_endpoint_descriptor *desc;
+ unsigned halted;
+ unsigned cancel_transfer;
+ unsigned num : 5,
+ fifo_depth : 14,
+ in : 1;
+};
+
+/* device struct */
+struct udc {
+ struct usb_gadget gadget;
+ spinlock_t lock; /* protects all state */
+ /* all endpoints */
+ struct udc_ep ep[UDC_EP_NUM];
+ struct usb_gadget_driver *driver;
+ /* operational flags */
+ unsigned active : 1,
+ stall_ep0in : 1,
+ waiting_zlp_ack_ep0in : 1,
+ set_cfg_not_acked : 1,
+ irq_registered : 1,
+ data_ep_enabled : 1,
+ data_ep_queued : 1,
+ mem_region : 1,
+ sys_suspended : 1,
+ connected;
+
+ u16 chiprev;
+
+ /* registers */
+ struct pci_dev *pdev;
+ struct udc_csrs __iomem *csr;
+ struct udc_regs __iomem *regs;
+ struct udc_ep_regs __iomem *ep_regs;
+ u32 __iomem *rxfifo;
+ u32 __iomem *txfifo;
+
+ /* DMA desc pools */
+ struct pci_pool *data_requests;
+ struct pci_pool *stp_requests;
+
+ /* device data */
+ unsigned long phys_addr;
+ void __iomem *virt_addr;
+ unsigned irq;
+
+ /* states */
+ u16 cur_config;
+ u16 cur_intf;
+ u16 cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+ u32 data[2];
+ struct usb_ctrlrequest request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK)))) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name) \
+ ((u32Val) \
+ | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \
+ & ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name) \
+ ((u32Val & ((u32) bitfield_stub_name##_MASK)) \
+ >> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...) dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(udc , args...) do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index ba163f35bf21..63d7d6568699 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -601,25 +601,6 @@ static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
-static void *at91_ep_alloc_buffer(
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t gfp_flags)
-{
- *dma = ~0;
- return kmalloc(bytes, gfp_flags);
-}
-
-static void at91_ep_free_buffer(
- struct usb_ep *ep,
- void *buf,
- dma_addr_t dma,
- unsigned bytes)
-{
- kfree(buf);
-}
-
static int at91_ep_queue(struct usb_ep *_ep,
struct usb_request *_req, gfp_t gfp_flags)
{
@@ -788,8 +769,6 @@ static const struct usb_ep_ops at91_ep_ops = {
.disable = at91_ep_disable,
.alloc_request = at91_ep_alloc_request,
.free_request = at91_ep_free_request,
- .alloc_buffer = at91_ep_alloc_buffer,
- .free_buffer = at91_ep_free_buffer,
.queue = at91_ep_queue,
.dequeue = at91_ep_dequeue,
.set_halt = at91_ep_set_halt,
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index fcb5526cb085..f2fbdc7fe376 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -497,38 +497,6 @@ dummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
kfree (req);
}
-static void *
-dummy_alloc_buffer (
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t mem_flags
-) {
- char *retval;
- struct dummy_ep *ep;
- struct dummy *dum;
-
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
-
- if (!dum->driver)
- return NULL;
- retval = kmalloc (bytes, mem_flags);
- *dma = (dma_addr_t) retval;
- return retval;
-}
-
-static void
-dummy_free_buffer (
- struct usb_ep *_ep,
- void *buf,
- dma_addr_t dma,
- unsigned bytes
-) {
- if (bytes)
- kfree (buf);
-}
-
static void
fifo_complete (struct usb_ep *ep, struct usb_request *req)
{
@@ -659,10 +627,6 @@ static const struct usb_ep_ops dummy_ep_ops = {
.alloc_request = dummy_alloc_request,
.free_request = dummy_free_request,
- .alloc_buffer = dummy_alloc_buffer,
- .free_buffer = dummy_free_buffer,
- /* map, unmap, ... eventually hook the "generic" dma calls */
-
.queue = dummy_queue,
.dequeue = dummy_dequeue,
@@ -1784,8 +1748,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
spin_lock_irq (&dum->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- dev_warn (&hcd->self.root_hub->dev, "HC isn't running!\n");
- rc = -ENODEV;
+ rc = -ESHUTDOWN;
} else {
dum->rh_state = DUMMY_RH_RUNNING;
set_link_state (dum);
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 325bf7cfb83f..a3376739a81b 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -277,7 +277,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
#define DEV_CONFIG_CDC
#endif
@@ -292,7 +292,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
-#ifdef CONFIG_USB_GADGET_SH
+#ifdef CONFIG_USB_GADGET_SUPERH
#define DEV_CONFIG_SUBSET
#endif
@@ -301,6 +301,14 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
+#ifdef CONFIG_USB_GADGET_M66592
+#define DEV_CONFIG_CDC
+#endif
+
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define DEV_CONFIG_CDC
+#endif
+
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 4639b629e60c..be7a1bd2823b 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -3434,6 +3434,9 @@ static int fsg_main_thread(void *fsg_)
allow_signal(SIGKILL);
allow_signal(SIGUSR1);
+ /* Allow the thread to be frozen */
+ set_freezable();
+
/* Arrange for userspace references to be interpreted as kernel
* pointers. That way we can pass a kernel pointer to a routine
* that expects a __user pointer and it will work okay. */
@@ -3733,19 +3736,12 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
}
/* Free the data buffers */
- for (i = 0; i < NUM_BUFFERS; ++i) {
- struct fsg_buffhd *bh = &fsg->buffhds[i];
-
- if (bh->buf)
- usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma,
- mod_data.buflen);
- }
+ for (i = 0; i < NUM_BUFFERS; ++i)
+ kfree(fsg->buffhds[i].buf);
/* Free the request and buffer for endpoint 0 */
if (req) {
- if (req->buf)
- usb_ep_free_buffer(fsg->ep0, req->buf,
- req->dma, EP0_BUFSIZE);
+ kfree(req->buf);
usb_ep_free_request(fsg->ep0, req);
}
@@ -3963,8 +3959,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
#endif
if (gadget->is_otg) {
- otg_desc.bmAttributes |= USB_OTG_HNP,
- config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ otg_desc.bmAttributes |= USB_OTG_HNP;
}
rc = -ENOMEM;
@@ -3973,8 +3968,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
if (!req)
goto out;
- req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,
- &req->dma, GFP_KERNEL);
+ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
if (!req->buf)
goto out;
req->complete = ep0_complete;
@@ -3986,8 +3980,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Allocate for the bulk-in endpoint. We assume that
* the buffer will also work with the bulk-out (and
* interrupt-in) endpoint. */
- bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen,
- &bh->dma, GFP_KERNEL);
+ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
if (!bh->buf)
goto out;
bh->next = bh + 1;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 3ca2b3159f00..10b2b33b8698 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -228,7 +228,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
/* Config PHY interface */
portctrl = fsl_readl(&dr_regs->portsc1);
- portctrl &= ~(PORTSCX_PHY_TYPE_SEL & PORTSCX_PORT_WIDTH);
+ portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
portctrl |= PORTSCX_PTS_ULPI;
@@ -601,39 +601,6 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
-/*------------------------------------------------------------------
- * Allocate an I/O buffer
-*---------------------------------------------------------------------*/
-static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags)
-{
- struct fsl_ep *ep;
-
- if (!_ep)
- return NULL;
-
- ep = container_of(_ep, struct fsl_ep, ep);
-
- return dma_alloc_coherent(ep->udc->gadget.dev.parent,
- bytes, dma, gfp_flags);
-}
-
-/*------------------------------------------------------------------
- * frees an i/o buffer
-*---------------------------------------------------------------------*/
-static void fsl_free_buffer(struct usb_ep *_ep, void *buf,
- dma_addr_t dma, unsigned bytes)
-{
- struct fsl_ep *ep;
-
- if (!_ep)
- return;
-
- ep = container_of(_ep, struct fsl_ep, ep);
-
- dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
-}
-
/*-------------------------------------------------------------------------*/
static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
{
@@ -1047,9 +1014,6 @@ static struct usb_ep_ops fsl_ep_ops = {
.alloc_request = fsl_alloc_request,
.free_request = fsl_free_request,
- .alloc_buffer = fsl_alloc_buffer,
- .free_buffer = fsl_free_buffer,
-
.queue = fsl_ep_queue,
.dequeue = fsl_ep_dequeue,
@@ -2189,27 +2153,19 @@ static void fsl_udc_release(struct device *dev)
* init resource for globle controller
* Return the udc handle on success or NULL on failure
------------------------------------------------------------------*/
-static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
+static int __init struct_udc_setup(struct fsl_udc *udc,
+ struct platform_device *pdev)
{
- struct fsl_udc *udc;
struct fsl_usb2_platform_data *pdata;
size_t size;
- udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
- if (udc == NULL) {
- ERR("malloc udc failed\n");
- return NULL;
- }
-
pdata = pdev->dev.platform_data;
udc->phy_mode = pdata->phy_mode;
- /* max_ep_nr is bidirectional ep number, max_ep doubles the number */
- udc->max_ep = pdata->max_ep_nr * 2;
udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
if (!udc->eps) {
ERR("malloc fsl_ep failed\n");
- goto cleanup;
+ return -1;
}
/* initialized QHs, take care of alignment */
@@ -2225,7 +2181,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
if (!udc->ep_qh) {
ERR("malloc QHs for udc failed\n");
kfree(udc->eps);
- goto cleanup;
+ return -1;
}
udc->ep_qh_size = size;
@@ -2244,11 +2200,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
udc->remote_wakeup = 0; /* default to 0 on reset */
spin_lock_init(&udc->lock);
- return udc;
-
-cleanup:
- kfree(udc);
- return NULL;
+ return 0;
}
/*----------------------------------------------------------------
@@ -2287,35 +2239,37 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
}
/* Driver probe function
- * all intialize operations implemented here except enabling usb_intr reg
+ * all intialization operations implemented here except enabling usb_intr reg
+ * board setup should have been done in the platform code
*/
static int __init fsl_udc_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = -ENODEV;
unsigned int i;
+ u32 dccparams;
if (strcmp(pdev->name, driver_name)) {
VDBG("Wrong device\n");
return -ENODEV;
}
- /* board setup should have been done in the platform code */
-
- /* Initialize the udc structure including QH member and other member */
- udc_controller = struct_udc_setup(pdev);
- if (!udc_controller) {
- VDBG("udc_controller is NULL \n");
+ udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
+ if (udc_controller == NULL) {
+ ERR("malloc udc failed\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
+ if (!res) {
+ kfree(udc_controller);
return -ENXIO;
+ }
if (!request_mem_region(res->start, res->end - res->start + 1,
driver_name)) {
ERR("request mem region for %s failed \n", pdev->name);
+ kfree(udc_controller);
return -EBUSY;
}
@@ -2328,13 +2282,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
usb_sys_regs = (struct usb_sys_interface *)
((u32)dr_regs + USB_DR_SYS_OFFSET);
+ /* Read Device Controller Capability Parameters register */
+ dccparams = fsl_readl(&dr_regs->dccparams);
+ if (!(dccparams & DCCPARAMS_DC)) {
+ ERR("This SOC doesn't support device role\n");
+ ret = -ENODEV;
+ goto err2;
+ }
+ /* Get max device endpoints */
+ /* DEN is bidirectional ep number, max_ep doubles the number */
+ udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
+
udc_controller->irq = platform_get_irq(pdev, 0);
if (!udc_controller->irq) {
ret = -ENODEV;
goto err2;
}
- ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ,
+ ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
driver_name, udc_controller);
if (ret != 0) {
ERR("cannot request irq %d err %d \n",
@@ -2342,6 +2307,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
goto err2;
}
+ /* Initialize the udc structure including QH member and other member */
+ if (struct_udc_setup(udc_controller, pdev)) {
+ ERR("Can't initialize udc data structure\n");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
/* initialize usb hw reg except for regs for EP,
* leave usbintr reg untouched */
dr_controller_setup(udc_controller);
@@ -2403,6 +2375,7 @@ err2:
iounmap(dr_regs);
err1:
release_mem_region(res->start, res->end - res->start + 1);
+ kfree(udc_controller);
return ret;
}
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index c6291e046507..832ab82b4882 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -101,6 +101,10 @@ struct usb_sys_interface {
#define WAIT_FOR_OUT_STATUS 3
#define DATA_STATE_RECV 4
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_DC 0x00000080
+#define DCCPARAMS_DEN_MASK 0x0000001f
+
/* Frame Index Register Bit Masks */
#define USB_FRINDEX_MASKS 0x3fff
/* USB CMD Register Bit Masks */
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index d041b919e7b8..f7f159c1002b 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -8,6 +8,8 @@
* (And avoiding all runtime comparisons in typical one-choice configs!)
*
* NOTE: some of these controller drivers may not be available yet.
+ * Some are available on 2.4 kernels; several are available, but not
+ * yet pushed in the 2.6 mainline tree.
*/
#ifdef CONFIG_USB_GADGET_NET2280
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
@@ -15,6 +17,12 @@
#define gadget_is_net2280(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name)
+#else
+#define gadget_is_amd5536udc(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_DUMMY_HCD
#define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name)
#else
@@ -33,12 +41,14 @@
#define gadget_is_goku(g) 0
#endif
+/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_SUPERH
#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
#else
#define gadget_is_sh(g) 0
#endif
+/* not yet stable on 2.6 (would help "original Zaurus") */
#ifdef CONFIG_USB_GADGET_SA1100
#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
#else
@@ -51,6 +61,7 @@
#define gadget_is_lh7a40x(g) 0
#endif
+/* handhelds.org tree (?) */
#ifdef CONFIG_USB_GADGET_MQ11XX
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
#else
@@ -63,22 +74,24 @@
#define gadget_is_omap(g) 0
#endif
+/* not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_N9604
#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
#else
#define gadget_is_n9604(g) 0
#endif
+/* various unstable versions available */
#ifdef CONFIG_USB_GADGET_PXA27X
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
#else
#define gadget_is_pxa27x(g) 0
#endif
-#ifdef CONFIG_USB_GADGET_HUSB2DEV
-#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name)
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name)
#else
-#define gadget_is_husb2dev(g) 0
+#define gadget_is_atmel_usba(g) 0
#endif
#ifdef CONFIG_USB_GADGET_S3C2410
@@ -93,6 +106,7 @@
#define gadget_is_at91(g) 0
#endif
+/* status unclear */
#ifdef CONFIG_USB_GADGET_IMX
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
#else
@@ -106,6 +120,7 @@
#endif
/* Mentor high speed function controller */
+/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MUSBHSFC
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
#else
@@ -119,12 +134,20 @@
#define gadget_is_musbhdrc(g) 0
#endif
+/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MPC8272
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
#else
#define gadget_is_mpc8272(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_M66592
+#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
+#else
+#define gadget_is_m66592(g) 0
+#endif
+
+
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
// ...
@@ -181,9 +204,13 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
- else if (gadget_is_husb2dev(gadget))
+ else if (gadget_is_atmel_usba(gadget))
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
return 0x19;
+ else if (gadget_is_amd5536udc(gadget))
+ return 0x20;
+ else if (gadget_is_m66592(gadget))
+ return 0x21;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index d08a8d0e6427..1c5aa49d7432 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -1248,17 +1248,11 @@ autoconf_fail:
tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
/* preallocate control response and buffer */
- dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+ dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ);
if (!dev->req) {
err = -ENOMEM;
goto fail;
}
- dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ,
- &dev->req->dma, GFP_KERNEL);
- if (!dev->req->buf) {
- err = -ENOMEM;
- goto fail;
- }
dev->req->complete = gmidi_setup_complete;
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index ae931af05cef..349b8166f34a 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -20,7 +20,6 @@
* - DMA works with ep1 (OUT transfers) and ep2 (IN transfers).
*/
-#undef DEBUG
// #define VERBOSE /* extra debug messages (success too) */
// #define USB_TRACE /* packet-level success messages */
@@ -296,51 +295,6 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-/* allocating buffers this way eliminates dma mapping overhead, which
- * on some platforms will mean eliminating a per-io buffer copy. with
- * some kinds of system caches, further tweaks may still be needed.
- */
-static void *
-goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags)
-{
- void *retval;
- struct goku_ep *ep;
-
- ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep)
- return NULL;
- *dma = DMA_ADDR_INVALID;
-
- if (ep->dma) {
- /* the main problem with this call is that it wastes memory
- * on typical 1/N page allocations: it allocates 1-N pages.
- */
-#warning Using dma_alloc_coherent even with buffers smaller than a page.
- retval = dma_alloc_coherent(&ep->dev->pdev->dev,
- bytes, dma, gfp_flags);
- } else
- retval = kmalloc(bytes, gfp_flags);
- return retval;
-}
-
-static void
-goku_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes)
-{
- /* free memory into the right allocator */
- if (dma != DMA_ADDR_INVALID) {
- struct goku_ep *ep;
-
- ep = container_of(_ep, struct goku_ep, ep);
- if (!_ep)
- return;
- dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
- } else
- kfree (buf);
-}
-
-/*-------------------------------------------------------------------------*/
-
static void
done(struct goku_ep *ep, struct goku_request *req, int status)
{
@@ -485,7 +439,7 @@ top:
/* use ep1/ep2 double-buffering for OUT */
if (!(size & PACKET_ACTIVE))
size = readl(&regs->EPxSizeLB[ep->num]);
- if (!(size & PACKET_ACTIVE)) // "can't happen"
+ if (!(size & PACKET_ACTIVE)) /* "can't happen" */
break;
size &= DATASIZE; /* EPxSizeH == 0 */
@@ -1026,9 +980,6 @@ static struct usb_ep_ops goku_ep_ops = {
.alloc_request = goku_alloc_request,
.free_request = goku_free_request,
- .alloc_buffer = goku_alloc_buffer,
- .free_buffer = goku_free_buffer,
-
.queue = goku_queue,
.dequeue = goku_dequeue,
@@ -1140,17 +1091,17 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
is_usb_connected
? ((tmp & PW_PULLUP) ? "full speed" : "powered")
: "disconnected",
- ({char *tmp;
+ ({char *state;
switch(dev->ep0state){
- case EP0_DISCONNECT: tmp = "ep0_disconnect"; break;
- case EP0_IDLE: tmp = "ep0_idle"; break;
- case EP0_IN: tmp = "ep0_in"; break;
- case EP0_OUT: tmp = "ep0_out"; break;
- case EP0_STATUS: tmp = "ep0_status"; break;
- case EP0_STALL: tmp = "ep0_stall"; break;
- case EP0_SUSPEND: tmp = "ep0_suspend"; break;
- default: tmp = "ep0_?"; break;
- } tmp; })
+ case EP0_DISCONNECT: state = "ep0_disconnect"; break;
+ case EP0_IDLE: state = "ep0_idle"; break;
+ case EP0_IN: state = "ep0_in"; break;
+ case EP0_OUT: state = "ep0_out"; break;
+ case EP0_STATUS: state = "ep0_status"; break;
+ case EP0_STALL: state = "ep0_stall"; break;
+ case EP0_SUSPEND: state = "ep0_suspend"; break;
+ default: state = "ep0_?"; break;
+ } state; })
);
size -= t;
next += t;
@@ -1195,7 +1146,6 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
for (i = 0; i < 4; i++) {
struct goku_ep *ep = &dev->ep [i];
struct goku_request *req;
- int t;
if (i && !ep->desc)
continue;
@@ -1283,7 +1233,7 @@ done:
static void udc_reinit (struct goku_udc *dev)
{
static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" };
-
+
unsigned i;
INIT_LIST_HEAD (&dev->gadget.ep_list);
@@ -1827,14 +1777,13 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
/* alloc, and start init */
- dev = kmalloc (sizeof *dev, GFP_KERNEL);
+ dev = kzalloc (sizeof *dev, GFP_KERNEL);
if (dev == NULL){
pr_debug("enomem %s\n", pci_name(pdev));
retval = -ENOMEM;
goto done;
}
- memset(dev, 0, sizeof *dev);
spin_lock_init(&dev->lock);
dev->pdev = pdev;
dev->gadget.ops = &goku_ops;
@@ -1896,9 +1845,9 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* done */
the_controller = dev;
- device_register(&dev->gadget.dev);
-
- return 0;
+ retval = device_register(&dev->gadget.dev);
+ if (retval == 0)
+ return 0;
done:
if (dev)
@@ -1910,8 +1859,8 @@ done:
/*-------------------------------------------------------------------------*/
static struct pci_device_id pci_ids [] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class_mask = ~0,
.vendor = 0x102f, /* Toshiba */
.device = 0x0107, /* this UDC */
.subvendor = PCI_ANY_ID,
diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h
index ea8c8e58cabf..bc4eb1e0b507 100644
--- a/drivers/usb/gadget/goku_udc.h
+++ b/drivers/usb/gadget/goku_udc.h
@@ -41,8 +41,10 @@ struct goku_udc_regs {
#define INT_SYSERROR 0x40000
#define INT_PWRDETECT 0x80000
-#define INT_DEVWIDE (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
-#define INT_EP0 (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
+#define INT_DEVWIDE \
+ (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
+#define INT_EP0 \
+ (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
u32 dma_master;
#define MST_EOPB_DIS 0x0800
@@ -231,7 +233,7 @@ struct goku_request {
enum ep0state {
EP0_DISCONNECT, /* no host */
EP0_IDLE, /* between STATUS ack and SETUP report */
- EP0_IN, EP0_OUT, /* data stage */
+ EP0_IN, EP0_OUT, /* data stage */
EP0_STATUS, /* status stage */
EP0_STALL, /* data or status stages */
EP0_SUSPEND, /* usb suspend */
@@ -242,7 +244,7 @@ struct goku_udc {
struct usb_gadget gadget;
spinlock_t lock;
struct goku_ep ep[4];
- struct usb_gadget_driver *driver;
+ struct usb_gadget_driver *driver;
enum ep0state ep0state;
unsigned got_irq:1,
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 46d0e5252744..e60745ffaf8e 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -37,7 +37,7 @@
#include <linux/device.h>
#include <linux/moduleparam.h>
-#include <linux/usb_gadgetfs.h>
+#include <linux/usb/gadgetfs.h>
#include <linux/usb_gadget.h>
@@ -923,7 +923,7 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
struct dev_data *dev = ep->driver_data;
if (req->buf != dev->rbuf) {
- usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+ kfree(req->buf);
req->buf = dev->rbuf;
req->dma = DMA_ADDR_INVALID;
}
@@ -963,7 +963,7 @@ static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
return -EBUSY;
}
if (len > sizeof (dev->rbuf))
- req->buf = usb_ep_alloc_buffer (ep, len, &req->dma, GFP_ATOMIC);
+ req->buf = kmalloc(len, GFP_ATOMIC);
if (req->buf == 0) {
req->buf = dev->rbuf;
return -ENOMEM;
@@ -1505,7 +1505,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
break;
-#ifndef CONFIG_USB_GADGETFS_PXA2XX
+#ifndef CONFIG_USB_GADGET_PXA2XX
/* PXA automagically handles this request too */
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != 0x80)
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index a0a73c08a344..e78c2ddc1f88 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -75,10 +75,6 @@ static int lh7a40x_ep_enable(struct usb_ep *ep,
static int lh7a40x_ep_disable(struct usb_ep *ep);
static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t);
static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *);
-static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *,
- gfp_t);
-static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t,
- unsigned);
static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t);
static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *);
static int lh7a40x_set_halt(struct usb_ep *ep, int);
@@ -104,9 +100,6 @@ static struct usb_ep_ops lh7a40x_ep_ops = {
.alloc_request = lh7a40x_alloc_request,
.free_request = lh7a40x_free_request,
- .alloc_buffer = lh7a40x_alloc_buffer,
- .free_buffer = lh7a40x_free_buffer,
-
.queue = lh7a40x_queue,
.dequeue = lh7a40x_dequeue,
@@ -1134,26 +1127,6 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req)
kfree(req);
}
-static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes,
- dma_addr_t * dma, gfp_t gfp_flags)
-{
- char *retval;
-
- DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags);
-
- retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM));
- if (retval)
- *dma = virt_to_bus(retval);
- return retval;
-}
-
-static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma,
- unsigned bytes)
-{
- DEBUG("%s, %p\n", __FUNCTION__, ep);
- kfree(buf);
-}
-
/** Queue one request
* Kickstart transfer if needed
* NOTE: Sets INDEX register
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
new file mode 100644
index 000000000000..700dda8a9157
--- /dev/null
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -0,0 +1,1633 @@
+/*
+ * M66592 UDC (USB gadget)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+#include "m66592-udc.h"
+
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+
+#define DRIVER_VERSION "29 May 2007"
+
+/* module parameters */
+static unsigned short clock = M66592_XTAL24;
+module_param(clock, ushort, 0644);
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+ "(default=16384)");
+
+static unsigned short vif = M66592_LDRV;
+module_param(vif, ushort, 0644);
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
+
+static unsigned short endian;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
+static unsigned short irq_sense = M66592_INTL;
+module_param(irq_sense, ushort, 0644);
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+ "(default=2)");
+
+static const char udc_name[] = "m66592_udc";
+static const char *m66592_ep_name[] = {
+ "ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7"
+};
+
+static void disable_controller(struct m66592 *m66592);
+static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req);
+static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req);
+static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags);
+
+static void transfer_complete(struct m66592_ep *ep,
+ struct m66592_request *req, int status);
+
+/*-------------------------------------------------------------------------*/
+static inline u16 get_usb_speed(struct m66592 *m66592)
+{
+ return (m66592_read(m66592, M66592_DVSTCTR) & M66592_RHST);
+}
+
+static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = m66592_read(m66592, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
+ M66592_INTENB0);
+ m66592_bset(m66592, (1 << pipenum), reg);
+ m66592_write(m66592, tmp, M66592_INTENB0);
+}
+
+static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = m66592_read(m66592, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
+ M66592_INTENB0);
+ m66592_bclr(m66592, (1 << pipenum), reg);
+ m66592_write(m66592, tmp, M66592_INTENB0);
+}
+
+static void m66592_usb_connect(struct m66592 *m66592)
+{
+ m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
+ m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
+ M66592_INTENB0);
+ m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
+
+ m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
+}
+
+static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
+ M66592_INTENB0);
+ m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+
+ m66592->gadget.speed = USB_SPEED_UNKNOWN;
+ spin_unlock(&m66592->lock);
+ m66592->driver->disconnect(&m66592->gadget);
+ spin_lock(&m66592->lock);
+
+ disable_controller(m66592);
+ INIT_LIST_HEAD(&m66592->ep[0].queue);
+}
+
+static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
+{
+ u16 pid = 0;
+ unsigned long offset;
+
+ if (pipenum == 0)
+ pid = m66592_read(m66592, M66592_DCPCTR) & M66592_PID;
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ pid = m66592_read(m66592, offset) & M66592_PID;
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+ return pid;
+}
+
+static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
+ u16 pid)
+{
+ unsigned long offset;
+
+ if (pipenum == 0)
+ m66592_mdfy(m66592, pid, M66592_PID, M66592_DCPCTR);
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ m66592_mdfy(m66592, pid, M66592_PID, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+}
+
+static inline void pipe_start(struct m66592 *m66592, u16 pipenum)
+{
+ control_reg_set_pid(m66592, pipenum, M66592_PID_BUF);
+}
+
+static inline void pipe_stop(struct m66592 *m66592, u16 pipenum)
+{
+ control_reg_set_pid(m66592, pipenum, M66592_PID_NAK);
+}
+
+static inline void pipe_stall(struct m66592 *m66592, u16 pipenum)
+{
+ control_reg_set_pid(m66592, pipenum, M66592_PID_STALL);
+}
+
+static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum)
+{
+ u16 ret = 0;
+ unsigned long offset;
+
+ if (pipenum == 0)
+ ret = m66592_read(m66592, M66592_DCPCTR);
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ ret = m66592_read(m66592, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+ return ret;
+}
+
+static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum)
+{
+ unsigned long offset;
+
+ pipe_stop(m66592, pipenum);
+
+ if (pipenum == 0)
+ m66592_bset(m66592, M66592_SQCLR, M66592_DCPCTR);
+ else if (pipenum < M66592_MAX_NUM_PIPE) {
+ offset = get_pipectr_addr(pipenum);
+ m66592_bset(m66592, M66592_SQCLR, offset);
+ } else
+ printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
+}
+
+static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
+{
+ u16 tmp;
+ int size;
+
+ if (pipenum == 0) {
+ tmp = m66592_read(m66592, M66592_DCPCFG);
+ if ((tmp & M66592_CNTMD) != 0)
+ size = 256;
+ else {
+ tmp = m66592_read(m66592, M66592_DCPMAXP);
+ size = tmp & M66592_MAXP;
+ }
+ } else {
+ m66592_write(m66592, pipenum, M66592_PIPESEL);
+ tmp = m66592_read(m66592, M66592_PIPECFG);
+ if ((tmp & M66592_CNTMD) != 0) {
+ tmp = m66592_read(m66592, M66592_PIPEBUF);
+ size = ((tmp >> 10) + 1) * 64;
+ } else {
+ tmp = m66592_read(m66592, M66592_PIPEMAXP);
+ size = tmp & M66592_MXPS;
+ }
+ }
+
+ return size;
+}
+
+static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
+{
+ struct m66592_ep *ep = m66592->pipenum2ep[pipenum];
+
+ if (ep->use_dma)
+ return;
+
+ m66592_mdfy(m66592, pipenum, M66592_CURPIPE, ep->fifosel);
+
+ ndelay(450);
+
+ m66592_bset(m66592, M66592_MBW, ep->fifosel);
+}
+
+static int pipe_buffer_setting(struct m66592 *m66592,
+ struct m66592_pipe_info *info)
+{
+ u16 bufnum = 0, buf_bsize = 0;
+ u16 pipecfg = 0;
+
+ if (info->pipe == 0)
+ return -EINVAL;
+
+ m66592_write(m66592, info->pipe, M66592_PIPESEL);
+
+ if (info->dir_in)
+ pipecfg |= M66592_DIR;
+ pipecfg |= info->type;
+ pipecfg |= info->epnum;
+ switch (info->type) {
+ case M66592_INT:
+ bufnum = 4 + (info->pipe - M66592_BASE_PIPENUM_INT);
+ buf_bsize = 0;
+ break;
+ case M66592_BULK:
+ bufnum = m66592->bi_bufnum +
+ (info->pipe - M66592_BASE_PIPENUM_BULK) * 16;
+ m66592->bi_bufnum += 16;
+ buf_bsize = 7;
+ pipecfg |= M66592_DBLB;
+ if (!info->dir_in)
+ pipecfg |= M66592_SHTNAK;
+ break;
+ case M66592_ISO:
+ bufnum = m66592->bi_bufnum +
+ (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16;
+ m66592->bi_bufnum += 16;
+ buf_bsize = 7;
+ break;
+ }
+ if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
+ printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
+ m66592->bi_bufnum);
+ return -ENOMEM;
+ }
+
+ m66592_write(m66592, pipecfg, M66592_PIPECFG);
+ m66592_write(m66592, (buf_bsize << 10) | (bufnum), M66592_PIPEBUF);
+ m66592_write(m66592, info->maxpacket, M66592_PIPEMAXP);
+ if (info->interval)
+ info->interval--;
+ m66592_write(m66592, info->interval, M66592_PIPEPERI);
+
+ return 0;
+}
+
+static void pipe_buffer_release(struct m66592 *m66592,
+ struct m66592_pipe_info *info)
+{
+ if (info->pipe == 0)
+ return;
+
+ switch (info->type) {
+ case M66592_BULK:
+ if (is_bulk_pipe(info->pipe))
+ m66592->bi_bufnum -= 16;
+ break;
+ case M66592_ISO:
+ if (is_isoc_pipe(info->pipe))
+ m66592->bi_bufnum -= 16;
+ break;
+ }
+
+ if (is_bulk_pipe(info->pipe)) {
+ m66592->bulk--;
+ } else if (is_interrupt_pipe(info->pipe))
+ m66592->interrupt--;
+ else if (is_isoc_pipe(info->pipe)) {
+ m66592->isochronous--;
+ if (info->type == M66592_BULK)
+ m66592->bulk--;
+ } else
+ printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
+ info->pipe);
+}
+
+static void pipe_initialize(struct m66592_ep *ep)
+{
+ struct m66592 *m66592 = ep->m66592;
+
+ m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel);
+
+ m66592_write(m66592, M66592_ACLRM, ep->pipectr);
+ m66592_write(m66592, 0, ep->pipectr);
+ m66592_write(m66592, M66592_SQCLR, ep->pipectr);
+ if (ep->use_dma) {
+ m66592_mdfy(m66592, ep->pipenum, M66592_CURPIPE, ep->fifosel);
+
+ ndelay(450);
+
+ m66592_bset(m66592, M66592_MBW, ep->fifosel);
+ }
+}
+
+static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
+ const struct usb_endpoint_descriptor *desc,
+ u16 pipenum, int dma)
+{
+ if ((pipenum != 0) && dma) {
+ if (m66592->num_dma == 0) {
+ m66592->num_dma++;
+ ep->use_dma = 1;
+ ep->fifoaddr = M66592_D0FIFO;
+ ep->fifosel = M66592_D0FIFOSEL;
+ ep->fifoctr = M66592_D0FIFOCTR;
+ ep->fifotrn = M66592_D0FIFOTRN;
+ } else if (m66592->num_dma == 1) {
+ m66592->num_dma++;
+ ep->use_dma = 1;
+ ep->fifoaddr = M66592_D1FIFO;
+ ep->fifosel = M66592_D1FIFOSEL;
+ ep->fifoctr = M66592_D1FIFOCTR;
+ ep->fifotrn = M66592_D1FIFOTRN;
+ } else {
+ ep->use_dma = 0;
+ ep->fifoaddr = M66592_CFIFO;
+ ep->fifosel = M66592_CFIFOSEL;
+ ep->fifoctr = M66592_CFIFOCTR;
+ ep->fifotrn = 0;
+ }
+ } else {
+ ep->use_dma = 0;
+ ep->fifoaddr = M66592_CFIFO;
+ ep->fifosel = M66592_CFIFOSEL;
+ ep->fifoctr = M66592_CFIFOCTR;
+ ep->fifotrn = 0;
+ }
+
+ ep->pipectr = get_pipectr_addr(pipenum);
+ ep->pipenum = pipenum;
+ ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ m66592->pipenum2ep[pipenum] = ep;
+ m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
+ INIT_LIST_HEAD(&ep->queue);
+}
+
+static void m66592_ep_release(struct m66592_ep *ep)
+{
+ struct m66592 *m66592 = ep->m66592;
+ u16 pipenum = ep->pipenum;
+
+ if (pipenum == 0)
+ return;
+
+ if (ep->use_dma)
+ m66592->num_dma--;
+ ep->pipenum = 0;
+ ep->busy = 0;
+ ep->use_dma = 0;
+}
+
+static int alloc_pipe_config(struct m66592_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct m66592 *m66592 = ep->m66592;
+ struct m66592_pipe_info info;
+ int dma = 0;
+ int *counter;
+ int ret;
+
+ ep->desc = desc;
+
+ BUG_ON(ep->pipenum);
+
+ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (m66592->bulk >= M66592_MAX_NUM_BULK) {
+ if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+ printk(KERN_ERR "bulk pipe is insufficient\n");
+ return -ENODEV;
+ } else {
+ info.pipe = M66592_BASE_PIPENUM_ISOC
+ + m66592->isochronous;
+ counter = &m66592->isochronous;
+ }
+ } else {
+ info.pipe = M66592_BASE_PIPENUM_BULK + m66592->bulk;
+ counter = &m66592->bulk;
+ }
+ info.type = M66592_BULK;
+ dma = 1;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (m66592->interrupt >= M66592_MAX_NUM_INT) {
+ printk(KERN_ERR "interrupt pipe is insufficient\n");
+ return -ENODEV;
+ }
+ info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt;
+ info.type = M66592_INT;
+ counter = &m66592->interrupt;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+ printk(KERN_ERR "isochronous pipe is insufficient\n");
+ return -ENODEV;
+ }
+ info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous;
+ info.type = M66592_ISO;
+ counter = &m66592->isochronous;
+ break;
+ default:
+ printk(KERN_ERR "unexpect xfer type\n");
+ return -EINVAL;
+ }
+ ep->type = info.type;
+
+ info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ info.interval = desc->bInterval;
+ if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ info.dir_in = 1;
+ else
+ info.dir_in = 0;
+
+ ret = pipe_buffer_setting(m66592, &info);
+ if (ret < 0) {
+ printk(KERN_ERR "pipe_buffer_setting fail\n");
+ return ret;
+ }
+
+ (*counter)++;
+ if ((counter == &m66592->isochronous) && info.type == M66592_BULK)
+ m66592->bulk++;
+
+ m66592_ep_setting(m66592, ep, desc, info.pipe, dma);
+ pipe_initialize(ep);
+
+ return 0;
+}
+
+static int free_pipe_config(struct m66592_ep *ep)
+{
+ struct m66592 *m66592 = ep->m66592;
+ struct m66592_pipe_info info;
+
+ info.pipe = ep->pipenum;
+ info.type = ep->type;
+ pipe_buffer_release(m66592, &info);
+ m66592_ep_release(ep);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static void pipe_irq_enable(struct m66592 *m66592, u16 pipenum)
+{
+ enable_irq_ready(m66592, pipenum);
+ enable_irq_nrdy(m66592, pipenum);
+}
+
+static void pipe_irq_disable(struct m66592 *m66592, u16 pipenum)
+{
+ disable_irq_ready(m66592, pipenum);
+ disable_irq_nrdy(m66592, pipenum);
+}
+
+/* if complete is true, gadget driver complete function is not call */
+static void control_end(struct m66592 *m66592, unsigned ccpl)
+{
+ m66592->ep[0].internal_ccpl = ccpl;
+ pipe_start(m66592, 0);
+ m66592_bset(m66592, M66592_CCPL, M66592_DCPCTR);
+}
+
+static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ struct m66592 *m66592 = ep->m66592;
+
+ pipe_change(m66592, ep->pipenum);
+ m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
+ m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+ if (req->req.length == 0) {
+ m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+ pipe_start(m66592, 0);
+ transfer_complete(ep, req, 0);
+ } else {
+ m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS);
+ irq_ep0_write(ep, req);
+ }
+}
+
+static void start_packet_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ struct m66592 *m66592 = ep->m66592;
+ u16 tmp;
+
+ pipe_change(m66592, ep->pipenum);
+ disable_irq_empty(m66592, ep->pipenum);
+ pipe_start(m66592, ep->pipenum);
+
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (unlikely((tmp & M66592_FRDY) == 0))
+ pipe_irq_enable(m66592, ep->pipenum);
+ else
+ irq_packet_write(ep, req);
+}
+
+static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
+{
+ struct m66592 *m66592 = ep->m66592;
+ u16 pipenum = ep->pipenum;
+
+ if (ep->pipenum == 0) {
+ m66592_mdfy(m66592, M66592_PIPE0,
+ (M66592_ISEL | M66592_CURPIPE),
+ M66592_CFIFOSEL);
+ m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+ pipe_start(m66592, pipenum);
+ pipe_irq_enable(m66592, pipenum);
+ } else {
+ if (ep->use_dma) {
+ m66592_bset(m66592, M66592_TRCLR, ep->fifosel);
+ pipe_change(m66592, pipenum);
+ m66592_bset(m66592, M66592_TRENB, ep->fifosel);
+ m66592_write(m66592,
+ (req->req.length + ep->ep.maxpacket - 1)
+ / ep->ep.maxpacket,
+ ep->fifotrn);
+ }
+ pipe_start(m66592, pipenum); /* trigger once */
+ pipe_irq_enable(m66592, pipenum);
+ }
+}
+
+static void start_packet(struct m66592_ep *ep, struct m66592_request *req)
+{
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ start_packet_write(ep, req);
+ else
+ start_packet_read(ep, req);
+}
+
+static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
+{
+ u16 ctsq;
+
+ ctsq = m66592_read(ep->m66592, M66592_INTSTS0) & M66592_CTSQ;
+
+ switch (ctsq) {
+ case M66592_CS_RDDS:
+ start_ep0_write(ep, req);
+ break;
+ case M66592_CS_WRDS:
+ start_packet_read(ep, req);
+ break;
+
+ case M66592_CS_WRND:
+ control_end(ep->m66592, 0);
+ break;
+ default:
+ printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
+ break;
+ }
+}
+
+static void init_controller(struct m66592 *m66592)
+{
+ m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
+ M66592_PINCFG);
+ m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */
+ m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
+
+ m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+ m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+ m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+
+ msleep(3);
+
+ m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+
+ msleep(1);
+
+ m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+
+ m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
+ m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
+ M66592_DMA0CFG);
+}
+
+static void disable_controller(struct m66592 *m66592)
+{
+ m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
+ udelay(1);
+ m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+}
+
+static void m66592_start_xclock(struct m66592 *m66592)
+{
+ u16 tmp;
+
+ tmp = m66592_read(m66592, M66592_SYSCFG);
+ if (!(tmp & M66592_XCKE))
+ m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+}
+
+/*-------------------------------------------------------------------------*/
+static void transfer_complete(struct m66592_ep *ep,
+ struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ int restart = 0;
+
+ if (unlikely(ep->pipenum == 0)) {
+ if (ep->internal_ccpl) {
+ ep->internal_ccpl = 0;
+ return;
+ }
+ }
+
+ list_del_init(&req->queue);
+ if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ req->req.status = -ESHUTDOWN;
+ else
+ req->req.status = status;
+
+ if (!list_empty(&ep->queue))
+ restart = 1;
+
+ spin_unlock(&ep->m66592->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&ep->m66592->lock);
+
+ if (restart) {
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ if (ep->desc)
+ start_packet(ep, req);
+ }
+}
+
+static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ int i;
+ u16 tmp;
+ unsigned bufsize;
+ size_t size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct m66592 *m66592 = ep->m66592;
+
+ pipe_change(m66592, pipenum);
+ m66592_bset(m66592, M66592_ISEL, ep->fifosel);
+
+ i = 0;
+ do {
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (i++ > 100000) {
+ printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
+ "conflict. please power off this controller.");
+ return;
+ }
+ ndelay(1);
+ } while ((tmp & M66592_FRDY) == 0);
+
+ /* prepare parameters */
+ bufsize = get_buffer_size(m66592, pipenum);
+ buf = req->req.buf + req->req.actual;
+ size = min(bufsize, req->req.length - req->req.actual);
+
+ /* write fifo */
+ if (req->req.buf) {
+ if (size > 0)
+ m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+ if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
+ m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+ }
+
+ /* update parameters */
+ req->req.actual += size;
+
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ disable_irq_ready(m66592, pipenum);
+ disable_irq_empty(m66592, pipenum);
+ } else {
+ disable_irq_ready(m66592, pipenum);
+ enable_irq_empty(m66592, pipenum);
+ }
+ pipe_start(m66592, pipenum);
+}
+
+static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+ u16 tmp;
+ unsigned bufsize;
+ size_t size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct m66592 *m66592 = ep->m66592;
+
+ pipe_change(m66592, pipenum);
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (unlikely((tmp & M66592_FRDY) == 0)) {
+ pipe_stop(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
+ return;
+ }
+
+ /* prepare parameters */
+ bufsize = get_buffer_size(m66592, pipenum);
+ buf = req->req.buf + req->req.actual;
+ size = min(bufsize, req->req.length - req->req.actual);
+
+ /* write fifo */
+ if (req->req.buf) {
+ m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+ if ((size == 0)
+ || ((size % ep->ep.maxpacket) != 0)
+ || ((bufsize != ep->ep.maxpacket)
+ && (bufsize > size)))
+ m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+ }
+
+ /* update parameters */
+ req->req.actual += size;
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ disable_irq_ready(m66592, pipenum);
+ enable_irq_empty(m66592, pipenum);
+ } else {
+ disable_irq_empty(m66592, pipenum);
+ pipe_irq_enable(m66592, pipenum);
+ }
+}
+
+static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
+{
+ u16 tmp;
+ int rcv_len, bufsize, req_len;
+ int size;
+ void *buf;
+ u16 pipenum = ep->pipenum;
+ struct m66592 *m66592 = ep->m66592;
+ int finish = 0;
+
+ pipe_change(m66592, pipenum);
+ tmp = m66592_read(m66592, ep->fifoctr);
+ if (unlikely((tmp & M66592_FRDY) == 0)) {
+ req->req.status = -EPIPE;
+ pipe_stop(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ printk(KERN_ERR "read fifo not ready");
+ return;
+ }
+
+ /* prepare parameters */
+ rcv_len = tmp & M66592_DTLN;
+ bufsize = get_buffer_size(m66592, pipenum);
+
+ buf = req->req.buf + req->req.actual;
+ req_len = req->req.length - req->req.actual;
+ if (rcv_len < bufsize)
+ size = min(rcv_len, req_len);
+ else
+ size = min(bufsize, req_len);
+
+ /* update parameters */
+ req->req.actual += size;
+
+ /* check transfer finish */
+ if ((!req->req.zero && (req->req.actual == req->req.length))
+ || (size % ep->ep.maxpacket)
+ || (size == 0)) {
+ pipe_stop(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ finish = 1;
+ }
+
+ /* read fifo */
+ if (req->req.buf) {
+ if (size == 0)
+ m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+ else
+ m66592_read_fifo(m66592, ep->fifoaddr, buf, size);
+ }
+
+ if ((ep->pipenum != 0) && finish)
+ transfer_complete(ep, req, 0);
+}
+
+static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
+{
+ u16 check;
+ u16 pipenum;
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+
+ if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
+ m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
+ m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
+ M66592_CFIFOSEL);
+
+ ep = &m66592->ep[0];
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ irq_packet_read(ep, req);
+ } else {
+ for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if ((status & check) && (enb & check)) {
+ m66592_write(m66592, ~check, M66592_BRDYSTS);
+ ep = m66592->pipenum2ep[pipenum];
+ req = list_entry(ep->queue.next,
+ struct m66592_request, queue);
+ if (ep->desc->bEndpointAddress & USB_DIR_IN)
+ irq_packet_write(ep, req);
+ else
+ irq_packet_read(ep, req);
+ }
+ }
+ }
+}
+
+static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb)
+{
+ u16 tmp;
+ u16 check;
+ u16 pipenum;
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+
+ if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) {
+ m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS);
+
+ ep = &m66592->ep[0];
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ irq_ep0_write(ep, req);
+ } else {
+ for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if ((status & check) && (enb & check)) {
+ m66592_write(m66592, ~check, M66592_BEMPSTS);
+ tmp = control_reg_get(m66592, pipenum);
+ if ((tmp & M66592_INBUFM) == 0) {
+ disable_irq_empty(m66592, pipenum);
+ pipe_irq_disable(m66592, pipenum);
+ pipe_stop(m66592, pipenum);
+ ep = m66592->pipenum2ep[pipenum];
+ req = list_entry(ep->queue.next,
+ struct m66592_request,
+ queue);
+ if (!list_empty(&ep->queue))
+ transfer_complete(ep, req, 0);
+ }
+ }
+ }
+ }
+}
+
+static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ struct m66592_ep *ep;
+ u16 pid;
+ u16 status = 0;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ status = 1 << USB_DEVICE_SELF_POWERED;
+ break;
+ case USB_RECIP_INTERFACE:
+ status = 0;
+ break;
+ case USB_RECIP_ENDPOINT:
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pid = control_reg_get_pid(m66592, ep->pipenum);
+ if (pid == M66592_PID_STALL)
+ status = 1 << USB_ENDPOINT_HALT;
+ else
+ status = 0;
+ break;
+ default:
+ pipe_stall(m66592, 0);
+ return; /* exit */
+ }
+
+ m66592->ep0_data = cpu_to_le16(status);
+ m66592->ep0_req->buf = &m66592->ep0_data;
+ m66592->ep0_req->length = 2;
+ /* AV: what happens if we get called again before that gets through? */
+ spin_unlock(&m66592->lock);
+ m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+ spin_lock(&m66592->lock);
+}
+
+static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_INTERFACE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_ENDPOINT: {
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pipe_stop(m66592, ep->pipenum);
+ control_reg_sqclr(m66592, ep->pipenum);
+
+ control_end(m66592, 1);
+
+ req = list_entry(ep->queue.next,
+ struct m66592_request, queue);
+ if (ep->busy) {
+ ep->busy = 0;
+ if (list_empty(&ep->queue))
+ break;
+ start_packet(ep, req);
+ } else if (!list_empty(&ep->queue))
+ pipe_start(m66592, ep->pipenum);
+ }
+ break;
+ default:
+ pipe_stall(m66592, 0);
+ break;
+ }
+}
+
+static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+
+ switch (ctrl->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_DEVICE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_INTERFACE:
+ control_end(m66592, 1);
+ break;
+ case USB_RECIP_ENDPOINT: {
+ struct m66592_ep *ep;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+
+ ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
+ pipe_stall(m66592, ep->pipenum);
+
+ control_end(m66592, 1);
+ }
+ break;
+ default:
+ pipe_stall(m66592, 0);
+ break;
+ }
+}
+
+/* if return value is true, call class driver's setup() */
+static int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+ u16 *p = (u16 *)ctrl;
+ unsigned long offset = M66592_USBREQ;
+ int i, ret = 0;
+
+ /* read fifo */
+ m66592_write(m66592, ~M66592_VALID, M66592_INTSTS0);
+
+ for (i = 0; i < 4; i++)
+ p[i] = m66592_read(m66592, offset + i*2);
+
+ /* check request */
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+ switch (ctrl->bRequest) {
+ case USB_REQ_GET_STATUS:
+ get_status(m66592, ctrl);
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ clear_feature(m66592, ctrl);
+ break;
+ case USB_REQ_SET_FEATURE:
+ set_feature(m66592, ctrl);
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+ } else
+ ret = 1;
+ return ret;
+}
+
+static void m66592_update_usb_speed(struct m66592 *m66592)
+{
+ u16 speed = get_usb_speed(m66592);
+
+ switch (speed) {
+ case M66592_HSMODE:
+ m66592->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case M66592_FSMODE:
+ m66592->gadget.speed = USB_SPEED_FULL;
+ break;
+ default:
+ m66592->gadget.speed = USB_SPEED_UNKNOWN;
+ printk(KERN_ERR "USB speed unknown\n");
+ }
+}
+
+static void irq_device_state(struct m66592 *m66592)
+{
+ u16 dvsq;
+
+ dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ;
+ m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0);
+
+ if (dvsq == M66592_DS_DFLT) { /* bus reset */
+ m66592->driver->disconnect(&m66592->gadget);
+ m66592_update_usb_speed(m66592);
+ }
+ if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
+ m66592_update_usb_speed(m66592);
+ if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+ && m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ m66592_update_usb_speed(m66592);
+
+ m66592->old_dvsq = dvsq;
+}
+
+static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
+{
+ struct usb_ctrlrequest ctrl;
+ u16 ctsq;
+
+ ctsq = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ;
+ m66592_write(m66592, ~M66592_CTRT, M66592_INTSTS0);
+
+ switch (ctsq) {
+ case M66592_CS_IDST: {
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ ep = &m66592->ep[0];
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ transfer_complete(ep, req, 0);
+ }
+ break;
+
+ case M66592_CS_RDDS:
+ case M66592_CS_WRDS:
+ case M66592_CS_WRND:
+ if (setup_packet(m66592, &ctrl)) {
+ spin_unlock(&m66592->lock);
+ if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
+ pipe_stall(m66592, 0);
+ spin_lock(&m66592->lock);
+ }
+ break;
+ case M66592_CS_RDSS:
+ case M66592_CS_WRSS:
+ control_end(m66592, 0);
+ break;
+ default:
+ printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+ break;
+ }
+}
+
+static irqreturn_t m66592_irq(int irq, void *_m66592)
+{
+ struct m66592 *m66592 = _m66592;
+ u16 intsts0;
+ u16 intenb0;
+ u16 brdysts, nrdysts, bempsts;
+ u16 brdyenb, nrdyenb, bempenb;
+ u16 savepipe;
+ u16 mask0;
+
+ spin_lock(&m66592->lock);
+
+ intsts0 = m66592_read(m66592, M66592_INTSTS0);
+ intenb0 = m66592_read(m66592, M66592_INTENB0);
+
+ savepipe = m66592_read(m66592, M66592_CFIFOSEL);
+
+ mask0 = intsts0 & intenb0;
+ if (mask0) {
+ brdysts = m66592_read(m66592, M66592_BRDYSTS);
+ nrdysts = m66592_read(m66592, M66592_NRDYSTS);
+ bempsts = m66592_read(m66592, M66592_BEMPSTS);
+ brdyenb = m66592_read(m66592, M66592_BRDYENB);
+ nrdyenb = m66592_read(m66592, M66592_NRDYENB);
+ bempenb = m66592_read(m66592, M66592_BEMPENB);
+
+ if (mask0 & M66592_VBINT) {
+ m66592_write(m66592, 0xffff & ~M66592_VBINT,
+ M66592_INTSTS0);
+ m66592_start_xclock(m66592);
+
+ /* start vbus sampling */
+ m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
+ & M66592_VBSTS;
+ m66592->scount = M66592_MAX_SAMPLING;
+
+ mod_timer(&m66592->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ if (intsts0 & M66592_DVSQ)
+ irq_device_state(m66592);
+
+ if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+ && (brdysts & brdyenb)) {
+ irq_pipe_ready(m66592, brdysts, brdyenb);
+ }
+ if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+ && (bempsts & bempenb)) {
+ irq_pipe_empty(m66592, bempsts, bempenb);
+ }
+
+ if (intsts0 & M66592_CTRT)
+ irq_control_stage(m66592);
+ }
+
+ m66592_write(m66592, savepipe, M66592_CFIFOSEL);
+
+ spin_unlock(&m66592->lock);
+ return IRQ_HANDLED;
+}
+
+static void m66592_timer(unsigned long _m66592)
+{
+ struct m66592 *m66592 = (struct m66592 *)_m66592;
+ unsigned long flags;
+ u16 tmp;
+
+ spin_lock_irqsave(&m66592->lock, flags);
+ tmp = m66592_read(m66592, M66592_SYSCFG);
+ if (!(tmp & M66592_RCKE)) {
+ m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+ udelay(10);
+ m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+ }
+ if (m66592->scount > 0) {
+ tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS;
+ if (tmp == m66592->old_vbus) {
+ m66592->scount--;
+ if (m66592->scount == 0) {
+ if (tmp == M66592_VBSTS)
+ m66592_usb_connect(m66592);
+ else
+ m66592_usb_disconnect(m66592);
+ } else {
+ mod_timer(&m66592->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ } else {
+ m66592->scount = M66592_MAX_SAMPLING;
+ m66592->old_vbus = tmp;
+ mod_timer(&m66592->timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ }
+ spin_unlock_irqrestore(&m66592->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+static int m66592_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct m66592_ep *ep;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ return alloc_pipe_config(ep, desc);
+}
+
+static int m66592_disable(struct usb_ep *_ep)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ BUG_ON(!ep);
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ transfer_complete(ep, req, -ECONNRESET);
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+ }
+
+ pipe_irq_disable(ep->m66592, ep->pipenum);
+ return free_pipe_config(ep);
+}
+
+static struct usb_request *m66592_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct m66592_request *req;
+
+ req = kzalloc(sizeof(struct m66592_request), gfp_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void m66592_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct m66592_request *req;
+
+ req = container_of(_req, struct m66592_request, req);
+ kfree(req);
+}
+
+static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+ int request = 0;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ req = container_of(_req, struct m66592_request, req);
+
+ if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+
+ if (list_empty(&ep->queue))
+ request = 1;
+
+ list_add_tail(&req->queue, &ep->queue);
+ req->req.actual = 0;
+ req->req.status = -EINPROGRESS;
+
+ if (ep->desc == 0) /* control */
+ start_ep0(ep, req);
+ else {
+ if (request && !ep->busy)
+ start_packet(ep, req);
+ }
+
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+
+ return 0;
+}
+
+static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ req = container_of(_req, struct m66592_request, req);
+
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ if (!list_empty(&ep->queue))
+ transfer_complete(ep, req, -ECONNRESET);
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+
+ return 0;
+}
+
+static int m66592_set_halt(struct usb_ep *_ep, int value)
+{
+ struct m66592_ep *ep;
+ struct m66592_request *req;
+ unsigned long flags;
+ int ret = 0;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ req = list_entry(ep->queue.next, struct m66592_request, queue);
+
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ if (!list_empty(&ep->queue)) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ if (value) {
+ ep->busy = 1;
+ pipe_stall(ep->m66592, ep->pipenum);
+ } else {
+ ep->busy = 0;
+ pipe_stop(ep->m66592, ep->pipenum);
+ }
+
+out:
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+ return ret;
+}
+
+static void m66592_fifo_flush(struct usb_ep *_ep)
+{
+ struct m66592_ep *ep;
+ unsigned long flags;
+
+ ep = container_of(_ep, struct m66592_ep, ep);
+ spin_lock_irqsave(&ep->m66592->lock, flags);
+ if (list_empty(&ep->queue) && !ep->busy) {
+ pipe_stop(ep->m66592, ep->pipenum);
+ m66592_bclr(ep->m66592, M66592_BCLR, ep->fifoctr);
+ }
+ spin_unlock_irqrestore(&ep->m66592->lock, flags);
+}
+
+static struct usb_ep_ops m66592_ep_ops = {
+ .enable = m66592_enable,
+ .disable = m66592_disable,
+
+ .alloc_request = m66592_alloc_request,
+ .free_request = m66592_free_request,
+
+ .queue = m66592_queue,
+ .dequeue = m66592_dequeue,
+
+ .set_halt = m66592_set_halt,
+ .fifo_flush = m66592_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+static struct m66592 *the_controller;
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct m66592 *m66592 = the_controller;
+ int retval;
+
+ if (!driver
+ || driver->speed != USB_SPEED_HIGH
+ || !driver->bind
+ || !driver->setup)
+ return -EINVAL;
+ if (!m66592)
+ return -ENODEV;
+ if (m66592->driver)
+ return -EBUSY;
+
+ /* hook up the driver */
+ driver->driver.bus = NULL;
+ m66592->driver = driver;
+ m66592->gadget.dev.driver = &driver->driver;
+
+ retval = device_add(&m66592->gadget.dev);
+ if (retval) {
+ printk(KERN_ERR "device_add error (%d)\n", retval);
+ goto error;
+ }
+
+ retval = driver->bind (&m66592->gadget);
+ if (retval) {
+ printk(KERN_ERR "bind to driver error (%d)\n", retval);
+ device_del(&m66592->gadget.dev);
+ goto error;
+ }
+
+ m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
+ if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
+ m66592_start_xclock(m66592);
+ /* start vbus sampling */
+ m66592->old_vbus = m66592_read(m66592,
+ M66592_INTSTS0) & M66592_VBSTS;
+ m66592->scount = M66592_MAX_SAMPLING;
+ mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
+ }
+
+ return 0;
+
+error:
+ m66592->driver = NULL;
+ m66592->gadget.dev.driver = NULL;
+
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct m66592 *m66592 = the_controller;
+ unsigned long flags;
+
+ if (driver != m66592->driver || !driver->unbind)
+ return -EINVAL;
+
+ spin_lock_irqsave(&m66592->lock, flags);
+ if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
+ m66592_usb_disconnect(m66592);
+ spin_unlock_irqrestore(&m66592->lock, flags);
+
+ m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
+
+ driver->unbind(&m66592->gadget);
+
+ init_controller(m66592);
+ disable_controller(m66592);
+
+ device_del(&m66592->gadget.dev);
+ m66592->driver = NULL;
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+static int m66592_get_frame(struct usb_gadget *_gadget)
+{
+ struct m66592 *m66592 = gadget_to_m66592(_gadget);
+ return m66592_read(m66592, M66592_FRMNUM) & 0x03FF;
+}
+
+static struct usb_gadget_ops m66592_gadget_ops = {
+ .get_frame = m66592_get_frame,
+};
+
+static int __exit m66592_remove(struct platform_device *pdev)
+{
+ struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
+
+ del_timer_sync(&m66592->timer);
+ iounmap(m66592->reg);
+ free_irq(platform_get_irq(pdev, 0), m66592);
+ m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+ kfree(m66592);
+ return 0;
+}
+
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
+static int __init m66592_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int irq;
+ void __iomem *reg = NULL;
+ struct m66592 *m66592 = NULL;
+ int ret = 0;
+ int i;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ (char *)udc_name);
+ if (!res) {
+ ret = -ENODEV;
+ printk(KERN_ERR "platform_get_resource_byname error.\n");
+ goto clean_up;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENODEV;
+ printk(KERN_ERR "platform_get_irq error.\n");
+ goto clean_up;
+ }
+
+ reg = ioremap(res->start, resource_len(res));
+ if (reg == NULL) {
+ ret = -ENOMEM;
+ printk(KERN_ERR "ioremap error.\n");
+ goto clean_up;
+ }
+
+ /* initialize ucd */
+ m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
+ if (m66592 == NULL) {
+ printk(KERN_ERR "kzalloc error\n");
+ goto clean_up;
+ }
+
+ spin_lock_init(&m66592->lock);
+ dev_set_drvdata(&pdev->dev, m66592);
+
+ m66592->gadget.ops = &m66592_gadget_ops;
+ device_initialize(&m66592->gadget.dev);
+ strcpy(m66592->gadget.dev.bus_id, "gadget");
+ m66592->gadget.is_dualspeed = 1;
+ m66592->gadget.dev.parent = &pdev->dev;
+ m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
+ m66592->gadget.dev.release = pdev->dev.release;
+ m66592->gadget.name = udc_name;
+
+ init_timer(&m66592->timer);
+ m66592->timer.function = m66592_timer;
+ m66592->timer.data = (unsigned long)m66592;
+ m66592->reg = reg;
+
+ m66592->bi_bufnum = M66592_BASE_BUFNUM;
+
+ ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+ udc_name, m66592);
+ if (ret < 0) {
+ printk(KERN_ERR "request_irq error (%d)\n", ret);
+ goto clean_up;
+ }
+
+ INIT_LIST_HEAD(&m66592->gadget.ep_list);
+ m66592->gadget.ep0 = &m66592->ep[0].ep;
+ INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list);
+ for (i = 0; i < M66592_MAX_NUM_PIPE; i++) {
+ struct m66592_ep *ep = &m66592->ep[i];
+
+ if (i != 0) {
+ INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
+ list_add_tail(&m66592->ep[i].ep.ep_list,
+ &m66592->gadget.ep_list);
+ }
+ ep->m66592 = m66592;
+ INIT_LIST_HEAD(&ep->queue);
+ ep->ep.name = m66592_ep_name[i];
+ ep->ep.ops = &m66592_ep_ops;
+ ep->ep.maxpacket = 512;
+ }
+ m66592->ep[0].ep.maxpacket = 64;
+ m66592->ep[0].pipenum = 0;
+ m66592->ep[0].fifoaddr = M66592_CFIFO;
+ m66592->ep[0].fifosel = M66592_CFIFOSEL;
+ m66592->ep[0].fifoctr = M66592_CFIFOCTR;
+ m66592->ep[0].fifotrn = 0;
+ m66592->ep[0].pipectr = get_pipectr_addr(0);
+ m66592->pipenum2ep[0] = &m66592->ep[0];
+ m66592->epaddr2ep[0] = &m66592->ep[0];
+
+ the_controller = m66592;
+
+ m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
+ if (m66592->ep0_req == NULL)
+ goto clean_up2;
+ m66592->ep0_req->complete = nop_completion;
+
+ init_controller(m66592);
+
+ dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
+ return 0;
+
+clean_up2:
+ free_irq(irq, m66592);
+clean_up:
+ if (m66592) {
+ if (m66592->ep0_req)
+ m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+ kfree(m66592);
+ }
+ if (reg)
+ iounmap(reg);
+
+ return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+static struct platform_driver m66592_driver = {
+ .remove = __exit_p(m66592_remove),
+ .driver = {
+ .name = (char *) udc_name,
+ },
+};
+
+static int __init m66592_udc_init(void)
+{
+ return platform_driver_probe(&m66592_driver, m66592_probe);
+}
+module_init(m66592_udc_init);
+
+static void __exit m66592_udc_cleanup(void)
+{
+ platform_driver_unregister(&m66592_driver);
+}
+module_exit(m66592_udc_cleanup);
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
new file mode 100644
index 000000000000..bfa0c645f229
--- /dev/null
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -0,0 +1,575 @@
+/*
+ * M66592 UDC (USB gadget)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __M66592_UDC_H__
+#define __M66592_UDC_H__
+
+#define M66592_SYSCFG 0x00
+#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
+#define M66592_XTAL48 0x8000 /* 48MHz */
+#define M66592_XTAL24 0x4000 /* 24MHz */
+#define M66592_XTAL12 0x0000 /* 12MHz */
+#define M66592_XCKE 0x2000 /* b13: External clock enable */
+#define M66592_RCKE 0x1000 /* b12: Register clock enable */
+#define M66592_PLLC 0x0800 /* b11: PLL control */
+#define M66592_SCKE 0x0400 /* b10: USB clock enable */
+#define M66592_ATCKM 0x0100 /* b8: Automatic clock supply */
+#define M66592_HSE 0x0080 /* b7: Hi-speed enable */
+#define M66592_DCFM 0x0040 /* b6: Controller function select */
+#define M66592_DMRPD 0x0020 /* b5: D- pull down control */
+#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */
+#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */
+#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */
+#define M66592_USBE 0x0001 /* b0: USB module operation enable */
+
+#define M66592_SYSSTS 0x02
+#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */
+#define M66592_SE1 0x0003 /* SE1 */
+#define M66592_KSTS 0x0002 /* K State */
+#define M66592_JSTS 0x0001 /* J State */
+#define M66592_SE0 0x0000 /* SE0 */
+
+#define M66592_DVSTCTR 0x04
+#define M66592_WKUP 0x0100 /* b8: Remote wakeup */
+#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define M66592_USBRST 0x0040 /* b6: USB reset enable */
+#define M66592_RESUME 0x0020 /* b5: Resume enable */
+#define M66592_UACT 0x0010 /* b4: USB bus enable */
+#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */
+#define M66592_HSMODE 0x0003 /* Hi-Speed mode */
+#define M66592_FSMODE 0x0002 /* Full-Speed mode */
+#define M66592_HSPROC 0x0001 /* HS handshake is processing */
+
+#define M66592_TESTMODE 0x06
+#define M66592_UTST 0x000F /* b4-0: Test select */
+#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define M66592_H_TST_K 0x000A /* HOST TEST K */
+#define M66592_H_TST_J 0x0009 /* HOST TEST J */
+#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define M66592_P_TST_K 0x0002 /* PERI TEST K */
+#define M66592_P_TST_J 0x0001 /* PERI TEST J */
+#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+
+#define M66592_PINCFG 0x0A
+#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
+#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
+
+#define M66592_DMA0CFG 0x0C
+#define M66592_DMA1CFG 0x0E
+#define M66592_DREQA 0x4000 /* b14: Dreq active select */
+#define M66592_BURST 0x2000 /* b13: Burst mode */
+#define M66592_DACKA 0x0400 /* b10: Dack active select */
+#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */
+#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA 0x0040 /* b6: Dend active select */
+#define M66592_PKTM 0x0020 /* b5: Packet mode */
+#define M66592_DENDE 0x0010 /* b4: Dend enable */
+#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
+
+#define M66592_CFIFO 0x10
+#define M66592_D0FIFO 0x14
+#define M66592_D1FIFO 0x18
+
+#define M66592_CFIFOSEL 0x1E
+#define M66592_D0FIFOSEL 0x24
+#define M66592_D1FIFOSEL 0x2A
+#define M66592_RCNT 0x8000 /* b15: Read count mode */
+#define M66592_REW 0x4000 /* b14: Buffer rewind */
+#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
+#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
+#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */
+#define M66592_MBW_8 0x0000 /* 8bit */
+#define M66592_MBW_16 0x0400 /* 16bit */
+#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
+#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
+#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */
+#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */
+
+#define M66592_CFIFOCTR 0x20
+#define M66592_D0FIFOCTR 0x26
+#define M66592_D1FIFOCTR 0x2c
+#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */
+#define M66592_BCLR 0x4000 /* b14: Buffer clear */
+#define M66592_FRDY 0x2000 /* b13: FIFO ready */
+#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */
+
+#define M66592_CFIFOSIE 0x22
+#define M66592_TGL 0x8000 /* b15: Buffer toggle */
+#define M66592_SCLR 0x4000 /* b14: Buffer clear */
+#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */
+
+#define M66592_D0FIFOTRN 0x28
+#define M66592_D1FIFOTRN 0x2E
+#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */
+
+#define M66592_INTENB0 0x30
+#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */
+#define M66592_RSME 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */
+#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */
+#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition irq */
+#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */
+#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */
+#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */
+#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */
+#define M66592_WDST 0x0008 /* b3: Control write data stage completed irq */
+#define M66592_RDST 0x0004 /* b2: Control read data stage completed irq */
+#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */
+#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */
+
+#define M66592_INTENB1 0x32
+#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */
+#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */
+#define M66592_INTL 0x0002 /* b1: Interrupt sense select */
+#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */
+
+#define M66592_BRDYENB 0x36
+#define M66592_BRDYSTS 0x46
+#define M66592_BRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_BRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_BRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_BRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_BRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_BRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_BRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_BRDY0 0x0001 /* b1: PIPE0 */
+
+#define M66592_NRDYENB 0x38
+#define M66592_NRDYSTS 0x48
+#define M66592_NRDY7 0x0080 /* b7: PIPE7 */
+#define M66592_NRDY6 0x0040 /* b6: PIPE6 */
+#define M66592_NRDY5 0x0020 /* b5: PIPE5 */
+#define M66592_NRDY4 0x0010 /* b4: PIPE4 */
+#define M66592_NRDY3 0x0008 /* b3: PIPE3 */
+#define M66592_NRDY2 0x0004 /* b2: PIPE2 */
+#define M66592_NRDY1 0x0002 /* b1: PIPE1 */
+#define M66592_NRDY0 0x0001 /* b1: PIPE0 */
+
+#define M66592_BEMPENB 0x3A
+#define M66592_BEMPSTS 0x4A
+#define M66592_BEMP7 0x0080 /* b7: PIPE7 */
+#define M66592_BEMP6 0x0040 /* b6: PIPE6 */
+#define M66592_BEMP5 0x0020 /* b5: PIPE5 */
+#define M66592_BEMP4 0x0010 /* b4: PIPE4 */
+#define M66592_BEMP3 0x0008 /* b3: PIPE3 */
+#define M66592_BEMP2 0x0004 /* b2: PIPE2 */
+#define M66592_BEMP1 0x0002 /* b1: PIPE1 */
+#define M66592_BEMP0 0x0001 /* b0: PIPE0 */
+
+#define M66592_SOFCFG 0x3C
+#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */
+#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */
+#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */
+
+#define M66592_INTSTS0 0x40
+#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */
+#define M66592_RESM 0x4000 /* b14: Resume interrupt */
+#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define M66592_DVST 0x1000 /* b12: Device state transition */
+#define M66592_CTRT 0x0800 /* b11: Control stage transition */
+#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define M66592_VBSTS 0x0080 /* b7: VBUS input port */
+#define M66592_DVSQ 0x0070 /* b6-4: Device state */
+#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define M66592_DS_SUSP 0x0040 /* Suspend */
+#define M66592_DS_CNFG 0x0030 /* Configured */
+#define M66592_DS_ADDS 0x0020 /* Address */
+#define M66592_DS_DFLT 0x0010 /* Default */
+#define M66592_DS_POWR 0x0000 /* Powered */
+#define M66592_DVSQS 0x0030 /* b5-4: Device state */
+#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */
+#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define M66592_CS_SQER 0x0006 /* Sequence error */
+#define M66592_CS_WRND 0x0005 /* Control write nodata status */
+#define M66592_CS_WRSS 0x0004 /* Control write status stage */
+#define M66592_CS_WRDS 0x0003 /* Control write data stage */
+#define M66592_CS_RDSS 0x0002 /* Control read status stage */
+#define M66592_CS_RDDS 0x0001 /* Control read data stage */
+#define M66592_CS_IDST 0x0000 /* Idle or setup stage */
+
+#define M66592_INTSTS1 0x42
+#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */
+#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */
+#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */
+
+#define M66592_FRMNUM 0x4C
+#define M66592_OVRN 0x8000 /* b15: Overrun error */
+#define M66592_CRCE 0x4000 /* b14: Received data error */
+#define M66592_SOFRM 0x0800 /* b11: SOF output mode */
+#define M66592_FRNM 0x07FF /* b10-0: Frame number */
+
+#define M66592_UFRMNUM 0x4E
+#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */
+
+#define M66592_RECOVER 0x50
+#define M66592_STSRECOV 0x0700 /* Status recovery */
+#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */
+#define M66592_STSR_DEFAULT 0x0100 /* Default state */
+#define M66592_STSR_ADDRESS 0x0200 /* Address state */
+#define M66592_STSR_CONFIG 0x0300 /* Configured state */
+#define M66592_USBADDR 0x007F /* b6-0: USB address */
+
+#define M66592_USBREQ 0x54
+#define M66592_bRequest 0xFF00 /* b15-8: bRequest */
+#define M66592_GET_STATUS 0x0000
+#define M66592_CLEAR_FEATURE 0x0100
+#define M66592_ReqRESERVED 0x0200
+#define M66592_SET_FEATURE 0x0300
+#define M66592_ReqRESERVED1 0x0400
+#define M66592_SET_ADDRESS 0x0500
+#define M66592_GET_DESCRIPTOR 0x0600
+#define M66592_SET_DESCRIPTOR 0x0700
+#define M66592_GET_CONFIGURATION 0x0800
+#define M66592_SET_CONFIGURATION 0x0900
+#define M66592_GET_INTERFACE 0x0A00
+#define M66592_SET_INTERFACE 0x0B00
+#define M66592_SYNCH_FRAME 0x0C00
+#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data direction */
+#define M66592_HOST_TO_DEVICE 0x0000
+#define M66592_DEVICE_TO_HOST 0x0080
+#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */
+#define M66592_STANDARD 0x0000
+#define M66592_CLASS 0x0020
+#define M66592_VENDOR 0x0040
+#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */
+#define M66592_DEVICE 0x0000
+#define M66592_INTERFACE 0x0001
+#define M66592_ENDPOINT 0x0002
+
+#define M66592_USBVAL 0x56
+#define M66592_wValue 0xFFFF /* b15-0: wValue */
+/* Standard Feature Selector */
+#define M66592_ENDPOINT_HALT 0x0000
+#define M66592_DEVICE_REMOTE_WAKEUP 0x0001
+#define M66592_TEST_MODE 0x0002
+/* Descriptor Types */
+#define M66592_DT_TYPE 0xFF00
+#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8)
+#define M66592_DT_DEVICE 0x01
+#define M66592_DT_CONFIGURATION 0x02
+#define M66592_DT_STRING 0x03
+#define M66592_DT_INTERFACE 0x04
+#define M66592_DT_ENDPOINT 0x05
+#define M66592_DT_DEVICE_QUALIFIER 0x06
+#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07
+#define M66592_DT_INTERFACE_POWER 0x08
+#define M66592_DT_INDEX 0x00FF
+#define M66592_CONF_NUM 0x00FF
+#define M66592_ALT_SET 0x00FF
+
+#define M66592_USBINDEX 0x58
+#define M66592_wIndex 0xFFFF /* b15-0: wIndex */
+#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode */
+#define M66592_TEST_J 0x0100 /* Test_J */
+#define M66592_TEST_K 0x0200 /* Test_K */
+#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */
+#define M66592_TEST_PACKET 0x0400 /* Test_Packet */
+#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */
+#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */
+#define M66592_TEST_Reserved 0x4000 /* Reserved */
+#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific tests */
+#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */
+#define M66592_EP_DIR_IN 0x0080
+#define M66592_EP_DIR_OUT 0x0000
+
+#define M66592_USBLENG 0x5A
+#define M66592_wLength 0xFFFF /* b15-0: wLength */
+
+#define M66592_DCPCFG 0x5C
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */
+
+#define M66592_DCPMAXP 0x5E
+#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */
+#define M66592_DEVICE_0 0x0000 /* Device address 0 */
+#define M66592_DEVICE_1 0x4000 /* Device address 1 */
+#define M66592_DEVICE_2 0x8000 /* Device address 2 */
+#define M66592_DEVICE_3 0xC000 /* Device address 3 */
+#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of ep0 */
+
+#define M66592_DCPCTR 0x60
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_SUREQ 0x4000 /* b14: Send USB request */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_CCPL 0x0004 /* b2: control transfer complete */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
+#define M66592_PID_STALL 0x0002 /* STALL */
+#define M66592_PID_BUF 0x0001 /* BUF */
+#define M66592_PID_NAK 0x0000 /* NAK */
+
+#define M66592_PIPESEL 0x64
+#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */
+#define M66592_PIPE0 0x0000 /* PIPE 0 */
+#define M66592_PIPE1 0x0001 /* PIPE 1 */
+#define M66592_PIPE2 0x0002 /* PIPE 2 */
+#define M66592_PIPE3 0x0003 /* PIPE 3 */
+#define M66592_PIPE4 0x0004 /* PIPE 4 */
+#define M66592_PIPE5 0x0005 /* PIPE 5 */
+#define M66592_PIPE6 0x0006 /* PIPE 6 */
+#define M66592_PIPE7 0x0007 /* PIPE 7 */
+
+#define M66592_PIPECFG 0x66
+#define M66592_TYP 0xC000 /* b15-14: Transfer type */
+#define M66592_ISO 0xC000 /* Isochronous */
+#define M66592_INT 0x8000 /* Interrupt */
+#define M66592_BULK 0x4000 /* Bulk */
+#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode */
+#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */
+#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */
+#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define M66592_DIR 0x0010 /* b4: Transfer direction select */
+#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */
+#define M66592_DIR_P_IN 0x0010 /* PERI IN */
+#define M66592_DIR_H_IN 0x0000 /* HOST IN */
+#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */
+#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */
+#define M66592_EP1 0x0001
+#define M66592_EP2 0x0002
+#define M66592_EP3 0x0003
+#define M66592_EP4 0x0004
+#define M66592_EP5 0x0005
+#define M66592_EP6 0x0006
+#define M66592_EP7 0x0007
+#define M66592_EP8 0x0008
+#define M66592_EP9 0x0009
+#define M66592_EP10 0x000A
+#define M66592_EP11 0x000B
+#define M66592_EP12 0x000C
+#define M66592_EP13 0x000D
+#define M66592_EP14 0x000E
+#define M66592_EP15 0x000F
+
+#define M66592_PIPEBUF 0x68
+#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */
+
+#define M66592_PIPEMAXP 0x6A
+#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */
+
+#define M66592_PIPEPERI 0x6C
+#define M66592_IFIS 0x1000 /* b12: ISO in-buffer flush mode */
+#define M66592_IITV 0x0007 /* b2-0: ISO interval */
+
+#define M66592_PIPE1CTR 0x70
+#define M66592_PIPE2CTR 0x72
+#define M66592_PIPE3CTR 0x74
+#define M66592_PIPE4CTR 0x76
+#define M66592_PIPE5CTR 0x78
+#define M66592_PIPE6CTR 0x7A
+#define M66592_PIPE7CTR 0x7C
+#define M66592_BSTS 0x8000 /* b15: Buffer status */
+#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define M66592_PID 0x0003 /* b1-0: Response PID */
+
+#define M66592_INVALID_REG 0x7E
+
+
+#define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2)
+
+#define M66592_MAX_SAMPLING 10
+
+#define M66592_MAX_NUM_PIPE 8
+#define M66592_MAX_NUM_BULK 3
+#define M66592_MAX_NUM_ISOC 2
+#define M66592_MAX_NUM_INT 2
+
+#define M66592_BASE_PIPENUM_BULK 3
+#define M66592_BASE_PIPENUM_ISOC 1
+#define M66592_BASE_PIPENUM_INT 6
+
+#define M66592_BASE_BUFNUM 6
+#define M66592_MAX_BUFNUM 0x4F
+
+struct m66592_pipe_info {
+ u16 pipe;
+ u16 epnum;
+ u16 maxpacket;
+ u16 type;
+ u16 interval;
+ u16 dir_in;
+};
+
+struct m66592_request {
+ struct usb_request req;
+ struct list_head queue;
+};
+
+struct m66592_ep {
+ struct usb_ep ep;
+ struct m66592 *m66592;
+
+ struct list_head queue;
+ unsigned busy:1;
+ unsigned internal_ccpl:1; /* use only control */
+
+ /* this member can able to after m66592_enable */
+ unsigned use_dma:1;
+ u16 pipenum;
+ u16 type;
+ const struct usb_endpoint_descriptor *desc;
+ /* register address */
+ unsigned long fifoaddr;
+ unsigned long fifosel;
+ unsigned long fifoctr;
+ unsigned long fifotrn;
+ unsigned long pipectr;
+};
+
+struct m66592 {
+ spinlock_t lock;
+ void __iomem *reg;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+
+ struct m66592_ep ep[M66592_MAX_NUM_PIPE];
+ struct m66592_ep *pipenum2ep[M66592_MAX_NUM_PIPE];
+ struct m66592_ep *epaddr2ep[16];
+
+ struct usb_request *ep0_req; /* for internal request */
+ u16 ep0_data; /* for internal request */
+
+ struct timer_list timer;
+
+ u16 old_vbus;
+ int scount;
+
+ int old_dvsq;
+
+ /* pipe config */
+ int bulk;
+ int interrupt;
+ int isochronous;
+ int num_dma;
+ int bi_bufnum; /* bulk and isochronous's bufnum */
+};
+
+#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
+#define m66592_to_gadget(m66592) (&m66592->gadget)
+
+#define is_bulk_pipe(pipenum) \
+ ((pipenum >= M66592_BASE_PIPENUM_BULK) && \
+ (pipenum < (M66592_BASE_PIPENUM_BULK + M66592_MAX_NUM_BULK)))
+#define is_interrupt_pipe(pipenum) \
+ ((pipenum >= M66592_BASE_PIPENUM_INT) && \
+ (pipenum < (M66592_BASE_PIPENUM_INT + M66592_MAX_NUM_INT)))
+#define is_isoc_pipe(pipenum) \
+ ((pipenum >= M66592_BASE_PIPENUM_ISOC) && \
+ (pipenum < (M66592_BASE_PIPENUM_ISOC + M66592_MAX_NUM_ISOC)))
+
+#define enable_irq_ready(m66592, pipenum) \
+ enable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
+#define disable_irq_ready(m66592, pipenum) \
+ disable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
+#define enable_irq_empty(m66592, pipenum) \
+ enable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
+#define disable_irq_empty(m66592, pipenum) \
+ disable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
+#define enable_irq_nrdy(m66592, pipenum) \
+ enable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
+#define disable_irq_nrdy(m66592, pipenum) \
+ disable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
+
+/*-------------------------------------------------------------------------*/
+static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
+{
+ return inw((unsigned long)m66592->reg + offset);
+}
+
+static inline void m66592_read_fifo(struct m66592 *m66592,
+ unsigned long offset,
+ void *buf, unsigned long len)
+{
+ unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+
+ len = (len + 1) / 2;
+ insw(fifoaddr, buf, len);
+}
+
+static inline void m66592_write(struct m66592 *m66592, u16 val,
+ unsigned long offset)
+{
+ outw(val, (unsigned long)m66592->reg + offset);
+}
+
+static inline void m66592_write_fifo(struct m66592 *m66592,
+ unsigned long offset,
+ void *buf, unsigned long len)
+{
+ unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+ unsigned long odd = len & 0x0001;
+
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (odd) {
+ unsigned char *p = buf + len*2;
+ outb(*p, fifoaddr);
+ }
+}
+
+static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
+ unsigned long offset)
+{
+ u16 tmp;
+ tmp = m66592_read(m66592, offset);
+ tmp = tmp & (~pat);
+ tmp = tmp | val;
+ m66592_write(m66592, tmp, offset);
+}
+
+#define m66592_bclr(m66592, val, offset) \
+ m66592_mdfy(m66592, 0, val, offset)
+#define m66592_bset(m66592, val, offset) \
+ m66592_mdfy(m66592, val, 0, offset)
+
+#endif /* ifndef __M66592_UDC_H__ */
+
+
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index d975ecf18e00..c3d364ecd4f8 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -450,100 +450,6 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-/*
- * dma-coherent memory allocation (for dma-capable endpoints)
- *
- * NOTE: the dma_*_coherent() API calls suck. Most implementations are
- * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
- * respect to calls with irqs disabled: alloc is safe, free is not.
- * We currently work around (b), but not (a).
- */
-
-static void *
-net2280_alloc_buffer (
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t gfp_flags
-)
-{
- void *retval;
- struct net2280_ep *ep;
-
- ep = container_of (_ep, struct net2280_ep, ep);
- if (!_ep)
- return NULL;
- *dma = DMA_ADDR_INVALID;
-
- if (ep->dma)
- retval = dma_alloc_coherent(&ep->dev->pdev->dev,
- bytes, dma, gfp_flags);
- else
- retval = kmalloc(bytes, gfp_flags);
- return retval;
-}
-
-static DEFINE_SPINLOCK(buflock);
-static LIST_HEAD(buffers);
-
-struct free_record {
- struct list_head list;
- struct device *dev;
- unsigned bytes;
- dma_addr_t dma;
-};
-
-static void do_free(unsigned long ignored)
-{
- spin_lock_irq(&buflock);
- while (!list_empty(&buffers)) {
- struct free_record *buf;
-
- buf = list_entry(buffers.next, struct free_record, list);
- list_del(&buf->list);
- spin_unlock_irq(&buflock);
-
- dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
-
- spin_lock_irq(&buflock);
- }
- spin_unlock_irq(&buflock);
-}
-
-static DECLARE_TASKLET(deferred_free, do_free, 0);
-
-static void
-net2280_free_buffer (
- struct usb_ep *_ep,
- void *address,
- dma_addr_t dma,
- unsigned bytes
-) {
- /* free memory into the right allocator */
- if (dma != DMA_ADDR_INVALID) {
- struct net2280_ep *ep;
- struct free_record *buf = address;
- unsigned long flags;
-
- ep = container_of(_ep, struct net2280_ep, ep);
- if (!_ep)
- return;
-
- ep = container_of (_ep, struct net2280_ep, ep);
- buf->dev = &ep->dev->pdev->dev;
- buf->bytes = bytes;
- buf->dma = dma;
-
- spin_lock_irqsave(&buflock, flags);
- list_add_tail(&buf->list, &buffers);
- tasklet_schedule(&deferred_free);
- spin_unlock_irqrestore(&buflock, flags);
- } else
- kfree (address);
-}
-
-/*-------------------------------------------------------------------------*/
-
/* load a packet into the fifo we use for usb IN transfers.
* works for all endpoints.
*
@@ -1392,9 +1298,6 @@ static const struct usb_ep_ops net2280_ep_ops = {
.alloc_request = net2280_alloc_request,
.free_request = net2280_free_request,
- .alloc_buffer = net2280_alloc_buffer,
- .free_buffer = net2280_free_buffer,
-
.queue = net2280_queue,
.dequeue = net2280_dequeue,
@@ -2964,7 +2867,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
, &dev->pci->pcimstctl);
/* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */
pci_set_master (pdev);
- pci_set_mwi (pdev);
+ pci_try_set_mwi (pdev);
/* ... also flushes any posted pci writes */
dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index c4975a6cf777..9b0f0925dddf 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -296,111 +296,6 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-/*
- * dma-coherent memory allocation (for dma-capable endpoints)
- *
- * NOTE: the dma_*_coherent() API calls suck. Most implementations are
- * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
- * respect to calls with irqs disabled: alloc is safe, free is not.
- * We currently work around (b), but not (a).
- */
-
-static void *
-omap_alloc_buffer(
- struct usb_ep *_ep,
- unsigned bytes,
- dma_addr_t *dma,
- gfp_t gfp_flags
-)
-{
- void *retval;
- struct omap_ep *ep;
-
- if (!_ep)
- return NULL;
-
- ep = container_of(_ep, struct omap_ep, ep);
- if (use_dma && ep->has_dma) {
- static int warned;
- if (!warned && bytes < PAGE_SIZE) {
- dev_warn(ep->udc->gadget.dev.parent,
- "using dma_alloc_coherent for "
- "small allocations wastes memory\n");
- warned++;
- }
- return dma_alloc_coherent(ep->udc->gadget.dev.parent,
- bytes, dma, gfp_flags);
- }
-
- retval = kmalloc(bytes, gfp_flags);
- if (retval)
- *dma = virt_to_phys(retval);
- return retval;
-}
-
-static DEFINE_SPINLOCK(buflock);
-static LIST_HEAD(buffers);
-
-struct free_record {
- struct list_head list;
- struct device *dev;
- unsigned bytes;
- dma_addr_t dma;
-};
-
-static void do_free(unsigned long ignored)
-{
- spin_lock_irq(&buflock);
- while (!list_empty(&buffers)) {
- struct free_record *buf;
-
- buf = list_entry(buffers.next, struct free_record, list);
- list_del(&buf->list);
- spin_unlock_irq(&buflock);
-
- dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
-
- spin_lock_irq(&buflock);
- }
- spin_unlock_irq(&buflock);
-}
-
-static DECLARE_TASKLET(deferred_free, do_free, 0);
-
-static void omap_free_buffer(
- struct usb_ep *_ep,
- void *buf,
- dma_addr_t dma,
- unsigned bytes
-)
-{
- if (!_ep) {
- WARN_ON(1);
- return;
- }
-
- /* free memory into the right allocator */
- if (dma != DMA_ADDR_INVALID) {
- struct omap_ep *ep;
- struct free_record *rec = buf;
- unsigned long flags;
-
- ep = container_of(_ep, struct omap_ep, ep);
-
- rec->dev = ep->udc->gadget.dev.parent;
- rec->bytes = bytes;
- rec->dma = dma;
-
- spin_lock_irqsave(&buflock, flags);
- list_add_tail(&rec->list, &buffers);
- tasklet_schedule(&deferred_free);
- spin_unlock_irqrestore(&buflock, flags);
- } else
- kfree(buf);
-}
-
-/*-------------------------------------------------------------------------*/
-
static void
done(struct omap_ep *ep, struct omap_req *req, int status)
{
@@ -1271,9 +1166,6 @@ static struct usb_ep_ops omap_ep_ops = {
.alloc_request = omap_alloc_request,
.free_request = omap_free_request,
- .alloc_buffer = omap_alloc_buffer,
- .free_buffer = omap_free_buffer,
-
.queue = omap_ep_queue,
.dequeue = omap_ep_dequeue,
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 84392e835d5f..63b9521c1322 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -24,9 +24,9 @@
*
*/
-#undef DEBUG
// #define VERBOSE DBG_VERBOSE
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -46,19 +46,17 @@
#include <asm/byteorder.h>
#include <asm/dma.h>
+#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
#include <asm/hardware.h>
-#ifdef CONFIG_ARCH_PXA
-#include <asm/arch/pxa-regs.h>
-#endif
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
-#include <asm/arch/udc.h>
+#include <asm/mach/udc_pxa2xx.h>
/*
@@ -76,9 +74,17 @@
* it constrains the sorts of USB configuration change events that work.
* The errata for these chips are misleading; some "fixed" bugs from
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
+ *
+ * Note that the UDC hardware supports DMA (except on IXP) but that's
+ * not used here. IN-DMA (to host) is simple enough, when the data is
+ * suitably aligned (16 bytes) ... the network stack doesn't do that,
+ * other software can. OUT-DMA is buggy in most chip versions, as well
+ * as poorly designed (data toggle not automatic). So this driver won't
+ * bother using DMA. (Mostly-working IN-DMA support was available in
+ * kernels before 2.6.23, but was never enabled or well tested.)
*/
-#define DRIVER_VERSION "4-May-2005"
+#define DRIVER_VERSION "30-June-2007"
#define DRIVER_DESC "PXA 25x USB Device Controller driver"
@@ -87,12 +93,9 @@ static const char driver_name [] = "pxa2xx_udc";
static const char ep0name [] = "ep0";
-// #define USE_DMA
-// #define USE_OUT_DMA
// #define DISABLE_TEST_MODE
#ifdef CONFIG_ARCH_IXP4XX
-#undef USE_DMA
/* cpu-specific register addresses are compiled in to this code */
#ifdef CONFIG_ARCH_PXA
@@ -104,25 +107,6 @@ static const char ep0name [] = "ep0";
#include "pxa2xx_udc.h"
-#ifdef USE_DMA
-static int use_dma = 1;
-module_param(use_dma, bool, 0);
-MODULE_PARM_DESC (use_dma, "true to use dma");
-
-static void dma_nodesc_handler (int dmach, void *_ep);
-static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);
-
-#ifdef USE_OUT_DMA
-#define DMASTR " (dma support)"
-#else
-#define DMASTR " (dma in)"
-#endif
-
-#else /* !USE_DMA */
-#define DMASTR " (pio only)"
-#undef USE_OUT_DMA
-#endif
-
#ifdef CONFIG_USB_PXA2XX_SMALL
#define SIZE_STR " (small)"
#else
@@ -155,7 +139,7 @@ static int is_vbus_present(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_vbus)
- return udc_gpio_get(mach->gpio_vbus);
+ return gpio_get_value(mach->gpio_vbus);
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
@@ -167,7 +151,7 @@ static void pullup_off(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- udc_gpio_set(mach->gpio_pullup, 0);
+ gpio_set_value(mach->gpio_pullup, 0);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
@@ -177,7 +161,7 @@ static void pullup_on(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
- udc_gpio_set(mach->gpio_pullup, 1);
+ gpio_set_value(mach->gpio_pullup, 1);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
@@ -281,9 +265,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
}
ep->desc = desc;
- ep->dma = -1;
ep->stopped = 0;
- ep->pio_irqs = ep->dma_irqs = 0;
+ ep->pio_irqs = 0;
ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
/* flush fifo (mostly for OUT buffers) */
@@ -291,30 +274,6 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
/* ... reset halt state too, if we could ... */
-#ifdef USE_DMA
- /* for (some) bulk and ISO endpoints, try to get a DMA channel and
- * bind it to the endpoint. otherwise use PIO.
- */
- switch (ep->bmAttributes) {
- case USB_ENDPOINT_XFER_ISOC:
- if (le16_to_cpu(desc->wMaxPacketSize) % 32)
- break;
- // fall through
- case USB_ENDPOINT_XFER_BULK:
- if (!use_dma || !ep->reg_drcmr)
- break;
- ep->dma = pxa_request_dma ((char *)_ep->name,
- (le16_to_cpu (desc->wMaxPacketSize) > 64)
- ? DMA_PRIO_MEDIUM /* some iso */
- : DMA_PRIO_LOW,
- dma_nodesc_handler, ep);
- if (ep->dma >= 0) {
- *ep->reg_drcmr = DRCMR_MAPVLD | ep->dma;
- DMSG("%s using dma%d\n", _ep->name, ep->dma);
- }
- }
-#endif
-
DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
return 0;
}
@@ -334,14 +293,6 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
nuke (ep, -ESHUTDOWN);
-#ifdef USE_DMA
- if (ep->dma >= 0) {
- *ep->reg_drcmr = 0;
- pxa_free_dma (ep->dma);
- ep->dma = -1;
- }
-#endif
-
/* flush fifo (mostly for IN buffers) */
pxa2xx_ep_fifo_flush (_ep);
@@ -390,35 +341,6 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
-
-/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's
- * no device-affinity and the heap works perfectly well for i/o buffers.
- * It wastes much less memory than dma_alloc_coherent() would, and even
- * prevents cacheline (32 bytes wide) sharing problems.
- */
-static void *
-pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags)
-{
- char *retval;
-
- retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));
- if (retval)
-#ifdef USE_DMA
- *dma = virt_to_bus (retval);
-#else
- *dma = (dma_addr_t)~0;
-#endif
- return retval;
-}
-
-static void
-pxa2xx_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma,
- unsigned bytes)
-{
- kfree (buf);
-}
-
/*-------------------------------------------------------------------------*/
/*
@@ -518,18 +440,8 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
/* requests complete when all IN data is in the FIFO */
if (is_last) {
done (ep, req, 0);
- if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) {
+ if (list_empty(&ep->queue))
pio_irq_disable (ep->bEndpointAddress);
-#ifdef USE_DMA
- /* unaligned data and zlps couldn't use dma */
- if (unlikely(!list_empty(&ep->queue))) {
- req = list_entry(ep->queue.next,
- struct pxa2xx_request, queue);
- kick_dma(ep,req);
- return 0;
- }
-#endif
- }
return 1;
}
@@ -728,182 +640,6 @@ read_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
return 0;
}
-#ifdef USE_DMA
-
-#define MAX_IN_DMA ((DCMD_LENGTH + 1) - BULK_FIFO_SIZE)
-
-static void
-start_dma_nodesc(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int is_in)
-{
- u32 dcmd = req->req.length;
- u32 buf = req->req.dma;
- u32 fifo = io_v2p ((u32)ep->reg_uddr);
-
- /* caller guarantees there's a packet or more remaining
- * - IN may end with a short packet (TSP set separately),
- * - OUT is always full length
- */
- buf += req->req.actual;
- dcmd -= req->req.actual;
- ep->dma_fixup = 0;
-
- /* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */
- DCSR(ep->dma) = DCSR_NODESC;
- if (is_in) {
- DSADR(ep->dma) = buf;
- DTADR(ep->dma) = fifo;
- if (dcmd > MAX_IN_DMA)
- dcmd = MAX_IN_DMA;
- else
- ep->dma_fixup = (dcmd % ep->ep.maxpacket) != 0;
- dcmd |= DCMD_BURST32 | DCMD_WIDTH1
- | DCMD_FLOWTRG | DCMD_INCSRCADDR;
- } else {
-#ifdef USE_OUT_DMA
- DSADR(ep->dma) = fifo;
- DTADR(ep->dma) = buf;
- if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC)
- dcmd = ep->ep.maxpacket;
- dcmd |= DCMD_BURST32 | DCMD_WIDTH1
- | DCMD_FLOWSRC | DCMD_INCTRGADDR;
-#endif
- }
- DCMD(ep->dma) = dcmd;
- DCSR(ep->dma) = DCSR_RUN | DCSR_NODESC
- | (unlikely(is_in)
- ? DCSR_STOPIRQEN /* use dma_nodesc_handler() */
- : 0); /* use handle_ep() */
-}
-
-static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req)
-{
- int is_in = ep->bEndpointAddress & USB_DIR_IN;
-
- if (is_in) {
- /* unaligned tx buffers and zlps only work with PIO */
- if ((req->req.dma & 0x0f) != 0
- || unlikely((req->req.length - req->req.actual)
- == 0)) {
- pio_irq_enable(ep->bEndpointAddress);
- if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0)
- (void) write_fifo(ep, req);
- } else {
- start_dma_nodesc(ep, req, USB_DIR_IN);
- }
- } else {
- if ((req->req.length - req->req.actual) < ep->ep.maxpacket) {
- DMSG("%s short dma read...\n", ep->ep.name);
- /* we're always set up for pio out */
- read_fifo (ep, req);
- } else {
- *ep->reg_udccs = UDCCS_BO_DME
- | (*ep->reg_udccs & UDCCS_BO_FST);
- start_dma_nodesc(ep, req, USB_DIR_OUT);
- }
- }
-}
-
-static void cancel_dma(struct pxa2xx_ep *ep)
-{
- struct pxa2xx_request *req;
- u32 tmp;
-
- if (DCSR(ep->dma) == 0 || list_empty(&ep->queue))
- return;
-
- DCSR(ep->dma) = 0;
- while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0)
- cpu_relax();
-
- req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
- tmp = DCMD(ep->dma) & DCMD_LENGTH;
- req->req.actual = req->req.length - (tmp & DCMD_LENGTH);
-
- /* the last tx packet may be incomplete, so flush the fifo.
- * FIXME correct req.actual if we can
- */
- if (ep->bEndpointAddress & USB_DIR_IN)
- *ep->reg_udccs = UDCCS_BI_FTF;
-}
-
-/* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */
-static void dma_nodesc_handler(int dmach, void *_ep)
-{
- struct pxa2xx_ep *ep = _ep;
- struct pxa2xx_request *req;
- u32 tmp, completed;
-
- local_irq_disable();
-
- req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
-
- ep->dma_irqs++;
- ep->dev->stats.irqs++;
- HEX_DISPLAY(ep->dev->stats.irqs);
-
- /* ack/clear */
- tmp = DCSR(ep->dma);
- DCSR(ep->dma) = tmp;
- if ((tmp & DCSR_STOPSTATE) == 0
- || (DDADR(ep->dma) & DDADR_STOP) != 0) {
- DBG(DBG_VERBOSE, "%s, dcsr %08x ddadr %08x\n",
- ep->ep.name, DCSR(ep->dma), DDADR(ep->dma));
- goto done;
- }
- DCSR(ep->dma) = 0; /* clear DCSR_STOPSTATE */
-
- /* update transfer status */
- completed = tmp & DCSR_BUSERR;
- if (ep->bEndpointAddress & USB_DIR_IN)
- tmp = DSADR(ep->dma);
- else
- tmp = DTADR(ep->dma);
- req->req.actual = tmp - req->req.dma;
-
- /* FIXME seems we sometimes see partial transfers... */
-
- if (unlikely(completed != 0))
- req->req.status = -EIO;
- else if (req->req.actual) {
- /* these registers have zeroes in low bits; they miscount
- * some (end-of-transfer) short packets: tx 14 as tx 12
- */
- if (ep->dma_fixup)
- req->req.actual = min(req->req.actual + 3,
- req->req.length);
-
- tmp = (req->req.length - req->req.actual);
- completed = (tmp == 0);
- if (completed && (ep->bEndpointAddress & USB_DIR_IN)) {
-
- /* maybe validate final short packet ... */
- if ((req->req.actual % ep->ep.maxpacket) != 0)
- *ep->reg_udccs = UDCCS_BI_TSP/*|UDCCS_BI_TPC*/;
-
- /* ... or zlp, using pio fallback */
- else if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK
- && req->req.zero) {
- DMSG("%s zlp terminate ...\n", ep->ep.name);
- completed = 0;
- }
- }
- }
-
- if (likely(completed)) {
- done(ep, req, 0);
-
- /* maybe re-activate after completion */
- if (ep->stopped || list_empty(&ep->queue))
- goto done;
- req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
- }
- kick_dma(ep, req);
-done:
- local_irq_enable();
-}
-
-#endif
-
/*-------------------------------------------------------------------------*/
static int
@@ -942,19 +678,8 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
(ep->desc->wMaxPacketSize)))
return -EMSGSIZE;
-#ifdef USE_DMA
- // FIXME caller may already have done the dma mapping
- if (ep->dma >= 0) {
- _req->dma = dma_map_single(dev->dev,
- _req->buf, _req->length,
- ((ep->bEndpointAddress & USB_DIR_IN) != 0)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- }
-#endif
-
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
- _ep->name, _req, _req->length, _req->buf);
+ _ep->name, _req, _req->length, _req->buf);
local_irq_save(flags);
@@ -1002,11 +727,6 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
local_irq_restore (flags);
return -EL2HLT;
}
-#ifdef USE_DMA
- /* either start dma or prime pio pump */
- } else if (ep->dma >= 0) {
- kick_dma(ep, req);
-#endif
/* can the FIFO can satisfy the request immediately? */
} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
@@ -1017,7 +737,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req = NULL;
}
- if (likely (req && ep->desc) && ep->dma < 0)
+ if (likely (req && ep->desc))
pio_irq_enable(ep->bEndpointAddress);
}
@@ -1038,10 +758,6 @@ static void nuke(struct pxa2xx_ep *ep, int status)
struct pxa2xx_request *req;
/* called with irqs blocked */
-#ifdef USE_DMA
- if (ep->dma >= 0 && !ep->stopped)
- cancel_dma(ep);
-#endif
while (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next,
struct pxa2xx_request,
@@ -1076,19 +792,7 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
return -EINVAL;
}
-#ifdef USE_DMA
- if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
- cancel_dma(ep);
- done(ep, req, -ECONNRESET);
- /* restart i/o */
- if (!list_empty(&ep->queue)) {
- req = list_entry(ep->queue.next,
- struct pxa2xx_request, queue);
- kick_dma(ep, req);
- }
- } else
-#endif
- done(ep, req, -ECONNRESET);
+ done(ep, req, -ECONNRESET);
local_irq_restore(flags);
return 0;
@@ -1203,9 +907,6 @@ static struct usb_ep_ops pxa2xx_ep_ops = {
.alloc_request = pxa2xx_ep_alloc_request,
.free_request = pxa2xx_ep_free_request,
- .alloc_buffer = pxa2xx_ep_alloc_buffer,
- .free_buffer = pxa2xx_ep_free_buffer,
-
.queue = pxa2xx_ep_queue,
.dequeue = pxa2xx_ep_dequeue,
@@ -1325,7 +1026,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
/* basic device status */
t = scnprintf(next, size, DRIVER_DESC "\n"
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
- driver_name, DRIVER_VERSION SIZE_STR DMASTR,
+ driver_name, DRIVER_VERSION SIZE_STR "(pio)",
dev->driver ? dev->driver->driver.name : "(none)",
is_vbus_present() ? "full speed" : "disconnected");
size -= t;
@@ -1390,7 +1091,6 @@ udc_proc_read(char *page, char **start, off_t off, int count,
for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
struct pxa2xx_ep *ep = &dev->ep [i];
struct pxa2xx_request *req;
- int t;
if (i != 0) {
const struct usb_endpoint_descriptor *d;
@@ -1400,10 +1100,9 @@ udc_proc_read(char *page, char **start, off_t off, int count,
continue;
tmp = *dev->ep [i].reg_udccs;
t = scnprintf(next, size,
- "%s max %d %s udccs %02x irqs %lu/%lu\n",
+ "%s max %d %s udccs %02x irqs %lu\n",
ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
- (ep->dma >= 0) ? "dma" : "pio", tmp,
- ep->pio_irqs, ep->dma_irqs);
+ "pio", tmp, ep->pio_irqs);
/* TODO translate all five groups of udccs bits! */
} else /* ep0 should only have one transfer queued */
@@ -1423,19 +1122,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
continue;
}
list_for_each_entry(req, &ep->queue, queue) {
-#ifdef USE_DMA
- if (ep->dma >= 0 && req->queue.prev == &ep->queue)
- t = scnprintf(next, size,
- "\treq %p len %d/%d "
- "buf %p (dma%d dcmd %08x)\n",
- &req->req, req->req.actual,
- req->req.length, req->req.buf,
- ep->dma, DCMD(ep->dma)
- // low 13 bits == bytes-to-go
- );
- else
-#endif
- t = scnprintf(next, size,
+ t = scnprintf(next, size,
"\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual,
req->req.length, req->req.buf);
@@ -1488,7 +1175,6 @@ static void udc_disable(struct pxa2xx_udc *dev)
ep0_idle (dev);
dev->gadget.speed = USB_SPEED_UNKNOWN;
- LED_CONNECTED_OFF;
}
@@ -1514,7 +1200,7 @@ static void udc_reinit(struct pxa2xx_udc *dev)
ep->desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
- ep->pio_irqs = ep->dma_irqs = 0;
+ ep->pio_irqs = 0;
}
/* the rest was statically initialized, and is read-only */
@@ -1666,7 +1352,6 @@ stop_activity(struct pxa2xx_udc *dev, struct usb_gadget_driver *driver)
del_timer_sync(&dev->timer);
/* report disconnect; the driver is already quiesced */
- LED_CONNECTED_OFF;
if (driver)
driver->disconnect(&dev->gadget);
@@ -1715,16 +1400,13 @@ lubbock_vbus_irq(int irq, void *_dev)
int vbus;
dev->stats.irqs++;
- HEX_DISPLAY(dev->stats.irqs);
switch (irq) {
case LUBBOCK_USB_IRQ:
- LED_CONNECTED_ON;
vbus = 1;
disable_irq(LUBBOCK_USB_IRQ);
enable_irq(LUBBOCK_USB_DISC_IRQ);
break;
case LUBBOCK_USB_DISC_IRQ:
- LED_CONNECTED_OFF;
vbus = 0;
disable_irq(LUBBOCK_USB_DISC_IRQ);
enable_irq(LUBBOCK_USB_IRQ);
@@ -1742,7 +1424,7 @@ lubbock_vbus_irq(int irq, void *_dev)
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
- int vbus = udc_gpio_get(dev->mach->gpio_vbus);
+ int vbus = gpio_get_value(dev->mach->gpio_vbus);
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
@@ -2040,18 +1722,6 @@ static void handle_ep(struct pxa2xx_ep *ep)
/* fifos can hold packets, ready for reading... */
if (likely(req)) {
-#ifdef USE_OUT_DMA
-// TODO didn't yet debug out-dma. this approach assumes
-// the worst about short packets and RPC; it might be better.
-
- if (likely(ep->dma >= 0)) {
- if (!(udccs & UDCCS_BO_RSP)) {
- *ep->reg_udccs = UDCCS_BO_RPC;
- ep->dma_irqs++;
- return;
- }
- }
-#endif
completed = read_fifo(ep, req);
} else
pio_irq_disable (ep->bEndpointAddress);
@@ -2074,7 +1744,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
int handled;
dev->stats.irqs++;
- HEX_DISPLAY(dev->stats.irqs);
do {
u32 udccr = UDCCR;
@@ -2125,7 +1794,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
} else {
DBG(DBG_VERBOSE, "USB reset end\n");
dev->gadget.speed = USB_SPEED_FULL;
- LED_CONNECTED_ON;
memset(&dev->stats, 0, sizeof dev->stats);
/* driver and endpoints are still reset */
}
@@ -2217,7 +1885,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS1,
.reg_uddr = &UDDR1,
- drcmr (25)
},
.ep[2] = {
.ep = {
@@ -2232,7 +1899,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS2,
.reg_ubcr = &UBCR2,
.reg_uddr = &UDDR2,
- drcmr (26)
},
#ifndef CONFIG_USB_PXA2XX_SMALL
.ep[3] = {
@@ -2247,7 +1913,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS3,
.reg_uddr = &UDDR3,
- drcmr (27)
},
.ep[4] = {
.ep = {
@@ -2262,7 +1927,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS4,
.reg_ubcr = &UBCR4,
.reg_uddr = &UDDR4,
- drcmr (28)
},
.ep[5] = {
.ep = {
@@ -2291,7 +1955,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS6,
.reg_uddr = &UDDR6,
- drcmr (30)
},
.ep[7] = {
.ep = {
@@ -2306,7 +1969,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS7,
.reg_ubcr = &UBCR7,
.reg_uddr = &UDDR7,
- drcmr (31)
},
.ep[8] = {
.ep = {
@@ -2320,7 +1982,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS8,
.reg_uddr = &UDDR8,
- drcmr (32)
},
.ep[9] = {
.ep = {
@@ -2335,7 +1996,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS9,
.reg_ubcr = &UBCR9,
.reg_uddr = &UDDR9,
- drcmr (33)
},
.ep[10] = {
.ep = {
@@ -2364,7 +2024,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS11,
.reg_uddr = &UDDR11,
- drcmr (35)
},
.ep[12] = {
.ep = {
@@ -2379,7 +2038,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS12,
.reg_ubcr = &UBCR12,
.reg_uddr = &UDDR12,
- drcmr (36)
},
.ep[13] = {
.ep = {
@@ -2393,7 +2051,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS13,
.reg_uddr = &UDDR13,
- drcmr (37)
},
.ep[14] = {
.ep = {
@@ -2408,7 +2065,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS14,
.reg_ubcr = &UBCR14,
.reg_uddr = &UDDR14,
- drcmr (38)
},
.ep[15] = {
.ep = {
@@ -2466,7 +2122,7 @@ static struct pxa2xx_udc memory = {
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = &memory;
- int retval, out_dma = 1, vbus_irq, irq;
+ int retval, vbus_irq, irq;
u32 chiprev;
/* insist on Intel/ARM/XScale */
@@ -2489,7 +2145,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
case PXA250_B2: case PXA210_B2:
case PXA250_B1: case PXA210_B1:
case PXA250_B0: case PXA210_B0:
- out_dma = 0;
+ /* OUT-DMA is broken ... */
/* fall through */
case PXA250_C0: case PXA210_C0:
break;
@@ -2498,11 +2154,9 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
case IXP425_B0:
case IXP465_AD:
dev->has_cfr = 1;
- out_dma = 0;
break;
#endif
default:
- out_dma = 0;
printk(KERN_ERR "%s: unrecognized processor: %08x\n",
driver_name, chiprev);
/* iop3xx, ixp4xx, ... */
@@ -2513,36 +2167,41 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (irq < 0)
return -ENODEV;
- pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq,
+ pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
dev->has_cfr ? "" : " (!cfr)",
- out_dma ? "" : " (broken dma-out)",
- SIZE_STR DMASTR
+ SIZE_STR "(pio)"
);
-#ifdef USE_DMA
-#ifndef USE_OUT_DMA
- out_dma = 0;
-#endif
- /* pxa 250 erratum 130 prevents using OUT dma (fixed C0) */
- if (!out_dma) {
- DMSG("disabled OUT dma\n");
- dev->ep[ 2].reg_drcmr = dev->ep[ 4].reg_drcmr = 0;
- dev->ep[ 7].reg_drcmr = dev->ep[ 9].reg_drcmr = 0;
- dev->ep[12].reg_drcmr = dev->ep[14].reg_drcmr = 0;
- }
-#endif
-
/* other non-static parts of init */
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
+
if (dev->mach->gpio_vbus) {
- udc_gpio_init_vbus(dev->mach->gpio_vbus);
- vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus);
+ if ((retval = gpio_request(dev->mach->gpio_vbus,
+ "pxa2xx_udc GPIO VBUS"))) {
+ dev_dbg(&pdev->dev,
+ "can't get vbus gpio %d, err: %d\n",
+ dev->mach->gpio_vbus, retval);
+ return -EBUSY;
+ }
+ gpio_direction_input(dev->mach->gpio_vbus);
+ vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
set_irq_type(vbus_irq, IRQT_BOTHEDGE);
} else
vbus_irq = 0;
- if (dev->mach->gpio_pullup)
- udc_gpio_init_pullup(dev->mach->gpio_pullup);
+
+ if (dev->mach->gpio_pullup) {
+ if ((retval = gpio_request(dev->mach->gpio_pullup,
+ "pca2xx_udc GPIO PULLUP"))) {
+ dev_dbg(&pdev->dev,
+ "can't get pullup gpio %d, err: %d\n",
+ dev->mach->gpio_pullup, retval);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
+ return -EBUSY;
+ }
+ gpio_direction_output(dev->mach->gpio_pullup, 0);
+ }
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
@@ -2566,6 +2225,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
dev->got_irq = 1;
@@ -2581,6 +2244,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
driver_name, LUBBOCK_USB_DISC_IRQ, retval);
lubbock_fail0:
free_irq(irq, dev);
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
retval = request_irq(LUBBOCK_USB_IRQ,
@@ -2593,11 +2260,6 @@ lubbock_fail0:
free_irq(LUBBOCK_USB_DISC_IRQ, dev);
goto lubbock_fail0;
}
-#ifdef DEBUG
- /* with U-Boot (but not BLOB), hex is off by default */
- HEX_DISPLAY(dev->stats.irqs);
- LUB_DISC_BLNK_LED &= 0xff;
-#endif
} else
#endif
if (vbus_irq) {
@@ -2608,6 +2270,10 @@ lubbock_fail0:
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, vbus_irq, retval);
free_irq(irq, dev);
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+ if (dev->mach->gpio_vbus)
+ gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
}
@@ -2641,8 +2307,13 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
free_irq(LUBBOCK_USB_IRQ, dev);
}
#endif
- if (dev->mach->gpio_vbus)
- free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
+ if (dev->mach->gpio_vbus) {
+ free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
+ gpio_free(dev->mach->gpio_vbus);
+ }
+ if (dev->mach->gpio_pullup)
+ gpio_free(dev->mach->gpio_pullup);
+
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 773e549aff3f..0e5d0e6fb0e2 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -54,8 +54,6 @@ struct pxa2xx_ep {
const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned long pio_irqs;
- unsigned long dma_irqs;
- short dma;
unsigned short fifo_size;
u8 bEndpointAddress;
@@ -63,7 +61,7 @@ struct pxa2xx_ep {
unsigned stopped : 1;
unsigned dma_fixup : 1;
-
+
/* UDCCS = UDC Control/Status for this EP
* UBCR = UDC Byte Count Remaining (contents of OUT fifo)
* UDDR = UDC Endpoint Data Register (the fifo)
@@ -72,12 +70,6 @@ struct pxa2xx_ep {
volatile u32 *reg_udccs;
volatile u32 *reg_ubcr;
volatile u32 *reg_uddr;
-#ifdef USE_DMA
- volatile u32 *reg_drcmr;
-#define drcmr(n) .reg_drcmr = & DRCMR ## n ,
-#else
-#define drcmr(n)
-#endif
};
struct pxa2xx_request {
@@ -85,7 +77,7 @@ struct pxa2xx_request {
struct list_head queue;
};
-enum ep0_state {
+enum ep0_state {
EP0_IDLE,
EP0_IN_DATA_PHASE,
EP0_OUT_DATA_PHASE,
@@ -108,7 +100,6 @@ struct udc_stats {
#ifdef CONFIG_USB_PXA2XX_SMALL
/* when memory's tight, SMALL config saves code+data. */
-#undef USE_DMA
#define PXA_UDC_NUM_ENDPOINTS 3
#endif
@@ -144,37 +135,8 @@ struct pxa2xx_udc {
#ifdef CONFIG_ARCH_LUBBOCK
#include <asm/arch/lubbock.h>
/* lubbock can also report usb connect/disconnect irqs */
-
-#ifdef DEBUG
-#define HEX_DISPLAY(n) if (machine_is_lubbock()) { LUB_HEXLED = (n); }
#endif
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* LEDs are only for debug */
-#ifndef HEX_DISPLAY
-#define HEX_DISPLAY(n) do {} while(0)
-#endif
-
-#ifdef DEBUG
-#include <asm/leds.h>
-
-#define LED_CONNECTED_ON leds_event(led_green_on)
-#define LED_CONNECTED_OFF do { \
- leds_event(led_green_off); \
- HEX_DISPLAY(0); \
- } while(0)
-#endif
-
-#ifndef LED_CONNECTED_ON
-#define LED_CONNECTED_ON do {} while(0)
-#define LED_CONNECTED_OFF do {} while(0)
-#endif
-
-/*-------------------------------------------------------------------------*/
-
static struct pxa2xx_udc *the_controller;
/*-------------------------------------------------------------------------*/
@@ -204,7 +166,7 @@ static const char *state_name[] = {
# define UDC_DEBUG DBG_NORMAL
#endif
-static void __attribute__ ((__unused__))
+static void __maybe_unused
dump_udccr(const char *label)
{
u32 udccr = UDCCR;
@@ -220,7 +182,7 @@ dump_udccr(const char *label)
(udccr & UDCCR_UDE) ? " ude" : "");
}
-static void __attribute__ ((__unused__))
+static void __maybe_unused
dump_udccs0(const char *label)
{
u32 udccs0 = UDCCS0;
@@ -237,7 +199,7 @@ dump_udccs0(const char *label)
(udccs0 & UDCCS0_OPR) ? " opr" : "");
}
-static void __attribute__ ((__unused__))
+static void __maybe_unused
dump_state(struct pxa2xx_udc *dev)
{
u32 tmp;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 708657c89132..db1b2bfcee4e 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -53,7 +53,7 @@
*/
#if 0
-#define DEBUG(str,args...) do { \
+#define DBG(str,args...) do { \
if (rndis_debug) \
printk(KERN_DEBUG str , ## args ); \
} while (0)
@@ -65,7 +65,7 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
#else
#define rndis_debug 0
-#define DEBUG(str,args...) do{}while(0)
+#define DBG(str,args...) do{}while(0)
#endif
#define RNDIS_MAX_CONFIGS 1
@@ -183,9 +183,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
if (!resp) return -ENOMEM;
if (buf_len && rndis_debug > 1) {
- DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
+ DBG("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
- DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+ DBG("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpu(get_unaligned((__le32 *)
&buf[i])),
le32_to_cpu(get_unaligned((__le32 *)
@@ -207,7 +207,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
- DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
+ DBG("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
length = sizeof (oid_supported_list);
count = length / sizeof (u32);
for (i = 0; i < count; i++)
@@ -217,7 +217,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
- DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
/* Bogus question!
* Hardware must be ready to receive high level protocols.
* BTW:
@@ -230,14 +230,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
- DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
- DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
/* one medium, one transport... (maybe you do it better) */
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
@@ -245,7 +245,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MAXIMUM_FRAME_SIZE:
- DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -256,7 +256,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_LINK_SPEED:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
+ DBG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].media_state
== NDIS_MEDIA_STATE_DISCONNECTED)
*outbuf = __constant_cpu_to_le32 (0);
@@ -268,7 +268,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_TRANSMIT_BLOCK_SIZE:
- DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -278,7 +278,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RECEIVE_BLOCK_SIZE:
- DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@@ -288,7 +288,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_ID:
- DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].vendorID);
retval = 0;
@@ -296,7 +296,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_DESCRIPTION:
- DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
memcpy (outbuf,
rndis_per_dev_params [configNr].vendorDescr, length);
@@ -304,7 +304,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
- DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
+ DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
/* Created as LE */
*outbuf = rndis_driver_version;
retval = 0;
@@ -312,14 +312,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
- DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
+ DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
retval = 0;
break;
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
- DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
retval = 0;
break;
@@ -327,14 +327,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)
- DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.media_state);
retval = 0;
break;
case OID_GEN_PHYSICAL_MEDIUM:
- DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
+ DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -344,7 +344,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 */
- DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32(
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
| NDIS_MAC_OPTION_FULL_DUPLEX);
@@ -356,7 +356,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_OK:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+ DBG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->tx_packets -
@@ -369,7 +369,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_OK:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->rx_packets -
@@ -382,7 +382,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_ERROR:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_errors);
@@ -393,7 +393,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_ERROR:
if (rndis_debug > 1)
- DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_errors);
@@ -403,7 +403,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_NO_BUFFER:
- DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_dropped);
@@ -413,7 +413,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
#ifdef RNDIS_OPTIONAL_STATS
case OID_GEN_DIRECTED_BYTES_XMIT:
- DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
/*
* Aunt Tilly's size of shoes
* minus antarctica count of penguins
@@ -433,7 +433,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_FRAMES_XMIT:
- DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
/* dito */
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
@@ -449,7 +449,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
- DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast*1234);
@@ -458,7 +458,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_XMIT:
- DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@@ -467,7 +467,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
- DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42*255);
@@ -476,7 +476,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_XMIT:
- DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42);
@@ -485,19 +485,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_BYTES_RCV:
- DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
- DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
- DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast * 1111);
@@ -506,7 +506,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
- DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@@ -515,7 +515,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_RCV:
- DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42*255);
@@ -524,7 +524,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
- DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
+ DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42);
@@ -533,7 +533,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_RCV_CRC_ERROR:
- DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
+ DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_crc_errors);
@@ -542,7 +542,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
- DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
+ DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -552,7 +552,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_PERMANENT_ADDRESS:
- DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@@ -564,7 +564,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_CURRENT_ADDRESS:
- DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@@ -576,7 +576,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MULTICAST_LIST:
- DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (0xE0000000);
retval = 0;
@@ -584,21 +584,21 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
- DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (1);
retval = 0;
break;
case OID_802_3_MAC_OPTIONS:
- DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
break;
/* ieee802.3 statistics OIDs (table 4-4) */
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
- DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
+ DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_frame_errors);
@@ -608,51 +608,51 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
- DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
- DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
#ifdef RNDIS_OPTIONAL_STATS
case OID_802_3_XMIT_DEFERRED:
- DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_MAX_COLLISIONS:
- DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_RCV_OVERRUN:
- DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
+ DBG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_UNDERRUN:
- DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
- DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_TIMES_CRS_LOST:
- DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_LATE_COLLISIONS:
- DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
+ DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
/* TODO */
break;
#endif /* RNDIS_OPTIONAL_STATS */
@@ -660,7 +660,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:
- DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
+ DBG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
/* for now, no wakeup capabilities */
length = sizeof (struct NDIS_PNP_CAPABILITIES);
@@ -668,7 +668,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
retval = 0;
break;
case OID_PNP_QUERY_POWER:
- DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+ DBG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
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...
@@ -705,9 +705,9 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
return -ENOMEM;
if (buf_len && rndis_debug > 1) {
- DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+ DBG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
- DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+ DBG("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpu(get_unaligned((__le32 *)
&buf[i])),
le32_to_cpu(get_unaligned((__le32 *)
@@ -731,7 +731,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));
- DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
+ DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__FUNCTION__, *params->filter);
/* this call has a significant side effect: it's
@@ -756,7 +756,7 @@ update_linkstate:
case OID_802_3_MULTICAST_LIST:
/* I think we can ignore this */
- DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+ DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
retval = 0;
break;
#if 0
@@ -764,7 +764,7 @@ update_linkstate:
{
struct rndis_config_parameter *param;
param = (struct rndis_config_parameter *) buf;
- DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
+ DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
__FUNCTION__,
min(cpu_to_le32(param->ParameterNameLength),80),
buf + param->ParameterNameOffset);
@@ -781,7 +781,7 @@ update_linkstate:
* FIXME ... then things go batty; Windows wedges itself.
*/
i = le32_to_cpu(get_unaligned((__le32 *)buf));
- DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+ DBG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
switch (i) {
case NdisDeviceStateD0:
*params->filter = params->saved_filter;
@@ -858,7 +858,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
- // DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
+ // DBG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
/*
@@ -911,15 +911,15 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
#ifdef VERBOSE
- DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
- DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
- DEBUG("%s: InfoBuffer: ", __FUNCTION__);
+ DBG("%s: Length: %d\n", __FUNCTION__, BufLength);
+ DBG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
+ DBG("%s: InfoBuffer: ", __FUNCTION__);
for (i = 0; i < BufLength; i++) {
- DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
+ DBG("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
}
- DEBUG ("\n");
+ DBG("\n");
#endif
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
@@ -1082,14 +1082,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
/* For USB: responses may take up to 10 seconds */
switch (MsgType) {
case REMOTE_NDIS_INITIALIZE_MSG:
- DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
+ DBG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
__FUNCTION__ );
params->state = RNDIS_INITIALIZED;
return rndis_init_response (configNr,
(rndis_init_msg_type *) buf);
case REMOTE_NDIS_HALT_MSG:
- DEBUG("%s: REMOTE_NDIS_HALT_MSG\n",
+ DBG("%s: REMOTE_NDIS_HALT_MSG\n",
__FUNCTION__ );
params->state = RNDIS_UNINITIALIZED;
if (params->dev) {
@@ -1107,7 +1107,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
(rndis_set_msg_type *) buf);
case REMOTE_NDIS_RESET_MSG:
- DEBUG("%s: REMOTE_NDIS_RESET_MSG\n",
+ DBG("%s: REMOTE_NDIS_RESET_MSG\n",
__FUNCTION__ );
return rndis_reset_response (configNr,
(rndis_reset_msg_type *) buf);
@@ -1115,7 +1115,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
case REMOTE_NDIS_KEEPALIVE_MSG:
/* For USB: host does this every 5 seconds */
if (rndis_debug > 1)
- DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
+ DBG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
__FUNCTION__ );
return rndis_keepalive_response (configNr,
(rndis_keepalive_msg_type *)
@@ -1132,7 +1132,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
{
unsigned i;
for (i = 0; i < MsgLength; i += 16) {
- DEBUG ("%03d: "
+ DBG("%03d: "
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
@@ -1163,18 +1163,18 @@ 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;
- DEBUG("%s: configNr = %d\n", __FUNCTION__, i);
+ DBG("%s: configNr = %d\n", __FUNCTION__, i);
return i;
}
}
- DEBUG("failed\n");
+ DBG("failed\n");
return -1;
}
void rndis_deregister (int configNr)
{
- DEBUG("%s: \n", __FUNCTION__ );
+ DBG("%s: \n", __FUNCTION__ );
if (configNr >= RNDIS_MAX_CONFIGS) return;
rndis_per_dev_params [configNr].used = 0;
@@ -1186,7 +1186,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
struct net_device_stats *stats,
u16 *cdc_filter)
{
- DEBUG("%s:\n", __FUNCTION__ );
+ DBG("%s:\n", __FUNCTION__ );
if (!dev || !stats) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@@ -1199,7 +1199,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
{
- DEBUG("%s:\n", __FUNCTION__ );
+ DBG("%s:\n", __FUNCTION__ );
if (!vendorDescr) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@@ -1211,7 +1211,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
{
- DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
+ DBG("%s: %u %u\n", __FUNCTION__, medium, speed);
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
rndis_per_dev_params [configNr].medium = medium;
@@ -1390,7 +1390,7 @@ static int rndis_proc_write (struct file *file, const char __user *buffer,
break;
default:
if (fl_speed) p->speed = speed;
- else DEBUG ("%c is not valid\n", c);
+ else DBG("%c is not valid\n", c);
break;
}
@@ -1419,12 +1419,12 @@ int __devinit rndis_init (void)
if (!(rndis_connect_state [i]
= create_proc_entry (name, 0660, NULL)))
{
- DEBUG ("%s :remove entries", __FUNCTION__);
+ DBG("%s :remove entries", __FUNCTION__);
while (i) {
sprintf (name, NAME_TEMPLATE, --i);
remove_proc_entry (name, NULL);
}
- DEBUG ("\n");
+ DBG("\n");
return -EIO;
}
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
new file mode 100644
index 000000000000..0be80c635c48
--- /dev/null
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -0,0 +1,2045 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.c
+ *
+ * Samsung S3C24xx series on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard
+ * Additional cleanups by Ben Dooks <ben-linux@fluff.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/clk.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <linux/usb.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-udc.h>
+#include <asm/arch/udc.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c2410_udc.h"
+
+#define DRIVER_DESC "S3C2410 USB Device Controller Gadget"
+#define DRIVER_VERSION "29 Apr 2007"
+#define DRIVER_AUTHOR "Herbert Pötzl <herbert@13thfloor.at>, " \
+ "Arnaud Patard <arnaud.patard@rtp-net.org>"
+
+static const char gadget_name[] = "s3c2410_udc";
+static const char driver_desc[] = DRIVER_DESC;
+
+static struct s3c2410_udc *the_controller;
+static struct clk *udc_clock;
+static struct clk *usb_bus_clock;
+static void __iomem *base_addr;
+static u64 rsrc_start;
+static u64 rsrc_len;
+static struct dentry *s3c2410_udc_debugfs_root;
+
+static inline u32 udc_read(u32 reg)
+{
+ return readb(base_addr + reg);
+}
+
+static inline void udc_write(u32 value, u32 reg)
+{
+ writeb(value, base_addr + reg);
+}
+
+static inline void udc_writeb(void __iomem *base, u32 value, u32 reg)
+{
+ writeb(value, base + reg);
+}
+
+static struct s3c2410_udc_mach_info *udc_info;
+
+/*************************** DEBUG FUNCTION ***************************/
+#define DEBUG_NORMAL 1
+#define DEBUG_VERBOSE 2
+
+#ifdef CONFIG_USB_S3C2410_DEBUG
+#define USB_S3C2410_DEBUG_LEVEL 0
+
+static uint32_t s3c2410_ticks = 0;
+
+static int dprintk(int level, const char *fmt, ...)
+{
+ static char printk_buf[1024];
+ static long prevticks;
+ static int invocation;
+ va_list args;
+ int len;
+
+ if (level > USB_S3C2410_DEBUG_LEVEL)
+ return 0;
+
+ if (s3c2410_ticks != prevticks) {
+ prevticks = s3c2410_ticks;
+ invocation = 0;
+ }
+
+ len = scnprintf(printk_buf,
+ sizeof(printk_buf), "%1lu.%02d USB: ",
+ prevticks, invocation++);
+
+ va_start(args, fmt);
+ len = vscnprintf(printk_buf+len,
+ sizeof(printk_buf)-len, fmt, args);
+ va_end(args);
+
+ return printk(KERN_DEBUG "%s", printk_buf);
+}
+#else
+static int dprintk(int level, const char *fmt, ...)
+{
+ return 0;
+}
+#endif
+static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
+{
+ u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+ u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
+ u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2;
+ u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2;
+
+ addr_reg = udc_read(S3C2410_UDC_FUNC_ADDR_REG);
+ pwr_reg = udc_read(S3C2410_UDC_PWR_REG);
+ ep_int_reg = udc_read(S3C2410_UDC_EP_INT_REG);
+ usb_int_reg = udc_read(S3C2410_UDC_USB_INT_REG);
+ ep_int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+ usb_int_en_reg = udc_read(S3C2410_UDC_USB_INT_EN_REG);
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ ep0_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ udc_write(1, S3C2410_UDC_INDEX_REG);
+ ep1_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep1_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+ ep1_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep1_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+ udc_write(2, S3C2410_UDC_INDEX_REG);
+ ep2_i_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep2_i_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+ ep2_o_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ ep2_o_csr2 = udc_read(S3C2410_UDC_IN_CSR2_REG);
+
+ seq_printf(m, "FUNC_ADDR_REG : 0x%04X\n"
+ "PWR_REG : 0x%04X\n"
+ "EP_INT_REG : 0x%04X\n"
+ "USB_INT_REG : 0x%04X\n"
+ "EP_INT_EN_REG : 0x%04X\n"
+ "USB_INT_EN_REG : 0x%04X\n"
+ "EP0_CSR : 0x%04X\n"
+ "EP1_I_CSR1 : 0x%04X\n"
+ "EP1_I_CSR2 : 0x%04X\n"
+ "EP1_O_CSR1 : 0x%04X\n"
+ "EP1_O_CSR2 : 0x%04X\n"
+ "EP2_I_CSR1 : 0x%04X\n"
+ "EP2_I_CSR2 : 0x%04X\n"
+ "EP2_O_CSR1 : 0x%04X\n"
+ "EP2_O_CSR2 : 0x%04X\n",
+ addr_reg,pwr_reg,ep_int_reg,usb_int_reg,
+ ep_int_en_reg, usb_int_en_reg, ep0_csr,
+ ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2,
+ ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2
+ );
+
+ return 0;
+}
+
+static int s3c2410_udc_debugfs_fops_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, s3c2410_udc_debugfs_seq_show, NULL);
+}
+
+static const struct file_operations s3c2410_udc_debugfs_fops = {
+ .open = s3c2410_udc_debugfs_fops_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+/* io macros */
+
+static inline void s3c2410_udc_clear_ep0_opr(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_SOPKTRDY,
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_clear_ep0_sst(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ writeb(0x00, base + S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_clear_ep0_se(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_SSE, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_ipr(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_IPKRDY, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG);
+}
+
+inline void s3c2410_udc_set_ep0_ss(void __iomem *b)
+{
+ udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+
+ udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY
+ | S3C2410_UDC_EP0_CSR_DE),
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
+ | S3C2410_UDC_EP0_CSR_SSE),
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
+{
+ udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ udc_writeb(base, (S3C2410_UDC_EP0_CSR_IPKRDY
+ | S3C2410_UDC_EP0_CSR_DE),
+ S3C2410_UDC_EP0_CSR_REG);
+}
+
+/*------------------------- I/O ----------------------------------*/
+
+/*
+ * s3c2410_udc_done
+ */
+static void s3c2410_udc_done(struct s3c2410_ep *ep,
+ struct s3c2410_request *req, int status)
+{
+ unsigned halted = ep->halted;
+
+ list_del_init(&req->queue);
+
+ if (likely (req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ ep->halted = 1;
+ req->req.complete(&ep->ep, &req->req);
+ ep->halted = halted;
+}
+
+static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
+ struct s3c2410_ep *ep, int status)
+{
+ /* Sanity check */
+ if (&ep->queue == NULL)
+ return;
+
+ while (!list_empty (&ep->queue)) {
+ struct s3c2410_request *req;
+ req = list_entry (ep->queue.next, struct s3c2410_request,
+ queue);
+ s3c2410_udc_done(ep, req, status);
+ }
+}
+
+static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
+{
+ unsigned i;
+
+ /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
+ * fifos, and pending transactions mustn't be continued in any case.
+ */
+
+ for (i = 1; i < S3C2410_ENDPOINTS; i++)
+ s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
+}
+
+static inline int s3c2410_udc_fifo_count_out(void)
+{
+ int tmp;
+
+ tmp = udc_read(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;
+ tmp |= udc_read(S3C2410_UDC_OUT_FIFO_CNT1_REG);
+ return tmp;
+}
+
+/*
+ * s3c2410_udc_write_packet
+ */
+static inline int s3c2410_udc_write_packet(int fifo,
+ struct s3c2410_request *req,
+ unsigned max)
+{
+ unsigned len = min(req->req.length - req->req.actual, max);
+ u8 *buf = req->req.buf + req->req.actual;
+
+ prefetch(buf);
+
+ dprintk(DEBUG_VERBOSE, "%s %d %d %d %d\n", __func__,
+ req->req.actual, req->req.length, len, req->req.actual + len);
+
+ req->req.actual += len;
+
+ udelay(5);
+ writesb(base_addr + fifo, buf, len);
+ return len;
+}
+
+/*
+ * s3c2410_udc_write_fifo
+ *
+ * return: 0 = still running, 1 = completed, negative = errno
+ */
+static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep,
+ struct s3c2410_request *req)
+{
+ unsigned count;
+ int is_last;
+ u32 idx;
+ int fifo_reg;
+ u32 ep_csr;
+
+ idx = ep->bEndpointAddress & 0x7F;
+ switch (idx) {
+ default:
+ idx = 0;
+ case 0:
+ fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+ break;
+ case 1:
+ fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+ break;
+ case 2:
+ fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+ break;
+ case 3:
+ fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+ break;
+ case 4:
+ fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+ break;
+ }
+
+ count = s3c2410_udc_write_packet(fifo_reg, req, ep->ep.maxpacket);
+
+ /* last packet is often short (sometimes a zlp) */
+ if (count != ep->ep.maxpacket)
+ is_last = 1;
+ else if (req->req.length != req->req.actual || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 2;
+
+ /* Only ep0 debug messages are interesting */
+ if (idx == 0)
+ dprintk(DEBUG_NORMAL,
+ "Written ep%d %d.%d of %d b [last %d,z %d]\n",
+ idx, count, req->req.actual, req->req.length,
+ is_last, req->req.zero);
+
+ if (is_last) {
+ /* The order is important. It prevents sending 2 packets
+ * at the same time */
+
+ if (idx == 0) {
+ /* Reset signal => no need to say 'data sent' */
+ if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+ & S3C2410_UDC_USBINT_RESET))
+ s3c2410_udc_set_ep0_de_in(base_addr);
+ ep->dev->ep0state=EP0_IDLE;
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY,
+ S3C2410_UDC_IN_CSR1_REG);
+ }
+
+ s3c2410_udc_done(ep, req, 0);
+ is_last = 1;
+ } else {
+ if (idx == 0) {
+ /* Reset signal => no need to say 'data sent' */
+ if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+ & S3C2410_UDC_USBINT_RESET))
+ s3c2410_udc_set_ep0_ipr(base_addr);
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY,
+ S3C2410_UDC_IN_CSR1_REG);
+ }
+ }
+
+ return is_last;
+}
+
+static inline int s3c2410_udc_read_packet(int fifo, u8 *buf,
+ struct s3c2410_request *req, unsigned avail)
+{
+ unsigned len;
+
+ len = min(req->req.length - req->req.actual, avail);
+ req->req.actual += len;
+
+ readsb(fifo + base_addr, buf, len);
+ return len;
+}
+
+/*
+ * return: 0 = still running, 1 = queue empty, negative = errno
+ */
+static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep,
+ struct s3c2410_request *req)
+{
+ u8 *buf;
+ u32 ep_csr;
+ unsigned bufferspace;
+ int is_last=1;
+ unsigned avail;
+ int fifo_count = 0;
+ u32 idx;
+ int fifo_reg;
+
+ idx = ep->bEndpointAddress & 0x7F;
+
+ switch (idx) {
+ default:
+ idx = 0;
+ case 0:
+ fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+ break;
+ case 1:
+ fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+ break;
+ case 2:
+ fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+ break;
+ case 3:
+ fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+ break;
+ case 4:
+ fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+ break;
+ }
+
+ if (!req->req.length)
+ return 1;
+
+ buf = req->req.buf + req->req.actual;
+ bufferspace = req->req.length - req->req.actual;
+ if (!bufferspace) {
+ dprintk(DEBUG_NORMAL, "%s: buffer full!\n", __func__);
+ return -1;
+ }
+
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+
+ fifo_count = s3c2410_udc_fifo_count_out();
+ dprintk(DEBUG_NORMAL, "%s fifo count : %d\n", __func__, fifo_count);
+
+ if (fifo_count > ep->ep.maxpacket)
+ avail = ep->ep.maxpacket;
+ else
+ avail = fifo_count;
+
+ fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail);
+
+ /* checking this with ep0 is not accurate as we already
+ * read a control request
+ **/
+ if (idx != 0 && fifo_count < ep->ep.maxpacket) {
+ is_last = 1;
+ /* overflowed this request? flush extra data */
+ if (fifo_count != avail)
+ req->req.status = -EOVERFLOW;
+ } else {
+ is_last = (req->req.length <= req->req.actual) ? 1 : 0;
+ }
+
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ fifo_count = s3c2410_udc_fifo_count_out();
+
+ /* Only ep0 debug messages are interesting */
+ if (idx == 0)
+ dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n",
+ __func__, fifo_count,is_last);
+
+ if (is_last) {
+ if (idx == 0) {
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ ep->dev->ep0state = EP0_IDLE;
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,
+ S3C2410_UDC_OUT_CSR1_REG);
+ }
+
+ s3c2410_udc_done(ep, req, 0);
+ } else {
+ if (idx == 0) {
+ s3c2410_udc_clear_ep0_opr(base_addr);
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,
+ S3C2410_UDC_OUT_CSR1_REG);
+ }
+ }
+
+ return is_last;
+}
+
+static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq)
+{
+ unsigned char *outbuf = (unsigned char*)crq;
+ int bytes_read = 0;
+
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+
+ bytes_read = s3c2410_udc_fifo_count_out();
+
+ dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read);
+
+ if (bytes_read > sizeof(struct usb_ctrlrequest))
+ bytes_read = sizeof(struct usb_ctrlrequest);
+
+ readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read);
+
+ dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__,
+ bytes_read, crq->bRequest, crq->bRequestType,
+ crq->wValue, crq->wIndex, crq->wLength);
+
+ return bytes_read;
+}
+
+static int s3c2410_udc_get_status(struct s3c2410_udc *dev,
+ struct usb_ctrlrequest *crq)
+{
+ u16 status = 0;
+ u8 ep_num = crq->wIndex & 0x7F;
+ u8 is_in = crq->wIndex & USB_DIR_IN;
+
+ switch (crq->bRequestType & USB_RECIP_MASK) {
+ case USB_RECIP_INTERFACE:
+ break;
+
+ case USB_RECIP_DEVICE:
+ status = dev->devstatus;
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ if (ep_num > 4 || crq->wLength > 2)
+ return 1;
+
+ if (ep_num == 0) {
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ status = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ status = status & S3C2410_UDC_EP0_CSR_SENDSTL;
+ } else {
+ udc_write(ep_num, S3C2410_UDC_INDEX_REG);
+ if (is_in) {
+ status = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ status = status & S3C2410_UDC_ICSR1_SENDSTL;
+ } else {
+ status = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ status = status & S3C2410_UDC_OCSR1_SENDSTL;
+ }
+ }
+
+ status = status ? 1 : 0;
+ break;
+
+ default:
+ return 1;
+ }
+
+ /* Seems to be needed to get it working. ouch :( */
+ udelay(5);
+ udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG);
+ udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG);
+ s3c2410_udc_set_ep0_de_in(base_addr);
+
+ return 0;
+}
+/*------------------------- usb state machine -------------------------------*/
+static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value);
+
+static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
+ struct s3c2410_ep *ep,
+ struct usb_ctrlrequest *crq,
+ u32 ep0csr)
+{
+ int len, ret, tmp;
+
+ /* start control request? */
+ if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))
+ return;
+
+ s3c2410_udc_nuke(dev, ep, -EPROTO);
+
+ len = s3c2410_udc_read_fifo_crq(crq);
+ if (len != sizeof(*crq)) {
+ dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"
+ " wanted %d bytes got %d. Stalling out...\n",
+ sizeof(*crq), len);
+ s3c2410_udc_set_ep0_ss(base_addr);
+ return;
+ }
+
+ dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n",
+ crq->bRequest, crq->bRequestType, crq->wLength);
+
+ /* cope with automagic for some standard requests. */
+ dev->req_std = (crq->bRequestType & USB_TYPE_MASK)
+ == USB_TYPE_STANDARD;
+ dev->req_config = 0;
+ dev->req_pending = 1;
+
+ switch (crq->bRequest) {
+ case USB_REQ_SET_CONFIGURATION:
+ dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
+
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ dev->req_config = 1;
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ }
+ break;
+
+ case USB_REQ_SET_INTERFACE:
+ dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
+
+ if (crq->bRequestType == USB_RECIP_INTERFACE) {
+ dev->req_config = 1;
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ }
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
+
+ if (crq->bRequestType == USB_RECIP_DEVICE) {
+ tmp = crq->wValue & 0x7F;
+ dev->address = tmp;
+ udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE),
+ S3C2410_UDC_FUNC_ADDR_REG);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ return;
+ }
+ break;
+
+ case USB_REQ_GET_STATUS:
+ dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
+ s3c2410_udc_clear_ep0_opr(base_addr);
+
+ if (dev->req_std) {
+ if (!s3c2410_udc_get_status(dev, crq)) {
+ return;
+ }
+ }
+ break;
+
+ case USB_REQ_CLEAR_FEATURE:
+ s3c2410_udc_clear_ep0_opr(base_addr);
+
+ if (crq->bRequestType != USB_RECIP_ENDPOINT)
+ break;
+
+ if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
+ break;
+
+ s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ return;
+
+ case USB_REQ_SET_FEATURE:
+ s3c2410_udc_clear_ep0_opr(base_addr);
+
+ if (crq->bRequestType != USB_RECIP_ENDPOINT)
+ break;
+
+ if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
+ break;
+
+ s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ return;
+
+ default:
+ s3c2410_udc_clear_ep0_opr(base_addr);
+ break;
+ }
+
+ if (crq->bRequestType & USB_DIR_IN)
+ dev->ep0state = EP0_IN_DATA_PHASE;
+ else
+ dev->ep0state = EP0_OUT_DATA_PHASE;
+
+ ret = dev->driver->setup(&dev->gadget, crq);
+ if (ret < 0) {
+ if (dev->req_config) {
+ dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n",
+ crq->bRequest, ret);
+ return;
+ }
+
+ if (ret == -EOPNOTSUPP)
+ dprintk(DEBUG_NORMAL, "Operation not supported\n");
+ else
+ dprintk(DEBUG_NORMAL,
+ "dev->driver->setup failed. (%d)\n", ret);
+
+ udelay(5);
+ s3c2410_udc_set_ep0_ss(base_addr);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ dev->ep0state = EP0_IDLE;
+ /* deferred i/o == no response yet */
+ } else if (dev->req_pending) {
+ dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");
+ dev->req_pending=0;
+ }
+
+ dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]);
+}
+
+static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev)
+{
+ u32 ep0csr;
+ struct s3c2410_ep *ep = &dev->ep[0];
+ struct s3c2410_request *req;
+ struct usb_ctrlrequest crq;
+
+ if (list_empty(&ep->queue))
+ req = NULL;
+ else
+ req = list_entry(ep->queue.next, struct s3c2410_request, queue);
+
+ /* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to
+ * S3C2410_UDC_EP0_CSR_REG when index is zero */
+
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+
+ dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n",
+ ep0csr, ep0states[dev->ep0state]);
+
+ /* clear stall status */
+ if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
+ s3c2410_udc_nuke(dev, ep, -EPIPE);
+ dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
+ s3c2410_udc_clear_ep0_sst(base_addr);
+ dev->ep0state = EP0_IDLE;
+ return;
+ }
+
+ /* clear setup end */
+ if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {
+ dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");
+ s3c2410_udc_nuke(dev, ep, 0);
+ s3c2410_udc_clear_ep0_se(base_addr);
+ dev->ep0state = EP0_IDLE;
+ }
+
+ switch (dev->ep0state) {
+ case EP0_IDLE:
+ s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
+ break;
+
+ case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */
+ dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
+ if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {
+ s3c2410_udc_write_fifo(ep, req);
+ }
+ break;
+
+ case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */
+ dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
+ if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {
+ s3c2410_udc_read_fifo(ep,req);
+ }
+ break;
+
+ case EP0_END_XFER:
+ dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n");
+ dev->ep0state = EP0_IDLE;
+ break;
+
+ case EP0_STALL:
+ dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n");
+ dev->ep0state = EP0_IDLE;
+ break;
+ }
+}
+
+/*
+ * handle_ep - Manage I/O endpoints
+ */
+
+static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+{
+ struct s3c2410_request *req;
+ int is_in = ep->bEndpointAddress & USB_DIR_IN;
+ u32 ep_csr1;
+ u32 idx;
+
+ if (likely (!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct s3c2410_request, queue);
+ else
+ req = NULL;
+
+ idx = ep->bEndpointAddress & 0x7F;
+
+ if (is_in) {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n",
+ idx, ep_csr1, req ? 1 : 0);
+
+ if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) {
+ dprintk(DEBUG_VERBOSE, "st\n");
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL,
+ S3C2410_UDC_IN_CSR1_REG);
+ return;
+ }
+
+ if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) {
+ s3c2410_udc_write_fifo(ep,req);
+ }
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+ dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1);
+
+ if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL,
+ S3C2410_UDC_OUT_CSR1_REG);
+ return;
+ }
+
+ if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
+ s3c2410_udc_read_fifo(ep,req);
+ }
+ }
+}
+
+#include <asm/arch/regs-irq.h>
+
+/*
+ * s3c2410_udc_irq - interrupt handler
+ */
+static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
+{
+ struct s3c2410_udc *dev = _dev;
+ int usb_status;
+ int usbd_status;
+ int pwr_reg;
+ int ep0csr;
+ int i;
+ u32 idx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ /* Driver connected ? */
+ if (!dev->driver) {
+ /* Clear interrupts */
+ udc_write(udc_read(S3C2410_UDC_USB_INT_REG),
+ S3C2410_UDC_USB_INT_REG);
+ udc_write(udc_read(S3C2410_UDC_EP_INT_REG),
+ S3C2410_UDC_EP_INT_REG);
+ }
+
+ /* Save index */
+ idx = udc_read(S3C2410_UDC_INDEX_REG);
+
+ /* Read status registers */
+ usb_status = udc_read(S3C2410_UDC_USB_INT_REG);
+ usbd_status = udc_read(S3C2410_UDC_EP_INT_REG);
+ pwr_reg = udc_read(S3C2410_UDC_PWR_REG);
+
+ udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+ ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+
+ dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n",
+ usb_status, usbd_status, pwr_reg, ep0csr);
+
+ /*
+ * Now, handle interrupts. There's two types :
+ * - Reset, Resume, Suspend coming -> usb_int_reg
+ * - EP -> ep_int_reg
+ */
+
+ /* RESET */
+ if (usb_status & S3C2410_UDC_USBINT_RESET) {
+ /* two kind of reset :
+ * - reset start -> pwr reg = 8
+ * - reset end -> pwr reg = 0
+ **/
+ dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",
+ ep0csr, pwr_reg);
+
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+ udc_write(0x00, S3C2410_UDC_INDEX_REG);
+ udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3,
+ S3C2410_UDC_MAXP_REG);
+ dev->address = 0;
+
+ dev->ep0state = EP0_IDLE;
+ dev->gadget.speed = USB_SPEED_FULL;
+
+ /* clear interrupt */
+ udc_write(S3C2410_UDC_USBINT_RESET,
+ S3C2410_UDC_USB_INT_REG);
+
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ spin_unlock_irqrestore(&dev->lock, flags);
+ return IRQ_HANDLED;
+ }
+
+ /* RESUME */
+ if (usb_status & S3C2410_UDC_USBINT_RESUME) {
+ dprintk(DEBUG_NORMAL, "USB resume\n");
+
+ /* clear interrupt */
+ udc_write(S3C2410_UDC_USBINT_RESUME,
+ S3C2410_UDC_USB_INT_REG);
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver
+ && dev->driver->resume)
+ dev->driver->resume(&dev->gadget);
+ }
+
+ /* SUSPEND */
+ if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
+ dprintk(DEBUG_NORMAL, "USB suspend\n");
+
+ /* clear interrupt */
+ udc_write(S3C2410_UDC_USBINT_SUSPEND,
+ S3C2410_UDC_USB_INT_REG);
+
+ if (dev->gadget.speed != USB_SPEED_UNKNOWN
+ && dev->driver
+ && dev->driver->suspend)
+ dev->driver->suspend(&dev->gadget);
+
+ dev->ep0state = EP0_IDLE;
+ }
+
+ /* EP */
+ /* control traffic */
+ /* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready
+ * generate an interrupt
+ */
+ if (usbd_status & S3C2410_UDC_INT_EP0) {
+ dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");
+ /* Clear the interrupt bit by setting it to 1 */
+ udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
+ s3c2410_udc_handle_ep0(dev);
+ }
+
+ /* endpoint data transfers */
+ for (i = 1; i < S3C2410_ENDPOINTS; i++) {
+ u32 tmp = 1 << i;
+ if (usbd_status & tmp) {
+ dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);
+
+ /* Clear the interrupt bit by setting it to 1 */
+ udc_write(tmp, S3C2410_UDC_EP_INT_REG);
+ s3c2410_udc_handle_ep(&dev->ep[i]);
+ }
+ }
+
+ dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq);
+
+ /* Restore old index */
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return IRQ_HANDLED;
+}
+/*------------------------- s3c2410_ep_ops ----------------------------------*/
+
+static inline struct s3c2410_ep *to_s3c2410_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct s3c2410_ep, ep);
+}
+
+static inline struct s3c2410_udc *to_s3c2410_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct s3c2410_udc, gadget);
+}
+
+static inline struct s3c2410_request *to_s3c2410_req(struct usb_request *req)
+{
+ return container_of(req, struct s3c2410_request, req);
+}
+
+/*
+ * s3c2410_udc_ep_enable
+ */
+static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct s3c2410_udc *dev;
+ struct s3c2410_ep *ep;
+ u32 max, tmp;
+ unsigned long flags;
+ u32 csr1,csr2;
+ u32 int_en_reg;
+
+ ep = to_s3c2410_ep(_ep);
+
+ if (!_ep || !desc || ep->desc
+ || _ep->name == ep0name
+ || desc->bDescriptorType != USB_DT_ENDPOINT)
+ return -EINVAL;
+
+ dev = ep->dev;
+ if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+
+ local_irq_save (flags);
+ _ep->maxpacket = max & 0x7ff;
+ ep->desc = desc;
+ ep->halted = 0;
+ ep->bEndpointAddress = desc->bEndpointAddress;
+
+ /* set max packet */
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(max >> 3, S3C2410_UDC_MAXP_REG);
+
+ /* set type, direction, address; reset fifo counters */
+ if (desc->bEndpointAddress & USB_DIR_IN) {
+ csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT;
+ csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN;
+
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);
+ } else {
+ /* don't flush in fifo or it will cause endpoint interrupt */
+ csr1 = S3C2410_UDC_ICSR1_CLRDT;
+ csr2 = S3C2410_UDC_ICSR2_DMAIEN;
+
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);
+
+ csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT;
+ csr2 = S3C2410_UDC_OCSR2_DMAIEN;
+
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr1, S3C2410_UDC_OUT_CSR1_REG);
+ udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+ udc_write(csr2, S3C2410_UDC_OUT_CSR2_REG);
+ }
+
+ /* enable irqs */
+ int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+ udc_write(int_en_reg | (1 << ep->num), S3C2410_UDC_EP_INT_EN_REG);
+
+ /* print some debug message */
+ tmp = desc->bEndpointAddress;
+ dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
+ _ep->name,ep->num, tmp,
+ desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);
+
+ local_irq_restore (flags);
+ s3c2410_udc_set_halt(_ep, 0);
+
+ return 0;
+}
+
+/*
+ * s3c2410_udc_ep_disable
+ */
+static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ unsigned long flags;
+ u32 int_en_reg;
+
+ if (!_ep || !ep->desc) {
+ dprintk(DEBUG_NORMAL, "%s not enabled\n",
+ _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ local_irq_save(flags);
+
+ dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
+
+ ep->desc = NULL;
+ ep->halted = 1;
+
+ s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
+
+ /* disable irqs */
+ int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+ udc_write(int_en_reg & ~(1<<ep->num), S3C2410_UDC_EP_INT_EN_REG);
+
+ local_irq_restore(flags);
+
+ dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name);
+
+ return 0;
+}
+
+/*
+ * s3c2410_udc_alloc_request
+ */
+static struct usb_request *
+s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags)
+{
+ struct s3c2410_request *req;
+
+ dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags);
+
+ if (!_ep)
+ return NULL;
+
+ req = kzalloc (sizeof(struct s3c2410_request), mem_flags);
+ if (!req)
+ return NULL;
+
+ INIT_LIST_HEAD (&req->queue);
+ return &req->req;
+}
+
+/*
+ * s3c2410_udc_free_request
+ */
+static void
+s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ struct s3c2410_request *req = to_s3c2410_req(_req);
+
+ dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
+
+ if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+ return;
+
+ WARN_ON (!list_empty (&req->queue));
+ kfree(req);
+}
+
+/*
+ * s3c2410_udc_queue
+ */
+static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct s3c2410_request *req = to_s3c2410_req(_req);
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ struct s3c2410_udc *dev;
+ u32 ep_csr = 0;
+ int fifo_count = 0;
+ unsigned long flags;
+
+ if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);
+ return -EINVAL;
+ }
+
+ dev = ep->dev;
+ if (unlikely (!dev->driver
+ || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+ return -ESHUTDOWN;
+ }
+
+ local_irq_save (flags);
+
+ if (unlikely(!_req || !_req->complete
+ || !_req->buf || !list_empty(&req->queue))) {
+ if (!_req)
+ dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__);
+ else {
+ dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n",
+ __func__, !_req->complete,!_req->buf,
+ !list_empty(&req->queue));
+ }
+
+ local_irq_restore(flags);
+ return -EINVAL;
+ }
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n",
+ __func__, ep->bEndpointAddress, _req->length);
+
+ if (ep->bEndpointAddress) {
+ udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG);
+
+ ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)
+ ? S3C2410_UDC_IN_CSR1_REG
+ : S3C2410_UDC_OUT_CSR1_REG);
+ fifo_count = s3c2410_udc_fifo_count_out();
+ } else {
+ udc_write(0, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+ fifo_count = s3c2410_udc_fifo_count_out();
+ }
+
+ /* kickstart this i/o queue? */
+ if (list_empty(&ep->queue) && !ep->halted) {
+ if (ep->bEndpointAddress == 0 /* ep0 */) {
+ switch (dev->ep0state) {
+ case EP0_IN_DATA_PHASE:
+ if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY)
+ && s3c2410_udc_write_fifo(ep,
+ req)) {
+ dev->ep0state = EP0_IDLE;
+ req = NULL;
+ }
+ break;
+
+ case EP0_OUT_DATA_PHASE:
+ if ((!_req->length)
+ || ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
+ && s3c2410_udc_read_fifo(ep,
+ req))) {
+ dev->ep0state = EP0_IDLE;
+ req = NULL;
+ }
+ break;
+
+ default:
+ local_irq_restore(flags);
+ return -EL2HLT;
+ }
+ } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
+ && (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY))
+ && s3c2410_udc_write_fifo(ep, req)) {
+ req = NULL;
+ } else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
+ && fifo_count
+ && s3c2410_udc_read_fifo(ep, req)) {
+ req = NULL;
+ }
+ }
+
+ /* pio or dma irq handler advances the queue. */
+ if (likely (req != 0))
+ list_add_tail(&req->queue, &ep->queue);
+
+ local_irq_restore(flags);
+
+ dprintk(DEBUG_VERBOSE, "%s ok\n", __func__);
+ return 0;
+}
+
+/*
+ * s3c2410_udc_dequeue
+ */
+static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ struct s3c2410_udc *udc;
+ int retval = -EINVAL;
+ unsigned long flags;
+ struct s3c2410_request *req = NULL;
+
+ dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
+
+ if (!the_controller->driver)
+ return -ESHUTDOWN;
+
+ if (!_ep || !_req)
+ return retval;
+
+ udc = to_s3c2410_udc(ep->gadget);
+
+ local_irq_save (flags);
+
+ list_for_each_entry (req, &ep->queue, queue) {
+ if (&req->req == _req) {
+ list_del_init (&req->queue);
+ _req->status = -ECONNRESET;
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval == 0) {
+ dprintk(DEBUG_VERBOSE,
+ "dequeued req %p from %s, len %d buf %p\n",
+ req, _ep->name, _req->length, _req->buf);
+
+ s3c2410_udc_done(ep, req, -ECONNRESET);
+ }
+
+ local_irq_restore (flags);
+ return retval;
+}
+
+/*
+ * s3c2410_udc_set_halt
+ */
+static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
+{
+ struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+ u32 ep_csr = 0;
+ unsigned long flags;
+ u32 idx;
+
+ if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+ dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__);
+ return -EINVAL;
+ }
+
+ local_irq_save (flags);
+
+ idx = ep->bEndpointAddress & 0x7F;
+
+ if (idx == 0) {
+ s3c2410_udc_set_ep0_ss(base_addr);
+ s3c2410_udc_set_ep0_de_out(base_addr);
+ } else {
+ udc_write(idx, S3C2410_UDC_INDEX_REG);
+ ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN)
+ ? S3C2410_UDC_IN_CSR1_REG
+ : S3C2410_UDC_OUT_CSR1_REG);
+
+ if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+ if (value)
+ udc_write(ep_csr | S3C2410_UDC_ICSR1_SENDSTL,
+ S3C2410_UDC_IN_CSR1_REG);
+ else {
+ ep_csr &= ~S3C2410_UDC_ICSR1_SENDSTL;
+ udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);
+ ep_csr |= S3C2410_UDC_ICSR1_CLRDT;
+ udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);
+ }
+ } else {
+ if (value)
+ udc_write(ep_csr | S3C2410_UDC_OCSR1_SENDSTL,
+ S3C2410_UDC_OUT_CSR1_REG);
+ else {
+ ep_csr &= ~S3C2410_UDC_OCSR1_SENDSTL;
+ udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);
+ ep_csr |= S3C2410_UDC_OCSR1_CLRDT;
+ udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);
+ }
+ }
+ }
+
+ ep->halted = value ? 1 : 0;
+ local_irq_restore (flags);
+
+ return 0;
+}
+
+static const struct usb_ep_ops s3c2410_ep_ops = {
+ .enable = s3c2410_udc_ep_enable,
+ .disable = s3c2410_udc_ep_disable,
+
+ .alloc_request = s3c2410_udc_alloc_request,
+ .free_request = s3c2410_udc_free_request,
+
+ .queue = s3c2410_udc_queue,
+ .dequeue = s3c2410_udc_dequeue,
+
+ .set_halt = s3c2410_udc_set_halt,
+};
+
+/*------------------------- usb_gadget_ops ----------------------------------*/
+
+/*
+ * s3c2410_udc_get_frame
+ */
+static int s3c2410_udc_get_frame(struct usb_gadget *_gadget)
+{
+ int tmp;
+
+ dprintk(DEBUG_VERBOSE, "%s()\n", __func__);
+
+ tmp = udc_read(S3C2410_UDC_FRAME_NUM2_REG) << 8;
+ tmp |= udc_read(S3C2410_UDC_FRAME_NUM1_REG);
+ return tmp;
+}
+
+/*
+ * s3c2410_udc_wakeup
+ */
+static int s3c2410_udc_wakeup(struct usb_gadget *_gadget)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+ return 0;
+}
+
+/*
+ * s3c2410_udc_set_selfpowered
+ */
+static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
+{
+ struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ if (value)
+ udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
+ else
+ udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+ return 0;
+}
+
+static void s3c2410_udc_disable(struct s3c2410_udc *dev);
+static void s3c2410_udc_enable(struct s3c2410_udc *dev);
+
+static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ if (udc_info && udc_info->udc_command) {
+ if (is_on)
+ s3c2410_udc_enable(udc);
+ else {
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+ if (udc->driver && udc->driver->disconnect)
+ udc->driver->disconnect(&udc->gadget);
+
+ }
+ s3c2410_udc_disable(udc);
+ }
+ }
+ else
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int s3c2410_udc_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ udc->vbus = (is_active != 0);
+ s3c2410_udc_set_pullup(udc, is_active);
+ return 0;
+}
+
+static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ s3c2410_udc_set_pullup(udc, is_on ? 0 : 1);
+ return 0;
+}
+
+static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
+{
+ struct s3c2410_udc *dev = _dev;
+ unsigned int value;
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+ value = s3c2410_gpio_getpin(udc_info->vbus_pin);
+
+ if (udc_info->vbus_pin_inverted)
+ value = !value;
+
+ if (value != dev->vbus)
+ s3c2410_udc_vbus_session(&dev->gadget, value);
+
+ return IRQ_HANDLED;
+}
+
+static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ if (udc_info && udc_info->vbus_draw) {
+ udc_info->vbus_draw(ma);
+ return 0;
+ }
+
+ return -ENOTSUPP;
+}
+
+static const struct usb_gadget_ops s3c2410_ops = {
+ .get_frame = s3c2410_udc_get_frame,
+ .wakeup = s3c2410_udc_wakeup,
+ .set_selfpowered = s3c2410_udc_set_selfpowered,
+ .pullup = s3c2410_udc_pullup,
+ .vbus_session = s3c2410_udc_vbus_session,
+ .vbus_draw = s3c2410_vbus_draw,
+};
+
+/*------------------------- gadget driver handling---------------------------*/
+/*
+ * s3c2410_udc_disable
+ */
+static void s3c2410_udc_disable(struct s3c2410_udc *dev)
+{
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+ /* Disable all interrupts */
+ udc_write(0x00, S3C2410_UDC_USB_INT_EN_REG);
+ udc_write(0x00, S3C2410_UDC_EP_INT_EN_REG);
+
+ /* Clear the interrupt registers */
+ udc_write(S3C2410_UDC_USBINT_RESET
+ | S3C2410_UDC_USBINT_RESUME
+ | S3C2410_UDC_USBINT_SUSPEND,
+ S3C2410_UDC_USB_INT_REG);
+
+ udc_write(0x1F, S3C2410_UDC_EP_INT_REG);
+
+ /* Good bye, cruel world */
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+ /* Set speed to unknown */
+ dev->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+/*
+ * s3c2410_udc_reinit
+ */
+static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
+{
+ u32 i;
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD (&dev->gadget.ep_list);
+ INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+ dev->ep0state = EP0_IDLE;
+
+ for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+ struct s3c2410_ep *ep = &dev->ep[i];
+
+ if (i != 0)
+ list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+
+ ep->dev = dev;
+ ep->desc = NULL;
+ ep->halted = 0;
+ INIT_LIST_HEAD (&ep->queue);
+ }
+}
+
+/*
+ * s3c2410_udc_enable
+ */
+static void s3c2410_udc_enable(struct s3c2410_udc *dev)
+{
+ int i;
+
+ dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n");
+
+ /* dev->gadget.speed = USB_SPEED_UNKNOWN; */
+ dev->gadget.speed = USB_SPEED_FULL;
+
+ /* Set MAXP for all endpoints */
+ for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+ udc_write(i, S3C2410_UDC_INDEX_REG);
+ udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3,
+ S3C2410_UDC_MAXP_REG);
+ }
+
+ /* Set default power state */
+ udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG);
+
+ /* Enable reset and suspend interrupt interrupts */
+ udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND,
+ S3C2410_UDC_USB_INT_EN_REG);
+
+ /* Enable ep0 interrupt */
+ udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);
+
+ /* time to say "hello, world" */
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+}
+
+/*
+ * usb_gadget_register_driver
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct s3c2410_udc *udc = the_controller;
+ int retval;
+
+ dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",
+ driver->driver.name);
+
+ /* Sanity checks */
+ if (!udc)
+ return -ENODEV;
+
+ if (udc->driver)
+ return -EBUSY;
+
+ if (!driver->bind || !driver->setup
+ || driver->speed != USB_SPEED_FULL) {
+ printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
+ driver->bind, driver->setup, driver->speed);
+ return -EINVAL;
+ }
+#if defined(MODULE)
+ if (!driver->unbind) {
+ printk(KERN_ERR "Invalid driver: no unbind method\n");
+ return -EINVAL;
+ }
+#endif
+
+ /* Hook the driver */
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+
+ /* Bind the driver */
+ if ((retval = device_add(&udc->gadget.dev)) != 0) {
+ printk(KERN_ERR "Error in device_add() : %d\n",retval);
+ goto register_error;
+ }
+
+ dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
+ driver->driver.name);
+
+ if ((retval = driver->bind (&udc->gadget)) != 0) {
+ device_del(&udc->gadget.dev);
+ goto register_error;
+ }
+
+ /* Enable udc */
+ s3c2410_udc_enable(udc);
+
+ return 0;
+
+register_error:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+}
+
+/*
+ * usb_gadget_unregister_driver
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct s3c2410_udc *udc = the_controller;
+
+ if (!udc)
+ return -ENODEV;
+
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",
+ driver->driver.name);
+
+ if (driver->disconnect)
+ driver->disconnect(&udc->gadget);
+
+ device_del(&udc->gadget.dev);
+ udc->driver = NULL;
+
+ /* Disable udc */
+ s3c2410_udc_disable(udc);
+
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static struct s3c2410_udc memory = {
+ .gadget = {
+ .ops = &s3c2410_ops,
+ .ep0 = &memory.ep[0].ep,
+ .name = gadget_name,
+ .dev = {
+ .bus_id = "gadget",
+ },
+ },
+
+ /* control endpoint */
+ .ep[0] = {
+ .num = 0,
+ .ep = {
+ .name = ep0name,
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP0_FIFO_SIZE,
+ },
+ .dev = &memory,
+ },
+
+ /* first group of endpoints */
+ .ep[1] = {
+ .num = 1,
+ .ep = {
+ .name = "ep1-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 1,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .ep[2] = {
+ .num = 2,
+ .ep = {
+ .name = "ep2-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 2,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .ep[3] = {
+ .num = 3,
+ .ep = {
+ .name = "ep3-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 3,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ },
+ .ep[4] = {
+ .num = 4,
+ .ep = {
+ .name = "ep4-bulk",
+ .ops = &s3c2410_ep_ops,
+ .maxpacket = EP_FIFO_SIZE,
+ },
+ .dev = &memory,
+ .fifo_size = EP_FIFO_SIZE,
+ .bEndpointAddress = 4,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ }
+
+};
+
+/*
+ * probe - binds to the platform device
+ */
+static int s3c2410_udc_probe(struct platform_device *pdev)
+{
+ struct s3c2410_udc *udc = &memory;
+ struct device *dev = &pdev->dev;
+ int retval;
+ unsigned int irq;
+
+ dev_dbg(dev, "%s()\n", __func__);
+
+ usb_bus_clock = clk_get(NULL, "usb-bus-gadget");
+ if (IS_ERR(usb_bus_clock)) {
+ dev_err(dev, "failed to get usb bus clock source\n");
+ return PTR_ERR(usb_bus_clock);
+ }
+
+ clk_enable(usb_bus_clock);
+
+ udc_clock = clk_get(NULL, "usb-device");
+ if (IS_ERR(udc_clock)) {
+ dev_err(dev, "failed to get udc clock source\n");
+ return PTR_ERR(udc_clock);
+ }
+
+ clk_enable(udc_clock);
+
+ mdelay(10);
+
+ dev_dbg(dev, "got and enabled clocks\n");
+
+ if (strncmp(pdev->name, "s3c2440", 7) == 0) {
+ dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n");
+ memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE;
+ memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE;
+ memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE;
+ memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
+ }
+
+ spin_lock_init (&udc->lock);
+ udc_info = pdev->dev.platform_data;
+
+ rsrc_start = S3C2410_PA_USBDEV;
+ rsrc_len = S3C24XX_SZ_USBDEV;
+
+ if (!request_mem_region(rsrc_start, rsrc_len, gadget_name))
+ return -EBUSY;
+
+ base_addr = ioremap(rsrc_start, rsrc_len);
+ if (!base_addr) {
+ retval = -ENOMEM;
+ goto err_mem;
+ }
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+ the_controller = udc;
+ platform_set_drvdata(pdev, udc);
+
+ s3c2410_udc_disable(udc);
+ s3c2410_udc_reinit(udc);
+
+ /* irq setup after old hardware state is cleaned up */
+ retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
+ IRQF_DISABLED, gadget_name, udc);
+
+ if (retval != 0) {
+ dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval);
+ retval = -EBUSY;
+ goto err_map;
+ }
+
+ dev_dbg(dev, "got irq %i\n", IRQ_USBD);
+
+ if (udc_info && udc_info->vbus_pin > 0) {
+ irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+ retval = request_irq(irq, s3c2410_udc_vbus_irq,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING
+ | IRQF_TRIGGER_FALLING,
+ gadget_name, udc);
+
+ if (retval != 0) {
+ dev_err(dev, "can't get vbus irq %i, err %d\n",
+ irq, retval);
+ retval = -EBUSY;
+ goto err_int;
+ }
+
+ dev_dbg(dev, "got irq %i\n", irq);
+ } else {
+ udc->vbus = 1;
+ }
+
+ if (s3c2410_udc_debugfs_root) {
+ udc->regs_info = debugfs_create_file("registers", S_IRUGO,
+ s3c2410_udc_debugfs_root,
+ udc, &s3c2410_udc_debugfs_fops);
+ if (IS_ERR(udc->regs_info)) {
+ dev_warn(dev, "debugfs file creation failed %ld\n",
+ PTR_ERR(udc->regs_info));
+ udc->regs_info = NULL;
+ }
+ }
+
+ dev_dbg(dev, "probe ok\n");
+
+ return 0;
+
+err_int:
+ free_irq(IRQ_USBD, udc);
+err_map:
+ iounmap(base_addr);
+err_mem:
+ release_mem_region(rsrc_start, rsrc_len);
+
+ return retval;
+}
+
+/*
+ * s3c2410_udc_remove
+ */
+static int s3c2410_udc_remove(struct platform_device *pdev)
+{
+ struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+ unsigned int irq;
+
+ dev_dbg(&pdev->dev, "%s()\n", __func__);
+ if (udc->driver)
+ return -EBUSY;
+
+ debugfs_remove(udc->regs_info);
+
+ if (udc_info && udc_info->vbus_pin > 0) {
+ irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+ free_irq(irq, udc);
+ }
+
+ free_irq(IRQ_USBD, udc);
+
+ iounmap(base_addr);
+ release_mem_region(rsrc_start, rsrc_len);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (!IS_ERR(udc_clock) && udc_clock != NULL) {
+ clk_disable(udc_clock);
+ clk_put(udc_clock);
+ udc_clock = NULL;
+ }
+
+ if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) {
+ clk_disable(usb_bus_clock);
+ clk_put(usb_bus_clock);
+ usb_bus_clock = NULL;
+ }
+
+ dev_dbg(&pdev->dev, "%s: remove ok\n", __func__);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+ return 0;
+}
+
+static int s3c2410_udc_resume(struct platform_device *pdev)
+{
+ if (udc_info && udc_info->udc_command)
+ udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+
+ return 0;
+}
+#else
+#define s3c2410_udc_suspend NULL
+#define s3c2410_udc_resume NULL
+#endif
+
+static struct platform_driver udc_driver_2410 = {
+ .driver = {
+ .name = "s3c2410-usbgadget",
+ .owner = THIS_MODULE,
+ },
+ .probe = s3c2410_udc_probe,
+ .remove = s3c2410_udc_remove,
+ .suspend = s3c2410_udc_suspend,
+ .resume = s3c2410_udc_resume,
+};
+
+static struct platform_driver udc_driver_2440 = {
+ .driver = {
+ .name = "s3c2440-usbgadget",
+ .owner = THIS_MODULE,
+ },
+ .probe = s3c2410_udc_probe,
+ .remove = s3c2410_udc_remove,
+ .suspend = s3c2410_udc_suspend,
+ .resume = s3c2410_udc_resume,
+};
+
+static int __init udc_init(void)
+{
+ int retval;
+
+ dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+
+ s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
+ if (IS_ERR(s3c2410_udc_debugfs_root)) {
+ printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
+ gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
+ s3c2410_udc_debugfs_root = NULL;
+ }
+
+ retval = platform_driver_register(&udc_driver_2410);
+ if (retval)
+ goto err;
+
+ retval = platform_driver_register(&udc_driver_2440);
+ if (retval)
+ goto err;
+
+ return 0;
+
+err:
+ debugfs_remove(s3c2410_udc_debugfs_root);
+ return retval;
+}
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver_2410);
+ platform_driver_unregister(&udc_driver_2440);
+ debugfs_remove(s3c2410_udc_debugfs_root);
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h
new file mode 100644
index 000000000000..9e0bece4f241
--- /dev/null
+++ b/drivers/usb/gadget/s3c2410_udc.h
@@ -0,0 +1,110 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.h
+ * Samsung on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard
+ * Additional cleanups by Ben Dooks <ben-linux@fluff.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _S3C2410_UDC_H
+#define _S3C2410_UDC_H
+
+struct s3c2410_ep {
+ struct list_head queue;
+ unsigned long last_io; /* jiffies timestamp */
+ struct usb_gadget *gadget;
+ struct s3c2410_udc *dev;
+ const struct usb_endpoint_descriptor *desc;
+ struct usb_ep ep;
+ u8 num;
+
+ unsigned short fifo_size;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+
+ unsigned halted : 1;
+ unsigned already_seen : 1;
+ unsigned setup_stage : 1;
+};
+
+
+/* Warning : ep0 has a fifo of 16 bytes */
+/* Don't try to set 32 or 64 */
+/* also testusb 14 fails wit 16 but is */
+/* fine with 8 */
+#define EP0_FIFO_SIZE 8
+#define EP_FIFO_SIZE 64
+#define DEFAULT_POWER_STATE 0x00
+
+#define S3C2440_EP_FIFO_SIZE 128
+
+static const char ep0name [] = "ep0";
+
+static const char *const ep_name[] = {
+ ep0name, /* everyone has ep0 */
+ /* s3c2410 four bidirectional bulk endpoints */
+ "ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk",
+};
+
+#define S3C2410_ENDPOINTS ARRAY_SIZE(ep_name)
+
+struct s3c2410_request {
+ struct list_head queue; /* ep's requests */
+ struct usb_request req;
+};
+
+enum ep0_state {
+ EP0_IDLE,
+ EP0_IN_DATA_PHASE,
+ EP0_OUT_DATA_PHASE,
+ EP0_END_XFER,
+ EP0_STALL,
+};
+
+static const char *ep0states[]= {
+ "EP0_IDLE",
+ "EP0_IN_DATA_PHASE",
+ "EP0_OUT_DATA_PHASE",
+ "EP0_END_XFER",
+ "EP0_STALL",
+};
+
+struct s3c2410_udc {
+ spinlock_t lock;
+
+ struct s3c2410_ep ep[S3C2410_ENDPOINTS];
+ int address;
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct s3c2410_request fifo_req;
+ u8 fifo_buf[EP_FIFO_SIZE];
+ u16 devstatus;
+
+ u32 port_status;
+ int ep0state;
+
+ unsigned got_irq : 1;
+
+ unsigned req_std : 1;
+ unsigned req_config : 1;
+ unsigned req_pending : 1;
+ u8 vbus;
+ struct dentry *regs_info;
+};
+
+#endif
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f847c3414be3..9cd98e73dc1d 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -33,6 +33,7 @@
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/mutex.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -258,7 +259,7 @@ static const char *EP_IN_NAME;
static const char *EP_OUT_NAME;
static const char *EP_NOTIFY_NAME;
-static struct semaphore gs_open_close_sem[GS_NUM_PORTS];
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
@@ -595,7 +596,7 @@ static int __init gs_module_init(void)
tty_set_operations(gs_tty_driver, &gs_tty_ops);
for (i=0; i < GS_NUM_PORTS; i++)
- sema_init(&gs_open_close_sem[i], 1);
+ mutex_init(&gs_open_close_lock[i]);
retval = tty_register_driver(gs_tty_driver);
if (retval) {
@@ -635,7 +636,7 @@ static int gs_open(struct tty_struct *tty, struct file *file)
struct gs_port *port;
struct gs_dev *dev;
struct gs_buf *buf;
- struct semaphore *sem;
+ struct mutex *mtx;
int ret;
port_num = tty->index;
@@ -656,10 +657,10 @@ static int gs_open(struct tty_struct *tty, struct file *file)
return -ENODEV;
}
- sem = &gs_open_close_sem[port_num];
- if (down_interruptible(sem)) {
+ mtx = &gs_open_close_lock[port_num];
+ if (mutex_lock_interruptible(mtx)) {
printk(KERN_ERR
- "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+ "gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
port_num, tty, file);
return -ERESTARTSYS;
}
@@ -754,12 +755,12 @@ static int gs_open(struct tty_struct *tty, struct file *file)
exit_unlock_port:
spin_unlock_irqrestore(&port->port_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
exit_unlock_dev:
spin_unlock_irqrestore(&dev->dev_lock, flags);
- up(sem);
+ mutex_unlock(mtx);
return ret;
}
@@ -781,7 +782,7 @@ exit_unlock_dev:
static void gs_close(struct tty_struct *tty, struct file *file)
{
struct gs_port *port = tty->driver_data;
- struct semaphore *sem;
+ struct mutex *mtx;
if (port == NULL) {
printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +791,8 @@ static void gs_close(struct tty_struct *tty, struct file *file)
gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
- sem = &gs_open_close_sem[port->port_num];
- down(sem);
+ mtx = &gs_open_close_lock[port->port_num];
+ mutex_lock(mtx);
spin_lock_irq(&port->port_lock);
@@ -846,7 +847,7 @@ static void gs_close(struct tty_struct *tty, struct file *file)
exit:
spin_unlock_irq(&port->port_lock);
- up(sem);
+ mutex_unlock(mtx);
}
/*
@@ -1427,7 +1428,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL);
+ gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
@@ -1435,7 +1436,6 @@ static int __init gs_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release,
gadget->name);
- memset(dev, 0, sizeof(struct gs_dev));
dev->dev_gadget = gadget;
spin_lock_init(&dev->dev_lock);
INIT_LIST_HEAD(&dev->dev_req_list);
@@ -2215,7 +2215,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
*
* Free the buffer and all associated memory.
*/
-void gs_buf_free(struct gs_buf *gb)
+static void gs_buf_free(struct gs_buf *gb)
{
if (gb) {
kfree(gb->buf_buf);
@@ -2228,7 +2228,7 @@ void gs_buf_free(struct gs_buf *gb)
*
* Clear out all data in the circular buffer.
*/
-void gs_buf_clear(struct gs_buf *gb)
+static void gs_buf_clear(struct gs_buf *gb)
{
if (gb != NULL)
gb->buf_get = gb->buf_put;
@@ -2241,7 +2241,7 @@ void gs_buf_clear(struct gs_buf *gb)
* Return the number of bytes of data available in the circular
* buffer.
*/
-unsigned int gs_buf_data_avail(struct gs_buf *gb)
+static unsigned int gs_buf_data_avail(struct gs_buf *gb)
{
if (gb != NULL)
return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
@@ -2255,7 +2255,7 @@ unsigned int gs_buf_data_avail(struct gs_buf *gb)
* Return the number of bytes of space available in the circular
* buffer.
*/
-unsigned int gs_buf_space_avail(struct gs_buf *gb)
+static unsigned int gs_buf_space_avail(struct gs_buf *gb)
{
if (gb != NULL)
return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
@@ -2271,7 +2271,8 @@ unsigned int gs_buf_space_avail(struct gs_buf *gb)
*
* Return the number of bytes copied.
*/
-unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
+static unsigned int
+gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
{
unsigned int len;
@@ -2309,7 +2310,8 @@ unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
*
* Return the number of bytes copied.
*/
-unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
+static unsigned int
+gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
{
unsigned int len;
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 7078374d0b79..a2e6e3fc8c8d 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -481,8 +481,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
req = usb_ep_alloc_request (ep, GFP_ATOMIC);
if (req) {
req->length = length;
- req->buf = usb_ep_alloc_buffer (ep, length,
- &req->dma, GFP_ATOMIC);
+ req->buf = kmalloc(length, GFP_ATOMIC);
if (!req->buf) {
usb_ep_free_request (ep, req);
req = NULL;
@@ -493,8 +492,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
{
- if (req->buf)
- usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+ kfree(req->buf);
usb_ep_free_request (ep, req);
}
@@ -1199,8 +1197,7 @@ autoconf_fail:
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
if (!dev->req)
goto enomem;
- dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
- &dev->req->dma, GFP_KERNEL);
+ dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
if (!dev->req->buf)
goto enomem;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 62711870f8ee..2f529828c74d 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -69,8 +69,20 @@ config USB_EHCI_TT_NEWSCHED
config USB_EHCI_BIG_ENDIAN_MMIO
bool
- depends on USB_EHCI_HCD
- default n
+ depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX)
+ default y
+
+config USB_EHCI_BIG_ENDIAN_DESC
+ bool
+ depends on USB_EHCI_HCD && 440EPX
+ default y
+
+config USB_EHCI_FSL
+ bool
+ select USB_EHCI_ROOT_HUB_TT
+ default y if MPC834x || PPC_MPC831x
+ ---help---
+ Variation of ARC USB block used in some Freescale chips.
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
@@ -224,3 +236,15 @@ config USB_SL811_CS
To compile this driver as a module, choose M here: the
module will be called "sl811_cs".
+config USB_R8A66597_HCD
+ tristate "R8A66597 HCD suppoort"
+ depends on USB
+ help
+ The R8A66597 is a USB 2.0 host and peripheral controller.
+
+ Enable this option if your board has this chip, and you want
+ to use it as a host controller. If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called r8a66597-hcd.
+
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 2ff396bd180f..bb8e9d44f371 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,3 +15,5 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
+obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
+
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 43eddaecc3dd..c9cc4413198e 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -52,7 +52,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
HCS_INDICATOR (params) ? " ind" : "",
HCS_N_CC (params),
HCS_N_PCC (params),
- HCS_PORTROUTED (params) ? "" : " ordered",
+ HCS_PORTROUTED (params) ? "" : " ordered",
HCS_PPC (params) ? "" : " !ppc",
HCS_N_PORTS (params)
);
@@ -91,20 +91,20 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
if (HCC_ISOC_CACHE (params)) {
ehci_dbg (ehci,
- "%s hcc_params %04x caching frame %s%s%s\n",
- label, params,
- HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
- HCC_CANPARK (params) ? " park" : "",
- HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+ "%s hcc_params %04x caching frame %s%s%s\n",
+ label, params,
+ HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+ HCC_CANPARK(params) ? " park" : "",
+ HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
} else {
ehci_dbg (ehci,
- "%s hcc_params %04x thresh %d uframes %s%s%s\n",
- label,
- params,
- HCC_ISOC_THRES (params),
- HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
- HCC_CANPARK (params) ? " park" : "",
- HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+ "%s hcc_params %04x thresh %d uframes %s%s%s\n",
+ label,
+ params,
+ HCC_ISOC_THRES(params),
+ HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+ HCC_CANPARK(params) ? " park" : "",
+ HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
}
}
#else
@@ -115,23 +115,23 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
#ifdef DEBUG
-static void __attribute__((__unused__))
+static void __maybe_unused
dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
{
- ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
- le32_to_cpup (&qtd->hw_next),
- le32_to_cpup (&qtd->hw_alt_next),
- le32_to_cpup (&qtd->hw_token),
- le32_to_cpup (&qtd->hw_buf [0]));
+ ehci_dbg(ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
+ hc32_to_cpup(ehci, &qtd->hw_next),
+ hc32_to_cpup(ehci, &qtd->hw_alt_next),
+ hc32_to_cpup(ehci, &qtd->hw_token),
+ hc32_to_cpup(ehci, &qtd->hw_buf [0]));
if (qtd->hw_buf [1])
- ehci_dbg (ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
- le32_to_cpup (&qtd->hw_buf [1]),
- le32_to_cpup (&qtd->hw_buf [2]),
- le32_to_cpup (&qtd->hw_buf [3]),
- le32_to_cpup (&qtd->hw_buf [4]));
+ ehci_dbg(ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
+ hc32_to_cpup(ehci, &qtd->hw_buf[1]),
+ hc32_to_cpup(ehci, &qtd->hw_buf[2]),
+ hc32_to_cpup(ehci, &qtd->hw_buf[3]),
+ hc32_to_cpup(ehci, &qtd->hw_buf[4]));
}
-static void __attribute__((__unused__))
+static void __maybe_unused
dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{
ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
@@ -140,51 +140,53 @@ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
}
-static void __attribute__((__unused__))
+static void __maybe_unused
dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
{
ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
- label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
+ label, itd->frame, itd, hc32_to_cpu(ehci, itd->hw_next),
+ itd->urb);
ehci_dbg (ehci,
" trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
- le32_to_cpu(itd->hw_transaction[0]),
- le32_to_cpu(itd->hw_transaction[1]),
- le32_to_cpu(itd->hw_transaction[2]),
- le32_to_cpu(itd->hw_transaction[3]),
- le32_to_cpu(itd->hw_transaction[4]),
- le32_to_cpu(itd->hw_transaction[5]),
- le32_to_cpu(itd->hw_transaction[6]),
- le32_to_cpu(itd->hw_transaction[7]));
+ hc32_to_cpu(ehci, itd->hw_transaction[0]),
+ hc32_to_cpu(ehci, itd->hw_transaction[1]),
+ hc32_to_cpu(ehci, itd->hw_transaction[2]),
+ hc32_to_cpu(ehci, itd->hw_transaction[3]),
+ hc32_to_cpu(ehci, itd->hw_transaction[4]),
+ hc32_to_cpu(ehci, itd->hw_transaction[5]),
+ hc32_to_cpu(ehci, itd->hw_transaction[6]),
+ hc32_to_cpu(ehci, itd->hw_transaction[7]));
ehci_dbg (ehci,
" buf: %08x %08x %08x %08x %08x %08x %08x\n",
- le32_to_cpu(itd->hw_bufp[0]),
- le32_to_cpu(itd->hw_bufp[1]),
- le32_to_cpu(itd->hw_bufp[2]),
- le32_to_cpu(itd->hw_bufp[3]),
- le32_to_cpu(itd->hw_bufp[4]),
- le32_to_cpu(itd->hw_bufp[5]),
- le32_to_cpu(itd->hw_bufp[6]));
+ hc32_to_cpu(ehci, itd->hw_bufp[0]),
+ hc32_to_cpu(ehci, itd->hw_bufp[1]),
+ hc32_to_cpu(ehci, itd->hw_bufp[2]),
+ hc32_to_cpu(ehci, itd->hw_bufp[3]),
+ hc32_to_cpu(ehci, itd->hw_bufp[4]),
+ hc32_to_cpu(ehci, itd->hw_bufp[5]),
+ hc32_to_cpu(ehci, itd->hw_bufp[6]));
ehci_dbg (ehci, " index: %d %d %d %d %d %d %d %d\n",
itd->index[0], itd->index[1], itd->index[2],
itd->index[3], itd->index[4], itd->index[5],
itd->index[6], itd->index[7]);
}
-static void __attribute__((__unused__))
+static void __maybe_unused
dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
- label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
+ label, sitd->frame, sitd, hc32_to_cpu(ehci, sitd->hw_next),
+ sitd->urb);
ehci_dbg (ehci,
" addr %08x sched %04x result %08x buf %08x %08x\n",
- le32_to_cpu(sitd->hw_fullspeed_ep),
- le32_to_cpu(sitd->hw_uframe),
- le32_to_cpu(sitd->hw_results),
- le32_to_cpu(sitd->hw_buf [0]),
- le32_to_cpu(sitd->hw_buf [1]));
+ hc32_to_cpu(ehci, sitd->hw_fullspeed_ep),
+ hc32_to_cpu(ehci, sitd->hw_uframe),
+ hc32_to_cpu(ehci, sitd->hw_results),
+ hc32_to_cpu(ehci, sitd->hw_buf[0]),
+ hc32_to_cpu(ehci, sitd->hw_buf[1]));
}
-static int __attribute__((__unused__))
+static int __maybe_unused
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
{
return scnprintf (buf, len,
@@ -203,7 +205,7 @@ dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
);
}
-static int __attribute__((__unused__))
+static int __maybe_unused
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
{
return scnprintf (buf, len,
@@ -267,28 +269,27 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
(status & PORT_PEC) ? " PEC" : "",
(status & PORT_PE) ? " PE" : "",
(status & PORT_CSC) ? " CSC" : "",
- (status & PORT_CONNECT) ? " CONNECT" : ""
- );
+ (status & PORT_CONNECT) ? " CONNECT" : "");
}
#else
-static inline void __attribute__((__unused__))
+static inline void __maybe_unused
dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{}
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
{ return 0; }
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
{ return 0; }
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
{ return 0; }
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
{ return 0; }
@@ -332,9 +333,10 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
default: tmp = '?'; break; \
}; tmp; })
-static inline char token_mark (__le32 token)
+static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
{
- __u32 v = le32_to_cpu (token);
+ __u32 v = hc32_to_cpu(ehci, token);
+
if (v & QTD_STS_ACTIVE)
return '*';
if (v & QTD_STS_HALT)
@@ -360,46 +362,48 @@ static void qh_lines (
unsigned size = *sizep;
char *next = *nextp;
char mark;
+ u32 list_end = EHCI_LIST_END(ehci);
- if (qh->hw_qtd_next == EHCI_LIST_END) /* NEC does this */
+ if (qh->hw_qtd_next == list_end) /* NEC does this */
mark = '@';
else
- mark = token_mark (qh->hw_token);
+ mark = token_mark(ehci, qh->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */
- if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
+ if ((qh->hw_alt_next & QTD_MASK(ehci))
+ == ehci->async->hw_alt_next)
mark = '#'; /* blocked */
- else if (qh->hw_alt_next == EHCI_LIST_END)
+ else if (qh->hw_alt_next == list_end)
mark = '.'; /* use hw_qtd_next */
/* else alt_next points to some other qtd */
}
- scratch = le32_to_cpup (&qh->hw_info1);
- hw_curr = (mark == '*') ? le32_to_cpup (&qh->hw_current) : 0;
+ scratch = hc32_to_cpup(ehci, &qh->hw_info1);
+ hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->hw_current) : 0;
temp = scnprintf (next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f,
- scratch, le32_to_cpup (&qh->hw_info2),
- le32_to_cpup (&qh->hw_token), mark,
- (__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token)
+ scratch, hc32_to_cpup(ehci, &qh->hw_info2),
+ hc32_to_cpup(ehci, &qh->hw_token), mark,
+ (cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token)
? "data1" : "data0",
- (le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f);
+ (hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f);
size -= temp;
next += temp;
/* hc may be modifying the list as we read it ... */
list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd, qtd_list);
- scratch = le32_to_cpup (&td->hw_token);
+ scratch = hc32_to_cpup(ehci, &td->hw_token);
mark = ' ';
if (hw_curr == td->qtd_dma)
mark = '*';
- else if (qh->hw_qtd_next == cpu_to_le32(td->qtd_dma))
+ else if (qh->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
mark = '+';
else if (QTD_LENGTH (scratch)) {
if (td->hw_alt_next == ehci->async->hw_alt_next)
mark = '#';
- else if (td->hw_alt_next != EHCI_LIST_END)
+ else if (td->hw_alt_next != list_end)
mark = '/';
}
temp = snprintf (next, size,
@@ -490,7 +494,7 @@ show_periodic (struct class_device *class_dev, char *buf)
unsigned temp, size, seen_count;
char *next;
unsigned i;
- __le32 tag;
+ __hc32 tag;
if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
return 0;
@@ -514,18 +518,19 @@ show_periodic (struct class_device *class_dev, char *buf)
p = ehci->pshadow [i];
if (likely (!p.ptr))
continue;
- tag = Q_NEXT_TYPE (ehci->periodic [i]);
+ tag = Q_NEXT_TYPE(ehci, ehci->periodic [i]);
temp = scnprintf (next, size, "%4d: ", i);
size -= temp;
next += temp;
do {
- switch (tag) {
+ switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH:
temp = scnprintf (next, size, " qh%d-%04x/%p",
p.qh->period,
- le32_to_cpup (&p.qh->hw_info2)
+ hc32_to_cpup(ehci,
+ &p.qh->hw_info2)
/* uframe masks */
& (QH_CMASK | QH_SMASK),
p.qh);
@@ -543,7 +548,7 @@ show_periodic (struct class_device *class_dev, char *buf)
}
/* show more info the first time around */
if (temp == seen_count && p.ptr) {
- u32 scratch = le32_to_cpup (
+ u32 scratch = hc32_to_cpup(ehci,
&p.qh->hw_info1);
struct ehci_qtd *qtd;
char *type = "";
@@ -554,7 +559,8 @@ show_periodic (struct class_device *class_dev, char *buf)
&p.qh->qtd_list,
qtd_list) {
temp++;
- switch (0x03 & (le32_to_cpu (
+ switch (0x03 & (hc32_to_cpu(
+ ehci,
qtd->hw_token) >> 8)) {
case 0: type = "out"; continue;
case 1: type = "in"; continue;
@@ -576,7 +582,7 @@ show_periodic (struct class_device *class_dev, char *buf)
} else
temp = 0;
if (p.qh) {
- tag = Q_NEXT_TYPE (p.qh->hw_next);
+ tag = Q_NEXT_TYPE(ehci, p.qh->hw_next);
p = p.qh->qh_next;
}
break;
@@ -584,23 +590,23 @@ show_periodic (struct class_device *class_dev, char *buf)
temp = scnprintf (next, size,
" fstn-%8x/%p", p.fstn->hw_prev,
p.fstn);
- tag = Q_NEXT_TYPE (p.fstn->hw_next);
+ tag = Q_NEXT_TYPE(ehci, p.fstn->hw_next);
p = p.fstn->fstn_next;
break;
case Q_TYPE_ITD:
temp = scnprintf (next, size,
" itd/%p", p.itd);
- tag = Q_NEXT_TYPE (p.itd->hw_next);
+ tag = Q_NEXT_TYPE(ehci, p.itd->hw_next);
p = p.itd->itd_next;
break;
case Q_TYPE_SITD:
temp = scnprintf (next, size,
" sitd%d-%04x/%p",
p.sitd->stream->interval,
- le32_to_cpup (&p.sitd->hw_uframe)
+ hc32_to_cpup(ehci, &p.sitd->hw_uframe)
& 0x0000ffff,
p.sitd);
- tag = Q_NEXT_TYPE (p.sitd->hw_next);
+ tag = Q_NEXT_TYPE(ehci, p.sitd->hw_next);
p = p.sitd->sitd_next;
break;
}
@@ -673,7 +679,8 @@ show_registers (struct class_device *class_dev, char *buf)
unsigned count = 256/4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
- offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
+ offset = HCC_EXT_CAPS(ehci_readl(ehci,
+ &ehci->caps->hcc_params));
while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) {
@@ -740,14 +747,16 @@ show_registers (struct class_device *class_dev, char *buf)
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
- ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
+ ehci_readl(ehci,
+ &ehci->regs->port_status[i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size,
" debug control %08x\n",
- ehci_readl(ehci, &ehci->debug->control));
+ ehci_readl(ehci,
+ &ehci->debug->control));
size -= temp;
next += temp;
}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index c7a7c590426f..b7b7bfbce527 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -67,7 +67,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
* in host mode.
*/
if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
- (pdata->operating_mode == FSL_USB2_MPH_HOST))) {
+ (pdata->operating_mode == FSL_USB2_MPH_HOST) ||
+ (pdata->operating_mode == FSL_USB2_DR_OTG))) {
dev_err(&pdev->dev,
"Non Host Mode configured for %s. Wrong driver linked.\n",
pdev->dev.bus_id);
@@ -185,12 +186,14 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct fsl_usb2_platform_data *pdata;
void __iomem *non_ehci = hcd->regs;
+ u32 temp;
pdata =
(struct fsl_usb2_platform_data *)hcd->self.controller->
platform_data;
/* Enable PHY interface in the control reg. */
- out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
+ temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+ out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
@@ -206,7 +209,8 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
#endif
- if (pdata->operating_mode == FSL_USB2_DR_HOST)
+ if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
+ (pdata->operating_mode == FSL_USB2_DR_OTG))
mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 099aff64f536..c4e15ed1405a 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -41,10 +41,6 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
-#ifdef CONFIG_PPC_PS3
-#include <asm/firmware.h>
-#endif
-
/*-------------------------------------------------------------------------*/
@@ -201,9 +197,15 @@ static void tdi_reset (struct ehci_hcd *ehci)
u32 __iomem *reg_ptr;
u32 tmp;
- reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
+ reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
tmp = ehci_readl(ehci, reg_ptr);
- tmp |= 0x3;
+ tmp |= USBMODE_CM_HC;
+ /* The default byte access to MMR space is LE after
+ * controller reset. Set the required endian mode
+ * for transfer buffers to match the host microprocessor
+ */
+ if (ehci_big_endian_mmio(ehci))
+ tmp |= USBMODE_BE;
ehci_writel(ehci, tmp, reg_ptr);
}
@@ -273,6 +275,58 @@ static void ehci_work(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_CPU_FREQ
+
+#include <linux/cpufreq.h>
+
+static void ehci_cpufreq_pause (struct ehci_hcd *ehci)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+ if (!ehci->cpufreq_changing++)
+ qh_inactivate_split_intr_qhs(ehci);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_cpufreq_unpause (struct ehci_hcd *ehci)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ehci->lock, flags);
+ if (!--ehci->cpufreq_changing)
+ qh_reactivate_split_intr_qhs(ehci);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+/*
+ * ehci_cpufreq_notifier is needed to avoid MMF errors that occur when
+ * EHCI controllers that don't cache many uframes get delayed trying to
+ * read main memory during CPU frequency transitions. This can cause
+ * split interrupt transactions to not be completed in the required uframe.
+ * This has been observed on the Broadcom/ServerWorks HT1000 controller.
+ */
+static int ehci_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct ehci_hcd *ehci = container_of(nb, struct ehci_hcd,
+ cpufreq_transition);
+
+ switch (val) {
+ case CPUFREQ_PRECHANGE:
+ ehci_cpufreq_pause(ehci);
+ break;
+ case CPUFREQ_POSTCHANGE:
+ ehci_cpufreq_unpause(ehci);
+ break;
+ }
+ return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
@@ -347,6 +401,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
is_on ? SetPortFeature : ClearPortFeature,
USB_PORT_FEAT_POWER,
port--, NULL, 0);
+ /* Flush those writes */
+ ehci_readl(ehci, &ehci->regs->command);
msleep(20);
}
@@ -404,6 +460,10 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
+#ifdef CONFIG_CPU_FREQ
+ cpufreq_unregister_notifier(&ehci->cpufreq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+#endif
/* let companion controllers work when we aren't */
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
@@ -470,12 +530,12 @@ static int ehci_init(struct usb_hcd *hcd)
* from automatically advancing to the next td after short reads.
*/
ehci->async->qh_next.qh = NULL;
- ehci->async->hw_next = QH_NEXT(ehci->async->qh_dma);
- ehci->async->hw_info1 = cpu_to_le32(QH_HEAD);
- ehci->async->hw_token = cpu_to_le32(QTD_STS_HALT);
- ehci->async->hw_qtd_next = EHCI_LIST_END;
+ ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
+ ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
+ ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
+ ehci->async->hw_qtd_next = EHCI_LIST_END(ehci);
ehci->async->qh_state = QH_STATE_LINKED;
- ehci->async->hw_alt_next = QTD_NEXT(ehci->async->dummy->qtd_dma);
+ ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
/* clear interrupt enables, set irq latency */
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
@@ -509,6 +569,17 @@ static int ehci_init(struct usb_hcd *hcd)
}
ehci->command = temp;
+#ifdef CONFIG_CPU_FREQ
+ INIT_LIST_HEAD(&ehci->split_intr_qhs);
+ /*
+ * If the EHCI controller caches enough uframes, this probably
+ * isn't needed unless there are so many low/full speed devices
+ * that the controller's can't cache it all.
+ */
+ ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
+ cpufreq_register_notifier(&ehci->cpufreq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+#endif
return 0;
}
@@ -925,7 +996,7 @@ MODULE_LICENSE ("GPL");
#define PCI_DRIVER ehci_pci_driver
#endif
-#ifdef CONFIG_MPC834x
+#ifdef CONFIG_USB_EHCI_FSL
#include "ehci-fsl.c"
#define PLATFORM_DRIVER ehci_fsl_driver
#endif
@@ -937,7 +1008,12 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
-#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver
+#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
+#endif
+
+#ifdef CONFIG_440EPX
+#include "ehci-ppc-soc.c"
+#define PLATFORM_DRIVER ehci_ppc_soc_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
@@ -971,18 +1047,15 @@ static int __init ehci_hcd_init(void)
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
- if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
- retval = ps3_system_bus_driver_register(
- &PS3_SYSTEM_BUS_DRIVER);
- if (retval < 0) {
+ retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0) {
#ifdef PLATFORM_DRIVER
- platform_driver_unregister(&PLATFORM_DRIVER);
+ platform_driver_unregister(&PLATFORM_DRIVER);
#endif
#ifdef PCI_DRIVER
- pci_unregister_driver(&PCI_DRIVER);
+ pci_unregister_driver(&PCI_DRIVER);
#endif
- return retval;
- }
+ return retval;
}
#endif
@@ -999,8 +1072,7 @@ static void __exit ehci_hcd_cleanup(void)
pci_unregister_driver(&PCI_DRIVER);
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
- if (firmware_has_feature(FW_FEATURE_PS3_LV1))
- ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
}
module_exit(ehci_hcd_cleanup);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index f4d301bc83b9..0dcb4164dc83 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -28,6 +28,89 @@
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_PERSIST
+
+static int ehci_hub_control(
+ struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue,
+ u16 wIndex,
+ char *buf,
+ u16 wLength
+);
+
+/* After a power loss, ports that were owned by the companion must be
+ * reset so that the companion can still own them.
+ */
+static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
+{
+ u32 __iomem *reg;
+ u32 status;
+ int port;
+ __le32 buf;
+ struct usb_hcd *hcd = ehci_to_hcd(ehci);
+
+ if (!ehci->owned_ports)
+ return;
+
+ /* Give the connections some time to appear */
+ msleep(20);
+
+ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ if (test_bit(port, &ehci->owned_ports)) {
+ reg = &ehci->regs->port_status[port];
+ status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
+
+ /* Port already owned by companion? */
+ if (status & PORT_OWNER)
+ clear_bit(port, &ehci->owned_ports);
+ else if (test_bit(port, &ehci->companion_ports))
+ ehci_writel(ehci, status & ~PORT_PE, reg);
+ else
+ ehci_hub_control(hcd, SetPortFeature,
+ USB_PORT_FEAT_RESET, port + 1,
+ NULL, 0);
+ }
+ }
+
+ if (!ehci->owned_ports)
+ return;
+ msleep(90); /* Wait for resets to complete */
+
+ port = HCS_N_PORTS(ehci->hcs_params);
+ while (port--) {
+ if (test_bit(port, &ehci->owned_ports)) {
+ ehci_hub_control(hcd, GetPortStatus,
+ 0, port + 1,
+ (char *) &buf, sizeof(buf));
+
+ /* The companion should now own the port,
+ * but if something went wrong the port must not
+ * remain enabled.
+ */
+ reg = &ehci->regs->port_status[port];
+ status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
+ if (status & PORT_OWNER)
+ ehci_writel(ehci, status | PORT_CSC, reg);
+ else {
+ ehci_dbg(ehci, "failed handover port %d: %x\n",
+ port + 1, status);
+ ehci_writel(ehci, status & ~PORT_PE, reg);
+ }
+ }
+ }
+
+ 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)
@@ -60,14 +143,16 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
* then manually resume them in the bus_resume() routine.
*/
ehci->bus_suspended = 0;
+ ehci->owned_ports = 0;
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
u32 t2 = t1;
/* keep track of which ports we suspend */
- if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) &&
- !(t1 & PORT_SUSPEND)) {
+ if (t1 & PORT_OWNER)
+ set_bit(port, &ehci->owned_ports);
+ else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
t2 |= PORT_SUSPEND;
set_bit(port, &ehci->bus_suspended);
}
@@ -108,11 +193,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
+ u32 power_okay;
int i;
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
spin_lock_irq (&ehci->lock);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ spin_unlock_irq(&ehci->lock);
+ return -ESHUTDOWN;
+ }
/* Ideally and we've got a real resume here, and no port's power
* was lost. (For PCI, that means Vaux was maintained.) But we
@@ -120,8 +210,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
* the last user of the controller, not reset/pm hardware keeping
* state we gave to it.
*/
- temp = ehci_readl(ehci, &ehci->regs->intr_enable);
- ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
+ power_okay = ehci_readl(ehci, &ehci->regs->intr_enable);
+ ehci_dbg(ehci, "resume root hub%s\n",
+ power_okay ? "" : " after power loss");
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
@@ -184,6 +275,9 @@ 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);
return 0;
}
@@ -448,7 +542,8 @@ static int ehci_hub_control (
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports = HCS_N_PORTS (ehci->hcs_params);
- u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1];
+ u32 __iomem *status_reg = &ehci->regs->port_status[
+ (wIndex & 0xff) - 1];
u32 temp, status;
unsigned long flags;
int retval = 0;
@@ -556,9 +651,24 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_CONNECTION;
if (temp & PORT_PEC)
status |= 1 << USB_PORT_FEAT_C_ENABLE;
- if ((temp & PORT_OCC) && !ignore_oc)
+
+ if ((temp & PORT_OCC) && !ignore_oc){
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
+ /*
+ * Hubs should disable port power on over-current.
+ * However, not all EHCI implementations do this
+ * automatically, even if they _do_ support per-port
+ * power switching; they're allowed to just limit the
+ * current. khubd will turn the power back on.
+ */
+ if (HCS_PPC (ehci->hcs_params)){
+ ehci_writel(ehci,
+ temp & ~(PORT_RWC_BITS | PORT_POWER),
+ status_reg);
+ }
+ }
+
/* whoever resumes must GetPortStatus to complete it!! */
if (temp & PORT_RESUME) {
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index a8ba2e1497a4..8816d09903d0 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -27,7 +27,7 @@
* need to use dma_pool or dma_alloc_coherent
* - driver buffers, read/written by HC ... single shot DMA mapped
*
- * There's also PCI "register" data, which is memory mapped.
+ * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
* No memory seen by this driver is pageable.
*/
@@ -35,13 +35,14 @@
/* Allocate the key transfer structures from the previously allocated pool */
-static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
+static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
+ dma_addr_t dma)
{
memset (qtd, 0, sizeof *qtd);
qtd->qtd_dma = dma;
qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
- qtd->hw_next = EHCI_LIST_END;
- qtd->hw_alt_next = EHCI_LIST_END;
+ qtd->hw_next = EHCI_LIST_END(ehci);
+ qtd->hw_alt_next = EHCI_LIST_END(ehci);
INIT_LIST_HEAD (&qtd->qtd_list);
}
@@ -52,7 +53,7 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags)
qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != NULL) {
- ehci_qtd_init (qtd, dma);
+ ehci_qtd_init(ehci, qtd, dma);
}
return qtd;
}
@@ -63,9 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
}
-static void qh_destroy (struct kref *kref)
+static void qh_destroy(struct ehci_qh *qh)
{
- struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
struct ehci_hcd *ehci = qh->ehci;
/* clean qtds first, and know this is not linked */
@@ -89,11 +89,14 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
return qh;
memset (qh, 0, sizeof *qh);
- kref_init(&qh->kref);
+ qh->refcount = 1;
qh->ehci = ehci;
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
+#ifdef CONFIG_CPU_FREQ
+ INIT_LIST_HEAD (&qh->split_intr_qhs);
+#endif
/* dummy td enables safe urb queuing */
qh->dummy = ehci_qtd_alloc (ehci, flags);
@@ -108,13 +111,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
/* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
{
- kref_get(&qh->kref);
+ WARN_ON(!qh->refcount);
+ qh->refcount++;
return qh;
}
static inline void qh_put (struct ehci_qh *qh)
{
- kref_put(&qh->kref, qh_destroy);
+ if (!--qh->refcount)
+ qh_destroy(qh);
}
/*-------------------------------------------------------------------------*/
@@ -217,7 +222,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
goto fail;
}
for (i = 0; i < ehci->periodic_size; i++)
- ehci->periodic [i] = EHCI_LIST_END;
+ ehci->periodic [i] = EHCI_LIST_END(ehci);
/* software shadow of hardware table */
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 12edc723ec73..a7816e392a85 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -149,8 +149,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
* fixed in newer silicon.
*/
case 0x0068:
- pci_read_config_dword(pdev, PCI_REVISION_ID, &temp);
- if ((temp & 0xff) < 0xa4)
+ if (pdev->revision < 0xa4)
ehci->no_selective_suspend = 1;
break;
}
@@ -313,13 +312,14 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
ehci_work(ehci);
spin_unlock_irq(&ehci->lock);
- /* here we "know" root ports should always stay powered */
- ehci_port_power(ehci, 1);
-
ehci_writel(ehci, ehci->command, &ehci->regs->command);
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+ /* 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;
}
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
new file mode 100644
index 000000000000..c2cedb09ed8b
--- /dev/null
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -0,0 +1,182 @@
+/*
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 2006-2007 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * Bus Glue for PPC On-Chip EHCI driver
+ * Tested on AMCC 440EPx
+ *
+ * Based on "ehci-au12xx.c" by David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/platform_device.h>
+
+extern int usb_disabled(void);
+
+/**
+ * usb_ehci_ppc_soc_probe - initialize PPC-SoC-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_ehci_ppc_soc_probe(const struct hc_driver *driver,
+ struct usb_hcd **hcd_out,
+ struct platform_device *dev)
+{
+ int retval;
+ struct usb_hcd *hcd;
+ struct ehci_hcd *ehci;
+
+ if (dev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ retval = -ENOMEM;
+ }
+ hcd = usb_create_hcd(driver, &dev->dev, "PPC-SOC EHCI");
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = dev->resource[0].start;
+ hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_debug("request_mem_region failed");
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ pr_debug("ioremap failed");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ ehci = hcd_to_ehci(hcd);
+ ehci->big_endian_mmio = 1;
+ ehci->big_endian_desc = 1;
+ ehci->caps = hcd->regs;
+ ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+ /* cache this readonly data; minimize chip reads */
+ ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+#if defined(CONFIG_440EPX)
+ /*
+ * 440EPx Errata USBH_3
+ * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
+ */
+ out_be32((void *)((ulong)(&ehci->regs->command) + 0x8c), (1 << 0));
+ ehci_dbg(ehci, "Break Memory Transfer (BMT) has beed enabled!\n");
+#endif
+
+ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
+ if (retval == 0)
+ return retval;
+
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+ return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_ehci_hcd_ppc_soc_remove - shutdown processing for PPC-SoC-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_ppc_soc_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_ehci_ppc_soc_remove(struct usb_hcd *hcd, struct platform_device *dev)
+{
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+}
+
+static const struct hc_driver ehci_ppc_soc_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "PPC-SOC EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_init,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#ifdef CONFIG_PM
+ .hub_suspend = ehci_hub_suspend,
+ .hub_resume = ehci_hub_resume,
+#endif
+};
+
+static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = NULL;
+ int ret;
+
+ pr_debug("In ehci_hcd_ppc_soc_drv_probe\n");
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ ret = usb_ehci_ppc_soc_probe(&ehci_ppc_soc_hc_driver, &hcd, pdev);
+ return ret;
+}
+
+static int ehci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_ehci_ppc_soc_remove(hcd, pdev);
+ return 0;
+}
+
+MODULE_ALIAS("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 37b83ba09969..829fe649a981 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <asm/firmware.h>
#include <asm/ps3.h>
static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
@@ -73,7 +74,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
#endif
};
-static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
{
int result;
struct usb_hcd *hcd;
@@ -85,13 +86,30 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
goto fail_start;
}
+ result = ps3_open_hv_device(dev);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
+ __func__, __LINE__);
+ goto fail_open;
+ }
+
+ result = ps3_dma_region_create(dev->d_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
+ "(%d)\n", __func__, __LINE__, result);
+ BUG_ON("check region type");
+ goto fail_dma_region;
+ }
+
result = ps3_mmio_region_create(dev->m_region);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
__func__, __LINE__);
result = -EPERM;
- goto fail_mmio;
+ goto fail_mmio_region;
}
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
@@ -120,6 +138,11 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
hcd->rsrc_start = dev->m_region->lpar_addr;
hcd->rsrc_len = dev->m_region->len;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
+ dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
+ __func__, __LINE__);
+
hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
if (!hcd->regs) {
@@ -153,34 +176,73 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
fail_add_hcd:
iounmap(hcd->regs);
fail_ioremap:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
fail_create_hcd:
ps3_io_irq_destroy(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
-fail_mmio:
+fail_mmio_region:
+ ps3_dma_region_free(dev->d_region);
+fail_dma_region:
+ ps3_close_hv_device(dev);
+fail_open:
fail_start:
return result;
}
-static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
{
+ unsigned int tmp;
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
- usb_put_hcd(hcd);
+ BUG_ON(!hcd);
+
+ dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
+
+ tmp = hcd->irq;
+
+ usb_remove_hcd(hcd);
+
ps3_system_bus_set_driver_data(dev, NULL);
+ BUG_ON(!hcd->regs);
+ iounmap(hcd->regs);
+
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ ps3_io_irq_destroy(tmp);
+ ps3_free_mmio_region(dev->m_region);
+
+ ps3_dma_region_free(dev->d_region);
+ ps3_close_hv_device(dev);
+
return 0;
}
-MODULE_ALIAS("ps3-ehci");
+static int ps3_ehci_driver_register(struct ps3_system_bus_driver *drv)
+{
+ return firmware_has_feature(FW_FEATURE_PS3_LV1)
+ ? ps3_system_bus_driver_register(drv)
+ : 0;
+}
+
+static void ps3_ehci_driver_unregister(struct ps3_system_bus_driver *drv)
+{
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1))
+ ps3_system_bus_driver_unregister(drv);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_EHCI);
-static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+static struct ps3_system_bus_driver ps3_ehci_driver = {
+ .core.name = "ps3-ehci-driver",
+ .core.owner = THIS_MODULE,
.match_id = PS3_MATCH_ID_EHCI,
- .core = {
- .name = "ps3-ehci-driver",
- },
- .probe = ps3_ehci_sb_probe,
- .remove = ps3_ehci_sb_remove,
+ .probe = ps3_ehci_probe,
+ .remove = ps3_ehci_remove,
+ .shutdown = ps3_ehci_remove,
};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index e7fbbd00e7cd..2284028f8aa5 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -43,15 +43,15 @@
/* fill a qtd, returning how much of the buffer we were able to queue up */
static int
-qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
- int token, int maxpacket)
+qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
+ size_t len, int token, int maxpacket)
{
int i, count;
u64 addr = buf;
/* one buffer entry per 4K ... first might be short or unaligned */
- qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
- qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
+ qtd->hw_buf[0] = cpu_to_hc32(ehci, (u32)addr);
+ qtd->hw_buf_hi[0] = cpu_to_hc32(ehci, (u32)(addr >> 32));
count = 0x1000 - (buf & 0x0fff); /* rest of that page */
if (likely (len < count)) /* ... iff needed */
count = len;
@@ -62,8 +62,9 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
/* per-qtd limit: from 16K to 20K (best alignment) */
for (i = 1; count < len && i < 5; i++) {
addr = buf;
- qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
- qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
+ qtd->hw_buf[i] = cpu_to_hc32(ehci, (u32)addr);
+ qtd->hw_buf_hi[i] = cpu_to_hc32(ehci,
+ (u32)(addr >> 32));
buf += 0x1000;
if ((count + 0x1000) < len)
count += 0x1000;
@@ -75,7 +76,7 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
if (count != len)
count -= (count % maxpacket);
}
- qtd->hw_token = cpu_to_le32 ((count << 16) | token);
+ qtd->hw_token = cpu_to_hc32(ehci, (count << 16) | token);
qtd->length = count;
return count;
@@ -89,28 +90,28 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
/* writes to an active overlay are unsafe */
BUG_ON(qh->qh_state != QH_STATE_IDLE);
- qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
- qh->hw_alt_next = EHCI_LIST_END;
+ qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
+ qh->hw_alt_next = EHCI_LIST_END(ehci);
/* Except for control endpoints, we make hardware maintain data
* toggle (like OHCI) ... here (re)initialize the toggle in the QH,
* and set the pseudo-toggle in udev. Only usb_clear_halt() will
* ever clear it.
*/
- if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) {
+ if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
unsigned is_out, epnum;
- is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
- epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
+ is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+ epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
- qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+ qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
usb_settoggle (qh->dev, epnum, is_out, 1);
}
}
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb ();
- qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+ qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
}
/* if it weren't for a common silicon quirk (writing the dummy into the qh
@@ -128,7 +129,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
qtd = list_entry (qh->qtd_list.next,
struct ehci_qtd, qtd_list);
/* first qtd may already be partially processed */
- if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current)
+ if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current)
qtd = NULL;
}
@@ -222,7 +223,7 @@ __acquires(ehci->lock)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */
- if ((qh->hw_info2 & __constant_cpu_to_le32 (QH_SMASK)) != 0) {
+ if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
@@ -277,7 +278,6 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
* Chases up to qh->hw_current. Returns number of completions called,
* indicating how much "real" work we did.
*/
-#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
@@ -287,6 +287,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned count = 0;
int do_status = 0;
u8 state;
+ u32 halt = HALT_BIT(ehci);
if (unlikely (list_empty (&qh->qtd_list)))
return count;
@@ -311,6 +312,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct urb *urb;
u32 token = 0;
+ /* ignore QHs that are currently inactive */
+ if (qh->hw_info1 & __constant_cpu_to_le32(QH_INACTIVATE))
+ break;
+
qtd = list_entry (entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
@@ -330,7 +335,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* hardware copies qtd out of qh overlay */
rmb ();
- token = le32_to_cpu (qtd->hw_token);
+ token = hc32_to_cpu(ehci, qtd->hw_token);
/* always clean up qtds the hc de-activated */
if ((token & QTD_STS_ACTIVE) == 0) {
@@ -342,7 +347,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* that silicon quirk can kick in with this dummy too.
*/
} else if (IS_SHORT_READ (token)
- && !(qtd->hw_alt_next & EHCI_LIST_END)) {
+ && !(qtd->hw_alt_next
+ & EHCI_LIST_END(ehci))) {
stopped = 1;
goto halt;
}
@@ -374,17 +380,17 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* token in overlay may be most current */
if (state == QH_STATE_IDLE
- && cpu_to_le32 (qtd->qtd_dma)
+ && cpu_to_hc32(ehci, qtd->qtd_dma)
== qh->hw_current)
- token = le32_to_cpu (qh->hw_token);
+ token = hc32_to_cpu(ehci, qh->hw_token);
/* force halt for unlinked or blocked qh, so we'll
* patch the qh later and so that completions can't
* activate it while we "know" it's stopped.
*/
- if ((HALT_BIT & qh->hw_token) == 0) {
+ if ((halt & qh->hw_token) == 0) {
halt:
- qh->hw_token |= HALT_BIT;
+ qh->hw_token |= halt;
wmb ();
}
}
@@ -419,7 +425,7 @@ halt:
* it after fault cleanup, or recovering from silicon wrongly
* overlaying the dummy qtd (which reduces DMA chatter).
*/
- if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
+ if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) {
switch (state) {
case QH_STATE_IDLE:
qh_refresh(ehci, qh);
@@ -428,7 +434,7 @@ halt:
/* should be rare for periodic transfers,
* except maybe high bandwidth ...
*/
- if ((__constant_cpu_to_le32 (QH_SMASK)
+ if ((cpu_to_hc32(ehci, QH_SMASK)
& qh->hw_info2) != 0) {
intr_deschedule (ehci, qh);
(void) qh_schedule (ehci, qh);
@@ -502,8 +508,9 @@ qh_urb_transaction (
is_input = usb_pipein (urb->pipe);
if (usb_pipecontrol (urb->pipe)) {
/* SETUP pid */
- qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
- token | (2 /* "setup" */ << 8), 8);
+ qtd_fill(ehci, qtd, urb->setup_dma,
+ sizeof (struct usb_ctrlrequest),
+ token | (2 /* "setup" */ << 8), 8);
/* ... and always at least one more pid */
token ^= QTD_TOGGLE;
@@ -512,7 +519,7 @@ qh_urb_transaction (
if (unlikely (!qtd))
goto cleanup;
qtd->urb = urb;
- qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+ qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
/* for zero length DATA stages, STATUS is always IN */
@@ -539,7 +546,7 @@ qh_urb_transaction (
for (;;) {
int this_qtd_len;
- this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket);
+ this_qtd_len = qtd_fill(ehci, qtd, buf, len, token, maxpacket);
len -= this_qtd_len;
buf += this_qtd_len;
if (is_input)
@@ -557,7 +564,7 @@ qh_urb_transaction (
if (unlikely (!qtd))
goto cleanup;
qtd->urb = urb;
- qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+ qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
}
@@ -566,7 +573,7 @@ qh_urb_transaction (
*/
if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
|| usb_pipecontrol (urb->pipe)))
- qtd->hw_alt_next = EHCI_LIST_END;
+ qtd->hw_alt_next = EHCI_LIST_END(ehci);
/*
* control requests may need a terminating data "status" ack;
@@ -590,17 +597,17 @@ qh_urb_transaction (
if (unlikely (!qtd))
goto cleanup;
qtd->urb = urb;
- qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+ qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
/* never any data in such packets */
- qtd_fill (qtd, 0, 0, token, 0);
+ qtd_fill(ehci, qtd, 0, 0, token, 0);
}
}
/* by default, enable interrupt on urb completion */
if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
- qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
+ qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
return head;
cleanup:
@@ -769,8 +776,8 @@ done:
/* init as live, toggle clear, advance to dummy */
qh->qh_state = QH_STATE_IDLE;
- qh->hw_info1 = cpu_to_le32 (info1);
- qh->hw_info2 = cpu_to_le32 (info2);
+ qh->hw_info1 = cpu_to_hc32(ehci, info1);
+ qh->hw_info2 = cpu_to_hc32(ehci, info2);
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
qh_refresh (ehci, qh);
return qh;
@@ -782,7 +789,7 @@ done:
static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- __le32 dma = QH_NEXT (qh->qh_dma);
+ __hc32 dma = QH_NEXT(ehci, qh->qh_dma);
struct ehci_qh *head;
/* (re)start the async schedule? */
@@ -820,8 +827,6 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-#define QH_ADDR_MASK __constant_cpu_to_le32(0x7f)
-
/*
* For control/bulk/interrupt, return QH with these TDs appended.
* Allocates and initializes the QH if necessary.
@@ -837,6 +842,7 @@ static struct ehci_qh *qh_append_tds (
)
{
struct ehci_qh *qh = NULL;
+ u32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f);
qh = (struct ehci_qh *) *ptr;
if (unlikely (qh == NULL)) {
@@ -858,7 +864,7 @@ static struct ehci_qh *qh_append_tds (
/* usb_reset_device() briefly reverts to address 0 */
if (usb_pipedevice (urb->pipe) == 0)
- qh->hw_info1 &= ~QH_ADDR_MASK;
+ qh->hw_info1 &= ~qh_addr_mask;
}
/* just one way to queue requests: swap with the dummy qtd.
@@ -867,7 +873,7 @@ static struct ehci_qh *qh_append_tds (
if (likely (qtd != NULL)) {
struct ehci_qtd *dummy;
dma_addr_t dma;
- __le32 token;
+ __hc32 token;
/* to avoid racing the HC, use the dummy td instead of
* the first td of our list (becomes new dummy). both
@@ -875,7 +881,7 @@ static struct ehci_qh *qh_append_tds (
* HC is allowed to fetch the old dummy (4.10.2).
*/
token = qtd->hw_token;
- qtd->hw_token = HALT_BIT;
+ qtd->hw_token = HALT_BIT(ehci);
wmb ();
dummy = qh->dummy;
@@ -887,14 +893,14 @@ static struct ehci_qh *qh_append_tds (
list_add (&dummy->qtd_list, qtd_list);
__list_splice (qtd_list, qh->qtd_list.prev);
- ehci_qtd_init (qtd, qtd->qtd_dma);
+ ehci_qtd_init(ehci, qtd, qtd->qtd_dma);
qh->dummy = qtd;
/* hc must see the new dummy at list end */
dma = qtd->qtd_dma;
qtd = list_entry (qh->qtd_list.prev,
struct ehci_qtd, qtd_list);
- qtd->hw_next = QTD_NEXT (dma);
+ qtd->hw_next = QTD_NEXT(ehci, dma);
/* let the hc process these next qtds */
wmb ();
@@ -970,7 +976,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
timer_action_done (ehci, TIMER_IAA_WATCHDOG);
- // qh->hw_next = cpu_to_le32 (qh->qh_dma);
+ // qh->hw_next = cpu_to_hc32(qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
qh_put (qh); // refcount from reclaim
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 7b5ae7111f23..d4a8ace49676 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -44,9 +44,10 @@ static int ehci_get_frame (struct usb_hcd *hcd);
* @tag: hardware tag for type of this record
*/
static union ehci_shadow *
-periodic_next_shadow (union ehci_shadow *periodic, __le32 tag)
+periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic,
+ __hc32 tag)
{
- switch (tag) {
+ switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH:
return &periodic->qh->qh_next;
case Q_TYPE_FSTN:
@@ -62,13 +63,14 @@ periodic_next_shadow (union ehci_shadow *periodic, __le32 tag)
/* caller must hold ehci->lock */
static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
{
- union ehci_shadow *prev_p = &ehci->pshadow [frame];
- __le32 *hw_p = &ehci->periodic [frame];
+ union ehci_shadow *prev_p = &ehci->pshadow[frame];
+ __hc32 *hw_p = &ehci->periodic[frame];
union ehci_shadow here = *prev_p;
/* find predecessor of "ptr"; hw and shadow lists are in sync */
while (here.ptr && here.ptr != ptr) {
- prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
+ prev_p = periodic_next_shadow(ehci, prev_p,
+ Q_NEXT_TYPE(ehci, *hw_p));
hw_p = here.hw_next;
here = *prev_p;
}
@@ -79,7 +81,8 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
/* update shadow and hardware lists ... the old "next" pointers
* from ptr may still be in use, the caller updates them.
*/
- *prev_p = *periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
+ *prev_p = *periodic_next_shadow(ehci, &here,
+ Q_NEXT_TYPE(ehci, *hw_p));
*hw_p = *here.hw_next;
}
@@ -87,18 +90,19 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
static unsigned short
periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
{
- __le32 *hw_p = &ehci->periodic [frame];
+ __hc32 *hw_p = &ehci->periodic [frame];
union ehci_shadow *q = &ehci->pshadow [frame];
unsigned usecs = 0;
while (q->ptr) {
- switch (Q_NEXT_TYPE (*hw_p)) {
+ switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
case Q_TYPE_QH:
/* is it in the S-mask? */
- if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
+ if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
usecs += q->qh->usecs;
/* ... or C-mask? */
- if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+ if (q->qh->hw_info2 & cpu_to_hc32(ehci,
+ 1 << (8 + uframe)))
usecs += q->qh->c_usecs;
hw_p = &q->qh->hw_next;
q = &q->qh->qh_next;
@@ -108,7 +112,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
/* for "save place" FSTNs, count the relevant INTR
* bandwidth from the previous frame
*/
- if (q->fstn->hw_prev != EHCI_LIST_END) {
+ if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) {
ehci_dbg (ehci, "ignoring FSTN cost ...\n");
}
hw_p = &q->fstn->hw_next;
@@ -121,9 +125,10 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
break;
case Q_TYPE_SITD:
/* is it in the S-mask? (count SPLIT, DATA) */
- if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
+ if (q->sitd->hw_uframe & cpu_to_hc32(ehci,
+ 1 << uframe)) {
if (q->sitd->hw_fullspeed_ep &
- __constant_cpu_to_le32 (1<<31))
+ cpu_to_hc32(ehci, 1<<31))
usecs += q->sitd->stream->usecs;
else /* worst case for OUT start-split */
usecs += HS_USECS_ISO (188);
@@ -131,7 +136,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
/* ... C-mask? (count CSPLIT, DATA) */
if (q->sitd->hw_uframe &
- cpu_to_le32 (1 << (8 + uframe))) {
+ cpu_to_hc32(ehci, 1 << (8 + uframe))) {
/* worst case for IN complete-split */
usecs += q->sitd->stream->c_usecs;
}
@@ -173,9 +178,9 @@ static int same_tt (struct usb_device *dev1, struct usb_device *dev2)
* will cause a transfer in "B-frame" uframe 0. "B-frames" lag
* "H-frames" by 1 uframe. See the EHCI spec sec 4.5 and figure 4.7.
*/
-static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __le32 mask)
+static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask)
{
- unsigned char smask = QH_SMASK & le32_to_cpu(mask);
+ unsigned char smask = QH_SMASK & hc32_to_cpu(ehci, mask);
if (!smask) {
ehci_err(ehci, "invalid empty smask!\n");
/* uframe 7 can't have bw so this will indicate failure */
@@ -217,14 +222,14 @@ periodic_tt_usecs (
unsigned short tt_usecs[8]
)
{
- __le32 *hw_p = &ehci->periodic [frame];
+ __hc32 *hw_p = &ehci->periodic [frame];
union ehci_shadow *q = &ehci->pshadow [frame];
unsigned char uf;
memset(tt_usecs, 0, 16);
while (q->ptr) {
- switch (Q_NEXT_TYPE(*hw_p)) {
+ switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
case Q_TYPE_ITD:
hw_p = &q->itd->hw_next;
q = &q->itd->itd_next;
@@ -247,8 +252,8 @@ periodic_tt_usecs (
continue;
// case Q_TYPE_FSTN:
default:
- ehci_dbg(ehci,
- "ignoring periodic frame %d FSTN\n", frame);
+ ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n",
+ frame);
hw_p = &q->fstn->hw_next;
q = &q->fstn->fstn_next;
}
@@ -368,41 +373,42 @@ static int tt_no_collision (
*/
for (; frame < ehci->periodic_size; frame += period) {
union ehci_shadow here;
- __le32 type;
+ __hc32 type;
here = ehci->pshadow [frame];
- type = Q_NEXT_TYPE (ehci->periodic [frame]);
+ type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
while (here.ptr) {
- switch (type) {
+ switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_ITD:
- type = Q_NEXT_TYPE (here.itd->hw_next);
+ type = Q_NEXT_TYPE(ehci, here.itd->hw_next);
here = here.itd->itd_next;
continue;
case Q_TYPE_QH:
if (same_tt (dev, here.qh->dev)) {
u32 mask;
- mask = le32_to_cpu (here.qh->hw_info2);
+ mask = hc32_to_cpu(ehci,
+ here.qh->hw_info2);
/* "knows" no gap is needed */
mask |= mask >> 8;
if (mask & uf_mask)
break;
}
- type = Q_NEXT_TYPE (here.qh->hw_next);
+ type = Q_NEXT_TYPE(ehci, here.qh->hw_next);
here = here.qh->qh_next;
continue;
case Q_TYPE_SITD:
if (same_tt (dev, here.sitd->urb->dev)) {
u16 mask;
- mask = le32_to_cpu (here.sitd
+ mask = hc32_to_cpu(ehci, here.sitd
->hw_uframe);
/* FIXME assumes no gap for IN! */
mask |= mask >> 8;
if (mask & uf_mask)
break;
}
- type = Q_NEXT_TYPE (here.sitd->hw_next);
+ type = Q_NEXT_TYPE(ehci, here.sitd->hw_next);
here = here.sitd->sitd_next;
continue;
// case Q_TYPE_FSTN:
@@ -473,6 +479,109 @@ static int disable_periodic (struct ehci_hcd *ehci)
}
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_CPU_FREQ
+
+static int safe_to_modify_i (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+ int now; /* current (frame * 8) + uframe */
+ int prev_start, next_start; /* uframes from/to split start */
+ int start_uframe = ffs(le32_to_cpup (&qh->hw_info2) & QH_SMASK);
+ int end_uframe = fls((le32_to_cpup (&qh->hw_info2) & QH_CMASK) >> 8);
+ int split_duration = end_uframe - start_uframe;
+
+ now = readl(&ehci->regs->frame_index) % (ehci->periodic_size << 3);
+
+ next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now)
+ % (qh->period << 3);
+ prev_start = (qh->period << 3) - next_start;
+
+ /*
+ * Make sure there will be at least one uframe when qh is safe.
+ */
+ if ((qh->period << 3) <= (ehci->i_thresh + 2 + split_duration))
+ /* never safe */
+ return -EINVAL;
+
+ /*
+ * Wait 1 uframe after transaction should have started, to make
+ * sure controller has time to write back overlay, so we can
+ * check QTD_STS_STS to see if transaction is in progress.
+ */
+ if ((next_start > ehci->i_thresh) && (prev_start > 1))
+ /* safe to set "i" bit if split isn't in progress */
+ return (qh->hw_token & STATUS_BIT(ehci)) ? 0 : 1;
+ else
+ return 0;
+}
+
+/* Set inactivate bit for all the split interrupt QHs. */
+static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci)
+{
+ struct ehci_qh *qh;
+ int not_done, safe;
+ u32 inactivate = INACTIVATE_BIT(ehci);
+ u32 active = ACTIVE_BIT(ehci);
+
+ do {
+ not_done = 0;
+ list_for_each_entry(qh, &ehci->split_intr_qhs,
+ split_intr_qhs) {
+ if (qh->hw_info1 & inactivate)
+ /* already off */
+ continue;
+ /*
+ * To avoid setting "I" after the start split happens,
+ * don't set it if the QH might be cached in the
+ * controller. Some HCs (Broadcom/ServerWorks HT1000)
+ * will stop in the middle of a split transaction when
+ * the "I" bit is set.
+ */
+ safe = safe_to_modify_i(ehci, qh);
+ if (safe == 0) {
+ not_done = 1;
+ } else if (safe > 0) {
+ qh->was_active = qh->hw_token & active;
+ qh->hw_info1 |= inactivate;
+ }
+ }
+ } while (not_done);
+ wmb();
+}
+
+static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
+{
+ struct ehci_qh *qh;
+ u32 token;
+ int not_done, safe;
+ u32 inactivate = INACTIVATE_BIT(ehci);
+ u32 active = ACTIVE_BIT(ehci);
+ u32 halt = HALT_BIT(ehci);
+
+ do {
+ not_done = 0;
+ list_for_each_entry(qh, &ehci->split_intr_qhs, split_intr_qhs) {
+ if (!(qh->hw_info1 & inactivate)) /* already on */
+ continue;
+ /*
+ * Don't reactivate if cached, or controller might
+ * overwrite overlay after we modify it!
+ */
+ safe = safe_to_modify_i(ehci, qh);
+ if (safe == 0) {
+ not_done = 1;
+ } else if (safe > 0) {
+ /* See EHCI 1.0 section 4.15.2.4. */
+ token = qh->hw_token;
+ qh->hw_token = (token | halt) & ~active;
+ wmb();
+ qh->hw_info1 &= ~inactivate;
+ wmb();
+ qh->hw_token = (token & ~halt) | qh->was_active;
+ }
+ }
+ } while (not_done);
+}
+#endif
/* periodic schedule slots have iso tds (normal or split) first, then a
* sparse tree for active interrupt transfers.
@@ -487,25 +596,36 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev,
"link qh%d-%04x/%p start %d [%d/%d us]\n",
- period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
+ period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs);
+#ifdef CONFIG_CPU_FREQ
+ /*
+ * If low/full speed interrupt QHs are inactive (because of
+ * cpufreq changing processor speeds), start QH with I flag set--
+ * it will automatically be cleared when cpufreq is done.
+ */
+ if (ehci->cpufreq_changing)
+ if (!(qh->hw_info1 & (cpu_to_le32(1 << 13))))
+ qh->hw_info1 |= INACTIVATE_BIT(ehci);
+#endif
+
/* high bandwidth, or otherwise every microframe */
if (period == 0)
period = 1;
for (i = qh->start; i < ehci->periodic_size; i += period) {
- union ehci_shadow *prev = &ehci->pshadow [i];
- __le32 *hw_p = &ehci->periodic [i];
+ union ehci_shadow *prev = &ehci->pshadow[i];
+ __hc32 *hw_p = &ehci->periodic[i];
union ehci_shadow here = *prev;
- __le32 type = 0;
+ __hc32 type = 0;
/* skip the iso nodes at list head */
while (here.ptr) {
- type = Q_NEXT_TYPE (*hw_p);
- if (type == Q_TYPE_QH)
+ type = Q_NEXT_TYPE(ehci, *hw_p);
+ if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
break;
- prev = periodic_next_shadow (prev, type);
+ prev = periodic_next_shadow(ehci, prev, type);
hw_p = &here.qh->hw_next;
here = *prev;
}
@@ -527,7 +647,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->hw_next = *hw_p;
wmb ();
prev->qh = qh;
- *hw_p = QH_NEXT (qh->qh_dma);
+ *hw_p = QH_NEXT (ehci, qh->qh_dma);
}
}
qh->qh_state = QH_STATE_LINKED;
@@ -538,6 +658,12 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
? ((qh->usecs + qh->c_usecs) / qh->period)
: (qh->usecs * 8);
+#ifdef CONFIG_CPU_FREQ
+ /* add qh to list of low/full speed interrupt QHs, if applicable */
+ if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
+ list_add(&qh->split_intr_qhs, &ehci->split_intr_qhs);
+ }
+#endif
/* maybe enable periodic schedule processing */
if (!ehci->periodic_sched++)
return enable_periodic (ehci);
@@ -555,7 +681,14 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
// and this qh is active in the current uframe
// (and overlay token SplitXstate is false?)
// THEN
- // qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
+ // qh->hw_info1 |= __constant_cpu_to_hc32(1 << 7 /* "ignore" */);
+
+#ifdef CONFIG_CPU_FREQ
+ /* remove qh from list of low/full speed interrupt QHs */
+ if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
+ list_del_init(&qh->split_intr_qhs);
+ }
+#endif
/* high bandwidth, or otherwise part of every microframe */
if ((period = qh->period) == 0)
@@ -572,7 +705,7 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev,
"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
qh->period,
- le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
+ hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs);
/* qh->qh_next still "live" to HC */
@@ -598,7 +731,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
* active high speed queues may need bigger delays...
*/
if (list_empty (&qh->qtd_list)
- || (__constant_cpu_to_le32 (QH_CMASK)
+ || (cpu_to_hc32(ehci, QH_CMASK)
& qh->hw_info2) != 0)
wait = 2;
else
@@ -606,7 +739,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
udelay (wait);
qh->qh_state = QH_STATE_IDLE;
- qh->hw_next = EHCI_LIST_END;
+ qh->hw_next = EHCI_LIST_END(ehci);
wmb ();
}
@@ -663,7 +796,7 @@ static int check_intr_schedule (
unsigned frame,
unsigned uframe,
const struct ehci_qh *qh,
- __le32 *c_maskp
+ __hc32 *c_maskp
)
{
int retval = -ENOSPC;
@@ -695,7 +828,7 @@ static int check_intr_schedule (
retval = 0;
- *c_maskp = cpu_to_le32 (mask << 8);
+ *c_maskp = cpu_to_hc32(ehci, mask << 8);
}
#else
/* Make sure this tt's buffer is also available for CSPLITs.
@@ -706,7 +839,7 @@ static int check_intr_schedule (
* one smart pass...
*/
mask = 0x03 << (uframe + qh->gap_uf);
- *c_maskp = cpu_to_le32 (mask << 8);
+ *c_maskp = cpu_to_hc32(ehci, mask << 8);
mask |= 1 << uframe;
if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) {
@@ -726,20 +859,20 @@ done:
/* "first fit" scheduling policy used the first time through,
* or when the previous schedule slot can't be re-used.
*/
-static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
{
int status;
unsigned uframe;
- __le32 c_mask;
+ __hc32 c_mask;
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
qh_refresh(ehci, qh);
- qh->hw_next = EHCI_LIST_END;
+ qh->hw_next = EHCI_LIST_END(ehci);
frame = qh->start;
/* reuse the previous schedule slots, if we can */
if (frame < qh->period) {
- uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK);
+ uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK);
status = check_intr_schedule (ehci, frame, --uframe,
qh, &c_mask);
} else {
@@ -775,10 +908,10 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->start = frame;
/* reset S-frame and (maybe) C-frame masks */
- qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK));
+ qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
qh->hw_info2 |= qh->period
- ? cpu_to_le32 (1 << uframe)
- : __constant_cpu_to_le32 (QH_SMASK);
+ ? cpu_to_hc32(ehci, 1 << uframe)
+ : cpu_to_hc32(ehci, QH_SMASK);
qh->hw_info2 |= c_mask;
} else
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
@@ -808,7 +941,7 @@ static int intr_submit (
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
- &ehci_to_hcd(ehci)->flags))) {
+ &ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
goto done;
}
@@ -898,9 +1031,9 @@ iso_stream_init (
buf1 |= maxp;
maxp *= multi;
- stream->buf0 = cpu_to_le32 ((epnum << 8) | dev->devnum);
- stream->buf1 = cpu_to_le32 (buf1);
- stream->buf2 = cpu_to_le32 (multi);
+ stream->buf0 = cpu_to_hc32(ehci, (epnum << 8) | dev->devnum);
+ stream->buf1 = cpu_to_hc32(ehci, buf1);
+ stream->buf2 = cpu_to_hc32(ehci, multi);
/* usbfs wants to report the average usecs per frame tied up
* when transfers on this endpoint are scheduled ...
@@ -943,7 +1076,7 @@ iso_stream_init (
bandwidth /= 1 << (interval + 2);
/* stream->splits gets created from raw_mask later */
- stream->address = cpu_to_le32 (addr);
+ stream->address = cpu_to_hc32(ehci, addr);
}
stream->bandwidth = bandwidth;
@@ -1077,7 +1210,8 @@ iso_sched_alloc (unsigned packets, gfp_t mem_flags)
}
static inline void
-itd_sched_init (
+itd_sched_init(
+ struct ehci_hcd *ehci,
struct ehci_iso_sched *iso_sched,
struct ehci_iso_stream *stream,
struct urb *urb
@@ -1107,7 +1241,7 @@ itd_sched_init (
&& !(urb->transfer_flags & URB_NO_INTERRUPT))
trans |= EHCI_ITD_IOC;
trans |= length << 16;
- uframe->transaction = cpu_to_le32 (trans);
+ uframe->transaction = cpu_to_hc32(ehci, trans);
/* might need to cross a buffer page within a uframe */
uframe->bufp = (buf & ~(u64)0x0fff);
@@ -1149,7 +1283,7 @@ itd_urb_transaction (
if (unlikely (sched == NULL))
return -ENOMEM;
- itd_sched_init (sched, stream, urb);
+ itd_sched_init(ehci, sched, stream, urb);
if (urb->interval < 8)
num_itds = 1 + (sched->span + 7) / 8;
@@ -1167,7 +1301,7 @@ itd_urb_transaction (
/* prefer previously-allocated itds */
if (likely (!list_empty(&stream->free_list))) {
itd = list_entry (stream->free_list.prev,
- struct ehci_itd, itd_list);
+ struct ehci_itd, itd_list);
list_del (&itd->itd_list);
itd_dma = itd->itd_dma;
} else
@@ -1294,7 +1428,7 @@ sitd_slot_ok (
uframe += period_uframes;
} while (uframe < mod);
- stream->splits = cpu_to_le32(stream->raw_mask << (uframe & 7));
+ stream->splits = cpu_to_hc32(ehci, stream->raw_mask << (uframe & 7));
return 1;
}
@@ -1415,12 +1549,13 @@ ready:
/*-------------------------------------------------------------------------*/
static inline void
-itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
+itd_init(struct ehci_hcd *ehci, struct ehci_iso_stream *stream,
+ struct ehci_itd *itd)
{
int i;
/* it's been recently zeroed */
- itd->hw_next = EHCI_LIST_END;
+ itd->hw_next = EHCI_LIST_END(ehci);
itd->hw_bufp [0] = stream->buf0;
itd->hw_bufp [1] = stream->buf1;
itd->hw_bufp [2] = stream->buf2;
@@ -1432,7 +1567,8 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
}
static inline void
-itd_patch (
+itd_patch(
+ struct ehci_hcd *ehci,
struct ehci_itd *itd,
struct ehci_iso_sched *iso_sched,
unsigned index,
@@ -1447,17 +1583,18 @@ itd_patch (
uframe &= 0x07;
itd->index [uframe] = index;
- itd->hw_transaction [uframe] = uf->transaction;
- itd->hw_transaction [uframe] |= cpu_to_le32 (pg << 12);
- itd->hw_bufp [pg] |= cpu_to_le32 (uf->bufp & ~(u32)0);
- itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
+ itd->hw_transaction[uframe] = uf->transaction;
+ itd->hw_transaction[uframe] |= cpu_to_hc32(ehci, pg << 12);
+ itd->hw_bufp[pg] |= cpu_to_hc32(ehci, uf->bufp & ~(u32)0);
+ itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(uf->bufp >> 32));
/* iso_frame_desc[].offset must be strictly increasing */
if (unlikely (uf->cross)) {
u64 bufp = uf->bufp + 4096;
+
itd->pg = ++pg;
- itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
- itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(bufp >> 32));
+ itd->hw_bufp[pg] |= cpu_to_hc32(ehci, bufp & ~(u32)0);
+ itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(bufp >> 32));
}
}
@@ -1470,7 +1607,7 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
ehci->pshadow [frame].itd = itd;
itd->frame = frame;
wmb ();
- ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+ ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
}
/* fit urb's itds into the selected schedule slot; activate as needed */
@@ -1515,14 +1652,14 @@ itd_link_urb (
list_move_tail (&itd->itd_list, &stream->td_list);
itd->stream = iso_stream_get (stream);
itd->urb = usb_get_urb (urb);
- itd_init (stream, itd);
+ itd_init (ehci, stream, itd);
}
uframe = next_uframe & 0x07;
frame = next_uframe >> 3;
itd->usecs [uframe] = stream->usecs;
- itd_patch (itd, iso_sched, packet, uframe);
+ itd_patch(ehci, itd, iso_sched, packet, uframe);
next_uframe += stream->interval;
stream->depth += stream->interval;
@@ -1570,7 +1707,7 @@ itd_complete (
urb_index = itd->index[uframe];
desc = &urb->iso_frame_desc [urb_index];
- t = le32_to_cpup (&itd->hw_transaction [uframe]);
+ t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]);
itd->hw_transaction [uframe] = 0;
stream->depth -= stream->interval;
@@ -1700,7 +1837,8 @@ done:
*/
static inline void
-sitd_sched_init (
+sitd_sched_init(
+ struct ehci_hcd *ehci,
struct ehci_iso_sched *iso_sched,
struct ehci_iso_stream *stream,
struct urb *urb
@@ -1729,7 +1867,7 @@ sitd_sched_init (
&& !(urb->transfer_flags & URB_NO_INTERRUPT))
trans |= SITD_IOC;
trans |= length << 16;
- packet->transaction = cpu_to_le32 (trans);
+ packet->transaction = cpu_to_hc32(ehci, trans);
/* might need to cross a buffer page within a td */
packet->bufp = buf;
@@ -1765,7 +1903,7 @@ sitd_urb_transaction (
if (iso_sched == NULL)
return -ENOMEM;
- sitd_sched_init (iso_sched, stream, urb);
+ sitd_sched_init(ehci, iso_sched, stream, urb);
/* allocate/init sITDs */
spin_lock_irqsave (&ehci->lock, flags);
@@ -1817,7 +1955,8 @@ sitd_urb_transaction (
/*-------------------------------------------------------------------------*/
static inline void
-sitd_patch (
+sitd_patch(
+ struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
struct ehci_sitd *sitd,
struct ehci_iso_sched *iso_sched,
@@ -1827,20 +1966,20 @@ sitd_patch (
struct ehci_iso_packet *uf = &iso_sched->packet [index];
u64 bufp = uf->bufp;
- sitd->hw_next = EHCI_LIST_END;
+ sitd->hw_next = EHCI_LIST_END(ehci);
sitd->hw_fullspeed_ep = stream->address;
sitd->hw_uframe = stream->splits;
sitd->hw_results = uf->transaction;
- sitd->hw_backpointer = EHCI_LIST_END;
+ sitd->hw_backpointer = EHCI_LIST_END(ehci);
bufp = uf->bufp;
- sitd->hw_buf [0] = cpu_to_le32 (bufp);
- sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32);
+ sitd->hw_buf[0] = cpu_to_hc32(ehci, bufp);
+ sitd->hw_buf_hi[0] = cpu_to_hc32(ehci, bufp >> 32);
- sitd->hw_buf [1] = cpu_to_le32 (uf->buf1);
+ sitd->hw_buf[1] = cpu_to_hc32(ehci, uf->buf1);
if (uf->cross)
bufp += 4096;
- sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
+ sitd->hw_buf_hi[1] = cpu_to_hc32(ehci, bufp >> 32);
sitd->index = index;
}
@@ -1853,7 +1992,7 @@ sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
ehci->pshadow [frame].sitd = sitd;
sitd->frame = frame;
wmb ();
- ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD;
+ ehci->periodic[frame] = cpu_to_hc32(ehci, sitd->sitd_dma | Q_TYPE_SITD);
}
/* fit urb's sitds into the selected schedule slot; activate as needed */
@@ -1881,7 +2020,7 @@ sitd_link_urb (
urb->dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
(next_uframe >> 3) % ehci->periodic_size,
- stream->interval, le32_to_cpu (stream->splits));
+ stream->interval, hc32_to_cpu(ehci, stream->splits));
stream->start = jiffies;
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@@ -1902,7 +2041,7 @@ sitd_link_urb (
sitd->stream = iso_stream_get (stream);
sitd->urb = usb_get_urb (urb);
- sitd_patch (stream, sitd, sched, packet);
+ sitd_patch(ehci, stream, sitd, sched, packet);
sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
sitd);
@@ -1940,7 +2079,7 @@ sitd_complete (
urb_index = sitd->index;
desc = &urb->iso_frame_desc [urb_index];
- t = le32_to_cpup (&sitd->hw_results);
+ t = hc32_to_cpup(ehci, &sitd->hw_results);
/* report transfer status */
if (t & SITD_ERRS) {
@@ -2095,7 +2234,7 @@ scan_periodic (struct ehci_hcd *ehci)
for (;;) {
union ehci_shadow q, *q_p;
- __le32 type, *hw_p;
+ __hc32 type, *hw_p;
unsigned uframes;
/* don't scan past the live uframe */
@@ -2113,7 +2252,7 @@ restart:
q_p = &ehci->pshadow [frame];
hw_p = &ehci->periodic [frame];
q.ptr = q_p->ptr;
- type = Q_NEXT_TYPE (*hw_p);
+ type = Q_NEXT_TYPE(ehci, *hw_p);
modified = 0;
while (q.ptr != NULL) {
@@ -2122,11 +2261,11 @@ restart:
int live;
live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
- switch (type) {
+ switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_QH:
/* handle any completions */
temp.qh = qh_get (q.qh);
- type = Q_NEXT_TYPE (q.qh->hw_next);
+ type = Q_NEXT_TYPE(ehci, q.qh->hw_next);
q = q.qh->qh_next;
modified = qh_completions (ehci, temp.qh);
if (unlikely (list_empty (&temp.qh->qtd_list)))
@@ -2137,10 +2276,10 @@ restart:
/* for "save place" FSTNs, look at QH entries
* in the previous frame for completions.
*/
- if (q.fstn->hw_prev != EHCI_LIST_END) {
+ if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
dbg ("ignoring completions from FSTNs");
}
- type = Q_NEXT_TYPE (q.fstn->hw_next);
+ type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
q = q.fstn->fstn_next;
break;
case Q_TYPE_ITD:
@@ -2148,11 +2287,12 @@ restart:
rmb ();
for (uf = live ? uframes : 8; uf < 8; uf++) {
if (0 == (q.itd->hw_transaction [uf]
- & ITD_ACTIVE))
+ & ITD_ACTIVE(ehci)))
continue;
q_p = &q.itd->itd_next;
hw_p = &q.itd->hw_next;
- type = Q_NEXT_TYPE (q.itd->hw_next);
+ type = Q_NEXT_TYPE(ehci,
+ q.itd->hw_next);
q = *q_p;
break;
}
@@ -2164,23 +2304,24 @@ restart:
*/
*q_p = q.itd->itd_next;
*hw_p = q.itd->hw_next;
- type = Q_NEXT_TYPE (q.itd->hw_next);
+ type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
wmb();
modified = itd_complete (ehci, q.itd);
q = *q_p;
break;
case Q_TYPE_SITD:
- if ((q.sitd->hw_results & SITD_ACTIVE)
+ if ((q.sitd->hw_results & SITD_ACTIVE(ehci))
&& live) {
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
- type = Q_NEXT_TYPE (q.sitd->hw_next);
+ type = Q_NEXT_TYPE(ehci,
+ q.sitd->hw_next);
q = *q_p;
break;
}
*q_p = q.sitd->sitd_next;
*hw_p = q.sitd->hw_next;
- type = Q_NEXT_TYPE (q.sitd->hw_next);
+ type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
wmb();
modified = sitd_complete (ehci, q.sitd);
q = *q_p;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 46fa57a520d0..2c68a04230c1 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -21,6 +21,22 @@
/* definitions used for the EHCI driver */
+/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
+ * the host controller implementation.
+ *
+ * To facilitate the strongest possible byte-order checking from "sparse"
+ * and so on, we use __leXX unless that's not practical.
+ */
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
+typedef __u32 __bitwise __hc32;
+typedef __u16 __bitwise __hc16;
+#else
+#define __hc32 __le32
+#define __hc16 __le16
+#endif
+
/* statistics can be kept for for tuning/monitoring */
struct ehci_stats {
/* irq usage */
@@ -55,6 +71,12 @@ struct ehci_hcd { /* one per controller */
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block cpufreq_transition;
+ int cpufreq_changing;
+ struct list_head split_intr_qhs;
+#endif
+
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
@@ -64,7 +86,7 @@ struct ehci_hcd { /* one per controller */
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
unsigned periodic_size;
- __le32 *periodic; /* hw periodic table */
+ __hc32 *periodic; /* hw periodic table */
dma_addr_t periodic_dma;
unsigned i_thresh; /* uframes HC might cache */
@@ -74,11 +96,14 @@ struct ehci_hcd { /* one per controller */
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
+
/* bit vectors (one bit per port) */
unsigned long bus_suspended; /* which ports were
already suspended at the start of a bus suspend */
unsigned long companion_ports; /* which ports are
dedicated to the companion controller */
+ unsigned long owned_ports; /* which ports are
+ owned by the companion during a bus suspend */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@@ -97,6 +122,7 @@ struct ehci_hcd { /* one per controller */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
+ unsigned big_endian_desc:1;
u8 sbrn; /* packed release number */
@@ -276,6 +302,12 @@ struct ehci_regs {
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
} __attribute__ ((packed));
+#define USBMODE 0x68 /* USB Device mode */
+#define USBMODE_SDIS (1<<3) /* Stream disable */
+#define USBMODE_BE (1<<2) /* BE/LE endianness select */
+#define USBMODE_CM_HC (3<<0) /* host controller mode */
+#define USBMODE_CM_IDLE (0<<0) /* idle state */
+
/* Appendix C, Debug port ... intended for use with special "debug devices"
* that can help if there's no serial console. (nonstandard enumeration.)
*/
@@ -303,7 +335,7 @@ struct ehci_dbg_port {
/*-------------------------------------------------------------------------*/
-#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
+#define QTD_NEXT(ehci, dma) cpu_to_hc32(ehci, (u32)dma)
/*
* EHCI Specification 0.95 Section 3.5
@@ -315,9 +347,9 @@ struct ehci_dbg_port {
*/
struct ehci_qtd {
/* first part defined by EHCI spec */
- __le32 hw_next; /* see EHCI 3.5.1 */
- __le32 hw_alt_next; /* see EHCI 3.5.2 */
- __le32 hw_token; /* see EHCI 3.5.3 */
+ __hc32 hw_next; /* see EHCI 3.5.1 */
+ __hc32 hw_alt_next; /* see EHCI 3.5.2 */
+ __hc32 hw_token; /* see EHCI 3.5.3 */
#define QTD_TOGGLE (1 << 31) /* data toggle */
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
#define QTD_IOC (1 << 15) /* interrupt on complete */
@@ -331,8 +363,13 @@ struct ehci_qtd {
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
#define QTD_STS_STS (1 << 1) /* split transaction state */
#define QTD_STS_PING (1 << 0) /* issue PING? */
- __le32 hw_buf [5]; /* see EHCI 3.5.4 */
- __le32 hw_buf_hi [5]; /* Appendix B */
+
+#define ACTIVE_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_ACTIVE)
+#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
+#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
+
+ __hc32 hw_buf [5]; /* see EHCI 3.5.4 */
+ __hc32 hw_buf_hi [5]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */
@@ -342,26 +379,33 @@ struct ehci_qtd {
} __attribute__ ((aligned (32)));
/* mask NakCnt+T in qh->hw_alt_next */
-#define QTD_MASK __constant_cpu_to_le32 (~0x1f)
+#define QTD_MASK(ehci) cpu_to_hc32 (ehci, ~0x1f)
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
/*-------------------------------------------------------------------------*/
/* type tag from {qh,itd,sitd,fstn}->hw_next */
-#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+#define Q_NEXT_TYPE(ehci,dma) ((dma) & cpu_to_hc32(ehci, 3 << 1))
+/*
+ * Now the following defines are not converted using the
+ * __constant_cpu_to_le32() macro anymore, since we have to support
+ * "dynamic" switching between be and le support, so that the driver
+ * can be used on one system with SoC EHCI controller using big-endian
+ * descriptors as well as a normal little-endian PCI EHCI controller.
+ */
/* values for that type tag */
-#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1)
-#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
-#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
-#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
+#define Q_TYPE_ITD (0 << 1)
+#define Q_TYPE_QH (1 << 1)
+#define Q_TYPE_SITD (2 << 1)
+#define Q_TYPE_FSTN (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
-#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+#define QH_NEXT(ehci,dma) (cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH))
/* for periodic/async schedules and qtd lists, mark end of list */
-#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */
+#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
/*
* Entries in periodic shadow table are pointers to one of four kinds
@@ -376,7 +420,7 @@ union ehci_shadow {
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
- __le32 *hw_next; /* (all types) */
+ __hc32 *hw_next; /* (all types) */
void *ptr;
};
@@ -392,23 +436,27 @@ union ehci_shadow {
struct ehci_qh {
/* first part defined by EHCI spec */
- __le32 hw_next; /* see EHCI 3.6.1 */
- __le32 hw_info1; /* see EHCI 3.6.2 */
+ __hc32 hw_next; /* see EHCI 3.6.1 */
+ __hc32 hw_info1; /* see EHCI 3.6.2 */
#define QH_HEAD 0x00008000
- __le32 hw_info2; /* see EHCI 3.6.2 */
+#define QH_INACTIVATE 0x00000080
+
+#define INACTIVATE_BIT(ehci) cpu_to_hc32(ehci, QH_INACTIVATE)
+
+ __hc32 hw_info2; /* see EHCI 3.6.2 */
#define QH_SMASK 0x000000ff
#define QH_CMASK 0x0000ff00
#define QH_HUBADDR 0x007f0000
#define QH_HUBPORT 0x3f800000
#define QH_MULT 0xc0000000
- __le32 hw_current; /* qtd list - see EHCI 3.6.4 */
+ __hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
/* qtd overlay (hardware parts of a struct ehci_qtd) */
- __le32 hw_qtd_next;
- __le32 hw_alt_next;
- __le32 hw_token;
- __le32 hw_buf [5];
- __le32 hw_buf_hi [5];
+ __hc32 hw_qtd_next;
+ __hc32 hw_alt_next;
+ __hc32 hw_token;
+ __hc32 hw_buf [5];
+ __hc32 hw_buf_hi [5];
/* the rest is HCD-private */
dma_addr_t qh_dma; /* address of qh */
@@ -418,7 +466,14 @@ struct ehci_qh {
struct ehci_qh *reclaim; /* next to reclaim */
struct ehci_hcd *ehci;
- struct kref kref;
+
+ /*
+ * Do NOT use atomic operations for QH refcounting. On some CPUs
+ * (PPC7448 for example), atomic operations cannot be performed on
+ * memory that is cache-inhibited (i.e. being used for DMA).
+ * Spinlocks are used to protect all QH fields.
+ */
+ u32 refcount;
unsigned stamp;
u8 qh_state;
@@ -437,6 +492,10 @@ struct ehci_qh {
unsigned short start; /* where polling starts */
#define NO_FRAME ((unsigned short)~0) /* pick new start */
struct usb_device *dev; /* access to TT */
+#ifdef CONFIG_CPU_FREQ
+ struct list_head split_intr_qhs; /* list of split qhs */
+ __le32 was_active; /* active bit before "i" set */
+#endif
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
@@ -445,7 +504,7 @@ struct ehci_qh {
struct ehci_iso_packet {
/* These will be copied to iTD when scheduling */
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
- __le32 transaction; /* itd->hw_transaction[i] |= */
+ __hc32 transaction; /* itd->hw_transaction[i] |= */
u8 cross; /* buf crosses pages */
/* for full speed OUT splits */
u32 buf1;
@@ -467,8 +526,8 @@ struct ehci_iso_sched {
*/
struct ehci_iso_stream {
/* first two fields match QH, but info1 == 0 */
- __le32 hw_next;
- __le32 hw_info1;
+ __hc32 hw_next;
+ __hc32 hw_info1;
u32 refcount;
u8 bEndpointAddress;
@@ -483,7 +542,7 @@ struct ehci_iso_stream {
unsigned long start; /* jiffies */
unsigned long rescheduled;
int next_uframe;
- __le32 splits;
+ __hc32 splits;
/* the rest is derived from the endpoint descriptor,
* trusting urb->interval == f(epdesc->bInterval) and
@@ -497,12 +556,12 @@ struct ehci_iso_stream {
unsigned bandwidth;
/* This is used to initialize iTD's hw_bufp fields */
- __le32 buf0;
- __le32 buf1;
- __le32 buf2;
+ __hc32 buf0;
+ __hc32 buf1;
+ __hc32 buf2;
/* this is used to initialize sITD's tt info */
- __le32 address;
+ __hc32 address;
};
/*-------------------------------------------------------------------------*/
@@ -515,8 +574,8 @@ struct ehci_iso_stream {
*/
struct ehci_itd {
/* first part defined by EHCI spec */
- __le32 hw_next; /* see EHCI 3.3.1 */
- __le32 hw_transaction [8]; /* see EHCI 3.3.2 */
+ __hc32 hw_next; /* see EHCI 3.3.1 */
+ __hc32 hw_transaction [8]; /* see EHCI 3.3.2 */
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
@@ -524,10 +583,10 @@ struct ehci_itd {
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
-#define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
+#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
- __le32 hw_bufp [7]; /* see EHCI 3.3.3 */
- __le32 hw_bufp_hi [7]; /* Appendix B */
+ __hc32 hw_bufp [7]; /* see EHCI 3.3.3 */
+ __hc32 hw_bufp_hi [7]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t itd_dma; /* for this itd */
@@ -554,11 +613,11 @@ struct ehci_itd {
*/
struct ehci_sitd {
/* first part defined by EHCI spec */
- __le32 hw_next;
+ __hc32 hw_next;
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
- __le32 hw_fullspeed_ep; /* EHCI table 3-9 */
- __le32 hw_uframe; /* EHCI table 3-10 */
- __le32 hw_results; /* EHCI table 3-11 */
+ __hc32 hw_fullspeed_ep; /* EHCI table 3-9 */
+ __hc32 hw_uframe; /* EHCI table 3-10 */
+ __hc32 hw_results; /* EHCI table 3-11 */
#define SITD_IOC (1 << 31) /* interrupt on completion */
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
#define SITD_LENGTH(x) (0x3ff & ((x)>>16))
@@ -570,11 +629,11 @@ struct ehci_sitd {
#define SITD_STS_MMF (1 << 2) /* incomplete split transaction */
#define SITD_STS_STS (1 << 1) /* split transaction state */
-#define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE)
+#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
- __le32 hw_buf [2]; /* EHCI table 3-12 */
- __le32 hw_backpointer; /* EHCI table 3-13 */
- __le32 hw_buf_hi [2]; /* Appendix B */
+ __hc32 hw_buf [2]; /* EHCI table 3-12 */
+ __hc32 hw_backpointer; /* EHCI table 3-13 */
+ __hc32 hw_buf_hi [2]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t sitd_dma;
@@ -599,8 +658,8 @@ struct ehci_sitd {
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
*/
struct ehci_fstn {
- __le32 hw_next; /* any periodic q entry */
- __le32 hw_prev; /* qh or EHCI_LIST_END */
+ __hc32 hw_next; /* any periodic q entry */
+ __hc32 hw_prev; /* qh or EHCI_LIST_END */
/* the rest is HCD-private */
dma_addr_t fstn_dma;
@@ -672,8 +731,21 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_big_endian_mmio(e) 0
#endif
-static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
- __u32 __iomem * regs)
+/*
+ * Big-endian read/write functions are arch-specific.
+ * Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the 4xx support is
+ * finally ported over.
+ */
+#if defined(CONFIG_PPC)
+#define readl_be(addr) in_be32((__force unsigned *)addr)
+#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
+#endif
+
+static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
+ __u32 __iomem * regs)
{
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
return ehci_big_endian_mmio(ehci) ?
@@ -684,8 +756,8 @@ static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
#endif
}
-static inline void ehci_writel (const struct ehci_hcd *ehci,
- const unsigned int val, __u32 __iomem *regs)
+static inline void ehci_writel(const struct ehci_hcd *ehci,
+ const unsigned int val, __u32 __iomem *regs)
{
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
ehci_big_endian_mmio(ehci) ?
@@ -698,6 +770,62 @@ static inline void ehci_writel (const struct ehci_hcd *ehci,
/*-------------------------------------------------------------------------*/
+/*
+ * The AMCC 440EPx not only implements its EHCI registers in big-endian
+ * format, but also its DMA data structures (descriptors).
+ *
+ * EHCI controllers accessed through PCI work normally (little-endian
+ * everywhere), so we won't bother supporting a BE-only mode for now.
+ */
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
+#define ehci_big_endian_desc(e) ((e)->big_endian_desc)
+
+/* cpu to ehci */
+static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
+{
+ return ehci_big_endian_desc(ehci)
+ ? (__force __hc32)cpu_to_be32(x)
+ : (__force __hc32)cpu_to_le32(x);
+}
+
+/* ehci to cpu */
+static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
+{
+ return ehci_big_endian_desc(ehci)
+ ? be32_to_cpu((__force __be32)x)
+ : le32_to_cpu((__force __le32)x);
+}
+
+static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
+{
+ return ehci_big_endian_desc(ehci)
+ ? be32_to_cpup((__force __be32 *)x)
+ : le32_to_cpup((__force __le32 *)x);
+}
+
+#else
+
+/* cpu to ehci */
+static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
+{
+ return cpu_to_le32(x);
+}
+
+/* ehci to cpu */
+static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
+{
+ return le32_to_cpu(x);
+}
+
+static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
+{
+ return le32_to_cpup(x);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 46873f2534b5..5c851a36de72 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -228,7 +228,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
struct urb, urb_list);
ptd = &ep->ptd;
len = ep->length;
- spin_lock(&urb->lock);
ep->data = (unsigned char *)urb->transfer_buffer
+ urb->actual_length;
@@ -264,7 +263,6 @@ static void preproc_atl_queue(struct isp116x *isp116x)
| PTD_EP(ep->epnum);
ptd->len = PTD_LEN(len) | PTD_DIR(dir);
ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
- spin_unlock(&urb->lock);
if (!ep->active) {
ptd->mps |= PTD_LAST_MSK;
isp116x->atl_last_dir = dir;
@@ -275,6 +273,61 @@ static void preproc_atl_queue(struct isp116x *isp116x)
}
/*
+ Take done or failed requests out of schedule. Give back
+ processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+ struct urb *urb)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+ unsigned i;
+
+ urb->hcpriv = NULL;
+ ep->error_count = 0;
+
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_SETUP;
+
+ urb_dbg(urb, "Finish");
+
+ spin_unlock(&isp116x->lock);
+ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+ spin_lock(&isp116x->lock);
+
+ /* take idle endpoints out of the schedule */
+ if (!list_empty(&ep->hep->urb_list))
+ return;
+
+ /* async deschedule */
+ if (!list_empty(&ep->schedule)) {
+ list_del_init(&ep->schedule);
+ return;
+ }
+
+ /* periodic deschedule */
+ DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+ for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+ struct isp116x_ep *temp;
+ struct isp116x_ep **prev = &isp116x->periodic[i];
+
+ while (*prev && ((temp = *prev) != ep))
+ prev = &temp->next;
+ if (*prev)
+ *prev = ep->next;
+ isp116x->load[i] -= ep->load;
+ }
+ ep->branch = PERIODIC_SIZE;
+ isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+ ep->load / ep->period;
+
+ /* switch irq type? */
+ if (!--isp116x->periodic_count) {
+ isp116x->irqenb &= ~HCuPINT_SOF;
+ isp116x->irqenb |= HCuPINT_ATL;
+ }
+}
+
+/*
Analyze transfer results, handle partial transfers and errors
*/
static void postproc_atl_queue(struct isp116x *isp116x)
@@ -284,6 +337,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
struct usb_device *udev;
struct ptd *ptd;
int short_not_ok;
+ int status;
u8 cc;
for (ep = isp116x->atl_active; ep; ep = ep->active) {
@@ -294,7 +348,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
ptd = &ep->ptd;
cc = PTD_GET_CC(ptd);
short_not_ok = 1;
- spin_lock(&urb->lock);
+ status = -EINPROGRESS;
/* Data underrun is special. For allowed underrun
we clear the error and continue as normal. For
@@ -302,47 +356,36 @@ static void postproc_atl_queue(struct isp116x *isp116x)
immediately while for control transfer,
we do a STATUS stage. */
if (cc == TD_DATAUNDERRUN) {
- if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
- DBG("Allowed data underrun\n");
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+ usb_pipecontrol(urb->pipe)) {
+ DBG("Allowed or control data underrun\n");
cc = TD_CC_NOERROR;
short_not_ok = 0;
} else {
ep->error_count = 1;
- if (usb_pipecontrol(urb->pipe))
- ep->nextpid = USB_PID_ACK;
- else
- usb_settoggle(udev, ep->epnum,
- ep->nextpid ==
- USB_PID_OUT,
- PTD_GET_TOGGLE(ptd));
+ usb_settoggle(udev, ep->epnum,
+ ep->nextpid == USB_PID_OUT,
+ PTD_GET_TOGGLE(ptd));
urb->actual_length += PTD_GET_COUNT(ptd);
- urb->status = cc_to_error[TD_DATAUNDERRUN];
- spin_unlock(&urb->lock);
- continue;
+ status = cc_to_error[TD_DATAUNDERRUN];
+ goto done;
}
}
- /* Keep underrun error through the STATUS stage */
- if (urb->status == cc_to_error[TD_DATAUNDERRUN])
- cc = TD_DATAUNDERRUN;
if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
&& (++ep->error_count >= 3 || cc == TD_CC_STALL
|| cc == TD_DATAOVERRUN)) {
- if (urb->status == -EINPROGRESS)
- urb->status = cc_to_error[cc];
+ status = cc_to_error[cc];
if (ep->nextpid == USB_PID_ACK)
ep->nextpid = 0;
- spin_unlock(&urb->lock);
- continue;
+ goto done;
}
/* According to usb spec, zero-length Int transfer signals
finishing of the urb. Hey, does this apply only
for IN endpoints? */
if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
- spin_unlock(&urb->lock);
- continue;
+ status = 0;
+ goto done;
}
/* Relax after previously failed, but later succeeded
@@ -381,8 +424,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
/* All data for this URB is transferred, let's finish */
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_ACK;
- else if (urb->status == -EINPROGRESS)
- urb->status = 0;
+ else
+ status = 0;
break;
case USB_PID_SETUP:
if (PTD_GET_ACTIVE(ptd)
@@ -402,69 +445,27 @@ static void postproc_atl_queue(struct isp116x *isp116x)
if (PTD_GET_ACTIVE(ptd)
|| (cc != TD_CC_NOERROR && cc < 0x0E))
break;
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
+ if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length <
+ urb->transfer_buffer_length)
+ status = -EREMOTEIO;
+ else
+ status = 0;
ep->nextpid = 0;
break;
default:
BUG();
}
- spin_unlock(&urb->lock);
- }
-}
-
-/*
- Take done or failed requests out of schedule. Give back
- processed urbs.
-*/
-static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
- struct urb *urb)
-__releases(isp116x->lock) __acquires(isp116x->lock)
-{
- unsigned i;
-
- urb->hcpriv = NULL;
- ep->error_count = 0;
-
- if (usb_pipecontrol(urb->pipe))
- ep->nextpid = USB_PID_SETUP;
-
- urb_dbg(urb, "Finish");
-
- spin_unlock(&isp116x->lock);
- usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
- spin_lock(&isp116x->lock);
-
- /* take idle endpoints out of the schedule */
- if (!list_empty(&ep->hep->urb_list))
- return;
-
- /* async deschedule */
- if (!list_empty(&ep->schedule)) {
- list_del_init(&ep->schedule);
- return;
- }
- /* periodic deschedule */
- DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
- for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
- struct isp116x_ep *temp;
- struct isp116x_ep **prev = &isp116x->periodic[i];
-
- while (*prev && ((temp = *prev) != ep))
- prev = &temp->next;
- if (*prev)
- *prev = ep->next;
- isp116x->load[i] -= ep->load;
- }
- ep->branch = PERIODIC_SIZE;
- isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
- ep->load / ep->period;
-
- /* switch irq type? */
- if (!--isp116x->periodic_count) {
- isp116x->irqenb &= ~HCuPINT_SOF;
- isp116x->irqenb |= HCuPINT_ATL;
+ done:
+ if (status != -EINPROGRESS) {
+ spin_lock(&urb->lock);
+ if (urb->status == -EINPROGRESS)
+ urb->status = status;
+ spin_unlock(&urb->lock);
+ }
+ if (urb->status != -EINPROGRESS)
+ finish_request(isp116x, ep, urb);
}
}
@@ -570,9 +571,6 @@ static void start_atl_transfers(struct isp116x *isp116x)
*/
static void finish_atl_transfers(struct isp116x *isp116x)
{
- struct isp116x_ep *ep;
- struct urb *urb;
-
if (!isp116x->atl_active)
return;
/* Fifo not ready? */
@@ -582,16 +580,6 @@ static void finish_atl_transfers(struct isp116x *isp116x)
atomic_inc(&isp116x->atl_finishing);
unpack_fifo(isp116x);
postproc_atl_queue(isp116x);
- for (ep = isp116x->atl_active; ep; ep = ep->active) {
- urb =
- container_of(ep->hep->urb_list.next, struct urb, urb_list);
- /* USB_PID_ACK check here avoids finishing of
- control transfers, for which TD_DATAUNDERRUN
- occured, while URB_SHORT_NOT_OK was set */
- if (urb && urb->status != -EINPROGRESS
- && ep->nextpid != USB_PID_ACK)
- finish_request(isp116x, ep, urb);
- }
atomic_dec(&isp116x->atl_finishing);
}
@@ -821,15 +809,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}
/* in case of unlink-during-submit */
- spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
- spin_unlock(&urb->lock);
finish_request(isp116x, ep, urb);
ret = 0;
goto fail;
}
urb->hcpriv = hep;
- spin_unlock(&urb->lock);
start_atl_transfers(isp116x);
fail:
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 273d5ddb72be..6f9e43e9a6ca 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -23,7 +23,7 @@
/* debug| print the main components of an URB
* small: 0) header + data packets 1) just header
*/
-static void __attribute__((unused))
+static void __maybe_unused
urb_print (struct urb * urb, char * str, int small)
{
unsigned int pipe= urb->pipe;
@@ -338,7 +338,7 @@ static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
}
/* caller MUST own hcd spinlock if verbose is set! */
-static void __attribute__((unused))
+static void __maybe_unused
ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
const struct ed *ed, int verbose)
{
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index a66637e725f3..6edf4097d2d2 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -35,15 +35,13 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/reboot.h>
+#include <linux/workqueue.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
-#ifdef CONFIG_PPC_PS3
-#include <asm/firmware.h>
-#endif
#include "../core/hcd.h"
@@ -82,6 +80,8 @@ static const char hcd_name [] = "ohci_hcd";
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
+static int ohci_restart (struct ohci_hcd *ohci);
+static void ohci_quirk_nec_worker (struct work_struct *work);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -171,11 +171,10 @@ static int ohci_urb_enqueue (
}
/* allocate the private part of the URB */
- urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+ urb_priv = kzalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
mem_flags);
if (!urb_priv)
return -ENOMEM;
- memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
INIT_LIST_HEAD (&urb_priv->pending);
urb_priv->length = size;
urb_priv->ed = ed;
@@ -510,15 +509,7 @@ static int ohci_run (struct ohci_hcd *ohci)
// flush the writes
(void) ohci_readl (ohci, &ohci->regs->control);
msleep(temp);
- temp = roothub_a (ohci);
- if (!(temp & RH_A_NPS)) {
- /* power down each port */
- for (temp = 0; temp < ohci->num_ports; temp++)
- ohci_writel (ohci, RH_PS_LSDA,
- &ohci->regs->roothub.portstatus [temp]);
- }
- // flush those writes
- (void) ohci_readl (ohci, &ohci->regs->control);
+
memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
/* 2msec timelimit here means no irqs/preempt */
@@ -659,9 +650,20 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
}
if (ints & OHCI_INTR_UE) {
- disable (ohci);
- ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
// e.g. due to PCI Master/Target Abort
+ if (ohci->flags & OHCI_QUIRK_NEC) {
+ /* Workaround for a silicon bug in some NEC chips used
+ * in Apple's PowerBooks. Adapted from Darwin code.
+ */
+ ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n");
+
+ ohci_writel (ohci, OHCI_INTR_UE, &regs->intrdisable);
+
+ schedule_work (&ohci->nec_work);
+ } else {
+ disable (ohci);
+ ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+ }
ohci_dump (ohci, 1);
ohci_usb_reset (ohci);
@@ -763,23 +765,16 @@ static void ohci_stop (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
/* must not be called from interrupt context */
-
-#ifdef CONFIG_PM
-
static int ohci_restart (struct ohci_hcd *ohci)
{
int temp;
int i;
struct urb_priv *priv;
- /* mark any devices gone, so they do nothing till khubd disconnects.
- * recycle any "live" eds/tds (and urbs) right away.
- * later, khubd disconnect processing will recycle the other state,
- * (either as disconnect/reconnect, or maybe someday as a reset).
- */
spin_lock_irq(&ohci->lock);
disable (ohci);
- usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
+
+ /* Recycle any "live" eds/tds (and urbs). */
if (!list_empty (&ohci->pending))
ohci_dbg(ohci, "abort schedule...\n");
list_for_each_entry (priv, &ohci->pending, pending) {
@@ -826,20 +821,31 @@ static int ohci_restart (struct ohci_hcd *ohci)
if ((temp = ohci_run (ohci)) < 0) {
ohci_err (ohci, "can't restart, %d\n", temp);
return temp;
- } else {
- /* here we "know" root ports should always stay powered,
- * and that if we try to turn them back on the root hub
- * will respond to CSC processing.
- */
- i = ohci->num_ports;
- while (i--)
- ohci_writel (ohci, RH_PS_PSS,
- &ohci->regs->roothub.portstatus [i]);
- ohci_dbg (ohci, "restart complete\n");
}
+ ohci_dbg(ohci, "restart complete\n");
return 0;
}
-#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* NEC workaround */
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+ struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+ int status;
+
+ status = ohci_init(ohci);
+ if (status != 0) {
+ ohci_err(ohci, "Restarting NEC controller failed "
+ "in ohci_init, %d\n", status);
+ return;
+ }
+
+ status = ohci_restart(ohci);
+ if (status != 0)
+ ohci_err(ohci, "Restarting NEC controller failed "
+ "in ohci_restart, %d\n", status);
+}
/*-------------------------------------------------------------------------*/
@@ -917,7 +923,7 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PPC_PS3
#include "ohci-ps3.c"
-#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver
+#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
#if !defined(PCI_DRIVER) && \
@@ -940,12 +946,9 @@ static int __init ohci_hcd_mod_init(void)
sizeof (struct ed), sizeof (struct td));
#ifdef PS3_SYSTEM_BUS_DRIVER
- if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
- retval = ps3_system_bus_driver_register(
- &PS3_SYSTEM_BUS_DRIVER);
- if (retval < 0)
- goto error_ps3;
- }
+ retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+ if (retval < 0)
+ goto error_ps3;
#endif
#ifdef PLATFORM_DRIVER
@@ -991,8 +994,7 @@ static int __init ohci_hcd_mod_init(void)
error_platform:
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
- if (firmware_has_feature(FW_FEATURE_PS3_LV1))
- ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
error_ps3:
#endif
return retval;
@@ -1014,8 +1016,7 @@ static void __exit ohci_hcd_mod_exit(void)
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
- if (firmware_has_feature(FW_FEATURE_PS3_LV1))
- ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
}
module_exit(ohci_hcd_mod_exit);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index bb9cc595219e..48e4b11f4d3e 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -55,8 +55,6 @@ static void dl_done_list (struct ohci_hcd *);
static void finish_unlinks (struct ohci_hcd *, u16);
#ifdef CONFIG_PM
-static int ohci_restart(struct ohci_hcd *ohci);
-
static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
__releases(ohci->lock)
__acquires(ohci->lock)
@@ -191,6 +189,9 @@ __acquires(ohci->lock)
spin_unlock_irq (&ohci->lock);
(void) ohci_init (ohci);
status = ohci_restart (ohci);
+
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
spin_lock_irq (&ohci->lock);
}
return status;
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 2f20d3dc895b..450c7b460c5a 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,6 +28,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
+ INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index ca62cb583221..a5e2eb85d073 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -111,6 +111,18 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
#endif
}
+/* Check for NEC chip and apply quirk for allegedly lost interrupts.
+ */
+static int ohci_quirk_nec(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci->flags |= OHCI_QUIRK_NEC;
+ ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
+
+ return 0;
+}
+
/* List of quirks for OHCI */
static const struct pci_device_id ohci_pci_quirks[] = {
{
@@ -134,6 +146,10 @@ static const struct pci_device_id ohci_pci_quirks[] = {
.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
},
{
+ PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB),
+ .driver_data = (unsigned long)ohci_quirk_nec,
+ },
+ {
/* Toshiba portege 4000 */
.vendor = PCI_VENDOR_ID_AL,
.device = 0x5237,
@@ -202,6 +218,42 @@ 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)
@@ -241,7 +293,10 @@ 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);
- usb_hcd_resume_root_hub(hcd);
+
+ /* FIXME: we should try to detect loss of VBUS power here */
+ prepare_for_handover(hcd);
+
return 0;
}
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index d601bbb9387b..ca2a6abbc117 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -134,7 +134,7 @@ static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct i2c_client *c;
- c = (struct i2c_client *)kzalloc(sizeof(*c), GFP_KERNEL);
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
index d7cf07288b0b..01a0caeaa6bc 100644
--- a/drivers/usb/host/ohci-ps3.c
+++ b/drivers/usb/host/ohci-ps3.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <asm/firmware.h>
#include <asm/ps3.h>
static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
@@ -75,7 +76,7 @@ static const struct hc_driver ps3_ohci_hc_driver = {
#endif
};
-static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
{
int result;
struct usb_hcd *hcd;
@@ -87,13 +88,31 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
goto fail_start;
}
+ result = ps3_open_hv_device(dev);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed: %s\n",
+ __func__, __LINE__, ps3_result(result));
+ result = -EPERM;
+ goto fail_open;
+ }
+
+ result = ps3_dma_region_create(dev->d_region);
+
+ if (result) {
+ dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
+ "(%d)\n", __func__, __LINE__, result);
+ BUG_ON("check region type");
+ goto fail_dma_region;
+ }
+
result = ps3_mmio_region_create(dev->m_region);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
__func__, __LINE__);
result = -EPERM;
- goto fail_mmio;
+ goto fail_mmio_region;
}
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
@@ -122,6 +141,11 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
hcd->rsrc_start = dev->m_region->lpar_addr;
hcd->rsrc_len = dev->m_region->len;
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
+ dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
+ __func__, __LINE__);
+
hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
if (!hcd->regs) {
@@ -155,34 +179,73 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
fail_add_hcd:
iounmap(hcd->regs);
fail_ioremap:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
fail_create_hcd:
ps3_io_irq_destroy(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
-fail_mmio:
+fail_mmio_region:
+ ps3_dma_region_free(dev->d_region);
+fail_dma_region:
+ ps3_close_hv_device(dev);
+fail_open:
fail_start:
return result;
}
-static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+static int ps3_ohci_remove (struct ps3_system_bus_device *dev)
{
+ unsigned int tmp;
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
- usb_put_hcd(hcd);
+ BUG_ON(!hcd);
+
+ dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
+ dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
+
+ tmp = hcd->irq;
+
+ usb_remove_hcd(hcd);
+
ps3_system_bus_set_driver_data(dev, NULL);
+ BUG_ON(!hcd->regs);
+ iounmap(hcd->regs);
+
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ ps3_io_irq_destroy(tmp);
+ ps3_free_mmio_region(dev->m_region);
+
+ ps3_dma_region_free(dev->d_region);
+ ps3_close_hv_device(dev);
+
return 0;
}
-MODULE_ALIAS("ps3-ohci");
+static int ps3_ohci_driver_register(struct ps3_system_bus_driver *drv)
+{
+ return firmware_has_feature(FW_FEATURE_PS3_LV1)
+ ? ps3_system_bus_driver_register(drv)
+ : 0;
+}
+
+static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv)
+{
+ if (firmware_has_feature(FW_FEATURE_PS3_LV1))
+ ps3_system_bus_driver_unregister(drv);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI);
-static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+static struct ps3_system_bus_driver ps3_ohci_driver = {
+ .core.name = "ps3-ohci-driver",
+ .core.owner = THIS_MODULE,
.match_id = PS3_MATCH_ID_OHCI,
- .core = {
- .name = "ps3-ohci-driver",
- },
- .probe = ps3_ohci_sb_probe,
- .remove = ps3_ohci_sb_remove,
+ .probe = ps3_ohci_probe,
+ .remove = ps3_ohci_remove,
+ .shutdown = ps3_ohci_remove,
};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index c2b5ecfe5e9f..4ada43cf1387 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -397,8 +397,10 @@ struct ohci_hcd {
#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */
#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
+#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
// there are also chip quirks/bugs in init logic
+ struct work_struct nec_work; /* Worker for NEC quirk */
};
/* convert between an hcd pointer and the corresponding ohci_hcd */
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
new file mode 100644
index 000000000000..d60f1985320c
--- /dev/null
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -0,0 +1,2242 @@
+/*
+ * R8A66597 HCD (Host Controller Driver)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ * Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Portions Copyright (C) 2004-2005 David Brownell
+ * Portions Copyright (C) 1999 Roman Weissgaerber
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include "../core/hcd.h"
+#include "r8a66597.h"
+
+MODULE_DESCRIPTION("R8A66597 USB Host Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+
+#define DRIVER_VERSION "29 May 2007"
+
+static const char hcd_name[] = "r8a66597_hcd";
+
+/* module parameters */
+static unsigned short clock = XTAL12;
+module_param(clock, ushort, 0644);
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+ "(default=0)");
+
+static unsigned short vif = LDRV;
+module_param(vif, ushort, 0644);
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
+
+static unsigned short endian;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
+static unsigned short irq_sense = INTL;
+module_param(irq_sense, ushort, 0644);
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
+ "(default=32)");
+
+static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
+static int r8a66597_get_frame(struct usb_hcd *hcd);
+
+/* this function must be called with interrupt disabled */
+static void enable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = r8a66597_read(r8a66597, INTENB0);
+ r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
+ r8a66597_bset(r8a66597, 1 << pipenum, reg);
+ r8a66597_write(r8a66597, tmp, INTENB0);
+}
+
+/* this function must be called with interrupt disabled */
+static void disable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
+ unsigned long reg)
+{
+ u16 tmp;
+
+ tmp = r8a66597_read(r8a66597, INTENB0);
+ r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
+ r8a66597_bclr(r8a66597, 1 << pipenum, reg);
+ r8a66597_write(r8a66597, tmp, INTENB0);
+}
+
+static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address,
+ u16 usbspd, u8 upphub, u8 hubport, int port)
+{
+ u16 val;
+ unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
+
+ val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
+ r8a66597_write(r8a66597, val, devadd_reg);
+}
+
+static int enable_controller(struct r8a66597 *r8a66597)
+{
+ u16 tmp;
+ int i = 0;
+
+ do {
+ r8a66597_write(r8a66597, USBE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ err("register access fail.");
+ return -ENXIO;
+ }
+ } while ((tmp & USBE) != USBE);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
+
+ i = 0;
+ r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+ do {
+ msleep(1);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 500) {
+ err("register access fail.");
+ return -ENXIO;
+ }
+ } while ((tmp & SCKE) != SCKE);
+
+ r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0);
+ r8a66597_bset(r8a66597, DRPD, SYSCFG1);
+
+ 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);
+ r8a66597_bset(r8a66597, irq_sense & INTL, SOFCFG);
+ 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);
+
+ return 0;
+}
+
+static void disable_controller(struct r8a66597 *r8a66597)
+{
+ u16 tmp;
+
+ 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);
+
+ r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+ udelay(1);
+ r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+ r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+}
+
+static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
+ struct usb_device *udev)
+{
+ struct r8a66597_device *dev;
+
+ if (udev->parent && udev->parent->devnum != 1)
+ udev = udev->parent;
+
+ dev = dev_get_drvdata(&udev->dev);
+ if (dev)
+ return dev->address;
+ else
+ return 0;
+}
+
+static int is_child_device(char *devpath)
+{
+ return (devpath[2] ? 1 : 0);
+}
+
+static int is_hub_limit(char *devpath)
+{
+ return ((strlen(devpath) >= 4) ? 1 : 0);
+}
+
+static void get_port_number(char *devpath, u16 *root_port, u16 *hub_port)
+{
+ if (root_port) {
+ *root_port = (devpath[0] & 0x0F) - 1;
+ if (*root_port >= R8A66597_MAX_ROOT_HUB)
+ err("illegal root port number");
+ }
+ if (hub_port)
+ *hub_port = devpath[2] & 0x0F;
+}
+
+static u16 get_r8a66597_usb_speed(enum usb_device_speed speed)
+{
+ u16 usbspd = 0;
+
+ switch (speed) {
+ case USB_SPEED_LOW:
+ usbspd = LSMODE;
+ break;
+ case USB_SPEED_FULL:
+ usbspd = FSMODE;
+ break;
+ case USB_SPEED_HIGH:
+ usbspd = HSMODE;
+ break;
+ default:
+ err("unknown speed");
+ break;
+ }
+
+ return usbspd;
+}
+
+static void set_child_connect_map(struct r8a66597 *r8a66597, int address)
+{
+ int idx;
+
+ idx = address / 32;
+ r8a66597->child_connect_map[idx] |= 1 << (address % 32);
+}
+
+static void put_child_connect_map(struct r8a66597 *r8a66597, int address)
+{
+ int idx;
+
+ idx = address / 32;
+ r8a66597->child_connect_map[idx] &= ~(1 << (address % 32));
+}
+
+static void set_pipe_reg_addr(struct r8a66597_pipe *pipe, u8 dma_ch)
+{
+ u16 pipenum = pipe->info.pipenum;
+ unsigned long fifoaddr[] = {D0FIFO, D1FIFO, CFIFO};
+ unsigned long fifosel[] = {D0FIFOSEL, D1FIFOSEL, CFIFOSEL};
+ unsigned long fifoctr[] = {D0FIFOCTR, D1FIFOCTR, CFIFOCTR};
+
+ if (dma_ch > R8A66597_PIPE_NO_DMA) /* dma fifo not use? */
+ dma_ch = R8A66597_PIPE_NO_DMA;
+
+ pipe->fifoaddr = fifoaddr[dma_ch];
+ pipe->fifosel = fifosel[dma_ch];
+ pipe->fifoctr = fifoctr[dma_ch];
+
+ if (pipenum == 0)
+ pipe->pipectr = DCPCTR;
+ else
+ pipe->pipectr = get_pipectr_addr(pipenum);
+
+ if (check_bulk_or_isoc(pipenum)) {
+ pipe->pipetre = get_pipetre_addr(pipenum);
+ pipe->pipetrn = get_pipetrn_addr(pipenum);
+ } else {
+ pipe->pipetre = 0;
+ pipe->pipetrn = 0;
+ }
+}
+
+static struct r8a66597_device *
+get_urb_to_r8a66597_dev(struct r8a66597 *r8a66597, struct urb *urb)
+{
+ if (usb_pipedevice(urb->pipe) == 0)
+ return &r8a66597->device0;
+
+ return dev_get_drvdata(&urb->dev->dev);
+}
+
+static int make_r8a66597_device(struct r8a66597 *r8a66597,
+ struct urb *urb, u8 addr)
+{
+ struct r8a66597_device *dev;
+ int usb_address = urb->setup_packet[2]; /* urb->pipe is address 0 */
+
+ dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
+ if (dev == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(&urb->dev->dev, dev);
+ dev->udev = urb->dev;
+ dev->address = addr;
+ dev->usb_address = usb_address;
+ dev->state = USB_STATE_ADDRESS;
+ dev->ep_in_toggle = 0;
+ dev->ep_out_toggle = 0;
+ INIT_LIST_HEAD(&dev->device_list);
+ list_add_tail(&dev->device_list, &r8a66597->child_device);
+
+ get_port_number(urb->dev->devpath, &dev->root_port, &dev->hub_port);
+ if (!is_child_device(urb->dev->devpath))
+ r8a66597->root_hub[dev->root_port].dev = dev;
+
+ set_devadd_reg(r8a66597, dev->address,
+ get_r8a66597_usb_speed(urb->dev->speed),
+ get_parent_r8a66597_address(r8a66597, urb->dev),
+ dev->hub_port, dev->root_port);
+
+ return 0;
+}
+
+/* this function must be called with interrupt disabled */
+static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
+{
+ u8 addr; /* R8A66597's address */
+ struct r8a66597_device *dev;
+
+ if (is_hub_limit(urb->dev->devpath)) {
+ err("Externel hub limit reached.");
+ return 0;
+ }
+
+ dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+ if (dev && dev->state >= USB_STATE_ADDRESS)
+ return dev->address;
+
+ for (addr = 1; addr <= R8A66597_MAX_DEVICE; addr++) {
+ if (r8a66597->address_map & (1 << addr))
+ continue;
+
+ dbg("alloc_address: r8a66597_addr=%d", addr);
+ r8a66597->address_map |= 1 << addr;
+
+ if (make_r8a66597_device(r8a66597, urb, addr) < 0)
+ return 0;
+
+ return addr;
+ }
+
+ err("cannot communicate with a USB device more than 10.(%x)",
+ r8a66597->address_map);
+
+ return 0;
+}
+
+/* this function must be called with interrupt disabled */
+static void free_usb_address(struct r8a66597 *r8a66597,
+ struct r8a66597_device *dev)
+{
+ int port;
+
+ if (!dev)
+ return;
+
+ dbg("free_addr: addr=%d", dev->address);
+
+ dev->state = USB_STATE_DEFAULT;
+ r8a66597->address_map &= ~(1 << dev->address);
+ dev->address = 0;
+ dev_set_drvdata(&dev->udev->dev, NULL);
+ list_del(&dev->device_list);
+ kfree(dev);
+
+ for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+ if (r8a66597->root_hub[port].dev == dev) {
+ r8a66597->root_hub[port].dev = NULL;
+ break;
+ }
+ }
+}
+
+static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
+ u16 mask, u16 loop)
+{
+ u16 tmp;
+ int i = 0;
+
+ do {
+ tmp = r8a66597_read(r8a66597, reg);
+ if (i++ > 1000000) {
+ err("register%lx, loop %x is timeout", reg, loop);
+ break;
+ }
+ ndelay(1);
+ } while ((tmp & mask) != loop);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_start(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe)
+{
+ u16 tmp;
+
+ tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID;
+ if ((pipe->info.pipenum != 0) & ((tmp & PID_STALL) != 0)) /* stall? */
+ r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr);
+ r8a66597_mdfy(r8a66597, PID_BUF, PID, pipe->pipectr);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_stop(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe)
+{
+ u16 tmp;
+
+ tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID;
+ if ((tmp & PID_STALL11) != PID_STALL11) /* force stall? */
+ r8a66597_mdfy(r8a66597, PID_STALL, PID, pipe->pipectr);
+ r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr);
+ r8a66597_reg_wait(r8a66597, pipe->pipectr, PBUSY, 0);
+}
+
+/* this function must be called with interrupt disabled */
+static void clear_all_buffer(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe *pipe)
+{
+ u16 tmp;
+
+ if (!pipe || pipe->info.pipenum == 0)
+ return;
+
+ pipe_stop(r8a66597, pipe);
+ r8a66597_bset(r8a66597, ACLRM, pipe->pipectr);
+ tmp = r8a66597_read(r8a66597, pipe->pipectr);
+ tmp = r8a66597_read(r8a66597, pipe->pipectr);
+ tmp = r8a66597_read(r8a66597, pipe->pipectr);
+ r8a66597_bclr(r8a66597, ACLRM, pipe->pipectr);
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_pipe_toggle(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe *pipe, int toggle)
+{
+ if (toggle)
+ r8a66597_bset(r8a66597, SQSET, pipe->pipectr);
+ else
+ r8a66597_bset(r8a66597, SQCLR, pipe->pipectr);
+}
+
+/* this function must be called with interrupt disabled */
+static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
+}
+
+/* this function must be called with interrupt disabled */
+static inline void fifo_change_from_pipe(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe *pipe)
+{
+ cfifo_change(r8a66597, 0);
+ r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D0FIFOSEL);
+ r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D1FIFOSEL);
+
+ r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum, MBW | CURPIPE,
+ pipe->fifosel);
+ r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum);
+}
+
+static u16 r8a66597_get_pipenum(struct urb *urb, struct usb_host_endpoint *hep)
+{
+ struct r8a66597_pipe *pipe = hep->hcpriv;
+
+ if (usb_pipeendpoint(urb->pipe) == 0)
+ return 0;
+ else
+ return pipe->info.pipenum;
+}
+
+static u16 get_urb_to_r8a66597_addr(struct r8a66597 *r8a66597, struct urb *urb)
+{
+ struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+
+ return (usb_pipedevice(urb->pipe) == 0) ? 0 : dev->address;
+}
+
+static unsigned short *get_toggle_pointer(struct r8a66597_device *dev,
+ int urb_pipe)
+{
+ if (!dev)
+ return NULL;
+
+ return usb_pipein(urb_pipe) ? &dev->ep_in_toggle : &dev->ep_out_toggle;
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_toggle_set(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe *pipe,
+ struct urb *urb, int set)
+{
+ struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+ unsigned char endpoint = usb_pipeendpoint(urb->pipe);
+ unsigned short *toggle = get_toggle_pointer(dev, urb->pipe);
+
+ if (!toggle)
+ return;
+
+ if (set)
+ *toggle |= 1 << endpoint;
+ else
+ *toggle &= ~(1 << endpoint);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_toggle_save(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe *pipe,
+ struct urb *urb)
+{
+ if (r8a66597_read(r8a66597, pipe->pipectr) & SQMON)
+ pipe_toggle_set(r8a66597, pipe, urb, 1);
+ else
+ pipe_toggle_set(r8a66597, pipe, urb, 0);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_toggle_restore(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe *pipe,
+ struct urb *urb)
+{
+ struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+ unsigned char endpoint = usb_pipeendpoint(urb->pipe);
+ unsigned short *toggle = get_toggle_pointer(dev, urb->pipe);
+
+ if (!toggle)
+ return;
+
+ r8a66597_pipe_toggle(r8a66597, pipe, *toggle & (1 << endpoint));
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_buffer_setting(struct r8a66597 *r8a66597,
+ struct r8a66597_pipe_info *info)
+{
+ u16 val = 0;
+
+ if (info->pipenum == 0)
+ return;
+
+ r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));
+ r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));
+ r8a66597_write(r8a66597, info->pipenum, PIPESEL);
+ if (!info->dir_in)
+ val |= R8A66597_DIR;
+ if (info->type == R8A66597_BULK && info->dir_in)
+ val |= R8A66597_DBLB | R8A66597_SHTNAK;
+ val |= info->type | info->epnum;
+ r8a66597_write(r8a66597, val, PIPECFG);
+
+ r8a66597_write(r8a66597, (info->buf_bsize << 10) | (info->bufnum),
+ 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)
+{
+ struct r8a66597_pipe_info *info;
+ struct urb *urb = td->urb;
+
+ if (td->pipenum > 0) {
+ info = &td->pipe->info;
+ cfifo_change(r8a66597, 0);
+ pipe_buffer_setting(r8a66597, info);
+
+ if (!usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe)) &&
+ !usb_pipecontrol(urb->pipe)) {
+ r8a66597_pipe_toggle(r8a66597, td->pipe, 0);
+ pipe_toggle_set(r8a66597, td->pipe, urb, 0);
+ clear_all_buffer(r8a66597, td->pipe);
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe), 1);
+ }
+ pipe_toggle_restore(r8a66597, td->pipe, urb);
+ }
+}
+
+/* this function must be called with interrupt disabled */
+static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
+ struct usb_endpoint_descriptor *ep)
+{
+ u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
+
+ memset(array, 0, sizeof(array));
+ switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ array[i++] = 4;
+ else {
+ array[i++] = 3;
+ array[i++] = 5;
+ }
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+ array[i++] = 6;
+ array[i++] = 7;
+ array[i++] = 8;
+ } else
+ array[i++] = 9;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ array[i++] = 2;
+ else
+ array[i++] = 1;
+ break;
+ default:
+ err("Illegal type");
+ return 0;
+ }
+
+ i = 1;
+ min = array[0];
+ while (array[i] != 0) {
+ if (r8a66597->pipe_cnt[min] > r8a66597->pipe_cnt[array[i]])
+ min = array[i];
+ i++;
+ }
+
+ return min;
+}
+
+static u16 get_r8a66597_type(__u8 type)
+{
+ u16 r8a66597_type;
+
+ switch (type) {
+ case USB_ENDPOINT_XFER_BULK:
+ r8a66597_type = R8A66597_BULK;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ r8a66597_type = R8A66597_INT;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ r8a66597_type = R8A66597_ISO;
+ break;
+ default:
+ err("Illegal type");
+ r8a66597_type = 0x0000;
+ break;
+ }
+
+ return r8a66597_type;
+}
+
+static u16 get_bufnum(u16 pipenum)
+{
+ u16 bufnum = 0;
+
+ if (pipenum == 0)
+ bufnum = 0;
+ else if (check_bulk_or_isoc(pipenum))
+ bufnum = 8 + (pipenum - 1) * R8A66597_BUF_BSIZE*2;
+ else if (check_interrupt(pipenum))
+ bufnum = 4 + (pipenum - 6);
+ else
+ err("Illegal pipenum (%d)", pipenum);
+
+ return bufnum;
+}
+
+static u16 get_buf_bsize(u16 pipenum)
+{
+ u16 buf_bsize = 0;
+
+ if (pipenum == 0)
+ buf_bsize = 3;
+ else if (check_bulk_or_isoc(pipenum))
+ buf_bsize = R8A66597_BUF_BSIZE - 1;
+ else if (check_interrupt(pipenum))
+ buf_bsize = 0;
+ else
+ err("Illegal pipenum (%d)", pipenum);
+
+ return buf_bsize;
+}
+
+/* this function must be called with interrupt disabled */
+static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
+ struct r8a66597_device *dev,
+ struct r8a66597_pipe *pipe,
+ struct urb *urb)
+{
+ int i;
+ struct r8a66597_pipe_info *info = &pipe->info;
+
+ if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) {
+ for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) {
+ if ((r8a66597->dma_map & (1 << i)) != 0)
+ continue;
+
+ info("address %d, EndpointAddress 0x%02x use DMA FIFO",
+ usb_pipedevice(urb->pipe),
+ info->dir_in ? USB_ENDPOINT_DIR_MASK + info->epnum
+ : info->epnum);
+
+ r8a66597->dma_map |= 1 << i;
+ dev->dma_map |= 1 << i;
+ set_pipe_reg_addr(pipe, i);
+
+ cfifo_change(r8a66597, 0);
+ r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum,
+ MBW | CURPIPE, pipe->fifosel);
+
+ r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE,
+ pipe->info.pipenum);
+ r8a66597_bset(r8a66597, BCLR, pipe->fifoctr);
+ break;
+ }
+ }
+}
+
+/* this function must be called with interrupt disabled */
+static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,
+ struct usb_host_endpoint *hep,
+ struct r8a66597_pipe_info *info)
+{
+ struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+ struct r8a66597_pipe *pipe = hep->hcpriv;
+
+ dbg("enable_pipe:");
+
+ pipe->info = *info;
+ set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA);
+ r8a66597->pipe_cnt[pipe->info.pipenum]++;
+ dev->pipe_cnt[pipe->info.pipenum]++;
+
+ enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb);
+}
+
+/* this function must be called with interrupt disabled */
+static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
+{
+ struct r8a66597_td *td, *next;
+ struct urb *urb;
+ struct list_head *list = &r8a66597->pipe_queue[pipenum];
+
+ if (list_empty(list))
+ return;
+
+ list_for_each_entry_safe(td, next, list, queue) {
+ if (!td)
+ continue;
+ if (td->address != address)
+ continue;
+
+ urb = td->urb;
+ list_del(&td->queue);
+ kfree(td);
+
+ if (urb) {
+ urb->status = -ENODEV;
+ urb->hcpriv = NULL;
+ spin_unlock(&r8a66597->lock);
+ usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+ spin_lock(&r8a66597->lock);
+ }
+ break;
+ }
+}
+
+/* this function must be called with interrupt disabled */
+static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597,
+ struct r8a66597_device *dev)
+{
+ int check_ep0 = 0;
+ u16 pipenum;
+
+ if (!dev)
+ return;
+
+ for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ if (!dev->pipe_cnt[pipenum])
+ continue;
+
+ if (!check_ep0) {
+ check_ep0 = 1;
+ force_dequeue(r8a66597, 0, dev->address);
+ }
+
+ r8a66597->pipe_cnt[pipenum] -= dev->pipe_cnt[pipenum];
+ dev->pipe_cnt[pipenum] = 0;
+ force_dequeue(r8a66597, pipenum, dev->address);
+ }
+
+ dbg("disable_pipe");
+
+ r8a66597->dma_map &= ~(dev->dma_map);
+ dev->dma_map = 0;
+}
+
+/* this function must be called with interrupt disabled */
+static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
+ struct usb_host_endpoint *hep,
+ struct usb_endpoint_descriptor *ep)
+{
+ struct r8a66597_pipe_info info;
+
+ info.pipenum = get_empty_pipenum(r8a66597, ep);
+ info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
+ info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+ info.maxpacket = ep->wMaxPacketSize;
+ info.type = get_r8a66597_type(ep->bmAttributes
+ & USB_ENDPOINT_XFERTYPE_MASK);
+ info.bufnum = get_bufnum(info.pipenum);
+ info.buf_bsize = get_buf_bsize(info.pipenum);
+ info.interval = ep->bInterval;
+ if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ info.dir_in = 1;
+ else
+ info.dir_in = 0;
+
+ enable_r8a66597_pipe(r8a66597, urb, hep, &info);
+}
+
+static void init_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
+{
+ struct r8a66597_device *dev;
+
+ dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+ dev->state = USB_STATE_CONFIGURED;
+}
+
+static void pipe_irq_enable(struct r8a66597 *r8a66597, struct urb *urb,
+ u16 pipenum)
+{
+ if (pipenum == 0 && usb_pipeout(urb->pipe))
+ enable_irq_empty(r8a66597, pipenum);
+ else
+ enable_irq_ready(r8a66597, pipenum);
+
+ if (!usb_pipeisoc(urb->pipe))
+ enable_irq_nrdy(r8a66597, pipenum);
+}
+
+static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ disable_irq_ready(r8a66597, pipenum);
+ disable_irq_nrdy(r8a66597, pipenum);
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
+{
+ r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
+ | (1 << USB_PORT_FEAT_C_CONNECTION);
+ r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
+ r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port)
+{
+ u16 speed = get_rh_usb_speed(r8a66597, port);
+ struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+
+ if (speed == HSMODE)
+ rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED);
+ else if (speed == LSMODE)
+ rh->port |= (1 << USB_PORT_FEAT_LOWSPEED);
+
+ rh->port &= ~(1 << USB_PORT_FEAT_RESET);
+ rh->port |= 1 << USB_PORT_FEAT_ENABLE;
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port)
+{
+ struct r8a66597_device *dev = r8a66597->root_hub[port].dev;
+
+ r8a66597->root_hub[port].port &= ~(1 << USB_PORT_FEAT_CONNECTION);
+ r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_C_CONNECTION);
+
+ disable_r8a66597_pipe_all(r8a66597, dev);
+ free_usb_address(r8a66597, dev);
+
+ r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_setup_packet(struct r8a66597 *r8a66597,
+ struct r8a66597_td *td)
+{
+ int i;
+ u16 *p = (u16 *)td->urb->setup_packet;
+ unsigned long setup_addr = USBREQ;
+
+ r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
+ DCPMAXP);
+ r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
+
+ for (i = 0; i < 4; i++) {
+ r8a66597_write(r8a66597, p[i], setup_addr);
+ setup_addr += 2;
+ }
+ r8a66597_write(r8a66597, SUREQ, DCPCTR);
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_packet_read(struct r8a66597 *r8a66597,
+ struct r8a66597_td *td)
+{
+ struct urb *urb = td->urb;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ if (urb->actual_length == 0) {
+ r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ }
+ pipe_irq_disable(r8a66597, td->pipenum);
+ pipe_start(r8a66597, td->pipe);
+ pipe_irq_enable(r8a66597, urb, td->pipenum);
+ } else {
+ if (urb->actual_length == 0) {
+ pipe_irq_disable(r8a66597, td->pipenum);
+ pipe_setting(r8a66597, td);
+ pipe_stop(r8a66597, td->pipe);
+ r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
+
+ if (td->pipe->pipetre) {
+ r8a66597_write(r8a66597, TRCLR,
+ td->pipe->pipetre);
+ r8a66597_write(r8a66597,
+ (urb->transfer_buffer_length
+ + td->maxpacket - 1)
+ / td->maxpacket,
+ td->pipe->pipetrn);
+ r8a66597_bset(r8a66597, TRENB,
+ td->pipe->pipetre);
+ }
+
+ pipe_start(r8a66597, td->pipe);
+ pipe_irq_enable(r8a66597, urb, td->pipenum);
+ }
+ }
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_packet_write(struct r8a66597 *r8a66597,
+ struct r8a66597_td *td)
+{
+ u16 tmp;
+ struct urb *urb = td->urb;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ pipe_stop(r8a66597, td->pipe);
+ r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ if (urb->actual_length == 0) {
+ r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ }
+ } else {
+ if (urb->actual_length == 0)
+ pipe_setting(r8a66597, td);
+ if (td->pipe->pipetre)
+ r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
+ }
+ r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
+
+ fifo_change_from_pipe(r8a66597, td->pipe);
+ tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
+ if (unlikely((tmp & FRDY) == 0))
+ pipe_irq_enable(r8a66597, urb, td->pipenum);
+ else
+ packet_write(r8a66597, td->pipenum);
+ pipe_start(r8a66597, td->pipe);
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_status_packet(struct r8a66597 *r8a66597,
+ struct r8a66597_td *td)
+{
+ struct urb *urb = td->urb;
+
+ r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+ pipe_stop(r8a66597, td->pipe);
+
+ if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
+ r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ r8a66597_write(r8a66597, BVAL, CFIFOCTR);
+ enable_irq_empty(r8a66597, 0);
+ } else {
+ r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ enable_irq_ready(r8a66597, 0);
+ }
+ enable_irq_nrdy(r8a66597, 0);
+ pipe_start(r8a66597, td->pipe);
+}
+
+/* this function must be called with interrupt disabled */
+static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
+{
+ BUG_ON(!td);
+
+ switch (td->type) {
+ case USB_PID_SETUP:
+ if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+ td->set_address = 1;
+ td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
+ td->urb);
+ if (td->urb->setup_packet[2] == 0)
+ return -EPIPE;
+ }
+ prepare_setup_packet(r8a66597, td);
+ break;
+ case USB_PID_IN:
+ prepare_packet_read(r8a66597, td);
+ break;
+ case USB_PID_OUT:
+ prepare_packet_write(r8a66597, td);
+ break;
+ case USB_PID_ACK:
+ prepare_status_packet(r8a66597, td);
+ break;
+ default:
+ err("invalid type.");
+ break;
+ }
+
+ return 0;
+}
+
+static int check_transfer_finish(struct r8a66597_td *td, struct urb *urb)
+{
+ if (usb_pipeisoc(urb->pipe)) {
+ if (urb->number_of_packets == td->iso_cnt)
+ return 1;
+ }
+
+ /* control or bulk or interrupt */
+ if ((urb->transfer_buffer_length <= urb->actual_length) ||
+ (td->short_packet) || (td->zero_packet))
+ return 1;
+
+ return 0;
+}
+
+/* this function must be called with interrupt disabled */
+static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
+{
+ unsigned long time;
+
+ BUG_ON(!td);
+
+ if (!list_empty(&r8a66597->pipe_queue[td->pipenum]) &&
+ !usb_pipecontrol(td->urb->pipe) && usb_pipein(td->urb->pipe)) {
+ r8a66597->timeout_map |= 1 << td->pipenum;
+ switch (usb_pipetype(td->urb->pipe)) {
+ case PIPE_INTERRUPT:
+ case PIPE_ISOCHRONOUS:
+ time = 30;
+ break;
+ default:
+ time = 300;
+ break;
+ }
+
+ mod_timer(&r8a66597->td_timer[td->pipenum],
+ jiffies + msecs_to_jiffies(time));
+ }
+}
+
+/* this function must be called with interrupt disabled */
+static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+ u16 pipenum, struct urb *urb)
+{
+ int restart = 0;
+ struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
+
+ r8a66597->timeout_map &= ~(1 << pipenum);
+
+ if (likely(td)) {
+ if (td->set_address && urb->status != 0)
+ r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
+
+ pipe_toggle_save(r8a66597, td->pipe, urb);
+ list_del(&td->queue);
+ kfree(td);
+ }
+
+ if (!list_empty(&r8a66597->pipe_queue[pipenum]))
+ restart = 1;
+
+ if (likely(urb)) {
+ if (usb_pipeisoc(urb->pipe))
+ urb->start_frame = r8a66597_get_frame(hcd);
+
+ urb->hcpriv = NULL;
+ spin_unlock(&r8a66597->lock);
+ usb_hcd_giveback_urb(hcd, urb);
+ spin_lock(&r8a66597->lock);
+ }
+
+ if (restart) {
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (unlikely(!td))
+ return;
+
+ start_transfer(r8a66597, td);
+ set_td_timer(r8a66597, td);
+ }
+}
+
+/* this function must be called with interrupt disabled */
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+ u16 pipenum, struct urb *urb)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
+{
+ done(r8a66597, td, pipenum, urb);
+}
+
+static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ u16 tmp;
+ int rcv_len, bufsize, urb_len, size;
+ u16 *buf;
+ struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
+ struct urb *urb;
+ int finish = 0;
+
+ if (unlikely(!td))
+ return;
+ urb = td->urb;
+
+ fifo_change_from_pipe(r8a66597, td->pipe);
+ tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
+ if (unlikely((tmp & FRDY) == 0)) {
+ urb->status = -EPIPE;
+ pipe_stop(r8a66597, td->pipe);
+ pipe_irq_disable(r8a66597, pipenum);
+ err("in fifo not ready (%d)", pipenum);
+ finish_request(r8a66597, td, pipenum, td->urb);
+ return;
+ }
+
+ /* prepare parameters */
+ rcv_len = tmp & DTLN;
+ bufsize = td->maxpacket;
+ if (usb_pipeisoc(urb->pipe)) {
+ buf = (u16 *)(urb->transfer_buffer +
+ urb->iso_frame_desc[td->iso_cnt].offset);
+ urb_len = urb->iso_frame_desc[td->iso_cnt].length;
+ } else {
+ buf = (void *)urb->transfer_buffer + urb->actual_length;
+ urb_len = urb->transfer_buffer_length - urb->actual_length;
+ }
+ if (rcv_len < bufsize)
+ size = min(rcv_len, urb_len);
+ else
+ size = min(bufsize, urb_len);
+
+ /* update parameters */
+ urb->actual_length += size;
+ if (rcv_len == 0)
+ td->zero_packet = 1;
+ if ((size % td->maxpacket) > 0) {
+ td->short_packet = 1;
+ if (urb->transfer_buffer_length != urb->actual_length &&
+ urb->transfer_flags & URB_SHORT_NOT_OK)
+ td->urb->status = -EREMOTEIO;
+ }
+ if (usb_pipeisoc(urb->pipe)) {
+ urb->iso_frame_desc[td->iso_cnt].actual_length = size;
+ urb->iso_frame_desc[td->iso_cnt].status = 0;
+ td->iso_cnt++;
+ }
+
+ /* check transfer finish */
+ if (check_transfer_finish(td, urb)) {
+ pipe_stop(r8a66597, td->pipe);
+ pipe_irq_disable(r8a66597, pipenum);
+ finish = 1;
+ }
+
+ /* read fifo */
+ if (urb->transfer_buffer) {
+ if (size == 0)
+ r8a66597_write(r8a66597, BCLR, td->pipe->fifoctr);
+ else
+ r8a66597_read_fifo(r8a66597, td->pipe->fifoaddr,
+ buf, size);
+ }
+
+ if (finish && pipenum != 0) {
+ if (td->urb->status == -EINPROGRESS)
+ td->urb->status = 0;
+ finish_request(r8a66597, td, pipenum, urb);
+ }
+}
+
+static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ u16 tmp;
+ int bufsize, size;
+ u16 *buf;
+ struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
+ struct urb *urb;
+
+ if (unlikely(!td))
+ return;
+ urb = td->urb;
+
+ fifo_change_from_pipe(r8a66597, td->pipe);
+ tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
+ if (unlikely((tmp & FRDY) == 0)) {
+ urb->status = -EPIPE;
+ pipe_stop(r8a66597, td->pipe);
+ pipe_irq_disable(r8a66597, pipenum);
+ err("out write fifo not ready. (%d)", pipenum);
+ finish_request(r8a66597, td, pipenum, td->urb);
+ return;
+ }
+
+ /* prepare parameters */
+ bufsize = td->maxpacket;
+ if (usb_pipeisoc(urb->pipe)) {
+ buf = (u16 *)(urb->transfer_buffer +
+ urb->iso_frame_desc[td->iso_cnt].offset);
+ size = min(bufsize,
+ (int)urb->iso_frame_desc[td->iso_cnt].length);
+ } else {
+ buf = (u16 *)(urb->transfer_buffer + urb->actual_length);
+ size = min((int)bufsize,
+ urb->transfer_buffer_length - urb->actual_length);
+ }
+
+ /* write fifo */
+ if (pipenum > 0)
+ r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
+ if (urb->transfer_buffer) {
+ r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
+ if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
+ r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr);
+ }
+
+ /* update parameters */
+ urb->actual_length += size;
+ if (usb_pipeisoc(urb->pipe)) {
+ urb->iso_frame_desc[td->iso_cnt].actual_length = size;
+ urb->iso_frame_desc[td->iso_cnt].status = 0;
+ td->iso_cnt++;
+ }
+
+ /* check transfer finish */
+ if (check_transfer_finish(td, urb)) {
+ disable_irq_ready(r8a66597, pipenum);
+ enable_irq_empty(r8a66597, pipenum);
+ if (!usb_pipeisoc(urb->pipe))
+ enable_irq_nrdy(r8a66597, pipenum);
+ } else
+ pipe_irq_enable(r8a66597, urb, pipenum);
+}
+
+
+static void check_next_phase(struct r8a66597 *r8a66597)
+{
+ struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
+ struct urb *urb;
+ u8 finish = 0;
+
+ if (unlikely(!td))
+ return;
+ urb = td->urb;
+
+ switch (td->type) {
+ case USB_PID_IN:
+ case USB_PID_OUT:
+ if (urb->status != -EINPROGRESS) {
+ finish = 1;
+ break;
+ }
+ if (check_transfer_finish(td, urb))
+ td->type = USB_PID_ACK;
+ break;
+ case USB_PID_SETUP:
+ if (urb->status != -EINPROGRESS)
+ finish = 1;
+ else if (urb->transfer_buffer_length == urb->actual_length) {
+ td->type = USB_PID_ACK;
+ urb->status = 0;
+ } else if (usb_pipeout(urb->pipe))
+ td->type = USB_PID_OUT;
+ else
+ td->type = USB_PID_IN;
+ break;
+ case USB_PID_ACK:
+ finish = 1;
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+ break;
+ }
+
+ if (finish)
+ finish_request(r8a66597, td, 0, urb);
+ else
+ start_transfer(r8a66597, td);
+}
+
+static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+{
+ struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
+
+ if (td && td->urb) {
+ u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
+
+ if (pid == PID_NAK)
+ td->urb->status = -ECONNRESET;
+ else
+ td->urb->status = -EPIPE;
+ }
+}
+
+static void irq_pipe_ready(struct r8a66597 *r8a66597)
+{
+ u16 check;
+ u16 pipenum;
+ u16 mask;
+ struct r8a66597_td *td;
+
+ mask = r8a66597_read(r8a66597, BRDYSTS)
+ & r8a66597_read(r8a66597, BRDYENB);
+ r8a66597_write(r8a66597, ~mask, BRDYSTS);
+ if (mask & BRDY0) {
+ td = r8a66597_get_td(r8a66597, 0);
+ if (td && td->type == USB_PID_IN)
+ packet_read(r8a66597, 0);
+ else
+ pipe_irq_disable(r8a66597, 0);
+ check_next_phase(r8a66597);
+ }
+
+ for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if (mask & check) {
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (unlikely(!td))
+ continue;
+
+ if (td->type == USB_PID_IN)
+ packet_read(r8a66597, pipenum);
+ else if (td->type == USB_PID_OUT)
+ packet_write(r8a66597, pipenum);
+ }
+ }
+}
+
+static void irq_pipe_empty(struct r8a66597 *r8a66597)
+{
+ u16 tmp;
+ u16 check;
+ u16 pipenum;
+ u16 mask;
+ struct r8a66597_td *td;
+
+ mask = r8a66597_read(r8a66597, BEMPSTS)
+ & r8a66597_read(r8a66597, BEMPENB);
+ r8a66597_write(r8a66597, ~mask, BEMPSTS);
+ if (mask & BEMP0) {
+ cfifo_change(r8a66597, 0);
+ td = r8a66597_get_td(r8a66597, 0);
+ if (td && td->type != USB_PID_OUT)
+ disable_irq_empty(r8a66597, 0);
+ check_next_phase(r8a66597);
+ }
+
+ for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if (mask & check) {
+ struct r8a66597_td *td;
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (unlikely(!td))
+ continue;
+
+ tmp = r8a66597_read(r8a66597, td->pipe->pipectr);
+ if ((tmp & INBUFM) == 0) {
+ disable_irq_empty(r8a66597, pipenum);
+ pipe_irq_disable(r8a66597, pipenum);
+ if (td->urb->status == -EINPROGRESS)
+ td->urb->status = 0;
+ finish_request(r8a66597, td, pipenum, td->urb);
+ }
+ }
+ }
+}
+
+static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
+{
+ u16 check;
+ u16 pipenum;
+ u16 mask;
+
+ mask = r8a66597_read(r8a66597, NRDYSTS)
+ & r8a66597_read(r8a66597, NRDYENB);
+ r8a66597_write(r8a66597, ~mask, NRDYSTS);
+ if (mask & NRDY0) {
+ cfifo_change(r8a66597, 0);
+ set_urb_error(r8a66597, 0);
+ pipe_irq_disable(r8a66597, 0);
+ check_next_phase(r8a66597);
+ }
+
+ for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ check = 1 << pipenum;
+ if (mask & check) {
+ struct r8a66597_td *td;
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (unlikely(!td))
+ continue;
+
+ set_urb_error(r8a66597, pipenum);
+ pipe_irq_disable(r8a66597, pipenum);
+ pipe_stop(r8a66597, td->pipe);
+ finish_request(r8a66597, td, pipenum, td->urb);
+ }
+ }
+}
+
+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));
+}
+
+static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+ u16 intsts0, intsts1, intsts2;
+ u16 intenb0, intenb1, intenb2;
+ u16 mask0, mask1, mask2;
+
+ spin_lock(&r8a66597->lock);
+
+ intsts0 = r8a66597_read(r8a66597, INTSTS0);
+ intsts1 = r8a66597_read(r8a66597, INTSTS1);
+ intsts2 = r8a66597_read(r8a66597, INTSTS2);
+ intenb0 = r8a66597_read(r8a66597, INTENB0);
+ intenb1 = r8a66597_read(r8a66597, INTENB1);
+ intenb2 = r8a66597_read(r8a66597, INTENB2);
+
+ mask2 = intsts2 & intenb2;
+ mask1 = intsts1 & intenb1;
+ mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
+ if (mask2) {
+ if (mask2 & ATTCH) {
+ r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
+ r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
+
+ /* start usb bus sampling */
+ start_root_hub_sampling(r8a66597, 1);
+ }
+ if (mask2 & DTCH) {
+ r8a66597_write(r8a66597, ~DTCH, INTSTS2);
+ r8a66597_bclr(r8a66597, DTCHE, INTENB2);
+ r8a66597_usb_disconnect(r8a66597, 1);
+ }
+ }
+
+ if (mask1) {
+ if (mask1 & ATTCH) {
+ r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
+ r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
+
+ /* start usb bus sampling */
+ start_root_hub_sampling(r8a66597, 0);
+ }
+ if (mask1 & DTCH) {
+ r8a66597_write(r8a66597, ~DTCH, INTSTS1);
+ r8a66597_bclr(r8a66597, DTCHE, INTENB1);
+ r8a66597_usb_disconnect(r8a66597, 0);
+ }
+ if (mask1 & SIGN) {
+ r8a66597_write(r8a66597, ~SIGN, INTSTS1);
+ set_urb_error(r8a66597, 0);
+ check_next_phase(r8a66597);
+ }
+ if (mask1 & SACK) {
+ r8a66597_write(r8a66597, ~SACK, INTSTS1);
+ check_next_phase(r8a66597);
+ }
+ }
+ if (mask0) {
+ if (mask0 & BRDY)
+ irq_pipe_ready(r8a66597);
+ if (mask0 & BEMP)
+ irq_pipe_empty(r8a66597);
+ if (mask0 & NRDY)
+ irq_pipe_nrdy(r8a66597);
+ }
+
+ spin_unlock(&r8a66597->lock);
+ return IRQ_HANDLED;
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_root_hub_control(struct r8a66597 *r8a66597, int port)
+{
+ u16 tmp;
+ struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+
+ if (rh->port & (1 << USB_PORT_FEAT_RESET)) {
+ unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+ tmp = r8a66597_read(r8a66597, dvstctr_reg);
+ if ((tmp & USBRST) == USBRST) {
+ r8a66597_mdfy(r8a66597, UACT, USBRST | UACT,
+ dvstctr_reg);
+ mod_timer(&r8a66597->rh_timer,
+ jiffies + msecs_to_jiffies(50));
+ } else
+ r8a66597_usb_connect(r8a66597, 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));
+ }
+ } else {
+ rh->scount = R8A66597_MAX_SAMPLING;
+ rh->old_syssts = tmp;
+ mod_timer(&r8a66597->rh_timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ }
+}
+
+static void r8a66597_td_timer(unsigned long _r8a66597)
+{
+ struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
+ unsigned long flags;
+ u16 pipenum;
+ struct r8a66597_td *td, *new_td = NULL;
+ struct r8a66597_pipe *pipe;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+ if (!(r8a66597->timeout_map & (1 << pipenum)))
+ continue;
+ if (timer_pending(&r8a66597->td_timer[pipenum]))
+ continue;
+
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (!td) {
+ r8a66597->timeout_map &= ~(1 << pipenum);
+ continue;
+ }
+
+ if (td->urb->actual_length) {
+ set_td_timer(r8a66597, td);
+ break;
+ }
+
+ pipe = td->pipe;
+ pipe_stop(r8a66597, pipe);
+
+ new_td = td;
+ do {
+ list_move_tail(&new_td->queue,
+ &r8a66597->pipe_queue[pipenum]);
+ new_td = r8a66597_get_td(r8a66597, pipenum);
+ if (!new_td) {
+ new_td = td;
+ break;
+ }
+ } while (td != new_td && td->address == new_td->address);
+
+ start_transfer(r8a66597, new_td);
+
+ if (td == new_td)
+ r8a66597->timeout_map &= ~(1 << pipenum);
+ else
+ set_td_timer(r8a66597, new_td);
+ break;
+ }
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
+static void r8a66597_timer(unsigned long _r8a66597)
+{
+ struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
+ unsigned long flags;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+
+ r8a66597_root_hub_control(r8a66597, 0);
+ r8a66597_root_hub_control(r8a66597, 1);
+
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
+static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
+{
+ struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+
+ if (dev && dev->address && dev->state != USB_STATE_CONFIGURED &&
+ (urb->dev->state == USB_STATE_CONFIGURED))
+ return 1;
+ else
+ return 0;
+}
+
+static int r8a66597_start(struct usb_hcd *hcd)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+
+ hcd->state = HC_STATE_RUNNING;
+ return enable_controller(r8a66597);
+}
+
+static void r8a66597_stop(struct usb_hcd *hcd)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+
+ disable_controller(r8a66597);
+}
+
+static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
+{
+ unsigned int usb_address = usb_pipedevice(urb->pipe);
+ u16 root_port, hub_port;
+
+ if (usb_address == 0) {
+ get_port_number(urb->dev->devpath,
+ &root_port, &hub_port);
+ set_devadd_reg(r8a66597, 0,
+ get_r8a66597_usb_speed(urb->dev->speed),
+ get_parent_r8a66597_address(r8a66597, urb->dev),
+ hub_port, root_port);
+ }
+}
+
+static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
+ struct urb *urb,
+ struct usb_host_endpoint *hep)
+{
+ struct r8a66597_td *td;
+ u16 pipenum;
+
+ td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
+ if (td == NULL)
+ return NULL;
+
+ pipenum = r8a66597_get_pipenum(urb, hep);
+ td->pipenum = pipenum;
+ td->pipe = hep->hcpriv;
+ td->urb = urb;
+ td->address = get_urb_to_r8a66597_addr(r8a66597, urb);
+ td->maxpacket = usb_maxpacket(urb->dev, urb->pipe,
+ !usb_pipein(urb->pipe));
+ if (usb_pipecontrol(urb->pipe))
+ td->type = USB_PID_SETUP;
+ else if (usb_pipein(urb->pipe))
+ td->type = USB_PID_IN;
+ else
+ td->type = USB_PID_OUT;
+ INIT_LIST_HEAD(&td->queue);
+
+ return td;
+}
+
+static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
+ struct usb_host_endpoint *hep,
+ struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+ struct r8a66597_td *td = NULL;
+ int ret = 0, request = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
+ ret = -ENODEV;
+ goto error;
+ }
+
+ if (!hep->hcpriv) {
+ hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
+ GFP_ATOMIC);
+ if (!hep->hcpriv) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ set_pipe_reg_addr(hep->hcpriv, R8A66597_PIPE_NO_DMA);
+ if (usb_pipeendpoint(urb->pipe))
+ init_pipe_info(r8a66597, urb, hep, &hep->desc);
+ }
+
+ if (unlikely(check_pipe_config(r8a66597, urb)))
+ init_pipe_config(r8a66597, urb);
+
+ set_address_zero(r8a66597, urb);
+ td = r8a66597_make_td(r8a66597, urb, hep);
+ if (td == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
+ request = 1;
+ list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
+
+ spin_lock(&urb->lock);
+ if (urb->status != -EINPROGRESS) {
+ spin_unlock(&urb->lock);
+ ret = -EPIPE;
+ goto error;
+ }
+ urb->hcpriv = td;
+ spin_unlock(&urb->lock);
+
+ if (request) {
+ ret = start_transfer(r8a66597, td);
+ if (ret < 0) {
+ list_del(&td->queue);
+ kfree(td);
+ }
+ } else
+ set_td_timer(r8a66597, td);
+
+error:
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+ return ret;
+}
+
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+ struct r8a66597_td *td;
+ unsigned long flags;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ if (urb->hcpriv) {
+ td = urb->hcpriv;
+ pipe_stop(r8a66597, td->pipe);
+ pipe_irq_disable(r8a66597, td->pipenum);
+ disable_irq_empty(r8a66597, td->pipenum);
+ done(r8a66597, td, td->pipenum, urb);
+ }
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+ return 0;
+}
+
+static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *hep)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+ struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv;
+ struct r8a66597_td *td;
+ struct urb *urb = NULL;
+ u16 pipenum;
+ unsigned long flags;
+
+ if (pipe == NULL)
+ return;
+ pipenum = pipe->info.pipenum;
+
+ if (pipenum == 0) {
+ kfree(hep->hcpriv);
+ hep->hcpriv = NULL;
+ return;
+ }
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ pipe_stop(r8a66597, pipe);
+ pipe_irq_disable(r8a66597, pipenum);
+ disable_irq_empty(r8a66597, pipenum);
+ td = r8a66597_get_td(r8a66597, pipenum);
+ if (td)
+ urb = td->urb;
+ done(r8a66597, td, pipenum, urb);
+ kfree(hep->hcpriv);
+ hep->hcpriv = NULL;
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
+static int r8a66597_get_frame(struct usb_hcd *hcd)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+ return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;
+}
+
+static void collect_usb_address_map(struct usb_device *udev, unsigned long *map)
+{
+ int chix;
+
+ if (udev->state == USB_STATE_CONFIGURED &&
+ udev->parent && udev->parent->devnum > 1 &&
+ udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB)
+ map[udev->devnum/32] |= (1 << (udev->devnum % 32));
+
+ for (chix = 0; chix < udev->maxchild; chix++) {
+ struct usb_device *childdev = udev->children[chix];
+
+ if (childdev)
+ collect_usb_address_map(childdev, map);
+ }
+}
+
+/* this function must be called with interrupt disabled */
+static struct r8a66597_device *get_r8a66597_device(struct r8a66597 *r8a66597,
+ int addr)
+{
+ struct r8a66597_device *dev;
+ struct list_head *list = &r8a66597->child_device;
+
+ list_for_each_entry(dev, list, device_list) {
+ if (!dev)
+ continue;
+ if (dev->usb_address != addr)
+ continue;
+
+ return dev;
+ }
+
+ err("get_r8a66597_device fail.(%d)\n", addr);
+ return NULL;
+}
+
+static void update_usb_address_map(struct r8a66597 *r8a66597,
+ struct usb_device *root_hub,
+ unsigned long *map)
+{
+ int i, j, addr;
+ unsigned long diff;
+ unsigned long flags;
+
+ for (i = 0; i < 4; i++) {
+ diff = r8a66597->child_connect_map[i] ^ map[i];
+ if (!diff)
+ continue;
+
+ for (j = 0; j < 32; j++) {
+ if (!(diff & (1 << j)))
+ continue;
+
+ addr = i * 32 + j;
+ if (map[i] & (1 << j))
+ set_child_connect_map(r8a66597, addr);
+ else {
+ struct r8a66597_device *dev;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ dev = get_r8a66597_device(r8a66597, addr);
+ disable_r8a66597_pipe_all(r8a66597, dev);
+ free_usb_address(r8a66597, dev);
+ put_child_connect_map(r8a66597, addr);
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+ }
+ }
+ }
+}
+
+static void r8a66597_check_detect_child(struct r8a66597 *r8a66597,
+ struct usb_hcd *hcd)
+{
+ struct usb_bus *bus;
+ unsigned long now_map[4];
+
+ memset(now_map, 0, sizeof(now_map));
+
+ list_for_each_entry(bus, &usb_bus_list, bus_list) {
+ if (!bus->root_hub)
+ continue;
+
+ if (bus->busnum != hcd->self.busnum)
+ continue;
+
+ collect_usb_address_map(bus->root_hub, now_map);
+ update_usb_address_map(r8a66597, bus->root_hub, now_map);
+ }
+}
+
+static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+ unsigned long flags;
+ int i;
+
+ r8a66597_check_detect_child(r8a66597, hcd);
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+
+ *buf = 0; /* initialize (no change) */
+
+ for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++) {
+ if (r8a66597->root_hub[i].port & 0xffff0000)
+ *buf |= 1 << (i + 1);
+ }
+
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+
+ return (*buf != 0);
+}
+
+static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
+ struct usb_hub_descriptor *desc)
+{
+ desc->bDescriptorType = 0x29;
+ desc->bHubContrCurrent = 0;
+ desc->bNbrPorts = R8A66597_MAX_ROOT_HUB;
+ desc->bDescLength = 9;
+ desc->bPwrOn2PwrGood = 0;
+ desc->wHubCharacteristics = cpu_to_le16(0x0011);
+ desc->bitmap[0] = ((1 << R8A66597_MAX_ROOT_HUB) - 1) << 1;
+ desc->bitmap[1] = ~0;
+}
+
+static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+ int ret;
+ int port = (wIndex & 0x00FF) - 1;
+ struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+ unsigned long flags;
+
+ ret = 0;
+
+ spin_lock_irqsave(&r8a66597->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (wIndex > R8A66597_MAX_ROOT_HUB)
+ goto error;
+ if (wLength != 0)
+ goto error;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ rh->port &= (1 << USB_PORT_FEAT_POWER);
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ break;
+ case USB_PORT_FEAT_POWER:
+ r8a66597_port_power(r8a66597, port, 0);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ case USB_PORT_FEAT_C_SUSPEND:
+ case USB_PORT_FEAT_C_CONNECTION:
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ case USB_PORT_FEAT_C_RESET:
+ break;
+ default:
+ goto error;
+ }
+ rh->port &= ~(1 << wValue);
+ break;
+ case GetHubDescriptor:
+ r8a66597_hub_descriptor(r8a66597,
+ (struct usb_hub_descriptor *)buf);
+ break;
+ case GetHubStatus:
+ *buf = 0x00;
+ break;
+ case GetPortStatus:
+ if (wIndex > R8A66597_MAX_ROOT_HUB)
+ goto error;
+ *(u32 *)buf = rh->port;
+ break;
+ case SetPortFeature:
+ if (wIndex > R8A66597_MAX_ROOT_HUB)
+ goto error;
+ if (wLength != 0)
+ goto error;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ break;
+ case USB_PORT_FEAT_POWER:
+ r8a66597_port_power(r8a66597, port, 1);
+ rh->port |= (1 << USB_PORT_FEAT_POWER);
+ break;
+ case USB_PORT_FEAT_RESET: {
+ struct r8a66597_device *dev = rh->dev;
+
+ rh->port |= (1 << USB_PORT_FEAT_RESET);
+
+ disable_r8a66597_pipe_all(r8a66597, dev);
+ free_usb_address(r8a66597, dev);
+
+ r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT,
+ get_dvstctr_reg(port));
+ mod_timer(&r8a66597->rh_timer,
+ jiffies + msecs_to_jiffies(50));
+ }
+ break;
+ default:
+ goto error;
+ }
+ rh->port |= 1 << wValue;
+ break;
+ default:
+error:
+ ret = -EPIPE;
+ break;
+ }
+
+ spin_unlock_irqrestore(&r8a66597->lock, flags);
+ return ret;
+}
+
+static struct hc_driver r8a66597_hc_driver = {
+ .description = hcd_name,
+ .hcd_priv_size = sizeof(struct r8a66597),
+ .irq = r8a66597_irq,
+
+ /*
+ * generic hardware linkage
+ */
+ .flags = HCD_USB2,
+
+ .start = r8a66597_start,
+ .stop = r8a66597_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = r8a66597_urb_enqueue,
+ .urb_dequeue = r8a66597_urb_dequeue,
+ .endpoint_disable = r8a66597_endpoint_disable,
+
+ /*
+ * periodic schedule support
+ */
+ .get_frame_number = r8a66597_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = r8a66597_hub_status_data,
+ .hub_control = r8a66597_hub_control,
+};
+
+#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) */
+#define r8a66597_suspend NULL
+#define r8a66597_resume NULL
+#endif
+
+static int __init_or_module r8a66597_remove(struct platform_device *pdev)
+{
+ struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+ struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
+
+ del_timer_sync(&r8a66597->rh_timer);
+ iounmap((void *)r8a66597->reg);
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+ return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+static int __init r8a66597_probe(struct platform_device *pdev)
+{
+ struct resource *res = NULL;
+ int irq = -1;
+ void __iomem *reg = NULL;
+ struct usb_hcd *hcd = NULL;
+ struct r8a66597 *r8a66597;
+ int ret = 0;
+ int i;
+
+ if (pdev->dev.dma_mask) {
+ ret = -EINVAL;
+ err("dma not support");
+ goto clean_up;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ (char *)hcd_name);
+ if (!res) {
+ ret = -ENODEV;
+ err("platform_get_resource_byname error.");
+ goto clean_up;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENODEV;
+ err("platform_get_irq error.");
+ goto clean_up;
+ }
+
+ reg = ioremap(res->start, resource_len(res));
+ if (reg == NULL) {
+ ret = -ENOMEM;
+ err("ioremap error.");
+ goto clean_up;
+ }
+
+ /* initialize hcd */
+ hcd = usb_create_hcd(&r8a66597_hc_driver, &pdev->dev, (char *)hcd_name);
+ if (!hcd) {
+ ret = -ENOMEM;
+ err("Failed to create hcd");
+ goto clean_up;
+ }
+ r8a66597 = hcd_to_r8a66597(hcd);
+ memset(r8a66597, 0, sizeof(struct r8a66597));
+ dev_set_drvdata(&pdev->dev, r8a66597);
+
+ spin_lock_init(&r8a66597->lock);
+ init_timer(&r8a66597->rh_timer);
+ r8a66597->rh_timer.function = r8a66597_timer;
+ r8a66597->rh_timer.data = (unsigned long)r8a66597;
+ r8a66597->reg = (unsigned long)reg;
+
+ for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) {
+ INIT_LIST_HEAD(&r8a66597->pipe_queue[i]);
+ init_timer(&r8a66597->td_timer[i]);
+ r8a66597->td_timer[i].function = r8a66597_td_timer;
+ r8a66597->td_timer[i].data = (unsigned long)r8a66597;
+ }
+ INIT_LIST_HEAD(&r8a66597->child_device);
+
+ hcd->rsrc_start = res->start;
+ ret = usb_add_hcd(hcd, irq, 0);
+ if (ret != 0) {
+ err("Failed to add hcd");
+ goto clean_up;
+ }
+
+ return 0;
+
+clean_up:
+ if (reg)
+ iounmap(reg);
+ if (res)
+ release_mem_region(res->start, 1);
+
+ return ret;
+}
+
+static struct platform_driver r8a66597_driver = {
+ .probe = r8a66597_probe,
+ .remove = r8a66597_remove,
+ .suspend = r8a66597_suspend,
+ .resume = r8a66597_resume,
+ .driver = {
+ .name = (char *) hcd_name,
+ },
+};
+
+static int __init r8a66597_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ info("driver %s, %s", hcd_name, DRIVER_VERSION);
+ return platform_driver_register(&r8a66597_driver);
+}
+module_init(r8a66597_init);
+
+static void __exit r8a66597_cleanup(void)
+{
+ platform_driver_unregister(&r8a66597_driver);
+}
+module_exit(r8a66597_cleanup);
+
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
new file mode 100644
index 000000000000..fe9ceb077d9b
--- /dev/null
+++ b/drivers/usb/host/r8a66597.h
@@ -0,0 +1,631 @@
+/*
+ * R8A66597 HCD (Host Controller Driver)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ * Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Portions Copyright (C) 2004-2005 David Brownell
+ * Portions Copyright (C) 1999 Roman Weissgaerber
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __R8A66597_H__
+#define __R8A66597_H__
+
+#define SYSCFG0 0x00
+#define SYSCFG1 0x02
+#define SYSSTS0 0x04
+#define SYSSTS1 0x06
+#define DVSTCTR0 0x08
+#define DVSTCTR1 0x0A
+#define TESTMODE 0x0C
+#define PINCFG 0x0E
+#define DMA0CFG 0x10
+#define DMA1CFG 0x12
+#define CFIFO 0x14
+#define D0FIFO 0x18
+#define D1FIFO 0x1C
+#define CFIFOSEL 0x20
+#define CFIFOCTR 0x22
+#define CFIFOSIE 0x24
+#define D0FIFOSEL 0x28
+#define D0FIFOCTR 0x2A
+#define D1FIFOSEL 0x2C
+#define D1FIFOCTR 0x2E
+#define INTENB0 0x30
+#define INTENB1 0x32
+#define INTENB2 0x34
+#define BRDYENB 0x36
+#define NRDYENB 0x38
+#define BEMPENB 0x3A
+#define SOFCFG 0x3C
+#define INTSTS0 0x40
+#define INTSTS1 0x42
+#define INTSTS2 0x44
+#define BRDYSTS 0x46
+#define NRDYSTS 0x48
+#define BEMPSTS 0x4A
+#define FRMNUM 0x4C
+#define UFRMNUM 0x4E
+#define USBADDR 0x50
+#define USBREQ 0x54
+#define USBVAL 0x56
+#define USBINDX 0x58
+#define USBLENG 0x5A
+#define DCPCFG 0x5C
+#define DCPMAXP 0x5E
+#define DCPCTR 0x60
+#define PIPESEL 0x64
+#define PIPECFG 0x68
+#define PIPEBUF 0x6A
+#define PIPEMAXP 0x6C
+#define PIPEPERI 0x6E
+#define PIPE1CTR 0x70
+#define PIPE2CTR 0x72
+#define PIPE3CTR 0x74
+#define PIPE4CTR 0x76
+#define PIPE5CTR 0x78
+#define PIPE6CTR 0x7A
+#define PIPE7CTR 0x7C
+#define PIPE8CTR 0x7E
+#define PIPE9CTR 0x80
+#define PIPE1TRE 0x90
+#define PIPE1TRN 0x92
+#define PIPE2TRE 0x94
+#define PIPE2TRN 0x96
+#define PIPE3TRE 0x98
+#define PIPE3TRN 0x9A
+#define PIPE4TRE 0x9C
+#define PIPE4TRN 0x9E
+#define PIPE5TRE 0xA0
+#define PIPE5TRN 0xA2
+#define DEVADD0 0xD0
+#define DEVADD1 0xD2
+#define DEVADD2 0xD4
+#define DEVADD3 0xD6
+#define DEVADD4 0xD8
+#define DEVADD5 0xDA
+#define DEVADD6 0xDC
+#define DEVADD7 0xDE
+#define DEVADD8 0xE0
+#define DEVADD9 0xE2
+#define DEVADDA 0xE4
+
+/* System Configuration Control Register */
+#define XTAL 0xC000 /* b15-14: Crystal selection */
+#define XTAL48 0x8000 /* 48MHz */
+#define XTAL24 0x4000 /* 24MHz */
+#define XTAL12 0x0000 /* 12MHz */
+#define XCKE 0x2000 /* b13: External clock enable */
+#define PLLC 0x0800 /* b11: PLL control */
+#define SCKE 0x0400 /* b10: USB clock enable */
+#define PCSDIS 0x0200 /* b9: not CS wakeup */
+#define LPSME 0x0100 /* b8: Low power sleep mode */
+#define HSE 0x0080 /* b7: Hi-speed enable */
+#define DCFM 0x0040 /* b6: Controller function select */
+#define DRPD 0x0020 /* b5: D+/- pull down control */
+#define DPRPU 0x0010 /* b4: D+ pull up control */
+#define USBE 0x0001 /* b0: USB module operation enable */
+
+/* System Configuration Status Register */
+#define OVCBIT 0x8000 /* b15-14: Over-current bit */
+#define OVCMON 0xC000 /* b15-14: Over-current monitor */
+#define SOFEA 0x0020 /* b5: SOF monitor */
+#define IDMON 0x0004 /* b3: ID-pin monitor */
+#define LNST 0x0003 /* b1-0: D+, D- line status */
+#define SE1 0x0003 /* SE1 */
+#define FS_KSTS 0x0002 /* Full-Speed K State */
+#define FS_JSTS 0x0001 /* Full-Speed J State */
+#define LS_JSTS 0x0002 /* Low-Speed J State */
+#define LS_KSTS 0x0001 /* Low-Speed K State */
+#define SE0 0x0000 /* SE0 */
+
+/* Device State Control Register */
+#define EXTLP0 0x0400 /* b10: External port */
+#define VBOUT 0x0200 /* b9: VBUS output */
+#define WKUP 0x0100 /* b8: Remote wakeup */
+#define RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define USBRST 0x0040 /* b6: USB reset enable */
+#define RESUME 0x0020 /* b5: Resume enable */
+#define UACT 0x0010 /* b4: USB bus enable */
+#define RHST 0x0007 /* b1-0: Reset handshake status */
+#define HSPROC 0x0004 /* HS handshake is processing */
+#define HSMODE 0x0003 /* Hi-Speed mode */
+#define FSMODE 0x0002 /* Full-Speed mode */
+#define LSMODE 0x0001 /* Low-Speed mode */
+#define UNDECID 0x0000 /* Undecided */
+
+/* Test Mode Register */
+#define UTST 0x000F /* b3-0: Test select */
+#define H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define H_TST_K 0x000A /* HOST TEST K */
+#define H_TST_J 0x0009 /* HOST TEST J */
+#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define P_TST_K 0x0002 /* PERI TEST K */
+#define P_TST_J 0x0001 /* PERI TEST J */
+#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+
+/* Data Pin Configuration Register */
+#define LDRV 0x8000 /* b15: Drive Current Adjust */
+#define VIF1 0x0000 /* VIF = 1.8V */
+#define VIF3 0x8000 /* VIF = 3.3V */
+#define INTA 0x0001 /* b1: USB INT-pin active */
+
+/* DMAx Pin Configuration Register */
+#define DREQA 0x4000 /* b14: Dreq active select */
+#define BURST 0x2000 /* b13: Burst mode */
+#define DACKA 0x0400 /* b10: Dack active select */
+#define DFORM 0x0380 /* b9-7: DMA mode select */
+#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define DENDA 0x0040 /* b6: Dend active select */
+#define PKTM 0x0020 /* b5: Packet mode */
+#define DENDE 0x0010 /* b4: Dend enable */
+#define OBUS 0x0004 /* b2: OUTbus mode */
+
+/* CFIFO/DxFIFO Port Select Register */
+#define RCNT 0x8000 /* b15: Read count mode */
+#define REW 0x4000 /* b14: Buffer rewind */
+#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
+#define DREQE 0x1000 /* b12: DREQ output enable */
+#define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
+#define MBW_8 0x0000 /* 8bit */
+#define MBW_16 0x0400 /* 16bit */
+#define BIGEND 0x0100 /* b8: Big endian mode */
+#define BYTE_LITTLE 0x0000 /* little dendian */
+#define BYTE_BIG 0x0100 /* big endifan */
+#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define CURPIPE 0x000F /* b2-0: PIPE select */
+
+/* CFIFO/DxFIFO Port Control Register */
+#define BVAL 0x8000 /* b15: Buffer valid flag */
+#define BCLR 0x4000 /* b14: Buffer clear */
+#define FRDY 0x2000 /* b13: FIFO ready */
+#define DTLN 0x0FFF /* b11-0: FIFO received data length */
+
+/* Interrupt Enable Register 0 */
+#define VBSE 0x8000 /* b15: VBUS interrupt */
+#define RSME 0x4000 /* b14: Resume interrupt */
+#define SOFE 0x2000 /* b13: Frame update interrupt */
+#define DVSE 0x1000 /* b12: Device state transition interrupt */
+#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
+
+/* Interrupt Enable Register 1 */
+#define OVRCRE 0x8000 /* b15: Over-current interrupt */
+#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
+#define EOFERRE 0x0040 /* b6: EOF error interrupt */
+#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
+
+/* BRDY Interrupt Enable/Status Register */
+#define BRDY9 0x0200 /* b9: PIPE9 */
+#define BRDY8 0x0100 /* b8: PIPE8 */
+#define BRDY7 0x0080 /* b7: PIPE7 */
+#define BRDY6 0x0040 /* b6: PIPE6 */
+#define BRDY5 0x0020 /* b5: PIPE5 */
+#define BRDY4 0x0010 /* b4: PIPE4 */
+#define BRDY3 0x0008 /* b3: PIPE3 */
+#define BRDY2 0x0004 /* b2: PIPE2 */
+#define BRDY1 0x0002 /* b1: PIPE1 */
+#define BRDY0 0x0001 /* b1: PIPE0 */
+
+/* NRDY Interrupt Enable/Status Register */
+#define NRDY9 0x0200 /* b9: PIPE9 */
+#define NRDY8 0x0100 /* b8: PIPE8 */
+#define NRDY7 0x0080 /* b7: PIPE7 */
+#define NRDY6 0x0040 /* b6: PIPE6 */
+#define NRDY5 0x0020 /* b5: PIPE5 */
+#define NRDY4 0x0010 /* b4: PIPE4 */
+#define NRDY3 0x0008 /* b3: PIPE3 */
+#define NRDY2 0x0004 /* b2: PIPE2 */
+#define NRDY1 0x0002 /* b1: PIPE1 */
+#define NRDY0 0x0001 /* b1: PIPE0 */
+
+/* BEMP Interrupt Enable/Status Register */
+#define BEMP9 0x0200 /* b9: PIPE9 */
+#define BEMP8 0x0100 /* b8: PIPE8 */
+#define BEMP7 0x0080 /* b7: PIPE7 */
+#define BEMP6 0x0040 /* b6: PIPE6 */
+#define BEMP5 0x0020 /* b5: PIPE5 */
+#define BEMP4 0x0010 /* b4: PIPE4 */
+#define BEMP3 0x0008 /* b3: PIPE3 */
+#define BEMP2 0x0004 /* b2: PIPE2 */
+#define BEMP1 0x0002 /* b1: PIPE1 */
+#define BEMP0 0x0001 /* b0: PIPE0 */
+
+/* SOF Pin Configuration Register */
+#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
+#define BRDYM 0x0040 /* b6: BRDY clear timing */
+#define INTL 0x0020 /* b5: Interrupt sense select */
+#define EDGESTS 0x0010 /* b4: */
+#define SOFMODE 0x000C /* b3-2: SOF pin select */
+#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
+#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
+
+/* Interrupt Status Register 0 */
+#define VBINT 0x8000 /* b15: VBUS interrupt */
+#define RESM 0x4000 /* b14: Resume interrupt */
+#define SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define DVST 0x1000 /* b12: Device state transition interrupt */
+#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define VBSTS 0x0080 /* b7: VBUS input port */
+#define DVSQ 0x0070 /* b6-4: Device state */
+#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define DS_SUSP 0x0040 /* Suspend */
+#define DS_CNFG 0x0030 /* Configured */
+#define DS_ADDS 0x0020 /* Address */
+#define DS_DFLT 0x0010 /* Default */
+#define DS_POWR 0x0000 /* Powered */
+#define DVSQS 0x0030 /* b5-4: Device state */
+#define VALID 0x0008 /* b3: Setup packet detected flag */
+#define CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define CS_SQER 0x0006 /* Sequence error */
+#define CS_WRND 0x0005 /* Control write nodata status stage */
+#define CS_WRSS 0x0004 /* Control write status stage */
+#define CS_WRDS 0x0003 /* Control write data stage */
+#define CS_RDSS 0x0002 /* Control read status stage */
+#define CS_RDDS 0x0001 /* Control read data stage */
+#define CS_IDST 0x0000 /* Idle or setup stage */
+
+/* Interrupt Status Register 1 */
+#define OVRCR 0x8000 /* b15: Over-current interrupt */
+#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define DTCH 0x1000 /* b12: Detach sense interrupt */
+#define ATTCH 0x0800 /* b11: Attach sense interrupt */
+#define EOFERR 0x0040 /* b6: EOF-error interrupt */
+#define SIGN 0x0020 /* b5: Setup ignore interrupt */
+#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
+
+/* Frame Number Register */
+#define OVRN 0x8000 /* b15: Overrun error */
+#define CRCE 0x4000 /* b14: Received data error */
+#define FRNM 0x07FF /* b10-0: Frame number */
+
+/* Micro Frame Number Register */
+#define UFRNM 0x0007 /* b2-0: Micro frame number */
+
+/* Default Control Pipe Maxpacket Size Register */
+/* Pipe Maxpacket Size Register */
+#define DEVSEL 0xF000 /* b15-14: Device address select */
+#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
+
+/* Default Control Pipe Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define SUREQ 0x4000 /* b14: Send USB request */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define SUREQCLR 0x0800 /* b11: stop setup request */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PINGE 0x0010 /* b4: ping enable */
+#define CCPL 0x0004 /* b2: Enable control transfer complete */
+#define PID 0x0003 /* b1-0: Response PID */
+#define PID_STALL11 0x0003 /* STALL */
+#define PID_STALL 0x0002 /* STALL */
+#define PID_BUF 0x0001 /* BUF */
+#define PID_NAK 0x0000 /* NAK */
+
+/* Pipe Window Select Register */
+#define PIPENM 0x0007 /* b2-0: Pipe select */
+
+/* Pipe Configuration Register */
+#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
+#define R8A66597_ISO 0xC000 /* Isochronous */
+#define R8A66597_INT 0x8000 /* Interrupt */
+#define R8A66597_BULK 0x4000 /* Bulk */
+#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
+#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
+#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
+#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
+#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
+
+/* Pipe Buffer Configuration Register */
+#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
+#define PIPE0BUF 256
+#define PIPExBUF 64
+
+/* Pipe Maxpacket Size Register */
+#define MXPS 0x07FF /* b10-0: Maxpacket size */
+
+/* Pipe Cycle Configuration Register */
+#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
+#define IITV 0x0007 /* b2-0: Isochronous interval */
+
+/* Pipex Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define ATREPM 0x0400 /* b10: Auto repeat mode */
+#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PID 0x0003 /* b1-0: Response PID */
+
+/* PIPExTRE */
+#define TRENB 0x0200 /* b9: Transaction counter enable */
+#define TRCLR 0x0100 /* b8: Transaction counter clear */
+
+/* PIPExTRN */
+#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
+
+/* DEVADDx */
+#define UPPHUB 0x7800
+#define HUBPORT 0x0700
+#define USBSPD 0x00C0
+#define RTPORT 0x0001
+
+#define R8A66597_MAX_NUM_PIPE 10
+#define R8A66597_BUF_BSIZE 8
+#define R8A66597_MAX_DEVICE 10
+#define R8A66597_MAX_ROOT_HUB 2
+#define R8A66597_MAX_SAMPLING 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))
+#define check_interrupt(pipenum) ((pipenum >= 6 && pipenum <= 9))
+#define make_devsel(addr) (addr << 12)
+
+struct r8a66597_pipe_info {
+ u16 pipenum;
+ u16 address; /* R8A66597 HCD usb addres */
+ u16 epnum;
+ u16 maxpacket;
+ u16 type;
+ u16 bufnum;
+ u16 buf_bsize;
+ u16 interval;
+ u16 dir_in;
+};
+
+struct r8a66597_pipe {
+ struct r8a66597_pipe_info info;
+
+ unsigned long fifoaddr;
+ unsigned long fifosel;
+ unsigned long fifoctr;
+ unsigned long pipectr;
+ unsigned long pipetre;
+ unsigned long pipetrn;
+};
+
+struct r8a66597_td {
+ struct r8a66597_pipe *pipe;
+ struct urb *urb;
+ struct list_head queue;
+
+ u16 type;
+ u16 pipenum;
+ int iso_cnt;
+
+ u16 address; /* R8A66597's USB address */
+ u16 maxpacket;
+
+ unsigned zero_packet:1;
+ unsigned short_packet:1;
+ unsigned set_address:1;
+};
+
+struct r8a66597_device {
+ u16 address; /* R8A66597's USB address */
+ u16 hub_port;
+ u16 root_port;
+
+ unsigned short ep_in_toggle;
+ unsigned short ep_out_toggle;
+ unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
+ unsigned char dma_map;
+
+ enum usb_device_state state;
+
+ struct usb_device *udev;
+ int usb_address;
+ struct list_head device_list;
+};
+
+struct r8a66597_root_hub {
+ u32 port;
+ u16 old_syssts;
+ int scount;
+
+ struct r8a66597_device *dev;
+};
+
+struct r8a66597 {
+ spinlock_t lock;
+ unsigned long reg;
+
+ struct r8a66597_device device0;
+ struct r8a66597_root_hub root_hub[R8A66597_MAX_ROOT_HUB];
+ struct list_head pipe_queue[R8A66597_MAX_NUM_PIPE];
+
+ struct timer_list rh_timer;
+ struct timer_list td_timer[R8A66597_MAX_NUM_PIPE];
+
+ unsigned short address_map;
+ unsigned short timeout_map;
+ unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
+ unsigned char dma_map;
+
+ struct list_head child_device;
+ unsigned long child_connect_map[4];
+};
+
+static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
+{
+ return (struct r8a66597 *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *r8a66597_to_hcd(struct r8a66597 *r8a66597)
+{
+ return container_of((void *)r8a66597, struct usb_hcd, hcd_priv);
+}
+
+static inline struct r8a66597_td *r8a66597_get_td(struct r8a66597 *r8a66597,
+ u16 pipenum)
+{
+ if (unlikely(list_empty(&r8a66597->pipe_queue[pipenum])))
+ return NULL;
+
+ return list_entry(r8a66597->pipe_queue[pipenum].next,
+ struct r8a66597_td, queue);
+}
+
+static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597,
+ u16 pipenum)
+{
+ struct r8a66597_td *td;
+
+ td = r8a66597_get_td(r8a66597, pipenum);
+ return (td ? td->urb : NULL);
+}
+
+static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
+{
+ return inw(r8a66597->reg + offset);
+}
+
+static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, u16 *buf,
+ int len)
+{
+ len = (len + 1) / 2;
+ insw(r8a66597->reg + offset, buf, len);
+}
+
+static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
+ unsigned long offset)
+{
+ outw(val, r8a66597->reg + offset);
+}
+
+static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, u16 *buf,
+ int len)
+{
+ unsigned long fifoaddr = r8a66597->reg + offset;
+ int odd = len & 0x0001;
+
+ len = len / 2;
+ outsw(fifoaddr, buf, len);
+ if (unlikely(odd)) {
+ buf = &buf[len];
+ outb((unsigned char)*buf, fifoaddr);
+ }
+}
+
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+ u16 val, u16 pat, unsigned long offset)
+{
+ u16 tmp;
+ tmp = r8a66597_read(r8a66597, offset);
+ tmp = tmp & (~pat);
+ tmp = tmp | val;
+ r8a66597_write(r8a66597, tmp, offset);
+}
+
+#define r8a66597_bclr(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, val, 0, offset)
+
+static inline unsigned long get_syscfg_reg(int port)
+{
+ return port == 0 ? SYSCFG0 : SYSCFG1;
+}
+
+static inline unsigned long get_syssts_reg(int port)
+{
+ return port == 0 ? SYSSTS0 : SYSSTS1;
+}
+
+static inline unsigned long get_dvstctr_reg(int port)
+{
+ return port == 0 ? DVSTCTR0 : DVSTCTR1;
+}
+
+static inline unsigned long get_intenb_reg(int port)
+{
+ return port == 0 ? INTENB1 : INTENB2;
+}
+
+static inline unsigned long get_intsts_reg(int port)
+{
+ return port == 0 ? INTSTS1 : INTSTS2;
+}
+
+static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
+{
+ unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+ return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
+}
+
+static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
+ int power)
+{
+ unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+ if (power)
+ r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
+ else
+ r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
+}
+
+#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
+#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
+#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
+#define get_devadd_addr(address) (DEVADD0 + address * 2)
+
+#define enable_irq_ready(r8a66597, pipenum) \
+ enable_pipe_irq(r8a66597, pipenum, BRDYENB)
+#define disable_irq_ready(r8a66597, pipenum) \
+ disable_pipe_irq(r8a66597, pipenum, BRDYENB)
+#define enable_irq_empty(r8a66597, pipenum) \
+ enable_pipe_irq(r8a66597, pipenum, BEMPENB)
+#define disable_irq_empty(r8a66597, pipenum) \
+ disable_pipe_irq(r8a66597, pipenum, BEMPENB)
+#define enable_irq_nrdy(r8a66597, pipenum) \
+ enable_pipe_irq(r8a66597, pipenum, NRDYENB)
+#define disable_irq_nrdy(r8a66597, pipenum) \
+ disable_pipe_irq(r8a66597, pipenum, NRDYENB)
+
+#endif /* __R8A66597_H__ */
+
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 2d0e73b20099..5da63f535005 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -278,10 +278,9 @@ static int sl811_cs_probe(struct pcmcia_device *link)
{
local_info_t *local;
- local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+ local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
return -ENOMEM;
- memset(local, 0, sizeof(local_info_t));
local->p_dev = link;
link->priv = local;
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index e98df2ee9901..7f765ec038cd 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -52,6 +52,7 @@
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/pci_ids.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
@@ -83,7 +84,7 @@ static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
* u132_module_lock exists to protect access to global variables
*
*/
-static struct semaphore u132_module_lock;
+static struct mutex u132_module_lock;
static int u132_exiting = 0;
static int u132_instances = 0;
static struct list_head u132_static_list;
@@ -258,10 +259,10 @@ static void u132_hcd_delete(struct kref *kref)
struct platform_device *pdev = u132->platform_dev;
struct usb_hcd *hcd = u132_to_hcd(u132);
u132->going += 1;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
list_del_init(&u132->u132_list);
u132_instances -= 1;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
"2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
usb_put_hcd(hcd);
@@ -3111,10 +3112,10 @@ static int __devinit u132_probe(struct platform_device *pdev)
int retval = 0;
struct u132 *u132 = hcd_to_u132(hcd);
hcd->rsrc_start = 0;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
list_add_tail(&u132->u132_list, &u132_static_list);
u132->sequence_num = ++u132_instances;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
u132_u132_init_kref(u132);
u132_initialise(u132, pdev);
hcd->product_desc = "ELAN U132 Host Controller";
@@ -3216,7 +3217,7 @@ static int __init u132_hcd_init(void)
INIT_LIST_HEAD(&u132_static_list);
u132_instances = 0;
u132_exiting = 0;
- init_MUTEX(&u132_module_lock);
+ mutex_init(&u132_module_lock);
if (usb_disabled())
return -ENODEV;
printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
@@ -3232,9 +3233,9 @@ static void __exit u132_hcd_exit(void)
{
struct u132 *u132;
struct u132 *temp;
- down(&u132_module_lock);
+ mutex_lock(&u132_module_lock);
u132_exiting += 1;
- up(&u132_module_lock);
+ mutex_unlock(&u132_module_lock);
list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
platform_device_unregister(u132->platform_dev);
} platform_driver_unregister(&u132_platform_driver);
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index d22da26ff167..805e5fc5f5db 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -730,10 +730,9 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
int rc = 0;
spin_lock_irq(&uhci->lock);
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n");
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
rc = -ESHUTDOWN;
- } else if (!uhci->dead)
+ else if (!uhci->dead)
wakeup_rh(uhci);
spin_unlock_irq(&uhci->lock);
return rc;
@@ -934,7 +933,7 @@ static int __init uhci_hcd_init(void)
}
uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
- sizeof(struct urb_priv), 0, 0, NULL, NULL);
+ sizeof(struct urb_priv), 0, 0, NULL);
if (!uhci_up_cachep)
goto up_failed;
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 4aed305982ec..3bb908ca38e9 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -827,8 +827,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* If direction is "send", change the packet ID from SETUP (0x2D)
* to OUT (0xE1). Else change it from SETUP to IN (0x69) and
* set Short Packet Detect (SPD) for all data packets.
+ *
+ * 0-length transfers always get treated as "send".
*/
- if (usb_pipeout(urb->pipe))
+ if (usb_pipeout(urb->pipe) || len == 0)
destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
else {
destination ^= (USB_PID_SETUP ^ USB_PID_IN);
@@ -839,7 +841,12 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
* Build the DATA TDs
*/
while (len > 0) {
- int pktsze = min(len, maxsze);
+ int pktsze = maxsze;
+
+ if (len <= pktsze) { /* The last data packet */
+ pktsze = len;
+ status &= ~TD_CTRL_SPD;
+ }
td = uhci_alloc_td(uhci);
if (!td)
@@ -866,20 +873,10 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb,
goto nomem;
*plink = LINK_TO_TD(td);
- /*
- * It's IN if the pipe is an output pipe or we're not expecting
- * data back.
- */
- destination &= ~TD_TOKEN_PID_MASK;
- if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
- destination |= USB_PID_IN;
- else
- destination |= USB_PID_OUT;
-
+ /* Change direction for the status transaction */
+ destination ^= (USB_PID_IN ^ USB_PID_OUT);
destination |= TD_TOKEN_TOGGLE; /* End in Data1 */
- status &= ~TD_CTRL_SPD;
-
uhci_add_td_to_urbp(td, urbp);
uhci_fill_td(td, status | TD_CTRL_IOC,
destination | uhci_explen(0), 0);
@@ -1185,10 +1182,18 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
}
}
+ /* Did we receive a short packet? */
} else if (len < uhci_expected_length(td_token(td))) {
- /* We received a short packet */
- if (urb->transfer_flags & URB_SHORT_NOT_OK)
+ /* For control transfers, go to the status TD if
+ * this isn't already the last data TD */
+ if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+ if (td->list.next != urbp->td_list.prev)
+ ret = 1;
+ }
+
+ /* For bulk and interrupt, this may be an error */
+ else if (urb->transfer_flags & URB_SHORT_NOT_OK)
ret = -EREMOTEIO;
/* Fixup needed only if this isn't the URB's last TD */
@@ -1208,10 +1213,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
err:
if (ret < 0) {
- /* In case a control transfer gets an error
- * during the setup stage */
- urb->actual_length = max(urb->actual_length, 0);
-
/* Note that the queue has stopped and save
* the next toggle value */
qh->element = UHCI_PTR_TERM;
@@ -1489,9 +1490,25 @@ __acquires(uhci->lock)
{
struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+ if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+ /* urb->actual_length < 0 means the setup transaction didn't
+ * complete successfully. Either it failed or the URB was
+ * unlinked first. Regardless, don't confuse people with a
+ * negative length. */
+ urb->actual_length = max(urb->actual_length, 0);
+
+ /* Report erroneous short transfers */
+ if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length <
+ urb->transfer_buffer_length &&
+ urb->status == 0))
+ urb->status = -EREMOTEIO;
+ }
+
/* When giving back the first URB in an Isochronous queue,
* reinitialize the QH's iso-related members for the next URB. */
- if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+ else if (qh->type == USB_ENDPOINT_XFER_ISOC &&
urbp->node.prev == &qh->queue &&
urbp->node.next != &qh->queue) {
struct urb *nurb = list_entry(urbp->node.next,
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 36502a06f73a..d1131a87a5b1 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,9 +284,9 @@ static void mdc800_usb_irq (struct urb *urb)
int data_received=0, wake_up;
unsigned char* b=urb->transfer_buffer;
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status >= 0)
- {
+ if (status >= 0) {
//dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
@@ -324,7 +324,7 @@ static void mdc800_usb_irq (struct urb *urb)
||
((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
||
- (urb->status < 0)
+ (status < 0)
);
if (wake_up)
@@ -376,15 +376,12 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
static void mdc800_usb_write_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status != 0)
- {
- err ("writing command fails (status=%i)", urb->status);
- }
+ if (status != 0)
+ err ("writing command fails (status=%i)", status);
else
- {
mdc800->state=READY;
- }
mdc800->written = 1;
wake_up (&mdc800->write_wait);
}
@@ -396,9 +393,9 @@ static void mdc800_usb_write_notify (struct urb *urb)
static void mdc800_usb_download_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
+ int status = urb->status;
- if (urb->status == 0)
- {
+ if (status == 0) {
/* Fill output buffer with these data */
memcpy (mdc800->out, urb->transfer_buffer, 64);
mdc800->out_count=64;
@@ -408,10 +405,8 @@ static void mdc800_usb_download_notify (struct urb *urb)
{
mdc800->state=READY;
}
- }
- else
- {
- err ("request bytes fails (status:%i)", urb->status);
+ } else {
+ err ("request bytes fails (status:%i)", status);
}
mdc800->downloaded = 1;
wake_up (&mdc800->download_wait);
@@ -649,9 +644,9 @@ static int mdc800_device_open (struct inode* inode, struct file *file)
retval=0;
mdc800->irq_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
- {
- err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+ retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
+ if (retval) {
+ err ("request USB irq fails (submit_retval=%i).", retval);
errn = -EIO;
goto error_out;
}
@@ -698,6 +693,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
{
size_t left=len, sts=len; /* single transfer size */
char __user *ptr = buf;
+ int retval;
mutex_lock(&mdc800->io_lock);
if (mdc800->state == NOT_CONNECTED)
@@ -737,9 +733,9 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
/* Download -> Request new bytes */
mdc800->download_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
- {
- err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+ retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
+ if (retval) {
+ err ("Can't submit download urb (retval=%i)",retval);
mutex_unlock(&mdc800->io_lock);
return len-left;
}
@@ -788,6 +784,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
{
size_t i=0;
+ int retval;
mutex_lock(&mdc800->io_lock);
if (mdc800->state != READY)
@@ -854,9 +851,9 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
mdc800->state=WORKING;
memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
mdc800->write_urb->dev = mdc800->dev;
- if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
- {
- err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+ retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
+ if (retval) {
+ err ("submitting write urb fails (retval=%i)", retval);
mutex_unlock(&mdc800->io_lock);
return -EIO;
}
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 51bd80d2b8cc..768b2c11a231 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -189,7 +189,7 @@ static struct usb_driver mts_usb_driver = {
#define MTS_DEBUG_INT() \
do { MTS_DEBUG_GOT_HERE(); \
MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
- MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+ MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
mts_debug_dump(context->instance);\
} while(0)
#else
@@ -393,8 +393,6 @@ void mts_int_submit_urb (struct urb* transfer,
context
);
- transfer->status = 0;
-
res = usb_submit_urb( transfer, GFP_ATOMIC );
if ( unlikely(res) ) {
MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
@@ -444,12 +442,13 @@ static void mts_get_status( struct urb *transfer )
static void mts_data_done( struct urb* transfer )
/* Interrupt context! */
{
+ int status = transfer->status;
MTS_INT_INIT();
if ( context->data_length != transfer->actual_length ) {
context->srb->resid = context->data_length - transfer->actual_length;
- } else if ( unlikely(transfer->status) ) {
- context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+ } else if ( unlikely(status) ) {
+ context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
}
mts_get_status(transfer);
@@ -461,10 +460,11 @@ static void mts_data_done( struct urb* transfer )
static void mts_command_done( struct urb *transfer )
/* Interrupt context! */
{
+ int status = transfer->status;
MTS_INT_INIT();
- if ( unlikely(transfer->status) ) {
- if (transfer->status == -ENOENT) {
+ if ( unlikely(status) ) {
+ if (status == -ENOENT) {
/* We are being killed */
MTS_DEBUG_GOT_HERE();
context->srb->result = DID_ABORT<<16;
@@ -502,12 +502,13 @@ static void mts_command_done( struct urb *transfer )
static void mts_do_sg (struct urb* transfer)
{
struct scatterlist * sg;
+ int status = transfer->status;
MTS_INT_INIT();
MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
- if (unlikely(transfer->status)) {
- context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+ if (unlikely(status)) {
+ context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
mts_transfer_cleanup(transfer);
}
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index 77145f9db043..e9fdbc8997b3 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#ifdef CONFIG_USB_DEBUG
@@ -80,7 +81,7 @@ MODULE_DEVICE_TABLE(usb, device_table);
/* Structure to hold all of our device specific stuff */
struct adu_device {
- struct semaphore sem; /* locks this structure */
+ struct mutex mtx; /* locks this structure */
struct usb_device* udev; /* save off the usb device pointer */
struct usb_interface* interface;
unsigned char minor; /* the starting minor number for this device */
@@ -108,8 +109,6 @@ struct adu_device {
struct urb* interrupt_out_urb;
};
-/* prevent races between open() and disconnect */
-static DEFINE_MUTEX(disconnect_mutex);
static struct usb_driver adu_driver;
static void adu_debug_data(int level, const char *function, int size,
@@ -180,17 +179,18 @@ static void adu_delete(struct adu_device *dev)
static void adu_interrupt_in_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
+ int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : enter, status %d", __FUNCTION__, status);
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
spin_lock(&dev->buflock);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+ if (status != 0) {
+ if ((status != -ENOENT) && (status != -ECONNRESET)) {
dbg(1," %s : nonzero status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
goto exit;
}
@@ -218,21 +218,22 @@ exit:
wake_up_interruptible(&dev->read_wait);
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : leave, status %d", __FUNCTION__, status);
}
static void adu_interrupt_out_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
+ int status = urb->status;
- dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : enter, status %d", __FUNCTION__, status);
adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status != 0) {
- if ((urb->status != -ENOENT) &&
- (urb->status != -ECONNRESET)) {
+ if (status != 0) {
+ if ((status != -ENOENT) &&
+ (status != -ECONNRESET)) {
dbg(1, " %s :nonzero status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
goto exit;
}
@@ -242,7 +243,7 @@ exit:
adu_debug_data(5, __FUNCTION__, urb->actual_length,
urb->transfer_buffer);
- dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+ dbg(4," %s : leave, status %d", __FUNCTION__, status);
}
static int adu_open(struct inode *inode, struct file *file)
@@ -256,8 +257,6 @@ static int adu_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
- mutex_lock(&disconnect_mutex);
-
interface = usb_find_interface(&adu_driver, subminor);
if (!interface) {
err("%s - error, can't find device for minor %d",
@@ -273,8 +272,8 @@ static int adu_open(struct inode *inode, struct file *file)
}
/* lock this device */
- if ((retval = down_interruptible(&dev->sem))) {
- dbg(2, "%s : sem down failed", __FUNCTION__);
+ if ((retval = mutex_lock_interruptible(&dev->mtx))) {
+ dbg(2, "%s : mutex lock failed", __FUNCTION__);
goto exit_no_device;
}
@@ -303,10 +302,9 @@ static int adu_open(struct inode *inode, struct file *file)
if (retval)
--dev->open_count;
}
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
exit_no_device:
- mutex_unlock(&disconnect_mutex);
dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
return retval;
@@ -318,12 +316,6 @@ static int adu_release_internal(struct adu_device *dev)
dbg(2," %s : enter", __FUNCTION__);
- if (dev->udev == NULL) {
- /* the device was unplugged before the file was released */
- adu_delete(dev);
- goto exit;
- }
-
/* decrement our usage count for the device */
--dev->open_count;
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
@@ -332,7 +324,6 @@ static int adu_release_internal(struct adu_device *dev)
dev->open_count = 0;
}
-exit:
dbg(2," %s : leave", __FUNCTION__);
return retval;
}
@@ -359,7 +350,7 @@ static int adu_release(struct inode *inode, struct file *file)
}
/* lock our device */
- down(&dev->sem); /* not interruptible */
+ mutex_lock(&dev->mtx); /* not interruptible */
if (dev->open_count <= 0) {
dbg(1," %s : device not opened", __FUNCTION__);
@@ -367,12 +358,19 @@ static int adu_release(struct inode *inode, struct file *file)
goto exit;
}
- /* do the work */
- retval = adu_release_internal(dev);
+ if (dev->udev == NULL) {
+ /* the device was unplugged before the file was released */
+ mutex_unlock(&dev->mtx);
+ adu_delete(dev);
+ dev = NULL;
+ } else {
+ /* do the work */
+ retval = adu_release_internal(dev);
+ }
exit:
if (dev)
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
return retval;
}
@@ -395,7 +393,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
dev = file->private_data;
dbg(2," %s : dev=%p", __FUNCTION__, dev);
/* lock this object */
- if (down_interruptible(&dev->sem))
+ if (mutex_lock_interruptible(&dev->mtx))
return -ERESTARTSYS;
/* verify that the device wasn't unplugged */
@@ -527,7 +525,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
return retval;
@@ -548,7 +546,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
dev = file->private_data;
/* lock this object */
- retval = down_interruptible(&dev->sem);
+ retval = mutex_lock_interruptible(&dev->mtx);
if (retval)
goto exit_nolock;
@@ -576,9 +574,9 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
retval = -EINTR;
goto exit;
}
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
- retval = down_interruptible(&dev->sem);
+ retval = mutex_lock_interruptible(&dev->mtx);
if (retval) {
retval = bytes_written ? bytes_written : retval;
goto exit_nolock;
@@ -643,7 +641,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
exit_nolock:
dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
@@ -703,7 +701,7 @@ static int adu_probe(struct usb_interface *interface,
goto exit;
}
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->mtx);
spin_lock_init(&dev->buflock);
dev->udev = udev;
init_waitqueue_head(&dev->read_wait);
@@ -831,31 +829,27 @@ static void adu_disconnect(struct usb_interface *interface)
dbg(2," %s : enter", __FUNCTION__);
- mutex_lock(&disconnect_mutex); /* not interruptible */
-
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
- down(&dev->sem); /* not interruptible */
-
minor = dev->minor;
/* give back our minor */
usb_deregister_dev(interface, &adu_class);
dev->minor = 0;
+ mutex_lock(&dev->mtx); /* not interruptible */
+
/* if the device is not opened, then we clean up right now */
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
if (!dev->open_count) {
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
adu_delete(dev);
} else {
dev->udev = NULL;
- up(&dev->sem);
+ mutex_unlock(&dev->mtx);
}
- mutex_unlock(&disconnect_mutex);
-
dev_info(&interface->dev, "ADU device adutux%d now disconnected",
(minor - ADU_MINOR_BASE));
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index cf70c16f0e3f..1cb56f2d5c84 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,9 +88,10 @@ static void appledisplay_complete(struct urb *urb)
{
struct appledisplay *pdata = urb->context;
unsigned long flags;
+ int status = urb->status;
int retval;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -102,12 +103,12 @@ static void appledisplay_complete(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* This urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
+ dbg("%s - urb shuttingdown with status: %d",
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
goto exit;
}
@@ -137,7 +138,7 @@ exit:
static int appledisplay_bl_update_status(struct backlight_device *bd)
{
- struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+ struct appledisplay *pdata = bl_get_data(bd);
int retval;
pdata->msgdata[0] = 0x10;
@@ -158,7 +159,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)
static int appledisplay_bl_get_brightness(struct backlight_device *bd)
{
- struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+ struct appledisplay *pdata = bl_get_data(bd);
int retval;
retval = usb_control_msg(
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index cac1500cba62..df7e1ecc810a 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -630,7 +630,7 @@ static int auerchain_start_wait_urb (pauerchain_t acp, struct urb *urb, int time
} else
status = urb->status;
- if (actual_length)
+ if (status >= 0)
*actual_length = urb->actual_length;
return status;
@@ -664,7 +664,7 @@ static int auerchain_control_msg (pauerchain_t acp, struct usb_device *dev, unsi
int ret;
struct usb_ctrlrequest *dr;
struct urb *urb;
- int length;
+ int uninitialized_var(length);
dbg ("auerchain_control_msg");
dr = kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
@@ -862,14 +862,16 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb)
pauerbuf_t bp = (pauerbuf_t) urb->context;
pauerswald_t cp;
int ret;
+ int status = urb->status;
+
dbg ("auerswald_ctrlread_wretcomplete called");
- dbg ("complete with status: %d", urb->status);
+ dbg ("complete with status: %d", status);
cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
/* check if it is possible to advance */
- if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+ if (!auerswald_status_retry(status) || !cp->usbdev) {
/* reuse the buffer */
- err ("control dummy: transmission error %d, can not retry", urb->status);
+ err ("control dummy: transmission error %d, can not retry", status);
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
@@ -902,21 +904,23 @@ static void auerswald_ctrlread_complete (struct urb * urb)
pauerswald_t cp;
pauerscon_t scp;
pauerbuf_t bp = (pauerbuf_t) urb->context;
+ int status = urb->status;
int ret;
+
dbg ("auerswald_ctrlread_complete called");
cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
/* check if there is valid data in this urb */
- if (urb->status) {
- dbg ("complete with non-zero status: %d", urb->status);
+ if (status) {
+ dbg ("complete with non-zero status: %d", status);
/* should we do a retry? */
- if (!auerswald_status_retry (urb->status)
+ if (!auerswald_status_retry(status)
|| !cp->usbdev
|| (cp->version < AUV_RETRY)
|| (bp->retries >= AU_RETRIES)) {
/* reuse the buffer */
- err ("control read: transmission error %d, can not retry", urb->status);
+ err ("control read: transmission error %d, can not retry", status);
auerbuf_releasebuf (bp);
/* Wake up all processes waiting for a buffer */
wake_up (&cp->bufferwait);
@@ -974,12 +978,13 @@ static void auerswald_int_complete (struct urb * urb)
unsigned int channelid;
unsigned int bytecount;
int ret;
+ int status = urb->status;
pauerbuf_t bp = NULL;
pauerswald_t cp = (pauerswald_t) urb->context;
dbg ("%s called", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -987,10 +992,10 @@ static void auerswald_int_complete (struct urb * urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
goto exit;
}
@@ -2034,12 +2039,12 @@ static void auerswald_disconnect (struct usb_interface *intf)
if (!cp)
return;
- down (&cp->mutex);
- info ("device /dev/%s now disconnecting", cp->name);
-
/* give back our USB minor number */
usb_deregister_dev(intf, &auerswald_class);
+ down (&cp->mutex);
+ info ("device /dev/%s now disconnecting", cp->name);
+
/* Stop the interrupt endpoint */
auerswald_int_release (cp);
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
index b15f2fd8dab4..92c1d2768df9 100644
--- a/drivers/usb/misc/berry_charge.c
+++ b/drivers/usb/misc/berry_charge.c
@@ -26,8 +26,11 @@
#define RIM_VENDOR 0x0fca
#define BLACKBERRY 0x0001
+#define BLACKBERRY_PEARL_DUAL 0x0004
+#define BLACKBERRY_PEARL 0x0006
static int debug;
+static int pearl_dual_mode = 1;
#ifdef dbg
#undef dbg
@@ -38,6 +41,8 @@ static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
+ { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL) },
+ { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL_DUAL) },
{ }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -86,6 +91,30 @@ static int magic_charge(struct usb_device *udev)
return retval;
}
+static int magic_dual_mode(struct usb_device *udev)
+{
+ char *dummy_buffer = kzalloc(2, GFP_KERNEL);
+ int retval;
+
+ if (!dummy_buffer)
+ return -ENOMEM;
+
+ /* send magic command so that the Blackberry Pearl device exposes
+ * two interfaces: both the USB mass-storage one and one which can
+ * be used for database access. */
+ dbg(&udev->dev, "Sending magic pearl command\n");
+ retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ 0xa9, 0xc0, 1, 1, dummy_buffer, 2, 100);
+ dbg(&udev->dev, "Magic pearl command returned %d\n", retval);
+
+ dbg(&udev->dev, "Calling set_configuration\n");
+ retval = usb_driver_set_configuration(udev, 1);
+ if (retval)
+ dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+
+ return retval;
+}
+
static int berry_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -105,6 +134,10 @@ static int berry_probe(struct usb_interface *intf,
/* turn the power on */
magic_charge(udev);
+ if ((le16_to_cpu(udev->descriptor.idProduct) == BLACKBERRY_PEARL) &&
+ (pearl_dual_mode))
+ magic_dual_mode(udev);
+
/* we don't really want to bind to the device, userspace programs can
* handle the syncing just fine, so get outta here. */
return -ENODEV;
@@ -138,3 +171,5 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(pearl_dual_mode, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pearl_dual_mode, "Change Blackberry Pearl to run in dual mode");
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index e0f122e131d7..538b535e955b 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -44,6 +44,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/workqueue.h>
@@ -64,7 +65,7 @@ static struct workqueue_struct *respond_queue;
* ftdi_module_lock exists to protect access to global variables
*
*/
-static struct semaphore ftdi_module_lock;
+static struct mutex ftdi_module_lock;
static int ftdi_instances = 0;
static struct list_head ftdi_static_list;
/*
@@ -199,10 +200,10 @@ static void ftdi_elan_delete(struct kref *kref)
dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
usb_put_dev(ftdi->udev);
ftdi->disconnected += 1;
- down(&ftdi_module_lock);
+ mutex_lock(&ftdi_module_lock);
list_del_init(&ftdi->ftdi_list);
ftdi_instances -= 1;
- up(&ftdi_module_lock);
+ mutex_unlock(&ftdi_module_lock);
kfree(ftdi->bulk_in_buffer);
ftdi->bulk_in_buffer = NULL;
}
@@ -746,10 +747,12 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
static void ftdi_elan_write_bulk_callback(struct urb *urb)
{
struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
- if (urb->status && !(urb->status == -ENOENT || urb->status ==
- -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ int status = urb->status;
+
+ if (status && !(status == -ENOENT || status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
- "d\n", urb, urb->status);
+ "d\n", urb, status);
}
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
@@ -2780,10 +2783,10 @@ static int ftdi_elan_probe(struct usb_interface *interface,
return -ENOMEM;
}
memset(ftdi, 0x00, sizeof(struct usb_ftdi));
- down(&ftdi_module_lock);
+ mutex_lock(&ftdi_module_lock);
list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
ftdi->sequence_num = ++ftdi_instances;
- up(&ftdi_module_lock);
+ mutex_unlock(&ftdi_module_lock);
ftdi_elan_init_kref(ftdi);
init_MUTEX(&ftdi->sw_lock);
ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -2909,7 +2912,7 @@ static int __init ftdi_elan_init(void)
int result;
printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
__TIME__, __DATE__);
- init_MUTEX(&ftdi_module_lock);
+ mutex_init(&ftdi_module_lock);
INIT_LIST_HEAD(&ftdi_static_list);
status_queue = create_singlethread_workqueue("ftdi-status-control");
if (!status_queue)
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 8d0e360636e6..e6fd024024f5 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -119,9 +119,6 @@ static struct usb_driver idmouse_driver = {
.id_table = idmouse_table,
};
-/* prevent races between open() and disconnect() */
-static DEFINE_MUTEX(disconnect_mutex);
-
static int idmouse_create_image(struct usb_idmouse *dev)
{
int bytes_read;
@@ -211,21 +208,15 @@ static int idmouse_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int result;
- /* prevent disconnects */
- mutex_lock(&disconnect_mutex);
-
/* get the interface from minor number and driver information */
interface = usb_find_interface (&idmouse_driver, iminor (inode));
- if (!interface) {
- mutex_unlock(&disconnect_mutex);
+ if (!interface)
return -ENODEV;
- }
+
/* get the device information block from the interface */
dev = usb_get_intfdata(interface);
- if (!dev) {
- mutex_unlock(&disconnect_mutex);
+ if (!dev)
return -ENODEV;
- }
/* lock this device */
down(&dev->sem);
@@ -255,9 +246,6 @@ error:
/* unlock this device */
up(&dev->sem);
-
- /* unlock the disconnect semaphore */
- mutex_unlock(&disconnect_mutex);
return result;
}
@@ -265,15 +253,10 @@ static int idmouse_release(struct inode *inode, struct file *file)
{
struct usb_idmouse *dev;
- /* prevent a race condition with open() */
- mutex_lock(&disconnect_mutex);
-
dev = file->private_data;
- if (dev == NULL) {
- mutex_unlock(&disconnect_mutex);
+ if (dev == NULL)
return -ENODEV;
- }
/* lock our device */
down(&dev->sem);
@@ -281,7 +264,6 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* are we really open? */
if (dev->open <= 0) {
up(&dev->sem);
- mutex_unlock(&disconnect_mutex);
return -ENODEV;
}
@@ -291,12 +273,9 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* the device was unplugged before the file was released */
up(&dev->sem);
idmouse_delete(dev);
- mutex_unlock(&disconnect_mutex);
- return 0;
+ } else {
+ up(&dev->sem);
}
-
- up(&dev->sem);
- mutex_unlock(&disconnect_mutex);
return 0;
}
@@ -391,30 +370,27 @@ static void idmouse_disconnect(struct usb_interface *interface)
{
struct usb_idmouse *dev;
- /* prevent races with open() */
- mutex_lock(&disconnect_mutex);
-
/* get device structure */
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
- /* lock it */
- down(&dev->sem);
-
/* give back our minor */
usb_deregister_dev(interface, &idmouse_class);
+ /* lock it */
+ down(&dev->sem);
+
/* prevent device read, write and ioctl */
dev->present = 0;
- /* unlock */
- up(&dev->sem);
-
/* if the device is opened, idmouse_release will clean this up */
- if (!dev->open)
+ if (!dev->open) {
+ up(&dev->sem);
idmouse_delete(dev);
-
- mutex_unlock(&disconnect_mutex);
+ } else {
+ /* unlock */
+ up(&dev->sem);
+ }
info("%s disconnected", DRIVER_DESC);
}
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 3bb33f7bfa36..46d9f27ec173 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -100,8 +100,6 @@ struct iowarrior {
/*--------------*/
/* globals */
/*--------------*/
-/* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
/*
* USB spec identifies 5 second timeouts.
@@ -160,9 +158,10 @@ static void iowarrior_callback(struct urb *urb)
int read_idx;
int aux_idx;
int offset;
- int status;
+ int status = urb->status;
+ int retval;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -215,10 +214,10 @@ static void iowarrior_callback(struct urb *urb)
wake_up_interruptible(&dev->read_wait);
exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
@@ -228,13 +227,15 @@ exit:
static void iowarrior_write_callback(struct urb *urb)
{
struct iowarrior *dev;
+ int status = urb->status;
+
dev = (struct iowarrior *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ if (status &&
+ !(status == -ENOENT ||
+ status == -ECONNRESET || status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
- __func__, urb->status);
+ __func__, status);
}
/* free up our allocated buffer */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
@@ -600,22 +601,18 @@ static int iowarrior_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
- /* prevent disconnects */
- down(&disconnect_sem);
-
interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) {
err("%s - error, can't find device for minor %d", __FUNCTION__,
subminor);
- retval = -ENODEV;
- goto out;
+ return -ENODEV;
}
dev = usb_get_intfdata(interface);
- if (!dev) {
- retval = -ENODEV;
- goto out;
- }
+ if (!dev)
+ return -ENODEV;
+
+ mutex_lock(&dev->mutex);
/* Only one process can open each device, no sharing. */
if (dev->opened) {
@@ -636,7 +633,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
retval = 0;
out:
- up(&disconnect_sem);
+ mutex_unlock(&dev->mutex);
return retval;
}
@@ -868,19 +865,16 @@ static void iowarrior_disconnect(struct usb_interface *interface)
struct iowarrior *dev;
int minor;
- /* prevent races with open() */
- down(&disconnect_sem);
-
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
- mutex_lock(&dev->mutex);
-
minor = dev->minor;
/* give back our minor */
usb_deregister_dev(interface, &iowarrior_class);
+ mutex_lock(&dev->mutex);
+
/* prevent device read, write and ioctl */
dev->present = 0;
@@ -898,7 +892,6 @@ static void iowarrior_disconnect(struct usb_interface *interface)
/* no process is using the device, cleanup now */
iowarrior_delete(dev);
}
- up(&disconnect_sem);
dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
minor - IOWARRIOR_MINOR_BASE);
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 7bad49404762..8208496dfc63 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -176,9 +176,6 @@ struct ld_usb {
int interrupt_out_busy;
};
-/* prevent races between open() and disconnect() */
-static DEFINE_MUTEX(disconnect_mutex);
-
static struct usb_driver ld_usb_driver;
/**
@@ -222,16 +219,17 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
struct ld_usb *dev = urb->context;
size_t *actual_buffer;
unsigned int next_ring_head;
+ int status = urb->status;
int retval;
- if (urb->status) {
- if (urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN) {
+ if (status) {
+ if (status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN) {
goto exit;
} else {
dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
spin_lock(&dev->rbsl);
goto resubmit; /* maybe we can recover */
}
@@ -278,14 +276,15 @@ exit:
static void ld_usb_interrupt_out_callback(struct urb *urb)
{
struct ld_usb *dev = urb->context;
+ int status = urb->status;
/* sync/async unlink faults aren't errors */
- if (urb->status && !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN))
+ if (status && !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN))
dbg_info(&dev->intf->dev,
"%s - nonzero write interrupt status received: %d\n",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
@@ -298,35 +297,28 @@ static int ld_usb_open(struct inode *inode, struct file *file)
{
struct ld_usb *dev;
int subminor;
- int retval = 0;
+ int retval;
struct usb_interface *interface;
nonseekable_open(inode, file);
subminor = iminor(inode);
- mutex_lock(&disconnect_mutex);
-
interface = usb_find_interface(&ld_usb_driver, subminor);
if (!interface) {
err("%s - error, can't find device for minor %d\n",
__FUNCTION__, subminor);
- retval = -ENODEV;
- goto unlock_disconnect_exit;
+ return -ENODEV;
}
dev = usb_get_intfdata(interface);
- if (!dev) {
- retval = -ENODEV;
- goto unlock_disconnect_exit;
- }
+ if (!dev)
+ return -ENODEV;
/* lock this device */
- if (down_interruptible(&dev->sem)) {
- retval = -ERESTARTSYS;
- goto unlock_disconnect_exit;
- }
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
/* allow opening only once */
if (dev->open_count) {
@@ -366,9 +358,6 @@ static int ld_usb_open(struct inode *inode, struct file *file)
unlock_exit:
up(&dev->sem);
-unlock_disconnect_exit:
- mutex_unlock(&disconnect_mutex);
-
return retval;
}
@@ -766,18 +755,16 @@ static void ld_usb_disconnect(struct usb_interface *intf)
struct ld_usb *dev;
int minor;
- mutex_lock(&disconnect_mutex);
-
dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
- down(&dev->sem);
-
minor = intf->minor;
/* give back our minor */
usb_deregister_dev(intf, &ld_usb_class);
+ down(&dev->sem);
+
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
up(&dev->sem);
@@ -787,8 +774,6 @@ static void ld_usb_disconnect(struct usb_interface *intf)
up(&dev->sem);
}
- mutex_unlock(&disconnect_mutex);
-
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
(minor - USB_LD_MINOR_BASE));
}
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 1713e19a7899..561970b889a5 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -254,9 +254,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_devic
static void tower_disconnect (struct usb_interface *interface);
-/* prevent races between open() and disconnect */
-static DEFINE_MUTEX (disconnect_mutex);
-
/* file operations needed when we register this driver */
static const struct file_operations tower_fops = {
.owner = THIS_MODULE,
@@ -344,28 +341,26 @@ static int tower_open (struct inode *inode, struct file *file)
nonseekable_open(inode, file);
subminor = iminor(inode);
- mutex_lock (&disconnect_mutex);
-
interface = usb_find_interface (&tower_driver, subminor);
if (!interface) {
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
- goto unlock_disconnect_exit;
+ goto exit;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
- goto unlock_disconnect_exit;
+ goto exit;
}
/* lock this device */
if (down_interruptible (&dev->sem)) {
retval = -ERESTARTSYS;
- goto unlock_disconnect_exit;
+ goto exit;
}
/* allow opening only once */
@@ -421,9 +416,7 @@ static int tower_open (struct inode *inode, struct file *file)
unlock_exit:
up (&dev->sem);
-unlock_disconnect_exit:
- mutex_unlock (&disconnect_mutex);
-
+exit:
dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
return retval;
@@ -749,19 +742,20 @@ exit:
static void tower_interrupt_in_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int status = urb->status;
int retval;
- dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, status);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- if (urb->status) {
- if (urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN) {
+ if (status) {
+ if (status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN) {
goto exit;
} else {
- dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+ dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
goto resubmit; /* maybe we can recover */
}
}
@@ -795,7 +789,7 @@ exit:
wake_up_interruptible (&dev->read_wait);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, status);
}
@@ -805,23 +799,24 @@ exit:
static void tower_interrupt_out_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+ int status = urb->status;
- dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: enter, status %d", __FUNCTION__, status);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
/* sync/async unlink faults aren't errors */
- if (urb->status && !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN)) {
+ if (status && !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dbg(1, "%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
dev->interrupt_out_busy = 0;
wake_up_interruptible(&dev->write_wait);
lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
- dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+ dbg(4, "%s: leave, status %d", __FUNCTION__, status);
}
@@ -993,19 +988,16 @@ static void tower_disconnect (struct usb_interface *interface)
dbg(2, "%s: enter", __FUNCTION__);
- mutex_lock (&disconnect_mutex);
-
dev = usb_get_intfdata (interface);
usb_set_intfdata (interface, NULL);
-
- down (&dev->sem);
-
minor = dev->minor;
/* give back our minor */
usb_deregister_dev (interface, &tower_class);
+ down (&dev->sem);
+
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
up (&dev->sem);
@@ -1015,8 +1007,6 @@ static void tower_disconnect (struct usb_interface *interface)
up (&dev->sem);
}
- mutex_unlock (&disconnect_mutex);
-
info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
dbg(2, "%s: leave", __FUNCTION__);
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 371bf2b1197d..aa9bcceabe74 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -305,9 +305,10 @@ static void interfacekit_irq(struct urb *urb)
struct interfacekit *kit = urb->context;
unsigned char *buffer = kit->data;
int i, level, sensor;
- int status;
+ int retval;
+ int status = urb->status;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -377,11 +378,11 @@ static void interfacekit_irq(struct urb *urb)
schedule_delayed_work(&kit->do_notify, 0);
resubmit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
kit->udev->bus->bus_name,
- kit->udev->devpath, status);
+ kit->udev->devpath, retval);
}
static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index 5727e1ea2f91..df0ebcdb9d6a 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -95,9 +95,10 @@ static void motorcontrol_irq(struct urb *urb)
struct motorcontrol *mc = urb->context;
unsigned char *buffer = mc->data;
int i, level;
- int status;
+ int retval;
+ int status = urb->status;;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -151,12 +152,12 @@ static void motorcontrol_irq(struct urb *urb)
schedule_delayed_work(&mc->do_notify, 0);
resubmit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
dev_err(&mc->intf->dev,
- "can't resubmit intr, %s-%s/motorcontrol0, status %d",
+ "can't resubmit intr, %s-%s/motorcontrol0, retval %d",
mc->udev->bus->bus_name,
- mc->udev->devpath, status);
+ mc->udev->devpath, retval);
}
static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 6f8b134a79cb..9f37ba44c132 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -72,8 +72,6 @@ MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES
static struct usb_driver sisusb_driver;
-DEFINE_MUTEX(disconnect_mutex);
-
static void
sisusb_free_buffers(struct sisusb_usb_data *sisusb)
{
@@ -2511,31 +2509,24 @@ sisusb_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor = iminor(inode);
- mutex_lock(&disconnect_mutex);
-
if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
subminor);
- mutex_unlock(&disconnect_mutex);
return -ENODEV;
}
- if (!(sisusb = usb_get_intfdata(interface))) {
- mutex_unlock(&disconnect_mutex);
+ if (!(sisusb = usb_get_intfdata(interface)))
return -ENODEV;
- }
mutex_lock(&sisusb->lock);
if (!sisusb->present || !sisusb->ready) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
return -ENODEV;
}
if (sisusb->isopen) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
return -EBUSY;
}
@@ -2543,7 +2534,6 @@ sisusb_open(struct inode *inode, struct file *file)
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Failed to initialize "
"device\n",
@@ -2552,7 +2542,6 @@ sisusb_open(struct inode *inode, struct file *file)
}
} else {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Device not attached to "
"USB 2.0 hub\n",
@@ -2570,8 +2559,6 @@ sisusb_open(struct inode *inode, struct file *file)
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
-
return 0;
}
@@ -2601,12 +2588,8 @@ sisusb_release(struct inode *inode, struct file *file)
struct sisusb_usb_data *sisusb;
int myminor;
- mutex_lock(&disconnect_mutex);
-
- if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
- mutex_unlock(&disconnect_mutex);
+ if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
return -ENODEV;
- }
mutex_lock(&sisusb->lock);
@@ -2626,8 +2609,6 @@ sisusb_release(struct inode *inode, struct file *file)
/* decrement the usage count on our device */
kref_put(&sisusb->kref, sisusb_delete);
- mutex_unlock(&disconnect_mutex);
-
return 0;
}
@@ -3383,12 +3364,9 @@ static void sisusb_disconnect(struct usb_interface *intf)
sisusb_console_exit(sisusb);
#endif
- /* The above code doesn't need the disconnect
- * semaphore to be down; its meaning is to
- * protect all other routines from the disconnect
- * case, not the other way round.
- */
- mutex_lock(&disconnect_mutex);
+ minor = sisusb->minor;
+
+ usb_deregister_dev(intf, &usb_sisusb_class);
mutex_lock(&sisusb->lock);
@@ -3396,12 +3374,8 @@ static void sisusb_disconnect(struct usb_interface *intf)
if (!sisusb_wait_all_out_complete(sisusb))
sisusb_kill_all_busy(sisusb);
- minor = sisusb->minor;
-
usb_set_intfdata(intf, NULL);
- usb_deregister_dev(intf, &usb_sisusb_class);
-
#ifdef SISUSB_OLD_CONFIG_COMPAT
if (sisusb->ioctl32registered) {
int ret;
@@ -3426,8 +3400,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
/* decrement our usage count */
kref_put(&sisusb->kref, sisusb_delete);
- mutex_unlock(&disconnect_mutex);
-
printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 5947afb0017e..8d0edc867f33 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -214,18 +214,13 @@ sisusbcon_init(struct vc_data *c, int init)
* are set up/restored.
*/
- mutex_lock(&disconnect_mutex);
-
- if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
- mutex_unlock(&disconnect_mutex);
+ if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
return;
- }
mutex_lock(&sisusb->lock);
if (!sisusb_sisusb_valid(sisusb)) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
return;
}
@@ -264,8 +259,6 @@ sisusbcon_init(struct vc_data *c, int init)
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
-
if (init) {
c->vc_cols = cols;
c->vc_rows = rows;
@@ -284,12 +277,8 @@ sisusbcon_deinit(struct vc_data *c)
* and others, ie not under our control.
*/
- mutex_lock(&disconnect_mutex);
-
- if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
- mutex_unlock(&disconnect_mutex);
+ if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
return;
- }
mutex_lock(&sisusb->lock);
@@ -314,8 +303,6 @@ sisusbcon_deinit(struct vc_data *c)
/* decrement the usage count on our sisusb */
kref_put(&sisusb->kref, sisusb_delete);
-
- mutex_unlock(&disconnect_mutex);
}
/* interface routine */
@@ -1490,14 +1477,11 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
{
int i, ret, minor = sisusb->minor;
- mutex_lock(&disconnect_mutex);
-
mutex_lock(&sisusb->lock);
/* Erm.. that should not happen */
if (sisusb->haveconsole || !sisusb->SiS_Pr) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
return 1;
}
@@ -1508,14 +1492,12 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
first > MAX_NR_CONSOLES ||
last > MAX_NR_CONSOLES) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
return 1;
}
/* If gfxcore not initialized or no consoles given, quit graciously */
if (!sisusb->gfxinit || first < 1 || last < 1) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
return 0;
}
@@ -1526,7 +1508,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Set up text mode (and upload default font) */
if (sisusb_reset_text_mode(sisusb, 1)) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Failed to set up text mode\n",
minor);
@@ -1550,7 +1531,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Allocate screen buffer */
if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate screen buffer\n",
minor);
@@ -1558,7 +1538,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
}
mutex_unlock(&sisusb->lock);
- mutex_unlock(&disconnect_mutex);
/* Now grab the desired console(s) */
ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
index f05f83268af4..864bc0e96591 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -808,8 +808,6 @@ static const struct SiS_VCLKData SiSUSB_VCLKData[] =
{ 0x2b,0xc2, 35} /* 0x71 768@576@60 */
};
-extern struct mutex disconnect_mutex;
-
int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 12bad8a205a7..719842032712 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -45,13 +45,13 @@ struct usb_lcd {
struct kref kref;
struct semaphore limit_sem; /* to stop writes at full throttle from
* using up all RAM */
+ struct usb_anchor submitted; /* URBs to wait for before suspend */
};
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
#define USB_LCD_CONCURRENT_WRITES 5
static struct usb_driver lcd_driver;
-static DEFINE_MUTEX(usb_lcd_open_mutex);
static void lcd_delete(struct kref *kref)
@@ -68,35 +68,35 @@ static int lcd_open(struct inode *inode, struct file *file)
{
struct usb_lcd *dev;
struct usb_interface *interface;
- int subminor;
- int retval = 0;
+ int subminor, r;
subminor = iminor(inode);
- mutex_lock(&usb_lcd_open_mutex);
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
err ("USBLCD: %s - error, can't find device for minor %d",
__FUNCTION__, subminor);
- retval = -ENODEV;
- goto exit;
+ return -ENODEV;
}
dev = usb_get_intfdata(interface);
- if (!dev) {
- retval = -ENODEV;
- goto exit;
- }
+ if (!dev)
+ return -ENODEV;
/* increment our usage count for the device */
kref_get(&dev->kref);
+ /* grab a power reference */
+ r = usb_autopm_get_interface(interface);
+ if (r < 0) {
+ kref_put(&dev->kref, lcd_delete);
+ return r;
+ }
+
/* save our object in the file's private structure */
file->private_data = dev;
-exit:
- mutex_unlock(&usb_lcd_open_mutex);
- return retval;
+ return 0;
}
static int lcd_release(struct inode *inode, struct file *file)
@@ -108,6 +108,7 @@ static int lcd_release(struct inode *inode, struct file *file)
return -ENODEV;
/* decrement the count on our device */
+ usb_autopm_put_interface(dev->interface);
kref_put(&dev->kref, lcd_delete);
return 0;
}
@@ -175,16 +176,17 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
static void lcd_write_bulk_callback(struct urb *urb)
{
struct usb_lcd *dev;
+ int status = urb->status;
dev = (struct usb_lcd *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN)) {
+ if (status &&
+ !(status == -ENOENT ||
+ status == -ECONNRESET ||
+ status == -ESHUTDOWN)) {
dbg("USBLCD: %s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
}
/* free up our allocated buffer */
@@ -233,12 +235,14 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, count, lcd_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_anchor_urb(urb, &dev->submitted);
/* 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);
- goto error;
+ goto error_unanchor;
}
/* release our reference to this urb, the USB core will eventually free it entirely */
@@ -246,7 +250,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
exit:
return count;
-
+error_unanchor:
+ usb_unanchor_urb(urb);
error:
usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
usb_free_urb(urb);
@@ -291,6 +296,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
}
kref_init(&dev->kref);
sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
+ init_usb_anchor(&dev->submitted);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
@@ -358,22 +364,41 @@ error:
return retval;
}
+static void lcd_draw_down(struct usb_lcd *dev)
+{
+ int time;
+
+ time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
+ if (!time)
+ usb_kill_anchored_urbs(&dev->submitted);
+}
+
+static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_lcd *dev = usb_get_intfdata(intf);
+
+ if (!dev)
+ return 0;
+ lcd_draw_down(dev);
+ return 0;
+}
+
+static int lcd_resume (struct usb_interface *intf)
+{
+ return 0;
+}
+
static void lcd_disconnect(struct usb_interface *interface)
{
struct usb_lcd *dev;
int minor = interface->minor;
- /* prevent skel_open() from racing skel_disconnect() */
- mutex_lock(&usb_lcd_open_mutex);
-
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &lcd_class);
- mutex_unlock(&usb_lcd_open_mutex);
-
/* decrement our usage count */
kref_put(&dev->kref, lcd_delete);
@@ -384,7 +409,10 @@ static struct usb_driver lcd_driver = {
.name = "usblcd",
.probe = lcd_probe,
.disconnect = lcd_disconnect,
+ .suspend = lcd_suspend,
+ .resume = lcd_resume,
.id_table = id_table,
+ .supports_autosuspend = 1,
};
static int __init usb_lcd_init(void)
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index fb321864a92d..e901d31e051b 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -768,8 +768,8 @@ static void ctrl_complete (struct urb *urb)
/* some faults are allowed, not required */
if (subcase->expected > 0 && (
- ((urb->status == -subcase->expected /* happened */
- || urb->status == 0)))) /* didn't */
+ ((status == -subcase->expected /* happened */
+ || status == 0)))) /* didn't */
status = 0;
/* sometimes more than one fault is allowed */
else if (subcase->number == 12 && status == -EPIPE)
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 1a60f9c473ad..2734fe2b9c43 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -111,12 +111,13 @@ static void async_complete(struct urb *urb)
struct uss720_async_request *rq;
struct parport *pp;
struct parport_uss720_private *priv;
+ int status = urb->status;
rq = urb->context;
priv = rq->priv;
pp = priv->pp;
- if (urb->status) {
- err("async_complete: urb error %d", urb->status);
+ if (status) {
+ err("async_complete: urb error %d", status);
} else if (rq->dr.bRequest == 3) {
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index 0af11a66207c..c03dfd7a9d36 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -4,7 +4,7 @@
* This is a binary format reader.
*
* Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
- * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ * Copyright (C) 2006,2007 Pete Zaitcev (zaitcev@redhat.com)
*/
#include <linux/kernel.h>
@@ -172,6 +172,7 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
+static struct class *mon_bin_class;
static dev_t mon_bin_dev0;
static struct cdev mon_bin_cdev;
@@ -1144,10 +1145,38 @@ static void mon_free_buff(struct mon_pgmap *map, int npages)
free_page((unsigned long) map[n].ptr);
}
+int mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+ struct device *dev;
+ unsigned minor = ubus? ubus->busnum: 0;
+
+ if (minor >= MON_BIN_MAX_MINOR)
+ return 0;
+
+ dev = device_create(mon_bin_class, ubus? ubus->controller: NULL,
+ MKDEV(MAJOR(mon_bin_dev0), minor), "usbmon%d", minor);
+ if (IS_ERR(dev))
+ return 0;
+
+ mbus->classdev = dev;
+ return 1;
+}
+
+void mon_bin_del(struct mon_bus *mbus)
+{
+ device_destroy(mon_bin_class, mbus->classdev->devt);
+}
+
int __init mon_bin_init(void)
{
int rc;
+ mon_bin_class = class_create(THIS_MODULE, "usbmon");
+ if (IS_ERR(mon_bin_class)) {
+ rc = PTR_ERR(mon_bin_class);
+ goto err_class;
+ }
+
rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
if (rc < 0)
goto err_dev;
@@ -1164,6 +1193,8 @@ int __init mon_bin_init(void)
err_add:
unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
err_dev:
+ class_destroy(mon_bin_class);
+err_class:
return rc;
}
@@ -1171,4 +1202,5 @@ void mon_bin_exit(void)
{
cdev_del(&mon_bin_cdev);
unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+ class_destroy(mon_bin_class);
}
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 8977ec0d0f99..ce61d8b0fd86 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -220,6 +220,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
list_del(&mbus->bus_link);
if (mbus->text_inited)
mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
mon_dissolve(mbus, ubus);
kref_put(&mbus->ref, mon_bus_drop);
@@ -301,8 +303,8 @@ static void mon_bus_init(struct usb_bus *ubus)
mbus->u_bus = ubus;
ubus->mon_bus = mbus;
- mbus->text_inited = mon_text_add(mbus, ubus->busnum);
- // mon_bin_add(...)
+ mbus->text_inited = mon_text_add(mbus, ubus);
+ mbus->bin_inited = mon_bin_add(mbus, ubus);
mutex_lock(&mon_lock);
list_add_tail(&mbus->bus_link, &mon_buses);
@@ -321,8 +323,8 @@ static void mon_bus0_init(void)
spin_lock_init(&mbus->lock);
INIT_LIST_HEAD(&mbus->r_list);
- mbus->text_inited = mon_text_add(mbus, 0);
- // mbus->bin_inited = mon_bin_add(mbus, 0);
+ mbus->text_inited = mon_text_add(mbus, NULL);
+ mbus->bin_inited = mon_bin_add(mbus, NULL);
}
/*
@@ -403,6 +405,8 @@ static void __exit mon_exit(void)
if (mbus->text_inited)
mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
/*
* This never happens, because the open/close paths in
@@ -423,6 +427,8 @@ static void __exit mon_exit(void)
mbus = &mon_bus0;
if (mbus->text_inited)
mon_text_del(mbus);
+ if (mbus->bin_inited)
+ mon_bin_del(mbus);
mutex_unlock(&mon_lock);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index ec0cc51e39ac..8f27a9e1c36b 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -340,7 +340,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
- mon_text_ctor, NULL);
+ mon_text_ctor);
if (rp->e_slab == NULL) {
rc = -ENOMEM;
goto err_slab;
@@ -655,20 +655,24 @@ static const struct file_operations mon_fops_text_u = {
.release = mon_text_release,
};
-int mon_text_add(struct mon_bus *mbus, int busnum)
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
{
struct dentry *d;
enum { NAMESZ = 10 };
char name[NAMESZ];
+ int busnum = ubus? ubus->busnum: 0;
int rc;
- rc = snprintf(name, NAMESZ, "%dt", busnum);
- if (rc <= 0 || rc >= NAMESZ)
- goto err_print_t;
- d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t);
- if (d == NULL)
- goto err_create_t;
- mbus->dent_t = d;
+ if (ubus != NULL) {
+ rc = snprintf(name, NAMESZ, "%dt", busnum);
+ if (rc <= 0 || rc >= NAMESZ)
+ goto err_print_t;
+ d = debugfs_create_file(name, 0600, mon_dir, mbus,
+ &mon_fops_text_t);
+ if (d == NULL)
+ goto err_create_t;
+ mbus->dent_t = d;
+ }
rc = snprintf(name, NAMESZ, "%du", busnum);
if (rc <= 0 || rc >= NAMESZ)
@@ -694,8 +698,10 @@ err_print_s:
mbus->dent_u = NULL;
err_create_u:
err_print_u:
- debugfs_remove(mbus->dent_t);
- mbus->dent_t = NULL;
+ if (ubus != NULL) {
+ debugfs_remove(mbus->dent_t);
+ mbus->dent_t = NULL;
+ }
err_create_t:
err_print_t:
return 0;
@@ -704,7 +710,8 @@ err_print_t:
void mon_text_del(struct mon_bus *mbus)
{
debugfs_remove(mbus->dent_u);
- debugfs_remove(mbus->dent_t);
+ if (mbus->dent_t != NULL)
+ debugfs_remove(mbus->dent_t);
debugfs_remove(mbus->dent_s);
}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index 13d63255283e..f68ad6d99ad7 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -20,9 +20,11 @@ struct mon_bus {
struct usb_bus *u_bus;
int text_inited;
+ int bin_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
struct dentry *dent_u; /* Second text interface file */
+ struct device *classdev; /* Device in usbmon class */
/* Ref */
int nreaders; /* Under mon_lock AND mbus->lock */
@@ -52,9 +54,10 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
struct mon_bus *mon_bus_lookup(unsigned int num);
-int /*bool*/ mon_text_add(struct mon_bus *mbus, int busnum);
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
void mon_text_del(struct mon_bus *mbus);
-// void mon_bin_add(struct mon_bus *);
+int /*bool*/ mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_bin_del(struct mon_bus *mbus);
int __init mon_text_init(void);
void mon_text_exit(void);
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 3efe67092f15..43d6db696f90 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -464,6 +464,16 @@ config USB_SERIAL_PL2303
To compile this driver as a module, choose M here: the
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
+ help
+ Say Y here if you want to use the OTi-6858 single port USB to serial
+ converter device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called oti6858.
+
config USB_SERIAL_HP4X
tristate "USB HP4x Calculators support"
depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 61166ad450e6..07a976eca6b7 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -40,6 +40,7 @@ obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
+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
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index fbc8c27d5d99..1cd29cd6bd00 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -411,12 +411,13 @@ static int aircable_write(struct usb_serial_port *port,
static void aircable_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
+ int status = urb->status;
int result;
- dbg("%s - urb->status: %d", __FUNCTION__ , urb->status);
+ dbg("%s - urb status: %d", __FUNCTION__ , status);
/* This has been taken from cypress_m8.c cypress_write_int_callback */
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -425,14 +426,14 @@ 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__, urb->status);
+ __FUNCTION__, 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 - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -457,16 +458,17 @@ static void aircable_read_bulk_callback(struct urb *urb)
unsigned long no_packages, remaining, package_length, i;
int result, shift = 0;
unsigned char *temp;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - urb status = %d", __FUNCTION__, status);
if (!port->open_count) {
dbg("%s - port is closed, exiting.", __FUNCTION__);
return;
}
- if (urb->status == -EPROTO) {
+ if (status == -EPROTO) {
dbg("%s - caught -EPROTO, resubmitting the urb",
__FUNCTION__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 39a498362594..cff6fd190a28 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -82,12 +82,13 @@ static void airprime_read_bulk_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
int result;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
+ if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
return;
}
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
@@ -109,6 +110,7 @@ static void airprime_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct airprime_private *priv = usb_get_serial_port_data(port);
+ int status = urb->status;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -116,9 +118,9 @@ static void airprime_write_bulk_callback(struct urb *urb)
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
- if (urb->status)
+ if (status)
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
spin_lock_irqsave(&priv->lock, flags);
--priv->outstanding_urbs;
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index fe437125f14b..c9fd486c1c7d 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -172,7 +172,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
- if ((!port->tty) || (!port->tty->termios)) {
+ if (!port->tty || !port->tty->termios) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
@@ -188,16 +188,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
cflag = port->tty->termios->c_cflag;
- /* check that they really want us to change something: */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
- RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
- }
- }
-
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
dbg("error kmalloc");
@@ -220,7 +210,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("setting CS7");
break;
default:
- err("CSIZE was set but not CS5-CS8, using CS8!");
+ dbg("CSIZE was set but not CS5-CS8, using CS8!");
/* fall through */
case CS8:
config |= 0x03;
@@ -251,38 +241,33 @@ static void ark3116_set_termios(struct usb_serial_port *port,
}
/* set baudrate */
- baud = 0;
- switch (cflag & CBAUD) {
- case B0:
- err("can't set 0 baud, using 9600 instead");
+ baud = tty_get_baud_rate(port->tty);
+
+ switch (baud) {
+ case 75:
+ case 150:
+ case 300:
+ case 600:
+ case 1200:
+ case 1800:
+ case 2400:
+ case 4800:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 57600:
+ case 115200:
+ case 230400:
+ case 460800:
break;
- case B75: baud = 75; break;
- case B150: baud = 150; break;
- case B300: baud = 300; break;
- case B600: baud = 600; break;
- case B1200: baud = 1200; break;
- case B1800: baud = 1800; break;
- case B2400: baud = 2400; break;
- case B4800: baud = 4800; break;
- case B9600: baud = 9600; break;
- case B19200: baud = 19200; break;
- case B38400: baud = 38400; break;
- case B57600: baud = 57600; break;
- case B115200: baud = 115200; break;
- case B230400: baud = 230400; break;
- case B460800: baud = 460800; break;
+ /* set 9600 as default (if given baudrate is invalid for example) */
default:
- dbg("does not support the baudrate requested (fix it)");
- break;
+ baud = 9600;
}
- /* set 9600 as default (if given baudrate is invalid for example) */
- if (baud == 0)
- baud = 9600;
-
/*
* found by try'n'error, be careful, maybe there are other options
- * for multiplicator etc!
+ * for multiplicator etc! (3.5 for example)
*/
if (baud == 460800)
/* strange, for 460800 the formula is wrong
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 3b800d277c4b..e67ce25f7512 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -255,9 +255,10 @@ static void belkin_sa_read_int_callback (struct urb *urb)
struct belkin_sa_private *priv;
unsigned char *data = urb->transfer_buffer;
int retval;
+ int status = urb->status;
unsigned long flags;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -265,10 +266,12 @@ static void belkin_sa_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__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, status);
goto exit;
}
@@ -346,6 +349,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
unsigned long flags;
unsigned long control_state;
int bad_flow_control;
+ speed_t baud;
if ((!port->tty) || (!port->tty->termios)) {
dbg ("%s - no tty or termios structure", __FUNCTION__);
@@ -361,16 +365,8 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
bad_flow_control = priv->bad_flow_control;
spin_unlock_irqrestore(&priv->lock, flags);
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
- }
- old_iflag = old_termios->c_iflag;
- old_cflag = old_termios->c_cflag;
- }
+ old_iflag = old_termios->c_iflag;
+ old_cflag = old_termios->c_cflag;
/* Set the baud rate */
if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
@@ -384,38 +380,30 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
err("Set RTS error");
}
+ }
- switch(cflag & CBAUD) {
- case B0: /* handled below */ break;
- case B300: urb_value = BELKIN_SA_BAUD(300); break;
- case B600: urb_value = BELKIN_SA_BAUD(600); break;
- case B1200: urb_value = BELKIN_SA_BAUD(1200); break;
- case B2400: urb_value = BELKIN_SA_BAUD(2400); break;
- case B4800: urb_value = BELKIN_SA_BAUD(4800); break;
- case B9600: urb_value = BELKIN_SA_BAUD(9600); break;
- case B19200: urb_value = BELKIN_SA_BAUD(19200); break;
- case B38400: urb_value = BELKIN_SA_BAUD(38400); break;
- case B57600: urb_value = BELKIN_SA_BAUD(57600); break;
- case B115200: urb_value = BELKIN_SA_BAUD(115200); break;
- case B230400: urb_value = BELKIN_SA_BAUD(230400); break;
- default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600");
- urb_value = BELKIN_SA_BAUD(9600); break;
- }
- if ((cflag & CBAUD) != B0 ) {
- if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
- err("Set baudrate error");
- } else {
- /* Disable flow control */
- if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
- err("Disable flowcontrol error");
-
- /* Drop RTS and DTR */
- control_state &= ~(TIOCM_DTR | TIOCM_RTS);
- if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
- err("DTR LOW error");
- if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
- err("RTS LOW error");
- }
+ baud = tty_get_baud_rate(port->tty);
+ urb_value = BELKIN_SA_BAUD(baud);
+ /* Clip to maximum speed */
+ if (urb_value == 0)
+ urb_value = 1;
+ /* Turn it back into a resulting real baud rate */
+ baud = BELKIN_SA_BAUD(urb_value);
+ /* FIXME: Once the tty updates are done then push this back to the tty */
+
+ if ((cflag & CBAUD) != B0 ) {
+ if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
+ err("Set baudrate error");
+ } else {
+ /* Disable flow control */
+ if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
+ err("Disable flowcontrol error");
+ /* Drop RTS and DTR */
+ control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
+ err("DTR LOW error");
+ if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
+ err("RTS LOW error");
}
/* set the parity */
@@ -435,7 +423,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break;
case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break;
case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break;
- default: err("CSIZE was not CS5-CS8, using default of 8");
+ default: dbg("CSIZE was not CS5-CS8, using default of 8");
urb_value = BELKIN_SA_DATA_BITS(8);
break;
}
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 4167753ed31f..4353df92487f 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -305,12 +305,13 @@ static void cyberjack_read_int_callback( struct urb *urb )
struct usb_serial_port *port = (struct usb_serial_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);
/* the urb might have been killed. */
- if (urb->status)
+ if (status)
return;
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
@@ -365,12 +366,14 @@ static void cyberjack_read_bulk_callback (struct urb *urb)
unsigned char *data = urb->transfer_buffer;
short todo;
int result;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -411,12 +414,14 @@ static void cyberjack_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
port->write_urb_busy = 0;
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
return;
}
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 57b8e27285fc..163386336a5d 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -1275,10 +1275,11 @@ static void cypress_read_int_callback(struct urb *urb)
int bytes = 0;
int result;
int i = 0;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET:
@@ -1292,7 +1293,7 @@ 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__,urb->status);
+ __FUNCTION__, status);
cypress_set_dead(port);
return;
}
@@ -1419,10 +1420,11 @@ static void cypress_write_int_callback(struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_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);
-
- switch (urb->status) {
+
+ switch (status) {
case 0:
/* success */
break;
@@ -1430,7 +1432,8 @@ static void cypress_write_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
priv->write_urb_in_use = 0;
return;
case -EPIPE: /* no break needed; clear halt and resubmit */
@@ -1438,7 +1441,8 @@ static void cypress_write_int_callback(struct urb *urb)
break;
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__, urb->status);
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, 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);
@@ -1450,7 +1454,7 @@ static void cypress_write_int_callback(struct urb *urb)
break;
default:
dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
- __FUNCTION__,urb->status);
+ __FUNCTION__, status);
cypress_set_dead(port);
break;
}
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index d78692c01cfa..976f54ec26e6 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -416,9 +416,6 @@ struct digi_port {
int dp_port_num;
int dp_out_buf_len;
unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];
- int dp_in_buf_len;
- unsigned char dp_in_buf[DIGI_IN_BUF_SIZE];
- unsigned char dp_in_flag_buf[DIGI_IN_BUF_SIZE];
int dp_write_urb_in_use;
unsigned int dp_modem_signals;
wait_queue_head_t dp_modem_change_wait;
@@ -920,7 +917,6 @@ dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
spin_lock_irqsave( &priv->dp_port_lock, flags );
priv->dp_throttled = 1;
priv->dp_throttle_restart = 0;
- priv->dp_in_buf_len = 0;
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
}
@@ -930,23 +926,16 @@ static void digi_rx_unthrottle( struct usb_serial_port *port )
{
int ret = 0;
- int len;
unsigned long flags;
struct digi_port *priv = usb_get_serial_port_data(port);
- struct tty_struct *tty = port->tty;
-
dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
spin_lock_irqsave( &priv->dp_port_lock, flags );
- /* send any buffered chars from throttle time on to tty subsystem */
-
- len = tty_buffer_request_room(tty, priv->dp_in_buf_len);
- if( len > 0 ) {
- tty_insert_flip_string_flags(tty, priv->dp_in_buf, priv->dp_in_flag_buf, len);
- tty_flip_buffer_push( tty );
- }
+ /* turn throttle off */
+ priv->dp_throttled = 0;
+ priv->dp_throttle_restart = 0;
/* restart read chain */
if( priv->dp_throttle_restart ) {
@@ -954,11 +943,6 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
ret = usb_submit_urb( port->read_urb, GFP_ATOMIC );
}
- /* turn throttle off */
- priv->dp_throttled = 0;
- priv->dp_in_buf_len = 0;
- priv->dp_throttle_restart = 0;
-
spin_unlock_irqrestore( &priv->dp_port_lock, flags );
if( ret ) {
@@ -1340,19 +1324,21 @@ static void digi_write_bulk_callback( struct urb *urb )
struct digi_port *priv;
struct digi_serial *serial_priv;
int ret = 0;
+ int status = urb->status;
-dbg( "digi_write_bulk_callback: TOP, urb->status=%d", urb->status );
+ dbg("digi_write_bulk_callback: TOP, urb status=%d", status);
/* 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__,
- urb->status );
+ err("%s: port or port->private is NULL, status=%d",
+ __FUNCTION__, 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__, urb->status );
+ err("%s: serial or serial->private is NULL, status=%d",
+ __FUNCTION__, status);
return;
}
@@ -1687,7 +1673,6 @@ dbg( "digi_startup: TOP" );
spin_lock_init( &priv->dp_port_lock );
priv->dp_port_num = i;
priv->dp_out_buf_len = 0;
- priv->dp_in_buf_len = 0;
priv->dp_write_urb_in_use = 0;
priv->dp_modem_signals = 0;
init_waitqueue_head( &priv->dp_modem_change_wait );
@@ -1757,25 +1742,28 @@ static void digi_read_bulk_callback( struct urb *urb )
struct digi_port *priv;
struct digi_serial *serial_priv;
int ret;
+ int status = urb->status;
dbg( "digi_read_bulk_callback: TOP" );
/* 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__,
- urb->status );
+ err("%s: port or port->private is NULL, status=%d",
+ __FUNCTION__, 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__, urb->status );
+ err("%s: serial is bad or serial->private is NULL, status=%d",
+ __FUNCTION__, status);
return;
}
/* do not resubmit urb if it has any status error */
- if( urb->status ) {
- err("%s: nonzero read bulk status: status=%d, port=%d", __FUNCTION__, urb->status, priv->dp_port_num );
+ if (status) {
+ err("%s: nonzero read bulk status: status=%d, port=%d",
+ __FUNCTION__, status, priv->dp_port_num);
return;
}
@@ -1816,10 +1804,11 @@ static int digi_read_inb_callback( struct urb *urb )
struct digi_port *priv = usb_get_serial_port_data(port);
int opcode = ((unsigned char *)urb->transfer_buffer)[0];
int len = ((unsigned char *)urb->transfer_buffer)[1];
- int status = ((unsigned char *)urb->transfer_buffer)[2];
+ int port_status = ((unsigned char *)urb->transfer_buffer)[2];
unsigned char *data = ((unsigned char *)urb->transfer_buffer)+3;
int flag,throttled;
int i;
+ int status = urb->status;
/* do not process callbacks on closed ports */
/* but do continue the read chain */
@@ -1828,7 +1817,10 @@ static int digi_read_inb_callback( struct urb *urb )
/* short/multiple packet check */
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__, urb->status, priv->dp_port_num, opcode, len, urb->actual_length, status );
+ err("%s: INCOMPLETE OR MULTIPLE PACKET, urb status=%d, "
+ "port=%d, opcode=%d, len=%d, actual_length=%d, "
+ "port_status=%d", __FUNCTION__, status, priv->dp_port_num,
+ opcode, len, urb->actual_length, port_status);
return( -1 );
}
@@ -1843,52 +1835,37 @@ static int digi_read_inb_callback( struct urb *urb )
/* receive data */
if( opcode == DIGI_CMD_RECEIVE_DATA ) {
- /* get flag from status */
+ /* get flag from port_status */
flag = 0;
/* overrun is special, not associated with a char */
- if( status & DIGI_OVERRUN_ERROR ) {
+ if (port_status & DIGI_OVERRUN_ERROR) {
tty_insert_flip_char( tty, 0, TTY_OVERRUN );
}
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
- if( status & DIGI_BREAK_ERROR ) {
+ if (port_status & DIGI_BREAK_ERROR) {
flag = TTY_BREAK;
- } else if( status & DIGI_PARITY_ERROR ) {
+ } else if (port_status & DIGI_PARITY_ERROR) {
flag = TTY_PARITY;
- } else if( status & DIGI_FRAMING_ERROR ) {
+ } else if (port_status & DIGI_FRAMING_ERROR) {
flag = TTY_FRAME;
}
- /* data length is len-1 (one byte of len is status) */
+ /* data length is len-1 (one byte of len is port_status) */
--len;
- if( throttled ) {
-
- len = min( len,
- DIGI_IN_BUF_SIZE - priv->dp_in_buf_len );
-
- if( len > 0 ) {
- memcpy( priv->dp_in_buf + priv->dp_in_buf_len,
- data, len );
- memset( priv->dp_in_flag_buf
- + priv->dp_in_buf_len, flag, len );
- priv->dp_in_buf_len += len;
- }
-
- } else {
- len = tty_buffer_request_room(tty, len);
- if( len > 0 ) {
- /* Hot path */
- if(flag == TTY_NORMAL)
- tty_insert_flip_string(tty, data, len);
- else {
- for(i = 0; i < len; i++)
- tty_insert_flip_char(tty, data[i], flag);
- }
- tty_flip_buffer_push( tty );
+ len = tty_buffer_request_room(tty, len);
+ if( len > 0 ) {
+ /* Hot path */
+ if(flag == TTY_NORMAL)
+ tty_insert_flip_string(tty, data, len);
+ else {
+ for(i = 0; i < len; i++)
+ tty_insert_flip_char(tty, data[i], flag);
}
+ tty_flip_buffer_push( tty );
}
}
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 4703c8f85383..050fcc996f56 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -326,12 +326,14 @@ static int empeg_chars_in_buffer (struct usb_serial_port *port)
static void empeg_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);
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -345,11 +347,13 @@ static void empeg_read_bulk_callback (struct urb *urb)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int result;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index da1c6f7f82b8..7b1673a44077 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -271,26 +271,58 @@ static int debug;
static __u16 vendor = FTDI_VID;
static __u16 product;
+struct ftdi_private {
+ ftdi_chip_type_t chip_type;
+ /* type of the device, either SIO or FT8U232AM */
+ int baud_base; /* baud base clock for divisor setting */
+ int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
+ __u16 last_set_data_urb_value ;
+ /* the last data state set - needed for doing a break */
+ int write_offset; /* This is the offset in the usb data block to write the serial data -
+ * it is different between devices
+ */
+ int flags; /* some ASYNC_xxxx flags are supported */
+ unsigned long last_dtr_rts; /* saved modem control outputs */
+ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
+ char prev_status, diff_status; /* Used for TIOCMIWAIT */
+ __u8 rx_flags; /* receive state flags (throttling) */
+ spinlock_t rx_lock; /* spinlock for receive state */
+ struct delayed_work rx_work;
+ struct usb_serial_port *port;
+ int rx_processed;
+ unsigned long rx_bytes;
+
+ __u16 interface; /* FT2232C port interface (0 for FT232/245) */
+
+ int force_baud; /* if non-zero, force the baud rate to this value */
+ int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
+
+ spinlock_t tx_lock; /* spinlock for transmit state */
+ unsigned long tx_bytes;
+ unsigned long tx_outstanding_bytes;
+ unsigned long tx_outstanding_urbs;
+};
+
/* struct ftdi_sio_quirk is used by devices requiring special attention. */
struct ftdi_sio_quirk {
int (*probe)(struct usb_serial *);
- void (*setup)(struct usb_serial *); /* Special settings during startup. */
+ void (*port_probe)(struct ftdi_private *); /* Special settings for probed ports. */
};
static int ftdi_olimex_probe (struct usb_serial *serial);
-static void ftdi_USB_UIRT_setup (struct usb_serial *serial);
-static void ftdi_HE_TIRA1_setup (struct usb_serial *serial);
+static void ftdi_USB_UIRT_setup (struct ftdi_private *priv);
+static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv);
static struct ftdi_sio_quirk ftdi_olimex_quirk = {
.probe = ftdi_olimex_probe,
};
static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
- .setup = ftdi_USB_UIRT_setup,
+ .port_probe = ftdi_USB_UIRT_setup,
};
static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
- .setup = ftdi_HE_TIRA1_setup,
+ .port_probe = ftdi_HE_TIRA1_setup,
};
/*
@@ -567,38 +599,6 @@ static const char *ftdi_chip_name[] = {
#define THROTTLED 0x01
#define ACTUALLY_THROTTLED 0x02
-struct ftdi_private {
- ftdi_chip_type_t chip_type;
- /* type of the device, either SIO or FT8U232AM */
- int baud_base; /* baud base clock for divisor setting */
- int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
- __u16 last_set_data_urb_value ;
- /* the last data state set - needed for doing a break */
- int write_offset; /* This is the offset in the usb data block to write the serial data -
- * it is different between devices
- */
- int flags; /* some ASYNC_xxxx flags are supported */
- unsigned long last_dtr_rts; /* saved modem control outputs */
- wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- char prev_status, diff_status; /* Used for TIOCMIWAIT */
- __u8 rx_flags; /* receive state flags (throttling) */
- spinlock_t rx_lock; /* spinlock for receive state */
- struct delayed_work rx_work;
- struct usb_serial_port *port;
- int rx_processed;
- unsigned long rx_bytes;
-
- __u16 interface; /* FT2232C port interface (0 for FT232/245) */
-
- int force_baud; /* if non-zero, force the baud rate to this value */
- int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
-
- spinlock_t tx_lock; /* spinlock for transmit state */
- unsigned long tx_bytes;
- unsigned long tx_outstanding_bytes;
- unsigned long tx_outstanding_urbs;
-};
-
/* Used for TIOCMIWAIT */
#define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
@@ -609,7 +609,6 @@ struct ftdi_private {
/* function prototypes for a FTDI serial converter */
static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id);
-static int ftdi_sio_attach (struct usb_serial *serial);
static void ftdi_shutdown (struct usb_serial *serial);
static int ftdi_sio_port_probe (struct usb_serial_port *port);
static int ftdi_sio_port_remove (struct usb_serial_port *port);
@@ -663,7 +662,6 @@ static struct usb_serial_driver ftdi_sio_device = {
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
- .attach = ftdi_sio_attach,
.shutdown = ftdi_shutdown,
};
@@ -1149,7 +1147,9 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
retval = device_create_file(&port->dev, &dev_attr_event_char);
if ((!retval) &&
- (priv->chip_type == FT232BM || priv->chip_type == FT2232C)) {
+ (priv->chip_type == FT232BM ||
+ priv->chip_type == FT2232C ||
+ priv->chip_type == FT232RL)) {
retval = device_create_file(&port->dev,
&dev_attr_latency_timer);
}
@@ -1198,6 +1198,8 @@ static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id
static int ftdi_sio_port_probe(struct usb_serial_port *port)
{
struct ftdi_private *priv;
+ struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial);
+
dbg("%s",__FUNCTION__);
@@ -1214,6 +1216,9 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
than queue a task to deliver them */
priv->flags = ASYNC_LOW_LATENCY;
+ if (quirk && quirk->port_probe)
+ quirk->port_probe(priv);
+
/* Increase the size of read buffers */
kfree(port->bulk_in_buffer);
port->bulk_in_buffer = kmalloc (BUFSZ, GFP_KERNEL);
@@ -1244,29 +1249,13 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
return 0;
}
-/* attach subroutine */
-static int ftdi_sio_attach (struct usb_serial *serial)
-{
- /* Check for device requiring special set up. */
- struct ftdi_sio_quirk *quirk = usb_get_serial_data(serial);
-
- if (quirk && quirk->setup)
- quirk->setup(serial);
-
- return 0;
-} /* ftdi_sio_attach */
-
-
/* Setup for the USB-UIRT device, which requires hardwired
* baudrate (38400 gets mapped to 312500) */
/* Called from usbserial:serial_probe */
-static void ftdi_USB_UIRT_setup (struct usb_serial *serial)
+static void ftdi_USB_UIRT_setup (struct ftdi_private *priv)
{
- struct ftdi_private *priv;
-
dbg("%s",__FUNCTION__);
- priv = usb_get_serial_port_data(serial->port[0]);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
priv->force_baud = B38400;
@@ -1274,13 +1263,10 @@ static void ftdi_USB_UIRT_setup (struct usb_serial *serial)
/* Setup for the HE-TIRA1 device, which requires hardwired
* baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */
-static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
+static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv)
{
- struct ftdi_private *priv;
-
dbg("%s",__FUNCTION__);
- priv = usb_get_serial_port_data(serial->port[0]);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
priv->force_baud = B38400;
@@ -1574,14 +1560,15 @@ static void ftdi_write_bulk_callback (struct urb *urb)
struct ftdi_private *priv;
int data_offset; /* will be 1 for the SIO and 0 otherwise */
unsigned long countback;
+ int status = urb->status;
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("nonzero write bulk status received: %d", urb->status);
+ if (status) {
+ dbg("nonzero write bulk status received: %d", status);
return;
}
@@ -1657,6 +1644,7 @@ static void ftdi_read_bulk_callback (struct urb *urb)
struct ftdi_private *priv;
unsigned long countread;
unsigned long flags;
+ int status = urb->status;
if (urb->number_of_packets > 0) {
err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
@@ -1685,9 +1673,10 @@ static void ftdi_read_bulk_callback (struct urb *urb)
err("%s - Not my urb!", __FUNCTION__);
}
- if (urb->status) {
+ if (status) {
/* This will happen at close every time so it is a dbg not an err */
- dbg("(this is ok on close) nonzero read bulk status received: %d", urb->status);
+ dbg("(this is ok on close) nonzero read bulk status received: "
+ "%d", status);
return;
}
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 74660a3aa670..04bd3b7a2985 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1036,15 +1036,16 @@ static void garmin_write_bulk_callback (struct urb *urb)
unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ int status = urb->status;
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
+ if (status) {
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
@@ -1281,7 +1282,8 @@ static void garmin_read_bulk_callback (struct urb *urb)
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;
+ int status = urb->status;
+ int retval;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -1290,9 +1292,9 @@ static void garmin_read_bulk_callback (struct urb *urb)
return;
}
- if (urb->status) {
+ if (status) {
dbg("%s - nonzero read bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
return;
}
@@ -1306,19 +1308,19 @@ static void garmin_read_bulk_callback (struct urb *urb)
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
- status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (retval)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
} else if (urb->actual_length > 0) {
/* Continue trying to read until nothing more is received */
if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) {
- status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (retval)
dev_err(&port->dev,
- "%s - failed resubmitting read urb, error %d\n",
- __FUNCTION__, status);
+ "%s - failed resubmitting read urb, "
+ "error %d\n", __FUNCTION__, retval);
}
} else {
dbg("%s - end of bulk data", __FUNCTION__);
@@ -1333,13 +1335,14 @@ static void garmin_read_bulk_callback (struct urb *urb)
static void garmin_read_int_callback (struct urb *urb)
{
unsigned long flags;
- int status;
+ int retval;
struct usb_serial_port *port = (struct usb_serial_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;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -1348,11 +1351,11 @@ 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__, urb->status);
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
return;
}
@@ -1374,11 +1377,11 @@ static void garmin_read_int_callback (struct urb *urb)
port->read_urb->transfer_buffer,
port->read_urb->transfer_buffer_length,
garmin_read_bulk_callback, port);
- status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (status) {
+ retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (retval) {
dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
} else {
spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE;
@@ -1422,11 +1425,11 @@ static void garmin_read_int_callback (struct urb *urb)
}
port->interrupt_in_urb->dev = port->serial->dev;
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
dev_err(&urb->dev->dev,
"%s - Error %d submitting interrupt urb\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 4f8282ad7720..88a2c7dce335 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -69,6 +69,7 @@ struct usb_serial_driver usb_serial_generic_device = {
.shutdown = usb_serial_generic_shutdown,
.throttle = usb_serial_generic_throttle,
.unthrottle = usb_serial_generic_unthrottle,
+ .resume = usb_serial_generic_resume,
};
static int generic_probe(struct usb_interface *interface,
@@ -169,6 +170,23 @@ static void generic_cleanup (struct usb_serial_port *port)
}
}
+int usb_serial_generic_resume(struct usb_serial *serial)
+{
+ struct usb_serial_port *port;
+ int i, c = 0, r;
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ if (port->open_count && port->read_urb) {
+ r = usb_submit_urb(port->read_urb, GFP_NOIO);
+ if (r < 0)
+ c++;
+ }
+ }
+
+ return c ? -EIO : 0;
+}
+
void usb_serial_generic_close (struct usb_serial_port *port, struct file * filp)
{
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -263,79 +281,82 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
return (chars);
}
-/* Push data to tty layer and resubmit the bulk read URB */
-static void flush_and_resubmit_read_urb (struct usb_serial_port *port)
+
+static void resubmit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
{
- struct usb_serial *serial = port->serial;
struct urb *urb = port->read_urb;
- struct tty_struct *tty = port->tty;
+ struct usb_serial *serial = port->serial;
int result;
- /* Push data to tty */
- if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
- tty_insert_flip_string(tty, urb->transfer_buffer, urb->actual_length);
- tty_flip_buffer_push(tty); /* is this allowed from an URB callback ? */
- }
-
/* Continue reading from device */
- usb_fill_bulk_urb (port->read_urb, serial->dev,
+ usb_fill_bulk_urb (urb, serial->dev,
usb_rcvbulkpipe (serial->dev,
port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
((serial->type->read_bulk_callback) ?
serial->type->read_bulk_callback :
usb_serial_generic_read_bulk_callback), port);
- result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ result = usb_submit_urb(urb, mem_flags);
if (result)
dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
}
+/* Push data to tty layer and resubmit the bulk read URB */
+static void flush_and_resubmit_read_urb (struct usb_serial_port *port)
+{
+ struct urb *urb = port->read_urb;
+ struct tty_struct *tty = port->tty;
+ int room;
+
+ /* Push data to tty */
+ if (tty && urb->actual_length) {
+ room = tty_buffer_request_room(tty, urb->actual_length);
+ if (room) {
+ tty_insert_flip_string(tty, urb->transfer_buffer, room);
+ tty_flip_buffer_push(tty); /* is this allowed from an URB callback ? */
+ }
+ }
+
+ resubmit_read_urb(port, GFP_ATOMIC);
+}
+
void usb_serial_generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
unsigned char *data = urb->transfer_buffer;
- int is_throttled;
- unsigned long flags;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (unlikely(status != 0)) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
/* Throttle the device if requested by tty */
- if (urb->actual_length) {
- spin_lock_irqsave(&port->lock, flags);
- is_throttled = port->throttled = port->throttle_req;
- spin_unlock_irqrestore(&port->lock, flags);
- if (is_throttled) {
- /* Let the received data linger in the read URB;
- * usb_serial_generic_unthrottle() will pick it
- * up later. */
- dbg("%s - throttling device", __FUNCTION__);
- return;
- }
- }
-
- /* Handle data and continue reading from device */
- flush_and_resubmit_read_urb(port);
+ spin_lock(&port->lock);
+ if (!(port->throttled = port->throttle_req))
+ /* Handle data and continue reading from device */
+ flush_and_resubmit_read_urb(port);
+ spin_unlock(&port->lock);
}
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;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
port->write_urb_busy = 0;
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -370,8 +391,8 @@ void usb_serial_generic_unthrottle (struct usb_serial_port *port)
spin_unlock_irqrestore(&port->lock, flags);
if (was_throttled) {
- /* Handle pending data and resume reading from device */
- flush_and_resubmit_read_urb(port);
+ /* Resume reading from device */
+ resubmit_read_urb(port, GFP_KERNEL);
}
}
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 056e1923c4de..dd42f57089ff 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -599,10 +599,11 @@ static void edge_interrupt_callback (struct urb *urb)
int txCredits;
int portNumber;
int result;
+ int status = urb->status;
dbg("%s", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -610,10 +611,12 @@ static void edge_interrupt_callback (struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, status);
goto exit;
}
@@ -688,13 +691,15 @@ static void edge_bulk_in_callback (struct urb *urb)
{
struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
unsigned char *data = urb->transfer_buffer;
- int status;
+ int retval;
__u16 raw_data_length;
+ int status = urb->status;
dbg("%s", __FUNCTION__);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
edge_serial->read_in_progress = false;
return;
}
@@ -722,9 +727,11 @@ static void edge_bulk_in_callback (struct urb *urb)
if (edge_serial->rxBytesAvail > 0) {
dbg("%s - posting a read", __FUNCTION__);
edge_serial->read_urb->dev = edge_serial->serial->dev;
- status = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
- if (status) {
- dev_err(&urb->dev->dev, "%s - usb_submit_urb(read bulk) failed, status = %d\n", __FUNCTION__, status);
+ 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);
edge_serial->read_in_progress = false;
}
} else {
@@ -744,11 +751,13 @@ static void edge_bulk_out_data_callback (struct urb *urb)
{
struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
struct tty_struct *tty;
+ int status = urb->status;
dbg("%s", __FUNCTION__);
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
}
tty = edge_port->port->tty;
@@ -1504,15 +1513,6 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old
}
cflag = tty->termios->c_cflag;
- /* check that they really want us to change something */
- if (old_termios) {
- if (cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag) {
- dbg("%s - nothing to change", __FUNCTION__);
- return;
- }
- }
-
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag, tty->termios->c_iflag);
if (old_termios) {
diff --git a/drivers/usb/serial/io_fw_down3.h b/drivers/usb/serial/io_fw_down3.h
index 93b56d68a27b..4496b068c50f 100644
--- a/drivers/usb/serial/io_fw_down3.h
+++ b/drivers/usb/serial/io_fw_down3.h
@@ -5,7 +5,7 @@
//**************************************************************
-static int IMAGE_SIZE = 12749;
+static int IMAGE_SIZE = 12938;
struct EDGE_FIRMWARE_VERSION_INFO
{
@@ -16,7 +16,7 @@ struct EDGE_FIRMWARE_VERSION_INFO
static struct EDGE_FIRMWARE_VERSION_INFO IMAGE_VERSION_NAME =
{
- 4, 10, 0 // Major, Minor, Build
+ 4, 80, 0 // Major, Minor, Build
};
@@ -27,16 +27,16 @@ static unsigned char IMAGE_ARRAY_NAME[] =
// WORD Length;
// BYTE CheckSum;
// };
-0xca, 0x31,
-0xa8,
+0x87, 0x32,
+0x9a,
-0x02, 0x26, 0xfe, 0x02, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00,
+0x02, 0x27, 0xbf, 0x02, 0x21, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x1a, 0x85, 0x3f,
0x8c, 0x85, 0x40, 0x8a, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00,
0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0xe5, 0x3e,
0x24, 0x08, 0xf8, 0xe6, 0x60, 0x2b, 0xe5, 0x3e, 0x24, 0x10, 0xf8, 0xa6, 0x81, 0xe5, 0x3e, 0x75,
0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0x78, 0x8c, 0xe5, 0x81,
-0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0x94, 0xe6, 0xf0, 0x08, 0xa3, 0xd9,
+0x04, 0xc3, 0x98, 0xf9, 0x94, 0x22, 0x40, 0x03, 0x02, 0x11, 0xdc, 0xe6, 0xf0, 0x08, 0xa3, 0xd9,
0xfa, 0x74, 0x08, 0x25, 0x3e, 0xf8, 0x05, 0x3e, 0x08, 0xe6, 0x54, 0x80, 0x70, 0x0c, 0xe5, 0x3e,
0xb4, 0x07, 0xf3, 0x78, 0x08, 0x75, 0x3e, 0x00, 0x80, 0xef, 0xe5, 0x3e, 0x24, 0x10, 0xf8, 0x86,
0x81, 0xe5, 0x3e, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83,
@@ -49,387 +49,398 @@ static unsigned char IMAGE_ARRAY_NAME[] =
0xc9, 0xf0, 0x69, 0x60, 0x02, 0x7e, 0x04, 0xa3, 0xe0, 0xca, 0xf0, 0x6a, 0x60, 0x02, 0x7e, 0x04,
0xa3, 0xe0, 0xcb, 0xf0, 0x6b, 0x60, 0x02, 0x7e, 0x04, 0x22, 0xc0, 0xe0, 0xc0, 0xd0, 0xc0, 0xf0,
0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05,
-0xc0, 0x06, 0xc0, 0x07, 0x90, 0xff, 0x93, 0x74, 0x01, 0xf0, 0xe5, 0x81, 0x94, 0xfd, 0x40, 0x03,
-0x02, 0x11, 0x94, 0x85, 0x41, 0x8d, 0x85, 0x42, 0x8b, 0x74, 0xaf, 0xf5, 0x82, 0x74, 0xfa, 0xf5,
-0x83, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x4a, 0xe0, 0x30, 0xe7, 0x2c,
-0x90, 0xff, 0x4e, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20,
-0xb4, 0x02, 0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x27,
-0x8d, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82,
-0xa3, 0xe0, 0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x52, 0xe0, 0x30, 0xe7, 0x2c,
-0x90, 0xff, 0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x25,
-0xb4, 0x02, 0x22, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x27,
-0x8d, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82,
-0x80, 0x03, 0x02, 0x02, 0x62, 0x74, 0x15, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x20, 0x04,
-0xf1, 0x20, 0x02, 0x03, 0x30, 0x01, 0xeb, 0x74, 0x18, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0,
-0x14, 0xfc, 0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62,
-0x7e, 0x01, 0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x33, 0x12, 0x00, 0xc9, 0xee,
-0x64, 0x04, 0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64,
-0x02, 0x60, 0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x33, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02,
-0x33, 0x7c, 0x0a, 0x74, 0x18, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0,
-0xa3, 0xee, 0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0,
-0x80, 0x10, 0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0,
-0xd2, 0xb1, 0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6,
-0x60, 0x08, 0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x3d,
-0x60, 0x13, 0x14, 0xf5, 0x3d, 0x70, 0x0e, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11,
-0x0f, 0xd2, 0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0,
-0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32,
-0x90, 0xff, 0x04, 0xe0, 0x90, 0xfa, 0xb6, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa,
-0xec, 0xff, 0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e,
-0x01, 0x7f, 0x08, 0x8e, 0x3b, 0x8f, 0x3c, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec,
-0xff, 0xea, 0x90, 0xfa, 0xba, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x1c, 0x30, 0xe4, 0xf5, 0x4d, 0xe5,
-0x4d, 0xc3, 0x94, 0x02, 0x50, 0x0f, 0x12, 0x1c, 0x11, 0xe4, 0x12, 0x1a, 0x38, 0x05, 0x4d, 0x04,
-0x12, 0x1c, 0x02, 0x80, 0xea, 0x12, 0x1c, 0x30, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24,
-0xc0, 0x70, 0x03, 0x02, 0x08, 0xc5, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6,
-0xe0, 0xfe, 0x54, 0x0f, 0xf5, 0x4d, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a,
-0x90, 0xff, 0x01, 0xe0, 0x12, 0x1b, 0x4c, 0x03, 0x56, 0x00, 0x04, 0x29, 0x01, 0x05, 0x3c, 0x03,
-0x06, 0x03, 0x05, 0x06, 0x45, 0x06, 0x07, 0xa7, 0x08, 0x07, 0xef, 0x09, 0x08, 0x4b, 0x0a, 0x08,
-0x8b, 0x0b, 0x00, 0x00, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa,
-0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x64, 0x02, 0x45,
-0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24,
-0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xee, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0x11, 0x74,
-0x01, 0x12, 0x1a, 0x38, 0x78, 0x67, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x1c, 0x11, 0x74, 0x02, 0x12,
-0x1a, 0x38, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb6, 0xe0,
-0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0f,
-0x26, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb6, 0xe0, 0xff,
-0x60, 0x07, 0x64, 0x80, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0xb2, 0x40, 0x03, 0x02, 0x0f,
-0x26, 0xe5, 0x4d, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x1c, 0x0e, 0x12, 0x1a,
-0x38, 0x80, 0x24, 0x90, 0xff, 0x82, 0x12, 0x1c, 0x0e, 0x12, 0x1a, 0x38, 0x80, 0x19, 0x15, 0x4d,
-0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0x12, 0x1c, 0x0c, 0x12, 0x1a, 0x38, 0x80, 0x09, 0x12, 0x1c,
-0xb3, 0x12, 0x1c, 0x0c, 0x12, 0x1a, 0x38, 0x12, 0x1c, 0x11, 0x12, 0x19, 0xf2, 0x60, 0x05, 0x74,
-0x01, 0x12, 0x1a, 0x38, 0x7f, 0x02, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f,
-0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x14, 0x60, 0x2d,
-0x14, 0x60, 0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x04,
-0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02,
-0x0f, 0x26, 0x78, 0x67, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20,
-0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb6,
-0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb6, 0xe0, 0xd3,
-0x94, 0x01, 0x40, 0x03, 0x02, 0x0f, 0x26, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xfa, 0xba, 0xe0,
-0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0xb2, 0x40, 0x03, 0x02, 0x0f,
-0x26, 0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0,
-0x07, 0xe5, 0x4d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x4d, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0,
-0x54, 0xf7, 0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x4d, 0x24, 0xfe, 0x60,
-0x20, 0x24, 0xfb, 0x60, 0x34, 0x24, 0x06, 0x70, 0x35, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33,
-0xfd, 0x7f, 0x03, 0x12, 0x2d, 0xa8, 0x80, 0x26, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2d, 0xa8, 0x80,
-0x1d, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2d, 0xa8, 0x80, 0x0e,
-0xe4, 0xfd, 0x7f, 0x04, 0x12, 0x2d, 0xa8, 0x80, 0x05, 0x7f, 0x87, 0x12, 0x31, 0x32, 0x15, 0x4d,
-0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, 0x09, 0x12, 0x1c,
-0xb3, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7,
-0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9,
-0x14, 0x60, 0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba,
-0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0,
-0x60, 0x03, 0x02, 0x0f, 0x26, 0x78, 0x67, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, 0x02, 0x31, 0xb1,
-0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe0, 0x07,
-0xe5, 0x4d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x0a, 0xe5, 0x4d, 0xd3, 0x94,
-0x01, 0x40, 0x03, 0x02, 0x0f, 0x26, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xfa, 0xba, 0xe0, 0x70,
-0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x12, 0x31, 0x82,
-0x40, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x26,
-0xe5, 0x4d, 0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x1d, 0x64, 0x02, 0x1d, 0x2f, 0xe5, 0x35, 0x20,
-0xe1, 0x03, 0x02, 0x0f, 0x26, 0x15, 0x4d, 0x30, 0x0a, 0x0b, 0x12, 0x1c, 0xa5, 0xf5, 0x83, 0xe0,
-0x44, 0x08, 0xf0, 0x80, 0x09, 0x12, 0x1c, 0xb3, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0xe4, 0xff,
-0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60,
-0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9,
-0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x30, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xbb,
-0xe0, 0x90, 0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x35, 0x01, 0x80, 0x03, 0x53, 0x35, 0xfe,
-0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45,
-0x3b, 0x70, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa,
-0xba, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, 0x75, 0x24, 0x02,
-0x60, 0x03, 0x02, 0x0f, 0x26, 0xed, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0x30, 0x12, 0x1d,
-0x5d, 0x7d, 0x03, 0x12, 0x0f, 0x6d, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0x2a, 0x90, 0xfa,
-0xb3, 0xe0, 0xfd, 0xa3, 0x12, 0x1c, 0x7b, 0x12, 0x0f, 0x89, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b,
-0xaf, 0x3c, 0x02, 0x0f, 0xba, 0x12, 0x1c, 0x30, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe4, 0x0d, 0x12,
-0x1d, 0x5d, 0x7d, 0x14, 0x12, 0x0f, 0x6d, 0x60, 0x10, 0x02, 0x0f, 0x26, 0x12, 0x1d, 0x5d, 0x7d,
-0x04, 0x12, 0x0f, 0xc1, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x0f, 0x2a, 0x90, 0xfa, 0xb3, 0xe0,
-0xfd, 0xa3, 0x12, 0x1c, 0x7b, 0x12, 0x0f, 0x89, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c,
-0x02, 0x0f, 0xba, 0x12, 0x1d, 0x5d, 0x7d, 0x05, 0x12, 0x0f, 0xc1, 0x60, 0x03, 0x02, 0x0f, 0x26,
-0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3, 0x12, 0x1c, 0x78, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa,
-0xb4, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xbb, 0xe0, 0x90, 0xfa, 0xb2, 0xf0,
-0xe4, 0xf5, 0x4c, 0x90, 0xfa, 0xb2, 0xe0, 0xff, 0xe5, 0x4c, 0xc3, 0x9f, 0x50, 0x24, 0x12, 0x1c,
-0x72, 0x12, 0x0f, 0xcc, 0xff, 0xfd, 0x90, 0xfa, 0xb4, 0xe4, 0x8d, 0xf0, 0x12, 0x1a, 0x6c, 0x90,
-0xfa, 0xb3, 0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0f, 0x26, 0x05, 0x4c,
-0x80, 0xd1, 0x12, 0x1c, 0x72, 0x12, 0x0f, 0xcc, 0x24, 0xfe, 0xff, 0x90, 0xfa, 0xb3, 0xf0, 0xfd,
-0xa3, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x1a, 0x6c, 0x7a, 0xf9, 0x79, 0x6f, 0x7b, 0x01, 0x8b, 0x36,
-0x8a, 0x37, 0x89, 0x38, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x1c, 0x78, 0x12, 0x25,
-0xd7, 0x8f, 0x4c, 0x05, 0x4c, 0x05, 0x4c, 0x12, 0x1c, 0x11, 0xe5, 0x4c, 0x12, 0x1a, 0x38, 0x12,
-0x1c, 0x11, 0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x1a, 0x4a, 0xaf, 0x4c, 0x7e, 0x00, 0xc3, 0xef,
-0x95, 0x3c, 0xee, 0x95, 0x3b, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c, 0x8e, 0x39, 0x8f,
-0x3a, 0x02, 0x2c, 0x07, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5,
-0x3c, 0x64, 0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03,
-0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26,
-0x12, 0x1c, 0xc9, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03,
-0x02, 0x0f, 0x26, 0x75, 0x36, 0x00, 0x75, 0x37, 0x00, 0x75, 0x38, 0x32, 0x02, 0x0f, 0xa9, 0xe5,
-0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26,
-0x90, 0xfa, 0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xd3, 0x90, 0xfa, 0xbb, 0xe0, 0x94, 0x01,
-0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x60, 0x03,
-0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa,
-0xbb, 0xe0, 0xf5, 0x32, 0xe5, 0x32, 0x70, 0x08, 0x43, 0x35, 0x01, 0x53, 0x35, 0xfd, 0x80, 0x06,
-0x53, 0x35, 0xfe, 0x43, 0x35, 0x02, 0xe4, 0xff, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x20, 0xe7, 0x03,
-0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x64, 0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa,
-0xb6, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x26, 0x90, 0xfa, 0xba, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60,
-0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c, 0xc9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35,
-0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26, 0x7f, 0x01, 0x02, 0x31, 0xb1, 0xe5, 0x35, 0x30, 0xe7, 0x03,
-0x02, 0x0f, 0x26, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xd3, 0x90, 0xfa, 0xbb,
-0xe0, 0x94, 0x00, 0x90, 0xfa, 0xba, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x26, 0x12, 0x1c,
-0xc9, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x26, 0xe5, 0x35, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x26,
-0xe4, 0xff, 0x02, 0x31, 0xb1, 0x90, 0xff, 0x01, 0x12, 0x1d, 0x74, 0xef, 0x12, 0x1a, 0x38, 0x90,
-0xfa, 0xb6, 0x12, 0x1d, 0x74, 0x90, 0x00, 0x01, 0xef, 0x12, 0x1a, 0x4a, 0x90, 0x00, 0x02, 0xe4,
-0x12, 0x1a, 0x4a, 0x74, 0x03, 0x12, 0x1c, 0x02, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0xa3, 0xe0, 0x85,
-0x38, 0x82, 0x85, 0x37, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, 0xe0, 0x12, 0x1b,
-0x4c, 0x09, 0x4a, 0x02, 0x09, 0x6c, 0x04, 0x09, 0x8e, 0x05, 0x09, 0xba, 0x06, 0x09, 0xd8, 0x07,
-0x09, 0xf6, 0x08, 0x0a, 0x14, 0x09, 0x0a, 0x32, 0x0b, 0x0a, 0xe7, 0x80, 0x0d, 0x6f, 0x81, 0x0d,
-0xa0, 0x82, 0x0b, 0x2e, 0x83, 0x0b, 0x77, 0x84, 0x0b, 0x96, 0x85, 0x0b, 0xdb, 0x86, 0x0c, 0x26,
-0x87, 0x0c, 0xb7, 0x88, 0x0d, 0x42, 0x89, 0x0a, 0x50, 0x92, 0x0a, 0x50, 0x93, 0x0e, 0x53, 0xc0,
-0x0e, 0x7f, 0xc1, 0x0e, 0x90, 0xc2, 0x00, 0x00, 0x0f, 0x15, 0xe5, 0x35, 0x20, 0xe7, 0x05, 0x7f,
-0x05, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00,
-0x7f, 0x07, 0x02, 0x11, 0x16, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0x18, 0xe5, 0x35, 0x20, 0xe7,
-0x05, 0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd,
-0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x11, 0x16, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0x18, 0xe5, 0x35,
-0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1d, 0x92, 0x50, 0x06, 0xe5, 0x3c, 0x45, 0x3b, 0x70,
-0x05, 0x7f, 0x02, 0x02, 0x30, 0xec, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfe, 0x24, 0xfd, 0x50, 0x02,
-0x80, 0x03, 0x02, 0x31, 0x6f, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02,
-0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x08,
-0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29,
-0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x09, 0x02, 0x11,
-0x16, 0x7f, 0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c,
-0xc1, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, 0x11, 0x16, 0x7f,
-0x07, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60,
-0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x11, 0x16, 0x7f, 0x07, 0x02,
-0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x29, 0x12, 0x1c, 0xc1, 0x60, 0x03, 0x04,
-0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x11, 0x16, 0x7f, 0x07, 0x02, 0x30, 0xec,
-0xe5, 0x35, 0x30, 0xe7, 0x56, 0x12, 0x1c, 0xc9, 0x70, 0x4a, 0x90, 0xff, 0x02, 0xe0, 0xf5, 0x4c,
-0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12, 0xe5, 0x4c, 0xb4, 0x83, 0x05, 0x75,
-0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x4c, 0x12, 0x1b, 0x72, 0x12,
-0x1d, 0x8b, 0x12, 0x25, 0x39, 0x12, 0x1c, 0xd9, 0x12, 0x1a, 0x0b, 0x60, 0x05, 0x12, 0x31, 0xbd,
-0x80, 0x06, 0x85, 0x33, 0x39, 0x85, 0x34, 0x3a, 0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75, 0x38,
-0x72, 0x02, 0x2c, 0x07, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f, 0x18, 0x12, 0x1c, 0xc9, 0x60, 0x05,
-0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x1d, 0x92, 0x40, 0x05, 0x7f, 0x03, 0x02, 0x30, 0xec, 0x90,
-0xff, 0x02, 0xe0, 0xf5, 0x4c, 0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12, 0xe5,
-0x4c, 0xb4, 0x83, 0x05, 0x75, 0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04, 0xf5,
-0x4c, 0x12, 0x1b, 0x72, 0x02, 0x31, 0x6f, 0x12, 0x1d, 0x9c, 0x12, 0x2a, 0x06, 0x12, 0x1c, 0x83,
-0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x78, 0x68, 0x12, 0x1b,
-0x28, 0x90, 0x00, 0x02, 0x12, 0x1a, 0x0b, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, 0xe4, 0x12, 0x1a,
-0x4a, 0x90, 0xfa, 0xb7, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x7c, 0xe6, 0xfc, 0x08, 0xe6, 0x8c,
-0x83, 0x12, 0x1c, 0x8b, 0xef, 0xf0, 0x12, 0x31, 0xc7, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x90, 0xfa,
-0xb6, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06, 0xa3,
-0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, 0xbb, 0xe0, 0x42,
-0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xba, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06, 0xa3, 0xe0,
-0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xbb, 0xe0, 0x42, 0xb0,
-0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0x30, 0x90, 0xfa, 0xb6, 0xe0, 0xb4, 0x01,
-0x0a, 0x12, 0x1c, 0x11, 0xe5, 0x90, 0x12, 0x1a, 0x38, 0x80, 0x08, 0x12, 0x1c, 0x11, 0xe5, 0xb0,
-0x12, 0x1a, 0x38, 0x02, 0x0f, 0xa9, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x24, 0x12, 0x12, 0x1c, 0x41,
-0x20, 0xe1, 0x33, 0x12, 0x1c, 0xd0, 0xef, 0x24, 0xfc, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90, 0xfa,
-0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x1d, 0xa6,
-0xf0, 0x80, 0x13, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0xf0,
-0x80, 0x04, 0x12, 0x1d, 0xad, 0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x90, 0xfa, 0xb6, 0xe0, 0xff,
-0x24, 0x12, 0x12, 0x1c, 0x41, 0x20, 0xe1, 0x39, 0x12, 0x1c, 0xd0, 0xef, 0x24, 0xfc, 0x60, 0x1b,
-0x04, 0x70, 0x2e, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0,
-0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xb7, 0xe0, 0x60,
-0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xdf,
-0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x12, 0x1c, 0xc1, 0x60, 0x4d, 0x04, 0x60,
-0x03, 0x02, 0x0c, 0xb2, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x0f, 0x90, 0xff, 0xa4, 0x12, 0x1c, 0x3a,
-0x30, 0xe1, 0x6f, 0x12, 0x1d, 0x7c, 0x02, 0x0c, 0xb2, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfb, 0x12,
-0x1c, 0x3d, 0xfe, 0x30, 0xe1, 0x5c, 0x30, 0xe2, 0x11, 0x30, 0xb4, 0x05, 0x12, 0x1d, 0x7c, 0x80,
-0x51, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x48, 0x30, 0x95, 0x05, 0x12, 0x1d, 0x7c,
-0x80, 0x40, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x37, 0x90, 0xfa, 0xb7, 0xe0, 0x60,
-0x12, 0x90, 0xff, 0xb4, 0x12, 0x1c, 0x3a, 0x30, 0xe1, 0x28, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02,
-0xf0, 0x80, 0x1f, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfb, 0x12, 0x1c, 0x3d, 0x30, 0xe1, 0x13, 0x30,
-0x93, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54,
-0xfd, 0xf0, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfc,
-0x60, 0x40, 0x04, 0x70, 0x78, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xa2, 0xe0, 0x44,
-0x40, 0xf0, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x65, 0xd2, 0x03, 0xa3, 0xe0, 0x54, 0xdf, 0xf0, 0x90,
-0xff, 0xa3, 0xef, 0x54, 0x7f, 0xf0, 0x80, 0x55, 0x30, 0x03, 0x0e, 0x90, 0xff, 0xa3, 0xe0, 0x44,
-0x80, 0xf0, 0xc2, 0x03, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x54, 0xbf, 0xf0,
-0x80, 0x3b, 0x90, 0xfa, 0xb7, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xb2, 0xe0, 0x44, 0x40, 0xf0, 0xa3,
-0xe0, 0xff, 0x30, 0xe7, 0x28, 0xd2, 0x04, 0xa3, 0xe0, 0x54, 0xdf, 0xf0, 0x90, 0xff, 0xb3, 0xef,
-0x54, 0x7f, 0xf0, 0x80, 0x18, 0x30, 0x04, 0x0e, 0x90, 0xff, 0xb3, 0xe0, 0x44, 0x80, 0xf0, 0xc2,
-0x04, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff, 0x02,
-0x30, 0xec, 0x12, 0x1c, 0x30, 0x90, 0xfa, 0xb6, 0xe0, 0x24, 0xfc, 0x60, 0x0f, 0x04, 0x70, 0x16,
-0x90, 0xff, 0xa6, 0xe0, 0x12, 0x1c, 0x11, 0x12, 0x1a, 0x38, 0x80, 0x0a, 0x90, 0xff, 0xb6, 0xe0,
-0x12, 0x1c, 0x11, 0x12, 0x1a, 0x38, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02, 0x2c, 0x07, 0xe4,
-0xff, 0x12, 0x30, 0xec, 0x12, 0x1d, 0x37, 0x7f, 0x03, 0x12, 0x12, 0x19, 0x90, 0xf9, 0x15, 0xe0,
-0x30, 0xe4, 0x08, 0x90, 0xff, 0x93, 0x74, 0x80, 0xf0, 0x80, 0x10, 0x90, 0xff, 0xfc, 0xe0, 0x54,
-0x7f, 0xf0, 0x7f, 0xff, 0x7e, 0x00, 0x12, 0x30, 0x16, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd,
-0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x90, 0xfa, 0xbc, 0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa,
-0xb4, 0xf0, 0xa3, 0x74, 0x15, 0xf0, 0xe0, 0x54, 0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa,
-0xb9, 0xf0, 0xd3, 0x94, 0x00, 0xe4, 0x94, 0x3e, 0x40, 0x08, 0x90, 0xfa, 0xbd, 0xe0, 0x90, 0xfa,
-0xb9, 0xf0, 0x12, 0x0f, 0x50, 0xe5, 0x31, 0x45, 0x30, 0x70, 0x73, 0x12, 0x1c, 0x4a, 0x90, 0xfa,
-0xbc, 0x12, 0x1d, 0x56, 0x60, 0x27, 0xd3, 0xef, 0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90,
-0xfa, 0xb9, 0x74, 0x40, 0xf0, 0x80, 0x08, 0x90, 0xfa, 0xbd, 0xe0, 0x90, 0xfa, 0xb9, 0xf0, 0x12,
-0x0f, 0x50, 0xe5, 0x31, 0x45, 0x30, 0x70, 0x46, 0x12, 0x1c, 0x4a, 0x80, 0xd1, 0x75, 0x4c, 0x02,
-0x90, 0xfa, 0xbc, 0xe4, 0xf0, 0xa3, 0x04, 0xf0, 0x90, 0xfa, 0xb4, 0xe4, 0xf0, 0xa3, 0x74, 0x0f,
-0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0x90, 0xfa, 0xbd, 0xe0, 0xf5, 0x4a, 0x7d, 0x0f, 0x7c,
-0x00, 0x12, 0x28, 0x9f, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0xe4,
-0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xaf, 0x31,
-0x02, 0x30, 0xec, 0x12, 0x1c, 0xd0, 0x30, 0xe7, 0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x64, 0xf0,
-0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80, 0x11, 0x90, 0xfa, 0xb7, 0xe0, 0x54, 0x0f, 0x90,
-0xf9, 0x63, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02, 0xc2, 0x94, 0xe4, 0xff, 0x02, 0x30, 0xec, 0x12,
-0x1d, 0x9c, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80, 0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x30, 0xec,
-0x12, 0x1c, 0xd0, 0x54, 0x03, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03,
-0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91, 0x80, 0x23, 0x12, 0x1d, 0xa6, 0x12, 0x0f, 0x78,
-0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0x78, 0xff,
-0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2, 0x91, 0x12, 0x1d, 0xa6, 0xf0, 0x90, 0xfa, 0xb7,
-0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f, 0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60,
-0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80, 0x27, 0xc2, 0x92, 0x80, 0x23, 0x12, 0x1d, 0xad,
-0x12, 0x0f, 0x98, 0x60, 0x04, 0xd2, 0x92, 0x80, 0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12,
-0x0f, 0x98, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92, 0x80, 0x02, 0xd2, 0x92, 0x12, 0x1d, 0xad, 0xf0,
-0xe4, 0xff, 0x02, 0x30, 0xec, 0xe5, 0x35, 0x30, 0xe7, 0x07, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f,
-0x18, 0x7f, 0x05, 0x02, 0x30, 0xec, 0x12, 0x31, 0xbd, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb3,
-0x90, 0xfa, 0xb4, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90,
-0xfa, 0xb4, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x22,
-0xaa, 0x4e, 0xa9, 0x4f, 0x7b, 0xff, 0x90, 0xfa, 0xb4, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa,
-0xb9, 0xe0, 0xf5, 0x4a, 0x12, 0x28, 0x9f, 0x75, 0x30, 0x00, 0x8f, 0x31, 0x22, 0x12, 0x22, 0xa0,
-0x7e, 0x00, 0x8e, 0x30, 0x8f, 0x31, 0xef, 0x22, 0xf0, 0x7f, 0x01, 0x12, 0x12, 0x19, 0x90, 0xff,
-0xa6, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x54, 0xa0, 0x22, 0x12, 0x25, 0xd7, 0x8f, 0x4c, 0x7e, 0x00,
-0xc3, 0xef, 0x95, 0x3c, 0xee, 0x95, 0x3b, 0x22, 0xf0, 0x7f, 0x01, 0x12, 0x12, 0x19, 0x90, 0xff,
-0xb6, 0xe0, 0x90, 0xfa, 0xb8, 0xf0, 0x54, 0xa0, 0x22, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02,
-0x2c, 0x07, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x02, 0x31, 0x82, 0x8e, 0x39, 0x8f, 0x3a, 0x02, 0x2c,
-0x07, 0x12, 0x22, 0xa0, 0x7e, 0x00, 0x8e, 0x30, 0x8f, 0x31, 0xef, 0x22, 0x7d, 0x01, 0x12, 0x25,
-0xd7, 0x90, 0xfa, 0xb1, 0xe0, 0x22, 0xef, 0x90, 0xf8, 0x04, 0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf,
-0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd, 0xfe, 0xde, 0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94,
-0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70, 0x03, 0xd0, 0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd,
-0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 0xc0, 0x05, 0xe5, 0x3e, 0x24,
-0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c, 0xff, 0x12, 0x10, 0x78, 0x7f, 0x00, 0x7e, 0x00,
-0xe5, 0x43, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83,
-0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xa3, 0x15, 0x43, 0x80, 0x07, 0xa3, 0xa3, 0xa3,
-0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0,
-0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0,
-0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x12, 0x11, 0x0f, 0xd0, 0x05, 0xd0,
-0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x85, 0xa8, 0x44, 0x75, 0xa8, 0x88, 0xec, 0x70,
-0x02, 0x7c, 0x3f, 0x8c, 0x3d, 0x22, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11, 0x66,
-0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x04, 0xc0, 0x06, 0x7c, 0xff, 0x12, 0x10,
-0x78, 0xe5, 0x43, 0x60, 0x42, 0xfe, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0,
-0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x43, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80,
-0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80, 0xd8, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0,
-0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83,
-0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78, 0x08, 0x08, 0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6,
-0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77, 0x00, 0x80, 0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08,
-0xee, 0x12, 0x11, 0x0f, 0xd0, 0x06, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75,
-0x3d, 0x00, 0x85, 0x44, 0xa8, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc3, 0xe5, 0x43, 0x24,
-0xe8, 0x50, 0x05, 0x12, 0x11, 0x66, 0x80, 0xf4, 0xef, 0x60, 0x31, 0x90, 0x30, 0x54, 0xe4, 0x93,
-0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff, 0x12, 0x10, 0x78, 0xd0, 0x04, 0x43, 0x07, 0x80,
-0xe5, 0x43, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x1b, 0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef,
-0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05, 0x43, 0x12, 0x11, 0x0f, 0xd0, 0x83, 0xd0, 0x82,
-0xd0, 0xf0, 0x22, 0x02, 0x11, 0x94, 0xc0, 0x04, 0x7c, 0x20, 0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04,
-0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75, 0x88, 0x00, 0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00,
-0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04, 0xf0, 0x90, 0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00,
-0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90, 0xff, 0x48, 0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90,
-0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1,
-0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc,
-0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0xd2, 0xb0, 0xd2, 0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12,
-0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x0f, 0xdc,
-0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x03, 0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee,
-0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x42, 0x8e, 0x41, 0x22, 0xc3, 0xef, 0x94, 0xbc,
-0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f, 0xd0, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f,
-0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x40, 0x8e, 0x3f, 0x22, 0xef, 0x70, 0x01, 0x22, 0xc0, 0x00, 0xc0,
-0xa8, 0xc2, 0xaf, 0xe5, 0x3e, 0x24, 0x18, 0xf8, 0xa6, 0x07, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0xc6,
-0x54, 0x7f, 0xf6, 0xd0, 0xa8, 0xe6, 0x30, 0xe7, 0x03, 0xd0, 0x00, 0x22, 0x12, 0x11, 0x66, 0x80,
-0xf4, 0xc0, 0x00, 0x7f, 0x01, 0xef, 0x24, 0x08, 0xf8, 0xe6, 0x60, 0x09, 0x0f, 0xbf, 0x08, 0xf5,
-0x12, 0x11, 0x66, 0x80, 0xee, 0xd0, 0x00, 0x22, 0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00,
-0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8, 0x76, 0x9a, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24,
-0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83, 0xc0, 0x82, 0xc0, 0x83, 0xa3, 0xa3, 0xe4, 0x78,
-0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f, 0x75, 0xf0, 0x02, 0xa4, 0x24, 0x36, 0xf5, 0x82,
-0xe5, 0xf0, 0x34, 0x30, 0xf5, 0x83, 0xe4, 0x93, 0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0,
-0x82, 0xec, 0xf0, 0xa3, 0xee, 0xf0, 0xed, 0x24, 0x08, 0xf8, 0xef, 0x44, 0x80, 0xf6, 0xd0, 0x04,
-0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x75, 0x3e, 0x00, 0x75, 0x43,
-0x00, 0x7a, 0x08, 0x79, 0x18, 0x78, 0x08, 0x76, 0x00, 0x77, 0x00, 0x08, 0x09, 0xda, 0xf8, 0x90,
-0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x30, 0x54, 0xe4, 0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8,
-0x04, 0xf0, 0x78, 0x08, 0x74, 0x80, 0x44, 0x7f, 0xf6, 0x74, 0x01, 0x44, 0x10, 0xf5, 0x89, 0x75,
-0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75, 0x81, 0x8b, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf,
-0xe5, 0x43, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x1b, 0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79,
-0x08, 0xe0, 0x54, 0x7f, 0xfa, 0x7b, 0x00, 0xe6, 0x54, 0x7f, 0xb5, 0x02, 0x02, 0x7b, 0xff, 0x08,
-0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0, 0x07, 0x12, 0x12, 0x41, 0xad, 0x07, 0xaf, 0x02,
-0x12, 0x12, 0x58, 0xd0, 0x07, 0xa3, 0xa3, 0xa3, 0xdf, 0xce, 0x12, 0x11, 0x66, 0x80, 0xc1, 0x8f,
-0x24, 0x12, 0x2a, 0x06, 0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12,
-0x21, 0xf3, 0xe0, 0xfd, 0x12, 0x22, 0x8a, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x21, 0xf3, 0xed, 0xf0,
-0x12, 0x22, 0x56, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xe0, 0xff, 0x12, 0x22, 0x99, 0x24, 0x09, 0x12,
-0x21, 0xf3, 0xef, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x22, 0x09, 0xc0,
-0x83, 0xc0, 0x82, 0xa3, 0xe0, 0x25, 0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15,
-0x82, 0xe0, 0x33, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x78, 0x80, 0x12, 0x22, 0x09,
-0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0xff, 0x12, 0x22, 0x8a, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x21,
-0xf3, 0xef, 0xf0, 0xed, 0x12, 0x22, 0x99, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xed, 0xf0, 0x12, 0x21,
-0xfb, 0xe0, 0xff, 0x30, 0xe7, 0x19, 0x12, 0x22, 0x6e, 0x12, 0x21, 0xf3, 0xe0, 0x60, 0x09, 0x12,
-0x21, 0xfb, 0xef, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x12, 0x21, 0xfb, 0xef, 0x54, 0xfd, 0xf0, 0x78,
-0x7e, 0x12, 0x22, 0x09, 0xa3, 0xa3, 0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6,
-0xfd, 0x12, 0x22, 0x43, 0xa3, 0xe0, 0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24,
-0x05, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x31, 0x94, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x78, 0x80,
-0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x24, 0x06, 0x12, 0x21, 0xf3, 0xe0, 0x60, 0x03, 0x43, 0x07,
-0x04, 0x53, 0x07, 0xfc, 0x78, 0x80, 0x12, 0x22, 0x7a, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0x42,
-0x07, 0x43, 0x07, 0x80, 0x12, 0x22, 0x8a, 0xf5, 0x82, 0x8a, 0x83, 0xa3, 0xa3, 0xef, 0xf0, 0x12,
-0x22, 0x99, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0xff, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xe0,
-0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf, 0x80, 0x03, 0x43, 0x07, 0x20, 0xec,
-0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07, 0x10, 0x12, 0x21, 0xfb, 0xe0, 0xfe,
-0x54, 0x03, 0x60, 0x73, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1, 0x69, 0x78, 0x80, 0x12, 0x22, 0x6f,
-0x12, 0x21, 0xf3, 0xe0, 0x12, 0x1b, 0x4c, 0x14, 0xa6, 0x00, 0x14, 0xda, 0x01, 0x14, 0xdf, 0x03,
-0x14, 0xda, 0x05, 0x14, 0xdf, 0x07, 0x14, 0xda, 0x09, 0x14, 0xdf, 0x0b, 0x14, 0xda, 0x0d, 0x14,
-0xdf, 0x0f, 0x00, 0x00, 0x14, 0xe7, 0xe5, 0x24, 0x64, 0x03, 0x70, 0x21, 0x90, 0xf9, 0x15, 0xe0,
-0x30, 0xe2, 0x0d, 0x30, 0xb4, 0x05, 0x43, 0x07, 0x02, 0x80, 0x2c, 0x53, 0x07, 0xfd, 0x80, 0x27,
-0x30, 0x95, 0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07, 0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05,
-0x43, 0x07, 0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d, 0x43, 0x07, 0x02, 0x80, 0x08, 0x53,
-0x07, 0xfd, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x22, 0x78, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xef,
-0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff, 0x12, 0x21, 0xfb, 0xe0, 0xfe, 0x54,
-0x03, 0x70, 0x03, 0x02, 0x15, 0xd7, 0xee, 0x20, 0xe1, 0x03, 0x02, 0x15, 0xd4, 0x12, 0x22, 0x6e,
-0x12, 0x21, 0xf3, 0xe0, 0x12, 0x1b, 0x4c, 0x15, 0x36, 0x00, 0x15, 0x6c, 0x01, 0x15, 0x6c, 0x03,
-0x15, 0xa0, 0x05, 0x15, 0xa0, 0x07, 0x15, 0x86, 0x09, 0x15, 0x86, 0x0b, 0x15, 0xba, 0x0d, 0x15,
-0xba, 0x0f, 0x00, 0x00, 0x15, 0xd7, 0xe5, 0x24, 0x64, 0x03, 0x70, 0x23, 0x90, 0xf9, 0x15, 0xe0,
-0x30, 0xe2, 0x0f, 0x30, 0xb1, 0x06, 0x53, 0x07, 0x7f, 0x02, 0x15, 0xd7, 0x43, 0x07, 0x80, 0x02,
-0x15, 0xd7, 0x30, 0x94, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x7d, 0x43, 0x07, 0x80, 0x80, 0x78, 0x30,
-0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x70, 0x43, 0x07, 0x80, 0x80, 0x6b, 0xe5, 0x24, 0xb4, 0x03,
-0x09, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xdf,
-0xf0, 0x53, 0x07, 0x7f, 0x80, 0x51, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x44,
-0x10, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x20, 0xf0, 0x53, 0x07, 0x7f, 0x80, 0x37,
-0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0xff,
-0x9e, 0xe0, 0x54, 0xdf, 0xf0, 0x43, 0x07, 0x80, 0x80, 0x1d, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90,
-0xff, 0x9e, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x20, 0xf0, 0x43,
-0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f, 0x78, 0x80, 0x12, 0x22, 0x3f, 0xe0, 0xfc, 0xa3, 0xe0,
-0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03, 0x53, 0x07, 0xdf, 0xec, 0x30, 0xe3, 0x05,
-0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x10, 0x80,
-0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43, 0x07, 0x08, 0x80, 0x03, 0x53, 0x07, 0xf7,
-0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03, 0x53, 0x07, 0xfb, 0xed, 0x30, 0xe6, 0x05,
-0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed, 0x30, 0xe7, 0x05, 0x43, 0x07, 0x02, 0x80,
-0x03, 0x53, 0x07, 0xfd, 0x78, 0x7e, 0x12, 0x22, 0x3f, 0xa3, 0xef, 0xf0, 0x12, 0x31, 0xc7, 0x7f,
-0x00, 0x22, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3, 0x74, 0x16, 0xf0, 0x90, 0xff, 0xf9, 0x74,
-0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcc, 0xe4, 0xfd, 0x12, 0x22, 0xa0, 0x90, 0xfa, 0xcc,
-0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1a, 0x6c, 0x12, 0x18, 0xe2, 0xe5, 0x23, 0x30, 0xe7, 0x02, 0xd2,
-0x02, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x24, 0x90, 0xfa, 0xcc, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5,
-0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b,
-0x00, 0x7a, 0x00, 0x79, 0x23, 0x75, 0x2d, 0x00, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0xe5,
-0x23, 0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x23, 0x64, 0x07, 0x60, 0x1e, 0xe5, 0x23, 0x64,
-0x06, 0x60, 0x18, 0xe5, 0x23, 0x64, 0x14, 0x60, 0x12, 0xe5, 0x23, 0x64, 0x41, 0x60, 0x0c, 0xe5,
-0x23, 0x64, 0x1a, 0x70, 0x46, 0xe5, 0x24, 0x64, 0x02, 0x70, 0x40, 0xe5, 0x23, 0xb4, 0x07, 0x16,
-0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x02, 0xf0, 0xa3,
-0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1e, 0xe5, 0x23, 0xb4, 0x41, 0x12, 0x90, 0xf9, 0x15, 0xe0, 0x44,
-0x06, 0xf0, 0xa3, 0xe0, 0x44, 0x06, 0xf0, 0xd2, 0xb1, 0xd2, 0xb4, 0x80, 0x07, 0x90, 0xf9, 0x15,
-0xe0, 0x44, 0x01, 0xf0, 0x90, 0xf9, 0x16, 0xe0, 0x44, 0x01, 0xf0, 0xe5, 0x23, 0x64, 0x42, 0x60,
-0x05, 0xe5, 0x23, 0xb4, 0x43, 0x0c, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x80, 0xf0, 0xa3, 0xe0, 0x44,
-0x80, 0xf0, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x18, 0xe2, 0x90, 0xff,
-0xf5, 0xe5, 0x23, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x33, 0xf5, 0x34, 0xf5, 0x32, 0x12, 0x1d, 0x84,
-0x12, 0x1c, 0x30, 0x12, 0x1d, 0x8b, 0x90, 0xf9, 0x67, 0x12, 0x1b, 0x43, 0x90, 0xf9, 0x6c, 0x12,
-0x1b, 0x43, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81,
+0xc0, 0x06, 0xc0, 0x07, 0x74, 0x15, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x60, 0x23, 0x74,
+0x66, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x14, 0xf0, 0x70, 0x16, 0x74, 0xff, 0xf0, 0x74,
+0x1c, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x60, 0x04, 0x14, 0xf0, 0x70, 0x04, 0xc2, 0x90,
+0x80, 0xfc, 0x90, 0xff, 0x93, 0x74, 0x81, 0xf0, 0xe5, 0x81, 0x94, 0xfd, 0x40, 0x03, 0x02, 0x11,
+0xdc, 0x85, 0x41, 0x8d, 0x85, 0x42, 0x8b, 0x74, 0xb2, 0xf5, 0x82, 0x74, 0xfa, 0xf5, 0x83, 0xe0,
+0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x4a, 0xe0, 0x30, 0xe7, 0x2c, 0x90, 0xff,
+0x4e, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x20, 0xb4, 0x02,
+0x1d, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x28, 0x4e, 0x80,
+0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x04, 0xd0, 0x83, 0xd0, 0x82, 0xa3, 0xe0,
+0xb4, 0x01, 0x1b, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x52, 0xe0, 0x30, 0xe7, 0x2c, 0x90, 0xff,
+0x56, 0xe0, 0x30, 0xe7, 0x25, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x02, 0xf0, 0x80, 0x25, 0xb4, 0x02,
+0x22, 0xc0, 0x82, 0xc0, 0x83, 0x90, 0xff, 0x7a, 0xe0, 0x30, 0xe7, 0x05, 0x12, 0x28, 0x4e, 0x80,
+0x09, 0xd0, 0x83, 0xd0, 0x82, 0x74, 0x03, 0xf0, 0x80, 0x09, 0xd0, 0x83, 0xd0, 0x82, 0x80, 0x03,
+0x02, 0x02, 0x90, 0x74, 0x16, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x20, 0x04, 0xf1, 0x20,
+0x02, 0x03, 0x30, 0x01, 0xeb, 0x74, 0x19, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xe0, 0x14, 0xfc,
+0xf0, 0xa3, 0xe0, 0xfd, 0xa3, 0xe0, 0xfe, 0x64, 0x04, 0x70, 0x0f, 0xec, 0x70, 0x62, 0x7e, 0x01,
+0x12, 0x00, 0xc9, 0x7c, 0x0a, 0x7d, 0xfa, 0x02, 0x02, 0x61, 0x12, 0x00, 0xc9, 0xee, 0x64, 0x04,
+0x60, 0x1d, 0xec, 0x70, 0x4b, 0x7c, 0x0a, 0xed, 0x14, 0xfd, 0x70, 0x15, 0xee, 0x64, 0x02, 0x60,
+0x07, 0x7e, 0x02, 0x7d, 0x32, 0x02, 0x02, 0x61, 0x7e, 0x01, 0x7d, 0xfa, 0x02, 0x02, 0x61, 0x7c,
+0x0a, 0x74, 0x19, 0xf5, 0x82, 0x74, 0xf9, 0xf5, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0, 0xa3, 0xee,
+0xf0, 0x14, 0x60, 0x18, 0x20, 0xe1, 0x0f, 0x20, 0x01, 0x06, 0xd2, 0xb1, 0xc2, 0xb0, 0x80, 0x10,
+0xc2, 0xb1, 0xd2, 0xb0, 0x80, 0x0a, 0xc2, 0xb1, 0xc2, 0xb0, 0x80, 0x04, 0xd2, 0xb0, 0xd2, 0xb1,
+0x78, 0x19, 0x79, 0x09, 0x7a, 0x07, 0xe7, 0x70, 0x04, 0xa6, 0x00, 0x80, 0x0b, 0xe6, 0x60, 0x08,
+0x16, 0xe6, 0x70, 0x04, 0xe7, 0x44, 0x80, 0xf7, 0x08, 0x09, 0xda, 0xea, 0xe5, 0x3d, 0x60, 0x13,
+0x14, 0xf5, 0x3d, 0x70, 0x0e, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11, 0x57, 0xd2,
+0x8c, 0xd2, 0x8d, 0xd0, 0x07, 0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0,
+0x01, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0xd0, 0xd0, 0xd0, 0xe0, 0x32, 0x90, 0xff,
+0x04, 0xe0, 0x90, 0xfa, 0xb9, 0xf0, 0x90, 0xff, 0x06, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 0xff,
+0xea, 0xfe, 0xef, 0xc3, 0x94, 0x08, 0xee, 0x94, 0x01, 0x50, 0x02, 0x80, 0x04, 0x7e, 0x01, 0x7f,
+0x08, 0x8e, 0x3b, 0x8f, 0x3c, 0x90, 0xff, 0x02, 0xe0, 0xfc, 0xa3, 0xe0, 0xfa, 0xec, 0xff, 0xea,
+0x90, 0xfa, 0xbd, 0xf0, 0xef, 0xa3, 0xf0, 0x12, 0x1c, 0xe0, 0xe4, 0xf5, 0x4d, 0xe5, 0x4d, 0xc3,
+0x94, 0x02, 0x50, 0x0f, 0x12, 0x1c, 0xc1, 0xe4, 0x12, 0x1a, 0xe8, 0x05, 0x4d, 0x04, 0x12, 0x1c,
+0xb2, 0x80, 0xea, 0x12, 0x1c, 0xe0, 0x90, 0xff, 0x00, 0xe0, 0xff, 0x54, 0x60, 0x24, 0xc0, 0x70,
+0x03, 0x02, 0x08, 0xf3, 0x24, 0x40, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0, 0xfe,
+0x54, 0x0f, 0xf5, 0x4d, 0xee, 0x30, 0xe7, 0x03, 0xd3, 0x80, 0x01, 0xc3, 0x92, 0x0a, 0x90, 0xff,
+0x01, 0xe0, 0x12, 0x1b, 0xfc, 0x03, 0x84, 0x00, 0x04, 0x57, 0x01, 0x05, 0x6a, 0x03, 0x06, 0x31,
+0x05, 0x06, 0x73, 0x06, 0x07, 0xd5, 0x08, 0x08, 0x1d, 0x09, 0x08, 0x79, 0x0a, 0x08, 0xb9, 0x0b,
+0x00, 0x00, 0x0f, 0x6e, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xbd, 0xe0,
+0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x3c, 0x64, 0x02, 0x45, 0x3b, 0x60,
+0x03, 0x02, 0x0f, 0x6e, 0xef, 0x54, 0x1f, 0x14, 0x60, 0x2b, 0x14, 0x60, 0x47, 0x24, 0x02, 0x60,
+0x03, 0x02, 0x0f, 0x6e, 0xee, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1c, 0xc1, 0x74, 0x01, 0x12,
+0x1a, 0xe8, 0x78, 0x67, 0xe6, 0x30, 0xe0, 0x08, 0x12, 0x1c, 0xc1, 0x74, 0x02, 0x12, 0x1a, 0xe8,
+0x7f, 0x02, 0x02, 0x32, 0x6e, 0xe5, 0x35, 0x20, 0xe1, 0x09, 0x90, 0xfa, 0xb9, 0xe0, 0x60, 0x03,
+0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0, 0xd3, 0x94, 0x01, 0x40, 0x03, 0x02, 0x0f, 0x6e, 0x7f,
+0x02, 0x02, 0x32, 0x6e, 0xe5, 0x35, 0x20, 0xe1, 0x0e, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x60, 0x07,
+0x64, 0x80, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x0f, 0xfa, 0x40, 0x03, 0x02, 0x0f, 0x6e, 0xe5,
+0x4d, 0x70, 0x19, 0x30, 0x0a, 0x0b, 0x90, 0xff, 0x80, 0x12, 0x1c, 0xbe, 0x12, 0x1a, 0xe8, 0x80,
+0x24, 0x90, 0xff, 0x82, 0x12, 0x1c, 0xbe, 0x12, 0x1a, 0xe8, 0x80, 0x19, 0x15, 0x4d, 0x30, 0x0a,
+0x0b, 0x12, 0x1d, 0x55, 0x12, 0x1c, 0xbc, 0x12, 0x1a, 0xe8, 0x80, 0x09, 0x12, 0x1d, 0x63, 0x12,
+0x1c, 0xbc, 0x12, 0x1a, 0xe8, 0x12, 0x1c, 0xc1, 0x12, 0x1a, 0xa2, 0x60, 0x05, 0x74, 0x01, 0x12,
+0x1a, 0xe8, 0x7f, 0x02, 0x02, 0x32, 0x6e, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x6e, 0xe5,
+0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1d, 0x79, 0x14, 0x60, 0x2d, 0x14, 0x60,
+0x59, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xbd, 0xe0, 0x70, 0x04, 0xa3, 0xe0,
+0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x6e,
+0x78, 0x67, 0xe6, 0x54, 0xfe, 0xf6, 0xe4, 0xff, 0x02, 0x32, 0x6e, 0xe5, 0x35, 0x20, 0xe1, 0x06,
+0x20, 0xe0, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x30, 0xe0, 0x09, 0x90, 0xfa, 0xb9, 0xe0, 0x60,
+0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x30, 0xe1, 0x0c, 0x90, 0xfa, 0xb9, 0xe0, 0xd3, 0x94, 0x01,
+0x40, 0x03, 0x02, 0x0f, 0x6e, 0xe4, 0xff, 0x02, 0x32, 0x6e, 0x90, 0xfa, 0xbd, 0xe0, 0x70, 0x02,
+0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x0f, 0xfa, 0x40, 0x03, 0x02, 0x0f, 0x6e, 0xe5,
+0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x30, 0xe0, 0x07, 0xe5,
+0x4d, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x4d, 0x70, 0x0f, 0x90, 0xff, 0x82, 0xe0, 0x54, 0xf7,
+0xf0, 0x90, 0xff, 0x80, 0xe0, 0x54, 0xf7, 0xf0, 0x22, 0xe5, 0x4d, 0x24, 0xfe, 0x60, 0x20, 0x24,
+0xfb, 0x60, 0x34, 0x24, 0x06, 0x70, 0x35, 0x30, 0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f,
+0x03, 0x12, 0x2e, 0x79, 0x80, 0x26, 0xe4, 0xfd, 0x7f, 0x03, 0x12, 0x2e, 0x79, 0x80, 0x1d, 0x30,
+0x0a, 0x0c, 0xa2, 0x0a, 0xe4, 0x33, 0xfd, 0x7f, 0x04, 0x12, 0x2e, 0x79, 0x80, 0x0e, 0xe4, 0xfd,
+0x7f, 0x04, 0x12, 0x2e, 0x79, 0x80, 0x05, 0x7f, 0x87, 0x12, 0x31, 0xef, 0x15, 0x4d, 0x30, 0x0a,
+0x0b, 0x12, 0x1d, 0x55, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x80, 0x09, 0x12, 0x1d, 0x63, 0xf5,
+0x83, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0xff, 0x02, 0x32, 0x6e, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02,
+0x0f, 0x6e, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1d, 0x79, 0x14, 0x60,
+0x2d, 0x14, 0x60, 0x55, 0x24, 0x02, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xbd, 0xe0, 0x70,
+0x04, 0xa3, 0xe0, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0, 0x60, 0x03,
+0x02, 0x0f, 0x6e, 0x78, 0x67, 0xe6, 0x44, 0x01, 0xf6, 0xe4, 0xff, 0x02, 0x32, 0x6e, 0xe5, 0x35,
+0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x30, 0xe0, 0x07, 0xe5, 0x4d,
+0x60, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x30, 0xe1, 0x0a, 0xe5, 0x4d, 0xd3, 0x94, 0x01, 0x40,
+0x03, 0x02, 0x0f, 0x6e, 0xe4, 0xff, 0x02, 0x32, 0x6e, 0x90, 0xfa, 0xbd, 0xe0, 0x70, 0x02, 0xa3,
+0xe0, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x12, 0x32, 0x3f, 0x40, 0x03,
+0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x20, 0xe1, 0x06, 0x20, 0xe0, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x4d,
+0x70, 0x09, 0x30, 0x0a, 0x03, 0x02, 0x1e, 0x14, 0x02, 0x1d, 0xdf, 0xe5, 0x35, 0x20, 0xe1, 0x03,
+0x02, 0x0f, 0x6e, 0x15, 0x4d, 0x30, 0x0a, 0x0b, 0x12, 0x1d, 0x55, 0xf5, 0x83, 0xe0, 0x44, 0x08,
+0xf0, 0x80, 0x09, 0x12, 0x1d, 0x63, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0xe4, 0xff, 0x02, 0x32,
+0x6e, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02,
+0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1d, 0x79, 0x60, 0x03,
+0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x30, 0xe1, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xbe, 0xe0, 0x90,
+0xff, 0xff, 0xf0, 0xe0, 0x60, 0x05, 0x43, 0x35, 0x01, 0x80, 0x03, 0x53, 0x35, 0xfe, 0xe4, 0xff,
+0x02, 0x32, 0x6e, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x3c, 0x45, 0x3b, 0x70,
+0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1d, 0x79, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xbd, 0xe0,
+0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0x24, 0xfe, 0x60, 0x3a, 0x14, 0x60, 0x75, 0x24, 0x02, 0x60, 0x03,
+0x02, 0x0f, 0x6e, 0xed, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1c, 0xe0, 0x12, 0x1e, 0x0d, 0x7d,
+0x03, 0x12, 0x0f, 0xb5, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x0f, 0x72, 0x90, 0xfa, 0xb6, 0xe0,
+0xfd, 0xa3, 0x12, 0x1d, 0x2b, 0x12, 0x0f, 0xd1, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c,
+0x02, 0x10, 0x02, 0x12, 0x1c, 0xe0, 0x90, 0xf9, 0x16, 0xe0, 0x30, 0xe4, 0x0d, 0x12, 0x1e, 0x0d,
+0x7d, 0x14, 0x12, 0x0f, 0xb5, 0x60, 0x10, 0x02, 0x0f, 0x6e, 0x12, 0x1e, 0x0d, 0x7d, 0x04, 0x12,
+0x10, 0x09, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x0f, 0x72, 0x90, 0xfa, 0xb6, 0xe0, 0xfd, 0xa3,
+0x12, 0x1d, 0x2b, 0x12, 0x0f, 0xd1, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c, 0x02, 0x10,
+0x02, 0x12, 0x1e, 0x0d, 0x7d, 0x05, 0x12, 0x10, 0x09, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x7b, 0x01,
+0x7a, 0xfa, 0x79, 0xb6, 0x12, 0x1d, 0x28, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x90, 0xfa, 0xb7, 0xe4,
+0x75, 0xf0, 0x03, 0x12, 0x1b, 0x1c, 0x90, 0xfa, 0xbe, 0xe0, 0x90, 0xfa, 0xb5, 0xf0, 0xe4, 0xf5,
+0x4c, 0x90, 0xfa, 0xb5, 0xe0, 0xff, 0xe5, 0x4c, 0xc3, 0x9f, 0x50, 0x24, 0x12, 0x1d, 0x22, 0x12,
+0x10, 0x14, 0xff, 0xfd, 0x90, 0xfa, 0xb7, 0xe4, 0x8d, 0xf0, 0x12, 0x1b, 0x1c, 0x90, 0xfa, 0xb6,
+0xe0, 0xc3, 0x9f, 0xf0, 0xd3, 0x94, 0x00, 0x50, 0x03, 0x02, 0x0f, 0x6e, 0x05, 0x4c, 0x80, 0xd1,
+0x12, 0x1d, 0x22, 0x12, 0x10, 0x14, 0x24, 0xfe, 0xff, 0x90, 0xfa, 0xb6, 0xf0, 0xfd, 0xa3, 0xe4,
+0x75, 0xf0, 0x02, 0x12, 0x1b, 0x1c, 0x7a, 0xf9, 0x79, 0x72, 0x7b, 0x01, 0x8b, 0x36, 0x8a, 0x37,
+0x89, 0x38, 0xe9, 0x24, 0x02, 0xf9, 0xe4, 0x3a, 0xfa, 0x12, 0x1d, 0x28, 0x12, 0x26, 0x98, 0x8f,
+0x4c, 0x05, 0x4c, 0x05, 0x4c, 0x12, 0x1c, 0xc1, 0xe5, 0x4c, 0x12, 0x1a, 0xe8, 0x12, 0x1c, 0xc1,
+0x90, 0x00, 0x01, 0x74, 0x03, 0x12, 0x1a, 0xfa, 0xaf, 0x4c, 0x7e, 0x00, 0xc3, 0xef, 0x95, 0x3c,
+0xee, 0x95, 0x3b, 0x50, 0x02, 0x80, 0x04, 0xae, 0x3b, 0xaf, 0x3c, 0x8e, 0x39, 0x8f, 0x3a, 0x02,
+0x2c, 0xd8, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x3c, 0x64,
+0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0, 0x60, 0x03, 0x02, 0x0f,
+0x6e, 0x90, 0xfa, 0xbd, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1d,
+0x79, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0f,
+0x6e, 0x75, 0x36, 0x00, 0x75, 0x37, 0x00, 0x75, 0x38, 0x32, 0x02, 0x0f, 0xf1, 0xe5, 0x35, 0x30,
+0xe7, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa,
+0xb9, 0xe0, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0xd3, 0x90, 0xfa, 0xbe, 0xe0, 0x94, 0x01, 0x90, 0xfa,
+0xbd, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1d, 0x79, 0x60, 0x03, 0x02, 0x0f,
+0x6e, 0xe5, 0x35, 0x20, 0xe0, 0x06, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xbe, 0xe0,
+0xf5, 0x32, 0xe5, 0x32, 0x70, 0x08, 0x43, 0x35, 0x01, 0x53, 0x35, 0xfd, 0x80, 0x06, 0x53, 0x35,
+0xfe, 0x43, 0x35, 0x02, 0xe4, 0xff, 0x02, 0x32, 0x6e, 0xe5, 0x35, 0x20, 0xe7, 0x03, 0x02, 0x0f,
+0x6e, 0xe5, 0x3c, 0x64, 0x01, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xb9, 0xe0,
+0x60, 0x03, 0x02, 0x0f, 0x6e, 0x90, 0xfa, 0xbd, 0xe0, 0x70, 0x02, 0xa3, 0xe0, 0x60, 0x03, 0x02,
+0x0f, 0x6e, 0x12, 0x1d, 0x79, 0x64, 0x01, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x20, 0xe1,
+0x03, 0x02, 0x0f, 0x6e, 0x7f, 0x01, 0x02, 0x32, 0x6e, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f,
+0x6e, 0xe5, 0x3c, 0x45, 0x3b, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0xd3, 0x90, 0xfa, 0xbe, 0xe0, 0x94,
+0x00, 0x90, 0xfa, 0xbd, 0xe0, 0x94, 0x00, 0x40, 0x03, 0x02, 0x0f, 0x6e, 0x12, 0x1d, 0x79, 0x64,
+0x01, 0x60, 0x03, 0x02, 0x0f, 0x6e, 0xe5, 0x35, 0x20, 0xe1, 0x03, 0x02, 0x0f, 0x6e, 0xe4, 0xff,
+0x02, 0x32, 0x6e, 0x90, 0xff, 0x01, 0x12, 0x1e, 0x24, 0xef, 0x12, 0x1a, 0xe8, 0x90, 0xfa, 0xb9,
+0x12, 0x1e, 0x24, 0x90, 0x00, 0x01, 0xef, 0x12, 0x1a, 0xfa, 0x90, 0x00, 0x02, 0xe4, 0x12, 0x1a,
+0xfa, 0x74, 0x03, 0x12, 0x1c, 0xb2, 0x90, 0xfa, 0xbd, 0xe0, 0xff, 0xa3, 0xe0, 0x85, 0x38, 0x82,
+0x85, 0x37, 0x83, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xff, 0x01, 0xe0, 0x12, 0x1b, 0xfc, 0x09,
+0x7b, 0x02, 0x09, 0x9d, 0x04, 0x09, 0xbf, 0x05, 0x09, 0xeb, 0x06, 0x0a, 0x09, 0x07, 0x0a, 0x27,
+0x08, 0x0a, 0x45, 0x09, 0x0a, 0x63, 0x0b, 0x0b, 0x18, 0x80, 0x0d, 0xb7, 0x81, 0x0d, 0xe8, 0x82,
+0x0b, 0x5f, 0x83, 0x0b, 0xa8, 0x84, 0x0b, 0xc7, 0x85, 0x0c, 0x0c, 0x86, 0x0c, 0x57, 0x87, 0x0c,
+0xe8, 0x88, 0x0d, 0x73, 0x89, 0x0a, 0x81, 0x92, 0x0a, 0x81, 0x93, 0x0d, 0xa0, 0xb0, 0x0e, 0x9b,
+0xc0, 0x0e, 0xc7, 0xc1, 0x0e, 0xd8, 0xc2, 0x00, 0x00, 0x0f, 0x5d, 0xe5, 0x35, 0x20, 0xe7, 0x05,
+0x7f, 0x05, 0x02, 0x31, 0xa9, 0x12, 0x1d, 0x71, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c,
+0x00, 0x7f, 0x07, 0x02, 0x11, 0x5e, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0xb4, 0xe5, 0x35, 0x20,
+0xe7, 0x05, 0x7f, 0x05, 0x02, 0x31, 0xa9, 0x12, 0x1d, 0x71, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef,
+0xfd, 0x7c, 0x00, 0x7f, 0x0c, 0x02, 0x11, 0x5e, 0xe4, 0xfd, 0x7f, 0x07, 0x02, 0x2f, 0xb4, 0xe5,
+0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x71, 0x12, 0x1e, 0x42, 0x50, 0x06, 0xe5, 0x3c, 0x45, 0x3b,
+0x70, 0x05, 0x7f, 0x02, 0x02, 0x31, 0xa9, 0x90, 0xfa, 0xb9, 0xe0, 0x24, 0xfe, 0x24, 0xfd, 0x50,
+0x02, 0x80, 0x03, 0x02, 0x32, 0x2c, 0x7f, 0x07, 0x02, 0x31, 0xa9, 0xe5, 0x35, 0x30, 0xe7, 0x03,
+0x02, 0x0f, 0x71, 0x12, 0x1d, 0x71, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f,
+0x08, 0x02, 0x11, 0x5e, 0x7f, 0x07, 0x02, 0x31, 0xa9, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f,
+0x71, 0x12, 0x1d, 0x71, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x09, 0x02,
+0x11, 0x5e, 0x7f, 0x07, 0x02, 0x31, 0xa9, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x71, 0x12,
+0x1d, 0x71, 0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0a, 0x02, 0x11, 0x5e,
+0x7f, 0x07, 0x02, 0x31, 0xa9, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x71, 0x12, 0x1d, 0x71,
+0x60, 0x03, 0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0b, 0x02, 0x11, 0x5e, 0x7f, 0x07,
+0x02, 0x31, 0xa9, 0xe5, 0x35, 0x30, 0xe7, 0x03, 0x02, 0x0f, 0x71, 0x12, 0x1d, 0x71, 0x60, 0x03,
+0x04, 0x70, 0x09, 0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0e, 0x02, 0x11, 0x5e, 0x7f, 0x07, 0x02, 0x31,
+0xa9, 0xe5, 0x35, 0x30, 0xe7, 0x56, 0x12, 0x1d, 0x79, 0x70, 0x4a, 0x90, 0xff, 0x02, 0xe0, 0xf5,
+0x4c, 0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12, 0xe5, 0x4c, 0xb4, 0x83, 0x05,
+0x75, 0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04, 0xf5, 0x4c, 0x12, 0x1c, 0x22,
+0x12, 0x1e, 0x3b, 0x12, 0x25, 0xfa, 0x12, 0x1d, 0x89, 0x12, 0x1a, 0xbb, 0x60, 0x05, 0x12, 0x32,
+0x7a, 0x80, 0x06, 0x85, 0x33, 0x39, 0x85, 0x34, 0x3a, 0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75,
+0x38, 0x75, 0x02, 0x2c, 0xd8, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f, 0xb4, 0x12, 0x1d, 0x79, 0x60,
+0x05, 0x7f, 0x05, 0x02, 0x31, 0xa9, 0x12, 0x1e, 0x42, 0x40, 0x05, 0x7f, 0x03, 0x02, 0x31, 0xa9,
+0x90, 0xff, 0x02, 0xe0, 0xf5, 0x4c, 0xe5, 0x4c, 0xb4, 0x82, 0x05, 0x75, 0x4c, 0x61, 0x80, 0x12,
+0xe5, 0x4c, 0xb4, 0x83, 0x05, 0x75, 0x4c, 0x62, 0x80, 0x08, 0xe5, 0x4c, 0xc4, 0x54, 0xf0, 0x04,
+0xf5, 0x4c, 0x12, 0x1c, 0x22, 0x02, 0x32, 0x2c, 0x12, 0x1e, 0x4c, 0x12, 0x2a, 0xc7, 0x12, 0x1d,
+0x33, 0xe0, 0x54, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0xe0, 0x90, 0xfa, 0xba, 0xf0, 0x78, 0x68, 0x12,
+0x1b, 0xd8, 0x90, 0x00, 0x02, 0x12, 0x1a, 0xbb, 0x30, 0xe7, 0xf2, 0x90, 0x00, 0x02, 0xe4, 0x12,
+0x1a, 0xfa, 0x90, 0xfa, 0xba, 0xe0, 0x44, 0x80, 0xff, 0xf0, 0x78, 0x7c, 0xe6, 0xfc, 0x08, 0xe6,
+0x8c, 0x83, 0x12, 0x1d, 0x3b, 0xef, 0xf0, 0x12, 0x32, 0x84, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0x90,
+0xfa, 0xb9, 0xe0, 0x64, 0x01, 0x70, 0x1f, 0x90, 0xfa, 0xbd, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06,
+0xa3, 0xe0, 0xf5, 0x90, 0x80, 0x2d, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0x90, 0x90, 0xfa, 0xbe, 0xe0,
+0x42, 0x90, 0xd2, 0xaf, 0x80, 0x1d, 0x90, 0xfa, 0xbd, 0xe0, 0xff, 0x7e, 0x00, 0x70, 0x06, 0xa3,
+0xe0, 0xf5, 0xb0, 0x80, 0x0e, 0xc2, 0xaf, 0xef, 0xf4, 0x52, 0xb0, 0x90, 0xfa, 0xbe, 0xe0, 0x42,
+0xb0, 0xd2, 0xaf, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0x12, 0x1c, 0xe0, 0x90, 0xfa, 0xb9, 0xe0, 0xb4,
+0x01, 0x0a, 0x12, 0x1c, 0xc1, 0xe5, 0x90, 0x12, 0x1a, 0xe8, 0x80, 0x08, 0x12, 0x1c, 0xc1, 0xe5,
+0xb0, 0x12, 0x1a, 0xe8, 0x02, 0x0f, 0xf1, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x24, 0x13, 0x12, 0x1c,
+0xf1, 0x20, 0xe1, 0x33, 0x12, 0x1d, 0x80, 0xef, 0x24, 0xfc, 0x60, 0x18, 0x04, 0x70, 0x28, 0x90,
+0xfa, 0xba, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x19, 0x12, 0x1e,
+0x56, 0xf0, 0x80, 0x13, 0x90, 0xfa, 0xba, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10,
+0xf0, 0x80, 0x04, 0x12, 0x1e, 0x5d, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0x90, 0xfa, 0xb9, 0xe0,
+0xff, 0x24, 0x13, 0x12, 0x1c, 0xf1, 0x20, 0xe1, 0x39, 0x12, 0x1d, 0x80, 0xef, 0x24, 0xfc, 0x60,
+0x1b, 0x04, 0x70, 0x2e, 0x90, 0xfa, 0xba, 0xe0, 0x60, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20,
+0xf0, 0x80, 0x1f, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x16, 0x90, 0xfa, 0xba, 0xe0,
+0x60, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54,
+0xdf, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0x12, 0x1d, 0x80, 0x12, 0x1d, 0x71, 0x60, 0x4d, 0x04,
+0x60, 0x03, 0x02, 0x0c, 0xe3, 0x90, 0xfa, 0xba, 0xe0, 0x60, 0x0f, 0x90, 0xff, 0xa4, 0x12, 0x1c,
+0xea, 0x30, 0xe1, 0x6f, 0x12, 0x1e, 0x2c, 0x02, 0x0c, 0xe3, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfb,
+0x12, 0x1c, 0xed, 0xfe, 0x30, 0xe1, 0x5c, 0x30, 0xe2, 0x11, 0x30, 0xb4, 0x05, 0x12, 0x1e, 0x2c,
+0x80, 0x51, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x48, 0x30, 0x95, 0x05, 0x12, 0x1e,
+0x2c, 0x80, 0x40, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xfd, 0xf0, 0x80, 0x37, 0x90, 0xfa, 0xba, 0xe0,
+0x60, 0x12, 0x90, 0xff, 0xb4, 0x12, 0x1c, 0xea, 0x30, 0xe1, 0x28, 0x90, 0xff, 0xb4, 0xe0, 0x44,
+0x02, 0xf0, 0x80, 0x1f, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xfb, 0x12, 0x1c, 0xed, 0x30, 0xe1, 0x13,
+0x30, 0x93, 0x09, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0,
+0x54, 0xfd, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0x12, 0x1d, 0x80, 0x90, 0xfa, 0xb9, 0xe0, 0x24,
+0xfc, 0x60, 0x40, 0x04, 0x70, 0x78, 0x90, 0xfa, 0xba, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xa2, 0xe0,
+0x44, 0x40, 0xf0, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x65, 0xd2, 0x03, 0xa3, 0xe0, 0x54, 0xdf, 0xf0,
+0x90, 0xff, 0xa3, 0xef, 0x54, 0x7f, 0xf0, 0x80, 0x55, 0x30, 0x03, 0x0e, 0x90, 0xff, 0xa3, 0xe0,
+0x44, 0x80, 0xf0, 0xc2, 0x03, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x54, 0xbf,
+0xf0, 0x80, 0x3b, 0x90, 0xfa, 0xba, 0xe0, 0x60, 0x1d, 0x90, 0xff, 0xb2, 0xe0, 0x44, 0x40, 0xf0,
+0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x28, 0xd2, 0x04, 0xa3, 0xe0, 0x54, 0xdf, 0xf0, 0x90, 0xff, 0xb3,
+0xef, 0x54, 0x7f, 0xf0, 0x80, 0x18, 0x30, 0x04, 0x0e, 0x90, 0xff, 0xb3, 0xe0, 0x44, 0x80, 0xf0,
+0xc2, 0x04, 0xa3, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x54, 0xbf, 0xf0, 0xe4, 0xff,
+0x02, 0x31, 0xa9, 0x12, 0x1c, 0xe0, 0x90, 0xfa, 0xb9, 0xe0, 0x24, 0xfc, 0x60, 0x0f, 0x04, 0x70,
+0x16, 0x90, 0xff, 0xa6, 0xe0, 0x12, 0x1c, 0xc1, 0x12, 0x1a, 0xe8, 0x80, 0x0a, 0x90, 0xff, 0xb6,
+0xe0, 0x12, 0x1c, 0xc1, 0x12, 0x1a, 0xe8, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02, 0x2c, 0xd8,
+0x90, 0xf9, 0x15, 0x74, 0x01, 0xf0, 0x90, 0xf9, 0x1c, 0x74, 0x19, 0xf0, 0x90, 0xf9, 0x66, 0x74,
+0xff, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0xe4, 0xff, 0x12, 0x31, 0xa9, 0x12, 0x1d, 0xe7, 0x7f,
+0x03, 0x12, 0x12, 0x61, 0x90, 0xf9, 0x16, 0xe0, 0x30, 0xe4, 0x08, 0x90, 0xff, 0x93, 0x74, 0x80,
+0xf0, 0x80, 0x10, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0x7f, 0xf0, 0x7f, 0xff, 0x7e, 0x00, 0x12, 0x30,
+0xd3, 0xc2, 0x90, 0xc2, 0xaf, 0x00, 0x80, 0xfd, 0xe4, 0xf5, 0x4e, 0xf5, 0x4f, 0x90, 0xfa, 0xbf,
+0x74, 0x3e, 0xf0, 0xa3, 0xe4, 0xf0, 0x90, 0xfa, 0xb7, 0xf0, 0xa3, 0x74, 0x15, 0xf0, 0xe0, 0x54,
+0x3f, 0xff, 0xc3, 0x74, 0x40, 0x9f, 0x90, 0xfa, 0xbc, 0xf0, 0xd3, 0x94, 0x00, 0xe4, 0x94, 0x3e,
+0x40, 0x08, 0x90, 0xfa, 0xc0, 0xe0, 0x90, 0xfa, 0xbc, 0xf0, 0x12, 0x0f, 0x98, 0xe5, 0x31, 0x45,
+0x30, 0x70, 0x73, 0x12, 0x1c, 0xfa, 0x90, 0xfa, 0xbf, 0x12, 0x1e, 0x06, 0x60, 0x27, 0xd3, 0xef,
+0x94, 0x40, 0xee, 0x94, 0x00, 0x40, 0x08, 0x90, 0xfa, 0xbc, 0x74, 0x40, 0xf0, 0x80, 0x08, 0x90,
+0xfa, 0xc0, 0xe0, 0x90, 0xfa, 0xbc, 0xf0, 0x12, 0x0f, 0x98, 0xe5, 0x31, 0x45, 0x30, 0x70, 0x46,
+0x12, 0x1c, 0xfa, 0x80, 0xd1, 0x75, 0x4c, 0x02, 0x90, 0xfa, 0xbf, 0xe4, 0xf0, 0xa3, 0x04, 0xf0,
+0x90, 0xfa, 0xb7, 0xe4, 0xf0, 0xa3, 0x74, 0x0f, 0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0x90,
+0xfa, 0xc0, 0xe0, 0xf5, 0x4a, 0x7d, 0x0f, 0x7c, 0x00, 0x12, 0x29, 0x60, 0x75, 0x30, 0x00, 0x8f,
+0x31, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x4c, 0xe4, 0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x26,
+0x98, 0xe4, 0xf5, 0x30, 0xf5, 0x31, 0xaf, 0x31, 0x02, 0x31, 0xa9, 0x12, 0x1d, 0x80, 0x30, 0xe7,
+0x10, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x67, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x15, 0xc2, 0x95, 0x80,
+0x11, 0x90, 0xfa, 0xba, 0xe0, 0x54, 0x0f, 0x90, 0xf9, 0x65, 0xf0, 0xd3, 0x94, 0x00, 0x40, 0x02,
+0xc2, 0x94, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0x12, 0x1e, 0x4c, 0xbf, 0x01, 0x04, 0xd2, 0x93, 0x80,
+0x02, 0xc2, 0x93, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0x12, 0x1d, 0x80, 0x54, 0x03, 0x14, 0x60, 0x0a,
+0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x91, 0x80, 0x27, 0xc2, 0x91,
+0x80, 0x23, 0x12, 0x1e, 0x56, 0x12, 0x0f, 0xc0, 0x60, 0x04, 0xd2, 0x91, 0x80, 0x17, 0x90, 0xff,
+0xa4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0xc0, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x91, 0x80, 0x02, 0xd2,
+0x91, 0x12, 0x1e, 0x56, 0xf0, 0x90, 0xfa, 0xba, 0xe0, 0x54, 0x0c, 0xff, 0x13, 0x13, 0x54, 0x3f,
+0x14, 0x60, 0x0a, 0x14, 0x60, 0x0f, 0x14, 0x60, 0x08, 0x24, 0x03, 0x70, 0x2b, 0xd2, 0x92, 0x80,
+0x27, 0xc2, 0x92, 0x80, 0x23, 0x12, 0x1e, 0x5d, 0x12, 0x0f, 0xe0, 0x60, 0x04, 0xd2, 0x92, 0x80,
+0x17, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x10, 0x12, 0x0f, 0xe0, 0xff, 0xbf, 0xa0, 0x04, 0xc2, 0x92,
+0x80, 0x02, 0xd2, 0x92, 0x12, 0x1e, 0x5d, 0xf0, 0xe4, 0xff, 0x02, 0x31, 0xa9, 0xe5, 0x35, 0x30,
+0xe7, 0x07, 0xe4, 0xfd, 0x7f, 0x05, 0x02, 0x2f, 0xb4, 0x7f, 0x05, 0x02, 0x31, 0xa9, 0x12, 0x32,
+0x7a, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb6, 0x90, 0xfa, 0xb7, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0,
+0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x90, 0xfa, 0xb7, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1b,
+0x1c, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x22, 0xaa, 0x4e, 0xa9, 0x4f, 0x7b, 0xff, 0x90, 0xfa,
+0xb7, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xbc, 0xe0, 0xf5, 0x4a, 0x12, 0x29, 0x60, 0x75,
+0x30, 0x00, 0x8f, 0x31, 0x22, 0x12, 0x23, 0x61, 0x7e, 0x00, 0x8e, 0x30, 0x8f, 0x31, 0xef, 0x22,
+0xf0, 0x7f, 0x01, 0x12, 0x12, 0x61, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xbb, 0xf0, 0x54, 0xa0,
+0x22, 0x12, 0x26, 0x98, 0x8f, 0x4c, 0x7e, 0x00, 0xc3, 0xef, 0x95, 0x3c, 0xee, 0x95, 0x3b, 0x22,
+0xf0, 0x7f, 0x01, 0x12, 0x12, 0x61, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xbb, 0xf0, 0x54, 0xa0,
+0x22, 0x75, 0x39, 0x00, 0x75, 0x3a, 0x01, 0x02, 0x2c, 0xd8, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x02,
+0x32, 0x3f, 0x8e, 0x39, 0x8f, 0x3a, 0x02, 0x2c, 0xd8, 0x12, 0x23, 0x61, 0x7e, 0x00, 0x8e, 0x30,
+0x8f, 0x31, 0xef, 0x22, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x90, 0xfa, 0xb4, 0xe0, 0x22, 0xef, 0x90,
+0xf8, 0x04, 0xf0, 0x22, 0xc0, 0xa8, 0xc2, 0xaf, 0xee, 0x60, 0x0a, 0xc0, 0x05, 0x7d, 0x7f, 0xdd,
+0xfe, 0xde, 0xfa, 0xd0, 0x05, 0xef, 0xc3, 0x94, 0x15, 0x50, 0x03, 0xd0, 0xa8, 0x22, 0x13, 0x70,
+0x03, 0xd0, 0xa8, 0x22, 0xff, 0xd5, 0x07, 0xfd, 0xd0, 0xa8, 0x22, 0xc0, 0x00, 0xc0, 0x01, 0xc0,
+0x02, 0xc0, 0x04, 0xc0, 0x05, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0x86, 0x05, 0x53, 0x05, 0x7f, 0x7c,
+0xff, 0x12, 0x10, 0xc0, 0x7f, 0x00, 0x7e, 0x00, 0xe5, 0x43, 0x60, 0x46, 0xfc, 0x90, 0xf9, 0x1d,
+0xe0, 0x54, 0x7f, 0x6d, 0x70, 0x0f, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff,
+0xa3, 0x15, 0x43, 0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xdc, 0xe6, 0x80, 0x26, 0xdc, 0x06, 0xd0, 0x82,
+0xd0, 0x83, 0x80, 0x1e, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83,
+0xe8, 0xf0, 0xa3, 0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3,
+0x80, 0xda, 0x12, 0x11, 0x57, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22,
+0x85, 0xa8, 0x44, 0x75, 0xa8, 0x88, 0xec, 0x70, 0x02, 0x7c, 0x3f, 0x8c, 0x3d, 0x22, 0xe5, 0x3e,
+0x24, 0x08, 0xf8, 0x76, 0x00, 0x12, 0x11, 0xae, 0x80, 0xfb, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02,
+0xc0, 0x04, 0xc0, 0x06, 0x7c, 0xff, 0x12, 0x10, 0xc0, 0xe5, 0x43, 0x60, 0x42, 0xfe, 0x90, 0xf9,
+0x1d, 0xe0, 0x54, 0x7f, 0x6f, 0x70, 0x0b, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x15, 0x43,
+0x80, 0x07, 0xa3, 0xa3, 0xa3, 0xde, 0xea, 0x80, 0x26, 0xde, 0x06, 0xd0, 0x82, 0xd0, 0x83, 0x80,
+0xd8, 0xe0, 0xf8, 0xa3, 0xe0, 0xf9, 0xa3, 0xe0, 0xfa, 0xd0, 0x82, 0xd0, 0x83, 0xe8, 0xf0, 0xa3,
+0xe9, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xa3, 0xa3, 0x80, 0xda, 0x78,
+0x08, 0x08, 0x79, 0x18, 0x09, 0x7c, 0x01, 0xe6, 0x54, 0x7f, 0x6f, 0x70, 0x06, 0x76, 0x00, 0x77,
+0x00, 0x80, 0x06, 0x08, 0x09, 0x0c, 0xbc, 0x08, 0xee, 0x12, 0x11, 0x57, 0xd0, 0x06, 0xd0, 0x04,
+0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0x22, 0x75, 0x3d, 0x00, 0x85, 0x44, 0xa8, 0x22, 0xc0, 0xf0,
+0xc0, 0x82, 0xc0, 0x83, 0xc3, 0xe5, 0x43, 0x24, 0xe8, 0x50, 0x05, 0x12, 0x11, 0xae, 0x80, 0xf4,
+0xef, 0x60, 0x31, 0x90, 0x31, 0x11, 0xe4, 0x93, 0xc3, 0x9f, 0x40, 0x2f, 0xc0, 0x04, 0x7c, 0xff,
+0x12, 0x10, 0xc0, 0xd0, 0x04, 0x43, 0x07, 0x80, 0xe5, 0x43, 0x75, 0xf0, 0x03, 0xa4, 0x24, 0x1d,
+0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xef, 0xf0, 0xec, 0xa3, 0xf0, 0xed, 0xa3, 0xf0, 0x05,
+0x43, 0x12, 0x11, 0x57, 0xd0, 0x83, 0xd0, 0x82, 0xd0, 0xf0, 0x22, 0x02, 0x11, 0xdc, 0xc0, 0x04,
+0x7c, 0x20, 0xd2, 0x8c, 0xd2, 0x8d, 0xd5, 0x04, 0xfd, 0xd0, 0x04, 0x22, 0x75, 0xa8, 0x00, 0x75,
+0x88, 0x00, 0x75, 0xb8, 0x00, 0x75, 0xf0, 0x00, 0x75, 0xd0, 0x00, 0xe4, 0xf8, 0x90, 0xf8, 0x04,
+0xf0, 0x90, 0x00, 0x00, 0xf6, 0x08, 0xb8, 0x00, 0xfb, 0x02, 0x00, 0x00, 0xc2, 0xaf, 0xe4, 0x90,
+0xff, 0x48, 0xf0, 0x90, 0xff, 0x50, 0xf0, 0x90, 0xff, 0x08, 0xf0, 0x90, 0xff, 0x10, 0xf0, 0x90,
+0xff, 0x80, 0xf0, 0xa3, 0xa3, 0xf0, 0xd2, 0xb1, 0xc2, 0xb0, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x10,
+0x24, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x10, 0x24, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x10, 0x24, 0xd2,
+0xb0, 0xd2, 0xb1, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x10, 0x24, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x10,
+0x24, 0x7e, 0xff, 0x7f, 0xff, 0x12, 0x10, 0x24, 0x80, 0xcc, 0xc3, 0xee, 0x94, 0x02, 0x50, 0x04,
+0x7e, 0x03, 0x7f, 0xe8, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f,
+0x42, 0x8e, 0x41, 0x22, 0xc3, 0xef, 0x94, 0xbc, 0xee, 0x94, 0x02, 0x50, 0x04, 0x7e, 0x07, 0x7f,
+0xd0, 0xef, 0xf4, 0xff, 0xee, 0xf4, 0xfe, 0x0f, 0xbf, 0x00, 0x01, 0x0e, 0x8f, 0x40, 0x8e, 0x3f,
+0x22, 0xef, 0x70, 0x01, 0x22, 0xc0, 0x00, 0xc0, 0xa8, 0xc2, 0xaf, 0xe5, 0x3e, 0x24, 0x18, 0xf8,
+0xa6, 0x07, 0xe5, 0x3e, 0x24, 0x08, 0xf8, 0xc6, 0x54, 0x7f, 0xf6, 0xd0, 0xa8, 0xe6, 0x30, 0xe7,
+0x03, 0xd0, 0x00, 0x22, 0x12, 0x11, 0xae, 0x80, 0xf4, 0xc0, 0x00, 0x7f, 0x01, 0xef, 0x24, 0x08,
+0xf8, 0xe6, 0x60, 0x09, 0x0f, 0xbf, 0x08, 0xf5, 0x12, 0x11, 0xae, 0x80, 0xee, 0xd0, 0x00, 0x22,
+0xc0, 0xf0, 0xc0, 0x82, 0xc0, 0x83, 0xc0, 0x00, 0xc0, 0x06, 0xc0, 0x04, 0xed, 0x24, 0x10, 0xf8,
+0x76, 0x9a, 0xed, 0x75, 0xf0, 0x21, 0xa4, 0x24, 0x05, 0xf5, 0x82, 0xe4, 0x34, 0xf8, 0xf5, 0x83,
+0xc0, 0x82, 0xc0, 0x83, 0xa3, 0xa3, 0xe4, 0x78, 0x0d, 0xf0, 0xa3, 0xd8, 0xfc, 0xef, 0x54, 0x7f,
+0x75, 0xf0, 0x02, 0xa4, 0x24, 0xf3, 0xf5, 0x82, 0xe5, 0xf0, 0x34, 0x30, 0xf5, 0x83, 0xe4, 0x93,
+0xfe, 0x74, 0x01, 0x93, 0xfc, 0xd0, 0x83, 0xd0, 0x82, 0xec, 0xf0, 0xa3, 0xee, 0xf0, 0xed, 0x24,
+0x08, 0xf8, 0xef, 0x44, 0x80, 0xf6, 0xd0, 0x04, 0xd0, 0x06, 0xd0, 0x00, 0xd0, 0x83, 0xd0, 0x82,
+0xd0, 0xf0, 0x22, 0x75, 0x3e, 0x00, 0x75, 0x43, 0x00, 0x7a, 0x08, 0x79, 0x18, 0x78, 0x08, 0x76,
+0x00, 0x77, 0x00, 0x08, 0x09, 0xda, 0xf8, 0x90, 0xf8, 0x04, 0xe0, 0xfc, 0x90, 0x31, 0x11, 0xe4,
+0x93, 0xc3, 0x9c, 0x50, 0x05, 0xe4, 0x90, 0xf8, 0x04, 0xf0, 0x78, 0x08, 0x74, 0x80, 0x44, 0x7f,
+0xf6, 0x74, 0x01, 0x44, 0x10, 0xf5, 0x89, 0x75, 0xb8, 0x00, 0xd2, 0xab, 0xd2, 0xa9, 0x22, 0x75,
+0x81, 0x8b, 0xd2, 0x8e, 0xd2, 0x8c, 0xd2, 0xaf, 0xe5, 0x43, 0x60, 0x36, 0xff, 0x90, 0xf9, 0x1d,
+0xe0, 0x54, 0x80, 0x60, 0x28, 0x78, 0x08, 0x79, 0x08, 0xe0, 0x54, 0x7f, 0xfa, 0x7b, 0x00, 0xe6,
+0x54, 0x7f, 0xb5, 0x02, 0x02, 0x7b, 0xff, 0x08, 0xd9, 0xf5, 0xeb, 0x70, 0x10, 0xea, 0xf0, 0xc0,
+0x07, 0x12, 0x12, 0x89, 0xad, 0x07, 0xaf, 0x02, 0x12, 0x12, 0xa0, 0xd0, 0x07, 0xa3, 0xa3, 0xa3,
+0xdf, 0xce, 0x12, 0x11, 0xae, 0x80, 0xc1, 0x8f, 0x24, 0x12, 0x2a, 0xc7, 0x12, 0x22, 0xb5, 0xa3,
+0xa3, 0xe0, 0xa3, 0x30, 0xe7, 0x28, 0x78, 0x7e, 0x12, 0x22, 0x99, 0xe0, 0x44, 0x01, 0xf0, 0x12,
+0x22, 0xfa, 0x12, 0x22, 0x9d, 0xe0, 0x20, 0xe0, 0xf6, 0x12, 0x23, 0x50, 0x74, 0x02, 0xf0, 0x12,
+0x22, 0xda, 0xe0, 0xa3, 0x30, 0xe5, 0x07, 0x12, 0x23, 0x50, 0xe0, 0x44, 0x01, 0xf0, 0x78, 0x80,
+0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x08, 0x12, 0x22, 0xa1, 0xe0, 0xfd, 0x12, 0x23,
+0x39, 0x8a, 0x83, 0x24, 0x0a, 0x12, 0x22, 0xa1, 0xed, 0xf0, 0x12, 0x23, 0x06, 0x24, 0x07, 0x12,
+0x22, 0xa1, 0xe0, 0xff, 0x12, 0x23, 0x5a, 0x24, 0x09, 0x12, 0x22, 0xa1, 0xef, 0xf0, 0x90, 0xf9,
+0x16, 0xe0, 0x30, 0xe4, 0x20, 0x08, 0x12, 0x22, 0xb7, 0xc0, 0x83, 0xc0, 0x82, 0xa3, 0xe0, 0x25,
+0xe0, 0xff, 0x05, 0x82, 0xd5, 0x82, 0x02, 0x15, 0x83, 0x15, 0x82, 0xe0, 0x33, 0xd0, 0x82, 0xd0,
+0x83, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x22, 0xb5, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xec, 0xff, 0x12,
+0x23, 0x39, 0x8a, 0x83, 0x24, 0x08, 0x12, 0x22, 0xa1, 0xef, 0xf0, 0xed, 0x12, 0x23, 0x5a, 0x24,
+0x07, 0x12, 0x22, 0xa1, 0xed, 0xf0, 0x12, 0x22, 0xa9, 0xe0, 0x30, 0xe6, 0x0a, 0x12, 0x23, 0x41,
+0x24, 0x09, 0x12, 0x22, 0xa1, 0xe4, 0xf0, 0x12, 0x22, 0xa9, 0xe0, 0xff, 0x30, 0xe7, 0x1b, 0x12,
+0x23, 0x1e, 0x24, 0x09, 0x12, 0x22, 0xa1, 0xe0, 0x60, 0x09, 0x12, 0x22, 0xa9, 0xef, 0x44, 0x02,
+0xf0, 0x80, 0x07, 0x12, 0x22, 0xa9, 0xef, 0x54, 0xfd, 0xf0, 0x78, 0x7e, 0x12, 0x22, 0xb7, 0xa3,
+0xa3, 0xe0, 0xff, 0x53, 0x07, 0xc7, 0x08, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x12, 0x22, 0xe0, 0xa3,
+0xe0, 0x30, 0xe3, 0x12, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x05, 0x12, 0x22, 0xa1, 0xe0,
+0x90, 0x32, 0x51, 0x93, 0x42, 0x07, 0x53, 0x07, 0xfb, 0x12, 0x23, 0x1e, 0x24, 0x06, 0x12, 0x22,
+0xa1, 0xe0, 0x60, 0x03, 0x43, 0x07, 0x04, 0x53, 0x07, 0xfc, 0x78, 0x80, 0x12, 0x23, 0x29, 0x24,
+0x04, 0x12, 0x22, 0xa1, 0xe0, 0x42, 0x07, 0x43, 0x07, 0x80, 0x12, 0x23, 0x39, 0xf5, 0x82, 0x8a,
+0x83, 0xa3, 0xa3, 0xef, 0xf0, 0x12, 0x23, 0x5a, 0x24, 0x04, 0x12, 0x22, 0xa1, 0xe0, 0xff, 0x8d,
+0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe1, 0x05, 0x53, 0x07, 0xdf,
+0x80, 0x03, 0x43, 0x07, 0x20, 0xec, 0x30, 0xe4, 0x05, 0x53, 0x07, 0xef, 0x80, 0x03, 0x43, 0x07,
+0x10, 0x12, 0x22, 0xa9, 0xe0, 0xfe, 0x54, 0x03, 0x60, 0x73, 0x53, 0x07, 0xdf, 0xee, 0x30, 0xe1,
+0x69, 0x12, 0x23, 0x1e, 0x24, 0x09, 0x12, 0x22, 0xa1, 0xe0, 0x12, 0x1b, 0xfc, 0x15, 0x2c, 0x00,
+0x15, 0x60, 0x01, 0x15, 0x65, 0x03, 0x15, 0x60, 0x05, 0x15, 0x65, 0x07, 0x15, 0x60, 0x09, 0x15,
+0x65, 0x0b, 0x15, 0x60, 0x0d, 0x15, 0x65, 0x0f, 0x00, 0x00, 0x15, 0x6d, 0xe5, 0x24, 0x64, 0x03,
+0x70, 0x21, 0x90, 0xf9, 0x16, 0xe0, 0x30, 0xe2, 0x0d, 0x30, 0xb4, 0x05, 0x43, 0x07, 0x02, 0x80,
+0x2c, 0x53, 0x07, 0xfd, 0x80, 0x27, 0x30, 0x95, 0x05, 0x43, 0x07, 0x02, 0x80, 0x1f, 0x53, 0x07,
+0xfd, 0x80, 0x1a, 0x30, 0x93, 0x05, 0x43, 0x07, 0x02, 0x80, 0x12, 0x53, 0x07, 0xfd, 0x80, 0x0d,
+0x43, 0x07, 0x02, 0x80, 0x08, 0x53, 0x07, 0xfd, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x12, 0x23, 0x27,
+0x24, 0x04, 0x12, 0x22, 0xa1, 0xef, 0xf0, 0x8d, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xff,
+0x12, 0x22, 0xa9, 0xe0, 0xfe, 0x54, 0x03, 0x70, 0x03, 0x02, 0x16, 0x60, 0xee, 0x20, 0xe1, 0x03,
+0x02, 0x16, 0x5d, 0x08, 0x12, 0x23, 0x20, 0x24, 0x09, 0x12, 0x22, 0xa1, 0xe0, 0x12, 0x1b, 0xfc,
+0x15, 0xbf, 0x00, 0x15, 0xf5, 0x01, 0x15, 0xf5, 0x03, 0x16, 0x29, 0x05, 0x16, 0x29, 0x07, 0x16,
+0x0f, 0x09, 0x16, 0x0f, 0x0b, 0x16, 0x43, 0x0d, 0x16, 0x43, 0x0f, 0x00, 0x00, 0x16, 0x60, 0xe5,
+0x24, 0x64, 0x03, 0x70, 0x23, 0x90, 0xf9, 0x16, 0xe0, 0x30, 0xe2, 0x0f, 0x30, 0xb1, 0x06, 0x53,
+0x07, 0x7f, 0x02, 0x16, 0x60, 0x43, 0x07, 0x80, 0x02, 0x16, 0x60, 0x30, 0x94, 0x05, 0x53, 0x07,
+0x7f, 0x80, 0x7d, 0x43, 0x07, 0x80, 0x80, 0x78, 0x30, 0x92, 0x05, 0x53, 0x07, 0x7f, 0x80, 0x70,
+0x43, 0x07, 0x80, 0x80, 0x6b, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xef,
+0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xdf, 0xf0, 0x53, 0x07, 0x7f, 0x80, 0x51, 0xe5,
+0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e,
+0xe0, 0x44, 0x20, 0xf0, 0x53, 0x07, 0x7f, 0x80, 0x37, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff,
+0x9e, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x07, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xdf, 0xf0, 0x43, 0x07,
+0x80, 0x80, 0x1d, 0xe5, 0x24, 0xb4, 0x03, 0x09, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x10, 0xf0, 0x80,
+0x07, 0x90, 0xff, 0x9e, 0xe0, 0x44, 0x20, 0xf0, 0x43, 0x07, 0x80, 0x80, 0x03, 0x53, 0x07, 0x7f,
+0x12, 0x22, 0xda, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x30, 0xe0, 0x05, 0x43, 0x07, 0x20, 0x80, 0x03,
+0x53, 0x07, 0xdf, 0xec, 0x30, 0xe3, 0x05, 0x43, 0x07, 0x40, 0x80, 0x03, 0x53, 0x07, 0xbf, 0xec,
+0x30, 0xe0, 0x05, 0x43, 0x07, 0x10, 0x80, 0x03, 0x53, 0x07, 0xef, 0xed, 0x30, 0xe4, 0x05, 0x43,
+0x07, 0x08, 0x80, 0x03, 0x53, 0x07, 0xf7, 0xed, 0x30, 0xe5, 0x05, 0x43, 0x07, 0x04, 0x80, 0x03,
+0x53, 0x07, 0xfb, 0xed, 0x30, 0xe6, 0x05, 0x43, 0x07, 0x01, 0x80, 0x03, 0x53, 0x07, 0xfe, 0xed,
+0x30, 0xe7, 0x05, 0x43, 0x07, 0x02, 0x80, 0x03, 0x53, 0x07, 0xfd, 0x78, 0x7e, 0x12, 0x22, 0xdc,
+0xa3, 0xef, 0xf0, 0x12, 0x32, 0x84, 0x7f, 0x00, 0x22, 0x90, 0xff, 0xfa, 0x74, 0x08, 0xf0, 0xa3,
+0x74, 0x16, 0xf0, 0x90, 0xff, 0xf9, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcf, 0xe4,
+0xfd, 0x12, 0x23, 0x61, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x03, 0x12, 0x1b, 0x1c, 0x12, 0x19,
+0x92, 0xe5, 0x23, 0x30, 0xe7, 0x02, 0xd2, 0x02, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x24, 0x90, 0xfa,
+0xcf, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x90, 0xfa, 0xcf,
+0xe4, 0xf0, 0xa3, 0x74, 0x0b, 0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x75, 0x2d, 0x00, 0xf5,
+0x2e, 0x7d, 0x01, 0x12, 0x26, 0x98, 0xe5, 0x23, 0x24, 0x80, 0x90, 0xff, 0xf8, 0xf0, 0xe5, 0x23,
+0x64, 0x07, 0x60, 0x1e, 0xe5, 0x23, 0x64, 0x06, 0x60, 0x18, 0xe5, 0x23, 0x64, 0x14, 0x60, 0x12,
+0xe5, 0x23, 0x64, 0x41, 0x60, 0x0c, 0xe5, 0x23, 0x64, 0x1a, 0x70, 0x46, 0xe5, 0x24, 0x64, 0x02,
+0x70, 0x40, 0xe5, 0x23, 0xb4, 0x07, 0x16, 0xd2, 0x94, 0xd2, 0x95, 0xd2, 0x92, 0xd2, 0x93, 0x90,
+0xf9, 0x16, 0xe0, 0x44, 0x02, 0xf0, 0xa3, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1e, 0xe5, 0x23, 0xb4,
+0x41, 0x12, 0x90, 0xf9, 0x16, 0xe0, 0x44, 0x06, 0xf0, 0xa3, 0xe0, 0x44, 0x06, 0xf0, 0xd2, 0xb1,
+0xd2, 0xb4, 0x80, 0x07, 0x90, 0xf9, 0x16, 0xe0, 0x44, 0x01, 0xf0, 0x90, 0xf9, 0x17, 0xe0, 0x44,
+0x01, 0xf0, 0xe5, 0x23, 0x64, 0x42, 0x60, 0x0c, 0xe5, 0x23, 0x64, 0x43, 0x60, 0x06, 0xe5, 0x23,
+0x64, 0x44, 0x70, 0x2e, 0x90, 0xf9, 0x16, 0xe0, 0xff, 0xe5, 0x23, 0xb4, 0x44, 0x04, 0x7e, 0x40,
+0x80, 0x02, 0x7e, 0x00, 0xee, 0x24, 0x80, 0x4f, 0x90, 0xf9, 0x16, 0xf0, 0xa3, 0xe0, 0xff, 0xe5,
+0x23, 0xb4, 0x44, 0x04, 0x7e, 0x40, 0x80, 0x02, 0x7e, 0x00, 0xee, 0x24, 0x80, 0x4f, 0x90, 0xf9,
+0x17, 0xf0, 0x90, 0xfa, 0xcf, 0xe4, 0xf0, 0xa3, 0x74, 0x0d, 0xf0, 0x12, 0x19, 0x92, 0x90, 0xff,
+0xf5, 0xe5, 0x23, 0xf0, 0xe4, 0xf5, 0x35, 0xf5, 0x33, 0xf5, 0x34, 0xf5, 0x32, 0x12, 0x1e, 0x34,
+0x12, 0x1c, 0xe0, 0x12, 0x1e, 0x3b, 0x90, 0xf9, 0x6a, 0x12, 0x1b, 0xf3, 0x90, 0xf9, 0x6f, 0x12,
+0x1b, 0xf3, 0x90, 0xff, 0xff, 0xe4, 0xf0, 0x90, 0xff, 0x83, 0xe0, 0xe4, 0xf0, 0x90, 0xff, 0x81,
0x74, 0x80, 0xf0, 0xa3, 0x74, 0x84, 0xf0, 0x90, 0xff, 0x80, 0xf0, 0xe4, 0xf5, 0x23, 0xe5, 0x23,
-0x12, 0x1c, 0xa7, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x23, 0x12, 0x1c, 0xb5, 0xf5, 0x83, 0xe4, 0xf0,
-0x05, 0x23, 0xe5, 0x23, 0xb4, 0x07, 0xe7, 0x78, 0x7a, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x31,
-0x4d, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x31, 0x5a, 0xe4, 0x93, 0xff,
-0x08, 0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x1c, 0x97, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0,
+0x12, 0x1d, 0x57, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x23, 0x12, 0x1d, 0x65, 0xf5, 0x83, 0xe4, 0xf0,
+0x05, 0x23, 0xe5, 0x23, 0xb4, 0x07, 0xe7, 0x78, 0x7a, 0x76, 0xfe, 0x08, 0x76, 0xf0, 0x90, 0x32,
+0x0a, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xad, 0x07, 0x90, 0x32, 0x17, 0xe4, 0x93, 0xff,
+0x08, 0xf6, 0xff, 0xed, 0x54, 0x0f, 0xfd, 0x12, 0x1d, 0x47, 0x74, 0x84, 0xf0, 0xed, 0x75, 0xf0,
0x08, 0xa4, 0x24, 0x47, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xc3, 0x74, 0xf0,
-0x9f, 0x78, 0x7b, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x1c, 0x28, 0xce, 0xc3, 0x13, 0xce,
-0x13, 0xd8, 0xf9, 0xff, 0xed, 0x12, 0x1c, 0xf8, 0xef, 0xf0, 0xed, 0x12, 0x1d, 0x1e, 0xe4, 0xf5,
-0x23, 0xe5, 0x23, 0x90, 0x31, 0x47, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xe5, 0x23, 0x25, 0xe0,
-0x24, 0x4e, 0xf5, 0x82, 0xe4, 0x34, 0x31, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7,
-0x53, 0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1c, 0x97, 0x12, 0x1d, 0x06, 0x24, 0x47, 0xf5, 0x82,
-0xe4, 0x34, 0xff, 0x12, 0x1c, 0x18, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12,
-0x1c, 0xf8, 0xef, 0xf0, 0x12, 0x1c, 0x1f, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d,
-0x0b, 0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x1d, 0x1e,
+0x9f, 0x78, 0x7b, 0xf6, 0x74, 0xfe, 0x94, 0x00, 0x18, 0x12, 0x1c, 0xd8, 0xce, 0xc3, 0x13, 0xce,
+0x13, 0xd8, 0xf9, 0xff, 0xed, 0x12, 0x1d, 0xa8, 0xef, 0xf0, 0xed, 0x12, 0x1d, 0xce, 0xe4, 0xf5,
+0x23, 0xe5, 0x23, 0x90, 0x32, 0x04, 0x93, 0xff, 0x78, 0x78, 0xf6, 0xfd, 0xe5, 0x23, 0x25, 0xe0,
+0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x34, 0x32, 0xf5, 0x83, 0xe4, 0x93, 0x08, 0xf6, 0xed, 0x30, 0xe7,
+0x53, 0x18, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1d, 0x47, 0x12, 0x1d, 0xb6, 0x24, 0x47, 0xf5, 0x82,
+0xe4, 0x34, 0xff, 0x12, 0x1c, 0xc8, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0xff, 0xe9, 0x12,
+0x1d, 0xa8, 0xef, 0xf0, 0x12, 0x1c, 0xcf, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d,
+0xbb, 0x24, 0x45, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x12, 0x1d, 0xce,
0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x46, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80,
-0xf0, 0x02, 0x18, 0xb7, 0x78, 0x78, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1c, 0xea, 0x12, 0x1d, 0x06,
-0x24, 0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x1c, 0x18, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8,
-0xf9, 0x12, 0x1d, 0x0b, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12,
-0x1c, 0x1f, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d, 0x0b, 0x24, 0x05, 0xf5, 0x82,
+0xf0, 0x02, 0x19, 0x67, 0x78, 0x78, 0xe6, 0x54, 0x0f, 0xf9, 0x12, 0x1d, 0x9a, 0x12, 0x1d, 0xb6,
+0x24, 0x07, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0x12, 0x1c, 0xc8, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8,
+0xf9, 0x12, 0x1d, 0xbb, 0x24, 0x01, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0x12,
+0x1c, 0xcf, 0xce, 0xc3, 0x13, 0xce, 0x13, 0xd8, 0xf9, 0x12, 0x1d, 0xbb, 0x24, 0x05, 0xf5, 0x82,
0xe4, 0x34, 0xff, 0xf5, 0x83, 0xef, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x02, 0xf5, 0x82,
0xe4, 0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0xe9, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x06, 0xf5, 0x82,
0xe4, 0x34, 0xff, 0xf5, 0x83, 0xe4, 0xf0, 0x05, 0x23, 0xe5, 0x23, 0x64, 0x04, 0x60, 0x03, 0x02,
-0x17, 0xe1, 0x90, 0x31, 0x4c, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0x12, 0x1c, 0xe8, 0xe4, 0xf0,
-0x90, 0x31, 0x4b, 0x93, 0xff, 0xf6, 0x12, 0x1c, 0x95, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05,
-0xf0, 0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12,
-0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x25, 0xd7, 0xe7, 0x09, 0xf6, 0x08,
+0x18, 0x91, 0x90, 0x32, 0x09, 0xe4, 0x93, 0xff, 0x78, 0x78, 0xf6, 0x12, 0x1d, 0x98, 0xe4, 0xf0,
+0x90, 0x32, 0x08, 0x93, 0xff, 0xf6, 0x12, 0x1d, 0x45, 0xe4, 0xf0, 0x90, 0xff, 0xfd, 0x74, 0x05,
+0xf0, 0x22, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x01, 0x12,
+0x1b, 0x32, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x26, 0x98, 0xe7, 0x09, 0xf6, 0x08,
0xdf, 0xfa, 0x80, 0x46, 0xe7, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x3e, 0x88, 0x82, 0x8c, 0x83,
0xe7, 0x09, 0xf0, 0xa3, 0xdf, 0xfa, 0x80, 0x32, 0xe3, 0x09, 0xf6, 0x08, 0xdf, 0xfa, 0x80, 0x78,
0xe3, 0x09, 0xf2, 0x08, 0xdf, 0xfa, 0x80, 0x70, 0x88, 0x82, 0x8c, 0x83, 0xe3, 0x09, 0xf0, 0xa3,
@@ -445,7 +456,7 @@ static unsigned char IMAGE_ARRAY_NAME[] =
0x82, 0x8a, 0x83, 0xe4, 0x93, 0xa3, 0xf2, 0x08, 0xdf, 0xf9, 0x80, 0xcc, 0x88, 0xf0, 0xef, 0x60,
0x01, 0x0e, 0x4e, 0x60, 0xc3, 0x88, 0xf0, 0xed, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xb9, 0xf5,
0x82, 0xeb, 0x24, 0x02, 0xb4, 0x04, 0x00, 0x50, 0xaf, 0x23, 0x23, 0x45, 0x82, 0x23, 0x90, 0x19,
-0x4c, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb,
+0xfc, 0x73, 0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb,
0xfe, 0x02, 0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22, 0xbb, 0x01, 0x0c, 0xe5, 0x82,
0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50, 0x06, 0xe9, 0x25, 0x82, 0xf8,
0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22, 0xe5, 0x82, 0x29, 0xf5, 0x82,
@@ -469,364 +480,365 @@ static unsigned char IMAGE_ARRAY_NAME[] =
0xe0, 0xf9, 0x22, 0xeb, 0xf0, 0xa3, 0xea, 0xf0, 0xa3, 0xe9, 0xf0, 0x22, 0xd0, 0x83, 0xd0, 0x82,
0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3, 0x93, 0xf8, 0x74, 0x01,
0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60, 0xef, 0xa3, 0xa3, 0xa3,
-0x80, 0xdf, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0xe5, 0x4c, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25,
+0x80, 0xdf, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0xe5, 0x4c, 0x12, 0x1a, 0xe8, 0x74, 0x01, 0x25,
0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0x74, 0x11, 0x12,
-0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x06,
-0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38,
-0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0xe4, 0x12, 0x1a, 0x38, 0x04, 0x25,
+0x1a, 0xe8, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x06,
+0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0xe8, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38,
+0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0xe4, 0x12, 0x1a, 0xe8, 0x04, 0x25,
0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0xab, 0x36, 0xfa, 0xa9, 0x38, 0xe4, 0x12, 0x1a,
-0x38, 0x04, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x04, 0xe0, 0xab,
-0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35,
-0x37, 0xf5, 0x37, 0x90, 0xff, 0x05, 0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0x38,
+0xe8, 0x04, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x90, 0xff, 0x04, 0xe0, 0xab,
+0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0xe8, 0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35,
+0x37, 0xf5, 0x37, 0x90, 0xff, 0x05, 0xe0, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x12, 0x1a, 0xe8,
0x74, 0x01, 0x25, 0x38, 0xf5, 0x38, 0xe4, 0x35, 0x37, 0xf5, 0x37, 0x22, 0xf5, 0x83, 0xe0, 0x54,
0x08, 0xab, 0x36, 0xaa, 0x37, 0xa9, 0x38, 0x22, 0xf5, 0x83, 0xef, 0xf0, 0xfd, 0x7c, 0x00, 0xc3,
0x78, 0x7b, 0xe6, 0x9d, 0xf6, 0x18, 0xe6, 0x9c, 0xf6, 0xe6, 0xfe, 0x08, 0xe6, 0x78, 0x03, 0x22,
-0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75, 0x38, 0x6f, 0x22, 0xe0, 0x44, 0x04, 0xf0, 0x74, 0x12,
-0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xe0, 0x22, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x7e,
-0x00, 0xc3, 0x90, 0xfa, 0xbd, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xbc, 0xe0, 0x9e, 0xf0, 0x90, 0xfa,
-0xb4, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0xef, 0x25, 0x4f, 0xf5, 0x4f, 0xee, 0x35, 0x4e, 0xf5,
-0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb1, 0x90, 0xfa, 0xb4, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0,
+0x75, 0x36, 0x01, 0x75, 0x37, 0xf9, 0x75, 0x38, 0x72, 0x22, 0xe0, 0x44, 0x04, 0xf0, 0x74, 0x13,
+0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0xe0, 0x22, 0x90, 0xfa, 0xbc, 0xe0, 0xff, 0x7e,
+0x00, 0xc3, 0x90, 0xfa, 0xc0, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xbf, 0xe0, 0x9e, 0xf0, 0x90, 0xfa,
+0xb7, 0xee, 0x8f, 0xf0, 0x12, 0x1b, 0x1c, 0xef, 0x25, 0x4f, 0xf5, 0x4f, 0xee, 0x35, 0x4e, 0xf5,
+0x4e, 0x22, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xb4, 0x90, 0xfa, 0xb7, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0,
0xf5, 0x2e, 0x22, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0x8e, 0x83, 0x24, 0x04, 0xf5, 0x82, 0xe4,
0x35, 0x83, 0xf5, 0x83, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x40, 0xf5, 0x82, 0xe4,
0x34, 0xff, 0xf5, 0x83, 0x22, 0xe5, 0x4d, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x48, 0xf5, 0x82, 0xe4,
0x34, 0xff, 0x22, 0xe5, 0x4d, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x08, 0xf5, 0x82, 0xe4, 0x34, 0xff,
-0x22, 0x90, 0xfa, 0xb6, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22,
-0x90, 0xfa, 0xbb, 0xe0, 0x90, 0xfa, 0xb7, 0xf0, 0x22, 0x75, 0x33, 0x00, 0x8f, 0x34, 0x90, 0xf9,
-0x6c, 0x12, 0x1b, 0x3a, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00,
+0x22, 0x90, 0xfa, 0xb9, 0xe0, 0xff, 0x24, 0xfc, 0x22, 0x90, 0xff, 0x00, 0xe0, 0x54, 0x1f, 0x22,
+0x90, 0xfa, 0xbe, 0xe0, 0x90, 0xfa, 0xba, 0xf0, 0x22, 0x75, 0x33, 0x00, 0x8f, 0x34, 0x90, 0xf9,
+0x6f, 0x12, 0x1b, 0xea, 0x90, 0x00, 0x02, 0x22, 0x54, 0x0f, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x00,
0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x75, 0xf0, 0x08, 0xa4, 0x24, 0x41, 0xf5, 0x82,
0xe4, 0x34, 0xff, 0xf5, 0x83, 0x22, 0x74, 0x80, 0xf0, 0x08, 0xe6, 0xff, 0xe9, 0x75, 0xf0, 0x08,
-0xa4, 0x22, 0x74, 0xaf, 0x25, 0x22, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0,
+0xa4, 0x22, 0x74, 0xb2, 0x25, 0x22, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0x22, 0x75, 0xf0,
0x08, 0xa4, 0x24, 0x42, 0xf5, 0x82, 0xe4, 0x34, 0xff, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x22, 0x90,
0xff, 0x82, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x03, 0xf0, 0x90, 0xff,
0xfc, 0xe0, 0x54, 0xfd, 0xf0, 0x22, 0x78, 0x67, 0xe6, 0x54, 0xfd, 0xf6, 0x90, 0xff, 0xfd, 0x74,
-0x65, 0xf0, 0x22, 0x12, 0x1b, 0x1c, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a,
-0xfa, 0x79, 0xb4, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0,
-0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x67, 0x02, 0x1b, 0x3a, 0x90, 0xff, 0xa4, 0xe0,
+0x65, 0xf0, 0x22, 0x12, 0x1b, 0xcc, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x22, 0x7b, 0x01, 0x7a,
+0xfa, 0x79, 0xb7, 0x22, 0x90, 0xff, 0x80, 0xe0, 0x44, 0x08, 0xf0, 0x22, 0x90, 0xff, 0x83, 0xe0,
+0x54, 0x7f, 0xf0, 0x22, 0xe0, 0xff, 0x90, 0xf9, 0x6a, 0x02, 0x1b, 0xea, 0x90, 0xff, 0xa4, 0xe0,
0x44, 0x02, 0xf0, 0x22, 0x75, 0x39, 0x01, 0x75, 0x3a, 0x09, 0x22, 0x7b, 0x01, 0x7a, 0xf9, 0x79,
-0x6f, 0x22, 0xd3, 0xe5, 0x3c, 0x94, 0x08, 0xe5, 0x3b, 0x94, 0x01, 0x22, 0x90, 0xfa, 0xbb, 0xe0,
-0xff, 0x90, 0xfa, 0xb7, 0xf0, 0x22, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4,
-0xe0, 0x54, 0xef, 0x22, 0x12, 0x10, 0x03, 0x78, 0x88, 0xef, 0xf6, 0x12, 0x2a, 0x06, 0x12, 0x22,
-0x4a, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x21, 0xf3, 0xe0, 0xfd, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x0a,
-0x12, 0x22, 0x52, 0x24, 0x0a, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x1a, 0x4a, 0x12,
-0x22, 0x4a, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x53, 0x12, 0x22, 0x56, 0x24,
-0x04, 0x12, 0x21, 0xf3, 0xe0, 0xf5, 0x54, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xf5, 0x55,
+0x72, 0x22, 0xd3, 0xe5, 0x3c, 0x94, 0x08, 0xe5, 0x3b, 0x94, 0x01, 0x22, 0x90, 0xfa, 0xbe, 0xe0,
+0xff, 0x90, 0xfa, 0xba, 0xf0, 0x22, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xef, 0x22, 0x90, 0xff, 0xb4,
+0xe0, 0x54, 0xef, 0x22, 0x12, 0x10, 0x4b, 0x78, 0x88, 0xef, 0xf6, 0x12, 0x2a, 0xc7, 0x12, 0x22,
+0xfa, 0x8e, 0x83, 0x24, 0x09, 0x12, 0x22, 0xa1, 0xe0, 0xfd, 0x12, 0x22, 0xe8, 0x90, 0x00, 0x0a,
+0x12, 0x23, 0x02, 0x24, 0x0a, 0x12, 0x22, 0xa1, 0xe0, 0x90, 0x00, 0x0b, 0x12, 0x1a, 0xfa, 0x12,
+0x22, 0xfa, 0xf5, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xa3, 0xe0, 0xf5, 0x53, 0x12, 0x23, 0x06, 0x24,
+0x04, 0x12, 0x22, 0xa1, 0xe0, 0xf5, 0x54, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0xa3, 0xe0, 0xf5, 0x55,
0xe5, 0x53, 0xc4, 0x13, 0x13, 0x13, 0x54, 0x01, 0x78, 0x88, 0xf6, 0xd3, 0x94, 0x00, 0x40, 0x06,
-0xe5, 0x54, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x88, 0xe6, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x0c, 0xef,
-0x12, 0x1a, 0x4a, 0x78, 0x80, 0x12, 0x22, 0x09, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x53,
-0x07, 0x0c, 0x53, 0x06, 0xe6, 0xe5, 0x53, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, 0x54, 0x20,
-0xe5, 0x0e, 0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7, 0x03, 0x43, 0x07, 0x02,
-0xe5, 0x53, 0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x53, 0x30, 0xe2, 0x03, 0x43, 0x07, 0x20,
-0xe5, 0x53, 0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x53, 0x30, 0xe1, 0x03, 0x43, 0x07,
-0x80, 0xe5, 0x53, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x53, 0x30, 0xe6, 0x03, 0x43, 0x06,
-0x08, 0xe5, 0x54, 0x20, 0xe4, 0x0e, 0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7,
-0x03, 0x43, 0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, 0x8f, 0xf0,
-0x12, 0x1a, 0xef, 0xe5, 0x55, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, 0x12, 0x22,
-0x2c, 0x90, 0x00, 0x08, 0xef, 0x12, 0x1a, 0x4a, 0x80, 0x0a, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x08,
-0xe4, 0x12, 0x1a, 0x4a, 0xe5, 0x55, 0x54, 0x03, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x07, 0xef, 0x12,
-0x1a, 0x4a, 0xe5, 0x55, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x1a, 0x4a, 0x90,
-0x00, 0x07, 0x12, 0x1a, 0x0b, 0x70, 0x13, 0x12, 0x22, 0x2d, 0xe9, 0x24, 0x09, 0xf9, 0xe4, 0x3a,
-0xfa, 0x12, 0x19, 0xf2, 0xff, 0xc3, 0x13, 0x12, 0x1a, 0x38, 0x12, 0x22, 0x78, 0x24, 0x08, 0x12,
-0x21, 0xf3, 0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x21, 0xf3, 0xe0,
-0xfd, 0xee, 0xed, 0x12, 0x22, 0x2c, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0xef, 0x12,
-0x31, 0xc7, 0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2f, 0x18, 0x02, 0x10, 0x86, 0x90, 0xfa, 0xe3, 0xe0,
-0xb4, 0x03, 0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, 0xfa, 0xd7,
-0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0xff, 0x7e, 0x00, 0x90, 0xfa,
-0xd3, 0xee, 0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, 0x12, 0x1a,
-0x98, 0xff, 0x90, 0xfa, 0xd5, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, 0x01, 0x8e,
-0x50, 0x8f, 0x51, 0x74, 0x0a, 0x25, 0x51, 0xf5, 0x51, 0xe4, 0x35, 0x50, 0xf5, 0x50, 0x90, 0xfa,
-0xd8, 0xe0, 0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd6, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, 0xff, 0x90,
-0xfa, 0xda, 0xf0, 0xc3, 0x90, 0xfa, 0xd4, 0xe0, 0x9f, 0x90, 0xfa, 0xd3, 0xe0, 0x94, 0x00, 0x50,
-0x06, 0xa3, 0xe0, 0x90, 0xfa, 0xda, 0xf0, 0x12, 0x1f, 0xfb, 0x60, 0x03, 0xe0, 0xff, 0x22, 0x12,
-0x2d, 0x5a, 0x90, 0xfa, 0xd3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, 0xfa, 0xd7,
-0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, 0xfa, 0xda,
-0xf0, 0x80, 0x08, 0x90, 0xfa, 0xd4, 0xe0, 0x90, 0xfa, 0xda, 0xf0, 0x12, 0x1f, 0xfb, 0x60, 0x03,
-0xe0, 0xff, 0x22, 0x12, 0x2d, 0x5a, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5,
-0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x7f, 0x00, 0x22, 0xaa, 0x50, 0xa9, 0x51, 0x7b,
-0x01, 0x90, 0xfa, 0xd5, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xda, 0xe0, 0xf5, 0x4a, 0x12,
-0x28, 0x9f, 0x90, 0xfa, 0xd9, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, 0xfe, 0x60,
-0x2e, 0x24, 0xfe, 0x70, 0x03, 0x02, 0x20, 0xbb, 0x24, 0x06, 0x60, 0x03, 0x02, 0x21, 0x03, 0x78,
-0x71, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x33,
-0x90, 0xfa, 0x91, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xaf, 0x74, 0x01, 0xf0, 0x22, 0x78,
-0x72, 0xe6, 0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x43,
-0x90, 0xfa, 0x93, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xb0, 0x74, 0x01, 0xf0, 0x22, 0x90,
-0xfa, 0x9d, 0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x21, 0x03, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa,
-0xca, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xca, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff,
-0xa6, 0x12, 0x22, 0x5d, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xca, 0xf0, 0x80, 0xe6, 0x90, 0xfa,
-0xcb, 0xe0, 0xff, 0x74, 0x34, 0xfe, 0x12, 0x2c, 0xb4, 0xef, 0x70, 0x57, 0x90, 0xfa, 0xcb, 0xe0,
-0xff, 0x74, 0x34, 0x90, 0xfa, 0x95, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xa7, 0xe0, 0xa3,
-0x30, 0xe5, 0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xca, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xca,
-0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x22, 0x5d, 0x90, 0xff, 0xb6,
-0xe0, 0x90, 0xfa, 0xca, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xcb, 0xe0, 0xff, 0x74, 0x44, 0xfe, 0x12,
-0x2c, 0xb4, 0xef, 0x70, 0x0e, 0x90, 0xfa, 0xcb, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, 0x97, 0xf0,
-0xef, 0xa3, 0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0,
-0x00, 0xc0, 0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0,
-0x07, 0x90, 0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xc9, 0xf0, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0xef,
-0x12, 0x1b, 0x4c, 0x21, 0xbb, 0x26, 0x21, 0xbb, 0x2e, 0x21, 0x5e, 0x30, 0x21, 0x5e, 0x32, 0x21,
-0x6c, 0x38, 0x21, 0x7e, 0x3a, 0x21, 0xb0, 0x3e, 0x21, 0x9b, 0x44, 0x21, 0x90, 0x46, 0x21, 0xa6,
-0x50, 0x21, 0xa6, 0x52, 0x21, 0xa6, 0x54, 0x21, 0xa6, 0x56, 0x00, 0x00, 0x21, 0xc0, 0x90, 0xfa,
-0xc9, 0xe0, 0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x11, 0x16, 0x80, 0x62, 0x7c, 0x00, 0x7d, 0x01,
-0x7f, 0x03, 0x12, 0x11, 0x16, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, 0x7c, 0x00,
-0x7d, 0x01, 0x7f, 0x02, 0x12, 0x11, 0x16, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x3e,
-0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x05, 0x12, 0x11, 0x16, 0x80, 0x33, 0x7c, 0x00, 0x7d, 0x01, 0x7f,
-0x06, 0x12, 0x11, 0x16, 0x80, 0x28, 0x90, 0xfa, 0xc9, 0xe0, 0xff, 0x12, 0x20, 0x18, 0x80, 0x1e,
-0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x04, 0x12, 0x11, 0x16, 0x80, 0x13, 0x12, 0x27, 0x8d, 0x80, 0x0e,
-0x90, 0xfa, 0xc9, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x2c, 0xb4, 0xd0, 0x07,
-0xd0, 0x06, 0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0,
-0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0x24,
-0x04, 0x8e, 0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x74, 0x12, 0x25, 0x24, 0xf5,
-0x82, 0xe4, 0x34, 0xf9, 0xf5, 0x83, 0x22, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e,
-0x83, 0x22, 0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b,
-0xff, 0x7a, 0x31, 0x79, 0x99, 0x7e, 0x00, 0x7f, 0x0a, 0x02, 0x19, 0xcc, 0xff, 0x90, 0xf9, 0x6c,
-0x02, 0x1b, 0x3a, 0x90, 0xf9, 0x67, 0x12, 0x1b, 0x3a, 0x90, 0x00, 0x04, 0x02, 0x1a, 0x0b, 0xe6,
-0xfc, 0x08, 0xe6, 0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, 0x78, 0x7e, 0xe6, 0xfe, 0x08, 0xe6,
-0xff, 0x22, 0xed, 0x12, 0x1a, 0x4a, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90,
-0xfa, 0xcb, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, 0xf0, 0x4e, 0xf0, 0x22, 0x08, 0xe6,
-0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x24, 0x09, 0x22, 0x78, 0x7e, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c,
-0x83, 0x22, 0xa6, 0x07, 0xe6, 0x24, 0x6e, 0xf8, 0xe6, 0x22, 0x78, 0x7e, 0xe6, 0xfa, 0x08, 0xe6,
-0xfb, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22, 0x8b, 0x82, 0x8a, 0x83, 0xe5, 0x82, 0x22,
-0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0x8d, 0x28, 0x90, 0xfa, 0xcf, 0xe4, 0xf0, 0xa3, 0x74, 0x02,
-0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xce, 0x90, 0xfa, 0xcf, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0, 0xf5,
-0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xce, 0xe0, 0x65, 0x28, 0x60, 0x46, 0xa3, 0xe0,
-0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x23, 0x2f, 0x90, 0xfa, 0xce, 0xe0,
-0xff, 0x90, 0xfa, 0xd1, 0xe4, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0x12, 0x23, 0x2f, 0x90, 0xfa, 0xd1,
-0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xcf, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xfa, 0xce, 0xe0,
-0xa3, 0x75, 0xf0, 0x00, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x04, 0x12, 0x1a,
-0x6c, 0x02, 0x22, 0xb1, 0x90, 0xfa, 0xd0, 0xe0, 0x24, 0x01, 0xff, 0x90, 0xfa, 0xcf, 0xe0, 0x34,
-0x00, 0xab, 0x25, 0xaa, 0x26, 0xa9, 0x27, 0x8f, 0xf0, 0x12, 0x1a, 0xd0, 0x7f, 0x00, 0x22, 0x7b,
-0x01, 0x7a, 0xfa, 0x79, 0xce, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1a, 0x6c, 0x85,
-0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x25, 0xd7, 0x8f, 0x62, 0x12, 0x2a, 0x06, 0x12, 0x22,
-0x4a, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x21, 0xf3, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x02, 0xf0, 0x08,
-0x12, 0x22, 0x3f, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x22, 0x56, 0x24, 0x0b, 0x12, 0x21, 0xf3,
-0xe0, 0x44, 0x01, 0xf0, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0,
-0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x62, 0x24, 0xfe, 0x44, 0x20, 0xfc, 0x4d, 0xf0, 0xe5, 0x82, 0x24,
-0x04, 0x12, 0x21, 0xf3, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3, 0x74,
-0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x05, 0x12, 0x21, 0xf3, 0xc0,
-0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x96, 0x25, 0x62, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83,
-0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82, 0x8e,
-0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x21, 0xf3, 0xe0, 0x44, 0x80, 0xf0,
-0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x62, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12,
-0x10, 0x03, 0x7f, 0x02, 0x12, 0x12, 0x19, 0x78, 0x67, 0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0, 0xd2,
-0xb1, 0x90, 0xf9, 0x15, 0xe0, 0x30, 0xe7, 0x07, 0x90, 0xff, 0x9e, 0xe4, 0xf0, 0x80, 0x36, 0xd2,
-0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, 0x7b, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa, 0x7c,
-0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, 0x79, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa, 0x7a,
-0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74, 0x40,
-0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, 0xe4, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90, 0xff,
-0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43, 0x87,
-0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7b, 0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7c, 0xe0,
-0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x79, 0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x7a, 0xe0,
-0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x17, 0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe4, 0xe0,
-0xf5, 0xa8, 0x02, 0x10, 0x86, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x12, 0x2d, 0x3c, 0x90, 0xfa,
-0xc0, 0x12, 0x1b, 0x43, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0x43, 0x90, 0xfa,
-0xc4, 0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x1a, 0x6c, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0x3a, 0xe9, 0x24,
-0x01, 0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x43, 0xab, 0x5c, 0xaa, 0x5d, 0xa9,
-0x5e, 0x12, 0x2d, 0x48, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x82, 0xf6, 0x90, 0xfa, 0xbe,
-0xe0, 0xff, 0x78, 0x82, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xc0, 0x12, 0x2d, 0x1d, 0xff,
-0x78, 0x83, 0xf6, 0x90, 0xfa, 0xc3, 0x12, 0x2d, 0x1d, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x83, 0xf6,
-0x12, 0x2d, 0x1a, 0x5e, 0x4f, 0xff, 0x78, 0x83, 0xf6, 0x12, 0x2d, 0x23, 0x75, 0xf0, 0x02, 0x12,
-0x1a, 0x6c, 0x90, 0xfa, 0xc4, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x1a, 0x6c, 0xab, 0x5c, 0xaa, 0x5d,
-0xa9, 0x5e, 0x90, 0x00, 0x04, 0x12, 0x1a, 0x0b, 0x30, 0xe4, 0x03, 0x12, 0x2d, 0x32, 0x78, 0x82,
-0x06, 0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xbf, 0xf0, 0x22, 0x8b, 0x56, 0x8a, 0x57, 0x89, 0x58, 0x90,
-0xfa, 0xbf, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xbe, 0xf0, 0x12, 0x19, 0xf2, 0x24, 0x6e, 0x60,
-0x26, 0x14, 0x70, 0x70, 0x12, 0x2d, 0x09, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x24, 0x95,
-0x80, 0x62, 0x12, 0x2d, 0x53, 0x12, 0x1f, 0x2c, 0x90, 0xfa, 0xbf, 0xef, 0xf0, 0x80, 0x55, 0x90,
-0xfa, 0xbf, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2d, 0x09, 0x60, 0x09, 0x24, 0x30, 0x70, 0x3e,
-0x12, 0x2c, 0x5f, 0x80, 0x3f, 0xe5, 0x58, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x57, 0xfa, 0x7b, 0x01,
-0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2d, 0x53, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0xfd,
-0x90, 0x00, 0x08, 0x12, 0x1a, 0x98, 0xf5, 0x2e, 0x85, 0xf0, 0x2d, 0xd0, 0x01, 0xd0, 0x02, 0xd0,
-0x03, 0x12, 0x25, 0xd7, 0x90, 0xfa, 0xbe, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90, 0xfa,
-0xbf, 0x74, 0x81, 0xf0, 0x90, 0xfa, 0xbf, 0xe0, 0x12, 0x2d, 0x53, 0x90, 0x00, 0x02, 0x12, 0x1a,
-0x4a, 0x90, 0xfa, 0xbe, 0xe0, 0xff, 0x22, 0x8b, 0x29, 0x8a, 0x2a, 0x89, 0x2b, 0x8d, 0x2c, 0xe5,
-0x2c, 0x70, 0x03, 0xaf, 0x2c, 0x22, 0x12, 0x2d, 0x82, 0x70, 0x16, 0x12, 0x2d, 0xa1, 0xe5, 0x2d,
-0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0x1b, 0x50, 0xf2, 0x12, 0x26, 0x64, 0x40, 0x0b, 0x7f, 0x00,
-0x22, 0x12, 0x2d, 0xa1, 0x12, 0x26, 0x64, 0x50, 0xf8, 0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0, 0xe5,
-0x2c, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4, 0xf0,
-0xf5, 0x2f, 0xe5, 0x2c, 0x14, 0xff, 0xe5, 0x2f, 0xc3, 0x9f, 0x50, 0x2a, 0x12, 0x31, 0x04, 0x40,
-0x03, 0xaf, 0x2f, 0x22, 0xc3, 0xe5, 0x2c, 0x95, 0x2f, 0xff, 0xbf, 0x02, 0x07, 0x90, 0xff, 0xf0,
-0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2d, 0x94, 0x05, 0x2f, 0x74, 0x01, 0x25, 0x2b, 0xf5, 0x2b, 0xe4,
-0x35, 0x2a, 0xf5, 0x2a, 0x80, 0xcc, 0x12, 0x31, 0x04, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x12, 0x2d,
-0x94, 0xaf, 0x2c, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x2e, 0xf0, 0x02, 0x31, 0x1b, 0x12, 0x10, 0x03,
-0x78, 0x84, 0x12, 0x22, 0x82, 0x30, 0xe1, 0x08, 0x7f, 0x13, 0x12, 0x30, 0xec, 0x02, 0x26, 0xfb,
-0x78, 0x84, 0xe6, 0xf9, 0x24, 0x12, 0x12, 0x21, 0xff, 0xe0, 0xff, 0x30, 0xe7, 0x40, 0x54, 0x03,
-0x60, 0x1e, 0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x44, 0x04,
-0xf0, 0x80, 0x46, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x80, 0x39,
-0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x80,
-0x28, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1b, 0xef, 0x54,
-0x03, 0x60, 0x14, 0xe9, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80, 0x07,
-0x90, 0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x17, 0xe0, 0x04, 0xf0, 0xaf,
-0x01, 0x12, 0x22, 0x33, 0xfd, 0x12, 0x2f, 0x49, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x75, 0xa8,
-0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x8b, 0x02, 0x27, 0x48, 0x02, 0x30, 0xcf,
-0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf, 0xf4,
-0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54, 0x0f,
-0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80, 0x0b,
-0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x2b, 0x4c, 0xe4, 0x7e, 0x01, 0x93, 0x60,
-0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60, 0x01,
-0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4, 0x93,
-0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3, 0xc8,
-0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xe4, 0xf5, 0x22,
-0x12, 0x1d, 0x12, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x22, 0x24, 0x03, 0xff, 0x12, 0x2f, 0x77, 0x12,
-0x1d, 0x12, 0xe4, 0xf0, 0x05, 0x22, 0xe5, 0x22, 0xc3, 0x94, 0x02, 0x40, 0xe3, 0xe4, 0xf5, 0x22,
-0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x91, 0x12, 0x1d, 0x53, 0x60, 0x2c, 0x12, 0x2c, 0xb4,
-0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x91, 0x12, 0x1b, 0x1c, 0xe4, 0xf0,
-0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x22, 0x90, 0xfa, 0x9d, 0x12, 0x1b, 0x1c, 0xe0, 0xa3, 0x30,
-0xe6, 0x33, 0x12, 0x1d, 0x12, 0x74, 0x04, 0xf0, 0x22, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa,
-0x95, 0x12, 0x1d, 0x53, 0x60, 0x16, 0x12, 0x2c, 0xb4, 0xef, 0x60, 0x19, 0x75, 0xf0, 0x02, 0xe5,
-0x22, 0x90, 0xfa, 0x95, 0x12, 0x1b, 0x1c, 0xe4, 0xf0, 0xa3, 0xf0, 0x22, 0x05, 0x22, 0xe5, 0x22,
-0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xfe, 0xef,
-0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xe0, 0x12,
-0x1c, 0x11, 0x12, 0x1a, 0x38, 0x0f, 0x12, 0x1c, 0x00, 0x80, 0xdd, 0xef, 0xfd, 0xc3, 0xe5, 0x3a,
-0x9d, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5, 0x39, 0xd3, 0xe5, 0x3a, 0x94, 0x00, 0xe5, 0x39,
-0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, 0x12, 0x1d, 0x2f, 0x12, 0x1d, 0x84,
-0x12, 0x1d, 0x76, 0x12, 0x19, 0xf2, 0x24, 0x6e, 0x60, 0x1e, 0x14, 0x60, 0x1b, 0x24, 0x8e, 0x70,
-0x2d, 0x90, 0x00, 0x01, 0x12, 0x1a, 0x0b, 0xff, 0x24, 0xfc, 0x60, 0x03, 0x04, 0x70, 0x1f, 0xef,
-0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x11, 0x16, 0x12, 0x1d, 0x8b, 0x12, 0x25, 0x39, 0x12, 0x1c,
-0xd9, 0x12, 0x1a, 0x0b, 0x60, 0x03, 0x02, 0x31, 0xbd, 0xe4, 0xff, 0x12, 0x31, 0xb1, 0x22, 0x8b,
-0x45, 0x8a, 0x46, 0x89, 0x47, 0x8c, 0x48, 0x8d, 0x49, 0xd2, 0x00, 0x12, 0x2d, 0x82, 0x70, 0x16,
-0x12, 0x2d, 0xa1, 0xe5, 0x48, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0x1b, 0x50, 0xf2, 0x12, 0x29,
-0x14, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2d, 0xa1, 0x12, 0x29, 0x14, 0x50, 0xf8, 0xe4, 0xf5,
-0x4b, 0xe5, 0x4a, 0x14, 0xff, 0xe5, 0x4b, 0xc3, 0x9f, 0x50, 0x17, 0x12, 0x29, 0x04, 0x40, 0x03,
-0x7f, 0x18, 0x22, 0x05, 0x4b, 0x74, 0x01, 0x25, 0x47, 0xf5, 0x47, 0xe4, 0x35, 0x46, 0xf5, 0x46,
-0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x29, 0x04, 0x40, 0x03, 0x7f, 0x18,
-0x22, 0x7f, 0x00, 0x22, 0xab, 0x45, 0xaa, 0x46, 0xa9, 0x47, 0x12, 0x19, 0xf2, 0x90, 0xff, 0xf1,
-0xf0, 0x02, 0x31, 0x1b, 0x90, 0xff, 0xf1, 0xe5, 0x49, 0xf0, 0x02, 0x31, 0x1b, 0x7b, 0x01, 0x7a,
-0xfa, 0x79, 0xcc, 0xe4, 0xfd, 0x12, 0x22, 0xa0, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x09, 0x12,
-0x1a, 0x6c, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12,
-0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x90, 0xff, 0xf7, 0xe5,
-0x23, 0x12, 0x29, 0x78, 0x90, 0xff, 0xf6, 0xe5, 0x23, 0xf0, 0x90, 0xfa, 0xcc, 0xe4, 0xf0, 0xa3,
-0x74, 0x06, 0x12, 0x29, 0x78, 0xe5, 0x23, 0x30, 0xe0, 0x07, 0x90, 0xff, 0xfc, 0x74, 0x94, 0xf0,
-0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90,
-0xfa, 0xcc, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1a, 0x82, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01,
-0x02, 0x25, 0xd7, 0x90, 0xff, 0x93, 0x74, 0x2a, 0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06, 0x90,
-0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, 0xe0, 0x44, 0x90, 0xf0, 0xe4, 0x90, 0xf9, 0x15,
-0xf0, 0xa3, 0xf0, 0x12, 0x2a, 0x78, 0x12, 0x16, 0x42, 0x12, 0x2f, 0xcd, 0x7e, 0x07, 0x7f, 0xd0,
-0x12, 0x11, 0xe2, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x11, 0xfc, 0xe4, 0x78, 0x77, 0xf6, 0x78, 0x77,
-0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x6e, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x77, 0x06,
-0x80, 0xec, 0x7f, 0x03, 0x12, 0x2e, 0xb3, 0x90, 0xf9, 0x15, 0xe0, 0x20, 0xe4, 0x05, 0x7f, 0x04,
-0x12, 0x2e, 0xb3, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8, 0xe0,
-0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x15, 0x65, 0xa8, 0x65, 0xa6, 0x07, 0x30, 0x08, 0x05, 0x12,
-0x11, 0x66, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x65, 0xe6, 0xff, 0xb4, 0x03, 0x0f, 0x78, 0x7c, 0x76,
-0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, 0x7c, 0x76, 0xff,
-0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x80, 0x76, 0xfa, 0x08, 0x76, 0x9b,
-0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x22, 0x92, 0x7b, 0x01, 0x7a, 0xff,
-0x79, 0x48, 0x78, 0x68, 0x12, 0x1b, 0x31, 0xa8, 0x65, 0xe6, 0x24, 0xfd, 0x75, 0xf0, 0x08, 0xa4,
-0xff, 0xae, 0xf0, 0x78, 0x6a, 0x12, 0x22, 0x92, 0x79, 0x08, 0x78, 0x6b, 0x12, 0x1b, 0x31, 0x78,
-0x6d, 0xef, 0x12, 0x22, 0x92, 0x05, 0x65, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xab, 0xf0, 0xe0,
-0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe3, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcc, 0xe4,
-0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x25, 0xd7, 0x7e, 0x00, 0x90, 0xfa, 0xe1, 0xee, 0xf0,
-0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcc, 0xe0, 0xb4, 0x52, 0x09, 0x90, 0xf9,
-0x15, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe1, 0xe0, 0x70, 0x04, 0xa3, 0xe0, 0x64,
-0x01, 0x70, 0x10, 0x90, 0xfa, 0xcc, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x15, 0xe0, 0x44, 0x10,
-0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe3, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x15, 0xe0, 0x54, 0xef, 0xf0,
-0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x12, 0x10, 0x03, 0x78, 0x8a, 0xef, 0xf6, 0x12,
-0x2a, 0x06, 0x12, 0x22, 0x33, 0x30, 0xe0, 0x25, 0x12, 0x22, 0x07, 0xe0, 0x54, 0x7f, 0xf0, 0x78,
-0x6b, 0x12, 0x1b, 0x28, 0x90, 0x00, 0x02, 0x12, 0x1a, 0x0b, 0x30, 0xe7, 0x09, 0x90, 0x00, 0x02,
-0xe4, 0x12, 0x1a, 0x4a, 0x80, 0xe9, 0x12, 0x22, 0x07, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x22, 0x33,
-0x30, 0xe1, 0x1e, 0x12, 0x21, 0xe9, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x31, 0x5c, 0x78, 0x68, 0x12,
-0x1b, 0x28, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x1a, 0x4a, 0x12, 0x21, 0xe9, 0xe0, 0x44, 0x80,
-0xf0, 0x12, 0x31, 0xc7, 0xe4, 0xff, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x03, 0x68, 0x01, 0xff,
-0x48, 0x03, 0x6b, 0x01, 0xff, 0x08, 0x02, 0x66, 0x00, 0x00, 0x44, 0xfa, 0x95, 0x00, 0x00, 0x00,
-0x00, 0x44, 0xfa, 0x91, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xaf, 0x00, 0x00, 0x42, 0xfa, 0x7b,
-0x00, 0x00, 0x42, 0xfa, 0x79, 0x00, 0x00, 0x42, 0xf9, 0x6a, 0xff, 0xff, 0x42, 0xfa, 0x77, 0x00,
-0x00, 0x43, 0xf9, 0x18, 0x0a, 0x32, 0x02, 0x41, 0xf9, 0x65, 0x20, 0x41, 0xf9, 0x66, 0x20, 0x41,
-0xf9, 0x63, 0x00, 0x41, 0xf9, 0x64, 0x00, 0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf9,
-0x15, 0x00, 0x00, 0x41, 0xf9, 0x17, 0x00, 0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12,
-0x10, 0x03, 0x78, 0x85, 0xef, 0xf6, 0x12, 0x30, 0x93, 0x12, 0x30, 0xec, 0x78, 0x85, 0xe6, 0xff,
-0x24, 0x12, 0x12, 0x21, 0xff, 0xe0, 0xfe, 0x30, 0xe7, 0x16, 0xef, 0xb4, 0x03, 0x09, 0x90, 0xff,
-0x9e, 0xe0, 0x54, 0xfa, 0xf0, 0x80, 0x22, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf5, 0xf0, 0x80, 0x19,
-0xee, 0x54, 0x03, 0x60, 0x14, 0xef, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20, 0xf0,
-0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x17, 0xe0, 0x14, 0xf0, 0xe0,
-0x70, 0x02, 0xd2, 0xb3, 0x02, 0x10, 0x86, 0x12, 0x1d, 0x6c, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04,
-0xe5, 0x39, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x3a, 0x94, 0x08, 0xe5, 0x39, 0x94, 0x00, 0x40,
-0x11, 0x7f, 0x08, 0xef, 0xe5, 0x3a, 0x94, 0x08, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5, 0x39,
-0x80, 0x05, 0xaf, 0x3a, 0x12, 0x1d, 0x84, 0xe4, 0xfe, 0xee, 0xc3, 0x9f, 0x50, 0x19, 0x12, 0x1c,
-0x11, 0x12, 0x19, 0xf2, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xed,
-0xf0, 0x0e, 0x12, 0x1c, 0x00, 0x80, 0xe2, 0xef, 0x54, 0x7f, 0x90, 0xff, 0x81, 0xf0, 0x22, 0x8b,
-0x59, 0x8a, 0x5a, 0x89, 0x5b, 0x12, 0x2d, 0x48, 0x70, 0x05, 0xa3, 0x74, 0x08, 0xf0, 0x22, 0xab,
-0x59, 0xaa, 0x5a, 0xa9, 0x5b, 0x12, 0x2d, 0x3c, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x43, 0xe5, 0x5b,
-0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5a, 0xfa, 0x90, 0xfa, 0xc0, 0x12, 0x1b, 0x43, 0xe4, 0x90, 0xfa,
-0xbf, 0xf0, 0x78, 0x8b, 0xf6, 0x90, 0xfa, 0xbe, 0xe0, 0xff, 0x78, 0x8b, 0xe6, 0xc3, 0x9f, 0x50,
-0x12, 0x12, 0x2d, 0x1a, 0xff, 0x12, 0x2d, 0x23, 0x12, 0x2d, 0x36, 0x78, 0x8b, 0x06, 0x12, 0x2d,
-0x32, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x31, 0x4d, 0xe4, 0x93, 0xff, 0x78, 0x74,
-0xf6, 0x54, 0x0f, 0x12, 0x1c, 0xf8, 0xe0, 0x08, 0x76, 0x00, 0x08, 0xf6, 0x18, 0x12, 0x1c, 0x29,
-0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x75, 0xee, 0xf6, 0x08, 0xef, 0xf6, 0xee,
-0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, 0xe0, 0x20, 0xe7, 0x03, 0x7f, 0x00,
-0x22, 0x78, 0x75, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0xec, 0xf0, 0xa3, 0xed, 0xf0,
-0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58, 0x90,
-0x00, 0x03, 0x12, 0x1a, 0x0b, 0x54, 0xf0, 0x24, 0xa0, 0x22, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0x3a,
-0x02, 0x19, 0xf2, 0x90, 0xfa, 0xc0, 0x12, 0x1b, 0x3a, 0xef, 0x12, 0x1a, 0x38, 0x90, 0xfa, 0xc7,
-0xe4, 0x22, 0x90, 0xfa, 0xc1, 0xe4, 0x75, 0xf0, 0x01, 0x02, 0x1a, 0x6c, 0x90, 0x00, 0x08, 0x12,
-0x1a, 0x98, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, 0x05, 0x12, 0x1a, 0x0b, 0x90, 0xfa,
-0xbe, 0xf0, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58, 0x22, 0x90, 0xfa, 0xda, 0xe0, 0xff, 0x7e,
-0x00, 0xc3, 0x90, 0xfa, 0xd4, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xd3, 0xe0, 0x9e, 0xf0, 0x90, 0xfa,
-0xd5, 0xee, 0x8f, 0xf0, 0x12, 0x1a, 0x6c, 0xef, 0x25, 0x51, 0xf5, 0x51, 0xee, 0x35, 0x50, 0xf5,
-0x50, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0xfa, 0xe3,
-0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x29, 0xaa, 0x2a, 0xa9, 0x2b, 0x02, 0x1a,
-0x38, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x64, 0xed, 0x70, 0x0f, 0xe5, 0x64, 0xb4,
-0x03, 0x05, 0x7f, 0x01, 0x02, 0x31, 0x32, 0x7f, 0x02, 0x02, 0x31, 0x32, 0xaf, 0x64, 0x12, 0x2a,
-0x06, 0x74, 0x6e, 0x25, 0x64, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, 0xd2, 0x09, 0x12, 0x1c, 0x83, 0xe0,
-0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x64, 0xb4, 0x03, 0x07, 0x7f, 0x81, 0x12, 0x31,
-0x32, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x31, 0x32, 0x30, 0x09, 0x07, 0x12, 0x1c, 0x83, 0xe0, 0x44,
-0x80, 0xf0, 0x12, 0x31, 0xc7, 0x22, 0x12, 0x10, 0x03, 0x90, 0xff, 0xfd, 0xe0, 0x44, 0x60, 0xf0,
-0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0x00, 0xe0, 0x30, 0xe7, 0x13,
-0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x35, 0x80, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x01,
-0xf0, 0x80, 0x0d, 0x12, 0x1d, 0x2f, 0x53, 0x35, 0x7f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0xfe, 0xf0,
-0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0xb0, 0x12, 0x1d, 0x37, 0x02, 0x10, 0x86,
-0x12, 0x10, 0x03, 0x78, 0x89, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x2a, 0x06, 0x90, 0xf9, 0x67, 0x12,
-0x1b, 0x3a, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x80, 0xe6, 0xfe, 0x08,
-0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x22, 0x25, 0x12, 0x31, 0xc7,
-0x78, 0x89, 0xe6, 0xff, 0x12, 0x13, 0x3f, 0x12, 0x30, 0xec, 0x02, 0x10, 0x86, 0x8f, 0x63, 0x12,
-0x2a, 0x06, 0x12, 0x22, 0x07, 0xe0, 0x54, 0x3f, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x21, 0xf3,
-0xe0, 0x54, 0x3f, 0xf0, 0x08, 0xe6, 0xfe, 0x08, 0xe6, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x21, 0xf3,
-0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x63, 0xf8, 0x74, 0xfb, 0x56, 0xf6,
-0x7f, 0x00, 0x22, 0x8f, 0x23, 0xc2, 0x08, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x12, 0x78, 0x7e, 0x12,
-0x21, 0xeb, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x22, 0x4a, 0x12, 0x21, 0xef, 0xe0, 0x20, 0xe0, 0xf6,
-0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x31, 0xc7,
-0xaf, 0x23, 0x12, 0x13, 0x3f, 0x22, 0x12, 0x10, 0x03, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x4a, 0x24,
-0x06, 0x12, 0x21, 0xf1, 0xe0, 0xfd, 0x12, 0x22, 0x2d, 0x90, 0x00, 0x03, 0x12, 0x22, 0x52, 0x24,
-0x05, 0x12, 0x21, 0xf3, 0xe0, 0x90, 0x00, 0x04, 0x12, 0x1a, 0x4a, 0x12, 0x31, 0xc7, 0x7d, 0x02,
-0xe4, 0xff, 0x12, 0x2f, 0x18, 0x02, 0x10, 0x86, 0xae, 0x05, 0x12, 0x1c, 0xde, 0xef, 0x12, 0x1a,
-0x4a, 0x0e, 0x0e, 0x0e, 0xee, 0xd3, 0x95, 0x3c, 0xe4, 0x95, 0x3b, 0x40, 0x02, 0xae, 0x3c, 0xee,
-0xd3, 0x94, 0x08, 0x74, 0x80, 0x94, 0x81, 0x40, 0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02,
-0x12, 0x1a, 0x4a, 0xaf, 0x06, 0x12, 0x31, 0xb1, 0x22, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01,
-0x60, 0x03, 0x7f, 0x10, 0x22, 0xed, 0x54, 0x7c, 0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22,
-0x74, 0x6e, 0x2e, 0xf8, 0x74, 0x02, 0x46, 0xf6, 0x74, 0x96, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa,
-0xf5, 0x83, 0xed, 0xf0, 0x7f, 0x00, 0x22, 0xbf, 0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04,
-0x7c, 0xff, 0x7d, 0xe2, 0x8d, 0x82, 0x8c, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04,
-0x12, 0x21, 0xf3, 0xe0, 0x44, 0x80, 0xf0, 0x74, 0x6e, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f,
-0x00, 0x22, 0x12, 0x10, 0x03, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60,
-0x16, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xff, 0xc3, 0xe5, 0x3a, 0x9f, 0xe5, 0x39, 0x94, 0x00,
-0x40, 0x05, 0x12, 0x28, 0x16, 0x80, 0x03, 0x12, 0x31, 0xbd, 0x02, 0x10, 0x86, 0x90, 0xff, 0xfc,
-0xe0, 0x20, 0xe7, 0x1f, 0xc2, 0xaf, 0x7d, 0xff, 0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04,
-0x7f, 0x00, 0xef, 0x1f, 0xaa, 0x06, 0x70, 0x01, 0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4,
-0xf0, 0x80, 0xef, 0x22, 0x12, 0x10, 0x03, 0x78, 0x66, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0,
-0x12, 0x30, 0xe1, 0x0f, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x12, 0x19,
-0x12, 0x1d, 0x46, 0x02, 0x10, 0x86, 0x8e, 0x5f, 0x8f, 0x60, 0xe5, 0x60, 0x15, 0x60, 0xae, 0x5f,
-0x70, 0x02, 0x15, 0x5f, 0xd3, 0x94, 0x00, 0xee, 0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0,
-0x12, 0x0f, 0xdc, 0x80, 0xe5, 0x22, 0x11, 0x94, 0x2d, 0xf6, 0x23, 0xef, 0x31, 0xa3, 0x2f, 0xf4,
-0x2f, 0xa2, 0x30, 0xb2, 0x2e, 0xe6, 0x26, 0x6d, 0x2b, 0xaf, 0x30, 0x55, 0x30, 0x74, 0x1d, 0xb4,
-0x2e, 0x40, 0x2a, 0xe8, 0x0e, 0x12, 0x10, 0x03, 0x78, 0x86, 0x12, 0x22, 0x82, 0x20, 0xe1, 0x07,
-0x7f, 0x12, 0x12, 0x30, 0xec, 0x80, 0x0a, 0x78, 0x86, 0xe6, 0xff, 0x12, 0x23, 0x49, 0x12, 0x30,
-0xec, 0x02, 0x10, 0x86, 0x12, 0x10, 0x03, 0x78, 0x87, 0x12, 0x22, 0x82, 0x20, 0xe2, 0x07, 0x7f,
-0x11, 0x12, 0x30, 0xec, 0x80, 0x0a, 0x78, 0x87, 0xe6, 0xff, 0x12, 0x2e, 0x7d, 0x12, 0x30, 0xec,
-0x02, 0x10, 0x86, 0x8f, 0x61, 0x12, 0x2e, 0x7d, 0xaf, 0x61, 0x12, 0x2a, 0x06, 0x12, 0x22, 0x12,
-0x12, 0x31, 0xc7, 0x74, 0x6e, 0x25, 0x61, 0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x61, 0x12, 0x13,
-0x3f, 0x22, 0x12, 0x10, 0x03, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60,
-0x05, 0x12, 0x2c, 0x07, 0x80, 0x06, 0x12, 0x1d, 0x64, 0x12, 0x1d, 0x6c, 0x02, 0x10, 0x86, 0x12,
-0x29, 0x93, 0x12, 0x12, 0xbb, 0x90, 0xf8, 0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x12,
-0x58, 0x12, 0x29, 0x1d, 0x12, 0x12, 0xf7, 0x12, 0x11, 0x74, 0x80, 0xe3, 0x12, 0x1c, 0xde, 0xef,
-0x12, 0x1a, 0x4a, 0xe4, 0xf5, 0x33, 0xf5, 0x34, 0xef, 0x60, 0x03, 0x02, 0x31, 0xbd, 0xe4, 0xff,
-0x12, 0x31, 0xb1, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5,
-0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff,
-0x54, 0x28, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22,
-0xd3, 0x22, 0xef, 0x30, 0xe7, 0x08, 0x12, 0x1c, 0x95, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12,
-0x1c, 0xe8, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00,
-0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x7e, 0x12, 0x22,
-0x09, 0xa3, 0xa3, 0xe0, 0xff, 0x30, 0xe7, 0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85,
-0x3b, 0x39, 0x85, 0x3c, 0x3a, 0x90, 0xff, 0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f,
-0xf0, 0x22, 0xe4, 0xfe, 0xee, 0x90, 0x31, 0x47, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe,
-0x07, 0xf2, 0xc3, 0x22, 0x00, 0x08, 0x18, 0x28, 0x38, 0x01, 0x81, 0x10, 0x0a, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x12, 0x10, 0x03, 0x7f, 0x02, 0x12, 0x10, 0x92, 0x12, 0x1d, 0x46, 0x02, 0x10,
-0x86, 0x75, 0x39, 0x00, 0x8f, 0x3a, 0x12, 0x1c, 0x30, 0x12, 0x2c, 0x07, 0x22, 0x12, 0x1d, 0x6c,
-0x12, 0x1d, 0x2f, 0x12, 0x1d, 0x64, 0x22, 0xc2, 0x08, 0x22,
+0xe5, 0x54, 0x30, 0xe1, 0x01, 0x06, 0x78, 0x88, 0xe6, 0x12, 0x22, 0xe7, 0x90, 0x00, 0x0c, 0xef,
+0x12, 0x1a, 0xfa, 0x12, 0x22, 0xb5, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x53, 0x07, 0x0c,
+0x53, 0x06, 0xe6, 0xe5, 0x53, 0x30, 0xe5, 0x03, 0x43, 0x07, 0x01, 0xe5, 0x54, 0x20, 0xe5, 0x0e,
+0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7, 0x03, 0x43, 0x07, 0x02, 0xe5, 0x53,
+0x30, 0xe3, 0x03, 0x43, 0x07, 0x10, 0xe5, 0x53, 0x30, 0xe2, 0x03, 0x43, 0x07, 0x20, 0xe5, 0x53,
+0x54, 0x03, 0x60, 0x03, 0x43, 0x07, 0x40, 0xe5, 0x53, 0x30, 0xe1, 0x03, 0x43, 0x07, 0x80, 0xe5,
+0x53, 0x30, 0xe4, 0x03, 0x43, 0x06, 0x01, 0xe5, 0x53, 0x30, 0xe6, 0x03, 0x43, 0x06, 0x08, 0xe5,
+0x54, 0x20, 0xe4, 0x0e, 0xe5, 0x53, 0x54, 0x7f, 0x70, 0x08, 0xe5, 0x53, 0x20, 0xe7, 0x03, 0x43,
+0x06, 0x10, 0x53, 0x07, 0xfb, 0x53, 0x06, 0x79, 0x90, 0x00, 0x05, 0xee, 0x8f, 0xf0, 0x12, 0x1b,
+0x9f, 0xe5, 0x55, 0x30, 0xe3, 0x12, 0x54, 0x30, 0xff, 0xc4, 0x54, 0x0f, 0x12, 0x22, 0xe7, 0x90,
+0x00, 0x08, 0xef, 0x12, 0x1a, 0xfa, 0x80, 0x0a, 0x12, 0x22, 0xe8, 0x90, 0x00, 0x08, 0xe4, 0x12,
+0x1a, 0xfa, 0xe5, 0x55, 0x54, 0x03, 0x12, 0x22, 0xe7, 0x90, 0x00, 0x07, 0xef, 0x12, 0x1a, 0xfa,
+0xe5, 0x55, 0x54, 0x04, 0xff, 0xc3, 0x13, 0x90, 0x00, 0x09, 0x12, 0x1a, 0xfa, 0x90, 0x00, 0x07,
+0x12, 0x1a, 0xbb, 0x70, 0x13, 0x12, 0x22, 0xe8, 0xe9, 0x24, 0x09, 0xf9, 0xe4, 0x3a, 0xfa, 0x12,
+0x1a, 0xa2, 0xff, 0xc3, 0x13, 0x12, 0x1a, 0xe8, 0x12, 0x23, 0x27, 0x24, 0x08, 0x12, 0x22, 0xa1,
+0xe0, 0xfe, 0x8d, 0x82, 0x8c, 0x83, 0xe5, 0x82, 0x24, 0x07, 0x12, 0x22, 0xa1, 0xe0, 0xfd, 0xee,
+0xed, 0x12, 0x22, 0xe7, 0x90, 0x00, 0x03, 0xee, 0x8f, 0xf0, 0x12, 0x1b, 0x9f, 0x12, 0x32, 0x84,
+0x7d, 0x0a, 0xe4, 0xff, 0x12, 0x2f, 0xb4, 0x02, 0x10, 0xce, 0x90, 0xfa, 0xe6, 0xe0, 0xb4, 0x03,
+0x06, 0x7e, 0x00, 0x7f, 0x40, 0x80, 0x04, 0x7e, 0x00, 0x7f, 0x08, 0x90, 0xfa, 0xda, 0xee, 0xf0,
+0xa3, 0xef, 0xf0, 0x90, 0x00, 0x05, 0x12, 0x1a, 0xbb, 0xff, 0x7e, 0x00, 0x90, 0xfa, 0xd6, 0xee,
+0xf0, 0xa3, 0xef, 0xf0, 0x70, 0x03, 0x7f, 0x08, 0x22, 0x90, 0x00, 0x08, 0x12, 0x1b, 0x48, 0xff,
+0x90, 0xfa, 0xd8, 0xe5, 0xf0, 0xf0, 0xa3, 0xef, 0xf0, 0xae, 0x02, 0xaf, 0x01, 0x8e, 0x50, 0x8f,
+0x51, 0x74, 0x0a, 0x25, 0x51, 0xf5, 0x51, 0xe4, 0x35, 0x50, 0xf5, 0x50, 0x90, 0xfa, 0xdb, 0xe0,
+0xff, 0x14, 0xfe, 0x90, 0xfa, 0xd9, 0xe0, 0x5e, 0xfe, 0xc3, 0xef, 0x9e, 0xff, 0x90, 0xfa, 0xdd,
+0xf0, 0xc3, 0x90, 0xfa, 0xd7, 0xe0, 0x9f, 0x90, 0xfa, 0xd6, 0xe0, 0x94, 0x00, 0x50, 0x06, 0xa3,
+0xe0, 0x90, 0xfa, 0xdd, 0xf0, 0x12, 0x20, 0xa9, 0x60, 0x03, 0xe0, 0xff, 0x22, 0x12, 0x2e, 0x2b,
+0x90, 0xfa, 0xd6, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0x4e, 0x60, 0x2b, 0x90, 0xfa, 0xda, 0xe0, 0xfc,
+0xa3, 0xe0, 0xfd, 0xd3, 0xef, 0x9d, 0xee, 0x9c, 0x40, 0x07, 0xe0, 0x90, 0xfa, 0xdd, 0xf0, 0x80,
+0x08, 0x90, 0xfa, 0xd7, 0xe0, 0x90, 0xfa, 0xdd, 0xf0, 0x12, 0x20, 0xa9, 0x60, 0x03, 0xe0, 0xff,
+0x22, 0x12, 0x2e, 0x2b, 0x80, 0xca, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x52, 0xe4, 0xf5, 0x2d, 0xf5,
+0x2e, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x7f, 0x00, 0x22, 0xaa, 0x50, 0xa9, 0x51, 0x7b, 0x01, 0x90,
+0xfa, 0xd8, 0xe0, 0xfc, 0xa3, 0xe0, 0xfd, 0x90, 0xfa, 0xdd, 0xe0, 0xf5, 0x4a, 0x12, 0x29, 0x60,
+0x90, 0xfa, 0xdc, 0xef, 0xf0, 0x22, 0xef, 0x24, 0xae, 0x60, 0x52, 0x24, 0xfe, 0x60, 0x2e, 0x24,
+0xfe, 0x70, 0x03, 0x02, 0x21, 0x69, 0x24, 0x06, 0x60, 0x03, 0x02, 0x21, 0xb1, 0x78, 0x71, 0xe6,
+0x54, 0xfb, 0xf6, 0x90, 0xff, 0xa5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x33, 0x90, 0xfa,
+0x94, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xb2, 0x74, 0x01, 0xf0, 0x22, 0x78, 0x72, 0xe6,
+0x54, 0xfb, 0xf6, 0x90, 0xff, 0xb5, 0xe0, 0xf5, 0x22, 0x44, 0x0f, 0xf0, 0x74, 0x43, 0x90, 0xfa,
+0x96, 0xf0, 0xe5, 0x22, 0xa3, 0xf0, 0x90, 0xfa, 0xb3, 0x74, 0x01, 0xf0, 0x22, 0x90, 0xfa, 0xa0,
+0xe0, 0xa3, 0x20, 0xe5, 0x03, 0x02, 0x21, 0xb1, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xcd, 0xf0,
+0xa3, 0xf0, 0x90, 0xfa, 0xcd, 0xe0, 0xff, 0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xa6, 0x12,
+0x23, 0x0d, 0x90, 0xff, 0xa6, 0xe0, 0x90, 0xfa, 0xcd, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xce, 0xe0,
+0xff, 0x74, 0x34, 0xfe, 0x12, 0x2d, 0x85, 0xef, 0x70, 0x57, 0x90, 0xfa, 0xce, 0xe0, 0xff, 0x74,
+0x34, 0x90, 0xfa, 0x98, 0xf0, 0xef, 0xa3, 0xf0, 0x22, 0x90, 0xfa, 0xaa, 0xe0, 0xa3, 0x30, 0xe5,
+0x40, 0x90, 0xff, 0xb6, 0xe0, 0x90, 0xfa, 0xcd, 0xf0, 0xa3, 0xf0, 0x90, 0xfa, 0xcd, 0xe0, 0xff,
+0x54, 0x0f, 0xfe, 0x60, 0x10, 0x90, 0xff, 0xb6, 0x12, 0x23, 0x0d, 0x90, 0xff, 0xb6, 0xe0, 0x90,
+0xfa, 0xcd, 0xf0, 0x80, 0xe6, 0x90, 0xfa, 0xce, 0xe0, 0xff, 0x74, 0x44, 0xfe, 0x12, 0x2d, 0x85,
+0xef, 0x70, 0x0e, 0x90, 0xfa, 0xce, 0xe0, 0xff, 0x74, 0x44, 0x90, 0xfa, 0x9a, 0xf0, 0xef, 0xa3,
+0xf0, 0x22, 0xc0, 0xe0, 0xc0, 0xf0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0xd0, 0x75, 0xd0, 0x00, 0xc0,
+0x00, 0xc0, 0x01, 0xc0, 0x02, 0xc0, 0x03, 0xc0, 0x04, 0xc0, 0x05, 0xc0, 0x06, 0xc0, 0x07, 0x90,
+0xff, 0x92, 0xe0, 0xff, 0x90, 0xfa, 0xcc, 0xf0, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0xef, 0x12, 0x1b,
+0xfc, 0x22, 0x69, 0x26, 0x22, 0x69, 0x2e, 0x22, 0x0c, 0x30, 0x22, 0x0c, 0x32, 0x22, 0x1a, 0x38,
+0x22, 0x2c, 0x3a, 0x22, 0x5e, 0x3e, 0x22, 0x49, 0x44, 0x22, 0x3e, 0x46, 0x22, 0x54, 0x50, 0x22,
+0x54, 0x52, 0x22, 0x54, 0x54, 0x22, 0x54, 0x56, 0x00, 0x00, 0x22, 0x6e, 0x90, 0xfa, 0xcc, 0xe0,
+0xfd, 0x7c, 0x00, 0x7f, 0x01, 0x12, 0x11, 0x5e, 0x80, 0x62, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x03,
+0x12, 0x11, 0x5e, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x20, 0xf0, 0x80, 0x50, 0x7c, 0x00, 0x7d, 0x01,
+0x7f, 0x02, 0x12, 0x11, 0x5e, 0x90, 0xff, 0xfe, 0xe0, 0x44, 0x40, 0xf0, 0x80, 0x3e, 0x7c, 0x00,
+0x7d, 0x01, 0x7f, 0x05, 0x12, 0x11, 0x5e, 0x80, 0x33, 0x7c, 0x00, 0x7d, 0x01, 0x7f, 0x06, 0x12,
+0x11, 0x5e, 0x80, 0x28, 0x90, 0xfa, 0xcc, 0xe0, 0xff, 0x12, 0x20, 0xc6, 0x80, 0x1e, 0x7c, 0x00,
+0x7d, 0x01, 0x7f, 0x04, 0x12, 0x11, 0x5e, 0x80, 0x13, 0x12, 0x28, 0x4e, 0x80, 0x0e, 0x90, 0xfa,
+0xcc, 0xe0, 0x24, 0x00, 0xff, 0xe4, 0x34, 0xff, 0xfe, 0x12, 0x2d, 0x85, 0xd0, 0x07, 0xd0, 0x06,
+0xd0, 0x05, 0xd0, 0x04, 0xd0, 0x03, 0xd0, 0x02, 0xd0, 0x01, 0xd0, 0x00, 0xd0, 0xd0, 0xd0, 0x82,
+0xd0, 0x83, 0xd0, 0xf0, 0xd0, 0xe0, 0x32, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0x24, 0x04, 0x8e,
+0x83, 0xf5, 0x82, 0xe4, 0x35, 0x83, 0xf5, 0x83, 0x22, 0x74, 0x13, 0x25, 0x24, 0xf5, 0x82, 0xe4,
+0x34, 0xf9, 0xf5, 0x83, 0x22, 0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0x22,
+0x78, 0x80, 0xe6, 0xfe, 0x08, 0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0x7b, 0xff, 0x7a,
+0x32, 0x79, 0x56, 0x7e, 0x00, 0x7f, 0x0a, 0x02, 0x1a, 0x7c, 0x78, 0x80, 0xe6, 0xfc, 0x08, 0xe6,
+0xf5, 0x82, 0x8c, 0x83, 0xa3, 0xa3, 0x22, 0xff, 0x90, 0xf9, 0x6f, 0x02, 0x1b, 0xea, 0x90, 0xf9,
+0x6a, 0x12, 0x1b, 0xea, 0x90, 0x00, 0x04, 0x02, 0x1a, 0xbb, 0x78, 0x7e, 0xe6, 0xfe, 0x08, 0xe6,
+0xff, 0x22, 0xed, 0x12, 0x1a, 0xfa, 0x8f, 0x82, 0x8e, 0x83, 0xe5, 0x82, 0x22, 0xef, 0xf0, 0x90,
+0xfa, 0xce, 0xe0, 0x54, 0x0f, 0x4e, 0xfe, 0xf0, 0xef, 0x54, 0xf0, 0x4e, 0xf0, 0x22, 0x78, 0x80,
+0xe6, 0xfc, 0x08, 0xe6, 0x8c, 0x83, 0x22, 0x78, 0x7e, 0xe6, 0xfc, 0x08, 0xe6, 0xfd, 0x8c, 0x83,
+0x22, 0xa6, 0x07, 0xe6, 0x24, 0x6e, 0xf8, 0xe6, 0x22, 0x78, 0x7e, 0xe6, 0xfa, 0x08, 0xe6, 0xfb,
+0x22, 0x08, 0xe6, 0xfe, 0x08, 0xe6, 0x8e, 0x83, 0x22, 0x26, 0xf6, 0x18, 0xee, 0x36, 0xf6, 0x22,
+0xef, 0x24, 0x0b, 0xf5, 0x82, 0xe4, 0x3e, 0xf5, 0x83, 0x22, 0x8b, 0x82, 0x8a, 0x83, 0xe5, 0x82,
+0x22, 0x8b, 0x25, 0x8a, 0x26, 0x89, 0x27, 0x8d, 0x28, 0x90, 0xfa, 0xd2, 0xe4, 0xf0, 0xa3, 0x74,
+0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xd1, 0x90, 0xfa, 0xd2, 0xe0, 0xf5, 0x2d, 0xa3, 0xe0,
+0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x90, 0xfa, 0xd1, 0xe0, 0x65, 0x28, 0x60, 0x46, 0xa3,
+0xe0, 0xff, 0xa3, 0xe0, 0xa3, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x12, 0x23, 0xf0, 0x90, 0xfa, 0xd1,
+0xe0, 0xff, 0x90, 0xfa, 0xd4, 0xe4, 0x8f, 0xf0, 0x12, 0x1b, 0x1c, 0x12, 0x23, 0xf0, 0x90, 0xfa,
+0xd4, 0xe0, 0xff, 0xa3, 0xe0, 0x90, 0xfa, 0xd2, 0xcf, 0xf0, 0xa3, 0xef, 0xf0, 0x90, 0xfa, 0xd1,
+0xe0, 0xa3, 0x75, 0xf0, 0x00, 0x12, 0x1b, 0x1c, 0x90, 0xfa, 0xd2, 0xe4, 0x75, 0xf0, 0x04, 0x12,
+0x1b, 0x1c, 0x02, 0x23, 0x72, 0x90, 0xfa, 0xd3, 0xe0, 0x24, 0x01, 0xff, 0x90, 0xfa, 0xd2, 0xe0,
+0x34, 0x00, 0xab, 0x25, 0xaa, 0x26, 0xa9, 0x27, 0x8f, 0xf0, 0x12, 0x1b, 0x80, 0x7f, 0x00, 0x22,
+0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xd1, 0x90, 0xfa, 0xd2, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1b, 0x1c,
+0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x02, 0x26, 0x98, 0x8f, 0x62, 0x12, 0x2a, 0xc7, 0x12,
+0x22, 0xfa, 0x8e, 0x83, 0x24, 0x0b, 0x12, 0x22, 0xa1, 0xe0, 0x54, 0xfb, 0xf0, 0x44, 0x02, 0xf0,
+0x08, 0x12, 0x22, 0xdc, 0xe0, 0xa3, 0x30, 0xe5, 0x0c, 0x12, 0x23, 0x06, 0x24, 0x0b, 0x12, 0x22,
+0xa1, 0xe0, 0x44, 0x01, 0xf0, 0x78, 0x7c, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0xf5, 0x82, 0x8e, 0x83,
+0xe0, 0x54, 0xb8, 0xfd, 0xf0, 0xe5, 0x62, 0x24, 0xfe, 0x44, 0x20, 0xfc, 0x4d, 0xf0, 0xe5, 0x82,
+0x24, 0x04, 0x12, 0x22, 0xa1, 0xe0, 0x54, 0xb8, 0xf0, 0x4c, 0xf0, 0x8f, 0x82, 0x8e, 0x83, 0xa3,
+0x74, 0x03, 0xf0, 0x18, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x8e, 0x83, 0x24, 0x05, 0x12, 0x22, 0xa1,
+0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfd, 0x74, 0x99, 0x25, 0x62, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5,
+0x83, 0xe0, 0x54, 0xfc, 0x44, 0x03, 0xfc, 0xed, 0x4c, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x8f, 0x82,
+0x8e, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x22, 0xa1, 0xe0, 0x44, 0x80,
+0xf0, 0x12, 0x32, 0x84, 0x74, 0x6e, 0x25, 0x62, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22,
+0x12, 0x10, 0x4b, 0x7f, 0x02, 0x12, 0x12, 0x61, 0x78, 0x67, 0xe6, 0x44, 0x02, 0xf6, 0xd2, 0xb0,
+0xd2, 0xb1, 0x90, 0xf9, 0x16, 0xe0, 0x30, 0xe7, 0x07, 0x90, 0xff, 0x9e, 0xe4, 0xf0, 0x80, 0x36,
+0xd2, 0xb3, 0x90, 0xff, 0xa4, 0xe0, 0x90, 0xfa, 0x7e, 0xf0, 0x90, 0xff, 0xb4, 0xe0, 0x90, 0xfa,
+0x7f, 0xf0, 0x90, 0xff, 0xa2, 0xe0, 0x90, 0xfa, 0x7c, 0xf0, 0x90, 0xff, 0xb2, 0xe0, 0x90, 0xfa,
+0x7d, 0xf0, 0x90, 0xff, 0xa4, 0x74, 0x30, 0xf0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xff, 0xa2, 0x74,
+0x40, 0xf0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xfa, 0xe7, 0xe5, 0xa8, 0xf0, 0x75, 0xa8, 0x81, 0x90,
+0xff, 0x92, 0xe0, 0x60, 0x04, 0xe4, 0xf0, 0x80, 0xf6, 0x90, 0xff, 0xfd, 0x74, 0x3a, 0xf0, 0x43,
+0x87, 0x01, 0x00, 0x00, 0x00, 0x90, 0xfa, 0x7e, 0xe0, 0x90, 0xff, 0xa4, 0xf0, 0x90, 0xfa, 0x7f,
+0xe0, 0x90, 0xff, 0xb4, 0xf0, 0x90, 0xfa, 0x7c, 0xe0, 0x90, 0xff, 0xa2, 0xf0, 0x90, 0xfa, 0x7d,
+0xe0, 0x90, 0xff, 0xb2, 0xf0, 0x90, 0xf9, 0x18, 0xe0, 0x60, 0x02, 0xc2, 0xb3, 0x90, 0xfa, 0xe7,
+0xe0, 0xf5, 0xa8, 0x02, 0x10, 0xce, 0x8b, 0x5c, 0x8a, 0x5d, 0x89, 0x5e, 0x12, 0x2e, 0x0d, 0x90,
+0xfa, 0xc3, 0x12, 0x1b, 0xf3, 0xaa, 0x5d, 0xa9, 0x5e, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0xf3, 0x90,
+0xfa, 0xc7, 0xe4, 0x75, 0xf0, 0x0a, 0x12, 0x1b, 0x1c, 0x90, 0xfa, 0xc6, 0x12, 0x1b, 0xea, 0xe9,
+0x24, 0x01, 0xf9, 0xe4, 0x3a, 0xfa, 0x90, 0xfa, 0xc9, 0x12, 0x1b, 0xf3, 0xab, 0x5c, 0xaa, 0x5d,
+0xa9, 0x5e, 0x12, 0x2e, 0x19, 0xe0, 0xff, 0xc3, 0x13, 0xf0, 0xe4, 0x78, 0x82, 0xf6, 0x90, 0xfa,
+0xc1, 0xe0, 0xff, 0x78, 0x82, 0xe6, 0xc3, 0x9f, 0x50, 0x4a, 0x90, 0xfa, 0xc3, 0x12, 0x2d, 0xee,
+0xff, 0x78, 0x83, 0xf6, 0x90, 0xfa, 0xc6, 0x12, 0x2d, 0xee, 0xfe, 0xf4, 0x5f, 0xff, 0x78, 0x83,
+0xf6, 0x12, 0x2d, 0xeb, 0x5e, 0x4f, 0xff, 0x78, 0x83, 0xf6, 0x12, 0x2d, 0xf4, 0x75, 0xf0, 0x02,
+0x12, 0x1b, 0x1c, 0x90, 0xfa, 0xc7, 0xe4, 0x75, 0xf0, 0x02, 0x12, 0x1b, 0x1c, 0xab, 0x5c, 0xaa,
+0x5d, 0xa9, 0x5e, 0x90, 0x00, 0x04, 0x12, 0x1a, 0xbb, 0x30, 0xe4, 0x03, 0x12, 0x2e, 0x03, 0x78,
+0x82, 0x06, 0x80, 0xaa, 0xe4, 0x90, 0xfa, 0xc2, 0xf0, 0x22, 0x8b, 0x56, 0x8a, 0x57, 0x89, 0x58,
+0x90, 0xfa, 0xc2, 0x74, 0x06, 0xf0, 0xe4, 0x90, 0xfa, 0xc1, 0xf0, 0x12, 0x1a, 0xa2, 0x24, 0x6e,
+0x60, 0x26, 0x14, 0x70, 0x70, 0x12, 0x2d, 0xda, 0x60, 0x09, 0x24, 0x30, 0x70, 0x12, 0x12, 0x25,
+0x56, 0x80, 0x62, 0x12, 0x2e, 0x24, 0x12, 0x1f, 0xda, 0x90, 0xfa, 0xc2, 0xef, 0xf0, 0x80, 0x55,
+0x90, 0xfa, 0xc2, 0x74, 0x81, 0xf0, 0x80, 0x4d, 0x12, 0x2d, 0xda, 0x60, 0x09, 0x24, 0x30, 0x70,
+0x3e, 0x12, 0x2d, 0x30, 0x80, 0x3f, 0xe5, 0x58, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x57, 0xfa, 0x7b,
+0x01, 0xc0, 0x03, 0xc0, 0x02, 0xc0, 0x01, 0x12, 0x2e, 0x24, 0x90, 0x00, 0x05, 0x12, 0x1a, 0xbb,
+0xfd, 0x90, 0x00, 0x08, 0x12, 0x1b, 0x48, 0xf5, 0x2e, 0x85, 0xf0, 0x2d, 0xd0, 0x01, 0xd0, 0x02,
+0xd0, 0x03, 0x12, 0x26, 0x98, 0x90, 0xfa, 0xc1, 0xef, 0xf0, 0xe4, 0xa3, 0xf0, 0x80, 0x06, 0x90,
+0xfa, 0xc2, 0x74, 0x81, 0xf0, 0x90, 0xfa, 0xc2, 0xe0, 0x12, 0x2e, 0x24, 0x90, 0x00, 0x02, 0x12,
+0x1a, 0xfa, 0x90, 0xfa, 0xc1, 0xe0, 0xff, 0x22, 0x8b, 0x29, 0x8a, 0x2a, 0x89, 0x2b, 0x8d, 0x2c,
+0xe5, 0x2c, 0x70, 0x03, 0xaf, 0x2c, 0x22, 0x12, 0x2e, 0x53, 0x70, 0x16, 0x12, 0x2e, 0x72, 0xe5,
+0x2d, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0xd8, 0x50, 0xf2, 0x12, 0x27, 0x25, 0x40, 0x0b, 0x7f,
+0x00, 0x22, 0x12, 0x2e, 0x72, 0x12, 0x27, 0x25, 0x50, 0xf8, 0x90, 0xff, 0xf3, 0x74, 0xa1, 0xf0,
+0xe5, 0x2c, 0xb4, 0x01, 0x07, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0xf1, 0xe4,
+0xf0, 0xf5, 0x2f, 0xe5, 0x2c, 0x14, 0xff, 0xe5, 0x2f, 0xc3, 0x9f, 0x50, 0x2a, 0x12, 0x31, 0xc1,
+0x40, 0x03, 0xaf, 0x2f, 0x22, 0xc3, 0xe5, 0x2c, 0x95, 0x2f, 0xff, 0xbf, 0x02, 0x07, 0x90, 0xff,
+0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x12, 0x2e, 0x65, 0x05, 0x2f, 0x74, 0x01, 0x25, 0x2b, 0xf5, 0x2b,
+0xe4, 0x35, 0x2a, 0xf5, 0x2a, 0x80, 0xcc, 0x12, 0x31, 0xc1, 0x40, 0x03, 0x7f, 0x18, 0x22, 0x12,
+0x2e, 0x65, 0xaf, 0x2c, 0x22, 0x90, 0xff, 0xf1, 0xe5, 0x2e, 0xf0, 0x02, 0x31, 0xd8, 0x12, 0x10,
+0x4b, 0x78, 0x84, 0x12, 0x23, 0x31, 0x30, 0xe1, 0x08, 0x7f, 0x13, 0x12, 0x31, 0xa9, 0x02, 0x27,
+0xbc, 0x78, 0x84, 0xe6, 0xf9, 0x24, 0x13, 0x12, 0x22, 0xad, 0xe0, 0xff, 0x30, 0xe7, 0x40, 0x54,
+0x03, 0x60, 0x1e, 0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x44,
+0x04, 0xf0, 0x80, 0x46, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfd, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x80,
+0x39, 0xe9, 0xb4, 0x03, 0x0d, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xfb, 0xf0, 0xe0, 0x44, 0x01, 0xf0,
+0x80, 0x28, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf7, 0xf0, 0xe0, 0x44, 0x02, 0xf0, 0x80, 0x1b, 0xef,
+0x54, 0x03, 0x60, 0x14, 0xe9, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x54, 0xdf, 0xf0, 0x80,
+0x07, 0x90, 0xff, 0xb4, 0xe0, 0x54, 0xdf, 0xf0, 0xc2, 0xb3, 0x90, 0xf9, 0x18, 0xe0, 0x04, 0xf0,
+0xaf, 0x01, 0x12, 0x22, 0xee, 0xfd, 0x12, 0x2f, 0xe5, 0x12, 0x31, 0xa9, 0x02, 0x10, 0xce, 0x75,
+0xa8, 0x40, 0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x8b, 0x02, 0x28, 0x09, 0x02, 0x31,
+0x8c, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2, 0x08, 0xdf,
+0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33, 0xc4, 0x54,
+0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf, 0xe4, 0x80,
+0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x2b, 0xa9, 0xe4, 0x7e, 0x01, 0x93,
+0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93, 0xa3, 0x60,
+0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3, 0xfa, 0xe4,
+0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xf0, 0xa3,
+0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe, 0xe4, 0xf5,
+0x22, 0x12, 0x1d, 0xc2, 0xe0, 0xb4, 0x04, 0x0d, 0xe5, 0x22, 0x24, 0x03, 0xff, 0x12, 0x30, 0x13,
+0x12, 0x1d, 0xc2, 0xe4, 0xf0, 0x05, 0x22, 0xe5, 0x22, 0xc3, 0x94, 0x02, 0x40, 0xe3, 0xe4, 0xf5,
+0x22, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x94, 0x12, 0x1e, 0x03, 0x60, 0x2c, 0x12, 0x2d,
+0x85, 0xef, 0x60, 0x52, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90, 0xfa, 0x94, 0x12, 0x1b, 0xcc, 0xe4,
+0xf0, 0xa3, 0xf0, 0x75, 0xf0, 0x0a, 0xe5, 0x22, 0x90, 0xfa, 0xa0, 0x12, 0x1b, 0xcc, 0xe0, 0xa3,
+0x30, 0xe6, 0x33, 0x12, 0x1d, 0xc2, 0x74, 0x04, 0xf0, 0x22, 0x75, 0xf0, 0x02, 0xe5, 0x22, 0x90,
+0xfa, 0x98, 0x12, 0x1e, 0x03, 0x60, 0x16, 0x12, 0x2d, 0x85, 0xef, 0x60, 0x19, 0x75, 0xf0, 0x02,
+0xe5, 0x22, 0x90, 0xfa, 0x98, 0x12, 0x1b, 0xcc, 0xe4, 0xf0, 0xa3, 0xf0, 0x22, 0x05, 0x22, 0xe5,
+0x22, 0xc3, 0x94, 0x02, 0x40, 0x9b, 0x22, 0xe4, 0xff, 0x90, 0xff, 0x83, 0xe0, 0x54, 0x0f, 0xfe,
+0xef, 0xc3, 0x9e, 0x50, 0x17, 0x74, 0xf0, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83, 0xe0,
+0x12, 0x1c, 0xc1, 0x12, 0x1a, 0xe8, 0x0f, 0x12, 0x1c, 0xb0, 0x80, 0xdd, 0xef, 0xfd, 0xc3, 0xe5,
+0x3a, 0x9d, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5, 0x39, 0xd3, 0xe5, 0x3a, 0x94, 0x00, 0xe5,
+0x39, 0x94, 0x00, 0x40, 0x06, 0xe4, 0x90, 0xff, 0x83, 0xf0, 0x22, 0x12, 0x1d, 0xdf, 0x12, 0x1e,
+0x34, 0x12, 0x1e, 0x26, 0x12, 0x1a, 0xa2, 0x24, 0x6e, 0x60, 0x1e, 0x14, 0x60, 0x1b, 0x24, 0x8e,
+0x70, 0x2d, 0x90, 0x00, 0x01, 0x12, 0x1a, 0xbb, 0xff, 0x24, 0xfc, 0x60, 0x03, 0x04, 0x70, 0x1f,
+0xef, 0xfd, 0x7c, 0x00, 0x7f, 0x0d, 0x02, 0x11, 0x5e, 0x12, 0x1e, 0x3b, 0x12, 0x25, 0xfa, 0x12,
+0x1d, 0x89, 0x12, 0x1a, 0xbb, 0x60, 0x03, 0x02, 0x32, 0x7a, 0xe4, 0xff, 0x12, 0x32, 0x6e, 0x22,
+0x8b, 0x45, 0x8a, 0x46, 0x89, 0x47, 0x8c, 0x48, 0x8d, 0x49, 0xd2, 0x00, 0x12, 0x2e, 0x53, 0x70,
+0x16, 0x12, 0x2e, 0x72, 0xe5, 0x48, 0x90, 0xff, 0xf1, 0xf0, 0x12, 0x31, 0xd8, 0x50, 0xf2, 0x12,
+0x29, 0xd5, 0x40, 0x0b, 0x7f, 0x18, 0x22, 0x12, 0x2e, 0x72, 0x12, 0x29, 0xd5, 0x50, 0xf8, 0xe4,
+0xf5, 0x4b, 0xe5, 0x4a, 0x14, 0xff, 0xe5, 0x4b, 0xc3, 0x9f, 0x50, 0x17, 0x12, 0x29, 0xc5, 0x40,
+0x03, 0x7f, 0x18, 0x22, 0x05, 0x4b, 0x74, 0x01, 0x25, 0x47, 0xf5, 0x47, 0xe4, 0x35, 0x46, 0xf5,
+0x46, 0x80, 0xdf, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x01, 0xf0, 0x12, 0x29, 0xc5, 0x40, 0x03, 0x7f,
+0x18, 0x22, 0x7f, 0x00, 0x22, 0xab, 0x45, 0xaa, 0x46, 0xa9, 0x47, 0x12, 0x1a, 0xa2, 0x90, 0xff,
+0xf1, 0xf0, 0x02, 0x31, 0xd8, 0x90, 0xff, 0xf1, 0xe5, 0x49, 0xf0, 0x02, 0x31, 0xd8, 0x7b, 0x01,
+0x7a, 0xfa, 0x79, 0xcf, 0xe4, 0xfd, 0x12, 0x23, 0x61, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x09,
+0x12, 0x1b, 0x1c, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23, 0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x01,
+0x12, 0x1b, 0x32, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x90, 0xff, 0xf7,
+0xe5, 0x23, 0x12, 0x2a, 0x39, 0x90, 0xff, 0xf6, 0xe5, 0x23, 0xf0, 0x90, 0xfa, 0xcf, 0xe4, 0xf0,
+0xa3, 0x74, 0x06, 0x12, 0x2a, 0x39, 0xe5, 0x23, 0x30, 0xe0, 0x07, 0x90, 0xff, 0xfc, 0x74, 0x94,
+0xf0, 0x22, 0x90, 0xff, 0xfc, 0x74, 0x90, 0xf0, 0x22, 0xf0, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x23,
+0x90, 0xfa, 0xcf, 0xe4, 0x75, 0xf0, 0x01, 0x12, 0x1b, 0x32, 0x85, 0xf0, 0x2e, 0xf5, 0x2d, 0x7d,
+0x01, 0x02, 0x26, 0x98, 0x90, 0xff, 0x93, 0x74, 0x81, 0xf0, 0x90, 0xff, 0xff, 0xe0, 0x60, 0x06,
+0x90, 0xff, 0xfc, 0x74, 0x10, 0xf0, 0x90, 0xff, 0x91, 0xe0, 0x44, 0x90, 0xf0, 0xe4, 0x90, 0xf9,
+0x16, 0xf0, 0xa3, 0xf0, 0x12, 0x2b, 0x39, 0x12, 0x16, 0xc9, 0x12, 0x30, 0x69, 0x7e, 0x07, 0x7f,
+0xd0, 0x12, 0x12, 0x2a, 0x7e, 0x0f, 0x7f, 0xa0, 0x12, 0x12, 0x44, 0xe4, 0x78, 0x77, 0xf6, 0x78,
+0x77, 0xe6, 0xff, 0xc3, 0x94, 0x06, 0x50, 0x0b, 0x74, 0x6e, 0x2f, 0xf8, 0xe4, 0xf6, 0x78, 0x77,
+0x06, 0x80, 0xec, 0x7f, 0x03, 0x12, 0x30, 0xb2, 0x90, 0xf9, 0x16, 0xe0, 0x20, 0xe4, 0x05, 0x7f,
+0x04, 0x12, 0x30, 0xb2, 0x90, 0xff, 0x9b, 0xe4, 0xf0, 0x90, 0xff, 0x9a, 0xf0, 0x90, 0xff, 0xe8,
+0xe0, 0x54, 0x1f, 0xf0, 0xd2, 0xa8, 0x22, 0x15, 0x65, 0xa8, 0x65, 0xa6, 0x07, 0x30, 0x08, 0x05,
+0x12, 0x11, 0xae, 0x80, 0xf8, 0xd2, 0x08, 0xa8, 0x65, 0xe6, 0xff, 0xb4, 0x03, 0x0f, 0x78, 0x7c,
+0x76, 0xff, 0x08, 0x76, 0xe0, 0x08, 0x76, 0xff, 0x08, 0x76, 0xa0, 0x80, 0x0d, 0x78, 0x7c, 0x76,
+0xff, 0x08, 0x76, 0xe2, 0x08, 0x76, 0xff, 0x08, 0x76, 0xb0, 0x78, 0x80, 0x76, 0xfa, 0x08, 0x76,
+0x9e, 0xef, 0x24, 0xfd, 0x75, 0xf0, 0x0a, 0xa4, 0xae, 0xf0, 0x12, 0x23, 0x49, 0x7b, 0x01, 0x7a,
+0xff, 0x79, 0x48, 0x78, 0x68, 0x12, 0x1b, 0xe1, 0xa8, 0x65, 0xe6, 0x24, 0xfd, 0x75, 0xf0, 0x08,
+0xa4, 0xff, 0xae, 0xf0, 0x78, 0x6a, 0x12, 0x23, 0x49, 0x79, 0x08, 0x78, 0x6b, 0x12, 0x1b, 0xe1,
+0x78, 0x6d, 0xef, 0x12, 0x23, 0x49, 0x05, 0x65, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xab, 0xf0,
+0xe0, 0x44, 0x20, 0xf0, 0x90, 0xfa, 0xe6, 0x74, 0x02, 0xf0, 0x7b, 0x01, 0x7a, 0xfa, 0x79, 0xcf,
+0xe4, 0xf5, 0x2d, 0xf5, 0x2e, 0x7d, 0x01, 0x12, 0x26, 0x98, 0x7e, 0x00, 0x90, 0xfa, 0xe4, 0xee,
+0xf0, 0xa3, 0xef, 0xf0, 0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcf, 0xe0, 0xb4, 0x52, 0x09, 0x90,
+0xf9, 0x16, 0xe0, 0x54, 0xef, 0xf0, 0x80, 0x29, 0x90, 0xfa, 0xe4, 0xe0, 0x70, 0x04, 0xa3, 0xe0,
+0x64, 0x01, 0x70, 0x10, 0x90, 0xfa, 0xcf, 0xe0, 0xb4, 0x10, 0x09, 0x90, 0xf9, 0x16, 0xe0, 0x44,
+0x10, 0xf0, 0x80, 0x0d, 0x90, 0xfa, 0xe6, 0x74, 0x03, 0xf0, 0x90, 0xf9, 0x16, 0xe0, 0x54, 0xef,
+0xf0, 0x90, 0xff, 0xf0, 0xe0, 0x44, 0x20, 0xf0, 0x22, 0x03, 0x68, 0x01, 0xff, 0x48, 0x03, 0x6b,
+0x01, 0xff, 0x08, 0x02, 0x66, 0x00, 0x00, 0x44, 0xfa, 0x98, 0x00, 0x00, 0x00, 0x00, 0x44, 0xfa,
+0x94, 0x00, 0x00, 0x00, 0x00, 0x42, 0xfa, 0xb2, 0x00, 0x00, 0x42, 0xfa, 0x7e, 0x00, 0x00, 0x42,
+0xfa, 0x7c, 0x00, 0x00, 0x42, 0xf9, 0x6d, 0xff, 0xff, 0x42, 0xfa, 0x7a, 0x00, 0x00, 0x41, 0xf9,
+0x66, 0xff, 0x41, 0xf9, 0x1c, 0x19, 0x41, 0xf9, 0x15, 0x00, 0x43, 0xf9, 0x19, 0x0a, 0x32, 0x02,
+0x41, 0xf9, 0x68, 0x20, 0x41, 0xf9, 0x69, 0x20, 0x41, 0xf9, 0x65, 0x00, 0x41, 0xf9, 0x67, 0x00,
+0x44, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf9, 0x16, 0x00, 0x00, 0x41, 0xf9, 0x18, 0x00,
+0x01, 0x20, 0x00, 0x41, 0xf8, 0x04, 0x00, 0x00, 0x12, 0x10, 0x4b, 0x78, 0x8a, 0xef, 0xf6, 0x12,
+0x2a, 0xc7, 0x12, 0x22, 0xee, 0x30, 0xe0, 0x29, 0x78, 0x7c, 0x12, 0x22, 0xb7, 0xe0, 0x54, 0x7f,
+0xf0, 0x78, 0x6b, 0x12, 0x1b, 0xd8, 0x90, 0x00, 0x02, 0x12, 0x1a, 0xbb, 0x30, 0xe7, 0x09, 0x90,
+0x00, 0x02, 0xe4, 0x12, 0x1a, 0xfa, 0x80, 0xe9, 0x78, 0x7c, 0x12, 0x22, 0xb7, 0xe0, 0x44, 0x80,
+0xf0, 0x12, 0x22, 0xee, 0x30, 0xe1, 0x1e, 0x12, 0x22, 0x97, 0xe0, 0x54, 0x7f, 0xf0, 0x12, 0x32,
+0x19, 0x78, 0x68, 0x12, 0x1b, 0xd8, 0x90, 0x00, 0x02, 0x74, 0x80, 0x12, 0x1a, 0xfa, 0x12, 0x22,
+0x97, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x32, 0x84, 0xe4, 0xff, 0x12, 0x31, 0xa9, 0x02, 0x10, 0xce,
+0x12, 0x10, 0x4b, 0x78, 0x85, 0xef, 0xf6, 0x12, 0x31, 0x50, 0x12, 0x31, 0xa9, 0x78, 0x85, 0xe6,
+0xff, 0x24, 0x13, 0x12, 0x22, 0xad, 0xe0, 0xfe, 0x30, 0xe7, 0x16, 0xef, 0xb4, 0x03, 0x09, 0x90,
+0xff, 0x9e, 0xe0, 0x54, 0xfa, 0xf0, 0x80, 0x22, 0x90, 0xff, 0x9e, 0xe0, 0x54, 0xf5, 0xf0, 0x80,
+0x19, 0xee, 0x54, 0x03, 0x60, 0x14, 0xef, 0xb4, 0x03, 0x09, 0x90, 0xff, 0xa4, 0xe0, 0x44, 0x20,
+0xf0, 0x80, 0x07, 0x90, 0xff, 0xb4, 0xe0, 0x44, 0x20, 0xf0, 0x90, 0xf9, 0x18, 0xe0, 0x14, 0xf0,
+0xe0, 0x70, 0x02, 0xd2, 0xb3, 0x02, 0x10, 0xce, 0x12, 0x1e, 0x1c, 0xe5, 0x3a, 0x64, 0x09, 0x70,
+0x04, 0xe5, 0x39, 0x64, 0x01, 0x60, 0x48, 0xc3, 0xe5, 0x3a, 0x94, 0x08, 0xe5, 0x39, 0x94, 0x00,
+0x40, 0x11, 0x7f, 0x08, 0xef, 0xe5, 0x3a, 0x94, 0x08, 0xf5, 0x3a, 0xe5, 0x39, 0x94, 0x00, 0xf5,
+0x39, 0x80, 0x05, 0xaf, 0x3a, 0x12, 0x1e, 0x34, 0xe4, 0xfe, 0xee, 0xc3, 0x9f, 0x50, 0x19, 0x12,
+0x1c, 0xc1, 0x12, 0x1a, 0xa2, 0xfd, 0x74, 0xf8, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfe, 0xf5, 0x83,
+0xed, 0xf0, 0x0e, 0x12, 0x1c, 0xb0, 0x80, 0xe2, 0xef, 0x54, 0x7f, 0x90, 0xff, 0x81, 0xf0, 0x22,
+0x8b, 0x59, 0x8a, 0x5a, 0x89, 0x5b, 0x12, 0x2e, 0x19, 0x70, 0x05, 0xa3, 0x74, 0x08, 0xf0, 0x22,
+0xab, 0x59, 0xaa, 0x5a, 0xa9, 0x5b, 0x12, 0x2e, 0x0d, 0x90, 0xfa, 0xc9, 0x12, 0x1b, 0xf3, 0xe5,
+0x5b, 0x24, 0x03, 0xf9, 0xe4, 0x35, 0x5a, 0xfa, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0xf3, 0xe4, 0x90,
+0xfa, 0xc2, 0xf0, 0x78, 0x8b, 0xf6, 0x90, 0xfa, 0xc1, 0xe0, 0xff, 0x78, 0x8b, 0xe6, 0xc3, 0x9f,
+0x50, 0x12, 0x12, 0x2d, 0xeb, 0xff, 0x12, 0x2d, 0xf4, 0x12, 0x2e, 0x07, 0x78, 0x8b, 0x06, 0x12,
+0x2e, 0x03, 0x80, 0xe2, 0x22, 0xad, 0x07, 0xac, 0x06, 0x90, 0x32, 0x0a, 0xe4, 0x93, 0xff, 0x78,
+0x74, 0xf6, 0x54, 0x0f, 0x12, 0x1d, 0xa8, 0xe0, 0x08, 0x76, 0x00, 0x08, 0xf6, 0x18, 0x12, 0x1c,
+0xd9, 0xc3, 0x33, 0xce, 0x33, 0xce, 0xd8, 0xf9, 0xff, 0x78, 0x75, 0xee, 0xf6, 0x08, 0xef, 0xf6,
+0xee, 0x44, 0xf8, 0x18, 0xf6, 0xef, 0x08, 0xf6, 0x90, 0xff, 0x7a, 0xe0, 0x20, 0xe7, 0x03, 0x7f,
+0x00, 0x22, 0x78, 0x75, 0xe6, 0xfe, 0x08, 0xe6, 0xf5, 0x82, 0x8e, 0x83, 0xec, 0xf0, 0xa3, 0xed,
+0xf0, 0x90, 0xff, 0x7a, 0x74, 0x02, 0xf0, 0x7f, 0x01, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58,
+0x90, 0x00, 0x03, 0x12, 0x1a, 0xbb, 0x54, 0xf0, 0x24, 0xa0, 0x22, 0x90, 0xfa, 0xc9, 0x12, 0x1b,
+0xea, 0x02, 0x1a, 0xa2, 0x90, 0xfa, 0xc3, 0x12, 0x1b, 0xea, 0xef, 0x12, 0x1a, 0xe8, 0x90, 0xfa,
+0xca, 0xe4, 0x22, 0x90, 0xfa, 0xc4, 0xe4, 0x75, 0xf0, 0x01, 0x02, 0x1b, 0x1c, 0x90, 0x00, 0x08,
+0x12, 0x1b, 0x48, 0xaa, 0xf0, 0xf9, 0x7b, 0x01, 0x22, 0x90, 0x00, 0x05, 0x12, 0x1a, 0xbb, 0x90,
+0xfa, 0xc1, 0xf0, 0x22, 0xab, 0x56, 0xaa, 0x57, 0xa9, 0x58, 0x22, 0x90, 0xfa, 0xdd, 0xe0, 0xff,
+0x7e, 0x00, 0xc3, 0x90, 0xfa, 0xd7, 0xe0, 0x9f, 0xf0, 0x90, 0xfa, 0xd6, 0xe0, 0x9e, 0xf0, 0x90,
+0xfa, 0xd8, 0xee, 0x8f, 0xf0, 0x12, 0x1b, 0x1c, 0xef, 0x25, 0x51, 0xf5, 0x51, 0xee, 0x35, 0x50,
+0xf5, 0x50, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0x54, 0xfe, 0xf0, 0xe0, 0x54, 0xfd, 0xf0, 0x90, 0xfa,
+0xe6, 0xe0, 0x64, 0x03, 0x22, 0x90, 0xff, 0xf2, 0xe0, 0xab, 0x29, 0xaa, 0x2a, 0xa9, 0x2b, 0x02,
+0x1a, 0xe8, 0x90, 0xff, 0xf3, 0x74, 0xa0, 0xf0, 0x22, 0x8f, 0x64, 0xed, 0x70, 0x0f, 0xe5, 0x64,
+0xb4, 0x03, 0x05, 0x7f, 0x01, 0x02, 0x31, 0xef, 0x7f, 0x02, 0x02, 0x31, 0xef, 0xaf, 0x64, 0x12,
+0x2a, 0xc7, 0x74, 0x6e, 0x25, 0x64, 0xf8, 0xe6, 0x30, 0xe2, 0x0b, 0xd2, 0x09, 0x12, 0x1d, 0x33,
+0xe0, 0x54, 0x7f, 0xf0, 0x80, 0x02, 0xc2, 0x09, 0xe5, 0x64, 0xb4, 0x03, 0x07, 0x7f, 0x81, 0x12,
+0x31, 0xef, 0x80, 0x05, 0x7f, 0x82, 0x12, 0x31, 0xef, 0x30, 0x09, 0x07, 0x12, 0x1d, 0x33, 0xe0,
+0x44, 0x80, 0xf0, 0x12, 0x32, 0x84, 0x22, 0x12, 0x10, 0x4b, 0x90, 0xff, 0xfd, 0xe0, 0x44, 0x60,
+0xf0, 0xd2, 0x01, 0x90, 0xff, 0xfc, 0xe0, 0x44, 0x02, 0xf0, 0x90, 0xff, 0x00, 0xe0, 0x30, 0xe7,
+0x13, 0x90, 0xff, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x35, 0x80, 0x90, 0xff, 0xfc, 0xe0, 0x44,
+0x01, 0xf0, 0x80, 0x0d, 0x12, 0x1d, 0xdf, 0x53, 0x35, 0x7f, 0x90, 0xff, 0xfc, 0xe0, 0x54, 0xfe,
+0xf0, 0x90, 0xff, 0x81, 0xe0, 0x44, 0x80, 0xf0, 0x12, 0x02, 0xde, 0x12, 0x1d, 0xe7, 0x02, 0x10,
+0xce, 0x12, 0x10, 0x4b, 0x78, 0x89, 0xef, 0xf6, 0xd2, 0x00, 0x12, 0x2a, 0xc7, 0x90, 0xf9, 0x6a,
+0x12, 0x1b, 0xea, 0xe9, 0x24, 0x03, 0xf9, 0xe4, 0x3a, 0xfa, 0xc0, 0x02, 0x78, 0x80, 0xe6, 0xfe,
+0x08, 0xe6, 0xaa, 0x06, 0xf8, 0xac, 0x02, 0x7d, 0x01, 0xd0, 0x02, 0x12, 0x22, 0xd3, 0x12, 0x32,
+0x84, 0x78, 0x89, 0xe6, 0xff, 0x12, 0x13, 0x87, 0x12, 0x31, 0xa9, 0x02, 0x10, 0xce, 0x8f, 0x63,
+0x12, 0x2a, 0xc7, 0x78, 0x7c, 0x12, 0x22, 0xb7, 0xe0, 0x54, 0x3f, 0xf0, 0xe5, 0x82, 0x24, 0x04,
+0x12, 0x22, 0xa1, 0xe0, 0x54, 0x3f, 0xf0, 0x12, 0x23, 0x41, 0x24, 0x0b, 0x12, 0x22, 0xa1, 0xe0,
+0x54, 0xf8, 0xf0, 0x12, 0x32, 0x84, 0x74, 0x6e, 0x25, 0x63, 0xf8, 0x74, 0xfb, 0x56, 0xf6, 0x7f,
+0x00, 0x22, 0x12, 0x10, 0x4b, 0x12, 0x2a, 0xc7, 0x12, 0x22, 0xfa, 0x24, 0x06, 0x12, 0x22, 0x9f,
+0xe0, 0xfd, 0x12, 0x22, 0xe8, 0x90, 0x00, 0x03, 0x12, 0x23, 0x02, 0x24, 0x05, 0x12, 0x22, 0xa1,
+0xe0, 0x90, 0x00, 0x04, 0x12, 0x1a, 0xfa, 0x12, 0x32, 0x84, 0x7d, 0x02, 0xe4, 0xff, 0x12, 0x2f,
+0xb4, 0x02, 0x10, 0xce, 0xae, 0x05, 0x12, 0x1d, 0x8e, 0xef, 0x12, 0x1a, 0xfa, 0x0e, 0x0e, 0x0e,
+0xee, 0xd3, 0x95, 0x3c, 0xe4, 0x95, 0x3b, 0x40, 0x02, 0xae, 0x3c, 0xee, 0xd3, 0x94, 0x08, 0x74,
+0x80, 0x94, 0x81, 0x40, 0x0a, 0x7e, 0x03, 0x90, 0x00, 0x02, 0x74, 0x02, 0x12, 0x1a, 0xfa, 0xaf,
+0x06, 0x12, 0x32, 0x6e, 0x22, 0xae, 0x07, 0xed, 0x54, 0x03, 0x64, 0x01, 0x60, 0x03, 0x7f, 0x10,
+0x22, 0xed, 0x54, 0x7c, 0xc3, 0x94, 0x04, 0x50, 0x03, 0x7f, 0x0b, 0x22, 0x74, 0x6e, 0x2e, 0xf8,
+0x74, 0x02, 0x46, 0xf6, 0x74, 0x99, 0x2e, 0xf5, 0x82, 0xe4, 0x34, 0xfa, 0xf5, 0x83, 0xed, 0xf0,
+0x7f, 0x00, 0x22, 0xbf, 0x03, 0x06, 0x7c, 0xff, 0x7d, 0xe0, 0x80, 0x04, 0x7c, 0xff, 0x7d, 0xe2,
+0x8d, 0x82, 0x8c, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0xe5, 0x82, 0x24, 0x04, 0x12, 0x22, 0xa1, 0xe0,
+0x44, 0x80, 0xf0, 0x74, 0x6e, 0x2f, 0xf8, 0x74, 0x04, 0x46, 0xf6, 0x7f, 0x00, 0x22, 0x12, 0x10,
+0x4b, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60, 0x16, 0x90, 0xff, 0x83,
+0xe0, 0x54, 0x0f, 0xff, 0xc3, 0xe5, 0x3a, 0x9f, 0xe5, 0x39, 0x94, 0x00, 0x40, 0x05, 0x12, 0x28,
+0xd7, 0x80, 0x03, 0x12, 0x32, 0x7a, 0x02, 0x10, 0xce, 0x90, 0xff, 0xfc, 0xe0, 0x20, 0xe7, 0x1f,
+0xc2, 0xaf, 0x7d, 0xff, 0xac, 0x05, 0x1d, 0xec, 0x60, 0x15, 0x7e, 0x04, 0x7f, 0x00, 0xef, 0x1f,
+0xaa, 0x06, 0x70, 0x01, 0x1e, 0x4a, 0x60, 0xec, 0x90, 0xff, 0x92, 0xe4, 0xf0, 0x80, 0xef, 0x22,
+0x12, 0x10, 0x4b, 0x78, 0x66, 0xe6, 0xfe, 0x08, 0xe6, 0xff, 0x30, 0xe0, 0x12, 0x30, 0xe1, 0x0f,
+0x90, 0xff, 0xfc, 0xe0, 0x44, 0x20, 0xf0, 0x7f, 0x04, 0x12, 0x12, 0x61, 0x12, 0x1d, 0xf6, 0x02,
+0x10, 0xce, 0x8f, 0x23, 0xc2, 0x08, 0x12, 0x2a, 0xc7, 0x12, 0x22, 0xc0, 0x78, 0x7e, 0x12, 0x23,
+0x42, 0x24, 0x0b, 0x12, 0x22, 0xa1, 0xe0, 0x54, 0xf8, 0xf0, 0x12, 0x32, 0x84, 0xaf, 0x23, 0x12,
+0x13, 0x87, 0x22, 0x8e, 0x5f, 0x8f, 0x60, 0xe5, 0x60, 0x15, 0x60, 0xae, 0x5f, 0x70, 0x02, 0x15,
+0x5f, 0xd3, 0x94, 0x00, 0xee, 0x94, 0x00, 0x40, 0x09, 0x7e, 0x07, 0x7f, 0xd0, 0x12, 0x10, 0x24,
+0x80, 0xe5, 0x22, 0x11, 0xdc, 0x2e, 0xc7, 0x24, 0xb0, 0x32, 0x60, 0x30, 0x90, 0x30, 0x3e, 0x31,
+0x6f, 0x2f, 0x82, 0x27, 0x2e, 0x2c, 0x80, 0x31, 0x12, 0x31, 0x31, 0x1e, 0x64, 0x2f, 0x11, 0x2c,
+0x18, 0x0e, 0x12, 0x10, 0x4b, 0x78, 0x86, 0x12, 0x23, 0x31, 0x20, 0xe1, 0x07, 0x7f, 0x12, 0x12,
+0x31, 0xa9, 0x80, 0x0a, 0x78, 0x86, 0xe6, 0xff, 0x12, 0x24, 0x0a, 0x12, 0x31, 0xa9, 0x02, 0x10,
+0xce, 0x12, 0x10, 0x4b, 0x78, 0x87, 0x12, 0x23, 0x31, 0x20, 0xe2, 0x07, 0x7f, 0x11, 0x12, 0x31,
+0xa9, 0x80, 0x0a, 0x78, 0x87, 0xe6, 0xff, 0x12, 0x2f, 0x4e, 0x12, 0x31, 0xa9, 0x02, 0x10, 0xce,
+0x8f, 0x61, 0x12, 0x2f, 0x4e, 0xaf, 0x61, 0x12, 0x2a, 0xc7, 0x12, 0x22, 0xc0, 0x12, 0x32, 0x84,
+0x74, 0x6e, 0x25, 0x61, 0xf8, 0x74, 0xfd, 0x56, 0xf6, 0xaf, 0x61, 0x12, 0x13, 0x87, 0x22, 0x12,
+0x10, 0x4b, 0xe5, 0x3a, 0x64, 0x09, 0x70, 0x04, 0xe5, 0x39, 0x64, 0x01, 0x60, 0x05, 0x12, 0x2c,
+0xd8, 0x80, 0x06, 0x12, 0x1e, 0x14, 0x12, 0x1e, 0x1c, 0x02, 0x10, 0xce, 0x12, 0x2a, 0x54, 0x12,
+0x13, 0x03, 0x90, 0xf8, 0x04, 0xe0, 0xff, 0x60, 0x05, 0x7d, 0x01, 0x12, 0x12, 0xa0, 0x12, 0x29,
+0xde, 0x12, 0x13, 0x3f, 0x12, 0x11, 0xbc, 0x80, 0xe3, 0x12, 0x1d, 0x8e, 0xef, 0x12, 0x1a, 0xfa,
+0xe4, 0xf5, 0x33, 0xf5, 0x34, 0xef, 0x60, 0x03, 0x02, 0x32, 0x7a, 0xe4, 0xff, 0x12, 0x32, 0x6e,
+0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0xa0, 0x60, 0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff,
+0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0x90, 0xff, 0xf0, 0xe0, 0xff, 0x54, 0x28, 0x60,
+0xf7, 0xef, 0x30, 0xe5, 0x08, 0x90, 0xff, 0xf0, 0x44, 0x20, 0xf0, 0xc3, 0x22, 0xd3, 0x22, 0xef,
+0x30, 0xe7, 0x08, 0x12, 0x1d, 0x45, 0xe0, 0x54, 0xdf, 0xf0, 0x22, 0xef, 0x12, 0x1d, 0x98, 0xe0,
+0x54, 0xdf, 0xf0, 0x22, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03, 0x87, 0x40, 0x00, 0x40, 0x00, 0x40,
+0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0x08, 0x00, 0x78, 0x7e, 0x12, 0x22, 0xb7, 0xa3, 0xa3,
+0xe0, 0xff, 0x30, 0xe7, 0x06, 0x54, 0x7f, 0xf0, 0x44, 0x80, 0xf0, 0x22, 0x85, 0x3b, 0x39, 0x85,
+0x3c, 0x3a, 0x90, 0xff, 0x82, 0xe0, 0x54, 0xf7, 0xf0, 0xa3, 0xe0, 0x54, 0x7f, 0xf0, 0x22, 0xe4,
+0xfe, 0xee, 0x90, 0x32, 0x04, 0x93, 0xb5, 0x07, 0x02, 0xd3, 0x22, 0x0e, 0xbe, 0x07, 0xf2, 0xc3,
+0x22, 0x00, 0x08, 0x18, 0x28, 0x38, 0x01, 0x81, 0x90, 0x0a, 0x02, 0x00, 0x00, 0x11, 0x13, 0x00,
+0x12, 0x10, 0x4b, 0x7f, 0x02, 0x12, 0x10, 0xda, 0x12, 0x1d, 0xf6, 0x02, 0x10, 0xce, 0x75, 0x39,
+0x00, 0x8f, 0x3a, 0x12, 0x1c, 0xe0, 0x12, 0x2c, 0xd8, 0x22, 0x12, 0x1e, 0x1c, 0x12, 0x1d, 0xdf,
+0x12, 0x1e, 0x14, 0x22, 0xc2, 0x08, 0x22,
};
#undef IMAGE_VERSION_NAME
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 544098d2b775..b8670905bc3a 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -48,7 +48,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.7"
+#define DRIVER_VERSION "v0.7mode043006"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"
@@ -173,8 +173,12 @@ static struct usb_device_id edgeport_2port_id_table [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
-// The 4-port shows up as two 2-port devices
+ /* The 4, 8 and 16 port devices show up as multiple 2 port devices */
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) },
{ }
};
@@ -209,6 +213,10 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) },
+ { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) },
{ }
};
@@ -231,6 +239,7 @@ static int TIStayInBootMode = 0;
static int low_latency = EDGE_LOW_LATENCY;
static int closing_wait = EDGE_CLOSING_WAIT;
static int ignore_cpu_rev = 0;
+static int default_uart_mode = 0; /* RS232 */
static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length);
@@ -241,6 +250,10 @@ static int restart_read(struct edgeport_port *edge_port);
static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
static void edge_send(struct usb_serial_port *port);
+/* sysfs attributes */
+static int edge_create_sysfs_attrs(struct usb_serial_port *port);
+static int edge_remove_sysfs_attrs(struct usb_serial_port *port);
+
/* circular buffer */
static struct edge_buf *edge_buf_alloc(unsigned int size);
static void edge_buf_free(struct edge_buf *eb);
@@ -1706,13 +1719,14 @@ static void edge_interrupt_callback (struct urb *urb)
int length = urb->actual_length;
int port_number;
int function;
- int status;
+ int retval;
__u8 lsr;
__u8 msr;
+ int status = urb->status;
dbg("%s", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -1720,10 +1734,12 @@ static void edge_interrupt_callback (struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
return;
default:
- dev_err(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
+ dev_err(&urb->dev->dev, "%s - nonzero urb status received: "
+ "%d\n", __FUNCTION__, status);
goto exit;
}
@@ -1781,10 +1797,10 @@ static void edge_interrupt_callback (struct urb *urb)
}
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
dev_err (&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
static void edge_bulk_in_callback (struct urb *urb)
@@ -1792,12 +1808,13 @@ static void edge_bulk_in_callback (struct urb *urb)
struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
- int status = 0;
+ int retval = 0;
int port_number;
+ int status = urb->status;
dbg("%s", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -1805,17 +1822,18 @@ static void edge_bulk_in_callback (struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
return;
default:
dev_err (&urb->dev->dev,"%s - nonzero read bulk status received: %d\n",
- __FUNCTION__, urb->status );
+ __FUNCTION__, status);
}
- if (urb->status == -EPIPE)
+ if (status == -EPIPE)
goto exit;
- if (urb->status) {
+ if (status) {
dev_err(&urb->dev->dev,"%s - stopping read!\n", __FUNCTION__);
return;
}
@@ -1849,14 +1867,14 @@ exit:
spin_lock(&edge_port->ep_lock);
if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) {
urb->dev = edge_port->port->serial->dev;
- status = usb_submit_urb(urb, GFP_ATOMIC);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
} else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) {
edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED;
}
spin_unlock(&edge_port->ep_lock);
- if (status)
+ if (retval)
dev_err (&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length)
@@ -1883,12 +1901,13 @@ static void edge_bulk_out_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_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);
edge_port->ep_write_urb_in_use = 0;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -1896,11 +1915,12 @@ static void edge_bulk_out_callback (struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
return;
default:
- dev_err (&urb->dev->dev,"%s - nonzero write bulk status received: %d\n",
- __FUNCTION__, urb->status);
+ dev_err(&urb->dev->dev, "%s - nonzero write bulk status "
+ "received: %d\n", __FUNCTION__, status);
}
/* send any buffered data */
@@ -2351,7 +2371,7 @@ static int restart_read(struct edgeport_port *edge_port)
urb->complete = edge_bulk_in_callback;
urb->context = edge_port;
urb->dev = edge_port->port->serial->dev;
- status = usb_submit_urb(urb, GFP_KERNEL);
+ status = usb_submit_urb(urb, GFP_ATOMIC);
}
edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
edge_port->shadow_mcr |= MCR_RTS;
@@ -2524,14 +2544,6 @@ static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old
}
cflag = tty->termios->c_cflag;
- /* check that they really want us to change something */
- if (old_termios) {
- if (cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag) {
- dbg ("%s - nothing to change", __FUNCTION__);
- return;
- }
- }
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag, tty->termios->c_iflag);
@@ -2758,7 +2770,7 @@ static int edge_startup (struct usb_serial *serial)
edge_port->port = serial->port[i];
edge_port->edge_serial = edge_serial;
usb_set_serial_port_data(serial->port[i], edge_port);
- edge_port->bUartMode = 0; /* Default is RS232 */
+ edge_port->bUartMode = default_uart_mode;
}
return 0;
@@ -2782,19 +2794,60 @@ static void edge_shutdown (struct usb_serial *serial)
dbg ("%s", __FUNCTION__);
- for (i=0; i < serial->num_ports; ++i) {
+ for (i = 0; i < serial->num_ports; ++i) {
edge_port = usb_get_serial_port_data(serial->port[i]);
- if (edge_port) {
- edge_buf_free(edge_port->ep_out_buf);
- kfree(edge_port);
- }
+ edge_remove_sysfs_attrs(edge_port->port);
+ edge_buf_free(edge_port->ep_out_buf);
+ kfree(edge_port);
usb_set_serial_port_data(serial->port[i], NULL);
}
- kfree (usb_get_serial_data(serial));
+ kfree(usb_get_serial_data(serial));
usb_set_serial_data(serial, NULL);
}
+/* Sysfs Attributes */
+
+static ssize_t show_uart_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_serial_port *port = to_usb_serial_port(dev);
+ struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+
+ return sprintf(buf, "%d\n", edge_port->bUartMode);
+}
+
+static ssize_t store_uart_mode(struct device *dev,
+ struct device_attribute *attr, const char *valbuf, size_t count)
+{
+ struct usb_serial_port *port = to_usb_serial_port(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);
+
+ if (v < 256)
+ edge_port->bUartMode = v;
+ else
+ dev_err(dev, "%s - uart_mode %d is invalid\n", __FUNCTION__, v);
+
+ return count;
+}
+
+static DEVICE_ATTR(uart_mode, S_IWUSR | S_IRUGO, show_uart_mode, store_uart_mode);
+
+static int edge_create_sysfs_attrs(struct usb_serial_port *port)
+{
+ return device_create_file(&port->dev, &dev_attr_uart_mode);
+}
+
+static int edge_remove_sysfs_attrs(struct usb_serial_port *port)
+{
+ device_remove_file(&port->dev, &dev_attr_uart_mode);
+ return 0;
+}
+
+
/* Circular Buffer */
/*
@@ -2991,6 +3044,7 @@ static struct usb_serial_driver edgeport_1port_device = {
.unthrottle = edge_unthrottle,
.attach = edge_startup,
.shutdown = edge_shutdown,
+ .port_probe = edge_create_sysfs_attrs,
.ioctl = edge_ioctl,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
@@ -3022,6 +3076,7 @@ static struct usb_serial_driver edgeport_2port_device = {
.unthrottle = edge_unthrottle,
.attach = edge_startup,
.shutdown = edge_shutdown,
+ .port_probe = edge_create_sysfs_attrs,
.ioctl = edge_ioctl,
.set_termios = edge_set_termios,
.tiocmget = edge_tiocmget,
@@ -3085,3 +3140,6 @@ MODULE_PARM_DESC(closing_wait, "Maximum wait for data to drain, in .01 secs");
module_param(ignore_cpu_rev, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ignore_cpu_rev, "Ignore the cpu revision when connecting to a device");
+module_param(default_uart_mode, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(default_uart_mode, "Default uart_mode, 0=RS232, ...");
+
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index e57fa117e486..8e1a491e52a9 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -131,7 +131,7 @@
#define ION_DEVICE_ID_TI_EDGEPORT_2I 0x0207 // Edgeport/2i RS422/RS485
#define ION_DEVICE_ID_TI_EDGEPORT_421 0x020C // Edgeport/421 4 hub 2 RS232 + Parallel (lucent on a different hub port)
#define ION_DEVICE_ID_TI_EDGEPORT_21 0x020D // Edgeport/21 2 RS232 + Parallel (lucent on a different hub port)
-#define ION_DEVICE_ID_TI_EDGEPORT_8 0x020F // Edgeport/8 (single-CPU)
+#define ION_DEVICE_ID_TI_EDGEPORT_416 0x0212 // Edgeport/416
#define ION_DEVICE_ID_TI_EDGEPORT_1 0x0215 // Edgeport/1 RS232
#define ION_DEVICE_ID_TI_EDGEPORT_42 0x0217 // Edgeport/42 4 hub 2 RS232
#define ION_DEVICE_ID_TI_EDGEPORT_22I 0x021A // Edgeport/22I is an Edgeport/4 with ports 1&2 RS422 and ports 3&4 RS232
@@ -143,12 +143,14 @@
#define ION_DEVICE_ID_TI_EDGEPORT_21C 0x021E // Edgeport/21c is a TI based Edgeport/2 with lucent chip
// Generation 3 devices -- 3410 based edgport/1 (256 byte I2C)
-#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1 0x240 // Edgeport/1 RS232
-#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I 0x241 // Edgeport/1i- RS422 model
+#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1 0x0240 // Edgeport/1 RS232
+#define ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I 0x0241 // Edgeport/1i- RS422 model
// Ti based software switchable RS232/RS422/RS485 devices
-#define ION_DEVICE_ID_TI_EDGEPORT_4S 0x242 // Edgeport/4s - software switchable model
-#define ION_DEVICE_ID_IT_EDGEPORT_8S 0x243 // Edgeport/8s - software switchable model
+#define ION_DEVICE_ID_TI_EDGEPORT_4S 0x0242 // Edgeport/4s - software switchable model
+#define ION_DEVICE_ID_TI_EDGEPORT_8S 0x0243 // Edgeport/8s - software switchable model
+#define ION_DEVICE_ID_TI_EDGEPORT_8 0x0244 // Edgeport/8 (single-CPU)
+#define ION_DEVICE_ID_TI_EDGEPORT_416B 0x0247 // Edgeport/416
/************************************************************************
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 4df0ec74e0b1..0455c1552ae9 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -732,11 +732,13 @@ static void ipaq_read_bulk_callback(struct urb *urb)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int result;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -870,11 +872,13 @@ static void ipaq_write_bulk_callback(struct urb *urb)
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);
-
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
return;
}
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 1bc586064c77..1b94daa61584 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -167,11 +167,13 @@ static void ipw_read_bulk_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
int result;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -369,13 +371,15 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
static void ipw_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
+ int status = urb->status;
dbg("%s", __FUNCTION__);
port->write_urb_busy = 0;
- if (urb->status)
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status)
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
usb_serial_port_softint(port);
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 9d847f69291c..5ab6a0c5ac52 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -21,6 +21,10 @@
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * 2007_Jun_21 Alan Cox <alan@redhat.com>
+ * Minimal cleanups for some of the driver problens and tty layer abuse.
+ * Still needs fixing to allow multiple dongles.
+ *
* 2002_Mar_07 greg kh
* moved some needed structures and #define values from the
* net/irda/irda-usb.h file into our file, as we don't want to depend on
@@ -109,6 +113,7 @@ static void ir_write_bulk_callback (struct urb *urb);
static void ir_read_bulk_callback (struct urb *urb);
static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios);
+/* Not that this lot means you can only have one per system */
static u8 ir_baud = 0;
static u8 ir_xbof = 0;
static u8 ir_add_bof = 0;
@@ -392,12 +397,14 @@ 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;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
port->write_urb_busy = 0;
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -417,6 +424,7 @@ static void ir_read_bulk_callback (struct urb *urb)
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
int result;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -425,8 +433,7 @@ static void ir_read_bulk_callback (struct urb *urb)
return;
}
- switch (urb->status) {
-
+ switch (status) {
case 0: /* Successful */
/*
@@ -444,22 +451,12 @@ static void ir_read_bulk_callback (struct urb *urb)
urb->actual_length,
data);
- /*
- * Bypass flip-buffers, and feed the ldisc directly
- * due to our potentially large buffer size. Since we
- * used to set low_latency, this is exactly what the
- * tty layer did anyway :)
- */
tty = port->tty;
- /*
- * FIXME: must not do this in IRQ context
- */
- tty->ldisc.receive_buf(
- tty,
- data+1,
- NULL,
- urb->actual_length-1);
+ if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
+ tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
+ tty_flip_buffer_push(tty);
+ }
/*
* No break here.
@@ -490,7 +487,7 @@ static void ir_read_bulk_callback (struct urb *urb)
default:
dbg("%s - nonzero read bulk status received: %d",
__FUNCTION__,
- urb->status);
+ status);
break ;
}
@@ -501,8 +498,9 @@ static void ir_read_bulk_callback (struct urb *urb)
static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
{
unsigned char *transfer_buffer;
- unsigned int cflag;
int result;
+ speed_t baud;
+ int ir_baud;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -511,77 +509,59 @@ static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_t
return;
}
- cflag = port->tty->termios->c_cflag;
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
- }
+ baud = tty_get_baud_rate(port->tty);
+
+ /*
+ * FIXME, we should compare the baud request against the
+ * capability stated in the IR header that we got in the
+ * startup function.
+ */
+
+ switch (baud) {
+ case 2400: ir_baud = SPEED_2400; break;
+ case 9600: ir_baud = SPEED_9600; break;
+ case 19200: ir_baud = SPEED_19200; break;
+ case 38400: ir_baud = SPEED_38400; break;
+ case 57600: ir_baud = SPEED_57600; break;
+ case 115200: ir_baud = SPEED_115200; break;
+ case 576000: ir_baud = SPEED_576000; break;
+ case 1152000: ir_baud = SPEED_1152000; break;
+ case 4000000: ir_baud = SPEED_4000000; break;
+ break;
+ default:
+ ir_baud = SPEED_9600;
+ baud = 9600;
+ /* And once the new tty stuff is all done we need to
+ call back to correct the baud bits */
}
- /* All we can change is the baud rate */
- if (cflag & CBAUD) {
-
- dbg ("%s - asking for baud %d",
- __FUNCTION__,
- tty_get_baud_rate(port->tty));
-
- /*
- * FIXME, we should compare the baud request against the
- * capability stated in the IR header that we got in the
- * startup function.
- */
- switch (cflag & CBAUD) {
- case B2400: ir_baud = SPEED_2400; break;
- default:
- case B9600: ir_baud = SPEED_9600; break;
- case B19200: ir_baud = SPEED_19200; break;
- case B38400: ir_baud = SPEED_38400; break;
- case B57600: ir_baud = SPEED_57600; break;
- case B115200: ir_baud = SPEED_115200; break;
- case B576000: ir_baud = SPEED_576000; break;
- case B1152000: ir_baud = SPEED_1152000; break;
-#ifdef B4000000
- case B4000000: ir_baud = SPEED_4000000; break;
-#endif
- }
+ if (xbof == -1)
+ ir_xbof = ir_xbof_change(ir_add_bof);
+ else
+ ir_xbof = ir_xbof_change(xbof) ;
- if (xbof == -1) {
- ir_xbof = ir_xbof_change(ir_add_bof);
- } else {
- ir_xbof = ir_xbof_change(xbof) ;
- }
+ /* FIXME need to check to see if our write urb is busy right
+ * now, or use a urb pool.
+ *
+ * send the baud change out on an "empty" data packet
+ */
+ transfer_buffer = port->write_urb->transfer_buffer;
+ *transfer_buffer = ir_xbof | ir_baud;
- /* Notify the tty driver that the termios have changed. */
- port->tty->ldisc.set_termios(port->tty, NULL);
-
- /* FIXME need to check to see if our write urb is busy right
- * now, or use a urb pool.
- *
- * send the baud change out on an "empty" data packet
- */
- transfer_buffer = port->write_urb->transfer_buffer;
- *transfer_buffer = ir_xbof | ir_baud;
-
- usb_fill_bulk_urb (
- port->write_urb,
- port->serial->dev,
- usb_sndbulkpipe(port->serial->dev,
- port->bulk_out_endpointAddress),
- port->write_urb->transfer_buffer,
- 1,
- ir_write_bulk_callback,
- port);
-
- port->write_urb->transfer_flags = URB_ZERO_PACKET;
-
- 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);
- }
- return;
+ usb_fill_bulk_urb (
+ port->write_urb,
+ port->serial->dev,
+ usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer,
+ 1,
+ ir_write_bulk_callback,
+ port);
+
+ port->write_urb->transfer_flags = URB_ZERO_PACKET;
+
+ 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);
}
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index e6966f12ed5a..f2a6fce5de1e 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -115,12 +115,13 @@ static int debug;
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.1.4"
+#define DRIVER_VERSION "v1.1.5"
#define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu"
#define DRIVER_DESC "Keyspan USB to Serial Converter Driver"
#define INSTAT_BUFLEN 32
#define GLOCONT_BUFLEN 64
+#define INDAT49W_BUFLEN 512
/* Per device and per port private data */
struct keyspan_serial_private {
@@ -129,9 +130,15 @@ struct keyspan_serial_private {
struct urb *instat_urb;
char instat_buf[INSTAT_BUFLEN];
+ /* added to support 49wg, where data from all 4 ports comes in on 1 EP */
+ /* and high-speed supported */
+ struct urb *indat_urb;
+ char indat_buf[INDAT49W_BUFLEN];
+
/* XXX this one probably will need a lock */
struct urb *glocont_urb;
char glocont_buf[GLOCONT_BUFLEN];
+ char ctrl_buf[8]; // for EP0 control message
};
struct keyspan_port_private {
@@ -179,12 +186,13 @@ struct keyspan_port_private {
/* Include Keyspan message headers. All current Keyspan Adapters
- make use of one of four message formats which are referred
- to as USA-26, USA-28 and USA-49, USA-90 by Keyspan and within this driver. */
+ make use of one of five message formats which are referred
+ to as USA-26, USA-28, USA-49, USA-90, USA-67 by Keyspan and within this driver. */
#include "keyspan_usa26msg.h"
#include "keyspan_usa28msg.h"
#include "keyspan_usa49msg.h"
#include "keyspan_usa90msg.h"
+#include "keyspan_usa67msg.h"
/* Functions used by new usb-serial code. */
@@ -419,14 +427,15 @@ static void usa26_indat_callback(struct urb *urb)
struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
dbg ("%s", __FUNCTION__);
endpoint = usb_pipeendpoint(urb->pipe);
- if (urb->status) {
+ if (status) {
dbg("%s - nonzero status: %x on endpoint %d.",
- __FUNCTION__, urb->status, endpoint);
+ __FUNCTION__, status, endpoint);
return;
}
@@ -511,11 +520,12 @@ static void usa26_instat_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
int old_dcd_state, err;
+ int status = urb->status;
serial = (struct usb_serial *) urb->context;
- if (urb->status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero status: %x", __FUNCTION__, status);
return;
}
if (urb->actual_length != 9) {
@@ -579,6 +589,7 @@ static void usa28_indat_callback(struct urb *urb)
struct tty_struct *tty;
unsigned char *data;
struct keyspan_port_private *p_priv;
+ int status = urb->status;
dbg ("%s", __FUNCTION__);
@@ -590,9 +601,9 @@ static void usa28_indat_callback(struct urb *urb)
return;
do {
- if (urb->status) {
+ if (status) {
dbg("%s - nonzero status: %x on endpoint %d.",
- __FUNCTION__, urb->status, usb_pipeendpoint(urb->pipe));
+ __FUNCTION__, status, usb_pipeendpoint(urb->pipe));
return;
}
@@ -648,11 +659,12 @@ static void usa28_instat_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
int old_dcd_state;
+ int status = urb->status;
serial = (struct usb_serial *) urb->context;
- if (urb->status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero status: %x", __FUNCTION__, status);
return;
}
@@ -739,13 +751,14 @@ static void usa49_instat_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
int old_dcd_state;
+ int status = urb->status;
dbg ("%s", __FUNCTION__);
serial = (struct usb_serial *) urb->context;
- if (urb->status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero status: %x", __FUNCTION__, status);
return;
}
@@ -805,14 +818,15 @@ static void usa49_indat_callback(struct urb *urb)
struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
dbg ("%s", __FUNCTION__);
endpoint = usb_pipeendpoint(urb->pipe);
- if (urb->status) {
+ if (status) {
dbg("%s - nonzero status: %x on endpoint %d.", __FUNCTION__,
- urb->status, endpoint);
+ status, endpoint);
return;
}
@@ -850,13 +864,90 @@ static void usa49_indat_callback(struct urb *urb)
}
}
+static void usa49wg_indat_callback(struct urb *urb)
+{
+ int i, len, x, err;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
+
+ dbg ("%s", __FUNCTION__);
+
+ serial = urb->context;
+
+ if (status) {
+ dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ return;
+ }
+
+ /* inbound data is in the form P#, len, status, data */
+ i = 0;
+ len = 0;
+
+ if (urb->actual_length) {
+ while (i < urb->actual_length) {
+
+ /* Check port number from message*/
+ if (data[i] >= serial->num_ports) {
+ dbg ("%s - Unexpected port number %d",
+ __FUNCTION__, data[i]);
+ return;
+ }
+ port = serial->port[data[i++]];
+ tty = port->tty;
+ len = data[i++];
+
+ /* 0x80 bit is error flag */
+ if ((data[i] & 0x80) == 0) {
+ /* no error on any byte */
+ i++;
+ for (x = 1; x < len ; ++x)
+ if (port->open_count)
+ tty_insert_flip_char(tty,
+ data[i++], 0);
+ else
+ i++;
+ } else {
+ /*
+ * some bytes had errors, every byte has status
+ */
+ for (x = 0; x + 1 < len; x += 2) {
+ int stat = data[i], flag = 0;
+ if (stat & RXERROR_OVERRUN)
+ flag |= TTY_OVERRUN;
+ if (stat & RXERROR_FRAMING)
+ flag |= TTY_FRAME;
+ if (stat & RXERROR_PARITY)
+ flag |= TTY_PARITY;
+ /* XXX should handle break (0x10) */
+ if (port->open_count)
+ tty_insert_flip_char(tty,
+ data[i+1], flag);
+ i += 2;
+ }
+ }
+ if (port->open_count)
+ tty_flip_buffer_push(tty);
+ }
+ }
+
+ /* Resubmit urb so we continue receiving */
+ urb->dev = serial->dev;
+
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err != 0)
+ dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+}
+
/* not used, usa-49 doesn't have per-port control endpoints */
-static void usa49_outcont_callback(struct urb *urb)
+static void usa49_outcont_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa90_indat_callback(struct urb *urb)
+static void usa90_indat_callback(struct urb *urb)
{
int i, err;
int endpoint;
@@ -864,15 +955,15 @@ static void usa90_indat_callback(struct urb *urb)
struct keyspan_port_private *p_priv;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
dbg ("%s", __FUNCTION__);
endpoint = usb_pipeendpoint(urb->pipe);
-
- if (urb->status) {
+ if (status) {
dbg("%s - nonzero status: %x on endpoint %d.",
- __FUNCTION__, urb->status, endpoint);
+ __FUNCTION__, status, endpoint);
return;
}
@@ -938,11 +1029,12 @@ static void usa90_instat_callback(struct urb *urb)
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
int old_dcd_state, err;
+ int status = urb->status;
serial = (struct usb_serial *) urb->context;
- if (urb->status) {
- dbg("%s - nonzero status: %x", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero status: %x", __FUNCTION__, status);
return;
}
if (urb->actual_length < 14) {
@@ -995,6 +1087,88 @@ static void usa90_outcont_callback(struct urb *urb)
}
}
+/* Status messages from the 28xg */
+static void usa67_instat_callback(struct urb *urb)
+{
+ int err;
+ unsigned char *data = urb->transfer_buffer;
+ struct keyspan_usa67_portStatusMessage *msg;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ int old_dcd_state;
+ int status = urb->status;
+
+ dbg ("%s", __FUNCTION__);
+
+ serial = urb->context;
+
+ if (status) {
+ dbg("%s - nonzero status: %x", __FUNCTION__, status);
+ return;
+ }
+
+ if (urb->actual_length != sizeof(struct keyspan_usa67_portStatusMessage)) {
+ dbg("%s - bad length %d", __FUNCTION__, urb->actual_length);
+ return;
+ }
+
+
+ /* Now do something useful with the data */
+ msg = (struct keyspan_usa67_portStatusMessage *)data;
+
+ /* Check port number from message and retrieve private data */
+ if (msg->port >= serial->num_ports) {
+ dbg ("%s - Unexpected port number %d", __FUNCTION__, msg->port);
+ return;
+ }
+
+ port = serial->port[msg->port];
+ p_priv = usb_get_serial_port_data(port);
+
+ /* Update handshaking pin state information */
+ old_dcd_state = p_priv->dcd_state;
+ p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
+ p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
+
+ if (port->tty && !C_CLOCAL(port->tty)
+ && old_dcd_state != p_priv->dcd_state) {
+ if (old_dcd_state)
+ tty_hangup(port->tty);
+ /* else */
+ /* wake_up_interruptible(&p_priv->open_wait); */
+ }
+
+ /* Resubmit urb so we continue receiving */
+ urb->dev = serial->dev;
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err != 0)
+ dbg("%s - resubmit read urb failed. (%d)", __FUNCTION__, err);
+}
+
+static void usa67_glocont_callback(struct urb *urb)
+{
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ int i;
+
+ dbg ("%s", __FUNCTION__);
+
+ 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__);
+ keyspan_usa67_send_setup(serial, port,
+ p_priv->resend_cont - 1);
+ break;
+ }
+ }
+}
+
static int keyspan_write_room (struct usb_serial_port *port)
{
struct keyspan_port_private *p_priv;
@@ -1311,6 +1485,11 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
return NULL;
}
+ if (endpoint == 0) {
+ /* control EP filled in when used */
+ return urb;
+ }
+
ep_desc = find_ep(serial, endpoint);
if (!ep_desc) {
/* leak the urb, something's wrong and the callers don't care */
@@ -1380,6 +1559,14 @@ static struct callbacks {
.outdat_callback = usa2x_outdat_callback,
.inack_callback = usa28_inack_callback,
.outcont_callback = usa90_outcont_callback,
+ }, {
+ /* msg_usa67 callbacks */
+ .instat_callback = usa67_instat_callback,
+ .glocont_callback = usa67_glocont_callback,
+ .indat_callback = usa26_indat_callback,
+ .outdat_callback = usa2x_outdat_callback,
+ .inack_callback = usa26_inack_callback,
+ .outcont_callback = usa26_outcont_callback,
}
};
@@ -1410,6 +1597,11 @@ static void keyspan_setup_urbs(struct usb_serial *serial)
serial, s_priv->instat_buf, INSTAT_BUFLEN,
cback->instat_callback);
+ s_priv->indat_urb = keyspan_setup_urb
+ (serial, d_details->indat_endpoint, USB_DIR_IN,
+ serial, s_priv->indat_buf, INDAT49W_BUFLEN,
+ usa49wg_indat_callback);
+
s_priv->glocont_urb = keyspan_setup_urb
(serial, d_details->glocont_endpoint, USB_DIR_OUT,
serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
@@ -1685,8 +1877,8 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
}
/* Save reset port val for resend.
- Don't overwrite resend for close condition. */
- if (p_priv->resend_cont != 3)
+ Don't overwrite resend for open/close condition. */
+ 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__); */
@@ -1836,8 +2028,8 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
}
/* Save reset port val for resend.
- Don't overwrite resend for close condition. */
- if (p_priv->resend_cont != 3)
+ Don't overwrite resend for open/close condition. */
+ 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__);
@@ -1940,11 +2132,11 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
struct usb_serial_port *port,
int reset_port)
{
- struct keyspan_usa49_portControlMessage msg;
+ struct keyspan_usa49_portControlMessage msg;
+ struct usb_ctrlrequest *dr = NULL;
struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
const struct keyspan_device_details *d_details;
- int glocont_urb;
struct urb *this_urb;
int err, device_port;
@@ -1954,10 +2146,9 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
p_priv = usb_get_serial_port_data(port);
d_details = s_priv->device_details;
- glocont_urb = d_details->glocont_endpoint;
this_urb = s_priv->glocont_urb;
- /* Work out which port within the device is being setup */
+ /* 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);
@@ -1969,9 +2160,10 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
}
/* Save reset port val for resend.
- Don't overwrite resend for close condition. */
- if (p_priv->resend_cont != 3)
+ Don't overwrite resend for open/close condition. */
+ 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__); */
mdelay(5);
@@ -2083,20 +2275,39 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
msg.dtr = p_priv->dtr_state;
p_priv->resend_cont = 0;
- memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+
+ /* if the device is a 49wg, we send control message on usb control EP 0 */
+
+ if (d_details->product_id == keyspan_usa49wg_product_id) {
+ dr = (void *)(s_priv->ctrl_buf);
+ dr->bRequestType = USB_TYPE_VENDOR | USB_DIR_OUT;
+ dr->bRequest = 0xB0; /* 49wg control message */;
+ dr->wValue = 0;
+ dr->wIndex = 0;
+ dr->wLength = cpu_to_le16(sizeof(msg));
+
+ memcpy (s_priv->glocont_buf, &msg, sizeof(msg));
+
+ usb_fill_control_urb(this_urb, serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ (unsigned char *)dr, s_priv->glocont_buf, sizeof(msg),
+ usa49_glocont_callback, serial);
+
+ } else {
+ memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
- /* send the data out the device on control endpoint */
- this_urb->transfer_buffer_length = sizeof(msg);
+ /* send the data out the device on control endpoint */
+ this_urb->transfer_buffer_length = sizeof(msg);
- this_urb->dev = serial->dev;
+ 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);
}
#if 0
else {
dbg("%s - usb_submit_urb(%d) OK %d bytes (end %d)", __FUNCTION__,
- outcont_urb, this_urb->transfer_buffer_length,
- usb_pipeendpoint(this_urb->pipe));
+ outcont_urb, this_urb->transfer_buffer_length,
+ usb_pipeendpoint(this_urb->pipe));
}
#endif
@@ -2241,6 +2452,154 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
return (0);
}
+static int keyspan_usa67_send_setup(struct usb_serial *serial,
+ struct usb_serial_port *port,
+ int reset_port)
+{
+ struct keyspan_usa67_portControlMessage msg;
+ struct keyspan_serial_private *s_priv;
+ struct keyspan_port_private *p_priv;
+ const struct keyspan_device_details *d_details;
+ struct urb *this_urb;
+ int err, device_port;
+
+ dbg ("%s", __FUNCTION__);
+
+ s_priv = usb_get_serial_data(serial);
+ p_priv = usb_get_serial_port_data(port);
+ d_details = s_priv->device_details;
+
+ this_urb = s_priv->glocont_urb;
+
+ /* Work out which port within the device is being setup */
+ device_port = port->number - port->serial->minor;
+
+ /* 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);
+ return -1;
+ }
+
+ /* Save reset port val for resend.
+ Don't overwrite resend for open/close condition. */
+ 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__); */
+ mdelay(5);
+ return(-1);
+ }
+
+ memset(&msg, 0, sizeof(struct keyspan_usa67_portControlMessage));
+
+ msg.port = device_port;
+
+ /* Only set baud rate if it's changed */
+ if (p_priv->old_baud != p_priv->baud) {
+ p_priv->old_baud = p_priv->baud;
+ msg.setClocking = 0xff;
+ 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__,
+ p_priv->baud);
+ msg.baudLo = 0;
+ msg.baudHi = 125; /* Values for 9600 baud */
+ msg.prescaler = 10;
+ }
+ msg.setPrescaler = 0xff;
+ }
+
+ msg.lcr = (p_priv->cflag & CSTOPB) ? STOPBITS_678_2 : STOPBITS_5678_1;
+ switch (p_priv->cflag & CSIZE) {
+ case CS5:
+ msg.lcr |= USA_DATABITS_5;
+ break;
+ case CS6:
+ msg.lcr |= USA_DATABITS_6;
+ break;
+ case CS7:
+ msg.lcr |= USA_DATABITS_7;
+ break;
+ case CS8:
+ msg.lcr |= USA_DATABITS_8;
+ break;
+ }
+ if (p_priv->cflag & PARENB) {
+ /* note USA_PARITY_NONE == 0 */
+ msg.lcr |= (p_priv->cflag & PARODD)?
+ USA_PARITY_ODD: USA_PARITY_EVEN;
+ }
+ msg.setLcr = 0xff;
+
+ msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+ msg.xonFlowControl = 0;
+ msg.setFlowControl = 0xff;
+ msg.forwardingLength = 16;
+ msg.xonChar = 17;
+ msg.xoffChar = 19;
+
+ if (reset_port == 1) {
+ /* Opening port */
+ msg._txOn = 1;
+ msg._txOff = 0;
+ msg.txFlush = 0;
+ msg.txBreak = 0;
+ msg.rxOn = 1;
+ msg.rxOff = 0;
+ msg.rxFlush = 1;
+ msg.rxForward = 0;
+ msg.returnStatus = 0;
+ msg.resetDataToggle = 0xff;
+ } else if (reset_port == 2) {
+ /* Closing port */
+ msg._txOn = 0;
+ msg._txOff = 1;
+ msg.txFlush = 0;
+ msg.txBreak = 0;
+ msg.rxOn = 0;
+ msg.rxOff = 1;
+ msg.rxFlush = 1;
+ msg.rxForward = 0;
+ msg.returnStatus = 0;
+ msg.resetDataToggle = 0;
+ } else {
+ /* Sending intermediate configs */
+ msg._txOn = (! p_priv->break_on);
+ msg._txOff = 0;
+ msg.txFlush = 0;
+ msg.txBreak = (p_priv->break_on);
+ msg.rxOn = 0;
+ msg.rxOff = 0;
+ msg.rxFlush = 0;
+ msg.rxForward = 0;
+ msg.returnStatus = 0;
+ msg.resetDataToggle = 0x0;
+ }
+
+ /* Do handshaking outputs */
+ msg.setTxTriState_setRts = 0xff;
+ msg.txTriState_rts = p_priv->rts_state;
+
+ msg.setHskoa_setDtr = 0xff;
+ msg.hskoa_dtr = p_priv->dtr_state;
+
+ p_priv->resend_cont = 0;
+
+ memcpy(this_urb->transfer_buffer, &msg, sizeof(msg));
+
+ /* send the data out the device on control endpoint */
+ this_urb->transfer_buffer_length = sizeof(msg);
+ this_urb->dev = serial->dev;
+
+ err = usb_submit_urb(this_urb, GFP_ATOMIC);
+ if (err != 0)
+ dbg("%s - usb_submit_urb(setup) failed (%d)", __FUNCTION__,
+ err);
+ return (0);
+}
+
static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
{
struct usb_serial *serial = port->serial;
@@ -2265,6 +2624,9 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port)
case msg_usa90:
keyspan_usa90_send_setup(serial, port, reset_port);
break;
+ case msg_usa67:
+ keyspan_usa67_send_setup(serial, port, reset_port);
+ break;
}
}
@@ -2313,9 +2675,19 @@ static int keyspan_startup (struct usb_serial *serial)
keyspan_setup_urbs(serial);
- s_priv->instat_urb->dev = serial->dev;
- if ((err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL)) != 0) {
- dbg("%s - submit instat urb failed %d", __FUNCTION__, err);
+ if (s_priv->instat_urb != NULL) {
+ 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__,
+ 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__,
+ err);
}
return (0);
@@ -2335,6 +2707,7 @@ static void keyspan_shutdown (struct usb_serial *serial)
/* Stop reading/writing urbs */
stop_urb(s_priv->instat_urb);
stop_urb(s_priv->glocont_urb);
+ stop_urb(s_priv->indat_urb);
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
p_priv = usb_get_serial_port_data(port);
@@ -2348,6 +2721,7 @@ static void keyspan_shutdown (struct usb_serial *serial)
/* Now free them */
usb_free_urb(s_priv->instat_urb);
+ usb_free_urb(s_priv->indat_urb);
usb_free_urb(s_priv->glocont_urb);
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index c6830cbdc6df..8a0d17401529 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -99,6 +99,10 @@ static int keyspan_usa90_send_setup (struct usb_serial *serial,
struct usb_serial_port *port,
int reset_port);
+static int keyspan_usa67_send_setup (struct usb_serial *serial,
+ struct usb_serial_port *port,
+ int reset_port);
+
/* Struct used for firmware - increased size of data section
to allow Keyspan's 'C' firmware struct to be used unmodified */
struct ezusb_hex_record {
@@ -229,15 +233,17 @@ struct ezusb_hex_record {
#define keyspan_usa28_product_id 0x010f
#define keyspan_usa28x_product_id 0x0110
#define keyspan_usa28xa_product_id 0x0115
+#define keyspan_usa28xb_product_id 0x0110
+#define keyspan_usa28xg_product_id 0x0135
#define keyspan_usa49w_product_id 0x010a
#define keyspan_usa49wlc_product_id 0x012a
-
+#define keyspan_usa49wg_product_id 0x0131
struct keyspan_device_details {
/* product ID value */
int product_id;
- enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90} msg_format;
+ enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format;
/* Number of physical ports */
int num_ports;
@@ -264,6 +270,9 @@ struct keyspan_device_details {
/* Endpoint used for input status */
int instat_endpoint;
+ /* Endpoint used for input data 49WG only */
+ int indat_endpoint;
+
/* Endpoint used for global control functions */
int glocont_endpoint;
@@ -287,6 +296,7 @@ static const struct keyspan_device_details usa18x_device_details = {
.inack_endpoints = {0x85},
.outcont_endpoints = {0x05},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa19w_calc_baud,
.baudclk = KEYSPAN_USA18X_BAUDCLK,
@@ -303,6 +313,7 @@ static const struct keyspan_device_details usa19_device_details = {
.inack_endpoints = {0x83},
.outcont_endpoints = {0x03},
.instat_endpoint = 0x84,
+ .indat_endpoint = -1,
.glocont_endpoint = -1,
.calculate_baud_rate = keyspan_usa19_calc_baud,
.baudclk = KEYSPAN_USA19_BAUDCLK,
@@ -319,6 +330,7 @@ static const struct keyspan_device_details usa19qi_device_details = {
.inack_endpoints = {0x83},
.outcont_endpoints = {0x03},
.instat_endpoint = 0x84,
+ .indat_endpoint = -1,
.glocont_endpoint = -1,
.calculate_baud_rate = keyspan_usa28_calc_baud,
.baudclk = KEYSPAN_USA19_BAUDCLK,
@@ -335,6 +347,7 @@ static const struct keyspan_device_details mpr_device_details = {
.inack_endpoints = {0x83},
.outcont_endpoints = {0x03},
.instat_endpoint = 0x84,
+ .indat_endpoint = -1,
.glocont_endpoint = -1,
.calculate_baud_rate = keyspan_usa28_calc_baud,
.baudclk = KEYSPAN_USA19_BAUDCLK,
@@ -351,6 +364,7 @@ static const struct keyspan_device_details usa19qw_device_details = {
.inack_endpoints = {0x85},
.outcont_endpoints = {0x05},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa19w_calc_baud,
.baudclk = KEYSPAN_USA19W_BAUDCLK,
@@ -367,6 +381,7 @@ static const struct keyspan_device_details usa19w_device_details = {
.inack_endpoints = {0x85},
.outcont_endpoints = {0x05},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa19w_calc_baud,
.baudclk = KEYSPAN_USA19W_BAUDCLK,
@@ -383,6 +398,7 @@ static const struct keyspan_device_details usa19hs_device_details = {
.inack_endpoints = {-1},
.outcont_endpoints = {0x02},
.instat_endpoint = 0x82,
+ .indat_endpoint = -1,
.glocont_endpoint = -1,
.calculate_baud_rate = keyspan_usa19hs_calc_baud,
.baudclk = KEYSPAN_USA19HS_BAUDCLK,
@@ -399,6 +415,7 @@ static const struct keyspan_device_details usa28_device_details = {
.inack_endpoints = {0x85, 0x86},
.outcont_endpoints = {0x05, 0x06},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa28_calc_baud,
.baudclk = KEYSPAN_USA28_BAUDCLK,
@@ -415,6 +432,7 @@ static const struct keyspan_device_details usa28x_device_details = {
.inack_endpoints = {0x85, 0x86},
.outcont_endpoints = {0x05, 0x06},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa19w_calc_baud,
.baudclk = KEYSPAN_USA28X_BAUDCLK,
@@ -431,11 +449,28 @@ static const struct keyspan_device_details usa28xa_device_details = {
.inack_endpoints = {0x85, 0x86},
.outcont_endpoints = {0x05, 0x06},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa19w_calc_baud,
.baudclk = KEYSPAN_USA28X_BAUDCLK,
};
+static const struct keyspan_device_details usa28xg_device_details = {
+ .product_id = keyspan_usa28xg_product_id,
+ .msg_format = msg_usa67,
+ .num_ports = 2,
+ .indat_endp_flip = 0,
+ .outdat_endp_flip = 0,
+ .indat_endpoints = {0x84, 0x88},
+ .outdat_endpoints = {0x02, 0x06},
+ .inack_endpoints = {-1, -1},
+ .outcont_endpoints = {-1, -1},
+ .instat_endpoint = 0x81,
+ .indat_endpoint = -1,
+ .glocont_endpoint = 0x01,
+ .calculate_baud_rate = keyspan_usa19w_calc_baud,
+ .baudclk = KEYSPAN_USA28X_BAUDCLK,
+};
/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */
static const struct keyspan_device_details usa49w_device_details = {
@@ -449,6 +484,7 @@ static const struct keyspan_device_details usa49w_device_details = {
.inack_endpoints = {-1, -1, -1, -1},
.outcont_endpoints = {-1, -1, -1, -1},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa19w_calc_baud,
.baudclk = KEYSPAN_USA49W_BAUDCLK,
@@ -465,11 +501,29 @@ static const struct keyspan_device_details usa49wlc_device_details = {
.inack_endpoints = {-1, -1, -1, -1},
.outcont_endpoints = {-1, -1, -1, -1},
.instat_endpoint = 0x87,
+ .indat_endpoint = -1,
.glocont_endpoint = 0x07,
.calculate_baud_rate = keyspan_usa19w_calc_baud,
.baudclk = KEYSPAN_USA19W_BAUDCLK,
};
+static const struct keyspan_device_details usa49wg_device_details = {
+ .product_id = keyspan_usa49wg_product_id,
+ .msg_format = msg_usa49,
+ .num_ports = 4,
+ .indat_endp_flip = 0,
+ .outdat_endp_flip = 0,
+ .indat_endpoints = {-1, -1, -1, -1}, /* single 'global' data in EP */
+ .outdat_endpoints = {0x01, 0x02, 0x04, 0x06},
+ .inack_endpoints = {-1, -1, -1, -1},
+ .outcont_endpoints = {-1, -1, -1, -1},
+ .instat_endpoint = 0x81,
+ .indat_endpoint = 0x88,
+ .glocont_endpoint = 0x00, /* uses control EP */
+ .calculate_baud_rate = keyspan_usa19w_calc_baud,
+ .baudclk = KEYSPAN_USA19W_BAUDCLK,
+};
+
static const struct keyspan_device_details *keyspan_devices[] = {
&usa18x_device_details,
&usa19_device_details,
@@ -481,9 +535,11 @@ static const struct keyspan_device_details *keyspan_devices[] = {
&usa28_device_details,
&usa28x_device_details,
&usa28xa_device_details,
+ &usa28xg_device_details,
/* 28xb not required as it renumerates as a 28x */
&usa49w_device_details,
&usa49wlc_device_details,
+ &usa49wg_device_details,
NULL,
};
@@ -510,8 +566,11 @@ static struct usb_device_id keyspan_ids_combined[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
{ } /* Terminating entry */
};
@@ -557,12 +616,15 @@ static struct usb_device_id keyspan_2port_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) },
{ } /* Terminating entry */
};
static struct usb_device_id keyspan_4port_ids[] = {
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
+ { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
{ } /* Terminating entry */
};
@@ -573,7 +635,6 @@ static struct usb_serial_driver keyspan_pre_device = {
.name = "keyspan_no_firm",
},
.description = "Keyspan - (without firmware)",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_pre_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -588,7 +649,6 @@ static struct usb_serial_driver keyspan_1port_device = {
.name = "keyspan_1",
},
.description = "Keyspan 1 port adapter",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_1port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -616,7 +676,6 @@ static struct usb_serial_driver keyspan_2port_device = {
.name = "keyspan_2",
},
.description = "Keyspan 2 port adapter",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_2port_ids,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
@@ -644,11 +703,10 @@ static struct usb_serial_driver keyspan_4port_device = {
.name = "keyspan_4",
},
.description = "Keyspan 4 port adapter",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_4port_ids,
.num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 5,
- .num_bulk_out = 5,
+ .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 dd0b66a6ed5d..be9ac20a8f10 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -218,11 +218,12 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
struct tty_struct *tty = port->tty;
unsigned char *data = urb->transfer_buffer;
int i;
- int status;
+ int retval;
+ int status = urb->status;
struct keyspan_pda_private *priv;
priv = usb_get_serial_port_data(port);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -230,10 +231,12 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, status);
goto exit;
}
@@ -268,10 +271,10 @@ static void keyspan_pda_rx_interrupt (struct urb *urb)
}
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
diff --git a/drivers/usb/serial/keyspan_usa67msg.h b/drivers/usb/serial/keyspan_usa67msg.h
new file mode 100644
index 000000000000..20fa3e2f7187
--- /dev/null
+++ b/drivers/usb/serial/keyspan_usa67msg.h
@@ -0,0 +1,254 @@
+/*
+ usa67msg.h
+
+ Copyright (c) 1998-2007 InnoSys Incorporated. All Rights Reserved
+ This file is available under a BSD-style copyright
+
+ Keyspan USB Async Firmware to run on Anchor FX1
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain this licence text
+ without modification, this list of conditions, and the following
+ disclaimer. The following copyright notice must appear immediately at
+ the beginning of all source files:
+
+ Copyright (c) 1998-2007 InnoSys Incorporated. All Rights Reserved
+
+ This file is available under a BSD-style copyright
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of InnoSys Incorprated may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ Fourth revision: This message format supports the USA28XG
+
+ Buffer formats for RX/TX data messages are not defined by
+ a structure, but are described here:
+
+ USB OUT (host -> USAxx, transmit) messages contain a
+ REQUEST_ACK indicator (set to 0xff to request an ACK at the
+ completion of transmit; 0x00 otherwise), followed by data:
+
+ RQSTACK DAT DAT DAT ...
+
+ with a total data length of up to 63.
+
+ USB IN (USAxx -> host, receive) messages begin with a status
+ byte in which the 0x80 bit is either:
+
+ (a) 0x80 bit clear
+ indicates that the bytes following it are all data
+ bytes:
+
+ STAT DATA DATA DATA DATA DATA ...
+
+ for a total of up to 63 DATA bytes,
+
+ or:
+
+ (b) 0x80 bit set
+ indiates that the bytes following alternate data and
+ status bytes:
+
+ STAT DATA STAT DATA STAT DATA STAT DATA ...
+
+ for a total of up to 32 DATA bytes.
+
+ The valid bits in the STAT bytes are:
+
+ OVERRUN 0x02
+ PARITY 0x04
+ FRAMING 0x08
+ BREAK 0x10
+
+ Notes:
+
+ (1) The OVERRUN bit can appear in either (a) or (b) format
+ messages, but the but the PARITY/FRAMING/BREAK bits
+ only appear in (b) format messages.
+ (2) For the host to determine the exact point at which the
+ overrun occurred (to identify the point in the data
+ stream at which the data was lost), it needs to count
+ 128 characters, starting at the first character of the
+ message in which OVERRUN was reported; the lost character(s)
+ would have been received between the 128th and 129th
+ characters.
+ (3) An RX data message in which the first byte has 0x80 clear
+ serves as a "break off" indicator.
+
+ revision history:
+
+ 1999feb10 add reportHskiaChanges to allow us to ignore them
+ 1999feb10 add txAckThreshold for fast+loose throughput enhancement
+ 1999mar30 beef up support for RX error reporting
+ 1999apr14 add resetDataToggle to control message
+ 2000jan04 merge with usa17msg.h
+ 2000jun01 add extended BSD-style copyright text
+ 2001jul05 change message format to improve OVERRUN case
+ 2002jun05 update copyright date, improve comments
+ 2006feb06 modify for FX1 chip
+
+*/
+
+#ifndef __USA67MSG__
+#define __USA67MSG__
+
+
+// all things called "ControlMessage" are sent on the 'control' endpoint
+
+typedef struct keyspan_usa67_portControlMessage
+{
+ u8 port; // 0 or 1 (selects port)
+ /*
+ there are three types of "commands" sent in the control message:
+
+ 1. configuration changes which must be requested by setting
+ the corresponding "set" flag (and should only be requested
+ when necessary, to reduce overhead on the device):
+ */
+ u8 setClocking, // host requests baud rate be set
+ baudLo, // host does baud divisor calculation
+ baudHi, // baudHi is only used for first port (gives lower rates)
+ externalClock_txClocking,
+ // 0=internal, other=external
+
+ setLcr, // host requests lcr be set
+ lcr, // use PARITY, STOPBITS, DATABITS below
+
+ setFlowControl, // host requests flow control be set
+ ctsFlowControl, // 1=use CTS flow control, 0=don't
+ xonFlowControl, // 1=use XON/XOFF flow control, 0=don't
+ xonChar, // specified in current character format
+ xoffChar, // specified in current character format
+
+ setTxTriState_setRts,
+ // host requests TX tri-state be set
+ txTriState_rts, // 1=active (normal), 0=tristate (off)
+
+ setHskoa_setDtr,
+ // host requests HSKOA output be set
+ hskoa_dtr, // 1=on, 0=off
+
+ setPrescaler, // host requests prescalar be set (default: 13)
+ prescaler; // specified as N/8; values 8-ff are valid
+ // must be set any time internal baud rate is set;
+ // must not be set when external clocking is used
+
+ /*
+ 3. configuration data which is simply used as is (no overhead,
+ but must be specified correctly in every host message).
+ */
+ u8 forwardingLength, // forward when this number of chars available
+ reportHskiaChanges_dsrFlowControl,
+ // 1=normal; 0=ignore external clock
+ // 1=use DSR flow control, 0=don't
+ txAckThreshold, // 0=not allowed, 1=normal, 2-255 deliver ACK faster
+ loopbackMode; // 0=no loopback, 1=loopback enabled
+
+ /*
+ 4. commands which are flags only; these are processed in order
+ (so that, e.g., if both _txOn and _txOff flags are set, the
+ port ends in a TX_OFF state); any non-zero value is respected
+ */
+ u8 _txOn, // enable transmitting (and continue if there's data)
+ _txOff, // stop transmitting
+ txFlush, // toss outbound data
+ txBreak, // turn on break (cleared by _txOn)
+ rxOn, // turn on receiver
+ rxOff, // turn off receiver
+ rxFlush, // toss inbound data
+ rxForward, // forward all inbound data, NOW (as if fwdLen==1)
+ returnStatus, // return current status (even if it hasn't changed)
+ resetDataToggle;// reset data toggle state to DATA0
+
+} keyspan_usa67_portControlMessage;
+
+// defines for bits in lcr
+#define USA_DATABITS_5 0x00
+#define USA_DATABITS_6 0x01
+#define USA_DATABITS_7 0x02
+#define USA_DATABITS_8 0x03
+#define STOPBITS_5678_1 0x00 // 1 stop bit for all byte sizes
+#define STOPBITS_5_1p5 0x04 // 1.5 stop bits for 5-bit byte
+#define STOPBITS_678_2 0x04 // 2 stop bits for 6/7/8-bit byte
+#define USA_PARITY_NONE 0x00
+#define USA_PARITY_ODD 0x08
+#define USA_PARITY_EVEN 0x18
+#define PARITY_1 0x28
+#define PARITY_0 0x38
+
+// all things called "StatusMessage" are sent on the status endpoint
+
+typedef struct keyspan_usa67_portStatusMessage // one for each port
+{
+ u8 port, // 0=first, 1=second, other=see below
+ hskia_cts, // reports HSKIA pin
+ gpia_dcd, // reports GPIA pin
+ _txOff, // port has been disabled (by host)
+ _txXoff, // port is in XOFF state (either host or RX XOFF)
+ txAck, // indicates a TX message acknowledgement
+ rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off
+ controlResponse;// 1=a control message has been processed
+} keyspan_usa67_portStatusMessage;
+
+// bits in RX data message when STAT byte is included
+#define RXERROR_OVERRUN 0x02
+#define RXERROR_PARITY 0x04
+#define RXERROR_FRAMING 0x08
+#define RXERROR_BREAK 0x10
+
+typedef struct keyspan_usa67_globalControlMessage
+{
+ u8 port, // 3
+ sendGlobalStatus, // 2=request for two status responses
+ resetStatusToggle, // 1=reset global status toggle
+ resetStatusCount; // a cycling value
+} keyspan_usa67_globalControlMessage;
+
+typedef struct keyspan_usa67_globalStatusMessage
+{
+ u8 port, // 3
+ sendGlobalStatus, // from request, decremented
+ resetStatusCount; // as in request
+} keyspan_usa67_globalStatusMessage;
+
+typedef struct keyspan_usa67_globalDebugMessage
+{
+ u8 port, // 2
+ a,
+ b,
+ c,
+ d;
+} keyspan_usa67_globalDebugMessage;
+
+// ie: the maximum length of an FX1 endpoint buffer
+#define MAX_DATA_LEN 64
+
+// update status approx. 60 times a second (16.6666 ms)
+#define STATUS_UPDATE_INTERVAL 16
+
+// status rationing tuning value (each port gets checked each n ms)
+#define STATUS_RATION 10
+
+#endif
+
+
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 7b085f334ceb..5a4127e62c4a 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -567,12 +567,13 @@ exit:
static void klsi_105_write_bulk_callback ( struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (urb->status) {
+
+ if (status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
- urb->status);
+ status);
return;
}
@@ -631,16 +632,17 @@ static void klsi_105_read_bulk_callback (struct urb *urb)
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", __FUNCTION__, port->number);
/* The urb might have been killed. */
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__,
- urb->status);
- return;
- }
-
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d", __FUNCTION__,
+ status);
+ return;
+ }
+
/* The data received is again preceded by a length double-byte in LSB-
* first order (see klsi_105_write() )
*/
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 0683b51f0932..02a86dbc0e97 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -358,24 +358,26 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp)
}
-static void kobil_read_int_callback( struct urb *purb)
+static void kobil_read_int_callback(struct urb *urb)
{
int result;
- struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
+ struct usb_serial_port *port = urb->context;
struct tty_struct *tty;
- unsigned char *data = purb->transfer_buffer;
+ unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
// char *dbg_data;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (purb->status) {
- dbg("%s - port %d Read int status not zero: %d", __FUNCTION__, port->number, purb->status);
+ if (status) {
+ dbg("%s - port %d Read int status not zero: %d",
+ __FUNCTION__, port->number, status);
return;
}
-
- tty = port->tty;
- if (purb->actual_length) {
-
+
+ tty = port->tty;
+ if (urb->actual_length) {
+
// BEGIN DEBUG
/*
dbg_data = kzalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL);
@@ -390,15 +392,15 @@ static void kobil_read_int_callback( struct urb *purb)
*/
// END DEBUG
- tty_buffer_request_room(tty, purb->actual_length);
- tty_insert_flip_string(tty, data, purb->actual_length);
+ tty_buffer_request_room(tty, urb->actual_length);
+ tty_insert_flip_string(tty, data, urb->actual_length);
tty_flip_buffer_push(tty);
}
// someone sets the dev to 0 if the close method has been called
port->interrupt_in_urb->dev = port->serial->dev;
- result = usb_submit_urb( port->interrupt_in_urb, GFP_ATOMIC );
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
dbg("%s - port %d Send read URB returns: %i", __FUNCTION__, port->number, result);
}
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 3db1adc25f84..2a3fabcf5186 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -81,7 +81,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "z2.0" /* Linux in-kernel version */
+#define DRIVER_VERSION "z2.1" /* Linux in-kernel version */
#define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>"
#define DRIVER_DESC "Magic Control Technology USB-RS232 converter driver"
@@ -110,6 +110,10 @@ static int mct_u232_tiocmget (struct usb_serial_port *port,
static int mct_u232_tiocmset (struct usb_serial_port *port,
struct file *file, unsigned int set,
unsigned int clear);
+static void mct_u232_throttle (struct usb_serial_port *port);
+static void mct_u232_unthrottle (struct usb_serial_port *port);
+
+
/*
* All of the device info needed for the MCT USB-RS232 converter.
*/
@@ -145,6 +149,8 @@ static struct usb_serial_driver mct_u232_device = {
.num_ports = 1,
.open = mct_u232_open,
.close = mct_u232_close,
+ .throttle = mct_u232_throttle,
+ .unthrottle = mct_u232_unthrottle,
.read_int_callback = mct_u232_read_int_callback,
.ioctl = mct_u232_ioctl,
.set_termios = mct_u232_set_termios,
@@ -162,8 +168,11 @@ struct mct_u232_private {
unsigned char last_lcr; /* Line Control Register */
unsigned char last_lsr; /* Line Status Register */
unsigned char last_msr; /* Modem Status Register */
+ unsigned int rx_flags; /* Throttling flags */
};
+#define THROTTLED 0x01
+
/*
* Handle vendor specific USB requests
*/
@@ -216,11 +225,13 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value)
}
}
-static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
+static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_port *port,
+ int value)
{
__le32 divisor;
int rc;
unsigned char zero_byte = 0;
+ unsigned char cts_enable_byte = 0;
divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value));
@@ -238,10 +249,17 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
'baud rate change' message. The actual functionality of the
request codes in these messages is not fully understood but these
particular codes are never seen in any operation besides a baud
- rate change. Both of these messages send a single byte of data
- whose value is always zero. The second of these two extra messages
- is required in order for data to be properly written to an RS-232
- device which does not assert the 'CTS' signal. */
+ rate change. Both of these messages send a single byte of data.
+ In the first message, the value of this byte is always zero.
+
+ The second message has been determined experimentally to control
+ whether data will be transmitted to a device which is not asserting
+ the 'CTS' signal. If the second message's data byte is zero, data
+ will be transmitted even if 'CTS' is not asserted (i.e. no hardware
+ flow control). if the second message's data byte is nonzero (a value
+ of 1 is used by this driver), data will not be transmitted to a device
+ which is not asserting 'CTS'.
+ */
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
MCT_U232_SET_UNKNOWN1_REQUEST,
@@ -252,14 +270,19 @@ static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
err("Sending USB device request code %d failed (error = %d)",
MCT_U232_SET_UNKNOWN1_REQUEST, rc);
+ if (port && C_CRTSCTS(port->tty)) {
+ cts_enable_byte = 1;
+ }
+
+ dbg("set_baud_rate: send second control message, data = %02X", cts_enable_byte);
rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
- MCT_U232_SET_UNKNOWN2_REQUEST,
+ MCT_U232_SET_CTS_REQUEST,
MCT_U232_SET_REQUEST_TYPE,
- 0, 0, &zero_byte, MCT_U232_SET_UNKNOWN2_SIZE,
+ 0, 0, &cts_enable_byte, MCT_U232_SET_CTS_SIZE,
WDR_TIMEOUT);
if (rc < 0)
- err("Sending USB device request code %d failed (error = %d)",
- MCT_U232_SET_UNKNOWN2_REQUEST, rc);
+ err("Sending USB device request code %d failed (error = %d)",
+ MCT_U232_SET_CTS_REQUEST, rc);
return rc;
} /* mct_u232_set_baud_rate */
@@ -458,8 +481,25 @@ error:
static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
{
+ unsigned int c_cflag;
+ unsigned long flags;
+ unsigned int control_state;
+ struct mct_u232_private *priv = usb_get_serial_port_data(port);
dbg("%s port %d", __FUNCTION__, port->number);
+ if (port->tty) {
+ c_cflag = port->tty->termios->c_cflag;
+ if (c_cflag & HUPCL) {
+ /* drop DTR and RTS */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ control_state = priv->control_state;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ mct_u232_set_modem_ctrl(port->serial, control_state);
+ }
+ }
+
+
if (port->serial->dev) {
/* shutdown our urbs */
usb_kill_urb(port->write_urb);
@@ -476,10 +516,11 @@ static void mct_u232_read_int_callback (struct urb *urb)
struct usb_serial *serial = port->serial;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
- int status;
+ int retval;
+ int status = urb->status;
unsigned long flags;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -487,10 +528,12 @@ static void mct_u232_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__, urb->status);
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, status);
goto exit;
}
@@ -554,10 +597,10 @@ static void mct_u232_read_int_callback (struct urb *urb)
#endif
spin_unlock_irqrestore(&priv->lock, flags);
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
} /* mct_u232_read_int_callback */
static void mct_u232_set_termios (struct usb_serial_port *port,
@@ -565,11 +608,10 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
{
struct usb_serial *serial = port->serial;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- unsigned int iflag = port->tty->termios->c_iflag;
unsigned int cflag = port->tty->termios->c_cflag;
unsigned int old_cflag = old_termios->c_cflag;
unsigned long flags;
- unsigned int control_state, new_state;
+ unsigned int control_state;
unsigned char last_lcr;
/* get a local copy of the current port settings */
@@ -585,18 +627,14 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
* Premature optimization is the root of all evil.
*/
- /* reassert DTR and (maybe) RTS on transition from B0 */
+ /* reassert DTR and RTS on transition from B0 */
if ((old_cflag & CBAUD) == B0) {
dbg("%s: baud was B0", __FUNCTION__);
- control_state |= TIOCM_DTR;
- /* don't set RTS if using hardware flow control */
- if (!(old_cflag & CRTSCTS)) {
- control_state |= TIOCM_RTS;
- }
+ control_state |= TIOCM_DTR | TIOCM_RTS;
mct_u232_set_modem_ctrl(serial, control_state);
}
- mct_u232_set_baud_rate(serial, cflag & CBAUD);
+ mct_u232_set_baud_rate(serial, port, cflag & CBAUD);
if ((cflag & CBAUD) == B0 ) {
dbg("%s: baud is B0", __FUNCTION__);
@@ -638,21 +676,6 @@ static void mct_u232_set_termios (struct usb_serial_port *port,
mct_u232_set_line_ctrl(serial, last_lcr);
- /*
- * Set flow control: well, I do not really now how to handle DTR/RTS.
- * Just do what we have seen with SniffUSB on Win98.
- */
- /* Drop DTR/RTS if no flow control otherwise assert */
- new_state = control_state;
- if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
- new_state |= TIOCM_DTR | TIOCM_RTS;
- else
- new_state &= ~(TIOCM_DTR | TIOCM_RTS);
- if (new_state != control_state) {
- mct_u232_set_modem_ctrl(serial, new_state);
- control_state = new_state;
- }
-
/* save off the modified port settings */
spin_lock_irqsave(&priv->lock, flags);
priv->control_state = control_state;
@@ -747,6 +770,50 @@ static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
return 0;
} /* mct_u232_ioctl */
+static void mct_u232_throttle (struct usb_serial_port *port)
+{
+ struct mct_u232_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int control_state;
+ struct tty_struct *tty;
+
+ tty = port->tty;
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->rx_flags |= THROTTLED;
+ if (C_CRTSCTS(tty)) {
+ priv->control_state &= ~TIOCM_RTS;
+ control_state = priv->control_state;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ (void) mct_u232_set_modem_ctrl(port->serial, control_state);
+ } else {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+}
+
+
+static void mct_u232_unthrottle (struct usb_serial_port *port)
+{
+ struct mct_u232_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int control_state;
+ struct tty_struct *tty;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ tty = port->tty;
+ spin_lock_irqsave(&priv->lock, flags);
+ if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
+ priv->rx_flags &= ~THROTTLED;
+ priv->control_state |= TIOCM_RTS;
+ control_state = priv->control_state;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ (void) mct_u232_set_modem_ctrl(port->serial, control_state);
+ } else {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+}
static int __init mct_u232_init (void)
{
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index 73dd0d984cd3..a61bac8f224a 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -63,14 +63,15 @@
#define MCT_U232_SET_UNKNOWN1_REQUEST 11 /* Unknown functionality */
#define MCT_U232_SET_UNKNOWN1_SIZE 1
-/* This USB device request code is not well understood. It is transmitted by
- the MCT-supplied Windows driver whenever the baud rate changes.
+/* This USB device request code appears to control whether CTS is required
+ during transmission.
- Without this USB device request, the USB/RS-232 adapter will not write to
- RS-232 devices which do not assert the 'CTS' signal.
+ Sending a zero byte allows data transmission to a device which is not
+ asserting CTS. Sending a '1' byte will cause transmission to be deferred
+ until the device asserts CTS.
*/
-#define MCT_U232_SET_UNKNOWN2_REQUEST 12 /* Unknown functionality */
-#define MCT_U232_SET_UNKNOWN2_SIZE 1
+#define MCT_U232_SET_CTS_REQUEST 12
+#define MCT_U232_SET_CTS_SIZE 1
/*
* Baud rate (divisor)
@@ -439,7 +440,7 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value);
* which says "U232-P9" ;-)
*
* The circuit board inside the adaptor contains a Philips PDIUSBD12
- * USB endpoint chip and a Phillips P87C52UBAA microcontroller with
+ * USB endpoint chip and a Philips P87C52UBAA microcontroller with
* embedded UART. Exhaustive documentation for these is available at:
*
* http://www.semiconductors.philips.com/pip/p87c52ubaa
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index b563e2ad8728..01e811becec4 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -9,9 +9,9 @@
* the Free Software Foundation, version 2 of the License.
*
* Developed by:
- * VijayaKumar.G.N. <vijaykumar@aspirecom.net>
- * AjayKumar <ajay@aspirecom.net>
- * Gurudeva.N. <gurudev@aspirecom.net>
+ * Vijaya Kumar <vijaykumar.gn@gmail.com>
+ * Ajay Kumar <naanuajay@yahoo.com>
+ * Gurudeva <ngurudeva@yahoo.com>
*
* Cleaned up from the original by:
* Greg Kroah-Hartman <gregkh@suse.de>
@@ -103,18 +103,14 @@ static void mos7720_interrupt_callback(struct urb *urb)
{
int result;
int length;
+ int status = urb->status;
__u8 *data;
__u8 sp1;
__u8 sp2;
dbg("%s"," : Entering\n");
- if (!urb) {
- dbg("%s","Invalid Pointer !!!!:\n");
- return;
- }
-
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -123,11 +119,11 @@ static void mos7720_interrupt_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__,
- urb->status);
+ status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__,
- urb->status);
+ status);
goto exit;
}
@@ -198,14 +194,15 @@ exit:
*/
static void mos7720_bulk_in_callback(struct urb *urb)
{
- int status;
+ int retval;
unsigned char *data ;
struct usb_serial_port *port;
struct moschip_port *mos7720_port;
struct tty_struct *tty;
+ int status = urb->status;
- if (urb->status) {
- dbg("nonzero read bulk status received: %d",urb->status);
+ if (status) {
+ dbg("nonzero read bulk status received: %d", status);
return;
}
@@ -236,10 +233,10 @@ static void mos7720_bulk_in_callback(struct urb *urb)
if (port->read_urb->status != -EINPROGRESS) {
port->read_urb->dev = port->serial->dev;
- status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (status)
- dbg("usb_submit_urb(read bulk) failed, status = %d",
- status);
+ retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (retval)
+ dbg("usb_submit_urb(read bulk) failed, retval = %d",
+ retval);
}
}
@@ -252,9 +249,10 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
{
struct moschip_port *mos7720_port;
struct tty_struct *tty;
+ int status = urb->status;
- if (urb->status) {
- dbg("nonzero write bulk status received:%d", urb->status);
+ if (status) {
+ dbg("nonzero write bulk status received:%d", status);
return;
}
@@ -1235,16 +1233,6 @@ static void mos7720_set_termios(struct usb_serial_port *port,
return;
}
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) ==
- RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("Nothing to change");
- return;
- }
- }
-
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag,
RELEVANT_IFLAG(tty->termios->c_iflag));
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 36620c651079..f76480f1455d 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -434,15 +434,11 @@ static void mos7840_control_callback(struct urb *urb)
struct moschip_port *mos7840_port;
__u8 regval = 0x0;
int result = 0;
-
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
+ int status = urb->status;
mos7840_port = (struct moschip_port *)urb->context;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -451,11 +447,11 @@ static void mos7840_control_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__,
- urb->status);
+ status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__,
- urb->status);
+ status);
goto exit;
}
@@ -521,14 +517,11 @@ static void mos7840_interrupt_callback(struct urb *urb)
__u8 sp[5], st;
int i, rv = 0;
__u16 wval, wreg = 0;
+ int status = urb->status;
dbg("%s", " : Entering\n");
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -537,11 +530,11 @@ static void mos7840_interrupt_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__,
- urb->status);
+ status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__,
- urb->status);
+ status);
goto exit;
}
@@ -666,20 +659,16 @@ static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port,
static void mos7840_bulk_in_callback(struct urb *urb)
{
- int status;
+ int retval;
unsigned char *data;
struct usb_serial *serial;
struct usb_serial_port *port;
struct moschip_port *mos7840_port;
struct tty_struct *tty;
+ int status = urb->status;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
- if (urb->status) {
- dbg("nonzero read bulk status received: %d", urb->status);
+ if (status) {
+ dbg("nonzero read bulk status received: %d", status);
return;
}
@@ -729,11 +718,11 @@ static void mos7840_bulk_in_callback(struct urb *urb)
mos7840_port->read_urb->dev = serial->dev;
- status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+ retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
- if (status) {
- dbg(" usb_submit_urb(read bulk) failed, status = %d",
- status);
+ if (retval) {
+ dbg(" usb_submit_urb(read bulk) failed, retval = %d",
+ retval);
}
}
@@ -747,13 +736,9 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
{
struct moschip_port *mos7840_port;
struct tty_struct *tty;
+ int status = urb->status;
int i;
- if (!urb) {
- dbg("%s", "Invalid Pointer !!!!:\n");
- return;
- }
-
mos7840_port = (struct moschip_port *)urb->context;
spin_lock(&mos7840_port->pool_lock);
for (i = 0; i < NUM_URBS; i++) {
@@ -764,8 +749,8 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
}
spin_unlock(&mos7840_port->pool_lock);
- if (urb->status) {
- dbg("nonzero write bulk status received:%d\n", urb->status);
+ if (status) {
+ dbg("nonzero write bulk status received:%d\n", status);
return;
}
@@ -2185,16 +2170,6 @@ static void mos7840_set_termios(struct usb_serial_port *port,
return;
}
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(tty->termios->c_iflag) ==
- RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s\n", "Nothing to change");
- return;
- }
- }
-
dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
@@ -2254,30 +2229,6 @@ static int mos7840_get_lsr_info(struct moschip_port *mos7840_port,
}
/*****************************************************************************
- * mos7840_get_bytes_avail - get number of bytes available
- *
- * Purpose: Let user call ioctl to get the count of number of bytes available.
- *****************************************************************************/
-
-static int mos7840_get_bytes_avail(struct moschip_port *mos7840_port,
- unsigned int __user *value)
-{
- unsigned int result = 0;
- struct tty_struct *tty = mos7840_port->port->tty;
-
- if (!tty)
- return -ENOIOCTLCMD;
-
- result = tty->read_cnt;
-
- dbg("%s(%d) = %d", __FUNCTION__, mos7840_port->port->number, result);
- if (copy_to_user(value, &result, sizeof(int)))
- return -EFAULT;
-
- return -ENOIOCTLCMD;
-}
-
-/*****************************************************************************
* mos7840_set_modem_info
* function to set modem info
*****************************************************************************/
@@ -2425,8 +2376,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
struct async_icount cprev;
struct serial_icounter_struct icount;
int mosret = 0;
- int retval;
- struct tty_ldisc *ld;
if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
dbg("%s", "Invalid port \n");
@@ -2445,42 +2394,6 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
switch (cmd) {
/* return number of bytes available */
- case TIOCINQ:
- dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
- return mos7840_get_bytes_avail(mos7840_port, argp);
-
- case TIOCOUTQ:
- dbg("%s (%d) TIOCOUTQ", __FUNCTION__, port->number);
- return put_user(tty->driver->chars_in_buffer ?
- tty->driver->chars_in_buffer(tty) : 0,
- (int __user *)arg);
-
- case TCFLSH:
- retval = tty_check_change(tty);
- if (retval)
- return retval;
-
- ld = tty_ldisc_ref(tty);
- switch (arg) {
- case TCIFLUSH:
- if (ld && ld->flush_buffer)
- ld->flush_buffer(tty);
- break;
- case TCIOFLUSH:
- if (ld && ld->flush_buffer)
- ld->flush_buffer(tty);
- /* fall through */
- case TCOFLUSH:
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- break;
- default:
- tty_ldisc_deref(ld);
- return -EINVAL;
- }
- tty_ldisc_deref(ld);
- return 0;
-
case TIOCSERGETLSR:
dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
return mos7840_get_lsr_info(mos7840_port, argp);
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 90701111d746..7f337c9aeb5f 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -37,9 +37,10 @@ static void navman_read_int_callback(struct urb *urb)
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
+ int status = urb->status;
int result;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -48,11 +49,11 @@ 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__, urb->status);
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
goto exit;
}
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 00afc1712c39..ee94d9616d82 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -1,10 +1,9 @@
/*
* USB ZyXEL omni.net LCD PLUS driver
*
- * 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 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.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
@@ -201,14 +200,15 @@ static void omninet_read_bulk_callback (struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_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);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -312,12 +312,14 @@ 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;
+ int status = urb->status;
dbg("%s - port %0x\n", __FUNCTION__, port->number);
port->write_urb_busy = 0;
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
return;
}
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 5d3999e3ff61..84c12b5f1271 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -38,6 +38,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
+#include <linux/bitops.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
@@ -240,6 +241,7 @@ struct option_port_private {
/* Output endpoints and buffer for this port */
struct urb *out_urbs[N_OUT_URB];
char out_buffer[N_OUT_URB][OUT_BUFLEN];
+ unsigned long out_busy; /* Bit vector of URBs in use */
/* Settings for the port */
int rts_state; /* Handshaking pins (outputs) */
@@ -370,7 +372,7 @@ static int option_write(struct usb_serial_port *port,
todo = OUT_BUFLEN;
this_urb = portdata->out_urbs[i];
- if (this_urb->status == -EINPROGRESS) {
+ if (test_and_set_bit(i, &portdata->out_busy)) {
if (time_before(jiffies,
portdata->tx_start_time[i] + 10 * HZ))
continue;
@@ -394,6 +396,7 @@ static int option_write(struct usb_serial_port *port,
dbg("usb_submit_urb %p (write bulk) failed "
"(%d, has %d)", this_urb,
err, this_urb->status);
+ clear_bit(i, &portdata->out_busy);
continue;
}
portdata->tx_start_time[i] = jiffies;
@@ -413,15 +416,16 @@ static void option_indat_callback(struct urb *urb)
struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
dbg("%s: %p", __FUNCTION__, urb);
endpoint = usb_pipeendpoint(urb->pipe);
port = (struct usb_serial_port *) urb->context;
- if (urb->status) {
+ if (status) {
dbg("%s: nonzero status: %d on endpoint %02x.",
- __FUNCTION__, urb->status, endpoint);
+ __FUNCTION__, status, endpoint);
} else {
tty = port->tty;
if (urb->actual_length) {
@@ -433,7 +437,7 @@ static void option_indat_callback(struct urb *urb)
}
/* Resubmit urb so we continue receiving */
- if (port->open_count && urb->status != -ESHUTDOWN) {
+ if (port->open_count && status != -ESHUTDOWN) {
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
printk(KERN_ERR "%s: resubmit read urb failed. "
@@ -446,17 +450,29 @@ static void option_indat_callback(struct urb *urb)
static void option_outdat_callback(struct urb *urb)
{
struct usb_serial_port *port;
+ struct option_port_private *portdata;
+ int i;
dbg("%s", __FUNCTION__);
port = (struct usb_serial_port *) urb->context;
usb_serial_port_softint(port);
+
+ portdata = usb_get_serial_port_data(port);
+ for (i = 0; i < N_OUT_URB; ++i) {
+ if (portdata->out_urbs[i] == urb) {
+ smp_mb__before_clear_bit();
+ clear_bit(i, &portdata->out_busy);
+ break;
+ }
+ }
}
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 option_port_private *portdata = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
@@ -464,7 +480,7 @@ static void option_instat_callback(struct urb *urb)
dbg("%s", __FUNCTION__);
dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
- if (urb->status == 0) {
+ if (status == 0) {
struct usb_ctrlrequest *req_pkt =
(struct usb_ctrlrequest *)urb->transfer_buffer;
@@ -495,10 +511,10 @@ static void option_instat_callback(struct urb *urb)
req_pkt->bRequestType,req_pkt->bRequest);
}
} else
- dbg("%s: error %d", __FUNCTION__, urb->status);
+ dbg("%s: error %d", __FUNCTION__, status);
/* Resubmit urb so we continue receiving IRQ data */
- if (urb->status != -ESHUTDOWN) {
+ if (status != -ESHUTDOWN) {
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
@@ -518,7 +534,7 @@ static int option_write_room(struct usb_serial_port *port)
for (i=0; i < N_OUT_URB; i++) {
this_urb = portdata->out_urbs[i];
- if (this_urb && this_urb->status != -EINPROGRESS)
+ if (this_urb && !test_bit(i, &portdata->out_busy))
data_len += OUT_BUFLEN;
}
@@ -537,7 +553,7 @@ 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];
- if (this_urb && this_urb->status == -EINPROGRESS)
+ if (this_urb && test_bit(i, &portdata->out_busy))
data_len += this_urb->transfer_buffer_length;
}
dbg("%s: %d", __FUNCTION__, data_len);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
new file mode 100644
index 000000000000..d7db71eca520
--- /dev/null
+++ b/drivers/usb/serial/oti6858.c
@@ -0,0 +1,1342 @@
+/*
+ * Ours Technology Inc. OTi-6858 USB to serial adapter driver.
+ *
+ * Copyleft (C) 2007 Kees Lemmens (adapted for kernel 2.6.20)
+ * Copyright (C) 2006 Tomasz Michal Lukaszewski (FIXME: add e-mail)
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2003 IBM Corp.
+ *
+ * Many thanks to the authors of pl2303 driver: all functions in this file
+ * are heavily based on pl2303 code, buffering code is a 1-to-1 copy.
+ *
+ * Warning! You use this driver on your own risk! The only official
+ * description of this device I have is datasheet from manufacturer,
+ * and it doesn't contain almost any information needed to write a driver.
+ * Almost all knowlegde used while writing this driver was gathered by:
+ * - analyzing traffic between device and the M$ Windows 2000 driver,
+ * - trying different bit combinations and checking pin states
+ * with a voltmeter,
+ * - receiving malformed frames and producing buffer overflows
+ * to learn how errors are reported,
+ * So, THIS CODE CAN DESTROY OTi-6858 AND ANY OTHER DEVICES, THAT ARE
+ * CONNECTED TO IT!
+ *
+ * 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.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * TODO:
+ * - implement correct flushing for ioctls and oti6858_close()
+ * - check how errors (rx overflow, parity error, framing error) are reported
+ * - implement oti6858_break_ctl()
+ * - implement more ioctls
+ * - test/implement flow control
+ * - allow setting custom baud rates
+ */
+
+#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/serial.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <asm/uaccess.h>
+#include "oti6858.h"
+
+#define OTI6858_DESCRIPTION \
+ "Ours Technology Inc. OTi-6858 USB to serial adapter driver"
+#define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>"
+#define OTI6858_VERSION "0.1"
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver oti6858_driver = {
+ .name = "oti6858",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+static int debug;
+
+
+/* buffering code, copied from pl2303 driver */
+#define PL2303_BUF_SIZE 1024
+#define PL2303_TMP_BUF_SIZE 1024
+
+struct pl2303_buf {
+ unsigned int buf_size;
+ char *buf_buf;
+ char *buf_get;
+ char *buf_put;
+};
+
+/* requests */
+#define OTI6858_REQ_GET_STATUS (USB_DIR_IN | USB_TYPE_VENDOR | 0x00)
+#define OTI6858_REQ_T_GET_STATUS 0x01
+
+#define OTI6858_REQ_SET_LINE (USB_DIR_OUT | USB_TYPE_VENDOR | 0x00)
+#define OTI6858_REQ_T_SET_LINE 0x00
+
+#define OTI6858_REQ_CHECK_TXBUFF (USB_DIR_IN | USB_TYPE_VENDOR | 0x01)
+#define OTI6858_REQ_T_CHECK_TXBUFF 0x00
+
+/* format of the control packet */
+struct oti6858_control_pkt {
+ u16 divisor; /* baud rate = 96000000 / (16 * divisor), LE */
+#define OTI6858_MAX_BAUD_RATE 3000000
+ u8 frame_fmt;
+#define FMT_STOP_BITS_MASK 0xc0
+#define FMT_STOP_BITS_1 0x00
+#define FMT_STOP_BITS_2 0x40 /* 1.5 stop bits if FMT_DATA_BITS_5 */
+#define FMT_PARITY_MASK 0x38
+#define FMT_PARITY_NONE 0x00
+#define FMT_PARITY_ODD 0x08
+#define FMT_PARITY_EVEN 0x18
+#define FMT_PARITY_MARK 0x28
+#define FMT_PARITY_SPACE 0x38
+#define FMT_DATA_BITS_MASK 0x03
+#define FMT_DATA_BITS_5 0x00
+#define FMT_DATA_BITS_6 0x01
+#define FMT_DATA_BITS_7 0x02
+#define FMT_DATA_BITS_8 0x03
+ u8 something; /* always equals 0x43 */
+ u8 control; /* settings of flow control lines */
+#define CONTROL_MASK 0x0c
+#define CONTROL_DTR_HIGH 0x08
+#define CONTROL_RTS_HIGH 0x04
+ u8 tx_status;
+#define TX_BUFFER_EMPTIED 0x09
+ u8 pin_state;
+#define PIN_MASK 0x3f
+#define PIN_RTS 0x20 /* output pin */
+#define PIN_CTS 0x10 /* input pin, active low */
+#define PIN_DSR 0x08 /* input pin, active low */
+#define PIN_DTR 0x04 /* output pin */
+#define PIN_RI 0x02 /* input pin, active low */
+#define PIN_DCD 0x01 /* input pin, active low */
+ u8 rx_bytes_avail; /* number of bytes in rx buffer */;
+};
+
+#define OTI6858_CTRL_PKT_SIZE sizeof(struct oti6858_control_pkt)
+#define OTI6858_CTRL_EQUALS_PENDING(a, priv) \
+ ( ((a)->divisor == (priv)->pending_setup.divisor) \
+ && ((a)->control == (priv)->pending_setup.control) \
+ && ((a)->frame_fmt == (priv)->pending_setup.frame_fmt) )
+
+/* function prototypes */
+static int oti6858_open(struct usb_serial_port *port, struct file *filp);
+static void oti6858_close(struct usb_serial_port *port, struct file *filp);
+static void oti6858_set_termios(struct usb_serial_port *port,
+ struct ktermios *old);
+static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg);
+static void oti6858_read_int_callback(struct urb *urb);
+static void oti6858_read_bulk_callback(struct urb *urb);
+static void oti6858_write_bulk_callback(struct urb *urb);
+static int oti6858_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count);
+static int oti6858_write_room(struct usb_serial_port *port);
+static void oti6858_break_ctl(struct usb_serial_port *port, int break_state);
+static int oti6858_chars_in_buffer(struct usb_serial_port *port);
+static int oti6858_tiocmget(struct usb_serial_port *port, struct file *file);
+static int oti6858_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear);
+static int oti6858_startup(struct usb_serial *serial);
+static void oti6858_shutdown(struct usb_serial *serial);
+
+/* functions operating on buffers */
+static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
+static void pl2303_buf_free(struct pl2303_buf *pb);
+static void pl2303_buf_clear(struct pl2303_buf *pb);
+static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
+static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
+static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+ unsigned int count);
+static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ unsigned int count);
+
+
+/* device info */
+static struct usb_serial_driver oti6858_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .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,
+ .write = oti6858_write,
+ .ioctl = oti6858_ioctl,
+ .break_ctl = oti6858_break_ctl,
+ .set_termios = oti6858_set_termios,
+ .tiocmget = oti6858_tiocmget,
+ .tiocmset = oti6858_tiocmset,
+ .read_bulk_callback = oti6858_read_bulk_callback,
+ .read_int_callback = oti6858_read_int_callback,
+ .write_bulk_callback = oti6858_write_bulk_callback,
+ .write_room = oti6858_write_room,
+ .chars_in_buffer = oti6858_chars_in_buffer,
+ .attach = oti6858_startup,
+ .shutdown = oti6858_shutdown,
+};
+
+struct oti6858_private {
+ spinlock_t lock;
+
+ struct pl2303_buf *buf;
+ struct oti6858_control_pkt status;
+
+ struct {
+ u8 read_urb_in_use;
+ u8 write_urb_in_use;
+ u8 termios_initialized;
+ } flags;
+ struct delayed_work delayed_write_work;
+
+ struct {
+ u16 divisor;
+ u8 frame_fmt;
+ u8 control;
+ } pending_setup;
+ u8 transient;
+ u8 setup_done;
+ struct delayed_work delayed_setup_work;
+
+ wait_queue_head_t intr_wait;
+ struct usb_serial_port *port; /* USB port with which associated */
+};
+
+#undef dbg
+/* #define dbg(format, arg...) printk(KERN_INFO "%s: " format "\n", __FILE__, ## arg) */
+#define dbg(format, arg...) printk(KERN_INFO "" format "\n", ## arg)
+
+static void setup_line(struct work_struct *work)
+{
+ struct oti6858_private *priv = container_of(work, struct oti6858_private, delayed_setup_work.work);
+ struct usb_serial_port *port = priv->port;
+ struct oti6858_control_pkt *new_setup;
+ unsigned long flags;
+ int result;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ if ((new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL)) == NULL) {
+ dev_err(&port->dev, "%s(): out of memory!\n", __FUNCTION__);
+ /* we will try again */
+ schedule_delayed_work(&priv->delayed_setup_work, msecs_to_jiffies(2));
+ return;
+ }
+
+ result = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ OTI6858_REQ_T_GET_STATUS,
+ OTI6858_REQ_GET_STATUS,
+ 0, 0,
+ new_setup, OTI6858_CTRL_PKT_SIZE,
+ 100);
+
+ if (result != OTI6858_CTRL_PKT_SIZE) {
+ dev_err(&port->dev, "%s(): error reading status", __FUNCTION__);
+ kfree(new_setup);
+ /* we will try again */
+ schedule_delayed_work(&priv->delayed_setup_work, msecs_to_jiffies(2));
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!OTI6858_CTRL_EQUALS_PENDING(new_setup, priv)) {
+ new_setup->divisor = priv->pending_setup.divisor;
+ new_setup->control = priv->pending_setup.control;
+ new_setup->frame_fmt = priv->pending_setup.frame_fmt;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ result = usb_control_msg(port->serial->dev,
+ usb_sndctrlpipe(port->serial->dev, 0),
+ OTI6858_REQ_T_SET_LINE,
+ OTI6858_REQ_SET_LINE,
+ 0, 0,
+ new_setup, OTI6858_CTRL_PKT_SIZE,
+ 100);
+ } else {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ result = 0;
+ }
+ kfree(new_setup);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (result != OTI6858_CTRL_PKT_SIZE)
+ priv->transient = 0;
+ priv->setup_done = 1;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ 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);
+ }
+}
+
+void send_data(struct work_struct *work)
+{
+ struct oti6858_private *priv = container_of(work, struct oti6858_private, delayed_write_work.work);
+ struct usb_serial_port *port = priv->port;
+ int count = 0, result;
+ unsigned long flags;
+ unsigned char allow;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->flags.write_urb_in_use) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ schedule_delayed_work(&priv->delayed_write_work, msecs_to_jiffies(2));
+ return;
+ }
+ priv->flags.write_urb_in_use = 1;
+
+ count = pl2303_buf_data_avail(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (count > port->bulk_out_size)
+ count = port->bulk_out_size;
+
+ if (count != 0) {
+ result = usb_control_msg(port->serial->dev,
+ usb_rcvctrlpipe(port->serial->dev, 0),
+ OTI6858_REQ_T_CHECK_TXBUFF,
+ OTI6858_REQ_CHECK_TXBUFF,
+ count, 0, &allow, 1, 100);
+ if (result != 1 || allow != 0)
+ count = 0;
+ }
+
+ if (count == 0) {
+ priv->flags.write_urb_in_use = 0;
+
+ dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ 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);
+ }
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer, count);
+ 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 != 0) {
+ dev_err(&port->dev, "%s(): usb_submit_urb() failed"
+ " with error %d\n", __FUNCTION__, result);
+ priv->flags.write_urb_in_use = 0;
+ }
+
+ usb_serial_port_softint(port);
+}
+
+static int oti6858_startup(struct usb_serial *serial)
+{
+ struct usb_serial_port *port = serial->port[0];
+ struct oti6858_private *priv;
+ int i;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ priv = kzalloc(sizeof(struct oti6858_private), GFP_KERNEL);
+ if (!priv)
+ break;
+ priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
+ if (priv->buf == NULL) {
+ kfree(priv);
+ break;
+ }
+
+ spin_lock_init(&priv->lock);
+ init_waitqueue_head(&priv->intr_wait);
+// INIT_WORK(&priv->setup_work, setup_line, serial->port[i]);
+// INIT_WORK(&priv->write_work, send_data, serial->port[i]);
+ priv->port = port;
+ INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line);
+ INIT_DELAYED_WORK(&priv->delayed_write_work, send_data);
+
+ usb_set_serial_port_data(serial->port[i], priv);
+ }
+ if (i == serial->num_ports)
+ return 0;
+
+ for (--i; i >= 0; --i) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ pl2303_buf_free(priv->buf);
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ return -ENOMEM;
+}
+
+static int oti6858_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s(port = %d, count = %d)", __FUNCTION__, port->number, count);
+
+ if (!count)
+ return count;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ count = pl2303_buf_put(priv->buf, buf, count);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return count;
+}
+
+static int oti6858_write_room(struct usb_serial_port *port)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ int room = 0;
+ unsigned long flags;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ room = pl2303_buf_space_avail(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return room;
+}
+
+static int oti6858_chars_in_buffer(struct usb_serial_port *port)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ int chars = 0;
+ unsigned long flags;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ chars = pl2303_buf_data_avail(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return chars;
+}
+
+static void oti6858_set_termios(struct usb_serial_port *port,
+ struct ktermios *old_termios)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int cflag;
+ u8 frame_fmt, control;
+ u16 divisor;
+ int br;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ if ((!port->tty) || (!port->tty->termios)) {
+ dbg("%s(): no tty structures", __FUNCTION__);
+ return;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->flags.termios_initialized) {
+ *(port->tty->termios) = tty_std_termios;
+ port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ priv->flags.termios_initialized = 1;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ cflag = port->tty->termios->c_cflag;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ divisor = priv->pending_setup.divisor;
+ frame_fmt = priv->pending_setup.frame_fmt;
+ control = priv->pending_setup.control;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ frame_fmt &= ~FMT_DATA_BITS_MASK;
+ switch (cflag & CSIZE) {
+ case CS5:
+ frame_fmt |= FMT_DATA_BITS_5;
+ break;
+ case CS6:
+ frame_fmt |= FMT_DATA_BITS_6;
+ break;
+ case CS7:
+ frame_fmt |= FMT_DATA_BITS_7;
+ break;
+ default:
+ case CS8:
+ frame_fmt |= FMT_DATA_BITS_8;
+ break;
+ }
+
+ /* manufacturer claims that this device can work with baud rates
+ * up to 3 Mbps; I've tested it only on 115200 bps, so I can't
+ * guarantee that any other baud rate will work (especially
+ * the higher ones)
+ */
+ br = tty_get_baud_rate(port->tty);
+ if (br == 0) {
+ divisor = 0;
+ } else if (br <= OTI6858_MAX_BAUD_RATE) {
+ int real_br;
+
+ divisor = (96000000 + 8 * br) / (16 * br);
+ real_br = 96000000 / (16 * divisor);
+ if ((((real_br - br) * 100 + br - 1) / br) > 2) {
+ dbg("%s(): baud rate %d is invalid", __FUNCTION__, br);
+ return;
+ }
+ divisor = cpu_to_le16(divisor);
+ } else {
+ dbg("%s(): baud rate %d is too high", __FUNCTION__, br);
+ return;
+ }
+
+ frame_fmt &= ~FMT_STOP_BITS_MASK;
+ if ((cflag & CSTOPB) != 0) {
+ frame_fmt |= FMT_STOP_BITS_2;
+ } else {
+ frame_fmt |= FMT_STOP_BITS_1;
+ }
+
+ frame_fmt &= ~FMT_PARITY_MASK;
+ if ((cflag & PARENB) != 0) {
+ if ((cflag & PARODD) != 0) {
+ frame_fmt |= FMT_PARITY_ODD;
+ } else {
+ frame_fmt |= FMT_PARITY_EVEN;
+ }
+ } else {
+ frame_fmt |= FMT_PARITY_NONE;
+ }
+
+ control &= ~CONTROL_MASK;
+ if ((cflag & CRTSCTS) != 0)
+ control |= (CONTROL_DTR_HIGH | CONTROL_RTS_HIGH);
+
+ /* change control lines if we are switching to or from B0 */
+ /* FIXME:
+ spin_lock_irqsave(&priv->lock, flags);
+ control = priv->line_control;
+ if ((cflag & CBAUD) == B0)
+ priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
+ else
+ priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
+ if (control != priv->line_control) {
+ control = priv->line_control;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ set_control_lines(serial->dev, control);
+ } else {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (divisor != priv->pending_setup.divisor
+ || control != priv->pending_setup.control
+ || frame_fmt != priv->pending_setup.frame_fmt) {
+ priv->pending_setup.divisor = divisor;
+ priv->pending_setup.control = control;
+ priv->pending_setup.frame_fmt = frame_fmt;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int oti6858_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ struct ktermios tmp_termios;
+ struct usb_serial *serial = port->serial;
+ struct oti6858_control_pkt *buf;
+ unsigned long flags;
+ int result;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ if (port->open_count != 1)
+ return 0;
+
+ if ((buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL)) == NULL) {
+ dev_err(&port->dev, "%s(): out of memory!\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ OTI6858_REQ_T_GET_STATUS,
+ OTI6858_REQ_GET_STATUS,
+ 0, 0,
+ buf, OTI6858_CTRL_PKT_SIZE,
+ 100);
+ if (result != OTI6858_CTRL_PKT_SIZE) {
+ /* assume default (after power-on reset) values */
+ buf->divisor = cpu_to_le16(0x009c); /* 38400 bps */
+ buf->frame_fmt = 0x03; /* 8N1 */
+ buf->something = 0x43;
+ buf->control = 0x4c; /* DTR, RTS */
+ buf->tx_status = 0x00;
+ buf->pin_state = 0x5b; /* RTS, CTS, DSR, DTR, RI, DCD */
+ buf->rx_bytes_avail = 0x00;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ memcpy(&priv->status, buf, OTI6858_CTRL_PKT_SIZE);
+ priv->pending_setup.divisor = buf->divisor;
+ priv->pending_setup.frame_fmt = buf->frame_fmt;
+ priv->pending_setup.control = buf->control;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ kfree(buf);
+
+ dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ 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);
+ oti6858_close(port, NULL);
+ return -EPROTO;
+ }
+
+ /* setup termios */
+ if (port->tty)
+ oti6858_set_termios(port, &tmp_termios);
+
+ return 0;
+}
+
+static void oti6858_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ long timeout;
+ wait_queue_t wait;
+
+ dbg("%s(port = %d)", __FUNCTION__, 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__);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (pl2303_buf_data_avail(priv->buf) == 0
+ || timeout == 0 || signal_pending(current)
+ || !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ 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);
+ dbg("%s(): after wait loop", __FUNCTION__);
+
+ /* clear out any remaining data in the buffer */
+ pl2303_buf_clear(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wait for characters to drain from the device */
+ /* (this is long enough for the entire 256 byte */
+ /* pl2303 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) */
+ /* FIXME
+ bps = tty_get_baud_rate(port->tty);
+ if (bps > 1200)
+ timeout = max((HZ*2560)/bps,HZ/10);
+ else
+ */
+ timeout = 2*HZ;
+ schedule_timeout_interruptible(timeout);
+ dbg("%s(): after schedule_timeout_interruptible()", __FUNCTION__);
+
+ /* cancel scheduled setup */
+ cancel_delayed_work(&priv->delayed_setup_work);
+ cancel_delayed_work(&priv->delayed_write_work);
+ flush_scheduled_work();
+
+ /* shutdown our urbs */
+ dbg("%s(): shutting down urbs", __FUNCTION__);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
+
+ /*
+ if (port->tty && (port->tty->termios->c_cflag) & HUPCL) {
+ // drop DTR and RTS
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->pending_setup.control &= ~CONTROL_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ */
+}
+
+static int oti6858_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ u8 control;
+
+ dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)",
+ __FUNCTION__, port->number, set, clear);
+
+ if (!usb_get_intfdata(port->serial->interface))
+ return -ENODEV;
+
+ /* FIXME: check if this is correct (active high/low) */
+ spin_lock_irqsave(&priv->lock, flags);
+ control = priv->pending_setup.control;
+ if ((set & TIOCM_RTS) != 0)
+ control |= CONTROL_RTS_HIGH;
+ if ((set & TIOCM_DTR) != 0)
+ control |= CONTROL_DTR_HIGH;
+ if ((clear & TIOCM_RTS) != 0)
+ control &= ~CONTROL_RTS_HIGH;
+ if ((clear & TIOCM_DTR) != 0)
+ control &= ~CONTROL_DTR_HIGH;
+
+ if (control != priv->pending_setup.control) {
+ priv->pending_setup.control = control;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static int oti6858_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned pin_state;
+ unsigned result = 0;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ if (!usb_get_intfdata(port->serial->interface))
+ return -ENODEV;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pin_state = priv->status.pin_state & PIN_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* FIXME: check if this is correct (active high/low) */
+ if ((pin_state & PIN_RTS) != 0)
+ result |= TIOCM_RTS;
+ if ((pin_state & PIN_CTS) != 0)
+ result |= TIOCM_CTS;
+ if ((pin_state & PIN_DSR) != 0)
+ result |= TIOCM_DSR;
+ if ((pin_state & PIN_DTR) != 0)
+ result |= TIOCM_DTR;
+ if ((pin_state & PIN_RI) != 0)
+ result |= TIOCM_RI;
+ if ((pin_state & PIN_DCD) != 0)
+ result |= TIOCM_CD;
+
+ dbg("%s() = 0x%08x", __FUNCTION__, result);
+
+ return result;
+}
+
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int prev, status;
+ unsigned int changed;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ prev = priv->status.pin_state;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+ wait_event_interruptible(priv->intr_wait, priv->status.pin_state != prev);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->status.pin_state & PIN_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ changed = prev ^ status;
+ /* FIXME: check if this is correct (active high/low) */
+ if ( ((arg & TIOCM_RNG) && (changed & PIN_RI)) ||
+ ((arg & TIOCM_DSR) && (changed & PIN_DSR)) ||
+ ((arg & TIOCM_CD) && (changed & PIN_DCD)) ||
+ ((arg & TIOCM_CTS) && (changed & PIN_CTS))) {
+ return 0;
+ }
+ prev = status;
+ }
+
+ /* NOTREACHED */
+ return 0;
+}
+
+static int oti6858_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *user_arg = (void __user *) arg;
+ unsigned int x;
+
+ dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)",
+ __FUNCTION__, port->number, cmd, arg);
+
+ switch (cmd) {
+ case TCGETS:
+ if (copy_to_user(user_arg, port->tty->termios,
+ sizeof(struct ktermios))) {
+ return -EFAULT;
+ }
+ return 0;
+
+ case TCSETS:
+ case TCSETSW: /* FIXME: this is not the same! */
+ case TCSETSF: /* FIXME: this is not the same! */
+ if (copy_from_user(port->tty->termios, user_arg,
+ sizeof(struct ktermios))) {
+ return -EFAULT;
+ }
+ oti6858_set_termios(port, NULL);
+ return 0;
+
+ case TCFLSH:
+ /* FIXME */
+ return 0;
+
+ case TIOCMBIS:
+ if (copy_from_user(&x, user_arg, sizeof(x)))
+ return -EFAULT;
+ return oti6858_tiocmset(port, NULL, x, 0);
+
+ case TIOCMBIC:
+ if (copy_from_user(&x, user_arg, sizeof(x)))
+ return -EFAULT;
+ return oti6858_tiocmset(port, NULL, 0, x);
+
+ case TIOCGSERIAL:
+ if (copy_to_user(user_arg, port->tty->termios,
+ sizeof(struct ktermios))) {
+ return -EFAULT;
+ }
+ return 0;
+
+ case TIOCSSERIAL:
+ if (copy_from_user(port->tty->termios, user_arg,
+ sizeof(struct ktermios))) {
+ return -EFAULT;
+ }
+ oti6858_set_termios(port, NULL);
+ return 0;
+
+ case TIOCMIWAIT:
+ dbg("%s(): TIOCMIWAIT", __FUNCTION__);
+ return wait_modem_info(port, arg);
+
+ default:
+ dbg("%s(): 0x%04x not supported", __FUNCTION__, cmd);
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static void oti6858_break_ctl(struct usb_serial_port *port, int break_state)
+{
+ int state;
+
+ dbg("%s(port = %d)", __FUNCTION__, port->number);
+
+ state = (break_state == 0) ? 0 : 1;
+ dbg("%s(): turning break %s", __FUNCTION__, state ? "on" : "off");
+
+ /* FIXME */
+/*
+ result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
+ BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
+ 0, NULL, 0, 100);
+ if (result != 0)
+ dbg("%s(): error sending break", __FUNCTION__);
+ */
+}
+
+static void oti6858_shutdown(struct usb_serial *serial)
+{
+ struct oti6858_private *priv;
+ int i;
+
+ dbg("%s()", __FUNCTION__);
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ if (priv) {
+ pl2303_buf_free(priv->buf);
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ }
+}
+
+static void oti6858_read_int_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_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);
+
+ switch (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__, status);
+ return;
+ default:
+ dbg("%s(): nonzero urb status received: %d",
+ __FUNCTION__, status);
+ break;
+ }
+
+ if (status == 0 && urb->actual_length == OTI6858_CTRL_PKT_SIZE) {
+ struct oti6858_control_pkt *xs = urb->transfer_buffer;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (!priv->transient) {
+ if (!OTI6858_CTRL_EQUALS_PENDING(xs, priv)) {
+ if (xs->rx_bytes_avail == 0) {
+ priv->transient = 4;
+ priv->setup_done = 0;
+ resubmit = 0;
+ dbg("%s(): scheduling setup_line()",
+ __FUNCTION__);
+ schedule_delayed_work(&priv->delayed_setup_work, 0);
+ }
+ }
+ } else {
+ if (OTI6858_CTRL_EQUALS_PENDING(xs, priv)) {
+ priv->transient = 0;
+ } else if (!priv->setup_done) {
+ resubmit = 0;
+ } else if (--priv->transient == 0) {
+ if (xs->rx_bytes_avail == 0) {
+ priv->transient = 4;
+ priv->setup_done = 0;
+ resubmit = 0;
+ dbg("%s(): scheduling setup_line()",
+ __FUNCTION__);
+ schedule_delayed_work(&priv->delayed_setup_work, 0);
+ }
+ }
+ }
+
+ if (!priv->transient) {
+ if (xs->pin_state != priv->status.pin_state)
+ wake_up_interruptible(&priv->intr_wait);
+ memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);
+ }
+
+ if (!priv->transient && xs->rx_bytes_avail != 0) {
+ can_recv = xs->rx_bytes_avail;
+ priv->flags.read_urb_in_use = 1;
+ }
+
+ transient = priv->transient;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ if (can_recv) {
+ int result;
+
+ port->read_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (result != 0) {
+ priv->flags.read_urb_in_use = 0;
+ dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
+ " error %d\n", __FUNCTION__, result);
+ } else {
+ resubmit = 0;
+ }
+ } else if (!transient) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->flags.write_urb_in_use == 0
+ && pl2303_buf_data_avail(priv->buf) != 0) {
+ schedule_delayed_work(&priv->delayed_write_work,0);
+ resubmit = 0;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ if (resubmit) {
+ int result;
+
+// dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ 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);
+ }
+ }
+}
+
+static void oti6858_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct oti6858_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ unsigned long flags;
+ int i, result;
+ int status = urb->status;
+ char tty_flag;
+
+ dbg("%s(port = %d, status = %d)",
+ __FUNCTION__, port->number, status);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->flags.read_urb_in_use = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (status != 0) {
+ if (!port->open_count) {
+ dbg("%s(): port is closed, exiting", __FUNCTION__);
+ return;
+ }
+ /*
+ if (status == -EPROTO) {
+ // PL2303 mysteriously fails with -EPROTO reschedule the read
+ dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ return;
+ }
+ */
+ dbg("%s(): unable to handle the error, exiting", __FUNCTION__);
+ return;
+ }
+
+ // get tty_flag from status
+ tty_flag = TTY_NORMAL;
+
+/* FIXME: probably, errors will be signalled using interrupt pipe! */
+/*
+ // 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;
+ dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
+*/
+
+ tty = port->tty;
+ if (tty != NULL && urb->actual_length > 0) {
+ tty_buffer_request_room(tty, urb->actual_length);
+ for (i = 0; i < urb->actual_length; ++i)
+ tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_flip_buffer_push(tty);
+ }
+
+ // schedule the interrupt urb if we are still open */
+ if (port->open_count != 0) {
+ 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,"
+ " error %d\n", __FUNCTION__, result);
+ }
+ }
+}
+
+static void oti6858_write_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_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);
+
+ switch (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__, 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__);
+
+ 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);
+ } else {
+ return;
+ }
+ }
+
+ priv->flags.write_urb_in_use = 0;
+
+ // schedule the interrupt urb if we are still open */
+ port->interrupt_in_urb->dev = port->serial->dev;
+ dbg("%s(): submitting interrupt urb", __FUNCTION__);
+ 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);
+ }
+}
+
+
+/*
+ * pl2303_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+{
+ struct pl2303_buf *pb;
+
+ if (size == 0)
+ return NULL;
+
+ pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), 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;
+}
+
+/*
+ * pl2303_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+static void pl2303_buf_free(struct pl2303_buf *pb)
+{
+ if (pb) {
+ kfree(pb->buf_buf);
+ kfree(pb);
+ }
+}
+
+/*
+ * pl2303_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+static void pl2303_buf_clear(struct pl2303_buf *pb)
+{
+ if (pb != NULL) {
+ /* equivalent to a get of all data available */
+ pb->buf_get = pb->buf_put;
+ }
+}
+
+/*
+ * pl2303_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+{
+ if (pb == NULL)
+ return 0;
+ return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
+}
+
+/*
+ * pl2303_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+{
+ if (pb == NULL)
+ return 0;
+ return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
+}
+
+/*
+ * pl2303_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_space_avail(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;
+}
+
+/*
+ * pl2303_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_data_avail(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;
+}
+
+/* module description and (de)initialization */
+
+static int __init oti6858_init(void)
+{
+ int retval;
+
+ if ((retval = usb_serial_register(&oti6858_device)) == 0) {
+ if ((retval = usb_register(&oti6858_driver)) != 0)
+ usb_serial_deregister(&oti6858_device);
+ else
+ return 0;
+ }
+
+ return retval;
+}
+
+static void __exit oti6858_exit(void)
+{
+ usb_deregister(&oti6858_driver);
+ usb_serial_deregister(&oti6858_device);
+}
+
+module_init(oti6858_init);
+module_exit(oti6858_exit);
+
+MODULE_DESCRIPTION(OTI6858_DESCRIPTION);
+MODULE_AUTHOR(OTI6858_AUTHOR);
+MODULE_VERSION(OTI6858_VERSION);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "enable debug output");
+
diff --git a/drivers/usb/serial/oti6858.h b/drivers/usb/serial/oti6858.h
new file mode 100644
index 000000000000..704ac3a532b3
--- /dev/null
+++ b/drivers/usb/serial/oti6858.h
@@ -0,0 +1,15 @@
+/*
+ * Ours Technology Inc. OTi-6858 USB to serial adapter driver.
+ *
+ * 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 __LINUX_USB_SERIAL_OTI6858_H
+#define __LINUX_USB_SERIAL_OTI6858_H
+
+#define OTI6858_VENDOR_ID 0x0ea0
+#define OTI6858_PRODUCT_ID 0x6858
+
+#endif
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 83dfae93a45d..f9f85f56f0db 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -1,14 +1,14 @@
/*
* Prolific PL2303 USB to serial adaptor driver
*
- * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2003 IBM Corp.
*
* Original driver for 2.2.x by anonymous
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
+ * This 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.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
@@ -484,15 +484,6 @@ static void pl2303_set_termios(struct usb_serial_port *port,
spin_unlock_irqrestore(&priv->lock, flags);
cflag = port->tty->termios->c_cflag;
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
- RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
- }
- }
buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
@@ -517,29 +508,7 @@ static void pl2303_set_termios(struct usb_serial_port *port,
dbg("%s - data bits = %d", __FUNCTION__, buf[6]);
}
- baud = 0;
- switch (cflag & CBAUD) {
- case B0: baud = 0; break;
- case B75: baud = 75; break;
- case B150: baud = 150; break;
- case B300: baud = 300; break;
- case B600: baud = 600; break;
- case B1200: baud = 1200; break;
- case B1800: baud = 1800; break;
- case B2400: baud = 2400; break;
- case B4800: baud = 4800; break;
- case B9600: baud = 9600; break;
- case B19200: baud = 19200; break;
- case B38400: baud = 38400; break;
- case B57600: baud = 57600; break;
- case B115200: baud = 115200; break;
- case B230400: baud = 230400; break;
- case B460800: baud = 460800; break;
- default:
- dev_err(&port->dev, "pl2303 driver does not support"
- " the baudrate requested (fix it)\n");
- break;
- }
+ baud = tty_get_baud_rate(port->tty);;
dbg("%s - baud = %d", __FUNCTION__, baud);
if (baud) {
buf[0] = baud & 0xff;
@@ -617,6 +586,13 @@ static void pl2303_set_termios(struct usb_serial_port *port,
VENDOR_WRITE_REQUEST_TYPE,
0x0, index, NULL, 0, 100);
dbg("0x40:0x1:0x0:0x%x %d", index, i);
+ } else {
+ i = usb_control_msg(serial->dev,
+ usb_sndctrlpipe(serial->dev, 0),
+ VENDOR_WRITE_REQUEST,
+ VENDOR_WRITE_REQUEST_TYPE,
+ 0x0, 0x0, NULL, 0, 100);
+ dbg ("0x40:0x1:0x0:0x0 %d", i);
}
kfree(buf);
@@ -954,11 +930,12 @@ static void pl2303_read_int_callback(struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
unsigned char *data = urb->transfer_buffer;
unsigned int actual_length = urb->actual_length;
- int status;
+ int status = urb->status;
+ int retval;
dbg("%s (%d)", __FUNCTION__, port->number);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -967,11 +944,11 @@ static void pl2303_read_int_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__,
- urb->status);
+ status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__,
- urb->status);
+ status);
goto exit;
}
@@ -981,11 +958,11 @@ static void pl2303_read_int_callback(struct urb *urb)
pl2303_update_line_status(port, data, actual_length);
exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
dev_err(&urb->dev->dev,
"%s - usb_submit_urb failed with result %d\n",
- __FUNCTION__, status);
+ __FUNCTION__, retval);
}
static void pl2303_read_bulk_callback(struct urb *urb)
@@ -997,23 +974,23 @@ static void pl2303_read_bulk_callback(struct urb *urb)
unsigned long flags;
int i;
int result;
- u8 status;
+ int status = urb->status;
+ u8 line_status;
char tty_flag;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - urb status = %d", __FUNCTION__, status);
if (!port->open_count) {
dbg("%s - port is closed, exiting.", __FUNCTION__);
return;
}
- if (urb->status == -EPROTO) {
+ if (status == -EPROTO) {
/* PL2303 mysteriously fails with -EPROTO reschedule
* the read */
dbg("%s - caught -EPROTO, resubmitting the urb",
__FUNCTION__);
- urb->status = 0;
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
@@ -1033,18 +1010,18 @@ static void pl2303_read_bulk_callback(struct urb *urb)
tty_flag = TTY_NORMAL;
spin_lock_irqsave(&priv->lock, flags);
- status = priv->line_status;
+ line_status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
wake_up_interruptible(&priv->delta_msr_wait);
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
- if (status & UART_BREAK_ERROR )
+ if (line_status & UART_BREAK_ERROR )
tty_flag = TTY_BREAK;
- else if (status & UART_PARITY_ERROR)
+ else if (line_status & UART_PARITY_ERROR)
tty_flag = TTY_PARITY;
- else if (status & UART_FRAME_ERROR)
+ else if (line_status & UART_FRAME_ERROR)
tty_flag = TTY_FRAME;
dbg("%s - tty_flag = %d", __FUNCTION__, tty_flag);
@@ -1052,7 +1029,7 @@ static void pl2303_read_bulk_callback(struct urb *urb)
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)
+ if (line_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);
@@ -1076,10 +1053,11 @@ static void pl2303_write_bulk_callback(struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_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);
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -1088,14 +1066,14 @@ static void pl2303_write_bulk_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__,
- urb->status);
+ 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__,
- urb->status);
+ status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 5a03a3fc9386..86899d55d8d8 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -211,11 +211,13 @@ static void safe_read_bulk_callback (struct urb *urb)
unsigned char length = urb->actual_length;
int i;
int result;
+ int status = urb->status;
dbg ("%s", __FUNCTION__);
- if (urb->status) {
- dbg ("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index ac1829c6e8f0..0794ccdebfd4 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 Kevin Lloyd <linux@sierrawireless.com>
+ Copyright (C) 2006, 2007 Kevin Lloyd <linux@sierrawireless.com>
IMPORTANT DISCLAIMER: This driver is not commercially supported by
Sierra Wireless. Use at your own risk.
@@ -12,10 +12,9 @@
Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
-
*/
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.2.5b"
#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
@@ -28,23 +27,98 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#define SWIMS_USB_REQUEST_SetMode 0x0B
+#define SWIMS_USB_REQUEST_TYPE_SetMode 0x40
+#define SWIMS_USB_INDEX_SetMode 0x0000
+#define SWIMS_SET_MODE_Modem 0x0001
+
+/* per port private data */
+#define N_IN_URB 4
+#define N_OUT_URB 4
+#define IN_BUFLEN 4096
+
+static int debug;
+
+enum devicetype {
+ DEVICE_3_PORT = 0,
+ DEVICE_1_PORT = 1,
+ DEVICE_INSTALLER = 2,
+};
+
+int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+{
+ int result;
+ dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ 0x00, /* __u8 request */
+ 0x40, /* __u8 request type */
+ swiState, /* __u16 value */
+ 0, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+{
+ int result;
+ dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+ result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ SWIMS_USB_REQUEST_SetMode, /* __u8 request */
+ SWIMS_USB_REQUEST_TYPE_SetMode, /* __u8 request type */
+ eSocMode, /* __u16 value */
+ SWIMS_USB_INDEX_SetMode, /* __u16 index */
+ NULL, /* void *data */
+ 0, /* __u16 size */
+ USB_CTRL_SET_TIMEOUT); /* int timeout */
+ return result;
+}
+
+int sierra_probe(struct usb_interface *iface, const struct usb_device_id *id)
+{
+ int result;
+ struct usb_device *udev;
+
+ udev = usb_get_dev(interface_to_usbdev(iface));
+
+ /* Check if in installer mode */
+ if (id->driver_info == DEVICE_INSTALLER) {
+ dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+ result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+ /*We do not want to bind to the device when in installer mode*/
+ return -EIO;
+ }
+
+ return usb_serial_probe(iface, id);
+}
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+ { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+ { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880 E */
+ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881 E */
- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
- { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+ { USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+ { USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+
+ { USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
@@ -58,43 +132,43 @@ static struct usb_device_id id_table_1port [] = {
static struct usb_device_id id_table_3port [] = {
{ USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x0f30, 0x1b1d) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
- { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless AirCard 595U */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
+ { USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U*/
+
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
- { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 & AC 875U */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { USB_DEVICE(0x1199, 0x6832) }, /* Sierra Wireless MC8780*/
+ { USB_DEVICE(0x1199, 0x6833) }, /* Sierra Wireless MC8781*/
+ { USB_DEVICE(0x1199, 0x6850) }, /* Sierra Wireless AirCard 880 */
+ { USB_DEVICE(0x1199, 0x6851) }, /* Sierra Wireless AirCard 881 */
+ { USB_DEVICE(0x1199, 0x6852) }, /* Sierra Wireless AirCard 880E */
+ { USB_DEVICE(0x1199, 0x6853) }, /* Sierra Wireless AirCard 881E */
{ }
};
static struct usb_driver sierra_driver = {
.name = "sierra",
- .probe = usb_serial_probe,
+ .probe = sierra_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
-static int debug;
-
-/* per port private data */
-#define N_IN_URB 4
-#define N_OUT_URB 4
-#define IN_BUFLEN 4096
-#define OUT_BUFLEN 128
-
struct sierra_port_private {
+ spinlock_t lock; /* lock the structure */
+ int outstanding_urbs; /* number of out urbs in flight */
+
/* Input endpoints and buffer for this port */
struct urb *in_urbs[N_IN_URB];
char in_buffer[N_IN_URB][IN_BUFLEN];
- /* Output endpoints and buffer for this port */
- struct urb *out_urbs[N_OUT_URB];
- char out_buffer[N_OUT_URB][OUT_BUFLEN];
/* Settings for the port */
int rts_state; /* Handshaking pins (outputs) */
@@ -103,8 +177,6 @@ struct sierra_port_private {
int dsr_state;
int dcd_state;
int ri_state;
-
- unsigned long tx_start_time[N_OUT_URB];
};
static int sierra_send_setup(struct usb_serial_port *port)
@@ -197,61 +269,98 @@ static int sierra_ioctl(struct usb_serial_port *port, struct file *file,
return -ENOIOCTLCMD;
}
+static void sierra_outdat_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ int status = urb->status;
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, 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);
+
+ spin_lock_irqsave(&portdata->lock, flags);
+ --portdata->outstanding_urbs;
+ spin_unlock_irqrestore(&portdata->lock, flags);
+
+ usb_serial_port_softint(port);
+}
+
/* Write */
static int sierra_write(struct usb_serial_port *port,
const unsigned char *buf, int count)
{
- struct sierra_port_private *portdata;
- int i;
- int left, todo;
- struct urb *this_urb = NULL; /* spurious */
- int err;
+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ unsigned long flags;
+ unsigned char *buffer;
+ struct urb *urb;
+ int status;
portdata = usb_get_serial_port_data(port);
dbg("%s: write (%d chars)", __FUNCTION__, count);
- i = 0;
- left = count;
- for (i=0; left > 0 && i < N_OUT_URB; i++) {
- todo = left;
- if (todo > OUT_BUFLEN)
- todo = OUT_BUFLEN;
-
- this_urb = portdata->out_urbs[i];
- if (this_urb->status == -EINPROGRESS) {
- if (time_before(jiffies,
- portdata->tx_start_time[i] + 10 * HZ))
- continue;
- usb_unlink_urb(this_urb);
- continue;
- }
- if (this_urb->status != 0)
- dbg("usb_write %p failed (err=%d)",
- this_urb, this_urb->status);
-
- dbg("%s: endpoint %d buf %d", __FUNCTION__,
- usb_pipeendpoint(this_urb->pipe), i);
-
- /* send the data */
- memcpy (this_urb->transfer_buffer, buf, todo);
- this_urb->transfer_buffer_length = todo;
-
- this_urb->dev = port->serial->dev;
- err = usb_submit_urb(this_urb, GFP_ATOMIC);
- if (err) {
- dbg("usb_submit_urb %p (write bulk) failed "
- "(%d, has %d)", this_urb,
- err, this_urb->status);
- continue;
- }
- portdata->tx_start_time[i] = jiffies;
- buf += todo;
- left -= todo;
+ 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__);
+ return 0;
+ }
+ portdata->outstanding_urbs++;
+ spin_unlock_irqrestore(&portdata->lock, flags);
+
+ buffer = kmalloc(count, GFP_ATOMIC);
+ if (!buffer) {
+ dev_err(&port->dev, "out of memory\n");
+ count = -ENOMEM;
+ goto error_no_buffer;
+ }
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ dev_err(&port->dev, "no more free urbs\n");
+ count = -ENOMEM;
+ goto error_no_urb;
+ }
+
+ memcpy(buffer, buf, count);
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ buffer, count, sierra_outdat_callback, port);
+
+ /* 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);
+ count = status;
+ goto error;
}
- count -= left;
- dbg("%s: wrote (did %d)", __FUNCTION__, count);
+ /* we are done with this urb, so let the host driver
+ * really free it when it is finished with it */
+ usb_free_urb(urb);
+
+ return count;
+error:
+ usb_free_urb(urb);
+error_no_urb:
+ kfree(buffer);
+error_no_buffer:
+ spin_lock_irqsave(&portdata->lock, flags);
+ --portdata->outstanding_urbs;
+ spin_unlock_irqrestore(&portdata->lock, flags);
return count;
}
@@ -262,15 +371,16 @@ static void sierra_indat_callback(struct urb *urb)
struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
dbg("%s: %p", __FUNCTION__, urb);
endpoint = usb_pipeendpoint(urb->pipe);
port = (struct usb_serial_port *) urb->context;
- if (urb->status) {
+ if (status) {
dbg("%s: nonzero status: %d on endpoint %02x.",
- __FUNCTION__, urb->status, endpoint);
+ __FUNCTION__, status, endpoint);
} else {
tty = port->tty;
if (urb->actual_length) {
@@ -282,30 +392,20 @@ static void sierra_indat_callback(struct urb *urb)
}
/* Resubmit urb so we continue receiving */
- if (port->open_count && urb->status != -ESHUTDOWN) {
+ if (port->open_count && status != -ESHUTDOWN) {
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
- printk(KERN_ERR "%s: resubmit read urb failed. "
- "(%d)", __FUNCTION__, err);
+ dev_err(&port->dev, "resubmit read urb failed."
+ "(%d)", err);
}
}
return;
}
-static void sierra_outdat_callback(struct urb *urb)
-{
- struct usb_serial_port *port;
-
- dbg("%s", __FUNCTION__);
-
- port = (struct usb_serial_port *) urb->context;
-
- usb_serial_port_softint(port);
-}
-
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 sierra_port_private *portdata = usb_get_serial_port_data(port);
struct usb_serial *serial = port->serial;
@@ -313,7 +413,7 @@ static void sierra_instat_callback(struct urb *urb)
dbg("%s", __FUNCTION__);
dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
- if (urb->status == 0) {
+ if (status == 0) {
struct usb_ctrlrequest *req_pkt =
(struct usb_ctrlrequest *)urb->transfer_buffer;
@@ -344,10 +444,10 @@ static void sierra_instat_callback(struct urb *urb)
req_pkt->bRequestType,req_pkt->bRequest);
}
} else
- dbg("%s: error %d", __FUNCTION__, urb->status);
+ dbg("%s: error %d", __FUNCTION__, status);
/* Resubmit urb so we continue receiving IRQ data */
- if (urb->status != -ESHUTDOWN) {
+ if (status != -ESHUTDOWN) {
urb->dev = serial->dev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err)
@@ -358,49 +458,44 @@ static void sierra_instat_callback(struct urb *urb)
static int sierra_write_room(struct usb_serial_port *port)
{
- struct sierra_port_private *portdata;
- int i;
- int data_len = 0;
- struct urb *this_urb;
+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ unsigned long flags;
- portdata = usb_get_serial_port_data(port);
+ dbg("%s - port %d", __FUNCTION__, port->number);
- for (i=0; i < N_OUT_URB; i++) {
- this_urb = portdata->out_urbs[i];
- if (this_urb && this_urb->status != -EINPROGRESS)
- data_len += OUT_BUFLEN;
+ /* 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__);
+ return 0;
}
+ spin_unlock_irqrestore(&portdata->lock, flags);
- dbg("%s: %d", __FUNCTION__, data_len);
- return data_len;
+ return 2048;
}
static int sierra_chars_in_buffer(struct usb_serial_port *port)
{
- struct sierra_port_private *portdata;
- int i;
- int data_len = 0;
- struct urb *this_urb;
-
- portdata = usb_get_serial_port_data(port);
-
- for (i=0; i < N_OUT_URB; i++) {
- this_urb = portdata->out_urbs[i];
- if (this_urb && this_urb->status == -EINPROGRESS)
- data_len += this_urb->transfer_buffer_length;
- }
- dbg("%s: %d", __FUNCTION__, data_len);
- return data_len;
+ dbg("%s - port %d", __FUNCTION__, 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.
+ */
+ return 0;
}
static int sierra_open(struct usb_serial_port *port, struct file *filp)
{
struct sierra_port_private *portdata;
struct usb_serial *serial = port->serial;
- int i, err;
+ int i;
struct urb *urb;
int result;
- __u16 set_mode_dzero = 0x0000;
portdata = usb_get_serial_port_data(port);
@@ -413,7 +508,7 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
/* Reset low level data toggle and start reading from endpoints */
for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i];
- if (! urb)
+ if (!urb)
continue;
if (urb->dev != serial->dev) {
dbg("%s: dev %p != %p", __FUNCTION__,
@@ -427,35 +522,25 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
*/
usb_clear_halt(urb->dev, urb->pipe);
- err = usb_submit_urb(urb, GFP_KERNEL);
- if (err) {
- dbg("%s: submit urb %d failed (%d) %d",
- __FUNCTION__, i, err,
- urb->transfer_buffer_length);
+ result = usb_submit_urb(urb, GFP_KERNEL);
+ if (result) {
+ dev_err(&port->dev, "submit urb %d failed (%d) %d",
+ i, result, urb->transfer_buffer_length);
}
}
- /* Reset low level data toggle on out endpoints */
- for (i = 0; i < N_OUT_URB; i++) {
- urb = portdata->out_urbs[i];
- if (! urb)
- continue;
- urb->dev = serial->dev;
- /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
- usb_pipeout(urb->pipe), 0); */
- }
-
port->tty->low_latency = 1;
- /* set mode to D0 */
- result = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x00, 0x40, set_mode_dzero, 0, NULL,
- 0, USB_CTRL_SET_TIMEOUT);
-
sierra_send_setup(port);
- return (0);
+ /* start up the interrupt endpoint if we have one */
+ if (port->interrupt_in_urb) {
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (result)
+ dev_err(&port->dev, "submit irq_in urb failed %d",
+ result);
+ }
+ return 0;
}
static void sierra_close(struct usb_serial_port *port, struct file *filp)
@@ -475,74 +560,27 @@ static void sierra_close(struct usb_serial_port *port, struct file *filp)
/* Stop reading/writing urbs */
for (i = 0; i < N_IN_URB; i++)
- usb_unlink_urb(portdata->in_urbs[i]);
- for (i = 0; i < N_OUT_URB; i++)
- usb_unlink_urb(portdata->out_urbs[i]);
- }
- port->tty = NULL;
-}
-
-/* Helper functions used by sierra_setup_urbs */
-static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
- int dir, void *ctx, char *buf, int len,
- usb_complete_t callback)
-{
- struct urb *urb;
-
- if (endpoint == -1)
- return NULL; /* endpoint not needed */
-
- urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
- if (urb == NULL) {
- dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
- return NULL;
+ usb_kill_urb(portdata->in_urbs[i]);
}
- /* Fill URB using supplied data. */
- usb_fill_bulk_urb(urb, serial->dev,
- usb_sndbulkpipe(serial->dev, endpoint) | dir,
- buf, len, callback, ctx);
-
- return urb;
-}
-
-/* Setup urbs */
-static void sierra_setup_urbs(struct usb_serial *serial)
-{
- int i,j;
- struct usb_serial_port *port;
- struct sierra_port_private *portdata;
-
- dbg("%s", __FUNCTION__);
-
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- portdata = usb_get_serial_port_data(port);
-
- /* Do indat endpoints first */
- for (j = 0; j < N_IN_URB; ++j) {
- portdata->in_urbs[j] = sierra_setup_urb (serial,
- port->bulk_in_endpointAddress, USB_DIR_IN, port,
- portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback);
- }
+ usb_kill_urb(port->interrupt_in_urb);
- /* outdat endpoints */
- for (j = 0; j < N_OUT_URB; ++j) {
- portdata->out_urbs[j] = sierra_setup_urb (serial,
- port->bulk_out_endpointAddress, USB_DIR_OUT, port,
- portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback);
- }
- }
+ port->tty = NULL;
}
static int sierra_startup(struct usb_serial *serial)
{
- int i, err;
struct usb_serial_port *port;
struct sierra_port_private *portdata;
+ struct urb *urb;
+ int i;
+ int j;
dbg("%s", __FUNCTION__);
+ /*Set Device mode to D0 */
+ sierra_set_power_state(serial->dev, 0x0000);
+
/* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
@@ -550,22 +588,31 @@ static int sierra_startup(struct usb_serial *serial)
if (!portdata) {
dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
__FUNCTION__, i);
- return (1);
+ return -ENOMEM;
}
+ spin_lock_init(&portdata->lock);
usb_set_serial_port_data(port, portdata);
- if (! port->interrupt_in_urb)
- continue;
- err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
- if (err)
- dbg("%s: submit irq_in urb failed %d",
- __FUNCTION__, err);
+ /* initialize the in urbs */
+ for (j = 0; j < N_IN_URB; ++j) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (urb == NULL) {
+ dbg("%s: alloc for in port failed.",
+ __FUNCTION__);
+ continue;
+ }
+ /* Fill URB using supplied data. */
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ portdata->in_buffer[j], IN_BUFLEN,
+ sierra_indat_callback, port);
+ portdata->in_urbs[j] = urb;
+ }
}
- sierra_setup_urbs(serial);
-
- return (0);
+ return 0;
}
static void sierra_shutdown(struct usb_serial *serial)
@@ -576,22 +623,6 @@ static void sierra_shutdown(struct usb_serial *serial)
dbg("%s", __FUNCTION__);
- /* Stop reading/writing urbs */
- for (i = 0; i < serial->num_ports; ++i) {
- port = serial->port[i];
- if (!port)
- continue;
- portdata = usb_get_serial_port_data(port);
- if (!portdata)
- continue;
-
- for (j = 0; j < N_IN_URB; j++)
- usb_unlink_urb(portdata->in_urbs[j]);
- for (j = 0; j < N_OUT_URB; j++)
- usb_unlink_urb(portdata->out_urbs[j]);
- }
-
- /* Now free them */
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
if (!port)
@@ -601,25 +632,12 @@ static void sierra_shutdown(struct usb_serial *serial)
continue;
for (j = 0; j < N_IN_URB; j++) {
- if (portdata->in_urbs[j]) {
- usb_free_urb(portdata->in_urbs[j]);
- portdata->in_urbs[j] = NULL;
- }
+ usb_kill_urb(portdata->in_urbs[j]);
+ usb_free_urb(portdata->in_urbs[j]);
+ portdata->in_urbs[j] = NULL;
}
- for (j = 0; j < N_OUT_URB; j++) {
- if (portdata->out_urbs[j]) {
- usb_free_urb(portdata->out_urbs[j]);
- portdata->out_urbs[j] = NULL;
- }
- }
- }
-
- /* Now free per port private data */
- for (i = 0; i < serial->num_ports; i++) {
- port = serial->port[i];
- if (!port)
- continue;
- kfree(usb_get_serial_port_data(port));
+ kfree(portdata);
+ usb_set_serial_port_data(port, NULL);
}
}
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 3d505fd0645b..f98626ae75fe 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -1112,22 +1112,24 @@ static void ti_interrupt_callback(struct urb *urb)
int length = urb->actual_length;
int port_number;
int function;
- int status;
+ int status = urb->status;
+ int retval;
__u8 msr;
dbg("%s", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("%s - urb shutting down, %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down, %d", __FUNCTION__, status);
tdev->td_urb_error = 1;
return;
default:
- dev_err(dev, "%s - nonzero urb status, %d\n", __FUNCTION__, urb->status);
+ dev_err(dev, "%s - nonzero urb status, %d\n",
+ __FUNCTION__, status);
tdev->td_urb_error = 1;
goto exit;
}
@@ -1175,9 +1177,10 @@ static void ti_interrupt_callback(struct urb *urb)
}
exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- dev_err(dev, "%s - resubmit interrupt urb failed, %d\n", __FUNCTION__, status);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(dev, "%s - resubmit interrupt urb failed, %d\n",
+ __FUNCTION__, retval);
}
@@ -1186,30 +1189,32 @@ static void ti_bulk_in_callback(struct urb *urb)
struct ti_port *tport = (struct ti_port *)urb->context;
struct usb_serial_port *port = tport->tp_port;
struct device *dev = &urb->dev->dev;
- int status = 0;
+ int status = urb->status;
+ int retval = 0;
dbg("%s", __FUNCTION__);
- switch (urb->status) {
+ switch (status) {
case 0:
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("%s - urb shutting down, %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down, %d", __FUNCTION__, 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__, urb->status );
+ dev_err(dev, "%s - nonzero urb status, %d\n",
+ __FUNCTION__, status );
tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait);
}
- if (urb->status == -EPIPE)
+ if (status == -EPIPE)
goto exit;
- if (urb->status) {
+ if (status) {
dev_err(dev, "%s - stopping read!\n", __FUNCTION__);
return;
}
@@ -1234,13 +1239,14 @@ exit:
spin_lock(&tport->tp_lock);
if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) {
urb->dev = port->serial->dev;
- status = usb_submit_urb(urb, GFP_ATOMIC);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
} else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) {
tport->tp_read_urb_state = TI_READ_URB_STOPPED;
}
spin_unlock(&tport->tp_lock);
- if (status)
- dev_err(dev, "%s - resubmit read urb failed, %d\n", __FUNCTION__, status);
+ if (retval)
+ dev_err(dev, "%s - resubmit read urb failed, %d\n",
+ __FUNCTION__, retval);
}
@@ -1249,23 +1255,25 @@ static void ti_bulk_out_callback(struct urb *urb)
struct ti_port *tport = (struct ti_port *)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);
tport->tp_write_urb_in_use = 0;
- switch (urb->status) {
+ switch (status) {
case 0:
break;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- dbg("%s - urb shutting down, %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down, %d", __FUNCTION__, 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__, urb->status);
+ dev_err(dev, "%s - nonzero urb status, %d\n",
+ __FUNCTION__, status);
tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait);
}
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 87f378806db6..a3665659d13b 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -46,6 +46,8 @@ static struct usb_driver usb_serial_driver = {
.name = "usbserial",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
.no_dynamic_id = 1,
};
@@ -120,11 +122,9 @@ static void return_serial(struct usb_serial *serial)
if (serial == NULL)
return;
- spin_lock(&table_lock);
for (i = 0; i < serial->num_ports; ++i) {
serial_table[serial->minor + i] = NULL;
}
- spin_unlock(&table_lock);
}
static void destroy_serial(struct kref *kref)
@@ -172,7 +172,9 @@ static void destroy_serial(struct kref *kref)
void usb_serial_put(struct usb_serial *serial)
{
+ spin_lock(&table_lock);
kref_put(&serial->kref, destroy_serial);
+ spin_unlock(&table_lock);
}
/*****************************************************************************
@@ -1069,6 +1071,35 @@ void usb_serial_disconnect(struct usb_interface *interface)
dev_info(dev, "device disconnected\n");
}
+int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_serial *serial = usb_get_intfdata(intf);
+ struct usb_serial_port *port;
+ int i, r = 0;
+
+ if (serial) {
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ if (port)
+ kill_traffic(port);
+ }
+ }
+
+ if (serial->type->suspend)
+ serial->type->suspend(serial, message);
+
+ return r;
+}
+EXPORT_SYMBOL(usb_serial_suspend);
+
+int usb_serial_resume(struct usb_interface *intf)
+{
+ struct usb_serial *serial = usb_get_intfdata(intf);
+
+ return serial->type->resume(serial);
+}
+EXPORT_SYMBOL(usb_serial_resume);
+
static const struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index ffbe601cde2a..7d84a7647e81 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -5,9 +5,9 @@
* Copyright (C) 1999 - 2004
* Greg Kroah-Hartman (greg@kroah.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.
+ * 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.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
@@ -273,7 +273,8 @@ struct visor_private {
int bytes_in;
int bytes_out;
int outstanding_urbs;
- int throttled;
+ unsigned char throttled;
+ unsigned char actually_throttled;
};
/* number of outstanding urbs to prevent userspace DoS from happening */
@@ -484,16 +485,17 @@ static void visor_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct visor_private *priv = usb_get_serial_port_data(port);
+ int status = urb->status;
unsigned long flags;
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (urb->status)
+
+ if (status)
dbg("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
spin_lock_irqsave(&priv->lock, flags);
--priv->outstanding_urbs;
@@ -508,15 +510,16 @@ static void visor_read_bulk_callback (struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct visor_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
+ int status = urb->status;
struct tty_struct *tty;
- unsigned long flags;
- int throttled;
int result;
+ int available_room;
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -524,17 +527,20 @@ static void visor_read_bulk_callback (struct urb *urb)
tty = port->tty;
if (tty && urb->actual_length) {
- tty_buffer_request_room(tty, urb->actual_length);
- tty_insert_flip_string(tty, data, urb->actual_length);
- tty_flip_buffer_push(tty);
+ available_room = tty_buffer_request_room(tty, urb->actual_length);
+ if (available_room) {
+ tty_insert_flip_string(tty, data, available_room);
+ tty_flip_buffer_push(tty);
+ }
+ spin_lock(&priv->lock);
+ priv->bytes_in += available_room;
+
+ } else {
+ spin_lock(&priv->lock);
}
- spin_lock_irqsave(&priv->lock, flags);
- priv->bytes_in += urb->actual_length;
- throttled = priv->throttled;
- spin_unlock_irqrestore(&priv->lock, flags);
/* Continue trying to always read if we should */
- if (!throttled) {
+ if (!priv->throttled) {
usb_fill_bulk_urb (port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
port->bulk_in_endpointAddress),
@@ -544,16 +550,19 @@ static void visor_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);
+ } else {
+ priv->actually_throttled = 1;
}
- return;
+ spin_unlock(&priv->lock);
}
static void visor_read_int_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ int status = urb->status;
int result;
- switch (urb->status) {
+ switch (status) {
case 0:
/* success */
break;
@@ -562,11 +571,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__, urb->status);
+ __FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
+ __FUNCTION__, status);
goto exit;
}
@@ -608,6 +617,7 @@ static void visor_unthrottle (struct usb_serial_port *port)
dbg("%s - port %d", __FUNCTION__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = 0;
+ priv->actually_throttled = 0;
spin_unlock_irqrestore(&priv->lock, flags);
port->read_urb->dev = port->serial->dev;
@@ -938,14 +948,6 @@ static void visor_set_termios (struct usb_serial_port *port, struct ktermios *ol
}
cflag = port->tty->termios->c_cflag;
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
- }
- }
/* get the byte size */
switch (cflag & CSIZE) {
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 27c5f8f9a2d5..cc8b44c08712 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -74,6 +74,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/termbits.h>
#include <linux/usb.h>
@@ -203,7 +204,7 @@ static struct usb_serial_driver whiteheat_device = {
struct whiteheat_command_private {
- spinlock_t lock;
+ struct mutex mutex;
__u8 port_running;
__u8 command_finished;
wait_queue_head_t wait_command; /* for handling sleeping while waiting for a command to finish */
@@ -232,6 +233,7 @@ struct whiteheat_private {
struct usb_serial_port *port;
struct list_head tx_urbs_free;
struct list_head tx_urbs_submitted;
+ struct mutex deathwarrant;
};
@@ -425,6 +427,7 @@ static int whiteheat_attach (struct usb_serial *serial)
}
spin_lock_init(&info->lock);
+ mutex_init(&info->deathwarrant);
info->flags = 0;
info->mcr = 0;
INIT_WORK(&info->rx_work, rx_data_softint);
@@ -495,7 +498,7 @@ static int whiteheat_attach (struct usb_serial *serial)
goto no_command_private;
}
- spin_lock_init(&command_info->lock);
+ mutex_init(&command_info->mutex);
command_info->port_running = 0;
init_waitqueue_head(&command_info->wait_command);
usb_set_serial_port_data(command_port, command_info);
@@ -654,7 +657,6 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
struct urb *urb;
struct list_head *tmp;
struct list_head *tmp2;
- unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -683,24 +685,32 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
firm_close(port);
+printk(KERN_ERR"Before processing rx_urbs_submitted.\n");
/* shutdown our bulk reads and writes */
- spin_lock_irqsave(&info->lock, flags);
+ mutex_lock(&info->deathwarrant);
+ spin_lock_irq(&info->lock);
list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
+ list_del(tmp);
+ spin_unlock_irq(&info->lock);
usb_kill_urb(urb);
- list_move(tmp, &info->rx_urbs_free);
+ spin_lock_irq(&info->lock);
+ list_add(tmp, &info->rx_urbs_free);
}
list_for_each_safe(tmp, tmp2, &info->rx_urb_q)
list_move(tmp, &info->rx_urbs_free);
-
list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
+ list_del(tmp);
+ spin_unlock_irq(&info->lock);
usb_kill_urb(urb);
- list_move(tmp, &info->tx_urbs_free);
+ spin_lock_irq(&info->lock);
+ list_add(tmp, &info->tx_urbs_free);
}
- spin_unlock_irqrestore(&info->lock, flags);
+ spin_unlock_irq(&info->lock);
+ mutex_unlock(&info->deathwarrant);
stop_command_port(port->serial);
@@ -872,7 +882,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)
+static void whiteheat_set_termios(struct usb_serial_port *port, struct ktermios *old_termios)
{
dbg("%s -port %d", __FUNCTION__, port->number);
@@ -881,15 +891,6 @@ static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios
goto exit;
}
- /* check that they really want us to change something */
- if (old_termios) {
- if ((port->tty->termios->c_cflag == old_termios->c_cflag) &&
- (port->tty->termios->c_iflag == old_termios->c_iflag)) {
- dbg("%s - nothing to change...", __FUNCTION__);
- goto exit;
- }
- }
-
firm_setup_port(port);
exit:
@@ -920,7 +921,7 @@ static int whiteheat_chars_in_buffer(struct usb_serial_port *port)
spin_unlock_irqrestore(&info->lock, flags);
dbg ("%s - returns %d", __FUNCTION__, chars);
- return (chars);
+ return chars;
}
@@ -962,54 +963,57 @@ static void whiteheat_unthrottle (struct usb_serial_port *port)
/*****************************************************************************
* Connect Tech's White Heat callback routines
*****************************************************************************/
-static void command_port_write_callback (struct urb *urb)
+static void command_port_write_callback(struct urb *urb)
{
+ int status = urb->status;
+
dbg("%s", __FUNCTION__);
- if (urb->status) {
- dbg ("nonzero urb status: %d", urb->status);
+ if (status) {
+ dbg("nonzero urb status: %d", status);
return;
}
}
-static void command_port_read_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 whiteheat_command_private *command_info;
+ int status = urb->status;
unsigned char *data = urb->transfer_buffer;
int result;
- unsigned long flags;
dbg("%s", __FUNCTION__);
- if (urb->status) {
- dbg("%s - nonzero urb status: %d", __FUNCTION__, urb->status);
- return;
- }
-
- usb_serial_debug_data(debug, &command_port->dev, __FUNCTION__, urb->actual_length, data);
-
command_info = usb_get_serial_port_data(command_port);
if (!command_info) {
dbg ("%s - command_info is NULL, exiting.", __FUNCTION__);
return;
}
- spin_lock_irqsave(&command_info->lock, flags);
+ if (status) {
+ dbg("%s - nonzero urb status: %d", __FUNCTION__, 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);
if (data[0] == WHITEHEAT_CMD_COMPLETE) {
command_info->command_finished = WHITEHEAT_CMD_COMPLETE;
- wake_up_interruptible(&command_info->wait_command);
+ wake_up(&command_info->wait_command);
} else if (data[0] == WHITEHEAT_CMD_FAILURE) {
command_info->command_finished = WHITEHEAT_CMD_FAILURE;
- wake_up_interruptible(&command_info->wait_command);
+ 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__);
} 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_interruptible(&command_info->wait_command);
+ wake_up(&command_info->wait_command);
} else {
dbg("%s - bad reply from firmware", __FUNCTION__);
}
@@ -1017,7 +1021,6 @@ static void command_port_read_callback (struct urb *urb)
/* Continue trying to always read */
command_port->read_urb->dev = command_port->serial->dev;
result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);
- spin_unlock_irqrestore(&command_info->lock, flags);
if (result)
dbg("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
}
@@ -1029,6 +1032,7 @@ static void whiteheat_read_callback(struct urb *urb)
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);
@@ -1042,8 +1046,9 @@ static void whiteheat_read_callback(struct urb *urb)
list_del(&wrap->list);
spin_unlock(&info->lock);
- if (urb->status) {
- dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, status);
spin_lock(&info->lock);
list_add(&wrap->list, &info->rx_urbs_free);
spin_unlock(&info->lock);
@@ -1070,6 +1075,7 @@ static void whiteheat_write_callback(struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_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);
@@ -1083,8 +1089,9 @@ static void whiteheat_write_callback(struct urb *urb)
list_move(&wrap->list, &info->tx_urbs_free);
spin_unlock(&info->lock);
- if (urb->status) {
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ if (status) {
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, status);
return;
}
@@ -1095,20 +1102,20 @@ static void whiteheat_write_callback(struct urb *urb)
/*****************************************************************************
* Connect Tech's White Heat firmware interface
*****************************************************************************/
-static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize)
+static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize)
{
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
struct whiteheat_private *info;
__u8 *transfer_buffer;
int retval = 0;
- unsigned long flags;
+ int t;
dbg("%s - command %d", __FUNCTION__, command);
command_port = port->serial->port[COMMAND_PORT];
command_info = usb_get_serial_port_data(command_port);
- spin_lock_irqsave(&command_info->lock, flags);
+ mutex_lock(&command_info->mutex);
command_info->command_finished = false;
transfer_buffer = (__u8 *)command_port->write_urb->transfer_buffer;
@@ -1116,18 +1123,17 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *
memcpy (&transfer_buffer[1], data, datasize);
command_port->write_urb->transfer_buffer_length = datasize + 1;
command_port->write_urb->dev = port->serial->dev;
- retval = usb_submit_urb (command_port->write_urb, GFP_KERNEL);
+ retval = usb_submit_urb (command_port->write_urb, GFP_NOIO);
if (retval) {
dbg("%s - submit urb failed", __FUNCTION__);
goto exit;
}
- spin_unlock_irqrestore(&command_info->lock, flags);
/* wait for the command to complete */
- wait_event_interruptible_timeout(command_info->wait_command,
+ t = wait_event_timeout(command_info->wait_command,
(bool)command_info->command_finished, COMMAND_TIMEOUT);
-
- spin_lock_irqsave(&command_info->lock, flags);
+ if (!t)
+ usb_kill_urb(command_port->write_urb);
if (command_info->command_finished == false) {
dbg("%s - command timed out.", __FUNCTION__);
@@ -1152,7 +1158,7 @@ static int firm_send_command (struct usb_serial_port *port, __u8 command, __u8 *
}
exit:
- spin_unlock_irqrestore(&command_info->lock, flags);
+ mutex_unlock(&command_info->mutex);
return retval;
}
@@ -1305,12 +1311,11 @@ static int start_command_port(struct usb_serial *serial)
{
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
- unsigned long flags;
int retval = 0;
command_port = serial->port[COMMAND_PORT];
command_info = usb_get_serial_port_data(command_port);
- spin_lock_irqsave(&command_info->lock, flags);
+ mutex_lock(&command_info->mutex);
if (!command_info->port_running) {
/* Work around HCD bugs */
usb_clear_halt(serial->dev, command_port->read_urb->pipe);
@@ -1325,7 +1330,7 @@ static int start_command_port(struct usb_serial *serial)
command_info->port_running++;
exit:
- spin_unlock_irqrestore(&command_info->lock, flags);
+ mutex_unlock(&command_info->mutex);
return retval;
}
@@ -1334,15 +1339,14 @@ static void stop_command_port(struct usb_serial *serial)
{
struct usb_serial_port *command_port;
struct whiteheat_command_private *command_info;
- unsigned long flags;
command_port = serial->port[COMMAND_PORT];
command_info = usb_get_serial_port_data(command_port);
- spin_lock_irqsave(&command_info->lock, flags);
+ mutex_lock(&command_info->mutex);
command_info->port_running--;
if (!command_info->port_running)
usb_kill_urb(command_port->read_urb);
- spin_unlock_irqrestore(&command_info->lock, flags);
+ mutex_unlock(&command_info->mutex);
}
@@ -1363,17 +1367,23 @@ static int start_port_read(struct usb_serial_port *port)
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
urb->dev = port->serial->dev;
+ spin_unlock_irqrestore(&info->lock, flags);
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
+ spin_lock_irqsave(&info->lock, flags);
list_add(tmp, &info->rx_urbs_free);
list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) {
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
+ list_del(tmp);
+ spin_unlock_irqrestore(&info->lock, flags);
usb_kill_urb(urb);
- list_move(tmp, &info->rx_urbs_free);
+ spin_lock_irqsave(&info->lock, flags);
+ list_add(tmp, &info->rx_urbs_free);
}
break;
}
+ spin_lock_irqsave(&info->lock, flags);
list_add(tmp, &info->rx_urbs_submitted);
}
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
index 1628cb258562..9a410b5a6e5b 100644
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -46,43 +46,43 @@
*/
int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
{
- int ret;
+ int ret;
- if(srb == NULL)
- return USB_STOR_TRANSPORT_ERROR;
+ if (srb == NULL)
+ return USB_STOR_TRANSPORT_ERROR;
- US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+ US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
- switch(srb->device->lun) {
- case 0:
+ switch (srb->device->lun) {
+ case 0:
- /*
- * LUN 0 corresponds to the CompactFlash card reader.
- */
- ret = usb_stor_CB_transport(srb, us);
- break;
+ /*
+ * LUN 0 corresponds to the CompactFlash card reader.
+ */
+ ret = usb_stor_CB_transport(srb, us);
+ break;
#ifdef CONFIG_USB_STORAGE_SDDR09
- case 1:
+ case 1:
- /*
- * LUN 1 corresponds to the SmartMedia card reader.
- */
+ /*
+ * LUN 1 corresponds to the SmartMedia card reader.
+ */
- /*
- * Set the LUN to 0 (just in case).
- */
- srb->device->lun = 0; us->srb->device->lun = 0;
- ret = sddr09_transport(srb, us);
- srb->device->lun = 1; us->srb->device->lun = 1;
- break;
+ /*
+ * Set the LUN to 0 (just in case).
+ */
+ srb->device->lun = 0; us->srb->device->lun = 0;
+ ret = sddr09_transport(srb, us);
+ srb->device->lun = 1; us->srb->device->lun = 1;
+ break;
#endif
- default:
- US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
- ret = USB_STOR_TRANSPORT_ERROR;
- break;
- }
- return ret;
+ default:
+ US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+ ret = USB_STOR_TRANSPORT_ERROR;
+ break;
+ }
+ return ret;
}
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d35369392fed..dfd42fe9e5f0 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -57,9 +57,10 @@ static void usb_onetouch_irq(struct urb *urb)
struct usb_onetouch *onetouch = urb->context;
signed char *data = onetouch->data;
struct input_dev *dev = onetouch->dev;
- int status;
+ int status = urb->status;
+ int retval;
- switch (urb->status) {
+ switch (status) {
case 0: /* success */
break;
case -ECONNRESET: /* unlink */
@@ -75,11 +76,11 @@ static void usb_onetouch_irq(struct urb *urb)
input_sync(dev);
resubmit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
- if (status)
- err ("can't resubmit intr, %s-%s/input0, status %d",
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ err ("can't resubmit intr, %s-%s/input0, retval %d",
onetouch->udev->bus->bus_name,
- onetouch->udev->devpath, status);
+ onetouch->udev->devpath, retval);
}
static int usb_onetouch_open(struct input_dev *dev)
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e227f64d5641..47e56079925d 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -285,10 +285,15 @@ static int device_reset(struct scsi_cmnd *srb)
US_DEBUGP("%s called\n", __FUNCTION__);
- /* lock the device pointers and do the reset */
- mutex_lock(&(us->dev_mutex));
- result = us->transport_reset(us);
- mutex_unlock(&us->dev_mutex);
+ result = usb_autopm_get_interface(us->pusb_intf);
+ if (result == 0) {
+
+ /* lock the device pointers and do the reset */
+ mutex_lock(&(us->dev_mutex));
+ result = us->transport_reset(us);
+ mutex_unlock(&us->dev_mutex);
+ usb_autopm_put_interface(us->pusb_intf);
+ }
return result < 0 ? FAILED : SUCCESS;
}
@@ -321,10 +326,14 @@ void usb_stor_report_device_reset(struct us_data *us)
/* Report a driver-initiated bus reset to the SCSI layer.
* Calling this for a SCSI-initiated reset is unnecessary but harmless.
- * The caller must own the SCSI host lock. */
+ * The caller must not own the SCSI host lock. */
void usb_stor_report_bus_reset(struct us_data *us)
{
- scsi_report_bus_reset(us_to_host(us), 0);
+ struct Scsi_Host *host = us_to_host(us);
+
+ scsi_lock(host);
+ scsi_report_bus_reset(host, 0);
+ scsi_unlock(host);
}
/***********************************************************************
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 54979c239c63..a624e72f81dc 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -50,10 +50,10 @@
/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
*/
UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
- "ATMEL",
- "SND1 Storage",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE),
+ "ATMEL",
+ "SND1 Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
/* modified by Tobias Lorenz <tobias.lorenz@gmx.net> */
UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200,
@@ -69,18 +69,18 @@ UNUSUAL_DEV( 0x03ee, 0x6906, 0x0003, 0x0003,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
-UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x03f0, 0x0107, 0x0200, 0x0200,
"HP",
"CD-Writer+",
- US_SC_8070, US_PR_CB, NULL, 0),
+ US_SC_8070, US_PR_CB, NULL, 0),
#ifdef CONFIG_USB_STORAGE_USBAT
-UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
+UNUSUAL_DEV( 0x03f0, 0x0207, 0x0001, 0x0001,
"HP",
"CD-Writer+ 8200e",
US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
-UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
+UNUSUAL_DEV( 0x03f0, 0x0307, 0x0001, 0x0001,
"HP",
"CD-Writer+ CD-4e",
US_SC_8070, US_PR_USBAT, init_usbat_cd, 0),
@@ -115,10 +115,10 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113,
/* Submitted by Ernestas Vaiciukevicius <ernisv@gmail.com> */
UNUSUAL_DEV( 0x0419, 0x0100, 0x0100, 0x0100,
- "Samsung Info. Systems America, Inc.",
- "MP3 Player",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE ),
+ "Samsung Info. Systems America, Inc.",
+ "MP3 Player",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
/* Reported by Orgad Shaneh <orgads@gmail.com> */
UNUSUAL_DEV( 0x0419, 0xaace, 0x0100, 0x0100,
@@ -256,10 +256,10 @@ UNUSUAL_DEV( 0x0457, 0x0150, 0x0100, 0x0100,
* the revision to my model only
*/
UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x0100,
- "USB 2.0",
- "Flash Disk",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_NOT_LOCKABLE ),
+ "USB 2.0",
+ "Flash Disk",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE ),
#ifdef CONFIG_USB_STORAGE_KARMA
UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101,
@@ -313,6 +313,13 @@ UNUSUAL_DEV( 0x04b0, 0x0301, 0x0010, 0x0010,
US_SC_DEVICE, US_PR_DEVICE,NULL,
US_FL_NOT_LOCKABLE ),
+/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
+UNUSUAL_DEV( 0x04b0, 0x0401, 0x0200, 0x0200,
+ "NIKON",
+ "NIKON DSC D100",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY),
+
/* Reported by Andreas Bockhold <andreas@bockionline.de> */
UNUSUAL_DEV( 0x04b0, 0x0405, 0x0100, 0x0100,
"NIKON",
@@ -408,19 +415,19 @@ UNUSUAL_DEV( 0x04da, 0x2373, 0x0000, 0x9999,
/* Most of the following entries were developed with the help of
* Shuttle/SCM directly.
*/
-UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0001, 0x0200, 0x0200,
"Matshita",
"LS-120",
US_SC_8020, US_PR_CB, NULL, 0),
-UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x0002, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG ),
+ US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_SDDR09
-UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
+UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
"Sandisk",
"ImageMate SDDR09",
US_SC_SCSI, US_PR_EUSB_SDDR09, usb_stor_sddr09_init,
@@ -431,52 +438,52 @@ UNUSUAL_DEV( 0x04e6, 0x0005, 0x0100, 0x0208,
"SCM Microsystems",
"eUSB SmartMedia / CompactFlash Adapter",
US_SC_SCSI, US_PR_DPCM_USB, usb_stor_sddr09_dpcm_init,
- 0),
+ 0),
#endif
/* Reported by Markus Demleitner <msdemlei@cl.uni-heidelberg.de> */
-UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x0006, 0x0100, 0x0100,
"SCM Microsystems Inc.",
"eUSB MMC Adapter",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN),
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN),
/* Reported by Daniel Nouri <dpunktnpunkt@web.de> */
-UNUSUAL_DEV( 0x04e6, 0x0006, 0x0205, 0x0205,
+UNUSUAL_DEV( 0x04e6, 0x0006, 0x0205, 0x0205,
"Shuttle",
"eUSB MMC Adapter",
- US_SC_SCSI, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN),
+ US_SC_SCSI, US_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN),
-UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0007, 0x0100, 0x0200,
"Sony",
"Hifd",
- US_SC_SCSI, US_PR_CB, NULL,
- US_FL_SINGLE_LUN),
+ US_SC_SCSI, US_PR_CB, NULL,
+ US_FL_SINGLE_LUN),
-UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0009, 0x0200, 0x0200,
"Shuttle",
"eUSB ATA/ATAPI Adapter",
US_SC_8020, US_PR_CB, NULL, 0),
-UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x000a, 0x0200, 0x0200,
"Shuttle",
"eUSB CompactFlash Adapter",
US_SC_8020, US_PR_CB, NULL, 0),
-UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x000B, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+ US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
-UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x04e6, 0x000C, 0x0100, 0x0100,
"Shuttle",
"eUSCSI Bridge",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG ),
+ US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+ US_FL_SCM_MULT_TARG ),
-UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
+UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
"Shuttle",
"CD-RW Device",
US_SC_8020, US_PR_CB, NULL, 0),
@@ -556,9 +563,9 @@ UNUSUAL_DEV( 0x052b, 0x1911, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
-UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
+UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
"Sony",
- "DSC-S30/S70/S75/505V/F505/F707/F717/P8",
+ "DSC-S30/S70/S75/505V/F505/F707/F717/P8",
US_SC_SCSI, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
@@ -572,7 +579,7 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0610,
/* Reported by wim@geeks.nl */
-UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100,
"Sony",
"Memorystick NW-MS7",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -593,21 +600,21 @@ UNUSUAL_DEV( 0x054c, 0x002c, 0x0501, 0x2000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
-UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x054c, 0x002d, 0x0100, 0x0100,
"Sony",
"Memorystick MSAC-US1",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
/* Submitted by Klaus Mueller <k.mueller@intershop.de> */
-UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310,
+UNUSUAL_DEV( 0x054c, 0x002e, 0x0106, 0x0310,
"Sony",
"Handycam",
US_SC_SCSI, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
/* Submitted by Rajesh Kumble Nayak <nayak@obs-nice.fr> */
-UNUSUAL_DEV( 0x054c, 0x002e, 0x0500, 0x0500,
+UNUSUAL_DEV( 0x054c, 0x002e, 0x0500, 0x0500,
"Sony",
"Handycam HC-85",
US_SC_UFI, US_PR_DEVICE, NULL,
@@ -648,26 +655,26 @@ UNUSUAL_DEV( 0x054c, 0x016a, 0x0000, 0x9999,
/* Submitted by Frank Engel <frankie@cse.unsw.edu.au> */
UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999,
- "Sony",
- "PEG Mass Storage",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY ),
+ "Sony",
+ "PEG Mass Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_INQUIRY ),
/* floppy reports multiple luns */
UNUSUAL_DEV( 0x055d, 0x2020, 0x0000, 0x0210,
- "SAMSUNG",
- "SFD-321U [FW 0C]",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_SINGLE_LUN ),
+ "SAMSUNG",
+ "SFD-321U [FW 0C]",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
-UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
+UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
"Flashbuster-U",
US_SC_DEVICE, US_PR_CB, NULL,
US_FL_SINGLE_LUN),
-UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
+UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
"Y-E Data",
"Flashbuster-U",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -677,7 +684,7 @@ UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
* This entry is needed only because the device reports
* bInterfaceClass = 0xff (vendor-specific)
*/
-UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999,
+UNUSUAL_DEV( 0x057b, 0x0022, 0x0000, 0x9999,
"Y-E Data",
"Silicon Media R/W",
US_SC_DEVICE, US_PR_DEVICE, NULL, 0),
@@ -825,13 +832,13 @@ UNUSUAL_DEV( 0x0636, 0x0003, 0x0000, 0x9999,
US_SC_SCSI, US_PR_BULK, NULL,
US_FL_FIX_INQUIRY ),
-UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x0644, 0x0000, 0x0100, 0x0100,
"TEAC",
"Floppy Drive",
- US_SC_UFI, US_PR_CB, NULL, 0 ),
+ US_SC_UFI, US_PR_CB, NULL, 0 ),
#ifdef CONFIG_USB_STORAGE_SDDR09
-UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x066b, 0x0105, 0x0100, 0x0100,
"Olympus",
"Camedia MAUSB-2",
US_SC_SCSI, US_PR_EUSB_SDDR09, usb_stor_sddr09_init,
@@ -867,14 +874,14 @@ UNUSUAL_DEV( 0x0686, 0x4011, 0x0001, 0x0001,
/* Reported by Miguel A. Fosas <amn3s1a@ono.com> */
UNUSUAL_DEV( 0x0686, 0x4017, 0x0001, 0x0001,
- "Minolta",
- "DIMAGE E223",
- US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
+ "Minolta",
+ "DIMAGE E223",
+ US_SC_SCSI, US_PR_DEVICE, NULL, 0 ),
UNUSUAL_DEV( 0x0693, 0x0005, 0x0100, 0x0100,
"Hagiwara",
"Flashgate",
- US_SC_SCSI, US_PR_BULK, NULL, 0 ),
+ US_SC_SCSI, US_PR_BULK, NULL, 0 ),
/* Reported by David Hamilton <niftimusmaximus@lycos.com> */
UNUSUAL_DEV( 0x069b, 0x3004, 0x0001, 0x0001,
@@ -918,7 +925,7 @@ UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100,
US_FL_SINGLE_LUN ),
#ifdef CONFIG_USB_STORAGE_SDDR09
-UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999,
+UNUSUAL_DEV( 0x0781, 0x0200, 0x0000, 0x9999,
"Sandisk",
"ImageMate SDDR-09",
US_SC_SCSI, US_PR_EUSB_SDDR09, usb_stor_sddr09_init,
@@ -939,17 +946,17 @@ UNUSUAL_DEV( 0x07ab, 0xfccd, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY),
-UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133,
+UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133,
"Microtech",
"USB-SCSI-DB25",
US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
-UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
+UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-HD50",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
- US_FL_SCM_MULT_TARG ),
+ US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_DPCM
UNUSUAL_DEV( 0x07af, 0x0006, 0x0100, 0x0100,
@@ -1053,10 +1060,10 @@ UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0xffff,
* as "DualSlot CompactFlash(TM) & MStick Drive USB"
*/
UNUSUAL_DEV( 0x07c4, 0xa10b, 0x0000, 0xffff,
- "DataFab Systems Inc.",
- "USB CF+MS",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- 0 ),
+ "DataFab Systems Inc.",
+ "USB CF+MS",
+ US_SC_SCSI, US_PR_DATAFAB, NULL,
+ 0 ),
#endif
@@ -1119,10 +1126,10 @@ UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
* US_FL_IGNORE_RESIDUE Needed
*/
UNUSUAL_DEV( 0x08ca, 0x3103, 0x0100, 0x0100,
- "AIPTEK",
- "Aiptek USB Keychain MP3 Player",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_RESIDUE),
+ "AIPTEK",
+ "Aiptek USB Keychain MP3 Player",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE),
/* Entry needed for flags. Moreover, all devices with this ID use
* bulk-only transport, but _some_ falsely report Control/Bulk instead.
@@ -1166,26 +1173,26 @@ UNUSUAL_DEV( 0x090c, 0x1132, 0x0000, 0xffff,
* Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
*/
UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
- "Pentax",
- "Optio 2/3/400",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY ),
+ "Pentax",
+ "Optio 2/3/400",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_INQUIRY ),
/* Submitted by Per Winkvist <per.winkvist@uk.com> */
UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
- "Pentax",
- "Optio S/S4",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_FIX_INQUIRY ),
+ "Pentax",
+ "Optio S/S4",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_INQUIRY ),
/* These are virtual windows driver CDs, which the zd1211rw driver
* automatically converts into WLAN devices. */
UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101,
- "ZyXEL",
- "G-220F USB-WLAN Install",
- US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_IGNORE_DEVICE ),
+ "ZyXEL",
+ "G-220F USB-WLAN Install",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE ),
UNUSUAL_DEV( 0x0ace, 0x20ff, 0x0101, 0x0101,
"SiteCom",
@@ -1211,17 +1218,17 @@ UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
#ifdef CONFIG_USB_STORAGE_DATAFAB
UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
- "Acomdata",
- "CF",
- US_SC_SCSI, US_PR_DATAFAB, NULL,
- US_FL_SINGLE_LUN ),
+ "Acomdata",
+ "CF",
+ US_SC_SCSI, US_PR_DATAFAB, NULL,
+ US_FL_SINGLE_LUN ),
#endif
#ifdef CONFIG_USB_STORAGE_SDDR55
UNUSUAL_DEV( 0x0c0b, 0xa109, 0x0000, 0xffff,
- "Acomdata",
- "SM",
- US_SC_SCSI, US_PR_SDDR55, NULL,
- US_FL_SINGLE_LUN ),
+ "Acomdata",
+ "SM",
+ US_SC_SCSI, US_PR_SDDR55, NULL,
+ US_FL_SINGLE_LUN ),
#endif
/* Submitted by: Nick Sillik <n.sillik@temple.edu>
@@ -1384,6 +1391,17 @@ UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
0 ),
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV( 0x1199, 0x0fff, 0x0000, 0x9999,
+ "Sierra Wireless",
+ "USB MMC Storage",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE),
+
/* Reported by Jaco Kroon <jaco@kroon.co.za>
* The usb-storage module found on the Digitech GNX4 (and supposedly other
* devices) misbehaves and causes a bunch of invalid I/O errors.
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 8e898e3d861e..28842d208bb0 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -191,16 +191,13 @@ static int storage_suspend(struct usb_interface *iface, pm_message_t message)
{
struct us_data *us = usb_get_intfdata(iface);
+ US_DEBUGP("%s\n", __FUNCTION__);
+
/* Wait until no command is running */
mutex_lock(&us->dev_mutex);
- US_DEBUGP("%s\n", __FUNCTION__);
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_SUSPEND);
- iface->dev.power.power_state.event = message.event;
-
- /* When runtime PM is working, we'll set a flag to indicate
- * whether we should autoresume when a SCSI request arrives. */
mutex_unlock(&us->dev_mutex);
return 0;
@@ -210,14 +207,25 @@ static int storage_resume(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
- mutex_lock(&us->dev_mutex);
-
US_DEBUGP("%s\n", __FUNCTION__);
+
if (us->suspend_resume_hook)
(us->suspend_resume_hook)(us, US_RESUME);
- iface->dev.power.power_state.event = PM_EVENT_ON;
- mutex_unlock(&us->dev_mutex);
+ return 0;
+}
+
+static int storage_reset_resume(struct usb_interface *iface)
+{
+ struct us_data *us = usb_get_intfdata(iface);
+
+ US_DEBUGP("%s\n", __FUNCTION__);
+
+ /* Report the reset to the SCSI core */
+ usb_stor_report_bus_reset(us);
+
+ /* FIXME: Notify the subdrivers that they need to reinitialize
+ * the device */
return 0;
}
@@ -228,7 +236,7 @@ static int storage_resume(struct usb_interface *iface)
* a USB port reset, whether from this driver or a different one.
*/
-static void storage_pre_reset(struct usb_interface *iface)
+static int storage_pre_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
@@ -236,22 +244,23 @@ static void storage_pre_reset(struct usb_interface *iface)
/* Make sure no command runs during the reset */
mutex_lock(&us->dev_mutex);
+ return 0;
}
-static void storage_post_reset(struct usb_interface *iface)
+static int storage_post_reset(struct usb_interface *iface)
{
struct us_data *us = usb_get_intfdata(iface);
US_DEBUGP("%s\n", __FUNCTION__);
/* Report the reset to the SCSI core */
- scsi_lock(us_to_host(us));
usb_stor_report_bus_reset(us);
- scsi_unlock(us_to_host(us));
/* FIXME: Notify the subdrivers that they need to reinitialize
* the device */
+
mutex_unlock(&us->dev_mutex);
+ return 0;
}
/*
@@ -300,8 +309,7 @@ static int usb_stor_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
-
- current->flags |= PF_NOFREEZE;
+ int autopm_rc;
for(;;) {
US_DEBUGP("*** thread sleeping.\n");
@@ -310,6 +318,9 @@ static int usb_stor_control_thread(void * __us)
US_DEBUGP("*** thread awakened.\n");
+ /* Autoresume the device */
+ autopm_rc = usb_autopm_get_interface(us->pusb_intf);
+
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
@@ -368,6 +379,12 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = SAM_STAT_GOOD;
}
+ /* Did the autoresume fail? */
+ else if (autopm_rc < 0) {
+ US_DEBUGP("Could not wake device\n");
+ us->srb->result = DID_ERROR << 16;
+ }
+
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
@@ -410,25 +427,21 @@ SkipForAbort:
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
- } /* for (;;) */
- scsi_host_put(host);
+ /* Start an autosuspend */
+ if (autopm_rc == 0)
+ usb_autopm_put_interface(us->pusb_intf);
+ } /* for (;;) */
- /* notify the exit routine that we're actually exiting now
- *
- * complete()/wait_for_completion() is similar to up()/down(),
- * except that complete() is safe in the case where the structure
- * is getting deleted in a parallel mode of execution (i.e. just
- * after the down() -- that's necessary for the thread-shutdown
- * case.
- *
- * complete_and_exit() goes even further than this -- it is safe in
- * the case that the thread of the caller is going away (not just
- * the structure) -- this is necessary for the module-remove case.
- * This is important in preemption kernels, which transfer the flow
- * of execution immediately upon a complete().
- */
- complete_and_exit(&threads_gone, 0);
+ /* Wait until we are told to stop */
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (kthread_should_stop())
+ break;
+ schedule();
+ }
+ __set_current_state(TASK_RUNNING);
+ return 0;
}
/***********************************************************************
@@ -796,19 +809,13 @@ static int usb_stor_acquire_resources(struct us_data *us)
}
/* Start up our control thread */
- th = kthread_create(usb_stor_control_thread, us, "usb-storage");
+ th = kthread_run(usb_stor_control_thread, us, "usb-storage");
if (IS_ERR(th)) {
printk(KERN_WARNING USB_STORAGE
"Unable to start control thread\n");
return PTR_ERR(th);
}
-
- /* Take a reference to the host for the control thread and
- * count it among all the threads we have launched. Then
- * start it up. */
- scsi_host_get(us_to_host(us));
- atomic_inc(&total_threads);
- wake_up_process(th);
+ us->ctl_thread = th;
return 0;
}
@@ -825,6 +832,8 @@ static void usb_stor_release_resources(struct us_data *us)
US_DEBUGP("-- sending exit command to thread\n");
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
up(&us->sema);
+ if (us->ctl_thread)
+ kthread_stop(us->ctl_thread);
/* Call the destructor routine, if it exists */
if (us->extra_destructor) {
@@ -909,6 +918,7 @@ static int usb_stor_scan_thread(void * __us)
printk(KERN_DEBUG
"usb-storage: device found at %d\n", us->pusb_dev->devnum);
+ set_freezable();
/* Wait for the timeout to expire or for a disconnect */
if (delay_use > 0) {
printk(KERN_DEBUG "usb-storage: waiting for device "
@@ -938,6 +948,7 @@ retry:
}
scsi_host_put(us_to_host(us));
+ usb_autopm_put_interface(us->pusb_intf);
complete_and_exit(&threads_gone, 0);
}
@@ -1027,6 +1038,7 @@ static int storage_probe(struct usb_interface *intf,
* start it up. */
scsi_host_get(us_to_host(us));
atomic_inc(&total_threads);
+ usb_autopm_get_interface(intf); /* dropped in the scanning thread */
wake_up_process(th);
return 0;
@@ -1059,10 +1071,12 @@ static struct usb_driver usb_storage_driver = {
#ifdef CONFIG_PM
.suspend = storage_suspend,
.resume = storage_resume,
+ .reset_resume = storage_reset_resume,
#endif
.pre_reset = storage_pre_reset,
.post_reset = storage_post_reset,
.id_table = storage_usb_ids,
+ .supports_autosuspend = 1,
};
static int __init usb_stor_init(void)
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 6dac1ffdde86..6445665b1577 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -144,6 +144,7 @@ struct us_data {
unsigned char *sensebuf; /* sense data buffer */
dma_addr_t cr_dma; /* buffer DMA addresses */
dma_addr_t iobuf_dma;
+ struct task_struct *ctl_thread; /* the control thread */
/* mutual exclusion and synchronization structures */
struct semaphore sema; /* to sleep thread on */
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 8432bf171d2e..8de11deb5d14 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -34,9 +34,6 @@ static struct usb_device_id skel_table [] = {
};
MODULE_DEVICE_TABLE(usb, skel_table);
-/* to prevent a race between open and disconnect */
-static DEFINE_MUTEX(skel_open_lock);
-
/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192
@@ -54,16 +51,21 @@ struct usb_skel {
struct usb_device *udev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct semaphore limit_sem; /* limiting the number of writes in progress */
+ struct usb_anchor submitted; /* in case we need to retract our submissions */
unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
+ int errors; /* the last request tanked */
+ int open_count; /* count the number of openers */
+ spinlock_t err_lock; /* lock for errors */
struct kref kref;
struct mutex io_mutex; /* synchronize I/O with disconnect */
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
static struct usb_driver skel_driver;
+static void skel_draw_down(struct usb_skel *dev);
static void skel_delete(struct kref *kref)
{
@@ -83,10 +85,8 @@ static int skel_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
- mutex_lock(&skel_open_lock);
interface = usb_find_interface(&skel_driver, subminor);
if (!interface) {
- mutex_unlock(&skel_open_lock);
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
@@ -95,22 +95,33 @@ static int skel_open(struct inode *inode, struct file *file)
dev = usb_get_intfdata(interface);
if (!dev) {
- mutex_unlock(&skel_open_lock);
retval = -ENODEV;
goto exit;
}
/* increment our usage count for the device */
kref_get(&dev->kref);
- /* now we can drop the lock */
- mutex_unlock(&skel_open_lock);
- /* prevent the device from being autosuspended */
- retval = usb_autopm_get_interface(interface);
- if (retval) {
+ /* lock the device to allow correctly handling errors
+ * in resumption */
+ mutex_lock(&dev->io_mutex);
+
+ if (!dev->open_count++) {
+ retval = usb_autopm_get_interface(interface);
+ if (retval) {
+ dev->open_count--;
+ mutex_unlock(&dev->io_mutex);
+ kref_put(&dev->kref, skel_delete);
+ goto exit;
+ }
+ } /* else { //uncomment this block if you want exclusive open
+ retval = -EBUSY;
+ dev->open_count--;
+ mutex_unlock(&dev->io_mutex);
kref_put(&dev->kref, skel_delete);
goto exit;
- }
+ } */
+ /* prevent the device from being autosuspended */
/* save our object in the file's private structure */
file->private_data = dev;
@@ -129,7 +140,7 @@ static int skel_release(struct inode *inode, struct file *file)
/* allow the device to be autosuspended */
mutex_lock(&dev->io_mutex);
- if (dev->interface)
+ if (!--dev->open_count && dev->interface)
usb_autopm_put_interface(dev->interface);
mutex_unlock(&dev->io_mutex);
@@ -138,6 +149,30 @@ static int skel_release(struct inode *inode, struct file *file)
return 0;
}
+static int skel_flush(struct file *file, fl_owner_t id)
+{
+ struct usb_skel *dev;
+ int res;
+
+ dev = (struct usb_skel *)file->private_data;
+ if (dev == NULL)
+ return -ENODEV;
+
+ /* wait for io to stop */
+ mutex_lock(&dev->io_mutex);
+ skel_draw_down(dev);
+
+ /* read out errors, leave subsequent opens a clean slate */
+ spin_lock_irq(&dev->err_lock);
+ res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0;
+ dev->errors = 0;
+ spin_unlock_irq(&dev->err_lock);
+
+ mutex_unlock(&dev->io_mutex);
+
+ return res;
+}
+
static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct usb_skel *dev;
@@ -179,12 +214,16 @@ static void skel_write_bulk_callback(struct urb *urb)
dev = (struct usb_skel *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
- urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN)) {
- err("%s - nonzero write bulk status received: %d",
- __FUNCTION__, urb->status);
+ if (urb->status) {
+ if(!(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN))
+ err("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+
+ spin_lock(&dev->err_lock);
+ dev->errors = urb->status;
+ spin_unlock(&dev->err_lock);
}
/* free up our allocated buffer */
@@ -213,6 +252,17 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
goto exit;
}
+ spin_lock_irq(&dev->err_lock);
+ if ((retval = dev->errors) < 0) {
+ /* any error is reported once */
+ dev->errors = 0;
+ /* to preserve notifications about reset */
+ retval = (retval == -EPIPE) ? retval : -EIO;
+ }
+ spin_unlock_irq(&dev->err_lock);
+ if (retval < 0)
+ goto error;
+
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
@@ -244,13 +294,14 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, writesize, skel_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ usb_anchor_urb(urb, &dev->submitted);
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
mutex_unlock(&dev->io_mutex);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
- goto error;
+ goto error_unanchor;
}
/* release our reference to this urb, the USB core will eventually free it entirely */
@@ -259,6 +310,8 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
return writesize;
+error_unanchor:
+ usb_unanchor_urb(urb);
error:
if (urb) {
usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
@@ -276,6 +329,7 @@ static const struct file_operations skel_fops = {
.write = skel_write,
.open = skel_open,
.release = skel_release,
+ .flush = skel_flush,
};
/*
@@ -306,6 +360,8 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
kref_init(&dev->kref);
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
mutex_init(&dev->io_mutex);
+ spin_lock_init(&dev->err_lock);
+ init_usb_anchor(&dev->submitted);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
@@ -368,22 +424,18 @@ static void skel_disconnect(struct usb_interface *interface)
struct usb_skel *dev;
int minor = interface->minor;
- /* prevent skel_open() from racing skel_disconnect() */
- mutex_lock(&skel_open_lock);
-
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &skel_class);
- mutex_unlock(&skel_open_lock);
/* prevent more I/O from starting */
mutex_lock(&dev->io_mutex);
dev->interface = NULL;
mutex_unlock(&dev->io_mutex);
-
+ usb_kill_anchored_urbs(&dev->submitted);
/* decrement our usage count */
kref_put(&dev->kref, skel_delete);
@@ -391,10 +443,59 @@ static void skel_disconnect(struct usb_interface *interface)
info("USB Skeleton #%d now disconnected", minor);
}
+static void skel_draw_down(struct usb_skel *dev)
+{
+ int time;
+
+ time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
+ if (!time)
+ usb_kill_anchored_urbs(&dev->submitted);
+}
+
+static int skel_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct usb_skel *dev = usb_get_intfdata(intf);
+
+ if (!dev)
+ return 0;
+ skel_draw_down(dev);
+ return 0;
+}
+
+static int skel_resume (struct usb_interface *intf)
+{
+ return 0;
+}
+
+static int skel_pre_reset(struct usb_interface *intf)
+{
+ struct usb_skel *dev = usb_get_intfdata(intf);
+
+ mutex_lock(&dev->io_mutex);
+ skel_draw_down(dev);
+
+ return 0;
+}
+
+static int skel_post_reset(struct usb_interface *intf)
+{
+ struct usb_skel *dev = usb_get_intfdata(intf);
+
+ /* we are sure no URBs are active - no locking needed */
+ dev->errors = -EPIPE;
+ mutex_unlock(&dev->io_mutex);
+
+ return 0;
+}
+
static struct usb_driver skel_driver = {
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
+ .suspend = skel_suspend,
+ .resume = skel_resume,
+ .pre_reset = skel_pre_reset,
+ .post_reset = skel_post_reset,
.id_table = skel_table,
.supports_autosuspend = 1,
};
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
index 0dda73da8628..7f907fb23b8a 100644
--- a/drivers/video/68328fb.c
+++ b/drivers/video/68328fb.c
@@ -60,7 +60,7 @@ static u_long videomemory;
static u_long videomemorysize;
static struct fb_info fb_info;
-static u32 mc68x328fb_pseudo_palette[17];
+static u32 mc68x328fb_pseudo_palette[16];
static struct fb_var_screeninfo mc68x328fb_default __initdata = {
.red = { 0, 8, 0 },
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 403dac787ebf..564cc9b51822 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -12,6 +12,13 @@ config VGASTATE
tristate
default n
+config VIDEO_OUTPUT_CONTROL
+ tristate "Lowlevel video output switch controls"
+ default m
+ help
+ This framework adds support for low-level control of the video
+ output switch.
+
config FB
tristate "Support for frame buffer devices"
---help---
@@ -812,7 +819,7 @@ config FB_PVR2
config FB_EPSON1355
bool "Epson 1355 framebuffer support"
- depends on (FB = y) && (SUPERH || ARCH_CEIVA)
+ depends on (FB = y) && ARCH_CEIVA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -849,6 +856,16 @@ config FB_INTSRAM
Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
to let frame buffer in external SDRAM.
+config FB_ATMEL_STN
+ bool "Use a STN display with AT91/AT32 LCD Controller"
+ depends on FB_ATMEL && MACH_AT91SAM9261EK
+ default n
+ help
+ Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD
+ Controller. Say N if you want to connect a TFT.
+
+ If unsure, say N.
+
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
depends on FB && PCI
@@ -1790,19 +1807,20 @@ config FB_IBM_GXT4500
adaptor, found on some IBM System P (pSeries) machines.
config FB_PS3
- bool "PS3 GPU framebuffer driver"
- depends on (FB = y) && PS3_PS3AV
+ tristate "PS3 GPU framebuffer driver"
+ depends on FB && PS3_PS3AV
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
+ select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
---help---
Include support for the virtual frame buffer in the PS3 platform.
config FB_PS3_DEFAULT_SIZE_M
int "PS3 default frame buffer size (in MiB)"
depends on FB_PS3
- default 18
+ default 9
---help---
This is the default size (in MiB) of the virtual frame buffer in
the PS3.
@@ -1820,6 +1838,10 @@ config FB_XILINX
framebuffer. ML300 carries a 640*480 LCD display on the board,
ML403 uses a standard DB15 VGA connector.
+if ARCH_OMAP
+ source "drivers/video/omap/Kconfig"
+endif
+
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index bd8b05229500..518933d4905f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -113,6 +113,7 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
+obj-$(CONFIG_FB_OMAP) += omap/
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
@@ -122,3 +123,6 @@ obj-$(CONFIG_FB_OF) += offb.o
# the test framebuffer is last
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
+
+#video output switch sysfs driver
+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 6c9dc2e69c82..a7a1c891bfa2 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -447,13 +447,12 @@ static int clcdfb_probe(struct amba_device *dev, void *id)
goto out;
}
- fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
+ fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL);
if (!fb) {
printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
ret = -ENOMEM;
goto free_region;
}
- memset(fb, 0, sizeof(struct clcd_fb));
fb->dev = dev;
fb->board = board;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index e1d5bd0c98c4..235b618b4117 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -79,6 +79,29 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
.accel = FB_ACCEL_NONE,
};
+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+{
+ unsigned long value;
+
+ if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000()))
+ return xres;
+
+ value = xres;
+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+ /* STN display */
+ if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+ value *= 3;
+ }
+ if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+ || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+ && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+ value = DIV_ROUND_UP(value, 4);
+ else
+ value = DIV_ROUND_UP(value, 8);
+ }
+
+ return value;
+}
static void atmel_lcdfb_update_dma(struct fb_info *info,
struct fb_var_screeninfo *var)
@@ -181,6 +204,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
var->xoffset = var->yoffset = 0;
switch (var->bits_per_pixel) {
+ case 1:
case 2:
case 4:
case 8:
@@ -195,8 +219,11 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
var->blue.offset = 10;
var->red.length = var->green.length = var->blue.length = 5;
break;
- case 24:
case 32:
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ /* fall through */
+ case 24:
var->red.offset = 0;
var->green.offset = 8;
var->blue.offset = 16;
@@ -228,8 +255,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
static int atmel_lcdfb_set_par(struct fb_info *info)
{
struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned long hozval_linesz;
unsigned long value;
unsigned long clk_value_khz;
+ unsigned long bits_per_line;
dev_dbg(info->device, "%s:\n", __func__);
dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
@@ -241,12 +270,15 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
- if (info->var.bits_per_pixel <= 8)
+ if (info->var.bits_per_pixel == 1)
+ info->fix.visual = FB_VISUAL_MONO01;
+ else if (info->var.bits_per_pixel <= 8)
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
else
info->fix.visual = FB_VISUAL_TRUECOLOR;
- info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+ bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
+ info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
/* Re-initialize the DMA engine... */
dev_dbg(info->device, " * update DMA engine\n");
@@ -262,18 +294,21 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
/* Set pixel clock */
clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
- value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
-
- if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
- value++;
+ value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
value = (value / 2) - 1;
+ dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value);
if (value <= 0) {
dev_notice(info->device, "Bypassing pixel clock divider\n");
lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
- } else
+ } else {
lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+ info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1)));
+ dev_dbg(info->device, " updated pixclk: %lu KHz\n",
+ PICOS2KHZ(info->var.pixclock));
+ }
+
/* Initialize control register 2 */
value = sinfo->default_lcdcon2;
@@ -311,9 +346,14 @@ static int atmel_lcdfb_set_par(struct fb_info *info)
dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+ /* Horizontal value (aka line size) */
+ hozval_linesz = compute_hozval(info->var.xres,
+ lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+
/* Display size */
- value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
value |= info->var.yres - 1;
+ dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value);
lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
/* FIFO Threshold: Use formula from data sheet */
@@ -421,6 +461,15 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
ret = 0;
}
break;
+
+ case FB_VISUAL_MONO01:
+ if (regno < 2) {
+ val = (regno == 0) ? 0x00 : 0x1F;
+ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+ ret = 0;
+ }
+ break;
+
}
return ret;
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
index 90e7df22f508..685a754991c6 100644
--- a/drivers/video/aty/ati_ids.h
+++ b/drivers/video/aty/ati_ids.h
@@ -204,6 +204,7 @@
#define PCI_CHIP_RV280_5961 0x5961
#define PCI_CHIP_RV280_5962 0x5962
#define PCI_CHIP_RV280_5964 0x5964
+#define PCI_CHIP_RS485_5975 0x5975
#define PCI_CHIP_RV280_5C61 0x5C61
#define PCI_CHIP_RV280_5C63 0x5C63
#define PCI_CHIP_R423_5D57 0x5D57
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 7fea4d8ae8e2..cfcbe37d2d70 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1733,7 +1733,7 @@ static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
static int aty128_bl_update_status(struct backlight_device *bd)
{
- struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+ struct aty128fb_par *par = bl_get_data(bd);
unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
int level;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 2fbff6317433..bc6f0096aa04 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -541,7 +541,7 @@ static char ram_off[] __devinitdata = "OFF";
#endif /* CONFIG_FB_ATY_CT */
-static u32 pseudo_palette[17];
+static u32 pseudo_palette[16];
#ifdef CONFIG_FB_ATY_GX
static char *aty_gx_ram[8] __devinitdata = {
@@ -2141,7 +2141,7 @@ static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
static int aty_bl_update_status(struct backlight_device *bd)
{
- struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+ struct atyfb_par *par = bl_get_data(bd);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
int level;
@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
int node, len, i, j, ret;
u32 mem, chip_id;
- /* Do not attach when we have a serial console. */
- if (!con_is_present())
- return -ENXIO;
-
/*
* Map memory-mapped registers.
*/
@@ -2937,12 +2933,11 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
/* nothing */ ;
j = i + 4;
- par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
+ par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC);
if (!par->mmap_map) {
PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
return -ENOMEM;
}
- memset(par->mmap_map, 0, j * sizeof(*par->mmap_map));
for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
struct resource *rp = &pdev->resource[i];
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 0be25fa5540c..1a056adb61c8 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -47,7 +47,7 @@ static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
static int radeon_bl_update_status(struct backlight_device *bd)
{
- struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+ struct radeon_bl_privdata *pdata = bl_get_data(bd);
struct radeonfb_info *rinfo = pdata->rinfo;
u32 lvds_gen_cntl, tmpPixclksCntl;
int level;
@@ -206,7 +206,7 @@ void radeonfb_bl_exit(struct radeonfb_info *rinfo)
if (bd) {
struct radeon_bl_privdata *pdata;
- pdata = class_get_devdata(&bd->class_dev);
+ pdata = bl_get_data(bd);
backlight_device_unregister(bd);
kfree(pdata);
rinfo->info->bl_dev = NULL;
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 2ce050193018..47ca62fe7c3e 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -153,6 +153,8 @@ static struct pci_device_id radeonfb_pci_table[] = {
/* Mobility 9200 (M9+) */
CHIP_DEF(PCI_CHIP_RV280_5C61, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
CHIP_DEF(PCI_CHIP_RV280_5C63, RV280, CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
+ /*Mobility Xpress 200 */
+ CHIP_DEF(PCI_CHIP_RS485_5975, R300, CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
/* 9200 */
CHIP_DEF(PCI_CHIP_RV280_5960, RV280, CHIP_HAS_CRTC2),
CHIP_DEF(PCI_CHIP_RV280_5961, RV280, CHIP_HAS_CRTC2),
@@ -2102,7 +2104,9 @@ static ssize_t radeon_show_one_edid(char *buf, loff_t off, size_t count, const u
}
-static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t radeon_show_edid1(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pci_dev *pdev = to_pci_dev(dev);
@@ -2113,7 +2117,9 @@ static ssize_t radeon_show_edid1(struct kobject *kobj, char *buf, loff_t off, si
}
-static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t radeon_show_edid2(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct pci_dev *pdev = to_pci_dev(dev);
@@ -2126,7 +2132,6 @@ static ssize_t radeon_show_edid2(struct kobject *kobj, char *buf, loff_t off, si
static struct bin_attribute edid1_attr = {
.attr = {
.name = "edid1",
- .owner = THIS_MODULE,
.mode = 0444,
},
.size = EDID_LENGTH,
@@ -2136,7 +2141,6 @@ static struct bin_attribute edid1_attr = {
static struct bin_attribute edid2_attr = {
.attr = {
.name = "edid2",
- .owner = THIS_MODULE,
.mode = 0444,
},
.size = EDID_LENGTH,
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 7ebffcdfd1e3..7c922c7b460b 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -301,7 +301,7 @@ struct radeonfb_info {
void __iomem *bios_seg;
int fp_bios_start;
- u32 pseudo_palette[17];
+ u32 pseudo_palette[16];
struct { u8 red, green, blue, pad; }
palette[256];
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index dbf4ec3f6d57..03e57ef88378 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1589,11 +1589,10 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
return -EFAULT;
}
- fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+ fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
if (!fbi->pseudo_palette) {
return -ENOMEM;
}
- memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
print_err("Fail to allocate colormap (%d entries)",
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index fbef663fc057..2580f5fa2486 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -8,26 +8,32 @@ menuconfig BACKLIGHT_LCD_SUPPORT
Enable this to be able to choose the drivers for controlling the
backlight and the LCD panel on some platforms, for example on PDAs.
-config BACKLIGHT_CLASS_DEVICE
- tristate "Lowlevel Backlight controls"
+#
+# LCD
+#
+config LCD_CLASS_DEVICE
+ tristate "Lowlevel LCD controls"
depends on BACKLIGHT_LCD_SUPPORT
default m
help
- This framework adds support for low-level control of the LCD
- backlight. This includes support for brightness and power.
+ This framework adds support for low-level control of LCD.
+ Some framebuffer devices connect to platform-specific LCD modules
+ in order to have a platform-specific way to control the flat panel
+ (contrast and applying power to the LCD (not to the backlight!)).
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
-config LCD_CLASS_DEVICE
- tristate "Lowlevel LCD controls"
+#
+# Backlight
+#
+config BACKLIGHT_CLASS_DEVICE
+ tristate "Lowlevel Backlight controls"
depends on BACKLIGHT_LCD_SUPPORT
default m
help
- This framework adds support for low-level control of LCD.
- Some framebuffer devices connect to platform-specific LCD modules
- in order to have a platform-specific way to control the flat panel
- (contrast and applying power to the LCD (not to the backlight!)).
+ This framework adds support for low-level control of the LCD
+ backlight. This includes support for brightness and power.
To have support for your specific LCD panel you will have to
select the proper drivers which depend on this option.
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index c65e81ff3578..b26de8cf3112 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -69,18 +69,20 @@ static inline void backlight_unregister_fb(struct backlight_device *bd)
}
#endif /* CONFIG_FB */
-static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_power(struct device *dev,
+ struct device_attribute *attr,char *buf)
{
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.power);
}
-static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_power(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
int power = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -101,18 +103,20 @@ static ssize_t backlight_store_power(struct class_device *cdev, const char *buf,
return rc;
}
-static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.brightness);
}
-static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_brightness(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
int brightness = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -138,18 +142,19 @@ static ssize_t backlight_store_brightness(struct class_device *cdev, const char
return rc;
}
-static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_max_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
return sprintf(buf, "%d\n", bd->props.max_brightness);
}
-static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
- char *buf)
+static ssize_t backlight_show_actual_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
- struct backlight_device *bd = to_backlight_device(cdev);
+ struct backlight_device *bd = to_backlight_device(dev);
mutex_lock(&bd->ops_lock);
if (bd->ops && bd->ops->get_brightness)
@@ -159,31 +164,22 @@ static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
return rc;
}
-static void backlight_class_release(struct class_device *dev)
+struct class *backlight_class;
+
+static void bl_device_release(struct device *dev)
{
struct backlight_device *bd = to_backlight_device(dev);
kfree(bd);
}
-static struct class backlight_class = {
- .name = "backlight",
- .release = backlight_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store) \
-{ \
- .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
- .show = _show, \
- .store = _store, \
-}
-
-static const struct class_device_attribute bl_class_device_attributes[] = {
- DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
- DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
+static struct device_attribute bl_device_attributes[] = {
+ __ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
+ __ATTR(brightness, 0644, backlight_show_brightness,
backlight_store_brightness),
- DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
+ __ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
NULL),
- DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+ __ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+ __ATTR_NULL,
};
/**
@@ -191,22 +187,20 @@ static const struct class_device_attribute bl_class_device_attributes[] = {
* backlight_device class.
* @name: the name of the new object(must be the same as the name of the
* respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- * methods may retrieve it by using class_get_devdata(&bd->class_dev).
+ * @devdata: an optional pointer to be stored for private driver use. The
+ * methods may retrieve it by using bl_get_data(bd).
* @ops: the backlight operations structure.
*
- * Creates and registers new backlight class_device. Returns either an
+ * Creates and registers new backlight device. Returns either an
* ERR_PTR() or a pointer to the newly allocated device.
*/
struct backlight_device *backlight_device_register(const char *name,
- struct device *dev,
- void *devdata,
- struct backlight_ops *ops)
+ struct device *parent, void *devdata, struct backlight_ops *ops)
{
- int i, rc;
struct backlight_device *new_bd;
+ int rc;
- pr_debug("backlight_device_alloc: name=%s\n", name);
+ pr_debug("backlight_device_register: name=%s\n", name);
new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
if (!new_bd)
@@ -214,13 +208,14 @@ struct backlight_device *backlight_device_register(const char *name,
mutex_init(&new_bd->update_lock);
mutex_init(&new_bd->ops_lock);
- new_bd->ops = ops;
- new_bd->class_dev.class = &backlight_class;
- new_bd->class_dev.dev = dev;
- strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
- class_set_devdata(&new_bd->class_dev, devdata);
- rc = class_device_register(&new_bd->class_dev);
+ new_bd->dev.class = backlight_class;
+ new_bd->dev.parent = parent;
+ new_bd->dev.release = bl_device_release;
+ strlcpy(new_bd->dev.bus_id, name, BUS_ID_SIZE);
+ dev_set_drvdata(&new_bd->dev, devdata);
+
+ rc = device_register(&new_bd->dev);
if (rc) {
kfree(new_bd);
return ERR_PTR(rc);
@@ -228,23 +223,11 @@ struct backlight_device *backlight_device_register(const char *name,
rc = backlight_register_fb(new_bd);
if (rc) {
- class_device_unregister(&new_bd->class_dev);
+ device_unregister(&new_bd->dev);
return ERR_PTR(rc);
}
-
- for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
- rc = class_device_create_file(&new_bd->class_dev,
- &bl_class_device_attributes[i]);
- if (rc) {
- while (--i >= 0)
- class_device_remove_file(&new_bd->class_dev,
- &bl_class_device_attributes[i]);
- class_device_unregister(&new_bd->class_dev);
- /* No need to kfree(new_bd) since release() method was called */
- return ERR_PTR(rc);
- }
- }
+ new_bd->ops = ops;
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
@@ -265,42 +248,40 @@ EXPORT_SYMBOL(backlight_device_register);
*/
void backlight_device_unregister(struct backlight_device *bd)
{
- int i;
-
if (!bd)
return;
- pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
-
#ifdef CONFIG_PMAC_BACKLIGHT
mutex_lock(&pmac_backlight_mutex);
if (pmac_backlight == bd)
pmac_backlight = NULL;
mutex_unlock(&pmac_backlight_mutex);
#endif
-
- for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
- class_device_remove_file(&bd->class_dev,
- &bl_class_device_attributes[i]);
-
mutex_lock(&bd->ops_lock);
bd->ops = NULL;
mutex_unlock(&bd->ops_lock);
backlight_unregister_fb(bd);
-
- class_device_unregister(&bd->class_dev);
+ device_unregister(&bd->dev);
}
EXPORT_SYMBOL(backlight_device_unregister);
static void __exit backlight_class_exit(void)
{
- class_unregister(&backlight_class);
+ class_destroy(backlight_class);
}
static int __init backlight_class_init(void)
{
- return class_register(&backlight_class);
+ backlight_class = class_create(THIS_MODULE, "backlight");
+ if (IS_ERR(backlight_class)) {
+ printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+ PTR_ERR(backlight_class));
+ return PTR_ERR(backlight_class);
+ }
+
+ backlight_class->dev_attrs = bl_device_attributes;
+ return 0;
}
/*
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index e9bbc3455c94..b7904da51b23 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -174,7 +174,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
struct cr_panel *crp;
u8 dev_en;
- crp = kzalloc(sizeof(crp), GFP_KERNEL);
+ crp = kzalloc(sizeof(*crp), GFP_KERNEL);
if (crp == NULL)
return -ENOMEM;
@@ -202,7 +202,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
}
crp->cr_lcd_device = lcd_device_register("cr-lcd",
- &pdev->dev,
+ &pdev->dev, NULL,
&cr_lcd_ops);
if (IS_ERR(crp->cr_lcd_device)) {
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 6ef8f0a7a137..6f652c65fae1 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -61,10 +61,11 @@ static inline void lcd_unregister_fb(struct lcd_device *ld)
}
#endif /* CONFIG_FB */
-static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
int rc;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->get_power)
@@ -76,11 +77,12 @@ static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
return rc;
}
-static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_power(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
int power = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -100,10 +102,11 @@ static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_
return rc;
}
-static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_contrast(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
int rc = -ENXIO;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
mutex_lock(&ld->ops_lock);
if (ld->ops && ld->ops->get_contrast)
@@ -113,11 +116,12 @@ static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
return rc;
}
-static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_contrast(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
int rc = -ENXIO;
char *endp;
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
int contrast = simple_strtoul(buf, &endp, 0);
size_t size = endp - buf;
@@ -137,53 +141,45 @@ static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, si
return rc;
}
-static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_max_contrast(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct lcd_device *ld = to_lcd_device(cdev);
+ struct lcd_device *ld = to_lcd_device(dev);
return sprintf(buf, "%d\n", ld->props.max_contrast);
}
-static void lcd_class_release(struct class_device *dev)
+struct class *lcd_class;
+
+static void lcd_device_release(struct device *dev)
{
struct lcd_device *ld = to_lcd_device(dev);
kfree(ld);
}
-static struct class lcd_class = {
- .name = "lcd",
- .release = lcd_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store) \
-{ \
- .attr = { .name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
- .show = _show, \
- .store = _store, \
-}
-
-static const struct class_device_attribute lcd_class_device_attributes[] = {
- DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
- DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
- DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+static struct device_attribute lcd_device_attributes[] = {
+ __ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
+ __ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
+ __ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+ __ATTR_NULL,
};
/**
* lcd_device_register - register a new object of lcd_device class.
* @name: the name of the new object(must be the same as the name of the
* respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- * methods may retrieve it by using class_get_devdata(ld->class_dev).
+ * @devdata: an optional pointer to be stored in the device. The
+ * methods may retrieve it by using lcd_get_data(ld).
* @ops: the lcd operations structure.
*
- * Creates and registers a new lcd class_device. Returns either an ERR_PTR()
+ * Creates and registers a new lcd device. Returns either an ERR_PTR()
* or a pointer to the newly allocated device.
*/
-struct lcd_device *lcd_device_register(const char *name, void *devdata,
- struct lcd_ops *ops)
+struct lcd_device *lcd_device_register(const char *name, struct device *parent,
+ void *devdata, struct lcd_ops *ops)
{
- int i, rc;
struct lcd_device *new_ld;
+ int rc;
pr_debug("lcd_device_register: name=%s\n", name);
@@ -193,12 +189,14 @@ struct lcd_device *lcd_device_register(const char *name, void *devdata,
mutex_init(&new_ld->ops_lock);
mutex_init(&new_ld->update_lock);
- new_ld->ops = ops;
- new_ld->class_dev.class = &lcd_class;
- strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
- class_set_devdata(&new_ld->class_dev, devdata);
- rc = class_device_register(&new_ld->class_dev);
+ new_ld->dev.class = lcd_class;
+ new_ld->dev.parent = parent;
+ new_ld->dev.release = lcd_device_release;
+ strlcpy(new_ld->dev.bus_id, name, BUS_ID_SIZE);
+ dev_set_drvdata(&new_ld->dev, devdata);
+
+ rc = device_register(&new_ld->dev);
if (rc) {
kfree(new_ld);
return ERR_PTR(rc);
@@ -206,22 +204,11 @@ struct lcd_device *lcd_device_register(const char *name, void *devdata,
rc = lcd_register_fb(new_ld);
if (rc) {
- class_device_unregister(&new_ld->class_dev);
+ device_unregister(&new_ld->dev);
return ERR_PTR(rc);
}
- for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
- rc = class_device_create_file(&new_ld->class_dev,
- &lcd_class_device_attributes[i]);
- if (rc) {
- while (--i >= 0)
- class_device_remove_file(&new_ld->class_dev,
- &lcd_class_device_attributes[i]);
- class_device_unregister(&new_ld->class_dev);
- /* No need to kfree(new_ld) since release() method was called */
- return ERR_PTR(rc);
- }
- }
+ new_ld->ops = ops;
return new_ld;
}
@@ -235,33 +222,34 @@ EXPORT_SYMBOL(lcd_device_register);
*/
void lcd_device_unregister(struct lcd_device *ld)
{
- int i;
-
if (!ld)
return;
- pr_debug("lcd_device_unregister: name=%s\n", ld->class_dev.class_id);
-
- for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++)
- class_device_remove_file(&ld->class_dev,
- &lcd_class_device_attributes[i]);
-
mutex_lock(&ld->ops_lock);
ld->ops = NULL;
mutex_unlock(&ld->ops_lock);
lcd_unregister_fb(ld);
- class_device_unregister(&ld->class_dev);
+
+ device_unregister(&ld->dev);
}
EXPORT_SYMBOL(lcd_device_unregister);
static void __exit lcd_class_exit(void)
{
- class_unregister(&lcd_class);
+ class_destroy(lcd_class);
}
static int __init lcd_class_init(void)
{
- return class_register(&lcd_class);
+ lcd_class = class_create(THIS_MODULE, "lcd");
+ if (IS_ERR(lcd_class)) {
+ printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+ PTR_ERR(lcd_class));
+ return PTR_ERR(lcd_class);
+ }
+
+ lcd_class->dev_attrs = lcd_device_attributes;
+ return 0;
}
/*
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 50b78af0fa24..dea6579941b7 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -366,11 +366,10 @@ int __init clps711xfb_init(void)
if (fb_get_options("clps711xfb", NULL))
return -ENODEV;
- cfb = kmalloc(sizeof(*cfb), GFP_KERNEL);
+ cfb = kzalloc(sizeof(*cfb), GFP_KERNEL);
if (!cfb)
goto out;
- memset(cfb, 0, sizeof(*cfb));
strcpy(cfb->fix.id, "clps711x");
cfb->fbops = &clps7111fb_ops;
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 63b85bf81a65..49643969f9f8 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -6,7 +6,7 @@ menu "Console display driver support"
config VGA_CONSOLE
bool "VGA text console" if EMBEDDED || !X86
- depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH
+ depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BFIN
default y
help
Saying Y here will allow you to use Linux in text mode through a
@@ -118,6 +118,22 @@ config FRAMEBUFFER_CONSOLE
help
Low-level framebuffer-based console driver.
+config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
+ bool "Map the console to the primary display device"
+ depends on FRAMEBUFFER_CONSOLE
+ default n
+ ---help---
+ If this option is selected, the framebuffer console will
+ automatically select the primary display device (if the architecture
+ supports this feature). Otherwise, the framebuffer console will
+ always select the first framebuffer driver that is loaded. The latter
+ is the default behavior.
+
+ You can always override the automatic selection of the primary device
+ by using the fbcon=map: boot option.
+
+ If unsure, select n.
+
config FRAMEBUFFER_CONSOLE_ROTATION
bool "Framebuffer Console Rotation"
depends on FRAMEBUFFER_CONSOLE
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 73813c60d03a..decfdc8eb9cc 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -75,6 +75,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/crc32.h> /* For counting font checksums */
+#include <asm/fb.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -125,6 +126,8 @@ static int first_fb_vc;
static int last_fb_vc = MAX_NR_CONSOLES - 1;
static int fbcon_is_default = 1;
static int fbcon_has_exited;
+static int primary_device = -1;
+static int map_override;
/* font data */
static char fontname[40];
@@ -152,6 +155,7 @@ static int fbcon_set_origin(struct vc_data *);
#define DEFAULT_CURSOR_BLINK_RATE (20)
static int vbl_cursor_cnt;
+static int fbcon_cursor_noblink;
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
@@ -188,16 +192,14 @@ static __inline__ void ypan_down(struct vc_data *vc, int count);
static void fbcon_bmove_rec(struct vc_data *vc, struct display *p, int sy, int sx,
int dy, int dx, int height, int width, u_int y_break);
static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
- struct vc_data *vc);
-static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
- int unit);
+ int unit);
static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
int line, int count, int dy);
static void fbcon_modechanged(struct fb_info *info);
static void fbcon_set_all_vcs(struct fb_info *info);
static void fbcon_start(void);
static void fbcon_exit(void);
-static struct class_device *fbcon_class_device;
+static struct device *fbcon_device;
#ifdef CONFIG_MAC
/*
@@ -441,7 +443,8 @@ static void fbcon_add_cursor_timer(struct fb_info *info)
struct fbcon_ops *ops = info->fbcon_par;
if ((!info->queue.func || info->queue.func == fb_flashcursor) &&
- !(ops->flags & FBCON_FLAGS_CURSOR_TIMER)) {
+ !(ops->flags & FBCON_FLAGS_CURSOR_TIMER) &&
+ !fbcon_cursor_noblink) {
if (!info->queue.func)
INIT_WORK(&info->queue, fb_flashcursor);
@@ -495,13 +498,17 @@ static int __init fb_console_setup(char *this_opt)
if (!strncmp(options, "map:", 4)) {
options += 4;
- if (*options)
+ if (*options) {
for (i = 0, j = 0; i < MAX_NR_CONSOLES; i++) {
if (!options[j])
j = 0;
con2fb_map_boot[i] =
(options[j++]-'0') % FB_MAX;
}
+
+ map_override = 1;
+ }
+
return 1;
}
@@ -736,7 +743,9 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
if (!err) {
info->fbcon_par = ops;
- set_blitting_type(vc, info);
+
+ if (vc)
+ set_blitting_type(vc, info);
}
if (err) {
@@ -798,11 +807,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
ops->flags |= FBCON_FLAGS_INIT;
ops->graphics = 0;
-
- if (vc)
- fbcon_set_disp(info, &info->var, vc);
- else
- fbcon_preset_disp(info, &info->var, unit);
+ fbcon_set_disp(info, &info->var, unit);
if (show_logo) {
struct vc_data *fg_vc = vc_cons[fg_console].d;
@@ -1107,6 +1112,9 @@ static void fbcon_init(struct vc_data *vc, int init)
if (var_to_display(p, &info->var, info))
return;
+ if (!info->fbcon_par)
+ con2fb_acquire_newinfo(vc, info, vc->vc_num, -1);
+
/* If we are not the first console on this
fb, copy the font from that console */
t = &fb_display[fg_console];
@@ -1349,6 +1357,11 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
return;
+ if (vc->vc_cursor_type & 0x10)
+ fbcon_del_cursor_timer(info);
+ else
+ fbcon_add_cursor_timer(info);
+
ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
if (mode & CM_SOFTBACK) {
mode &= ~CM_SOFTBACK;
@@ -1368,36 +1381,29 @@ static int scrollback_phys_max = 0;
static int scrollback_max = 0;
static int scrollback_current = 0;
-/*
- * If no vc is existent yet, just set struct display
- */
-static void fbcon_preset_disp(struct fb_info *info, struct fb_var_screeninfo *var,
- int unit)
-{
- struct display *p = &fb_display[unit];
- struct display *t = &fb_display[fg_console];
-
- if (var_to_display(p, var, info))
- return;
-
- p->fontdata = t->fontdata;
- p->userfont = t->userfont;
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
-}
-
static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
- struct vc_data *vc)
+ int unit)
{
- struct display *p = &fb_display[vc->vc_num], *t;
- struct vc_data **default_mode = vc->vc_display_fg;
- struct vc_data *svc = *default_mode;
+ struct display *p, *t;
+ struct vc_data **default_mode, *vc;
+ struct vc_data *svc;
struct fbcon_ops *ops = info->fbcon_par;
int rows, cols, charcnt = 256;
+ p = &fb_display[unit];
+
if (var_to_display(p, var, info))
return;
+
+ vc = vc_cons[unit].d;
+
+ if (!vc)
+ return;
+
+ default_mode = vc->vc_display_fg;
+ svc = *default_mode;
t = &fb_display[svc->vc_num];
+
if (!vc->vc_font.data) {
vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
vc->vc_font.width = (*default_mode)->vc_font.width;
@@ -1704,6 +1710,56 @@ static void fbcon_redraw_move(struct vc_data *vc, struct display *p,
}
}
+static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+ struct display *p, int line, int count, int ycount)
+{
+ int offset = ycount * vc->vc_cols;
+ unsigned short *d = (unsigned short *)
+ (vc->vc_origin + vc->vc_size_row * line);
+ unsigned short *s = d + offset;
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ while (count--) {
+ unsigned short *start = s;
+ unsigned short *le = advance_row(s, 1);
+ unsigned short c;
+ int x = 0;
+
+ do {
+ c = scr_readw(s);
+
+ if (c == scr_readw(d)) {
+ if (s > start) {
+ ops->bmove(vc, info, line + ycount, x,
+ line, x, 1, s-start);
+ x += s - start + 1;
+ start = s + 1;
+ } else {
+ x++;
+ start++;
+ }
+ }
+
+ scr_writew(c, d);
+ console_conditional_schedule();
+ s++;
+ d++;
+ } while (s < le);
+ if (s > start)
+ ops->bmove(vc, info, line + ycount, x, line, x, 1,
+ s-start);
+ console_conditional_schedule();
+ if (ycount > 0)
+ line++;
+ else {
+ line--;
+ /* NOTE: We subtract two lines from these pointers */
+ s -= vc->vc_size_row;
+ d -= vc->vc_size_row;
+ }
+ }
+}
+
static void fbcon_redraw(struct vc_data *vc, struct display *p,
int line, int count, int offset)
{
@@ -1789,7 +1845,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num];
- struct fbcon_ops *ops = info->fbcon_par;
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
if (fbcon_is_inactive(vc, info))
@@ -1813,10 +1868,15 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
goto redraw_up;
switch (p->scrollmode) {
case SCROLL_MOVE:
- ops->bmove(vc, info, t + count, 0, t, 0,
- b - t - count, vc->vc_cols);
- ops->clear(vc, info, b - count, 0, count,
- vc->vc_cols);
+ fbcon_redraw_blit(vc, info, p, t, b - t - count,
+ count);
+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+ scr_memsetw((unsigned short *) (vc->vc_origin +
+ vc->vc_size_row *
+ (b - count)),
+ vc->vc_video_erase_char,
+ vc->vc_size_row * count);
+ return 1;
break;
case SCROLL_WRAP_MOVE:
@@ -1899,9 +1959,15 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
goto redraw_down;
switch (p->scrollmode) {
case SCROLL_MOVE:
- ops->bmove(vc, info, t, 0, t + count, 0,
- b - t - count, vc->vc_cols);
- ops->clear(vc, info, t, 0, count, vc->vc_cols);
+ fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
+ -count);
+ fbcon_clear(vc, t, 0, count, vc->vc_cols);
+ scr_memsetw((unsigned short *) (vc->vc_origin +
+ vc->vc_size_row *
+ t),
+ vc->vc_video_erase_char,
+ vc->vc_size_row * count);
+ return 1;
break;
case SCROLL_WRAP_MOVE:
@@ -2937,9 +3003,48 @@ static int fbcon_mode_deleted(struct fb_info *info,
return found;
}
-static int fbcon_fb_unregistered(int idx)
+#ifdef CONFIG_VT_HW_CONSOLE_BINDING
+static int fbcon_unbind(void)
{
- int i;
+ int ret;
+
+ ret = unbind_con_driver(&fb_con, first_fb_vc, last_fb_vc,
+ fbcon_is_default);
+ return ret;
+}
+#else
+static inline int fbcon_unbind(void)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
+
+static int fbcon_fb_unbind(int idx)
+{
+ int i, new_idx = -1, ret = 0;
+
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ if (con2fb_map[i] != idx &&
+ con2fb_map[i] != -1) {
+ new_idx = i;
+ break;
+ }
+ }
+
+ if (new_idx != -1) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ if (con2fb_map[i] == idx)
+ set_con2fb_map(i, new_idx, 0);
+ }
+ } else
+ ret = fbcon_unbind();
+
+ return ret;
+}
+
+static int fbcon_fb_unregistered(struct fb_info *info)
+{
+ int i, idx = info->node;
for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] == idx)
@@ -2967,12 +3072,48 @@ static int fbcon_fb_unregistered(int idx)
if (!num_registered_fb)
unregister_con_driver(&fb_con);
+
+ if (primary_device == idx)
+ primary_device = -1;
+
return 0;
}
-static int fbcon_fb_registered(int idx)
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
+static void fbcon_select_primary(struct fb_info *info)
{
- int ret = 0, i;
+ if (!map_override && primary_device == -1 &&
+ fb_is_primary_device(info)) {
+ int i;
+
+ printk(KERN_INFO "fbcon: %s (fb%i) is primary device\n",
+ info->fix.id, info->node);
+ primary_device = info->node;
+
+ for (i = first_fb_vc; i <= last_fb_vc; i++)
+ con2fb_map_boot[i] = primary_device;
+
+ if (con_is_bound(&fb_con)) {
+ printk(KERN_INFO "fbcon: Remapping primary device, "
+ "fb%i, to tty %i-%i\n", info->node,
+ first_fb_vc + 1, last_fb_vc + 1);
+ info_idx = primary_device;
+ }
+ }
+
+}
+#else
+static inline void fbcon_select_primary(struct fb_info *info)
+{
+ return;
+}
+#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
+
+static int fbcon_fb_registered(struct fb_info *info)
+{
+ int ret = 0, i, idx = info->node;
+
+ fbcon_select_primary(info);
if (info_idx == -1) {
for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -2986,8 +3127,7 @@ static int fbcon_fb_registered(int idx)
ret = fbcon_takeover(1);
} else {
for (i = first_fb_vc; i <= last_fb_vc; i++) {
- if (con2fb_map_boot[i] == idx &&
- con2fb_map[i] == -1)
+ if (con2fb_map_boot[i] == idx)
set_con2fb_map(i, idx, 0);
}
}
@@ -3034,12 +3174,7 @@ static void fbcon_new_modelist(struct fb_info *info)
mode = fb_find_nearest_mode(fb_display[i].mode,
&info->modelist);
fb_videomode_to_var(&var, mode);
-
- if (vc)
- fbcon_set_disp(info, &var, vc);
- else
- fbcon_preset_disp(info, &var, i);
-
+ fbcon_set_disp(info, &var, vc->vc_num);
}
}
@@ -3114,11 +3249,14 @@ static int fbcon_event_notify(struct notifier_block *self,
mode = event->data;
ret = fbcon_mode_deleted(info, mode);
break;
+ case FB_EVENT_FB_UNBIND:
+ ret = fbcon_fb_unbind(info->node);
+ break;
case FB_EVENT_FB_REGISTERED:
- ret = fbcon_fb_registered(info->node);
+ ret = fbcon_fb_registered(info);
break;
case FB_EVENT_FB_UNREGISTERED:
- ret = fbcon_fb_unregistered(info->node);
+ ret = fbcon_fb_unregistered(info);
break;
case FB_EVENT_SET_CONSOLE_MAP:
con2fb = event->data;
@@ -3179,8 +3317,9 @@ static struct notifier_block fbcon_event_notifier = {
.notifier_call = fbcon_event_notify,
};
-static ssize_t store_rotate(struct class_device *class_device,
- const char *buf, size_t count)
+static ssize_t store_rotate(struct device *device,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct fb_info *info;
int rotate, idx;
@@ -3203,8 +3342,9 @@ err:
return count;
}
-static ssize_t store_rotate_all(struct class_device *class_device,
- const char *buf, size_t count)
+static ssize_t store_rotate_all(struct device *device,
+ struct device_attribute *attr,const char *buf,
+ size_t count)
{
struct fb_info *info;
int rotate, idx;
@@ -3227,7 +3367,8 @@ err:
return count;
}
-static ssize_t show_rotate(struct class_device *class_device, char *buf)
+static ssize_t show_rotate(struct device *device,
+ struct device_attribute *attr,char *buf)
{
struct fb_info *info;
int rotate = 0, idx;
@@ -3248,20 +3389,86 @@ err:
return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
}
-static struct class_device_attribute class_device_attrs[] = {
+static ssize_t show_cursor_blink(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *info;
+ struct fbcon_ops *ops;
+ int idx, blink = -1;
+
+ if (fbcon_has_exited)
+ return 0;
+
+ acquire_console_sem();
+ idx = con2fb_map[fg_console];
+
+ if (idx == -1 || registered_fb[idx] == NULL)
+ goto err;
+
+ info = registered_fb[idx];
+ ops = info->fbcon_par;
+
+ if (!ops)
+ goto err;
+
+ blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0;
+err:
+ release_console_sem();
+ return snprintf(buf, PAGE_SIZE, "%d\n", blink);
+}
+
+static ssize_t store_cursor_blink(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *info;
+ int blink, idx;
+ char **last = NULL;
+
+ if (fbcon_has_exited)
+ return count;
+
+ acquire_console_sem();
+ idx = con2fb_map[fg_console];
+
+ if (idx == -1 || registered_fb[idx] == NULL)
+ goto err;
+
+ info = registered_fb[idx];
+
+ if (!info->fbcon_par)
+ goto err;
+
+ blink = simple_strtoul(buf, last, 0);
+
+ if (blink) {
+ fbcon_cursor_noblink = 0;
+ fbcon_add_cursor_timer(info);
+ } else {
+ fbcon_cursor_noblink = 1;
+ fbcon_del_cursor_timer(info);
+ }
+
+err:
+ release_console_sem();
+ return count;
+}
+
+static struct device_attribute device_attrs[] = {
__ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
__ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
+ __ATTR(cursor_blink, S_IRUGO|S_IWUSR, show_cursor_blink,
+ store_cursor_blink),
};
-static int fbcon_init_class_device(void)
+static int fbcon_init_device(void)
{
int i, error = 0;
fbcon_has_sysfs = 1;
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
- error = class_device_create_file(fbcon_class_device,
- &class_device_attrs[i]);
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++) {
+ error = device_create_file(fbcon_device, &device_attrs[i]);
if (error)
break;
@@ -3269,8 +3476,7 @@ static int fbcon_init_class_device(void)
if (error) {
while (--i >= 0)
- class_device_remove_file(fbcon_class_device,
- &class_device_attrs[i]);
+ device_remove_file(fbcon_device, &device_attrs[i]);
fbcon_has_sysfs = 0;
}
@@ -3356,16 +3562,15 @@ static int __init fb_console_init(void)
acquire_console_sem();
fb_register_client(&fbcon_event_notifier);
- fbcon_class_device =
- class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon");
+ fbcon_device = device_create(fb_class, NULL, MKDEV(0, 0), "fbcon");
- if (IS_ERR(fbcon_class_device)) {
- printk(KERN_WARNING "Unable to create class_device "
+ if (IS_ERR(fbcon_device)) {
+ printk(KERN_WARNING "Unable to create device "
"for fbcon; errno = %ld\n",
- PTR_ERR(fbcon_class_device));
- fbcon_class_device = NULL;
+ PTR_ERR(fbcon_device));
+ fbcon_device = NULL;
} else
- fbcon_init_class_device();
+ fbcon_init_device();
for (i = 0; i < MAX_NR_CONSOLES; i++)
con2fb_map[i] = -1;
@@ -3379,14 +3584,13 @@ module_init(fb_console_init);
#ifdef MODULE
-static void __exit fbcon_deinit_class_device(void)
+static void __exit fbcon_deinit_device(void)
{
int i;
if (fbcon_has_sysfs) {
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_remove_file(fbcon_class_device,
- &class_device_attrs[i]);
+ for (i = 0; i < ARRAY_SIZE(device_attrs); i++)
+ device_remove_file(fbcon_device, &device_attrs[i]);
fbcon_has_sysfs = 0;
}
@@ -3396,8 +3600,8 @@ static void __exit fb_console_exit(void)
{
acquire_console_sem();
fb_unregister_client(&fbcon_event_notifier);
- fbcon_deinit_class_device();
- class_device_destroy(fb_class, MKDEV(0, 0));
+ fbcon_deinit_device();
+ device_destroy(fb_class, MKDEV(0, 0));
fbcon_exit();
release_console_sem();
unregister_con_driver(&fb_con);
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index f46fe95f69fb..d18b73aafa0d 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -187,7 +187,11 @@ static void vgacon_scrollback_init(int pitch)
}
}
-static void vgacon_scrollback_startup(void)
+/*
+ * Called only duing init so call of alloc_bootmen is ok.
+ * Marked __init_refok to silence modpost.
+ */
+static void __init_refok vgacon_scrollback_startup(void)
{
vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
* 1024);
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 8b762739b1e0..b0be7eac32d8 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -94,7 +94,7 @@ static inline int VAR_MATCH(struct fb_var_screeninfo *x, struct fb_var_screeninf
struct fb_info_control {
struct fb_info info;
struct fb_par_control par;
- u32 pseudo_palette[17];
+ u32 pseudo_palette[16];
struct cmap_regs __iomem *cmap_regs;
unsigned long cmap_regs_phys;
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 7a6eeda5ae9a..30ede6e8830f 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -1221,11 +1221,10 @@ cyberpro_alloc_fb_info(unsigned int id, char *name)
{
struct cfb_info *cfb;
- cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL);
+ cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL);
if (!cfb)
return NULL;
- memset(cfb, 0, sizeof(struct cfb_info));
cfb->id = id;
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
index 94a66c2d2cf5..e23324d10be2 100644
--- a/drivers/video/cyblafb.c
+++ b/drivers/video/cyblafb.c
@@ -1068,15 +1068,18 @@ static int cyblafb_setcolreg(unsigned regno, unsigned red, unsigned green,
out8(0x3C9, green >> 10);
out8(0x3C9, blue >> 10);
- } else if (bpp == 16) // RGB 565
- ((u32 *) info->pseudo_palette)[regno] =
- (red & 0xF800) |
- ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
- else if (bpp == 32) // ARGB 8888
- ((u32 *) info->pseudo_palette)[regno] =
- ((transp & 0xFF00) << 16) |
- ((red & 0xFF00) << 8) |
- ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
+ } else if (regno < 16) {
+ if (bpp == 16) // RGB 565
+ ((u32 *) info->pseudo_palette)[regno] =
+ (red & 0xF800) |
+ ((green & 0xFC00) >> 5) |
+ ((blue & 0xF800) >> 11);
+ else if (bpp == 32) // ARGB 8888
+ ((u32 *) info->pseudo_palette)[regno] =
+ ((transp & 0xFF00) << 16) |
+ ((red & 0xFF00) << 8) |
+ ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
+ }
return 0;
}
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index ca2c54ce508e..33be46ccb54f 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -63,23 +63,12 @@
struct epson1355_par {
unsigned long reg_addr;
+ u32 pseudo_palette[16];
};
/* ------------------------------------------------------------------------- */
-#ifdef CONFIG_SUPERH
-
-static inline u8 epson1355_read_reg(int index)
-{
- return ctrl_inb(par.reg_addr + index);
-}
-
-static inline void epson1355_write_reg(u8 data, int index)
-{
- ctrl_outb(data, par.reg_addr + index);
-}
-
-#elif defined(CONFIG_ARM)
+#if defined(CONFIG_ARM)
# ifdef CONFIG_ARCH_CEIVA
# include <asm/arch/hardware.h>
@@ -289,7 +278,7 @@ static int epson1355fb_blank(int blank_mode, struct fb_info *info)
struct epson1355_par *par = info->par;
switch (blank_mode) {
- case FB_BLANK_UNBLANKING:
+ case FB_BLANK_UNBLANK:
case FB_BLANK_NORMAL:
lcd_enable(par, 1);
backlight_enable(1);
@@ -635,7 +624,7 @@ int __init epson1355fb_probe(struct platform_device *dev)
goto bail;
}
- info = framebuffer_alloc(sizeof(struct epson1355_par) + sizeof(u32) * 256, &dev->dev);
+ info = framebuffer_alloc(sizeof(struct epson1355_par), &dev->dev);
if (!info) {
rc = -ENOMEM;
goto bail;
@@ -648,7 +637,7 @@ int __init epson1355fb_probe(struct platform_device *dev)
rc = -ENOMEM;
goto bail;
}
- info->pseudo_palette = (void *)(default_par + 1);
+ info->pseudo_palette = default_par->pseudo_palette;
info->screen_base = ioremap(EPSON1355FB_FB_PHYS, EPSON1355FB_FB_LEN);
if (!info->screen_base) {
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 38c2e2558f5e..215ac579f901 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -33,17 +33,10 @@
#include <linux/err.h>
#include <linux/device.h>
#include <linux/efi.h>
+#include <linux/fb.h>
-#if defined(__mc68000__) || defined(CONFIG_APUS)
-#include <asm/setup.h>
-#endif
+#include <asm/fb.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#include <linux/fb.h>
/*
* Frame buffer device initialization and setup routines
@@ -411,10 +404,146 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
}
}
+static int fb_show_logo_line(struct fb_info *info, int rotate,
+ const struct linux_logo *logo, int y,
+ unsigned int n)
+{
+ u32 *palette = NULL, *saved_pseudo_palette = NULL;
+ unsigned char *logo_new = NULL, *logo_rotate = NULL;
+ struct fb_image image;
+
+ /* Return if the frame buffer is not mapped or suspended */
+ if (logo == NULL || info->state != FBINFO_STATE_RUNNING ||
+ info->flags & FBINFO_MODULE)
+ return 0;
+
+ image.depth = 8;
+ image.data = logo->data;
+
+ if (fb_logo.needs_cmapreset)
+ fb_set_logocmap(info, logo);
+
+ if (fb_logo.needs_truepalette ||
+ fb_logo.needs_directpalette) {
+ palette = kmalloc(256 * 4, GFP_KERNEL);
+ if (palette == NULL)
+ return 0;
+
+ if (fb_logo.needs_truepalette)
+ fb_set_logo_truepalette(info, logo, palette);
+ else
+ fb_set_logo_directpalette(info, logo, palette);
+
+ saved_pseudo_palette = info->pseudo_palette;
+ info->pseudo_palette = palette;
+ }
+
+ if (fb_logo.depth <= 4) {
+ logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL);
+ if (logo_new == NULL) {
+ kfree(palette);
+ if (saved_pseudo_palette)
+ info->pseudo_palette = saved_pseudo_palette;
+ return 0;
+ }
+ image.data = logo_new;
+ fb_set_logo(info, logo, logo_new, fb_logo.depth);
+ }
+
+ image.dx = 0;
+ image.dy = y;
+ image.width = logo->width;
+ image.height = logo->height;
+
+ if (rotate) {
+ logo_rotate = kmalloc(logo->width *
+ logo->height, GFP_KERNEL);
+ if (logo_rotate)
+ fb_rotate_logo(info, logo_rotate, &image, rotate);
+ }
+
+ fb_do_show_logo(info, &image, rotate, n);
+
+ kfree(palette);
+ if (saved_pseudo_palette != NULL)
+ info->pseudo_palette = saved_pseudo_palette;
+ kfree(logo_new);
+ kfree(logo_rotate);
+ return logo->height;
+}
+
+
+#ifdef CONFIG_FB_LOGO_EXTRA
+
+#define FB_LOGO_EX_NUM_MAX 10
+static struct logo_data_extra {
+ const struct linux_logo *logo;
+ unsigned int n;
+} fb_logo_ex[FB_LOGO_EX_NUM_MAX];
+static unsigned int fb_logo_ex_num;
+
+void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n)
+{
+ if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX)
+ return;
+
+ fb_logo_ex[fb_logo_ex_num].logo = logo;
+ fb_logo_ex[fb_logo_ex_num].n = n;
+ fb_logo_ex_num++;
+}
+
+static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height,
+ unsigned int yres)
+{
+ unsigned int i;
+
+ /* FIXME: logo_ex supports only truecolor fb. */
+ if (info->fix.visual != FB_VISUAL_TRUECOLOR)
+ fb_logo_ex_num = 0;
+
+ for (i = 0; i < fb_logo_ex_num; i++) {
+ height += fb_logo_ex[i].logo->height;
+ if (height > yres) {
+ height -= fb_logo_ex[i].logo->height;
+ fb_logo_ex_num = i;
+ break;
+ }
+ }
+ return height;
+}
+
+static int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
+{
+ unsigned int i;
+
+ for (i = 0; i < fb_logo_ex_num; i++)
+ y += fb_show_logo_line(info, rotate,
+ fb_logo_ex[i].logo, y, fb_logo_ex[i].n);
+
+ return y;
+}
+
+#else /* !CONFIG_FB_LOGO_EXTRA */
+
+static inline int fb_prepare_extra_logos(struct fb_info *info,
+ unsigned int height,
+ unsigned int yres)
+{
+ return height;
+}
+
+static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate)
+{
+ return y;
+}
+
+#endif /* CONFIG_FB_LOGO_EXTRA */
+
+
int fb_prepare_logo(struct fb_info *info, int rotate)
{
int depth = fb_get_color_depth(&info->var, &info->fix);
- int yres;
+ unsigned int yres;
memset(&fb_logo, 0, sizeof(struct logo_data));
@@ -456,7 +585,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
if (!fb_logo.logo) {
return 0;
}
-
+
if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
yres = info->var.yres;
else
@@ -473,75 +602,20 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
else if (fb_logo.logo->type == LINUX_LOGO_VGA16)
fb_logo.depth = 4;
else
- fb_logo.depth = 1;
- return fb_logo.logo->height;
+ fb_logo.depth = 1;
+
+ return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
}
int fb_show_logo(struct fb_info *info, int rotate)
{
- u32 *palette = NULL, *saved_pseudo_palette = NULL;
- unsigned char *logo_new = NULL, *logo_rotate = NULL;
- struct fb_image image;
-
- /* Return if the frame buffer is not mapped or suspended */
- if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING ||
- info->flags & FBINFO_MODULE)
- return 0;
-
- image.depth = 8;
- image.data = fb_logo.logo->data;
-
- if (fb_logo.needs_cmapreset)
- fb_set_logocmap(info, fb_logo.logo);
-
- if (fb_logo.needs_truepalette ||
- fb_logo.needs_directpalette) {
- palette = kmalloc(256 * 4, GFP_KERNEL);
- if (palette == NULL)
- return 0;
-
- if (fb_logo.needs_truepalette)
- fb_set_logo_truepalette(info, fb_logo.logo, palette);
- else
- fb_set_logo_directpalette(info, fb_logo.logo, palette);
-
- saved_pseudo_palette = info->pseudo_palette;
- info->pseudo_palette = palette;
- }
-
- if (fb_logo.depth <= 4) {
- logo_new = kmalloc(fb_logo.logo->width * fb_logo.logo->height,
- GFP_KERNEL);
- if (logo_new == NULL) {
- kfree(palette);
- if (saved_pseudo_palette)
- info->pseudo_palette = saved_pseudo_palette;
- return 0;
- }
- image.data = logo_new;
- fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
- }
+ int y;
- image.dx = 0;
- image.dy = 0;
- image.width = fb_logo.logo->width;
- image.height = fb_logo.logo->height;
+ y = fb_show_logo_line(info, rotate, fb_logo.logo, 0,
+ num_online_cpus());
+ y = fb_show_extra_logos(info, y, rotate);
- if (rotate) {
- logo_rotate = kmalloc(fb_logo.logo->width *
- fb_logo.logo->height, GFP_KERNEL);
- if (logo_rotate)
- fb_rotate_logo(info, logo_rotate, &image, rotate);
- }
-
- fb_do_show_logo(info, &image, rotate, num_online_cpus());
-
- kfree(palette);
- if (saved_pseudo_palette != NULL)
- info->pseudo_palette = saved_pseudo_palette;
- kfree(logo_new);
- kfree(logo_rotate);
- return fb_logo.logo->height;
+ return y;
}
#else
int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
@@ -1155,17 +1229,15 @@ fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
#endif
-static int
+static int
fb_mmap(struct file *file, struct vm_area_struct * vma)
{
int fbidx = iminor(file->f_path.dentry->d_inode);
struct fb_info *info = registered_fb[fbidx];
struct fb_ops *fb = info->fbops;
unsigned long off;
-#if !defined(__sparc__) || defined(__sparc_v9__)
unsigned long start;
u32 len;
-#endif
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
return -EINVAL;
@@ -1180,12 +1252,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
return res;
}
-#if defined(__sparc__) && !defined(__sparc_v9__)
- /* Should never get here, all fb drivers should have their own
- mmap routines */
- return -EINVAL;
-#else
- /* !sparc32... */
lock_kernel();
/* frame buffer memory */
@@ -1209,50 +1275,11 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
-#if defined(__mc68000__)
-#if defined(CONFIG_SUN3)
- pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
-#elif defined(CONFIG_MMU)
- if (CPU_IS_020_OR_030)
- pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
- if (CPU_IS_040_OR_060) {
- pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
- /* Use no-cache mode, serialized */
- pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
- }
-#endif
-#elif defined(__powerpc__)
- vma->vm_page_prot = phys_mem_access_prot(file, off >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
-#elif defined(__alpha__)
- /* Caching is off in the I/O space quadrant by design. */
-#elif defined(__i386__) || defined(__x86_64__)
- if (boot_cpu_data.x86 > 3)
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
-#elif defined(__mips__) || defined(__sparc_v9__)
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#elif defined(__hppa__)
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
-#elif defined(__arm__) || defined(__sh__) || defined(__m32r__)
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-#elif defined(__avr32__)
- vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
- & ~_PAGE_CACHABLE)
- | (_PAGE_BUFFER | _PAGE_DIRTY));
-#elif defined(__ia64__)
- if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#else
-#warning What do we have to do here??
-#endif
+ fb_pgprotect(file, vma, off);
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
-#endif /* !sparc32 */
}
static int
@@ -1388,17 +1415,34 @@ register_framebuffer(struct fb_info *fb_info)
*
* Returns negative errno on error, or zero for success.
*
+ * This function will also notify the framebuffer console
+ * to release the driver.
+ *
+ * This is meant to be called within a driver's module_exit()
+ * function. If this is called outside module_exit(), ensure
+ * that the driver implements fb_open() and fb_release() to
+ * check that no processes are using the device.
*/
int
unregister_framebuffer(struct fb_info *fb_info)
{
struct fb_event event;
- int i;
+ int i, ret = 0;
i = fb_info->node;
- if (!registered_fb[i])
- return -EINVAL;
+ if (!registered_fb[i]) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ event.info = fb_info;
+ ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
+
+ if (ret) {
+ ret = -EINVAL;
+ goto done;
+ }
if (fb_info->pixmap.addr &&
(fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
@@ -1410,7 +1454,8 @@ unregister_framebuffer(struct fb_info *fb_info)
device_destroy(fb_class, MKDEV(FB_MAJOR, i));
event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
- return 0;
+done:
+ return ret;
}
/**
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
index 70ff55b14596..6c91c61cdb63 100644
--- a/drivers/video/fm2fb.c
+++ b/drivers/video/fm2fb.c
@@ -195,13 +195,15 @@ static int fm2fb_blank(int blank, struct fb_info *info)
static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
- if (regno > info->cmap.len)
- return 1;
- red >>= 8;
- green >>= 8;
- blue >>= 8;
+ if (regno < 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+
+ ((u32*)(info->pseudo_palette))[regno] = (red << 16) |
+ (green << 8) | blue;
+ }
- ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue;
return 0;
}
@@ -237,7 +239,7 @@ static int __devinit fm2fb_probe(struct zorro_dev *z,
if (!zorro_request_device(z,"fm2fb"))
return -ENXIO;
- info = framebuffer_alloc(256 * sizeof(u32), &z->dev);
+ info = framebuffer_alloc(16 * sizeof(u32), &z->dev);
if (!info) {
zorro_release_device(z);
return -ENOMEM;
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index bf0e60b5a3b6..b9b572b293d4 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -86,7 +86,7 @@ static int gbe_revision;
static int ypan, ywrap;
-static uint32_t pseudo_palette[256];
+static uint32_t pseudo_palette[16];
static char *mode_option __initdata = NULL;
@@ -854,8 +854,7 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
green >>= 8;
blue >>= 8;
- switch (info->var.bits_per_pixel) {
- case 8:
+ if (info->var.bits_per_pixel <= 8) {
/* wait for the color map FIFO to have a free entry */
for (i = 0; i < 1000 && gbe->cm_fifo >= 63; i++)
udelay(10);
@@ -864,23 +863,25 @@ static int gbefb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 1;
}
gbe->cmap[regno] = (red << 24) | (green << 16) | (blue << 8);
- break;
- case 15:
- case 16:
- red >>= 3;
- green >>= 3;
- blue >>= 3;
- pseudo_palette[regno] =
- (red << info->var.red.offset) |
- (green << info->var.green.offset) |
- (blue << info->var.blue.offset);
- break;
- case 32:
- pseudo_palette[regno] =
- (red << info->var.red.offset) |
- (green << info->var.green.offset) |
- (blue << info->var.blue.offset);
- break;
+ } else if (regno < 16) {
+ switch (info->var.bits_per_pixel) {
+ case 15:
+ case 16:
+ red >>= 3;
+ green >>= 3;
+ blue >>= 3;
+ pseudo_palette[regno] =
+ (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ break;
+ case 32:
+ pseudo_palette[regno] =
+ (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ break;
+ }
}
return 0;
diff --git a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h
index 889e4ea5edc1..328ae6c673ec 100644
--- a/drivers/video/i810/i810.h
+++ b/drivers/video/i810/i810.h
@@ -266,7 +266,7 @@ struct i810fb_par {
struct i810fb_i2c_chan chan[3];
struct mutex open_lock;
unsigned int use_count;
- u32 pseudo_palette[17];
+ u32 pseudo_palette[16];
unsigned long mmio_start_phys;
u8 __iomem *mmio_start_virtual;
u8 *edid;
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index eb1a4812ad1d..b87ea21d3d78 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -379,10 +379,6 @@ int __init igafb_init(void)
if (fb_get_options("igafb", NULL))
return -ENODEV;
- /* Do not attach when we have a serial console. */
- if (!con_is_present())
- return -ENXIO;
-
pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
PCI_DEVICE_ID_INTERG_1682, 0);
if (pdev == NULL) {
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 80b94c19a9fa..6148300fadd6 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -302,7 +302,7 @@ struct intelfb_info {
u32 ring_lockup;
/* palette */
- u32 pseudo_palette[17];
+ u32 pseudo_palette[16];
/* chip info */
int pci_chipset;
diff --git a/drivers/video/kyro/STG4000InitDevice.c b/drivers/video/kyro/STG4000InitDevice.c
index ab5285a7f1d6..1d3f2080aa6f 100644
--- a/drivers/video/kyro/STG4000InitDevice.c
+++ b/drivers/video/kyro/STG4000InitDevice.c
@@ -247,7 +247,6 @@ int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev)
u32 ulCoreClock;
u32 tmp;
u32 ulChipSpeed;
- u8 rev;
STG_WRITE_REG(IntMask, 0xFFFF);
@@ -276,9 +275,9 @@ int SetCoreClockPLL(volatile STG4000REG __iomem *pSTGReg, struct pci_dev *pDev)
PMX2_SOFTRESET_ROM_RST);
pci_read_config_word(pDev, PCI_CONFIG_SUBSYS_ID, &sub);
- pci_read_config_byte(pDev, PCI_REVISION_ID, &rev);
- ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub, (u32)rev);
+ ulChipSpeed = InitSDRAMRegisters(pSTGReg, (u32)sub,
+ (u32)pDev->revision);
if (ulChipSpeed == 0)
return -EINVAL;
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 9397bcef3018..9de1c114f809 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -10,6 +10,11 @@ menuconfig LOGO
if LOGO
+config FB_LOGO_EXTRA
+ bool
+ depends on FB=y
+ default y if SPU_BASE
+
config LOGO_LINUX_MONO
bool "Standard black and white Linux logo"
default y
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index b985dfad6c63..a5fc4edf84e6 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -14,6 +14,8 @@ obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o
obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o
obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o
+obj-$(CONFIG_SPU_BASE) += logo_spe_clut224.o
+
# How to generate logo's
# Use logo-cfiles to retrieve list of .c files to be built
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 80c03618eb53..2b0f799aa8da 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -34,8 +34,11 @@ extern const struct linux_logo logo_superh_vga16;
extern const struct linux_logo logo_superh_clut224;
extern const struct linux_logo logo_m32r_clut224;
-
-const struct linux_logo *fb_find_logo(int depth)
+/* logo's are marked __initdata. Use __init_refok to tell
+ * modpost that it is intended that this function uses data
+ * marked __initdata.
+ */
+const struct linux_logo * __init_refok fb_find_logo(int depth)
{
const struct linux_logo *logo = NULL;
diff --git a/drivers/video/logo/logo_spe_clut224.ppm b/drivers/video/logo/logo_spe_clut224.ppm
new file mode 100644
index 000000000000..d36ad624a79c
--- /dev/null
+++ b/drivers/video/logo/logo_spe_clut224.ppm
@@ -0,0 +1,283 @@
+P3
+40 40
+255
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 6 6 6
+15 15 15 21 21 21 19 19 19 14 14 14 6 6 6 2 2 2
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 2 2 2 21 21 21 55 55 55
+56 56 56 54 54 54 53 53 53 60 60 60 56 56 56 25 25 25
+6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 2 2 2 27 27 27 62 62 62 17 17 19
+2 2 6 2 2 6 2 2 6 2 2 6 16 16 18 57 57 57
+45 45 45 8 8 8 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 16 16 16 62 62 62 8 8 10 2 2 6
+2 2 6 2 2 6 2 2 6 12 12 14 67 67 67 16 16 17
+45 45 45 41 41 41 4 4 4 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 2 2 2 35 35 35 40 40 40 2 2 6 2 2 6
+2 2 6 2 2 6 2 2 6 15 15 17 70 70 70 27 27 27
+3 3 6 62 62 62 20 20 20 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 4 4 4 58 58 58 12 12 14 2 2 6 2 2 6
+2 2 6 2 2 6 2 2 6 4 4 7 4 4 7 2 2 6
+2 2 6 34 34 36 40 40 40 3 3 3 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 7 7 7 64 64 64 2 2 6 5 5 5 17 17 17
+3 3 6 2 2 6 2 2 6 15 15 15 21 21 21 7 7 10
+2 2 6 8 8 10 62 62 62 6 6 6 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 7 7 7 66 66 66 5 5 8 122 122 122 122 122 122
+9 9 11 3 3 6 104 96 81 179 179 179 122 122 122 13 13 13
+2 2 6 2 2 6 67 67 67 10 10 10 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 7 7 7 65 65 65 41 41 43 152 149 142 192 191 189
+48 48 49 23 23 24 228 210 210 86 86 86 192 191 189 59 59 61
+2 2 6 2 2 6 64 64 64 14 14 14 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 7 7 7 66 66 66 59 59 59 59 59 61 86 86 86
+99 84 50 78 66 28 152 149 142 5 5 8 122 122 122 104 96 81
+2 2 6 2 2 6 67 67 67 14 14 14 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 5 5 5 63 63 63 24 24 24 152 149 142 175 122 13
+238 184 12 220 170 13 226 181 52 112 86 32 194 165 151 46 46 47
+2 2 6 2 2 6 65 65 65 17 17 17 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 5 5 5 59 59 59 21 21 21 175 122 13 231 174 11
+240 192 13 237 183 61 240 192 13 240 192 13 234 179 16 81 64 9
+2 2 6 2 2 6 63 63 63 25 25 25 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 5 5 5 54 54 54 51 48 39 189 138 9 238 184 12
+240 192 13 240 192 13 240 192 13 215 161 11 207 152 19 81 64 9
+16 16 18 5 5 8 40 40 40 44 44 44 4 4 4 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 5 5 5 59 59 59 27 27 27 126 107 64 187 136 12
+220 170 13 201 147 20 189 138 9 198 154 46 199 182 125 70 70 70
+27 27 27 104 96 81 12 12 14 70 70 70 16 16 16 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 17 17 17 70 70 70 12 12 12 168 168 168 174 135 135
+175 122 13 175 122 13 178 151 83 192 191 189 233 233 233 179 179 179
+3 3 6 29 29 31 3 3 6 41 41 41 44 44 44 5 5 5
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+8 8 8 53 53 53 44 44 44 59 59 59 238 238 238 192 191 189
+192 191 189 192 191 189 221 205 205 240 240 240 253 253 253 253 253 253
+70 70 70 2 2 6 2 2 6 5 5 8 67 67 67 22 22 22
+2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 5 5
+38 38 38 56 56 56 7 7 9 221 205 205 253 253 253 233 233 233
+221 205 205 233 233 233 251 251 251 253 253 253 253 253 253 253 253 253
+192 191 189 2 2 6 2 2 6 2 2 6 25 25 25 64 64 64
+15 15 15 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 2 2 2 27 27 27
+66 66 66 7 7 9 86 86 86 252 252 252 253 253 253 253 253 253
+252 252 252 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
+244 244 244 19 19 21 2 2 6 2 2 6 2 2 6 38 38 38
+54 54 54 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 62 62 62
+10 10 12 3 3 6 122 122 122 235 235 235 251 251 251 248 248 248
+235 235 235 248 248 248 252 252 252 246 246 246 233 233 233 237 228 228
+223 207 207 70 70 70 2 2 6 2 2 6 2 2 6 2 2 6
+46 46 47 38 38 38 4 4 4 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 2 2 2 33 33 33 44 44 44
+4 4 7 9 9 11 168 168 168 240 240 240 252 252 252 252 252 252
+246 246 246 253 253 253 253 253 253 251 251 251 245 241 241 233 233 233
+221 205 205 192 191 189 29 29 31 27 27 27 9 9 12 2 2 6
+3 3 6 65 65 65 15 15 15 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 6 6 6 59 59 59 19 19 21
+24 24 24 86 86 86 249 249 249 253 253 253 253 253 253 253 253 253
+253 253 253 228 210 210 241 230 230 253 253 253 253 253 253 253 253 253
+251 251 251 228 210 210 152 149 142 5 5 8 27 27 27 4 4 7
+2 2 6 46 46 47 34 34 34 2 2 2 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 16 16 16 67 67 67 19 19 21
+12 12 14 223 207 207 254 20 20 254 20 20 253 127 127 242 223 223
+254 20 20 253 127 127 254 48 48 242 223 223 254 86 86 254 20 20
+254 20 20 253 137 137 233 233 233 32 32 32 35 35 35 23 23 24
+2 2 6 15 15 15 60 60 60 6 6 6 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 4 4 4 38 38 38 48 48 49 22 22 22
+86 86 86 253 253 253 254 20 20 241 230 230 227 216 186 253 137 137
+253 137 137 253 253 253 253 137 137 253 137 137 254 48 48 253 253 253
+253 253 253 253 253 253 253 253 253 62 62 62 2 2 6 23 23 24
+2 2 6 2 2 6 62 62 62 17 17 17 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 14 14 14 70 70 70 14 14 14 16 16 18
+179 179 179 253 253 253 227 216 186 254 48 48 240 219 160 253 127 127
+254 20 20 253 137 137 254 86 86 231 203 141 254 20 20 254 20 20
+253 137 137 253 253 253 253 253 253 104 96 81 2 2 6 23 23 24
+2 2 6 2 2 6 46 46 47 27 27 27 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 4 4 4 39 39 39 42 42 43 19 19 21 13 13 13
+228 210 210 242 223 223 253 253 253 242 223 223 253 127 127 253 127 127
+253 127 127 253 127 127 253 137 137 253 253 253 254 48 48 253 253 253
+228 210 210 253 253 253 253 253 253 122 122 122 2 2 6 19 19 19
+2 2 6 2 2 6 39 39 39 38 38 38 3 3 3 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 8 8 8 60 60 60 3 3 6 33 33 33 38 38 38
+253 137 137 254 86 86 253 137 137 254 86 86 253 137 137 209 197 168
+253 127 127 253 253 253 253 253 253 253 253 253 253 127 127 254 86 86
+254 86 86 253 137 137 253 253 253 122 122 122 2 2 6 17 17 17
+2 2 6 2 2 6 34 34 36 42 42 43 3 3 3 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 13 13 13 59 59 59 2 2 6 9 9 12 56 56 56
+252 252 252 240 219 160 253 137 137 240 219 160 253 253 253 237 228 228
+254 86 86 253 253 253 253 253 253 253 253 253 253 253 253 242 223 223
+227 216 186 249 249 249 253 253 253 122 122 122 16 16 17 17 17 17
+12 12 14 3 3 6 39 39 39 38 38 38 3 3 3 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 2
+5 5 5 22 22 22 104 96 81 187 136 12 207 152 19 51 48 39
+221 205 205 253 253 253 253 253 253 253 253 253 253 253 253 240 240 240
+250 247 243 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 247 243 240 219 160 99 84 50 5 5 8 2 2 6
+7 7 9 46 46 47 58 58 58 35 35 35 3 3 3 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 8 8 8 33 33 33
+58 58 58 86 86 86 170 136 53 239 182 13 246 190 14 220 170 13
+44 38 29 179 179 179 253 253 253 253 253 253 253 253 253 240 240 240
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 240 219 160 240 192 13 112 86 32 2 2 6 2 2 6
+3 3 6 41 33 20 220 170 13 53 53 53 4 4 4 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 2 2 2 32 32 32 150 116 44
+215 161 11 215 161 11 228 170 11 245 188 14 246 190 14 246 190 14
+187 136 12 9 9 11 122 122 122 251 251 251 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
+248 248 248 211 196 135 239 182 13 175 122 13 6 5 6 2 2 6
+16 14 12 187 136 12 238 184 12 84 78 65 10 10 10 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 4 4 4 53 53 53 207 152 19
+242 185 13 245 188 14 246 190 14 246 190 14 246 190 14 246 190 14
+240 192 13 81 64 9 2 2 6 86 86 86 244 244 244 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
+233 233 233 199 182 125 231 174 11 207 152 19 175 122 13 175 122 13
+201 147 20 239 182 13 244 187 14 150 116 44 35 35 35 6 6 6
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 5 5 5 53 53 53 201 147 20
+242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
+246 190 14 220 170 13 13 11 10 2 2 6 152 149 142 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
+235 235 235 199 182 125 228 170 11 234 177 12 226 168 11 226 168 11
+234 177 12 246 190 14 246 190 14 234 179 16 126 107 64 36 36 36
+6 6 6 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 3 3 3 48 48 49 189 142 35
+242 185 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
+246 190 14 246 190 14 140 112 39 36 36 36 192 191 189 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253
+192 191 189 112 86 32 226 168 11 244 187 14 244 187 14 244 187 14
+245 188 14 246 190 14 246 190 14 246 190 14 242 185 13 150 116 44
+27 27 27 2 2 2 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 6 6 6 58 58 58 189 142 35
+239 182 13 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
+246 190 14 246 190 14 239 188 14 209 197 168 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253 252 252 252 168 168 168
+16 16 18 97 67 8 228 170 11 245 188 14 246 190 14 246 190 14
+246 190 14 246 190 14 246 190 14 246 190 14 244 187 14 198 154 46
+35 35 35 3 3 3 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 13 13 13 84 78 65 215 161 11
+244 187 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14
+246 190 14 246 190 14 238 184 12 187 136 12 168 168 168 244 244 244
+253 253 253 252 252 252 240 240 240 179 179 179 67 67 67 2 2 6
+2 2 6 97 67 8 228 170 11 246 190 14 246 190 14 246 190 14
+246 190 14 246 190 14 245 188 14 234 177 12 189 142 35 86 77 61
+16 16 16 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 13 13 13 103 92 56 207 152 19
+228 170 11 234 177 12 239 182 13 242 186 14 245 188 14 246 190 14
+246 190 14 246 190 14 239 182 13 189 138 9 41 33 20 10 10 12
+30 30 31 23 23 24 5 5 8 2 2 6 2 2 6 2 2 6
+4 4 6 112 86 32 215 161 11 245 188 14 246 190 14 245 188 14
+239 182 13 228 170 11 189 142 35 104 96 81 48 48 49 17 17 17
+2 2 2 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 5 5 5 39 39 39 103 92 56
+141 109 44 175 122 13 187 136 12 189 138 9 207 152 19 228 170 11
+239 182 13 239 182 13 215 161 11 175 122 13 41 33 20 2 2 6
+15 15 17 20 20 22 20 20 22 20 20 22 20 20 22 8 8 10
+4 4 6 97 67 8 189 138 9 231 174 11 239 182 13 226 168 11
+189 138 9 126 107 64 59 59 59 21 21 21 5 5 5 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 5 5 5 17 17 17
+34 34 34 57 57 57 84 78 65 103 92 56 125 101 41 140 112 39
+175 122 13 175 122 13 175 122 13 97 67 8 72 67 58 84 78 65
+60 60 60 56 56 56 56 56 56 56 56 56 57 57 57 65 65 65
+86 86 86 95 73 34 175 122 13 187 136 12 187 136 12 175 122 13
+103 92 56 41 41 41 10 10 10 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+2 2 2 4 4 4 12 12 12 24 24 24 40 40 40 70 70 70
+86 77 61 95 73 34 88 72 41 72 67 58 36 36 36 10 10 10
+5 5 5 5 5 5 5 5 5 4 4 4 5 5 5 6 6 6
+22 22 22 61 61 59 88 72 41 112 86 32 112 86 32 84 78 65
+32 32 32 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 3 3 3 10 10 10
+21 21 21 33 33 33 31 31 31 16 16 16 2 2 2 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+2 2 2 12 12 12 30 30 31 40 40 40 32 32 32 16 16 16
+2 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index f7d647dda978..aa8c714d6245 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -170,7 +170,7 @@ static struct fb_fix_screeninfo macfb_fix = {
};
static struct fb_info fb_info;
-static u32 pseudo_palette[17];
+static u32 pseudo_palette[16];
static int inverse = 0;
static int vidtest = 0;
@@ -529,56 +529,63 @@ static int macfb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (regno >= fb_info->cmap.len)
return 1;
- switch (fb_info->var.bits_per_pixel) {
- case 1:
- /* We shouldn't get here */
- break;
- case 2:
- case 4:
- case 8:
- if (macfb_setpalette)
- macfb_setpalette(regno, red, green, blue, fb_info);
- else
- return 1;
- break;
- case 16:
- if (fb_info->var.red.offset == 10) {
- /* 1:5:5:5 */
- ((u32*) (fb_info->pseudo_palette))[regno] =
+ if (fb_info->var.bits_per_pixel <= 8) {
+ switch (fb_info->var.bits_per_pixel) {
+ case 1:
+ /* We shouldn't get here */
+ break;
+ case 2:
+ case 4:
+ case 8:
+ if (macfb_setpalette)
+ macfb_setpalette(regno, red, green, blue,
+ fb_info);
+ else
+ return 1;
+ break;
+ }
+ } else if (regno < 16) {
+ switch (fb_info->var.bits_per_pixel) {
+ case 16:
+ if (fb_info->var.red.offset == 10) {
+ /* 1:5:5:5 */
+ ((u32*) (fb_info->pseudo_palette))[regno] =
((red & 0xf800) >> 1) |
((green & 0xf800) >> 6) |
((blue & 0xf800) >> 11) |
((transp != 0) << 15);
- } else {
- /* 0:5:6:5 */
- ((u32*) (fb_info->pseudo_palette))[regno] =
+ } else {
+ /* 0:5:6:5 */
+ ((u32*) (fb_info->pseudo_palette))[regno] =
((red & 0xf800) ) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
+ }
+ break;
+ /* I'm pretty sure that one or the other of these
+ doesn't exist on 68k Macs */
+ case 24:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((u32 *)(fb_info->pseudo_palette))[regno] =
+ (red << fb_info->var.red.offset) |
+ (green << fb_info->var.green.offset) |
+ (blue << fb_info->var.blue.offset);
+ break;
+ case 32:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((u32 *)(fb_info->pseudo_palette))[regno] =
+ (red << fb_info->var.red.offset) |
+ (green << fb_info->var.green.offset) |
+ (blue << fb_info->var.blue.offset);
+ break;
}
- break;
- /* I'm pretty sure that one or the other of these
- doesn't exist on 68k Macs */
- case 24:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- ((u32 *)(fb_info->pseudo_palette))[regno] =
- (red << fb_info->var.red.offset) |
- (green << fb_info->var.green.offset) |
- (blue << fb_info->var.blue.offset);
- break;
- case 32:
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- ((u32 *)(fb_info->pseudo_palette))[regno] =
- (red << fb_info->var.red.offset) |
- (green << fb_info->var.green.offset) |
- (blue << fb_info->var.blue.offset);
- break;
- }
- return 0;
+ }
+
+ return 0;
}
static struct fb_ops macfb_ops = {
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index ab2149531a04..083f60321ed8 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -369,9 +369,8 @@ EXPORT_SYMBOL(mac_map_monitor_sense);
*
*/
-int __devinit mac_find_mode(struct fb_var_screeninfo *var,
- struct fb_info *info, const char *mode_option,
- unsigned int default_bpp)
+int mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
+ const char *mode_option, unsigned int default_bpp)
{
const struct fb_videomode *db = NULL;
unsigned int dbsize = 0;
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h
index babeb81f467d..b86ba08aac9e 100644
--- a/drivers/video/macmodes.h
+++ b/drivers/video/macmodes.h
@@ -55,10 +55,10 @@ extern int mac_vmode_to_var(int vmode, int cmode,
extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
int *cmode);
extern int mac_map_monitor_sense(int sense);
-extern int __devinit mac_find_mode(struct fb_var_screeninfo *var,
- struct fb_info *info,
- const char *mode_option,
- unsigned int default_bpp);
+extern int mac_find_mode(struct fb_var_screeninfo *var,
+ struct fb_info *info,
+ const char *mode_option,
+ unsigned int default_bpp);
/*
diff --git a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c
index c57aaadf410c..3660d2673bdc 100644
--- a/drivers/video/matrox/matroxfb_accel.c
+++ b/drivers/video/matrox/matroxfb_accel.c
@@ -91,7 +91,6 @@ static inline void matrox_cfb4_pal(u_int32_t* pal) {
for (i = 0; i < 16; i++) {
pal[i] = i * 0x11111111U;
}
- pal[i] = 0xFFFFFFFF;
}
static inline void matrox_cfb8_pal(u_int32_t* pal) {
@@ -100,7 +99,6 @@ static inline void matrox_cfb8_pal(u_int32_t* pal) {
for (i = 0; i < 16; i++) {
pal[i] = i * 0x01010101U;
}
- pal[i] = 0x0F0F0F0F;
}
static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area);
@@ -145,13 +143,10 @@ void matrox_cfbX_init(WPMINFO2) {
ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit;
}
break;
- case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) {
+ case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5)
maccess = 0xC0000001;
- ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF;
- } else {
+ else
maccess = 0x40000001;
- ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
- }
mopmode = M_OPMODE_16BPP;
if (accel) {
ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
@@ -161,7 +156,6 @@ void matrox_cfbX_init(WPMINFO2) {
break;
case 24: maccess = 0x00000003;
mopmode = M_OPMODE_24BPP;
- ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
if (accel) {
ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
@@ -170,7 +164,6 @@ void matrox_cfbX_init(WPMINFO2) {
break;
case 32: maccess = 0x00000002;
mopmode = M_OPMODE_32BPP;
- ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF;
if (accel) {
ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea;
ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect;
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index c8559a756b75..86ca7b179000 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -679,6 +679,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
mga_outb(M_DAC_VAL, blue);
break;
case 16:
+ if (regno >= 16)
+ break;
{
u_int16_t col =
(red << ACCESS_FBINFO(fbcon).var.red.offset) |
@@ -690,6 +692,8 @@ static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
break;
case 24:
case 32:
+ if (regno >= 16)
+ break;
ACCESS_FBINFO(cmap[regno]) =
(red << ACCESS_FBINFO(fbcon).var.red.offset) |
(green << ACCESS_FBINFO(fbcon).var.green.offset) |
@@ -1994,7 +1998,6 @@ static void matroxfb_unregister_device(struct matrox_fb_info* minfo) {
static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dummy) {
struct board* b;
- u_int8_t rev;
u_int16_t svid;
u_int16_t sid;
struct matrox_fb_info* minfo;
@@ -2005,11 +2008,10 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm
#endif
DBG(__FUNCTION__)
- pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
svid = pdev->subsystem_vendor;
sid = pdev->subsystem_device;
for (b = dev_list; b->vendor; b++) {
- if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < rev)) continue;
+ if ((b->vendor != pdev->vendor) || (b->device != pdev->device) || (b->rev < pdev->revision)) continue;
if (b->svid)
if ((b->svid != svid) || (b->sid != sid)) continue;
break;
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index 9c25c2f7966b..d59577c8de86 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -518,7 +518,7 @@ struct matrox_fb_info {
dll:1;
} memory;
} values;
- u_int32_t cmap[17];
+ u_int32_t cmap[16];
};
#define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon)
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
index 03ae55b168ff..4b3344e03695 100644
--- a/drivers/video/matrox/matroxfb_crtc2.c
+++ b/drivers/video/matrox/matroxfb_crtc2.c
@@ -163,11 +163,6 @@ static void matroxfb_dh_disable(struct matroxfb_dh_fb_info* m2info) {
ACCESS_FBINFO(hw).crtc2.ctl = 0x00000004;
}
-static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) {
- /* no acceleration for secondary head... */
- m2info->cmap[16] = 0xFFFFFFFF;
-}
-
static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info,
struct fb_var_screeninfo* var) {
unsigned int pos;
@@ -385,7 +380,6 @@ static int matroxfb_dh_set_par(struct fb_info* info) {
}
}
up_read(&ACCESS_FBINFO(altout).lock);
- matroxfb_dh_cfbX_init(m2info);
}
m2info->initialized = 1;
return 0;
diff --git a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h
index 608e40bb20e9..1005582e843e 100644
--- a/drivers/video/matrox/matroxfb_crtc2.h
+++ b/drivers/video/matrox/matroxfb_crtc2.h
@@ -2,8 +2,6 @@
#define __MATROXFB_CRTC2_H__
#include <linux/ioctl.h>
-#include <linux/i2c.h>
-#include <linux/i2c-algo-bit.h>
#include "matroxfb_base.h"
struct matroxfb_dh_fb_info {
@@ -30,7 +28,7 @@ struct matroxfb_dh_fb_info {
unsigned int interlaced:1;
- u_int32_t cmap[17];
+ u_int32_t cmap[16];
};
#endif /* __MATROXFB_CRTC2_H__ */
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c
index 5d29a26b8cdf..de0d755f9019 100644
--- a/drivers/video/matrox/matroxfb_maven.c
+++ b/drivers/video/matrox/matroxfb_maven.c
@@ -273,8 +273,11 @@ static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll,
}
}
}
+
+ /* if h2/post/in/feed have not been assigned, return zero (error) */
if (besth2 < 2)
return 0;
+
dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant);
return fxtal * (*feed) / (*in) * ctl->den;
}
@@ -284,7 +287,7 @@ static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl,
unsigned int* in, unsigned int* feed, unsigned int* post,
unsigned int* htotal2) {
unsigned int fvco;
- unsigned int p;
+ unsigned int uninitialized_var(p);
fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2);
if (!fvco)
@@ -715,7 +718,9 @@ static int maven_find_exact_clocks(unsigned int ht, unsigned int vt,
m->regs[0x82] = 0x81;
for (x = 0; x < 8; x++) {
- unsigned int a, b, c, h2;
+ unsigned int c;
+ unsigned int uninitialized_var(a), uninitialized_var(b),
+ uninitialized_var(h2);
unsigned int h = ht + 2 + x;
if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) {
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 43f62d8ee41d..443e3c85a9a0 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -50,7 +50,7 @@ static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
static int nvidia_bl_update_status(struct backlight_device *bd)
{
- struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+ struct nvidia_par *par = bl_get_data(bd);
u32 tmp_pcrt, tmp_pmc, fpcontrol;
int level;
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index aff11bbf59a7..d1a10549f543 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -150,8 +150,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
M = pll & 0xFF;
N = (pll >> 8) & 0xFF;
if (((par->Chipset & 0xfff0) == 0x0290) ||
- ((par->Chipset & 0xfff0) == 0x0390) ||
- ((par->Chipset & 0xfff0) == 0x02E0)) {
+ ((par->Chipset & 0xfff0) == 0x0390)) {
MB = 1;
NB = 1;
} else {
@@ -161,7 +160,7 @@ static void nvGetClocks(struct nvidia_par *par, unsigned int *MClk,
*MClk = ((N * NB * par->CrystalFreqKHz) / (M * MB)) >> P;
pll = NV_RD32(par->PMC, 0x4000);
- P = (pll >> 16) & 0x03;
+ P = (pll >> 16) & 0x07;
pll = NV_RD32(par->PMC, 0x4004);
M = pll & 0xFF;
N = (pll >> 8) & 0xFF;
@@ -892,11 +891,17 @@ void NVCalcStateExt(struct nvidia_par *par,
state->general = bpp == 16 ? 0x00101100 : 0x00100100;
state->repaint1 = hDisplaySize < 1280 ? 0x04 : 0x00;
break;
+ case NV_ARCH_40:
+ if (!par->FlatPanel)
+ state->control = NV_RD32(par->PRAMDAC0, 0x0580) &
+ 0xeffffeff;
+ /* fallthrough */
case NV_ARCH_10:
case NV_ARCH_20:
case NV_ARCH_30:
default:
- if ((par->Chipset & 0xfff0) == 0x0240) {
+ if ((par->Chipset & 0xfff0) == 0x0240 ||
+ (par->Chipset & 0xfff0) == 0x03d0) {
state->arbitration0 = 256;
state->arbitration1 = 0x0480;
} else if (((par->Chipset & 0xffff) == 0x01A0) ||
@@ -939,7 +944,7 @@ void NVCalcStateExt(struct nvidia_par *par,
void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
{
- int i;
+ int i, j;
NV_WR32(par->PMC, 0x0140, 0x00000000);
NV_WR32(par->PMC, 0x0200, 0xFFFF00FF);
@@ -951,7 +956,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
NV_WR32(par->PTIMER, 0x0100 * 4, 0xFFFFFFFF);
if (par->Architecture == NV_ARCH_04) {
- NV_WR32(par->PFB, 0x0200, state->config);
+ if (state)
+ NV_WR32(par->PFB, 0x0200, state->config);
} else if ((par->Architecture < NV_ARCH_40) ||
(par->Chipset & 0xfff0) == 0x0040) {
for (i = 0; i < 8; i++) {
@@ -964,8 +970,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
- ((par->Chipset & 0xfff0) == 0x02E0) ||
- ((par->Chipset & 0xfff0) == 0x0290))
+ ((par->Chipset & 0xfff0) == 0x0290) ||
+ ((par->Chipset & 0xfff0) == 0x0390) ||
+ ((par->Chipset & 0xfff0) == 0x03D0))
regions = 15;
for(i = 0; i < regions; i++) {
NV_WR32(par->PFB, 0x0600 + (i * 0x10), 0);
@@ -1206,16 +1213,20 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
NV_WR32(par->PGRAPH, 0x0608, 0xFFFFFFFF);
} else {
if (par->Architecture >= NV_ARCH_40) {
- u32 tmp;
-
NV_WR32(par->PGRAPH, 0x0084, 0x401287c0);
NV_WR32(par->PGRAPH, 0x008C, 0x60de8051);
NV_WR32(par->PGRAPH, 0x0090, 0x00008000);
NV_WR32(par->PGRAPH, 0x0610, 0x00be3c5f);
+ NV_WR32(par->PGRAPH, 0x0bc4,
+ NV_RD32(par->PGRAPH, 0x0bc4) |
+ 0x00008000);
- tmp = NV_RD32(par->REGS, 0x1540) & 0xff;
- for(i = 0; tmp && !(tmp & 1); tmp >>= 1, i++);
- NV_WR32(par->PGRAPH, 0x5000, i);
+ j = NV_RD32(par->REGS, 0x1540) & 0xff;
+
+ if (j) {
+ for (i = 0; !(j & 1); j >>= 1, i++);
+ NV_WR32(par->PGRAPH, 0x5000, i);
+ }
if ((par->Chipset & 0xfff0) == 0x0040) {
NV_WR32(par->PGRAPH, 0x09b0,
@@ -1250,6 +1261,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
case 0x0160:
case 0x01D0:
case 0x0240:
+ case 0x03D0:
NV_WR32(par->PMC, 0x1700,
NV_RD32(par->PFB, 0x020C));
NV_WR32(par->PMC, 0x1704, 0);
@@ -1269,7 +1281,6 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
0x00000108);
break;
case 0x0220:
- case 0x0230:
NV_WR32(par->PGRAPH, 0x0860, 0);
NV_WR32(par->PGRAPH, 0x0864, 0);
NV_WR32(par->PRAMDAC, 0x0608,
@@ -1277,8 +1288,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
0x00100000);
break;
case 0x0090:
- case 0x02E0:
case 0x0290:
+ case 0x0390:
NV_WR32(par->PRAMDAC, 0x0608,
NV_RD32(par->PRAMDAC, 0x0608) |
0x00100000);
@@ -1355,8 +1366,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if (((par->Chipset & 0xfff0) == 0x0090) ||
((par->Chipset & 0xfff0) == 0x01D0) ||
- ((par->Chipset & 0xfff0) == 0x02E0) ||
- ((par->Chipset & 0xfff0) == 0x0290)) {
+ ((par->Chipset & 0xfff0) == 0x0290) ||
+ ((par->Chipset & 0xfff0) == 0x0390) ||
+ ((par->Chipset & 0xfff0) == 0x03D0)) {
for (i = 0; i < 60; i++) {
NV_WR32(par->PGRAPH,
0x0D00 + i*4,
@@ -1407,8 +1419,8 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
} else {
if ((par->Chipset & 0xfff0) == 0x0090 ||
(par->Chipset & 0xfff0) == 0x01D0 ||
- (par->Chipset & 0xfff0) == 0x02E0 ||
- (par->Chipset & 0xfff0) == 0x0290) {
+ (par->Chipset & 0xfff0) == 0x0290 ||
+ (par->Chipset & 0xfff0) == 0x0390) {
NV_WR32(par->PGRAPH, 0x0DF0,
NV_RD32(par->PFB, 0x0200));
NV_WR32(par->PGRAPH, 0x0DF4,
@@ -1495,6 +1507,12 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
NV_WR32(par->PFIFO, 0x0494 * 4, 0x00000001);
NV_WR32(par->PFIFO, 0x0495 * 4, 0x00000001);
NV_WR32(par->PFIFO, 0x0140 * 4, 0x00000001);
+
+ if (!state) {
+ par->CurrentState = NULL;
+ return;
+ }
+
if (par->Architecture >= NV_ARCH_10) {
if (par->twoHeads) {
NV_WR32(par->PCRTC0, 0x0860, state->head);
@@ -1566,6 +1584,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
VGA_WR08(par->PCIO, 0x03D5, state->interlace);
if (!par->FlatPanel) {
+ if (par->Architecture >= NV_ARCH_40)
+ NV_WR32(par->PRAMDAC0, 0x0580, state->control);
+
NV_WR32(par->PRAMDAC0, 0x050C, state->pllsel);
NV_WR32(par->PRAMDAC0, 0x0508, state->vpll);
if (par->twoHeads)
@@ -1631,6 +1652,9 @@ void NVUnloadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state) {
state->scale = NV_RD32(par->PRAMDAC, 0x0848);
state->config = NV_RD32(par->PFB, 0x0200);
+ if (par->Architecture >= NV_ARCH_40 && !par->FlatPanel)
+ state->control = NV_RD32(par->PRAMDAC0, 0x0580);
+
if (par->Architecture >= NV_ARCH_10) {
if (par->twoHeads) {
state->head = NV_RD32(par->PCRTC0, 0x0860);
diff --git a/drivers/video/nvidia/nv_setup.c b/drivers/video/nvidia/nv_setup.c
index 707e2c8a13ed..82579d3a9970 100644
--- a/drivers/video/nvidia/nv_setup.c
+++ b/drivers/video/nvidia/nv_setup.c
@@ -166,11 +166,13 @@ u8 NVReadDacData(struct nvidia_par *par)
static int NVIsConnected(struct nvidia_par *par, int output)
{
volatile u32 __iomem *PRAMDAC = par->PRAMDAC0;
- u32 reg52C, reg608;
+ u32 reg52C, reg608, dac0_reg608 = 0;
int present;
- if (output)
- PRAMDAC += 0x800;
+ if (output) {
+ dac0_reg608 = NV_RD32(PRAMDAC, 0x0608);
+ PRAMDAC += 0x800;
+ }
reg52C = NV_RD32(PRAMDAC, 0x052C);
reg608 = NV_RD32(PRAMDAC, 0x0608);
@@ -194,8 +196,8 @@ static int NVIsConnected(struct nvidia_par *par, int output)
else
printk("nvidiafb: CRTC%i analog not found\n", output);
- NV_WR32(par->PRAMDAC0, 0x0608, NV_RD32(par->PRAMDAC0, 0x0608) &
- 0x0000EFFF);
+ if (output)
+ NV_WR32(par->PRAMDAC0, 0x0608, dac0_reg608);
NV_WR32(PRAMDAC, 0x052C, reg52C);
NV_WR32(PRAMDAC, 0x0608, reg608);
diff --git a/drivers/video/nvidia/nv_type.h b/drivers/video/nvidia/nv_type.h
index 38f7cc0a2331..2fdf77ec39fc 100644
--- a/drivers/video/nvidia/nv_type.h
+++ b/drivers/video/nvidia/nv_type.h
@@ -86,6 +86,7 @@ typedef struct _riva_hw_state {
u32 timingV;
u32 displayV;
u32 crtcSync;
+ u32 control;
} RIVA_HW_STATE;
struct riva_regs {
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 41f63658572f..a7fe214f0f77 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -674,6 +674,7 @@ static int nvidiafb_set_par(struct fb_info *info)
info->fbops->fb_sync = nvidiafb_sync;
info->pixmap.scan_align = 4;
info->flags &= ~FBINFO_HWACCEL_DISABLED;
+ info->flags |= FBINFO_READS_FAST;
NVResetGraphics(info);
} else {
info->fbops->fb_imageblit = cfb_imageblit;
@@ -682,6 +683,7 @@ static int nvidiafb_set_par(struct fb_info *info)
info->fbops->fb_sync = NULL;
info->pixmap.scan_align = 1;
info->flags |= FBINFO_HWACCEL_DISABLED;
+ info->flags &= ~FBINFO_READS_FAST;
}
par->cursor_reset = 1;
@@ -1193,7 +1195,8 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info)
printk(KERN_INFO PFX "Device ID: %x \n", id);
- if ((id & 0xfff0) == 0x00f0) {
+ if ((id & 0xfff0) == 0x00f0 ||
+ (id & 0xfff0) == 0x02e0) {
/* pci-e */
id = NV_RD32(par->REGS, 0x1800);
@@ -1238,18 +1241,16 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info)
case 0x0040: /* GeForce 6800 */
case 0x00C0: /* GeForce 6800 */
case 0x0120: /* GeForce 6800 */
- case 0x0130:
case 0x0140: /* GeForce 6600 */
case 0x0160: /* GeForce 6200 */
case 0x01D0: /* GeForce 7200, 7300, 7400 */
- case 0x02E0: /* GeForce 7300 GT */
case 0x0090: /* GeForce 7800 */
case 0x0210: /* GeForce 6800 */
case 0x0220: /* GeForce 6200 */
- case 0x0230:
case 0x0240: /* GeForce 6100 */
case 0x0290: /* GeForce 7900 */
case 0x0390: /* GeForce 7600 */
+ case 0x03D0:
arch = NV_ARCH_40;
break;
case 0x0020: /* TNT, TNT2 */
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 885b42836cbb..452433d46973 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -271,7 +271,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
return;
}
- size = sizeof(struct fb_info) + sizeof(u32) * 17;
+ size = sizeof(struct fb_info) + sizeof(u32) * 16;
info = kmalloc(size, GFP_ATOMIC);
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
new file mode 100644
index 000000000000..7f4d25b8a184
--- /dev/null
+++ b/drivers/video/omap/Kconfig
@@ -0,0 +1,58 @@
+config FB_OMAP
+ tristate "OMAP frame buffer support (EXPERIMENTAL)"
+ depends on FB
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for OMAP based boards.
+
+config FB_OMAP_BOOTLOADER_INIT
+ bool "Check bootloader initializaion"
+ depends on FB_OMAP
+ help
+ Say Y here if you want to enable checking if the bootloader has
+ already initialized the display controller. In this case the
+ driver will skip the initialization.
+
+config FB_OMAP_CONSISTENT_DMA_SIZE
+ int "Consistent DMA memory size (MB)"
+ depends on FB_OMAP
+ range 1 14
+ default 2
+ help
+ Increase the DMA consistent memory size according to your video
+ memory needs, for example if you want to use multiple planes.
+ The size must be 2MB aligned.
+ If unsure say 1.
+
+config FB_OMAP_DMA_TUNE
+ bool "Set DMA SDRAM access priority high"
+ depends on FB_OMAP && ARCH_OMAP1
+ help
+ On systems in which video memory is in system memory
+ (SDRAM) this will speed up graphics DMA operations.
+ If you have such a system and want to use rotation
+ answer yes. Answer no if you have a dedicated video
+ memory, or don't use any of the accelerated features.
+
+config FB_OMAP_LCDC_EXTERNAL
+ bool "External LCD controller support"
+ depends on FB_OMAP
+ help
+ Say Y here, if you want to have support for boards with an
+ external LCD controller connected to the SoSSI/RFBI interface.
+
+config FB_OMAP_LCDC_HWA742
+ bool "Epson HWA742 LCD controller support"
+ depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+ help
+ Say Y here if you want to have support for the external
+ Epson HWA742 LCD controller.
+
+config FB_OMAP_LCDC_BLIZZARD
+ bool "Epson Blizzard LCD controller support"
+ depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL
+ help
+ Say Y here if you want to have support for the external
+ Epson Blizzard LCD controller.
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile
new file mode 100644
index 000000000000..99da8b6d2c36
--- /dev/null
+++ b/drivers/video/omap/Makefile
@@ -0,0 +1,29 @@
+#
+# Makefile for the new OMAP framebuffer device driver
+#
+
+obj-$(CONFIG_FB_OMAP) += omapfb.o
+
+objs-yy := omapfb_main.o
+
+objs-y$(CONFIG_ARCH_OMAP1) += lcdc.o
+objs-y$(CONFIG_ARCH_OMAP2) += dispc.o
+
+objs-$(CONFIG_ARCH_OMAP1)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
+objs-$(CONFIG_ARCH_OMAP2)$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += rfbi.o
+
+objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
+objs-y$(CONFIG_FB_OMAP_LCDC_BLIZZARD) += blizzard.o
+
+objs-y$(CONFIG_MACH_OMAP_H4) += lcd_h4.o
+objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
+objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
+objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
+objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
+objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
+objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
+objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
+objs-y$(CONFIG_MACH_SX1) += lcd_sx1.o
+
+omapfb-objs := $(objs-yy)
+
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
new file mode 100644
index 000000000000..e682940a97a4
--- /dev/null
+++ b/drivers/video/omap/blizzard.c
@@ -0,0 +1,1568 @@
+/*
+ * Epson Blizzard LCD controller driver
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Authors: Juha Yrjola <juha.yrjola@nokia.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * YUV support: Jussi Laako <jussi.laako@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/blizzard.h>
+
+#include "dispc.h"
+
+#define MODULE_NAME "blizzard"
+
+#define BLIZZARD_REV_CODE 0x00
+#define BLIZZARD_CONFIG 0x02
+#define BLIZZARD_PLL_DIV 0x04
+#define BLIZZARD_PLL_LOCK_RANGE 0x06
+#define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08
+#define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a
+#define BLIZZARD_PLL_MODE 0x0c
+#define BLIZZARD_CLK_SRC 0x0e
+#define BLIZZARD_MEM_BANK0_ACTIVATE 0x10
+#define BLIZZARD_MEM_BANK0_STATUS 0x14
+#define BLIZZARD_HDISP 0x2a
+#define BLIZZARD_HNDP 0x2c
+#define BLIZZARD_VDISP0 0x2e
+#define BLIZZARD_VDISP1 0x30
+#define BLIZZARD_VNDP 0x32
+#define BLIZZARD_HSW 0x34
+#define BLIZZARD_VSW 0x38
+#define BLIZZARD_DISPLAY_MODE 0x68
+#define BLIZZARD_INPUT_WIN_X_START_0 0x6c
+#define BLIZZARD_DATA_SOURCE_SELECT 0x8e
+#define BLIZZARD_DISP_MEM_DATA_PORT 0x90
+#define BLIZZARD_DISP_MEM_READ_ADDR0 0x92
+#define BLIZZARD_POWER_SAVE 0xE6
+#define BLIZZARD_NDISP_CTRL_STATUS 0xE8
+
+/* Data source select */
+/* For S1D13745 */
+#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00
+#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01
+#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04
+#define BLIZZARD_SRC_DISABLE_OVERLAY 0x05
+/* For S1D13744 */
+#define BLIZZARD_SRC_WRITE_LCD 0x00
+#define BLIZZARD_SRC_BLT_LCD 0x06
+
+#define BLIZZARD_COLOR_RGB565 0x01
+#define BLIZZARD_COLOR_YUV420 0x09
+
+#define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */
+#define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */
+
+#define BLIZZARD_AUTO_UPDATE_TIME (HZ / 20)
+
+/* Reserve 4 request slots for requests in irq context */
+#define REQ_POOL_SIZE 24
+#define IRQ_REQ_POOL_SIZE 4
+
+#define REQ_FROM_IRQ_POOL 0x01
+
+#define REQ_COMPLETE 0
+#define REQ_PENDING 1
+
+struct blizzard_reg_list {
+ int start;
+ int end;
+};
+
+/* These need to be saved / restored separately from the rest. */
+static struct blizzard_reg_list blizzard_pll_regs[] = {
+ {
+ .start = 0x04, /* Don't save PLL ctrl (0x0C) */
+ .end = 0x0a,
+ },
+ {
+ .start = 0x0e, /* Clock configuration */
+ .end = 0x0e,
+ },
+};
+
+static struct blizzard_reg_list blizzard_gen_regs[] = {
+ {
+ .start = 0x18, /* SDRAM control */
+ .end = 0x20,
+ },
+ {
+ .start = 0x28, /* LCD Panel configuration */
+ .end = 0x5a, /* HSSI interface, TV configuration */
+ },
+};
+
+static u8 blizzard_reg_cache[0x5a / 2];
+
+struct update_param {
+ int plane;
+ int x, y, width, height;
+ int out_x, out_y;
+ int out_width, out_height;
+ int color_mode;
+ int bpp;
+ int flags;
+};
+
+struct blizzard_request {
+ struct list_head entry;
+ unsigned int flags;
+
+ int (*handler)(struct blizzard_request *req);
+ void (*complete)(void *data);
+ void *complete_data;
+
+ union {
+ struct update_param update;
+ struct completion *sync;
+ } par;
+};
+
+struct plane_info {
+ unsigned long offset;
+ int pos_x, pos_y;
+ int width, height;
+ int out_width, out_height;
+ int scr_width;
+ int color_mode;
+ int bpp;
+};
+
+struct blizzard_struct {
+ enum omapfb_update_mode update_mode;
+ enum omapfb_update_mode update_mode_before_suspend;
+
+ struct timer_list auto_update_timer;
+ int stop_auto_update;
+ struct omapfb_update_window auto_update_window;
+ int enabled_planes;
+ int vid_nonstd_color;
+ int vid_scaled;
+ int last_color_mode;
+ int zoom_on;
+ int screen_width;
+ int screen_height;
+ unsigned te_connected:1;
+ unsigned vsync_only:1;
+
+ struct plane_info plane[OMAPFB_PLANE_NUM];
+
+ struct blizzard_request req_pool[REQ_POOL_SIZE];
+ struct list_head pending_req_list;
+ struct list_head free_req_list;
+ struct semaphore req_sema;
+ spinlock_t req_lock;
+
+ unsigned long sys_ck_rate;
+ struct extif_timings reg_timings, lut_timings;
+
+ u32 max_transmit_size;
+ u32 extif_clk_period;
+ int extif_clk_div;
+ unsigned long pix_tx_time;
+ unsigned long line_upd_time;
+
+ struct omapfb_device *fbdev;
+ struct lcd_ctrl_extif *extif;
+ struct lcd_ctrl *int_ctrl;
+
+ void (*power_up)(struct device *dev);
+ void (*power_down)(struct device *dev);
+
+ int version;
+} blizzard;
+
+struct lcd_ctrl blizzard_ctrl;
+
+static u8 blizzard_read_reg(u8 reg)
+{
+ u8 data;
+
+ blizzard.extif->set_bits_per_cycle(8);
+ blizzard.extif->write_command(&reg, 1);
+ blizzard.extif->read_data(&data, 1);
+
+ return data;
+}
+
+static void blizzard_write_reg(u8 reg, u8 val)
+{
+ blizzard.extif->set_bits_per_cycle(8);
+ blizzard.extif->write_command(&reg, 1);
+ blizzard.extif->write_data(&val, 1);
+}
+
+static void blizzard_restart_sdram(void)
+{
+ unsigned long tmo;
+
+ blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0);
+ udelay(50);
+ blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 1);
+ tmo = jiffies + msecs_to_jiffies(200);
+ while (!(blizzard_read_reg(BLIZZARD_MEM_BANK0_STATUS) & 0x01)) {
+ if (time_after(jiffies, tmo)) {
+ dev_err(blizzard.fbdev->dev,
+ "s1d1374x: SDRAM not ready");
+ break;
+ }
+ msleep(1);
+ }
+}
+
+static void blizzard_stop_sdram(void)
+{
+ blizzard_write_reg(BLIZZARD_MEM_BANK0_ACTIVATE, 0);
+}
+
+/* Wait until the last window was completely written into the controllers
+ * SDRAM and we can start transferring the next window.
+ */
+static void blizzard_wait_line_buffer(void)
+{
+ unsigned long tmo = jiffies + msecs_to_jiffies(30);
+
+ while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 7)) {
+ if (time_after(jiffies, tmo)) {
+ if (printk_ratelimit())
+ dev_err(blizzard.fbdev->dev,
+ "s1d1374x: line buffer not ready\n");
+ break;
+ }
+ }
+}
+
+/* Wait until the YYC color space converter is idle. */
+static void blizzard_wait_yyc(void)
+{
+ unsigned long tmo = jiffies + msecs_to_jiffies(30);
+
+ while (blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS) & (1 << 4)) {
+ if (time_after(jiffies, tmo)) {
+ if (printk_ratelimit())
+ dev_err(blizzard.fbdev->dev,
+ "s1d1374x: YYC not ready\n");
+ break;
+ }
+ }
+}
+
+static void disable_overlay(void)
+{
+ blizzard_write_reg(BLIZZARD_DATA_SOURCE_SELECT,
+ BLIZZARD_SRC_DISABLE_OVERLAY);
+}
+
+static void set_window_regs(int x_start, int y_start, int x_end, int y_end,
+ int x_out_start, int y_out_start,
+ int x_out_end, int y_out_end, int color_mode,
+ int zoom_off, int flags)
+{
+ u8 tmp[18];
+ u8 cmd;
+
+ x_end--;
+ y_end--;
+ tmp[0] = x_start;
+ tmp[1] = x_start >> 8;
+ tmp[2] = y_start;
+ tmp[3] = y_start >> 8;
+ tmp[4] = x_end;
+ tmp[5] = x_end >> 8;
+ tmp[6] = y_end;
+ tmp[7] = y_end >> 8;
+
+ x_out_end--;
+ y_out_end--;
+ tmp[8] = x_out_start;
+ tmp[9] = x_out_start >> 8;
+ tmp[10] = y_out_start;
+ tmp[11] = y_out_start >> 8;
+ tmp[12] = x_out_end;
+ tmp[13] = x_out_end >> 8;
+ tmp[14] = y_out_end;
+ tmp[15] = y_out_end >> 8;
+
+ tmp[16] = color_mode;
+ if (zoom_off && blizzard.version == BLIZZARD_VERSION_S1D13745)
+ tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
+ else if (flags & OMAPFB_FORMAT_FLAG_ENABLE_OVERLAY)
+ tmp[17] = BLIZZARD_SRC_WRITE_OVERLAY_ENABLE;
+ else
+ tmp[17] = blizzard.version == BLIZZARD_VERSION_S1D13744 ?
+ BLIZZARD_SRC_WRITE_LCD :
+ BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
+
+ blizzard.extif->set_bits_per_cycle(8);
+ cmd = BLIZZARD_INPUT_WIN_X_START_0;
+ blizzard.extif->write_command(&cmd, 1);
+ blizzard.extif->write_data(tmp, 18);
+}
+
+static void enable_tearsync(int y, int width, int height, int screen_height,
+ int out_height, int force_vsync)
+{
+ u8 b;
+
+ b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
+ b |= 1 << 3;
+ blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b);
+
+ if (likely(blizzard.vsync_only || force_vsync)) {
+ blizzard.extif->enable_tearsync(1, 0);
+ return;
+ }
+
+ if (width * blizzard.pix_tx_time < blizzard.line_upd_time) {
+ blizzard.extif->enable_tearsync(1, 0);
+ return;
+ }
+
+ if ((width * blizzard.pix_tx_time / 1000) * height <
+ (y + out_height) * (blizzard.line_upd_time / 1000)) {
+ blizzard.extif->enable_tearsync(1, 0);
+ return;
+ }
+
+ blizzard.extif->enable_tearsync(1, y + 1);
+}
+
+static void disable_tearsync(void)
+{
+ u8 b;
+
+ blizzard.extif->enable_tearsync(0, 0);
+ b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
+ b &= ~(1 << 3);
+ blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b);
+ b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
+}
+
+static inline void set_extif_timings(const struct extif_timings *t);
+
+static inline struct blizzard_request *alloc_req(void)
+{
+ unsigned long flags;
+ struct blizzard_request *req;
+ int req_flags = 0;
+
+ if (!in_interrupt())
+ down(&blizzard.req_sema);
+ else
+ req_flags = REQ_FROM_IRQ_POOL;
+
+ spin_lock_irqsave(&blizzard.req_lock, flags);
+ BUG_ON(list_empty(&blizzard.free_req_list));
+ req = list_entry(blizzard.free_req_list.next,
+ struct blizzard_request, entry);
+ list_del(&req->entry);
+ spin_unlock_irqrestore(&blizzard.req_lock, flags);
+
+ INIT_LIST_HEAD(&req->entry);
+ req->flags = req_flags;
+
+ return req;
+}
+
+static inline void free_req(struct blizzard_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&blizzard.req_lock, flags);
+
+ list_del(&req->entry);
+ list_add(&req->entry, &blizzard.free_req_list);
+ if (!(req->flags & REQ_FROM_IRQ_POOL))
+ up(&blizzard.req_sema);
+
+ spin_unlock_irqrestore(&blizzard.req_lock, flags);
+}
+
+static void process_pending_requests(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&blizzard.req_lock, flags);
+
+ while (!list_empty(&blizzard.pending_req_list)) {
+ struct blizzard_request *req;
+ void (*complete)(void *);
+ void *complete_data;
+
+ req = list_entry(blizzard.pending_req_list.next,
+ struct blizzard_request, entry);
+ spin_unlock_irqrestore(&blizzard.req_lock, flags);
+
+ if (req->handler(req) == REQ_PENDING)
+ return;
+
+ complete = req->complete;
+ complete_data = req->complete_data;
+ free_req(req);
+
+ if (complete)
+ complete(complete_data);
+
+ spin_lock_irqsave(&blizzard.req_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&blizzard.req_lock, flags);
+}
+
+static void submit_req_list(struct list_head *head)
+{
+ unsigned long flags;
+ int process = 1;
+
+ spin_lock_irqsave(&blizzard.req_lock, flags);
+ if (likely(!list_empty(&blizzard.pending_req_list)))
+ process = 0;
+ list_splice_init(head, blizzard.pending_req_list.prev);
+ spin_unlock_irqrestore(&blizzard.req_lock, flags);
+
+ if (process)
+ process_pending_requests();
+}
+
+static void request_complete(void *data)
+{
+ struct blizzard_request *req = (struct blizzard_request *)data;
+ void (*complete)(void *);
+ void *complete_data;
+
+ complete = req->complete;
+ complete_data = req->complete_data;
+
+ free_req(req);
+
+ if (complete)
+ complete(complete_data);
+
+ process_pending_requests();
+}
+
+
+static int do_full_screen_update(struct blizzard_request *req)
+{
+ int i;
+ int flags;
+
+ for (i = 0; i < 3; i++) {
+ struct plane_info *p = &blizzard.plane[i];
+ if (!(blizzard.enabled_planes & (1 << i))) {
+ blizzard.int_ctrl->enable_plane(i, 0);
+ continue;
+ }
+ dev_dbg(blizzard.fbdev->dev, "pw %d ph %d\n",
+ p->width, p->height);
+ blizzard.int_ctrl->setup_plane(i,
+ OMAPFB_CHANNEL_OUT_LCD, p->offset,
+ p->scr_width, p->pos_x, p->pos_y,
+ p->width, p->height,
+ p->color_mode);
+ blizzard.int_ctrl->enable_plane(i, 1);
+ }
+
+ dev_dbg(blizzard.fbdev->dev, "sw %d sh %d\n",
+ blizzard.screen_width, blizzard.screen_height);
+ blizzard_wait_line_buffer();
+ flags = req->par.update.flags;
+ if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
+ enable_tearsync(0, blizzard.screen_width,
+ blizzard.screen_height,
+ blizzard.screen_height,
+ blizzard.screen_height,
+ flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
+ else
+ disable_tearsync();
+
+ set_window_regs(0, 0, blizzard.screen_width, blizzard.screen_height,
+ 0, 0, blizzard.screen_width, blizzard.screen_height,
+ BLIZZARD_COLOR_RGB565, blizzard.zoom_on, flags);
+ blizzard.zoom_on = 0;
+
+ blizzard.extif->set_bits_per_cycle(16);
+ /* set_window_regs has left the register index at the right
+ * place, so no need to set it here.
+ */
+ blizzard.extif->transfer_area(blizzard.screen_width,
+ blizzard.screen_height,
+ request_complete, req);
+ return REQ_PENDING;
+}
+
+/* Setup all planes with an overlapping area with the update window. */
+static int do_partial_update(struct blizzard_request *req, int plane,
+ int x, int y, int w, int h,
+ int x_out, int y_out, int w_out, int h_out,
+ int wnd_color_mode, int bpp)
+{
+ int i;
+ int gx1, gy1, gx2, gy2;
+ int gx1_out, gy1_out, gx2_out, gy2_out;
+ int color_mode;
+ int flags;
+ int zoom_off;
+
+ /* Global coordinates, relative to pixel 0,0 of the LCD */
+ gx1 = x + blizzard.plane[plane].pos_x;
+ gy1 = y + blizzard.plane[plane].pos_y;
+ gx2 = gx1 + w;
+ gy2 = gy1 + h;
+
+ flags = req->par.update.flags;
+ if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
+ gx1_out = gx1;
+ gy1_out = gy1;
+ gx2_out = gx1 + w * 2;
+ gy2_out = gy1 + h * 2;
+ } else {
+ gx1_out = x_out + blizzard.plane[plane].pos_x;
+ gy1_out = y_out + blizzard.plane[plane].pos_y;
+ gx2_out = gx1_out + w_out;
+ gy2_out = gy1_out + h_out;
+ }
+ zoom_off = blizzard.zoom_on && gx1 == 0 && gy1 == 0 &&
+ w == blizzard.screen_width && h == blizzard.screen_height;
+ blizzard.zoom_on = (!zoom_off && blizzard.zoom_on) ||
+ (w < w_out || h < h_out);
+
+ for (i = 0; i < OMAPFB_PLANE_NUM; i++) {
+ struct plane_info *p = &blizzard.plane[i];
+ int px1, py1;
+ int px2, py2;
+ int pw, ph;
+ int pposx, pposy;
+ unsigned long offset;
+
+ if (!(blizzard.enabled_planes & (1 << i)) ||
+ (wnd_color_mode && i != plane)) {
+ blizzard.int_ctrl->enable_plane(i, 0);
+ continue;
+ }
+ /* Plane coordinates */
+ if (i == plane) {
+ /* Plane in which we are doing the update.
+ * Local coordinates are the one in the update
+ * request.
+ */
+ px1 = x;
+ py1 = y;
+ px2 = x + w;
+ py2 = y + h;
+ pposx = 0;
+ pposy = 0;
+ } else {
+ /* Check if this plane has an overlapping part */
+ px1 = gx1 - p->pos_x;
+ py1 = gy1 - p->pos_y;
+ px2 = gx2 - p->pos_x;
+ py2 = gy2 - p->pos_y;
+ if (px1 >= p->width || py1 >= p->height ||
+ px2 <= 0 || py2 <= 0) {
+ blizzard.int_ctrl->enable_plane(i, 0);
+ continue;
+ }
+ /* Calculate the coordinates for the overlapping
+ * part in the plane's local coordinates.
+ */
+ pposx = -px1;
+ pposy = -py1;
+ if (px1 < 0)
+ px1 = 0;
+ if (py1 < 0)
+ py1 = 0;
+ if (px2 > p->width)
+ px2 = p->width;
+ if (py2 > p->height)
+ py2 = p->height;
+ if (pposx < 0)
+ pposx = 0;
+ if (pposy < 0)
+ pposy = 0;
+ }
+ pw = px2 - px1;
+ ph = py2 - py1;
+ offset = p->offset + (p->scr_width * py1 + px1) * p->bpp / 8;
+ if (wnd_color_mode)
+ /* Window embedded in the plane with a differing
+ * color mode / bpp. Calculate the number of DMA
+ * transfer elements in terms of the plane's bpp.
+ */
+ pw = (pw + 1) * bpp / p->bpp;
+#ifdef VERBOSE
+ dev_dbg(blizzard.fbdev->dev,
+ "plane %d offset %#08lx pposx %d pposy %d "
+ "px1 %d py1 %d pw %d ph %d\n",
+ i, offset, pposx, pposy, px1, py1, pw, ph);
+#endif
+ blizzard.int_ctrl->setup_plane(i,
+ OMAPFB_CHANNEL_OUT_LCD, offset,
+ p->scr_width,
+ pposx, pposy, pw, ph,
+ p->color_mode);
+
+ blizzard.int_ctrl->enable_plane(i, 1);
+ }
+
+ switch (wnd_color_mode) {
+ case OMAPFB_COLOR_YUV420:
+ color_mode = BLIZZARD_COLOR_YUV420;
+ /* Currently only the 16 bits/pixel cycle format is
+ * supported on the external interface. Adjust the number
+ * of transfer elements per line for 12bpp format.
+ */
+ w = (w + 1) * 3 / 4;
+ break;
+ default:
+ color_mode = BLIZZARD_COLOR_RGB565;
+ break;
+ }
+
+ blizzard_wait_line_buffer();
+ if (blizzard.last_color_mode == BLIZZARD_COLOR_YUV420)
+ blizzard_wait_yyc();
+ blizzard.last_color_mode = color_mode;
+ if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
+ enable_tearsync(gy1, w, h,
+ blizzard.screen_height,
+ h_out,
+ flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
+ else
+ disable_tearsync();
+
+ set_window_regs(gx1, gy1, gx2, gy2, gx1_out, gy1_out, gx2_out, gy2_out,
+ color_mode, zoom_off, flags);
+
+ blizzard.extif->set_bits_per_cycle(16);
+ /* set_window_regs has left the register index at the right
+ * place, so no need to set it here.
+ */
+ blizzard.extif->transfer_area(w, h, request_complete, req);
+
+ return REQ_PENDING;
+}
+
+static int send_frame_handler(struct blizzard_request *req)
+{
+ struct update_param *par = &req->par.update;
+ int plane = par->plane;
+
+#ifdef VERBOSE
+ dev_dbg(blizzard.fbdev->dev,
+ "send_frame: x %d y %d w %d h %d "
+ "x_out %d y_out %d w_out %d h_out %d "
+ "color_mode %04x flags %04x planes %01x\n",
+ par->x, par->y, par->width, par->height,
+ par->out_x, par->out_y, par->out_width, par->out_height,
+ par->color_mode, par->flags, blizzard.enabled_planes);
+#endif
+ if (par->flags & OMAPFB_FORMAT_FLAG_DISABLE_OVERLAY)
+ disable_overlay();
+
+ if ((blizzard.enabled_planes & blizzard.vid_nonstd_color) ||
+ (blizzard.enabled_planes & blizzard.vid_scaled))
+ return do_full_screen_update(req);
+
+ return do_partial_update(req, plane, par->x, par->y,
+ par->width, par->height,
+ par->out_x, par->out_y,
+ par->out_width, par->out_height,
+ par->color_mode, par->bpp);
+}
+
+static void send_frame_complete(void *data)
+{
+}
+
+#define ADD_PREQ(_x, _y, _w, _h, _x_out, _y_out, _w_out, _h_out) do { \
+ req = alloc_req(); \
+ req->handler = send_frame_handler; \
+ req->complete = send_frame_complete; \
+ req->par.update.plane = plane_idx; \
+ req->par.update.x = _x; \
+ req->par.update.y = _y; \
+ req->par.update.width = _w; \
+ req->par.update.height = _h; \
+ req->par.update.out_x = _x_out; \
+ req->par.update.out_y = _y_out; \
+ req->par.update.out_width = _w_out; \
+ req->par.update.out_height = _h_out; \
+ req->par.update.bpp = bpp; \
+ req->par.update.color_mode = color_mode;\
+ req->par.update.flags = flags; \
+ list_add_tail(&req->entry, req_head); \
+} while(0)
+
+static void create_req_list(int plane_idx,
+ struct omapfb_update_window *win,
+ struct list_head *req_head)
+{
+ struct blizzard_request *req;
+ int x = win->x;
+ int y = win->y;
+ int width = win->width;
+ int height = win->height;
+ int x_out = win->out_x;
+ int y_out = win->out_y;
+ int width_out = win->out_width;
+ int height_out = win->out_height;
+ int color_mode;
+ int bpp;
+ int flags;
+ unsigned int ystart = y;
+ unsigned int yspan = height;
+ unsigned int ystart_out = y_out;
+ unsigned int yspan_out = height_out;
+
+ flags = win->format & ~OMAPFB_FORMAT_MASK;
+ color_mode = win->format & OMAPFB_FORMAT_MASK;
+ switch (color_mode) {
+ case OMAPFB_COLOR_YUV420:
+ /* Embedded window with different color mode */
+ bpp = 12;
+ /* X, Y, height must be aligned at 2, width at 4 pixels */
+ x &= ~1;
+ y &= ~1;
+ height = yspan = height & ~1;
+ width = width & ~3;
+ break;
+ default:
+ /* Same as the plane color mode */
+ bpp = blizzard.plane[plane_idx].bpp;
+ break;
+ }
+ if (width * height * bpp / 8 > blizzard.max_transmit_size) {
+ yspan = blizzard.max_transmit_size / (width * bpp / 8);
+ yspan_out = yspan * height_out / height;
+ ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out,
+ width_out, yspan_out);
+ ystart += yspan;
+ ystart_out += yspan_out;
+ yspan = height - yspan;
+ yspan_out = height_out - yspan_out;
+ flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
+ }
+
+ ADD_PREQ(x, ystart, width, yspan, x_out, ystart_out,
+ width_out, yspan_out);
+}
+
+static void auto_update_complete(void *data)
+{
+ if (!blizzard.stop_auto_update)
+ mod_timer(&blizzard.auto_update_timer,
+ jiffies + BLIZZARD_AUTO_UPDATE_TIME);
+}
+
+static void blizzard_update_window_auto(unsigned long arg)
+{
+ LIST_HEAD(req_list);
+ struct blizzard_request *last;
+ struct omapfb_plane_struct *plane;
+
+ plane = blizzard.fbdev->fb_info[0]->par;
+ create_req_list(plane->idx,
+ &blizzard.auto_update_window, &req_list);
+ last = list_entry(req_list.prev, struct blizzard_request, entry);
+
+ last->complete = auto_update_complete;
+ last->complete_data = NULL;
+
+ submit_req_list(&req_list);
+}
+
+int blizzard_update_window_async(struct fb_info *fbi,
+ struct omapfb_update_window *win,
+ void (*complete_callback)(void *arg),
+ void *complete_callback_data)
+{
+ LIST_HEAD(req_list);
+ struct blizzard_request *last;
+ struct omapfb_plane_struct *plane = fbi->par;
+
+ if (unlikely(blizzard.update_mode != OMAPFB_MANUAL_UPDATE))
+ return -EINVAL;
+ if (unlikely(!blizzard.te_connected &&
+ (win->format & OMAPFB_FORMAT_FLAG_TEARSYNC)))
+ return -EINVAL;
+
+ create_req_list(plane->idx, win, &req_list);
+ last = list_entry(req_list.prev, struct blizzard_request, entry);
+
+ last->complete = complete_callback;
+ last->complete_data = (void *)complete_callback_data;
+
+ submit_req_list(&req_list);
+
+ return 0;
+}
+EXPORT_SYMBOL(blizzard_update_window_async);
+
+static int update_full_screen(void)
+{
+ return blizzard_update_window_async(blizzard.fbdev->fb_info[0],
+ &blizzard.auto_update_window, NULL, NULL);
+
+}
+
+static int blizzard_setup_plane(int plane, int channel_out,
+ unsigned long offset, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ struct plane_info *p;
+
+#ifdef VERBOSE
+ dev_dbg(blizzard.fbdev->dev,
+ "plane %d ch_out %d offset %#08lx scr_width %d "
+ "pos_x %d pos_y %d width %d height %d color_mode %d\n",
+ plane, channel_out, offset, screen_width,
+ pos_x, pos_y, width, height, color_mode);
+#endif
+ if ((unsigned)plane > OMAPFB_PLANE_NUM)
+ return -EINVAL;
+ p = &blizzard.plane[plane];
+
+ switch (color_mode) {
+ case OMAPFB_COLOR_YUV422:
+ case OMAPFB_COLOR_YUY422:
+ p->bpp = 16;
+ blizzard.vid_nonstd_color &= ~(1 << plane);
+ break;
+ case OMAPFB_COLOR_YUV420:
+ p->bpp = 12;
+ blizzard.vid_nonstd_color |= 1 << plane;
+ break;
+ case OMAPFB_COLOR_RGB565:
+ p->bpp = 16;
+ blizzard.vid_nonstd_color &= ~(1 << plane);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ p->offset = offset;
+ p->pos_x = pos_x;
+ p->pos_y = pos_y;
+ p->width = width;
+ p->height = height;
+ p->scr_width = screen_width;
+ if (!p->out_width)
+ p->out_width = width;
+ if (!p->out_height)
+ p->out_height = height;
+
+ p->color_mode = color_mode;
+
+ return 0;
+}
+
+static int blizzard_set_scale(int plane, int orig_w, int orig_h,
+ int out_w, int out_h)
+{
+ struct plane_info *p = &blizzard.plane[plane];
+ int r;
+
+ dev_dbg(blizzard.fbdev->dev,
+ "plane %d orig_w %d orig_h %d out_w %d out_h %d\n",
+ plane, orig_w, orig_h, out_w, out_h);
+ if ((unsigned)plane > OMAPFB_PLANE_NUM)
+ return -ENODEV;
+
+ r = blizzard.int_ctrl->set_scale(plane, orig_w, orig_h, out_w, out_h);
+ if (r < 0)
+ return r;
+
+ p->width = orig_w;
+ p->height = orig_h;
+ p->out_width = out_w;
+ p->out_height = out_h;
+ if (orig_w == out_w && orig_h == out_h)
+ blizzard.vid_scaled &= ~(1 << plane);
+ else
+ blizzard.vid_scaled |= 1 << plane;
+
+ return 0;
+}
+
+static int blizzard_enable_plane(int plane, int enable)
+{
+ if (enable)
+ blizzard.enabled_planes |= 1 << plane;
+ else
+ blizzard.enabled_planes &= ~(1 << plane);
+
+ return 0;
+}
+
+static int sync_handler(struct blizzard_request *req)
+{
+ complete(req->par.sync);
+ return REQ_COMPLETE;
+}
+
+static void blizzard_sync(void)
+{
+ LIST_HEAD(req_list);
+ struct blizzard_request *req;
+ struct completion comp;
+
+ req = alloc_req();
+
+ req->handler = sync_handler;
+ req->complete = NULL;
+ init_completion(&comp);
+ req->par.sync = &comp;
+
+ list_add(&req->entry, &req_list);
+ submit_req_list(&req_list);
+
+ wait_for_completion(&comp);
+}
+
+
+static void blizzard_bind_client(struct omapfb_notifier_block *nb)
+{
+ if (blizzard.update_mode == OMAPFB_MANUAL_UPDATE) {
+ omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY);
+ }
+}
+
+static int blizzard_set_update_mode(enum omapfb_update_mode mode)
+{
+ if (unlikely(mode != OMAPFB_MANUAL_UPDATE &&
+ mode != OMAPFB_AUTO_UPDATE &&
+ mode != OMAPFB_UPDATE_DISABLED))
+ return -EINVAL;
+
+ if (mode == blizzard.update_mode)
+ return 0;
+
+ dev_info(blizzard.fbdev->dev, "s1d1374x: setting update mode to %s\n",
+ mode == OMAPFB_UPDATE_DISABLED ? "disabled" :
+ (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual"));
+
+ switch (blizzard.update_mode) {
+ case OMAPFB_MANUAL_UPDATE:
+ omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_DISABLED);
+ break;
+ case OMAPFB_AUTO_UPDATE:
+ blizzard.stop_auto_update = 1;
+ del_timer_sync(&blizzard.auto_update_timer);
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ break;
+ }
+
+ blizzard.update_mode = mode;
+ blizzard_sync();
+ blizzard.stop_auto_update = 0;
+
+ switch (mode) {
+ case OMAPFB_MANUAL_UPDATE:
+ omapfb_notify_clients(blizzard.fbdev, OMAPFB_EVENT_READY);
+ break;
+ case OMAPFB_AUTO_UPDATE:
+ blizzard_update_window_auto(0);
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ break;
+ }
+
+ return 0;
+}
+
+static enum omapfb_update_mode blizzard_get_update_mode(void)
+{
+ return blizzard.update_mode;
+}
+
+static inline void set_extif_timings(const struct extif_timings *t)
+{
+ blizzard.extif->set_timings(t);
+}
+
+static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
+{
+ int bus_tick = blizzard.extif_clk_period * div;
+ return (ps + bus_tick - 1) / bus_tick * bus_tick;
+}
+
+static int calc_reg_timing(unsigned long sysclk, int div)
+{
+ struct extif_timings *t;
+ unsigned long systim;
+
+ /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+ * AccessTime 2 ns + 12.2 ns (regs),
+ * WEOffTime = WEOnTime + 1 ns,
+ * REOffTime = REOnTime + 12 ns (regs),
+ * CSOffTime = REOffTime + 1 ns
+ * ReadCycle = 2ns + 2*SYSCLK (regs),
+ * WriteCycle = 2*SYSCLK + 2 ns,
+ * CSPulseWidth = 10 ns */
+
+ systim = 1000000000 / (sysclk / 1000);
+ dev_dbg(blizzard.fbdev->dev,
+ "Blizzard systim %lu ps extif_clk_period %u div %d\n",
+ systim, blizzard.extif_clk_period, div);
+
+ t = &blizzard.reg_timings;
+ memset(t, 0, sizeof(*t));
+
+ t->clk_div = div;
+
+ t->cs_on_time = 0;
+ t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div);
+ t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+ t->re_off_time = round_to_extif_ticks(t->re_on_time + 13000, div);
+ t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+ t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->we_cycle_time < t->we_off_time)
+ t->we_cycle_time = t->we_off_time;
+ t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->re_cycle_time < t->re_off_time)
+ t->re_cycle_time = t->re_off_time;
+ t->cs_pulse_width = 0;
+
+ dev_dbg(blizzard.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n",
+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+ dev_dbg(blizzard.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
+ t->we_on_time, t->we_off_time, t->re_cycle_time,
+ t->we_cycle_time);
+ dev_dbg(blizzard.fbdev->dev, "[reg]rdaccess %d cspulse %d\n",
+ t->access_time, t->cs_pulse_width);
+
+ return blizzard.extif->convert_timings(t);
+}
+
+static int calc_lut_timing(unsigned long sysclk, int div)
+{
+ struct extif_timings *t;
+ unsigned long systim;
+
+ /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+ * AccessTime 2 ns + 4 * SYSCLK + 26 (lut),
+ * WEOffTime = WEOnTime + 1 ns,
+ * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut),
+ * CSOffTime = REOffTime + 1 ns
+ * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut),
+ * WriteCycle = 2*SYSCLK + 2 ns,
+ * CSPulseWidth = 10 ns */
+
+ systim = 1000000000 / (sysclk / 1000);
+ dev_dbg(blizzard.fbdev->dev,
+ "Blizzard systim %lu ps extif_clk_period %u div %d\n",
+ systim, blizzard.extif_clk_period, div);
+
+ t = &blizzard.lut_timings;
+ memset(t, 0, sizeof(*t));
+
+ t->clk_div = div;
+
+ t->cs_on_time = 0;
+ t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+ 26000, div);
+ t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+ t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+ 26000, div);
+ t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+ t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->we_cycle_time < t->we_off_time)
+ t->we_cycle_time = t->we_off_time;
+ t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div);
+ if (t->re_cycle_time < t->re_off_time)
+ t->re_cycle_time = t->re_off_time;
+ t->cs_pulse_width = 0;
+
+ dev_dbg(blizzard.fbdev->dev,
+ "[lut]cson %d csoff %d reon %d reoff %d\n",
+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+ dev_dbg(blizzard.fbdev->dev,
+ "[lut]weon %d weoff %d recyc %d wecyc %d\n",
+ t->we_on_time, t->we_off_time, t->re_cycle_time,
+ t->we_cycle_time);
+ dev_dbg(blizzard.fbdev->dev, "[lut]rdaccess %d cspulse %d\n",
+ t->access_time, t->cs_pulse_width);
+
+ return blizzard.extif->convert_timings(t);
+}
+
+static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
+{
+ int max_clk_div;
+ int div;
+
+ blizzard.extif->get_clk_info(&blizzard.extif_clk_period, &max_clk_div);
+ for (div = 1; div <= max_clk_div; div++) {
+ if (calc_reg_timing(sysclk, div) == 0)
+ break;
+ }
+ if (div > max_clk_div) {
+ dev_dbg(blizzard.fbdev->dev, "reg timing failed\n");
+ goto err;
+ }
+ *extif_mem_div = div;
+
+ for (div = 1; div <= max_clk_div; div++) {
+ if (calc_lut_timing(sysclk, div) == 0)
+ break;
+ }
+
+ if (div > max_clk_div)
+ goto err;
+
+ blizzard.extif_clk_div = div;
+
+ return 0;
+err:
+ dev_err(blizzard.fbdev->dev, "can't setup timings\n");
+ return -1;
+}
+
+static void calc_blizzard_clk_rates(unsigned long ext_clk,
+ unsigned long *sys_clk, unsigned long *pix_clk)
+{
+ int pix_clk_src;
+ int sys_div = 0, sys_mul = 0;
+ int pix_div;
+
+ pix_clk_src = blizzard_read_reg(BLIZZARD_CLK_SRC);
+ pix_div = ((pix_clk_src >> 3) & 0x1f) + 1;
+ if ((pix_clk_src & (0x3 << 1)) == 0) {
+ /* Source is the PLL */
+ sys_div = (blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x3f) + 1;
+ sys_mul = blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_0);
+ sys_mul |= ((blizzard_read_reg(BLIZZARD_PLL_CLOCK_SYNTH_1)
+ & 0x0f) << 11);
+ *sys_clk = ext_clk * sys_mul / sys_div;
+ } else /* else source is ext clk, or oscillator */
+ *sys_clk = ext_clk;
+
+ *pix_clk = *sys_clk / pix_div; /* HZ */
+ dev_dbg(blizzard.fbdev->dev,
+ "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n",
+ ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul);
+ dev_dbg(blizzard.fbdev->dev, "sys_clk %ld pix_clk %ld\n",
+ *sys_clk, *pix_clk);
+}
+
+static int setup_tearsync(unsigned long pix_clk, int extif_div)
+{
+ int hdisp, vdisp;
+ int hndp, vndp;
+ int hsw, vsw;
+ int hs, vs;
+ int hs_pol_inv, vs_pol_inv;
+ int use_hsvs, use_ndp;
+ u8 b;
+
+ hsw = blizzard_read_reg(BLIZZARD_HSW);
+ vsw = blizzard_read_reg(BLIZZARD_VSW);
+ hs_pol_inv = !(hsw & 0x80);
+ vs_pol_inv = !(vsw & 0x80);
+ hsw = hsw & 0x7f;
+ vsw = vsw & 0x3f;
+
+ hdisp = blizzard_read_reg(BLIZZARD_HDISP) * 8;
+ vdisp = blizzard_read_reg(BLIZZARD_VDISP0) +
+ ((blizzard_read_reg(BLIZZARD_VDISP1) & 0x3) << 8);
+
+ hndp = blizzard_read_reg(BLIZZARD_HNDP) & 0x3f;
+ vndp = blizzard_read_reg(BLIZZARD_VNDP);
+
+ /* time to transfer one pixel (16bpp) in ps */
+ blizzard.pix_tx_time = blizzard.reg_timings.we_cycle_time;
+ if (blizzard.extif->get_max_tx_rate != NULL) {
+ /* The external interface might have a rate limitation,
+ * if so, we have to maximize our transfer rate.
+ */
+ unsigned long min_tx_time;
+ unsigned long max_tx_rate = blizzard.extif->get_max_tx_rate();
+
+ dev_dbg(blizzard.fbdev->dev, "max_tx_rate %ld HZ\n",
+ max_tx_rate);
+ min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */
+ if (blizzard.pix_tx_time < min_tx_time)
+ blizzard.pix_tx_time = min_tx_time;
+ }
+
+ /* time to update one line in ps */
+ blizzard.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000);
+ blizzard.line_upd_time *= 1000;
+ if (hdisp * blizzard.pix_tx_time > blizzard.line_upd_time)
+ /* transfer speed too low, we might have to use both
+ * HS and VS */
+ use_hsvs = 1;
+ else
+ /* decent transfer speed, we'll always use only VS */
+ use_hsvs = 0;
+
+ if (use_hsvs && (hs_pol_inv || vs_pol_inv)) {
+ /* HS or'ed with VS doesn't work, use the active high
+ * TE signal based on HNDP / VNDP */
+ use_ndp = 1;
+ hs_pol_inv = 0;
+ vs_pol_inv = 0;
+ hs = hndp;
+ vs = vndp;
+ } else {
+ /* Use HS or'ed with VS as a TE signal if both are needed
+ * or VNDP if only vsync is needed. */
+ use_ndp = 0;
+ hs = hsw;
+ vs = vsw;
+ if (!use_hsvs) {
+ hs_pol_inv = 0;
+ vs_pol_inv = 0;
+ }
+ }
+
+ hs = hs * 1000000 / (pix_clk / 1000); /* ps */
+ hs *= 1000;
+
+ vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */
+ vs *= 1000;
+
+ if (vs <= hs)
+ return -EDOM;
+ /* set VS to 120% of HS to minimize VS detection time */
+ vs = hs * 12 / 10;
+ /* minimize HS too */
+ if (hs > 10000)
+ hs = 10000;
+
+ b = blizzard_read_reg(BLIZZARD_NDISP_CTRL_STATUS);
+ b &= ~0x3;
+ b |= use_hsvs ? 1 : 0;
+ b |= (use_ndp && use_hsvs) ? 0 : 2;
+ blizzard_write_reg(BLIZZARD_NDISP_CTRL_STATUS, b);
+
+ blizzard.vsync_only = !use_hsvs;
+
+ dev_dbg(blizzard.fbdev->dev,
+ "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n",
+ pix_clk, blizzard.pix_tx_time, blizzard.line_upd_time);
+ dev_dbg(blizzard.fbdev->dev,
+ "hs %d ps vs %d ps mode %d vsync_only %d\n",
+ hs, vs, b & 0x3, !use_hsvs);
+
+ return blizzard.extif->setup_tearsync(1, hs, vs,
+ hs_pol_inv, vs_pol_inv,
+ extif_div);
+}
+
+static void blizzard_get_caps(int plane, struct omapfb_caps *caps)
+{
+ blizzard.int_ctrl->get_caps(plane, caps);
+ caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE |
+ OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE |
+ OMAPFB_CAPS_WINDOW_SCALE |
+ OMAPFB_CAPS_WINDOW_OVERLAY;
+ if (blizzard.te_connected)
+ caps->ctrl |= OMAPFB_CAPS_TEARSYNC;
+ caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) |
+ (1 << OMAPFB_COLOR_YUV420);
+}
+
+static void _save_regs(struct blizzard_reg_list *list, int cnt)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++, list++) {
+ int reg;
+ for (reg = list->start; reg <= list->end; reg += 2)
+ blizzard_reg_cache[reg / 2] = blizzard_read_reg(reg);
+ }
+}
+
+static void _restore_regs(struct blizzard_reg_list *list, int cnt)
+{
+ int i;
+
+ for (i = 0; i < cnt; i++, list++) {
+ int reg;
+ for (reg = list->start; reg <= list->end; reg += 2)
+ blizzard_write_reg(reg, blizzard_reg_cache[reg / 2]);
+ }
+}
+
+static void blizzard_save_all_regs(void)
+{
+ _save_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
+ _save_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
+}
+
+static void blizzard_restore_pll_regs(void)
+{
+ _restore_regs(blizzard_pll_regs, ARRAY_SIZE(blizzard_pll_regs));
+}
+
+static void blizzard_restore_gen_regs(void)
+{
+ _restore_regs(blizzard_gen_regs, ARRAY_SIZE(blizzard_gen_regs));
+}
+
+static void blizzard_suspend(void)
+{
+ u32 l;
+ unsigned long tmo;
+
+ if (blizzard.last_color_mode) {
+ update_full_screen();
+ blizzard_sync();
+ }
+ blizzard.update_mode_before_suspend = blizzard.update_mode;
+ /* the following will disable clocks as well */
+ blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED);
+
+ blizzard_save_all_regs();
+
+ blizzard_stop_sdram();
+
+ l = blizzard_read_reg(BLIZZARD_POWER_SAVE);
+ /* Standby, Sleep. We assume we use an external clock. */
+ l |= 0x03;
+ blizzard_write_reg(BLIZZARD_POWER_SAVE, l);
+
+ tmo = jiffies + msecs_to_jiffies(100);
+ while (!(blizzard_read_reg(BLIZZARD_PLL_MODE) & (1 << 1))) {
+ if (time_after(jiffies, tmo)) {
+ dev_err(blizzard.fbdev->dev,
+ "s1d1374x: sleep timeout, stopping PLL manually\n");
+ l = blizzard_read_reg(BLIZZARD_PLL_MODE);
+ l &= ~0x03;
+ /* Disable PLL, counter function */
+ l |= 0x2;
+ blizzard_write_reg(BLIZZARD_PLL_MODE, l);
+ break;
+ }
+ msleep(1);
+ }
+
+ if (blizzard.power_down != NULL)
+ blizzard.power_down(blizzard.fbdev->dev);
+}
+
+static void blizzard_resume(void)
+{
+ u32 l;
+
+ if (blizzard.power_up != NULL)
+ blizzard.power_up(blizzard.fbdev->dev);
+
+ l = blizzard_read_reg(BLIZZARD_POWER_SAVE);
+ /* Standby, Sleep */
+ l &= ~0x03;
+ blizzard_write_reg(BLIZZARD_POWER_SAVE, l);
+
+ blizzard_restore_pll_regs();
+ l = blizzard_read_reg(BLIZZARD_PLL_MODE);
+ l &= ~0x03;
+ /* Enable PLL, counter function */
+ l |= 0x1;
+ blizzard_write_reg(BLIZZARD_PLL_MODE, l);
+
+ while (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & (1 << 7)))
+ msleep(1);
+
+ blizzard_restart_sdram();
+
+ blizzard_restore_gen_regs();
+
+ /* Enable display */
+ blizzard_write_reg(BLIZZARD_DISPLAY_MODE, 0x01);
+
+ /* the following will enable clocks as necessary */
+ blizzard_set_update_mode(blizzard.update_mode_before_suspend);
+
+ /* Force a background update */
+ blizzard.zoom_on = 1;
+ update_full_screen();
+ blizzard_sync();
+}
+
+static int blizzard_init(struct omapfb_device *fbdev, int ext_mode,
+ struct omapfb_mem_desc *req_vram)
+{
+ int r = 0, i;
+ u8 rev, conf;
+ unsigned long ext_clk;
+ int extif_div;
+ unsigned long sys_clk, pix_clk;
+ struct omapfb_platform_data *omapfb_conf;
+ struct blizzard_platform_data *ctrl_conf;
+
+ blizzard.fbdev = fbdev;
+
+ BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
+
+ blizzard.fbdev = fbdev;
+ blizzard.extif = fbdev->ext_if;
+ blizzard.int_ctrl = fbdev->int_ctrl;
+
+ omapfb_conf = fbdev->dev->platform_data;
+ ctrl_conf = omapfb_conf->ctrl_platform_data;
+ if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) {
+ dev_err(fbdev->dev, "s1d1374x: missing platform data\n");
+ r = -ENOENT;
+ goto err1;
+ }
+
+ blizzard.power_down = ctrl_conf->power_down;
+ blizzard.power_up = ctrl_conf->power_up;
+
+ spin_lock_init(&blizzard.req_lock);
+
+ if ((r = blizzard.int_ctrl->init(fbdev, 1, req_vram)) < 0)
+ goto err1;
+
+ if ((r = blizzard.extif->init(fbdev)) < 0)
+ goto err2;
+
+ blizzard_ctrl.set_color_key = blizzard.int_ctrl->set_color_key;
+ blizzard_ctrl.get_color_key = blizzard.int_ctrl->get_color_key;
+ blizzard_ctrl.setup_mem = blizzard.int_ctrl->setup_mem;
+ blizzard_ctrl.mmap = blizzard.int_ctrl->mmap;
+
+ ext_clk = ctrl_conf->get_clock_rate(fbdev->dev);
+ if ((r = calc_extif_timings(ext_clk, &extif_div)) < 0)
+ goto err3;
+
+ set_extif_timings(&blizzard.reg_timings);
+
+ if (blizzard.power_up != NULL)
+ blizzard.power_up(fbdev->dev);
+
+ calc_blizzard_clk_rates(ext_clk, &sys_clk, &pix_clk);
+
+ if ((r = calc_extif_timings(sys_clk, &extif_div)) < 0)
+ goto err3;
+ set_extif_timings(&blizzard.reg_timings);
+
+ if (!(blizzard_read_reg(BLIZZARD_PLL_DIV) & 0x80)) {
+ dev_err(fbdev->dev,
+ "controller not initialized by the bootloader\n");
+ r = -ENODEV;
+ goto err3;
+ }
+
+ if (ctrl_conf->te_connected) {
+ if ((r = setup_tearsync(pix_clk, extif_div)) < 0)
+ goto err3;
+ blizzard.te_connected = 1;
+ }
+
+ rev = blizzard_read_reg(BLIZZARD_REV_CODE);
+ conf = blizzard_read_reg(BLIZZARD_CONFIG);
+
+ switch (rev & 0xfc) {
+ case 0x9c:
+ blizzard.version = BLIZZARD_VERSION_S1D13744;
+ pr_info("omapfb: s1d13744 LCD controller rev %d "
+ "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+ break;
+ case 0xa4:
+ blizzard.version = BLIZZARD_VERSION_S1D13745;
+ pr_info("omapfb: s1d13745 LCD controller rev %d "
+ "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+ break;
+ default:
+ dev_err(fbdev->dev, "invalid s1d1374x revision %02x\n",
+ rev);
+ r = -ENODEV;
+ goto err3;
+ }
+
+ blizzard.max_transmit_size = blizzard.extif->max_transmit_size;
+
+ blizzard.update_mode = OMAPFB_UPDATE_DISABLED;
+
+ blizzard.auto_update_window.x = 0;
+ blizzard.auto_update_window.y = 0;
+ blizzard.auto_update_window.width = fbdev->panel->x_res;
+ blizzard.auto_update_window.height = fbdev->panel->y_res;
+ blizzard.auto_update_window.out_x = 0;
+ blizzard.auto_update_window.out_x = 0;
+ blizzard.auto_update_window.out_width = fbdev->panel->x_res;
+ blizzard.auto_update_window.out_height = fbdev->panel->y_res;
+ blizzard.auto_update_window.format = 0;
+
+ blizzard.screen_width = fbdev->panel->x_res;
+ blizzard.screen_height = fbdev->panel->y_res;
+
+ init_timer(&blizzard.auto_update_timer);
+ blizzard.auto_update_timer.function = blizzard_update_window_auto;
+ blizzard.auto_update_timer.data = 0;
+
+ INIT_LIST_HEAD(&blizzard.free_req_list);
+ INIT_LIST_HEAD(&blizzard.pending_req_list);
+ for (i = 0; i < ARRAY_SIZE(blizzard.req_pool); i++)
+ list_add(&blizzard.req_pool[i].entry, &blizzard.free_req_list);
+ BUG_ON(i <= IRQ_REQ_POOL_SIZE);
+ sema_init(&blizzard.req_sema, i - IRQ_REQ_POOL_SIZE);
+
+ return 0;
+err3:
+ if (blizzard.power_down != NULL)
+ blizzard.power_down(fbdev->dev);
+ blizzard.extif->cleanup();
+err2:
+ blizzard.int_ctrl->cleanup();
+err1:
+ return r;
+}
+
+static void blizzard_cleanup(void)
+{
+ blizzard_set_update_mode(OMAPFB_UPDATE_DISABLED);
+ blizzard.extif->cleanup();
+ blizzard.int_ctrl->cleanup();
+ if (blizzard.power_down != NULL)
+ blizzard.power_down(blizzard.fbdev->dev);
+}
+
+struct lcd_ctrl blizzard_ctrl = {
+ .name = "blizzard",
+ .init = blizzard_init,
+ .cleanup = blizzard_cleanup,
+ .bind_client = blizzard_bind_client,
+ .get_caps = blizzard_get_caps,
+ .set_update_mode = blizzard_set_update_mode,
+ .get_update_mode = blizzard_get_update_mode,
+ .setup_plane = blizzard_setup_plane,
+ .set_scale = blizzard_set_scale,
+ .enable_plane = blizzard_enable_plane,
+ .update_window = blizzard_update_window_async,
+ .sync = blizzard_sync,
+ .suspend = blizzard_suspend,
+ .resume = blizzard_resume,
+};
+
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
new file mode 100644
index 000000000000..f4c23434de6f
--- /dev/null
+++ b/drivers/video/omap/dispc.c
@@ -0,0 +1,1502 @@
+/*
+ * OMAP2 display controller support
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/arch/sram.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/board.h>
+
+#include "dispc.h"
+
+#define MODULE_NAME "dispc"
+
+#define DSS_BASE 0x48050000
+#define DSS_SYSCONFIG 0x0010
+
+#define DISPC_BASE 0x48050400
+
+/* DISPC common */
+#define DISPC_REVISION 0x0000
+#define DISPC_SYSCONFIG 0x0010
+#define DISPC_SYSSTATUS 0x0014
+#define DISPC_IRQSTATUS 0x0018
+#define DISPC_IRQENABLE 0x001C
+#define DISPC_CONTROL 0x0040
+#define DISPC_CONFIG 0x0044
+#define DISPC_CAPABLE 0x0048
+#define DISPC_DEFAULT_COLOR0 0x004C
+#define DISPC_DEFAULT_COLOR1 0x0050
+#define DISPC_TRANS_COLOR0 0x0054
+#define DISPC_TRANS_COLOR1 0x0058
+#define DISPC_LINE_STATUS 0x005C
+#define DISPC_LINE_NUMBER 0x0060
+#define DISPC_TIMING_H 0x0064
+#define DISPC_TIMING_V 0x0068
+#define DISPC_POL_FREQ 0x006C
+#define DISPC_DIVISOR 0x0070
+#define DISPC_SIZE_DIG 0x0078
+#define DISPC_SIZE_LCD 0x007C
+
+#define DISPC_DATA_CYCLE1 0x01D4
+#define DISPC_DATA_CYCLE2 0x01D8
+#define DISPC_DATA_CYCLE3 0x01DC
+
+/* DISPC GFX plane */
+#define DISPC_GFX_BA0 0x0080
+#define DISPC_GFX_BA1 0x0084
+#define DISPC_GFX_POSITION 0x0088
+#define DISPC_GFX_SIZE 0x008C
+#define DISPC_GFX_ATTRIBUTES 0x00A0
+#define DISPC_GFX_FIFO_THRESHOLD 0x00A4
+#define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8
+#define DISPC_GFX_ROW_INC 0x00AC
+#define DISPC_GFX_PIXEL_INC 0x00B0
+#define DISPC_GFX_WINDOW_SKIP 0x00B4
+#define DISPC_GFX_TABLE_BA 0x00B8
+
+/* DISPC Video plane 1/2 */
+#define DISPC_VID1_BASE 0x00BC
+#define DISPC_VID2_BASE 0x014C
+
+/* Offsets into DISPC_VID1/2_BASE */
+#define DISPC_VID_BA0 0x0000
+#define DISPC_VID_BA1 0x0004
+#define DISPC_VID_POSITION 0x0008
+#define DISPC_VID_SIZE 0x000C
+#define DISPC_VID_ATTRIBUTES 0x0010
+#define DISPC_VID_FIFO_THRESHOLD 0x0014
+#define DISPC_VID_FIFO_SIZE_STATUS 0x0018
+#define DISPC_VID_ROW_INC 0x001C
+#define DISPC_VID_PIXEL_INC 0x0020
+#define DISPC_VID_FIR 0x0024
+#define DISPC_VID_PICTURE_SIZE 0x0028
+#define DISPC_VID_ACCU0 0x002C
+#define DISPC_VID_ACCU1 0x0030
+
+/* 8 elements in 8 byte increments */
+#define DISPC_VID_FIR_COEF_H0 0x0034
+/* 8 elements in 8 byte increments */
+#define DISPC_VID_FIR_COEF_HV0 0x0038
+/* 5 elements in 4 byte increments */
+#define DISPC_VID_CONV_COEF0 0x0074
+
+#define DISPC_IRQ_FRAMEMASK 0x0001
+#define DISPC_IRQ_VSYNC 0x0002
+#define DISPC_IRQ_EVSYNC_EVEN 0x0004
+#define DISPC_IRQ_EVSYNC_ODD 0x0008
+#define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010
+#define DISPC_IRQ_PROG_LINE_NUM 0x0020
+#define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040
+#define DISPC_IRQ_GFX_END_WIN 0x0080
+#define DISPC_IRQ_PAL_GAMMA_MASK 0x0100
+#define DISPC_IRQ_OCP_ERR 0x0200
+#define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400
+#define DISPC_IRQ_VID1_END_WIN 0x0800
+#define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000
+#define DISPC_IRQ_VID2_END_WIN 0x2000
+#define DISPC_IRQ_SYNC_LOST 0x4000
+
+#define DISPC_IRQ_MASK_ALL 0x7fff
+
+#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
+ DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
+ DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
+ DISPC_IRQ_SYNC_LOST)
+
+#define RFBI_CONTROL 0x48050040
+
+#define MAX_PALETTE_SIZE (256 * 16)
+
+#define FLD_MASK(pos, len) (((1 << len) - 1) << pos)
+
+#define MOD_REG_FLD(reg, mask, val) \
+ dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));
+
+#define OMAP2_SRAM_START 0x40200000
+/* Maximum size, in reality this is smaller if SRAM is partially locked. */
+#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
+
+/* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */
+#define DISPC_MEMTYPE_NUM 2
+
+#define RESMAP_SIZE(_page_cnt) \
+ ((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8)
+#define RESMAP_PTR(_res_map, _page_nr) \
+ (((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8))
+#define RESMAP_MASK(_page_nr) \
+ (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1)))
+
+struct resmap {
+ unsigned long start;
+ unsigned page_cnt;
+ unsigned long *map;
+};
+
+static struct {
+ u32 base;
+
+ struct omapfb_mem_desc mem_desc;
+ struct resmap *res_map[DISPC_MEMTYPE_NUM];
+ atomic_t map_count[OMAPFB_PLANE_NUM];
+
+ dma_addr_t palette_paddr;
+ void *palette_vaddr;
+
+ int ext_mode;
+
+ unsigned long enabled_irqs;
+ void (*irq_callback)(void *);
+ void *irq_callback_data;
+ struct completion frame_done;
+
+ int fir_hinc[OMAPFB_PLANE_NUM];
+ int fir_vinc[OMAPFB_PLANE_NUM];
+
+ struct clk *dss_ick, *dss1_fck;
+ struct clk *dss_54m_fck;
+
+ enum omapfb_update_mode update_mode;
+ struct omapfb_device *fbdev;
+
+ struct omapfb_color_key color_key;
+} dispc;
+
+static void enable_lcd_clocks(int enable);
+
+static void inline dispc_write_reg(int idx, u32 val)
+{
+ __raw_writel(val, dispc.base + idx);
+}
+
+static u32 inline dispc_read_reg(int idx)
+{
+ u32 l = __raw_readl(dispc.base + idx);
+ return l;
+}
+
+/* Select RFBI or bypass mode */
+static void enable_rfbi_mode(int enable)
+{
+ u32 l;
+
+ l = dispc_read_reg(DISPC_CONTROL);
+ /* Enable RFBI, GPIO0/1 */
+ l &= ~((1 << 11) | (1 << 15) | (1 << 16));
+ l |= enable ? (1 << 11) : 0;
+ /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */
+ l |= 1 << 15;
+ l |= enable ? 0 : (1 << 16);
+ dispc_write_reg(DISPC_CONTROL, l);
+
+ /* Set bypass mode in RFBI module */
+ l = __raw_readl(io_p2v(RFBI_CONTROL));
+ l |= enable ? 0 : (1 << 1);
+ __raw_writel(l, io_p2v(RFBI_CONTROL));
+}
+
+static void set_lcd_data_lines(int data_lines)
+{
+ u32 l;
+ int code = 0;
+
+ switch (data_lines) {
+ case 12:
+ code = 0;
+ break;
+ case 16:
+ code = 1;
+ break;
+ case 18:
+ code = 2;
+ break;
+ case 24:
+ code = 3;
+ break;
+ default:
+ BUG();
+ }
+
+ l = dispc_read_reg(DISPC_CONTROL);
+ l &= ~(0x03 << 8);
+ l |= code << 8;
+ dispc_write_reg(DISPC_CONTROL, l);
+}
+
+static void set_load_mode(int mode)
+{
+ BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY |
+ DISPC_LOAD_CLUT_ONCE_FRAME));
+ MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);
+}
+
+void omap_dispc_set_lcd_size(int x, int y)
+{
+ BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
+ enable_lcd_clocks(1);
+ MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11),
+ ((y - 1) << 16) | (x - 1));
+ enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_set_lcd_size);
+
+void omap_dispc_set_digit_size(int x, int y)
+{
+ BUG_ON((x > (1 << 11)) || (y > (1 << 11)));
+ enable_lcd_clocks(1);
+ MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11),
+ ((y - 1) << 16) | (x - 1));
+ enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_set_digit_size);
+
+static void setup_plane_fifo(int plane, int ext_mode)
+{
+ const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
+ DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD,
+ DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD };
+ const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
+ DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS,
+ DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS };
+ int low, high;
+ u32 l;
+
+ BUG_ON(plane > 2);
+
+ l = dispc_read_reg(fsz_reg[plane]);
+ l &= FLD_MASK(0, 9);
+ if (ext_mode) {
+ low = l * 3 / 4;
+ high = l;
+ } else {
+ low = l / 4;
+ high = l * 3 / 4;
+ }
+ MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9),
+ (high << 16) | low);
+}
+
+void omap_dispc_enable_lcd_out(int enable)
+{
+ enable_lcd_clocks(1);
+ MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0);
+ enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_enable_lcd_out);
+
+void omap_dispc_enable_digit_out(int enable)
+{
+ enable_lcd_clocks(1);
+ MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0);
+ enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_enable_digit_out);
+
+static inline int _setup_plane(int plane, int channel_out,
+ u32 paddr, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
+ DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+ DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+ const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0,
+ DISPC_VID2_BASE + DISPC_VID_BA0 };
+ const u32 ps_reg[] = { DISPC_GFX_POSITION,
+ DISPC_VID1_BASE + DISPC_VID_POSITION,
+ DISPC_VID2_BASE + DISPC_VID_POSITION };
+ const u32 sz_reg[] = { DISPC_GFX_SIZE,
+ DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE,
+ DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE };
+ const u32 ri_reg[] = { DISPC_GFX_ROW_INC,
+ DISPC_VID1_BASE + DISPC_VID_ROW_INC,
+ DISPC_VID2_BASE + DISPC_VID_ROW_INC };
+ const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
+ DISPC_VID2_BASE + DISPC_VID_SIZE };
+
+ int chout_shift, burst_shift;
+ int chout_val;
+ int color_code;
+ int bpp;
+ int cconv_en;
+ int set_vsize;
+ u32 l;
+
+#ifdef VERBOSE
+ dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d"
+ " pos_x %d pos_y %d width %d height %d color_mode %d\n",
+ plane, channel_out, paddr, screen_width, pos_x, pos_y,
+ width, height, color_mode);
+#endif
+
+ set_vsize = 0;
+ switch (plane) {
+ case OMAPFB_PLANE_GFX:
+ burst_shift = 6;
+ chout_shift = 8;
+ break;
+ case OMAPFB_PLANE_VID1:
+ case OMAPFB_PLANE_VID2:
+ burst_shift = 14;
+ chout_shift = 16;
+ set_vsize = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (channel_out) {
+ case OMAPFB_CHANNEL_OUT_LCD:
+ chout_val = 0;
+ break;
+ case OMAPFB_CHANNEL_OUT_DIGIT:
+ chout_val = 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cconv_en = 0;
+ switch (color_mode) {
+ case OMAPFB_COLOR_RGB565:
+ color_code = DISPC_RGB_16_BPP;
+ bpp = 16;
+ break;
+ case OMAPFB_COLOR_YUV422:
+ if (plane == 0)
+ return -EINVAL;
+ color_code = DISPC_UYVY_422;
+ cconv_en = 1;
+ bpp = 16;
+ break;
+ case OMAPFB_COLOR_YUY422:
+ if (plane == 0)
+ return -EINVAL;
+ color_code = DISPC_YUV2_422;
+ cconv_en = 1;
+ bpp = 16;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ l = dispc_read_reg(at_reg[plane]);
+
+ l &= ~(0x0f << 1);
+ l |= color_code << 1;
+ l &= ~(1 << 9);
+ l |= cconv_en << 9;
+
+ l &= ~(0x03 << burst_shift);
+ l |= DISPC_BURST_8x32 << burst_shift;
+
+ l &= ~(1 << chout_shift);
+ l |= chout_val << chout_shift;
+
+ dispc_write_reg(at_reg[plane], l);
+
+ dispc_write_reg(ba_reg[plane], paddr);
+ MOD_REG_FLD(ps_reg[plane],
+ FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x);
+
+ MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11),
+ ((height - 1) << 16) | (width - 1));
+
+ if (set_vsize) {
+ /* Set video size if set_scale hasn't set it */
+ if (!dispc.fir_vinc[plane])
+ MOD_REG_FLD(vs_reg[plane],
+ FLD_MASK(16, 11), (height - 1) << 16);
+ if (!dispc.fir_hinc[plane])
+ MOD_REG_FLD(vs_reg[plane],
+ FLD_MASK(0, 11), width - 1);
+ }
+
+ dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1);
+
+ return height * screen_width * bpp / 8;
+}
+
+static int omap_dispc_setup_plane(int plane, int channel_out,
+ unsigned long offset,
+ int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ u32 paddr;
+ int r;
+
+ if ((unsigned)plane > dispc.mem_desc.region_cnt)
+ return -EINVAL;
+ paddr = dispc.mem_desc.region[plane].paddr + offset;
+ enable_lcd_clocks(1);
+ r = _setup_plane(plane, channel_out, paddr,
+ screen_width,
+ pos_x, pos_y, width, height, color_mode);
+ enable_lcd_clocks(0);
+ return r;
+}
+
+static void write_firh_reg(int plane, int reg, u32 value)
+{
+ u32 base;
+
+ if (plane == 1)
+ base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0;
+ else
+ base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0;
+ dispc_write_reg(base + reg * 8, value);
+}
+
+static void write_firhv_reg(int plane, int reg, u32 value)
+{
+ u32 base;
+
+ if (plane == 1)
+ base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0;
+ else
+ base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0;
+ dispc_write_reg(base + reg * 8, value);
+}
+
+static void set_upsampling_coef_table(int plane)
+{
+ const u32 coef[][2] = {
+ { 0x00800000, 0x00800000 },
+ { 0x0D7CF800, 0x037B02FF },
+ { 0x1E70F5FF, 0x0C6F05FE },
+ { 0x335FF5FE, 0x205907FB },
+ { 0xF74949F7, 0x00404000 },
+ { 0xF55F33FB, 0x075920FE },
+ { 0xF5701EFE, 0x056F0CFF },
+ { 0xF87C0DFF, 0x027B0300 },
+ };
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ write_firh_reg(plane, i, coef[i][0]);
+ write_firhv_reg(plane, i, coef[i][1]);
+ }
+}
+
+static int omap_dispc_set_scale(int plane,
+ int orig_width, int orig_height,
+ int out_width, int out_height)
+{
+ const u32 at_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+ DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+ const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE,
+ DISPC_VID2_BASE + DISPC_VID_SIZE };
+ const u32 fir_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_FIR,
+ DISPC_VID2_BASE + DISPC_VID_FIR };
+
+ u32 l;
+ int fir_hinc;
+ int fir_vinc;
+
+ if ((unsigned)plane > OMAPFB_PLANE_NUM)
+ return -ENODEV;
+
+ if (plane == OMAPFB_PLANE_GFX &&
+ (out_width != orig_width || out_height != orig_height))
+ return -EINVAL;
+
+ enable_lcd_clocks(1);
+ if (orig_width < out_width) {
+ /*
+ * Upsampling.
+ * Currently you can only scale both dimensions in one way.
+ */
+ if (orig_height > out_height ||
+ orig_width * 8 < out_width ||
+ orig_height * 8 < out_height) {
+ enable_lcd_clocks(0);
+ return -EINVAL;
+ }
+ set_upsampling_coef_table(plane);
+ } else if (orig_width > out_width) {
+ /* Downsampling not yet supported
+ */
+
+ enable_lcd_clocks(0);
+ return -EINVAL;
+ }
+ if (!orig_width || orig_width == out_width)
+ fir_hinc = 0;
+ else
+ fir_hinc = 1024 * orig_width / out_width;
+ if (!orig_height || orig_height == out_height)
+ fir_vinc = 0;
+ else
+ fir_vinc = 1024 * orig_height / out_height;
+ dispc.fir_hinc[plane] = fir_hinc;
+ dispc.fir_vinc[plane] = fir_vinc;
+
+ MOD_REG_FLD(fir_reg[plane],
+ FLD_MASK(16, 12) | FLD_MASK(0, 12),
+ ((fir_vinc & 4095) << 16) |
+ (fir_hinc & 4095));
+
+ dev_dbg(dispc.fbdev->dev, "out_width %d out_height %d orig_width %d "
+ "orig_height %d fir_hinc %d fir_vinc %d\n",
+ out_width, out_height, orig_width, orig_height,
+ fir_hinc, fir_vinc);
+
+ MOD_REG_FLD(vs_reg[plane],
+ FLD_MASK(16, 11) | FLD_MASK(0, 11),
+ ((out_height - 1) << 16) | (out_width - 1));
+
+ l = dispc_read_reg(at_reg[plane]);
+ l &= ~(0x03 << 5);
+ l |= fir_hinc ? (1 << 5) : 0;
+ l |= fir_vinc ? (1 << 6) : 0;
+ dispc_write_reg(at_reg[plane], l);
+
+ enable_lcd_clocks(0);
+ return 0;
+}
+
+static int omap_dispc_enable_plane(int plane, int enable)
+{
+ const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES,
+ DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES,
+ DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES };
+ if ((unsigned int)plane > dispc.mem_desc.region_cnt)
+ return -EINVAL;
+
+ enable_lcd_clocks(1);
+ MOD_REG_FLD(at_reg[plane], 1, enable ? 1 : 0);
+ enable_lcd_clocks(0);
+
+ return 0;
+}
+
+static int omap_dispc_set_color_key(struct omapfb_color_key *ck)
+{
+ u32 df_reg, tr_reg;
+ int shift, val;
+
+ switch (ck->channel_out) {
+ case OMAPFB_CHANNEL_OUT_LCD:
+ df_reg = DISPC_DEFAULT_COLOR0;
+ tr_reg = DISPC_TRANS_COLOR0;
+ shift = 10;
+ break;
+ case OMAPFB_CHANNEL_OUT_DIGIT:
+ df_reg = DISPC_DEFAULT_COLOR1;
+ tr_reg = DISPC_TRANS_COLOR1;
+ shift = 12;
+ break;
+ default:
+ return -EINVAL;
+ }
+ switch (ck->key_type) {
+ case OMAPFB_COLOR_KEY_DISABLED:
+ val = 0;
+ break;
+ case OMAPFB_COLOR_KEY_GFX_DST:
+ val = 1;
+ break;
+ case OMAPFB_COLOR_KEY_VID_SRC:
+ val = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ enable_lcd_clocks(1);
+ MOD_REG_FLD(DISPC_CONFIG, FLD_MASK(shift, 2), val << shift);
+
+ if (val != 0)
+ dispc_write_reg(tr_reg, ck->trans_key);
+ dispc_write_reg(df_reg, ck->background);
+ enable_lcd_clocks(0);
+
+ dispc.color_key = *ck;
+
+ return 0;
+}
+
+static int omap_dispc_get_color_key(struct omapfb_color_key *ck)
+{
+ *ck = dispc.color_key;
+ return 0;
+}
+
+static void load_palette(void)
+{
+}
+
+static int omap_dispc_set_update_mode(enum omapfb_update_mode mode)
+{
+ int r = 0;
+
+ if (mode != dispc.update_mode) {
+ switch (mode) {
+ case OMAPFB_AUTO_UPDATE:
+ case OMAPFB_MANUAL_UPDATE:
+ enable_lcd_clocks(1);
+ omap_dispc_enable_lcd_out(1);
+ dispc.update_mode = mode;
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ init_completion(&dispc.frame_done);
+ omap_dispc_enable_lcd_out(0);
+ if (!wait_for_completion_timeout(&dispc.frame_done,
+ msecs_to_jiffies(500))) {
+ dev_err(dispc.fbdev->dev,
+ "timeout waiting for FRAME DONE\n");
+ }
+ dispc.update_mode = mode;
+ enable_lcd_clocks(0);
+ break;
+ default:
+ r = -EINVAL;
+ }
+ }
+
+ return r;
+}
+
+static void omap_dispc_get_caps(int plane, struct omapfb_caps *caps)
+{
+ caps->ctrl |= OMAPFB_CAPS_PLANE_RELOCATE_MEM;
+ if (plane > 0)
+ caps->ctrl |= OMAPFB_CAPS_PLANE_SCALE;
+ caps->plane_color |= (1 << OMAPFB_COLOR_RGB565) |
+ (1 << OMAPFB_COLOR_YUV422) |
+ (1 << OMAPFB_COLOR_YUY422);
+ if (plane == 0)
+ caps->plane_color |= (1 << OMAPFB_COLOR_CLUT_8BPP) |
+ (1 << OMAPFB_COLOR_CLUT_4BPP) |
+ (1 << OMAPFB_COLOR_CLUT_2BPP) |
+ (1 << OMAPFB_COLOR_CLUT_1BPP) |
+ (1 << OMAPFB_COLOR_RGB444);
+}
+
+static enum omapfb_update_mode omap_dispc_get_update_mode(void)
+{
+ return dispc.update_mode;
+}
+
+static void setup_color_conv_coef(void)
+{
+ u32 mask = FLD_MASK(16, 11) | FLD_MASK(0, 11);
+ int cf1_reg = DISPC_VID1_BASE + DISPC_VID_CONV_COEF0;
+ int cf2_reg = DISPC_VID2_BASE + DISPC_VID_CONV_COEF0;
+ int at1_reg = DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES;
+ int at2_reg = DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES;
+ const struct color_conv_coef {
+ int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
+ int full_range;
+ } ctbl_bt601_5 = {
+ 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
+ };
+ const struct color_conv_coef *ct;
+#define CVAL(x, y) (((x & 2047) << 16) | (y & 2047))
+
+ ct = &ctbl_bt601_5;
+
+ MOD_REG_FLD(cf1_reg, mask, CVAL(ct->rcr, ct->ry));
+ MOD_REG_FLD(cf1_reg + 4, mask, CVAL(ct->gy, ct->rcb));
+ MOD_REG_FLD(cf1_reg + 8, mask, CVAL(ct->gcb, ct->gcr));
+ MOD_REG_FLD(cf1_reg + 12, mask, CVAL(ct->bcr, ct->by));
+ MOD_REG_FLD(cf1_reg + 16, mask, CVAL(0, ct->bcb));
+
+ MOD_REG_FLD(cf2_reg, mask, CVAL(ct->rcr, ct->ry));
+ MOD_REG_FLD(cf2_reg + 4, mask, CVAL(ct->gy, ct->rcb));
+ MOD_REG_FLD(cf2_reg + 8, mask, CVAL(ct->gcb, ct->gcr));
+ MOD_REG_FLD(cf2_reg + 12, mask, CVAL(ct->bcr, ct->by));
+ MOD_REG_FLD(cf2_reg + 16, mask, CVAL(0, ct->bcb));
+#undef CVAL
+
+ MOD_REG_FLD(at1_reg, (1 << 11), ct->full_range);
+ MOD_REG_FLD(at2_reg, (1 << 11), ct->full_range);
+}
+
+static void calc_ck_div(int is_tft, int pck, int *lck_div, int *pck_div)
+{
+ unsigned long fck, lck;
+
+ *lck_div = 1;
+ pck = max(1, pck);
+ fck = clk_get_rate(dispc.dss1_fck);
+ lck = fck;
+ *pck_div = (lck + pck - 1) / pck;
+ if (is_tft)
+ *pck_div = max(2, *pck_div);
+ else
+ *pck_div = max(3, *pck_div);
+ if (*pck_div > 255) {
+ *pck_div = 255;
+ lck = pck * *pck_div;
+ *lck_div = fck / lck;
+ BUG_ON(*lck_div < 1);
+ if (*lck_div > 255) {
+ *lck_div = 255;
+ dev_warn(dispc.fbdev->dev, "pixclock %d kHz too low.\n",
+ pck / 1000);
+ }
+ }
+}
+
+static void set_lcd_tft_mode(int enable)
+{
+ u32 mask;
+
+ mask = 1 << 3;
+ MOD_REG_FLD(DISPC_CONTROL, mask, enable ? mask : 0);
+}
+
+static void set_lcd_timings(void)
+{
+ u32 l;
+ int lck_div, pck_div;
+ struct lcd_panel *panel = dispc.fbdev->panel;
+ int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
+ unsigned long fck;
+
+ l = dispc_read_reg(DISPC_TIMING_H);
+ l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
+ l |= ( max(1, (min(64, panel->hsw))) - 1 ) << 0;
+ l |= ( max(1, (min(256, panel->hfp))) - 1 ) << 8;
+ l |= ( max(1, (min(256, panel->hbp))) - 1 ) << 20;
+ dispc_write_reg(DISPC_TIMING_H, l);
+
+ l = dispc_read_reg(DISPC_TIMING_V);
+ l &= ~(FLD_MASK(0, 6) | FLD_MASK(8, 8) | FLD_MASK(20, 8));
+ l |= ( max(1, (min(64, panel->vsw))) - 1 ) << 0;
+ l |= ( max(0, (min(255, panel->vfp))) - 0 ) << 8;
+ l |= ( max(0, (min(255, panel->vbp))) - 0 ) << 20;
+ dispc_write_reg(DISPC_TIMING_V, l);
+
+ l = dispc_read_reg(DISPC_POL_FREQ);
+ l &= ~FLD_MASK(12, 6);
+ l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 12;
+ l |= panel->acb & 0xff;
+ dispc_write_reg(DISPC_POL_FREQ, l);
+
+ calc_ck_div(is_tft, panel->pixel_clock * 1000, &lck_div, &pck_div);
+
+ l = dispc_read_reg(DISPC_DIVISOR);
+ l &= ~(FLD_MASK(16, 8) | FLD_MASK(0, 8));
+ l |= (lck_div << 16) | (pck_div << 0);
+ dispc_write_reg(DISPC_DIVISOR, l);
+
+ /* update panel info with the exact clock */
+ fck = clk_get_rate(dispc.dss1_fck);
+ panel->pixel_clock = fck / lck_div / pck_div / 1000;
+}
+
+int omap_dispc_request_irq(void (*callback)(void *data), void *data)
+{
+ int r = 0;
+
+ BUG_ON(callback == NULL);
+
+ if (dispc.irq_callback)
+ r = -EBUSY;
+ else {
+ dispc.irq_callback = callback;
+ dispc.irq_callback_data = data;
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(omap_dispc_request_irq);
+
+void omap_dispc_enable_irqs(int irq_mask)
+{
+ enable_lcd_clocks(1);
+ dispc.enabled_irqs = irq_mask;
+ irq_mask |= DISPC_IRQ_MASK_ERROR;
+ MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
+ enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_enable_irqs);
+
+void omap_dispc_disable_irqs(int irq_mask)
+{
+ enable_lcd_clocks(1);
+ dispc.enabled_irqs &= ~irq_mask;
+ irq_mask &= ~DISPC_IRQ_MASK_ERROR;
+ MOD_REG_FLD(DISPC_IRQENABLE, 0x7fff, irq_mask);
+ enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_disable_irqs);
+
+void omap_dispc_free_irq(void)
+{
+ enable_lcd_clocks(1);
+ omap_dispc_disable_irqs(DISPC_IRQ_MASK_ALL);
+ dispc.irq_callback = NULL;
+ dispc.irq_callback_data = NULL;
+ enable_lcd_clocks(0);
+}
+EXPORT_SYMBOL(omap_dispc_free_irq);
+
+static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
+{
+ u32 stat = dispc_read_reg(DISPC_IRQSTATUS);
+
+ if (stat & DISPC_IRQ_FRAMEMASK)
+ complete(&dispc.frame_done);
+
+ if (stat & DISPC_IRQ_MASK_ERROR) {
+ if (printk_ratelimit()) {
+ dev_err(dispc.fbdev->dev, "irq error status %04x\n",
+ stat & 0x7fff);
+ }
+ }
+
+ if ((stat & dispc.enabled_irqs) && dispc.irq_callback)
+ dispc.irq_callback(dispc.irq_callback_data);
+
+ dispc_write_reg(DISPC_IRQSTATUS, stat);
+
+ return IRQ_HANDLED;
+}
+
+static int get_dss_clocks(void)
+{
+ if (IS_ERR((dispc.dss_ick = clk_get(dispc.fbdev->dev, "dss_ick")))) {
+ dev_err(dispc.fbdev->dev, "can't get dss_ick");
+ return PTR_ERR(dispc.dss_ick);
+ }
+
+ if (IS_ERR((dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck")))) {
+ dev_err(dispc.fbdev->dev, "can't get dss1_fck");
+ clk_put(dispc.dss_ick);
+ return PTR_ERR(dispc.dss1_fck);
+ }
+
+ if (IS_ERR((dispc.dss_54m_fck =
+ clk_get(dispc.fbdev->dev, "dss_54m_fck")))) {
+ dev_err(dispc.fbdev->dev, "can't get dss_54m_fck");
+ clk_put(dispc.dss_ick);
+ clk_put(dispc.dss1_fck);
+ return PTR_ERR(dispc.dss_54m_fck);
+ }
+
+ return 0;
+}
+
+static void put_dss_clocks(void)
+{
+ clk_put(dispc.dss_54m_fck);
+ clk_put(dispc.dss1_fck);
+ clk_put(dispc.dss_ick);
+}
+
+static void enable_lcd_clocks(int enable)
+{
+ if (enable)
+ clk_enable(dispc.dss1_fck);
+ else
+ clk_disable(dispc.dss1_fck);
+}
+
+static void enable_interface_clocks(int enable)
+{
+ if (enable)
+ clk_enable(dispc.dss_ick);
+ else
+ clk_disable(dispc.dss_ick);
+}
+
+static void enable_digit_clocks(int enable)
+{
+ if (enable)
+ clk_enable(dispc.dss_54m_fck);
+ else
+ clk_disable(dispc.dss_54m_fck);
+}
+
+static void omap_dispc_suspend(void)
+{
+ if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
+ init_completion(&dispc.frame_done);
+ omap_dispc_enable_lcd_out(0);
+ if (!wait_for_completion_timeout(&dispc.frame_done,
+ msecs_to_jiffies(500))) {
+ dev_err(dispc.fbdev->dev,
+ "timeout waiting for FRAME DONE\n");
+ }
+ enable_lcd_clocks(0);
+ }
+}
+
+static void omap_dispc_resume(void)
+{
+ if (dispc.update_mode == OMAPFB_AUTO_UPDATE) {
+ enable_lcd_clocks(1);
+ if (!dispc.ext_mode) {
+ set_lcd_timings();
+ load_palette();
+ }
+ omap_dispc_enable_lcd_out(1);
+ }
+}
+
+
+static int omap_dispc_update_window(struct fb_info *fbi,
+ struct omapfb_update_window *win,
+ void (*complete_callback)(void *arg),
+ void *complete_callback_data)
+{
+ return dispc.update_mode == OMAPFB_UPDATE_DISABLED ? -ENODEV : 0;
+}
+
+static int mmap_kern(struct omapfb_mem_region *region)
+{
+ struct vm_struct *kvma;
+ struct vm_area_struct vma;
+ pgprot_t pgprot;
+ unsigned long vaddr;
+
+ kvma = get_vm_area(region->size, VM_IOREMAP);
+ if (kvma == NULL) {
+ dev_err(dispc.fbdev->dev, "can't get kernel vm area\n");
+ return -ENOMEM;
+ }
+ vma.vm_mm = &init_mm;
+
+ vaddr = (unsigned long)kvma->addr;
+
+ pgprot = pgprot_writecombine(pgprot_kernel);
+ vma.vm_start = vaddr;
+ vma.vm_end = vaddr + region->size;
+ if (io_remap_pfn_range(&vma, vaddr, region->paddr >> PAGE_SHIFT,
+ region->size, pgprot) < 0) {
+ dev_err(dispc.fbdev->dev, "kernel mmap for FBMEM failed\n");
+ return -EAGAIN;
+ }
+ region->vaddr = (void *)vaddr;
+
+ return 0;
+}
+
+static void mmap_user_open(struct vm_area_struct *vma)
+{
+ int plane = (int)vma->vm_private_data;
+
+ atomic_inc(&dispc.map_count[plane]);
+}
+
+static void mmap_user_close(struct vm_area_struct *vma)
+{
+ int plane = (int)vma->vm_private_data;
+
+ atomic_dec(&dispc.map_count[plane]);
+}
+
+static struct vm_operations_struct mmap_user_ops = {
+ .open = mmap_user_open,
+ .close = mmap_user_close,
+};
+
+static int omap_dispc_mmap_user(struct fb_info *info,
+ struct vm_area_struct *vma)
+{
+ struct omapfb_plane_struct *plane = info->par;
+ unsigned long off;
+ unsigned long start;
+ u32 len;
+
+ if (vma->vm_end - vma->vm_start == 0)
+ return 0;
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ start = info->fix.smem_start;
+ len = info->fix.smem_len;
+ if (off >= len)
+ return -EINVAL;
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ vma->vm_ops = &mmap_user_ops;
+ vma->vm_private_data = (void *)plane->idx;
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+ /* vm_ops.open won't be called for mmap itself. */
+ atomic_inc(&dispc.map_count[plane->idx]);
+ return 0;
+}
+
+static void unmap_kern(struct omapfb_mem_region *region)
+{
+ vunmap(region->vaddr);
+}
+
+static int alloc_palette_ram(void)
+{
+ dispc.palette_vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+ MAX_PALETTE_SIZE, &dispc.palette_paddr, GFP_KERNEL);
+ if (dispc.palette_vaddr == NULL) {
+ dev_err(dispc.fbdev->dev, "failed to alloc palette memory\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void free_palette_ram(void)
+{
+ dma_free_writecombine(dispc.fbdev->dev, MAX_PALETTE_SIZE,
+ dispc.palette_vaddr, dispc.palette_paddr);
+}
+
+static int alloc_fbmem(struct omapfb_mem_region *region)
+{
+ region->vaddr = dma_alloc_writecombine(dispc.fbdev->dev,
+ region->size, &region->paddr, GFP_KERNEL);
+
+ if (region->vaddr == NULL) {
+ dev_err(dispc.fbdev->dev, "unable to allocate FB DMA memory\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void free_fbmem(struct omapfb_mem_region *region)
+{
+ dma_free_writecombine(dispc.fbdev->dev, region->size,
+ region->vaddr, region->paddr);
+}
+
+static struct resmap *init_resmap(unsigned long start, size_t size)
+{
+ unsigned page_cnt;
+ struct resmap *res_map;
+
+ page_cnt = PAGE_ALIGN(size) / PAGE_SIZE;
+ res_map =
+ kzalloc(sizeof(struct resmap) + RESMAP_SIZE(page_cnt), GFP_KERNEL);
+ if (res_map == NULL)
+ return NULL;
+ res_map->start = start;
+ res_map->page_cnt = page_cnt;
+ res_map->map = (unsigned long *)(res_map + 1);
+ return res_map;
+}
+
+static void cleanup_resmap(struct resmap *res_map)
+{
+ kfree(res_map);
+}
+
+static inline int resmap_mem_type(unsigned long start)
+{
+ if (start >= OMAP2_SRAM_START &&
+ start < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
+ return OMAPFB_MEMTYPE_SRAM;
+ else
+ return OMAPFB_MEMTYPE_SDRAM;
+}
+
+static inline int resmap_page_reserved(struct resmap *res_map, unsigned page_nr)
+{
+ return *RESMAP_PTR(res_map, page_nr) & RESMAP_MASK(page_nr) ? 1 : 0;
+}
+
+static inline void resmap_reserve_page(struct resmap *res_map, unsigned page_nr)
+{
+ BUG_ON(resmap_page_reserved(res_map, page_nr));
+ *RESMAP_PTR(res_map, page_nr) |= RESMAP_MASK(page_nr);
+}
+
+static inline void resmap_free_page(struct resmap *res_map, unsigned page_nr)
+{
+ BUG_ON(!resmap_page_reserved(res_map, page_nr));
+ *RESMAP_PTR(res_map, page_nr) &= ~RESMAP_MASK(page_nr);
+}
+
+static void resmap_reserve_region(unsigned long start, size_t size)
+{
+
+ struct resmap *res_map;
+ unsigned start_page;
+ unsigned end_page;
+ int mtype;
+ unsigned i;
+
+ mtype = resmap_mem_type(start);
+ res_map = dispc.res_map[mtype];
+ dev_dbg(dispc.fbdev->dev, "reserve mem type %d start %08lx size %d\n",
+ mtype, start, size);
+ start_page = (start - res_map->start) / PAGE_SIZE;
+ end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
+ for (i = start_page; i < end_page; i++)
+ resmap_reserve_page(res_map, i);
+}
+
+static void resmap_free_region(unsigned long start, size_t size)
+{
+ struct resmap *res_map;
+ unsigned start_page;
+ unsigned end_page;
+ unsigned i;
+ int mtype;
+
+ mtype = resmap_mem_type(start);
+ res_map = dispc.res_map[mtype];
+ dev_dbg(dispc.fbdev->dev, "free mem type %d start %08lx size %d\n",
+ mtype, start, size);
+ start_page = (start - res_map->start) / PAGE_SIZE;
+ end_page = start_page + PAGE_ALIGN(size) / PAGE_SIZE;
+ for (i = start_page; i < end_page; i++)
+ resmap_free_page(res_map, i);
+}
+
+static unsigned long resmap_alloc_region(int mtype, size_t size)
+{
+ unsigned i;
+ unsigned total;
+ unsigned start_page;
+ unsigned long start;
+ struct resmap *res_map = dispc.res_map[mtype];
+
+ BUG_ON(mtype >= DISPC_MEMTYPE_NUM || res_map == NULL || !size);
+
+ size = PAGE_ALIGN(size) / PAGE_SIZE;
+ start_page = 0;
+ total = 0;
+ for (i = 0; i < res_map->page_cnt; i++) {
+ if (resmap_page_reserved(res_map, i)) {
+ start_page = i + 1;
+ total = 0;
+ } else if (++total == size)
+ break;
+ }
+ if (total < size)
+ return 0;
+
+ start = res_map->start + start_page * PAGE_SIZE;
+ resmap_reserve_region(start, size * PAGE_SIZE);
+
+ return start;
+}
+
+/* Note that this will only work for user mappings, we don't deal with
+ * kernel mappings here, so fbcon will keep using the old region.
+ */
+static int omap_dispc_setup_mem(int plane, size_t size, int mem_type,
+ unsigned long *paddr)
+{
+ struct omapfb_mem_region *rg;
+ unsigned long new_addr = 0;
+
+ if ((unsigned)plane > dispc.mem_desc.region_cnt)
+ return -EINVAL;
+ if (mem_type >= DISPC_MEMTYPE_NUM)
+ return -EINVAL;
+ if (dispc.res_map[mem_type] == NULL)
+ return -ENOMEM;
+ rg = &dispc.mem_desc.region[plane];
+ if (size == rg->size && mem_type == rg->type)
+ return 0;
+ if (atomic_read(&dispc.map_count[plane]))
+ return -EBUSY;
+ if (rg->size != 0)
+ resmap_free_region(rg->paddr, rg->size);
+ if (size != 0) {
+ new_addr = resmap_alloc_region(mem_type, size);
+ if (!new_addr) {
+ /* Reallocate old region. */
+ resmap_reserve_region(rg->paddr, rg->size);
+ return -ENOMEM;
+ }
+ }
+ rg->paddr = new_addr;
+ rg->size = size;
+ rg->type = mem_type;
+
+ *paddr = new_addr;
+
+ return 0;
+}
+
+static int setup_fbmem(struct omapfb_mem_desc *req_md)
+{
+ struct omapfb_mem_region *rg;
+ int i;
+ int r;
+ unsigned long mem_start[DISPC_MEMTYPE_NUM];
+ unsigned long mem_end[DISPC_MEMTYPE_NUM];
+
+ if (!req_md->region_cnt) {
+ dev_err(dispc.fbdev->dev, "no memory regions defined\n");
+ return -ENOENT;
+ }
+
+ rg = &req_md->region[0];
+ memset(mem_start, 0xff, sizeof(mem_start));
+ memset(mem_end, 0, sizeof(mem_end));
+
+ for (i = 0; i < req_md->region_cnt; i++, rg++) {
+ int mtype;
+ if (rg->paddr) {
+ rg->alloc = 0;
+ if (rg->vaddr == NULL) {
+ rg->map = 1;
+ if ((r = mmap_kern(rg)) < 0)
+ return r;
+ }
+ } else {
+ if (rg->type != OMAPFB_MEMTYPE_SDRAM) {
+ dev_err(dispc.fbdev->dev,
+ "unsupported memory type\n");
+ return -EINVAL;
+ }
+ rg->alloc = rg->map = 1;
+ if ((r = alloc_fbmem(rg)) < 0)
+ return r;
+ }
+ mtype = rg->type;
+
+ if (rg->paddr < mem_start[mtype])
+ mem_start[mtype] = rg->paddr;
+ if (rg->paddr + rg->size > mem_end[mtype])
+ mem_end[mtype] = rg->paddr + rg->size;
+ }
+
+ for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
+ unsigned long start;
+ size_t size;
+ if (mem_end[i] == 0)
+ continue;
+ start = mem_start[i];
+ size = mem_end[i] - start;
+ dispc.res_map[i] = init_resmap(start, size);
+ r = -ENOMEM;
+ if (dispc.res_map[i] == NULL)
+ goto fail;
+ /* Initial state is that everything is reserved. This
+ * includes possible holes as well, which will never be
+ * freed.
+ */
+ resmap_reserve_region(start, size);
+ }
+
+ dispc.mem_desc = *req_md;
+
+ return 0;
+fail:
+ for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
+ if (dispc.res_map[i] != NULL)
+ cleanup_resmap(dispc.res_map[i]);
+ }
+ return r;
+}
+
+static void cleanup_fbmem(void)
+{
+ struct omapfb_mem_region *rg;
+ int i;
+
+ for (i = 0; i < DISPC_MEMTYPE_NUM; i++) {
+ if (dispc.res_map[i] != NULL)
+ cleanup_resmap(dispc.res_map[i]);
+ }
+ rg = &dispc.mem_desc.region[0];
+ for (i = 0; i < dispc.mem_desc.region_cnt; i++, rg++) {
+ if (rg->alloc)
+ free_fbmem(rg);
+ else {
+ if (rg->map)
+ unmap_kern(rg);
+ }
+ }
+}
+
+static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
+ struct omapfb_mem_desc *req_vram)
+{
+ int r;
+ u32 l;
+ struct lcd_panel *panel = fbdev->panel;
+ int tmo = 10000;
+ int skip_init = 0;
+ int i;
+
+ memset(&dispc, 0, sizeof(dispc));
+
+ dispc.base = io_p2v(DISPC_BASE);
+ dispc.fbdev = fbdev;
+ dispc.ext_mode = ext_mode;
+
+ init_completion(&dispc.frame_done);
+
+ if ((r = get_dss_clocks()) < 0)
+ return r;
+
+ enable_interface_clocks(1);
+ enable_lcd_clocks(1);
+
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+ l = dispc_read_reg(DISPC_CONTROL);
+ /* LCD enabled ? */
+ if (l & 1) {
+ pr_info("omapfb: skipping hardware initialization\n");
+ skip_init = 1;
+ }
+#endif
+
+ if (!skip_init) {
+ /* Reset monitoring works only w/ the 54M clk */
+ enable_digit_clocks(1);
+
+ /* Soft reset */
+ MOD_REG_FLD(DISPC_SYSCONFIG, 1 << 1, 1 << 1);
+
+ while (!(dispc_read_reg(DISPC_SYSSTATUS) & 1)) {
+ if (!--tmo) {
+ dev_err(dispc.fbdev->dev, "soft reset failed\n");
+ r = -ENODEV;
+ enable_digit_clocks(0);
+ goto fail1;
+ }
+ }
+
+ enable_digit_clocks(0);
+ }
+
+ /* Enable smart idle and autoidle */
+ l = dispc_read_reg(DISPC_CONTROL);
+ l &= ~((3 << 12) | (3 << 3));
+ l |= (2 << 12) | (2 << 3) | (1 << 0);
+ dispc_write_reg(DISPC_SYSCONFIG, l);
+ omap_writel(1 << 0, DSS_BASE + DSS_SYSCONFIG);
+
+ /* Set functional clock autogating */
+ l = dispc_read_reg(DISPC_CONFIG);
+ l |= 1 << 9;
+ dispc_write_reg(DISPC_CONFIG, l);
+
+ l = dispc_read_reg(DISPC_IRQSTATUS);
+ dispc_write_reg(l, DISPC_IRQSTATUS);
+
+ /* Enable those that we handle always */
+ omap_dispc_enable_irqs(DISPC_IRQ_FRAMEMASK);
+
+ if ((r = request_irq(INT_24XX_DSS_IRQ, omap_dispc_irq_handler,
+ 0, MODULE_NAME, fbdev)) < 0) {
+ dev_err(dispc.fbdev->dev, "can't get DSS IRQ\n");
+ goto fail1;
+ }
+
+ /* L3 firewall setting: enable access to OCM RAM */
+ __raw_writel(0x402000b0, io_p2v(0x680050a0));
+
+ if ((r = alloc_palette_ram()) < 0)
+ goto fail2;
+
+ if ((r = setup_fbmem(req_vram)) < 0)
+ goto fail3;
+
+ if (!skip_init) {
+ for (i = 0; i < dispc.mem_desc.region_cnt; i++) {
+ memset(dispc.mem_desc.region[i].vaddr, 0,
+ dispc.mem_desc.region[i].size);
+ }
+
+ /* Set logic clock to fck, pixel clock to fck/2 for now */
+ MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(16, 8), 1 << 16);
+ MOD_REG_FLD(DISPC_DIVISOR, FLD_MASK(0, 8), 2 << 0);
+
+ setup_plane_fifo(0, ext_mode);
+ setup_plane_fifo(1, ext_mode);
+ setup_plane_fifo(2, ext_mode);
+
+ setup_color_conv_coef();
+
+ set_lcd_tft_mode(panel->config & OMAP_LCDC_PANEL_TFT);
+ set_load_mode(DISPC_LOAD_FRAME_ONLY);
+
+ if (!ext_mode) {
+ set_lcd_data_lines(panel->data_lines);
+ omap_dispc_set_lcd_size(panel->x_res, panel->y_res);
+ set_lcd_timings();
+ } else
+ set_lcd_data_lines(panel->bpp);
+ enable_rfbi_mode(ext_mode);
+ }
+
+ l = dispc_read_reg(DISPC_REVISION);
+ pr_info("omapfb: DISPC version %d.%d initialized\n",
+ l >> 4 & 0x0f, l & 0x0f);
+ enable_lcd_clocks(0);
+
+ return 0;
+fail3:
+ free_palette_ram();
+fail2:
+ free_irq(INT_24XX_DSS_IRQ, fbdev);
+fail1:
+ enable_lcd_clocks(0);
+ enable_interface_clocks(0);
+ put_dss_clocks();
+
+ return r;
+}
+
+static void omap_dispc_cleanup(void)
+{
+ int i;
+
+ omap_dispc_set_update_mode(OMAPFB_UPDATE_DISABLED);
+ /* This will also disable clocks that are on */
+ for (i = 0; i < dispc.mem_desc.region_cnt; i++)
+ omap_dispc_enable_plane(i, 0);
+ cleanup_fbmem();
+ free_palette_ram();
+ free_irq(INT_24XX_DSS_IRQ, dispc.fbdev);
+ enable_interface_clocks(0);
+ put_dss_clocks();
+}
+
+const struct lcd_ctrl omap2_int_ctrl = {
+ .name = "internal",
+ .init = omap_dispc_init,
+ .cleanup = omap_dispc_cleanup,
+ .get_caps = omap_dispc_get_caps,
+ .set_update_mode = omap_dispc_set_update_mode,
+ .get_update_mode = omap_dispc_get_update_mode,
+ .update_window = omap_dispc_update_window,
+ .suspend = omap_dispc_suspend,
+ .resume = omap_dispc_resume,
+ .setup_plane = omap_dispc_setup_plane,
+ .setup_mem = omap_dispc_setup_mem,
+ .set_scale = omap_dispc_set_scale,
+ .enable_plane = omap_dispc_enable_plane,
+ .set_color_key = omap_dispc_set_color_key,
+ .get_color_key = omap_dispc_get_color_key,
+ .mmap = omap_dispc_mmap_user,
+};
diff --git a/drivers/video/omap/dispc.h b/drivers/video/omap/dispc.h
new file mode 100644
index 000000000000..eb1512b56ce8
--- /dev/null
+++ b/drivers/video/omap/dispc.h
@@ -0,0 +1,43 @@
+#ifndef _DISPC_H
+#define _DISPC_H
+
+#include <linux/interrupt.h>
+
+#define DISPC_PLANE_GFX 0
+#define DISPC_PLANE_VID1 1
+#define DISPC_PLANE_VID2 2
+
+#define DISPC_RGB_1_BPP 0x00
+#define DISPC_RGB_2_BPP 0x01
+#define DISPC_RGB_4_BPP 0x02
+#define DISPC_RGB_8_BPP 0x03
+#define DISPC_RGB_12_BPP 0x04
+#define DISPC_RGB_16_BPP 0x06
+#define DISPC_RGB_24_BPP 0x08
+#define DISPC_RGB_24_BPP_UNPACK_32 0x09
+#define DISPC_YUV2_422 0x0a
+#define DISPC_UYVY_422 0x0b
+
+#define DISPC_BURST_4x32 0
+#define DISPC_BURST_8x32 1
+#define DISPC_BURST_16x32 2
+
+#define DISPC_LOAD_CLUT_AND_FRAME 0x00
+#define DISPC_LOAD_CLUT_ONLY 0x01
+#define DISPC_LOAD_FRAME_ONLY 0x02
+#define DISPC_LOAD_CLUT_ONCE_FRAME 0x03
+
+#define DISPC_TFT_DATA_LINES_12 0
+#define DISPC_TFT_DATA_LINES_16 1
+#define DISPC_TFT_DATA_LINES_18 2
+#define DISPC_TFT_DATA_LINES_24 3
+
+extern void omap_dispc_set_lcd_size(int width, int height);
+
+extern void omap_dispc_enable_lcd_out(int enable);
+extern void omap_dispc_enable_digit_out(int enable);
+
+extern int omap_dispc_request_irq(void (*callback)(void *data), void *data);
+extern void omap_dispc_free_irq(void);
+
+#endif
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
new file mode 100644
index 000000000000..dc48e02f215c
--- /dev/null
+++ b/drivers/video/omap/hwa742.c
@@ -0,0 +1,1077 @@
+/*
+ * Epson HWA742 LCD controller driver
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Authors: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Imre Deak <imre.deak@nokia.com>
+ * YUV support: Jussi Laako <jussi.laako@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/hwa742.h>
+
+#define HWA742_REV_CODE_REG 0x0
+#define HWA742_CONFIG_REG 0x2
+#define HWA742_PLL_DIV_REG 0x4
+#define HWA742_PLL_0_REG 0x6
+#define HWA742_PLL_1_REG 0x8
+#define HWA742_PLL_2_REG 0xa
+#define HWA742_PLL_3_REG 0xc
+#define HWA742_PLL_4_REG 0xe
+#define HWA742_CLK_SRC_REG 0x12
+#define HWA742_PANEL_TYPE_REG 0x14
+#define HWA742_H_DISP_REG 0x16
+#define HWA742_H_NDP_REG 0x18
+#define HWA742_V_DISP_1_REG 0x1a
+#define HWA742_V_DISP_2_REG 0x1c
+#define HWA742_V_NDP_REG 0x1e
+#define HWA742_HS_W_REG 0x20
+#define HWA742_HP_S_REG 0x22
+#define HWA742_VS_W_REG 0x24
+#define HWA742_VP_S_REG 0x26
+#define HWA742_PCLK_POL_REG 0x28
+#define HWA742_INPUT_MODE_REG 0x2a
+#define HWA742_TRANSL_MODE_REG1 0x2e
+#define HWA742_DISP_MODE_REG 0x34
+#define HWA742_WINDOW_TYPE 0x36
+#define HWA742_WINDOW_X_START_0 0x38
+#define HWA742_WINDOW_X_START_1 0x3a
+#define HWA742_WINDOW_Y_START_0 0x3c
+#define HWA742_WINDOW_Y_START_1 0x3e
+#define HWA742_WINDOW_X_END_0 0x40
+#define HWA742_WINDOW_X_END_1 0x42
+#define HWA742_WINDOW_Y_END_0 0x44
+#define HWA742_WINDOW_Y_END_1 0x46
+#define HWA742_MEMORY_WRITE_LSB 0x48
+#define HWA742_MEMORY_WRITE_MSB 0x49
+#define HWA742_MEMORY_READ_0 0x4a
+#define HWA742_MEMORY_READ_1 0x4c
+#define HWA742_MEMORY_READ_2 0x4e
+#define HWA742_POWER_SAVE 0x56
+#define HWA742_NDP_CTRL 0x58
+
+#define HWA742_AUTO_UPDATE_TIME (HZ / 20)
+
+/* Reserve 4 request slots for requests in irq context */
+#define REQ_POOL_SIZE 24
+#define IRQ_REQ_POOL_SIZE 4
+
+#define REQ_FROM_IRQ_POOL 0x01
+
+#define REQ_COMPLETE 0
+#define REQ_PENDING 1
+
+struct update_param {
+ int x, y, width, height;
+ int color_mode;
+ int flags;
+};
+
+struct hwa742_request {
+ struct list_head entry;
+ unsigned int flags;
+
+ int (*handler)(struct hwa742_request *req);
+ void (*complete)(void *data);
+ void *complete_data;
+
+ union {
+ struct update_param update;
+ struct completion *sync;
+ } par;
+};
+
+struct {
+ enum omapfb_update_mode update_mode;
+ enum omapfb_update_mode update_mode_before_suspend;
+
+ struct timer_list auto_update_timer;
+ int stop_auto_update;
+ struct omapfb_update_window auto_update_window;
+ unsigned te_connected:1;
+ unsigned vsync_only:1;
+
+ struct hwa742_request req_pool[REQ_POOL_SIZE];
+ struct list_head pending_req_list;
+ struct list_head free_req_list;
+ struct semaphore req_sema;
+ spinlock_t req_lock;
+
+ struct extif_timings reg_timings, lut_timings;
+
+ int prev_color_mode;
+ int prev_flags;
+ int window_type;
+
+ u32 max_transmit_size;
+ u32 extif_clk_period;
+ unsigned long pix_tx_time;
+ unsigned long line_upd_time;
+
+
+ struct omapfb_device *fbdev;
+ struct lcd_ctrl_extif *extif;
+ struct lcd_ctrl *int_ctrl;
+
+ void (*power_up)(struct device *dev);
+ void (*power_down)(struct device *dev);
+} hwa742;
+
+struct lcd_ctrl hwa742_ctrl;
+
+static u8 hwa742_read_reg(u8 reg)
+{
+ u8 data;
+
+ hwa742.extif->set_bits_per_cycle(8);
+ hwa742.extif->write_command(&reg, 1);
+ hwa742.extif->read_data(&data, 1);
+
+ return data;
+}
+
+static void hwa742_write_reg(u8 reg, u8 data)
+{
+ hwa742.extif->set_bits_per_cycle(8);
+ hwa742.extif->write_command(&reg, 1);
+ hwa742.extif->write_data(&data, 1);
+}
+
+static void set_window_regs(int x_start, int y_start, int x_end, int y_end)
+{
+ u8 tmp[8];
+ u8 cmd;
+
+ x_end--;
+ y_end--;
+ tmp[0] = x_start;
+ tmp[1] = x_start >> 8;
+ tmp[2] = y_start;
+ tmp[3] = y_start >> 8;
+ tmp[4] = x_end;
+ tmp[5] = x_end >> 8;
+ tmp[6] = y_end;
+ tmp[7] = y_end >> 8;
+
+ hwa742.extif->set_bits_per_cycle(8);
+ cmd = HWA742_WINDOW_X_START_0;
+
+ hwa742.extif->write_command(&cmd, 1);
+
+ hwa742.extif->write_data(tmp, 8);
+}
+
+static void set_format_regs(int conv, int transl, int flags)
+{
+ if (flags & OMAPFB_FORMAT_FLAG_DOUBLE) {
+ hwa742.window_type = ((hwa742.window_type & 0xfc) | 0x01);
+#ifdef VERBOSE
+ dev_dbg(hwa742.fbdev->dev, "hwa742: enabled pixel doubling\n");
+#endif
+ } else {
+ hwa742.window_type = (hwa742.window_type & 0xfc);
+#ifdef VERBOSE
+ dev_dbg(hwa742.fbdev->dev, "hwa742: disabled pixel doubling\n");
+#endif
+ }
+
+ hwa742_write_reg(HWA742_INPUT_MODE_REG, conv);
+ hwa742_write_reg(HWA742_TRANSL_MODE_REG1, transl);
+ hwa742_write_reg(HWA742_WINDOW_TYPE, hwa742.window_type);
+}
+
+static void enable_tearsync(int y, int width, int height, int screen_height,
+ int force_vsync)
+{
+ u8 b;
+
+ b = hwa742_read_reg(HWA742_NDP_CTRL);
+ b |= 1 << 2;
+ hwa742_write_reg(HWA742_NDP_CTRL, b);
+
+ if (likely(hwa742.vsync_only || force_vsync)) {
+ hwa742.extif->enable_tearsync(1, 0);
+ return;
+ }
+
+ if (width * hwa742.pix_tx_time < hwa742.line_upd_time) {
+ hwa742.extif->enable_tearsync(1, 0);
+ return;
+ }
+
+ if ((width * hwa742.pix_tx_time / 1000) * height <
+ (y + height) * (hwa742.line_upd_time / 1000)) {
+ hwa742.extif->enable_tearsync(1, 0);
+ return;
+ }
+
+ hwa742.extif->enable_tearsync(1, y + 1);
+}
+
+static void disable_tearsync(void)
+{
+ u8 b;
+
+ hwa742.extif->enable_tearsync(0, 0);
+
+ b = hwa742_read_reg(HWA742_NDP_CTRL);
+ b &= ~(1 << 2);
+ hwa742_write_reg(HWA742_NDP_CTRL, b);
+}
+
+static inline struct hwa742_request *alloc_req(void)
+{
+ unsigned long flags;
+ struct hwa742_request *req;
+ int req_flags = 0;
+
+ if (!in_interrupt())
+ down(&hwa742.req_sema);
+ else
+ req_flags = REQ_FROM_IRQ_POOL;
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+ BUG_ON(list_empty(&hwa742.free_req_list));
+ req = list_entry(hwa742.free_req_list.next,
+ struct hwa742_request, entry);
+ list_del(&req->entry);
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+ INIT_LIST_HEAD(&req->entry);
+ req->flags = req_flags;
+
+ return req;
+}
+
+static inline void free_req(struct hwa742_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+
+ list_del(&req->entry);
+ list_add(&req->entry, &hwa742.free_req_list);
+ if (!(req->flags & REQ_FROM_IRQ_POOL))
+ up(&hwa742.req_sema);
+
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+}
+
+static void process_pending_requests(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+
+ while (!list_empty(&hwa742.pending_req_list)) {
+ struct hwa742_request *req;
+ void (*complete)(void *);
+ void *complete_data;
+
+ req = list_entry(hwa742.pending_req_list.next,
+ struct hwa742_request, entry);
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+ if (req->handler(req) == REQ_PENDING)
+ return;
+
+ complete = req->complete;
+ complete_data = req->complete_data;
+ free_req(req);
+
+ if (complete)
+ complete(complete_data);
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+ }
+
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+}
+
+static void submit_req_list(struct list_head *head)
+{
+ unsigned long flags;
+ int process = 1;
+
+ spin_lock_irqsave(&hwa742.req_lock, flags);
+ if (likely(!list_empty(&hwa742.pending_req_list)))
+ process = 0;
+ list_splice_init(head, hwa742.pending_req_list.prev);
+ spin_unlock_irqrestore(&hwa742.req_lock, flags);
+
+ if (process)
+ process_pending_requests();
+}
+
+static void request_complete(void *data)
+{
+ struct hwa742_request *req = (struct hwa742_request *)data;
+ void (*complete)(void *);
+ void *complete_data;
+
+ complete = req->complete;
+ complete_data = req->complete_data;
+
+ free_req(req);
+
+ if (complete)
+ complete(complete_data);
+
+ process_pending_requests();
+}
+
+static int send_frame_handler(struct hwa742_request *req)
+{
+ struct update_param *par = &req->par.update;
+ int x = par->x;
+ int y = par->y;
+ int w = par->width;
+ int h = par->height;
+ int bpp;
+ int conv, transl;
+ unsigned long offset;
+ int color_mode = par->color_mode;
+ int flags = par->flags;
+ int scr_width = hwa742.fbdev->panel->x_res;
+ int scr_height = hwa742.fbdev->panel->y_res;
+
+#ifdef VERBOSE
+ dev_dbg(hwa742.fbdev->dev, "x %d y %d w %d h %d scr_width %d "
+ "color_mode %d flags %d\n",
+ x, y, w, h, scr_width, color_mode, flags);
+#endif
+
+ switch (color_mode) {
+ case OMAPFB_COLOR_YUV422:
+ bpp = 16;
+ conv = 0x08;
+ transl = 0x25;
+ break;
+ case OMAPFB_COLOR_YUV420:
+ bpp = 12;
+ conv = 0x09;
+ transl = 0x25;
+ break;
+ case OMAPFB_COLOR_RGB565:
+ bpp = 16;
+ conv = 0x01;
+ transl = 0x05;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (hwa742.prev_flags != flags ||
+ hwa742.prev_color_mode != color_mode) {
+ set_format_regs(conv, transl, flags);
+ hwa742.prev_color_mode = color_mode;
+ hwa742.prev_flags = flags;
+ }
+ flags = req->par.update.flags;
+ if (flags & OMAPFB_FORMAT_FLAG_TEARSYNC)
+ enable_tearsync(y, scr_width, h, scr_height,
+ flags & OMAPFB_FORMAT_FLAG_FORCE_VSYNC);
+ else
+ disable_tearsync();
+
+ set_window_regs(x, y, x + w, y + h);
+
+ offset = (scr_width * y + x) * bpp / 8;
+
+ hwa742.int_ctrl->setup_plane(OMAPFB_PLANE_GFX,
+ OMAPFB_CHANNEL_OUT_LCD, offset, scr_width, 0, 0, w, h,
+ color_mode);
+
+ hwa742.extif->set_bits_per_cycle(16);
+
+ hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
+ hwa742.extif->transfer_area(w, h, request_complete, req);
+
+ return REQ_PENDING;
+}
+
+static void send_frame_complete(void *data)
+{
+ hwa742.int_ctrl->enable_plane(OMAPFB_PLANE_GFX, 0);
+}
+
+#define ADD_PREQ(_x, _y, _w, _h) do { \
+ req = alloc_req(); \
+ req->handler = send_frame_handler; \
+ req->complete = send_frame_complete; \
+ req->par.update.x = _x; \
+ req->par.update.y = _y; \
+ req->par.update.width = _w; \
+ req->par.update.height = _h; \
+ req->par.update.color_mode = color_mode;\
+ req->par.update.flags = flags; \
+ list_add_tail(&req->entry, req_head); \
+} while(0)
+
+static void create_req_list(struct omapfb_update_window *win,
+ struct list_head *req_head)
+{
+ struct hwa742_request *req;
+ int x = win->x;
+ int y = win->y;
+ int width = win->width;
+ int height = win->height;
+ int color_mode;
+ int flags;
+
+ flags = win->format & ~OMAPFB_FORMAT_MASK;
+ color_mode = win->format & OMAPFB_FORMAT_MASK;
+
+ if (x & 1) {
+ ADD_PREQ(x, y, 1, height);
+ width--;
+ x++;
+ flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
+ }
+ if (width & ~1) {
+ unsigned int xspan = width & ~1;
+ unsigned int ystart = y;
+ unsigned int yspan = height;
+
+ if (xspan * height * 2 > hwa742.max_transmit_size) {
+ yspan = hwa742.max_transmit_size / (xspan * 2);
+ ADD_PREQ(x, ystart, xspan, yspan);
+ ystart += yspan;
+ yspan = height - yspan;
+ flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
+ }
+
+ ADD_PREQ(x, ystart, xspan, yspan);
+ x += xspan;
+ width -= xspan;
+ flags &= ~OMAPFB_FORMAT_FLAG_TEARSYNC;
+ }
+ if (width)
+ ADD_PREQ(x, y, 1, height);
+}
+
+static void auto_update_complete(void *data)
+{
+ if (!hwa742.stop_auto_update)
+ mod_timer(&hwa742.auto_update_timer,
+ jiffies + HWA742_AUTO_UPDATE_TIME);
+}
+
+static void hwa742_update_window_auto(unsigned long arg)
+{
+ LIST_HEAD(req_list);
+ struct hwa742_request *last;
+
+ create_req_list(&hwa742.auto_update_window, &req_list);
+ last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+ last->complete = auto_update_complete;
+ last->complete_data = NULL;
+
+ submit_req_list(&req_list);
+}
+
+int hwa742_update_window_async(struct fb_info *fbi,
+ struct omapfb_update_window *win,
+ void (*complete_callback)(void *arg),
+ void *complete_callback_data)
+{
+ LIST_HEAD(req_list);
+ struct hwa742_request *last;
+ int r = 0;
+
+ if (hwa742.update_mode != OMAPFB_MANUAL_UPDATE) {
+ dev_dbg(hwa742.fbdev->dev, "invalid update mode\n");
+ r = -EINVAL;
+ goto out;
+ }
+ if (unlikely(win->format &
+ ~(0x03 | OMAPFB_FORMAT_FLAG_DOUBLE |
+ OMAPFB_FORMAT_FLAG_TEARSYNC | OMAPFB_FORMAT_FLAG_FORCE_VSYNC))) {
+ dev_dbg(hwa742.fbdev->dev, "invalid window flag");
+ r = -EINVAL;
+ goto out;
+ }
+
+ create_req_list(win, &req_list);
+ last = list_entry(req_list.prev, struct hwa742_request, entry);
+
+ last->complete = complete_callback;
+ last->complete_data = (void *)complete_callback_data;
+
+ submit_req_list(&req_list);
+
+out:
+ return r;
+}
+EXPORT_SYMBOL(hwa742_update_window_async);
+
+static int hwa742_setup_plane(int plane, int channel_out,
+ unsigned long offset, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ if (plane != OMAPFB_PLANE_GFX ||
+ channel_out != OMAPFB_CHANNEL_OUT_LCD)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int hwa742_enable_plane(int plane, int enable)
+{
+ if (plane != 0)
+ return -EINVAL;
+
+ hwa742.int_ctrl->enable_plane(plane, enable);
+
+ return 0;
+}
+
+static int sync_handler(struct hwa742_request *req)
+{
+ complete(req->par.sync);
+ return REQ_COMPLETE;
+}
+
+static void hwa742_sync(void)
+{
+ LIST_HEAD(req_list);
+ struct hwa742_request *req;
+ struct completion comp;
+
+ req = alloc_req();
+
+ req->handler = sync_handler;
+ req->complete = NULL;
+ init_completion(&comp);
+ req->par.sync = &comp;
+
+ list_add(&req->entry, &req_list);
+ submit_req_list(&req_list);
+
+ wait_for_completion(&comp);
+}
+
+static void hwa742_bind_client(struct omapfb_notifier_block *nb)
+{
+ dev_dbg(hwa742.fbdev->dev, "update_mode %d\n", hwa742.update_mode);
+ if (hwa742.update_mode == OMAPFB_MANUAL_UPDATE) {
+ omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
+ }
+}
+
+static int hwa742_set_update_mode(enum omapfb_update_mode mode)
+{
+ if (mode != OMAPFB_MANUAL_UPDATE && mode != OMAPFB_AUTO_UPDATE &&
+ mode != OMAPFB_UPDATE_DISABLED)
+ return -EINVAL;
+
+ if (mode == hwa742.update_mode)
+ return 0;
+
+ dev_info(hwa742.fbdev->dev, "HWA742: setting update mode to %s\n",
+ mode == OMAPFB_UPDATE_DISABLED ? "disabled" :
+ (mode == OMAPFB_AUTO_UPDATE ? "auto" : "manual"));
+
+ switch (hwa742.update_mode) {
+ case OMAPFB_MANUAL_UPDATE:
+ omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_DISABLED);
+ break;
+ case OMAPFB_AUTO_UPDATE:
+ hwa742.stop_auto_update = 1;
+ del_timer_sync(&hwa742.auto_update_timer);
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ break;
+ }
+
+ hwa742.update_mode = mode;
+ hwa742_sync();
+ hwa742.stop_auto_update = 0;
+
+ switch (mode) {
+ case OMAPFB_MANUAL_UPDATE:
+ omapfb_notify_clients(hwa742.fbdev, OMAPFB_EVENT_READY);
+ break;
+ case OMAPFB_AUTO_UPDATE:
+ hwa742_update_window_auto(0);
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ break;
+ }
+
+ return 0;
+}
+
+static enum omapfb_update_mode hwa742_get_update_mode(void)
+{
+ return hwa742.update_mode;
+}
+
+static unsigned long round_to_extif_ticks(unsigned long ps, int div)
+{
+ int bus_tick = hwa742.extif_clk_period * div;
+ return (ps + bus_tick - 1) / bus_tick * bus_tick;
+}
+
+static int calc_reg_timing(unsigned long sysclk, int div)
+{
+ struct extif_timings *t;
+ unsigned long systim;
+
+ /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+ * AccessTime 2 ns + 12.2 ns (regs),
+ * WEOffTime = WEOnTime + 1 ns,
+ * REOffTime = REOnTime + 16 ns (regs),
+ * CSOffTime = REOffTime + 1 ns
+ * ReadCycle = 2ns + 2*SYSCLK (regs),
+ * WriteCycle = 2*SYSCLK + 2 ns,
+ * CSPulseWidth = 10 ns */
+ systim = 1000000000 / (sysclk / 1000);
+ dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps"
+ "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+ t = &hwa742.reg_timings;
+ memset(t, 0, sizeof(*t));
+ t->clk_div = div;
+ t->cs_on_time = 0;
+ t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->access_time = round_to_extif_ticks(t->re_on_time + 12200, div);
+ t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+ t->re_off_time = round_to_extif_ticks(t->re_on_time + 16000, div);
+ t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+ t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->we_cycle_time < t->we_off_time)
+ t->we_cycle_time = t->we_off_time;
+ t->re_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->re_cycle_time < t->re_off_time)
+ t->re_cycle_time = t->re_off_time;
+ t->cs_pulse_width = 0;
+
+ dev_dbg(hwa742.fbdev->dev, "[reg]cson %d csoff %d reon %d reoff %d\n",
+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+ dev_dbg(hwa742.fbdev->dev, "[reg]weon %d weoff %d recyc %d wecyc %d\n",
+ t->we_on_time, t->we_off_time, t->re_cycle_time,
+ t->we_cycle_time);
+ dev_dbg(hwa742.fbdev->dev, "[reg]rdaccess %d cspulse %d\n",
+ t->access_time, t->cs_pulse_width);
+
+ return hwa742.extif->convert_timings(t);
+}
+
+static int calc_lut_timing(unsigned long sysclk, int div)
+{
+ struct extif_timings *t;
+ unsigned long systim;
+
+ /* CSOnTime 0, WEOnTime 2 ns, REOnTime 2 ns,
+ * AccessTime 2 ns + 4 * SYSCLK + 26 (lut),
+ * WEOffTime = WEOnTime + 1 ns,
+ * REOffTime = REOnTime + 4*SYSCLK + 26 ns (lut),
+ * CSOffTime = REOffTime + 1 ns
+ * ReadCycle = 2ns + 4*SYSCLK + 26 ns (lut),
+ * WriteCycle = 2*SYSCLK + 2 ns,
+ * CSPulseWidth = 10 ns
+ */
+ systim = 1000000000 / (sysclk / 1000);
+ dev_dbg(hwa742.fbdev->dev, "HWA742 systim %lu ps extif_clk_period %u ps"
+ "extif_clk_div %d\n", systim, hwa742.extif_clk_period, div);
+
+ t = &hwa742.lut_timings;
+ memset(t, 0, sizeof(*t));
+
+ t->clk_div = div;
+
+ t->cs_on_time = 0;
+ t->we_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->re_on_time = round_to_extif_ticks(t->cs_on_time + 2000, div);
+ t->access_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+ 26000, div);
+ t->we_off_time = round_to_extif_ticks(t->we_on_time + 1000, div);
+ t->re_off_time = round_to_extif_ticks(t->re_on_time + 4 * systim +
+ 26000, div);
+ t->cs_off_time = round_to_extif_ticks(t->re_off_time + 1000, div);
+ t->we_cycle_time = round_to_extif_ticks(2 * systim + 2000, div);
+ if (t->we_cycle_time < t->we_off_time)
+ t->we_cycle_time = t->we_off_time;
+ t->re_cycle_time = round_to_extif_ticks(2000 + 4 * systim + 26000, div);
+ if (t->re_cycle_time < t->re_off_time)
+ t->re_cycle_time = t->re_off_time;
+ t->cs_pulse_width = 0;
+
+ dev_dbg(hwa742.fbdev->dev, "[lut]cson %d csoff %d reon %d reoff %d\n",
+ t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
+ dev_dbg(hwa742.fbdev->dev, "[lut]weon %d weoff %d recyc %d wecyc %d\n",
+ t->we_on_time, t->we_off_time, t->re_cycle_time,
+ t->we_cycle_time);
+ dev_dbg(hwa742.fbdev->dev, "[lut]rdaccess %d cspulse %d\n",
+ t->access_time, t->cs_pulse_width);
+
+ return hwa742.extif->convert_timings(t);
+}
+
+static int calc_extif_timings(unsigned long sysclk, int *extif_mem_div)
+{
+ int max_clk_div;
+ int div;
+
+ hwa742.extif->get_clk_info(&hwa742.extif_clk_period, &max_clk_div);
+ for (div = 1; div < max_clk_div; div++) {
+ if (calc_reg_timing(sysclk, div) == 0)
+ break;
+ }
+ if (div > max_clk_div)
+ goto err;
+
+ *extif_mem_div = div;
+
+ for (div = 1; div < max_clk_div; div++) {
+ if (calc_lut_timing(sysclk, div) == 0)
+ break;
+ }
+
+ if (div > max_clk_div)
+ goto err;
+
+ return 0;
+
+err:
+ dev_err(hwa742.fbdev->dev, "can't setup timings\n");
+ return -1;
+}
+
+static void calc_hwa742_clk_rates(unsigned long ext_clk,
+ unsigned long *sys_clk, unsigned long *pix_clk)
+{
+ int pix_clk_src;
+ int sys_div = 0, sys_mul = 0;
+ int pix_div;
+
+ pix_clk_src = hwa742_read_reg(HWA742_CLK_SRC_REG);
+ pix_div = ((pix_clk_src >> 3) & 0x1f) + 1;
+ if ((pix_clk_src & (0x3 << 1)) == 0) {
+ /* Source is the PLL */
+ sys_div = (hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x3f) + 1;
+ sys_mul = (hwa742_read_reg(HWA742_PLL_4_REG) & 0x7f) + 1;
+ *sys_clk = ext_clk * sys_mul / sys_div;
+ } else /* else source is ext clk, or oscillator */
+ *sys_clk = ext_clk;
+
+ *pix_clk = *sys_clk / pix_div; /* HZ */
+ dev_dbg(hwa742.fbdev->dev,
+ "ext_clk %ld pix_src %d pix_div %d sys_div %d sys_mul %d\n",
+ ext_clk, pix_clk_src & (0x3 << 1), pix_div, sys_div, sys_mul);
+ dev_dbg(hwa742.fbdev->dev, "sys_clk %ld pix_clk %ld\n",
+ *sys_clk, *pix_clk);
+}
+
+
+static int setup_tearsync(unsigned long pix_clk, int extif_div)
+{
+ int hdisp, vdisp;
+ int hndp, vndp;
+ int hsw, vsw;
+ int hs, vs;
+ int hs_pol_inv, vs_pol_inv;
+ int use_hsvs, use_ndp;
+ u8 b;
+
+ hsw = hwa742_read_reg(HWA742_HS_W_REG);
+ vsw = hwa742_read_reg(HWA742_VS_W_REG);
+ hs_pol_inv = !(hsw & 0x80);
+ vs_pol_inv = !(vsw & 0x80);
+ hsw = hsw & 0x7f;
+ vsw = vsw & 0x3f;
+
+ hdisp = (hwa742_read_reg(HWA742_H_DISP_REG) & 0x7f) * 8;
+ vdisp = hwa742_read_reg(HWA742_V_DISP_1_REG) +
+ ((hwa742_read_reg(HWA742_V_DISP_2_REG) & 0x3) << 8);
+
+ hndp = hwa742_read_reg(HWA742_H_NDP_REG) & 0x7f;
+ vndp = hwa742_read_reg(HWA742_V_NDP_REG);
+
+ /* time to transfer one pixel (16bpp) in ps */
+ hwa742.pix_tx_time = hwa742.reg_timings.we_cycle_time;
+ if (hwa742.extif->get_max_tx_rate != NULL) {
+ /*
+ * The external interface might have a rate limitation,
+ * if so, we have to maximize our transfer rate.
+ */
+ unsigned long min_tx_time;
+ unsigned long max_tx_rate = hwa742.extif->get_max_tx_rate();
+
+ dev_dbg(hwa742.fbdev->dev, "max_tx_rate %ld HZ\n",
+ max_tx_rate);
+ min_tx_time = 1000000000 / (max_tx_rate / 1000); /* ps */
+ if (hwa742.pix_tx_time < min_tx_time)
+ hwa742.pix_tx_time = min_tx_time;
+ }
+
+ /* time to update one line in ps */
+ hwa742.line_upd_time = (hdisp + hndp) * 1000000 / (pix_clk / 1000);
+ hwa742.line_upd_time *= 1000;
+ if (hdisp * hwa742.pix_tx_time > hwa742.line_upd_time)
+ /*
+ * transfer speed too low, we might have to use both
+ * HS and VS
+ */
+ use_hsvs = 1;
+ else
+ /* decent transfer speed, we'll always use only VS */
+ use_hsvs = 0;
+
+ if (use_hsvs && (hs_pol_inv || vs_pol_inv)) {
+ /*
+ * HS or'ed with VS doesn't work, use the active high
+ * TE signal based on HNDP / VNDP
+ */
+ use_ndp = 1;
+ hs_pol_inv = 0;
+ vs_pol_inv = 0;
+ hs = hndp;
+ vs = vndp;
+ } else {
+ /*
+ * Use HS or'ed with VS as a TE signal if both are needed
+ * or VNDP if only vsync is needed.
+ */
+ use_ndp = 0;
+ hs = hsw;
+ vs = vsw;
+ if (!use_hsvs) {
+ hs_pol_inv = 0;
+ vs_pol_inv = 0;
+ }
+ }
+
+ hs = hs * 1000000 / (pix_clk / 1000); /* ps */
+ hs *= 1000;
+
+ vs = vs * (hdisp + hndp) * 1000000 / (pix_clk / 1000); /* ps */
+ vs *= 1000;
+
+ if (vs <= hs)
+ return -EDOM;
+ /* set VS to 120% of HS to minimize VS detection time */
+ vs = hs * 12 / 10;
+ /* minimize HS too */
+ hs = 10000;
+
+ b = hwa742_read_reg(HWA742_NDP_CTRL);
+ b &= ~0x3;
+ b |= use_hsvs ? 1 : 0;
+ b |= (use_ndp && use_hsvs) ? 0 : 2;
+ hwa742_write_reg(HWA742_NDP_CTRL, b);
+
+ hwa742.vsync_only = !use_hsvs;
+
+ dev_dbg(hwa742.fbdev->dev,
+ "pix_clk %ld HZ pix_tx_time %ld ps line_upd_time %ld ps\n",
+ pix_clk, hwa742.pix_tx_time, hwa742.line_upd_time);
+ dev_dbg(hwa742.fbdev->dev,
+ "hs %d ps vs %d ps mode %d vsync_only %d\n",
+ hs, vs, (b & 0x3), !use_hsvs);
+
+ return hwa742.extif->setup_tearsync(1, hs, vs,
+ hs_pol_inv, vs_pol_inv, extif_div);
+}
+
+static void hwa742_get_caps(int plane, struct omapfb_caps *caps)
+{
+ hwa742.int_ctrl->get_caps(plane, caps);
+ caps->ctrl |= OMAPFB_CAPS_MANUAL_UPDATE |
+ OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE;
+ if (hwa742.te_connected)
+ caps->ctrl |= OMAPFB_CAPS_TEARSYNC;
+ caps->wnd_color |= (1 << OMAPFB_COLOR_RGB565) |
+ (1 << OMAPFB_COLOR_YUV420);
+}
+
+static void hwa742_suspend(void)
+{
+ hwa742.update_mode_before_suspend = hwa742.update_mode;
+ hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+ /* Enable sleep mode */
+ hwa742_write_reg(HWA742_POWER_SAVE, 1 << 1);
+ if (hwa742.power_down != NULL)
+ hwa742.power_down(hwa742.fbdev->dev);
+}
+
+static void hwa742_resume(void)
+{
+ if (hwa742.power_up != NULL)
+ hwa742.power_up(hwa742.fbdev->dev);
+ /* Disable sleep mode */
+ hwa742_write_reg(HWA742_POWER_SAVE, 0);
+ while (1) {
+ /* Loop until PLL output is stabilized */
+ if (hwa742_read_reg(HWA742_PLL_DIV_REG) & (1 << 7))
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(5));
+ }
+ hwa742_set_update_mode(hwa742.update_mode_before_suspend);
+}
+
+static int hwa742_init(struct omapfb_device *fbdev, int ext_mode,
+ struct omapfb_mem_desc *req_vram)
+{
+ int r = 0, i;
+ u8 rev, conf;
+ unsigned long ext_clk;
+ unsigned long sys_clk, pix_clk;
+ int extif_mem_div;
+ struct omapfb_platform_data *omapfb_conf;
+ struct hwa742_platform_data *ctrl_conf;
+
+ BUG_ON(!fbdev->ext_if || !fbdev->int_ctrl);
+
+ hwa742.fbdev = fbdev;
+ hwa742.extif = fbdev->ext_if;
+ hwa742.int_ctrl = fbdev->int_ctrl;
+
+ omapfb_conf = fbdev->dev->platform_data;
+ ctrl_conf = omapfb_conf->ctrl_platform_data;
+
+ if (ctrl_conf == NULL || ctrl_conf->get_clock_rate == NULL) {
+ dev_err(fbdev->dev, "HWA742: missing platform data\n");
+ r = -ENOENT;
+ goto err1;
+ }
+
+ hwa742.power_down = ctrl_conf->power_down;
+ hwa742.power_up = ctrl_conf->power_up;
+
+ spin_lock_init(&hwa742.req_lock);
+
+ if ((r = hwa742.int_ctrl->init(fbdev, 1, req_vram)) < 0)
+ goto err1;
+
+ if ((r = hwa742.extif->init(fbdev)) < 0)
+ goto err2;
+
+ ext_clk = ctrl_conf->get_clock_rate(fbdev->dev);
+ if ((r = calc_extif_timings(ext_clk, &extif_mem_div)) < 0)
+ goto err3;
+ hwa742.extif->set_timings(&hwa742.reg_timings);
+ if (hwa742.power_up != NULL)
+ hwa742.power_up(fbdev->dev);
+
+ calc_hwa742_clk_rates(ext_clk, &sys_clk, &pix_clk);
+ if ((r = calc_extif_timings(sys_clk, &extif_mem_div)) < 0)
+ goto err4;
+ hwa742.extif->set_timings(&hwa742.reg_timings);
+
+ rev = hwa742_read_reg(HWA742_REV_CODE_REG);
+ if ((rev & 0xfc) != 0x80) {
+ dev_err(fbdev->dev, "HWA742: invalid revision %02x\n", rev);
+ r = -ENODEV;
+ goto err4;
+ }
+
+
+ if (!(hwa742_read_reg(HWA742_PLL_DIV_REG) & 0x80)) {
+ dev_err(fbdev->dev,
+ "HWA742: controller not initialized by the bootloader\n");
+ r = -ENODEV;
+ goto err4;
+ }
+
+ if (ctrl_conf->te_connected) {
+ if ((r = setup_tearsync(pix_clk, extif_mem_div)) < 0) {
+ dev_err(hwa742.fbdev->dev,
+ "HWA742: can't setup tearing synchronization\n");
+ goto err4;
+ }
+ hwa742.te_connected = 1;
+ }
+
+ hwa742.max_transmit_size = hwa742.extif->max_transmit_size;
+
+ hwa742.update_mode = OMAPFB_UPDATE_DISABLED;
+
+ hwa742.auto_update_window.x = 0;
+ hwa742.auto_update_window.y = 0;
+ hwa742.auto_update_window.width = fbdev->panel->x_res;
+ hwa742.auto_update_window.height = fbdev->panel->y_res;
+ hwa742.auto_update_window.format = 0;
+
+ init_timer(&hwa742.auto_update_timer);
+ hwa742.auto_update_timer.function = hwa742_update_window_auto;
+ hwa742.auto_update_timer.data = 0;
+
+ hwa742.prev_color_mode = -1;
+ hwa742.prev_flags = 0;
+
+ hwa742.fbdev = fbdev;
+
+ INIT_LIST_HEAD(&hwa742.free_req_list);
+ INIT_LIST_HEAD(&hwa742.pending_req_list);
+ for (i = 0; i < ARRAY_SIZE(hwa742.req_pool); i++)
+ list_add(&hwa742.req_pool[i].entry, &hwa742.free_req_list);
+ BUG_ON(i <= IRQ_REQ_POOL_SIZE);
+ sema_init(&hwa742.req_sema, i - IRQ_REQ_POOL_SIZE);
+
+ conf = hwa742_read_reg(HWA742_CONFIG_REG);
+ dev_info(fbdev->dev, ": Epson HWA742 LCD controller rev %d "
+ "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
+
+ return 0;
+err4:
+ if (hwa742.power_down != NULL)
+ hwa742.power_down(fbdev->dev);
+err3:
+ hwa742.extif->cleanup();
+err2:
+ hwa742.int_ctrl->cleanup();
+err1:
+ return r;
+}
+
+static void hwa742_cleanup(void)
+{
+ hwa742_set_update_mode(OMAPFB_UPDATE_DISABLED);
+ hwa742.extif->cleanup();
+ hwa742.int_ctrl->cleanup();
+ if (hwa742.power_down != NULL)
+ hwa742.power_down(hwa742.fbdev->dev);
+}
+
+struct lcd_ctrl hwa742_ctrl = {
+ .name = "hwa742",
+ .init = hwa742_init,
+ .cleanup = hwa742_cleanup,
+ .bind_client = hwa742_bind_client,
+ .get_caps = hwa742_get_caps,
+ .set_update_mode = hwa742_set_update_mode,
+ .get_update_mode = hwa742_get_update_mode,
+ .setup_plane = hwa742_setup_plane,
+ .enable_plane = hwa742_enable_plane,
+ .update_window = hwa742_update_window_async,
+ .sync = hwa742_sync,
+ .suspend = hwa742_suspend,
+ .resume = hwa742_resume,
+};
+
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
new file mode 100644
index 000000000000..51807b4e26d1
--- /dev/null
+++ b/drivers/video/omap/lcd_h3.c
@@ -0,0 +1,141 @@
+/*
+ * LCD panel support for the TI OMAP H3 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/tps65010.h>
+#include <asm/arch/omapfb.h>
+
+#define MODULE_NAME "omapfb-lcd_h3"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int h3_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void h3_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int h3_panel_enable(struct lcd_panel *panel)
+{
+ int r = 0;
+
+ /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+ r = tps65010_set_gpio_out_value(GPIO1, HIGH);
+ if (!r)
+ r = tps65010_set_gpio_out_value(GPIO2, HIGH);
+ if (r)
+ pr_err("Unable to turn on LCD panel\n");
+
+ return r;
+}
+
+static void h3_panel_disable(struct lcd_panel *panel)
+{
+ int r = 0;
+
+ /* GPIO1 and GPIO2 of TPS65010 send LCD_ENBKL and LCD_ENVDD signals */
+ r = tps65010_set_gpio_out_value(GPIO1, LOW);
+ if (!r)
+ tps65010_set_gpio_out_value(GPIO2, LOW);
+ if (r)
+ pr_err("Unable to turn off LCD panel\n");
+}
+
+static unsigned long h3_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel h3_panel = {
+ .name = "h3",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .data_lines = 16,
+ .bpp = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 12000,
+ .hsw = 12,
+ .hfp = 14,
+ .hbp = 72 - 12,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 0,
+
+ .init = h3_panel_init,
+ .cleanup = h3_panel_cleanup,
+ .enable = h3_panel_enable,
+ .disable = h3_panel_disable,
+ .get_caps = h3_panel_get_caps,
+};
+
+static int h3_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&h3_panel);
+ return 0;
+}
+
+static int h3_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int h3_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int h3_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver h3_panel_driver = {
+ .probe = h3_panel_probe,
+ .remove = h3_panel_remove,
+ .suspend = h3_panel_suspend,
+ .resume = h3_panel_resume,
+ .driver = {
+ .name = "lcd_h3",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int h3_panel_drv_init(void)
+{
+ return platform_driver_register(&h3_panel_driver);
+}
+
+static void h3_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&h3_panel_driver);
+}
+
+module_init(h3_panel_drv_init);
+module_exit(h3_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
new file mode 100644
index 000000000000..fd6f0eb16de1
--- /dev/null
+++ b/drivers/video/omap/lcd_h4.c
@@ -0,0 +1,117 @@
+/*
+ * LCD panel support for the TI OMAP H4 board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/omapfb.h>
+
+static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void h4_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int h4_panel_enable(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static void h4_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long h4_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel h4_panel = {
+ .name = "h4",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 6250,
+ .hsw = 15,
+ .hfp = 15,
+ .hbp = 60,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 1,
+
+ .init = h4_panel_init,
+ .cleanup = h4_panel_cleanup,
+ .enable = h4_panel_enable,
+ .disable = h4_panel_disable,
+ .get_caps = h4_panel_get_caps,
+};
+
+static int h4_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&h4_panel);
+ return 0;
+}
+
+static int h4_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int h4_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int h4_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver h4_panel_driver = {
+ .probe = h4_panel_probe,
+ .remove = h4_panel_remove,
+ .suspend = h4_panel_suspend,
+ .resume = h4_panel_resume,
+ .driver = {
+ .name = "lcd_h4",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int h4_panel_drv_init(void)
+{
+ return platform_driver_register(&h4_panel_driver);
+}
+
+static void h4_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&h4_panel_driver);
+}
+
+module_init(h4_panel_drv_init);
+module_exit(h4_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
new file mode 100644
index 000000000000..551f385861d1
--- /dev/null
+++ b/drivers/video/omap/lcd_inn1510.c
@@ -0,0 +1,124 @@
+/*
+ * LCD panel support for the TI OMAP1510 Innovator board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/omapfb.h>
+
+static int innovator1510_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void innovator1510_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int innovator1510_panel_enable(struct lcd_panel *panel)
+{
+ fpga_write(0x7, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+ return 0;
+}
+
+static void innovator1510_panel_disable(struct lcd_panel *panel)
+{
+ fpga_write(0x0, OMAP1510_FPGA_LCD_PANEL_CONTROL);
+}
+
+static unsigned long innovator1510_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel innovator1510_panel = {
+ .name = "inn1510",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 12500,
+ .hsw = 40,
+ .hfp = 40,
+ .hbp = 72,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 12,
+
+ .init = innovator1510_panel_init,
+ .cleanup = innovator1510_panel_cleanup,
+ .enable = innovator1510_panel_enable,
+ .disable = innovator1510_panel_disable,
+ .get_caps = innovator1510_panel_get_caps,
+};
+
+static int innovator1510_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&innovator1510_panel);
+ return 0;
+}
+
+static int innovator1510_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int innovator1510_panel_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ return 0;
+}
+
+static int innovator1510_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver innovator1510_panel_driver = {
+ .probe = innovator1510_panel_probe,
+ .remove = innovator1510_panel_remove,
+ .suspend = innovator1510_panel_suspend,
+ .resume = innovator1510_panel_resume,
+ .driver = {
+ .name = "lcd_inn1510",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int innovator1510_panel_drv_init(void)
+{
+ return platform_driver_register(&innovator1510_panel_driver);
+}
+
+static void innovator1510_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&innovator1510_panel_driver);
+}
+
+module_init(innovator1510_panel_drv_init);
+module_exit(innovator1510_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
new file mode 100644
index 000000000000..95604ca43301
--- /dev/null
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -0,0 +1,150 @@
+/*
+ * LCD panel support for the TI OMAP1610 Innovator board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+
+#define MODULE_NAME "omapfb-lcd_h3"
+
+#define pr_err(fmt, args...) printk(KERN_ERR MODULE_NAME ": " fmt, ## args)
+
+static int innovator1610_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ int r = 0;
+
+ if (omap_request_gpio(14)) {
+ pr_err("can't request GPIO 14\n");
+ r = -1;
+ goto exit;
+ }
+ if (omap_request_gpio(15)) {
+ pr_err("can't request GPIO 15\n");
+ omap_free_gpio(14);
+ r = -1;
+ goto exit;
+ }
+ /* configure GPIO(14, 15) as outputs */
+ omap_set_gpio_direction(14, 0);
+ omap_set_gpio_direction(15, 0);
+exit:
+ return r;
+}
+
+static void innovator1610_panel_cleanup(struct lcd_panel *panel)
+{
+ omap_free_gpio(15);
+ omap_free_gpio(14);
+}
+
+static int innovator1610_panel_enable(struct lcd_panel *panel)
+{
+ /* set GPIO14 and GPIO15 high */
+ omap_set_gpio_dataout(14, 1);
+ omap_set_gpio_dataout(15, 1);
+ return 0;
+}
+
+static void innovator1610_panel_disable(struct lcd_panel *panel)
+{
+ /* set GPIO13, GPIO14 and GPIO15 low */
+ omap_set_gpio_dataout(14, 0);
+ omap_set_gpio_dataout(15, 0);
+}
+
+static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel innovator1610_panel = {
+ .name = "inn1610",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 320,
+ .y_res = 240,
+ .pixel_clock = 12500,
+ .hsw = 40,
+ .hfp = 40,
+ .hbp = 72,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 12,
+
+ .init = innovator1610_panel_init,
+ .cleanup = innovator1610_panel_cleanup,
+ .enable = innovator1610_panel_enable,
+ .disable = innovator1610_panel_disable,
+ .get_caps = innovator1610_panel_get_caps,
+};
+
+static int innovator1610_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&innovator1610_panel);
+ return 0;
+}
+
+static int innovator1610_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int innovator1610_panel_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ return 0;
+}
+
+static int innovator1610_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver innovator1610_panel_driver = {
+ .probe = innovator1610_panel_probe,
+ .remove = innovator1610_panel_remove,
+ .suspend = innovator1610_panel_suspend,
+ .resume = innovator1610_panel_resume,
+ .driver = {
+ .name = "lcd_inn1610",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int innovator1610_panel_drv_init(void)
+{
+ return platform_driver_register(&innovator1610_panel_driver);
+}
+
+static void innovator1610_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&innovator1610_panel_driver);
+}
+
+module_init(innovator1610_panel_drv_init);
+module_exit(innovator1610_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
new file mode 100644
index 000000000000..a38038840fd6
--- /dev/null
+++ b/drivers/video/omap/lcd_osk.c
@@ -0,0 +1,144 @@
+/*
+ * LCD panel support for the TI OMAP OSK board
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ * Adapted for OSK by <dirk.behme@de.bosch.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/omapfb.h>
+
+static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void osk_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int osk_panel_enable(struct lcd_panel *panel)
+{
+ /* configure PWL pin */
+ omap_cfg_reg(PWL);
+
+ /* Enable PWL unit */
+ omap_writeb(0x01, OMAP_PWL_CLK_ENABLE);
+
+ /* Set PWL level */
+ omap_writeb(0xFF, OMAP_PWL_ENABLE);
+
+ /* configure GPIO2 as output */
+ omap_set_gpio_direction(2, 0);
+
+ /* set GPIO2 high */
+ omap_set_gpio_dataout(2, 1);
+
+ return 0;
+}
+
+static void osk_panel_disable(struct lcd_panel *panel)
+{
+ /* Set PWL level to zero */
+ omap_writeb(0x00, OMAP_PWL_ENABLE);
+
+ /* Disable PWL unit */
+ omap_writeb(0x00, OMAP_PWL_CLK_ENABLE);
+
+ /* set GPIO2 low */
+ omap_set_gpio_dataout(2, 0);
+}
+
+static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel osk_panel = {
+ .name = "osk",
+ .config = OMAP_LCDC_PANEL_TFT,
+
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 240,
+ .y_res = 320,
+ .pixel_clock = 12500,
+ .hsw = 40,
+ .hfp = 40,
+ .hbp = 72,
+ .vsw = 1,
+ .vfp = 1,
+ .vbp = 0,
+ .pcd = 12,
+
+ .init = osk_panel_init,
+ .cleanup = osk_panel_cleanup,
+ .enable = osk_panel_enable,
+ .disable = osk_panel_disable,
+ .get_caps = osk_panel_get_caps,
+};
+
+static int osk_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&osk_panel);
+ return 0;
+}
+
+static int osk_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int osk_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int osk_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver osk_panel_driver = {
+ .probe = osk_panel_probe,
+ .remove = osk_panel_remove,
+ .suspend = osk_panel_suspend,
+ .resume = osk_panel_resume,
+ .driver = {
+ .name = "lcd_osk",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int osk_panel_drv_init(void)
+{
+ return platform_driver_register(&osk_panel_driver);
+}
+
+static void osk_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&osk_panel_driver);
+}
+
+module_init(osk_panel_drv_init);
+module_exit(osk_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
new file mode 100644
index 000000000000..52bdfdac42c9
--- /dev/null
+++ b/drivers/video/omap/lcd_palmte.c
@@ -0,0 +1,123 @@
+/*
+ * LCD panel support for the Palm Tungsten E
+ *
+ * Original version : Romain Goyet <r.goyet@gmail.com>
+ * Current version : Laurent Gonzalez <palmte.linux@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 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/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/arch/fpga.h>
+#include <asm/arch/omapfb.h>
+
+static int palmte_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void palmte_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int palmte_panel_enable(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static void palmte_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long palmte_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel palmte_panel = {
+ .name = "palmte",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE |
+ OMAP_LCDC_HSVS_OPPOSITE,
+
+ .data_lines = 16,
+ .bpp = 8,
+ .pixel_clock = 12000,
+ .x_res = 320,
+ .y_res = 320,
+ .hsw = 4,
+ .hfp = 8,
+ .hbp = 28,
+ .vsw = 1,
+ .vfp = 8,
+ .vbp = 7,
+ .pcd = 0,
+
+ .init = palmte_panel_init,
+ .cleanup = palmte_panel_cleanup,
+ .enable = palmte_panel_enable,
+ .disable = palmte_panel_disable,
+ .get_caps = palmte_panel_get_caps,
+};
+
+static int palmte_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&palmte_panel);
+ return 0;
+}
+
+static int palmte_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int palmte_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int palmte_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver palmte_panel_driver = {
+ .probe = palmte_panel_probe,
+ .remove = palmte_panel_remove,
+ .suspend = palmte_panel_suspend,
+ .resume = palmte_panel_resume,
+ .driver = {
+ .name = "lcd_palmte",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int palmte_panel_drv_init(void)
+{
+ return platform_driver_register(&palmte_panel_driver);
+}
+
+static void palmte_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&palmte_panel_driver);
+}
+
+module_init(palmte_panel_drv_init);
+module_exit(palmte_panel_drv_cleanup);
+
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c
new file mode 100644
index 000000000000..4bb349f54356
--- /dev/null
+++ b/drivers/video/omap/lcd_palmtt.c
@@ -0,0 +1,127 @@
+/*
+ * LCD panel support for Palm Tungsten|T
+ * Current version : Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Modified from lcd_inn1510.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+GPIO11 - backlight
+GPIO12 - screen blanking
+GPIO13 - screen blanking
+*/
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+
+static int palmtt_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void palmtt_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static int palmtt_panel_enable(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static void palmtt_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long palmtt_panel_get_caps(struct lcd_panel *panel)
+{
+ return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+struct lcd_panel palmtt_panel = {
+ .name = "palmtt",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE |
+ OMAP_LCDC_HSVS_OPPOSITE,
+ .bpp = 16,
+ .data_lines = 16,
+ .x_res = 320,
+ .y_res = 320,
+ .pixel_clock = 10000,
+ .hsw = 4,
+ .hfp = 8,
+ .hbp = 28,
+ .vsw = 1,
+ .vfp = 8,
+ .vbp = 7,
+ .pcd = 0,
+
+ .init = palmtt_panel_init,
+ .cleanup = palmtt_panel_cleanup,
+ .enable = palmtt_panel_enable,
+ .disable = palmtt_panel_disable,
+ .get_caps = palmtt_panel_get_caps,
+};
+
+static int palmtt_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&palmtt_panel);
+ return 0;
+}
+
+static int palmtt_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int palmtt_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int palmtt_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver palmtt_panel_driver = {
+ .probe = palmtt_panel_probe,
+ .remove = palmtt_panel_remove,
+ .suspend = palmtt_panel_suspend,
+ .resume = palmtt_panel_resume,
+ .driver = {
+ .name = "lcd_palmtt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int palmtt_panel_drv_init(void)
+{
+ return platform_driver_register(&palmtt_panel_driver);
+}
+
+static void palmtt_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&palmtt_panel_driver);
+}
+
+module_init(palmtt_panel_drv_init);
+module_exit(palmtt_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c
new file mode 100644
index 000000000000..ea6170ddff35
--- /dev/null
+++ b/drivers/video/omap/lcd_palmz71.c
@@ -0,0 +1,123 @@
+/*
+ * LCD panel support for the Palm Zire71
+ *
+ * Original version : Romain Goyet
+ * Current version : Laurent Gonzalez
+ * Modified for zire71 : Marek Vasut
+ *
+ * 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/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/arch/omapfb.h>
+
+static int palmz71_panel_init(struct lcd_panel *panel,
+ struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void palmz71_panel_cleanup(struct lcd_panel *panel)
+{
+
+}
+
+static int palmz71_panel_enable(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+static void palmz71_panel_disable(struct lcd_panel *panel)
+{
+}
+
+static unsigned long palmz71_panel_get_caps(struct lcd_panel *panel)
+{
+ return OMAPFB_CAPS_SET_BACKLIGHT;
+}
+
+struct lcd_panel palmz71_panel = {
+ .name = "palmz71",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC | OMAP_LCDC_HSVS_RISING_EDGE |
+ OMAP_LCDC_HSVS_OPPOSITE,
+ .data_lines = 16,
+ .bpp = 16,
+ .pixel_clock = 24000,
+ .x_res = 320,
+ .y_res = 320,
+ .hsw = 4,
+ .hfp = 8,
+ .hbp = 28,
+ .vsw = 1,
+ .vfp = 8,
+ .vbp = 7,
+ .pcd = 0,
+
+ .init = palmz71_panel_init,
+ .cleanup = palmz71_panel_cleanup,
+ .enable = palmz71_panel_enable,
+ .disable = palmz71_panel_disable,
+ .get_caps = palmz71_panel_get_caps,
+};
+
+static int palmz71_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&palmz71_panel);
+ return 0;
+}
+
+static int palmz71_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int palmz71_panel_suspend(struct platform_device *pdev,
+ pm_message_t mesg)
+{
+ return 0;
+}
+
+static int palmz71_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver palmz71_panel_driver = {
+ .probe = palmz71_panel_probe,
+ .remove = palmz71_panel_remove,
+ .suspend = palmz71_panel_suspend,
+ .resume = palmz71_panel_resume,
+ .driver = {
+ .name = "lcd_palmz71",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int palmz71_panel_drv_init(void)
+{
+ return platform_driver_register(&palmz71_panel_driver);
+}
+
+static void palmz71_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&palmz71_panel_driver);
+}
+
+module_init(palmz71_panel_drv_init);
+module_exit(palmz71_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcd_sx1.c b/drivers/video/omap/lcd_sx1.c
new file mode 100644
index 000000000000..c4f306a4e5c9
--- /dev/null
+++ b/drivers/video/omap/lcd_sx1.c
@@ -0,0 +1,334 @@
+/*
+ * LCD panel support for the Siemens SX1 mobile phone
+ *
+ * Current version : Vovan888@gmail.com, great help from FCA00000
+ *
+ * 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/platform_device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/omapfb.h>
+#include <asm/arch/mcbsp.h>
+#include <asm/arch/mux.h>
+
+/*
+ * OMAP310 GPIO registers
+ */
+#define GPIO_DATA_INPUT 0xfffce000
+#define GPIO_DATA_OUTPUT 0xfffce004
+#define GPIO_DIR_CONTROL 0xfffce008
+#define GPIO_INT_CONTROL 0xfffce00c
+#define GPIO_INT_MASK 0xfffce010
+#define GPIO_INT_STATUS 0xfffce014
+#define GPIO_PIN_CONTROL 0xfffce018
+
+
+#define A_LCD_SSC_RD 3
+#define A_LCD_SSC_SD 7
+#define _A_LCD_RESET 9
+#define _A_LCD_SSC_CS 12
+#define _A_LCD_SSC_A0 13
+
+#define DSP_REG 0xE1017024
+
+const unsigned char INIT_1[12] = {
+ 0x1C, 0x02, 0x88, 0x00, 0x1E, 0xE0, 0x00, 0xDC, 0x00, 0x02, 0x00
+};
+
+const unsigned char INIT_2[127] = {
+ 0x15, 0x00, 0x29, 0x00, 0x3E, 0x00, 0x51, 0x00,
+ 0x65, 0x00, 0x7A, 0x00, 0x8D, 0x00, 0xA1, 0x00,
+ 0xB6, 0x00, 0xC7, 0x00, 0xD8, 0x00, 0xEB, 0x00,
+ 0xFB, 0x00, 0x0B, 0x01, 0x1B, 0x01, 0x27, 0x01,
+ 0x34, 0x01, 0x41, 0x01, 0x4C, 0x01, 0x55, 0x01,
+ 0x5F, 0x01, 0x68, 0x01, 0x70, 0x01, 0x78, 0x01,
+ 0x7E, 0x01, 0x86, 0x01, 0x8C, 0x01, 0x94, 0x01,
+ 0x9B, 0x01, 0xA1, 0x01, 0xA4, 0x01, 0xA9, 0x01,
+ 0xAD, 0x01, 0xB2, 0x01, 0xB7, 0x01, 0xBC, 0x01,
+ 0xC0, 0x01, 0xC4, 0x01, 0xC8, 0x01, 0xCB, 0x01,
+ 0xCF, 0x01, 0xD2, 0x01, 0xD5, 0x01, 0xD8, 0x01,
+ 0xDB, 0x01, 0xE0, 0x01, 0xE3, 0x01, 0xE6, 0x01,
+ 0xE8, 0x01, 0xEB, 0x01, 0xEE, 0x01, 0xF1, 0x01,
+ 0xF3, 0x01, 0xF8, 0x01, 0xF9, 0x01, 0xFC, 0x01,
+ 0x00, 0x02, 0x03, 0x02, 0x07, 0x02, 0x09, 0x02,
+ 0x0E, 0x02, 0x13, 0x02, 0x1C, 0x02, 0x00
+};
+
+const unsigned char INIT_3[15] = {
+ 0x14, 0x26, 0x33, 0x3D, 0x45, 0x4D, 0x53, 0x59,
+ 0x5E, 0x63, 0x67, 0x6D, 0x71, 0x78, 0xFF
+};
+
+static void epson_sendbyte(int flag, unsigned char byte)
+{
+ int i, shifter = 0x80;
+
+ if (!flag)
+ omap_set_gpio_dataout(_A_LCD_SSC_A0, 0);
+ mdelay(2);
+ omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
+
+ omap_set_gpio_dataout(A_LCD_SSC_SD, flag);
+
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
+ for (i = 0; i < 8; i++) {
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
+ omap_set_gpio_dataout(A_LCD_SSC_SD, shifter & byte);
+ OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
+ shifter >>= 1;
+ }
+ omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+}
+
+static void init_system(void)
+{
+ omap_mcbsp_request(OMAP_MCBSP3);
+ omap_mcbsp_stop(OMAP_MCBSP3);
+}
+
+static void setup_GPIO(void)
+{
+ /* new wave */
+ omap_request_gpio(A_LCD_SSC_RD);
+ omap_request_gpio(A_LCD_SSC_SD);
+ omap_request_gpio(_A_LCD_RESET);
+ omap_request_gpio(_A_LCD_SSC_CS);
+ omap_request_gpio(_A_LCD_SSC_A0);
+
+ /* set all GPIOs to output */
+ omap_set_gpio_direction(A_LCD_SSC_RD, 0);
+ omap_set_gpio_direction(A_LCD_SSC_SD, 0);
+ omap_set_gpio_direction(_A_LCD_RESET, 0);
+ omap_set_gpio_direction(_A_LCD_SSC_CS, 0);
+ omap_set_gpio_direction(_A_LCD_SSC_A0, 0);
+
+ /* set GPIO data */
+ omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
+ omap_set_gpio_dataout(A_LCD_SSC_SD, 0);
+ omap_set_gpio_dataout(_A_LCD_RESET, 0);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+}
+
+static void display_init(void)
+{
+ int i;
+
+ omap_cfg_reg(MCBSP3_CLKX);
+
+ mdelay(2);
+ setup_GPIO();
+ mdelay(2);
+
+ /* reset LCD */
+ omap_set_gpio_dataout(A_LCD_SSC_SD, 1);
+ epson_sendbyte(0, 0x25);
+
+ omap_set_gpio_dataout(_A_LCD_RESET, 0);
+ mdelay(10);
+ omap_set_gpio_dataout(_A_LCD_RESET, 1);
+
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ mdelay(2);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD, phase 1 */
+ epson_sendbyte(0, 0xCA);
+ for (i = 0; i < 10; i++)
+ epson_sendbyte(1, INIT_1[i]);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 2 */
+ epson_sendbyte(0, 0xCB);
+ for (i = 0; i < 125; i++)
+ epson_sendbyte(1, INIT_2[i]);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 2a */
+ epson_sendbyte(0, 0xCC);
+ for (i = 0; i < 14; i++)
+ epson_sendbyte(1, INIT_3[i]);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 3 */
+ epson_sendbyte(0, 0xBC);
+ epson_sendbyte(1, 0x08);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 4 */
+ epson_sendbyte(0, 0x07);
+ epson_sendbyte(1, 0x05);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 5 */
+ epson_sendbyte(0, 0x94);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 6 */
+ epson_sendbyte(0, 0xC6);
+ epson_sendbyte(1, 0x80);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ mdelay(100); /* used to be 1000 */
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 7 */
+ epson_sendbyte(0, 0x16);
+ epson_sendbyte(1, 0x02);
+ epson_sendbyte(1, 0x00);
+ epson_sendbyte(1, 0xB1);
+ epson_sendbyte(1, 0x00);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 8 */
+ epson_sendbyte(0, 0x76);
+ epson_sendbyte(1, 0x00);
+ epson_sendbyte(1, 0x00);
+ epson_sendbyte(1, 0xDB);
+ epson_sendbyte(1, 0x00);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ /* init LCD phase 9 */
+ epson_sendbyte(0, 0xAF);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+}
+
+static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
+{
+ return 0;
+}
+
+static void sx1_panel_cleanup(struct lcd_panel *panel)
+{
+}
+
+static void sx1_panel_disable(struct lcd_panel *panel)
+{
+ printk(KERN_INFO "SX1: LCD panel disable\n");
+ sx1_setmmipower(0);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+
+ epson_sendbyte(0, 0x25);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ epson_sendbyte(0, 0xAE);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ mdelay(100);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+
+ epson_sendbyte(0, 0x95);
+ omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+}
+
+static int sx1_panel_enable(struct lcd_panel *panel)
+{
+ printk(KERN_INFO "lcd_sx1: LCD panel enable\n");
+ init_system();
+ display_init();
+
+ sx1_setmmipower(1);
+ sx1_setbacklight(0x18);
+ sx1_setkeylight (0x06);
+ return 0;
+}
+
+
+static unsigned long sx1_panel_get_caps(struct lcd_panel *panel)
+{
+ return 0;
+}
+
+struct lcd_panel sx1_panel = {
+ .name = "sx1",
+ .config = OMAP_LCDC_PANEL_TFT | OMAP_LCDC_INV_VSYNC |
+ OMAP_LCDC_INV_HSYNC | OMAP_LCDC_INV_PIX_CLOCK |
+ OMAP_LCDC_INV_OUTPUT_EN,
+
+ .x_res = 176,
+ .y_res = 220,
+ .data_lines = 16,
+ .bpp = 16,
+ .hsw = 5,
+ .hfp = 5,
+ .hbp = 5,
+ .vsw = 2,
+ .vfp = 1,
+ .vbp = 1,
+ .pixel_clock = 1500,
+
+ .init = sx1_panel_init,
+ .cleanup = sx1_panel_cleanup,
+ .enable = sx1_panel_enable,
+ .disable = sx1_panel_disable,
+ .get_caps = sx1_panel_get_caps,
+};
+
+static int sx1_panel_probe(struct platform_device *pdev)
+{
+ omapfb_register_panel(&sx1_panel);
+ return 0;
+}
+
+static int sx1_panel_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int sx1_panel_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ return 0;
+}
+
+static int sx1_panel_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+struct platform_driver sx1_panel_driver = {
+ .probe = sx1_panel_probe,
+ .remove = sx1_panel_remove,
+ .suspend = sx1_panel_suspend,
+ .resume = sx1_panel_resume,
+ .driver = {
+ .name = "lcd_sx1",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int sx1_panel_drv_init(void)
+{
+ return platform_driver_register(&sx1_panel_driver);
+}
+
+static void sx1_panel_drv_cleanup(void)
+{
+ platform_driver_unregister(&sx1_panel_driver);
+}
+
+module_init(sx1_panel_drv_init);
+module_exit(sx1_panel_drv_cleanup);
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
new file mode 100644
index 000000000000..9085188d815e
--- /dev/null
+++ b/drivers/video/omap/lcdc.c
@@ -0,0 +1,893 @@
+/*
+ * OMAP1 internal LCD controller
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#include <asm/mach-types.h>
+
+#define MODULE_NAME "lcdc"
+
+#define OMAP_LCDC_BASE 0xfffec000
+#define OMAP_LCDC_SIZE 256
+#define OMAP_LCDC_IRQ INT_LCD_CTRL
+
+#define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00)
+#define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04)
+#define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08)
+#define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c)
+#define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10)
+#define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14)
+#define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18)
+#define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c)
+
+#define OMAP_LCDC_STAT_DONE (1 << 0)
+#define OMAP_LCDC_STAT_VSYNC (1 << 1)
+#define OMAP_LCDC_STAT_SYNC_LOST (1 << 2)
+#define OMAP_LCDC_STAT_ABC (1 << 3)
+#define OMAP_LCDC_STAT_LINE_INT (1 << 4)
+#define OMAP_LCDC_STAT_FUF (1 << 5)
+#define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6)
+
+#define OMAP_LCDC_CTRL_LCD_EN (1 << 0)
+#define OMAP_LCDC_CTRL_LCD_TFT (1 << 7)
+#define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10)
+
+#define OMAP_LCDC_IRQ_VSYNC (1 << 2)
+#define OMAP_LCDC_IRQ_DONE (1 << 3)
+#define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4)
+#define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5)
+#define OMAP_LCDC_IRQ_LINE (1 << 6)
+#define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2)
+
+#define MAX_PALETTE_SIZE PAGE_SIZE
+
+enum lcdc_load_mode {
+ OMAP_LCDC_LOAD_PALETTE,
+ OMAP_LCDC_LOAD_FRAME,
+ OMAP_LCDC_LOAD_PALETTE_AND_FRAME
+};
+
+static struct omap_lcd_controller {
+ enum omapfb_update_mode update_mode;
+ int ext_mode;
+
+ unsigned long frame_offset;
+ int screen_width;
+ int xres;
+ int yres;
+
+ enum omapfb_color_format color_mode;
+ int bpp;
+ void *palette_virt;
+ dma_addr_t palette_phys;
+ int palette_code;
+ int palette_size;
+
+ unsigned int irq_mask;
+ struct completion last_frame_complete;
+ struct completion palette_load_complete;
+ struct clk *lcd_ck;
+ struct omapfb_device *fbdev;
+
+ void (*dma_callback)(void *data);
+ void *dma_callback_data;
+
+ int fbmem_allocated;
+ dma_addr_t vram_phys;
+ void *vram_virt;
+ unsigned long vram_size;
+} lcdc;
+
+static void inline enable_irqs(int mask)
+{
+ lcdc.irq_mask |= mask;
+}
+
+static void inline disable_irqs(int mask)
+{
+ lcdc.irq_mask &= ~mask;
+}
+
+static void set_load_mode(enum lcdc_load_mode mode)
+{
+ u32 l;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l &= ~(3 << 20);
+ switch (mode) {
+ case OMAP_LCDC_LOAD_PALETTE:
+ l |= 1 << 20;
+ break;
+ case OMAP_LCDC_LOAD_FRAME:
+ l |= 2 << 20;
+ break;
+ case OMAP_LCDC_LOAD_PALETTE_AND_FRAME:
+ break;
+ default:
+ BUG();
+ }
+ omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void enable_controller(void)
+{
+ u32 l;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l |= OMAP_LCDC_CTRL_LCD_EN;
+ l &= ~OMAP_LCDC_IRQ_MASK;
+ l |= lcdc.irq_mask | OMAP_LCDC_IRQ_DONE; /* enabled IRQs */
+ omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void disable_controller_async(void)
+{
+ u32 l;
+ u32 mask;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK;
+ /*
+ * Preserve the DONE mask, since we still want to get the
+ * final DONE irq. It will be disabled in the IRQ handler.
+ */
+ mask &= ~OMAP_LCDC_IRQ_DONE;
+ l &= ~mask;
+ omap_writel(l, OMAP_LCDC_CONTROL);
+}
+
+static void disable_controller(void)
+{
+ init_completion(&lcdc.last_frame_complete);
+ disable_controller_async();
+ if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
+ msecs_to_jiffies(500)))
+ dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
+}
+
+static void reset_controller(u32 status)
+{
+ static unsigned long reset_count;
+ static unsigned long last_jiffies;
+
+ disable_controller_async();
+ reset_count++;
+ if (reset_count == 1 || time_after(jiffies, last_jiffies + HZ)) {
+ dev_err(lcdc.fbdev->dev,
+ "resetting (status %#010x,reset count %lu)\n",
+ status, reset_count);
+ last_jiffies = jiffies;
+ }
+ if (reset_count < 100) {
+ enable_controller();
+ } else {
+ reset_count = 0;
+ dev_err(lcdc.fbdev->dev,
+ "too many reset attempts, giving up.\n");
+ }
+}
+
+/*
+ * Configure the LCD DMA according to the current mode specified by parameters
+ * in lcdc.fbdev and fbdev->var.
+ */
+static void setup_lcd_dma(void)
+{
+ static const int dma_elem_type[] = {
+ 0,
+ OMAP_DMA_DATA_TYPE_S8,
+ OMAP_DMA_DATA_TYPE_S16,
+ 0,
+ OMAP_DMA_DATA_TYPE_S32,
+ };
+ struct omapfb_plane_struct *plane = lcdc.fbdev->fb_info[0]->par;
+ struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
+ unsigned long src;
+ int esize, xelem, yelem;
+
+ src = lcdc.vram_phys + lcdc.frame_offset;
+
+ switch (var->rotate) {
+ case 0:
+ if (plane->info.mirror || (src & 3) ||
+ lcdc.color_mode == OMAPFB_COLOR_YUV420 ||
+ (lcdc.xres & 1))
+ esize = 2;
+ else
+ esize = 4;
+ xelem = lcdc.xres * lcdc.bpp / 8 / esize;
+ yelem = lcdc.yres;
+ break;
+ case 90:
+ case 180:
+ case 270:
+ if (cpu_is_omap15xx()) {
+ BUG();
+ }
+ esize = 2;
+ xelem = lcdc.yres * lcdc.bpp / 16;
+ yelem = lcdc.xres;
+ break;
+ default:
+ BUG();
+ return;
+ }
+#ifdef VERBOSE
+ dev_dbg(lcdc.fbdev->dev,
+ "setup_dma: src %#010lx esize %d xelem %d yelem %d\n",
+ src, esize, xelem, yelem);
+#endif
+ omap_set_lcd_dma_b1(src, xelem, yelem, dma_elem_type[esize]);
+ if (!cpu_is_omap15xx()) {
+ int bpp = lcdc.bpp;
+
+ /*
+ * YUV support is only for external mode when we have the
+ * YUV window embedded in a 16bpp frame buffer.
+ */
+ if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
+ bpp = 16;
+ /* Set virtual xres elem size */
+ omap_set_lcd_dma_b1_vxres(
+ lcdc.screen_width * bpp / 8 / esize);
+ /* Setup transformations */
+ omap_set_lcd_dma_b1_rotation(var->rotate);
+ omap_set_lcd_dma_b1_mirror(plane->info.mirror);
+ }
+ omap_setup_lcd_dma();
+}
+
+static irqreturn_t lcdc_irq_handler(int irq, void *dev_id)
+{
+ u32 status;
+
+ status = omap_readl(OMAP_LCDC_STATUS);
+
+ if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
+ reset_controller(status);
+ else {
+ if (status & OMAP_LCDC_STAT_DONE) {
+ u32 l;
+
+ /*
+ * Disable IRQ_DONE. The status bit will be cleared
+ * only when the controller is reenabled and we don't
+ * want to get more interrupts.
+ */
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l &= ~OMAP_LCDC_IRQ_DONE;
+ omap_writel(l, OMAP_LCDC_CONTROL);
+ complete(&lcdc.last_frame_complete);
+ }
+ if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
+ disable_controller_async();
+ complete(&lcdc.palette_load_complete);
+ }
+ }
+
+ /*
+ * Clear these interrupt status bits.
+ * Sync_lost, FUF bits were cleared by disabling the LCD controller
+ * LOADED_PALETTE can be cleared this way only in palette only
+ * load mode. In other load modes it's cleared by disabling the
+ * controller.
+ */
+ status &= ~(OMAP_LCDC_STAT_VSYNC |
+ OMAP_LCDC_STAT_LOADED_PALETTE |
+ OMAP_LCDC_STAT_ABC |
+ OMAP_LCDC_STAT_LINE_INT);
+ omap_writel(status, OMAP_LCDC_STATUS);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Change to a new video mode. We defer this to a later time to avoid any
+ * flicker and not to mess up the current LCD DMA context. For this we disable
+ * the LCD controler, which will generate a DONE irq after the last frame has
+ * been transferred. Then it'll be safe to reconfigure both the LCD controller
+ * as well as the LCD DMA.
+ */
+static int omap_lcdc_setup_plane(int plane, int channel_out,
+ unsigned long offset, int screen_width,
+ int pos_x, int pos_y, int width, int height,
+ int color_mode)
+{
+ struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var;
+ struct lcd_panel *panel = lcdc.fbdev->panel;
+ int rot_x, rot_y;
+
+ if (var->rotate == 0) {
+ rot_x = panel->x_res;
+ rot_y = panel->y_res;
+ } else {
+ rot_x = panel->y_res;
+ rot_y = panel->x_res;
+ }
+ if (plane != 0 || channel_out != 0 || pos_x != 0 || pos_y != 0 ||
+ width > rot_x || height > rot_y) {
+#ifdef VERBOSE
+ dev_dbg(lcdc.fbdev->dev,
+ "invalid plane params plane %d pos_x %d pos_y %d "
+ "w %d h %d\n", plane, pos_x, pos_y, width, height);
+#endif
+ return -EINVAL;
+ }
+
+ lcdc.frame_offset = offset;
+ lcdc.xres = width;
+ lcdc.yres = height;
+ lcdc.screen_width = screen_width;
+ lcdc.color_mode = color_mode;
+
+ switch (color_mode) {
+ case OMAPFB_COLOR_CLUT_8BPP:
+ lcdc.bpp = 8;
+ lcdc.palette_code = 0x3000;
+ lcdc.palette_size = 512;
+ break;
+ case OMAPFB_COLOR_RGB565:
+ lcdc.bpp = 16;
+ lcdc.palette_code = 0x4000;
+ lcdc.palette_size = 32;
+ break;
+ case OMAPFB_COLOR_RGB444:
+ lcdc.bpp = 16;
+ lcdc.palette_code = 0x4000;
+ lcdc.palette_size = 32;
+ break;
+ case OMAPFB_COLOR_YUV420:
+ if (lcdc.ext_mode) {
+ lcdc.bpp = 12;
+ break;
+ }
+ /* fallthrough */
+ case OMAPFB_COLOR_YUV422:
+ if (lcdc.ext_mode) {
+ lcdc.bpp = 16;
+ break;
+ }
+ /* fallthrough */
+ default:
+ /* FIXME: other BPPs.
+ * bpp1: code 0, size 256
+ * bpp2: code 0x1000 size 256
+ * bpp4: code 0x2000 size 256
+ * bpp12: code 0x4000 size 32
+ */
+ dev_dbg(lcdc.fbdev->dev, "invalid color mode %d\n", color_mode);
+ BUG();
+ return -1;
+ }
+
+ if (lcdc.ext_mode) {
+ setup_lcd_dma();
+ return 0;
+ }
+
+ if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+ disable_controller();
+ omap_stop_lcd_dma();
+ setup_lcd_dma();
+ enable_controller();
+ }
+
+ return 0;
+}
+
+static int omap_lcdc_enable_plane(int plane, int enable)
+{
+ dev_dbg(lcdc.fbdev->dev,
+ "plane %d enable %d update_mode %d ext_mode %d\n",
+ plane, enable, lcdc.update_mode, lcdc.ext_mode);
+ if (plane != OMAPFB_PLANE_GFX)
+ return -EINVAL;
+
+ return 0;
+}
+
+/*
+ * Configure the LCD DMA for a palette load operation and do the palette
+ * downloading synchronously. We don't use the frame+palette load mode of
+ * the controller, since the palette can always be downloaded seperately.
+ */
+static void load_palette(void)
+{
+ u16 *palette;
+
+ palette = (u16 *)lcdc.palette_virt;
+
+ *(u16 *)palette &= 0x0fff;
+ *(u16 *)palette |= lcdc.palette_code;
+
+ omap_set_lcd_dma_b1(lcdc.palette_phys,
+ lcdc.palette_size / 4 + 1, 1, OMAP_DMA_DATA_TYPE_S32);
+
+ omap_set_lcd_dma_single_transfer(1);
+ omap_setup_lcd_dma();
+
+ init_completion(&lcdc.palette_load_complete);
+ enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+ set_load_mode(OMAP_LCDC_LOAD_PALETTE);
+ enable_controller();
+ if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
+ msecs_to_jiffies(500)))
+ dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
+ /* The controller gets disabled in the irq handler */
+ disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
+ omap_stop_lcd_dma();
+
+ omap_set_lcd_dma_single_transfer(lcdc.ext_mode);
+}
+
+/* Used only in internal controller mode */
+static int omap_lcdc_setcolreg(u_int regno, u16 red, u16 green, u16 blue,
+ u16 transp, int update_hw_pal)
+{
+ u16 *palette;
+
+ if (lcdc.color_mode != OMAPFB_COLOR_CLUT_8BPP || regno > 255)
+ return -EINVAL;
+
+ palette = (u16 *)lcdc.palette_virt;
+
+ palette[regno] &= ~0x0fff;
+ palette[regno] |= ((red >> 12) << 8) | ((green >> 12) << 4 ) |
+ (blue >> 12);
+
+ if (update_hw_pal) {
+ disable_controller();
+ omap_stop_lcd_dma();
+ load_palette();
+ setup_lcd_dma();
+ set_load_mode(OMAP_LCDC_LOAD_FRAME);
+ enable_controller();
+ }
+
+ return 0;
+}
+
+static void calc_ck_div(int is_tft, int pck, int *pck_div)
+{
+ unsigned long lck;
+
+ pck = max(1, pck);
+ lck = clk_get_rate(lcdc.lcd_ck);
+ *pck_div = (lck + pck - 1) / pck;
+ if (is_tft)
+ *pck_div = max(2, *pck_div);
+ else
+ *pck_div = max(3, *pck_div);
+ if (*pck_div > 255) {
+ /* FIXME: try to adjust logic clock divider as well */
+ *pck_div = 255;
+ dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
+ pck / 1000);
+ }
+}
+
+static void inline setup_regs(void)
+{
+ u32 l;
+ struct lcd_panel *panel = lcdc.fbdev->panel;
+ int is_tft = panel->config & OMAP_LCDC_PANEL_TFT;
+ unsigned long lck;
+ int pcd;
+
+ l = omap_readl(OMAP_LCDC_CONTROL);
+ l &= ~OMAP_LCDC_CTRL_LCD_TFT;
+ l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0;
+#ifdef CONFIG_MACH_OMAP_PALMTE
+/* FIXME:if (machine_is_omap_palmte()) { */
+ /* PalmTE uses alternate TFT setting in 8BPP mode */
+ l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0;
+/* } */
+#endif
+ omap_writel(l, OMAP_LCDC_CONTROL);
+
+ l = omap_readl(OMAP_LCDC_TIMING2);
+ l &= ~(((1 << 6) - 1) << 20);
+ l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
+ omap_writel(l, OMAP_LCDC_TIMING2);
+
+ l = panel->x_res - 1;
+ l |= (panel->hsw - 1) << 10;
+ l |= (panel->hfp - 1) << 16;
+ l |= (panel->hbp - 1) << 24;
+ omap_writel(l, OMAP_LCDC_TIMING0);
+
+ l = panel->y_res - 1;
+ l |= (panel->vsw - 1) << 10;
+ l |= panel->vfp << 16;
+ l |= panel->vbp << 24;
+ omap_writel(l, OMAP_LCDC_TIMING1);
+
+ l = omap_readl(OMAP_LCDC_TIMING2);
+ l &= ~0xff;
+
+ lck = clk_get_rate(lcdc.lcd_ck);
+
+ if (!panel->pcd)
+ calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd);
+ else {
+ dev_warn(lcdc.fbdev->dev,
+ "Pixel clock divider value is obsolete.\n"
+ "Try to set pixel_clock to %lu and pcd to 0 "
+ "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
+ lck / panel->pcd / 1000, panel->name);
+
+ pcd = panel->pcd;
+ }
+ l |= pcd & 0xff;
+ l |= panel->acb << 8;
+ omap_writel(l, OMAP_LCDC_TIMING2);
+
+ /* update panel info with the exact clock */
+ panel->pixel_clock = lck / pcd / 1000;
+}
+
+/*
+ * Configure the LCD controller, download the color palette and start a looped
+ * DMA transfer of the frame image data. Called only in internal
+ * controller mode.
+ */
+static int omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
+{
+ int r = 0;
+
+ if (mode != lcdc.update_mode) {
+ switch (mode) {
+ case OMAPFB_AUTO_UPDATE:
+ setup_regs();
+ load_palette();
+
+ /* Setup and start LCD DMA */
+ setup_lcd_dma();
+
+ set_load_mode(OMAP_LCDC_LOAD_FRAME);
+ enable_irqs(OMAP_LCDC_IRQ_DONE);
+ /* This will start the actual DMA transfer */
+ enable_controller();
+ lcdc.update_mode = mode;
+ break;
+ case OMAPFB_UPDATE_DISABLED:
+ disable_controller();
+ omap_stop_lcd_dma();
+ lcdc.update_mode = mode;
+ break;
+ default:
+ r = -EINVAL;
+ }
+ }
+
+ return r;
+}
+
+static enum omapfb_update_mode omap_lcdc_get_update_mode(void)
+{
+ return lcdc.update_mode;
+}
+
+/* PM code called only in internal controller mode */
+static void omap_lcdc_suspend(void)
+{
+ if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+ disable_controller();
+ omap_stop_lcd_dma();
+ }
+}
+
+static void omap_lcdc_resume(void)
+{
+ if (lcdc.update_mode == OMAPFB_AUTO_UPDATE) {
+ setup_regs();
+ load_palette();
+ setup_lcd_dma();
+ set_load_mode(OMAP_LCDC_LOAD_FRAME);
+ enable_irqs(OMAP_LCDC_IRQ_DONE);
+ enable_controller();
+ }
+}
+
+static void omap_lcdc_get_caps(int plane, struct omapfb_caps *caps)
+{
+ return;
+}
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data)
+{
+ BUG_ON(callback == NULL);
+
+ if (lcdc.dma_callback)
+ return -EBUSY;
+ else {
+ lcdc.dma_callback = callback;
+ lcdc.dma_callback_data = data;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(omap_lcdc_set_dma_callback);
+
+void omap_lcdc_free_dma_callback(void)
+{
+ lcdc.dma_callback = NULL;
+}
+EXPORT_SYMBOL(omap_lcdc_free_dma_callback);
+
+static void lcdc_dma_handler(u16 status, void *data)
+{
+ if (lcdc.dma_callback)
+ lcdc.dma_callback(lcdc.dma_callback_data);
+}
+
+static int mmap_kern(void)
+{
+ struct vm_struct *kvma;
+ struct vm_area_struct vma;
+ pgprot_t pgprot;
+ unsigned long vaddr;
+
+ kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP);
+ if (kvma == NULL) {
+ dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n");
+ return -ENOMEM;
+ }
+ vma.vm_mm = &init_mm;
+
+ vaddr = (unsigned long)kvma->addr;
+ vma.vm_start = vaddr;
+ vma.vm_end = vaddr + lcdc.vram_size;
+
+ pgprot = pgprot_writecombine(pgprot_kernel);
+ if (io_remap_pfn_range(&vma, vaddr,
+ lcdc.vram_phys >> PAGE_SHIFT,
+ lcdc.vram_size, pgprot) < 0) {
+ dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n");
+ return -EAGAIN;
+ }
+
+ lcdc.vram_virt = (void *)vaddr;
+
+ return 0;
+}
+
+static void unmap_kern(void)
+{
+ vunmap(lcdc.vram_virt);
+}
+
+static int alloc_palette_ram(void)
+{
+ lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
+ MAX_PALETTE_SIZE, &lcdc.palette_phys, GFP_KERNEL);
+ if (lcdc.palette_virt == NULL) {
+ dev_err(lcdc.fbdev->dev, "failed to alloc palette memory\n");
+ return -ENOMEM;
+ }
+ memset(lcdc.palette_virt, 0, MAX_PALETTE_SIZE);
+
+ return 0;
+}
+
+static void free_palette_ram(void)
+{
+ dma_free_writecombine(lcdc.fbdev->dev, MAX_PALETTE_SIZE,
+ lcdc.palette_virt, lcdc.palette_phys);
+}
+
+static int alloc_fbmem(struct omapfb_mem_region *region)
+{
+ int bpp;
+ int frame_size;
+ struct lcd_panel *panel = lcdc.fbdev->panel;
+
+ bpp = panel->bpp;
+ if (bpp == 12)
+ bpp = 16;
+ frame_size = PAGE_ALIGN(panel->x_res * bpp / 8 * panel->y_res);
+ if (region->size > frame_size)
+ frame_size = region->size;
+ lcdc.vram_size = frame_size;
+ lcdc.vram_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
+ lcdc.vram_size, &lcdc.vram_phys, GFP_KERNEL);
+ if (lcdc.vram_virt == NULL) {
+ dev_err(lcdc.fbdev->dev, "unable to allocate FB DMA memory\n");
+ return -ENOMEM;
+ }
+ region->size = frame_size;
+ region->paddr = lcdc.vram_phys;
+ region->vaddr = lcdc.vram_virt;
+ region->alloc = 1;
+
+ memset(lcdc.vram_virt, 0, lcdc.vram_size);
+
+ return 0;
+}
+
+static void free_fbmem(void)
+{
+ dma_free_writecombine(lcdc.fbdev->dev, lcdc.vram_size,
+ lcdc.vram_virt, lcdc.vram_phys);
+}
+
+static int setup_fbmem(struct omapfb_mem_desc *req_md)
+{
+ int r;
+
+ if (!req_md->region_cnt) {
+ dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
+ return -EINVAL;
+ }
+
+ if (req_md->region_cnt > 1) {
+ dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
+ req_md->region_cnt = 1;
+ }
+
+ if (req_md->region[0].paddr == 0) {
+ lcdc.fbmem_allocated = 1;
+ if ((r = alloc_fbmem(&req_md->region[0])) < 0)
+ return r;
+ return 0;
+ }
+
+ lcdc.vram_phys = req_md->region[0].paddr;
+ lcdc.vram_size = req_md->region[0].size;
+
+ if ((r = mmap_kern()) < 0)
+ return r;
+
+ dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n",
+ lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt);
+
+ return 0;
+}
+
+static void cleanup_fbmem(void)
+{
+ if (lcdc.fbmem_allocated)
+ free_fbmem();
+ else
+ unmap_kern();
+}
+
+static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
+ struct omapfb_mem_desc *req_vram)
+{
+ int r;
+ u32 l;
+ int rate;
+ struct clk *tc_ck;
+
+ lcdc.irq_mask = 0;
+
+ lcdc.fbdev = fbdev;
+ lcdc.ext_mode = ext_mode;
+
+ l = 0;
+ omap_writel(l, OMAP_LCDC_CONTROL);
+
+ /* FIXME:
+ * According to errata some platforms have a clock rate limitiation
+ */
+ lcdc.lcd_ck = clk_get(NULL, "lcd_ck");
+ if (IS_ERR(lcdc.lcd_ck)) {
+ dev_err(fbdev->dev, "unable to access LCD clock\n");
+ r = PTR_ERR(lcdc.lcd_ck);
+ goto fail0;
+ }
+
+ tc_ck = clk_get(NULL, "tc_ck");
+ if (IS_ERR(tc_ck)) {
+ dev_err(fbdev->dev, "unable to access TC clock\n");
+ r = PTR_ERR(tc_ck);
+ goto fail1;
+ }
+
+ rate = clk_get_rate(tc_ck);
+ clk_put(tc_ck);
+
+ if (machine_is_ams_delta())
+ rate /= 4;
+ if (machine_is_omap_h3())
+ rate /= 3;
+ r = clk_set_rate(lcdc.lcd_ck, rate);
+ if (r) {
+ dev_err(fbdev->dev, "failed to adjust LCD rate\n");
+ goto fail1;
+ }
+ clk_enable(lcdc.lcd_ck);
+
+ r = request_irq(OMAP_LCDC_IRQ, lcdc_irq_handler, 0, MODULE_NAME, fbdev);
+ if (r) {
+ dev_err(fbdev->dev, "unable to get IRQ\n");
+ goto fail2;
+ }
+
+ r = omap_request_lcd_dma(lcdc_dma_handler, NULL);
+ if (r) {
+ dev_err(fbdev->dev, "unable to get LCD DMA\n");
+ goto fail3;
+ }
+
+ omap_set_lcd_dma_single_transfer(ext_mode);
+ omap_set_lcd_dma_ext_controller(ext_mode);
+
+ if (!ext_mode)
+ if ((r = alloc_palette_ram()) < 0)
+ goto fail4;
+
+ if ((r = setup_fbmem(req_vram)) < 0)
+ goto fail5;
+
+ pr_info("omapfb: LCDC initialized\n");
+
+ return 0;
+fail5:
+ if (!ext_mode)
+ free_palette_ram();
+fail4:
+ omap_free_lcd_dma();
+fail3:
+ free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
+fail2:
+ clk_disable(lcdc.lcd_ck);
+fail1:
+ clk_put(lcdc.lcd_ck);
+fail0:
+ return r;
+}
+
+static void omap_lcdc_cleanup(void)
+{
+ if (!lcdc.ext_mode)
+ free_palette_ram();
+ cleanup_fbmem();
+ omap_free_lcd_dma();
+ free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
+ clk_disable(lcdc.lcd_ck);
+ clk_put(lcdc.lcd_ck);
+}
+
+const struct lcd_ctrl omap1_int_ctrl = {
+ .name = "internal",
+ .init = omap_lcdc_init,
+ .cleanup = omap_lcdc_cleanup,
+ .get_caps = omap_lcdc_get_caps,
+ .set_update_mode = omap_lcdc_set_update_mode,
+ .get_update_mode = omap_lcdc_get_update_mode,
+ .update_window = NULL,
+ .suspend = omap_lcdc_suspend,
+ .resume = omap_lcdc_resume,
+ .setup_plane = omap_lcdc_setup_plane,
+ .enable_plane = omap_lcdc_enable_plane,
+ .setcolreg = omap_lcdc_setcolreg,
+};
diff --git a/drivers/video/omap/lcdc.h b/drivers/video/omap/lcdc.h
new file mode 100644
index 000000000000..adb731e5314a
--- /dev/null
+++ b/drivers/video/omap/lcdc.h
@@ -0,0 +1,7 @@
+#ifndef LCDC_H
+#define LCDC_H
+
+int omap_lcdc_set_dma_callback(void (*callback)(void *data), void *data);
+void omap_lcdc_free_dma_callback(void);
+
+#endif
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
new file mode 100644
index 000000000000..14d0f7a11145
--- /dev/null
+++ b/drivers/video/omap/omapfb_main.c
@@ -0,0 +1,1941 @@
+/*
+ * Framebuffer driver for TI OMAP boards
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * Acknowledgements:
+ * Alex McMains <aam@ridgerun.com> - Original driver
+ * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements
+ * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API
+ * Texas Instruments - H3 support
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#define MODULE_NAME "omapfb"
+
+static unsigned int def_accel;
+static unsigned long def_vram[OMAPFB_PLANE_NUM];
+static int def_vram_cnt;
+static unsigned long def_vxres;
+static unsigned long def_vyres;
+static unsigned int def_rotate;
+static unsigned int def_mirror;
+
+#ifdef CONFIG_FB_OMAP_MANUAL_UPDATE
+static int manual_update = 1;
+#else
+static int manual_update;
+#endif
+
+static struct platform_device *fbdev_pdev;
+static struct lcd_panel *fbdev_panel;
+static struct omapfb_device *omapfb_dev;
+
+struct caps_table_struct {
+ unsigned long flag;
+ const char *name;
+};
+
+static struct caps_table_struct ctrl_caps[] = {
+ { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" },
+ { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" },
+ { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" },
+ { OMAPFB_CAPS_PLANE_SCALE, "scale plane" },
+ { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" },
+ { OMAPFB_CAPS_WINDOW_SCALE, "scale window" },
+ { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" },
+ { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" },
+};
+
+static struct caps_table_struct color_caps[] = {
+ { 1 << OMAPFB_COLOR_RGB565, "RGB565", },
+ { 1 << OMAPFB_COLOR_YUV422, "YUV422", },
+ { 1 << OMAPFB_COLOR_YUV420, "YUV420", },
+ { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", },
+ { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", },
+ { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", },
+ { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", },
+ { 1 << OMAPFB_COLOR_RGB444, "RGB444", },
+ { 1 << OMAPFB_COLOR_YUY422, "YUY422", },
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD panel
+ * ---------------------------------------------------------------------------
+ */
+extern struct lcd_ctrl omap1_int_ctrl;
+extern struct lcd_ctrl omap2_int_ctrl;
+extern struct lcd_ctrl hwa742_ctrl;
+extern struct lcd_ctrl blizzard_ctrl;
+
+static struct lcd_ctrl *ctrls[] = {
+#ifdef CONFIG_ARCH_OMAP1
+ &omap1_int_ctrl,
+#else
+ &omap2_int_ctrl,
+#endif
+
+#ifdef CONFIG_FB_OMAP_LCDC_HWA742
+ &hwa742_ctrl,
+#endif
+#ifdef CONFIG_FB_OMAP_LCDC_BLIZZARD
+ &blizzard_ctrl,
+#endif
+};
+
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+#ifdef CONFIG_ARCH_OMAP1
+extern struct lcd_ctrl_extif omap1_ext_if;
+#else
+extern struct lcd_ctrl_extif omap2_ext_if;
+#endif
+#endif
+
+static void omapfb_rqueue_lock(struct omapfb_device *fbdev)
+{
+ mutex_lock(&fbdev->rqueue_mutex);
+}
+
+static void omapfb_rqueue_unlock(struct omapfb_device *fbdev)
+{
+ mutex_unlock(&fbdev->rqueue_mutex);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LCD controller and LCD DMA
+ * ---------------------------------------------------------------------------
+ */
+/* Lookup table to map elem size to elem type. */
+static const int dma_elem_type[] = {
+ 0,
+ OMAP_DMA_DATA_TYPE_S8,
+ OMAP_DMA_DATA_TYPE_S16,
+ 0,
+ OMAP_DMA_DATA_TYPE_S32,
+};
+
+/*
+ * Allocate resources needed for LCD controller and LCD DMA operations. Video
+ * memory is allocated from system memory according to the virtual display
+ * size, except if a bigger memory size is specified explicitly as a kernel
+ * parameter.
+ */
+static int ctrl_init(struct omapfb_device *fbdev)
+{
+ int r;
+ int i;
+
+ /* kernel/module vram parameters override boot tags/board config */
+ if (def_vram_cnt) {
+ for (i = 0; i < def_vram_cnt; i++)
+ fbdev->mem_desc.region[i].size =
+ PAGE_ALIGN(def_vram[i]);
+ fbdev->mem_desc.region_cnt = i;
+ } else {
+ struct omapfb_platform_data *conf;
+
+ conf = fbdev->dev->platform_data;
+ fbdev->mem_desc = conf->mem_desc;
+ }
+
+ if (!fbdev->mem_desc.region_cnt) {
+ struct lcd_panel *panel = fbdev->panel;
+ int def_size;
+ int bpp = panel->bpp;
+
+ /* 12 bpp is packed in 16 bits */
+ if (bpp == 12)
+ bpp = 16;
+ def_size = def_vxres * def_vyres * bpp / 8;
+ fbdev->mem_desc.region_cnt = 1;
+ fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size);
+ }
+ r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc);
+ if (r < 0) {
+ dev_err(fbdev->dev, "controller initialization failed (%d)\n",
+ r);
+ return r;
+ }
+
+#ifdef DEBUG
+ for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+ dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n",
+ i,
+ fbdev->mem_desc.region[i].paddr,
+ fbdev->mem_desc.region[i].vaddr,
+ fbdev->mem_desc.region[i].size);
+ }
+#endif
+ return 0;
+}
+
+static void ctrl_cleanup(struct omapfb_device *fbdev)
+{
+ fbdev->ctrl->cleanup();
+}
+
+/* Must be called with fbdev->rqueue_mutex held. */
+static int ctrl_change_mode(struct fb_info *fbi)
+{
+ int r;
+ unsigned long offset;
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct fb_var_screeninfo *var = &fbi->var;
+
+ offset = var->yoffset * fbi->fix.line_length +
+ var->xoffset * var->bits_per_pixel / 8;
+
+ if (fbdev->ctrl->sync)
+ fbdev->ctrl->sync();
+ r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out,
+ offset, var->xres_virtual,
+ plane->info.pos_x, plane->info.pos_y,
+ var->xres, var->yres, plane->color_mode);
+ if (fbdev->ctrl->set_scale != NULL)
+ r = fbdev->ctrl->set_scale(plane->idx,
+ var->xres, var->yres,
+ plane->info.out_width,
+ plane->info.out_height);
+
+ return r;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * fbdev framework callbacks and the ioctl interface
+ * ---------------------------------------------------------------------------
+ */
+/* Called each time the omapfb device is opened */
+static int omapfb_open(struct fb_info *info, int user)
+{
+ return 0;
+}
+
+static void omapfb_sync(struct fb_info *info);
+
+/* Called when the omapfb device is closed. We make sure that any pending
+ * gfx DMA operations are ended, before we return. */
+static int omapfb_release(struct fb_info *info, int user)
+{
+ omapfb_sync(info);
+ return 0;
+}
+
+/* Store a single color palette entry into a pseudo palette or the hardware
+ * palette if one is available. For now we support only 16bpp and thus store
+ * the entry only to the pseudo palette.
+ */
+static int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green,
+ u_int blue, u_int transp, int update_hw_pal)
+{
+ struct omapfb_plane_struct *plane = info->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct fb_var_screeninfo *var = &info->var;
+ int r = 0;
+
+ switch (plane->color_mode) {
+ case OMAPFB_COLOR_YUV422:
+ case OMAPFB_COLOR_YUV420:
+ case OMAPFB_COLOR_YUY422:
+ r = -EINVAL;
+ break;
+ case OMAPFB_COLOR_CLUT_8BPP:
+ case OMAPFB_COLOR_CLUT_4BPP:
+ case OMAPFB_COLOR_CLUT_2BPP:
+ case OMAPFB_COLOR_CLUT_1BPP:
+ if (fbdev->ctrl->setcolreg)
+ r = fbdev->ctrl->setcolreg(regno, red, green, blue,
+ transp, update_hw_pal);
+ /* Fallthrough */
+ case OMAPFB_COLOR_RGB565:
+ case OMAPFB_COLOR_RGB444:
+ if (r != 0)
+ break;
+
+ if (regno < 0) {
+ r = -EINVAL;
+ break;
+ }
+
+ if (regno < 16) {
+ u16 pal;
+ pal = ((red >> (16 - var->red.length)) <<
+ var->red.offset) |
+ ((green >> (16 - var->green.length)) <<
+ var->green.offset) |
+ (blue >> (16 - var->blue.length));
+ ((u32 *)(info->pseudo_palette))[regno] = pal;
+ }
+ break;
+ default:
+ BUG();
+ }
+ return r;
+}
+
+static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ return _setcolreg(info, regno, red, green, blue, transp, 1);
+}
+
+static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ int count, index, r;
+ u16 *red, *green, *blue, *transp;
+ u16 trans = 0xffff;
+
+ red = cmap->red;
+ green = cmap->green;
+ blue = cmap->blue;
+ transp = cmap->transp;
+ index = cmap->start;
+
+ for (count = 0; count < cmap->len; count++) {
+ if (transp)
+ trans = *transp++;
+ r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
+ count == cmap->len - 1);
+ if (r != 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int omapfb_update_full_screen(struct fb_info *fbi);
+
+static int omapfb_blank(int blank, struct fb_info *fbi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ int do_update = 0;
+ int r = 0;
+
+ omapfb_rqueue_lock(fbdev);
+ switch (blank) {
+ case VESA_NO_BLANKING:
+ if (fbdev->state == OMAPFB_SUSPENDED) {
+ if (fbdev->ctrl->resume)
+ fbdev->ctrl->resume();
+ fbdev->panel->enable(fbdev->panel);
+ fbdev->state = OMAPFB_ACTIVE;
+ if (fbdev->ctrl->get_update_mode() ==
+ OMAPFB_MANUAL_UPDATE)
+ do_update = 1;
+ }
+ break;
+ case VESA_POWERDOWN:
+ if (fbdev->state == OMAPFB_ACTIVE) {
+ fbdev->panel->disable(fbdev->panel);
+ if (fbdev->ctrl->suspend)
+ fbdev->ctrl->suspend();
+ fbdev->state = OMAPFB_SUSPENDED;
+ }
+ break;
+ default:
+ r = -EINVAL;
+ }
+ omapfb_rqueue_unlock(fbdev);
+
+ if (r == 0 && do_update)
+ r = omapfb_update_full_screen(fbi);
+
+ return r;
+}
+
+static void omapfb_sync(struct fb_info *fbi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+
+ omapfb_rqueue_lock(fbdev);
+ if (fbdev->ctrl->sync)
+ fbdev->ctrl->sync();
+ omapfb_rqueue_unlock(fbdev);
+}
+
+/*
+ * Set fb_info.fix fields and also updates fbdev.
+ * When calling this fb_info.var must be set up already.
+ */
+static void set_fb_fix(struct fb_info *fbi)
+{
+ struct fb_fix_screeninfo *fix = &fbi->fix;
+ struct fb_var_screeninfo *var = &fbi->var;
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_mem_region *rg;
+ int bpp;
+
+ rg = &plane->fbdev->mem_desc.region[plane->idx];
+ fbi->screen_base = (char __iomem *)rg->vaddr;
+ fix->smem_start = rg->paddr;
+ fix->smem_len = rg->size;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ bpp = var->bits_per_pixel;
+ if (var->nonstd)
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ else switch (var->bits_per_pixel) {
+ case 16:
+ case 12:
+ fix->visual = FB_VISUAL_TRUECOLOR;
+ /* 12bpp is stored in 16 bits */
+ bpp = 16;
+ break;
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ }
+ fix->accel = FB_ACCEL_OMAP1610;
+ fix->line_length = var->xres_virtual * bpp / 8;
+}
+
+static int set_color_mode(struct omapfb_plane_struct *plane,
+ struct fb_var_screeninfo *var)
+{
+ switch (var->nonstd) {
+ case 0:
+ break;
+ case OMAPFB_COLOR_YUV422:
+ var->bits_per_pixel = 16;
+ plane->color_mode = var->nonstd;
+ return 0;
+ case OMAPFB_COLOR_YUV420:
+ var->bits_per_pixel = 12;
+ plane->color_mode = var->nonstd;
+ return 0;
+ case OMAPFB_COLOR_YUY422:
+ var->bits_per_pixel = 16;
+ plane->color_mode = var->nonstd;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 1:
+ plane->color_mode = OMAPFB_COLOR_CLUT_1BPP;
+ return 0;
+ case 2:
+ plane->color_mode = OMAPFB_COLOR_CLUT_2BPP;
+ return 0;
+ case 4:
+ plane->color_mode = OMAPFB_COLOR_CLUT_4BPP;
+ return 0;
+ case 8:
+ plane->color_mode = OMAPFB_COLOR_CLUT_8BPP;
+ return 0;
+ case 12:
+ var->bits_per_pixel = 16;
+ plane->color_mode = OMAPFB_COLOR_RGB444;
+ return 0;
+ case 16:
+ plane->color_mode = OMAPFB_COLOR_RGB565;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * Check the values in var against our capabilities and in case of out of
+ * bound values try to adjust them.
+ */
+static int set_fb_var(struct fb_info *fbi,
+ struct fb_var_screeninfo *var)
+{
+ int bpp;
+ unsigned long max_frame_size;
+ unsigned long line_size;
+ int xres_min, xres_max;
+ int yres_min, yres_max;
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct lcd_panel *panel = fbdev->panel;
+
+ if (set_color_mode(plane, var) < 0)
+ return -EINVAL;
+
+ bpp = var->bits_per_pixel;
+ if (plane->color_mode == OMAPFB_COLOR_RGB444)
+ bpp = 16;
+
+ switch (var->rotate) {
+ case 0:
+ case 180:
+ xres_min = OMAPFB_PLANE_XRES_MIN;
+ xres_max = panel->x_res;
+ yres_min = OMAPFB_PLANE_YRES_MIN;
+ yres_max = panel->y_res;
+ if (cpu_is_omap15xx()) {
+ var->xres = panel->x_res;
+ var->yres = panel->y_res;
+ }
+ break;
+ case 90:
+ case 270:
+ xres_min = OMAPFB_PLANE_YRES_MIN;
+ xres_max = panel->y_res;
+ yres_min = OMAPFB_PLANE_XRES_MIN;
+ yres_max = panel->x_res;
+ if (cpu_is_omap15xx()) {
+ var->xres = panel->y_res;
+ var->yres = panel->x_res;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (var->xres < xres_min)
+ var->xres = xres_min;
+ if (var->yres < yres_min)
+ var->yres = yres_min;
+ if (var->xres > xres_max)
+ var->xres = xres_max;
+ if (var->yres > yres_max)
+ var->yres = yres_max;
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+ max_frame_size = fbdev->mem_desc.region[plane->idx].size;
+ line_size = var->xres_virtual * bpp / 8;
+ if (line_size * var->yres_virtual > max_frame_size) {
+ /* Try to keep yres_virtual first */
+ line_size = max_frame_size / var->yres_virtual;
+ var->xres_virtual = line_size * 8 / bpp;
+ if (var->xres_virtual < var->xres) {
+ /* Still doesn't fit. Shrink yres_virtual too */
+ var->xres_virtual = var->xres;
+ line_size = var->xres * bpp / 8;
+ var->yres_virtual = max_frame_size / line_size;
+ }
+ /* Recheck this, as the virtual size changed. */
+ if (var->xres_virtual < var->xres)
+ var->xres = var->xres_virtual;
+ if (var->yres_virtual < var->yres)
+ var->yres = var->yres_virtual;
+ if (var->xres < xres_min || var->yres < yres_min)
+ return -EINVAL;
+ }
+ if (var->xres + var->xoffset > var->xres_virtual)
+ var->xoffset = var->xres_virtual - var->xres;
+ if (var->yres + var->yoffset > var->yres_virtual)
+ var->yoffset = var->yres_virtual - var->yres;
+ line_size = var->xres * bpp / 8;
+
+ if (plane->color_mode == OMAPFB_COLOR_RGB444) {
+ var->red.offset = 8; var->red.length = 4;
+ var->red.msb_right = 0;
+ var->green.offset = 4; var->green.length = 4;
+ var->green.msb_right = 0;
+ var->blue.offset = 0; var->blue.length = 4;
+ var->blue.msb_right = 0;
+ } else {
+ var->red.offset = 11; var->red.length = 5;
+ var->red.msb_right = 0;
+ var->green.offset = 5; var->green.length = 6;
+ var->green.msb_right = 0;
+ var->blue.offset = 0; var->blue.length = 5;
+ var->blue.msb_right = 0;
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+
+ /* pixclock in ps, the rest in pixclock */
+ var->pixclock = 10000000 / (panel->pixel_clock / 100);
+ var->left_margin = panel->hfp;
+ var->right_margin = panel->hbp;
+ var->upper_margin = panel->vfp;
+ var->lower_margin = panel->vbp;
+ var->hsync_len = panel->hsw;
+ var->vsync_len = panel->vsw;
+
+ /* TODO: get these from panel->config */
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->sync = 0;
+
+ return 0;
+}
+
+
+/* Set rotation (0, 90, 180, 270 degree), and switch to the new mode. */
+static void omapfb_rotate(struct fb_info *fbi, int rotate)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+
+ omapfb_rqueue_lock(fbdev);
+ if (cpu_is_omap15xx() && rotate != fbi->var.rotate) {
+ struct fb_var_screeninfo *new_var = &fbdev->new_var;
+
+ memcpy(new_var, &fbi->var, sizeof(*new_var));
+ new_var->rotate = rotate;
+ if (set_fb_var(fbi, new_var) == 0 &&
+ memcmp(new_var, &fbi->var, sizeof(*new_var))) {
+ memcpy(&fbi->var, new_var, sizeof(*new_var));
+ ctrl_change_mode(fbi);
+ }
+ }
+ omapfb_rqueue_unlock(fbdev);
+}
+
+/*
+ * Set new x,y offsets in the virtual display for the visible area and switch
+ * to the new mode.
+ */
+static int omapfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *fbi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ int r = 0;
+
+ omapfb_rqueue_lock(fbdev);
+ if (var->xoffset != fbi->var.xoffset ||
+ var->yoffset != fbi->var.yoffset) {
+ struct fb_var_screeninfo *new_var = &fbdev->new_var;
+
+ memcpy(new_var, &fbi->var, sizeof(*new_var));
+ new_var->xoffset = var->xoffset;
+ new_var->yoffset = var->yoffset;
+ if (set_fb_var(fbi, new_var))
+ r = -EINVAL;
+ else {
+ memcpy(&fbi->var, new_var, sizeof(*new_var));
+ ctrl_change_mode(fbi);
+ }
+ }
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+/* Set mirror to vertical axis and switch to the new mode. */
+static int omapfb_mirror(struct fb_info *fbi, int mirror)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ int r = 0;
+
+ omapfb_rqueue_lock(fbdev);
+ mirror = mirror ? 1 : 0;
+ if (cpu_is_omap15xx())
+ r = -EINVAL;
+ else if (mirror != plane->info.mirror) {
+ plane->info.mirror = mirror;
+ r = ctrl_change_mode(fbi);
+ }
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+/*
+ * Check values in var, try to adjust them in case of out of bound values if
+ * possible, or return error.
+ */
+static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ if (fbdev->ctrl->sync != NULL)
+ fbdev->ctrl->sync();
+ r = set_fb_var(fbi, var);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+/*
+ * Switch to a new mode. The parameters for it has been check already by
+ * omapfb_check_var.
+ */
+static int omapfb_set_par(struct fb_info *fbi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ int r = 0;
+
+ omapfb_rqueue_lock(fbdev);
+ set_fb_fix(fbi);
+ r = ctrl_change_mode(fbi);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+int omapfb_update_window_async(struct fb_info *fbi,
+ struct omapfb_update_window *win,
+ void (*callback)(void *),
+ void *callback_data)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct fb_var_screeninfo *var;
+
+ var = &fbi->var;
+ if (win->x >= var->xres || win->y >= var->yres ||
+ win->out_x > var->xres || win->out_y >= var->yres)
+ return -EINVAL;
+
+ if (!fbdev->ctrl->update_window ||
+ fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
+ return -ENODEV;
+
+ if (win->x + win->width >= var->xres)
+ win->width = var->xres - win->x;
+ if (win->y + win->height >= var->yres)
+ win->height = var->yres - win->y;
+ /* The out sizes should be cropped to the LCD size */
+ if (win->out_x + win->out_width > fbdev->panel->x_res)
+ win->out_width = fbdev->panel->x_res - win->out_x;
+ if (win->out_y + win->out_height > fbdev->panel->y_res)
+ win->out_height = fbdev->panel->y_res - win->out_y;
+ if (!win->width || !win->height || !win->out_width || !win->out_height)
+ return 0;
+
+ return fbdev->ctrl->update_window(fbi, win, callback, callback_data);
+}
+EXPORT_SYMBOL(omapfb_update_window_async);
+
+static int omapfb_update_win(struct fb_info *fbi,
+ struct omapfb_update_window *win)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ int ret;
+
+ omapfb_rqueue_lock(plane->fbdev);
+ ret = omapfb_update_window_async(fbi, win, NULL, 0);
+ omapfb_rqueue_unlock(plane->fbdev);
+
+ return ret;
+}
+
+static int omapfb_update_full_screen(struct fb_info *fbi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct omapfb_update_window win;
+ int r;
+
+ if (!fbdev->ctrl->update_window ||
+ fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE)
+ return -ENODEV;
+
+ win.x = 0;
+ win.y = 0;
+ win.width = fbi->var.xres;
+ win.height = fbi->var.yres;
+ win.out_x = 0;
+ win.out_y = 0;
+ win.out_width = fbi->var.xres;
+ win.out_height = fbi->var.yres;
+ win.format = 0;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->update_window(fbi, &win, NULL, 0);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct lcd_panel *panel = fbdev->panel;
+ struct omapfb_plane_info old_info;
+ int r = 0;
+
+ if (pi->pos_x + pi->out_width > panel->x_res ||
+ pi->pos_y + pi->out_height > panel->y_res)
+ return -EINVAL;
+
+ omapfb_rqueue_lock(fbdev);
+ if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) {
+ /*
+ * This plane's memory was freed, can't enable it
+ * until it's reallocated.
+ */
+ r = -EINVAL;
+ goto out;
+ }
+ old_info = plane->info;
+ plane->info = *pi;
+ if (pi->enabled) {
+ r = ctrl_change_mode(fbi);
+ if (r < 0) {
+ plane->info = old_info;
+ goto out;
+ }
+ }
+ r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled);
+ if (r < 0) {
+ plane->info = old_info;
+ goto out;
+ }
+out:
+ omapfb_rqueue_unlock(fbdev);
+ return r;
+}
+
+static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+
+ *pi = plane->info;
+ return 0;
+}
+
+static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx];
+ size_t size;
+ int r = 0;
+
+ if (fbdev->ctrl->setup_mem == NULL)
+ return -ENODEV;
+ if (mi->type > OMAPFB_MEMTYPE_MAX)
+ return -EINVAL;
+
+ size = PAGE_ALIGN(mi->size);
+ omapfb_rqueue_lock(fbdev);
+ if (plane->info.enabled) {
+ r = -EBUSY;
+ goto out;
+ }
+ if (rg->size != size || rg->type != mi->type) {
+ struct fb_var_screeninfo *new_var = &fbdev->new_var;
+ unsigned long old_size = rg->size;
+ u8 old_type = rg->type;
+ unsigned long paddr;
+
+ rg->size = size;
+ rg->type = mi->type;
+ /*
+ * size == 0 is a special case, for which we
+ * don't check / adjust the screen parameters.
+ * This isn't a problem since the plane can't
+ * be reenabled unless its size is > 0.
+ */
+ if (old_size != size && size) {
+ if (size) {
+ memcpy(new_var, &fbi->var, sizeof(*new_var));
+ r = set_fb_var(fbi, new_var);
+ if (r < 0)
+ goto out;
+ }
+ }
+
+ if (fbdev->ctrl->sync)
+ fbdev->ctrl->sync();
+ r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr);
+ if (r < 0) {
+ /* Revert changes. */
+ rg->size = old_size;
+ rg->type = old_type;
+ goto out;
+ }
+ rg->paddr = paddr;
+
+ if (old_size != size) {
+ if (size) {
+ memcpy(&fbi->var, new_var, sizeof(fbi->var));
+ set_fb_fix(fbi);
+ } else {
+ /*
+ * Set these explicitly to indicate that the
+ * plane memory is dealloce'd, the other
+ * screen parameters in var / fix are invalid.
+ */
+ fbi->fix.smem_start = 0;
+ fbi->fix.smem_len = 0;
+ }
+ }
+ }
+out:
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct omapfb_mem_region *rg;
+
+ rg = &fbdev->mem_desc.region[plane->idx];
+ memset(mi, 0, sizeof(*mi));
+ mi->size = rg->size;
+ mi->type = rg->type;
+
+ return 0;
+}
+
+static int omapfb_set_color_key(struct omapfb_device *fbdev,
+ struct omapfb_color_key *ck)
+{
+ int r;
+
+ if (!fbdev->ctrl->set_color_key)
+ return -ENODEV;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->set_color_key(ck);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static int omapfb_get_color_key(struct omapfb_device *fbdev,
+ struct omapfb_color_key *ck)
+{
+ int r;
+
+ if (!fbdev->ctrl->get_color_key)
+ return -ENODEV;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->get_color_key(ck);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM];
+static int notifier_inited;
+
+static void omapfb_init_notifier(void)
+{
+ int i;
+
+ for (i = 0; i < OMAPFB_PLANE_NUM; i++)
+ BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]);
+}
+
+int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
+ omapfb_notifier_callback_t callback,
+ void *callback_data)
+{
+ int r;
+
+ if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
+ return -EINVAL;
+
+ if (!notifier_inited) {
+ omapfb_init_notifier();
+ notifier_inited = 1;
+ }
+
+ omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *,
+ unsigned long, void *))callback;
+ omapfb_nb->data = callback_data;
+ r = blocking_notifier_chain_register(
+ &omapfb_client_list[omapfb_nb->plane_idx],
+ &omapfb_nb->nb);
+ if (r)
+ return r;
+ if (omapfb_dev != NULL &&
+ omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) {
+ omapfb_dev->ctrl->bind_client(omapfb_nb);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(omapfb_register_client);
+
+int omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb)
+{
+ return blocking_notifier_chain_unregister(
+ &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb);
+}
+EXPORT_SYMBOL(omapfb_unregister_client);
+
+void omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event)
+{
+ int i;
+
+ if (!notifier_inited)
+ /* no client registered yet */
+ return;
+
+ for (i = 0; i < OMAPFB_PLANE_NUM; i++)
+ blocking_notifier_call_chain(&omapfb_client_list[i], event,
+ fbdev->fb_info[i]);
+}
+EXPORT_SYMBOL(omapfb_notify_clients);
+
+static int omapfb_set_update_mode(struct omapfb_device *fbdev,
+ enum omapfb_update_mode mode)
+{
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->set_update_mode(mode);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev)
+{
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->get_update_mode();
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+static void omapfb_get_caps(struct omapfb_device *fbdev, int plane,
+ struct omapfb_caps *caps)
+{
+ memset(caps, 0, sizeof(*caps));
+ fbdev->ctrl->get_caps(plane, caps);
+ caps->ctrl |= fbdev->panel->get_caps(fbdev->panel);
+}
+
+/* For lcd testing */
+void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval)
+{
+ omapfb_rqueue_lock(fbdev);
+ *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval;
+ if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) {
+ struct omapfb_update_window win;
+
+ memset(&win, 0, sizeof(win));
+ win.width = 2;
+ win.height = 2;
+ win.out_width = 2;
+ win.out_height = 2;
+ fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, 0);
+ }
+ omapfb_rqueue_unlock(fbdev);
+}
+EXPORT_SYMBOL(omapfb_write_first_pixel);
+
+/*
+ * Ioctl interface. Part of the kernel mode frame buffer API is duplicated
+ * here to be accessible by user mode code.
+ */
+static int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+ unsigned long arg)
+{
+ struct omapfb_plane_struct *plane = fbi->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ struct fb_ops *ops = fbi->fbops;
+ union {
+ struct omapfb_update_window update_window;
+ struct omapfb_plane_info plane_info;
+ struct omapfb_mem_info mem_info;
+ struct omapfb_color_key color_key;
+ enum omapfb_update_mode update_mode;
+ struct omapfb_caps caps;
+ unsigned int mirror;
+ int plane_out;
+ int enable_plane;
+ } p;
+ int r = 0;
+
+ BUG_ON(!ops);
+ switch (cmd) {
+ case OMAPFB_MIRROR:
+ if (get_user(p.mirror, (int __user *)arg))
+ r = -EFAULT;
+ else
+ omapfb_mirror(fbi, p.mirror);
+ break;
+ case OMAPFB_SYNC_GFX:
+ omapfb_sync(fbi);
+ break;
+ case OMAPFB_VSYNC:
+ break;
+ case OMAPFB_SET_UPDATE_MODE:
+ if (get_user(p.update_mode, (int __user *)arg))
+ r = -EFAULT;
+ else
+ r = omapfb_set_update_mode(fbdev, p.update_mode);
+ break;
+ case OMAPFB_GET_UPDATE_MODE:
+ p.update_mode = omapfb_get_update_mode(fbdev);
+ if (put_user(p.update_mode,
+ (enum omapfb_update_mode __user *)arg))
+ r = -EFAULT;
+ break;
+ case OMAPFB_UPDATE_WINDOW_OLD:
+ if (copy_from_user(&p.update_window, (void __user *)arg,
+ sizeof(struct omapfb_update_window_old)))
+ r = -EFAULT;
+ else {
+ struct omapfb_update_window *u = &p.update_window;
+ u->out_x = u->x;
+ u->out_y = u->y;
+ u->out_width = u->width;
+ u->out_height = u->height;
+ memset(u->reserved, 0, sizeof(u->reserved));
+ r = omapfb_update_win(fbi, u);
+ }
+ break;
+ case OMAPFB_UPDATE_WINDOW:
+ if (copy_from_user(&p.update_window, (void __user *)arg,
+ sizeof(p.update_window)))
+ r = -EFAULT;
+ else
+ r = omapfb_update_win(fbi, &p.update_window);
+ break;
+ case OMAPFB_SETUP_PLANE:
+ if (copy_from_user(&p.plane_info, (void __user *)arg,
+ sizeof(p.plane_info)))
+ r = -EFAULT;
+ else
+ r = omapfb_setup_plane(fbi, &p.plane_info);
+ break;
+ case OMAPFB_QUERY_PLANE:
+ if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0)
+ break;
+ if (copy_to_user((void __user *)arg, &p.plane_info,
+ sizeof(p.plane_info)))
+ r = -EFAULT;
+ break;
+ case OMAPFB_SETUP_MEM:
+ if (copy_from_user(&p.mem_info, (void __user *)arg,
+ sizeof(p.mem_info)))
+ r = -EFAULT;
+ else
+ r = omapfb_setup_mem(fbi, &p.mem_info);
+ break;
+ case OMAPFB_QUERY_MEM:
+ if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0)
+ break;
+ if (copy_to_user((void __user *)arg, &p.mem_info,
+ sizeof(p.mem_info)))
+ r = -EFAULT;
+ break;
+ case OMAPFB_SET_COLOR_KEY:
+ if (copy_from_user(&p.color_key, (void __user *)arg,
+ sizeof(p.color_key)))
+ r = -EFAULT;
+ else
+ r = omapfb_set_color_key(fbdev, &p.color_key);
+ break;
+ case OMAPFB_GET_COLOR_KEY:
+ if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0)
+ break;
+ if (copy_to_user((void __user *)arg, &p.color_key,
+ sizeof(p.color_key)))
+ r = -EFAULT;
+ break;
+ case OMAPFB_GET_CAPS:
+ omapfb_get_caps(fbdev, plane->idx, &p.caps);
+ if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
+ r = -EFAULT;
+ break;
+ case OMAPFB_LCD_TEST:
+ {
+ int test_num;
+
+ if (get_user(test_num, (int __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
+ if (!fbdev->panel->run_test) {
+ r = -EINVAL;
+ break;
+ }
+ r = fbdev->panel->run_test(fbdev->panel, test_num);
+ break;
+ }
+ case OMAPFB_CTRL_TEST:
+ {
+ int test_num;
+
+ if (get_user(test_num, (int __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
+ if (!fbdev->ctrl->run_test) {
+ r = -EINVAL;
+ break;
+ }
+ r = fbdev->ctrl->run_test(test_num);
+ break;
+ }
+ default:
+ r = -EINVAL;
+ }
+
+ return r;
+}
+
+static int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ struct omapfb_plane_struct *plane = info->par;
+ struct omapfb_device *fbdev = plane->fbdev;
+ int r;
+
+ omapfb_rqueue_lock(fbdev);
+ r = fbdev->ctrl->mmap(info, vma);
+ omapfb_rqueue_unlock(fbdev);
+
+ return r;
+}
+
+/*
+ * Callback table for the frame buffer framework. Some of these pointers
+ * will be changed according to the current setting of fb_info->accel_flags.
+ */
+static struct fb_ops omapfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = omapfb_open,
+ .fb_release = omapfb_release,
+ .fb_setcolreg = omapfb_setcolreg,
+ .fb_setcmap = omapfb_setcmap,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = omapfb_blank,
+ .fb_ioctl = omapfb_ioctl,
+ .fb_check_var = omapfb_check_var,
+ .fb_set_par = omapfb_set_par,
+ .fb_rotate = omapfb_rotate,
+ .fb_pan_display = omapfb_pan_display,
+};
+
+/*
+ * ---------------------------------------------------------------------------
+ * Sysfs interface
+ * ---------------------------------------------------------------------------
+ */
+/* omapfbX sysfs entries */
+static ssize_t omapfb_show_caps_num(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int plane;
+ size_t size;
+ struct omapfb_caps caps;
+
+ plane = 0;
+ size = 0;
+ while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
+ omapfb_get_caps(fbdev, plane, &caps);
+ size += snprintf(&buf[size], PAGE_SIZE - size,
+ "plane#%d %#010x %#010x %#010x\n",
+ plane, caps.ctrl, caps.plane_color, caps.wnd_color);
+ plane++;
+ }
+ return size;
+}
+
+static ssize_t omapfb_show_caps_text(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int i;
+ struct omapfb_caps caps;
+ int plane;
+ size_t size;
+
+ plane = 0;
+ size = 0;
+ while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) {
+ omapfb_get_caps(fbdev, plane, &caps);
+ size += snprintf(&buf[size], PAGE_SIZE - size,
+ "plane#%d:\n", plane);
+ for (i = 0; i < ARRAY_SIZE(ctrl_caps) &&
+ size < PAGE_SIZE; i++) {
+ if (ctrl_caps[i].flag & caps.ctrl)
+ size += snprintf(&buf[size], PAGE_SIZE - size,
+ " %s\n", ctrl_caps[i].name);
+ }
+ size += snprintf(&buf[size], PAGE_SIZE - size,
+ " plane colors:\n");
+ for (i = 0; i < ARRAY_SIZE(color_caps) &&
+ size < PAGE_SIZE; i++) {
+ if (color_caps[i].flag & caps.plane_color)
+ size += snprintf(&buf[size], PAGE_SIZE - size,
+ " %s\n", color_caps[i].name);
+ }
+ size += snprintf(&buf[size], PAGE_SIZE - size,
+ " window colors:\n");
+ for (i = 0; i < ARRAY_SIZE(color_caps) &&
+ size < PAGE_SIZE; i++) {
+ if (color_caps[i].flag & caps.wnd_color)
+ size += snprintf(&buf[size], PAGE_SIZE - size,
+ " %s\n", color_caps[i].name);
+ }
+
+ plane++;
+ }
+ return size;
+}
+
+static DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL);
+static DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL);
+
+/* panel sysfs entries */
+static ssize_t omapfb_show_panel_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name);
+}
+
+static ssize_t omapfb_show_bklight_level(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int r;
+
+ if (fbdev->panel->get_bklight_level) {
+ r = snprintf(buf, PAGE_SIZE, "%d\n",
+ fbdev->panel->get_bklight_level(fbdev->panel));
+ } else
+ r = -ENODEV;
+ return r;
+}
+
+static ssize_t omapfb_store_bklight_level(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int r;
+
+ if (fbdev->panel->set_bklight_level) {
+ unsigned int level;
+
+ if (sscanf(buf, "%10d", &level) == 1) {
+ r = fbdev->panel->set_bklight_level(fbdev->panel,
+ level);
+ } else
+ r = -EINVAL;
+ } else
+ r = -ENODEV;
+ return r ? r : size;
+}
+
+static ssize_t omapfb_show_bklight_max(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+ int r;
+
+ if (fbdev->panel->get_bklight_level) {
+ r = snprintf(buf, PAGE_SIZE, "%d\n",
+ fbdev->panel->get_bklight_max(fbdev->panel));
+ } else
+ r = -ENODEV;
+ return r;
+}
+
+static struct device_attribute dev_attr_panel_name =
+ __ATTR(name, 0444, omapfb_show_panel_name, NULL);
+static DEVICE_ATTR(backlight_level, 0664,
+ omapfb_show_bklight_level, omapfb_store_bklight_level);
+static DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL);
+
+static struct attribute *panel_attrs[] = {
+ &dev_attr_panel_name.attr,
+ &dev_attr_backlight_level.attr,
+ &dev_attr_backlight_max.attr,
+ NULL,
+};
+
+static struct attribute_group panel_attr_grp = {
+ .name = "panel",
+ .attrs = panel_attrs,
+};
+
+/* ctrl sysfs entries */
+static ssize_t omapfb_show_ctrl_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omapfb_device *fbdev = (struct omapfb_device *)dev->driver_data;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name);
+}
+
+static struct device_attribute dev_attr_ctrl_name =
+ __ATTR(name, 0444, omapfb_show_ctrl_name, NULL);
+
+static struct attribute *ctrl_attrs[] = {
+ &dev_attr_ctrl_name.attr,
+ NULL,
+};
+
+static struct attribute_group ctrl_attr_grp = {
+ .name = "ctrl",
+ .attrs = ctrl_attrs,
+};
+
+static int omapfb_register_sysfs(struct omapfb_device *fbdev)
+{
+ int r;
+
+ if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num)))
+ goto fail0;
+
+ if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text)))
+ goto fail1;
+
+ if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp)))
+ goto fail2;
+
+ if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp)))
+ goto fail3;
+
+ return 0;
+fail3:
+ sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+fail2:
+ device_remove_file(fbdev->dev, &dev_attr_caps_text);
+fail1:
+ device_remove_file(fbdev->dev, &dev_attr_caps_num);
+fail0:
+ dev_err(fbdev->dev, "unable to register sysfs interface\n");
+ return r;
+}
+
+static void omapfb_unregister_sysfs(struct omapfb_device *fbdev)
+{
+ sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp);
+ sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp);
+ device_remove_file(fbdev->dev, &dev_attr_caps_num);
+ device_remove_file(fbdev->dev, &dev_attr_caps_text);
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * LDM callbacks
+ * ---------------------------------------------------------------------------
+ */
+/* Initialize system fb_info object and set the default video mode.
+ * The frame buffer memory already allocated by lcddma_init
+ */
+static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ int r = 0;
+
+ info->fbops = &omapfb_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ strncpy(fix->id, MODULE_NAME, sizeof(fix->id));
+
+ info->pseudo_palette = fbdev->pseudo_palette;
+
+ var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0;
+ var->xres = def_vxres;
+ var->yres = def_vyres;
+ var->xres_virtual = def_vxres;
+ var->yres_virtual = def_vyres;
+ var->rotate = def_rotate;
+ var->bits_per_pixel = fbdev->panel->bpp;
+
+ set_fb_var(info, var);
+ set_fb_fix(info);
+
+ r = fb_alloc_cmap(&info->cmap, 16, 0);
+ if (r != 0)
+ dev_err(fbdev->dev, "unable to allocate color map memory\n");
+
+ return r;
+}
+
+/* Release the fb_info object */
+static void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi)
+{
+ fb_dealloc_cmap(&fbi->cmap);
+}
+
+static void planes_cleanup(struct omapfb_device *fbdev)
+{
+ int i;
+
+ for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+ if (fbdev->fb_info[i] == NULL)
+ break;
+ fbinfo_cleanup(fbdev, fbdev->fb_info[i]);
+ framebuffer_release(fbdev->fb_info[i]);
+ }
+}
+
+static int planes_init(struct omapfb_device *fbdev)
+{
+ struct fb_info *fbi;
+ int i;
+ int r;
+
+ for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+ struct omapfb_plane_struct *plane;
+ fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct),
+ fbdev->dev);
+ if (fbi == NULL) {
+ dev_err(fbdev->dev,
+ "unable to allocate memory for plane info\n");
+ planes_cleanup(fbdev);
+ return -ENOMEM;
+ }
+ plane = fbi->par;
+ plane->idx = i;
+ plane->fbdev = fbdev;
+ plane->info.mirror = def_mirror;
+ fbdev->fb_info[i] = fbi;
+
+ if ((r = fbinfo_init(fbdev, fbi)) < 0) {
+ framebuffer_release(fbi);
+ planes_cleanup(fbdev);
+ return r;
+ }
+ plane->info.out_width = fbi->var.xres;
+ plane->info.out_height = fbi->var.yres;
+ }
+ return 0;
+}
+
+/*
+ * Free driver resources. Can be called to rollback an aborted initialization
+ * sequence.
+ */
+static void omapfb_free_resources(struct omapfb_device *fbdev, int state)
+{
+ int i;
+
+ switch (state) {
+ case OMAPFB_ACTIVE:
+ for (i = 0; i < fbdev->mem_desc.region_cnt; i++)
+ unregister_framebuffer(fbdev->fb_info[i]);
+ case 7:
+ omapfb_unregister_sysfs(fbdev);
+ case 6:
+ fbdev->panel->disable(fbdev->panel);
+ case 5:
+ omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED);
+ case 4:
+ planes_cleanup(fbdev);
+ case 3:
+ ctrl_cleanup(fbdev);
+ case 2:
+ fbdev->panel->cleanup(fbdev->panel);
+ case 1:
+ dev_set_drvdata(fbdev->dev, NULL);
+ kfree(fbdev);
+ case 0:
+ /* nothing to free */
+ break;
+ default:
+ BUG();
+ }
+}
+
+static int omapfb_find_ctrl(struct omapfb_device *fbdev)
+{
+ struct omapfb_platform_data *conf;
+ char name[17];
+ int i;
+
+ conf = fbdev->dev->platform_data;
+
+ fbdev->ctrl = NULL;
+
+ strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1);
+ name[sizeof(name) - 1] = '\0';
+
+ if (strcmp(name, "internal") == 0) {
+ fbdev->ctrl = fbdev->int_ctrl;
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ctrls); i++) {
+ dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name);
+ if (strcmp(ctrls[i]->name, name) == 0) {
+ fbdev->ctrl = ctrls[i];
+ break;
+ }
+ }
+
+ if (fbdev->ctrl == NULL) {
+ dev_dbg(fbdev->dev, "ctrl %s not supported\n", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void check_required_callbacks(struct omapfb_device *fbdev)
+{
+#define _C(x) (fbdev->ctrl->x != NULL)
+#define _P(x) (fbdev->panel->x != NULL)
+ BUG_ON(fbdev->ctrl == NULL || fbdev->panel == NULL);
+ BUG_ON(!(_C(init) && _C(cleanup) && _C(get_caps) &&
+ _C(set_update_mode) && _C(setup_plane) && _C(enable_plane) &&
+ _P(init) && _P(cleanup) && _P(enable) && _P(disable) &&
+ _P(get_caps)));
+#undef _P
+#undef _C
+}
+
+/*
+ * Called by LDM binding to probe and attach a new device.
+ * Initialization sequence:
+ * 1. allocate system omapfb_device structure
+ * 2. select controller type according to platform configuration
+ * init LCD panel
+ * 3. init LCD controller and LCD DMA
+ * 4. init system fb_info structure for all planes
+ * 5. setup video mode for first plane and enable it
+ * 6. enable LCD panel
+ * 7. register sysfs attributes
+ * OMAPFB_ACTIVE: register system fb_info structure for all planes
+ */
+static int omapfb_do_probe(struct platform_device *pdev,
+ struct lcd_panel *panel)
+{
+ struct omapfb_device *fbdev = NULL;
+ int init_state;
+ unsigned long phz, hhz, vhz;
+ unsigned long vram;
+ int i;
+ int r = 0;
+
+ init_state = 0;
+
+ if (pdev->num_resources != 0) {
+ dev_err(&pdev->dev, "probed for an unknown device\n");
+ r = -ENODEV;
+ goto cleanup;
+ }
+
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "missing platform data\n");
+ r = -ENOENT;
+ goto cleanup;
+ }
+
+ fbdev = kzalloc(sizeof(struct omapfb_device), GFP_KERNEL);
+ if (fbdev == NULL) {
+ dev_err(&pdev->dev,
+ "unable to allocate memory for device info\n");
+ r = -ENOMEM;
+ goto cleanup;
+ }
+ init_state++;
+
+ fbdev->dev = &pdev->dev;
+ fbdev->panel = panel;
+ platform_set_drvdata(pdev, fbdev);
+
+ mutex_init(&fbdev->rqueue_mutex);
+
+#ifdef CONFIG_ARCH_OMAP1
+ fbdev->int_ctrl = &omap1_int_ctrl;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ fbdev->ext_if = &omap1_ext_if;
+#endif
+#else /* OMAP2 */
+ fbdev->int_ctrl = &omap2_int_ctrl;
+#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL
+ fbdev->ext_if = &omap2_ext_if;
+#endif
+#endif
+ if (omapfb_find_ctrl(fbdev) < 0) {
+ dev_err(fbdev->dev,
+ "LCD controller not found, board not supported\n");
+ r = -ENODEV;
+ goto cleanup;
+ }
+
+ r = fbdev->panel->init(fbdev->panel, fbdev);
+ if (r)
+ goto cleanup;
+
+ pr_info("omapfb: configured for panel %s\n", fbdev->panel->name);
+
+ def_vxres = def_vxres ? : fbdev->panel->x_res;
+ def_vyres = def_vyres ? : fbdev->panel->y_res;
+
+ init_state++;
+
+ r = ctrl_init(fbdev);
+ if (r)
+ goto cleanup;
+ if (fbdev->ctrl->mmap != NULL)
+ omapfb_ops.fb_mmap = omapfb_mmap;
+ init_state++;
+
+ check_required_callbacks(fbdev);
+
+ r = planes_init(fbdev);
+ if (r)
+ goto cleanup;
+ init_state++;
+
+#ifdef CONFIG_FB_OMAP_DMA_TUNE
+ /* Set DMA priority for EMIFF access to highest */
+ if (cpu_class_is_omap1())
+ omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15);
+#endif
+
+ r = ctrl_change_mode(fbdev->fb_info[0]);
+ if (r) {
+ dev_err(fbdev->dev, "mode setting failed\n");
+ goto cleanup;
+ }
+
+ /* GFX plane is enabled by default */
+ r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1);
+ if (r)
+ goto cleanup;
+
+ omapfb_set_update_mode(fbdev, manual_update ?
+ OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE);
+ init_state++;
+
+ r = fbdev->panel->enable(fbdev->panel);
+ if (r)
+ goto cleanup;
+ init_state++;
+
+ r = omapfb_register_sysfs(fbdev);
+ if (r)
+ goto cleanup;
+ init_state++;
+
+ vram = 0;
+ for (i = 0; i < fbdev->mem_desc.region_cnt; i++) {
+ r = register_framebuffer(fbdev->fb_info[i]);
+ if (r != 0) {
+ dev_err(fbdev->dev,
+ "registering framebuffer %d failed\n", i);
+ goto cleanup;
+ }
+ vram += fbdev->mem_desc.region[i].size;
+ }
+
+ fbdev->state = OMAPFB_ACTIVE;
+
+ panel = fbdev->panel;
+ phz = panel->pixel_clock * 1000;
+ hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw);
+ vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw);
+
+ omapfb_dev = fbdev;
+
+ pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n",
+ vram, fbdev->mem_desc.region_cnt);
+ pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz "
+ "vfreq %lu.%lu Hz\n",
+ phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10);
+
+ return 0;
+
+cleanup:
+ omapfb_free_resources(fbdev, init_state);
+
+ return r;
+}
+
+static int omapfb_probe(struct platform_device *pdev)
+{
+ BUG_ON(fbdev_pdev != NULL);
+
+ /* Delay actual initialization until the LCD is registered */
+ fbdev_pdev = pdev;
+ if (fbdev_panel != NULL)
+ omapfb_do_probe(fbdev_pdev, fbdev_panel);
+ return 0;
+}
+
+void omapfb_register_panel(struct lcd_panel *panel)
+{
+ BUG_ON(fbdev_panel != NULL);
+
+ fbdev_panel = panel;
+ if (fbdev_pdev != NULL)
+ omapfb_do_probe(fbdev_pdev, fbdev_panel);
+}
+
+/* Called when the device is being detached from the driver */
+static int omapfb_remove(struct platform_device *pdev)
+{
+ struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+ enum omapfb_state saved_state = fbdev->state;
+
+ /* FIXME: wait till completion of pending events */
+
+ fbdev->state = OMAPFB_DISABLED;
+ omapfb_free_resources(fbdev, saved_state);
+
+ return 0;
+}
+
+/* PM suspend */
+static int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+
+ omapfb_blank(VESA_POWERDOWN, fbdev->fb_info[0]);
+
+ return 0;
+}
+
+/* PM resume */
+static int omapfb_resume(struct platform_device *pdev)
+{
+ struct omapfb_device *fbdev = platform_get_drvdata(pdev);
+
+ omapfb_blank(VESA_NO_BLANKING, fbdev->fb_info[0]);
+ return 0;
+}
+
+static struct platform_driver omapfb_driver = {
+ .probe = omapfb_probe,
+ .remove = omapfb_remove,
+ .suspend = omapfb_suspend,
+ .resume = omapfb_resume,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+#ifndef MODULE
+
+/* Process kernel command line parameters */
+static int __init omapfb_setup(char *options)
+{
+ char *this_opt = NULL;
+ int r = 0;
+
+ pr_debug("omapfb: options %s\n", options);
+
+ if (!options || !*options)
+ return 0;
+
+ while (!r && (this_opt = strsep(&options, ",")) != NULL) {
+ if (!strncmp(this_opt, "accel", 5))
+ def_accel = 1;
+ else if (!strncmp(this_opt, "vram:", 5)) {
+ char *suffix;
+ unsigned long vram;
+ vram = (simple_strtoul(this_opt + 5, &suffix, 0));
+ switch (suffix[0]) {
+ case '\0':
+ break;
+ case 'm':
+ case 'M':
+ vram *= 1024;
+ /* Fall through */
+ case 'k':
+ case 'K':
+ vram *= 1024;
+ break;
+ default:
+ pr_debug("omapfb: invalid vram suffix %c\n",
+ suffix[0]);
+ r = -1;
+ }
+ def_vram[def_vram_cnt++] = vram;
+ }
+ else if (!strncmp(this_opt, "vxres:", 6))
+ def_vxres = simple_strtoul(this_opt + 6, NULL, 0);
+ else if (!strncmp(this_opt, "vyres:", 6))
+ def_vyres = simple_strtoul(this_opt + 6, NULL, 0);
+ else if (!strncmp(this_opt, "rotate:", 7))
+ def_rotate = (simple_strtoul(this_opt + 7, NULL, 0));
+ else if (!strncmp(this_opt, "mirror:", 7))
+ def_mirror = (simple_strtoul(this_opt + 7, NULL, 0));
+ else if (!strncmp(this_opt, "manual_update", 13))
+ manual_update = 1;
+ else {
+ pr_debug("omapfb: invalid option\n");
+ r = -1;
+ }
+ }
+
+ return r;
+}
+
+#endif
+
+/* Register both the driver and the device */
+static int __init omapfb_init(void)
+{
+#ifndef MODULE
+ char *option;
+
+ if (fb_get_options("omapfb", &option))
+ return -ENODEV;
+ omapfb_setup(option);
+#endif
+ /* Register the driver with LDM */
+ if (platform_driver_register(&omapfb_driver)) {
+ pr_debug("failed to register omapfb driver\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit omapfb_cleanup(void)
+{
+ platform_driver_unregister(&omapfb_driver);
+}
+
+module_param_named(accel, def_accel, uint, 0664);
+module_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664);
+module_param_named(vxres, def_vxres, long, 0664);
+module_param_named(vyres, def_vyres, long, 0664);
+module_param_named(rotate, def_rotate, uint, 0664);
+module_param_named(mirror, def_mirror, uint, 0664);
+module_param_named(manual_update, manual_update, bool, 0664);
+
+module_init(omapfb_init);
+module_exit(omapfb_cleanup);
+
+MODULE_DESCRIPTION("TI OMAP framebuffer driver");
+MODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
new file mode 100644
index 000000000000..2b4269813b22
--- /dev/null
+++ b/drivers/video/omap/rfbi.c
@@ -0,0 +1,588 @@
+/*
+ * OMAP2 Remote Frame Buffer Interface support
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.com>
+ * Imre Deak <imre.deak@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/arch/omapfb.h>
+
+#include "dispc.h"
+
+/* To work around an RFBI transfer rate limitation */
+#define OMAP_RFBI_RATE_LIMIT 1
+
+#define RFBI_BASE 0x48050800
+#define RFBI_REVISION 0x0000
+#define RFBI_SYSCONFIG 0x0010
+#define RFBI_SYSSTATUS 0x0014
+#define RFBI_CONTROL 0x0040
+#define RFBI_PIXEL_CNT 0x0044
+#define RFBI_LINE_NUMBER 0x0048
+#define RFBI_CMD 0x004c
+#define RFBI_PARAM 0x0050
+#define RFBI_DATA 0x0054
+#define RFBI_READ 0x0058
+#define RFBI_STATUS 0x005c
+#define RFBI_CONFIG0 0x0060
+#define RFBI_ONOFF_TIME0 0x0064
+#define RFBI_CYCLE_TIME0 0x0068
+#define RFBI_DATA_CYCLE1_0 0x006c
+#define RFBI_DATA_CYCLE2_0 0x0070
+#define RFBI_DATA_CYCLE3_0 0x0074
+#define RFBI_VSYNC_WIDTH 0x0090
+#define RFBI_HSYNC_WIDTH 0x0094
+
+#define DISPC_BASE 0x48050400
+#define DISPC_CONTROL 0x0040
+
+static struct {
+ u32 base;
+ void (*lcdc_callback)(void *data);
+ void *lcdc_callback_data;
+ unsigned long l4_khz;
+ int bits_per_cycle;
+ struct omapfb_device *fbdev;
+ struct clk *dss_ick;
+ struct clk *dss1_fck;
+ unsigned tearsync_pin_cnt;
+ unsigned tearsync_mode;
+} rfbi;
+
+static inline void rfbi_write_reg(int idx, u32 val)
+{
+ __raw_writel(val, rfbi.base + idx);
+}
+
+static inline u32 rfbi_read_reg(int idx)
+{
+ return __raw_readl(rfbi.base + idx);
+}
+
+static int rfbi_get_clocks(void)
+{
+ if (IS_ERR((rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "dss_ick")))) {
+ dev_err(rfbi.fbdev->dev, "can't get dss_ick");
+ return PTR_ERR(rfbi.dss_ick);
+ }
+
+ if (IS_ERR((rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck")))) {
+ dev_err(rfbi.fbdev->dev, "can't get dss1_fck");
+ clk_put(rfbi.dss_ick);
+ return PTR_ERR(rfbi.dss1_fck);
+ }
+
+ return 0;
+}
+
+static void rfbi_put_clocks(void)
+{
+ clk_put(rfbi.dss1_fck);
+ clk_put(rfbi.dss_ick);
+}
+
+static void rfbi_enable_clocks(int enable)
+{
+ if (enable) {
+ clk_enable(rfbi.dss_ick);
+ clk_enable(rfbi.dss1_fck);
+ } else {
+ clk_disable(rfbi.dss1_fck);
+ clk_disable(rfbi.dss_ick);
+ }
+}
+
+
+#ifdef VERBOSE
+static void rfbi_print_timings(void)
+{
+ u32 l;
+ u32 time;
+
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ time = 1000000000 / rfbi.l4_khz;
+ if (l & (1 << 4))
+ time *= 2;
+
+ dev_dbg(rfbi.fbdev->dev, "Tick time %u ps\n", time);
+ l = rfbi_read_reg(RFBI_ONOFF_TIME0);
+ dev_dbg(rfbi.fbdev->dev,
+ "CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
+ "REONTIME %d, REOFFTIME %d\n",
+ l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
+ (l >> 20) & 0x0f, (l >> 24) & 0x3f);
+
+ l = rfbi_read_reg(RFBI_CYCLE_TIME0);
+ dev_dbg(rfbi.fbdev->dev,
+ "WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
+ "ACCESSTIME %d\n",
+ (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
+ (l >> 22) & 0x3f);
+}
+#else
+static void rfbi_print_timings(void) {}
+#endif
+
+static void rfbi_set_timings(const struct extif_timings *t)
+{
+ u32 l;
+
+ BUG_ON(!t->converted);
+
+ rfbi_enable_clocks(1);
+ rfbi_write_reg(RFBI_ONOFF_TIME0, t->tim[0]);
+ rfbi_write_reg(RFBI_CYCLE_TIME0, t->tim[1]);
+
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ l &= ~(1 << 4);
+ l |= (t->tim[2] ? 1 : 0) << 4;
+ rfbi_write_reg(RFBI_CONFIG0, l);
+
+ rfbi_print_timings();
+ rfbi_enable_clocks(0);
+}
+
+static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+ *clk_period = 1000000000 / rfbi.l4_khz;
+ *max_clk_div = 2;
+}
+
+static int ps_to_rfbi_ticks(int time, int div)
+{
+ unsigned long tick_ps;
+ int ret;
+
+ /* Calculate in picosecs to yield more exact results */
+ tick_ps = 1000000000 / (rfbi.l4_khz) * div;
+
+ ret = (time + tick_ps - 1) / tick_ps;
+
+ return ret;
+}
+
+#ifdef OMAP_RFBI_RATE_LIMIT
+static unsigned long rfbi_get_max_tx_rate(void)
+{
+ unsigned long l4_rate, dss1_rate;
+ int min_l4_ticks = 0;
+ int i;
+
+ /* According to TI this can't be calculated so make the
+ * adjustments for a couple of known frequencies and warn for
+ * others.
+ */
+ static const struct {
+ unsigned long l4_clk; /* HZ */
+ unsigned long dss1_clk; /* HZ */
+ unsigned long min_l4_ticks;
+ } ftab[] = {
+ { 55, 132, 7, }, /* 7.86 MPix/s */
+ { 110, 110, 12, }, /* 9.16 MPix/s */
+ { 110, 132, 10, }, /* 11 Mpix/s */
+ { 120, 120, 10, }, /* 12 Mpix/s */
+ { 133, 133, 10, }, /* 13.3 Mpix/s */
+ };
+
+ l4_rate = rfbi.l4_khz / 1000;
+ dss1_rate = clk_get_rate(rfbi.dss1_fck) / 1000000;
+
+ for (i = 0; i < ARRAY_SIZE(ftab); i++) {
+ /* Use a window instead of an exact match, to account
+ * for different DPLL multiplier / divider pairs.
+ */
+ if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
+ abs(ftab[i].dss1_clk - dss1_rate) < 3) {
+ min_l4_ticks = ftab[i].min_l4_ticks;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(ftab)) {
+ /* Can't be sure, return anyway the maximum not
+ * rate-limited. This might cause a problem only for the
+ * tearing synchronisation.
+ */
+ dev_err(rfbi.fbdev->dev,
+ "can't determine maximum RFBI transfer rate\n");
+ return rfbi.l4_khz * 1000;
+ }
+ return rfbi.l4_khz * 1000 / min_l4_ticks;
+}
+#else
+static int rfbi_get_max_tx_rate(void)
+{
+ return rfbi.l4_khz * 1000;
+}
+#endif
+
+
+static int rfbi_convert_timings(struct extif_timings *t)
+{
+ u32 l;
+ int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
+ int actim, recyc, wecyc;
+ int div = t->clk_div;
+
+ if (div <= 0 || div > 2)
+ return -1;
+
+ /* Make sure that after conversion it still holds that:
+ * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
+ * csoff > cson, csoff >= max(weoff, reoff), actim > reon
+ */
+ weon = ps_to_rfbi_ticks(t->we_on_time, div);
+ weoff = ps_to_rfbi_ticks(t->we_off_time, div);
+ if (weoff <= weon)
+ weoff = weon + 1;
+ if (weon > 0x0f)
+ return -1;
+ if (weoff > 0x3f)
+ return -1;
+
+ reon = ps_to_rfbi_ticks(t->re_on_time, div);
+ reoff = ps_to_rfbi_ticks(t->re_off_time, div);
+ if (reoff <= reon)
+ reoff = reon + 1;
+ if (reon > 0x0f)
+ return -1;
+ if (reoff > 0x3f)
+ return -1;
+
+ cson = ps_to_rfbi_ticks(t->cs_on_time, div);
+ csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
+ if (csoff <= cson)
+ csoff = cson + 1;
+ if (csoff < max(weoff, reoff))
+ csoff = max(weoff, reoff);
+ if (cson > 0x0f)
+ return -1;
+ if (csoff > 0x3f)
+ return -1;
+
+ l = cson;
+ l |= csoff << 4;
+ l |= weon << 10;
+ l |= weoff << 14;
+ l |= reon << 20;
+ l |= reoff << 24;
+
+ t->tim[0] = l;
+
+ actim = ps_to_rfbi_ticks(t->access_time, div);
+ if (actim <= reon)
+ actim = reon + 1;
+ if (actim > 0x3f)
+ return -1;
+
+ wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
+ if (wecyc < weoff)
+ wecyc = weoff;
+ if (wecyc > 0x3f)
+ return -1;
+
+ recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
+ if (recyc < reoff)
+ recyc = reoff;
+ if (recyc > 0x3f)
+ return -1;
+
+ cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
+ if (cs_pulse > 0x3f)
+ return -1;
+
+ l = wecyc;
+ l |= recyc << 6;
+ l |= cs_pulse << 12;
+ l |= actim << 22;
+
+ t->tim[1] = l;
+
+ t->tim[2] = div - 1;
+
+ t->converted = 1;
+
+ return 0;
+}
+
+static int rfbi_setup_tearsync(unsigned pin_cnt,
+ unsigned hs_pulse_time, unsigned vs_pulse_time,
+ int hs_pol_inv, int vs_pol_inv, int extif_div)
+{
+ int hs, vs;
+ int min;
+ u32 l;
+
+ if (pin_cnt != 1 && pin_cnt != 2)
+ return -EINVAL;
+
+ hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
+ vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
+ if (hs < 2)
+ return -EDOM;
+ if (pin_cnt == 2)
+ min = 2;
+ else
+ min = 4;
+ if (vs < min)
+ return -EDOM;
+ if (vs == hs)
+ return -EINVAL;
+ rfbi.tearsync_pin_cnt = pin_cnt;
+ dev_dbg(rfbi.fbdev->dev,
+ "setup_tearsync: pins %d hs %d vs %d hs_inv %d vs_inv %d\n",
+ pin_cnt, hs, vs, hs_pol_inv, vs_pol_inv);
+
+ rfbi_enable_clocks(1);
+ rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
+ rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
+
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ if (hs_pol_inv)
+ l &= ~(1 << 21);
+ else
+ l |= 1 << 21;
+ if (vs_pol_inv)
+ l &= ~(1 << 20);
+ else
+ l |= 1 << 20;
+ rfbi_enable_clocks(0);
+
+ return 0;
+}
+
+static int rfbi_enable_tearsync(int enable, unsigned line)
+{
+ u32 l;
+
+ dev_dbg(rfbi.fbdev->dev, "tearsync %d line %d mode %d\n",
+ enable, line, rfbi.tearsync_mode);
+ if (line > (1 << 11) - 1)
+ return -EINVAL;
+
+ rfbi_enable_clocks(1);
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ l &= ~(0x3 << 2);
+ if (enable) {
+ rfbi.tearsync_mode = rfbi.tearsync_pin_cnt;
+ l |= rfbi.tearsync_mode << 2;
+ } else
+ rfbi.tearsync_mode = 0;
+ rfbi_write_reg(RFBI_CONFIG0, l);
+ rfbi_write_reg(RFBI_LINE_NUMBER, line);
+ rfbi_enable_clocks(0);
+
+ return 0;
+}
+
+static void rfbi_write_command(const void *buf, unsigned int len)
+{
+ rfbi_enable_clocks(1);
+ if (rfbi.bits_per_cycle == 16) {
+ const u16 *w = buf;
+ BUG_ON(len & 1);
+ for (; len; len -= 2)
+ rfbi_write_reg(RFBI_CMD, *w++);
+ } else {
+ const u8 *b = buf;
+ BUG_ON(rfbi.bits_per_cycle != 8);
+ for (; len; len--)
+ rfbi_write_reg(RFBI_CMD, *b++);
+ }
+ rfbi_enable_clocks(0);
+}
+
+static void rfbi_read_data(void *buf, unsigned int len)
+{
+ rfbi_enable_clocks(1);
+ if (rfbi.bits_per_cycle == 16) {
+ u16 *w = buf;
+ BUG_ON(len & ~1);
+ for (; len; len -= 2) {
+ rfbi_write_reg(RFBI_READ, 0);
+ *w++ = rfbi_read_reg(RFBI_READ);
+ }
+ } else {
+ u8 *b = buf;
+ BUG_ON(rfbi.bits_per_cycle != 8);
+ for (; len; len--) {
+ rfbi_write_reg(RFBI_READ, 0);
+ *b++ = rfbi_read_reg(RFBI_READ);
+ }
+ }
+ rfbi_enable_clocks(0);
+}
+
+static void rfbi_write_data(const void *buf, unsigned int len)
+{
+ rfbi_enable_clocks(1);
+ if (rfbi.bits_per_cycle == 16) {
+ const u16 *w = buf;
+ BUG_ON(len & 1);
+ for (; len; len -= 2)
+ rfbi_write_reg(RFBI_PARAM, *w++);
+ } else {
+ const u8 *b = buf;
+ BUG_ON(rfbi.bits_per_cycle != 8);
+ for (; len; len--)
+ rfbi_write_reg(RFBI_PARAM, *b++);
+ }
+ rfbi_enable_clocks(0);
+}
+
+static void rfbi_transfer_area(int width, int height,
+ void (callback)(void * data), void *data)
+{
+ u32 w;
+
+ BUG_ON(callback == NULL);
+
+ rfbi_enable_clocks(1);
+ omap_dispc_set_lcd_size(width, height);
+
+ rfbi.lcdc_callback = callback;
+ rfbi.lcdc_callback_data = data;
+
+ rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
+
+ w = rfbi_read_reg(RFBI_CONTROL);
+ w |= 1; /* enable */
+ if (!rfbi.tearsync_mode)
+ w |= 1 << 4; /* internal trigger, reset by HW */
+ rfbi_write_reg(RFBI_CONTROL, w);
+
+ omap_dispc_enable_lcd_out(1);
+}
+
+static inline void _stop_transfer(void)
+{
+ u32 w;
+
+ w = rfbi_read_reg(RFBI_CONTROL);
+ rfbi_write_reg(RFBI_CONTROL, w & ~(1 << 0));
+ rfbi_enable_clocks(0);
+}
+
+static void rfbi_dma_callback(void *data)
+{
+ _stop_transfer();
+ rfbi.lcdc_callback(rfbi.lcdc_callback_data);
+}
+
+static void rfbi_set_bits_per_cycle(int bpc)
+{
+ u32 l;
+
+ rfbi_enable_clocks(1);
+ l = rfbi_read_reg(RFBI_CONFIG0);
+ l &= ~(0x03 << 0);
+
+ switch (bpc) {
+ case 8:
+ break;
+ case 16:
+ l |= 3;
+ break;
+ default:
+ BUG();
+ }
+ rfbi_write_reg(RFBI_CONFIG0, l);
+ rfbi.bits_per_cycle = bpc;
+ rfbi_enable_clocks(0);
+}
+
+static int rfbi_init(struct omapfb_device *fbdev)
+{
+ u32 l;
+ int r;
+
+ rfbi.fbdev = fbdev;
+ rfbi.base = io_p2v(RFBI_BASE);
+
+ if ((r = rfbi_get_clocks()) < 0)
+ return r;
+ rfbi_enable_clocks(1);
+
+ rfbi.l4_khz = clk_get_rate(rfbi.dss_ick) / 1000;
+
+ /* Reset */
+ rfbi_write_reg(RFBI_SYSCONFIG, 1 << 1);
+ while (!(rfbi_read_reg(RFBI_SYSSTATUS) & (1 << 0)));
+
+ l = rfbi_read_reg(RFBI_SYSCONFIG);
+ /* Enable autoidle and smart-idle */
+ l |= (1 << 0) | (2 << 3);
+ rfbi_write_reg(RFBI_SYSCONFIG, l);
+
+ /* 16-bit interface, ITE trigger mode, 16-bit data */
+ l = (0x03 << 0) | (0x00 << 2) | (0x01 << 5) | (0x02 << 7);
+ l |= (0 << 9) | (1 << 20) | (1 << 21);
+ rfbi_write_reg(RFBI_CONFIG0, l);
+
+ rfbi_write_reg(RFBI_DATA_CYCLE1_0, 0x00000010);
+
+ l = rfbi_read_reg(RFBI_CONTROL);
+ /* Select CS0, clear bypass mode */
+ l = (0x01 << 2);
+ rfbi_write_reg(RFBI_CONTROL, l);
+
+ if ((r = omap_dispc_request_irq(rfbi_dma_callback, NULL)) < 0) {
+ dev_err(fbdev->dev, "can't get DISPC irq\n");
+ rfbi_enable_clocks(0);
+ return r;
+ }
+
+ l = rfbi_read_reg(RFBI_REVISION);
+ pr_info("omapfb: RFBI version %d.%d initialized\n",
+ (l >> 4) & 0x0f, l & 0x0f);
+
+ rfbi_enable_clocks(0);
+
+ return 0;
+}
+
+static void rfbi_cleanup(void)
+{
+ omap_dispc_free_irq();
+ rfbi_put_clocks();
+}
+
+const struct lcd_ctrl_extif omap2_ext_if = {
+ .init = rfbi_init,
+ .cleanup = rfbi_cleanup,
+ .get_clk_info = rfbi_get_clk_info,
+ .get_max_tx_rate = rfbi_get_max_tx_rate,
+ .set_bits_per_cycle = rfbi_set_bits_per_cycle,
+ .convert_timings = rfbi_convert_timings,
+ .set_timings = rfbi_set_timings,
+ .write_command = rfbi_write_command,
+ .read_data = rfbi_read_data,
+ .write_data = rfbi_write_data,
+ .transfer_area = rfbi_transfer_area,
+ .setup_tearsync = rfbi_setup_tearsync,
+ .enable_tearsync = rfbi_enable_tearsync,
+
+ .max_transmit_size = (u32) ~0,
+};
+
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c
new file mode 100644
index 000000000000..81dbcf53cf0e
--- /dev/null
+++ b/drivers/video/omap/sossi.c
@@ -0,0 +1,686 @@
+/*
+ * OMAP1 Special OptimiSed Screen Interface support
+ *
+ * Copyright (C) 2004-2005 Nokia Corporation
+ * Author: Juha Yrjölä <juha.yrjola@nokia.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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+
+#include <asm/arch/dma.h>
+#include <asm/arch/omapfb.h>
+
+#include "lcdc.h"
+
+#define MODULE_NAME "omapfb-sossi"
+
+#define OMAP_SOSSI_BASE 0xfffbac00
+#define SOSSI_ID_REG 0x00
+#define SOSSI_INIT1_REG 0x04
+#define SOSSI_INIT2_REG 0x08
+#define SOSSI_INIT3_REG 0x0c
+#define SOSSI_FIFO_REG 0x10
+#define SOSSI_REOTABLE_REG 0x14
+#define SOSSI_TEARING_REG 0x18
+#define SOSSI_INIT1B_REG 0x1c
+#define SOSSI_FIFOB_REG 0x20
+
+#define DMA_GSCR 0xfffedc04
+#define DMA_LCD_CCR 0xfffee3c2
+#define DMA_LCD_CTRL 0xfffee3c4
+#define DMA_LCD_LCH_CTRL 0xfffee3ea
+
+#define CONF_SOSSI_RESET_R (1 << 23)
+
+#define RD_ACCESS 0
+#define WR_ACCESS 1
+
+#define SOSSI_MAX_XMIT_BYTES (512 * 1024)
+
+static struct {
+ void __iomem *base;
+ struct clk *fck;
+ unsigned long fck_hz;
+ spinlock_t lock;
+ int bus_pick_count;
+ int bus_pick_width;
+ int tearsync_mode;
+ int tearsync_line;
+ void (*lcdc_callback)(void *data);
+ void *lcdc_callback_data;
+ int vsync_dma_pending;
+ /* timing for read and write access */
+ int clk_div;
+ u8 clk_tw0[2];
+ u8 clk_tw1[2];
+ /*
+ * if last_access is the same as current we don't have to change
+ * the timings
+ */
+ int last_access;
+
+ struct omapfb_device *fbdev;
+} sossi;
+
+static inline u32 sossi_read_reg(int reg)
+{
+ return readl(sossi.base + reg);
+}
+
+static inline u16 sossi_read_reg16(int reg)
+{
+ return readw(sossi.base + reg);
+}
+
+static inline u8 sossi_read_reg8(int reg)
+{
+ return readb(sossi.base + reg);
+}
+
+static inline void sossi_write_reg(int reg, u32 value)
+{
+ writel(value, sossi.base + reg);
+}
+
+static inline void sossi_write_reg16(int reg, u16 value)
+{
+ writew(value, sossi.base + reg);
+}
+
+static inline void sossi_write_reg8(int reg, u8 value)
+{
+ writeb(value, sossi.base + reg);
+}
+
+static void sossi_set_bits(int reg, u32 bits)
+{
+ sossi_write_reg(reg, sossi_read_reg(reg) | bits);
+}
+
+static void sossi_clear_bits(int reg, u32 bits)
+{
+ sossi_write_reg(reg, sossi_read_reg(reg) & ~bits);
+}
+
+#define HZ_TO_PS(x) (1000000000 / (x / 1000))
+
+static u32 ps_to_sossi_ticks(u32 ps, int div)
+{
+ u32 clk_period = HZ_TO_PS(sossi.fck_hz) * div;
+ return (clk_period + ps - 1) / clk_period;
+}
+
+static int calc_rd_timings(struct extif_timings *t)
+{
+ u32 tw0, tw1;
+ int reon, reoff, recyc, actim;
+ int div = t->clk_div;
+
+ /*
+ * Make sure that after conversion it still holds that:
+ * reoff > reon, recyc >= reoff, actim > reon
+ */
+ reon = ps_to_sossi_ticks(t->re_on_time, div);
+ /* reon will be exactly one sossi tick */
+ if (reon > 1)
+ return -1;
+
+ reoff = ps_to_sossi_ticks(t->re_off_time, div);
+
+ if (reoff <= reon)
+ reoff = reon + 1;
+
+ tw0 = reoff - reon;
+ if (tw0 > 0x10)
+ return -1;
+
+ recyc = ps_to_sossi_ticks(t->re_cycle_time, div);
+ if (recyc <= reoff)
+ recyc = reoff + 1;
+
+ tw1 = recyc - tw0;
+ /* values less then 3 result in the SOSSI block resetting itself */
+ if (tw1 < 3)
+ tw1 = 3;
+ if (tw1 > 0x40)
+ return -1;
+
+ actim = ps_to_sossi_ticks(t->access_time, div);
+ if (actim < reoff)
+ actim++;
+ /*
+ * access time (data hold time) will be exactly one sossi
+ * tick
+ */
+ if (actim - reoff > 1)
+ return -1;
+
+ t->tim[0] = tw0 - 1;
+ t->tim[1] = tw1 - 1;
+
+ return 0;
+}
+
+static int calc_wr_timings(struct extif_timings *t)
+{
+ u32 tw0, tw1;
+ int weon, weoff, wecyc;
+ int div = t->clk_div;
+
+ /*
+ * Make sure that after conversion it still holds that:
+ * weoff > weon, wecyc >= weoff
+ */
+ weon = ps_to_sossi_ticks(t->we_on_time, div);
+ /* weon will be exactly one sossi tick */
+ if (weon > 1)
+ return -1;
+
+ weoff = ps_to_sossi_ticks(t->we_off_time, div);
+ if (weoff <= weon)
+ weoff = weon + 1;
+ tw0 = weoff - weon;
+ if (tw0 > 0x10)
+ return -1;
+
+ wecyc = ps_to_sossi_ticks(t->we_cycle_time, div);
+ if (wecyc <= weoff)
+ wecyc = weoff + 1;
+
+ tw1 = wecyc - tw0;
+ /* values less then 3 result in the SOSSI block resetting itself */
+ if (tw1 < 3)
+ tw1 = 3;
+ if (tw1 > 0x40)
+ return -1;
+
+ t->tim[2] = tw0 - 1;
+ t->tim[3] = tw1 - 1;
+
+ return 0;
+}
+
+static void _set_timing(int div, int tw0, int tw1)
+{
+ u32 l;
+
+#ifdef VERBOSE
+ dev_dbg(sossi.fbdev->dev, "Using TW0 = %d, TW1 = %d, div = %d\n",
+ tw0 + 1, tw1 + 1, div);
+#endif
+
+ clk_set_rate(sossi.fck, sossi.fck_hz / div);
+ clk_enable(sossi.fck);
+ l = sossi_read_reg(SOSSI_INIT1_REG);
+ l &= ~((0x0f << 20) | (0x3f << 24));
+ l |= (tw0 << 20) | (tw1 << 24);
+ sossi_write_reg(SOSSI_INIT1_REG, l);
+ clk_disable(sossi.fck);
+}
+
+static void _set_bits_per_cycle(int bus_pick_count, int bus_pick_width)
+{
+ u32 l;
+
+ l = sossi_read_reg(SOSSI_INIT3_REG);
+ l &= ~0x3ff;
+ l |= ((bus_pick_count - 1) << 5) | ((bus_pick_width - 1) & 0x1f);
+ sossi_write_reg(SOSSI_INIT3_REG, l);
+}
+
+static void _set_tearsync_mode(int mode, unsigned line)
+{
+ u32 l;
+
+ l = sossi_read_reg(SOSSI_TEARING_REG);
+ l &= ~(((1 << 11) - 1) << 15);
+ l |= line << 15;
+ l &= ~(0x3 << 26);
+ l |= mode << 26;
+ sossi_write_reg(SOSSI_TEARING_REG, l);
+ if (mode)
+ sossi_set_bits(SOSSI_INIT2_REG, 1 << 6); /* TE logic */
+ else
+ sossi_clear_bits(SOSSI_INIT2_REG, 1 << 6);
+}
+
+static inline void set_timing(int access)
+{
+ if (access != sossi.last_access) {
+ sossi.last_access = access;
+ _set_timing(sossi.clk_div,
+ sossi.clk_tw0[access], sossi.clk_tw1[access]);
+ }
+}
+
+static void sossi_start_transfer(void)
+{
+ /* WE */
+ sossi_clear_bits(SOSSI_INIT2_REG, 1 << 4);
+ /* CS active low */
+ sossi_clear_bits(SOSSI_INIT1_REG, 1 << 30);
+}
+
+static void sossi_stop_transfer(void)
+{
+ /* WE */
+ sossi_set_bits(SOSSI_INIT2_REG, 1 << 4);
+ /* CS active low */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 30);
+}
+
+static void wait_end_of_write(void)
+{
+ /* Before reading we must check if some writings are going on */
+ while (!(sossi_read_reg(SOSSI_INIT2_REG) & (1 << 3)));
+}
+
+static void send_data(const void *data, unsigned int len)
+{
+ while (len >= 4) {
+ sossi_write_reg(SOSSI_FIFO_REG, *(const u32 *) data);
+ len -= 4;
+ data += 4;
+ }
+ while (len >= 2) {
+ sossi_write_reg16(SOSSI_FIFO_REG, *(const u16 *) data);
+ len -= 2;
+ data += 2;
+ }
+ while (len) {
+ sossi_write_reg8(SOSSI_FIFO_REG, *(const u8 *) data);
+ len--;
+ data++;
+ }
+}
+
+static void set_cycles(unsigned int len)
+{
+ unsigned long nr_cycles = len / (sossi.bus_pick_width / 8);
+
+ BUG_ON((nr_cycles - 1) & ~0x3ffff);
+
+ sossi_clear_bits(SOSSI_INIT1_REG, 0x3ffff);
+ sossi_set_bits(SOSSI_INIT1_REG, (nr_cycles - 1) & 0x3ffff);
+}
+
+static int sossi_convert_timings(struct extif_timings *t)
+{
+ int r = 0;
+ int div = t->clk_div;
+
+ t->converted = 0;
+
+ if (div <= 0 || div > 8)
+ return -1;
+
+ /* no CS on SOSSI, so ignore cson, csoff, cs_pulsewidth */
+ if ((r = calc_rd_timings(t)) < 0)
+ return r;
+
+ if ((r = calc_wr_timings(t)) < 0)
+ return r;
+
+ t->tim[4] = div;
+
+ t->converted = 1;
+
+ return 0;
+}
+
+static void sossi_set_timings(const struct extif_timings *t)
+{
+ BUG_ON(!t->converted);
+
+ sossi.clk_tw0[RD_ACCESS] = t->tim[0];
+ sossi.clk_tw1[RD_ACCESS] = t->tim[1];
+
+ sossi.clk_tw0[WR_ACCESS] = t->tim[2];
+ sossi.clk_tw1[WR_ACCESS] = t->tim[3];
+
+ sossi.clk_div = t->tim[4];
+}
+
+static void sossi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
+{
+ *clk_period = HZ_TO_PS(sossi.fck_hz);
+ *max_clk_div = 8;
+}
+
+static void sossi_set_bits_per_cycle(int bpc)
+{
+ int bus_pick_count, bus_pick_width;
+
+ /*
+ * We set explicitly the the bus_pick_count as well, although
+ * with remapping/reordering disabled it will be calculated by HW
+ * as (32 / bus_pick_width).
+ */
+ switch (bpc) {
+ case 8:
+ bus_pick_count = 4;
+ bus_pick_width = 8;
+ break;
+ case 16:
+ bus_pick_count = 2;
+ bus_pick_width = 16;
+ break;
+ default:
+ BUG();
+ return;
+ }
+ sossi.bus_pick_width = bus_pick_width;
+ sossi.bus_pick_count = bus_pick_count;
+}
+
+static int sossi_setup_tearsync(unsigned pin_cnt,
+ unsigned hs_pulse_time, unsigned vs_pulse_time,
+ int hs_pol_inv, int vs_pol_inv, int div)
+{
+ int hs, vs;
+ u32 l;
+
+ if (pin_cnt != 1 || div < 1 || div > 8)
+ return -EINVAL;
+
+ hs = ps_to_sossi_ticks(hs_pulse_time, div);
+ vs = ps_to_sossi_ticks(vs_pulse_time, div);
+ if (vs < 8 || vs <= hs || vs >= (1 << 12))
+ return -EDOM;
+ vs /= 8;
+ vs--;
+ if (hs > 8)
+ hs = 8;
+ if (hs)
+ hs--;
+
+ dev_dbg(sossi.fbdev->dev,
+ "setup_tearsync: hs %d vs %d hs_inv %d vs_inv %d\n",
+ hs, vs, hs_pol_inv, vs_pol_inv);
+
+ clk_enable(sossi.fck);
+ l = sossi_read_reg(SOSSI_TEARING_REG);
+ l &= ~((1 << 15) - 1);
+ l |= vs << 3;
+ l |= hs;
+ if (hs_pol_inv)
+ l |= 1 << 29;
+ else
+ l &= ~(1 << 29);
+ if (vs_pol_inv)
+ l |= 1 << 28;
+ else
+ l &= ~(1 << 28);
+ sossi_write_reg(SOSSI_TEARING_REG, l);
+ clk_disable(sossi.fck);
+
+ return 0;
+}
+
+static int sossi_enable_tearsync(int enable, unsigned line)
+{
+ int mode;
+
+ dev_dbg(sossi.fbdev->dev, "tearsync %d line %d\n", enable, line);
+ if (line >= 1 << 11)
+ return -EINVAL;
+ if (enable) {
+ if (line)
+ mode = 2; /* HS or VS */
+ else
+ mode = 3; /* VS only */
+ } else
+ mode = 0;
+ sossi.tearsync_line = line;
+ sossi.tearsync_mode = mode;
+
+ return 0;
+}
+
+static void sossi_write_command(const void *data, unsigned int len)
+{
+ clk_enable(sossi.fck);
+ set_timing(WR_ACCESS);
+ _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
+ /* CMD#/DATA */
+ sossi_clear_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(len);
+ sossi_start_transfer();
+ send_data(data, len);
+ sossi_stop_transfer();
+ wait_end_of_write();
+ clk_disable(sossi.fck);
+}
+
+static void sossi_write_data(const void *data, unsigned int len)
+{
+ clk_enable(sossi.fck);
+ set_timing(WR_ACCESS);
+ _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
+ /* CMD#/DATA */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(len);
+ sossi_start_transfer();
+ send_data(data, len);
+ sossi_stop_transfer();
+ wait_end_of_write();
+ clk_disable(sossi.fck);
+}
+
+static void sossi_transfer_area(int width, int height,
+ void (callback)(void *data), void *data)
+{
+ BUG_ON(callback == NULL);
+
+ sossi.lcdc_callback = callback;
+ sossi.lcdc_callback_data = data;
+
+ clk_enable(sossi.fck);
+ set_timing(WR_ACCESS);
+ _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
+ _set_tearsync_mode(sossi.tearsync_mode, sossi.tearsync_line);
+ /* CMD#/DATA */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(width * height * sossi.bus_pick_width / 8);
+
+ sossi_start_transfer();
+ if (sossi.tearsync_mode) {
+ /*
+ * Wait for the sync signal and start the transfer only
+ * then. We can't seem to be able to use HW sync DMA for
+ * this since LCD DMA shows huge latencies, as if it
+ * would ignore some of the DMA requests from SoSSI.
+ */
+ unsigned long flags;
+
+ spin_lock_irqsave(&sossi.lock, flags);
+ sossi.vsync_dma_pending++;
+ spin_unlock_irqrestore(&sossi.lock, flags);
+ } else
+ /* Just start the transfer right away. */
+ omap_enable_lcd_dma();
+}
+
+static void sossi_dma_callback(void *data)
+{
+ omap_stop_lcd_dma();
+ sossi_stop_transfer();
+ clk_disable(sossi.fck);
+ sossi.lcdc_callback(sossi.lcdc_callback_data);
+}
+
+static void sossi_read_data(void *data, unsigned int len)
+{
+ clk_enable(sossi.fck);
+ set_timing(RD_ACCESS);
+ _set_bits_per_cycle(sossi.bus_pick_count, sossi.bus_pick_width);
+ /* CMD#/DATA */
+ sossi_set_bits(SOSSI_INIT1_REG, 1 << 18);
+ set_cycles(len);
+ sossi_start_transfer();
+ while (len >= 4) {
+ *(u32 *) data = sossi_read_reg(SOSSI_FIFO_REG);
+ len -= 4;
+ data += 4;
+ }
+ while (len >= 2) {
+ *(u16 *) data = sossi_read_reg16(SOSSI_FIFO_REG);
+ len -= 2;
+ data += 2;
+ }
+ while (len) {
+ *(u8 *) data = sossi_read_reg8(SOSSI_FIFO_REG);
+ len--;
+ data++;
+ }
+ sossi_stop_transfer();
+ clk_disable(sossi.fck);
+}
+
+static irqreturn_t sossi_match_irq(int irq, void *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&sossi.lock, flags);
+ if (sossi.vsync_dma_pending) {
+ sossi.vsync_dma_pending--;
+ omap_enable_lcd_dma();
+ }
+ spin_unlock_irqrestore(&sossi.lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int sossi_init(struct omapfb_device *fbdev)
+{
+ u32 l, k;
+ struct clk *fck;
+ struct clk *dpll1out_ck;
+ int r;
+
+ sossi.base = (void __iomem *)IO_ADDRESS(OMAP_SOSSI_BASE);
+ sossi.fbdev = fbdev;
+ spin_lock_init(&sossi.lock);
+
+ dpll1out_ck = clk_get(fbdev->dev, "ck_dpll1out");
+ if (IS_ERR(dpll1out_ck)) {
+ dev_err(fbdev->dev, "can't get DPLL1OUT clock\n");
+ return PTR_ERR(dpll1out_ck);
+ }
+ /*
+ * We need the parent clock rate, which we might divide further
+ * depending on the timing requirements of the controller. See
+ * _set_timings.
+ */
+ sossi.fck_hz = clk_get_rate(dpll1out_ck);
+ clk_put(dpll1out_ck);
+
+ fck = clk_get(fbdev->dev, "ck_sossi");
+ if (IS_ERR(fck)) {
+ dev_err(fbdev->dev, "can't get SoSSI functional clock\n");
+ return PTR_ERR(fck);
+ }
+ sossi.fck = fck;
+
+ /* Reset and enable the SoSSI module */
+ l = omap_readl(MOD_CONF_CTRL_1);
+ l |= CONF_SOSSI_RESET_R;
+ omap_writel(l, MOD_CONF_CTRL_1);
+ l &= ~CONF_SOSSI_RESET_R;
+ omap_writel(l, MOD_CONF_CTRL_1);
+
+ clk_enable(sossi.fck);
+ l = omap_readl(ARM_IDLECT2);
+ l &= ~(1 << 8); /* DMACK_REQ */
+ omap_writel(l, ARM_IDLECT2);
+
+ l = sossi_read_reg(SOSSI_INIT2_REG);
+ /* Enable and reset the SoSSI block */
+ l |= (1 << 0) | (1 << 1);
+ sossi_write_reg(SOSSI_INIT2_REG, l);
+ /* Take SoSSI out of reset */
+ l &= ~(1 << 1);
+ sossi_write_reg(SOSSI_INIT2_REG, l);
+
+ sossi_write_reg(SOSSI_ID_REG, 0);
+ l = sossi_read_reg(SOSSI_ID_REG);
+ k = sossi_read_reg(SOSSI_ID_REG);
+
+ if (l != 0x55555555 || k != 0xaaaaaaaa) {
+ dev_err(fbdev->dev,
+ "invalid SoSSI sync pattern: %08x, %08x\n", l, k);
+ r = -ENODEV;
+ goto err;
+ }
+
+ if ((r = omap_lcdc_set_dma_callback(sossi_dma_callback, NULL)) < 0) {
+ dev_err(fbdev->dev, "can't get LCDC IRQ\n");
+ r = -ENODEV;
+ goto err;
+ }
+
+ l = sossi_read_reg(SOSSI_ID_REG); /* Component code */
+ l = sossi_read_reg(SOSSI_ID_REG);
+ dev_info(fbdev->dev, "SoSSI version %d.%d initialized\n",
+ l >> 16, l & 0xffff);
+
+ l = sossi_read_reg(SOSSI_INIT1_REG);
+ l |= (1 << 19); /* DMA_MODE */
+ l &= ~(1 << 31); /* REORDERING */
+ sossi_write_reg(SOSSI_INIT1_REG, l);
+
+ if ((r = request_irq(INT_1610_SoSSI_MATCH, sossi_match_irq,
+ IRQT_FALLING,
+ "sossi_match", sossi.fbdev->dev)) < 0) {
+ dev_err(sossi.fbdev->dev, "can't get SoSSI match IRQ\n");
+ goto err;
+ }
+
+ clk_disable(sossi.fck);
+ return 0;
+
+err:
+ clk_disable(sossi.fck);
+ clk_put(sossi.fck);
+ return r;
+}
+
+static void sossi_cleanup(void)
+{
+ omap_lcdc_free_dma_callback();
+ clk_put(sossi.fck);
+}
+
+struct lcd_ctrl_extif omap1_ext_if = {
+ .init = sossi_init,
+ .cleanup = sossi_cleanup,
+ .get_clk_info = sossi_get_clk_info,
+ .convert_timings = sossi_convert_timings,
+ .set_timings = sossi_set_timings,
+ .set_bits_per_cycle = sossi_set_bits_per_cycle,
+ .setup_tearsync = sossi_setup_tearsync,
+ .enable_tearsync = sossi_enable_tearsync,
+ .write_command = sossi_write_command,
+ .read_data = sossi_read_data,
+ .write_data = sossi_write_data,
+ .transfer_area = sossi_transfer_area,
+
+ .max_transmit_size = SOSSI_MAX_XMIT_BYTES,
+};
+
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index e64f8b5d0056..8503e733a172 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -52,7 +52,7 @@ struct fb_info_platinum {
struct {
__u8 red, green, blue;
} palette[256];
- u32 pseudo_palette[17];
+ u32 pseudo_palette[16];
volatile struct cmap_regs __iomem *cmap_regs;
unsigned long cmap_regs_phys;
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 0a04483aa3e0..10c0cc6e93fc 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -24,7 +24,7 @@
* License. See the file COPYING in the main directory of this archive for
* more details.
*
- *
+ *
*/
#include <linux/module.h>
@@ -58,7 +58,7 @@
#endif
/*
- * Driver data
+ * Driver data
*/
static char *mode __devinitdata = NULL;
@@ -82,12 +82,12 @@ struct pm2fb_par
{
pm2type_t type; /* Board type */
unsigned char __iomem *v_regs;/* virtual address of p_regs */
- u32 memclock; /* memclock */
+ u32 memclock; /* memclock */
u32 video; /* video flags before blanking */
u32 mem_config; /* MemConfig reg at probe */
u32 mem_control; /* MemControl reg at probe */
u32 boot_address; /* BootAddress reg at probe */
- u32 palette[16];
+ u32 palette[16];
};
/*
@@ -95,12 +95,12 @@ struct pm2fb_par
* if we don't use modedb.
*/
static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
- .id = "",
+ .id = "",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
.xpanstep = 1,
.ypanstep = 1,
- .ywrapstep = 0,
+ .ywrapstep = 0,
.accel = FB_ACCEL_3DLABS_PERMEDIA2,
};
@@ -109,26 +109,26 @@ static struct fb_fix_screeninfo pm2fb_fix __devinitdata = {
*/
static struct fb_var_screeninfo pm2fb_var __devinitdata = {
/* "640x480, 8 bpp @ 60 Hz */
- .xres = 640,
- .yres = 480,
- .xres_virtual = 640,
- .yres_virtual = 480,
- .bits_per_pixel =8,
- .red = {0, 8, 0},
- .blue = {0, 8, 0},
- .green = {0, 8, 0},
- .activate = FB_ACTIVATE_NOW,
- .height = -1,
- .width = -1,
- .accel_flags = 0,
- .pixclock = 39721,
- .left_margin = 40,
- .right_margin = 24,
- .upper_margin = 32,
- .lower_margin = 11,
- .hsync_len = 96,
- .vsync_len = 2,
- .vmode = FB_VMODE_NONINTERLACED
+ .xres = 640,
+ .yres = 480,
+ .xres_virtual = 640,
+ .yres_virtual = 480,
+ .bits_per_pixel = 8,
+ .red = {0, 8, 0},
+ .blue = {0, 8, 0},
+ .green = {0, 8, 0},
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .accel_flags = 0,
+ .pixclock = 39721,
+ .left_margin = 40,
+ .right_margin = 24,
+ .upper_margin = 32,
+ .lower_margin = 11,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .vmode = FB_VMODE_NONINTERLACED
};
/*
@@ -166,7 +166,7 @@ static inline u32 pm2_RDAC_RD(struct pm2fb_par* p, s32 idx)
pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
index = PM2VR_RD_INDEXED_DATA;
break;
- }
+ }
mb();
return pm2_RD(p, index);
}
@@ -182,7 +182,7 @@ static inline void pm2_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
index = PM2VR_RD_INDEXED_DATA;
break;
- }
+ }
wmb();
pm2_WR(p, index, v);
wmb();
@@ -197,7 +197,7 @@ static inline void pm2v_RDAC_WR(struct pm2fb_par* p, s32 idx, u32 v)
}
#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
-#define WAIT_FIFO(p,a)
+#define WAIT_FIFO(p, a)
#else
static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a)
{
@@ -209,7 +209,7 @@ static inline void WAIT_FIFO(struct pm2fb_par* p, u32 a)
/*
* partial products for the supported horizontal resolutions.
*/
-#define PACKPP(p0,p1,p2) (((p2) << 6) | ((p1) << 3) | (p0))
+#define PACKPP(p0, p1, p2) (((p2) << 6) | ((p1) << 3) | (p0))
static const struct {
u16 width;
u16 pp;
@@ -357,7 +357,7 @@ static void reset_card(struct pm2fb_par* p)
static void reset_config(struct pm2fb_par* p)
{
WAIT_FIFO(p, 52);
- pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
+ pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG) &
~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
@@ -367,7 +367,7 @@ static void reset_config(struct pm2fb_par* p)
pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
- pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
+ pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
pm2_WR(p, PM2R_LB_READ_MODE, 0);
pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
@@ -535,7 +535,7 @@ static void set_video(struct pm2fb_par* p, u32 video) {
vsync = video;
DPRINTK("video = 0x%x\n", video);
-
+
/*
* The hardware cursor needs +vsync to recognise vert retrace.
* We may not be using the hardware cursor, but the X Glint
@@ -574,9 +574,9 @@ static void set_video(struct pm2fb_par* p, u32 video) {
*/
/**
- * pm2fb_check_var - Optional function. Validates a var passed in.
- * @var: frame buffer variable screen structure
- * @info: frame buffer structure that represents a single frame buffer
+ * pm2fb_check_var - Optional function. Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
*
* Checks to see if the hardware supports the state requested by
* var passed in.
@@ -615,23 +615,23 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
-
+
if (var->xres < 320 || var->xres > 1600) {
DPRINTK("width not supported: %u\n", var->xres);
return -EINVAL;
}
-
+
if (var->yres < 200 || var->yres > 1200) {
DPRINTK("height not supported: %u\n", var->yres);
return -EINVAL;
}
-
+
if (lpitch * var->yres_virtual > info->fix.smem_len) {
DPRINTK("no memory for screen (%ux%ux%u)\n",
var->xres, var->yres_virtual, var->bits_per_pixel);
return -EINVAL;
}
-
+
if (PICOS2KHZ(var->pixclock) > PM2_MAX_PIXCLOCK) {
DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
return -EINVAL;
@@ -672,17 +672,17 @@ static int pm2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
break;
}
var->height = var->width = -1;
-
+
var->accel_flags = 0; /* Can't mmap if this is on */
-
+
DPRINTK("Checking graphics mode at %dx%d depth %d\n",
var->xres, var->yres, var->bits_per_pixel);
return 0;
}
/**
- * pm2fb_set_par - Alters the hardware state.
- * @info: frame buffer structure that represents a single frame buffer
+ * pm2fb_set_par - Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
*
* Using the fb_var_screeninfo in fb_info we set the resolution of the
* this particular framebuffer.
@@ -709,7 +709,7 @@ static int pm2fb_set_par(struct fb_info *info)
clear_palette(par);
if ( par->memclock )
set_memclock(par, par->memclock);
-
+
width = (info->var.xres_virtual + 7) & ~7;
height = info->var.yres_virtual;
depth = (info->var.bits_per_pixel + 7) & ~7;
@@ -722,7 +722,7 @@ static int pm2fb_set_par(struct fb_info *info)
DPRINTK("pixclock too high (%uKHz)\n", pixclock);
return -EINVAL;
}
-
+
hsstart = to3264(info->var.right_margin, depth, data64);
hsend = hsstart + to3264(info->var.hsync_len, depth, data64);
hbend = hsend + to3264(info->var.left_margin, depth, data64);
@@ -737,7 +737,7 @@ static int pm2fb_set_par(struct fb_info *info)
base = to3264(info->var.yoffset * xres + info->var.xoffset, depth, 1);
if (data64)
video |= PM2F_DATA_64_ENABLE;
-
+
if (info->var.sync & FB_SYNC_HOR_HIGH_ACT) {
if (lowhsync) {
DPRINTK("ignoring +hsync, using -hsync.\n");
@@ -778,9 +778,9 @@ static int pm2fb_set_par(struct fb_info *info)
WAIT_FIFO(par, 1);
pm2_WR(par, PM2VR_RD_INDEX_HIGH, 0);
}
-
+
set_aperture(par, depth);
-
+
mb();
WAIT_FIFO(par, 19);
pm2_RDAC_WR(par, PM2I_RD_COLOR_KEY_CONTROL,
@@ -847,22 +847,22 @@ static int pm2fb_set_par(struct fb_info *info)
set_pixclock(par, pixclock);
DPRINTK("Setting graphics mode at %dx%d depth %d\n",
info->var.xres, info->var.yres, info->var.bits_per_pixel);
- return 0;
+ return 0;
}
/**
- * pm2fb_setcolreg - Sets a color register.
- * @regno: boolean, 0 copy local, 1 get_user() function
- * @red: frame buffer colormap structure
- * @green: The green value which can be up to 16 bits wide
+ * pm2fb_setcolreg - Sets a color register.
+ * @regno: boolean, 0 copy local, 1 get_user() function
+ * @red: frame buffer colormap structure
+ * @green: The green value which can be up to 16 bits wide
* @blue: The blue value which can be up to 16 bits wide.
- * @transp: If supported the alpha value which can be up to 16 bits wide.
- * @info: frame buffer info structure
- *
- * Set a single color register. The values supplied have a 16 bit
- * magnitude which needs to be scaled in this function for the hardware.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
+ *
+ * Set a single color register. The values supplied have a 16 bit
+ * magnitude which needs to be scaled in this function for the hardware.
* Pretty much a direct lift from tdfxfb.c.
- *
+ *
* Returns negative errno on error, or zero on success.
*/
static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
@@ -906,7 +906,7 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
* (blue << blue.offset) | (transp << transp.offset)
* RAMDAC does not exist
*/
-#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF -(val)) >> 16)
switch (info->fix.visual) {
case FB_VISUAL_TRUECOLOR:
case FB_VISUAL_PSEUDOCOLOR:
@@ -916,9 +916,9 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
transp = CNVT_TOHW(transp, info->var.transp.length);
break;
case FB_VISUAL_DIRECTCOLOR:
- /* example here assumes 8 bit DAC. Might be different
- * for your hardware */
- red = CNVT_TOHW(red, 8);
+ /* example here assumes 8 bit DAC. Might be different
+ * for your hardware */
+ red = CNVT_TOHW(red, 8);
green = CNVT_TOHW(green, 8);
blue = CNVT_TOHW(blue, 8);
/* hey, there is bug in transp handling... */
@@ -940,11 +940,11 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
switch (info->var.bits_per_pixel) {
case 8:
- break;
- case 16:
+ break;
+ case 16:
case 24:
- case 32:
- par->palette[regno] = v;
+ case 32:
+ par->palette[regno] = v;
break;
}
return 0;
@@ -956,15 +956,15 @@ static int pm2fb_setcolreg(unsigned regno, unsigned red, unsigned green,
}
/**
- * pm2fb_pan_display - Pans the display.
- * @var: frame buffer variable screen structure
- * @info: frame buffer structure that represents a single frame buffer
+ * pm2fb_pan_display - Pans the display.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
*
* 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.
+ * `xoffset' and `yoffset' fields of the `var' structure.
+ * If the values don't fit, return -EINVAL.
*
- * Returns negative errno on error, or zero on success.
+ * Returns negative errno on error, or zero on success.
*
*/
static int pm2fb_pan_display(struct fb_var_screeninfo *var,
@@ -980,24 +980,24 @@ static int pm2fb_pan_display(struct fb_var_screeninfo *var,
depth = (depth > 32) ? 32 : depth;
base = to3264(var->yoffset * xres + var->xoffset, depth, 1);
WAIT_FIFO(p, 1);
- pm2_WR(p, PM2R_SCREEN_BASE, base);
+ pm2_WR(p, PM2R_SCREEN_BASE, base);
return 0;
}
/**
- * pm2fb_blank - Blanks the display.
- * @blank_mode: the blank mode we want.
- * @info: frame buffer structure that represents a single frame buffer
+ * pm2fb_blank - Blanks the display.
+ * @blank_mode: the blank mode we want.
+ * @info: frame buffer structure that represents a single frame buffer
*
- * Blank the screen if blank_mode != 0, else unblank. Return 0 if
- * blanking succeeded, != 0 if un-/blanking failed due to e.g. a
- * video mode which doesn't support it. Implements VESA suspend
- * and powerdown modes on hardware that supports disabling hsync/vsync:
- * blank_mode == 2: suspend vsync
- * blank_mode == 3: suspend hsync
- * blank_mode == 4: powerdown
+ * Blank the screen if blank_mode != 0, else unblank. Return 0 if
+ * blanking succeeded, != 0 if un-/blanking failed due to e.g. a
+ * video mode which doesn't support it. Implements VESA suspend
+ * and powerdown modes on hardware that supports disabling hsync/vsync:
+ * blank_mode == 2: suspend vsync
+ * blank_mode == 3: suspend hsync
+ * blank_mode == 4: powerdown
*
- * Returns negative errno on error, or zero on success.
+ * Returns negative errno on error, or zero on success.
*
*/
static int pm2fb_blank(int blank_mode, struct fb_info *info)
@@ -1071,7 +1071,7 @@ static void pm2fb_block_op(struct fb_info* info, int copy,
pm2_WR(par, PM2R_RECTANGLE_ORIGIN, (y << 16) | x);
pm2_WR(par, PM2R_RECTANGLE_SIZE, (h << 16) | w);
wmb();
- pm2_WR(par, PM2R_RENDER,PM2F_RENDER_RECTANGLE |
+ pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE |
(x<xsrc ? PM2F_INCREASE_X : 0) |
(y<ysrc ? PM2F_INCREASE_Y : 0) |
(copy ? 0 : PM2F_RENDER_FASTFILL));
@@ -1234,7 +1234,7 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
DPRINTK("Adjusting register base for big-endian.\n");
#endif
DPRINTK("Register base at 0x%lx\n", pm2fb_fix.mmio_start);
-
+
/* Registers - request region and map it. */
if ( !request_mem_region(pm2fb_fix.mmio_start, pm2fb_fix.mmio_len,
"pm2fb regbase") ) {
@@ -1317,17 +1317,17 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
}
info->fbops = &pm2fb_ops;
- info->fix = pm2fb_fix;
+ info->fix = pm2fb_fix;
info->pseudo_palette = default_par->palette;
info->flags = FBINFO_DEFAULT |
- FBINFO_HWACCEL_YPAN |
- FBINFO_HWACCEL_COPYAREA |
- FBINFO_HWACCEL_FILLRECT;
+ FBINFO_HWACCEL_YPAN |
+ FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_FILLRECT;
if (!mode)
mode = "640x480@60";
-
- err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8);
+
+ err = fb_find_mode(&info->var, info, mode, NULL, 0, NULL, 8);
if (!err || err == 4)
info->var = pm2fb_var;
@@ -1348,8 +1348,8 @@ static int __devinit pm2fb_probe(struct pci_dev *pdev,
return 0;
err_exit_all:
- fb_dealloc_cmap(&info->cmap);
- err_exit_both:
+ fb_dealloc_cmap(&info->cmap);
+ err_exit_both:
iounmap(info->screen_base);
release_mem_region(pm2fb_fix.smem_start, pm2fb_fix.smem_len);
err_exit_mmio:
@@ -1374,7 +1374,7 @@ static void __devexit pm2fb_remove(struct pci_dev *pdev)
struct pm2fb_par *par = info->par;
unregister_framebuffer(info);
-
+
iounmap(info->screen_base);
release_mem_region(fix->smem_start, fix->smem_len);
iounmap(par->v_regs);
@@ -1402,9 +1402,9 @@ static struct pci_device_id pm2fb_id_table[] = {
static struct pci_driver pm2fb_driver = {
.name = "pm2fb",
- .id_table = pm2fb_id_table,
- .probe = pm2fb_probe,
- .remove = __devexit_p(pm2fb_remove),
+ .id_table = pm2fb_id_table,
+ .probe = pm2fb_probe,
+ .remove = __devexit_p(pm2fb_remove),
};
MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
@@ -1423,7 +1423,7 @@ static int __init pm2fb_setup(char *options)
if (!options || !*options)
return 0;
- while ((this_opt = strsep(&options, ",")) != NULL) {
+ while ((this_opt = strsep(&options, ",")) != NULL) {
if (!*this_opt)
continue;
if(!strcmp(this_opt, "lowhsync")) {
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index b52e883f0a52..5b3f54c0918e 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -77,7 +77,7 @@ static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
.xpanstep = 1,
.ypanstep = 1,
.ywrapstep = 0,
- .accel = FB_ACCEL_NONE,
+ .accel = FB_ACCEL_3DLABS_PERMEDIA3,
};
/*
@@ -185,6 +185,238 @@ static inline int pm3fb_shift_bpp(unsigned bpp, int v)
return 0;
}
+/* acceleration */
+static int pm3fb_sync(struct fb_info *info)
+{
+ struct pm3_par *par = info->par;
+
+ PM3_WAIT(par, 2);
+ PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
+ PM3_WRITE_REG(par, PM3Sync, 0);
+ mb();
+ do {
+ while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0);
+ rmb();
+ } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag);
+
+ return 0;
+}
+
+static void pm3fb_init_engine(struct fb_info *info)
+{
+ struct pm3_par *par = info->par;
+ const u32 width = (info->var.xres_virtual + 7) & ~7;
+
+ PM3_WAIT(par, 50);
+ PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
+ PM3_WRITE_REG(par, PM3StatisticMode, 0x0);
+ PM3_WRITE_REG(par, PM3DeltaMode, 0x0);
+ PM3_WRITE_REG(par, PM3RasterizerMode, 0x0);
+ PM3_WRITE_REG(par, PM3ScissorMode, 0x0);
+ PM3_WRITE_REG(par, PM3LineStippleMode, 0x0);
+ PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0);
+ PM3_WRITE_REG(par, PM3GIDMode, 0x0);
+ PM3_WRITE_REG(par, PM3DepthMode, 0x0);
+ PM3_WRITE_REG(par, PM3StencilMode, 0x0);
+ PM3_WRITE_REG(par, PM3StencilData, 0x0);
+ PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0);
+ PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0);
+ PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0);
+ PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0);
+ PM3_WRITE_REG(par, PM3TextureReadMode, 0x0);
+ PM3_WRITE_REG(par, PM3LUTMode, 0x0);
+ PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0);
+ PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0);
+ PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0);
+ PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0);
+ PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0);
+ PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0);
+ PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0);
+ PM3_WRITE_REG(par, PM3FogMode, 0x0);
+ PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0);
+ PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0);
+ PM3_WRITE_REG(par, PM3AntialiasMode, 0x0);
+ PM3_WRITE_REG(par, PM3YUVMode, 0x0);
+ PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0);
+ PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0);
+ PM3_WRITE_REG(par, PM3DitherMode, 0x0);
+ PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0);
+ PM3_WRITE_REG(par, PM3RouterMode, 0x0);
+ PM3_WRITE_REG(par, PM3Window, 0x0);
+
+ PM3_WRITE_REG(par, PM3Config2D, 0x0);
+
+ PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff);
+
+ PM3_WRITE_REG(par, PM3XBias, 0x0);
+ PM3_WRITE_REG(par, PM3YBias, 0x0);
+ PM3_WRITE_REG(par, PM3DeltaControl, 0x0);
+
+ PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff);
+
+ PM3_WRITE_REG(par, PM3FBDestReadEnables,
+ PM3FBDestReadEnables_E(0xff) |
+ PM3FBDestReadEnables_R(0xff) |
+ PM3FBDestReadEnables_ReferenceAlpha(0xff));
+ PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0);
+ PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0);
+ PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0,
+ PM3FBDestReadBufferWidth_Width(width));
+
+ PM3_WRITE_REG(par, PM3FBDestReadMode,
+ PM3FBDestReadMode_ReadEnable |
+ PM3FBDestReadMode_Enable0);
+ PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0);
+ PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0);
+ PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth,
+ PM3FBSourceReadBufferWidth_Width(width));
+ PM3_WRITE_REG(par, PM3FBSourceReadMode,
+ PM3FBSourceReadMode_Blocking |
+ PM3FBSourceReadMode_ReadEnable);
+
+ PM3_WAIT(par, 2);
+ {
+ unsigned long rm = 1;
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ PM3_WRITE_REG(par, PM3PixelSize,
+ PM3PixelSize_GLOBAL_8BIT);
+ break;
+ case 16:
+ PM3_WRITE_REG(par, PM3PixelSize,
+ PM3PixelSize_GLOBAL_16BIT);
+ break;
+ case 32:
+ PM3_WRITE_REG(par, PM3PixelSize,
+ PM3PixelSize_GLOBAL_32BIT);
+ break;
+ default:
+ DPRINTK(1, "Unsupported depth %d\n",
+ info->var.bits_per_pixel);
+ break;
+ }
+ PM3_WRITE_REG(par, PM3RasterizerMode, rm);
+ }
+
+ PM3_WAIT(par, 20);
+ PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff);
+ PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff);
+ PM3_WRITE_REG(par, PM3FBWriteMode,
+ PM3FBWriteMode_WriteEnable |
+ PM3FBWriteMode_OpaqueSpan |
+ PM3FBWriteMode_Enable0);
+ PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0);
+ PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0);
+ PM3_WRITE_REG(par, PM3FBWriteBufferWidth0,
+ PM3FBWriteBufferWidth_Width(width));
+
+ PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0);
+ {
+ /* size in lines of FB */
+ unsigned long sofb = info->screen_size /
+ info->fix.line_length;
+ if (sofb > 4095)
+ PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095);
+ else
+ PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb);
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ PM3_WRITE_REG(par, PM3DitherMode,
+ (1 << 10) | (2 << 3));
+ break;
+ case 16:
+ PM3_WRITE_REG(par, PM3DitherMode,
+ (1 << 10) | (1 << 3));
+ break;
+ case 32:
+ PM3_WRITE_REG(par, PM3DitherMode,
+ (1 << 10) | (0 << 3));
+ break;
+ default:
+ DPRINTK(1, "Unsupported depth %d\n",
+ info->current_par->depth);
+ break;
+ }
+ }
+
+ PM3_WRITE_REG(par, PM3dXDom, 0x0);
+ PM3_WRITE_REG(par, PM3dXSub, 0x0);
+ PM3_WRITE_REG(par, PM3dY, (1 << 16));
+ PM3_WRITE_REG(par, PM3StartXDom, 0x0);
+ PM3_WRITE_REG(par, PM3StartXSub, 0x0);
+ PM3_WRITE_REG(par, PM3StartY, 0x0);
+ PM3_WRITE_REG(par, PM3Count, 0x0);
+
+/* Disable LocalBuffer. better safe than sorry */
+ PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0);
+ PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0);
+ PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0);
+ PM3_WRITE_REG(par, PM3LBWriteMode, 0x0);
+
+ pm3fb_sync(info);
+}
+
+static void pm3fb_fillrect (struct fb_info *info,
+ const struct fb_fillrect *region)
+{
+ struct pm3_par *par = info->par;
+ struct fb_fillrect modded;
+ int vxres, vyres;
+ u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
+ ((u32*)info->pseudo_palette)[region->color] : region->color;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return;
+ if ((info->flags & FBINFO_HWACCEL_DISABLED) ||
+ region->rop != ROP_COPY ) {
+ cfb_fillrect(info, region);
+ return;
+ }
+
+ vxres = info->var.xres_virtual;
+ vyres = info->var.yres_virtual;
+
+ memcpy(&modded, region, sizeof(struct fb_fillrect));
+
+ if(!modded.width || !modded.height ||
+ modded.dx >= vxres || modded.dy >= vyres)
+ return;
+
+ if(modded.dx + modded.width > vxres)
+ modded.width = vxres - modded.dx;
+ if(modded.dy + modded.height > vyres)
+ modded.height = vyres - modded.dy;
+
+ if(info->var.bits_per_pixel == 8)
+ color |= color << 8;
+ if(info->var.bits_per_pixel <= 16)
+ color |= color << 16;
+
+ PM3_WAIT(par, 4);
+
+ PM3_WRITE_REG(par, PM3Config2D,
+ PM3Config2D_UseConstantSource |
+ PM3Config2D_ForegroundROPEnable |
+ (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
+ PM3Config2D_FBWriteEnable);
+
+ PM3_WRITE_REG(par, PM3ForegroundColor, color);
+
+ PM3_WRITE_REG(par, PM3RectanglePosition,
+ (PM3RectanglePosition_XOffset(modded.dx)) |
+ (PM3RectanglePosition_YOffset(modded.dy)));
+
+ PM3_WRITE_REG(par, PM3Render2D,
+ PM3Render2D_XPositive |
+ PM3Render2D_YPositive |
+ PM3Render2D_Operation_Normal |
+ PM3Render2D_SpanOperation |
+ (PM3Render2D_Width(modded.width)) |
+ (PM3Render2D_Height(modded.height)));
+}
+/* end of acceleration functions */
+
/* write the mode to registers */
static void pm3fb_write_mode(struct fb_info *info)
{
@@ -380,8 +612,6 @@ static void pm3fb_write_mode(struct fb_info *info)
/*
* hardware independent functions
*/
-int pm3fb_init(void);
-
static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
u32 lpitch;
@@ -528,6 +758,7 @@ static int pm3fb_set_par(struct fb_info *info)
pm3fb_clear_colormap(par, 0, 0, 0);
PM3_WRITE_DAC_REG(par, PM3RD_CursorMode,
PM3RD_CursorMode_CURSOR_DISABLE);
+ pm3fb_init_engine(info);
pm3fb_write_mode(info);
return 0;
}
@@ -675,10 +906,11 @@ static struct fb_ops pm3fb_ops = {
.fb_set_par = pm3fb_set_par,
.fb_setcolreg = pm3fb_setcolreg,
.fb_pan_display = pm3fb_pan_display,
- .fb_fillrect = cfb_fillrect,
+ .fb_fillrect = pm3fb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_blank = pm3fb_blank,
+ .fb_sync = pm3fb_sync,
};
/* ------------------------------------------------------------------------- */
@@ -847,7 +1079,8 @@ static int __devinit pm3fb_probe(struct pci_dev *dev,
info->fix = pm3fb_fix;
info->pseudo_palette = par->palette;
- info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/
+ info->flags = FBINFO_DEFAULT |
+ FBINFO_HWACCEL_FILLRECT;/* | FBINFO_HWACCEL_YPAN;*/
/*
* This should give a reasonable default video mode. The following is
@@ -935,35 +1168,12 @@ static struct pci_driver pm3fb_driver = {
MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
-#ifndef MODULE
- /*
- * Setup
- */
-
-/*
- * Only necessary if your driver takes special options,
- * otherwise we fall back on the generic fb_setup().
- */
-static int __init pm3fb_setup(char *options)
+static int __init pm3fb_init(void)
{
- /* Parse user speficied options (`video=pm3fb:') */
- return 0;
-}
-#endif /* MODULE */
-
-int __init pm3fb_init(void)
-{
- /*
- * For kernel boot options (in 'video=pm3fb:<options>' format)
- */
#ifndef MODULE
- char *option = NULL;
-
- if (fb_get_options("pm3fb", &option))
+ if (fb_get_options("pm3fb", NULL))
return -ENODEV;
- pm3fb_setup(option);
#endif
-
return pci_register_driver(&pm3fb_driver);
}
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 9cf92ba5d6e3..646ec823c168 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -27,7 +27,6 @@
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/platform_device.h>
#include <linux/console.h>
#include <linux/ioctl.h>
#include <linux/notifier.h>
@@ -46,6 +45,9 @@
#include <asm/ps3fb.h>
#include <asm/ps3.h>
+
+#define DEVICE_NAME "ps3fb"
+
#ifdef PS3FB_DEBUG
#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
#else
@@ -126,7 +128,6 @@ struct gpu_driver_info {
struct ps3fb_priv {
unsigned int irq_no;
- void *dev;
u64 context_handle, memory_handle;
void *xdr_ea;
@@ -171,7 +172,7 @@ static const struct ps3fb_res_table ps3fb_res[] = {
{ 0, 0, 0, 0 , 0} };
/* default resolution */
-#define GPU_RES_INDEX 0 /* 720 x 480 */
+#define GPU_RES_INDEX 0 /* 720 x 480 */
static const struct fb_videomode ps3fb_modedb[] = {
/* 60 Hz broadcast modes (modes "1" to "5") */
@@ -298,10 +299,9 @@ static const struct fb_videomode ps3fb_modedb[] = {
#define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
static int ps3fb_mode;
-module_param(ps3fb_mode, bool, 0);
-
-static char *mode_option __initdata;
+module_param(ps3fb_mode, int, 0);
+static char *mode_option __devinitdata;
static int ps3fb_get_res_table(u32 xres, u32 yres)
{
@@ -681,15 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc)
EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
-void ps3fb_flip_ctl(int on)
+void ps3fb_flip_ctl(int on, void *data)
{
+ struct ps3fb_priv *priv = data;
if (on)
- atomic_dec_if_positive(&ps3fb.ext_flip);
+ atomic_dec_if_positive(&priv->ext_flip);
else
- atomic_inc(&ps3fb.ext_flip);
+ atomic_inc(&priv->ext_flip);
}
-EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
/*
* ioctl
@@ -812,6 +812,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
static int ps3fbd(void *arg)
{
+ set_freezable();
while (!kthread_should_stop()) {
try_to_freeze();
set_current_state(TASK_INTERRUPTIBLE);
@@ -851,37 +852,9 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
return IRQ_HANDLED;
}
-#ifndef MODULE
-static int __init ps3fb_setup(char *options)
-{
- char *this_opt;
- int mode = 0;
-
- if (!options || !*options)
- return 0; /* no options */
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt)
- continue;
- if (!strncmp(this_opt, "mode:", 5))
- mode = simple_strtoul(this_opt + 5, NULL, 0);
- else
- mode_option = this_opt;
- }
- return mode;
-}
-#endif /* MODULE */
-
- /*
- * Initialisation
- */
-static void ps3fb_platform_release(struct device *device)
-{
- /* This is called when the reference count goes to zero. */
-}
-
-static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
+static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
+ struct ps3_system_bus_device *dev)
{
int error;
@@ -897,7 +870,6 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
return -EINVAL;
}
- ps3fb.dev = dev;
error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
&ps3fb.irq_no);
if (error) {
@@ -907,7 +879,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
}
error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
- "ps3fb vsync", ps3fb.dev);
+ DEVICE_NAME, dev);
if (error) {
printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
error);
@@ -966,16 +938,45 @@ static struct fb_ops ps3fb_ops = {
};
static struct fb_fix_screeninfo ps3fb_fix __initdata = {
- .id = "PS3 FB",
+ .id = DEVICE_NAME,
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.accel = FB_ACCEL_NONE,
};
-static int __init ps3fb_probe(struct platform_device *dev)
+static int ps3fb_set_sync(void)
+{
+ int status;
+
+#ifdef HEAD_A
+ status = lv1_gpu_context_attribute(0x0,
+ L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+ 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC "
+ "failed: %d\n", __func__, status);
+ return -1;
+ }
+#endif
+#ifdef HEAD_B
+ status = lv1_gpu_context_attribute(0x0,
+ L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+ 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+
+ if (status) {
+ printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE "
+ "failed: %d\n", __func__, status);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
{
struct fb_info *info;
int retval = -ENOMEM;
+ u32 xres, yres;
u64 ddr_lpar = 0;
u64 lpar_dma_control = 0;
u64 lpar_driver_info = 0;
@@ -986,6 +987,30 @@ static int __init ps3fb_probe(struct platform_device *dev)
unsigned long offset;
struct task_struct *task;
+ status = ps3_open_hv_device(dev);
+ if (status) {
+ printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__);
+ goto err;
+ }
+
+ if (!ps3fb_mode)
+ ps3fb_mode = ps3av_get_mode();
+ DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
+
+ if (ps3fb_mode > 0 &&
+ !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
+ ps3fb.res_index = ps3fb_get_res_table(xres, yres);
+ DPRINTK("res_index:%d\n", ps3fb.res_index);
+ } else
+ ps3fb.res_index = GPU_RES_INDEX;
+
+ atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
+ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
+ init_waitqueue_head(&ps3fb.wait_vsync);
+ ps3fb.num_frames = 1;
+
+ ps3fb_set_sync();
+
/* get gpu context handle */
status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
&ps3fb.memory_handle, &ddr_lpar);
@@ -1029,7 +1054,7 @@ static int __init ps3fb_probe(struct platform_device *dev)
* leakage into userspace
*/
memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
- info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+ info = framebuffer_alloc(sizeof(u32) * 16, &dev->core);
if (!info)
goto err_free_irq;
@@ -1042,7 +1067,7 @@ static int __init ps3fb_probe(struct platform_device *dev)
info->fix.smem_len = ps3fb_videomemory.size - offset;
info->pseudo_palette = info->par;
info->par = NULL;
- info->flags = FBINFO_FLAG_DEFAULT;
+ info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
retval = fb_alloc_cmap(&info->cmap, 256, 0);
if (retval < 0)
@@ -1061,19 +1086,20 @@ static int __init ps3fb_probe(struct platform_device *dev)
if (retval < 0)
goto err_fb_dealloc;
- platform_set_drvdata(dev, info);
+ dev->core.driver_data = info;
printk(KERN_INFO
"fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
info->node, ps3fb_videomemory.size >> 10);
- task = kthread_run(ps3fbd, info, "ps3fbd");
+ task = kthread_run(ps3fbd, info, DEVICE_NAME);
if (IS_ERR(task)) {
retval = PTR_ERR(task);
goto err_unregister_framebuffer;
}
ps3fb.task = task;
+ ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
return 0;
@@ -1084,7 +1110,7 @@ err_fb_dealloc:
err_framebuffer_release:
framebuffer_release(info);
err_free_irq:
- free_irq(ps3fb.irq_no, ps3fb.dev);
+ free_irq(ps3fb.irq_no, dev);
ps3_irq_plug_destroy(ps3fb.irq_no);
err_iounmap_dinfo:
iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1096,26 +1122,30 @@ err:
return retval;
}
-static void ps3fb_shutdown(struct platform_device *dev)
+static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
{
- ps3fb_flip_ctl(0); /* flip off */
+ int status;
+ struct fb_info *info = dev->core.driver_data;
+
+ DPRINTK(" -> %s:%d\n", __func__, __LINE__);
+
+ ps3fb_flip_ctl(0, &ps3fb); /* flip off */
ps3fb.dinfo->irq.mask = 0;
- free_irq(ps3fb.irq_no, ps3fb.dev);
- ps3_irq_plug_destroy(ps3fb.irq_no);
- iounmap((u8 __iomem *)ps3fb.dinfo);
-}
-void ps3fb_cleanup(void)
-{
- int status;
+ if (info) {
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+ ps3av_register_flip_ctl(NULL, NULL);
if (ps3fb.task) {
struct task_struct *task = ps3fb.task;
ps3fb.task = NULL;
kthread_stop(task);
}
if (ps3fb.irq_no) {
- free_irq(ps3fb.irq_no, ps3fb.dev);
+ free_irq(ps3fb.irq_no, dev);
ps3_irq_plug_destroy(ps3fb.irq_no);
}
iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1128,134 +1158,69 @@ void ps3fb_cleanup(void)
if (status)
DPRINTK("lv1_gpu_memory_free failed: %d\n", status);
- ps3av_dev_close();
-}
+ ps3_close_hv_device(dev);
+ DPRINTK(" <- %s:%d\n", __func__, __LINE__);
-EXPORT_SYMBOL_GPL(ps3fb_cleanup);
-
-static int ps3fb_remove(struct platform_device *dev)
-{
- struct fb_info *info = platform_get_drvdata(dev);
-
- if (info) {
- unregister_framebuffer(info);
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- }
- ps3fb_cleanup();
return 0;
}
-static struct platform_driver ps3fb_driver = {
- .probe = ps3fb_probe,
- .remove = ps3fb_remove,
- .shutdown = ps3fb_shutdown,
- .driver = { .name = "ps3fb" }
-};
-
-static struct platform_device ps3fb_device = {
- .name = "ps3fb",
- .id = 0,
- .dev = { .release = ps3fb_platform_release }
+static struct ps3_system_bus_driver ps3fb_driver = {
+ .match_id = PS3_MATCH_ID_GRAPHICS,
+ .core.name = DEVICE_NAME,
+ .core.owner = THIS_MODULE,
+ .probe = ps3fb_probe,
+ .remove = ps3fb_shutdown,
+ .shutdown = ps3fb_shutdown,
};
-int ps3fb_set_sync(void)
+static int __init ps3fb_setup(void)
{
- int status;
+ char *options;
-#ifdef HEAD_A
- status = lv1_gpu_context_attribute(0x0,
- L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
- 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
- if (status) {
- printk(KERN_ERR
- "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
- __func__, status);
- return -1;
- }
-#endif
-#ifdef HEAD_B
- status = lv1_gpu_context_attribute(0x0,
- L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
- 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
-
- if (status) {
- printk(KERN_ERR
- "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
- __func__, status);
- return -1;
- }
-#endif
+#ifdef MODULE
return 0;
-}
-
-EXPORT_SYMBOL_GPL(ps3fb_set_sync);
-
-static int __init ps3fb_init(void)
-{
- int error;
-#ifndef MODULE
- int mode;
- char *option = NULL;
-
- if (fb_get_options("ps3fb", &option))
- goto err;
#endif
- if (!ps3fb_videomemory.address)
- goto err;
-
- error = ps3av_dev_open();
- if (error) {
- printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
- goto err;
- }
+ if (fb_get_options(DEVICE_NAME, &options))
+ return -ENXIO;
- ps3fb_mode = ps3av_get_mode();
- DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
-#ifndef MODULE
- mode = ps3fb_setup(option); /* check boot option */
- if (mode)
- ps3fb_mode = mode;
-#endif
- if (ps3fb_mode > 0) {
- u32 xres, yres;
- ps3av_video_mode2res(ps3fb_mode, &xres, &yres);
- ps3fb.res_index = ps3fb_get_res_table(xres, yres);
- DPRINTK("res_index:%d\n", ps3fb.res_index);
- } else
- ps3fb.res_index = GPU_RES_INDEX;
+ if (!options || !*options)
+ return 0;
- atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
- atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
- init_waitqueue_head(&ps3fb.wait_vsync);
- ps3fb.num_frames = 1;
+ while (1) {
+ char *this_opt = strsep(&options, ",");
- error = platform_driver_register(&ps3fb_driver);
- if (!error) {
- error = platform_device_register(&ps3fb_device);
- if (error)
- platform_driver_unregister(&ps3fb_driver);
+ if (!this_opt)
+ break;
+ if (!*this_opt)
+ continue;
+ if (!strncmp(this_opt, "mode:", 5))
+ ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0);
+ else
+ mode_option = this_opt;
}
+ return 0;
+}
- ps3fb_set_sync();
-
- return error;
+static int __init ps3fb_init(void)
+{
+ if (!ps3fb_videomemory.address || ps3fb_setup())
+ return -ENXIO;
-err:
- return -ENXIO;
+ return ps3_system_bus_driver_register(&ps3fb_driver);
}
-module_init(ps3fb_init);
-
-#ifdef MODULE
static void __exit ps3fb_exit(void)
{
- platform_device_unregister(&ps3fb_device);
- platform_driver_unregister(&ps3fb_driver);
+ DPRINTK(" -> %s:%d\n", __func__, __LINE__);
+ ps3_system_bus_driver_unregister(&ps3fb_driver);
+ DPRINTK(" <- %s:%d\n", __func__, __LINE__);
}
+module_init(ps3fb_init);
module_exit(ps3fb_exit);
MODULE_LICENSE("GPL");
-#endif /* MODULE */
+MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
+MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index df2909ae704c..f9300266044d 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -115,11 +115,11 @@ enum { VO_PAL, VO_NTSC, VO_VGA };
enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 };
struct pvr2_params { unsigned int val; char *name; };
-static struct pvr2_params cables[] __initdata = {
+static struct pvr2_params cables[] __devinitdata = {
{ CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" },
};
-static struct pvr2_params outputs[] __initdata = {
+static struct pvr2_params outputs[] __devinitdata = {
{ VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" },
};
@@ -147,16 +147,16 @@ static struct pvr2fb_par {
static struct fb_info *fb_info;
-static struct fb_fix_screeninfo pvr2_fix __initdata = {
+static struct fb_fix_screeninfo pvr2_fix __devinitdata = {
.id = "NEC PowerVR2",
- .type = FB_TYPE_PACKED_PIXELS,
- .visual = FB_VISUAL_TRUECOLOR,
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
.ypanstep = 1,
.ywrapstep = 1,
- .accel = FB_ACCEL_NONE,
+ .accel = FB_ACCEL_NONE,
};
-static struct fb_var_screeninfo pvr2_var __initdata = {
+static struct fb_var_screeninfo pvr2_var __devinitdata = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
@@ -195,10 +195,6 @@ static unsigned int shdma = PVR2_CASCADE_CHAN;
static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS;
#endif
-/* Interface used by the world */
-
-int pvr2fb_setup(char*);
-
static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue,
unsigned int transp, struct fb_info *info);
static int pvr2fb_blank(int blank, struct fb_info *info);
@@ -227,12 +223,12 @@ static struct fb_ops pvr2fb_ops = {
#ifdef CONFIG_SH_DMA
.fb_write = pvr2fb_write,
#endif
- .fb_fillrect = cfb_fillrect,
+ .fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
-static struct fb_videomode pvr2_modedb[] __initdata = {
+static struct fb_videomode pvr2_modedb[] __devinitdata = {
/*
* Broadcast video modes (PAL and NTSC). I'm unfamiliar with
* PAL-M and PAL-N, but from what I've read both modes parallel PAL and
@@ -252,7 +248,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = {
/* 640x480 @ 60hz (VGA) */
"vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26,
0, FB_VMODE_YWRAP
- },
+ },
};
#define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb)
@@ -262,7 +258,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = {
#define DEFMODE_VGA 2
static int defmode = DEFMODE_NTSC;
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
static inline void pvr2fb_set_pal_type(unsigned int type)
{
@@ -293,7 +289,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var)
{
switch (var->bits_per_pixel) {
case 16: /* RGB 565 */
- pvr2fb_set_pal_type(PAL_RGB565);
+ pvr2fb_set_pal_type(PAL_RGB565);
var->red.offset = 11; var->red.length = 5;
var->green.offset = 5; var->green.length = 6;
var->blue.offset = 0; var->blue.length = 5;
@@ -306,7 +302,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var)
var->transp.offset = 0; var->transp.length = 0;
break;
case 32: /* ARGB 8888 */
- pvr2fb_set_pal_type(PAL_ARGB8888);
+ pvr2fb_set_pal_type(PAL_ARGB8888);
var->red.offset = 16; var->red.length = 8;
var->green.offset = 8; var->green.length = 8;
var->blue.offset = 0; var->blue.length = 8;
@@ -337,24 +333,25 @@ static int pvr2fb_setcolreg(unsigned int regno, unsigned int red,
((blue & 0xf800) >> 11);
pvr2fb_set_pal_entry(par, regno, tmp);
- ((u16*)(info->pseudo_palette))[regno] = tmp;
break;
case 24: /* RGB 888 */
red >>= 8; green >>= 8; blue >>= 8;
- ((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue;
+ tmp = (red << 16) | (green << 8) | blue;
break;
case 32: /* ARGB 8888 */
red >>= 8; green >>= 8; blue >>= 8;
tmp = (transp << 24) | (red << 16) | (green << 8) | blue;
pvr2fb_set_pal_entry(par, regno, tmp);
- ((u32*)(info->pseudo_palette))[regno] = tmp;
break;
default:
pr_debug("Invalid bit depth %d?!?\n", info->var.bits_per_pixel);
return 1;
}
+ if (regno < 16)
+ ((u32*)(info->pseudo_palette))[regno] = tmp;
+
return 0;
}
@@ -379,13 +376,13 @@ static int pvr2fb_set_par(struct fb_info *info)
var->vmode &= FB_VMODE_MASK;
if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA)
par->is_interlaced = 1;
- /*
+ /*
* XXX: Need to be more creative with this (i.e. allow doublecan for
* PAL/NTSC output).
*/
if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA)
par->is_doublescan = 1;
-
+
par->hsync_total = var->left_margin + var->xres + var->right_margin +
var->hsync_len;
par->vsync_total = var->upper_margin + var->yres + var->lower_margin +
@@ -408,7 +405,7 @@ static int pvr2fb_set_par(struct fb_info *info)
} else {
/* VGA mode */
/* XXX: What else needs to be checked? */
- /*
+ /*
* XXX: We have a little freedom in VGA modes, what ranges
* should be here (i.e. hsync/vsync totals, etc.)?
*/
@@ -419,8 +416,8 @@ static int pvr2fb_set_par(struct fb_info *info)
/* Calculate the remainding offsets */
par->diwstart_h = par->borderstart_h + var->left_margin;
par->diwstart_v = par->borderstart_v + var->upper_margin;
- par->borderstop_h = par->diwstart_h + var->xres +
- var->right_margin;
+ par->borderstop_h = par->diwstart_h + var->xres +
+ var->right_margin;
par->borderstop_v = par->diwstart_v + var->yres +
var->lower_margin;
@@ -465,12 +462,12 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
set_color_bitfields(var);
if (var->vmode & FB_VMODE_YWRAP) {
- if (var->xoffset || var->yoffset < 0 ||
+ if (var->xoffset || var->yoffset < 0 ||
var->yoffset >= var->yres_virtual) {
var->xoffset = var->yoffset = 0;
} else {
if (var->xoffset > var->xres_virtual - var->xres ||
- var->yoffset > var->yres_virtual - var->yres ||
+ var->yoffset > var->yres_virtual - var->yres ||
var->xoffset < 0 || var->yoffset < 0)
var->xoffset = var->yoffset = 0;
}
@@ -478,7 +475,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->xoffset = var->yoffset = 0;
}
- /*
+ /*
* XXX: Need to be more creative with this (i.e. allow doublecan for
* PAL/NTSC output).
*/
@@ -507,7 +504,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->vsync_len = par->borderstop_v +
(par->vsync_total - par->borderstop_v);
}
-
+
hsync_total = var->left_margin + var->xres + var->right_margin +
var->hsync_len;
vtotal = var->upper_margin + var->yres + var->lower_margin +
@@ -531,7 +528,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
}
}
}
-
+
/* Check memory sizes */
line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
if (line_length * var->yres_virtual > info->fix.smem_len)
@@ -552,7 +549,7 @@ static void pvr2_update_display(struct fb_info *info)
DISP_DIWADDRS);
}
-/*
+/*
* Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't
* very stable. It's probably due to the fact that a lot of the 2D video
* registers are still undocumented.
@@ -592,18 +589,18 @@ static void pvr2_init_display(struct fb_info *info)
/* display window start position */
fb_writel(par->diwstart_h, DISP_DIWHSTRT);
fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT);
-
+
/* misc. settings */
fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF);
/* clock doubler (for VGA), scan doubler, display enable */
- fb_writel(((video_output == VO_VGA) << 23) |
+ fb_writel(((video_output == VO_VGA) << 23) |
(par->is_doublescan << 1) | 1, DISP_DIWMODE);
/* bits per pixel */
fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE);
- /* video enable, color sync, interlace,
+ /* video enable, color sync, interlace,
* hsync and vsync polarity (currently unused) */
fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF);
}
@@ -657,7 +654,7 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id)
static int pvr2_init_cable(void)
{
if (cable_type < 0) {
- fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000,
+ fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000,
PCTRA);
cable_type = (fb_readw(PDTRA) >> 8) & 3;
}
@@ -687,7 +684,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
if (!pages)
return -ENOMEM;
-
+
down_read(&current->mm->mmap_sem);
ret = get_user_pages(current, current->mm, (unsigned long)buf,
nr_pages, WRITE, 0, pages, NULL);
@@ -700,7 +697,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
}
dma_configure_channel(shdma, 0x12c1);
-
+
dst = (unsigned long)fb_info->screen_base + *ppos;
start = (unsigned long)page_address(pages[0]);
end = (unsigned long)page_address(pages[nr_pages]);
@@ -744,7 +741,7 @@ out_unmap:
kfree(pages);
return ret;
-}
+}
#endif /* CONFIG_SH_DMA */
/**
@@ -765,21 +762,21 @@ out_unmap:
* in for flexibility anyways. Who knows, maybe someone has tv-out on a
* PCI-based version of these things ;-)
*/
-static int __init pvr2fb_common_init(void)
+static int __devinit pvr2fb_common_init(void)
{
struct pvr2fb_par *par = currentpar;
unsigned long modememused, rev;
fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start,
pvr2_fix.smem_len);
-
+
if (!fb_info->screen_base) {
printk(KERN_ERR "pvr2fb: Failed to remap smem space\n");
goto out_err;
}
par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start,
- pvr2_fix.mmio_len);
+ pvr2_fix.mmio_len);
if (!par->mmio_base) {
printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n");
goto out_err;
@@ -820,7 +817,7 @@ static int __init pvr2fb_common_init(void)
printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n",
fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f,
modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10));
- printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n",
+ printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n",
fb_info->node, fb_info->var.xres, fb_info->var.yres,
fb_info->var.bits_per_pixel,
get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
@@ -878,8 +875,8 @@ static int __init pvr2fb_dc_init(void)
video_output = VO_NTSC;
}
}
-
- /*
+
+ /*
* Nothing exciting about the DC PVR2 .. only a measly 8MiB.
*/
pvr2_fix.smem_start = 0xa5000000; /* RAM starts here */
@@ -903,7 +900,7 @@ static int __init pvr2fb_dc_init(void)
return pvr2fb_common_init();
}
-static void pvr2fb_dc_exit(void)
+static void __exit pvr2fb_dc_exit(void)
{
if (fb_info->screen_base) {
iounmap(fb_info->screen_base);
@@ -987,13 +984,13 @@ static int __init pvr2fb_pci_init(void)
return pci_register_driver(&pvr2fb_pci_driver);
}
-static void pvr2fb_pci_exit(void)
+static void __exit pvr2fb_pci_exit(void)
{
pci_unregister_driver(&pvr2fb_pci_driver);
}
#endif /* CONFIG_PCI */
-static int __init pvr2_get_param(const struct pvr2_params *p, const char *s,
+static int __devinit pvr2_get_param(const struct pvr2_params *p, const char *s,
int val, int size)
{
int i;
@@ -1021,7 +1018,7 @@ static int __init pvr2_get_param(const struct pvr2_params *p, const char *s,
*/
#ifndef MODULE
-int __init pvr2fb_setup(char *options)
+static int __init pvr2fb_setup(char *options)
{
char *this_opt;
char cable_arg[80];
@@ -1061,7 +1058,7 @@ static struct pvr2_board {
int (*init)(void);
void (*exit)(void);
char name[16];
-} board_list[] = {
+} board_driver[] = {
#ifdef CONFIG_SH_DREAMCAST
{ pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" },
#endif
@@ -1071,7 +1068,7 @@ static struct pvr2_board {
{ 0, },
};
-int __init pvr2fb_init(void)
+static int __init pvr2fb_init(void)
{
int i, ret = -ENODEV;
int size;
@@ -1085,18 +1082,17 @@ int __init pvr2fb_init(void)
#endif
size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32);
- fb_info = kmalloc(size, GFP_KERNEL);
+ fb_info = kzalloc(size, GFP_KERNEL);
if (!fb_info) {
printk(KERN_ERR "Failed to allocate memory for fb_info\n");
return -ENOMEM;
}
- memset(fb_info, 0, size);
currentpar = (struct pvr2fb_par *)(fb_info + 1);
- for (i = 0; i < ARRAY_SIZE(board_list); i++) {
- struct pvr2_board *pvr_board = board_list + i;
+ for (i = 0; i < ARRAY_SIZE(board_driver); i++) {
+ struct pvr2_board *pvr_board = board_driver + i;
if (!pvr_board->init)
continue;
@@ -1118,13 +1114,13 @@ static void __exit pvr2fb_exit(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(board_list); i++) {
- struct pvr2_board *pvr_board = board_list + i;
+ for (i = 0; i < ARRAY_SIZE(board_driver); i++) {
+ struct pvr2_board *pvr_board = board_driver + i;
if (pvr_board->exit)
pvr_board->exit();
}
-
+
#ifdef CONFIG_SH_STORE_QUEUES
sq_unmap(pvr2fb_map);
#endif
@@ -1139,4 +1135,3 @@ module_exit(pvr2fb_exit);
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards");
MODULE_LICENSE("GPL");
-
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index 48536c3e58a4..4beac1df617b 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -95,7 +95,7 @@ static int __init q40fb_probe(struct platform_device *dev)
/* mapped in q40/config.c */
q40fb_fix.smem_start = Q40_PHYS_SCREEN_ADDR;
- info = framebuffer_alloc(sizeof(u32) * 256, &dev->dev);
+ info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
if (!info)
return -ENOMEM;
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 0fe547842c64..5c47968e7f21 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -307,7 +307,7 @@ static int riva_bl_get_level_brightness(struct riva_par *par,
static int riva_bl_update_status(struct backlight_device *bd)
{
- struct riva_par *par = class_get_devdata(&bd->class_dev);
+ struct riva_par *par = bl_get_data(bd);
U032 tmp_pcrt, tmp_pmc;
int level;
@@ -2146,7 +2146,7 @@ static void __devexit rivafb_remove(struct pci_dev *pd)
* ------------------------------------------------------------------------- */
#ifndef MODULE
-static int __init rivafb_setup(char *options)
+static int __devinit rivafb_setup(char *options)
{
char *this_opt;
diff --git a/drivers/video/riva/riva_hw.c b/drivers/video/riva/riva_hw.c
index 70bfd78eca81..13307703a9f0 100644
--- a/drivers/video/riva/riva_hw.c
+++ b/drivers/video/riva/riva_hw.c
@@ -1223,6 +1223,8 @@ static int CalcVClock
}
}
}
+
+ /* non-zero: M/N/P/clock values assigned. zero: error (not set) */
return (DeltaOld != 0xFFFFFFFF);
}
/*
@@ -1240,7 +1242,10 @@ int CalcStateExt
int dotClock
)
{
- int pixelDepth, VClk, m, n, p;
+ int pixelDepth;
+ int uninitialized_var(VClk),uninitialized_var(m),
+ uninitialized_var(n), uninitialized_var(p);
+
/*
* Save mode parameters.
*/
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 3d7507ad55f6..b855f4a34afe 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2174,11 +2174,10 @@ static int __devinit savage_init_fb_info(struct fb_info *info,
#if defined(CONFIG_FB_SAVAGE_ACCEL)
/* FIFO size + padding for commands */
- info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
+ info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL);
err = -ENOMEM;
if (info->pixmap.addr) {
- memset(info->pixmap.addr, 0, 8*1024);
info->pixmap.size = 8*1024;
info->pixmap.scan_align = 4;
info->pixmap.buf_align = 4;
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index ebb6756aea08..4fb16240c04d 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -752,7 +752,7 @@ static int __init sgivwfb_probe(struct platform_device *dev)
struct fb_info *info;
char *monitor;
- info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 256, &dev->dev);
+ info = framebuffer_alloc(sizeof(struct sgivw_par) + sizeof(u32) * 16, &dev->dev);
if (!info)
return -ENOMEM;
par = info->par;
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index d5e2d9c27847..d53bf6945f0c 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -479,7 +479,7 @@ struct sis_video_info {
struct fb_var_screeninfo default_var;
struct fb_fix_screeninfo sisfb_fix;
- u32 pseudo_palette[17];
+ u32 pseudo_palette[16];
struct sisfb_monitor {
u16 hmin;
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index a30e1e13d8be..e8ccace01252 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1405,12 +1405,18 @@ sisfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
}
break;
case 16:
+ if (regno >= 16)
+ break;
+
((u32 *)(info->pseudo_palette))[regno] =
(red & 0xf800) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
break;
case 32:
+ if (regno >= 16)
+ break;
+
red >>= 8;
green >>= 8;
blue >>= 8;
@@ -5789,7 +5795,7 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ivideo->warncount = 0;
ivideo->chip_id = pdev->device;
ivideo->chip_vendor = pdev->vendor;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &ivideo->revision_id);
+ ivideo->revision_id = pdev->revision;
ivideo->SiS_Pr.ChipRevision = ivideo->revision_id;
pci_read_config_word(pdev, PCI_COMMAND, &reg16);
ivideo->sisvga_enabled = reg16 & 0x01;
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 62fa5500361d..5eff28ce4f4d 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -1348,7 +1348,7 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
f_ddprintk("found device : %s\n", spec->name);
par->dev = pdev;
- pci_read_config_byte(pdev, PCI_REVISION_ID, &par->revision);
+ par->revision = pdev->revision;
fix->mmio_start = pci_resource_start(pdev,0);
fix->mmio_len = 0x400000;
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index f0fde6ea7c36..89facb73edfc 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -1625,8 +1625,7 @@ tgafb_register(struct device *dev)
par->tga_regs_base = mem_base + TGA_REGS_OFFSET;
par->tga_type = tga_type;
if (tga_bus_pci)
- pci_read_config_byte(to_pci_dev(dev), PCI_REVISION_ID,
- &par->tga_chip_rev);
+ par->tga_chip_rev = (to_pci_dev(dev))->revision;
if (tga_bus_tc)
par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff;
@@ -1635,7 +1634,7 @@ tgafb_register(struct device *dev)
FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT;
info->fbops = &tgafb_ops;
info->screen_base = par->tga_fb_base;
- info->pseudo_palette = (void *)(par + 1);
+ info->pseudo_palette = par->palette;
/* This should give a reasonable default video mode. */
if (tga_bus_pci) {
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index 55e8aa450bfa..c699864b6f4a 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -976,7 +976,7 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 1;
- if (bpp==8) {
+ if (bpp == 8) {
t_outb(0xFF,0x3C6);
t_outb(regno,0x3C8);
@@ -984,19 +984,21 @@ static int tridentfb_setcolreg(unsigned regno, unsigned red, unsigned green,
t_outb(green>>10,0x3C9);
t_outb(blue>>10,0x3C9);
- } else if (bpp == 16) { /* RGB 565 */
- u32 col;
-
- col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
- ((blue & 0xF800) >> 11);
- col |= col << 16;
- ((u32 *)(info->pseudo_palette))[regno] = col;
- } else if (bpp == 32) /* ARGB 8888 */
- ((u32*)info->pseudo_palette)[regno] =
- ((transp & 0xFF00) <<16) |
- ((red & 0xFF00) << 8) |
- ((green & 0xFF00)) |
- ((blue & 0xFF00)>>8);
+ } else if (regno < 16) {
+ if (bpp == 16) { /* RGB 565 */
+ u32 col;
+
+ col = (red & 0xF800) | ((green & 0xFC00) >> 5) |
+ ((blue & 0xF800) >> 11);
+ col |= col << 16;
+ ((u32 *)(info->pseudo_palette))[regno] = col;
+ } else if (bpp == 32) /* ARGB 8888 */
+ ((u32*)info->pseudo_palette)[regno] =
+ ((transp & 0xFF00) <<16) |
+ ((red & 0xFF00) << 8) |
+ ((green & 0xFF00)) |
+ ((blue & 0xFF00)>>8);
+ }
// debug("exit\n");
return 0;
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
index 07389ba01eff..e6f7c78da68b 100644
--- a/drivers/video/tx3912fb.c
+++ b/drivers/video/tx3912fb.c
@@ -291,7 +291,7 @@ int __init tx3912fb_init(void)
fb_info.fbops = &tx3912fb_ops;
fb_info.var = tx3912fb_var;
fb_info.fix = tx3912fb_fix;
- fb_info.pseudo_palette = pseudo_palette;
+ fb_info.pseudo_palette = cfb8;
fb_info.flags = FBINFO_DEFAULT;
/* Clear the framebuffer */
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index ad66f070acb8..7b0cef9ca8f9 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -356,10 +356,9 @@ int __init valkyriefb_init(void)
}
#endif /* ppc (!CONFIG_MAC) */
- p = kmalloc(sizeof(*p), GFP_ATOMIC);
+ p = kzalloc(sizeof(*p), GFP_ATOMIC);
if (p == 0)
return -ENOMEM;
- memset(p, 0, sizeof(*p));
/* Map in frame buffer and registers */
if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) {
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index 30c0b948852b..4c3a63308df1 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -68,26 +68,26 @@ static const struct svga_pll vt8623_pll = {2, 127, 2, 7, 0, 3,
/* CRT timing register sets */
-struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
-struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
-struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
-struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
-struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
-struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
-
-struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
-struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
-struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
-struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
-struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
-struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
-
-struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
-struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
-struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
-struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
-
-struct svga_timing_regs vt8623_timing_regs = {
+static struct vga_regset vt8623_h_total_regs[] = {{0x00, 0, 7}, {0x36, 3, 3}, VGA_REGSET_END};
+static struct vga_regset vt8623_h_display_regs[] = {{0x01, 0, 7}, VGA_REGSET_END};
+static struct vga_regset vt8623_h_blank_start_regs[] = {{0x02, 0, 7}, VGA_REGSET_END};
+static struct vga_regset vt8623_h_blank_end_regs[] = {{0x03, 0, 4}, {0x05, 7, 7}, {0x33, 5, 5}, VGA_REGSET_END};
+static struct vga_regset vt8623_h_sync_start_regs[] = {{0x04, 0, 7}, {0x33, 4, 4}, VGA_REGSET_END};
+static struct vga_regset vt8623_h_sync_end_regs[] = {{0x05, 0, 4}, VGA_REGSET_END};
+
+static struct vga_regset vt8623_v_total_regs[] = {{0x06, 0, 7}, {0x07, 0, 0}, {0x07, 5, 5}, {0x35, 0, 0}, VGA_REGSET_END};
+static struct vga_regset vt8623_v_display_regs[] = {{0x12, 0, 7}, {0x07, 1, 1}, {0x07, 6, 6}, {0x35, 2, 2}, VGA_REGSET_END};
+static struct vga_regset vt8623_v_blank_start_regs[] = {{0x15, 0, 7}, {0x07, 3, 3}, {0x09, 5, 5}, {0x35, 3, 3}, VGA_REGSET_END};
+static struct vga_regset vt8623_v_blank_end_regs[] = {{0x16, 0, 7}, VGA_REGSET_END};
+static struct vga_regset vt8623_v_sync_start_regs[] = {{0x10, 0, 7}, {0x07, 2, 2}, {0x07, 7, 7}, {0x35, 1, 1}, VGA_REGSET_END};
+static struct vga_regset vt8623_v_sync_end_regs[] = {{0x11, 0, 3}, VGA_REGSET_END};
+
+static struct vga_regset vt8623_offset_regs[] = {{0x13, 0, 7}, {0x35, 5, 7}, VGA_REGSET_END};
+static struct vga_regset vt8623_line_compare_regs[] = {{0x18, 0, 7}, {0x07, 4, 4}, {0x09, 6, 6}, {0x33, 0, 2}, {0x35, 4, 4}, VGA_REGSET_END};
+static struct vga_regset vt8623_fetch_count_regs[] = {{0x1C, 0, 7}, {0x1D, 0, 1}, VGA_REGSET_END};
+static struct vga_regset vt8623_start_address_regs[] = {{0x0d, 0, 7}, {0x0c, 0, 7}, {0x34, 0, 7}, {0x48, 0, 1}, VGA_REGSET_END};
+
+static struct svga_timing_regs vt8623_timing_regs = {
vt8623_h_total_regs, vt8623_h_display_regs, vt8623_h_blank_start_regs,
vt8623_h_blank_end_regs, vt8623_h_sync_start_regs, vt8623_h_sync_end_regs,
vt8623_v_total_regs, vt8623_v_display_regs, vt8623_v_blank_start_regs,
@@ -903,7 +903,7 @@ static void __exit vt8623fb_cleanup(void)
/* Driver Initialisation */
-int __init vt8623fb_init(void)
+static int __init vt8623fb_init(void)
{
#ifndef MODULE
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index ca75b3ad3a2e..6854fd6b9714 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -1,8 +1,6 @@
-menu "Dallas's 1-wire bus"
- depends on HAS_IOMEM
-
-config W1
+menuconfig W1
tristate "Dallas's 1-wire support"
+ depends on HAS_IOMEM
---help---
Dallas' 1-wire bus is useful to connect slow 1-pin devices
such as iButtons and thermal sensors.
@@ -12,8 +10,10 @@ config W1
This W1 support can also be built as a module. If so, the module
will be called wire.ko.
+if W1
+
config W1_CON
- depends on CONNECTOR && W1
+ depends on CONNECTOR
bool "Userspace communication over connector"
default y
--- help ---
@@ -27,4 +27,4 @@ config W1_CON
source drivers/w1/masters/Kconfig
source drivers/w1/slaves/Kconfig
-endmenu
+endif # W1
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig
index 8f779338f744..8236d447adf5 100644
--- a/drivers/w1/masters/Kconfig
+++ b/drivers/w1/masters/Kconfig
@@ -3,11 +3,10 @@
#
menu "1-wire Bus Masters"
- depends on W1
config W1_MASTER_MATROX
tristate "Matrox G400 transport layer for 1-wire"
- depends on W1 && PCI
+ depends on PCI
help
Say Y here if you want to communicate with your 1-wire devices
using Matrox's G400 GPIO pins.
@@ -17,7 +16,7 @@ config W1_MASTER_MATROX
config W1_MASTER_DS2490
tristate "DS2490 USB <-> W1 transport layer for 1-wire"
- depends on W1 && USB
+ depends on USB
help
Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges,
for example DS9490*.
@@ -27,7 +26,7 @@ config W1_MASTER_DS2490
config W1_MASTER_DS2482
tristate "Maxim DS2482 I2C to 1-Wire bridge"
- depends on I2C && W1 && EXPERIMENTAL
+ depends on I2C && EXPERIMENTAL
help
If you say yes here you get support for the Maxim DS2482
I2C to 1-Wire bridge.
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
index 6f9d880ab2e9..d356da5709fc 100644
--- a/drivers/w1/masters/matrox_w1.c
+++ b/drivers/w1/masters/matrox_w1.c
@@ -164,7 +164,7 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi
if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
return -ENODEV;
- dev = kmalloc(sizeof(struct matrox_device) +
+ dev = kzalloc(sizeof(struct matrox_device) +
sizeof(struct w1_bus_master), GFP_KERNEL);
if (!dev) {
dev_err(&pdev->dev,
@@ -173,7 +173,6 @@ static int __devinit matrox_w1_probe(struct pci_dev *pdev, const struct pci_devi
return -ENOMEM;
}
- memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master));
dev->bus_master = (struct w1_bus_master *)(dev + 1);
diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index df95d6c2cefa..3df29a122f84 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -3,25 +3,21 @@
#
menu "1-wire Slaves"
- depends on W1
config W1_SLAVE_THERM
tristate "Thermal family implementation"
- depends on W1
help
Say Y here if you want to connect 1-wire thermal sensors to your
wire.
config W1_SLAVE_SMEM
tristate "Simple 64bit memory family implementation"
- depends on W1
help
Say Y here if you want to connect 1-wire
simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
config W1_SLAVE_DS2433
tristate "4kb EEPROM family support (DS2433)"
- depends on W1
help
Say Y here if you want to use a 1-wire
4kb EEPROM family device (DS2433).
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index 8ea17a53eed8..858c16a544c2 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -91,8 +91,9 @@ static int w1_f23_refresh_block(struct w1_slave *sl, struct w1_f23_data *data,
}
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
-static ssize_t w1_f23_read_bin(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t w1_f23_read_bin(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
@@ -199,8 +200,9 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
return 0;
}
-static ssize_t w1_f23_write_bin(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t w1_f23_write_bin(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
int addr, len, idx;
@@ -252,7 +254,6 @@ static struct bin_attribute w1_f23_bin_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = W1_EEPROM_SIZE,
.read = w1_f23_read_bin,
@@ -265,10 +266,9 @@ static int w1_f23_add_slave(struct w1_slave *sl)
#ifdef CONFIG_W1_SLAVE_DS2433_CRC
struct w1_f23_data *data;
- data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
+ data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- memset(data, 0, sizeof(struct w1_f23_data));
sl->family_data = data;
#endif /* CONFIG_W1_SLAVE_DS2433_CRC */
diff --git a/drivers/w1/slaves/w1_ds2760.c b/drivers/w1/slaves/w1_ds2760.c
index 88a37fbccc3f..ed6b0576208c 100644
--- a/drivers/w1/slaves/w1_ds2760.c
+++ b/drivers/w1/slaves/w1_ds2760.c
@@ -68,8 +68,9 @@ int w1_ds2760_write(struct device *dev, char *buf, int addr, size_t count)
return w1_ds2760_io(dev, buf, addr, count, 1);
}
-static ssize_t w1_ds2760_read_bin(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t w1_ds2760_read_bin(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
return w1_ds2760_read(dev, buf, off, count);
@@ -121,8 +122,6 @@ static void release_bat_id(int id)
mutex_lock(&bat_idr_lock);
idr_remove(&bat_idr, id);
mutex_unlock(&bat_idr_lock);
-
- return;
}
static int w1_ds2760_add_slave(struct w1_slave *sl)
@@ -174,8 +173,6 @@ static void w1_ds2760_remove_slave(struct w1_slave *sl)
platform_device_unregister(pdev);
release_bat_id(id);
sysfs_remove_bin_file(&sl->dev.kobj, &w1_ds2760_bin_attr);
-
- return;
}
static struct w1_family_ops w1_ds2760_fops = {
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 1a6937dc190b..4318935678c5 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -42,13 +42,13 @@ static u8 bad_roms[][9] = {
{}
};
-static ssize_t w1_therm_read_bin(struct kobject *, char *, loff_t, size_t);
+static ssize_t w1_therm_read_bin(struct kobject *, struct bin_attribute *,
+ char *, loff_t, size_t);
static struct bin_attribute w1_therm_bin_attr = {
.attr = {
.name = "w1_slave",
.mode = S_IRUGO,
- .owner = THIS_MODULE,
},
.size = W1_SLAVE_DATA_SIZE,
.read = w1_therm_read_bin,
@@ -159,7 +159,9 @@ static int w1_therm_check_rom(u8 rom[9])
return 0;
}
-static ssize_t w1_therm_read_bin(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t w1_therm_read_bin(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
struct w1_master *dev = sl->master;
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 7d6876dbcc96..8d7ab74170d5 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -105,7 +105,9 @@ static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *a
return sprintf(buf, "%s\n", sl->name);
}
-static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read_id(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -128,7 +130,6 @@ static struct bin_attribute w1_slave_attr_bin_id = {
.attr = {
.name = "id",
.mode = S_IRUGO,
- .owner = THIS_MODULE,
},
.size = 8,
.read = w1_slave_read_id,
@@ -136,7 +137,9 @@ static struct bin_attribute w1_slave_attr_bin_id = {
/* Default family */
-static ssize_t w1_default_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t w1_default_write(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -153,7 +156,9 @@ out_up:
return count;
}
-static ssize_t w1_default_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
+static ssize_t w1_default_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct w1_slave *sl = kobj_to_w1_slave(kobj);
@@ -167,7 +172,6 @@ static struct bin_attribute w1_default_attr = {
.attr = {
.name = "rw",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE,
},
.size = PAGE_SIZE,
.read = w1_default_read,
@@ -516,7 +520,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
int err;
struct w1_netlink_msg msg;
- sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
+ sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
if (!sl) {
dev_err(&dev->dev,
"%s: failed to allocate new slave device.\n",
@@ -524,7 +528,6 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
return -ENOMEM;
}
- memset(sl, 0, sizeof(*sl));
sl->owner = THIS_MODULE;
sl->master = dev;
@@ -801,6 +804,7 @@ static int w1_control(void *data)
struct w1_master *dev, *n;
int have_to_wait = 0;
+ set_freezable();
while (!kthread_should_stop() || have_to_wait) {
have_to_wait = 0;
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 258defdb2efd..2fbd8dd16df5 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -41,7 +41,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
/*
* We are in process context(kernel thread), so can sleep.
*/
- dev = kmalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
+ dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
if (!dev) {
printk(KERN_ERR
"Failed to allocate %zd bytes for new w1 device.\n",
@@ -49,7 +49,6 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
return NULL;
}
- memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
dev->bus_master = (struct w1_bus_master *)(dev + 1);
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
new file mode 100644
index 000000000000..56592f0d6cef
--- /dev/null
+++ b/drivers/xen/Makefile
@@ -0,0 +1,2 @@
+obj-y += grant-table.o
+obj-y += xenbus/
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
new file mode 100644
index 000000000000..ea94dbabf9a9
--- /dev/null
+++ b/drivers/xen/grant-table.c
@@ -0,0 +1,582 @@
+/******************************************************************************
+ * grant_table.c
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * Copyright (c) 2005-2006, Christopher Clark
+ * Copyright (c) 2004-2005, K A 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.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <asm/pgtable.h>
+#include <asm/sync_bitops.h>
+
+
+/* External tools reserve first few grant table entries. */
+#define NR_RESERVED_ENTRIES 8
+#define GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry))
+
+static grant_ref_t **gnttab_list;
+static unsigned int nr_grant_frames;
+static unsigned int boot_max_nr_grant_frames;
+static int gnttab_free_count;
+static grant_ref_t gnttab_free_head;
+static DEFINE_SPINLOCK(gnttab_list_lock);
+
+static struct grant_entry *shared;
+
+static struct gnttab_free_callback *gnttab_free_callback_list;
+
+static int gnttab_expand(unsigned int req_entries);
+
+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
+
+static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
+{
+ return &gnttab_list[(entry) / RPP][(entry) % RPP];
+}
+/* This can be used as an l-value */
+#define gnttab_entry(entry) (*__gnttab_entry(entry))
+
+static int get_free_entries(unsigned count)
+{
+ unsigned long flags;
+ int ref, rc;
+ grant_ref_t head;
+
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+
+ if ((gnttab_free_count < count) &&
+ ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+ return rc;
+ }
+
+ ref = head = gnttab_free_head;
+ gnttab_free_count -= count;
+ while (count-- > 1)
+ head = gnttab_entry(head);
+ gnttab_free_head = gnttab_entry(head);
+ gnttab_entry(head) = GNTTAB_LIST_END;
+
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+
+ return ref;
+}
+
+static void do_free_callbacks(void)
+{
+ struct gnttab_free_callback *callback, *next;
+
+ callback = gnttab_free_callback_list;
+ gnttab_free_callback_list = NULL;
+
+ while (callback != NULL) {
+ next = callback->next;
+ if (gnttab_free_count >= callback->count) {
+ callback->next = NULL;
+ callback->fn(callback->arg);
+ } else {
+ callback->next = gnttab_free_callback_list;
+ gnttab_free_callback_list = callback;
+ }
+ callback = next;
+ }
+}
+
+static inline void check_free_callbacks(void)
+{
+ if (unlikely(gnttab_free_callback_list))
+ do_free_callbacks();
+}
+
+static void put_free_entry(grant_ref_t ref)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ gnttab_entry(ref) = gnttab_free_head;
+ gnttab_free_head = ref;
+ gnttab_free_count++;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
+static void update_grant_entry(grant_ref_t ref, domid_t domid,
+ unsigned long frame, unsigned flags)
+{
+ /*
+ * Introducing a valid entry into the grant table:
+ * 1. Write ent->domid.
+ * 2. Write ent->frame:
+ * GTF_permit_access: Frame to which access is permitted.
+ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ * frame, or zero if none.
+ * 3. Write memory barrier (WMB).
+ * 4. Write ent->flags, inc. valid type.
+ */
+ shared[ref].frame = frame;
+ shared[ref].domid = domid;
+ wmb();
+ shared[ref].flags = flags;
+}
+
+/*
+ * Public grant-issuing interface functions
+ */
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+ unsigned long frame, int readonly)
+{
+ update_grant_entry(ref, domid, frame,
+ GTF_permit_access | (readonly ? GTF_readonly : 0));
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+ int readonly)
+{
+ int ref;
+
+ ref = get_free_entries(1);
+ if (unlikely(ref < 0))
+ return -ENOSPC;
+
+ gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
+
+ return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
+
+int gnttab_query_foreign_access(grant_ref_t ref)
+{
+ u16 nflags;
+
+ nflags = shared[ref].flags;
+
+ return (nflags & (GTF_reading|GTF_writing));
+}
+EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
+
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
+{
+ u16 flags, nflags;
+
+ nflags = shared[ref].flags;
+ do {
+ flags = nflags;
+ if (flags & (GTF_reading|GTF_writing)) {
+ printk(KERN_ALERT "WARNING: g.e. still in use!\n");
+ return 0;
+ }
+ } while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
+
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+ unsigned long page)
+{
+ if (gnttab_end_foreign_access_ref(ref, readonly)) {
+ put_free_entry(ref);
+ if (page != 0)
+ free_page(page);
+ } else {
+ /* XXX This needs to be fixed so that the ref and page are
+ placed on a list to be freed up later. */
+ printk(KERN_WARNING
+ "WARNING: leaking g.e. and page still in use!\n");
+ }
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
+{
+ int ref;
+
+ ref = get_free_entries(1);
+ if (unlikely(ref < 0))
+ return -ENOSPC;
+ gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
+
+ return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
+ unsigned long pfn)
+{
+ update_grant_entry(ref, domid, pfn, GTF_accept_transfer);
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
+{
+ unsigned long frame;
+ u16 flags;
+
+ /*
+ * If a transfer is not even yet started, try to reclaim the grant
+ * reference and return failure (== 0).
+ */
+ while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
+ if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags)
+ return 0;
+ cpu_relax();
+ }
+
+ /* If a transfer is in progress then wait until it is completed. */
+ while (!(flags & GTF_transfer_completed)) {
+ flags = shared[ref].flags;
+ cpu_relax();
+ }
+
+ rmb(); /* Read the frame number /after/ reading completion status. */
+ frame = shared[ref].frame;
+ BUG_ON(frame == 0);
+
+ return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
+{
+ unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
+ put_free_entry(ref);
+ return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
+
+void gnttab_free_grant_reference(grant_ref_t ref)
+{
+ put_free_entry(ref);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
+
+void gnttab_free_grant_references(grant_ref_t head)
+{
+ grant_ref_t ref;
+ unsigned long flags;
+ int count = 1;
+ if (head == GNTTAB_LIST_END)
+ return;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ ref = head;
+ while (gnttab_entry(ref) != GNTTAB_LIST_END) {
+ ref = gnttab_entry(ref);
+ count++;
+ }
+ gnttab_entry(ref) = gnttab_free_head;
+ gnttab_free_head = head;
+ gnttab_free_count += count;
+ check_free_callbacks();
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
+
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
+{
+ int h = get_free_entries(count);
+
+ if (h < 0)
+ return -ENOSPC;
+
+ *head = h;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
+
+int gnttab_empty_grant_references(const grant_ref_t *private_head)
+{
+ return (*private_head == GNTTAB_LIST_END);
+}
+EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
+
+int gnttab_claim_grant_reference(grant_ref_t *private_head)
+{
+ grant_ref_t g = *private_head;
+ if (unlikely(g == GNTTAB_LIST_END))
+ return -ENOSPC;
+ *private_head = gnttab_entry(g);
+ return g;
+}
+EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+ grant_ref_t release)
+{
+ gnttab_entry(release) = *private_head;
+ *private_head = release;
+}
+EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+ void (*fn)(void *), void *arg, u16 count)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ if (callback->next)
+ goto out;
+ callback->fn = fn;
+ callback->arg = arg;
+ callback->count = count;
+ callback->next = gnttab_free_callback_list;
+ gnttab_free_callback_list = callback;
+ check_free_callbacks();
+out:
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
+
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
+{
+ struct gnttab_free_callback **pcb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gnttab_list_lock, flags);
+ for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
+ if (*pcb == callback) {
+ *pcb = callback->next;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
+
+static int grow_gnttab_list(unsigned int more_frames)
+{
+ unsigned int new_nr_grant_frames, extra_entries, i;
+
+ new_nr_grant_frames = nr_grant_frames + more_frames;
+ extra_entries = more_frames * GREFS_PER_GRANT_FRAME;
+
+ for (i = nr_grant_frames; i < new_nr_grant_frames; i++) {
+ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
+ if (!gnttab_list[i])
+ goto grow_nomem;
+ }
+
+
+ for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+ i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+ gnttab_entry(i) = i + 1;
+
+ gnttab_entry(i) = gnttab_free_head;
+ gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+ gnttab_free_count += extra_entries;
+
+ nr_grant_frames = new_nr_grant_frames;
+
+ check_free_callbacks();
+
+ return 0;
+
+grow_nomem:
+ for ( ; i >= nr_grant_frames; i--)
+ free_page((unsigned long) gnttab_list[i]);
+ return -ENOMEM;
+}
+
+static unsigned int __max_nr_grant_frames(void)
+{
+ struct gnttab_query_size query;
+ int rc;
+
+ query.dom = DOMID_SELF;
+
+ rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
+ if ((rc < 0) || (query.status != GNTST_okay))
+ return 4; /* Legacy max supported number of frames */
+
+ return query.max_nr_frames;
+}
+
+static inline unsigned int max_nr_grant_frames(void)
+{
+ unsigned int xen_max = __max_nr_grant_frames();
+
+ if (xen_max > boot_max_nr_grant_frames)
+ return boot_max_nr_grant_frames;
+ 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;
+ unsigned long *frames;
+ unsigned int nr_gframes = end_idx + 1;
+ int rc;
+
+ frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
+ if (!frames)
+ return -ENOMEM;
+
+ setup.dom = DOMID_SELF;
+ setup.nr_frames = nr_gframes;
+ setup.frame_list = frames;
+
+ rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+ if (rc == -ENOSYS) {
+ kfree(frames);
+ return -ENOSYS;
+ }
+
+ 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);
+ BUG_ON(rc);
+ frames -= nr_gframes; /* adjust after map_pte_fn() */
+
+ kfree(frames);
+
+ return 0;
+}
+
+static int gnttab_resume(void)
+{
+ if (max_nr_grant_frames() < nr_grant_frames)
+ return -ENOSYS;
+ return gnttab_map(0, nr_grant_frames - 1);
+}
+
+static int gnttab_suspend(void)
+{
+ apply_to_page_range(&init_mm, (unsigned long)shared,
+ PAGE_SIZE * nr_grant_frames,
+ unmap_pte_fn, NULL);
+
+ return 0;
+}
+
+static int gnttab_expand(unsigned int req_entries)
+{
+ int rc;
+ unsigned int cur, extra;
+
+ cur = nr_grant_frames;
+ extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
+ GREFS_PER_GRANT_FRAME);
+ if (cur + extra > max_nr_grant_frames())
+ return -ENOSPC;
+
+ rc = gnttab_map(cur, cur + extra - 1);
+ if (rc == 0)
+ rc = grow_gnttab_list(extra);
+
+ return rc;
+}
+
+static int __devinit gnttab_init(void)
+{
+ int i;
+ unsigned int max_nr_glist_frames;
+ unsigned int nr_init_grefs;
+
+ if (!is_running_on_xen())
+ return -ENODEV;
+
+ nr_grant_frames = 1;
+ boot_max_nr_grant_frames = __max_nr_grant_frames();
+
+ /* Determine the maximum number of frames required for the
+ * grant reference free list on the current hypervisor.
+ */
+ max_nr_glist_frames = (boot_max_nr_grant_frames *
+ GREFS_PER_GRANT_FRAME /
+ (PAGE_SIZE / sizeof(grant_ref_t)));
+
+ gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
+ GFP_KERNEL);
+ if (gnttab_list == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_grant_frames; i++) {
+ gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
+ if (gnttab_list[i] == NULL)
+ goto ini_nomem;
+ }
+
+ if (gnttab_resume() < 0)
+ return -ENODEV;
+
+ nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+
+ for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
+ gnttab_entry(i) = i + 1;
+
+ gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
+ gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
+ gnttab_free_head = NR_RESERVED_ENTRIES;
+
+ printk("Grant table initialized\n");
+ return 0;
+
+ ini_nomem:
+ for (i--; i >= 0; i--)
+ free_page((unsigned long)gnttab_list[i]);
+ kfree(gnttab_list);
+ return -ENOMEM;
+}
+
+core_initcall(gnttab_init);
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
new file mode 100644
index 000000000000..5571f5b84223
--- /dev/null
+++ b/drivers/xen/xenbus/Makefile
@@ -0,0 +1,7 @@
+obj-y += xenbus.o
+
+xenbus-objs =
+xenbus-objs += xenbus_client.o
+xenbus-objs += xenbus_comms.o
+xenbus-objs += xenbus_xs.o
+xenbus-objs += xenbus_probe.o
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
new file mode 100644
index 000000000000..9fd2f70ab46d
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -0,0 +1,569 @@
+/******************************************************************************
+ * Client-facing interface for the Xenbus driver. In other words, the
+ * interface between the Xenbus and the device-specific code, be it the
+ * frontend or the backend of that driver.
+ *
+ * Copyright (C) 2005 XenSource 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; 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/types.h>
+#include <linux/vmalloc.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+ static const char *const name[] = {
+ [ XenbusStateUnknown ] = "Unknown",
+ [ XenbusStateInitialising ] = "Initialising",
+ [ XenbusStateInitWait ] = "InitWait",
+ [ XenbusStateInitialised ] = "Initialised",
+ [ XenbusStateConnected ] = "Connected",
+ [ XenbusStateClosing ] = "Closing",
+ [ XenbusStateClosed ] = "Closed",
+ };
+ return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+EXPORT_SYMBOL_GPL(xenbus_strstate);
+
+/**
+ * xenbus_watch_path - register a watch
+ * @dev: xenbus device
+ * @path: path to watch
+ * @watch: watch to register
+ * @callback: callback to register
+ *
+ * Register a @watch on the given path, using the given xenbus_watch structure
+ * for storage, and the given @callback function as the callback. Return 0 on
+ * success, or -errno on error. On success, the given @path will be saved as
+ * @watch->node, and remains the caller's to free. On error, @watch->node will
+ * be NULL, the device will switch to %XenbusStateClosing, and the error will
+ * be saved in the store.
+ */
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int))
+{
+ int err;
+
+ watch->node = path;
+ watch->callback = callback;
+
+ err = register_xenbus_watch(watch);
+
+ if (err) {
+ watch->node = NULL;
+ watch->callback = NULL;
+ xenbus_dev_fatal(dev, err, "adding watch on %s", path);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_path);
+
+
+/**
+ * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path
+ * @dev: xenbus device
+ * @watch: watch to register
+ * @callback: callback to register
+ * @pathfmt: format of path to watch
+ *
+ * Register a watch on the given @path, using the given xenbus_watch
+ * structure for storage, and the given @callback function as the callback.
+ * Return 0 on success, or -errno on error. On success, the watched path
+ * (@path/@path2) will be saved as @watch->node, and becomes the caller's to
+ * kfree(). On error, watch->node will be NULL, so the caller has nothing to
+ * free, the device will switch to %XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_watch_pathfmt(struct xenbus_device *dev,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int),
+ const char *pathfmt, ...)
+{
+ int err;
+ va_list ap;
+ char *path;
+
+ va_start(ap, pathfmt);
+ path = kvasprintf(GFP_KERNEL, pathfmt, ap);
+ va_end(ap);
+
+ if (!path) {
+ xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
+ return -ENOMEM;
+ }
+ err = xenbus_watch_path(dev, path, watch, callback);
+
+ if (err)
+ kfree(path);
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
+
+
+/**
+ * xenbus_switch_state
+ * @dev: xenbus device
+ * @xbt: transaction handle
+ * @state: new state
+ *
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Return 0 on success, or -errno on error. On error, the device will switch
+ * to XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+{
+ /* We check whether the state is currently set to the given value, and
+ if not, then the state is set. We don't want to unconditionally
+ write the given state, because we don't want to fire watches
+ unnecessarily. Furthermore, if the node has gone, we don't write
+ to it, as the device will be tearing down, and we don't want to
+ resurrect that directory.
+
+ Note that, because of this cached value of our state, this function
+ will not work inside a Xenstore transaction (something it was
+ trying to in the past) because dev->state would not get reset if
+ the transaction was aborted.
+
+ */
+
+ int current_state;
+ int err;
+
+ if (state == dev->state)
+ return 0;
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
+ &current_state);
+ if (err != 1)
+ return 0;
+
+ err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
+ if (err) {
+ if (state != XenbusStateClosing) /* Avoid looping */
+ xenbus_dev_fatal(dev, err, "writing new state");
+ return err;
+ }
+
+ dev->state = state;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_switch_state);
+
+int xenbus_frontend_closed(struct xenbus_device *dev)
+{
+ xenbus_switch_state(dev, XenbusStateClosed);
+ complete(&dev->down);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
+
+/**
+ * Return the path to the error node for the given device, or NULL on failure.
+ * If the value returned is non-NULL, then it is the caller's to kfree.
+ */
+static char *error_path(struct xenbus_device *dev)
+{
+ return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
+}
+
+
+static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
+ const char *fmt, va_list ap)
+{
+ int ret;
+ unsigned int len;
+ char *printf_buffer = NULL;
+ char *path_buffer = NULL;
+
+#define PRINTF_BUFFER_SIZE 4096
+ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+ if (printf_buffer == NULL)
+ goto fail;
+
+ len = sprintf(printf_buffer, "%i ", -err);
+ ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
+
+ BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
+
+ dev_err(&dev->dev, "%s\n", printf_buffer);
+
+ path_buffer = error_path(dev);
+
+ if (path_buffer == NULL) {
+ dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+ dev->nodename, printf_buffer);
+ goto fail;
+ }
+
+ if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
+ dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+ dev->nodename, printf_buffer);
+ goto fail;
+ }
+
+fail:
+ kfree(printf_buffer);
+ kfree(path_buffer);
+}
+
+
+/**
+ * xenbus_dev_error
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Report the given negative errno into the store, along with the given
+ * formatted message.
+ */
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xenbus_va_dev_error(dev, err, fmt, ap);
+ va_end(ap);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_error);
+
+/**
+ * xenbus_dev_fatal
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
+ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * closedown of this driver and its peer.
+ */
+
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xenbus_va_dev_error(dev, err, fmt, ap);
+ va_end(ap);
+
+ xenbus_switch_state(dev, XenbusStateClosing);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
+
+/**
+ * xenbus_grant_ring
+ * @dev: xenbus device
+ * @ring_mfn: mfn of ring to grant
+
+ * Grant access to the given @ring_mfn to the peer of the given device. Return
+ * 0 on success, or -errno on error. On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
+{
+ int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
+ if (err < 0)
+ xenbus_dev_fatal(dev, err, "granting access to ring page");
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_grant_ring);
+
+
+/**
+ * Allocate an event channel for the given xenbus_device, assigning the newly
+ * created local port to *port. Return 0 on success, or -errno on error. On
+ * error, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+{
+ struct evtchn_alloc_unbound alloc_unbound;
+ int err;
+
+ alloc_unbound.dom = DOMID_SELF;
+ alloc_unbound.remote_dom = dev->otherend_id;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+ &alloc_unbound);
+ if (err)
+ xenbus_dev_fatal(dev, err, "allocating event channel");
+ else
+ *port = alloc_unbound.port;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
+
+
+/**
+ * Bind to an existing interdomain event channel in another domain. Returns 0
+ * on success and stores the local port in *port. On error, returns -errno,
+ * switches the device to XenbusStateClosing, and saves the error in XenStore.
+ */
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
+{
+ struct evtchn_bind_interdomain bind_interdomain;
+ int err;
+
+ bind_interdomain.remote_dom = dev->otherend_id;
+ bind_interdomain.remote_port = remote_port;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+ &bind_interdomain);
+ if (err)
+ xenbus_dev_fatal(dev, err,
+ "binding to event channel %d from domain %d",
+ remote_port, dev->otherend_id);
+ else
+ *port = bind_interdomain.local_port;
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_bind_evtchn);
+
+
+/**
+ * Free an existing event channel. Returns 0 on success or -errno on error.
+ */
+int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+{
+ struct evtchn_close close;
+ int err;
+
+ close.port = port;
+
+ err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+ if (err)
+ xenbus_dev_error(dev, err, "freeing event channel %d", port);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
+
+
+/**
+ * xenbus_map_ring_valloc
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @vaddr: pointer to address to be filled out by mapping
+ *
+ * Based on Rusty Russell's skeleton driver's map_page.
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
+ * page to that address, and sets *vaddr to that address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
+{
+ struct gnttab_map_grant_ref op = {
+ .flags = GNTMAP_host_map,
+ .ref = gnt_ref,
+ .dom = dev->otherend_id,
+ };
+ struct vm_struct *area;
+
+ *vaddr = NULL;
+
+ area = alloc_vm_area(PAGE_SIZE);
+ if (!area)
+ return -ENOMEM;
+
+ op.host_addr = (unsigned long)area->addr;
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay) {
+ free_vm_area(area);
+ xenbus_dev_fatal(dev, op.status,
+ "mapping in shared page %d from domain %d",
+ gnt_ref, dev->otherend_id);
+ return op.status;
+ }
+
+ /* Stuff the handle in an unused field */
+ area->phys_addr = (unsigned long)op.handle;
+
+ *vaddr = area->addr;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
+
+
+/**
+ * xenbus_map_ring
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @handle: pointer to grant handle to be filled
+ * @vaddr: address to be mapped to
+ *
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring does not allocate the virtual address space (you must do
+ * this yourself!). It only maps in the page to the specified address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+ grant_handle_t *handle, void *vaddr)
+{
+ struct gnttab_map_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ .flags = GNTMAP_host_map,
+ .ref = gnt_ref,
+ .dom = dev->otherend_id,
+ };
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay) {
+ xenbus_dev_fatal(dev, op.status,
+ "mapping in shared page %d from domain %d",
+ gnt_ref, dev->otherend_id);
+ } else
+ *handle = op.handle;
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring);
+
+
+/**
+ * xenbus_unmap_ring_vfree
+ * @dev: xenbus device
+ * @vaddr: addr to unmap
+ *
+ * Based on Rusty Russell's skeleton driver's unmap_page.
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Use xenbus_unmap_ring_vfree if you mapped in your memory with
+ * xenbus_map_ring_valloc (it will free the virtual address space).
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
+{
+ struct vm_struct *area;
+ struct gnttab_unmap_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ };
+
+ /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
+ * method so that we don't have to muck with vmalloc internals here.
+ * We could force the user to hang on to their struct vm_struct from
+ * xenbus_map_ring_valloc, but these 6 lines considerably simplify
+ * this API.
+ */
+ read_lock(&vmlist_lock);
+ for (area = vmlist; area != NULL; area = area->next) {
+ if (area->addr == vaddr)
+ break;
+ }
+ read_unlock(&vmlist_lock);
+
+ if (!area) {
+ xenbus_dev_error(dev, -ENOENT,
+ "can't find mapped virtual address %p", vaddr);
+ return GNTST_bad_virt_addr;
+ }
+
+ op.handle = (grant_handle_t)area->phys_addr;
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status == GNTST_okay)
+ free_vm_area(area);
+ else
+ xenbus_dev_error(dev, op.status,
+ "unmapping page at handle %d error %d",
+ (int16_t)area->phys_addr, op.status);
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
+
+
+/**
+ * xenbus_unmap_ring
+ * @dev: xenbus device
+ * @handle: grant handle
+ * @vaddr: addr to unmap
+ *
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring(struct xenbus_device *dev,
+ grant_handle_t handle, void *vaddr)
+{
+ struct gnttab_unmap_grant_ref op = {
+ .host_addr = (unsigned long)vaddr,
+ .handle = handle,
+ };
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status != GNTST_okay)
+ xenbus_dev_error(dev, op.status,
+ "unmapping page at handle %d error %d",
+ handle, op.status);
+
+ return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
+
+
+/**
+ * xenbus_read_driver_state
+ * @path: path for driver
+ *
+ * Return the state of the driver rooted at the given store path, or
+ * XenbusStateUnknown if no state can be read.
+ */
+enum xenbus_state xenbus_read_driver_state(const char *path)
+{
+ enum xenbus_state result;
+ int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
+ if (err)
+ result = XenbusStateUnknown;
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
new file mode 100644
index 000000000000..6efbe3f29ca5
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenbus_comms.c
+ *
+ * Low level code to talks to Xen Store: ringbuffer and event channel.
+ *
+ * Copyright (C) 2005 Rusty Russell, 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/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include "xenbus_comms.h"
+
+static int xenbus_irq;
+
+static DECLARE_WORK(probe_work, xenbus_probe);
+
+static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
+
+static irqreturn_t wake_waiting(int irq, void *unused)
+{
+ if (unlikely(xenstored_ready == 0)) {
+ xenstored_ready = 1;
+ schedule_work(&probe_work);
+ }
+
+ wake_up(&xb_waitq);
+ return IRQ_HANDLED;
+}
+
+static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+ return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+static void *get_output_chunk(XENSTORE_RING_IDX cons,
+ XENSTORE_RING_IDX prod,
+ char *buf, uint32_t *len)
+{
+ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+ if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+ *len = XENSTORE_RING_SIZE - (prod - cons);
+ return buf + MASK_XENSTORE_IDX(prod);
+}
+
+static const void *get_input_chunk(XENSTORE_RING_IDX cons,
+ XENSTORE_RING_IDX prod,
+ const char *buf, uint32_t *len)
+{
+ *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+ if ((prod - cons) < *len)
+ *len = prod - cons;
+ return buf + MASK_XENSTORE_IDX(cons);
+}
+
+/**
+ * xb_write - low level write
+ * @data: buffer to send
+ * @len: length of buffer
+ *
+ * Returns 0 on success, error otherwise.
+ */
+int xb_write(const void *data, unsigned len)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ XENSTORE_RING_IDX cons, prod;
+ int rc;
+
+ while (len != 0) {
+ void *dst;
+ unsigned int avail;
+
+ rc = wait_event_interruptible(
+ xb_waitq,
+ (intf->req_prod - intf->req_cons) !=
+ XENSTORE_RING_SIZE);
+ if (rc < 0)
+ return rc;
+
+ /* Read indexes, then verify. */
+ cons = intf->req_cons;
+ prod = intf->req_prod;
+ if (!check_indexes(cons, prod)) {
+ intf->req_cons = intf->req_prod = 0;
+ return -EIO;
+ }
+
+ dst = get_output_chunk(cons, prod, intf->req, &avail);
+ if (avail == 0)
+ continue;
+ if (avail > len)
+ avail = len;
+
+ /* Must write data /after/ reading the consumer index. */
+ mb();
+
+ memcpy(dst, data, avail);
+ data += avail;
+ len -= avail;
+
+ /* Other side must not see new producer until data is there. */
+ wmb();
+ intf->req_prod += avail;
+
+ /* Implies mb(): other side will see the updated producer. */
+ notify_remote_via_evtchn(xen_store_evtchn);
+ }
+
+ return 0;
+}
+
+int xb_data_to_read(void)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ return (intf->rsp_cons != intf->rsp_prod);
+}
+
+int xb_wait_for_data_to_read(void)
+{
+ return wait_event_interruptible(xb_waitq, xb_data_to_read());
+}
+
+int xb_read(void *data, unsigned len)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ XENSTORE_RING_IDX cons, prod;
+ int rc;
+
+ while (len != 0) {
+ unsigned int avail;
+ const char *src;
+
+ rc = xb_wait_for_data_to_read();
+ if (rc < 0)
+ return rc;
+
+ /* Read indexes, then verify. */
+ cons = intf->rsp_cons;
+ prod = intf->rsp_prod;
+ if (!check_indexes(cons, prod)) {
+ intf->rsp_cons = intf->rsp_prod = 0;
+ return -EIO;
+ }
+
+ src = get_input_chunk(cons, prod, intf->rsp, &avail);
+ if (avail == 0)
+ continue;
+ if (avail > len)
+ avail = len;
+
+ /* Must read data /after/ reading the producer index. */
+ rmb();
+
+ memcpy(data, src, avail);
+ data += avail;
+ len -= avail;
+
+ /* Other side must not see free space until we've copied out */
+ mb();
+ intf->rsp_cons += avail;
+
+ pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
+
+ /* Implies mb(): other side will see the updated consumer. */
+ notify_remote_via_evtchn(xen_store_evtchn);
+ }
+
+ return 0;
+}
+
+/**
+ * xb_init_comms - Set up interrupt handler off store event channel.
+ */
+int xb_init_comms(void)
+{
+ struct xenstore_domain_interface *intf = xen_store_interface;
+ int err;
+
+ if (intf->req_prod != intf->req_cons)
+ printk(KERN_ERR "XENBUS request ring is not quiescent "
+ "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+
+ if (intf->rsp_prod != intf->rsp_cons) {
+ printk(KERN_WARNING "XENBUS response ring is not quiescent "
+ "(%08x:%08x): fixing up\n",
+ intf->rsp_cons, intf->rsp_prod);
+ intf->rsp_cons = intf->rsp_prod;
+ }
+
+ if (xenbus_irq)
+ unbind_from_irqhandler(xenbus_irq, &xb_waitq);
+
+ err = bind_evtchn_to_irqhandler(
+ xen_store_evtchn, wake_waiting,
+ 0, "xenbus", &xb_waitq);
+ if (err <= 0) {
+ printk(KERN_ERR "XENBUS request irq failed %i\n", err);
+ return err;
+ }
+
+ xenbus_irq = err;
+
+ return 0;
+}
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
new file mode 100644
index 000000000000..c21db7513736
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.h
@@ -0,0 +1,46 @@
+/*
+ * Private include for xenbus communications.
+ *
+ * Copyright (C) 2005 Rusty Russell, 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.
+ */
+
+#ifndef _XENBUS_COMMS_H
+#define _XENBUS_COMMS_H
+
+int xs_init(void);
+int xb_init_comms(void);
+
+/* Low level routines. */
+int xb_write(const void *data, unsigned len);
+int xb_read(void *data, unsigned len);
+int xb_data_to_read(void);
+int xb_wait_for_data_to_read(void);
+int xs_input_avail(void);
+extern struct xenstore_domain_interface *xen_store_interface;
+extern int xen_store_evtchn;
+
+#endif /* _XENBUS_COMMS_H */
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
new file mode 100644
index 000000000000..0b769f7c4a48
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -0,0 +1,935 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource 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; 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.
+ */
+
+#define DPRINTK(fmt, args...) \
+ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
+ __func__, __LINE__, ##args)
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+int xen_store_evtchn;
+struct xenstore_domain_interface *xen_store_interface;
+static unsigned long xen_store_mfn;
+
+static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
+
+static void wait_for_devices(struct xenbus_driver *xendrv);
+
+static int xenbus_probe_frontend(const char *type, const char *name);
+
+static void xenbus_dev_shutdown(struct device *_dev);
+
+/* If something in array of ids matches this device, return it. */
+static const struct xenbus_device_id *
+match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
+{
+ for (; *arr->devicetype != '\0'; arr++) {
+ if (!strcmp(arr->devicetype, dev->devicetype))
+ return arr;
+ }
+ return NULL;
+}
+
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct xenbus_driver *drv = to_xenbus_driver(_drv);
+
+ if (!drv->ids)
+ return 0;
+
+ return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
+}
+
+/* device/<type>/<id> => <type>-<id> */
+static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
+{
+ nodename = strchr(nodename, '/');
+ if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
+ printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+ return -EINVAL;
+ }
+
+ strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
+ if (!strchr(bus_id, '/')) {
+ printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+ return -EINVAL;
+ }
+ *strchr(bus_id, '/') = '-';
+ return 0;
+}
+
+
+static void free_otherend_details(struct xenbus_device *dev)
+{
+ kfree(dev->otherend);
+ dev->otherend = NULL;
+}
+
+
+static void free_otherend_watch(struct xenbus_device *dev)
+{
+ if (dev->otherend_watch.node) {
+ unregister_xenbus_watch(&dev->otherend_watch);
+ kfree(dev->otherend_watch.node);
+ dev->otherend_watch.node = NULL;
+ }
+}
+
+
+int read_otherend_details(struct xenbus_device *xendev,
+ char *id_node, char *path_node)
+{
+ int err = xenbus_gather(XBT_NIL, xendev->nodename,
+ id_node, "%i", &xendev->otherend_id,
+ path_node, NULL, &xendev->otherend,
+ NULL);
+ if (err) {
+ xenbus_dev_fatal(xendev, err,
+ "reading other end details from %s",
+ xendev->nodename);
+ return err;
+ }
+ if (strlen(xendev->otherend) == 0 ||
+ !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
+ xenbus_dev_fatal(xendev, -ENOENT,
+ "unable to read other end from %s. "
+ "missing or inaccessible.",
+ xendev->nodename);
+ free_otherend_details(xendev);
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+
+static int read_backend_details(struct xenbus_device *xendev)
+{
+ return read_otherend_details(xendev, "backend-id", "backend");
+}
+
+
+/* Bus type for frontend drivers. */
+static struct xen_bus_type xenbus_frontend = {
+ .root = "device",
+ .levels = 2, /* device/type/<id> */
+ .get_bus_id = frontend_bus_id,
+ .probe = xenbus_probe_frontend,
+ .bus = {
+ .name = "xen",
+ .match = xenbus_match,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
+ },
+};
+
+static void otherend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ struct xenbus_device *dev =
+ container_of(watch, struct xenbus_device, otherend_watch);
+ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+ enum xenbus_state state;
+
+ /* Protect us against watches firing on old details when the otherend
+ details change, say immediately after a resume. */
+ if (!dev->otherend ||
+ strncmp(dev->otherend, vec[XS_WATCH_PATH],
+ strlen(dev->otherend))) {
+ dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]);
+ return;
+ }
+
+ state = xenbus_read_driver_state(dev->otherend);
+
+ dev_dbg(&dev->dev, "state is %d, (%s), %s, %s",
+ state, xenbus_strstate(state), dev->otherend_watch.node,
+ vec[XS_WATCH_PATH]);
+
+ /*
+ * Ignore xenbus transitions during shutdown. This prevents us doing
+ * work that can fail e.g., when the rootfs is gone.
+ */
+ if (system_state > SYSTEM_RUNNING) {
+ struct xen_bus_type *bus = bus;
+ bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+ /* If we're frontend, drive the state machine to Closed. */
+ /* This should cause the backend to release our resources. */
+ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+ xenbus_frontend_closed(dev);
+ return;
+ }
+
+ if (drv->otherend_changed)
+ drv->otherend_changed(dev, state);
+}
+
+
+static int talk_to_otherend(struct xenbus_device *dev)
+{
+ struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+
+ free_otherend_watch(dev);
+ free_otherend_details(dev);
+
+ return drv->read_otherend_details(dev);
+}
+
+
+static int watch_otherend(struct xenbus_device *dev)
+{
+ return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed,
+ "%s/%s", dev->otherend, "state");
+}
+
+
+int xenbus_dev_probe(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+ const struct xenbus_device_id *id;
+ int err;
+
+ DPRINTK("%s", dev->nodename);
+
+ if (!drv->probe) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ id = match_device(drv->ids, dev);
+ if (!id) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ err = talk_to_otherend(dev);
+ if (err) {
+ dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n",
+ dev->nodename);
+ return err;
+ }
+
+ err = drv->probe(dev, id);
+ if (err)
+ goto fail;
+
+ err = watch_otherend(dev);
+ if (err) {
+ dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
+ dev->nodename);
+ return err;
+ }
+
+ return 0;
+fail:
+ xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
+ xenbus_switch_state(dev, XenbusStateClosed);
+ return -ENODEV;
+}
+
+int xenbus_dev_remove(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+
+ DPRINTK("%s", dev->nodename);
+
+ free_otherend_watch(dev);
+ free_otherend_details(dev);
+
+ if (drv->remove)
+ drv->remove(dev);
+
+ xenbus_switch_state(dev, XenbusStateClosed);
+ return 0;
+}
+
+static void xenbus_dev_shutdown(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ unsigned long timeout = 5*HZ;
+
+ DPRINTK("%s", dev->nodename);
+
+ get_device(&dev->dev);
+ if (dev->state != XenbusStateConnected) {
+ printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
+ dev->nodename, xenbus_strstate(dev->state));
+ goto out;
+ }
+ xenbus_switch_state(dev, XenbusStateClosing);
+ timeout = wait_for_completion_timeout(&dev->down, timeout);
+ if (!timeout)
+ printk(KERN_INFO "%s: %s timeout closing device\n",
+ __func__, dev->nodename);
+ out:
+ put_device(&dev->dev);
+}
+
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus,
+ struct module *owner,
+ const char *mod_name)
+{
+ drv->driver.name = drv->name;
+ drv->driver.bus = &bus->bus;
+ drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
+
+ return driver_register(&drv->driver);
+}
+
+int __xenbus_register_frontend(struct xenbus_driver *drv,
+ struct module *owner, const char *mod_name)
+{
+ int ret;
+
+ drv->read_otherend_details = read_backend_details;
+
+ ret = xenbus_register_driver_common(drv, &xenbus_frontend,
+ owner, mod_name);
+ if (ret)
+ return ret;
+
+ /* If this driver is loaded as a module wait for devices to attach. */
+ wait_for_devices(drv);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
+
+void xenbus_unregister_driver(struct xenbus_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
+
+struct xb_find_info
+{
+ struct xenbus_device *dev;
+ const char *nodename;
+};
+
+static int cmp_dev(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct xb_find_info *info = data;
+
+ if (!strcmp(xendev->nodename, info->nodename)) {
+ info->dev = xendev;
+ get_device(dev);
+ return 1;
+ }
+ return 0;
+}
+
+struct xenbus_device *xenbus_device_find(const char *nodename,
+ struct bus_type *bus)
+{
+ struct xb_find_info info = { .dev = NULL, .nodename = nodename };
+
+ bus_for_each_dev(bus, NULL, &info, cmp_dev);
+ return info.dev;
+}
+
+static int cleanup_dev(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct xb_find_info *info = data;
+ int len = strlen(info->nodename);
+
+ DPRINTK("%s", info->nodename);
+
+ /* Match the info->nodename path, or any subdirectory of that path. */
+ if (strncmp(xendev->nodename, info->nodename, len))
+ return 0;
+
+ /* If the node name is longer, ensure it really is a subdirectory. */
+ if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
+ return 0;
+
+ info->dev = xendev;
+ get_device(dev);
+ return 1;
+}
+
+static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
+{
+ struct xb_find_info info = { .nodename = path };
+
+ do {
+ info.dev = NULL;
+ bus_for_each_dev(bus, NULL, &info, cleanup_dev);
+ if (info.dev) {
+ device_unregister(&info.dev->dev);
+ put_device(&info.dev->dev);
+ }
+ } while (info.dev);
+}
+
+static void xenbus_dev_release(struct device *dev)
+{
+ if (dev)
+ kfree(to_xenbus_device(dev));
+}
+
+static ssize_t xendev_show_nodename(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
+}
+DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
+
+static ssize_t xendev_show_devtype(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
+}
+DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+
+
+int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename)
+{
+ int err;
+ struct xenbus_device *xendev;
+ size_t stringlen;
+ char *tmpstring;
+
+ enum xenbus_state state = xenbus_read_driver_state(nodename);
+
+ if (state != XenbusStateInitialising) {
+ /* Device is not new, so ignore it. This can happen if a
+ device is going away after switching to Closed. */
+ return 0;
+ }
+
+ stringlen = strlen(nodename) + 1 + strlen(type) + 1;
+ xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
+ if (!xendev)
+ return -ENOMEM;
+
+ xendev->state = XenbusStateInitialising;
+
+ /* Copy the strings into the extra space. */
+
+ tmpstring = (char *)(xendev + 1);
+ strcpy(tmpstring, nodename);
+ xendev->nodename = tmpstring;
+
+ tmpstring += strlen(tmpstring) + 1;
+ strcpy(tmpstring, type);
+ xendev->devicetype = tmpstring;
+ init_completion(&xendev->down);
+
+ xendev->dev.bus = &bus->bus;
+ xendev->dev.release = xenbus_dev_release;
+
+ err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
+ if (err)
+ goto fail;
+
+ /* Register with generic device framework. */
+ err = device_register(&xendev->dev);
+ if (err)
+ goto fail;
+
+ err = device_create_file(&xendev->dev, &dev_attr_nodename);
+ if (err)
+ goto fail_unregister;
+
+ err = device_create_file(&xendev->dev, &dev_attr_devtype);
+ if (err)
+ goto fail_remove_file;
+
+ return 0;
+fail_remove_file:
+ device_remove_file(&xendev->dev, &dev_attr_nodename);
+fail_unregister:
+ device_unregister(&xendev->dev);
+fail:
+ kfree(xendev);
+ return err;
+}
+
+/* device/<typename>/<name> */
+static int xenbus_probe_frontend(const char *type, const char *name)
+{
+ char *nodename;
+ int err;
+
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s",
+ xenbus_frontend.root, type, name);
+ if (!nodename)
+ return -ENOMEM;
+
+ DPRINTK("%s", nodename);
+
+ err = xenbus_probe_node(&xenbus_frontend, type, nodename);
+ kfree(nodename);
+ return err;
+}
+
+static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
+{
+ int err = 0;
+ char **dir;
+ unsigned int dir_n = 0;
+ int i;
+
+ dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ for (i = 0; i < dir_n; i++) {
+ err = bus->probe(type, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ return err;
+}
+
+int xenbus_probe_devices(struct xen_bus_type *bus)
+{
+ int err = 0;
+ char **dir;
+ unsigned int i, dir_n;
+
+ dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ for (i = 0; i < dir_n; i++) {
+ err = xenbus_probe_device_type(bus, dir[i]);
+ if (err)
+ break;
+ }
+ kfree(dir);
+ return err;
+}
+
+static unsigned int char_count(const char *str, char c)
+{
+ unsigned int i, ret = 0;
+
+ for (i = 0; str[i]; i++)
+ if (str[i] == c)
+ ret++;
+ return ret;
+}
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; str[i]; i++)
+ if (str[i] == c) {
+ if (len == 0)
+ return i;
+ len--;
+ }
+ return (len == 0) ? i : -ERANGE;
+}
+
+void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
+{
+ int exists, rootlen;
+ struct xenbus_device *dev;
+ char type[BUS_ID_SIZE];
+ const char *p, *root;
+
+ if (char_count(node, '/') < 2)
+ return;
+
+ exists = xenbus_exists(XBT_NIL, node, "");
+ if (!exists) {
+ xenbus_cleanup_devices(node, &bus->bus);
+ return;
+ }
+
+ /* backend/<type>/... or device/<type>/... */
+ p = strchr(node, '/') + 1;
+ snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
+ type[BUS_ID_SIZE-1] = '\0';
+
+ rootlen = strsep_len(node, '/', bus->levels);
+ if (rootlen < 0)
+ return;
+ root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
+ if (!root)
+ return;
+
+ dev = xenbus_device_find(root, &bus->bus);
+ if (!dev)
+ xenbus_probe_node(bus, type, root);
+ else
+ put_device(&dev->dev);
+
+ kfree(root);
+}
+
+static void frontend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ DPRINTK("");
+
+ xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+}
+
+/* We watch for devices appearing and vanishing. */
+static struct xenbus_watch fe_watch = {
+ .node = "device",
+ .callback = frontend_changed,
+};
+
+static int suspend_dev(struct device *dev, void *data)
+{
+ int err = 0;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+ if (drv->suspend)
+ err = drv->suspend(xdev);
+ if (err)
+ printk(KERN_WARNING
+ "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
+ return 0;
+}
+
+static int suspend_cancel_dev(struct device *dev, void *data)
+{
+ int err = 0;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+ if (drv->suspend_cancel)
+ err = drv->suspend_cancel(xdev);
+ if (err)
+ printk(KERN_WARNING
+ "xenbus: suspend_cancel %s failed: %i\n",
+ dev->bus_id, err);
+ return 0;
+}
+
+static int resume_dev(struct device *dev, void *data)
+{
+ int err;
+ struct xenbus_driver *drv;
+ struct xenbus_device *xdev;
+
+ DPRINTK("");
+
+ if (dev->driver == NULL)
+ return 0;
+
+ drv = to_xenbus_driver(dev->driver);
+ xdev = container_of(dev, struct xenbus_device, dev);
+
+ err = talk_to_otherend(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus: resume (talk_to_otherend) %s failed: %i\n",
+ dev->bus_id, err);
+ return err;
+ }
+
+ xdev->state = XenbusStateInitialising;
+
+ if (drv->resume) {
+ err = drv->resume(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus: resume %s failed: %i\n",
+ dev->bus_id, err);
+ return err;
+ }
+ }
+
+ err = watch_otherend(xdev);
+ if (err) {
+ printk(KERN_WARNING
+ "xenbus_probe: resume (watch_otherend) %s failed: "
+ "%d.\n", dev->bus_id, err);
+ return err;
+ }
+
+ return 0;
+}
+
+void xenbus_suspend(void)
+{
+ DPRINTK("");
+
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
+ xenbus_backend_suspend(suspend_dev);
+ xs_suspend();
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend);
+
+void xenbus_resume(void)
+{
+ xb_init_comms();
+ xs_resume();
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
+ xenbus_backend_resume(resume_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_resume);
+
+void xenbus_suspend_cancel(void)
+{
+ xs_suspend_cancel();
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev);
+ xenbus_backend_resume(suspend_cancel_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend_cancel);
+
+/* A flag to determine if xenstored is 'ready' (i.e. has started) */
+int xenstored_ready = 0;
+
+
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+ int ret = 0;
+
+ if (xenstored_ready > 0)
+ ret = nb->notifier_call(nb, 0, NULL);
+ else
+ blocking_notifier_chain_register(&xenstore_chain, nb);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+ blocking_notifier_chain_unregister(&xenstore_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
+
+void xenbus_probe(struct work_struct *unused)
+{
+ BUG_ON((xenstored_ready <= 0));
+
+ /* Enumerate devices in xenstore and watch for changes. */
+ xenbus_probe_devices(&xenbus_frontend);
+ register_xenbus_watch(&fe_watch);
+ xenbus_backend_probe_and_watch();
+
+ /* Notify others that xenstore is up */
+ blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
+}
+
+static int __init xenbus_probe_init(void)
+{
+ int err = 0;
+
+ DPRINTK("");
+
+ err = -ENODEV;
+ if (!is_running_on_xen())
+ goto out_error;
+
+ /* Register ourselves with the kernel bus subsystem */
+ err = bus_register(&xenbus_frontend.bus);
+ if (err)
+ goto out_error;
+
+ err = xenbus_backend_bus_register();
+ if (err)
+ goto out_unreg_front;
+
+ /*
+ * Domain0 doesn't have a store_evtchn or store_mfn yet.
+ */
+ if (is_initial_xendomain()) {
+ /* dom0 not yet supported */
+ } else {
+ xenstored_ready = 1;
+ xen_store_evtchn = xen_start_info->store_evtchn;
+ xen_store_mfn = xen_start_info->store_mfn;
+ }
+ xen_store_interface = mfn_to_virt(xen_store_mfn);
+
+ /* Initialize the interface to xenstore. */
+ err = xs_init();
+ if (err) {
+ printk(KERN_WARNING
+ "XENBUS: Error initializing xenstore comms: %i\n", err);
+ goto out_unreg_back;
+ }
+
+ if (!is_initial_xendomain())
+ xenbus_probe(NULL);
+
+ return 0;
+
+ out_unreg_back:
+ xenbus_backend_bus_unregister();
+
+ out_unreg_front:
+ bus_unregister(&xenbus_frontend.bus);
+
+ out_error:
+ return err;
+}
+
+postcore_initcall(xenbus_probe_init);
+
+MODULE_LICENSE("GPL");
+
+static int is_disconnected_device(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct device_driver *drv = data;
+
+ /*
+ * A device with no driver will never connect. We care only about
+ * devices which should currently be in the process of connecting.
+ */
+ if (!dev->driver)
+ return 0;
+
+ /* Is this search limited to a particular driver? */
+ if (drv && (dev->driver != drv))
+ return 0;
+
+ return (xendev->state != XenbusStateConnected);
+}
+
+static int exists_disconnected_device(struct device_driver *drv)
+{
+ return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ is_disconnected_device);
+}
+
+static int print_device_status(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+ struct device_driver *drv = data;
+
+ /* Is this operation limited to a particular driver? */
+ if (drv && (dev->driver != drv))
+ return 0;
+
+ if (!dev->driver) {
+ /* Information only: is this too noisy? */
+ printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
+ xendev->nodename);
+ } else if (xendev->state != XenbusStateConnected) {
+ printk(KERN_WARNING "XENBUS: Timeout connecting "
+ "to device: %s (state %d)\n",
+ xendev->nodename, xendev->state);
+ }
+
+ return 0;
+}
+
+/* We only wait for device setup after most initcalls have run. */
+static int ready_to_wait_for_devices;
+
+/*
+ * On a 10 second timeout, wait for all devices currently configured. We need
+ * to do this to guarantee that the filesystems and / or network devices
+ * needed for boot are available, before we can allow the boot to proceed.
+ *
+ * This needs to be on a late_initcall, to happen after the frontend device
+ * drivers have been initialised, but before the root fs is mounted.
+ *
+ * A possible improvement here would be to have the tools add a per-device
+ * flag to the store entry, indicating whether it is needed at boot time.
+ * This would allow people who knew what they were doing to accelerate their
+ * boot slightly, but of course needs tools or manual intervention to set up
+ * those flags correctly.
+ */
+static void wait_for_devices(struct xenbus_driver *xendrv)
+{
+ unsigned long timeout = jiffies + 10*HZ;
+ struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
+
+ if (!ready_to_wait_for_devices || !is_running_on_xen())
+ return;
+
+ while (exists_disconnected_device(drv)) {
+ if (time_after(jiffies, timeout))
+ break;
+ schedule_timeout_interruptible(HZ/10);
+ }
+
+ bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+ print_device_status);
+}
+
+#ifndef MODULE
+static int __init boot_wait_for_devices(void)
+{
+ ready_to_wait_for_devices = 1;
+ wait_for_devices(NULL);
+ return 0;
+}
+
+late_initcall(boot_wait_for_devices);
+#endif
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
new file mode 100644
index 000000000000..e09b19415a40
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * xenbus_probe.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource 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; 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 _XENBUS_PROBE_H
+#define _XENBUS_PROBE_H
+
+#ifdef CONFIG_XEN_BACKEND
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
+extern void xenbus_backend_probe_and_watch(void);
+extern int xenbus_backend_bus_register(void);
+extern void xenbus_backend_bus_unregister(void);
+#else
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_probe_and_watch(void) {}
+static inline int xenbus_backend_bus_register(void) { return 0; }
+static inline void xenbus_backend_bus_unregister(void) {}
+#endif
+
+struct xen_bus_type
+{
+ char *root;
+ unsigned int levels;
+ int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
+ int (*probe)(const char *type, const char *dir);
+ struct bus_type bus;
+};
+
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
+extern int xenbus_dev_probe(struct device *_dev);
+extern int xenbus_dev_remove(struct device *_dev);
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
+ struct xen_bus_type *bus,
+ struct module *owner,
+ const char *mod_name);
+extern int xenbus_probe_node(struct xen_bus_type *bus,
+ const char *type,
+ const char *nodename);
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
+
+extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+
+#endif
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
new file mode 100644
index 000000000000..9e943fbce81b
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -0,0 +1,861 @@
+/******************************************************************************
+ * xenbus_xs.c
+ *
+ * This is the kernel equivalent of the "xs" library. We don't need everything
+ * and we use xenbus_comms for communication.
+ *
+ * Copyright (C) 2005 Rusty Russell, 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/unistd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/kthread.h>
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include "xenbus_comms.h"
+
+struct xs_stored_msg {
+ struct list_head list;
+
+ struct xsd_sockmsg hdr;
+
+ union {
+ /* Queued replies. */
+ struct {
+ char *body;
+ } reply;
+
+ /* Queued watch events. */
+ struct {
+ struct xenbus_watch *handle;
+ char **vec;
+ unsigned int vec_size;
+ } watch;
+ } u;
+};
+
+struct xs_handle {
+ /* A list of replies. Currently only one will ever be outstanding. */
+ struct list_head reply_list;
+ spinlock_t reply_lock;
+ wait_queue_head_t reply_waitq;
+
+ /*
+ * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
+ * response_mutex is never taken simultaneously with the other three.
+ */
+
+ /* One request at a time. */
+ struct mutex request_mutex;
+
+ /* Protect xenbus reader thread against save/restore. */
+ struct mutex response_mutex;
+
+ /* Protect transactions against save/restore. */
+ struct rw_semaphore transaction_mutex;
+
+ /* Protect watch (de)register against save/restore. */
+ struct rw_semaphore watch_mutex;
+};
+
+static struct xs_handle xs_state;
+
+/* List of registered watches, and a lock to protect it. */
+static LIST_HEAD(watches);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch callback events, and a lock to protect it. */
+static LIST_HEAD(watch_events);
+static DEFINE_SPINLOCK(watch_events_lock);
+
+/*
+ * Details of the xenwatch callback kernel thread. The thread waits on the
+ * watch_events_waitq for work to do (queued on watch_events list). When it
+ * wakes up it acquires the xenwatch_mutex before reading the list and
+ * carrying out work.
+ */
+static pid_t xenwatch_pid;
+static DEFINE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
+
+static int get_error(const char *errorstring)
+{
+ unsigned int i;
+
+ for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
+ if (i == ARRAY_SIZE(xsd_errors) - 1) {
+ printk(KERN_WARNING
+ "XENBUS xen store gave: unknown error %s",
+ errorstring);
+ return EINVAL;
+ }
+ }
+ return xsd_errors[i].errnum;
+}
+
+static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
+{
+ struct xs_stored_msg *msg;
+ char *body;
+
+ spin_lock(&xs_state.reply_lock);
+
+ while (list_empty(&xs_state.reply_list)) {
+ spin_unlock(&xs_state.reply_lock);
+ /* XXX FIXME: Avoid synchronous wait for response here. */
+ wait_event(xs_state.reply_waitq,
+ !list_empty(&xs_state.reply_list));
+ spin_lock(&xs_state.reply_lock);
+ }
+
+ msg = list_entry(xs_state.reply_list.next,
+ struct xs_stored_msg, list);
+ list_del(&msg->list);
+
+ spin_unlock(&xs_state.reply_lock);
+
+ *type = msg->hdr.type;
+ if (len)
+ *len = msg->hdr.len;
+ body = msg->u.reply.body;
+
+ kfree(msg);
+
+ return body;
+}
+
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+{
+ void *ret;
+ struct xsd_sockmsg req_msg = *msg;
+ int err;
+
+ if (req_msg.type == XS_TRANSACTION_START)
+ down_read(&xs_state.transaction_mutex);
+
+ mutex_lock(&xs_state.request_mutex);
+
+ err = xb_write(msg, sizeof(*msg) + msg->len);
+ if (err) {
+ msg->type = XS_ERROR;
+ ret = ERR_PTR(err);
+ } else
+ ret = read_reply(&msg->type, &msg->len);
+
+ mutex_unlock(&xs_state.request_mutex);
+
+ if ((msg->type == XS_TRANSACTION_END) ||
+ ((req_msg.type == XS_TRANSACTION_START) &&
+ (msg->type == XS_ERROR)))
+ up_read(&xs_state.transaction_mutex);
+
+ return ret;
+}
+
+/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
+static void *xs_talkv(struct xenbus_transaction t,
+ enum xsd_sockmsg_type type,
+ const struct kvec *iovec,
+ unsigned int num_vecs,
+ unsigned int *len)
+{
+ struct xsd_sockmsg msg;
+ void *ret = NULL;
+ unsigned int i;
+ int err;
+
+ msg.tx_id = t.id;
+ msg.req_id = 0;
+ msg.type = type;
+ msg.len = 0;
+ for (i = 0; i < num_vecs; i++)
+ msg.len += iovec[i].iov_len;
+
+ mutex_lock(&xs_state.request_mutex);
+
+ err = xb_write(&msg, sizeof(msg));
+ if (err) {
+ mutex_unlock(&xs_state.request_mutex);
+ return ERR_PTR(err);
+ }
+
+ for (i = 0; i < num_vecs; i++) {
+ err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
+ if (err) {
+ mutex_unlock(&xs_state.request_mutex);
+ return ERR_PTR(err);
+ }
+ }
+
+ ret = read_reply(&msg.type, len);
+
+ mutex_unlock(&xs_state.request_mutex);
+
+ if (IS_ERR(ret))
+ return ret;
+
+ if (msg.type == XS_ERROR) {
+ err = get_error(ret);
+ kfree(ret);
+ return ERR_PTR(-err);
+ }
+
+ if (msg.type != type) {
+ if (printk_ratelimit())
+ printk(KERN_WARNING
+ "XENBUS unexpected type [%d], expected [%d]\n",
+ msg.type, type);
+ kfree(ret);
+ return ERR_PTR(-EINVAL);
+ }
+ return ret;
+}
+
+/* Simplified version of xs_talkv: single message. */
+static void *xs_single(struct xenbus_transaction t,
+ enum xsd_sockmsg_type type,
+ const char *string,
+ unsigned int *len)
+{
+ struct kvec iovec;
+
+ iovec.iov_base = (void *)string;
+ iovec.iov_len = strlen(string) + 1;
+ return xs_talkv(t, type, &iovec, 1, len);
+}
+
+/* Many commands only need an ack, don't care what it says. */
+static int xs_error(char *reply)
+{
+ if (IS_ERR(reply))
+ return PTR_ERR(reply);
+ kfree(reply);
+ return 0;
+}
+
+static unsigned int count_strings(const char *strings, unsigned int len)
+{
+ unsigned int num;
+ const char *p;
+
+ for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
+ num++;
+
+ return num;
+}
+
+/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
+static char *join(const char *dir, const char *name)
+{
+ char *buffer;
+
+ if (strlen(name) == 0)
+ buffer = kasprintf(GFP_KERNEL, "%s", dir);
+ else
+ buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+ return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
+}
+
+static char **split(char *strings, unsigned int len, unsigned int *num)
+{
+ char *p, **ret;
+
+ /* Count the strings. */
+ *num = count_strings(strings, len);
+
+ /* Transfer to one big alloc for easy freeing. */
+ ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
+ if (!ret) {
+ kfree(strings);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(&ret[*num], strings, len);
+ kfree(strings);
+
+ strings = (char *)&ret[*num];
+ for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
+ ret[(*num)++] = p;
+
+ return ret;
+}
+
+char **xenbus_directory(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *num)
+{
+ char *strings, *path;
+ unsigned int len;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return (char **)path;
+
+ strings = xs_single(t, XS_DIRECTORY, path, &len);
+ kfree(path);
+ if (IS_ERR(strings))
+ return (char **)strings;
+
+ return split(strings, len, num);
+}
+EXPORT_SYMBOL_GPL(xenbus_directory);
+
+/* Check if a path exists. Return 1 if it does. */
+int xenbus_exists(struct xenbus_transaction t,
+ const char *dir, const char *node)
+{
+ char **d;
+ int dir_n;
+
+ d = xenbus_directory(t, dir, node, &dir_n);
+ if (IS_ERR(d))
+ return 0;
+ kfree(d);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(xenbus_exists);
+
+/* Get the value of a single file.
+ * Returns a kmalloced value: call free() on it after use.
+ * len indicates length in bytes.
+ */
+void *xenbus_read(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *len)
+{
+ char *path;
+ void *ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return (void *)path;
+
+ ret = xs_single(t, XS_READ, path, len);
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_read);
+
+/* Write the value of a single file.
+ * Returns -err on failure.
+ */
+int xenbus_write(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *string)
+{
+ const char *path;
+ struct kvec iovec[2];
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ iovec[0].iov_base = (void *)path;
+ iovec[0].iov_len = strlen(path) + 1;
+ iovec[1].iov_base = (void *)string;
+ iovec[1].iov_len = strlen(string);
+
+ ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_write);
+
+/* Create a new directory. */
+int xenbus_mkdir(struct xenbus_transaction t,
+ const char *dir, const char *node)
+{
+ char *path;
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_mkdir);
+
+/* Destroy a file or directory (directories must be empty). */
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
+{
+ char *path;
+ int ret;
+
+ path = join(dir, node);
+ if (IS_ERR(path))
+ return PTR_ERR(path);
+
+ ret = xs_error(xs_single(t, XS_RM, path, NULL));
+ kfree(path);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_rm);
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ */
+int xenbus_transaction_start(struct xenbus_transaction *t)
+{
+ char *id_str;
+
+ down_read(&xs_state.transaction_mutex);
+
+ id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
+ if (IS_ERR(id_str)) {
+ up_read(&xs_state.transaction_mutex);
+ return PTR_ERR(id_str);
+ }
+
+ t->id = simple_strtoul(id_str, NULL, 0);
+ kfree(id_str);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_start);
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ */
+int xenbus_transaction_end(struct xenbus_transaction t, int abort)
+{
+ char abortstr[2];
+ int err;
+
+ if (abort)
+ strcpy(abortstr, "F");
+ else
+ strcpy(abortstr, "T");
+
+ err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
+
+ up_read(&xs_state.transaction_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_end);
+
+/* Single read and scanf: returns -errno or num scanned. */
+int xenbus_scanf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *val;
+
+ val = xenbus_read(t, dir, node, NULL);
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ va_start(ap, fmt);
+ ret = vsscanf(val, fmt, ap);
+ va_end(ap);
+ kfree(val);
+ /* Distinctive errno. */
+ if (ret == 0)
+ return -ERANGE;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_scanf);
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+#define PRINTF_BUFFER_SIZE 4096
+ char *printf_buffer;
+
+ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+ if (printf_buffer == NULL)
+ return -ENOMEM;
+
+ va_start(ap, fmt);
+ ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
+ va_end(ap);
+
+ BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+ ret = xenbus_write(t, dir, node, printf_buffer);
+
+ kfree(printf_buffer);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_printf);
+
+/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
+{
+ va_list ap;
+ const char *name;
+ int ret = 0;
+
+ va_start(ap, dir);
+ while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+ const char *fmt = va_arg(ap, char *);
+ void *result = va_arg(ap, void *);
+ char *p;
+
+ p = xenbus_read(t, dir, name, NULL);
+ if (IS_ERR(p)) {
+ ret = PTR_ERR(p);
+ break;
+ }
+ if (fmt) {
+ if (sscanf(p, fmt, result) == 0)
+ ret = -EINVAL;
+ kfree(p);
+ } else
+ *(char **)result = p;
+ }
+ va_end(ap);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_gather);
+
+static int xs_watch(const char *path, const char *token)
+{
+ struct kvec iov[2];
+
+ iov[0].iov_base = (void *)path;
+ iov[0].iov_len = strlen(path) + 1;
+ iov[1].iov_base = (void *)token;
+ iov[1].iov_len = strlen(token) + 1;
+
+ return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,
+ ARRAY_SIZE(iov), NULL));
+}
+
+static int xs_unwatch(const char *path, const char *token)
+{
+ struct kvec iov[2];
+
+ iov[0].iov_base = (char *)path;
+ iov[0].iov_len = strlen(path) + 1;
+ iov[1].iov_base = (char *)token;
+ iov[1].iov_len = strlen(token) + 1;
+
+ return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,
+ ARRAY_SIZE(iov), NULL));
+}
+
+static struct xenbus_watch *find_watch(const char *token)
+{
+ struct xenbus_watch *i, *cmp;
+
+ cmp = (void *)simple_strtoul(token, NULL, 16);
+
+ list_for_each_entry(i, &watches, list)
+ if (i == cmp)
+ return i;
+
+ return NULL;
+}
+
+/* Register callback to watch this node. */
+int register_xenbus_watch(struct xenbus_watch *watch)
+{
+ /* Pointer in ascii is the token. */
+ char token[sizeof(watch) * 2 + 1];
+ int err;
+
+ sprintf(token, "%lX", (long)watch);
+
+ down_read(&xs_state.watch_mutex);
+
+ spin_lock(&watches_lock);
+ BUG_ON(find_watch(token));
+ list_add(&watch->list, &watches);
+ spin_unlock(&watches_lock);
+
+ err = xs_watch(watch->node, token);
+
+ /* Ignore errors due to multiple registration. */
+ if ((err != 0) && (err != -EEXIST)) {
+ spin_lock(&watches_lock);
+ list_del(&watch->list);
+ spin_unlock(&watches_lock);
+ }
+
+ up_read(&xs_state.watch_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(register_xenbus_watch);
+
+void unregister_xenbus_watch(struct xenbus_watch *watch)
+{
+ struct xs_stored_msg *msg, *tmp;
+ char token[sizeof(watch) * 2 + 1];
+ int err;
+
+ sprintf(token, "%lX", (long)watch);
+
+ down_read(&xs_state.watch_mutex);
+
+ spin_lock(&watches_lock);
+ BUG_ON(!find_watch(token));
+ list_del(&watch->list);
+ spin_unlock(&watches_lock);
+
+ err = xs_unwatch(watch->node, token);
+ if (err)
+ printk(KERN_WARNING
+ "XENBUS Failed to release watch %s: %i\n",
+ watch->node, err);
+
+ up_read(&xs_state.watch_mutex);
+
+ /* Make sure there are no callbacks running currently (unless
+ its us) */
+ if (current->pid != xenwatch_pid)
+ mutex_lock(&xenwatch_mutex);
+
+ /* Cancel pending watch events. */
+ spin_lock(&watch_events_lock);
+ list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+ if (msg->u.watch.handle != watch)
+ continue;
+ list_del(&msg->list);
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+ spin_unlock(&watch_events_lock);
+
+ if (current->pid != xenwatch_pid)
+ mutex_unlock(&xenwatch_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
+
+void xs_suspend(void)
+{
+ down_write(&xs_state.transaction_mutex);
+ down_write(&xs_state.watch_mutex);
+ mutex_lock(&xs_state.request_mutex);
+ mutex_lock(&xs_state.response_mutex);
+}
+
+void xs_resume(void)
+{
+ struct xenbus_watch *watch;
+ char token[sizeof(watch) * 2 + 1];
+
+ mutex_unlock(&xs_state.response_mutex);
+ mutex_unlock(&xs_state.request_mutex);
+ up_write(&xs_state.transaction_mutex);
+
+ /* No need for watches_lock: the watch_mutex is sufficient. */
+ list_for_each_entry(watch, &watches, list) {
+ sprintf(token, "%lX", (long)watch);
+ xs_watch(watch->node, token);
+ }
+
+ up_write(&xs_state.watch_mutex);
+}
+
+void xs_suspend_cancel(void)
+{
+ mutex_unlock(&xs_state.response_mutex);
+ mutex_unlock(&xs_state.request_mutex);
+ up_write(&xs_state.watch_mutex);
+ up_write(&xs_state.transaction_mutex);
+}
+
+static int xenwatch_thread(void *unused)
+{
+ struct list_head *ent;
+ struct xs_stored_msg *msg;
+
+ for (;;) {
+ wait_event_interruptible(watch_events_waitq,
+ !list_empty(&watch_events));
+
+ if (kthread_should_stop())
+ break;
+
+ mutex_lock(&xenwatch_mutex);
+
+ spin_lock(&watch_events_lock);
+ ent = watch_events.next;
+ if (ent != &watch_events)
+ list_del(ent);
+ spin_unlock(&watch_events_lock);
+
+ if (ent != &watch_events) {
+ msg = list_entry(ent, struct xs_stored_msg, list);
+ msg->u.watch.handle->callback(
+ msg->u.watch.handle,
+ (const char **)msg->u.watch.vec,
+ msg->u.watch.vec_size);
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+
+ mutex_unlock(&xenwatch_mutex);
+ }
+
+ return 0;
+}
+
+static int process_msg(void)
+{
+ struct xs_stored_msg *msg;
+ char *body;
+ int err;
+
+ /*
+ * We must disallow save/restore while reading a xenstore message.
+ * A partial read across s/r leaves us out of sync with xenstored.
+ */
+ for (;;) {
+ err = xb_wait_for_data_to_read();
+ if (err)
+ return err;
+ mutex_lock(&xs_state.response_mutex);
+ if (xb_data_to_read())
+ break;
+ /* We raced with save/restore: pending data 'disappeared'. */
+ mutex_unlock(&xs_state.response_mutex);
+ }
+
+
+ msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+ if (msg == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = xb_read(&msg->hdr, sizeof(msg->hdr));
+ if (err) {
+ kfree(msg);
+ goto out;
+ }
+
+ body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+ if (body == NULL) {
+ kfree(msg);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ err = xb_read(body, msg->hdr.len);
+ if (err) {
+ kfree(body);
+ kfree(msg);
+ goto out;
+ }
+ body[msg->hdr.len] = '\0';
+
+ if (msg->hdr.type == XS_WATCH_EVENT) {
+ msg->u.watch.vec = split(body, msg->hdr.len,
+ &msg->u.watch.vec_size);
+ if (IS_ERR(msg->u.watch.vec)) {
+ kfree(msg);
+ err = PTR_ERR(msg->u.watch.vec);
+ goto out;
+ }
+
+ spin_lock(&watches_lock);
+ msg->u.watch.handle = find_watch(
+ msg->u.watch.vec[XS_WATCH_TOKEN]);
+ if (msg->u.watch.handle != NULL) {
+ spin_lock(&watch_events_lock);
+ list_add_tail(&msg->list, &watch_events);
+ wake_up(&watch_events_waitq);
+ spin_unlock(&watch_events_lock);
+ } else {
+ kfree(msg->u.watch.vec);
+ kfree(msg);
+ }
+ spin_unlock(&watches_lock);
+ } else {
+ msg->u.reply.body = body;
+ spin_lock(&xs_state.reply_lock);
+ list_add_tail(&msg->list, &xs_state.reply_list);
+ spin_unlock(&xs_state.reply_lock);
+ wake_up(&xs_state.reply_waitq);
+ }
+
+ out:
+ mutex_unlock(&xs_state.response_mutex);
+ return err;
+}
+
+static int xenbus_thread(void *unused)
+{
+ int err;
+
+ for (;;) {
+ err = process_msg();
+ if (err)
+ printk(KERN_WARNING "XENBUS error %d while reading "
+ "message\n", err);
+ if (kthread_should_stop())
+ break;
+ }
+
+ return 0;
+}
+
+int xs_init(void)
+{
+ int err;
+ struct task_struct *task;
+
+ INIT_LIST_HEAD(&xs_state.reply_list);
+ spin_lock_init(&xs_state.reply_lock);
+ init_waitqueue_head(&xs_state.reply_waitq);
+
+ mutex_init(&xs_state.request_mutex);
+ mutex_init(&xs_state.response_mutex);
+ init_rwsem(&xs_state.transaction_mutex);
+ init_rwsem(&xs_state.watch_mutex);
+
+ /* Initialize the shared memory rings to talk to xenstored */
+ err = xb_init_comms();
+ if (err)
+ return err;
+
+ task = kthread_run(xenwatch_thread, NULL, "xenwatch");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ xenwatch_pid = task->pid;
+
+ task = kthread_run(xenbus_thread, NULL, "xenbus");
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+
+ return 0;
+}
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index c3ba0ec334c4..9130f1c12c26 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -49,8 +49,9 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute *
static DEVICE_ATTR(resource, S_IRUGO, zorro_show_resource, NULL);
-static ssize_t zorro_read_config(struct kobject *kobj, char *buf, loff_t off,
- size_t count)
+static ssize_t zorro_read_config(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct zorro_dev *z = to_zorro_dev(container_of(kobj, struct device,
kobj));
@@ -78,7 +79,6 @@ static struct bin_attribute zorro_config_attr = {
.attr = {
.name = "config",
.mode = S_IRUGO | S_IWUSR,
- .owner = THIS_MODULE
},
.size = sizeof(struct ConfigDev),
.read = zorro_read_config,
diff --git a/fs/9p/9p.h b/fs/9p/9p.h
deleted file mode 100644
index 94e2f92ab2e8..000000000000
--- a/fs/9p/9p.h
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * linux/fs/9p/9p.h
- *
- * 9P protocol definitions.
- *
- * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * 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:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-/* Message Types */
-enum {
- TVERSION = 100,
- RVERSION,
- TAUTH = 102,
- RAUTH,
- TATTACH = 104,
- RATTACH,
- TERROR = 106,
- RERROR,
- TFLUSH = 108,
- RFLUSH,
- TWALK = 110,
- RWALK,
- TOPEN = 112,
- ROPEN,
- TCREATE = 114,
- RCREATE,
- TREAD = 116,
- RREAD,
- TWRITE = 118,
- RWRITE,
- TCLUNK = 120,
- RCLUNK,
- TREMOVE = 122,
- RREMOVE,
- TSTAT = 124,
- RSTAT,
- TWSTAT = 126,
- RWSTAT,
-};
-
-/* modes */
-enum {
- V9FS_OREAD = 0x00,
- V9FS_OWRITE = 0x01,
- V9FS_ORDWR = 0x02,
- V9FS_OEXEC = 0x03,
- V9FS_OEXCL = 0x04,
- V9FS_OTRUNC = 0x10,
- V9FS_OREXEC = 0x20,
- V9FS_ORCLOSE = 0x40,
- V9FS_OAPPEND = 0x80,
-};
-
-/* permissions */
-enum {
- V9FS_DMDIR = 0x80000000,
- V9FS_DMAPPEND = 0x40000000,
- V9FS_DMEXCL = 0x20000000,
- V9FS_DMMOUNT = 0x10000000,
- V9FS_DMAUTH = 0x08000000,
- V9FS_DMTMP = 0x04000000,
- V9FS_DMSYMLINK = 0x02000000,
- V9FS_DMLINK = 0x01000000,
- /* 9P2000.u extensions */
- V9FS_DMDEVICE = 0x00800000,
- V9FS_DMNAMEDPIPE = 0x00200000,
- V9FS_DMSOCKET = 0x00100000,
- V9FS_DMSETUID = 0x00080000,
- V9FS_DMSETGID = 0x00040000,
-};
-
-/* qid.types */
-enum {
- V9FS_QTDIR = 0x80,
- V9FS_QTAPPEND = 0x40,
- V9FS_QTEXCL = 0x20,
- V9FS_QTMOUNT = 0x10,
- V9FS_QTAUTH = 0x08,
- V9FS_QTTMP = 0x04,
- V9FS_QTSYMLINK = 0x02,
- V9FS_QTLINK = 0x01,
- V9FS_QTFILE = 0x00,
-};
-
-#define V9FS_NOTAG (u16)(~0)
-#define V9FS_NOFID (u32)(~0)
-#define V9FS_MAXWELEM 16
-
-/* ample room for Twrite/Rread header (iounit) */
-#define V9FS_IOHDRSZ 24
-
-struct v9fs_str {
- u16 len;
- char *str;
-};
-
-/* qids are the unique ID for a file (like an inode */
-struct v9fs_qid {
- u8 type;
- u32 version;
- u64 path;
-};
-
-/* Plan 9 file metadata (stat) structure */
-struct v9fs_stat {
- u16 size;
- u16 type;
- u32 dev;
- struct v9fs_qid qid;
- u32 mode;
- u32 atime;
- u32 mtime;
- u64 length;
- struct v9fs_str name;
- struct v9fs_str uid;
- struct v9fs_str gid;
- struct v9fs_str muid;
- struct v9fs_str extension; /* 9p2000.u extensions */
- u32 n_uid; /* 9p2000.u extensions */
- u32 n_gid; /* 9p2000.u extensions */
- u32 n_muid; /* 9p2000.u extensions */
-};
-
-/* file metadata (stat) structure used to create Twstat message
- The is similar to v9fs_stat, but the strings don't point to
- the same memory block and should be freed separately
-*/
-struct v9fs_wstat {
- u16 size;
- u16 type;
- u32 dev;
- struct v9fs_qid qid;
- u32 mode;
- u32 atime;
- u32 mtime;
- u64 length;
- char *name;
- char *uid;
- char *gid;
- char *muid;
- char *extension; /* 9p2000.u extensions */
- u32 n_uid; /* 9p2000.u extensions */
- u32 n_gid; /* 9p2000.u extensions */
- u32 n_muid; /* 9p2000.u extensions */
-};
-
-/* Structures for Protocol Operations */
-
-struct Tversion {
- u32 msize;
- struct v9fs_str version;
-};
-
-struct Rversion {
- u32 msize;
- struct v9fs_str version;
-};
-
-struct Tauth {
- u32 afid;
- struct v9fs_str uname;
- struct v9fs_str aname;
-};
-
-struct Rauth {
- struct v9fs_qid qid;
-};
-
-struct Rerror {
- struct v9fs_str error;
- u32 errno; /* 9p2000.u extension */
-};
-
-struct Tflush {
- u16 oldtag;
-};
-
-struct Rflush {
-};
-
-struct Tattach {
- u32 fid;
- u32 afid;
- struct v9fs_str uname;
- struct v9fs_str aname;
-};
-
-struct Rattach {
- struct v9fs_qid qid;
-};
-
-struct Twalk {
- u32 fid;
- u32 newfid;
- u16 nwname;
- struct v9fs_str wnames[16];
-};
-
-struct Rwalk {
- u16 nwqid;
- struct v9fs_qid wqids[16];
-};
-
-struct Topen {
- u32 fid;
- u8 mode;
-};
-
-struct Ropen {
- struct v9fs_qid qid;
- u32 iounit;
-};
-
-struct Tcreate {
- u32 fid;
- struct v9fs_str name;
- u32 perm;
- u8 mode;
- struct v9fs_str extension;
-};
-
-struct Rcreate {
- struct v9fs_qid qid;
- u32 iounit;
-};
-
-struct Tread {
- u32 fid;
- u64 offset;
- u32 count;
-};
-
-struct Rread {
- u32 count;
- u8 *data;
-};
-
-struct Twrite {
- u32 fid;
- u64 offset;
- u32 count;
- u8 *data;
-};
-
-struct Rwrite {
- u32 count;
-};
-
-struct Tclunk {
- u32 fid;
-};
-
-struct Rclunk {
-};
-
-struct Tremove {
- u32 fid;
-};
-
-struct Rremove {
-};
-
-struct Tstat {
- u32 fid;
-};
-
-struct Rstat {
- struct v9fs_stat stat;
-};
-
-struct Twstat {
- u32 fid;
- struct v9fs_stat stat;
-};
-
-struct Rwstat {
-};
-
-/*
- * fcall is the primary packet structure
- *
- */
-
-struct v9fs_fcall {
- u32 size;
- u8 id;
- u16 tag;
- void *sdata;
-
- union {
- struct Tversion tversion;
- struct Rversion rversion;
- struct Tauth tauth;
- struct Rauth rauth;
- struct Rerror rerror;
- struct Tflush tflush;
- struct Rflush rflush;
- struct Tattach tattach;
- struct Rattach rattach;
- struct Twalk twalk;
- struct Rwalk rwalk;
- struct Topen topen;
- struct Ropen ropen;
- struct Tcreate tcreate;
- struct Rcreate rcreate;
- struct Tread tread;
- struct Rread rread;
- struct Twrite twrite;
- struct Rwrite rwrite;
- struct Tclunk tclunk;
- struct Rclunk rclunk;
- struct Tremove tremove;
- struct Rremove rremove;
- struct Tstat tstat;
- struct Rstat rstat;
- struct Twstat twstat;
- struct Rwstat rwstat;
- } params;
-};
-
-#define PRINT_FCALL_ERROR(s, fcall) dprintk(DEBUG_ERROR, "%s: %.*s\n", s, \
- fcall?fcall->params.rerror.error.len:0, \
- fcall?fcall->params.rerror.error.str:"");
-
-int v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
- char *version, struct v9fs_fcall **rcall);
-
-int v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
- u32 fid, u32 afid, struct v9fs_fcall **rcall);
-
-int v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid);
-
-int v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_fcall **rcall);
-
-int v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_wstat *wstat, struct v9fs_fcall **rcall);
-
-int v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
- char *name, struct v9fs_fcall **rcall);
-
-int v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
- struct v9fs_fcall **rcall);
-
-int v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_fcall **rcall);
-
-int v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name,
- u32 perm, u8 mode, char *extension, struct v9fs_fcall **rcall);
-
-int v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid,
- u64 offset, u32 count, struct v9fs_fcall **rcall);
-
-int v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
- u32 count, const char __user * data,
- struct v9fs_fcall **rcall);
-int v9fs_printfcall(char *, int, struct v9fs_fcall *, int);
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
index 87897f84dfb6..bc7f0d1551e6 100644
--- a/fs/9p/Makefile
+++ b/fs/9p/Makefile
@@ -1,18 +1,12 @@
obj-$(CONFIG_9P_FS) := 9p.o
9p-objs := \
- trans_fd.o \
- mux.o \
- fcall.o \
- conv.o \
vfs_super.o \
vfs_inode.o \
vfs_addr.o \
vfs_file.o \
vfs_dir.o \
vfs_dentry.o \
- error.o \
v9fs.o \
fid.o \
- fcprint.o
diff --git a/fs/9p/conv.h b/fs/9p/conv.h
deleted file mode 100644
index dd5b6b1b610f..000000000000
--- a/fs/9p/conv.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * linux/fs/9p/conv.h
- *
- * 9P protocol conversion definitions.
- *
- * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * 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:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-int v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
- int extended);
-int v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
- int extended);
-
-void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag);
-
-struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version);
-struct v9fs_fcall *v9fs_create_tattach(u32 fid, u32 afid, char *uname,
- char *aname);
-struct v9fs_fcall *v9fs_create_tflush(u16 oldtag);
-struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
- char **wnames);
-struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode);
-struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
- char *extension, int extended);
-struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count);
-struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
- const char __user *data);
-struct v9fs_fcall *v9fs_create_tclunk(u32 fid);
-struct v9fs_fcall *v9fs_create_tremove(u32 fid);
-struct v9fs_fcall *v9fs_create_tstat(u32 fid);
-struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
- int extended);
diff --git a/fs/9p/debug.h b/fs/9p/debug.h
deleted file mode 100644
index 4228c0bb3c32..000000000000
--- a/fs/9p/debug.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * linux/fs/9p/debug.h - V9FS Debug Definitions
- *
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * 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:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#define DEBUG_ERROR (1<<0)
-#define DEBUG_CURRENT (1<<1)
-#define DEBUG_9P (1<<2)
-#define DEBUG_VFS (1<<3)
-#define DEBUG_CONV (1<<4)
-#define DEBUG_MUX (1<<5)
-#define DEBUG_TRANS (1<<6)
-#define DEBUG_SLABS (1<<7)
-#define DEBUG_FCALL (1<<8)
-
-#define DEBUG_DUMP_PKT 0
-
-extern int v9fs_debug_level;
-
-#define dprintk(level, format, arg...) \
-do { \
- if((v9fs_debug_level & level)==level) \
- printk(KERN_NOTICE "-- %s (%d): " \
- format , __FUNCTION__, current->pid , ## arg); \
-} while(0)
-
-#define eprintk(level, format, arg...) \
-do { \
- printk(level "v9fs: %s (%d): " \
- format , __FUNCTION__, current->pid , ## arg); \
-} while(0)
-
-#if DEBUG_DUMP_PKT
-static inline void dump_data(const unsigned char *data, unsigned int datalen)
-{
- int i, n;
- char buf[5*8];
-
- n = 0;
- i = 0;
- while (i < datalen) {
- n += snprintf(buf+n, sizeof(buf)-n, "%02x", data[i++]);
- if (i%4 == 0)
- n += snprintf(buf+n, sizeof(buf)-n, " ");
-
- if (i%16 == 0) {
- dprintk(DEBUG_ERROR, "%s\n", buf);
- n = 0;
- }
- }
-
- dprintk(DEBUG_ERROR, "%s\n", buf);
-}
-#else /* DEBUG_DUMP_PKT */
-static inline void dump_data(const unsigned char *data, unsigned int datalen)
-{
-
-}
-#endif /* DEBUG_DUMP_PKT */
diff --git a/fs/9p/error.c b/fs/9p/error.c
deleted file mode 100644
index 0d7fa4e08812..000000000000
--- a/fs/9p/error.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * linux/fs/9p/error.c
- *
- * Error string handling
- *
- * Plan 9 uses error strings, Unix uses error numbers. These functions
- * try to help manage that and provide for dynamically adding error
- * mappings.
- *
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * 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:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/module.h>
-
-#include <linux/list.h>
-#include <linux/jhash.h>
-
-#include "debug.h"
-#include "error.h"
-
-/**
- * v9fs_error_init - preload
- * @errstr: error string
- *
- */
-
-int v9fs_error_init(void)
-{
- struct errormap *c;
- int bucket;
-
- /* initialize hash table */
- for (bucket = 0; bucket < ERRHASHSZ; bucket++)
- INIT_HLIST_HEAD(&hash_errmap[bucket]);
-
- /* load initial error map into hash table */
- for (c = errmap; c->name != NULL; c++) {
- c->namelen = strlen(c->name);
- bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
- INIT_HLIST_NODE(&c->list);
- hlist_add_head(&c->list, &hash_errmap[bucket]);
- }
-
- return 1;
-}
-
-/**
- * errstr2errno - convert error string to error number
- * @errstr: error string
- *
- */
-
-int v9fs_errstr2errno(char *errstr, int len)
-{
- int errno = 0;
- struct hlist_node *p = NULL;
- struct errormap *c = NULL;
- int bucket = jhash(errstr, len, 0) % ERRHASHSZ;
-
- hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
- if (c->namelen==len && !memcmp(c->name, errstr, len)) {
- errno = c->val;
- break;
- }
- }
-
- if (errno == 0) {
- /* TODO: if error isn't found, add it dynamically */
- errstr[len] = 0;
- printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
- errstr);
- errno = 1;
- }
-
- return -errno;
-}
diff --git a/fs/9p/fcall.c b/fs/9p/fcall.c
deleted file mode 100644
index dc336a67592f..000000000000
--- a/fs/9p/fcall.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * linux/fs/9p/fcall.c
- *
- * This file contains functions to perform synchronous 9P calls
- *
- * Copyright (C) 2004 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
- *
- * 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:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/idr.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
-#include "mux.h"
-
-/**
- * v9fs_t_version - negotiate protocol parameters with sever
- * @v9ses: 9P2000 session information
- * @msize: requested max size packet
- * @version: requested version.extension string
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_version(struct v9fs_session_info *v9ses, u32 msize,
- char *version, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "msize: %d version: %s\n", msize, version);
- tc = v9fs_create_tversion(msize, version);
-
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_attach - mount the server
- * @v9ses: 9P2000 session information
- * @uname: user name doing the attach
- * @aname: remote name being attached to
- * @fid: mount fid to attatch to root node
- * @afid: authentication fid (in this case result key)
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_attach(struct v9fs_session_info *v9ses, char *uname, char *aname,
- u32 fid, u32 afid, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall* tc;
-
- dprintk(DEBUG_9P, "uname '%s' aname '%s' fid %d afid %d\n", uname,
- aname, fid, afid);
-
- tc = v9fs_create_tattach(fid, afid, uname, aname);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-static void v9fs_t_clunk_cb(void *a, struct v9fs_fcall *tc,
- struct v9fs_fcall *rc, int err)
-{
- int fid, id;
- struct v9fs_session_info *v9ses;
-
- id = 0;
- fid = tc->params.tclunk.fid;
- if (rc)
- id = rc->id;
-
- kfree(tc);
- kfree(rc);
- if (id == RCLUNK) {
- v9ses = a;
- v9fs_put_idpool(fid, &v9ses->fidpool);
- }
-}
-
-/**
- * v9fs_t_clunk - release a fid (finish a transaction)
- * @v9ses: 9P2000 session information
- * @fid: fid to release
- * @fcall: pointer to response fcall pointer
- *
- */
-
-int
-v9fs_t_clunk(struct v9fs_session_info *v9ses, u32 fid)
-{
- int ret;
- struct v9fs_fcall *tc, *rc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- rc = NULL;
- tc = v9fs_create_tclunk(fid);
- if (!IS_ERR(tc))
- ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
- else
- ret = PTR_ERR(tc);
-
- if (ret)
- dprintk(DEBUG_ERROR, "failed fid %d err %d\n", fid, ret);
-
- v9fs_t_clunk_cb(v9ses, tc, rc, ret);
- return ret;
-}
-
-#if 0
-/**
- * v9fs_v9fs_t_flush - flush a pending transaction
- * @v9ses: 9P2000 session information
- * @tag: tag to release
- *
- */
-int v9fs_t_flush(struct v9fs_session_info *v9ses, u16 oldtag)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "oldtag %d\n", oldtag);
-
- tc = v9fs_create_tflush(oldtag);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, NULL);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-#endif
-
-/**
- * v9fs_t_stat - read a file's meta-data
- * @v9ses: 9P2000 session information
- * @fid: fid pointing to file or directory to get info about
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_stat(struct v9fs_session_info *v9ses, u32 fid, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- ret = -ENOMEM;
- tc = v9fs_create_tstat(fid);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_wstat - write a file's meta-data
- * @v9ses: 9P2000 session information
- * @fid: fid pointing to file or directory to write info about
- * @stat: metadata
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_wstat(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_wstat *wstat, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- tc = v9fs_create_twstat(fid, wstat, v9ses->extended);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_walk - walk a fid to a new file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to walk
- * @newfid: new fid (for clone operations)
- * @name: path to walk fid to
- * @fcall: pointer to response fcall
- *
- */
-
-/* TODO: support multiple walk */
-
-int
-v9fs_t_walk(struct v9fs_session_info *v9ses, u32 fid, u32 newfid,
- char *name, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
- int nwname;
-
- dprintk(DEBUG_9P, "fid %d newfid %d wname '%s'\n", fid, newfid, name);
-
- if (name)
- nwname = 1;
- else
- nwname = 0;
-
- tc = v9fs_create_twalk(fid, newfid, nwname, &name);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_open - open a file
- *
- * @v9ses - 9P2000 session information
- * @fid - fid to open
- * @mode - mode to open file (R, RW, etc)
- * @fcall - pointer to response fcall
- *
- */
-
-int
-v9fs_t_open(struct v9fs_session_info *v9ses, u32 fid, u8 mode,
- struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d mode %d\n", fid, mode);
-
- tc = v9fs_create_topen(fid, mode);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_remove - remove a file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to remove
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_remove(struct v9fs_session_info *v9ses, u32 fid,
- struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d\n", fid);
-
- tc = v9fs_create_tremove(fid);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_create - create a file or directory
- * @v9ses: 9P2000 session information
- * @fid: fid to create
- * @name: name of the file or directory to create
- * @perm: permissions to create with
- * @mode: mode to open file (R, RW, etc)
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_create(struct v9fs_session_info *v9ses, u32 fid, char *name, u32 perm,
- u8 mode, char *extension, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc;
-
- dprintk(DEBUG_9P, "fid %d name '%s' perm %x mode %d\n",
- fid, name, perm, mode);
-
- tc = v9fs_create_tcreate(fid, name, perm, mode, extension,
- v9ses->extended);
-
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, rcp);
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_read - read data
- * @v9ses: 9P2000 session information
- * @fid: fid to read from
- * @offset: offset to start read at
- * @count: how many bytes to read
- * @fcall: pointer to response fcall (with data)
- *
- */
-
-int
-v9fs_t_read(struct v9fs_session_info *v9ses, u32 fid, u64 offset,
- u32 count, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc, *rc;
-
- dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
- (long long unsigned) offset, count);
-
- tc = v9fs_create_tread(fid, offset, count);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
- if (!ret)
- ret = rc->params.rread.count;
- if (rcp)
- *rcp = rc;
- else
- kfree(rc);
-
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
-/**
- * v9fs_t_write - write data
- * @v9ses: 9P2000 session information
- * @fid: fid to write to
- * @offset: offset to start write at
- * @count: how many bytes to write
- * @fcall: pointer to response fcall
- *
- */
-
-int
-v9fs_t_write(struct v9fs_session_info *v9ses, u32 fid, u64 offset, u32 count,
- const char __user *data, struct v9fs_fcall **rcp)
-{
- int ret;
- struct v9fs_fcall *tc, *rc;
-
- dprintk(DEBUG_9P, "fid %d offset 0x%llux count 0x%x\n", fid,
- (long long unsigned) offset, count);
-
- tc = v9fs_create_twrite(fid, offset, count, data);
- if (!IS_ERR(tc)) {
- ret = v9fs_mux_rpc(v9ses->mux, tc, &rc);
-
- if (!ret)
- ret = rc->params.rwrite.count;
- if (rcp)
- *rcp = rc;
- else
- kfree(rc);
-
- kfree(tc);
- } else
- ret = PTR_ERR(tc);
-
- return ret;
-}
-
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 90419715c7e9..08fa320b7e6d 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -26,10 +26,10 @@
#include <linux/sched.h>
#include <linux/idr.h>
#include <asm/semaphore.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -40,67 +40,29 @@
*
*/
-int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry)
+int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid)
{
- struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
- dprintk(DEBUG_9P, "fid %d (%p) dentry %s (%p)\n", fid->fid, fid,
- dentry->d_iname, dentry);
- if (dentry->d_fsdata == NULL) {
- dentry->d_fsdata =
- kmalloc(sizeof(struct list_head), GFP_KERNEL);
- if (dentry->d_fsdata == NULL) {
- dprintk(DEBUG_ERROR, "Out of memory\n");
- return -ENOMEM;
- }
- fid_list = (struct list_head *)dentry->d_fsdata;
- INIT_LIST_HEAD(fid_list); /* Initialize list head */
- }
+ struct v9fs_dentry *dent;
- fid->uid = current->uid;
- list_add(&fid->list, fid_list);
- return 0;
-}
+ P9_DPRINTK(P9_DEBUG_VFS, "fid %d dentry %s\n",
+ fid->fid, dentry->d_iname);
-/**
- * v9fs_fid_create - allocate a FID structure
- * @dentry - dentry to link newly created fid to
- *
- */
-
-struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *v9ses, int fid)
-{
- struct v9fs_fid *new;
+ dent = dentry->d_fsdata;
+ if (!dent) {
+ dent = kmalloc(sizeof(struct v9fs_dentry), GFP_KERNEL);
+ if (!dent)
+ return -ENOMEM;
- dprintk(DEBUG_9P, "fid create fid %d\n", fid);
- new = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL);
- if (new == NULL) {
- dprintk(DEBUG_ERROR, "Out of Memory\n");
- return ERR_PTR(-ENOMEM);
+ spin_lock_init(&dent->lock);
+ INIT_LIST_HEAD(&dent->fidlist);
+ dentry->d_fsdata = dent;
}
- new->fid = fid;
- new->v9ses = v9ses;
- new->fidopen = 0;
- new->fidclunked = 0;
- new->iounit = 0;
- new->rdir_pos = 0;
- new->rdir_fcall = NULL;
- init_MUTEX(&new->lock);
- INIT_LIST_HEAD(&new->list);
-
- return new;
-}
-
-/**
- * v9fs_fid_destroy - deallocate a FID structure
- * @fid: fid to destroy
- *
- */
+ spin_lock(&dent->lock);
+ list_add(&fid->dlist, &dent->fidlist);
+ spin_unlock(&dent->lock);
-void v9fs_fid_destroy(struct v9fs_fid *fid)
-{
- list_del(&fid->list);
- kfree(fid);
+ return 0;
}
/**
@@ -114,30 +76,42 @@ void v9fs_fid_destroy(struct v9fs_fid *fid)
*
*/
-struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
+struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
{
- struct list_head *fid_list = (struct list_head *)dentry->d_fsdata;
- struct v9fs_fid *return_fid = NULL;
-
- dprintk(DEBUG_9P, " dentry: %s (%p)\n", dentry->d_iname, dentry);
-
- if (fid_list)
- return_fid = list_entry(fid_list->next, struct v9fs_fid, list);
+ struct v9fs_dentry *dent;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ dent = dentry->d_fsdata;
+ if (dent)
+ fid = list_entry(dent->fidlist.next, struct p9_fid, dlist);
+ else
+ fid = ERR_PTR(-EBADF);
+
+ P9_DPRINTK(P9_DEBUG_VFS, " fid: %p\n", fid);
+ return fid;
+}
- if (!return_fid) {
- dprintk(DEBUG_ERROR, "Couldn't find a fid in dentry\n");
- return_fid = ERR_PTR(-EBADF);
+struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry)
+{
+ struct p9_fid *fid;
+ struct v9fs_dentry *dent;
+
+ dent = dentry->d_fsdata;
+ fid = v9fs_fid_lookup(dentry);
+ if (!IS_ERR(fid)) {
+ spin_lock(&dent->lock);
+ list_del(&fid->dlist);
+ spin_unlock(&dent->lock);
}
- if(down_interruptible(&return_fid->lock))
- return ERR_PTR(-EINTR);
-
- return return_fid;
+ return fid;
}
+
/**
* v9fs_fid_clone - lookup the fid for a dentry, clone a private copy and
- * release it
+ * release it
* @dentry: dentry to look for fid in
*
* find a fid in the dentry and then clone to a new private fid
@@ -146,49 +120,15 @@ struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry)
*
*/
-struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry)
+struct p9_fid *v9fs_fid_clone(struct dentry *dentry)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *base_fid, *new_fid = ERR_PTR(-EBADF);
- struct v9fs_fcall *fcall = NULL;
- int fid, err;
-
- base_fid = v9fs_fid_lookup(dentry);
-
- if(IS_ERR(base_fid))
- return base_fid;
-
- if(base_fid) { /* clone fid */
- fid = v9fs_get_idpool(&v9ses->fidpool);
- if (fid < 0) {
- eprintk(KERN_WARNING, "newfid fails!\n");
- new_fid = ERR_PTR(-ENOSPC);
- goto Release_Fid;
- }
-
- err = v9fs_t_walk(v9ses, base_fid->fid, fid, NULL, &fcall);
- if (err < 0) {
- dprintk(DEBUG_ERROR, "clone walk didn't work\n");
- v9fs_put_idpool(fid, &v9ses->fidpool);
- new_fid = ERR_PTR(err);
- goto Free_Fcall;
- }
- new_fid = v9fs_fid_create(v9ses, fid);
- if (new_fid == NULL) {
- dprintk(DEBUG_ERROR, "out of memory\n");
- new_fid = ERR_PTR(-ENOMEM);
- }
-Free_Fcall:
- kfree(fcall);
- }
+ struct p9_fid *ofid, *fid;
-Release_Fid:
- up(&base_fid->lock);
- return new_fid;
-}
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ ofid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(ofid))
+ return ofid;
-void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid)
-{
- v9fs_t_clunk(v9ses, fid->fid);
- v9fs_fid_destroy(fid);
+ fid = p9_client_walk(ofid, 0, NULL, 1);
+ return fid;
}
diff --git a/fs/9p/fid.h b/fs/9p/fid.h
index 48fc170c26c8..47a0ba742872 100644
--- a/fs/9p/fid.h
+++ b/fs/9p/fid.h
@@ -22,41 +22,12 @@
#include <linux/list.h>
-#define FID_OP 0
-#define FID_WALK 1
-#define FID_CREATE 2
-
-struct v9fs_fid {
- struct list_head list; /* list of fids associated with a dentry */
- struct list_head active; /* XXX - debug */
-
- struct semaphore lock;
-
- u32 fid;
- unsigned char fidopen; /* set when fid is opened */
- unsigned char fidclunked; /* set when fid has already been clunked */
-
- struct v9fs_qid qid;
- u32 iounit;
-
- /* readdir stuff */
- int rdir_fpos;
- loff_t rdir_pos;
- struct v9fs_fcall *rdir_fcall;
-
- /* management stuff */
- uid_t uid; /* user associated with this fid */
-
- /* private data */
- struct file *filp; /* backpointer to File struct for open files */
- struct v9fs_session_info *v9ses; /* session info for this FID */
+struct v9fs_dentry {
+ spinlock_t lock; /* protect fidlist */
+ struct list_head fidlist;
};
-struct v9fs_fid *v9fs_fid_lookup(struct dentry *dentry);
-struct v9fs_fid *v9fs_fid_get_created(struct dentry *);
-void v9fs_fid_destroy(struct v9fs_fid *fid);
-struct v9fs_fid *v9fs_fid_create(struct v9fs_session_info *, int fid);
-int v9fs_fid_insert(struct v9fs_fid *fid, struct dentry *dentry);
-struct v9fs_fid *v9fs_fid_clone(struct dentry *dentry);
-void v9fs_fid_clunk(struct v9fs_session_info *v9ses, struct v9fs_fid *fid);
-
+struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
+struct p9_fid *v9fs_fid_lookup_remove(struct dentry *dentry);
+struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
+int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
diff --git a/fs/9p/trans_fd.c b/fs/9p/trans_fd.c
deleted file mode 100644
index 34d43355beb7..000000000000
--- a/fs/9p/trans_fd.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * linux/fs/9p/trans_fd.c
- *
- * Fd transport layer. Includes deprecated socket layer.
- *
- * Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
- * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
- * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com>
- * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to:
- * Free Software Foundation
- * 51 Franklin Street, Fifth Floor
- * Boston, MA 02111-1301 USA
- *
- */
-
-#include <linux/in.h>
-#include <linux/module.h>
-#include <linux/net.h>
-#include <linux/ipv6.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/un.h>
-#include <asm/uaccess.h>
-#include <linux/inet.h>
-#include <linux/idr.h>
-#include <linux/file.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "transport.h"
-
-#define V9FS_PORT 564
-
-struct v9fs_trans_fd {
- struct file *rd;
- struct file *wr;
-};
-
-/**
- * v9fs_fd_read- read from a fd
- * @v9ses: session information
- * @v: buffer to receive data into
- * @len: size of receive buffer
- *
- */
-static int v9fs_fd_read(struct v9fs_transport *trans, void *v, int len)
-{
- int ret;
- struct v9fs_trans_fd *ts;
-
- if (!trans || trans->status == Disconnected || !(ts = trans->priv))
- return -EREMOTEIO;
-
- if (!(ts->rd->f_flags & O_NONBLOCK))
- dprintk(DEBUG_ERROR, "blocking read ...\n");
-
- ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
- if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
- trans->status = Disconnected;
- return ret;
-}
-
-/**
- * v9fs_fd_write - write to a socket
- * @v9ses: session information
- * @v: buffer to send data from
- * @len: size of send buffer
- *
- */
-static int v9fs_fd_write(struct v9fs_transport *trans, void *v, int len)
-{
- int ret;
- mm_segment_t oldfs;
- struct v9fs_trans_fd *ts;
-
- if (!trans || trans->status == Disconnected || !(ts = trans->priv))
- return -EREMOTEIO;
-
- if (!(ts->wr->f_flags & O_NONBLOCK))
- dprintk(DEBUG_ERROR, "blocking write ...\n");
-
- oldfs = get_fs();
- set_fs(get_ds());
- /* The cast to a user pointer is valid due to the set_fs() */
- ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
- set_fs(oldfs);
-
- if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
- trans->status = Disconnected;
- return ret;
-}
-
-static unsigned int
-v9fs_fd_poll(struct v9fs_transport *trans, struct poll_table_struct *pt)
-{
- int ret, n;
- struct v9fs_trans_fd *ts;
- mm_segment_t oldfs;
-
- if (!trans || trans->status != Connected || !(ts = trans->priv))
- return -EREMOTEIO;
-
- if (!ts->rd->f_op || !ts->rd->f_op->poll)
- return -EIO;
-
- if (!ts->wr->f_op || !ts->wr->f_op->poll)
- return -EIO;
-
- oldfs = get_fs();
- set_fs(get_ds());
-
- ret = ts->rd->f_op->poll(ts->rd, pt);
- if (ret < 0)
- goto end;
-
- if (ts->rd != ts->wr) {
- n = ts->wr->f_op->poll(ts->wr, pt);
- if (n < 0) {
- ret = n;
- goto end;
- }
- ret = (ret & ~POLLOUT) | (n & ~POLLIN);
- }
-
- end:
- set_fs(oldfs);
- return ret;
-}
-
-static int v9fs_fd_open(struct v9fs_session_info *v9ses, int rfd, int wfd)
-{
- struct v9fs_transport *trans = v9ses->transport;
- struct v9fs_trans_fd *ts = kmalloc(sizeof(struct v9fs_trans_fd),
- GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- ts->rd = fget(rfd);
- ts->wr = fget(wfd);
- if (!ts->rd || !ts->wr) {
- if (ts->rd)
- fput(ts->rd);
- if (ts->wr)
- fput(ts->wr);
- kfree(ts);
- return -EIO;
- }
-
- trans->priv = ts;
- trans->status = Connected;
-
- return 0;
-}
-
-static int v9fs_fd_init(struct v9fs_session_info *v9ses, const char *addr,
- char *data)
-{
- if (v9ses->rfdno == ~0 || v9ses->wfdno == ~0) {
- printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
- return -ENOPROTOOPT;
- }
-
- return v9fs_fd_open(v9ses, v9ses->rfdno, v9ses->wfdno);
-}
-
-static int v9fs_socket_open(struct v9fs_session_info *v9ses,
- struct socket *csocket)
-{
- int fd, ret;
-
- csocket->sk->sk_allocation = GFP_NOIO;
- if ((fd = sock_map_fd(csocket)) < 0) {
- eprintk(KERN_ERR, "v9fs_socket_open: failed to map fd\n");
- ret = fd;
- release_csocket:
- sock_release(csocket);
- return ret;
- }
-
- if ((ret = v9fs_fd_open(v9ses, fd, fd)) < 0) {
- sockfd_put(csocket);
- eprintk(KERN_ERR, "v9fs_socket_open: failed to open fd\n");
- goto release_csocket;
- }
-
- ((struct v9fs_trans_fd *)v9ses->transport->priv)->rd->f_flags |=
- O_NONBLOCK;
- return 0;
-}
-
-static int v9fs_tcp_init(struct v9fs_session_info *v9ses, const char *addr,
- char *data)
-{
- int ret;
- struct socket *csocket = NULL;
- struct sockaddr_in sin_server;
-
- sin_server.sin_family = AF_INET;
- sin_server.sin_addr.s_addr = in_aton(addr);
- sin_server.sin_port = htons(v9ses->port);
- sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
-
- if (!csocket) {
- eprintk(KERN_ERR, "v9fs_trans_tcp: problem creating socket\n");
- return -1;
- }
-
- ret = csocket->ops->connect(csocket,
- (struct sockaddr *)&sin_server,
- sizeof(struct sockaddr_in), 0);
- if (ret < 0) {
- eprintk(KERN_ERR,
- "v9fs_trans_tcp: problem connecting socket to %s\n",
- addr);
- return ret;
- }
-
- return v9fs_socket_open(v9ses, csocket);
-}
-
-static int
-v9fs_unix_init(struct v9fs_session_info *v9ses, const char *addr, char *data)
-{
- int ret;
- struct socket *csocket;
- struct sockaddr_un sun_server;
-
- if (strlen(addr) > UNIX_PATH_MAX) {
- eprintk(KERN_ERR, "v9fs_trans_unix: address too long: %s\n",
- addr);
- return -ENAMETOOLONG;
- }
-
- sun_server.sun_family = PF_UNIX;
- strcpy(sun_server.sun_path, addr);
- sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
- ret = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
- sizeof(struct sockaddr_un) - 1, 0);
- if (ret < 0) {
- eprintk(KERN_ERR,
- "v9fs_trans_unix: problem connecting socket: %s: %d\n",
- addr, ret);
- return ret;
- }
-
- return v9fs_socket_open(v9ses, csocket);
-}
-
-/**
- * v9fs_sock_close - shutdown socket
- * @trans: private socket structure
- *
- */
-static void v9fs_fd_close(struct v9fs_transport *trans)
-{
- struct v9fs_trans_fd *ts;
-
- if (!trans)
- return;
-
- ts = xchg(&trans->priv, NULL);
-
- if (!ts)
- return;
-
- trans->status = Disconnected;
- if (ts->rd)
- fput(ts->rd);
- if (ts->wr)
- fput(ts->wr);
- kfree(ts);
-}
-
-struct v9fs_transport v9fs_trans_fd = {
- .init = v9fs_fd_init,
- .write = v9fs_fd_write,
- .read = v9fs_fd_read,
- .close = v9fs_fd_close,
- .poll = v9fs_fd_poll,
-};
-
-struct v9fs_transport v9fs_trans_tcp = {
- .init = v9fs_tcp_init,
- .write = v9fs_fd_write,
- .read = v9fs_fd_read,
- .close = v9fs_fd_close,
- .poll = v9fs_fd_poll,
-};
-
-struct v9fs_transport v9fs_trans_unix = {
- .init = v9fs_unix_init,
- .write = v9fs_fd_write,
- .read = v9fs_fd_read,
- .close = v9fs_fd_close,
- .poll = v9fs_fd_poll,
-};
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 6ad6f192b6e4..0a7068e30ecb 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -29,16 +29,12 @@
#include <linux/sched.h>
#include <linux/parser.h>
#include <linux/idr.h>
-
-#include "debug.h"
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+#include <net/9p/conn.h>
+#include <net/9p/client.h>
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
-#include "transport.h"
-#include "mux.h"
-
-/* TODO: sysfs or debugfs interface */
-int v9fs_debug_level = 0; /* feature-rific global debug level */
/*
* Option Parsing (code inspired by NFS code)
@@ -47,12 +43,12 @@ int v9fs_debug_level = 0; /* feature-rific global debug level */
enum {
/* Options that take integer arguments */
- Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid, Opt_debug,
+ Opt_debug, Opt_port, Opt_msize, Opt_uid, Opt_gid, Opt_afid,
Opt_rfdno, Opt_wfdno,
/* String options */
Opt_uname, Opt_remotename,
/* Options that take no arguments */
- Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd,
+ Opt_legacy, Opt_nodevmap, Opt_unix, Opt_tcp, Opt_fd, Opt_pci,
/* Cache options */
Opt_cache_loose,
/* Error token */
@@ -60,6 +56,7 @@ enum {
};
static match_table_t tokens = {
+ {Opt_debug, "debug=%x"},
{Opt_port, "port=%u"},
{Opt_msize, "msize=%u"},
{Opt_uid, "uid=%u"},
@@ -67,12 +64,14 @@ static match_table_t tokens = {
{Opt_afid, "afid=%u"},
{Opt_rfdno, "rfdno=%u"},
{Opt_wfdno, "wfdno=%u"},
- {Opt_debug, "debug=%x"},
{Opt_uname, "uname=%s"},
{Opt_remotename, "aname=%s"},
{Opt_unix, "proto=unix"},
{Opt_tcp, "proto=tcp"},
{Opt_fd, "proto=fd"},
+#ifdef CONFIG_PCI_9P
+ {Opt_pci, "proto=pci"},
+#endif
{Opt_tcp, "tcp"},
{Opt_unix, "unix"},
{Opt_fd, "fd"},
@@ -83,6 +82,8 @@ static match_table_t tokens = {
{Opt_err, NULL}
};
+extern struct p9_transport *p9pci_trans_create(void);
+
/*
* Parse option string.
*/
@@ -122,12 +123,18 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
token = match_token(p, tokens, args);
if (token < Opt_uname) {
if ((ret = match_int(&args[0], &option)) < 0) {
- dprintk(DEBUG_ERROR,
+ P9_DPRINTK(P9_DEBUG_ERROR,
"integer field, but no integer?\n");
continue;
}
}
switch (token) {
+ case Opt_debug:
+ v9ses->debug = option;
+#ifdef CONFIG_NET_9P_DEBUG
+ p9_debug_level = option;
+#endif
+ break;
case Opt_port:
v9ses->port = option;
break;
@@ -149,15 +156,15 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
case Opt_wfdno:
v9ses->wfdno = option;
break;
- case Opt_debug:
- v9ses->debug = option;
- break;
case Opt_tcp:
v9ses->proto = PROTO_TCP;
break;
case Opt_unix:
v9ses->proto = PROTO_UNIX;
break;
+ case Opt_pci:
+ v9ses->proto = PROTO_PCI;
+ break;
case Opt_fd:
v9ses->proto = PROTO_FD;
break;
@@ -183,82 +190,6 @@ static void v9fs_parse_options(char *options, struct v9fs_session_info *v9ses)
}
/**
- * v9fs_inode2v9ses - safely extract v9fs session info from super block
- * @inode: inode to extract information from
- *
- * Paranoid function to extract v9ses information from superblock,
- * if anything is missing it will report an error.
- *
- */
-
-struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
-{
- return (inode->i_sb->s_fs_info);
-}
-
-/**
- * v9fs_get_idpool - allocate numeric id from pool
- * @p - pool to allocate from
- *
- * XXX - This seems to be an awful generic function, should it be in idr.c with
- * the lock included in struct idr?
- */
-
-int v9fs_get_idpool(struct v9fs_idpool *p)
-{
- int i = 0;
- int error;
-
-retry:
- if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
- return 0;
-
- if (down_interruptible(&p->lock) == -EINTR) {
- eprintk(KERN_WARNING, "Interrupted while locking\n");
- return -1;
- }
-
- /* no need to store exactly p, we just need something non-null */
- error = idr_get_new(&p->pool, p, &i);
- up(&p->lock);
-
- if (error == -EAGAIN)
- goto retry;
- else if (error)
- return -1;
-
- return i;
-}
-
-/**
- * v9fs_put_idpool - release numeric id from pool
- * @p - pool to allocate from
- *
- * XXX - This seems to be an awful generic function, should it be in idr.c with
- * the lock included in struct idr?
- */
-
-void v9fs_put_idpool(int id, struct v9fs_idpool *p)
-{
- if (down_interruptible(&p->lock) == -EINTR) {
- eprintk(KERN_WARNING, "Interrupted while locking\n");
- return;
- }
- idr_remove(&p->pool, id);
- up(&p->lock);
-}
-
-/**
- * v9fs_check_idpool - check if the specified id is available
- * @id - id to check
- * @p - pool
- */
-int v9fs_check_idpool(int id, struct v9fs_idpool *p)
-{
- return idr_find(&p->pool, id) != NULL;
-}
-
-/**
* v9fs_session_init - initialize session
* @v9ses: session information structure
* @dev_name: device being mounted
@@ -266,25 +197,21 @@ int v9fs_check_idpool(int id, struct v9fs_idpool *p)
*
*/
-int
-v9fs_session_init(struct v9fs_session_info *v9ses,
+struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
const char *dev_name, char *data)
{
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_transport *trans_proto;
- int n = 0;
- int newfid = -1;
int retval = -EINVAL;
- struct v9fs_str *version;
+ struct p9_transport *trans;
+ struct p9_fid *fid;
v9ses->name = __getname();
if (!v9ses->name)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
v9ses->remotename = __getname();
if (!v9ses->remotename) {
__putname(v9ses->name);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
strcpy(v9ses->name, V9FS_DEFUSER);
@@ -292,130 +219,60 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
v9fs_parse_options(data, v9ses);
- /* set global debug level */
- v9fs_debug_level = v9ses->debug;
-
- /* id pools that are session-dependent: fids and tags */
- idr_init(&v9ses->fidpool.pool);
- init_MUTEX(&v9ses->fidpool.lock);
-
switch (v9ses->proto) {
case PROTO_TCP:
- trans_proto = &v9fs_trans_tcp;
+ trans = p9_trans_create_tcp(dev_name, v9ses->port);
break;
case PROTO_UNIX:
- trans_proto = &v9fs_trans_unix;
+ trans = p9_trans_create_unix(dev_name);
*v9ses->remotename = 0;
break;
case PROTO_FD:
- trans_proto = &v9fs_trans_fd;
+ trans = p9_trans_create_fd(v9ses->rfdno, v9ses->wfdno);
*v9ses->remotename = 0;
break;
+#ifdef CONFIG_PCI_9P
+ case PROTO_PCI:
+ trans = p9pci_trans_create();
+ *v9ses->remotename = 0;
+ break;
+#endif
default:
printk(KERN_ERR "v9fs: Bad mount protocol %d\n", v9ses->proto);
retval = -ENOPROTOOPT;
- goto SessCleanUp;
+ goto error;
};
- v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL);
- if (!v9ses->transport) {
- retval = -ENOMEM;
- goto SessCleanUp;
+ if (IS_ERR(trans)) {
+ retval = PTR_ERR(trans);
+ trans = NULL;
+ goto error;
}
- memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport));
+ v9ses->clnt = p9_client_create(trans, v9ses->maxdata + P9_IOHDRSZ,
+ v9ses->extended);
- if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) {
- eprintk(KERN_ERR, "problem initializing transport\n");
- goto SessCleanUp;
+ if (IS_ERR(v9ses->clnt)) {
+ retval = PTR_ERR(v9ses->clnt);
+ v9ses->clnt = NULL;
+ P9_DPRINTK(P9_DEBUG_ERROR, "problem initializing 9p client\n");
+ goto error;
}
- v9ses->inprogress = 0;
- v9ses->shutdown = 0;
- v9ses->session_hung = 0;
-
- v9ses->mux = v9fs_mux_init(v9ses->transport, v9ses->maxdata + V9FS_IOHDRSZ,
- &v9ses->extended);
-
- if (IS_ERR(v9ses->mux)) {
- retval = PTR_ERR(v9ses->mux);
- v9ses->mux = NULL;
- dprintk(DEBUG_ERROR, "problem initializing mux\n");
- goto SessCleanUp;
+ fid = p9_client_attach(v9ses->clnt, NULL, v9ses->name,
+ v9ses->remotename);
+ if (IS_ERR(fid)) {
+ retval = PTR_ERR(fid);
+ fid = NULL;
+ P9_DPRINTK(P9_DEBUG_ERROR, "cannot attach\n");
+ goto error;
}
- if (v9ses->afid == ~0) {
- if (v9ses->extended)
- retval =
- v9fs_t_version(v9ses, v9ses->maxdata, "9P2000.u",
- &fcall);
- else
- retval = v9fs_t_version(v9ses, v9ses->maxdata, "9P2000",
- &fcall);
-
- if (retval < 0) {
- dprintk(DEBUG_ERROR, "v9fs_t_version failed\n");
- goto FreeFcall;
- }
-
- version = &fcall->params.rversion.version;
- if (version->len==8 && !memcmp(version->str, "9P2000.u", 8)) {
- dprintk(DEBUG_9P, "9P2000 UNIX extensions enabled\n");
- v9ses->extended = 1;
- } else if (version->len==6 && !memcmp(version->str, "9P2000", 6)) {
- dprintk(DEBUG_9P, "9P2000 legacy mode enabled\n");
- v9ses->extended = 0;
- } else {
- retval = -EREMOTEIO;
- goto FreeFcall;
- }
+ return fid;
- n = fcall->params.rversion.msize;
- kfree(fcall);
-
- if (n < v9ses->maxdata)
- v9ses->maxdata = n;
- }
-
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
- eprintk(KERN_WARNING, "couldn't allocate FID\n");
- retval = -ENOMEM;
- goto SessCleanUp;
- }
- /* it is a little bit ugly, but we have to prevent newfid */
- /* being the same as afid, so if it is, get a new fid */
- if (v9ses->afid != ~0 && newfid == v9ses->afid) {
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
- eprintk(KERN_WARNING, "couldn't allocate FID\n");
- retval = -ENOMEM;
- goto SessCleanUp;
- }
- }
-
- if ((retval =
- v9fs_t_attach(v9ses, v9ses->name, v9ses->remotename, newfid,
- v9ses->afid, NULL))
- < 0) {
- dprintk(DEBUG_ERROR, "cannot attach\n");
- goto SessCleanUp;
- }
-
- if (v9ses->afid != ~0) {
- dprintk(DEBUG_ERROR, "afid not equal to ~0\n");
- if (v9fs_t_clunk(v9ses, v9ses->afid))
- dprintk(DEBUG_ERROR, "clunk failed\n");
- }
-
- return newfid;
-
- FreeFcall:
- kfree(fcall);
-
- SessCleanUp:
+error:
v9fs_session_close(v9ses);
- return retval;
+ return ERR_PTR(retval);
}
/**
@@ -426,15 +283,9 @@ v9fs_session_init(struct v9fs_session_info *v9ses,
void v9fs_session_close(struct v9fs_session_info *v9ses)
{
- if (v9ses->mux) {
- v9fs_mux_destroy(v9ses->mux);
- v9ses->mux = NULL;
- }
-
- if (v9ses->transport) {
- v9ses->transport->close(v9ses->transport);
- kfree(v9ses->transport);
- v9ses->transport = NULL;
+ if (v9ses->clnt) {
+ p9_client_destroy(v9ses->clnt);
+ v9ses->clnt = NULL;
}
__putname(v9ses->name);
@@ -446,9 +297,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
* and cancel all pending requests.
*/
void v9fs_session_cancel(struct v9fs_session_info *v9ses) {
- dprintk(DEBUG_ERROR, "cancel session %p\n", v9ses);
- v9ses->transport->status = Disconnected;
- v9fs_mux_cancel(v9ses->mux, -EIO);
+ P9_DPRINTK(P9_DEBUG_ERROR, "cancel session %p\n", v9ses);
+ p9_client_disconnect(v9ses->clnt);
}
extern int v9fs_error_init(void);
@@ -460,24 +310,9 @@ extern int v9fs_error_init(void);
static int __init init_v9fs(void)
{
- int ret;
-
- v9fs_error_init();
-
printk(KERN_INFO "Installing v9fs 9p2000 file system support\n");
- ret = v9fs_mux_global_init();
- if (ret) {
- printk(KERN_WARNING "v9fs: starting mux failed\n");
- return ret;
- }
- ret = register_filesystem(&v9fs_fs_type);
- if (ret) {
- printk(KERN_WARNING "v9fs: registering file system failed\n");
- v9fs_mux_global_exit();
- }
-
- return ret;
+ return register_filesystem(&v9fs_fs_type);
}
/**
@@ -487,13 +322,13 @@ static int __init init_v9fs(void)
static void __exit exit_v9fs(void)
{
- v9fs_mux_global_exit();
unregister_filesystem(&v9fs_fs_type);
}
module_init(init_v9fs)
module_exit(exit_v9fs)
+MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
MODULE_LICENSE("GPL");
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 820bf5ca35d8..abc4b1668ace 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -22,16 +22,6 @@
*/
/*
- * Idpool structure provides lock and id management
- *
- */
-
-struct v9fs_idpool {
- struct semaphore lock;
- struct idr pool;
-};
-
-/*
* Session structure provides information for an opened session
*
*/
@@ -54,15 +44,7 @@ struct v9fs_session_info {
unsigned int uid; /* default uid/muid for legacy support */
unsigned int gid; /* default gid for legacy support */
- /* book keeping */
- struct v9fs_idpool fidpool; /* The FID pool for file descriptors */
-
- struct v9fs_transport *transport;
- struct v9fs_mux_data *mux;
-
- int inprogress; /* session in progress => true */
- int shutdown; /* session shutting down. no more attaches. */
- unsigned char session_hung;
+ struct p9_client *clnt; /* 9p client */
struct dentry *debugfs_dir;
};
@@ -71,6 +53,7 @@ enum {
PROTO_TCP,
PROTO_UNIX,
PROTO_FD,
+ PROTO_PCI,
};
/* possible values of ->cache */
@@ -82,12 +65,9 @@ enum {
extern struct dentry *v9fs_debugfs_root;
-int v9fs_session_init(struct v9fs_session_info *, const char *, char *);
-struct v9fs_session_info *v9fs_inode2v9ses(struct inode *);
+struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
+ char *);
void v9fs_session_close(struct v9fs_session_info *v9ses);
-int v9fs_get_idpool(struct v9fs_idpool *p);
-void v9fs_put_idpool(int id, struct v9fs_idpool *p);
-int v9fs_check_idpool(int id, struct v9fs_idpool *p);
void v9fs_session_cancel(struct v9fs_session_info *v9ses);
#define V9FS_MAGIC 0x01021997
@@ -97,3 +77,7 @@ void v9fs_session_cancel(struct v9fs_session_info *v9ses);
#define V9FS_DEFUSER "nobody"
#define V9FS_DEFANAME ""
+static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
+{
+ return (inode->i_sb->s_fs_info);
+}
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 6a82d39dc498..fd01d90cada5 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -45,10 +45,10 @@ extern struct dentry_operations v9fs_dentry_operations;
extern struct dentry_operations v9fs_cached_dentry_operations;
struct inode *v9fs_get_inode(struct super_block *sb, int mode);
-ino_t v9fs_qid2ino(struct v9fs_qid *qid);
-void v9fs_stat2inode(struct v9fs_stat *, struct inode *, struct super_block *);
+ino_t v9fs_qid2ino(struct p9_qid *qid);
+void v9fs_stat2inode(struct p9_stat *, struct inode *, struct super_block *);
int v9fs_dir_release(struct inode *inode, struct file *filp);
int v9fs_file_open(struct inode *inode, struct file *file);
-void v9fs_inode2stat(struct inode *inode, struct v9fs_stat *stat);
+void v9fs_inode2stat(struct inode *inode, struct p9_stat *stat);
void v9fs_dentry_release(struct dentry *);
int v9fs_uflags2omode(int uflags);
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c
index 9ac4ffe9ac7d..6248f0e727a3 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -33,10 +33,10 @@
#include <linux/pagemap.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -50,55 +50,26 @@
static int v9fs_vfs_readpage(struct file *filp, struct page *page)
{
- char *buffer = NULL;
- int retval = -EIO;
- loff_t offset = page_offset(page);
- int count = PAGE_CACHE_SIZE;
- struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- int rsize = v9ses->maxdata - V9FS_IOHDRSZ;
- struct v9fs_fid *v9f = filp->private_data;
- struct v9fs_fcall *fcall = NULL;
- int fid = v9f->fid;
- int total = 0;
- int result = 0;
-
- dprintk(DEBUG_VFS, "\n");
+ int retval;
+ loff_t offset;
+ char *buffer;
+ struct p9_fid *fid;
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ fid = filp->private_data;
buffer = kmap(page);
- do {
- if (count < rsize)
- rsize = count;
-
- result = v9fs_t_read(v9ses, fid, offset, rsize, &fcall);
-
- if (result < 0) {
- printk(KERN_ERR "v9fs_t_read returned %d\n",
- result);
-
- kfree(fcall);
- goto UnmapAndUnlock;
- } else
- offset += result;
-
- memcpy(buffer, fcall->params.rread.data, result);
-
- count -= result;
- buffer += result;
- total += result;
-
- kfree(fcall);
+ offset = page_offset(page);
- if (result < rsize)
- break;
- } while (count);
+ retval = p9_client_readn(fid, buffer, offset, PAGE_CACHE_SIZE);
+ if (retval < 0)
+ goto done;
- memset(buffer, 0, count);
+ memset(buffer + retval, 0, PAGE_CACHE_SIZE - retval);
flush_dcache_page(page);
SetPageUptodate(page);
retval = 0;
-UnmapAndUnlock:
+done:
kunmap(page);
unlock_page(page);
return retval;
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c
index d93960429c09..f9534f18df0a 100644
--- a/fs/9p/vfs_dentry.c
+++ b/fs/9p/vfs_dentry.c
@@ -34,10 +34,10 @@
#include <linux/namei.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -52,7 +52,7 @@
static int v9fs_dentry_delete(struct dentry *dentry)
{
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
return 1;
}
@@ -69,7 +69,7 @@ static int v9fs_dentry_delete(struct dentry *dentry)
static int v9fs_cached_dentry_delete(struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
if(!inode)
return 1;
@@ -85,26 +85,19 @@ static int v9fs_cached_dentry_delete(struct dentry *dentry)
void v9fs_dentry_release(struct dentry *dentry)
{
- int err;
-
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
-
- if (dentry->d_fsdata != NULL) {
- struct list_head *fid_list = dentry->d_fsdata;
- struct v9fs_fid *temp = NULL;
- struct v9fs_fid *current_fid = NULL;
-
- list_for_each_entry_safe(current_fid, temp, fid_list, list) {
- err = v9fs_t_clunk(current_fid->v9ses, current_fid->fid);
-
- if (err < 0)
- dprintk(DEBUG_ERROR, "clunk failed: %d name %s\n",
- err, dentry->d_iname);
-
- v9fs_fid_destroy(current_fid);
+ struct v9fs_dentry *dent;
+ struct p9_fid *temp, *current_fid;
+
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ dent = dentry->d_fsdata;
+ if (dent) {
+ list_for_each_entry_safe(current_fid, temp, &dent->fidlist,
+ dlist) {
+ p9_client_clunk(current_fid);
}
- kfree(dentry->d_fsdata); /* free the list_head */
+ kfree(dent);
+ dentry->d_fsdata = NULL;
}
}
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 1dd86ee90bc5..0924d4477da3 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -32,11 +32,10 @@
#include <linux/sched.h>
#include <linux/inet.h>
#include <linux/idr.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -46,14 +45,14 @@
*
*/
-static inline int dt_type(struct v9fs_stat *mistat)
+static inline int dt_type(struct p9_stat *mistat)
{
unsigned long perm = mistat->mode;
int rettype = DT_REG;
- if (perm & V9FS_DMDIR)
+ if (perm & P9_DMDIR)
rettype = DT_DIR;
- if (perm & V9FS_DMSYMLINK)
+ if (perm & P9_DMSYMLINK)
rettype = DT_LNK;
return rettype;
@@ -69,106 +68,36 @@ static inline int dt_type(struct v9fs_stat *mistat)
static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct v9fs_fcall *fcall = NULL;
- struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *file = filp->private_data;
- unsigned int i, n, s;
- int fid = -1;
- int ret = 0;
- struct v9fs_stat stat;
- int over = 0;
-
- dprintk(DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
-
- fid = file->fid;
-
- if (file->rdir_fcall && (filp->f_pos != file->rdir_pos)) {
- kfree(file->rdir_fcall);
- file->rdir_fcall = NULL;
- }
-
- if (file->rdir_fcall) {
- n = file->rdir_fcall->params.rread.count;
- i = file->rdir_fpos;
- while (i < n) {
- s = v9fs_deserialize_stat(
- file->rdir_fcall->params.rread.data + i,
- n - i, &stat, v9ses->extended);
-
- if (s == 0) {
- dprintk(DEBUG_ERROR,
- "error while deserializing stat\n");
- ret = -EIO;
- goto FreeStructs;
- }
-
- over = filldir(dirent, stat.name.str, stat.name.len,
- filp->f_pos, v9fs_qid2ino(&stat.qid),
- dt_type(&stat));
-
- if (over) {
- file->rdir_fpos = i;
- file->rdir_pos = filp->f_pos;
- break;
- }
-
- i += s;
- filp->f_pos += s;
- }
-
- if (!over) {
- kfree(file->rdir_fcall);
- file->rdir_fcall = NULL;
- }
- }
-
- while (!over) {
- ret = v9fs_t_read(v9ses, fid, filp->f_pos,
- v9ses->maxdata-V9FS_IOHDRSZ, &fcall);
- if (ret < 0) {
- dprintk(DEBUG_ERROR, "error while reading: %d: %p\n",
- ret, fcall);
- goto FreeStructs;
- } else if (ret == 0)
+ int over;
+ struct p9_fid *fid;
+ struct v9fs_session_info *v9ses;
+ struct inode *inode;
+ struct p9_stat *st;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+ inode = filp->f_path.dentry->d_inode;
+ v9ses = v9fs_inode2v9ses(inode);
+ fid = filp->private_data;
+ while ((st = p9_client_dirread(fid, filp->f_pos)) != NULL) {
+ if (IS_ERR(st))
+ return PTR_ERR(st);
+
+ over = filldir(dirent, st->name.str, st->name.len, filp->f_pos,
+ v9fs_qid2ino(&st->qid), dt_type(st));
+
+ if (over)
break;
- n = ret;
- i = 0;
- while (i < n) {
- s = v9fs_deserialize_stat(fcall->params.rread.data + i,
- n - i, &stat, v9ses->extended);
-
- if (s == 0) {
- dprintk(DEBUG_ERROR,
- "error while deserializing stat\n");
- return -EIO;
- }
-
- over = filldir(dirent, stat.name.str, stat.name.len,
- filp->f_pos, v9fs_qid2ino(&stat.qid),
- dt_type(&stat));
-
- if (over) {
- file->rdir_fcall = fcall;
- file->rdir_fpos = i;
- file->rdir_pos = filp->f_pos;
- fcall = NULL;
- break;
- }
-
- i += s;
- filp->f_pos += s;
- }
-
- kfree(fcall);
+ filp->f_pos += st->size;
+ kfree(st);
+ st = NULL;
}
- FreeStructs:
- kfree(fcall);
- return ret;
+ kfree(st);
+ return 0;
}
+
/**
* v9fs_dir_release - close a directory
* @inode: inode of the directory
@@ -178,29 +107,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
int v9fs_dir_release(struct inode *inode, struct file *filp)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *fid = filp->private_data;
- int fidnum = -1;
-
- dprintk(DEBUG_VFS, "inode: %p filp: %p fid: %d\n", inode, filp,
- fid->fid);
- fidnum = fid->fid;
+ struct p9_fid *fid;
+ fid = filp->private_data;
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "inode: %p filp: %p fid: %d\n", inode, filp, fid->fid);
filemap_write_and_wait(inode->i_mapping);
-
- if (fidnum >= 0) {
- dprintk(DEBUG_VFS, "fidopen: %d v9f->fid: %d\n", fid->fidopen,
- fid->fid);
-
- if (v9fs_t_clunk(v9ses, fidnum))
- dprintk(DEBUG_ERROR, "clunk failed\n");
-
- kfree(fid->rdir_fcall);
- kfree(fid);
-
- filp->private_data = NULL;
- }
-
+ p9_client_clunk(fid);
return 0;
}
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 6e7678e4852f..2a40c2946d0a 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -34,10 +34,10 @@
#include <linux/list.h>
#include <asm/uaccess.h>
#include <linux/idr.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -52,48 +52,40 @@ static const struct file_operations v9fs_cached_file_operations;
int v9fs_file_open(struct inode *inode, struct file *file)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *vfid;
- struct v9fs_fcall *fcall = NULL;
- int omode;
int err;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ int omode;
- dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file);
-
- vfid = v9fs_fid_clone(file->f_path.dentry);
- if (IS_ERR(vfid))
- return PTR_ERR(vfid);
-
+ P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p \n", inode, file);
+ v9ses = v9fs_inode2v9ses(inode);
omode = v9fs_uflags2omode(file->f_flags);
- err = v9fs_t_open(v9ses, vfid->fid, omode, &fcall);
- if (err < 0) {
- PRINT_FCALL_ERROR("open failed", fcall);
- goto Clunk_Fid;
+ fid = file->private_data;
+ if (!fid) {
+ fid = v9fs_fid_clone(file->f_path.dentry);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
+
+ err = p9_client_open(fid, omode);
+ if (err < 0) {
+ p9_client_clunk(fid);
+ return err;
+ }
+ if (omode & P9_OTRUNC) {
+ inode->i_size = 0;
+ inode->i_blocks = 0;
+ }
}
- file->private_data = vfid;
- vfid->fidopen = 1;
- vfid->fidclunked = 0;
- vfid->iounit = fcall->params.ropen.iounit;
- vfid->rdir_pos = 0;
- vfid->rdir_fcall = NULL;
- vfid->filp = file;
- kfree(fcall);
-
- if((vfid->qid.version) && (v9ses->cache)) {
- dprintk(DEBUG_VFS, "cached");
+ file->private_data = fid;
+ if ((fid->qid.version) && (v9ses->cache)) {
+ P9_DPRINTK(P9_DEBUG_VFS, "cached");
/* enable cached file options */
if(file->f_op == &v9fs_file_operations)
file->f_op = &v9fs_cached_file_operations;
}
return 0;
-
-Clunk_Fid:
- v9fs_fid_clunk(v9ses, vfid);
- kfree(fcall);
-
- return err;
}
/**
@@ -110,7 +102,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
int res = 0;
struct inode *inode = filp->f_path.dentry->d_inode;
- dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
+ P9_DPRINTK(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
/* No mandatory locks */
if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
@@ -136,55 +128,16 @@ static ssize_t
v9fs_file_read(struct file *filp, char __user * data, size_t count,
loff_t * offset)
{
- struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *v9f = filp->private_data;
- struct v9fs_fcall *fcall = NULL;
- int fid = v9f->fid;
- int rsize = 0;
- int result = 0;
- int total = 0;
- int n;
-
- dprintk(DEBUG_VFS, "\n");
-
- rsize = v9ses->maxdata - V9FS_IOHDRSZ;
- if (v9f->iounit != 0 && rsize > v9f->iounit)
- rsize = v9f->iounit;
-
- do {
- if (count < rsize)
- rsize = count;
+ int ret;
+ struct p9_fid *fid;
- result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall);
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ fid = filp->private_data;
+ ret = p9_client_uread(fid, data, *offset, count);
+ if (ret > 0)
+ *offset += ret;
- if (result < 0) {
- printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n",
- result);
-
- kfree(fcall);
- return total;
- } else
- *offset += result;
-
- n = copy_to_user(data, fcall->params.rread.data, result);
- if (n) {
- dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n);
- kfree(fcall);
- return -EFAULT;
- }
-
- count -= result;
- data += result;
- total += result;
-
- kfree(fcall);
-
- if (result < rsize)
- break;
- } while (count);
-
- return total;
+ return ret;
}
/**
@@ -200,50 +153,25 @@ static ssize_t
v9fs_file_write(struct file *filp, const char __user * data,
size_t count, loff_t * offset)
{
+ int ret;
+ struct p9_fid *fid;
struct inode *inode = filp->f_path.dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- struct v9fs_fid *v9fid = filp->private_data;
- struct v9fs_fcall *fcall;
- int fid = v9fid->fid;
- int result = -EIO;
- int rsize = 0;
- int total = 0;
-
- dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count,
- (int)*offset);
- rsize = v9ses->maxdata - V9FS_IOHDRSZ;
- if (v9fid->iounit != 0 && rsize > v9fid->iounit)
- rsize = v9fid->iounit;
-
- do {
- if (count < rsize)
- rsize = count;
- result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall);
- if (result < 0) {
- PRINT_FCALL_ERROR("error while writing", fcall);
- kfree(fcall);
- return result;
- } else
- *offset += result;
+ P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data,
+ (int)count, (int)*offset);
- kfree(fcall);
- fcall = NULL;
+ fid = filp->private_data;
+ ret = p9_client_uwrite(fid, data, *offset, count);
+ if (ret > 0)
+ *offset += ret;
- if (result != rsize) {
- eprintk(KERN_ERR,
- "short write: v9fs_t_write returned %d\n",
- result);
- break;
- }
-
- count -= result;
- data += result;
- total += result;
- } while (count);
+ if (*offset > inode->i_size) {
+ inode->i_size = *offset;
+ inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
+ }
invalidate_inode_pages2(inode->i_mapping);
- return total;
+ return ret;
}
static const struct file_operations v9fs_cached_file_operations = {
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index c76cd8fa3f6c..e5c45eed58a9 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -34,10 +34,10 @@
#include <linux/namei.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -58,27 +58,27 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
int res;
res = mode & 0777;
if (S_ISDIR(mode))
- res |= V9FS_DMDIR;
+ res |= P9_DMDIR;
if (v9ses->extended) {
if (S_ISLNK(mode))
- res |= V9FS_DMSYMLINK;
+ res |= P9_DMSYMLINK;
if (v9ses->nodev == 0) {
if (S_ISSOCK(mode))
- res |= V9FS_DMSOCKET;
+ res |= P9_DMSOCKET;
if (S_ISFIFO(mode))
- res |= V9FS_DMNAMEDPIPE;
+ res |= P9_DMNAMEDPIPE;
if (S_ISBLK(mode))
- res |= V9FS_DMDEVICE;
+ res |= P9_DMDEVICE;
if (S_ISCHR(mode))
- res |= V9FS_DMDEVICE;
+ res |= P9_DMDEVICE;
}
if ((mode & S_ISUID) == S_ISUID)
- res |= V9FS_DMSETUID;
+ res |= P9_DMSETUID;
if ((mode & S_ISGID) == S_ISGID)
- res |= V9FS_DMSETGID;
- if ((mode & V9FS_DMLINK))
- res |= V9FS_DMLINK;
+ res |= P9_DMSETGID;
+ if ((mode & P9_DMLINK))
+ res |= P9_DMLINK;
}
return res;
@@ -97,27 +97,27 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
res = mode & 0777;
- if ((mode & V9FS_DMDIR) == V9FS_DMDIR)
+ if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR;
- else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended))
+ else if ((mode & P9_DMSYMLINK) && (v9ses->extended))
res |= S_IFLNK;
- else if ((mode & V9FS_DMSOCKET) && (v9ses->extended)
+ else if ((mode & P9_DMSOCKET) && (v9ses->extended)
&& (v9ses->nodev == 0))
res |= S_IFSOCK;
- else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended)
+ else if ((mode & P9_DMNAMEDPIPE) && (v9ses->extended)
&& (v9ses->nodev == 0))
res |= S_IFIFO;
- else if ((mode & V9FS_DMDEVICE) && (v9ses->extended)
+ else if ((mode & P9_DMDEVICE) && (v9ses->extended)
&& (v9ses->nodev == 0))
res |= S_IFBLK;
else
res |= S_IFREG;
if (v9ses->extended) {
- if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID)
+ if ((mode & P9_DMSETUID) == P9_DMSETUID)
res |= S_ISUID;
- if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID)
+ if ((mode & P9_DMSETGID) == P9_DMSETGID)
res |= S_ISGID;
}
@@ -132,26 +132,26 @@ int v9fs_uflags2omode(int uflags)
switch (uflags&3) {
default:
case O_RDONLY:
- ret = V9FS_OREAD;
+ ret = P9_OREAD;
break;
case O_WRONLY:
- ret = V9FS_OWRITE;
+ ret = P9_OWRITE;
break;
case O_RDWR:
- ret = V9FS_ORDWR;
+ ret = P9_ORDWR;
break;
}
if (uflags & O_EXCL)
- ret |= V9FS_OEXCL;
+ ret |= P9_OEXCL;
if (uflags & O_TRUNC)
- ret |= V9FS_OTRUNC;
+ ret |= P9_OTRUNC;
if (uflags & O_APPEND)
- ret |= V9FS_OAPPEND;
+ ret |= P9_OAPPEND;
return ret;
}
@@ -164,7 +164,7 @@ int v9fs_uflags2omode(int uflags)
*/
static void
-v9fs_blank_wstat(struct v9fs_wstat *wstat)
+v9fs_blank_wstat(struct p9_wstat *wstat)
{
wstat->type = ~0;
wstat->dev = ~0;
@@ -197,7 +197,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
struct inode *inode;
struct v9fs_session_info *v9ses = sb->s_fs_info;
- dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
+ P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
inode = new_inode(sb);
if (inode) {
@@ -215,7 +215,8 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
case S_IFCHR:
case S_IFSOCK:
if(!v9ses->extended) {
- dprintk(DEBUG_ERROR, "special files without extended mode\n");
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "special files without extended mode\n");
return ERR_PTR(-EINVAL);
}
init_special_inode(inode, inode->i_mode,
@@ -227,7 +228,8 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
break;
case S_IFLNK:
if(!v9ses->extended) {
- dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n");
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "extended modes used w/o 9P2000.u\n");
return ERR_PTR(-EINVAL);
}
inode->i_op = &v9fs_symlink_inode_operations;
@@ -241,71 +243,19 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
inode->i_fop = &v9fs_dir_operations;
break;
default:
- dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "BAD mode 0x%x S_IFMT 0x%x\n",
mode, mode & S_IFMT);
return ERR_PTR(-EINVAL);
}
} else {
- eprintk(KERN_WARNING, "Problem allocating inode\n");
+ P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
return ERR_PTR(-ENOMEM);
}
return inode;
}
-static int
-v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm,
- u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit)
-{
- int fid;
- int err;
- struct v9fs_fcall *fcall;
-
- fid = v9fs_get_idpool(&v9ses->fidpool);
- if (fid < 0) {
- eprintk(KERN_WARNING, "no free fids available\n");
- return -ENOSPC;
- }
-
- err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall);
- if (err < 0) {
- PRINT_FCALL_ERROR("clone error", fcall);
- if (fcall && fcall->id == RWALK)
- goto clunk_fid;
- else
- goto put_fid;
- }
- kfree(fcall);
-
- err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall);
- if (err < 0) {
- PRINT_FCALL_ERROR("create fails", fcall);
- goto clunk_fid;
- }
-
- if (iounit)
- *iounit = fcall->params.rcreate.iounit;
-
- if (qid)
- *qid = fcall->params.rcreate.qid;
-
- if (fidp)
- *fidp = fid;
-
- kfree(fcall);
- return 0;
-
-clunk_fid:
- v9fs_t_clunk(v9ses, fid);
- fid = V9FS_NOFID;
-
-put_fid:
- if (fid != V9FS_NOFID)
- v9fs_put_idpool(fid, &v9ses->fidpool);
-
- kfree(fcall);
- return err;
-}
-
+/*
static struct v9fs_fid*
v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
{
@@ -355,23 +305,25 @@ error:
kfree(fcall);
return ERR_PTR(err);
}
+*/
static struct inode *
-v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid,
+v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
struct super_block *sb)
{
int err, umode;
struct inode *ret;
- struct v9fs_fcall *fcall;
+ struct p9_stat *st;
ret = NULL;
- err = v9fs_t_stat(v9ses, fid, &fcall);
- if (err) {
- PRINT_FCALL_ERROR("stat error", fcall);
+ st = p9_client_stat(fid);
+ if (IS_ERR(st)) {
+ err = PTR_ERR(st);
+ st = NULL;
goto error;
}
- umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode);
+ umode = p9mode2unixmode(v9ses, st->mode);
ret = v9fs_get_inode(sb, umode);
if (IS_ERR(ret)) {
err = PTR_ERR(ret);
@@ -379,12 +331,13 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid,
goto error;
}
- v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb);
- kfree(fcall);
+ v9fs_stat2inode(st, ret, sb);
+ ret->i_ino = v9fs_qid2ino(&st->qid);
+ kfree(st);
return ret;
error:
- kfree(fcall);
+ kfree(st);
if (ret)
iput(ret);
@@ -401,43 +354,20 @@ error:
static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
{
- struct v9fs_fcall *fcall = NULL;
- struct super_block *sb = NULL;
- struct v9fs_session_info *v9ses = NULL;
- struct v9fs_fid *v9fid = NULL;
- struct inode *file_inode = NULL;
- int fid = -1;
- int result = 0;
+ struct inode *file_inode;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *v9fid;
- dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
+ P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
rmdir);
file_inode = file->d_inode;
- sb = file_inode->i_sb;
v9ses = v9fs_inode2v9ses(file_inode);
v9fid = v9fs_fid_clone(file);
if(IS_ERR(v9fid))
return PTR_ERR(v9fid);
- fid = v9fid->fid;
- if (fid < 0) {
- dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n",
- file_inode->i_ino);
- return -EBADF;
- }
-
- result = v9fs_t_remove(v9ses, fid, &fcall);
- if (result < 0) {
- PRINT_FCALL_ERROR("remove fails", fcall);
- goto Error;
- }
-
- v9fs_put_idpool(fid, &v9ses->fidpool);
- v9fs_fid_destroy(v9fid);
-
-Error:
- kfree(fcall);
- return result;
+ return p9_client_remove(v9fid);
}
static int
@@ -446,61 +376,59 @@ v9fs_open_created(struct inode *inode, struct file *file)
return 0;
}
+
/**
- * v9fs_vfs_create - VFS hook to create files
- * @inode: directory inode that is being deleted
- * @dentry: dentry that is being deleted
- * @mode: create permissions
- * @nd: path information
+ * v9fs_create - Create a file
+ * @dentry: dentry that is being created
+ * @perm: create permissions
+ * @mode: open mode
*
*/
-
-static int
-v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
- struct nameidata *nd)
+static struct p9_fid *
+v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
+ struct dentry *dentry, char *extension, u32 perm, u8 mode)
{
int err;
- u32 fid, perm, iounit;
- int flags;
- struct v9fs_session_info *v9ses;
- struct v9fs_fid *dfid, *vfid, *ffid;
+ char *name;
+ struct p9_fid *dfid, *ofid, *fid;
struct inode *inode;
- struct v9fs_qid qid;
- struct file *filp;
- inode = NULL;
- vfid = NULL;
- v9ses = v9fs_inode2v9ses(dir);
+ err = 0;
+ ofid = NULL;
+ fid = NULL;
+ name = (char *) dentry->d_name.name;
dfid = v9fs_fid_clone(dentry->d_parent);
if(IS_ERR(dfid)) {
err = PTR_ERR(dfid);
+ dfid = NULL;
goto error;
}
- perm = unixmode2p9mode(v9ses, mode);
- if (nd && nd->flags & LOOKUP_OPEN)
- flags = nd->intent.open.flags - 1;
- else
- flags = O_RDWR;
-
- err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
- perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit);
+ /* clone a fid to use for creation */
+ ofid = p9_client_walk(dfid, 0, NULL, 1);
+ if (IS_ERR(ofid)) {
+ err = PTR_ERR(ofid);
+ ofid = NULL;
+ goto error;
+ }
- if (err)
- goto clunk_dfid;
+ err = p9_client_fcreate(ofid, name, perm, mode, extension);
+ if (err < 0)
+ goto error;
- vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
- v9fs_fid_clunk(v9ses, dfid);
- if (IS_ERR(vfid)) {
- err = PTR_ERR(vfid);
- vfid = NULL;
+ /* now walk from the parent so we can get unopened fid */
+ fid = p9_client_walk(dfid, 1, &name, 0);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
goto error;
- }
+ } else
+ dfid = NULL;
- inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
+ /* instantiate inode and assign the unopened fid to the dentry */
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
- inode = NULL;
goto error;
}
@@ -508,35 +436,78 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
dentry->d_op = &v9fs_cached_dentry_operations;
else
dentry->d_op = &v9fs_dentry_operations;
+
d_instantiate(dentry, inode);
+ v9fs_fid_add(dentry, fid);
+ return ofid;
- if (nd && nd->flags & LOOKUP_OPEN) {
- ffid = v9fs_fid_create(v9ses, fid);
- if (!ffid)
- return -ENOMEM;
+error:
+ if (dfid)
+ p9_client_clunk(dfid);
+
+ if (ofid)
+ p9_client_clunk(ofid);
+
+ if (fid)
+ p9_client_clunk(fid);
+
+ return ERR_PTR(err);
+}
+
+/**
+ * v9fs_vfs_create - VFS hook to create files
+ * @inode: directory inode that is being created
+ * @dentry: dentry that is being deleted
+ * @mode: create permissions
+ * @nd: path information
+ *
+ */
+static int
+v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ int err;
+ u32 perm;
+ int flags;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct file *filp;
+
+ err = 0;
+ fid = NULL;
+ v9ses = v9fs_inode2v9ses(dir);
+ perm = unixmode2p9mode(v9ses, mode);
+ if (nd && nd->flags & LOOKUP_OPEN)
+ flags = nd->intent.open.flags - 1;
+ else
+ flags = O_RDWR;
+
+ fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
+ v9fs_uflags2omode(flags));
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+
+ /* if we are opening a file, assign the open fid to the file */
+ if (nd && nd->flags & LOOKUP_OPEN) {
filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
if (IS_ERR(filp)) {
- v9fs_fid_destroy(ffid);
- return PTR_ERR(filp);
+ err = PTR_ERR(filp);
+ goto error;
}
- ffid->rdir_pos = 0;
- ffid->rdir_fcall = NULL;
- ffid->fidopen = 1;
- ffid->iounit = iounit;
- ffid->filp = filp;
- filp->private_data = ffid;
- }
+ filp->private_data = fid;
+ } else
+ p9_client_clunk(fid);
return 0;
-clunk_dfid:
- v9fs_fid_clunk(v9ses, dfid);
-
error:
- if (vfid)
- v9fs_fid_destroy(vfid);
+ if (fid)
+ p9_client_clunk(fid);
return err;
}
@@ -552,57 +523,23 @@ error:
static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int err;
- u32 fid, perm;
+ u32 perm;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dfid, *vfid;
- struct inode *inode;
+ struct p9_fid *fid;
- inode = NULL;
- vfid = NULL;
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
+ err = 0;
v9ses = v9fs_inode2v9ses(dir);
- dfid = v9fs_fid_clone(dentry->d_parent);
- if(IS_ERR(dfid)) {
- err = PTR_ERR(dfid);
- goto error;
- }
-
perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
-
- err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
- perm, V9FS_OREAD, NULL, &fid, NULL, NULL);
-
- if (err) {
- dprintk(DEBUG_ERROR, "create error %d\n", err);
- goto clean_up_dfid;
+ fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
}
- vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
- if (IS_ERR(vfid)) {
- err = PTR_ERR(vfid);
- vfid = NULL;
- goto clean_up_dfid;
- }
+ if (fid)
+ p9_client_clunk(fid);
- v9fs_fid_clunk(v9ses, dfid);
- inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
- if (IS_ERR(inode)) {
- err = PTR_ERR(inode);
- inode = NULL;
- v9fs_fid_destroy(vfid);
- goto error;
- }
-
- if(v9ses->cache)
- dentry->d_op = &v9fs_cached_dentry_operations;
- else
- dentry->d_op = &v9fs_dentry_operations;
- d_instantiate(dentry, inode);
- return 0;
-
-clean_up_dfid:
- v9fs_fid_clunk(v9ses, dfid);
-
-error:
return err;
}
@@ -619,104 +556,54 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
{
struct super_block *sb;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dirfid;
- struct v9fs_fid *fid;
+ struct p9_fid *dfid, *fid;
struct inode *inode;
- struct v9fs_fcall *fcall = NULL;
- int dirfidnum = -1;
- int newfid = -1;
+ char *name;
int result = 0;
- dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
+ P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
dir, dentry->d_name.name, dentry, nameidata);
sb = dir->i_sb;
v9ses = v9fs_inode2v9ses(dir);
- dirfid = v9fs_fid_lookup(dentry->d_parent);
-
- if(IS_ERR(dirfid))
- return ERR_PTR(PTR_ERR(dirfid));
-
- dirfidnum = dirfid->fid;
-
- newfid = v9fs_get_idpool(&v9ses->fidpool);
- if (newfid < 0) {
- eprintk(KERN_WARNING, "newfid fails!\n");
- result = -ENOSPC;
- goto Release_Dirfid;
- }
-
- result = v9fs_t_walk(v9ses, dirfidnum, newfid,
- (char *)dentry->d_name.name, &fcall);
-
- up(&dirfid->lock);
-
- if (result < 0) {
- if (fcall && fcall->id == RWALK)
- v9fs_t_clunk(v9ses, newfid);
- else
- v9fs_put_idpool(newfid, &v9ses->fidpool);
-
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ if (IS_ERR(dfid))
+ return ERR_PTR(PTR_ERR(dfid));
+
+ name = (char *) dentry->d_name.name;
+ fid = p9_client_walk(dfid, 1, &name, 1);
+ if (IS_ERR(fid)) {
+ result = PTR_ERR(fid);
if (result == -ENOENT) {
d_add(dentry, NULL);
- dprintk(DEBUG_VFS,
- "Return negative dentry %p count %d\n",
- dentry, atomic_read(&dentry->d_count));
- kfree(fcall);
return NULL;
}
- dprintk(DEBUG_ERROR, "walk error:%d\n", result);
- goto FreeFcall;
- }
- kfree(fcall);
-
- result = v9fs_t_stat(v9ses, newfid, &fcall);
- if (result < 0) {
- dprintk(DEBUG_ERROR, "stat error\n");
- goto FreeFcall;
- }
-
- inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses,
- fcall->params.rstat.stat.mode));
- if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) {
- eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n",
- PTR_ERR(inode));
-
- result = -ENOSPC;
- goto FreeFcall;
+ return ERR_PTR(result);
}
- inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid);
-
- fid = v9fs_fid_create(v9ses, newfid);
- if (fid == NULL) {
- dprintk(DEBUG_ERROR, "couldn't insert\n");
- result = -ENOMEM;
- goto FreeFcall;
+ inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
+ if (IS_ERR(inode)) {
+ result = PTR_ERR(inode);
+ inode = NULL;
+ goto error;
}
- result = v9fs_fid_insert(fid, dentry);
+ result = v9fs_fid_add(dentry, fid);
if (result < 0)
- goto FreeFcall;
+ goto error;
- fid->qid = fcall->params.rstat.stat.qid;
- v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb);
if((fid->qid.version)&&(v9ses->cache))
dentry->d_op = &v9fs_cached_dentry_operations;
else
dentry->d_op = &v9fs_dentry_operations;
d_add(dentry, inode);
- kfree(fcall);
-
return NULL;
-Release_Dirfid:
- up(&dirfid->lock);
-
-FreeFcall:
- kfree(fcall);
+error:
+ if (fid)
+ p9_client_clunk(fid);
return ERR_PTR(result);
}
@@ -758,73 +645,54 @@ static int
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- struct inode *old_inode = old_dentry->d_inode;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode);
- struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry);
- struct v9fs_fid *olddirfid;
- struct v9fs_fid *newdirfid;
- struct v9fs_wstat wstat;
- struct v9fs_fcall *fcall = NULL;
- int fid = -1;
- int olddirfidnum = -1;
- int newdirfidnum = -1;
- int retval = 0;
-
- dprintk(DEBUG_VFS, "\n");
+ struct inode *old_inode;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *oldfid;
+ struct p9_fid *olddirfid;
+ struct p9_fid *newdirfid;
+ struct p9_wstat wstat;
+ int retval;
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ retval = 0;
+ old_inode = old_dentry->d_inode;
+ v9ses = v9fs_inode2v9ses(old_inode);
+ oldfid = v9fs_fid_lookup(old_dentry);
if(IS_ERR(oldfid))
return PTR_ERR(oldfid);
olddirfid = v9fs_fid_clone(old_dentry->d_parent);
if(IS_ERR(olddirfid)) {
retval = PTR_ERR(olddirfid);
- goto Release_lock;
+ goto done;
}
newdirfid = v9fs_fid_clone(new_dentry->d_parent);
if(IS_ERR(newdirfid)) {
retval = PTR_ERR(newdirfid);
- goto Clunk_olddir;
+ goto clunk_olddir;
}
/* 9P can only handle file rename in the same directory */
if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
- dprintk(DEBUG_ERROR, "old dir and new dir are different\n");
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "old dir and new dir are different\n");
retval = -EXDEV;
- goto Clunk_newdir;
- }
-
- fid = oldfid->fid;
- olddirfidnum = olddirfid->fid;
- newdirfidnum = newdirfid->fid;
-
- if (fid < 0) {
- dprintk(DEBUG_ERROR, "no fid for old file #%lu\n",
- old_inode->i_ino);
- retval = -EBADF;
- goto Clunk_newdir;
+ goto clunk_newdir;
}
v9fs_blank_wstat(&wstat);
wstat.muid = v9ses->name;
wstat.name = (char *) new_dentry->d_name.name;
+ retval = p9_client_wstat(oldfid, &wstat);
- retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall);
+clunk_newdir:
+ p9_client_clunk(olddirfid);
- if (retval < 0)
- PRINT_FCALL_ERROR("wstat error", fcall);
-
- kfree(fcall);
-
-Clunk_newdir:
- v9fs_fid_clunk(v9ses, newdirfid);
-
-Clunk_olddir:
- v9fs_fid_clunk(v9ses, olddirfid);
-
-Release_lock:
- up(&oldfid->lock);
+clunk_olddir:
+ p9_client_clunk(newdirfid);
+done:
return retval;
}
@@ -840,28 +708,30 @@ static int
v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat)
{
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_clone(dentry);
- int err = -EPERM;
+ int err;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_stat *st;
- dprintk(DEBUG_VFS, "dentry: %p\n", dentry);
- if(IS_ERR(fid))
+ P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
+ err = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ if (v9ses->cache == CACHE_LOOSE)
+ return simple_getattr(mnt, dentry, stat);
+
+ fid = v9fs_fid_lookup(dentry);
+ if (IS_ERR(fid))
return PTR_ERR(fid);
- err = v9fs_t_stat(v9ses, fid->fid, &fcall);
+ st = p9_client_stat(fid);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
- if (err < 0)
- dprintk(DEBUG_ERROR, "stat error\n");
- else {
- v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode,
- dentry->d_inode->i_sb);
+ v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
generic_fillattr(dentry->d_inode, stat);
- }
- kfree(fcall);
- v9fs_fid_clunk(v9ses, fid);
- return err;
+ kfree(st);
+ return 0;
}
/**
@@ -873,13 +743,15 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_clone(dentry);
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_wstat wstat;
- int res = -EPERM;
+ int retval;
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_wstat wstat;
- dprintk(DEBUG_VFS, "\n");
+ P9_DPRINTK(P9_DEBUG_VFS, "\n");
+ retval = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ fid = v9fs_fid_lookup(dentry);
if(IS_ERR(fid))
return PTR_ERR(fid);
@@ -904,17 +776,11 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
wstat.n_gid = iattr->ia_gid;
}
- res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
+ retval = p9_client_wstat(fid, &wstat);
+ if (retval >= 0)
+ retval = inode_setattr(dentry->d_inode, iattr);
- if (res < 0)
- PRINT_FCALL_ERROR("wstat error", fcall);
-
- kfree(fcall);
- if (res >= 0)
- res = inode_setattr(dentry->d_inode, iattr);
-
- v9fs_fid_clunk(v9ses, fid);
- return res;
+ return retval;
}
/**
@@ -926,7 +792,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
*/
void
-v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
+v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
struct super_block *sb)
{
int n;
@@ -967,8 +833,9 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
case 'b':
break;
default:
- dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n",
- type, stat->extension.len, stat->extension.str);
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "Unknown special type %c (%.*s)\n", type,
+ stat->extension.len, stat->extension.str);
};
inode->i_rdev = MKDEV(major, minor);
} else
@@ -976,8 +843,8 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
inode->i_size = stat->length;
- inode->i_blocks =
- (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+ /* not real number of blocks, but 512 byte ones ... */
+ inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
}
/**
@@ -987,7 +854,7 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
* BUG: potential for inode number collisions?
*/
-ino_t v9fs_qid2ino(struct v9fs_qid *qid)
+ino_t v9fs_qid2ino(struct p9_qid *qid)
{
u64 path = qid->path + 2;
ino_t i = 0;
@@ -1010,56 +877,46 @@ ino_t v9fs_qid2ino(struct v9fs_qid *qid)
static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
- int retval = -EPERM;
+ int retval;
- struct v9fs_fcall *fcall = NULL;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
- struct v9fs_fid *fid = v9fs_fid_clone(dentry);
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
+ struct p9_stat *st;
+ P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
+ retval = -EPERM;
+ v9ses = v9fs_inode2v9ses(dentry->d_inode);
+ fid = v9fs_fid_lookup(dentry);
if(IS_ERR(fid))
return PTR_ERR(fid);
- if (!v9ses->extended) {
- retval = -EBADF;
- dprintk(DEBUG_ERROR, "not extended\n");
- goto ClunkFid;
- }
-
- dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name);
- retval = v9fs_t_stat(v9ses, fid->fid, &fcall);
-
- if (retval < 0) {
- dprintk(DEBUG_ERROR, "stat error\n");
- goto FreeFcall;
- }
+ if (!v9ses->extended)
+ return -EBADF;
- if (!fcall) {
- retval = -EIO;
- goto ClunkFid;
- }
+ st = p9_client_stat(fid);
+ if (IS_ERR(st))
+ return PTR_ERR(st);
- if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) {
+ if (!(st->mode & P9_DMSYMLINK)) {
retval = -EINVAL;
- goto FreeFcall;
+ goto done;
}
/* copy extension buffer into buffer */
- if (fcall->params.rstat.stat.extension.len < buflen)
- buflen = fcall->params.rstat.stat.extension.len + 1;
+ if (st->extension.len < buflen)
+ buflen = st->extension.len + 1;
- memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
+ memmove(buffer, st->extension.str, buflen - 1);
buffer[buflen-1] = 0;
- dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len,
- fcall->params.rstat.stat.extension.str, buffer);
- retval = buflen;
+ P9_DPRINTK(P9_DEBUG_VFS,
+ "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len,
+ st->extension.str, buffer);
-FreeFcall:
- kfree(fcall);
-
-ClunkFid:
- v9fs_fid_clunk(v9ses, fid);
+ retval = buflen;
+done:
+ kfree(st);
return retval;
}
@@ -1084,14 +941,14 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
if (buflen > PATH_MAX)
buflen = PATH_MAX;
- dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
+ P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
retval = v9fs_readlink(dentry, link, buflen);
if (retval > 0) {
if ((ret = copy_to_user(buffer, link, retval)) != 0) {
- dprintk(DEBUG_ERROR, "problem copying to user: %d\n",
- ret);
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "problem copying to user: %d\n", ret);
retval = ret;
}
}
@@ -1112,7 +969,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
int len = 0;
char *link = __getname();
- dprintk(DEBUG_VFS, "%s n", dentry->d_name.name);
+ P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
if (!link)
link = ERR_PTR(-ENOMEM);
@@ -1141,7 +998,7 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
{
char *s = nd_get_link(nd);
- dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
+ P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
if (!IS_ERR(s))
__putname(s);
}
@@ -1149,66 +1006,24 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
int mode, const char *extension)
{
- int err;
- u32 fid, perm;
+ u32 perm;
struct v9fs_session_info *v9ses;
- struct v9fs_fid *dfid, *vfid = NULL;
- struct inode *inode = NULL;
+ struct p9_fid *fid;
v9ses = v9fs_inode2v9ses(dir);
if (!v9ses->extended) {
- dprintk(DEBUG_ERROR, "not extended\n");
+ P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
return -EPERM;
}
- dfid = v9fs_fid_clone(dentry->d_parent);
- if(IS_ERR(dfid)) {
- err = PTR_ERR(dfid);
- goto error;
- }
-
perm = unixmode2p9mode(v9ses, mode);
+ fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm,
+ P9_OREAD);
+ if (IS_ERR(fid))
+ return PTR_ERR(fid);
- err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name,
- perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL);
-
- if (err)
- goto clunk_dfid;
-
- err = v9fs_t_clunk(v9ses, fid);
- if (err)
- goto clunk_dfid;
-
- vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry);
- if (IS_ERR(vfid)) {
- err = PTR_ERR(vfid);
- vfid = NULL;
- goto clunk_dfid;
- }
-
- inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb);
- if (IS_ERR(inode)) {
- err = PTR_ERR(inode);
- inode = NULL;
- goto free_vfid;
- }
-
- if(v9ses->cache)
- dentry->d_op = &v9fs_cached_dentry_operations;
- else
- dentry->d_op = &v9fs_dentry_operations;
- d_instantiate(dentry, inode);
+ p9_client_clunk(fid);
return 0;
-
-free_vfid:
- v9fs_fid_destroy(vfid);
-
-clunk_dfid:
- v9fs_fid_clunk(v9ses, dfid);
-
-error:
- return err;
-
}
/**
@@ -1224,8 +1039,8 @@ error:
static int
v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
- dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
- symname);
+ P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino,
+ dentry->d_name.name, symname);
return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
}
@@ -1247,11 +1062,11 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *dentry)
{
int retval;
- struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
- struct v9fs_fid *oldfid;
+ struct p9_fid *oldfid;
char *name;
- dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
+ P9_DPRINTK(P9_DEBUG_VFS,
+ " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
old_dentry->d_name.name);
oldfid = v9fs_fid_clone(old_dentry);
@@ -1265,11 +1080,11 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
}
sprintf(name, "%d\n", oldfid->fid);
- retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
+ retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
__putname(name);
clunk_fid:
- v9fs_fid_clunk(v9ses, oldfid);
+ p9_client_clunk(oldfid);
return retval;
}
@@ -1288,7 +1103,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
int retval;
char *name;
- dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
+ P9_DPRINTK(P9_DEBUG_VFS,
+ " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
if (!new_valid_dev(rdev))
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index 7bdf8b326841..ba904371218b 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -37,10 +37,10 @@
#include <linux/mount.h>
#include <linux/idr.h>
#include <linux/sched.h>
+#include <net/9p/9p.h>
+#include <net/9p/client.h>
-#include "debug.h"
#include "v9fs.h"
-#include "9p.h"
#include "v9fs_vfs.h"
#include "fid.h"
@@ -107,41 +107,48 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
struct vfsmount *mnt)
{
struct super_block *sb = NULL;
- struct v9fs_fcall *fcall = NULL;
struct inode *inode = NULL;
struct dentry *root = NULL;
struct v9fs_session_info *v9ses = NULL;
- struct v9fs_fid *root_fid = NULL;
+ struct p9_stat *st = NULL;
int mode = S_IRWXUGO | S_ISVTX;
uid_t uid = current->fsuid;
gid_t gid = current->fsgid;
- int stat_result = 0;
- int newfid = 0;
+ struct p9_fid *fid;
int retval = 0;
- dprintk(DEBUG_VFS, " \n");
+ P9_DPRINTK(P9_DEBUG_VFS, " \n");
v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
if (!v9ses)
return -ENOMEM;
- if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) {
- dprintk(DEBUG_ERROR, "problem initiating session\n");
- retval = newfid;
- goto out_free_session;
+ fid = v9fs_session_init(v9ses, dev_name, data);
+ if (IS_ERR(fid)) {
+ retval = PTR_ERR(fid);
+ fid = NULL;
+ kfree(v9ses);
+ v9ses = NULL;
+ goto error;
+ }
+
+ st = p9_client_stat(fid);
+ if (IS_ERR(st)) {
+ retval = PTR_ERR(st);
+ goto error;
}
sb = sget(fs_type, NULL, v9fs_set_super, v9ses);
if (IS_ERR(sb)) {
retval = PTR_ERR(sb);
- goto out_close_session;
+ goto error;
}
v9fs_fill_super(sb, v9ses, flags);
inode = v9fs_get_inode(sb, S_IFDIR | mode);
if (IS_ERR(inode)) {
retval = PTR_ERR(inode);
- goto put_back_sb;
+ goto error;
}
inode->i_uid = uid;
@@ -150,54 +157,30 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
root = d_alloc_root(inode);
if (!root) {
retval = -ENOMEM;
- goto put_back_sb;
+ goto error;
}
sb->s_root = root;
+ root->d_inode->i_ino = v9fs_qid2ino(&st->qid);
+ v9fs_stat2inode(st, root->d_inode, sb);
+ v9fs_fid_add(root, fid);
- stat_result = v9fs_t_stat(v9ses, newfid, &fcall);
- if (stat_result < 0) {
- dprintk(DEBUG_ERROR, "stat error\n");
- v9fs_t_clunk(v9ses, newfid);
- } else {
- /* Setup the Root Inode */
- root_fid = v9fs_fid_create(v9ses, newfid);
- if (root_fid == NULL) {
- retval = -ENOMEM;
- goto put_back_sb;
- }
-
- retval = v9fs_fid_insert(root_fid, root);
- if (retval < 0) {
- kfree(fcall);
- goto put_back_sb;
- }
-
- root_fid->qid = fcall->params.rstat.stat.qid;
- root->d_inode->i_ino =
- v9fs_qid2ino(&fcall->params.rstat.stat.qid);
- v9fs_stat2inode(&fcall->params.rstat.stat, root->d_inode, sb);
- }
+ return simple_set_mnt(mnt, sb);
- kfree(fcall);
+error:
+ if (fid)
+ p9_client_clunk(fid);
- if (stat_result < 0) {
- retval = stat_result;
- goto put_back_sb;
+ if (v9ses) {
+ v9fs_session_close(v9ses);
+ kfree(v9ses);
}
- return simple_set_mnt(mnt, sb);
-
-out_close_session:
- v9fs_session_close(v9ses);
-out_free_session:
- kfree(v9ses);
- return retval;
+ if (sb) {
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+ }
-put_back_sb:
- /* deactivate_super calls v9fs_kill_super which will frees the rest */
- up_write(&sb->s_umount);
- deactivate_super(sb);
return retval;
}
@@ -211,7 +194,7 @@ static void v9fs_kill_super(struct super_block *s)
{
struct v9fs_session_info *v9ses = s->s_fs_info;
- dprintk(DEBUG_VFS, " %p\n", s);
+ P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s);
v9fs_dentry_release(s->s_root); /* clunk root */
@@ -219,7 +202,7 @@ static void v9fs_kill_super(struct super_block *s)
v9fs_session_close(v9ses);
kfree(v9ses);
- dprintk(DEBUG_VFS, "exiting kill_super\n");
+ P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
}
/**
@@ -234,7 +217,7 @@ static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info;
if (v9ses->debug != 0)
- seq_printf(m, ",debug=%u", v9ses->debug);
+ seq_printf(m, ",debug=%x", v9ses->debug);
if (v9ses->port != V9FS_PORT)
seq_printf(m, ",port=%u", v9ses->port);
if (v9ses->maxdata != 9000)
diff --git a/fs/Kconfig b/fs/Kconfig
index 42cfb7dc95b5..9acccda4fd6b 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -251,7 +251,7 @@ config JBD2
config JBD2_DEBUG
bool "JBD2 (ext4dev/ext4) debugging support"
- depends on JBD2
+ depends on JBD2 && DEBUG_FS
help
If you are using the ext4dev/ext4 journaled file system (or
potentially any other filesystem/device using JBD2), this option
@@ -260,10 +260,10 @@ config JBD2_DEBUG
By default, the debugging output will be turned off.
If you select Y here, then you will be able to turn on debugging
- with "echo N > /proc/sys/fs/jbd2-debug", where N is a number between
- 1 and 5. The higher the number, the more debugging output is
- generated. To turn debugging off again, do
- "echo 0 > /proc/sys/fs/jbd2-debug".
+ with "echo N > /sys/kernel/debug/jbd2/jbd2-debug", where N is a
+ number between 1 and 5. The higher the number, the more debugging
+ output is generated. To turn debugging off again, do
+ "echo 0 > /sys/kernel/debug/jbd2/jbd2-debug".
config FS_MBCACHE
# Meta block cache for Extended Attributes (ext2/ext3/ext4)
@@ -991,7 +991,7 @@ config TMPFS_POSIX_ACL
config HUGETLBFS
bool "HugeTLB file system support"
- depends on X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
+ depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || BROKEN
help
hugetlbfs is a filesystem backing for HugeTLB pages, based on
ramfs. For architectures that support it, say Y here and read
@@ -1700,7 +1700,8 @@ config NFSD_V3_ACL
config NFSD_V4
bool "Provide NFSv4 server support (EXPERIMENTAL)"
- depends on NFSD_V3 && EXPERIMENTAL
+ depends on NFSD && NFSD_V3 && EXPERIMENTAL
+ select RPCSEC_GSS_KRB5
help
If you would like to include the NFSv4 server as well as the NFSv2
and NFSv3 servers, say Y here. This feature is experimental, and
@@ -2074,7 +2075,7 @@ config AFS_DEBUG
config 9P_FS
tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
- depends on INET && EXPERIMENTAL
+ depends on INET && NET_9P && EXPERIMENTAL
help
If you say Y here, you will get experimental support for
Plan 9 resource sharing via the 9P2000 protocol.
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index de2ed5ca3351..1c9fd3029496 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -234,14 +234,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
sizeof(struct adfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (adfs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 6d0ebc321530..c80191ae2059 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -99,7 +99,7 @@ static int init_inodecache(void)
sizeof(struct affs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (affs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 73ce561f3ea0..a66671082cfb 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -8,6 +8,7 @@ kafs-objs := \
cmservice.o \
dir.o \
file.o \
+ flock.o \
fsclient.o \
inode.o \
main.o \
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index 245257948140..c548aa346f0d 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -37,6 +37,13 @@ typedef enum {
AFS_FTYPE_SYMLINK = 3,
} afs_file_type_t;
+typedef enum {
+ AFS_LOCK_READ = 0, /* read lock request */
+ AFS_LOCK_WRITE = 1, /* write lock request */
+} afs_lock_type_t;
+
+#define AFS_LOCKWAIT (5 * 60) /* time until a lock times out (seconds) */
+
/*
* AFS file identifier
*/
@@ -120,6 +127,7 @@ struct afs_file_status {
struct afs_fid parent; /* parent dir ID for non-dirs only */
time_t mtime_client; /* last time client changed data */
time_t mtime_server; /* last time server changed data */
+ s32 lock_count; /* file lock count (0=UNLK -1=WRLCK +ve=#RDLCK */
};
/*
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index a18c374ebe08..eb647323d8f0 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -31,6 +31,9 @@ enum AFS_FS_Operations {
FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */
FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */
+ FSSETLOCK = 156, /* AFS Request a file lock */
+ FSEXTENDLOCK = 157, /* AFS Extend a file lock */
+ FSRELEASELOCK = 158, /* AFS Release a file lock */
FSLOOKUP = 161, /* AFS lookup file in directory */
FSFETCHDATA64 = 65537, /* AFS Fetch file data */
FSSTOREDATA64 = 65538, /* AFS Store file data */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index bacf518c6fa8..b8243945818d 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -125,6 +125,9 @@ static void afs_break_callback(struct afs_server *server,
spin_unlock(&server->cb_lock);
queue_work(afs_callback_update_worker, &vnode->cb_broken_work);
+ if (list_empty(&vnode->granted_locks) &&
+ !list_empty(&vnode->pending_locks))
+ afs_lock_may_be_available(vnode);
spin_unlock(&vnode->lock);
}
}
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 546c59522eb1..33fe39ad4e03 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -44,6 +44,7 @@ const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
.release = afs_release,
.readdir = afs_readdir,
+ .lock = afs_lock,
};
const struct inode_operations afs_dir_inode_operations = {
diff --git a/fs/afs/file.c b/fs/afs/file.c
index aede7eb66dd4..525f7c56e068 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -34,6 +34,8 @@ const struct file_operations afs_file_operations = {
.mmap = generic_file_readonly_mmap,
.splice_read = generic_file_splice_read,
.fsync = afs_fsync,
+ .lock = afs_lock,
+ .flock = afs_flock,
};
const struct inode_operations afs_file_inode_operations = {
diff --git a/fs/afs/flock.c b/fs/afs/flock.c
new file mode 100644
index 000000000000..4f77f3caee97
--- /dev/null
+++ b/fs/afs/flock.c
@@ -0,0 +1,559 @@
+/* AFS file locking support
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/smp_lock.h>
+#include "internal.h"
+
+#define AFS_LOCK_GRANTED 0
+#define AFS_LOCK_PENDING 1
+
+static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl);
+static void afs_fl_release_private(struct file_lock *fl);
+
+static struct workqueue_struct *afs_lock_manager;
+
+static struct file_lock_operations afs_lock_ops = {
+ .fl_copy_lock = afs_fl_copy_lock,
+ .fl_release_private = afs_fl_release_private,
+};
+
+/*
+ * initialise the lock manager thread if it isn't already running
+ */
+static int afs_init_lock_manager(void)
+{
+ if (!afs_lock_manager) {
+ afs_lock_manager = create_singlethread_workqueue("kafs_lockd");
+ if (!afs_lock_manager)
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ * destroy the lock manager thread if it's running
+ */
+void __exit afs_kill_lock_manager(void)
+{
+ if (afs_lock_manager)
+ destroy_workqueue(afs_lock_manager);
+}
+
+/*
+ * if the callback is broken on this vnode, then the lock may now be available
+ */
+void afs_lock_may_be_available(struct afs_vnode *vnode)
+{
+ _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+
+ queue_delayed_work(afs_lock_manager, &vnode->lock_work, 0);
+}
+
+/*
+ * the lock will time out in 5 minutes unless we extend it, so schedule
+ * extension in a bit less than that time
+ */
+static void afs_schedule_lock_extension(struct afs_vnode *vnode)
+{
+ queue_delayed_work(afs_lock_manager, &vnode->lock_work,
+ AFS_LOCKWAIT * HZ / 2);
+}
+
+/*
+ * do work for a lock, including:
+ * - probing for a lock we're waiting on but didn't get immediately
+ * - extending a lock that's close to timing out
+ */
+void afs_lock_work(struct work_struct *work)
+{
+ struct afs_vnode *vnode =
+ container_of(work, struct afs_vnode, lock_work.work);
+ struct file_lock *fl;
+ afs_lock_type_t type;
+ struct key *key;
+ int ret;
+
+ _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+
+ spin_lock(&vnode->lock);
+
+ if (test_bit(AFS_VNODE_UNLOCKING, &vnode->flags)) {
+ _debug("unlock");
+ spin_unlock(&vnode->lock);
+
+ /* attempt to release the server lock; if it fails, we just
+ * wait 5 minutes and it'll time out anyway */
+ ret = afs_vnode_release_lock(vnode, vnode->unlock_key);
+ if (ret < 0)
+ printk(KERN_WARNING "AFS:"
+ " Failed to release lock on {%x:%x} error %d\n",
+ vnode->fid.vid, vnode->fid.vnode, ret);
+
+ spin_lock(&vnode->lock);
+ key_put(vnode->unlock_key);
+ vnode->unlock_key = NULL;
+ clear_bit(AFS_VNODE_UNLOCKING, &vnode->flags);
+ }
+
+ /* if we've got a lock, then it must be time to extend that lock as AFS
+ * locks time out after 5 minutes */
+ if (!list_empty(&vnode->granted_locks)) {
+ _debug("extend");
+
+ if (test_and_set_bit(AFS_VNODE_LOCKING, &vnode->flags))
+ BUG();
+ fl = list_entry(vnode->granted_locks.next,
+ struct file_lock, fl_u.afs.link);
+ key = key_get(fl->fl_file->private_data);
+ spin_unlock(&vnode->lock);
+
+ ret = afs_vnode_extend_lock(vnode, key);
+ clear_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ key_put(key);
+ switch (ret) {
+ case 0:
+ afs_schedule_lock_extension(vnode);
+ break;
+ default:
+ /* ummm... we failed to extend the lock - retry
+ * extension shortly */
+ printk(KERN_WARNING "AFS:"
+ " Failed to extend lock on {%x:%x} error %d\n",
+ vnode->fid.vid, vnode->fid.vnode, ret);
+ queue_delayed_work(afs_lock_manager, &vnode->lock_work,
+ HZ * 10);
+ break;
+ }
+ _leave(" [extend]");
+ return;
+ }
+
+ /* if we don't have a granted lock, then we must've been called back by
+ * the server, and so if might be possible to get a lock we're
+ * currently waiting for */
+ if (!list_empty(&vnode->pending_locks)) {
+ _debug("get");
+
+ if (test_and_set_bit(AFS_VNODE_LOCKING, &vnode->flags))
+ BUG();
+ fl = list_entry(vnode->pending_locks.next,
+ struct file_lock, fl_u.afs.link);
+ key = key_get(fl->fl_file->private_data);
+ type = (fl->fl_type == F_RDLCK) ?
+ AFS_LOCK_READ : AFS_LOCK_WRITE;
+ spin_unlock(&vnode->lock);
+
+ ret = afs_vnode_set_lock(vnode, key, type);
+ clear_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ switch (ret) {
+ case -EWOULDBLOCK:
+ _debug("blocked");
+ break;
+ case 0:
+ _debug("acquired");
+ if (type == AFS_LOCK_READ)
+ set_bit(AFS_VNODE_READLOCKED, &vnode->flags);
+ else
+ set_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);
+ ret = AFS_LOCK_GRANTED;
+ default:
+ spin_lock(&vnode->lock);
+ /* the pending lock may have been withdrawn due to a
+ * signal */
+ if (list_entry(vnode->pending_locks.next,
+ struct file_lock, fl_u.afs.link) == fl) {
+ fl->fl_u.afs.state = ret;
+ if (ret == AFS_LOCK_GRANTED)
+ list_move_tail(&fl->fl_u.afs.link,
+ &vnode->granted_locks);
+ else
+ list_del_init(&fl->fl_u.afs.link);
+ wake_up(&fl->fl_wait);
+ spin_unlock(&vnode->lock);
+ } else {
+ _debug("withdrawn");
+ clear_bit(AFS_VNODE_READLOCKED, &vnode->flags);
+ clear_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);
+ spin_unlock(&vnode->lock);
+ afs_vnode_release_lock(vnode, key);
+ if (!list_empty(&vnode->pending_locks))
+ afs_lock_may_be_available(vnode);
+ }
+ break;
+ }
+ key_put(key);
+ _leave(" [pend]");
+ return;
+ }
+
+ /* looks like the lock request was withdrawn on a signal */
+ spin_unlock(&vnode->lock);
+ _leave(" [no locks]");
+}
+
+/*
+ * pass responsibility for the unlocking of a vnode on the server to the
+ * manager thread, lest a pending signal in the calling thread interrupt
+ * AF_RXRPC
+ * - the caller must hold the vnode lock
+ */
+static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key)
+{
+ cancel_delayed_work(&vnode->lock_work);
+ if (!test_and_clear_bit(AFS_VNODE_READLOCKED, &vnode->flags) &&
+ !test_and_clear_bit(AFS_VNODE_WRITELOCKED, &vnode->flags))
+ BUG();
+ if (test_and_set_bit(AFS_VNODE_UNLOCKING, &vnode->flags))
+ BUG();
+ vnode->unlock_key = key_get(key);
+ afs_lock_may_be_available(vnode);
+}
+
+/*
+ * request a lock on a file on the server
+ */
+static int afs_do_setlk(struct file *file, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+ afs_lock_type_t type;
+ struct key *key = file->private_data;
+ int ret;
+
+ _enter("{%x:%u},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
+
+ /* only whole-file locks are supported */
+ if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
+ return -EINVAL;
+
+ ret = afs_init_lock_manager();
+ if (ret < 0)
+ return ret;
+
+ fl->fl_ops = &afs_lock_ops;
+ INIT_LIST_HEAD(&fl->fl_u.afs.link);
+ fl->fl_u.afs.state = AFS_LOCK_PENDING;
+
+ type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE;
+
+ lock_kernel();
+
+ /* make sure we've got a callback on this file and that our view of the
+ * data version is up to date */
+ ret = afs_vnode_fetch_status(vnode, NULL, key);
+ if (ret < 0)
+ goto error;
+
+ if (vnode->status.lock_count != 0 && !(fl->fl_flags & FL_SLEEP)) {
+ ret = -EAGAIN;
+ goto error;
+ }
+
+ spin_lock(&vnode->lock);
+
+ if (list_empty(&vnode->pending_locks)) {
+ /* if there's no-one else with a lock on this vnode, then we
+ * need to ask the server for a lock */
+ if (list_empty(&vnode->granted_locks)) {
+ _debug("not locked");
+ ASSERTCMP(vnode->flags &
+ ((1 << AFS_VNODE_LOCKING) |
+ (1 << AFS_VNODE_READLOCKED) |
+ (1 << AFS_VNODE_WRITELOCKED)), ==, 0);
+ list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
+ set_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ spin_unlock(&vnode->lock);
+
+ ret = afs_vnode_set_lock(vnode, key, type);
+ clear_bit(AFS_VNODE_LOCKING, &vnode->flags);
+ switch (ret) {
+ case 0:
+ goto acquired_server_lock;
+ case -EWOULDBLOCK:
+ spin_lock(&vnode->lock);
+ ASSERT(list_empty(&vnode->granted_locks));
+ ASSERTCMP(vnode->pending_locks.next, ==,
+ &fl->fl_u.afs.link);
+ goto wait;
+ default:
+ spin_lock(&vnode->lock);
+ list_del_init(&fl->fl_u.afs.link);
+ spin_unlock(&vnode->lock);
+ goto error;
+ }
+ }
+
+ /* if we've already got a readlock on the server and no waiting
+ * writelocks, then we might be able to instantly grant another
+ * readlock */
+ if (type == AFS_LOCK_READ &&
+ vnode->flags & (1 << AFS_VNODE_READLOCKED)) {
+ _debug("instant readlock");
+ ASSERTCMP(vnode->flags &
+ ((1 << AFS_VNODE_LOCKING) |
+ (1 << AFS_VNODE_WRITELOCKED)), ==, 0);
+ ASSERT(!list_empty(&vnode->granted_locks));
+ goto sharing_existing_lock;
+ }
+ }
+
+ /* otherwise, we need to wait for a local lock to become available */
+ _debug("wait local");
+ list_add_tail(&fl->fl_u.afs.link, &vnode->pending_locks);
+wait:
+ if (!(fl->fl_flags & FL_SLEEP)) {
+ _debug("noblock");
+ ret = -EAGAIN;
+ goto abort_attempt;
+ }
+ spin_unlock(&vnode->lock);
+
+ /* now we need to sleep and wait for the lock manager thread to get the
+ * lock from the server */
+ _debug("sleep");
+ ret = wait_event_interruptible(fl->fl_wait,
+ fl->fl_u.afs.state <= AFS_LOCK_GRANTED);
+ if (fl->fl_u.afs.state <= AFS_LOCK_GRANTED) {
+ ret = fl->fl_u.afs.state;
+ if (ret < 0)
+ goto error;
+ spin_lock(&vnode->lock);
+ goto given_lock;
+ }
+
+ /* we were interrupted, but someone may still be in the throes of
+ * giving us the lock */
+ _debug("intr");
+ ASSERTCMP(ret, ==, -ERESTARTSYS);
+
+ spin_lock(&vnode->lock);
+ if (fl->fl_u.afs.state <= AFS_LOCK_GRANTED) {
+ ret = fl->fl_u.afs.state;
+ if (ret < 0) {
+ spin_unlock(&vnode->lock);
+ goto error;
+ }
+ goto given_lock;
+ }
+
+abort_attempt:
+ /* we aren't going to get the lock, either because we're unwilling to
+ * wait, or because some signal happened */
+ _debug("abort");
+ if (list_empty(&vnode->granted_locks) &&
+ vnode->pending_locks.next == &fl->fl_u.afs.link) {
+ if (vnode->pending_locks.prev != &fl->fl_u.afs.link) {
+ /* kick the next pending lock into having a go */
+ list_del_init(&fl->fl_u.afs.link);
+ afs_lock_may_be_available(vnode);
+ }
+ } else {
+ list_del_init(&fl->fl_u.afs.link);
+ }
+ spin_unlock(&vnode->lock);
+ goto error;
+
+acquired_server_lock:
+ /* we've acquired a server lock, but it needs to be renewed after 5
+ * mins */
+ spin_lock(&vnode->lock);
+ afs_schedule_lock_extension(vnode);
+ if (type == AFS_LOCK_READ)
+ set_bit(AFS_VNODE_READLOCKED, &vnode->flags);
+ else
+ set_bit(AFS_VNODE_WRITELOCKED, &vnode->flags);
+sharing_existing_lock:
+ /* the lock has been granted as far as we're concerned... */
+ fl->fl_u.afs.state = AFS_LOCK_GRANTED;
+ list_move_tail(&fl->fl_u.afs.link, &vnode->granted_locks);
+given_lock:
+ /* ... but we do still need to get the VFS's blessing */
+ ASSERT(!(vnode->flags & (1 << AFS_VNODE_LOCKING)));
+ ASSERT((vnode->flags & ((1 << AFS_VNODE_READLOCKED) |
+ (1 << AFS_VNODE_WRITELOCKED))) != 0);
+ ret = posix_lock_file(file, fl, NULL);
+ if (ret < 0)
+ goto vfs_rejected_lock;
+ spin_unlock(&vnode->lock);
+
+ /* again, make sure we've got a callback on this file and, again, make
+ * sure that our view of the data version is up to date (we ignore
+ * errors incurred here and deal with the consequences elsewhere) */
+ afs_vnode_fetch_status(vnode, NULL, key);
+
+error:
+ unlock_kernel();
+ _leave(" = %d", ret);
+ return ret;
+
+vfs_rejected_lock:
+ /* the VFS rejected the lock we just obtained, so we have to discard
+ * what we just got */
+ _debug("vfs refused %d", ret);
+ list_del_init(&fl->fl_u.afs.link);
+ if (list_empty(&vnode->granted_locks))
+ afs_defer_unlock(vnode, key);
+ spin_unlock(&vnode->lock);
+ goto abort_attempt;
+}
+
+/*
+ * unlock on a file on the server
+ */
+static int afs_do_unlk(struct file *file, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+ struct key *key = file->private_data;
+ int ret;
+
+ _enter("{%x:%u},%u", vnode->fid.vid, vnode->fid.vnode, fl->fl_type);
+
+ /* only whole-file unlocks are supported */
+ if (fl->fl_start != 0 || fl->fl_end != OFFSET_MAX)
+ return -EINVAL;
+
+ fl->fl_ops = &afs_lock_ops;
+ INIT_LIST_HEAD(&fl->fl_u.afs.link);
+ fl->fl_u.afs.state = AFS_LOCK_PENDING;
+
+ spin_lock(&vnode->lock);
+ ret = posix_lock_file(file, fl, NULL);
+ if (ret < 0) {
+ spin_unlock(&vnode->lock);
+ _leave(" = %d [vfs]", ret);
+ return ret;
+ }
+
+ /* discard the server lock only if all granted locks are gone */
+ if (list_empty(&vnode->granted_locks))
+ afs_defer_unlock(vnode, key);
+ spin_unlock(&vnode->lock);
+ _leave(" = 0");
+ return 0;
+}
+
+/*
+ * return information about a lock we currently hold, if indeed we hold one
+ */
+static int afs_do_getlk(struct file *file, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host);
+ struct key *key = file->private_data;
+ int ret, lock_count;
+
+ _enter("");
+
+ fl->fl_type = F_UNLCK;
+
+ mutex_lock(&vnode->vfs_inode.i_mutex);
+
+ /* check local lock records first */
+ ret = 0;
+ posix_test_lock(file, fl);
+ if (fl->fl_type == F_UNLCK) {
+ /* no local locks; consult the server */
+ ret = afs_vnode_fetch_status(vnode, NULL, key);
+ if (ret < 0)
+ goto error;
+ lock_count = vnode->status.lock_count;
+ if (lock_count) {
+ if (lock_count > 0)
+ fl->fl_type = F_RDLCK;
+ else
+ fl->fl_type = F_WRLCK;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+ }
+ }
+
+error:
+ mutex_unlock(&vnode->vfs_inode.i_mutex);
+ _leave(" = %d [%hd]", ret, fl->fl_type);
+ return ret;
+}
+
+/*
+ * manage POSIX locks on a file
+ */
+int afs_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+
+ _enter("{%x:%u},%d,{t=%x,fl=%x,r=%Ld:%Ld}",
+ vnode->fid.vid, vnode->fid.vnode, cmd,
+ fl->fl_type, fl->fl_flags,
+ (long long) fl->fl_start, (long long) fl->fl_end);
+
+ /* AFS doesn't support mandatory locks */
+ if ((vnode->vfs_inode.i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
+ fl->fl_type != F_UNLCK)
+ return -ENOLCK;
+
+ if (IS_GETLK(cmd))
+ return afs_do_getlk(file, fl);
+ if (fl->fl_type == F_UNLCK)
+ return afs_do_unlk(file, fl);
+ return afs_do_setlk(file, fl);
+}
+
+/*
+ * manage FLOCK locks on a file
+ */
+int afs_flock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+
+ _enter("{%x:%u},%d,{t=%x,fl=%x}",
+ vnode->fid.vid, vnode->fid.vnode, cmd,
+ fl->fl_type, fl->fl_flags);
+
+ /*
+ * No BSD flocks over NFS allowed.
+ * Note: we could try to fake a POSIX lock request here by
+ * using ((u32) filp | 0x80000000) or some such as the pid.
+ * Not sure whether that would be unique, though, or whether
+ * that would break in other places.
+ */
+ if (!(fl->fl_flags & FL_FLOCK))
+ return -ENOLCK;
+
+ /* we're simulating flock() locks using posix locks on the server */
+ fl->fl_owner = (fl_owner_t) file;
+ fl->fl_start = 0;
+ fl->fl_end = OFFSET_MAX;
+
+ if (fl->fl_type == F_UNLCK)
+ return afs_do_unlk(file, fl);
+ return afs_do_setlk(file, fl);
+}
+
+/*
+ * the POSIX lock management core VFS code copies the lock record and adds the
+ * copy into its own list, so we need to add that copy to the vnode's lock
+ * queue in the same place as the original (which will be deleted shortly
+ * after)
+ */
+static void afs_fl_copy_lock(struct file_lock *new, struct file_lock *fl)
+{
+ _enter("");
+
+ list_add(&new->fl_u.afs.link, &fl->fl_u.afs.link);
+}
+
+/*
+ * need to remove this lock from the vnode queue when it's removed from the
+ * VFS's list
+ */
+static void afs_fl_release_private(struct file_lock *fl)
+{
+ _enter("");
+
+ list_del_init(&fl->fl_u.afs.link);
+}
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 5dff1308b6f0..023b95b0d9d7 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -67,7 +67,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,
EXTRACT(status->group);
bp++; /* sync counter */
data_version |= (u64) ntohl(*bp++) << 32;
- bp++; /* lock count */
+ EXTRACT(status->lock_count);
size |= (u64) ntohl(*bp++) << 32;
bp++; /* spare 4 */
*_bp = bp;
@@ -1748,3 +1748,156 @@ int afs_fs_get_volume_status(struct afs_server *server,
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
}
+
+/*
+ * deliver reply data to an FS.SetLock, FS.ExtendLock or FS.ReleaseLock
+ */
+static int afs_deliver_fs_xxxx_lock(struct afs_call *call,
+ struct sk_buff *skb, bool last)
+{
+ const __be32 *bp;
+
+ _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+ afs_transfer_reply(call, skb);
+ if (!last)
+ return 0;
+
+ if (call->reply_size != call->reply_max)
+ return -EBADMSG;
+
+ /* unmarshall the reply once we've received all of it */
+ bp = call->buffer;
+ /* xdr_decode_AFSVolSync(&bp, call->replyX); */
+
+ _leave(" = 0 [done]");
+ return 0;
+}
+
+/*
+ * FS.SetLock operation type
+ */
+static const struct afs_call_type afs_RXFSSetLock = {
+ .name = "FS.SetLock",
+ .deliver = afs_deliver_fs_xxxx_lock,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * FS.ExtendLock operation type
+ */
+static const struct afs_call_type afs_RXFSExtendLock = {
+ .name = "FS.ExtendLock",
+ .deliver = afs_deliver_fs_xxxx_lock,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * FS.ReleaseLock operation type
+ */
+static const struct afs_call_type afs_RXFSReleaseLock = {
+ .name = "FS.ReleaseLock",
+ .deliver = afs_deliver_fs_xxxx_lock,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * get a lock on a file
+ */
+int afs_fs_set_lock(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ afs_lock_type_t type,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ call = afs_alloc_flat_call(&afs_RXFSSetLock, 5 * 4, 6 * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSSETLOCK);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+ *bp++ = htonl(type);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * extend a lock on a file
+ */
+int afs_fs_extend_lock(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ call = afs_alloc_flat_call(&afs_RXFSExtendLock, 4 * 4, 6 * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSEXTENDLOCK);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
+/*
+ * release a lock on a file
+ */
+int afs_fs_release_lock(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ call = afs_alloc_flat_call(&afs_RXFSReleaseLock, 4 * 4, 6 * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSRELEASELOCK);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 2c55dd94a1de..6306438f331f 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -351,10 +351,18 @@ struct afs_vnode {
#define AFS_VNODE_ZAP_DATA 3 /* set if vnode's data should be invalidated */
#define AFS_VNODE_DELETED 4 /* set if vnode deleted on server */
#define AFS_VNODE_MOUNTPOINT 5 /* set if vnode is a mountpoint symlink */
+#define AFS_VNODE_LOCKING 6 /* set if waiting for lock on vnode */
+#define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */
+#define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */
+#define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */
long acl_order; /* ACL check count (callback break count) */
struct list_head writebacks; /* alterations in pagecache that need writing */
+ struct list_head pending_locks; /* locks waiting to be granted */
+ struct list_head granted_locks; /* locks granted on this file */
+ struct delayed_work lock_work; /* work to be done in locking */
+ struct key *unlock_key; /* key to be used in unlocking */
/* outstanding callback notification on this file */
struct rb_node server_rb; /* link in server->fs_vnodes */
@@ -474,6 +482,15 @@ extern int afs_open(struct inode *, struct file *);
extern int afs_release(struct inode *, struct file *);
/*
+ * flock.c
+ */
+extern void __exit afs_kill_lock_manager(void);
+extern void afs_lock_work(struct work_struct *);
+extern void afs_lock_may_be_available(struct afs_vnode *);
+extern int afs_lock(struct file *, int, struct file_lock *);
+extern int afs_flock(struct file *, int, struct file_lock *);
+
+/*
* fsclient.c
*/
extern int afs_fs_fetch_file_status(struct afs_server *, struct key *,
@@ -513,6 +530,15 @@ extern int afs_fs_get_volume_status(struct afs_server *, struct key *,
struct afs_vnode *,
struct afs_volume_status *,
const struct afs_wait_mode *);
+extern int afs_fs_set_lock(struct afs_server *, struct key *,
+ struct afs_vnode *, afs_lock_type_t,
+ const struct afs_wait_mode *);
+extern int afs_fs_extend_lock(struct afs_server *, struct key *,
+ struct afs_vnode *,
+ const struct afs_wait_mode *);
+extern int afs_fs_release_lock(struct afs_server *, struct key *,
+ struct afs_vnode *,
+ const struct afs_wait_mode *);
/*
* inode.c
@@ -681,6 +707,10 @@ extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *,
struct afs_volume_status *);
+extern int afs_vnode_set_lock(struct afs_vnode *, struct key *,
+ afs_lock_type_t);
+extern int afs_vnode_extend_lock(struct afs_vnode *, struct key *);
+extern int afs_vnode_release_lock(struct afs_vnode *, struct key *);
/*
* volume.c
diff --git a/fs/afs/main.c b/fs/afs/main.c
index cd21195bbb24..0f60f6b35769 100644
--- a/fs/afs/main.c
+++ b/fs/afs/main.c
@@ -168,6 +168,7 @@ static void __exit afs_exit(void)
printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
afs_fs_exit();
+ afs_kill_lock_manager();
afs_close_socket();
afs_purge_servers();
afs_callback_update_kill();
diff --git a/fs/afs/misc.c b/fs/afs/misc.c
index d1a889c40742..2d33a5f7d218 100644
--- a/fs/afs/misc.c
+++ b/fs/afs/misc.c
@@ -35,6 +35,7 @@ int afs_abort_to_error(u32 abort_code)
case VOVERQUOTA: return -EDQUOT;
case VBUSY: return -EBUSY;
case VMOVED: return -ENXIO;
+ case 0x2f6df0a: return -EWOULDBLOCK;
case 0x2f6df0c: return -EACCES;
case 0x2f6df0f: return -EBUSY;
case 0x2f6df10: return -EEXIST;
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 13df512aea9e..6edb56683b9a 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -201,23 +201,9 @@ static int afs_proc_cells_open(struct inode *inode, struct file *file)
*/
static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
/* lock the list against modification */
down_read(&afs_proc_cells_sem);
-
- /* allow for the header line */
- if (!pos)
- return (void *) 1;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &afs_proc_cells)
- if (!pos--)
- break;
-
- return _p != &afs_proc_cells ? _p : NULL;
+ return seq_list_start_head(&afs_proc_cells, *_pos);
}
/*
@@ -225,14 +211,7 @@ static void *afs_proc_cells_start(struct seq_file *m, loff_t *_pos)
*/
static void *afs_proc_cells_next(struct seq_file *p, void *v, loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = v == (void *) 1 ? afs_proc_cells.next : _p->next;
-
- return _p != &afs_proc_cells ? _p : NULL;
+ return seq_list_next(v, &afs_proc_cells, pos);
}
/*
@@ -250,7 +229,7 @@ static int afs_proc_cells_show(struct seq_file *m, void *v)
{
struct afs_cell *cell = list_entry(v, struct afs_cell, proc_link);
- if (v == (void *) 1) {
+ if (v == &afs_proc_cells) {
/* display header on line 1 */
seq_puts(m, "USE NAME\n");
return 0;
@@ -503,26 +482,13 @@ static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
*/
static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
struct afs_cell *cell = m->private;
- loff_t pos = *_pos;
_enter("cell=%p pos=%Ld", cell, *_pos);
/* lock the list against modification */
down_read(&cell->vl_sem);
-
- /* allow for the header line */
- if (!pos)
- return (void *) 1;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &cell->vl_list)
- if (!pos--)
- break;
-
- return _p != &cell->vl_list ? _p : NULL;
+ return seq_list_start_head(&cell->vl_list, *_pos);
}
/*
@@ -531,17 +497,10 @@ static void *afs_proc_cell_volumes_start(struct seq_file *m, loff_t *_pos)
static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
loff_t *_pos)
{
- struct list_head *_p;
struct afs_cell *cell = p->private;
_enter("cell=%p pos=%Ld", cell, *_pos);
-
- (*_pos)++;
-
- _p = v;
- _p = (v == (void *) 1) ? cell->vl_list.next : _p->next;
-
- return (_p != &cell->vl_list) ? _p : NULL;
+ return seq_list_next(v, &cell->vl_list, _pos);
}
/*
@@ -569,11 +528,12 @@ const char afs_vlocation_states[][4] = {
*/
static int afs_proc_cell_volumes_show(struct seq_file *m, void *v)
{
+ struct afs_cell *cell = m->private;
struct afs_vlocation *vlocation =
list_entry(v, struct afs_vlocation, link);
/* display header on line 1 */
- if (v == (void *) 1) {
+ if (v == &cell->vl_list) {
seq_puts(m, "USE STT VLID[0] VLID[1] VLID[2] NAME\n");
return 0;
}
@@ -734,26 +694,13 @@ static int afs_proc_cell_servers_release(struct inode *inode,
static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
__acquires(m->private->servers_lock)
{
- struct list_head *_p;
struct afs_cell *cell = m->private;
- loff_t pos = *_pos;
_enter("cell=%p pos=%Ld", cell, *_pos);
/* lock the list against modification */
read_lock(&cell->servers_lock);
-
- /* allow for the header line */
- if (!pos)
- return (void *) 1;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &cell->servers)
- if (!pos--)
- break;
-
- return _p != &cell->servers ? _p : NULL;
+ return seq_list_start_head(&cell->servers, *_pos);
}
/*
@@ -762,17 +709,10 @@ static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
loff_t *_pos)
{
- struct list_head *_p;
struct afs_cell *cell = p->private;
_enter("cell=%p pos=%Ld", cell, *_pos);
-
- (*_pos)++;
-
- _p = v;
- _p = v == (void *) 1 ? cell->servers.next : _p->next;
-
- return _p != &cell->servers ? _p : NULL;
+ return seq_list_next(v, &cell->servers, _pos);
}
/*
@@ -791,11 +731,12 @@ static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
*/
static int afs_proc_cell_servers_show(struct seq_file *m, void *v)
{
+ struct afs_cell *cell = m->private;
struct afs_server *server = list_entry(v, struct afs_server, link);
char ipaddr[20];
/* display header on line 1 */
- if (v == (void *) 1) {
+ if (v == &cell->servers) {
seq_puts(m, "USE ADDR STATE\n");
return 0;
}
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 1b36f45076ad..8ccee9ee1d9d 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -792,6 +792,7 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
{
struct msghdr msg;
struct iovec iov[1];
+ int n;
_enter("");
@@ -806,22 +807,20 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)
msg.msg_flags = 0;
call->state = AFS_CALL_AWAIT_ACK;
- switch (rxrpc_kernel_send_data(call->rxcall, &msg, len)) {
- case 0:
+ n = rxrpc_kernel_send_data(call->rxcall, &msg, len);
+ if (n >= 0) {
_leave(" [replied]");
return;
-
- case -ENOMEM:
+ }
+ if (n == -ENOMEM) {
_debug("oom");
rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);
- default:
- rxrpc_kernel_end_call(call->rxcall);
- call->rxcall = NULL;
- call->type->destructor(call);
- afs_free_call(call);
- _leave(" [error]");
- return;
}
+ rxrpc_kernel_end_call(call->rxcall);
+ call->rxcall = NULL;
+ call->type->destructor(call);
+ afs_free_call(call);
+ _leave(" [error]");
}
/*
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 2e8496ba1205..b8808b40f82b 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -89,8 +89,7 @@ int __init afs_fs_init(void)
sizeof(struct afs_vnode),
0,
SLAB_HWCACHE_ALIGN,
- afs_i_init_once,
- NULL);
+ afs_i_init_once);
if (!afs_inode_cachep) {
printk(KERN_NOTICE "kAFS: Failed to allocate inode cache\n");
return ret;
@@ -460,6 +459,9 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
spin_lock_init(&vnode->writeback_lock);
spin_lock_init(&vnode->lock);
INIT_LIST_HEAD(&vnode->writebacks);
+ INIT_LIST_HEAD(&vnode->pending_locks);
+ INIT_LIST_HEAD(&vnode->granted_locks);
+ INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
}
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index 232c55dc245d..2f05c4fc2a70 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -561,7 +561,7 @@ no_server:
/*
* create a hard link
*/
-extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
+int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode,
struct key *key, const char *name)
{
struct afs_server *server;
@@ -887,11 +887,6 @@ int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
vnode->fid.unique,
key_serial(key));
- /* this op will fetch the status */
- spin_lock(&vnode->lock);
- vnode->update_cnt++;
- spin_unlock(&vnode->lock);
-
do {
/* pick a server to query */
server = afs_volume_pick_fileserver(vnode);
@@ -905,20 +900,127 @@ int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
} while (!afs_volume_release_fileserver(vnode, server, ret));
/* adjust the flags */
- if (ret == 0) {
- afs_vnode_finalise_status_update(vnode, server);
+ if (ret == 0)
+ afs_put_server(server);
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ return PTR_ERR(server);
+}
+
+/*
+ * get a lock on a file
+ */
+int afs_vnode_set_lock(struct afs_vnode *vnode, struct key *key,
+ afs_lock_type_t type)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x,%u",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key), type);
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_set_lock(server, key, vnode, type, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0)
+ afs_put_server(server);
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ return PTR_ERR(server);
+}
+
+/*
+ * extend a lock on a file
+ */
+int afs_vnode_extend_lock(struct afs_vnode *vnode, struct key *key)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key));
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_extend_lock(server, key, vnode, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0)
+ afs_put_server(server);
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ return PTR_ERR(server);
+}
+
+/*
+ * release a lock on a file
+ */
+int afs_vnode_release_lock(struct afs_vnode *vnode, struct key *key)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key));
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_release_lock(server, key, vnode, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0)
afs_put_server(server);
- } else {
- afs_vnode_status_update_failed(vnode, ret);
- }
_leave(" = %d", ret);
return ret;
no_server:
- spin_lock(&vnode->lock);
- vnode->update_cnt--;
- ASSERTCMP(vnode->update_cnt, >=, 0);
- spin_unlock(&vnode->lock);
return PTR_ERR(server);
}
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index 40fe3a3222e4..b4a75880f6fd 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -53,7 +53,7 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
};
/**
- * anon_inode_getfd - creates a new file instance by hooking it up to and
+ * anon_inode_getfd - creates a new file instance by hooking it up to an
* anonymous inode, and a dentry that describe the "class"
* of the file
*
@@ -66,7 +66,7 @@ static struct dentry_operations anon_inodefs_dentry_operations = {
*
* Creates a new file by hooking it on a single inode. This is useful for files
* that do not need to have a full-fledged inode in order to operate correctly.
- * All the files created with anon_inode_getfd() will share a single inode, by
+ * All the files created with anon_inode_getfd() will share a single inode,
* hence saving memory and avoiding code duplication for the file/inode/dentry
* setup.
*/
@@ -139,11 +139,12 @@ err_put_filp:
put_filp(file);
return error;
}
+EXPORT_SYMBOL_GPL(anon_inode_getfd);
/*
- * A single inode exist for all anon_inode files. Contrary to pipes,
- * anon_inode inodes has no per-instance data associated, so we can avoid
- * the allocation of multiple of them.
+ * A single inode exists for all anon_inode files. Contrary to pipes,
+ * anon_inode inodes have no associated per-instance data, so we need
+ * only allocate one of them.
*/
static struct inode *anon_inode_mkinode(void)
{
diff --git a/fs/attr.c b/fs/attr.c
index a0a0c7b07ba3..f8dfc2269d85 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -42,7 +42,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
/* Make sure a caller can chmod. */
if (ia_valid & ATTR_MODE) {
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
goto error;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
@@ -52,7 +52,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr)
/* Check for setting the inode time. */
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
- if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
goto error;
}
fine:
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index a5c5171c2828..a45141827681 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -414,7 +414,7 @@ befs_read_inode(struct inode *inode)
}
/* Initialize the inode cache. Called at fs setup.
- *
+ *
* Taken from NFS implementation by Al Viro.
*/
static int
@@ -424,7 +424,7 @@ befs_init_inodecache(void)
sizeof (struct befs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (befs_inode_cachep == NULL) {
printk(KERN_ERR "befs_init_inodecache: "
"Couldn't initalize inode slabcache\n");
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index 58c7bd9f5301..f346eb14e86f 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -250,14 +250,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&bi->vfs_inode);
}
-
+
static int init_inodecache(void)
{
bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
sizeof(struct bfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (bfs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 08e4414b8374..4482a0673b15 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -148,6 +148,7 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
elf_addr_t *elf_info;
int ei_index = 0;
struct task_struct *tsk = current;
+ struct vm_area_struct *vma;
/*
* If this architecture has a platform capability string, copy it
@@ -234,6 +235,15 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
sp = (elf_addr_t __user *)bprm->p;
#endif
+
+ /*
+ * Grow the stack manually; some architectures have a limit on how
+ * far ahead a user-space access may be in order to grow the stack.
+ */
+ vma = find_extend_vma(current->mm, bprm->p);
+ if (!vma)
+ return -EFAULT;
+
/* Now, let's put argc (and argv, envp if appropriate) on the stack */
if (__put_user(argc, sp++))
return -EFAULT;
@@ -254,8 +264,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
size_t len;
if (__put_user((elf_addr_t)p, argv++))
return -EFAULT;
- len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
- if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+ len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
return 0;
p += len;
}
@@ -266,8 +276,8 @@ create_elf_tables(struct linux_binprm *bprm, struct elfhdr *exec,
size_t len;
if (__put_user((elf_addr_t)p, envp++))
return -EFAULT;
- len = strnlen_user((void __user *)p, PAGE_SIZE*MAX_ARG_PAGES);
- if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+ len = strnlen_user((void __user *)p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
return 0;
p += len;
}
@@ -777,10 +787,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
}
/* OK, This is the point of no return */
- current->mm->start_data = 0;
- current->mm->end_data = 0;
- current->mm->end_code = 0;
- current->mm->mmap = NULL;
current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags;
@@ -988,9 +994,13 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
compute_creds(bprm);
current->flags &= ~PF_FORKNOEXEC;
- create_elf_tables(bprm, &loc->elf_ex,
+ retval = create_elf_tables(bprm, &loc->elf_ex,
(interpreter_type == INTERPRETER_AOUT),
load_addr, interp_load_addr);
+ if (retval < 0) {
+ send_sig(SIGKILL, current, 0);
+ goto out;
+ }
/* N.B. passed_fileno might not be initialized? */
if (interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1;
@@ -1189,7 +1199,7 @@ static int dump_seek(struct file *file, loff_t off)
*
* I think we should skip something. But I am not sure how. H.J.
*/
-static int maydump(struct vm_area_struct *vma)
+static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
{
/* The vma can be set up to tell us the answer directly. */
if (vma->vm_flags & VM_ALWAYSDUMP)
@@ -1199,15 +1209,19 @@ static int maydump(struct vm_area_struct *vma)
if (vma->vm_flags & (VM_IO | VM_RESERVED))
return 0;
- /* Dump shared memory only if mapped from an anonymous file. */
- if (vma->vm_flags & VM_SHARED)
- return vma->vm_file->f_path.dentry->d_inode->i_nlink == 0;
+ /* By default, dump shared memory if mapped from an anonymous file. */
+ if (vma->vm_flags & VM_SHARED) {
+ if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0)
+ return test_bit(MMF_DUMP_ANON_SHARED, &mm_flags);
+ else
+ return test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags);
+ }
- /* If it hasn't been written to, don't write it out */
+ /* By default, if it hasn't been written to, don't write it out. */
if (!vma->anon_vma)
- return 0;
+ return test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags);
- return 1;
+ return test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags);
}
/* An ELF note in memory */
@@ -1499,6 +1513,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
#endif
int thread_status_size = 0;
elf_addr_t *auxv;
+ unsigned long mm_flags;
#ifdef ELF_CORE_WRITE_EXTRA_NOTES
int extra_notes_size;
#endif
@@ -1642,6 +1657,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+ /*
+ * We must use the same mm->flags while dumping core to avoid
+ * inconsistency between the program headers and bodies, otherwise an
+ * unusable core file can be generated.
+ */
+ mm_flags = current->mm->flags;
+
/* Write program headers for segments dump */
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
@@ -1654,7 +1676,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
phdr.p_offset = offset;
phdr.p_vaddr = vma->vm_start;
phdr.p_paddr = 0;
- phdr.p_filesz = maydump(vma) ? sz : 0;
+ phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0;
phdr.p_memsz = sz;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1698,7 +1720,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
vma = next_vma(vma, gate_vma)) {
unsigned long addr;
- if (!maydump(vma))
+ if (!maydump(vma, mm_flags))
continue;
for (addr = vma->vm_start;
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 9d62fbad3d4b..2f5d8dbe676d 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -621,8 +621,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
p = (char __user *) current->mm->arg_start;
for (loop = bprm->argc; loop > 0; loop--) {
__put_user((elf_caddr_t) p, argv++);
- len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
- if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
+ len = strnlen_user(p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
return -EINVAL;
p += len;
}
@@ -633,8 +633,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
current->mm->env_start = (unsigned long) p;
for (loop = bprm->envc; loop > 0; loop--) {
__put_user((elf_caddr_t)(unsigned long) p, envp++);
- len = strnlen_user(p, PAGE_SIZE * MAX_ARG_PAGES);
- if (!len || len > PAGE_SIZE * MAX_ARG_PAGES)
+ len = strnlen_user(p, MAX_ARG_STRLEN);
+ if (!len || len > MAX_ARG_STRLEN)
return -EINVAL;
p += len;
}
@@ -1181,8 +1181,10 @@ static int dump_seek(struct file *file, loff_t off)
*
* I think we should skip something. But I am not sure how. H.J.
*/
-static int maydump(struct vm_area_struct *vma)
+static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
{
+ int dump_ok;
+
/* Do not dump I/O mapped devices or special mappings */
if (vma->vm_flags & (VM_IO | VM_RESERVED)) {
kdcore("%08lx: %08lx: no (IO)", vma->vm_start, vma->vm_flags);
@@ -1197,27 +1199,35 @@ static int maydump(struct vm_area_struct *vma)
return 0;
}
- /* Dump shared memory only if mapped from an anonymous file. */
+ /* By default, dump shared memory if mapped from an anonymous file. */
if (vma->vm_flags & VM_SHARED) {
if (vma->vm_file->f_path.dentry->d_inode->i_nlink == 0) {
- kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags);
- return 1;
+ dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags);
+ kdcore("%08lx: %08lx: %s (share)", vma->vm_start,
+ vma->vm_flags, dump_ok ? "yes" : "no");
+ return dump_ok;
}
- kdcore("%08lx: %08lx: no (share)", vma->vm_start, vma->vm_flags);
- return 0;
+ dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags);
+ kdcore("%08lx: %08lx: %s (share)", vma->vm_start,
+ vma->vm_flags, dump_ok ? "yes" : "no");
+ return dump_ok;
}
#ifdef CONFIG_MMU
- /* If it hasn't been written to, don't write it out */
+ /* By default, if it hasn't been written to, don't write it out */
if (!vma->anon_vma) {
- kdcore("%08lx: %08lx: no (!anon)", vma->vm_start, vma->vm_flags);
- return 0;
+ dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags);
+ kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start,
+ vma->vm_flags, dump_ok ? "yes" : "no");
+ return dump_ok;
}
#endif
- kdcore("%08lx: %08lx: yes", vma->vm_start, vma->vm_flags);
- return 1;
+ dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags);
+ kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags,
+ dump_ok ? "yes" : "no");
+ return dump_ok;
}
/* An ELF note in memory */
@@ -1456,15 +1466,15 @@ static int elf_dump_thread_status(long signr, struct elf_thread_status *t)
* dump the segments for an MMU process
*/
#ifdef CONFIG_MMU
-static int elf_fdpic_dump_segments(struct file *file, struct mm_struct *mm,
- size_t *size, unsigned long *limit)
+static int elf_fdpic_dump_segments(struct file *file, size_t *size,
+ unsigned long *limit, unsigned long mm_flags)
{
struct vm_area_struct *vma;
for (vma = current->mm->mmap; vma; vma = vma->vm_next) {
unsigned long addr;
- if (!maydump(vma))
+ if (!maydump(vma, mm_flags))
continue;
for (addr = vma->vm_start;
@@ -1511,15 +1521,15 @@ end_coredump:
* dump the segments for a NOMMU process
*/
#ifndef CONFIG_MMU
-static int elf_fdpic_dump_segments(struct file *file, struct mm_struct *mm,
- size_t *size, unsigned long *limit)
+static int elf_fdpic_dump_segments(struct file *file, size_t *size,
+ unsigned long *limit, unsigned long mm_flags)
{
struct vm_list_struct *vml;
for (vml = current->mm->context.vmlist; vml; vml = vml->next) {
struct vm_area_struct *vma = vml->vma;
- if (!maydump(vma))
+ if (!maydump(vma, mm_flags))
continue;
if ((*size += PAGE_SIZE) > *limit)
@@ -1570,6 +1580,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
struct vm_list_struct *vml;
#endif
elf_addr_t *auxv;
+ unsigned long mm_flags;
/*
* We no longer stop all VM operations.
@@ -1707,6 +1718,13 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
/* Page-align dumped data */
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
+ /*
+ * We must use the same mm->flags while dumping core to avoid
+ * inconsistency between the program headers and bodies, otherwise an
+ * unusable core file can be generated.
+ */
+ mm_flags = current->mm->flags;
+
/* write program headers for segments dump */
for (
#ifdef CONFIG_MMU
@@ -1728,7 +1746,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
phdr.p_offset = offset;
phdr.p_vaddr = vma->vm_start;
phdr.p_paddr = 0;
- phdr.p_filesz = maydump(vma) ? sz : 0;
+ phdr.p_filesz = maydump(vma, mm_flags) ? sz : 0;
phdr.p_memsz = sz;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -1762,7 +1780,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
DUMP_SEEK(dataoff);
- if (elf_fdpic_dump_segments(file, current->mm, &size, &limit) < 0)
+ if (elf_fdpic_dump_segments(file, &size, &limit, mm_flags) < 0)
goto end_coredump;
#ifdef ELF_CORE_WRITE_EXTRA_DATA
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 330fd3fe8546..42e94b3ab7be 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -126,7 +126,9 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto _ret;
if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
- remove_arg_zero(bprm);
+ retval = remove_arg_zero(bprm);
+ if (retval)
+ goto _ret;
}
if (fmt->flags & MISC_FMT_OPEN_BINARY) {
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 304c88544d89..4d0e0f6d3273 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -67,7 +67,9 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
* This is done in reverse order, because of how the
* user environment and arguments are stored.
*/
- remove_arg_zero(bprm);
+ retval = remove_arg_zero(bprm);
+ if (retval)
+ return retval;
retval = copy_strings_kernel(1, &bprm->interp, bprm);
if (retval < 0) return retval;
bprm->argc++;
diff --git a/fs/bio.c b/fs/bio.c
index 33e46340a766..0d2c2d38b7ba 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1187,7 +1187,7 @@ static void __init biovec_init_slabs(void)
size = bvs->nr_vecs * sizeof(struct bio_vec);
bvs->slab = kmem_cache_create(bvs->name, size, 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
}
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b3e9bfa748cf..2980eabe5779 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -517,7 +517,7 @@ void __init bdev_cache_init(void)
bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD|SLAB_PANIC),
- init_once, NULL);
+ init_once);
err = register_filesystem(&bd_type);
if (err)
panic("Cannot register bdev pseudo-fs");
@@ -588,12 +588,10 @@ EXPORT_SYMBOL(bdget);
long nr_blockdev_pages(void)
{
- struct list_head *p;
+ struct block_device *bdev;
long ret = 0;
spin_lock(&bdev_lock);
- list_for_each(p, &all_bdevs) {
- struct block_device *bdev;
- bdev = list_entry(p, struct block_device, bd_list);
+ list_for_each_entry(bdev, &all_bdevs, bd_list) {
ret += bdev->bd_inode->i_mapping->nrpages;
}
spin_unlock(&bdev_lock);
@@ -874,7 +872,7 @@ static struct bd_holder *find_bd_holder(struct block_device *bdev,
*/
static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
{
- int ret;
+ int err;
if (!bo)
return -EINVAL;
@@ -882,15 +880,18 @@ static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
if (!bd_holder_grab_dirs(bdev, bo))
return -EBUSY;
- ret = add_symlink(bo->sdir, bo->sdev);
- if (ret == 0) {
- ret = add_symlink(bo->hdir, bo->hdev);
- if (ret)
- del_symlink(bo->sdir, bo->sdev);
+ err = add_symlink(bo->sdir, bo->sdev);
+ if (err)
+ return err;
+
+ err = add_symlink(bo->hdir, bo->hdev);
+ if (err) {
+ del_symlink(bo->sdir, bo->sdev);
+ return err;
}
- if (ret == 0)
- list_add_tail(&bo->list, &bdev->bd_holder_list);
- return ret;
+
+ list_add_tail(&bo->list, &bdev->bd_holder_list);
+ return 0;
}
/**
@@ -948,7 +949,7 @@ static struct bd_holder *del_bd_holder(struct block_device *bdev,
static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
struct kobject *kobj)
{
- int res;
+ int err;
struct bd_holder *bo, *found;
if (!kobj)
@@ -959,21 +960,24 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
return -ENOMEM;
mutex_lock(&bdev->bd_mutex);
- res = bd_claim(bdev, holder);
- if (res == 0) {
- found = find_bd_holder(bdev, bo);
- if (found == NULL) {
- res = add_bd_holder(bdev, bo);
- if (res)
- bd_release(bdev);
- }
- }
- if (res || found)
- free_bd_holder(bo);
- mutex_unlock(&bdev->bd_mutex);
+ err = bd_claim(bdev, holder);
+ if (err)
+ goto fail;
- return res;
+ found = find_bd_holder(bdev, bo);
+ if (found)
+ goto fail;
+
+ err = add_bd_holder(bdev, bo);
+ if (err)
+ bd_release(bdev);
+ else
+ bo = NULL;
+fail:
+ mutex_unlock(&bdev->bd_mutex);
+ free_bd_holder(bo);
+ return err;
}
/**
@@ -987,15 +991,12 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
static void bd_release_from_kobject(struct block_device *bdev,
struct kobject *kobj)
{
- struct bd_holder *bo;
-
if (!kobj)
return;
mutex_lock(&bdev->bd_mutex);
bd_release(bdev);
- if ((bo = del_bd_holder(bdev, kobj)))
- free_bd_holder(bo);
+ free_bd_holder(del_bd_holder(bdev, kobj));
mutex_unlock(&bdev->bd_mutex);
}
diff --git a/fs/buffer.c b/fs/buffer.c
index aa68206bd517..0e5ec371ce72 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -356,7 +356,7 @@ static void free_more_memory(void)
for_each_online_pgdat(pgdat) {
zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones;
if (*zones)
- try_to_free_pages(zones, GFP_NOFS);
+ try_to_free_pages(zones, 0, GFP_NOFS);
}
}
@@ -676,6 +676,39 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
EXPORT_SYMBOL(mark_buffer_dirty_inode);
/*
+ * Mark the page dirty, and set it dirty in the radix tree, and mark the inode
+ * dirty.
+ *
+ * If warn is true, then emit a warning if the page is not uptodate and has
+ * not been truncated.
+ */
+static int __set_page_dirty(struct page *page,
+ struct address_space *mapping, int warn)
+{
+ if (unlikely(!mapping))
+ return !TestSetPageDirty(page);
+
+ if (TestSetPageDirty(page))
+ return 0;
+
+ write_lock_irq(&mapping->tree_lock);
+ if (page->mapping) { /* Race with truncate? */
+ WARN_ON_ONCE(warn && !PageUptodate(page));
+
+ if (mapping_cap_account_dirty(mapping)) {
+ __inc_zone_page_state(page, NR_FILE_DIRTY);
+ task_io_account_write(PAGE_CACHE_SIZE);
+ }
+ radix_tree_tag_set(&mapping->page_tree,
+ page_index(page), PAGECACHE_TAG_DIRTY);
+ }
+ write_unlock_irq(&mapping->tree_lock);
+ __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+
+ return 1;
+}
+
+/*
* Add a page to the dirty page list.
*
* It is a sad fact of life that this function is called from several places
@@ -702,7 +735,7 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode);
*/
int __set_page_dirty_buffers(struct page *page)
{
- struct address_space * const mapping = page_mapping(page);
+ struct address_space *mapping = page_mapping(page);
if (unlikely(!mapping))
return !TestSetPageDirty(page);
@@ -719,21 +752,7 @@ int __set_page_dirty_buffers(struct page *page)
}
spin_unlock(&mapping->private_lock);
- if (TestSetPageDirty(page))
- return 0;
-
- write_lock_irq(&mapping->tree_lock);
- if (page->mapping) { /* Race with truncate? */
- if (mapping_cap_account_dirty(mapping)) {
- __inc_zone_page_state(page, NR_FILE_DIRTY);
- task_io_account_write(PAGE_CACHE_SIZE);
- }
- radix_tree_tag_set(&mapping->page_tree,
- page_index(page), PAGECACHE_TAG_DIRTY);
- }
- write_unlock_irq(&mapping->tree_lock);
- __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
- return 1;
+ return __set_page_dirty(page, mapping, 1);
}
EXPORT_SYMBOL(__set_page_dirty_buffers);
@@ -982,7 +1001,7 @@ grow_dev_page(struct block_device *bdev, sector_t block,
struct buffer_head *bh;
page = find_or_create_page(inode->i_mapping, index,
- mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
+ (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE);
if (!page)
return NULL;
@@ -1026,11 +1045,6 @@ failed:
/*
* Create buffers for the specified block device block's page. If
* that page was dirty, the buffers are set dirty also.
- *
- * Except that's a bug. Attaching dirty buffers to a dirty
- * blockdev's page can result in filesystem corruption, because
- * some of those buffers may be aliases of filesystem data.
- * grow_dev_page() will go BUG() if this happens.
*/
static int
grow_buffers(struct block_device *bdev, sector_t block, int size)
@@ -1137,8 +1151,9 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
*/
void fastcall mark_buffer_dirty(struct buffer_head *bh)
{
+ WARN_ON_ONCE(!buffer_uptodate(bh));
if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh))
- __set_page_dirty_nobuffers(bh->b_page);
+ __set_page_dirty(bh->b_page, page_mapping(bh->b_page), 0);
}
/*
@@ -2179,6 +2194,52 @@ int generic_commit_write(struct file *file, struct page *page,
return 0;
}
+/*
+ * block_page_mkwrite() is not allowed to change the file size as it gets
+ * called from a page fault handler when a page is first dirtied. Hence we must
+ * be careful to check for EOF conditions here. We set the page up correctly
+ * for a written page which means we get ENOSPC checking when writing into
+ * holes and correct delalloc and unwritten extent mapping on filesystems that
+ * support these features.
+ *
+ * We are not allowed to take the i_mutex here so we have to play games to
+ * protect against truncate races as the page could now be beyond EOF. Because
+ * vmtruncate() writes the inode size before removing pages, once we have the
+ * page lock we can determine safely if the page is beyond EOF. If it is not
+ * beyond EOF, then the page is guaranteed safe against truncation until we
+ * unlock the page.
+ */
+int
+block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+ get_block_t get_block)
+{
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+ unsigned long end;
+ loff_t size;
+ int ret = -EINVAL;
+
+ lock_page(page);
+ size = i_size_read(inode);
+ if ((page->mapping != inode->i_mapping) ||
+ (page_offset(page) > size)) {
+ /* page got truncated out from underneath us */
+ goto out_unlock;
+ }
+
+ /* page is wholly or partially inside EOF */
+ if (((page->index + 1) << PAGE_CACHE_SHIFT) > size)
+ end = size & ~PAGE_CACHE_MASK;
+ else
+ end = PAGE_CACHE_SIZE;
+
+ ret = block_prepare_write(page, 0, end, get_block);
+ if (!ret)
+ ret = block_commit_write(page, 0, end);
+
+out_unlock:
+ unlock_page(page);
+ return ret;
+}
/*
* nobh_prepare_write()'s prereads are special: the buffer_heads are freed
@@ -2962,6 +3023,7 @@ EXPORT_SYMBOL(__brelse);
EXPORT_SYMBOL(__wait_on_buffer);
EXPORT_SYMBOL(block_commit_write);
EXPORT_SYMBOL(block_prepare_write);
+EXPORT_SYMBOL(block_page_mkwrite);
EXPORT_SYMBOL(block_read_full_page);
EXPORT_SYMBOL(block_sync_page);
EXPORT_SYMBOL(block_truncate_page);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 164a45cdaf5f..bbbf07baa145 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -321,14 +321,13 @@ void unregister_chrdev_region(dev_t from, unsigned count)
}
}
-int unregister_chrdev(unsigned int major, const char *name)
+void unregister_chrdev(unsigned int major, const char *name)
{
struct char_device_struct *cd;
cd = __unregister_chrdev_region(major, 0, 256);
if (cd && cd->cdev)
cdev_del(cd->cdev);
kfree(cd);
- return 0;
}
static DEFINE_SPINLOCK(cdev_lock);
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index a9b6bc5157b8..6d84ca2beead 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -1,3 +1,10 @@
+Version 1.50
+------------
+Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
+done with "serverino" mount option). Add support for POSIX Unlink
+(helps with certain sharing violation cases when server such as
+Samba supports newer POSIX CIFS Protocol Extensions).
+
Version 1.49
------------
IPv6 support. Enable ipv6 addresses to be passed on mount (put the ipv6
@@ -8,7 +15,11 @@ when Unix Extensions were ignored). This allows users to override the
default uid and gid for files when they are certain that the uids or
gids on the server do not match those of the client. Make "sec=none"
mount override username (so that null user connection is attempted)
-to match what documentation said.
+to match what documentation said. Support for very large reads, over 127K,
+available to some newer servers (such as Samba 3.0.26 and later but
+note that it also requires setting CIFSMaxBufSize at module install
+time to a larger value which may hurt performance in some cases).
+Make sign option force signing (or fail if server does not support it).
Version 1.48
------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 4d01697722cc..85f1eb14083e 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -301,10 +301,21 @@ A partial list of the supported mount options follows:
during the local client kernel build will be used.
If server does not support Unicode, this parameter is
unused.
- rsize default read size (usually 16K)
- wsize default write size (usually 16K, 32K is often better over GigE)
- maximum wsize currently allowed by CIFS is 57344 (14 4096 byte
- pages)
+ rsize default read size (usually 16K). The client currently
+ can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize
+ defaults to 16K and may be changed (from 8K to the maximum
+ kmalloc size allowed by your kernel) at module install time
+ for cifs.ko. Setting CIFSMaxBufSize to a very large value
+ will cause cifs to use more memory and may reduce performance
+ in some cases. To use rsize greater than 127K (the original
+ cifs protocol maximum) also requires that the server support
+ a new Unix Capability flag (for very large read) which some
+ newer servers (e.g. Samba 3.0.26 or later) do. rsize can be
+ set from a minimum of 2048 to a maximum of 130048 (127K or
+ CIFSMaxBufSize, whichever is smaller)
+ wsize default write size (default 57344)
+ maximum wsize currently allowed by CIFS is 57344 (fourteen
+ 4096 byte pages)
rw mount the network share read-write (note that the
server may still consider the share read-only)
ro mount network share read-only
@@ -359,7 +370,7 @@ A partial list of the supported mount options follows:
Note that this does not affect the normal ACL check on the
target machine done by the server software (of the server
ACL against the user name provided at mount time).
- serverino Use servers inode numbers instead of generating automatically
+ serverino Use server's inode numbers instead of generating automatically
incrementing inode numbers on the client. Although this will
make it easier to spot hardlinked files (as they will have
the same inode numbers) and inode numbers may be persistent,
@@ -367,12 +378,11 @@ A partial list of the supported mount options follows:
are unique if multiple server side mounts are exported under a
single share (since inode numbers on the servers might not
be unique if multiple filesystems are mounted under the same
- shared higher level directory). Note that this requires that
- the server support the CIFS Unix Extensions as other servers
- do not return a unique IndexNumber on SMB FindFirst (most
- servers return zero as the IndexNumber). Parameter has no
- effect to Windows servers and others which do not support the
- CIFS Unix Extensions.
+ shared higher level directory). Note that some older
+ (e.g. pre-Windows 2000) do not support returning UniqueIDs
+ or the CIFS Unix Extensions equivalent and for those
+ this mount option will have no effect. Exporting cifs mounts
+ under nfsd requires this mount option on the cifs mount.
noserverino Client generates inode numbers (rather than using the actual one
from the server) by default.
setuids If the CIFS Unix extensions are negotiated with the server
@@ -582,10 +592,10 @@ the start of smb requests and responses can be enabled via:
echo 1 > /proc/fs/cifs/traceSMB
-Two other experimental features are under development and to test
-require enabling CONFIG_CIFS_EXPERIMENTAL
+Two other experimental features are under development. To test these
+requires enabling CONFIG_CIFS_EXPERIMENTAL
- More efficient write operations
+ ipv6 enablement
DNOTIFY fcntl: needed for support of directory change
notification and perhaps later for file leases)
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
index 78b620e332bd..d7bd51575fd6 100644
--- a/fs/cifs/TODO
+++ b/fs/cifs/TODO
@@ -18,9 +18,9 @@ better)
d) Kerberos/SPNEGO session setup support - (started)
-e) More testing of NTLMv2 authentication (mostly implemented - double check
-that NTLMv2 signing works, also need to cleanup now unneeded SessSetup code in
-fs/cifs/connect.c)
+e) Cleanup now unneeded SessSetup code in
+fs/cifs/connect.c and add back in NTLMSSP code if any servers
+need it
f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup
used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM
@@ -106,6 +106,12 @@ but recognizes them
succeed but still return access denied (appears to be Windows
server not cifs client problem) and has not been reproduced recently.
NTFS partitions do not have this problem.
+4) Unix/POSIX capabilities are reset after reconnection, and affect
+a few fields in the tree connection but we do do not know which
+superblocks to apply these changes to. We should probably walk
+the list of superblocks to set these. Also need to check the
+flags on the second mount to the same share, and see if we
+can do the same trick that NFS does to remount duplicate shares.
Misc testing to do
==================
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c
index 2e75883b7f54..f50a88d58f78 100644
--- a/fs/cifs/asn1.c
+++ b/fs/cifs/asn1.c
@@ -1,7 +1,7 @@
-/*
+/*
* The ASB.1/BER parsing code is derived from ip_nat_snmp_basic.c which was in
* turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
- *
+ *
* Copyright (c) 2000 RP Internet (www.rpi.net.au).
*
* This program is free software; you can redistribute it and/or modify
@@ -80,7 +80,7 @@
static unsigned long SPNEGO_OID[7] = { 1, 3, 6, 1, 5, 5, 2 };
static unsigned long NTLMSSP_OID[10] = { 1, 3, 6, 1, 4, 1, 311, 2, 2, 10 };
-/*
+/*
* ASN.1 context.
*/
struct asn1_ctx {
@@ -190,7 +190,7 @@ asn1_header_decode(struct asn1_ctx *ctx,
unsigned char **eoc,
unsigned int *cls, unsigned int *con, unsigned int *tag)
{
- unsigned int def = 0;
+ unsigned int def = 0;
unsigned int len = 0;
if (!asn1_id_decode(ctx, cls, con, tag))
@@ -331,7 +331,7 @@ static unsigned char asn1_ulong_decode(struct asn1_ctx *ctx,
*integer |= ch;
}
return 1;
-}
+}
static unsigned char
asn1_octets_decode(struct asn1_ctx *ctx,
@@ -376,7 +376,7 @@ asn1_subid_decode(struct asn1_ctx *ctx, unsigned long *subid)
return 1;
}
-static int
+static int
asn1_oid_decode(struct asn1_ctx *ctx,
unsigned char *eoc, unsigned long **oid, unsigned int *len)
{
@@ -459,7 +459,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
unsigned int cls, con, tag, oidlen, rc;
int use_ntlmssp = FALSE;
- *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default */
+ *secType = NTLM; /* BB eventually make Kerberos or NLTMSSP the default*/
/* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
@@ -498,7 +498,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)
|| (tag != ASN1_EOC)) {
- cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 0",
+ cFYI(1,
+ ("cls = %d con = %d tag = %d end = %p (%d) exit 0",
cls, con, tag, end, *end));
return 0;
}
@@ -508,7 +509,8 @@ decode_negTokenInit(unsigned char *security_blob, int length,
return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) {
- cFYI(1,("cls = %d con = %d tag = %d end = %p (%d) exit 1",
+ cFYI(1,
+ ("cls = %d con = %d tag = %d end = %p (%d) exit 1",
cls, con, tag, end, *end));
return 0;
}
@@ -540,32 +542,34 @@ decode_negTokenInit(unsigned char *security_blob, int length,
rc = asn1_header_decode(&ctx, &end, &cls, &con, &tag);
if (!rc) {
cFYI(1,
- ("Error 1 decoding negTokenInit header exit 2"));
+ ("Error decoding negTokenInit hdr exit2"));
return 0;
}
if ((tag == ASN1_OJI) && (con == ASN1_PRI)) {
rc = asn1_oid_decode(&ctx, end, &oid, &oidlen);
- if(rc) {
+ if (rc) {
cFYI(1,
- ("OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx",
- oidlen, *oid, *(oid + 1), *(oid + 2),
- *(oid + 3)));
- rc = compare_oid(oid, oidlen, NTLMSSP_OID,
- NTLMSSP_OID_LEN);
+ ("OID len = %d oid = 0x%lx 0x%lx "
+ "0x%lx 0x%lx",
+ oidlen, *oid, *(oid + 1),
+ *(oid + 2), *(oid + 3)));
+ rc = compare_oid(oid, oidlen,
+ NTLMSSP_OID, NTLMSSP_OID_LEN);
kfree(oid);
if (rc)
use_ntlmssp = TRUE;
}
} else {
- cFYI(1,("This should be an oid what is going on? "));
+ cFYI(1, ("Should be an oid what is going on?"));
}
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1,
- ("Error decoding last part of negTokenInit exit 3"));
+ ("Error decoding last part negTokenInit exit3"));
return 0;
- } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) { /* tag = 3 indicating mechListMIC */
+ } else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
+ /* tag = 3 indicating mechListMIC */
cFYI(1,
("Exit 4 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end));
@@ -573,7 +577,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1,
- ("Error decoding last part of negTokenInit exit 5"));
+ ("Error decoding last part negTokenInit exit5"));
return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_CON)
|| (tag != ASN1_SEQ)) {
@@ -584,7 +588,7 @@ decode_negTokenInit(unsigned char *security_blob, int length,
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1,
- ("Error decoding last part of negTokenInit exit 7"));
+ ("Error decoding last part negTokenInit exit 7"));
return 0;
} else if ((cls != ASN1_CTX) || (con != ASN1_CON)) {
cFYI(1,
@@ -594,20 +598,21 @@ decode_negTokenInit(unsigned char *security_blob, int length,
}
if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) {
cFYI(1,
- ("Error decoding last part of negTokenInit exit 9"));
+ ("Error decoding last part negTokenInit exit9"));
return 0;
} else if ((cls != ASN1_UNI) || (con != ASN1_PRI)
|| (tag != ASN1_GENSTR)) {
cFYI(1,
- ("Exit 10 cls = %d con = %d tag = %d end = %p (%d)",
+ ("Exit10 cls = %d con = %d tag = %d end = %p (%d)",
cls, con, tag, end, *end));
return 0;
}
- cFYI(1, ("Need to call asn1_octets_decode() function for this %s", ctx.pointer)); /* is this UTF-8 or ASCII? */
+ cFYI(1, ("Need to call asn1_octets_decode() function for %s",
+ ctx.pointer)); /* is this UTF-8 or ASCII? */
}
- /* if (use_kerberos)
- *secType = Kerberos
+ /* if (use_kerberos)
+ *secType = Kerberos
else */
if (use_ntlmssp) {
*secType = NTLMSSP;
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 07838b2ac1ce..1bf8cf522ad6 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -58,7 +58,7 @@ cifs_dump_mem(char *label, void *data, int length)
}
#ifdef CONFIG_CIFS_DEBUG2
-void cifs_dump_detail(struct smb_hdr * smb)
+void cifs_dump_detail(struct smb_hdr *smb)
{
cERROR(1, ("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
smb->Command, smb->Status.CifsError,
@@ -67,10 +67,10 @@ void cifs_dump_detail(struct smb_hdr * smb)
}
-void cifs_dump_mids(struct TCP_Server_Info * server)
+void cifs_dump_mids(struct TCP_Server_Info *server)
{
struct list_head *tmp;
- struct mid_q_entry * mid_entry;
+ struct mid_q_entry *mid_entry;
if (server == NULL)
return;
@@ -114,12 +114,12 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
{
struct list_head *tmp;
struct list_head *tmp1;
- struct mid_q_entry * mid_entry;
+ struct mid_q_entry *mid_entry;
struct cifsSesInfo *ses;
struct cifsTconInfo *tcon;
int i;
int length = 0;
- char * original_buf = buf;
+ char *original_buf = buf;
*beginBuffer = buf + offset;
@@ -145,7 +145,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
(ses->serverNOS == NULL)) {
buf += sprintf(buf, "\nentry for %s not fully "
"displayed\n\t", ses->serverName);
-
} else {
length =
sprintf(buf,
@@ -901,90 +900,14 @@ security_flags_write(struct file *file, const char __user *buffer,
}
/* flags look ok - update the global security flags for cifs module */
extended_security = flags;
+ if (extended_security & CIFSSEC_MUST_SIGN) {
+ /* requiring signing implies signing is allowed */
+ extended_security |= CIFSSEC_MAY_SIGN;
+ cFYI(1, ("packet signing now required"));
+ } else if ((extended_security & CIFSSEC_MAY_SIGN) == 0) {
+ cFYI(1, ("packet signing disabled"));
+ }
+ /* BB should we turn on MAY flags for other MUST options? */
return count;
}
-
-/* static int
-ntlmv2_enabled_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "%d\n", ntlmv2_support);
-
- len -= off;
- *start = page + off;
-
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
-}
-static int
-ntlmv2_enabled_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- char c;
- int rc;
-
- rc = get_user(c, buffer);
- if (rc)
- return rc;
- if (c == '0' || c == 'n' || c == 'N')
- ntlmv2_support = 0;
- else if (c == '1' || c == 'y' || c == 'Y')
- ntlmv2_support = 1;
- else if (c == '2')
- ntlmv2_support = 2;
-
- return count;
-}
-
-static int
-packet_signing_enabled_read(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len;
-
- len = sprintf(page, "%d\n", sign_CIFS_PDUs);
-
- len -= off;
- *start = page + off;
-
- if (len > count)
- len = count;
- else
- *eof = 1;
-
- if (len < 0)
- len = 0;
-
- return len;
-}
-static int
-packet_signing_enabled_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- char c;
- int rc;
-
- rc = get_user(c, buffer);
- if (rc)
- return rc;
- if (c == '0' || c == 'n' || c == 'N')
- sign_CIFS_PDUs = 0;
- else if (c == '1' || c == 'y' || c == 'Y')
- sign_CIFS_PDUs = 1;
- else if (c == '2')
- sign_CIFS_PDUs = 2;
-
- return count;
-} */
-
-
#endif
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 4cc2012e9322..34af556cdd8d 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -43,6 +43,6 @@ struct cifs_sb_info {
mode_t mnt_dir_mode;
int mnt_cifs_flags;
int prepathlen;
- char * prepath;
+ char *prepath;
};
#endif /* _CIFS_FS_SB_H */
diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c
index 701e9a9185f2..b5903b89250d 100644
--- a/fs/cifs/cifs_unicode.c
+++ b/fs/cifs/cifs_unicode.c
@@ -66,7 +66,7 @@ cifs_strtoUCS(__le16 * to, const char *from, int len,
{
int charlen;
int i;
- wchar_t * wchar_to = (wchar_t *)to; /* needed to quiet sparse */
+ wchar_t *wchar_to = (wchar_t *)to; /* needed to quiet sparse */
for (i = 0; len && *from; i++, from += charlen, len -= charlen) {
diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h
index 39e5b970325f..614c11fcdcb6 100644
--- a/fs/cifs/cifs_unicode.h
+++ b/fs/cifs/cifs_unicode.h
@@ -5,20 +5,20 @@
* Convert a unicode character to upper or lower case using
* compressed tables.
*
- * Copyright (c) International Business Machines Corp., 2000,2005555555555555555555555555555555555555555555555555555555
+ * Copyright (c) International Business Machines Corp., 2000,2007
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
@@ -70,7 +70,7 @@ int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *);
* Address of the first string
*/
static inline wchar_t *
-UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
+UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
{
wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
@@ -88,7 +88,7 @@ UniStrcat(wchar_t * ucs1, const wchar_t * ucs2)
* or NULL if the character is not in the string
*/
static inline wchar_t *
-UniStrchr(const wchar_t * ucs, wchar_t uc)
+UniStrchr(const wchar_t *ucs, wchar_t uc)
{
while ((*ucs != uc) && *ucs)
ucs++;
@@ -107,7 +107,7 @@ UniStrchr(const wchar_t * ucs, wchar_t uc)
* > 0: First string is greater than second
*/
static inline int
-UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
+UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
{
while ((*ucs1 == *ucs2) && *ucs1) {
ucs1++;
@@ -120,7 +120,7 @@ UniStrcmp(const wchar_t * ucs1, const wchar_t * ucs2)
* UniStrcpy: Copy a string
*/
static inline wchar_t *
-UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
+UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
{
wchar_t *anchor = ucs1; /* save the start of result string */
@@ -132,7 +132,7 @@ UniStrcpy(wchar_t * ucs1, const wchar_t * ucs2)
* UniStrlen: Return the length of a string (in 16 bit Unicode chars not bytes)
*/
static inline size_t
-UniStrlen(const wchar_t * ucs1)
+UniStrlen(const wchar_t *ucs1)
{
int i = 0;
@@ -142,10 +142,11 @@ UniStrlen(const wchar_t * ucs1)
}
/*
- * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a string (length limited)
+ * UniStrnlen: Return the length (in 16 bit Unicode chars not bytes) of a
+ * string (length limited)
*/
static inline size_t
-UniStrnlen(const wchar_t * ucs1, int maxlen)
+UniStrnlen(const wchar_t *ucs1, int maxlen)
{
int i = 0;
@@ -161,7 +162,7 @@ UniStrnlen(const wchar_t * ucs1, int maxlen)
* UniStrncat: Concatenate length limited string
*/
static inline wchar_t *
-UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{
wchar_t *anchor = ucs1; /* save pointer to string 1 */
@@ -179,7 +180,7 @@ UniStrncat(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncmp: Compare length limited string
*/
static inline int
-UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{
if (!n)
return 0; /* Null strings are equal */
@@ -194,7 +195,7 @@ UniStrncmp(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncmp_le: Compare length limited string - native to little-endian
*/
static inline int
-UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{
if (!n)
return 0; /* Null strings are equal */
@@ -209,7 +210,7 @@ UniStrncmp_le(const wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncpy: Copy length limited string with pad
*/
static inline wchar_t *
-UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{
wchar_t *anchor = ucs1;
@@ -226,7 +227,7 @@ UniStrncpy(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* UniStrncpy_le: Copy length limited string with pad to little-endian
*/
static inline wchar_t *
-UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
+UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
{
wchar_t *anchor = ucs1;
@@ -247,7 +248,7 @@ UniStrncpy_le(wchar_t * ucs1, const wchar_t * ucs2, size_t n)
* NULL if no matching string is found
*/
static inline wchar_t *
-UniStrstr(const wchar_t * ucs1, const wchar_t * ucs2)
+UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
{
const wchar_t *anchor1 = ucs1;
const wchar_t *anchor2 = ucs2;
@@ -297,7 +298,7 @@ UniToupper(register wchar_t uc)
* UniStrupr: Upper case a unicode string
*/
static inline wchar_t *
-UniStrupr(register wchar_t * upin)
+UniStrupr(register wchar_t *upin)
{
register wchar_t *up;
@@ -338,7 +339,7 @@ UniTolower(wchar_t uc)
* UniStrlwr: Lower case a unicode string
*/
static inline wchar_t *
-UniStrlwr(register wchar_t * upin)
+UniStrlwr(register wchar_t *upin)
{
register wchar_t *up;
diff --git a/fs/cifs/cifs_uniupr.h b/fs/cifs/cifs_uniupr.h
index da2ad5b451ac..18a9d978e519 100644
--- a/fs/cifs/cifs_uniupr.h
+++ b/fs/cifs/cifs_uniupr.h
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* uniupr.h - Unicode compressed case ranges
@@ -53,7 +53,7 @@ signed char CifsUniUpperTable[512] = {
0, -1, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, /* 1a0-1af */
-1, 0, 0, 0, -1, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, /* 1b0-1bf */
0, 0, 0, 0, 0, -1, -2, 0, -1, -2, 0, -1, -2, 0, -1, 0, /* 1c0-1cf */
- -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
+ -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, -79, 0, -1, /* 1d0-1df */
0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1, /* 1f0-1ff */
};
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index fdeda519eace..36272293027d 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -21,7 +21,7 @@
#include <linux/fs.h>
#include "cifspdu.h"
-#include "cifsglob.h"
+#include "cifsglob.h"
#include "cifs_debug.h"
#include "md5.h"
#include "cifs_unicode.h"
@@ -29,54 +29,57 @@
#include <linux/ctype.h>
#include <linux/random.h>
-/* Calculate and return the CIFS signature based on the mac key and the smb pdu */
+/* Calculate and return the CIFS signature based on the mac key and SMB PDU */
/* the 16 byte signature must be allocated by the caller */
/* Note we only use the 1st eight bytes */
-/* Note that the smb header signature field on input contains the
+/* Note that the smb header signature field on input contains the
sequence number before this function is called */
extern void mdfour(unsigned char *out, unsigned char *in, int n);
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
- unsigned char *p24);
-
-static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu,
- const char * key, char * signature)
+ unsigned char *p24);
+
+static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
+ const struct mac_key *key, char *signature)
{
struct MD5Context context;
- if((cifs_pdu == NULL) || (signature == NULL))
+ if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL;
MD5Init(&context);
- MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
- MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length);
- MD5Final(signature,&context);
+ MD5Update(&context, (char *)&key->data, key->len);
+ MD5Update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
+
+ MD5Final(signature, &context);
return 0;
}
-int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
- __u32 * pexpected_response_sequence_number)
+int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
+ __u32 *pexpected_response_sequence_number)
{
int rc = 0;
char smb_signature[20];
- if((cifs_pdu == NULL) || (server == NULL))
+ if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL;
- if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+ if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
return rc;
spin_lock(&GlobalMid_Lock);
- cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number);
+ cifs_pdu->Signature.Sequence.SequenceNumber =
+ cpu_to_le32(server->sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;
-
+
*pexpected_response_sequence_number = server->sequence_number++;
server->sequence_number++;
spin_unlock(&GlobalMid_Lock);
- rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature);
- if(rc)
+ rc = cifs_calculate_signature(cifs_pdu, &server->mac_signing_key,
+ smb_signature);
+ if (rc)
memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
else
memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
@@ -84,115 +87,119 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
return rc;
}
-static int cifs_calc_signature2(const struct kvec * iov, int n_vec,
- const char * key, char * signature)
+static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
+ const struct mac_key *key, char *signature)
{
struct MD5Context context;
int i;
- if((iov == NULL) || (signature == NULL))
+ if ((iov == NULL) || (signature == NULL) || (key == NULL))
return -EINVAL;
MD5Init(&context);
- MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16);
- for(i=0;i<n_vec;i++) {
- if(iov[i].iov_base == NULL) {
- cERROR(1,("null iovec entry"));
+ MD5Update(&context, (char *)&key->data, key->len);
+ for (i = 0; i < n_vec; i++) {
+ if (iov[i].iov_base == NULL) {
+ cERROR(1, ("null iovec entry"));
return -EIO;
- } else if(iov[i].iov_len == 0)
+ } else if (iov[i].iov_len == 0)
break; /* bail out if we are sent nothing to sign */
- /* The first entry includes a length field (which does not get
+ /* The first entry includes a length field (which does not get
signed that occupies the first 4 bytes before the header */
- if(i==0) {
+ if (i == 0) {
if (iov[0].iov_len <= 8 ) /* cmd field at offset 9 */
break; /* nothing to sign or corrupt header */
- MD5Update(&context,iov[0].iov_base+4, iov[0].iov_len-4);
+ MD5Update(&context, iov[0].iov_base+4,
+ iov[0].iov_len-4);
} else
- MD5Update(&context,iov[i].iov_base, iov[i].iov_len);
+ MD5Update(&context, iov[i].iov_base, iov[i].iov_len);
}
- MD5Final(signature,&context);
+ MD5Final(signature, &context);
return 0;
}
-int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server,
+int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
__u32 * pexpected_response_sequence_number)
{
int rc = 0;
char smb_signature[20];
- struct smb_hdr * cifs_pdu = iov[0].iov_base;
+ struct smb_hdr *cifs_pdu = iov[0].iov_base;
- if((cifs_pdu == NULL) || (server == NULL))
+ if ((cifs_pdu == NULL) || (server == NULL))
return -EINVAL;
- if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
+ if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
return rc;
- spin_lock(&GlobalMid_Lock);
- cifs_pdu->Signature.Sequence.SequenceNumber =
+ spin_lock(&GlobalMid_Lock);
+ cifs_pdu->Signature.Sequence.SequenceNumber =
cpu_to_le32(server->sequence_number);
- cifs_pdu->Signature.Sequence.Reserved = 0;
+ cifs_pdu->Signature.Sequence.Reserved = 0;
- *pexpected_response_sequence_number = server->sequence_number++;
- server->sequence_number++;
- spin_unlock(&GlobalMid_Lock);
+ *pexpected_response_sequence_number = server->sequence_number++;
+ server->sequence_number++;
+ spin_unlock(&GlobalMid_Lock);
- rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key,
+ rc = cifs_calc_signature2(iov, n_vec, &server->mac_signing_key,
smb_signature);
- if(rc)
- memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
- else
- memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
-
- return rc;
+ if (rc)
+ memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
+ else
+ memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
+ return rc;
}
-int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
- __u32 expected_sequence_number)
+int cifs_verify_signature(struct smb_hdr *cifs_pdu,
+ const struct mac_key *mac_key,
+ __u32 expected_sequence_number)
{
unsigned int rc;
char server_response_sig[8];
char what_we_think_sig_should_be[20];
- if((cifs_pdu == NULL) || (mac_key == NULL))
+ if ((cifs_pdu == NULL) || (mac_key == NULL))
return -EINVAL;
if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
return 0;
if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
- struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)cifs_pdu;
- if(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
+ struct smb_com_lock_req *pSMB =
+ (struct smb_com_lock_req *)cifs_pdu;
+ if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
return 0;
}
- /* BB what if signatures are supposed to be on for session but server does not
- send one? BB */
-
+ /* BB what if signatures are supposed to be on for session but
+ server does not send one? BB */
+
/* Do not need to verify session setups with signature "BSRSPYL " */
- if(memcmp(cifs_pdu->Signature.SecuritySignature,"BSRSPYL ",8)==0)
- cFYI(1,("dummy signature received for smb command 0x%x",cifs_pdu->Command));
+ if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
+ cFYI(1, ("dummy signature received for smb command 0x%x",
+ cifs_pdu->Command));
/* save off the origiginal signature so we can modify the smb and check
its signature against what the server sent */
- memcpy(server_response_sig,cifs_pdu->Signature.SecuritySignature,8);
+ memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
- cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(expected_sequence_number);
+ cifs_pdu->Signature.Sequence.SequenceNumber =
+ cpu_to_le32(expected_sequence_number);
cifs_pdu->Signature.Sequence.Reserved = 0;
rc = cifs_calculate_signature(cifs_pdu, mac_key,
what_we_think_sig_should_be);
- if(rc)
+ if (rc)
return rc;
-
-/* cifs_dump_mem("what we think it should be: ",what_we_think_sig_should_be,16); */
+/* cifs_dump_mem("what we think it should be: ",
+ what_we_think_sig_should_be, 16); */
- if(memcmp(server_response_sig, what_we_think_sig_should_be, 8))
+ if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
return -EACCES;
else
return 0;
@@ -200,89 +207,94 @@ int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key,
}
/* We fill in key by putting in 40 byte array which was allocated by caller */
-int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
+int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
+ const char *password)
{
char temp_key[16];
if ((key == NULL) || (rn == NULL))
return -EINVAL;
E_md4hash(password, temp_key);
- mdfour(key,temp_key,16);
- memcpy(key+16,rn, CIFS_SESS_KEY_SIZE);
+ mdfour(key->data.ntlm, temp_key, 16);
+ memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE);
+ key->len = 40;
return 0;
}
-int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses,
- const struct nls_table * nls_info)
+int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *ses,
+ const struct nls_table *nls_info)
{
char temp_hash[16];
struct HMACMD5Context ctx;
- char * ucase_buf;
- __le16 * unicode_buf;
- unsigned int i,user_name_len,dom_name_len;
+ char *ucase_buf;
+ __le16 *unicode_buf;
+ unsigned int i, user_name_len, dom_name_len;
- if(ses == NULL)
+ if (ses == NULL)
return -EINVAL;
E_md4hash(ses->password, temp_hash);
hmac_md5_init_limK_to_64(temp_hash, 16, &ctx);
user_name_len = strlen(ses->userName);
- if(user_name_len > MAX_USERNAME_SIZE)
+ if (user_name_len > MAX_USERNAME_SIZE)
return -EINVAL;
- if(ses->domainName == NULL)
+ if (ses->domainName == NULL)
return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
dom_name_len = strlen(ses->domainName);
- if(dom_name_len > MAX_USERNAME_SIZE)
+ if (dom_name_len > MAX_USERNAME_SIZE)
return -EINVAL;
-
+
ucase_buf = kmalloc((MAX_USERNAME_SIZE+1), GFP_KERNEL);
- if(ucase_buf == NULL)
+ if (ucase_buf == NULL)
return -ENOMEM;
unicode_buf = kmalloc((MAX_USERNAME_SIZE+1)*4, GFP_KERNEL);
- if(unicode_buf == NULL) {
+ if (unicode_buf == NULL) {
kfree(ucase_buf);
return -ENOMEM;
}
-
- for(i=0;i<user_name_len;i++)
+
+ for (i = 0; i < user_name_len; i++)
ucase_buf[i] = nls_info->charset2upper[(int)ses->userName[i]];
ucase_buf[i] = 0;
- user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
+ user_name_len = cifs_strtoUCS(unicode_buf, ucase_buf,
+ MAX_USERNAME_SIZE*2, nls_info);
unicode_buf[user_name_len] = 0;
user_name_len++;
- for(i=0;i<dom_name_len;i++)
+ for (i = 0; i < dom_name_len; i++)
ucase_buf[i] = nls_info->charset2upper[(int)ses->domainName[i]];
ucase_buf[i] = 0;
- dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf, MAX_USERNAME_SIZE*2, nls_info);
+ dom_name_len = cifs_strtoUCS(unicode_buf+user_name_len, ucase_buf,
+ MAX_USERNAME_SIZE*2, nls_info);
unicode_buf[user_name_len + dom_name_len] = 0;
hmac_md5_update((const unsigned char *) unicode_buf,
- (user_name_len+dom_name_len)*2,&ctx);
+ (user_name_len+dom_name_len)*2, &ctx);
- hmac_md5_final(ses->server->mac_signing_key,&ctx);
+ hmac_md5_final(ses->server->ntlmv2_hash, &ctx);
kfree(ucase_buf);
kfree(unicode_buf);
return 0;
}
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
+void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key)
{
int i;
char password_with_pad[CIFS_ENCPWD_SIZE];
- if(ses->server == NULL)
+ if (ses->server == NULL)
return;
memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
- if(ses->password)
+ if (ses->password)
strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
- if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
- if(extended_security & CIFSSEC_MAY_PLNTXT) {
- memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE);
+ if ((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0)
+ if (extended_security & CIFSSEC_MAY_PLNTXT) {
+ memcpy(lnm_session_key, password_with_pad,
+ CIFS_ENCPWD_SIZE);
return;
}
@@ -297,7 +309,7 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
utf8 and other multibyte codepages each need their own strupper
function since a byte at a time will ont work. */
- for(i = 0; i < CIFS_ENCPWD_SIZE; i++) {
+ for (i = 0; i < CIFS_ENCPWD_SIZE; i++) {
password_with_pad[i] = toupper(password_with_pad[i]);
}
@@ -307,19 +319,19 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
}
#endif /* CIFS_WEAK_PW_HASH */
-static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
- const struct nls_table * nls_cp)
+static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
+ const struct nls_table *nls_cp)
{
int rc = 0;
int len;
char nt_hash[16];
- struct HMACMD5Context * pctxt;
- wchar_t * user;
- wchar_t * domain;
+ struct HMACMD5Context *pctxt;
+ wchar_t *user;
+ wchar_t *domain;
pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
- if(pctxt == NULL)
+ if (pctxt == NULL)
return -ENOMEM;
/* calculate md4 hash of password */
@@ -331,41 +343,45 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
/* convert ses->userName to unicode and uppercase */
len = strlen(ses->userName);
user = kmalloc(2 + (len * 2), GFP_KERNEL);
- if(user == NULL)
+ if (user == NULL)
goto calc_exit_2;
len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
UniStrupr(user);
hmac_md5_update((char *)user, 2*len, pctxt);
/* convert ses->domainName to unicode and uppercase */
- if(ses->domainName) {
+ if (ses->domainName) {
len = strlen(ses->domainName);
- domain = kmalloc(2 + (len * 2), GFP_KERNEL);
- if(domain == NULL)
+ domain = kmalloc(2 + (len * 2), GFP_KERNEL);
+ if (domain == NULL)
goto calc_exit_1;
len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
- UniStrupr(domain);
+ /* the following line was removed since it didn't work well
+ with lower cased domain name that passed as an option.
+ Maybe converting the domain name earlier makes sense */
+ /* UniStrupr(domain); */
hmac_md5_update((char *)domain, 2*len, pctxt);
-
+
kfree(domain);
}
calc_exit_1:
kfree(user);
calc_exit_2:
- /* BB FIXME what about bytes 24 through 40 of the signing key?
+ /* BB FIXME what about bytes 24 through 40 of the signing key?
compare with the NTLM example */
- hmac_md5_final(ses->server->mac_signing_key, pctxt);
+ hmac_md5_final(ses->server->ntlmv2_hash, pctxt);
return rc;
}
-void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
- const struct nls_table * nls_cp)
+void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
+ const struct nls_table *nls_cp)
{
int rc;
- struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf;
+ struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
+ struct HMACMD5Context context;
buf->blob_signature = cpu_to_le32(0x00000101);
buf->reserved = 0;
@@ -379,21 +395,31 @@ void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
/* calculate buf->ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, nls_cp);
- if(rc)
- cERROR(1,("could not get v2 hash rc %d",rc));
+ if (rc)
+ cERROR(1, ("could not get v2 hash rc %d", rc));
CalcNTLMv2_response(ses, resp_buf);
+
+ /* now calculate the MAC key for NTLMv2 */
+ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
+ hmac_md5_update(resp_buf, 16, &context);
+ hmac_md5_final(ses->server->mac_signing_key.data.ntlmv2.key, &context);
+
+ memcpy(&ses->server->mac_signing_key.data.ntlmv2.resp, resp_buf,
+ sizeof(struct ntlmv2_resp));
+ ses->server->mac_signing_key.len = 16 + sizeof(struct ntlmv2_resp);
}
-void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response)
+void CalcNTLMv2_response(const struct cifsSesInfo *ses,
+ char *v2_session_response)
{
struct HMACMD5Context context;
/* rest of v2 struct already generated */
- memcpy(v2_session_response + 8, ses->server->cryptKey,8);
- hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
+ memcpy(v2_session_response + 8, ses->server->cryptKey, 8);
+ hmac_md5_init_limK_to_64(ses->server->ntlmv2_hash, 16, &context);
- hmac_md5_update(v2_session_response+8,
+ hmac_md5_update(v2_session_response+8,
sizeof(struct ntlmv2_resp) - 8, &context);
- hmac_md5_final(v2_session_response,&context);
+ hmac_md5_final(v2_session_response, &context);
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
}
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 8b0cbf4a4ad0..cabb6a55d7dd 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -64,23 +64,27 @@ unsigned int multiuser_mount = 0;
unsigned int extended_security = CIFSSEC_DEF;
/* unsigned int ntlmv2_support = 0; */
unsigned int sign_CIFS_PDUs = 1;
-extern struct task_struct * oplockThread; /* remove sparse warning */
-struct task_struct * oplockThread = NULL;
+extern struct task_struct *oplockThread; /* remove sparse warning */
+struct task_struct *oplockThread = NULL;
/* extern struct task_struct * dnotifyThread; remove sparse warning */
-static struct task_struct * dnotifyThread = NULL;
+static struct task_struct *dnotifyThread = NULL;
static const struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0);
-MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
+MODULE_PARM_DESC(CIFSMaxBufSize, "Network buffer size (not including header). "
+ "Default: 16384 Range: 8192 to 130048");
unsigned int cifs_min_rcv = CIFS_MIN_RCV_POOL;
module_param(cifs_min_rcv, int, 0);
-MODULE_PARM_DESC(cifs_min_rcv,"Network buffers in pool. Default: 4 Range: 1 to 64");
+MODULE_PARM_DESC(cifs_min_rcv, "Network buffers in pool. Default: 4 Range: "
+ "1 to 64");
unsigned int cifs_min_small = 30;
module_param(cifs_min_small, int, 0);
-MODULE_PARM_DESC(cifs_min_small,"Small network buffers in pool. Default: 30 Range: 2 to 256");
+MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 "
+ "Range: 2 to 256");
unsigned int cifs_max_pending = CIFS_MAX_REQ;
module_param(cifs_max_pending, int, 0);
-MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256");
+MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. "
+ "Default: 50 Range: 2 to 256");
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
@@ -95,10 +99,10 @@ cifs_read_super(struct super_block *sb, void *data,
struct inode *inode;
struct cifs_sb_info *cifs_sb;
int rc = 0;
-
+
/* BB should we make this contingent on mount parm? */
sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
- sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info),GFP_KERNEL);
+ sb->s_fs_info = kzalloc(sizeof(struct cifs_sb_info), GFP_KERNEL);
cifs_sb = CIFS_SB(sb);
if (cifs_sb == NULL)
return -ENOMEM;
@@ -114,12 +118,9 @@ cifs_read_super(struct super_block *sb, void *data,
sb->s_magic = CIFS_MAGIC_NUMBER;
sb->s_op = &cifs_super_ops;
-#ifdef CONFIG_CIFS_EXPERIMENTAL
- if (experimEnabled != 0)
- sb->s_export_op = &cifs_export_ops;
-#endif /* EXPERIMENTAL */
/* if (cifs_sb->tcon->ses->server->maxBuf > MAX_CIFS_HDR_SIZE + 512)
- sb->s_blocksize = cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
+ sb->s_blocksize =
+ cifs_sb->tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE; */
#ifdef CONFIG_CIFS_QUOTA
sb->s_qcop = &cifs_quotactl_ops;
#endif
@@ -139,6 +140,13 @@ cifs_read_super(struct super_block *sb, void *data,
goto out_no_root;
}
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
+ cFYI(1, ("export ops supported"));
+ sb->s_export_op = &cifs_export_ops;
+ }
+#endif /* EXPERIMENTAL */
+
return 0;
out_no_root:
@@ -149,7 +157,7 @@ out_no_root:
out_mount_failed:
if (cifs_sb) {
if (cifs_sb->local_nls)
- unload_nls(cifs_sb->local_nls);
+ unload_nls(cifs_sb->local_nls);
kfree(cifs_sb);
}
return rc;
@@ -164,10 +172,10 @@ cifs_put_super(struct super_block *sb)
cFYI(1, ("In cifs_put_super"));
cifs_sb = CIFS_SB(sb);
if (cifs_sb == NULL) {
- cFYI(1,("Empty cifs superblock info passed to unmount"));
+ cFYI(1, ("Empty cifs superblock info passed to unmount"));
return;
}
- rc = cifs_umount(sb, cifs_sb);
+ rc = cifs_umount(sb, cifs_sb);
if (rc) {
cERROR(1, ("cifs_umount failed with return code %d", rc));
}
@@ -180,7 +188,7 @@ static int
cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
- int xid;
+ int xid;
int rc = -EOPNOTSUPP;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
@@ -193,7 +201,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_type = CIFS_MAGIC_NUMBER;
/* instead could get the real value via SMB_QUERY_FS_ATTRIBUTE_INFO */
- buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would
+ buf->f_namelen = PATH_MAX; /* PATH_MAX may be too long - it would
presumably be total path, but note
that some servers (includinng Samba 3)
have a shorter maximum path */
@@ -217,8 +225,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
bypassed it because we detected that this was an older LANMAN sess */
if (rc)
rc = SMBOldQFSInfo(xid, pTcon, buf);
- /*
- int f_type;
+ /* int f_type;
__fsid_t f_fsid;
int f_namelen; */
/* BB get from info in tcon struct at mount time call to QFSAttrInfo */
@@ -227,7 +234,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
longer available? */
}
-static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
+static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
struct cifs_sb_info *cifs_sb;
@@ -235,10 +242,10 @@ static int cifs_permission(struct inode * inode, int mask, struct nameidata *nd)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) {
return 0;
- } else /* file mode might have been restricted at mount time
- on the client (above and beyond ACL on servers) for
+ } else /* file mode might have been restricted at mount time
+ on the client (above and beyond ACL on servers) for
servers which do not support setting and viewing mode bits,
- so allowing client to check permissions is useful */
+ so allowing client to check permissions is useful */
return generic_permission(inode, mask, NULL);
}
@@ -267,7 +274,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->clientCanCacheRead = FALSE;
cifs_inode->clientCanCacheAll = FALSE;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
-
+
/* Can not set i_flags here - they get immediately overwritten
to zero by the VFS */
/* cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;*/
@@ -309,26 +316,26 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
seq_printf(s, ",posixpaths");
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) ||
- !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+ !(cifs_sb->tcon->unix_ext))
seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) ||
- !(cifs_sb->tcon->ses->capabilities & CAP_UNIX))
+ !(cifs_sb->tcon->unix_ext))
seq_printf(s, ",gid=%d", cifs_sb->mnt_gid);
- seq_printf(s, ",rsize=%d",cifs_sb->rsize);
- seq_printf(s, ",wsize=%d",cifs_sb->wsize);
+ seq_printf(s, ",rsize=%d", cifs_sb->rsize);
+ seq_printf(s, ",wsize=%d", cifs_sb->wsize);
}
return 0;
}
#ifdef CONFIG_CIFS_QUOTA
-int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
- struct fs_disk_quota * pdquota)
+int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid,
+ struct fs_disk_quota *pdquota)
{
int xid;
int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
-
+
if (cifs_sb)
pTcon = cifs_sb->tcon;
else
@@ -337,7 +344,7 @@ int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
xid = GetXid();
if (pTcon) {
- cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
+ cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
} else {
return -EIO;
}
@@ -346,8 +353,8 @@ int cifs_xquota_set(struct super_block * sb, int quota_type, qid_t qid,
return rc;
}
-int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
- struct fs_disk_quota * pdquota)
+int cifs_xquota_get(struct super_block *sb, int quota_type, qid_t qid,
+ struct fs_disk_quota *pdquota)
{
int xid;
int rc = 0;
@@ -361,7 +368,7 @@ int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
xid = GetXid();
if (pTcon) {
- cFYI(1,("set type: 0x%x id: %d",quota_type,qid));
+ cFYI(1, ("set type: 0x%x id: %d", quota_type, qid));
} else {
rc = -EIO;
}
@@ -370,9 +377,9 @@ int cifs_xquota_get(struct super_block * sb, int quota_type, qid_t qid,
return rc;
}
-int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
+int cifs_xstate_set(struct super_block *sb, unsigned int flags, int operation)
{
- int xid;
+ int xid;
int rc = 0;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifsTconInfo *pTcon;
@@ -384,7 +391,7 @@ int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
xid = GetXid();
if (pTcon) {
- cFYI(1,("flags: 0x%x operation: 0x%x",flags,operation));
+ cFYI(1, ("flags: 0x%x operation: 0x%x", flags, operation));
} else {
rc = -EIO;
}
@@ -393,7 +400,7 @@ int cifs_xstate_set(struct super_block * sb, unsigned int flags, int operation)
return rc;
}
-int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
+int cifs_xstate_get(struct super_block *sb, struct fs_quota_stat *qstats)
{
int xid;
int rc = 0;
@@ -407,7 +414,7 @@ int cifs_xstate_get(struct super_block * sb, struct fs_quota_stat *qstats)
}
xid = GetXid();
if (pTcon) {
- cFYI(1,("pqstats %p",qstats));
+ cFYI(1, ("pqstats %p", qstats));
} else {
rc = -EIO;
}
@@ -424,10 +431,10 @@ static struct quotactl_ops cifs_quotactl_ops = {
};
#endif
-static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
+static void cifs_umount_begin(struct vfsmount *vfsmnt, int flags)
{
struct cifs_sb_info *cifs_sb;
- struct cifsTconInfo * tcon;
+ struct cifsTconInfo *tcon;
if (!(flags & MNT_FORCE))
return;
@@ -445,9 +452,8 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */
- if (tcon->ses && tcon->ses->server)
- {
- cFYI(1,("wake up tasks now - umount begin not complete"));
+ if (tcon->ses && tcon->ses->server) {
+ cFYI(1, ("wake up tasks now - umount begin not complete"));
wake_up_all(&tcon->ses->server->request_q);
wake_up_all(&tcon->ses->server->response_q);
msleep(1); /* yield */
@@ -480,10 +486,11 @@ static const struct super_operations cifs_super_ops = {
.statfs = cifs_statfs,
.alloc_inode = cifs_alloc_inode,
.destroy_inode = cifs_destroy_inode,
-/* .drop_inode = generic_delete_inode,
- .delete_inode = cifs_delete_inode, *//* Do not need the above two functions
- unless later we add lazy close of inodes or unless the kernel forgets to call
- us with the same number of releases (closes) as opens */
+/* .drop_inode = generic_delete_inode,
+ .delete_inode = cifs_delete_inode, */ /* Do not need above two
+ functions unless later we add lazy close of inodes or unless the
+ kernel forgets to call us with the same number of releases (closes)
+ as opens */
.show_options = cifs_show_options,
.umount_begin = cifs_umount_begin,
.remount_fs = cifs_remount,
@@ -586,11 +593,11 @@ const struct inode_operations cifs_file_inode_ops = {
.getxattr = cifs_getxattr,
.listxattr = cifs_listxattr,
.removexattr = cifs_removexattr,
-#endif
+#endif
};
const struct inode_operations cifs_symlink_inode_ops = {
- .readlink = generic_readlink,
+ .readlink = generic_readlink,
.follow_link = cifs_follow_link,
.put_link = cifs_put_link,
.permission = cifs_permission,
@@ -602,7 +609,7 @@ const struct inode_operations cifs_symlink_inode_ops = {
.getxattr = cifs_getxattr,
.listxattr = cifs_listxattr,
.removexattr = cifs_removexattr,
-#endif
+#endif
};
const struct file_operations cifs_file_ops = {
@@ -628,7 +635,7 @@ const struct file_operations cifs_file_ops = {
};
const struct file_operations cifs_file_direct_ops = {
- /* no mmap, no aio, no readv -
+ /* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
.read = cifs_user_read,
.write = cifs_user_write,
@@ -668,7 +675,7 @@ const struct file_operations cifs_file_nobrl_ops = {
};
const struct file_operations cifs_file_direct_nobrl_ops = {
- /* no mmap, no aio, no readv -
+ /* no mmap, no aio, no readv -
BB reevaluate whether they can be done with directio, no cache */
.read = cifs_user_read,
.write = cifs_user_write,
@@ -693,11 +700,11 @@ const struct file_operations cifs_dir_ops = {
#ifdef CONFIG_CIFS_EXPERIMENTAL
.dir_notify = cifs_dir_notify,
#endif /* CONFIG_CIFS_EXPERIMENTAL */
- .ioctl = cifs_ioctl,
+ .ioctl = cifs_ioctl,
};
static void
-cifs_init_once(void *inode, struct kmem_cache * cachep, unsigned long flags)
+cifs_init_once(void *inode, struct kmem_cache *cachep, unsigned long flags)
{
struct cifsInodeInfo *cifsi = inode;
@@ -712,7 +719,7 @@ cifs_init_inodecache(void)
sizeof (struct cifsInodeInfo),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- cifs_init_once, NULL);
+ cifs_init_once);
if (cifs_inode_cachep == NULL)
return -ENOMEM;
@@ -741,7 +748,7 @@ cifs_init_request_bufs(void)
cifs_req_cachep = kmem_cache_create("cifs_request",
CIFSMaxBufSize +
MAX_CIFS_HDR_SIZE, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (cifs_req_cachep == NULL)
return -ENOMEM;
@@ -749,7 +756,7 @@ cifs_init_request_bufs(void)
cifs_min_rcv = 1;
else if (cifs_min_rcv > 64) {
cifs_min_rcv = 64;
- cERROR(1,("cifs_min_rcv set to maximum (64)"));
+ cERROR(1, ("cifs_min_rcv set to maximum (64)"));
}
cifs_req_poolp = mempool_create_slab_pool(cifs_min_rcv,
@@ -762,25 +769,25 @@ cifs_init_request_bufs(void)
/* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and
almost all handle based requests (but not write response, nor is it
sufficient for path based requests). A smaller size would have
- been more efficient (compacting multiple slab items on one 4k page)
+ been more efficient (compacting multiple slab items on one 4k page)
for the case in which debug was on, but this larger size allows
more SMBs to use small buffer alloc and is still much more
- efficient to alloc 1 per page off the slab compared to 17K (5page)
+ efficient to alloc 1 per page off the slab compared to 17K (5page)
alloc of large cifs buffers even when page debugging is on */
cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq",
- MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN,
+ NULL);
if (cifs_sm_req_cachep == NULL) {
mempool_destroy(cifs_req_poolp);
kmem_cache_destroy(cifs_req_cachep);
- return -ENOMEM;
+ return -ENOMEM;
}
if (cifs_min_small < 2)
cifs_min_small = 2;
else if (cifs_min_small > 256) {
cifs_min_small = 256;
- cFYI(1,("cifs_min_small set to maximum (256)"));
+ cFYI(1, ("cifs_min_small set to maximum (256)"));
}
cifs_sm_req_poolp = mempool_create_slab_pool(cifs_min_small,
@@ -810,7 +817,7 @@ cifs_init_mids(void)
{
cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids",
sizeof (struct mid_q_entry), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (cifs_mid_cachep == NULL)
return -ENOMEM;
@@ -823,7 +830,7 @@ cifs_init_mids(void)
cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs",
sizeof (struct oplock_q_entry), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (cifs_oplock_cachep == NULL) {
mempool_destroy(cifs_mid_poolp);
kmem_cache_destroy(cifs_mid_cachep);
@@ -841,41 +848,43 @@ cifs_destroy_mids(void)
kmem_cache_destroy(cifs_oplock_cachep);
}
-static int cifs_oplock_thread(void * dummyarg)
+static int cifs_oplock_thread(void *dummyarg)
{
- struct oplock_q_entry * oplock_item;
+ struct oplock_q_entry *oplock_item;
struct cifsTconInfo *pTcon;
- struct inode * inode;
+ struct inode *inode;
__u16 netfid;
int rc;
+ set_freezable();
do {
- if (try_to_freeze())
+ if (try_to_freeze())
continue;
-
+
spin_lock(&GlobalMid_Lock);
if (list_empty(&GlobalOplock_Q)) {
spin_unlock(&GlobalMid_Lock);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(39*HZ);
} else {
- oplock_item = list_entry(GlobalOplock_Q.next,
+ oplock_item = list_entry(GlobalOplock_Q.next,
struct oplock_q_entry, qhead);
if (oplock_item) {
- cFYI(1,("found oplock item to write out"));
+ cFYI(1, ("found oplock item to write out"));
pTcon = oplock_item->tcon;
inode = oplock_item->pinode;
netfid = oplock_item->netfid;
spin_unlock(&GlobalMid_Lock);
DeleteOplockQEntry(oplock_item);
/* can not grab inode sem here since it would
- deadlock when oplock received on delete
+ deadlock when oplock received on delete
since vfs_unlink holds the i_mutex across
the call */
/* mutex_lock(&inode->i_mutex);*/
if (S_ISREG(inode->i_mode)) {
rc = filemap_fdatawrite(inode->i_mapping);
- if (CIFS_I(inode)->clientCanCacheRead == 0) {
+ if (CIFS_I(inode)->clientCanCacheRead
+ == 0) {
filemap_fdatawait(inode->i_mapping);
invalidate_remote_inode(inode);
}
@@ -884,20 +893,22 @@ static int cifs_oplock_thread(void * dummyarg)
/* mutex_unlock(&inode->i_mutex);*/
if (rc)
CIFS_I(inode)->write_behind_rc = rc;
- cFYI(1,("Oplock flush inode %p rc %d",inode,rc));
-
- /* releasing a stale oplock after recent reconnection
- of smb session using a now incorrect file
- handle is not a data integrity issue but do
- not bother sending an oplock release if session
- to server still is disconnected since oplock
+ cFYI(1, ("Oplock flush inode %p rc %d",
+ inode, rc));
+
+ /* releasing stale oplock after recent reconnect
+ of smb session using a now incorrect file
+ handle is not a data integrity issue but do
+ not bother sending an oplock release if session
+ to server still is disconnected since oplock
already released by the server in that case */
if (pTcon->tidStatus != CifsNeedReconnect) {
rc = CIFSSMBLock(0, pTcon, netfid,
- 0 /* len */ , 0 /* offset */, 0,
+ 0 /* len */ , 0 /* offset */, 0,
0, LOCKING_ANDX_OPLOCK_RELEASE,
0 /* wait flag */);
- cFYI(1,("Oplock release rc = %d ",rc));
+ cFYI(1,
+ ("Oplock release rc = %d ", rc));
}
} else
spin_unlock(&GlobalMid_Lock);
@@ -909,7 +920,7 @@ static int cifs_oplock_thread(void * dummyarg)
return 0;
}
-static int cifs_dnotify_thread(void * dummyarg)
+static int cifs_dnotify_thread(void *dummyarg)
{
struct list_head *tmp;
struct cifsSesInfo *ses;
@@ -924,9 +935,9 @@ static int cifs_dnotify_thread(void * dummyarg)
to be woken up and wakeq so the
thread can wake up and error out */
list_for_each(tmp, &GlobalSMBSessionList) {
- ses = list_entry(tmp, struct cifsSesInfo,
+ ses = list_entry(tmp, struct cifsSesInfo,
cifsSessionList);
- if (ses && ses->server &&
+ if (ses && ses->server &&
atomic_read(&ses->server->inFlight))
wake_up_all(&ses->server->response_q);
}
@@ -950,13 +961,13 @@ init_cifs(void)
#ifdef CONFIG_CIFS_EXPERIMENTAL
INIT_LIST_HEAD(&GlobalDnotifyReqList);
INIT_LIST_HEAD(&GlobalDnotifyRsp_Q);
-#endif
+#endif
/*
* Initialize Global counters
*/
atomic_set(&sesInfoAllocCount, 0);
atomic_set(&tconInfoAllocCount, 0);
- atomic_set(&tcpSesAllocCount,0);
+ atomic_set(&tcpSesAllocCount, 0);
atomic_set(&tcpSesReconnectCount, 0);
atomic_set(&tconInfoReconnectCount, 0);
@@ -977,10 +988,10 @@ init_cifs(void)
if (cifs_max_pending < 2) {
cifs_max_pending = 2;
- cFYI(1,("cifs_max_pending set to min of 2"));
+ cFYI(1, ("cifs_max_pending set to min of 2"));
} else if (cifs_max_pending > 256) {
cifs_max_pending = 256;
- cFYI(1,("cifs_max_pending set to max of 256"));
+ cFYI(1, ("cifs_max_pending set to max of 256"));
}
rc = cifs_init_inodecache();
@@ -1002,14 +1013,14 @@ init_cifs(void)
oplockThread = kthread_run(cifs_oplock_thread, NULL, "cifsoplockd");
if (IS_ERR(oplockThread)) {
rc = PTR_ERR(oplockThread);
- cERROR(1,("error %d create oplock thread", rc));
+ cERROR(1, ("error %d create oplock thread", rc));
goto out_unregister_filesystem;
}
dnotifyThread = kthread_run(cifs_dnotify_thread, NULL, "cifsdnotifyd");
if (IS_ERR(dnotifyThread)) {
rc = PTR_ERR(dnotifyThread);
- cERROR(1,("error %d create dnotify thread", rc));
+ cERROR(1, ("error %d create dnotify thread", rc));
goto out_stop_oplock_thread;
}
@@ -1035,7 +1046,7 @@ init_cifs(void)
static void __exit
exit_cifs(void)
{
- cFYI(0, ("In unregister ie exit_cifs"));
+ cFYI(0, ("exit_cifs"));
#ifdef CONFIG_PROC_FS
cifs_proc_clean();
#endif
@@ -1048,9 +1059,10 @@ exit_cifs(void)
}
MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>");
-MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
+MODULE_LICENSE("GPL"); /* combination of LGPL + GPL source behaves as GPL */
MODULE_DESCRIPTION
- ("VFS to access servers complying with the SNIA CIFS Specification e.g. Samba and Windows");
+ ("VFS to access servers complying with the SNIA CIFS Specification "
+ "e.g. Samba and Windows");
MODULE_VERSION(CIFS_VERSION);
module_init(init_cifs)
module_exit(exit_cifs)
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index c235d32ad4a8..a20de77a3856 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CIFSFS_H
@@ -43,9 +43,9 @@ extern void cifs_read_inode(struct inode *);
/* Functions related to inodes */
extern const struct inode_operations cifs_dir_inode_ops;
-extern int cifs_create(struct inode *, struct dentry *, int,
+extern int cifs_create(struct inode *, struct dentry *, int,
struct nameidata *);
-extern struct dentry * cifs_lookup(struct inode *, struct dentry *,
+extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
struct nameidata *);
extern int cifs_unlink(struct inode *, struct dentry *);
extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
@@ -63,16 +63,16 @@ extern const struct inode_operations cifs_symlink_inode_ops;
/* Functions related to files and directories */
extern const struct file_operations cifs_file_ops;
-extern const struct file_operations cifs_file_direct_ops; /* if directio mount */
+extern const struct file_operations cifs_file_direct_ops; /* if directio mnt */
extern const struct file_operations cifs_file_nobrl_ops;
-extern const struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */
+extern const struct file_operations cifs_file_direct_nobrl_ops; /* no brlocks */
extern int cifs_open(struct inode *inode, struct file *file);
extern int cifs_close(struct inode *inode, struct file *file);
extern int cifs_closedir(struct inode *inode, struct file *file);
extern ssize_t cifs_user_read(struct file *file, char __user *read_data,
- size_t read_size, loff_t * poffset);
+ size_t read_size, loff_t *poffset);
extern ssize_t cifs_user_write(struct file *file, const char __user *write_data,
- size_t write_size, loff_t * poffset);
+ size_t write_size, loff_t *poffset);
extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, struct dentry *, int);
extern int cifs_flush(struct file *, fl_owner_t id);
@@ -88,8 +88,9 @@ extern struct dentry_operations cifs_ci_dentry_ops;
/* Functions related to symlinks */
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
-extern void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *);
-extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
+extern void cifs_put_link(struct dentry *direntry,
+ struct nameidata *nd, void *);
+extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
int buflen);
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
const char *symname);
@@ -98,7 +99,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
size_t, int);
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
-extern int cifs_ioctl (struct inode * inode, struct file * filep,
+extern int cifs_ioctl (struct inode *inode, struct file *filep,
unsigned int command, unsigned long arg);
-#define CIFS_VERSION "1.49"
+#define CIFS_VERSION "1.50"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 23655de2f4a4..b98742fc3b5a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsglob.h
*
- * Copyright (C) International Business Machines Corp., 2002,2006
+ * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org)
*
@@ -14,7 +14,7 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU Lesser General Public License for more details.
- *
+ *
*/
#include <linux/in.h>
#include <linux/in6.h>
@@ -28,7 +28,7 @@
#define MAX_TREE_SIZE 2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1
#define MAX_SERVER_SIZE 15
-#define MAX_SHARE_SIZE 64 /* used to be 20 - this should still be enough */
+#define MAX_SHARE_SIZE 64 /* used to be 20, this should still be enough */
#define MAX_USERNAME_SIZE 32 /* 32 is to allow for 15 char names + null
termination then *2 for unicode versions */
#define MAX_PASSWORD_SIZE 16
@@ -38,13 +38,13 @@
/*
* MAX_REQ is the maximum number of requests that WE will send
* on one socket concurently. It also matches the most common
- * value of max multiplex returned by servers. We may
+ * value of max multiplex returned by servers. We may
* eventually want to use the negotiated value (in case
* future servers can handle more) when we are more confident that
* we will not have problems oveloading the socket with pending
* write data.
*/
-#define CIFS_MAX_REQ 50
+#define CIFS_MAX_REQ 50
#define SERVER_NAME_LENGTH 15
#define SERVER_NAME_LEN_WITH_NULL (SERVER_NAME_LENGTH + 1)
@@ -104,6 +104,17 @@ enum protocolEnum {
/* Netbios frames protocol not supported at this time */
};
+struct mac_key {
+ unsigned int len;
+ union {
+ char ntlm[CIFS_SESS_KEY_SIZE + 16];
+ struct {
+ char key[16];
+ struct ntlmv2_resp resp;
+ } ntlmv2;
+ } data;
+};
+
/*
*****************************************************************
* Except the CIFS PDUs themselves all the
@@ -120,13 +131,13 @@ struct TCP_Server_Info {
struct sockaddr_in sockAddr;
struct sockaddr_in6 sockAddr6;
} addr;
- wait_queue_head_t response_q;
+ wait_queue_head_t response_q;
wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
struct list_head pending_mid_q;
void *Server_NlsInfo; /* BB - placeholder for future NLS info */
unsigned short server_codepage; /* codepage for the server */
unsigned long ip_address; /* IP addr for the server if known */
- enum protocolEnum protocolType;
+ enum protocolEnum protocolType;
char versionMajor;
char versionMinor;
unsigned svlocal:1; /* local server or remote */
@@ -159,14 +170,15 @@ struct TCP_Server_Info {
/* 16th byte of RFC1001 workstation name is always null */
char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
__u32 sequence_number; /* needed for CIFS PDU signature */
- char mac_signing_key[CIFS_SESS_KEY_SIZE + 16];
+ struct mac_key mac_signing_key;
+ char ntlmv2_hash[16];
unsigned long lstrp; /* when we got last response from this server */
};
/*
* The following is our shortcut to user information. We surface the uid,
* and name. We always get the password on the fly in case it
- * has changed. We also hang a list of sessions owned by this user off here.
+ * has changed. We also hang a list of sessions owned by this user off here.
*/
struct cifsUidInfo {
struct list_head userList;
@@ -197,11 +209,11 @@ struct cifsSesInfo {
int Suid; /* remote smb uid */
uid_t linux_uid; /* local Linux uid */
int capabilities;
- char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
+ char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for
TCP names - will ipv6 and sctp addresses fit? */
char userName[MAX_USERNAME_SIZE + 1];
- char * domainName;
- char * password;
+ char *domainName;
+ char *password;
};
/* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1
@@ -213,7 +225,7 @@ struct cifsSesInfo {
#define CIFS_SES_LANMAN 8
/*
* there is one of these for each connection to a resource on a particular
- * session
+ * session
*/
struct cifsTconInfo {
struct list_head cifsConnectionList;
@@ -269,7 +281,9 @@ struct cifsTconInfo {
FILE_SYSTEM_UNIX_INFO fsUnixInfo;
unsigned retry:1;
unsigned nocase:1;
- /* BB add field for back pointer to sb struct? */
+ unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol
+ for this mount even if server would support */
+ /* BB add field for back pointer to sb struct(s)? */
};
/*
@@ -291,9 +305,9 @@ struct cifs_search_info {
__u16 entries_in_buffer;
__u16 info_level;
__u32 resume_key;
- char * ntwrk_buf_start;
- char * srch_entries_start;
- char * presume_name;
+ char *ntwrk_buf_start;
+ char *srch_entries_start;
+ char *presume_name;
unsigned int resume_name_len;
unsigned endOfSearch:1;
unsigned emptyDir:1;
@@ -309,15 +323,15 @@ struct cifsFileInfo {
__u16 netfid; /* file id from remote */
/* BB add lock scope info here if needed */ ;
/* lock scope id (0 if none) */
- struct file * pfile; /* needed for writepage */
- struct inode * pInode; /* needed for oplock break */
+ struct file *pfile; /* needed for writepage */
+ struct inode *pInode; /* needed for oplock break */
struct mutex lock_mutex;
struct list_head llist; /* list of byte range locks we have. */
unsigned closePend:1; /* file is marked to close */
unsigned invalidHandle:1; /* file closed via session abend */
atomic_t wrtPending; /* handle in use - defer close */
struct semaphore fh_sem; /* prevents reopen race after dead ses*/
- char * search_resume_name; /* BB removeme BB */
+ char *search_resume_name; /* BB removeme BB */
struct cifs_search_info srch_inf;
};
@@ -327,7 +341,7 @@ struct cifsFileInfo {
struct cifsInodeInfo {
struct list_head lockList;
- /* BB add in lists for dirty pages - i.e. write caching info for oplock */
+ /* BB add in lists for dirty pages i.e. write caching info for oplock */
struct list_head openFileList;
int write_behind_rc;
__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
@@ -381,9 +395,9 @@ static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon,
}
#else
-#define cifs_stats_inc(field) do {} while(0)
-#define cifs_stats_bytes_written(tcon, bytes) do {} while(0)
-#define cifs_stats_bytes_read(tcon, bytes) do {} while(0)
+#define cifs_stats_inc(field) do {} while (0)
+#define cifs_stats_bytes_written(tcon, bytes) do {} while (0)
+#define cifs_stats_bytes_read(tcon, bytes) do {} while (0)
#endif
@@ -410,8 +424,8 @@ struct mid_q_entry {
struct oplock_q_entry {
struct list_head qhead;
- struct inode * pinode;
- struct cifsTconInfo * tcon;
+ struct inode *pinode;
+ struct cifsTconInfo *tcon;
__u16 netfid;
};
@@ -426,7 +440,7 @@ struct dir_notify_req {
__u16 netfid;
__u32 filter; /* CompletionFilter (for multishot) */
int multishot;
- struct file * pfile;
+ struct file *pfile;
};
#define MID_FREE 0
@@ -464,7 +478,7 @@ require use of the stronger protocol */
#define CIFSSEC_MUST_LANMAN 0x10010
#define CIFSSEC_MUST_PLNTXT 0x20020
#define CIFSSEC_MASK 0x37037 /* current flags supported if weak */
-#else
+#else
#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */
#endif /* WEAK_PW_HASH */
#define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */
@@ -502,7 +516,7 @@ require use of the stronger protocol */
* ----------
* sesSem operations on smb session
* tconSem operations on tree connection
- * fh_sem file handle reconnection operations
+ * fh_sem file handle reconnection operations
*
****************************************************************************/
@@ -515,7 +529,7 @@ require use of the stronger protocol */
/*
* The list of servers that did not respond with NT LM 0.12.
* This list helps improve performance and eliminate the messages indicating
- * that we had a communications error talking to the server in this list.
+ * that we had a communications error talking to the server in this list.
*/
/* Feature not supported */
/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
@@ -568,12 +582,12 @@ GLOBAL_EXTERN atomic_t midCount;
/* Misc globals */
GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions
to be established on existing mount if we
- have the uid/password or Kerberos credential
+ have the uid/password or Kerberos credential
or equivalent for current user */
GLOBAL_EXTERN unsigned int oplockEnabled;
GLOBAL_EXTERN unsigned int experimEnabled;
GLOBAL_EXTERN unsigned int lookupCacheEnabled;
-GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
+GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index d619ca7d1416..6a2056e58ceb 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -144,7 +144,7 @@
#define SMBOPEN_OAPPEND 0x0001
/*
- * SMB flag definitions
+ * SMB flag definitions
*/
#define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock smb */
#define SMBFLG_RCV_POSTED 0x02 /* obsolete */
@@ -157,9 +157,9 @@
#define SMBFLG_RESPONSE 0x80 /* this PDU is a response from server */
/*
- * SMB flag2 definitions
+ * SMB flag2 definitions
*/
-#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3)
+#define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3)
path names in response */
#define SMBFLG2_KNOWS_EAS cpu_to_le16(2)
#define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4)
@@ -260,7 +260,7 @@
#define ATTR_SPARSE 0x0200
#define ATTR_REPARSE 0x0400
#define ATTR_COMPRESSED 0x0800
-#define ATTR_OFFLINE 0x1000 /* ie file not immediately available -
+#define ATTR_OFFLINE 0x1000 /* ie file not immediately available -
on offline storage */
#define ATTR_NOT_CONTENT_INDEXED 0x2000
#define ATTR_ENCRYPTED 0x4000
@@ -300,7 +300,7 @@
#define CREATE_DELETE_ON_CLOSE 0x00001000
#define CREATE_OPEN_BY_ID 0x00002000
#define OPEN_REPARSE_POINT 0x00200000
-#define CREATE_OPTIONS_MASK 0x007FFFFF
+#define CREATE_OPTIONS_MASK 0x007FFFFF
#define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */
/* ImpersonationLevel flags */
@@ -366,17 +366,19 @@ struct smb_hdr {
#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 )
/*
- * Computer Name Length
+ * Computer Name Length (since Netbios name was length 16 with last byte 0x20)
+ * No longer as important, now that TCP names are more commonly used to
+ * resolve hosts.
*/
#define CNLEN 15
/*
- * Share Name Length @S8A
- * Note: This length is limited by the SMB used to get @S8A
- * the Share info. NetShareEnum only returns 13 @S8A
- * chars, including the null termination. @S8A
+ * Share Name Length (SNLEN)
+ * Note: This length was limited by the SMB used to get
+ * the Share info. NetShareEnum only returned 13
+ * chars, including the null termination.
+ * This was removed because it no longer is limiting.
*/
-#define SNLEN 12 /*@S8A */
/*
* Comment Length
@@ -394,8 +396,8 @@ struct smb_hdr {
*
* The Naming convention is the lower case version of the
* smb command code name for the struct and this is typedef to the
- * uppercase version of the same name with the prefix SMB_ removed
- * for brevity. Although typedefs are not commonly used for
+ * uppercase version of the same name with the prefix SMB_ removed
+ * for brevity. Although typedefs are not commonly used for
* structure definitions in the Linux kernel, their use in the
* CIFS standards document, which this code is based on, may
* make this one of the cases where typedefs for structures make
@@ -403,7 +405,7 @@ struct smb_hdr {
* Typedefs can always be removed later if they are too distracting
* and they are only used for the CIFSs PDUs themselves, not
* internal cifs vfs structures
- *
+ *
*/
typedef struct negotiate_req {
@@ -511,7 +513,7 @@ typedef union smb_com_session_setup_andx {
unsigned char SecurityBlob[1]; /* followed by */
/* STRING NativeOS */
/* STRING NativeLanMan */
- } __attribute__((packed)) req; /* NTLM request format (with
+ } __attribute__((packed)) req; /* NTLM request format (with
extended security */
struct { /* request format */
@@ -549,7 +551,7 @@ typedef union smb_com_session_setup_andx {
/* unsigned char * NativeOS; */
/* unsigned char * NativeLanMan; */
/* unsigned char * PrimaryDomain; */
- } __attribute__((packed)) resp; /* NTLM response
+ } __attribute__((packed)) resp; /* NTLM response
(with or without extended sec) */
struct { /* request format */
@@ -618,7 +620,7 @@ struct ntlmv2_resp {
#define CAP_NT_SMBS 0x00000010
#define CAP_STATUS32 0x00000040
#define CAP_LEVEL_II_OPLOCKS 0x00000080
-#define CAP_NT_FIND 0x00000200 /* reserved should be zero
+#define CAP_NT_FIND 0x00000200 /* reserved should be zero
(because NT_SMBs implies the same thing?) */
#define CAP_BULK_TRANSFER 0x20000000
#define CAP_EXTENDED_SECURITY 0x80000000
@@ -676,7 +678,7 @@ typedef struct smb_com_logoff_andx_rsp {
__u16 ByteCount;
} __attribute__((packed)) LOGOFF_ANDX_RSP;
-typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on
+typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on
tree_connect PDU to effect disconnect */
/* tdis is probably simplest SMB PDU */
struct {
@@ -712,6 +714,7 @@ typedef struct smb_com_findclose_req {
#define REQ_OPLOCK 0x00000002
#define REQ_BATCHOPLOCK 0x00000004
#define REQ_OPENDIRONLY 0x00000008
+#define REQ_EXTENDED_INFO 0x00000010
typedef struct smb_com_open_req { /* also handles create */
struct smb_hdr hdr; /* wct = 24 */
@@ -799,27 +802,28 @@ typedef struct smb_com_openx_rsp {
__u32 FileId;
__u16 Reserved;
__u16 ByteCount;
-} __attribute__((packed)) OPENX_RSP;
+} __attribute__((packed)) OPENX_RSP;
/* For encoding of POSIX Open Request - see trans2 function 0x209 data struct */
/* Legacy write request for older servers */
typedef struct smb_com_writex_req {
- struct smb_hdr hdr; /* wct = 12 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __le32 OffsetLow;
- __u32 Reserved; /* Timeout */
- __le16 WriteMode; /* 1 = write through */
- __le16 Remaining;
- __le16 Reserved2;
- __le16 DataLengthLow;
- __le16 DataOffset;
- __le16 ByteCount;
- __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
- char Data[0];
+ struct smb_hdr hdr; /* wct = 12 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __le32 OffsetLow;
+ __u32 Reserved; /* Timeout */
+ __le16 WriteMode; /* 1 = write through */
+ __le16 Remaining;
+ __le16 Reserved2;
+ __le16 DataLengthLow;
+ __le16 DataOffset;
+ __le16 ByteCount;
+ __u8 Pad; /* BB check for whether padded to DWORD
+ boundary and optimum performance here */
+ char Data[0];
} __attribute__((packed)) WRITEX_REQ;
typedef struct smb_com_write_req {
@@ -837,7 +841,8 @@ typedef struct smb_com_write_req {
__le16 DataOffset;
__le32 OffsetHigh;
__le16 ByteCount;
- __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
+ __u8 Pad; /* BB check for whether padded to DWORD
+ boundary and optimum performance here */
char Data[0];
} __attribute__((packed)) WRITE_REQ;
@@ -855,17 +860,17 @@ typedef struct smb_com_write_rsp {
/* legacy read request for older servers */
typedef struct smb_com_readx_req {
- struct smb_hdr hdr; /* wct = 10 */
- __u8 AndXCommand;
- __u8 AndXReserved;
- __le16 AndXOffset;
- __u16 Fid;
- __le32 OffsetLow;
- __le16 MaxCount;
- __le16 MinCount; /* obsolete */
- __le32 Reserved;
- __le16 Remaining;
- __le16 ByteCount;
+ struct smb_hdr hdr; /* wct = 10 */
+ __u8 AndXCommand;
+ __u8 AndXReserved;
+ __le16 AndXOffset;
+ __u16 Fid;
+ __le32 OffsetLow;
+ __le16 MaxCount;
+ __le16 MinCount; /* obsolete */
+ __le32 Reserved;
+ __le16 Remaining;
+ __le16 ByteCount;
} __attribute__((packed)) READX_REQ;
typedef struct smb_com_read_req {
@@ -896,7 +901,8 @@ typedef struct smb_com_read_rsp {
__le16 DataLengthHigh;
__u64 Reserved2;
__u16 ByteCount;
- __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */
+ __u8 Pad; /* BB check for whether padded to DWORD
+ boundary and optimum performance here */
char Data[1];
} __attribute__((packed)) READ_RSP;
@@ -967,7 +973,7 @@ typedef struct smb_com_rename_req {
#define COPY_TARGET_MODE_ASCII 0x0004 /* if not set, binary */
#define COPY_SOURCE_MODE_ASCII 0x0008 /* if not set, binary */
#define COPY_VERIFY_WRITES 0x0010
-#define COPY_TREE 0x0020
+#define COPY_TREE 0x0020
typedef struct smb_com_copy_req {
struct smb_hdr hdr; /* wct = 3 */
@@ -975,7 +981,7 @@ typedef struct smb_com_copy_req {
__le16 OpenFunction;
__le16 Flags;
__le16 ByteCount;
- __u8 BufferFormat; /* 4 = ASCII or Unicode */
+ __u8 BufferFormat; /* 4 = ASCII or Unicode */
unsigned char OldFileName[1];
/* followed by __u8 BufferFormat2 */
/* followed by NewFileName string */
@@ -1083,28 +1089,28 @@ typedef struct smb_com_setattr_rsp {
/*******************************************************/
/* NT Transact structure defintions follow */
-/* Currently only ioctl, acl (get security descriptor) */
+/* Currently only ioctl, acl (get security descriptor) */
/* and notify are implemented */
/*******************************************************/
typedef struct smb_com_ntransact_req {
- struct smb_hdr hdr; /* wct >= 19 */
- __u8 MaxSetupCount;
- __u16 Reserved;
- __le32 TotalParameterCount;
- __le32 TotalDataCount;
- __le32 MaxParameterCount;
- __le32 MaxDataCount;
- __le32 ParameterCount;
- __le32 ParameterOffset;
- __le32 DataCount;
- __le32 DataOffset;
- __u8 SetupCount; /* four setup words follow subcommand */
- /* SNIA spec incorrectly included spurious pad here */
- __le16 SubCommand; /* 2 = IOCTL/FSCTL */
- /* SetupCount words follow then */
- __le16 ByteCount;
- __u8 Pad[3];
- __u8 Parms[0];
+ struct smb_hdr hdr; /* wct >= 19 */
+ __u8 MaxSetupCount;
+ __u16 Reserved;
+ __le32 TotalParameterCount;
+ __le32 TotalDataCount;
+ __le32 MaxParameterCount;
+ __le32 MaxDataCount;
+ __le32 ParameterCount;
+ __le32 ParameterOffset;
+ __le32 DataCount;
+ __le32 DataOffset;
+ __u8 SetupCount; /* four setup words follow subcommand */
+ /* SNIA spec incorrectly included spurious pad here */
+ __le16 SubCommand; /* 2 = IOCTL/FSCTL */
+ /* SetupCount words follow then */
+ __le16 ByteCount;
+ __u8 Pad[3];
+ __u8 Parms[0];
} __attribute__((packed)) NTRANSACT_REQ;
typedef struct smb_com_ntransact_rsp {
@@ -1120,7 +1126,7 @@ typedef struct smb_com_ntransact_rsp {
__le32 DataDisplacement;
__u8 SetupCount; /* 0 */
__u16 ByteCount;
- /* __u8 Pad[3]; */
+ /* __u8 Pad[3]; */
/* parms and data follow */
} __attribute__((packed)) NTRANSACT_RSP;
@@ -1215,7 +1221,7 @@ typedef struct smb_com_transaction_change_notify_req {
/* __u8 Data[1];*/
} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ;
-/* BB eventually change to use generic ntransact rsp struct
+/* BB eventually change to use generic ntransact rsp struct
and validation routine */
typedef struct smb_com_transaction_change_notify_rsp {
struct smb_hdr hdr; /* wct = 18 */
@@ -1262,7 +1268,7 @@ struct file_notify_information {
__le32 Action;
__le32 FileNameLength;
__u8 FileName[0];
-} __attribute__((packed));
+} __attribute__((packed));
struct reparse_data {
__u32 ReparseTag;
@@ -1331,7 +1337,7 @@ struct trans2_resp {
__u8 Reserved1;
/* SetupWords[SetupCount];
__u16 ByteCount;
- __u16 Reserved2;*/
+ __u16 Reserved2;*/
/* data area follows */
} __attribute__((packed));
@@ -1370,9 +1376,9 @@ struct smb_t2_rsp {
#define SMB_QUERY_FILE_INTERNAL_INFO 0x3ee
#define SMB_QUERY_FILE_ACCESS_INFO 0x3f0
#define SMB_QUERY_FILE_NAME_INFO2 0x3f1 /* 0x30 bytes */
-#define SMB_QUERY_FILE_POSITION_INFO 0x3f6
+#define SMB_QUERY_FILE_POSITION_INFO 0x3f6
#define SMB_QUERY_FILE_MODE_INFO 0x3f8
-#define SMB_QUERY_FILE_ALGN_INFO 0x3f9
+#define SMB_QUERY_FILE_ALGN_INFO 0x3f9
#define SMB_SET_FILE_BASIC_INFO 0x101
@@ -1506,35 +1512,35 @@ struct smb_com_transaction2_sfi_req {
__u16 Pad1;
__u16 Fid;
__le16 InformationLevel;
- __u16 Reserved4;
+ __u16 Reserved4;
} __attribute__((packed));
struct smb_com_transaction2_sfi_rsp {
struct smb_hdr hdr; /* wct = 10 + SetupCount */
struct trans2_resp t2;
__u16 ByteCount;
- __u16 Reserved2; /* parameter word reserved -
+ __u16 Reserved2; /* parameter word reserved -
present for infolevels > 100 */
} __attribute__((packed));
struct smb_t2_qfi_req {
- struct smb_hdr hdr;
- struct trans2_req t2;
+ struct smb_hdr hdr;
+ struct trans2_req t2;
__u8 Pad;
__u16 Fid;
__le16 InformationLevel;
} __attribute__((packed));
struct smb_t2_qfi_rsp {
- struct smb_hdr hdr; /* wct = 10 + SetupCount */
- struct trans2_resp t2;
- __u16 ByteCount;
- __u16 Reserved2; /* parameter word reserved -
- present for infolevels > 100 */
+ struct smb_hdr hdr; /* wct = 10 + SetupCount */
+ struct trans2_resp t2;
+ __u16 ByteCount;
+ __u16 Reserved2; /* parameter word reserved -
+ present for infolevels > 100 */
} __attribute__((packed));
/*
- * Flags on T2 FINDFIRST and FINDNEXT
+ * Flags on T2 FINDFIRST and FINDNEXT
*/
#define CIFS_SEARCH_CLOSE_ALWAYS 0x0001
#define CIFS_SEARCH_CLOSE_AT_END 0x0002
@@ -1743,7 +1749,9 @@ typedef struct smb_com_transaction2_get_dfs_refer_req {
__u8 Reserved3;
__le16 SubCommand; /* one setup word */
__le16 ByteCount;
- __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */
+ __u8 Pad[3]; /* Win2K has sent 0x0F01 (max response length
+ perhaps?) followed by one byte pad - doesn't
+ seem to matter though */
__le16 MaxReferralLevel;
char RequestFileName[1];
} __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ;
@@ -1752,7 +1760,10 @@ typedef struct dfs_referral_level_3 {
__le16 VersionNumber;
__le16 ReferralSize;
__le16 ServerType; /* 0x0001 = CIFS server */
- __le16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
+ __le16 ReferralFlags; /* or proximity - not clear which since it is
+ always set to zero - SNIA spec says 0x01
+ means strip off PathConsumed chars before
+ submitting RequestFileName to remote node */
__le16 TimeToLive;
__le16 Proximity;
__le16 DfsPathOffset;
@@ -1778,11 +1789,13 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
#define DFSREF_STORAGE_SERVER 0x0002
/* IOCTL information */
-/* List of ioctl function codes that look to be of interest to remote clients like this. */
-/* Need to do some experimentation to make sure they all work remotely. */
-/* Some of the following such as the encryption/compression ones would be */
-/* invoked from tools via a specialized hook into the VFS rather than via the */
-/* standard vfs entry points */
+/*
+ * List of ioctl function codes that look to be of interest to remote clients
+ * like this one. Need to do some experimentation to make sure they all work
+ * remotely. Some of the following, such as the encryption/compression ones
+ * would be invoked from tools via a specialized hook into the VFS rather
+ * than via the standard vfs entry points
+ */
#define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
#define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
#define FSCTL_REQUEST_BATCH_OPLOCK 0x00090008
@@ -1811,7 +1824,7 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp {
/*
************************************************************************
* All structs for everything above the SMB PDUs themselves
- * (such as the T2 level specific data) go here
+ * (such as the T2 level specific data) go here
************************************************************************
*/
@@ -1857,7 +1870,7 @@ typedef struct {
__le64 FreeAllocationUnits;
__le32 SectorsPerAllocationUnit;
__le32 BytesPerSector;
-} __attribute__((packed)) FILE_SYSTEM_INFO; /* size info, level 0x103 */
+} __attribute__((packed)) FILE_SYSTEM_INFO; /* size info, level 0x103 */
typedef struct {
__le32 fsid;
@@ -1871,7 +1884,7 @@ typedef struct {
__le16 MajorVersionNumber;
__le16 MinorVersionNumber;
__le64 Capability;
-} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */
+} __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extension level 0x200*/
/* Version numbers for CIFS UNIX major and minor. */
#define CIFS_UNIX_MAJOR_VERSION 1
@@ -1885,16 +1898,20 @@ typedef struct {
#define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Allow POSIX path chars */
#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based
calls including posix open
- and posix unlink */
+ and posix unlink */
+#define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up
+ to 0xFFFF00 */
+#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080
+
#ifdef CONFIG_CIFS_POSIX
/* Can not set pathnames cap yet until we send new posix create SMB since
otherwise server can treat such handles opened with older ntcreatex
(by a new client which knows how to send posix path ops)
as non-posix handles (can affect write behavior with byte range locks.
We can add back in POSIX_PATH_OPS cap when Posix Create/Mkdir finished */
-/* #define CIFS_UNIX_CAP_MASK 0x0000003b */
-#define CIFS_UNIX_CAP_MASK 0x0000001b
-#else
+/* #define CIFS_UNIX_CAP_MASK 0x000000fb */
+#define CIFS_UNIX_CAP_MASK 0x000000db
+#else
#define CIFS_UNIX_CAP_MASK 0x00000013
#endif /* CONFIG_CIFS_POSIX */
@@ -1904,10 +1921,10 @@ typedef struct {
typedef struct {
/* For undefined recommended transfer size return -1 in that field */
__le32 OptimalTransferSize; /* bsize on some os, iosize on other os */
- __le32 BlockSize;
+ __le32 BlockSize;
/* The next three fields are in terms of the block size.
(above). If block size is unknown, 4096 would be a
- reasonable block size for a server to report.
+ reasonable block size for a server to report.
Note that returning the blocks/blocksavail removes need
to make a second call (to QFSInfo level 0x103 to get this info.
UserBlockAvail is typically less than or equal to BlocksAvail,
@@ -2062,9 +2079,9 @@ struct file_alt_name_info {
struct file_stream_info {
__le32 number_of_streams; /* BB check sizes and verify location */
- /* followed by info on streams themselves
+ /* followed by info on streams themselves
u64 size;
- u64 allocation_size
+ u64 allocation_size
stream info */
}; /* level 0x109 */
@@ -2083,7 +2100,7 @@ struct cifs_posix_ace { /* access control entry (ACE) */
__u8 cifs_e_tag;
__u8 cifs_e_perm;
__le64 cifs_uid; /* or gid */
-} __attribute__((packed));
+} __attribute__((packed));
struct cifs_posix_acl { /* access conrol list (ACL) */
__le16 version;
@@ -2138,6 +2155,12 @@ typedef struct {
/* struct following varies based on requested level */
} __attribute__((packed)) OPEN_PSX_RSP; /* level 0x209 SetPathInfo data */
+#define SMB_POSIX_UNLINK_FILE_TARGET 0
+#define SMB_POSIX_UNLINK_DIRECTORY_TARGET 1
+
+struct unlink_psx_rq { /* level 0x20a SetPathInfo */
+ __le16 type;
+} __attribute__((packed));
struct file_internal_info {
__u64 UniqueId; /* inode number */
@@ -2154,7 +2177,7 @@ struct file_attrib_tag {
/********************************************************/
-/* FindFirst/FindNext transact2 data buffer formats */
+/* FindFirst/FindNext transact2 data buffer formats */
/********************************************************/
typedef struct {
@@ -2232,7 +2255,7 @@ typedef struct {
__le64 EndOfFile;
__le64 AllocationSize;
__le32 ExtFileAttributes;
- __le32 FileNameLength;
+ __le32 FileNameLength;
__le32 EaSize; /* length of the xattrs */
__u8 ShortNameLength;
__u8 Reserved;
@@ -2259,7 +2282,7 @@ typedef struct {
struct win_dev {
unsigned char type[8]; /* IntxCHR or IntxBLK */
__le64 major;
- __le64 minor;
+ __le64 minor;
} __attribute__((packed));
struct gea {
@@ -2291,36 +2314,36 @@ struct fealist {
struct data_blob {
__u8 *data;
size_t length;
- void (*free) (struct data_blob * data_blob);
+ void (*free) (struct data_blob *data_blob);
} __attribute__((packed));
#ifdef CONFIG_CIFS_POSIX
-/*
+/*
For better POSIX semantics from Linux client, (even better
than the existing CIFS Unix Extensions) we need updated PDUs for:
-
+
1) PosixCreateX - to set and return the mode, inode#, device info and
perhaps add a CreateDevice - to create Pipes and other special .inodes
Also note POSIX open flags
- 2) Close - to return the last write time to do cache across close
+ 2) Close - to return the last write time to do cache across close
more safely
- 3) FindFirst return unique inode number - what about resume key, two
+ 3) FindFirst return unique inode number - what about resume key, two
forms short (matches readdir) and full (enough info to cache inodes)
4) Mkdir - set mode
-
- And under consideration:
+
+ And under consideration:
5) FindClose2 (return nanosecond timestamp ??)
- 6) Use nanosecond timestamps throughout all time fields if
+ 6) Use nanosecond timestamps throughout all time fields if
corresponding attribute flag is set
7) sendfile - handle based copy
8) Direct i/o
9) Misc fcntls?
-
+
what about fixing 64 bit alignment
-
+
There are also various legacy SMB/CIFS requests used as is
-
+
From existing Lanman and NTLM dialects:
--------------------------------------
NEGOTIATE
@@ -2341,48 +2364,48 @@ struct data_blob {
(BB verify that never need to set allocation size)
SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via
Unix ext?)
-
+
COPY (note support for copy across directories) - FUTURE, OPTIONAL
setting/getting OS/2 EAs - FUTURE (BB can this handle
setting Linux xattrs perfectly) - OPTIONAL
dnotify - FUTURE, OPTIONAL
quota - FUTURE, OPTIONAL
-
- Note that various requests implemented for NT interop such as
+
+ Note that various requests implemented for NT interop such as
NT_TRANSACT (IOCTL) QueryReparseInfo
are unneeded to servers compliant with the CIFS POSIX extensions
-
+
From CIFS Unix Extensions:
-------------------------
T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
- T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields
- Actually need QUERY_FILE_UNIX_INFO since has inode num
- BB what about a) blksize/blkbits/blocks
+ T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) BB check for missing
+ inode fields
+ Actually a need QUERY_FILE_UNIX_INFO
+ since has inode num
+ BB what about a) blksize/blkbits/blocks
b) i_version
c) i_rdev
d) notify mask?
e) generation
f) size_seqcount
T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
- TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
+ TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
-
-
*/
/* xsymlink is a symlink format (used by MacOS) that can be used
- to save symlink info in a regular file when
+ to save symlink info in a regular file when
mounted to operating systems that do not
support the cifs Unix extensions or EAs (for xattr
based symlinks). For such a file to be recognized
- as containing symlink data:
+ as containing symlink data:
- 1) file size must be 1067,
+ 1) file size must be 1067,
2) signature must begin file data,
3) length field must be set to ASCII representation
- of a number which is less than or equal to 1024,
+ of a number which is less than or equal to 1024,
4) md5 must match that of the path data */
struct xsymlink {
@@ -2393,10 +2416,10 @@ struct xsymlink {
char length[4];
char cr1; /* \n */
/* md5 of valid subset of path ie path[0] through path[length-1] */
- __u8 md5[32];
+ __u8 md5[32];
char cr2; /* \n */
/* if room left, then end with \n then 0x20s by convention but not required */
- char path[1024];
+ char path[1024];
} __attribute__((packed));
typedef struct file_xattr_info {
@@ -2405,7 +2428,8 @@ typedef struct file_xattr_info {
__u32 xattr_value_len;
char xattr_name[0];
/* followed by xattr_value[xattr_value_len], no pad */
-} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */
+} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info
+ level 0x205 */
/* flags for chattr command */
@@ -2431,8 +2455,9 @@ typedef struct file_xattr_info {
typedef struct file_chattr_info {
__le64 mask; /* list of all possible attribute bits */
__le64 mode; /* list of actual attribute bits on this inode */
-} __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */
+} __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes
+ (chattr, chflags) level 0x206 */
-#endif
+#endif
#endif /* _CIFSPDU_H */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 5d163e2b6143..04a69dafedba 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CIFSPROTO_H
#define _CIFSPROTO_H
@@ -49,9 +49,9 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
struct smb_hdr * /* out */ ,
int * /* bytes returned */ , const int long_op);
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
- struct kvec *, int /* nvec to send */,
+ struct kvec *, int /* nvec to send */,
int * /* type of buf returned */ , const int long_op);
-extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
+extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
struct cifsTconInfo *,
struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ ,
@@ -64,19 +64,19 @@ extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
extern int decode_negTokenInit(unsigned char *security_blob, int length,
enum securityEnum *secType);
-extern int cifs_inet_pton(int, char * source, void *dst);
+extern int cifs_inet_pton(int, char *source, void *dst);
extern int map_smb_to_linux_error(struct smb_hdr *smb);
extern void header_assemble(struct smb_hdr *, char /* command */ ,
const struct cifsTconInfo *, int /* length of
fixed section (word count) in two byte units */);
extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
struct cifsSesInfo *ses,
- void ** request_buf);
+ void **request_buf);
extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
- const int stage,
+ const int stage,
const struct nls_table *nls_cp);
extern __u16 GetNextMid(struct TCP_Server_Info *server);
-extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
+extern struct oplock_q_entry *AllocOplockQEntry(struct inode *, u16,
struct cifsTconInfo *);
extern void DeleteOplockQEntry(struct oplock_q_entry *);
extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
@@ -85,12 +85,12 @@ extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
extern int cifs_get_inode_info(struct inode **pinode,
- const unsigned char *search_path,
+ const unsigned char *search_path,
FILE_ALL_INFO * pfile_info,
struct super_block *sb, int xid);
extern int cifs_get_inode_info_unix(struct inode **pinode,
const unsigned char *search_path,
- struct super_block *sb,int xid);
+ struct super_block *sb, int xid);
extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
const char *);
@@ -98,8 +98,8 @@ extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
void cifs_proc_init(void);
void cifs_proc_clean(void);
-extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
- struct nls_table * nls_info);
+extern int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
+ struct nls_table *nls_info);
extern int CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses);
extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
@@ -108,11 +108,11 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
const char *searchName, const struct nls_table *nls_codepage,
- __u16 *searchHandle, struct cifs_search_info * psrch_inf,
+ __u16 *searchHandle, struct cifs_search_info *psrch_inf,
int map, const char dirsep);
extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
- __u16 searchHandle, struct cifs_search_info * psrch_inf);
+ __u16 searchHandle, struct cifs_search_info *psrch_inf);
extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
const __u16 search_handle);
@@ -123,9 +123,9 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
int legacy /* whether to use old info level */,
const struct nls_table *nls_codepage, int remap);
extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- FILE_ALL_INFO * findData,
- const struct nls_table *nls_codepage, int remap);
+ const unsigned char *searchName,
+ FILE_ALL_INFO *findData,
+ const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBUnixQPathInfo(const int xid,
struct cifsTconInfo *tcon,
@@ -143,13 +143,13 @@ extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path,
const struct nls_table *nls_codepage, int remap);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- const char *old_path,
+ const char *old_path,
const struct nls_table *nls_codepage,
- unsigned int *pnum_referrals,
- unsigned char ** preferrals,
+ unsigned int *pnum_referrals,
+ unsigned char **preferrals,
int remap);
extern void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
- struct super_block * sb, struct smb_vol * vol);
+ struct super_block *sb, struct smb_vol *vol);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct kstatfs *FSData);
extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon,
@@ -181,11 +181,11 @@ extern int CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon,
- __u64 size, __u16 fileHandle,__u32 opener_pid,
+ __u64 size, __u16 fileHandle, __u32 opener_pid,
int AllocSizeFlag);
extern int CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *pTcon,
char *full_path, __u64 mode, __u64 uid,
- __u64 gid, dev_t dev,
+ __u64 gid, dev_t dev,
const struct nls_table *nls_codepage,
int remap_special_chars);
@@ -196,7 +196,10 @@ extern int CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
extern int CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
const char *name, const struct nls_table *nls_codepage,
int remap_special_chars);
-
+extern int CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon,
+ const char *name, __u16 type,
+ const struct nls_table *nls_codepage,
+ int remap_special_chars);
extern int CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
const char *name,
const struct nls_table *nls_codepage,
@@ -205,8 +208,8 @@ extern int CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
const struct nls_table *nls_codepage,
int remap_special_chars);
-extern int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
- int netfid, char * target_name,
+extern int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
+ int netfid, char *target_name,
const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSCreateHardLink(const int xid,
@@ -217,7 +220,7 @@ extern int CIFSCreateHardLink(const int xid,
extern int CIFSUnixCreateHardLink(const int xid,
struct cifsTconInfo *tcon,
const char *fromName, const char *toName,
- const struct nls_table *nls_codepage,
+ const struct nls_table *nls_codepage,
int remap_special_chars);
extern int CIFSUnixCreateSymLink(const int xid,
struct cifsTconInfo *tcon,
@@ -228,7 +231,7 @@ extern int CIFSSMBUnixQuerySymLink(const int xid,
const unsigned char *searchName,
char *syminfo, const int buflen,
const struct nls_table *nls_codepage);
-extern int CIFSSMBQueryReparseLinkInfo(const int xid,
+extern int CIFSSMBQueryReparseLinkInfo(const int xid,
struct cifsTconInfo *tcon,
const unsigned char *searchName,
char *symlinkinfo, const int buflen, __u16 fid,
@@ -244,35 +247,35 @@ extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const int access_flags, const int omode,
__u16 * netfid, int *pOplock, FILE_ALL_INFO *,
const struct nls_table *nls_codepage, int remap);
-extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
+extern int CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon,
u32 posix_flags, __u64 mode, __u16 * netfid,
FILE_UNIX_BASIC_INFO *pRetData,
__u32 *pOplock, const char *name,
- const struct nls_table *nls_codepage, int remap);
+ const struct nls_table *nls_codepage, int remap);
extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon,
const int smb_file_id);
extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
- const int netfid, unsigned int count,
- const __u64 lseek, unsigned int *nbytes, char **buf,
- int * return_buf_type);
+ const int netfid, unsigned int count,
+ const __u64 lseek, unsigned int *nbytes, char **buf,
+ int *return_buf_type);
extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
const int netfid, const unsigned int count,
const __u64 lseek, unsigned int *nbytes,
- const char *buf, const char __user *ubuf,
+ const char *buf, const char __user *ubuf,
const int long_op);
extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
const int netfid, const unsigned int count,
- const __u64 offset, unsigned int *nbytes,
+ const __u64 offset, unsigned int *nbytes,
struct kvec *iov, const int nvec, const int long_op);
extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName, __u64 * inode_number,
- const struct nls_table *nls_codepage,
+ const struct nls_table *nls_codepage,
int remap_special_chars);
extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
- const struct nls_table * codepage);
-extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
- const struct nls_table * cp, int mapChars);
+ const struct nls_table *codepage);
+extern int cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
+ const struct nls_table *cp, int mapChars);
extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const __u16 netfid, const __u64 len,
@@ -281,7 +284,7 @@ extern int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
const int waitFlag);
extern int CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const int get_flag,
- const __u64 len, struct file_lock *,
+ const __u64 len, struct file_lock *,
const __u16 lock_type, const int waitFlag);
extern int CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon);
extern int CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses);
@@ -291,54 +294,56 @@ extern void sesInfoFree(struct cifsSesInfo *);
extern struct cifsTconInfo *tconInfoAlloc(void);
extern void tconInfoFree(struct cifsTconInfo *);
-extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
+extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *);
extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *);
-extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
- __u32 expected_sequence_number);
-extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
-extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
+extern int cifs_verify_signature(struct smb_hdr *,
+ const struct mac_key *mac_key,
+ __u32 expected_sequence_number);
+extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn,
+ const char *pass);
+extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
const struct nls_table *);
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );
-extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
+extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
const struct nls_table *);
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
+extern void calc_lanman_hash(struct cifsSesInfo *ses, char *lnm_session_key);
#endif /* CIFS_WEAK_PW_HASH */
extern int CIFSSMBCopy(int xid,
struct cifsTconInfo *source_tcon,
const char *fromName,
const __u16 target_tid,
const char *toName, const int flags,
- const struct nls_table *nls_codepage,
+ const struct nls_table *nls_codepage,
int remap_special_chars);
-extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
- const int notify_subdirs,const __u16 netfid,
- __u32 filter, struct file * file, int multishot,
+extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
+ const int notify_subdirs, const __u16 netfid,
+ __u32 filter, struct file *file, int multishot,
const struct nls_table *nls_codepage);
extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName, char * EAData,
+ const unsigned char *searchName, char *EAData,
size_t bufsize, const struct nls_table *nls_codepage,
int remap_special_chars);
-extern ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
- const unsigned char * searchName,const unsigned char * ea_name,
- unsigned char * ea_value, size_t buf_size,
+extern ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName, const unsigned char *ea_name,
+ unsigned char *ea_value, size_t buf_size,
const struct nls_table *nls_codepage, int remap_special_chars);
-extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
- const char *fileName, const char * ea_name,
- const void * ea_value, const __u16 ea_value_len,
+extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon,
+ const char *fileName, const char *ea_name,
+ const void *ea_value, const __u16 ea_value_len,
const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon,
__u16 fid, char *acl_inf, const int buflen,
const int acl_type /* ACCESS vs. DEFAULT */);
extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
- char *acl_inf, const int buflen,const int acl_type,
+ char *acl_inf, const int buflen, const int acl_type,
const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
const unsigned char *fileName,
const char *local_acl, const int buflen, const int acl_type,
const struct nls_table *nls_codepage, int remap_special_chars);
extern int CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
- const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
+ const int netfid, __u64 * pExtAttrBits, __u64 *pMask);
#endif /* _CIFSPROTO_H */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 57419a176688..8eb102f940d4 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -48,7 +48,7 @@ static struct {
{LANMAN_PROT, "\2LM1.2X002"},
{LANMAN2_PROT, "\2LANMAN2.1"},
#endif /* weak password hashing for legacy clients */
- {CIFS_PROT, "\2NT LM 0.12"},
+ {CIFS_PROT, "\2NT LM 0.12"},
{POSIX_PROT, "\2POSIX 2"},
{BAD_PROT, "\2"}
};
@@ -61,7 +61,7 @@ static struct {
{LANMAN_PROT, "\2LM1.2X002"},
{LANMAN2_PROT, "\2LANMAN2.1"},
#endif /* weak password hashing for legacy clients */
- {CIFS_PROT, "\2NT LM 0.12"},
+ {CIFS_PROT, "\2NT LM 0.12"},
{BAD_PROT, "\2"}
};
#endif
@@ -84,17 +84,17 @@ static struct {
/* Mark as invalid, all open files on tree connections since they
were closed when session to server was lost */
-static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
+static void mark_open_files_invalid(struct cifsTconInfo *pTcon)
{
struct cifsFileInfo *open_file = NULL;
- struct list_head * tmp;
- struct list_head * tmp1;
+ struct list_head *tmp;
+ struct list_head *tmp1;
/* list all files open on tree connection and mark them invalid */
write_lock(&GlobalSMBSeslock);
list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
- open_file = list_entry(tmp,struct cifsFileInfo, tlist);
- if(open_file) {
+ open_file = list_entry(tmp, struct cifsFileInfo, tlist);
+ if (open_file) {
open_file->invalidHandle = TRUE;
}
}
@@ -113,75 +113,78 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
check for tcp and smb session status done differently
for those three - in the calling routine */
- if(tcon) {
- if(tcon->tidStatus == CifsExiting) {
+ if (tcon) {
+ if (tcon->tidStatus == CifsExiting) {
/* only tree disconnect, open, and write,
(and ulogoff which does not have tcon)
are allowed as we start force umount */
- if((smb_command != SMB_COM_WRITE_ANDX) &&
- (smb_command != SMB_COM_OPEN_ANDX) &&
+ if ((smb_command != SMB_COM_WRITE_ANDX) &&
+ (smb_command != SMB_COM_OPEN_ANDX) &&
(smb_command != SMB_COM_TREE_DISCONNECT)) {
- cFYI(1,("can not send cmd %d while umounting",
+ cFYI(1, ("can not send cmd %d while umounting",
smb_command));
return -ENODEV;
}
}
- if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
- (tcon->ses->server)){
+ if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+ (tcon->ses->server)) {
struct nls_table *nls_codepage;
- /* Give Demultiplex thread up to 10 seconds to
+ /* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket
timeout which is 7 seconds */
- while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+ while (tcon->ses->server->tcpStatus ==
+ CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q,
- (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
- if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+ (tcon->ses->server->tcpStatus ==
+ CifsGood), 10 * HZ);
+ if (tcon->ses->server->tcpStatus ==
+ CifsNeedReconnect) {
/* on "soft" mounts we wait once */
- if((tcon->retry == FALSE) ||
+ if ((tcon->retry == FALSE) ||
(tcon->ses->status == CifsExiting)) {
- cFYI(1,("gave up waiting on reconnect in smb_init"));
+ cFYI(1, ("gave up waiting on "
+ "reconnect in smb_init"));
return -EHOSTDOWN;
} /* else "hard" mount - keep retrying
until process is killed or server
comes back on-line */
} else /* TCP session is reestablished now */
break;
-
}
-
+
nls_codepage = load_nls_default();
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem);
- if(tcon->ses->status == CifsNeedReconnect)
- rc = cifs_setup_session(0, tcon->ses,
+ if (tcon->ses->status == CifsNeedReconnect)
+ rc = cifs_setup_session(0, tcon->ses,
nls_codepage);
- if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+ if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
mark_open_files_invalid(tcon);
- rc = CIFSTCon(0, tcon->ses, tcon->treeName,
+ rc = CIFSTCon(0, tcon->ses, tcon->treeName,
tcon, nls_codepage);
up(&tcon->ses->sesSem);
/* tell server which Unix caps we support */
if (tcon->ses->capabilities & CAP_UNIX)
reset_cifs_unix_caps(0 /* no xid */,
- tcon,
+ tcon,
NULL /* we do not know sb */,
- NULL /* no vol info */);
+ NULL /* no vol info */);
/* BB FIXME add code to check if wsize needs
update due to negotiated smb buffer size
shrinking */
- if(rc == 0)
+ if (rc == 0)
atomic_inc(&tconInfoReconnectCount);
cFYI(1, ("reconnect tcon rc = %d", rc));
- /* Removed call to reopen open files here -
- it is safer (and faster) to reopen files
+ /* Removed call to reopen open files here.
+ It is safer (and faster) to reopen files
one at a time as needed in read and write */
- /* Check if handle based operation so we
+ /* Check if handle based operation so we
know whether we can continue or not without
returning to caller to reset file handle */
- switch(smb_command) {
+ switch (smb_command) {
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
case SMB_COM_CLOSE:
@@ -200,7 +203,7 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
return -EIO;
}
}
- if(rc)
+ if (rc)
return rc;
*request_buf = cifs_small_buf_get();
@@ -209,23 +212,24 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
return -ENOMEM;
}
- header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
+ header_assemble((struct smb_hdr *) *request_buf, smb_command,
+ tcon, wct);
- if(tcon != NULL)
- cifs_stats_inc(&tcon->num_smbs_sent);
+ if (tcon != NULL)
+ cifs_stats_inc(&tcon->num_smbs_sent);
return rc;
}
int
-small_smb_init_no_tc(const int smb_command, const int wct,
+small_smb_init_no_tc(const int smb_command, const int wct,
struct cifsSesInfo *ses, void **request_buf)
{
int rc;
- struct smb_hdr * buffer;
+ struct smb_hdr *buffer;
rc = small_smb_init(smb_command, wct, NULL, request_buf);
- if(rc)
+ if (rc)
return rc;
buffer = (struct smb_hdr *)*request_buf;
@@ -237,7 +241,7 @@ small_smb_init_no_tc(const int smb_command, const int wct,
/* uid, tid can stay at zero as set in header assemble */
- /* BB add support for turning on the signing when
+ /* BB add support for turning on the signing when
this function is used after 1st of session setup requests */
return rc;
@@ -254,52 +258,53 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
check for tcp and smb session status done differently
for those three - in the calling routine */
- if(tcon) {
- if(tcon->tidStatus == CifsExiting) {
+ if (tcon) {
+ if (tcon->tidStatus == CifsExiting) {
/* only tree disconnect, open, and write,
(and ulogoff which does not have tcon)
are allowed as we start force umount */
- if((smb_command != SMB_COM_WRITE_ANDX) &&
+ if ((smb_command != SMB_COM_WRITE_ANDX) &&
(smb_command != SMB_COM_OPEN_ANDX) &&
(smb_command != SMB_COM_TREE_DISCONNECT)) {
- cFYI(1,("can not send cmd %d while umounting",
+ cFYI(1, ("can not send cmd %d while umounting",
smb_command));
return -ENODEV;
}
}
- if((tcon->ses) && (tcon->ses->status != CifsExiting) &&
- (tcon->ses->server)){
+ if ((tcon->ses) && (tcon->ses->status != CifsExiting) &&
+ (tcon->ses->server)) {
struct nls_table *nls_codepage;
/* Give Demultiplex thread up to 10 seconds to
reconnect, should be greater than cifs socket
timeout which is 7 seconds */
- while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
+ while (tcon->ses->server->tcpStatus ==
+ CifsNeedReconnect) {
wait_event_interruptible_timeout(tcon->ses->server->response_q,
- (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
- if(tcon->ses->server->tcpStatus ==
+ (tcon->ses->server->tcpStatus ==
+ CifsGood), 10 * HZ);
+ if (tcon->ses->server->tcpStatus ==
CifsNeedReconnect) {
/* on "soft" mounts we wait once */
- if((tcon->retry == FALSE) ||
+ if ((tcon->retry == FALSE) ||
(tcon->ses->status == CifsExiting)) {
- cFYI(1,("gave up waiting on reconnect in smb_init"));
+ cFYI(1, ("gave up waiting on "
+ "reconnect in smb_init"));
return -EHOSTDOWN;
} /* else "hard" mount - keep retrying
until process is killed or server
comes on-line */
} else /* TCP session is reestablished now */
break;
-
}
-
nls_codepage = load_nls_default();
/* need to prevent multiple threads trying to
simultaneously reconnect the same SMB session */
down(&tcon->ses->sesSem);
- if(tcon->ses->status == CifsNeedReconnect)
- rc = cifs_setup_session(0, tcon->ses,
+ if (tcon->ses->status == CifsNeedReconnect)
+ rc = cifs_setup_session(0, tcon->ses,
nls_codepage);
- if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
+ if (!rc && (tcon->tidStatus == CifsNeedReconnect)) {
mark_open_files_invalid(tcon);
rc = CIFSTCon(0, tcon->ses, tcon->treeName,
tcon, nls_codepage);
@@ -307,24 +312,24 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* tell server which Unix caps we support */
if (tcon->ses->capabilities & CAP_UNIX)
reset_cifs_unix_caps(0 /* no xid */,
- tcon,
+ tcon,
NULL /* do not know sb */,
NULL /* no vol info */);
/* BB FIXME add code to check if wsize needs
update due to negotiated smb buffer size
shrinking */
- if(rc == 0)
+ if (rc == 0)
atomic_inc(&tconInfoReconnectCount);
cFYI(1, ("reconnect tcon rc = %d", rc));
- /* Removed call to reopen open files here -
- it is safer (and faster) to reopen files
+ /* Removed call to reopen open files here.
+ It is safer (and faster) to reopen files
one at a time as needed in read and write */
- /* Check if handle based operation so we
+ /* Check if handle based operation so we
know whether we can continue or not without
returning to caller to reset file handle */
- switch(smb_command) {
+ switch (smb_command) {
case SMB_COM_READ_ANDX:
case SMB_COM_WRITE_ANDX:
case SMB_COM_CLOSE:
@@ -343,7 +348,7 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
return -EIO;
}
}
- if(rc)
+ if (rc)
return rc;
*request_buf = cifs_buf_get();
@@ -355,48 +360,48 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
/* potential retries of smb operations it turns out we can determine */
/* from the mid flags when the request buffer can be resent without */
/* having to use a second distinct buffer for the response */
- if(response_buf)
- *response_buf = *request_buf;
+ if (response_buf)
+ *response_buf = *request_buf;
header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
wct /*wct */ );
- if(tcon != NULL)
- cifs_stats_inc(&tcon->num_smbs_sent);
+ if (tcon != NULL)
+ cifs_stats_inc(&tcon->num_smbs_sent);
return rc;
}
-static int validate_t2(struct smb_t2_rsp * pSMB)
+static int validate_t2(struct smb_t2_rsp *pSMB)
{
int rc = -EINVAL;
int total_size;
- char * pBCC;
+ char *pBCC;
/* check for plausible wct, bcc and t2 data and parm sizes */
/* check for parm and data offset going beyond end of smb */
- if(pSMB->hdr.WordCount >= 10) {
- if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
+ if (pSMB->hdr.WordCount >= 10) {
+ if ((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
(le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
/* check that bcc is at least as big as parms + data */
/* check that bcc is less than negotiated smb buffer */
total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
- if(total_size < 512) {
- total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
+ if (total_size < 512) {
+ total_size +=
+ le16_to_cpu(pSMB->t2_rsp.DataCount);
/* BCC le converted in SendReceive */
- pBCC = (pSMB->hdr.WordCount * 2) +
+ pBCC = (pSMB->hdr.WordCount * 2) +
sizeof(struct smb_hdr) +
(char *)pSMB;
- if((total_size <= (*(u16 *)pBCC)) &&
- (total_size <
+ if ((total_size <= (*(u16 *)pBCC)) &&
+ (total_size <
CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
return 0;
}
-
}
}
}
- cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
+ cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB,
sizeof(struct smb_t2_rsp) + 16);
return rc;
}
@@ -408,12 +413,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
int rc = 0;
int bytes_returned;
int i;
- struct TCP_Server_Info * server;
+ struct TCP_Server_Info *server;
u16 count;
unsigned int secFlags;
u16 dialect;
- if(ses->server)
+ if (ses->server)
server = ses->server;
else {
rc = -EIO;
@@ -425,20 +430,20 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
return rc;
/* if any of auth flags (ie not sign or seal) are overriden use them */
- if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
- secFlags = ses->overrideSecFlg;
+ if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
+ secFlags = ses->overrideSecFlg; /* BB FIXME fix sign flags? */
else /* if override flags set only sign/seal OR them with global auth */
secFlags = extended_security | ses->overrideSecFlg;
- cFYI(1,("secFlags 0x%x",secFlags));
+ cFYI(1, ("secFlags 0x%x", secFlags));
pSMB->hdr.Mid = GetNextMid(server);
pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-
+
count = 0;
- for(i=0;i<CIFS_NUM_PROT;i++) {
+ for (i = 0; i < CIFS_NUM_PROT; i++) {
strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
count += strlen(protocols[i].name) + 1;
/* null at end of source and target buffers anyway */
@@ -448,26 +453,26 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc != 0)
+ if (rc != 0)
goto neg_err_exit;
dialect = le16_to_cpu(pSMBr->DialectIndex);
- cFYI(1,("Dialect: %d", dialect));
+ cFYI(1, ("Dialect: %d", dialect));
/* Check wct = 1 error case */
- if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
+ if ((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
/* core returns wct = 1, but we do not ask for core - otherwise
- small wct just comes when dialect index is -1 indicating we
+ small wct just comes when dialect index is -1 indicating we
could not negotiate a common dialect */
rc = -EOPNOTSUPP;
goto neg_err_exit;
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
- } else if((pSMBr->hdr.WordCount == 13)
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+ } else if ((pSMBr->hdr.WordCount == 13)
&& ((dialect == LANMAN_PROT)
|| (dialect == LANMAN2_PROT))) {
__s16 tmp;
- struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
+ struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
- if((secFlags & CIFSSEC_MAY_LANMAN) ||
+ if ((secFlags & CIFSSEC_MAY_LANMAN) ||
(secFlags & CIFSSEC_MAY_PLNTXT))
server->secType = LANMAN;
else {
@@ -475,7 +480,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
" in /proc/fs/cifs/SecurityFlags"));
rc = -EOPNOTSUPP;
goto neg_err_exit;
- }
+ }
server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
@@ -483,7 +488,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
/* even though we do not use raw we might as well set this
accurately, in case we ever find a need for it */
- if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
+ if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
server->maxRw = 0xFF00;
server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
} else {
@@ -504,29 +509,29 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
utc = CURRENT_TIME;
ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
le16_to_cpu(rsp->SrvTime.Time));
- cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
- (int)ts.tv_sec, (int)utc.tv_sec,
+ cFYI(1, ("SrvTime %d sec since 1970 (utc: %d) diff: %d",
+ (int)ts.tv_sec, (int)utc.tv_sec,
(int)(utc.tv_sec - ts.tv_sec)));
val = (int)(utc.tv_sec - ts.tv_sec);
seconds = val < 0 ? -val : val;
result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
remain = seconds % MIN_TZ_ADJ;
- if(remain >= (MIN_TZ_ADJ / 2))
+ if (remain >= (MIN_TZ_ADJ / 2))
result += MIN_TZ_ADJ;
- if(val < 0)
+ if (val < 0)
result = - result;
server->timeAdj = result;
} else {
server->timeAdj = (int)tmp;
server->timeAdj *= 60; /* also in seconds */
}
- cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
+ cFYI(1, ("server->timeAdj: %d seconds", server->timeAdj));
/* BB get server time for time conversions and add
- code to use it and timezone since this is not UTC */
+ code to use it and timezone since this is not UTC */
- if (rsp->EncryptionKeyLength ==
+ if (rsp->EncryptionKeyLength ==
cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
memcpy(server->cryptKey, rsp->EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
@@ -535,39 +540,39 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
goto neg_err_exit;
}
- cFYI(1,("LANMAN negotiated"));
+ cFYI(1, ("LANMAN negotiated"));
/* we will not end up setting signing flags - as no signing
was in LANMAN and server did not return the flags on */
goto signing_check;
#else /* weak security disabled */
- } else if(pSMBr->hdr.WordCount == 13) {
- cERROR(1,("mount failed, cifs module not built "
+ } else if (pSMBr->hdr.WordCount == 13) {
+ cERROR(1, ("mount failed, cifs module not built "
"with CIFS_WEAK_PW_HASH support"));
rc = -EOPNOTSUPP;
#endif /* WEAK_PW_HASH */
goto neg_err_exit;
- } else if(pSMBr->hdr.WordCount != 17) {
+ } else if (pSMBr->hdr.WordCount != 17) {
/* unknown wct */
rc = -EOPNOTSUPP;
goto neg_err_exit;
}
/* else wct == 17 NTLM */
server->secMode = pSMBr->SecurityMode;
- if((server->secMode & SECMODE_USER) == 0)
- cFYI(1,("share mode security"));
+ if ((server->secMode & SECMODE_USER) == 0)
+ cFYI(1, ("share mode security"));
- if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
+ if ((server->secMode & SECMODE_PW_ENCRYPT) == 0)
#ifdef CONFIG_CIFS_WEAK_PW_HASH
if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
#endif /* CIFS_WEAK_PW_HASH */
- cERROR(1,("Server requests plain text password"
+ cERROR(1, ("Server requests plain text password"
" but client support disabled"));
- if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+ if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
server->secType = NTLMv2;
- else if(secFlags & CIFSSEC_MAY_NTLM)
+ else if (secFlags & CIFSSEC_MAY_NTLM)
server->secType = NTLM;
- else if(secFlags & CIFSSEC_MAY_NTLMV2)
+ else if (secFlags & CIFSSEC_MAY_NTLMV2)
server->secType = NTLMv2;
/* else krb5 ... any others ... */
@@ -596,7 +601,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
/* BB might be helpful to save off the domain of server here */
- if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
+ if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) &&
(server->capabilities & CAP_EXTENDED_SECURITY)) {
count = pSMBr->ByteCount;
if (count < 16)
@@ -620,7 +625,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
SecurityBlob,
count - 16,
&server->secType);
- if(rc == 1) {
+ if (rc == 1) {
/* BB Need to fill struct for sessetup here */
rc = -EOPNOTSUPP;
} else {
@@ -633,26 +638,37 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
#ifdef CONFIG_CIFS_WEAK_PW_HASH
signing_check:
#endif
- if(sign_CIFS_PDUs == FALSE) {
- if(server->secMode & SECMODE_SIGN_REQUIRED)
- cERROR(1,("Server requires "
- "/proc/fs/cifs/PacketSigningEnabled to be on"));
- server->secMode &=
+ if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
+ /* MUST_SIGN already includes the MAY_SIGN FLAG
+ so if this is zero it means that signing is disabled */
+ cFYI(1, ("Signing disabled"));
+ if (server->secMode & SECMODE_SIGN_REQUIRED)
+ cERROR(1, ("Server requires "
+ "/proc/fs/cifs/PacketSigningEnabled "
+ "to be on"));
+ server->secMode &=
~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
- } else if(sign_CIFS_PDUs == 1) {
- if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
- server->secMode &=
- ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
- } else if(sign_CIFS_PDUs == 2) {
- if((server->secMode &
+ } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
+ /* signing required */
+ cFYI(1, ("Must sign - secFlags 0x%x", secFlags));
+ if ((server->secMode &
(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
- cERROR(1,("signing required but server lacks support"));
- }
+ cERROR(1,
+ ("signing required but server lacks support"));
+ rc = -EOPNOTSUPP;
+ } else
+ server->secMode |= SECMODE_SIGN_REQUIRED;
+ } else {
+ /* signing optional ie CIFSSEC_MAY_SIGN */
+ if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
+ server->secMode &=
+ ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
}
-neg_err_exit:
+
+neg_err_exit:
cifs_buf_release(pSMB);
- cFYI(1,("negprot rc %d",rc));
+ cFYI(1, ("negprot rc %d", rc));
return rc;
}
@@ -669,7 +685,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
* If last user of the connection and
* connection alive - disconnect it
* If this is the last connection on the server session disconnect it
- * (and inside session disconnect we should check if tcp socket needs
+ * (and inside session disconnect we should check if tcp socket needs
* to be freed and kernel thread woken up).
*/
if (tcon)
@@ -683,18 +699,18 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
return -EBUSY;
}
- /* No need to return error on this operation if tid invalidated and
+ /* No need to return error on this operation if tid invalidated and
closed on server already e.g. due to tcp session crashing */
- if(tcon->tidStatus == CifsNeedReconnect) {
+ if (tcon->tidStatus == CifsNeedReconnect) {
up(&tcon->tconSem);
- return 0;
+ return 0;
}
- if((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
+ if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) {
up(&tcon->tconSem);
return -EIO;
}
- rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
+ rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon,
(void **)&smb_buffer);
if (rc) {
up(&tcon->tconSem);
@@ -711,7 +727,7 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
cifs_small_buf_release(smb_buffer);
up(&tcon->tconSem);
- /* No need to return error on this operation if tid invalidated and
+ /* No need to return error on this operation if tid invalidated and
closed on server already e.g. due to tcp session crashing */
if (rc == -EAGAIN)
rc = 0;
@@ -745,11 +761,11 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
}
smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
-
- if(ses->server) {
+
+ if (ses->server) {
pSMB->hdr.Mid = GetNextMid(ses->server);
- if(ses->server->secMode &
+ if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
}
@@ -772,7 +788,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
cifs_small_buf_release(pSMB);
/* if session dead then we do not need to do ulogoff,
- since server closed smb session, no sense reporting
+ since server closed smb session, no sense reporting
error */
if (rc == -EAGAIN)
rc = 0;
@@ -780,6 +796,82 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
}
int
+CIFSPOSIXDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+ __u16 type, const struct nls_table *nls_codepage, int remap)
+{
+ TRANSACTION2_SPI_REQ *pSMB = NULL;
+ TRANSACTION2_SPI_RSP *pSMBr = NULL;
+ struct unlink_psx_rq *pRqD;
+ int name_len;
+ int rc = 0;
+ int bytes_returned = 0;
+ __u16 params, param_offset, offset, byte_count;
+
+ cFYI(1, ("In POSIX delete"));
+PsxDelete:
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len =
+ cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+ PATH_MAX, nls_codepage, remap);
+ name_len++; /* trailing null */
+ name_len *= 2;
+ } else { /* BB add path length overrun check */
+ name_len = strnlen(fileName, PATH_MAX);
+ name_len++; /* trailing null */
+ strncpy(pSMB->FileName, fileName, name_len);
+ }
+
+ params = 6 + name_len;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = 0; /* BB double check this with jra */
+ pSMB->MaxSetupCount = 0;
+ pSMB->Reserved = 0;
+ pSMB->Flags = 0;
+ pSMB->Timeout = 0;
+ pSMB->Reserved2 = 0;
+ param_offset = offsetof(struct smb_com_transaction2_spi_req,
+ InformationLevel) - 4;
+ offset = param_offset + params;
+
+ /* Setup pointer to Request Data (inode type) */
+ pRqD = (struct unlink_psx_rq *)(((char *)&pSMB->hdr.Protocol) + offset);
+ pRqD->type = cpu_to_le16(type);
+ pSMB->ParameterOffset = cpu_to_le16(param_offset);
+ pSMB->DataOffset = cpu_to_le16(offset);
+ pSMB->SetupCount = 1;
+ pSMB->Reserved3 = 0;
+ pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+ byte_count = 3 /* pad */ + params + sizeof(struct unlink_psx_rq);
+
+ pSMB->DataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
+ pSMB->TotalDataCount = cpu_to_le16(sizeof(struct unlink_psx_rq));
+ pSMB->ParameterCount = cpu_to_le16(params);
+ pSMB->TotalParameterCount = pSMB->ParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_UNLINK);
+ pSMB->Reserved4 = 0;
+ pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->ByteCount = cpu_to_le16(byte_count);
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("Posix delete returned %d", rc));
+ }
+ cifs_buf_release(pSMB);
+
+ cifs_stats_inc(&tcon->num_deletes);
+
+ if (rc == -EAGAIN)
+ goto PsxDelete;
+
+ return rc;
+}
+
+int
CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon, const char *fileName,
const struct nls_table *nls_codepage, int remap)
{
@@ -797,7 +889,7 @@ DelFileRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
+ cifsConvertToUCS((__le16 *) pSMB->fileName, fileName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -816,7 +908,7 @@ DelFileRetry:
cifs_stats_inc(&tcon->num_deletes);
if (rc) {
cFYI(1, ("Error in RMFile = %d", rc));
- }
+ }
cifs_buf_release(pSMB);
if (rc == -EAGAIN)
@@ -826,7 +918,7 @@ DelFileRetry:
}
int
-CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
+CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon, const char *dirName,
const struct nls_table *nls_codepage, int remap)
{
DELETE_DIRECTORY_REQ *pSMB = NULL;
@@ -887,7 +979,7 @@ MkDirRetry:
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
+ name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -916,7 +1008,7 @@ MkDirRetry:
int
CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
__u64 mode, __u16 * netfid, FILE_UNIX_BASIC_INFO *pRetData,
- __u32 *pOplock, const char *name,
+ __u32 *pOplock, const char *name,
const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -924,7 +1016,6 @@ CIFSPOSIXCreate(const int xid, struct cifsTconInfo *tcon, __u32 posix_flags,
int name_len;
int rc = 0;
int bytes_returned = 0;
- char *data_offset;
__u16 params, param_offset, offset, byte_count, count;
OPEN_PSX_REQ * pdata;
OPEN_PSX_RSP * psx_rsp;
@@ -958,13 +1049,12 @@ PsxCreat:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset);
pdata->Level = SMB_QUERY_FILE_UNIX_BASIC;
pdata->Permissions = cpu_to_le64(mode);
- pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
+ pdata->PosixOpenFlags = cpu_to_le32(posix_flags);
pdata->OpenFlags = cpu_to_le32(*pOplock);
pSMB->ParameterOffset = cpu_to_le16(param_offset);
pSMB->DataOffset = cpu_to_le16(offset);
@@ -979,7 +1069,7 @@ PsxCreat:
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->InformationLevel = cpu_to_le16(SMB_POSIX_OPEN);
pSMB->Reserved4 = 0;
- pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -988,7 +1078,7 @@ PsxCreat:
goto psx_create_err;
}
- cFYI(1,("copying inode info"));
+ cFYI(1, ("copying inode info"));
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP))) {
@@ -997,34 +1087,33 @@ PsxCreat:
}
/* copy return information to pRetData */
- psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
+ psx_rsp = (OPEN_PSX_RSP *)((char *) &pSMBr->hdr.Protocol
+ le16_to_cpu(pSMBr->t2.DataOffset));
-
+
*pOplock = le16_to_cpu(psx_rsp->OplockFlags);
- if(netfid)
+ if (netfid)
*netfid = psx_rsp->Fid; /* cifs fid stays in le */
/* Let caller know file was created so we can set the mode. */
/* Do we care about the CreateAction in any other cases? */
- if(cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
+ if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction)
*pOplock |= CIFS_CREATE_ACTION;
/* check to make sure response data is there */
- if(psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
+ if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) {
pRetData->Type = -1; /* unknown */
#ifdef CONFIG_CIFS_DEBUG2
- cFYI(1,("unknown type"));
+ cFYI(1, ("unknown type"));
#endif
} else {
- if(pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
+ if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP)
+ sizeof(FILE_UNIX_BASIC_INFO)) {
- cERROR(1,("Open response data too small"));
+ cERROR(1, ("Open response data too small"));
pRetData->Type = -1;
goto psx_create_err;
}
- memcpy((char *) pRetData,
+ memcpy((char *) pRetData,
(char *)psx_rsp + sizeof(OPEN_PSX_RSP),
sizeof (FILE_UNIX_BASIC_INFO));
}
-
psx_create_err:
cifs_buf_release(pSMB);
@@ -1034,7 +1123,7 @@ psx_create_err:
if (rc == -EAGAIN)
goto PsxCreat;
- return rc;
+ return rc;
}
static __u16 convert_disposition(int disposition)
@@ -1061,7 +1150,7 @@ static __u16 convert_disposition(int disposition)
ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC;
break;
default:
- cFYI(1,("unknown disposition %d",disposition));
+ cFYI(1, ("unknown disposition %d", disposition));
ofun = SMBOPEN_OAPPEND; /* regular open */
}
return ofun;
@@ -1071,7 +1160,7 @@ int
SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
const int access_flags, const int create_options, __u16 * netfid,
- int *pOplock, FILE_ALL_INFO * pfile_info,
+ int *pOplock, FILE_ALL_INFO * pfile_info,
const struct nls_table *nls_codepage, int remap)
{
int rc = -EACCES;
@@ -1113,16 +1202,16 @@ OldOpenRetry:
1 = write
2 = rw
3 = execute
- */
+ */
pSMB->Mode = cpu_to_le16(2);
pSMB->Mode |= cpu_to_le16(0x40); /* deny none */
/* set file as system file if special file such
as fifo and server expecting SFU style and
no Unix extensions */
- if(create_options & CREATE_OPTION_SPECIAL)
- pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
- else
+ if (create_options & CREATE_OPTION_SPECIAL)
+ pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM);
+ else
pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */
/* if ((omode & S_IWUGO) == 0)
@@ -1132,7 +1221,8 @@ OldOpenRetry:
being created */
/* BB FIXME BB */
-/* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */
+/* pSMB->CreateOptions = cpu_to_le32(create_options &
+ CREATE_OPTIONS_MASK); */
/* BB FIXME END BB */
pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY);
@@ -1143,7 +1233,7 @@ OldOpenRetry:
pSMB->ByteCount = cpu_to_le16(count);
/* long_op set to 1 to allow for oplock break timeouts */
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 1);
+ (struct smb_hdr *) pSMBr, &bytes_returned, 1);
cifs_stats_inc(&tcon->num_opens);
if (rc) {
cFYI(1, ("Error in Open = %d", rc));
@@ -1156,17 +1246,17 @@ OldOpenRetry:
/* Let caller know file was created so we can set the mode. */
/* Do we care about the CreateAction in any other cases? */
/* BB FIXME BB */
-/* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+/* if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
*pOplock |= CIFS_CREATE_ACTION; */
/* BB FIXME END */
- if(pfile_info) {
+ if (pfile_info) {
pfile_info->CreationTime = 0; /* BB convert CreateTime*/
pfile_info->LastAccessTime = 0; /* BB fixme */
pfile_info->LastWriteTime = 0; /* BB fixme */
pfile_info->ChangeTime = 0; /* BB fixme */
pfile_info->Attributes =
- cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
+ cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes));
/* the file_info buf is endian converted by caller */
pfile_info->AllocationSize =
cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile));
@@ -1185,7 +1275,7 @@ int
CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
const int access_flags, const int create_options, __u16 * netfid,
- int *pOplock, FILE_ALL_INFO * pfile_info,
+ int *pOplock, FILE_ALL_INFO * pfile_info,
const struct nls_table *nls_codepage, int remap)
{
int rc = -EACCES;
@@ -1228,7 +1318,7 @@ openRetry:
/* set file as system file if special file such
as fifo and server expecting SFU style and
no Unix extensions */
- if(create_options & CREATE_OPTION_SPECIAL)
+ if (create_options & CREATE_OPTION_SPECIAL)
pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM);
else
pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
@@ -1266,10 +1356,10 @@ openRetry:
*netfid = pSMBr->Fid; /* cifs fid stays in le */
/* Let caller know file was created so we can set the mode. */
/* Do we care about the CreateAction in any other cases? */
- if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
- *pOplock |= CIFS_CREATE_ACTION;
- if(pfile_info) {
- memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
+ if (cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
+ *pOplock |= CIFS_CREATE_ACTION;
+ if (pfile_info) {
+ memcpy((char *)pfile_info, (char *)&pSMBr->CreationTime,
36 /* CreationTime to Attributes */);
/* the file_info buf is endian converted by caller */
pfile_info->AllocationSize = pSMBr->AllocationSize;
@@ -1285,10 +1375,9 @@ openRetry:
}
int
-CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
- const int netfid, const unsigned int count,
- const __u64 lseek, unsigned int *nbytes, char **buf,
- int * pbuf_type)
+CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid,
+ const unsigned int count, const __u64 lseek, unsigned int *nbytes,
+ char **buf, int *pbuf_type)
{
int rc = -EACCES;
READ_REQ *pSMB = NULL;
@@ -1298,8 +1387,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
int resp_buf_type = 0;
struct kvec iov[1];
- cFYI(1,("Reading %d bytes on fid %d",count,netfid));
- if(tcon->ses->capabilities & CAP_LARGE_FILES)
+ cFYI(1, ("Reading %d bytes on fid %d", count, netfid));
+ if (tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 12;
else
wct = 10; /* old style read */
@@ -1316,28 +1405,28 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = netfid;
pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
- if(wct == 12)
+ if (wct == 12)
pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
- else if((lseek >> 32) > 0) /* can not handle this big offset for old */
+ else if ((lseek >> 32) > 0) /* can not handle this big offset for old */
return -EIO;
pSMB->Remaining = 0;
pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
- if(wct == 12)
+ if (wct == 12)
pSMB->ByteCount = 0; /* no need to do le conversion since 0 */
else {
/* old style read */
- struct smb_com_readx_req * pSMBW =
+ struct smb_com_readx_req *pSMBW =
(struct smb_com_readx_req *)pSMB;
pSMBW->ByteCount = 0;
}
iov[0].iov_base = (char *)pSMB;
iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
- rc = SendReceive2(xid, tcon->ses, iov,
+ rc = SendReceive2(xid, tcon->ses, iov,
1 /* num iovecs */,
- &resp_buf_type, 0);
+ &resp_buf_type, 0);
cifs_stats_inc(&tcon->num_reads);
pSMBr = (READ_RSP *)iov[0].iov_base;
if (rc) {
@@ -1351,33 +1440,34 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
/*check that DataLength would not go beyond end of SMB */
if ((data_length > CIFSMaxBufSize)
|| (data_length > count)) {
- cFYI(1,("bad length %d for count %d",data_length,count));
+ cFYI(1, ("bad length %d for count %d",
+ data_length, count));
rc = -EIO;
*nbytes = 0;
} else {
pReadData = (char *) (&pSMBr->hdr.Protocol) +
le16_to_cpu(pSMBr->DataOffset);
-/* if(rc = copy_to_user(buf, pReadData, data_length)) {
- cERROR(1,("Faulting on read rc = %d",rc));
- rc = -EFAULT;
+/* if (rc = copy_to_user(buf, pReadData, data_length)) {
+ cERROR(1,("Faulting on read rc = %d",rc));
+ rc = -EFAULT;
}*/ /* can not use copy_to_user when using page cache*/
- if(*buf)
- memcpy(*buf,pReadData,data_length);
+ if (*buf)
+ memcpy(*buf, pReadData, data_length);
}
}
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
- if(*buf) {
- if(resp_buf_type == CIFS_SMALL_BUFFER)
+ if (*buf) {
+ if (resp_buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(iov[0].iov_base);
- else if(resp_buf_type == CIFS_LARGE_BUFFER)
+ else if (resp_buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(iov[0].iov_base);
- } else if(resp_buf_type != CIFS_NO_BUFFER) {
- /* return buffer to caller to free */
- *buf = iov[0].iov_base;
- if(resp_buf_type == CIFS_SMALL_BUFFER)
+ } else if (resp_buf_type != CIFS_NO_BUFFER) {
+ /* return buffer to caller to free */
+ *buf = iov[0].iov_base;
+ if (resp_buf_type == CIFS_SMALL_BUFFER)
*pbuf_type = CIFS_SMALL_BUFFER;
- else if(resp_buf_type == CIFS_LARGE_BUFFER)
+ else if (resp_buf_type == CIFS_LARGE_BUFFER)
*pbuf_type = CIFS_LARGE_BUFFER;
} /* else no valid buffer on return - leave as null */
@@ -1391,7 +1481,7 @@ int
CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
const int netfid, const unsigned int count,
const __u64 offset, unsigned int *nbytes, const char *buf,
- const char __user * ubuf, const int long_op)
+ const char __user *ubuf, const int long_op)
{
int rc = -EACCES;
WRITE_REQ *pSMB = NULL;
@@ -1401,10 +1491,10 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
__u16 byte_count;
/* cFYI(1,("write at %lld %d bytes",offset,count));*/
- if(tcon->ses == NULL)
+ if (tcon->ses == NULL)
return -ECONNABORTED;
- if(tcon->ses->capabilities & CAP_LARGE_FILES)
+ if (tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 14;
else
wct = 12;
@@ -1420,20 +1510,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = netfid;
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
- if(wct == 14)
+ if (wct == 14)
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
- else if((offset >> 32) > 0) /* can not handle this big offset for old */
+ else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
return -EIO;
-
+
pSMB->Reserved = 0xFFFFFFFF;
pSMB->WriteMode = 0;
pSMB->Remaining = 0;
- /* Can increase buffer size if buffer is big enough in some cases - ie we
+ /* Can increase buffer size if buffer is big enough in some cases ie we
can send more if LARGE_WRITE_X capability returned by the server and if
our buffer is big enough or if we convert to iovecs on socket writes
and eliminate the copy to the CIFS buffer */
- if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
+ if (tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
} else {
bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
@@ -1443,11 +1533,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
if (bytes_sent > count)
bytes_sent = count;
pSMB->DataOffset =
- cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
- if(buf)
- memcpy(pSMB->Data,buf,bytes_sent);
- else if(ubuf) {
- if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
+ cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
+ if (buf)
+ memcpy(pSMB->Data, buf, bytes_sent);
+ else if (ubuf) {
+ if (copy_from_user(pSMB->Data, ubuf, bytes_sent)) {
cifs_buf_release(pSMB);
return -EFAULT;
}
@@ -1456,7 +1546,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
cifs_buf_release(pSMB);
return -EINVAL;
} /* else setting file size with write of zero bytes */
- if(wct == 14)
+ if (wct == 14)
byte_count = bytes_sent + 1; /* pad */
else /* wct == 12 */ {
byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */
@@ -1465,10 +1555,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
pSMB->hdr.smb_buf_length += byte_count;
- if(wct == 14)
+ if (wct == 14)
pSMB->ByteCount = cpu_to_le16(byte_count);
- else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */
- struct smb_com_writex_req * pSMBW =
+ else { /* old style write has byte count 4 bytes earlier
+ so 4 bytes pad */
+ struct smb_com_writex_req *pSMBW =
(struct smb_com_writex_req *)pSMB;
pSMBW->ByteCount = cpu_to_le16(byte_count);
}
@@ -1487,7 +1578,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
cifs_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
@@ -1505,9 +1596,9 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
int smb_hdr_len;
int resp_buf_type = 0;
- cFYI(1,("write2 at %lld %d bytes", (long long)offset, count));
+ cFYI(1, ("write2 at %lld %d bytes", (long long)offset, count));
- if(tcon->ses->capabilities & CAP_LARGE_FILES)
+ if (tcon->ses->capabilities & CAP_LARGE_FILES)
wct = 14;
else
wct = 12;
@@ -1521,37 +1612,37 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = netfid;
pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
- if(wct == 14)
+ if (wct == 14)
pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
- else if((offset >> 32) > 0) /* can not handle this big offset for old */
+ else if ((offset >> 32) > 0) /* can not handle big offset for old srv */
return -EIO;
pSMB->Reserved = 0xFFFFFFFF;
pSMB->WriteMode = 0;
pSMB->Remaining = 0;
pSMB->DataOffset =
- cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
+ cpu_to_le16(offsetof(struct smb_com_write_req, Data) - 4);
pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF);
pSMB->DataLengthHigh = cpu_to_le16(count >> 16);
smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
- if(wct == 14)
+ if (wct == 14)
pSMB->hdr.smb_buf_length += count+1;
else /* wct == 12 */
- pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
- if(wct == 14)
+ pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */
+ if (wct == 14)
pSMB->ByteCount = cpu_to_le16(count + 1);
else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ {
- struct smb_com_writex_req * pSMBW =
+ struct smb_com_writex_req *pSMBW =
(struct smb_com_writex_req *)pSMB;
pSMBW->ByteCount = cpu_to_le16(count + 5);
}
iov[0].iov_base = pSMB;
- if(wct == 14)
+ if (wct == 14)
iov[0].iov_len = smb_hdr_len + 4;
else /* wct == 12 pad bigger by four bytes */
iov[0].iov_len = smb_hdr_len + 8;
-
+
rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
long_op);
@@ -1559,7 +1650,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
if (rc) {
cFYI(1, ("Send error Write2 = %d", rc));
*nbytes = 0;
- } else if(resp_buf_type == 0) {
+ } else if (resp_buf_type == 0) {
/* presumably this can not happen, but best to be safe */
rc = -EIO;
*nbytes = 0;
@@ -1568,15 +1659,15 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
*nbytes = le16_to_cpu(pSMBr->CountHigh);
*nbytes = (*nbytes) << 16;
*nbytes += le16_to_cpu(pSMBr->Count);
- }
+ }
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
- if(resp_buf_type == CIFS_SMALL_BUFFER)
+ if (resp_buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(iov[0].iov_base);
- else if(resp_buf_type == CIFS_LARGE_BUFFER)
+ else if (resp_buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(iov[0].iov_base);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
@@ -1596,7 +1687,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
int timeout = 0;
__u16 count;
- cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
+ cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d", waitFlag, numLock));
rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
if (rc)
@@ -1604,7 +1695,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
- if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
+ if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
timeout = -1; /* no response expected */
pSMB->Timeout = 0;
} else if (waitFlag == TRUE) {
@@ -1620,7 +1711,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
pSMB->AndXCommand = 0xFF; /* none */
pSMB->Fid = smb_file_id; /* netfid stays le */
- if((numLock != 0) || (numUnlock != 0)) {
+ if ((numLock != 0) || (numUnlock != 0)) {
pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
/* BB where to store pid high? */
pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
@@ -1648,7 +1739,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
}
cifs_small_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
@@ -1656,12 +1747,11 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
int
CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
const __u16 smb_file_id, const int get_flag, const __u64 len,
- struct file_lock *pLockData, const __u16 lock_type,
+ struct file_lock *pLockData, const __u16 lock_type,
const int waitFlag)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
- char *data_offset;
struct cifs_posix_lock *parm_data;
int rc = 0;
int timeout = 0;
@@ -1670,7 +1760,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("Posix Lock"));
- if(pLockData == NULL)
+ if (pLockData == NULL)
return EINVAL;
rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
@@ -1680,7 +1770,7 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
- params = 6;
+ params = 6;
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@@ -1688,14 +1778,12 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
-
count = sizeof(struct cifs_posix_lock);
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
- if(get_flag)
+ if (get_flag)
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
else
pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
@@ -1705,11 +1793,11 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
pSMB->TotalDataCount = pSMB->DataCount;
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
- parm_data = (struct cifs_posix_lock *)
+ parm_data = (struct cifs_posix_lock *)
(((char *) &pSMB->hdr.Protocol) + offset);
parm_data->lock_type = cpu_to_le16(lock_type);
- if(waitFlag) {
+ if (waitFlag) {
timeout = 3; /* blocking operation, no timeout */
parm_data->lock_flags = cpu_to_le16(1);
pSMB->Timeout = cpu_to_le32(-1);
@@ -1746,22 +1834,22 @@ CIFSSMBPosixLock(const int xid, struct cifsTconInfo *tcon,
rc = -EIO; /* bad smb */
goto plk_err_exit;
}
- if(pLockData == NULL) {
+ if (pLockData == NULL) {
rc = -EINVAL;
goto plk_err_exit;
}
data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
data_count = le16_to_cpu(pSMBr->t2.DataCount);
- if(data_count < sizeof(struct cifs_posix_lock)) {
+ if (data_count < sizeof(struct cifs_posix_lock)) {
rc = -EIO;
goto plk_err_exit;
}
parm_data = (struct cifs_posix_lock *)
((char *)&pSMBr->hdr.Protocol + data_offset);
- if(parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
+ if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
pLockData->fl_type = F_UNLCK;
}
-
+
plk_err_exit:
if (pSMB)
cifs_small_buf_release(pSMB);
@@ -1784,7 +1872,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
/* do not retry on dead session on close */
rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
- if(rc == -EAGAIN)
+ if (rc == -EAGAIN)
return 0;
if (rc)
return rc;
@@ -1798,7 +1886,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_closes);
if (rc) {
- if(rc!=-EINTR) {
+ if (rc != -EINTR) {
/* EINTR is expected when user ctl-c to kill app */
cERROR(1, ("Send error in Close = %d", rc));
}
@@ -1807,7 +1895,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
cifs_small_buf_release(pSMB);
/* Since session is dead, file will be closed on server already */
- if(rc == -EAGAIN)
+ if (rc == -EAGAIN)
rc = 0;
return rc;
@@ -1839,7 +1927,7 @@ renameRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
+ cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -1851,7 +1939,7 @@ renameRetry:
toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fromName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->OldFileName, fromName, name_len);
@@ -1872,7 +1960,7 @@ renameRetry:
cifs_stats_inc(&tcon->num_renames);
if (rc) {
cFYI(1, ("Send error in rename = %d", rc));
- }
+ }
cifs_buf_release(pSMB);
@@ -1882,13 +1970,13 @@ renameRetry:
return rc;
}
-int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
- int netfid, char * target_name,
- const struct nls_table * nls_codepage, int remap)
+int CIFSSMBRenameOpenFile(const int xid, struct cifsTconInfo *pTcon,
+ int netfid, char *target_name,
+ const struct nls_table *nls_codepage, int remap)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
- struct set_file_rename * rename_info;
+ struct set_file_rename *rename_info;
char *data_offset;
char dummy_string[30];
int rc = 0;
@@ -1927,13 +2015,14 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
rename_info->overwrite = cpu_to_le32(1);
rename_info->root_fid = 0;
/* unicode only call */
- if(target_name == NULL) {
- sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
- len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
+ if (target_name == NULL) {
+ sprintf(dummy_string, "cifs%x", pSMB->hdr.Mid);
+ len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
dummy_string, 24, nls_codepage, remap);
} else {
len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
- target_name, PATH_MAX, nls_codepage, remap);
+ target_name, PATH_MAX, nls_codepage,
+ remap);
}
rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
@@ -1947,10 +2036,10 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&pTcon->num_t2renames);
if (rc) {
- cFYI(1,("Send error in Rename (by file handle) = %d", rc));
+ cFYI(1, ("Send error in Rename (by file handle) = %d", rc));
}
cifs_buf_release(pSMB);
@@ -1962,9 +2051,9 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
}
int
-CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
- const __u16 target_tid, const char *toName, const int flags,
- const struct nls_table *nls_codepage, int remap)
+CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char *fromName,
+ const __u16 target_tid, const char *toName, const int flags,
+ const struct nls_table *nls_codepage, int remap)
{
int rc = 0;
COPY_REQ *pSMB = NULL;
@@ -1986,7 +2075,7 @@ copyRetry:
pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
+ name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName,
fromName, PATH_MAX, nls_codepage,
remap);
name_len++; /* trailing null */
@@ -1994,11 +2083,12 @@ copyRetry:
pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00;
- name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
+ name_len2 =
+ cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fromName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->OldFileName, fromName, name_len);
@@ -2058,7 +2148,7 @@ createSymLinkRetry:
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fromName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, fromName, name_len);
@@ -2070,7 +2160,7 @@ createSymLinkRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
@@ -2081,7 +2171,7 @@ createSymLinkRetry:
, nls_codepage);
name_len_target++; /* trailing null */
name_len_target *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len_target = strnlen(toName, PATH_MAX);
name_len_target++; /* trailing null */
strncpy(data_offset, toName, name_len_target);
@@ -2108,9 +2198,7 @@ createSymLinkRetry:
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_symlinks);
if (rc) {
- cFYI(1,
- ("Send error in SetPathInfo (create symlink) = %d",
- rc));
+ cFYI(1, ("Send error in SetPathInfo create symlink = %d", rc));
}
if (pSMB)
@@ -2149,7 +2237,7 @@ createHardLinkRetry:
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(toName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, toName, name_len);
@@ -2161,7 +2249,7 @@ createHardLinkRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
@@ -2171,7 +2259,7 @@ createHardLinkRetry:
nls_codepage, remap);
name_len_target++; /* trailing null */
name_len_target *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len_target = strnlen(fromName, PATH_MAX);
name_len_target++; /* trailing null */
strncpy(data_offset, fromName, name_len_target);
@@ -2243,13 +2331,13 @@ winCreateHardLinkRetry:
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0; /* pad */
- pSMB->OldFileName[name_len + 1] = 0x04;
+ pSMB->OldFileName[name_len + 1] = 0x04;
name_len2 =
- cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
+ cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2],
toName, PATH_MAX, nls_codepage, remap);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fromName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->OldFileName, fromName, name_len);
@@ -2302,12 +2390,11 @@ querySymLinkRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifs_strtoUCS((__le16 *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
@@ -2324,7 +2411,7 @@ querySymLinkRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -2355,16 +2442,16 @@ querySymLinkRetry:
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = UniStrnlen((wchar_t *) ((char *)
- &pSMBr->hdr.Protocol +data_offset),
- min_t(const int, buflen,count) / 2);
+ &pSMBr->hdr.Protocol + data_offset),
+ min_t(const int, buflen, count) / 2);
/* BB FIXME investigate remapping reserved chars here */
cifs_strfromUCS_le(symlinkinfo,
- (__le16 *) ((char *)&pSMBr->hdr.Protocol +
- data_offset),
+ (__le16 *) ((char *)&pSMBr->hdr.Protocol
+ + data_offset),
name_len, nls_codepage);
} else {
strncpy(symlinkinfo,
- (char *) &pSMBr->hdr.Protocol +
+ (char *) &pSMBr->hdr.Protocol +
data_offset,
min_t(const int, buflen, count));
}
@@ -2385,14 +2472,14 @@ querySymLinkRetry:
Setup words themselves and ByteCount
MaxSetupCount (size of returned setup area) and
MaxParameterCount (returned parms size) must be set by caller */
-static int
+static int
smb_init_ntransact(const __u16 sub_command, const int setup_count,
const int parm_len, struct cifsTconInfo *tcon,
- void ** ret_buf)
+ void **ret_buf)
{
int rc;
__u32 temp_offset;
- struct smb_com_ntransact_req * pSMB;
+ struct smb_com_ntransact_req *pSMB;
rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon,
(void **)&pSMB);
@@ -2416,47 +2503,47 @@ smb_init_ntransact(const __u16 sub_command, const int setup_count,
}
static int
-validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
- int * pdatalen, int * pparmlen)
+validate_ntransact(char *buf, char **ppparm, char **ppdata,
+ int *pdatalen, int *pparmlen)
{
- char * end_of_smb;
+ char *end_of_smb;
__u32 data_count, data_offset, parm_count, parm_offset;
- struct smb_com_ntransact_rsp * pSMBr;
+ struct smb_com_ntransact_rsp *pSMBr;
- if(buf == NULL)
+ if (buf == NULL)
return -EINVAL;
pSMBr = (struct smb_com_ntransact_rsp *)buf;
/* ByteCount was converted from little endian in SendReceive */
- end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
+ end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount +
(char *)&pSMBr->ByteCount;
-
data_offset = le32_to_cpu(pSMBr->DataOffset);
data_count = le32_to_cpu(pSMBr->DataCount);
- parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
+ parm_offset = le32_to_cpu(pSMBr->ParameterOffset);
parm_count = le32_to_cpu(pSMBr->ParameterCount);
*ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset;
*ppdata = (char *)&pSMBr->hdr.Protocol + data_offset;
/* should we also check that parm and data areas do not overlap? */
- if(*ppparm > end_of_smb) {
- cFYI(1,("parms start after end of smb"));
+ if (*ppparm > end_of_smb) {
+ cFYI(1, ("parms start after end of smb"));
return -EINVAL;
- } else if(parm_count + *ppparm > end_of_smb) {
- cFYI(1,("parm end after end of smb"));
+ } else if (parm_count + *ppparm > end_of_smb) {
+ cFYI(1, ("parm end after end of smb"));
return -EINVAL;
- } else if(*ppdata > end_of_smb) {
- cFYI(1,("data starts after end of smb"));
+ } else if (*ppdata > end_of_smb) {
+ cFYI(1, ("data starts after end of smb"));
return -EINVAL;
- } else if(data_count + *ppdata > end_of_smb) {
+ } else if (data_count + *ppdata > end_of_smb) {
cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p",
- *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */
+ *ppdata, data_count, (data_count + *ppdata),
+ end_of_smb, pSMBr));
return -EINVAL;
- } else if(parm_count + data_count > pSMBr->ByteCount) {
- cFYI(1,("parm count and data count larger than SMB"));
+ } else if (parm_count + data_count > pSMBr->ByteCount) {
+ cFYI(1, ("parm count and data count larger than SMB"));
return -EINVAL;
}
return 0;
@@ -2465,14 +2552,14 @@ validate_ntransact(char * buf, char ** ppparm, char ** ppdata,
int
CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
- char *symlinkinfo, const int buflen,__u16 fid,
+ char *symlinkinfo, const int buflen, __u16 fid,
const struct nls_table *nls_codepage)
{
int rc = 0;
int bytes_returned;
int name_len;
- struct smb_com_transaction_ioctl_req * pSMB;
- struct smb_com_transaction_ioctl_rsp * pSMBr;
+ struct smb_com_transaction_ioctl_req *pSMB;
+ struct smb_com_transaction_ioctl_rsp *pSMBr;
cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
@@ -2511,47 +2598,53 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
/* BB also check enough total bytes returned */
rc = -EIO; /* bad smb */
else {
- if(data_count && (data_count < 2048)) {
- char * end_of_smb = 2 /* sizeof byte count */ +
+ if (data_count && (data_count < 2048)) {
+ char *end_of_smb = 2 /* sizeof byte count */ +
pSMBr->ByteCount +
(char *)&pSMBr->ByteCount;
- struct reparse_data * reparse_buf = (struct reparse_data *)
- ((char *)&pSMBr->hdr.Protocol + data_offset);
- if((char*)reparse_buf >= end_of_smb) {
+ struct reparse_data *reparse_buf =
+ (struct reparse_data *)
+ ((char *)&pSMBr->hdr.Protocol
+ + data_offset);
+ if ((char *)reparse_buf >= end_of_smb) {
rc = -EIO;
goto qreparse_out;
}
- if((reparse_buf->LinkNamesBuf +
+ if ((reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset +
reparse_buf->TargetNameLen) >
end_of_smb) {
- cFYI(1,("reparse buf extended beyond SMB"));
+ cFYI(1,("reparse buf goes beyond SMB"));
rc = -EIO;
goto qreparse_out;
}
-
+
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = UniStrnlen((wchar_t *)
- (reparse_buf->LinkNamesBuf +
- reparse_buf->TargetNameOffset),
- min(buflen/2, reparse_buf->TargetNameLen / 2));
+ (reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset),
+ min(buflen/2,
+ reparse_buf->TargetNameLen / 2));
cifs_strfromUCS_le(symlinkinfo,
- (__le16 *) (reparse_buf->LinkNamesBuf +
+ (__le16 *) (reparse_buf->LinkNamesBuf +
reparse_buf->TargetNameOffset),
name_len, nls_codepage);
} else { /* ASCII names */
- strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
- reparse_buf->TargetNameOffset,
- min_t(const int, buflen, reparse_buf->TargetNameLen));
+ strncpy(symlinkinfo,
+ reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset,
+ min_t(const int, buflen,
+ reparse_buf->TargetNameLen));
}
} else {
rc = -EIO;
- cFYI(1,("Invalid return data count on get reparse info ioctl"));
+ cFYI(1, ("Invalid return data count on "
+ "get reparse info ioctl"));
}
symlinkinfo[buflen] = 0; /* just in case so the caller
does not go off the end of the buffer */
- cFYI(1,("readlink result - %s",symlinkinfo));
+ cFYI(1, ("readlink result - %s", symlinkinfo));
}
}
qreparse_out:
@@ -2566,7 +2659,8 @@ qreparse_out:
#ifdef CONFIG_CIFS_POSIX
/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
-static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
+static void cifs_convert_ace(posix_acl_xattr_entry *ace,
+ struct cifs_posix_ace *cifs_ace)
{
/* u8 cifs fields do not need le conversion */
ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
@@ -2578,30 +2672,31 @@ static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace
}
/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
-static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
- const int acl_type,const int size_of_data_area)
+static int cifs_copy_posix_acl(char *trgt, char *src, const int buflen,
+ const int acl_type, const int size_of_data_area)
{
int size = 0;
int i;
__u16 count;
- struct cifs_posix_ace * pACE;
- struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
- posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
+ struct cifs_posix_ace *pACE;
+ struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)src;
+ posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)trgt;
if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
return -EOPNOTSUPP;
- if(acl_type & ACL_TYPE_ACCESS) {
+ if (acl_type & ACL_TYPE_ACCESS) {
count = le16_to_cpu(cifs_acl->access_entry_count);
pACE = &cifs_acl->ace_array[0];
size = sizeof(struct cifs_posix_acl);
size += sizeof(struct cifs_posix_ace) * count;
/* check if we would go beyond end of SMB */
- if(size_of_data_area < size) {
- cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
+ if (size_of_data_area < size) {
+ cFYI(1, ("bad CIFS POSIX ACL size %d vs. %d",
+ size_of_data_area, size));
return -EINVAL;
}
- } else if(acl_type & ACL_TYPE_DEFAULT) {
+ } else if (acl_type & ACL_TYPE_DEFAULT) {
count = le16_to_cpu(cifs_acl->access_entry_count);
size = sizeof(struct cifs_posix_acl);
size += sizeof(struct cifs_posix_ace) * count;
@@ -2610,7 +2705,7 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
count = le16_to_cpu(cifs_acl->default_entry_count);
size += sizeof(struct cifs_posix_ace) * count;
/* check if we would go beyond end of SMB */
- if(size_of_data_area < size)
+ if (size_of_data_area < size)
return -EINVAL;
} else {
/* illegal type */
@@ -2618,76 +2713,77 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
}
size = posix_acl_xattr_size(count);
- if((buflen == 0) || (local_acl == NULL)) {
- /* used to query ACL EA size */
- } else if(size > buflen) {
+ if ((buflen == 0) || (local_acl == NULL)) {
+ /* used to query ACL EA size */
+ } else if (size > buflen) {
return -ERANGE;
} else /* buffer big enough */ {
local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
- for(i = 0;i < count ;i++) {
- cifs_convert_ace(&local_acl->a_entries[i],pACE);
- pACE ++;
+ for (i = 0; i < count ; i++) {
+ cifs_convert_ace(&local_acl->a_entries[i], pACE);
+ pACE++;
}
}
return size;
}
-static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
- const posix_acl_xattr_entry * local_ace)
+static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace *cifs_ace,
+ const posix_acl_xattr_entry *local_ace)
{
__u16 rc = 0; /* 0 = ACL converted ok */
cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag);
/* BB is there a better way to handle the large uid? */
- if(local_ace->e_id == cpu_to_le32(-1)) {
+ if (local_ace->e_id == cpu_to_le32(-1)) {
/* Probably no need to le convert -1 on any arch but can not hurt */
cifs_ace->cifs_uid = cpu_to_le64(-1);
- } else
+ } else
cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
- /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
+ /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
return rc;
}
/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
-static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
- const int acl_type)
+static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
+ const int buflen, const int acl_type)
{
__u16 rc = 0;
- struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
- posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
+ struct cifs_posix_acl *cifs_acl = (struct cifs_posix_acl *)parm_data;
+ posix_acl_xattr_header *local_acl = (posix_acl_xattr_header *)pACL;
int count;
int i;
- if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
+ if ((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
return 0;
count = posix_acl_xattr_count((size_t)buflen);
- cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
+ cFYI(1, ("setting acl with %d entries from buf of length %d and "
+ "version of %d",
count, buflen, le32_to_cpu(local_acl->a_version)));
- if(le32_to_cpu(local_acl->a_version) != 2) {
- cFYI(1,("unknown POSIX ACL version %d",
+ if (le32_to_cpu(local_acl->a_version) != 2) {
+ cFYI(1, ("unknown POSIX ACL version %d",
le32_to_cpu(local_acl->a_version)));
return 0;
}
cifs_acl->version = cpu_to_le16(1);
- if(acl_type == ACL_TYPE_ACCESS)
+ if (acl_type == ACL_TYPE_ACCESS)
cifs_acl->access_entry_count = cpu_to_le16(count);
- else if(acl_type == ACL_TYPE_DEFAULT)
+ else if (acl_type == ACL_TYPE_DEFAULT)
cifs_acl->default_entry_count = cpu_to_le16(count);
else {
- cFYI(1,("unknown ACL type %d",acl_type));
+ cFYI(1, ("unknown ACL type %d", acl_type));
return 0;
}
- for(i=0;i<count;i++) {
+ for (i = 0; i < count; i++) {
rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
&local_acl->a_entries[i]);
- if(rc != 0) {
+ if (rc != 0) {
/* ACE not converted */
break;
}
}
- if(rc == 0) {
+ if (rc == 0) {
rc = (__u16)(count * sizeof(struct cifs_posix_ace));
rc += sizeof(struct cifs_posix_acl);
/* BB add check to make sure ACL does not overflow SMB */
@@ -2697,9 +2793,9 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl
int
CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- char *acl_inf, const int buflen, const int acl_type,
- const struct nls_table *nls_codepage, int remap)
+ const unsigned char *searchName,
+ char *acl_inf, const int buflen, const int acl_type,
+ const struct nls_table *nls_codepage, int remap)
{
/* SMB_QUERY_POSIX_ACL */
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -2708,7 +2804,7 @@ CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
int bytes_returned;
int name_len;
__u16 params, byte_count;
-
+
cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
queryAclRetry:
@@ -2716,16 +2812,16 @@ queryAclRetry:
(void **) &pSMBr);
if (rc)
return rc;
-
+
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
pSMB->FileName[name_len] = 0;
pSMB->FileName[name_len+1] = 0;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
@@ -2734,7 +2830,7 @@ queryAclRetry:
params = 2 /* level */ + 4 /* rsrvd */ + name_len /* incl null */ ;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
- /* BB find exact max data count below from sess structure BB */
+ /* BB find exact max data count below from sess structure BB */
pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
@@ -2742,7 +2838,8 @@ queryAclRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ offsetof(struct smb_com_transaction2_qpi_req,
+ InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -2763,7 +2860,7 @@ queryAclRetry:
cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
} else {
/* decode response */
-
+
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || (pSMBr->ByteCount < 2))
/* BB also check enough total bytes returned */
@@ -2773,7 +2870,7 @@ queryAclRetry:
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
rc = cifs_copy_posix_acl(acl_inf,
(char *)&pSMBr->hdr.Protocol+data_offset,
- buflen,acl_type,count);
+ buflen, acl_type, count);
}
}
cifs_buf_release(pSMB);
@@ -2784,10 +2881,10 @@ queryAclRetry:
int
CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *fileName,
- const char *local_acl, const int buflen,
- const int acl_type,
- const struct nls_table *nls_codepage, int remap)
+ const unsigned char *fileName,
+ const char *local_acl, const int buflen,
+ const int acl_type,
+ const struct nls_table *nls_codepage, int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -2800,16 +2897,16 @@ CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
setAclRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ (void **) &pSMBr);
if (rc)
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, fileName, name_len);
@@ -2823,15 +2920,15 @@ setAclRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
/* convert to on the wire format for POSIX ACL */
- data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
+ data_count = ACL_to_cifs_posix(parm_data, local_acl, buflen, acl_type);
- if(data_count == 0) {
+ if (data_count == 0) {
rc = -EOPNOTSUPP;
goto setACLerrorExit;
}
@@ -2849,7 +2946,7 @@ setAclRetry:
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cFYI(1, ("Set POSIX ACL returned %d", rc));
}
@@ -2864,86 +2961,85 @@ setACLerrorExit:
/* BB fix tabs in this function FIXME BB */
int
CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
- const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
+ const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
{
- int rc = 0;
- struct smb_t2_qfi_req *pSMB = NULL;
- struct smb_t2_qfi_rsp *pSMBr = NULL;
- int bytes_returned;
- __u16 params, byte_count;
+ int rc = 0;
+ struct smb_t2_qfi_req *pSMB = NULL;
+ struct smb_t2_qfi_rsp *pSMBr = NULL;
+ int bytes_returned;
+ __u16 params, byte_count;
- cFYI(1,("In GetExtAttr"));
- if(tcon == NULL)
- return -ENODEV;
+ cFYI(1, ("In GetExtAttr"));
+ if (tcon == NULL)
+ return -ENODEV;
GetExtAttrRetry:
- rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
- if (rc)
- return rc;
-
- params = 2 /* level */ +2 /* fid */;
- pSMB->t2.TotalDataCount = 0;
- pSMB->t2.MaxParameterCount = cpu_to_le16(4);
- /* BB find exact max data count below from sess structure BB */
- pSMB->t2.MaxDataCount = cpu_to_le16(4000);
- pSMB->t2.MaxSetupCount = 0;
- pSMB->t2.Reserved = 0;
- pSMB->t2.Flags = 0;
- pSMB->t2.Timeout = 0;
- pSMB->t2.Reserved2 = 0;
- pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
- Fid) - 4);
- pSMB->t2.DataCount = 0;
- pSMB->t2.DataOffset = 0;
- pSMB->t2.SetupCount = 1;
- pSMB->t2.Reserved3 = 0;
- pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
- byte_count = params + 1 /* pad */ ;
- pSMB->t2.TotalParameterCount = cpu_to_le16(params);
- pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
- pSMB->Pad = 0;
+ rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ params = 2 /* level */ +2 /* fid */;
+ pSMB->t2.TotalDataCount = 0;
+ pSMB->t2.MaxParameterCount = cpu_to_le16(4);
+ /* BB find exact max data count below from sess structure BB */
+ pSMB->t2.MaxDataCount = cpu_to_le16(4000);
+ pSMB->t2.MaxSetupCount = 0;
+ pSMB->t2.Reserved = 0;
+ pSMB->t2.Flags = 0;
+ pSMB->t2.Timeout = 0;
+ pSMB->t2.Reserved2 = 0;
+ pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
+ Fid) - 4);
+ pSMB->t2.DataCount = 0;
+ pSMB->t2.DataOffset = 0;
+ pSMB->t2.SetupCount = 1;
+ pSMB->t2.Reserved3 = 0;
+ pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
+ byte_count = params + 1 /* pad */ ;
+ pSMB->t2.TotalParameterCount = cpu_to_le16(params);
+ pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
+ pSMB->Pad = 0;
pSMB->Fid = netfid;
- pSMB->hdr.smb_buf_length += byte_count;
- pSMB->t2.ByteCount = cpu_to_le16(byte_count);
-
- rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
- if (rc) {
- cFYI(1, ("error %d in GetExtAttr", rc));
- } else {
- /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 2))
- /* BB also check enough total bytes returned */
- /* If rc should we check for EOPNOSUPP and
- disable the srvino flag? or in caller? */
- rc = -EIO; /* bad smb */
- else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
- struct file_chattr_info * pfinfo;
- /* BB Do we need a cast or hash here ? */
- if(count != 16) {
- cFYI(1, ("Illegal size ret in GetExtAttr"));
- rc = -EIO;
- goto GetExtAttrOut;
- }
- pfinfo = (struct file_chattr_info *)
- (data_offset + (char *) &pSMBr->hdr.Protocol);
- *pExtAttrBits = le64_to_cpu(pfinfo->mode);
+ pSMB->hdr.smb_buf_length += byte_count;
+ pSMB->t2.ByteCount = cpu_to_le16(byte_count);
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("error %d in GetExtAttr", rc));
+ } else {
+ /* decode response */
+ rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+ if (rc || (pSMBr->ByteCount < 2))
+ /* BB also check enough total bytes returned */
+ /* If rc should we check for EOPNOSUPP and
+ disable the srvino flag? or in caller? */
+ rc = -EIO; /* bad smb */
+ else {
+ __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+ __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
+ struct file_chattr_info *pfinfo;
+ /* BB Do we need a cast or hash here ? */
+ if (count != 16) {
+ cFYI(1, ("Illegal size ret in GetExtAttr"));
+ rc = -EIO;
+ goto GetExtAttrOut;
+ }
+ pfinfo = (struct file_chattr_info *)
+ (data_offset + (char *) &pSMBr->hdr.Protocol);
+ *pExtAttrBits = le64_to_cpu(pfinfo->mode);
*pMask = le64_to_cpu(pfinfo->mask);
- }
- }
+ }
+ }
GetExtAttrOut:
- cifs_buf_release(pSMB);
- if (rc == -EAGAIN)
- goto GetExtAttrRetry;
- return rc;
+ cifs_buf_release(pSMB);
+ if (rc == -EAGAIN)
+ goto GetExtAttrRetry;
+ return rc;
}
-
#endif /* CONFIG_POSIX */
@@ -2955,7 +3051,7 @@ static const struct cifs_sid sid_user =
{1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
/* Convert CIFS ACL to POSIX form */
-static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
+static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len)
{
return 0;
}
@@ -2963,7 +3059,7 @@ static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
/* Get Security Descriptor (by handle) from remote server for a file or dir */
int
CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
- /* BB fix up return info */ char *acl_inf, const int buflen,
+ /* BB fix up return info */ char *acl_inf, const int buflen,
const int acl_type /* ACCESS/DEFAULT not sure implication */)
{
int rc = 0;
@@ -2973,7 +3069,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
cFYI(1, ("GetCifsACL"));
- rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
+ rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0,
8 /* parm len */, tcon, (void **) &pSMB);
if (rc)
return rc;
@@ -2994,23 +3090,23 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
if (rc) {
cFYI(1, ("Send error in QuerySecDesc = %d", rc));
} else { /* decode response */
- struct cifs_sid * psec_desc;
+ struct cifs_sid *psec_desc;
__le32 * parm;
int parm_len;
int data_len;
int acl_len;
- struct smb_com_ntransact_rsp * pSMBr;
+ struct smb_com_ntransact_rsp *pSMBr;
/* validate_nttransact */
- rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
+ rc = validate_ntransact(iov[0].iov_base, (char **)&parm,
(char **)&psec_desc,
&parm_len, &data_len);
-
- if(rc)
+ if (rc)
goto qsec_out;
pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
- cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc)); /* BB removeme BB */
+ cERROR(1, ("smb %p parm %p data %p",
+ pSMBr, parm, psec_desc)); /* BB removeme BB */
if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
rc = -EIO; /* bad smb */
@@ -3020,14 +3116,14 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
/* BB check that data area is minimum length and as big as acl_len */
acl_len = le32_to_cpu(*(__le32 *)parm);
- /* BB check if(acl_len > bufsize) */
+ /* BB check if (acl_len > bufsize) */
parse_sec_desc(psec_desc, acl_len);
}
qsec_out:
- if(buf_type == CIFS_SMALL_BUFFER)
+ if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(iov[0].iov_base);
- else if(buf_type == CIFS_LARGE_BUFFER)
+ else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(iov[0].iov_base);
/* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */
return rc;
@@ -3036,9 +3132,9 @@ qsec_out:
/* Legacy Query Path Information call for lookup to old servers such
as Win9x/WinME */
int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- FILE_ALL_INFO * pFinfo,
- const struct nls_table *nls_codepage, int remap)
+ const unsigned char *searchName,
+ FILE_ALL_INFO *pFinfo,
+ const struct nls_table *nls_codepage, int remap)
{
QUERY_INFORMATION_REQ * pSMB;
QUERY_INFORMATION_RSP * pSMBr;
@@ -3046,31 +3142,31 @@ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
int bytes_returned;
int name_len;
- cFYI(1, ("In SMBQPath path %s", searchName));
+ cFYI(1, ("In SMBQPath path %s", searchName));
QInfRetry:
rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ (void **) &pSMBr);
if (rc)
return rc;
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX, nls_codepage, remap);
+ cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else {
+ } else {
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
}
pSMB->BufferFormat = 0x04;
- name_len++; /* account for buffer type byte */
+ name_len++; /* account for buffer type byte */
pSMB->hdr.smb_buf_length += (__u16) name_len;
pSMB->ByteCount = cpu_to_le16(name_len);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
- (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
cFYI(1, ("Send error in QueryInfo = %d", rc));
} else if (pFinfo) { /* decode response */
@@ -3127,17 +3223,17 @@ QPathInfoRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
}
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+ params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
@@ -3147,7 +3243,7 @@ QPathInfoRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -3156,7 +3252,7 @@ QPathInfoRetry:
byte_count = params + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
- if(legacy)
+ if (legacy)
pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
else
pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
@@ -3173,16 +3269,18 @@ QPathInfoRetry:
if (rc) /* BB add auto retry on EOPNOTSUPP? */
rc = -EIO;
- else if (!legacy && (pSMBr->ByteCount < 40))
+ else if (!legacy && (pSMBr->ByteCount < 40))
rc = -EIO; /* bad smb */
- else if(legacy && (pSMBr->ByteCount < 24))
- rc = -EIO; /* 24 or 26 expected but we do not read last field */
- else if (pFindData){
+ else if (legacy && (pSMBr->ByteCount < 24))
+ rc = -EIO; /* 24 or 26 expected but we do not read
+ last field */
+ else if (pFindData) {
int size;
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- if(legacy) /* we do not read the last field, EAsize, fortunately
- since it varies by subdialect and on Set vs. Get, is
- two bytes or 4 bytes depending but we don't care here */
+ if (legacy) /* we do not read the last field, EAsize,
+ fortunately since it varies by subdialect
+ and on Set vs. Get, is two bytes or 4
+ bytes depending but we don't care here */
size = sizeof(FILE_INFO_STANDARD);
else
size = sizeof(FILE_ALL_INFO);
@@ -3226,24 +3324,24 @@ UnixQPathInfoRetry:
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
}
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+ params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
/* BB find exact max SMB PDU from sess structure BB */
- pSMB->MaxDataCount = cpu_to_le16(4000);
+ pSMB->MaxDataCount = cpu_to_le16(4000);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -3303,12 +3401,11 @@ findUniqueRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
- /* find define for this maxpathcomponent */
- , nls_codepage);
+ cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+ PATH_MAX, nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
@@ -3324,7 +3421,7 @@ findUniqueRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(
- offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
+ offsetof(struct smb_com_transaction2_ffirst_req, InformationLevel)-4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1; /* one byte, no need to le convert */
@@ -3364,10 +3461,10 @@ findUniqueRetry:
/* xid, tcon, searchName and codepage are input parms, rest are returned */
int
CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
- const char *searchName,
+ const char *searchName,
const struct nls_table *nls_codepage,
- __u16 * pnetfid,
- struct cifs_search_info * psrch_inf, int remap, const char dirsep)
+ __u16 *pnetfid,
+ struct cifs_search_info *psrch_inf, int remap, const char dirsep)
{
/* level 257 SMB_ */
TRANSACTION2_FFIRST_REQ *pSMB = NULL;
@@ -3378,7 +3475,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
int name_len;
__u16 params, byte_count;
- cFYI(1, ("In FindFirst for %s",searchName));
+ cFYI(1, ("In FindFirst for %s", searchName));
findFirstRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
@@ -3388,7 +3485,7 @@ findFirstRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
PATH_MAX, nls_codepage, remap);
/* We can not add the asterik earlier in case
it got remapped to 0xF03A as if it were part of the
@@ -3405,7 +3502,7 @@ findFirstRetry:
} else { /* BB add check for overrun of SMB buf BB */
name_len = strnlen(searchName, PATH_MAX);
/* BB fix here and in unicode clause above ie
- if(name_len > buffersize-header)
+ if (name_len > buffersize-header)
free buffer exit; BB */
strncpy(pSMB->FileName, searchName, name_len);
pSMB->FileName[name_len] = dirsep;
@@ -3438,8 +3535,8 @@ findFirstRetry:
pSMB->SearchAttributes =
cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
ATTR_DIRECTORY);
- pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
- pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
+ pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
+ pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END |
CIFS_SEARCH_RETURN_RESUME);
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
@@ -3466,7 +3563,7 @@ findFirstRetry:
} else { /* decode response */
/* BB remember to free buffer if error BB */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if(rc == 0) {
+ if (rc == 0) {
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
psrch_inf->unicode = TRUE;
else
@@ -3474,18 +3571,19 @@ findFirstRetry:
psrch_inf->ntwrk_buf_start = (char *)pSMBr;
psrch_inf->smallBuf = 0;
- psrch_inf->srch_entries_start =
- (char *) &pSMBr->hdr.Protocol +
+ psrch_inf->srch_entries_start =
+ (char *) &pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.DataOffset);
parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.ParameterOffset));
- if(parms->EndofSearch)
+ if (parms->EndofSearch)
psrch_inf->endOfSearch = TRUE;
else
psrch_inf->endOfSearch = FALSE;
- psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
+ psrch_inf->entries_in_buffer =
+ le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
psrch_inf->entries_in_buffer;
*pnetfid = parms->SearchHandle;
@@ -3498,7 +3596,7 @@ findFirstRetry:
}
int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
- __u16 searchHandle, struct cifs_search_info * psrch_inf)
+ __u16 searchHandle, struct cifs_search_info *psrch_inf)
{
TRANSACTION2_FNEXT_REQ *pSMB = NULL;
TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
@@ -3510,7 +3608,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("In FindNext"));
- if(psrch_inf->endOfSearch == TRUE)
+ if (psrch_inf->endOfSearch == TRUE)
return -ENOENT;
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
@@ -3518,12 +3616,13 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
if (rc)
return rc;
- params = 14; /* includes 2 bytes of null string, converted to LE below */
+ params = 14; /* includes 2 bytes of null string, converted to LE below*/
byte_count = 0;
pSMB->TotalDataCount = 0; /* no EAs */
pSMB->MaxParameterCount = cpu_to_le16(8);
pSMB->MaxDataCount =
- cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
+ cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) &
+ 0xFFFFFF00);
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
pSMB->Flags = 0;
@@ -3539,15 +3638,6 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->SearchHandle = searchHandle; /* always kept as le */
pSMB->SearchCount =
cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
- /* test for Unix extensions */
-/* if (tcon->ses->capabilities & CAP_UNIX) {
- pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
- psrch_inf->info_level = SMB_FIND_FILE_UNIX;
- } else {
- pSMB->InformationLevel =
- cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
- psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
- } */
pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
pSMB->ResumeKey = psrch_inf->resume_key;
pSMB->SearchFlags =
@@ -3555,7 +3645,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
name_len = psrch_inf->resume_name_len;
params += name_len;
- if(name_len < PATH_MAX) {
+ if (name_len < PATH_MAX) {
memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
byte_count += name_len;
/* 14 byte parm len above enough for 2 byte null terminator */
@@ -3570,20 +3660,20 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
-
+
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
cifs_stats_inc(&tcon->num_fnext);
if (rc) {
if (rc == -EBADF) {
psrch_inf->endOfSearch = TRUE;
- rc = 0; /* search probably was closed at end of search above */
+ rc = 0; /* search probably was closed at end of search*/
} else
cFYI(1, ("FindNext returned = %d", rc));
} else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
-
- if(rc == 0) {
+
+ if (rc == 0) {
/* BB fixme add lock for file (srch_info) struct here */
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
psrch_inf->unicode = TRUE;
@@ -3594,7 +3684,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
parms = (T2_FNEXT_RSP_PARMS *)response_data;
response_data = (char *)&pSMBr->hdr.Protocol +
le16_to_cpu(pSMBr->t2.DataOffset);
- if(psrch_inf->smallBuf)
+ if (psrch_inf->smallBuf)
cifs_small_buf_release(
psrch_inf->ntwrk_buf_start);
else
@@ -3602,15 +3692,16 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
psrch_inf->srch_entries_start = response_data;
psrch_inf->ntwrk_buf_start = (char *)pSMB;
psrch_inf->smallBuf = 0;
- if(parms->EndofSearch)
+ if (parms->EndofSearch)
psrch_inf->endOfSearch = TRUE;
else
psrch_inf->endOfSearch = FALSE;
-
- psrch_inf->entries_in_buffer = le16_to_cpu(parms->SearchCount);
+ psrch_inf->entries_in_buffer =
+ le16_to_cpu(parms->SearchCount);
psrch_inf->index_of_last_entry +=
psrch_inf->entries_in_buffer;
-/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
+/* cFYI(1,("fnxt2 entries in buf %d index_of_last %d",
+ psrch_inf->entries_in_buffer, psrch_inf->index_of_last_entry)); */
/* BB fixme add unlock here */
}
@@ -3625,12 +3716,12 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
FNext2_err_exit:
if (rc != 0)
cifs_buf_release(pSMB);
-
return rc;
}
int
-CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
+CIFSFindClose(const int xid, struct cifsTconInfo *tcon,
+ const __u16 searchHandle)
{
int rc = 0;
FINDCLOSE_REQ *pSMB = NULL;
@@ -3642,7 +3733,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
/* no sense returning error if session restarted
as file handle has been closed */
- if(rc == -EAGAIN)
+ if (rc == -EAGAIN)
return 0;
if (rc)
return rc;
@@ -3667,9 +3758,9 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle
int
CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
- const unsigned char *searchName,
- __u64 * inode_number,
- const struct nls_table *nls_codepage, int remap)
+ const unsigned char *searchName,
+ __u64 * inode_number,
+ const struct nls_table *nls_codepage, int remap)
{
int rc = 0;
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -3677,24 +3768,23 @@ CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
int name_len, bytes_returned;
__u16 params, byte_count;
- cFYI(1,("In GetSrvInodeNum for %s",searchName));
- if(tcon == NULL)
- return -ENODEV;
+ cFYI(1, ("In GetSrvInodeNum for %s", searchName));
+ if (tcon == NULL)
+ return -ENODEV;
GetInodeNumberRetry:
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ (void **) &pSMBr);
if (rc)
return rc;
-
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
- PATH_MAX,nls_codepage, remap);
+ PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, searchName, name_len);
@@ -3711,7 +3801,7 @@ GetInodeNumberRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -3737,12 +3827,12 @@ GetInodeNumberRetry:
/* If rc should we check for EOPNOSUPP and
disable the srvino flag? or in caller? */
rc = -EIO; /* bad smb */
- else {
+ else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 count = le16_to_cpu(pSMBr->t2.DataCount);
- struct file_internal_info * pfinfo;
+ struct file_internal_info *pfinfo;
/* BB Do we need a cast or hash here ? */
- if(count < 8) {
+ if (count < 8) {
cFYI(1, ("Illegal size ret in QryIntrnlInf"));
rc = -EIO;
goto GetInodeNumOut;
@@ -3769,12 +3859,12 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
/* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
- struct dfs_referral_level_3 * referrals = NULL;
+ struct dfs_referral_level_3 *referrals = NULL;
int rc = 0;
int bytes_returned;
int name_len;
unsigned int i;
- char * temp;
+ char *temp;
__u16 params, byte_count;
*number_of_UNC_in_array = 0;
*targetUNCs = NULL;
@@ -3787,8 +3877,8 @@ getDFSRetry:
(void **) &pSMBr);
if (rc)
return rc;
-
- /* server pointer checked in called function,
+
+ /* server pointer checked in called function,
but should never be null here anyway */
pSMB->hdr.Mid = GetNextMid(ses->server);
pSMB->hdr.Tid = ses->ipc_tid;
@@ -3807,19 +3897,19 @@ getDFSRetry:
searchName, PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(searchName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->RequestFileName, searchName, name_len);
}
- if(ses->server) {
- if(ses->server->secMode &
+ if (ses->server) {
+ if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
}
- pSMB->hdr.Uid = ses->Suid;
+ pSMB->hdr.Uid = ses->Suid;
params = 2 /* level */ + name_len /*includes null */ ;
pSMB->TotalDataCount = 0;
@@ -3833,7 +3923,7 @@ getDFSRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
+ struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
@@ -3852,74 +3942,87 @@ getDFSRetry:
/* BB Add logic to parse referrals here */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 17)) /* BB also check enough total bytes returned */
+ /* BB Also check if enough total bytes returned? */
+ if (rc || (pSMBr->ByteCount < 17))
rc = -EIO; /* bad smb */
else {
- __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+ __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
__u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
cFYI(1,
- ("Decoding GetDFSRefer response. BCC: %d Offset %d",
+ ("Decoding GetDFSRefer response BCC: %d Offset %d",
pSMBr->ByteCount, data_offset));
- referrals =
- (struct dfs_referral_level_3 *)
+ referrals =
+ (struct dfs_referral_level_3 *)
(8 /* sizeof start of data block */ +
data_offset +
- (char *) &pSMBr->hdr.Protocol);
- cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",
- le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
+ (char *) &pSMBr->hdr.Protocol);
+ cFYI(1, ("num_referrals: %d dfs flags: 0x%x ... \n"
+ "for referral one refer size: 0x%x srv "
+ "type: 0x%x refer flags: 0x%x ttl: 0x%x",
+ le16_to_cpu(pSMBr->NumberOfReferrals),
+ le16_to_cpu(pSMBr->DFSFlags),
+ le16_to_cpu(referrals->ReferralSize),
+ le16_to_cpu(referrals->ServerType),
+ le16_to_cpu(referrals->ReferralFlags),
+ le16_to_cpu(referrals->TimeToLive)));
/* BB This field is actually two bytes in from start of
data block so we could do safety check that DataBlock
begins at address of pSMBr->NumberOfReferrals */
- *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
+ *number_of_UNC_in_array =
+ le16_to_cpu(pSMBr->NumberOfReferrals);
/* BB Fix below so can return more than one referral */
- if(*number_of_UNC_in_array > 1)
+ if (*number_of_UNC_in_array > 1)
*number_of_UNC_in_array = 1;
/* get the length of the strings describing refs */
name_len = 0;
- for(i=0;i<*number_of_UNC_in_array;i++) {
+ for (i = 0; i < *number_of_UNC_in_array; i++) {
/* make sure that DfsPathOffset not past end */
- __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
+ __u16 offset =
+ le16_to_cpu(referrals->DfsPathOffset);
if (offset > data_count) {
- /* if invalid referral, stop here and do
+ /* if invalid referral, stop here and do
not try to copy any more */
*number_of_UNC_in_array = i;
break;
- }
+ }
temp = ((char *)referrals) + offset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
- name_len += UniStrnlen((wchar_t *)temp,data_count);
+ name_len += UniStrnlen((wchar_t *)temp,
+ data_count);
} else {
- name_len += strnlen(temp,data_count);
+ name_len += strnlen(temp, data_count);
}
referrals++;
- /* BB add check that referral pointer does not fall off end PDU */
-
+ /* BB add check that referral pointer does
+ not fall off end PDU */
}
/* BB add check for name_len bigger than bcc */
- *targetUNCs =
- kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
- if(*targetUNCs == NULL) {
+ *targetUNCs =
+ kmalloc(name_len+1+(*number_of_UNC_in_array),
+ GFP_KERNEL);
+ if (*targetUNCs == NULL) {
rc = -ENOMEM;
goto GetDFSRefExit;
}
/* copy the ref strings */
- referrals =
- (struct dfs_referral_level_3 *)
- (8 /* sizeof data hdr */ +
- data_offset +
+ referrals = (struct dfs_referral_level_3 *)
+ (8 /* sizeof data hdr */ + data_offset +
(char *) &pSMBr->hdr.Protocol);
- for(i=0;i<*number_of_UNC_in_array;i++) {
- temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
+ for (i = 0; i < *number_of_UNC_in_array; i++) {
+ temp = ((char *)referrals) +
+ le16_to_cpu(referrals->DfsPathOffset);
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
cifs_strfromUCS_le(*targetUNCs,
- (__le16 *) temp, name_len, nls_codepage);
+ (__le16 *) temp,
+ name_len,
+ nls_codepage);
} else {
- strncpy(*targetUNCs,temp,name_len);
+ strncpy(*targetUNCs, temp, name_len);
}
/* BB update target_uncs pointers */
referrals++;
@@ -3996,18 +4099,17 @@ oldQFSInfoRetry:
rc = -EIO; /* bad smb */
else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- cFYI(1,("qfsinf resp BCC: %d Offset %d",
+ cFYI(1, ("qfsinf resp BCC: %d Offset %d",
pSMBr->ByteCount, data_offset));
- response_data =
- (FILE_SYSTEM_ALLOC_INFO *)
+ response_data = (FILE_SYSTEM_ALLOC_INFO *)
(((char *) &pSMBr->hdr.Protocol) + data_offset);
FSData->f_bsize =
le16_to_cpu(response_data->BytesPerSector) *
le32_to_cpu(response_data->
SectorsPerAllocationUnit);
FSData->f_blocks =
- le32_to_cpu(response_data->TotalAllocationUnits);
+ le32_to_cpu(response_data->TotalAllocationUnits);
FSData->f_bfree = FSData->f_bavail =
le32_to_cpu(response_data->FreeAllocationUnits);
cFYI(1,
@@ -4056,7 +4158,7 @@ QFSInfoRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -4071,7 +4173,7 @@ QFSInfoRetry:
if (rc) {
cFYI(1, ("Send error in QFSInfo = %d", rc));
} else { /* decode response */
- rc = validate_t2((struct smb_t2_rsp *)pSMBr);
+ rc = validate_t2((struct smb_t2_rsp *)pSMBr);
if (rc || (pSMBr->ByteCount < 24))
rc = -EIO; /* bad smb */
@@ -4136,7 +4238,7 @@ QFSAttributeRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -4153,7 +4255,8 @@ QFSAttributeRetry:
} else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 13)) { /* BB also check enough bytes returned */
+ if (rc || (pSMBr->ByteCount < 13)) {
+ /* BB also check if enough bytes returned */
rc = -EIO; /* bad smb */
} else {
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
@@ -4204,7 +4307,7 @@ QFSDeviceRetry:
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
@@ -4274,8 +4377,8 @@ QFSUnixRetry:
byte_count = params + 1 /* pad */ ;
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
- smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+ smb_com_transaction2_qfsi_req, InformationLevel) - 4);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
@@ -4335,7 +4438,8 @@ SETFSUnixRetry:
pSMB->Flags = 0;
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
- param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
+ param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum)
+ - 4;
offset = param_offset + params;
pSMB->MaxParameterCount = cpu_to_le16(4);
@@ -4417,8 +4521,8 @@ QFSPosixRetry:
byte_count = params + 1 /* pad */ ;
pSMB->ParameterCount = cpu_to_le16(params);
pSMB->TotalParameterCount = pSMB->ParameterCount;
- pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
- smb_com_transaction2_qfsi_req, InformationLevel) - 4);
+ pSMB->ParameterOffset = cpu_to_le16(offsetof(struct
+ smb_com_transaction2_qfsi_req, InformationLevel) - 4);
pSMB->SetupCount = 1;
pSMB->Reserved3 = 0;
pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
@@ -4447,18 +4551,18 @@ QFSPosixRetry:
le64_to_cpu(response_data->TotalBlocks);
FSData->f_bfree =
le64_to_cpu(response_data->BlocksAvail);
- if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
+ if (response_data->UserBlocksAvail == cpu_to_le64(-1)) {
FSData->f_bavail = FSData->f_bfree;
} else {
FSData->f_bavail =
- le64_to_cpu(response_data->UserBlocksAvail);
+ le64_to_cpu(response_data->UserBlocksAvail);
}
- if(response_data->TotalFileNodes != cpu_to_le64(-1))
+ if (response_data->TotalFileNodes != cpu_to_le64(-1))
FSData->f_files =
- le64_to_cpu(response_data->TotalFileNodes);
- if(response_data->FreeFileNodes != cpu_to_le64(-1))
+ le64_to_cpu(response_data->TotalFileNodes);
+ if (response_data->FreeFileNodes != cpu_to_le64(-1))
FSData->f_ffree =
- le64_to_cpu(response_data->FreeFileNodes);
+ le64_to_cpu(response_data->FreeFileNodes);
}
}
cifs_buf_release(pSMB);
@@ -4470,15 +4574,15 @@ QFSPosixRetry:
}
-/* We can not use write of zero bytes trick to
- set file size due to need for large file support. Also note that
- this SetPathInfo is preferred to SetFileInfo based method in next
+/* We can not use write of zero bytes trick to
+ set file size due to need for large file support. Also note that
+ this SetPathInfo is preferred to SetFileInfo based method in next
routine which is only needed to work around a sharing violation bug
in Samba which this routine can run into */
int
CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- __u64 size, int SetAllocation,
+ __u64 size, int SetAllocation,
const struct nls_table *nls_codepage, int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
@@ -4517,22 +4621,22 @@ SetEOFRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
- if(SetAllocation) {
- if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
- else
- pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
- } else /* Set File Size */ {
+ if (SetAllocation) {
+ if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
+ else
+ pSMB->InformationLevel =
+ cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
+ } else /* Set File Size */ {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
else
pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
}
parm_data =
@@ -4567,8 +4671,8 @@ SetEOFRetry:
}
int
-CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
- __u16 fid, __u32 pid_of_opener, int SetAllocation)
+CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
+ __u16 fid, __u32 pid_of_opener, int SetAllocation)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -4589,7 +4693,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
-
+
params = 6;
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
@@ -4599,7 +4703,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+ data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
count = sizeof(struct file_end_of_file_info);
pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -4614,25 +4718,25 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
pSMB->TotalParameterCount = pSMB->ParameterCount;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
parm_data =
- (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
- offset);
+ (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol)
+ + offset);
pSMB->DataOffset = cpu_to_le16(offset);
parm_data->FileSize = cpu_to_le64(size);
pSMB->Fid = fid;
- if(SetAllocation) {
+ if (SetAllocation) {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
else
pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
- } else /* Set File Size */ {
+ } else /* Set File Size */ {
if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
else
pSMB->InformationLevel =
- cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
+ cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
}
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count;
@@ -4648,21 +4752,21 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
if (pSMB)
cifs_small_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
}
-/* Some legacy servers such as NT4 require that the file times be set on
+/* Some legacy servers such as NT4 require that the file times be set on
an open handle, rather than by pathname - this is awkward due to
potential access conflicts on the open, but it is unavoidable for these
old servers since the only other choice is to go from 100 nanosecond DCE
time and resort to the original setpathinfo level which takes the ancient
DOS time format with 2 second granularity */
int
-CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data,
- __u16 fid)
+CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon,
+ const FILE_BASIC_INFO *data, __u16 fid)
{
struct smb_com_transaction2_sfi_req *pSMB = NULL;
struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
@@ -4684,7 +4788,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
use an existing handle (rather than opening one on the fly) */
/* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
-
+
params = 6;
pSMB->MaxSetupCount = 0;
pSMB->Reserved = 0;
@@ -4694,7 +4798,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
offset = param_offset + params;
- data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
+ data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
count = sizeof (FILE_BASIC_INFO);
pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -4717,16 +4821,16 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
- memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
+ memcpy(data_offset, data, sizeof(FILE_BASIC_INFO));
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
if (rc) {
- cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
+ cFYI(1, ("Send error in Set Time (SetFileInfo) = %d", rc));
}
cifs_small_buf_release(pSMB);
- /* Note: On -EAGAIN error only caller can retry on handle based calls
+ /* Note: On -EAGAIN error only caller can retry on handle based calls
since file handle passed in no longer valid */
return rc;
@@ -4735,7 +4839,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_I
int
CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- const FILE_BASIC_INFO * data,
+ const FILE_BASIC_INFO *data,
const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -4760,7 +4864,7 @@ SetTimesRetry:
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, fileName, name_len);
@@ -4776,7 +4880,7 @@ SetTimesRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
pSMB->ParameterOffset = cpu_to_le16(param_offset);
@@ -4837,11 +4941,11 @@ SetAttrLgcyRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- ConvertToUCS((__le16 *) pSMB->fileName, fileName,
+ ConvertToUCS((__le16 *) pSMB->fileName, fileName,
PATH_MAX, nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->fileName, fileName, name_len);
@@ -4867,8 +4971,8 @@ SetAttrLgcyRetry:
int
CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
- char *fileName, __u64 mode, __u64 uid, __u64 gid,
- dev_t device, const struct nls_table *nls_codepage,
+ char *fileName, __u64 mode, __u64 uid, __u64 gid,
+ dev_t device, const struct nls_table *nls_codepage,
int remap)
{
TRANSACTION2_SPI_REQ *pSMB = NULL;
@@ -4888,7 +4992,7 @@ setPermsRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -4908,7 +5012,7 @@ setPermsRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
data_offset =
(FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
@@ -4931,7 +5035,7 @@ setPermsRetry:
older clients, but we should be precise - we use SetFileSize to
set file size and do not want to truncate file size to zero
accidently as happened on one Samba server beta by putting
- zero instead of -1 here */
+ zero instead of -1 here */
data_offset->EndOfFile = NO_CHANGE_64;
data_offset->NumOfBytes = NO_CHANGE_64;
data_offset->LastStatusChange = NO_CHANGE_64;
@@ -4943,20 +5047,20 @@ setPermsRetry:
data_offset->DevMajor = cpu_to_le64(MAJOR(device));
data_offset->DevMinor = cpu_to_le64(MINOR(device));
data_offset->Permissions = cpu_to_le64(mode);
-
- if(S_ISREG(mode))
+
+ if (S_ISREG(mode))
data_offset->Type = cpu_to_le32(UNIX_FILE);
- else if(S_ISDIR(mode))
+ else if (S_ISDIR(mode))
data_offset->Type = cpu_to_le32(UNIX_DIR);
- else if(S_ISLNK(mode))
+ else if (S_ISLNK(mode))
data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
- else if(S_ISCHR(mode))
+ else if (S_ISCHR(mode))
data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
- else if(S_ISBLK(mode))
+ else if (S_ISBLK(mode))
data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
- else if(S_ISFIFO(mode))
+ else if (S_ISFIFO(mode))
data_offset->Type = cpu_to_le32(UNIX_FIFO);
- else if(S_ISSOCK(mode))
+ else if (S_ISSOCK(mode))
data_offset->Type = cpu_to_le32(UNIX_SOCKET);
@@ -4974,20 +5078,20 @@ setPermsRetry:
return rc;
}
-int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
+int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
const int notify_subdirs, const __u16 netfid,
- __u32 filter, struct file * pfile, int multishot,
+ __u32 filter, struct file *pfile, int multishot,
const struct nls_table *nls_codepage)
{
int rc = 0;
- struct smb_com_transaction_change_notify_req * pSMB = NULL;
- struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
+ struct smb_com_transaction_change_notify_req *pSMB = NULL;
+ struct smb_com_ntransaction_change_notify_rsp *pSMBr = NULL;
struct dir_notify_req *dnotify_req;
int bytes_returned;
- cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
+ cFYI(1, ("In CIFSSMBNotify for file handle %d", (int)netfid));
rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
- (void **) &pSMBr);
+ (void **) &pSMBr);
if (rc)
return rc;
@@ -5008,7 +5112,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
pSMB->SetupCount = 4; /* single byte does not need le conversion */
pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
pSMB->ParameterCount = pSMB->TotalParameterCount;
- if(notify_subdirs)
+ if (notify_subdirs)
pSMB->WatchTree = 1; /* one byte - no le conversion needed */
pSMB->Reserved2 = 0;
pSMB->CompletionFilter = cpu_to_le32(filter);
@@ -5021,11 +5125,11 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
cFYI(1, ("Error in Notify = %d", rc));
} else {
/* Add file to outstanding requests */
- /* BB change to kmem cache alloc */
+ /* BB change to kmem cache alloc */
dnotify_req = kmalloc(
sizeof(struct dir_notify_req),
GFP_KERNEL);
- if(dnotify_req) {
+ if (dnotify_req) {
dnotify_req->Pid = pSMB->hdr.Pid;
dnotify_req->PidHigh = pSMB->hdr.PidHigh;
dnotify_req->Mid = pSMB->hdr.Mid;
@@ -5036,20 +5140,20 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon,
dnotify_req->filter = filter;
dnotify_req->multishot = multishot;
spin_lock(&GlobalMid_Lock);
- list_add_tail(&dnotify_req->lhead,
+ list_add_tail(&dnotify_req->lhead,
&GlobalDnotifyReqList);
spin_unlock(&GlobalMid_Lock);
- } else
+ } else
rc = -ENOMEM;
}
cifs_buf_release(pSMB);
- return rc;
+ return rc;
}
#ifdef CONFIG_CIFS_XATTR
ssize_t
CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
- char * EAData, size_t buf_size,
+ char *EAData, size_t buf_size,
const struct nls_table *nls_codepage, int remap)
{
/* BB assumes one setup word */
@@ -5058,8 +5162,8 @@ CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
int rc = 0;
int bytes_returned;
int name_len;
- struct fea * temp_fea;
- char * temp_ptr;
+ struct fea *temp_fea;
+ char *temp_ptr;
__u16 params, byte_count;
cFYI(1, ("In Query All EAs path %s", searchName));
@@ -5071,7 +5175,7 @@ QAllEAsRetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -5081,7 +5185,7 @@ QAllEAsRetry:
strncpy(pSMB->FileName, searchName, name_len);
}
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+ params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
@@ -5091,7 +5195,7 @@ QAllEAsRetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -5115,7 +5219,7 @@ QAllEAsRetry:
/* BB also check enough total bytes returned */
/* BB we need to improve the validity checking
of these trans2 responses */
- if (rc || (pSMBr->ByteCount < 4))
+ if (rc || (pSMBr->ByteCount < 4))
rc = -EIO; /* bad smb */
/* else if (pFindData){
memcpy((char *) pFindData,
@@ -5128,39 +5232,40 @@ QAllEAsRetry:
/* check that each element of each entry does not
go beyond end of list */
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- struct fealist * ea_response_data;
+ struct fealist *ea_response_data;
rc = 0;
/* validate_trans2_offsets() */
- /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+ /* BB check if start of smb + data_offset > &bcc+ bcc */
ea_response_data = (struct fealist *)
(((char *) &pSMBr->hdr.Protocol) +
data_offset);
name_len = le32_to_cpu(ea_response_data->list_len);
- cFYI(1,("ea length %d", name_len));
- if(name_len <= 8) {
+ cFYI(1, ("ea length %d", name_len));
+ if (name_len <= 8) {
/* returned EA size zeroed at top of function */
- cFYI(1,("empty EA list returned from server"));
+ cFYI(1, ("empty EA list returned from server"));
} else {
/* account for ea list len */
name_len -= 4;
temp_fea = ea_response_data->list;
temp_ptr = (char *)temp_fea;
- while(name_len > 0) {
+ while (name_len > 0) {
__u16 value_len;
name_len -= 4;
temp_ptr += 4;
rc += temp_fea->name_len;
/* account for prefix user. and trailing null */
- rc = rc + 5 + 1;
- if(rc<(int)buf_size) {
- memcpy(EAData,"user.",5);
- EAData+=5;
- memcpy(EAData,temp_ptr,temp_fea->name_len);
- EAData+=temp_fea->name_len;
+ rc = rc + 5 + 1;
+ if (rc < (int)buf_size) {
+ memcpy(EAData, "user.", 5);
+ EAData += 5;
+ memcpy(EAData, temp_ptr,
+ temp_fea->name_len);
+ EAData += temp_fea->name_len;
/* null terminate name */
*EAData = 0;
EAData = EAData + 1;
- } else if(buf_size == 0) {
+ } else if (buf_size == 0) {
/* skip copy - calc size only */
} else {
/* stop before overrun buffer */
@@ -5172,11 +5277,15 @@ QAllEAsRetry:
/* account for trailing null */
name_len--;
temp_ptr++;
- value_len = le16_to_cpu(temp_fea->value_len);
+ value_len =
+ le16_to_cpu(temp_fea->value_len);
name_len -= value_len;
temp_ptr += value_len;
- /* BB check that temp_ptr is still within smb BB*/
- /* no trailing null to account for in value len */
+ /* BB check that temp_ptr is still
+ within the SMB BB*/
+
+ /* no trailing null to account for
+ in value len */
/* go on to next EA */
temp_fea = (struct fea *)temp_ptr;
}
@@ -5191,9 +5300,9 @@ QAllEAsRetry:
return (ssize_t)rc;
}
-ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
- const unsigned char * searchName,const unsigned char * ea_name,
- unsigned char * ea_value, size_t buf_size,
+ssize_t CIFSSMBQueryEA(const int xid, struct cifsTconInfo *tcon,
+ const unsigned char *searchName, const unsigned char *ea_name,
+ unsigned char *ea_value, size_t buf_size,
const struct nls_table *nls_codepage, int remap)
{
TRANSACTION2_QPI_REQ *pSMB = NULL;
@@ -5201,8 +5310,8 @@ ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
int rc = 0;
int bytes_returned;
int name_len;
- struct fea * temp_fea;
- char * temp_ptr;
+ struct fea *temp_fea;
+ char *temp_ptr;
__u16 params, byte_count;
cFYI(1, ("In Query EA path %s", searchName));
@@ -5214,7 +5323,7 @@ QEARetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
@@ -5224,7 +5333,7 @@ QEARetry:
strncpy(pSMB->FileName, searchName, name_len);
}
- params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
+ params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */;
pSMB->TotalDataCount = 0;
pSMB->MaxParameterCount = cpu_to_le16(2);
pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
@@ -5234,7 +5343,7 @@ QEARetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
pSMB->ParameterOffset = cpu_to_le16(offsetof(
- struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+ struct smb_com_transaction2_qpi_req, InformationLevel) - 4);
pSMB->DataCount = 0;
pSMB->DataOffset = 0;
pSMB->SetupCount = 1;
@@ -5258,7 +5367,7 @@ QEARetry:
/* BB also check enough total bytes returned */
/* BB we need to improve the validity checking
of these trans2 responses */
- if (rc || (pSMBr->ByteCount < 4))
+ if (rc || (pSMBr->ByteCount < 4))
rc = -EIO; /* bad smb */
/* else if (pFindData){
memcpy((char *) pFindData,
@@ -5271,18 +5380,18 @@ QEARetry:
/* check that each element of each entry does not
go beyond end of list */
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
- struct fealist * ea_response_data;
+ struct fealist *ea_response_data;
rc = -ENODATA;
/* validate_trans2_offsets() */
- /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
+ /* BB check if start of smb + data_offset > &bcc+ bcc*/
ea_response_data = (struct fealist *)
(((char *) &pSMBr->hdr.Protocol) +
data_offset);
name_len = le32_to_cpu(ea_response_data->list_len);
- cFYI(1,("ea length %d", name_len));
- if(name_len <= 8) {
+ cFYI(1, ("ea length %d", name_len));
+ if (name_len <= 8) {
/* returned EA size zeroed at top of function */
- cFYI(1,("empty EA list returned from server"));
+ cFYI(1, ("empty EA list returned from server"));
} else {
/* account for ea list len */
name_len -= 4;
@@ -5290,28 +5399,30 @@ QEARetry:
temp_ptr = (char *)temp_fea;
/* loop through checking if we have a matching
name and then return the associated value */
- while(name_len > 0) {
+ while (name_len > 0) {
__u16 value_len;
name_len -= 4;
temp_ptr += 4;
- value_len = le16_to_cpu(temp_fea->value_len);
- /* BB validate that value_len falls within SMB,
- even though maximum for name_len is 255 */
- if(memcmp(temp_fea->name,ea_name,
+ value_len =
+ le16_to_cpu(temp_fea->value_len);
+ /* BB validate that value_len falls within SMB,
+ even though maximum for name_len is 255 */
+ if (memcmp(temp_fea->name, ea_name,
temp_fea->name_len) == 0) {
/* found a match */
rc = value_len;
/* account for prefix user. and trailing null */
- if(rc<=(int)buf_size) {
+ if (rc <= (int)buf_size) {
memcpy(ea_value,
temp_fea->name+temp_fea->name_len+1,
rc);
- /* ea values, unlike ea names,
- are not null terminated */
- } else if(buf_size == 0) {
+ /* ea values, unlike ea
+ names, are not null
+ terminated */
+ } else if (buf_size == 0) {
/* skip copy - calc size only */
} else {
- /* stop before overrun buffer */
+ /* stop before overrun buffer */
rc = -ERANGE;
}
break;
@@ -5323,11 +5434,11 @@ QEARetry:
temp_ptr++;
name_len -= value_len;
temp_ptr += value_len;
- /* no trailing null to account for in value len */
- /* go on to next EA */
+ /* No trailing null to account for in
+ value_len. Go on to next EA */
temp_fea = (struct fea *)temp_ptr;
}
- }
+ }
}
}
if (pSMB)
@@ -5340,9 +5451,9 @@ QEARetry:
int
CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
- const char * ea_name, const void * ea_value,
- const __u16 ea_value_len, const struct nls_table *nls_codepage,
- int remap)
+ const char *ea_name, const void *ea_value,
+ const __u16 ea_value_len, const struct nls_table *nls_codepage,
+ int remap)
{
struct smb_com_transaction2_spi_req *pSMB = NULL;
struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -5361,11 +5472,11 @@ SetEARetry:
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
- cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
+ cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
PATH_MAX, nls_codepage, remap);
name_len++; /* trailing null */
name_len *= 2;
- } else { /* BB improve the check for buffer overruns BB */
+ } else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fileName, PATH_MAX);
name_len++; /* trailing null */
strncpy(pSMB->FileName, fileName, name_len);
@@ -5376,10 +5487,10 @@ SetEARetry:
/* done calculating parms using name_len of file name,
now use name_len to calculate length of ea name
we are going to create in the inode xattrs */
- if(ea_name == NULL)
+ if (ea_name == NULL)
name_len = 0;
else
- name_len = strnlen(ea_name,255);
+ name_len = strnlen(ea_name, 255);
count = sizeof(*parm_data) + ea_value_len + name_len + 1;
pSMB->MaxParameterCount = cpu_to_le16(2);
@@ -5390,7 +5501,7 @@ SetEARetry:
pSMB->Timeout = 0;
pSMB->Reserved2 = 0;
param_offset = offsetof(struct smb_com_transaction2_spi_req,
- InformationLevel) - 4;
+ InformationLevel) - 4;
offset = param_offset + params;
pSMB->InformationLevel =
cpu_to_le16(SMB_SET_FILE_EA);
@@ -5410,17 +5521,19 @@ SetEARetry:
/* we checked above that name len is less than 255 */
parm_data->list[0].name_len = (__u8)name_len;
/* EA names are always ASCII */
- if(ea_name)
- strncpy(parm_data->list[0].name,ea_name,name_len);
+ if (ea_name)
+ strncpy(parm_data->list[0].name, ea_name, name_len);
parm_data->list[0].name[name_len] = 0;
parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
/* caller ensures that ea_value_len is less than 64K but
we need to ensure that it fits within the smb */
- /*BB add length check that it would fit in negotiated SMB buffer size BB */
- /* if(ea_value_len > buffer_size - 512 (enough for header)) */
- if(ea_value_len)
- memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
+ /*BB add length check to see if it would fit in
+ negotiated SMB buffer size BB */
+ /* if (ea_value_len > buffer_size - 512 (enough for header)) */
+ if (ea_value_len)
+ memcpy(parm_data->list[0].name+name_len+1,
+ ea_value, ea_value_len);
pSMB->TotalDataCount = pSMB->DataCount;
pSMB->ParameterCount = cpu_to_le16(params);
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f4e92661b223..4af3588c1a96 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/connect.c
*
- * Copyright (C) International Business Machines Corp., 2002,2006
+ * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/fs.h>
#include <linux/net.h>
@@ -85,6 +85,7 @@ struct smb_vol {
unsigned direct_io:1;
unsigned remap:1; /* set to remap seven reserved chars in filenames */
unsigned posix_paths:1; /* unset to not ask for posix pathnames. */
+ unsigned no_linux_ext:1;
unsigned sfu_emul:1;
unsigned nullauth:1; /* attempt to authenticate with null user */
unsigned nocase; /* request case insensitive filenames */
@@ -93,20 +94,20 @@ struct smb_vol {
unsigned int wsize;
unsigned int sockopt;
unsigned short int port;
- char * prepath;
+ char *prepath;
};
-static int ipv4_connect(struct sockaddr_in *psin_server,
+static int ipv4_connect(struct sockaddr_in *psin_server,
struct socket **csocket,
- char * netb_name,
- char * server_netb_name);
-static int ipv6_connect(struct sockaddr_in6 *psin_server,
+ char *netb_name,
+ char *server_netb_name);
+static int ipv6_connect(struct sockaddr_in6 *psin_server,
struct socket **csocket);
- /*
+ /*
* cifs tcp session reconnection
- *
+ *
* mark tcp session as reconnecting so temporarily locked
* mark all smb sessions as reconnecting for tcp session
* reconnect tcp session
@@ -120,11 +121,11 @@ cifs_reconnect(struct TCP_Server_Info *server)
struct list_head *tmp;
struct cifsSesInfo *ses;
struct cifsTconInfo *tcon;
- struct mid_q_entry * mid_entry;
-
+ struct mid_q_entry *mid_entry;
+
spin_lock(&GlobalMid_Lock);
- if( kthread_should_stop() ) {
- /* the demux thread will exit normally
+ if ( kthread_should_stop() ) {
+ /* the demux thread will exit normally
next time through the loop */
spin_unlock(&GlobalMid_Lock);
return rc;
@@ -150,18 +151,19 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
list_for_each(tmp, &GlobalTreeConnectionList) {
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
- if((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
+ if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) {
tcon->tidStatus = CifsNeedReconnect;
}
}
read_unlock(&GlobalSMBSeslock);
/* do not want to be sending data on a socket we are freeing */
- down(&server->tcpSem);
- if(server->ssocket) {
- cFYI(1,("State: 0x%x Flags: 0x%lx", server->ssocket->state,
+ down(&server->tcpSem);
+ if (server->ssocket) {
+ cFYI(1, ("State: 0x%x Flags: 0x%lx", server->ssocket->state,
server->ssocket->flags));
- server->ssocket->ops->shutdown(server->ssocket,SEND_SHUTDOWN);
- cFYI(1,("Post shutdown state: 0x%x Flags: 0x%lx", server->ssocket->state,
+ server->ssocket->ops->shutdown(server->ssocket, SEND_SHUTDOWN);
+ cFYI(1, ("Post shutdown state: 0x%x Flags: 0x%lx",
+ server->ssocket->state,
server->ssocket->flags));
sock_release(server->ssocket);
server->ssocket = NULL;
@@ -172,8 +174,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
mid_entry = list_entry(tmp, struct
mid_q_entry,
qhead);
- if(mid_entry) {
- if(mid_entry->midState == MID_REQUEST_SUBMITTED) {
+ if (mid_entry) {
+ if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
/* Mark other intransit requests as needing
retry so we do not immediately mark the
session bad again (ie after we reconnect
@@ -183,29 +185,29 @@ cifs_reconnect(struct TCP_Server_Info *server)
}
}
spin_unlock(&GlobalMid_Lock);
- up(&server->tcpSem);
+ up(&server->tcpSem);
- while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood))
- {
+ while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
try_to_freeze();
- if(server->protocolType == IPV6) {
- rc = ipv6_connect(&server->addr.sockAddr6,&server->ssocket);
+ if (server->protocolType == IPV6) {
+ rc = ipv6_connect(&server->addr.sockAddr6,
+ &server->ssocket);
} else {
- rc = ipv4_connect(&server->addr.sockAddr,
+ rc = ipv4_connect(&server->addr.sockAddr,
&server->ssocket,
server->workstation_RFC1001_name,
server->server_RFC1001_name);
}
- if(rc) {
- cFYI(1,("reconnect error %d",rc));
+ if (rc) {
+ cFYI(1, ("reconnect error %d", rc));
msleep(3000);
} else {
atomic_inc(&tcpSesReconnectCount);
spin_lock(&GlobalMid_Lock);
- if( !kthread_should_stop() )
+ if ( !kthread_should_stop() )
server->tcpStatus = CifsGood;
server->sequence_number = 0;
- spin_unlock(&GlobalMid_Lock);
+ spin_unlock(&GlobalMid_Lock);
/* atomic_set(&server->inFlight,0);*/
wake_up(&server->response_q);
}
@@ -213,27 +215,27 @@ cifs_reconnect(struct TCP_Server_Info *server)
return rc;
}
-/*
+/*
return codes:
0 not a transact2, or all data present
>0 transact2 with that much data missing
-EINVAL = invalid transact2
*/
-static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
+static int check2ndT2(struct smb_hdr *pSMB, unsigned int maxBufSize)
{
- struct smb_t2_rsp * pSMBt;
- int total_data_size;
+ struct smb_t2_rsp *pSMBt;
+ int total_data_size;
int data_in_this_rsp;
int remaining;
- if(pSMB->Command != SMB_COM_TRANSACTION2)
+ if (pSMB->Command != SMB_COM_TRANSACTION2)
return 0;
- /* check for plausible wct, bcc and t2 data and parm sizes */
- /* check for parm and data offset going beyond end of smb */
- if(pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
- cFYI(1,("invalid transact2 word count"));
+ /* check for plausible wct, bcc and t2 data and parm sizes */
+ /* check for parm and data offset going beyond end of smb */
+ if (pSMB->WordCount != 10) { /* coalesce_t2 depends on this */
+ cFYI(1, ("invalid transact2 word count"));
return -EINVAL;
}
@@ -244,25 +246,25 @@ static int check2ndT2(struct smb_hdr * pSMB, unsigned int maxBufSize)
remaining = total_data_size - data_in_this_rsp;
- if(remaining == 0)
+ if (remaining == 0)
return 0;
- else if(remaining < 0) {
- cFYI(1,("total data %d smaller than data in frame %d",
+ else if (remaining < 0) {
+ cFYI(1, ("total data %d smaller than data in frame %d",
total_data_size, data_in_this_rsp));
return -EINVAL;
} else {
- cFYI(1,("missing %d bytes from transact2, check next response",
+ cFYI(1, ("missing %d bytes from transact2, check next response",
remaining));
- if(total_data_size > maxBufSize) {
- cERROR(1,("TotalDataSize %d is over maximum buffer %d",
- total_data_size,maxBufSize));
- return -EINVAL;
+ if (total_data_size > maxBufSize) {
+ cERROR(1, ("TotalDataSize %d is over maximum buffer %d",
+ total_data_size, maxBufSize));
+ return -EINVAL;
}
return remaining;
}
}
-static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
+static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB)
{
struct smb_t2_rsp *pSMB2 = (struct smb_t2_rsp *)psecond;
struct smb_t2_rsp *pSMBt = (struct smb_t2_rsp *)pTargetSMB;
@@ -270,43 +272,43 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
int total_in_buf;
int remaining;
int total_in_buf2;
- char * data_area_of_target;
- char * data_area_of_buf2;
+ char *data_area_of_target;
+ char *data_area_of_buf2;
__u16 byte_count;
total_data_size = le16_to_cpu(pSMBt->t2_rsp.TotalDataCount);
- if(total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
- cFYI(1,("total data sizes of primary and secondary t2 differ"));
+ if (total_data_size != le16_to_cpu(pSMB2->t2_rsp.TotalDataCount)) {
+ cFYI(1, ("total data size of primary and secondary t2 differ"));
}
total_in_buf = le16_to_cpu(pSMBt->t2_rsp.DataCount);
remaining = total_data_size - total_in_buf;
-
- if(remaining < 0)
+
+ if (remaining < 0)
return -EINVAL;
- if(remaining == 0) /* nothing to do, ignore */
+ if (remaining == 0) /* nothing to do, ignore */
return 0;
-
+
total_in_buf2 = le16_to_cpu(pSMB2->t2_rsp.DataCount);
- if(remaining < total_in_buf2) {
- cFYI(1,("transact2 2nd response contains too much data"));
+ if (remaining < total_in_buf2) {
+ cFYI(1, ("transact2 2nd response contains too much data"));
}
/* find end of first SMB data area */
- data_area_of_target = (char *)&pSMBt->hdr.Protocol +
+ data_area_of_target = (char *)&pSMBt->hdr.Protocol +
le16_to_cpu(pSMBt->t2_rsp.DataOffset);
/* validate target area */
data_area_of_buf2 = (char *) &pSMB2->hdr.Protocol +
- le16_to_cpu(pSMB2->t2_rsp.DataOffset);
+ le16_to_cpu(pSMB2->t2_rsp.DataOffset);
data_area_of_target += total_in_buf;
/* copy second buffer into end of first buffer */
- memcpy(data_area_of_target,data_area_of_buf2,total_in_buf2);
+ memcpy(data_area_of_target, data_area_of_buf2, total_in_buf2);
total_in_buf += total_in_buf2;
pSMBt->t2_rsp.DataCount = cpu_to_le16(total_in_buf);
byte_count = le16_to_cpu(BCC_LE(pTargetSMB));
@@ -317,11 +319,11 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB)
byte_count += total_in_buf2;
/* BB also add check that we are not beyond maximum buffer size */
-
+
pTargetSMB->smb_buf_length = byte_count;
- if(remaining == total_in_buf2) {
- cFYI(1,("found the last secondary response"));
+ if (remaining == total_in_buf2) {
+ cFYI(1, ("found the last secondary response"));
return 0; /* we are done */
} else /* more responses to go */
return 1;
@@ -348,21 +350,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
int isMultiRsp;
int reconnect;
- allow_signal(SIGKILL);
current->flags |= PF_MEMALLOC;
server->tsk = current; /* save process info to wake at shutdown */
cFYI(1, ("Demultiplex PID: %d", current->pid));
- write_lock(&GlobalSMBSeslock);
+ write_lock(&GlobalSMBSeslock);
atomic_inc(&tcpSesAllocCount);
length = tcpSesAllocCount.counter;
write_unlock(&GlobalSMBSeslock);
complete(&cifsd_complete);
- if(length > 1) {
+ if (length > 1) {
mempool_resize(cifs_req_poolp,
length + cifs_min_rcv,
GFP_KERNEL);
}
+ set_freezable();
while (!kthread_should_stop()) {
if (try_to_freeze())
continue;
@@ -425,10 +427,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
break;
}
if (!try_to_freeze() && (length == -EINTR)) {
- cFYI(1,("cifsd thread killed"));
+ cFYI(1, ("cifsd thread killed"));
break;
}
- cFYI(1,("Reconnect after unexpected peek error %d",
+ cFYI(1, ("Reconnect after unexpected peek error %d",
length));
cifs_reconnect(server);
csocket = server->ssocket;
@@ -452,26 +454,26 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
with the most common, zero, as regular data */
temp = *((char *) smb_buffer);
- /* Note that FC 1001 length is big endian on the wire,
+ /* Note that FC 1001 length is big endian on the wire,
but we convert it here so it is always manipulated
as host byte order */
pdu_length = ntohl(smb_buffer->smb_buf_length);
smb_buffer->smb_buf_length = pdu_length;
- cFYI(1,("rfc1002 length 0x%x)", pdu_length+4));
+ cFYI(1, ("rfc1002 length 0x%x", pdu_length+4));
if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) {
- continue;
+ continue;
} else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) {
- cFYI(1,("Good RFC 1002 session rsp"));
+ cFYI(1, ("Good RFC 1002 session rsp"));
continue;
} else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) {
- /* we get this from Windows 98 instead of
+ /* we get this from Windows 98 instead of
an error on SMB negprot response */
- cFYI(1,("Negative RFC1002 Session Response Error 0x%x)",
+ cFYI(1, ("Negative RFC1002 Session Response Error 0x%x)",
pdu_length));
- if(server->tcpStatus == CifsNew) {
- /* if nack on negprot (rather than
+ if (server->tcpStatus == CifsNew) {
+ /* if nack on negprot (rather than
ret of smb negprot error) reconnecting
not going to help, ret error to mount */
break;
@@ -481,10 +483,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
msleep(1000);
/* always try 445 first on reconnect
since we get NACK on some if we ever
- connected to port 139 (the NACK is
+ connected to port 139 (the NACK is
since we do not begin with RFC1001
session initialize frame) */
- server->addr.sockAddr.sin_port =
+ server->addr.sockAddr.sin_port =
htons(CIFS_PORT);
cifs_reconnect(server);
csocket = server->ssocket;
@@ -492,7 +494,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
continue;
}
} else if (temp != (char) 0) {
- cERROR(1,("Unknown RFC 1002 frame"));
+ cERROR(1, ("Unknown RFC 1002 frame"));
cifs_dump_mem(" Received Data: ", (char *)smb_buffer,
length);
cifs_reconnect(server);
@@ -501,7 +503,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
/* else we have an SMB response */
- if((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
+ if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) ||
(pdu_length < sizeof (struct smb_hdr) - 1 - 4)) {
cERROR(1, ("Invalid size SMB length %d pdu_length %d",
length, pdu_length+4));
@@ -509,12 +511,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
csocket = server->ssocket;
wake_up(&server->response_q);
continue;
- }
+ }
/* else length ok */
reconnect = 0;
- if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
+ if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) {
isLargeBuf = TRUE;
memcpy(bigbuf, smallbuf, 4);
smb_buffer = bigbuf;
@@ -522,11 +524,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
length = 0;
iov.iov_base = 4 + (char *)smb_buffer;
iov.iov_len = pdu_length;
- for (total_read = 0; total_read < pdu_length;
+ for (total_read = 0; total_read < pdu_length;
total_read += length) {
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
pdu_length - total_read, 0);
- if( kthread_should_stop() ||
+ if ( kthread_should_stop() ||
(length == -EINTR)) {
/* then will exit */
reconnect = 2;
@@ -534,19 +536,19 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
} else if (server->tcpStatus == CifsNeedReconnect) {
cifs_reconnect(server);
csocket = server->ssocket;
- /* Reconnect wakes up rspns q */
+ /* Reconnect wakes up rspns q */
/* Now we will reread sock */
reconnect = 1;
break;
- } else if ((length == -ERESTARTSYS) ||
+ } else if ((length == -ERESTARTSYS) ||
(length == -EAGAIN)) {
msleep(1); /* minimum sleep to prevent looping,
- allowing socket to clear and app
+ allowing socket to clear and app
threads to set tcpStatus
CifsNeedReconnect if server hung*/
continue;
} else if (length <= 0) {
- cERROR(1,("Received no data, expecting %d",
+ cERROR(1, ("Received no data, expecting %d",
pdu_length - total_read));
cifs_reconnect(server);
csocket = server->ssocket;
@@ -554,13 +556,13 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
break;
}
}
- if(reconnect == 2)
+ if (reconnect == 2)
break;
- else if(reconnect == 1)
+ else if (reconnect == 1)
continue;
length += 4; /* account for rfc1002 hdr */
-
+
dump_smb(smb_buffer, length);
if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
@@ -574,28 +576,28 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
- if ((mid_entry->mid == smb_buffer->Mid) &&
+ if ((mid_entry->mid == smb_buffer->Mid) &&
(mid_entry->midState == MID_REQUEST_SUBMITTED) &&
(mid_entry->command == smb_buffer->Command)) {
- if(check2ndT2(smb_buffer,server->maxBuf) > 0) {
+ if (check2ndT2(smb_buffer,server->maxBuf) > 0) {
/* We have a multipart transact2 resp */
isMultiRsp = TRUE;
- if(mid_entry->resp_buf) {
+ if (mid_entry->resp_buf) {
/* merge response - fix up 1st*/
- if(coalesce_t2(smb_buffer,
+ if (coalesce_t2(smb_buffer,
mid_entry->resp_buf)) {
mid_entry->multiRsp = 1;
break;
} else {
/* all parts received */
mid_entry->multiEnd = 1;
- goto multi_t2_fnd;
+ goto multi_t2_fnd;
}
} else {
- if(!isLargeBuf) {
+ if (!isLargeBuf) {
cERROR(1,("1st trans2 resp needs bigbuf"));
/* BB maybe we can fix this up, switch
- to already allocated large buffer? */
+ to already allocated large buffer? */
} else {
/* Have first buffer */
mid_entry->resp_buf =
@@ -605,9 +607,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
}
}
break;
- }
+ }
mid_entry->resp_buf = smb_buffer;
- if(isLargeBuf)
+ if (isLargeBuf)
mid_entry->largeBuf = 1;
else
mid_entry->largeBuf = 0;
@@ -627,24 +629,25 @@ multi_t2_fnd:
spin_unlock(&GlobalMid_Lock);
if (task_to_wake) {
/* Was previous buf put in mpx struct for multi-rsp? */
- if(!isMultiRsp) {
+ if (!isMultiRsp) {
/* smb buffer will be freed by user thread */
- if(isLargeBuf) {
+ if (isLargeBuf) {
bigbuf = NULL;
} else
smallbuf = NULL;
}
wake_up_process(task_to_wake);
} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
- && (isMultiRsp == FALSE)) {
- cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
- cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
+ && (isMultiRsp == FALSE)) {
+ cERROR(1, ("No task to wake, unknown frame received! "
+ "NumMids %d", midCount.counter));
+ cifs_dump_mem("Received Data is: ", (char *)smb_buffer,
sizeof(struct smb_hdr));
#ifdef CONFIG_CIFS_DEBUG2
cifs_dump_detail(smb_buffer);
cifs_dump_mids(server);
#endif /* CIFS_DEBUG2 */
-
+
}
} /* end while !EXITING */
@@ -654,12 +657,12 @@ multi_t2_fnd:
/* check if we have blocked requests that need to free */
/* Note that cifs_max_pending is normally 50, but
can be set at module install time to as little as two */
- if(atomic_read(&server->inFlight) >= cifs_max_pending)
+ if (atomic_read(&server->inFlight) >= cifs_max_pending)
atomic_set(&server->inFlight, cifs_max_pending - 1);
/* We do not want to set the max_pending too low or we
could end up with the counter going negative */
spin_unlock(&GlobalMid_Lock);
- /* Although there should not be any requests blocked on
+ /* Although there should not be any requests blocked on
this queue it can not hurt to be paranoid and try to wake up requests
that may haven been blocked when more than 50 at time were on the wire
to the same server - they now will see the session is in exit state
@@ -667,8 +670,8 @@ multi_t2_fnd:
wake_up_all(&server->request_q);
/* give those requests time to exit */
msleep(125);
-
- if(server->ssocket) {
+
+ if (server->ssocket) {
sock_release(csocket);
server->ssocket = NULL;
}
@@ -708,10 +711,10 @@ multi_t2_fnd:
list_for_each(tmp, &server->pending_mid_q) {
mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
if (mid_entry->midState == MID_REQUEST_SUBMITTED) {
- cFYI(1,
- ("Clearing Mid 0x%x - waking up ",mid_entry->mid));
+ cFYI(1, ("Clearing Mid 0x%x - waking up ",
+ mid_entry->mid));
task_to_wake = mid_entry->tsk;
- if(task_to_wake) {
+ if (task_to_wake) {
wake_up_process(task_to_wake);
}
}
@@ -723,7 +726,7 @@ multi_t2_fnd:
}
if (!list_empty(&server->pending_mid_q)) {
- /* mpx threads have not exited yet give them
+ /* mpx threads have not exited yet give them
at least the smb send timeout time for long ops */
/* due to delays on oplock break requests, we need
to wait at least 45 seconds before giving up
@@ -741,7 +744,7 @@ multi_t2_fnd:
/* last chance to mark ses pointers invalid
if there are any pointing to this (e.g
- if a crazy root user tried to kill cifsd
+ if a crazy root user tried to kill cifsd
kernel thread explicitly this might happen) */
list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo,
@@ -753,17 +756,18 @@ multi_t2_fnd:
write_unlock(&GlobalSMBSeslock);
kfree(server);
- if(length > 0) {
+ if (length > 0) {
mempool_resize(cifs_req_poolp,
length + cifs_min_rcv,
GFP_KERNEL);
}
-
+
return 0;
}
static int
-cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
+cifs_parse_mount_options(char *options, const char *devname,
+ struct smb_vol *vol)
{
char *value;
char *data;
@@ -771,15 +775,15 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
char separator[2];
separator[0] = ',';
- separator[1] = 0;
+ separator[1] = 0;
if (Local_System_Name[0] != 0)
- memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+ memcpy(vol->source_rfc1001_name, Local_System_Name, 15);
else {
char *nodename = utsname()->nodename;
- int n = strnlen(nodename,15);
- memset(vol->source_rfc1001_name,0x20,15);
- for(i=0 ; i < n ; i++) {
+ int n = strnlen(nodename, 15);
+ memset(vol->source_rfc1001_name, 0x20, 15);
+ for (i = 0; i < n; i++) {
/* does not have to be perfect mapping since field is
informational, only used for servers that do not support
port 445 and it can be overridden at mount time */
@@ -804,31 +808,32 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if (!options)
return 1;
- if(strncmp(options,"sep=",4) == 0) {
- if(options[4] != 0) {
+ if (strncmp(options, "sep=", 4) == 0) {
+ if (options[4] != 0) {
separator[0] = options[4];
options += 5;
} else {
- cFYI(1,("Null separator not allowed"));
+ cFYI(1, ("Null separator not allowed"));
}
}
-
+
while ((data = strsep(&options, separator)) != NULL) {
if (!*data)
continue;
if ((value = strchr(data, '=')) != NULL)
*value++ = '\0';
- if (strnicmp(data, "user_xattr",10) == 0) {/*parse before user*/
+ /* Have to parse this before we parse for "user" */
+ if (strnicmp(data, "user_xattr", 10) == 0) {
vol->no_xattr = 0;
- } else if (strnicmp(data, "nouser_xattr",12) == 0) {
+ } else if (strnicmp(data, "nouser_xattr", 12) == 0) {
vol->no_xattr = 1;
} else if (strnicmp(data, "user", 4) == 0) {
if (!value) {
printk(KERN_WARNING
"CIFS: invalid or missing username\n");
return 1; /* needs_arg; */
- } else if(!*value) {
+ } else if (!*value) {
/* null user, ie anonymous, authentication */
vol->nullauth = 1;
}
@@ -842,12 +847,12 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
if (!value) {
vol->password = NULL;
continue;
- } else if(value[0] == 0) {
+ } else if (value[0] == 0) {
/* check if string begins with double comma
since that would mean the password really
does start with a comma, and would not
indicate an empty string */
- if(value[1] != separator[0]) {
+ if (value[1] != separator[0]) {
vol->password = NULL;
continue;
}
@@ -856,7 +861,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* removed password length check, NTLM passwords
can be arbitrarily long */
- /* if comma in password, the string will be
+ /* if comma in password, the string will be
prematurely null terminated. Commas in password are
specified across the cifs mount interface by a double
comma ie ,, and a comma used as in other cases ie ','
@@ -866,18 +871,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
/* NB: password legally can have multiple commas and
the only illegal character in a password is null */
- if ((value[temp_len] == 0) &&
+ if ((value[temp_len] == 0) &&
(value[temp_len+1] == separator[0])) {
/* reinsert comma */
value[temp_len] = separator[0];
- temp_len+=2; /* move after the second comma */
- while(value[temp_len] != 0) {
+ temp_len += 2; /* move after second comma */
+ while (value[temp_len] != 0) {
if (value[temp_len] == separator[0]) {
- if (value[temp_len+1] ==
+ if (value[temp_len+1] ==
separator[0]) {
/* skip second comma */
temp_len++;
- } else {
+ } else {
/* single comma indicating start
of next parm */
break;
@@ -885,24 +890,25 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
}
temp_len++;
}
- if(value[temp_len] == 0) {
+ if (value[temp_len] == 0) {
options = NULL;
} else {
value[temp_len] = 0;
/* point option to start of next parm */
options = value + temp_len + 1;
}
- /* go from value to value + temp_len condensing
+ /* go from value to value + temp_len condensing
double commas to singles. Note that this ends up
allocating a few bytes too many, which is ok */
vol->password = kzalloc(temp_len, GFP_KERNEL);
- if(vol->password == NULL) {
- printk("CIFS: no memory for pass\n");
+ if (vol->password == NULL) {
+ printk(KERN_WARNING "CIFS: no memory "
+ "for password\n");
return 1;
}
- for(i=0,j=0;i<temp_len;i++,j++) {
+ for (i = 0, j = 0; i < temp_len; i++, j++) {
vol->password[j] = value[i];
- if(value[i] == separator[0]
+ if (value[i] == separator[0]
&& value[i+1] == separator[0]) {
/* skip second comma */
i++;
@@ -911,8 +917,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->password[j] = 0;
} else {
vol->password = kzalloc(temp_len+1, GFP_KERNEL);
- if(vol->password == NULL) {
- printk("CIFS: no memory for pass\n");
+ if (vol->password == NULL) {
+ printk(KERN_WARNING "CIFS: no memory "
+ "for password\n");
return 1;
}
strcpy(vol->password, value);
@@ -923,20 +930,21 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
} else if (strnlen(value, 35) < 35) {
vol->UNCip = value;
} else {
- printk(KERN_WARNING "CIFS: ip address too long\n");
+ printk(KERN_WARNING "CIFS: ip address "
+ "too long\n");
return 1;
}
- } else if (strnicmp(data, "sec", 3) == 0) {
- if (!value || !*value) {
- cERROR(1,("no security value specified"));
- continue;
- } else if (strnicmp(value, "krb5i", 5) == 0) {
- vol->secFlg |= CIFSSEC_MAY_KRB5 |
+ } else if (strnicmp(data, "sec", 3) == 0) {
+ if (!value || !*value) {
+ cERROR(1, ("no security value specified"));
+ continue;
+ } else if (strnicmp(value, "krb5i", 5) == 0) {
+ vol->secFlg |= CIFSSEC_MAY_KRB5 |
CIFSSEC_MUST_SIGN;
} else if (strnicmp(value, "krb5p", 5) == 0) {
- /* vol->secFlg |= CIFSSEC_MUST_SEAL |
- CIFSSEC_MAY_KRB5; */
- cERROR(1,("Krb5 cifs privacy not supported"));
+ /* vol->secFlg |= CIFSSEC_MUST_SEAL |
+ CIFSSEC_MAY_KRB5; */
+ cERROR(1, ("Krb5 cifs privacy not supported"));
return 1;
} else if (strnicmp(value, "krb5", 4) == 0) {
vol->secFlg |= CIFSSEC_MAY_KRB5;
@@ -956,33 +964,34 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->secFlg |= CIFSSEC_MAY_NTLMV2;
#ifdef CONFIG_CIFS_WEAK_PW_HASH
} else if (strnicmp(value, "lanman", 6) == 0) {
- vol->secFlg |= CIFSSEC_MAY_LANMAN;
+ vol->secFlg |= CIFSSEC_MAY_LANMAN;
#endif
} else if (strnicmp(value, "none", 4) == 0) {
vol->nullauth = 1;
- } else {
- cERROR(1,("bad security option: %s", value));
- return 1;
- }
+ } else {
+ cERROR(1, ("bad security option: %s", value));
+ return 1;
+ }
} else if ((strnicmp(data, "unc", 3) == 0)
|| (strnicmp(data, "target", 6) == 0)
|| (strnicmp(data, "path", 4) == 0)) {
if (!value || !*value) {
- printk(KERN_WARNING
- "CIFS: invalid path to network resource\n");
+ printk(KERN_WARNING "CIFS: invalid path to "
+ "network resource\n");
return 1; /* needs_arg; */
}
if ((temp_len = strnlen(value, 300)) < 300) {
- vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+ vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
if (vol->UNC == NULL)
return 1;
- strcpy(vol->UNC,value);
+ strcpy(vol->UNC, value);
if (strncmp(vol->UNC, "//", 2) == 0) {
vol->UNC[0] = '\\';
vol->UNC[1] = '\\';
- } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
+ } else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
printk(KERN_WARNING
- "CIFS: UNC Path does not begin with // or \\\\ \n");
+ "CIFS: UNC Path does not begin "
+ "with // or \\\\ \n");
return 1;
}
} else {
@@ -1001,43 +1010,47 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->domainname = value;
cFYI(1, ("Domain name set"));
} else {
- printk(KERN_WARNING "CIFS: domain name too long\n");
+ printk(KERN_WARNING "CIFS: domain name too "
+ "long\n");
return 1;
}
- } else if (strnicmp(data, "prefixpath", 10) == 0) {
- if (!value || !*value) {
- printk(KERN_WARNING
- "CIFS: invalid path prefix\n");
- return 1; /* needs_arg; */
- }
- if ((temp_len = strnlen(value, 1024)) < 1024) {
+ } else if (strnicmp(data, "prefixpath", 10) == 0) {
+ if (!value || !*value) {
+ printk(KERN_WARNING
+ "CIFS: invalid path prefix\n");
+ return 1; /* needs_argument */
+ }
+ if ((temp_len = strnlen(value, 1024)) < 1024) {
if (value[0] != '/')
temp_len++; /* missing leading slash */
- vol->prepath = kmalloc(temp_len+1,GFP_KERNEL);
- if (vol->prepath == NULL)
- return 1;
+ vol->prepath = kmalloc(temp_len+1, GFP_KERNEL);
+ if (vol->prepath == NULL)
+ return 1;
if (value[0] != '/') {
vol->prepath[0] = '/';
- strcpy(vol->prepath+1,value);
+ strcpy(vol->prepath+1, value);
} else
- strcpy(vol->prepath,value);
- cFYI(1,("prefix path %s",vol->prepath));
- } else {
- printk(KERN_WARNING "CIFS: prefix too long\n");
- return 1;
- }
+ strcpy(vol->prepath, value);
+ cFYI(1, ("prefix path %s", vol->prepath));
+ } else {
+ printk(KERN_WARNING "CIFS: prefix too long\n");
+ return 1;
+ }
} else if (strnicmp(data, "iocharset", 9) == 0) {
if (!value || !*value) {
- printk(KERN_WARNING "CIFS: invalid iocharset specified\n");
+ printk(KERN_WARNING "CIFS: invalid iocharset "
+ "specified\n");
return 1; /* needs_arg; */
}
if (strnlen(value, 65) < 65) {
- if (strnicmp(value,"default",7))
+ if (strnicmp(value, "default", 7))
vol->iocharset = value;
- /* if iocharset not set load_nls_default used by caller */
- cFYI(1, ("iocharset set to %s",value));
+ /* if iocharset not set then load_nls_default
+ is used by caller */
+ cFYI(1, ("iocharset set to %s", value));
} else {
- printk(KERN_WARNING "CIFS: iocharset name too long.\n");
+ printk(KERN_WARNING "CIFS: iocharset name "
+ "too long.\n");
return 1;
}
} else if (strnicmp(data, "uid", 3) == 0) {
@@ -1089,54 +1102,59 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
}
} else if (strnicmp(data, "netbiosname", 4) == 0) {
if (!value || !*value || (*value == ' ')) {
- cFYI(1,("invalid (empty) netbiosname specified"));
+ cFYI(1, ("invalid (empty) netbiosname"));
} else {
- memset(vol->source_rfc1001_name,0x20,15);
- for(i=0;i<15;i++) {
- /* BB are there cases in which a comma can be
+ memset(vol->source_rfc1001_name, 0x20, 15);
+ for (i = 0; i < 15; i++) {
+ /* BB are there cases in which a comma can be
valid in this workstation netbios name (and need
special handling)? */
/* We do not uppercase netbiosname for user */
- if (value[i]==0)
+ if (value[i] == 0)
break;
- else
- vol->source_rfc1001_name[i] = value[i];
+ else
+ vol->source_rfc1001_name[i] =
+ value[i];
}
/* The string has 16th byte zero still from
set at top of the function */
- if ((i==15) && (value[i] != 0))
- printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n");
+ if ((i == 15) && (value[i] != 0))
+ printk(KERN_WARNING "CIFS: netbiosname"
+ " longer than 15 truncated.\n");
}
} else if (strnicmp(data, "servern", 7) == 0) {
/* servernetbiosname specified override *SMBSERVER */
if (!value || !*value || (*value == ' ')) {
- cFYI(1,("empty server netbiosname specified"));
+ cFYI(1, ("empty server netbiosname specified"));
} else {
/* last byte, type, is 0x20 for servr type */
- memset(vol->target_rfc1001_name,0x20,16);
+ memset(vol->target_rfc1001_name, 0x20, 16);
- for(i=0;i<15;i++) {
+ for (i = 0; i < 15; i++) {
/* BB are there cases in which a comma can be
- valid in this workstation netbios name (and need
- special handling)? */
+ valid in this workstation netbios name
+ (and need special handling)? */
- /* user or mount helper must uppercase netbiosname */
- if (value[i]==0)
+ /* user or mount helper must uppercase
+ the netbiosname */
+ if (value[i] == 0)
break;
else
- vol->target_rfc1001_name[i] = value[i];
+ vol->target_rfc1001_name[i] =
+ value[i];
}
/* The string has 16th byte zero still from
set at top of the function */
- if ((i==15) && (value[i] != 0))
- printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n");
+ if ((i == 15) && (value[i] != 0))
+ printk(KERN_WARNING "CIFS: server net"
+ "biosname longer than 15 truncated.\n");
}
} else if (strnicmp(data, "credentials", 4) == 0) {
/* ignore */
} else if (strnicmp(data, "version", 3) == 0) {
/* ignore */
- } else if (strnicmp(data, "guest",5) == 0) {
+ } else if (strnicmp(data, "guest", 5) == 0) {
/* ignore */
} else if (strnicmp(data, "rw", 2) == 0) {
vol->rw = TRUE;
@@ -1148,11 +1166,11 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
(strnicmp(data, "noauto", 6) == 0) ||
(strnicmp(data, "dev", 3) == 0)) {
/* The mount tool or mount.cifs helper (if present)
- uses these opts to set flags, and the flags are read
- by the kernel vfs layer before we get here (ie
- before read super) so there is no point trying to
- parse these options again and set anything and it
- is ok to just ignore them */
+ uses these opts to set flags, and the flags are read
+ by the kernel vfs layer before we get here (ie
+ before read super) so there is no point trying to
+ parse these options again and set anything and it
+ is ok to just ignore them */
continue;
} else if (strnicmp(data, "ro", 2) == 0) {
vol->rw = FALSE;
@@ -1168,26 +1186,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->remap = 1;
} else if (strnicmp(data, "nomapchars", 10) == 0) {
vol->remap = 0;
- } else if (strnicmp(data, "sfu", 3) == 0) {
- vol->sfu_emul = 1;
- } else if (strnicmp(data, "nosfu", 5) == 0) {
- vol->sfu_emul = 0;
+ } else if (strnicmp(data, "sfu", 3) == 0) {
+ vol->sfu_emul = 1;
+ } else if (strnicmp(data, "nosfu", 5) == 0) {
+ vol->sfu_emul = 0;
} else if (strnicmp(data, "posixpaths", 10) == 0) {
vol->posix_paths = 1;
} else if (strnicmp(data, "noposixpaths", 12) == 0) {
vol->posix_paths = 0;
- } else if ((strnicmp(data, "nocase", 6) == 0) ||
+ } else if (strnicmp(data, "nounix", 6) == 0) {
+ vol->no_linux_ext = 1;
+ } else if (strnicmp(data, "nolinux", 7) == 0) {
+ vol->no_linux_ext = 1;
+ } else if ((strnicmp(data, "nocase", 6) == 0) ||
(strnicmp(data, "ignorecase", 10) == 0)) {
- vol->nocase = 1;
+ vol->nocase = 1;
} else if (strnicmp(data, "brl", 3) == 0) {
vol->nobrl = 0;
- } else if ((strnicmp(data, "nobrl", 5) == 0) ||
+ } else if ((strnicmp(data, "nobrl", 5) == 0) ||
(strnicmp(data, "nolock", 6) == 0)) {
vol->nobrl = 1;
/* turn off mandatory locking in mode
if remote locking is turned off since the
local vfs will do advisory */
- if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
+ if (vol->file_mode ==
+ (S_IALLUGO & ~(S_ISUID | S_IXGRP)))
vol->file_mode = S_IALLUGO;
} else if (strnicmp(data, "setuids", 7) == 0) {
vol->setuids = 1;
@@ -1201,55 +1224,61 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
vol->intr = 0;
} else if (strnicmp(data, "intr", 4) == 0) {
vol->intr = 1;
- } else if (strnicmp(data, "serverino",7) == 0) {
+ } else if (strnicmp(data, "serverino", 7) == 0) {
vol->server_ino = 1;
- } else if (strnicmp(data, "noserverino",9) == 0) {
+ } else if (strnicmp(data, "noserverino", 9) == 0) {
vol->server_ino = 0;
- } else if (strnicmp(data, "cifsacl",7) == 0) {
+ } else if (strnicmp(data, "cifsacl", 7) == 0) {
vol->cifs_acl = 1;
} else if (strnicmp(data, "nocifsacl", 9) == 0) {
vol->cifs_acl = 0;
- } else if (strnicmp(data, "acl",3) == 0) {
+ } else if (strnicmp(data, "acl", 3) == 0) {
vol->no_psx_acl = 0;
- } else if (strnicmp(data, "noacl",5) == 0) {
+ } else if (strnicmp(data, "noacl", 5) == 0) {
vol->no_psx_acl = 1;
- } else if (strnicmp(data, "sign",4) == 0) {
+ } else if (strnicmp(data, "sign", 4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SIGN;
/* } else if (strnicmp(data, "seal",4) == 0) {
vol->secFlg |= CIFSSEC_MUST_SEAL; */
- } else if (strnicmp(data, "direct",6) == 0) {
+ } else if (strnicmp(data, "direct", 6) == 0) {
vol->direct_io = 1;
- } else if (strnicmp(data, "forcedirectio",13) == 0) {
+ } else if (strnicmp(data, "forcedirectio", 13) == 0) {
vol->direct_io = 1;
- } else if (strnicmp(data, "in6_addr",8) == 0) {
+ } else if (strnicmp(data, "in6_addr", 8) == 0) {
if (!value || !*value) {
vol->in6_addr = NULL;
} else if (strnlen(value, 49) == 48) {
vol->in6_addr = value;
} else {
- printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
+ printk(KERN_WARNING "CIFS: ip v6 address not "
+ "48 characters long\n");
return 1;
}
} else if (strnicmp(data, "noac", 4) == 0) {
- printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
+ printk(KERN_WARNING "CIFS: Mount option noac not "
+ "supported. Instead set "
+ "/proc/fs/cifs/LookupCacheEnabled to 0\n");
} else
- printk(KERN_WARNING "CIFS: Unknown mount option %s\n",data);
+ printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
+ data);
}
if (vol->UNC == NULL) {
if (devname == NULL) {
- printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n");
+ printk(KERN_WARNING "CIFS: Missing UNC name for mount "
+ "target\n");
return 1;
}
if ((temp_len = strnlen(devname, 300)) < 300) {
- vol->UNC = kmalloc(temp_len+1,GFP_KERNEL);
+ vol->UNC = kmalloc(temp_len+1, GFP_KERNEL);
if (vol->UNC == NULL)
return 1;
- strcpy(vol->UNC,devname);
+ strcpy(vol->UNC, devname);
if (strncmp(vol->UNC, "//", 2) == 0) {
vol->UNC[0] = '\\';
vol->UNC[1] = '\\';
} else if (strncmp(vol->UNC, "\\\\", 2) != 0) {
- printk(KERN_WARNING "CIFS: UNC Path does not begin with // or \\\\ \n");
+ printk(KERN_WARNING "CIFS: UNC Path does not "
+ "begin with // or \\\\ \n");
return 1;
}
} else {
@@ -1257,14 +1286,14 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
return 1;
}
}
- if(vol->UNCip == NULL)
+ if (vol->UNCip == NULL)
vol->UNCip = &vol->UNC[2];
return 0;
}
static struct cifsSesInfo *
-cifs_find_tcp_session(struct in_addr * target_ip_addr,
+cifs_find_tcp_session(struct in_addr *target_ip_addr,
struct in6_addr *target_ip6_addr,
char *userName, struct TCP_Server_Info **psrvTcp)
{
@@ -1276,19 +1305,25 @@ cifs_find_tcp_session(struct in_addr * target_ip_addr,
list_for_each(tmp, &GlobalSMBSessionList) {
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
if (ses->server) {
- if((target_ip_addr &&
+ if ((target_ip_addr &&
(ses->server->addr.sockAddr.sin_addr.s_addr
== target_ip_addr->s_addr)) || (target_ip6_addr
&& memcmp(&ses->server->addr.sockAddr6.sin6_addr,
- target_ip6_addr,sizeof(*target_ip6_addr)))){
- /* BB lock server and tcp session and increment use count here?? */
- *psrvTcp = ses->server; /* found a match on the TCP session */
+ target_ip6_addr, sizeof(*target_ip6_addr)))) {
+ /* BB lock server and tcp session and increment
+ use count here?? */
+
+ /* found a match on the TCP session */
+ *psrvTcp = ses->server;
+
/* BB check if reconnection needed */
if (strncmp
(ses->userName, userName,
MAX_USERNAME_SIZE) == 0){
read_unlock(&GlobalSMBSeslock);
- return ses; /* found exact match on both tcp and SMB sessions */
+ /* Found exact match on both TCP and
+ SMB sessions */
+ return ses;
}
}
}
@@ -1319,7 +1354,8 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
/* BB lock tcon, server and tcp session and increment use count here? */
/* found a match on the TCP session */
/* BB check if reconnection needed */
- cFYI(1,("IP match, old UNC: %s new: %s",
+ cFYI(1,
+ ("IP match, old UNC: %s new: %s",
tcon->treeName, uncName));
if (strncmp
(tcon->treeName, uncName,
@@ -1354,11 +1390,11 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
unsigned int num_referrals;
int rc = 0;
- rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
+ rc = get_dfs_path(xid, pSesInfo, old_path, nls_codepage,
&num_referrals, &referrals, remap);
/* BB Add in code to: if valid refrl, if not ip address contact
- the helper that resolves tcp names, mount to it, try to
+ the helper that resolves tcp names, mount to it, try to
tcon to it unmount it if fail */
kfree(referrals);
@@ -1367,10 +1403,9 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
}
int
-get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
- const char *old_path, const struct nls_table *nls_codepage,
- unsigned int *pnum_referrals,
- unsigned char ** preferrals, int remap)
+get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
+ const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
+ unsigned char **preferrals, int remap)
{
char *temp_unc;
int rc = 0;
@@ -1379,7 +1414,8 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
if (pSesInfo->ipc_tid == 0) {
temp_unc = kmalloc(2 /* for slashes */ +
- strnlen(pSesInfo->serverName,SERVER_NAME_LEN_WITH_NULL * 2)
+ strnlen(pSesInfo->serverName,
+ SERVER_NAME_LEN_WITH_NULL * 2)
+ 1 + 4 /* slash IPC$ */ + 2,
GFP_KERNEL);
if (temp_unc == NULL)
@@ -1390,7 +1426,7 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
strcpy(temp_unc + 2 + strlen(pSesInfo->serverName), "\\IPC$");
rc = CIFSTCon(xid, pSesInfo, temp_unc, NULL, nls_codepage);
cFYI(1,
- ("CIFS Tcon rc = %d ipc_tid = %d", rc,pSesInfo->ipc_tid));
+ ("CIFS Tcon rc = %d ipc_tid = %d", rc, pSesInfo->ipc_tid));
kfree(temp_unc);
}
if (rc == 0)
@@ -1401,62 +1437,63 @@ get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
}
/* See RFC1001 section 14 on representation of Netbios names */
-static void rfc1002mangle(char * target,char * source, unsigned int length)
+static void rfc1002mangle(char *target, char *source, unsigned int length)
{
- unsigned int i,j;
+ unsigned int i, j;
- for(i=0,j=0;i<(length);i++) {
+ for (i = 0, j = 0; i < (length); i++) {
/* mask a nibble at a time and encode */
target[j] = 'A' + (0x0F & (source[i] >> 4));
target[j+1] = 'A' + (0x0F & source[i]);
- j+=2;
+ j += 2;
}
}
static int
-ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
- char * netbios_name, char * target_name)
+ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
+ char *netbios_name, char *target_name)
{
int rc = 0;
int connected = 0;
__be16 orig_port = 0;
- if(*csocket == NULL) {
- rc = sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, csocket);
+ if (*csocket == NULL) {
+ rc = sock_create_kern(PF_INET, SOCK_STREAM,
+ IPPROTO_TCP, csocket);
if (rc < 0) {
- cERROR(1, ("Error %d creating socket",rc));
+ cERROR(1, ("Error %d creating socket", rc));
*csocket = NULL;
return rc;
} else {
/* BB other socket options to set KEEPALIVE, NODELAY? */
- cFYI(1,("Socket created"));
- (*csocket)->sk->sk_allocation = GFP_NOFS;
+ cFYI(1, ("Socket created"));
+ (*csocket)->sk->sk_allocation = GFP_NOFS;
}
}
psin_server->sin_family = AF_INET;
- if(psin_server->sin_port) { /* user overrode default port */
+ if (psin_server->sin_port) { /* user overrode default port */
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
- sizeof (struct sockaddr_in),0);
+ sizeof (struct sockaddr_in), 0);
if (rc >= 0)
connected = 1;
- }
+ }
- if(!connected) {
- /* save original port so we can retry user specified port
+ if (!connected) {
+ /* save original port so we can retry user specified port
later if fall back ports fail this time */
orig_port = psin_server->sin_port;
/* do not retry on the same port we just failed on */
- if(psin_server->sin_port != htons(CIFS_PORT)) {
+ if (psin_server->sin_port != htons(CIFS_PORT)) {
psin_server->sin_port = htons(CIFS_PORT);
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
- sizeof (struct sockaddr_in),0);
+ sizeof (struct sockaddr_in), 0);
if (rc >= 0)
connected = 1;
}
@@ -1464,60 +1501,63 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
if (!connected) {
psin_server->sin_port = htons(RFC1001_PORT);
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
- psin_server, sizeof (struct sockaddr_in),0);
- if (rc >= 0)
+ psin_server,
+ sizeof (struct sockaddr_in), 0);
+ if (rc >= 0)
connected = 1;
}
/* give up here - unless we want to retry on different
protocol families some day */
if (!connected) {
- if(orig_port)
+ if (orig_port)
psin_server->sin_port = orig_port;
- cFYI(1,("Error %d connecting to server via ipv4",rc));
+ cFYI(1, ("Error %d connecting to server via ipv4", rc));
sock_release(*csocket);
*csocket = NULL;
return rc;
}
- /* Eventually check for other socket options to change from
- the default. sock_setsockopt not used because it expects
+ /* Eventually check for other socket options to change from
+ the default. sock_setsockopt not used because it expects
user space buffer */
- cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf,
+ cFYI(1, ("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",
+ (*csocket)->sk->sk_sndbuf,
(*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
/* make the bufsizes depend on wsize/rsize and max requests */
- if((*csocket)->sk->sk_sndbuf < (200 * 1024))
+ if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
(*csocket)->sk->sk_sndbuf = 200 * 1024;
- if((*csocket)->sk->sk_rcvbuf < (140 * 1024))
+ if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
(*csocket)->sk->sk_rcvbuf = 140 * 1024;
/* send RFC1001 sessinit */
- if(psin_server->sin_port == htons(RFC1001_PORT)) {
+ if (psin_server->sin_port == htons(RFC1001_PORT)) {
/* some servers require RFC1001 sessinit before sending
- negprot - BB check reconnection in case where second
+ negprot - BB check reconnection in case where second
sessinit is sent but no second negprot */
- struct rfc1002_session_packet * ses_init_buf;
- struct smb_hdr * smb_buf;
- ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL);
- if(ses_init_buf) {
+ struct rfc1002_session_packet *ses_init_buf;
+ struct smb_hdr *smb_buf;
+ ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
+ GFP_KERNEL);
+ if (ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32;
- if(target_name && (target_name[0] != 0)) {
+ if (target_name && (target_name[0] != 0)) {
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
target_name, 16);
} else {
rfc1002mangle(ses_init_buf->trailer.session_req.called_name,
- DEFAULT_CIFS_CALLED_NAME,16);
+ DEFAULT_CIFS_CALLED_NAME, 16);
}
ses_init_buf->trailer.session_req.calling_len = 32;
/* calling name ends in null (byte 16) from old smb
convention. */
- if(netbios_name && (netbios_name[0] !=0)) {
+ if (netbios_name && (netbios_name[0] != 0)) {
rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
- netbios_name,16);
+ netbios_name, 16);
} else {
rfc1002mangle(ses_init_buf->trailer.session_req.calling_name,
- "LINUX_CIFS_CLNT",16);
+ "LINUX_CIFS_CLNT", 16);
}
ses_init_buf->trailer.session_req.scope1 = 0;
ses_init_buf->trailer.session_req.scope2 = 0;
@@ -1527,20 +1567,20 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
rc = smb_send(*csocket, smb_buf, 0x44,
(struct sockaddr *)psin_server);
kfree(ses_init_buf);
- msleep(1); /* RFC1001 layer in at least one server
+ msleep(1); /* RFC1001 layer in at least one server
requires very short break before negprot
presumably because not expecting negprot
to follow so fast. This is a simple
- solution that works without
+ solution that works without
complicating the code and causes no
significant slowing down on mount
for everyone else */
}
- /* else the negprot may still work without this
+ /* else the negprot may still work without this
even though malloc failed */
-
+
}
-
+
return rc;
}
@@ -1551,41 +1591,42 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
int connected = 0;
__be16 orig_port = 0;
- if(*csocket == NULL) {
- rc = sock_create_kern(PF_INET6, SOCK_STREAM, IPPROTO_TCP, csocket);
+ if (*csocket == NULL) {
+ rc = sock_create_kern(PF_INET6, SOCK_STREAM,
+ IPPROTO_TCP, csocket);
if (rc < 0) {
- cERROR(1, ("Error %d creating ipv6 socket",rc));
+ cERROR(1, ("Error %d creating ipv6 socket", rc));
*csocket = NULL;
return rc;
} else {
/* BB other socket options to set KEEPALIVE, NODELAY? */
- cFYI(1,("ipv6 Socket created"));
+ cFYI(1, ("ipv6 Socket created"));
(*csocket)->sk->sk_allocation = GFP_NOFS;
}
}
psin_server->sin6_family = AF_INET6;
- if(psin_server->sin6_port) { /* user overrode default port */
+ if (psin_server->sin6_port) { /* user overrode default port */
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
- sizeof (struct sockaddr_in6),0);
+ sizeof (struct sockaddr_in6), 0);
if (rc >= 0)
connected = 1;
- }
+ }
- if(!connected) {
- /* save original port so we can retry user specified port
+ if (!connected) {
+ /* save original port so we can retry user specified port
later if fall back ports fail this time */
orig_port = psin_server->sin6_port;
/* do not retry on the same port we just failed on */
- if(psin_server->sin6_port != htons(CIFS_PORT)) {
+ if (psin_server->sin6_port != htons(CIFS_PORT)) {
psin_server->sin6_port = htons(CIFS_PORT);
rc = (*csocket)->ops->connect(*csocket,
(struct sockaddr *) psin_server,
- sizeof (struct sockaddr_in6),0);
+ sizeof (struct sockaddr_in6), 0);
if (rc >= 0)
connected = 1;
}
@@ -1593,31 +1634,31 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
if (!connected) {
psin_server->sin6_port = htons(RFC1001_PORT);
rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *)
- psin_server, sizeof (struct sockaddr_in6),0);
- if (rc >= 0)
+ psin_server, sizeof (struct sockaddr_in6), 0);
+ if (rc >= 0)
connected = 1;
}
/* give up here - unless we want to retry on different
protocol families some day */
if (!connected) {
- if(orig_port)
+ if (orig_port)
psin_server->sin6_port = orig_port;
- cFYI(1,("Error %d connecting to server via ipv6",rc));
+ cFYI(1, ("Error %d connecting to server via ipv6", rc));
sock_release(*csocket);
*csocket = NULL;
return rc;
}
- /* Eventually check for other socket options to change from
- the default. sock_setsockopt not used because it expects
+ /* Eventually check for other socket options to change from
+ the default. sock_setsockopt not used because it expects
user space buffer */
(*csocket)->sk->sk_rcvtimeo = 7 * HZ;
-
+
return rc;
}
-void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
- struct super_block * sb, struct smb_vol * vol_info)
+void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon,
+ struct super_block *sb, struct smb_vol *vol_info)
{
/* if we are reconnecting then should we check to see if
* any requested capabilities changed locally e.g. via
@@ -1629,65 +1670,87 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon,
* What if we wanted to mount the server share twice once with
* and once without posixacls or posix paths? */
__u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-
-
- if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
+
+ if (vol_info && vol_info->no_linux_ext) {
+ tcon->fsUnixInfo.Capability = 0;
+ tcon->unix_ext = 0; /* Unix Extensions disabled */
+ cFYI(1, ("Linux protocol extensions disabled"));
+ return;
+ } else if (vol_info)
+ tcon->unix_ext = 1; /* Unix Extensions supported */
+
+ if (tcon->unix_ext == 0) {
+ cFYI(1, ("Unix extensions disabled so not set on reconnect"));
+ return;
+ }
+
+ if (!CIFSSMBQFSUnixInfo(xid, tcon)) {
__u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-
+
/* check for reconnect case in which we do not
want to change the mount behavior if we can avoid it */
- if(vol_info == NULL) {
- /* turn off POSIX ACL and PATHNAMES if not set
+ if (vol_info == NULL) {
+ /* turn off POSIX ACL and PATHNAMES if not set
originally at mount time */
if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
-
-
-
-
}
-
+
cap &= CIFS_UNIX_CAP_MASK;
- if(vol_info && vol_info->no_psx_acl)
+ if (vol_info && vol_info->no_psx_acl)
cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
- else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
- cFYI(1,("negotiated posix acl support"));
- if(sb)
+ else if (CIFS_UNIX_POSIX_ACL_CAP & cap) {
+ cFYI(1, ("negotiated posix acl support"));
+ if (sb)
sb->s_flags |= MS_POSIXACL;
}
- if(vol_info && vol_info->posix_paths == 0)
+ if (vol_info && vol_info->posix_paths == 0)
cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
- else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
- cFYI(1,("negotiate posix pathnames"));
- if(sb)
- CIFS_SB(sb)->mnt_cifs_flags |=
+ else if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+ cFYI(1, ("negotiate posix pathnames"));
+ if (sb)
+ CIFS_SB(sb)->mnt_cifs_flags |=
CIFS_MOUNT_POSIX_PATHS;
}
-
+
/* We might be setting the path sep back to a different
form if we are reconnecting and the server switched its
- posix path capability for this share */
- if(sb && (CIFS_SB(sb)->prepathlen > 0))
+ posix path capability for this share */
+ if (sb && (CIFS_SB(sb)->prepathlen > 0))
CIFS_SB(sb)->prepath[0] = CIFS_DIR_SEP(CIFS_SB(sb));
-
- cFYI(1,("Negotiate caps 0x%x",(int)cap));
+
+ if (sb && (CIFS_SB(sb)->rsize > 127 * 1024)) {
+ if ((cap & CIFS_UNIX_LARGE_READ_CAP) == 0) {
+ CIFS_SB(sb)->rsize = 127 * 1024;
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1, ("larger reads not supported by srv"));
+#endif
+ }
+ }
+
+
+ cFYI(1, ("Negotiate caps 0x%x", (int)cap));
#ifdef CONFIG_CIFS_DEBUG2
- if(cap & CIFS_UNIX_FCNTL_CAP)
- cFYI(1,("FCNTL cap"));
- if(cap & CIFS_UNIX_EXTATTR_CAP)
- cFYI(1,("EXTATTR cap"));
- if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
- cFYI(1,("POSIX path cap"));
- if(cap & CIFS_UNIX_XATTR_CAP)
- cFYI(1,("XATTR cap"));
- if(cap & CIFS_UNIX_POSIX_ACL_CAP)
- cFYI(1,("POSIX ACL cap"));
+ if (cap & CIFS_UNIX_FCNTL_CAP)
+ cFYI(1, ("FCNTL cap"));
+ if (cap & CIFS_UNIX_EXTATTR_CAP)
+ cFYI(1, ("EXTATTR cap"));
+ if (cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+ cFYI(1, ("POSIX path cap"));
+ if (cap & CIFS_UNIX_XATTR_CAP)
+ cFYI(1, ("XATTR cap"));
+ if (cap & CIFS_UNIX_POSIX_ACL_CAP)
+ cFYI(1, ("POSIX ACL cap"));
+ if (cap & CIFS_UNIX_LARGE_READ_CAP)
+ cFYI(1, ("very large read cap"));
+ if (cap & CIFS_UNIX_LARGE_WRITE_CAP)
+ cFYI(1, ("very large write cap"));
#endif /* CIFS_DEBUG2 */
if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
- cFYI(1,("setting capabilities failed"));
+ cFYI(1, ("setting capabilities failed"));
}
}
}
@@ -1711,8 +1774,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
xid = GetXid();
/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
-
- memset(&volume_info,0,sizeof(struct smb_vol));
+
+ memset(&volume_info, 0, sizeof(struct smb_vol));
if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
kfree(volume_info.UNC);
kfree(volume_info.password);
@@ -1722,15 +1785,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
if (volume_info.nullauth) {
- cFYI(1,("null user"));
+ cFYI(1, ("null user"));
volume_info.username = NULL;
} else if (volume_info.username) {
/* BB fixme parse for domain name here */
- cFYI(1, ("Username: %s ", volume_info.username));
+ cFYI(1, ("Username: %s", volume_info.username));
} else {
cifserror("No username specified");
- /* In userspace mount helper we can get user name from alternate
- locations such as env variables and files on disk */
+ /* In userspace mount helper we can get user name from alternate
+ locations such as env variables and files on disk */
kfree(volume_info.UNC);
kfree(volume_info.password);
kfree(volume_info.prepath);
@@ -1739,18 +1802,20 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
if (volume_info.UNCip && volume_info.UNC) {
- rc = cifs_inet_pton(AF_INET, volume_info.UNCip,&sin_server.sin_addr.s_addr);
+ rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
+ &sin_server.sin_addr.s_addr);
- if(rc <= 0) {
+ if (rc <= 0) {
/* not ipv4 address, try ipv6 */
- rc = cifs_inet_pton(AF_INET6,volume_info.UNCip,&sin_server6.sin6_addr.in6_u);
- if(rc > 0)
+ rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
+ &sin_server6.sin6_addr.in6_u);
+ if (rc > 0)
address_type = AF_INET6;
} else {
address_type = AF_INET;
}
-
- if(rc <= 0) {
+
+ if (rc <= 0) {
/* we failed translating address */
kfree(volume_info.UNC);
kfree(volume_info.password);
@@ -1762,9 +1827,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cFYI(1, ("UNC: %s ip: %s", volume_info.UNC, volume_info.UNCip));
/* success */
rc = 0;
- } else if (volume_info.UNCip){
- /* BB using ip addr as server name connect to the DFS root below */
- cERROR(1,("Connecting to DFS root not implemented yet"));
+ } else if (volume_info.UNCip) {
+ /* BB using ip addr as server name to connect to the
+ DFS root below */
+ cERROR(1, ("Connecting to DFS root not implemented yet"));
kfree(volume_info.UNC);
kfree(volume_info.password);
kfree(volume_info.prepath);
@@ -1772,7 +1838,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL;
} else /* which servers DFS root would we conect to */ {
cERROR(1,
- ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified"));
+ ("CIFS mount error: No UNC path (e.g. -o "
+ "unc=//192.168.1.100/public) specified"));
kfree(volume_info.UNC);
kfree(volume_info.password);
kfree(volume_info.prepath);
@@ -1781,13 +1848,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
/* this is needed for ASCII cp to Unicode converts */
- if(volume_info.iocharset == NULL) {
+ if (volume_info.iocharset == NULL) {
cifs_sb->local_nls = load_nls_default();
/* load_nls_default can not return null */
} else {
cifs_sb->local_nls = load_nls(volume_info.iocharset);
- if(cifs_sb->local_nls == NULL) {
- cERROR(1,("CIFS mount error: iocharset %s not found",volume_info.iocharset));
+ if (cifs_sb->local_nls == NULL) {
+ cERROR(1, ("CIFS mount error: iocharset %s not found",
+ volume_info.iocharset));
kfree(volume_info.UNC);
kfree(volume_info.password);
kfree(volume_info.prepath);
@@ -1796,12 +1864,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
}
- if(address_type == AF_INET)
+ if (address_type == AF_INET)
existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr,
NULL /* no ipv6 addr */,
volume_info.username, &srvTcp);
- else if(address_type == AF_INET6) {
- cFYI(1,("looking for ipv6 address"));
+ else if (address_type == AF_INET6) {
+ cFYI(1, ("looking for ipv6 address"));
existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
&sin_server6.sin6_addr,
volume_info.username, &srvTcp);
@@ -1813,26 +1881,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return -EINVAL;
}
-
if (srvTcp) {
- cFYI(1, ("Existing tcp session with server found"));
+ cFYI(1, ("Existing tcp session with server found"));
} else { /* create socket */
if (volume_info.port)
sin_server.sin_port = htons(volume_info.port);
else
sin_server.sin_port = 0;
if (address_type == AF_INET6) {
- cFYI(1,("attempting ipv6 connect"));
+ cFYI(1, ("attempting ipv6 connect"));
/* BB should we allow ipv6 on port 139? */
/* other OS never observed in Wild doing 139 with v6 */
- rc = ipv6_connect(&sin_server6,&csocket);
- } else
- rc = ipv4_connect(&sin_server,&csocket,
+ rc = ipv6_connect(&sin_server6, &csocket);
+ } else
+ rc = ipv4_connect(&sin_server, &csocket,
volume_info.source_rfc1001_name,
volume_info.target_rfc1001_name);
if (rc < 0) {
- cERROR(1,
- ("Error connecting to IPv4 socket. Aborting operation"));
+ cERROR(1, ("Error connecting to IPv4 socket. "
+ "Aborting operation"));
if (csocket != NULL)
sock_release(csocket);
kfree(volume_info.UNC);
@@ -1853,8 +1920,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
return rc;
} else {
memset(srvTcp, 0, sizeof (struct TCP_Server_Info));
- memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in));
- atomic_set(&srvTcp->inFlight,0);
+ memcpy(&srvTcp->addr.sockAddr, &sin_server,
+ sizeof (struct sockaddr_in));
+ atomic_set(&srvTcp->inFlight, 0);
/* BB Add code for ipv6 case too */
srvTcp->ssocket = csocket;
srvTcp->protocolType = IPV4;
@@ -1869,7 +1937,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
srvTcp->tsk = kthread_run((void *)(void *)cifs_demultiplex_thread, srvTcp, "cifsd");
if ( IS_ERR(srvTcp->tsk) ) {
rc = PTR_ERR(srvTcp->tsk);
- cERROR(1,("error %d create cifsd thread", rc));
+ cERROR(1, ("error %d create cifsd thread", rc));
srvTcp->tsk = NULL;
sock_release(csocket);
kfree(volume_info.UNC);
@@ -1880,8 +1948,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
}
wait_for_completion(&cifsd_complete);
rc = 0;
- memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
- memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16);
+ memcpy(srvTcp->workstation_RFC1001_name,
+ volume_info.source_rfc1001_name, 16);
+ memcpy(srvTcp->server_RFC1001_name,
+ volume_info.target_rfc1001_name, 16);
srvTcp->sequence_number = 0;
}
}
@@ -1902,16 +1972,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
NIPQUAD(sin_server.sin_addr.s_addr));
}
- if (!rc){
- /* volume_info.password freed at unmount */
+ if (!rc) {
+ /* volume_info.password freed at unmount */
if (volume_info.password)
pSesInfo->password = volume_info.password;
if (volume_info.username)
strncpy(pSesInfo->userName,
- volume_info.username,MAX_USERNAME_SIZE);
+ volume_info.username,
+ MAX_USERNAME_SIZE);
if (volume_info.domainname) {
int len = strlen(volume_info.domainname);
- pSesInfo->domainName =
+ pSesInfo->domainName =
kmalloc(len + 1, GFP_KERNEL);
if (pSesInfo->domainName)
strcpy(pSesInfo->domainName,
@@ -1921,46 +1992,48 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
pSesInfo->overrideSecFlg = volume_info.secFlg;
down(&pSesInfo->sesSem);
/* BB FIXME need to pass vol->secFlgs BB */
- rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
+ rc = cifs_setup_session(xid, pSesInfo,
+ cifs_sb->local_nls);
up(&pSesInfo->sesSem);
if (!rc)
atomic_inc(&srvTcp->socketUseCount);
} else
kfree(volume_info.password);
}
-
+
/* search for existing tcon to this server share */
if (!rc) {
if (volume_info.rsize > CIFSMaxBufSize) {
- cERROR(1,("rsize %d too large, using MaxBufSize",
+ cERROR(1, ("rsize %d too large, using MaxBufSize",
volume_info.rsize));
cifs_sb->rsize = CIFSMaxBufSize;
- } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize))
+ } else if ((volume_info.rsize) &&
+ (volume_info.rsize <= CIFSMaxBufSize))
cifs_sb->rsize = volume_info.rsize;
else /* default */
cifs_sb->rsize = CIFSMaxBufSize;
if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
- cERROR(1,("wsize %d too large using 4096 instead",
+ cERROR(1, ("wsize %d too large, using 4096 instead",
volume_info.wsize));
cifs_sb->wsize = 4096;
} else if (volume_info.wsize)
cifs_sb->wsize = volume_info.wsize;
else
- cifs_sb->wsize =
+ cifs_sb->wsize =
min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
127*1024);
/* old default of CIFSMaxBufSize was too small now
- that SMB Write2 can send multiple pages in kvec.
+ that SMB Write2 can send multiple pages in kvec.
RFC1001 does not describe what happens when frame
bigger than 128K is sent so use that as max in
conjunction with 52K kvec constraint on arch with 4K
page size */
if (cifs_sb->rsize < 2048) {
- cifs_sb->rsize = 2048;
+ cifs_sb->rsize = 2048;
/* Windows ME may prefer this */
- cFYI(1,("readsize set to minimum 2048"));
+ cFYI(1, ("readsize set to minimum: 2048"));
}
/* calculate prepath */
cifs_sb->prepath = volume_info.prepath;
@@ -1968,14 +2041,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cifs_sb->prepathlen = strlen(cifs_sb->prepath);
cifs_sb->prepath[0] = CIFS_DIR_SEP(cifs_sb);
volume_info.prepath = NULL;
- } else
+ } else
cifs_sb->prepathlen = 0;
cifs_sb->mnt_uid = volume_info.linux_uid;
cifs_sb->mnt_gid = volume_info.linux_gid;
cifs_sb->mnt_file_mode = volume_info.file_mode;
cifs_sb->mnt_dir_mode = volume_info.dir_mode;
- cFYI(1,("file mode: 0x%x dir mode: 0x%x",
- cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode));
+ cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
+ cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
if (volume_info.noperm)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
@@ -1998,7 +2071,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (volume_info.override_gid)
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
if (volume_info.direct_io) {
- cFYI(1,("mounting share using direct i/o"));
+ cFYI(1, ("mounting share using direct i/o"));
cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
}
@@ -2009,7 +2082,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
cFYI(1, ("Found match on UNC path"));
/* we can have only one retry value for a connection
to a share so for resources mounted more than once
- to the same server share the last value passed in
+ to the same server share the last value passed in
for the retry flag is used */
tcon->retry = volume_info.retry;
tcon->nocase = volume_info.nocase;
@@ -2018,17 +2091,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if (tcon == NULL)
rc = -ENOMEM;
else {
- /* check for null share name ie connecting to
+ /* check for null share name ie connecting to
* dfs root */
- /* BB check if this works for exactly length
+ /* BB check if this works for exactly length
* three strings */
if ((strchr(volume_info.UNC + 3, '\\') == NULL)
&& (strchr(volume_info.UNC + 3, '/') ==
NULL)) {
rc = connect_to_dfs_path(xid, pSesInfo,
"", cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(volume_info.UNC);
FreeXid(xid);
@@ -2037,7 +2110,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* BB Do we need to wrap sesSem around
* this TCon call and Unix SetFS as
* we do on SessSetup and reconnect? */
- rc = CIFSTCon(xid, pSesInfo,
+ rc = CIFSTCon(xid, pSesInfo,
volume_info.UNC,
tcon, cifs_sb->local_nls);
cFYI(1, ("CIFS Tcon rc = %d", rc));
@@ -2074,9 +2147,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
always wake up processes blocked in
tcp in recv_mesg then we could remove the
send_sig call */
- send_sig(SIGKILL,srvTcp->tsk,1);
+ force_sig(SIGKILL, srvTcp->tsk);
tsk = srvTcp->tsk;
- if(tsk)
+ if (tsk)
kthread_stop(tsk);
}
}
@@ -2085,15 +2158,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
tconInfoFree(tcon);
if (existingCifsSes == NULL) {
if (pSesInfo) {
- if ((pSesInfo->server) &&
+ if ((pSesInfo->server) &&
(pSesInfo->status == CifsGood)) {
int temp_rc;
temp_rc = CIFSSMBLogoff(xid, pSesInfo);
/* if the socketUseCount is now zero */
if ((temp_rc == -ESHUTDOWN) &&
- (pSesInfo->server) && (pSesInfo->server->tsk)) {
+ (pSesInfo->server) &&
+ (pSesInfo->server->tsk)) {
struct task_struct *tsk;
- send_sig(SIGKILL,pSesInfo->server->tsk,1);
+ force_sig(SIGKILL,
+ pSesInfo->server->tsk);
tsk = pSesInfo->server->tsk;
if (tsk)
kthread_stop(tsk);
@@ -2112,19 +2187,29 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* do not care if following two calls succeed - informational */
CIFSSMBQFSDeviceInfo(xid, tcon);
CIFSSMBQFSAttributeInfo(xid, tcon);
-
+
/* tell server which Unix caps we support */
if (tcon->ses->capabilities & CAP_UNIX)
+ /* reset of caps checks mount to see if unix extensions
+ disabled for just this mount */
reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
-
+ else
+ tcon->unix_ext = 0; /* server does not support them */
+
+ if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
+ cifs_sb->rsize = 1024 * 127;
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1, ("no very large read support, rsize now 127K"));
+#endif
+ }
if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
cifs_sb->wsize = min(cifs_sb->wsize,
(tcon->ses->server->maxBuf -
MAX_CIFS_HDR_SIZE));
if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
- cifs_sb->rsize = min(cifs_sb->rsize,
- (tcon->ses->server->maxBuf -
- MAX_CIFS_HDR_SIZE));
+ cifs_sb->rsize = min(cifs_sb->rsize,
+ (tcon->ses->server->maxBuf -
+ MAX_CIFS_HDR_SIZE));
}
/* volume_info.password is freed above when existing session found
@@ -2177,7 +2262,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ if (ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
@@ -2196,7 +2282,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
}
pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
- pSMB->req_no_secext.CaseInsensitivePasswordLength =
+ pSMB->req_no_secext.CaseInsensitivePasswordLength =
cpu_to_le16(CIFS_SESS_KEY_SIZE);
pSMB->req_no_secext.CaseSensitivePasswordLength =
@@ -2214,9 +2300,9 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
}
if (user == NULL)
bytes_returned = 0; /* skip null user */
- else
+ else
bytes_returned =
- cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
+ cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
nls_codepage);
/* convert number of 16 bit words to bytes */
bcc_ptr += 2 * bytes_returned;
@@ -2246,7 +2332,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2;
} else {
- if (user != NULL) {
+ if (user != NULL) {
strncpy(bcc_ptr, user, 200);
bcc_ptr += strnlen(user, 200);
}
@@ -2281,11 +2367,12 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 action = le16_to_cpu(pSMBr->resp.Action);
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN)
- cFYI(1, (" Guest login")); /* do we want to mark SesInfo struct ? */
- ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */
+ cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
+ ses->Suid = smb_buffer_response->Uid; /* UID left in wire format
+ (little endian) */
cFYI(1, ("UID = %d ", ses->Suid));
- /* response can have either 3 or 4 word count - Samba sends 3 */
- bcc_ptr = pByteArea(smb_buffer_response);
+ /* response can have either 3 or 4 word count - Samba sends 3 */
+ bcc_ptr = pByteArea(smb_buffer_response);
if ((pSMBr->resp.hdr.WordCount == 3)
|| ((pSMBr->resp.hdr.WordCount == 4)
&& (blob_len < pSMBr->resp.ByteCount))) {
@@ -2295,8 +2382,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
if ((long) (bcc_ptr) % 2) {
remaining_words =
- (BCC(smb_buffer_response) - 1) /2;
- bcc_ptr++; /* Unicode strings must be word aligned */
+ (BCC(smb_buffer_response) - 1) / 2;
+ /* Unicode strings must be word
+ aligned */
+ bcc_ptr++;
} else {
remaining_words =
BCC(smb_buffer_response) / 2;
@@ -2307,13 +2396,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
- if(ses->serverOS)
+ if (ses->serverOS)
kfree(ses->serverOS);
- ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
- if(ses->serverOS == NULL)
+ ses->serverOS = kzalloc(2 * (len + 1),
+ GFP_KERNEL);
+ if (ses->serverOS == NULL)
goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverOS,
- (__le16 *)bcc_ptr, len,nls_codepage);
+ (__le16 *)bcc_ptr,
+ len, nls_codepage);
bcc_ptr += 2 * (len + 1);
remaining_words -= len + 1;
ses->serverOS[2 * len] = 0;
@@ -2322,42 +2413,49 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = UniStrnlen((wchar_t *)bcc_ptr,
remaining_words-1);
kfree(ses->serverNOS);
- ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
- if(ses->serverNOS == NULL)
+ ses->serverNOS = kzalloc(2 * (len + 1),
+ GFP_KERNEL);
+ if (ses->serverNOS == NULL)
goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverNOS,
- (__le16 *)bcc_ptr,len,nls_codepage);
+ (__le16 *)bcc_ptr,
+ len, nls_codepage);
bcc_ptr += 2 * (len + 1);
ses->serverNOS[2 * len] = 0;
ses->serverNOS[1 + (2 * len)] = 0;
- if(strncmp(ses->serverNOS,
- "NT LAN Manager 4",16) == 0) {
- cFYI(1,("NT4 server"));
+ if (strncmp(ses->serverNOS,
+ "NT LAN Manager 4", 16) == 0) {
+ cFYI(1, ("NT4 server"));
ses->flags |= CIFS_SES_NT4;
}
remaining_words -= len + 1;
if (remaining_words > 0) {
len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
- /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
- if(ses->serverDomain)
+ /* last string is not always null terminated
+ (for e.g. for Windows XP & 2000) */
+ if (ses->serverDomain)
kfree(ses->serverDomain);
ses->serverDomain =
- kzalloc(2*(len+1),GFP_KERNEL);
- if(ses->serverDomain == NULL)
+ kzalloc(2*(len+1),
+ GFP_KERNEL);
+ if (ses->serverDomain == NULL)
goto sesssetup_nomem;
cifs_strfromUCS_le(ses->serverDomain,
- (__le16 *)bcc_ptr,len,nls_codepage);
+ (__le16 *)bcc_ptr,
+ len, nls_codepage);
bcc_ptr += 2 * (len + 1);
ses->serverDomain[2*len] = 0;
ses->serverDomain[1+(2*len)] = 0;
- } /* else no more room so create dummy domain string */
- else {
- if(ses->serverDomain)
+ } else { /* else no more room so create
+ dummy domain string */
+ if (ses->serverDomain)
kfree(ses->serverDomain);
- ses->serverDomain =
+ ses->serverDomain =
kzalloc(2, GFP_KERNEL);
}
- } else { /* no room so create dummy domain and NOS string */
+ } else { /* no room so create dummy domain
+ and NOS string */
+
/* if these kcallocs fail not much we
can do, but better to not fail the
sesssetup itself */
@@ -2374,19 +2472,22 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
kfree(ses->serverOS);
- ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
- if(ses->serverOS == NULL)
+ ses->serverOS = kzalloc(len + 1,
+ GFP_KERNEL);
+ if (ses->serverOS == NULL)
goto sesssetup_nomem;
- strncpy(ses->serverOS,bcc_ptr, len);
+ strncpy(ses->serverOS, bcc_ptr, len);
bcc_ptr += len;
- bcc_ptr[0] = 0; /* null terminate the string */
+ /* null terminate the string */
+ bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
kfree(ses->serverNOS);
- ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
- if(ses->serverNOS == NULL)
+ ses->serverNOS = kzalloc(len + 1,
+ GFP_KERNEL);
+ if (ses->serverNOS == NULL)
goto sesssetup_nomem;
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len;
@@ -2394,23 +2495,27 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- if(ses->serverDomain)
+ if (ses->serverDomain)
kfree(ses->serverDomain);
- ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
- if(ses->serverDomain == NULL)
+ ses->serverDomain = kzalloc(len + 1,
+ GFP_KERNEL);
+ if (ses->serverDomain == NULL)
goto sesssetup_nomem;
- strncpy(ses->serverDomain, bcc_ptr, len);
+ strncpy(ses->serverDomain, bcc_ptr,
+ len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
} else
cFYI(1,
- ("Variable field of length %d extends beyond end of smb ",
+ ("Variable field of length %d "
+ "extends beyond end of smb ",
len));
}
} else {
cERROR(1,
- (" Security Blob Length extends beyond end of SMB"));
+ (" Security Blob Length extends beyond "
+ "end of SMB"));
}
} else {
cERROR(1,
@@ -2429,7 +2534,7 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings,
static int
CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
- struct cifsSesInfo *ses, int * pNTLMv2_flag,
+ struct cifsSesInfo *ses, int *pNTLMv2_flag,
const struct nls_table *nls_codepage)
{
struct smb_hdr *smb_buffer;
@@ -2449,7 +2554,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
__u16 count;
cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
- if(ses == NULL)
+ if (ses == NULL)
return -EINVAL;
domain = ses->domainName;
*pNTLMv2_flag = FALSE;
@@ -2473,7 +2578,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
@@ -2501,9 +2606,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_56 |
/* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
- if(sign_CIFS_PDUs)
+ if (sign_CIFS_PDUs)
negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
-/* if(ntlmv2_support)
+/* if (ntlmv2_support)
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
/* setup pointers to domain name and workstation name */
bcc_ptr += SecurityBlobLength;
@@ -2573,11 +2678,11 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
__u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN)
- cFYI(1, (" Guest login"));
- /* Do we want to set anything in SesInfo struct when guest login? */
+ cFYI(1, (" Guest login"));
+ /* Do we want to set anything in SesInfo struct when guest login? */
- bcc_ptr = pByteArea(smb_buffer_response);
- /* response can have either 3 or 4 word count - Samba sends 3 */
+ bcc_ptr = pByteArea(smb_buffer_response);
+ /* response can have either 3 or 4 word count - Samba sends 3 */
SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr;
if (SecurityBlob2->MessageType != NtLmChallenge) {
@@ -2585,7 +2690,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
("Unexpected NTLMSSP message type received %d",
SecurityBlob2->MessageType));
} else if (ses) {
- ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
+ ses->Suid = smb_buffer_response->Uid; /* UID left in le format */
cFYI(1, ("UID = %d", ses->Suid));
if ((pSMBr->resp.hdr.WordCount == 3)
|| ((pSMBr->resp.hdr.WordCount == 4)
@@ -2603,18 +2708,18 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
memcpy(ses->server->cryptKey,
SecurityBlob2->Challenge,
CIFS_CRYPTO_KEY_SIZE);
- if(SecurityBlob2->NegotiateFlags &
+ if (SecurityBlob2->NegotiateFlags &
cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
*pNTLMv2_flag = TRUE;
- if((SecurityBlob2->NegotiateFlags &
- cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
+ if ((SecurityBlob2->NegotiateFlags &
+ cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN))
|| (sign_CIFS_PDUs > 1))
- ses->server->secMode |=
- SECMODE_SIGN_REQUIRED;
- if ((SecurityBlob2->NegotiateFlags &
+ ses->server->secMode |=
+ SECMODE_SIGN_REQUIRED;
+ if ((SecurityBlob2->NegotiateFlags &
cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs))
- ses->server->secMode |=
+ ses->server->secMode |=
SECMODE_SIGN_ENABLED;
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
@@ -2622,7 +2727,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
remaining_words =
(BCC(smb_buffer_response)
- 1) / 2;
- bcc_ptr++; /* Unicode strings must be word aligned */
+ /* Must word align unicode strings */
+ bcc_ptr++;
} else {
remaining_words =
BCC
@@ -2634,7 +2740,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
- if(ses->serverOS)
+ if (ses->serverOS)
kfree(ses->serverOS);
ses->serverOS =
kzalloc(2 * (len + 1), GFP_KERNEL);
@@ -2667,8 +2773,9 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
(2 * len)] = 0;
remaining_words -= len + 1;
if (remaining_words > 0) {
- len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
- /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ /* last string not always null terminated
+ (for e.g. for Windows XP & 2000) */
kfree(ses->serverDomain);
ses->serverDomain =
kzalloc(2 *
@@ -2706,7 +2813,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
if (((long) bcc_ptr + len) - (long)
pByteArea(smb_buffer_response)
<= BCC(smb_buffer_response)) {
- if(ses->serverOS)
+ if (ses->serverOS)
kfree(ses->serverOS);
ses->serverOS =
kzalloc(len + 1,
@@ -2733,18 +2840,20 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
ses->serverDomain =
kzalloc(len + 1,
GFP_KERNEL);
- strncpy(ses->serverDomain, bcc_ptr, len);
+ strncpy(ses->serverDomain,
+ bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
} else
cFYI(1,
- ("Variable field of length %d extends beyond end of smb",
+ ("field of length %d "
+ "extends beyond end of smb",
len));
}
} else {
- cERROR(1,
- (" Security Blob Length extends beyond end of SMB"));
+ cERROR(1, ("Security Blob Length extends beyond"
+ " end of SMB"));
}
} else {
cERROR(1, ("No session structure passed in."));
@@ -2783,7 +2892,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 count;
cFYI(1, ("In NTLMSSPSessSetup (Authenticate)"));
- if(ses == NULL)
+ if (ses == NULL)
return -EINVAL;
user = ses->userName;
domain = ses->domainName;
@@ -2808,7 +2917,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
pSMB->req.hdr.Uid = ses->Suid;
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
@@ -2832,13 +2941,13 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8);
SecurityBlob->MessageType = NtLmAuthenticate;
bcc_ptr += SecurityBlobLength;
- negotiate_flags =
+ negotiate_flags =
NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO |
0x80000000 | NTLMSSP_NEGOTIATE_128;
- if(sign_CIFS_PDUs)
+ if (sign_CIFS_PDUs)
negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN;
- if(ntlmv2_flag)
+ if (ntlmv2_flag)
negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
/* setup pointers to domain name and workstation name */
@@ -2902,13 +3011,17 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
cpu_to_le16(len);
}
- /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
+ /* SecurityBlob->WorkstationName.Length =
+ cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage);
SecurityBlob->WorkstationName.Length *= 2;
- SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length);
- SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength);
+ SecurityBlob->WorkstationName.MaximumLength =
+ cpu_to_le16(SecurityBlob->WorkstationName.Length);
+ SecurityBlob->WorkstationName.Buffer =
+ cpu_to_le32(SecurityBlobLength);
bcc_ptr += SecurityBlob->WorkstationName.Length;
SecurityBlobLength += SecurityBlob->WorkstationName.Length;
- SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */
+ SecurityBlob->WorkstationName.Length =
+ cpu_to_le16(SecurityBlob->WorkstationName.Length); */
if ((long) bcc_ptr % 2) {
*bcc_ptr = 0;
@@ -2994,17 +3107,20 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
__u16 blob_len =
le16_to_cpu(pSMBr->resp.SecurityBlobLength);
if (action & GUEST_LOGIN)
- cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */
-/* if(SecurityBlob2->MessageType != NtLm??){
- cFYI("Unexpected message type on auth response is %d "));
- } */
+ cFYI(1, (" Guest login")); /* BB Should we set anything
+ in SesInfo struct ? */
+/* if (SecurityBlob2->MessageType != NtLm??) {
+ cFYI("Unexpected message type on auth response is %d"));
+ } */
+
if (ses) {
cFYI(1,
- ("Does UID on challenge %d match auth response UID %d ",
+ ("Check challenge UID %d vs auth response UID %d",
ses->Suid, smb_buffer_response->Uid));
- ses->Suid = smb_buffer_response->Uid; /* UID left in wire format */
- bcc_ptr = pByteArea(smb_buffer_response);
- /* response can have either 3 or 4 word count - Samba sends 3 */
+ /* UID left in wire format */
+ ses->Suid = smb_buffer_response->Uid;
+ bcc_ptr = pByteArea(smb_buffer_response);
+ /* response can have either 3 or 4 word count - Samba sends 3 */
if ((pSMBr->resp.hdr.WordCount == 3)
|| ((pSMBr->resp.hdr.WordCount == 4)
&& (blob_len <
@@ -3034,7 +3150,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
- if(ses->serverOS)
+ if (ses->serverOS)
kfree(ses->serverOS);
ses->serverOS =
kzalloc(2 * (len + 1), GFP_KERNEL);
@@ -3066,9 +3182,9 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
ses->serverNOS[1+(2*len)] = 0;
remaining_words -= len + 1;
if (remaining_words > 0) {
- len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
+ len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
/* last string not always null terminated (e.g. for Windows XP & 2000) */
- if(ses->serverDomain)
+ if (ses->serverDomain)
kfree(ses->serverDomain);
ses->serverDomain =
kzalloc(2 *
@@ -3096,12 +3212,12 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
= 0;
} /* else no more room so create dummy domain string */
else {
- if(ses->serverDomain)
+ if (ses->serverDomain)
kfree(ses->serverDomain);
ses->serverDomain = kzalloc(2,GFP_KERNEL);
}
} else { /* no room so create dummy domain and NOS string */
- if(ses->serverDomain)
+ if (ses->serverDomain)
kfree(ses->serverDomain);
ses->serverDomain = kzalloc(2, GFP_KERNEL);
kfree(ses->serverNOS);
@@ -3109,10 +3225,10 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
}
} else { /* ASCII */
len = strnlen(bcc_ptr, 1024);
- if (((long) bcc_ptr + len) -
- (long) pByteArea(smb_buffer_response)
- <= BCC(smb_buffer_response)) {
- if(ses->serverOS)
+ if (((long) bcc_ptr + len) -
+ (long) pByteArea(smb_buffer_response)
+ <= BCC(smb_buffer_response)) {
+ if (ses->serverOS)
kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
strncpy(ses->serverOS,bcc_ptr, len);
@@ -3123,28 +3239,35 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
len = strnlen(bcc_ptr, 1024);
kfree(ses->serverNOS);
- ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
- strncpy(ses->serverNOS, bcc_ptr, len);
+ ses->serverNOS = kzalloc(len+1,
+ GFP_KERNEL);
+ strncpy(ses->serverNOS,
+ bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
len = strnlen(bcc_ptr, 1024);
- if(ses->serverDomain)
+ if (ses->serverDomain)
kfree(ses->serverDomain);
- ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
- strncpy(ses->serverDomain, bcc_ptr, len);
+ ses->serverDomain =
+ kzalloc(len+1,
+ GFP_KERNEL);
+ strncpy(ses->serverDomain,
+ bcc_ptr, len);
bcc_ptr += len;
bcc_ptr[0] = 0;
bcc_ptr++;
} else
cFYI(1,
- ("Variable field of length %d extends beyond end of smb ",
+ ("field of length %d "
+ "extends beyond end of smb ",
len));
}
} else {
cERROR(1,
- (" Security Blob Length extends beyond end of SMB"));
+ (" Security Blob extends beyond end "
+ "of SMB"));
}
} else {
cERROR(1, ("No session structure passed in."));
@@ -3196,7 +3319,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
pSMB->AndXCommand = 0xFF;
pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
bcc_ptr = &pSMB->Password[0];
- if((ses->server->secMode) & SECMODE_USER) {
+ if ((ses->server->secMode) & SECMODE_USER) {
pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
*bcc_ptr = 0; /* password is null byte */
bcc_ptr++; /* skip password */
@@ -3210,7 +3333,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
by Samba (not sure whether other servers allow
NTLMv2 password here) */
#ifdef CONFIG_CIFS_WEAK_PW_HASH
- if((extended_security & CIFSSEC_MAY_LANMAN) &&
+ if ((extended_security & CIFSSEC_MAY_LANMAN) &&
(ses->server->secType == LANMAN))
calc_lanman_hash(ses, bcc_ptr);
else
@@ -3220,14 +3343,14 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr);
bcc_ptr += CIFS_SESS_KEY_SIZE;
- if(ses->capabilities & CAP_UNICODE) {
+ if (ses->capabilities & CAP_UNICODE) {
/* must align unicode strings */
*bcc_ptr = 0; /* null byte password */
bcc_ptr++;
}
}
- if(ses->server->secMode &
+ if (ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
@@ -3240,8 +3363,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
if (ses->capabilities & CAP_UNICODE) {
smb_buffer->Flags2 |= SMBFLG2_UNICODE;
length =
- cifs_strtoUCS((__le16 *) bcc_ptr, tree,
- 6 /* max utf8 char length in bytes */ *
+ cifs_strtoUCS((__le16 *) bcc_ptr, tree,
+ 6 /* max utf8 char length in bytes */ *
(/* server len*/ + 256 /* share len */), nls_codepage);
bcc_ptr += 2 * length; /* convert num 16 bit words to bytes */
bcc_ptr += 2; /* skip trailing null */
@@ -3265,8 +3388,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
tcon->tid = smb_buffer_response->Tid;
bcc_ptr = pByteArea(smb_buffer_response);
length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
- /* skip service field (NB: this field is always ASCII) */
- bcc_ptr += length + 1;
+ /* skip service field (NB: this field is always ASCII) */
+ bcc_ptr += length + 1;
strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
length = UniStrnlen((wchar_t *) bcc_ptr, 512);
@@ -3284,7 +3407,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
bcc_ptr[1] = 0;
bcc_ptr += 2;
}
- /* else do not bother copying these informational fields */
+ /* else do not bother copying these information fields*/
} else {
length = strnlen(bcc_ptr, 1024);
if ((bcc_ptr + length) -
@@ -3296,9 +3419,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
strncpy(tcon->nativeFileSystem, bcc_ptr,
length);
}
- /* else do not bother copying these informational fields */
+ /* else do not bother copying these information fields*/
}
- if((smb_buffer_response->WordCount == 3) ||
+ if ((smb_buffer_response->WordCount == 3) ||
(smb_buffer_response->WordCount == 7))
/* field is in same location */
tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
@@ -3306,7 +3429,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
tcon->Flags = 0;
cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
} else if ((rc == 0) && tcon == NULL) {
- /* all we need to save for IPC$ connection */
+ /* all we need to save for IPC$ connection */
ses->ipc_tid = smb_buffer_response->Tid;
}
@@ -3322,7 +3445,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
int xid;
struct cifsSesInfo *ses = NULL;
struct task_struct *cifsd_task;
- char * tmp;
+ char *tmp;
xid = GetXid();
@@ -3343,9 +3466,9 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
FreeXid(xid);
return 0;
} else if (rc == -ESHUTDOWN) {
- cFYI(1,("Waking up socket by sending it signal"));
+ cFYI(1, ("Waking up socket by sending signal"));
if (cifsd_task) {
- send_sig(SIGKILL,cifsd_task,1);
+ force_sig(SIGKILL, cifsd_task);
kthread_stop(cifsd_task);
}
rc = 0;
@@ -3354,7 +3477,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
} else
cFYI(1, ("No session or bad tcon"));
}
-
+
cifs_sb->tcon = NULL;
tmp = cifs_sb->prepath;
cifs_sb->prepathlen = 0;
@@ -3366,11 +3489,11 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
sesInfoFree(ses);
FreeXid(xid);
- return rc; /* BB check if we should always return zero here */
-}
+ return rc; /* BB check if we should always return zero here */
+}
int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
- struct nls_table * nls_info)
+ struct nls_table *nls_info)
{
int rc = 0;
char ntlm_session_key[CIFS_SESS_KEY_SIZE];
@@ -3378,16 +3501,16 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
int first_time = 0;
/* what if server changes its buffer size after dropping the session? */
- if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
+ if (pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
rc = CIFSSMBNegotiate(xid, pSesInfo);
- if(rc == -EAGAIN) /* retry only once on 1st time connection */ {
+ if (rc == -EAGAIN) /* retry only once on 1st time connection */ {
rc = CIFSSMBNegotiate(xid, pSesInfo);
- if(rc == -EAGAIN)
+ if (rc == -EAGAIN)
rc = -EHOSTDOWN;
}
- if(rc == 0) {
+ if (rc == 0) {
spin_lock(&GlobalMid_Lock);
- if(pSesInfo->server->tcpStatus != CifsExiting)
+ if (pSesInfo->server->tcpStatus != CifsExiting)
pSesInfo->server->tcpStatus = CifsGood;
else
rc = -EHOSTDOWN;
@@ -3399,18 +3522,19 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if (!rc) {
pSesInfo->flags = 0;
pSesInfo->capabilities = pSesInfo->server->capabilities;
- if(linuxExtEnabled == 0)
+ if (linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX);
/* pSesInfo->sequence_number = 0;*/
- cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
+ cFYI(1,
+ ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
pSesInfo->server->secMode,
pSesInfo->server->capabilities,
pSesInfo->server->timeAdj));
- if(experimEnabled < 2)
+ if (experimEnabled < 2)
rc = CIFS_SessSetup(xid, pSesInfo,
first_time, nls_info);
else if (extended_security
- && (pSesInfo->capabilities
+ && (pSesInfo->capabilities
& CAP_EXTENDED_SECURITY)
&& (pSesInfo->server->secType == NTLMSSP)) {
rc = -EOPNOTSUPP;
@@ -3423,21 +3547,22 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
&ntlmv2_flag,
nls_info);
if (!rc) {
- if(ntlmv2_flag) {
- char * v2_response;
- cFYI(1,("more secure NTLM ver2 hash"));
- if(CalcNTLMv2_partial_mac_key(pSesInfo,
+ if (ntlmv2_flag) {
+ char *v2_response;
+ cFYI(1, ("more secure NTLM ver2 hash"));
+ if (CalcNTLMv2_partial_mac_key(pSesInfo,
nls_info)) {
rc = -ENOMEM;
goto ss_err_exit;
} else
v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
- if(v2_response) {
- CalcNTLMv2_response(pSesInfo,v2_response);
- /* if(first_time)
- cifs_calculate_ntlmv2_mac_key(
- pSesInfo->server->mac_signing_key,
- response, ntlm_session_key, */
+ if (v2_response) {
+ CalcNTLMv2_response(pSesInfo,
+ v2_response);
+ /* if (first_time)
+ cifs_calculate_ntlmv2_mac_key(
+ pSesInfo->server->mac_signing_key,
+ response, ntlm_session_key,*/
kfree(v2_response);
/* BB Put dummy sig in SessSetup PDU? */
} else {
@@ -3450,9 +3575,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey,
ntlm_session_key);
- if(first_time)
+ if (first_time)
cifs_calculate_mac_key(
- pSesInfo->server->mac_signing_key,
+ &pSesInfo->server->mac_signing_key,
ntlm_session_key,
pSesInfo->password);
}
@@ -3470,18 +3595,18 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
pSesInfo->server->cryptKey,
ntlm_session_key);
- if(first_time)
+ if (first_time)
cifs_calculate_mac_key(
- pSesInfo->server->mac_signing_key,
+ &pSesInfo->server->mac_signing_key,
ntlm_session_key, pSesInfo->password);
rc = CIFSSessSetup(xid, pSesInfo,
ntlm_session_key, nls_info);
}
if (rc) {
- cERROR(1,("Send error in SessSetup = %d",rc));
+ cERROR(1, ("Send error in SessSetup = %d", rc));
} else {
- cFYI(1,("CIFS Session Established successfully"));
+ cFYI(1, ("CIFS Session Established successfully"));
pSesInfo->status = CifsGood;
}
}
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 8e86aaceb68a..4830acc86d74 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -135,10 +135,10 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
- FILE_ALL_INFO * buf = NULL;
+ FILE_ALL_INFO *buf = NULL;
struct inode *newinode = NULL;
- struct cifsFileInfo * pCifsFile = NULL;
- struct cifsInodeInfo * pCifsInode;
+ struct cifsFileInfo *pCifsFile = NULL;
+ struct cifsInodeInfo *pCifsInode;
int disposition = FILE_OVERWRITE_IF;
int write_only = FALSE;
@@ -207,8 +207,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
} else {
/* If Open reported that we actually created a file
then we now have to set the mode if possible */
- if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&
- (oplock & CIFS_CREATE_ACTION)) {
+ if ((pTcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode,
@@ -235,8 +234,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
/* Could set r/o dos attribute if mode & 0222 == 0 */
}
- /* BB server might mask mode so we have to query for Unix case*/
- if (pTcon->ses->capabilities & CAP_UNIX)
+ /* server might mask mode so we have to query for it */
+ if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb, xid);
else {
@@ -264,7 +263,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode);
}
- if ((nd->flags & LOOKUP_OPEN) == FALSE) {
+ if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
+ ((nd->flags & LOOKUP_OPEN) == FALSE)) {
/* mknod case - do not leave file open */
CIFSSMBClose(xid, pTcon, fileHandle);
} else if (newinode) {
@@ -323,7 +323,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
- struct inode * newinode = NULL;
+ struct inode *newinode = NULL;
if (!old_valid_dev(device_number))
return -EINVAL;
@@ -336,7 +336,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode,
full_path = build_path_from_dentry(direntry);
if (full_path == NULL)
rc = -ENOMEM;
- else if (pTcon->ses->capabilities & CAP_UNIX) {
+ else if (pTcon->unix_ext) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@@ -490,7 +490,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
cFYI(1,
(" Full path: %s inode = 0x%p", full_path, direntry->d_inode));
- if (pTcon->ses->capabilities & CAP_UNIX)
+ if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newInode, full_path,
parent_dir_inode->i_sb, xid);
else
diff --git a/fs/cifs/export.c b/fs/cifs/export.c
index 1d716392c3aa..893fd0aebff8 100644
--- a/fs/cifs/export.c
+++ b/fs/cifs/export.c
@@ -5,7 +5,7 @@
* Author(s): Steve French (sfrench@us.ibm.com)
*
* Common Internet FileSystem (CIFS) client
- *
+ *
* Operations related to support for exporting files via NFSD
*
* This library is free software; you can redistribute it and/or modify
@@ -22,31 +22,45 @@
* along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
- /*
+
+ /*
* See Documentation/filesystems/Exporting
* and examples in fs/exportfs
+ *
+ * Since cifs is a network file system, an "fsid" must be included for
+ * any nfs exports file entries which refer to cifs paths. In addition
+ * the cifs mount must be mounted with the "serverino" option (ie use stable
+ * server inode numbers instead of locally generated temporary ones).
+ * Although cifs inodes do not use generation numbers (have generation number
+ * of zero) - the inode number alone should be good enough for simple cases
+ * in which users want to export cifs shares with NFS. The decode and encode
+ * could be improved by using a new routine which expects 64 bit inode numbers
+ * instead of the default 32 bit routines in fs/exportfs
+ *
*/
#include <linux/fs.h>
-
+#include <linux/exportfs.h>
+#include "cifsglob.h"
+#include "cifs_debug.h"
+
#ifdef CONFIG_CIFS_EXPERIMENTAL
-
static struct dentry *cifs_get_parent(struct dentry *dentry)
{
- /* BB need to add code here eventually to enable export via NFSD */
- return ERR_PTR(-EACCES);
+ /* BB need to add code here eventually to enable export via NFSD */
+ cFYI(1, ("get parent for %p", dentry));
+ return ERR_PTR(-EACCES);
}
-
+
struct export_operations cifs_export_ops = {
- .get_parent = cifs_get_parent,
-/* Following five export operations are unneeded so far and can default */
-/* .get_dentry =
- .get_name =
- .find_exported_dentry =
- .decode_fh =
- .encode_fs = */
- };
-
+ .get_parent = cifs_get_parent,
+/* Following five export operations are unneeded so far and can default:
+ .get_dentry =
+ .get_name =
+ .find_exported_dentry =
+ .decode_fh =
+ .encode_fs = */
+};
+
#endif /* EXPERIMENTAL */
-
+
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c
index 8e375bb4b379..995474c90885 100644
--- a/fs/cifs/fcntl.c
+++ b/fs/cifs/fcntl.c
@@ -66,7 +66,7 @@ static __u32 convert_to_cifs_notify_flags(unsigned long fcntl_notify_flags)
return cifs_ntfy_flags;
}
-int cifs_dir_notify(struct file * file, unsigned long arg)
+int cifs_dir_notify(struct file *file, unsigned long arg)
{
int xid;
int rc = -EINVAL;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 94d5b49049df..e13592afca9c 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -2,8 +2,8 @@
* fs/cifs/file.c
*
* vfs operations that deal with files
- *
- * Copyright (C) International Business Machines Corp., 2002,2003
+ *
+ * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org)
*
@@ -45,7 +45,7 @@ static inline struct cifsFileInfo *cifs_init_private(
{
memset(private_data, 0, sizeof(struct cifsFileInfo));
private_data->netfid = netfid;
- private_data->pid = current->tgid;
+ private_data->pid = current->tgid;
init_MUTEX(&private_data->fh_sem);
mutex_init(&private_data->lock_mutex);
INIT_LIST_HEAD(&private_data->llist);
@@ -57,7 +57,7 @@ static inline struct cifsFileInfo *cifs_init_private(
does not tell us which handle the write is for so there can
be a close (overlapping with write) of the filehandle that
cifs_writepages chose to use */
- atomic_set(&private_data->wrtPending,0);
+ atomic_set(&private_data->wrtPending, 0);
return private_data;
}
@@ -105,7 +105,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
in the list so we do not have to walk the
list to search for one in prepare_write */
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
- list_add_tail(&pCifsFile->flist,
+ list_add_tail(&pCifsFile->flist,
&pCifsInode->openFileList);
} else {
list_add(&pCifsFile->flist,
@@ -138,7 +138,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file,
}
client_can_cache:
- if (pTcon->ses->capabilities & CAP_UNIX)
+ if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&file->f_path.dentry->d_inode,
full_path, inode->i_sb, xid);
else
@@ -189,7 +189,7 @@ int cifs_open(struct inode *inode, struct file *file)
/* needed for writepage */
pCifsFile->pfile = file;
-
+
file->private_data = pCifsFile;
break;
}
@@ -212,15 +212,15 @@ int cifs_open(struct inode *inode, struct file *file)
return -ENOMEM;
}
- cFYI(1, (" inode = 0x%p file flags are 0x%x for %s",
+ cFYI(1, ("inode = 0x%p file flags are 0x%x for %s",
inode, file->f_flags, full_path));
desiredAccess = cifs_convert_flags(file->f_flags);
/*********************************************************************
* open flag mapping table:
- *
+ *
* POSIX Flag CIFS Disposition
- * ---------- ----------------
+ * ---------- ----------------
* O_CREAT FILE_OPEN_IF
* O_CREAT | O_EXCL FILE_CREATE
* O_CREAT | O_TRUNC FILE_OVERWRITE_IF
@@ -228,12 +228,12 @@ int cifs_open(struct inode *inode, struct file *file)
* none of the above FILE_OPEN
*
* Note that there is not a direct match between disposition
- * FILE_SUPERSEDE (ie create whether or not file exists although
+ * FILE_SUPERSEDE (ie create whether or not file exists although
* O_CREAT | O_TRUNC is similar but truncates the existing
* file rather than creating a new file as FILE_SUPERSEDE does
* (which uses the attributes / metadata passed in on open call)
*?
- *? O_SYNC is a reasonable match to CIFS writethrough flag
+ *? O_SYNC is a reasonable match to CIFS writethrough flag
*? and the read write flags match reasonably. O_LARGEFILE
*? is irrelevant because largefile support is always used
*? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY,
@@ -253,8 +253,8 @@ int cifs_open(struct inode *inode, struct file *file)
and calling get_inode_info with returned buf (at least helps
non-Unix server case) */
- /* BB we can not do this if this is the second open of a file
- and the first handle has writebehind data, we might be
+ /* BB we can not do this if this is the second open of a file
+ and the first handle has writebehind data, we might be
able to simply do a filemap_fdatawrite/filemap_fdatawait first */
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
if (!buf) {
@@ -263,7 +263,7 @@ int cifs_open(struct inode *inode, struct file *file)
}
if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS)
- rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
+ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
& CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -300,15 +300,15 @@ int cifs_open(struct inode *inode, struct file *file)
write_unlock(&GlobalSMBSeslock);
}
- if (oplock & CIFS_CREATE_ACTION) {
+ if (oplock & CIFS_CREATE_ACTION) {
/* time to set mode which we can not set earlier due to
problems creating new read-only files */
- if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+ if (pTcon->unix_ext) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
inode->i_mode,
(__u64)-1, (__u64)-1, 0 /* dev */,
cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
/* BB implement via Windows security descriptors eg
@@ -345,7 +345,7 @@ static int cifs_reopen_file(struct file *file, int can_flush)
struct cifsTconInfo *pTcon;
struct cifsFileInfo *pCifsFile;
struct cifsInodeInfo *pCifsInode;
- struct inode * inode;
+ struct inode *inode;
char *full_path = NULL;
int desiredAccess;
int disposition = FILE_OPEN;
@@ -372,13 +372,13 @@ static int cifs_reopen_file(struct file *file, int can_flush)
}
inode = file->f_path.dentry->d_inode;
- if(inode == NULL) {
+ if (inode == NULL) {
cERROR(1, ("inode not valid"));
dump_stack();
rc = -EBADF;
goto reopen_error_exit;
}
-
+
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
@@ -396,7 +396,7 @@ reopen_error_exit:
}
cFYI(1, ("inode = 0x%p file flags 0x%x for %s",
- inode, file->f_flags,full_path));
+ inode, file->f_flags, full_path));
desiredAccess = cifs_convert_flags(file->f_flags);
if (oplockEnabled)
@@ -405,14 +405,14 @@ reopen_error_exit:
oplock = FALSE;
/* Can not refresh inode by passing in file_info buf to be returned
- by SMBOpen and then calling get_inode_info with returned buf
- since file might have write behind data that needs to be flushed
+ by SMBOpen and then calling get_inode_info with returned buf
+ since file might have write behind data that needs to be flushed
and server version of file size can be stale. If we knew for sure
that inode was not dirty locally we could do this */
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
- cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+ cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
up(&pCifsFile->fh_sem);
@@ -430,7 +430,7 @@ reopen_error_exit:
go to server to get inode info */
pCifsInode->clientCanCacheAll = FALSE;
pCifsInode->clientCanCacheRead = FALSE;
- if (pTcon->ses->capabilities & CAP_UNIX)
+ if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&inode,
full_path, inode->i_sb, xid);
else
@@ -486,23 +486,24 @@ int cifs_close(struct inode *inode, struct file *file)
already closed */
if (pTcon->tidStatus != CifsNeedReconnect) {
int timeout = 2;
- while((atomic_read(&pSMBFile->wrtPending) != 0)
+ while ((atomic_read(&pSMBFile->wrtPending) != 0)
&& (timeout < 1000) ) {
/* Give write a better chance to get to
server ahead of the close. We do not
want to add a wait_q here as it would
increase the memory utilization as
the struct would be in each open file,
- but this should give enough time to
+ but this should give enough time to
clear the socket */
#ifdef CONFIG_CIFS_DEBUG2
- cFYI(1,("close delay, write pending"));
+ cFYI(1, ("close delay, write pending"));
#endif /* DEBUG2 */
msleep(timeout);
timeout *= 4;
}
- if(atomic_read(&pSMBFile->wrtPending))
- cERROR(1,("close with pending writes"));
+ if (atomic_read(&pSMBFile->wrtPending))
+ cERROR(1,
+ ("close with pending writes"));
rc = CIFSSMBClose(xid, pTcon,
pSMBFile->netfid);
}
@@ -534,7 +535,7 @@ int cifs_close(struct inode *inode, struct file *file)
CIFS_I(inode)->clientCanCacheRead = FALSE;
CIFS_I(inode)->clientCanCacheAll = FALSE;
}
- if ((rc ==0) && CIFS_I(inode)->write_behind_rc)
+ if ((rc == 0) && CIFS_I(inode)->write_behind_rc)
rc = CIFS_I(inode)->write_behind_rc;
FreeXid(xid);
return rc;
@@ -554,7 +555,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
if (pCFileStruct) {
struct cifsTconInfo *pTcon;
- struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ struct cifs_sb_info *cifs_sb =
+ CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
@@ -572,7 +574,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
if (ptmp) {
cFYI(1, ("closedir free smb buf in srch struct"));
pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
- if(pCFileStruct->srch_inf.smallBuf)
+ if (pCFileStruct->srch_inf.smallBuf)
cifs_small_buf_release(ptmp);
else
cifs_buf_release(ptmp);
@@ -594,7 +596,8 @@ int cifs_closedir(struct inode *inode, struct file *file)
static int store_file_lock(struct cifsFileInfo *fid, __u64 len,
__u64 offset, __u8 lockType)
{
- struct cifsLockInfo *li = kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
+ struct cifsLockInfo *li =
+ kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);
if (li == NULL)
return -ENOMEM;
li->offset = offset;
@@ -625,8 +628,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
cFYI(1, ("Lock parm: 0x%x flockflags: "
"0x%x flocktype: 0x%x start: %lld end: %lld",
- cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
- pfLock->fl_end));
+ cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,
+ pfLock->fl_end));
if (pfLock->fl_flags & FL_POSIX)
cFYI(1, ("Posix"));
@@ -641,7 +644,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
"not implemented yet"));
if (pfLock->fl_flags & FL_LEASE)
cFYI(1, ("Lease on file - not implemented yet"));
- if (pfLock->fl_flags &
+ if (pfLock->fl_flags &
(~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))
cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));
@@ -683,9 +686,9 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
account for negative length which we can not accept over the
wire */
if (IS_GETLK(cmd)) {
- if(posix_locking) {
+ if (posix_locking) {
int posix_lock_type;
- if(lockType & LOCKING_ANDX_SHARED_LOCK)
+ if (lockType & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK;
else
posix_lock_type = CIFS_WRLCK;
@@ -700,7 +703,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
0, 1, lockType, 0 /* wait flag */ );
if (rc == 0) {
- rc = CIFSSMBLock(xid, pTcon, netfid, length,
+ rc = CIFSSMBLock(xid, pTcon, netfid, length,
pfLock->fl_start, 1 /* numUnlock */ ,
0 /* numLock */ , lockType,
0 /* wait flag */ );
@@ -729,22 +732,24 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
if (posix_locking) {
int posix_lock_type;
- if(lockType & LOCKING_ANDX_SHARED_LOCK)
+ if (lockType & LOCKING_ANDX_SHARED_LOCK)
posix_lock_type = CIFS_RDLCK;
else
posix_lock_type = CIFS_WRLCK;
-
- if(numUnlock == 1)
+
+ if (numUnlock == 1)
posix_lock_type = CIFS_UNLCK;
rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,
length, pfLock,
posix_lock_type, wait_flag);
} else {
- struct cifsFileInfo *fid = (struct cifsFileInfo *)file->private_data;
+ struct cifsFileInfo *fid =
+ (struct cifsFileInfo *)file->private_data;
if (numLock) {
- rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,
+ rc = CIFSSMBLock(xid, pTcon, netfid, length,
+ pfLock->fl_start,
0, numLock, lockType, wait_flag);
if (rc == 0) {
@@ -763,7 +768,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
list_for_each_entry_safe(li, tmp, &fid->llist, llist) {
if (pfLock->fl_start <= li->offset &&
length >= li->length) {
- stored_rc = CIFSSMBLock(xid, pTcon, netfid,
+ stored_rc = CIFSSMBLock(xid, pTcon,
+ netfid,
li->length, li->offset,
1, 0, li->type, FALSE);
if (stored_rc)
@@ -805,7 +811,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
if (file->private_data == NULL)
return -EBADF;
open_file = (struct cifsFileInfo *) file->private_data;
-
+
xid = GetXid();
if (*poffset > file->f_path.dentry->d_inode->i_size)
@@ -824,7 +830,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
and blocked, and the file has been freed on us while
we blocked so return what we managed to write */
return total_written;
- }
+ }
if (open_file->closePend) {
FreeXid(xid);
if (total_written)
@@ -867,8 +873,8 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
/* since the write may have blocked check these pointers again */
if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {
struct inode *inode = file->f_path.dentry->d_inode;
-/* Do not update local mtime - server will set its actual value on write
- * inode->i_ctime = inode->i_mtime =
+/* Do not update local mtime - server will set its actual value on write
+ * inode->i_ctime = inode->i_mtime =
* current_fs_time(inode->i_sb);*/
if (total_written > 0) {
spin_lock(&inode->i_lock);
@@ -877,7 +883,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data,
*poffset);
spin_unlock(&inode->i_lock);
}
- mark_inode_dirty_sync(file->f_path.dentry->d_inode);
+ mark_inode_dirty_sync(file->f_path.dentry->d_inode);
}
FreeXid(xid);
return total_written;
@@ -898,13 +904,13 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
pTcon = cifs_sb->tcon;
- cFYI(1,("write %zd bytes to offset %lld of %s", write_size,
+ cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,
*poffset, file->f_path.dentry->d_name.name));
if (file->private_data == NULL)
return -EBADF;
open_file = (struct cifsFileInfo *)file->private_data;
-
+
xid = GetXid();
if (*poffset > file->f_path.dentry->d_inode->i_size)
@@ -921,10 +927,10 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
FreeXid(xid);
/* if we have gotten here we have written some data
and blocked, and the file has been freed on us
- while we blocked so return what we managed to
+ while we blocked so return what we managed to
write */
return total_written;
- }
+ }
if (open_file->closePend) {
FreeXid(xid);
if (total_written)
@@ -935,14 +941,14 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
if (open_file->invalidHandle) {
/* we could deadlock if we called
filemap_fdatawait from here so tell
- reopen_file not to flush data to
+ reopen_file not to flush data to
server now */
rc = cifs_reopen_file(file, FALSE);
if (rc != 0)
break;
}
- if(experimEnabled || (pTcon->ses->server &&
- ((pTcon->ses->server->secMode &
+ if (experimEnabled || (pTcon->ses->server &&
+ ((pTcon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
== 0))) {
struct kvec iov[2];
@@ -976,7 +982,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
}
} else
*poffset += bytes_written;
- long_op = FALSE; /* subsequent writes fast -
+ long_op = FALSE; /* subsequent writes fast -
15 seconds is plenty */
}
@@ -1009,8 +1015,8 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
the VFS or MM) should not happen but we had reports of on oops (due to
it being zero) during stress testcases so we need to check for it */
- if(cifs_inode == NULL) {
- cERROR(1,("Null inode passed to cifs_writeable_file"));
+ if (cifs_inode == NULL) {
+ cERROR(1, ("Null inode passed to cifs_writeable_file"));
dump_stack();
return NULL;
}
@@ -1024,13 +1030,14 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
(open_file->pfile->f_flags & O_WRONLY))) {
atomic_inc(&open_file->wrtPending);
read_unlock(&GlobalSMBSeslock);
- if((open_file->invalidHandle) &&
+ if ((open_file->invalidHandle) &&
(!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) {
rc = cifs_reopen_file(open_file->pfile, FALSE);
/* if it fails, try another handle - might be */
/* dangerous to hold up writepages with retry */
- if(rc) {
- cFYI(1,("failed on reopen file in wp"));
+ if (rc) {
+ cFYI(1,
+ ("failed on reopen file in wp"));
read_lock(&GlobalSMBSeslock);
/* can not use this handle, no write
pending on this one after all */
@@ -1082,7 +1089,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
/* check to make sure that we are not extending the file */
if (mapping->host->i_size - offset < (loff_t)to)
- to = (unsigned)(mapping->host->i_size - offset);
+ to = (unsigned)(mapping->host->i_size - offset);
open_file = find_writable_file(CIFS_I(mapping->host));
if (open_file) {
@@ -1116,8 +1123,8 @@ static int cifs_writepages(struct address_space *mapping,
int done = 0;
pgoff_t end;
pgoff_t index;
- int range_whole = 0;
- struct kvec * iov;
+ int range_whole = 0;
+ struct kvec *iov;
int len;
int n_iov = 0;
pgoff_t next;
@@ -1131,7 +1138,7 @@ static int cifs_writepages(struct address_space *mapping,
int xid;
cifs_sb = CIFS_SB(mapping->host->i_sb);
-
+
/*
* If wsize is smaller that the page cache size, default to writing
* one page at a time via cifs_writepage
@@ -1139,14 +1146,14 @@ static int cifs_writepages(struct address_space *mapping,
if (cifs_sb->wsize < PAGE_CACHE_SIZE)
return generic_writepages(mapping, wbc);
- if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
- if(cifs_sb->tcon->ses->server->secMode &
- (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
- if(!experimEnabled)
+ if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
+ if (cifs_sb->tcon->ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ if (!experimEnabled)
return generic_writepages(mapping, wbc);
iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
- if(iov == NULL)
+ if (iov == NULL)
return generic_writepages(mapping, wbc);
@@ -1279,7 +1286,7 @@ retry:
1);
atomic_dec(&open_file->wrtPending);
if (rc || bytes_written < bytes_to_write) {
- cERROR(1,("Write2 ret %d, written = %d",
+ cERROR(1, ("Write2 ret %d, wrote %d",
rc, bytes_written));
/* BB what if continued retry is
requested via mount flags? */
@@ -1295,8 +1302,8 @@ retry:
success rc but too little data written? */
/* BB investigate retry logic on temporary
server crash cases and how recovery works
- when page marked as error */
- if(rc)
+ when page marked as error */
+ if (rc)
SetPageError(page);
kunmap(page);
unlock_page(page);
@@ -1326,7 +1333,7 @@ retry:
return rc;
}
-static int cifs_writepage(struct page* page, struct writeback_control *wbc)
+static int cifs_writepage(struct page *page, struct writeback_control *wbc)
{
int rc = -EFAULT;
int xid;
@@ -1334,7 +1341,7 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc)
xid = GetXid();
/* BB add check for wbc flags */
page_cache_get(page);
- if (!PageUptodate(page)) {
+ if (!PageUptodate(page)) {
cFYI(1, ("ppw - page not up to date"));
}
@@ -1348,7 +1355,7 @@ static int cifs_writepage(struct page* page, struct writeback_control *wbc)
* Just unlocking the page will cause the radix tree tag-bits
* to fail to update with the state of the page correctly.
*/
- set_page_writeback(page);
+ set_page_writeback(page);
rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page); /* BB add check for error and Clearuptodate? */
unlock_page(page);
@@ -1368,7 +1375,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
char *page_data;
xid = GetXid();
- cFYI(1, ("commit write for page %p up to position %lld for %d",
+ cFYI(1, ("commit write for page %p up to position %lld for %d",
page, position, to));
spin_lock(&inode->i_lock);
if (position > inode->i_size) {
@@ -1396,7 +1403,7 @@ static int cifs_commit_write(struct file *file, struct page *page,
rc = 0;
/* else if (rc < 0) should we set writebehind rc? */
kunmap(page);
- } else {
+ } else {
set_page_dirty(page);
}
@@ -1412,9 +1419,9 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
xid = GetXid();
- cFYI(1, ("Sync file - name: %s datasync: 0x%x",
+ cFYI(1, ("Sync file - name: %s datasync: 0x%x",
dentry->d_name.name, datasync));
-
+
rc = filemap_fdatawrite(inode->i_mapping);
if (rc == 0)
CIFS_I(inode)->write_behind_rc = 0;
@@ -1438,7 +1445,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
if (!inode)
return; */
-/* fill in rpages then
+/* fill in rpages then
result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */
/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));
@@ -1456,7 +1463,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync)
*/
int cifs_flush(struct file *file, fl_owner_t id)
{
- struct inode * inode = file->f_path.dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
int rc = 0;
/* Rather than do the steps manually:
@@ -1471,8 +1478,8 @@ int cifs_flush(struct file *file, fl_owner_t id)
rc = filemap_fdatawrite(inode->i_mapping);
if (!rc) /* reset wb rc if we were able to write out dirty pages */
CIFS_I(inode)->write_behind_rc = 0;
-
- cFYI(1, ("Flush inode %p file %p rc %d",inode,file,rc));
+
+ cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));
return rc;
}
@@ -1508,13 +1515,13 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
for (total_read = 0, current_offset = read_data;
read_size > total_read;
total_read += bytes_read, current_offset += bytes_read) {
- current_read_size = min_t(const int, read_size - total_read,
+ current_read_size = min_t(const int, read_size - total_read,
cifs_sb->rsize);
rc = -EAGAIN;
smb_read_data = NULL;
while (rc == -EAGAIN) {
int buf_type = CIFS_NO_BUFFER;
- if ((open_file->invalidHandle) &&
+ if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
rc = cifs_reopen_file(file, TRUE);
if (rc != 0)
@@ -1535,9 +1542,9 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data,
rc = -EFAULT;
}
- if(buf_type == CIFS_SMALL_BUFFER)
+ if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data);
- else if(buf_type == CIFS_LARGE_BUFFER)
+ else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data);
smb_read_data = NULL;
}
@@ -1586,21 +1593,21 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
if ((file->f_flags & O_ACCMODE) == O_WRONLY)
cFYI(1, ("attempting read on write only file instance"));
- for (total_read = 0, current_offset = read_data;
+ for (total_read = 0, current_offset = read_data;
read_size > total_read;
total_read += bytes_read, current_offset += bytes_read) {
current_read_size = min_t(const int, read_size - total_read,
cifs_sb->rsize);
/* For windows me and 9x we do not want to request more
than it negotiated since it will refuse the read then */
- if((pTcon->ses) &&
+ if ((pTcon->ses) &&
!(pTcon->ses->capabilities & CAP_LARGE_FILES)) {
current_read_size = min_t(const int, current_read_size,
pTcon->ses->server->maxBuf - 128);
}
rc = -EAGAIN;
while (rc == -EAGAIN) {
- if ((open_file->invalidHandle) &&
+ if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
rc = cifs_reopen_file(file, TRUE);
if (rc != 0)
@@ -1646,7 +1653,7 @@ int cifs_file_mmap(struct file *file, struct vm_area_struct *vma)
}
-static void cifs_copy_cache_pages(struct address_space *mapping,
+static void cifs_copy_cache_pages(struct address_space *mapping,
struct list_head *pages, int bytes_read, char *data,
struct pagevec *plru_pvec)
{
@@ -1669,12 +1676,12 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
continue;
}
- target = kmap_atomic(page,KM_USER0);
+ target = kmap_atomic(page, KM_USER0);
if (PAGE_CACHE_SIZE > bytes_read) {
memcpy(target, data, bytes_read);
/* zero the tail end of this partial page */
- memset(target + bytes_read, 0,
+ memset(target + bytes_read, 0,
PAGE_CACHE_SIZE - bytes_read);
bytes_read = 0;
} else {
@@ -1703,7 +1710,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
int bytes_read = 0;
- unsigned int read_size,i;
+ unsigned int read_size, i;
char *smb_read_data = NULL;
struct smb_com_read_rsp *pSMBr;
struct pagevec lru_pvec;
@@ -1720,7 +1727,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
pTcon = cifs_sb->tcon;
pagevec_init(&lru_pvec, 0);
-
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1, ("rpages: num pages %d", num_pages));
+#endif
for (i = 0; i < num_pages; ) {
unsigned contig_pages;
struct page *tmp_page;
@@ -1734,14 +1743,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
/* count adjacent pages that we will read into */
contig_pages = 0;
- expected_index =
+ expected_index =
list_entry(page_list->prev, struct page, lru)->index;
- list_for_each_entry_reverse(tmp_page,page_list,lru) {
+ list_for_each_entry_reverse(tmp_page, page_list, lru) {
if (tmp_page->index == expected_index) {
contig_pages++;
expected_index++;
} else
- break;
+ break;
}
if (contig_pages + i > num_pages)
contig_pages = num_pages - i;
@@ -1753,10 +1762,13 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
/* Read size needs to be in multiples of one page */
read_size = min_t(const unsigned int, read_size,
cifs_sb->rsize & PAGE_CACHE_MASK);
-
+#ifdef CONFIG_CIFS_DEBUG2
+ cFYI(1, ("rpages: read size 0x%x contiguous pages %d",
+ read_size, contig_pages));
+#endif
rc = -EAGAIN;
while (rc == -EAGAIN) {
- if ((open_file->invalidHandle) &&
+ if ((open_file->invalidHandle) &&
(!open_file->closePend)) {
rc = cifs_reopen_file(file, TRUE);
if (rc != 0)
@@ -1769,11 +1781,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
&bytes_read, &smb_read_data,
&buf_type);
/* BB more RC checks ? */
- if (rc== -EAGAIN) {
+ if (rc == -EAGAIN) {
if (smb_read_data) {
- if(buf_type == CIFS_SMALL_BUFFER)
+ if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data);
- else if(buf_type == CIFS_LARGE_BUFFER)
+ else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data);
smb_read_data = NULL;
}
@@ -1794,10 +1806,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) {
i++; /* account for partial page */
- /* server copy of file can have smaller size
+ /* server copy of file can have smaller size
than client */
- /* BB do we need to verify this common case ?
- this case is ok - if we are at server EOF
+ /* BB do we need to verify this common case ?
+ this case is ok - if we are at server EOF
we will hit it on next read */
/* break; */
@@ -1806,14 +1818,14 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
cFYI(1, ("No bytes read (%d) at offset %lld . "
"Cleaning remaining pages from readahead list",
bytes_read, offset));
- /* BB turn off caching and do new lookup on
+ /* BB turn off caching and do new lookup on
file size at server? */
break;
}
if (smb_read_data) {
- if(buf_type == CIFS_SMALL_BUFFER)
+ if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data);
- else if(buf_type == CIFS_LARGE_BUFFER)
+ else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data);
smb_read_data = NULL;
}
@@ -1824,12 +1836,12 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
/* need to free smb_read_data buf before exit */
if (smb_read_data) {
- if(buf_type == CIFS_SMALL_BUFFER)
+ if (buf_type == CIFS_SMALL_BUFFER)
cifs_small_buf_release(smb_read_data);
- else if(buf_type == CIFS_LARGE_BUFFER)
+ else if (buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(smb_read_data);
smb_read_data = NULL;
- }
+ }
FreeXid(xid);
return rc;
@@ -1844,26 +1856,26 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
page_cache_get(page);
read_data = kmap(page);
/* for reads over a certain size could initiate async read ahead */
-
+
rc = cifs_read(file, read_data, PAGE_CACHE_SIZE, poffset);
-
+
if (rc < 0)
goto io_error;
else
- cFYI(1, ("Bytes read %d",rc));
-
+ cFYI(1, ("Bytes read %d", rc));
+
file->f_path.dentry->d_inode->i_atime =
current_fs_time(file->f_path.dentry->d_inode->i_sb);
-
+
if (PAGE_CACHE_SIZE > rc)
memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc);
flush_dcache_page(page);
SetPageUptodate(page);
rc = 0;
-
+
io_error:
- kunmap(page);
+ kunmap(page);
page_cache_release(page);
return rc;
}
@@ -1881,7 +1893,7 @@ static int cifs_readpage(struct file *file, struct page *page)
return -EBADF;
}
- cFYI(1, ("readpage %p at offset %d 0x%x\n",
+ cFYI(1, ("readpage %p at offset %d 0x%x\n",
page, (int)offset, (int)offset));
rc = cifs_readpage_worker(file, page, &offset);
@@ -1895,7 +1907,7 @@ static int cifs_readpage(struct file *file, struct page *page)
/* We do not want to update the file size from server for inodes
open for write - to avoid races with writepage extending
the file - in the future we could consider allowing
- refreshing the inode only on increases in the file size
+ refreshing the inode only on increases in the file size
but this is tricky to do without racing with writebehind
page caching in the current Linux kernel design */
int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
@@ -1904,8 +1916,8 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
if (cifsInode)
open_file = find_writable_file(cifsInode);
-
- if(open_file) {
+
+ if (open_file) {
struct cifs_sb_info *cifs_sb;
/* there is not actually a write pending so let
@@ -1915,12 +1927,12 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_file)
cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb);
if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) {
- /* since no page cache to corrupt on directio
+ /* since no page cache to corrupt on directio
we can change size safely */
return 1;
}
- if(i_size_read(&cifsInode->vfs_inode) < end_of_file)
+ if (i_size_read(&cifsInode->vfs_inode) < end_of_file)
return 1;
return 0;
@@ -1935,7 +1947,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
loff_t i_size;
loff_t offset;
- cFYI(1, ("prepare write for page %p from %d to %d",page,from,to));
+ cFYI(1, ("prepare write for page %p from %d to %d", page, from, to));
if (PageUptodate(page))
return 0;
@@ -1955,14 +1967,7 @@ static int cifs_prepare_write(struct file *file, struct page *page,
* We don't need to read data beyond the end of the file.
* zero it, and set the page uptodate
*/
- void *kaddr = kmap_atomic(page, KM_USER0);
-
- if (from)
- memset(kaddr, 0, from);
- if (to < PAGE_CACHE_SIZE)
- memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ simple_prepare_write(file, page, from, to);
SetPageUptodate(page);
} else if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
/* might as well read a page, it is fast enough */
@@ -1974,8 +1979,8 @@ static int cifs_prepare_write(struct file *file, struct page *page,
this will be written out by commit_write so is fine */
}
- /* we do not need to pass errors back
- e.g. if we do not have read access to the file
+ /* we do not need to pass errors back
+ e.g. if we do not have read access to the file
because cifs_commit_write will do the right thing. -- shaggy */
return 0;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f0ff12b3f398..dd4167762a8e 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -57,14 +57,14 @@ int cifs_get_inode_info_unix(struct inode **pinode,
if (tmp_path == NULL) {
return -ENOMEM;
}
- /* have to skip first of the double backslash of
+ /* have to skip first of the double backslash of
UNC name */
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
strncat(tmp_path, search_path, MAX_PATHCONF);
rc = connect_to_dfs_path(xid, pTcon->ses,
/* treename + */ tmp_path,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(tmp_path);
@@ -81,7 +81,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
- if (*pinode == NULL)
+ if (*pinode == NULL)
return -ENOMEM;
/* Is an i_ino of zero legal? */
/* Are there sanity checks we can use to ensure that
@@ -92,7 +92,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
} /* note ino incremented to unique num in new_inode */
if (sb->s_flags & MS_NOATIME)
(*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
-
+
insert_inode_hash(*pinode);
}
@@ -103,7 +103,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
cifsInfo->time = jiffies;
cFYI(1, ("New time %ld", cifsInfo->time));
/* this is ok to set on every inode revalidate */
- atomic_set(&cifsInfo->inUse,1);
+ atomic_set(&cifsInfo->inUse, 1);
inode->i_atime =
cifs_NTtimeToUnix(le64_to_cpu(findData.LastAccessTime));
@@ -114,8 +114,8 @@ int cifs_get_inode_info_unix(struct inode **pinode,
cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange));
inode->i_mode = le64_to_cpu(findData.Permissions);
/* since we set the inode type below we need to mask off
- to avoid strange results if bits set above */
- inode->i_mode &= ~S_IFMT;
+ to avoid strange results if bits set above */
+ inode->i_mode &= ~S_IFMT;
if (type == UNIX_FILE) {
inode->i_mode |= S_IFREG;
} else if (type == UNIX_SYMLINK) {
@@ -137,9 +137,9 @@ int cifs_get_inode_info_unix(struct inode **pinode,
} else {
/* safest to call it a file if we do not know */
inode->i_mode |= S_IFREG;
- cFYI(1,("unknown type %d",type));
+ cFYI(1, ("unknown type %d", type));
}
-
+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
inode->i_uid = cifs_sb->mnt_uid;
else
@@ -149,7 +149,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode->i_gid = cifs_sb->mnt_gid;
else
inode->i_gid = le64_to_cpu(findData.Gid);
-
+
inode->i_nlink = le64_to_cpu(findData.Nlinks);
spin_lock(&inode->i_lock);
@@ -183,17 +183,17 @@ int cifs_get_inode_info_unix(struct inode **pinode,
inode->i_op = &cifs_file_inode_ops;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
- inode->i_fop =
+ inode->i_fop =
&cifs_file_direct_nobrl_ops;
else
inode->i_fop = &cifs_file_direct_ops;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
inode->i_fop = &cifs_file_nobrl_ops;
- else /* not direct, send byte range locks */
+ else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops;
/* check if server can support readpages */
- if (pTcon->ses->server->maxBuf <
+ if (pTcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
@@ -215,7 +215,7 @@ int cifs_get_inode_info_unix(struct inode **pinode,
return rc;
}
-static int decode_sfu_inode(struct inode * inode, __u64 size,
+static int decode_sfu_inode(struct inode *inode, __u64 size,
const unsigned char *path,
struct cifs_sb_info *cifs_sb, int xid)
{
@@ -225,7 +225,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
struct cifsTconInfo *pTcon = cifs_sb->tcon;
char buf[24];
unsigned int bytes_read;
- char * pbuf;
+ char *pbuf;
pbuf = buf;
@@ -235,22 +235,22 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
} else if (size < 8) {
return -EINVAL; /* EOPNOTSUPP? */
}
-
+
rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc==0) {
+ if (rc == 0) {
int buf_type = CIFS_NO_BUFFER;
/* Read header */
rc = CIFSSMBRead(xid, pTcon,
- netfid,
+ netfid,
24 /* length */, 0 /* offset */,
&bytes_read, &pbuf, &buf_type);
if ((rc == 0) && (bytes_read >= 8)) {
if (memcmp("IntxBLK", pbuf, 8) == 0) {
- cFYI(1,("Block device"));
+ cFYI(1, ("Block device"));
inode->i_mode |= S_IFBLK;
if (bytes_read == 24) {
/* we have enough to decode dev num */
@@ -261,7 +261,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
inode->i_rdev = MKDEV(mjr, mnr);
}
} else if (memcmp("IntxCHR", pbuf, 8) == 0) {
- cFYI(1,("Char device"));
+ cFYI(1, ("Char device"));
inode->i_mode |= S_IFCHR;
if (bytes_read == 24) {
/* we have enough to decode dev num */
@@ -270,27 +270,26 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
inode->i_rdev = MKDEV(mjr, mnr);
- }
+ }
} else if (memcmp("IntxLNK", pbuf, 7) == 0) {
- cFYI(1,("Symlink"));
+ cFYI(1, ("Symlink"));
inode->i_mode |= S_IFLNK;
} else {
inode->i_mode |= S_IFREG; /* file? */
- rc = -EOPNOTSUPP;
+ rc = -EOPNOTSUPP;
}
} else {
inode->i_mode |= S_IFREG; /* then it is a file */
- rc = -EOPNOTSUPP; /* or some unknown SFU type */
- }
+ rc = -EOPNOTSUPP; /* or some unknown SFU type */
+ }
CIFSSMBClose(xid, pTcon, netfid);
}
return rc;
-
}
#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */
-static int get_sfu_uid_mode(struct inode * inode,
+static int get_sfu_uid_mode(struct inode *inode,
const unsigned char *path,
struct cifs_sb_info *cifs_sb, int xid)
{
@@ -301,15 +300,15 @@ static int get_sfu_uid_mode(struct inode * inode,
rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS",
ea_value, 4 /* size of buf */, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc < 0)
return (int)rc;
else if (rc > 3) {
mode = le32_to_cpu(*((__le32 *)ea_value));
- inode->i_mode &= ~SFBITS_MASK;
- cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode));
+ inode->i_mode &= ~SFBITS_MASK;
+ cFYI(1, ("special bits 0%o org mode 0%o", mode, inode->i_mode));
inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode;
- cFYI(1,("special mode bits 0%o", mode));
+ cFYI(1, ("special mode bits 0%o", mode));
return 0;
} else {
return 0;
@@ -317,8 +316,6 @@ static int get_sfu_uid_mode(struct inode * inode,
#else
return -EOPNOTSUPP;
#endif
-
-
}
int cifs_get_inode_info(struct inode **pinode,
@@ -334,11 +331,11 @@ int cifs_get_inode_info(struct inode **pinode,
int adjustTZ = FALSE;
pTcon = cifs_sb->tcon;
- cFYI(1,("Getting info on %s", search_path));
+ cFYI(1, ("Getting info on %s", search_path));
if ((pfindData == NULL) && (*pinode != NULL)) {
if (CIFS_I(*pinode)->clientCanCacheRead) {
- cFYI(1,("No need to revalidate cached inode sizes"));
+ cFYI(1, ("No need to revalidate cached inode sizes"));
return rc;
}
}
@@ -359,12 +356,11 @@ int cifs_get_inode_info(struct inode **pinode,
failed at least once - set flag in tcon or mount */
if ((rc == -EOPNOTSUPP) || (rc == -EINVAL)) {
rc = SMBQueryInformation(xid, pTcon, search_path,
- pfindData, cifs_sb->local_nls,
+ pfindData, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
adjustTZ = TRUE;
}
-
}
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) {
@@ -384,8 +380,8 @@ int cifs_get_inode_info(struct inode **pinode,
strncat(tmp_path, search_path, MAX_PATHCONF);
rc = connect_to_dfs_path(xid, pTcon->ses,
/* treename + */ tmp_path,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(tmp_path);
/* BB fix up inode etc. */
@@ -419,17 +415,17 @@ int cifs_get_inode_info(struct inode **pinode,
there Windows server or network appliances for which
IndexNumber field is not guaranteed unique? */
- if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM){
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
int rc1 = 0;
__u64 inode_num;
- rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
- search_path, &inode_num,
+ rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
+ search_path, &inode_num,
cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc1) {
- cFYI(1,("GetSrvInodeNum rc %d", rc1));
+ cFYI(1, ("GetSrvInodeNum rc %d", rc1));
/* BB EOPNOSUPP disable SERVER_INUM? */
} else /* do we need cast or hash to ino? */
(*pinode)->i_ino = inode_num;
@@ -463,7 +459,7 @@ int cifs_get_inode_info(struct inode **pinode,
cFYI(0, ("Attributes came in as 0x%x", attr));
if (adjustTZ && (pTcon->ses) && (pTcon->ses->server)) {
inode->i_ctime.tv_sec += pTcon->ses->server->timeAdj;
- inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
+ inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj;
}
/* set default mode. will override for dirs below */
@@ -471,8 +467,9 @@ int cifs_get_inode_info(struct inode **pinode,
/* new inode, can safely set these fields */
inode->i_mode = cifs_sb->mnt_file_mode;
else /* since we set the inode type below we need to mask off
- to avoid strange results if type changes and both get orred in */
- inode->i_mode &= ~S_IFMT;
+ to avoid strange results if type changes and both
+ get orred in */
+ inode->i_mode &= ~S_IFMT;
/* if (attr & ATTR_REPARSE) */
/* We no longer handle these as symlinks because we could not
follow them due to the absolute path with drive letter */
@@ -490,13 +487,13 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB Finish for SFU style symlinks and devices */
} else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(cifsInfo->cifsAttrs & ATTR_SYSTEM)) {
- if (decode_sfu_inode(inode,
+ if (decode_sfu_inode(inode,
le64_to_cpu(pfindData->EndOfFile),
search_path,
cifs_sb, xid)) {
- cFYI(1,("Unrecognized sfu inode type"));
+ cFYI(1, ("Unrecognized sfu inode type"));
}
- cFYI(1,("sfu mode 0%o",inode->i_mode));
+ cFYI(1, ("sfu mode 0%o", inode->i_mode));
} else {
inode->i_mode |= S_IFREG;
/* treat the dos attribute of read-only as read-only
@@ -512,12 +509,12 @@ int cifs_get_inode_info(struct inode **pinode,
/* BB add code here -
validate if device or weird share or device type? */
}
-
+
spin_lock(&inode->i_lock);
if (is_size_safe_to_change(cifsInfo, le64_to_cpu(pfindData->EndOfFile))) {
/* can not safely shrink the file size here if the
client is writing to it due to potential races */
- i_size_write(inode,le64_to_cpu(pfindData->EndOfFile));
+ i_size_write(inode, le64_to_cpu(pfindData->EndOfFile));
/* 512 bytes (2**9) is the fake blocksize that must be
used for this calculation */
@@ -528,7 +525,7 @@ int cifs_get_inode_info(struct inode **pinode,
inode->i_nlink = le32_to_cpu(pfindData->NumberOfLinks);
- /* BB fill in uid and gid here? with help from winbind?
+ /* BB fill in uid and gid here? with help from winbind?
or retrieve from NTFS stream extended attribute */
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
/* fill in uid, gid, mode from server ACL */
@@ -540,7 +537,7 @@ int cifs_get_inode_info(struct inode **pinode,
inode->i_gid = cifs_sb->mnt_gid;
/* set so we do not keep refreshing these fields with
bad data after user has changed them in memory */
- atomic_set(&cifsInfo->inUse,1);
+ atomic_set(&cifsInfo->inUse, 1);
}
if (S_ISREG(inode->i_mode)) {
@@ -557,7 +554,7 @@ int cifs_get_inode_info(struct inode **pinode,
else /* not direct, send byte range locks */
inode->i_fop = &cifs_file_ops;
- if (pTcon->ses->server->maxBuf <
+ if (pTcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)
inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
@@ -586,10 +583,11 @@ void cifs_read_inode(struct inode *inode)
cifs_sb = CIFS_SB(inode->i_sb);
xid = GetXid();
- if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
- cifs_get_inode_info_unix(&inode, "", inode->i_sb,xid);
+
+ if (cifs_sb->tcon->unix_ext)
+ cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid);
else
- cifs_get_inode_info(&inode, "", NULL, inode->i_sb,xid);
+ cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid);
/* can not call macro FreeXid here since in a void func */
_FreeXid(xid);
}
@@ -623,9 +621,21 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
FreeXid(xid);
return -ENOMEM;
}
- rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+
+ if ((pTcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+ le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
+ rc = CIFSPOSIXDelFile(xid, pTcon, full_path,
+ SMB_POSIX_UNLINK_FILE_TARGET, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+ cFYI(1, ("posix del rc %d", rc));
+ if ((rc == 0) || (rc == -ENOENT))
+ goto psx_del_no_retry;
+ }
+ rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+psx_del_no_retry:
if (!rc) {
if (direntry->d_inode)
drop_nlink(direntry->d_inode);
@@ -638,12 +648,12 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, NULL, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc==0) {
+ if (rc == 0) {
CIFSSMBRenameOpenFile(xid, pTcon, netfid, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
if (direntry->d_inode)
@@ -659,7 +669,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
rc = CIFSSMBSetTimes(xid, pTcon, full_path,
pinfo_buf,
cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
else
rc = -EOPNOTSUPP;
@@ -670,7 +680,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
/* rc = CIFSSMBSetAttrLegacy(xid, pTcon,
full_path,
(__u16)ATTR_NORMAL,
- cifs_sb->local_nls);
+ cifs_sb->local_nls);
For some strange reason it seems that NT4 eats the
old setattr call without actually setting the
attributes so on to the third attempted workaround
@@ -683,9 +693,9 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
FILE_WRITE_ATTRIBUTES, 0,
&netfid, &oplock, NULL,
cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc==0) {
+ if (rc == 0) {
rc = CIFSSMBSetFileTimes(xid, pTcon,
pinfo_buf,
netfid);
@@ -694,10 +704,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
}
kfree(pinfo_buf);
}
- if (rc==0) {
- rc = CIFSSMBDelFile(xid, pTcon, full_path,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ if (rc == 0) {
+ rc = CIFSSMBDelFile(xid, pTcon, full_path,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) {
if (direntry->d_inode)
@@ -711,10 +721,10 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CREATE_NOT_DIR |
CREATE_DELETE_ON_CLOSE,
&netfid, &oplock, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc==0) {
+ if (rc == 0) {
CIFSSMBRenameOpenFile(xid, pTcon,
netfid, NULL,
cifs_sb->local_nls,
@@ -773,8 +783,8 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_mode = le64_to_cpu(pData->Permissions);
/* since we set the inode type below we need to mask off type
- to avoid strange results if bits above were corrupt */
- tmp_inode->i_mode &= ~S_IFMT;
+ to avoid strange results if bits above were corrupt */
+ tmp_inode->i_mode &= ~S_IFMT;
if (type == UNIX_FILE) {
*pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG;
@@ -804,11 +814,11 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
/* safest to just call it a file */
*pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG;
- cFYI(1,("unknown inode type %d",type));
+ cFYI(1, ("unknown inode type %d", type));
}
#ifdef CONFIG_CIFS_DEBUG2
- cFYI(1,("object type: %d", type));
+ cFYI(1, ("object type: %d", type));
#endif
tmp_inode->i_uid = le64_to_cpu(pData->Uid);
tmp_inode->i_gid = le64_to_cpu(pData->Gid);
@@ -816,7 +826,7 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
- /* can not safely change the file size here if the
+ /* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(tmp_inode, end_of_file);
@@ -830,27 +840,28 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops;
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_direct_ops;
-
- } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
+
+ } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_ops;
- if((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
- (cifs_sb->tcon->ses->server->maxBuf <
+ if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
+ (cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
tmp_inode->i_data.a_ops = &cifs_addr_ops;
- if(isNewInode)
- return; /* No sense invalidating pages for new inode since we
- have not started caching readahead file data yet */
+ if (isNewInode)
+ return; /* No sense invalidating pages for new inode
+ since we we have not started caching
+ readahead file data yet */
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
(local_size == tmp_inode->i_size)) {
@@ -869,10 +880,10 @@ static void posix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_op = &cifs_symlink_inode_ops;
/* tmp_inode->i_fop = *//* do not need to set to anything */
} else {
- cFYI(1, ("Special inode"));
+ cFYI(1, ("Special inode"));
init_special_inode(tmp_inode, tmp_inode->i_mode,
tmp_inode->i_rdev);
- }
+ }
}
int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
@@ -896,22 +907,22 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
FreeXid(xid);
return -ENOMEM;
}
-
- if((pTcon->ses->capabilities & CAP_UNIX) &&
- (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+
+ if ((pTcon->ses->capabilities & CAP_UNIX) &&
+ (CIFS_UNIX_POSIX_PATH_OPS_CAP &
le64_to_cpu(pTcon->fsUnixInfo.Capability))) {
u32 oplock = 0;
- FILE_UNIX_BASIC_INFO * pInfo =
+ FILE_UNIX_BASIC_INFO * pInfo =
kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
- if(pInfo == NULL) {
+ if (pInfo == NULL) {
rc = -ENOMEM;
goto mkdir_out;
}
-
+
rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT,
mode, NULL /* netfid */, pInfo, &oplock,
- full_path, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ full_path, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (rc) {
cFYI(1, ("posix mkdir returned 0x%x", rc));
@@ -919,8 +930,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
} else {
int obj_type;
if (pInfo->Type == -1) /* no return info - go query */
- goto mkdir_get_info;
-/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */
+ goto mkdir_get_info;
+/*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need
+ to set uid/gid */
inc_nlink(inode);
if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
@@ -937,7 +949,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
newinode->i_ino =
(unsigned long)pInfo->UniqueId;
} /* note ino incremented to unique num in new_inode */
- if(inode->i_sb->s_flags & MS_NOATIME)
+ if (inode->i_sb->s_flags & MS_NOATIME)
newinode->i_flags |= S_NOATIME | S_NOCMTIME;
newinode->i_nlink = 2;
@@ -949,18 +961,18 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
posix_fill_in_inode(direntry->d_inode,
pInfo, &obj_type, 1 /* NewInode */);
#ifdef CONFIG_CIFS_DEBUG2
- cFYI(1,("instantiated dentry %p %s to inode %p",
+ cFYI(1, ("instantiated dentry %p %s to inode %p",
direntry, direntry->d_name.name, newinode));
- if(newinode->i_nlink != 2)
- cFYI(1,("unexpected number of links %d",
+ if (newinode->i_nlink != 2)
+ cFYI(1, ("unexpected number of links %d",
newinode->i_nlink));
#endif
}
kfree(pInfo);
goto mkdir_out;
- }
-
+ }
+
/* BB add setting the equivalent of mode via CreateX w/ACLs */
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -968,14 +980,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
cFYI(1, ("cifs_mkdir returned 0x%x", rc));
d_drop(direntry);
} else {
-mkdir_get_info:
+mkdir_get_info:
inc_nlink(inode);
- if (pTcon->ses->capabilities & CAP_UNIX)
+ if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb,xid);
+ inode->i_sb, xid);
else
rc = cifs_get_inode_info(&newinode, full_path, NULL,
- inode->i_sb,xid);
+ inode->i_sb, xid);
if (pTcon->nocase)
direntry->d_op = &cifs_ci_dentry_ops;
@@ -983,10 +995,10 @@ mkdir_get_info:
direntry->d_op = &cifs_dentry_ops;
d_instantiate(direntry, newinode);
/* setting nlink not necessary except in cases where we
- * failed to get it from the server or was set bogus */
+ * failed to get it from the server or was set bogus */
if ((direntry->d_inode) && (direntry->d_inode->i_nlink < 2))
- direntry->d_inode->i_nlink = 2;
- if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+ direntry->d_inode->i_nlink = 2;
+ if (pTcon->unix_ext) {
mode &= ~current->fs->umask;
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
CIFSSMBUnixSetPerms(xid, pTcon, full_path,
@@ -1002,27 +1014,27 @@ mkdir_get_info:
mode, (__u64)-1,
(__u64)-1, 0 /* dev_t */,
cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
} else {
/* BB to be implemented via Windows secrty descriptors
eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode,
-1, -1, local_nls); */
- if(direntry->d_inode) {
+ if (direntry->d_inode) {
direntry->d_inode->i_mode = mode;
direntry->d_inode->i_mode |= S_IFDIR;
- if(cifs_sb->mnt_cifs_flags &
+ if (cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_SET_UID) {
- direntry->d_inode->i_uid =
+ direntry->d_inode->i_uid =
current->fsuid;
- direntry->d_inode->i_gid =
+ direntry->d_inode->i_gid =
current->fsgid;
}
}
}
}
-mkdir_out:
+mkdir_out:
kfree(full_path);
FreeXid(xid);
return rc;
@@ -1056,7 +1068,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
if (!rc) {
drop_nlink(inode);
spin_lock(&direntry->d_inode->i_lock);
- i_size_write(direntry->d_inode,0);
+ i_size_write(direntry->d_inode, 0);
clear_nlink(direntry->d_inode);
spin_unlock(&direntry->d_inode->i_lock);
}
@@ -1119,9 +1131,9 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
if (info_buf_source != NULL) {
info_buf_target = info_buf_source + 1;
- if (pTcon->ses->capabilities & CAP_UNIX)
+ if (pTcon->unix_ext)
rc = CIFSSMBUnixQPathInfo(xid, pTcon, fromName,
- info_buf_source,
+ info_buf_source,
cifs_sb_source->local_nls,
cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
@@ -1171,12 +1183,12 @@ int cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
might not right be right access to request */
rc = CIFSSMBOpen(xid, pTcon, fromName, FILE_OPEN, GENERIC_READ,
CREATE_NOT_DIR, &netfid, &oplock, NULL,
- cifs_sb_source->local_nls,
- cifs_sb_source->mnt_cifs_flags &
+ cifs_sb_source->local_nls,
+ cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc==0) {
+ if (rc == 0) {
rc = CIFSSMBRenameOpenFile(xid, pTcon, netfid, toName,
- cifs_sb_source->local_nls,
+ cifs_sb_source->local_nls,
cifs_sb_source->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
@@ -1247,9 +1259,9 @@ int cifs_revalidate(struct dentry *direntry)
local_mtime = direntry->d_inode->i_mtime;
local_size = direntry->d_inode->i_size;
- if (cifs_sb->tcon->ses->capabilities & CAP_UNIX) {
+ if (cifs_sb->tcon->unix_ext) {
rc = cifs_get_inode_info_unix(&direntry->d_inode, full_path,
- direntry->d_sb,xid);
+ direntry->d_sb, xid);
if (rc) {
cFYI(1, ("error on getting revalidate info %d", rc));
/* if (rc != -ENOENT)
@@ -1258,7 +1270,7 @@ int cifs_revalidate(struct dentry *direntry)
}
} else {
rc = cifs_get_inode_info(&direntry->d_inode, full_path, NULL,
- direntry->d_sb,xid);
+ direntry->d_sb, xid);
if (rc) {
cFYI(1, ("error on getting revalidate info %d", rc));
/* if (rc != -ENOENT)
@@ -1271,7 +1283,7 @@ int cifs_revalidate(struct dentry *direntry)
/* if not oplocked, we invalidate inode pages if mtime or file size
had changed on server */
- if (timespec_equal(&local_mtime,&direntry->d_inode->i_mtime) &&
+ if (timespec_equal(&local_mtime, &direntry->d_inode->i_mtime) &&
(local_size == direntry->d_inode->i_size)) {
cFYI(1, ("cifs_revalidate - inode unchanged"));
} else {
@@ -1298,7 +1310,7 @@ int cifs_revalidate(struct dentry *direntry)
if (invalidate_inode) {
/* shrink_dcache not necessary now that cifs dentry ops
are exported for negative dentries */
-/* if(S_ISDIR(direntry->d_inode->i_mode))
+/* if (S_ISDIR(direntry->d_inode->i_mode))
shrink_dcache_parent(direntry); */
if (S_ISREG(direntry->d_inode->i_mode)) {
if (direntry->d_inode->i_mapping)
@@ -1313,7 +1325,7 @@ int cifs_revalidate(struct dentry *direntry)
}
}
/* mutex_unlock(&direntry->d_inode->i_mutex); */
-
+
kfree(full_path);
FreeXid(xid);
return rc;
@@ -1335,23 +1347,19 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
pgoff_t index = from >> PAGE_CACHE_SHIFT;
unsigned offset = from & (PAGE_CACHE_SIZE - 1);
struct page *page;
- char *kaddr;
int rc = 0;
page = grab_cache_page(mapping, index);
if (!page)
return -ENOMEM;
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0);
unlock_page(page);
page_cache_release(page);
return rc;
}
-static int cifs_vmtruncate(struct inode * inode, loff_t offset)
+static int cifs_vmtruncate(struct inode *inode, loff_t offset)
{
struct address_space *mapping = inode->i_mapping;
unsigned long limit;
@@ -1424,13 +1432,13 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
/* check if we have permission to change attrs */
rc = inode_change_ok(direntry->d_inode, attrs);
- if(rc < 0) {
+ if (rc < 0) {
FreeXid(xid);
return rc;
} else
rc = 0;
}
-
+
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
FreeXid(xid);
@@ -1459,16 +1467,16 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size,
nfid, npid, FALSE);
atomic_dec(&open_file->wrtPending);
- cFYI(1,("SetFSize for attrs rc = %d", rc));
- if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+ cFYI(1, ("SetFSize for attrs rc = %d", rc));
+ if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
int bytes_written;
rc = CIFSSMBWrite(xid, pTcon,
nfid, 0, attrs->ia_size,
&bytes_written, NULL, NULL,
1 /* 45 seconds */);
- cFYI(1,("Wrt seteof rc %d", rc));
+ cFYI(1, ("Wrt seteof rc %d", rc));
}
- } else
+ } else
rc = -EINVAL;
if (rc != 0) {
@@ -1478,11 +1486,11 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
it by handle */
rc = CIFSSMBSetEOF(xid, pTcon, full_path,
attrs->ia_size, FALSE,
- cifs_sb->local_nls,
+ cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc));
- if((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+ if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
__u16 netfid;
int oplock = FALSE;
@@ -1493,14 +1501,14 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc==0) {
+ if (rc == 0) {
int bytes_written;
rc = CIFSSMBWrite(xid, pTcon,
netfid, 0,
attrs->ia_size,
&bytes_written, NULL,
NULL, 1 /* 45 sec */);
- cFYI(1,("wrt seteof rc %d",rc));
+ cFYI(1, ("wrt seteof rc %d", rc));
CIFSSMBClose(xid, pTcon, netfid);
}
@@ -1517,7 +1525,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
rc = cifs_vmtruncate(direntry->d_inode, attrs->ia_size);
cifs_truncate_page(direntry->d_inode->i_mapping,
direntry->d_inode->i_size);
- } else
+ } else
goto cifs_setattr_exit;
}
if (attrs->ia_valid & ATTR_UID) {
@@ -1535,11 +1543,11 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
mode = attrs->ia_mode;
}
- if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ if ((pTcon->unix_ext)
&& (attrs->ia_valid & (ATTR_MODE | ATTR_GID | ATTR_UID)))
rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, uid, gid,
0 /* dev_t */, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
else if (attrs->ia_valid & ATTR_MODE) {
rc = 0;
@@ -1559,7 +1567,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs &
(~ATTR_READONLY));
/* Windows ignores set to zero */
- if(time_buf.Attributes == 0)
+ if (time_buf.Attributes == 0)
time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
}
/* BB to be implemented -
@@ -1585,7 +1593,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
stamps are changed explicitly (i.e. by utime()
since we would then have a mix of client and
server times */
-
+
if (set_time && (attrs->ia_valid & ATTR_CTIME)) {
set_time = TRUE;
/* Although Samba throws this field away
@@ -1624,7 +1632,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
NULL, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if (rc==0) {
+ if (rc == 0) {
rc = CIFSSMBSetFileTimes(xid, pTcon, &time_buf,
netfid);
CIFSSMBClose(xid, pTcon, netfid);
@@ -1634,7 +1642,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
granularity */
/* rc = CIFSSMBSetTimesLegacy(xid, pTcon, full_path,
- &time_buf, cifs_sb->local_nls); */
+ &time_buf, cifs_sb->local_nls); */
}
}
/* Even if error on time set, no sense failing the call if
@@ -1642,7 +1650,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
and this check ensures that we are not being called from
sys_utimes in which case we ought to fail the call back to
the user when the server rejects the call */
- if((rc) && (attrs->ia_valid &
+ if ((rc) && (attrs->ia_valid &
(ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE)))
rc = 0;
}
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index a414f1775ae0..d24fe6880a04 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -3,7 +3,7 @@
*
* vfs operations that deal with io control
*
- * Copyright (C) International Business Machines Corp., 2005
+ * Copyright (C) International Business Machines Corp., 2005,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
#define CIFS_IOC_CHECKUMOUNT _IO(0xCF, 2)
-int cifs_ioctl (struct inode * inode, struct file * filep,
+int cifs_ioctl (struct inode *inode, struct file *filep,
unsigned int command, unsigned long arg)
{
int rc = -ENOTTY; /* strange error - but the precedent */
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 6baea85d726e..6a85ef7b8797 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -50,32 +50,33 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
fromName = build_path_from_dentry(old_file);
toName = build_path_from_dentry(direntry);
- if((fromName == NULL) || (toName == NULL)) {
+ if ((fromName == NULL) || (toName == NULL)) {
rc = -ENOMEM;
goto cifs_hl_exit;
}
- if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
+/* if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)*/
+ if (pTcon->unix_ext)
rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
- cifs_sb_target->local_nls,
+ cifs_sb_target->local_nls,
cifs_sb_target->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
else {
rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
- cifs_sb_target->local_nls,
+ cifs_sb_target->local_nls,
cifs_sb_target->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if((rc == -EIO) || (rc == -EINVAL))
- rc = -EOPNOTSUPP;
+ if ((rc == -EIO) || (rc == -EINVAL))
+ rc = -EOPNOTSUPP;
}
d_drop(direntry); /* force new lookup from server of target */
/* if source file is cached (oplocked) revalidate will not go to server
until the file is closed or oplock broken so update nlinks locally */
- if(old_file->d_inode) {
+ if (old_file->d_inode) {
cifsInode = CIFS_I(old_file->d_inode);
- if(rc == 0) {
+ if (rc == 0) {
old_file->d_inode->i_nlink++;
/* BB should we make this contingent on superblock flag NOATIME? */
/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
@@ -84,14 +85,14 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
to set the parent dir cifs inode time to zero
to force revalidate (faster) for it too? */
}
- /* if not oplocked will force revalidate to get info
+ /* if not oplocked will force revalidate to get info
on source file from srv */
cifsInode->time = 0;
- /* Will update parent dir timestamps from srv within a second.
+ /* Will update parent dir timestamps from srv within a second.
Would it really be worth it to set the parent dir (cifs
inode) time field to zero to force revalidate on parent
- directory faster ie
+ directory faster ie
CIFS_I(inode)->time = 0; */
}
@@ -109,7 +110,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
int rc = -EACCES;
int xid;
char *full_path = NULL;
- char * target_path = ERR_PTR(-ENOMEM);
+ char *target_path = ERR_PTR(-ENOMEM);
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
@@ -129,13 +130,19 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
goto out;
}
-/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+ /* We could change this to:
+ if (pTcon->unix_ext)
+ but there does not seem any point in refusing to
+ get symlink info if we can, even if unix extensions
+ turned off for this mount */
+
if (pTcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
target_path,
PATH_MAX-1,
cifs_sb->local_nls);
else {
+ /* BB add read reparse point symlink code here */
/* rc = CIFSSMBQueryReparseLinkInfo */
/* BB Add code to Query ReparsePoint info */
/* BB Add MAC style xsymlink check here if enabled */
@@ -176,7 +183,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
full_path = build_path_from_dentry(direntry);
- if(full_path == NULL) {
+ if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
@@ -185,19 +192,20 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
cFYI(1, ("symname is %s", symname));
/* BB what if DFS and this volume is on different share? BB */
- if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
+ if (pTcon->unix_ext)
rc = CIFSUnixCreateSymLink(xid, pTcon, full_path, symname,
cifs_sb->local_nls);
/* else
- rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,cifs_sb_target->local_nls); */
+ rc = CIFSCreateReparseSymLink(xid, pTcon, fromName, toName,
+ cifs_sb_target->local_nls); */
if (rc == 0) {
- if (pTcon->ses->capabilities & CAP_UNIX)
+ if (pTcon->unix_ext)
rc = cifs_get_inode_info_unix(&newinode, full_path,
- inode->i_sb,xid);
+ inode->i_sb, xid);
else
rc = cifs_get_inode_info(&newinode, full_path, NULL,
- inode->i_sb,xid);
+ inode->i_sb, xid);
if (rc != 0) {
cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d",
@@ -226,9 +234,9 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
- char *tmp_path = NULL;
- char * tmpbuffer;
- unsigned char * referrals = NULL;
+ char *tmp_path = NULL;
+ char *tmpbuffer;
+ unsigned char *referrals = NULL;
int num_referrals = 0;
int len;
__u16 fid;
@@ -237,13 +245,13 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
-/* BB would it be safe against deadlock to grab this sem
+/* BB would it be safe against deadlock to grab this sem
even though rename itself grabs the sem and calls lookup? */
/* mutex_lock(&inode->i_sb->s_vfs_rename_mutex);*/
full_path = build_path_from_dentry(direntry);
/* mutex_unlock(&inode->i_sb->s_vfs_rename_mutex);*/
- if(full_path == NULL) {
+ if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
@@ -251,70 +259,80 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
cFYI(1,
("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
full_path, inode, pBuffer, buflen));
- if(buflen > PATH_MAX)
+ if (buflen > PATH_MAX)
len = PATH_MAX;
else
len = buflen;
- tmpbuffer = kmalloc(len,GFP_KERNEL);
- if(tmpbuffer == NULL) {
+ tmpbuffer = kmalloc(len, GFP_KERNEL);
+ if (tmpbuffer == NULL) {
kfree(full_path);
FreeXid(xid);
return -ENOMEM;
}
-/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
+/* BB add read reparse point symlink code and
+ Unix extensions symlink code here BB */
+/* We could disable this based on pTcon->unix_ext flag instead ... but why? */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
tmpbuffer,
len - 1,
cifs_sb->local_nls);
else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
- cERROR(1,("SFU style symlinks not implemented yet"));
+ cERROR(1, ("SFU style symlinks not implemented yet"));
/* add open and read as in fs/cifs/inode.c */
-
} else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
- OPEN_REPARSE_POINT,&fid, &oplock, NULL,
- cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ OPEN_REPARSE_POINT, &fid, &oplock, NULL,
+ cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- if(!rc) {
+ if (!rc) {
rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
tmpbuffer,
- len - 1,
+ len - 1,
fid,
cifs_sb->local_nls);
- if(CIFSSMBClose(xid, pTcon, fid)) {
- cFYI(1,("Error closing junction point (open for ioctl)"));
+ if (CIFSSMBClose(xid, pTcon, fid)) {
+ cFYI(1, ("Error closing junction point "
+ "(open for ioctl)"));
}
- if(rc == -EIO) {
+ if (rc == -EIO) {
/* Query if DFS Junction */
tmp_path =
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
GFP_KERNEL);
if (tmp_path) {
- strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
- strncat(tmp_path, full_path, MAX_PATHCONF);
- rc = get_dfs_path(xid, pTcon->ses, tmp_path,
+ strncpy(tmp_path, pTcon->treeName,
+ MAX_TREE_SIZE);
+ strncat(tmp_path, full_path,
+ MAX_PATHCONF);
+ rc = get_dfs_path(xid, pTcon->ses,
+ tmp_path,
cifs_sb->local_nls,
&num_referrals, &referrals,
cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
- if((num_referrals == 0) && (rc == 0))
+ cFYI(1, ("Get DFS for %s rc = %d ",
+ tmp_path, rc));
+ if ((num_referrals == 0) && (rc == 0))
rc = -EACCES;
else {
- cFYI(1,("num referral: %d",num_referrals));
- if(referrals) {
- cFYI(1,("referral string: %s",referrals));
- strncpy(tmpbuffer, referrals, len-1);
+ cFYI(1, ("num referral: %d",
+ num_referrals));
+ if (referrals) {
+ cFYI(1,("referral string: %s", referrals));
+ strncpy(tmpbuffer,
+ referrals,
+ len-1);
}
}
kfree(referrals);
kfree(tmp_path);
}
- /* BB add code like else decode referrals then memcpy to
- tmpbuffer and free referrals string array BB */
+ /* BB add code like else decode referrals
+ then memcpy to tmpbuffer and free referrals
+ string array BB */
}
}
}
diff --git a/fs/cifs/md4.c b/fs/cifs/md4.c
index 46d62c9dda0f..a2415c1a14db 100644
--- a/fs/cifs/md4.c
+++ b/fs/cifs/md4.c
@@ -1,20 +1,20 @@
-/*
+/*
Unix SMB/Netbios implementation.
Version 1.9.
a implementation of MD4 designed for use in the SMB authentication protocol
Copyright (C) Andrew Tridgell 1997-1998.
Modified by Steve French (sfrench@us.ibm.com) 2002-2003
-
+
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.
@@ -170,7 +170,7 @@ mdfour(unsigned char *out, unsigned char *in, int n)
while (n > 64) {
copy64(M, in);
- mdfour64(M,&A,&B, &C, &D);
+ mdfour64(M, &A, &B, &C, &D);
in += 64;
n -= 64;
}
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
index ccebf9b7eb86..e5c3e1212697 100644
--- a/fs/cifs/md5.c
+++ b/fs/cifs/md5.c
@@ -15,9 +15,9 @@
* will fill a supplied 16-byte array with the digest.
*/
-/* This code slightly modified to fit into Samba by
- abartlet@samba.org Jun 2001
- and to fit the cifs vfs by
+/* This code slightly modified to fit into Samba by
+ abartlet@samba.org Jun 2001
+ and to fit the cifs vfs by
Steve French sfrench@us.ibm.com */
#include <linux/string.h>
@@ -106,7 +106,7 @@ MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
}
/*
- * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
void
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 19cc294c7c70..0bcec0844bee 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/misc.c
*
- * Copyright (C) International Business Machines Corp., 2002,2005
+ * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/slab.h>
@@ -32,12 +32,12 @@
extern mempool_t *cifs_sm_req_poolp;
extern mempool_t *cifs_req_poolp;
-extern struct task_struct * oplockThread;
+extern struct task_struct *oplockThread;
-/* The xid serves as a useful identifier for each incoming vfs request,
- in a similar way to the mid which is useful to track each sent smb,
- and CurrentXid can also provide a running counter (although it
- will eventually wrap past zero) of the total vfs operations handled
+/* The xid serves as a useful identifier for each incoming vfs request,
+ in a similar way to the mid which is useful to track each sent smb,
+ and CurrentXid can also provide a running counter (although it
+ will eventually wrap past zero) of the total vfs operations handled
since the cifs fs was mounted */
unsigned int
@@ -47,10 +47,12 @@ _GetXid(void)
spin_lock(&GlobalMid_Lock);
GlobalTotalActiveXid++;
+
+ /* keep high water mark for number of simultaneous ops in filesystem */
if (GlobalTotalActiveXid > GlobalMaxActiveXid)
- GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */
- if(GlobalTotalActiveXid > 65000)
- cFYI(1,("warning: more than 65000 requests active"));
+ GlobalMaxActiveXid = GlobalTotalActiveXid;
+ if (GlobalTotalActiveXid > 65000)
+ cFYI(1, ("warning: more than 65000 requests active"));
xid = GlobalCurrentXid++;
spin_unlock(&GlobalMid_Lock);
return xid;
@@ -60,7 +62,7 @@ void
_FreeXid(unsigned int xid)
{
spin_lock(&GlobalMid_Lock);
- /* if(GlobalTotalActiveXid == 0)
+ /* if (GlobalTotalActiveXid == 0)
BUG(); */
GlobalTotalActiveXid--;
spin_unlock(&GlobalMid_Lock);
@@ -144,12 +146,12 @@ cifs_buf_get(void)
{
struct smb_hdr *ret_buf = NULL;
-/* We could use negotiated size instead of max_msgsize -
- but it may be more efficient to always alloc same size
- albeit slightly larger than necessary and maxbuffersize
+/* We could use negotiated size instead of max_msgsize -
+ but it may be more efficient to always alloc same size
+ albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
- ret_buf =
- (struct smb_hdr *) mempool_alloc(cifs_req_poolp, GFP_KERNEL | GFP_NOFS);
+ ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp,
+ GFP_KERNEL | GFP_NOFS);
/* clear the first few header bytes */
/* for most paths, more is cleared in header_assemble */
@@ -172,7 +174,7 @@ cifs_buf_release(void *buf_to_free)
/* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/
return;
}
- mempool_free(buf_to_free,cifs_req_poolp);
+ mempool_free(buf_to_free, cifs_req_poolp);
atomic_dec(&bufAllocCount);
return;
@@ -183,12 +185,12 @@ cifs_small_buf_get(void)
{
struct smb_hdr *ret_buf = NULL;
-/* We could use negotiated size instead of max_msgsize -
- but it may be more efficient to always alloc same size
- albeit slightly larger than necessary and maxbuffersize
+/* We could use negotiated size instead of max_msgsize -
+ but it may be more efficient to always alloc same size
+ albeit slightly larger than necessary and maxbuffersize
defaults to this and can not be bigger */
- ret_buf =
- (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp, GFP_KERNEL | GFP_NOFS);
+ ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp,
+ GFP_KERNEL | GFP_NOFS);
if (ret_buf) {
/* No need to clear memory here, cleared in header assemble */
/* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/
@@ -209,30 +211,30 @@ cifs_small_buf_release(void *buf_to_free)
cFYI(1, ("Null buffer passed to cifs_small_buf_release"));
return;
}
- mempool_free(buf_to_free,cifs_sm_req_poolp);
+ mempool_free(buf_to_free, cifs_sm_req_poolp);
atomic_dec(&smBufAllocCount);
return;
}
-/*
+/*
Find a free multiplex id (SMB mid). Otherwise there could be
mid collisions which might cause problems, demultiplexing the
wrong response to this request. Multiplex ids could collide if
one of a series requests takes much longer than the others, or
if a very large number of long lived requests (byte range
locks or FindNotify requests) are pending. No more than
- 64K-1 requests can be outstanding at one time. If no
+ 64K-1 requests can be outstanding at one time. If no
mids are available, return zero. A future optimization
could make the combination of mids and uid the key we use
- to demultiplex on (rather than mid alone).
+ to demultiplex on (rather than mid alone).
In addition to the above check, the cifs demultiplex
code already used the command code as a secondary
check of the frame and if signing is negotiated the
response would be discarded if the mid were the same
but the signature was wrong. Since the mid is not put in the
pending queue until later (when it is about to be dispatched)
- we do have to limit the number of outstanding requests
+ we do have to limit the number of outstanding requests
to somewhat less than 64K-1 although it is hard to imagine
so many threads being in the vfs at one time.
*/
@@ -240,27 +242,27 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
{
__u16 mid = 0;
__u16 last_mid;
- int collision;
+ int collision;
- if(server == NULL)
+ if (server == NULL)
return mid;
spin_lock(&GlobalMid_Lock);
last_mid = server->CurrentMid; /* we do not want to loop forever */
server->CurrentMid++;
/* This nested loop looks more expensive than it is.
- In practice the list of pending requests is short,
+ In practice the list of pending requests is short,
fewer than 50, and the mids are likely to be unique
on the first pass through the loop unless some request
takes longer than the 64 thousand requests before it
(and it would also have to have been a request that
did not time out) */
- while(server->CurrentMid != last_mid) {
+ while (server->CurrentMid != last_mid) {
struct list_head *tmp;
struct mid_q_entry *mid_entry;
collision = 0;
- if(server->CurrentMid == 0)
+ if (server->CurrentMid == 0)
server->CurrentMid++;
list_for_each(tmp, &server->pending_mid_q) {
@@ -273,7 +275,7 @@ __u16 GetNextMid(struct TCP_Server_Info *server)
break;
}
}
- if(collision == 0) {
+ if (collision == 0) {
mid = server->CurrentMid;
break;
}
@@ -290,11 +292,11 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
const struct cifsTconInfo *treeCon, int word_count
/* length of fixed section (word count) in two byte units */)
{
- struct list_head* temp_item;
- struct cifsSesInfo * ses;
+ struct list_head *temp_item;
+ struct cifsSesInfo *ses;
char *temp = (char *) buffer;
- memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */
+ memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */
buffer->smb_buf_length =
(2 * word_count) + sizeof (struct smb_hdr) -
@@ -325,7 +327,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
/* Uid is not converted */
buffer->Uid = treeCon->ses->Suid;
buffer->Mid = GetNextMid(treeCon->ses->server);
- if(multiuser_mount != 0) {
+ if (multiuser_mount != 0) {
/* For the multiuser case, there are few obvious technically */
/* possible mechanisms to match the local linux user (uid) */
/* to a valid remote smb user (smb_uid): */
@@ -348,21 +350,22 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
/* flag were disabled. */
/* BB Add support for establishing new tCon and SMB Session */
- /* with userid/password pairs found on the smb session */
+ /* with userid/password pairs found on the smb session */
/* for other target tcp/ip addresses BB */
- if(current->fsuid != treeCon->ses->linux_uid) {
- cFYI(1,("Multiuser mode and UID did not match tcon uid"));
+ if (current->fsuid != treeCon->ses->linux_uid) {
+ cFYI(1, ("Multiuser mode and UID "
+ "did not match tcon uid"));
read_lock(&GlobalSMBSeslock);
list_for_each(temp_item, &GlobalSMBSessionList) {
ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);
- if(ses->linux_uid == current->fsuid) {
- if(ses->server == treeCon->ses->server) {
- cFYI(1,("found matching uid substitute right smb_uid"));
+ if (ses->linux_uid == current->fsuid) {
+ if (ses->server == treeCon->ses->server) {
+ cFYI(1, ("found matching uid substitute right smb_uid"));
buffer->Uid = ses->Suid;
break;
} else {
- /* BB eventually call cifs_setup_session here */
- cFYI(1,("local UID found but smb sess with this server does not exist"));
+ /* BB eventually call cifs_setup_session here */
+ cFYI(1, ("local UID found but no smb sess with this server exists"));
}
}
}
@@ -374,8 +377,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
buffer->Flags2 |= SMBFLG2_DFS;
if (treeCon->nocase)
buffer->Flags |= SMBFLG_CASELESS;
- if((treeCon->ses) && (treeCon->ses->server))
- if(treeCon->ses->server->secMode &
+ if ((treeCon->ses) && (treeCon->ses->server))
+ if (treeCon->ses->server->secMode &
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
}
@@ -388,18 +391,18 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
static int
checkSMBhdr(struct smb_hdr *smb, __u16 mid)
{
- /* Make sure that this really is an SMB, that it is a response,
+ /* Make sure that this really is an SMB, that it is a response,
and that the message ids match */
- if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
- (mid == smb->Mid)) {
- if(smb->Flags & SMBFLG_RESPONSE)
- return 0;
- else {
+ if ((*(__le32 *) smb->Protocol == cpu_to_le32(0x424d53ff)) &&
+ (mid == smb->Mid)) {
+ if (smb->Flags & SMBFLG_RESPONSE)
+ return 0;
+ else {
/* only one valid case where server sends us request */
- if(smb->Command == SMB_COM_LOCKING_ANDX)
+ if (smb->Command == SMB_COM_LOCKING_ANDX)
return 0;
else
- cERROR(1, ("Rcvd Request not response"));
+ cERROR(1, ("Received Request not response"));
}
} else { /* bad signature or mid */
if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff))
@@ -426,9 +429,9 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
smb->WordCount = 0;
/* some error cases do not return wct and bcc */
return 0;
- } else if ((length == sizeof(struct smb_hdr) + 1) &&
+ } else if ((length == sizeof(struct smb_hdr) + 1) &&
(smb->WordCount == 0)) {
- char * tmp = (char *)smb;
+ char *tmp = (char *)smb;
/* Need to work around a bug in two servers here */
/* First, check if the part of bcc they sent was zero */
if (tmp[sizeof(struct smb_hdr)] == 0) {
@@ -442,7 +445,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
tmp[sizeof(struct smb_hdr)+1] = 0;
return 0;
}
- cERROR(1,("rcvd invalid byte count (bcc)"));
+ cERROR(1, ("rcvd invalid byte count (bcc)"));
} else {
cERROR(1, ("Length less than smb header size"));
}
@@ -458,32 +461,33 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
return 1;
clc_len = smbCalcSize_LE(smb);
- if(4 + len != length) {
- cERROR(1, ("Length read does not match RFC1001 length %d",len));
+ if (4 + len != length) {
+ cERROR(1, ("Length read does not match RFC1001 length %d",
+ len));
return 1;
}
if (4 + len != clc_len) {
/* check if bcc wrapped around for large read responses */
- if((len > 64 * 1024) && (len > clc_len)) {
+ if ((len > 64 * 1024) && (len > clc_len)) {
/* check if lengths match mod 64K */
- if(((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
- return 0; /* bcc wrapped */
+ if (((4 + len) & 0xFFFF) == (clc_len & 0xFFFF))
+ return 0; /* bcc wrapped */
}
cFYI(1, ("Calculated size %d vs length %d mismatch for mid %d",
clc_len, 4 + len, smb->Mid));
/* Windows XP can return a few bytes too much, presumably
- an illegal pad, at the end of byte range lock responses
+ an illegal pad, at the end of byte range lock responses
so we allow for that three byte pad, as long as actual
received length is as long or longer than calculated length */
- /* We have now had to extend this more, since there is a
+ /* We have now had to extend this more, since there is a
case in which it needs to be bigger still to handle a
malformed response to transact2 findfirst from WinXP when
access denied is returned and thus bcc and wct are zero
but server says length is 0x21 bytes too long as if the server
forget to reset the smb rfc1001 length when it reset the
wct and bcc to minimum size and drop the t2 parms and data */
- if((4+len > clc_len) && (len <= clc_len + 512))
+ if ((4+len > clc_len) && (len <= clc_len + 512))
return 0;
else {
cERROR(1, ("RFC1001 size %d bigger than SMB for Mid=%d",
@@ -495,61 +499,64 @@ checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
}
int
is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
-{
- struct smb_com_lock_req * pSMB = (struct smb_com_lock_req *)buf;
+{
+ struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf;
struct list_head *tmp;
struct list_head *tmp1;
struct cifsTconInfo *tcon;
struct cifsFileInfo *netfile;
- cFYI(1,("Checking for oplock break or dnotify response"));
- if((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
+ cFYI(1, ("Checking for oplock break or dnotify response"));
+ if ((pSMB->hdr.Command == SMB_COM_NT_TRANSACT) &&
(pSMB->hdr.Flags & SMBFLG_RESPONSE)) {
- struct smb_com_transaction_change_notify_rsp * pSMBr =
+ struct smb_com_transaction_change_notify_rsp *pSMBr =
(struct smb_com_transaction_change_notify_rsp *)buf;
- struct file_notify_information * pnotify;
+ struct file_notify_information *pnotify;
__u32 data_offset = 0;
- if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
+ if (pSMBr->ByteCount > sizeof(struct file_notify_information)) {
data_offset = le32_to_cpu(pSMBr->DataOffset);
pnotify = (struct file_notify_information *)
((char *)&pSMBr->hdr.Protocol + data_offset);
- cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
+ cFYI(1, ("dnotify on %s Action: 0x%x",
+ pnotify->FileName,
pnotify->Action)); /* BB removeme BB */
- /* cifs_dump_mem("Rcvd notify Data: ",buf,
+ /* cifs_dump_mem("Rcvd notify Data: ",buf,
sizeof(struct smb_hdr)+60); */
return TRUE;
}
- if(pSMBr->hdr.Status.CifsError) {
- cFYI(1,("notify err 0x%d",pSMBr->hdr.Status.CifsError));
+ if (pSMBr->hdr.Status.CifsError) {
+ cFYI(1, ("notify err 0x%d",
+ pSMBr->hdr.Status.CifsError));
return TRUE;
}
return FALSE;
- }
- if(pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
+ }
+ if (pSMB->hdr.Command != SMB_COM_LOCKING_ANDX)
return FALSE;
- if(pSMB->hdr.Flags & SMBFLG_RESPONSE) {
+ if (pSMB->hdr.Flags & SMBFLG_RESPONSE) {
/* no sense logging error on invalid handle on oplock
break - harmless race between close request and oplock
break response is expected from time to time writing out
large dirty files cached on the client */
- if ((NT_STATUS_INVALID_HANDLE) ==
- le32_to_cpu(pSMB->hdr.Status.CifsError)) {
- cFYI(1,("invalid handle on oplock break"));
+ if ((NT_STATUS_INVALID_HANDLE) ==
+ le32_to_cpu(pSMB->hdr.Status.CifsError)) {
+ cFYI(1, ("invalid handle on oplock break"));
return TRUE;
- } else if (ERRbadfid ==
+ } else if (ERRbadfid ==
le16_to_cpu(pSMB->hdr.Status.DosError.Error)) {
- return TRUE;
+ return TRUE;
} else {
return FALSE; /* on valid oplock brk we get "request" */
}
}
- if(pSMB->hdr.WordCount != 8)
+ if (pSMB->hdr.WordCount != 8)
return FALSE;
- cFYI(1,(" oplock type 0x%d level 0x%d",pSMB->LockType,pSMB->OplockLevel));
- if(!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
- return FALSE;
+ cFYI(1, ("oplock type 0x%d level 0x%d",
+ pSMB->LockType, pSMB->OplockLevel));
+ if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE))
+ return FALSE;
/* look up tcon based on tid & uid */
read_lock(&GlobalSMBSeslock);
@@ -557,36 +564,38 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) {
cifs_stats_inc(&tcon->num_oplock_brks);
- list_for_each(tmp1,&tcon->openFileList){
- netfile = list_entry(tmp1,struct cifsFileInfo,
+ list_for_each(tmp1, &tcon->openFileList) {
+ netfile = list_entry(tmp1, struct cifsFileInfo,
tlist);
- if(pSMB->Fid == netfile->netfid) {
+ if (pSMB->Fid == netfile->netfid) {
struct cifsInodeInfo *pCifsInode;
read_unlock(&GlobalSMBSeslock);
- cFYI(1,("file id match, oplock break"));
- pCifsInode =
+ cFYI(1,
+ ("file id match, oplock break"));
+ pCifsInode =
CIFS_I(netfile->pInode);
pCifsInode->clientCanCacheAll = FALSE;
- if(pSMB->OplockLevel == 0)
+ if (pSMB->OplockLevel == 0)
pCifsInode->clientCanCacheRead
= FALSE;
pCifsInode->oplockPending = TRUE;
AllocOplockQEntry(netfile->pInode,
netfile->netfid,
tcon);
- cFYI(1,("about to wake up oplock thd"));
- if(oplockThread)
+ cFYI(1,
+ ("about to wake up oplock thread"));
+ if (oplockThread)
wake_up_process(oplockThread);
return TRUE;
}
}
read_unlock(&GlobalSMBSeslock);
- cFYI(1,("No matching file for oplock break"));
+ cFYI(1, ("No matching file for oplock break"));
return TRUE;
}
}
read_unlock(&GlobalSMBSeslock);
- cFYI(1,("Can not process oplock break for non-existent connection"));
+ cFYI(1, ("Can not process oplock break for non-existent connection"));
return TRUE;
}
@@ -643,13 +652,13 @@ dump_smb(struct smb_hdr *smb_buf, int smb_buf_length)
only legal in POSIX-like OS (if they are present in the string). Path
names are little endian 16 bit Unicode on the wire */
int
-cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
- const struct nls_table * cp)
+cifs_convertUCSpath(char *target, const __le16 *source, int maxlen,
+ const struct nls_table *cp)
{
- int i,j,len;
+ int i, j, len;
__u16 src_char;
- for(i = 0, j = 0; i < maxlen; i++) {
+ for (i = 0, j = 0; i < maxlen; i++) {
src_char = le16_to_cpu(source[i]);
switch (src_char) {
case 0:
@@ -678,10 +687,10 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
case UNI_LESSTHAN:
target[j] = '<';
break;
- default:
- len = cp->uni2char(src_char, &target[j],
+ default:
+ len = cp->uni2char(src_char, &target[j],
NLS_MAX_CHARSET_SIZE);
- if(len > 0) {
+ if (len > 0) {
j += len;
continue;
} else {
@@ -690,7 +699,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen,
}
j++;
/* make sure we do not overrun callers allocated temp buffer */
- if(j >= (2 * NAME_MAX))
+ if (j >= (2 * NAME_MAX))
break;
}
cUCS_out:
@@ -703,18 +712,18 @@ cUCS_out:
only legal in POSIX-like OS (if they are present in the string). Path
names are little endian 16 bit Unicode on the wire */
int
-cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
- const struct nls_table * cp, int mapChars)
+cifsConvertToUCS(__le16 *target, const char *source, int maxlen,
+ const struct nls_table *cp, int mapChars)
{
- int i,j,charlen;
+ int i, j, charlen;
int len_remaining = maxlen;
char src_char;
__u16 temp;
- if(!mapChars)
+ if (!mapChars)
return cifs_strtoUCS(target, source, PATH_MAX, cp);
- for(i = 0, j = 0; i < maxlen; j++) {
+ for (i = 0, j = 0; i < maxlen; j++) {
src_char = source[i];
switch (src_char) {
case 0:
@@ -737,7 +746,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
break;
case '|':
target[j] = cpu_to_le16(UNI_PIPE);
- break;
+ break;
/* BB We can not handle remapping slash until
all the calls to build_path_from_dentry
are modified, as they use slash as separator BB */
@@ -749,7 +758,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
len_remaining, &temp);
/* if no match, use question mark, which
at least in some cases servers as wild card */
- if(charlen < 1) {
+ if (charlen < 1) {
target[j] = cpu_to_le16(0x003f);
charlen = 1;
} else
@@ -758,7 +767,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen,
/* character may take more than one byte in the
the source string, but will take exactly two
bytes in the target string */
- i+= charlen;
+ i += charlen;
continue;
}
i++; /* move to next char in source string */
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index 53e304d59544..2bfed3f45d0f 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -3,23 +3,22 @@
*
* Copyright (c) International Business Machines Corp., 2002
* Author(s): Steve French (sfrench@us.ibm.com)
- *
+ *
* Error mapping routines from Samba libsmb/errormap.c
* Copyright (C) Andrew Tridgell 2001
*
- *
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -30,9 +29,7 @@
#include <linux/fs.h>
#include <asm/div64.h>
#include <asm/byteorder.h>
-#ifdef CONFIG_CIFS_EXPERIMENTAL
#include <linux/inet.h>
-#endif
#include "cifsfs.h"
#include "cifspdu.h"
#include "cifsglob.h"
@@ -67,22 +64,22 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
{ERRbadshare, -ETXTBSY},
{ERRlock, -EACCES},
{ERRunsup, -EINVAL},
- {ERRnosuchshare,-ENXIO},
+ {ERRnosuchshare, -ENXIO},
{ERRfilexists, -EEXIST},
{ERRinvparm, -EINVAL},
{ERRdiskfull, -ENOSPC},
{ERRinvname, -ENOENT},
- {ERRinvlevel,-EOPNOTSUPP},
+ {ERRinvlevel, -EOPNOTSUPP},
{ERRdirnotempty, -ENOTEMPTY},
{ERRnotlocked, -ENOLCK},
{ERRcancelviolation, -ENOLCK},
{ERRalreadyexists, -EEXIST},
{ERRmoredata, -EOVERFLOW},
- {ERReasnotsupported,-EOPNOTSUPP},
+ {ERReasnotsupported, -EOPNOTSUPP},
{ErrQuota, -EDQUOT},
{ErrNotALink, -ENOLINK},
- {ERRnetlogonNotStarted,-ENOPROTOOPT},
- {ErrTooManyLinks,-EMLINK},
+ {ERRnetlogonNotStarted, -ENOPROTOOPT},
+ {ErrTooManyLinks, -EMLINK},
{0, 0}
};
@@ -133,85 +130,24 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
/* returns 0 if invalid address */
int
-cifs_inet_pton(int address_family, char *cp,void *dst)
+cifs_inet_pton(int address_family, char *cp, void *dst)
{
-#ifdef CONFIG_CIFS_EXPERIMENTAL
int ret = 0;
/* calculate length by finding first slash or NULL */
- /* BB Should we convert '/' slash to '\' here since it seems already done
- before this */
- if( address_family == AF_INET ){
- ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);
- } else if( address_family == AF_INET6 ){
+ /* BB Should we convert '/' slash to '\' here since it seems already
+ * done before this */
+ if ( address_family == AF_INET ) {
+ ret = in4_pton(cp, -1 /* len */, dst , '\\', NULL);
+ } else if ( address_family == AF_INET6 ) {
ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL);
}
#ifdef CONFIG_CIFS_DEBUG2
- cFYI(1,("address conversion returned %d for %s", ret, cp));
+ cFYI(1, ("address conversion returned %d for %s", ret, cp));
#endif
if (ret > 0)
ret = 1;
return ret;
-#else
- int value;
- int digit;
- int i;
- char temp;
- char bytes[4];
- char *end = bytes;
- static const int addr_class_max[4] =
- { 0xffffffff, 0xffffff, 0xffff, 0xff };
-
- if(address_family != AF_INET)
- return -EAFNOSUPPORT;
-
- for (i = 0; i < 4; i++) {
- bytes[i] = 0;
- }
-
- temp = *cp;
-
- while (TRUE) {
- if (!isdigit(temp))
- return 0;
-
- value = 0;
- digit = 0;
- for (;;) {
- if (isascii(temp) && isdigit(temp)) {
- value = (value * 10) + temp - '0';
- temp = *++cp;
- digit = 1;
- } else
- break;
- }
-
- if (temp == '.') {
- if ((end > bytes + 2) || (value > 255))
- return 0;
- *end++ = value;
- temp = *++cp;
- } else if (temp == ':') {
- cFYI(1,("IPv6 addresses not supported for CIFS mounts yet"));
- return -1;
- } else
- break;
- }
-
- /* check for last characters */
- if (temp != '\0' && (!isascii(temp) || !isspace(temp)))
- if (temp != '\\') {
- if (temp != '/')
- return 0;
- else
- (*cp = '\\'); /* switch the slash the expected way */
- }
- if (value > addr_class_max[end - bytes])
- return 0;
-
- *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value);
- return 1; /* success */
-#endif /* EXPERIMENTAL */
}
/*****************************************************************************
@@ -246,7 +182,7 @@ static const struct {
ERRHRD, ERRgeneral, NT_STATUS_UNRECOGNIZED_MEDIA}, {
ERRDOS, 27, NT_STATUS_NONEXISTENT_SECTOR},
/* { This NT error code was 'sqashed'
- from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
+ from NT_STATUS_MORE_PROCESSING_REQUIRED to NT_STATUS_OK
during the session setup } */
{
ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY}, {
@@ -261,7 +197,7 @@ static const struct {
ERRDOS, 193, NT_STATUS_INVALID_FILE_FOR_SECTION}, {
ERRDOS, ERRnoaccess, NT_STATUS_ALREADY_COMMITTED},
/* { This NT error code was 'sqashed'
- from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
+ from NT_STATUS_ACCESS_DENIED to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
during the session setup } */
{
ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED}, {
@@ -331,7 +267,7 @@ static const struct {
ERRHRD, ERRgeneral, NT_STATUS_INVALID_ACCOUNT_NAME}, {
ERRHRD, ERRgeneral, NT_STATUS_USER_EXISTS},
/* { This NT error code was 'sqashed'
- from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
+ from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE
during the session setup } */
{
ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, {
@@ -341,7 +277,7 @@ static const struct {
ERRHRD, ERRgeneral, NT_STATUS_MEMBER_NOT_IN_GROUP}, {
ERRHRD, ERRgeneral, NT_STATUS_LAST_ADMIN},
/* { This NT error code was 'sqashed'
- from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
+ from NT_STATUS_WRONG_PASSWORD to NT_STATUS_LOGON_FAILURE
during the session setup } */
{
ERRSRV, ERRbadpw, NT_STATUS_WRONG_PASSWORD}, {
@@ -393,8 +329,8 @@ static const struct {
ERRHRD, ERRgeneral, NT_STATUS_FILE_INVALID}, {
ERRHRD, ERRgeneral, NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
/* { This NT error code was 'sqashed'
- from NT_STATUS_INSUFFICIENT_RESOURCES to NT_STATUS_INSUFF_SERVER_RESOURCES
- during the session setup } */
+ from NT_STATUS_INSUFFICIENT_RESOURCES to
+ NT_STATUS_INSUFF_SERVER_RESOURCES during the session setup } */
{
ERRDOS, ERRnomem, NT_STATUS_INSUFFICIENT_RESOURCES}, {
ERRDOS, ERRbadpath, NT_STATUS_DFS_EXIT_PATH_FOUND}, {
@@ -638,8 +574,8 @@ static const struct {
ERRDOS, 19, NT_STATUS_TOO_LATE}, {
ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_LSA_SECRET},
/* { This NT error code was 'sqashed'
- from NT_STATUS_NO_TRUST_SAM_ACCOUNT to NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE
- during the session setup } */
+ from NT_STATUS_NO_TRUST_SAM_ACCOUNT to
+ NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE during the session setup } */
{
ERRDOS, ERRnoaccess, NT_STATUS_NO_TRUST_SAM_ACCOUNT}, {
ERRDOS, ERRnoaccess, NT_STATUS_TRUSTED_DOMAIN_FAILURE}, {
@@ -658,7 +594,7 @@ static const struct {
ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, {
ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
/* { This NT error code was 'sqashed'
- from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
+ from NT_STATUS_DOMAIN_TRUST_INCONSISTENT to NT_STATUS_LOGON_FAILURE
during the session setup } */
{
ERRDOS, ERRnoaccess, NT_STATUS_DOMAIN_TRUST_INCONSISTENT}, {
@@ -789,7 +725,7 @@ cifs_print_status(__u32 status_code)
if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==
(status_code & 0xFFFFFF)) {
printk(KERN_NOTICE "Status code returned 0x%08x %s\n",
- status_code,nt_errs[idx].nt_errstr);
+ status_code, nt_errs[idx].nt_errstr);
}
idx++;
}
@@ -821,7 +757,7 @@ int
map_smb_to_linux_error(struct smb_hdr *smb)
{
unsigned int i;
- int rc = -EIO; /* if transport error smb error may not be set */
+ int rc = -EIO; /* if transport error smb error may not be set */
__u8 smberrclass;
__u16 smberrcode;
@@ -832,9 +768,10 @@ map_smb_to_linux_error(struct smb_hdr *smb)
return 0;
if (smb->Flags2 & SMBFLG2_ERR_STATUS) {
- /* translate the newer STATUS codes to old style errors and then to POSIX errors */
+ /* translate the newer STATUS codes to old style SMB errors
+ * and then to POSIX errors */
__u32 err = le32_to_cpu(smb->Status.CifsError);
- if(cifsFYI & CIFS_RC)
+ if (cifsFYI & CIFS_RC)
cifs_print_status(err);
ntstatus_to_dos(err, &smberrclass, &smberrcode);
} else {
@@ -845,38 +782,42 @@ map_smb_to_linux_error(struct smb_hdr *smb)
/* old style errors */
/* DOS class smb error codes - map DOS */
- if (smberrclass == ERRDOS) { /* one byte field no need to byte reverse */
+ if (smberrclass == ERRDOS) { /* 1 byte field no need to byte reverse */
for (i = 0;
i <
sizeof (mapping_table_ERRDOS) /
sizeof (struct smb_to_posix_error); i++) {
if (mapping_table_ERRDOS[i].smb_err == 0)
break;
- else if (mapping_table_ERRDOS[i].smb_err == smberrcode) {
+ else if (mapping_table_ERRDOS[i].smb_err ==
+ smberrcode) {
rc = mapping_table_ERRDOS[i].posix_code;
break;
}
- /* else try the next error mapping one to see if it will match */
+ /* else try next error mapping one to see if match */
}
- } else if (smberrclass == ERRSRV) { /* server class of error codes */
+ } else if (smberrclass == ERRSRV) { /* server class of error codes */
for (i = 0;
i <
sizeof (mapping_table_ERRSRV) /
sizeof (struct smb_to_posix_error); i++) {
if (mapping_table_ERRSRV[i].smb_err == 0)
break;
- else if (mapping_table_ERRSRV[i].smb_err == smberrcode) {
+ else if (mapping_table_ERRSRV[i].smb_err ==
+ smberrcode) {
rc = mapping_table_ERRSRV[i].posix_code;
break;
}
- /* else try the next error mapping one to see if it will match */
+ /* else try next error mapping to see if match */
}
}
/* else ERRHRD class errors or junk - return EIO */
- cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", smberrcode,rc));
+ cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!",
+ smberrcode, rc));
- /* generic corrective action e.g. reconnect SMB session on ERRbaduid could be added */
+ /* generic corrective action e.g. reconnect SMB session on
+ * ERRbaduid could be added */
return rc;
}
@@ -910,7 +851,7 @@ smbCalcSize_LE(struct smb_hdr *ptr)
struct timespec
cifs_NTtimeToUnix(u64 ntutc)
{
- struct timespec ts;
+ struct timespec ts;
/* BB what about the timezone? BB */
/* Subtract the NTFS time offset, then convert to 1s intervals. */
@@ -918,7 +859,7 @@ cifs_NTtimeToUnix(u64 ntutc)
t = ntutc - NTFS_TIME_OFFSET;
ts.tv_nsec = do_div(t, 10000000) * 100;
- ts.tv_sec = t;
+ ts.tv_sec = t;
return ts;
}
@@ -946,20 +887,20 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
SMB_TIME * st = (SMB_TIME *)&time;
SMB_DATE * sd = (SMB_DATE *)&date;
- cFYI(1,("date %d time %d",date, time));
+ cFYI(1, ("date %d time %d", date, time));
sec = 2 * st->TwoSeconds;
min = st->Minutes;
- if((sec > 59) || (min > 59))
- cERROR(1,("illegal time min %d sec %d", min, sec));
+ if ((sec > 59) || (min > 59))
+ cERROR(1, ("illegal time min %d sec %d", min, sec));
sec += (min * 60);
sec += 60 * 60 * st->Hours;
- if(st->Hours > 24)
- cERROR(1,("illegal hours %d",st->Hours));
+ if (st->Hours > 24)
+ cERROR(1, ("illegal hours %d", st->Hours));
days = sd->Day;
month = sd->Month;
- if((days > 31) || (month > 12))
- cERROR(1,("illegal date, month %d day: %d", month, days));
+ if ((days > 31) || (month > 12))
+ cERROR(1, ("illegal date, month %d day: %d", month, days));
month -= 1;
days += total_days_of_prev_months[month];
days += 3652; /* account for difference in days between 1980 and 1970 */
@@ -970,15 +911,15 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
for years/100 except for years/400, but since the maximum number for DOS
year is 2**7, the last year is 1980+127, which means we need only
consider 2 special case years, ie the years 2000 and 2100, and only
- adjust for the lack of leap year for the year 2100, as 2000 was a
+ adjust for the lack of leap year for the year 2100, as 2000 was a
leap year (divisable by 400) */
- if(year >= 120) /* the year 2100 */
+ if (year >= 120) /* the year 2100 */
days = days - 1; /* do not count leap year for the year 2100 */
/* adjust for leap year where we are still before leap day */
- if(year != 120)
+ if (year != 120)
days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
- sec += 24 * 60 * 60 * days;
+ sec += 24 * 60 * 60 * days;
ts.tv_sec = sec;
@@ -986,4 +927,4 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
ts.tv_nsec = 0;
return ts;
-}
+}
diff --git a/fs/cifs/nterr.c b/fs/cifs/nterr.c
index 4da50cd34469..819fd994b121 100644
--- a/fs/cifs/nterr.c
+++ b/fs/cifs/nterr.c
@@ -1,19 +1,19 @@
-/*
+/*
* Unix SMB/Netbios implementation.
* Version 1.9.
* RPC Pipe client / server routines
* Copyright (C) Luke Kenneth Casson Leighton 1997-2001.
- *
+ *
* 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.
diff --git a/fs/cifs/nterr.h b/fs/cifs/nterr.h
index d2fb06c97dfa..588abbb9d08c 100644
--- a/fs/cifs/nterr.h
+++ b/fs/cifs/nterr.h
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/Netbios implementation.
Version 1.9.
NT error code constants
@@ -6,17 +6,17 @@
Copyright (C) John H Terpstra 1996-2000
Copyright (C) Luke Kenneth Casson Leighton 1996-2000
Copyright (C) Paul Ashton 1998-2000
-
+
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.
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h
index d39b712a11c5..7170a9b70f1e 100644
--- a/fs/cifs/ntlmssp.h
+++ b/fs/cifs/ntlmssp.h
@@ -1,7 +1,7 @@
/*
* fs/cifs/ntlmssp.h
*
- * Copyright (c) International Business Machines Corp., 2002,2006
+ * Copyright (c) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -16,7 +16,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define NTLMSSP_SIGNATURE "NTLMSSP"
@@ -27,18 +27,18 @@
#define UnknownMessage cpu_to_le32(8)
/* Negotiate Flags */
-#define NTLMSSP_NEGOTIATE_UNICODE 0x01 // Text strings are in unicode
-#define NTLMSSP_NEGOTIATE_OEM 0x02 // Text strings are in OEM
-#define NTLMSSP_REQUEST_TARGET 0x04 // Server return its auth realm
-#define NTLMSSP_NEGOTIATE_SIGN 0x0010 // Request signature capability
-#define NTLMSSP_NEGOTIATE_SEAL 0x0020 // Request confidentiality
+#define NTLMSSP_NEGOTIATE_UNICODE 0x01 /* Text strings are in unicode */
+#define NTLMSSP_NEGOTIATE_OEM 0x02 /* Text strings are in OEM */
+#define NTLMSSP_REQUEST_TARGET 0x04 /* Server return its auth realm */
+#define NTLMSSP_NEGOTIATE_SIGN 0x0010 /* Request signature capability */
+#define NTLMSSP_NEGOTIATE_SEAL 0x0020 /* Request confidentiality */
#define NTLMSSP_NEGOTIATE_DGRAM 0x0040
-#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 // Use LM session key for sign/seal
-#define NTLMSSP_NEGOTIATE_NTLM 0x0200 // NTLM authentication
+#define NTLMSSP_NEGOTIATE_LM_KEY 0x0080 /* Sign/seal use LM session key */
+#define NTLMSSP_NEGOTIATE_NTLM 0x0200 /* NTLM authentication */
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x1000
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x2000
-#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 // client/server on same machine
-#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 // Sign for all security levels
+#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x4000 /* client/server on same machine */
+#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x8000 /* Sign for all security levels */
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x10000
#define NTLMSSP_TARGET_TYPE_SERVER 0x20000
#define NTLMSSP_TARGET_TYPE_SHARE 0x40000
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index c08bda9fcac6..916df9431336 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -2,7 +2,7 @@
* fs/cifs/readdir.c
*
* Directory search handling
- *
+ *
* Copyright (C) International Business Machines Corp., 2004, 2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
@@ -34,24 +34,23 @@
#ifdef CONFIG_CIFS_DEBUG2
static void dump_cifs_file_struct(struct file *file, char *label)
{
- struct cifsFileInfo * cf;
+ struct cifsFileInfo *cf;
if (file) {
cf = file->private_data;
if (cf == NULL) {
- cFYI(1,("empty cifs private file data"));
+ cFYI(1, ("empty cifs private file data"));
return;
}
if (cf->invalidHandle) {
- cFYI(1,("invalid handle"));
+ cFYI(1, ("invalid handle"));
}
if (cf->srch_inf.endOfSearch) {
- cFYI(1,("end of search"));
+ cFYI(1, ("end of search"));
}
if (cf->srch_inf.emptyDir) {
- cFYI(1,("empty dir"));
+ cFYI(1, ("empty dir"));
}
-
}
}
#endif /* DEBUG2 */
@@ -73,7 +72,8 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
qstring->hash = full_name_hash(qstring->name, qstring->len);
tmp_dentry = d_lookup(file->f_path.dentry, qstring);
if (tmp_dentry) {
- cFYI(0, ("existing dentry with inode 0x%p", tmp_dentry->d_inode));
+ cFYI(0, ("existing dentry with inode 0x%p",
+ tmp_dentry->d_inode));
*ptmp_inode = tmp_dentry->d_inode;
/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
if (*ptmp_inode == NULL) {
@@ -87,7 +87,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
} else {
tmp_dentry = d_alloc(file->f_path.dentry, qstring);
if (tmp_dentry == NULL) {
- cERROR(1,("Failed allocating dentry"));
+ cERROR(1, ("Failed allocating dentry"));
*ptmp_inode = NULL;
return rc;
}
@@ -100,7 +100,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
if (*ptmp_inode == NULL)
return rc;
if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
- (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
+ (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
rc = 2;
}
@@ -109,7 +109,7 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
return rc;
}
-static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
+static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode)
{
if ((tcon) && (tcon->ses) && (tcon->ses->server)) {
inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
@@ -121,7 +121,7 @@ static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
- char * buf, int *pobject_type, int isNewInode)
+ char *buf, int *pobject_type, int isNewInode)
{
loff_t local_size;
struct timespec local_mtime;
@@ -150,7 +150,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
} else { /* legacy, OS2 and DOS style */
/* struct timespec ts;*/
- FIND_FILE_STANDARD_INFO * pfindData =
+ FIND_FILE_STANDARD_INFO * pfindData =
(FIND_FILE_STANDARD_INFO *)buf;
tmp_inode->i_mtime = cnvrtDosUnixTm(
@@ -175,7 +175,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
/* treat dos attribute of read-only as read-only mode bit e.g. 555? */
/* 2767 perms - indicate mandatory locking */
- /* BB fill in uid and gid here? with help from winbind?
+ /* BB fill in uid and gid here? with help from winbind?
or retrieve from NTFS stream extended attribute */
if (atomic_read(&cifsInfo->inUse) == 0) {
tmp_inode->i_uid = cifs_sb->mnt_uid;
@@ -196,7 +196,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
tmp_inode->i_mode = cifs_sb->mnt_dir_mode;
}
tmp_inode->i_mode |= S_IFDIR;
- } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
+ } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) &&
(attr & ATTR_SYSTEM)) {
if (end_of_file == 0) {
*pobject_type = DT_FIFO;
@@ -206,13 +206,13 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
inode as needing revalidate and get the real type
(blk vs chr vs. symlink) later ie in lookup */
*pobject_type = DT_REG;
- tmp_inode->i_mode |= S_IFREG;
- cifsInfo->time = 0;
+ tmp_inode->i_mode |= S_IFREG;
+ cifsInfo->time = 0;
}
/* we no longer mark these because we could not follow them */
/* } else if (attr & ATTR_REPARSE) {
- *pobject_type = DT_LNK;
- tmp_inode->i_mode |= S_IFLNK; */
+ *pobject_type = DT_LNK;
+ tmp_inode->i_mode |= S_IFLNK; */
} else {
*pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG;
@@ -220,7 +220,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
tmp_inode->i_mode &= ~(S_IWUGO);
else if ((tmp_inode->i_mode & S_IWUGO) == 0)
/* the ATTR_READONLY flag may have been changed on */
- /* server -- set any w bits allowed by mnt_file_mode */
+ /* server -- set any w bits allowed by mnt_file_mode */
tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode);
} /* could add code here - to validate if device or weird share type? */
@@ -231,7 +231,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
- /* can not safely change the file size here if the
+ /* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(tmp_inode, end_of_file);
@@ -254,7 +254,6 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
tmp_inode->i_fop = &cifs_file_direct_nobrl_ops;
else
tmp_inode->i_fop = &cifs_file_direct_ops;
-
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL)
tmp_inode->i_fop = &cifs_file_nobrl_ops;
else
@@ -322,8 +321,8 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions);
/* since we set the inode type below we need to mask off type
- to avoid strange results if bits above were corrupt */
- tmp_inode->i_mode &= ~S_IFMT;
+ to avoid strange results if bits above were corrupt */
+ tmp_inode->i_mode &= ~S_IFMT;
if (type == UNIX_FILE) {
*pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG;
@@ -353,7 +352,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
/* safest to just call it a file */
*pobject_type = DT_REG;
tmp_inode->i_mode |= S_IFREG;
- cFYI(1,("unknown inode type %d",type));
+ cFYI(1, ("unknown inode type %d", type));
}
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
@@ -368,7 +367,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
spin_lock(&tmp_inode->i_lock);
if (is_size_safe_to_change(cifsInfo, end_of_file)) {
- /* can not safely change the file size here if the
+ /* can not safely change the file size here if the
client is writing to it due to potential races */
i_size_write(tmp_inode, end_of_file);
@@ -393,15 +392,16 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_fop = &cifs_file_ops;
if ((cifs_sb->tcon) && (cifs_sb->tcon->ses) &&
- (cifs_sb->tcon->ses->server->maxBuf <
+ (cifs_sb->tcon->ses->server->maxBuf <
PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE))
tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf;
else
tmp_inode->i_data.a_ops = &cifs_addr_ops;
if (isNewInode)
- return; /* No sense invalidating pages for new inode since we
- have not started caching readahead file data yet */
+ return; /* No sense invalidating pages for new inode
+ since we have not started caching readahead
+ file data for it yet */
if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) &&
(local_size == tmp_inode->i_size)) {
@@ -420,7 +420,7 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
tmp_inode->i_op = &cifs_symlink_inode_ops;
/* tmp_inode->i_fop = *//* do not need to set to anything */
} else {
- cFYI(1, ("Special inode"));
+ cFYI(1, ("Special inode"));
init_special_inode(tmp_inode, tmp_inode->i_mode,
tmp_inode->i_rdev);
}
@@ -429,14 +429,14 @@ static void unix_fill_in_inode(struct inode *tmp_inode,
static int initiate_cifs_search(const int xid, struct file *file)
{
int rc = 0;
- char * full_path;
- struct cifsFileInfo * cifsFile;
+ char *full_path;
+ struct cifsFileInfo *cifsFile;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
if (file->private_data == NULL) {
- file->private_data =
- kzalloc(sizeof(struct cifsFileInfo),GFP_KERNEL);
+ file->private_data =
+ kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
}
if (file->private_data == NULL)
@@ -463,9 +463,11 @@ static int initiate_cifs_search(const int xid, struct file *file)
ffirst_retry:
/* test for Unix extensions */
- if (pTcon->ses->capabilities & CAP_UNIX) {
+ /* but now check for them on the share/mount not on the SMB session */
+/* if (pTcon->ses->capabilities & CAP_UNIX) { */
+ if (pTcon->unix_ext) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX;
- } else if ((pTcon->ses->capabilities &
+ } else if ((pTcon->ses->capabilities &
(CAP_NT_SMBS | CAP_NT_FIND)) == 0) {
cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD;
} else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
@@ -474,13 +476,13 @@ ffirst_retry:
cifsFile->srch_inf.info_level = SMB_FIND_FILE_DIRECTORY_INFO;
}
- rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls,
+ rc = CIFSFindFirst(xid, pTcon, full_path, cifs_sb->local_nls,
&cifsFile->netfid, &cifsFile->srch_inf,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
if (rc == 0)
cifsFile->invalidHandle = FALSE;
- if ((rc == -EOPNOTSUPP) &&
+ if ((rc == -EOPNOTSUPP) &&
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)) {
cifs_sb->mnt_cifs_flags &= ~CIFS_MOUNT_SERVER_INUM;
goto ffirst_retry;
@@ -495,17 +497,17 @@ static int cifs_unicode_bytelen(char *str)
int len;
__le16 * ustr = (__le16 *)str;
- for(len=0;len <= PATH_MAX;len++) {
+ for (len = 0; len <= PATH_MAX; len++) {
if (ustr[len] == 0)
return len << 1;
}
- cFYI(1,("Unicode string longer than PATH_MAX found"));
+ cFYI(1, ("Unicode string longer than PATH_MAX found"));
return len << 1;
}
static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
{
- char * new_entry;
+ char *new_entry;
FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry;
if (level == SMB_FIND_FILE_INFO_STANDARD) {
@@ -516,21 +518,21 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
pfData->FileNameLength;
} else
new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset);
- cFYI(1,("new entry %p old entry %p",new_entry,old_entry));
+ cFYI(1, ("new entry %p old entry %p", new_entry, old_entry));
/* validate that new_entry is not past end of SMB */
if (new_entry >= end_of_smb) {
cERROR(1,
("search entry %p began after end of SMB %p old entry %p",
- new_entry, end_of_smb, old_entry));
+ new_entry, end_of_smb, old_entry));
return NULL;
} else if (((level == SMB_FIND_FILE_INFO_STANDARD) &&
- (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) ||
- ((level != SMB_FIND_FILE_INFO_STANDARD) &&
+ (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb))
+ || ((level != SMB_FIND_FILE_INFO_STANDARD) &&
(new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) {
- cERROR(1,("search entry %p extends after end of SMB %p",
+ cERROR(1, ("search entry %p extends after end of SMB %p",
new_entry, end_of_smb));
return NULL;
- } else
+ } else
return new_entry;
}
@@ -541,8 +543,8 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level)
static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
{
int rc = 0;
- char * filename = NULL;
- int len = 0;
+ char *filename = NULL;
+ int len = 0;
if (cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
@@ -554,25 +556,25 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
len = strnlen(filename, 5);
}
} else if (cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) {
- FILE_DIRECTORY_INFO * pFindData =
+ FILE_DIRECTORY_INFO * pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if (cfile->srch_inf.info_level ==
+ } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
- FILE_FULL_DIRECTORY_INFO * pFindData =
+ FILE_FULL_DIRECTORY_INFO * pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
} else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_ID_FULL_DIR_INFO) {
- SEARCH_ID_FULL_DIR_INFO * pFindData =
+ SEARCH_ID_FULL_DIR_INFO * pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if (cfile->srch_inf.info_level ==
+ } else if (cfile->srch_inf.info_level ==
SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
- FILE_BOTH_DIRECTORY_INFO * pFindData =
+ FILE_BOTH_DIRECTORY_INFO * pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
@@ -582,7 +584,8 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
filename = &pFindData->FileName[0];
len = pFindData->FileNameLength;
} else {
- cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level));
+ cFYI(1, ("Unknown findfirst level %d",
+ cfile->srch_inf.info_level));
}
if (filename) {
@@ -595,15 +598,15 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
} else if (len == 4) {
/* check for .. */
if ((ufilename[0] == UNICODE_DOT)
- &&(ufilename[1] == UNICODE_DOT))
+ && (ufilename[1] == UNICODE_DOT))
rc = 2;
}
} else /* ASCII */ {
if (len == 1) {
- if (filename[0] == '.')
+ if (filename[0] == '.')
rc = 1;
} else if (len == 2) {
- if((filename[0] == '.') && (filename[1] == '.'))
+ if ((filename[0] == '.') && (filename[1] == '.'))
rc = 2;
}
}
@@ -614,7 +617,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile)
/* Check if directory that we are searching has changed so we can decide
whether we can use the cached search results from the previous search */
-static int is_dir_changed(struct file * file)
+static int is_dir_changed(struct file *file)
{
struct inode *inode = file->f_path.dentry->d_inode;
struct cifsInodeInfo *cifsInfo = CIFS_I(inode);
@@ -633,22 +636,22 @@ static int is_dir_changed(struct file * file)
/* We start counting in the buffer with entry 2 and increment for every
entry (do not increment for . or .. entry) */
static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
- struct file *file, char **ppCurrentEntry, int *num_to_ret)
+ struct file *file, char **ppCurrentEntry, int *num_to_ret)
{
int rc = 0;
int pos_in_buf = 0;
loff_t first_entry_in_buffer;
loff_t index_to_find = file->f_pos;
- struct cifsFileInfo * cifsFile = file->private_data;
+ struct cifsFileInfo *cifsFile = file->private_data;
/* check if index in the buffer */
-
- if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
+
+ if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
(num_to_ret == NULL))
return -ENOENT;
-
+
*ppCurrentEntry = NULL;
- first_entry_in_buffer =
- cifsFile->srch_inf.index_of_last_entry -
+ first_entry_in_buffer =
+ cifsFile->srch_inf.index_of_last_entry -
cifsFile->srch_inf.entries_in_buffer;
/* if first entry in buf is zero then is first buffer
@@ -660,17 +663,17 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
#ifdef CONFIG_CIFS_DEBUG2
dump_cifs_file_struct(file, "In fce ");
#endif
- if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
- is_dir_changed(file)) ||
+ if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
+ is_dir_changed(file)) ||
(index_to_find < first_entry_in_buffer)) {
/* close and restart search */
- cFYI(1,("search backing up - close and restart search"));
+ cFYI(1, ("search backing up - close and restart search"));
cifsFile->invalidHandle = TRUE;
CIFSFindClose(xid, pTcon, cifsFile->netfid);
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL;
if (cifsFile->srch_inf.ntwrk_buf_start) {
- cFYI(1,("freeing SMB ff cache buf on search rewind"));
+ cFYI(1, ("freeing SMB ff cache buf on search rewind"));
if (cifsFile->srch_inf.smallBuf)
cifs_small_buf_release(cifsFile->srch_inf.
ntwrk_buf_start);
@@ -678,17 +681,18 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
cifs_buf_release(cifsFile->srch_inf.
ntwrk_buf_start);
}
- rc = initiate_cifs_search(xid,file);
+ rc = initiate_cifs_search(xid, file);
if (rc) {
- cFYI(1,("error %d reinitiating a search on rewind",rc));
+ cFYI(1, ("error %d reinitiating a search on rewind",
+ rc));
return rc;
}
}
- while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
- (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){
- cFYI(1,("calling findnext2"));
- rc = CIFSFindNext(xid,pTcon,cifsFile->netfid,
+ while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
+ (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)) {
+ cFYI(1, ("calling findnext2"));
+ rc = CIFSFindNext(xid, pTcon, cifsFile->netfid,
&cifsFile->srch_inf);
if (rc)
return -ENOENT;
@@ -697,8 +701,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
/* we found the buffer that contains the entry */
/* scan and find it */
int i;
- char * current_entry;
- char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
+ char *current_entry;
+ char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start);
@@ -706,28 +710,28 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
- cifsFile->srch_inf.entries_in_buffer;
pos_in_buf = index_to_find - first_entry_in_buffer;
- cFYI(1,("found entry - pos_in_buf %d",pos_in_buf));
+ cFYI(1, ("found entry - pos_in_buf %d", pos_in_buf));
- for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) {
+ for (i=0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
/* go entry by entry figuring out which is first */
- current_entry = nxt_dir_entry(current_entry,end_of_smb,
+ current_entry = nxt_dir_entry(current_entry, end_of_smb,
cifsFile->srch_inf.info_level);
}
- if((current_entry == NULL) && (i < pos_in_buf)) {
+ if ((current_entry == NULL) && (i < pos_in_buf)) {
/* BB fixme - check if we should flag this error */
- cERROR(1,("reached end of buf searching for pos in buf"
+ cERROR(1, ("reached end of buf searching for pos in buf"
" %d index to find %lld rc %d",
- pos_in_buf,index_to_find,rc));
+ pos_in_buf, index_to_find, rc));
}
rc = 0;
*ppCurrentEntry = current_entry;
} else {
- cFYI(1,("index not in buffer - could not findnext into it"));
+ cFYI(1, ("index not in buffer - could not findnext into it"));
return 0;
}
- if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
- cFYI(1,("can not return entries pos_in_buf beyond last entry"));
+ if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
+ cFYI(1, ("can not return entries pos_in_buf beyond last"));
*num_to_ret = 0;
} else
*num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
@@ -738,81 +742,81 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
/* inode num, inode type and filename returned */
static int cifs_get_name_from_search_buf(struct qstr *pqst,
char *current_entry, __u16 level, unsigned int unicode,
- struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum)
+ struct cifs_sb_info *cifs_sb, int max_len, ino_t *pinum)
{
int rc = 0;
unsigned int len = 0;
- char * filename;
- struct nls_table * nlt = cifs_sb->local_nls;
+ char *filename;
+ struct nls_table *nlt = cifs_sb->local_nls;
*pinum = 0;
- if(level == SMB_FIND_FILE_UNIX) {
- FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
+ if (level == SMB_FIND_FILE_UNIX) {
+ FILE_UNIX_INFO *pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0];
- if(unicode) {
+ if (unicode) {
len = cifs_unicode_bytelen(filename);
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, PATH_MAX);
}
- /* BB fixme - hash low and high 32 bits if not 64 bit arch BB fixme */
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
+ /* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
*pinum = pFindData->UniqueId;
- } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
- FILE_DIRECTORY_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
+ FILE_DIRECTORY_INFO *pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
- FILE_FULL_DIRECTORY_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+ FILE_FULL_DIRECTORY_INFO *pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
- SEARCH_ID_FULL_DIR_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+ SEARCH_ID_FULL_DIR_INFO *pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
*pinum = pFindData->UniqueId;
- } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
- FILE_BOTH_DIRECTORY_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+ FILE_BOTH_DIRECTORY_INFO *pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
- } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
+ } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
FIND_FILE_STANDARD_INFO * pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0];
/* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength;
} else {
- cFYI(1,("Unknown findfirst level %d",level));
+ cFYI(1, ("Unknown findfirst level %d", level));
return -EINVAL;
}
- if(len > max_len) {
- cERROR(1,("bad search response length %d past smb end", len));
+ if (len > max_len) {
+ cERROR(1, ("bad search response length %d past smb end", len));
return -EINVAL;
}
- if(unicode) {
+ if (unicode) {
/* BB fixme - test with long names */
/* Note converted filename can be longer than in unicode */
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR)
pqst->len = cifs_convertUCSpath((char *)pqst->name,
(__le16 *)filename, len/2, nlt);
else
pqst->len = cifs_strfromUCS_le((char *)pqst->name,
- (__le16 *)filename,len/2,nlt);
+ (__le16 *)filename, len/2, nlt);
} else {
pqst->name = filename;
pqst->len = len;
}
- pqst->hash = full_name_hash(pqst->name,pqst->len);
-/* cFYI(1,("filldir on %s",pqst->name)); */
+ pqst->hash = full_name_hash(pqst->name, pqst->len);
+/* cFYI(1, ("filldir on %s",pqst->name)); */
return rc;
}
@@ -821,49 +825,50 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
{
int rc = 0;
struct qstr qstring;
- struct cifsFileInfo * pCifsF;
+ struct cifsFileInfo *pCifsF;
unsigned obj_type;
ino_t inum;
- struct cifs_sb_info * cifs_sb;
+ struct cifs_sb_info *cifs_sb;
struct inode *tmp_inode;
struct dentry *tmp_dentry;
/* get filename and len into qstring */
/* get dentry */
/* decide whether to create and populate ionde */
- if((direntry == NULL) || (file == NULL))
+ if ((direntry == NULL) || (file == NULL))
return -EINVAL;
pCifsF = file->private_data;
-
- if((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
+
+ if ((scratch_buf == NULL) || (pfindEntry == NULL) || (pCifsF == NULL))
return -ENOENT;
- rc = cifs_entry_is_dot(pfindEntry,pCifsF);
+ rc = cifs_entry_is_dot(pfindEntry, pCifsF);
/* skip . and .. since we added them first */
- if(rc != 0)
+ if (rc != 0)
return 0;
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
qstring.name = scratch_buf;
- rc = cifs_get_name_from_search_buf(&qstring,pfindEntry,
+ rc = cifs_get_name_from_search_buf(&qstring, pfindEntry,
pCifsF->srch_inf.info_level,
- pCifsF->srch_inf.unicode,cifs_sb,
+ pCifsF->srch_inf.unicode, cifs_sb,
max_len,
&inum /* returned */);
- if(rc)
+ if (rc)
return rc;
- rc = construct_dentry(&qstring,file,&tmp_inode, &tmp_dentry);
- if((tmp_inode == NULL) || (tmp_dentry == NULL))
+ rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
+ if ((tmp_inode == NULL) || (tmp_dentry == NULL))
return -ENOMEM;
- if(rc) {
+ if (rc) {
/* inode created, we need to hash it with right inode number */
- if(inum != 0) {
- /* BB fixme - hash the 2 32 quantities bits together if necessary BB */
+ if (inum != 0) {
+ /* BB fixme - hash the 2 32 quantities bits together if
+ * necessary BB */
tmp_inode->i_ino = inum;
}
insert_inode_hash(tmp_inode);
@@ -872,27 +877,27 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
/* we pass in rc below, indicating whether it is a new inode,
so we can figure out whether to invalidate the inode cached
data if the file has changed */
- if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
+ if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX)
unix_fill_in_inode(tmp_inode,
(FILE_UNIX_INFO *)pfindEntry,
&obj_type, rc);
- else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
+ else if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD)
fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */,
pfindEntry, &obj_type, rc);
else
fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc);
- if(rc) /* new inode - needs to be tied to dentry */ {
+ if (rc) /* new inode - needs to be tied to dentry */ {
d_instantiate(tmp_dentry, tmp_inode);
- if(rc == 2)
+ if (rc == 2)
d_rehash(tmp_dentry);
}
-
-
- rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,
- tmp_inode->i_ino,obj_type);
- if(rc) {
- cFYI(1,("filldir rc = %d",rc));
+
+
+ rc = filldir(direntry, qstring.name, qstring.len, file->f_pos,
+ tmp_inode->i_ino, obj_type);
+ if (rc) {
+ cFYI(1, ("filldir rc = %d", rc));
/* we can not return filldir errors to the caller
since they are "normal" when the stat blocksize
is too small - we return remapped error instead */
@@ -909,57 +914,57 @@ static int cifs_save_resume_key(const char *current_entry,
int rc = 0;
unsigned int len = 0;
__u16 level;
- char * filename;
+ char *filename;
- if((cifsFile == NULL) || (current_entry == NULL))
+ if ((cifsFile == NULL) || (current_entry == NULL))
return -EINVAL;
level = cifsFile->srch_inf.info_level;
- if(level == SMB_FIND_FILE_UNIX) {
+ if (level == SMB_FIND_FILE_UNIX) {
FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry;
filename = &pFindData->FileName[0];
- if(cifsFile->srch_inf.unicode) {
+ if (cifsFile->srch_inf.unicode) {
len = cifs_unicode_bytelen(filename);
} else {
/* BB should we make this strnlen of PATH_MAX? */
len = strnlen(filename, PATH_MAX);
}
cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
- } else if(level == SMB_FIND_FILE_DIRECTORY_INFO) {
- FILE_DIRECTORY_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
+ FILE_DIRECTORY_INFO *pFindData =
(FILE_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if(level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
- FILE_FULL_DIRECTORY_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_FULL_DIRECTORY_INFO) {
+ FILE_FULL_DIRECTORY_INFO *pFindData =
(FILE_FULL_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if(level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
- SEARCH_ID_FULL_DIR_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_ID_FULL_DIR_INFO) {
+ SEARCH_ID_FULL_DIR_INFO *pFindData =
(SEARCH_ID_FULL_DIR_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if(level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
- FILE_BOTH_DIRECTORY_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_BOTH_DIRECTORY_INFO) {
+ FILE_BOTH_DIRECTORY_INFO *pFindData =
(FILE_BOTH_DIRECTORY_INFO *)current_entry;
filename = &pFindData->FileName[0];
len = le32_to_cpu(pFindData->FileNameLength);
cifsFile->srch_inf.resume_key = pFindData->FileIndex;
- } else if(level == SMB_FIND_FILE_INFO_STANDARD) {
- FIND_FILE_STANDARD_INFO * pFindData =
+ } else if (level == SMB_FIND_FILE_INFO_STANDARD) {
+ FIND_FILE_STANDARD_INFO *pFindData =
(FIND_FILE_STANDARD_INFO *)current_entry;
filename = &pFindData->FileName[0];
/* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength;
cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else {
- cFYI(1,("Unknown findfirst level %d",level));
+ cFYI(1, ("Unknown findfirst level %d", level));
return -EINVAL;
}
cifsFile->srch_inf.resume_name_len = len;
@@ -970,21 +975,21 @@ static int cifs_save_resume_key(const char *current_entry,
int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
{
int rc = 0;
- int xid,i;
+ int xid, i;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
struct cifsFileInfo *cifsFile = NULL;
- char * current_entry;
+ char *current_entry;
int num_to_fill = 0;
- char * tmp_buf = NULL;
- char * end_of_smb;
+ char *tmp_buf = NULL;
+ char *end_of_smb;
int max_len;
xid = GetXid();
cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
pTcon = cifs_sb->tcon;
- if(pTcon == NULL)
+ if (pTcon == NULL)
return -EINVAL;
switch ((int) file->f_pos) {
@@ -1005,27 +1010,27 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
}
file->f_pos++;
default:
- /* 1) If search is active,
- is in current search buffer?
+ /* 1) If search is active,
+ is in current search buffer?
if it before then restart search
if after then keep searching till find it */
- if(file->private_data == NULL) {
- rc = initiate_cifs_search(xid,file);
- cFYI(1,("initiate cifs search rc %d",rc));
- if(rc) {
+ if (file->private_data == NULL) {
+ rc = initiate_cifs_search(xid, file);
+ cFYI(1, ("initiate cifs search rc %d", rc));
+ if (rc) {
FreeXid(xid);
return rc;
}
}
- if(file->private_data == NULL) {
+ if (file->private_data == NULL) {
rc = -EINVAL;
FreeXid(xid);
return rc;
}
cifsFile = file->private_data;
if (cifsFile->srch_inf.endOfSearch) {
- if(cifsFile->srch_inf.emptyDir) {
+ if (cifsFile->srch_inf.emptyDir) {
cFYI(1, ("End of search, empty dir"));
rc = 0;
break;
@@ -1033,23 +1038,23 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
} /* else {
cifsFile->invalidHandle = TRUE;
CIFSFindClose(xid, pTcon, cifsFile->netfid);
- }
+ }
kfree(cifsFile->search_resume_name);
cifsFile->search_resume_name = NULL; */
- rc = find_cifs_entry(xid,pTcon, file,
- &current_entry,&num_to_fill);
- if(rc) {
- cFYI(1,("fce error %d",rc));
+ rc = find_cifs_entry(xid, pTcon, file,
+ &current_entry, &num_to_fill);
+ if (rc) {
+ cFYI(1, ("fce error %d", rc));
goto rddir2_exit;
} else if (current_entry != NULL) {
- cFYI(1,("entry %lld found",file->f_pos));
+ cFYI(1, ("entry %lld found", file->f_pos));
} else {
- cFYI(1,("could not find entry"));
+ cFYI(1, ("could not find entry"));
goto rddir2_exit;
}
- cFYI(1,("loop through %d times filling dir for net buf %p",
- num_to_fill,cifsFile->srch_inf.ntwrk_buf_start));
+ cFYI(1, ("loop through %d times filling dir for net buf %p",
+ num_to_fill, cifsFile->srch_inf.ntwrk_buf_start));
max_len = smbCalcSize((struct smb_hdr *)
cifsFile->srch_inf.ntwrk_buf_start);
end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
@@ -1059,8 +1064,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
such multibyte target UTF-8 characters. cifs_unicode.c,
which actually does the conversion, has the same limit */
tmp_buf = kmalloc((2 * NAME_MAX) + 4, GFP_KERNEL);
- for(i=0;(i<num_to_fill) && (rc == 0);i++) {
- if(current_entry == NULL) {
+ for (i = 0; (i < num_to_fill) && (rc == 0); i++) {
+ if (current_entry == NULL) {
/* evaluate whether this case is an error */
cERROR(1,("past end of SMB num to fill %d i %d",
num_to_fill, i));
@@ -1070,20 +1075,20 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
we want to check for that here? */
rc = cifs_filldir(current_entry, file,
filldir, direntry, tmp_buf, max_len);
- if(rc == -EOVERFLOW) {
+ if (rc == -EOVERFLOW) {
rc = 0;
break;
}
file->f_pos++;
- if(file->f_pos ==
+ if (file->f_pos ==
cifsFile->srch_inf.index_of_last_entry) {
- cFYI(1,("last entry in buf at pos %lld %s",
- file->f_pos,tmp_buf));
- cifs_save_resume_key(current_entry,cifsFile);
+ cFYI(1, ("last entry in buf at pos %lld %s",
+ file->f_pos, tmp_buf));
+ cifs_save_resume_key(current_entry, cifsFile);
break;
- } else
- current_entry =
+ } else
+ current_entry =
nxt_dir_entry(current_entry, end_of_smb,
cifsFile->srch_inf.info_level);
}
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 758464630893..2ea027dda215 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -3,7 +3,7 @@
*
* SMB/CIFS session setup handling routines
*
- * Copyright (c) International Business Machines Corp., 2006
+ * Copyright (c) International Business Machines Corp., 2006, 2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
#include <linux/utsname.h>
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
- unsigned char *p24);
+ unsigned char *p24);
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
{
@@ -45,13 +45,14 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
- /* BB verify whether signing required on neg or just on auth frame
+ /* BB verify whether signing required on neg or just on auth frame
(and NTLM case) */
capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
- if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ if (ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
if (ses->capabilities & CAP_UNICODE) {
@@ -74,10 +75,10 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
return capabilities;
}
-static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
- const struct nls_table * nls_cp)
+static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
+ const struct nls_table *nls_cp)
{
- char * bcc_ptr = *pbcc_area;
+ char *bcc_ptr = *pbcc_area;
int bytes_ret = 0;
/* BB FIXME add check that strings total less
@@ -89,7 +90,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
bcc_ptr++;
} */
/* copy user */
- if(ses->userName == NULL) {
+ if (ses->userName == NULL) {
/* null user mount */
*bcc_ptr = 0;
*(bcc_ptr+1) = 0;
@@ -100,14 +101,14 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* account for null termination */
/* copy domain */
- if(ses->domainName == NULL) {
+ if (ses->domainName == NULL) {
/* Sending null domain better than using a bogus domain name (as
we did briefly in 2.6.18) since server will use its default */
*bcc_ptr = 0;
*(bcc_ptr+1) = 0;
bytes_ret = 0;
} else
- bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName,
+ bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName,
256, nls_cp);
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* account for null terminator */
@@ -122,37 +123,37 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
bcc_ptr += 2; /* trailing null */
bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
- 32, nls_cp);
+ 32, nls_cp);
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* trailing null */
*pbcc_area = bcc_ptr;
}
-static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
- const struct nls_table * nls_cp)
+static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses,
+ const struct nls_table *nls_cp)
{
- char * bcc_ptr = *pbcc_area;
+ char *bcc_ptr = *pbcc_area;
/* copy user */
/* BB what about null user mounts - check that we do this BB */
- /* copy user */
- if(ses->userName == NULL) {
- /* BB what about null user mounts - check that we do this BB */
- } else { /* 300 should be long enough for any conceivable user name */
- strncpy(bcc_ptr, ses->userName, 300);
- }
+ /* copy user */
+ if (ses->userName == NULL) {
+ /* BB what about null user mounts - check that we do this BB */
+ } else { /* 300 should be long enough for any conceivable user name */
+ strncpy(bcc_ptr, ses->userName, 300);
+ }
/* BB improve check for overflow */
- bcc_ptr += strnlen(ses->userName, 300);
+ bcc_ptr += strnlen(ses->userName, 300);
*bcc_ptr = 0;
- bcc_ptr++; /* account for null termination */
+ bcc_ptr++; /* account for null termination */
- /* copy domain */
-
- if(ses->domainName != NULL) {
- strncpy(bcc_ptr, ses->domainName, 256);
+ /* copy domain */
+
+ if (ses->domainName != NULL) {
+ strncpy(bcc_ptr, ses->domainName, 256);
bcc_ptr += strnlen(ses->domainName, 256);
- } /* else we will send a null domain name
+ } /* else we will send a null domain name
so the server will default to its own domain */
*bcc_ptr = 0;
bcc_ptr++;
@@ -167,19 +168,20 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
- *pbcc_area = bcc_ptr;
+ *pbcc_area = bcc_ptr;
}
-static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
- const struct nls_table * nls_cp)
+static int decode_unicode_ssetup(char **pbcc_area, int bleft,
+ struct cifsSesInfo *ses,
+ const struct nls_table *nls_cp)
{
int rc = 0;
int words_left, len;
- char * data = *pbcc_area;
+ char *data = *pbcc_area;
- cFYI(1,("bleft %d",bleft));
+ cFYI(1, ("bleft %d", bleft));
/* SMB header is unaligned, so cifs servers word align start of
@@ -189,7 +191,7 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
their final Unicode string - in which case we
now will not attempt to decode the byte of junk
which follows it */
-
+
words_left = bleft / 2;
/* save off server operating system */
@@ -198,14 +200,14 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
/* We look for obvious messed up bcc or strings in response so we do not go off
the end since (at least) WIN2K and Windows XP have a major bug in not null
terminating last Unicode string in response */
- if(len >= words_left)
+ if (len >= words_left)
return rc;
- if(ses->serverOS)
+ if (ses->serverOS)
kfree(ses->serverOS);
/* UTF-8 string will not grow more than four times as big as UCS-16 */
ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
- if(ses->serverOS != NULL) {
+ if (ses->serverOS != NULL) {
cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
nls_cp);
}
@@ -215,67 +217,68 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
/* save off server network operating system */
len = UniStrnlen((wchar_t *) data, words_left);
- if(len >= words_left)
+ if (len >= words_left)
return rc;
- if(ses->serverNOS)
+ if (ses->serverNOS)
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
- if(ses->serverNOS != NULL) {
+ if (ses->serverNOS != NULL) {
cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
nls_cp);
- if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
- cFYI(1,("NT4 server"));
+ if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) {
+ cFYI(1, ("NT4 server"));
ses->flags |= CIFS_SES_NT4;
}
}
data += 2 * (len + 1);
words_left -= len + 1;
- /* save off server domain */
- len = UniStrnlen((wchar_t *) data, words_left);
-
- if(len > words_left)
- return rc;
-
- if(ses->serverDomain)
- kfree(ses->serverDomain);
- ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
- if(ses->serverDomain != NULL) {
- cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
- nls_cp);
- ses->serverDomain[2*len] = 0;
- ses->serverDomain[(2*len) + 1] = 0;
- }
- data += 2 * (len + 1);
- words_left -= len + 1;
-
- cFYI(1,("words left: %d",words_left));
+ /* save off server domain */
+ len = UniStrnlen((wchar_t *) data, words_left);
+
+ if (len > words_left)
+ return rc;
+
+ if (ses->serverDomain)
+ kfree(ses->serverDomain);
+ ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
+ if (ses->serverDomain != NULL) {
+ cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
+ nls_cp);
+ ses->serverDomain[2*len] = 0;
+ ses->serverDomain[(2*len) + 1] = 0;
+ }
+ data += 2 * (len + 1);
+ words_left -= len + 1;
+
+ cFYI(1, ("words left: %d", words_left));
return rc;
}
-static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
- const struct nls_table * nls_cp)
+static int decode_ascii_ssetup(char **pbcc_area, int bleft,
+ struct cifsSesInfo *ses,
+ const struct nls_table *nls_cp)
{
int rc = 0;
int len;
- char * bcc_ptr = *pbcc_area;
+ char *bcc_ptr = *pbcc_area;
+
+ cFYI(1, ("decode sessetup ascii. bleft %d", bleft));
- cFYI(1,("decode sessetup ascii. bleft %d", bleft));
-
len = strnlen(bcc_ptr, bleft);
- if(len >= bleft)
+ if (len >= bleft)
return rc;
-
- if(ses->serverOS)
+
+ if (ses->serverOS)
kfree(ses->serverOS);
ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
- if(ses->serverOS)
+ if (ses->serverOS)
strncpy(ses->serverOS, bcc_ptr, len);
- if(strncmp(ses->serverOS, "OS/2",4) == 0) {
- cFYI(1,("OS/2 server"));
+ if (strncmp(ses->serverOS, "OS/2", 4) == 0) {
+ cFYI(1, ("OS/2 server"));
ses->flags |= CIFS_SES_OS2;
}
@@ -283,34 +286,34 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
bleft -= len + 1;
len = strnlen(bcc_ptr, bleft);
- if(len >= bleft)
+ if (len >= bleft)
return rc;
- if(ses->serverNOS)
+ if (ses->serverNOS)
kfree(ses->serverNOS);
ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
- if(ses->serverNOS)
+ if (ses->serverNOS)
strncpy(ses->serverNOS, bcc_ptr, len);
bcc_ptr += len + 1;
bleft -= len + 1;
- len = strnlen(bcc_ptr, bleft);
- if(len > bleft)
- return rc;
+ len = strnlen(bcc_ptr, bleft);
+ if (len > bleft)
+ return rc;
/* No domain field in LANMAN case. Domain is
returned by old servers in the SMB negprot response */
/* BB For newer servers which do not support Unicode,
but thus do return domain here we could add parsing
for it later, but it is not very important */
- cFYI(1,("ascii: bytes left %d",bleft));
+ cFYI(1, ("ascii: bytes left %d", bleft));
return rc;
}
-int
+int
CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
const struct nls_table *nls_cp)
{
@@ -328,13 +331,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
__u16 action;
int bytes_remaining;
- if(ses == NULL)
+ if (ses == NULL)
return -EINVAL;
type = ses->server->secType;
- cFYI(1,("sess setup type %d",type));
- if(type == LANMAN) {
+ cFYI(1, ("sess setup type %d", type));
+ if (type == LANMAN) {
#ifndef CONFIG_CIFS_WEAK_PW_HASH
/* LANMAN and plaintext are less secure and off by default.
So we make this explicitly be turned on in kconfig (in the
@@ -344,15 +347,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
return -EOPNOTSUPP;
#endif
wct = 10; /* lanman 2 style sessionsetup */
- } else if((type == NTLM) || (type == NTLMv2)) {
+ } else if ((type == NTLM) || (type == NTLMv2)) {
/* For NTLMv2 failures eventually may need to retry NTLM */
wct = 13; /* old style NTLM sessionsetup */
- } else /* same size for negotiate or auth, NTLMSSP or extended security */
+ } else /* same size: negotiate or auth, NTLMSSP or extended security */
wct = 12;
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
(void **)&smb_buf);
- if(rc)
+ if (rc)
return rc;
pSMB = (SESSION_SETUP_ANDX *)smb_buf;
@@ -364,8 +367,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
second part which will include the strings
and rest of bcc area, in order to avoid having
to do a large buffer 17K allocation */
- iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = smb_buf->smb_buf_length + 4;
+ iov[0].iov_base = (char *)pSMB;
+ iov[0].iov_len = smb_buf->smb_buf_length + 4;
/* 2000 big enough to fit max user, domain, NOS name etc. */
str_area = kmalloc(2000, GFP_KERNEL);
@@ -373,18 +376,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
ses->flags &= ~CIFS_SES_LANMAN;
- if(type == LANMAN) {
+ if (type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESS_KEY_SIZE];
/* no capabilities flags in old lanman negotiation */
- pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
+ pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
/* BB calculate hash with password */
/* and copy into bcc */
calc_lanman_hash(ses, lnm_session_key);
- ses->flags |= CIFS_SES_LANMAN;
+ ses->flags |= CIFS_SES_LANMAN;
/* #ifdef CONFIG_CIFS_DEBUG2
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
CIFS_SESS_KEY_SIZE);
@@ -397,10 +400,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
changed to do higher than lanman dialect and
we reconnected would we ever calc signing_key? */
- cFYI(1,("Negotiating LANMAN setting up strings"));
+ cFYI(1, ("Negotiating LANMAN setting up strings"));
/* Unicode not allowed for LANMAN dialects */
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
-#endif
+#endif
} else if (type == NTLM) {
char ntlm_session_key[CIFS_SESS_KEY_SIZE];
@@ -409,38 +412,38 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
cpu_to_le16(CIFS_SESS_KEY_SIZE);
pSMB->req_no_secext.CaseSensitivePasswordLength =
cpu_to_le16(CIFS_SESS_KEY_SIZE);
-
+
/* calculate session key */
SMBNTencrypt(ses->password, ses->server->cryptKey,
ntlm_session_key);
- if(first_time) /* should this be moved into common code
+ if (first_time) /* should this be moved into common code
with similar ntlmv2 path? */
- cifs_calculate_mac_key(ses->server->mac_signing_key,
+ cifs_calculate_mac_key(&ses->server->mac_signing_key,
ntlm_session_key, ses->password);
/* copy session key */
- memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+ memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESS_KEY_SIZE;
- memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
+ memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE);
bcc_ptr += CIFS_SESS_KEY_SIZE;
- if(ses->capabilities & CAP_UNICODE) {
+ if (ses->capabilities & CAP_UNICODE) {
/* unicode strings must be word aligned */
if (iov[0].iov_len % 2) {
*bcc_ptr = 0;
- bcc_ptr++;
- }
+ bcc_ptr++;
+ }
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
} else if (type == NTLMv2) {
- char * v2_sess_key =
+ char *v2_sess_key =
kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
/* BB FIXME change all users of v2_sess_key to
struct ntlmv2_resp */
- if(v2_sess_key == NULL) {
+ if (v2_sess_key == NULL) {
cifs_small_buf_release(smb_buf);
return -ENOMEM;
}
@@ -456,8 +459,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* calculate session key */
setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
- if(first_time) /* should this be moved into common code
- with similar ntlmv2 path? */
+ if (first_time) /* should this be moved into common code
+ with similar ntlmv2 path? */
/* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
response BB FIXME, v2_sess_key); */
@@ -465,11 +468,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
bcc_ptr += LM2_SESS_KEY_SIZE; */
- memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp));
+ memcpy(bcc_ptr, (char *)v2_sess_key,
+ sizeof(struct ntlmv2_resp));
bcc_ptr += sizeof(struct ntlmv2_resp);
kfree(v2_sess_key);
- if(ses->capabilities & CAP_UNICODE) {
- if(iov[0].iov_len % 2) {
+ if (ses->capabilities & CAP_UNICODE) {
+ if (iov[0].iov_len % 2) {
*bcc_ptr = 0;
} bcc_ptr++;
unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
@@ -488,20 +492,20 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
BCC_LE(smb_buf) = cpu_to_le16(count);
iov[1].iov_base = str_area;
- iov[1].iov_len = count;
+ iov[1].iov_len = count;
rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
/* SMB request buf freed in SendReceive2 */
- cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
- if(rc)
+ cFYI(1, ("ssetup rc from sendrecv2 is %d", rc));
+ if (rc)
goto ssetup_exit;
pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
smb_buf = (struct smb_hdr *)iov[0].iov_base;
- if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
+ if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
rc = -EIO;
- cERROR(1,("bad word count %d", smb_buf->WordCount));
+ cERROR(1, ("bad word count %d", smb_buf->WordCount));
goto ssetup_exit;
}
action = le16_to_cpu(pSMB->resp.Action);
@@ -514,31 +518,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
bytes_remaining = BCC(smb_buf);
bcc_ptr = pByteArea(smb_buf);
- if(smb_buf->WordCount == 4) {
+ if (smb_buf->WordCount == 4) {
__u16 blob_len;
blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
bcc_ptr += blob_len;
- if(blob_len > bytes_remaining) {
- cERROR(1,("bad security blob length %d", blob_len));
+ if (blob_len > bytes_remaining) {
+ cERROR(1, ("bad security blob length %d", blob_len));
rc = -EINVAL;
goto ssetup_exit;
}
bytes_remaining -= blob_len;
- }
+ }
/* BB check if Unicode and decode strings */
- if(smb_buf->Flags2 & SMBFLG2_UNICODE)
+ if (smb_buf->Flags2 & SMBFLG2_UNICODE)
rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
ses, nls_cp);
else
- rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
-
+ rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
+ ses, nls_cp);
+
ssetup_exit:
kfree(str_area);
- if(resp_buf_type == CIFS_SMALL_BUFFER) {
- cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
+ if (resp_buf_type == CIFS_SMALL_BUFFER) {
+ cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base));
cifs_small_buf_release(iov[0].iov_base);
- } else if(resp_buf_type == CIFS_LARGE_BUFFER)
+ } else if (resp_buf_type == CIFS_LARGE_BUFFER)
cifs_buf_release(iov[0].iov_base);
return rc;
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index 1b1daf63f062..cfa6d21fb4e8 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -1,32 +1,32 @@
-/*
+/*
Unix SMB/Netbios implementation.
Version 1.9.
- a partial implementation of DES designed for use in the
+ a partial implementation of DES designed for use in the
SMB authentication protocol
Copyright (C) Andrew Tridgell 1998
Modified by Steve French (sfrench@us.ibm.com) 2002,2004
-
+
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.
*/
-/* NOTES:
+/* NOTES:
This code makes no attempt to be fast! In fact, it is a very
- slow implementation
+ slow implementation
This code is NOT a complete DES implementation. It implements only
the minimum necessary for SMB authentication, as used by all SMB
@@ -153,7 +153,7 @@ static uchar sbox[8][4][16] = {
};
static void
-permute(char *out, char *in, uchar * p, int n)
+permute(char *out, char *in, uchar *p, int n)
{
int i;
for (i = 0; i < n; i++)
@@ -202,18 +202,18 @@ dohash(char *out, char *in, char *key, int forw)
char *rl;
/* Have to reduce stack usage */
- pk1 = kmalloc(56+56+64+64,GFP_KERNEL);
- if(pk1 == NULL)
+ pk1 = kmalloc(56+56+64+64, GFP_KERNEL);
+ if (pk1 == NULL)
return;
ki = kmalloc(16*48, GFP_KERNEL);
- if(ki == NULL) {
+ if (ki == NULL) {
kfree(pk1);
return;
}
cd = pk1 + 56;
- pd1= cd + 56;
+ pd1 = cd + 56;
rl = pd1 + 64;
permute(pk1, key, perm1, 56);
@@ -247,7 +247,7 @@ dohash(char *out, char *in, char *key, int forw)
char *r2; /* r2[32] */
er = kmalloc(48+48+32+32+32, GFP_KERNEL);
- if(er == NULL) {
+ if (er == NULL) {
kfree(pk1);
kfree(ki);
return;
@@ -327,8 +327,8 @@ smbhash(unsigned char *out, unsigned char *in, unsigned char *key, int forw)
char *keyb; /* keyb[64] */
unsigned char key2[8];
- outb = kmalloc(64 * 3,GFP_KERNEL);
- if(outb == NULL)
+ outb = kmalloc(64 * 3, GFP_KERNEL);
+ if (outb == NULL)
return;
inb = outb + 64;
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index 4b25ba92180d..90542a39be17 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -1,4 +1,4 @@
-/*
+/*
Unix SMB/Netbios implementation.
Version 1.9.
SMB parameters and setup
@@ -7,17 +7,17 @@
Modified by Jeremy Allison 1995.
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2002-2003
Modified by Steve French (sfrench@us.ibm.com) 2002-2003
-
+
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.
@@ -57,7 +57,7 @@ void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
/*
This implements the X/Open SMB password encryption
- It takes a password, a 8 byte "crypt key" and puts 24 bytes of
+ It takes a password, a 8 byte "crypt key" and puts 24 bytes of
encrypted password into p24 */
/* Note that password must be uppercased and null terminated */
void
@@ -73,9 +73,9 @@ SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
E_P16(p14, p21);
SMBOWFencrypt(p21, c8, p24);
-
- memset(p14,0,15);
- memset(p21,0,21);
+
+ memset(p14, 0, 15);
+ memset(p21, 0, 21);
}
/* Routines for Windows NT MD4 Hash functions. */
@@ -90,14 +90,14 @@ _my_wcslen(__u16 * str)
/*
* Convert a string into an NT UNICODE string.
- * Note that regardless of processor type
+ * Note that regardless of processor type
* this must be in intel (little-endian)
* format.
*/
static int
_my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
-{ /* not a very good conversion routine - change/fix */
+{ /* BB not a very good conversion routine - change/fix */
int i;
__u16 val;
@@ -112,7 +112,7 @@ _my_mbstowcs(__u16 * dst, const unsigned char *src, int len)
return i;
}
-/*
+/*
* Creates the MD4 Hash of the users password in NT UNICODE.
*/
@@ -123,7 +123,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
__u16 wpwd[129];
/* Password cannot be longer than 128 characters */
- if(passwd) {
+ if (passwd) {
len = strlen((char *) passwd);
if (len > 128) {
len = 128;
@@ -138,7 +138,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
len = _my_wcslen(wpwd) * sizeof (__u16);
mdfour(p16, (unsigned char *) wpwd, len);
- memset(wpwd,0,129 * 2);
+ memset(wpwd, 0, 129 * 2);
}
#if 0 /* currently unused */
@@ -178,17 +178,17 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
const char *domain_n, unsigned char kr_buf[16],
const struct nls_table *nls_codepage)
{
- wchar_t * user_u;
- wchar_t * dom_u;
+ wchar_t *user_u;
+ wchar_t *dom_u;
int user_l, domain_l;
struct HMACMD5Context ctx;
/* might as well do one alloc to hold both (user_u and dom_u) */
- user_u = kmalloc(2048 * sizeof(wchar_t),GFP_KERNEL);
- if(user_u == NULL)
+ user_u = kmalloc(2048 * sizeof(wchar_t), GFP_KERNEL);
+ if (user_u == NULL)
return;
dom_u = user_u + 1024;
-
+
/* push_ucs2(NULL, user_u, user_n, (user_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER);
push_ucs2(NULL, dom_u, domain_n, (domain_l+1)*2, STR_UNICODE|STR_NOALIGN|STR_TERMINATE|STR_UPPER); */
@@ -206,7 +206,7 @@ ntv2_owf_gen(const unsigned char owf[16], const char *user_n,
kfree(user_u);
}
-#endif
+#endif
/* Does the des encryption from the NT or LM MD4 hash. */
static void
@@ -256,15 +256,15 @@ SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24)
#if 0
static void
SMBOWFencrypt_ntv2(const unsigned char kr[16],
- const struct data_blob * srv_chal,
- const struct data_blob * cli_chal, unsigned char resp_buf[16])
+ const struct data_blob *srv_chal,
+ const struct data_blob *cli_chal, unsigned char resp_buf[16])
{
- struct HMACMD5Context ctx;
+ struct HMACMD5Context ctx;
- hmac_md5_init_limK_to_64(kr, 16, &ctx);
- hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
- hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
- hmac_md5_final(resp_buf, &ctx);
+ hmac_md5_init_limK_to_64(kr, 16, &ctx);
+ hmac_md5_update(srv_chal->data, srv_chal->length, &ctx);
+ hmac_md5_update(cli_chal->data, cli_chal->length, &ctx);
+ hmac_md5_final(resp_buf, &ctx);
}
static void
diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h
index 212c3c296409..2ef0be288820 100644
--- a/fs/cifs/smberr.h
+++ b/fs/cifs/smberr.h
@@ -4,8 +4,8 @@
* Copyright (c) International Business Machines Corp., 2002,2004
* Author(s): Steve French (sfrench@us.ibm.com)
*
- * See Error Codes section of the SNIA CIFS Specification
- * for more information
+ * See Error Codes section of the SNIA CIFS Specification
+ * for more information
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
@@ -19,7 +19,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define SUCCESS 0x00 /* The request was successful. */
@@ -110,7 +110,7 @@
/* Below errors are used internally (do not come over the wire) for passthrough
from STATUS codes to POSIX only */
-#define ErrTooManyLinks 0xFFFE
+#define ErrTooManyLinks 0xFFFE
/* Following error codes may be generated with the ERRSRV error class.*/
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 5f468459a1e2..746bc9405db1 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -1,10 +1,10 @@
/*
* fs/cifs/transport.c
*
- * Copyright (C) International Business Machines Corp., 2002,2005
+ * Copyright (C) International Business Machines Corp., 2002,2007
* Author(s): Steve French (sfrench@us.ibm.com)
* Jeremy Allison (jra@samba.org) 2006.
- *
+ *
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
@@ -17,7 +17,7 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/fs.h>
@@ -32,7 +32,7 @@
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
-
+
extern mempool_t *cifs_mid_poolp;
extern struct kmem_cache *cifs_oplock_cachep;
@@ -49,7 +49,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses)
cERROR(1, ("Null TCP session in AllocMidQEntry"));
return NULL;
}
-
+
temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,
GFP_KERNEL | GFP_NOFS);
if (temp == NULL)
@@ -86,7 +86,7 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
list_del(&midEntry->qhead);
atomic_dec(&midCount);
spin_unlock(&GlobalMid_Lock);
- if(midEntry->largeBuf)
+ if (midEntry->largeBuf)
cifs_buf_release(midEntry->resp_buf);
else
cifs_small_buf_release(midEntry->resp_buf);
@@ -94,8 +94,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
now = jiffies;
/* commands taking longer than one second are indications that
something is wrong, unless it is quite a slow link or server */
- if((now - midEntry->when_alloc) > HZ) {
- if((cifsFYI & CIFS_TIMER) &&
+ if ((now - midEntry->when_alloc) > HZ) {
+ if ((cifsFYI & CIFS_TIMER) &&
(midEntry->command != SMB_COM_LOCKING_ANDX)) {
printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d",
midEntry->command, midEntry->mid);
@@ -110,10 +110,10 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
}
struct oplock_q_entry *
-AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
+AllocOplockQEntry(struct inode *pinode, __u16 fid, struct cifsTconInfo *tcon)
{
struct oplock_q_entry *temp;
- if ((pinode== NULL) || (tcon == NULL)) {
+ if ((pinode == NULL) || (tcon == NULL)) {
cERROR(1, ("Null parms passed to AllocOplockQEntry"));
return NULL;
}
@@ -133,9 +133,9 @@ AllocOplockQEntry(struct inode * pinode, __u16 fid, struct cifsTconInfo * tcon)
}
-void DeleteOplockQEntry(struct oplock_q_entry * oplockEntry)
+void DeleteOplockQEntry(struct oplock_q_entry *oplockEntry)
{
- spin_lock(&GlobalMid_Lock);
+ spin_lock(&GlobalMid_Lock);
/* should we check if list empty first? */
list_del(&oplockEntry->qhead);
spin_unlock(&GlobalMid_Lock);
@@ -152,7 +152,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
struct kvec iov;
unsigned len = smb_buf_length + 4;
- if(ssocket == NULL)
+ if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */
iov.iov_base = smb_buffer;
iov.iov_len = len;
@@ -164,8 +164,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
/* smb header is converted in header_assemble. bcc and rest of SMB word
- area, and byte area if necessary, is converted to littleendian in
- cifssmb.c and RFC1001 len is converted to bigendian in smb_send
+ area, and byte area if necessary, is converted to littleendian in
+ cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Flags2 is converted in SendReceive */
smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length);
@@ -177,9 +177,9 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
i++;
/* smaller timeout here than send2 since smaller size */
- /* Although it may not be required, this also is smaller
- oplock break time */
- if(i > 12) {
+ /* Although it may not be required, this also is smaller
+ oplock break time */
+ if (i > 12) {
cERROR(1,
("sends on sock %p stuck for 7 seconds",
ssocket));
@@ -189,7 +189,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
msleep(1 << i);
continue;
}
- if (rc < 0)
+ if (rc < 0)
break;
else
i = 0; /* reset i after each successful send */
@@ -199,7 +199,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer,
}
if (rc < 0) {
- cERROR(1,("Error %d sending data on socket to server", rc));
+ cERROR(1, ("Error %d sending data on socket to server", rc));
} else {
rc = 0;
}
@@ -223,8 +223,8 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
unsigned int total_len;
int first_vec = 0;
unsigned int smb_buf_length = smb_buffer->smb_buf_length;
-
- if(ssocket == NULL)
+
+ if (ssocket == NULL)
return -ENOTSOCK; /* BB eventually add reconnect code here */
smb_msg.msg_name = sin;
@@ -234,8 +234,8 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/
/* smb header is converted in header_assemble. bcc and rest of SMB word
- area, and byte area if necessary, is converted to littleendian in
- cifssmb.c and RFC1001 len is converted to bigendian in smb_send
+ area, and byte area if necessary, is converted to littleendian in
+ cifssmb.c and RFC1001 len is converted to bigendian in smb_send
Flags2 is converted in SendReceive */
@@ -252,7 +252,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
n_vec - first_vec, total_len);
if ((rc == -ENOSPC) || (rc == -EAGAIN)) {
i++;
- if(i >= 14) {
+ if (i >= 14) {
cERROR(1,
("sends on sock %p stuck for 15 seconds",
ssocket));
@@ -262,17 +262,17 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
msleep(1 << i);
continue;
}
- if (rc < 0)
+ if (rc < 0)
break;
if (rc >= total_len) {
WARN_ON(rc > total_len);
break;
}
- if(rc == 0) {
+ if (rc == 0) {
/* should never happen, letting socket clear before
retrying is our only obvious option here */
- cERROR(1,("tcp sent no data"));
+ cERROR(1, ("tcp sent no data"));
msleep(500);
continue;
}
@@ -295,7 +295,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
}
if (rc < 0) {
- cERROR(1,("Error %d sending data on socket to server", rc));
+ cERROR(1, ("Error %d sending data on socket to server", rc));
} else
rc = 0;
@@ -308,13 +308,13 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec,
static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
{
- if(long_op == -1) {
+ if (long_op == -1) {
/* oplock breaks must not be held up */
atomic_inc(&ses->server->inFlight);
} else {
- spin_lock(&GlobalMid_Lock);
- while(1) {
- if(atomic_read(&ses->server->inFlight) >=
+ spin_lock(&GlobalMid_Lock);
+ while (1) {
+ if (atomic_read(&ses->server->inFlight) >=
cifs_max_pending){
spin_unlock(&GlobalMid_Lock);
#ifdef CONFIG_CIFS_STATS2
@@ -328,14 +328,14 @@ static int wait_for_free_request(struct cifsSesInfo *ses, const int long_op)
#endif
spin_lock(&GlobalMid_Lock);
} else {
- if(ses->server->tcpStatus == CifsExiting) {
+ if (ses->server->tcpStatus == CifsExiting) {
spin_unlock(&GlobalMid_Lock);
return -ENOENT;
}
- /* can not count locking commands against total since
- they are allowed to block on server */
-
+ /* can not count locking commands against total
+ as they are allowed to block on server */
+
/* update # of requests on the wire to server */
if (long_op < 3)
atomic_inc(&ses->server->inFlight);
@@ -353,11 +353,11 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
if (ses->server->tcpStatus == CifsExiting) {
return -ENOENT;
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
- cFYI(1,("tcp session dead - return to caller to retry"));
+ cFYI(1, ("tcp session dead - return to caller to retry"));
return -EAGAIN;
} else if (ses->status != CifsGood) {
/* check if SMB session is bad because we are setting it up */
- if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
+ if ((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) {
return -EAGAIN;
} /* else ok - we are setting up session */
@@ -369,7 +369,7 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf,
return 0;
}
-static int wait_for_response(struct cifsSesInfo *ses,
+static int wait_for_response(struct cifsSesInfo *ses,
struct mid_q_entry *midQ,
unsigned long timeout,
unsigned long time_to_wait)
@@ -379,8 +379,8 @@ static int wait_for_response(struct cifsSesInfo *ses,
for (;;) {
curr_timeout = timeout + jiffies;
wait_event(ses->server->response_q,
- (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
- time_after(jiffies, curr_timeout) ||
+ (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
+ time_after(jiffies, curr_timeout) ||
((ses->server->tcpStatus != CifsGood) &&
(ses->server->tcpStatus != CifsNew)));
@@ -398,16 +398,16 @@ static int wait_for_response(struct cifsSesInfo *ses,
spin_unlock(&GlobalMid_Lock);
/* Calculate time_to_wait past last receive time.
- Although we prefer not to time out if the
+ Although we prefer not to time out if the
server is still responding - we will time
- out if the server takes more than 15 (or 45
+ out if the server takes more than 15 (or 45
or 180) seconds to respond to this request
- and has not responded to any request from
+ and has not responded to any request from
other threads on the client within 10 seconds */
lrt += time_to_wait;
if (time_after(jiffies, lrt)) {
/* No replies for time_to_wait. */
- cERROR(1,("server not responding"));
+ cERROR(1, ("server not responding"));
return -1;
}
} else {
@@ -417,8 +417,8 @@ static int wait_for_response(struct cifsSesInfo *ses,
}
int
-SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
- struct kvec *iov, int n_vec, int * pRespBufType /* ret */,
+SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
+ struct kvec *iov, int n_vec, int *pRespBufType /* ret */,
const int long_op)
{
int rc = 0;
@@ -426,21 +426,21 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
unsigned long timeout;
struct mid_q_entry *midQ;
struct smb_hdr *in_buf = iov[0].iov_base;
-
+
*pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */
if ((ses == NULL) || (ses->server == NULL)) {
cifs_small_buf_release(in_buf);
- cERROR(1,("Null session"));
+ cERROR(1, ("Null session"));
return -EIO;
}
- if(ses->server->tcpStatus == CifsExiting) {
+ if (ses->server->tcpStatus == CifsExiting) {
cifs_small_buf_release(in_buf);
return -ENOENT;
}
- /* Ensure that we do not send more than 50 overlapping requests
+ /* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or
use ses->maxReq */
@@ -450,23 +450,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
return rc;
}
- /* make sure that we sign in the same order that we send on this socket
+ /* make sure that we sign in the same order that we send on this socket
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
- down(&ses->server->tcpSem);
+ down(&ses->server->tcpSem);
rc = allocate_mid(ses, in_buf, &midQ);
if (rc) {
up(&ses->server->tcpSem);
cifs_small_buf_release(in_buf);
/* Update # of requests on wire to server */
- atomic_dec(&ses->server->inFlight);
+ atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
- rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
+ rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number);
midQ->midState = MID_REQUEST_SUBMITTED;
#ifdef CONFIG_CIFS_STATS2
@@ -482,7 +482,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
up(&ses->server->tcpSem);
cifs_small_buf_release(in_buf);
- if(rc < 0)
+ if (rc < 0)
goto out;
if (long_op == -1)
@@ -490,18 +490,18 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
else if (long_op == 2) /* writes past end of file can take loong time */
timeout = 180 * HZ;
else if (long_op == 1)
- timeout = 45 * HZ; /* should be greater than
+ timeout = 45 * HZ; /* should be greater than
servers oplock break timeout (about 43 seconds) */
else
timeout = 15 * HZ;
- /* wait for 15 seconds or until woken up due to response arriving or
+ /* wait for 15 seconds or until woken up due to response arriving or
due to last connection to this server being unmounted */
if (signal_pending(current)) {
/* if signal pending do not hold up user for full smb timeout
but we still give response a chance to complete */
timeout = 2 * HZ;
- }
+ }
/* No user interrupts in wait - wreaks havoc with performance */
wait_for_response(ses, midQ, timeout, 10 * HZ);
@@ -511,10 +511,10 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length;
} else {
- cERROR(1,("No response to cmd %d mid %d",
+ cERROR(1, ("No response to cmd %d mid %d",
midQ->command, midQ->mid));
- if(midQ->midState == MID_REQUEST_SUBMITTED) {
- if(ses->server->tcpStatus == CifsExiting)
+ if (midQ->midState == MID_REQUEST_SUBMITTED) {
+ if (ses->server->tcpStatus == CifsExiting)
rc = -EHOSTDOWN;
else {
ses->server->tcpStatus = CifsNeedReconnect;
@@ -523,9 +523,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
}
if (rc != -EHOSTDOWN) {
- if(midQ->midState == MID_RETRY_NEEDED) {
+ if (midQ->midState == MID_RETRY_NEEDED) {
rc = -EAGAIN;
- cFYI(1,("marking request for retry"));
+ cFYI(1, ("marking request for retry"));
} else {
rc = -EIO;
}
@@ -533,21 +533,21 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
spin_unlock(&GlobalMid_Lock);
DeleteMidQEntry(midQ);
/* Update # of requests on wire to server */
- atomic_dec(&ses->server->inFlight);
+ atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
-
+
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
receive_len, xid));
rc = -EIO;
} else { /* rcvd frame is ok */
- if (midQ->resp_buf &&
+ if (midQ->resp_buf &&
(midQ->midState == MID_RESPONSE_RECEIVED)) {
iov[0].iov_base = (char *)midQ->resp_buf;
- if(midQ->largeBuf)
+ if (midQ->largeBuf)
*pRespBufType = CIFS_LARGE_BUFFER;
else
*pRespBufType = CIFS_SMALL_BUFFER;
@@ -555,14 +555,14 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
dump_smb(midQ->resp_buf, 80);
/* convert the length into a more usable form */
- if((receive_len > 24) &&
+ if ((receive_len > 24) &&
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(midQ->resp_buf,
- ses->server->mac_signing_key,
+ &ses->server->mac_signing_key,
midQ->sequence_number+1);
- if(rc) {
- cERROR(1,("Unexpected SMB signature"));
+ if (rc) {
+ cERROR(1, ("Unexpected SMB signature"));
/* BB FIXME add code to kill session */
}
}
@@ -576,19 +576,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
sizeof (struct smb_hdr) -
4 /* do not count RFC1001 header */ +
(2 * midQ->resp_buf->WordCount) + 2 /* bcc */ )
- BCC(midQ->resp_buf) =
+ BCC(midQ->resp_buf) =
le16_to_cpu(BCC_LE(midQ->resp_buf));
midQ->resp_buf = NULL; /* mark it so will not be freed
by DeleteMidQEntry */
} else {
rc = -EIO;
- cFYI(1,("Bad MID state?"));
+ cFYI(1, ("Bad MID state?"));
}
}
out:
DeleteMidQEntry(midQ);
- atomic_dec(&ses->server->inFlight);
+ atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
@@ -605,18 +605,18 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
struct mid_q_entry *midQ;
if (ses == NULL) {
- cERROR(1,("Null smb session"));
+ cERROR(1, ("Null smb session"));
return -EIO;
}
- if(ses->server == NULL) {
- cERROR(1,("Null tcp session"));
+ if (ses->server == NULL) {
+ cERROR(1, ("Null tcp session"));
return -EIO;
}
- if(ses->server->tcpStatus == CifsExiting)
+ if (ses->server->tcpStatus == CifsExiting)
return -ENOENT;
- /* Ensure that we do not send more than 50 overlapping requests
+ /* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or
use ses->maxReq */
@@ -624,17 +624,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
if (rc)
return rc;
- /* make sure that we sign in the same order that we send on this socket
+ /* make sure that we sign in the same order that we send on this socket
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
- down(&ses->server->tcpSem);
+ down(&ses->server->tcpSem);
rc = allocate_mid(ses, in_buf, &midQ);
if (rc) {
up(&ses->server->tcpSem);
/* Update # of requests on wire to server */
- atomic_dec(&ses->server->inFlight);
+ atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
@@ -645,7 +645,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
DeleteMidQEntry(midQ);
up(&ses->server->tcpSem);
/* Update # of requests on wire to server */
- atomic_dec(&ses->server->inFlight);
+ atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return -EIO;
}
@@ -664,7 +664,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
#endif
up(&ses->server->tcpSem);
- if(rc < 0)
+ if (rc < 0)
goto out;
if (long_op == -1)
@@ -672,17 +672,17 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
else if (long_op == 2) /* writes past end of file can take loong time */
timeout = 180 * HZ;
else if (long_op == 1)
- timeout = 45 * HZ; /* should be greater than
+ timeout = 45 * HZ; /* should be greater than
servers oplock break timeout (about 43 seconds) */
else
timeout = 15 * HZ;
- /* wait for 15 seconds or until woken up due to response arriving or
+ /* wait for 15 seconds or until woken up due to response arriving or
due to last connection to this server being unmounted */
if (signal_pending(current)) {
/* if signal pending do not hold up user for full smb timeout
but we still give response a chance to complete */
timeout = 2 * HZ;
- }
+ }
/* No user interrupts in wait - wreaks havoc with performance */
wait_for_response(ses, midQ, timeout, 10 * HZ);
@@ -692,10 +692,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length;
} else {
- cERROR(1,("No response for cmd %d mid %d",
+ cERROR(1, ("No response for cmd %d mid %d",
midQ->command, midQ->mid));
- if(midQ->midState == MID_REQUEST_SUBMITTED) {
- if(ses->server->tcpStatus == CifsExiting)
+ if (midQ->midState == MID_REQUEST_SUBMITTED) {
+ if (ses->server->tcpStatus == CifsExiting)
rc = -EHOSTDOWN;
else {
ses->server->tcpStatus = CifsNeedReconnect;
@@ -704,9 +704,9 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
}
if (rc != -EHOSTDOWN) {
- if(midQ->midState == MID_RETRY_NEEDED) {
+ if (midQ->midState == MID_RETRY_NEEDED) {
rc = -EAGAIN;
- cFYI(1,("marking request for retry"));
+ cFYI(1, ("marking request for retry"));
} else {
rc = -EIO;
}
@@ -714,11 +714,11 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
spin_unlock(&GlobalMid_Lock);
DeleteMidQEntry(midQ);
/* Update # of requests on wire to server */
- atomic_dec(&ses->server->inFlight);
+ atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
}
-
+
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
receive_len, xid));
@@ -734,14 +734,14 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
dump_smb(out_buf, 92);
/* convert the length into a more usable form */
- if((receive_len > 24) &&
+ if ((receive_len > 24) &&
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf,
- ses->server->mac_signing_key,
+ &ses->server->mac_signing_key,
midQ->sequence_number+1);
- if(rc) {
- cERROR(1,("Unexpected SMB signature"));
+ if (rc) {
+ cERROR(1, ("Unexpected SMB signature"));
/* BB FIXME add code to kill session */
}
}
@@ -759,13 +759,13 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
} else {
rc = -EIO;
- cERROR(1,("Bad MID state?"));
+ cERROR(1, ("Bad MID state?"));
}
}
out:
DeleteMidQEntry(midQ);
- atomic_dec(&ses->server->inFlight);
+ atomic_dec(&ses->server->inFlight);
wake_up(&ses->server->request_q);
return rc;
@@ -783,7 +783,7 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf,
header_assemble(in_buf, SMB_COM_NT_CANCEL, tcon, 0);
in_buf->Mid = mid;
- down(&ses->server->tcpSem);
+ down(&ses->server->tcpSem);
rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
if (rc) {
up(&ses->server->tcpSem);
@@ -832,20 +832,20 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
struct cifsSesInfo *ses;
if (tcon == NULL || tcon->ses == NULL) {
- cERROR(1,("Null smb session"));
+ cERROR(1, ("Null smb session"));
return -EIO;
}
ses = tcon->ses;
- if(ses->server == NULL) {
- cERROR(1,("Null tcp session"));
+ if (ses->server == NULL) {
+ cERROR(1, ("Null tcp session"));
return -EIO;
}
- if(ses->server->tcpStatus == CifsExiting)
+ if (ses->server->tcpStatus == CifsExiting)
return -ENOENT;
- /* Ensure that we do not send more than 50 overlapping requests
+ /* Ensure that we do not send more than 50 overlapping requests
to the same server. We may make this configurable later or
use ses->maxReq */
@@ -853,11 +853,11 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
if (rc)
return rc;
- /* make sure that we sign in the same order that we send on this socket
+ /* make sure that we sign in the same order that we send on this socket
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
- down(&ses->server->tcpSem);
+ down(&ses->server->tcpSem);
rc = allocate_mid(ses, in_buf, &midQ);
if (rc) {
@@ -887,14 +887,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
#endif
up(&ses->server->tcpSem);
- if(rc < 0) {
+ if (rc < 0) {
DeleteMidQEntry(midQ);
return rc;
}
/* Wait for a reply - allow signals to interrupt. */
rc = wait_event_interruptible(ses->server->response_q,
- (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
+ (!(midQ->midState == MID_REQUEST_SUBMITTED)) ||
((ses->server->tcpStatus != CifsGood) &&
(ses->server->tcpStatus != CifsNew)));
@@ -928,7 +928,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
}
/* Wait 5 seconds for the response. */
- if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ)==0) {
+ if (wait_for_response(ses, midQ, 5 * HZ, 5 * HZ) == 0) {
/* We got the response - restart system call. */
rstart = 1;
}
@@ -939,10 +939,10 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
spin_unlock(&GlobalMid_Lock);
receive_len = midQ->resp_buf->smb_buf_length;
} else {
- cERROR(1,("No response for cmd %d mid %d",
+ cERROR(1, ("No response for cmd %d mid %d",
midQ->command, midQ->mid));
- if(midQ->midState == MID_REQUEST_SUBMITTED) {
- if(ses->server->tcpStatus == CifsExiting)
+ if (midQ->midState == MID_REQUEST_SUBMITTED) {
+ if (ses->server->tcpStatus == CifsExiting)
rc = -EHOSTDOWN;
else {
ses->server->tcpStatus = CifsNeedReconnect;
@@ -951,9 +951,9 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
}
if (rc != -EHOSTDOWN) {
- if(midQ->midState == MID_RETRY_NEEDED) {
+ if (midQ->midState == MID_RETRY_NEEDED) {
rc = -EAGAIN;
- cFYI(1,("marking request for retry"));
+ cFYI(1, ("marking request for retry"));
} else {
rc = -EIO;
}
@@ -962,7 +962,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
DeleteMidQEntry(midQ);
return rc;
}
-
+
if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
cERROR(1, ("Frame too large received. Length: %d Xid: %d",
receive_len, xid));
@@ -978,14 +978,14 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
dump_smb(out_buf, 92);
/* convert the length into a more usable form */
- if((receive_len > 24) &&
+ if ((receive_len > 24) &&
(ses->server->secMode & (SECMODE_SIGN_REQUIRED |
SECMODE_SIGN_ENABLED))) {
rc = cifs_verify_signature(out_buf,
- ses->server->mac_signing_key,
+ &ses->server->mac_signing_key,
midQ->sequence_number+1);
- if(rc) {
- cERROR(1,("Unexpected SMB signature"));
+ if (rc) {
+ cERROR(1, ("Unexpected SMB signature"));
/* BB FIXME add code to kill session */
}
}
@@ -1003,7 +1003,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon,
BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf));
} else {
rc = -EIO;
- cERROR(1,("Bad MID state?"));
+ cERROR(1, ("Bad MID state?"));
}
}
DeleteMidQEntry(midQ);
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 18fcec190f8b..f61e433d281c 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -1,7 +1,7 @@
/*
* fs/cifs/xattr.c
*
- * Copyright (c) International Business Machines Corp., 2003
+ * Copyright (c) International Business Machines Corp., 2003, 2007
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
@@ -37,50 +37,52 @@
#define XATTR_TRUSTED_PREFIX_LEN 8
#define XATTR_SECURITY_PREFIX_LEN 9
/* BB need to add server (Samba e.g) support for security and trusted prefix */
-
-int cifs_removexattr(struct dentry * direntry, const char * ea_name)
+
+int cifs_removexattr(struct dentry *direntry, const char *ea_name)
{
int rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
int xid;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- struct super_block * sb;
- char * full_path;
-
- if(direntry == NULL)
+ struct super_block *sb;
+ char *full_path;
+
+ if (direntry == NULL)
return -EIO;
- if(direntry->d_inode == NULL)
+ if (direntry->d_inode == NULL)
return -EIO;
sb = direntry->d_inode->i_sb;
- if(sb == NULL)
+ if (sb == NULL)
return -EIO;
xid = GetXid();
-
+
cifs_sb = CIFS_SB(sb);
pTcon = cifs_sb->tcon;
-
+
full_path = build_path_from_dentry(direntry);
- if(full_path == NULL) {
+ if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
- if(ea_name == NULL) {
- cFYI(1,("Null xattr names not supported"));
- } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5)
- && (strncmp(ea_name,CIFS_XATTR_OS2_PREFIX,4))) {
- cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name));
+ if (ea_name == NULL) {
+ cFYI(1, ("Null xattr names not supported"));
+ } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
+ && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
+ cFYI(1,
+ ("illegal xattr request %s (only user namespace supported)",
+ ea_name));
/* BB what if no namespace prefix? */
/* Should we just pass them to server, except for
system and perhaps security prefixes? */
} else {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto remove_ea_exit;
- ea_name+=5; /* skip past user. prefix */
- rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL,
+ ea_name += 5; /* skip past user. prefix */
+ rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
(__u16)0, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
}
@@ -91,23 +93,23 @@ remove_ea_exit:
return rc;
}
-int cifs_setxattr(struct dentry * direntry, const char * ea_name,
- const void * ea_value, size_t value_size, int flags)
+int cifs_setxattr(struct dentry *direntry, const char *ea_name,
+ const void *ea_value, size_t value_size, int flags)
{
int rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
int xid;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- struct super_block * sb;
- char * full_path;
+ struct super_block *sb;
+ char *full_path;
- if(direntry == NULL)
+ if (direntry == NULL)
return -EIO;
- if(direntry->d_inode == NULL)
+ if (direntry->d_inode == NULL)
return -EIO;
sb = direntry->d_inode->i_sb;
- if(sb == NULL)
+ if (sb == NULL)
return -EIO;
xid = GetXid();
@@ -115,7 +117,7 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
- if(full_path == NULL) {
+ if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
@@ -123,67 +125,69 @@ int cifs_setxattr(struct dentry * direntry, const char * ea_name,
/* return alt name if available as pseudo attr */
/* if proc/fs/cifs/streamstoxattr is set then
- search server for EAs or streams to
+ search server for EAs or streams to
returns as xattrs */
- if(value_size > MAX_EA_VALUE_SIZE) {
- cFYI(1,("size of EA value too large"));
+ if (value_size > MAX_EA_VALUE_SIZE) {
+ cFYI(1, ("size of EA value too large"));
kfree(full_path);
FreeXid(xid);
return -EOPNOTSUPP;
}
- if(ea_name == NULL) {
- cFYI(1,("Null xattr names not supported"));
- } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (ea_name == NULL) {
+ cFYI(1, ("Null xattr names not supported"));
+ } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit;
- if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
- cFYI(1,("attempt to set cifs inode metadata"));
+ if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
+ cFYI(1, ("attempt to set cifs inode metadata"));
}
ea_name += 5; /* skip past user. prefix */
- rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
+ rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
(__u16)value_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto set_ea_exit;
ea_name += 4; /* skip past os2. prefix */
- rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value,
+ rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
(__u16)value_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
} else {
- int temp;
- temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
+ int temp;
+ temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS));
if (temp == 0) {
#ifdef CONFIG_CIFS_POSIX
- if(sb->s_flags & MS_POSIXACL)
- rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
- ea_value, (const int)value_size,
- ACL_TYPE_ACCESS,cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ if (sb->s_flags & MS_POSIXACL)
+ rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
+ ea_value, (const int)value_size,
+ ACL_TYPE_ACCESS, cifs_sb->local_nls,
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- cFYI(1,("set POSIX ACL rc %d",rc));
+ cFYI(1, ("set POSIX ACL rc %d", rc));
#else
- cFYI(1,("set POSIX ACL not supported"));
+ cFYI(1, ("set POSIX ACL not supported"));
#endif
- } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+ } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
+ strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
- if(sb->s_flags & MS_POSIXACL)
- rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,
- ea_value, (const int)value_size,
+ if (sb->s_flags & MS_POSIXACL)
+ rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
+ ea_value, (const int)value_size,
ACL_TYPE_DEFAULT, cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
- cFYI(1,("set POSIX default ACL rc %d",rc));
+ cFYI(1, ("set POSIX default ACL rc %d", rc));
#else
- cFYI(1,("set default POSIX ACL not supported"));
+ cFYI(1, ("set default POSIX ACL not supported"));
#endif
} else {
- cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name));
+ cFYI(1, ("illegal xattr request %s (only user namespace"
+ " supported)", ea_name));
/* BB what if no namespace prefix? */
- /* Should we just pass them to server, except for
+ /* Should we just pass them to server, except for
system and perhaps security prefixes? */
}
}
@@ -195,23 +199,23 @@ set_ea_exit:
return rc;
}
-ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
- void * ea_value, size_t buf_size)
+ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
+ void *ea_value, size_t buf_size)
{
ssize_t rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
int xid;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- struct super_block * sb;
- char * full_path;
+ struct super_block *sb;
+ char *full_path;
- if(direntry == NULL)
+ if (direntry == NULL)
return -EIO;
- if(direntry->d_inode == NULL)
+ if (direntry->d_inode == NULL)
return -EIO;
sb = direntry->d_inode->i_sb;
- if(sb == NULL)
+ if (sb == NULL)
return -EIO;
xid = GetXid();
@@ -220,42 +224,42 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
- if(full_path == NULL) {
+ if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
/* return dos attributes as pseudo xattr */
/* return alt name if available as pseudo attr */
- if(ea_name == NULL) {
- cFYI(1,("Null xattr names not supported"));
- } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (ea_name == NULL) {
+ cFYI(1, ("Null xattr names not supported"));
+ } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit;
- if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) {
- cFYI(1,("attempt to query cifs inode metadata"));
+ if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
+ cFYI(1, ("attempt to query cifs inode metadata"));
/* revalidate/getattr then populate from inode */
} /* BB add else when above is implemented */
ea_name += 5; /* skip past user. prefix */
- rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
+ rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) {
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
goto get_ea_exit;
ea_name += 4; /* skip past os2. prefix */
- rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value,
+ rc = CIFSSMBQueryEA(xid, pTcon, full_path, ea_name, ea_value,
buf_size, cifs_sb->local_nls,
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
- } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,
+ } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX
- if(sb->s_flags & MS_POSIXACL)
+ if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
- ea_value, buf_size, ACL_TYPE_ACCESS,
+ ea_value, buf_size, ACL_TYPE_ACCESS,
cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
/* else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) {
__u16 fid;
@@ -272,39 +276,40 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name,
CIFSSMBClose(xid, pTcon, fid);
}
} */ /* BB enable after fixing up return data */
-
-#else
- cFYI(1,("query POSIX ACL not supported yet"));
+#else
+ cFYI(1, ("query POSIX ACL not supported yet"));
#endif /* CONFIG_CIFS_POSIX */
- } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,
+ } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
- if(sb->s_flags & MS_POSIXACL)
+ if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
- ea_value, buf_size, ACL_TYPE_DEFAULT,
+ ea_value, buf_size, ACL_TYPE_DEFAULT,
cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
-#else
- cFYI(1,("query POSIX default ACL not supported yet"));
+#else
+ cFYI(1, ("query POSIX default ACL not supported yet"));
#endif
- } else if(strncmp(ea_name,
- CIFS_XATTR_TRUSTED_PREFIX,XATTR_TRUSTED_PREFIX_LEN) == 0) {
- cFYI(1,("Trusted xattr namespace not supported yet"));
- } else if(strncmp(ea_name,
- CIFS_XATTR_SECURITY_PREFIX,XATTR_SECURITY_PREFIX_LEN) == 0) {
- cFYI(1,("Security xattr namespace not supported yet"));
+ } else if (strncmp(ea_name,
+ CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
+ cFYI(1, ("Trusted xattr namespace not supported yet"));
+ } else if (strncmp(ea_name,
+ CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
+ cFYI(1, ("Security xattr namespace not supported yet"));
} else {
- cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name));
+ cFYI(1,
+ ("illegal xattr request %s (only user namespace supported)",
+ ea_name));
}
- /* We could add an additional check for streams ie
+ /* We could add an additional check for streams ie
if proc/fs/cifs/streamstoxattr is set then
- search server for EAs or streams to
+ search server for EAs or streams to
returns as xattrs */
- if(rc == -EINVAL)
- rc = -EOPNOTSUPP;
+ if (rc == -EINVAL)
+ rc = -EOPNOTSUPP;
get_ea_exit:
kfree(full_path);
@@ -313,34 +318,34 @@ get_ea_exit:
return rc;
}
-ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
+ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
{
ssize_t rc = -EOPNOTSUPP;
#ifdef CONFIG_CIFS_XATTR
int xid;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
- struct super_block * sb;
- char * full_path;
+ struct super_block *sb;
+ char *full_path;
- if(direntry == NULL)
+ if (direntry == NULL)
return -EIO;
- if(direntry->d_inode == NULL)
+ if (direntry->d_inode == NULL)
return -EIO;
sb = direntry->d_inode->i_sb;
- if(sb == NULL)
+ if (sb == NULL)
return -EIO;
cifs_sb = CIFS_SB(sb);
pTcon = cifs_sb->tcon;
- if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
return -EOPNOTSUPP;
xid = GetXid();
full_path = build_path_from_dentry(direntry);
- if(full_path == NULL) {
+ if (full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
@@ -348,11 +353,11 @@ ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size)
/* return alt name if available as pseudo attr */
/* if proc/fs/cifs/streamstoxattr is set then
- search server for EAs or streams to
+ search server for EAs or streams to
returns as xattrs */
- rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size,
+ rc = CIFSSMBQAllEAs(xid, pTcon, full_path, data, buf_size,
cifs_sb->local_nls,
- cifs_sb->mnt_cifs_flags &
+ cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
kfree(full_path);
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index fcb88fa8d2f2..8a2370341c7a 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -43,17 +43,12 @@ void coda_cache_enter(struct inode *inode, int mask)
void coda_cache_clear_inode(struct inode *inode)
{
struct coda_inode_info *cii = ITOC(inode);
- cii->c_cached_perm = 0;
+ cii->c_cached_epoch = atomic_read(&permission_epoch) - 1;
}
/* remove all acl caches */
void coda_cache_clear_all(struct super_block *sb)
{
- struct coda_sb_info *sbi;
-
- sbi = coda_sbp(sb);
- BUG_ON(!sbi);
-
atomic_inc(&permission_epoch);
}
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 28c872747f81..a7a780929eec 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -55,11 +55,6 @@ static int coda_set_inode(struct inode *inode, void *data)
return 0;
}
-static int coda_fail_inode(struct inode *inode, void *data)
-{
- return -1;
-}
-
struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
struct coda_vattr * attr)
{
@@ -141,7 +136,7 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
return NULL;
}
- inode = iget5_locked(sb, hash, coda_test_inode, coda_fail_inode, fid);
+ inode = ilookup5(sb, hash, coda_test_inode, fid);
if ( !inode )
return NULL;
diff --git a/fs/coda/coda_int.h b/fs/coda/coda_int.h
index 9e6338fea514..8ccd5ed81d9c 100644
--- a/fs/coda/coda_int.h
+++ b/fs/coda/coda_int.h
@@ -1,12 +1,19 @@
#ifndef _CODA_INT_
#define _CODA_INT_
+struct dentry;
+
extern struct file_system_type coda_fs_type;
+extern unsigned long coda_timeout;
+extern int coda_hard;
+extern int coda_fake_statfs;
void coda_destroy_inodecache(void);
int coda_init_inodecache(void);
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry,
int datasync);
+void coda_sysctl_init(void);
+void coda_sysctl_clean(void);
#endif /* _CODA_INT_ */
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 9ddf5ed62162..f89ff083079b 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -25,7 +25,6 @@
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
-#include <linux/coda_proc.h>
#include "coda_int.h"
@@ -43,15 +42,15 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
struct inode *new_inode, struct dentry *new_dentry);
/* dir file-ops */
-static int coda_readdir(struct file *file, void *dirent, filldir_t filldir);
+static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
/* dentry ops */
static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
static int coda_dentry_delete(struct dentry *);
/* support routines */
-static int coda_venus_readdir(struct file *filp, filldir_t filldir,
- void *dirent, struct dentry *dir);
+static int coda_venus_readdir(struct file *coda_file, void *buf,
+ filldir_t filldir);
/* same as fs/bad_inode.c */
static int coda_return_EIO(void)
@@ -87,7 +86,6 @@ const struct file_operations coda_dir_operations = {
.read = generic_read_dir,
.readdir = coda_readdir,
.open = coda_open,
- .flush = coda_flush,
.release = coda_release,
.fsync = coda_fsync,
};
@@ -97,58 +95,45 @@ const struct file_operations coda_dir_operations = {
/* access routines: lookup, readlink, permission */
static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
{
- struct inode *res_inode = NULL;
+ struct inode *inode = NULL;
struct CodaFid resfid = { { 0, } };
- int dropme = 0; /* to indicate entry should not be cached */
int type = 0;
int error = 0;
const char *name = entry->d_name.name;
size_t length = entry->d_name.len;
-
- if ( length > CODA_MAXNAMLEN ) {
- printk("name too long: lookup, %s (%*s)\n",
+
+ if (length > CODA_MAXNAMLEN) {
+ printk(KERN_ERR "name too long: lookup, %s (%*s)\n",
coda_i2s(dir), (int)length, name);
return ERR_PTR(-ENAMETOOLONG);
}
+ /* control object, create inode on the fly */
+ if (coda_isroot(dir) && coda_iscontrol(name, length)) {
+ error = coda_cnode_makectl(&inode, dir->i_sb);
+ type = CODA_NOCACHE;
+ goto exit;
+ }
+
lock_kernel();
- /* control object, create inode on the fly */
- if (coda_isroot(dir) && coda_iscontrol(name, length)) {
- error = coda_cnode_makectl(&res_inode, dir->i_sb);
- dropme = 1;
- goto exit;
- }
- error = venus_lookup(dir->i_sb, coda_i2f(dir),
- (const char *)name, length, &type, &resfid);
+ error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
+ &type, &resfid);
+ if (!error)
+ error = coda_cnode_make(&inode, &resfid, dir->i_sb);
- res_inode = NULL;
- if (!error) {
- if (type & CODA_NOCACHE) {
- type &= (~CODA_NOCACHE);
- dropme = 1;
- }
+ unlock_kernel();
- error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
- if (error) {
- unlock_kernel();
- return ERR_PTR(error);
- }
- } else if (error != -ENOENT) {
- unlock_kernel();
+ if (error && error != -ENOENT)
return ERR_PTR(error);
- }
exit:
- entry->d_time = 0;
entry->d_op = &coda_dentry_operations;
- d_add(entry, res_inode);
- if ( dropme ) {
- d_drop(entry);
- coda_flag_inode(res_inode, C_VATTR);
- }
- unlock_kernel();
- return NULL;
+
+ if (inode && (type & CODA_NOCACHE))
+ coda_flag_inode(inode, C_VATTR | C_PURGE);
+
+ return d_splice_alias(inode, entry);
}
@@ -161,8 +146,6 @@ int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
lock_kernel();
- coda_vfs_stat.permission++;
-
if (coda_cache_check(inode, mask))
goto out;
@@ -173,12 +156,11 @@ int coda_permission(struct inode *inode, int mask, struct nameidata *nd)
out:
unlock_kernel();
-
- return error;
+ return error;
}
-static inline void coda_dir_changed(struct inode *dir, int link)
+static inline void coda_dir_update_mtime(struct inode *dir)
{
#ifdef REQUERY_VENUS_FOR_MTIME
/* invalidate the directory cnode's attributes so we refetch the
@@ -186,12 +168,27 @@ static inline void coda_dir_changed(struct inode *dir, int link)
coda_flag_inode(dir, C_VATTR);
#else
/* optimistically we can also act as if our nose bleeds. The
- * granularity of the mtime is coarse anyways so we might actually be
- * right most of the time. Note: we only do this for directories. */
+ * granularity of the mtime is coarse anyways so we might actually be
+ * right most of the time. Note: we only do this for directories. */
dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
#endif
- if (link)
- dir->i_nlink += link;
+}
+
+/* we have to wrap inc_nlink/drop_nlink because sometimes userspace uses a
+ * trick to fool GNU find's optimizations. If we can't be sure of the link
+ * (because of volume mount points) we set i_nlink to 1 which forces find
+ * to consider every child as a possible directory. We should also never
+ * see an increment or decrement for deleted directories where i_nlink == 0 */
+static inline void coda_dir_inc_nlink(struct inode *dir)
+{
+ if (dir->i_nlink >= 2)
+ inc_nlink(dir);
+}
+
+static inline void coda_dir_drop_nlink(struct inode *dir)
+{
+ if (dir->i_nlink > 2)
+ drop_nlink(dir);
}
/* creation routines: create, mknod, mkdir, link, symlink */
@@ -205,7 +202,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na
struct coda_vattr attrs;
lock_kernel();
- coda_vfs_stat.create++;
if (coda_isroot(dir) && coda_iscontrol(name, length)) {
unlock_kernel();
@@ -229,10 +225,10 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode, struct na
}
/* invalidate the directory cnode's attributes */
- coda_dir_changed(dir, 0);
+ coda_dir_update_mtime(dir);
unlock_kernel();
d_instantiate(de, inode);
- return 0;
+ return 0;
}
static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
@@ -245,7 +241,6 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
struct CodaFid newfid;
lock_kernel();
- coda_vfs_stat.mkdir++;
if (coda_isroot(dir) && coda_iscontrol(name, len)) {
unlock_kernel();
@@ -268,12 +263,13 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
d_drop(de);
return PTR_ERR(inode);
}
-
+
/* invalidate the directory cnode's attributes */
- coda_dir_changed(dir, 1);
+ coda_dir_inc_nlink(dir);
+ coda_dir_update_mtime(dir);
unlock_kernel();
d_instantiate(de, inode);
- return 0;
+ return 0;
}
/* try to make de an entry in dir_inodde linked to source_de */
@@ -286,7 +282,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
int error;
lock_kernel();
- coda_vfs_stat.link++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
unlock_kernel();
@@ -296,16 +291,16 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
error = venus_link(dir_inode->i_sb, coda_i2f(inode),
coda_i2f(dir_inode), (const char *)name, len);
- if (error) {
+ if (error) {
d_drop(de);
goto out;
}
- coda_dir_changed(dir_inode, 0);
+ coda_dir_update_mtime(dir_inode);
atomic_inc(&inode->i_count);
d_instantiate(de, inode);
inc_nlink(inode);
-
+
out:
unlock_kernel();
return(error);
@@ -318,10 +313,9 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
const char *name = de->d_name.name;
int len = de->d_name.len;
int symlen;
- int error=0;
-
+ int error = 0;
+
lock_kernel();
- coda_vfs_stat.symlink++;
if (coda_isroot(dir_inode) && coda_iscontrol(name, len)) {
unlock_kernel();
@@ -336,18 +330,18 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
/*
* This entry is now negative. Since we do not create
- * an inode for the entry we have to drop it.
+ * an inode for the entry we have to drop it.
*/
d_drop(de);
- error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
+ error = venus_symlink(dir_inode->i_sb, coda_i2f(dir_inode), name, len,
symname, symlen);
/* mtime is no good anymore */
if ( !error )
- coda_dir_changed(dir_inode, 0);
+ coda_dir_update_mtime(dir_inode);
unlock_kernel();
- return error;
+ return error;
}
/* destruction routines: unlink, rmdir */
@@ -358,79 +352,70 @@ int coda_unlink(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
lock_kernel();
- coda_vfs_stat.unlink++;
- error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
- if ( error ) {
+ error = venus_remove(dir->i_sb, coda_i2f(dir), name, len);
+ if ( error ) {
unlock_kernel();
- return error;
- }
+ return error;
+ }
- coda_dir_changed(dir, 0);
+ coda_dir_update_mtime(dir);
drop_nlink(de->d_inode);
unlock_kernel();
-
- return 0;
+ return 0;
}
int coda_rmdir(struct inode *dir, struct dentry *de)
{
const char *name = de->d_name.name;
int len = de->d_name.len;
- int error;
+ int error;
lock_kernel();
- coda_vfs_stat.rmdir++;
- if (!d_unhashed(de)) {
- unlock_kernel();
- return -EBUSY;
- }
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
+ if (!error) {
+ /* VFS may delete the child */
+ if (de->d_inode)
+ de->d_inode->i_nlink = 0;
- if ( error ) {
- unlock_kernel();
- return error;
- }
-
- coda_dir_changed(dir, -1);
- drop_nlink(de->d_inode);
- d_delete(de);
+ /* fix the link count of the parent */
+ coda_dir_drop_nlink(dir);
+ coda_dir_update_mtime(dir);
+ }
unlock_kernel();
-
- return 0;
+ return error;
}
/* rename */
-static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
+static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
- const char *old_name = old_dentry->d_name.name;
- const char *new_name = new_dentry->d_name.name;
+ const char *old_name = old_dentry->d_name.name;
+ const char *new_name = new_dentry->d_name.name;
int old_length = old_dentry->d_name.len;
int new_length = new_dentry->d_name.len;
- int link_adjust = 0;
- int error;
+ int error;
lock_kernel();
- coda_vfs_stat.rename++;
- error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
- coda_i2f(new_dir), old_length, new_length,
+ error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
+ coda_i2f(new_dir), old_length, new_length,
(const char *) old_name, (const char *)new_name);
- if ( !error ) {
+ if ( !error ) {
if ( new_dentry->d_inode ) {
- if ( S_ISDIR(new_dentry->d_inode->i_mode) )
- link_adjust = 1;
-
- coda_dir_changed(old_dir, -link_adjust);
- coda_dir_changed(new_dir, link_adjust);
+ if ( S_ISDIR(new_dentry->d_inode->i_mode) ) {
+ coda_dir_drop_nlink(old_dir);
+ coda_dir_inc_nlink(new_dir);
+ }
+ coda_dir_update_mtime(old_dir);
+ coda_dir_update_mtime(new_dir);
coda_flag_inode(new_dentry->d_inode, C_VATTR);
} else {
coda_flag_inode(old_dir, C_VATTR);
coda_flag_inode(new_dir, C_VATTR);
- }
+ }
}
unlock_kernel();
@@ -439,44 +424,41 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
/* file operations for directories */
-int coda_readdir(struct file *coda_file, void *dirent, filldir_t filldir)
+int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
{
- struct dentry *coda_dentry = coda_file->f_path.dentry;
struct coda_file_info *cfi;
struct file *host_file;
- struct inode *host_inode;
int ret;
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;
- coda_vfs_stat.readdir++;
-
- host_inode = host_file->f_path.dentry->d_inode;
- mutex_lock(&host_inode->i_mutex);
- host_file->f_pos = coda_file->f_pos;
-
- if (!host_file->f_op->readdir) {
- /* Venus: we must read Venus dirents from the file */
- ret = coda_venus_readdir(host_file, filldir, dirent, coda_dentry);
- } else {
- /* potemkin case: we were handed a directory inode. */
- /* Yuk, we can't call vfs_readdir because we are already
- * holding the inode semaphore. */
- ret = -ENOTDIR;
- if (!host_file->f_op || !host_file->f_op->readdir)
- goto out;
+ if (!host_file->f_op)
+ return -ENOTDIR;
+
+ if (host_file->f_op->readdir)
+ {
+ /* potemkin case: we were handed a directory inode.
+ * We can't use vfs_readdir because we have to keep the file
+ * position in sync between the coda_file and the host_file.
+ * and as such we need grab the inode mutex. */
+ struct inode *host_inode = host_file->f_path.dentry->d_inode;
+
+ mutex_lock(&host_inode->i_mutex);
+ host_file->f_pos = coda_file->f_pos;
ret = -ENOENT;
if (!IS_DEADDIR(host_inode)) {
- ret = host_file->f_op->readdir(host_file, filldir, dirent);
+ ret = host_file->f_op->readdir(host_file, buf, filldir);
file_accessed(host_file);
}
+
+ coda_file->f_pos = host_file->f_pos;
+ mutex_unlock(&host_inode->i_mutex);
}
-out:
- coda_file->f_pos = host_file->f_pos;
- mutex_unlock(&host_inode->i_mutex);
+ else /* Venus: we must read Venus dirents from a file */
+ ret = coda_venus_readdir(coda_file, buf, filldir);
return ret;
}
@@ -501,57 +483,68 @@ static inline unsigned int CDT2DT(unsigned char cdt)
}
/* support routines */
-static int coda_venus_readdir(struct file *filp, filldir_t filldir,
- void *dirent, struct dentry *dir)
+static int coda_venus_readdir(struct file *coda_file, void *buf,
+ filldir_t filldir)
{
int result = 0; /* # of entries returned */
+ struct coda_file_info *cfi;
+ struct coda_inode_info *cii;
+ struct file *host_file;
+ struct dentry *de;
struct venus_dirent *vdir;
unsigned long vdir_size =
(unsigned long)(&((struct venus_dirent *)0)->d_name);
unsigned int type;
struct qstr name;
ino_t ino;
- int ret, i;
+ int ret;
+
+ cfi = CODA_FTOC(coda_file);
+ BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
+ host_file = cfi->cfi_container;
+
+ de = coda_file->f_path.dentry;
+ cii = ITOC(de->d_inode);
vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
if (!vdir) return -ENOMEM;
- i = filp->f_pos;
- switch(i) {
- case 0:
- ret = filldir(dirent, ".", 1, 0, dir->d_inode->i_ino, DT_DIR);
- if (ret < 0) break;
+ if (coda_file->f_pos == 0) {
+ ret = filldir(buf, ".", 1, 0, de->d_inode->i_ino, DT_DIR);
+ if (ret < 0)
+ goto out;
result++;
- filp->f_pos++;
- /* fallthrough */
- case 1:
- ret = filldir(dirent, "..", 2, 1, dir->d_parent->d_inode->i_ino, DT_DIR);
- if (ret < 0) break;
+ coda_file->f_pos++;
+ }
+ if (coda_file->f_pos == 1) {
+ ret = filldir(buf, "..", 2, 1, de->d_parent->d_inode->i_ino, DT_DIR);
+ if (ret < 0)
+ goto out;
result++;
- filp->f_pos++;
- /* fallthrough */
- default:
+ coda_file->f_pos++;
+ }
while (1) {
/* read entries from the directory file */
- ret = kernel_read(filp, filp->f_pos - 2, (char *)vdir,
+ ret = kernel_read(host_file, coda_file->f_pos - 2, (char *)vdir,
sizeof(*vdir));
if (ret < 0) {
- printk("coda_venus_readdir: read dir failed %d\n", ret);
+ printk(KERN_ERR "coda readdir: read dir %s failed %d\n",
+ coda_f2s(&cii->c_fid), ret);
break;
}
if (ret == 0) break; /* end of directory file reached */
/* catch truncated reads */
if (ret < vdir_size || ret < vdir_size + vdir->d_namlen) {
- printk("coda_venus_readdir: short read: %ld\n",
- filp->f_path.dentry->d_inode->i_ino);
+ printk(KERN_ERR "coda readdir: short read on %s\n",
+ coda_f2s(&cii->c_fid));
ret = -EBADF;
break;
}
/* validate whether the directory file actually makes sense */
if (vdir->d_reclen < vdir_size + vdir->d_namlen) {
- printk("coda_venus_readdir: Invalid dir: %ld\n",
- filp->f_path.dentry->d_inode->i_ino);
+ printk(KERN_ERR "coda readdir: invalid dir %s\n",
+ coda_f2s(&cii->c_fid));
ret = -EBADF;
break;
}
@@ -570,21 +563,21 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir,
* userspace doesn't have to worry about breaking
* getcwd by having mismatched inode numbers for
* internal volume mountpoints. */
- ino = find_inode_number(dir, &name);
+ ino = find_inode_number(de, &name);
if (!ino) ino = vdir->d_fileno;
type = CDT2DT(vdir->d_type);
- ret = filldir(dirent, name.name, name.len, filp->f_pos,
- ino, type);
+ ret = filldir(buf, name.name, name.len,
+ coda_file->f_pos, ino, type);
/* failure means no space for filling in this round */
if (ret < 0) break;
result++;
}
/* we'll always have progress because d_reclen is unsigned and
* we've already established it is non-zero. */
- filp->f_pos += vdir->d_reclen;
+ coda_file->f_pos += vdir->d_reclen;
}
- }
+out:
kfree(vdir);
return result ? result : ret;
}
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 99dbe866816d..29137ff3ca67 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -22,14 +22,9 @@
#include <linux/coda_linux.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_proc.h>
#include "coda_int.h"
-/* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support
- * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */
-static int use_coda_close;
-
static ssize_t
coda_file_read(struct file *coda_file, char __user *buf, size_t count, loff_t *ppos)
{
@@ -134,8 +129,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
unsigned short coda_flags = coda_flags_to_cflags(flags);
struct coda_file_info *cfi;
- coda_vfs_stat.open++;
-
cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
if (!cfi)
return -ENOMEM;
@@ -143,8 +136,11 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
lock_kernel();
error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
- &host_file);
- if (error || !host_file) {
+ &host_file);
+ if (!host_file)
+ error = -EIO;
+
+ if (error) {
kfree(cfi);
unlock_kernel();
return error;
@@ -163,49 +159,6 @@ int coda_open(struct inode *coda_inode, struct file *coda_file)
return 0;
}
-int coda_flush(struct file *coda_file, fl_owner_t id)
-{
- unsigned short flags = coda_file->f_flags & ~O_EXCL;
- unsigned short coda_flags = coda_flags_to_cflags(flags);
- struct coda_file_info *cfi;
- struct inode *coda_inode;
- int err = 0, fcnt;
-
- lock_kernel();
-
- coda_vfs_stat.flush++;
-
- /* last close semantics */
- fcnt = file_count(coda_file);
- if (fcnt > 1)
- goto out;
-
- /* No need to make an upcall when we have not made any modifications
- * to the file */
- if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY)
- goto out;
-
- if (use_coda_close)
- goto out;
-
- cfi = CODA_FTOC(coda_file);
- BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
-
- coda_inode = coda_file->f_path.dentry->d_inode;
-
- err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
- coda_file->f_uid);
-
- if (err == -EOPNOTSUPP) {
- use_coda_close = 1;
- err = 0;
- }
-
-out:
- unlock_kernel();
- return err;
-}
-
int coda_release(struct inode *coda_inode, struct file *coda_file)
{
unsigned short flags = (coda_file->f_flags) & (~O_EXCL);
@@ -216,23 +169,12 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
int err = 0;
lock_kernel();
- coda_vfs_stat.release++;
-
- if (!use_coda_close) {
- err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode),
- coda_flags);
- if (err == -EOPNOTSUPP) {
- use_coda_close = 1;
- err = 0;
- }
- }
cfi = CODA_FTOC(coda_file);
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
- if (use_coda_close)
- err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
- coda_flags, coda_file->f_uid);
+ err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
+ coda_flags, coda_file->f_uid);
host_inode = cfi->cfi_container->f_path.dentry->d_inode;
cii = ITOC(coda_inode);
@@ -249,7 +191,10 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
coda_file->private_data = NULL;
unlock_kernel();
- return err;
+
+ /* VFS fput ignores the return value from file_operations->release, so
+ * there is no use returning an error here */
+ return 0;
}
int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
@@ -268,8 +213,6 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
host_file = cfi->cfi_container;
- coda_vfs_stat.fsync++;
-
if (host_file->f_op && host_file->f_op->fsync) {
host_dentry = host_file->f_path.dentry;
host_inode = host_dentry->d_inode;
@@ -293,7 +236,6 @@ const struct file_operations coda_file_operations = {
.write = coda_file_write,
.mmap = coda_file_mmap,
.open = coda_open,
- .flush = coda_flush,
.release = coda_release,
.fsync = coda_fsync,
.splice_read = coda_file_splice_read,
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index dbff1bd4fb96..342f4e0d582e 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -64,13 +64,13 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&ei->vfs_inode);
}
-
+
int coda_init_inodecache(void)
{
coda_inode_cachep = kmem_cache_create("coda_inode_cache",
sizeof(struct coda_inode_info),
0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- init_once, NULL);
+ init_once);
if (coda_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -83,7 +83,7 @@ void coda_destroy_inodecache(void)
static int coda_remount(struct super_block *sb, int *flags, char *data)
{
- *flags |= MS_NODIRATIME;
+ *flags |= MS_NOATIME;
return 0;
}
@@ -141,11 +141,10 @@ static int get_device_index(struct coda_mount_data *data)
static int coda_fill_super(struct super_block *sb, void *data, int silent)
{
- struct inode *root = NULL;
- struct coda_sb_info *sbi = NULL;
+ struct inode *root = NULL;
struct venus_comm *vc = NULL;
struct CodaFid fid;
- int error;
+ int error;
int idx;
idx = get_device_index((struct coda_mount_data *) data);
@@ -167,21 +166,14 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
return -EBUSY;
}
- sbi = kmalloc(sizeof(struct coda_sb_info), GFP_KERNEL);
- if(!sbi) {
- return -ENOMEM;
- }
-
vc->vc_sb = sb;
- sbi->sbi_vcomm = vc;
-
- sb->s_fs_info = sbi;
- sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
- sb->s_blocksize = 1024; /* XXXXX what do we put here?? */
- sb->s_blocksize_bits = 10;
- sb->s_magic = CODA_SUPER_MAGIC;
- sb->s_op = &coda_super_operations;
+ sb->s_fs_info = vc;
+ sb->s_flags |= MS_NOATIME;
+ sb->s_blocksize = 4096; /* XXXXX what do we put here?? */
+ sb->s_blocksize_bits = 12;
+ sb->s_magic = CODA_SUPER_MAGIC;
+ sb->s_op = &coda_super_operations;
/* get root fid from Venus: this needs the root inode */
error = venus_rootfid(sb, &fid);
@@ -207,26 +199,20 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
return 0;
error:
- if (sbi) {
- kfree(sbi);
- if(vc)
- vc->vc_sb = NULL;
- }
if (root)
- iput(root);
+ iput(root);
+ if (vc)
+ vc->vc_sb = NULL;
- return -EINVAL;
+ return -EINVAL;
}
static void coda_put_super(struct super_block *sb)
{
- struct coda_sb_info *sbi;
-
- sbi = coda_sbp(sb);
- sbi->sbi_vcomm->vc_sb = NULL;
+ coda_vcp(sb)->vc_sb = NULL;
+ sb->s_fs_info = NULL;
printk("Coda: Bye bye.\n");
- kfree(sbi);
}
static void coda_clear_inode(struct inode *inode)
@@ -296,7 +282,7 @@ static int coda_statfs(struct dentry *dentry, struct kstatfs *buf)
/* and fill in the rest */
buf->f_type = CODA_SUPER_MAGIC;
- buf->f_bsize = 1024;
+ buf->f_bsize = 4096;
buf->f_namelen = CODA_MAXNAMLEN;
return 0;
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c
index 803aacf0d49c..dcc6aead70f5 100644
--- a/fs/coda/psdev.c
+++ b/fs/coda/psdev.c
@@ -45,12 +45,9 @@
#include <linux/coda_linux.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_psdev.h>
-#include <linux/coda_proc.h>
#include "coda_int.h"
-#define upc_free(r) kfree(r)
-
/* statistics */
int coda_hard; /* allows signals during upcalls */
unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */
@@ -195,7 +192,8 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf,
if (req->uc_opcode == CODA_OPEN_BY_FD) {
struct coda_open_by_fd_out *outp =
(struct coda_open_by_fd_out *)req->uc_data;
- outp->fh = fget(outp->fd);
+ if (!outp->oh.result)
+ outp->fh = fget(outp->fd);
}
wake_up(&req->uc_sleep);
@@ -263,7 +261,7 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf,
}
CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
- upc_free(req);
+ kfree(req);
out:
unlock_kernel();
return (count ? count : retval);
@@ -271,71 +269,70 @@ out:
static int coda_psdev_open(struct inode * inode, struct file * file)
{
- struct venus_comm *vcp;
- int idx;
+ struct venus_comm *vcp;
+ int idx, err;
- lock_kernel();
idx = iminor(inode);
- if(idx >= MAX_CODADEVS) {
- unlock_kernel();
+ if (idx < 0 || idx >= MAX_CODADEVS)
return -ENODEV;
- }
+ lock_kernel();
+
+ err = -EBUSY;
vcp = &coda_comms[idx];
- if(vcp->vc_inuse) {
- unlock_kernel();
- return -EBUSY;
- }
-
- if (!vcp->vc_inuse++) {
+ if (!vcp->vc_inuse) {
+ vcp->vc_inuse++;
+
INIT_LIST_HEAD(&vcp->vc_pending);
INIT_LIST_HEAD(&vcp->vc_processing);
init_waitqueue_head(&vcp->vc_waitq);
vcp->vc_sb = NULL;
vcp->vc_seq = 0;
+
+ file->private_data = vcp;
+ err = 0;
}
-
- file->private_data = vcp;
unlock_kernel();
- return 0;
+ return err;
}
static int coda_psdev_release(struct inode * inode, struct file * file)
{
- struct venus_comm *vcp = (struct venus_comm *) file->private_data;
- struct upc_req *req, *tmp;
+ struct venus_comm *vcp = (struct venus_comm *) file->private_data;
+ struct upc_req *req, *tmp;
- lock_kernel();
- if ( !vcp->vc_inuse ) {
- unlock_kernel();
+ if (!vcp || !vcp->vc_inuse ) {
printk("psdev_release: Not open.\n");
return -1;
}
- if (--vcp->vc_inuse) {
- unlock_kernel();
- return 0;
- }
-
- /* Wakeup clients so they can return. */
+ lock_kernel();
+
+ /* Wakeup clients so they can return. */
list_for_each_entry_safe(req, tmp, &vcp->vc_pending, uc_chain) {
+ list_del(&req->uc_chain);
+
/* Async requests need to be freed here */
if (req->uc_flags & REQ_ASYNC) {
CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr));
- upc_free(req);
+ kfree(req);
continue;
}
req->uc_flags |= REQ_ABORT;
wake_up(&req->uc_sleep);
- }
-
- list_for_each_entry(req, &vcp->vc_processing, uc_chain) {
+ }
+
+ list_for_each_entry_safe(req, tmp, &vcp->vc_processing, uc_chain) {
+ list_del(&req->uc_chain);
+
req->uc_flags |= REQ_ABORT;
- wake_up(&req->uc_sleep);
- }
+ wake_up(&req->uc_sleep);
+ }
+ file->private_data = NULL;
+ vcp->vc_inuse--;
unlock_kernel();
return 0;
}
@@ -376,21 +373,20 @@ out:
return err;
}
-
-MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>");
+MODULE_AUTHOR("Jan Harkes, Peter J. Braam");
+MODULE_DESCRIPTION("Coda Distributed File System VFS interface");
+MODULE_ALIAS_CHARDEV_MAJOR(CODA_PSDEV_MAJOR);
MODULE_LICENSE("GPL");
+#ifdef CONFIG_CODA_FS_OLD_API
+MODULE_VERSION("5.3.21");
+#else
+MODULE_VERSION("6.6");
+#endif
static int __init init_coda(void)
{
int status;
int i;
- printk(KERN_INFO "Coda Kernel/Venus communications, "
-#ifdef CONFIG_CODA_FS_OLD_API
- "v5.3.20"
-#else
- "v6.0.0"
-#endif
- ", coda@cs.cmu.edu\n");
status = coda_init_inodecache();
if (status)
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index 76e00a65a75b..4513b7258458 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -20,7 +20,6 @@
#include <linux/coda_linux.h>
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
-#include <linux/coda_proc.h>
static int coda_symlink_filler(struct file *file, struct page *page)
{
@@ -32,7 +31,6 @@ static int coda_symlink_filler(struct file *file, struct page *page)
lock_kernel();
cii = ITOC(inode);
- coda_vfs_stat.follow_link++;
error = venus_readlink(inode->i_sb, &cii->c_fid, p, &len);
unlock_kernel();
diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c
index c57a1fa7cf23..81b7771c6465 100644
--- a/fs/coda/sysctl.c
+++ b/fs/coda/sysctl.c
@@ -5,181 +5,14 @@
*
* Carnegie Mellon encourages users to contribute improvements to
* the Coda project. Contact Peter Braam (coda@cs.cmu.edu).
- *
- * CODA operation statistics
- * (c) March, 1998 Zhanyong Wan <zhanyong.wan@yale.edu>
- *
*/
-#include <linux/time.h>
-#include <linux/mm.h>
#include <linux/sysctl.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/ctype.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <linux/utsname.h>
-#include <linux/module.h>
-#include <linux/coda.h>
-#include <linux/coda_linux.h>
-#include <linux/coda_fs_i.h>
-#include <linux/coda_psdev.h>
-#include <linux/coda_cache.h>
-#include <linux/coda_proc.h>
+#include "coda_int.h"
static struct ctl_table_header *fs_table_header;
-#define CODA_TIMEOUT 3 /* timeout on upcalls to become intrble */
-#define CODA_HARD 5 /* mount type "hard" or "soft" */
-#define CODA_VFS 6 /* vfs statistics */
-#define CODA_CACHE_INV 9 /* cache invalidation statistics */
-#define CODA_FAKE_STATFS 10 /* don't query venus for actual cache usage */
-
-struct coda_vfs_stats coda_vfs_stat;
-static struct coda_cache_inv_stats coda_cache_inv_stat;
-
-static void reset_coda_vfs_stats( void )
-{
- memset( &coda_vfs_stat, 0, sizeof( coda_vfs_stat ) );
-}
-
-static void reset_coda_cache_inv_stats( void )
-{
- memset( &coda_cache_inv_stat, 0, sizeof( coda_cache_inv_stat ) );
-}
-
-static int do_reset_coda_vfs_stats( ctl_table * table, int write,
- struct file * filp, void __user * buffer,
- size_t * lenp, loff_t * ppos )
-{
- if ( write ) {
- reset_coda_vfs_stats();
-
- *ppos += *lenp;
- } else {
- *lenp = 0;
- }
-
- return 0;
-}
-
-static int do_reset_coda_cache_inv_stats( ctl_table * table, int write,
- struct file * filp,
- void __user * buffer,
- size_t * lenp, loff_t * ppos )
-{
- if ( write ) {
- reset_coda_cache_inv_stats();
-
- *ppos += *lenp;
- } else {
- *lenp = 0;
- }
-
- return 0;
-}
-
-static int proc_vfs_stats_show(struct seq_file *m, void *v)
-{
- struct coda_vfs_stats * ps = & coda_vfs_stat;
-
- seq_printf(m,
- "Coda VFS statistics\n"
- "===================\n\n"
- "File Operations:\n"
- "\topen\t\t%9d\n"
- "\tflush\t\t%9d\n"
- "\trelease\t\t%9d\n"
- "\tfsync\t\t%9d\n\n"
- "Dir Operations:\n"
- "\treaddir\t\t%9d\n\n"
- "Inode Operations\n"
- "\tcreate\t\t%9d\n"
- "\tlookup\t\t%9d\n"
- "\tlink\t\t%9d\n"
- "\tunlink\t\t%9d\n"
- "\tsymlink\t\t%9d\n"
- "\tmkdir\t\t%9d\n"
- "\trmdir\t\t%9d\n"
- "\trename\t\t%9d\n"
- "\tpermission\t%9d\n",
-
- /* file operations */
- ps->open,
- ps->flush,
- ps->release,
- ps->fsync,
-
- /* dir operations */
- ps->readdir,
-
- /* inode operations */
- ps->create,
- ps->lookup,
- ps->link,
- ps->unlink,
- ps->symlink,
- ps->mkdir,
- ps->rmdir,
- ps->rename,
- ps->permission);
- return 0;
-}
-
-static int proc_cache_inv_stats_show(struct seq_file *m, void *v)
-{
- struct coda_cache_inv_stats * ps = & coda_cache_inv_stat;
-
- seq_printf(m,
- "Coda cache invalidation statistics\n"
- "==================================\n\n"
- "flush\t\t%9d\n"
- "purge user\t%9d\n"
- "zap_dir\t\t%9d\n"
- "zap_file\t%9d\n"
- "zap_vnode\t%9d\n"
- "purge_fid\t%9d\n"
- "replace\t\t%9d\n",
- ps->flush,
- ps->purge_user,
- ps->zap_dir,
- ps->zap_file,
- ps->zap_vnode,
- ps->purge_fid,
- ps->replace );
- return 0;
-}
-
-static int proc_vfs_stats_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_vfs_stats_show, NULL);
-}
-
-static int proc_cache_inv_stats_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_cache_inv_stats_show, NULL);
-}
-
-static const struct file_operations proc_vfs_stats_fops = {
- .owner = THIS_MODULE,
- .open = proc_vfs_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations proc_cache_inv_stats_fops = {
- .owner = THIS_MODULE,
- .open = proc_cache_inv_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static ctl_table coda_table[] = {
{
.ctl_name = CTL_UNNUMBERED,
@@ -199,22 +32,6 @@ static ctl_table coda_table[] = {
},
{
.ctl_name = CTL_UNNUMBERED,
- .procname = "vfs_stats",
- .data = NULL,
- .maxlen = 0,
- .mode = 0644,
- .proc_handler = &do_reset_coda_vfs_stats
- },
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "cache_inv_stats",
- .data = NULL,
- .maxlen = 0,
- .mode = 0644,
- .proc_handler = &do_reset_coda_cache_inv_stats
- },
- {
- .ctl_name = CTL_UNNUMBERED,
.procname = "fake_statfs",
.data = &coda_fake_statfs,
.maxlen = sizeof(int),
@@ -235,59 +52,20 @@ static ctl_table fs_table[] = {
};
-#ifdef CONFIG_PROC_FS
-
-/*
- target directory structure:
- /proc/fs (see linux/fs/proc/root.c)
- /proc/fs/coda
- /proc/fs/coda/{vfs_stats,
-
-*/
-
-static struct proc_dir_entry* proc_fs_coda;
-
-#endif
-
void coda_sysctl_init(void)
{
- reset_coda_vfs_stats();
- reset_coda_cache_inv_stats();
-
-#ifdef CONFIG_PROC_FS
- proc_fs_coda = proc_mkdir("coda", proc_root_fs);
- if (proc_fs_coda) {
- struct proc_dir_entry *pde;
-
- proc_fs_coda->owner = THIS_MODULE;
- pde = create_proc_entry("vfs_stats", 0, proc_fs_coda);
- if (pde)
- pde->proc_fops = &proc_vfs_stats_fops;
- pde = create_proc_entry("cache_inv_stats", 0, proc_fs_coda);
- if (pde)
- pde->proc_fops = &proc_cache_inv_stats_fops;
- }
-#endif
-
#ifdef CONFIG_SYSCTL
if ( !fs_table_header )
fs_table_header = register_sysctl_table(fs_table);
-#endif
+#endif
}
-void coda_sysctl_clean(void)
+void coda_sysctl_clean(void)
{
-
#ifdef CONFIG_SYSCTL
if ( fs_table_header ) {
unregister_sysctl_table(fs_table_header);
fs_table_header = NULL;
}
#endif
-
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("cache_inv_stats", proc_fs_coda);
- remove_proc_entry("vfs_stats", proc_fs_coda);
- remove_proc_entry("coda", proc_root_fs);
-#endif
}
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c
index 5faacdb1a479..cdb4c07a7870 100644
--- a/fs/coda/upcall.c
+++ b/fs/coda/upcall.c
@@ -35,12 +35,10 @@
#include <linux/coda_psdev.h>
#include <linux/coda_fs_i.h>
#include <linux/coda_cache.h>
-#include <linux/coda_proc.h>
-#define upc_alloc() kmalloc(sizeof(struct upc_req), GFP_KERNEL)
-#define upc_free(r) kfree(r)
+#include "coda_int.h"
-static int coda_upcall(struct coda_sb_info *mntinfo, int inSize, int *outSize,
+static int coda_upcall(struct venus_comm *vc, int inSize, int *outSize,
union inputArgs *buffer);
static void *alloc_upcall(int opcode, int size)
@@ -86,13 +84,9 @@ int venus_rootfid(struct super_block *sb, struct CodaFid *fidp)
insize = SIZE(root);
UPARG(CODA_ROOT);
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-
- if (error) {
- printk("coda_get_rootfid: error %d\n", error);
- } else {
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+ if (!error)
*fidp = outp->coda_root.VFid;
- }
CODA_FREE(inp, insize);
return error;
@@ -109,9 +103,9 @@ int venus_getattr(struct super_block *sb, struct CodaFid *fid,
UPARG(CODA_GETATTR);
inp->coda_getattr.VFid = *fid;
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-
- *attr = outp->coda_getattr.attr;
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+ if (!error)
+ *attr = outp->coda_getattr.attr;
CODA_FREE(inp, insize);
return error;
@@ -130,7 +124,7 @@ int venus_setattr(struct super_block *sb, struct CodaFid *fid,
inp->coda_setattr.VFid = *fid;
inp->coda_setattr.attr = *vattr;
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -156,64 +150,18 @@ int venus_lookup(struct super_block *sb, struct CodaFid *fid,
memcpy((char *)(inp) + offset, name, length);
*((char *)inp + offset + length) = '\0';
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-
- *resfid = outp->coda_lookup.VFid;
- *type = outp->coda_lookup.vtype;
-
- CODA_FREE(inp, insize);
- return error;
-}
-
-int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
- vuid_t uid)
-{
- union inputArgs *inp;
- union outputArgs *outp;
- int insize, outsize, error;
-#ifdef CONFIG_CODA_FS_OLD_API
- struct coda_cred cred = { 0, };
- cred.cr_fsuid = uid;
-#endif
-
- insize = SIZE(store);
- UPARG(CODA_STORE);
-
-#ifdef CONFIG_CODA_FS_OLD_API
- memcpy(&(inp->ih.cred), &cred, sizeof(cred));
-#else
- inp->ih.uid = uid;
-#endif
-
- inp->coda_store.VFid = *fid;
- inp->coda_store.flags = flags;
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-
- CODA_FREE(inp, insize);
- return error;
-}
-
-int venus_release(struct super_block *sb, struct CodaFid *fid, int flags)
-{
- union inputArgs *inp;
- union outputArgs *outp;
- int insize, outsize, error;
-
- insize = SIZE(release);
- UPARG(CODA_RELEASE);
-
- inp->coda_release.VFid = *fid;
- inp->coda_release.flags = flags;
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+ if (!error) {
+ *resfid = outp->coda_lookup.VFid;
+ *type = outp->coda_lookup.vtype;
+ }
CODA_FREE(inp, insize);
return error;
}
int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
- vuid_t uid)
+ vuid_t uid)
{
union inputArgs *inp;
union outputArgs *outp;
@@ -235,7 +183,7 @@ int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
inp->coda_close.VFid = *fid;
inp->coda_close.flags = flags;
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -251,12 +199,12 @@ int venus_open(struct super_block *sb, struct CodaFid *fid,
insize = SIZE(open_by_fd);
UPARG(CODA_OPEN_BY_FD);
- inp->coda_open.VFid = *fid;
- inp->coda_open.flags = flags;
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ inp->coda_open_by_fd.VFid = *fid;
+ inp->coda_open_by_fd.flags = flags;
- *fh = outp->coda_open_by_fd.fh;
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+ if (!error)
+ *fh = outp->coda_open_by_fd.fh;
CODA_FREE(inp, insize);
return error;
@@ -281,11 +229,12 @@ int venus_mkdir(struct super_block *sb, struct CodaFid *dirfid,
/* Venus must get null terminated string */
memcpy((char *)(inp) + offset, name, length);
*((char *)inp + offset + length) = '\0';
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- *attrs = outp->coda_mkdir.attr;
- *newfid = outp->coda_mkdir.VFid;
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+ if (!error) {
+ *attrs = outp->coda_mkdir.attr;
+ *newfid = outp->coda_mkdir.VFid;
+ }
CODA_FREE(inp, insize);
return error;
@@ -323,7 +272,7 @@ int venus_rename(struct super_block *sb, struct CodaFid *old_fid,
memcpy((char *)(inp) + offset, new_name, new_length);
*((char *)inp + offset + new_length) = '\0';
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -351,11 +300,12 @@ int venus_create(struct super_block *sb, struct CodaFid *dirfid,
/* Venus must get null terminated string */
memcpy((char *)(inp) + offset, name, length);
*((char *)inp + offset + length) = '\0';
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
- *attrs = outp->coda_create.attr;
- *newfid = outp->coda_create.VFid;
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+ if (!error) {
+ *attrs = outp->coda_create.attr;
+ *newfid = outp->coda_create.VFid;
+ }
CODA_FREE(inp, insize);
return error;
@@ -377,8 +327,8 @@ int venus_rmdir(struct super_block *sb, struct CodaFid *dirfid,
inp->coda_rmdir.name = offset;
memcpy((char *)(inp) + offset, name, length);
*((char *)inp + offset + length) = '\0';
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -399,8 +349,8 @@ int venus_remove(struct super_block *sb, struct CodaFid *dirfid,
inp->coda_remove.name = offset;
memcpy((char *)(inp) + offset, name, length);
*((char *)inp + offset + length) = '\0';
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -420,19 +370,18 @@ int venus_readlink(struct super_block *sb, struct CodaFid *fid,
UPARG(CODA_READLINK);
inp->coda_readlink.VFid = *fid;
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
-
- if (! error) {
- retlen = outp->coda_readlink.count;
+
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
+ if (!error) {
+ retlen = outp->coda_readlink.count;
if ( retlen > *length )
- retlen = *length;
+ retlen = *length;
*length = retlen;
result = (char *)outp + (long)outp->coda_readlink.data;
memcpy(buffer, result, retlen);
*(buffer + retlen) = '\0';
}
-
+
CODA_FREE(inp, insize);
return error;
}
@@ -458,8 +407,8 @@ int venus_link(struct super_block *sb, struct CodaFid *fid,
/* make sure strings are null terminated */
memcpy((char *)(inp) + offset, name, len);
*((char *)inp + offset + len) = '\0';
-
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -494,7 +443,7 @@ int venus_symlink(struct super_block *sb, struct CodaFid *fid,
memcpy((char *)(inp) + offset, name, len);
*((char *)inp + offset + len) = '\0';
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -509,9 +458,9 @@ int venus_fsync(struct super_block *sb, struct CodaFid *fid)
insize=SIZE(fsync);
UPARG(CODA_FSYNC);
- inp->coda_fsync.VFid = *fid;
- error = coda_upcall(coda_sbp(sb), sizeof(union inputArgs),
- &outsize, inp);
+ inp->coda_fsync.VFid = *fid;
+ error = coda_upcall(coda_vcp(sb), sizeof(union inputArgs),
+ &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -529,7 +478,7 @@ int venus_access(struct super_block *sb, struct CodaFid *fid, int mask)
inp->coda_access.VFid = *fid;
inp->coda_access.flags = mask;
- error = coda_upcall(coda_sbp(sb), insize, &outsize, inp);
+ error = coda_upcall(coda_vcp(sb), insize, &outsize, inp);
CODA_FREE(inp, insize);
return error;
@@ -578,9 +527,9 @@ int venus_pioctl(struct super_block *sb, struct CodaFid *fid,
goto exit;
}
- error = coda_upcall(coda_sbp(sb), SIZE(ioctl) + data->vi.in_size,
- &outsize, inp);
-
+ error = coda_upcall(coda_vcp(sb), SIZE(ioctl) + data->vi.in_size,
+ &outsize, inp);
+
if (error) {
printk("coda_pioctl: Venus returns: %d for %s\n",
error, coda_f2s(fid));
@@ -620,16 +569,13 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
insize = max_t(unsigned int, INSIZE(statfs), OUTSIZE(statfs));
UPARG(CODA_STATFS);
- error = coda_upcall(coda_sbp(dentry->d_sb), insize, &outsize, inp);
-
- if (!error) {
+ error = coda_upcall(coda_vcp(dentry->d_sb), insize, &outsize, inp);
+ if (!error) {
sfs->f_blocks = outp->coda_statfs.stat.f_blocks;
sfs->f_bfree = outp->coda_statfs.stat.f_bfree;
sfs->f_bavail = outp->coda_statfs.stat.f_bavail;
sfs->f_files = outp->coda_statfs.stat.f_files;
sfs->f_ffree = outp->coda_statfs.stat.f_ffree;
- } else {
- printk("coda_statfs: Venus returns: %d\n", error);
}
CODA_FREE(inp, insize);
@@ -638,96 +584,129 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs)
/*
* coda_upcall and coda_downcall routines.
- *
*/
+static void coda_block_signals(sigset_t *old)
+{
+ spin_lock_irq(&current->sighand->siglock);
+ *old = current->blocked;
+
+ sigfillset(&current->blocked);
+ sigdelset(&current->blocked, SIGKILL);
+ sigdelset(&current->blocked, SIGSTOP);
+ sigdelset(&current->blocked, SIGINT);
+
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+}
+
+static void coda_unblock_signals(sigset_t *old)
+{
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = *old;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+}
+
+/* Don't allow signals to interrupt the following upcalls before venus
+ * has seen them,
+ * - CODA_CLOSE or CODA_RELEASE upcall (to avoid reference count problems)
+ * - CODA_STORE (to avoid data loss)
+ */
+#define CODA_INTERRUPTIBLE(r) (!coda_hard && \
+ (((r)->uc_opcode != CODA_CLOSE && \
+ (r)->uc_opcode != CODA_STORE && \
+ (r)->uc_opcode != CODA_RELEASE) || \
+ (r)->uc_flags & REQ_READ))
-static inline void coda_waitfor_upcall(struct upc_req *vmp,
- struct venus_comm *vcommp)
+static inline void coda_waitfor_upcall(struct upc_req *req)
{
DECLARE_WAITQUEUE(wait, current);
+ unsigned long timeout = jiffies + coda_timeout * HZ;
+ sigset_t old;
+ int blocked;
- vmp->uc_posttime = jiffies;
+ coda_block_signals(&old);
+ blocked = 1;
- add_wait_queue(&vmp->uc_sleep, &wait);
+ add_wait_queue(&req->uc_sleep, &wait);
for (;;) {
- if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE )
+ if (CODA_INTERRUPTIBLE(req))
set_current_state(TASK_INTERRUPTIBLE);
else
set_current_state(TASK_UNINTERRUPTIBLE);
- /* venus died */
- if ( !vcommp->vc_inuse )
- break;
-
/* got a reply */
- if ( vmp->uc_flags & ( REQ_WRITE | REQ_ABORT ) )
+ if (req->uc_flags & (REQ_WRITE | REQ_ABORT))
break;
- if ( !coda_hard && vmp->uc_opcode != CODA_CLOSE && signal_pending(current) ) {
- /* if this process really wants to die, let it go */
- if ( sigismember(&(current->pending.signal), SIGKILL) ||
- sigismember(&(current->pending.signal), SIGINT) )
- break;
- /* signal is present: after timeout always return
- really smart idea, probably useless ... */
- if ( jiffies - vmp->uc_posttime > coda_timeout * HZ )
- break;
+ if (blocked && time_after(jiffies, timeout) &&
+ CODA_INTERRUPTIBLE(req))
+ {
+ coda_unblock_signals(&old);
+ blocked = 0;
+ }
+
+ if (signal_pending(current)) {
+ list_del(&req->uc_chain);
+ break;
}
- schedule();
+
+ if (blocked)
+ schedule_timeout(HZ);
+ else
+ schedule();
}
- remove_wait_queue(&vmp->uc_sleep, &wait);
- set_current_state(TASK_RUNNING);
+ if (blocked)
+ coda_unblock_signals(&old);
- return;
+ remove_wait_queue(&req->uc_sleep, &wait);
+ set_current_state(TASK_RUNNING);
}
-/*
- * coda_upcall will return an error in the case of
+/*
+ * coda_upcall will return an error in the case of
* failed communication with Venus _or_ will peek at Venus
* reply and return Venus' error.
*
* As venus has 2 types of errors, normal errors (positive) and internal
* errors (negative), normal errors are negated, while internal errors
* are all mapped to -EINTR, while showing a nice warning message. (jh)
- *
*/
-static int coda_upcall(struct coda_sb_info *sbi,
- int inSize, int *outSize,
- union inputArgs *buffer)
+static int coda_upcall(struct venus_comm *vcp,
+ int inSize, int *outSize,
+ union inputArgs *buffer)
{
- struct venus_comm *vcommp;
union outputArgs *out;
- struct upc_req *req;
+ union inputArgs *sig_inputArgs;
+ struct upc_req *req, *sig_req;
int error = 0;
- vcommp = sbi->sbi_vcomm;
- if ( !vcommp->vc_inuse ) {
- printk("No pseudo device in upcall comms at %p\n", vcommp);
- return -ENXIO;
+ if (!vcp->vc_inuse) {
+ printk(KERN_NOTICE "coda: Venus dead, not sending upcall\n");
+ return -ENXIO;
}
/* Format the request message. */
- req = upc_alloc();
- if (!req) {
- printk("Failed to allocate upc_req structure\n");
+ req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
+ if (!req)
return -ENOMEM;
- }
+
req->uc_data = (void *)buffer;
req->uc_flags = 0;
req->uc_inSize = inSize;
req->uc_outSize = *outSize ? *outSize : inSize;
req->uc_opcode = ((union inputArgs *)buffer)->ih.opcode;
- req->uc_unique = ++vcommp->vc_seq;
+ req->uc_unique = ++vcp->vc_seq;
init_waitqueue_head(&req->uc_sleep);
-
+
/* Fill in the common input args. */
((union inputArgs *)buffer)->ih.unique = req->uc_unique;
/* Append msg to pending queue and poke Venus. */
- list_add_tail(&(req->uc_chain), &vcommp->vc_pending);
-
- wake_up_interruptible(&vcommp->vc_waitq);
+ list_add_tail(&req->uc_chain, &vcp->vc_pending);
+
+ wake_up_interruptible(&vcp->vc_waitq);
/* We can be interrupted while we wait for Venus to process
* our request. If the interrupt occurs before Venus has read
* the request, we dequeue and return. If it occurs after the
@@ -738,67 +717,60 @@ static int coda_upcall(struct coda_sb_info *sbi,
* ENODEV. */
/* Go to sleep. Wake up on signals only after the timeout. */
- coda_waitfor_upcall(req, vcommp);
+ coda_waitfor_upcall(req);
- if (vcommp->vc_inuse) { /* i.e. Venus is still alive */
- /* Op went through, interrupt or not... */
- if (req->uc_flags & REQ_WRITE) {
+ /* Op went through, interrupt or not... */
+ if (req->uc_flags & REQ_WRITE) {
out = (union outputArgs *)req->uc_data;
/* here we map positive Venus errors to kernel errors */
error = -out->oh.result;
*outSize = req->uc_outSize;
goto exit;
- }
- if ( !(req->uc_flags & REQ_READ) && signal_pending(current)) {
- /* Interrupted before venus read it. */
- list_del(&(req->uc_chain));
- /* perhaps the best way to convince the app to
- give up? */
- error = -EINTR;
+ }
+
+ error = -EINTR;
+ if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) {
+ printk(KERN_WARNING "coda: Unexpected interruption.\n");
goto exit;
- }
- if ( (req->uc_flags & REQ_READ) && signal_pending(current) ) {
- /* interrupted after Venus did its read, send signal */
- union inputArgs *sig_inputArgs;
- struct upc_req *sig_req;
-
- list_del(&(req->uc_chain));
- error = -ENOMEM;
- sig_req = upc_alloc();
- if (!sig_req) goto exit;
-
- CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
- if (!sig_req->uc_data) {
- upc_free(sig_req);
- goto exit;
- }
-
- error = -EINTR;
- sig_inputArgs = (union inputArgs *)sig_req->uc_data;
- sig_inputArgs->ih.opcode = CODA_SIGNAL;
- sig_inputArgs->ih.unique = req->uc_unique;
-
- sig_req->uc_flags = REQ_ASYNC;
- sig_req->uc_opcode = sig_inputArgs->ih.opcode;
- sig_req->uc_unique = sig_inputArgs->ih.unique;
- sig_req->uc_inSize = sizeof(struct coda_in_hdr);
- sig_req->uc_outSize = sizeof(struct coda_in_hdr);
-
- /* insert at head of queue! */
- list_add(&(sig_req->uc_chain), &vcommp->vc_pending);
- wake_up_interruptible(&vcommp->vc_waitq);
- } else {
- printk("Coda: Strange interruption..\n");
- error = -EINTR;
- }
- } else { /* If venus died i.e. !VC_OPEN(vcommp) */
- printk("coda_upcall: Venus dead on (op,un) (%d.%d) flags %d\n",
- req->uc_opcode, req->uc_unique, req->uc_flags);
- error = -ENODEV;
}
- exit:
- upc_free(req);
+ /* Interrupted before venus read it. */
+ if (!(req->uc_flags & REQ_READ))
+ goto exit;
+
+ /* Venus saw the upcall, make sure we can send interrupt signal */
+ if (!vcp->vc_inuse) {
+ printk(KERN_INFO "coda: Venus dead, not sending signal.\n");
+ goto exit;
+ }
+
+ error = -ENOMEM;
+ sig_req = kmalloc(sizeof(struct upc_req), GFP_KERNEL);
+ if (!sig_req) goto exit;
+
+ CODA_ALLOC((sig_req->uc_data), char *, sizeof(struct coda_in_hdr));
+ if (!sig_req->uc_data) {
+ kfree(sig_req);
+ goto exit;
+ }
+
+ error = -EINTR;
+ sig_inputArgs = (union inputArgs *)sig_req->uc_data;
+ sig_inputArgs->ih.opcode = CODA_SIGNAL;
+ sig_inputArgs->ih.unique = req->uc_unique;
+
+ sig_req->uc_flags = REQ_ASYNC;
+ sig_req->uc_opcode = sig_inputArgs->ih.opcode;
+ sig_req->uc_unique = sig_inputArgs->ih.unique;
+ sig_req->uc_inSize = sizeof(struct coda_in_hdr);
+ sig_req->uc_outSize = sizeof(struct coda_in_hdr);
+
+ /* insert at head of queue! */
+ list_add(&(sig_req->uc_chain), &vcp->vc_pending);
+ wake_up_interruptible(&vcp->vc_waitq);
+
+exit:
+ kfree(req);
return error;
}
@@ -838,77 +810,66 @@ static int coda_upcall(struct coda_sb_info *sbi,
int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb)
{
+ struct inode *inode = NULL;
+ struct CodaFid *fid, *newfid;
+
/* Handle invalidation requests. */
- if ( !sb || !sb->s_root || !sb->s_root->d_inode)
- return 0;
-
- switch (opcode) {
-
- case CODA_FLUSH : {
- coda_cache_clear_all(sb);
- shrink_dcache_sb(sb);
- coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
- return(0);
- }
-
- case CODA_PURGEUSER : {
- coda_cache_clear_all(sb);
- return(0);
- }
-
- case CODA_ZAPDIR : {
- struct inode *inode;
- struct CodaFid *fid = &out->coda_zapdir.CodaFid;
-
- inode = coda_fid_to_inode(fid, sb);
- if (inode) {
- coda_flag_inode_children(inode, C_PURGE);
- coda_flag_inode(inode, C_VATTR);
- iput(inode);
- }
-
- return(0);
- }
-
- case CODA_ZAPFILE : {
- struct inode *inode;
- struct CodaFid *fid = &out->coda_zapfile.CodaFid;
- inode = coda_fid_to_inode(fid, sb);
- if ( inode ) {
- coda_flag_inode(inode, C_VATTR);
- iput(inode);
- }
- return 0;
- }
-
- case CODA_PURGEFID : {
- struct inode *inode;
- struct CodaFid *fid = &out->coda_purgefid.CodaFid;
- inode = coda_fid_to_inode(fid, sb);
- if ( inode ) {
+ if ( !sb || !sb->s_root)
+ return 0;
+
+ switch (opcode) {
+ case CODA_FLUSH:
+ coda_cache_clear_all(sb);
+ shrink_dcache_sb(sb);
+ if (sb->s_root->d_inode)
+ coda_flag_inode(sb->s_root->d_inode, C_FLUSH);
+ break;
+
+ case CODA_PURGEUSER:
+ coda_cache_clear_all(sb);
+ break;
+
+ case CODA_ZAPDIR:
+ fid = &out->coda_zapdir.CodaFid;
+ inode = coda_fid_to_inode(fid, sb);
+ if (inode) {
+ coda_flag_inode_children(inode, C_PURGE);
+ coda_flag_inode(inode, C_VATTR);
+ }
+ break;
+
+ case CODA_ZAPFILE:
+ fid = &out->coda_zapfile.CodaFid;
+ inode = coda_fid_to_inode(fid, sb);
+ if (inode)
+ coda_flag_inode(inode, C_VATTR);
+ break;
+
+ case CODA_PURGEFID:
+ fid = &out->coda_purgefid.CodaFid;
+ inode = coda_fid_to_inode(fid, sb);
+ if (inode) {
coda_flag_inode_children(inode, C_PURGE);
/* catch the dentries later if some are still busy */
coda_flag_inode(inode, C_PURGE);
d_prune_aliases(inode);
- iput(inode);
- }
- return 0;
- }
-
- case CODA_REPLACE : {
- struct inode *inode;
- struct CodaFid *oldfid = &out->coda_replace.OldFid;
- struct CodaFid *newfid = &out->coda_replace.NewFid;
- inode = coda_fid_to_inode(oldfid, sb);
- if ( inode ) {
- coda_replace_fid(inode, oldfid, newfid);
- iput(inode);
- }
- return 0;
- }
- }
- return 0;
+ }
+ break;
+
+ case CODA_REPLACE:
+ fid = &out->coda_replace.OldFid;
+ newfid = &out->coda_replace.NewFid;
+ inode = coda_fid_to_inode(fid, sb);
+ if (inode)
+ coda_replace_fid(inode, fid, newfid);
+ break;
+ }
+
+ if (inode)
+ iput(inode);
+
+ return 0;
}
diff --git a/fs/compat.c b/fs/compat.c
index 4db6216e5266..15078ce4c04a 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1257,6 +1257,7 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
{
struct page *kmapped_page = NULL;
char *kaddr = NULL;
+ unsigned long kpos = 0;
int ret;
while (argc-- > 0) {
@@ -1265,92 +1266,84 @@ static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
unsigned long pos;
if (get_user(str, argv+argc) ||
- !(len = strnlen_user(compat_ptr(str), bprm->p))) {
+ !(len = strnlen_user(compat_ptr(str), MAX_ARG_STRLEN))) {
ret = -EFAULT;
goto out;
}
- if (bprm->p < len) {
+ if (len > MAX_ARG_STRLEN) {
ret = -E2BIG;
goto out;
}
- bprm->p -= len;
- /* XXX: add architecture specific overflow check here. */
+ /* We're going to work our way backwords. */
pos = bprm->p;
+ str += len;
+ bprm->p -= len;
while (len > 0) {
- int i, new, err;
int offset, bytes_to_copy;
- struct page *page;
offset = pos % PAGE_SIZE;
- i = pos/PAGE_SIZE;
- page = bprm->page[i];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_HIGHUSER);
- bprm->page[i] = page;
- if (!page) {
- ret = -ENOMEM;
+ if (offset == 0)
+ offset = PAGE_SIZE;
+
+ bytes_to_copy = offset;
+ if (bytes_to_copy > len)
+ bytes_to_copy = len;
+
+ offset -= bytes_to_copy;
+ pos -= bytes_to_copy;
+ str -= bytes_to_copy;
+ len -= bytes_to_copy;
+
+ if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
+ struct page *page;
+
+#ifdef CONFIG_STACK_GROWSUP
+ ret = expand_stack_downwards(bprm->vma, pos);
+ if (ret < 0) {
+ /* We've exceed the stack rlimit. */
+ ret = -E2BIG;
+ goto out;
+ }
+#endif
+ ret = get_user_pages(current, bprm->mm, pos,
+ 1, 1, 1, &page, NULL);
+ if (ret <= 0) {
+ /* We've exceed the stack rlimit. */
+ ret = -E2BIG;
goto out;
}
- new = 1;
- }
- if (page != kmapped_page) {
- if (kmapped_page)
+ if (kmapped_page) {
+ flush_kernel_dcache_page(kmapped_page);
kunmap(kmapped_page);
+ put_page(kmapped_page);
+ }
kmapped_page = page;
kaddr = kmap(kmapped_page);
+ kpos = pos & PAGE_MASK;
+ flush_cache_page(bprm->vma, kpos,
+ page_to_pfn(kmapped_page));
}
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
- err = copy_from_user(kaddr+offset, compat_ptr(str),
- bytes_to_copy);
- if (err) {
+ if (copy_from_user(kaddr+offset, compat_ptr(str),
+ bytes_to_copy)) {
ret = -EFAULT;
goto out;
}
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
}
}
ret = 0;
out:
- if (kmapped_page)
+ if (kmapped_page) {
+ flush_kernel_dcache_page(kmapped_page);
kunmap(kmapped_page);
- return ret;
-}
-
-#ifdef CONFIG_MMU
-
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
- int i;
-
- for (i = 0; i < MAX_ARG_PAGES; i++) {
- if (bprm->page[i])
- __free_page(bprm->page[i]);
- bprm->page[i] = NULL;
+ put_page(kmapped_page);
}
+ return ret;
}
-#endif /* CONFIG_MMU */
-
/*
* compat_do_execve() is mostly a copy of do_execve(), with the exception
* that it processes 32 bit argv and envp pointers.
@@ -1363,7 +1356,6 @@ int compat_do_execve(char * filename,
struct linux_binprm *bprm;
struct file *file;
int retval;
- int i;
retval = -ENOMEM;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
@@ -1377,24 +1369,19 @@ int compat_do_execve(char * filename,
sched_exec();
- bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
bprm->file = file;
bprm->filename = filename;
bprm->interp = filename;
- bprm->mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm->mm)
- goto out_file;
- retval = init_new_context(current, bprm->mm);
- if (retval < 0)
- goto out_mm;
+ retval = bprm_mm_init(bprm);
+ if (retval)
+ goto out_file;
- bprm->argc = compat_count(argv, bprm->p / sizeof(compat_uptr_t));
+ bprm->argc = compat_count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
goto out_mm;
- bprm->envc = compat_count(envp, bprm->p / sizeof(compat_uptr_t));
+ bprm->envc = compat_count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
goto out_mm;
@@ -1421,8 +1408,6 @@ int compat_do_execve(char * filename,
retval = search_binary_handler(bprm, regs);
if (retval >= 0) {
- free_arg_pages(bprm);
-
/* execve success */
security_bprm_free(bprm);
acct_update_integrals(current);
@@ -1431,19 +1416,12 @@ int compat_do_execve(char * filename,
}
out:
- /* Something went wrong, return the inode and free the argument pages*/
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page * page = bprm->page[i];
- if (page)
- __free_page(page);
- }
-
if (bprm->security)
security_bprm_free(bprm);
out_mm:
if (bprm->mm)
- mmdrop(bprm->mm);
+ mmput(bprm->mm);
out_file:
if (bprm->file) {
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 6b44cdc96fac..e440a7b95d02 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -63,6 +63,7 @@
#include <linux/wireless.h>
#include <linux/atalk.h>
#include <linux/blktrace_api.h>
+#include <linux/loop.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci.h>
@@ -3489,6 +3490,9 @@ HANDLE_IOCTL(LPSETTIMEOUT, lp_timeout_trans)
IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32)
IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32)
+
+/* loop */
+IGNORE_IOCTL(LOOP_CLR_FD)
};
#define IOCTL_HASHSIZE 256
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index 7b48c034b312..3b0185fdf9a4 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -29,10 +29,11 @@
struct configfs_dirent {
atomic_t s_count;
+ int s_dependent_count;
struct list_head s_sibling;
struct list_head s_children;
struct list_head s_links;
- void * s_element;
+ void * s_element;
int s_type;
umode_t s_mode;
struct dentry * s_dentry;
@@ -41,8 +42,8 @@ struct configfs_dirent {
#define CONFIGFS_ROOT 0x0001
#define CONFIGFS_DIR 0x0002
-#define CONFIGFS_ITEM_ATTR 0x0004
-#define CONFIGFS_ITEM_LINK 0x0020
+#define CONFIGFS_ITEM_ATTR 0x0004
+#define CONFIGFS_ITEM_LINK 0x0020
#define CONFIGFS_USET_DIR 0x0040
#define CONFIGFS_USET_DEFAULT 0x0080
#define CONFIGFS_USET_DROPPING 0x0100
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 5e6e37e58f36..2f436d4f1d6d 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -355,6 +355,10 @@ static int configfs_detach_prep(struct dentry *dentry)
/* Mark that we've taken i_mutex */
sd->s_type |= CONFIGFS_USET_DROPPING;
+ /*
+ * Yup, recursive. If there's a problem, blame
+ * deep nesting of default_groups
+ */
ret = configfs_detach_prep(sd->s_dentry);
if (!ret)
continue;
@@ -562,7 +566,7 @@ static int populate_groups(struct config_group *group)
/*
* All of link_obj/unlink_obj/link_group/unlink_group require that
- * subsys->su_sem is held.
+ * subsys->su_mutex is held.
*/
static void unlink_obj(struct config_item *item)
@@ -714,6 +718,28 @@ static void configfs_detach_group(struct config_item *item)
}
/*
+ * After the item has been detached from the filesystem view, we are
+ * ready to tear it out of the hierarchy. Notify the client before
+ * we do that so they can perform any cleanup that requires
+ * navigating the hierarchy. A client does not need to provide this
+ * callback. The subsystem semaphore MUST be held by the caller, and
+ * references must be valid for both items. It also assumes the
+ * caller has validated ci_type.
+ */
+static void client_disconnect_notify(struct config_item *parent_item,
+ struct config_item *item)
+{
+ struct config_item_type *type;
+
+ type = parent_item->ci_type;
+ BUG_ON(!type);
+
+ if (type->ct_group_ops && type->ct_group_ops->disconnect_notify)
+ type->ct_group_ops->disconnect_notify(to_config_group(parent_item),
+ item);
+}
+
+/*
* Drop the initial reference from make_item()/make_group()
* This function assumes that reference is held on item
* and that item holds a valid reference to the parent. Also, it
@@ -733,11 +759,244 @@ static void client_drop_item(struct config_item *parent_item,
*/
if (type->ct_group_ops && type->ct_group_ops->drop_item)
type->ct_group_ops->drop_item(to_config_group(parent_item),
- item);
+ item);
else
config_item_put(item);
}
+#ifdef DEBUG
+static void configfs_dump_one(struct configfs_dirent *sd, int level)
+{
+ printk(KERN_INFO "%*s\"%s\":\n", level, " ", configfs_get_name(sd));
+
+#define type_print(_type) if (sd->s_type & _type) printk(KERN_INFO "%*s %s\n", level, " ", #_type);
+ type_print(CONFIGFS_ROOT);
+ type_print(CONFIGFS_DIR);
+ type_print(CONFIGFS_ITEM_ATTR);
+ type_print(CONFIGFS_ITEM_LINK);
+ type_print(CONFIGFS_USET_DIR);
+ type_print(CONFIGFS_USET_DEFAULT);
+ type_print(CONFIGFS_USET_DROPPING);
+#undef type_print
+}
+
+static int configfs_dump(struct configfs_dirent *sd, int level)
+{
+ struct configfs_dirent *child_sd;
+ int ret = 0;
+
+ configfs_dump_one(sd, level);
+
+ if (!(sd->s_type & (CONFIGFS_DIR|CONFIGFS_ROOT)))
+ return 0;
+
+ list_for_each_entry(child_sd, &sd->s_children, s_sibling) {
+ ret = configfs_dump(child_sd, level + 2);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+
+/*
+ * configfs_depend_item() and configfs_undepend_item()
+ *
+ * WARNING: Do not call these from a configfs callback!
+ *
+ * This describes these functions and their helpers.
+ *
+ * Allow another kernel system to depend on a config_item. If this
+ * happens, the item cannot go away until the dependant can live without
+ * it. The idea is to give client modules as simple an interface as
+ * possible. When a system asks them to depend on an item, they just
+ * call configfs_depend_item(). If the item is live and the client
+ * driver is in good shape, we'll happily do the work for them.
+ *
+ * Why is the locking complex? Because configfs uses the VFS to handle
+ * all locking, but this function is called outside the normal
+ * VFS->configfs path. So it must take VFS locks to prevent the
+ * VFS->configfs stuff (configfs_mkdir(), configfs_rmdir(), etc). This is
+ * why you can't call these functions underneath configfs callbacks.
+ *
+ * Note, btw, that this can be called at *any* time, even when a configfs
+ * subsystem isn't registered, or when configfs is loading or unloading.
+ * Just like configfs_register_subsystem(). So we take the same
+ * precautions. We pin the filesystem. We lock each i_mutex _in_order_
+ * on our way down the tree. If we can find the target item in the
+ * configfs tree, it must be part of the subsystem tree as well, so we
+ * do not need the subsystem semaphore. Holding the i_mutex chain locks
+ * out mkdir() and rmdir(), who might be racing us.
+ */
+
+/*
+ * configfs_depend_prep()
+ *
+ * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are
+ * attributes. This is similar but not the same to configfs_detach_prep().
+ * Note that configfs_detach_prep() expects the parent to be locked when it
+ * is called, but we lock the parent *inside* configfs_depend_prep(). We
+ * do that so we can unlock it if we find nothing.
+ *
+ * Here we do a depth-first search of the dentry hierarchy looking for
+ * our object. We take i_mutex on each step of the way down. IT IS
+ * ESSENTIAL THAT i_mutex LOCKING IS ORDERED. If we come back up a branch,
+ * we'll drop the i_mutex.
+ *
+ * If the target is not found, -ENOENT is bubbled up and we have released
+ * all locks. If the target was found, the locks will be cleared by
+ * configfs_depend_rollback().
+ *
+ * This adds a requirement that all config_items be unique!
+ *
+ * This is recursive because the locking traversal is tricky. There isn't
+ * much on the stack, though, so folks that need this function - be careful
+ * about your stack! Patches will be accepted to make it iterative.
+ */
+static int configfs_depend_prep(struct dentry *origin,
+ struct config_item *target)
+{
+ struct configfs_dirent *child_sd, *sd = origin->d_fsdata;
+ int ret = 0;
+
+ BUG_ON(!origin || !sd);
+
+ /* Lock this guy on the way down */
+ mutex_lock(&sd->s_dentry->d_inode->i_mutex);
+ if (sd->s_element == target) /* Boo-yah */
+ goto out;
+
+ list_for_each_entry(child_sd, &sd->s_children, s_sibling) {
+ if (child_sd->s_type & CONFIGFS_DIR) {
+ ret = configfs_depend_prep(child_sd->s_dentry,
+ target);
+ if (!ret)
+ goto out; /* Child path boo-yah */
+ }
+ }
+
+ /* We looped all our children and didn't find target */
+ mutex_unlock(&sd->s_dentry->d_inode->i_mutex);
+ ret = -ENOENT;
+
+out:
+ return ret;
+}
+
+/*
+ * This is ONLY called if configfs_depend_prep() did its job. So we can
+ * trust the entire path from item back up to origin.
+ *
+ * We walk backwards from item, unlocking each i_mutex. We finish by
+ * unlocking origin.
+ */
+static void configfs_depend_rollback(struct dentry *origin,
+ struct config_item *item)
+{
+ struct dentry *dentry = item->ci_dentry;
+
+ while (dentry != origin) {
+ mutex_unlock(&dentry->d_inode->i_mutex);
+ dentry = dentry->d_parent;
+ }
+
+ mutex_unlock(&origin->d_inode->i_mutex);
+}
+
+int configfs_depend_item(struct configfs_subsystem *subsys,
+ struct config_item *target)
+{
+ int ret;
+ struct configfs_dirent *p, *root_sd, *subsys_sd = NULL;
+ struct config_item *s_item = &subsys->su_group.cg_item;
+
+ /*
+ * Pin the configfs filesystem. This means we can safely access
+ * the root of the configfs filesystem.
+ */
+ ret = configfs_pin_fs();
+ if (ret)
+ return ret;
+
+ /*
+ * Next, lock the root directory. We're going to check that the
+ * subsystem is really registered, and so we need to lock out
+ * configfs_[un]register_subsystem().
+ */
+ mutex_lock(&configfs_sb->s_root->d_inode->i_mutex);
+
+ root_sd = configfs_sb->s_root->d_fsdata;
+
+ list_for_each_entry(p, &root_sd->s_children, s_sibling) {
+ if (p->s_type & CONFIGFS_DIR) {
+ if (p->s_element == s_item) {
+ subsys_sd = p;
+ break;
+ }
+ }
+ }
+
+ if (!subsys_sd) {
+ ret = -ENOENT;
+ goto out_unlock_fs;
+ }
+
+ /* Ok, now we can trust subsys/s_item */
+
+ /* Scan the tree, locking i_mutex recursively, return 0 if found */
+ ret = configfs_depend_prep(subsys_sd->s_dentry, target);
+ if (ret)
+ goto out_unlock_fs;
+
+ /* We hold all i_mutexes from the subsystem down to the target */
+ p = target->ci_dentry->d_fsdata;
+ p->s_dependent_count += 1;
+
+ configfs_depend_rollback(subsys_sd->s_dentry, target);
+
+out_unlock_fs:
+ mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex);
+
+ /*
+ * If we succeeded, the fs is pinned via other methods. If not,
+ * we're done with it anyway. So release_fs() is always right.
+ */
+ configfs_release_fs();
+
+ return ret;
+}
+EXPORT_SYMBOL(configfs_depend_item);
+
+/*
+ * Release the dependent linkage. This is much simpler than
+ * configfs_depend_item() because we know that that the client driver is
+ * pinned, thus the subsystem is pinned, and therefore configfs is pinned.
+ */
+void configfs_undepend_item(struct configfs_subsystem *subsys,
+ struct config_item *target)
+{
+ struct configfs_dirent *sd;
+
+ /*
+ * Since we can trust everything is pinned, we just need i_mutex
+ * on the item.
+ */
+ mutex_lock(&target->ci_dentry->d_inode->i_mutex);
+
+ sd = target->ci_dentry->d_fsdata;
+ BUG_ON(sd->s_dependent_count < 1);
+
+ sd->s_dependent_count -= 1;
+
+ /*
+ * After this unlock, we cannot trust the item to stay alive!
+ * DO NOT REFERENCE item after this unlock.
+ */
+ mutex_unlock(&target->ci_dentry->d_inode->i_mutex);
+}
+EXPORT_SYMBOL(configfs_undepend_item);
static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
@@ -783,7 +1042,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name);
- down(&subsys->su_sem);
+ mutex_lock(&subsys->su_mutex);
group = NULL;
item = NULL;
if (type->ct_group_ops->make_group) {
@@ -797,7 +1056,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (item)
link_obj(parent_item, item);
}
- up(&subsys->su_sem);
+ mutex_unlock(&subsys->su_mutex);
kfree(name);
if (!item) {
@@ -841,13 +1100,16 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
out_unlink:
if (ret) {
/* Tear down everything we built up */
- down(&subsys->su_sem);
+ mutex_lock(&subsys->su_mutex);
+
+ client_disconnect_notify(parent_item, item);
if (group)
unlink_group(group);
else
unlink_obj(item);
client_drop_item(parent_item, item);
- up(&subsys->su_sem);
+
+ mutex_unlock(&subsys->su_mutex);
if (module_got)
module_put(owner);
@@ -881,6 +1143,13 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
if (sd->s_type & CONFIGFS_USET_DEFAULT)
return -EPERM;
+ /*
+ * Here's where we check for dependents. We're protected by
+ * i_mutex.
+ */
+ if (sd->s_dependent_count)
+ return -EBUSY;
+
/* Get a working ref until we have the child */
parent_item = configfs_get_config_item(dentry->d_parent);
subsys = to_config_group(parent_item)->cg_subsys;
@@ -910,17 +1179,19 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
if (sd->s_type & CONFIGFS_USET_DIR) {
configfs_detach_group(item);
- down(&subsys->su_sem);
+ mutex_lock(&subsys->su_mutex);
+ client_disconnect_notify(parent_item, item);
unlink_group(to_config_group(item));
} else {
configfs_detach_item(item);
- down(&subsys->su_sem);
+ mutex_lock(&subsys->su_mutex);
+ client_disconnect_notify(parent_item, item);
unlink_obj(item);
}
client_drop_item(parent_item, item);
- up(&subsys->su_sem);
+ mutex_unlock(&subsys->su_mutex);
/* Drop our reference from above */
config_item_put(item);
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index 3527c7c6def8..a3658f9a082c 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -27,19 +27,26 @@
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
#include <linux/configfs.h>
#include "configfs_internal.h"
+/*
+ * A simple attribute can only be 4096 characters. Why 4k? Because the
+ * original code limited it to PAGE_SIZE. That's a bad idea, though,
+ * because an attribute of 16k on ia64 won't work on x86. So we limit to
+ * 4k, our minimum common page size.
+ */
+#define SIMPLE_ATTR_SIZE 4096
struct configfs_buffer {
size_t count;
loff_t pos;
char * page;
struct configfs_item_operations * ops;
- struct semaphore sem;
+ struct mutex mutex;
int needs_read_fill;
};
@@ -69,7 +76,7 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf
count = ops->show_attribute(item,attr,buffer->page);
buffer->needs_read_fill = 0;
- BUG_ON(count > (ssize_t)PAGE_SIZE);
+ BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE);
if (count >= 0)
buffer->count = count;
else
@@ -102,7 +109,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
struct configfs_buffer * buffer = file->private_data;
ssize_t retval = 0;
- down(&buffer->sem);
+ mutex_lock(&buffer->mutex);
if (buffer->needs_read_fill) {
if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
goto out;
@@ -112,7 +119,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
buffer->count);
out:
- up(&buffer->sem);
+ mutex_unlock(&buffer->mutex);
return retval;
}
@@ -137,8 +144,8 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size
if (!buffer->page)
return -ENOMEM;
- if (count >= PAGE_SIZE)
- count = PAGE_SIZE - 1;
+ if (count >= SIMPLE_ATTR_SIZE)
+ count = SIMPLE_ATTR_SIZE - 1;
error = copy_from_user(buffer->page,buf,count);
buffer->needs_read_fill = 1;
/* if buf is assumed to contain a string, terminate it by \0,
@@ -193,13 +200,13 @@ configfs_write_file(struct file *file, const char __user *buf, size_t count, lof
struct configfs_buffer * buffer = file->private_data;
ssize_t len;
- down(&buffer->sem);
+ mutex_lock(&buffer->mutex);
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
len = flush_write_buffer(file->f_path.dentry, buffer, count);
if (len > 0)
*ppos += len;
- up(&buffer->sem);
+ mutex_unlock(&buffer->mutex);
return len;
}
@@ -253,7 +260,7 @@ static int check_perm(struct inode * inode, struct file * file)
error = -ENOMEM;
goto Enomem;
}
- init_MUTEX(&buffer->sem);
+ mutex_init(&buffer->mutex);
buffer->needs_read_fill = 1;
buffer->ops = ops;
file->private_data = buffer;
@@ -292,6 +299,7 @@ static int configfs_release(struct inode * inode, struct file * filp)
if (buffer) {
if (buffer->page)
free_page((unsigned long)buffer->page);
+ mutex_destroy(&buffer->mutex);
kfree(buffer);
}
return 0;
diff --git a/fs/configfs/item.c b/fs/configfs/item.c
index 24421209f854..76dc4c3e5d51 100644
--- a/fs/configfs/item.c
+++ b/fs/configfs/item.c
@@ -62,7 +62,6 @@ void config_item_init(struct config_item * item)
* dynamically allocated string that @item->ci_name points to.
* Otherwise, use the static @item->ci_namebuf array.
*/
-
int config_item_set_name(struct config_item * item, const char * fmt, ...)
{
int error = 0;
@@ -139,12 +138,7 @@ struct config_item * config_item_get(struct config_item * item)
return item;
}
-/**
- * config_item_cleanup - free config_item resources.
- * @item: item.
- */
-
-void config_item_cleanup(struct config_item * item)
+static void config_item_cleanup(struct config_item * item)
{
struct config_item_type * t = item->ci_type;
struct config_group * s = item->ci_group;
@@ -179,39 +173,35 @@ void config_item_put(struct config_item * item)
kref_put(&item->ci_kref, config_item_release);
}
-
/**
* config_group_init - initialize a group for use
* @k: group
*/
-
void config_group_init(struct config_group *group)
{
config_item_init(&group->cg_item);
INIT_LIST_HEAD(&group->cg_children);
}
-
/**
- * config_group_find_obj - search for item in group.
+ * config_group_find_item - search for item in group.
* @group: group we're looking in.
* @name: item's name.
*
- * Lock group via @group->cg_subsys, and iterate over @group->cg_list,
- * looking for a matching config_item. If matching item is found
- * take a reference and return the item.
+ * Iterate over @group->cg_list, looking for a matching config_item.
+ * If matching item is found take a reference and return the item.
+ * Caller must have locked group via @group->cg_subsys->su_mtx.
*/
-
-struct config_item * config_group_find_obj(struct config_group * group, const char * name)
+struct config_item *config_group_find_item(struct config_group *group,
+ const char *name)
{
struct list_head * entry;
struct config_item * ret = NULL;
- /* XXX LOCKING! */
list_for_each(entry,&group->cg_children) {
struct config_item * item = to_item(entry);
if (config_item_name(item) &&
- !strcmp(config_item_name(item), name)) {
+ !strcmp(config_item_name(item), name)) {
ret = config_item_get(item);
break;
}
@@ -219,9 +209,8 @@ struct config_item * config_group_find_obj(struct config_group * group, const ch
return ret;
}
-
EXPORT_SYMBOL(config_item_init);
EXPORT_SYMBOL(config_group_init);
EXPORT_SYMBOL(config_item_get);
EXPORT_SYMBOL(config_item_put);
-EXPORT_SYMBOL(config_group_find_obj);
+EXPORT_SYMBOL(config_group_find_item);
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index b00d962de833..871b0cb61839 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -136,7 +136,7 @@ static int __init configfs_init(void)
configfs_dir_cachep = kmem_cache_create("configfs_dir_cache",
sizeof(struct configfs_dirent),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!configfs_dir_cachep)
goto out;
diff --git a/fs/dcache.c b/fs/dcache.c
index 0e73aa0a0e8b..678d39deb607 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -883,6 +883,11 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
}
+static struct shrinker dcache_shrinker = {
+ .shrink = shrink_dcache_memory,
+ .seeks = DEFAULT_SEEKS,
+};
+
/**
* d_alloc - allocate a dcache entry
* @parent: parent of entry to allocate
@@ -2115,7 +2120,7 @@ static void __init dcache_init(unsigned long mempages)
dentry_cache = KMEM_CACHE(dentry,
SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD);
- set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory);
+ register_shrinker(&dcache_shrinker);
/* Hash may have been set up in dcache_init_early */
if (!hashdist)
@@ -2160,10 +2165,10 @@ void __init vfs_caches_init(unsigned long mempages)
mempages -= reserve;
names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
dcache_init(mempages);
inode_init(mempages);
diff --git a/fs/dcookies.c b/fs/dcookies.c
index 21af1629f9bc..c1208f53bd74 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -205,7 +205,7 @@ static int dcookie_init(void)
dcookie_cache = kmem_cache_create("dcookie_cache",
sizeof(struct dcookie_struct),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!dcookie_cache)
goto out;
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index ec8896b264de..11be8a325e26 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -345,11 +345,6 @@ void debugfs_remove(struct dentry *dentry)
switch (dentry->d_inode->i_mode & S_IFMT) {
case S_IFDIR:
ret = simple_rmdir(parent->d_inode, dentry);
- if (ret)
- printk(KERN_ERR
- "DebugFS rmdir on %s failed : "
- "directory not empty.\n",
- dentry->d_name.name);
break;
case S_IFLNK:
kfree(dentry->d_inode->i_private);
@@ -368,6 +363,69 @@ void debugfs_remove(struct dentry *dentry)
}
EXPORT_SYMBOL_GPL(debugfs_remove);
+/**
+ * debugfs_rename - rename a file/directory in the debugfs filesystem
+ * @old_dir: a pointer to the parent dentry for the renamed object. This
+ * should be a directory dentry.
+ * @old_dentry: dentry of an object to be renamed.
+ * @new_dir: a pointer to the parent dentry where the object should be
+ * moved. This should be a directory dentry.
+ * @new_name: a pointer to a string containing the target name.
+ *
+ * This function renames a file/directory in debugfs. The target must not
+ * exist for rename to succeed.
+ *
+ * This function will return a pointer to old_dentry (which is updated to
+ * reflect renaming) if it succeeds. If an error occurs, %NULL will be
+ * returned.
+ *
+ * If debugfs is not enabled in the kernel, the value -%ENODEV will be
+ * returned.
+ */
+struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
+ struct dentry *new_dir, const char *new_name)
+{
+ int error;
+ struct dentry *dentry = NULL, *trap;
+ const char *old_name;
+
+ trap = lock_rename(new_dir, old_dir);
+ /* Source or destination directories don't exist? */
+ if (!old_dir->d_inode || !new_dir->d_inode)
+ goto exit;
+ /* Source does not exist, cyclic rename, or mountpoint? */
+ if (!old_dentry->d_inode || old_dentry == trap ||
+ d_mountpoint(old_dentry))
+ goto exit;
+ dentry = lookup_one_len(new_name, new_dir, strlen(new_name));
+ /* Lookup failed, cyclic rename or target exists? */
+ if (IS_ERR(dentry) || dentry == trap || dentry->d_inode)
+ goto exit;
+
+ old_name = fsnotify_oldname_init(old_dentry->d_name.name);
+
+ error = simple_rename(old_dir->d_inode, old_dentry, new_dir->d_inode,
+ dentry);
+ if (error) {
+ fsnotify_oldname_free(old_name);
+ goto exit;
+ }
+ d_move(old_dentry, dentry);
+ fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name,
+ old_dentry->d_name.name, S_ISDIR(old_dentry->d_inode->i_mode),
+ NULL, old_dentry->d_inode);
+ fsnotify_oldname_free(old_name);
+ unlock_rename(new_dir, old_dir);
+ dput(dentry);
+ return old_dentry;
+exit:
+ if (dentry && !IS_ERR(dentry))
+ dput(dentry);
+ unlock_rename(new_dir, old_dir);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(debugfs_rename);
+
static decl_subsys(debug, NULL, NULL);
static int __init debugfs_init(void)
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index 5069b2cb5a1f..2f8e3c81bc19 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -133,14 +133,6 @@ static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field,
return len;
}
-#define __CONFIGFS_ATTR(_name,_mode,_read,_write) { \
- .attr = { .ca_name = __stringify(_name), \
- .ca_mode = _mode, \
- .ca_owner = THIS_MODULE }, \
- .show = _read, \
- .store = _write, \
-}
-
#define CLUSTER_ATTR(name, check_zero) \
static ssize_t name##_write(struct cluster *cl, const char *buf, size_t len) \
{ \
@@ -615,7 +607,7 @@ static struct clusters clusters_root = {
int dlm_config_init(void)
{
config_group_init(&clusters_root.subsys.su_group);
- init_MUTEX(&clusters_root.subsys.su_sem);
+ mutex_init(&clusters_root.subsys.su_mutex);
return configfs_register_subsystem(&clusters_root.subsys);
}
@@ -759,9 +751,9 @@ static struct space *get_space(char *name)
if (!space_list)
return NULL;
- down(&space_list->cg_subsys->su_sem);
- i = config_group_find_obj(space_list, name);
- up(&space_list->cg_subsys->su_sem);
+ mutex_lock(&space_list->cg_subsys->su_mutex);
+ i = config_group_find_item(space_list, name);
+ mutex_unlock(&space_list->cg_subsys->su_mutex);
return to_space(i);
}
@@ -780,7 +772,7 @@ static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr)
if (!comm_list)
return NULL;
- down(&clusters_root.subsys.su_sem);
+ mutex_lock(&clusters_root.subsys.su_mutex);
list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
cm = to_comm(i);
@@ -800,7 +792,7 @@ static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr)
break;
}
}
- up(&clusters_root.subsys.su_sem);
+ mutex_unlock(&clusters_root.subsys.su_mutex);
if (!found)
cm = NULL;
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 0553a6158dcb..dd362739d291 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -1449,7 +1449,7 @@ int dlm_lowcomms_start(void)
error = -ENOMEM;
con_cache = kmem_cache_create("dlm_conn", sizeof(struct connection),
__alignof__(struct connection), 0,
- NULL, NULL);
+ NULL);
if (!con_cache)
goto out;
diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c
index f858fef6e41c..ecf0e5cb2035 100644
--- a/fs/dlm/memory.c
+++ b/fs/dlm/memory.c
@@ -23,7 +23,7 @@ int dlm_memory_init(void)
int ret = 0;
lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
- __alignof__(struct dlm_lkb), 0, NULL, NULL);
+ __alignof__(struct dlm_lkb), 0, NULL);
if (!lkb_cache)
ret = -ENOMEM;
return ret;
@@ -39,9 +39,7 @@ char *allocate_lvb(struct dlm_ls *ls)
{
char *p;
- p = kmalloc(ls->ls_lvblen, GFP_KERNEL);
- if (p)
- memset(p, 0, ls->ls_lvblen);
+ p = kzalloc(ls->ls_lvblen, GFP_KERNEL);
return p;
}
@@ -59,9 +57,7 @@ struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen)
DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);
- r = kmalloc(sizeof(*r) + namelen, GFP_KERNEL);
- if (r)
- memset(r, 0, sizeof(*r) + namelen);
+ r = kzalloc(sizeof(*r) + namelen, GFP_KERNEL);
return r;
}
@@ -101,9 +97,7 @@ struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen)
DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,
printk("namelen = %d\n", namelen););
- de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL);
- if (de)
- memset(de, 0, sizeof(*de) + namelen);
+ de = kzalloc(sizeof(*de) + namelen, GFP_KERNEL);
return de;
}
diff --git a/fs/dnotify.c b/fs/dnotify.c
index 936409fcd939..28d01ed66de0 100644
--- a/fs/dnotify.c
+++ b/fs/dnotify.c
@@ -176,7 +176,7 @@ EXPORT_SYMBOL_GPL(dnotify_parent);
static int __init dnotify_init(void)
{
dn_cache = kmem_cache_create("dnotify_cache",
- sizeof(struct dnotify_struct), 0, SLAB_PANIC, NULL, NULL);
+ sizeof(struct dnotify_struct), 0, SLAB_PANIC, NULL);
return 0;
}
diff --git a/fs/dquot.c b/fs/dquot.c
index 8819d281500c..de9a29f64ff3 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -538,6 +538,11 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure;
}
+static struct shrinker dqcache_shrinker = {
+ .shrink = shrink_dqcache_memory,
+ .seeks = DEFAULT_SEEKS,
+};
+
/*
* Put reference to dquot
* NOTE: If you change this function please check whether dqput_blocks() works right...
@@ -1843,11 +1848,11 @@ static int __init dquot_init(void)
register_sysctl_table(sys_table);
- dquot_cachep = kmem_cache_create("dquot",
+ dquot_cachep = kmem_cache_create("dquot",
sizeof(struct dquot), sizeof(unsigned long) * 4,
(SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD|SLAB_PANIC),
- NULL, NULL);
+ NULL);
order = 0;
dquot_hash = (struct hlist_head *)__get_free_pages(GFP_ATOMIC, order);
@@ -1870,7 +1875,7 @@ static int __init dquot_init(void)
printk("Dquot-cache hash table entries: %ld (order %ld, %ld bytes)\n",
nr_hash, order, (PAGE_SIZE << order));
- set_shrinker(DEFAULT_SEEKS, shrink_dqcache_memory);
+ register_shrinker(&dqcache_shrinker);
return 0;
}
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index 03ea7696fe39..59375efcf39d 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -20,7 +20,7 @@ static void drop_pagecache_sb(struct super_block *sb)
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (inode->i_state & (I_FREEING|I_WILL_FREE))
continue;
- invalidate_mapping_pages(inode->i_mapping, 0, -1);
+ __invalidate_mapping_pages(inode->i_mapping, 0, -1, true);
}
spin_unlock(&inode_lock);
}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 83e94fedd4e9..0a50942b4378 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -282,7 +282,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
struct dentry *lower_dentry;
struct vfsmount *lower_mnt;
char *encoded_name;
- unsigned int encoded_namelen;
+ int encoded_namelen;
struct ecryptfs_crypt_stat *crypt_stat = NULL;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
char *page_virt = NULL;
@@ -473,7 +473,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
struct dentry *lower_dir_dentry;
umode_t mode;
char *encoded_symname;
- unsigned int encoded_symlen;
+ int encoded_symlen;
struct ecryptfs_crypt_stat *crypt_stat = NULL;
lower_dentry = ecryptfs_dentry_to_lower(dentry);
@@ -902,8 +902,9 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
mutex_lock(&crypt_stat->cs_mutex);
if (S_ISDIR(dentry->d_inode->i_mode))
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
- else if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
- || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) {
+ else if (S_ISREG(dentry->d_inode->i_mode)
+ && (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)
+ || !(crypt_stat->flags & ECRYPTFS_KEY_VALID))) {
struct vfsmount *lower_mnt;
struct file *lower_file = NULL;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 606128f5c927..e557a6766927 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -677,7 +677,7 @@ static int ecryptfs_init_kmem_caches(void)
info = &ecryptfs_cache_infos[i];
*(info->cache) = kmem_cache_create(info->name, info->size,
- 0, SLAB_HWCACHE_ALIGN, info->ctor, NULL);
+ 0, SLAB_HWCACHE_ALIGN, info->ctor);
if (!*(info->cache)) {
ecryptfs_free_kmem_caches();
ecryptfs_printk(KERN_WARNING, "%s: "
@@ -840,8 +840,6 @@ static int __init ecryptfs_init(void)
goto out;
}
kobj_set_kset_s(&ecryptfs_subsys, fs_subsys);
- sysfs_attr_version.attr.owner = THIS_MODULE;
- sysfs_attr_version_str.attr.owner = THIS_MODULE;
rc = do_sysfs_registration();
if (rc) {
printk(KERN_ERR "sysfs registration failed\n");
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 7d5a43cb0d5c..e4ab7bc14efe 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -409,8 +409,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
if (!PageUptodate(page))
rc = ecryptfs_do_readpage(file, page, page->index);
if (page->index != 0) {
- loff_t end_of_prev_pg_pos =
- (((loff_t)page->index << PAGE_CACHE_SHIFT) - 1);
+ loff_t end_of_prev_pg_pos = page_offset(page) - 1;
if (end_of_prev_pg_pos > i_size_read(page->mapping->host)) {
rc = ecryptfs_truncate(file->f_path.dentry,
@@ -736,7 +735,7 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
goto out;
}
inode->i_blocks = lower_inode->i_blocks;
- pos = (page->index << PAGE_CACHE_SHIFT) + to;
+ pos = page_offset(page) + to;
if (pos > i_size_read(inode)) {
i_size_write(inode, pos);
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
diff --git a/fs/efs/namei.c b/fs/efs/namei.c
index ed4a207fe22a..5276b19423c1 100644
--- a/fs/efs/namei.c
+++ b/fs/efs/namei.c
@@ -75,6 +75,38 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei
return NULL;
}
+struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp)
+{
+ __u32 *objp = vobjp;
+ unsigned long ino = objp[0];
+ __u32 generation = objp[1];
+ struct inode *inode;
+ struct dentry *result;
+
+ if (ino == 0)
+ return ERR_PTR(-ESTALE);
+ inode = iget(sb, ino);
+ if (inode == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ if (is_bad_inode(inode) ||
+ (generation && inode->i_generation != generation)) {
+ result = ERR_PTR(-ESTALE);
+ goto out_iput;
+ }
+
+ result = d_alloc_anon(inode);
+ if (!result) {
+ result = ERR_PTR(-ENOMEM);
+ goto out_iput;
+ }
+ return result;
+
+ out_iput:
+ iput(inode);
+ return result;
+}
+
struct dentry *efs_get_parent(struct dentry *child)
{
struct dentry *parent;
diff --git a/fs/efs/super.c b/fs/efs/super.c
index e0a6839e68ae..ce4acb8ff819 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -11,6 +11,7 @@
#include <linux/efs_fs.h>
#include <linux/efs_vh.h>
#include <linux/efs_fs_sb.h>
+#include <linux/exportfs.h>
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
@@ -74,13 +75,13 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
efs_inode_cachep = kmem_cache_create("efs_inode_cache",
sizeof(struct efs_inode_info),
0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- init_once, NULL);
+ init_once);
if (efs_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -113,6 +114,7 @@ static const struct super_operations efs_superblock_operations = {
};
static struct export_operations efs_export_ops = {
+ .get_dentry = efs_get_dentry,
.get_parent = efs_get_parent,
};
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 0b73cd45a06d..77b9953624f4 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -1324,12 +1324,12 @@ static int __init eventpoll_init(void)
/* Allocates slab cache used to allocate "struct epitem" items */
epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem),
0, SLAB_HWCACHE_ALIGN|EPI_SLAB_DEBUG|SLAB_PANIC,
- NULL, NULL);
+ NULL);
/* Allocates slab cache used to allocate "struct eppoll_entry" */
pwq_cache = kmem_cache_create("eventpoll_pwq",
sizeof(struct eppoll_entry), 0,
- EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);
+ EPI_SLAB_DEBUG|SLAB_PANIC, NULL);
return 0;
}
diff --git a/fs/exec.c b/fs/exec.c
index f20561ff4528..7bdea7937ee8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -54,6 +54,7 @@
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
+#include <asm/tlb.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
@@ -178,6 +179,207 @@ exit:
goto out;
}
+#ifdef CONFIG_MMU
+
+static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ int write)
+{
+ struct page *page;
+ int ret;
+
+#ifdef CONFIG_STACK_GROWSUP
+ if (write) {
+ ret = expand_stack_downwards(bprm->vma, pos);
+ if (ret < 0)
+ return NULL;
+ }
+#endif
+ ret = get_user_pages(current, bprm->mm, pos,
+ 1, write, 1, &page, NULL);
+ if (ret <= 0)
+ return NULL;
+
+ if (write) {
+ struct rlimit *rlim = current->signal->rlim;
+ unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start;
+
+ /*
+ * Limit to 1/4-th the stack size for the argv+env strings.
+ * This ensures that:
+ * - the remaining binfmt code will not run out of stack space,
+ * - the program will have a reasonable amount of stack left
+ * to work from.
+ */
+ if (size > rlim[RLIMIT_STACK].rlim_cur / 4) {
+ put_page(page);
+ return NULL;
+ }
+ }
+
+ return page;
+}
+
+static void put_arg_page(struct page *page)
+{
+ put_page(page);
+}
+
+static void free_arg_page(struct linux_binprm *bprm, int i)
+{
+}
+
+static void free_arg_pages(struct linux_binprm *bprm)
+{
+}
+
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ struct page *page)
+{
+ flush_cache_page(bprm->vma, pos, page_to_pfn(page));
+}
+
+static int __bprm_mm_init(struct linux_binprm *bprm)
+{
+ int err = -ENOMEM;
+ struct vm_area_struct *vma = NULL;
+ struct mm_struct *mm = bprm->mm;
+
+ bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
+ if (!vma)
+ goto err;
+
+ down_write(&mm->mmap_sem);
+ vma->vm_mm = mm;
+
+ /*
+ * Place the stack at the largest stack address the architecture
+ * supports. Later, we'll move this to an appropriate place. We don't
+ * use STACK_TOP because that can depend on attributes which aren't
+ * configured yet.
+ */
+ vma->vm_end = STACK_TOP_MAX;
+ vma->vm_start = vma->vm_end - PAGE_SIZE;
+
+ vma->vm_flags = VM_STACK_FLAGS;
+ vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
+ err = insert_vm_struct(mm, vma);
+ if (err) {
+ up_write(&mm->mmap_sem);
+ goto err;
+ }
+
+ mm->stack_vm = mm->total_vm = 1;
+ up_write(&mm->mmap_sem);
+
+ bprm->p = vma->vm_end - sizeof(void *);
+
+ return 0;
+
+err:
+ if (vma) {
+ bprm->vma = NULL;
+ kmem_cache_free(vm_area_cachep, vma);
+ }
+
+ return err;
+}
+
+static bool valid_arg_len(struct linux_binprm *bprm, long len)
+{
+ return len <= MAX_ARG_STRLEN;
+}
+
+#else
+
+static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ int write)
+{
+ struct page *page;
+
+ page = bprm->page[pos / PAGE_SIZE];
+ if (!page && write) {
+ page = alloc_page(GFP_HIGHUSER|__GFP_ZERO);
+ if (!page)
+ return NULL;
+ bprm->page[pos / PAGE_SIZE] = page;
+ }
+
+ return page;
+}
+
+static void put_arg_page(struct page *page)
+{
+}
+
+static void free_arg_page(struct linux_binprm *bprm, int i)
+{
+ if (bprm->page[i]) {
+ __free_page(bprm->page[i]);
+ bprm->page[i] = NULL;
+ }
+}
+
+static void free_arg_pages(struct linux_binprm *bprm)
+{
+ int i;
+
+ for (i = 0; i < MAX_ARG_PAGES; i++)
+ free_arg_page(bprm, i);
+}
+
+static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos,
+ struct page *page)
+{
+}
+
+static int __bprm_mm_init(struct linux_binprm *bprm)
+{
+ bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *);
+ return 0;
+}
+
+static bool valid_arg_len(struct linux_binprm *bprm, long len)
+{
+ return len <= bprm->p;
+}
+
+#endif /* CONFIG_MMU */
+
+/*
+ * Create a new mm_struct and populate it with a temporary stack
+ * vm_area_struct. We don't have enough context at this point to set the stack
+ * flags, permissions, and offset, so we use temporary values. We'll update
+ * them later in setup_arg_pages().
+ */
+int bprm_mm_init(struct linux_binprm *bprm)
+{
+ int err;
+ struct mm_struct *mm = NULL;
+
+ bprm->mm = mm = mm_alloc();
+ err = -ENOMEM;
+ if (!mm)
+ goto err;
+
+ err = init_new_context(current, mm);
+ if (err)
+ goto err;
+
+ err = __bprm_mm_init(bprm);
+ if (err)
+ goto err;
+
+ return 0;
+
+err:
+ if (mm) {
+ bprm->mm = NULL;
+ mmdrop(mm);
+ }
+
+ return err;
+}
+
/*
* count() counts the number of strings in array ARGV.
*/
@@ -203,15 +405,16 @@ static int count(char __user * __user * argv, int max)
}
/*
- * 'copy_strings()' copies argument/environment strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
+ * 'copy_strings()' copies argument/environment strings from the old
+ * processes's memory to the new process's stack. The call to get_user_pages()
+ * ensures the destination page is created and not swapped out.
*/
static int copy_strings(int argc, char __user * __user * argv,
struct linux_binprm *bprm)
{
struct page *kmapped_page = NULL;
char *kaddr = NULL;
+ unsigned long kpos = 0;
int ret;
while (argc-- > 0) {
@@ -220,69 +423,69 @@ static int copy_strings(int argc, char __user * __user * argv,
unsigned long pos;
if (get_user(str, argv+argc) ||
- !(len = strnlen_user(str, bprm->p))) {
+ !(len = strnlen_user(str, MAX_ARG_STRLEN))) {
ret = -EFAULT;
goto out;
}
- if (bprm->p < len) {
+ if (!valid_arg_len(bprm, len)) {
ret = -E2BIG;
goto out;
}
- bprm->p -= len;
- /* XXX: add architecture specific overflow check here. */
+ /* We're going to work our way backwords. */
pos = bprm->p;
+ str += len;
+ bprm->p -= len;
while (len > 0) {
- int i, new, err;
int offset, bytes_to_copy;
- struct page *page;
offset = pos % PAGE_SIZE;
- i = pos/PAGE_SIZE;
- page = bprm->page[i];
- new = 0;
- if (!page) {
- page = alloc_page(GFP_HIGHUSER);
- bprm->page[i] = page;
+ if (offset == 0)
+ offset = PAGE_SIZE;
+
+ bytes_to_copy = offset;
+ if (bytes_to_copy > len)
+ bytes_to_copy = len;
+
+ offset -= bytes_to_copy;
+ pos -= bytes_to_copy;
+ str -= bytes_to_copy;
+ len -= bytes_to_copy;
+
+ if (!kmapped_page || kpos != (pos & PAGE_MASK)) {
+ struct page *page;
+
+ page = get_arg_page(bprm, pos, 1);
if (!page) {
- ret = -ENOMEM;
+ ret = -E2BIG;
goto out;
}
- new = 1;
- }
- if (page != kmapped_page) {
- if (kmapped_page)
+ if (kmapped_page) {
+ flush_kernel_dcache_page(kmapped_page);
kunmap(kmapped_page);
+ put_arg_page(kmapped_page);
+ }
kmapped_page = page;
kaddr = kmap(kmapped_page);
+ kpos = pos & PAGE_MASK;
+ flush_arg_page(bprm, kpos, kmapped_page);
}
- if (new && offset)
- memset(kaddr, 0, offset);
- bytes_to_copy = PAGE_SIZE - offset;
- if (bytes_to_copy > len) {
- bytes_to_copy = len;
- if (new)
- memset(kaddr+offset+len, 0,
- PAGE_SIZE-offset-len);
- }
- err = copy_from_user(kaddr+offset, str, bytes_to_copy);
- if (err) {
+ if (copy_from_user(kaddr+offset, str, bytes_to_copy)) {
ret = -EFAULT;
goto out;
}
-
- pos += bytes_to_copy;
- str += bytes_to_copy;
- len -= bytes_to_copy;
}
}
ret = 0;
out:
- if (kmapped_page)
+ if (kmapped_page) {
+ flush_kernel_dcache_page(kmapped_page);
kunmap(kmapped_page);
+ put_arg_page(kmapped_page);
+ }
return ret;
}
@@ -298,181 +501,172 @@ int copy_strings_kernel(int argc,char ** argv, struct linux_binprm *bprm)
set_fs(oldfs);
return r;
}
-
EXPORT_SYMBOL(copy_strings_kernel);
#ifdef CONFIG_MMU
+
/*
- * This routine is used to map in a page into an address space: needed by
- * execve() for the initial stack and environment pages.
+ * During bprm_mm_init(), we create a temporary stack at STACK_TOP_MAX. Once
+ * the binfmt code determines where the new stack should reside, we shift it to
+ * its final location. The process proceeds as follows:
*
- * vma->vm_mm->mmap_sem is held for writing.
+ * 1) Use shift to calculate the new vma endpoints.
+ * 2) Extend vma to cover both the old and new ranges. This ensures the
+ * arguments passed to subsequent functions are consistent.
+ * 3) Move vma's page tables to the new range.
+ * 4) Free up any cleared pgd range.
+ * 5) Shrink the vma to cover only the new range.
*/
-void install_arg_page(struct vm_area_struct *vma,
- struct page *page, unsigned long address)
+static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
{
struct mm_struct *mm = vma->vm_mm;
- pte_t * pte;
- spinlock_t *ptl;
+ unsigned long old_start = vma->vm_start;
+ unsigned long old_end = vma->vm_end;
+ unsigned long length = old_end - old_start;
+ unsigned long new_start = old_start - shift;
+ unsigned long new_end = old_end - shift;
+ struct mmu_gather *tlb;
- if (unlikely(anon_vma_prepare(vma)))
- goto out;
+ BUG_ON(new_start > new_end);
- flush_dcache_page(page);
- pte = get_locked_pte(mm, address, &ptl);
- if (!pte)
- goto out;
- if (!pte_none(*pte)) {
- pte_unmap_unlock(pte, ptl);
- goto out;
+ /*
+ * ensure there are no vmas between where we want to go
+ * and where we are
+ */
+ if (vma != find_vma(mm, new_start))
+ return -EFAULT;
+
+ /*
+ * cover the whole range: [new_start, old_end)
+ */
+ vma_adjust(vma, new_start, old_end, vma->vm_pgoff, NULL);
+
+ /*
+ * move the page tables downwards, on failure we rely on
+ * process cleanup to remove whatever mess we made.
+ */
+ if (length != move_page_tables(vma, old_start,
+ vma, new_start, length))
+ return -ENOMEM;
+
+ lru_add_drain();
+ tlb = tlb_gather_mmu(mm, 0);
+ if (new_end > old_start) {
+ /*
+ * when the old and new regions overlap clear from new_end.
+ */
+ free_pgd_range(&tlb, new_end, old_end, new_end,
+ vma->vm_next ? vma->vm_next->vm_start : 0);
+ } else {
+ /*
+ * otherwise, clean from old_start; this is done to not touch
+ * the address space in [new_end, old_start) some architectures
+ * have constraints on va-space that make this illegal (IA64) -
+ * for the others its just a little faster.
+ */
+ free_pgd_range(&tlb, old_start, old_end, new_end,
+ vma->vm_next ? vma->vm_next->vm_start : 0);
}
- inc_mm_counter(mm, anon_rss);
- lru_cache_add_active(page);
- set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte(
- page, vma->vm_page_prot))));
- page_add_new_anon_rmap(page, vma, address);
- pte_unmap_unlock(pte, ptl);
-
- /* no need for flush_tlb */
- return;
-out:
- __free_page(page);
- force_sig(SIGKILL, current);
+ tlb_finish_mmu(tlb, new_end, old_end);
+
+ /*
+ * shrink the vma to just the new range.
+ */
+ vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL);
+
+ return 0;
}
#define EXTRA_STACK_VM_PAGES 20 /* random */
+/*
+ * Finalizes the stack vm_area_struct. The flags and permissions are updated,
+ * the stack is optionally relocated, and some extra space is added.
+ */
int setup_arg_pages(struct linux_binprm *bprm,
unsigned long stack_top,
int executable_stack)
{
- unsigned long stack_base;
- struct vm_area_struct *mpnt;
+ unsigned long ret;
+ unsigned long stack_shift;
struct mm_struct *mm = current->mm;
- int i, ret;
- long arg_size;
+ struct vm_area_struct *vma = bprm->vma;
+ struct vm_area_struct *prev = NULL;
+ unsigned long vm_flags;
+ unsigned long stack_base;
#ifdef CONFIG_STACK_GROWSUP
- /* Move the argument and environment strings to the bottom of the
- * stack space.
- */
- int offset, j;
- char *to, *from;
-
- /* Start by shifting all the pages down */
- i = 0;
- for (j = 0; j < MAX_ARG_PAGES; j++) {
- struct page *page = bprm->page[j];
- if (!page)
- continue;
- bprm->page[i++] = page;
- }
-
- /* Now move them within their pages */
- offset = bprm->p % PAGE_SIZE;
- to = kmap(bprm->page[0]);
- for (j = 1; j < i; j++) {
- memmove(to, to + offset, PAGE_SIZE - offset);
- from = kmap(bprm->page[j]);
- memcpy(to + PAGE_SIZE - offset, from, offset);
- kunmap(bprm->page[j - 1]);
- to = from;
- }
- memmove(to, to + offset, PAGE_SIZE - offset);
- kunmap(bprm->page[j - 1]);
-
/* Limit stack size to 1GB */
stack_base = current->signal->rlim[RLIMIT_STACK].rlim_max;
if (stack_base > (1 << 30))
stack_base = 1 << 30;
- stack_base = PAGE_ALIGN(stack_top - stack_base);
- /* Adjust bprm->p to point to the end of the strings. */
- bprm->p = stack_base + PAGE_SIZE * i - offset;
+ /* Make sure we didn't let the argument array grow too large. */
+ if (vma->vm_end - vma->vm_start > stack_base)
+ return -ENOMEM;
- mm->arg_start = stack_base;
- arg_size = i << PAGE_SHIFT;
+ stack_base = PAGE_ALIGN(stack_top - stack_base);
- /* zero pages that were copied above */
- while (i < MAX_ARG_PAGES)
- bprm->page[i++] = NULL;
+ stack_shift = vma->vm_start - stack_base;
+ mm->arg_start = bprm->p - stack_shift;
+ bprm->p = vma->vm_end - stack_shift;
#else
- stack_base = arch_align_stack(stack_top - MAX_ARG_PAGES*PAGE_SIZE);
- stack_base = PAGE_ALIGN(stack_base);
- bprm->p += stack_base;
+ stack_top = arch_align_stack(stack_top);
+ stack_top = PAGE_ALIGN(stack_top);
+ stack_shift = vma->vm_end - stack_top;
+
+ bprm->p -= stack_shift;
mm->arg_start = bprm->p;
- arg_size = stack_top - (PAGE_MASK & (unsigned long) mm->arg_start);
#endif
- arg_size += EXTRA_STACK_VM_PAGES * PAGE_SIZE;
-
if (bprm->loader)
- bprm->loader += stack_base;
- bprm->exec += stack_base;
-
- mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL);
- if (!mpnt)
- return -ENOMEM;
+ bprm->loader -= stack_shift;
+ bprm->exec -= stack_shift;
down_write(&mm->mmap_sem);
- {
- mpnt->vm_mm = mm;
-#ifdef CONFIG_STACK_GROWSUP
- mpnt->vm_start = stack_base;
- mpnt->vm_end = stack_base + arg_size;
-#else
- mpnt->vm_end = stack_top;
- mpnt->vm_start = mpnt->vm_end - arg_size;
-#endif
- /* Adjust stack execute permissions; explicitly enable
- * for EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X
- * and leave alone (arch default) otherwise. */
- if (unlikely(executable_stack == EXSTACK_ENABLE_X))
- mpnt->vm_flags = VM_STACK_FLAGS | VM_EXEC;
- else if (executable_stack == EXSTACK_DISABLE_X)
- mpnt->vm_flags = VM_STACK_FLAGS & ~VM_EXEC;
- else
- mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_flags |= mm->def_flags;
- mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7];
- if ((ret = insert_vm_struct(mm, mpnt))) {
+ vm_flags = vma->vm_flags;
+
+ /*
+ * Adjust stack execute permissions; explicitly enable for
+ * EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X and leave alone
+ * (arch default) otherwise.
+ */
+ if (unlikely(executable_stack == EXSTACK_ENABLE_X))
+ vm_flags |= VM_EXEC;
+ else if (executable_stack == EXSTACK_DISABLE_X)
+ vm_flags &= ~VM_EXEC;
+ vm_flags |= mm->def_flags;
+
+ ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end,
+ vm_flags);
+ if (ret)
+ goto out_unlock;
+ BUG_ON(prev != vma);
+
+ /* Move stack pages down in memory. */
+ if (stack_shift) {
+ ret = shift_arg_pages(vma, stack_shift);
+ if (ret) {
up_write(&mm->mmap_sem);
- kmem_cache_free(vm_area_cachep, mpnt);
return ret;
}
- mm->stack_vm = mm->total_vm = vma_pages(mpnt);
}
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page *page = bprm->page[i];
- if (page) {
- bprm->page[i] = NULL;
- install_arg_page(mpnt, page, stack_base);
- }
- stack_base += PAGE_SIZE;
- }
+#ifdef CONFIG_STACK_GROWSUP
+ stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+#else
+ stack_base = vma->vm_start - EXTRA_STACK_VM_PAGES * PAGE_SIZE;
+#endif
+ ret = expand_stack(vma, stack_base);
+ if (ret)
+ ret = -EFAULT;
+
+out_unlock:
up_write(&mm->mmap_sem);
-
return 0;
}
-
EXPORT_SYMBOL(setup_arg_pages);
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
- int i;
-
- for (i = 0; i < MAX_ARG_PAGES; i++) {
- if (bprm->page[i])
- __free_page(bprm->page[i]);
- bprm->page[i] = NULL;
- }
-}
-
#endif /* CONFIG_MMU */
struct file *open_exec(const char *name)
@@ -864,9 +1058,9 @@ int flush_old_exec(struct linux_binprm * bprm)
current->sas_ss_sp = current->sas_ss_size = 0;
if (current->euid == current->uid && current->egid == current->gid)
- current->mm->dumpable = 1;
+ set_dumpable(current->mm, 1);
else
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
name = bprm->filename;
@@ -894,7 +1088,7 @@ int flush_old_exec(struct linux_binprm * bprm)
file_permission(bprm->file, MAY_READ) ||
(bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
suid_keys(current);
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
}
/* An exec changes our domain. We are no longer part of the thread
@@ -1000,43 +1194,42 @@ EXPORT_SYMBOL(compute_creds);
* points to; chop off the first by relocating brpm->p to right after
* the first '\0' encountered.
*/
-void remove_arg_zero(struct linux_binprm *bprm)
+int remove_arg_zero(struct linux_binprm *bprm)
{
- if (bprm->argc) {
- char ch;
+ int ret = 0;
+ unsigned long offset;
+ char *kaddr;
+ struct page *page;
- do {
- unsigned long offset;
- unsigned long index;
- char *kaddr;
- struct page *page;
-
- offset = bprm->p & ~PAGE_MASK;
- index = bprm->p >> PAGE_SHIFT;
+ if (!bprm->argc)
+ return 0;
- page = bprm->page[index];
- kaddr = kmap_atomic(page, KM_USER0);
+ do {
+ offset = bprm->p & ~PAGE_MASK;
+ page = get_arg_page(bprm, bprm->p, 0);
+ if (!page) {
+ ret = -EFAULT;
+ goto out;
+ }
+ kaddr = kmap_atomic(page, KM_USER0);
- /* run through page until we reach end or find NUL */
- do {
- ch = *(kaddr + offset);
+ for (; offset < PAGE_SIZE && kaddr[offset];
+ offset++, bprm->p++)
+ ;
- /* discard that character... */
- bprm->p++;
- offset++;
- } while (offset < PAGE_SIZE && ch != '\0');
+ kunmap_atomic(kaddr, KM_USER0);
+ put_arg_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ if (offset == PAGE_SIZE)
+ free_arg_page(bprm, (bprm->p >> PAGE_SHIFT) - 1);
+ } while (offset == PAGE_SIZE);
- /* free the old page */
- if (offset == PAGE_SIZE) {
- __free_page(page);
- bprm->page[index] = NULL;
- }
- } while (ch != '\0');
+ bprm->p++;
+ bprm->argc--;
+ ret = 0;
- bprm->argc--;
- }
+out:
+ return ret;
}
EXPORT_SYMBOL(remove_arg_zero);
@@ -1062,7 +1255,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
fput(bprm->file);
bprm->file = NULL;
- loader = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+ loader = bprm->vma->vm_end - sizeof(void *);
file = open_exec("/sbin/loader");
retval = PTR_ERR(file);
@@ -1154,8 +1347,8 @@ int do_execve(char * filename,
{
struct linux_binprm *bprm;
struct file *file;
+ unsigned long env_p;
int retval;
- int i;
retval = -ENOMEM;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
@@ -1169,25 +1362,19 @@ int do_execve(char * filename,
sched_exec();
- bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-
bprm->file = file;
bprm->filename = filename;
bprm->interp = filename;
- bprm->mm = mm_alloc();
- retval = -ENOMEM;
- if (!bprm->mm)
- goto out_file;
- retval = init_new_context(current, bprm->mm);
- if (retval < 0)
- goto out_mm;
+ retval = bprm_mm_init(bprm);
+ if (retval)
+ goto out_file;
- bprm->argc = count(argv, bprm->p / sizeof(void *));
+ bprm->argc = count(argv, MAX_ARG_STRINGS);
if ((retval = bprm->argc) < 0)
goto out_mm;
- bprm->envc = count(envp, bprm->p / sizeof(void *));
+ bprm->envc = count(envp, MAX_ARG_STRINGS);
if ((retval = bprm->envc) < 0)
goto out_mm;
@@ -1208,15 +1395,16 @@ int do_execve(char * filename,
if (retval < 0)
goto out;
+ env_p = bprm->p;
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out;
+ bprm->argv_len = env_p - bprm->p;
retval = search_binary_handler(bprm,regs);
if (retval >= 0) {
- free_arg_pages(bprm);
-
/* execve success */
+ free_arg_pages(bprm);
security_bprm_free(bprm);
acct_update_integrals(current);
kfree(bprm);
@@ -1224,26 +1412,19 @@ int do_execve(char * filename,
}
out:
- /* Something went wrong, return the inode and free the argument pages*/
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- struct page * page = bprm->page[i];
- if (page)
- __free_page(page);
- }
-
+ free_arg_pages(bprm);
if (bprm->security)
security_bprm_free(bprm);
out_mm:
if (bprm->mm)
- mmdrop(bprm->mm);
+ mmput (bprm->mm);
out_file:
if (bprm->file) {
allow_write_access(bprm->file);
fput(bprm->file);
}
-
out_kfree:
kfree(bprm);
@@ -1484,6 +1665,56 @@ fail:
return core_waiters;
}
+/*
+ * set_dumpable converts traditional three-value dumpable to two flags and
+ * stores them into mm->flags. It modifies lower two bits of mm->flags, but
+ * these bits are not changed atomically. So get_dumpable can observe the
+ * intermediate state. To avoid doing unexpected behavior, get get_dumpable
+ * return either old dumpable or new one by paying attention to the order of
+ * modifying the bits.
+ *
+ * dumpable | mm->flags (binary)
+ * old new | initial interim final
+ * ---------+-----------------------
+ * 0 1 | 00 01 01
+ * 0 2 | 00 10(*) 11
+ * 1 0 | 01 00 00
+ * 1 2 | 01 11 11
+ * 2 0 | 11 10(*) 00
+ * 2 1 | 11 11 01
+ *
+ * (*) get_dumpable regards interim value of 10 as 11.
+ */
+void set_dumpable(struct mm_struct *mm, int value)
+{
+ switch (value) {
+ case 0:
+ clear_bit(MMF_DUMPABLE, &mm->flags);
+ smp_wmb();
+ clear_bit(MMF_DUMP_SECURELY, &mm->flags);
+ break;
+ case 1:
+ set_bit(MMF_DUMPABLE, &mm->flags);
+ smp_wmb();
+ clear_bit(MMF_DUMP_SECURELY, &mm->flags);
+ break;
+ case 2:
+ set_bit(MMF_DUMP_SECURELY, &mm->flags);
+ smp_wmb();
+ set_bit(MMF_DUMPABLE, &mm->flags);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(set_dumpable);
+
+int get_dumpable(struct mm_struct *mm)
+{
+ int ret;
+
+ ret = mm->flags & 0x3;
+ return (ret >= 2) ? 2 : ret;
+}
+
int do_coredump(long signr, int exit_code, struct pt_regs * regs)
{
char corename[CORENAME_MAX_SIZE + 1];
@@ -1502,7 +1733,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
if (!binfmt || !binfmt->core_dump)
goto fail;
down_write(&mm->mmap_sem);
- if (!mm->dumpable) {
+ if (!get_dumpable(mm)) {
up_write(&mm->mmap_sem);
goto fail;
}
@@ -1512,11 +1743,11 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
* process nor do we know its entire history. We only know it
* was tainted so we dump it as root in mode 2.
*/
- if (mm->dumpable == 2) { /* Setuid core dump mode */
+ if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
flag = O_EXCL; /* Stop rewrite attacks */
current->fsuid = 0; /* Dump root private */
}
- mm->dumpable = 0;
+ set_dumpable(mm, 0);
retval = coredump_wait(exit_code);
if (retval < 0)
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index e98f6cd7200c..8adb32a9387a 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -1,15 +1,45 @@
+#include <linux/exportfs.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/module.h>
+#include <linux/mount.h>
#include <linux/namei.h>
-struct export_operations export_op_default;
+#define dprintk(fmt, args...) do{}while(0)
-#define CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun)
-#define dprintk(fmt, args...) do{}while(0)
+static int get_name(struct dentry *dentry, char *name,
+ struct dentry *child);
+
+
+static struct dentry *exportfs_get_dentry(struct super_block *sb, void *obj)
+{
+ struct dentry *result = ERR_PTR(-ESTALE);
+
+ if (sb->s_export_op->get_dentry) {
+ result = sb->s_export_op->get_dentry(sb, obj);
+ if (!result)
+ result = ERR_PTR(-ESTALE);
+ }
+
+ return result;
+}
+
+static int exportfs_get_name(struct dentry *dir, char *name,
+ struct dentry *child)
+{
+ struct export_operations *nop = dir->d_sb->s_export_op;
+ if (nop->get_name)
+ return nop->get_name(dir, name, child);
+ else
+ return get_name(dir, name, child);
+}
+
+/*
+ * Check if the dentry or any of it's aliases is acceptable.
+ */
static struct dentry *
find_acceptable_alias(struct dentry *result,
int (*acceptable)(void *context, struct dentry *dentry),
@@ -17,6 +47,9 @@ find_acceptable_alias(struct dentry *result,
{
struct dentry *dentry, *toput = NULL;
+ if (acceptable(context, result))
+ return result;
+
spin_lock(&dcache_lock);
list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) {
dget_locked(dentry);
@@ -37,130 +70,50 @@ find_acceptable_alias(struct dentry *result,
return NULL;
}
-/**
- * find_exported_dentry - helper routine to implement export_operations->decode_fh
- * @sb: The &super_block identifying the filesystem
- * @obj: An opaque identifier of the object to be found - passed to
- * get_inode
- * @parent: An optional opqaue identifier of the parent of the object.
- * @acceptable: A function used to test possible &dentries to see if they are
- * acceptable
- * @context: A parameter to @acceptable so that it knows on what basis to
- * judge.
- *
- * find_exported_dentry is the central helper routine to enable file systems
- * to provide the decode_fh() export_operation. It's main task is to take
- * an &inode, find or create an appropriate &dentry structure, and possibly
- * splice this into the dcache in the correct place.
- *
- * The decode_fh() operation provided by the filesystem should call
- * find_exported_dentry() with the same parameters that it received except
- * that instead of the file handle fragment, pointers to opaque identifiers
- * for the object and optionally its parent are passed. The default decode_fh
- * routine passes one pointer to the start of the filehandle fragment, and
- * one 8 bytes into the fragment. It is expected that most filesystems will
- * take this approach, though the offset to the parent identifier may well be
- * different.
- *
- * find_exported_dentry() will call get_dentry to get an dentry pointer from
- * the file system. If any &dentry in the d_alias list is acceptable, it will
- * be returned. Otherwise find_exported_dentry() will attempt to splice a new
- * &dentry into the dcache using get_name() and get_parent() to find the
- * appropriate place.
+/*
+ * Find root of a disconnected subtree and return a reference to it.
*/
-
-struct dentry *
-find_exported_dentry(struct super_block *sb, void *obj, void *parent,
- int (*acceptable)(void *context, struct dentry *de),
- void *context)
+static struct dentry *
+find_disconnected_root(struct dentry *dentry)
{
- struct dentry *result = NULL;
- struct dentry *target_dir;
- int err;
- struct export_operations *nops = sb->s_export_op;
- struct dentry *alias;
- int noprogress;
- char nbuf[NAME_MAX+1];
-
- /*
- * Attempt to find the inode.
- */
- result = CALL(sb->s_export_op,get_dentry)(sb,obj);
- err = -ESTALE;
- if (result == NULL)
- goto err_out;
- if (IS_ERR(result)) {
- err = PTR_ERR(result);
- goto err_out;
+ dget(dentry);
+ spin_lock(&dentry->d_lock);
+ while (!IS_ROOT(dentry) &&
+ (dentry->d_parent->d_flags & DCACHE_DISCONNECTED)) {
+ struct dentry *parent = dentry->d_parent;
+ dget(parent);
+ spin_unlock(&dentry->d_lock);
+ dput(dentry);
+ dentry = parent;
+ spin_lock(&dentry->d_lock);
}
- if (S_ISDIR(result->d_inode->i_mode) &&
- (result->d_flags & DCACHE_DISCONNECTED)) {
- /* it is an unconnected directory, we must connect it */
- ;
- } else {
- if (acceptable(context, result))
- return result;
- if (S_ISDIR(result->d_inode->i_mode)) {
- err = -EACCES;
- goto err_result;
- }
+ spin_unlock(&dentry->d_lock);
+ return dentry;
+}
- alias = find_acceptable_alias(result, acceptable, context);
- if (alias)
- return alias;
- }
-
- /* It's a directory, or we are required to confirm the file's
- * location in the tree based on the parent information
- */
- dprintk("find_exported_dentry: need to look harder for %s/%d\n",sb->s_id,*(int*)obj);
- if (S_ISDIR(result->d_inode->i_mode))
- target_dir = dget(result);
- else {
- if (parent == NULL)
- goto err_result;
- target_dir = CALL(sb->s_export_op,get_dentry)(sb,parent);
- if (IS_ERR(target_dir))
- err = PTR_ERR(target_dir);
- if (target_dir == NULL || IS_ERR(target_dir))
- goto err_result;
- }
- /*
- * Now we need to make sure that target_dir is properly connected.
- * It may already be, as the flag isn't always updated when connection
- * happens.
- * So, we walk up parent links until we find a connected directory,
- * or we run out of directories. Then we find the parent, find
- * the name of the child in that parent, and do a lookup.
- * This should connect the child into the parent
- * We then repeat.
- */
+/*
+ * Make sure target_dir is fully connected to the dentry tree.
+ *
+ * It may already be, as the flag isn't always updated when connection happens.
+ */
+static int
+reconnect_path(struct super_block *sb, struct dentry *target_dir)
+{
+ char nbuf[NAME_MAX+1];
+ int noprogress = 0;
+ int err = -ESTALE;
- /* it is possible that a confused file system might not let us complete
+ /*
+ * It is possible that a confused file system might not let us complete
* the path to the root. For example, if get_parent returns a directory
* in which we cannot find a name for the child. While this implies a
* very sick filesystem we don't want it to cause knfsd to spin. Hence
* the noprogress counter. If we go through the loop 10 times (2 is
* probably enough) without getting anywhere, we just give up
*/
- noprogress= 0;
while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) {
- struct dentry *pd = target_dir;
-
- dget(pd);
- spin_lock(&pd->d_lock);
- while (!IS_ROOT(pd) &&
- (pd->d_parent->d_flags&DCACHE_DISCONNECTED)) {
- struct dentry *parent = pd->d_parent;
-
- dget(parent);
- spin_unlock(&pd->d_lock);
- dput(pd);
- pd = parent;
- spin_lock(&pd->d_lock);
- }
- spin_unlock(&pd->d_lock);
+ struct dentry *pd = find_disconnected_root(target_dir);
if (!IS_ROOT(pd)) {
/* must have found a connected parent - great */
@@ -175,29 +128,40 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
spin_unlock(&pd->d_lock);
noprogress = 0;
} else {
- /* we have hit the top of a disconnected path. Try
- * to find parent and connect
- * note: racing with some other process renaming a
- * directory isn't much of a problem here. If someone
- * renames the directory, it will end up properly
- * connected, which is what we want
+ /*
+ * We have hit the top of a disconnected path, try to
+ * find parent and connect.
+ *
+ * Racing with some other process renaming a directory
+ * isn't much of a problem here. If someone renames
+ * the directory, it will end up properly connected,
+ * which is what we want
+ *
+ * Getting the parent can't be supported generically,
+ * the locking is too icky.
+ *
+ * Instead we just return EACCES. If server reboots
+ * or inodes get flushed, you lose
*/
- struct dentry *ppd;
+ struct dentry *ppd = ERR_PTR(-EACCES);
struct dentry *npd;
mutex_lock(&pd->d_inode->i_mutex);
- ppd = CALL(nops,get_parent)(pd);
+ if (sb->s_export_op->get_parent)
+ ppd = sb->s_export_op->get_parent(pd);
mutex_unlock(&pd->d_inode->i_mutex);
if (IS_ERR(ppd)) {
err = PTR_ERR(ppd);
- dprintk("find_exported_dentry: get_parent of %ld failed, err %d\n",
- pd->d_inode->i_ino, err);
+ dprintk("%s: get_parent of %ld failed, err %d\n",
+ __FUNCTION__, pd->d_inode->i_ino, err);
dput(pd);
break;
}
- dprintk("find_exported_dentry: find name of %lu in %lu\n", pd->d_inode->i_ino, ppd->d_inode->i_ino);
- err = CALL(nops,get_name)(ppd, nbuf, pd);
+
+ dprintk("%s: find name of %lu in %lu\n", __FUNCTION__,
+ pd->d_inode->i_ino, ppd->d_inode->i_ino);
+ err = exportfs_get_name(ppd, nbuf, pd);
if (err) {
dput(ppd);
dput(pd);
@@ -208,13 +172,14 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
continue;
break;
}
- dprintk("find_exported_dentry: found name: %s\n", nbuf);
+ dprintk("%s: found name: %s\n", __FUNCTION__, nbuf);
mutex_lock(&ppd->d_inode->i_mutex);
npd = lookup_one_len(nbuf, ppd, strlen(nbuf));
mutex_unlock(&ppd->d_inode->i_mutex);
if (IS_ERR(npd)) {
err = PTR_ERR(npd);
- dprintk("find_exported_dentry: lookup failed: %d\n", err);
+ dprintk("%s: lookup failed: %d\n",
+ __FUNCTION__, err);
dput(ppd);
dput(pd);
break;
@@ -227,7 +192,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
if (npd == pd)
noprogress = 0;
else
- printk("find_exported_dentry: npd != pd\n");
+ printk("%s: npd != pd\n", __FUNCTION__);
dput(npd);
dput(ppd);
if (IS_ROOT(pd)) {
@@ -243,15 +208,101 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
/* something went wrong - oh-well */
if (!err)
err = -ESTALE;
- goto err_target;
+ return err;
}
- /* if we weren't after a directory, have one more step to go */
- if (result != target_dir) {
- struct dentry *nresult;
- err = CALL(nops,get_name)(target_dir, nbuf, result);
+
+ return 0;
+}
+
+/**
+ * find_exported_dentry - helper routine to implement export_operations->decode_fh
+ * @sb: The &super_block identifying the filesystem
+ * @obj: An opaque identifier of the object to be found - passed to
+ * get_inode
+ * @parent: An optional opqaue identifier of the parent of the object.
+ * @acceptable: A function used to test possible &dentries to see if they are
+ * acceptable
+ * @context: A parameter to @acceptable so that it knows on what basis to
+ * judge.
+ *
+ * find_exported_dentry is the central helper routine to enable file systems
+ * to provide the decode_fh() export_operation. It's main task is to take
+ * an &inode, find or create an appropriate &dentry structure, and possibly
+ * splice this into the dcache in the correct place.
+ *
+ * The decode_fh() operation provided by the filesystem should call
+ * find_exported_dentry() with the same parameters that it received except
+ * that instead of the file handle fragment, pointers to opaque identifiers
+ * for the object and optionally its parent are passed. The default decode_fh
+ * routine passes one pointer to the start of the filehandle fragment, and
+ * one 8 bytes into the fragment. It is expected that most filesystems will
+ * take this approach, though the offset to the parent identifier may well be
+ * different.
+ *
+ * find_exported_dentry() will call get_dentry to get an dentry pointer from
+ * the file system. If any &dentry in the d_alias list is acceptable, it will
+ * be returned. Otherwise find_exported_dentry() will attempt to splice a new
+ * &dentry into the dcache using get_name() and get_parent() to find the
+ * appropriate place.
+ */
+
+struct dentry *
+find_exported_dentry(struct super_block *sb, void *obj, void *parent,
+ int (*acceptable)(void *context, struct dentry *de),
+ void *context)
+{
+ struct dentry *result, *alias;
+ int err = -ESTALE;
+
+ /*
+ * Attempt to find the inode.
+ */
+ result = exportfs_get_dentry(sb, obj);
+ if (IS_ERR(result))
+ return result;
+
+ if (S_ISDIR(result->d_inode->i_mode)) {
+ if (!(result->d_flags & DCACHE_DISCONNECTED)) {
+ if (acceptable(context, result))
+ return result;
+ err = -EACCES;
+ goto err_result;
+ }
+
+ err = reconnect_path(sb, result);
+ if (err)
+ goto err_result;
+ } else {
+ struct dentry *target_dir, *nresult;
+ char nbuf[NAME_MAX+1];
+
+ alias = find_acceptable_alias(result, acceptable, context);
+ if (alias)
+ return alias;
+
+ if (parent == NULL)
+ goto err_result;
+
+ target_dir = exportfs_get_dentry(sb,parent);
+ if (IS_ERR(target_dir)) {
+ err = PTR_ERR(target_dir);
+ goto err_result;
+ }
+
+ err = reconnect_path(sb, target_dir);
+ if (err) {
+ dput(target_dir);
+ goto err_result;
+ }
+
+ /*
+ * As we weren't after a directory, have one more step to go.
+ */
+ err = exportfs_get_name(target_dir, nbuf, result);
if (!err) {
mutex_lock(&target_dir->d_inode->i_mutex);
- nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf));
+ nresult = lookup_one_len(nbuf, target_dir,
+ strlen(nbuf));
mutex_unlock(&target_dir->d_inode->i_mutex);
if (!IS_ERR(nresult)) {
if (nresult->d_inode) {
@@ -261,11 +312,8 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
dput(nresult);
}
}
+ dput(target_dir);
}
- dput(target_dir);
- /* now result is properly connected, it is our best bet */
- if (acceptable(context, result))
- return result;
alias = find_acceptable_alias(result, acceptable, context);
if (alias)
@@ -275,32 +323,16 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent,
dput(result);
/* It might be justifiable to return ESTALE here,
* but the filehandle at-least looks reasonable good
- * and it just be a permission problem, so returning
+ * and it may just be a permission problem, so returning
* -EACCESS is safer
*/
return ERR_PTR(-EACCES);
- err_target:
- dput(target_dir);
err_result:
dput(result);
- err_out:
return ERR_PTR(err);
}
-
-
-static struct dentry *get_parent(struct dentry *child)
-{
- /* get_parent cannot be supported generically, the locking
- * is too icky.
- * instead, we just return EACCES. If server reboots or inodes
- * get flushed, you lose
- */
- return ERR_PTR(-EACCES);
-}
-
-
struct getdents_callback {
char *name; /* name that was found. It already points to a
buffer NAME_MAX+1 is size */
@@ -390,61 +422,6 @@ out:
return error;
}
-
-static struct dentry *export_iget(struct super_block *sb, unsigned long ino, __u32 generation)
-{
-
- /* iget isn't really right if the inode is currently unallocated!!
- * This should really all be done inside each filesystem
- *
- * ext2fs' read_inode has been strengthed to return a bad_inode if
- * the inode had been deleted.
- *
- * Currently we don't know the generation for parent directory, so
- * a generation of 0 means "accept any"
- */
- struct inode *inode;
- struct dentry *result;
- if (ino == 0)
- return ERR_PTR(-ESTALE);
- inode = iget(sb, ino);
- if (inode == NULL)
- return ERR_PTR(-ENOMEM);
- if (is_bad_inode(inode)
- || (generation && inode->i_generation != generation)
- ) {
- /* we didn't find the right inode.. */
- dprintk("fh_verify: Inode %lu, Bad count: %d %d or version %u %u\n",
- inode->i_ino,
- inode->i_nlink, atomic_read(&inode->i_count),
- inode->i_generation,
- generation);
-
- iput(inode);
- return ERR_PTR(-ESTALE);
- }
- /* now to find a dentry.
- * If possible, get a well-connected one
- */
- result = d_alloc_anon(inode);
- if (!result) {
- iput(inode);
- return ERR_PTR(-ENOMEM);
- }
- return result;
-}
-
-
-static struct dentry *get_object(struct super_block *sb, void *vobjp)
-{
- __u32 *objp = vobjp;
- unsigned long ino = objp[0];
- __u32 generation = objp[1];
-
- return export_iget(sb, ino, generation);
-}
-
-
/**
* export_encode_fh - default export_operations->encode_fh function
* @dentry: the dentry to encode
@@ -517,16 +494,40 @@ static struct dentry *export_decode_fh(struct super_block *sb, __u32 *fh, int fh
acceptable, context);
}
-struct export_operations export_op_default = {
- .decode_fh = export_decode_fh,
- .encode_fh = export_encode_fh,
+int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
+ int connectable)
+{
+ struct export_operations *nop = dentry->d_sb->s_export_op;
+ int error;
+
+ if (nop->encode_fh)
+ error = nop->encode_fh(dentry, fh, max_len, connectable);
+ else
+ error = export_encode_fh(dentry, fh, max_len, connectable);
- .get_name = get_name,
- .get_parent = get_parent,
- .get_dentry = get_object,
-};
+ return error;
+}
+EXPORT_SYMBOL_GPL(exportfs_encode_fh);
+
+struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len,
+ int fileid_type, int (*acceptable)(void *, struct dentry *),
+ void *context)
+{
+ struct export_operations *nop = mnt->mnt_sb->s_export_op;
+ struct dentry *result;
+
+ if (nop->decode_fh) {
+ result = nop->decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type,
+ acceptable, context);
+ } else {
+ result = export_decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type,
+ acceptable, context);
+ }
+
+ return result;
+}
+EXPORT_SYMBOL_GPL(exportfs_decode_fh);
-EXPORT_SYMBOL(export_op_default);
EXPORT_SYMBOL(find_exported_dentry);
MODULE_LICENSE("GPL");
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 7c420b800c34..e58669e1b87c 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -464,7 +464,7 @@ ext2_xattr_set_acl(struct inode *inode, int type, const void *value,
if (!test_opt(inode->i_sb, POSIX_ACL))
return -EOPNOTSUPP;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (value) {
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 04afeecaaef3..ab7961260c49 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -24,9 +24,9 @@
#include "acl.h"
/*
- * Called when an inode is released. Note that this is different
- * from ext2_open_file: open gets called at every open, but release
- * gets called only when /all/ the files are closed.
+ * Called when filp is released. This happens when all file descriptors
+ * for a single struct file are closed. Note that different open() calls
+ * for the same file yield different struct file structures.
*/
static int ext2_release_file (struct inode * inode, struct file * filp)
{
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index e85c48218239..3bcd25422ee4 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -36,7 +36,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EACCES;
if (get_user(flags, (int __user *) arg))
@@ -74,7 +74,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
case EXT2_IOC_GETVERSION:
return put_user(inode->i_generation, (int __user *) arg);
case EXT2_IOC_SETVERSION:
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 5de5061eb331..68579a0ed3f0 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -25,6 +25,7 @@
#include <linux/parser.h>
#include <linux/random.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <linux/smp_lock.h>
#include <linux/vfs.h>
#include <linux/seq_file.h>
@@ -166,14 +167,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
#endif
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
sizeof(struct ext2_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (ext2_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -882,13 +883,11 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
goto failed_mount;
}
bgl_lock_init(&sbi->s_blockgroup_lock);
- sbi->s_debts = kmalloc(sbi->s_groups_count * sizeof(*sbi->s_debts),
- GFP_KERNEL);
+ sbi->s_debts = kcalloc(sbi->s_groups_count, sizeof(*sbi->s_debts), GFP_KERNEL);
if (!sbi->s_debts) {
printk ("EXT2-fs: not enough memory\n");
goto failed_mount_group_desc;
}
- memset(sbi->s_debts, 0, sbi->s_groups_count * sizeof(*sbi->s_debts));
for (i = 0; i < db_count; i++) {
block = descriptor_loc(sb, logic_sb_block, i);
sbi->s_group_desc[i] = sb_bread(sb, block);
@@ -1099,15 +1098,18 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
struct super_block *sb = dentry->d_sb;
struct ext2_sb_info *sbi = EXT2_SB(sb);
struct ext2_super_block *es = sbi->s_es;
- unsigned long overhead;
- int i;
u64 fsid;
if (test_opt (sb, MINIX_DF))
- overhead = 0;
- else {
+ sbi->s_overhead_last = 0;
+ else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
+ unsigned long i, overhead = 0;
+ smp_rmb();
+
/*
- * Compute the overhead (FS structures)
+ * Compute the overhead (FS structures). This is constant
+ * for a given filesystem unless the number of block groups
+ * changes so we cache the previous value until it does.
*/
/*
@@ -1131,17 +1133,22 @@ static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf)
*/
overhead += (sbi->s_groups_count *
(2 + sbi->s_itb_per_group));
+ sbi->s_overhead_last = overhead;
+ smp_wmb();
+ sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
}
buf->f_type = EXT2_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
+ buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last;
buf->f_bfree = ext2_count_free_blocks(sb);
+ es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = ext2_count_free_inodes(sb);
+ es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
buf->f_namelen = EXT2_NAME_LEN;
fsid = le64_to_cpup((void *)es->s_uuid) ^
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 1e5038d9a01b..d34e9967430a 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -489,7 +489,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
if (!test_opt(inode->i_sb, POSIX_ACL))
return -EOPNOTSUPP;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (value) {
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index 852869840f24..c00723a99f44 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -136,12 +136,14 @@ static int ext3_readdir(struct file * filp,
err = ext3_get_blocks_handle(NULL, inode, blk, 1,
&map_bh, 0, 0);
if (err > 0) {
- page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
- &filp->f_ra,
- filp,
- map_bh.b_blocknr >>
- (PAGE_CACHE_SHIFT - inode->i_blkbits),
- 1);
+ pgoff_t index = map_bh.b_blocknr >>
+ (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ if (!ra_has_index(&filp->f_ra, index))
+ page_cache_sync_readahead(
+ sb->s_bdev->bd_inode->i_mapping,
+ &filp->f_ra, filp,
+ index, 1);
+ filp->f_ra.prev_index = index;
bh = ext3_bread(NULL, inode, blk, 0, &err);
}
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 2a85ddee4740..de4e3161e479 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -3195,7 +3195,7 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val)
*/
journal = EXT3_JOURNAL(inode);
- if (is_journal_aborted(journal) || IS_RDONLY(inode))
+ if (is_journal_aborted(journal))
return -EROFS;
journal_lock_updates(journal);
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 965006dba6be..4a2a02c95bf9 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -41,7 +41,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EACCES;
if (get_user(flags, (int __user *) arg))
@@ -122,7 +122,7 @@ flags_err:
__u32 generation;
int err;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
@@ -181,7 +181,7 @@ flags_err:
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EACCES;
if (get_user(rsv_window_size, (int __user *)arg))
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 9bb046df827a..1586807b8177 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1019,6 +1019,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
if (!inode)
return ERR_PTR(-EACCES);
+
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
}
return d_splice_alias(inode, dentry);
}
@@ -1054,6 +1059,11 @@ struct dentry *ext3_get_parent(struct dentry *child)
if (!inode)
return ERR_PTR(-EACCES);
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
+
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 6e3062913a92..f0614e3f1fe8 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -29,12 +29,14 @@
#include <linux/parser.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <linux/vfs.h>
#include <linux/random.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/quotaops.h>
#include <linux/seq_file.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
@@ -459,6 +461,14 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
static void ext3_destroy_inode(struct inode *inode)
{
+ if (!list_empty(&(EXT3_I(inode)->i_orphan))) {
+ printk("EXT3 Inode %p: orphan list check failed!\n",
+ EXT3_I(inode));
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
+ EXT3_I(inode), sizeof(struct ext3_inode_info),
+ false);
+ dump_stack();
+ }
kmem_cache_free(ext3_inode_cachep, EXT3_I(inode));
}
@@ -480,7 +490,7 @@ static int init_inodecache(void)
sizeof(struct ext3_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (ext3_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -1566,7 +1576,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
- (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
+ (!is_power_of_2(sbi->s_inode_size)) ||
(sbi->s_inode_size > blocksize)) {
printk (KERN_ERR
"EXT3-fs: unsupported inode size: %d\n",
@@ -2075,6 +2085,7 @@ static int ext3_create_journal(struct super_block * sb,
unsigned int journal_inum)
{
journal_t *journal;
+ int err;
if (sb->s_flags & MS_RDONLY) {
printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to "
@@ -2082,13 +2093,15 @@ static int ext3_create_journal(struct super_block * sb,
return -EROFS;
}
- if (!(journal = ext3_get_journal(sb, journal_inum)))
+ journal = ext3_get_journal(sb, journal_inum);
+ if (!journal)
return -EINVAL;
printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n",
journal_inum);
- if (journal_create(journal)) {
+ err = journal_create(journal);
+ if (err) {
printk(KERN_ERR "EXT3-fs: error creating journal.\n");
journal_destroy(journal);
return -EIO;
@@ -2139,12 +2152,14 @@ static void ext3_mark_recovery_complete(struct super_block * sb,
journal_lock_updates(journal);
journal_flush(journal);
+ lock_super(sb);
if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) &&
sb->s_flags & MS_RDONLY) {
EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
sb->s_dirt = 0;
ext3_commit_super(sb, es, 1);
}
+ unlock_super(sb);
journal_unlock_updates(journal);
}
@@ -2333,7 +2348,13 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
(sbi->s_mount_state & EXT3_VALID_FS))
es->s_state = cpu_to_le16(sbi->s_mount_state);
+ /*
+ * We have to unlock super so that we can wait for
+ * transactions.
+ */
+ unlock_super(sb);
ext3_mark_recovery_complete(sb, es);
+ lock_super(sb);
} else {
__le32 ret;
if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb,
@@ -2406,19 +2427,19 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
struct super_block *sb = dentry->d_sb;
struct ext3_sb_info *sbi = EXT3_SB(sb);
struct ext3_super_block *es = sbi->s_es;
- ext3_fsblk_t overhead;
- int i;
u64 fsid;
- if (test_opt (sb, MINIX_DF))
- overhead = 0;
- else {
- unsigned long ngroups;
- ngroups = EXT3_SB(sb)->s_groups_count;
+ if (test_opt(sb, MINIX_DF)) {
+ sbi->s_overhead_last = 0;
+ } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
+ unsigned long ngroups = sbi->s_groups_count, i;
+ ext3_fsblk_t overhead = 0;
smp_rmb();
/*
- * Compute the overhead (FS structures)
+ * Compute the overhead (FS structures). This is constant
+ * for a given filesystem unless the number of block groups
+ * changes so we cache the previous value until it does.
*/
/*
@@ -2442,18 +2463,23 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
* Every block group has an inode bitmap, a block
* bitmap, and an inode table.
*/
- overhead += (ngroups * (2 + EXT3_SB(sb)->s_itb_per_group));
+ overhead += ngroups * (2 + sbi->s_itb_per_group);
+ sbi->s_overhead_last = overhead;
+ smp_wmb();
+ sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
}
buf->f_type = EXT3_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
+ buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last;
buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
+ es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
+ es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
buf->f_namelen = EXT3_NAME_LEN;
fsid = le64_to_cpup((void *)es->s_uuid) ^
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index 9e882546d91a..a8bae8cd1d5d 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -489,7 +489,7 @@ ext4_xattr_set_acl(struct inode *inode, int type, const void *value,
if (!test_opt(inode->i_sb, POSIX_ACL))
return -EOPNOTSUPP;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (value) {
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 3b64bb16c727..e53b4af52f11 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -517,7 +517,7 @@ do_more:
/*
* An HJ special. This is expensive...
*/
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
jbd_unlock_bh_state(bitmap_bh);
{
struct buffer_head *debug_bh;
@@ -1585,7 +1585,7 @@ allocated:
ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no);
if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
- in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
+ in_range(ext4_inode_bitmap(sb, gdp), ret_block, num) ||
in_range(ret_block, ext4_inode_table(sb, gdp),
EXT4_SB(sb)->s_itb_per_group) ||
in_range(ret_block + num - 1, ext4_inode_table(sb, gdp),
@@ -1597,7 +1597,7 @@ allocated:
performed_allocation = 1;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
{
struct buffer_head *debug_bh;
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index e8ad06e28318..3ab01c04e00c 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -135,12 +135,14 @@ static int ext4_readdir(struct file * filp,
map_bh.b_state = 0;
err = ext4_get_blocks_wrap(NULL, inode, blk, 1, &map_bh, 0, 0);
if (err > 0) {
- page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
- &filp->f_ra,
- filp,
- map_bh.b_blocknr >>
- (PAGE_CACHE_SHIFT - inode->i_blkbits),
- 1);
+ pgoff_t index = map_bh.b_blocknr >>
+ (PAGE_CACHE_SHIFT - inode->i_blkbits);
+ if (!ra_has_index(&filp->f_ra, index))
+ page_cache_sync_readahead(
+ sb->s_bdev->bd_inode->i_mapping,
+ &filp->f_ra, filp,
+ index, 1);
+ filp->f_ra.prev_index = index;
bh = ext4_bread(NULL, inode, blk, 0, &err);
}
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index b9ce24129070..750c46f7d893 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -39,6 +39,7 @@
#include <linux/quotaops.h>
#include <linux/string.h>
#include <linux/slab.h>
+#include <linux/falloc.h>
#include <linux/ext4_fs_extents.h>
#include <asm/uaccess.h>
@@ -91,36 +92,6 @@ static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
}
-static int ext4_ext_check_header(const char *function, struct inode *inode,
- struct ext4_extent_header *eh)
-{
- const char *error_msg = NULL;
-
- if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
- error_msg = "invalid magic";
- goto corrupted;
- }
- if (unlikely(eh->eh_max == 0)) {
- error_msg = "invalid eh_max";
- goto corrupted;
- }
- if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
- error_msg = "invalid eh_entries";
- goto corrupted;
- }
- return 0;
-
-corrupted:
- ext4_error(inode->i_sb, function,
- "bad header in inode #%lu: %s - magic %x, "
- "entries %u, max %u, depth %u",
- inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
- le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
- le16_to_cpu(eh->eh_depth));
-
- return -EIO;
-}
-
static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
{
int err;
@@ -269,6 +240,70 @@ static int ext4_ext_space_root_idx(struct inode *inode)
return size;
}
+static int
+ext4_ext_max_entries(struct inode *inode, int depth)
+{
+ int max;
+
+ if (depth == ext_depth(inode)) {
+ if (depth == 0)
+ max = ext4_ext_space_root(inode);
+ else
+ max = ext4_ext_space_root_idx(inode);
+ } else {
+ if (depth == 0)
+ max = ext4_ext_space_block(inode);
+ else
+ max = ext4_ext_space_block_idx(inode);
+ }
+
+ return max;
+}
+
+static int __ext4_ext_check_header(const char *function, struct inode *inode,
+ struct ext4_extent_header *eh,
+ int depth)
+{
+ const char *error_msg;
+ int max = 0;
+
+ if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
+ error_msg = "invalid magic";
+ goto corrupted;
+ }
+ if (unlikely(le16_to_cpu(eh->eh_depth) != depth)) {
+ error_msg = "unexpected eh_depth";
+ goto corrupted;
+ }
+ if (unlikely(eh->eh_max == 0)) {
+ error_msg = "invalid eh_max";
+ goto corrupted;
+ }
+ max = ext4_ext_max_entries(inode, depth);
+ if (unlikely(le16_to_cpu(eh->eh_max) > max)) {
+ error_msg = "too large eh_max";
+ goto corrupted;
+ }
+ if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
+ error_msg = "invalid eh_entries";
+ goto corrupted;
+ }
+ return 0;
+
+corrupted:
+ ext4_error(inode->i_sb, function,
+ "bad header in inode #%lu: %s - magic %x, "
+ "entries %u, max %u(%u), depth %u(%u)",
+ inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
+ le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
+ max, le16_to_cpu(eh->eh_depth), depth);
+
+ return -EIO;
+}
+
+#define ext4_ext_check_header(inode, eh, depth) \
+ __ext4_ext_check_header(__FUNCTION__, inode, eh, depth)
+
#ifdef EXT_DEBUG
static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
{
@@ -282,7 +317,7 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
} else if (path->p_ext) {
ext_debug(" %d:%d:%llu ",
le32_to_cpu(path->p_ext->ee_block),
- le16_to_cpu(path->p_ext->ee_len),
+ ext4_ext_get_actual_len(path->p_ext),
ext_pblock(path->p_ext));
} else
ext_debug(" []");
@@ -305,7 +340,7 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),
- le16_to_cpu(ex->ee_len), ext_pblock(ex));
+ ext4_ext_get_actual_len(ex), ext_pblock(ex));
}
ext_debug("\n");
}
@@ -329,6 +364,7 @@ static void ext4_ext_drop_refs(struct ext4_ext_path *path)
/*
* ext4_ext_binsearch_idx:
* binary search for the closest index of the given block
+ * the header must be checked before calling this
*/
static void
ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -336,27 +372,25 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
struct ext4_extent_header *eh = path->p_hdr;
struct ext4_extent_idx *r, *l, *m;
- BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
- BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
- BUG_ON(le16_to_cpu(eh->eh_entries) <= 0);
ext_debug("binsearch for %d(idx): ", block);
l = EXT_FIRST_INDEX(eh) + 1;
- r = EXT_FIRST_INDEX(eh) + le16_to_cpu(eh->eh_entries) - 1;
+ r = EXT_LAST_INDEX(eh);
while (l <= r) {
m = l + (r - l) / 2;
if (block < le32_to_cpu(m->ei_block))
r = m - 1;
else
l = m + 1;
- ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ei_block,
- m, m->ei_block, r, r->ei_block);
+ ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ei_block),
+ m, le32_to_cpu(m->ei_block),
+ r, le32_to_cpu(r->ei_block));
}
path->p_idx = l - 1;
ext_debug(" -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),
- idx_block(path->p_idx));
+ idx_pblock(path->p_idx));
#ifdef CHECK_BINSEARCH
{
@@ -388,6 +422,7 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
/*
* ext4_ext_binsearch:
* binary search for closest extent of the given block
+ * the header must be checked before calling this
*/
static void
ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
@@ -395,9 +430,6 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
struct ext4_extent_header *eh = path->p_hdr;
struct ext4_extent *r, *l, *m;
- BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
- BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
-
if (eh->eh_entries == 0) {
/*
* this leaf is empty:
@@ -409,7 +441,7 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
ext_debug("binsearch for %d: ", block);
l = EXT_FIRST_EXTENT(eh) + 1;
- r = EXT_FIRST_EXTENT(eh) + le16_to_cpu(eh->eh_entries) - 1;
+ r = EXT_LAST_EXTENT(eh);
while (l <= r) {
m = l + (r - l) / 2;
@@ -417,15 +449,16 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
r = m - 1;
else
l = m + 1;
- ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ee_block,
- m, m->ee_block, r, r->ee_block);
+ ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ee_block),
+ m, le32_to_cpu(m->ee_block),
+ r, le32_to_cpu(r->ee_block));
}
path->p_ext = l - 1;
ext_debug(" -> %d:%llu:%d ",
le32_to_cpu(path->p_ext->ee_block),
ext_pblock(path->p_ext),
- le16_to_cpu(path->p_ext->ee_len));
+ ext4_ext_get_actual_len(path->p_ext));
#ifdef CHECK_BINSEARCH
{
@@ -468,11 +501,10 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
short int depth, i, ppos = 0, alloc = 0;
eh = ext_inode_hdr(inode);
- BUG_ON(eh == NULL);
- if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+ depth = ext_depth(inode);
+ if (ext4_ext_check_header(inode, eh, depth))
return ERR_PTR(-EIO);
- i = depth = ext_depth(inode);
/* account possible depth increase */
if (!path) {
@@ -484,10 +516,12 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
}
path[0].p_hdr = eh;
+ i = depth;
/* walk through the tree */
while (i) {
ext_debug("depth %d: num %d, max %d\n",
ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
+
ext4_ext_binsearch_idx(inode, path + ppos, block);
path[ppos].p_block = idx_pblock(path[ppos].p_idx);
path[ppos].p_depth = i;
@@ -504,7 +538,7 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
path[ppos].p_hdr = eh;
i--;
- if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+ if (ext4_ext_check_header(inode, eh, i))
goto err;
}
@@ -513,9 +547,6 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
path[ppos].p_ext = NULL;
path[ppos].p_idx = NULL;
- if (ext4_ext_check_header(__FUNCTION__, inode, eh))
- goto err;
-
/* find extent */
ext4_ext_binsearch(inode, path + ppos, block);
@@ -553,7 +584,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {
len = (len - 1) * sizeof(struct ext4_extent_idx);
len = len < 0 ? 0 : len;
- ext_debug("insert new index %d after: %d. "
+ ext_debug("insert new index %d after: %llu. "
"move %d from 0x%p to 0x%p\n",
logical, ptr, len,
(curp->p_idx + 1), (curp->p_idx + 2));
@@ -564,7 +595,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
/* insert before */
len = len * sizeof(struct ext4_extent_idx);
len = len < 0 ? 0 : len;
- ext_debug("insert new index %d before: %d. "
+ ext_debug("insert new index %d before: %llu. "
"move %d from 0x%p to 0x%p\n",
logical, ptr, len,
curp->p_idx, (curp->p_idx + 1));
@@ -686,7 +717,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
ext_debug("move %d:%llu:%d in new leaf %llu\n",
le32_to_cpu(path[depth].p_ext->ee_block),
ext_pblock(path[depth].p_ext),
- le16_to_cpu(path[depth].p_ext->ee_len),
+ ext4_ext_get_actual_len(path[depth].p_ext),
newblock);
/*memmove(ex++, path[depth].p_ext++,
sizeof(struct ext4_extent));
@@ -764,7 +795,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) !=
EXT_LAST_INDEX(path[i].p_hdr));
while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
- ext_debug("%d: move %d:%d in new index %llu\n", i,
+ ext_debug("%d: move %d:%llu in new index %llu\n", i,
le32_to_cpu(path[i].p_idx->ei_block),
idx_pblock(path[i].p_idx),
newblock);
@@ -893,8 +924,13 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode));
curp->p_hdr->eh_entries = cpu_to_le16(1);
curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
- /* FIXME: it works, but actually path[0] can be index */
- curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
+
+ if (path[0].p_hdr->eh_depth)
+ curp->p_idx->ei_block =
+ EXT_FIRST_INDEX(path[0].p_hdr)->ei_block;
+ else
+ curp->p_idx->ei_block =
+ EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
ext4_idx_store_pblock(curp->p_idx, newblock);
neh = ext_inode_hdr(inode);
@@ -1106,7 +1142,24 @@ static int
ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
struct ext4_extent *ex2)
{
- if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) !=
+ unsigned short ext1_ee_len, ext2_ee_len, max_len;
+
+ /*
+ * Make sure that either both extents are uninitialized, or
+ * both are _not_.
+ */
+ if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2))
+ return 0;
+
+ if (ext4_ext_is_uninitialized(ex1))
+ max_len = EXT_UNINIT_MAX_LEN;
+ else
+ max_len = EXT_INIT_MAX_LEN;
+
+ ext1_ee_len = ext4_ext_get_actual_len(ex1);
+ ext2_ee_len = ext4_ext_get_actual_len(ex2);
+
+ if (le32_to_cpu(ex1->ee_block) + ext1_ee_len !=
le32_to_cpu(ex2->ee_block))
return 0;
@@ -1115,19 +1168,66 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
* as an RO_COMPAT feature, refuse to merge to extents if
* this can result in the top bit of ee_len being set.
*/
- if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN)
+ if (ext1_ee_len + ext2_ee_len > max_len)
return 0;
#ifdef AGGRESSIVE_TEST
if (le16_to_cpu(ex1->ee_len) >= 4)
return 0;
#endif
- if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2))
+ if (ext_pblock(ex1) + ext1_ee_len == ext_pblock(ex2))
return 1;
return 0;
}
/*
+ * This function tries to merge the "ex" extent to the next extent in the tree.
+ * It always tries to merge towards right. If you want to merge towards
+ * left, pass "ex - 1" as argument instead of "ex".
+ * Returns 0 if the extents (ex and ex+1) were _not_ merged and returns
+ * 1 if they got merged.
+ */
+int ext4_ext_try_to_merge(struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *ex)
+{
+ struct ext4_extent_header *eh;
+ unsigned int depth, len;
+ int merge_done = 0;
+ int uninitialized = 0;
+
+ depth = ext_depth(inode);
+ BUG_ON(path[depth].p_hdr == NULL);
+ eh = path[depth].p_hdr;
+
+ while (ex < EXT_LAST_EXTENT(eh)) {
+ if (!ext4_can_extents_be_merged(inode, ex, ex + 1))
+ break;
+ /* merge with next extent! */
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ + ext4_ext_get_actual_len(ex + 1));
+ if (uninitialized)
+ ext4_ext_mark_uninitialized(ex);
+
+ if (ex + 1 < EXT_LAST_EXTENT(eh)) {
+ len = (EXT_LAST_EXTENT(eh) - ex - 1)
+ * sizeof(struct ext4_extent);
+ memmove(ex + 1, ex + 2, len);
+ }
+ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1);
+ merge_done = 1;
+ WARN_ON(eh->eh_entries == 0);
+ if (!eh->eh_entries)
+ ext4_error(inode->i_sb, "ext4_ext_try_to_merge",
+ "inode#%lu, eh->eh_entries = 0!", inode->i_ino);
+ }
+
+ return merge_done;
+}
+
+/*
* check if a portion of the "newext" extent overlaps with an
* existing extent.
*
@@ -1144,7 +1244,7 @@ unsigned int ext4_ext_check_overlap(struct inode *inode,
unsigned int ret = 0;
b1 = le32_to_cpu(newext->ee_block);
- len1 = le16_to_cpu(newext->ee_len);
+ len1 = ext4_ext_get_actual_len(newext);
depth = ext_depth(inode);
if (!path[depth].p_ext)
goto out;
@@ -1191,8 +1291,9 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
struct ext4_extent *nearex; /* nearest extent */
struct ext4_ext_path *npath = NULL;
int depth, len, err, next;
+ unsigned uninitialized = 0;
- BUG_ON(newext->ee_len == 0);
+ BUG_ON(ext4_ext_get_actual_len(newext) == 0);
depth = ext_depth(inode);
ex = path[depth].p_ext;
BUG_ON(path[depth].p_hdr == NULL);
@@ -1200,14 +1301,24 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
/* try to insert block into found extent and return */
if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {
ext_debug("append %d block to %d:%d (from %llu)\n",
- le16_to_cpu(newext->ee_len),
+ ext4_ext_get_actual_len(newext),
le32_to_cpu(ex->ee_block),
- le16_to_cpu(ex->ee_len), ext_pblock(ex));
+ ext4_ext_get_actual_len(ex), ext_pblock(ex));
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
return err;
- ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len)
- + le16_to_cpu(newext->ee_len));
+
+ /*
+ * ext4_can_extents_be_merged should have checked that either
+ * both extents are uninitialized, or both aren't. Thus we
+ * need to check only one of them here.
+ */
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
+ + ext4_ext_get_actual_len(newext));
+ if (uninitialized)
+ ext4_ext_mark_uninitialized(ex);
eh = path[depth].p_hdr;
nearex = ex;
goto merge;
@@ -1263,7 +1374,7 @@ has_space:
ext_debug("first extent in the leaf: %d:%llu:%d\n",
le32_to_cpu(newext->ee_block),
ext_pblock(newext),
- le16_to_cpu(newext->ee_len));
+ ext4_ext_get_actual_len(newext));
path[depth].p_ext = EXT_FIRST_EXTENT(eh);
} else if (le32_to_cpu(newext->ee_block)
> le32_to_cpu(nearex->ee_block)) {
@@ -1276,7 +1387,7 @@ has_space:
"move %d from 0x%p to 0x%p\n",
le32_to_cpu(newext->ee_block),
ext_pblock(newext),
- le16_to_cpu(newext->ee_len),
+ ext4_ext_get_actual_len(newext),
nearex, len, nearex + 1, nearex + 2);
memmove(nearex + 2, nearex + 1, len);
}
@@ -1289,7 +1400,7 @@ has_space:
"move %d from 0x%p to 0x%p\n",
le32_to_cpu(newext->ee_block),
ext_pblock(newext),
- le16_to_cpu(newext->ee_len),
+ ext4_ext_get_actual_len(newext),
nearex, len, nearex + 1, nearex + 2);
memmove(nearex + 1, nearex, len);
path[depth].p_ext = nearex;
@@ -1304,20 +1415,7 @@ has_space:
merge:
/* try to merge extents to the right */
- while (nearex < EXT_LAST_EXTENT(eh)) {
- if (!ext4_can_extents_be_merged(inode, nearex, nearex + 1))
- break;
- /* merge with next extent! */
- nearex->ee_len = cpu_to_le16(le16_to_cpu(nearex->ee_len)
- + le16_to_cpu(nearex[1].ee_len));
- if (nearex + 1 < EXT_LAST_EXTENT(eh)) {
- len = (EXT_LAST_EXTENT(eh) - nearex - 1)
- * sizeof(struct ext4_extent);
- memmove(nearex + 1, nearex + 2, len);
- }
- eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
- BUG_ON(eh->eh_entries == 0);
- }
+ ext4_ext_try_to_merge(inode, path, nearex);
/* try to merge extents to the left */
@@ -1379,8 +1477,8 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
end = le32_to_cpu(ex->ee_block);
if (block + num < end)
end = block + num;
- } else if (block >=
- le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)) {
+ } else if (block >= le32_to_cpu(ex->ee_block)
+ + ext4_ext_get_actual_len(ex)) {
/* need to allocate space after found extent */
start = block;
end = block + num;
@@ -1392,7 +1490,8 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
* by found extent
*/
start = block;
- end = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len);
+ end = le32_to_cpu(ex->ee_block)
+ + ext4_ext_get_actual_len(ex);
if (block + num < end)
end = block + num;
exists = 1;
@@ -1408,7 +1507,7 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
cbex.ec_type = EXT4_EXT_CACHE_GAP;
} else {
cbex.ec_block = le32_to_cpu(ex->ee_block);
- cbex.ec_len = le16_to_cpu(ex->ee_len);
+ cbex.ec_len = ext4_ext_get_actual_len(ex);
cbex.ec_start = ext_pblock(ex);
cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
}
@@ -1481,15 +1580,15 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
ext_debug("cache gap(before): %lu [%lu:%lu]",
(unsigned long) block,
(unsigned long) le32_to_cpu(ex->ee_block),
- (unsigned long) le16_to_cpu(ex->ee_len));
+ (unsigned long) ext4_ext_get_actual_len(ex));
} else if (block >= le32_to_cpu(ex->ee_block)
- + le16_to_cpu(ex->ee_len)) {
+ + ext4_ext_get_actual_len(ex)) {
lblock = le32_to_cpu(ex->ee_block)
- + le16_to_cpu(ex->ee_len);
+ + ext4_ext_get_actual_len(ex);
len = ext4_ext_next_allocated_block(path);
ext_debug("cache gap(after): [%lu:%lu] %lu",
(unsigned long) le32_to_cpu(ex->ee_block),
- (unsigned long) le16_to_cpu(ex->ee_len),
+ (unsigned long) ext4_ext_get_actual_len(ex),
(unsigned long) block);
BUG_ON(len == lblock);
len = len - lblock;
@@ -1619,12 +1718,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
unsigned long from, unsigned long to)
{
struct buffer_head *bh;
+ unsigned short ee_len = ext4_ext_get_actual_len(ex);
int i;
#ifdef EXTENTS_STATS
{
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
- unsigned short ee_len = le16_to_cpu(ex->ee_len);
spin_lock(&sbi->s_ext_stats_lock);
sbi->s_ext_blocks += ee_len;
sbi->s_ext_extents++;
@@ -1638,12 +1737,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
}
#endif
if (from >= le32_to_cpu(ex->ee_block)
- && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+ && to == le32_to_cpu(ex->ee_block) + ee_len - 1) {
/* tail removal */
unsigned long num;
ext4_fsblk_t start;
- num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from;
- start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num;
+ num = le32_to_cpu(ex->ee_block) + ee_len - from;
+ start = ext_pblock(ex) + ee_len - num;
ext_debug("free last %lu blocks starting %llu\n", num, start);
for (i = 0; i < num; i++) {
bh = sb_find_get_block(inode->i_sb, start + i);
@@ -1651,12 +1750,12 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
}
ext4_free_blocks(handle, inode, start, num);
} else if (from == le32_to_cpu(ex->ee_block)
- && to <= le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+ && to <= le32_to_cpu(ex->ee_block) + ee_len - 1) {
printk("strange request: removal %lu-%lu from %u:%u\n",
- from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+ from, to, le32_to_cpu(ex->ee_block), ee_len);
} else {
printk("strange request: removal(2) %lu-%lu from %u:%u\n",
- from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+ from, to, le32_to_cpu(ex->ee_block), ee_len);
}
return 0;
}
@@ -1671,21 +1770,23 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
unsigned a, b, block, num;
unsigned long ex_ee_block;
unsigned short ex_ee_len;
+ unsigned uninitialized = 0;
struct ext4_extent *ex;
+ /* the header must be checked already in ext4_ext_remove_space() */
ext_debug("truncate since %lu in leaf\n", start);
if (!path[depth].p_hdr)
path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
eh = path[depth].p_hdr;
BUG_ON(eh == NULL);
- BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
- BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
/* find where to start removing */
ex = EXT_LAST_EXTENT(eh);
ex_ee_block = le32_to_cpu(ex->ee_block);
- ex_ee_len = le16_to_cpu(ex->ee_len);
+ if (ext4_ext_is_uninitialized(ex))
+ uninitialized = 1;
+ ex_ee_len = ext4_ext_get_actual_len(ex);
while (ex >= EXT_FIRST_EXTENT(eh) &&
ex_ee_block + ex_ee_len > start) {
@@ -1753,6 +1854,12 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
ex->ee_block = cpu_to_le32(block);
ex->ee_len = cpu_to_le16(num);
+ /*
+ * Do not mark uninitialized if all the blocks in the
+ * extent have been removed.
+ */
+ if (uninitialized && num)
+ ext4_ext_mark_uninitialized(ex);
err = ext4_ext_dirty(handle, inode, path + depth);
if (err)
@@ -1762,7 +1869,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
ext_pblock(ex));
ex--;
ex_ee_block = le32_to_cpu(ex->ee_block);
- ex_ee_len = le16_to_cpu(ex->ee_len);
+ ex_ee_len = ext4_ext_get_actual_len(ex);
}
if (correct_index && eh->eh_entries)
@@ -1825,7 +1932,7 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
return -ENOMEM;
}
path[0].p_hdr = ext_inode_hdr(inode);
- if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) {
+ if (ext4_ext_check_header(inode, path[0].p_hdr, depth)) {
err = -EIO;
goto out;
}
@@ -1846,17 +1953,8 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
if (!path[i].p_hdr) {
ext_debug("initialize header\n");
path[i].p_hdr = ext_block_hdr(path[i].p_bh);
- if (ext4_ext_check_header(__FUNCTION__, inode,
- path[i].p_hdr)) {
- err = -EIO;
- goto out;
- }
}
- BUG_ON(le16_to_cpu(path[i].p_hdr->eh_entries)
- > le16_to_cpu(path[i].p_hdr->eh_max));
- BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC);
-
if (!path[i].p_idx) {
/* this level hasn't been touched yet */
path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
@@ -1873,17 +1971,27 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
i, EXT_FIRST_INDEX(path[i].p_hdr),
path[i].p_idx);
if (ext4_ext_more_to_rm(path + i)) {
+ struct buffer_head *bh;
/* go to the next level */
ext_debug("move to level %d (block %llu)\n",
i + 1, idx_pblock(path[i].p_idx));
memset(path + i + 1, 0, sizeof(*path));
- path[i+1].p_bh =
- sb_bread(sb, idx_pblock(path[i].p_idx));
- if (!path[i+1].p_bh) {
+ bh = sb_bread(sb, idx_pblock(path[i].p_idx));
+ if (!bh) {
/* should we reset i_size? */
err = -EIO;
break;
}
+ if (WARN_ON(i + 1 > depth)) {
+ err = -EIO;
+ break;
+ }
+ if (ext4_ext_check_header(inode, ext_block_hdr(bh),
+ depth - i - 1)) {
+ err = -EIO;
+ break;
+ }
+ path[i + 1].p_bh = bh;
/* save actual number of indexes since this
* number is changed at the next iteration */
@@ -1977,15 +2085,158 @@ void ext4_ext_release(struct super_block *sb)
#endif
}
+/*
+ * This function is called by ext4_ext_get_blocks() if someone tries to write
+ * to an uninitialized extent. It may result in splitting the uninitialized
+ * extent into multiple extents (upto three - one initialized and two
+ * uninitialized).
+ * There are three possibilities:
+ * a> There is no split required: Entire extent should be initialized
+ * b> Splits in two extents: Write is happening at either end of the extent
+ * c> Splits in three extents: Somone is writing in middle of the extent
+ */
+int ext4_ext_convert_to_initialized(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ ext4_fsblk_t iblock,
+ unsigned long max_blocks)
+{
+ struct ext4_extent *ex, newex;
+ struct ext4_extent *ex1 = NULL;
+ struct ext4_extent *ex2 = NULL;
+ struct ext4_extent *ex3 = NULL;
+ struct ext4_extent_header *eh;
+ unsigned int allocated, ee_block, ee_len, depth;
+ ext4_fsblk_t newblock;
+ int err = 0;
+ int ret = 0;
+
+ depth = ext_depth(inode);
+ eh = path[depth].p_hdr;
+ ex = path[depth].p_ext;
+ ee_block = le32_to_cpu(ex->ee_block);
+ ee_len = ext4_ext_get_actual_len(ex);
+ allocated = ee_len - (iblock - ee_block);
+ newblock = iblock - ee_block + ext_pblock(ex);
+ ex2 = ex;
+
+ /* ex1: ee_block to iblock - 1 : uninitialized */
+ if (iblock > ee_block) {
+ ex1 = ex;
+ ex1->ee_len = cpu_to_le16(iblock - ee_block);
+ ext4_ext_mark_uninitialized(ex1);
+ ex2 = &newex;
+ }
+ /*
+ * for sanity, update the length of the ex2 extent before
+ * we insert ex3, if ex1 is NULL. This is to avoid temporary
+ * overlap of blocks.
+ */
+ if (!ex1 && allocated > max_blocks)
+ ex2->ee_len = cpu_to_le16(max_blocks);
+ /* ex3: to ee_block + ee_len : uninitialised */
+ if (allocated > max_blocks) {
+ unsigned int newdepth;
+ ex3 = &newex;
+ ex3->ee_block = cpu_to_le32(iblock + max_blocks);
+ ext4_ext_store_pblock(ex3, newblock + max_blocks);
+ ex3->ee_len = cpu_to_le16(allocated - max_blocks);
+ ext4_ext_mark_uninitialized(ex3);
+ err = ext4_ext_insert_extent(handle, inode, path, ex3);
+ if (err)
+ goto out;
+ /*
+ * The depth, and hence eh & ex might change
+ * as part of the insert above.
+ */
+ newdepth = ext_depth(inode);
+ if (newdepth != depth) {
+ depth = newdepth;
+ path = ext4_ext_find_extent(inode, iblock, NULL);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ path = NULL;
+ goto out;
+ }
+ eh = path[depth].p_hdr;
+ ex = path[depth].p_ext;
+ if (ex2 != &newex)
+ ex2 = ex;
+ }
+ allocated = max_blocks;
+ }
+ /*
+ * If there was a change of depth as part of the
+ * insertion of ex3 above, we need to update the length
+ * of the ex1 extent again here
+ */
+ if (ex1 && ex1 != ex) {
+ ex1 = ex;
+ ex1->ee_len = cpu_to_le16(iblock - ee_block);
+ ext4_ext_mark_uninitialized(ex1);
+ ex2 = &newex;
+ }
+ /* ex2: iblock to iblock + maxblocks-1 : initialised */
+ ex2->ee_block = cpu_to_le32(iblock);
+ ex2->ee_start = cpu_to_le32(newblock);
+ ext4_ext_store_pblock(ex2, newblock);
+ ex2->ee_len = cpu_to_le16(allocated);
+ if (ex2 != ex)
+ goto insert;
+ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
+ /*
+ * New (initialized) extent starts from the first block
+ * in the current extent. i.e., ex2 == ex
+ * We have to see if it can be merged with the extent
+ * on the left.
+ */
+ if (ex2 > EXT_FIRST_EXTENT(eh)) {
+ /*
+ * To merge left, pass "ex2 - 1" to try_to_merge(),
+ * since it merges towards right _only_.
+ */
+ ret = ext4_ext_try_to_merge(inode, path, ex2 - 1);
+ if (ret) {
+ err = ext4_ext_correct_indexes(handle, inode, path);
+ if (err)
+ goto out;
+ depth = ext_depth(inode);
+ ex2--;
+ }
+ }
+ /*
+ * Try to Merge towards right. This might be required
+ * only when the whole extent is being written to.
+ * i.e. ex2 == ex and ex3 == NULL.
+ */
+ if (!ex3) {
+ ret = ext4_ext_try_to_merge(inode, path, ex2);
+ if (ret) {
+ err = ext4_ext_correct_indexes(handle, inode, path);
+ if (err)
+ goto out;
+ }
+ }
+ /* Mark modified extent as dirty */
+ err = ext4_ext_dirty(handle, inode, path + depth);
+ goto out;
+insert:
+ err = ext4_ext_insert_extent(handle, inode, path, &newex);
+out:
+ return err ? err : allocated;
+}
+
int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
ext4_fsblk_t iblock,
unsigned long max_blocks, struct buffer_head *bh_result,
int create, int extend_disksize)
{
struct ext4_ext_path *path = NULL;
+ struct ext4_extent_header *eh;
struct ext4_extent newex, *ex;
ext4_fsblk_t goal, newblock;
- int err = 0, depth;
+ int err = 0, depth, ret;
unsigned long allocated = 0;
__clear_bit(BH_New, &bh_result->b_state);
@@ -1998,8 +2249,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
if (goal) {
if (goal == EXT4_EXT_CACHE_GAP) {
if (!create) {
- /* block isn't allocated yet and
- * user doesn't want to allocate it */
+ /*
+ * block isn't allocated yet and
+ * user doesn't want to allocate it
+ */
goto out2;
}
/* we should allocate requested block */
@@ -2033,21 +2286,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
* this is why assert can't be put in ext4_ext_find_extent()
*/
BUG_ON(path[depth].p_ext == NULL && depth != 0);
+ eh = path[depth].p_hdr;
ex = path[depth].p_ext;
if (ex) {
unsigned long ee_block = le32_to_cpu(ex->ee_block);
ext4_fsblk_t ee_start = ext_pblock(ex);
- unsigned short ee_len = le16_to_cpu(ex->ee_len);
+ unsigned short ee_len;
/*
- * Allow future support for preallocated extents to be added
- * as an RO_COMPAT feature:
* Uninitialized extents are treated as holes, except that
- * we avoid (fail) allocating new blocks during a write.
+ * we split out initialized portions during a write.
*/
- if (ee_len > EXT_MAX_LEN)
- goto out2;
+ ee_len = ext4_ext_get_actual_len(ex);
/* if found extent covers block, simply return it */
if (iblock >= ee_block && iblock < ee_block + ee_len) {
newblock = iblock - ee_block + ee_start;
@@ -2055,9 +2306,27 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
allocated = ee_len - (iblock - ee_block);
ext_debug("%d fit into %lu:%d -> %llu\n", (int) iblock,
ee_block, ee_len, newblock);
- ext4_ext_put_in_cache(inode, ee_block, ee_len,
- ee_start, EXT4_EXT_CACHE_EXTENT);
- goto out;
+
+ /* Do not put uninitialized extent in the cache */
+ if (!ext4_ext_is_uninitialized(ex)) {
+ ext4_ext_put_in_cache(inode, ee_block,
+ ee_len, ee_start,
+ EXT4_EXT_CACHE_EXTENT);
+ goto out;
+ }
+ if (create == EXT4_CREATE_UNINITIALIZED_EXT)
+ goto out;
+ if (!create)
+ goto out2;
+
+ ret = ext4_ext_convert_to_initialized(handle, inode,
+ path, iblock,
+ max_blocks);
+ if (ret <= 0)
+ goto out2;
+ else
+ allocated = ret;
+ goto outnew;
}
}
@@ -2066,8 +2335,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
* we couldn't try to create block if create flag is zero
*/
if (!create) {
- /* put just found gap into cache to speed up
- * subsequent requests */
+ /*
+ * put just found gap into cache to speed up
+ * subsequent requests
+ */
ext4_ext_put_gap_in_cache(inode, path, iblock);
goto out2;
}
@@ -2081,6 +2352,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* allocate new block */
goal = ext4_ext_find_goal(inode, path, iblock);
+ /*
+ * See if request is beyond maximum number of blocks we can have in
+ * a single extent. For an initialized extent this limit is
+ * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
+ * EXT_UNINIT_MAX_LEN.
+ */
+ if (max_blocks > EXT_INIT_MAX_LEN &&
+ create != EXT4_CREATE_UNINITIALIZED_EXT)
+ max_blocks = EXT_INIT_MAX_LEN;
+ else if (max_blocks > EXT_UNINIT_MAX_LEN &&
+ create == EXT4_CREATE_UNINITIALIZED_EXT)
+ max_blocks = EXT_UNINIT_MAX_LEN;
+
/* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
newex.ee_block = cpu_to_le32(iblock);
newex.ee_len = cpu_to_le16(max_blocks);
@@ -2098,6 +2382,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* try to insert new extent into found leaf and return */
ext4_ext_store_pblock(&newex, newblock);
newex.ee_len = cpu_to_le16(allocated);
+ if (create == EXT4_CREATE_UNINITIALIZED_EXT) /* Mark uninitialized */
+ ext4_ext_mark_uninitialized(&newex);
err = ext4_ext_insert_extent(handle, inode, path, &newex);
if (err) {
/* free data blocks we just allocated */
@@ -2111,10 +2397,13 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
/* previous routine could use block we allocated */
newblock = ext_pblock(&newex);
+outnew:
__set_bit(BH_New, &bh_result->b_state);
- ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
- EXT4_EXT_CACHE_EXTENT);
+ /* Cache only when it is _not_ an uninitialized extent */
+ if (create != EXT4_CREATE_UNINITIALIZED_EXT)
+ ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
+ EXT4_EXT_CACHE_EXTENT);
out:
if (allocated > max_blocks)
allocated = max_blocks;
@@ -2178,7 +2467,8 @@ void ext4_ext_truncate(struct inode * inode, struct page *page)
err = ext4_ext_remove_space(inode, last_block);
/* In a multi-transaction truncate, we only make the final
- * transaction synchronous. */
+ * transaction synchronous.
+ */
if (IS_SYNC(inode))
handle->h_sync = 1;
@@ -2217,3 +2507,127 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
return needed;
}
+
+/*
+ * preallocate space for a file. This implements ext4's fallocate inode
+ * operation, which gets called from sys_fallocate system call.
+ * For block-mapped files, posix_fallocate should fall back to the method
+ * of writing zeroes to the required new blocks (the same behavior which is
+ * expected for file systems which do not support fallocate() system call).
+ */
+long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
+{
+ handle_t *handle;
+ ext4_fsblk_t block, max_blocks;
+ ext4_fsblk_t nblocks = 0;
+ int ret = 0;
+ int ret2 = 0;
+ int retries = 0;
+ struct buffer_head map_bh;
+ unsigned int credits, blkbits = inode->i_blkbits;
+
+ /*
+ * currently supporting (pre)allocate mode for extent-based
+ * files _only_
+ */
+ if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
+ return -EOPNOTSUPP;
+
+ /* preallocation to directories is currently not supported */
+ if (S_ISDIR(inode->i_mode))
+ return -ENODEV;
+
+ block = offset >> blkbits;
+ max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
+ - block;
+
+ /*
+ * credits to insert 1 extent into extent tree + buffers to be able to
+ * modify 1 super block, 1 block bitmap and 1 group descriptor.
+ */
+ credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + 3;
+retry:
+ while (ret >= 0 && ret < max_blocks) {
+ block = block + ret;
+ max_blocks = max_blocks - ret;
+ handle = ext4_journal_start(inode, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ break;
+ }
+
+ ret = ext4_ext_get_blocks(handle, inode, block,
+ max_blocks, &map_bh,
+ EXT4_CREATE_UNINITIALIZED_EXT, 0);
+ WARN_ON(!ret);
+ if (!ret) {
+ ext4_error(inode->i_sb, "ext4_fallocate",
+ "ext4_ext_get_blocks returned 0! inode#%lu"
+ ", block=%llu, max_blocks=%llu",
+ inode->i_ino, block, max_blocks);
+ ret = -EIO;
+ ext4_mark_inode_dirty(handle, inode);
+ ret2 = ext4_journal_stop(handle);
+ break;
+ }
+ if (ret > 0) {
+ /* check wrap through sign-bit/zero here */
+ if ((block + ret) < 0 || (block + ret) < block) {
+ ret = -EIO;
+ ext4_mark_inode_dirty(handle, inode);
+ ret2 = ext4_journal_stop(handle);
+ break;
+ }
+ if (buffer_new(&map_bh) && ((block + ret) >
+ (EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits)
+ >> blkbits)))
+ nblocks = nblocks + ret;
+ }
+
+ /* Update ctime if new blocks get allocated */
+ if (nblocks) {
+ struct timespec now;
+
+ now = current_fs_time(inode->i_sb);
+ if (!timespec_equal(&inode->i_ctime, &now))
+ inode->i_ctime = now;
+ }
+
+ ext4_mark_inode_dirty(handle, inode);
+ ret2 = ext4_journal_stop(handle);
+ if (ret2)
+ break;
+ }
+
+ if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+
+ /*
+ * Time to update the file size.
+ * Update only when preallocation was requested beyond the file size.
+ */
+ if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+ (offset + len) > i_size_read(inode)) {
+ if (ret > 0) {
+ /*
+ * if no error, we assume preallocation succeeded
+ * completely
+ */
+ mutex_lock(&inode->i_mutex);
+ i_size_write(inode, offset + len);
+ EXT4_I(inode)->i_disksize = i_size_read(inode);
+ mutex_unlock(&inode->i_mutex);
+ } else if (ret < 0 && nblocks) {
+ /* Handle partial allocation scenario */
+ loff_t newsize;
+
+ mutex_lock(&inode->i_mutex);
+ newsize = (nblocks << blkbits) + i_size_read(inode);
+ i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
+ EXT4_I(inode)->i_disksize = i_size_read(inode);
+ mutex_unlock(&inode->i_mutex);
+ }
+ }
+
+ return ret > 0 ? ret2 : ret;
+}
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index d4c8186aed64..1a81cd66d63b 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -134,5 +134,6 @@ const struct inode_operations ext4_file_inode_operations = {
.removexattr = generic_removexattr,
#endif
.permission = ext4_permission,
+ .fallocate = ext4_fallocate,
};
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index c88b439ba5cd..427f83066a0d 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -563,7 +563,8 @@ got:
inode->i_ino = ino;
/* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
+ ext4_current_time(inode);
memset(ei->i_data, 0, sizeof(ei->i_data));
ei->i_dir_start_lookup = 0;
@@ -595,9 +596,8 @@ got:
spin_unlock(&sbi->s_next_gen_lock);
ei->i_state = EXT4_STATE_NEW;
- ei->i_extra_isize =
- (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ?
- sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0;
+
+ ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
ret = inode;
if(DQUOT_ALLOC_INODE(inode)) {
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 8416fa28c422..a4848e04a5ed 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -726,7 +726,7 @@ static int ext4_splice_branch(handle_t *handle, struct inode *inode,
/* We are done with atomic stuff, now do the rest of housekeeping */
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
/* had we spliced it onto indirect block? */
@@ -1766,7 +1766,6 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
struct inode *inode = mapping->host;
struct buffer_head *bh;
int err = 0;
- void *kaddr;
blocksize = inode->i_sb->s_blocksize;
length = blocksize - (offset & (blocksize - 1));
@@ -1778,10 +1777,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
*/
if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
ext4_should_writeback_data(inode) && PageUptodate(page)) {
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, length, KM_USER0);
set_page_dirty(page);
goto unlock;
}
@@ -1834,10 +1830,7 @@ int ext4_block_truncate_page(handle_t *handle, struct page *page,
goto unlock;
}
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + offset, 0, length);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, offset, length, KM_USER0);
BUFFER_TRACE(bh, "zeroed end of block");
@@ -2375,7 +2368,7 @@ do_indirects:
ext4_discard_reservation(inode);
mutex_unlock(&ei->truncate_mutex);
- inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
/*
@@ -2583,6 +2576,25 @@ void ext4_set_inode_flags(struct inode *inode)
inode->i_flags |= S_DIRSYNC;
}
+/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
+void ext4_get_inode_flags(struct ext4_inode_info *ei)
+{
+ unsigned int flags = ei->vfs_inode.i_flags;
+
+ ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL|
+ EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL);
+ if (flags & S_SYNC)
+ ei->i_flags |= EXT4_SYNC_FL;
+ if (flags & S_APPEND)
+ ei->i_flags |= EXT4_APPEND_FL;
+ if (flags & S_IMMUTABLE)
+ ei->i_flags |= EXT4_IMMUTABLE_FL;
+ if (flags & S_NOATIME)
+ ei->i_flags |= EXT4_NOATIME_FL;
+ if (flags & S_DIRSYNC)
+ ei->i_flags |= EXT4_DIRSYNC_FL;
+}
+
void ext4_read_inode(struct inode * inode)
{
struct ext4_iloc iloc;
@@ -2610,10 +2622,6 @@ void ext4_read_inode(struct inode * inode)
}
inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
inode->i_size = le32_to_cpu(raw_inode->i_size);
- inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
- inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
- inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
- inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
ei->i_state = 0;
ei->i_dir_start_lookup = 0;
@@ -2691,6 +2699,11 @@ void ext4_read_inode(struct inode * inode)
} else
ei->i_extra_isize = 0;
+ EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
+ EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
+ EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode);
+ EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode);
+
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext4_file_inode_operations;
inode->i_fop = &ext4_file_operations;
@@ -2744,6 +2757,7 @@ static int ext4_do_update_inode(handle_t *handle,
if (ei->i_state & EXT4_STATE_NEW)
memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
+ ext4_get_inode_flags(ei);
raw_inode->i_mode = cpu_to_le16(inode->i_mode);
if(!(test_opt(inode->i_sb, NO_UID32))) {
raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
@@ -2771,9 +2785,12 @@ static int ext4_do_update_inode(handle_t *handle,
}
raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
raw_inode->i_size = cpu_to_le32(ei->i_disksize);
- raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
- raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
- raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
+
+ EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode);
+ EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode);
+ EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode);
+ EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode);
+
raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
raw_inode->i_flags = cpu_to_le32(ei->i_flags);
@@ -2886,7 +2903,7 @@ int ext4_write_inode(struct inode *inode, int wait)
return 0;
if (ext4_journal_current_handle()) {
- jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n");
+ jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n");
dump_stack();
return -EIO;
}
@@ -3082,6 +3099,39 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
}
/*
+ * Expand an inode by new_extra_isize bytes.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize(struct inode *inode, unsigned int new_extra_isize,
+ struct ext4_iloc iloc, handle_t *handle)
+{
+ struct ext4_inode *raw_inode;
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_xattr_entry *entry;
+
+ if (EXT4_I(inode)->i_extra_isize >= new_extra_isize)
+ return 0;
+
+ raw_inode = ext4_raw_inode(&iloc);
+
+ header = IHDR(inode, raw_inode);
+ entry = IFIRST(header);
+
+ /* No extended attributes present */
+ if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR) ||
+ header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
+ memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0,
+ new_extra_isize);
+ EXT4_I(inode)->i_extra_isize = new_extra_isize;
+ return 0;
+ }
+
+ /* try to expand with EAs present */
+ return ext4_expand_extra_isize_ea(inode, new_extra_isize,
+ raw_inode, handle);
+}
+
+/*
* What we do here is to mark the in-core inode as clean with respect to inode
* dirtiness (it may still be data-dirty).
* This means that the in-core inode may be reaped by prune_icache
@@ -3105,10 +3155,38 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
{
struct ext4_iloc iloc;
- int err;
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ static unsigned int mnt_count;
+ int err, ret;
might_sleep();
err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&
+ !(EXT4_I(inode)->i_state & EXT4_STATE_NO_EXPAND)) {
+ /*
+ * We need extra buffer credits since we may write into EA block
+ * with this same handle. If journal_extend fails, then it will
+ * only result in a minor loss of functionality for that inode.
+ * If this is felt to be critical, then e2fsck should be run to
+ * force a large enough s_min_extra_isize.
+ */
+ if ((jbd2_journal_extend(handle,
+ EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {
+ ret = ext4_expand_extra_isize(inode,
+ sbi->s_want_extra_isize,
+ iloc, handle);
+ if (ret) {
+ EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
+ if (mnt_count != sbi->s_es->s_mnt_count) {
+ ext4_warning(inode->i_sb, __FUNCTION__,
+ "Unable to expand inode %lu. Delete"
+ " some EAs or run e2fsck.",
+ inode->i_ino);
+ mnt_count = sbi->s_es->s_mnt_count;
+ }
+ }
+ }
+ }
if (!err)
err = ext4_mark_iloc_dirty(handle, inode, &iloc);
return err;
@@ -3197,7 +3275,7 @@ int ext4_change_inode_journal_flag(struct inode *inode, int val)
*/
journal = EXT4_JOURNAL(inode);
- if (is_journal_aborted(journal) || IS_RDONLY(inode))
+ if (is_journal_aborted(journal))
return -EROFS;
jbd2_journal_lock_updates(journal);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 500567dd53b6..c04c7ccba9e3 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -28,6 +28,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
switch (cmd) {
case EXT4_IOC_GETFLAGS:
+ ext4_get_inode_flags(ei);
flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
return put_user(flags, (int __user *) arg);
case EXT4_IOC_SETFLAGS: {
@@ -40,7 +41,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EACCES;
if (get_user(flags, (int __user *) arg))
@@ -96,7 +97,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
ei->i_flags = flags;
ext4_set_inode_flags(inode);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
err = ext4_mark_iloc_dirty(handle, inode, &iloc);
flags_err:
@@ -121,7 +122,7 @@ flags_err:
__u32 generation;
int err;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
@@ -133,14 +134,14 @@ flags_err:
return PTR_ERR(handle);
err = ext4_reserve_inode_write(handle, inode, &iloc);
if (err == 0) {
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
inode->i_generation = generation;
err = ext4_mark_iloc_dirty(handle, inode, &iloc);
}
ext4_journal_stop(handle);
return err;
}
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
case EXT4_IOC_WAIT_FOR_READONLY:
/*
* This is racy - by the time we're woken up and running,
@@ -180,7 +181,7 @@ flags_err:
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EACCES;
if (get_user(rsv_window_size, (int __user *)arg))
@@ -282,7 +283,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case EXT4_IOC32_SETVERSION_OLD:
cmd = EXT4_IOC_SETVERSION_OLD;
break;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
case EXT4_IOC32_WAIT_FOR_READONLY:
cmd = EXT4_IOC_WAIT_FOR_READONLY;
break;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 2811e5720ad0..da224974af78 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -1017,6 +1017,11 @@ static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, str
if (!inode)
return ERR_PTR(-EACCES);
+
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
}
return d_splice_alias(inode, dentry);
}
@@ -1052,6 +1057,11 @@ struct dentry *ext4_get_parent(struct dentry *child)
if (!inode)
return ERR_PTR(-EACCES);
+ if (is_bad_inode(inode)) {
+ iput(inode);
+ return ERR_PTR(-ENOENT);
+ }
+
parent = d_alloc_anon(inode);
if (!parent) {
iput(inode);
@@ -1285,7 +1295,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
* happen is that the times are slightly out of date
* and/or different from the directory change time.
*/
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ dir->i_mtime = dir->i_ctime = ext4_current_time(dir);
ext4_update_dx_flag(dir);
dir->i_version++;
ext4_mark_inode_dirty(handle, dir);
@@ -1619,6 +1629,35 @@ static int ext4_delete_entry (handle_t *handle,
return -ENOENT;
}
+/*
+ * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
+ * since this indicates that nlinks count was previously 1.
+ */
+static void ext4_inc_count(handle_t *handle, struct inode *inode)
+{
+ inc_nlink(inode);
+ if (is_dx(inode) && inode->i_nlink > 1) {
+ /* limit is 16-bit i_links_count */
+ if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) {
+ inode->i_nlink = 1;
+ EXT4_SET_RO_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK);
+ }
+ }
+}
+
+/*
+ * If a directory had nlink == 1, then we should let it be 1. This indicates
+ * directory has >EXT4_LINK_MAX subdirs.
+ */
+static void ext4_dec_count(handle_t *handle, struct inode *inode)
+{
+ drop_nlink(inode);
+ if (S_ISDIR(inode->i_mode) && inode->i_nlink == 0)
+ inc_nlink(inode);
+}
+
+
static int ext4_add_nondir(handle_t *handle,
struct dentry *dentry, struct inode *inode)
{
@@ -1715,7 +1754,7 @@ static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
struct ext4_dir_entry_2 * de;
int err, retries = 0;
- if (dir->i_nlink >= EXT4_LINK_MAX)
+ if (EXT4_DIR_LINK_MAX(dir))
return -EMLINK;
retry:
@@ -1738,7 +1777,7 @@ retry:
inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
dir_block = ext4_bread (handle, inode, 0, 1, &err);
if (!dir_block) {
- drop_nlink(inode); /* is this nlink == 0? */
+ ext4_dec_count(handle, inode); /* is this nlink == 0? */
ext4_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -1770,7 +1809,7 @@ retry:
iput (inode);
goto out_stop;
}
- inc_nlink(dir);
+ ext4_inc_count(handle, dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
d_instantiate(dentry, inode);
@@ -2035,9 +2074,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
retval = ext4_delete_entry(handle, dir, de, bh);
if (retval)
goto end_rmdir;
- if (inode->i_nlink != 2)
+ if (!EXT4_DIR_LINK_EMPTY(inode))
ext4_warning (inode->i_sb, "ext4_rmdir",
- "empty directory has nlink!=2 (%d)",
+ "empty directory has too many links (%d)",
inode->i_nlink);
inode->i_version++;
clear_nlink(inode);
@@ -2046,9 +2085,9 @@ static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
* recovery. */
inode->i_size = 0;
ext4_orphan_add(handle, inode);
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
- drop_nlink(dir);
+ ext4_dec_count(handle, dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
@@ -2096,13 +2135,13 @@ static int ext4_unlink(struct inode * dir, struct dentry *dentry)
retval = ext4_delete_entry(handle, dir, de, bh);
if (retval)
goto end_unlink;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ dir->i_ctime = dir->i_mtime = ext4_current_time(dir);
ext4_update_dx_flag(dir);
ext4_mark_inode_dirty(handle, dir);
- drop_nlink(inode);
+ ext4_dec_count(handle, inode);
if (!inode->i_nlink)
ext4_orphan_add(handle, inode);
- inode->i_ctime = dir->i_ctime;
+ inode->i_ctime = ext4_current_time(inode);
ext4_mark_inode_dirty(handle, inode);
retval = 0;
@@ -2149,7 +2188,7 @@ retry:
err = __page_symlink(inode, symname, l,
mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
if (err) {
- drop_nlink(inode);
+ ext4_dec_count(handle, inode);
ext4_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -2175,8 +2214,9 @@ static int ext4_link (struct dentry * old_dentry,
struct inode *inode = old_dentry->d_inode;
int err, retries = 0;
- if (inode->i_nlink >= EXT4_LINK_MAX)
+ if (EXT4_DIR_LINK_MAX(inode))
return -EMLINK;
+
/*
* Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
* otherwise has the potential to corrupt the orphan inode list.
@@ -2193,8 +2233,8 @@ retry:
if (IS_DIRSYNC(dir))
handle->h_sync = 1;
- inode->i_ctime = CURRENT_TIME_SEC;
- inc_nlink(inode);
+ inode->i_ctime = ext4_current_time(inode);
+ ext4_inc_count(handle, inode);
atomic_inc(&inode->i_count);
err = ext4_add_nondir(handle, dentry, inode);
@@ -2295,7 +2335,7 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
* Like most other Unix systems, set the ctime for inodes on a
* rename.
*/
- old_inode->i_ctime = CURRENT_TIME_SEC;
+ old_inode->i_ctime = ext4_current_time(old_inode);
ext4_mark_inode_dirty(handle, old_inode);
/*
@@ -2327,10 +2367,10 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
}
if (new_inode) {
- drop_nlink(new_inode);
- new_inode->i_ctime = CURRENT_TIME_SEC;
+ ext4_dec_count(handle, new_inode);
+ new_inode->i_ctime = ext4_current_time(new_inode);
}
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ old_dir->i_ctime = old_dir->i_mtime = ext4_current_time(old_dir);
ext4_update_dx_flag(old_dir);
if (dir_bh) {
BUFFER_TRACE(dir_bh, "get_write_access");
@@ -2338,11 +2378,13 @@ static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
ext4_journal_dirty_metadata(handle, dir_bh);
- drop_nlink(old_dir);
+ ext4_dec_count(handle, old_dir);
if (new_inode) {
- drop_nlink(new_inode);
+ /* checked empty_dir above, can't have another parent,
+ * ext3_dec_count() won't work for many-linked dirs */
+ new_inode->i_nlink = 0;
} else {
- inc_nlink(new_dir);
+ ext4_inc_count(handle, new_dir);
ext4_update_dx_flag(new_dir);
ext4_mark_inode_dirty(handle, new_dir);
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 175b68c60968..75adbb64e028 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -29,12 +29,14 @@
#include <linux/parser.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <linux/vfs.h>
#include <linux/random.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/quotaops.h>
#include <linux/seq_file.h>
+#include <linux/log2.h>
#include <asm/uaccess.h>
@@ -510,6 +512,14 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
static void ext4_destroy_inode(struct inode *inode)
{
+ if (!list_empty(&(EXT4_I(inode)->i_orphan))) {
+ printk("EXT4 Inode %p: orphan list check failed!\n",
+ EXT4_I(inode));
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4,
+ EXT4_I(inode), sizeof(struct ext4_inode_info),
+ true);
+ dump_stack();
+ }
kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
}
@@ -531,7 +541,7 @@ static int init_inodecache(void)
sizeof(struct ext4_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (ext4_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -725,7 +735,7 @@ enum {
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
- Opt_grpquota, Opt_extents,
+ Opt_grpquota, Opt_extents, Opt_noextents,
};
static match_table_t tokens = {
@@ -776,6 +786,7 @@ static match_table_t tokens = {
{Opt_usrquota, "usrquota"},
{Opt_barrier, "barrier=%u"},
{Opt_extents, "extents"},
+ {Opt_noextents, "noextents"},
{Opt_err, NULL},
{Opt_resize, "resize"},
};
@@ -1111,6 +1122,9 @@ clear_qf_name:
case Opt_extents:
set_opt (sbi->s_mount_opt, EXTENTS);
break;
+ case Opt_noextents:
+ clear_opt (sbi->s_mount_opt, EXTENTS);
+ break;
default:
printk (KERN_ERR
"EXT4-fs: Unrecognized mount option \"%s\" "
@@ -1542,6 +1556,12 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
set_opt(sbi->s_mount_opt, RESERVATION);
+ /*
+ * turn on extents feature by default in ext4 filesystem
+ * User -o noextents to turn it off
+ */
+ set_opt(sbi->s_mount_opt, EXTENTS);
+
if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
NULL, 0))
goto failed_mount;
@@ -1625,13 +1645,15 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
- (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
+ (!is_power_of_2(sbi->s_inode_size)) ||
(sbi->s_inode_size > blocksize)) {
printk (KERN_ERR
"EXT4-fs: unsupported inode size: %d\n",
sbi->s_inode_size);
goto failed_mount;
}
+ if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
+ sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
}
sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
le32_to_cpu(es->s_log_frag_size);
@@ -1794,6 +1816,13 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
goto failed_mount3;
}
+ if (ext4_blocks_count(es) > 0xffffffffULL &&
+ !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
+ JBD2_FEATURE_INCOMPAT_64BIT)) {
+ printk(KERN_ERR "ext4: Failed to set 64-bit journal feature\n");
+ goto failed_mount4;
+ }
+
/* We have now updated the journal if required, so we can
* validate the data journaling mode. */
switch (test_opt(sb, DATA_FLAGS)) {
@@ -1848,6 +1877,32 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
}
ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
+
+ /* determine the minimum size of new large inodes, if present */
+ if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
+ sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+ EXT4_GOOD_OLD_INODE_SIZE;
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
+ if (sbi->s_want_extra_isize <
+ le16_to_cpu(es->s_want_extra_isize))
+ sbi->s_want_extra_isize =
+ le16_to_cpu(es->s_want_extra_isize);
+ if (sbi->s_want_extra_isize <
+ le16_to_cpu(es->s_min_extra_isize))
+ sbi->s_want_extra_isize =
+ le16_to_cpu(es->s_min_extra_isize);
+ }
+ }
+ /* Check if enough inode space is available */
+ if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize >
+ sbi->s_inode_size) {
+ sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
+ EXT4_GOOD_OLD_INODE_SIZE;
+ printk(KERN_INFO "EXT4-fs: required extra inode space not"
+ "available.\n");
+ }
+
/*
* akpm: core read_super() calls in here with the superblock locked.
* That deadlocks, because orphan cleanup needs to lock the superblock
@@ -2150,6 +2205,7 @@ static int ext4_create_journal(struct super_block * sb,
unsigned int journal_inum)
{
journal_t *journal;
+ int err;
if (sb->s_flags & MS_RDONLY) {
printk(KERN_ERR "EXT4-fs: readonly filesystem when trying to "
@@ -2157,13 +2213,15 @@ static int ext4_create_journal(struct super_block * sb,
return -EROFS;
}
- if (!(journal = ext4_get_journal(sb, journal_inum)))
+ journal = ext4_get_journal(sb, journal_inum);
+ if (!journal)
return -EINVAL;
printk(KERN_INFO "EXT4-fs: creating new journal on inode %u\n",
journal_inum);
- if (jbd2_journal_create(journal)) {
+ err = jbd2_journal_create(journal);
+ if (err) {
printk(KERN_ERR "EXT4-fs: error creating journal.\n");
jbd2_journal_destroy(journal);
return -EIO;
@@ -2214,12 +2272,14 @@ static void ext4_mark_recovery_complete(struct super_block * sb,
jbd2_journal_lock_updates(journal);
jbd2_journal_flush(journal);
+ lock_super(sb);
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
sb->s_flags & MS_RDONLY) {
EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
sb->s_dirt = 0;
ext4_commit_super(sb, es, 1);
}
+ unlock_super(sb);
jbd2_journal_unlock_updates(journal);
}
@@ -2408,7 +2468,13 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data)
(sbi->s_mount_state & EXT4_VALID_FS))
es->s_state = cpu_to_le16(sbi->s_mount_state);
+ /*
+ * We have to unlock super so that we can wait for
+ * transactions.
+ */
+ unlock_super(sb);
ext4_mark_recovery_complete(sb, es);
+ lock_super(sb);
} else {
__le32 ret;
if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb,
@@ -2481,19 +2547,19 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
struct super_block *sb = dentry->d_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es;
- ext4_fsblk_t overhead;
- int i;
u64 fsid;
- if (test_opt (sb, MINIX_DF))
- overhead = 0;
- else {
- unsigned long ngroups;
- ngroups = EXT4_SB(sb)->s_groups_count;
+ if (test_opt(sb, MINIX_DF)) {
+ sbi->s_overhead_last = 0;
+ } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
+ unsigned long ngroups = sbi->s_groups_count, i;
+ ext4_fsblk_t overhead = 0;
smp_rmb();
/*
- * Compute the overhead (FS structures)
+ * Compute the overhead (FS structures). This is constant
+ * for a given filesystem unless the number of block groups
+ * changes so we cache the previous value until it does.
*/
/*
@@ -2517,18 +2583,23 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
* Every block group has an inode bitmap, a block
* bitmap, and an inode table.
*/
- overhead += (ngroups * (2 + EXT4_SB(sb)->s_itb_per_group));
+ overhead += ngroups * (2 + sbi->s_itb_per_group);
+ sbi->s_overhead_last = overhead;
+ smp_wmb();
+ sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
}
buf->f_type = EXT4_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
- buf->f_blocks = ext4_blocks_count(es) - overhead;
+ buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
+ es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
if (buf->f_bfree < ext4_r_blocks_count(es))
buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
+ es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
buf->f_namelen = EXT4_NAME_LEN;
fsid = le64_to_cpup((void *)es->s_uuid) ^
le64_to_cpup((void *)es->s_uuid + sizeof(u64));
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e832e96095b3..b10d68fffb55 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -66,13 +66,6 @@
#define BFIRST(bh) ENTRY(BHDR(bh)+1)
#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
-#define IHDR(inode, raw_inode) \
- ((struct ext4_xattr_ibody_header *) \
- ((void *)raw_inode + \
- EXT4_GOOD_OLD_INODE_SIZE + \
- EXT4_I(inode)->i_extra_isize))
-#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
-
#ifdef EXT4_XATTR_DEBUG
# define ea_idebug(inode, f...) do { \
printk(KERN_DEBUG "inode %s:%lu: ", \
@@ -508,6 +501,24 @@ out:
return;
}
+/*
+ * Find the available free space for EAs. This also returns the total number of
+ * bytes used by EA entries.
+ */
+static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last,
+ size_t *min_offs, void *base, int *total)
+{
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ *total += EXT4_XATTR_LEN(last->e_name_len);
+ if (!last->e_value_block && last->e_value_size) {
+ size_t offs = le16_to_cpu(last->e_value_offs);
+ if (offs < *min_offs)
+ *min_offs = offs;
+ }
+ }
+ return (*min_offs - ((void *)last - base) - sizeof(__u32));
+}
+
struct ext4_xattr_info {
int name_index;
const char *name;
@@ -1013,7 +1024,9 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
}
if (!error) {
ext4_xattr_update_super_block(handle, inode->i_sb);
- inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_ctime = ext4_current_time(inode);
+ if (!value)
+ EXT4_I(inode)->i_state &= ~EXT4_STATE_NO_EXPAND;
error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
/*
* The bh is consumed by ext4_mark_iloc_dirty, even with
@@ -1067,6 +1080,253 @@ retry:
}
/*
+ * Shift the EA entries in the inode to create space for the increased
+ * i_extra_isize.
+ */
+static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
+ int value_offs_shift, void *to,
+ void *from, size_t n, int blocksize)
+{
+ struct ext4_xattr_entry *last = entry;
+ int new_offs;
+
+ /* Adjust the value offsets of the entries */
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ if (!last->e_value_block && last->e_value_size) {
+ new_offs = le16_to_cpu(last->e_value_offs) +
+ value_offs_shift;
+ BUG_ON(new_offs + le32_to_cpu(last->e_value_size)
+ > blocksize);
+ last->e_value_offs = cpu_to_le16(new_offs);
+ }
+ }
+ /* Shift the entries by n bytes */
+ memmove(to, from, n);
+}
+
+/*
+ * Expand an inode by new_extra_isize bytes when EAs are present.
+ * Returns 0 on success or negative error number on failure.
+ */
+int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+ struct ext4_inode *raw_inode, handle_t *handle)
+{
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_xattr_entry *entry, *last, *first;
+ struct buffer_head *bh = NULL;
+ struct ext4_xattr_ibody_find *is = NULL;
+ struct ext4_xattr_block_find *bs = NULL;
+ char *buffer = NULL, *b_entry_name = NULL;
+ size_t min_offs, free;
+ int total_ino, total_blk;
+ void *base, *start, *end;
+ int extra_isize = 0, error = 0, tried_min_extra_isize = 0;
+ int s_min_extra_isize = EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize;
+
+ down_write(&EXT4_I(inode)->xattr_sem);
+retry:
+ if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) {
+ up_write(&EXT4_I(inode)->xattr_sem);
+ return 0;
+ }
+
+ header = IHDR(inode, raw_inode);
+ entry = IFIRST(header);
+
+ /*
+ * Check if enough free space is available in the inode to shift the
+ * entries ahead by new_extra_isize.
+ */
+
+ base = start = entry;
+ end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
+ min_offs = end - base;
+ last = entry;
+ total_ino = sizeof(struct ext4_xattr_ibody_header);
+
+ free = ext4_xattr_free_space(last, &min_offs, base, &total_ino);
+ if (free >= new_extra_isize) {
+ entry = IFIRST(header);
+ ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize
+ - new_extra_isize, (void *)raw_inode +
+ EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize,
+ (void *)header, total_ino,
+ inode->i_sb->s_blocksize);
+ EXT4_I(inode)->i_extra_isize = new_extra_isize;
+ error = 0;
+ goto cleanup;
+ }
+
+ /*
+ * Enough free space isn't available in the inode, check if
+ * EA block can hold new_extra_isize bytes.
+ */
+ if (EXT4_I(inode)->i_file_acl) {
+ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ if (!bh)
+ goto cleanup;
+ if (ext4_xattr_check_block(bh)) {
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: bad block %llu", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+ }
+ base = BHDR(bh);
+ first = BFIRST(bh);
+ end = bh->b_data + bh->b_size;
+ min_offs = end - base;
+ free = ext4_xattr_free_space(first, &min_offs, base,
+ &total_blk);
+ if (free < new_extra_isize) {
+ if (!tried_min_extra_isize && s_min_extra_isize) {
+ tried_min_extra_isize++;
+ new_extra_isize = s_min_extra_isize;
+ brelse(bh);
+ goto retry;
+ }
+ error = -1;
+ goto cleanup;
+ }
+ } else {
+ free = inode->i_sb->s_blocksize;
+ }
+
+ while (new_extra_isize > 0) {
+ size_t offs, size, entry_size;
+ struct ext4_xattr_entry *small_entry = NULL;
+ struct ext4_xattr_info i = {
+ .value = NULL,
+ .value_len = 0,
+ };
+ unsigned int total_size; /* EA entry size + value size */
+ unsigned int shift_bytes; /* No. of bytes to shift EAs by? */
+ unsigned int min_total_size = ~0U;
+
+ is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
+ bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
+ if (!is || !bs) {
+ error = -ENOMEM;
+ goto cleanup;
+ }
+
+ is->s.not_found = -ENODATA;
+ bs->s.not_found = -ENODATA;
+ is->iloc.bh = NULL;
+ bs->bh = NULL;
+
+ last = IFIRST(header);
+ /* Find the entry best suited to be pushed into EA block */
+ entry = NULL;
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ total_size =
+ EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) +
+ EXT4_XATTR_LEN(last->e_name_len);
+ if (total_size <= free && total_size < min_total_size) {
+ if (total_size < new_extra_isize) {
+ small_entry = last;
+ } else {
+ entry = last;
+ min_total_size = total_size;
+ }
+ }
+ }
+
+ if (entry == NULL) {
+ if (small_entry) {
+ entry = small_entry;
+ } else {
+ if (!tried_min_extra_isize &&
+ s_min_extra_isize) {
+ tried_min_extra_isize++;
+ new_extra_isize = s_min_extra_isize;
+ goto retry;
+ }
+ error = -1;
+ goto cleanup;
+ }
+ }
+ offs = le16_to_cpu(entry->e_value_offs);
+ size = le32_to_cpu(entry->e_value_size);
+ entry_size = EXT4_XATTR_LEN(entry->e_name_len);
+ i.name_index = entry->e_name_index,
+ buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
+ b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
+ if (!buffer || !b_entry_name) {
+ error = -ENOMEM;
+ goto cleanup;
+ }
+ /* Save the entry name and the entry value */
+ memcpy(buffer, (void *)IFIRST(header) + offs,
+ EXT4_XATTR_SIZE(size));
+ memcpy(b_entry_name, entry->e_name, entry->e_name_len);
+ b_entry_name[entry->e_name_len] = '\0';
+ i.name = b_entry_name;
+
+ error = ext4_get_inode_loc(inode, &is->iloc);
+ if (error)
+ goto cleanup;
+
+ error = ext4_xattr_ibody_find(inode, &i, is);
+ if (error)
+ goto cleanup;
+
+ /* Remove the chosen entry from the inode */
+ error = ext4_xattr_ibody_set(handle, inode, &i, is);
+
+ entry = IFIRST(header);
+ if (entry_size + EXT4_XATTR_SIZE(size) >= new_extra_isize)
+ shift_bytes = new_extra_isize;
+ else
+ shift_bytes = entry_size + size;
+ /* Adjust the offsets and shift the remaining entries ahead */
+ ext4_xattr_shift_entries(entry, EXT4_I(inode)->i_extra_isize -
+ shift_bytes, (void *)raw_inode +
+ EXT4_GOOD_OLD_INODE_SIZE + extra_isize + shift_bytes,
+ (void *)header, total_ino - entry_size,
+ inode->i_sb->s_blocksize);
+
+ extra_isize += shift_bytes;
+ new_extra_isize -= shift_bytes;
+ EXT4_I(inode)->i_extra_isize = extra_isize;
+
+ i.name = b_entry_name;
+ i.value = buffer;
+ i.value_len = cpu_to_le32(size);
+ error = ext4_xattr_block_find(inode, &i, bs);
+ if (error)
+ goto cleanup;
+
+ /* Add entry which was removed from the inode into the block */
+ error = ext4_xattr_block_set(handle, inode, &i, bs);
+ if (error)
+ goto cleanup;
+ kfree(b_entry_name);
+ kfree(buffer);
+ brelse(is->iloc.bh);
+ kfree(is);
+ kfree(bs);
+ }
+ brelse(bh);
+ up_write(&EXT4_I(inode)->xattr_sem);
+ return 0;
+
+cleanup:
+ kfree(b_entry_name);
+ kfree(buffer);
+ if (is)
+ brelse(is->iloc.bh);
+ kfree(is);
+ kfree(bs);
+ brelse(bh);
+ up_write(&EXT4_I(inode)->xattr_sem);
+ return error;
+}
+
+
+
+/*
* ext4_xattr_delete_inode()
*
* Free extended attribute resources associated with this inode. This
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 79432b35398f..d7f5d6a12651 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -56,6 +56,13 @@ struct ext4_xattr_entry {
#define EXT4_XATTR_SIZE(size) \
(((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
+#define IHDR(inode, raw_inode) \
+ ((struct ext4_xattr_ibody_header *) \
+ ((void *)raw_inode + \
+ EXT4_GOOD_OLD_INODE_SIZE + \
+ EXT4_I(inode)->i_extra_isize))
+#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
+
# ifdef CONFIG_EXT4DEV_FS_XATTR
extern struct xattr_handler ext4_xattr_user_handler;
@@ -74,6 +81,9 @@ extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *,
extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
extern void ext4_xattr_put_super(struct super_block *);
+extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+ struct ext4_inode *raw_inode, handle_t *handle);
+
extern int init_ext4_xattr(void);
extern void exit_ext4_xattr(void);
@@ -129,6 +139,13 @@ exit_ext4_xattr(void)
{
}
+static inline int
+ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
+ struct ext4_inode *raw_inode, handle_t *handle)
+{
+ return -EOPNOTSUPP;
+}
+
#define ext4_xattr_handlers NULL
# endif /* CONFIG_EXT4DEV_FS_XATTR */
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 3c9c8a15ec73..be6f89b152ca 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -48,7 +48,7 @@ int __init fat_cache_init(void)
fat_cache_cachep = kmem_cache_create("fat_cache",
sizeof(struct fat_cache),
0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- init_once, NULL);
+ init_once);
if (fat_cache_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index ccf161dffb63..72cbcd61bd95 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -313,7 +313,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name,
wchar_t bufuname[14];
unsigned char xlate_len, nr_slots;
wchar_t *unicode = NULL;
- unsigned char work[8], bufname[260]; /* 256 + 4 */
+ unsigned char work[MSDOS_NAME], bufname[260]; /* 256 + 4 */
int uni_xlate = sbi->options.unicode_xlate;
int utf8 = sbi->options.utf8;
int anycase = (sbi->options.name_check != 's');
@@ -351,7 +351,8 @@ parse_record:
if (work[0] == 0x05)
work[0] = 0xE5;
for (i = 0, j = 0, last_u = 0; i < 8;) {
- if (!work[i]) break;
+ if (!work[i])
+ break;
chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_BASE);
@@ -365,13 +366,15 @@ parse_record:
}
j = last_u;
fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
- for (i = 0; i < 3;) {
- if (!de->ext[i]) break;
- chl = fat_shortname2uni(nls_disk, &de->ext[i], 3 - i,
+ for (i = 8; i < MSDOS_NAME;) {
+ if (!work[i])
+ break;
+ chl = fat_shortname2uni(nls_disk, &work[i],
+ MSDOS_NAME - i,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_EXT);
if (chl <= 1) {
- if (de->ext[i] != ' ')
+ if (work[i] != ' ')
last_u = j;
} else {
last_u = j;
@@ -445,7 +448,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,
int fill_len;
wchar_t bufuname[14];
wchar_t *unicode = NULL;
- unsigned char c, work[8], bufname[56], *ptname = bufname;
+ unsigned char c, work[MSDOS_NAME], bufname[56], *ptname = bufname;
unsigned long lpos, dummy, *furrfu = &lpos;
int uni_xlate = sbi->options.unicode_xlate;
int isvfat = sbi->options.isvfat;
@@ -527,7 +530,8 @@ parse_record:
if (work[0] == 0x05)
work[0] = 0xE5;
for (i = 0, j = 0, last = 0, last_u = 0; i < 8;) {
- if (!(c = work[i])) break;
+ if (!(c = work[i]))
+ break;
chl = fat_shortname2uni(nls_disk, &work[i], 8 - i,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_BASE);
@@ -549,9 +553,10 @@ parse_record:
j = last_u;
fat_short2uni(nls_disk, ".", 1, &bufuname[j++]);
ptname[i++] = '.';
- for (i2 = 0; i2 < 3;) {
- if (!(c = de->ext[i2])) break;
- chl = fat_shortname2uni(nls_disk, &de->ext[i2], 3 - i2,
+ for (i2 = 8; i2 < MSDOS_NAME;) {
+ if (!(c = work[i2]))
+ break;
+ chl = fat_shortname2uni(nls_disk, &work[i2], MSDOS_NAME - i2,
&bufuname[j++], opt_shortname,
de->lcase & CASE_LOWER_EXT);
if (chl <= 1) {
@@ -563,8 +568,8 @@ parse_record:
}
} else {
last_u = j;
- for (chi = 0; chi < chl && i2 < 3; chi++) {
- ptname[i++] = de->ext[i2++];
+ for (chi = 0; chi < chl && i2 < MSDOS_NAME; chi++) {
+ ptname[i++] = work[i2++];
last = i;
}
}
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index ab171ea8e869..2c1b73fb82ae 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -17,6 +17,8 @@ struct fatent_operations {
int (*ent_next)(struct fat_entry *);
};
+static DEFINE_SPINLOCK(fat12_entry_lock);
+
static void fat12_ent_blocknr(struct super_block *sb, int entry,
int *offset, sector_t *blocknr)
{
@@ -116,10 +118,13 @@ static int fat12_ent_get(struct fat_entry *fatent)
u8 **ent12_p = fatent->u.ent12_p;
int next;
+ spin_lock(&fat12_entry_lock);
if (fatent->entry & 1)
next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4);
else
next = (*ent12_p[1] << 8) | *ent12_p[0];
+ spin_unlock(&fat12_entry_lock);
+
next &= 0x0fff;
if (next >= BAD_FAT12)
next = FAT_ENT_EOF;
@@ -151,6 +156,7 @@ static void fat12_ent_put(struct fat_entry *fatent, int new)
if (new == FAT_ENT_EOF)
new = EOF_FAT12;
+ spin_lock(&fat12_entry_lock);
if (fatent->entry & 1) {
*ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f);
*ent12_p[1] = new >> 4;
@@ -158,6 +164,7 @@ static void fat12_ent_put(struct fat_entry *fatent, int new)
*ent12_p[0] = new & 0xff;
*ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8);
}
+ spin_unlock(&fat12_entry_lock);
mark_buffer_dirty(fatent->bhs[0]);
if (fatent->nr_bhs == 2)
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 479722d89667..4baa5f205368 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -20,6 +20,7 @@
#include <linux/pagemap.h>
#include <linux/mpage.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <linux/mount.h>
#include <linux/vfs.h>
#include <linux/parser.h>
@@ -354,8 +355,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
} else { /* not a directory */
inode->i_generation |= 1;
inode->i_mode = MSDOS_MKMODE(de->attr,
- ((sbi->options.showexec &&
- !is_exec(de->ext))
+ ((sbi->options.showexec && !is_exec(de->name + 8))
? S_IRUGO|S_IWUGO : S_IRWXUGO)
& ~sbi->options.fs_fmask) | S_IFREG;
MSDOS_I(inode)->i_start = le16_to_cpu(de->start);
@@ -514,7 +514,7 @@ static int __init fat_init_inodecache(void)
sizeof(struct msdos_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (fat_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 8e382a5d51bd..78b2ff044054 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -215,7 +215,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
/* O_NOATIME can only be set by the owner or superuser */
if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME))
- if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
/* required for strict SunOS emulation */
@@ -638,7 +638,7 @@ EXPORT_SYMBOL(kill_fasync);
static int __init fasync_init(void)
{
fasync_cache = kmem_cache_create("fasync_cache",
- sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL, NULL);
+ sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL);
return 0;
}
diff --git a/fs/freevxfs/vxfs_dir.h b/fs/freevxfs/vxfs_dir.h
index 8a4dfef1ddad..3c96d6e63978 100644
--- a/fs/freevxfs/vxfs_dir.h
+++ b/fs/freevxfs/vxfs_dir.h
@@ -80,7 +80,7 @@ struct vxfs_direct {
* a d_name with size len.
*/
#define VXFS_DIRPAD 4
-#define VXFS_NAMEMIN ((int)((struct vxfs_direct *)0)->d_name)
+#define VXFS_NAMEMIN offsetof(struct vxfs_direct, d_name)
#define VXFS_DIRROUND(len) ((VXFS_DIRPAD + (len) - 1) & ~(VXFS_DIRPAD -1))
#define VXFS_DIRLEN(len) (VXFS_DIRROUND(VXFS_NAMEMIN + (len)))
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 647d600f0bc8..4f95572d2722 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -263,8 +263,8 @@ vxfs_init(void)
int rv;
vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
- sizeof(struct vxfs_inode_info), 0,
- SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
+ sizeof(struct vxfs_inode_info), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
if (!vxfs_inode_cachep)
return -ENOMEM;
rv = register_filesystem(&vxfs_fs_type);
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 357764d85ff1..3ad22beb24c2 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1044,7 +1044,7 @@ int __init fuse_dev_init(void)
int err = -ENOMEM;
fuse_req_cachep = kmem_cache_create("fuse_request",
sizeof(struct fuse_req),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!fuse_req_cachep)
goto out;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index cc5efc13496a..5448f625ab56 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -706,7 +706,7 @@ static int __init fuse_fs_init(void)
fuse_inode_cachep = kmem_cache_create("fuse_inode",
sizeof(struct fuse_inode),
0, SLAB_HWCACHE_ALIGN,
- fuse_inode_init_once, NULL);
+ fuse_inode_init_once);
err = -ENOMEM;
if (!fuse_inode_cachep)
goto out_unreg2;
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
index 9ccb78947171..995d63b2e747 100644
--- a/fs/generic_acl.c
+++ b/fs/generic_acl.c
@@ -78,7 +78,7 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
- if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (value) {
acl = posix_acl_from_xattr(value, size);
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 6e80844367ee..1047a8c7226a 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -74,7 +74,7 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
{
if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
return -EOPNOTSUPP;
- if (current->fsuid != ip->i_inode.i_uid && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(&ip->i_inode))
return -EPERM;
if (S_ISLNK(ip->i_inode.i_mode))
return -EOPNOTSUPP;
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
index c1f44009853f..1ab3e9d73886 100644
--- a/fs/gfs2/eaops.c
+++ b/fs/gfs2/eaops.c
@@ -11,6 +11,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
+#include <linux/capability.h>
#include <linux/xattr.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 787a0edef100..d5d4e68b8807 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -72,7 +72,7 @@ static int __init init_gfs2_fs(void)
gfs2_glock_cachep = kmem_cache_create("gfs2_glock",
sizeof(struct gfs2_glock),
0, 0,
- gfs2_init_glock_once, NULL);
+ gfs2_init_glock_once);
if (!gfs2_glock_cachep)
goto fail;
@@ -80,13 +80,13 @@ static int __init init_gfs2_fs(void)
sizeof(struct gfs2_inode),
0, SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD,
- gfs2_init_inode_once, NULL);
+ gfs2_init_inode_once);
if (!gfs2_inode_cachep)
goto fail;
gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata",
sizeof(struct gfs2_bufdata),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!gfs2_bufdata_cachep)
goto fail;
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
index 26c888890c24..ce90032c010e 100644
--- a/fs/gfs2/ops_address.c
+++ b/fs/gfs2/ops_address.c
@@ -251,7 +251,7 @@ static int gfs2_readpage(struct file *file, struct page *page)
if (file) {
gf = file->private_data;
if (test_bit(GFF_EXLOCK, &gf->f_flags))
- /* gfs2_sharewrite_nopage has grabbed the ip->i_gl already */
+ /* gfs2_sharewrite_fault has grabbed the ip->i_gl already */
goto skip_lock;
}
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
index 99ea5659bc2c..b8312edee0e4 100644
--- a/fs/gfs2/ops_export.c
+++ b/fs/gfs2/ops_export.c
@@ -11,6 +11,7 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <linux/gfs2_ondisk.h>
#include <linux/crc32.h>
#include <linux/lm_interface.h>
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
index 196d83266e34..1a5e8e893d75 100644
--- a/fs/gfs2/ops_file.c
+++ b/fs/gfs2/ops_file.c
@@ -489,6 +489,29 @@ static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
}
/**
+ * gfs2_setlease - acquire/release a file lease
+ * @file: the file pointer
+ * @arg: lease type
+ * @fl: file lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_setlease(struct file *file, long arg, struct file_lock **fl)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
+
+ /*
+ * We don't currently have a way to enforce a lease across the whole
+ * cluster; until we do, disable leases (by just returning -EINVAL),
+ * unless the administrator has requested purely local locking.
+ */
+ if (!sdp->sd_args.ar_localflocks)
+ return -EINVAL;
+ return setlease(file, arg, fl);
+}
+
+/**
* gfs2_lock - acquire/release a posix lock on a file
* @file: the file pointer
* @cmd: either modify or retrieve lock state, possibly wait
@@ -638,6 +661,7 @@ const struct file_operations gfs2_file_fops = {
.flock = gfs2_flock,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
+ .setlease = gfs2_setlease,
};
const struct file_operations gfs2_dir_fops = {
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
index 404b7cc9f8c4..927d739d4685 100644
--- a/fs/gfs2/ops_vm.c
+++ b/fs/gfs2/ops_vm.c
@@ -27,13 +27,12 @@
#include "trans.h"
#include "util.h"
-static struct page *gfs2_private_nopage(struct vm_area_struct *area,
- unsigned long address, int *type)
+static int gfs2_private_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
- struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
+ struct gfs2_inode *ip = GFS2_I(vma->vm_file->f_mapping->host);
set_bit(GIF_PAGED, &ip->i_flags);
- return filemap_nopage(area, address, type);
+ return filemap_fault(vma, vmf);
}
static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
@@ -104,58 +103,67 @@ out:
return error;
}
-static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
- unsigned long address, int *type)
+static int gfs2_sharewrite_fault(struct vm_area_struct *vma,
+ struct vm_fault *vmf)
{
- struct file *file = area->vm_file;
+ struct file *file = vma->vm_file;
struct gfs2_file *gf = file->private_data;
struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
struct gfs2_holder i_gh;
- struct page *result = NULL;
- unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) +
- area->vm_pgoff;
int alloc_required;
int error;
+ int ret = 0;
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
if (error)
- return NULL;
+ goto out;
set_bit(GIF_PAGED, &ip->i_flags);
set_bit(GIF_SW_PAGED, &ip->i_flags);
- error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT,
- PAGE_CACHE_SIZE, &alloc_required);
- if (error)
- goto out;
+ error = gfs2_write_alloc_required(ip,
+ (u64)vmf->pgoff << PAGE_CACHE_SHIFT,
+ PAGE_CACHE_SIZE, &alloc_required);
+ if (error) {
+ ret = VM_FAULT_OOM; /* XXX: are these right? */
+ goto out_unlock;
+ }
set_bit(GFF_EXLOCK, &gf->f_flags);
- result = filemap_nopage(area, address, type);
+ ret = filemap_fault(vma, vmf);
clear_bit(GFF_EXLOCK, &gf->f_flags);
- if (!result || result == NOPAGE_OOM)
- goto out;
+ if (ret & VM_FAULT_ERROR)
+ goto out_unlock;
if (alloc_required) {
- error = alloc_page_backing(ip, result);
+ /* XXX: do we need to drop page lock around alloc_page_backing?*/
+ error = alloc_page_backing(ip, vmf->page);
if (error) {
- page_cache_release(result);
- result = NULL;
- goto out;
+ /*
+ * VM_FAULT_LOCKED should always be the case for
+ * filemap_fault, but it may not be in a future
+ * implementation.
+ */
+ if (ret & VM_FAULT_LOCKED)
+ unlock_page(vmf->page);
+ page_cache_release(vmf->page);
+ ret = VM_FAULT_OOM;
+ goto out_unlock;
}
- set_page_dirty(result);
+ set_page_dirty(vmf->page);
}
-out:
+out_unlock:
gfs2_glock_dq_uninit(&i_gh);
-
- return result;
+out:
+ return ret;
}
struct vm_operations_struct gfs2_vm_ops_private = {
- .nopage = gfs2_private_nopage,
+ .fault = gfs2_private_fault,
};
struct vm_operations_struct gfs2_vm_ops_sharewrite = {
- .nopage = gfs2_sharewrite_nopage,
+ .fault = gfs2_sharewrite_fault,
};
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 92cf8751e428..6c5f92dfb500 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -443,7 +443,7 @@ static int __init init_hfs_fs(void)
hfs_inode_cachep = kmem_cache_create("hfs_inode_cache",
sizeof(struct hfs_inode_info), 0, SLAB_HWCACHE_ALIGN,
- hfs_init_once, NULL);
+ hfs_init_once);
if (!hfs_inode_cachep)
return -ENOMEM;
err = register_filesystem(&hfs_fs_type);
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index 90ebab753d30..050d29c0a5b5 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -62,8 +62,10 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) &&
(head->key_type == HFSPLUS_KEY_BINARY))
tree->keycmp = hfsplus_cat_bin_cmp_key;
- else
+ else {
tree->keycmp = hfsplus_cat_case_cmp_key;
+ HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD;
+ }
} else {
printk(KERN_ERR "hfs: unknown B*Tree requested\n");
goto fail_page;
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 80b5682a2273..1955ee61251c 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -36,6 +36,8 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
u16 type;
sb = dir->i_sb;
+
+ dentry->d_op = &hfsplus_dentry_operations;
dentry->d_fsdata = NULL;
hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 3915635b4470..d9f5eda6d039 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -150,6 +150,7 @@ struct hfsplus_sb_info {
#define HFSPLUS_SB_NODECOMPOSE 0x0002
#define HFSPLUS_SB_FORCE 0x0004
#define HFSPLUS_SB_HFSX 0x0008
+#define HFSPLUS_SB_CASEFOLD 0x0010
struct hfsplus_inode_info {
@@ -321,6 +322,7 @@ void hfsplus_file_truncate(struct inode *);
/* inode.c */
extern const struct address_space_operations hfsplus_aops;
extern const struct address_space_operations hfsplus_btree_aops;
+extern struct dentry_operations hfsplus_dentry_operations;
void hfsplus_inode_read_fork(struct inode *, struct hfsplus_fork_raw *);
void hfsplus_inode_write_fork(struct inode *, struct hfsplus_fork_raw *);
@@ -353,6 +355,8 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unist
int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *);
int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *);
int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int);
+int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str);
+int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2);
/* wrapper.c */
int hfsplus_read_wrapper(struct super_block *);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 409ce5429c91..6f7c662174db 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -131,6 +131,11 @@ const struct address_space_operations hfsplus_aops = {
.writepages = hfsplus_writepages,
};
+struct dentry_operations hfsplus_dentry_operations = {
+ .d_hash = hfsplus_hash_dentry,
+ .d_compare = hfsplus_compare_dentry,
+};
+
static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index 79fd10402ea3..b60c0affbec5 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -38,7 +38,7 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EACCES;
if (get_user(flags, (int __user *)arg))
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index ebd1b380cbbc..7b0f2e5a44e2 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -283,11 +283,10 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
struct nls_table *nls = NULL;
int err = -EINVAL;
- sbi = kmalloc(sizeof(struct hfsplus_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
- memset(sbi, 0, sizeof(HFSPLUS_SB(sb)));
sb->s_fs_info = sbi;
INIT_HLIST_HEAD(&sbi->rsrc_inodes);
hfsplus_fill_defaults(sbi);
@@ -381,6 +380,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
iput(root);
goto cleanup;
}
+ sb->s_root->d_op = &hfsplus_dentry_operations;
str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
str.name = HFSP_HIDDENDIR_NAME;
@@ -479,7 +479,7 @@ static int __init init_hfsplus_fs(void)
hfsplus_inode_cachep = kmem_cache_create("hfsplus_icache",
HFSPLUS_INODE_SIZE, 0, SLAB_HWCACHE_ALIGN,
- hfsplus_init_once, NULL);
+ hfsplus_init_once);
if (!hfsplus_inode_cachep)
return -ENOMEM;
err = register_filesystem(&hfsplus_fs_type);
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c
index 689c8bd721fb..9e10f9444b64 100644
--- a/fs/hfsplus/unicode.c
+++ b/fs/hfsplus/unicode.c
@@ -239,61 +239,201 @@ out:
return res;
}
-int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, const char *astr, int len)
+/*
+ * Convert one or more ASCII characters into a single unicode character.
+ * Returns the number of ASCII characters corresponding to the unicode char.
+ */
+static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
+ wchar_t *uc)
{
- struct nls_table *nls = HFSPLUS_SB(sb).nls;
- int size, off, decompose;
+ int size = HFSPLUS_SB(sb).nls->char2uni(astr, len, uc);
+ if (size <= 0) {
+ *uc = '?';
+ size = 1;
+ }
+ switch (*uc) {
+ case 0x2400:
+ *uc = 0;
+ break;
+ case ':':
+ *uc = '/';
+ break;
+ }
+ return size;
+}
+
+/* Decomposes a single unicode character. */
+static inline u16 *decompose_unichar(wchar_t uc, int *size)
+{
+ int off;
+
+ off = hfsplus_decompose_table[(uc >> 12) & 0xf];
+ if (off == 0 || off == 0xffff)
+ return NULL;
+
+ off = hfsplus_decompose_table[off + ((uc >> 8) & 0xf)];
+ if (!off)
+ return NULL;
+
+ off = hfsplus_decompose_table[off + ((uc >> 4) & 0xf)];
+ if (!off)
+ return NULL;
+
+ off = hfsplus_decompose_table[off + (uc & 0xf)];
+ *size = off & 3;
+ if (*size == 0)
+ return NULL;
+ return hfsplus_decompose_table + (off / 4);
+}
+
+int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
+ const char *astr, int len)
+{
+ int size, dsize, decompose;
+ u16 *dstr, outlen = 0;
wchar_t c;
- u16 outlen = 0;
decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
-
while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
- size = nls->char2uni(astr, len, &c);
- if (size <= 0) {
- c = '?';
- size = 1;
- }
- astr += size;
- len -= size;
- switch (c) {
- case 0x2400:
- c = 0;
- break;
- case ':':
- c = '/';
- break;
- }
- if (c >= 0xc0 && decompose) {
- off = hfsplus_decompose_table[(c >> 12) & 0xf];
- if (!off)
- goto done;
- if (off == 0xffff) {
- goto done;
- }
- off = hfsplus_decompose_table[off + ((c >> 8) & 0xf)];
- if (!off)
- goto done;
- off = hfsplus_decompose_table[off + ((c >> 4) & 0xf)];
- if (!off)
- goto done;
- off = hfsplus_decompose_table[off + (c & 0xf)];
- size = off & 3;
- if (!size)
- goto done;
- off /= 4;
- if (outlen + size > HFSPLUS_MAX_STRLEN)
+ size = asc2unichar(sb, astr, len, &c);
+
+ if (decompose && (dstr = decompose_unichar(c, &dsize))) {
+ if (outlen + dsize > HFSPLUS_MAX_STRLEN)
break;
do {
- ustr->unicode[outlen++] = cpu_to_be16(hfsplus_decompose_table[off++]);
- } while (--size > 0);
- continue;
- }
- done:
- ustr->unicode[outlen++] = cpu_to_be16(c);
+ ustr->unicode[outlen++] = cpu_to_be16(*dstr++);
+ } while (--dsize > 0);
+ } else
+ ustr->unicode[outlen++] = cpu_to_be16(c);
+
+ astr += size;
+ len -= size;
}
ustr->length = cpu_to_be16(outlen);
if (len > 0)
return -ENAMETOOLONG;
return 0;
}
+
+/*
+ * Hash a string to an integer as appropriate for the HFS+ filesystem.
+ * Composed unicode characters are decomposed and case-folding is performed
+ * if the appropriate bits are (un)set on the superblock.
+ */
+int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
+{
+ struct super_block *sb = dentry->d_sb;
+ const char *astr;
+ const u16 *dstr;
+ int casefold, decompose, size, dsize, len;
+ unsigned long hash;
+ wchar_t c;
+ u16 c2;
+
+ casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
+ decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+ hash = init_name_hash();
+ astr = str->name;
+ len = str->len;
+ while (len > 0) {
+ size = asc2unichar(sb, astr, len, &c);
+ astr += size;
+ len -= size;
+
+ if (decompose && (dstr = decompose_unichar(c, &dsize))) {
+ do {
+ c2 = *dstr++;
+ if (!casefold || (c2 = case_fold(c2)))
+ hash = partial_name_hash(c2, hash);
+ } while (--dsize > 0);
+ } else {
+ c2 = c;
+ if (!casefold || (c2 = case_fold(c2)))
+ hash = partial_name_hash(c2, hash);
+ }
+ }
+ str->hash = end_name_hash(hash);
+
+ return 0;
+}
+
+/*
+ * Compare strings with HFS+ filename ordering.
+ * Composed unicode characters are decomposed and case-folding is performed
+ * if the appropriate bits are (un)set on the superblock.
+ */
+int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2)
+{
+ struct super_block *sb = dentry->d_sb;
+ int casefold, decompose, size;
+ int dsize1, dsize2, len1, len2;
+ const u16 *dstr1, *dstr2;
+ const char *astr1, *astr2;
+ u16 c1, c2;
+ wchar_t c;
+
+ casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
+ decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+ astr1 = s1->name;
+ len1 = s1->len;
+ astr2 = s2->name;
+ len2 = s2->len;
+ dsize1 = dsize2 = 0;
+ dstr1 = dstr2 = NULL;
+
+ while (len1 > 0 && len2 > 0) {
+ if (!dsize1) {
+ size = asc2unichar(sb, astr1, len1, &c);
+ astr1 += size;
+ len1 -= size;
+
+ if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) {
+ c1 = c;
+ dstr1 = &c1;
+ dsize1 = 1;
+ }
+ }
+
+ if (!dsize2) {
+ size = asc2unichar(sb, astr2, len2, &c);
+ astr2 += size;
+ len2 -= size;
+
+ if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) {
+ c2 = c;
+ dstr2 = &c2;
+ dsize2 = 1;
+ }
+ }
+
+ c1 = *dstr1;
+ c2 = *dstr2;
+ if (casefold) {
+ if (!(c1 = case_fold(c1))) {
+ dstr1++;
+ dsize1--;
+ continue;
+ }
+ if (!(c2 = case_fold(c2))) {
+ dstr2++;
+ dsize2--;
+ continue;
+ }
+ }
+ if (c1 < c2)
+ return -1;
+ else if (c1 > c2)
+ return 1;
+
+ dstr1++;
+ dsize1--;
+ dstr2++;
+ dsize2--;
+ }
+
+ if (len1 < len2)
+ return -1;
+ if (len1 > len2)
+ return 1;
+ return 0;
+}
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 29cc34abb2ea..89612ee7c80d 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -181,14 +181,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
mutex_init(&ei->i_parent_mutex);
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache",
sizeof(struct hpfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (hpfs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index e6b46b3ac2fe..c848a191525d 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -13,15 +13,18 @@
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/file.h>
+#include <linux/kernel.h>
#include <linux/writeback.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/capability.h>
+#include <linux/ctype.h>
#include <linux/backing-dev.h>
#include <linux/hugetlb.h>
#include <linux/pagevec.h>
+#include <linux/parser.h>
#include <linux/mman.h>
#include <linux/quotaops.h>
#include <linux/slab.h>
@@ -47,6 +50,21 @@ static struct backing_dev_info hugetlbfs_backing_dev_info = {
int sysctl_hugetlb_shm_group;
+enum {
+ Opt_size, Opt_nr_inodes,
+ Opt_mode, Opt_uid, Opt_gid,
+ Opt_err,
+};
+
+static match_table_t tokens = {
+ {Opt_size, "size=%s"},
+ {Opt_nr_inodes, "nr_inodes=%s"},
+ {Opt_mode, "mode=%o"},
+ {Opt_uid, "uid=%u"},
+ {Opt_gid, "gid=%u"},
+ {Opt_err, NULL},
+};
+
static void huge_pagevec_release(struct pagevec *pvec)
{
int i;
@@ -594,46 +612,73 @@ static const struct super_operations hugetlbfs_ops = {
static int
hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig)
{
- char *opt, *value, *rest;
+ char *p, *rest;
+ substring_t args[MAX_OPT_ARGS];
+ int option;
if (!options)
return 0;
- while ((opt = strsep(&options, ",")) != NULL) {
- if (!*opt)
+
+ while ((p = strsep(&options, ",")) != NULL) {
+ int token;
+ if (!*p)
continue;
- value = strchr(opt, '=');
- if (!value || !*value)
- return -EINVAL;
- else
- *value++ = '\0';
-
- if (!strcmp(opt, "uid"))
- pconfig->uid = simple_strtoul(value, &value, 0);
- else if (!strcmp(opt, "gid"))
- pconfig->gid = simple_strtoul(value, &value, 0);
- else if (!strcmp(opt, "mode"))
- pconfig->mode = simple_strtoul(value,&value,0) & 0777U;
- else if (!strcmp(opt, "size")) {
- unsigned long long size = memparse(value, &rest);
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_uid:
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ pconfig->uid = option;
+ break;
+
+ case Opt_gid:
+ if (match_int(&args[0], &option))
+ goto bad_val;
+ pconfig->gid = option;
+ break;
+
+ case Opt_mode:
+ if (match_octal(&args[0], &option))
+ goto bad_val;
+ pconfig->mode = option & 0777U;
+ break;
+
+ case Opt_size: {
+ unsigned long long size;
+ /* memparse() will accept a K/M/G without a digit */
+ if (!isdigit(*args[0].from))
+ goto bad_val;
+ size = memparse(args[0].from, &rest);
if (*rest == '%') {
size <<= HPAGE_SHIFT;
size *= max_huge_pages;
do_div(size, 100);
- rest++;
}
pconfig->nr_blocks = (size >> HPAGE_SHIFT);
- value = rest;
- } else if (!strcmp(opt,"nr_inodes")) {
- pconfig->nr_inodes = memparse(value, &rest);
- value = rest;
- } else
- return -EINVAL;
+ break;
+ }
+
+ case Opt_nr_inodes:
+ /* memparse() will accept a K/M/G without a digit */
+ if (!isdigit(*args[0].from))
+ goto bad_val;
+ pconfig->nr_inodes = memparse(args[0].from, &rest);
+ break;
- if (*value)
+ default:
+ printk(KERN_ERR "hugetlbfs: Bad mount option: \"%s\"\n",
+ p);
return -EINVAL;
+ break;
+ }
}
return 0;
+
+bad_val:
+ printk(KERN_ERR "hugetlbfs: Bad value '%s' for mount option '%s'\n",
+ args[0].from, p);
+ return 1;
}
static int
@@ -651,7 +696,6 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent)
config.gid = current->fsgid;
config.mode = 0755;
ret = hugetlbfs_parse_options(data, &config);
-
if (ret)
return ret;
@@ -804,7 +848,7 @@ static int __init init_hugetlbfs_fs(void)
hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache",
sizeof(struct hugetlbfs_inode_info),
- 0, 0, init_once, NULL);
+ 0, 0, init_once);
if (hugetlbfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/inode.c b/fs/inode.c
index 9a012cc5b6cd..29f5068f819b 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -145,7 +145,7 @@ static struct inode *alloc_inode(struct super_block *sb)
mapping->a_ops = &empty_aops;
mapping->host = inode;
mapping->flags = 0;
- mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
+ mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE);
mapping->assoc_mapping = NULL;
mapping->backing_dev_info = &default_backing_dev_info;
@@ -462,6 +462,11 @@ static int shrink_icache_memory(int nr, gfp_t gfp_mask)
return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
}
+static struct shrinker icache_shrinker = {
+ .shrink = shrink_icache_memory,
+ .seeks = DEFAULT_SEEKS,
+};
+
static void __wait_on_freeing_inode(struct inode *inode);
/*
* Called with the inode lock held.
@@ -519,7 +524,13 @@ repeat:
* new_inode - obtain an inode
* @sb: superblock
*
- * Allocates a new inode for given superblock.
+ * Allocates a new inode for given superblock. The default gfp_mask
+ * for allocations related to inode->i_mapping is GFP_HIGHUSER_PAGECACHE.
+ * If HIGHMEM pages are unsuitable or it is known that pages allocated
+ * for the page cache are not reclaimable or migratable,
+ * mapping_set_gfp_mask() must be called with suitable flags on the
+ * newly created inode's mapping
+ *
*/
struct inode *new_inode(struct super_block *sb)
{
@@ -1377,9 +1388,8 @@ void __init inode_init(unsigned long mempages)
0,
(SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|
SLAB_MEM_SPREAD),
- init_once,
- NULL);
- set_shrinker(DEFAULT_SEEKS, shrink_icache_memory);
+ init_once);
+ register_shrinker(&icache_shrinker);
/* Hash may have been set up in inode_init_early */
if (!hashdist)
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 9f2224f65a18..9bf2f6c09df6 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -716,10 +716,10 @@ static int __init inotify_user_setup(void)
watch_cachep = kmem_cache_create("inotify_watch_cache",
sizeof(struct inotify_user_watch),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
event_cachep = kmem_cache_create("inotify_event_cache",
sizeof(struct inotify_kernel_event),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
return 0;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 8c90cbc903fa..c2a773e8620b 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -12,7 +12,6 @@
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/module.h>
-#include <linux/kallsyms.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
@@ -21,7 +20,6 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int error = -ENOTTY;
- void *f;
if (!filp->f_op)
goto out;
@@ -31,16 +29,10 @@ static long do_ioctl(struct file *filp, unsigned int cmd,
if (error == -ENOIOCTLCMD)
error = -EINVAL;
goto out;
- } else if ((f = filp->f_op->ioctl)) {
+ } else if (filp->f_op->ioctl) {
lock_kernel();
- if (!filp->f_op->ioctl) {
- printk("%s: ioctl %p disappeared\n", __FUNCTION__, f);
- print_symbol("symbol: %s\n", (unsigned long)f);
- dump_stack();
- } else {
- error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
- filp, cmd, arg);
- }
+ error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,
+ filp, cmd, arg);
unlock_kernel();
}
@@ -182,11 +174,3 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
out:
return error;
}
-
-/*
- * Platforms implementing 32 bit compatibility ioctl handlers in
- * modules need this exported
- */
-#ifdef CONFIG_COMPAT
-EXPORT_SYMBOL(sys_ioctl);
-#endif
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 0e94c31cad9b..1ba407c64df1 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -7,34 +7,18 @@
*
* Steve Beynon : Missing last directory entries fixed
* (stephen@askone.demon.co.uk) : 21st June 1996
- *
+ *
* isofs directory handling functions
*/
#include <linux/smp_lock.h>
#include "isofs.h"
-static int isofs_readdir(struct file *, void *, filldir_t);
-
-const struct file_operations isofs_dir_operations =
-{
- .read = generic_read_dir,
- .readdir = isofs_readdir,
-};
-
-/*
- * directories can handle most operations...
- */
-const struct inode_operations isofs_dir_inode_operations =
-{
- .lookup = isofs_lookup,
-};
-
int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
{
char * old = de->name;
int len = de->name_len[0];
int i;
-
+
for (i = 0; i < len; i++) {
unsigned char c = old[i];
if (!c)
@@ -62,22 +46,27 @@ int isofs_name_translate(struct iso_directory_record *de, char *new, struct inod
}
/* Acorn extensions written by Matthew Wilcox <willy@bofh.ai> 1998 */
-int get_acorn_filename(struct iso_directory_record * de,
- char * retname, struct inode * inode)
+int get_acorn_filename(struct iso_directory_record *de,
+ char *retname, struct inode *inode)
{
int std;
- unsigned char * chr;
+ unsigned char *chr;
int retnamlen = isofs_name_translate(de, retname, inode);
- if (retnamlen == 0) return 0;
+
+ if (retnamlen == 0)
+ return 0;
std = sizeof(struct iso_directory_record) + de->name_len[0];
- if (std & 1) std++;
- if ((*((unsigned char *) de) - std) != 32) return retnamlen;
+ if (std & 1)
+ std++;
+ if ((*((unsigned char *) de) - std) != 32)
+ return retnamlen;
chr = ((unsigned char *) de) + std;
- if (strncmp(chr, "ARCHIMEDES", 10)) return retnamlen;
- if ((*retname == '_') && ((chr[19] & 1) == 1)) *retname = '!';
+ if (strncmp(chr, "ARCHIMEDES", 10))
+ return retnamlen;
+ if ((*retname == '_') && ((chr[19] & 1) == 1))
+ *retname = '!';
if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
- && ((chr[12] & 0xf0) == 0xf0))
- {
+ && ((chr[12] & 0xf0) == 0xf0)) {
retname[retnamlen] = ',';
sprintf(retname+retnamlen+1, "%3.3x",
((chr[12] & 0xf) << 8) | chr[11]);
@@ -91,7 +80,7 @@ int get_acorn_filename(struct iso_directory_record * de,
*/
static int do_isofs_readdir(struct inode *inode, struct file *filp,
void *dirent, filldir_t filldir,
- char * tmpname, struct iso_directory_record * tmpde)
+ char *tmpname, struct iso_directory_record *tmpde)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
@@ -121,9 +110,11 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
de_len = *(unsigned char *) de;
- /* If the length byte is zero, we should move on to the next
- CDROM sector. If we are at the end of the directory, we
- kick out of the while loop. */
+ /*
+ * If the length byte is zero, we should move on to the next
+ * CDROM sector. If we are at the end of the directory, we
+ * kick out of the while loop.
+ */
if (de_len == 0) {
brelse(bh);
@@ -157,11 +148,10 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
if (first_de) {
isofs_normalize_block_and_offset(de,
- &block_saved,
- &offset_saved);
+ &block_saved,
+ &offset_saved);
inode_number = isofs_get_ino(block_saved,
- offset_saved,
- bufbits);
+ offset_saved, bufbits);
}
if (de->flags[-sbi->s_high_sierra] & 0x80) {
@@ -199,7 +189,7 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
*/
if ((sbi->s_hide == 'y' &&
(de->flags[-sbi->s_high_sierra] & 1)) ||
- (sbi->s_showassoc =='n' &&
+ (sbi->s_showassoc =='n' &&
(de->flags[-sbi->s_high_sierra] & 4))) {
filp->f_pos += de_len;
continue;
@@ -240,7 +230,8 @@ static int do_isofs_readdir(struct inode *inode, struct file *filp,
continue;
}
- if (bh) brelse(bh);
+ if (bh)
+ brelse(bh);
return 0;
}
@@ -253,8 +244,8 @@ static int isofs_readdir(struct file *filp,
void *dirent, filldir_t filldir)
{
int result;
- char * tmpname;
- struct iso_directory_record * tmpde;
+ char *tmpname;
+ struct iso_directory_record *tmpde;
struct inode *inode = filp->f_path.dentry->d_inode;
tmpname = (char *)__get_free_page(GFP_KERNEL);
@@ -270,3 +261,19 @@ static int isofs_readdir(struct file *filp,
unlock_kernel();
return result;
}
+
+const struct file_operations isofs_dir_operations =
+{
+ .read = generic_read_dir,
+ .readdir = isofs_readdir,
+};
+
+/*
+ * directories can handle most operations...
+ */
+const struct inode_operations isofs_dir_inode_operations =
+{
+ .lookup = isofs_lookup,
+};
+
+
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 5c3eecf7542e..95c72aa81867 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -73,20 +73,20 @@ static void isofs_destroy_inode(struct inode *inode)
kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
}
-static void init_once(void *foo, struct kmem_cache * cachep, unsigned long flags)
+static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
struct iso_inode_info *ei = foo;
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
- sizeof(struct iso_inode_info),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
- init_once, NULL);
+ sizeof(struct iso_inode_info),
+ 0, (SLAB_RECLAIM_ACCOUNT|
+ SLAB_MEM_SPREAD),
+ init_once);
if (isofs_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -150,9 +150,9 @@ struct iso9660_options{
uid_t uid;
char *iocharset;
unsigned char utf8;
- /* LVE */
- s32 session;
- s32 sbsector;
+ /* LVE */
+ s32 session;
+ s32 sbsector;
};
/*
@@ -197,7 +197,7 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
hash = init_name_hash();
while (len--) {
c = tolower(*name++);
- hash = partial_name_hash(tolower(c), hash);
+ hash = partial_name_hash(c, hash);
}
qstr->hash = end_name_hash(hash);
@@ -360,10 +360,12 @@ static int parse_options(char *options, struct iso9660_options *popt)
popt->check = 'u'; /* unset */
popt->nocompress = 0;
popt->blocksize = 1024;
- popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could
- be shared with DOS machines so
- virtually anything could be
- a valid executable. */
+ popt->mode = S_IRUGO | S_IXUGO; /*
+ * r-x for all. The disc could
+ * be shared with DOS machines so
+ * virtually anything could be
+ * a valid executable.
+ */
popt->gid = 0;
popt->uid = 0;
popt->iocharset = NULL;
@@ -503,30 +505,30 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
Te.cdte_format=CDROM_LBA;
i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te);
if (!i) {
- printk(KERN_DEBUG "Session %d start %d type %d\n",
- session, Te.cdte_addr.lba,
- Te.cdte_ctrl&CDROM_DATA_TRACK);
+ printk(KERN_DEBUG "ISOFS: Session %d start %d type %d\n",
+ session, Te.cdte_addr.lba,
+ Te.cdte_ctrl&CDROM_DATA_TRACK);
if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4)
return Te.cdte_addr.lba;
}
-
- printk(KERN_ERR "Invalid session number or type of track\n");
+
+ printk(KERN_ERR "ISOFS: Invalid session number or type of track\n");
}
i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
if (session > 0)
- printk(KERN_ERR "Invalid session number\n");
+ printk(KERN_ERR "ISOFS: Invalid session number\n");
#if 0
- printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+ printk(KERN_DEBUG "isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
if (i==0) {
- printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
- printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+ printk(KERN_DEBUG "isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no");
+ printk(KERN_DEBUG "isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
}
#endif
if (i==0)
#if WE_OBEY_THE_WRITTEN_STANDARDS
- if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
+ if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
#endif
- vol_desc_start=ms_info.addr.lba;
+ vol_desc_start=ms_info.addr.lba;
return vol_desc_start;
}
@@ -538,20 +540,20 @@ static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
*/
static int isofs_fill_super(struct super_block *s, void *data, int silent)
{
- struct buffer_head * bh = NULL, *pri_bh = NULL;
- struct hs_primary_descriptor * h_pri = NULL;
- struct iso_primary_descriptor * pri = NULL;
+ struct buffer_head *bh = NULL, *pri_bh = NULL;
+ struct hs_primary_descriptor *h_pri = NULL;
+ struct iso_primary_descriptor *pri = NULL;
struct iso_supplementary_descriptor *sec = NULL;
- struct iso_directory_record * rootp;
- int joliet_level = 0;
- int iso_blknum, block;
- int orig_zonesize;
- int table;
- unsigned int vol_desc_start;
- unsigned long first_data_zone;
- struct inode * inode;
- struct iso9660_options opt;
- struct isofs_sb_info * sbi;
+ struct iso_directory_record *rootp;
+ struct inode *inode;
+ struct iso9660_options opt;
+ struct isofs_sb_info *sbi;
+ unsigned long first_data_zone;
+ int joliet_level = 0;
+ int iso_blknum, block;
+ int orig_zonesize;
+ int table;
+ unsigned int vol_desc_start;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
@@ -577,72 +579,73 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
vol_desc_start = (opt.sbsector != -1) ?
opt.sbsector : isofs_get_last_session(s,opt.session);
- for (iso_blknum = vol_desc_start+16;
- iso_blknum < vol_desc_start+100; iso_blknum++)
- {
- struct hs_volume_descriptor * hdp;
- struct iso_volume_descriptor * vdp;
-
- block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
- if (!(bh = sb_bread(s, block)))
- goto out_no_read;
-
- vdp = (struct iso_volume_descriptor *)bh->b_data;
- hdp = (struct hs_volume_descriptor *)bh->b_data;
-
- /* Due to the overlapping physical location of the descriptors,
- * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
- * proper identification in this case, we first check for ISO.
- */
- if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
- if (isonum_711 (vdp->type) == ISO_VD_END)
- break;
- if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) {
- if (pri == NULL) {
- pri = (struct iso_primary_descriptor *)vdp;
- /* Save the buffer in case we need it ... */
- pri_bh = bh;
- bh = NULL;
- }
- }
+ for (iso_blknum = vol_desc_start+16;
+ iso_blknum < vol_desc_start+100; iso_blknum++) {
+ struct hs_volume_descriptor *hdp;
+ struct iso_volume_descriptor *vdp;
+
+ block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
+ if (!(bh = sb_bread(s, block)))
+ goto out_no_read;
+
+ vdp = (struct iso_volume_descriptor *)bh->b_data;
+ hdp = (struct hs_volume_descriptor *)bh->b_data;
+
+ /*
+ * Due to the overlapping physical location of the descriptors,
+ * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
+ * proper identification in this case, we first check for ISO.
+ */
+ if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
+ if (isonum_711(vdp->type) == ISO_VD_END)
+ break;
+ if (isonum_711(vdp->type) == ISO_VD_PRIMARY) {
+ if (pri == NULL) {
+ pri = (struct iso_primary_descriptor *)vdp;
+ /* Save the buffer in case we need it ... */
+ pri_bh = bh;
+ bh = NULL;
+ }
+ }
#ifdef CONFIG_JOLIET
- else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) {
- sec = (struct iso_supplementary_descriptor *)vdp;
- if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
- if (opt.joliet == 'y') {
- if (sec->escape[2] == 0x40) {
- joliet_level = 1;
- } else if (sec->escape[2] == 0x43) {
- joliet_level = 2;
- } else if (sec->escape[2] == 0x45) {
- joliet_level = 3;
- }
- printk(KERN_DEBUG"ISO 9660 Extensions: Microsoft Joliet Level %d\n",
- joliet_level);
+ else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
+ sec = (struct iso_supplementary_descriptor *)vdp;
+ if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
+ if (opt.joliet == 'y') {
+ if (sec->escape[2] == 0x40)
+ joliet_level = 1;
+ else if (sec->escape[2] == 0x43)
+ joliet_level = 2;
+ else if (sec->escape[2] == 0x45)
+ joliet_level = 3;
+
+ printk(KERN_DEBUG "ISO 9660 Extensions: "
+ "Microsoft Joliet Level %d\n",
+ joliet_level);
+ }
+ goto root_found;
+ } else {
+ /* Unknown supplementary volume descriptor */
+ sec = NULL;
+ }
}
- goto root_found;
- } else {
- /* Unknown supplementary volume descriptor */
- sec = NULL;
- }
- }
#endif
- } else {
- if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
- if (isonum_711 (hdp->type) != ISO_VD_PRIMARY)
- goto out_freebh;
-
- sbi->s_high_sierra = 1;
- opt.rock = 'n';
- h_pri = (struct hs_primary_descriptor *)vdp;
- goto root_found;
+ } else {
+ if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
+ if (isonum_711(hdp->type) != ISO_VD_PRIMARY)
+ goto out_freebh;
+
+ sbi->s_high_sierra = 1;
+ opt.rock = 'n';
+ h_pri = (struct hs_primary_descriptor *)vdp;
+ goto root_found;
+ }
}
- }
- /* Just skip any volume descriptors we don't recognize */
+ /* Just skip any volume descriptors we don't recognize */
- brelse(bh);
- bh = NULL;
+ brelse(bh);
+ bh = NULL;
}
/*
* If we fall through, either no volume descriptor was found,
@@ -657,24 +660,24 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
root_found:
if (joliet_level && (pri == NULL || opt.rock == 'n')) {
- /* This is the case of Joliet with the norock mount flag.
- * A disc with both Joliet and Rock Ridge is handled later
- */
- pri = (struct iso_primary_descriptor *) sec;
+ /* This is the case of Joliet with the norock mount flag.
+ * A disc with both Joliet and Rock Ridge is handled later
+ */
+ pri = (struct iso_primary_descriptor *) sec;
}
if(sbi->s_high_sierra){
- rootp = (struct iso_directory_record *) h_pri->root_directory_record;
- sbi->s_nzones = isonum_733 (h_pri->volume_space_size);
- sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size);
- sbi->s_max_size = isonum_733(h_pri->volume_space_size);
+ rootp = (struct iso_directory_record *) h_pri->root_directory_record;
+ sbi->s_nzones = isonum_733(h_pri->volume_space_size);
+ sbi->s_log_zone_size = isonum_723(h_pri->logical_block_size);
+ sbi->s_max_size = isonum_733(h_pri->volume_space_size);
} else {
- if (!pri)
- goto out_freebh;
- rootp = (struct iso_directory_record *) pri->root_directory_record;
- sbi->s_nzones = isonum_733 (pri->volume_space_size);
- sbi->s_log_zone_size = isonum_723 (pri->logical_block_size);
- sbi->s_max_size = isonum_733(pri->volume_space_size);
+ if (!pri)
+ goto out_freebh;
+ rootp = (struct iso_directory_record *) pri->root_directory_record;
+ sbi->s_nzones = isonum_733(pri->volume_space_size);
+ sbi->s_log_zone_size = isonum_723(pri->logical_block_size);
+ sbi->s_max_size = isonum_733(pri->volume_space_size);
}
sbi->s_ninodes = 0; /* No way to figure this out easily */
@@ -687,42 +690,43 @@ root_found:
* blocks that were 512 bytes (which should only very rarely
* happen.)
*/
- if(orig_zonesize < opt.blocksize)
+ if (orig_zonesize < opt.blocksize)
goto out_bad_size;
/* RDE: convert log zone size to bit shift */
- switch (sbi->s_log_zone_size)
- { case 512: sbi->s_log_zone_size = 9; break;
- case 1024: sbi->s_log_zone_size = 10; break;
- case 2048: sbi->s_log_zone_size = 11; break;
+ switch (sbi->s_log_zone_size) {
+ case 512: sbi->s_log_zone_size = 9; break;
+ case 1024: sbi->s_log_zone_size = 10; break;
+ case 2048: sbi->s_log_zone_size = 11; break;
- default:
+ default:
goto out_bad_zone_size;
- }
+ }
s->s_magic = ISOFS_SUPER_MAGIC;
s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */
- /* The CDROM is read-only, has no nodes (devices) on it, and since
- all of the files appear to be owned by root, we really do not want
- to allow suid. (suid or devices will not show up unless we have
- Rock Ridge extensions) */
+ /*
+ * The CDROM is read-only, has no nodes (devices) on it, and since
+ * all of the files appear to be owned by root, we really do not want
+ * to allow suid. (suid or devices will not show up unless we have
+ * Rock Ridge extensions)
+ */
s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
/* Set this for reference. Its not currently used except on write
which we don't have .. */
-
- first_data_zone = isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length);
+
+ first_data_zone = isonum_733(rootp->extent) +
+ isonum_711(rootp->ext_attr_length);
sbi->s_firstdatazone = first_data_zone;
#ifndef BEQUIET
- printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
- sbi->s_max_size,
- 1UL << sbi->s_log_zone_size);
- printk(KERN_DEBUG "First datazone:%ld\n", sbi->s_firstdatazone);
+ printk(KERN_DEBUG "ISOFS: Max size:%ld Log zone size:%ld\n",
+ sbi->s_max_size, 1UL << sbi->s_log_zone_size);
+ printk(KERN_DEBUG "ISOFS: First datazone:%ld\n", sbi->s_firstdatazone);
if(sbi->s_high_sierra)
- printk(KERN_DEBUG "Disc in High Sierra format.\n");
+ printk(KERN_DEBUG "ISOFS: Disc in High Sierra format.\n");
#endif
/*
@@ -737,8 +741,8 @@ root_found:
pri = (struct iso_primary_descriptor *) sec;
rootp = (struct iso_directory_record *)
pri->root_directory_record;
- first_data_zone = isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length);
+ first_data_zone = isonum_733(rootp->extent) +
+ isonum_711(rootp->ext_attr_length);
}
/*
@@ -771,7 +775,7 @@ root_found:
#ifdef CONFIG_JOLIET
if (joliet_level && opt.utf8 == 0) {
- char * p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
+ char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
sbi->s_nls_iocharset = load_nls(p);
if (! sbi->s_nls_iocharset) {
/* Fail only if explicit charset specified */
@@ -821,7 +825,7 @@ root_found:
sbi->s_rock = 0;
if (sbi->s_firstdatazone != first_data_zone) {
sbi->s_firstdatazone = first_data_zone;
- printk(KERN_DEBUG
+ printk(KERN_DEBUG
"ISOFS: changing to secondary root\n");
iput(inode);
inode = isofs_iget(s, sbi->s_firstdatazone, 0);
@@ -830,8 +834,10 @@ root_found:
if (opt.check == 'u') {
/* Only Joliet is case insensitive by default */
- if (joliet_level) opt.check = 'r';
- else opt.check = 's';
+ if (joliet_level)
+ opt.check = 'r';
+ else
+ opt.check = 's';
}
sbi->s_joliet_level = joliet_level;
@@ -846,8 +852,10 @@ root_found:
goto out_no_root;
table = 0;
- if (joliet_level) table += 2;
- if (opt.check == 'r') table++;
+ if (joliet_level)
+ table += 2;
+ if (opt.check == 'r')
+ table++;
s->s_root->d_op = &isofs_dentry_ops[table];
kfree(opt.iocharset);
@@ -858,10 +866,10 @@ root_found:
* Display error messages and free resources.
*/
out_bad_root:
- printk(KERN_WARNING "isofs_fill_super: root inode not initialized\n");
+ printk(KERN_WARNING "%s: root inode not initialized\n", __func__);
goto out_iput;
out_no_root:
- printk(KERN_WARNING "isofs_fill_super: get root inode failed\n");
+ printk(KERN_WARNING "%s: get root inode failed\n", __func__);
out_iput:
iput(inode);
#ifdef CONFIG_JOLIET
@@ -870,21 +878,20 @@ out_iput:
#endif
goto out_freesbi;
out_no_read:
- printk(KERN_WARNING "isofs_fill_super: "
- "bread failed, dev=%s, iso_blknum=%d, block=%d\n",
- s->s_id, iso_blknum, block);
+ printk(KERN_WARNING "%s: bread failed, dev=%s, iso_blknum=%d, block=%d\n",
+ __func__, s->s_id, iso_blknum, block);
goto out_freesbi;
out_bad_zone_size:
- printk(KERN_WARNING "Bad logical zone size %ld\n",
+ printk(KERN_WARNING "ISOFS: Bad logical zone size %ld\n",
sbi->s_log_zone_size);
goto out_freebh;
out_bad_size:
- printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n",
+ printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)\n",
orig_zonesize, opt.blocksize);
goto out_freebh;
out_unknown_format:
if (!silent)
- printk(KERN_WARNING "Unable to identify CD-ROM format.\n");
+ printk(KERN_WARNING "ISOFS: Unable to identify CD-ROM format.\n");
out_freebh:
brelse(bh);
@@ -902,7 +909,7 @@ static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
buf->f_type = ISOFS_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = (ISOFS_SB(sb)->s_nzones
- << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
+ << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
buf->f_bfree = 0;
buf->f_bavail = 0;
buf->f_files = ISOFS_SB(sb)->s_ninodes;
@@ -931,20 +938,20 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
rv = 0;
if (iblock < 0 || iblock != iblock_s) {
- printk("isofs_get_blocks: block number too large\n");
+ printk(KERN_DEBUG "%s: block number too large\n", __func__);
goto abort;
}
b_off = iblock;
-
- offset = 0;
- firstext = ei->i_first_extent;
+
+ offset = 0;
+ firstext = ei->i_first_extent;
sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
- nextblk = ei->i_next_section_block;
- nextoff = ei->i_next_section_offset;
- section = 0;
+ nextblk = ei->i_next_section_block;
+ nextoff = ei->i_next_section_offset;
+ section = 0;
- while ( nblocks ) {
+ while (nblocks) {
/* If we are *way* beyond the end of the file, print a message.
* Access beyond the end of the file up to the next page boundary
* is normal, however because of the way the page cache works.
@@ -953,11 +960,11 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
* I/O errors.
*/
if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) {
- printk("isofs_get_blocks: block >= EOF (%ld, %ld)\n",
- iblock, (unsigned long) inode->i_size);
+ printk(KERN_DEBUG "%s: block >= EOF (%ld, %ld)\n",
+ __func__, iblock, (unsigned long) inode->i_size);
goto abort;
}
-
+
/* On the last section, nextblk == 0, section size is likely to
* exceed sect_size by a partial block, and access beyond the
* end of the file will reach beyond the section size, too.
@@ -976,20 +983,21 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
iput(ninode);
if (++section > 100) {
- printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
- printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
- "nextblk=%lu nextoff=%lu\n",
- iblock, firstext, (unsigned) sect_size,
- nextblk, nextoff);
+ printk(KERN_DEBUG "%s: More than 100 file sections ?!?"
+ " aborting...\n", __func__);
+ printk(KERN_DEBUG "%s: block=%ld firstext=%u sect_size=%u "
+ "nextblk=%lu nextoff=%lu\n", __func__,
+ iblock, firstext, (unsigned) sect_size,
+ nextblk, nextoff);
goto abort;
}
}
-
- if ( *bh ) {
+
+ if (*bh) {
map_bh(*bh, inode->i_sb, firstext + b_off - offset);
} else {
*bh = sb_getblk(inode->i_sb, firstext+b_off-offset);
- if ( !*bh )
+ if (!*bh)
goto abort;
}
bh++; /* Next buffer head */
@@ -1010,7 +1018,7 @@ static int isofs_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
if (create) {
- printk("isofs_get_block: Kernel tries to allocate a block\n");
+ printk(KERN_DEBUG "%s: Kernel tries to allocate a block\n", __func__);
return -EROFS;
}
@@ -1070,11 +1078,11 @@ static int isofs_read_level3_size(struct inode *inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
unsigned long block, offset, block_saved, offset_saved;
int i = 0;
int more_entries = 0;
- struct iso_directory_record * tmpde = NULL;
+ struct iso_directory_record *tmpde = NULL;
struct iso_inode_info *ei = ISOFS_I(inode);
inode->i_size = 0;
@@ -1089,7 +1097,7 @@ static int isofs_read_level3_size(struct inode *inode)
offset = ei->i_iget5_offset;
do {
- struct iso_directory_record * de;
+ struct iso_directory_record *de;
unsigned int de_len;
if (!bh) {
@@ -1163,10 +1171,9 @@ out_noread:
return -EIO;
out_toomany:
- printk(KERN_INFO "isofs_read_level3_size: "
- "More than 100 file sections ?!?, aborting...\n"
- "isofs_read_level3_size: inode=%lu\n",
- inode->i_ino);
+ printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...\n"
+ "isofs_read_level3_size: inode=%lu\n",
+ __func__, inode->i_ino);
goto out;
}
@@ -1177,9 +1184,9 @@ static void isofs_read_inode(struct inode *inode)
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned long block;
int high_sierra = sbi->s_high_sierra;
- struct buffer_head * bh = NULL;
- struct iso_directory_record * de;
- struct iso_directory_record * tmpde = NULL;
+ struct buffer_head *bh = NULL;
+ struct iso_directory_record *de;
+ struct iso_directory_record *tmpde = NULL;
unsigned int de_len;
unsigned long offset;
struct iso_inode_info *ei = ISOFS_I(inode);
@@ -1199,7 +1206,7 @@ static void isofs_read_inode(struct inode *inode)
tmpde = kmalloc(de_len, GFP_KERNEL);
if (tmpde == NULL) {
- printk(KERN_INFO "isofs_read_inode: out of memory\n");
+ printk(KERN_INFO "%s: out of memory\n", __func__);
goto fail;
}
memcpy(tmpde, bh->b_data + offset, frag1);
@@ -1212,24 +1219,26 @@ static void isofs_read_inode(struct inode *inode)
}
inode->i_ino = isofs_get_ino(ei->i_iget5_block,
- ei->i_iget5_offset,
- ISOFS_BUFFER_BITS(inode));
+ ei->i_iget5_offset,
+ ISOFS_BUFFER_BITS(inode));
/* Assume it is a normal-format file unless told otherwise */
ei->i_file_format = isofs_file_normal;
if (de->flags[-high_sierra] & 2) {
inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
- inode->i_nlink = 1; /* Set to 1. We know there are 2, but
- the find utility tries to optimize
- if it is 2, and it screws up. It is
- easier to give 1 which tells find to
- do it the hard way. */
+ inode->i_nlink = 1; /*
+ * Set to 1. We know there are 2, but
+ * the find utility tries to optimize
+ * if it is 2, and it screws up. It is
+ * easier to give 1 which tells find to
+ * do it the hard way.
+ */
} else {
- /* Everybody gets to read the file. */
+ /* Everybody gets to read the file. */
inode->i_mode = sbi->s_mode;
inode->i_nlink = 1;
- inode->i_mode |= S_IFREG;
+ inode->i_mode |= S_IFREG;
}
inode->i_uid = sbi->s_uid;
inode->i_gid = sbi->s_gid;
@@ -1239,13 +1248,14 @@ static void isofs_read_inode(struct inode *inode)
ei->i_format_parm[1] = 0;
ei->i_format_parm[2] = 0;
- ei->i_section_size = isonum_733 (de->size);
+ ei->i_section_size = isonum_733(de->size);
if (de->flags[-high_sierra] & 0x80) {
- if(isofs_read_level3_size(inode)) goto fail;
+ if(isofs_read_level3_size(inode))
+ goto fail;
} else {
ei->i_next_section_block = 0;
ei->i_next_section_offset = 0;
- inode->i_size = isonum_733 (de->size);
+ inode->i_size = isonum_733(de->size);
}
/*
@@ -1258,23 +1268,24 @@ static void isofs_read_inode(struct inode *inode)
inode->i_size &= 0x00ffffff;
if (de->interleave[0]) {
- printk("Interleaved files not (yet) supported.\n");
+ printk(KERN_DEBUG "ISOFS: Interleaved files not (yet) supported.\n");
inode->i_size = 0;
}
/* I have no idea what file_unit_size is used for, so
we will flag it for now */
if (de->file_unit_size[0] != 0) {
- printk("File unit size != 0 for ISO file (%ld).\n",
- inode->i_ino);
+ printk(KERN_DEBUG "ISOFS: File unit size != 0 for ISO file (%ld).\n",
+ inode->i_ino);
}
/* I have no idea what other flag bits are used for, so
we will flag it for now */
#ifdef DEBUG
if((de->flags[-high_sierra] & ~2)!= 0){
- printk("Unusual flag settings for ISO file (%ld %x).\n",
- inode->i_ino, de->flags[-high_sierra]);
+ printk(KERN_DEBUG "ISOFS: Unusual flag settings for ISO file "
+ "(%ld %x).\n",
+ inode->i_ino, de->flags[-high_sierra]);
}
#endif
@@ -1285,11 +1296,11 @@ static void isofs_read_inode(struct inode *inode)
inode->i_atime.tv_nsec =
inode->i_ctime.tv_nsec = 0;
- ei->i_first_extent = (isonum_733 (de->extent) +
- isonum_711 (de->ext_attr_length));
+ ei->i_first_extent = (isonum_733(de->extent) +
+ isonum_711(de->ext_attr_length));
/* Set the number of blocks for stat() - should be done before RR */
- inode->i_blocks = (inode->i_size + 511) >> 9;
+ inode->i_blocks = (inode->i_size + 511) >> 9;
/*
* Now test for possible Rock Ridge extensions which will override
@@ -1306,7 +1317,7 @@ static void isofs_read_inode(struct inode *inode)
/* Install the inode operations vector */
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &generic_ro_fops;
- switch ( ei->i_file_format ) {
+ switch (ei->i_file_format) {
#ifdef CONFIG_ZISOFS
case isofs_file_compressed:
inode->i_data.a_ops = &zisofs_aops;
@@ -1350,7 +1361,7 @@ static int isofs_iget5_test(struct inode *ino, void *data)
struct isofs_iget5_callback_data *d =
(struct isofs_iget5_callback_data*)data;
return (i->i_iget5_block == d->block)
- && (i->i_iget5_offset == d->offset);
+ && (i->i_iget5_offset == d->offset);
}
static int isofs_iget5_set(struct inode *ino, void *data)
@@ -1384,7 +1395,7 @@ struct inode *isofs_iget(struct super_block *sb,
hashval = (block << sb->s_blocksize_bits) | offset;
inode = iget5_locked(sb, hashval, &isofs_iget5_test,
- &isofs_iget5_set, &data);
+ &isofs_iget5_set, &data);
if (inode && (inode->i_state & I_NEW)) {
sb->s_op->read_inode(inode);
@@ -1398,7 +1409,7 @@ static int isofs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super,
- mnt);
+ mnt);
}
static struct file_system_type iso9660_fs_type = {
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
index efe2872cd4e3..a07e67b1ea7f 100644
--- a/fs/isofs/isofs.h
+++ b/fs/isofs/isofs.h
@@ -1,5 +1,6 @@
#include <linux/fs.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <linux/iso_fs.h>
#include <asm/unaligned.h>
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
index fb8fe7a9ddc6..92c14b850e9c 100644
--- a/fs/isofs/joliet.c
+++ b/fs/isofs/joliet.c
@@ -80,22 +80,20 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st
if (utf8) {
len = wcsntombs_be(outname, de->name,
- de->name_len[0] >> 1, PAGE_SIZE);
+ de->name_len[0] >> 1, PAGE_SIZE);
} else {
len = uni16_to_x8(outname, (__be16 *) de->name,
- de->name_len[0] >> 1, nls);
+ de->name_len[0] >> 1, nls);
}
- if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
+ if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1'))
len -= 2;
- }
/*
* Windows doesn't like periods at the end of a name,
* so neither do we
*/
- while (len >= 2 && (outname[len-1] == '.')) {
+ while (len >= 2 && (outname[len-1] == '.'))
len--;
- }
return len;
}
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index c04b3a14a3e9..c8c7e5138a01 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -15,7 +15,7 @@
* some sanity tests.
*/
static int
-isofs_cmp(struct dentry * dentry, const char * compare, int dlen)
+isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
{
struct qstr qstr;
@@ -48,24 +48,24 @@ isofs_cmp(struct dentry * dentry, const char * compare, int dlen)
*/
static unsigned long
isofs_find_entry(struct inode *dir, struct dentry *dentry,
- unsigned long *block_rv, unsigned long* offset_rv,
- char * tmpname, struct iso_directory_record * tmpde)
+ unsigned long *block_rv, unsigned long *offset_rv,
+ char *tmpname, struct iso_directory_record *tmpde)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
unsigned long block, f_pos, offset, block_saved, offset_saved;
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
if (!ISOFS_I(dir)->i_first_extent)
return 0;
-
+
f_pos = 0;
offset = 0;
block = 0;
while (f_pos < dir->i_size) {
- struct iso_directory_record * de;
+ struct iso_directory_record *de;
int de_len, match, i, dlen;
char *dpnt;
@@ -114,7 +114,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
if (sbi->s_rock &&
((i = get_rock_ridge_filename(de, tmpname, dir)))) {
- dlen = i; /* possibly -1 */
+ dlen = i; /* possibly -1 */
dpnt = tmpname;
#ifdef CONFIG_JOLIET
} else if (sbi->s_joliet_level) {
@@ -145,8 +145,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
isofs_normalize_block_and_offset(de,
&block_saved,
&offset_saved);
- *block_rv = block_saved;
- *offset_rv = offset_saved;
+ *block_rv = block_saved;
+ *offset_rv = offset_saved;
brelse(bh);
return 1;
}
@@ -155,7 +155,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
return 0;
}
-struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
int found;
unsigned long block, offset;
@@ -170,9 +170,9 @@ struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct n
lock_kernel();
found = isofs_find_entry(dir, dentry,
- &block, &offset,
- page_address(page),
- 1024 + page_address(page));
+ &block, &offset,
+ page_address(page),
+ 1024 + page_address(page));
__free_page(page);
inode = NULL;
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 1facfaff97cb..a003d50edcdb 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -887,7 +887,8 @@ restart_loop:
journal->j_committing_transaction = NULL;
spin_unlock(&journal->j_state_lock);
- if (commit_transaction->t_checkpoint_list == NULL) {
+ if (commit_transaction->t_checkpoint_list == NULL &&
+ commit_transaction->t_checkpoint_io_list == NULL) {
__journal_drop_transaction(journal, commit_transaction);
} else {
if (journal->j_checkpoint_transactions == NULL) {
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 46fe7439fb91..06ab3c10b1b8 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1668,7 +1668,7 @@ static int journal_create_jbd_slab(size_t slab_size)
* boundary.
*/
jbd_slab[i] = kmem_cache_create(jbd_slab_names[i],
- slab_size, slab_size, 0, NULL, NULL);
+ slab_size, slab_size, 0, NULL);
if (!jbd_slab[i]) {
printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
return -ENOMEM;
@@ -1711,8 +1711,7 @@ static int journal_init_journal_head_cache(void)
sizeof(struct journal_head),
0, /* offset */
0, /* flags */
- NULL, /* ctor */
- NULL); /* dtor */
+ NULL); /* ctor */
retval = 0;
if (journal_head_cache == 0) {
retval = -ENOMEM;
@@ -2008,8 +2007,7 @@ static int __init journal_init_handle_cache(void)
sizeof(handle_t),
0, /* offset */
0, /* flags */
- NULL, /* ctor */
- NULL); /* dtor */
+ NULL); /* ctor */
if (jbd_handle_cache == NULL) {
printk(KERN_EMERG "JBD: failed to create handle cache\n");
return -ENOMEM;
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index 824e3b7d4ec1..62e13c8db132 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -68,6 +68,7 @@
#include <linux/list.h>
#include <linux/init.h>
#endif
+#include <linux/log2.h>
static struct kmem_cache *revoke_record_cache;
static struct kmem_cache *revoke_table_cache;
@@ -169,13 +170,13 @@ int __init journal_init_revoke_caches(void)
{
revoke_record_cache = kmem_cache_create("revoke_record",
sizeof(struct jbd_revoke_record_s),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (revoke_record_cache == 0)
return -ENOMEM;
revoke_table_cache = kmem_cache_create("revoke_table",
sizeof(struct jbd_revoke_table_s),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (revoke_table_cache == 0) {
kmem_cache_destroy(revoke_record_cache);
revoke_record_cache = NULL;
@@ -211,7 +212,7 @@ int journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[0];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
@@ -238,7 +239,7 @@ int journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[1];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 2856e1100a5f..c0f59d1b13dc 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -896,7 +896,8 @@ restart_loop:
journal->j_committing_transaction = NULL;
spin_unlock(&journal->j_state_lock);
- if (commit_transaction->t_checkpoint_list == NULL) {
+ if (commit_transaction->t_checkpoint_list == NULL &&
+ commit_transaction->t_checkpoint_io_list == NULL) {
__jbd2_journal_drop_transaction(journal, commit_transaction);
} else {
if (journal->j_checkpoint_transactions == NULL) {
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 78d63b818f0b..f37324aee817 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -35,6 +35,7 @@
#include <linux/kthread.h>
#include <linux/poison.h>
#include <linux/proc_fs.h>
+#include <linux/debugfs.h>
#include <asm/uaccess.h>
#include <asm/page.h>
@@ -528,7 +529,7 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
{
int err = 0;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
spin_lock(&journal->j_state_lock);
if (!tid_geq(journal->j_commit_request, tid)) {
printk(KERN_EMERG
@@ -1679,7 +1680,7 @@ static int jbd2_journal_create_jbd_slab(size_t slab_size)
* boundary.
*/
jbd_slab[i] = kmem_cache_create(jbd_slab_names[i],
- slab_size, slab_size, 0, NULL, NULL);
+ slab_size, slab_size, 0, NULL);
if (!jbd_slab[i]) {
printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
return -ENOMEM;
@@ -1709,7 +1710,7 @@ void jbd2_slab_free(void *ptr, size_t size)
* Journal_head storage management
*/
static struct kmem_cache *jbd2_journal_head_cache;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
static atomic_t nr_journal_heads = ATOMIC_INIT(0);
#endif
@@ -1722,8 +1723,7 @@ static int journal_init_jbd2_journal_head_cache(void)
sizeof(struct journal_head),
0, /* offset */
0, /* flags */
- NULL, /* ctor */
- NULL); /* dtor */
+ NULL); /* ctor */
retval = 0;
if (jbd2_journal_head_cache == 0) {
retval = -ENOMEM;
@@ -1747,7 +1747,7 @@ static struct journal_head *journal_alloc_journal_head(void)
struct journal_head *ret;
static unsigned long last_warning;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
atomic_inc(&nr_journal_heads);
#endif
ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
@@ -1768,7 +1768,7 @@ static struct journal_head *journal_alloc_journal_head(void)
static void journal_free_journal_head(struct journal_head *jh)
{
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
atomic_dec(&nr_journal_heads);
memset(jh, JBD_POISON_FREE, sizeof(*jh));
#endif
@@ -1951,64 +1951,50 @@ void jbd2_journal_put_journal_head(struct journal_head *jh)
}
/*
- * /proc tunables
+ * debugfs tunables
*/
-#if defined(CONFIG_JBD_DEBUG)
-int jbd2_journal_enable_debug;
+#if defined(CONFIG_JBD2_DEBUG)
+u8 jbd2_journal_enable_debug;
EXPORT_SYMBOL(jbd2_journal_enable_debug);
#endif
-#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS)
+#if defined(CONFIG_JBD2_DEBUG) && defined(CONFIG_DEBUG_FS)
-static struct proc_dir_entry *proc_jbd_debug;
+#define JBD2_DEBUG_NAME "jbd2-debug"
-static int read_jbd_debug(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int ret;
+struct dentry *jbd2_debugfs_dir, *jbd2_debug;
- ret = sprintf(page + off, "%d\n", jbd2_journal_enable_debug);
- *eof = 1;
- return ret;
+static void __init jbd2_create_debugfs_entry(void)
+{
+ jbd2_debugfs_dir = debugfs_create_dir("jbd2", NULL);
+ if (jbd2_debugfs_dir)
+ jbd2_debug = debugfs_create_u8(JBD2_DEBUG_NAME, S_IRUGO,
+ jbd2_debugfs_dir,
+ &jbd2_journal_enable_debug);
}
-static int write_jbd_debug(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static void __exit jbd2_remove_debugfs_entry(void)
{
- char buf[32];
-
- if (count > ARRAY_SIZE(buf) - 1)
- count = ARRAY_SIZE(buf) - 1;
- if (copy_from_user(buf, buffer, count))
- return -EFAULT;
- buf[ARRAY_SIZE(buf) - 1] = '\0';
- jbd2_journal_enable_debug = simple_strtoul(buf, NULL, 10);
- return count;
+ if (jbd2_debug)
+ debugfs_remove(jbd2_debug);
+ if (jbd2_debugfs_dir)
+ debugfs_remove(jbd2_debugfs_dir);
}
-#define JBD_PROC_NAME "sys/fs/jbd2-debug"
+#else
-static void __init create_jbd_proc_entry(void)
+static void __init jbd2_create_debugfs_entry(void)
{
- proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL);
- if (proc_jbd_debug) {
- /* Why is this so hard? */
- proc_jbd_debug->read_proc = read_jbd_debug;
- proc_jbd_debug->write_proc = write_jbd_debug;
- }
+ do {
+ } while (0);
}
-static void __exit jbd2_remove_jbd_proc_entry(void)
+static void __exit jbd2_remove_debugfs_entry(void)
{
- if (proc_jbd_debug)
- remove_proc_entry(JBD_PROC_NAME, NULL);
+ do {
+ } while (0);
}
-#else
-
-#define create_jbd_proc_entry() do {} while (0)
-#define jbd2_remove_jbd_proc_entry() do {} while (0)
-
#endif
struct kmem_cache *jbd2_handle_cache;
@@ -2019,8 +2005,7 @@ static int __init journal_init_handle_cache(void)
sizeof(handle_t),
0, /* offset */
0, /* flags */
- NULL, /* ctor */
- NULL); /* dtor */
+ NULL); /* ctor */
if (jbd2_handle_cache == NULL) {
printk(KERN_EMERG "JBD: failed to create handle cache\n");
return -ENOMEM;
@@ -2067,18 +2052,18 @@ static int __init journal_init(void)
ret = journal_init_caches();
if (ret != 0)
jbd2_journal_destroy_caches();
- create_jbd_proc_entry();
+ jbd2_create_debugfs_entry();
return ret;
}
static void __exit journal_exit(void)
{
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
int n = atomic_read(&nr_journal_heads);
if (n)
printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
#endif
- jbd2_remove_jbd_proc_entry();
+ jbd2_remove_debugfs_entry();
jbd2_journal_destroy_caches();
}
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index 395c92a04ac9..b50be8a044eb 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -251,10 +251,10 @@ int jbd2_journal_recover(journal_t *journal)
if (!err)
err = do_one_pass(journal, &info, PASS_REPLAY);
- jbd_debug(0, "JBD: recovery, exit status %d, "
+ jbd_debug(1, "JBD: recovery, exit status %d, "
"recovered transactions %u to %u\n",
err, info.start_transaction, info.end_transaction);
- jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
+ jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n",
info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
/* Restart the log at the next transaction ID, thus invalidating
@@ -295,10 +295,10 @@ int jbd2_journal_skip_recovery(journal_t *journal)
printk(KERN_ERR "JBD: error %d scanning journal\n", err);
++journal->j_transaction_sequence;
} else {
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
#endif
- jbd_debug(0,
+ jbd_debug(1,
"JBD: ignoring %d transaction%s from the journal.\n",
dropped, (dropped == 1) ? "" : "s");
journal->j_transaction_sequence = ++info.end_transaction;
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index 9246e763da78..01d88975e0c5 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -68,6 +68,7 @@
#include <linux/list.h>
#include <linux/init.h>
#endif
+#include <linux/log2.h>
static struct kmem_cache *jbd2_revoke_record_cache;
static struct kmem_cache *jbd2_revoke_table_cache;
@@ -170,13 +171,13 @@ int __init jbd2_journal_init_revoke_caches(void)
{
jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
sizeof(struct jbd2_revoke_record_s),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (jbd2_revoke_record_cache == 0)
return -ENOMEM;
jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
sizeof(struct jbd2_revoke_table_s),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (jbd2_revoke_table_cache == 0) {
kmem_cache_destroy(jbd2_revoke_record_cache);
jbd2_revoke_record_cache = NULL;
@@ -212,7 +213,7 @@ int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[0];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
@@ -239,7 +240,7 @@ int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
journal->j_revoke = journal->j_revoke_table[1];
/* Check that the hash_size is a power of two */
- J_ASSERT ((hash_size & (hash_size-1)) == 0);
+ J_ASSERT(is_power_of_2(hash_size));
journal->j_revoke->hash_size = hash_size;
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c
index a46101ee867a..65b3a1b5b88d 100644
--- a/fs/jffs2/acl.c
+++ b/fs/jffs2/acl.c
@@ -435,7 +435,7 @@ static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value,
struct posix_acl *acl;
int rc;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (value) {
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 8754b2742112..d568ae846741 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -81,6 +81,7 @@ static int jffs2_garbage_collect_thread(void *_c)
set_user_nice(current, 10);
+ set_freezable();
for (;;) {
allow_signal(SIGHUP);
again:
diff --git a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c
index 35c1a5e30ba1..f9211252b5f1 100644
--- a/fs/jffs2/malloc.c
+++ b/fs/jffs2/malloc.c
@@ -33,56 +33,56 @@ int __init jffs2_create_slab_caches(void)
{
full_dnode_slab = kmem_cache_create("jffs2_full_dnode",
sizeof(struct jffs2_full_dnode),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!full_dnode_slab)
goto err;
raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent",
sizeof(struct jffs2_raw_dirent),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!raw_dirent_slab)
goto err;
raw_inode_slab = kmem_cache_create("jffs2_raw_inode",
sizeof(struct jffs2_raw_inode),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!raw_inode_slab)
goto err;
tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode",
sizeof(struct jffs2_tmp_dnode_info),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!tmp_dnode_info_slab)
goto err;
raw_node_ref_slab = kmem_cache_create("jffs2_refblock",
sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!raw_node_ref_slab)
goto err;
node_frag_slab = kmem_cache_create("jffs2_node_frag",
sizeof(struct jffs2_node_frag),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!node_frag_slab)
goto err;
inode_cache_slab = kmem_cache_create("jffs2_inode_cache",
sizeof(struct jffs2_inode_cache),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!inode_cache_slab)
goto err;
#ifdef CONFIG_JFFS2_FS_XATTR
xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum",
sizeof(struct jffs2_xattr_datum),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!xattr_datum_cache)
goto err;
xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref",
sizeof(struct jffs2_xattr_ref),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!xattr_ref_cache)
goto err;
#endif
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index e220d3bd610d..be2b70c2ec16 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -192,7 +192,7 @@ static int __init init_jffs2_fs(void)
sizeof(struct jffs2_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- jffs2_i_init_once, NULL);
+ jffs2_i_init_once);
if (!jffs2_inode_cachep) {
printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
return -ENOMEM;
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
index fe063af6fd2f..3c8663bea98c 100644
--- a/fs/jfs/ioctl.c
+++ b/fs/jfs/ioctl.c
@@ -69,7 +69,7 @@ int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd,
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EACCES;
if (get_user(flags, (int __user *) arg))
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index 2374b595f2e1..f0ec72b263f1 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -32,6 +32,7 @@ extern void jfs_truncate_nolock(struct inode *, loff_t);
extern void jfs_free_zero_link(struct inode *);
extern struct dentry *jfs_get_parent(struct dentry *dentry);
extern void jfs_get_inode_flags(struct jfs_inode_info *);
+extern struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp);
extern void jfs_set_inode_flags(struct inode *);
extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index 77c7f1129dde..62e96be02acf 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -213,7 +213,7 @@ int __init metapage_init(void)
* Allocate the metapage structures
*/
metapage_cache = kmem_cache_create("jfs_mp", sizeof(struct metapage),
- 0, 0, init_once, NULL);
+ 0, 0, init_once);
if (metapage_cache == NULL)
return -ENOMEM;
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 25161c4121e4..932797ba433b 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1477,6 +1477,38 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc
return dentry;
}
+struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp)
+{
+ __u32 *objp = vobjp;
+ unsigned long ino = objp[0];
+ __u32 generation = objp[1];
+ struct inode *inode;
+ struct dentry *result;
+
+ if (ino == 0)
+ return ERR_PTR(-ESTALE);
+ inode = iget(sb, ino);
+ if (inode == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ if (is_bad_inode(inode) ||
+ (generation && inode->i_generation != generation)) {
+ result = ERR_PTR(-ESTALE);
+ goto out_iput;
+ }
+
+ result = d_alloc_anon(inode);
+ if (!result) {
+ result = ERR_PTR(-ENOMEM);
+ goto out_iput;
+ }
+ return result;
+
+ out_iput:
+ iput(inode);
+ return result;
+}
+
struct dentry *jfs_get_parent(struct dentry *dentry)
{
struct super_block *sb = dentry->d_inode->i_sb;
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 20e4ac1c79a3..4b372f550652 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -27,6 +27,7 @@
#include <linux/kthread.h>
#include <linux/posix_acl.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <asm/uaccess.h>
#include <linux/seq_file.h>
@@ -737,6 +738,7 @@ static const struct super_operations jfs_super_operations = {
};
static struct export_operations jfs_export_operations = {
+ .get_dentry = jfs_get_dentry,
.get_parent = jfs_get_parent,
};
@@ -774,7 +776,7 @@ static int __init init_jfs_fs(void)
jfs_inode_cachep =
kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- init_once, NULL);
+ init_once);
if (jfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index b2375f0774b7..9b7f2cdaae0a 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -697,7 +697,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name,
struct posix_acl *acl;
int rc;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
/*
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 96070bff93fc..572601e98dcd 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -44,9 +44,8 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin,
*/
static struct nlm_host *
nlm_lookup_host(int server, const struct sockaddr_in *sin,
- int proto, int version,
- const char *hostname,
- int hostname_len)
+ int proto, int version, const char *hostname,
+ int hostname_len, const struct sockaddr_in *ssin)
{
struct hlist_head *chain;
struct hlist_node *pos;
@@ -54,7 +53,9 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
struct nsm_handle *nsm = NULL;
int hash;
- dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n",
+ dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT
+ ", p=%d, v=%d, my role=%s, name=%.*s)\n",
+ NIPQUAD(ssin->sin_addr.s_addr),
NIPQUAD(sin->sin_addr.s_addr), proto, version,
server? "server" : "client",
hostname_len,
@@ -91,6 +92,8 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
continue;
if (host->h_server != server)
continue;
+ if (!nlm_cmp_addr(&host->h_saddr, ssin))
+ continue;
/* Move to head of hash chain. */
hlist_del(&host->h_hash);
@@ -118,6 +121,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin,
host->h_name = nsm->sm_name;
host->h_addr = *sin;
host->h_addr.sin_port = 0; /* ouch! */
+ host->h_saddr = *ssin;
host->h_version = version;
host->h_proto = proto;
host->h_rpcclnt = NULL;
@@ -161,15 +165,9 @@ nlm_destroy_host(struct nlm_host *host)
*/
nsm_unmonitor(host);
- if ((clnt = host->h_rpcclnt) != NULL) {
- if (atomic_read(&clnt->cl_users)) {
- printk(KERN_WARNING
- "lockd: active RPC handle\n");
- clnt->cl_dead = 1;
- } else {
- rpc_destroy_client(host->h_rpcclnt);
- }
- }
+ clnt = host->h_rpcclnt;
+ if (clnt != NULL)
+ rpc_shutdown_client(clnt);
kfree(host);
}
@@ -180,8 +178,10 @@ struct nlm_host *
nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
const char *hostname, int hostname_len)
{
+ struct sockaddr_in ssin = {0};
+
return nlm_lookup_host(0, sin, proto, version,
- hostname, hostname_len);
+ hostname, hostname_len, &ssin);
}
/*
@@ -191,9 +191,12 @@ struct nlm_host *
nlmsvc_lookup_host(struct svc_rqst *rqstp,
const char *hostname, int hostname_len)
{
+ struct sockaddr_in ssin = {0};
+
+ ssin.sin_addr = rqstp->rq_daddr.addr;
return nlm_lookup_host(1, svc_addr_in(rqstp),
rqstp->rq_prot, rqstp->rq_vers,
- hostname, hostname_len);
+ hostname, hostname_len, &ssin);
}
/*
@@ -204,8 +207,9 @@ nlm_bind_host(struct nlm_host *host)
{
struct rpc_clnt *clnt;
- dprintk("lockd: nlm_bind_host(%08x)\n",
- (unsigned)ntohl(host->h_addr.sin_addr.s_addr));
+ dprintk("lockd: nlm_bind_host("NIPQUAD_FMT"->"NIPQUAD_FMT")\n",
+ NIPQUAD(host->h_saddr.sin_addr),
+ NIPQUAD(host->h_addr.sin_addr));
/* Lock host handle */
mutex_lock(&host->h_mutex);
@@ -232,6 +236,7 @@ nlm_bind_host(struct nlm_host *host)
.protocol = host->h_proto,
.address = (struct sockaddr *)&host->h_addr,
.addrsize = sizeof(host->h_addr),
+ .saddress = (struct sockaddr *)&host->h_saddr,
.timeout = &timeparms,
.servername = host->h_name,
.program = &nlm_program,
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 2102e2d0134d..3353ed8421a7 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -61,6 +61,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
status);
else
status = 0;
+ rpc_shutdown_client(clnt);
out:
return status;
}
@@ -138,7 +139,6 @@ nsm_create(void)
.program = &nsm_program,
.version = SM_VERSION,
.authflavor = RPC_AUTH_NULL,
- .flags = (RPC_CLNT_CREATE_ONESHOT),
};
return rpc_create(&args);
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 126b1bf02c0e..82e2192a0d5c 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -25,6 +25,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
+#include <linux/freezer.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/stats.h>
@@ -75,18 +76,31 @@ static const int nlm_port_min = 0, nlm_port_max = 65535;
static struct ctl_table_header * nlm_sysctl_table;
-static unsigned long set_grace_period(void)
+static unsigned long get_lockd_grace_period(void)
{
- unsigned long grace_period;
-
/* Note: nlm_timeout should always be nonzero */
if (nlm_grace_period)
- grace_period = ((nlm_grace_period + nlm_timeout - 1)
- / nlm_timeout) * nlm_timeout * HZ;
+ return roundup(nlm_grace_period, nlm_timeout) * HZ;
else
- grace_period = nlm_timeout * 5 * HZ;
+ return nlm_timeout * 5 * HZ;
+}
+
+unsigned long get_nfs_grace_period(void)
+{
+ unsigned long lockdgrace = get_lockd_grace_period();
+ unsigned long nfsdgrace = 0;
+
+ if (nlmsvc_ops)
+ nfsdgrace = nlmsvc_ops->get_grace_period();
+
+ return max(lockdgrace, nfsdgrace);
+}
+EXPORT_SYMBOL(get_nfs_grace_period);
+
+static unsigned long set_grace_period(void)
+{
nlmsvc_grace_period = 1;
- return grace_period + jiffies;
+ return get_nfs_grace_period() + jiffies;
}
static inline void clear_grace_period(void)
@@ -119,13 +133,11 @@ lockd(struct svc_rqst *rqstp)
complete(&lockd_start_done);
daemonize("lockd");
+ set_freezable();
/* Process request with signals blocked, but allow SIGKILL. */
allow_signal(SIGKILL);
- /* kick rpciod */
- rpciod_up();
-
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
if (!nlm_timeout)
@@ -202,9 +214,6 @@ lockd(struct svc_rqst *rqstp)
/* Exit the RPC thread */
svc_exit_thread(rqstp);
- /* release rpciod */
- rpciod_down();
-
/* Release module */
unlock_kernel();
module_put_and_exit(0);
diff --git a/fs/locks.c b/fs/locks.c
index 431a8b871fce..310510637247 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -458,22 +458,20 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl)
}
/* Allocate a file_lock initialised to this type of lease */
-static int lease_alloc(struct file *filp, int type, struct file_lock **flp)
+static struct file_lock *lease_alloc(struct file *filp, int type)
{
struct file_lock *fl = locks_alloc_lock();
int error = -ENOMEM;
if (fl == NULL)
- goto out;
+ return ERR_PTR(error);
error = lease_init(filp, type, fl);
if (error) {
locks_free_lock(fl);
- fl = NULL;
+ return ERR_PTR(error);
}
-out:
- *flp = fl;
- return error;
+ return fl;
}
/* Check if two locks overlap each other.
@@ -661,7 +659,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
return result;
}
-int
+void
posix_test_lock(struct file *filp, struct file_lock *fl)
{
struct file_lock *cfl;
@@ -673,14 +671,12 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
if (posix_locks_conflict(cfl, fl))
break;
}
- if (cfl) {
+ if (cfl)
__locks_copy_lock(fl, cfl);
- unlock_kernel();
- return 1;
- } else
+ else
fl->fl_type = F_UNLCK;
unlock_kernel();
- return 0;
+ return;
}
EXPORT_SYMBOL(posix_test_lock);
@@ -1169,9 +1165,9 @@ static void time_out_leases(struct inode *inode)
* @inode: the inode of the file to return
* @mode: the open mode (read or write)
*
- * break_lease (inlined for speed) has checked there already
- * is a lease on this file. Leases are broken on a call to open()
- * or truncate(). This function can sleep unless you
+ * break_lease (inlined for speed) has checked there already is at least
+ * some kind of lock (maybe a lease) on this file. Leases are broken on
+ * a call to open() or truncate(). This function can sleep unless you
* specified %O_NONBLOCK to your open().
*/
int __break_lease(struct inode *inode, unsigned int mode)
@@ -1179,12 +1175,10 @@ int __break_lease(struct inode *inode, unsigned int mode)
int error = 0, future;
struct file_lock *new_fl, *flock;
struct file_lock *fl;
- int alloc_err;
unsigned long break_time;
int i_have_this_lease = 0;
- alloc_err = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK,
- &new_fl);
+ new_fl = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK);
lock_kernel();
@@ -1212,8 +1206,9 @@ int __break_lease(struct inode *inode, unsigned int mode)
goto out;
}
- if (alloc_err && !i_have_this_lease && ((mode & O_NONBLOCK) == 0)) {
- error = alloc_err;
+ if (IS_ERR(new_fl) && !i_have_this_lease
+ && ((mode & O_NONBLOCK) == 0)) {
+ error = PTR_ERR(new_fl);
goto out;
}
@@ -1260,7 +1255,7 @@ restart:
out:
unlock_kernel();
- if (!alloc_err)
+ if (!IS_ERR(new_fl))
locks_free_lock(new_fl);
return error;
}
@@ -1329,7 +1324,7 @@ int fcntl_getlease(struct file *filp)
}
/**
- * __setlease - sets a lease on an open file
+ * setlease - sets a lease on an open file
* @filp: file pointer
* @arg: type of lease to obtain
* @flp: input - file_lock to use, output - file_lock inserted
@@ -1339,18 +1334,24 @@ int fcntl_getlease(struct file *filp)
*
* Called with kernel lock held.
*/
-static int __setlease(struct file *filp, long arg, struct file_lock **flp)
+int setlease(struct file *filp, long arg, struct file_lock **flp)
{
struct file_lock *fl, **before, **my_before = NULL, *lease;
struct dentry *dentry = filp->f_path.dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
+ return -EACCES;
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+ error = security_file_lock(filp, arg);
+ if (error)
+ return error;
+
time_out_leases(inode);
- error = -EINVAL;
- if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
- goto out;
+ BUG_ON(!(*flp)->fl_lmops->fl_break);
lease = *flp;
@@ -1418,39 +1419,49 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
out:
return error;
}
+EXPORT_SYMBOL(setlease);
/**
- * setlease - sets a lease on an open file
+ * vfs_setlease - sets a lease on an open file
* @filp: file pointer
* @arg: type of lease to obtain
* @lease: file_lock to use
*
* Call this to establish a lease on the file.
- * The fl_lmops fl_break function is required by break_lease
+ * The (*lease)->fl_lmops->fl_break operation must be set; if not,
+ * break_lease will oops!
+ *
+ * This will call the filesystem's setlease file method, if
+ * defined. Note that there is no getlease method; instead, the
+ * filesystem setlease method should call back to setlease() to
+ * add a lease to the inode's lease list, where fcntl_getlease() can
+ * find it. Since fcntl_getlease() only reports whether the current
+ * task holds a lease, a cluster filesystem need only do this for
+ * leases held by processes on this node.
+ *
+ * There is also no break_lease method; filesystems that
+ * handle their own leases shoud break leases themselves from the
+ * filesystem's open, create, and (on truncate) setattr methods.
+ *
+ * Warning: the only current setlease methods exist only to disable
+ * leases in certain cases. More vfs changes may be required to
+ * allow a full filesystem lease implementation.
*/
-int setlease(struct file *filp, long arg, struct file_lock **lease)
+int vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
{
- struct dentry *dentry = filp->f_path.dentry;
- struct inode *inode = dentry->d_inode;
int error;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
- return -EACCES;
- if (!S_ISREG(inode->i_mode))
- return -EINVAL;
- error = security_file_lock(filp, arg);
- if (error)
- return error;
-
lock_kernel();
- error = __setlease(filp, arg, lease);
+ if (filp->f_op && filp->f_op->setlease)
+ error = filp->f_op->setlease(filp, arg, lease);
+ else
+ error = setlease(filp, arg, lease);
unlock_kernel();
return error;
}
-
-EXPORT_SYMBOL(setlease);
+EXPORT_SYMBOL_GPL(vfs_setlease);
/**
* fcntl_setlease - sets a lease on an open file
@@ -1469,14 +1480,6 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
struct inode *inode = dentry->d_inode;
int error;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_LEASE))
- return -EACCES;
- if (!S_ISREG(inode->i_mode))
- return -EINVAL;
- error = security_file_lock(filp, arg);
- if (error)
- return error;
-
locks_init_lock(&fl);
error = lease_init(filp, arg, &fl);
if (error)
@@ -1484,15 +1487,15 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
lock_kernel();
- error = __setlease(filp, arg, &flp);
+ error = vfs_setlease(filp, arg, &flp);
if (error || arg == F_UNLCK)
goto out_unlock;
error = fasync_helper(fd, filp, 1, &flp->fl_fasync);
if (error < 0) {
- /* remove lease just inserted by __setlease */
+ /* remove lease just inserted by setlease */
flp->fl_type = F_UNLCK | F_INPROGRESS;
- flp->fl_break_time = jiffies- 10;
+ flp->fl_break_time = jiffies - 10;
time_out_leases(inode);
goto out_unlock;
}
@@ -1597,8 +1600,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
/**
* vfs_test_lock - test file byte range lock
* @filp: The file to test lock for
- * @fl: The lock to test
- * @conf: Place to return a copy of the conflicting lock, if found
+ * @fl: The lock to test; also used to hold result
*
* Returns -ERRNO on failure. Indicates presence of conflicting lock by
* setting conf->fl_type to something other than F_UNLCK.
@@ -2274,7 +2276,7 @@ static int __init filelock_init(void)
{
filelock_cache = kmem_cache_create("file_lock_cache",
sizeof(struct file_lock), 0, SLAB_PANIC,
- init_once, NULL);
+ init_once);
return 0;
}
diff --git a/fs/mbcache.c b/fs/mbcache.c
index deeb9dc062d9..1046cbefbfbf 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -100,7 +100,6 @@ struct mb_cache {
static LIST_HEAD(mb_cache_list);
static LIST_HEAD(mb_cache_lru_list);
static DEFINE_SPINLOCK(mb_cache_spinlock);
-static struct shrinker *mb_shrinker;
static inline int
mb_cache_indexes(struct mb_cache *cache)
@@ -118,6 +117,10 @@ mb_cache_indexes(struct mb_cache *cache)
static int mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask);
+static struct shrinker mb_cache_shrinker = {
+ .shrink = mb_cache_shrink_fn,
+ .seeks = DEFAULT_SEEKS,
+};
static inline int
__mb_cache_entry_is_hashed(struct mb_cache_entry *ce)
@@ -289,7 +292,7 @@ mb_cache_create(const char *name, struct mb_cache_op *cache_op,
INIT_LIST_HEAD(&cache->c_indexes_hash[m][n]);
}
cache->c_entry_cache = kmem_cache_create(name, entry_size, 0,
- SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
if (!cache->c_entry_cache)
goto fail;
@@ -662,13 +665,13 @@ mb_cache_entry_find_next(struct mb_cache_entry *prev, int index,
static int __init init_mbcache(void)
{
- mb_shrinker = set_shrinker(DEFAULT_SEEKS, mb_cache_shrink_fn);
+ register_shrinker(&mb_cache_shrinker);
return 0;
}
static void __exit exit_mbcache(void)
{
- remove_shrinker(mb_shrinker);
+ unregister_shrinker(&mb_cache_shrinker);
}
module_init(init_mbcache)
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index be4044614ac8..43668d7d668f 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -75,14 +75,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
minix_inode_cachep = kmem_cache_create("minix_inode_cache",
sizeof(struct minix_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (minix_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/namei.c b/fs/namei.c
index 5e2d98d10c5d..a83160acd748 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -107,6 +107,8 @@
* any extra contention...
*/
+static int fastcall link_path_walk(const char *name, struct nameidata *nd);
+
/* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
@@ -998,7 +1000,7 @@ return_err:
* Retry the whole path once, forcing real lookup requests
* instead of relying on the dcache.
*/
-int fastcall link_path_walk(const char *name, struct nameidata *nd)
+static int fastcall link_path_walk(const char *name, struct nameidata *nd)
{
struct nameidata save = *nd;
int result;
@@ -1022,7 +1024,7 @@ int fastcall link_path_walk(const char *name, struct nameidata *nd)
return result;
}
-int fastcall path_walk(const char * name, struct nameidata *nd)
+static int fastcall path_walk(const char * name, struct nameidata *nd)
{
current->total_link_count = 0;
return link_path_walk(name, nd);
@@ -1172,6 +1174,37 @@ int fastcall path_lookup(const char *name, unsigned int flags,
return do_path_lookup(AT_FDCWD, name, flags, nd);
}
+/**
+ * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair
+ * @dentry: pointer to dentry of the base directory
+ * @mnt: pointer to vfs mount of the base directory
+ * @name: pointer to file name
+ * @flags: lookup flags
+ * @nd: pointer to nameidata
+ */
+int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
+ const char *name, unsigned int flags,
+ struct nameidata *nd)
+{
+ int retval;
+
+ /* same as do_path_lookup */
+ nd->last_type = LAST_ROOT;
+ nd->flags = flags;
+ nd->depth = 0;
+
+ nd->mnt = mntget(mnt);
+ nd->dentry = dget(dentry);
+
+ retval = path_walk(name, nd);
+ if (unlikely(!retval && !audit_dummy_context() && nd->dentry &&
+ nd->dentry->d_inode))
+ audit_inode(name, nd->dentry->d_inode);
+
+ return retval;
+
+}
+
static int __path_lookup_intent_open(int dfd, const char *name,
unsigned int lookup_flags, struct nameidata *nd,
int open_flags, int create_mode)
@@ -1576,7 +1609,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
/* O_NOATIME can only be set by the owner or superuser */
if (flag & O_NOATIME)
- if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
/*
@@ -2774,8 +2807,8 @@ EXPORT_SYMBOL(__page_symlink);
EXPORT_SYMBOL(page_symlink);
EXPORT_SYMBOL(page_symlink_inode_operations);
EXPORT_SYMBOL(path_lookup);
+EXPORT_SYMBOL(vfs_path_lookup);
EXPORT_SYMBOL(path_release);
-EXPORT_SYMBOL(path_walk);
EXPORT_SYMBOL(permission);
EXPORT_SYMBOL(vfs_permission);
EXPORT_SYMBOL(file_permission);
diff --git a/fs/namespace.c b/fs/namespace.c
index b696e3a0d18f..ddbda13c2d31 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -28,6 +28,7 @@
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include "pnode.h"
+#include "internal.h"
/* spinlock for vfsmount related operations, inplace of dcache_lock */
__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
@@ -320,22 +321,16 @@ EXPORT_SYMBOL(mnt_unpin);
static void *m_start(struct seq_file *m, loff_t *pos)
{
struct mnt_namespace *n = m->private;
- struct list_head *p;
- loff_t l = *pos;
down_read(&namespace_sem);
- list_for_each(p, &n->list)
- if (!l--)
- return list_entry(p, struct vfsmount, mnt_list);
- return NULL;
+ return seq_list_start(&n->list, *pos);
}
static void *m_next(struct seq_file *m, void *v, loff_t *pos)
{
struct mnt_namespace *n = m->private;
- struct list_head *p = ((struct vfsmount *)v)->mnt_list.next;
- (*pos)++;
- return p == &n->list ? NULL : list_entry(p, struct vfsmount, mnt_list);
+
+ return seq_list_next(v, &n->list, pos);
}
static void m_stop(struct seq_file *m, void *v)
@@ -350,7 +345,7 @@ static inline void mangle(struct seq_file *m, const char *s)
static int show_vfsmnt(struct seq_file *m, void *v)
{
- struct vfsmount *mnt = v;
+ struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
int err = 0;
static struct proc_fs_info {
int flag;
@@ -405,7 +400,7 @@ struct seq_operations mounts_op = {
static int show_vfsstat(struct seq_file *m, void *v)
{
- struct vfsmount *mnt = v;
+ struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
int err = 0;
/* device */
@@ -1457,7 +1452,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
if (!new_ns)
- return NULL;
+ return ERR_PTR(-ENOMEM);
atomic_set(&new_ns->count, 1);
INIT_LIST_HEAD(&new_ns->list);
@@ -1471,7 +1466,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
if (!new_ns->root) {
up_write(&namespace_sem);
kfree(new_ns);
- return NULL;
+ return ERR_PTR(-ENOMEM);;
}
spin_lock(&vfsmount_lock);
list_add_tail(&new_ns->list, &new_ns->root->mnt_list);
@@ -1515,7 +1510,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
return new_ns;
}
-struct mnt_namespace *copy_mnt_ns(int flags, struct mnt_namespace *ns,
+struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns,
struct fs_struct *new_fs)
{
struct mnt_namespace *new_ns;
@@ -1806,7 +1801,7 @@ void __init mnt_init(unsigned long mempages)
init_rwsem(&namespace_sem);
mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct vfsmount),
- 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
mount_hashtable = (struct list_head *)__get_free_page(GFP_ATOMIC);
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index d3152f8d95c6..2b145de45b39 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -203,7 +203,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) {
if (pos >= MAX_NON_LFS) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
if (count > MAX_NON_LFS - (u32)pos) {
@@ -212,7 +211,6 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
}
if (pos >= inode->i_sb->s_maxbytes) {
if (count || pos > inode->i_sb->s_maxbytes) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
}
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index cf06eb9f050e..7f8536dbdedc 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -63,14 +63,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
mutex_init(&ei->open_mutex);
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
sizeof(struct ncp_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (ncp_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index 70a69115500f..a94473d3072c 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -24,31 +24,35 @@
/*
* Fill in the supplied page for mmap
+ * XXX: how are we excluding truncate/invalidate here? Maybe need to lock
+ * page?
*/
-static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
- unsigned long address, int *type)
+static int ncp_file_mmap_fault(struct vm_area_struct *area,
+ struct vm_fault *vmf)
{
struct file *file = area->vm_file;
struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
- struct page* page;
char *pg_addr;
unsigned int already_read;
unsigned int count;
int bufsize;
- int pos;
+ int pos; /* XXX: loff_t ? */
- page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages
- as long as recvmsg and memset works on it */
- if (!page)
- return page;
- pg_addr = kmap(page);
- address &= PAGE_MASK;
- pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT);
+ /*
+ * ncpfs has nothing against high pages as long
+ * as recvmsg and memset works on it
+ */
+ vmf->page = alloc_page(GFP_HIGHUSER);
+ if (!vmf->page)
+ return VM_FAULT_OOM;
+ pg_addr = kmap(vmf->page);
+ pos = vmf->pgoff << PAGE_SHIFT;
count = PAGE_SIZE;
- if (address + PAGE_SIZE > area->vm_end) {
- count = area->vm_end - address;
+ if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
+ WARN_ON(1); /* shouldn't happen? */
+ count = area->vm_end - (unsigned long)vmf->virtual_address;
}
/* what we can read in one go */
bufsize = NCP_SERVER(inode)->buffer_size;
@@ -83,23 +87,21 @@ static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area,
if (already_read < PAGE_SIZE)
memset(pg_addr + already_read, 0, PAGE_SIZE - already_read);
- flush_dcache_page(page);
- kunmap(page);
+ flush_dcache_page(vmf->page);
+ kunmap(vmf->page);
/*
* If I understand ncp_read_kernel() properly, the above always
* fetches from the network, here the analogue of disk.
* -- wli
*/
- if (type)
- *type = VM_FAULT_MAJOR;
count_vm_event(PGMAJFAULT);
- return page;
+ return VM_FAULT_MAJOR;
}
static struct vm_operations_struct ncp_file_mmap =
{
- .nopage = ncp_file_mmap_nopage,
+ .fault = ncp_file_mmap_fault,
};
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index f4580b44eef4..b55cb236cf74 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -6,8 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o
nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
pagelist.o proc.o read.o symlink.o unlink.o \
- write.o namespace.o
-nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
+ write.o namespace.o mount_clnt.o
+nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 75f309c8741a..a796be5051bf 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -14,6 +14,7 @@
#include <linux/sunrpc/svcsock.h>
#include <linux/nfs_fs.h>
#include <linux/mutex.h>
+#include <linux/freezer.h>
#include <net/inet_sock.h>
@@ -67,6 +68,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
daemonize("nfsv4-svc");
/* Process request with signals blocked, but allow SIGKILL. */
allow_signal(SIGKILL);
+ set_freezable();
complete(&nfs_callback_info.started);
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 849a2029975d..058ade7efe79 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -179,7 +179,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr
args->addr = svc_addr_in(rqstp);
status = decode_bitmap(xdr, args->bitmap);
out:
- dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+ dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
return status;
}
@@ -200,7 +200,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr,
args->truncate = ntohl(*p);
status = decode_fh(xdr, &args->fh);
out:
- dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+ dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
return status;
}
@@ -349,7 +349,7 @@ static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr,
status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
*savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
out:
- dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
+ dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(status));
return status;
}
@@ -392,7 +392,7 @@ static __be32 process_op(struct svc_rqst *rqstp,
status = res;
if (op->encode_res != NULL && status == 0)
status = op->encode_res(rqstp, xdr_out, resp);
- dprintk("%s: done, status = %d\n", __FUNCTION__, status);
+ dprintk("%s: done, status = %d\n", __FUNCTION__, ntohl(status));
return status;
}
@@ -431,7 +431,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
}
*hdr_res.status = status;
*hdr_res.nops = htonl(nops);
- dprintk("%s: done, status = %u\n", __FUNCTION__, status);
+ dprintk("%s: done, status = %u\n", __FUNCTION__, ntohl(status));
return rpc_success;
}
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 881fa4900923..a49f9feff776 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -102,19 +102,10 @@ static struct nfs_client *nfs_alloc_client(const char *hostname,
int nfsversion)
{
struct nfs_client *clp;
- int error;
if ((clp = kzalloc(sizeof(*clp), GFP_KERNEL)) == NULL)
goto error_0;
- error = rpciod_up();
- if (error < 0) {
- dprintk("%s: couldn't start rpciod! Error = %d\n",
- __FUNCTION__, error);
- goto error_1;
- }
- __set_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
-
if (nfsversion == 4) {
if (nfs_callback_up() < 0)
goto error_2;
@@ -139,8 +130,6 @@ static struct nfs_client *nfs_alloc_client(const char *hostname,
#ifdef CONFIG_NFS_V4
init_rwsem(&clp->cl_sem);
INIT_LIST_HEAD(&clp->cl_delegations);
- INIT_LIST_HEAD(&clp->cl_state_owners);
- INIT_LIST_HEAD(&clp->cl_unused);
spin_lock_init(&clp->cl_lock);
INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
@@ -154,9 +143,6 @@ error_3:
if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
nfs_callback_down();
error_2:
- rpciod_down();
- __clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state);
-error_1:
kfree(clp);
error_0:
return NULL;
@@ -167,16 +153,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
#ifdef CONFIG_NFS_V4
if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
nfs4_kill_renewd(clp);
- while (!list_empty(&clp->cl_unused)) {
- struct nfs4_state_owner *sp;
-
- sp = list_entry(clp->cl_unused.next,
- struct nfs4_state_owner,
- so_list);
- list_del(&sp->so_list);
- kfree(sp);
- }
- BUG_ON(!list_empty(&clp->cl_state_owners));
+ BUG_ON(!RB_EMPTY_ROOT(&clp->cl_state_owners));
if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
nfs_idmap_delete(clp);
#endif
@@ -198,9 +175,6 @@ static void nfs_free_client(struct nfs_client *clp)
if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
nfs_callback_down();
- if (__test_and_clear_bit(NFS_CS_RPCIOD, &clp->cl_res_state))
- rpciod_down();
-
kfree(clp->cl_hostname);
kfree(clp);
@@ -1232,23 +1206,9 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
*/
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
/* lock the list against modification */
spin_lock(&nfs_client_lock);
-
- /* allow for the header line */
- if (!pos)
- return SEQ_START_TOKEN;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &nfs_client_list)
- if (!pos--)
- break;
-
- return _p != &nfs_client_list ? _p : NULL;
+ return seq_list_start_head(&nfs_client_list, *_pos);
}
/*
@@ -1256,14 +1216,7 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
*/
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = (v == SEQ_START_TOKEN) ? nfs_client_list.next : _p->next;
-
- return _p != &nfs_client_list ? _p : NULL;
+ return seq_list_next(v, &nfs_client_list, pos);
}
/*
@@ -1282,7 +1235,7 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
struct nfs_client *clp;
/* display header on line 1 */
- if (v == SEQ_START_TOKEN) {
+ if (v == &nfs_client_list) {
seq_puts(m, "NV SERVER PORT USE HOSTNAME\n");
return 0;
}
@@ -1323,23 +1276,9 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)
*/
static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
/* lock the list against modification */
spin_lock(&nfs_client_lock);
-
- /* allow for the header line */
- if (!pos)
- return SEQ_START_TOKEN;
- pos--;
-
- /* find the n'th element in the list */
- list_for_each(_p, &nfs_volume_list)
- if (!pos--)
- break;
-
- return _p != &nfs_volume_list ? _p : NULL;
+ return seq_list_start_head(&nfs_volume_list, *_pos);
}
/*
@@ -1347,14 +1286,7 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)
*/
static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = (v == SEQ_START_TOKEN) ? nfs_volume_list.next : _p->next;
-
- return _p != &nfs_volume_list ? _p : NULL;
+ return seq_list_next(v, &nfs_volume_list, pos);
}
/*
@@ -1375,7 +1307,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
char dev[8], fsid[17];
/* display header on line 1 */
- if (v == SEQ_START_TOKEN) {
+ if (v == &nfs_volume_list) {
seq_puts(m, "NV SERVER PORT DEV FSID\n");
return 0;
}
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 7f37d1bea83f..20ac403469a0 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -27,6 +27,13 @@ static void nfs_free_delegation(struct nfs_delegation *delegation)
kfree(delegation);
}
+static void nfs_free_delegation_callback(struct rcu_head *head)
+{
+ struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu);
+
+ nfs_free_delegation(delegation);
+}
+
static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
{
struct inode *inode = state->inode;
@@ -57,7 +64,7 @@ out_err:
return status;
}
-static void nfs_delegation_claim_opens(struct inode *inode)
+static void nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
{
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_open_context *ctx;
@@ -72,9 +79,11 @@ again:
continue;
if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
continue;
+ if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
+ continue;
get_nfs_open_context(ctx);
spin_unlock(&inode->i_lock);
- err = nfs4_open_delegation_recall(ctx->dentry, state);
+ err = nfs4_open_delegation_recall(ctx, state, stateid);
if (err >= 0)
err = nfs_delegation_claim_locks(ctx, state);
put_nfs_open_context(ctx);
@@ -115,10 +124,6 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
struct nfs_delegation *delegation;
int status = 0;
- /* Ensure we first revalidate the attributes and page cache! */
- if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR)))
- __nfs_revalidate_inode(NFS_SERVER(inode), inode);
-
delegation = kmalloc(sizeof(*delegation), GFP_KERNEL);
if (delegation == NULL)
return -ENOMEM;
@@ -131,10 +136,10 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
delegation->inode = inode;
spin_lock(&clp->cl_lock);
- if (nfsi->delegation == NULL) {
- list_add(&delegation->super_list, &clp->cl_delegations);
- nfsi->delegation = delegation;
+ if (rcu_dereference(nfsi->delegation) == NULL) {
+ list_add_rcu(&delegation->super_list, &clp->cl_delegations);
nfsi->delegation_state = delegation->type;
+ rcu_assign_pointer(nfsi->delegation, delegation);
delegation = NULL;
} else {
if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
@@ -145,6 +150,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
status = -EIO;
}
}
+
+ /* Ensure we revalidate the attributes and page cache! */
+ spin_lock(&inode->i_lock);
+ nfsi->cache_validity |= NFS_INO_REVAL_FORCED;
+ spin_unlock(&inode->i_lock);
+
spin_unlock(&clp->cl_lock);
kfree(delegation);
return status;
@@ -155,7 +166,7 @@ static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *
int res = 0;
res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid);
- nfs_free_delegation(delegation);
+ call_rcu(&delegation->rcu, nfs_free_delegation_callback);
return res;
}
@@ -170,33 +181,55 @@ static void nfs_msync_inode(struct inode *inode)
/*
* Basic procedure for returning a delegation to the server
*/
-int __nfs_inode_return_delegation(struct inode *inode)
+static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
{
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode);
- struct nfs_delegation *delegation;
- int res = 0;
nfs_msync_inode(inode);
down_read(&clp->cl_sem);
/* Guard against new delegated open calls */
down_write(&nfsi->rwsem);
- spin_lock(&clp->cl_lock);
- delegation = nfsi->delegation;
- if (delegation != NULL) {
- list_del_init(&delegation->super_list);
- nfsi->delegation = NULL;
- nfsi->delegation_state = 0;
- }
- spin_unlock(&clp->cl_lock);
- nfs_delegation_claim_opens(inode);
+ nfs_delegation_claim_opens(inode, &delegation->stateid);
up_write(&nfsi->rwsem);
up_read(&clp->cl_sem);
nfs_msync_inode(inode);
- if (delegation != NULL)
- res = nfs_do_return_delegation(inode, delegation);
- return res;
+ return nfs_do_return_delegation(inode, delegation);
+}
+
+static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
+{
+ struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
+
+ if (delegation == NULL)
+ goto nomatch;
+ if (stateid != NULL && memcmp(delegation->stateid.data, stateid->data,
+ sizeof(delegation->stateid.data)) != 0)
+ goto nomatch;
+ list_del_rcu(&delegation->super_list);
+ nfsi->delegation_state = 0;
+ rcu_assign_pointer(nfsi->delegation, NULL);
+ return delegation;
+nomatch:
+ return NULL;
+}
+
+int nfs_inode_return_delegation(struct inode *inode)
+{
+ struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct nfs_delegation *delegation;
+ int err = 0;
+
+ if (rcu_dereference(nfsi->delegation) != NULL) {
+ spin_lock(&clp->cl_lock);
+ delegation = nfs_detach_delegation_locked(nfsi, NULL);
+ spin_unlock(&clp->cl_lock);
+ if (delegation != NULL)
+ err = __nfs_inode_return_delegation(inode, delegation);
+ }
+ return err;
}
/*
@@ -211,19 +244,23 @@ void nfs_return_all_delegations(struct super_block *sb)
if (clp == NULL)
return;
restart:
- spin_lock(&clp->cl_lock);
- list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
if (delegation->inode->i_sb != sb)
continue;
inode = igrab(delegation->inode);
if (inode == NULL)
continue;
+ spin_lock(&clp->cl_lock);
+ delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
- nfs_inode_return_delegation(inode);
+ rcu_read_unlock();
+ if (delegation != NULL)
+ __nfs_inode_return_delegation(inode, delegation);
iput(inode);
goto restart;
}
- spin_unlock(&clp->cl_lock);
+ rcu_read_unlock();
}
static int nfs_do_expire_all_delegations(void *ptr)
@@ -234,22 +271,26 @@ static int nfs_do_expire_all_delegations(void *ptr)
allow_signal(SIGKILL);
restart:
- spin_lock(&clp->cl_lock);
if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0)
goto out;
if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0)
goto out;
- list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
inode = igrab(delegation->inode);
if (inode == NULL)
continue;
+ spin_lock(&clp->cl_lock);
+ delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
- nfs_inode_return_delegation(inode);
+ rcu_read_unlock();
+ if (delegation)
+ __nfs_inode_return_delegation(inode, delegation);
iput(inode);
goto restart;
}
+ rcu_read_unlock();
out:
- spin_unlock(&clp->cl_lock);
nfs_put_client(clp);
module_put_and_exit(0);
}
@@ -280,17 +321,21 @@ void nfs_handle_cb_pathdown(struct nfs_client *clp)
if (clp == NULL)
return;
restart:
- spin_lock(&clp->cl_lock);
- list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
inode = igrab(delegation->inode);
if (inode == NULL)
continue;
+ spin_lock(&clp->cl_lock);
+ delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
spin_unlock(&clp->cl_lock);
- nfs_inode_return_delegation(inode);
+ rcu_read_unlock();
+ if (delegation != NULL)
+ __nfs_inode_return_delegation(inode, delegation);
iput(inode);
goto restart;
}
- spin_unlock(&clp->cl_lock);
+ rcu_read_unlock();
}
struct recall_threadargs {
@@ -316,21 +361,14 @@ static int recall_thread(void *data)
down_read(&clp->cl_sem);
down_write(&nfsi->rwsem);
spin_lock(&clp->cl_lock);
- delegation = nfsi->delegation;
- if (delegation != NULL && memcmp(delegation->stateid.data,
- args->stateid->data,
- sizeof(delegation->stateid.data)) == 0) {
- list_del_init(&delegation->super_list);
- nfsi->delegation = NULL;
- nfsi->delegation_state = 0;
+ delegation = nfs_detach_delegation_locked(nfsi, args->stateid);
+ if (delegation != NULL)
args->result = 0;
- } else {
- delegation = NULL;
+ else
args->result = -ENOENT;
- }
spin_unlock(&clp->cl_lock);
complete(&args->started);
- nfs_delegation_claim_opens(inode);
+ nfs_delegation_claim_opens(inode, args->stateid);
up_write(&nfsi->rwsem);
up_read(&clp->cl_sem);
nfs_msync_inode(inode);
@@ -371,14 +409,14 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
{
struct nfs_delegation *delegation;
struct inode *res = NULL;
- spin_lock(&clp->cl_lock);
- list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
res = igrab(delegation->inode);
break;
}
}
- spin_unlock(&clp->cl_lock);
+ rcu_read_unlock();
return res;
}
@@ -388,10 +426,10 @@ struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
{
struct nfs_delegation *delegation;
- spin_lock(&clp->cl_lock);
- list_for_each_entry(delegation, &clp->cl_delegations, super_list)
+ rcu_read_lock();
+ list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list)
delegation->flags |= NFS_DELEGATION_NEED_RECLAIM;
- spin_unlock(&clp->cl_lock);
+ rcu_read_unlock();
}
/*
@@ -399,39 +437,35 @@ void nfs_delegation_mark_reclaim(struct nfs_client *clp)
*/
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
{
- struct nfs_delegation *delegation, *n;
- LIST_HEAD(head);
- spin_lock(&clp->cl_lock);
- list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) {
+ struct nfs_delegation *delegation;
+restart:
+ rcu_read_lock();
+ list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0)
continue;
- list_move(&delegation->super_list, &head);
- NFS_I(delegation->inode)->delegation = NULL;
- NFS_I(delegation->inode)->delegation_state = 0;
- }
- spin_unlock(&clp->cl_lock);
- while(!list_empty(&head)) {
- delegation = list_entry(head.next, struct nfs_delegation, super_list);
- list_del(&delegation->super_list);
- nfs_free_delegation(delegation);
+ spin_lock(&clp->cl_lock);
+ delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL);
+ spin_unlock(&clp->cl_lock);
+ rcu_read_unlock();
+ if (delegation != NULL)
+ call_rcu(&delegation->rcu, nfs_free_delegation_callback);
+ goto restart;
}
+ rcu_read_unlock();
}
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
{
- struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_delegation *delegation;
- int res = 0;
+ int ret = 0;
- if (nfsi->delegation_state == 0)
- return 0;
- spin_lock(&clp->cl_lock);
- delegation = nfsi->delegation;
+ rcu_read_lock();
+ delegation = rcu_dereference(nfsi->delegation);
if (delegation != NULL) {
memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
- res = 1;
+ ret = 1;
}
- spin_unlock(&clp->cl_lock);
- return res;
+ rcu_read_unlock();
+ return ret;
}
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h
index 2cfd4b24c7fe..5874ce7fdbae 100644
--- a/fs/nfs/delegation.h
+++ b/fs/nfs/delegation.h
@@ -22,11 +22,12 @@ struct nfs_delegation {
long flags;
loff_t maxsize;
__u64 change_attr;
+ struct rcu_head rcu;
};
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
-int __nfs_inode_return_delegation(struct inode *inode);
+int nfs_inode_return_delegation(struct inode *inode);
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
@@ -39,27 +40,24 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
/* NFSv4 delegation-related procedures */
int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
-int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state);
+int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl);
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
static inline int nfs_have_delegation(struct inode *inode, int flags)
{
+ struct nfs_delegation *delegation;
+ int ret = 0;
+
flags &= FMODE_READ|FMODE_WRITE;
- smp_rmb();
- if ((NFS_I(inode)->delegation_state & flags) == flags)
- return 1;
- return 0;
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(inode)->delegation);
+ if (delegation != NULL && (delegation->type & flags) == flags)
+ ret = 1;
+ rcu_read_unlock();
+ return ret;
}
-static inline int nfs_inode_return_delegation(struct inode *inode)
-{
- int err = 0;
-
- if (NFS_I(inode)->delegation != NULL)
- err = __nfs_inode_return_delegation(inode);
- return err;
-}
#else
static inline int nfs_have_delegation(struct inode *inode, int flags)
{
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index c27258b5d3e1..ea97408e423e 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -654,7 +654,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
if (IS_ROOT(dentry))
return 1;
- verf = (unsigned long)dentry->d_fsdata;
+ verf = dentry->d_time;
if (nfs_caches_unstable(dir)
|| verf != NFS_I(dir)->cache_change_attribute)
return 0;
@@ -663,7 +663,7 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
{
- dentry->d_fsdata = (void *)verf;
+ dentry->d_time = verf;
}
static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf)
@@ -869,7 +869,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
lock_kernel();
drop_nlink(inode);
- nfs_complete_unlink(dentry);
+ nfs_complete_unlink(dentry, inode);
unlock_kernel();
}
/* When creating a negative dentry, we want to renew d_time */
@@ -897,14 +897,13 @@ int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
return (nd->intent.open.flags & O_EXCL) != 0;
}
-static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir,
- struct nfs_fh *fh, struct nfs_fattr *fattr)
+static inline int nfs_reval_fsid(struct inode *dir, const struct nfs_fattr *fattr)
{
struct nfs_server *server = NFS_SERVER(dir);
if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
- /* Revalidate fsid on root dir */
- return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode);
+ /* Revalidate fsid using the parent directory */
+ return __nfs_revalidate_inode(server, dir);
return 0;
}
@@ -946,7 +945,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
res = ERR_PTR(error);
goto out_unlock;
}
- error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr);
+ error = nfs_reval_fsid(dir, &fattr);
if (error < 0) {
res = ERR_PTR(error);
goto out_unlock;
@@ -1244,7 +1243,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
- if (nd && (nd->flags & LOOKUP_CREATE))
+ if ((nd->flags & LOOKUP_CREATE) != 0)
open_flags = nd->intent.open.flags;
lock_kernel();
@@ -1412,7 +1411,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
d_move(dentry, sdentry);
- error = nfs_async_unlink(dentry);
+ error = nfs_async_unlink(dir, dentry);
/* If we return 0 we don't unlink */
}
dput(sdentry);
@@ -1535,7 +1534,7 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
lock_kernel();
- page = alloc_page(GFP_KERNEL);
+ page = alloc_page(GFP_HIGHUSER);
if (!page) {
unlock_kernel();
return -ENOMEM;
@@ -1744,8 +1743,8 @@ int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
struct nfs_inode *nfsi;
struct nfs_access_entry *cache;
- spin_lock(&nfs_access_lru_lock);
restart:
+ spin_lock(&nfs_access_lru_lock);
list_for_each_entry(nfsi, &nfs_access_lru_list, access_cache_inode_lru) {
struct inode *inode;
@@ -1770,6 +1769,7 @@ remove_lru_entry:
clear_bit(NFS_INO_ACL_LRU_SET, &nfsi->flags);
}
spin_unlock(&inode->i_lock);
+ spin_unlock(&nfs_access_lru_lock);
iput(inode);
goto restart;
}
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 00eee87510fe..fcf4d384610e 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -266,7 +266,7 @@ static const struct rpc_call_ops nfs_read_direct_ops = {
static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos)
{
struct nfs_open_context *ctx = dreq->ctx;
- struct inode *inode = ctx->dentry->d_inode;
+ struct inode *inode = ctx->path.dentry->d_inode;
size_t rsize = NFS_SERVER(inode)->rsize;
unsigned int pgbase;
int result;
@@ -295,9 +295,14 @@ static ssize_t nfs_direct_read_schedule(struct nfs_direct_req *dreq, unsigned lo
break;
}
if ((unsigned)result < data->npages) {
- nfs_direct_release_pages(data->pagevec, result);
- nfs_readdata_release(data);
- break;
+ bytes = result * PAGE_SIZE;
+ if (bytes <= pgbase) {
+ nfs_direct_release_pages(data->pagevec, result);
+ nfs_readdata_release(data);
+ break;
+ }
+ bytes -= pgbase;
+ data->npages = result;
}
get_dreq(dreq);
@@ -601,7 +606,7 @@ static const struct rpc_call_ops nfs_write_direct_ops = {
static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned long user_addr, size_t count, loff_t pos, int sync)
{
struct nfs_open_context *ctx = dreq->ctx;
- struct inode *inode = ctx->dentry->d_inode;
+ struct inode *inode = ctx->path.dentry->d_inode;
size_t wsize = NFS_SERVER(inode)->wsize;
unsigned int pgbase;
int result;
@@ -630,9 +635,14 @@ static ssize_t nfs_direct_write_schedule(struct nfs_direct_req *dreq, unsigned l
break;
}
if ((unsigned)result < data->npages) {
- nfs_direct_release_pages(data->pagevec, result);
- nfs_writedata_release(data);
- break;
+ bytes = result * PAGE_SIZE;
+ if (bytes <= pgbase) {
+ nfs_direct_release_pages(data->pagevec, result);
+ nfs_writedata_release(data);
+ break;
+ }
+ bytes -= pgbase;
+ data->npages = result;
}
get_dreq(dreq);
@@ -763,10 +773,8 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
- return -EINVAL;
-
- if (count < 0)
goto out;
+
retval = -EFAULT;
if (!access_ok(VERIFY_WRITE, buf, count))
goto out;
@@ -814,7 +822,7 @@ out:
ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
- ssize_t retval;
+ ssize_t retval = -EINVAL;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
/* XXX: temporary */
@@ -827,7 +835,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
(unsigned long) count, (long long) pos);
if (nr_segs != 1)
- return -EINVAL;
+ goto out;
retval = generic_write_checks(file, &pos, &count, 0);
if (retval)
@@ -867,7 +875,7 @@ int __init nfs_init_directcache(void)
sizeof(struct nfs_direct_req),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- NULL, NULL);
+ NULL);
if (nfs_direct_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 8689b736fdd9..c87dc713b5d7 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -53,6 +53,7 @@ static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_check_flags(int flags);
static int nfs_lock(struct file *filp, int cmd, struct file_lock *fl);
static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl);
+static int nfs_setlease(struct file *file, long arg, struct file_lock **fl);
const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek,
@@ -69,6 +70,7 @@ const struct file_operations nfs_file_operations = {
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
.check_flags = nfs_check_flags,
+ .setlease = nfs_setlease,
};
const struct inode_operations nfs_file_inode_operations = {
@@ -400,7 +402,9 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
lock_kernel();
/* Try local locking first */
- if (posix_test_lock(filp, fl)) {
+ posix_test_lock(filp, fl);
+ if (fl->fl_type != F_UNLCK) {
+ /* found a conflict */
goto out;
}
@@ -558,3 +562,13 @@ static int nfs_flock(struct file *filp, int cmd, struct file_lock *fl)
return do_unlk(filp, cmd, fl);
return do_setlk(filp, cmd, fl);
}
+
+static int nfs_setlease(struct file *file, long arg, struct file_lock **fl)
+{
+ /*
+ * There is no protocol support for leases, so we have no way
+ * to implement them correctly in the face of opens by other
+ * clients.
+ */
+ return -EINVAL;
+}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index bd9f5a836592..bca6cdcb9f0d 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -461,14 +461,14 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) {
- atomic_set(&ctx->count, 1);
- ctx->dentry = dget(dentry);
- ctx->vfsmnt = mntget(mnt);
+ ctx->path.dentry = dget(dentry);
+ ctx->path.mnt = mntget(mnt);
ctx->cred = get_rpccred(cred);
ctx->state = NULL;
ctx->lockowner = current->files;
ctx->error = 0;
ctx->dir_cookie = 0;
+ kref_init(&ctx->kref);
}
return ctx;
}
@@ -476,27 +476,33 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
{
if (ctx != NULL)
- atomic_inc(&ctx->count);
+ kref_get(&ctx->kref);
return ctx;
}
-void put_nfs_open_context(struct nfs_open_context *ctx)
+static void nfs_free_open_context(struct kref *kref)
{
- if (atomic_dec_and_test(&ctx->count)) {
- if (!list_empty(&ctx->list)) {
- struct inode *inode = ctx->dentry->d_inode;
- spin_lock(&inode->i_lock);
- list_del(&ctx->list);
- spin_unlock(&inode->i_lock);
- }
- if (ctx->state != NULL)
- nfs4_close_state(ctx->state, ctx->mode);
- if (ctx->cred != NULL)
- put_rpccred(ctx->cred);
- dput(ctx->dentry);
- mntput(ctx->vfsmnt);
- kfree(ctx);
+ struct nfs_open_context *ctx = container_of(kref,
+ struct nfs_open_context, kref);
+
+ if (!list_empty(&ctx->list)) {
+ struct inode *inode = ctx->path.dentry->d_inode;
+ spin_lock(&inode->i_lock);
+ list_del(&ctx->list);
+ spin_unlock(&inode->i_lock);
}
+ if (ctx->state != NULL)
+ nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
+ if (ctx->cred != NULL)
+ put_rpccred(ctx->cred);
+ dput(ctx->path.dentry);
+ mntput(ctx->path.mnt);
+ kfree(ctx);
+}
+
+void put_nfs_open_context(struct nfs_open_context *ctx)
+{
+ kref_put(&ctx->kref, nfs_free_open_context);
}
/*
@@ -961,8 +967,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
goto out_changed;
server = NFS_SERVER(inode);
- /* Update the fsid if and only if this is the root directory */
- if (inode == inode->i_sb->s_root->d_inode
+ /* Update the fsid? */
+ if (S_ISDIR(inode->i_mode)
&& !nfs_fsid_equal(&server->fsid, &fattr->fsid))
server->fsid = fattr->fsid;
@@ -1066,8 +1072,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
invalid &= ~NFS_INO_INVALID_DATA;
if (data_stable)
invalid &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME|NFS_INO_REVAL_PAGECACHE);
- if (!nfs_have_delegation(inode, FMODE_READ))
+ if (!nfs_have_delegation(inode, FMODE_READ) ||
+ (nfsi->cache_validity & NFS_INO_REVAL_FORCED))
nfsi->cache_validity |= invalid;
+ nfsi->cache_validity &= ~NFS_INO_REVAL_FORCED;
return 0;
out_changed:
@@ -1103,27 +1111,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
*/
void nfs4_clear_inode(struct inode *inode)
{
- struct nfs_inode *nfsi = NFS_I(inode);
-
/* If we are holding a delegation, return it! */
nfs_inode_return_delegation(inode);
/* First call standard NFS clear_inode() code */
nfs_clear_inode(inode);
- /* Now clear out any remaining state */
- while (!list_empty(&nfsi->open_states)) {
- struct nfs4_state *state;
-
- state = list_entry(nfsi->open_states.next,
- struct nfs4_state,
- inode_states);
- dprintk("%s(%s/%Ld): found unclaimed NFSv4 state %p\n",
- __FUNCTION__,
- inode->i_sb->s_id,
- (long long)NFS_FILEID(inode),
- state);
- BUG_ON(atomic_read(&state->count) != 1);
- nfs4_close_state(state, state->state);
- }
}
#endif
@@ -1165,27 +1156,23 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
struct nfs_inode *nfsi = (struct nfs_inode *) foo;
inode_init_once(&nfsi->vfs_inode);
- spin_lock_init(&nfsi->req_lock);
- INIT_LIST_HEAD(&nfsi->dirty);
- INIT_LIST_HEAD(&nfsi->commit);
INIT_LIST_HEAD(&nfsi->open_files);
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
atomic_set(&nfsi->data_updates, 0);
- nfsi->ndirty = 0;
nfsi->ncommit = 0;
nfsi->npages = 0;
nfs4_init_once(nfsi);
}
-
+
static int __init nfs_init_inodecache(void)
{
nfs_inode_cachep = kmem_cache_create("nfs_inode_cache",
sizeof(struct nfs_inode),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (nfs_inode_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index ad2b40db1e65..76cf55d57101 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -183,9 +183,9 @@ unsigned long nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
/*
* Calculate the number of 512byte blocks used.
*/
-static inline unsigned long nfs_calc_block_size(u64 tsize)
+static inline blkcnt_t nfs_calc_block_size(u64 tsize)
{
- loff_t used = (tsize + 511) >> 9;
+ blkcnt_t used = (tsize + 511) >> 9;
return (used > ULONG_MAX) ? ULONG_MAX : used;
}
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index ca5a266a3140..8afd9f7e7a97 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -1,7 +1,5 @@
/*
- * linux/fs/nfs/mount_clnt.c
- *
- * MOUNT client to support NFSroot.
+ * In-kernel MOUNT protocol client
*
* Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
*/
@@ -18,33 +16,31 @@
#include <linux/nfs_fs.h>
#ifdef RPC_DEBUG
-# define NFSDBG_FACILITY NFSDBG_ROOT
+# define NFSDBG_FACILITY NFSDBG_MOUNT
#endif
-/*
-#define MOUNT_PROGRAM 100005
-#define MOUNT_VERSION 1
-#define MOUNT_MNT 1
-#define MOUNT_UMNT 3
- */
-
-static struct rpc_clnt * mnt_create(char *, struct sockaddr_in *,
- int, int);
static struct rpc_program mnt_program;
struct mnt_fhstatus {
- unsigned int status;
- struct nfs_fh * fh;
+ u32 status;
+ struct nfs_fh *fh;
};
-/*
- * Obtain an NFS file handle for the given host and path
+/**
+ * nfs_mount - Obtain an NFS file handle for the given host and path
+ * @addr: pointer to server's address
+ * @len: size of server's address
+ * @hostname: name of server host, or NULL
+ * @path: pointer to string containing export path to mount
+ * @version: mount version to use for this request
+ * @protocol: transport protocol to use for thie request
+ * @fh: pointer to location to place returned file handle
+ *
+ * Uses default timeout parameters specified by underlying transport.
*/
-int
-nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
- int version, int protocol)
+int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path,
+ int version, int protocol, struct nfs_fh *fh)
{
- struct rpc_clnt *mnt_clnt;
struct mnt_fhstatus result = {
.fh = fh
};
@@ -52,16 +48,25 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
.rpc_argp = path,
.rpc_resp = &result,
};
- char hostname[32];
+ struct rpc_create_args args = {
+ .protocol = protocol,
+ .address = addr,
+ .addrsize = len,
+ .servername = hostname,
+ .program = &mnt_program,
+ .version = version,
+ .authflavor = RPC_AUTH_UNIX,
+ .flags = RPC_CLNT_CREATE_INTR,
+ };
+ struct rpc_clnt *mnt_clnt;
int status;
- dprintk("NFS: nfs_mount(%08x:%s)\n",
- (unsigned)ntohl(addr->sin_addr.s_addr), path);
+ dprintk("NFS: sending MNT request for %s:%s\n",
+ (hostname ? hostname : "server"), path);
- sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr));
- mnt_clnt = mnt_create(hostname, addr, version, protocol);
+ mnt_clnt = rpc_create(&args);
if (IS_ERR(mnt_clnt))
- return PTR_ERR(mnt_clnt);
+ goto out_clnt_err;
if (version == NFS_MNT3_VERSION)
msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
@@ -69,33 +74,39 @@ nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT];
status = rpc_call_sync(mnt_clnt, &msg, 0);
- return status < 0? status : (result.status? -EACCES : 0);
-}
+ rpc_shutdown_client(mnt_clnt);
-static struct rpc_clnt *
-mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
- int protocol)
-{
- struct rpc_create_args args = {
- .protocol = protocol,
- .address = (struct sockaddr *)srvaddr,
- .addrsize = sizeof(*srvaddr),
- .servername = hostname,
- .program = &mnt_program,
- .version = version,
- .authflavor = RPC_AUTH_UNIX,
- .flags = (RPC_CLNT_CREATE_ONESHOT |
- RPC_CLNT_CREATE_INTR),
- };
+ if (status < 0)
+ goto out_call_err;
+ if (result.status != 0)
+ goto out_mnt_err;
+
+ dprintk("NFS: MNT request succeeded\n");
+ status = 0;
+
+out:
+ return status;
+
+out_clnt_err:
+ status = PTR_ERR(mnt_clnt);
+ dprintk("NFS: failed to create RPC client, status=%d\n", status);
+ goto out;
+
+out_call_err:
+ dprintk("NFS: failed to start MNT request, status=%d\n", status);
+ goto out;
- return rpc_create(&args);
+out_mnt_err:
+ dprintk("NFS: MNT server returned result %d\n", result.status);
+ status = -EACCES;
+ goto out;
}
/*
* XDR encode/decode functions for MOUNT
*/
-static int
-xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path)
+static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p,
+ const char *path)
{
p = xdr_encode_string(p, path);
@@ -103,8 +114,8 @@ xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path)
return 0;
}
-static int
-xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
+static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p,
+ struct mnt_fhstatus *res)
{
struct nfs_fh *fh = res->fh;
@@ -115,8 +126,8 @@ xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
return 0;
}
-static int
-xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
+static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p,
+ struct mnt_fhstatus *res)
{
struct nfs_fh *fh = res->fh;
@@ -135,53 +146,53 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
#define MNT_fhstatus_sz (1 + 8)
#define MNT_fhstatus3_sz (1 + 16)
-static struct rpc_procinfo mnt_procedures[] = {
-[MNTPROC_MNT] = {
- .p_proc = MNTPROC_MNT,
- .p_encode = (kxdrproc_t) xdr_encode_dirpath,
- .p_decode = (kxdrproc_t) xdr_decode_fhstatus,
- .p_arglen = MNT_dirpath_sz,
- .p_replen = MNT_fhstatus_sz,
- .p_statidx = MNTPROC_MNT,
- .p_name = "MOUNT",
+static struct rpc_procinfo mnt_procedures[] = {
+ [MNTPROC_MNT] = {
+ .p_proc = MNTPROC_MNT,
+ .p_encode = (kxdrproc_t) xdr_encode_dirpath,
+ .p_decode = (kxdrproc_t) xdr_decode_fhstatus,
+ .p_arglen = MNT_dirpath_sz,
+ .p_replen = MNT_fhstatus_sz,
+ .p_statidx = MNTPROC_MNT,
+ .p_name = "MOUNT",
},
};
static struct rpc_procinfo mnt3_procedures[] = {
-[MOUNTPROC3_MNT] = {
- .p_proc = MOUNTPROC3_MNT,
- .p_encode = (kxdrproc_t) xdr_encode_dirpath,
- .p_decode = (kxdrproc_t) xdr_decode_fhstatus3,
- .p_arglen = MNT_dirpath_sz,
- .p_replen = MNT_fhstatus3_sz,
- .p_statidx = MOUNTPROC3_MNT,
- .p_name = "MOUNT",
+ [MOUNTPROC3_MNT] = {
+ .p_proc = MOUNTPROC3_MNT,
+ .p_encode = (kxdrproc_t) xdr_encode_dirpath,
+ .p_decode = (kxdrproc_t) xdr_decode_fhstatus3,
+ .p_arglen = MNT_dirpath_sz,
+ .p_replen = MNT_fhstatus3_sz,
+ .p_statidx = MOUNTPROC3_MNT,
+ .p_name = "MOUNT",
},
};
-static struct rpc_version mnt_version1 = {
- .number = 1,
- .nrprocs = 2,
- .procs = mnt_procedures
+static struct rpc_version mnt_version1 = {
+ .number = 1,
+ .nrprocs = 2,
+ .procs = mnt_procedures,
};
-static struct rpc_version mnt_version3 = {
- .number = 3,
- .nrprocs = 2,
- .procs = mnt3_procedures
+static struct rpc_version mnt_version3 = {
+ .number = 3,
+ .nrprocs = 2,
+ .procs = mnt3_procedures,
};
-static struct rpc_version * mnt_version[] = {
+static struct rpc_version *mnt_version[] = {
NULL,
&mnt_version1,
NULL,
&mnt_version3,
};
-static struct rpc_stat mnt_stats;
+static struct rpc_stat mnt_stats;
-static struct rpc_program mnt_program = {
+static struct rpc_program mnt_program = {
.name = "mount",
.number = NFS_MNT_PROGRAM,
.nrvers = ARRAY_SIZE(mnt_version),
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index cd3ca7b5d3db..c5fce7567200 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -43,6 +43,7 @@
#define NFS_entry_sz (NFS_filename_sz+3)
#define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
+#define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
#define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
#define NFS_readlinkargs_sz (NFS_fhandle_sz)
#define NFS_readargs_sz (NFS_fhandle_sz+3)
@@ -66,7 +67,7 @@
* Common NFS XDR functions as inlines
*/
static inline __be32 *
-xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle)
+xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fhandle)
{
memcpy(p, fhandle->data, NFS2_FHSIZE);
return p + XDR_QUADLEN(NFS2_FHSIZE);
@@ -204,7 +205,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
/*
* Encode directory ops argument
- * LOOKUP, REMOVE, RMDIR
+ * LOOKUP, RMDIR
*/
static int
nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
@@ -216,6 +217,18 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
}
/*
+ * Encode REMOVE argument
+ */
+static int
+nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
+{
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name.name, args->name.len);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+/*
* Arguments to a READ call. Since we read data directly into the page
* cache, we also set up the reply iovec here so that iov[1] points
* exactly to the page we want to fetch.
@@ -223,7 +236,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
static int
nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
u32 offset = (u32)args->offset;
u32 count = args->count;
@@ -380,7 +393,7 @@ static int
nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
{
struct rpc_task *task = req->rq_task;
- struct rpc_auth *auth = task->tk_auth;
+ struct rpc_auth *auth = task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
u32 count = args->count;
@@ -541,7 +554,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
static int
nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
p = xdr_encode_fhandle(p, args->fh);
@@ -705,7 +718,7 @@ struct rpc_procinfo nfs_procedures[] = {
PROC(READ, readargs, readres, 3),
PROC(WRITE, writeargs, writeres, 4),
PROC(CREATE, createargs, diropres, 0),
- PROC(REMOVE, diropargs, stat, 0),
+ PROC(REMOVE, removeargs, stat, 0),
PROC(RENAME, renameargs, stat, 0),
PROC(LINK, linkargs, stat, 0),
PROC(SYMLINK, symlinkargs, stat, 0),
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 45268d6def2e..c7ca5d70870b 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -335,9 +335,7 @@ again:
* not sure this buys us anything (and I'd have
* to revamp the NFSv3 XDR code) */
status = nfs3_proc_setattr(dentry, &fattr, sattr);
- if (status == 0)
- nfs_setattr_update_inode(dentry->d_inode, sattr);
- nfs_refresh_inode(dentry->d_inode, &fattr);
+ nfs_post_op_update_inode(dentry->d_inode, &fattr);
dprintk("NFS reply setattr (post-create): %d\n", status);
}
if (status != 0)
@@ -351,62 +349,42 @@ out:
static int
nfs3_proc_remove(struct inode *dir, struct qstr *name)
{
- struct nfs_fattr dir_attr;
- struct nfs3_diropargs arg = {
- .fh = NFS_FH(dir),
- .name = name->name,
- .len = name->len
+ struct nfs_removeargs arg = {
+ .fh = NFS_FH(dir),
+ .name.len = name->len,
+ .name.name = name->name,
};
- struct rpc_message msg = {
- .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE],
- .rpc_argp = &arg,
- .rpc_resp = &dir_attr,
+ struct nfs_removeres res;
+ struct rpc_message msg = {
+ .rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE],
+ .rpc_argp = &arg,
+ .rpc_resp = &res,
};
int status;
dprintk("NFS call remove %s\n", name->name);
- nfs_fattr_init(&dir_attr);
+ nfs_fattr_init(&res.dir_attr);
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- nfs_post_op_update_inode(dir, &dir_attr);
+ nfs_post_op_update_inode(dir, &res.dir_attr);
dprintk("NFS reply remove: %d\n", status);
return status;
}
-static int
-nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+static void
+nfs3_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
{
- struct unlinkxdr {
- struct nfs3_diropargs arg;
- struct nfs_fattr res;
- } *ptr;
-
- ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return -ENOMEM;
- ptr->arg.fh = NFS_FH(dir->d_inode);
- ptr->arg.name = name->name;
- ptr->arg.len = name->len;
- nfs_fattr_init(&ptr->res);
msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE];
- msg->rpc_argp = &ptr->arg;
- msg->rpc_resp = &ptr->res;
- return 0;
}
static int
-nfs3_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{
- struct rpc_message *msg = &task->tk_msg;
- struct nfs_fattr *dir_attr;
-
- if (nfs3_async_handle_jukebox(task, dir->d_inode))
- return 1;
- if (msg->rpc_argp) {
- dir_attr = (struct nfs_fattr*)msg->rpc_resp;
- nfs_post_op_update_inode(dir->d_inode, dir_attr);
- kfree(msg->rpc_argp);
- }
- return 0;
+ struct nfs_removeres *res;
+ if (nfs3_async_handle_jukebox(task, dir))
+ return 0;
+ res = task->tk_msg.rpc_resp;
+ nfs_post_op_update_inode(dir, &res->dir_attr);
+ return 1;
}
static int
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index b51df8eb9f01..d9e08f0cf2a0 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -50,6 +50,7 @@
#define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
+#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
#define NFS3_accessargs_sz (NFS3_fh_sz+1)
#define NFS3_readlinkargs_sz (NFS3_fh_sz)
#define NFS3_readargs_sz (NFS3_fh_sz+3)
@@ -65,6 +66,7 @@
#define NFS3_attrstat_sz (1+NFS3_fattr_sz)
#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
+#define NFS3_removeres_sz (NFS3_wccstat_sz)
#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
@@ -106,7 +108,7 @@ static struct {
* Common NFS XDR functions as inlines
*/
static inline __be32 *
-xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh)
+xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
{
return xdr_encode_array(p, fh->data, fh->size);
}
@@ -300,6 +302,18 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
}
/*
+ * Encode REMOVE argument
+ */
+static int
+nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
+{
+ p = xdr_encode_fhandle(p, args->fh);
+ p = xdr_encode_array(p, args->name.name, args->name.len);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+ return 0;
+}
+
+/*
* Encode access() argument
*/
static int
@@ -319,7 +333,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *arg
static int
nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
u32 count = args->count;
@@ -458,7 +472,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
static int
nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
u32 count = args->count;
@@ -643,7 +657,7 @@ static int
nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
struct nfs3_getaclargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
p = xdr_encode_fhandle(p, args->fh);
@@ -736,6 +750,12 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
return status;
}
+static int
+nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
+{
+ return nfs3_xdr_wccstat(req, p, &res->dir_attr);
+}
+
/*
* Decode LOOKUP reply
*/
@@ -773,7 +793,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
static int
nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
unsigned int replen;
p = xdr_encode_fhandle(p, args->fh);
@@ -1126,7 +1146,7 @@ struct rpc_procinfo nfs3_procedures[] = {
PROC(MKDIR, mkdirargs, createres, 0),
PROC(SYMLINK, symlinkargs, createres, 0),
PROC(MKNOD, mknodargs, createres, 0),
- PROC(REMOVE, diropargs, wccstat, 0),
+ PROC(REMOVE, removeargs, removeres, 0),
PROC(RMDIR, diropargs, wccstat, 0),
PROC(RENAME, renameargs, renameres, 0),
PROC(LINK, linkargs, linkres, 0),
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index cf3a17eb5c09..d2802b1ca3b9 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -70,19 +70,26 @@ static inline void nfs_confirm_seqid(struct nfs_seqid_counter *seqid, int status
seqid->flags |= NFS_SEQID_CONFIRMED;
}
+struct nfs_unique_id {
+ struct rb_node rb_node;
+ __u64 id;
+};
+
/*
* NFS4 state_owners and lock_owners are simply labels for ordered
* sequences of RPC calls. Their sole purpose is to provide once-only
* semantics by allowing the server to identify replayed requests.
*/
struct nfs4_state_owner {
- spinlock_t so_lock;
- struct list_head so_list; /* per-clientid list of state_owners */
+ struct nfs_unique_id so_owner_id;
struct nfs_client *so_client;
- u32 so_id; /* 32-bit identifier, unique */
- atomic_t so_count;
+ struct nfs_server *so_server;
+ struct rb_node so_client_node;
struct rpc_cred *so_cred; /* Associated cred */
+
+ spinlock_t so_lock;
+ atomic_t so_count;
struct list_head so_states;
struct list_head so_delegations;
struct nfs_seqid_counter so_seqid;
@@ -108,7 +115,7 @@ struct nfs4_lock_state {
#define NFS_LOCK_INITIALIZED 1
int ls_flags;
struct nfs_seqid_counter ls_seqid;
- u32 ls_id;
+ struct nfs_unique_id ls_id;
nfs4_stateid ls_stateid;
atomic_t ls_count;
};
@@ -116,7 +123,10 @@ struct nfs4_lock_state {
/* bits for nfs4_state->flags */
enum {
LK_STATE_IN_USE,
- NFS_DELEGATED_STATE,
+ NFS_DELEGATED_STATE, /* Current stateid is delegation */
+ NFS_O_RDONLY_STATE, /* OPEN stateid has read-only state */
+ NFS_O_WRONLY_STATE, /* OPEN stateid has write-only state */
+ NFS_O_RDWR_STATE, /* OPEN stateid has read/write state */
};
struct nfs4_state {
@@ -130,11 +140,14 @@ struct nfs4_state {
unsigned long flags; /* Do we hold any locks? */
spinlock_t state_lock; /* Protects the lock_states list */
- nfs4_stateid stateid;
+ seqlock_t seqlock; /* Protects the stateid/open_stateid */
+ nfs4_stateid stateid; /* Current stateid: may be delegation */
+ nfs4_stateid open_stateid; /* OPEN stateid */
- unsigned int n_rdonly;
- unsigned int n_wronly;
- unsigned int n_rdwr;
+ /* The following 3 fields are protected by owner->so_lock */
+ unsigned int n_rdonly; /* Number of read-only references */
+ unsigned int n_wronly; /* Number of write-only references */
+ unsigned int n_rdwr; /* Number of read/write references */
int state; /* State on the server (R,W, or RW) */
atomic_t count;
};
@@ -165,11 +178,11 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
-extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state);
+extern int nfs4_do_close(struct path *path, struct nfs4_state *state);
extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
-extern int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name,
+extern int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page);
extern struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops;
@@ -189,14 +202,13 @@ extern void nfs4_renew_state(struct work_struct *);
/* nfs4state.c */
struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
-extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern void nfs4_drop_state_owner(struct nfs4_state_owner *);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
extern void nfs4_put_open_state(struct nfs4_state *);
-extern void nfs4_close_state(struct nfs4_state *, mode_t);
+extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
extern void nfs4_schedule_state_recovery(struct nfs_client *);
extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
@@ -222,7 +234,7 @@ extern struct svc_version nfs4_callback_version1;
#else
-#define nfs4_close_state(a, b) do { } while (0)
+#define nfs4_close_state(a, b, c) do { } while (0)
#endif /* CONFIG_NFS_V4 */
#endif /* __LINUX_FS_NFS_NFS4_FS.H */
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 648e0ac0f90e..6ca2795ccd9c 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -65,6 +65,9 @@ static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *)
static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, struct nfs4_exception *exception);
static int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs_client *clp);
+static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openflags);
+static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
/* Prevent leaks of NFSv4 errors into userland */
int nfs4_map_errors(int err)
@@ -214,27 +217,39 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
}
struct nfs4_opendata {
- atomic_t count;
+ struct kref kref;
struct nfs_openargs o_arg;
struct nfs_openres o_res;
struct nfs_open_confirmargs c_arg;
struct nfs_open_confirmres c_res;
struct nfs_fattr f_attr;
struct nfs_fattr dir_attr;
- struct dentry *dentry;
+ struct path path;
struct dentry *dir;
struct nfs4_state_owner *owner;
+ struct nfs4_state *state;
struct iattr attrs;
unsigned long timestamp;
+ unsigned int rpc_done : 1;
int rpc_status;
int cancelled;
};
-static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
+
+static void nfs4_init_opendata_res(struct nfs4_opendata *p)
+{
+ p->o_res.f_attr = &p->f_attr;
+ p->o_res.dir_attr = &p->dir_attr;
+ p->o_res.server = p->o_arg.server;
+ nfs_fattr_init(&p->f_attr);
+ nfs_fattr_init(&p->dir_attr);
+}
+
+static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
struct nfs4_state_owner *sp, int flags,
const struct iattr *attrs)
{
- struct dentry *parent = dget_parent(dentry);
+ struct dentry *parent = dget_parent(path->dentry);
struct inode *dir = parent->d_inode;
struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_opendata *p;
@@ -245,24 +260,19 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
if (p->o_arg.seqid == NULL)
goto err_free;
- atomic_set(&p->count, 1);
- p->dentry = dget(dentry);
+ p->path.mnt = mntget(path->mnt);
+ p->path.dentry = dget(path->dentry);
p->dir = parent;
p->owner = sp;
atomic_inc(&sp->so_count);
p->o_arg.fh = NFS_FH(dir);
p->o_arg.open_flags = flags,
p->o_arg.clientid = server->nfs_client->cl_clientid;
- p->o_arg.id = sp->so_id;
- p->o_arg.name = &dentry->d_name;
+ p->o_arg.id = sp->so_owner_id.id;
+ p->o_arg.name = &p->path.dentry->d_name;
p->o_arg.server = server;
p->o_arg.bitmask = server->attr_bitmask;
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
- p->o_res.f_attr = &p->f_attr;
- p->o_res.dir_attr = &p->dir_attr;
- p->o_res.server = server;
- nfs_fattr_init(&p->f_attr);
- nfs_fattr_init(&p->dir_attr);
if (flags & O_EXCL) {
u32 *s = (u32 *) p->o_arg.u.verifier.data;
s[0] = jiffies;
@@ -274,6 +284,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->c_arg.fh = &p->o_res.fh;
p->c_arg.stateid = &p->o_res.stateid;
p->c_arg.seqid = p->o_arg.seqid;
+ nfs4_init_opendata_res(p);
+ kref_init(&p->kref);
return p;
err_free:
kfree(p);
@@ -282,27 +294,25 @@ err:
return NULL;
}
-static void nfs4_opendata_free(struct nfs4_opendata *p)
+static void nfs4_opendata_free(struct kref *kref)
{
- if (p != NULL && atomic_dec_and_test(&p->count)) {
- nfs_free_seqid(p->o_arg.seqid);
- nfs4_put_state_owner(p->owner);
- dput(p->dir);
- dput(p->dentry);
- kfree(p);
- }
+ struct nfs4_opendata *p = container_of(kref,
+ struct nfs4_opendata, kref);
+
+ nfs_free_seqid(p->o_arg.seqid);
+ if (p->state != NULL)
+ nfs4_put_open_state(p->state);
+ nfs4_put_state_owner(p->owner);
+ dput(p->dir);
+ dput(p->path.dentry);
+ mntput(p->path.mnt);
+ kfree(p);
}
-/* Helper for asynchronous RPC calls */
-static int nfs4_call_async(struct rpc_clnt *clnt,
- const struct rpc_call_ops *tk_ops, void *calldata)
+static void nfs4_opendata_put(struct nfs4_opendata *p)
{
- struct rpc_task *task;
-
- if (!(task = rpc_new_task(clnt, RPC_TASK_ASYNC, tk_ops, calldata)))
- return -ENOMEM;
- rpc_execute(task);
- return 0;
+ if (p != NULL)
+ kref_put(&p->kref, nfs4_opendata_free);
}
static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
@@ -316,7 +326,34 @@ static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
return ret;
}
-static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_flags)
+static int can_open_cached(struct nfs4_state *state, int mode)
+{
+ int ret = 0;
+ switch (mode & (FMODE_READ|FMODE_WRITE|O_EXCL)) {
+ case FMODE_READ:
+ ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0;
+ ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
+ break;
+ case FMODE_WRITE:
+ ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0;
+ ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
+ break;
+ case FMODE_READ|FMODE_WRITE:
+ ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0;
+ }
+ return ret;
+}
+
+static int can_open_delegated(struct nfs_delegation *delegation, mode_t open_flags)
+{
+ if ((delegation->type & open_flags) != open_flags)
+ return 0;
+ if (delegation->flags & NFS_DELEGATION_NEED_RECLAIM)
+ return 0;
+ return 1;
+}
+
+static void update_open_stateflags(struct nfs4_state *state, mode_t open_flags)
{
switch (open_flags) {
case FMODE_WRITE:
@@ -328,41 +365,176 @@ static inline void update_open_stateflags(struct nfs4_state *state, mode_t open_
case FMODE_READ|FMODE_WRITE:
state->n_rdwr++;
}
+ nfs4_state_set_mode_locked(state, state->state | open_flags);
}
-static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
+static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
{
- struct inode *inode = state->inode;
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
+ memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data));
+ memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data));
+ switch (open_flags) {
+ case FMODE_READ:
+ set_bit(NFS_O_RDONLY_STATE, &state->flags);
+ break;
+ case FMODE_WRITE:
+ set_bit(NFS_O_WRONLY_STATE, &state->flags);
+ break;
+ case FMODE_READ|FMODE_WRITE:
+ set_bit(NFS_O_RDWR_STATE, &state->flags);
+ }
+}
+
+static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
+{
+ write_seqlock(&state->seqlock);
+ nfs_set_open_stateid_locked(state, stateid, open_flags);
+ write_sequnlock(&state->seqlock);
+}
+static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
+{
open_flags &= (FMODE_READ|FMODE_WRITE);
- /* Protect against nfs4_find_state_byowner() */
+ /*
+ * Protect the call to nfs4_state_set_mode_locked and
+ * serialise the stateid update
+ */
+ write_seqlock(&state->seqlock);
+ if (deleg_stateid != NULL) {
+ memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
+ set_bit(NFS_DELEGATED_STATE, &state->flags);
+ }
+ if (open_stateid != NULL)
+ nfs_set_open_stateid_locked(state, open_stateid, open_flags);
+ write_sequnlock(&state->seqlock);
spin_lock(&state->owner->so_lock);
- spin_lock(&inode->i_lock);
- memcpy(&state->stateid, stateid, sizeof(state->stateid));
update_open_stateflags(state, open_flags);
- nfs4_state_set_mode_locked(state, state->state | open_flags);
- spin_unlock(&inode->i_lock);
spin_unlock(&state->owner->so_lock);
}
+static void nfs4_return_incompatible_delegation(struct inode *inode, mode_t open_flags)
+{
+ struct nfs_delegation *delegation;
+
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(inode)->delegation);
+ if (delegation == NULL || (delegation->type & open_flags) == open_flags) {
+ rcu_read_unlock();
+ return;
+ }
+ rcu_read_unlock();
+ nfs_inode_return_delegation(inode);
+}
+
+static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
+{
+ struct nfs4_state *state = opendata->state;
+ struct nfs_inode *nfsi = NFS_I(state->inode);
+ struct nfs_delegation *delegation;
+ int open_mode = opendata->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL);
+ nfs4_stateid stateid;
+ int ret = -EAGAIN;
+
+ rcu_read_lock();
+ delegation = rcu_dereference(nfsi->delegation);
+ for (;;) {
+ if (can_open_cached(state, open_mode)) {
+ spin_lock(&state->owner->so_lock);
+ if (can_open_cached(state, open_mode)) {
+ update_open_stateflags(state, open_mode);
+ spin_unlock(&state->owner->so_lock);
+ rcu_read_unlock();
+ goto out_return_state;
+ }
+ spin_unlock(&state->owner->so_lock);
+ }
+ if (delegation == NULL)
+ break;
+ if (!can_open_delegated(delegation, open_mode))
+ break;
+ /* Save the delegation */
+ memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
+ rcu_read_unlock();
+ lock_kernel();
+ ret = _nfs4_do_access(state->inode, state->owner->so_cred, open_mode);
+ unlock_kernel();
+ if (ret != 0)
+ goto out;
+ ret = -EAGAIN;
+ rcu_read_lock();
+ delegation = rcu_dereference(nfsi->delegation);
+ /* If no delegation, try a cached open */
+ if (delegation == NULL)
+ continue;
+ /* Is the delegation still valid? */
+ if (memcmp(stateid.data, delegation->stateid.data, sizeof(stateid.data)) != 0)
+ continue;
+ rcu_read_unlock();
+ update_open_stateid(state, NULL, &stateid, open_mode);
+ goto out_return_state;
+ }
+ rcu_read_unlock();
+out:
+ return ERR_PTR(ret);
+out_return_state:
+ atomic_inc(&state->count);
+ return state;
+}
+
static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
{
struct inode *inode;
struct nfs4_state *state = NULL;
+ struct nfs_delegation *delegation;
+ nfs4_stateid *deleg_stateid = NULL;
+ int ret;
- if (!(data->f_attr.valid & NFS_ATTR_FATTR))
+ if (!data->rpc_done) {
+ state = nfs4_try_open_cached(data);
goto out;
+ }
+
+ ret = -EAGAIN;
+ if (!(data->f_attr.valid & NFS_ATTR_FATTR))
+ goto err;
inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
+ ret = PTR_ERR(inode);
if (IS_ERR(inode))
- goto out;
+ goto err;
+ ret = -ENOMEM;
state = nfs4_get_open_state(inode, data->owner);
if (state == NULL)
- goto put_inode;
- update_open_stateid(state, &data->o_res.stateid, data->o_arg.open_flags);
-put_inode:
+ goto err_put_inode;
+ if (data->o_res.delegation_type != 0) {
+ int delegation_flags = 0;
+
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(inode)->delegation);
+ if (delegation)
+ delegation_flags = delegation->flags;
+ rcu_read_unlock();
+ if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))
+ nfs_inode_set_delegation(state->inode,
+ data->owner->so_cred,
+ &data->o_res);
+ else
+ nfs_inode_reclaim_delegation(state->inode,
+ data->owner->so_cred,
+ &data->o_res);
+ }
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(inode)->delegation);
+ if (delegation != NULL)
+ deleg_stateid = &delegation->stateid;
+ update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags);
+ rcu_read_unlock();
iput(inode);
out:
return state;
+err_put_inode:
+ iput(inode);
+err:
+ return ERR_PTR(ret);
}
static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
@@ -382,79 +554,78 @@ static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *
return ERR_PTR(-ENOENT);
}
-static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, nfs4_stateid *stateid)
+static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state)
{
+ struct nfs4_opendata *opendata;
+
+ opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
+ if (opendata == NULL)
+ return ERR_PTR(-ENOMEM);
+ opendata->state = state;
+ atomic_inc(&state->count);
+ return opendata;
+}
+
+static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res)
+{
+ struct nfs4_state *newstate;
int ret;
opendata->o_arg.open_flags = openflags;
+ memset(&opendata->o_res, 0, sizeof(opendata->o_res));
+ memset(&opendata->c_res, 0, sizeof(opendata->c_res));
+ nfs4_init_opendata_res(opendata);
ret = _nfs4_proc_open(opendata);
if (ret != 0)
return ret;
- memcpy(stateid->data, opendata->o_res.stateid.data,
- sizeof(stateid->data));
+ newstate = nfs4_opendata_to_nfs4_state(opendata);
+ if (IS_ERR(newstate))
+ return PTR_ERR(newstate);
+ nfs4_close_state(&opendata->path, newstate, openflags);
+ *res = newstate;
return 0;
}
static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
{
- nfs4_stateid stateid;
struct nfs4_state *newstate;
- int mode = 0;
- int delegation = 0;
int ret;
/* memory barrier prior to reading state->n_* */
+ clear_bit(NFS_DELEGATED_STATE, &state->flags);
smp_rmb();
if (state->n_rdwr != 0) {
- ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &stateid);
+ ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
if (ret != 0)
return ret;
- mode |= FMODE_READ|FMODE_WRITE;
- if (opendata->o_res.delegation_type != 0)
- delegation = opendata->o_res.delegation_type;
- smp_rmb();
+ if (newstate != state)
+ return -ESTALE;
}
if (state->n_wronly != 0) {
- ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &stateid);
+ ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
if (ret != 0)
return ret;
- mode |= FMODE_WRITE;
- if (opendata->o_res.delegation_type != 0)
- delegation = opendata->o_res.delegation_type;
- smp_rmb();
+ if (newstate != state)
+ return -ESTALE;
}
if (state->n_rdonly != 0) {
- ret = nfs4_open_recover_helper(opendata, FMODE_READ, &stateid);
+ ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
if (ret != 0)
return ret;
- mode |= FMODE_READ;
+ if (newstate != state)
+ return -ESTALE;
}
- clear_bit(NFS_DELEGATED_STATE, &state->flags);
- if (mode == 0)
- return 0;
- if (opendata->o_res.delegation_type == 0)
- opendata->o_res.delegation_type = delegation;
- opendata->o_arg.open_flags |= mode;
- newstate = nfs4_opendata_to_nfs4_state(opendata);
- if (newstate != NULL) {
- if (opendata->o_res.delegation_type != 0) {
- struct nfs_inode *nfsi = NFS_I(newstate->inode);
- int delegation_flags = 0;
- if (nfsi->delegation)
- delegation_flags = nfsi->delegation->flags;
- if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM))
- nfs_inode_set_delegation(newstate->inode,
- opendata->owner->so_cred,
- &opendata->o_res);
- else
- nfs_inode_reclaim_delegation(newstate->inode,
- opendata->owner->so_cred,
- &opendata->o_res);
- }
- nfs4_close_state(newstate, opendata->o_arg.open_flags);
+ /*
+ * We may have performed cached opens for all three recoveries.
+ * Check if we need to update the current stateid.
+ */
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
+ memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {
+ write_seqlock(&state->seqlock);
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
+ memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));
+ write_sequnlock(&state->seqlock);
}
- if (newstate != state)
- return -ESTALE;
return 0;
}
@@ -462,41 +633,36 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
* OPEN_RECLAIM:
* reclaim state on the server after a reboot.
*/
-static int _nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
{
- struct nfs_delegation *delegation = NFS_I(state->inode)->delegation;
+ struct nfs_delegation *delegation;
struct nfs4_opendata *opendata;
int delegation_type = 0;
int status;
- if (delegation != NULL) {
- if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
- memcpy(&state->stateid, &delegation->stateid,
- sizeof(state->stateid));
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- return 0;
- }
- delegation_type = delegation->type;
- }
- opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL);
- if (opendata == NULL)
- return -ENOMEM;
+ opendata = nfs4_open_recoverdata_alloc(ctx, state);
+ if (IS_ERR(opendata))
+ return PTR_ERR(opendata);
opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
opendata->o_arg.fh = NFS_FH(state->inode);
- nfs_copy_fh(&opendata->o_res.fh, opendata->o_arg.fh);
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(state->inode)->delegation);
+ if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0)
+ delegation_type = delegation->flags;
+ rcu_read_unlock();
opendata->o_arg.u.delegation_type = delegation_type;
status = nfs4_open_recover(opendata, state);
- nfs4_opendata_free(opendata);
+ nfs4_opendata_put(opendata);
return status;
}
-static int nfs4_do_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_exception exception = { };
int err;
do {
- err = _nfs4_do_open_reclaim(sp, state, dentry);
+ err = _nfs4_do_open_reclaim(ctx, state);
if (err != -NFS4ERR_DELAY)
break;
nfs4_handle_exception(server, err, &exception);
@@ -512,37 +678,34 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
ctx = nfs4_state_find_open_context(state);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ret = nfs4_do_open_reclaim(sp, state, ctx->dentry);
+ ret = nfs4_do_open_reclaim(ctx, state);
put_nfs_open_context(ctx);
return ret;
}
-static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
+static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
{
- struct nfs4_state_owner *sp = state->owner;
struct nfs4_opendata *opendata;
int ret;
- if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
- return 0;
- opendata = nfs4_opendata_alloc(dentry, sp, 0, NULL);
- if (opendata == NULL)
- return -ENOMEM;
+ opendata = nfs4_open_recoverdata_alloc(ctx, state);
+ if (IS_ERR(opendata))
+ return PTR_ERR(opendata);
opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
- memcpy(opendata->o_arg.u.delegation.data, state->stateid.data,
+ memcpy(opendata->o_arg.u.delegation.data, stateid->data,
sizeof(opendata->o_arg.u.delegation.data));
ret = nfs4_open_recover(opendata, state);
- nfs4_opendata_free(opendata);
+ nfs4_opendata_put(opendata);
return ret;
}
-int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
+int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
{
struct nfs4_exception exception = { };
- struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+ struct nfs_server *server = NFS_SERVER(state->inode);
int err;
do {
- err = _nfs4_open_delegation_recall(dentry, state);
+ err = _nfs4_open_delegation_recall(ctx, state, stateid);
switch (err) {
case 0:
return err;
@@ -582,9 +745,10 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
sizeof(data->o_res.stateid.data));
renew_lease(data->o_res.server, data->timestamp);
+ data->rpc_done = 1;
}
- nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid);
nfs_confirm_seqid(&data->owner->so_seqid, data->rpc_status);
+ nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid);
}
static void nfs4_open_confirm_release(void *calldata)
@@ -596,14 +760,14 @@ static void nfs4_open_confirm_release(void *calldata)
if (data->cancelled == 0)
goto out_free;
/* In case of error, no cleanup! */
- if (data->rpc_status != 0)
+ if (!data->rpc_done)
goto out_free;
nfs_confirm_seqid(&data->owner->so_seqid, 0);
state = nfs4_opendata_to_nfs4_state(data);
- if (state != NULL)
- nfs4_close_state(state, data->o_arg.open_flags);
+ if (!IS_ERR(state))
+ nfs4_close_state(&data->path, state, data->o_arg.open_flags);
out_free:
- nfs4_opendata_free(data);
+ nfs4_opendata_put(data);
}
static const struct rpc_call_ops nfs4_open_confirm_ops = {
@@ -621,12 +785,9 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
struct rpc_task *task;
int status;
- atomic_inc(&data->count);
- /*
- * If rpc_run_task() ends up calling ->rpc_release(), we
- * want to ensure that it takes the 'error' code path.
- */
- data->rpc_status = -ENOMEM;
+ kref_get(&data->kref);
+ data->rpc_done = 0;
+ data->rpc_status = 0;
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data);
if (IS_ERR(task))
return PTR_ERR(task);
@@ -653,13 +814,37 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
return;
+ /*
+ * Check if we still need to send an OPEN call, or if we can use
+ * a delegation instead.
+ */
+ if (data->state != NULL) {
+ struct nfs_delegation *delegation;
+
+ if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL)))
+ goto out_no_action;
+ rcu_read_lock();
+ delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
+ if (delegation != NULL &&
+ (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) {
+ rcu_read_unlock();
+ goto out_no_action;
+ }
+ rcu_read_unlock();
+ }
/* Update sequence id. */
- data->o_arg.id = sp->so_id;
+ data->o_arg.id = sp->so_owner_id.id;
data->o_arg.clientid = sp->so_client->cl_clientid;
- if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
+ if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
+ nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
+ }
data->timestamp = jiffies;
rpc_call_setup(task, &msg, 0);
+ return;
+out_no_action:
+ task->tk_action = NULL;
+
}
static void nfs4_open_done(struct rpc_task *task, void *calldata)
@@ -683,8 +868,11 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
data->rpc_status = -ENOTDIR;
}
renew_lease(data->o_res.server, data->timestamp);
+ if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
+ nfs_confirm_seqid(&data->owner->so_seqid, 0);
}
nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid);
+ data->rpc_done = 1;
}
static void nfs4_open_release(void *calldata)
@@ -696,17 +884,17 @@ static void nfs4_open_release(void *calldata)
if (data->cancelled == 0)
goto out_free;
/* In case of error, no cleanup! */
- if (data->rpc_status != 0)
+ if (data->rpc_status != 0 || !data->rpc_done)
goto out_free;
/* In case we need an open_confirm, no cleanup! */
if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
goto out_free;
nfs_confirm_seqid(&data->owner->so_seqid, 0);
state = nfs4_opendata_to_nfs4_state(data);
- if (state != NULL)
- nfs4_close_state(state, data->o_arg.open_flags);
+ if (!IS_ERR(state))
+ nfs4_close_state(&data->path, state, data->o_arg.open_flags);
out_free:
- nfs4_opendata_free(data);
+ nfs4_opendata_put(data);
}
static const struct rpc_call_ops nfs4_open_ops = {
@@ -727,12 +915,10 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
struct rpc_task *task;
int status;
- atomic_inc(&data->count);
- /*
- * If rpc_run_task() ends up calling ->rpc_release(), we
- * want to ensure that it takes the 'error' code path.
- */
- data->rpc_status = -ENOMEM;
+ kref_get(&data->kref);
+ data->rpc_done = 0;
+ data->rpc_status = 0;
+ data->cancelled = 0;
task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data);
if (IS_ERR(task))
return PTR_ERR(task);
@@ -743,9 +929,12 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
} else
status = data->rpc_status;
rpc_put_task(task);
- if (status != 0)
+ if (status != 0 || !data->rpc_done)
return status;
+ if (o_res->fh.size == 0)
+ _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr);
+
if (o_arg->open_flags & O_CREAT) {
update_changeattr(dir, &o_res->cinfo);
nfs_post_op_update_inode(dir, o_res->dir_attr);
@@ -756,9 +945,8 @@ static int _nfs4_proc_open(struct nfs4_opendata *data)
if (status != 0)
return status;
}
- nfs_confirm_seqid(&data->owner->so_seqid, 0);
if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
- return server->nfs_client->rpc_ops->getattr(server, &o_res->fh, o_res->f_attr);
+ _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);
return 0;
}
@@ -772,6 +960,8 @@ static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int openf
mask |= MAY_READ;
if (openflags & FMODE_WRITE)
mask |= MAY_WRITE;
+ if (openflags & FMODE_EXEC)
+ mask |= MAY_EXEC;
status = nfs_access_get_cached(inode, cred, &cache);
if (status == 0)
goto out;
@@ -811,43 +1001,32 @@ static int nfs4_recover_expired_lease(struct nfs_server *server)
* reclaim state on the server after a network partition.
* Assumes caller holds the appropriate lock
*/
-static int _nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
{
- struct inode *inode = state->inode;
- struct nfs_delegation *delegation = NFS_I(inode)->delegation;
struct nfs4_opendata *opendata;
- int openflags = state->state & (FMODE_READ|FMODE_WRITE);
int ret;
- if (delegation != NULL && !(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
- ret = _nfs4_do_access(inode, sp->so_cred, openflags);
- if (ret < 0)
- return ret;
- memcpy(&state->stateid, &delegation->stateid, sizeof(state->stateid));
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- return 0;
- }
- opendata = nfs4_opendata_alloc(dentry, sp, openflags, NULL);
- if (opendata == NULL)
- return -ENOMEM;
+ opendata = nfs4_open_recoverdata_alloc(ctx, state);
+ if (IS_ERR(opendata))
+ return PTR_ERR(opendata);
ret = nfs4_open_recover(opendata, state);
if (ret == -ESTALE) {
/* Invalidate the state owner so we don't ever use it again */
- nfs4_drop_state_owner(sp);
- d_drop(dentry);
+ nfs4_drop_state_owner(state->owner);
+ d_drop(ctx->path.dentry);
}
- nfs4_opendata_free(opendata);
+ nfs4_opendata_put(opendata);
return ret;
}
-static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
{
- struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+ struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_exception exception = { };
int err;
do {
- err = _nfs4_open_expired(sp, state, dentry);
+ err = _nfs4_open_expired(ctx, state);
if (err == -NFS4ERR_DELAY)
nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
@@ -862,107 +1041,38 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
ctx = nfs4_state_find_open_context(state);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ret = nfs4_do_open_expired(sp, state, ctx->dentry);
+ ret = nfs4_do_open_expired(ctx, state);
put_nfs_open_context(ctx);
return ret;
}
/*
- * Returns a referenced nfs4_state if there is an open delegation on the file
+ * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
+ * fields corresponding to attributes that were used to store the verifier.
+ * Make sure we clobber those fields in the later setattr call
*/
-static int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res)
+static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr)
{
- struct nfs_delegation *delegation;
- struct nfs_server *server = NFS_SERVER(inode);
- struct nfs_client *clp = server->nfs_client;
- struct nfs_inode *nfsi = NFS_I(inode);
- struct nfs4_state_owner *sp = NULL;
- struct nfs4_state *state = NULL;
- int open_flags = flags & (FMODE_READ|FMODE_WRITE);
- int err;
+ if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
+ !(sattr->ia_valid & ATTR_ATIME_SET))
+ sattr->ia_valid |= ATTR_ATIME;
- err = -ENOMEM;
- if (!(sp = nfs4_get_state_owner(server, cred))) {
- dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__);
- return err;
- }
- err = nfs4_recover_expired_lease(server);
- if (err != 0)
- goto out_put_state_owner;
- /* Protect against reboot recovery - NOTE ORDER! */
- down_read(&clp->cl_sem);
- /* Protect against delegation recall */
- down_read(&nfsi->rwsem);
- delegation = NFS_I(inode)->delegation;
- err = -ENOENT;
- if (delegation == NULL || (delegation->type & open_flags) != open_flags)
- goto out_err;
- err = -ENOMEM;
- state = nfs4_get_open_state(inode, sp);
- if (state == NULL)
- goto out_err;
-
- err = -ENOENT;
- if ((state->state & open_flags) == open_flags) {
- spin_lock(&inode->i_lock);
- update_open_stateflags(state, open_flags);
- spin_unlock(&inode->i_lock);
- goto out_ok;
- } else if (state->state != 0)
- goto out_put_open_state;
-
- lock_kernel();
- err = _nfs4_do_access(inode, cred, open_flags);
- unlock_kernel();
- if (err != 0)
- goto out_put_open_state;
- set_bit(NFS_DELEGATED_STATE, &state->flags);
- update_open_stateid(state, &delegation->stateid, open_flags);
-out_ok:
- nfs4_put_state_owner(sp);
- up_read(&nfsi->rwsem);
- up_read(&clp->cl_sem);
- *res = state;
- return 0;
-out_put_open_state:
- nfs4_put_open_state(state);
-out_err:
- up_read(&nfsi->rwsem);
- up_read(&clp->cl_sem);
- if (err != -EACCES)
- nfs_inode_return_delegation(inode);
-out_put_state_owner:
- nfs4_put_state_owner(sp);
- return err;
-}
-
-static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred)
-{
- struct nfs4_exception exception = { };
- struct nfs4_state *res = ERR_PTR(-EIO);
- int err;
-
- do {
- err = _nfs4_open_delegated(inode, flags, cred, &res);
- if (err == 0)
- break;
- res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(inode),
- err, &exception));
- } while (exception.retry);
- return res;
+ if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
+ !(sattr->ia_valid & ATTR_MTIME_SET))
+ sattr->ia_valid |= ATTR_MTIME;
}
/*
* Returns a referenced nfs4_state
*/
-static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
+static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
{
struct nfs4_state_owner *sp;
struct nfs4_state *state = NULL;
struct nfs_server *server = NFS_SERVER(dir);
struct nfs_client *clp = server->nfs_client;
struct nfs4_opendata *opendata;
- int status;
+ int status;
/* Protect against reboot recovery conflicts */
status = -ENOMEM;
@@ -973,29 +1083,35 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
status = nfs4_recover_expired_lease(server);
if (status != 0)
goto err_put_state_owner;
+ if (path->dentry->d_inode != NULL)
+ nfs4_return_incompatible_delegation(path->dentry->d_inode, flags & (FMODE_READ|FMODE_WRITE));
down_read(&clp->cl_sem);
status = -ENOMEM;
- opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr);
+ opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
if (opendata == NULL)
goto err_release_rwsem;
+ if (path->dentry->d_inode != NULL)
+ opendata->state = nfs4_get_open_state(path->dentry->d_inode, sp);
+
status = _nfs4_proc_open(opendata);
if (status != 0)
- goto err_opendata_free;
+ goto err_opendata_put;
+
+ if (opendata->o_arg.open_flags & O_EXCL)
+ nfs4_exclusive_attrset(opendata, sattr);
- status = -ENOMEM;
state = nfs4_opendata_to_nfs4_state(opendata);
- if (state == NULL)
- goto err_opendata_free;
- if (opendata->o_res.delegation_type != 0)
- nfs_inode_set_delegation(state->inode, cred, &opendata->o_res);
- nfs4_opendata_free(opendata);
+ status = PTR_ERR(state);
+ if (IS_ERR(state))
+ goto err_opendata_put;
+ nfs4_opendata_put(opendata);
nfs4_put_state_owner(sp);
up_read(&clp->cl_sem);
*res = state;
return 0;
-err_opendata_free:
- nfs4_opendata_free(opendata);
+err_opendata_put:
+ nfs4_opendata_put(opendata);
err_release_rwsem:
up_read(&clp->cl_sem);
err_put_state_owner:
@@ -1006,14 +1122,14 @@ out_err:
}
-static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred)
+static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
{
struct nfs4_exception exception = { };
struct nfs4_state *res;
int status;
do {
- status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res);
+ status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
if (status == 0)
break;
/* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1028,7 +1144,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry,
* the user though...
*/
if (status == -NFS4ERR_BAD_SEQID) {
- printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n");
+ printk(KERN_WARNING "NFS: v4 server %s "
+ " returned a bad sequence-id error!\n",
+ NFS_SERVER(dir)->nfs_client->cl_hostname);
exception.retry = 1;
continue;
}
@@ -1042,6 +1160,11 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry,
exception.retry = 1;
continue;
}
+ if (status == -EAGAIN) {
+ /* We must have found a delegation */
+ exception.retry = 1;
+ continue;
+ }
res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir),
status, &exception));
} while (exception.retry);
@@ -1101,6 +1224,7 @@ static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
}
struct nfs4_closedata {
+ struct path path;
struct inode *inode;
struct nfs4_state *state;
struct nfs_closeargs arg;
@@ -1117,6 +1241,8 @@ static void nfs4_free_closedata(void *data)
nfs4_put_open_state(calldata->state);
nfs_free_seqid(calldata->arg.seqid);
nfs4_put_state_owner(sp);
+ dput(calldata->path.dentry);
+ mntput(calldata->path.mnt);
kfree(calldata);
}
@@ -1134,8 +1260,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
nfs_increment_open_seqid(task->tk_status, calldata->arg.seqid);
switch (task->tk_status) {
case 0:
- memcpy(&state->stateid, &calldata->res.stateid,
- sizeof(state->stateid));
+ nfs_set_open_stateid(state, &calldata->res.stateid, calldata->arg.open_flags);
renew_lease(server, calldata->timestamp);
break;
case -NFS4ERR_STALE_STATEID:
@@ -1160,26 +1285,30 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
.rpc_resp = &calldata->res,
.rpc_cred = state->owner->so_cred,
};
- int mode = 0, old_mode;
+ int clear_rd, clear_wr, clear_rdwr;
+ int mode;
if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
return;
- /* Recalculate the new open mode in case someone reopened the file
- * while we were waiting in line to be scheduled.
- */
+
+ mode = FMODE_READ|FMODE_WRITE;
+ clear_rd = clear_wr = clear_rdwr = 0;
spin_lock(&state->owner->so_lock);
- spin_lock(&calldata->inode->i_lock);
- mode = old_mode = state->state;
+ /* Calculate the change in open mode */
if (state->n_rdwr == 0) {
- if (state->n_rdonly == 0)
+ if (state->n_rdonly == 0) {
mode &= ~FMODE_READ;
- if (state->n_wronly == 0)
+ clear_rd |= test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+ clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
+ }
+ if (state->n_wronly == 0) {
mode &= ~FMODE_WRITE;
+ clear_wr |= test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+ clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
+ }
}
- nfs4_state_set_mode_locked(state, mode);
- spin_unlock(&calldata->inode->i_lock);
spin_unlock(&state->owner->so_lock);
- if (mode == old_mode || test_bit(NFS_DELEGATED_STATE, &state->flags)) {
+ if (!clear_rd && !clear_wr && !clear_rdwr) {
/* Note: exit _without_ calling nfs4_close_done */
task->tk_action = NULL;
return;
@@ -1209,19 +1338,21 @@ static const struct rpc_call_ops nfs4_close_ops = {
*
* NOTE: Caller must be holding the sp->so_owner semaphore!
*/
-int nfs4_do_close(struct inode *inode, struct nfs4_state *state)
+int nfs4_do_close(struct path *path, struct nfs4_state *state)
{
- struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_closedata *calldata;
+ struct nfs4_state_owner *sp = state->owner;
+ struct rpc_task *task;
int status = -ENOMEM;
calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);
if (calldata == NULL)
goto out;
- calldata->inode = inode;
+ calldata->inode = state->inode;
calldata->state = state;
- calldata->arg.fh = NFS_FH(inode);
- calldata->arg.stateid = &state->stateid;
+ calldata->arg.fh = NFS_FH(state->inode);
+ calldata->arg.stateid = &state->open_stateid;
/* Serialization for the sequence id */
calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
if (calldata->arg.seqid == NULL)
@@ -1229,36 +1360,55 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state)
calldata->arg.bitmask = server->attr_bitmask;
calldata->res.fattr = &calldata->fattr;
calldata->res.server = server;
+ calldata->path.mnt = mntget(path->mnt);
+ calldata->path.dentry = dget(path->dentry);
- status = nfs4_call_async(server->client, &nfs4_close_ops, calldata);
- if (status == 0)
- goto out;
-
- nfs_free_seqid(calldata->arg.seqid);
+ task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_close_ops, calldata);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ rpc_put_task(task);
+ return 0;
out_free_calldata:
kfree(calldata);
out:
+ nfs4_put_open_state(state);
+ nfs4_put_state_owner(sp);
return status;
}
-static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state)
+static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state)
{
struct file *filp;
+ int ret;
- filp = lookup_instantiate_filp(nd, dentry, NULL);
+ /* If the open_intent is for execute, we have an extra check to make */
+ if (nd->intent.open.flags & FMODE_EXEC) {
+ ret = _nfs4_do_access(state->inode,
+ state->owner->so_cred,
+ nd->intent.open.flags);
+ if (ret < 0)
+ goto out_close;
+ }
+ filp = lookup_instantiate_filp(nd, path->dentry, NULL);
if (!IS_ERR(filp)) {
struct nfs_open_context *ctx;
ctx = (struct nfs_open_context *)filp->private_data;
ctx->state = state;
return 0;
}
- nfs4_close_state(state, nd->intent.open.flags);
- return PTR_ERR(filp);
+ ret = PTR_ERR(filp);
+out_close:
+ nfs4_close_state(path, state, nd->intent.open.flags);
+ return ret;
}
struct dentry *
nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
+ struct path path = {
+ .mnt = nd->mnt,
+ .dentry = dentry,
+ };
struct iattr attr;
struct rpc_cred *cred;
struct nfs4_state *state;
@@ -1277,7 +1427,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
if (IS_ERR(cred))
return (struct dentry *)cred;
- state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred);
+ state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
if (PTR_ERR(state) == -ENOENT)
@@ -1287,22 +1437,24 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
res = d_add_unique(dentry, igrab(state->inode));
if (res != NULL)
dentry = res;
- nfs4_intent_set_file(nd, dentry, state);
+ nfs4_intent_set_file(nd, &path, state);
return res;
}
int
nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd)
{
+ struct path path = {
+ .mnt = nd->mnt,
+ .dentry = dentry,
+ };
struct rpc_cred *cred;
struct nfs4_state *state;
cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
if (IS_ERR(cred))
return PTR_ERR(cred);
- state = nfs4_open_delegated(dentry->d_inode, openflags, cred);
- if (IS_ERR(state))
- state = nfs4_do_open(dir, dentry, openflags, NULL, cred);
+ state = nfs4_do_open(dir, &path, openflags, NULL, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
switch (PTR_ERR(state)) {
@@ -1318,10 +1470,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
}
}
if (state->inode == dentry->d_inode) {
- nfs4_intent_set_file(nd, dentry, state);
+ nfs4_intent_set_file(nd, &path, state);
return 1;
}
- nfs4_close_state(state, openflags);
+ nfs4_close_state(&path, state, openflags);
out_drop:
d_drop(dentry);
return 0;
@@ -1418,7 +1570,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
* Note that we'll actually follow the referral later when
* we detect fsid mismatch in inode revalidation
*/
-static int nfs4_get_referral(struct inode *dir, struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
+static int nfs4_get_referral(struct inode *dir, const struct qstr *name, struct nfs_fattr *fattr, struct nfs_fh *fhandle)
{
int status = -ENOMEM;
struct page *page = NULL;
@@ -1533,8 +1685,8 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
return status;
}
-static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
- struct qstr *name, struct nfs_fh *fhandle,
+static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *dirfh,
+ const struct qstr *name, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
int status;
@@ -1559,8 +1711,6 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
dprintk("NFS call lookupfh %s\n", name->name);
status = rpc_call_sync(server->client, &msg, 0);
dprintk("NFS reply lookupfh: %d\n", status);
- if (status == -NFS4ERR_MOVED)
- status = -EREMOTE;
return status;
}
@@ -1571,39 +1721,24 @@ static int nfs4_proc_lookupfh(struct nfs_server *server, struct nfs_fh *dirfh,
struct nfs4_exception exception = { };
int err;
do {
- err = nfs4_handle_exception(server,
- _nfs4_proc_lookupfh(server, dirfh, name,
- fhandle, fattr),
- &exception);
+ err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr);
+ /* FIXME: !!!! */
+ if (err == -NFS4ERR_MOVED) {
+ err = -EREMOTE;
+ break;
+ }
+ err = nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
-static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
+static int _nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
- int status;
- struct nfs_server *server = NFS_SERVER(dir);
- struct nfs4_lookup_arg args = {
- .bitmask = server->attr_bitmask,
- .dir_fh = NFS_FH(dir),
- .name = name,
- };
- struct nfs4_lookup_res res = {
- .server = server,
- .fattr = fattr,
- .fh = fhandle,
- };
- struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
- .rpc_argp = &args,
- .rpc_resp = &res,
- };
-
- nfs_fattr_init(fattr);
+ int status;
dprintk("NFS call lookup %s\n", name->name);
- status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+ status = _nfs4_proc_lookupfh(NFS_SERVER(dir), NFS_FH(dir), name, fhandle, fattr);
if (status == -NFS4ERR_MOVED)
status = nfs4_get_referral(dir, name, fattr, fhandle);
dprintk("NFS reply lookup: %d\n", status);
@@ -1752,6 +1887,10 @@ static int
nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
int flags, struct nameidata *nd)
{
+ struct path path = {
+ .mnt = nd->mnt,
+ .dentry = dentry,
+ };
struct nfs4_state *state;
struct rpc_cred *cred;
int status = 0;
@@ -1761,7 +1900,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = PTR_ERR(cred);
goto out;
}
- state = nfs4_do_open(dir, dentry, flags, sattr, cred);
+ state = nfs4_do_open(dir, &path, flags, sattr, cred);
put_rpccred(cred);
if (IS_ERR(state)) {
status = PTR_ERR(state);
@@ -1773,11 +1912,12 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
status = nfs4_do_setattr(state->inode, &fattr, sattr, state);
if (status == 0)
nfs_setattr_update_inode(state->inode, sattr);
+ nfs_post_op_update_inode(state->inode, &fattr);
}
- if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN))
- status = nfs4_intent_set_file(nd, dentry, state);
+ if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
+ status = nfs4_intent_set_file(nd, &path, state);
else
- nfs4_close_state(state, flags);
+ nfs4_close_state(&path, state, flags);
out:
return status;
}
@@ -1785,28 +1925,27 @@ out:
static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
{
struct nfs_server *server = NFS_SERVER(dir);
- struct nfs4_remove_arg args = {
+ struct nfs_removeargs args = {
.fh = NFS_FH(dir),
- .name = name,
+ .name.len = name->len,
+ .name.name = name->name,
.bitmask = server->attr_bitmask,
};
- struct nfs_fattr dir_attr;
- struct nfs4_remove_res res = {
+ struct nfs_removeres res = {
.server = server,
- .dir_attr = &dir_attr,
};
struct rpc_message msg = {
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
- .rpc_argp = &args,
- .rpc_resp = &res,
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
+ .rpc_argp = &args,
+ .rpc_resp = &res,
};
int status;
- nfs_fattr_init(res.dir_attr);
+ nfs_fattr_init(&res.dir_attr);
status = rpc_call_sync(server->client, &msg, 0);
if (status == 0) {
update_changeattr(dir, &res.cinfo);
- nfs_post_op_update_inode(dir, res.dir_attr);
+ nfs_post_op_update_inode(dir, &res.dir_attr);
}
return status;
}
@@ -1823,48 +1962,26 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
return err;
}
-struct unlink_desc {
- struct nfs4_remove_arg args;
- struct nfs4_remove_res res;
- struct nfs_fattr dir_attr;
-};
-
-static int nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir,
- struct qstr *name)
+static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
{
- struct nfs_server *server = NFS_SERVER(dir->d_inode);
- struct unlink_desc *up;
+ struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs_removeargs *args = msg->rpc_argp;
+ struct nfs_removeres *res = msg->rpc_resp;
- up = kmalloc(sizeof(*up), GFP_KERNEL);
- if (!up)
- return -ENOMEM;
-
- up->args.fh = NFS_FH(dir->d_inode);
- up->args.name = name;
- up->args.bitmask = server->attr_bitmask;
- up->res.server = server;
- up->res.dir_attr = &up->dir_attr;
-
+ args->bitmask = server->attr_bitmask;
+ res->server = server;
msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
- msg->rpc_argp = &up->args;
- msg->rpc_resp = &up->res;
- return 0;
}
-static int nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{
- struct rpc_message *msg = &task->tk_msg;
- struct unlink_desc *up;
-
- if (msg->rpc_resp != NULL) {
- up = container_of(msg->rpc_resp, struct unlink_desc, res);
- update_changeattr(dir->d_inode, &up->res.cinfo);
- nfs_post_op_update_inode(dir->d_inode, up->res.dir_attr);
- kfree(up);
- msg->rpc_resp = NULL;
- msg->rpc_argp = NULL;
- }
- return 0;
+ struct nfs_removeres *res = task->tk_msg.rpc_resp;
+
+ if (nfs4_async_handle_error(task, res->server) == -EAGAIN)
+ return 0;
+ update_changeattr(dir, &res->cinfo);
+ nfs_post_op_update_inode(dir, &res->dir_attr);
+ return 1;
}
static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
@@ -3008,7 +3125,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
if (status != 0)
goto out;
lsp = request->fl_u.nfs4_fl.owner;
- arg.lock_owner.id = lsp->ls_id;
+ arg.lock_owner.id = lsp->ls_id.id;
status = rpc_call_sync(server->client, &msg, 0);
switch (status) {
case 0:
@@ -3152,6 +3269,11 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
{
struct nfs4_unlockdata *data;
+ /* Ensure this is an unlock - when canceling a lock, the
+ * canceled lock is passed in, and it won't be an unlock.
+ */
+ fl->fl_type = F_UNLCK;
+
data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
if (data == NULL) {
nfs_free_seqid(seqid);
@@ -3222,7 +3344,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
goto out_free;
p->arg.lock_stateid = &lsp->ls_stateid;
p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
- p->arg.lock_owner.id = lsp->ls_id;
+ p->arg.lock_owner.id = lsp->ls_id.id;
p->lsp = lsp;
atomic_inc(&lsp->ls_count);
p->ctx = get_nfs_open_context(ctx);
@@ -3285,7 +3407,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
memcpy(data->lsp->ls_stateid.data, data->res.stateid.data,
sizeof(data->lsp->ls_stateid.data));
data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
- renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
+ renew_lease(NFS_SERVER(data->ctx->path.dentry->d_inode), data->timestamp);
}
nfs_increment_lock_seqid(data->rpc_status, data->arg.lock_seqid);
out:
@@ -3544,7 +3666,7 @@ ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
return len;
}
-int nfs4_proc_fs_locations(struct inode *dir, struct qstr *name,
+int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
struct nfs4_fs_locations *fs_locations, struct page *page)
{
struct nfs_server *server = NFS_SERVER(dir);
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 8ed79d5c54f9..e9662ba81d86 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -38,12 +38,14 @@
* subsequent patch.
*/
+#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
#include <linux/kthread.h>
#include <linux/module.h>
+#include <linux/random.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
@@ -69,33 +71,14 @@ static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
return status;
}
-u32
-nfs4_alloc_lockowner_id(struct nfs_client *clp)
-{
- return clp->cl_lockowner_id ++;
-}
-
-static struct nfs4_state_owner *
-nfs4_client_grab_unused(struct nfs_client *clp, struct rpc_cred *cred)
-{
- struct nfs4_state_owner *sp = NULL;
-
- if (!list_empty(&clp->cl_unused)) {
- sp = list_entry(clp->cl_unused.next, struct nfs4_state_owner, so_list);
- atomic_inc(&sp->so_count);
- sp->so_cred = cred;
- list_move(&sp->so_list, &clp->cl_state_owners);
- clp->cl_nunused--;
- }
- return sp;
-}
-
struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
{
struct nfs4_state_owner *sp;
+ struct rb_node *pos;
struct rpc_cred *cred = NULL;
- list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
+ for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
+ sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
if (list_empty(&sp->so_states))
continue;
cred = get_rpccred(sp->so_cred);
@@ -107,32 +90,146 @@ struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp)
static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
{
struct nfs4_state_owner *sp;
+ struct rb_node *pos;
- if (!list_empty(&clp->cl_state_owners)) {
- sp = list_entry(clp->cl_state_owners.next,
- struct nfs4_state_owner, so_list);
+ pos = rb_first(&clp->cl_state_owners);
+ if (pos != NULL) {
+ sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
return get_rpccred(sp->so_cred);
}
return NULL;
}
+static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new,
+ __u64 minval, int maxbits)
+{
+ struct rb_node **p, *parent;
+ struct nfs_unique_id *pos;
+ __u64 mask = ~0ULL;
+
+ if (maxbits < 64)
+ mask = (1ULL << maxbits) - 1ULL;
+
+ /* Ensure distribution is more or less flat */
+ get_random_bytes(&new->id, sizeof(new->id));
+ new->id &= mask;
+ if (new->id < minval)
+ new->id += minval;
+retry:
+ p = &root->rb_node;
+ parent = NULL;
+
+ while (*p != NULL) {
+ parent = *p;
+ pos = rb_entry(parent, struct nfs_unique_id, rb_node);
+
+ if (new->id < pos->id)
+ p = &(*p)->rb_left;
+ else if (new->id > pos->id)
+ p = &(*p)->rb_right;
+ else
+ goto id_exists;
+ }
+ rb_link_node(&new->rb_node, parent, p);
+ rb_insert_color(&new->rb_node, root);
+ return;
+id_exists:
+ for (;;) {
+ new->id++;
+ if (new->id < minval || (new->id & mask) != new->id) {
+ new->id = minval;
+ break;
+ }
+ parent = rb_next(parent);
+ if (parent == NULL)
+ break;
+ pos = rb_entry(parent, struct nfs_unique_id, rb_node);
+ if (new->id < pos->id)
+ break;
+ }
+ goto retry;
+}
+
+static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id)
+{
+ rb_erase(&id->rb_node, root);
+}
+
static struct nfs4_state_owner *
-nfs4_find_state_owner(struct nfs_client *clp, struct rpc_cred *cred)
+nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred)
{
+ struct nfs_client *clp = server->nfs_client;
+ struct rb_node **p = &clp->cl_state_owners.rb_node,
+ *parent = NULL;
struct nfs4_state_owner *sp, *res = NULL;
- list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
- if (sp->so_cred != cred)
+ while (*p != NULL) {
+ parent = *p;
+ sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);
+
+ if (server < sp->so_server) {
+ p = &parent->rb_left;
continue;
- atomic_inc(&sp->so_count);
- /* Move to the head of the list */
- list_move(&sp->so_list, &clp->cl_state_owners);
- res = sp;
- break;
+ }
+ if (server > sp->so_server) {
+ p = &parent->rb_right;
+ continue;
+ }
+ if (cred < sp->so_cred)
+ p = &parent->rb_left;
+ else if (cred > sp->so_cred)
+ p = &parent->rb_right;
+ else {
+ atomic_inc(&sp->so_count);
+ res = sp;
+ break;
+ }
}
return res;
}
+static struct nfs4_state_owner *
+nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new)
+{
+ struct rb_node **p = &clp->cl_state_owners.rb_node,
+ *parent = NULL;
+ struct nfs4_state_owner *sp;
+
+ while (*p != NULL) {
+ parent = *p;
+ sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);
+
+ if (new->so_server < sp->so_server) {
+ p = &parent->rb_left;
+ continue;
+ }
+ if (new->so_server > sp->so_server) {
+ p = &parent->rb_right;
+ continue;
+ }
+ if (new->so_cred < sp->so_cred)
+ p = &parent->rb_left;
+ else if (new->so_cred > sp->so_cred)
+ p = &parent->rb_right;
+ else {
+ atomic_inc(&sp->so_count);
+ return sp;
+ }
+ }
+ nfs_alloc_unique_id(&clp->cl_openowner_id, &new->so_owner_id, 1, 64);
+ rb_link_node(&new->so_client_node, parent, p);
+ rb_insert_color(&new->so_client_node, &clp->cl_state_owners);
+ return new;
+}
+
+static void
+nfs4_remove_state_owner(struct nfs_client *clp, struct nfs4_state_owner *sp)
+{
+ if (!RB_EMPTY_NODE(&sp->so_client_node))
+ rb_erase(&sp->so_client_node, &clp->cl_state_owners);
+ nfs_free_unique_id(&clp->cl_openowner_id, &sp->so_owner_id);
+}
+
/*
* nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
* create a new state_owner.
@@ -160,10 +257,14 @@ nfs4_alloc_state_owner(void)
void
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
{
- struct nfs_client *clp = sp->so_client;
- spin_lock(&clp->cl_lock);
- list_del_init(&sp->so_list);
- spin_unlock(&clp->cl_lock);
+ if (!RB_EMPTY_NODE(&sp->so_client_node)) {
+ struct nfs_client *clp = sp->so_client;
+
+ spin_lock(&clp->cl_lock);
+ rb_erase(&sp->so_client_node, &clp->cl_state_owners);
+ RB_CLEAR_NODE(&sp->so_client_node);
+ spin_unlock(&clp->cl_lock);
+ }
}
/*
@@ -175,26 +276,25 @@ struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct
struct nfs_client *clp = server->nfs_client;
struct nfs4_state_owner *sp, *new;
- get_rpccred(cred);
- new = nfs4_alloc_state_owner();
spin_lock(&clp->cl_lock);
- sp = nfs4_find_state_owner(clp, cred);
- if (sp == NULL)
- sp = nfs4_client_grab_unused(clp, cred);
- if (sp == NULL && new != NULL) {
- list_add(&new->so_list, &clp->cl_state_owners);
- new->so_client = clp;
- new->so_id = nfs4_alloc_lockowner_id(clp);
- new->so_cred = cred;
- sp = new;
- new = NULL;
- }
+ sp = nfs4_find_state_owner(server, cred);
spin_unlock(&clp->cl_lock);
- kfree(new);
if (sp != NULL)
return sp;
- put_rpccred(cred);
- return NULL;
+ new = nfs4_alloc_state_owner();
+ if (new == NULL)
+ return NULL;
+ new->so_client = clp;
+ new->so_server = server;
+ new->so_cred = cred;
+ spin_lock(&clp->cl_lock);
+ sp = nfs4_insert_state_owner(clp, new);
+ spin_unlock(&clp->cl_lock);
+ if (sp == new)
+ get_rpccred(cred);
+ else
+ kfree(new);
+ return sp;
}
/*
@@ -208,18 +308,7 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp)
if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
return;
- if (clp->cl_nunused >= OPENOWNER_POOL_SIZE)
- goto out_free;
- if (list_empty(&sp->so_list))
- goto out_free;
- list_move(&sp->so_list, &clp->cl_unused);
- clp->cl_nunused++;
- spin_unlock(&clp->cl_lock);
- put_rpccred(cred);
- cred = NULL;
- return;
-out_free:
- list_del(&sp->so_list);
+ nfs4_remove_state_owner(clp, sp);
spin_unlock(&clp->cl_lock);
put_rpccred(cred);
kfree(sp);
@@ -236,6 +325,7 @@ nfs4_alloc_open_state(void)
atomic_set(&state->count, 1);
INIT_LIST_HEAD(&state->lock_states);
spin_lock_init(&state->state_lock);
+ seqlock_init(&state->seqlock);
return state;
}
@@ -263,13 +353,10 @@ __nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
struct nfs4_state *state;
list_for_each_entry(state, &nfsi->open_states, inode_states) {
- /* Is this in the process of being freed? */
- if (state->state == 0)
+ if (state->owner != owner)
continue;
- if (state->owner == owner) {
- atomic_inc(&state->count);
+ if (atomic_inc_not_zero(&state->count))
return state;
- }
}
return NULL;
}
@@ -341,16 +428,15 @@ void nfs4_put_open_state(struct nfs4_state *state)
/*
* Close the current file.
*/
-void nfs4_close_state(struct nfs4_state *state, mode_t mode)
+void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
{
- struct inode *inode = state->inode;
struct nfs4_state_owner *owner = state->owner;
- int oldstate, newstate = 0;
+ int call_close = 0;
+ int newstate;
atomic_inc(&owner->so_count);
/* Protect against nfs4_find_state() */
spin_lock(&owner->so_lock);
- spin_lock(&inode->i_lock);
switch (mode & (FMODE_READ | FMODE_WRITE)) {
case FMODE_READ:
state->n_rdonly--;
@@ -361,24 +447,29 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode)
case FMODE_READ|FMODE_WRITE:
state->n_rdwr--;
}
- oldstate = newstate = state->state;
+ newstate = FMODE_READ|FMODE_WRITE;
if (state->n_rdwr == 0) {
- if (state->n_rdonly == 0)
+ if (state->n_rdonly == 0) {
newstate &= ~FMODE_READ;
- if (state->n_wronly == 0)
+ call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
+ call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+ }
+ if (state->n_wronly == 0) {
newstate &= ~FMODE_WRITE;
+ call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
+ call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
+ }
+ if (newstate == 0)
+ clear_bit(NFS_DELEGATED_STATE, &state->flags);
}
- if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
- nfs4_state_set_mode_locked(state, newstate);
- oldstate = newstate;
- }
- spin_unlock(&inode->i_lock);
+ nfs4_state_set_mode_locked(state, newstate);
spin_unlock(&owner->so_lock);
- if (oldstate != newstate && nfs4_do_close(inode, state) == 0)
- return;
- nfs4_put_open_state(state);
- nfs4_put_state_owner(owner);
+ if (!call_close) {
+ nfs4_put_open_state(state);
+ nfs4_put_state_owner(owner);
+ } else
+ nfs4_do_close(path, state);
}
/*
@@ -415,12 +506,22 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f
atomic_set(&lsp->ls_count, 1);
lsp->ls_owner = fl_owner;
spin_lock(&clp->cl_lock);
- lsp->ls_id = nfs4_alloc_lockowner_id(clp);
+ nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64);
spin_unlock(&clp->cl_lock);
INIT_LIST_HEAD(&lsp->ls_locks);
return lsp;
}
+static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
+{
+ struct nfs_client *clp = lsp->ls_state->owner->so_client;
+
+ spin_lock(&clp->cl_lock);
+ nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id);
+ spin_unlock(&clp->cl_lock);
+ kfree(lsp);
+}
+
/*
* Return a compatible lock_state. If no initialized lock_state structure
* exists, return an uninitialized one.
@@ -450,7 +551,8 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_
return NULL;
}
spin_unlock(&state->state_lock);
- kfree(new);
+ if (new != NULL)
+ nfs4_free_lock_state(new);
return lsp;
}
@@ -471,7 +573,7 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
if (list_empty(&state->lock_states))
clear_bit(LK_STATE_IN_USE, &state->flags);
spin_unlock(&state->state_lock);
- kfree(lsp);
+ nfs4_free_lock_state(lsp);
}
static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
@@ -513,8 +615,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
{
struct nfs4_lock_state *lsp;
+ int seq;
- memcpy(dst, &state->stateid, sizeof(*dst));
+ do {
+ seq = read_seqbegin(&state->seqlock);
+ memcpy(dst, &state->stateid, sizeof(*dst));
+ } while (read_seqretry(&state->seqlock, seq));
if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
return;
@@ -557,12 +663,18 @@ void nfs_free_seqid(struct nfs_seqid *seqid)
* failed with a seqid incrementing error -
* see comments nfs_fs.h:seqid_mutating_error()
*/
-static inline void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
+static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
{
switch (status) {
case 0:
break;
case -NFS4ERR_BAD_SEQID:
+ if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
+ return;
+ printk(KERN_WARNING "NFS: v4 server returned a bad"
+ "sequence-id error on an"
+ "unconfirmed sequence %p!\n",
+ seqid->sequence);
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID:
case -NFS4ERR_BAD_STATEID:
@@ -586,7 +698,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
struct nfs4_state_owner, so_seqid);
nfs4_drop_state_owner(sp);
}
- return nfs_increment_seqid(status, seqid);
+ nfs_increment_seqid(status, seqid);
}
/*
@@ -596,7 +708,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
*/
void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
{
- return nfs_increment_seqid(status, seqid);
+ nfs_increment_seqid(status, seqid);
}
int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
@@ -748,15 +860,21 @@ out_err:
static void nfs4_state_mark_reclaim(struct nfs_client *clp)
{
struct nfs4_state_owner *sp;
+ struct rb_node *pos;
struct nfs4_state *state;
struct nfs4_lock_state *lock;
/* Reset all sequence ids to zero */
- list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
+ for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
+ sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
sp->so_seqid.counter = 0;
sp->so_seqid.flags = 0;
spin_lock(&sp->so_lock);
list_for_each_entry(state, &sp->so_states, open_states) {
+ clear_bit(NFS_DELEGATED_STATE, &state->flags);
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+ clear_bit(NFS_O_RDWR_STATE, &state->flags);
list_for_each_entry(lock, &state->lock_states, ls_locks) {
lock->ls_seqid.counter = 0;
lock->ls_seqid.flags = 0;
@@ -771,6 +889,7 @@ static int reclaimer(void *ptr)
{
struct nfs_client *clp = ptr;
struct nfs4_state_owner *sp;
+ struct rb_node *pos;
struct nfs4_state_recovery_ops *ops;
struct rpc_cred *cred;
int status = 0;
@@ -816,7 +935,8 @@ restart_loop:
/* Mark all delegations for reclaim */
nfs_delegation_mark_reclaim(clp);
/* Note: list is protected by exclusive lock on cl->cl_sem */
- list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
+ for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
+ sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
status = nfs4_reclaim_open_state(ops, sp);
if (status < 0) {
if (status == -NFS4ERR_NO_GRACE) {
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 8003c91ccb9a..badd73b7ca12 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -68,13 +68,19 @@ static int nfs4_stat_to_errno(int);
#endif
/* lock,open owner id:
- * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2)
+ * we currently use size 2 (u64) out of (NFS4_OPAQUE_LIMIT >> 2)
*/
-#define owner_id_maxsz (1 + 1)
+#define open_owner_id_maxsz (1 + 4)
+#define lock_owner_id_maxsz (1 + 4)
+#define decode_lockowner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
#define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2))
#define op_encode_hdr_maxsz (1)
#define op_decode_hdr_maxsz (2)
+#define encode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define decode_stateid_maxsz (XDR_QUADLEN(NFS4_STATEID_SIZE))
+#define encode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE))
+#define decode_verifier_maxsz (XDR_QUADLEN(NFS4_VERIFIER_SIZE))
#define encode_putfh_maxsz (op_encode_hdr_maxsz + 1 + \
(NFS4_FHSIZE >> 2))
#define decode_putfh_maxsz (op_decode_hdr_maxsz)
@@ -87,12 +93,19 @@ static int nfs4_stat_to_errno(int);
#define encode_getattr_maxsz (op_encode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
#define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
+#define nfs4_owner_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
+#define nfs4_group_maxsz (1 + XDR_QUADLEN(IDMAP_NAMESZ))
/* This is based on getfattr, which uses the most attributes: */
#define nfs4_fattr_value_maxsz (1 + (1 + 2 + 2 + 4 + 2 + 1 + 1 + 2 + 2 + \
- 3 + 3 + 3 + 2 * nfs4_name_maxsz))
+ 3 + 3 + 3 + nfs4_owner_maxsz + nfs4_group_maxsz))
#define nfs4_fattr_maxsz (nfs4_fattr_bitmap_maxsz + \
nfs4_fattr_value_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + nfs4_fattr_maxsz)
+#define encode_attrs_maxsz (nfs4_fattr_bitmap_maxsz + \
+ 1 + 2 + 1 + \
+ nfs4_owner_maxsz + \
+ nfs4_group_maxsz + \
+ 4 + 4)
#define encode_savefh_maxsz (op_encode_hdr_maxsz)
#define decode_savefh_maxsz (op_decode_hdr_maxsz)
#define encode_restorefh_maxsz (op_encode_hdr_maxsz)
@@ -116,8 +129,65 @@ static int nfs4_stat_to_errno(int);
3 + (NFS4_VERIFIER_SIZE >> 2))
#define decode_setclientid_confirm_maxsz \
(op_decode_hdr_maxsz)
-#define encode_lookup_maxsz (op_encode_hdr_maxsz + \
- 1 + ((3 + NFS4_FHSIZE) >> 2))
+#define encode_lookup_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz)
+#define decode_lookup_maxsz (op_decode_hdr_maxsz)
+#define encode_share_access_maxsz \
+ (2)
+#define encode_createmode_maxsz (1 + encode_attrs_maxsz)
+#define encode_opentype_maxsz (1 + encode_createmode_maxsz)
+#define encode_claim_null_maxsz (1 + nfs4_name_maxsz)
+#define encode_open_maxsz (op_encode_hdr_maxsz + \
+ 2 + encode_share_access_maxsz + 2 + \
+ open_owner_id_maxsz + \
+ encode_opentype_maxsz + \
+ encode_claim_null_maxsz)
+#define decode_ace_maxsz (3 + nfs4_owner_maxsz)
+#define decode_delegation_maxsz (1 + decode_stateid_maxsz + 1 + \
+ decode_ace_maxsz)
+#define decode_change_info_maxsz (5)
+#define decode_open_maxsz (op_decode_hdr_maxsz + \
+ decode_stateid_maxsz + \
+ decode_change_info_maxsz + 1 + \
+ nfs4_fattr_bitmap_maxsz + \
+ decode_delegation_maxsz)
+#define encode_open_confirm_maxsz \
+ (op_encode_hdr_maxsz + \
+ encode_stateid_maxsz + 1)
+#define decode_open_confirm_maxsz \
+ (op_decode_hdr_maxsz + \
+ decode_stateid_maxsz)
+#define encode_open_downgrade_maxsz \
+ (op_encode_hdr_maxsz + \
+ encode_stateid_maxsz + 1 + \
+ encode_share_access_maxsz)
+#define decode_open_downgrade_maxsz \
+ (op_decode_hdr_maxsz + \
+ decode_stateid_maxsz)
+#define encode_close_maxsz (op_encode_hdr_maxsz + \
+ 1 + encode_stateid_maxsz)
+#define decode_close_maxsz (op_decode_hdr_maxsz + \
+ decode_stateid_maxsz)
+#define encode_setattr_maxsz (op_encode_hdr_maxsz + \
+ encode_stateid_maxsz + \
+ encode_attrs_maxsz)
+#define decode_setattr_maxsz (op_decode_hdr_maxsz + \
+ nfs4_fattr_bitmap_maxsz)
+#define encode_read_maxsz (op_encode_hdr_maxsz + \
+ encode_stateid_maxsz + 3)
+#define decode_read_maxsz (op_decode_hdr_maxsz + 2)
+#define encode_readdir_maxsz (op_encode_hdr_maxsz + \
+ 2 + encode_verifier_maxsz + 5)
+#define decode_readdir_maxsz (op_decode_hdr_maxsz + \
+ decode_verifier_maxsz)
+#define encode_readlink_maxsz (op_encode_hdr_maxsz)
+#define decode_readlink_maxsz (op_decode_hdr_maxsz + 1)
+#define encode_write_maxsz (op_encode_hdr_maxsz + \
+ encode_stateid_maxsz + 4)
+#define decode_write_maxsz (op_decode_hdr_maxsz + \
+ 2 + decode_verifier_maxsz)
+#define encode_commit_maxsz (op_encode_hdr_maxsz + 3)
+#define decode_commit_maxsz (op_decode_hdr_maxsz + \
+ decode_verifier_maxsz)
#define encode_remove_maxsz (op_encode_hdr_maxsz + \
nfs4_name_maxsz)
#define encode_rename_maxsz (op_encode_hdr_maxsz + \
@@ -126,106 +196,142 @@ static int nfs4_stat_to_errno(int);
#define encode_link_maxsz (op_encode_hdr_maxsz + \
nfs4_name_maxsz)
#define decode_link_maxsz (op_decode_hdr_maxsz + 5)
+#define encode_lock_maxsz (op_encode_hdr_maxsz + \
+ 7 + \
+ 1 + encode_stateid_maxsz + 8)
+#define decode_lock_denied_maxsz \
+ (8 + decode_lockowner_maxsz)
+#define decode_lock_maxsz (op_decode_hdr_maxsz + \
+ decode_lock_denied_maxsz)
+#define encode_lockt_maxsz (op_encode_hdr_maxsz + 12)
+#define decode_lockt_maxsz (op_decode_hdr_maxsz + \
+ decode_lock_denied_maxsz)
+#define encode_locku_maxsz (op_encode_hdr_maxsz + 3 + \
+ encode_stateid_maxsz + \
+ 4)
+#define decode_locku_maxsz (op_decode_hdr_maxsz + \
+ decode_stateid_maxsz)
+#define encode_access_maxsz (op_encode_hdr_maxsz + 1)
+#define decode_access_maxsz (op_decode_hdr_maxsz + 2)
#define encode_symlink_maxsz (op_encode_hdr_maxsz + \
1 + nfs4_name_maxsz + \
1 + \
nfs4_fattr_maxsz)
#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
#define encode_create_maxsz (op_encode_hdr_maxsz + \
- 2 + nfs4_name_maxsz + \
- nfs4_fattr_maxsz)
-#define decode_create_maxsz (op_decode_hdr_maxsz + 8)
+ 1 + 2 + nfs4_name_maxsz + \
+ encode_attrs_maxsz)
+#define decode_create_maxsz (op_decode_hdr_maxsz + \
+ decode_change_info_maxsz + \
+ nfs4_fattr_bitmap_maxsz)
+#define encode_statfs_maxsz (encode_getattr_maxsz)
+#define decode_statfs_maxsz (decode_getattr_maxsz)
#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
#define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
+#define encode_getacl_maxsz (encode_getattr_maxsz)
+#define decode_getacl_maxsz (op_decode_hdr_maxsz + \
+ nfs4_fattr_bitmap_maxsz + 1)
+#define encode_setacl_maxsz (op_encode_hdr_maxsz + \
+ encode_stateid_maxsz + 3)
+#define decode_setacl_maxsz (decode_setattr_maxsz)
+#define encode_fs_locations_maxsz \
+ (encode_getattr_maxsz)
+#define decode_fs_locations_maxsz \
+ (0)
#define NFS4_enc_compound_sz (1024) /* XXX: large enough? */
#define NFS4_dec_compound_sz (1024) /* XXX: large enough? */
#define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 7)
+ encode_read_maxsz)
#define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 2)
+ decode_read_maxsz)
#define NFS4_enc_readlink_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz)
+ encode_readlink_maxsz)
#define NFS4_dec_readlink_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz)
+ decode_readlink_maxsz)
#define NFS4_enc_readdir_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 9)
+ encode_readdir_maxsz)
#define NFS4_dec_readdir_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 2)
+ decode_readdir_maxsz)
#define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 8 + \
+ encode_write_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 4 + \
+ decode_write_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 3 + \
+ encode_commit_maxsz + \
encode_getattr_maxsz)
#define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 2 + \
+ decode_commit_maxsz + \
decode_getattr_maxsz)
#define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \
- encode_putfh_maxsz + \
- op_encode_hdr_maxsz + \
- 13 + 3 + 2 + 64 + \
- encode_getattr_maxsz + \
- encode_getfh_maxsz)
+ encode_putfh_maxsz + \
+ encode_savefh_maxsz + \
+ encode_open_maxsz + \
+ encode_getfh_maxsz + \
+ encode_getattr_maxsz + \
+ encode_restorefh_maxsz + \
+ encode_getattr_maxsz)
#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \
- decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \
- decode_getattr_maxsz + \
- decode_getfh_maxsz)
-#define NFS4_enc_open_confirm_sz \
- (compound_encode_hdr_maxsz + \
- encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 5)
-#define NFS4_dec_open_confirm_sz (compound_decode_hdr_maxsz + \
- decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 4)
+ decode_putfh_maxsz + \
+ decode_savefh_maxsz + \
+ decode_open_maxsz + \
+ decode_getfh_maxsz + \
+ decode_getattr_maxsz + \
+ decode_restorefh_maxsz + \
+ decode_getattr_maxsz)
+#define NFS4_enc_open_confirm_sz \
+ (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_open_confirm_maxsz)
+#define NFS4_dec_open_confirm_sz \
+ (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_open_confirm_maxsz)
#define NFS4_enc_open_noattr_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz + \
- 11)
+ encode_open_maxsz + \
+ encode_getattr_maxsz)
#define NFS4_dec_open_noattr_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + \
- 4 + 5 + 2 + 3)
+ decode_open_maxsz + \
+ decode_getattr_maxsz)
#define NFS4_enc_open_downgrade_sz \
(compound_encode_hdr_maxsz + \
- encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 7 + \
- encode_getattr_maxsz)
+ encode_putfh_maxsz + \
+ encode_open_downgrade_maxsz + \
+ encode_getattr_maxsz)
#define NFS4_dec_open_downgrade_sz \
(compound_decode_hdr_maxsz + \
- decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 4 + \
- decode_getattr_maxsz)
-#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \
- encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 5 + \
- encode_getattr_maxsz)
-#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \
- decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 4 + \
- decode_getattr_maxsz)
-#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \
- encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 4 + \
- nfs4_fattr_maxsz + \
- encode_getattr_maxsz)
-#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \
- decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 3 + \
- nfs4_fattr_maxsz)
+ decode_putfh_maxsz + \
+ decode_open_downgrade_maxsz + \
+ decode_getattr_maxsz)
+#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_close_maxsz + \
+ encode_getattr_maxsz)
+#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_close_maxsz + \
+ decode_getattr_maxsz)
+#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_setattr_maxsz + \
+ encode_getattr_maxsz)
+#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_setattr_maxsz + \
+ decode_getattr_maxsz)
#define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_fsinfo_maxsz)
@@ -252,39 +358,28 @@ static int nfs4_stat_to_errno(int);
decode_fsinfo_maxsz)
#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_getattr_maxsz + \
- op_encode_hdr_maxsz + \
- 1 + 1 + 2 + 2 + \
- 1 + 4 + 1 + 2 + \
- owner_id_maxsz)
+ encode_lock_maxsz)
#define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- decode_getattr_maxsz + \
- op_decode_hdr_maxsz + \
- 2 + 2 + 1 + 2 + \
- owner_id_maxsz)
+ decode_lock_maxsz)
#define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_getattr_maxsz + \
- op_encode_hdr_maxsz + \
- 1 + 2 + 2 + 2 + \
- owner_id_maxsz)
-#define NFS4_dec_lockt_sz (NFS4_dec_lock_sz)
+ encode_lockt_maxsz)
+#define NFS4_dec_lockt_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_lockt_maxsz)
#define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_getattr_maxsz + \
- op_encode_hdr_maxsz + \
- 1 + 1 + 4 + 2 + 2)
+ encode_locku_maxsz)
#define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- decode_getattr_maxsz + \
- op_decode_hdr_maxsz + 4)
+ decode_locku_maxsz)
#define NFS4_enc_access_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 1)
+ encode_access_maxsz)
#define NFS4_dec_access_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 2)
+ decode_access_maxsz)
#define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz)
@@ -298,7 +393,7 @@ static int nfs4_stat_to_errno(int);
encode_getfh_maxsz)
#define NFS4_dec_lookup_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + \
+ decode_lookup_maxsz + \
decode_getattr_maxsz + \
decode_getfh_maxsz)
#define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \
@@ -383,10 +478,10 @@ static int nfs4_stat_to_errno(int);
decode_getattr_maxsz)
#define NFS4_enc_statfs_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_getattr_maxsz)
+ encode_statfs_maxsz)
#define NFS4_dec_statfs_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + 12)
+ decode_statfs_maxsz)
#define NFS4_enc_server_caps_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_getattr_maxsz)
@@ -402,27 +497,26 @@ static int nfs4_stat_to_errno(int);
decode_getattr_maxsz)
#define NFS4_enc_getacl_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_getattr_maxsz)
+ encode_getacl_maxsz)
#define NFS4_dec_getacl_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + \
- nfs4_fattr_bitmap_maxsz + 1)
+ decode_getacl_maxsz)
#define NFS4_enc_setacl_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- op_encode_hdr_maxsz + 4 + \
- nfs4_fattr_bitmap_maxsz + 1)
+ encode_setacl_maxsz)
#define NFS4_dec_setacl_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + nfs4_fattr_bitmap_maxsz)
+ decode_setacl_maxsz)
#define NFS4_enc_fs_locations_sz \
(compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
- encode_getattr_maxsz)
+ encode_lookup_maxsz + \
+ encode_fs_locations_maxsz)
#define NFS4_dec_fs_locations_sz \
(compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
- op_decode_hdr_maxsz + \
- nfs4_fattr_bitmap_maxsz)
+ decode_lookup_maxsz + \
+ decode_fs_locations_maxsz)
static struct {
unsigned int mode;
@@ -793,13 +887,14 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
WRITE64(nfs4_lock_length(args->fl));
WRITE32(args->new_lock_owner);
if (args->new_lock_owner){
- RESERVE_SPACE(4+NFS4_STATEID_SIZE+20);
+ RESERVE_SPACE(4+NFS4_STATEID_SIZE+32);
WRITE32(args->open_seqid->sequence->counter);
WRITEMEM(args->open_stateid->data, NFS4_STATEID_SIZE);
WRITE32(args->lock_seqid->sequence->counter);
WRITE64(args->lock_owner.clientid);
- WRITE32(4);
- WRITE32(args->lock_owner.id);
+ WRITE32(16);
+ WRITEMEM("lock id:", 8);
+ WRITE64(args->lock_owner.id);
}
else {
RESERVE_SPACE(NFS4_STATEID_SIZE+4);
@@ -814,14 +909,15 @@ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *arg
{
__be32 *p;
- RESERVE_SPACE(40);
+ RESERVE_SPACE(52);
WRITE32(OP_LOCKT);
WRITE32(nfs4_lock_type(args->fl, 0));
WRITE64(args->fl->fl_start);
WRITE64(nfs4_lock_length(args->fl));
WRITE64(args->lock_owner.clientid);
- WRITE32(4);
- WRITE32(args->lock_owner.id);
+ WRITE32(16);
+ WRITEMEM("lock id:", 8);
+ WRITE64(args->lock_owner.id);
return 0;
}
@@ -886,10 +982,11 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
WRITE32(OP_OPEN);
WRITE32(arg->seqid->sequence->counter);
encode_share_access(xdr, arg->open_flags);
- RESERVE_SPACE(16);
+ RESERVE_SPACE(28);
WRITE64(arg->clientid);
- WRITE32(4);
- WRITE32(arg->id);
+ WRITE32(16);
+ WRITEMEM("open id:", 8);
+ WRITE64(arg->id);
}
static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
@@ -1071,12 +1168,10 @@ static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
uint32_t attrs[2] = {
FATTR4_WORD0_RDATTR_ERROR|FATTR4_WORD0_FILEID,
FATTR4_WORD1_MOUNTED_ON_FILEID,
};
- int replen;
__be32 *p;
RESERVE_SPACE(12+NFS4_VERIFIER_SIZE+20);
@@ -1101,37 +1196,16 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
attrs[0] & readdir->bitmask[0],
attrs[1] & readdir->bitmask[1]);
- /* set up reply kvec
- * toplevel_status + taglen + rescount + OP_PUTFH + status
- * + OP_READDIR + status + verifer(2) = 9
- */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
- readdir->pgbase, readdir->count);
- dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
- __FUNCTION__, replen, readdir->pages,
- readdir->pgbase, readdir->count);
-
return 0;
}
static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *readlink, struct rpc_rqst *req)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
- unsigned int replen;
__be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_READLINK);
- /* set up reply kvec
- * toplevel_status + taglen + rescount + OP_PUTFH + status
- * + OP_READLINK + status + string length = 8
- */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + 8) << 2;
- xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages,
- readlink->pgbase, readlink->pglen);
-
return 0;
}
@@ -1361,7 +1435,7 @@ out:
/*
* Encode REMOVE request
*/
-static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
+static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1373,7 +1447,7 @@ static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs
encode_compound_hdr(&xdr, &hdr);
if ((status = encode_putfh(&xdr, args->fh)) != 0)
goto out;
- if ((status = encode_remove(&xdr, args->name)) != 0)
+ if ((status = encode_remove(&xdr, &args->name)) != 0)
goto out;
status = encode_getfattr(&xdr, args->bitmask);
out:
@@ -1697,6 +1771,8 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
struct compound_hdr hdr = {
.nops = 2,
};
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+ unsigned int replen;
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -1705,6 +1781,15 @@ static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct n
if(status)
goto out;
status = encode_readlink(&xdr, args, req);
+
+ /* set up reply kvec
+ * toplevel_status + taglen + rescount + OP_PUTFH + status
+ * + OP_READLINK + status + string length = 8
+ */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readlink_sz) << 2;
+ xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages,
+ args->pgbase, args->pglen);
+
out:
return status;
}
@@ -1718,6 +1803,8 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
struct compound_hdr hdr = {
.nops = 2,
};
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
+ int replen;
int status;
xdr_init_encode(&xdr, &req->rq_snd_buf, p);
@@ -1726,6 +1813,18 @@ static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nf
if(status)
goto out;
status = encode_readdir(&xdr, args, req);
+
+ /* set up reply kvec
+ * toplevel_status + taglen + rescount + OP_PUTFH + status
+ * + OP_READDIR + status + verifer(2) = 9
+ */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS4_dec_readdir_sz) << 2;
+ xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages,
+ args->pgbase, args->count);
+ dprintk("%s: inlined page args = (%u, %p, %u, %u)\n",
+ __FUNCTION__, replen, args->pages,
+ args->pgbase, args->count);
+
out:
return status;
}
@@ -1735,7 +1834,7 @@ out:
*/
static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
struct xdr_stream xdr;
struct compound_hdr hdr = {
.nops = 2,
@@ -1795,7 +1894,7 @@ nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
struct nfs_getaclargs *args)
{
struct xdr_stream xdr;
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
struct compound_hdr hdr = {
.nops = 2,
};
@@ -2030,7 +2129,7 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs
struct compound_hdr hdr = {
.nops = 3,
};
- struct rpc_auth *auth = req->rq_task->tk_auth;
+ struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
int replen;
int status;
@@ -3124,11 +3223,12 @@ static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
uint32_t len;
int status;
+ /* Zero handle first to allow comparisons */
+ memset(fh, 0, sizeof(*fh));
+
status = decode_op_hdr(xdr, OP_GETFH);
if (status)
return status;
- /* Zero handle first to allow comparisons */
- memset(fh, 0, sizeof(*fh));
READ_BUF(4);
READ32(len);
@@ -3269,7 +3369,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
__be32 *p;
- uint32_t bmlen;
+ uint32_t savewords, bmlen, i;
int status;
status = decode_op_hdr(xdr, OP_OPEN);
@@ -3287,7 +3387,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
goto xdr_error;
READ_BUF(bmlen << 2);
- p += bmlen;
+ savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
+ for (i = 0; i < savewords; ++i)
+ READ32(res->attrset[i]);
+ for (; i < NFS4_BITMAP_SIZE; i++)
+ res->attrset[i] = 0;
+
return decode_delegation(xdr, res);
xdr_error:
dprintk("%s: Bitmap too large! Length = %u\n", __FUNCTION__, bmlen);
@@ -3730,7 +3835,7 @@ out:
/*
* Decode REMOVE response
*/
-static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
+static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs_removeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3743,7 +3848,7 @@ static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_re
goto out;
if ((status = decode_remove(&xdr, &res->cinfo)) != 0)
goto out;
- decode_getfattr(&xdr, res->dir_attr, res->server);
+ decode_getfattr(&xdr, &res->dir_attr, res->server);
out:
return status;
}
@@ -3988,12 +4093,11 @@ static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openr
status = decode_open(&xdr, res);
if (status)
goto out;
- status = decode_getfh(&xdr, &res->fh);
- if (status)
+ if (decode_getfh(&xdr, &res->fh) != 0)
goto out;
if (decode_getfattr(&xdr, res->f_attr, res->server) != 0)
goto out;
- if ((status = decode_restorefh(&xdr)) != 0)
+ if (decode_restorefh(&xdr) != 0)
goto out;
decode_getfattr(&xdr, res->dir_attr, res->server);
out:
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 49d1008ce1d7..3490322d1145 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -428,7 +428,7 @@ static int __init root_nfs_getport(int program, int version, int proto)
printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n",
program, version, NIPQUAD(servaddr));
set_sockaddr(&sin, servaddr, 0);
- return rpcb_getport_external(&sin, program, version, proto);
+ return rpcb_getport_sync(&sin, program, version, proto);
}
@@ -496,7 +496,8 @@ static int __init root_nfs_get_handle(void)
NFS_MNT3_VERSION : NFS_MNT_VERSION;
set_sockaddr(&sin, servaddr, htons(mount_port));
- status = nfsroot_mount(&sin, nfs_path, &fh, version, protocol);
+ status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), NULL,
+ nfs_path, version, protocol, &fh);
if (status < 0)
printk(KERN_ERR "Root-NFS: Server returned error %d "
"while mounting %s\n", status, nfs_path);
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index c5bb51a29e80..345bb9b4765b 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -85,9 +85,8 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
req->wb_offset = offset;
req->wb_pgbase = offset;
req->wb_bytes = count;
- atomic_set(&req->wb_count, 1);
req->wb_context = get_nfs_open_context(ctx);
-
+ kref_init(&req->wb_kref);
return req;
}
@@ -109,30 +108,31 @@ void nfs_unlock_request(struct nfs_page *req)
}
/**
- * nfs_set_page_writeback_locked - Lock a request for writeback
+ * nfs_set_page_tag_locked - Tag a request as locked
* @req:
*/
-int nfs_set_page_writeback_locked(struct nfs_page *req)
+static int nfs_set_page_tag_locked(struct nfs_page *req)
{
- struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
+ struct nfs_inode *nfsi = NFS_I(req->wb_context->path.dentry->d_inode);
if (!nfs_lock_request(req))
return 0;
- radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK);
+ radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
return 1;
}
/**
- * nfs_clear_page_writeback - Unlock request and wake up sleepers
+ * nfs_clear_page_tag_locked - Clear request tag and wake up sleepers
*/
-void nfs_clear_page_writeback(struct nfs_page *req)
+void nfs_clear_page_tag_locked(struct nfs_page *req)
{
- struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
+ struct inode *inode = req->wb_context->path.dentry->d_inode;
+ struct nfs_inode *nfsi = NFS_I(inode);
if (req->wb_page != NULL) {
- spin_lock(&nfsi->req_lock);
- radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_WRITEBACK);
- spin_unlock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
+ radix_tree_tag_clear(&nfsi->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED);
+ spin_unlock(&inode->i_lock);
}
nfs_unlock_request(req);
}
@@ -160,11 +160,9 @@ void nfs_clear_request(struct nfs_page *req)
*
* Note: Should never be called with the spinlock held!
*/
-void
-nfs_release_request(struct nfs_page *req)
+static void nfs_free_request(struct kref *kref)
{
- if (!atomic_dec_and_test(&req->wb_count))
- return;
+ struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref);
/* Release struct file or cached credential */
nfs_clear_request(req);
@@ -172,6 +170,11 @@ nfs_release_request(struct nfs_page *req)
nfs_page_free(req);
}
+void nfs_release_request(struct nfs_page *req)
+{
+ kref_put(&req->wb_kref, nfs_free_request);
+}
+
static int nfs_wait_bit_interruptible(void *word)
{
int ret = 0;
@@ -193,7 +196,7 @@ static int nfs_wait_bit_interruptible(void *word)
int
nfs_wait_on_request(struct nfs_page *req)
{
- struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->dentry->d_inode);
+ struct rpc_clnt *clnt = NFS_CLIENT(req->wb_context->path.dentry->d_inode);
sigset_t oldmask;
int ret = 0;
@@ -379,20 +382,20 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
/**
* nfs_scan_list - Scan a list for matching requests
* @nfsi: NFS inode
- * @head: One of the NFS inode request lists
* @dst: Destination list
* @idx_start: lower bound of page->index to scan
* @npages: idx_start + npages sets the upper bound to scan.
+ * @tag: tag to scan for
*
* Moves elements from one of the inode request lists.
* If the number of requests is set to 0, the entire address_space
* starting at index idx_start, is scanned.
* The requests are *not* checked to ensure that they form a contiguous set.
- * You must be holding the inode's req_lock when calling this function
+ * You must be holding the inode's i_lock when calling this function
*/
-int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
+int nfs_scan_list(struct nfs_inode *nfsi,
struct list_head *dst, pgoff_t idx_start,
- unsigned int npages)
+ unsigned int npages, int tag)
{
struct nfs_page *pgvec[NFS_SCAN_MAXENTRIES];
struct nfs_page *req;
@@ -407,9 +410,9 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
idx_end = idx_start + npages - 1;
for (;;) {
- found = radix_tree_gang_lookup(&nfsi->nfs_page_tree,
+ found = radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree,
(void **)&pgvec[0], idx_start,
- NFS_SCAN_MAXENTRIES);
+ NFS_SCAN_MAXENTRIES, tag);
if (found <= 0)
break;
for (i = 0; i < found; i++) {
@@ -417,15 +420,18 @@ int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head,
if (req->wb_index > idx_end)
goto out;
idx_start = req->wb_index + 1;
- if (req->wb_list_head != head)
- continue;
- if (nfs_set_page_writeback_locked(req)) {
+ if (nfs_set_page_tag_locked(req)) {
nfs_list_remove_request(req);
+ radix_tree_tag_clear(&nfsi->nfs_page_tree,
+ req->wb_index, tag);
nfs_list_add_request(req, dst);
res++;
+ if (res == INT_MAX)
+ goto out;
}
}
-
+ /* for latency reduction */
+ cond_resched_lock(&nfsi->vfs_inode.i_lock);
}
out:
return res;
@@ -436,7 +442,7 @@ int __init nfs_init_nfspagecache(void)
nfs_page_cachep = kmem_cache_create("nfs_page",
sizeof(struct nfs_page),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (nfs_page_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 7be0ee2782cb..845cdde1d8b7 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -272,14 +272,14 @@ nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
static int
nfs_proc_remove(struct inode *dir, struct qstr *name)
{
- struct nfs_diropargs arg = {
- .fh = NFS_FH(dir),
- .name = name->name,
- .len = name->len
+ struct nfs_removeargs arg = {
+ .fh = NFS_FH(dir),
+ .name.len = name->len,
+ .name.name = name->name,
};
- struct rpc_message msg = {
- .rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
- .rpc_argp = &arg,
+ struct rpc_message msg = {
+ .rpc_proc = &nfs_procedures[NFSPROC_REMOVE],
+ .rpc_argp = &arg,
};
int status;
@@ -291,32 +291,16 @@ nfs_proc_remove(struct inode *dir, struct qstr *name)
return status;
}
-static int
-nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
+static void
+nfs_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
{
- struct nfs_diropargs *arg;
-
- arg = kmalloc(sizeof(*arg), GFP_KERNEL);
- if (!arg)
- return -ENOMEM;
- arg->fh = NFS_FH(dir->d_inode);
- arg->name = name->name;
- arg->len = name->len;
msg->rpc_proc = &nfs_procedures[NFSPROC_REMOVE];
- msg->rpc_argp = arg;
- return 0;
}
-static int
-nfs_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
+static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir)
{
- struct rpc_message *msg = &task->tk_msg;
-
- if (msg->rpc_argp) {
- nfs_mark_for_revalidate(dir->d_inode);
- kfree(msg->rpc_argp);
- }
- return 0;
+ nfs_mark_for_revalidate(dir);
+ return 1;
}
static int
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 7bd7cb95c034..19e05633f4e3 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -145,8 +145,8 @@ static void nfs_readpage_release(struct nfs_page *req)
unlock_page(req->wb_page);
dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
- req->wb_context->dentry->d_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+ req->wb_context->path.dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
nfs_clear_request(req);
@@ -164,7 +164,7 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data,
int flags;
data->req = req;
- data->inode = inode = req->wb_context->dentry->d_inode;
+ data->inode = inode = req->wb_context->path.dentry->d_inode;
data->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode);
@@ -483,17 +483,19 @@ int nfs_readpage(struct file *file, struct page *page)
*/
error = nfs_wb_page(inode, page);
if (error)
- goto out_error;
+ goto out_unlock;
+ if (PageUptodate(page))
+ goto out_unlock;
error = -ESTALE;
if (NFS_STALE(inode))
- goto out_error;
+ goto out_unlock;
if (file == NULL) {
error = -EBADF;
ctx = nfs_find_open_context(inode, NULL, FMODE_READ);
if (ctx == NULL)
- goto out_error;
+ goto out_unlock;
} else
ctx = get_nfs_open_context((struct nfs_open_context *)
file->private_data);
@@ -502,8 +504,7 @@ int nfs_readpage(struct file *file, struct page *page)
put_nfs_open_context(ctx);
return error;
-
-out_error:
+out_unlock:
unlock_page(page);
return error;
}
@@ -520,21 +521,32 @@ readpage_async_filler(void *data, struct page *page)
struct inode *inode = page->mapping->host;
struct nfs_page *new;
unsigned int len;
+ int error;
+
+ error = nfs_wb_page(inode, page);
+ if (error)
+ goto out_unlock;
+ if (PageUptodate(page))
+ goto out_unlock;
- nfs_wb_page(inode, page);
len = nfs_page_length(page);
if (len == 0)
return nfs_return_empty_page(page);
+
new = nfs_create_request(desc->ctx, inode, page, 0, len);
- if (IS_ERR(new)) {
- SetPageError(page);
- unlock_page(page);
- return PTR_ERR(new);
- }
+ if (IS_ERR(new))
+ goto out_error;
+
if (len < PAGE_CACHE_SIZE)
zero_user_page(page, len, PAGE_CACHE_SIZE - len, KM_USER0);
nfs_pageio_add_request(desc->pgio, new);
return 0;
+out_error:
+ error = PTR_ERR(new);
+ SetPageError(page);
+out_unlock:
+ unlock_page(page);
+ return error;
}
int nfs_readpages(struct file *filp, struct address_space *mapping,
@@ -586,7 +598,7 @@ int __init nfs_init_readpagecache(void)
nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
sizeof(struct nfs_read_data),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (nfs_rdata_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ca20d3cc2609..b2a851c1b8cb 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -45,6 +45,7 @@
#include <linux/inet.h>
#include <linux/nfs_xdr.h>
#include <linux/magic.h>
+#include <linux/parser.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -57,6 +58,167 @@
#define NFSDBG_FACILITY NFSDBG_VFS
+
+struct nfs_parsed_mount_data {
+ int flags;
+ int rsize, wsize;
+ int timeo, retrans;
+ int acregmin, acregmax,
+ acdirmin, acdirmax;
+ int namlen;
+ unsigned int bsize;
+ unsigned int auth_flavor_len;
+ rpc_authflavor_t auth_flavors[1];
+ char *client_address;
+
+ struct {
+ struct sockaddr_in address;
+ unsigned int program;
+ unsigned int version;
+ unsigned short port;
+ int protocol;
+ } mount_server;
+
+ struct {
+ struct sockaddr_in address;
+ char *hostname;
+ char *export_path;
+ unsigned int program;
+ int protocol;
+ } nfs_server;
+};
+
+enum {
+ /* Mount options that take no arguments */
+ Opt_soft, Opt_hard,
+ Opt_intr, Opt_nointr,
+ Opt_posix, Opt_noposix,
+ Opt_cto, Opt_nocto,
+ Opt_ac, Opt_noac,
+ Opt_lock, Opt_nolock,
+ Opt_v2, Opt_v3,
+ Opt_udp, Opt_tcp,
+ Opt_acl, Opt_noacl,
+ Opt_rdirplus, Opt_nordirplus,
+ Opt_sharecache, Opt_nosharecache,
+
+ /* Mount options that take integer arguments */
+ Opt_port,
+ Opt_rsize, Opt_wsize, Opt_bsize,
+ Opt_timeo, Opt_retrans,
+ Opt_acregmin, Opt_acregmax,
+ Opt_acdirmin, Opt_acdirmax,
+ Opt_actimeo,
+ Opt_namelen,
+ Opt_mountport,
+ Opt_mountprog, Opt_mountvers,
+ Opt_nfsprog, Opt_nfsvers,
+
+ /* Mount options that take string arguments */
+ Opt_sec, Opt_proto, Opt_mountproto,
+ Opt_addr, Opt_mounthost, Opt_clientaddr,
+
+ /* Mount options that are ignored */
+ Opt_userspace, Opt_deprecated,
+
+ Opt_err
+};
+
+static match_table_t nfs_mount_option_tokens = {
+ { Opt_userspace, "bg" },
+ { Opt_userspace, "fg" },
+ { Opt_soft, "soft" },
+ { Opt_hard, "hard" },
+ { Opt_intr, "intr" },
+ { Opt_nointr, "nointr" },
+ { Opt_posix, "posix" },
+ { Opt_noposix, "noposix" },
+ { Opt_cto, "cto" },
+ { Opt_nocto, "nocto" },
+ { Opt_ac, "ac" },
+ { Opt_noac, "noac" },
+ { Opt_lock, "lock" },
+ { Opt_nolock, "nolock" },
+ { Opt_v2, "v2" },
+ { Opt_v3, "v3" },
+ { Opt_udp, "udp" },
+ { Opt_tcp, "tcp" },
+ { Opt_acl, "acl" },
+ { Opt_noacl, "noacl" },
+ { Opt_rdirplus, "rdirplus" },
+ { Opt_nordirplus, "nordirplus" },
+ { Opt_sharecache, "sharecache" },
+ { Opt_nosharecache, "nosharecache" },
+
+ { Opt_port, "port=%u" },
+ { Opt_rsize, "rsize=%u" },
+ { Opt_wsize, "wsize=%u" },
+ { Opt_bsize, "bsize=%u" },
+ { Opt_timeo, "timeo=%u" },
+ { Opt_retrans, "retrans=%u" },
+ { Opt_acregmin, "acregmin=%u" },
+ { Opt_acregmax, "acregmax=%u" },
+ { Opt_acdirmin, "acdirmin=%u" },
+ { Opt_acdirmax, "acdirmax=%u" },
+ { Opt_actimeo, "actimeo=%u" },
+ { Opt_userspace, "retry=%u" },
+ { Opt_namelen, "namlen=%u" },
+ { Opt_mountport, "mountport=%u" },
+ { Opt_mountprog, "mountprog=%u" },
+ { Opt_mountvers, "mountvers=%u" },
+ { Opt_nfsprog, "nfsprog=%u" },
+ { Opt_nfsvers, "nfsvers=%u" },
+ { Opt_nfsvers, "vers=%u" },
+
+ { Opt_sec, "sec=%s" },
+ { Opt_proto, "proto=%s" },
+ { Opt_mountproto, "mountproto=%s" },
+ { Opt_addr, "addr=%s" },
+ { Opt_clientaddr, "clientaddr=%s" },
+ { Opt_mounthost, "mounthost=%s" },
+
+ { Opt_err, NULL }
+};
+
+enum {
+ Opt_xprt_udp, Opt_xprt_tcp,
+
+ Opt_xprt_err
+};
+
+static match_table_t nfs_xprt_protocol_tokens = {
+ { Opt_xprt_udp, "udp" },
+ { Opt_xprt_tcp, "tcp" },
+
+ { Opt_xprt_err, NULL }
+};
+
+enum {
+ Opt_sec_none, Opt_sec_sys,
+ Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
+ Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp,
+ Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
+
+ Opt_sec_err
+};
+
+static match_table_t nfs_secflavor_tokens = {
+ { Opt_sec_none, "none" },
+ { Opt_sec_none, "null" },
+ { Opt_sec_sys, "sys" },
+
+ { Opt_sec_krb5, "krb5" },
+ { Opt_sec_krb5i, "krb5i" },
+ { Opt_sec_krb5p, "krb5p" },
+
+ { Opt_sec_lkey, "lkey" },
+ { Opt_sec_lkeyi, "lkeyi" },
+ { Opt_sec_lkeyp, "lkeyp" },
+
+ { Opt_sec_err, NULL }
+};
+
+
static void nfs_umount_begin(struct vfsmount *, int);
static int nfs_statfs(struct dentry *, struct kstatfs *);
static int nfs_show_options(struct seq_file *, struct vfsmount *);
@@ -138,7 +300,10 @@ static const struct super_operations nfs4_sops = {
};
#endif
-static struct shrinker *acl_shrinker;
+static struct shrinker acl_shrinker = {
+ .shrink = nfs_access_cache_shrinker,
+ .seeks = DEFAULT_SEEKS,
+};
/*
* Register the NFS filesystems
@@ -159,7 +324,7 @@ int __init register_nfs_fs(void)
if (ret < 0)
goto error_2;
#endif
- acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker);
+ register_shrinker(&acl_shrinker);
return 0;
#ifdef CONFIG_NFS_V4
@@ -177,8 +342,7 @@ error_0:
*/
void __exit unregister_nfs_fs(void)
{
- if (acl_shrinker != NULL)
- remove_shrinker(acl_shrinker);
+ unregister_shrinker(&acl_shrinker);
#ifdef CONFIG_NFS_V4
unregister_filesystem(&nfs4_fs_type);
nfs_unregister_sysctl();
@@ -263,11 +427,11 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
{ RPC_AUTH_GSS_SPKM, "spkm" },
{ RPC_AUTH_GSS_SPKMI, "spkmi" },
{ RPC_AUTH_GSS_SPKMP, "spkmp" },
- { -1, "unknown" }
+ { UINT_MAX, "unknown" }
};
int i;
- for (i=0; sec_flavours[i].flavour != -1; i++) {
+ for (i = 0; sec_flavours[i].flavour != UINT_MAX; i++) {
if (sec_flavours[i].flavour == flavour)
break;
}
@@ -291,6 +455,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
{ NFS_MOUNT_NONLM, ",nolock", "" },
{ NFS_MOUNT_NOACL, ",noacl", "" },
{ NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" },
+ { NFS_MOUNT_UNSHARED, ",nosharecache", ""},
{ 0, NULL, NULL }
};
const struct proc_nfs_info *nfs_infop;
@@ -430,87 +595,641 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
*/
static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
{
+ struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb);
+ struct rpc_clnt *rpc;
+
shrink_submounts(vfsmnt, &nfs_automount_list);
+
+ if (!(flags & MNT_FORCE))
+ return;
+ /* -EIO all pending I/O */
+ rpc = server->client_acl;
+ if (!IS_ERR(rpc))
+ rpc_killall_tasks(rpc);
+ rpc = server->client;
+ if (!IS_ERR(rpc))
+ rpc_killall_tasks(rpc);
}
/*
- * Validate the NFS2/NFS3 mount data
- * - fills in the mount root filehandle
+ * Sanity-check a server address provided by the mount command
*/
-static int nfs_validate_mount_data(struct nfs_mount_data *data,
- struct nfs_fh *mntfh)
+static int nfs_verify_server_address(struct sockaddr *addr)
{
- if (data == NULL) {
- dprintk("%s: missing data argument\n", __FUNCTION__);
- return -EINVAL;
+ switch (addr->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sa = (struct sockaddr_in *) addr;
+ if (sa->sin_addr.s_addr != INADDR_ANY)
+ return 1;
+ break;
+ }
}
- if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
- dprintk("%s: bad mount version\n", __FUNCTION__);
- return -EINVAL;
+ return 0;
+}
+
+/*
+ * Error-check and convert a string of mount options from user space into
+ * a data structure
+ */
+static int nfs_parse_mount_options(char *raw,
+ struct nfs_parsed_mount_data *mnt)
+{
+ char *p, *string;
+
+ if (!raw) {
+ dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
+ return 1;
}
+ dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
- switch (data->version) {
- case 1:
- data->namlen = 0;
- case 2:
- data->bsize = 0;
- case 3:
- if (data->flags & NFS_MOUNT_VER3) {
- dprintk("%s: mount structure version %d does not support NFSv3\n",
- __FUNCTION__,
- data->version);
- return -EINVAL;
+ while ((p = strsep(&raw, ",")) != NULL) {
+ substring_t args[MAX_OPT_ARGS];
+ int option, token;
+
+ if (!*p)
+ continue;
+
+ dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", p);
+
+ token = match_token(p, nfs_mount_option_tokens, args);
+ switch (token) {
+ case Opt_soft:
+ mnt->flags |= NFS_MOUNT_SOFT;
+ break;
+ case Opt_hard:
+ mnt->flags &= ~NFS_MOUNT_SOFT;
+ break;
+ case Opt_intr:
+ mnt->flags |= NFS_MOUNT_INTR;
+ break;
+ case Opt_nointr:
+ mnt->flags &= ~NFS_MOUNT_INTR;
+ break;
+ case Opt_posix:
+ mnt->flags |= NFS_MOUNT_POSIX;
+ break;
+ case Opt_noposix:
+ mnt->flags &= ~NFS_MOUNT_POSIX;
+ break;
+ case Opt_cto:
+ mnt->flags &= ~NFS_MOUNT_NOCTO;
+ break;
+ case Opt_nocto:
+ mnt->flags |= NFS_MOUNT_NOCTO;
+ break;
+ case Opt_ac:
+ mnt->flags &= ~NFS_MOUNT_NOAC;
+ break;
+ case Opt_noac:
+ mnt->flags |= NFS_MOUNT_NOAC;
+ break;
+ case Opt_lock:
+ mnt->flags &= ~NFS_MOUNT_NONLM;
+ break;
+ case Opt_nolock:
+ mnt->flags |= NFS_MOUNT_NONLM;
+ break;
+ case Opt_v2:
+ mnt->flags &= ~NFS_MOUNT_VER3;
+ break;
+ case Opt_v3:
+ mnt->flags |= NFS_MOUNT_VER3;
+ break;
+ case Opt_udp:
+ mnt->flags &= ~NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = IPPROTO_UDP;
+ mnt->timeo = 7;
+ mnt->retrans = 5;
+ break;
+ case Opt_tcp:
+ mnt->flags |= NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = IPPROTO_TCP;
+ mnt->timeo = 600;
+ mnt->retrans = 2;
+ break;
+ case Opt_acl:
+ mnt->flags &= ~NFS_MOUNT_NOACL;
+ break;
+ case Opt_noacl:
+ mnt->flags |= NFS_MOUNT_NOACL;
+ break;
+ case Opt_rdirplus:
+ mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
+ break;
+ case Opt_nordirplus:
+ mnt->flags |= NFS_MOUNT_NORDIRPLUS;
+ break;
+ case Opt_sharecache:
+ mnt->flags &= ~NFS_MOUNT_UNSHARED;
+ break;
+ case Opt_nosharecache:
+ mnt->flags |= NFS_MOUNT_UNSHARED;
+ break;
+
+ case Opt_port:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0 || option > 65535)
+ return 0;
+ mnt->nfs_server.address.sin_port = htons(option);
+ break;
+ case Opt_rsize:
+ if (match_int(args, &mnt->rsize))
+ return 0;
+ break;
+ case Opt_wsize:
+ if (match_int(args, &mnt->wsize))
+ return 0;
+ break;
+ case Opt_bsize:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->bsize = option;
+ break;
+ case Opt_timeo:
+ if (match_int(args, &mnt->timeo))
+ return 0;
+ break;
+ case Opt_retrans:
+ if (match_int(args, &mnt->retrans))
+ return 0;
+ break;
+ case Opt_acregmin:
+ if (match_int(args, &mnt->acregmin))
+ return 0;
+ break;
+ case Opt_acregmax:
+ if (match_int(args, &mnt->acregmax))
+ return 0;
+ break;
+ case Opt_acdirmin:
+ if (match_int(args, &mnt->acdirmin))
+ return 0;
+ break;
+ case Opt_acdirmax:
+ if (match_int(args, &mnt->acdirmax))
+ return 0;
+ break;
+ case Opt_actimeo:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->acregmin =
+ mnt->acregmax =
+ mnt->acdirmin =
+ mnt->acdirmax = option;
+ break;
+ case Opt_namelen:
+ if (match_int(args, &mnt->namlen))
+ return 0;
+ break;
+ case Opt_mountport:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0 || option > 65535)
+ return 0;
+ mnt->mount_server.port = option;
+ break;
+ case Opt_mountprog:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->mount_server.program = option;
+ break;
+ case Opt_mountvers:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->mount_server.version = option;
+ break;
+ case Opt_nfsprog:
+ if (match_int(args, &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ mnt->nfs_server.program = option;
+ break;
+ case Opt_nfsvers:
+ if (match_int(args, &option))
+ return 0;
+ switch (option) {
+ case 2:
+ mnt->flags &= ~NFS_MOUNT_VER3;
+ break;
+ case 3:
+ mnt->flags |= NFS_MOUNT_VER3;
+ break;
+ default:
+ goto out_unrec_vers;
}
- data->root.size = NFS2_FHSIZE;
- memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
- case 4:
- if (data->flags & NFS_MOUNT_SECFLAVOUR) {
- dprintk("%s: mount structure version %d does not support strong security\n",
- __FUNCTION__,
- data->version);
- return -EINVAL;
+ break;
+
+ case Opt_sec:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string, nfs_secflavor_tokens, args);
+ kfree(string);
+
+ /*
+ * The flags setting is for v2/v3. The flavor_len
+ * setting is for v4. v2/v3 also need to know the
+ * difference between NULL and UNIX.
+ */
+ switch (token) {
+ case Opt_sec_none:
+ mnt->flags &= ~NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 0;
+ mnt->auth_flavors[0] = RPC_AUTH_NULL;
+ break;
+ case Opt_sec_sys:
+ mnt->flags &= ~NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 0;
+ mnt->auth_flavors[0] = RPC_AUTH_UNIX;
+ break;
+ case Opt_sec_krb5:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5;
+ break;
+ case Opt_sec_krb5i:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I;
+ break;
+ case Opt_sec_krb5p:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P;
+ break;
+ case Opt_sec_lkey:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY;
+ break;
+ case Opt_sec_lkeyi:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI;
+ break;
+ case Opt_sec_lkeyp:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP;
+ break;
+ case Opt_sec_spkm:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM;
+ break;
+ case Opt_sec_spkmi:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI;
+ break;
+ case Opt_sec_spkmp:
+ mnt->flags |= NFS_MOUNT_SECFLAVOUR;
+ mnt->auth_flavor_len = 1;
+ mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP;
+ break;
+ default:
+ goto out_unrec_sec;
}
- case 5:
- memset(data->context, 0, sizeof(data->context));
- }
+ break;
+ case Opt_proto:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string,
+ nfs_xprt_protocol_tokens, args);
+ kfree(string);
+
+ switch (token) {
+ case Opt_udp:
+ mnt->flags &= ~NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = IPPROTO_UDP;
+ mnt->timeo = 7;
+ mnt->retrans = 5;
+ break;
+ case Opt_tcp:
+ mnt->flags |= NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = IPPROTO_TCP;
+ mnt->timeo = 600;
+ mnt->retrans = 2;
+ break;
+ default:
+ goto out_unrec_xprt;
+ }
+ break;
+ case Opt_mountproto:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string,
+ nfs_xprt_protocol_tokens, args);
+ kfree(string);
+
+ switch (token) {
+ case Opt_udp:
+ mnt->mount_server.protocol = IPPROTO_UDP;
+ break;
+ case Opt_tcp:
+ mnt->mount_server.protocol = IPPROTO_TCP;
+ break;
+ default:
+ goto out_unrec_xprt;
+ }
+ break;
+ case Opt_addr:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ mnt->nfs_server.address.sin_family = AF_INET;
+ mnt->nfs_server.address.sin_addr.s_addr =
+ in_aton(string);
+ kfree(string);
+ break;
+ case Opt_clientaddr:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ mnt->client_address = string;
+ break;
+ case Opt_mounthost:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ mnt->mount_server.address.sin_family = AF_INET;
+ mnt->mount_server.address.sin_addr.s_addr =
+ in_aton(string);
+ kfree(string);
+ break;
- /* Set the pseudoflavor */
- if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
- data->pseudoflavor = RPC_AUTH_UNIX;
+ case Opt_userspace:
+ case Opt_deprecated:
+ break;
-#ifndef CONFIG_NFS_V3
- /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
- if (data->flags & NFS_MOUNT_VER3) {
- dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
- return -EPROTONOSUPPORT;
+ default:
+ goto out_unknown;
+ }
}
-#endif /* CONFIG_NFS_V3 */
- /* We now require that the mount process passes the remote address */
- if (data->addr.sin_addr.s_addr == INADDR_ANY) {
- dprintk("%s: mount program didn't pass remote address!\n",
- __FUNCTION__);
- return -EINVAL;
+ return 1;
+
+out_nomem:
+ printk(KERN_INFO "NFS: not enough memory to parse option\n");
+ return 0;
+
+out_unrec_vers:
+ printk(KERN_INFO "NFS: unrecognized NFS version number\n");
+ return 0;
+
+out_unrec_xprt:
+ printk(KERN_INFO "NFS: unrecognized transport protocol\n");
+ return 0;
+
+out_unrec_sec:
+ printk(KERN_INFO "NFS: unrecognized security flavor\n");
+ return 0;
+
+out_unknown:
+ printk(KERN_INFO "NFS: unknown mount option: %s\n", p);
+ return 0;
+}
+
+/*
+ * Use the remote server's MOUNT service to request the NFS file handle
+ * corresponding to the provided path.
+ */
+static int nfs_try_mount(struct nfs_parsed_mount_data *args,
+ struct nfs_fh *root_fh)
+{
+ struct sockaddr_in sin;
+ int status;
+
+ if (args->mount_server.version == 0) {
+ if (args->flags & NFS_MOUNT_VER3)
+ args->mount_server.version = NFS_MNT3_VERSION;
+ else
+ args->mount_server.version = NFS_MNT_VERSION;
}
- /* Prepare the root filehandle */
- if (data->flags & NFS_MOUNT_VER3)
- mntfh->size = data->root.size;
+ /*
+ * Construct the mount server's address.
+ */
+ if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY)
+ sin = args->mount_server.address;
else
- mntfh->size = NFS2_FHSIZE;
+ sin = args->nfs_server.address;
+ if (args->mount_server.port == 0) {
+ status = rpcb_getport_sync(&sin,
+ args->mount_server.program,
+ args->mount_server.version,
+ args->mount_server.protocol);
+ if (status < 0)
+ goto out_err;
+ sin.sin_port = htons(status);
+ } else
+ sin.sin_port = htons(args->mount_server.port);
+
+ /*
+ * Now ask the mount server to map our export path
+ * to a file handle.
+ */
+ status = nfs_mount((struct sockaddr *) &sin,
+ sizeof(sin),
+ args->nfs_server.hostname,
+ args->nfs_server.export_path,
+ args->mount_server.version,
+ args->mount_server.protocol,
+ root_fh);
+ if (status < 0)
+ goto out_err;
+
+ return status;
- if (mntfh->size > sizeof(mntfh->data)) {
- dprintk("%s: invalid root filehandle\n", __FUNCTION__);
- return -EINVAL;
+out_err:
+ dfprintk(MOUNT, "NFS: unable to contact server on host "
+ NIPQUAD_FMT "\n", NIPQUAD(sin.sin_addr.s_addr));
+ return status;
+}
+
+/*
+ * Validate the NFS2/NFS3 mount data
+ * - fills in the mount root filehandle
+ *
+ * For option strings, user space handles the following behaviors:
+ *
+ * + DNS: mapping server host name to IP address ("addr=" option)
+ *
+ * + failure mode: how to behave if a mount request can't be handled
+ * immediately ("fg/bg" option)
+ *
+ * + retry: how often to retry a mount request ("retry=" option)
+ *
+ * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
+ * mountproto=tcp after mountproto=udp, and so on
+ *
+ * XXX: as far as I can tell, changing the NFS program number is not
+ * supported in the NFS client.
+ */
+static int nfs_validate_mount_data(struct nfs_mount_data **options,
+ struct nfs_fh *mntfh,
+ const char *dev_name)
+{
+ struct nfs_mount_data *data = *options;
+
+ if (data == NULL)
+ goto out_no_data;
+
+ switch (data->version) {
+ case 1:
+ data->namlen = 0;
+ case 2:
+ data->bsize = 0;
+ case 3:
+ if (data->flags & NFS_MOUNT_VER3)
+ goto out_no_v3;
+ data->root.size = NFS2_FHSIZE;
+ memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+ case 4:
+ if (data->flags & NFS_MOUNT_SECFLAVOUR)
+ goto out_no_sec;
+ case 5:
+ memset(data->context, 0, sizeof(data->context));
+ case 6:
+ if (data->flags & NFS_MOUNT_VER3)
+ mntfh->size = data->root.size;
+ else
+ mntfh->size = NFS2_FHSIZE;
+
+ if (mntfh->size > sizeof(mntfh->data))
+ goto out_invalid_fh;
+
+ memcpy(mntfh->data, data->root.data, mntfh->size);
+ if (mntfh->size < sizeof(mntfh->data))
+ memset(mntfh->data + mntfh->size, 0,
+ sizeof(mntfh->data) - mntfh->size);
+ break;
+ default: {
+ unsigned int len;
+ char *c;
+ int status;
+ struct nfs_parsed_mount_data args = {
+ .flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP),
+ .rsize = NFS_MAX_FILE_IO_SIZE,
+ .wsize = NFS_MAX_FILE_IO_SIZE,
+ .timeo = 600,
+ .retrans = 2,
+ .acregmin = 3,
+ .acregmax = 60,
+ .acdirmin = 30,
+ .acdirmax = 60,
+ .mount_server.protocol = IPPROTO_UDP,
+ .mount_server.program = NFS_MNT_PROGRAM,
+ .nfs_server.protocol = IPPROTO_TCP,
+ .nfs_server.program = NFS_PROGRAM,
+ };
+
+ if (nfs_parse_mount_options((char *) *options, &args) == 0)
+ return -EINVAL;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ /*
+ * NB: after this point, caller will free "data"
+ * if we return an error
+ */
+ *options = data;
+
+ c = strchr(dev_name, ':');
+ if (c == NULL)
+ return -EINVAL;
+ len = c - dev_name - 1;
+ if (len > sizeof(data->hostname))
+ return -EINVAL;
+ strncpy(data->hostname, dev_name, len);
+ args.nfs_server.hostname = data->hostname;
+
+ c++;
+ if (strlen(c) > NFS_MAXPATHLEN)
+ return -EINVAL;
+ args.nfs_server.export_path = c;
+
+ status = nfs_try_mount(&args, mntfh);
+ if (status)
+ return -EINVAL;
+
+ /*
+ * Translate to nfs_mount_data, which nfs_fill_super
+ * can deal with.
+ */
+ data->version = 6;
+ data->flags = args.flags;
+ data->rsize = args.rsize;
+ data->wsize = args.wsize;
+ data->timeo = args.timeo;
+ data->retrans = args.retrans;
+ data->acregmin = args.acregmin;
+ data->acregmax = args.acregmax;
+ data->acdirmin = args.acdirmin;
+ data->acdirmax = args.acdirmax;
+ data->addr = args.nfs_server.address;
+ data->namlen = args.namlen;
+ data->bsize = args.bsize;
+ data->pseudoflavor = args.auth_flavors[0];
+
+ break;
+ }
}
- memcpy(mntfh->data, data->root.data, mntfh->size);
- if (mntfh->size < sizeof(mntfh->data))
- memset(mntfh->data + mntfh->size, 0,
- sizeof(mntfh->data) - mntfh->size);
+ if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
+ data->pseudoflavor = RPC_AUTH_UNIX;
+
+#ifndef CONFIG_NFS_V3
+ if (data->flags & NFS_MOUNT_VER3)
+ goto out_v3_not_compiled;
+#endif /* !CONFIG_NFS_V3 */
+
+ if (!nfs_verify_server_address((struct sockaddr *) &data->addr))
+ goto out_no_address;
return 0;
+
+out_no_data:
+ dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
+ return -EINVAL;
+
+out_no_v3:
+ dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n",
+ data->version);
+ return -EINVAL;
+
+out_no_sec:
+ dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n");
+ return -EINVAL;
+
+#ifndef CONFIG_NFS_V3
+out_v3_not_compiled:
+ dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel\n");
+ return -EPROTONOSUPPORT;
+#endif /* !CONFIG_NFS_V3 */
+
+out_no_address:
+ dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
+ return -EINVAL;
+
+out_invalid_fh:
+ dfprintk(MOUNT, "NFS: invalid root filehandle\n");
+ return -EINVAL;
}
/*
@@ -600,13 +1319,51 @@ static int nfs_compare_super(struct super_block *sb, void *data)
{
struct nfs_server *server = data, *old = NFS_SB(sb);
- if (old->nfs_client != server->nfs_client)
+ if (memcmp(&old->nfs_client->cl_addr,
+ &server->nfs_client->cl_addr,
+ sizeof(old->nfs_client->cl_addr)) != 0)
+ return 0;
+ /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
+ if (old->flags & NFS_MOUNT_UNSHARED)
return 0;
if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
return 0;
return 1;
}
+#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
+
+static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
+{
+ const struct nfs_server *a = s->s_fs_info;
+ const struct rpc_clnt *clnt_a = a->client;
+ const struct rpc_clnt *clnt_b = b->client;
+
+ if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK))
+ goto Ebusy;
+ if (a->nfs_client != b->nfs_client)
+ goto Ebusy;
+ if (a->flags != b->flags)
+ goto Ebusy;
+ if (a->wsize != b->wsize)
+ goto Ebusy;
+ if (a->rsize != b->rsize)
+ goto Ebusy;
+ if (a->acregmin != b->acregmin)
+ goto Ebusy;
+ if (a->acregmax != b->acregmax)
+ goto Ebusy;
+ if (a->acdirmin != b->acdirmin)
+ goto Ebusy;
+ if (a->acdirmax != b->acdirmax)
+ goto Ebusy;
+ if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
+ goto Ebusy;
+ return 0;
+Ebusy:
+ return -EBUSY;
+}
+
static int nfs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
{
@@ -615,30 +1372,37 @@ static int nfs_get_sb(struct file_system_type *fs_type,
struct nfs_fh mntfh;
struct nfs_mount_data *data = raw_data;
struct dentry *mntroot;
+ int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
int error;
/* Validate the mount data */
- error = nfs_validate_mount_data(data, &mntfh);
+ error = nfs_validate_mount_data(&data, &mntfh, dev_name);
if (error < 0)
- return error;
+ goto out;
/* Get a volume representation */
server = nfs_create_server(data, &mntfh);
if (IS_ERR(server)) {
error = PTR_ERR(server);
- goto out_err_noserver;
+ goto out;
}
+ if (server->flags & NFS_MOUNT_UNSHARED)
+ compare_super = NULL;
+
/* Get a superblock - note that we may end up sharing one that already exists */
- s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
+ s = sget(fs_type, compare_super, nfs_set_super, server);
if (IS_ERR(s)) {
error = PTR_ERR(s);
goto out_err_nosb;
}
if (s->s_fs_info != server) {
+ error = nfs_compare_mount_options(s, server, flags);
nfs_free_server(server);
server = NULL;
+ if (error < 0)
+ goto error_splat_super;
}
if (!s->s_root) {
@@ -656,17 +1420,21 @@ static int nfs_get_sb(struct file_system_type *fs_type,
s->s_flags |= MS_ACTIVE;
mnt->mnt_sb = s;
mnt->mnt_root = mntroot;
- return 0;
+ error = 0;
+
+out:
+ if (data != raw_data)
+ kfree(data);
+ return error;
out_err_nosb:
nfs_free_server(server);
-out_err_noserver:
- return error;
+ goto out;
error_splat_super:
up_write(&s->s_umount);
deactivate_super(s);
- return error;
+ goto out;
}
/*
@@ -691,6 +1459,7 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
struct super_block *s;
struct nfs_server *server;
struct dentry *mntroot;
+ int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
int error;
dprintk("--> nfs_xdev_get_sb()\n");
@@ -702,16 +1471,22 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
goto out_err_noserver;
}
+ if (server->flags & NFS_MOUNT_UNSHARED)
+ compare_super = NULL;
+
/* Get a superblock - note that we may end up sharing one that already exists */
- s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+ s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
if (IS_ERR(s)) {
error = PTR_ERR(s);
goto out_err_nosb;
}
if (s->s_fs_info != server) {
+ error = nfs_compare_mount_options(s, server, flags);
nfs_free_server(server);
server = NULL;
+ if (error < 0)
+ goto error_splat_super;
}
if (!s->s_root) {
@@ -772,25 +1547,171 @@ static void nfs4_fill_super(struct super_block *sb)
nfs_initialise_sb(sb);
}
-static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
+/*
+ * Validate NFSv4 mount options
+ */
+static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
+ const char *dev_name,
+ struct sockaddr_in *addr,
+ rpc_authflavor_t *authflavour,
+ char **hostname,
+ char **mntpath,
+ char **ip_addr)
{
- void *p = NULL;
-
- if (!src->len)
- return ERR_PTR(-EINVAL);
- if (src->len < maxlen)
- maxlen = src->len;
- if (dst == NULL) {
- p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
- if (p == NULL)
- return ERR_PTR(-ENOMEM);
- }
- if (copy_from_user(dst, src->data, maxlen)) {
- kfree(p);
- return ERR_PTR(-EFAULT);
+ struct nfs4_mount_data *data = *options;
+ char *c;
+
+ if (data == NULL)
+ goto out_no_data;
+
+ switch (data->version) {
+ case 1:
+ if (data->host_addrlen != sizeof(*addr))
+ goto out_no_address;
+ if (copy_from_user(addr, data->host_addr, sizeof(*addr)))
+ return -EFAULT;
+ if (addr->sin_port == 0)
+ addr->sin_port = htons(NFS_PORT);
+ if (!nfs_verify_server_address((struct sockaddr *) addr))
+ goto out_no_address;
+
+ switch (data->auth_flavourlen) {
+ case 0:
+ *authflavour = RPC_AUTH_UNIX;
+ break;
+ case 1:
+ if (copy_from_user(authflavour, data->auth_flavours,
+ sizeof(*authflavour)))
+ return -EFAULT;
+ break;
+ default:
+ goto out_inval_auth;
+ }
+
+ c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+ *hostname = c;
+
+ c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+ *mntpath = c;
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath);
+
+ c = strndup_user(data->client_addr.data, 16);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+ *ip_addr = c;
+
+ break;
+ default: {
+ unsigned int len;
+ struct nfs_parsed_mount_data args = {
+ .rsize = NFS_MAX_FILE_IO_SIZE,
+ .wsize = NFS_MAX_FILE_IO_SIZE,
+ .timeo = 600,
+ .retrans = 2,
+ .acregmin = 3,
+ .acregmax = 60,
+ .acdirmin = 30,
+ .acdirmax = 60,
+ .nfs_server.protocol = IPPROTO_TCP,
+ };
+
+ if (nfs_parse_mount_options((char *) *options, &args) == 0)
+ return -EINVAL;
+
+ if (!nfs_verify_server_address((struct sockaddr *)
+ &args.nfs_server.address))
+ return -EINVAL;
+ *addr = args.nfs_server.address;
+
+ switch (args.auth_flavor_len) {
+ case 0:
+ *authflavour = RPC_AUTH_UNIX;
+ break;
+ case 1:
+ *authflavour = (rpc_authflavor_t) args.auth_flavors[0];
+ break;
+ default:
+ goto out_inval_auth;
+ }
+
+ /*
+ * Translate to nfs4_mount_data, which nfs4_fill_super
+ * can deal with.
+ */
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+ *options = data;
+
+ data->version = 1;
+ data->flags = args.flags & NFS4_MOUNT_FLAGMASK;
+ data->rsize = args.rsize;
+ data->wsize = args.wsize;
+ data->timeo = args.timeo;
+ data->retrans = args.retrans;
+ data->acregmin = args.acregmin;
+ data->acregmax = args.acregmax;
+ data->acdirmin = args.acdirmin;
+ data->acdirmax = args.acdirmax;
+ data->proto = args.nfs_server.protocol;
+
+ /*
+ * Split "dev_name" into "hostname:mntpath".
+ */
+ c = strchr(dev_name, ':');
+ if (c == NULL)
+ return -EINVAL;
+ /* while calculating len, pretend ':' is '\0' */
+ len = c - dev_name;
+ if (len > NFS4_MAXNAMLEN)
+ return -EINVAL;
+ *hostname = kzalloc(len, GFP_KERNEL);
+ if (*hostname == NULL)
+ return -ENOMEM;
+ strncpy(*hostname, dev_name, len - 1);
+
+ c++; /* step over the ':' */
+ len = strlen(c);
+ if (len > NFS4_MAXPATHLEN)
+ return -EINVAL;
+ *mntpath = kzalloc(len + 1, GFP_KERNEL);
+ if (*mntpath == NULL)
+ return -ENOMEM;
+ strncpy(*mntpath, c, len);
+
+ dprintk("MNTPATH: %s\n", *mntpath);
+
+ if (args.client_address == NULL)
+ goto out_no_client_address;
+
+ *ip_addr = args.client_address;
+
+ break;
+ }
}
- dst[maxlen] = '\0';
- return dst;
+
+ return 0;
+
+out_no_data:
+ dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
+ return -EINVAL;
+
+out_inval_auth:
+ dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
+ data->auth_flavourlen);
+ return -EINVAL;
+
+out_no_address:
+ dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
+ return -EINVAL;
+
+out_no_client_address:
+ dfprintk(MOUNT, "NFS4: mount program didn't pass callback address\n");
+ return -EINVAL;
}
/*
@@ -806,81 +1727,29 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
rpc_authflavor_t authflavour;
struct nfs_fh mntfh;
struct dentry *mntroot;
- char *mntpath = NULL, *hostname = NULL, ip_addr[16];
- void *p;
+ char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
+ int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
int error;
- if (data == NULL) {
- dprintk("%s: missing data argument\n", __FUNCTION__);
- return -EINVAL;
- }
- if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
- dprintk("%s: bad mount version\n", __FUNCTION__);
- return -EINVAL;
- }
-
- /* We now require that the mount process passes the remote address */
- if (data->host_addrlen != sizeof(addr))
- return -EINVAL;
-
- if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
- return -EFAULT;
-
- if (addr.sin_family != AF_INET ||
- addr.sin_addr.s_addr == INADDR_ANY
- ) {
- dprintk("%s: mount program didn't pass remote IP address!\n",
- __FUNCTION__);
- return -EINVAL;
- }
- /* RFC3530: The default port for NFS is 2049 */
- if (addr.sin_port == 0)
- addr.sin_port = htons(NFS_PORT);
-
- /* Grab the authentication type */
- authflavour = RPC_AUTH_UNIX;
- if (data->auth_flavourlen != 0) {
- if (data->auth_flavourlen != 1) {
- dprintk("%s: Invalid number of RPC auth flavours %d.\n",
- __FUNCTION__, data->auth_flavourlen);
- error = -EINVAL;
- goto out_err_noserver;
- }
-
- if (copy_from_user(&authflavour, data->auth_flavours,
- sizeof(authflavour))) {
- error = -EFAULT;
- goto out_err_noserver;
- }
- }
-
- p = nfs_copy_user_string(NULL, &data->hostname, 256);
- if (IS_ERR(p))
- goto out_err;
- hostname = p;
-
- p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
- if (IS_ERR(p))
- goto out_err;
- mntpath = p;
-
- dprintk("MNTPATH: %s\n", mntpath);
-
- p = nfs_copy_user_string(ip_addr, &data->client_addr,
- sizeof(ip_addr) - 1);
- if (IS_ERR(p))
- goto out_err;
+ /* Validate the mount data */
+ error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour,
+ &hostname, &mntpath, &ip_addr);
+ if (error < 0)
+ goto out;
/* Get a volume representation */
server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
authflavour, &mntfh);
if (IS_ERR(server)) {
error = PTR_ERR(server);
- goto out_err_noserver;
+ goto out;
}
+ if (server->flags & NFS4_MOUNT_UNSHARED)
+ compare_super = NULL;
+
/* Get a superblock - note that we may end up sharing one that already exists */
- s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
+ s = sget(fs_type, compare_super, nfs_set_super, server);
if (IS_ERR(s)) {
error = PTR_ERR(s);
goto out_free;
@@ -906,25 +1775,22 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
s->s_flags |= MS_ACTIVE;
mnt->mnt_sb = s;
mnt->mnt_root = mntroot;
+ error = 0;
+
+out:
+ kfree(ip_addr);
kfree(mntpath);
kfree(hostname);
- return 0;
-
-out_err:
- error = PTR_ERR(p);
- goto out_err_noserver;
+ return error;
out_free:
nfs_free_server(server);
-out_err_noserver:
- kfree(mntpath);
- kfree(hostname);
- return error;
+ goto out;
error_splat_super:
up_write(&s->s_umount);
deactivate_super(s);
- goto out_err_noserver;
+ goto out;
}
static void nfs4_kill_super(struct super_block *sb)
@@ -949,6 +1815,7 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
struct super_block *s;
struct nfs_server *server;
struct dentry *mntroot;
+ int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
int error;
dprintk("--> nfs4_xdev_get_sb()\n");
@@ -960,8 +1827,11 @@ static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
goto out_err_noserver;
}
+ if (server->flags & NFS4_MOUNT_UNSHARED)
+ compare_super = NULL;
+
/* Get a superblock - note that we may end up sharing one that already exists */
- s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+ s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
if (IS_ERR(s)) {
error = PTR_ERR(s);
goto out_err_nosb;
@@ -1016,6 +1886,7 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
struct nfs_server *server;
struct dentry *mntroot;
struct nfs_fh mntfh;
+ int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
int error;
dprintk("--> nfs4_referral_get_sb()\n");
@@ -1027,8 +1898,11 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
goto out_err_noserver;
}
+ if (server->flags & NFS4_MOUNT_UNSHARED)
+ compare_super = NULL;
+
/* Get a superblock - note that we may end up sharing one that already exists */
- s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
+ s = sget(&nfs_fs_type, compare_super, nfs_set_super, server);
if (IS_ERR(s)) {
error = PTR_ERR(s);
goto out_err_nosb;
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c
index 0e28189c2151..045ab805c17f 100644
--- a/fs/nfs/unlink.c
+++ b/fs/nfs/unlink.c
@@ -3,7 +3,6 @@
*
* nfs sillydelete handling
*
- * NOTE: we rely on holding the BKL for list manipulation protection.
*/
#include <linux/slab.h>
@@ -15,46 +14,23 @@
struct nfs_unlinkdata {
- struct nfs_unlinkdata *next;
- struct dentry *dir, *dentry;
- struct qstr name;
- struct rpc_task task;
+ struct nfs_removeargs args;
+ struct nfs_removeres res;
+ struct inode *dir;
struct rpc_cred *cred;
- unsigned int count;
};
-static struct nfs_unlinkdata *nfs_deletes;
-static RPC_WAITQ(nfs_delete_queue, "nfs_delete_queue");
-
-/**
- * nfs_detach_unlinkdata - Remove asynchronous unlink from global list
- * @data: pointer to descriptor
- */
-static inline void
-nfs_detach_unlinkdata(struct nfs_unlinkdata *data)
-{
- struct nfs_unlinkdata **q;
-
- for (q = &nfs_deletes; *q != NULL; q = &((*q)->next)) {
- if (*q == data) {
- *q = data->next;
- break;
- }
- }
-}
-
/**
- * nfs_put_unlinkdata - release data from a sillydelete operation.
+ * nfs_free_unlinkdata - release data from a sillydelete operation.
* @data: pointer to unlink structure.
*/
static void
-nfs_put_unlinkdata(struct nfs_unlinkdata *data)
+nfs_free_unlinkdata(struct nfs_unlinkdata *data)
{
- if (--data->count == 0) {
- nfs_detach_unlinkdata(data);
- kfree(data->name.name);
- kfree(data);
- }
+ iput(data->dir);
+ put_rpccred(data->cred);
+ kfree(data->args.name.name);
+ kfree(data);
}
#define NAME_ALLOC_LEN(len) ((len+16) & ~15)
@@ -63,50 +39,36 @@ nfs_put_unlinkdata(struct nfs_unlinkdata *data)
* @dentry: pointer to dentry
* @data: nfs_unlinkdata
*/
-static inline void
-nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
+static int nfs_copy_dname(struct dentry *dentry, struct nfs_unlinkdata *data)
{
char *str;
int len = dentry->d_name.len;
- str = kmalloc(NAME_ALLOC_LEN(len), GFP_KERNEL);
+ str = kmemdup(dentry->d_name.name, NAME_ALLOC_LEN(len), GFP_KERNEL);
if (!str)
- return;
- memcpy(str, dentry->d_name.name, len);
- if (!data->name.len) {
- data->name.len = len;
- data->name.name = str;
- } else
- kfree(str);
+ return -ENOMEM;
+ data->args.name.len = len;
+ data->args.name.name = str;
+ return 0;
}
/**
* nfs_async_unlink_init - Initialize the RPC info
- * @task: rpc_task of the sillydelete
- *
- * We delay initializing RPC info until after the call to dentry_iput()
- * in order to minimize races against rename().
+ * task: rpc_task of the sillydelete
*/
static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
{
- struct nfs_unlinkdata *data = calldata;
- struct dentry *dir = data->dir;
- struct rpc_message msg = {
- .rpc_cred = data->cred,
+ struct nfs_unlinkdata *data = calldata;
+ struct inode *dir = data->dir;
+ struct rpc_message msg = {
+ .rpc_argp = &data->args,
+ .rpc_resp = &data->res,
+ .rpc_cred = data->cred,
};
- int status = -ENOENT;
-
- if (!data->name.len)
- goto out_err;
- status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
- if (status < 0)
- goto out_err;
- nfs_begin_data_update(dir->d_inode);
+ nfs_begin_data_update(dir);
+ NFS_PROTO(dir)->unlink_setup(&msg, dir);
rpc_call_setup(task, &msg, 0);
- return;
- out_err:
- rpc_exit(task, status);
}
/**
@@ -117,19 +79,13 @@ static void nfs_async_unlink_init(struct rpc_task *task, void *calldata)
*/
static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
{
- struct nfs_unlinkdata *data = calldata;
- struct dentry *dir = data->dir;
- struct inode *dir_i;
-
- if (!dir)
- return;
- dir_i = dir->d_inode;
- nfs_end_data_update(dir_i);
- if (NFS_PROTO(dir_i)->unlink_done(dir, task))
- return;
- put_rpccred(data->cred);
- data->cred = NULL;
- dput(dir);
+ struct nfs_unlinkdata *data = calldata;
+ struct inode *dir = data->dir;
+
+ if (!NFS_PROTO(dir)->unlink_done(task, dir))
+ rpc_restart_call(task);
+ else
+ nfs_end_data_update(dir);
}
/**
@@ -142,7 +98,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
static void nfs_async_unlink_release(void *calldata)
{
struct nfs_unlinkdata *data = calldata;
- nfs_put_unlinkdata(data);
+ nfs_free_unlinkdata(data);
}
static const struct rpc_call_ops nfs_unlink_ops = {
@@ -151,73 +107,94 @@ static const struct rpc_call_ops nfs_unlink_ops = {
.rpc_release = nfs_async_unlink_release,
};
+static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)
+{
+ struct rpc_task *task;
+ struct dentry *parent;
+ struct inode *dir;
+
+ if (nfs_copy_dname(dentry, data) < 0)
+ goto out_free;
+
+ parent = dget_parent(dentry);
+ if (parent == NULL)
+ goto out_free;
+ dir = igrab(parent->d_inode);
+ dput(parent);
+ if (dir == NULL)
+ goto out_free;
+
+ data->dir = dir;
+ data->args.fh = NFS_FH(dir);
+ nfs_fattr_init(&data->res.dir_attr);
+
+ task = rpc_run_task(NFS_CLIENT(dir), RPC_TASK_ASYNC, &nfs_unlink_ops, data);
+ if (!IS_ERR(task))
+ rpc_put_task(task);
+ return 1;
+out_free:
+ return 0;
+}
+
/**
* nfs_async_unlink - asynchronous unlinking of a file
+ * @dir: parent directory of dentry
* @dentry: dentry to unlink
*/
int
-nfs_async_unlink(struct dentry *dentry)
+nfs_async_unlink(struct inode *dir, struct dentry *dentry)
{
- struct dentry *dir = dentry->d_parent;
- struct nfs_unlinkdata *data;
- struct rpc_clnt *clnt = NFS_CLIENT(dir->d_inode);
- int status = -ENOMEM;
+ struct nfs_unlinkdata *data;
+ int status = -ENOMEM;
data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
+ if (data == NULL)
goto out;
- data->cred = rpcauth_lookupcred(clnt->cl_auth, 0);
+ data->cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
if (IS_ERR(data->cred)) {
status = PTR_ERR(data->cred);
goto out_free;
}
- data->dir = dget(dir);
- data->dentry = dentry;
-
- data->next = nfs_deletes;
- nfs_deletes = data;
- data->count = 1;
-
- rpc_init_task(&data->task, clnt, RPC_TASK_ASYNC, &nfs_unlink_ops, data);
+ status = -EBUSY;
spin_lock(&dentry->d_lock);
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
+ goto out_unlock;
dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+ dentry->d_fsdata = data;
spin_unlock(&dentry->d_lock);
-
- rpc_sleep_on(&nfs_delete_queue, &data->task, NULL, NULL);
- status = 0;
- out:
- return status;
+ return 0;
+out_unlock:
+ spin_unlock(&dentry->d_lock);
+ put_rpccred(data->cred);
out_free:
kfree(data);
+out:
return status;
}
/**
* nfs_complete_unlink - Initialize completion of the sillydelete
* @dentry: dentry to delete
+ * @inode: inode
*
* Since we're most likely to be called by dentry_iput(), we
* only use the dentry to find the sillydelete. We then copy the name
* into the qstr.
*/
void
-nfs_complete_unlink(struct dentry *dentry)
+nfs_complete_unlink(struct dentry *dentry, struct inode *inode)
{
- struct nfs_unlinkdata *data;
+ struct nfs_unlinkdata *data = NULL;
- for(data = nfs_deletes; data != NULL; data = data->next) {
- if (dentry == data->dentry)
- break;
- }
- if (!data)
- return;
- data->count++;
- nfs_copy_dname(dentry, data);
spin_lock(&dentry->d_lock);
- dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+ dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+ data = dentry->d_fsdata;
+ }
spin_unlock(&dentry->d_lock);
- rpc_wake_up_task(&data->task);
- nfs_put_unlinkdata(data);
+
+ if (data != NULL && (NFS_STALE(inode) || !nfs_call_unlink(dentry, data)))
+ nfs_free_unlinkdata(data);
}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index af344a158e01..ef97e0c0f5b1 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -117,19 +117,19 @@ static struct nfs_page *nfs_page_find_request_locked(struct page *page)
if (PagePrivate(page)) {
req = (struct nfs_page *)page_private(page);
if (req != NULL)
- atomic_inc(&req->wb_count);
+ kref_get(&req->wb_kref);
}
return req;
}
static struct nfs_page *nfs_page_find_request(struct page *page)
{
+ struct inode *inode = page->mapping->host;
struct nfs_page *req = NULL;
- spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
- spin_lock(req_lock);
+ spin_lock(&inode->i_lock);
req = nfs_page_find_request_locked(page);
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
return req;
}
@@ -191,8 +191,6 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
}
/* Update file length */
nfs_grow_file(page, offset, count);
- /* Set the PG_uptodate flag? */
- nfs_mark_uptodate(page, offset, count);
nfs_unlock_request(req);
return 0;
}
@@ -253,16 +251,16 @@ static void nfs_end_page_writeback(struct page *page)
static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
struct page *page)
{
+ struct inode *inode = page->mapping->host;
+ struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_page *req;
- struct nfs_inode *nfsi = NFS_I(page->mapping->host);
- spinlock_t *req_lock = &nfsi->req_lock;
int ret;
- spin_lock(req_lock);
+ spin_lock(&inode->i_lock);
for(;;) {
req = nfs_page_find_request_locked(page);
if (req == NULL) {
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
return 1;
}
if (nfs_lock_request_dontget(req))
@@ -272,28 +270,28 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
* succeed provided that someone hasn't already marked the
* request as dirty (in which case we don't care).
*/
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
ret = nfs_wait_on_request(req);
nfs_release_request(req);
if (ret != 0)
return ret;
- spin_lock(req_lock);
+ spin_lock(&inode->i_lock);
}
if (test_bit(PG_NEED_COMMIT, &req->wb_flags)) {
/* This request is marked for commit */
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
nfs_unlock_request(req);
nfs_pageio_complete(pgio);
return 1;
}
if (nfs_set_page_writeback(page) != 0) {
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
BUG();
}
radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
- NFS_PAGE_TAG_WRITEBACK);
+ NFS_PAGE_TAG_LOCKED);
ret = test_bit(PG_NEED_FLUSH, &req->wb_flags);
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
nfs_pageio_add_request(pgio, req);
return ret;
}
@@ -400,7 +398,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
if (PageDirty(req->wb_page))
set_bit(PG_NEED_FLUSH, &req->wb_flags);
nfsi->npages++;
- atomic_inc(&req->wb_count);
+ kref_get(&req->wb_kref);
return 0;
}
@@ -409,12 +407,12 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
*/
static void nfs_inode_remove_request(struct nfs_page *req)
{
- struct inode *inode = req->wb_context->dentry->d_inode;
+ struct inode *inode = req->wb_context->path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
BUG_ON (!NFS_WBACK_BUSY(req));
- spin_lock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
set_page_private(req->wb_page, 0);
ClearPagePrivate(req->wb_page);
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
@@ -422,11 +420,11 @@ static void nfs_inode_remove_request(struct nfs_page *req)
__set_page_dirty_nobuffers(req->wb_page);
nfsi->npages--;
if (!nfsi->npages) {
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
nfs_end_data_update(inode);
iput(inode);
} else
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
nfs_clear_request(req);
nfs_release_request(req);
}
@@ -457,14 +455,16 @@ nfs_dirty_request(struct nfs_page *req)
static void
nfs_mark_request_commit(struct nfs_page *req)
{
- struct inode *inode = req->wb_context->dentry->d_inode;
+ struct inode *inode = req->wb_context->path.dentry->d_inode;
struct nfs_inode *nfsi = NFS_I(inode);
- spin_lock(&nfsi->req_lock);
- nfs_list_add_request(req, &nfsi->commit);
+ spin_lock(&inode->i_lock);
nfsi->ncommit++;
set_bit(PG_NEED_COMMIT, &(req)->wb_flags);
- spin_unlock(&nfsi->req_lock);
+ radix_tree_tag_set(&nfsi->nfs_page_tree,
+ req->wb_index,
+ NFS_PAGE_TAG_COMMIT);
+ spin_unlock(&inode->i_lock);
inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
}
@@ -526,18 +526,18 @@ static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, u
idx_end = idx_start + npages - 1;
next = idx_start;
- while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_WRITEBACK)) {
+ while (radix_tree_gang_lookup_tag(&nfsi->nfs_page_tree, (void **)&req, next, 1, NFS_PAGE_TAG_LOCKED)) {
if (req->wb_index > idx_end)
break;
next = req->wb_index + 1;
BUG_ON(!NFS_WBACK_BUSY(req));
- atomic_inc(&req->wb_count);
- spin_unlock(&nfsi->req_lock);
+ kref_get(&req->wb_kref);
+ spin_unlock(&inode->i_lock);
error = nfs_wait_on_request(req);
nfs_release_request(req);
- spin_lock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
if (error < 0)
return error;
res++;
@@ -577,10 +577,9 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, u
int res = 0;
if (nfsi->ncommit != 0) {
- res = nfs_scan_list(nfsi, &nfsi->commit, dst, idx_start, npages);
+ res = nfs_scan_list(nfsi, dst, idx_start, npages,
+ NFS_PAGE_TAG_COMMIT);
nfsi->ncommit -= res;
- if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
- printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
}
return res;
}
@@ -603,7 +602,6 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
{
struct address_space *mapping = page->mapping;
struct inode *inode = mapping->host;
- struct nfs_inode *nfsi = NFS_I(inode);
struct nfs_page *req, *new = NULL;
pgoff_t rqend, end;
@@ -613,13 +611,13 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
/* Loop over all inode entries and see if we find
* A request for the page we wish to update
*/
- spin_lock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
req = nfs_page_find_request_locked(page);
if (req) {
if (!nfs_lock_request_dontget(req)) {
int error;
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
error = nfs_wait_on_request(req);
nfs_release_request(req);
if (error < 0) {
@@ -629,7 +627,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
}
continue;
}
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
if (new)
nfs_release_request(new);
break;
@@ -640,14 +638,14 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
nfs_lock_request_dontget(new);
error = nfs_inode_add_request(inode, new);
if (error) {
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
nfs_unlock_request(new);
return ERR_PTR(error);
}
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
return new;
}
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
new = nfs_create_request(ctx, inode, page, offset, bytes);
if (IS_ERR(new))
@@ -751,12 +749,17 @@ int nfs_updatepage(struct file *file, struct page *page,
static void nfs_writepage_release(struct nfs_page *req)
{
- if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) {
+ if (PageError(req->wb_page)) {
+ nfs_end_page_writeback(req->wb_page);
+ nfs_inode_remove_request(req);
+ } else if (!nfs_reschedule_unstable_write(req)) {
+ /* Set the PG_uptodate flag */
+ nfs_mark_uptodate(req->wb_page, req->wb_pgbase, req->wb_bytes);
nfs_end_page_writeback(req->wb_page);
nfs_inode_remove_request(req);
} else
nfs_end_page_writeback(req->wb_page);
- nfs_clear_page_writeback(req);
+ nfs_clear_page_tag_locked(req);
}
static inline int flush_task_priority(int how)
@@ -786,7 +789,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req,
* NB: take care not to mess about with data->commit et al. */
data->req = req;
- data->inode = inode = req->wb_context->dentry->d_inode;
+ data->inode = inode = req->wb_context->path.dentry->d_inode;
data->cred = req->wb_context->cred;
data->args.fh = NFS_FH(inode);
@@ -885,7 +888,7 @@ out_bad:
}
nfs_redirty_request(req);
nfs_end_page_writeback(req->wb_page);
- nfs_clear_page_writeback(req);
+ nfs_clear_page_tag_locked(req);
return -ENOMEM;
}
@@ -928,7 +931,7 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i
nfs_list_remove_request(req);
nfs_redirty_request(req);
nfs_end_page_writeback(req->wb_page);
- nfs_clear_page_writeback(req);
+ nfs_clear_page_tag_locked(req);
}
return -ENOMEM;
}
@@ -954,8 +957,8 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
struct page *page = req->wb_page;
dprintk("NFS: write (%s/%Ld %d@%Ld)",
- req->wb_context->dentry->d_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+ req->wb_context->path.dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
@@ -970,9 +973,9 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
}
if (nfs_write_need_commit(data)) {
- spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
+ struct inode *inode = page->mapping->host;
- spin_lock(req_lock);
+ spin_lock(&inode->i_lock);
if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) {
/* Do nothing we need to resend the writes */
} else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) {
@@ -983,7 +986,7 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
clear_bit(PG_NEED_COMMIT, &req->wb_flags);
dprintk(" server reboot detected\n");
}
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
} else
dprintk(" OK\n");
@@ -1020,8 +1023,8 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
page = req->wb_page;
dprintk("NFS: write (%s/%Ld %d@%Ld)",
- req->wb_context->dentry->d_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+ req->wb_context->path.dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
@@ -1039,12 +1042,14 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
dprintk(" marked for commit\n");
goto next;
}
+ /* Set the PG_uptodate flag? */
+ nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
dprintk(" OK\n");
remove_request:
nfs_end_page_writeback(page);
nfs_inode_remove_request(req);
next:
- nfs_clear_page_writeback(req);
+ nfs_clear_page_tag_locked(req);
}
}
@@ -1157,7 +1162,7 @@ static void nfs_commit_rpcsetup(struct list_head *head,
list_splice_init(head, &data->pages);
first = nfs_list_entry(data->pages.next);
- inode = first->wb_context->dentry->d_inode;
+ inode = first->wb_context->path.dentry->d_inode;
data->inode = inode;
data->cred = first->wb_context->cred;
@@ -1207,7 +1212,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
nfs_list_remove_request(req);
nfs_mark_request_commit(req);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
- nfs_clear_page_writeback(req);
+ nfs_clear_page_tag_locked(req);
}
return -ENOMEM;
}
@@ -1234,8 +1239,8 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
dprintk("NFS: commit (%s/%Ld %d@%Ld)",
- req->wb_context->dentry->d_inode->i_sb->s_id,
- (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+ req->wb_context->path.dentry->d_inode->i_sb->s_id,
+ (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
req->wb_bytes,
(long long)req_offset(req));
if (task->tk_status < 0) {
@@ -1249,6 +1254,9 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
* returned by the server against all stored verfs. */
if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
/* We have a match */
+ /* Set the PG_uptodate flag */
+ nfs_mark_uptodate(req->wb_page, req->wb_pgbase,
+ req->wb_bytes);
nfs_inode_remove_request(req);
dprintk(" OK\n");
goto next;
@@ -1257,7 +1265,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
dprintk(" mismatch\n");
nfs_redirty_request(req);
next:
- nfs_clear_page_writeback(req);
+ nfs_clear_page_tag_locked(req);
}
}
@@ -1268,13 +1276,12 @@ static const struct rpc_call_ops nfs_commit_ops = {
int nfs_commit_inode(struct inode *inode, int how)
{
- struct nfs_inode *nfsi = NFS_I(inode);
LIST_HEAD(head);
int res;
- spin_lock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
res = nfs_scan_commit(inode, &head, 0, 0);
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
if (res) {
int error = nfs_commit_list(inode, &head, how);
if (error < 0)
@@ -1292,7 +1299,6 @@ static inline int nfs_commit_list(struct inode *inode, struct list_head *head, i
long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how)
{
struct inode *inode = mapping->host;
- struct nfs_inode *nfsi = NFS_I(inode);
pgoff_t idx_start, idx_end;
unsigned int npages = 0;
LIST_HEAD(head);
@@ -1314,7 +1320,7 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr
}
}
how &= ~FLUSH_NOCOMMIT;
- spin_lock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
do {
ret = nfs_wait_on_requests_locked(inode, idx_start, npages);
if (ret != 0)
@@ -1325,18 +1331,19 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr
if (pages == 0)
break;
if (how & FLUSH_INVALIDATE) {
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
nfs_cancel_commit_list(&head);
ret = pages;
- spin_lock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
continue;
}
pages += nfs_scan_commit(inode, &head, 0, 0);
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
ret = nfs_commit_list(inode, &head, how);
- spin_lock(&nfsi->req_lock);
+ spin_lock(&inode->i_lock);
+
} while (ret >= 0);
- spin_unlock(&nfsi->req_lock);
+ spin_unlock(&inode->i_lock);
return ret;
}
@@ -1430,7 +1437,6 @@ int nfs_set_page_dirty(struct page *page)
{
struct address_space *mapping = page->mapping;
struct inode *inode;
- spinlock_t *req_lock;
struct nfs_page *req;
int ret;
@@ -1439,18 +1445,17 @@ int nfs_set_page_dirty(struct page *page)
inode = mapping->host;
if (!inode)
goto out_raced;
- req_lock = &NFS_I(inode)->req_lock;
- spin_lock(req_lock);
+ spin_lock(&inode->i_lock);
req = nfs_page_find_request_locked(page);
if (req != NULL) {
/* Mark any existing write requests for flushing */
ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags);
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
nfs_release_request(req);
return ret;
}
ret = __set_page_dirty_nobuffers(page);
- spin_unlock(req_lock);
+ spin_unlock(&inode->i_lock);
return ret;
out_raced:
return !TestSetPageDirty(page);
@@ -1462,7 +1467,7 @@ int __init nfs_init_writepagecache(void)
nfs_wdata_cachep = kmem_cache_create("nfs_write_data",
sizeof(struct nfs_write_data),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (nfs_wdata_cachep == NULL)
return -ENOMEM;
diff --git a/fs/nfsctl.c b/fs/nfsctl.c
index c043136a82ca..51f1b31acbf6 100644
--- a/fs/nfsctl.c
+++ b/fs/nfsctl.c
@@ -23,19 +23,15 @@
static struct file *do_open(char *name, int flags)
{
struct nameidata nd;
+ struct vfsmount *mnt;
int error;
- nd.mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
+ mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
+ if (IS_ERR(mnt))
+ return (struct file *)mnt;
- if (IS_ERR(nd.mnt))
- return (struct file *)nd.mnt;
-
- nd.dentry = dget(nd.mnt->mnt_root);
- nd.last_type = LAST_ROOT;
- nd.flags = 0;
- nd.depth = 0;
-
- error = path_walk(name, &nd);
+ error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd);
+ mntput(mnt); /* drop do_kern_mount reference */
if (error)
return ERR_PTR(error);
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
index 6e92b0fe5323..21928056e35e 100644
--- a/fs/nfsd/auth.c
+++ b/fs/nfsd/auth.c
@@ -9,20 +9,35 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcauth.h>
#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/export.h>
#define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
+int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
+{
+ struct exp_flavor_info *f;
+ struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
+
+ for (f = exp->ex_flavors; f < end; f++) {
+ if (f->pseudoflavor == rqstp->rq_flavor)
+ return f->flags;
+ }
+ return exp->ex_flags;
+
+}
+
int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
{
struct svc_cred cred = rqstp->rq_cred;
int i;
+ int flags = nfsexp_flags(rqstp, exp);
int ret;
- if (exp->ex_flags & NFSEXP_ALLSQUASH) {
+ if (flags & NFSEXP_ALLSQUASH) {
cred.cr_uid = exp->ex_anon_uid;
cred.cr_gid = exp->ex_anon_gid;
cred.cr_group_info = groups_alloc(0);
- } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) {
+ } else if (flags & NFSEXP_ROOTSQUASH) {
struct group_info *gi;
if (!cred.cr_uid)
cred.cr_uid = exp->ex_anon_uid;
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 79bd03b8bbf8..2d295dda4c1d 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -26,12 +26,15 @@
#include <linux/mount.h>
#include <linux/hash.h>
#include <linux/module.h>
+#include <linux/exportfs.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/nfsfh.h>
#include <linux/nfsd/syscall.h>
#include <linux/lockd/bind.h>
+#include <linux/sunrpc/msg_prot.h>
+#include <linux/sunrpc/gss_api.h>
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
@@ -451,8 +454,48 @@ out_free_all:
return err;
}
+static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
+{
+ int listsize, err;
+ struct exp_flavor_info *f;
+
+ err = get_int(mesg, &listsize);
+ if (err)
+ return err;
+ if (listsize < 0 || listsize > MAX_SECINFO_LIST)
+ return -EINVAL;
+
+ for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
+ err = get_int(mesg, &f->pseudoflavor);
+ if (err)
+ return err;
+ /*
+ * Just a quick sanity check; we could also try to check
+ * whether this pseudoflavor is supported, but at worst
+ * an unsupported pseudoflavor on the export would just
+ * be a pseudoflavor that won't match the flavor of any
+ * authenticated request. The administrator will
+ * probably discover the problem when someone fails to
+ * authenticate.
+ */
+ if (f->pseudoflavor < 0)
+ return -EINVAL;
+ err = get_int(mesg, &f->flags);
+ if (err)
+ return err;
+ /* Only some flags are allowed to differ between flavors: */
+ if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
+ return -EINVAL;
+ }
+ exp->ex_nflavors = listsize;
+ return 0;
+}
+
#else /* CONFIG_NFSD_V4 */
-static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; }
+static inline int
+fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
+static inline int
+secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
#endif
static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
@@ -476,6 +519,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
exp.ex_uuid = NULL;
+ /* secinfo */
+ exp.ex_nflavors = 0;
+
if (mesg[mlen-1] != '\n')
return -EINVAL;
mesg[mlen-1] = 0;
@@ -553,7 +599,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
if (exp.ex_uuid == NULL)
err = -ENOMEM;
}
- } else
+ } else if (strcmp(buf, "secinfo") == 0)
+ err = secinfo_parse(&mesg, buf, &exp);
+ else
/* quietly ignore unknown words and anything
* following. Newer user-space can try to set
* new values, then see what the result was.
@@ -593,6 +641,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
static void exp_flags(struct seq_file *m, int flag, int fsid,
uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
+static void show_secinfo(struct seq_file *m, struct svc_export *exp);
static int svc_export_show(struct seq_file *m,
struct cache_detail *cd,
@@ -622,6 +671,7 @@ static int svc_export_show(struct seq_file *m,
seq_printf(m, "%02x", exp->ex_uuid[i]);
}
}
+ show_secinfo(m, exp);
}
seq_puts(m, ")\n");
return 0;
@@ -654,6 +704,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
{
struct svc_export *new = container_of(cnew, struct svc_export, h);
struct svc_export *item = container_of(citem, struct svc_export, h);
+ int i;
new->ex_flags = item->ex_flags;
new->ex_anon_uid = item->ex_anon_uid;
@@ -669,6 +720,10 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
item->ex_fslocs.locations_count = 0;
new->ex_fslocs.migrated = item->ex_fslocs.migrated;
item->ex_fslocs.migrated = 0;
+ new->ex_nflavors = item->ex_nflavors;
+ for (i = 0; i < MAX_SECINFO_LIST; i++) {
+ new->ex_flavors[i] = item->ex_flavors[i];
+ }
}
static struct cache_head *svc_export_alloc(void)
@@ -738,16 +793,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
int err;
if (!clp)
- return NULL;
+ return ERR_PTR(-ENOENT);
key.ek_client = clp;
key.ek_fsidtype = fsid_type;
memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
ek = svc_expkey_lookup(&key);
- if (ek != NULL)
- if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
- ek = ERR_PTR(err);
+ if (ek == NULL)
+ return ERR_PTR(-ENOMEM);
+ err = cache_check(&svc_expkey_cache, &ek->h, reqp);
+ if (err)
+ return ERR_PTR(err);
return ek;
}
@@ -808,30 +865,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
struct cache_req *reqp)
{
struct svc_export *exp, key;
+ int err;
if (!clp)
- return NULL;
+ return ERR_PTR(-ENOENT);
key.ex_client = clp;
key.ex_mnt = mnt;
key.ex_dentry = dentry;
exp = svc_export_lookup(&key);
- if (exp != NULL) {
- int err;
-
- err = cache_check(&svc_export_cache, &exp->h, reqp);
- switch (err) {
- case 0: break;
- case -EAGAIN:
- case -ETIMEDOUT:
- exp = ERR_PTR(err);
- break;
- default:
- exp = NULL;
- }
- }
-
+ if (exp == NULL)
+ return ERR_PTR(-ENOMEM);
+ err = cache_check(&svc_export_cache, &exp->h, reqp);
+ if (err)
+ return ERR_PTR(err);
return exp;
}
@@ -847,7 +895,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
dget(dentry);
exp = exp_get_by_name(clp, mnt, dentry, reqp);
- while (exp == NULL && !IS_ROOT(dentry)) {
+ while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
struct dentry *parent;
parent = dget_parent(dentry);
@@ -900,7 +948,7 @@ static void exp_fsid_unhash(struct svc_export *exp)
return;
ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
- if (ek && !IS_ERR(ek)) {
+ if (!IS_ERR(ek)) {
ek->h.expiry_time = get_seconds()-1;
cache_put(&ek->h, &svc_expkey_cache);
}
@@ -938,7 +986,7 @@ static void exp_unhash(struct svc_export *exp)
struct inode *inode = exp->ex_dentry->d_inode;
ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
- if (ek && !IS_ERR(ek)) {
+ if (!IS_ERR(ek)) {
ek->h.expiry_time = get_seconds()-1;
cache_put(&ek->h, &svc_expkey_cache);
}
@@ -989,13 +1037,12 @@ exp_export(struct nfsctl_export *nxp)
/* must make sure there won't be an ex_fsid clash */
if ((nxp->ex_flags & NFSEXP_FSID) &&
- (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
- !IS_ERR(fsid_key) &&
+ (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
fsid_key->ek_mnt &&
(fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
goto finish;
- if (exp) {
+ if (!IS_ERR(exp)) {
/* just a flags/id/fsid update */
exp_fsid_unhash(exp);
@@ -1104,7 +1151,7 @@ exp_unexport(struct nfsctl_export *nxp)
err = -EINVAL;
exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
path_release(&nd);
- if (!exp)
+ if (IS_ERR(exp))
goto out_domain;
exp_do_unexport(exp);
@@ -1149,10 +1196,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
err = PTR_ERR(exp);
goto out;
}
- if (!exp) {
- dprintk("nfsd: exp_rootfh export not found.\n");
- goto out;
- }
/*
* fh must be initialized before calling fh_compose
@@ -1176,17 +1219,130 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
{
struct svc_export *exp;
struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
- if (!ek || IS_ERR(ek))
+ if (IS_ERR(ek))
return ERR_PTR(PTR_ERR(ek));
exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
cache_put(&ek->h, &svc_expkey_cache);
- if (!exp || IS_ERR(exp))
+ if (IS_ERR(exp))
return ERR_PTR(PTR_ERR(exp));
return exp;
}
+__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
+{
+ struct exp_flavor_info *f;
+ struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
+
+ /* legacy gss-only clients are always OK: */
+ if (exp->ex_client == rqstp->rq_gssclient)
+ return 0;
+ /* ip-address based client; check sec= export option: */
+ for (f = exp->ex_flavors; f < end; f++) {
+ if (f->pseudoflavor == rqstp->rq_flavor)
+ return 0;
+ }
+ /* defaults in absence of sec= options: */
+ if (exp->ex_nflavors == 0) {
+ if (rqstp->rq_flavor == RPC_AUTH_NULL ||
+ rqstp->rq_flavor == RPC_AUTH_UNIX)
+ return 0;
+ }
+ return nfserr_wrongsec;
+}
+
+/*
+ * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
+ * auth_unix client) if it's available and has secinfo information;
+ * otherwise, will try to use rq_gssclient.
+ *
+ * Called from functions that handle requests; functions that do work on
+ * behalf of mountd are passed a single client name to use, and should
+ * use exp_get_by_name() or exp_find().
+ */
+struct svc_export *
+rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
+ struct dentry *dentry)
+{
+ struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
+
+ if (rqstp->rq_client == NULL)
+ goto gss;
+
+ /* First try the auth_unix client: */
+ exp = exp_get_by_name(rqstp->rq_client, mnt, dentry,
+ &rqstp->rq_chandle);
+ if (PTR_ERR(exp) == -ENOENT)
+ goto gss;
+ if (IS_ERR(exp))
+ return exp;
+ /* If it has secinfo, assume there are no gss/... clients */
+ if (exp->ex_nflavors > 0)
+ return exp;
+gss:
+ /* Otherwise, try falling back on gss client */
+ if (rqstp->rq_gssclient == NULL)
+ return exp;
+ gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry,
+ &rqstp->rq_chandle);
+ if (PTR_ERR(gssexp) == -ENOENT)
+ return exp;
+ if (!IS_ERR(exp))
+ exp_put(exp);
+ return gssexp;
+}
+
+struct svc_export *
+rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
+{
+ struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
+
+ if (rqstp->rq_client == NULL)
+ goto gss;
+
+ /* First try the auth_unix client: */
+ exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
+ if (PTR_ERR(exp) == -ENOENT)
+ goto gss;
+ if (IS_ERR(exp))
+ return exp;
+ /* If it has secinfo, assume there are no gss/... clients */
+ if (exp->ex_nflavors > 0)
+ return exp;
+gss:
+ /* Otherwise, try falling back on gss client */
+ if (rqstp->rq_gssclient == NULL)
+ return exp;
+ gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
+ &rqstp->rq_chandle);
+ if (PTR_ERR(gssexp) == -ENOENT)
+ return exp;
+ if (!IS_ERR(exp))
+ exp_put(exp);
+ return gssexp;
+}
+
+struct svc_export *
+rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
+ struct dentry *dentry)
+{
+ struct svc_export *exp;
+
+ dget(dentry);
+ exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
+
+ while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
+ struct dentry *parent;
+
+ parent = dget_parent(dentry);
+ dput(dentry);
+ dentry = parent;
+ exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
+ }
+ dput(dentry);
+ return exp;
+}
/*
* Called when we need the filehandle for the root of the pseudofs,
@@ -1194,8 +1350,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
* export point with fsid==0
*/
__be32
-exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
- struct cache_req *creq)
+exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
{
struct svc_export *exp;
__be32 rv;
@@ -1203,12 +1358,16 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
- exp = exp_find(clp, FSID_NUM, fsidv, creq);
+ exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
+ if (PTR_ERR(exp) == -ENOENT)
+ return nfserr_perm;
if (IS_ERR(exp))
return nfserrno(PTR_ERR(exp));
- if (exp == NULL)
- return nfserr_perm;
rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
+ if (rv)
+ goto out;
+ rv = check_nfsd_access(exp, rqstp);
+out:
exp_put(exp);
return rv;
}
@@ -1296,28 +1455,62 @@ static struct flags {
{ 0, {"", ""}}
};
-static void exp_flags(struct seq_file *m, int flag, int fsid,
- uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
+static void show_expflags(struct seq_file *m, int flags, int mask)
{
- int first = 0;
struct flags *flg;
+ int state, first = 0;
for (flg = expflags; flg->flag; flg++) {
- int state = (flg->flag & flag)?0:1;
+ if (flg->flag & ~mask)
+ continue;
+ state = (flg->flag & flags) ? 0 : 1;
if (*flg->name[state])
seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
}
+}
+
+static void show_secinfo_flags(struct seq_file *m, int flags)
+{
+ seq_printf(m, ",");
+ show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
+}
+
+static void show_secinfo(struct seq_file *m, struct svc_export *exp)
+{
+ struct exp_flavor_info *f;
+ struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
+ int lastflags = 0, first = 0;
+
+ if (exp->ex_nflavors == 0)
+ return;
+ for (f = exp->ex_flavors; f < end; f++) {
+ if (first || f->flags != lastflags) {
+ if (!first)
+ show_secinfo_flags(m, lastflags);
+ seq_printf(m, ",sec=%d", f->pseudoflavor);
+ lastflags = f->flags;
+ } else {
+ seq_printf(m, ":%d", f->pseudoflavor);
+ }
+ }
+ show_secinfo_flags(m, lastflags);
+}
+
+static void exp_flags(struct seq_file *m, int flag, int fsid,
+ uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
+{
+ show_expflags(m, flag, NFSEXP_ALLFLAGS);
if (flag & NFSEXP_FSID)
- seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
+ seq_printf(m, ",fsid=%d", fsid);
if (anonu != (uid_t)-2 && anonu != (0x10000-2))
- seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
+ seq_printf(m, ",anonuid=%u", anonu);
if (anong != (gid_t)-2 && anong != (0x10000-2))
- seq_printf(m, "%sanongid=%d", first++?",":"", anong);
+ seq_printf(m, ",anongid=%u", anong);
if (fsloc && fsloc->locations_count > 0) {
char *loctype = (fsloc->migrated) ? "refer" : "replicas";
int i;
- seq_printf(m, "%s%s=", first++?",":"", loctype);
+ seq_printf(m, ",%s=", loctype);
seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
seq_putc(m, '@');
seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 221acd1f11f6..9e4a568a5013 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -65,6 +65,7 @@ nlm_fclose(struct file *filp)
static struct nlmsvc_binding nfsd_nlm_ops = {
.fopen = nlm_fopen, /* open file for locking */
.fclose = nlm_fclose, /* close file */
+ .get_grace_period = get_nfs4_grace_period,
};
void
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index cc3b7badd486..b6ed38380ab8 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -183,8 +183,13 @@ static void
summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
{
struct posix_acl_entry *pa, *pe;
- pas->users = 0;
- pas->groups = 0;
+
+ /*
+ * Only pas.users and pas.groups need initialization; previous
+ * posix_acl_valid() calls ensure that the other fields will be
+ * initialized in the following loop. But, just to placate gcc:
+ */
+ memset(pas, 0, sizeof(*pas));
pas->mask = 07;
pe = acl->a_entries + acl->a_count;
@@ -732,13 +737,16 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
*pacl = posix_state_to_acl(&effective_acl_state, flags);
if (IS_ERR(*pacl)) {
ret = PTR_ERR(*pacl);
+ *pacl = NULL;
goto out_dstate;
}
*dpacl = posix_state_to_acl(&default_acl_state,
flags | NFS4_ACL_TYPE_DEFAULT);
if (IS_ERR(*dpacl)) {
ret = PTR_ERR(*dpacl);
+ *dpacl = NULL;
posix_acl_release(*pacl);
+ *pacl = NULL;
goto out_dstate;
}
sort_pacl(*pacl);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 864090edc28b..31d6633c7fe4 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -75,7 +75,7 @@ enum nfs_cb_opnum4 {
#define op_enc_sz 1
#define op_dec_sz 2
#define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2))
-#define enc_stateid_sz 16
+#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2)
#define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \
1 + enc_stateid_sz + \
enc_nfs4_fh_sz)
@@ -394,7 +394,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
.rpc_argp = clp,
};
- char clientname[16];
int status;
if (atomic_read(&cb->cb_set))
@@ -417,11 +416,6 @@ nfsd4_probe_callback(struct nfs4_client *clp)
memset(program->stats, 0, sizeof(cb->cb_stat));
program->stats->program = program;
- /* Just here to make some printk's more useful: */
- snprintf(clientname, sizeof(clientname),
- "%u.%u.%u.%u", NIPQUAD(addr.sin_addr));
- args.servername = clientname;
-
/* Create RPC client */
cb->cb_client = rpc_create(&args);
if (IS_ERR(cb->cb_client)) {
@@ -429,29 +423,23 @@ nfsd4_probe_callback(struct nfs4_client *clp)
goto out_err;
}
- /* Kick rpciod, put the call on the wire. */
- if (rpciod_up() != 0)
- goto out_clnt;
-
/* the task holds a reference to the nfs4_client struct */
atomic_inc(&clp->cl_count);
msg.rpc_cred = nfsd4_lookupcred(clp,0);
if (IS_ERR(msg.rpc_cred))
- goto out_rpciod;
+ goto out_release_clp;
status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
put_rpccred(msg.rpc_cred);
if (status != 0) {
dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
- goto out_rpciod;
+ goto out_release_clp;
}
return;
-out_rpciod:
+out_release_clp:
atomic_dec(&clp->cl_count);
- rpciod_down();
-out_clnt:
rpc_shutdown_client(cb->cb_client);
out_err:
cb->cb_client = NULL;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 45aa21ce6784..2cf9a9a2d89c 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -587,6 +587,15 @@ idmap_lookup(struct svc_rqst *rqstp,
return ret;
}
+static char *
+rqst_authname(struct svc_rqst *rqstp)
+{
+ struct auth_domain *clp;
+
+ clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client;
+ return clp->name;
+}
+
static int
idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
uid_t *id)
@@ -600,7 +609,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
return -EINVAL;
memcpy(key.name, name, namelen);
key.name[namelen] = '\0';
- strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
+ strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
if (ret == -ENOENT)
ret = -ESRCH; /* nfserr_badname */
@@ -620,7 +629,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
};
int ret;
- strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
+ strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
if (ret == -ENOENT)
return sprintf(name, "%u", id);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 8522729830db..3c627128e205 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -47,6 +47,7 @@
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
#include <linux/nfs4_acl.h>
+#include <linux/sunrpc/gss_api.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -286,8 +287,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 status;
fh_put(&cstate->current_fh);
- status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh,
- &rqstp->rq_chandle);
+ status = exp_pseudoroot(rqstp, &cstate->current_fh);
return status;
}
@@ -474,8 +474,8 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 ret;
fh_init(&tmp_fh, NFS4_FHSIZE);
- if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
- &rqstp->rq_chandle)) != 0)
+ ret = exp_pseudoroot(rqstp, &tmp_fh);
+ if (ret)
return ret;
if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
fh_put(&tmp_fh);
@@ -611,6 +611,30 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
}
static __be32
+nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_secinfo *secinfo)
+{
+ struct svc_fh resfh;
+ struct svc_export *exp;
+ struct dentry *dentry;
+ __be32 err;
+
+ fh_init(&resfh, NFS4_FHSIZE);
+ err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
+ secinfo->si_name, secinfo->si_namelen,
+ &exp, &dentry);
+ if (err)
+ return err;
+ if (dentry->d_inode == NULL) {
+ exp_put(exp);
+ err = nfserr_noent;
+ } else
+ secinfo->si_exp = exp;
+ dput(dentry);
+ return err;
+}
+
+static __be32
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_setattr *setattr)
{
@@ -1009,6 +1033,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
[OP_SAVEFH] = {
.op_func = (nfsd4op_func)nfsd4_savefh,
},
+ [OP_SECINFO] = {
+ .op_func = (nfsd4op_func)nfsd4_secinfo,
+ },
[OP_SETATTR] = {
.op_func = (nfsd4op_func)nfsd4_setattr,
},
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 3cc8ce422ab1..3f559700788f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -49,8 +49,10 @@
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
#include <linux/namei.h>
+#include <linux/swap.h>
#include <linux/mutex.h>
#include <linux/lockd/bind.h>
+#include <linux/module.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -149,6 +151,7 @@ get_nfs4_file(struct nfs4_file *fi)
}
static int num_delegations;
+unsigned int max_delegations;
/*
* Open owner state (share locks)
@@ -192,7 +195,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
dprintk("NFSD alloc_init_deleg\n");
- if (num_delegations > STATEID_HASH_SIZE * 4)
+ if (fp->fi_had_conflict)
+ return NULL;
+ if (num_delegations > max_delegations)
return NULL;
dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
if (dp == NULL)
@@ -251,7 +256,7 @@ nfs4_close_delegation(struct nfs4_delegation *dp)
/* The following nfsd_close may not actually close the file,
* but we want to remove the lease in any case. */
if (dp->dl_flock)
- setlease(filp, F_UNLCK, &dp->dl_flock);
+ vfs_setlease(filp, F_UNLCK, &dp->dl_flock);
nfsd_close(filp);
}
@@ -378,7 +383,6 @@ shutdown_callback_client(struct nfs4_client *clp)
if (clnt) {
clp->cl_callback.cb_client = NULL;
rpc_shutdown_client(clnt);
- rpciod_down();
}
}
@@ -1000,6 +1004,7 @@ alloc_init_file(struct inode *ino)
list_add(&fp->fi_hash, &file_hashtbl[hashval]);
fp->fi_inode = igrab(ino);
fp->fi_id = current_fileid++;
+ fp->fi_had_conflict = false;
return fp;
}
return NULL;
@@ -1027,19 +1032,19 @@ static int
nfsd4_init_slabs(void)
{
stateowner_slab = kmem_cache_create("nfsd4_stateowners",
- sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
+ sizeof(struct nfs4_stateowner), 0, 0, NULL);
if (stateowner_slab == NULL)
goto out_nomem;
file_slab = kmem_cache_create("nfsd4_files",
- sizeof(struct nfs4_file), 0, 0, NULL, NULL);
+ sizeof(struct nfs4_file), 0, 0, NULL);
if (file_slab == NULL)
goto out_nomem;
stateid_slab = kmem_cache_create("nfsd4_stateids",
- sizeof(struct nfs4_stateid), 0, 0, NULL, NULL);
+ sizeof(struct nfs4_stateid), 0, 0, NULL);
if (stateid_slab == NULL)
goto out_nomem;
deleg_slab = kmem_cache_create("nfsd4_delegations",
- sizeof(struct nfs4_delegation), 0, 0, NULL, NULL);
+ sizeof(struct nfs4_delegation), 0, 0, NULL);
if (deleg_slab == NULL)
goto out_nomem;
return 0;
@@ -1326,6 +1331,7 @@ do_recall(void *__dp)
{
struct nfs4_delegation *dp = __dp;
+ dp->dl_file->fi_had_conflict = true;
nfsd4_cb_recall(dp);
return 0;
}
@@ -1396,7 +1402,7 @@ void nfsd_release_deleg_cb(struct file_lock *fl)
/*
* Set the delegation file_lock back pointer.
*
- * Called from __setlease() with lock_kernel() held.
+ * Called from setlease() with lock_kernel() held.
*/
static
void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
@@ -1410,7 +1416,7 @@ void nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl)
}
/*
- * Called from __setlease() with lock_kernel() held
+ * Called from setlease() with lock_kernel() held
*/
static
int nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try)
@@ -1710,10 +1716,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
fl.fl_file = stp->st_vfs_file;
fl.fl_pid = current->tgid;
- /* setlease checks to see if delegation should be handed out.
+ /* vfs_setlease checks to see if delegation should be handed out.
* the lock_manager callbacks fl_mylease and fl_change are used
*/
- if ((status = setlease(stp->st_vfs_file,
+ if ((status = vfs_setlease(stp->st_vfs_file,
flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK, &flp))) {
dprintk("NFSD: setlease failed [%d], no delegation\n", status);
unhash_delegation(dp);
@@ -3191,20 +3197,49 @@ nfsd4_load_reboot_recovery_data(void)
printk("NFSD: Failure reading reboot recovery data\n");
}
+unsigned long
+get_nfs4_grace_period(void)
+{
+ return max(user_lease_time, lease_time) * HZ;
+}
+
+/*
+ * Since the lifetime of a delegation isn't limited to that of an open, a
+ * client may quite reasonably hang on to a delegation as long as it has
+ * the inode cached. This becomes an obvious problem the first time a
+ * client's inode cache approaches the size of the server's total memory.
+ *
+ * For now we avoid this problem by imposing a hard limit on the number
+ * of delegations, which varies according to the server's memory size.
+ */
+static void
+set_max_delegations(void)
+{
+ /*
+ * Allow at most 4 delegations per megabyte of RAM. Quick
+ * estimates suggest that in the worst case (where every delegation
+ * is for a different inode), a delegation could take about 1.5K,
+ * giving a worst case usage of about 6% of memory.
+ */
+ max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
+}
+
/* initialization to perform when the nfsd service is started: */
static void
__nfs4_state_start(void)
{
- time_t grace_time;
+ unsigned long grace_time;
boot_time = get_seconds();
- grace_time = max(user_lease_time, lease_time);
+ grace_time = get_nfs_grace_period();
lease_time = user_lease_time;
in_grace = 1;
- printk("NFSD: starting %ld-second grace period\n", grace_time);
+ printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
+ grace_time/HZ);
laundry_wq = create_singlethread_workqueue("nfsd4");
- queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ);
+ queue_delayed_work(laundry_wq, &laundromat_work, grace_time);
+ set_max_delegations();
}
int
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 15809dfd88a5..b3d55c6747fd 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -56,6 +56,8 @@
#include <linux/nfsd_idmap.h>
#include <linux/nfs4.h>
#include <linux/nfs4_acl.h>
+#include <linux/sunrpc/gss_api.h>
+#include <linux/sunrpc/svcauth_gss.h>
#define NFSDDBG_FACILITY NFSDDBG_XDR
@@ -819,6 +821,23 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
}
static __be32
+nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
+ struct nfsd4_secinfo *secinfo)
+{
+ DECODE_HEAD;
+
+ READ_BUF(4);
+ READ32(secinfo->si_namelen);
+ READ_BUF(secinfo->si_namelen);
+ SAVEMEM(secinfo->si_name, secinfo->si_namelen);
+ status = check_filename(secinfo->si_name, secinfo->si_namelen,
+ nfserr_noent);
+ if (status)
+ return status;
+ DECODE_TAIL;
+}
+
+static __be32
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
{
DECODE_HEAD;
@@ -1131,6 +1150,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
case OP_SAVEFH:
op->status = nfs_ok;
break;
+ case OP_SECINFO:
+ op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);
+ break;
case OP_SETATTR:
op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
break;
@@ -1296,7 +1318,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
char *path, *rootpath;
fh_init(&tmp_fh, NFS4_FHSIZE);
- *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle);
+ *stat = exp_pseudoroot(rqstp, &tmp_fh);
if (*stat)
return NULL;
rootpath = tmp_fh.fh_export->ex_path;
@@ -1847,11 +1869,19 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
if (d_mountpoint(dentry)) {
int err;
+ /*
+ * Why the heck aren't we just using nfsd_lookup??
+ * Different "."/".." handling? Something else?
+ * At least, add a comment here to explain....
+ */
err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
if (err) {
nfserr = nfserrno(err);
goto out_put;
}
+ nfserr = check_nfsd_access(exp, cd->rd_rqstp);
+ if (nfserr)
+ goto out_put;
}
nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
@@ -2419,6 +2449,72 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
}
}
+static void
+nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr,
+ struct nfsd4_secinfo *secinfo)
+{
+ int i = 0;
+ struct svc_export *exp = secinfo->si_exp;
+ u32 nflavs;
+ struct exp_flavor_info *flavs;
+ struct exp_flavor_info def_flavs[2];
+ ENCODE_HEAD;
+
+ if (nfserr)
+ goto out;
+ if (exp->ex_nflavors) {
+ flavs = exp->ex_flavors;
+ nflavs = exp->ex_nflavors;
+ } else { /* Handling of some defaults in absence of real secinfo: */
+ flavs = def_flavs;
+ if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
+ nflavs = 2;
+ flavs[0].pseudoflavor = RPC_AUTH_UNIX;
+ flavs[1].pseudoflavor = RPC_AUTH_NULL;
+ } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
+ nflavs = 1;
+ flavs[0].pseudoflavor
+ = svcauth_gss_flavor(exp->ex_client);
+ } else {
+ nflavs = 1;
+ flavs[0].pseudoflavor
+ = exp->ex_client->flavour->flavour;
+ }
+ }
+
+ RESERVE_SPACE(4);
+ WRITE32(nflavs);
+ ADJUST_ARGS();
+ for (i = 0; i < nflavs; i++) {
+ u32 flav = flavs[i].pseudoflavor;
+ struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
+
+ if (gm) {
+ RESERVE_SPACE(4);
+ WRITE32(RPC_AUTH_GSS);
+ ADJUST_ARGS();
+ RESERVE_SPACE(4 + gm->gm_oid.len);
+ WRITE32(gm->gm_oid.len);
+ WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
+ ADJUST_ARGS();
+ RESERVE_SPACE(4);
+ WRITE32(0); /* qop */
+ ADJUST_ARGS();
+ RESERVE_SPACE(4);
+ WRITE32(gss_pseudoflavor_to_service(gm, flav));
+ ADJUST_ARGS();
+ gss_mech_put(gm);
+ } else {
+ RESERVE_SPACE(4);
+ WRITE32(flav);
+ ADJUST_ARGS();
+ }
+ }
+out:
+ if (exp)
+ exp_put(exp);
+}
+
/*
* The SETATTR encode routine is special -- it always encodes a bitmap,
* regardless of the error status.
@@ -2559,6 +2655,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
break;
case OP_SAVEFH:
break;
+ case OP_SECINFO:
+ nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo);
+ break;
case OP_SETATTR:
nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
break;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 71c686dc7257..baac89d917ca 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -35,7 +35,6 @@
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr.h>
#include <linux/nfsd/syscall.h>
-#include <linux/nfsd/interface.h>
#include <asm/uaccess.h>
@@ -245,7 +244,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size)
}
exp_readunlock();
if (err == 0)
- err = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base;
+ err = res->fh_size + offsetof(struct knfsd_fh, fh_base);
out:
return err;
}
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 6ca2d24fc216..0eb464a39aae 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -15,10 +15,12 @@
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/dcache.h>
+#include <linux/exportfs.h>
#include <linux/mount.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svcauth_gss.h>
#include <linux/nfsd/nfsd.h>
#define NFSDDBG_FACILITY NFSDDBG_FH
@@ -27,10 +29,6 @@
static int nfsd_nr_verified;
static int nfsd_nr_put;
-extern struct export_operations export_op_default;
-
-#define CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun)
-
/*
* our acceptability function.
* if NOSUBTREECHECK, accept anything
@@ -123,8 +121,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
int data_left = fh->fh_size/4;
error = nfserr_stale;
- if (rqstp->rq_client == NULL)
- goto out;
if (rqstp->rq_vers > 2)
error = nfserr_badhandle;
if (rqstp->rq_vers == 4 && fh->fh_size == 0)
@@ -148,7 +144,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
fh->fh_fsid[1] = fh->fh_fsid[2];
}
if ((data_left -= len)<0) goto out;
- exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle);
+ exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap);
datap += len;
} else {
dev_t xdev;
@@ -159,19 +155,17 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
xdev = old_decode_dev(fh->ofh_xdev);
xino = u32_to_ino_t(fh->ofh_xino);
mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
- exp = exp_find(rqstp->rq_client, FSID_DEV, tfh,
- &rqstp->rq_chandle);
+ exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
}
- if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN
- || PTR_ERR(exp) == -ETIMEDOUT)) {
- error = nfserrno(PTR_ERR(exp));
+ error = nfserr_stale;
+ if (PTR_ERR(exp) == -ENOENT)
goto out;
- }
- error = nfserr_stale;
- if (!exp || IS_ERR(exp))
+ if (IS_ERR(exp)) {
+ error = nfserrno(PTR_ERR(exp));
goto out;
+ }
/* Check if the request originated from a secure port. */
error = nfserr_perm;
@@ -211,11 +205,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
if (fileid_type == 0)
dentry = dget(exp->ex_dentry);
else {
- struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op;
- dentry = CALL(nop,decode_fh)(exp->ex_mnt->mnt_sb,
- datap, data_left,
- fileid_type,
- nfsd_acceptable, exp);
+ dentry = exportfs_decode_fh(exp->ex_mnt, datap,
+ data_left, fileid_type,
+ nfsd_acceptable, exp);
}
if (dentry == NULL)
goto out;
@@ -257,8 +249,19 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
if (error)
goto out;
+ if (!(access & MAY_LOCK)) {
+ /*
+ * pseudoflavor restrictions are not enforced on NLM,
+ * which clients virtually always use auth_sys for,
+ * even while using RPCSEC_GSS for NFS.
+ */
+ error = check_nfsd_access(exp, rqstp);
+ if (error)
+ goto out;
+ }
+
/* Finally, check access permissions. */
- error = nfsd_permission(exp, dentry, access);
+ error = nfsd_permission(rqstp, exp, dentry, access);
if (error) {
dprintk("fh_verify: %s/%s permission failure, "
@@ -286,15 +289,13 @@ out:
static inline int _fh_update(struct dentry *dentry, struct svc_export *exp,
__u32 *datap, int *maxsize)
{
- struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op;
-
if (dentry == exp->ex_dentry) {
*maxsize = 0;
return 0;
}
- return CALL(nop,encode_fh)(dentry, datap, maxsize,
- !(exp->ex_flags&NFSEXP_NOSUBTREECHECK));
+ return exportfs_encode_fh(dentry, datap, maxsize,
+ !(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
}
/*
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index b2c7147aa921..977a71f64e19 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -278,7 +278,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
* echo thing > device-special-file-or-pipe
* by doing a CREATE with type==0
*/
- nfserr = nfsd_permission(newfhp->fh_export,
+ nfserr = nfsd_permission(rqstp,
+ newfhp->fh_export,
newfhp->fh_dentry,
MAY_WRITE|MAY_LOCAL_ACCESS);
if (nfserr && nfserr != nfserr_rofs)
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index ff55950efb43..a8c89ae4c743 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/freezer.h>
#include <linux/fs_struct.h>
#include <linux/sunrpc/types.h>
@@ -432,6 +433,7 @@ nfsd(struct svc_rqst *rqstp)
* dirty pages.
*/
current->flags |= PF_LESS_THROTTLE;
+ set_freezable();
/*
* The main request loop
@@ -492,6 +494,15 @@ out:
module_put_and_exit(0);
}
+static __be32 map_new_errors(u32 vers, __be32 nfserr)
+{
+ if (nfserr == nfserr_jukebox && vers == 2)
+ return nfserr_dropit;
+ if (nfserr == nfserr_wrongsec && vers < 4)
+ return nfserr_acces;
+ return nfserr;
+}
+
int
nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
{
@@ -534,6 +545,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
/* Now call the procedure handler, and encode NFS status. */
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
+ nfserr = map_new_errors(rqstp->rq_vers, nfserr);
if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2)
nfserr = nfserr_dropit;
if (nfserr == nfserr_dropit) {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 8604e35bd48e..ee96a897a29e 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -113,21 +113,21 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
- exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle);
+ exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts);
if (IS_ERR(exp2)) {
err = PTR_ERR(exp2);
dput(mounts);
mntput(mnt);
goto out;
}
- if (exp2 && ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2))) {
+ if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
/* successfully crossed mount point */
exp_put(exp);
*expp = exp2;
dput(dentry);
*dpp = mounts;
} else {
- if (exp2) exp_put(exp2);
+ exp_put(exp2);
dput(mounts);
}
mntput(mnt);
@@ -135,21 +135,10 @@ out:
return err;
}
-/*
- * Look up one component of a pathname.
- * N.B. After this call _both_ fhp and resfh need an fh_put
- *
- * If the lookup would cross a mountpoint, and the mounted filesystem
- * is exported to the client with NFSEXP_NOHIDE, then the lookup is
- * accepted as it stands and the mounted directory is
- * returned. Otherwise the covered directory is returned.
- * NOTE: this mountpoint crossing is not supported properly by all
- * clients and is explicitly disallowed for NFSv3
- * NeilBrown <neilb@cse.unsw.edu.au>
- */
__be32
-nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
- int len, struct svc_fh *resfh)
+nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ const char *name, int len,
+ struct svc_export **exp_ret, struct dentry **dentry_ret)
{
struct svc_export *exp;
struct dentry *dparent;
@@ -168,8 +157,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
exp = fhp->fh_export;
exp_get(exp);
- err = nfserr_acces;
-
/* Lookup the name, but don't follow links */
if (isdotent(name, len)) {
if (len==1)
@@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
dput(dentry);
dentry = dp;
- exp2 = exp_parent(exp->ex_client, mnt, dentry,
- &rqstp->rq_chandle);
- if (IS_ERR(exp2)) {
+ exp2 = rqst_exp_parent(rqstp, mnt, dentry);
+ if (PTR_ERR(exp2) == -ENOENT) {
+ dput(dentry);
+ dentry = dget(dparent);
+ } else if (IS_ERR(exp2)) {
host_err = PTR_ERR(exp2);
dput(dentry);
mntput(mnt);
goto out_nfserr;
- }
- if (!exp2) {
- dput(dentry);
- dentry = dget(dparent);
} else {
exp_put(exp);
exp = exp2;
@@ -223,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
}
}
}
+ *dentry_ret = dentry;
+ *exp_ret = exp;
+ return 0;
+
+out_nfserr:
+ exp_put(exp);
+ return nfserrno(host_err);
+}
+
+/*
+ * Look up one component of a pathname.
+ * N.B. After this call _both_ fhp and resfh need an fh_put
+ *
+ * If the lookup would cross a mountpoint, and the mounted filesystem
+ * is exported to the client with NFSEXP_NOHIDE, then the lookup is
+ * accepted as it stands and the mounted directory is
+ * returned. Otherwise the covered directory is returned.
+ * NOTE: this mountpoint crossing is not supported properly by all
+ * clients and is explicitly disallowed for NFSv3
+ * NeilBrown <neilb@cse.unsw.edu.au>
+ */
+__be32
+nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
+ int len, struct svc_fh *resfh)
+{
+ struct svc_export *exp;
+ struct dentry *dentry;
+ __be32 err;
+
+ err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
+ if (err)
+ return err;
+ err = check_nfsd_access(exp, rqstp);
+ if (err)
+ goto out;
/*
* Note: we compose the file handle now, but as the
* dentry may be negative, it may need to be updated.
@@ -230,16 +250,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
err = fh_compose(resfh, exp, dentry, fhp);
if (!err && !dentry->d_inode)
err = nfserr_noent;
- dput(dentry);
out:
+ dput(dentry);
exp_put(exp);
return err;
-
-out_nfserr:
- err = nfserrno(host_err);
- goto out;
}
+
/*
* Set various file attributes.
* N.B. After this call fhp needs an fh_put
@@ -311,7 +328,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
/* The size case is special. It changes the file as well as the attributes. */
if (iap->ia_valid & ATTR_SIZE) {
if (iap->ia_size < inode->i_size) {
- err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
+ err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
if (err)
goto out;
}
@@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
/* Get inode */
error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
if (error)
- goto out;
+ return error;
dentry = fhp->fh_dentry;
inode = dentry->d_inode;
@@ -444,33 +461,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
if (host_error == -EINVAL) {
- error = nfserr_attrnotsupp;
- goto out;
+ return nfserr_attrnotsupp;
} else if (host_error < 0)
goto out_nfserr;
host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
if (host_error < 0)
- goto out_nfserr;
+ goto out_release;
- if (S_ISDIR(inode->i_mode)) {
+ if (S_ISDIR(inode->i_mode))
host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
- if (host_error < 0)
- goto out_nfserr;
- }
- error = nfs_ok;
-
-out:
+out_release:
posix_acl_release(pacl);
posix_acl_release(dpacl);
- return (error);
out_nfserr:
if (host_error == -EOPNOTSUPP)
- error = nfserr_attrnotsupp;
+ return nfserr_attrnotsupp;
else
- error = nfserrno(host_error);
- goto out;
+ return nfserrno(host_error);
}
static struct posix_acl *
@@ -607,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
sresult |= map->access;
- err2 = nfsd_permission(export, dentry, map->how);
+ err2 = nfsd_permission(rqstp, export, dentry, map->how);
switch (err2) {
case nfs_ok:
result |= map->access;
@@ -879,6 +888,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
.u.data = rqstp,
};
+ rqstp->rq_resused = 1;
host_err = splice_direct_to_actor(file, &sd, nfsd_direct_splice_actor);
} else {
oldfs = get_fs();
@@ -1033,7 +1043,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
__be32 err;
if (file) {
- err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+ err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
MAY_READ|MAY_OWNER_OVERRIDE);
if (err)
goto out;
@@ -1062,7 +1072,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
__be32 err = 0;
if (file) {
- err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+ err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
MAY_WRITE|MAY_OWNER_OVERRIDE);
if (err)
goto out;
@@ -1787,11 +1797,17 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
return err;
}
+static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp)
+{
+ return nfsexp_flags(rqstp, exp) & NFSEXP_READONLY;
+}
+
/*
* Check for a user's access permissions to this inode.
*/
__be32
-nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
+nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
+ struct dentry *dentry, int acc)
{
struct inode *inode = dentry->d_inode;
int err;
@@ -1822,7 +1838,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
*/
if (!(acc & MAY_LOCAL_ACCESS))
if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
- if (EX_RDONLY(exp) || IS_RDONLY(inode))
+ if (exp_rdonly(rqstp, exp) || IS_RDONLY(inode))
return nfserr_rofs;
if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
return nfserr_perm;
@@ -1905,7 +1921,7 @@ nfsd_racache_init(int cache_size)
raparm_hash[i].pb_head = NULL;
spin_lock_init(&raparm_hash[i].pb_lock);
}
- nperbucket = cache_size >> RAPARM_HASH_BITS;
+ nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
for (i = 0; i < cache_size - 1; i++) {
if (i % nperbucket == 0)
raparm_hash[j++].pb_head = raparml + i;
diff --git a/fs/nls/Makefile b/fs/nls/Makefile
index a7ade138d684..f499dd7c3905 100644
--- a/fs/nls/Makefile
+++ b/fs/nls/Makefile
@@ -36,11 +36,9 @@ obj-$(CONFIG_NLS_ISO8859_6) += nls_iso8859-6.o
obj-$(CONFIG_NLS_ISO8859_7) += nls_iso8859-7.o
obj-$(CONFIG_NLS_ISO8859_8) += nls_cp1255.o
obj-$(CONFIG_NLS_ISO8859_9) += nls_iso8859-9.o
-obj-$(CONFIG_NLS_ISO8859_10) += nls_iso8859-10.o
obj-$(CONFIG_NLS_ISO8859_13) += nls_iso8859-13.o
obj-$(CONFIG_NLS_ISO8859_14) += nls_iso8859-14.o
obj-$(CONFIG_NLS_ISO8859_15) += nls_iso8859-15.o
obj-$(CONFIG_NLS_KOI8_R) += nls_koi8-r.o
obj-$(CONFIG_NLS_KOI8_U) += nls_koi8-u.o nls_koi8-ru.o
-obj-$(CONFIG_NLS_ABC) += nls_abc.o
obj-$(CONFIG_NLS_UTF8) += nls_utf8.o
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
index bff01a54675a..e93c6142b23c 100644
--- a/fs/ntfs/namei.c
+++ b/fs/ntfs/namei.c
@@ -21,6 +21,7 @@
*/
#include <linux/dcache.h>
+#include <linux/exportfs.h>
#include <linux/security.h>
#include "attrib.h"
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 4566b9182551..90c4e3a29706 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -3143,7 +3143,7 @@ static int __init init_ntfs_fs(void)
ntfs_index_ctx_cache = kmem_cache_create(ntfs_index_ctx_cache_name,
sizeof(ntfs_index_context), 0 /* offset */,
- SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */);
+ SLAB_HWCACHE_ALIGN, NULL /* ctor */);
if (!ntfs_index_ctx_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_index_ctx_cache_name);
@@ -3151,7 +3151,7 @@ static int __init init_ntfs_fs(void)
}
ntfs_attr_ctx_cache = kmem_cache_create(ntfs_attr_ctx_cache_name,
sizeof(ntfs_attr_search_ctx), 0 /* offset */,
- SLAB_HWCACHE_ALIGN, NULL /* ctor */, NULL /* dtor */);
+ SLAB_HWCACHE_ALIGN, NULL /* ctor */);
if (!ntfs_attr_ctx_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_attr_ctx_cache_name);
@@ -3160,7 +3160,7 @@ static int __init init_ntfs_fs(void)
ntfs_name_cache = kmem_cache_create(ntfs_name_cache_name,
(NTFS_MAX_NAME_LEN+1) * sizeof(ntfschar), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!ntfs_name_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_name_cache_name);
@@ -3169,7 +3169,7 @@ static int __init init_ntfs_fs(void)
ntfs_inode_cache = kmem_cache_create(ntfs_inode_cache_name,
sizeof(ntfs_inode), 0,
- SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
if (!ntfs_inode_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_inode_cache_name);
@@ -3179,7 +3179,7 @@ static int __init init_ntfs_fs(void)
ntfs_big_inode_cache = kmem_cache_create(ntfs_big_inode_cache_name,
sizeof(big_ntfs_inode), 0,
SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- ntfs_big_inode_init_once, NULL);
+ ntfs_big_inode_init_once);
if (!ntfs_big_inode_cache) {
printk(KERN_CRIT "NTFS: Failed to create %s!\n",
ntfs_big_inode_cache_name);
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 19712a7d145f..f5e11f4fa952 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -50,6 +50,8 @@
#include "buffer_head_io.h"
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
+static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
+ struct ocfs2_extent_block *eb);
/*
* Structures which describe a path through a btree, and functions to
@@ -117,6 +119,31 @@ static void ocfs2_free_path(struct ocfs2_path *path)
}
/*
+ * All the elements of src into dest. After this call, src could be freed
+ * without affecting dest.
+ *
+ * Both paths should have the same root. Any non-root elements of dest
+ * will be freed.
+ */
+static void ocfs2_cp_path(struct ocfs2_path *dest, struct ocfs2_path *src)
+{
+ int i;
+
+ BUG_ON(path_root_bh(dest) != path_root_bh(src));
+ BUG_ON(path_root_el(dest) != path_root_el(src));
+
+ ocfs2_reinit_path(dest, 1);
+
+ for(i = 1; i < OCFS2_MAX_PATH_DEPTH; i++) {
+ dest->p_node[i].bh = src->p_node[i].bh;
+ dest->p_node[i].el = src->p_node[i].el;
+
+ if (dest->p_node[i].bh)
+ get_bh(dest->p_node[i].bh);
+ }
+}
+
+/*
* Make the *dest path the same as src and re-initialize src path to
* have a root only.
*/
@@ -212,10 +239,41 @@ out:
return ret;
}
+/*
+ * Return the index of the extent record which contains cluster #v_cluster.
+ * -1 is returned if it was not found.
+ *
+ * Should work fine on interior and exterior nodes.
+ */
+int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster)
+{
+ int ret = -1;
+ int i;
+ struct ocfs2_extent_rec *rec;
+ u32 rec_end, rec_start, clusters;
+
+ for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
+ rec = &el->l_recs[i];
+
+ rec_start = le32_to_cpu(rec->e_cpos);
+ clusters = ocfs2_rec_clusters(el, rec);
+
+ rec_end = rec_start + clusters;
+
+ if (v_cluster >= rec_start && v_cluster < rec_end) {
+ ret = i;
+ break;
+ }
+ }
+
+ return ret;
+}
+
enum ocfs2_contig_type {
CONTIG_NONE = 0,
CONTIG_LEFT,
- CONTIG_RIGHT
+ CONTIG_RIGHT,
+ CONTIG_LEFTRIGHT,
};
@@ -253,6 +311,14 @@ static enum ocfs2_contig_type
{
u64 blkno = le64_to_cpu(insert_rec->e_blkno);
+ /*
+ * Refuse to coalesce extent records with different flag
+ * fields - we don't want to mix unwritten extents with user
+ * data.
+ */
+ if (ext->e_flags != insert_rec->e_flags)
+ return CONTIG_NONE;
+
if (ocfs2_extents_adjacent(ext, insert_rec) &&
ocfs2_block_extent_contig(inode->i_sb, ext, blkno))
return CONTIG_RIGHT;
@@ -277,7 +343,14 @@ enum ocfs2_append_type {
APPEND_TAIL,
};
+enum ocfs2_split_type {
+ SPLIT_NONE = 0,
+ SPLIT_LEFT,
+ SPLIT_RIGHT,
+};
+
struct ocfs2_insert_type {
+ enum ocfs2_split_type ins_split;
enum ocfs2_append_type ins_appending;
enum ocfs2_contig_type ins_contig;
int ins_contig_index;
@@ -285,6 +358,13 @@ struct ocfs2_insert_type {
int ins_tree_depth;
};
+struct ocfs2_merge_ctxt {
+ enum ocfs2_contig_type c_contig_type;
+ int c_has_empty_extent;
+ int c_split_covers_rec;
+ int c_used_tail_recs;
+};
+
/*
* How many free extents have we got before we need more meta data?
*/
@@ -384,13 +464,7 @@ static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb,
strcpy(eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE);
eb->h_blkno = cpu_to_le64(first_blkno);
eb->h_fs_generation = cpu_to_le32(osb->fs_generation);
-
-#ifndef OCFS2_USE_ALL_METADATA_SUBALLOCATORS
- /* we always use slot zero's suballocator */
- eb->h_suballoc_slot = 0;
-#else
eb->h_suballoc_slot = cpu_to_le16(osb->slot_num);
-#endif
eb->h_suballoc_bit = cpu_to_le16(suballoc_bit_start);
eb->h_list.l_count =
cpu_to_le16(ocfs2_extent_recs_per_eb(osb->sb));
@@ -461,7 +535,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
struct inode *inode,
struct buffer_head *fe_bh,
struct buffer_head *eb_bh,
- struct buffer_head *last_eb_bh,
+ struct buffer_head **last_eb_bh,
struct ocfs2_alloc_context *meta_ac)
{
int status, new_blocks, i;
@@ -476,7 +550,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
mlog_entry_void();
- BUG_ON(!last_eb_bh);
+ BUG_ON(!last_eb_bh || !*last_eb_bh);
fe = (struct ocfs2_dinode *) fe_bh->b_data;
@@ -507,7 +581,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
goto bail;
}
- eb = (struct ocfs2_extent_block *)last_eb_bh->b_data;
+ eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
new_cpos = ocfs2_sum_rightmost_rec(&eb->h_list);
/* Note: new_eb_bhs[new_blocks - 1] is the guy which will be
@@ -568,7 +642,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
* journal_dirty erroring as it won't unless we've aborted the
* handle (in which case we would never be here) so reserving
* the write with journal_access is all we need to do. */
- status = ocfs2_journal_access(handle, inode, last_eb_bh,
+ status = ocfs2_journal_access(handle, inode, *last_eb_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
@@ -601,10 +675,10 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
* next_leaf on the previously last-extent-block. */
fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk);
- eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
+ eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data;
eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk);
- status = ocfs2_journal_dirty(handle, last_eb_bh);
+ status = ocfs2_journal_dirty(handle, *last_eb_bh);
if (status < 0)
mlog_errno(status);
status = ocfs2_journal_dirty(handle, fe_bh);
@@ -616,6 +690,14 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
mlog_errno(status);
}
+ /*
+ * Some callers want to track the rightmost leaf so pass it
+ * back here.
+ */
+ brelse(*last_eb_bh);
+ get_bh(new_eb_bhs[0]);
+ *last_eb_bh = new_eb_bhs[0];
+
status = 0;
bail:
if (new_eb_bhs) {
@@ -829,6 +911,87 @@ bail:
}
/*
+ * Grow a b-tree so that it has more records.
+ *
+ * We might shift the tree depth in which case existing paths should
+ * be considered invalid.
+ *
+ * Tree depth after the grow is returned via *final_depth.
+ *
+ * *last_eb_bh will be updated by ocfs2_add_branch().
+ */
+static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
+ struct buffer_head *di_bh, int *final_depth,
+ struct buffer_head **last_eb_bh,
+ struct ocfs2_alloc_context *meta_ac)
+{
+ int ret, shift;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ int depth = le16_to_cpu(di->id2.i_list.l_tree_depth);
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct buffer_head *bh = NULL;
+
+ BUG_ON(meta_ac == NULL);
+
+ shift = ocfs2_find_branch_target(osb, inode, di_bh, &bh);
+ if (shift < 0) {
+ ret = shift;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /* We traveled all the way to the bottom of the allocation tree
+ * and didn't find room for any more extents - we need to add
+ * another tree level */
+ if (shift) {
+ BUG_ON(bh);
+ mlog(0, "need to shift tree depth (current = %d)\n", depth);
+
+ /* ocfs2_shift_tree_depth will return us a buffer with
+ * the new extent block (so we can pass that to
+ * ocfs2_add_branch). */
+ ret = ocfs2_shift_tree_depth(osb, handle, inode, di_bh,
+ meta_ac, &bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ depth++;
+ if (depth == 1) {
+ /*
+ * Special case: we have room now if we shifted from
+ * tree_depth 0, so no more work needs to be done.
+ *
+ * We won't be calling add_branch, so pass
+ * back *last_eb_bh as the new leaf. At depth
+ * zero, it should always be null so there's
+ * no reason to brelse.
+ */
+ BUG_ON(*last_eb_bh);
+ get_bh(bh);
+ *last_eb_bh = bh;
+ goto out;
+ }
+ }
+
+ /* call ocfs2_add_branch to add the final part of the tree with
+ * the new data. */
+ mlog(0, "add branch. bh = %p\n", bh);
+ ret = ocfs2_add_branch(osb, handle, inode, di_bh, bh, last_eb_bh,
+ meta_ac);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+out:
+ if (final_depth)
+ *final_depth = depth;
+ brelse(bh);
+ return ret;
+}
+
+/*
* This is only valid for leaf nodes, which are the only ones that can
* have empty extents anyway.
*/
@@ -934,6 +1097,22 @@ static void ocfs2_rotate_leaf(struct ocfs2_extent_list *el,
}
+static void ocfs2_remove_empty_extent(struct ocfs2_extent_list *el)
+{
+ int size, num_recs = le16_to_cpu(el->l_next_free_rec);
+
+ BUG_ON(num_recs == 0);
+
+ if (ocfs2_is_empty_extent(&el->l_recs[0])) {
+ num_recs--;
+ size = num_recs * sizeof(struct ocfs2_extent_rec);
+ memmove(&el->l_recs[0], &el->l_recs[1], size);
+ memset(&el->l_recs[num_recs], 0,
+ sizeof(struct ocfs2_extent_rec));
+ el->l_next_free_rec = cpu_to_le16(num_recs);
+ }
+}
+
/*
* Create an empty extent record .
*
@@ -1211,6 +1390,10 @@ static void ocfs2_adjust_adjacent_records(struct ocfs2_extent_rec *left_rec,
* immediately to their right.
*/
left_clusters = le32_to_cpu(right_child_el->l_recs[0].e_cpos);
+ if (ocfs2_is_empty_extent(&right_child_el->l_recs[0])) {
+ BUG_ON(le16_to_cpu(right_child_el->l_next_free_rec) <= 1);
+ left_clusters = le32_to_cpu(right_child_el->l_recs[1].e_cpos);
+ }
left_clusters -= le32_to_cpu(left_rec->e_cpos);
left_rec->e_int_clusters = cpu_to_le32(left_clusters);
@@ -1531,10 +1714,16 @@ out:
return ret;
}
+/*
+ * Extend the transaction by enough credits to complete the rotation,
+ * and still leave at least the original number of credits allocated
+ * to this transaction.
+ */
static int ocfs2_extend_rotate_transaction(handle_t *handle, int subtree_depth,
+ int op_credits,
struct ocfs2_path *path)
{
- int credits = (path->p_tree_depth - subtree_depth) * 2 + 1;
+ int credits = (path->p_tree_depth - subtree_depth) * 2 + 1 + op_credits;
if (handle->h_buffer_credits < credits)
return ocfs2_extend_trans(handle, credits);
@@ -1568,6 +1757,29 @@ static int ocfs2_rotate_requires_path_adjustment(struct ocfs2_path *left_path,
return 0;
}
+static int ocfs2_leftmost_rec_contains(struct ocfs2_extent_list *el, u32 cpos)
+{
+ int next_free = le16_to_cpu(el->l_next_free_rec);
+ unsigned int range;
+ struct ocfs2_extent_rec *rec;
+
+ if (next_free == 0)
+ return 0;
+
+ rec = &el->l_recs[0];
+ if (ocfs2_is_empty_extent(rec)) {
+ /* Empty list. */
+ if (next_free == 1)
+ return 0;
+ rec = &el->l_recs[1];
+ }
+
+ range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);
+ if (cpos >= le32_to_cpu(rec->e_cpos) && cpos < range)
+ return 1;
+ return 0;
+}
+
/*
* Rotate all the records in a btree right one record, starting at insert_cpos.
*
@@ -1586,11 +1798,12 @@ static int ocfs2_rotate_requires_path_adjustment(struct ocfs2_path *left_path,
*/
static int ocfs2_rotate_tree_right(struct inode *inode,
handle_t *handle,
+ enum ocfs2_split_type split,
u32 insert_cpos,
struct ocfs2_path *right_path,
struct ocfs2_path **ret_left_path)
{
- int ret, start;
+ int ret, start, orig_credits = handle->h_buffer_credits;
u32 cpos;
struct ocfs2_path *left_path = NULL;
@@ -1657,9 +1870,9 @@ static int ocfs2_rotate_tree_right(struct inode *inode,
(unsigned long long)
path_leaf_bh(left_path)->b_blocknr);
- if (ocfs2_rotate_requires_path_adjustment(left_path,
+ if (split == SPLIT_NONE &&
+ ocfs2_rotate_requires_path_adjustment(left_path,
insert_cpos)) {
- mlog(0, "Path adjustment required\n");
/*
* We've rotated the tree as much as we
@@ -1687,7 +1900,7 @@ static int ocfs2_rotate_tree_right(struct inode *inode,
right_path->p_tree_depth);
ret = ocfs2_extend_rotate_transaction(handle, start,
- right_path);
+ orig_credits, right_path);
if (ret) {
mlog_errno(ret);
goto out;
@@ -1700,6 +1913,24 @@ static int ocfs2_rotate_tree_right(struct inode *inode,
goto out;
}
+ if (split != SPLIT_NONE &&
+ ocfs2_leftmost_rec_contains(path_leaf_el(right_path),
+ insert_cpos)) {
+ /*
+ * A rotate moves the rightmost left leaf
+ * record over to the leftmost right leaf
+ * slot. If we're doing an extent split
+ * instead of a real insert, then we have to
+ * check that the extent to be split wasn't
+ * just moved over. If it was, then we can
+ * exit here, passing left_path back -
+ * ocfs2_split_extent() is smart enough to
+ * search both leaves.
+ */
+ *ret_left_path = left_path;
+ goto out_ret_path;
+ }
+
/*
* There is no need to re-read the next right path
* as we know that it'll be our current left
@@ -1722,6 +1953,1031 @@ out_ret_path:
return ret;
}
+static void ocfs2_update_edge_lengths(struct inode *inode, handle_t *handle,
+ struct ocfs2_path *path)
+{
+ int i, idx;
+ struct ocfs2_extent_rec *rec;
+ struct ocfs2_extent_list *el;
+ struct ocfs2_extent_block *eb;
+ u32 range;
+
+ /* Path should always be rightmost. */
+ eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data;
+ BUG_ON(eb->h_next_leaf_blk != 0ULL);
+
+ el = &eb->h_list;
+ BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0);
+ idx = le16_to_cpu(el->l_next_free_rec) - 1;
+ rec = &el->l_recs[idx];
+ range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);
+
+ for (i = 0; i < path->p_tree_depth; i++) {
+ el = path->p_node[i].el;
+ idx = le16_to_cpu(el->l_next_free_rec) - 1;
+ rec = &el->l_recs[idx];
+
+ rec->e_int_clusters = cpu_to_le32(range);
+ le32_add_cpu(&rec->e_int_clusters, -le32_to_cpu(rec->e_cpos));
+
+ ocfs2_journal_dirty(handle, path->p_node[i].bh);
+ }
+}
+
+static void ocfs2_unlink_path(struct inode *inode, handle_t *handle,
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
+ struct ocfs2_path *path, int unlink_start)
+{
+ int ret, i;
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_extent_list *el;
+ struct buffer_head *bh;
+
+ for(i = unlink_start; i < path_num_items(path); i++) {
+ bh = path->p_node[i].bh;
+
+ eb = (struct ocfs2_extent_block *)bh->b_data;
+ /*
+ * Not all nodes might have had their final count
+ * decremented by the caller - handle this here.
+ */
+ el = &eb->h_list;
+ if (le16_to_cpu(el->l_next_free_rec) > 1) {
+ mlog(ML_ERROR,
+ "Inode %llu, attempted to remove extent block "
+ "%llu with %u records\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ (unsigned long long)le64_to_cpu(eb->h_blkno),
+ le16_to_cpu(el->l_next_free_rec));
+
+ ocfs2_journal_dirty(handle, bh);
+ ocfs2_remove_from_cache(inode, bh);
+ continue;
+ }
+
+ el->l_next_free_rec = 0;
+ memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
+
+ ocfs2_journal_dirty(handle, bh);
+
+ ret = ocfs2_cache_extent_block_free(dealloc, eb);
+ if (ret)
+ mlog_errno(ret);
+
+ ocfs2_remove_from_cache(inode, bh);
+ }
+}
+
+static void ocfs2_unlink_subtree(struct inode *inode, handle_t *handle,
+ struct ocfs2_path *left_path,
+ struct ocfs2_path *right_path,
+ int subtree_index,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int i;
+ struct buffer_head *root_bh = left_path->p_node[subtree_index].bh;
+ struct ocfs2_extent_list *root_el = left_path->p_node[subtree_index].el;
+ struct ocfs2_extent_list *el;
+ struct ocfs2_extent_block *eb;
+
+ el = path_leaf_el(left_path);
+
+ eb = (struct ocfs2_extent_block *)right_path->p_node[subtree_index + 1].bh->b_data;
+
+ for(i = 1; i < le16_to_cpu(root_el->l_next_free_rec); i++)
+ if (root_el->l_recs[i].e_blkno == eb->h_blkno)
+ break;
+
+ BUG_ON(i >= le16_to_cpu(root_el->l_next_free_rec));
+
+ memset(&root_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
+ le16_add_cpu(&root_el->l_next_free_rec, -1);
+
+ eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
+ eb->h_next_leaf_blk = 0;
+
+ ocfs2_journal_dirty(handle, root_bh);
+ ocfs2_journal_dirty(handle, path_leaf_bh(left_path));
+
+ ocfs2_unlink_path(inode, handle, dealloc, right_path,
+ subtree_index + 1);
+}
+
+static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
+ struct ocfs2_path *left_path,
+ struct ocfs2_path *right_path,
+ int subtree_index,
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
+ int *deleted)
+{
+ int ret, i, del_right_subtree = 0, right_has_empty = 0;
+ struct buffer_head *root_bh, *di_bh = path_root_bh(right_path);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_extent_list *right_leaf_el, *left_leaf_el;
+ struct ocfs2_extent_block *eb;
+
+ *deleted = 0;
+
+ right_leaf_el = path_leaf_el(right_path);
+ left_leaf_el = path_leaf_el(left_path);
+ root_bh = left_path->p_node[subtree_index].bh;
+ BUG_ON(root_bh != right_path->p_node[subtree_index].bh);
+
+ if (!ocfs2_is_empty_extent(&left_leaf_el->l_recs[0]))
+ return 0;
+
+ eb = (struct ocfs2_extent_block *)path_leaf_bh(right_path)->b_data;
+ if (ocfs2_is_empty_extent(&right_leaf_el->l_recs[0])) {
+ /*
+ * It's legal for us to proceed if the right leaf is
+ * the rightmost one and it has an empty extent. There
+ * are two cases to handle - whether the leaf will be
+ * empty after removal or not. If the leaf isn't empty
+ * then just remove the empty extent up front. The
+ * next block will handle empty leaves by flagging
+ * them for unlink.
+ *
+ * Non rightmost leaves will throw -EAGAIN and the
+ * caller can manually move the subtree and retry.
+ */
+
+ if (eb->h_next_leaf_blk != 0ULL)
+ return -EAGAIN;
+
+ if (le16_to_cpu(right_leaf_el->l_next_free_rec) > 1) {
+ ret = ocfs2_journal_access(handle, inode,
+ path_leaf_bh(right_path),
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ocfs2_remove_empty_extent(right_leaf_el);
+ } else
+ right_has_empty = 1;
+ }
+
+ if (eb->h_next_leaf_blk == 0ULL &&
+ le16_to_cpu(right_leaf_el->l_next_free_rec) == 1) {
+ /*
+ * We have to update i_last_eb_blk during the meta
+ * data delete.
+ */
+ ret = ocfs2_journal_access(handle, inode, di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ del_right_subtree = 1;
+ }
+
+ /*
+ * Getting here with an empty extent in the right path implies
+ * that it's the rightmost path and will be deleted.
+ */
+ BUG_ON(right_has_empty && !del_right_subtree);
+
+ ret = ocfs2_journal_access(handle, inode, root_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ for(i = subtree_index + 1; i < path_num_items(right_path); i++) {
+ ret = ocfs2_journal_access(handle, inode,
+ right_path->p_node[i].bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode,
+ left_path->p_node[i].bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ if (!right_has_empty) {
+ /*
+ * Only do this if we're moving a real
+ * record. Otherwise, the action is delayed until
+ * after removal of the right path in which case we
+ * can do a simple shift to remove the empty extent.
+ */
+ ocfs2_rotate_leaf(left_leaf_el, &right_leaf_el->l_recs[0]);
+ memset(&right_leaf_el->l_recs[0], 0,
+ sizeof(struct ocfs2_extent_rec));
+ }
+ if (eb->h_next_leaf_blk == 0ULL) {
+ /*
+ * Move recs over to get rid of empty extent, decrease
+ * next_free. This is allowed to remove the last
+ * extent in our leaf (setting l_next_free_rec to
+ * zero) - the delete code below won't care.
+ */
+ ocfs2_remove_empty_extent(right_leaf_el);
+ }
+
+ ret = ocfs2_journal_dirty(handle, path_leaf_bh(left_path));
+ if (ret)
+ mlog_errno(ret);
+ ret = ocfs2_journal_dirty(handle, path_leaf_bh(right_path));
+ if (ret)
+ mlog_errno(ret);
+
+ if (del_right_subtree) {
+ ocfs2_unlink_subtree(inode, handle, left_path, right_path,
+ subtree_index, dealloc);
+ ocfs2_update_edge_lengths(inode, handle, left_path);
+
+ eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
+ di->i_last_eb_blk = eb->h_blkno;
+
+ /*
+ * Removal of the extent in the left leaf was skipped
+ * above so we could delete the right path
+ * 1st.
+ */
+ if (right_has_empty)
+ ocfs2_remove_empty_extent(left_leaf_el);
+
+ ret = ocfs2_journal_dirty(handle, di_bh);
+ if (ret)
+ mlog_errno(ret);
+
+ *deleted = 1;
+ } else
+ ocfs2_complete_edge_insert(inode, handle, left_path, right_path,
+ subtree_index);
+
+out:
+ return ret;
+}
+
+/*
+ * Given a full path, determine what cpos value would return us a path
+ * containing the leaf immediately to the right of the current one.
+ *
+ * Will return zero if the path passed in is already the rightmost path.
+ *
+ * This looks similar, but is subtly different to
+ * ocfs2_find_cpos_for_left_leaf().
+ */
+static int ocfs2_find_cpos_for_right_leaf(struct super_block *sb,
+ struct ocfs2_path *path, u32 *cpos)
+{
+ int i, j, ret = 0;
+ u64 blkno;
+ struct ocfs2_extent_list *el;
+
+ *cpos = 0;
+
+ if (path->p_tree_depth == 0)
+ return 0;
+
+ blkno = path_leaf_bh(path)->b_blocknr;
+
+ /* Start at the tree node just above the leaf and work our way up. */
+ i = path->p_tree_depth - 1;
+ while (i >= 0) {
+ int next_free;
+
+ el = path->p_node[i].el;
+
+ /*
+ * Find the extent record just after the one in our
+ * path.
+ */
+ next_free = le16_to_cpu(el->l_next_free_rec);
+ for(j = 0; j < le16_to_cpu(el->l_next_free_rec); j++) {
+ if (le64_to_cpu(el->l_recs[j].e_blkno) == blkno) {
+ if (j == (next_free - 1)) {
+ if (i == 0) {
+ /*
+ * We've determined that the
+ * path specified is already
+ * the rightmost one - return a
+ * cpos of zero.
+ */
+ goto out;
+ }
+ /*
+ * The rightmost record points to our
+ * leaf - we need to travel up the
+ * tree one level.
+ */
+ goto next_node;
+ }
+
+ *cpos = le32_to_cpu(el->l_recs[j + 1].e_cpos);
+ goto out;
+ }
+ }
+
+ /*
+ * If we got here, we never found a valid node where
+ * the tree indicated one should be.
+ */
+ ocfs2_error(sb,
+ "Invalid extent tree at extent block %llu\n",
+ (unsigned long long)blkno);
+ ret = -EROFS;
+ goto out;
+
+next_node:
+ blkno = path->p_node[i].bh->b_blocknr;
+ i--;
+ }
+
+out:
+ return ret;
+}
+
+static int ocfs2_rotate_rightmost_leaf_left(struct inode *inode,
+ handle_t *handle,
+ struct buffer_head *bh,
+ struct ocfs2_extent_list *el)
+{
+ int ret;
+
+ if (!ocfs2_is_empty_extent(&el->l_recs[0]))
+ return 0;
+
+ ret = ocfs2_journal_access(handle, inode, bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ocfs2_remove_empty_extent(el);
+
+ ret = ocfs2_journal_dirty(handle, bh);
+ if (ret)
+ mlog_errno(ret);
+
+out:
+ return ret;
+}
+
+static int __ocfs2_rotate_tree_left(struct inode *inode,
+ handle_t *handle, int orig_credits,
+ struct ocfs2_path *path,
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
+ struct ocfs2_path **empty_extent_path)
+{
+ int ret, subtree_root, deleted;
+ u32 right_cpos;
+ struct ocfs2_path *left_path = NULL;
+ struct ocfs2_path *right_path = NULL;
+
+ BUG_ON(!ocfs2_is_empty_extent(&(path_leaf_el(path)->l_recs[0])));
+
+ *empty_extent_path = NULL;
+
+ ret = ocfs2_find_cpos_for_right_leaf(inode->i_sb, path,
+ &right_cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ left_path = ocfs2_new_path(path_root_bh(path),
+ path_root_el(path));
+ if (!left_path) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ocfs2_cp_path(left_path, path);
+
+ right_path = ocfs2_new_path(path_root_bh(path),
+ path_root_el(path));
+ if (!right_path) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ while (right_cpos) {
+ ret = ocfs2_find_path(inode, right_path, right_cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ subtree_root = ocfs2_find_subtree_root(inode, left_path,
+ right_path);
+
+ mlog(0, "Subtree root at index %d (blk %llu, depth %d)\n",
+ subtree_root,
+ (unsigned long long)
+ right_path->p_node[subtree_root].bh->b_blocknr,
+ right_path->p_tree_depth);
+
+ ret = ocfs2_extend_rotate_transaction(handle, subtree_root,
+ orig_credits, left_path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_rotate_subtree_left(inode, handle, left_path,
+ right_path, subtree_root,
+ dealloc, &deleted);
+ if (ret == -EAGAIN) {
+ /*
+ * The rotation has to temporarily stop due to
+ * the right subtree having an empty
+ * extent. Pass it back to the caller for a
+ * fixup.
+ */
+ *empty_extent_path = right_path;
+ right_path = NULL;
+ goto out;
+ }
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * The subtree rotate might have removed records on
+ * the rightmost edge. If so, then rotation is
+ * complete.
+ */
+ if (deleted)
+ break;
+
+ ocfs2_mv_path(left_path, right_path);
+
+ ret = ocfs2_find_cpos_for_right_leaf(inode->i_sb, left_path,
+ &right_cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+out:
+ ocfs2_free_path(right_path);
+ ocfs2_free_path(left_path);
+
+ return ret;
+}
+
+static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
+ struct ocfs2_path *path,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int ret, subtree_index;
+ u32 cpos;
+ struct ocfs2_path *left_path = NULL;
+ struct ocfs2_dinode *di;
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_extent_list *el;
+
+ /*
+ * XXX: This code assumes that the root is an inode, which is
+ * true for now but may change as tree code gets generic.
+ */
+ di = (struct ocfs2_dinode *)path_root_bh(path)->b_data;
+ if (!OCFS2_IS_VALID_DINODE(di)) {
+ ret = -EIO;
+ ocfs2_error(inode->i_sb,
+ "Inode %llu has invalid path root",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ goto out;
+ }
+
+ /*
+ * There's two ways we handle this depending on
+ * whether path is the only existing one.
+ */
+ ret = ocfs2_extend_rotate_transaction(handle, 0,
+ handle->h_buffer_credits,
+ path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access_path(inode, handle, path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, path, &cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (cpos) {
+ /*
+ * We have a path to the left of this one - it needs
+ * an update too.
+ */
+ left_path = ocfs2_new_path(path_root_bh(path),
+ path_root_el(path));
+ if (!left_path) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_find_path(inode, left_path, cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access_path(inode, handle, left_path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ subtree_index = ocfs2_find_subtree_root(inode, left_path, path);
+
+ ocfs2_unlink_subtree(inode, handle, left_path, path,
+ subtree_index, dealloc);
+ ocfs2_update_edge_lengths(inode, handle, left_path);
+
+ eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
+ di->i_last_eb_blk = eb->h_blkno;
+ } else {
+ /*
+ * 'path' is also the leftmost path which
+ * means it must be the only one. This gets
+ * handled differently because we want to
+ * revert the inode back to having extents
+ * in-line.
+ */
+ ocfs2_unlink_path(inode, handle, dealloc, path, 1);
+
+ el = &di->id2.i_list;
+ el->l_tree_depth = 0;
+ el->l_next_free_rec = 0;
+ memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
+
+ di->i_last_eb_blk = 0;
+ }
+
+ ocfs2_journal_dirty(handle, path_root_bh(path));
+
+out:
+ ocfs2_free_path(left_path);
+ return ret;
+}
+
+/*
+ * Left rotation of btree records.
+ *
+ * In many ways, this is (unsurprisingly) the opposite of right
+ * rotation. We start at some non-rightmost path containing an empty
+ * extent in the leaf block. The code works its way to the rightmost
+ * path by rotating records to the left in every subtree.
+ *
+ * This is used by any code which reduces the number of extent records
+ * in a leaf. After removal, an empty record should be placed in the
+ * leftmost list position.
+ *
+ * This won't handle a length update of the rightmost path records if
+ * the rightmost tree leaf record is removed so the caller is
+ * responsible for detecting and correcting that.
+ */
+static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle,
+ struct ocfs2_path *path,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int ret, orig_credits = handle->h_buffer_credits;
+ struct ocfs2_path *tmp_path = NULL, *restart_path = NULL;
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_extent_list *el;
+
+ el = path_leaf_el(path);
+ if (!ocfs2_is_empty_extent(&el->l_recs[0]))
+ return 0;
+
+ if (path->p_tree_depth == 0) {
+rightmost_no_delete:
+ /*
+ * In-inode extents. This is trivially handled, so do
+ * it up front.
+ */
+ ret = ocfs2_rotate_rightmost_leaf_left(inode, handle,
+ path_leaf_bh(path),
+ path_leaf_el(path));
+ if (ret)
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * Handle rightmost branch now. There's several cases:
+ * 1) simple rotation leaving records in there. That's trivial.
+ * 2) rotation requiring a branch delete - there's no more
+ * records left. Two cases of this:
+ * a) There are branches to the left.
+ * b) This is also the leftmost (the only) branch.
+ *
+ * 1) is handled via ocfs2_rotate_rightmost_leaf_left()
+ * 2a) we need the left branch so that we can update it with the unlink
+ * 2b) we need to bring the inode back to inline extents.
+ */
+
+ eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data;
+ el = &eb->h_list;
+ if (eb->h_next_leaf_blk == 0) {
+ /*
+ * This gets a bit tricky if we're going to delete the
+ * rightmost path. Get the other cases out of the way
+ * 1st.
+ */
+ if (le16_to_cpu(el->l_next_free_rec) > 1)
+ goto rightmost_no_delete;
+
+ if (le16_to_cpu(el->l_next_free_rec) == 0) {
+ ret = -EIO;
+ ocfs2_error(inode->i_sb,
+ "Inode %llu has empty extent block at %llu",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ (unsigned long long)le64_to_cpu(eb->h_blkno));
+ goto out;
+ }
+
+ /*
+ * XXX: The caller can not trust "path" any more after
+ * this as it will have been deleted. What do we do?
+ *
+ * In theory the rotate-for-merge code will never get
+ * here because it'll always ask for a rotate in a
+ * nonempty list.
+ */
+
+ ret = ocfs2_remove_rightmost_path(inode, handle, path,
+ dealloc);
+ if (ret)
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * Now we can loop, remembering the path we get from -EAGAIN
+ * and restarting from there.
+ */
+try_rotate:
+ ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits, path,
+ dealloc, &restart_path);
+ if (ret && ret != -EAGAIN) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ while (ret == -EAGAIN) {
+ tmp_path = restart_path;
+ restart_path = NULL;
+
+ ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits,
+ tmp_path, dealloc,
+ &restart_path);
+ if (ret && ret != -EAGAIN) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ocfs2_free_path(tmp_path);
+ tmp_path = NULL;
+
+ if (ret == 0)
+ goto try_rotate;
+ }
+
+out:
+ ocfs2_free_path(tmp_path);
+ ocfs2_free_path(restart_path);
+ return ret;
+}
+
+static void ocfs2_cleanup_merge(struct ocfs2_extent_list *el,
+ int index)
+{
+ struct ocfs2_extent_rec *rec = &el->l_recs[index];
+ unsigned int size;
+
+ if (rec->e_leaf_clusters == 0) {
+ /*
+ * We consumed all of the merged-from record. An empty
+ * extent cannot exist anywhere but the 1st array
+ * position, so move things over if the merged-from
+ * record doesn't occupy that position.
+ *
+ * This creates a new empty extent so the caller
+ * should be smart enough to have removed any existing
+ * ones.
+ */
+ if (index > 0) {
+ BUG_ON(ocfs2_is_empty_extent(&el->l_recs[0]));
+ size = index * sizeof(struct ocfs2_extent_rec);
+ memmove(&el->l_recs[1], &el->l_recs[0], size);
+ }
+
+ /*
+ * Always memset - the caller doesn't check whether it
+ * created an empty extent, so there could be junk in
+ * the other fields.
+ */
+ memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
+ }
+}
+
+/*
+ * Remove split_rec clusters from the record at index and merge them
+ * onto the beginning of the record at index + 1.
+ */
+static int ocfs2_merge_rec_right(struct inode *inode, struct buffer_head *bh,
+ handle_t *handle,
+ struct ocfs2_extent_rec *split_rec,
+ struct ocfs2_extent_list *el, int index)
+{
+ int ret;
+ unsigned int split_clusters = le16_to_cpu(split_rec->e_leaf_clusters);
+ struct ocfs2_extent_rec *left_rec;
+ struct ocfs2_extent_rec *right_rec;
+
+ BUG_ON(index >= le16_to_cpu(el->l_next_free_rec));
+
+ left_rec = &el->l_recs[index];
+ right_rec = &el->l_recs[index + 1];
+
+ ret = ocfs2_journal_access(handle, inode, bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ le16_add_cpu(&left_rec->e_leaf_clusters, -split_clusters);
+
+ le32_add_cpu(&right_rec->e_cpos, -split_clusters);
+ le64_add_cpu(&right_rec->e_blkno,
+ -ocfs2_clusters_to_blocks(inode->i_sb, split_clusters));
+ le16_add_cpu(&right_rec->e_leaf_clusters, split_clusters);
+
+ ocfs2_cleanup_merge(el, index);
+
+ ret = ocfs2_journal_dirty(handle, bh);
+ if (ret)
+ mlog_errno(ret);
+
+out:
+ return ret;
+}
+
+/*
+ * Remove split_rec clusters from the record at index and merge them
+ * onto the tail of the record at index - 1.
+ */
+static int ocfs2_merge_rec_left(struct inode *inode, struct buffer_head *bh,
+ handle_t *handle,
+ struct ocfs2_extent_rec *split_rec,
+ struct ocfs2_extent_list *el, int index)
+{
+ int ret, has_empty_extent = 0;
+ unsigned int split_clusters = le16_to_cpu(split_rec->e_leaf_clusters);
+ struct ocfs2_extent_rec *left_rec;
+ struct ocfs2_extent_rec *right_rec;
+
+ BUG_ON(index <= 0);
+
+ left_rec = &el->l_recs[index - 1];
+ right_rec = &el->l_recs[index];
+ if (ocfs2_is_empty_extent(&el->l_recs[0]))
+ has_empty_extent = 1;
+
+ ret = ocfs2_journal_access(handle, inode, bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (has_empty_extent && index == 1) {
+ /*
+ * The easy case - we can just plop the record right in.
+ */
+ *left_rec = *split_rec;
+
+ has_empty_extent = 0;
+ } else {
+ le16_add_cpu(&left_rec->e_leaf_clusters, split_clusters);
+ }
+
+ le32_add_cpu(&right_rec->e_cpos, split_clusters);
+ le64_add_cpu(&right_rec->e_blkno,
+ ocfs2_clusters_to_blocks(inode->i_sb, split_clusters));
+ le16_add_cpu(&right_rec->e_leaf_clusters, -split_clusters);
+
+ ocfs2_cleanup_merge(el, index);
+
+ ret = ocfs2_journal_dirty(handle, bh);
+ if (ret)
+ mlog_errno(ret);
+
+out:
+ return ret;
+}
+
+static int ocfs2_try_to_merge_extent(struct inode *inode,
+ handle_t *handle,
+ struct ocfs2_path *left_path,
+ int split_index,
+ struct ocfs2_extent_rec *split_rec,
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
+ struct ocfs2_merge_ctxt *ctxt)
+
+{
+ int ret = 0, delete_tail_recs = 0;
+ struct ocfs2_extent_list *el = path_leaf_el(left_path);
+ struct ocfs2_extent_rec *rec = &el->l_recs[split_index];
+
+ BUG_ON(ctxt->c_contig_type == CONTIG_NONE);
+
+ if (ctxt->c_split_covers_rec) {
+ delete_tail_recs++;
+
+ if (ctxt->c_contig_type == CONTIG_LEFTRIGHT ||
+ ctxt->c_has_empty_extent)
+ delete_tail_recs++;
+
+ if (ctxt->c_has_empty_extent) {
+ /*
+ * The merge code will need to create an empty
+ * extent to take the place of the newly
+ * emptied slot. Remove any pre-existing empty
+ * extents - having more than one in a leaf is
+ * illegal.
+ */
+ ret = ocfs2_rotate_tree_left(inode, handle, left_path,
+ dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ split_index--;
+ rec = &el->l_recs[split_index];
+ }
+ }
+
+ if (ctxt->c_contig_type == CONTIG_LEFTRIGHT) {
+ /*
+ * Left-right contig implies this.
+ */
+ BUG_ON(!ctxt->c_split_covers_rec);
+ BUG_ON(split_index == 0);
+
+ /*
+ * Since the leftright insert always covers the entire
+ * extent, this call will delete the insert record
+ * entirely, resulting in an empty extent record added to
+ * the extent block.
+ *
+ * Since the adding of an empty extent shifts
+ * everything back to the right, there's no need to
+ * update split_index here.
+ */
+ ret = ocfs2_merge_rec_left(inode, path_leaf_bh(left_path),
+ handle, split_rec, el, split_index);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * We can only get this from logic error above.
+ */
+ BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
+
+ /*
+ * The left merge left us with an empty extent, remove
+ * it.
+ */
+ ret = ocfs2_rotate_tree_left(inode, handle, left_path, dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ split_index--;
+ rec = &el->l_recs[split_index];
+
+ /*
+ * Note that we don't pass split_rec here on purpose -
+ * we've merged it into the left side.
+ */
+ ret = ocfs2_merge_rec_right(inode, path_leaf_bh(left_path),
+ handle, rec, el, split_index);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
+
+ ret = ocfs2_rotate_tree_left(inode, handle, left_path,
+ dealloc);
+ /*
+ * Error from this last rotate is not critical, so
+ * print but don't bubble it up.
+ */
+ if (ret)
+ mlog_errno(ret);
+ ret = 0;
+ } else {
+ /*
+ * Merge a record to the left or right.
+ *
+ * 'contig_type' is relative to the existing record,
+ * so for example, if we're "right contig", it's to
+ * the record on the left (hence the left merge).
+ */
+ if (ctxt->c_contig_type == CONTIG_RIGHT) {
+ ret = ocfs2_merge_rec_left(inode,
+ path_leaf_bh(left_path),
+ handle, split_rec, el,
+ split_index);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ } else {
+ ret = ocfs2_merge_rec_right(inode,
+ path_leaf_bh(left_path),
+ handle, split_rec, el,
+ split_index);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ if (ctxt->c_split_covers_rec) {
+ /*
+ * The merge may have left an empty extent in
+ * our leaf. Try to rotate it away.
+ */
+ ret = ocfs2_rotate_tree_left(inode, handle, left_path,
+ dealloc);
+ if (ret)
+ mlog_errno(ret);
+ ret = 0;
+ }
+ }
+
+out:
+ return ret;
+}
+
+static void ocfs2_subtract_from_rec(struct super_block *sb,
+ enum ocfs2_split_type split,
+ struct ocfs2_extent_rec *rec,
+ struct ocfs2_extent_rec *split_rec)
+{
+ u64 len_blocks;
+
+ len_blocks = ocfs2_clusters_to_blocks(sb,
+ le16_to_cpu(split_rec->e_leaf_clusters));
+
+ if (split == SPLIT_LEFT) {
+ /*
+ * Region is on the left edge of the existing
+ * record.
+ */
+ le32_add_cpu(&rec->e_cpos,
+ le16_to_cpu(split_rec->e_leaf_clusters));
+ le64_add_cpu(&rec->e_blkno, len_blocks);
+ le16_add_cpu(&rec->e_leaf_clusters,
+ -le16_to_cpu(split_rec->e_leaf_clusters));
+ } else {
+ /*
+ * Region is on the right edge of the existing
+ * record.
+ */
+ le16_add_cpu(&rec->e_leaf_clusters,
+ -le16_to_cpu(split_rec->e_leaf_clusters));
+ }
+}
+
/*
* Do the final bits of extent record insertion at the target leaf
* list. If this leaf is part of an allocation tree, it is assumed
@@ -1738,6 +2994,15 @@ static void ocfs2_insert_at_leaf(struct ocfs2_extent_rec *insert_rec,
BUG_ON(le16_to_cpu(el->l_tree_depth) != 0);
+ if (insert->ins_split != SPLIT_NONE) {
+ i = ocfs2_search_extent_list(el, le32_to_cpu(insert_rec->e_cpos));
+ BUG_ON(i == -1);
+ rec = &el->l_recs[i];
+ ocfs2_subtract_from_rec(inode->i_sb, insert->ins_split, rec,
+ insert_rec);
+ goto rotate;
+ }
+
/*
* Contiguous insert - either left or right.
*/
@@ -1792,6 +3057,7 @@ static void ocfs2_insert_at_leaf(struct ocfs2_extent_rec *insert_rec,
return;
}
+rotate:
/*
* Ok, we have to rotate.
*
@@ -1815,13 +3081,53 @@ static inline void ocfs2_update_dinode_clusters(struct inode *inode,
spin_unlock(&OCFS2_I(inode)->ip_lock);
}
+static void ocfs2_adjust_rightmost_records(struct inode *inode,
+ handle_t *handle,
+ struct ocfs2_path *path,
+ struct ocfs2_extent_rec *insert_rec)
+{
+ int ret, i, next_free;
+ struct buffer_head *bh;
+ struct ocfs2_extent_list *el;
+ struct ocfs2_extent_rec *rec;
+
+ /*
+ * Update everything except the leaf block.
+ */
+ for (i = 0; i < path->p_tree_depth; i++) {
+ bh = path->p_node[i].bh;
+ el = path->p_node[i].el;
+
+ next_free = le16_to_cpu(el->l_next_free_rec);
+ if (next_free == 0) {
+ ocfs2_error(inode->i_sb,
+ "Dinode %llu has a bad extent list",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ ret = -EIO;
+ return;
+ }
+
+ rec = &el->l_recs[next_free - 1];
+
+ rec->e_int_clusters = insert_rec->e_cpos;
+ le32_add_cpu(&rec->e_int_clusters,
+ le16_to_cpu(insert_rec->e_leaf_clusters));
+ le32_add_cpu(&rec->e_int_clusters,
+ -le32_to_cpu(rec->e_cpos));
+
+ ret = ocfs2_journal_dirty(handle, bh);
+ if (ret)
+ mlog_errno(ret);
+
+ }
+}
+
static int ocfs2_append_rec_to_path(struct inode *inode, handle_t *handle,
struct ocfs2_extent_rec *insert_rec,
struct ocfs2_path *right_path,
struct ocfs2_path **ret_left_path)
{
- int ret, i, next_free;
- struct buffer_head *bh;
+ int ret, next_free;
struct ocfs2_extent_list *el;
struct ocfs2_path *left_path = NULL;
@@ -1887,40 +3193,7 @@ static int ocfs2_append_rec_to_path(struct inode *inode, handle_t *handle,
goto out;
}
- el = path_root_el(right_path);
- bh = path_root_bh(right_path);
- i = 0;
- while (1) {
- struct ocfs2_extent_rec *rec;
-
- next_free = le16_to_cpu(el->l_next_free_rec);
- if (next_free == 0) {
- ocfs2_error(inode->i_sb,
- "Dinode %llu has a bad extent list",
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
- ret = -EIO;
- goto out;
- }
-
- rec = &el->l_recs[next_free - 1];
-
- rec->e_int_clusters = insert_rec->e_cpos;
- le32_add_cpu(&rec->e_int_clusters,
- le16_to_cpu(insert_rec->e_leaf_clusters));
- le32_add_cpu(&rec->e_int_clusters,
- -le32_to_cpu(rec->e_cpos));
-
- ret = ocfs2_journal_dirty(handle, bh);
- if (ret)
- mlog_errno(ret);
-
- /* Don't touch the leaf node */
- if (++i >= right_path->p_tree_depth)
- break;
-
- bh = right_path->p_node[i].bh;
- el = right_path->p_node[i].el;
- }
+ ocfs2_adjust_rightmost_records(inode, handle, right_path, insert_rec);
*ret_left_path = left_path;
ret = 0;
@@ -1931,6 +3204,83 @@ out:
return ret;
}
+static void ocfs2_split_record(struct inode *inode,
+ struct ocfs2_path *left_path,
+ struct ocfs2_path *right_path,
+ struct ocfs2_extent_rec *split_rec,
+ enum ocfs2_split_type split)
+{
+ int index;
+ u32 cpos = le32_to_cpu(split_rec->e_cpos);
+ struct ocfs2_extent_list *left_el = NULL, *right_el, *insert_el, *el;
+ struct ocfs2_extent_rec *rec, *tmprec;
+
+ right_el = path_leaf_el(right_path);;
+ if (left_path)
+ left_el = path_leaf_el(left_path);
+
+ el = right_el;
+ insert_el = right_el;
+ index = ocfs2_search_extent_list(el, cpos);
+ if (index != -1) {
+ if (index == 0 && left_path) {
+ BUG_ON(ocfs2_is_empty_extent(&el->l_recs[0]));
+
+ /*
+ * This typically means that the record
+ * started in the left path but moved to the
+ * right as a result of rotation. We either
+ * move the existing record to the left, or we
+ * do the later insert there.
+ *
+ * In this case, the left path should always
+ * exist as the rotate code will have passed
+ * it back for a post-insert update.
+ */
+
+ if (split == SPLIT_LEFT) {
+ /*
+ * It's a left split. Since we know
+ * that the rotate code gave us an
+ * empty extent in the left path, we
+ * can just do the insert there.
+ */
+ insert_el = left_el;
+ } else {
+ /*
+ * Right split - we have to move the
+ * existing record over to the left
+ * leaf. The insert will be into the
+ * newly created empty extent in the
+ * right leaf.
+ */
+ tmprec = &right_el->l_recs[index];
+ ocfs2_rotate_leaf(left_el, tmprec);
+ el = left_el;
+
+ memset(tmprec, 0, sizeof(*tmprec));
+ index = ocfs2_search_extent_list(left_el, cpos);
+ BUG_ON(index == -1);
+ }
+ }
+ } else {
+ BUG_ON(!left_path);
+ BUG_ON(!ocfs2_is_empty_extent(&left_el->l_recs[0]));
+ /*
+ * Left path is easy - we can just allow the insert to
+ * happen.
+ */
+ el = left_el;
+ insert_el = left_el;
+ index = ocfs2_search_extent_list(el, cpos);
+ BUG_ON(index == -1);
+ }
+
+ rec = &el->l_recs[index];
+ ocfs2_subtract_from_rec(inode->i_sb, split, rec, split_rec);
+ ocfs2_rotate_leaf(insert_el, split_rec);
+}
+
/*
* This function only does inserts on an allocation b-tree. For dinode
* lists, ocfs2_insert_at_leaf() is called directly.
@@ -1948,7 +3298,6 @@ static int ocfs2_insert_path(struct inode *inode,
{
int ret, subtree_index;
struct buffer_head *leaf_bh = path_leaf_bh(right_path);
- struct ocfs2_extent_list *el;
/*
* Pass both paths to the journal. The majority of inserts
@@ -1984,9 +3333,18 @@ static int ocfs2_insert_path(struct inode *inode,
}
}
- el = path_leaf_el(right_path);
+ if (insert->ins_split != SPLIT_NONE) {
+ /*
+ * We could call ocfs2_insert_at_leaf() for some types
+ * of splits, but it's easier to just let one seperate
+ * function sort it all out.
+ */
+ ocfs2_split_record(inode, left_path, right_path,
+ insert_rec, insert->ins_split);
+ } else
+ ocfs2_insert_at_leaf(insert_rec, path_leaf_el(right_path),
+ insert, inode);
- ocfs2_insert_at_leaf(insert_rec, el, insert, inode);
ret = ocfs2_journal_dirty(handle, leaf_bh);
if (ret)
mlog_errno(ret);
@@ -2075,7 +3433,7 @@ static int ocfs2_do_insert_extent(struct inode *inode,
* can wind up skipping both of these two special cases...
*/
if (rotate) {
- ret = ocfs2_rotate_tree_right(inode, handle,
+ ret = ocfs2_rotate_tree_right(inode, handle, type->ins_split,
le32_to_cpu(insert_rec->e_cpos),
right_path, &left_path);
if (ret) {
@@ -2100,8 +3458,9 @@ static int ocfs2_do_insert_extent(struct inode *inode,
}
out_update_clusters:
- ocfs2_update_dinode_clusters(inode, di,
- le16_to_cpu(insert_rec->e_leaf_clusters));
+ if (type->ins_split == SPLIT_NONE)
+ ocfs2_update_dinode_clusters(inode, di,
+ le16_to_cpu(insert_rec->e_leaf_clusters));
ret = ocfs2_journal_dirty(handle, di_bh);
if (ret)
@@ -2114,6 +3473,44 @@ out:
return ret;
}
+static enum ocfs2_contig_type
+ocfs2_figure_merge_contig_type(struct inode *inode,
+ struct ocfs2_extent_list *el, int index,
+ struct ocfs2_extent_rec *split_rec)
+{
+ struct ocfs2_extent_rec *rec;
+ enum ocfs2_contig_type ret = CONTIG_NONE;
+
+ /*
+ * We're careful to check for an empty extent record here -
+ * the merge code will know what to do if it sees one.
+ */
+
+ if (index > 0) {
+ rec = &el->l_recs[index - 1];
+ if (index == 1 && ocfs2_is_empty_extent(rec)) {
+ if (split_rec->e_cpos == el->l_recs[index].e_cpos)
+ ret = CONTIG_RIGHT;
+ } else {
+ ret = ocfs2_extent_contig(inode, rec, split_rec);
+ }
+ }
+
+ if (index < (le16_to_cpu(el->l_next_free_rec) - 1)) {
+ enum ocfs2_contig_type contig_type;
+
+ rec = &el->l_recs[index + 1];
+ contig_type = ocfs2_extent_contig(inode, rec, split_rec);
+
+ if (contig_type == CONTIG_LEFT && ret == CONTIG_RIGHT)
+ ret = CONTIG_LEFTRIGHT;
+ else if (ret == CONTIG_NONE)
+ ret = contig_type;
+ }
+
+ return ret;
+}
+
static void ocfs2_figure_contig_type(struct inode *inode,
struct ocfs2_insert_type *insert,
struct ocfs2_extent_list *el,
@@ -2205,6 +3602,8 @@ static int ocfs2_figure_insert_type(struct inode *inode,
struct ocfs2_path *path = NULL;
struct buffer_head *bh = NULL;
+ insert->ins_split = SPLIT_NONE;
+
el = &di->id2.i_list;
insert->ins_tree_depth = le16_to_cpu(el->l_tree_depth);
@@ -2327,9 +3726,10 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
u32 cpos,
u64 start_blk,
u32 new_clusters,
+ u8 flags,
struct ocfs2_alloc_context *meta_ac)
{
- int status, shift;
+ int status;
struct buffer_head *last_eb_bh = NULL;
struct buffer_head *bh = NULL;
struct ocfs2_insert_type insert = {0, };
@@ -2350,6 +3750,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
rec.e_cpos = cpu_to_le32(cpos);
rec.e_blkno = cpu_to_le64(start_blk);
rec.e_leaf_clusters = cpu_to_le16(new_clusters);
+ rec.e_flags = flags;
status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
&insert);
@@ -2364,55 +3765,16 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
insert.ins_appending, insert.ins_contig, insert.ins_contig_index,
insert.ins_free_records, insert.ins_tree_depth);
- /*
- * Avoid growing the tree unless we're out of records and the
- * insert type requres one.
- */
- if (insert.ins_contig != CONTIG_NONE || insert.ins_free_records)
- goto out_add;
-
- shift = ocfs2_find_branch_target(osb, inode, fe_bh, &bh);
- if (shift < 0) {
- status = shift;
- mlog_errno(status);
- goto bail;
- }
-
- /* We traveled all the way to the bottom of the allocation tree
- * and didn't find room for any more extents - we need to add
- * another tree level */
- if (shift) {
- BUG_ON(bh);
- mlog(0, "need to shift tree depth "
- "(current = %d)\n", insert.ins_tree_depth);
-
- /* ocfs2_shift_tree_depth will return us a buffer with
- * the new extent block (so we can pass that to
- * ocfs2_add_branch). */
- status = ocfs2_shift_tree_depth(osb, handle, inode, fe_bh,
- meta_ac, &bh);
- if (status < 0) {
+ if (insert.ins_contig == CONTIG_NONE && insert.ins_free_records == 0) {
+ status = ocfs2_grow_tree(inode, handle, fe_bh,
+ &insert.ins_tree_depth, &last_eb_bh,
+ meta_ac);
+ if (status) {
mlog_errno(status);
goto bail;
}
- insert.ins_tree_depth++;
- /* Special case: we have room now if we shifted from
- * tree_depth 0 */
- if (insert.ins_tree_depth == 1)
- goto out_add;
- }
-
- /* call ocfs2_add_branch to add the final part of the tree with
- * the new data. */
- mlog(0, "add branch. bh = %p\n", bh);
- status = ocfs2_add_branch(osb, handle, inode, fe_bh, bh, last_eb_bh,
- meta_ac);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
}
-out_add:
/* Finally, we can add clusters. This might rotate the tree for us. */
status = ocfs2_do_insert_extent(inode, handle, fe_bh, &rec, &insert);
if (status < 0)
@@ -2431,7 +3793,720 @@ bail:
return status;
}
-static inline int ocfs2_truncate_log_needs_flush(struct ocfs2_super *osb)
+static void ocfs2_make_right_split_rec(struct super_block *sb,
+ struct ocfs2_extent_rec *split_rec,
+ u32 cpos,
+ struct ocfs2_extent_rec *rec)
+{
+ u32 rec_cpos = le32_to_cpu(rec->e_cpos);
+ u32 rec_range = rec_cpos + le16_to_cpu(rec->e_leaf_clusters);
+
+ memset(split_rec, 0, sizeof(struct ocfs2_extent_rec));
+
+ split_rec->e_cpos = cpu_to_le32(cpos);
+ split_rec->e_leaf_clusters = cpu_to_le16(rec_range - cpos);
+
+ split_rec->e_blkno = rec->e_blkno;
+ le64_add_cpu(&split_rec->e_blkno,
+ ocfs2_clusters_to_blocks(sb, cpos - rec_cpos));
+
+ split_rec->e_flags = rec->e_flags;
+}
+
+static int ocfs2_split_and_insert(struct inode *inode,
+ handle_t *handle,
+ struct ocfs2_path *path,
+ struct buffer_head *di_bh,
+ struct buffer_head **last_eb_bh,
+ int split_index,
+ struct ocfs2_extent_rec *orig_split_rec,
+ struct ocfs2_alloc_context *meta_ac)
+{
+ int ret = 0, depth;
+ unsigned int insert_range, rec_range, do_leftright = 0;
+ struct ocfs2_extent_rec tmprec;
+ struct ocfs2_extent_list *rightmost_el;
+ struct ocfs2_extent_rec rec;
+ struct ocfs2_extent_rec split_rec = *orig_split_rec;
+ struct ocfs2_insert_type insert;
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_dinode *di;
+
+leftright:
+ /*
+ * Store a copy of the record on the stack - it might move
+ * around as the tree is manipulated below.
+ */
+ rec = path_leaf_el(path)->l_recs[split_index];
+
+ di = (struct ocfs2_dinode *)di_bh->b_data;
+ rightmost_el = &di->id2.i_list;
+
+ depth = le16_to_cpu(rightmost_el->l_tree_depth);
+ if (depth) {
+ BUG_ON(!(*last_eb_bh));
+ eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data;
+ rightmost_el = &eb->h_list;
+ }
+
+ if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
+ le16_to_cpu(rightmost_el->l_count)) {
+ int old_depth = depth;
+
+ ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh,
+ meta_ac);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (old_depth != depth) {
+ eb = (struct ocfs2_extent_block *)(*last_eb_bh)->b_data;
+ rightmost_el = &eb->h_list;
+ }
+ }
+
+ memset(&insert, 0, sizeof(struct ocfs2_insert_type));
+ insert.ins_appending = APPEND_NONE;
+ insert.ins_contig = CONTIG_NONE;
+ insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
+ - le16_to_cpu(rightmost_el->l_next_free_rec);
+ insert.ins_tree_depth = depth;
+
+ insert_range = le32_to_cpu(split_rec.e_cpos) +
+ le16_to_cpu(split_rec.e_leaf_clusters);
+ rec_range = le32_to_cpu(rec.e_cpos) +
+ le16_to_cpu(rec.e_leaf_clusters);
+
+ if (split_rec.e_cpos == rec.e_cpos) {
+ insert.ins_split = SPLIT_LEFT;
+ } else if (insert_range == rec_range) {
+ insert.ins_split = SPLIT_RIGHT;
+ } else {
+ /*
+ * Left/right split. We fake this as a right split
+ * first and then make a second pass as a left split.
+ */
+ insert.ins_split = SPLIT_RIGHT;
+
+ ocfs2_make_right_split_rec(inode->i_sb, &tmprec, insert_range,
+ &rec);
+
+ split_rec = tmprec;
+
+ BUG_ON(do_leftright);
+ do_leftright = 1;
+ }
+
+ ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec,
+ &insert);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (do_leftright == 1) {
+ u32 cpos;
+ struct ocfs2_extent_list *el;
+
+ do_leftright++;
+ split_rec = *orig_split_rec;
+
+ ocfs2_reinit_path(path, 1);
+
+ cpos = le32_to_cpu(split_rec.e_cpos);
+ ret = ocfs2_find_path(inode, path, cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ el = path_leaf_el(path);
+ split_index = ocfs2_search_extent_list(el, cpos);
+ goto leftright;
+ }
+out:
+
+ return ret;
+}
+
+/*
+ * Mark part or all of the extent record at split_index in the leaf
+ * pointed to by path as written. This removes the unwritten
+ * extent flag.
+ *
+ * Care is taken to handle contiguousness so as to not grow the tree.
+ *
+ * meta_ac is not strictly necessary - we only truly need it if growth
+ * of the tree is required. All other cases will degrade into a less
+ * optimal tree layout.
+ *
+ * last_eb_bh should be the rightmost leaf block for any inode with a
+ * btree. Since a split may grow the tree or a merge might shrink it, the caller cannot trust the contents of that buffer after this call.
+ *
+ * This code is optimized for readability - several passes might be
+ * made over certain portions of the tree. All of those blocks will
+ * have been brought into cache (and pinned via the journal), so the
+ * extra overhead is not expressed in terms of disk reads.
+ */
+static int __ocfs2_mark_extent_written(struct inode *inode,
+ struct buffer_head *di_bh,
+ handle_t *handle,
+ struct ocfs2_path *path,
+ int split_index,
+ struct ocfs2_extent_rec *split_rec,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int ret = 0;
+ struct ocfs2_extent_list *el = path_leaf_el(path);
+ struct buffer_head *eb_bh, *last_eb_bh = NULL;
+ struct ocfs2_extent_rec *rec = &el->l_recs[split_index];
+ struct ocfs2_merge_ctxt ctxt;
+ struct ocfs2_extent_list *rightmost_el;
+
+ if (!rec->e_flags & OCFS2_EXT_UNWRITTEN) {
+ ret = -EIO;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (le32_to_cpu(rec->e_cpos) > le32_to_cpu(split_rec->e_cpos) ||
+ ((le32_to_cpu(rec->e_cpos) + le16_to_cpu(rec->e_leaf_clusters)) <
+ (le32_to_cpu(split_rec->e_cpos) + le16_to_cpu(split_rec->e_leaf_clusters)))) {
+ ret = -EIO;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ eb_bh = path_leaf_bh(path);
+ ret = ocfs2_journal_access(handle, inode, eb_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ctxt.c_contig_type = ocfs2_figure_merge_contig_type(inode, el,
+ split_index,
+ split_rec);
+
+ /*
+ * The core merge / split code wants to know how much room is
+ * left in this inodes allocation tree, so we pass the
+ * rightmost extent list.
+ */
+ if (path->p_tree_depth) {
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+ le64_to_cpu(di->i_last_eb_blk),
+ &last_eb_bh, OCFS2_BH_CACHED, inode);
+ if (ret) {
+ mlog_exit(ret);
+ goto out;
+ }
+
+ eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
+ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
+ OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
+ ret = -EROFS;
+ goto out;
+ }
+
+ rightmost_el = &eb->h_list;
+ } else
+ rightmost_el = path_root_el(path);
+
+ ctxt.c_used_tail_recs = le16_to_cpu(rightmost_el->l_next_free_rec);
+ if (ctxt.c_used_tail_recs > 0 &&
+ ocfs2_is_empty_extent(&rightmost_el->l_recs[0]))
+ ctxt.c_used_tail_recs--;
+
+ if (rec->e_cpos == split_rec->e_cpos &&
+ rec->e_leaf_clusters == split_rec->e_leaf_clusters)
+ ctxt.c_split_covers_rec = 1;
+ else
+ ctxt.c_split_covers_rec = 0;
+
+ ctxt.c_has_empty_extent = ocfs2_is_empty_extent(&el->l_recs[0]);
+
+ mlog(0, "index: %d, contig: %u, used_tail_recs: %u, "
+ "has_empty: %u, split_covers: %u\n", split_index,
+ ctxt.c_contig_type, ctxt.c_used_tail_recs,
+ ctxt.c_has_empty_extent, ctxt.c_split_covers_rec);
+
+ if (ctxt.c_contig_type == CONTIG_NONE) {
+ if (ctxt.c_split_covers_rec)
+ el->l_recs[split_index] = *split_rec;
+ else
+ ret = ocfs2_split_and_insert(inode, handle, path, di_bh,
+ &last_eb_bh, split_index,
+ split_rec, meta_ac);
+ if (ret)
+ mlog_errno(ret);
+ } else {
+ ret = ocfs2_try_to_merge_extent(inode, handle, path,
+ split_index, split_rec,
+ dealloc, &ctxt);
+ if (ret)
+ mlog_errno(ret);
+ }
+
+ ocfs2_journal_dirty(handle, eb_bh);
+
+out:
+ brelse(last_eb_bh);
+ return ret;
+}
+
+/*
+ * Mark the already-existing extent at cpos as written for len clusters.
+ *
+ * If the existing extent is larger than the request, initiate a
+ * split. An attempt will be made at merging with adjacent extents.
+ *
+ * The caller is responsible for passing down meta_ac if we'll need it.
+ */
+int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+ handle_t *handle, u32 cpos, u32 len, u32 phys,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int ret, index;
+ u64 start_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys);
+ struct ocfs2_extent_rec split_rec;
+ struct ocfs2_path *left_path = NULL;
+ struct ocfs2_extent_list *el;
+
+ mlog(0, "Inode %lu cpos %u, len %u, phys %u (%llu)\n",
+ inode->i_ino, cpos, len, phys, (unsigned long long)start_blkno);
+
+ if (!ocfs2_writes_unwritten_extents(OCFS2_SB(inode->i_sb))) {
+ ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents "
+ "that are being written to, but the feature bit "
+ "is not set in the super block.",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ ret = -EROFS;
+ goto out;
+ }
+
+ /*
+ * XXX: This should be fixed up so that we just re-insert the
+ * next extent records.
+ */
+ ocfs2_extent_map_trunc(inode, 0);
+
+ left_path = ocfs2_new_inode_path(di_bh);
+ if (!left_path) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_find_path(inode, left_path, cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ el = path_leaf_el(left_path);
+
+ index = ocfs2_search_extent_list(el, cpos);
+ if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) {
+ ocfs2_error(inode->i_sb,
+ "Inode %llu has an extent at cpos %u which can no "
+ "longer be found.\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos);
+ ret = -EROFS;
+ goto out;
+ }
+
+ memset(&split_rec, 0, sizeof(struct ocfs2_extent_rec));
+ split_rec.e_cpos = cpu_to_le32(cpos);
+ split_rec.e_leaf_clusters = cpu_to_le16(len);
+ split_rec.e_blkno = cpu_to_le64(start_blkno);
+ split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags;
+ split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN;
+
+ ret = __ocfs2_mark_extent_written(inode, di_bh, handle, left_path,
+ index, &split_rec, meta_ac, dealloc);
+ if (ret)
+ mlog_errno(ret);
+
+out:
+ ocfs2_free_path(left_path);
+ return ret;
+}
+
+static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
+ handle_t *handle, struct ocfs2_path *path,
+ int index, u32 new_range,
+ struct ocfs2_alloc_context *meta_ac)
+{
+ int ret, depth, credits = handle->h_buffer_credits;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct buffer_head *last_eb_bh = NULL;
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_extent_list *rightmost_el, *el;
+ struct ocfs2_extent_rec split_rec;
+ struct ocfs2_extent_rec *rec;
+ struct ocfs2_insert_type insert;
+
+ /*
+ * Setup the record to split before we grow the tree.
+ */
+ el = path_leaf_el(path);
+ rec = &el->l_recs[index];
+ ocfs2_make_right_split_rec(inode->i_sb, &split_rec, new_range, rec);
+
+ depth = path->p_tree_depth;
+ if (depth > 0) {
+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+ le64_to_cpu(di->i_last_eb_blk),
+ &last_eb_bh, OCFS2_BH_CACHED, inode);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
+ rightmost_el = &eb->h_list;
+ } else
+ rightmost_el = path_leaf_el(path);
+
+ credits += path->p_tree_depth + ocfs2_extend_meta_needed(di);
+ ret = ocfs2_extend_trans(handle, credits);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
+ le16_to_cpu(rightmost_el->l_count)) {
+ int old_depth = depth;
+
+ ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh,
+ meta_ac);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (old_depth != depth) {
+ eb = (struct ocfs2_extent_block *)last_eb_bh->b_data;
+ rightmost_el = &eb->h_list;
+ }
+ }
+
+ memset(&insert, 0, sizeof(struct ocfs2_insert_type));
+ insert.ins_appending = APPEND_NONE;
+ insert.ins_contig = CONTIG_NONE;
+ insert.ins_split = SPLIT_RIGHT;
+ insert.ins_free_records = le16_to_cpu(rightmost_el->l_count)
+ - le16_to_cpu(rightmost_el->l_next_free_rec);
+ insert.ins_tree_depth = depth;
+
+ ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert);
+ if (ret)
+ mlog_errno(ret);
+
+out:
+ brelse(last_eb_bh);
+ return ret;
+}
+
+static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
+ struct ocfs2_path *path, int index,
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
+ u32 cpos, u32 len)
+{
+ int ret;
+ u32 left_cpos, rec_range, trunc_range;
+ int wants_rotate = 0, is_rightmost_tree_rec = 0;
+ struct super_block *sb = inode->i_sb;
+ struct ocfs2_path *left_path = NULL;
+ struct ocfs2_extent_list *el = path_leaf_el(path);
+ struct ocfs2_extent_rec *rec;
+ struct ocfs2_extent_block *eb;
+
+ if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) {
+ ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ index--;
+ }
+
+ if (index == (le16_to_cpu(el->l_next_free_rec) - 1) &&
+ path->p_tree_depth) {
+ /*
+ * Check whether this is the rightmost tree record. If
+ * we remove all of this record or part of its right
+ * edge then an update of the record lengths above it
+ * will be required.
+ */
+ eb = (struct ocfs2_extent_block *)path_leaf_bh(path)->b_data;
+ if (eb->h_next_leaf_blk == 0)
+ is_rightmost_tree_rec = 1;
+ }
+
+ rec = &el->l_recs[index];
+ if (index == 0 && path->p_tree_depth &&
+ le32_to_cpu(rec->e_cpos) == cpos) {
+ /*
+ * Changing the leftmost offset (via partial or whole
+ * record truncate) of an interior (or rightmost) path
+ * means we have to update the subtree that is formed
+ * by this leaf and the one to it's left.
+ *
+ * There are two cases we can skip:
+ * 1) Path is the leftmost one in our inode tree.
+ * 2) The leaf is rightmost and will be empty after
+ * we remove the extent record - the rotate code
+ * knows how to update the newly formed edge.
+ */
+
+ ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, path,
+ &left_cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (left_cpos && le16_to_cpu(el->l_next_free_rec) > 1) {
+ left_path = ocfs2_new_path(path_root_bh(path),
+ path_root_el(path));
+ if (!left_path) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_find_path(inode, left_path, left_cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+ }
+
+ ret = ocfs2_extend_rotate_transaction(handle, 0,
+ handle->h_buffer_credits,
+ path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access_path(inode, handle, path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access_path(inode, handle, left_path);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ rec_range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);
+ trunc_range = cpos + len;
+
+ if (le32_to_cpu(rec->e_cpos) == cpos && rec_range == trunc_range) {
+ int next_free;
+
+ memset(rec, 0, sizeof(*rec));
+ ocfs2_cleanup_merge(el, index);
+ wants_rotate = 1;
+
+ next_free = le16_to_cpu(el->l_next_free_rec);
+ if (is_rightmost_tree_rec && next_free > 1) {
+ /*
+ * We skip the edge update if this path will
+ * be deleted by the rotate code.
+ */
+ rec = &el->l_recs[next_free - 1];
+ ocfs2_adjust_rightmost_records(inode, handle, path,
+ rec);
+ }
+ } else if (le32_to_cpu(rec->e_cpos) == cpos) {
+ /* Remove leftmost portion of the record. */
+ le32_add_cpu(&rec->e_cpos, len);
+ le64_add_cpu(&rec->e_blkno, ocfs2_clusters_to_blocks(sb, len));
+ le16_add_cpu(&rec->e_leaf_clusters, -len);
+ } else if (rec_range == trunc_range) {
+ /* Remove rightmost portion of the record */
+ le16_add_cpu(&rec->e_leaf_clusters, -len);
+ if (is_rightmost_tree_rec)
+ ocfs2_adjust_rightmost_records(inode, handle, path, rec);
+ } else {
+ /* Caller should have trapped this. */
+ mlog(ML_ERROR, "Inode %llu: Invalid record truncate: (%u, %u) "
+ "(%u, %u)\n", (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ le32_to_cpu(rec->e_cpos),
+ le16_to_cpu(rec->e_leaf_clusters), cpos, len);
+ BUG();
+ }
+
+ if (left_path) {
+ int subtree_index;
+
+ subtree_index = ocfs2_find_subtree_root(inode, left_path, path);
+ ocfs2_complete_edge_insert(inode, handle, left_path, path,
+ subtree_index);
+ }
+
+ ocfs2_journal_dirty(handle, path_leaf_bh(path));
+
+ ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+out:
+ ocfs2_free_path(left_path);
+ return ret;
+}
+
+int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+ u32 cpos, u32 len, handle_t *handle,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int ret, index;
+ u32 rec_range, trunc_range;
+ struct ocfs2_extent_rec *rec;
+ struct ocfs2_extent_list *el;
+ struct ocfs2_path *path;
+
+ ocfs2_extent_map_trunc(inode, 0);
+
+ path = ocfs2_new_inode_path(di_bh);
+ if (!path) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_find_path(inode, path, cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ el = path_leaf_el(path);
+ index = ocfs2_search_extent_list(el, cpos);
+ if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) {
+ ocfs2_error(inode->i_sb,
+ "Inode %llu has an extent at cpos %u which can no "
+ "longer be found.\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos);
+ ret = -EROFS;
+ goto out;
+ }
+
+ /*
+ * We have 3 cases of extent removal:
+ * 1) Range covers the entire extent rec
+ * 2) Range begins or ends on one edge of the extent rec
+ * 3) Range is in the middle of the extent rec (no shared edges)
+ *
+ * For case 1 we remove the extent rec and left rotate to
+ * fill the hole.
+ *
+ * For case 2 we just shrink the existing extent rec, with a
+ * tree update if the shrinking edge is also the edge of an
+ * extent block.
+ *
+ * For case 3 we do a right split to turn the extent rec into
+ * something case 2 can handle.
+ */
+ rec = &el->l_recs[index];
+ rec_range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);
+ trunc_range = cpos + len;
+
+ BUG_ON(cpos < le32_to_cpu(rec->e_cpos) || trunc_range > rec_range);
+
+ mlog(0, "Inode %llu, remove (cpos %u, len %u). Existing index %d "
+ "(cpos %u, len %u)\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos, len, index,
+ le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec));
+
+ if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) {
+ ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
+ cpos, len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ } else {
+ ret = ocfs2_split_tree(inode, di_bh, handle, path, index,
+ trunc_range, meta_ac);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * The split could have manipulated the tree enough to
+ * move the record location, so we have to look for it again.
+ */
+ ocfs2_reinit_path(path, 1);
+
+ ret = ocfs2_find_path(inode, path, cpos);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ el = path_leaf_el(path);
+ index = ocfs2_search_extent_list(el, cpos);
+ if (index == -1 || index >= le16_to_cpu(el->l_next_free_rec)) {
+ ocfs2_error(inode->i_sb,
+ "Inode %llu: split at cpos %u lost record.",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ cpos);
+ ret = -EROFS;
+ goto out;
+ }
+
+ /*
+ * Double check our values here. If anything is fishy,
+ * it's easier to catch it at the top level.
+ */
+ rec = &el->l_recs[index];
+ rec_range = le32_to_cpu(rec->e_cpos) +
+ ocfs2_rec_clusters(el, rec);
+ if (rec_range != trunc_range) {
+ ocfs2_error(inode->i_sb,
+ "Inode %llu: error after split at cpos %u"
+ "trunc len %u, existing record is (%u,%u)",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ cpos, len, le32_to_cpu(rec->e_cpos),
+ ocfs2_rec_clusters(el, rec));
+ ret = -EROFS;
+ goto out;
+ }
+
+ ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
+ cpos, len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+out:
+ ocfs2_free_path(path);
+ return ret;
+}
+
+int ocfs2_truncate_log_needs_flush(struct ocfs2_super *osb)
{
struct buffer_head *tl_bh = osb->osb_tl_bh;
struct ocfs2_dinode *di;
@@ -2464,10 +4539,10 @@ static int ocfs2_truncate_log_can_coalesce(struct ocfs2_truncate_log *tl,
return current_tail == new_start;
}
-static int ocfs2_truncate_log_append(struct ocfs2_super *osb,
- handle_t *handle,
- u64 start_blk,
- unsigned int num_clusters)
+int ocfs2_truncate_log_append(struct ocfs2_super *osb,
+ handle_t *handle,
+ u64 start_blk,
+ unsigned int num_clusters)
{
int status, index;
unsigned int start_cluster, tl_count;
@@ -2623,7 +4698,7 @@ bail:
}
/* Expects you to already be holding tl_inode->i_mutex */
-static int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
+int __ocfs2_flush_truncate_log(struct ocfs2_super *osb)
{
int status;
unsigned int num_to_flush;
@@ -2957,6 +5032,219 @@ int ocfs2_truncate_log_init(struct ocfs2_super *osb)
return status;
}
+/*
+ * Delayed de-allocation of suballocator blocks.
+ *
+ * Some sets of block de-allocations might involve multiple suballocator inodes.
+ *
+ * The locking for this can get extremely complicated, especially when
+ * the suballocator inodes to delete from aren't known until deep
+ * within an unrelated codepath.
+ *
+ * ocfs2_extent_block structures are a good example of this - an inode
+ * btree could have been grown by any number of nodes each allocating
+ * out of their own suballoc inode.
+ *
+ * These structures allow the delay of block de-allocation until a
+ * later time, when locking of multiple cluster inodes won't cause
+ * deadlock.
+ */
+
+/*
+ * Describes a single block free from a suballocator
+ */
+struct ocfs2_cached_block_free {
+ struct ocfs2_cached_block_free *free_next;
+ u64 free_blk;
+ unsigned int free_bit;
+};
+
+struct ocfs2_per_slot_free_list {
+ struct ocfs2_per_slot_free_list *f_next_suballocator;
+ int f_inode_type;
+ int f_slot;
+ struct ocfs2_cached_block_free *f_first;
+};
+
+static int ocfs2_free_cached_items(struct ocfs2_super *osb,
+ int sysfile_type,
+ int slot,
+ struct ocfs2_cached_block_free *head)
+{
+ int ret;
+ u64 bg_blkno;
+ handle_t *handle;
+ struct inode *inode;
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_cached_block_free *tmp;
+
+ inode = ocfs2_get_system_file_inode(osb, sysfile_type, slot);
+ if (!inode) {
+ ret = -EINVAL;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ mutex_lock(&inode->i_mutex);
+
+ ret = ocfs2_meta_lock(inode, &di_bh, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_mutex;
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out_unlock;
+ }
+
+ while (head) {
+ bg_blkno = ocfs2_which_suballoc_group(head->free_blk,
+ head->free_bit);
+ mlog(0, "Free bit: (bit %u, blkno %llu)\n",
+ head->free_bit, (unsigned long long)head->free_blk);
+
+ ret = ocfs2_free_suballoc_bits(handle, inode, di_bh,
+ head->free_bit, bg_blkno, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_journal;
+ }
+
+ ret = ocfs2_extend_trans(handle, OCFS2_SUBALLOC_FREE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_journal;
+ }
+
+ tmp = head;
+ head = head->free_next;
+ kfree(tmp);
+ }
+
+out_journal:
+ ocfs2_commit_trans(osb, handle);
+
+out_unlock:
+ ocfs2_meta_unlock(inode, 1);
+ brelse(di_bh);
+out_mutex:
+ mutex_unlock(&inode->i_mutex);
+ iput(inode);
+out:
+ while(head) {
+ /* Premature exit may have left some dangling items. */
+ tmp = head;
+ head = head->free_next;
+ kfree(tmp);
+ }
+
+ return ret;
+}
+
+int ocfs2_run_deallocs(struct ocfs2_super *osb,
+ struct ocfs2_cached_dealloc_ctxt *ctxt)
+{
+ int ret = 0, ret2;
+ struct ocfs2_per_slot_free_list *fl;
+
+ if (!ctxt)
+ return 0;
+
+ while (ctxt->c_first_suballocator) {
+ fl = ctxt->c_first_suballocator;
+
+ if (fl->f_first) {
+ mlog(0, "Free items: (type %u, slot %d)\n",
+ fl->f_inode_type, fl->f_slot);
+ ret2 = ocfs2_free_cached_items(osb, fl->f_inode_type,
+ fl->f_slot, fl->f_first);
+ if (ret2)
+ mlog_errno(ret2);
+ if (!ret)
+ ret = ret2;
+ }
+
+ ctxt->c_first_suballocator = fl->f_next_suballocator;
+ kfree(fl);
+ }
+
+ return ret;
+}
+
+static struct ocfs2_per_slot_free_list *
+ocfs2_find_per_slot_free_list(int type,
+ int slot,
+ struct ocfs2_cached_dealloc_ctxt *ctxt)
+{
+ struct ocfs2_per_slot_free_list *fl = ctxt->c_first_suballocator;
+
+ while (fl) {
+ if (fl->f_inode_type == type && fl->f_slot == slot)
+ return fl;
+
+ fl = fl->f_next_suballocator;
+ }
+
+ fl = kmalloc(sizeof(*fl), GFP_NOFS);
+ if (fl) {
+ fl->f_inode_type = type;
+ fl->f_slot = slot;
+ fl->f_first = NULL;
+ fl->f_next_suballocator = ctxt->c_first_suballocator;
+
+ ctxt->c_first_suballocator = fl;
+ }
+ return fl;
+}
+
+static int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
+ int type, int slot, u64 blkno,
+ unsigned int bit)
+{
+ int ret;
+ struct ocfs2_per_slot_free_list *fl;
+ struct ocfs2_cached_block_free *item;
+
+ fl = ocfs2_find_per_slot_free_list(type, slot, ctxt);
+ if (fl == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ item = kmalloc(sizeof(*item), GFP_NOFS);
+ if (item == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ mlog(0, "Insert: (type %d, slot %u, bit %u, blk %llu)\n",
+ type, slot, bit, (unsigned long long)blkno);
+
+ item->free_blk = blkno;
+ item->free_bit = bit;
+ item->free_next = fl->f_first;
+
+ fl->f_first = item;
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
+ struct ocfs2_extent_block *eb)
+{
+ return ocfs2_cache_block_dealloc(ctxt, EXTENT_ALLOC_SYSTEM_INODE,
+ le16_to_cpu(eb->h_suballoc_slot),
+ le64_to_cpu(eb->h_blkno),
+ le16_to_cpu(eb->h_suballoc_bit));
+}
+
/* This function will figure out whether the currently last extent
* block will be deleted, and if it will, what the new last extent
* block will be so we can update his h_next_leaf_blk field, as well
@@ -3238,27 +5526,10 @@ delete:
BUG_ON(le32_to_cpu(el->l_recs[0].e_cpos));
BUG_ON(le64_to_cpu(el->l_recs[0].e_blkno));
- if (le16_to_cpu(eb->h_suballoc_slot) == 0) {
- /*
- * This code only understands how to
- * lock the suballocator in slot 0,
- * which is fine because allocation is
- * only ever done out of that
- * suballocator too. A future version
- * might change that however, so avoid
- * a free if we don't know how to
- * handle it. This way an fs incompat
- * bit will not be necessary.
- */
- ret = ocfs2_free_extent_block(handle,
- tc->tc_ext_alloc_inode,
- tc->tc_ext_alloc_bh,
- eb);
-
- /* An error here is not fatal. */
- if (ret < 0)
- mlog_errno(ret);
- }
+ ret = ocfs2_cache_extent_block_free(&tc->tc_dealloc, eb);
+ /* An error here is not fatal. */
+ if (ret < 0)
+ mlog_errno(ret);
} else {
deleted_eb = 0;
}
@@ -3397,9 +5668,9 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
return ocfs2_journal_dirty_data(handle, bh);
}
-static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize,
- struct page **pages, int numpages,
- u64 phys, handle_t *handle)
+static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start,
+ loff_t end, struct page **pages,
+ int numpages, u64 phys, handle_t *handle)
{
int i, ret, partial = 0;
void *kaddr;
@@ -3412,26 +5683,14 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize,
if (numpages == 0)
goto out;
- from = isize & (PAGE_CACHE_SIZE - 1); /* 1st page offset */
- if (PAGE_CACHE_SHIFT > OCFS2_SB(sb)->s_clustersize_bits) {
- /*
- * Since 'from' has been capped to a value below page
- * size, this calculation won't be able to overflow
- * 'to'
- */
- to = ocfs2_align_bytes_to_clusters(sb, from);
-
- /*
- * The truncate tail in this case should never contain
- * more than one page at maximum. The loop below also
- * assumes this.
- */
- BUG_ON(numpages != 1);
- }
-
+ to = PAGE_CACHE_SIZE;
for(i = 0; i < numpages; i++) {
page = pages[i];
+ from = start & (PAGE_CACHE_SIZE - 1);
+ if ((end >> PAGE_CACHE_SHIFT) == page->index)
+ to = end & (PAGE_CACHE_SIZE - 1);
+
BUG_ON(from > PAGE_CACHE_SIZE);
BUG_ON(to > PAGE_CACHE_SIZE);
@@ -3468,10 +5727,7 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize,
flush_dcache_page(page);
- /*
- * Every page after the 1st one should be completely zero'd.
- */
- from = 0;
+ start = (page->index + 1) << PAGE_CACHE_SHIFT;
}
out:
if (pages) {
@@ -3484,24 +5740,26 @@ out:
}
}
-static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page **pages,
- int *num, u64 *phys)
+static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
+ struct page **pages, int *num, u64 *phys)
{
int i, numpages = 0, ret = 0;
- unsigned int csize = OCFS2_SB(inode->i_sb)->s_clustersize;
unsigned int ext_flags;
struct super_block *sb = inode->i_sb;
struct address_space *mapping = inode->i_mapping;
unsigned long index;
- u64 next_cluster_bytes;
+ loff_t last_page_bytes;
BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb)));
+ BUG_ON(start > end);
- /* Cluster boundary, so we don't need to grab any pages. */
- if ((isize & (csize - 1)) == 0)
+ if (start == end)
goto out;
- ret = ocfs2_extent_map_get_blocks(inode, isize >> sb->s_blocksize_bits,
+ BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits !=
+ (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits);
+
+ ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits,
phys, NULL, &ext_flags);
if (ret) {
mlog_errno(ret);
@@ -3517,8 +5775,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page *
if (ext_flags & OCFS2_EXT_UNWRITTEN)
goto out;
- next_cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, isize);
- index = isize >> PAGE_CACHE_SHIFT;
+ last_page_bytes = PAGE_ALIGN(end);
+ index = start >> PAGE_CACHE_SHIFT;
do {
pages[numpages] = grab_cache_page(mapping, index);
if (!pages[numpages]) {
@@ -3529,7 +5787,7 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page *
numpages++;
index++;
- } while (index < (next_cluster_bytes >> PAGE_CACHE_SHIFT));
+ } while (index < (last_page_bytes >> PAGE_CACHE_SHIFT));
out:
if (ret != 0) {
@@ -3558,11 +5816,10 @@ out:
* otherwise block_write_full_page() will skip writeout of pages past
* i_size. The new_i_size parameter is passed for this reason.
*/
-int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
- u64 new_i_size)
+int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
+ u64 range_start, u64 range_end)
{
int ret, numpages;
- loff_t endbyte;
struct page **pages = NULL;
u64 phys;
@@ -3581,7 +5838,8 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
goto out;
}
- ret = ocfs2_grab_eof_pages(inode, new_i_size, pages, &numpages, &phys);
+ ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
+ &numpages, &phys);
if (ret) {
mlog_errno(ret);
goto out;
@@ -3590,17 +5848,16 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
if (numpages == 0)
goto out;
- ocfs2_zero_cluster_pages(inode, new_i_size, pages, numpages, phys,
- handle);
+ ocfs2_zero_cluster_pages(inode, range_start, range_end, pages,
+ numpages, phys, handle);
/*
* Initiate writeout of the pages we zero'd here. We don't
* wait on them - the truncate_inode_pages() call later will
* do that for us.
*/
- endbyte = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size);
- ret = do_sync_mapping_range(inode->i_mapping, new_i_size,
- endbyte - 1, SYNC_FILE_RANGE_WRITE);
+ ret = do_sync_mapping_range(inode->i_mapping, range_start,
+ range_end - 1, SYNC_FILE_RANGE_WRITE);
if (ret)
mlog_errno(ret);
@@ -3631,8 +5888,6 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
mlog_entry_void();
- down_write(&OCFS2_I(inode)->ip_alloc_sem);
-
new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb,
i_size_read(inode));
@@ -3754,7 +6009,6 @@ start:
goto start;
bail:
- up_write(&OCFS2_I(inode)->ip_alloc_sem);
ocfs2_schedule_truncate_log_flush(osb, 1);
@@ -3764,6 +6018,8 @@ bail:
if (handle)
ocfs2_commit_trans(osb, handle);
+ ocfs2_run_deallocs(osb, &tc->tc_dealloc);
+
ocfs2_free_path(path);
/* This will drop the ext_alloc cluster lock for us */
@@ -3774,23 +6030,18 @@ bail:
}
/*
- * Expects the inode to already be locked. This will figure out which
- * inodes need to be locked and will put them on the returned truncate
- * context.
+ * Expects the inode to already be locked.
*/
int ocfs2_prepare_truncate(struct ocfs2_super *osb,
struct inode *inode,
struct buffer_head *fe_bh,
struct ocfs2_truncate_context **tc)
{
- int status, metadata_delete, i;
+ int status;
unsigned int new_i_clusters;
struct ocfs2_dinode *fe;
struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *el;
struct buffer_head *last_eb_bh = NULL;
- struct inode *ext_alloc_inode = NULL;
- struct buffer_head *ext_alloc_bh = NULL;
mlog_entry_void();
@@ -3810,12 +6061,9 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
mlog_errno(status);
goto bail;
}
+ ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc);
- metadata_delete = 0;
if (fe->id2.i_list.l_tree_depth) {
- /* If we have a tree, then the truncate may result in
- * metadata deletes. Figure this out from the
- * rightmost leaf block.*/
status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
&last_eb_bh, OCFS2_BH_CACHED, inode);
if (status < 0) {
@@ -3830,43 +6078,10 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
status = -EIO;
goto bail;
}
- el = &(eb->h_list);
-
- i = 0;
- if (ocfs2_is_empty_extent(&el->l_recs[0]))
- i = 1;
- /*
- * XXX: Should we check that next_free_rec contains
- * the extent?
- */
- if (le32_to_cpu(el->l_recs[i].e_cpos) >= new_i_clusters)
- metadata_delete = 1;
}
(*tc)->tc_last_eb_bh = last_eb_bh;
- if (metadata_delete) {
- mlog(0, "Will have to delete metadata for this trunc. "
- "locking allocator.\n");
- ext_alloc_inode = ocfs2_get_system_file_inode(osb, EXTENT_ALLOC_SYSTEM_INODE, 0);
- if (!ext_alloc_inode) {
- status = -ENOMEM;
- mlog_errno(status);
- goto bail;
- }
-
- mutex_lock(&ext_alloc_inode->i_mutex);
- (*tc)->tc_ext_alloc_inode = ext_alloc_inode;
-
- status = ocfs2_meta_lock(ext_alloc_inode, &ext_alloc_bh, 1);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
- (*tc)->tc_ext_alloc_bh = ext_alloc_bh;
- (*tc)->tc_ext_alloc_locked = 1;
- }
-
status = 0;
bail:
if (status < 0) {
@@ -3880,16 +6095,13 @@ bail:
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
{
- if (tc->tc_ext_alloc_inode) {
- if (tc->tc_ext_alloc_locked)
- ocfs2_meta_unlock(tc->tc_ext_alloc_inode, 1);
-
- mutex_unlock(&tc->tc_ext_alloc_inode->i_mutex);
- iput(tc->tc_ext_alloc_inode);
- }
-
- if (tc->tc_ext_alloc_bh)
- brelse(tc->tc_ext_alloc_bh);
+ /*
+ * The caller is responsible for completing deallocation
+ * before freeing the context.
+ */
+ if (tc->tc_dealloc.c_first_suballocator != NULL)
+ mlog(ML_NOTICE,
+ "Truncate completion has non-empty dealloc context\n");
if (tc->tc_last_eb_bh)
brelse(tc->tc_last_eb_bh);
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index fbcb5934a081..990df48ae8d3 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -34,7 +34,17 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
u32 cpos,
u64 start_blk,
u32 new_clusters,
+ u8 flags,
struct ocfs2_alloc_context *meta_ac);
+struct ocfs2_cached_dealloc_ctxt;
+int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+ handle_t *handle, u32 cpos, u32 len, u32 phys,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_cached_dealloc_ctxt *dealloc);
+int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+ u32 cpos, u32 len, handle_t *handle,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_cached_dealloc_ctxt *dealloc);
int ocfs2_num_free_extents(struct ocfs2_super *osb,
struct inode *inode,
struct ocfs2_dinode *fe);
@@ -62,17 +72,41 @@ int ocfs2_begin_truncate_log_recovery(struct ocfs2_super *osb,
struct ocfs2_dinode **tl_copy);
int ocfs2_complete_truncate_log_recovery(struct ocfs2_super *osb,
struct ocfs2_dinode *tl_copy);
+int ocfs2_truncate_log_needs_flush(struct ocfs2_super *osb);
+int ocfs2_truncate_log_append(struct ocfs2_super *osb,
+ handle_t *handle,
+ u64 start_blk,
+ unsigned int num_clusters);
+int __ocfs2_flush_truncate_log(struct ocfs2_super *osb);
+
+/*
+ * Process local structure which describes the block unlinks done
+ * during an operation. This is populated via
+ * ocfs2_cache_block_dealloc().
+ *
+ * ocfs2_run_deallocs() should be called after the potentially
+ * de-allocating routines. No journal handles should be open, and most
+ * locks should have been dropped.
+ */
+struct ocfs2_cached_dealloc_ctxt {
+ struct ocfs2_per_slot_free_list *c_first_suballocator;
+};
+static inline void ocfs2_init_dealloc_ctxt(struct ocfs2_cached_dealloc_ctxt *c)
+{
+ c->c_first_suballocator = NULL;
+}
+int ocfs2_run_deallocs(struct ocfs2_super *osb,
+ struct ocfs2_cached_dealloc_ctxt *ctxt);
struct ocfs2_truncate_context {
- struct inode *tc_ext_alloc_inode;
- struct buffer_head *tc_ext_alloc_bh;
+ struct ocfs2_cached_dealloc_ctxt tc_dealloc;
int tc_ext_alloc_locked; /* is it cluster locked? */
/* these get destroyed once it's passed to ocfs2_commit_truncate. */
struct buffer_head *tc_last_eb_bh;
};
-int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
- u64 new_i_size);
+int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
+ u64 range_start, u64 range_end);
int ocfs2_prepare_truncate(struct ocfs2_super *osb,
struct inode *inode,
struct buffer_head *fe_bh,
@@ -84,6 +118,7 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
int ocfs2_find_leaf(struct inode *inode, struct ocfs2_extent_list *root_el,
u32 cpos, struct buffer_head **leaf_bh);
+int ocfs2_search_extent_list(struct ocfs2_extent_list *el, u32 v_cluster);
/*
* Helper function to look at the # of clusters in an extent record.
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index a480b09c79b9..460d440310f2 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -232,7 +232,7 @@ static int ocfs2_readpage(struct file *file, struct page *page)
* might now be discovering a truncate that hit on another node.
* block_read_full_page->get_block freaks out if it is asked to read
* beyond the end of a file, so we check here. Callers
- * (generic_file_read, fault->nopage) are clever enough to check i_size
+ * (generic_file_read, vm_ops->fault) are clever enough to check i_size
* and notice that the page they just read isn't needed.
*
* XXX sys_readahead() seems to get that wrong?
@@ -684,6 +684,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
bh = bh->b_this_page, block_start += bsize) {
block_end = block_start + bsize;
+ clear_buffer_new(bh);
+
/*
* Ignore blocks outside of our i/o range -
* they may belong to unallocated clusters.
@@ -698,9 +700,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
* For an allocating write with cluster size >= page
* size, we always write the entire page.
*/
-
- if (buffer_new(bh))
- clear_buffer_new(bh);
+ if (new)
+ set_buffer_new(bh);
if (!buffer_mapped(bh)) {
map_bh(bh, inode->i_sb, *p_blkno);
@@ -711,7 +712,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
if (!buffer_uptodate(bh))
set_buffer_uptodate(bh);
} else if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
- (block_start < from || block_end > to)) {
+ !buffer_new(bh) &&
+ (block_start < from || block_end > to)) {
ll_rw_block(READ, 1, &bh);
*wait_bh++=bh;
}
@@ -738,18 +740,13 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno,
bh = head;
block_start = 0;
do {
- void *kaddr;
-
block_end = block_start + bsize;
if (block_end <= from)
goto next_bh;
if (block_start >= to)
break;
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr+block_start, 0, bh->b_size);
- flush_dcache_page(page);
- kunmap_atomic(kaddr, KM_USER0);
+ zero_user_page(page, block_start, bh->b_size, KM_USER0);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
@@ -761,217 +758,240 @@ next_bh:
return ret;
}
+#if (PAGE_CACHE_SIZE >= OCFS2_MAX_CLUSTERSIZE)
+#define OCFS2_MAX_CTXT_PAGES 1
+#else
+#define OCFS2_MAX_CTXT_PAGES (OCFS2_MAX_CLUSTERSIZE / PAGE_CACHE_SIZE)
+#endif
+
+#define OCFS2_MAX_CLUSTERS_PER_PAGE (PAGE_CACHE_SIZE / OCFS2_MIN_CLUSTERSIZE)
+
/*
- * This will copy user data from the buffer page in the splice
- * context.
- *
- * For now, we ignore SPLICE_F_MOVE as that would require some extra
- * communication out all the way to ocfs2_write().
+ * Describe the state of a single cluster to be written to.
*/
-int ocfs2_map_and_write_splice_data(struct inode *inode,
- struct ocfs2_write_ctxt *wc, u64 *p_blkno,
- unsigned int *ret_from, unsigned int *ret_to)
+struct ocfs2_write_cluster_desc {
+ u32 c_cpos;
+ u32 c_phys;
+ /*
+ * Give this a unique field because c_phys eventually gets
+ * filled.
+ */
+ unsigned c_new;
+ unsigned c_unwritten;
+};
+
+static inline int ocfs2_should_zero_cluster(struct ocfs2_write_cluster_desc *d)
{
- int ret;
- unsigned int to, from, cluster_start, cluster_end;
- char *src, *dst;
- struct ocfs2_splice_write_priv *sp = wc->w_private;
- struct pipe_buffer *buf = sp->s_buf;
- unsigned long bytes, src_from;
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ return d->c_new || d->c_unwritten;
+}
- ocfs2_figure_cluster_boundaries(osb, wc->w_cpos, &cluster_start,
- &cluster_end);
+struct ocfs2_write_ctxt {
+ /* Logical cluster position / len of write */
+ u32 w_cpos;
+ u32 w_clen;
- from = sp->s_offset;
- src_from = sp->s_buf_offset;
- bytes = wc->w_count;
+ struct ocfs2_write_cluster_desc w_desc[OCFS2_MAX_CLUSTERS_PER_PAGE];
- if (wc->w_large_pages) {
- /*
- * For cluster size < page size, we have to
- * calculate pos within the cluster and obey
- * the rightmost boundary.
- */
- bytes = min(bytes, (unsigned long)(osb->s_clustersize
- - (wc->w_pos & (osb->s_clustersize - 1))));
- }
- to = from + bytes;
+ /*
+ * This is true if page_size > cluster_size.
+ *
+ * It triggers a set of special cases during write which might
+ * have to deal with allocating writes to partial pages.
+ */
+ unsigned int w_large_pages;
+
+ /*
+ * Pages involved in this write.
+ *
+ * w_target_page is the page being written to by the user.
+ *
+ * w_pages is an array of pages which always contains
+ * w_target_page, and in the case of an allocating write with
+ * page_size < cluster size, it will contain zero'd and mapped
+ * pages adjacent to w_target_page which need to be written
+ * out in so that future reads from that region will get
+ * zero's.
+ */
+ struct page *w_pages[OCFS2_MAX_CTXT_PAGES];
+ unsigned int w_num_pages;
+ struct page *w_target_page;
- BUG_ON(from > PAGE_CACHE_SIZE);
- BUG_ON(to > PAGE_CACHE_SIZE);
- BUG_ON(from < cluster_start);
- BUG_ON(to > cluster_end);
+ /*
+ * ocfs2_write_end() uses this to know what the real range to
+ * write in the target should be.
+ */
+ unsigned int w_target_from;
+ unsigned int w_target_to;
- if (wc->w_this_page_new)
- ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
- cluster_start, cluster_end, 1);
- else
- ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
- from, to, 0);
- if (ret) {
- mlog_errno(ret);
- goto out;
+ /*
+ * We could use journal_current_handle() but this is cleaner,
+ * IMHO -Mark
+ */
+ handle_t *w_handle;
+
+ struct buffer_head *w_di_bh;
+
+ struct ocfs2_cached_dealloc_ctxt w_dealloc;
+};
+
+static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc)
+{
+ int i;
+
+ for(i = 0; i < wc->w_num_pages; i++) {
+ if (wc->w_pages[i] == NULL)
+ continue;
+
+ unlock_page(wc->w_pages[i]);
+ mark_page_accessed(wc->w_pages[i]);
+ page_cache_release(wc->w_pages[i]);
}
- src = buf->ops->map(sp->s_pipe, buf, 1);
- dst = kmap_atomic(wc->w_this_page, KM_USER1);
- memcpy(dst + from, src + src_from, bytes);
- kunmap_atomic(wc->w_this_page, KM_USER1);
- buf->ops->unmap(sp->s_pipe, buf, src);
+ brelse(wc->w_di_bh);
+ kfree(wc);
+}
+
+static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp,
+ struct ocfs2_super *osb, loff_t pos,
+ unsigned len, struct buffer_head *di_bh)
+{
+ struct ocfs2_write_ctxt *wc;
+
+ wc = kzalloc(sizeof(struct ocfs2_write_ctxt), GFP_NOFS);
+ if (!wc)
+ return -ENOMEM;
- wc->w_finished_copy = 1;
+ wc->w_cpos = pos >> osb->s_clustersize_bits;
+ wc->w_clen = ocfs2_clusters_for_bytes(osb->sb, len);
+ get_bh(di_bh);
+ wc->w_di_bh = di_bh;
- *ret_from = from;
- *ret_to = to;
-out:
+ if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits))
+ wc->w_large_pages = 1;
+ else
+ wc->w_large_pages = 0;
+
+ ocfs2_init_dealloc_ctxt(&wc->w_dealloc);
+
+ *wcp = wc;
- return bytes ? (unsigned int)bytes : ret;
+ return 0;
}
/*
- * This will copy user data from the iovec in the buffered write
- * context.
+ * If a page has any new buffers, zero them out here, and mark them uptodate
+ * and dirty so they'll be written out (in order to prevent uninitialised
+ * block data from leaking). And clear the new bit.
*/
-int ocfs2_map_and_write_user_data(struct inode *inode,
- struct ocfs2_write_ctxt *wc, u64 *p_blkno,
- unsigned int *ret_from, unsigned int *ret_to)
+static void ocfs2_zero_new_buffers(struct page *page, unsigned from, unsigned to)
{
- int ret;
- unsigned int to, from, cluster_start, cluster_end;
- unsigned long bytes, src_from;
- char *dst;
- struct ocfs2_buffered_write_priv *bp = wc->w_private;
- const struct iovec *cur_iov = bp->b_cur_iov;
- char __user *buf;
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ unsigned int block_start, block_end;
+ struct buffer_head *head, *bh;
- ocfs2_figure_cluster_boundaries(osb, wc->w_cpos, &cluster_start,
- &cluster_end);
+ BUG_ON(!PageLocked(page));
+ if (!page_has_buffers(page))
+ return;
- buf = cur_iov->iov_base + bp->b_cur_off;
- src_from = (unsigned long)buf & ~PAGE_CACHE_MASK;
+ bh = head = page_buffers(page);
+ block_start = 0;
+ do {
+ block_end = block_start + bh->b_size;
- from = wc->w_pos & (PAGE_CACHE_SIZE - 1);
+ if (buffer_new(bh)) {
+ if (block_end > from && block_start < to) {
+ if (!PageUptodate(page)) {
+ unsigned start, end;
- /*
- * This is a lot of comparisons, but it reads quite
- * easily, which is important here.
- */
- /* Stay within the src page */
- bytes = PAGE_SIZE - src_from;
- /* Stay within the vector */
- bytes = min(bytes,
- (unsigned long)(cur_iov->iov_len - bp->b_cur_off));
- /* Stay within count */
- bytes = min(bytes, (unsigned long)wc->w_count);
- /*
- * For clustersize > page size, just stay within
- * target page, otherwise we have to calculate pos
- * within the cluster and obey the rightmost
- * boundary.
- */
- if (wc->w_large_pages) {
- /*
- * For cluster size < page size, we have to
- * calculate pos within the cluster and obey
- * the rightmost boundary.
- */
- bytes = min(bytes, (unsigned long)(osb->s_clustersize
- - (wc->w_pos & (osb->s_clustersize - 1))));
- } else {
- /*
- * cluster size > page size is the most common
- * case - we just stay within the target page
- * boundary.
- */
- bytes = min(bytes, PAGE_CACHE_SIZE - from);
- }
+ start = max(from, block_start);
+ end = min(to, block_end);
- to = from + bytes;
+ zero_user_page(page, start, end - start, KM_USER0);
+ set_buffer_uptodate(bh);
+ }
- BUG_ON(from > PAGE_CACHE_SIZE);
- BUG_ON(to > PAGE_CACHE_SIZE);
- BUG_ON(from < cluster_start);
- BUG_ON(to > cluster_end);
+ clear_buffer_new(bh);
+ mark_buffer_dirty(bh);
+ }
+ }
- if (wc->w_this_page_new)
- ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
- cluster_start, cluster_end, 1);
- else
- ret = ocfs2_map_page_blocks(wc->w_this_page, p_blkno, inode,
- from, to, 0);
- if (ret) {
- mlog_errno(ret);
- goto out;
- }
+ block_start = block_end;
+ bh = bh->b_this_page;
+ } while (bh != head);
+}
- dst = kmap(wc->w_this_page);
- memcpy(dst + from, bp->b_src_buf + src_from, bytes);
- kunmap(wc->w_this_page);
+/*
+ * Only called when we have a failure during allocating write to write
+ * zero's to the newly allocated region.
+ */
+static void ocfs2_write_failure(struct inode *inode,
+ struct ocfs2_write_ctxt *wc,
+ loff_t user_pos, unsigned user_len)
+{
+ int i;
+ unsigned from, to;
+ struct page *tmppage;
- /*
- * XXX: This is slow, but simple. The caller of
- * ocfs2_buffered_write_cluster() is responsible for
- * passing through the iovecs, so it's difficult to
- * predict what our next step is in here after our
- * initial write. A future version should be pushing
- * that iovec manipulation further down.
- *
- * By setting this, we indicate that a copy from user
- * data was done, and subsequent calls for this
- * cluster will skip copying more data.
- */
- wc->w_finished_copy = 1;
+ ocfs2_zero_new_buffers(wc->w_target_page, user_pos, user_len);
- *ret_from = from;
- *ret_to = to;
-out:
+ if (wc->w_large_pages) {
+ from = wc->w_target_from;
+ to = wc->w_target_to;
+ } else {
+ from = 0;
+ to = PAGE_CACHE_SIZE;
+ }
+
+ for(i = 0; i < wc->w_num_pages; i++) {
+ tmppage = wc->w_pages[i];
- return bytes ? (unsigned int)bytes : ret;
+ if (ocfs2_should_order_data(inode))
+ walk_page_buffers(wc->w_handle, page_buffers(tmppage),
+ from, to, NULL,
+ ocfs2_journal_dirty_data);
+
+ block_commit_write(tmppage, from, to);
+ }
}
-/*
- * Map, fill and write a page to disk.
- *
- * The work of copying data is done via callback. Newly allocated
- * pages which don't take user data will be zero'd (set 'new' to
- * indicate an allocating write)
- *
- * Returns a negative error code or the number of bytes copied into
- * the page.
- */
-static int ocfs2_write_data_page(struct inode *inode, handle_t *handle,
- u64 *p_blkno, struct page *page,
- struct ocfs2_write_ctxt *wc, int new)
+static int ocfs2_prepare_page_for_write(struct inode *inode, u64 *p_blkno,
+ struct ocfs2_write_ctxt *wc,
+ struct page *page, u32 cpos,
+ loff_t user_pos, unsigned user_len,
+ int new)
{
- int ret, copied = 0;
- unsigned int from = 0, to = 0;
+ int ret;
+ unsigned int map_from = 0, map_to = 0;
unsigned int cluster_start, cluster_end;
- unsigned int zero_from = 0, zero_to = 0;
+ unsigned int user_data_from = 0, user_data_to = 0;
- ocfs2_figure_cluster_boundaries(OCFS2_SB(inode->i_sb), wc->w_cpos,
+ ocfs2_figure_cluster_boundaries(OCFS2_SB(inode->i_sb), cpos,
&cluster_start, &cluster_end);
- if ((wc->w_pos >> PAGE_CACHE_SHIFT) == page->index
- && !wc->w_finished_copy) {
-
- wc->w_this_page = page;
- wc->w_this_page_new = new;
- ret = wc->w_write_data_page(inode, wc, p_blkno, &from, &to);
- if (ret < 0) {
+ if (page == wc->w_target_page) {
+ map_from = user_pos & (PAGE_CACHE_SIZE - 1);
+ map_to = map_from + user_len;
+
+ if (new)
+ ret = ocfs2_map_page_blocks(page, p_blkno, inode,
+ cluster_start, cluster_end,
+ new);
+ else
+ ret = ocfs2_map_page_blocks(page, p_blkno, inode,
+ map_from, map_to, new);
+ if (ret) {
mlog_errno(ret);
goto out;
}
- copied = ret;
-
- zero_from = from;
- zero_to = to;
+ user_data_from = map_from;
+ user_data_to = map_to;
if (new) {
- from = cluster_start;
- to = cluster_end;
+ map_from = cluster_start;
+ map_to = cluster_end;
}
+
+ wc->w_target_from = map_from;
+ wc->w_target_to = map_to;
} else {
/*
* If we haven't allocated the new page yet, we
@@ -980,11 +1000,11 @@ static int ocfs2_write_data_page(struct inode *inode, handle_t *handle,
*/
BUG_ON(!new);
- from = cluster_start;
- to = cluster_end;
+ map_from = cluster_start;
+ map_to = cluster_end;
ret = ocfs2_map_page_blocks(page, p_blkno, inode,
- cluster_start, cluster_end, 1);
+ cluster_start, cluster_end, new);
if (ret) {
mlog_errno(ret);
goto out;
@@ -1003,108 +1023,113 @@ static int ocfs2_write_data_page(struct inode *inode, handle_t *handle,
*/
if (new && !PageUptodate(page))
ocfs2_clear_page_regions(page, OCFS2_SB(inode->i_sb),
- wc->w_cpos, zero_from, zero_to);
+ cpos, user_data_from, user_data_to);
flush_dcache_page(page);
- if (ocfs2_should_order_data(inode)) {
- ret = walk_page_buffers(handle,
- page_buffers(page),
- from, to, NULL,
- ocfs2_journal_dirty_data);
- if (ret < 0)
- mlog_errno(ret);
- }
-
- /*
- * We don't use generic_commit_write() because we need to
- * handle our own i_size update.
- */
- ret = block_commit_write(page, from, to);
- if (ret)
- mlog_errno(ret);
out:
-
- return copied ? copied : ret;
+ return ret;
}
/*
- * Do the actual write of some data into an inode. Optionally allocate
- * in order to fulfill the write.
- *
- * cpos is the logical cluster offset within the file to write at
- *
- * 'phys' is the physical mapping of that offset. a 'phys' value of
- * zero indicates that allocation is required. In this case, data_ac
- * and meta_ac should be valid (meta_ac can be null if metadata
- * allocation isn't required).
+ * This function will only grab one clusters worth of pages.
*/
-static ssize_t ocfs2_write(struct file *file, u32 phys, handle_t *handle,
- struct buffer_head *di_bh,
- struct ocfs2_alloc_context *data_ac,
- struct ocfs2_alloc_context *meta_ac,
- struct ocfs2_write_ctxt *wc)
+static int ocfs2_grab_pages_for_write(struct address_space *mapping,
+ struct ocfs2_write_ctxt *wc,
+ u32 cpos, loff_t user_pos, int new,
+ struct page *mmap_page)
{
- int ret, i, numpages = 1, new;
- unsigned int copied = 0;
- u32 tmp_pos;
- u64 v_blkno, p_blkno;
- struct address_space *mapping = file->f_mapping;
+ int ret = 0, i;
+ unsigned long start, target_index, index;
struct inode *inode = mapping->host;
- unsigned long index, start;
- struct page **cpages;
- new = phys == 0 ? 1 : 0;
+ target_index = user_pos >> PAGE_CACHE_SHIFT;
/*
* Figure out how many pages we'll be manipulating here. For
* non allocating write, we just change the one
* page. Otherwise, we'll need a whole clusters worth.
*/
- if (new)
- numpages = ocfs2_pages_per_cluster(inode->i_sb);
-
- cpages = kzalloc(sizeof(*cpages) * numpages, GFP_NOFS);
- if (!cpages) {
- ret = -ENOMEM;
- mlog_errno(ret);
- return ret;
- }
-
- /*
- * Fill our page array first. That way we've grabbed enough so
- * that we can zero and flush if we error after adding the
- * extent.
- */
if (new) {
- start = ocfs2_align_clusters_to_page_index(inode->i_sb,
- wc->w_cpos);
- v_blkno = ocfs2_clusters_to_blocks(inode->i_sb, wc->w_cpos);
+ wc->w_num_pages = ocfs2_pages_per_cluster(inode->i_sb);
+ start = ocfs2_align_clusters_to_page_index(inode->i_sb, cpos);
} else {
- start = wc->w_pos >> PAGE_CACHE_SHIFT;
- v_blkno = wc->w_pos >> inode->i_sb->s_blocksize_bits;
+ wc->w_num_pages = 1;
+ start = target_index;
}
- for(i = 0; i < numpages; i++) {
+ for(i = 0; i < wc->w_num_pages; i++) {
index = start + i;
- cpages[i] = find_or_create_page(mapping, index, GFP_NOFS);
- if (!cpages[i]) {
- ret = -ENOMEM;
- mlog_errno(ret);
- goto out;
+ if (index == target_index && mmap_page) {
+ /*
+ * ocfs2_pagemkwrite() is a little different
+ * and wants us to directly use the page
+ * passed in.
+ */
+ lock_page(mmap_page);
+
+ if (mmap_page->mapping != mapping) {
+ unlock_page(mmap_page);
+ /*
+ * Sanity check - the locking in
+ * ocfs2_pagemkwrite() should ensure
+ * that this code doesn't trigger.
+ */
+ ret = -EINVAL;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ page_cache_get(mmap_page);
+ wc->w_pages[i] = mmap_page;
+ } else {
+ wc->w_pages[i] = find_or_create_page(mapping, index,
+ GFP_NOFS);
+ if (!wc->w_pages[i]) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
}
+
+ if (index == target_index)
+ wc->w_target_page = wc->w_pages[i];
}
+out:
+ return ret;
+}
+
+/*
+ * Prepare a single cluster for write one cluster into the file.
+ */
+static int ocfs2_write_cluster(struct address_space *mapping,
+ u32 phys, unsigned int unwritten,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_write_ctxt *wc, u32 cpos,
+ loff_t user_pos, unsigned user_len)
+{
+ int ret, i, new, should_zero = 0;
+ u64 v_blkno, p_blkno;
+ struct inode *inode = mapping->host;
+
+ new = phys == 0 ? 1 : 0;
+ if (new || unwritten)
+ should_zero = 1;
if (new) {
+ u32 tmp_pos;
+
/*
* This is safe to call with the page locks - it won't take
* any additional semaphores or cluster locks.
*/
- tmp_pos = wc->w_cpos;
+ tmp_pos = cpos;
ret = ocfs2_do_extend_allocation(OCFS2_SB(inode->i_sb), inode,
- &tmp_pos, 1, di_bh, handle,
- data_ac, meta_ac, NULL);
+ &tmp_pos, 1, 0, wc->w_di_bh,
+ wc->w_handle, data_ac,
+ meta_ac, NULL);
/*
* This shouldn't happen because we must have already
* calculated the correct meta data allocation required. The
@@ -1121,159 +1146,433 @@ static ssize_t ocfs2_write(struct file *file, u32 phys, handle_t *handle,
mlog_errno(ret);
goto out;
}
+ } else if (unwritten) {
+ ret = ocfs2_mark_extent_written(inode, wc->w_di_bh,
+ wc->w_handle, cpos, 1, phys,
+ meta_ac, &wc->w_dealloc);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
}
+ if (should_zero)
+ v_blkno = ocfs2_clusters_to_blocks(inode->i_sb, cpos);
+ else
+ v_blkno = user_pos >> inode->i_sb->s_blocksize_bits;
+
+ /*
+ * The only reason this should fail is due to an inability to
+ * find the extent added.
+ */
ret = ocfs2_extent_map_get_blocks(inode, v_blkno, &p_blkno, NULL,
NULL);
if (ret < 0) {
-
- /*
- * XXX: Should we go readonly here?
- */
-
- mlog_errno(ret);
+ ocfs2_error(inode->i_sb, "Corrupting extend for inode %llu, "
+ "at logical block %llu",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ (unsigned long long)v_blkno);
goto out;
}
BUG_ON(p_blkno == 0);
- for(i = 0; i < numpages; i++) {
- ret = ocfs2_write_data_page(inode, handle, &p_blkno, cpages[i],
- wc, new);
- if (ret < 0) {
- mlog_errno(ret);
- goto out;
+ for(i = 0; i < wc->w_num_pages; i++) {
+ int tmpret;
+
+ tmpret = ocfs2_prepare_page_for_write(inode, &p_blkno, wc,
+ wc->w_pages[i], cpos,
+ user_pos, user_len,
+ should_zero);
+ if (tmpret) {
+ mlog_errno(tmpret);
+ if (ret == 0)
+ tmpret = ret;
}
-
- copied += ret;
}
+ /*
+ * We only have cleanup to do in case of allocating write.
+ */
+ if (ret && new)
+ ocfs2_write_failure(inode, wc, user_pos, user_len);
+
out:
- for(i = 0; i < numpages; i++) {
- unlock_page(cpages[i]);
- mark_page_accessed(cpages[i]);
- page_cache_release(cpages[i]);
+
+ return ret;
+}
+
+static int ocfs2_write_cluster_by_desc(struct address_space *mapping,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_write_ctxt *wc,
+ loff_t pos, unsigned len)
+{
+ int ret, i;
+ struct ocfs2_write_cluster_desc *desc;
+
+ for (i = 0; i < wc->w_clen; i++) {
+ desc = &wc->w_desc[i];
+
+ ret = ocfs2_write_cluster(mapping, desc->c_phys,
+ desc->c_unwritten, data_ac, meta_ac,
+ wc, desc->c_cpos, pos, len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
}
- kfree(cpages);
- return copied ? copied : ret;
+ ret = 0;
+out:
+ return ret;
}
-static void ocfs2_write_ctxt_init(struct ocfs2_write_ctxt *wc,
- struct ocfs2_super *osb, loff_t pos,
- size_t count, ocfs2_page_writer *cb,
- void *cb_priv)
+/*
+ * ocfs2_write_end() wants to know which parts of the target page it
+ * should complete the write on. It's easiest to compute them ahead of
+ * time when a more complete view of the write is available.
+ */
+static void ocfs2_set_target_boundaries(struct ocfs2_super *osb,
+ struct ocfs2_write_ctxt *wc,
+ loff_t pos, unsigned len, int alloc)
{
- wc->w_count = count;
- wc->w_pos = pos;
- wc->w_cpos = wc->w_pos >> osb->s_clustersize_bits;
- wc->w_finished_copy = 0;
+ struct ocfs2_write_cluster_desc *desc;
- if (unlikely(PAGE_CACHE_SHIFT > osb->s_clustersize_bits))
- wc->w_large_pages = 1;
- else
- wc->w_large_pages = 0;
+ wc->w_target_from = pos & (PAGE_CACHE_SIZE - 1);
+ wc->w_target_to = wc->w_target_from + len;
- wc->w_write_data_page = cb;
- wc->w_private = cb_priv;
+ if (alloc == 0)
+ return;
+
+ /*
+ * Allocating write - we may have different boundaries based
+ * on page size and cluster size.
+ *
+ * NOTE: We can no longer compute one value from the other as
+ * the actual write length and user provided length may be
+ * different.
+ */
+
+ if (wc->w_large_pages) {
+ /*
+ * We only care about the 1st and last cluster within
+ * our range and whether they should be zero'd or not. Either
+ * value may be extended out to the start/end of a
+ * newly allocated cluster.
+ */
+ desc = &wc->w_desc[0];
+ if (ocfs2_should_zero_cluster(desc))
+ ocfs2_figure_cluster_boundaries(osb,
+ desc->c_cpos,
+ &wc->w_target_from,
+ NULL);
+
+ desc = &wc->w_desc[wc->w_clen - 1];
+ if (ocfs2_should_zero_cluster(desc))
+ ocfs2_figure_cluster_boundaries(osb,
+ desc->c_cpos,
+ NULL,
+ &wc->w_target_to);
+ } else {
+ wc->w_target_from = 0;
+ wc->w_target_to = PAGE_CACHE_SIZE;
+ }
}
/*
- * Write a cluster to an inode. The cluster may not be allocated yet,
- * in which case it will be. This only exists for buffered writes -
- * O_DIRECT takes a more "traditional" path through the kernel.
- *
- * The caller is responsible for incrementing pos, written counts, etc
+ * Populate each single-cluster write descriptor in the write context
+ * with information about the i/o to be done.
*
- * For file systems that don't support sparse files, pre-allocation
- * and page zeroing up until cpos should be done prior to this
- * function call.
- *
- * Callers should be holding i_sem, and the rw cluster lock.
- *
- * Returns the number of user bytes written, or less than zero for
- * error.
+ * Returns the number of clusters that will have to be allocated, as
+ * well as a worst case estimate of the number of extent records that
+ * would have to be created during a write to an unwritten region.
*/
-ssize_t ocfs2_buffered_write_cluster(struct file *file, loff_t pos,
- size_t count, ocfs2_page_writer *actor,
- void *priv)
+static int ocfs2_populate_write_desc(struct inode *inode,
+ struct ocfs2_write_ctxt *wc,
+ unsigned int *clusters_to_alloc,
+ unsigned int *extents_to_split)
+{
+ int ret;
+ struct ocfs2_write_cluster_desc *desc;
+ unsigned int num_clusters = 0;
+ unsigned int ext_flags = 0;
+ u32 phys = 0;
+ int i;
+
+ *clusters_to_alloc = 0;
+ *extents_to_split = 0;
+
+ for (i = 0; i < wc->w_clen; i++) {
+ desc = &wc->w_desc[i];
+ desc->c_cpos = wc->w_cpos + i;
+
+ if (num_clusters == 0) {
+ /*
+ * Need to look up the next extent record.
+ */
+ ret = ocfs2_get_clusters(inode, desc->c_cpos, &phys,
+ &num_clusters, &ext_flags);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * Assume worst case - that we're writing in
+ * the middle of the extent.
+ *
+ * We can assume that the write proceeds from
+ * left to right, in which case the extent
+ * insert code is smart enough to coalesce the
+ * next splits into the previous records created.
+ */
+ if (ext_flags & OCFS2_EXT_UNWRITTEN)
+ *extents_to_split = *extents_to_split + 2;
+ } else if (phys) {
+ /*
+ * Only increment phys if it doesn't describe
+ * a hole.
+ */
+ phys++;
+ }
+
+ desc->c_phys = phys;
+ if (phys == 0) {
+ desc->c_new = 1;
+ *clusters_to_alloc = *clusters_to_alloc + 1;
+ }
+ if (ext_flags & OCFS2_EXT_UNWRITTEN)
+ desc->c_unwritten = 1;
+
+ num_clusters--;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int ocfs2_write_begin_nolock(struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata,
+ struct buffer_head *di_bh, struct page *mmap_page)
{
int ret, credits = OCFS2_INODE_UPDATE_CREDITS;
- ssize_t written = 0;
- u32 phys;
- struct inode *inode = file->f_mapping->host;
+ unsigned int clusters_to_alloc, extents_to_split;
+ struct ocfs2_write_ctxt *wc;
+ struct inode *inode = mapping->host;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
- struct buffer_head *di_bh = NULL;
struct ocfs2_dinode *di;
struct ocfs2_alloc_context *data_ac = NULL;
struct ocfs2_alloc_context *meta_ac = NULL;
handle_t *handle;
- struct ocfs2_write_ctxt wc;
-
- ocfs2_write_ctxt_init(&wc, osb, pos, count, actor, priv);
- ret = ocfs2_meta_lock(inode, &di_bh, 1);
+ ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh);
if (ret) {
mlog_errno(ret);
- goto out;
+ return ret;
}
- di = (struct ocfs2_dinode *)di_bh->b_data;
-
- /*
- * Take alloc sem here to prevent concurrent lookups. That way
- * the mapping, zeroing and tree manipulation within
- * ocfs2_write() will be safe against ->readpage(). This
- * should also serve to lock out allocation from a shared
- * writeable region.
- */
- down_write(&OCFS2_I(inode)->ip_alloc_sem);
- ret = ocfs2_get_clusters(inode, wc.w_cpos, &phys, NULL, NULL);
+ ret = ocfs2_populate_write_desc(inode, wc, &clusters_to_alloc,
+ &extents_to_split);
if (ret) {
mlog_errno(ret);
- goto out_meta;
+ goto out;
}
- /* phys == 0 means that allocation is required. */
- if (phys == 0) {
- ret = ocfs2_lock_allocators(inode, di, 1, &data_ac, &meta_ac);
+ di = (struct ocfs2_dinode *)wc->w_di_bh->b_data;
+
+ /*
+ * We set w_target_from, w_target_to here so that
+ * ocfs2_write_end() knows which range in the target page to
+ * write out. An allocation requires that we write the entire
+ * cluster range.
+ */
+ if (clusters_to_alloc || extents_to_split) {
+ /*
+ * XXX: We are stretching the limits of
+ * ocfs2_lock_allocators(). It greatly over-estimates
+ * the work to be done.
+ */
+ ret = ocfs2_lock_allocators(inode, di, clusters_to_alloc,
+ extents_to_split, &data_ac, &meta_ac);
if (ret) {
mlog_errno(ret);
- goto out_meta;
+ goto out;
}
- credits = ocfs2_calc_extend_credits(inode->i_sb, di, 1);
- }
+ credits = ocfs2_calc_extend_credits(inode->i_sb, di,
+ clusters_to_alloc);
- ret = ocfs2_data_lock(inode, 1);
- if (ret) {
- mlog_errno(ret);
- goto out_meta;
}
+ ocfs2_set_target_boundaries(osb, wc, pos, len,
+ clusters_to_alloc + extents_to_split);
+
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
ret = PTR_ERR(handle);
mlog_errno(ret);
- goto out_data;
+ goto out;
}
- written = ocfs2_write(file, phys, handle, di_bh, data_ac,
- meta_ac, &wc);
- if (written < 0) {
- ret = written;
+ wc->w_handle = handle;
+
+ /*
+ * We don't want this to fail in ocfs2_write_end(), so do it
+ * here.
+ */
+ ret = ocfs2_journal_access(handle, inode, wc->w_di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
mlog_errno(ret);
goto out_commit;
}
- ret = ocfs2_journal_access(handle, inode, di_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
+ /*
+ * Fill our page array first. That way we've grabbed enough so
+ * that we can zero and flush if we error after adding the
+ * extent.
+ */
+ ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos,
+ clusters_to_alloc + extents_to_split,
+ mmap_page);
if (ret) {
mlog_errno(ret);
goto out_commit;
}
- pos += written;
+ ret = ocfs2_write_cluster_by_desc(mapping, data_ac, meta_ac, wc, pos,
+ len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ if (data_ac)
+ ocfs2_free_alloc_context(data_ac);
+ if (meta_ac)
+ ocfs2_free_alloc_context(meta_ac);
+
+ *pagep = wc->w_target_page;
+ *fsdata = wc;
+ return 0;
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+
+out:
+ ocfs2_free_write_ctxt(wc);
+
+ if (data_ac)
+ ocfs2_free_alloc_context(data_ac);
+ if (meta_ac)
+ ocfs2_free_alloc_context(meta_ac);
+ return ret;
+}
+
+int ocfs2_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
+{
+ int ret;
+ struct buffer_head *di_bh = NULL;
+ struct inode *inode = mapping->host;
+
+ ret = ocfs2_meta_lock(inode, &di_bh, 1);
+ if (ret) {
+ mlog_errno(ret);
+ return ret;
+ }
+
+ /*
+ * Take alloc sem here to prevent concurrent lookups. That way
+ * the mapping, zeroing and tree manipulation within
+ * ocfs2_write() will be safe against ->readpage(). This
+ * should also serve to lock out allocation from a shared
+ * writeable region.
+ */
+ down_write(&OCFS2_I(inode)->ip_alloc_sem);
+
+ ret = ocfs2_data_lock(inode, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_fail;
+ }
+
+ ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep,
+ fsdata, di_bh, NULL);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_fail_data;
+ }
+
+ brelse(di_bh);
+
+ return 0;
+
+out_fail_data:
+ ocfs2_data_unlock(inode, 1);
+out_fail:
+ up_write(&OCFS2_I(inode)->ip_alloc_sem);
+
+ brelse(di_bh);
+ ocfs2_meta_unlock(inode, 1);
+
+ return ret;
+}
+
+int ocfs2_write_end_nolock(struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
+{
+ int i;
+ unsigned from, to, start = pos & (PAGE_CACHE_SIZE - 1);
+ struct inode *inode = mapping->host;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_write_ctxt *wc = fsdata;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)wc->w_di_bh->b_data;
+ handle_t *handle = wc->w_handle;
+ struct page *tmppage;
+
+ if (unlikely(copied < len)) {
+ if (!PageUptodate(wc->w_target_page))
+ copied = 0;
+
+ ocfs2_zero_new_buffers(wc->w_target_page, start+copied,
+ start+len);
+ }
+ flush_dcache_page(wc->w_target_page);
+
+ for(i = 0; i < wc->w_num_pages; i++) {
+ tmppage = wc->w_pages[i];
+
+ if (tmppage == wc->w_target_page) {
+ from = wc->w_target_from;
+ to = wc->w_target_to;
+
+ BUG_ON(from > PAGE_CACHE_SIZE ||
+ to > PAGE_CACHE_SIZE ||
+ to < from);
+ } else {
+ /*
+ * Pages adjacent to the target (if any) imply
+ * a hole-filling write in which case we want
+ * to flush their entire range.
+ */
+ from = 0;
+ to = PAGE_CACHE_SIZE;
+ }
+
+ if (ocfs2_should_order_data(inode))
+ walk_page_buffers(wc->w_handle, page_buffers(tmppage),
+ from, to, NULL,
+ ocfs2_journal_dirty_data);
+
+ block_commit_write(tmppage, from, to);
+ }
+
+ pos += copied;
if (pos > inode->i_size) {
i_size_write(inode, pos);
mark_inode_dirty(inode);
@@ -1283,29 +1582,31 @@ ssize_t ocfs2_buffered_write_cluster(struct file *file, loff_t pos,
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
di->i_mtime = di->i_ctime = cpu_to_le64(inode->i_mtime.tv_sec);
di->i_mtime_nsec = di->i_ctime_nsec = cpu_to_le32(inode->i_mtime.tv_nsec);
+ ocfs2_journal_dirty(handle, wc->w_di_bh);
- ret = ocfs2_journal_dirty(handle, di_bh);
- if (ret)
- mlog_errno(ret);
-
-out_commit:
ocfs2_commit_trans(osb, handle);
-out_data:
- ocfs2_data_unlock(inode, 1);
+ ocfs2_run_deallocs(osb, &wc->w_dealloc);
+
+ ocfs2_free_write_ctxt(wc);
+
+ return copied;
+}
+
+int ocfs2_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
+{
+ int ret;
+ struct inode *inode = mapping->host;
-out_meta:
+ ret = ocfs2_write_end_nolock(mapping, pos, len, copied, page, fsdata);
+
+ ocfs2_data_unlock(inode, 1);
up_write(&OCFS2_I(inode)->ip_alloc_sem);
ocfs2_meta_unlock(inode, 1);
-out:
- brelse(di_bh);
- if (data_ac)
- ocfs2_free_alloc_context(data_ac);
- if (meta_ac)
- ocfs2_free_alloc_context(meta_ac);
-
- return written ? written : ret;
+ return ret;
}
const struct address_space_operations ocfs2_aops = {
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h
index 45821d479b5a..389579bd64e3 100644
--- a/fs/ocfs2/aops.h
+++ b/fs/ocfs2/aops.h
@@ -42,57 +42,22 @@ int walk_page_buffers( handle_t *handle,
int (*fn)( handle_t *handle,
struct buffer_head *bh));
-struct ocfs2_write_ctxt;
-typedef int (ocfs2_page_writer)(struct inode *, struct ocfs2_write_ctxt *,
- u64 *, unsigned int *, unsigned int *);
+int ocfs2_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata);
-ssize_t ocfs2_buffered_write_cluster(struct file *file, loff_t pos,
- size_t count, ocfs2_page_writer *actor,
- void *priv);
+int ocfs2_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata);
-struct ocfs2_write_ctxt {
- size_t w_count;
- loff_t w_pos;
- u32 w_cpos;
- unsigned int w_finished_copy;
+int ocfs2_write_end_nolock(struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata);
- /* This is true if page_size > cluster_size */
- unsigned int w_large_pages;
-
- /* Filler callback and private data */
- ocfs2_page_writer *w_write_data_page;
- void *w_private;
-
- /* Only valid for the filler callback */
- struct page *w_this_page;
- unsigned int w_this_page_new;
-};
-
-struct ocfs2_buffered_write_priv {
- char *b_src_buf;
- const struct iovec *b_cur_iov; /* Current iovec */
- size_t b_cur_off; /* Offset in the
- * current iovec */
-};
-int ocfs2_map_and_write_user_data(struct inode *inode,
- struct ocfs2_write_ctxt *wc,
- u64 *p_blkno,
- unsigned int *ret_from,
- unsigned int *ret_to);
-
-struct ocfs2_splice_write_priv {
- struct splice_desc *s_sd;
- struct pipe_buffer *s_buf;
- struct pipe_inode_info *s_pipe;
- /* Neither offset value is ever larger than one page */
- unsigned int s_offset;
- unsigned int s_buf_offset;
-};
-int ocfs2_map_and_write_splice_data(struct inode *inode,
- struct ocfs2_write_ctxt *wc,
- u64 *p_blkno,
- unsigned int *ret_from,
- unsigned int *ret_to);
+int ocfs2_write_begin_nolock(struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata,
+ struct buffer_head *di_bh, struct page *mmap_page);
/* all ocfs2_dio_end_io()'s fault */
#define ocfs2_iocb_is_rw_locked(iocb) \
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 979113479c66..2bd7f788cf34 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1335,6 +1335,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
ret = wait_event_interruptible(o2hb_steady_queue,
atomic_read(&reg->hr_steady_iterations) == 0);
if (ret) {
+ /* We got interrupted (hello ptrace!). Clean up */
spin_lock(&o2hb_live_lock);
hb_task = reg->hr_task;
reg->hr_task = NULL;
@@ -1345,7 +1346,16 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
goto out;
}
- ret = count;
+ /* Ok, we were woken. Make sure it wasn't by drop_item() */
+ spin_lock(&o2hb_live_lock);
+ hb_task = reg->hr_task;
+ spin_unlock(&o2hb_live_lock);
+
+ if (hb_task)
+ ret = count;
+ else
+ ret = -EIO;
+
out:
if (filp)
fput(filp);
@@ -1523,6 +1533,15 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
if (hb_task)
kthread_stop(hb_task);
+ /*
+ * If we're racing a dev_write(), we need to wake them. They will
+ * check reg->hr_task
+ */
+ if (atomic_read(&reg->hr_steady_iterations) != 0) {
+ atomic_set(&reg->hr_steady_iterations, 0);
+ wake_up(&o2hb_steady_queue);
+ }
+
config_item_put(item);
}
@@ -1665,7 +1684,67 @@ void o2hb_setup_callback(struct o2hb_callback_func *hc,
}
EXPORT_SYMBOL_GPL(o2hb_setup_callback);
-int o2hb_register_callback(struct o2hb_callback_func *hc)
+static struct o2hb_region *o2hb_find_region(const char *region_uuid)
+{
+ struct o2hb_region *p, *reg = NULL;
+
+ assert_spin_locked(&o2hb_live_lock);
+
+ list_for_each_entry(p, &o2hb_all_regions, hr_all_item) {
+ if (!strcmp(region_uuid, config_item_name(&p->hr_item))) {
+ reg = p;
+ break;
+ }
+ }
+
+ return reg;
+}
+
+static int o2hb_region_get(const char *region_uuid)
+{
+ int ret = 0;
+ struct o2hb_region *reg;
+
+ spin_lock(&o2hb_live_lock);
+
+ reg = o2hb_find_region(region_uuid);
+ if (!reg)
+ ret = -ENOENT;
+ spin_unlock(&o2hb_live_lock);
+
+ if (ret)
+ goto out;
+
+ ret = o2nm_depend_this_node();
+ if (ret)
+ goto out;
+
+ ret = o2nm_depend_item(&reg->hr_item);
+ if (ret)
+ o2nm_undepend_this_node();
+
+out:
+ return ret;
+}
+
+static void o2hb_region_put(const char *region_uuid)
+{
+ struct o2hb_region *reg;
+
+ spin_lock(&o2hb_live_lock);
+
+ reg = o2hb_find_region(region_uuid);
+
+ spin_unlock(&o2hb_live_lock);
+
+ if (reg) {
+ o2nm_undepend_item(&reg->hr_item);
+ o2nm_undepend_this_node();
+ }
+}
+
+int o2hb_register_callback(const char *region_uuid,
+ struct o2hb_callback_func *hc)
{
struct o2hb_callback_func *tmp;
struct list_head *iter;
@@ -1681,6 +1760,12 @@ int o2hb_register_callback(struct o2hb_callback_func *hc)
goto out;
}
+ if (region_uuid) {
+ ret = o2hb_region_get(region_uuid);
+ if (ret)
+ goto out;
+ }
+
down_write(&o2hb_callback_sem);
list_for_each(iter, &hbcall->list) {
@@ -1702,16 +1787,21 @@ out:
}
EXPORT_SYMBOL_GPL(o2hb_register_callback);
-void o2hb_unregister_callback(struct o2hb_callback_func *hc)
+void o2hb_unregister_callback(const char *region_uuid,
+ struct o2hb_callback_func *hc)
{
BUG_ON(hc->hc_magic != O2HB_CB_MAGIC);
mlog(ML_HEARTBEAT, "on behalf of %p for funcs %p\n",
__builtin_return_address(0), hc);
+ /* XXX Can this happen _with_ a region reference? */
if (list_empty(&hc->hc_item))
return;
+ if (region_uuid)
+ o2hb_region_put(region_uuid);
+
down_write(&o2hb_callback_sem);
list_del_init(&hc->hc_item);
diff --git a/fs/ocfs2/cluster/heartbeat.h b/fs/ocfs2/cluster/heartbeat.h
index cc6d40b39771..35397dd5ecdb 100644
--- a/fs/ocfs2/cluster/heartbeat.h
+++ b/fs/ocfs2/cluster/heartbeat.h
@@ -69,8 +69,10 @@ void o2hb_setup_callback(struct o2hb_callback_func *hc,
o2hb_cb_func *func,
void *data,
int priority);
-int o2hb_register_callback(struct o2hb_callback_func *hc);
-void o2hb_unregister_callback(struct o2hb_callback_func *hc);
+int o2hb_register_callback(const char *region_uuid,
+ struct o2hb_callback_func *hc);
+void o2hb_unregister_callback(const char *region_uuid,
+ struct o2hb_callback_func *hc);
void o2hb_fill_node_map(unsigned long *map,
unsigned bytes);
void o2hb_init(void);
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index 2b205f5d5790..e9e042b93dbf 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -74,7 +74,6 @@ struct mlog_attribute {
#define define_mask(_name) { \
.attr = { \
.name = #_name, \
- .owner = THIS_MODULE, \
.mode = S_IRUGO | S_IWUSR, \
}, \
.mask = ML_##_name, \
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index 9f5ad0f01ce0..af2070da308b 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -900,6 +900,46 @@ static struct o2nm_cluster_group o2nm_cluster_group = {
},
};
+int o2nm_depend_item(struct config_item *item)
+{
+ return configfs_depend_item(&o2nm_cluster_group.cs_subsys, item);
+}
+
+void o2nm_undepend_item(struct config_item *item)
+{
+ configfs_undepend_item(&o2nm_cluster_group.cs_subsys, item);
+}
+
+int o2nm_depend_this_node(void)
+{
+ int ret = 0;
+ struct o2nm_node *local_node;
+
+ local_node = o2nm_get_node_by_num(o2nm_this_node());
+ if (!local_node) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = o2nm_depend_item(&local_node->nd_item);
+ o2nm_node_put(local_node);
+
+out:
+ return ret;
+}
+
+void o2nm_undepend_this_node(void)
+{
+ struct o2nm_node *local_node;
+
+ local_node = o2nm_get_node_by_num(o2nm_this_node());
+ BUG_ON(!local_node);
+
+ o2nm_undepend_item(&local_node->nd_item);
+ o2nm_node_put(local_node);
+}
+
+
static void __exit exit_o2nm(void)
{
if (ocfs2_table_header)
@@ -934,7 +974,7 @@ static int __init init_o2nm(void)
goto out_sysctl;
config_group_init(&o2nm_cluster_group.cs_subsys.su_group);
- init_MUTEX(&o2nm_cluster_group.cs_subsys.su_sem);
+ mutex_init(&o2nm_cluster_group.cs_subsys.su_mutex);
ret = configfs_register_subsystem(&o2nm_cluster_group.cs_subsys);
if (ret) {
printk(KERN_ERR "nodemanager: Registration returned %d\n", ret);
diff --git a/fs/ocfs2/cluster/nodemanager.h b/fs/ocfs2/cluster/nodemanager.h
index 070522138ae2..7c860361b8dd 100644
--- a/fs/ocfs2/cluster/nodemanager.h
+++ b/fs/ocfs2/cluster/nodemanager.h
@@ -77,4 +77,9 @@ struct o2nm_node *o2nm_get_node_by_ip(__be32 addr);
void o2nm_node_get(struct o2nm_node *node);
void o2nm_node_put(struct o2nm_node *node);
+int o2nm_depend_item(struct config_item *item);
+void o2nm_undepend_item(struct config_item *item);
+int o2nm_depend_this_node(void);
+void o2nm_undepend_this_node(void);
+
#endif /* O2CLUSTER_NODEMANAGER_H */
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 0b229a9c7952..f0bdfd944c44 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -261,14 +261,12 @@ out:
static void o2net_complete_nodes_nsw(struct o2net_node *nn)
{
- struct list_head *iter, *tmp;
+ struct o2net_status_wait *nsw, *tmp;
unsigned int num_kills = 0;
- struct o2net_status_wait *nsw;
assert_spin_locked(&nn->nn_lock);
- list_for_each_safe(iter, tmp, &nn->nn_status_list) {
- nsw = list_entry(iter, struct o2net_status_wait, ns_node_item);
+ list_for_each_entry_safe(nsw, tmp, &nn->nn_status_list, ns_node_item) {
o2net_complete_nsw_locked(nn, nsw, O2NET_ERR_DIED, 0);
num_kills++;
}
@@ -764,13 +762,10 @@ EXPORT_SYMBOL_GPL(o2net_register_handler);
void o2net_unregister_handler_list(struct list_head *list)
{
- struct list_head *pos, *n;
- struct o2net_msg_handler *nmh;
+ struct o2net_msg_handler *nmh, *n;
write_lock(&o2net_handler_lock);
- list_for_each_safe(pos, n, list) {
- nmh = list_entry(pos, struct o2net_msg_handler,
- nh_unregister_item);
+ list_for_each_entry_safe(nmh, n, list, nh_unregister_item) {
mlog(ML_TCP, "unregistering handler func %p type %u key %08x\n",
nmh->nh_func, nmh->nh_msg_type, nmh->nh_key);
rb_erase(&nmh->nh_node, &o2net_handler_tree);
@@ -1638,8 +1633,8 @@ static void o2net_hb_node_up_cb(struct o2nm_node *node, int node_num,
void o2net_unregister_hb_callbacks(void)
{
- o2hb_unregister_callback(&o2net_hb_up);
- o2hb_unregister_callback(&o2net_hb_down);
+ o2hb_unregister_callback(NULL, &o2net_hb_up);
+ o2hb_unregister_callback(NULL, &o2net_hb_down);
}
int o2net_register_hb_callbacks(void)
@@ -1651,9 +1646,9 @@ int o2net_register_hb_callbacks(void)
o2hb_setup_callback(&o2net_hb_up, O2HB_NODE_UP_CB,
o2net_hb_node_up_cb, NULL, O2NET_HB_PRI);
- ret = o2hb_register_callback(&o2net_hb_up);
+ ret = o2hb_register_callback(NULL, &o2net_hb_up);
if (ret == 0)
- ret = o2hb_register_callback(&o2net_hb_down);
+ ret = o2hb_register_callback(NULL, &o2net_hb_down);
if (ret)
o2net_unregister_hb_callbacks();
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index c441ef1f2bad..0d5fdde959c8 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -368,7 +368,7 @@ int ocfs2_do_extend_dir(struct super_block *sb,
u32 offset = OCFS2_I(dir)->ip_clusters;
status = ocfs2_do_extend_allocation(OCFS2_SB(sb), dir, &offset,
- 1, parent_fe_bh, handle,
+ 1, 0, parent_fe_bh, handle,
data_ac, meta_ac, NULL);
BUG_ON(status == -EAGAIN);
if (status < 0) {
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index d836b98dd99a..6954565b8ccb 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -1128,8 +1128,8 @@ bail:
static void dlm_unregister_domain_handlers(struct dlm_ctxt *dlm)
{
- o2hb_unregister_callback(&dlm->dlm_hb_up);
- o2hb_unregister_callback(&dlm->dlm_hb_down);
+ o2hb_unregister_callback(NULL, &dlm->dlm_hb_up);
+ o2hb_unregister_callback(NULL, &dlm->dlm_hb_down);
o2net_unregister_handler_list(&dlm->dlm_domain_handlers);
}
@@ -1141,13 +1141,13 @@ static int dlm_register_domain_handlers(struct dlm_ctxt *dlm)
o2hb_setup_callback(&dlm->dlm_hb_down, O2HB_NODE_DOWN_CB,
dlm_hb_node_down_cb, dlm, DLM_HB_NODE_DOWN_PRI);
- status = o2hb_register_callback(&dlm->dlm_hb_down);
+ status = o2hb_register_callback(NULL, &dlm->dlm_hb_down);
if (status)
goto bail;
o2hb_setup_callback(&dlm->dlm_hb_up, O2HB_NODE_UP_CB,
dlm_hb_node_up_cb, dlm, DLM_HB_NODE_UP_PRI);
- status = o2hb_register_callback(&dlm->dlm_hb_up);
+ status = o2hb_register_callback(NULL, &dlm->dlm_hb_up);
if (status)
goto bail;
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index fd8cb1badc9b..7418dc83de1c 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -592,7 +592,7 @@ static int __init init_dlmfs_fs(void)
sizeof(struct dlmfs_inode_private),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- dlmfs_init_once, NULL);
+ dlmfs_init_once);
if (!dlmfs_inode_cache)
return -ENOMEM;
cleanup_inode = 1;
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 6edffca99d98..62e4a7daa286 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -192,25 +192,20 @@ static void dlm_print_one_mle(struct dlm_master_list_entry *mle)
static void dlm_dump_mles(struct dlm_ctxt *dlm)
{
struct dlm_master_list_entry *mle;
- struct list_head *iter;
mlog(ML_NOTICE, "dumping all mles for domain %s:\n", dlm->name);
spin_lock(&dlm->master_lock);
- list_for_each(iter, &dlm->master_list) {
- mle = list_entry(iter, struct dlm_master_list_entry, list);
+ list_for_each_entry(mle, &dlm->master_list, list)
dlm_print_one_mle(mle);
- }
spin_unlock(&dlm->master_lock);
}
int dlm_dump_all_mles(const char __user *data, unsigned int len)
{
- struct list_head *iter;
struct dlm_ctxt *dlm;
spin_lock(&dlm_domain_lock);
- list_for_each(iter, &dlm_domains) {
- dlm = list_entry (iter, struct dlm_ctxt, list);
+ list_for_each_entry(dlm, &dlm_domains, list) {
mlog(ML_NOTICE, "found dlm: %p, name=%s\n", dlm, dlm->name);
dlm_dump_mles(dlm);
}
@@ -454,12 +449,10 @@ static int dlm_find_mle(struct dlm_ctxt *dlm,
char *name, unsigned int namelen)
{
struct dlm_master_list_entry *tmpmle;
- struct list_head *iter;
assert_spin_locked(&dlm->master_lock);
- list_for_each(iter, &dlm->master_list) {
- tmpmle = list_entry(iter, struct dlm_master_list_entry, list);
+ list_for_each_entry(tmpmle, &dlm->master_list, list) {
if (!dlm_mle_equal(dlm, tmpmle, name, namelen))
continue;
dlm_get_mle(tmpmle);
@@ -472,13 +465,10 @@ static int dlm_find_mle(struct dlm_ctxt *dlm,
void dlm_hb_event_notify_attached(struct dlm_ctxt *dlm, int idx, int node_up)
{
struct dlm_master_list_entry *mle;
- struct list_head *iter;
assert_spin_locked(&dlm->spinlock);
- list_for_each(iter, &dlm->mle_hb_events) {
- mle = list_entry(iter, struct dlm_master_list_entry,
- hb_events);
+ list_for_each_entry(mle, &dlm->mle_hb_events, hb_events) {
if (node_up)
dlm_mle_node_up(dlm, mle, NULL, idx);
else
@@ -520,7 +510,7 @@ int dlm_init_mle_cache(void)
dlm_mle_cache = kmem_cache_create("dlm_mle_cache",
sizeof(struct dlm_master_list_entry),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (dlm_mle_cache == NULL)
return -ENOMEM;
return 0;
@@ -2434,7 +2424,7 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm,
int ret;
int i;
int count = 0;
- struct list_head *queue, *iter;
+ struct list_head *queue;
struct dlm_lock *lock;
assert_spin_locked(&res->spinlock);
@@ -2453,8 +2443,7 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm,
ret = 0;
queue = &res->granted;
for (i = 0; i < 3; i++) {
- list_for_each(iter, queue) {
- lock = list_entry(iter, struct dlm_lock, list);
+ list_for_each_entry(lock, queue, list) {
++count;
if (lock->ml.node == dlm->node_num) {
mlog(0, "found a lock owned by this node still "
@@ -2923,18 +2912,16 @@ again:
static void dlm_remove_nonlocal_locks(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res)
{
- struct list_head *iter, *iter2;
struct list_head *queue = &res->granted;
int i, bit;
- struct dlm_lock *lock;
+ struct dlm_lock *lock, *next;
assert_spin_locked(&res->spinlock);
BUG_ON(res->owner == dlm->node_num);
for (i=0; i<3; i++) {
- list_for_each_safe(iter, iter2, queue) {
- lock = list_entry (iter, struct dlm_lock, list);
+ list_for_each_entry_safe(lock, next, queue, list) {
if (lock->ml.node != dlm->node_num) {
mlog(0, "putting lock for node %u\n",
lock->ml.node);
@@ -2976,7 +2963,6 @@ static u8 dlm_pick_migration_target(struct dlm_ctxt *dlm,
{
int i;
struct list_head *queue = &res->granted;
- struct list_head *iter;
struct dlm_lock *lock;
int nodenum;
@@ -2984,10 +2970,9 @@ static u8 dlm_pick_migration_target(struct dlm_ctxt *dlm,
spin_lock(&res->spinlock);
for (i=0; i<3; i++) {
- list_for_each(iter, queue) {
+ list_for_each_entry(lock, queue, list) {
/* up to the caller to make sure this node
* is alive */
- lock = list_entry (iter, struct dlm_lock, list);
if (lock->ml.node != dlm->node_num) {
spin_unlock(&res->spinlock);
return lock->ml.node;
@@ -3234,8 +3219,7 @@ static int dlm_add_migration_mle(struct dlm_ctxt *dlm,
void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node)
{
- struct list_head *iter, *iter2;
- struct dlm_master_list_entry *mle;
+ struct dlm_master_list_entry *mle, *next;
struct dlm_lock_resource *res;
unsigned int hash;
@@ -3245,9 +3229,7 @@ top:
/* clean the master list */
spin_lock(&dlm->master_lock);
- list_for_each_safe(iter, iter2, &dlm->master_list) {
- mle = list_entry(iter, struct dlm_master_list_entry, list);
-
+ list_for_each_entry_safe(mle, next, &dlm->master_list, list) {
BUG_ON(mle->type != DLM_MLE_BLOCK &&
mle->type != DLM_MLE_MASTER &&
mle->type != DLM_MLE_MIGRATION);
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 671c4ed58ee2..a2c33160bfd6 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -158,8 +158,7 @@ void dlm_dispatch_work(struct work_struct *work)
struct dlm_ctxt *dlm =
container_of(work, struct dlm_ctxt, dispatched_work);
LIST_HEAD(tmp_list);
- struct list_head *iter, *iter2;
- struct dlm_work_item *item;
+ struct dlm_work_item *item, *next;
dlm_workfunc_t *workfunc;
int tot=0;
@@ -167,13 +166,12 @@ void dlm_dispatch_work(struct work_struct *work)
list_splice_init(&dlm->work_list, &tmp_list);
spin_unlock(&dlm->work_lock);
- list_for_each_safe(iter, iter2, &tmp_list) {
+ list_for_each_entry(item, &tmp_list, list) {
tot++;
}
mlog(0, "%s: work thread has %d work items\n", dlm->name, tot);
- list_for_each_safe(iter, iter2, &tmp_list) {
- item = list_entry(iter, struct dlm_work_item, list);
+ list_for_each_entry_safe(item, next, &tmp_list, list) {
workfunc = item->func;
list_del_init(&item->list);
@@ -549,7 +547,6 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
{
int status = 0;
struct dlm_reco_node_data *ndata;
- struct list_head *iter;
int all_nodes_done;
int destroy = 0;
int pass = 0;
@@ -567,8 +564,7 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
/* safe to access the node data list without a lock, since this
* process is the only one to change the list */
- list_for_each(iter, &dlm->reco.node_data) {
- ndata = list_entry (iter, struct dlm_reco_node_data, list);
+ list_for_each_entry(ndata, &dlm->reco.node_data, list) {
BUG_ON(ndata->state != DLM_RECO_NODE_DATA_INIT);
ndata->state = DLM_RECO_NODE_DATA_REQUESTING;
@@ -655,9 +651,7 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
* done, or if anyone died */
all_nodes_done = 1;
spin_lock(&dlm_reco_state_lock);
- list_for_each(iter, &dlm->reco.node_data) {
- ndata = list_entry (iter, struct dlm_reco_node_data, list);
-
+ list_for_each_entry(ndata, &dlm->reco.node_data, list) {
mlog(0, "checking recovery state of node %u\n",
ndata->node_num);
switch (ndata->state) {
@@ -774,16 +768,14 @@ static int dlm_init_recovery_area(struct dlm_ctxt *dlm, u8 dead_node)
static void dlm_destroy_recovery_area(struct dlm_ctxt *dlm, u8 dead_node)
{
- struct list_head *iter, *iter2;
- struct dlm_reco_node_data *ndata;
+ struct dlm_reco_node_data *ndata, *next;
LIST_HEAD(tmplist);
spin_lock(&dlm_reco_state_lock);
list_splice_init(&dlm->reco.node_data, &tmplist);
spin_unlock(&dlm_reco_state_lock);
- list_for_each_safe(iter, iter2, &tmplist) {
- ndata = list_entry (iter, struct dlm_reco_node_data, list);
+ list_for_each_entry_safe(ndata, next, &tmplist, list) {
list_del_init(&ndata->list);
kfree(ndata);
}
@@ -876,7 +868,6 @@ static void dlm_request_all_locks_worker(struct dlm_work_item *item, void *data)
struct dlm_lock_resource *res;
struct dlm_ctxt *dlm;
LIST_HEAD(resources);
- struct list_head *iter;
int ret;
u8 dead_node, reco_master;
int skip_all_done = 0;
@@ -920,8 +911,7 @@ static void dlm_request_all_locks_worker(struct dlm_work_item *item, void *data)
/* any errors returned will be due to the new_master dying,
* the dlm_reco_thread should detect this */
- list_for_each(iter, &resources) {
- res = list_entry (iter, struct dlm_lock_resource, recovering);
+ list_for_each_entry(res, &resources, recovering) {
ret = dlm_send_one_lockres(dlm, res, mres, reco_master,
DLM_MRES_RECOVERY);
if (ret < 0) {
@@ -983,7 +973,6 @@ int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data,
{
struct dlm_ctxt *dlm = data;
struct dlm_reco_data_done *done = (struct dlm_reco_data_done *)msg->buf;
- struct list_head *iter;
struct dlm_reco_node_data *ndata = NULL;
int ret = -EINVAL;
@@ -1000,8 +989,7 @@ int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data,
dlm->reco.dead_node, done->node_idx, dlm->node_num);
spin_lock(&dlm_reco_state_lock);
- list_for_each(iter, &dlm->reco.node_data) {
- ndata = list_entry (iter, struct dlm_reco_node_data, list);
+ list_for_each_entry(ndata, &dlm->reco.node_data, list) {
if (ndata->node_num != done->node_idx)
continue;
@@ -1049,13 +1037,11 @@ static void dlm_move_reco_locks_to_list(struct dlm_ctxt *dlm,
struct list_head *list,
u8 dead_node)
{
- struct dlm_lock_resource *res;
- struct list_head *iter, *iter2;
+ struct dlm_lock_resource *res, *next;
struct dlm_lock *lock;
spin_lock(&dlm->spinlock);
- list_for_each_safe(iter, iter2, &dlm->reco.resources) {
- res = list_entry (iter, struct dlm_lock_resource, recovering);
+ list_for_each_entry_safe(res, next, &dlm->reco.resources, recovering) {
/* always prune any $RECOVERY entries for dead nodes,
* otherwise hangs can occur during later recovery */
if (dlm_is_recovery_lock(res->lockname.name,
@@ -1169,7 +1155,7 @@ static void dlm_init_migratable_lockres(struct dlm_migratable_lockres *mres,
u8 flags, u8 master)
{
/* mres here is one full page */
- memset(mres, 0, PAGE_SIZE);
+ clear_page(mres);
mres->lockname_len = namelen;
memcpy(mres->lockname, lockname, namelen);
mres->num_locks = 0;
@@ -1252,7 +1238,7 @@ int dlm_send_one_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
struct dlm_migratable_lockres *mres,
u8 send_to, u8 flags)
{
- struct list_head *queue, *iter;
+ struct list_head *queue;
int total_locks, i;
u64 mig_cookie = 0;
struct dlm_lock *lock;
@@ -1278,9 +1264,7 @@ int dlm_send_one_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
total_locks = 0;
for (i=DLM_GRANTED_LIST; i<=DLM_BLOCKED_LIST; i++) {
queue = dlm_list_idx_to_ptr(res, i);
- list_for_each(iter, queue) {
- lock = list_entry (iter, struct dlm_lock, list);
-
+ list_for_each_entry(lock, queue, list) {
/* add another lock. */
total_locks++;
if (!dlm_add_lock_to_array(lock, mres, i))
@@ -1717,7 +1701,6 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
struct dlm_lockstatus *lksb = NULL;
int ret = 0;
int i, j, bad;
- struct list_head *iter;
struct dlm_lock *lock = NULL;
u8 from = O2NM_MAX_NODES;
unsigned int added = 0;
@@ -1755,8 +1738,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
spin_lock(&res->spinlock);
for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) {
tmpq = dlm_list_idx_to_ptr(res, j);
- list_for_each(iter, tmpq) {
- lock = list_entry (iter, struct dlm_lock, list);
+ list_for_each_entry(lock, tmpq, list) {
if (lock->ml.cookie != ml->cookie)
lock = NULL;
else
@@ -1930,8 +1912,8 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res)
{
int i;
- struct list_head *queue, *iter, *iter2;
- struct dlm_lock *lock;
+ struct list_head *queue;
+ struct dlm_lock *lock, *next;
res->state |= DLM_LOCK_RES_RECOVERING;
if (!list_empty(&res->recovering)) {
@@ -1947,8 +1929,7 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm,
/* find any pending locks and put them back on proper list */
for (i=DLM_BLOCKED_LIST; i>=DLM_GRANTED_LIST; i--) {
queue = dlm_list_idx_to_ptr(res, i);
- list_for_each_safe(iter, iter2, queue) {
- lock = list_entry (iter, struct dlm_lock, list);
+ list_for_each_entry_safe(lock, next, queue, list) {
dlm_lock_get(lock);
if (lock->convert_pending) {
/* move converting lock back to granted */
@@ -2013,18 +1994,15 @@ static void dlm_finish_local_lockres_recovery(struct dlm_ctxt *dlm,
u8 dead_node, u8 new_master)
{
int i;
- struct list_head *iter, *iter2;
struct hlist_node *hash_iter;
struct hlist_head *bucket;
-
- struct dlm_lock_resource *res;
+ struct dlm_lock_resource *res, *next;
mlog_entry_void();
assert_spin_locked(&dlm->spinlock);
- list_for_each_safe(iter, iter2, &dlm->reco.resources) {
- res = list_entry (iter, struct dlm_lock_resource, recovering);
+ list_for_each_entry_safe(res, next, &dlm->reco.resources, recovering) {
if (res->owner == dead_node) {
list_del_init(&res->recovering);
spin_lock(&res->spinlock);
@@ -2099,7 +2077,7 @@ static inline int dlm_lvb_needs_invalidation(struct dlm_lock *lock, int local)
static void dlm_revalidate_lvb(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res, u8 dead_node)
{
- struct list_head *iter, *queue;
+ struct list_head *queue;
struct dlm_lock *lock;
int blank_lvb = 0, local = 0;
int i;
@@ -2121,8 +2099,7 @@ static void dlm_revalidate_lvb(struct dlm_ctxt *dlm,
for (i=DLM_GRANTED_LIST; i<=DLM_CONVERTING_LIST; i++) {
queue = dlm_list_idx_to_ptr(res, i);
- list_for_each(iter, queue) {
- lock = list_entry (iter, struct dlm_lock, list);
+ list_for_each_entry(lock, queue, list) {
if (lock->ml.node == search_node) {
if (dlm_lvb_needs_invalidation(lock, local)) {
/* zero the lksb lvb and lockres lvb */
@@ -2143,8 +2120,7 @@ static void dlm_revalidate_lvb(struct dlm_ctxt *dlm,
static void dlm_free_dead_locks(struct dlm_ctxt *dlm,
struct dlm_lock_resource *res, u8 dead_node)
{
- struct list_head *iter, *tmpiter;
- struct dlm_lock *lock;
+ struct dlm_lock *lock, *next;
unsigned int freed = 0;
/* this node is the lockres master:
@@ -2155,24 +2131,21 @@ static void dlm_free_dead_locks(struct dlm_ctxt *dlm,
assert_spin_locked(&res->spinlock);
/* TODO: check pending_asts, pending_basts here */
- list_for_each_safe(iter, tmpiter, &res->granted) {
- lock = list_entry (iter, struct dlm_lock, list);
+ list_for_each_entry_safe(lock, next, &res->granted, list) {
if (lock->ml.node == dead_node) {
list_del_init(&lock->list);
dlm_lock_put(lock);
freed++;
}
}
- list_for_each_safe(iter, tmpiter, &res->converting) {
- lock = list_entry (iter, struct dlm_lock, list);
+ list_for_each_entry_safe(lock, next, &res->converting, list) {
if (lock->ml.node == dead_node) {
list_del_init(&lock->list);
dlm_lock_put(lock);
freed++;
}
}
- list_for_each_safe(iter, tmpiter, &res->blocked) {
- lock = list_entry (iter, struct dlm_lock, list);
+ list_for_each_entry_safe(lock, next, &res->blocked, list) {
if (lock->ml.node == dead_node) {
list_del_init(&lock->list);
dlm_lock_put(lock);
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index d1bd305ef0d7..f71250ed166f 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -600,15 +600,13 @@ static inline int ocfs2_highest_compat_lock_level(int level)
static void lockres_set_flags(struct ocfs2_lock_res *lockres,
unsigned long newflags)
{
- struct list_head *pos, *tmp;
- struct ocfs2_mask_waiter *mw;
+ struct ocfs2_mask_waiter *mw, *tmp;
assert_spin_locked(&lockres->l_lock);
lockres->l_flags = newflags;
- list_for_each_safe(pos, tmp, &lockres->l_mask_waiters) {
- mw = list_entry(pos, struct ocfs2_mask_waiter, mw_item);
+ list_for_each_entry_safe(mw, tmp, &lockres->l_mask_waiters, mw_item) {
if ((lockres->l_flags & mw->mw_mask) != mw->mw_goal)
continue;
diff --git a/fs/ocfs2/endian.h b/fs/ocfs2/endian.h
index f226b2207628..ff257628af16 100644
--- a/fs/ocfs2/endian.h
+++ b/fs/ocfs2/endian.h
@@ -32,6 +32,11 @@ static inline void le32_add_cpu(__le32 *var, u32 val)
*var = cpu_to_le32(le32_to_cpu(*var) + val);
}
+static inline void le64_add_cpu(__le64 *var, u64 val)
+{
+ *var = cpu_to_le64(le64_to_cpu(*var) + val);
+}
+
static inline void le32_and_cpu(__le32 *var, u32 val)
{
*var = cpu_to_le32(le32_to_cpu(*var) & val);
diff --git a/fs/ocfs2/export.h b/fs/ocfs2/export.h
index 5b77ee7866ef..e08bed9e45a0 100644
--- a/fs/ocfs2/export.h
+++ b/fs/ocfs2/export.h
@@ -26,6 +26,8 @@
#ifndef OCFS2_EXPORT_H
#define OCFS2_EXPORT_H
+#include <linux/exportfs.h>
+
extern struct export_operations ocfs2_export_ops;
#endif /* OCFS2_EXPORT_H */
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index ba2b2ab1c6e4..03c1d365c78b 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -109,17 +109,14 @@ static int ocfs2_extent_map_lookup(struct inode *inode, unsigned int cpos,
*/
void ocfs2_extent_map_trunc(struct inode *inode, unsigned int cpos)
{
- struct list_head *p, *n;
- struct ocfs2_extent_map_item *emi;
+ struct ocfs2_extent_map_item *emi, *n;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
struct ocfs2_extent_map *em = &oi->ip_extent_map;
LIST_HEAD(tmp_list);
unsigned int range;
spin_lock(&oi->ip_lock);
- list_for_each_safe(p, n, &em->em_list) {
- emi = list_entry(p, struct ocfs2_extent_map_item, ei_list);
-
+ list_for_each_entry_safe(emi, n, &em->em_list, ei_list) {
if (emi->ei_cpos >= cpos) {
/* Full truncate of this record. */
list_move(&emi->ei_list, &tmp_list);
@@ -136,8 +133,7 @@ void ocfs2_extent_map_trunc(struct inode *inode, unsigned int cpos)
}
spin_unlock(&oi->ip_lock);
- list_for_each_safe(p, n, &tmp_list) {
- emi = list_entry(p, struct ocfs2_extent_map_item, ei_list);
+ list_for_each_entry_safe(emi, n, &tmp_list, ei_list) {
list_del(&emi->ei_list);
kfree(emi);
}
@@ -377,37 +373,6 @@ out:
return ret;
}
-/*
- * Return the index of the extent record which contains cluster #v_cluster.
- * -1 is returned if it was not found.
- *
- * Should work fine on interior and exterior nodes.
- */
-static int ocfs2_search_extent_list(struct ocfs2_extent_list *el,
- u32 v_cluster)
-{
- int ret = -1;
- int i;
- struct ocfs2_extent_rec *rec;
- u32 rec_end, rec_start, clusters;
-
- for(i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
- rec = &el->l_recs[i];
-
- rec_start = le32_to_cpu(rec->e_cpos);
- clusters = ocfs2_rec_clusters(el, rec);
-
- rec_end = rec_start + clusters;
-
- if (v_cluster >= rec_start && v_cluster < rec_end) {
- ret = i;
- break;
- }
- }
-
- return ret;
-}
-
int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
u32 *p_cluster, u32 *num_clusters,
unsigned int *extent_flags)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 4979b6675717..5727cd18302a 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -34,6 +34,7 @@
#include <linux/splice.h>
#include <linux/mount.h>
#include <linux/writeback.h>
+#include <linux/falloc.h>
#define MLOG_MASK_PREFIX ML_INODE
#include <cluster/masklog.h>
@@ -263,6 +264,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
int status;
handle_t *handle;
struct ocfs2_dinode *di;
+ u64 cluster_bytes;
mlog_entry_void();
@@ -286,7 +288,9 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
/*
* Do this before setting i_size.
*/
- status = ocfs2_zero_tail_for_truncate(inode, handle, new_i_size);
+ cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size);
+ status = ocfs2_zero_range_for_truncate(inode, handle, new_i_size,
+ cluster_bytes);
if (status) {
mlog_errno(status);
goto out_commit;
@@ -326,9 +330,6 @@ static int ocfs2_truncate_file(struct inode *inode,
(unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)new_i_size);
- unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
- truncate_inode_pages(inode->i_mapping, new_i_size);
-
fe = (struct ocfs2_dinode *) di_bh->b_data;
if (!OCFS2_IS_VALID_DINODE(fe)) {
OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
@@ -363,16 +364,23 @@ static int ocfs2_truncate_file(struct inode *inode,
if (new_i_size == le64_to_cpu(fe->i_size))
goto bail;
+ down_write(&OCFS2_I(inode)->ip_alloc_sem);
+
/* This forces other nodes to sync and drop their pages. Do
* this even if we have a truncate without allocation change -
* ocfs2 cluster sizes can be much greater than page size, so
* we have to truncate them anyway. */
status = ocfs2_data_lock(inode, 1);
if (status < 0) {
+ up_write(&OCFS2_I(inode)->ip_alloc_sem);
+
mlog_errno(status);
goto bail;
}
+ unmap_mapping_range(inode->i_mapping, new_i_size + PAGE_SIZE - 1, 0, 1);
+ truncate_inode_pages(inode->i_mapping, new_i_size);
+
/* alright, we're going to need to do a full blown alloc size
* change. Orphan the inode so that recovery can complete the
* truncate if necessary. This does the task of marking
@@ -399,6 +407,8 @@ static int ocfs2_truncate_file(struct inode *inode,
bail_unlock_data:
ocfs2_data_unlock(inode, 1);
+ up_write(&OCFS2_I(inode)->ip_alloc_sem);
+
bail:
mlog_exit(status);
@@ -419,6 +429,7 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
struct inode *inode,
u32 *logical_offset,
u32 clusters_to_add,
+ int mark_unwritten,
struct buffer_head *fe_bh,
handle_t *handle,
struct ocfs2_alloc_context *data_ac,
@@ -431,9 +442,13 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
enum ocfs2_alloc_restarted reason = RESTART_NONE;
u32 bit_off, num_bits;
u64 block;
+ u8 flags = 0;
BUG_ON(!clusters_to_add);
+ if (mark_unwritten)
+ flags = OCFS2_EXT_UNWRITTEN;
+
free_extents = ocfs2_num_free_extents(osb, inode, fe);
if (free_extents < 0) {
status = free_extents;
@@ -483,7 +498,7 @@ int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
status = ocfs2_insert_extent(osb, handle, inode, fe_bh,
*logical_offset, block, num_bits,
- meta_ac);
+ flags, meta_ac);
if (status < 0) {
mlog_errno(status);
goto leave;
@@ -516,25 +531,31 @@ leave:
* For a given allocation, determine which allocators will need to be
* accessed, and lock them, reserving the appropriate number of bits.
*
- * Called from ocfs2_extend_allocation() for file systems which don't
- * support holes, and from ocfs2_write() for file systems which
- * understand sparse inodes.
+ * Sparse file systems call this from ocfs2_write_begin_nolock()
+ * and ocfs2_allocate_unwritten_extents().
+ *
+ * File systems which don't support holes call this from
+ * ocfs2_extend_allocation().
*/
int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
- u32 clusters_to_add,
+ u32 clusters_to_add, u32 extents_to_split,
struct ocfs2_alloc_context **data_ac,
struct ocfs2_alloc_context **meta_ac)
{
- int ret, num_free_extents;
+ int ret = 0, num_free_extents;
+ unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
*meta_ac = NULL;
- *data_ac = NULL;
+ if (data_ac)
+ *data_ac = NULL;
+
+ BUG_ON(clusters_to_add != 0 && data_ac == NULL);
mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
- "clusters_to_add = %u\n",
+ "clusters_to_add = %u, extents_to_split = %u\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode),
- le32_to_cpu(di->i_clusters), clusters_to_add);
+ le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split);
num_free_extents = ocfs2_num_free_extents(osb, inode, di);
if (num_free_extents < 0) {
@@ -552,9 +573,12 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
*
* Most of the time we'll only be seeing this 1 cluster at a time
* anyway.
+ *
+ * Always lock for any unwritten extents - we might want to
+ * add blocks during a split.
*/
if (!num_free_extents ||
- (ocfs2_sparse_alloc(osb) && num_free_extents < clusters_to_add)) {
+ (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
ret = ocfs2_reserve_new_metadata(osb, di, meta_ac);
if (ret < 0) {
if (ret != -ENOSPC)
@@ -563,6 +587,9 @@ int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
}
}
+ if (clusters_to_add == 0)
+ goto out;
+
ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
if (ret < 0) {
if (ret != -ENOSPC)
@@ -585,14 +612,13 @@ out:
return ret;
}
-static int ocfs2_extend_allocation(struct inode *inode,
- u32 clusters_to_add)
+static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
+ u32 clusters_to_add, int mark_unwritten)
{
int status = 0;
int restart_func = 0;
- int drop_alloc_sem = 0;
int credits;
- u32 prev_clusters, logical_start;
+ u32 prev_clusters;
struct buffer_head *bh = NULL;
struct ocfs2_dinode *fe = NULL;
handle_t *handle = NULL;
@@ -607,7 +633,7 @@ static int ocfs2_extend_allocation(struct inode *inode,
* This function only exists for file systems which don't
* support holes.
*/
- BUG_ON(ocfs2_sparse_alloc(osb));
+ BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb));
status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
OCFS2_BH_CACHED, inode);
@@ -623,19 +649,10 @@ static int ocfs2_extend_allocation(struct inode *inode,
goto leave;
}
- logical_start = OCFS2_I(inode)->ip_clusters;
-
restart_all:
BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
- /* blocks peope in read/write from reading our allocation
- * until we're done changing it. We depend on i_mutex to block
- * other extend/truncate calls while we're here. Ordering wrt
- * start_trans is important here -- always do it before! */
- down_write(&OCFS2_I(inode)->ip_alloc_sem);
- drop_alloc_sem = 1;
-
- status = ocfs2_lock_allocators(inode, fe, clusters_to_add, &data_ac,
+ status = ocfs2_lock_allocators(inode, fe, clusters_to_add, 0, &data_ac,
&meta_ac);
if (status) {
mlog_errno(status);
@@ -668,6 +685,7 @@ restarted_transaction:
inode,
&logical_start,
clusters_to_add,
+ mark_unwritten,
bh,
handle,
data_ac,
@@ -720,10 +738,6 @@ restarted_transaction:
OCFS2_I(inode)->ip_clusters, i_size_read(inode));
leave:
- if (drop_alloc_sem) {
- up_write(&OCFS2_I(inode)->ip_alloc_sem);
- drop_alloc_sem = 0;
- }
if (handle) {
ocfs2_commit_trans(osb, handle);
handle = NULL;
@@ -749,6 +763,25 @@ leave:
return status;
}
+static int ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
+ u32 clusters_to_add, int mark_unwritten)
+{
+ int ret;
+
+ /*
+ * The alloc sem blocks peope in read/write from reading our
+ * allocation until we're done changing it. We depend on
+ * i_mutex to block other extend/truncate calls while we're
+ * here.
+ */
+ down_write(&OCFS2_I(inode)->ip_alloc_sem);
+ ret = __ocfs2_extend_allocation(inode, logical_start, clusters_to_add,
+ mark_unwritten);
+ up_write(&OCFS2_I(inode)->ip_alloc_sem);
+
+ return ret;
+}
+
/* Some parts of this taken from generic_cont_expand, which turned out
* to be too fragile to do exactly what we need without us having to
* worry about recursive locking in ->prepare_write() and
@@ -890,7 +923,9 @@ static int ocfs2_extend_file(struct inode *inode,
}
if (clusters_to_add) {
- ret = ocfs2_extend_allocation(inode, clusters_to_add);
+ ret = ocfs2_extend_allocation(inode,
+ OCFS2_I(inode)->ip_clusters,
+ clusters_to_add, 0);
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
@@ -995,6 +1030,13 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
goto bail_unlock;
}
+ /*
+ * This will intentionally not wind up calling vmtruncate(),
+ * since all the work for a size change has been done above.
+ * Otherwise, we could get into problems with truncate as
+ * ip_alloc_sem is used there to protect against i_size
+ * changes.
+ */
status = inode_setattr(inode, attr);
if (status < 0) {
mlog_errno(status);
@@ -1070,17 +1112,16 @@ out:
return ret;
}
-static int ocfs2_write_remove_suid(struct inode *inode)
+static int __ocfs2_write_remove_suid(struct inode *inode,
+ struct buffer_head *bh)
{
int ret;
- struct buffer_head *bh = NULL;
- struct ocfs2_inode_info *oi = OCFS2_I(inode);
handle_t *handle;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct ocfs2_dinode *di;
mlog_entry("(Inode %llu, mode 0%o)\n",
- (unsigned long long)oi->ip_blkno, inode->i_mode);
+ (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_mode);
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (handle == NULL) {
@@ -1089,17 +1130,11 @@ static int ocfs2_write_remove_suid(struct inode *inode)
goto out;
}
- ret = ocfs2_read_block(osb, oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
- if (ret < 0) {
- mlog_errno(ret);
- goto out_trans;
- }
-
ret = ocfs2_journal_access(handle, inode, bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret < 0) {
mlog_errno(ret);
- goto out_bh;
+ goto out_trans;
}
inode->i_mode &= ~S_ISUID;
@@ -1112,8 +1147,7 @@ static int ocfs2_write_remove_suid(struct inode *inode)
ret = ocfs2_journal_dirty(handle, bh);
if (ret < 0)
mlog_errno(ret);
-out_bh:
- brelse(bh);
+
out_trans:
ocfs2_commit_trans(osb, handle);
out:
@@ -1159,6 +1193,499 @@ out:
return ret;
}
+static int ocfs2_write_remove_suid(struct inode *inode)
+{
+ int ret;
+ struct buffer_head *bh = NULL;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+
+ ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+ oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = __ocfs2_write_remove_suid(inode, bh);
+out:
+ brelse(bh);
+ return ret;
+}
+
+/*
+ * Allocate enough extents to cover the region starting at byte offset
+ * start for len bytes. Existing extents are skipped, any extents
+ * added are marked as "unwritten".
+ */
+static int ocfs2_allocate_unwritten_extents(struct inode *inode,
+ u64 start, u64 len)
+{
+ int ret;
+ u32 cpos, phys_cpos, clusters, alloc_size;
+
+ /*
+ * We consider both start and len to be inclusive.
+ */
+ cpos = start >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
+ clusters = ocfs2_clusters_for_bytes(inode->i_sb, start + len);
+ clusters -= cpos;
+
+ while (clusters) {
+ ret = ocfs2_get_clusters(inode, cpos, &phys_cpos,
+ &alloc_size, NULL);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * Hole or existing extent len can be arbitrary, so
+ * cap it to our own allocation request.
+ */
+ if (alloc_size > clusters)
+ alloc_size = clusters;
+
+ if (phys_cpos) {
+ /*
+ * We already have an allocation at this
+ * region so we can safely skip it.
+ */
+ goto next;
+ }
+
+ ret = __ocfs2_extend_allocation(inode, cpos, alloc_size, 1);
+ if (ret) {
+ if (ret != -ENOSPC)
+ mlog_errno(ret);
+ goto out;
+ }
+
+next:
+ cpos += alloc_size;
+ clusters -= alloc_size;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int __ocfs2_remove_inode_range(struct inode *inode,
+ struct buffer_head *di_bh,
+ u32 cpos, u32 phys_cpos, u32 len,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int ret;
+ u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct inode *tl_inode = osb->osb_tl_inode;
+ handle_t *handle;
+ struct ocfs2_alloc_context *meta_ac = NULL;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+
+ ret = ocfs2_lock_allocators(inode, di, 0, 1, NULL, &meta_ac);
+ if (ret) {
+ mlog_errno(ret);
+ return ret;
+ }
+
+ mutex_lock(&tl_inode->i_mutex);
+
+ if (ocfs2_truncate_log_needs_flush(osb)) {
+ ret = __ocfs2_flush_truncate_log(osb);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+ if (handle == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac,
+ dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ OCFS2_I(inode)->ip_clusters -= len;
+ di->i_clusters = cpu_to_le32(OCFS2_I(inode)->ip_clusters);
+
+ ret = ocfs2_journal_dirty(handle, di_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
+ if (ret)
+ mlog_errno(ret);
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+out:
+ mutex_unlock(&tl_inode->i_mutex);
+
+ if (meta_ac)
+ ocfs2_free_alloc_context(meta_ac);
+
+ return ret;
+}
+
+/*
+ * Truncate a byte range, avoiding pages within partial clusters. This
+ * preserves those pages for the zeroing code to write to.
+ */
+static void ocfs2_truncate_cluster_pages(struct inode *inode, u64 byte_start,
+ u64 byte_len)
+{
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ loff_t start, end;
+ struct address_space *mapping = inode->i_mapping;
+
+ start = (loff_t)ocfs2_align_bytes_to_clusters(inode->i_sb, byte_start);
+ end = byte_start + byte_len;
+ end = end & ~(osb->s_clustersize - 1);
+
+ if (start < end) {
+ unmap_mapping_range(mapping, start, end - start, 0);
+ truncate_inode_pages_range(mapping, start, end - 1);
+ }
+}
+
+static int ocfs2_zero_partial_clusters(struct inode *inode,
+ u64 start, u64 len)
+{
+ int ret = 0;
+ u64 tmpend, end = start + len;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ unsigned int csize = osb->s_clustersize;
+ handle_t *handle;
+
+ /*
+ * The "start" and "end" values are NOT necessarily part of
+ * the range whose allocation is being deleted. Rather, this
+ * is what the user passed in with the request. We must zero
+ * partial clusters here. There's no need to worry about
+ * physical allocation - the zeroing code knows to skip holes.
+ */
+ mlog(0, "byte start: %llu, end: %llu\n",
+ (unsigned long long)start, (unsigned long long)end);
+
+ /*
+ * If both edges are on a cluster boundary then there's no
+ * zeroing required as the region is part of the allocation to
+ * be truncated.
+ */
+ if ((start & (csize - 1)) == 0 && (end & (csize - 1)) == 0)
+ goto out;
+
+ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+ if (handle == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * We want to get the byte offset of the end of the 1st cluster.
+ */
+ tmpend = (u64)osb->s_clustersize + (start & ~(osb->s_clustersize - 1));
+ if (tmpend > end)
+ tmpend = end;
+
+ mlog(0, "1st range: start: %llu, tmpend: %llu\n",
+ (unsigned long long)start, (unsigned long long)tmpend);
+
+ ret = ocfs2_zero_range_for_truncate(inode, handle, start, tmpend);
+ if (ret)
+ mlog_errno(ret);
+
+ if (tmpend < end) {
+ /*
+ * This may make start and end equal, but the zeroing
+ * code will skip any work in that case so there's no
+ * need to catch it up here.
+ */
+ start = end & ~(osb->s_clustersize - 1);
+
+ mlog(0, "2nd range: start: %llu, end: %llu\n",
+ (unsigned long long)start, (unsigned long long)end);
+
+ ret = ocfs2_zero_range_for_truncate(inode, handle, start, end);
+ if (ret)
+ mlog_errno(ret);
+ }
+
+ ocfs2_commit_trans(osb, handle);
+out:
+ return ret;
+}
+
+static int ocfs2_remove_inode_range(struct inode *inode,
+ struct buffer_head *di_bh, u64 byte_start,
+ u64 byte_len)
+{
+ int ret = 0;
+ u32 trunc_start, trunc_len, cpos, phys_cpos, alloc_size;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_cached_dealloc_ctxt dealloc;
+
+ ocfs2_init_dealloc_ctxt(&dealloc);
+
+ if (byte_len == 0)
+ return 0;
+
+ trunc_start = ocfs2_clusters_for_bytes(osb->sb, byte_start);
+ trunc_len = (byte_start + byte_len) >> osb->s_clustersize_bits;
+ if (trunc_len >= trunc_start)
+ trunc_len -= trunc_start;
+ else
+ trunc_len = 0;
+
+ mlog(0, "Inode: %llu, start: %llu, len: %llu, cstart: %u, clen: %u\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ (unsigned long long)byte_start,
+ (unsigned long long)byte_len, trunc_start, trunc_len);
+
+ ret = ocfs2_zero_partial_clusters(inode, byte_start, byte_len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ cpos = trunc_start;
+ while (trunc_len) {
+ ret = ocfs2_get_clusters(inode, cpos, &phys_cpos,
+ &alloc_size, NULL);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (alloc_size > trunc_len)
+ alloc_size = trunc_len;
+
+ /* Only do work for non-holes */
+ if (phys_cpos != 0) {
+ ret = __ocfs2_remove_inode_range(inode, di_bh, cpos,
+ phys_cpos, alloc_size,
+ &dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ cpos += alloc_size;
+ trunc_len -= alloc_size;
+ }
+
+ ocfs2_truncate_cluster_pages(inode, byte_start, byte_len);
+
+out:
+ ocfs2_schedule_truncate_log_flush(osb, 1);
+ ocfs2_run_deallocs(osb, &dealloc);
+
+ return ret;
+}
+
+/*
+ * Parts of this function taken from xfs_change_file_space()
+ */
+static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+ loff_t f_pos, unsigned int cmd,
+ struct ocfs2_space_resv *sr,
+ int change_size)
+{
+ int ret;
+ s64 llen;
+ loff_t size;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct buffer_head *di_bh = NULL;
+ handle_t *handle;
+ unsigned long long max_off = ocfs2_max_file_offset(inode->i_sb->s_blocksize_bits);
+
+ if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
+ return -EROFS;
+
+ mutex_lock(&inode->i_mutex);
+
+ /*
+ * This prevents concurrent writes on other nodes
+ */
+ ret = ocfs2_rw_lock(inode, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_meta_lock(inode, &di_bh, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_rw_unlock;
+ }
+
+ if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
+ ret = -EPERM;
+ goto out_meta_unlock;
+ }
+
+ switch (sr->l_whence) {
+ case 0: /*SEEK_SET*/
+ break;
+ case 1: /*SEEK_CUR*/
+ sr->l_start += f_pos;
+ break;
+ case 2: /*SEEK_END*/
+ sr->l_start += i_size_read(inode);
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_meta_unlock;
+ }
+ sr->l_whence = 0;
+
+ llen = sr->l_len > 0 ? sr->l_len - 1 : sr->l_len;
+
+ if (sr->l_start < 0
+ || sr->l_start > max_off
+ || (sr->l_start + llen) < 0
+ || (sr->l_start + llen) > max_off) {
+ ret = -EINVAL;
+ goto out_meta_unlock;
+ }
+ size = sr->l_start + sr->l_len;
+
+ if (cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) {
+ if (sr->l_len <= 0) {
+ ret = -EINVAL;
+ goto out_meta_unlock;
+ }
+ }
+
+ if (file && should_remove_suid(file->f_path.dentry)) {
+ ret = __ocfs2_write_remove_suid(inode, di_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_meta_unlock;
+ }
+ }
+
+ down_write(&OCFS2_I(inode)->ip_alloc_sem);
+ switch (cmd) {
+ case OCFS2_IOC_RESVSP:
+ case OCFS2_IOC_RESVSP64:
+ /*
+ * This takes unsigned offsets, but the signed ones we
+ * pass have been checked against overflow above.
+ */
+ ret = ocfs2_allocate_unwritten_extents(inode, sr->l_start,
+ sr->l_len);
+ break;
+ case OCFS2_IOC_UNRESVSP:
+ case OCFS2_IOC_UNRESVSP64:
+ ret = ocfs2_remove_inode_range(inode, di_bh, sr->l_start,
+ sr->l_len);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ up_write(&OCFS2_I(inode)->ip_alloc_sem);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_meta_unlock;
+ }
+
+ /*
+ * We update c/mtime for these changes
+ */
+ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out_meta_unlock;
+ }
+
+ if (change_size && i_size_read(inode) < size)
+ i_size_write(inode, size);
+
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+ ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+
+ ocfs2_commit_trans(osb, handle);
+
+out_meta_unlock:
+ brelse(di_bh);
+ ocfs2_meta_unlock(inode, 1);
+out_rw_unlock:
+ ocfs2_rw_unlock(inode, 1);
+
+ mutex_unlock(&inode->i_mutex);
+out:
+ return ret;
+}
+
+int ocfs2_change_file_space(struct file *file, unsigned int cmd,
+ struct ocfs2_space_resv *sr)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);;
+
+ if ((cmd == OCFS2_IOC_RESVSP || cmd == OCFS2_IOC_RESVSP64) &&
+ !ocfs2_writes_unwritten_extents(osb))
+ return -ENOTTY;
+ else if ((cmd == OCFS2_IOC_UNRESVSP || cmd == OCFS2_IOC_UNRESVSP64) &&
+ !ocfs2_sparse_alloc(osb))
+ return -ENOTTY;
+
+ if (!S_ISREG(inode->i_mode))
+ return -EINVAL;
+
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EBADF;
+
+ return __ocfs2_change_file_space(file, inode, file->f_pos, cmd, sr, 0);
+}
+
+static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset,
+ loff_t len)
+{
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_space_resv sr;
+ int change_size = 1;
+
+ if (!ocfs2_writes_unwritten_extents(osb))
+ return -EOPNOTSUPP;
+
+ if (S_ISDIR(inode->i_mode))
+ return -ENODEV;
+
+ if (mode & FALLOC_FL_KEEP_SIZE)
+ change_size = 0;
+
+ sr.l_whence = 0;
+ sr.l_start = (s64)offset;
+ sr.l_len = (s64)len;
+
+ return __ocfs2_change_file_space(NULL, inode, offset,
+ OCFS2_IOC_RESVSP64, &sr, change_size);
+}
+
static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
loff_t *ppos,
size_t count,
@@ -1329,15 +1856,16 @@ ocfs2_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
*basep = base;
}
-static struct page * ocfs2_get_write_source(struct ocfs2_buffered_write_priv *bp,
+static struct page * ocfs2_get_write_source(char **ret_src_buf,
const struct iovec *cur_iov,
size_t iov_offset)
{
int ret;
- char *buf;
+ char *buf = cur_iov->iov_base + iov_offset;
struct page *src_page = NULL;
+ unsigned long off;
- buf = cur_iov->iov_base + iov_offset;
+ off = (unsigned long)(buf) & ~PAGE_CACHE_MASK;
if (!segment_eq(get_fs(), KERNEL_DS)) {
/*
@@ -1349,18 +1877,17 @@ static struct page * ocfs2_get_write_source(struct ocfs2_buffered_write_priv *bp
(unsigned long)buf & PAGE_CACHE_MASK, 1,
0, 0, &src_page, NULL);
if (ret == 1)
- bp->b_src_buf = kmap(src_page);
+ *ret_src_buf = kmap(src_page) + off;
else
src_page = ERR_PTR(-EFAULT);
} else {
- bp->b_src_buf = buf;
+ *ret_src_buf = buf;
}
return src_page;
}
-static void ocfs2_put_write_source(struct ocfs2_buffered_write_priv *bp,
- struct page *page)
+static void ocfs2_put_write_source(struct page *page)
{
if (page) {
kunmap(page);
@@ -1376,10 +1903,13 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos,
{
int ret = 0;
ssize_t copied, total = 0;
- size_t iov_offset = 0;
+ size_t iov_offset = 0, bytes;
+ loff_t pos;
const struct iovec *cur_iov = iov;
- struct ocfs2_buffered_write_priv bp;
- struct page *page;
+ struct page *user_page, *page;
+ char * uninitialized_var(buf);
+ char *dst;
+ void *fsdata;
/*
* handle partial DIO write. Adjust cur_iov if needed.
@@ -1387,21 +1917,38 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos,
ocfs2_set_next_iovec(&cur_iov, &iov_offset, o_direct_written);
do {
- bp.b_cur_off = iov_offset;
- bp.b_cur_iov = cur_iov;
+ pos = *ppos;
- page = ocfs2_get_write_source(&bp, cur_iov, iov_offset);
- if (IS_ERR(page)) {
- ret = PTR_ERR(page);
+ user_page = ocfs2_get_write_source(&buf, cur_iov, iov_offset);
+ if (IS_ERR(user_page)) {
+ ret = PTR_ERR(user_page);
goto out;
}
- copied = ocfs2_buffered_write_cluster(file, *ppos, count,
- ocfs2_map_and_write_user_data,
- &bp);
+ /* Stay within our page boundaries */
+ bytes = min((PAGE_CACHE_SIZE - ((unsigned long)pos & ~PAGE_CACHE_MASK)),
+ (PAGE_CACHE_SIZE - ((unsigned long)buf & ~PAGE_CACHE_MASK)));
+ /* Stay within the vector boundary */
+ bytes = min_t(size_t, bytes, cur_iov->iov_len - iov_offset);
+ /* Stay within count */
+ bytes = min(bytes, count);
+
+ page = NULL;
+ ret = ocfs2_write_begin(file, file->f_mapping, pos, bytes, 0,
+ &page, &fsdata);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
- ocfs2_put_write_source(&bp, page);
+ dst = kmap_atomic(page, KM_USER0);
+ memcpy(dst + (pos & (PAGE_CACHE_SIZE - 1)), buf, bytes);
+ kunmap_atomic(dst, KM_USER0);
+ flush_dcache_page(page);
+ ocfs2_put_write_source(user_page);
+ copied = ocfs2_write_end(file, file->f_mapping, pos, bytes,
+ bytes, page, fsdata);
if (copied < 0) {
mlog_errno(copied);
ret = copied;
@@ -1409,7 +1956,7 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos,
}
total += copied;
- *ppos = *ppos + copied;
+ *ppos = pos + copied;
count -= copied;
ocfs2_set_next_iovec(&cur_iov, &iov_offset, copied);
@@ -1579,52 +2126,46 @@ static int ocfs2_splice_write_actor(struct pipe_inode_info *pipe,
struct pipe_buffer *buf,
struct splice_desc *sd)
{
- int ret, count, total = 0;
+ int ret, count;
ssize_t copied = 0;
- struct ocfs2_splice_write_priv sp;
+ struct file *file = sd->u.file;
+ unsigned int offset;
+ struct page *page = NULL;
+ void *fsdata;
+ char *src, *dst;
ret = buf->ops->confirm(pipe, buf);
if (ret)
goto out;
- sp.s_sd = sd;
- sp.s_buf = buf;
- sp.s_pipe = pipe;
- sp.s_offset = sd->pos & ~PAGE_CACHE_MASK;
- sp.s_buf_offset = buf->offset;
-
+ offset = sd->pos & ~PAGE_CACHE_MASK;
count = sd->len;
- if (count + sp.s_offset > PAGE_CACHE_SIZE)
- count = PAGE_CACHE_SIZE - sp.s_offset;
+ if (count + offset > PAGE_CACHE_SIZE)
+ count = PAGE_CACHE_SIZE - offset;
- do {
- /*
- * splice wants us to copy up to one page at a
- * time. For pagesize > cluster size, this means we
- * might enter ocfs2_buffered_write_cluster() more
- * than once, so keep track of our progress here.
- */
- copied = ocfs2_buffered_write_cluster(sd->u.file,
- (loff_t)sd->pos + total,
- count,
- ocfs2_map_and_write_splice_data,
- &sp);
- if (copied < 0) {
- mlog_errno(copied);
- ret = copied;
- goto out;
- }
+ ret = ocfs2_write_begin(file, file->f_mapping, sd->pos, count, 0,
+ &page, &fsdata);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
- count -= copied;
- sp.s_offset += copied;
- sp.s_buf_offset += copied;
- total += copied;
- } while (count);
+ src = buf->ops->map(pipe, buf, 1);
+ dst = kmap_atomic(page, KM_USER1);
+ memcpy(dst + offset, src + buf->offset, count);
+ kunmap_atomic(page, KM_USER1);
+ buf->ops->unmap(pipe, buf, src);
- ret = 0;
+ copied = ocfs2_write_end(file, file->f_mapping, sd->pos, count, count,
+ page, fsdata);
+ if (copied < 0) {
+ mlog_errno(copied);
+ ret = copied;
+ goto out;
+ }
out:
- return total ? total : ret;
+ return copied ? copied : ret;
}
static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe,
@@ -1811,6 +2352,7 @@ const struct inode_operations ocfs2_file_iops = {
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
+ .fallocate = ocfs2_fallocate,
};
const struct inode_operations ocfs2_special_file_iops = {
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index a4dd1fa1822b..36fe27f268ee 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -39,15 +39,16 @@ enum ocfs2_alloc_restarted {
};
int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
struct inode *inode,
- u32 *cluster_start,
+ u32 *logical_offset,
u32 clusters_to_add,
+ int mark_unwritten,
struct buffer_head *fe_bh,
handle_t *handle,
struct ocfs2_alloc_context *data_ac,
struct ocfs2_alloc_context *meta_ac,
- enum ocfs2_alloc_restarted *reason);
+ enum ocfs2_alloc_restarted *reason_ret);
int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
- u32 clusters_to_add,
+ u32 clusters_to_add, u32 extents_to_split,
struct ocfs2_alloc_context **data_ac,
struct ocfs2_alloc_context **meta_ac);
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
@@ -61,4 +62,7 @@ int ocfs2_should_update_atime(struct inode *inode,
int ocfs2_update_inode_atime(struct inode *inode,
struct buffer_head *bh);
+int ocfs2_change_file_space(struct file *file, unsigned int cmd,
+ struct ocfs2_space_resv *sr);
+
#endif /* OCFS2_FILE_H */
diff --git a/fs/ocfs2/heartbeat.c b/fs/ocfs2/heartbeat.c
index b25ef63781ba..c4c36171240d 100644
--- a/fs/ocfs2/heartbeat.c
+++ b/fs/ocfs2/heartbeat.c
@@ -157,16 +157,16 @@ int ocfs2_register_hb_callbacks(struct ocfs2_super *osb)
if (ocfs2_mount_local(osb))
return 0;
- status = o2hb_register_callback(&osb->osb_hb_down);
+ status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_down);
if (status < 0) {
mlog_errno(status);
goto bail;
}
- status = o2hb_register_callback(&osb->osb_hb_up);
+ status = o2hb_register_callback(osb->uuid_str, &osb->osb_hb_up);
if (status < 0) {
mlog_errno(status);
- o2hb_unregister_callback(&osb->osb_hb_down);
+ o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
}
bail:
@@ -178,8 +178,8 @@ void ocfs2_clear_hb_callbacks(struct ocfs2_super *osb)
if (ocfs2_mount_local(osb))
return;
- o2hb_unregister_callback(&osb->osb_hb_down);
- o2hb_unregister_callback(&osb->osb_hb_up);
+ o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_down);
+ o2hb_unregister_callback(osb->uuid_str, &osb->osb_hb_up);
}
void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
@@ -209,7 +209,7 @@ void ocfs2_stop_heartbeat(struct ocfs2_super *osb)
envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[2] = NULL;
- ret = call_usermodehelper(argv[0], argv, envp, 1);
+ ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
if (ret < 0)
mlog_errno(ret);
}
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index f3ad21ad9aed..87dcece7e1b5 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -14,6 +14,7 @@
#include "ocfs2.h"
#include "alloc.h"
#include "dlmglue.h"
+#include "file.h"
#include "inode.h"
#include "journal.h"
@@ -62,7 +63,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags,
goto bail_unlock;
status = -EACCES;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
goto bail_unlock;
if (!S_ISDIR(inode->i_mode))
@@ -115,6 +116,7 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
{
unsigned int flags;
int status;
+ struct ocfs2_space_resv sr;
switch (cmd) {
case OCFS2_IOC_GETFLAGS:
@@ -130,6 +132,14 @@ int ocfs2_ioctl(struct inode * inode, struct file * filp,
return ocfs2_set_inode_attr(inode, flags,
OCFS2_FL_MODIFIABLE);
+ case OCFS2_IOC_RESVSP:
+ case OCFS2_IOC_RESVSP64:
+ case OCFS2_IOC_UNRESVSP:
+ case OCFS2_IOC_UNRESVSP64:
+ if (copy_from_user(&sr, (int __user *) arg, sizeof(sr)))
+ return -EFAULT;
+
+ return ocfs2_change_file_space(filp, cmd, &sr);
default:
return -ENOTTY;
}
@@ -148,6 +158,11 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case OCFS2_IOC32_SETFLAGS:
cmd = OCFS2_IOC_SETFLAGS;
break;
+ case OCFS2_IOC_RESVSP:
+ case OCFS2_IOC_RESVSP64:
+ case OCFS2_IOC_UNRESVSP:
+ case OCFS2_IOC_UNRESVSP64:
+ break;
default:
return -ENOIOCTLCMD;
}
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index dc1188081720..dbfb20bb27ea 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -722,8 +722,7 @@ void ocfs2_complete_recovery(struct work_struct *work)
container_of(work, struct ocfs2_journal, j_recovery_work);
struct ocfs2_super *osb = journal->j_osb;
struct ocfs2_dinode *la_dinode, *tl_dinode;
- struct ocfs2_la_recovery_item *item;
- struct list_head *p, *n;
+ struct ocfs2_la_recovery_item *item, *n;
LIST_HEAD(tmp_la_list);
mlog_entry_void();
@@ -734,8 +733,7 @@ void ocfs2_complete_recovery(struct work_struct *work)
list_splice_init(&journal->j_la_cleanups, &tmp_la_list);
spin_unlock(&journal->j_lock);
- list_for_each_safe(p, n, &tmp_la_list) {
- item = list_entry(p, struct ocfs2_la_recovery_item, lri_list);
+ list_for_each_entry_safe(item, n, &tmp_la_list, lri_list) {
list_del_init(&item->lri_list);
mlog(0, "Complete recovery for slot %d\n", item->lri_slot);
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 3db5de4506da..ce60aab013aa 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -289,6 +289,8 @@ int ocfs2_journal_dirty_data(handle_t *handle,
#define OCFS2_TRUNCATE_LOG_FLUSH_ONE_REC (OCFS2_SUBALLOC_FREE \
+ OCFS2_TRUNCATE_LOG_UPDATE)
+#define OCFS2_REMOVE_EXTENT_CREDITS (OCFS2_TRUNCATE_LOG_UPDATE + OCFS2_INODE_UPDATE_CREDITS)
+
/* data block for new dir/symlink, 2 for bitmap updates (bitmap fe +
* bitmap block for the new bit) */
#define OCFS2_DIR_LINK_ADDITIONAL_CREDITS (1 + 2)
diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
index af01158b39f5..98756156d298 100644
--- a/fs/ocfs2/mmap.c
+++ b/fs/ocfs2/mmap.c
@@ -37,66 +37,182 @@
#include "ocfs2.h"
+#include "aops.h"
#include "dlmglue.h"
#include "file.h"
#include "inode.h"
#include "mmap.h"
-static struct page *ocfs2_nopage(struct vm_area_struct * area,
- unsigned long address,
- int *type)
+static inline int ocfs2_vm_op_block_sigs(sigset_t *blocked, sigset_t *oldset)
+{
+ /* The best way to deal with signals in the vm path is
+ * to block them upfront, rather than allowing the
+ * locking paths to return -ERESTARTSYS. */
+ sigfillset(blocked);
+
+ /* We should technically never get a bad return value
+ * from sigprocmask */
+ return sigprocmask(SIG_BLOCK, blocked, oldset);
+}
+
+static inline int ocfs2_vm_op_unblock_sigs(sigset_t *oldset)
+{
+ return sigprocmask(SIG_SETMASK, oldset, NULL);
+}
+
+static int ocfs2_fault(struct vm_area_struct *area, struct vm_fault *vmf)
{
- struct page *page = NOPAGE_SIGBUS;
sigset_t blocked, oldset;
+ int error, ret;
+
+ mlog_entry("(area=%p, page offset=%lu)\n", area, vmf->pgoff);
+
+ error = ocfs2_vm_op_block_sigs(&blocked, &oldset);
+ if (error < 0) {
+ mlog_errno(error);
+ ret = VM_FAULT_SIGBUS;
+ goto out;
+ }
+
+ ret = filemap_fault(area, vmf);
+
+ error = ocfs2_vm_op_unblock_sigs(&oldset);
+ if (error < 0)
+ mlog_errno(error);
+out:
+ mlog_exit_ptr(vmf->page);
+ return ret;
+}
+
+static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
+ struct page *page)
+{
int ret;
+ struct address_space *mapping = inode->i_mapping;
+ loff_t pos = page_offset(page);
+ unsigned int len = PAGE_CACHE_SIZE;
+ pgoff_t last_index;
+ struct page *locked_page = NULL;
+ void *fsdata;
+ loff_t size = i_size_read(inode);
- mlog_entry("(area=%p, address=%lu, type=%p)\n", area, address,
- type);
+ /*
+ * Another node might have truncated while we were waiting on
+ * cluster locks.
+ */
+ last_index = size >> PAGE_CACHE_SHIFT;
+ if (page->index > last_index) {
+ ret = -EINVAL;
+ goto out;
+ }
- /* The best way to deal with signals in this path is
- * to block them upfront, rather than allowing the
- * locking paths to return -ERESTARTSYS. */
- sigfillset(&blocked);
+ /*
+ * The i_size check above doesn't catch the case where nodes
+ * truncated and then re-extended the file. We'll re-check the
+ * page mapping after taking the page lock inside of
+ * ocfs2_write_begin_nolock().
+ */
+ if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
+ ret = -EINVAL;
+ goto out;
+ }
- /* We should technically never get a bad ret return
- * from sigprocmask */
- ret = sigprocmask(SIG_BLOCK, &blocked, &oldset);
+ /*
+ * Call ocfs2_write_begin() and ocfs2_write_end() to take
+ * advantage of the allocation code there. We pass a write
+ * length of the whole page (chopped to i_size) to make sure
+ * the whole thing is allocated.
+ *
+ * Since we know the page is up to date, we don't have to
+ * worry about ocfs2_write_begin() skipping some buffer reads
+ * because the "write" would invalidate their data.
+ */
+ if (page->index == last_index)
+ len = size & ~PAGE_CACHE_MASK;
+
+ ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page,
+ &fsdata, di_bh, page);
+ if (ret) {
+ if (ret != -ENOSPC)
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_write_end_nolock(mapping, pos, len, len, locked_page,
+ fsdata);
if (ret < 0) {
mlog_errno(ret);
goto out;
}
+ BUG_ON(ret != len);
+ ret = 0;
+out:
+ return ret;
+}
- page = filemap_nopage(area, address, type);
+static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
+ struct buffer_head *di_bh = NULL;
+ sigset_t blocked, oldset;
+ int ret, ret2;
- ret = sigprocmask(SIG_SETMASK, &oldset, NULL);
- if (ret < 0)
+ ret = ocfs2_vm_op_block_sigs(&blocked, &oldset);
+ if (ret < 0) {
mlog_errno(ret);
+ return ret;
+ }
+
+ /*
+ * The cluster locks taken will block a truncate from another
+ * node. Taking the data lock will also ensure that we don't
+ * attempt page truncation as part of a downconvert.
+ */
+ ret = ocfs2_meta_lock(inode, &di_bh, 1);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * The alloc sem should be enough to serialize with
+ * ocfs2_truncate_file() changing i_size as well as any thread
+ * modifying the inode btree.
+ */
+ down_write(&OCFS2_I(inode)->ip_alloc_sem);
+
+ ret = ocfs2_data_lock(inode, 1);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_meta_unlock;
+ }
+
+ ret = __ocfs2_page_mkwrite(inode, di_bh, page);
+
+ ocfs2_data_unlock(inode, 1);
+
+out_meta_unlock:
+ up_write(&OCFS2_I(inode)->ip_alloc_sem);
+
+ brelse(di_bh);
+ ocfs2_meta_unlock(inode, 1);
+
out:
- mlog_exit_ptr(page);
- return page;
+ ret2 = ocfs2_vm_op_unblock_sigs(&oldset);
+ if (ret2 < 0)
+ mlog_errno(ret2);
+
+ return ret;
}
static struct vm_operations_struct ocfs2_file_vm_ops = {
- .nopage = ocfs2_nopage,
+ .fault = ocfs2_fault,
+ .page_mkwrite = ocfs2_page_mkwrite,
};
int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
{
int ret = 0, lock_level = 0;
- struct ocfs2_super *osb = OCFS2_SB(file->f_dentry->d_inode->i_sb);
-
- /*
- * Only support shared writeable mmap for local mounts which
- * don't know about holes.
- */
- if ((!ocfs2_mount_local(osb) || ocfs2_sparse_alloc(osb)) &&
- ((vma->vm_flags & VM_SHARED) || (vma->vm_flags & VM_MAYSHARE)) &&
- ((vma->vm_flags & VM_WRITE) || (vma->vm_flags & VM_MAYWRITE))) {
- mlog(0, "disallow shared writable mmaps %lx\n", vma->vm_flags);
- /* This is -EINVAL because generic_file_readonly_mmap
- * returns it in a similar situation. */
- return -EINVAL;
- }
ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode,
file->f_vfsmnt, &lock_level);
@@ -107,6 +223,7 @@ int ocfs2_mmap(struct file *file, struct vm_area_struct *vma)
ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level);
out:
vma->vm_ops = &ocfs2_file_vm_ops;
+ vma->vm_flags |= VM_CAN_NONLINEAR;
return 0;
}
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 36289e6295ce..d430fdab16e9 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -1674,7 +1674,7 @@ static int ocfs2_symlink(struct inode *dir,
u32 offset = 0;
inode->i_op = &ocfs2_symlink_inode_operations;
- status = ocfs2_do_extend_allocation(osb, inode, &offset, 1,
+ status = ocfs2_do_extend_allocation(osb, inode, &offset, 1, 0,
new_fe_bh,
handle, data_ac, NULL,
NULL);
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index a860633e833f..5cc90a40b3c5 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -219,6 +219,7 @@ struct ocfs2_super
u16 max_slots;
s16 node_num;
s16 slot_num;
+ s16 preferred_slot;
int s_sectsize_bits;
int s_clustersize;
int s_clustersize_bits;
@@ -305,6 +306,19 @@ static inline int ocfs2_sparse_alloc(struct ocfs2_super *osb)
return 0;
}
+static inline int ocfs2_writes_unwritten_extents(struct ocfs2_super *osb)
+{
+ /*
+ * Support for sparse files is a pre-requisite
+ */
+ if (!ocfs2_sparse_alloc(osb))
+ return 0;
+
+ if (osb->s_feature_ro_compat & OCFS2_FEATURE_RO_COMPAT_UNWRITTEN)
+ return 1;
+ return 0;
+}
+
/* set / clear functions because cluster events can make these happen
* in parallel so we want the transitions to be atomic. this also
* means that any future flags osb_flags must be protected by spinlock
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index f0d9eb08547a..82f8a75b207e 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -88,7 +88,7 @@
#define OCFS2_FEATURE_COMPAT_SUPP OCFS2_FEATURE_COMPAT_BACKUP_SB
#define OCFS2_FEATURE_INCOMPAT_SUPP (OCFS2_FEATURE_INCOMPAT_LOCAL_MOUNT \
| OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC)
-#define OCFS2_FEATURE_RO_COMPAT_SUPP 0
+#define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
/*
* Heartbeat-only devices are missing journals and other files. The
@@ -116,6 +116,11 @@
*/
#define OCFS2_FEATURE_COMPAT_BACKUP_SB 0x0001
+/*
+ * Unwritten extents support.
+ */
+#define OCFS2_FEATURE_RO_COMPAT_UNWRITTEN 0x0001
+
/* The byte offset of the first backup block will be 1G.
* The following will be 4G, 16G, 64G, 256G and 1T.
*/
@@ -170,6 +175,32 @@
#define OCFS2_IOC32_SETFLAGS _IOW('f', 2, int)
/*
+ * Space reservation / allocation / free ioctls and argument structure
+ * are designed to be compatible with XFS.
+ *
+ * ALLOCSP* and FREESP* are not and will never be supported, but are
+ * included here for completeness.
+ */
+struct ocfs2_space_resv {
+ __s16 l_type;
+ __s16 l_whence;
+ __s64 l_start;
+ __s64 l_len; /* len == 0 means until end of file */
+ __s32 l_sysid;
+ __u32 l_pid;
+ __s32 l_pad[4]; /* reserve area */
+};
+
+#define OCFS2_IOC_ALLOCSP _IOW ('X', 10, struct ocfs2_space_resv)
+#define OCFS2_IOC_FREESP _IOW ('X', 11, struct ocfs2_space_resv)
+#define OCFS2_IOC_RESVSP _IOW ('X', 40, struct ocfs2_space_resv)
+#define OCFS2_IOC_UNRESVSP _IOW ('X', 41, struct ocfs2_space_resv)
+#define OCFS2_IOC_ALLOCSP64 _IOW ('X', 36, struct ocfs2_space_resv)
+#define OCFS2_IOC_FREESP64 _IOW ('X', 37, struct ocfs2_space_resv)
+#define OCFS2_IOC_RESVSP64 _IOW ('X', 42, struct ocfs2_space_resv)
+#define OCFS2_IOC_UNRESVSP64 _IOW ('X', 43, struct ocfs2_space_resv)
+
+/*
* Journal Flags (ocfs2_dinode.id1.journal1.i_flags)
*/
#define OCFS2_JOURNAL_DIRTY_FL (0x00000001) /* Journal needs recovery */
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index d8b79067dc14..af4882b62cfa 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -121,17 +121,25 @@ static s16 __ocfs2_node_num_to_slot(struct ocfs2_slot_info *si,
return ret;
}
-static s16 __ocfs2_find_empty_slot(struct ocfs2_slot_info *si)
+static s16 __ocfs2_find_empty_slot(struct ocfs2_slot_info *si, s16 preferred)
{
int i;
s16 ret = OCFS2_INVALID_SLOT;
+ if (preferred >= 0 && preferred < si->si_num_slots) {
+ if (OCFS2_INVALID_SLOT == si->si_global_node_nums[preferred]) {
+ ret = preferred;
+ goto out;
+ }
+ }
+
for(i = 0; i < si->si_num_slots; i++) {
if (OCFS2_INVALID_SLOT == si->si_global_node_nums[i]) {
ret = (s16) i;
break;
}
}
+out:
return ret;
}
@@ -248,7 +256,7 @@ int ocfs2_find_slot(struct ocfs2_super *osb)
if (slot == OCFS2_INVALID_SLOT) {
/* if no slot yet, then just take 1st available
* one. */
- slot = __ocfs2_find_empty_slot(si);
+ slot = __ocfs2_find_empty_slot(si, osb->preferred_slot);
if (slot == OCFS2_INVALID_SLOT) {
spin_unlock(&si->si_lock);
mlog(ML_ERROR, "no free slots available!\n");
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index e3437626d183..d9c5c9fcb30f 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -98,14 +98,6 @@ static int ocfs2_relink_block_group(handle_t *handle,
u16 chain);
static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg,
u32 wanted);
-static int ocfs2_free_suballoc_bits(handle_t *handle,
- struct inode *alloc_inode,
- struct buffer_head *alloc_bh,
- unsigned int start_bit,
- u64 bg_blkno,
- unsigned int count);
-static inline u64 ocfs2_which_suballoc_group(u64 block,
- unsigned int bit);
static inline u32 ocfs2_desc_bitmap_to_cluster_off(struct inode *inode,
u64 bg_blkno,
u16 bg_bit_off);
@@ -496,13 +488,7 @@ int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
(*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(fe);
(*ac)->ac_which = OCFS2_AC_USE_META;
-
-#ifndef OCFS2_USE_ALL_METADATA_SUBALLOCATORS
- slot = 0;
-#else
slot = osb->slot_num;
-#endif
-
(*ac)->ac_group_search = ocfs2_block_group_search;
status = ocfs2_reserve_suballoc_bits(osb, (*ac),
@@ -1626,12 +1612,12 @@ bail:
/*
* expects the suballoc inode to already be locked.
*/
-static int ocfs2_free_suballoc_bits(handle_t *handle,
- struct inode *alloc_inode,
- struct buffer_head *alloc_bh,
- unsigned int start_bit,
- u64 bg_blkno,
- unsigned int count)
+int ocfs2_free_suballoc_bits(handle_t *handle,
+ struct inode *alloc_inode,
+ struct buffer_head *alloc_bh,
+ unsigned int start_bit,
+ u64 bg_blkno,
+ unsigned int count)
{
int status = 0;
u32 tmp_used;
@@ -1703,13 +1689,6 @@ bail:
return status;
}
-static inline u64 ocfs2_which_suballoc_group(u64 block, unsigned int bit)
-{
- u64 group = block - (u64) bit;
-
- return group;
-}
-
int ocfs2_free_dinode(handle_t *handle,
struct inode *inode_alloc_inode,
struct buffer_head *inode_alloc_bh,
@@ -1723,19 +1702,6 @@ int ocfs2_free_dinode(handle_t *handle,
inode_alloc_bh, bit, bg_blkno, 1);
}
-int ocfs2_free_extent_block(handle_t *handle,
- struct inode *eb_alloc_inode,
- struct buffer_head *eb_alloc_bh,
- struct ocfs2_extent_block *eb)
-{
- u64 blk = le64_to_cpu(eb->h_blkno);
- u16 bit = le16_to_cpu(eb->h_suballoc_bit);
- u64 bg_blkno = ocfs2_which_suballoc_group(blk, bit);
-
- return ocfs2_free_suballoc_bits(handle, eb_alloc_inode, eb_alloc_bh,
- bit, bg_blkno, 1);
-}
-
int ocfs2_free_clusters(handle_t *handle,
struct inode *bitmap_inode,
struct buffer_head *bitmap_bh,
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h
index 1a3c94cb9250..f212dc01a84b 100644
--- a/fs/ocfs2/suballoc.h
+++ b/fs/ocfs2/suballoc.h
@@ -86,20 +86,29 @@ int ocfs2_claim_clusters(struct ocfs2_super *osb,
u32 *cluster_start,
u32 *num_clusters);
+int ocfs2_free_suballoc_bits(handle_t *handle,
+ struct inode *alloc_inode,
+ struct buffer_head *alloc_bh,
+ unsigned int start_bit,
+ u64 bg_blkno,
+ unsigned int count);
int ocfs2_free_dinode(handle_t *handle,
struct inode *inode_alloc_inode,
struct buffer_head *inode_alloc_bh,
struct ocfs2_dinode *di);
-int ocfs2_free_extent_block(handle_t *handle,
- struct inode *eb_alloc_inode,
- struct buffer_head *eb_alloc_bh,
- struct ocfs2_extent_block *eb);
int ocfs2_free_clusters(handle_t *handle,
struct inode *bitmap_inode,
struct buffer_head *bitmap_bh,
u64 start_blk,
unsigned int num_clusters);
+static inline u64 ocfs2_which_suballoc_group(u64 block, unsigned int bit)
+{
+ u64 group = block - (u64) bit;
+
+ return group;
+}
+
static inline u32 ocfs2_cluster_from_desc(struct ocfs2_super *osb,
u64 bg_blkno)
{
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 86b559c7dce9..200c7d4790dc 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -82,7 +82,8 @@ MODULE_AUTHOR("Oracle");
MODULE_LICENSE("GPL");
static int ocfs2_parse_options(struct super_block *sb, char *options,
- unsigned long *mount_opt, int is_remount);
+ unsigned long *mount_opt, s16 *slot,
+ int is_remount);
static void ocfs2_put_super(struct super_block *sb);
static int ocfs2_mount_volume(struct super_block *sb);
static int ocfs2_remount(struct super_block *sb, int *flags, char *data);
@@ -114,8 +115,6 @@ static void ocfs2_write_super(struct super_block *sb);
static struct inode *ocfs2_alloc_inode(struct super_block *sb);
static void ocfs2_destroy_inode(struct inode *inode);
-static unsigned long long ocfs2_max_file_offset(unsigned int blockshift);
-
static const struct super_operations ocfs2_sops = {
.statfs = ocfs2_statfs,
.alloc_inode = ocfs2_alloc_inode,
@@ -140,6 +139,7 @@ enum {
Opt_data_ordered,
Opt_data_writeback,
Opt_atime_quantum,
+ Opt_slot,
Opt_err,
};
@@ -154,6 +154,7 @@ static match_table_t tokens = {
{Opt_data_ordered, "data=ordered"},
{Opt_data_writeback, "data=writeback"},
{Opt_atime_quantum, "atime_quantum=%u"},
+ {Opt_slot, "preferred_slot=%u"},
{Opt_err, NULL}
};
@@ -318,7 +319,7 @@ static void ocfs2_destroy_inode(struct inode *inode)
/* From xfs_super.c:xfs_max_file_offset
* Copyright (c) 2000-2004 Silicon Graphics, Inc.
*/
-static unsigned long long ocfs2_max_file_offset(unsigned int blockshift)
+unsigned long long ocfs2_max_file_offset(unsigned int blockshift)
{
unsigned int pagefactor = 1;
unsigned int bitshift = BITS_PER_LONG - 1;
@@ -355,9 +356,10 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
int incompat_features;
int ret = 0;
unsigned long parsed_options;
+ s16 slot;
struct ocfs2_super *osb = OCFS2_SB(sb);
- if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) {
+ if (!ocfs2_parse_options(sb, data, &parsed_options, &slot, 1)) {
ret = -EINVAL;
goto out;
}
@@ -534,6 +536,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
struct dentry *root;
int status, sector_size;
unsigned long parsed_opt;
+ s16 slot;
struct inode *inode = NULL;
struct ocfs2_super *osb = NULL;
struct buffer_head *bh = NULL;
@@ -541,7 +544,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
mlog_entry("%p, %p, %i", sb, data, silent);
- if (!ocfs2_parse_options(sb, data, &parsed_opt, 0)) {
+ if (!ocfs2_parse_options(sb, data, &parsed_opt, &slot, 0)) {
status = -EINVAL;
goto read_super_error;
}
@@ -571,6 +574,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
brelse(bh);
bh = NULL;
osb->s_mount_opt = parsed_opt;
+ osb->preferred_slot = slot;
sb->s_magic = OCFS2_SUPER_MAGIC;
@@ -713,6 +717,7 @@ static struct file_system_type ocfs2_fs_type = {
static int ocfs2_parse_options(struct super_block *sb,
char *options,
unsigned long *mount_opt,
+ s16 *slot,
int is_remount)
{
int status;
@@ -722,6 +727,7 @@ static int ocfs2_parse_options(struct super_block *sb,
options ? options : "(none)");
*mount_opt = 0;
+ *slot = OCFS2_INVALID_SLOT;
if (!options) {
status = 1;
@@ -782,6 +788,15 @@ static int ocfs2_parse_options(struct super_block *sb,
else
osb->s_atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM;
break;
+ case Opt_slot:
+ option = 0;
+ if (match_int(&args[0], &option)) {
+ status = 0;
+ goto bail;
+ }
+ if (option)
+ *slot = (s16)option;
+ break;
default:
mlog(ML_ERROR,
"Unrecognized mount option \"%s\" "
@@ -969,7 +984,7 @@ static int ocfs2_initialize_mem_caches(void)
0,
(SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- ocfs2_inode_init_once, NULL);
+ ocfs2_inode_init_once);
if (!ocfs2_inode_cachep)
return -ENOMEM;
diff --git a/fs/ocfs2/super.h b/fs/ocfs2/super.h
index 783f5270f2a1..3b9cb3d0b008 100644
--- a/fs/ocfs2/super.h
+++ b/fs/ocfs2/super.h
@@ -45,4 +45,6 @@ void __ocfs2_abort(struct super_block *sb,
#define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##args)
+unsigned long long ocfs2_max_file_offset(unsigned int blockshift);
+
#endif /* OCFS2_SUPER_H */
diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c
index 39814b900fc0..4da8851f2b23 100644
--- a/fs/ocfs2/uptodate.c
+++ b/fs/ocfs2/uptodate.c
@@ -548,7 +548,7 @@ int __init init_ocfs2_uptodate_cache(void)
{
ocfs2_uptodate_cachep = kmem_cache_create("ocfs2_uptodate",
sizeof(struct ocfs2_meta_cache_item),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (!ocfs2_uptodate_cachep)
return -ENOMEM;
diff --git a/fs/open.c b/fs/open.c
index 0d515d161974..a6b054edacba 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -26,6 +26,7 @@
#include <linux/syscalls.h>
#include <linux/rcupdate.h>
#include <linux/audit.h>
+#include <linux/falloc.h>
int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
@@ -352,6 +353,64 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
}
#endif
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len)
+{
+ struct file *file;
+ struct inode *inode;
+ long ret = -EINVAL;
+
+ if (offset < 0 || len <= 0)
+ goto out;
+
+ /* Return error if mode is not supported */
+ ret = -EOPNOTSUPP;
+ if (mode && !(mode & FALLOC_FL_KEEP_SIZE))
+ goto out;
+
+ ret = -EBADF;
+ file = fget(fd);
+ if (!file)
+ goto out;
+ if (!(file->f_mode & FMODE_WRITE))
+ goto out_fput;
+ /*
+ * Revalidate the write permissions, in case security policy has
+ * changed since the files were opened.
+ */
+ ret = security_file_permission(file, MAY_WRITE);
+ if (ret)
+ goto out_fput;
+
+ inode = file->f_path.dentry->d_inode;
+
+ ret = -ESPIPE;
+ if (S_ISFIFO(inode->i_mode))
+ goto out_fput;
+
+ ret = -ENODEV;
+ /*
+ * Let individual file system decide if it supports preallocation
+ * for directories or not.
+ */
+ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+ goto out_fput;
+
+ ret = -EFBIG;
+ /* Check for wrap through zero too */
+ if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0))
+ goto out_fput;
+
+ if (inode->i_op && inode->i_op->fallocate)
+ ret = inode->i_op->fallocate(inode, mode, offset, len);
+ else
+ ret = -ENOSYS;
+
+out_fput:
+ fput(file);
+out:
+ return ret;
+}
+
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and
@@ -855,7 +914,7 @@ EXPORT_SYMBOL(dentry_open);
/*
* Find an empty file descriptor entry, and mark it busy.
*/
-int get_unused_fd(void)
+int get_unused_fd_flags(int flags)
{
struct files_struct * files = current->files;
int fd, error;
@@ -891,7 +950,10 @@ repeat:
}
FD_SET(fd, fdt->open_fds);
- FD_CLR(fd, fdt->close_on_exec);
+ if (flags & O_CLOEXEC)
+ FD_SET(fd, fdt->close_on_exec);
+ else
+ FD_CLR(fd, fdt->close_on_exec);
files->next_fd = fd + 1;
#if 1
/* Sanity check */
@@ -907,6 +969,11 @@ out:
return error;
}
+int get_unused_fd(void)
+{
+ return get_unused_fd_flags(0);
+}
+
EXPORT_SYMBOL(get_unused_fd);
static void __put_unused_fd(struct files_struct *files, unsigned int fd)
@@ -959,7 +1026,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
- fd = get_unused_fd();
+ fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, flags, mode);
if (IS_ERR(f)) {
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c
index e62397341c36..dd86be2aa6c9 100644
--- a/fs/openpromfs/inode.c
+++ b/fs/openpromfs/inode.c
@@ -431,7 +431,7 @@ static int __init init_openprom_fs(void)
0,
(SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD),
- op_inode_init_once, NULL);
+ op_inode_init_once);
if (!op_inode_cachep)
return -ENOMEM;
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index e3491328596b..3d3e16631472 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -25,6 +25,8 @@
#define PARTITION_RISCIX_SCSI 2
#define PARTITION_LINUX 9
+#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
+ defined(CONFIG_ACORN_PARTITION_ADFS)
static struct adfs_discrecord *
adfs_partition(struct parsed_partitions *state, char *name, char *data,
unsigned long first_sector, int slot)
@@ -48,6 +50,7 @@ adfs_partition(struct parsed_partitions *state, char *name, char *data,
put_partition(state, slot, first_sector, nr_sects);
return dr;
}
+#endif
#ifdef CONFIG_ACORN_PARTITION_RISCIX
@@ -65,6 +68,8 @@ struct riscix_record {
struct riscix_part part[8];
};
+#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
+ defined(CONFIG_ACORN_PARTITION_ADFS)
static int
riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
unsigned long first_sect, int slot, unsigned long nr_sects)
@@ -105,6 +110,7 @@ riscix_partition(struct parsed_partitions *state, struct block_device *bdev,
return slot;
}
#endif
+#endif
#define LINUX_NATIVE_MAGIC 0xdeafa1de
#define LINUX_SWAP_MAGIC 0xdeafab1e
@@ -115,6 +121,8 @@ struct linux_part {
__le32 nr_sects;
};
+#if defined(CONFIG_ACORN_PARTITION_CUMANA) || \
+ defined(CONFIG_ACORN_PARTITION_ADFS)
static int
linux_partition(struct parsed_partitions *state, struct block_device *bdev,
unsigned long first_sect, int slot, unsigned long nr_sects)
@@ -146,6 +154,7 @@ linux_partition(struct parsed_partitions *state, struct block_device *bdev,
put_dev_sector(sect);
return slot;
}
+#endif
#ifdef CONFIG_ACORN_PARTITION_CUMANA
int
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 9a3a058f3553..783c57ec07d3 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -372,11 +372,10 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
{
struct hd_struct *p;
- p = kmalloc(sizeof(*p), GFP_KERNEL);
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return;
- memset(p, 0, sizeof(*p));
p->start_sect = start;
p->nr_sects = len;
p->partno = part;
@@ -397,7 +396,6 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len,
static struct attribute addpartattr = {
.name = "whole_disk",
.mode = S_IRUSR | S_IRGRP | S_IROTH,
- .owner = THIS_MODULE,
};
sysfs_create_file(&p->kobj, &addpartattr);
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
index 99873a2b4cbc..e7dd1d4e3473 100644
--- a/fs/partitions/ldm.c
+++ b/fs/partitions/ldm.c
@@ -677,15 +677,24 @@ static bool ldm_create_data_partitions (struct parsed_partitions *pp,
* Return: -1 Error, the calculated offset exceeded the size of the buffer
* n OK, a range-checked offset into buffer
*/
-static int ldm_relative (const u8 *buffer, int buflen, int base, int offset)
+static int ldm_relative(const u8 *buffer, int buflen, int base, int offset)
{
base += offset;
- if ((!buffer) || (offset < 0) || (base > buflen))
+ if (!buffer || offset < 0 || base > buflen) {
+ if (!buffer)
+ ldm_error("!buffer");
+ if (offset < 0)
+ ldm_error("offset (%d) < 0", offset);
+ if (base > buflen)
+ ldm_error("base (%d) > buflen (%d)", base, buflen);
return -1;
- if ((base + buffer[base]) >= buflen)
+ }
+ if (base + buffer[base] >= buflen) {
+ ldm_error("base (%d) + buffer[base] (%d) >= buflen (%d)", base,
+ buffer[base], buflen);
return -1;
-
+ }
return buffer[base] + offset + 1;
}
@@ -1054,60 +1063,98 @@ static bool ldm_parse_prt3(const u8 *buffer, int buflen, struct vblk *vb)
* Return: 'true' @vb contains a Volume VBLK
* 'false' @vb contents are not defined
*/
-static bool ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
+static bool ldm_parse_vol5(const u8 *buffer, int buflen, struct vblk *vb)
{
- int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2;
- int r_drive, len;
+ int r_objid, r_name, r_vtype, r_disable_drive_letter, r_child, r_size;
+ int r_id1, r_id2, r_size2, r_drive, len;
struct vblk_volu *volu;
- BUG_ON (!buffer || !vb);
-
- r_objid = ldm_relative (buffer, buflen, 0x18, 0);
- r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
- r_vtype = ldm_relative (buffer, buflen, 0x18, r_name);
- r_child = ldm_relative (buffer, buflen, 0x2E, r_vtype);
- r_size = ldm_relative (buffer, buflen, 0x3E, r_child);
-
- if (buffer[0x12] & VBLK_FLAG_VOLU_ID1)
- r_id1 = ldm_relative (buffer, buflen, 0x53, r_size);
- else
+ BUG_ON(!buffer || !vb);
+ r_objid = ldm_relative(buffer, buflen, 0x18, 0);
+ if (r_objid < 0) {
+ ldm_error("r_objid %d < 0", r_objid);
+ return false;
+ }
+ r_name = ldm_relative(buffer, buflen, 0x18, r_objid);
+ if (r_name < 0) {
+ ldm_error("r_name %d < 0", r_name);
+ return false;
+ }
+ r_vtype = ldm_relative(buffer, buflen, 0x18, r_name);
+ if (r_vtype < 0) {
+ ldm_error("r_vtype %d < 0", r_vtype);
+ return false;
+ }
+ r_disable_drive_letter = ldm_relative(buffer, buflen, 0x18, r_vtype);
+ if (r_disable_drive_letter < 0) {
+ ldm_error("r_disable_drive_letter %d < 0",
+ r_disable_drive_letter);
+ return false;
+ }
+ r_child = ldm_relative(buffer, buflen, 0x2D, r_disable_drive_letter);
+ if (r_child < 0) {
+ ldm_error("r_child %d < 0", r_child);
+ return false;
+ }
+ r_size = ldm_relative(buffer, buflen, 0x3D, r_child);
+ if (r_size < 0) {
+ ldm_error("r_size %d < 0", r_size);
+ return false;
+ }
+ if (buffer[0x12] & VBLK_FLAG_VOLU_ID1) {
+ r_id1 = ldm_relative(buffer, buflen, 0x52, r_size);
+ if (r_id1 < 0) {
+ ldm_error("r_id1 %d < 0", r_id1);
+ return false;
+ }
+ } else
r_id1 = r_size;
-
- if (buffer[0x12] & VBLK_FLAG_VOLU_ID2)
- r_id2 = ldm_relative (buffer, buflen, 0x53, r_id1);
- else
+ if (buffer[0x12] & VBLK_FLAG_VOLU_ID2) {
+ r_id2 = ldm_relative(buffer, buflen, 0x52, r_id1);
+ if (r_id2 < 0) {
+ ldm_error("r_id2 %d < 0", r_id2);
+ return false;
+ }
+ } else
r_id2 = r_id1;
-
- if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE)
- r_size2 = ldm_relative (buffer, buflen, 0x53, r_id2);
- else
+ if (buffer[0x12] & VBLK_FLAG_VOLU_SIZE) {
+ r_size2 = ldm_relative(buffer, buflen, 0x52, r_id2);
+ if (r_size2 < 0) {
+ ldm_error("r_size2 %d < 0", r_size2);
+ return false;
+ }
+ } else
r_size2 = r_id2;
-
- if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE)
- r_drive = ldm_relative (buffer, buflen, 0x53, r_size2);
- else
+ if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
+ r_drive = ldm_relative(buffer, buflen, 0x52, r_size2);
+ if (r_drive < 0) {
+ ldm_error("r_drive %d < 0", r_drive);
+ return false;
+ }
+ } else
r_drive = r_size2;
-
len = r_drive;
- if (len < 0)
+ if (len < 0) {
+ ldm_error("len %d < 0", len);
return false;
-
+ }
len += VBLK_SIZE_VOL5;
- if (len != BE32 (buffer + 0x14))
+ if (len > BE32(buffer + 0x14)) {
+ ldm_error("len %d > BE32(buffer + 0x14) %d", len,
+ BE32(buffer + 0x14));
return false;
-
+ }
volu = &vb->vblk.volu;
-
- ldm_get_vstr (buffer + 0x18 + r_name, volu->volume_type,
- sizeof (volu->volume_type));
- memcpy (volu->volume_state, buffer + 0x19 + r_vtype,
- sizeof (volu->volume_state));
- volu->size = ldm_get_vnum (buffer + 0x3E + r_child);
- volu->partition_type = buffer[0x42 + r_size];
- memcpy (volu->guid, buffer + 0x43 + r_size, sizeof (volu->guid));
+ ldm_get_vstr(buffer + 0x18 + r_name, volu->volume_type,
+ sizeof(volu->volume_type));
+ memcpy(volu->volume_state, buffer + 0x18 + r_disable_drive_letter,
+ sizeof(volu->volume_state));
+ volu->size = ldm_get_vnum(buffer + 0x3D + r_child);
+ volu->partition_type = buffer[0x41 + r_size];
+ memcpy(volu->guid, buffer + 0x42 + r_size, sizeof(volu->guid));
if (buffer[0x12] & VBLK_FLAG_VOLU_DRIVE) {
- ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint,
- sizeof (volu->drive_hint));
+ ldm_get_vstr(buffer + 0x52 + r_size, volu->drive_hint,
+ sizeof(volu->drive_hint));
}
return true;
}
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h
index d2e6a3046939..80f63b5fdd9f 100644
--- a/fs/partitions/ldm.h
+++ b/fs/partitions/ldm.h
@@ -68,7 +68,7 @@ struct parsed_partitions;
#define VBLK_SIZE_DSK3 12
#define VBLK_SIZE_DSK4 45
#define VBLK_SIZE_PRT3 28
-#define VBLK_SIZE_VOL5 59
+#define VBLK_SIZE_VOL5 58
/* component types */
#define COMP_STRIPE 0x01 /* Stripe-set */
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 98e78e2f18d6..965625a0977d 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -62,6 +62,8 @@
#include <linux/mman.h>
#include <linux/proc_fs.h>
#include <linux/ioport.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/pagemap.h>
@@ -76,9 +78,7 @@
#include <linux/rcupdate.h>
#include <linux/delayacct.h>
-#include <asm/uaccess.h>
#include <asm/pgtable.h>
-#include <asm/io.h>
#include <asm/processor.h>
#include "internal.h"
@@ -87,10 +87,10 @@
do { memcpy(buffer, string, strlen(string)); \
buffer += strlen(string); } while (0)
-static inline char * task_name(struct task_struct *p, char * buf)
+static inline char *task_name(struct task_struct *p, char *buf)
{
int i;
- char * name;
+ char *name;
char tcomm[sizeof(p->comm)];
get_task_comm(tcomm, p);
@@ -138,7 +138,7 @@ static const char *task_state_array[] = {
"X (dead)" /* 32 */
};
-static inline const char * get_task_state(struct task_struct *tsk)
+static inline const char *get_task_state(struct task_struct *tsk)
{
unsigned int state = (tsk->state & (TASK_RUNNING |
TASK_INTERRUPTIBLE |
@@ -156,7 +156,7 @@ static inline const char * get_task_state(struct task_struct *tsk)
return *p;
}
-static inline char * task_state(struct task_struct *p, char *buffer)
+static inline char *task_state(struct task_struct *p, char *buffer)
{
struct group_info *group_info;
int g;
@@ -172,8 +172,8 @@ static inline char * task_state(struct task_struct *p, char *buffer)
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n",
get_task_state(p),
- p->tgid, p->pid,
- pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0,
+ p->tgid, p->pid,
+ pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0,
pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0,
p->uid, p->euid, p->suid, p->fsuid,
p->gid, p->egid, p->sgid, p->fsgid);
@@ -191,15 +191,15 @@ static inline char * task_state(struct task_struct *p, char *buffer)
get_group_info(group_info);
task_unlock(p);
- for (g = 0; g < min(group_info->ngroups,NGROUPS_SMALL); g++)
- buffer += sprintf(buffer, "%d ", GROUP_AT(group_info,g));
+ for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++)
+ buffer += sprintf(buffer, "%d ", GROUP_AT(group_info, g));
put_group_info(group_info);
buffer += sprintf(buffer, "\n");
return buffer;
}
-static char * render_sigset_t(const char *header, sigset_t *set, char *buffer)
+static char *render_sigset_t(const char *header, sigset_t *set, char *buffer)
{
int i, len;
@@ -239,7 +239,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
}
}
-static inline char * task_sig(struct task_struct *p, char *buffer)
+static inline char *task_sig(struct task_struct *p, char *buffer)
{
unsigned long flags;
sigset_t pending, shpending, blocked, ignored, caught;
@@ -289,14 +289,23 @@ static inline char *task_cap(struct task_struct *p, char *buffer)
cap_t(p->cap_effective));
}
-int proc_pid_status(struct task_struct *task, char * buffer)
+static inline char *task_context_switch_counts(struct task_struct *p,
+ char *buffer)
{
- char * orig = buffer;
+ return buffer + sprintf(buffer, "voluntary_ctxt_switches:\t%lu\n"
+ "nonvoluntary_ctxt_switches:\t%lu\n",
+ p->nvcsw,
+ p->nivcsw);
+}
+
+int proc_pid_status(struct task_struct *task, char *buffer)
+{
+ char *orig = buffer;
struct mm_struct *mm = get_task_mm(task);
buffer = task_name(task, buffer);
buffer = task_state(task, buffer);
-
+
if (mm) {
buffer = task_mem(mm, buffer);
mmput(mm);
@@ -307,6 +316,7 @@ int proc_pid_status(struct task_struct *task, char * buffer)
#if defined(CONFIG_S390)
buffer = task_show_regs(task, buffer);
#endif
+ buffer = task_context_switch_counts(task, buffer);
return buffer - orig;
}
@@ -332,7 +342,7 @@ static clock_t task_utime(struct task_struct *p)
static clock_t task_stime(struct task_struct *p)
{
- clock_t stime = cputime_to_clock_t(p->stime);
+ clock_t stime;
/*
* Use CFS's precise accounting. (we subtract utime from
@@ -344,8 +354,7 @@ static clock_t task_stime(struct task_struct *p)
return stime;
}
-
-static int do_task_stat(struct task_struct *task, char * buffer, int whole)
+static int do_task_stat(struct task_struct *task, char *buffer, int whole)
{
unsigned long vsize, eip, esp, wchan = ~0UL;
long priority, nice;
@@ -353,7 +362,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
sigset_t sigign, sigcatch;
char state;
int res;
- pid_t ppid = 0, pgid = -1, sid = -1;
+ pid_t ppid = 0, pgid = -1, sid = -1;
int num_threads = 0;
struct mm_struct *mm;
unsigned long long start_time;
@@ -424,7 +433,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
}
rcu_read_unlock();
- if (!whole || num_threads<2)
+ if (!whole || num_threads < 2)
wchan = get_wchan(task);
if (!whole) {
min_flt = task->min_flt;
@@ -440,12 +449,13 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
/* Temporary variable needed for gcc-2.96 */
/* convert timespec -> nsec*/
- start_time = (unsigned long long)task->start_time.tv_sec * NSEC_PER_SEC
- + task->start_time.tv_nsec;
+ start_time =
+ (unsigned long long)task->real_start_time.tv_sec * NSEC_PER_SEC
+ + task->real_start_time.tv_nsec;
/* convert nsec -> ticks */
start_time = nsec_to_clock_t(start_time);
- res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %u %lu \
+ res = sprintf(buffer, "%d (%s) %c %d %d %d %d %d %u %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \
%lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu\n",
task->pid,
@@ -471,7 +481,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
start_time,
vsize,
mm ? get_mm_rss(mm) : 0,
- rsslim,
+ rsslim,
mm ? mm->start_code : 0,
mm ? mm->end_code : 0,
mm ? mm->start_stack : 0,
@@ -493,17 +503,17 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
task->rt_priority,
task->policy,
(unsigned long long)delayacct_blkio_ticks(task));
- if(mm)
+ if (mm)
mmput(mm);
return res;
}
-int proc_tid_stat(struct task_struct *task, char * buffer)
+int proc_tid_stat(struct task_struct *task, char *buffer)
{
return do_task_stat(task, buffer, 0);
}
-int proc_tgid_stat(struct task_struct *task, char * buffer)
+int proc_tgid_stat(struct task_struct *task, char *buffer)
{
return do_task_stat(task, buffer, 1);
}
@@ -512,12 +522,12 @@ int proc_pid_statm(struct task_struct *task, char *buffer)
{
int size = 0, resident = 0, shared = 0, text = 0, lib = 0, data = 0;
struct mm_struct *mm = get_task_mm(task);
-
+
if (mm) {
size = task_statm(mm, &shared, &text, &data, &resident);
mmput(mm);
}
- return sprintf(buffer,"%d %d %d %d %d %d %d\n",
+ return sprintf(buffer, "%d %d %d %d %d %d %d\n",
size, resident, shared, text, lib, data, 0);
}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 46ea5d56e1bb..3c77d5a64e7c 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -67,12 +67,12 @@
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/ptrace.h>
-#include <linux/seccomp.h>
#include <linux/cpuset.h>
#include <linux/audit.h>
#include <linux/poll.h>
#include <linux/nsproxy.h>
#include <linux/oom.h>
+#include <linux/elf.h>
#include "internal.h"
/* NOTE:
@@ -204,12 +204,17 @@ static int proc_pid_environ(struct task_struct *task, char * buffer)
int res = 0;
struct mm_struct *mm = get_task_mm(task);
if (mm) {
- unsigned int len = mm->env_end - mm->env_start;
+ unsigned int len;
+
+ res = -ESRCH;
+ if (!ptrace_may_attach(task))
+ goto out;
+
+ len = mm->env_end - mm->env_start;
if (len > PAGE_SIZE)
len = PAGE_SIZE;
res = access_process_vm(task, mm->env_start, buffer, len, 0);
- if (!ptrace_may_attach(task))
- res = -ESRCH;
+out:
mmput(mm);
}
return res;
@@ -279,7 +284,7 @@ static int proc_pid_auxv(struct task_struct *task, char *buffer)
static int proc_pid_wchan(struct task_struct *task, char *buffer)
{
unsigned long wchan;
- char symname[KSYM_NAME_LEN+1];
+ char symname[KSYM_NAME_LEN];
wchan = get_wchan(task);
@@ -812,71 +817,6 @@ static const struct file_operations proc_loginuid_operations = {
};
#endif
-#ifdef CONFIG_SECCOMP
-static ssize_t seccomp_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
- char __buf[20];
- size_t len;
-
- if (!tsk)
- return -ESRCH;
- /* no need to print the trailing zero, so use only len */
- len = sprintf(__buf, "%u\n", tsk->seccomp.mode);
- put_task_struct(tsk);
-
- return simple_read_from_buffer(buf, count, ppos, __buf, len);
-}
-
-static ssize_t seccomp_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct task_struct *tsk = get_proc_task(file->f_dentry->d_inode);
- char __buf[20], *end;
- unsigned int seccomp_mode;
- ssize_t result;
-
- result = -ESRCH;
- if (!tsk)
- goto out_no_task;
-
- /* can set it only once to be even more secure */
- result = -EPERM;
- if (unlikely(tsk->seccomp.mode))
- goto out;
-
- result = -EFAULT;
- memset(__buf, 0, sizeof(__buf));
- count = min(count, sizeof(__buf) - 1);
- if (copy_from_user(__buf, buf, count))
- goto out;
-
- seccomp_mode = simple_strtoul(__buf, &end, 0);
- if (*end == '\n')
- end++;
- result = -EINVAL;
- if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
- tsk->seccomp.mode = seccomp_mode;
- set_tsk_thread_flag(tsk, TIF_SECCOMP);
- } else
- goto out;
- result = -EIO;
- if (unlikely(!(end - __buf)))
- goto out;
- result = end - __buf;
-out:
- put_task_struct(tsk);
-out_no_task:
- return result;
-}
-
-static const struct file_operations proc_seccomp_operations = {
- .read = seccomp_read,
- .write = seccomp_write,
-};
-#endif /* CONFIG_SECCOMP */
-
#ifdef CONFIG_FAULT_INJECTION
static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
@@ -1075,7 +1015,7 @@ static int task_dumpable(struct task_struct *task)
task_lock(task);
mm = task->mm;
if (mm)
- dumpable = mm->dumpable;
+ dumpable = get_dumpable(mm);
task_unlock(task);
if(dumpable == 1)
return 1;
@@ -1846,6 +1786,91 @@ static const struct inode_operations proc_attr_dir_inode_operations = {
#endif
+#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
+static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
+ struct mm_struct *mm;
+ char buffer[PROC_NUMBUF];
+ size_t len;
+ int ret;
+
+ if (!task)
+ return -ESRCH;
+
+ ret = 0;
+ mm = get_task_mm(task);
+ if (mm) {
+ len = snprintf(buffer, sizeof(buffer), "%08lx\n",
+ ((mm->flags & MMF_DUMP_FILTER_MASK) >>
+ MMF_DUMP_FILTER_SHIFT));
+ mmput(mm);
+ ret = simple_read_from_buffer(buf, count, ppos, buffer, len);
+ }
+
+ put_task_struct(task);
+
+ return ret;
+}
+
+static ssize_t proc_coredump_filter_write(struct file *file,
+ const char __user *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct task_struct *task;
+ struct mm_struct *mm;
+ char buffer[PROC_NUMBUF], *end;
+ unsigned int val;
+ int ret;
+ int i;
+ unsigned long mask;
+
+ ret = -EFAULT;
+ memset(buffer, 0, sizeof(buffer));
+ if (count > sizeof(buffer) - 1)
+ count = sizeof(buffer) - 1;
+ if (copy_from_user(buffer, buf, count))
+ goto out_no_task;
+
+ ret = -EINVAL;
+ val = (unsigned int)simple_strtoul(buffer, &end, 0);
+ if (*end == '\n')
+ end++;
+ if (end - buffer == 0)
+ goto out_no_task;
+
+ ret = -ESRCH;
+ task = get_proc_task(file->f_dentry->d_inode);
+ if (!task)
+ goto out_no_task;
+
+ ret = end - buffer;
+ mm = get_task_mm(task);
+ if (!mm)
+ goto out_no_mm;
+
+ for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) {
+ if (val & mask)
+ set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
+ else
+ clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
+ }
+
+ mmput(mm);
+ out_no_mm:
+ put_task_struct(task);
+ out_no_task:
+ return ret;
+}
+
+static const struct file_operations proc_coredump_filter_operations = {
+ .read = proc_coredump_filter_read,
+ .write = proc_coredump_filter_write,
+};
+#endif
+
/*
* /proc/self:
*/
@@ -2037,9 +2062,6 @@ static const struct pid_entry tgid_base_stuff[] = {
REG("numa_maps", S_IRUGO, numa_maps),
#endif
REG("mem", S_IRUSR|S_IWUSR, mem),
-#ifdef CONFIG_SECCOMP
- REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
-#endif
LNK("cwd", cwd),
LNK("root", root),
LNK("exe", exe),
@@ -2069,6 +2091,9 @@ static const struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_FAULT_INJECTION
REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
#endif
+#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
+ REG("coredump_filter", S_IRUGO|S_IWUSR, coredump_filter),
+#endif
#ifdef CONFIG_TASK_IO_ACCOUNTING
INF("io", S_IRUGO, pid_io_accounting),
#endif
@@ -2324,9 +2349,6 @@ static const struct pid_entry tid_base_stuff[] = {
REG("numa_maps", S_IRUGO, numa_maps),
#endif
REG("mem", S_IRUSR|S_IWUSR, mem),
-#ifdef CONFIG_SECCOMP
- REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
-#endif
LNK("cwd", cwd),
LNK("root", root),
LNK("exe", exe),
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 8a40e15f5ecb..b5e7155d30d8 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -20,6 +20,7 @@
#include <linux/namei.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
+#include <linux/completion.h>
#include <asm/uaccess.h>
#include "internal.h"
@@ -529,12 +530,6 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
return -EAGAIN;
dp->low_ino = i;
- spin_lock(&proc_subdir_lock);
- dp->next = dir->subdir;
- dp->parent = dir;
- dir->subdir = dp;
- spin_unlock(&proc_subdir_lock);
-
if (S_ISDIR(dp->mode)) {
if (dp->proc_iops == NULL) {
dp->proc_fops = &proc_dir_operations;
@@ -550,6 +545,13 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
if (dp->proc_iops == NULL)
dp->proc_iops = &proc_file_inode_operations;
}
+
+ spin_lock(&proc_subdir_lock);
+ dp->next = dir->subdir;
+ dp->parent = dir;
+ dir->subdir = dp;
+ spin_unlock(&proc_subdir_lock);
+
return 0;
}
@@ -613,6 +615,9 @@ static struct proc_dir_entry *proc_create(struct proc_dir_entry **parent,
ent->namelen = len;
ent->mode = mode;
ent->nlink = nlink;
+ ent->pde_users = 0;
+ spin_lock_init(&ent->pde_unload_lock);
+ ent->pde_unload_completion = NULL;
out:
return ent;
}
@@ -649,9 +654,6 @@ struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
ent = proc_create(&parent, name, S_IFDIR | mode, 2);
if (ent) {
- ent->proc_fops = &proc_dir_operations;
- ent->proc_iops = &proc_dir_inode_operations;
-
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
@@ -686,10 +688,6 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
ent = proc_create(&parent,name,mode,nlink);
if (ent) {
- if (S_ISDIR(mode)) {
- ent->proc_fops = &proc_dir_operations;
- ent->proc_iops = &proc_dir_inode_operations;
- }
if (proc_register(parent, ent) < 0) {
kfree(ent);
ent = NULL;
@@ -734,9 +732,35 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
de = *p;
*p = de->next;
de->next = NULL;
+
+ spin_lock(&de->pde_unload_lock);
+ /*
+ * Stop accepting new callers into module. If you're
+ * dynamically allocating ->proc_fops, save a pointer somewhere.
+ */
+ de->proc_fops = NULL;
+ /* Wait until all existing callers into module are done. */
+ if (de->pde_users > 0) {
+ DECLARE_COMPLETION_ONSTACK(c);
+
+ if (!de->pde_unload_completion)
+ de->pde_unload_completion = &c;
+
+ spin_unlock(&de->pde_unload_lock);
+ spin_unlock(&proc_subdir_lock);
+
+ wait_for_completion(de->pde_unload_completion);
+
+ spin_lock(&proc_subdir_lock);
+ goto continue_removing;
+ }
+ spin_unlock(&de->pde_unload_lock);
+
+continue_removing:
if (S_ISDIR(de->mode))
parent->nlink--;
- proc_kill_inodes(de);
+ if (!S_ISREG(de->mode))
+ proc_kill_inodes(de);
de->nlink = 0;
WARN_ON(de->subdir);
if (!atomic_read(&de->count))
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index d5ce65c68d7b..94e2c1adf184 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/completion.h>
#include <linux/file.h>
#include <linux/limits.h>
#include <linux/init.h>
@@ -111,14 +112,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&ei->vfs_inode);
}
-
+
int __init proc_init_inodecache(void)
{
proc_inode_cachep = kmem_cache_create("proc_inode_cache",
sizeof(struct proc_inode),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (proc_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -140,6 +141,251 @@ static const struct super_operations proc_sops = {
.remount_fs = proc_remount,
};
+static void pde_users_dec(struct proc_dir_entry *pde)
+{
+ spin_lock(&pde->pde_unload_lock);
+ pde->pde_users--;
+ if (pde->pde_unload_completion && pde->pde_users == 0)
+ complete(pde->pde_unload_completion);
+ spin_unlock(&pde->pde_unload_lock);
+}
+
+static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ loff_t rv = -EINVAL;
+ loff_t (*llseek)(struct file *, loff_t, int);
+
+ spin_lock(&pde->pde_unload_lock);
+ /*
+ * remove_proc_entry() is going to delete PDE (as part of module
+ * cleanup sequence). No new callers into module allowed.
+ */
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ /*
+ * Bump refcount so that remove_proc_entry will wail for ->llseek to
+ * complete.
+ */
+ pde->pde_users++;
+ /*
+ * Save function pointer under lock, to protect against ->proc_fops
+ * NULL'ifying right after ->pde_unload_lock is dropped.
+ */
+ llseek = pde->proc_fops->llseek;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (!llseek)
+ llseek = default_llseek;
+ rv = llseek(file, offset, whence);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ ssize_t rv = -EIO;
+ ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ read = pde->proc_fops->read;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (read)
+ rv = read(file, buf, count, ppos);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ ssize_t rv = -EIO;
+ ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ write = pde->proc_fops->write;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (write)
+ rv = write(file, buf, count, ppos);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ unsigned int rv = 0;
+ unsigned int (*poll)(struct file *, struct poll_table_struct *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ poll = pde->proc_fops->poll;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (poll)
+ rv = poll(file, pts);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ long rv = -ENOTTY;
+ long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long);
+ int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ unlocked_ioctl = pde->proc_fops->unlocked_ioctl;
+ ioctl = pde->proc_fops->ioctl;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (unlocked_ioctl) {
+ rv = unlocked_ioctl(file, cmd, arg);
+ if (rv == -ENOIOCTLCMD)
+ rv = -EINVAL;
+ } else if (ioctl) {
+ lock_kernel();
+ rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
+ unlock_kernel();
+ }
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+#ifdef CONFIG_COMPAT
+static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ long rv = -ENOTTY;
+ long (*compat_ioctl)(struct file *, unsigned int, unsigned long);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ compat_ioctl = pde->proc_fops->compat_ioctl;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (compat_ioctl)
+ rv = compat_ioctl(file, cmd, arg);
+
+ pde_users_dec(pde);
+ return rv;
+}
+#endif
+
+static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ int rv = -EIO;
+ int (*mmap)(struct file *, struct vm_area_struct *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ mmap = pde->proc_fops->mmap;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (mmap)
+ rv = mmap(file, vma);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static int proc_reg_open(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *pde = PDE(inode);
+ int rv = 0;
+ int (*open)(struct inode *, struct file *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ open = pde->proc_fops->open;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (open)
+ rv = open(inode, file);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static int proc_reg_release(struct inode *inode, struct file *file)
+{
+ struct proc_dir_entry *pde = PDE(inode);
+ int rv = 0;
+ int (*release)(struct inode *, struct file *);
+
+ spin_lock(&pde->pde_unload_lock);
+ if (!pde->proc_fops) {
+ spin_unlock(&pde->pde_unload_lock);
+ return rv;
+ }
+ pde->pde_users++;
+ release = pde->proc_fops->release;
+ spin_unlock(&pde->pde_unload_lock);
+
+ if (release)
+ rv = release(inode, file);
+
+ pde_users_dec(pde);
+ return rv;
+}
+
+static const struct file_operations proc_reg_file_ops = {
+ .llseek = proc_reg_llseek,
+ .read = proc_reg_read,
+ .write = proc_reg_write,
+ .poll = proc_reg_poll,
+ .unlocked_ioctl = proc_reg_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = proc_reg_compat_ioctl,
+#endif
+ .mmap = proc_reg_mmap,
+ .open = proc_reg_open,
+ .release = proc_reg_release,
+};
+
struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
struct proc_dir_entry *de)
{
@@ -166,8 +412,12 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
inode->i_nlink = de->nlink;
if (de->proc_iops)
inode->i_op = de->proc_iops;
- if (de->proc_fops)
- inode->i_fop = de->proc_fops;
+ if (de->proc_fops) {
+ if (S_ISREG(inode->i_mode))
+ inode->i_fop = &proc_reg_file_ops;
+ else
+ inode->i_fop = de->proc_fops;
+ }
}
return inode;
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 5fd49e47f83a..bee251cb87c8 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -105,6 +105,7 @@ static int uptime_read_proc(char *page, char **start, off_t off,
cputime_t idletime = cputime_add(init_task.utime, init_task.stime);
do_posix_clock_monotonic_gettime(&uptime);
+ monotonic_to_bootbased(&uptime);
cputime_to_timespec(idletime, &idle);
len = sprintf(page,"%lu.%02lu %lu.%02lu\n",
(unsigned long) uptime.tv_sec,
@@ -443,12 +444,17 @@ static int show_stat(struct seq_file *p, void *v)
unsigned long jif;
cputime64_t user, nice, system, idle, iowait, irq, softirq, steal;
u64 sum = 0;
+ struct timespec boottime;
+ unsigned int *per_irq_sum;
+
+ per_irq_sum = kzalloc(sizeof(unsigned int)*NR_IRQS, GFP_KERNEL);
+ if (!per_irq_sum)
+ return -ENOMEM;
user = nice = system = idle = iowait =
irq = softirq = steal = cputime64_zero;
- jif = - wall_to_monotonic.tv_sec;
- if (wall_to_monotonic.tv_nsec)
- --jif;
+ getboottime(&boottime);
+ jif = boottime.tv_sec;
for_each_possible_cpu(i) {
int j;
@@ -461,8 +467,11 @@ static int show_stat(struct seq_file *p, void *v)
irq = cputime64_add(irq, kstat_cpu(i).cpustat.irq);
softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
- for (j = 0 ; j < NR_IRQS ; j++)
- sum += kstat_cpu(i).irqs[j];
+ for (j = 0; j < NR_IRQS; j++) {
+ unsigned int temp = kstat_cpu(i).irqs[j];
+ sum += temp;
+ per_irq_sum[j] += temp;
+ }
}
seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu\n",
@@ -498,9 +507,10 @@ static int show_stat(struct seq_file *p, void *v)
}
seq_printf(p, "intr %llu", (unsigned long long)sum);
-#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA) && !defined(CONFIG_IA64)
+#ifndef CONFIG_SMP
+ /* Touches too many cache lines on SMP setups */
for (i = 0; i < NR_IRQS; i++)
- seq_printf(p, " %u", kstat_irqs(i));
+ seq_printf(p, " %u", per_irq_sum[i]);
#endif
seq_printf(p,
@@ -515,6 +525,7 @@ static int show_stat(struct seq_file *p, void *v)
nr_running(),
nr_iowait());
+ kfree(per_irq_sum);
return 0;
}
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index b3a473b0a191..22846225acfa 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -69,7 +69,7 @@ static void show_tty_range(struct seq_file *m, struct tty_driver *p,
static int show_tty_driver(struct seq_file *m, void *v)
{
- struct tty_driver *p = v;
+ struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers);
dev_t from = MKDEV(p->major, p->minor_start);
dev_t to = from + p->num;
@@ -106,22 +106,13 @@ static int show_tty_driver(struct seq_file *m, void *v)
/* iterator */
static void *t_start(struct seq_file *m, loff_t *pos)
{
- struct list_head *p;
- loff_t l = *pos;
-
mutex_lock(&tty_mutex);
- list_for_each(p, &tty_drivers)
- if (!l--)
- return list_entry(p, struct tty_driver, tty_drivers);
- return NULL;
+ return seq_list_start(&tty_drivers, *pos);
}
static void *t_next(struct seq_file *m, void *v, loff_t *pos)
{
- struct list_head *p = ((struct tty_driver *)v)->tty_drivers.next;
- (*pos)++;
- return p==&tty_drivers ? NULL :
- list_entry(p, struct tty_driver, tty_drivers);
+ return seq_list_next(v, &tty_drivers, pos);
}
static void t_stop(struct seq_file *m, void *v)
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 8d256eb11813..1bc8d873a9e1 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -545,7 +545,7 @@ static int init_inodecache(void)
sizeof(struct qnx4_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (qnx4_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/quota.c b/fs/quota.c
index 9f237d6182c9..e6577ac15a6c 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -10,12 +10,14 @@
#include <linux/slab.h>
#include <asm/current.h>
#include <asm/uaccess.h>
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/buffer_head.h>
#include <linux/capability.h>
#include <linux/quotaops.h>
+#include <linux/types.h>
/* Check validity of generic quotactl commands */
static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
@@ -384,3 +386,119 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t
return ret;
}
+
+#if defined(CONFIG_X86_64) || defined(CONFIG_IA64)
+/*
+ * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
+ * and is necessary due to alignment problems.
+ */
+struct compat_if_dqblk {
+ compat_u64 dqb_bhardlimit;
+ compat_u64 dqb_bsoftlimit;
+ compat_u64 dqb_curspace;
+ compat_u64 dqb_ihardlimit;
+ compat_u64 dqb_isoftlimit;
+ compat_u64 dqb_curinodes;
+ compat_u64 dqb_btime;
+ compat_u64 dqb_itime;
+ compat_uint_t dqb_valid;
+};
+
+/* XFS structures */
+struct compat_fs_qfilestat {
+ compat_u64 dqb_bhardlimit;
+ compat_u64 qfs_nblks;
+ compat_uint_t qfs_nextents;
+};
+
+struct compat_fs_quota_stat {
+ __s8 qs_version;
+ __u16 qs_flags;
+ __s8 qs_pad;
+ struct compat_fs_qfilestat qs_uquota;
+ struct compat_fs_qfilestat qs_gquota;
+ compat_uint_t qs_incoredqs;
+ compat_int_t qs_btimelimit;
+ compat_int_t qs_itimelimit;
+ compat_int_t qs_rtbtimelimit;
+ __u16 qs_bwarnlimit;
+ __u16 qs_iwarnlimit;
+};
+
+asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
+ qid_t id, void __user *addr)
+{
+ unsigned int cmds;
+ struct if_dqblk __user *dqblk;
+ struct compat_if_dqblk __user *compat_dqblk;
+ struct fs_quota_stat __user *fsqstat;
+ struct compat_fs_quota_stat __user *compat_fsqstat;
+ compat_uint_t data;
+ u16 xdata;
+ long ret;
+
+ cmds = cmd >> SUBCMDSHIFT;
+
+ switch (cmds) {
+ case Q_GETQUOTA:
+ dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
+ compat_dqblk = addr;
+ ret = sys_quotactl(cmd, special, id, dqblk);
+ if (ret)
+ break;
+ if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
+ get_user(data, &dqblk->dqb_valid) ||
+ put_user(data, &compat_dqblk->dqb_valid))
+ ret = -EFAULT;
+ break;
+ case Q_SETQUOTA:
+ dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
+ compat_dqblk = addr;
+ ret = -EFAULT;
+ if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
+ get_user(data, &compat_dqblk->dqb_valid) ||
+ put_user(data, &dqblk->dqb_valid))
+ break;
+ ret = sys_quotactl(cmd, special, id, dqblk);
+ break;
+ case Q_XGETQSTAT:
+ fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
+ compat_fsqstat = addr;
+ ret = sys_quotactl(cmd, special, id, fsqstat);
+ if (ret)
+ break;
+ ret = -EFAULT;
+ /* Copying qs_version, qs_flags, qs_pad */
+ if (copy_in_user(compat_fsqstat, fsqstat,
+ offsetof(struct compat_fs_quota_stat, qs_uquota)))
+ break;
+ /* Copying qs_uquota */
+ if (copy_in_user(&compat_fsqstat->qs_uquota,
+ &fsqstat->qs_uquota,
+ sizeof(compat_fsqstat->qs_uquota)) ||
+ get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
+ put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
+ break;
+ /* Copying qs_gquota */
+ if (copy_in_user(&compat_fsqstat->qs_gquota,
+ &fsqstat->qs_gquota,
+ sizeof(compat_fsqstat->qs_gquota)) ||
+ get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
+ put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
+ break;
+ /* Copying the rest */
+ if (copy_in_user(&compat_fsqstat->qs_incoredqs,
+ &fsqstat->qs_incoredqs,
+ sizeof(struct compat_fs_quota_stat) -
+ offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
+ get_user(xdata, &fsqstat->qs_iwarnlimit) ||
+ put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
+ break;
+ ret = 0;
+ break;
+ default:
+ ret = sys_quotactl(cmd, special, id, addr);
+ }
+ return ret;
+}
+#endif
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index d40d22b347b7..ef2b46d099ff 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -60,6 +60,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
inode->i_blocks = 0;
inode->i_mapping->a_ops = &ramfs_aops;
inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
+ mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
default:
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 30eebfb1b2d8..2070aeee2a52 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -1305,7 +1305,6 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
if (get_inode_item_key_version (inode) == KEY_FORMAT_3_5 &&
*ppos + count > MAX_NON_LFS) {
if (*ppos >= MAX_NON_LFS) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
if (count > MAX_NON_LFS - (unsigned long)*ppos)
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 1272d11399fb..ddde489f1cb2 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -7,6 +7,7 @@
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_acl.h>
#include <linux/reiserfs_xattr.h>
+#include <linux/exportfs.h>
#include <linux/smp_lock.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index b484d2913c0d..11a0fcc2d402 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -51,8 +51,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
if (IS_RDONLY(inode))
return -EROFS;
- if ((current->fsuid != inode->i_uid)
- && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (get_user(flags, (int __user *)arg))
@@ -81,7 +80,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
case REISERFS_IOC_GETVERSION:
return put_user(inode->i_generation, (int __user *)arg);
case REISERFS_IOC_SETVERSION:
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index b4ac9119200e..5b68dd3f191a 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>
+#include <linux/exportfs.h>
#include <linux/vfs.h>
#include <linux/mnt_namespace.h>
#include <linux/mount.h>
@@ -526,7 +527,7 @@ static int init_inodecache(void)
reiserfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (reiserfs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index 5296a29cc5eb..b7e4fa4539de 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -21,7 +21,7 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
if (!reiserfs_posixacl(inode->i_sb))
return -EOPNOTSUPP;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
if (value) {
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 2284e03342c6..dae7945f90e4 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -572,14 +572,14 @@ static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
romfs_inode_cachep = kmem_cache_create("romfs_inode_cache",
sizeof(struct romfs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (romfs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 49194a4e6b91..bbb19be260ce 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -177,21 +177,23 @@ EXPORT_SYMBOL(seq_read);
static int traverse(struct seq_file *m, loff_t offset)
{
- loff_t pos = 0;
+ loff_t pos = 0, index;
int error = 0;
void *p;
m->version = 0;
- m->index = 0;
+ index = 0;
m->count = m->from = 0;
- if (!offset)
+ if (!offset) {
+ m->index = index;
return 0;
+ }
if (!m->buf) {
m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
if (!m->buf)
return -ENOMEM;
}
- p = m->op->start(m, &m->index);
+ p = m->op->start(m, &index);
while (p) {
error = PTR_ERR(p);
if (IS_ERR(p))
@@ -204,15 +206,17 @@ static int traverse(struct seq_file *m, loff_t offset)
if (pos + m->count > offset) {
m->from = offset - pos;
m->count -= m->from;
+ m->index = index;
break;
}
pos += m->count;
m->count = 0;
if (pos == offset) {
- m->index++;
+ index++;
+ m->index = index;
break;
}
- p = m->op->next(m, p, &m->index);
+ p = m->op->next(m, p, &index);
}
m->op->stop(m, p);
return error;
@@ -260,8 +264,8 @@ loff_t seq_lseek(struct file *file, loff_t offset, int origin)
}
}
}
- mutex_unlock(&m->lock);
file->f_version = m->version;
+ mutex_unlock(&m->lock);
return retval;
}
EXPORT_SYMBOL(seq_lseek);
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 6724a6cf01ff..73d1450a95d4 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -73,14 +73,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
smb_inode_cachep = kmem_cache_create("smb_inode_cache",
sizeof(struct smb_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (smb_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c
index 3f54a0f80fae..ca4b2d59c0ca 100644
--- a/fs/smbfs/request.c
+++ b/fs/smbfs/request.c
@@ -40,7 +40,7 @@ int smb_init_request_cache(void)
req_cachep = kmem_cache_create("smb_request",
sizeof(struct smb_request), 0,
SMB_SLAB_DEBUG | SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (req_cachep == NULL)
return -ENOMEM;
diff --git a/fs/splice.c b/fs/splice.c
index ed2ce995475c..0a0973218084 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -28,6 +28,7 @@
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/uio.h>
+#include <linux/security.h>
/*
* Attempt to steal a page from a pipe buffer. This should perhaps go into
@@ -264,7 +265,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
unsigned int flags)
{
struct address_space *mapping = in->f_mapping;
- unsigned int loff, nr_pages;
+ unsigned int loff, nr_pages, req_pages;
struct page *pages[PIPE_BUFFERS];
struct partial_page partial[PIPE_BUFFERS];
struct page *page;
@@ -280,28 +281,24 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
index = *ppos >> PAGE_CACHE_SHIFT;
loff = *ppos & ~PAGE_CACHE_MASK;
- nr_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-
- if (nr_pages > PIPE_BUFFERS)
- nr_pages = PIPE_BUFFERS;
-
- /*
- * Don't try to 2nd guess the read-ahead logic, call into
- * page_cache_readahead() like the page cache reads would do.
- */
- page_cache_readahead(mapping, &in->f_ra, in, index, nr_pages);
+ req_pages = (len + loff + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ nr_pages = min(req_pages, (unsigned)PIPE_BUFFERS);
/*
* Lookup the (hopefully) full range of pages we need.
*/
spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, pages);
+ index += spd.nr_pages;
/*
* If find_get_pages_contig() returned fewer pages than we needed,
- * allocate the rest and fill in the holes.
+ * readahead/allocate the rest and fill in the holes.
*/
+ if (spd.nr_pages < nr_pages)
+ page_cache_sync_readahead(mapping, &in->f_ra, in,
+ index, req_pages - spd.nr_pages);
+
error = 0;
- index += spd.nr_pages;
while (spd.nr_pages < nr_pages) {
/*
* Page could be there, find_get_pages_contig() breaks on
@@ -310,12 +307,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
page = find_get_page(mapping, index);
if (!page) {
/*
- * Make sure the read-ahead engine is notified
- * about this failure.
- */
- handle_ra_miss(mapping, &in->f_ra, index);
-
- /*
* page didn't exist, allocate one.
*/
page = page_cache_alloc_cold(mapping);
@@ -360,6 +351,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
this_len = min_t(unsigned long, len, PAGE_CACHE_SIZE - loff);
page = pages[page_nr];
+ if (PageReadahead(page))
+ page_cache_async_readahead(mapping, &in->f_ra, in,
+ page, index, req_pages - page_nr);
+
/*
* If the page isn't uptodate, we may need to start io on it
*/
@@ -452,6 +447,7 @@ fill_it:
*/
while (page_nr < nr_pages)
page_cache_release(pages[page_nr++]);
+ in->f_ra.prev_index = index;
if (spd.nr_pages)
return splice_to_pipe(pipe, &spd);
@@ -491,7 +487,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
ret = 0;
spliced = 0;
- while (len) {
+ while (len && !spliced) {
ret = __generic_file_splice_read(in, ppos, pipe, len, flags);
if (ret < 0)
@@ -598,7 +594,7 @@ find_page:
ret = add_to_page_cache_lru(page, mapping, index,
GFP_KERNEL);
if (unlikely(ret))
- goto out;
+ goto out_release;
}
ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len);
@@ -654,8 +650,9 @@ find_page:
*/
mark_page_accessed(page);
out:
- page_cache_release(page);
unlock_page(page);
+out_release:
+ page_cache_release(page);
out_ret:
return ret;
}
@@ -961,6 +958,10 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
if (unlikely(ret < 0))
return ret;
+ ret = security_file_permission(out, MAY_WRITE);
+ if (unlikely(ret < 0))
+ return ret;
+
return out->f_op->splice_write(pipe, out, ppos, len, flags);
}
@@ -983,6 +984,10 @@ static long do_splice_to(struct file *in, loff_t *ppos,
if (unlikely(ret < 0))
return ret;
+ ret = security_file_permission(in, MAY_READ);
+ if (unlikely(ret < 0))
+ return ret;
+
return in->f_op->splice_read(in, ppos, pipe, len, flags);
}
@@ -1051,15 +1056,11 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
sd->flags &= ~SPLICE_F_NONBLOCK;
while (len) {
- size_t read_len, max_read_len;
+ size_t read_len;
+ loff_t pos = sd->pos;
- /*
- * Do at most PIPE_BUFFERS pages worth of transfer:
- */
- max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE));
-
- ret = do_splice_to(in, &sd->pos, pipe, max_read_len, flags);
- if (unlikely(ret < 0))
+ ret = do_splice_to(in, &pos, pipe, len, flags);
+ if (unlikely(ret <= 0))
goto out_release;
read_len = ret;
@@ -1071,26 +1072,18 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
* could get stuck data in the internal pipe:
*/
ret = actor(pipe, sd);
- if (unlikely(ret < 0))
+ if (unlikely(ret <= 0))
goto out_release;
bytes += ret;
len -= ret;
+ sd->pos = pos;
- /*
- * In nonblocking mode, if we got back a short read then
- * that was due to either an IO error or due to the
- * pagecache entry not being there. In the IO error case
- * the _next_ splice attempt will produce a clean IO error
- * return value (not a short read), so in both cases it's
- * correct to break out of the loop here:
- */
- if ((flags & SPLICE_F_NONBLOCK) && (read_len < max_read_len))
- break;
+ if (ret < read_len)
+ goto out_release;
}
pipe->nrbufs = pipe->curbuf = 0;
-
return bytes;
out_release:
@@ -1152,10 +1145,12 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
.pos = *ppos,
.u.file = out,
};
- size_t ret;
+ long ret;
ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
- *ppos = sd.pos;
+ if (ret > 0)
+ *ppos += ret;
+
return ret;
}
diff --git a/fs/super.c b/fs/super.c
index 5260d620c555..fc8ebedc6bed 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -884,6 +884,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
error = type->get_sb(type, flags, name, data, mnt);
if (error < 0)
goto out_free_secdata;
+ BUG_ON(!mnt->mnt_sb);
error = security_sb_kern_mount(mnt->mnt_sb, secdata);
if (error)
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index d3b9f5f07db1..135353f8a296 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -20,29 +20,41 @@
#include "sysfs.h"
+struct bin_buffer {
+ struct mutex mutex;
+ void *buffer;
+ int mmapped;
+};
+
static int
fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
{
- struct bin_attribute * attr = to_bin_attr(dentry);
- struct kobject * kobj = to_kobj(dentry->d_parent);
+ struct sysfs_dirent *attr_sd = dentry->d_fsdata;
+ struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
+ struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ int rc;
+
+ /* need attr_sd for attr, its parent for kobj */
+ if (!sysfs_get_active_two(attr_sd))
+ return -ENODEV;
- if (!attr->read)
- return -EIO;
+ rc = -EIO;
+ if (attr->read)
+ rc = attr->read(kobj, attr, buffer, off, count);
- return attr->read(kobj, buffer, off, count);
+ sysfs_put_active_two(attr_sd);
+
+ return rc;
}
static ssize_t
-read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
+read(struct file *file, char __user *userbuf, size_t bytes, loff_t *off)
{
- char *buffer = file->private_data;
+ struct bin_buffer *bb = file->private_data;
struct dentry *dentry = file->f_path.dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
- int ret;
-
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
+ int count = min_t(size_t, bytes, PAGE_SIZE);
if (size) {
if (offs > size)
@@ -51,43 +63,56 @@ read(struct file * file, char __user * userbuf, size_t count, loff_t * off)
count = size - offs;
}
- ret = fill_read(dentry, buffer, offs, count);
- if (ret < 0)
- return ret;
- count = ret;
+ mutex_lock(&bb->mutex);
+
+ count = fill_read(dentry, bb->buffer, offs, count);
+ if (count < 0)
+ goto out_unlock;
- if (copy_to_user(userbuf, buffer, count))
- return -EFAULT;
+ if (copy_to_user(userbuf, bb->buffer, count)) {
+ count = -EFAULT;
+ goto out_unlock;
+ }
- pr_debug("offs = %lld, *off = %lld, count = %zd\n", offs, *off, count);
+ pr_debug("offs = %lld, *off = %lld, count = %d\n", offs, *off, count);
*off = offs + count;
+ out_unlock:
+ mutex_unlock(&bb->mutex);
return count;
}
static int
flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
{
- struct bin_attribute *attr = to_bin_attr(dentry);
- struct kobject *kobj = to_kobj(dentry->d_parent);
+ struct sysfs_dirent *attr_sd = dentry->d_fsdata;
+ struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
+ struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ int rc;
+
+ /* need attr_sd for attr, its parent for kobj */
+ if (!sysfs_get_active_two(attr_sd))
+ return -ENODEV;
+
+ rc = -EIO;
+ if (attr->write)
+ rc = attr->write(kobj, attr, buffer, offset, count);
- if (!attr->write)
- return -EIO;
+ sysfs_put_active_two(attr_sd);
- return attr->write(kobj, buffer, offset, count);
+ return rc;
}
-static ssize_t write(struct file * file, const char __user * userbuf,
- size_t count, loff_t * off)
+static ssize_t write(struct file *file, const char __user *userbuf,
+ size_t bytes, loff_t *off)
{
- char *buffer = file->private_data;
+ struct bin_buffer *bb = file->private_data;
struct dentry *dentry = file->f_path.dentry;
int size = dentry->d_inode->i_size;
loff_t offs = *off;
+ int count = min_t(size_t, bytes, PAGE_SIZE);
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
if (size) {
if (offs > size)
return 0;
@@ -95,72 +120,100 @@ static ssize_t write(struct file * file, const char __user * userbuf,
count = size - offs;
}
- if (copy_from_user(buffer, userbuf, count))
- return -EFAULT;
+ mutex_lock(&bb->mutex);
- count = flush_write(dentry, buffer, offs, count);
+ if (copy_from_user(bb->buffer, userbuf, count)) {
+ count = -EFAULT;
+ goto out_unlock;
+ }
+
+ count = flush_write(dentry, bb->buffer, offs, count);
if (count > 0)
*off = offs + count;
+
+ out_unlock:
+ mutex_unlock(&bb->mutex);
return count;
}
static int mmap(struct file *file, struct vm_area_struct *vma)
{
- struct dentry *dentry = file->f_path.dentry;
- struct bin_attribute *attr = to_bin_attr(dentry);
- struct kobject *kobj = to_kobj(dentry->d_parent);
+ struct bin_buffer *bb = file->private_data;
+ struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+ struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
+ struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+ int rc;
+
+ mutex_lock(&bb->mutex);
+
+ /* need attr_sd for attr, its parent for kobj */
+ if (!sysfs_get_active_two(attr_sd))
+ return -ENODEV;
- if (!attr->mmap)
- return -EINVAL;
+ rc = -EINVAL;
+ if (attr->mmap)
+ rc = attr->mmap(kobj, attr, vma);
- return attr->mmap(kobj, attr, vma);
+ if (rc == 0 && !bb->mmapped)
+ bb->mmapped = 1;
+ else
+ sysfs_put_active_two(attr_sd);
+
+ mutex_unlock(&bb->mutex);
+
+ return rc;
}
static int open(struct inode * inode, struct file * file)
{
- struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
- struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
- int error = -EINVAL;
-
- if (!kobj || !attr)
- goto Done;
+ struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+ struct bin_attribute *attr = attr_sd->s_elem.bin_attr.bin_attr;
+ struct bin_buffer *bb = NULL;
+ int error;
- /* Grab the module reference for this attribute if we have one */
- error = -ENODEV;
- if (!try_module_get(attr->attr.owner))
- goto Done;
+ /* need attr_sd for attr */
+ if (!sysfs_get_active(attr_sd))
+ return -ENODEV;
error = -EACCES;
if ((file->f_mode & FMODE_WRITE) && !(attr->write || attr->mmap))
- goto Error;
+ goto err_out;
if ((file->f_mode & FMODE_READ) && !(attr->read || attr->mmap))
- goto Error;
+ goto err_out;
error = -ENOMEM;
- file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!file->private_data)
- goto Error;
-
- error = 0;
- goto Done;
-
- Error:
- module_put(attr->attr.owner);
- Done:
- if (error)
- kobject_put(kobj);
+ bb = kzalloc(sizeof(*bb), GFP_KERNEL);
+ if (!bb)
+ goto err_out;
+
+ bb->buffer = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!bb->buffer)
+ goto err_out;
+
+ mutex_init(&bb->mutex);
+ file->private_data = bb;
+
+ /* open succeeded, put active reference and pin attr_sd */
+ sysfs_put_active(attr_sd);
+ sysfs_get(attr_sd);
+ return 0;
+
+ err_out:
+ sysfs_put_active(attr_sd);
+ kfree(bb);
return error;
}
static int release(struct inode * inode, struct file * file)
{
- struct kobject * kobj = to_kobj(file->f_path.dentry->d_parent);
- struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
- u8 * buffer = file->private_data;
-
- kobject_put(kobj);
- module_put(attr->attr.owner);
- kfree(buffer);
+ struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+ struct bin_buffer *bb = file->private_data;
+
+ if (bb->mmapped)
+ sysfs_put_active_two(attr_sd);
+ sysfs_put(attr_sd);
+ kfree(bb->buffer);
+ kfree(bb);
return 0;
}
@@ -181,9 +234,9 @@ const struct file_operations bin_fops = {
int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
{
- BUG_ON(!kobj || !kobj->dentry || !attr);
+ BUG_ON(!kobj || !kobj->sd || !attr);
- return sysfs_add_file(kobj->dentry, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
+ return sysfs_add_file(kobj->sd, &attr->attr, SYSFS_KOBJ_BIN_ATTR);
}
@@ -195,7 +248,7 @@ int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr)
void sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr)
{
- if (sysfs_hash_and_remove(kobj->dentry, attr->attr.name) < 0) {
+ if (sysfs_hash_and_remove(kobj->sd, attr->attr.name) < 0) {
printk(KERN_ERR "%s: "
"bad dentry or inode or no such file: \"%s\"\n",
__FUNCTION__, attr->attr.name);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index c4342a019972..048e6054c2fd 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -9,21 +9,337 @@
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/namei.h>
+#include <linux/idr.h>
+#include <linux/completion.h>
#include <asm/semaphore.h>
#include "sysfs.h"
-DECLARE_RWSEM(sysfs_rename_sem);
-spinlock_t sysfs_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_MUTEX(sysfs_mutex);
+spinlock_t sysfs_assoc_lock = SPIN_LOCK_UNLOCKED;
+
+static spinlock_t sysfs_ino_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_IDA(sysfs_ino_ida);
+
+/**
+ * sysfs_link_sibling - link sysfs_dirent into sibling list
+ * @sd: sysfs_dirent of interest
+ *
+ * Link @sd into its sibling list which starts from
+ * sd->s_parent->s_children.
+ *
+ * Locking:
+ * mutex_lock(sysfs_mutex)
+ */
+void sysfs_link_sibling(struct sysfs_dirent *sd)
+{
+ struct sysfs_dirent *parent_sd = sd->s_parent;
+
+ BUG_ON(sd->s_sibling);
+ sd->s_sibling = parent_sd->s_children;
+ parent_sd->s_children = sd;
+}
+
+/**
+ * sysfs_unlink_sibling - unlink sysfs_dirent from sibling list
+ * @sd: sysfs_dirent of interest
+ *
+ * Unlink @sd from its sibling list which starts from
+ * sd->s_parent->s_children.
+ *
+ * Locking:
+ * mutex_lock(sysfs_mutex)
+ */
+void sysfs_unlink_sibling(struct sysfs_dirent *sd)
+{
+ struct sysfs_dirent **pos;
+
+ for (pos = &sd->s_parent->s_children; *pos; pos = &(*pos)->s_sibling) {
+ if (*pos == sd) {
+ *pos = sd->s_sibling;
+ sd->s_sibling = NULL;
+ break;
+ }
+ }
+}
+
+/**
+ * sysfs_get_dentry - get dentry for the given sysfs_dirent
+ * @sd: sysfs_dirent of interest
+ *
+ * Get dentry for @sd. Dentry is looked up if currently not
+ * present. This function climbs sysfs_dirent tree till it
+ * reaches a sysfs_dirent with valid dentry attached and descends
+ * down from there looking up dentry for each step.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * Pointer to found dentry on success, ERR_PTR() value on error.
+ */
+struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd)
+{
+ struct sysfs_dirent *cur;
+ struct dentry *parent_dentry, *dentry;
+ int i, depth;
+
+ /* Find the first parent which has valid s_dentry and get the
+ * dentry.
+ */
+ mutex_lock(&sysfs_mutex);
+ restart0:
+ spin_lock(&sysfs_assoc_lock);
+ restart1:
+ spin_lock(&dcache_lock);
+
+ dentry = NULL;
+ depth = 0;
+ cur = sd;
+ while (!cur->s_dentry || !cur->s_dentry->d_inode) {
+ if (cur->s_flags & SYSFS_FLAG_REMOVED) {
+ dentry = ERR_PTR(-ENOENT);
+ depth = 0;
+ break;
+ }
+ cur = cur->s_parent;
+ depth++;
+ }
+ if (!IS_ERR(dentry))
+ dentry = dget_locked(cur->s_dentry);
+
+ spin_unlock(&dcache_lock);
+ spin_unlock(&sysfs_assoc_lock);
+
+ /* from the found dentry, look up depth times */
+ while (depth--) {
+ /* find and get depth'th ancestor */
+ for (cur = sd, i = 0; cur && i < depth; i++)
+ cur = cur->s_parent;
+
+ /* This can happen if tree structure was modified due
+ * to move/rename. Restart.
+ */
+ if (i != depth) {
+ dput(dentry);
+ goto restart0;
+ }
+
+ sysfs_get(cur);
+
+ mutex_unlock(&sysfs_mutex);
+
+ /* look it up */
+ parent_dentry = dentry;
+ dentry = lookup_one_len_kern(cur->s_name, parent_dentry,
+ strlen(cur->s_name));
+ dput(parent_dentry);
+
+ if (IS_ERR(dentry)) {
+ sysfs_put(cur);
+ return dentry;
+ }
+
+ mutex_lock(&sysfs_mutex);
+ spin_lock(&sysfs_assoc_lock);
+
+ /* This, again, can happen if tree structure has
+ * changed and we looked up the wrong thing. Restart.
+ */
+ if (cur->s_dentry != dentry) {
+ dput(dentry);
+ sysfs_put(cur);
+ goto restart1;
+ }
+
+ spin_unlock(&sysfs_assoc_lock);
+
+ sysfs_put(cur);
+ }
+
+ mutex_unlock(&sysfs_mutex);
+ return dentry;
+}
+
+/**
+ * sysfs_get_active - get an active reference to sysfs_dirent
+ * @sd: sysfs_dirent to get an active reference to
+ *
+ * Get an active reference of @sd. This function is noop if @sd
+ * is NULL.
+ *
+ * RETURNS:
+ * Pointer to @sd on success, NULL on failure.
+ */
+struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd)
+{
+ if (unlikely(!sd))
+ return NULL;
+
+ while (1) {
+ int v, t;
+
+ v = atomic_read(&sd->s_active);
+ if (unlikely(v < 0))
+ return NULL;
+
+ t = atomic_cmpxchg(&sd->s_active, v, v + 1);
+ if (likely(t == v))
+ return sd;
+ if (t < 0)
+ return NULL;
+
+ cpu_relax();
+ }
+}
+
+/**
+ * sysfs_put_active - put an active reference to sysfs_dirent
+ * @sd: sysfs_dirent to put an active reference to
+ *
+ * Put an active reference to @sd. This function is noop if @sd
+ * is NULL.
+ */
+void sysfs_put_active(struct sysfs_dirent *sd)
+{
+ struct completion *cmpl;
+ int v;
+
+ if (unlikely(!sd))
+ return;
+
+ v = atomic_dec_return(&sd->s_active);
+ if (likely(v != SD_DEACTIVATED_BIAS))
+ return;
+
+ /* atomic_dec_return() is a mb(), we'll always see the updated
+ * sd->s_sibling.
+ */
+ cmpl = (void *)sd->s_sibling;
+ complete(cmpl);
+}
+
+/**
+ * sysfs_get_active_two - get active references to sysfs_dirent and parent
+ * @sd: sysfs_dirent of interest
+ *
+ * Get active reference to @sd and its parent. Parent's active
+ * reference is grabbed first. This function is noop if @sd is
+ * NULL.
+ *
+ * RETURNS:
+ * Pointer to @sd on success, NULL on failure.
+ */
+struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd)
+{
+ if (sd) {
+ if (sd->s_parent && unlikely(!sysfs_get_active(sd->s_parent)))
+ return NULL;
+ if (unlikely(!sysfs_get_active(sd))) {
+ sysfs_put_active(sd->s_parent);
+ return NULL;
+ }
+ }
+ return sd;
+}
+
+/**
+ * sysfs_put_active_two - put active references to sysfs_dirent and parent
+ * @sd: sysfs_dirent of interest
+ *
+ * Put active references to @sd and its parent. This function is
+ * noop if @sd is NULL.
+ */
+void sysfs_put_active_two(struct sysfs_dirent *sd)
+{
+ if (sd) {
+ sysfs_put_active(sd);
+ sysfs_put_active(sd->s_parent);
+ }
+}
+
+/**
+ * sysfs_deactivate - deactivate sysfs_dirent
+ * @sd: sysfs_dirent to deactivate
+ *
+ * Deny new active references and drain existing ones.
+ */
+static void sysfs_deactivate(struct sysfs_dirent *sd)
+{
+ DECLARE_COMPLETION_ONSTACK(wait);
+ int v;
+
+ BUG_ON(sd->s_sibling || !(sd->s_flags & SYSFS_FLAG_REMOVED));
+ sd->s_sibling = (void *)&wait;
+
+ /* atomic_add_return() is a mb(), put_active() will always see
+ * the updated sd->s_sibling.
+ */
+ v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active);
+
+ if (v != SD_DEACTIVATED_BIAS)
+ wait_for_completion(&wait);
+
+ sd->s_sibling = NULL;
+}
+
+static int sysfs_alloc_ino(ino_t *pino)
+{
+ int ino, rc;
+
+ retry:
+ spin_lock(&sysfs_ino_lock);
+ rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino);
+ spin_unlock(&sysfs_ino_lock);
+
+ if (rc == -EAGAIN) {
+ if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL))
+ goto retry;
+ rc = -ENOMEM;
+ }
+
+ *pino = ino;
+ return rc;
+}
+
+static void sysfs_free_ino(ino_t ino)
+{
+ spin_lock(&sysfs_ino_lock);
+ ida_remove(&sysfs_ino_ida, ino);
+ spin_unlock(&sysfs_ino_lock);
+}
+
+void release_sysfs_dirent(struct sysfs_dirent * sd)
+{
+ struct sysfs_dirent *parent_sd;
+
+ repeat:
+ /* Moving/renaming is always done while holding reference.
+ * sd->s_parent won't change beneath us.
+ */
+ parent_sd = sd->s_parent;
+
+ if (sysfs_type(sd) == SYSFS_KOBJ_LINK)
+ sysfs_put(sd->s_elem.symlink.target_sd);
+ if (sysfs_type(sd) & SYSFS_COPY_NAME)
+ kfree(sd->s_name);
+ kfree(sd->s_iattr);
+ sysfs_free_ino(sd->s_ino);
+ kmem_cache_free(sysfs_dir_cachep, sd);
+
+ sd = parent_sd;
+ if (sd && atomic_dec_and_test(&sd->s_count))
+ goto repeat;
+}
static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
{
struct sysfs_dirent * sd = dentry->d_fsdata;
if (sd) {
- /* sd->s_dentry is protected with sysfs_lock. This
- * allows sysfs_drop_dentry() to dereference it.
+ /* sd->s_dentry is protected with sysfs_assoc_lock.
+ * This allows sysfs_drop_dentry() to dereference it.
*/
- spin_lock(&sysfs_lock);
+ spin_lock(&sysfs_assoc_lock);
/* The dentry might have been deleted or another
* lookup could have happened updating sd->s_dentry to
@@ -32,7 +348,7 @@ static void sysfs_d_iput(struct dentry * dentry, struct inode * inode)
*/
if (sd->s_dentry == dentry)
sd->s_dentry = NULL;
- spin_unlock(&sysfs_lock);
+ spin_unlock(&sysfs_assoc_lock);
sysfs_put(sd);
}
iput(inode);
@@ -42,260 +358,405 @@ static struct dentry_operations sysfs_dentry_ops = {
.d_iput = sysfs_d_iput,
};
-static unsigned int sysfs_inode_counter;
-ino_t sysfs_get_inum(void)
+struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
{
- if (unlikely(sysfs_inode_counter < 3))
- sysfs_inode_counter = 3;
- return sysfs_inode_counter++;
-}
+ char *dup_name = NULL;
+ struct sysfs_dirent *sd;
-/*
- * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
- */
-static struct sysfs_dirent * __sysfs_new_dirent(void * element)
-{
- struct sysfs_dirent * sd;
+ if (type & SYSFS_COPY_NAME) {
+ name = dup_name = kstrdup(name, GFP_KERNEL);
+ if (!name)
+ return NULL;
+ }
sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL);
if (!sd)
- return NULL;
+ goto err_out1;
+
+ if (sysfs_alloc_ino(&sd->s_ino))
+ goto err_out2;
- sd->s_ino = sysfs_get_inum();
atomic_set(&sd->s_count, 1);
+ atomic_set(&sd->s_active, 0);
atomic_set(&sd->s_event, 1);
- INIT_LIST_HEAD(&sd->s_children);
- INIT_LIST_HEAD(&sd->s_sibling);
- sd->s_element = element;
+
+ sd->s_name = name;
+ sd->s_mode = mode;
+ sd->s_flags = type;
return sd;
+
+ err_out2:
+ kmem_cache_free(sysfs_dir_cachep, sd);
+ err_out1:
+ kfree(dup_name);
+ return NULL;
}
-static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd,
- struct sysfs_dirent *sd)
+/**
+ * sysfs_attach_dentry - associate sysfs_dirent with dentry
+ * @sd: target sysfs_dirent
+ * @dentry: dentry to associate
+ *
+ * Associate @sd with @dentry. This is protected by
+ * sysfs_assoc_lock to avoid race with sysfs_d_iput().
+ *
+ * LOCKING:
+ * mutex_lock(sysfs_mutex)
+ */
+static void sysfs_attach_dentry(struct sysfs_dirent *sd, struct dentry *dentry)
{
- if (sd)
- list_add(&sd->s_sibling, &parent_sd->s_children);
+ dentry->d_op = &sysfs_dentry_ops;
+ dentry->d_fsdata = sysfs_get(sd);
+
+ /* protect sd->s_dentry against sysfs_d_iput */
+ spin_lock(&sysfs_assoc_lock);
+ sd->s_dentry = dentry;
+ spin_unlock(&sysfs_assoc_lock);
+
+ d_rehash(dentry);
}
-static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd,
- void * element)
+static int sysfs_ilookup_test(struct inode *inode, void *arg)
{
- struct sysfs_dirent *sd;
- sd = __sysfs_new_dirent(element);
- __sysfs_list_dirent(parent_sd, sd);
- return sd;
+ struct sysfs_dirent *sd = arg;
+ return inode->i_ino == sd->s_ino;
}
-/*
+/**
+ * sysfs_addrm_start - prepare for sysfs_dirent add/remove
+ * @acxt: pointer to sysfs_addrm_cxt to be used
+ * @parent_sd: parent sysfs_dirent
*
- * Return -EEXIST if there is already a sysfs element with the same name for
- * the same parent.
+ * This function is called when the caller is about to add or
+ * remove sysfs_dirent under @parent_sd. This function acquires
+ * sysfs_mutex, grabs inode for @parent_sd if available and lock
+ * i_mutex of it. @acxt is used to keep and pass context to
+ * other addrm functions.
*
- * called with parent inode's i_mutex held
+ * LOCKING:
+ * Kernel thread context (may sleep). sysfs_mutex is locked on
+ * return. i_mutex of parent inode is locked on return if
+ * available.
*/
-int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
- const unsigned char *new)
+void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
+ struct sysfs_dirent *parent_sd)
{
- struct sysfs_dirent * sd;
+ struct inode *inode;
- list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
- if (sd->s_element) {
- const unsigned char *existing = sysfs_get_name(sd);
- if (strcmp(existing, new))
- continue;
- else
- return -EEXIST;
- }
- }
+ memset(acxt, 0, sizeof(*acxt));
+ acxt->parent_sd = parent_sd;
- return 0;
+ /* Lookup parent inode. inode initialization and I_NEW
+ * clearing are protected by sysfs_mutex. By grabbing it and
+ * looking up with _nowait variant, inode state can be
+ * determined reliably.
+ */
+ mutex_lock(&sysfs_mutex);
+
+ inode = ilookup5_nowait(sysfs_sb, parent_sd->s_ino, sysfs_ilookup_test,
+ parent_sd);
+
+ if (inode && !(inode->i_state & I_NEW)) {
+ /* parent inode available */
+ acxt->parent_inode = inode;
+
+ /* sysfs_mutex is below i_mutex in lock hierarchy.
+ * First, trylock i_mutex. If fails, unlock
+ * sysfs_mutex and lock them in order.
+ */
+ if (!mutex_trylock(&inode->i_mutex)) {
+ mutex_unlock(&sysfs_mutex);
+ mutex_lock(&inode->i_mutex);
+ mutex_lock(&sysfs_mutex);
+ }
+ } else
+ iput(inode);
}
+/**
+ * sysfs_add_one - add sysfs_dirent to parent
+ * @acxt: addrm context to use
+ * @sd: sysfs_dirent to be added
+ *
+ * Get @acxt->parent_sd and set sd->s_parent to it and increment
+ * nlink of parent inode if @sd is a directory. @sd is NOT
+ * linked into the children list of the parent. The caller
+ * should invoke sysfs_link_sibling() after this function
+ * completes if @sd needs to be on the children list.
+ *
+ * This function should be called between calls to
+ * sysfs_addrm_start() and sysfs_addrm_finish() and should be
+ * passed the same @acxt as passed to sysfs_addrm_start().
+ *
+ * LOCKING:
+ * Determined by sysfs_addrm_start().
+ */
+void sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
+{
+ sd->s_parent = sysfs_get(acxt->parent_sd);
+
+ if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
+ inc_nlink(acxt->parent_inode);
-static struct sysfs_dirent *
-__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
+ acxt->cnt++;
+}
+
+/**
+ * sysfs_remove_one - remove sysfs_dirent from parent
+ * @acxt: addrm context to use
+ * @sd: sysfs_dirent to be added
+ *
+ * Mark @sd removed and drop nlink of parent inode if @sd is a
+ * directory. @sd is NOT unlinked from the children list of the
+ * parent. The caller is repsonsible for removing @sd from the
+ * children list before calling this function.
+ *
+ * This function should be called between calls to
+ * sysfs_addrm_start() and sysfs_addrm_finish() and should be
+ * passed the same @acxt as passed to sysfs_addrm_start().
+ *
+ * LOCKING:
+ * Determined by sysfs_addrm_start().
+ */
+void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
{
- struct sysfs_dirent * sd;
+ BUG_ON(sd->s_sibling || (sd->s_flags & SYSFS_FLAG_REMOVED));
- sd = __sysfs_new_dirent(element);
- if (!sd)
- goto out;
+ sd->s_flags |= SYSFS_FLAG_REMOVED;
+ sd->s_sibling = acxt->removed;
+ acxt->removed = sd;
- sd->s_mode = mode;
- sd->s_type = type;
- sd->s_dentry = dentry;
- if (dentry) {
- dentry->d_fsdata = sysfs_get(sd);
- dentry->d_op = &sysfs_dentry_ops;
- }
+ if (sysfs_type(sd) == SYSFS_DIR && acxt->parent_inode)
+ drop_nlink(acxt->parent_inode);
-out:
- return sd;
+ acxt->cnt++;
}
-int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
- void * element, umode_t mode, int type)
+/**
+ * sysfs_drop_dentry - drop dentry for the specified sysfs_dirent
+ * @sd: target sysfs_dirent
+ *
+ * Drop dentry for @sd. @sd must have been unlinked from its
+ * parent on entry to this function such that it can't be looked
+ * up anymore.
+ *
+ * @sd->s_dentry which is protected with sysfs_assoc_lock points
+ * to the currently associated dentry but we're not holding a
+ * reference to it and racing with dput(). Grab dcache_lock and
+ * verify dentry before dropping it. If @sd->s_dentry is NULL or
+ * dput() beats us, no need to bother.
+ */
+static void sysfs_drop_dentry(struct sysfs_dirent *sd)
{
- struct sysfs_dirent *sd;
+ struct dentry *dentry = NULL;
+ struct inode *inode;
- sd = __sysfs_make_dirent(dentry, element, mode, type);
- __sysfs_list_dirent(parent_sd, sd);
+ /* We're not holding a reference to ->s_dentry dentry but the
+ * field will stay valid as long as sysfs_assoc_lock is held.
+ */
+ spin_lock(&sysfs_assoc_lock);
+ spin_lock(&dcache_lock);
+
+ /* drop dentry if it's there and dput() didn't kill it yet */
+ if (sd->s_dentry && sd->s_dentry->d_inode) {
+ dentry = dget_locked(sd->s_dentry);
+ spin_lock(&dentry->d_lock);
+ __d_drop(dentry);
+ spin_unlock(&dentry->d_lock);
+ }
- return sd ? 0 : -ENOMEM;
+ spin_unlock(&dcache_lock);
+ spin_unlock(&sysfs_assoc_lock);
+
+ /* dentries for shadowed inodes are pinned, unpin */
+ if (dentry && sysfs_is_shadowed_inode(dentry->d_inode))
+ dput(dentry);
+ dput(dentry);
+
+ /* adjust nlink and update timestamp */
+ inode = ilookup(sysfs_sb, sd->s_ino);
+ if (inode) {
+ mutex_lock(&inode->i_mutex);
+
+ inode->i_ctime = CURRENT_TIME;
+ drop_nlink(inode);
+ if (sysfs_type(sd) == SYSFS_DIR)
+ drop_nlink(inode);
+
+ mutex_unlock(&inode->i_mutex);
+ iput(inode);
+ }
}
-static int init_dir(struct inode * inode)
+/**
+ * sysfs_addrm_finish - finish up sysfs_dirent add/remove
+ * @acxt: addrm context to finish up
+ *
+ * Finish up sysfs_dirent add/remove. Resources acquired by
+ * sysfs_addrm_start() are released and removed sysfs_dirents are
+ * cleaned up. Timestamps on the parent inode are updated.
+ *
+ * LOCKING:
+ * All mutexes acquired by sysfs_addrm_start() are released.
+ *
+ * RETURNS:
+ * Number of added/removed sysfs_dirents since sysfs_addrm_start().
+ */
+int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
{
- inode->i_op = &sysfs_dir_inode_operations;
- inode->i_fop = &sysfs_dir_operations;
+ /* release resources acquired by sysfs_addrm_start() */
+ mutex_unlock(&sysfs_mutex);
+ if (acxt->parent_inode) {
+ struct inode *inode = acxt->parent_inode;
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
- inc_nlink(inode);
- return 0;
+ /* if added/removed, update timestamps on the parent */
+ if (acxt->cnt)
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+
+ mutex_unlock(&inode->i_mutex);
+ iput(inode);
+ }
+
+ /* kill removed sysfs_dirents */
+ while (acxt->removed) {
+ struct sysfs_dirent *sd = acxt->removed;
+
+ acxt->removed = sd->s_sibling;
+ sd->s_sibling = NULL;
+
+ sysfs_drop_dentry(sd);
+ sysfs_deactivate(sd);
+ sysfs_put(sd);
+ }
+
+ return acxt->cnt;
}
-static int init_file(struct inode * inode)
+/**
+ * sysfs_find_dirent - find sysfs_dirent with the given name
+ * @parent_sd: sysfs_dirent to search under
+ * @name: name to look for
+ *
+ * Look for sysfs_dirent with name @name under @parent_sd.
+ *
+ * LOCKING:
+ * mutex_lock(sysfs_mutex)
+ *
+ * RETURNS:
+ * Pointer to sysfs_dirent if found, NULL if not.
+ */
+struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
+ const unsigned char *name)
{
- inode->i_size = PAGE_SIZE;
- inode->i_fop = &sysfs_file_operations;
- return 0;
+ struct sysfs_dirent *sd;
+
+ for (sd = parent_sd->s_children; sd; sd = sd->s_sibling)
+ if (sysfs_type(sd) && !strcmp(sd->s_name, name))
+ return sd;
+ return NULL;
}
-static int init_symlink(struct inode * inode)
+/**
+ * sysfs_get_dirent - find and get sysfs_dirent with the given name
+ * @parent_sd: sysfs_dirent to search under
+ * @name: name to look for
+ *
+ * Look for sysfs_dirent with name @name under @parent_sd and get
+ * it if found.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep). Grabs sysfs_mutex.
+ *
+ * RETURNS:
+ * Pointer to sysfs_dirent if found, NULL if not.
+ */
+struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
+ const unsigned char *name)
{
- inode->i_op = &sysfs_symlink_inode_operations;
- return 0;
+ struct sysfs_dirent *sd;
+
+ mutex_lock(&sysfs_mutex);
+ sd = sysfs_find_dirent(parent_sd, name);
+ sysfs_get(sd);
+ mutex_unlock(&sysfs_mutex);
+
+ return sd;
}
-static int create_dir(struct kobject * k, struct dentry * p,
- const char * n, struct dentry ** d)
+static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
+ const char *name, struct sysfs_dirent **p_sd)
{
- int error;
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
+ struct sysfs_addrm_cxt acxt;
+ struct sysfs_dirent *sd;
- mutex_lock(&p->d_inode->i_mutex);
- *d = lookup_one_len(n, p, strlen(n));
- if (!IS_ERR(*d)) {
- if (sysfs_dirent_exist(p->d_fsdata, n))
- error = -EEXIST;
- else
- error = sysfs_make_dirent(p->d_fsdata, *d, k, mode,
- SYSFS_DIR);
- if (!error) {
- error = sysfs_create(*d, mode, init_dir);
- if (!error) {
- inc_nlink(p->d_inode);
- (*d)->d_op = &sysfs_dentry_ops;
- d_rehash(*d);
- }
- }
- if (error && (error != -EEXIST)) {
- struct sysfs_dirent *sd = (*d)->d_fsdata;
- if (sd) {
- list_del_init(&sd->s_sibling);
- sysfs_put(sd);
- }
- d_drop(*d);
- }
- dput(*d);
- } else
- error = PTR_ERR(*d);
- mutex_unlock(&p->d_inode->i_mutex);
- return error;
-}
+ /* allocate */
+ sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
+ if (!sd)
+ return -ENOMEM;
+ sd->s_elem.dir.kobj = kobj;
+ /* link in */
+ sysfs_addrm_start(&acxt, parent_sd);
-int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
+ if (!sysfs_find_dirent(parent_sd, name)) {
+ sysfs_add_one(&acxt, sd);
+ sysfs_link_sibling(sd);
+ }
+
+ if (!sysfs_addrm_finish(&acxt)) {
+ sysfs_put(sd);
+ return -EEXIST;
+ }
+
+ *p_sd = sd;
+ return 0;
+}
+
+int sysfs_create_subdir(struct kobject *kobj, const char *name,
+ struct sysfs_dirent **p_sd)
{
- return create_dir(k,k->dentry,n,d);
+ return create_dir(kobj, kobj->sd, name, p_sd);
}
/**
* sysfs_create_dir - create a directory for an object.
* @kobj: object we're creating directory for.
- * @shadow_parent: parent parent object.
+ * @shadow_parent: parent object.
*/
-
-int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
+int sysfs_create_dir(struct kobject *kobj,
+ struct sysfs_dirent *shadow_parent_sd)
{
- struct dentry * dentry = NULL;
- struct dentry * parent;
+ struct sysfs_dirent *parent_sd, *sd;
int error = 0;
BUG_ON(!kobj);
- if (shadow_parent)
- parent = shadow_parent;
+ if (shadow_parent_sd)
+ parent_sd = shadow_parent_sd;
else if (kobj->parent)
- parent = kobj->parent->dentry;
+ parent_sd = kobj->parent->sd;
else if (sysfs_mount && sysfs_mount->mnt_sb)
- parent = sysfs_mount->mnt_sb->s_root;
+ parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
else
return -EFAULT;
- error = create_dir(kobj,parent,kobject_name(kobj),&dentry);
+ error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd);
if (!error)
- kobj->dentry = dentry;
+ kobj->sd = sd;
return error;
}
-/* attaches attribute's sysfs_dirent to the dentry corresponding to the
- * attribute file
- */
-static int sysfs_attach_attr(struct sysfs_dirent * sd, struct dentry * dentry)
+static int sysfs_count_nlink(struct sysfs_dirent *sd)
{
- struct attribute * attr = NULL;
- struct bin_attribute * bin_attr = NULL;
- int (* init) (struct inode *) = NULL;
- int error = 0;
-
- if (sd->s_type & SYSFS_KOBJ_BIN_ATTR) {
- bin_attr = sd->s_element;
- attr = &bin_attr->attr;
- } else {
- attr = sd->s_element;
- init = init_file;
- }
-
- dentry->d_fsdata = sysfs_get(sd);
- /* protect sd->s_dentry against sysfs_d_iput */
- spin_lock(&sysfs_lock);
- sd->s_dentry = dentry;
- spin_unlock(&sysfs_lock);
- error = sysfs_create(dentry, (attr->mode & S_IALLUGO) | S_IFREG, init);
- if (error) {
- sysfs_put(sd);
- return error;
- }
-
- if (bin_attr) {
- dentry->d_inode->i_size = bin_attr->size;
- dentry->d_inode->i_fop = &bin_fops;
- }
- dentry->d_op = &sysfs_dentry_ops;
- d_rehash(dentry);
-
- return 0;
-}
-
-static int sysfs_attach_link(struct sysfs_dirent * sd, struct dentry * dentry)
-{
- int err = 0;
-
- dentry->d_fsdata = sysfs_get(sd);
- /* protect sd->s_dentry against sysfs_d_iput */
- spin_lock(&sysfs_lock);
- sd->s_dentry = dentry;
- spin_unlock(&sysfs_lock);
- err = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
- if (!err) {
- dentry->d_op = &sysfs_dentry_ops;
- d_rehash(dentry);
- } else
- sysfs_put(sd);
+ struct sysfs_dirent *child;
+ int nr = 0;
- return err;
+ for (child = sd->s_children; child; child = child->s_sibling)
+ if (sysfs_type(child) == SYSFS_DIR)
+ nr++;
+ return nr + 2;
}
static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
@@ -303,24 +764,60 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
{
struct sysfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
struct sysfs_dirent * sd;
- int err = 0;
+ struct bin_attribute *bin_attr;
+ struct inode *inode;
+ int found = 0;
- list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
- if (sd->s_type & SYSFS_NOT_PINNED) {
- const unsigned char * name = sysfs_get_name(sd);
+ for (sd = parent_sd->s_children; sd; sd = sd->s_sibling) {
+ if (sysfs_type(sd) &&
+ !strcmp(sd->s_name, dentry->d_name.name)) {
+ found = 1;
+ break;
+ }
+ }
- if (strcmp(name, dentry->d_name.name))
- continue;
+ /* no such entry */
+ if (!found)
+ return NULL;
- if (sd->s_type & SYSFS_KOBJ_LINK)
- err = sysfs_attach_link(sd, dentry);
- else
- err = sysfs_attach_attr(sd, dentry);
+ /* attach dentry and inode */
+ inode = sysfs_get_inode(sd);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_lock(&sysfs_mutex);
+
+ if (inode->i_state & I_NEW) {
+ /* initialize inode according to type */
+ switch (sysfs_type(sd)) {
+ case SYSFS_DIR:
+ inode->i_op = &sysfs_dir_inode_operations;
+ inode->i_fop = &sysfs_dir_operations;
+ inode->i_nlink = sysfs_count_nlink(sd);
+ break;
+ case SYSFS_KOBJ_ATTR:
+ inode->i_size = PAGE_SIZE;
+ inode->i_fop = &sysfs_file_operations;
break;
+ case SYSFS_KOBJ_BIN_ATTR:
+ bin_attr = sd->s_elem.bin_attr.bin_attr;
+ inode->i_size = bin_attr->size;
+ inode->i_fop = &bin_fops;
+ break;
+ case SYSFS_KOBJ_LINK:
+ inode->i_op = &sysfs_symlink_inode_operations;
+ break;
+ default:
+ BUG();
}
}
- return ERR_PTR(err);
+ sysfs_instantiate(dentry, inode);
+ sysfs_attach_dentry(sd, dentry);
+
+ mutex_unlock(&sysfs_mutex);
+
+ return NULL;
}
const struct inode_operations sysfs_dir_inode_operations = {
@@ -328,58 +825,46 @@ const struct inode_operations sysfs_dir_inode_operations = {
.setattr = sysfs_setattr,
};
-static void remove_dir(struct dentry * d)
+static void remove_dir(struct sysfs_dirent *sd)
{
- struct dentry * parent = dget(d->d_parent);
- struct sysfs_dirent * sd;
+ struct sysfs_addrm_cxt acxt;
- mutex_lock(&parent->d_inode->i_mutex);
- d_delete(d);
- sd = d->d_fsdata;
- list_del_init(&sd->s_sibling);
- sysfs_put(sd);
- if (d->d_inode)
- simple_rmdir(parent->d_inode,d);
-
- pr_debug(" o %s removing done (%d)\n",d->d_name.name,
- atomic_read(&d->d_count));
-
- mutex_unlock(&parent->d_inode->i_mutex);
- dput(parent);
+ sysfs_addrm_start(&acxt, sd->s_parent);
+ sysfs_unlink_sibling(sd);
+ sysfs_remove_one(&acxt, sd);
+ sysfs_addrm_finish(&acxt);
}
-void sysfs_remove_subdir(struct dentry * d)
+void sysfs_remove_subdir(struct sysfs_dirent *sd)
{
- remove_dir(d);
+ remove_dir(sd);
}
-static void __sysfs_remove_dir(struct dentry *dentry)
+static void __sysfs_remove_dir(struct sysfs_dirent *dir_sd)
{
- struct sysfs_dirent * parent_sd;
- struct sysfs_dirent * sd, * tmp;
+ struct sysfs_addrm_cxt acxt;
+ struct sysfs_dirent **pos;
- dget(dentry);
- if (!dentry)
+ if (!dir_sd)
return;
- pr_debug("sysfs %s: removing dir\n",dentry->d_name.name);
- mutex_lock(&dentry->d_inode->i_mutex);
- parent_sd = dentry->d_fsdata;
- list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
- if (!sd->s_element || !(sd->s_type & SYSFS_NOT_PINNED))
- continue;
- list_del_init(&sd->s_sibling);
- sysfs_drop_dentry(sd, dentry);
- sysfs_put(sd);
+ pr_debug("sysfs %s: removing dir\n", dir_sd->s_name);
+ sysfs_addrm_start(&acxt, dir_sd);
+ pos = &dir_sd->s_children;
+ while (*pos) {
+ struct sysfs_dirent *sd = *pos;
+
+ if (sysfs_type(sd) && sysfs_type(sd) != SYSFS_DIR) {
+ *pos = sd->s_sibling;
+ sd->s_sibling = NULL;
+ sysfs_remove_one(&acxt, sd);
+ } else
+ pos = &(*pos)->s_sibling;
}
- mutex_unlock(&dentry->d_inode->i_mutex);
+ sysfs_addrm_finish(&acxt);
- remove_dir(dentry);
- /**
- * Drop reference from dget() on entrance.
- */
- dput(dentry);
+ remove_dir(dir_sd);
}
/**
@@ -393,102 +878,166 @@ static void __sysfs_remove_dir(struct dentry *dentry)
void sysfs_remove_dir(struct kobject * kobj)
{
- __sysfs_remove_dir(kobj->dentry);
- kobj->dentry = NULL;
+ struct sysfs_dirent *sd = kobj->sd;
+
+ spin_lock(&sysfs_assoc_lock);
+ kobj->sd = NULL;
+ spin_unlock(&sysfs_assoc_lock);
+
+ __sysfs_remove_dir(sd);
}
-int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
+int sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
const char *new_name)
{
- int error = 0;
- struct dentry * new_dentry;
+ struct sysfs_dirent *sd = kobj->sd;
+ struct dentry *new_parent = NULL;
+ struct dentry *old_dentry = NULL, *new_dentry = NULL;
+ const char *dup_name = NULL;
+ int error;
- if (!new_parent)
- return -EFAULT;
+ /* get dentries */
+ old_dentry = sysfs_get_dentry(sd);
+ if (IS_ERR(old_dentry)) {
+ error = PTR_ERR(old_dentry);
+ goto out_dput;
+ }
- down_write(&sysfs_rename_sem);
+ new_parent = sysfs_get_dentry(new_parent_sd);
+ if (IS_ERR(new_parent)) {
+ error = PTR_ERR(new_parent);
+ goto out_dput;
+ }
+
+ /* lock new_parent and get dentry for new name */
mutex_lock(&new_parent->d_inode->i_mutex);
new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
- if (!IS_ERR(new_dentry)) {
- /* By allowing two different directories with the
- * same d_parent we allow this routine to move
- * between different shadows of the same directory
- */
- if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
- return -EINVAL;
- else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
- error = -EINVAL;
- else if (new_dentry == kobj->dentry)
- error = -EINVAL;
- else if (!new_dentry->d_inode) {
- error = kobject_set_name(kobj, "%s", new_name);
- if (!error) {
- struct sysfs_dirent *sd, *parent_sd;
-
- d_add(new_dentry, NULL);
- d_move(kobj->dentry, new_dentry);
-
- sd = kobj->dentry->d_fsdata;
- parent_sd = new_parent->d_fsdata;
-
- list_del_init(&sd->s_sibling);
- list_add(&sd->s_sibling, &parent_sd->s_children);
- }
- else
- d_drop(new_dentry);
- } else
- error = -EEXIST;
- dput(new_dentry);
+ if (IS_ERR(new_dentry)) {
+ error = PTR_ERR(new_dentry);
+ goto out_unlock;
}
- mutex_unlock(&new_parent->d_inode->i_mutex);
- up_write(&sysfs_rename_sem);
+ /* By allowing two different directories with the same
+ * d_parent we allow this routine to move between different
+ * shadows of the same directory
+ */
+ error = -EINVAL;
+ if (old_dentry->d_parent->d_inode != new_parent->d_inode ||
+ new_dentry->d_parent->d_inode != new_parent->d_inode ||
+ old_dentry == new_dentry)
+ goto out_unlock;
+
+ error = -EEXIST;
+ if (new_dentry->d_inode)
+ goto out_unlock;
+
+ /* rename kobject and sysfs_dirent */
+ error = -ENOMEM;
+ new_name = dup_name = kstrdup(new_name, GFP_KERNEL);
+ if (!new_name)
+ goto out_drop;
+
+ error = kobject_set_name(kobj, "%s", new_name);
+ if (error)
+ goto out_drop;
+
+ dup_name = sd->s_name;
+ sd->s_name = new_name;
+
+ /* move under the new parent */
+ d_add(new_dentry, NULL);
+ d_move(sd->s_dentry, new_dentry);
+
+ mutex_lock(&sysfs_mutex);
+
+ sysfs_unlink_sibling(sd);
+ sysfs_get(new_parent_sd);
+ sysfs_put(sd->s_parent);
+ sd->s_parent = new_parent_sd;
+ sysfs_link_sibling(sd);
+
+ mutex_unlock(&sysfs_mutex);
+
+ error = 0;
+ goto out_unlock;
+
+ out_drop:
+ d_drop(new_dentry);
+ out_unlock:
+ mutex_unlock(&new_parent->d_inode->i_mutex);
+ out_dput:
+ kfree(dup_name);
+ dput(new_parent);
+ dput(old_dentry);
+ dput(new_dentry);
return error;
}
-int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
+int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
{
- struct dentry *old_parent_dentry, *new_parent_dentry, *new_dentry;
- struct sysfs_dirent *new_parent_sd, *sd;
+ struct sysfs_dirent *sd = kobj->sd;
+ struct sysfs_dirent *new_parent_sd;
+ struct dentry *old_parent, *new_parent = NULL;
+ struct dentry *old_dentry = NULL, *new_dentry = NULL;
int error;
- old_parent_dentry = kobj->parent ?
- kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
- new_parent_dentry = new_parent ?
- new_parent->dentry : sysfs_mount->mnt_sb->s_root;
+ BUG_ON(!sd->s_parent);
+ new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;
+
+ /* get dentries */
+ old_dentry = sysfs_get_dentry(sd);
+ if (IS_ERR(old_dentry)) {
+ error = PTR_ERR(old_dentry);
+ goto out_dput;
+ }
+ old_parent = sd->s_parent->s_dentry;
+
+ new_parent = sysfs_get_dentry(new_parent_sd);
+ if (IS_ERR(new_parent)) {
+ error = PTR_ERR(new_parent);
+ goto out_dput;
+ }
- if (old_parent_dentry->d_inode == new_parent_dentry->d_inode)
- return 0; /* nothing to move */
+ if (old_parent->d_inode == new_parent->d_inode) {
+ error = 0;
+ goto out_dput; /* nothing to move */
+ }
again:
- mutex_lock(&old_parent_dentry->d_inode->i_mutex);
- if (!mutex_trylock(&new_parent_dentry->d_inode->i_mutex)) {
- mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
+ mutex_lock(&old_parent->d_inode->i_mutex);
+ if (!mutex_trylock(&new_parent->d_inode->i_mutex)) {
+ mutex_unlock(&old_parent->d_inode->i_mutex);
goto again;
}
- new_parent_sd = new_parent_dentry->d_fsdata;
- sd = kobj->dentry->d_fsdata;
-
- new_dentry = lookup_one_len(kobj->name, new_parent_dentry,
- strlen(kobj->name));
+ new_dentry = lookup_one_len(kobj->name, new_parent, strlen(kobj->name));
if (IS_ERR(new_dentry)) {
error = PTR_ERR(new_dentry);
- goto out;
+ goto out_unlock;
} else
error = 0;
d_add(new_dentry, NULL);
- d_move(kobj->dentry, new_dentry);
+ d_move(sd->s_dentry, new_dentry);
dput(new_dentry);
/* Remove from old parent's list and insert into new parent's list. */
- list_del_init(&sd->s_sibling);
- list_add(&sd->s_sibling, &new_parent_sd->s_children);
+ mutex_lock(&sysfs_mutex);
+
+ sysfs_unlink_sibling(sd);
+ sysfs_get(new_parent_sd);
+ sysfs_put(sd->s_parent);
+ sd->s_parent = new_parent_sd;
+ sysfs_link_sibling(sd);
-out:
- mutex_unlock(&new_parent_dentry->d_inode->i_mutex);
- mutex_unlock(&old_parent_dentry->d_inode->i_mutex);
+ mutex_unlock(&sysfs_mutex);
+ out_unlock:
+ mutex_unlock(&new_parent->d_inode->i_mutex);
+ mutex_unlock(&old_parent->d_inode->i_mutex);
+ out_dput:
+ dput(new_parent);
+ dput(old_dentry);
+ dput(new_dentry);
return error;
}
@@ -496,23 +1045,27 @@ static int sysfs_dir_open(struct inode *inode, struct file *file)
{
struct dentry * dentry = file->f_path.dentry;
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
+ struct sysfs_dirent * sd;
- mutex_lock(&dentry->d_inode->i_mutex);
- file->private_data = sysfs_new_dirent(parent_sd, NULL);
- mutex_unlock(&dentry->d_inode->i_mutex);
-
- return file->private_data ? 0 : -ENOMEM;
+ sd = sysfs_new_dirent("_DIR_", 0, 0);
+ if (sd) {
+ mutex_lock(&sysfs_mutex);
+ sd->s_parent = sysfs_get(parent_sd);
+ sysfs_link_sibling(sd);
+ mutex_unlock(&sysfs_mutex);
+ }
+ file->private_data = sd;
+ return sd ? 0 : -ENOMEM;
}
static int sysfs_dir_close(struct inode *inode, struct file *file)
{
- struct dentry * dentry = file->f_path.dentry;
struct sysfs_dirent * cursor = file->private_data;
- mutex_lock(&dentry->d_inode->i_mutex);
- list_del_init(&cursor->s_sibling);
- mutex_unlock(&dentry->d_inode->i_mutex);
+ mutex_lock(&sysfs_mutex);
+ sysfs_unlink_sibling(cursor);
+ mutex_unlock(&sysfs_mutex);
release_sysfs_dirent(cursor);
@@ -530,7 +1083,7 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
struct dentry *dentry = filp->f_path.dentry;
struct sysfs_dirent * parent_sd = dentry->d_fsdata;
struct sysfs_dirent *cursor = filp->private_data;
- struct list_head *p, *q = &cursor->s_sibling;
+ struct sysfs_dirent **pos;
ino_t ino;
int i = filp->f_pos;
@@ -543,38 +1096,52 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
i++;
/* fallthrough */
case 1:
- ino = parent_ino(dentry);
+ if (parent_sd->s_parent)
+ ino = parent_sd->s_parent->s_ino;
+ else
+ ino = parent_sd->s_ino;
if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
break;
filp->f_pos++;
i++;
/* fallthrough */
default:
+ mutex_lock(&sysfs_mutex);
+
+ pos = &parent_sd->s_children;
+ while (*pos != cursor)
+ pos = &(*pos)->s_sibling;
+
+ /* unlink cursor */
+ *pos = cursor->s_sibling;
+
if (filp->f_pos == 2)
- list_move(q, &parent_sd->s_children);
+ pos = &parent_sd->s_children;
- for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
- struct sysfs_dirent *next;
+ for ( ; *pos; pos = &(*pos)->s_sibling) {
+ struct sysfs_dirent *next = *pos;
const char * name;
int len;
- next = list_entry(p, struct sysfs_dirent,
- s_sibling);
- if (!next->s_element)
+ if (!sysfs_type(next))
continue;
- name = sysfs_get_name(next);
+ name = next->s_name;
len = strlen(name);
ino = next->s_ino;
if (filldir(dirent, name, len, filp->f_pos, ino,
dt_type(next)) < 0)
- return 0;
+ break;
- list_move(q, p);
- p = q;
filp->f_pos++;
}
+
+ /* put cursor back in */
+ cursor->s_sibling = *pos;
+ *pos = cursor;
+
+ mutex_unlock(&sysfs_mutex);
}
return 0;
}
@@ -583,7 +1150,6 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
{
struct dentry * dentry = file->f_path.dentry;
- mutex_lock(&dentry->d_inode->i_mutex);
switch (origin) {
case 1:
offset += file->f_pos;
@@ -591,31 +1157,35 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
if (offset >= 0)
break;
default:
- mutex_unlock(&file->f_path.dentry->d_inode->i_mutex);
return -EINVAL;
}
if (offset != file->f_pos) {
+ mutex_lock(&sysfs_mutex);
+
file->f_pos = offset;
if (file->f_pos >= 2) {
struct sysfs_dirent *sd = dentry->d_fsdata;
struct sysfs_dirent *cursor = file->private_data;
- struct list_head *p;
+ struct sysfs_dirent **pos;
loff_t n = file->f_pos - 2;
- list_del(&cursor->s_sibling);
- p = sd->s_children.next;
- while (n && p != &sd->s_children) {
- struct sysfs_dirent *next;
- next = list_entry(p, struct sysfs_dirent,
- s_sibling);
- if (next->s_element)
+ sysfs_unlink_sibling(cursor);
+
+ pos = &sd->s_children;
+ while (n && *pos) {
+ struct sysfs_dirent *next = *pos;
+ if (sysfs_type(next))
n--;
- p = p->next;
+ pos = &(*pos)->s_sibling;
}
- list_add_tail(&cursor->s_sibling, p);
+
+ cursor->s_sibling = *pos;
+ *pos = cursor;
}
+
+ mutex_unlock(&sysfs_mutex);
}
- mutex_unlock(&dentry->d_inode->i_mutex);
+
return offset;
}
@@ -628,12 +1198,20 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
int sysfs_make_shadowed_dir(struct kobject *kobj,
void * (*follow_link)(struct dentry *, struct nameidata *))
{
+ struct dentry *dentry;
struct inode *inode;
struct inode_operations *i_op;
- inode = kobj->dentry->d_inode;
- if (inode->i_op != &sysfs_dir_inode_operations)
+ /* get dentry for @kobj->sd, dentry of a shadowed dir is pinned */
+ dentry = sysfs_get_dentry(kobj->sd);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ inode = dentry->d_inode;
+ if (inode->i_op != &sysfs_dir_inode_operations) {
+ dput(dentry);
return -EINVAL;
+ }
i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
if (!i_op)
@@ -658,54 +1236,72 @@ int sysfs_make_shadowed_dir(struct kobject *kobj,
* directory.
*/
-struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
+struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj)
{
- struct sysfs_dirent *sd;
- struct dentry *parent, *dir, *shadow;
+ struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
+ struct dentry *dir, *parent, *shadow;
struct inode *inode;
+ struct sysfs_dirent *sd;
+ struct sysfs_addrm_cxt acxt;
- dir = kobj->dentry;
- inode = dir->d_inode;
+ dir = sysfs_get_dentry(kobj->sd);
+ if (IS_ERR(dir)) {
+ sd = (void *)dir;
+ goto out;
+ }
parent = dir->d_parent;
- shadow = ERR_PTR(-EINVAL);
+
+ inode = dir->d_inode;
+ sd = ERR_PTR(-EINVAL);
if (!sysfs_is_shadowed_inode(inode))
- goto out;
+ goto out_dput;
shadow = d_alloc(parent, &dir->d_name);
if (!shadow)
goto nomem;
- sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR);
+ sd = sysfs_new_dirent("_SHADOW_", inode->i_mode, SYSFS_DIR);
if (!sd)
goto nomem;
+ sd->s_elem.dir.kobj = kobj;
+ sysfs_addrm_start(&acxt, parent_sd);
+
+ /* add but don't link into children list */
+ sysfs_add_one(&acxt, sd);
+
+ /* attach and instantiate dentry */
+ sysfs_attach_dentry(sd, shadow);
d_instantiate(shadow, igrab(inode));
- inc_nlink(inode);
- inc_nlink(parent->d_inode);
- shadow->d_op = &sysfs_dentry_ops;
+ inc_nlink(inode); /* tj: synchronization? */
+
+ sysfs_addrm_finish(&acxt);
dget(shadow); /* Extra count - pin the dentry in core */
-out:
- return shadow;
-nomem:
+ goto out_dput;
+
+ nomem:
dput(shadow);
- shadow = ERR_PTR(-ENOMEM);
- goto out;
+ sd = ERR_PTR(-ENOMEM);
+ out_dput:
+ dput(dir);
+ out:
+ return sd;
}
/**
* sysfs_remove_shadow_dir - remove an object's directory.
- * @shadow: dentry of shadow directory
+ * @shadow_sd: sysfs_dirent of shadow directory
*
* The only thing special about this is that we remove any files in
* the directory before we remove the directory, and we've inlined
* what used to be sysfs_rmdir() below, instead of calling separately.
*/
-void sysfs_remove_shadow_dir(struct dentry *shadow)
+void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd)
{
- __sysfs_remove_dir(shadow);
+ __sysfs_remove_dir(shadow_sd);
}
const struct file_operations sysfs_dir_operations = {
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index b502c7197ec0..3e1cc062a740 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -50,29 +50,15 @@ static struct sysfs_ops subsys_sysfs_ops = {
.store = subsys_attr_store,
};
-/**
- * add_to_collection - add buffer to a collection
- * @buffer: buffer to be added
- * @node: inode of set to add to
- */
-
-static inline void
-add_to_collection(struct sysfs_buffer *buffer, struct inode *node)
-{
- struct sysfs_buffer_collection *set = node->i_private;
-
- mutex_lock(&node->i_mutex);
- list_add(&buffer->associates, &set->associates);
- mutex_unlock(&node->i_mutex);
-}
-
-static inline void
-remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
-{
- mutex_lock(&node->i_mutex);
- list_del(&buffer->associates);
- mutex_unlock(&node->i_mutex);
-}
+struct sysfs_buffer {
+ size_t count;
+ loff_t pos;
+ char * page;
+ struct sysfs_ops * ops;
+ struct semaphore sem;
+ int needs_read_fill;
+ int event;
+};
/**
* fill_read_buffer - allocate and fill buffer from object.
@@ -87,9 +73,8 @@ remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
*/
static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
{
- struct sysfs_dirent * sd = dentry->d_fsdata;
- struct attribute * attr = to_attr(dentry);
- struct kobject * kobj = to_kobj(dentry->d_parent);
+ struct sysfs_dirent *attr_sd = dentry->d_fsdata;
+ struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
struct sysfs_ops * ops = buffer->ops;
int ret = 0;
ssize_t count;
@@ -99,8 +84,15 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
if (!buffer->page)
return -ENOMEM;
- buffer->event = atomic_read(&sd->s_event);
- count = ops->show(kobj,attr,buffer->page);
+ /* need attr_sd for attr and ops, its parent for kobj */
+ if (!sysfs_get_active_two(attr_sd))
+ return -ENODEV;
+
+ buffer->event = atomic_read(&attr_sd->s_event);
+ count = ops->show(kobj, attr_sd->s_elem.attr.attr, buffer->page);
+
+ sysfs_put_active_two(attr_sd);
+
BUG_ON(count > (ssize_t)PAGE_SIZE);
if (count >= 0) {
buffer->needs_read_fill = 0;
@@ -138,10 +130,7 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
down(&buffer->sem);
if (buffer->needs_read_fill) {
- if (buffer->orphaned)
- retval = -ENODEV;
- else
- retval = fill_read_buffer(file->f_path.dentry,buffer);
+ retval = fill_read_buffer(file->f_path.dentry,buffer);
if (retval)
goto out;
}
@@ -196,14 +185,23 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t
* passing the buffer that we acquired in fill_write_buffer().
*/
-static int
+static int
flush_write_buffer(struct dentry * dentry, struct sysfs_buffer * buffer, size_t count)
{
- struct attribute * attr = to_attr(dentry);
- struct kobject * kobj = to_kobj(dentry->d_parent);
+ struct sysfs_dirent *attr_sd = dentry->d_fsdata;
+ struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
struct sysfs_ops * ops = buffer->ops;
+ int rc;
+
+ /* need attr_sd for attr and ops, its parent for kobj */
+ if (!sysfs_get_active_two(attr_sd))
+ return -ENODEV;
+
+ rc = ops->store(kobj, attr_sd->s_elem.attr.attr, buffer->page, count);
+
+ sysfs_put_active_two(attr_sd);
- return ops->store(kobj,attr,buffer->page,count);
+ return rc;
}
@@ -231,37 +229,26 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
ssize_t len;
down(&buffer->sem);
- if (buffer->orphaned) {
- len = -ENODEV;
- goto out;
- }
len = fill_write_buffer(buffer, buf, count);
if (len > 0)
len = flush_write_buffer(file->f_path.dentry, buffer, len);
if (len > 0)
*ppos += len;
-out:
up(&buffer->sem);
return len;
}
static int sysfs_open_file(struct inode *inode, struct file *file)
{
- struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
- struct attribute * attr = to_attr(file->f_path.dentry);
- struct sysfs_buffer_collection *set;
+ struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata;
+ struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
struct sysfs_buffer * buffer;
struct sysfs_ops * ops = NULL;
- int error = 0;
-
- if (!kobj || !attr)
- goto Einval;
+ int error;
- /* Grab the module reference for this attribute if we have one */
- if (!try_module_get(attr->owner)) {
- error = -ENODEV;
- goto Done;
- }
+ /* need attr_sd for attr and ops, its parent for kobj */
+ if (!sysfs_get_active_two(attr_sd))
+ return -ENODEV;
/* if the kobject has no ktype, then we assume that it is a subsystem
* itself, and use ops for it.
@@ -273,33 +260,21 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
else
ops = &subsys_sysfs_ops;
+ error = -EACCES;
+
/* No sysfs operations, either from having no subsystem,
* or the subsystem have no operations.
*/
if (!ops)
- goto Eaccess;
-
- /* make sure we have a collection to add our buffers to */
- mutex_lock(&inode->i_mutex);
- if (!(set = inode->i_private)) {
- if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) {
- error = -ENOMEM;
- goto Done;
- } else {
- INIT_LIST_HEAD(&set->associates);
- }
- }
- mutex_unlock(&inode->i_mutex);
+ goto err_out;
/* File needs write support.
* The inode's perms must say it's ok,
* and we must have a store method.
*/
if (file->f_mode & FMODE_WRITE) {
-
if (!(inode->i_mode & S_IWUGO) || !ops->store)
- goto Eaccess;
-
+ goto err_out;
}
/* File needs read support.
@@ -308,48 +283,38 @@ static int sysfs_open_file(struct inode *inode, struct file *file)
*/
if (file->f_mode & FMODE_READ) {
if (!(inode->i_mode & S_IRUGO) || !ops->show)
- goto Eaccess;
+ goto err_out;
}
/* No error? Great, allocate a buffer for the file, and store it
* it in file->private_data for easy access.
*/
+ error = -ENOMEM;
buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
- if (buffer) {
- INIT_LIST_HEAD(&buffer->associates);
- init_MUTEX(&buffer->sem);
- buffer->needs_read_fill = 1;
- buffer->ops = ops;
- add_to_collection(buffer, inode);
- file->private_data = buffer;
- } else
- error = -ENOMEM;
- goto Done;
-
- Einval:
- error = -EINVAL;
- goto Done;
- Eaccess:
- error = -EACCES;
- module_put(attr->owner);
- Done:
- if (error)
- kobject_put(kobj);
+ if (!buffer)
+ goto err_out;
+
+ init_MUTEX(&buffer->sem);
+ buffer->needs_read_fill = 1;
+ buffer->ops = ops;
+ file->private_data = buffer;
+
+ /* open succeeded, put active references and pin attr_sd */
+ sysfs_put_active_two(attr_sd);
+ sysfs_get(attr_sd);
+ return 0;
+
+ err_out:
+ sysfs_put_active_two(attr_sd);
return error;
}
static int sysfs_release(struct inode * inode, struct file * filp)
{
- struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
- struct attribute * attr = to_attr(filp->f_path.dentry);
- struct module * owner = attr->owner;
- struct sysfs_buffer * buffer = filp->private_data;
+ struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
+ struct sysfs_buffer *buffer = filp->private_data;
- if (buffer)
- remove_from_collection(buffer, inode);
- kobject_put(kobj);
- /* After this point, attr should not be accessed. */
- module_put(owner);
+ sysfs_put(attr_sd);
if (buffer) {
if (buffer->page)
@@ -376,57 +341,43 @@ static int sysfs_release(struct inode * inode, struct file * filp)
static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
{
struct sysfs_buffer * buffer = filp->private_data;
- struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
- struct sysfs_dirent * sd = filp->f_path.dentry->d_fsdata;
- int res = 0;
+ struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata;
+ struct kobject *kobj = attr_sd->s_parent->s_elem.dir.kobj;
+
+ /* need parent for the kobj, grab both */
+ if (!sysfs_get_active_two(attr_sd))
+ goto trigger;
poll_wait(filp, &kobj->poll, wait);
- if (buffer->event != atomic_read(&sd->s_event)) {
- res = POLLERR|POLLPRI;
- buffer->needs_read_fill = 1;
- }
+ sysfs_put_active_two(attr_sd);
- return res;
-}
+ if (buffer->event != atomic_read(&attr_sd->s_event))
+ goto trigger;
+ return 0;
-static struct dentry *step_down(struct dentry *dir, const char * name)
-{
- struct dentry * de;
-
- if (dir == NULL || dir->d_inode == NULL)
- return NULL;
-
- mutex_lock(&dir->d_inode->i_mutex);
- de = lookup_one_len(name, dir, strlen(name));
- mutex_unlock(&dir->d_inode->i_mutex);
- dput(dir);
- if (IS_ERR(de))
- return NULL;
- if (de->d_inode == NULL) {
- dput(de);
- return NULL;
- }
- return de;
+ trigger:
+ buffer->needs_read_fill = 1;
+ return POLLERR|POLLPRI;
}
-void sysfs_notify(struct kobject * k, char *dir, char *attr)
+void sysfs_notify(struct kobject *k, char *dir, char *attr)
{
- struct dentry *de = k->dentry;
- if (de)
- dget(de);
- if (de && dir)
- de = step_down(de, dir);
- if (de && attr)
- de = step_down(de, attr);
- if (de) {
- struct sysfs_dirent * sd = de->d_fsdata;
- if (sd)
- atomic_inc(&sd->s_event);
+ struct sysfs_dirent *sd = k->sd;
+
+ mutex_lock(&sysfs_mutex);
+
+ if (sd && dir)
+ sd = sysfs_find_dirent(sd, dir);
+ if (sd && attr)
+ sd = sysfs_find_dirent(sd, attr);
+ if (sd) {
+ atomic_inc(&sd->s_event);
wake_up_interruptible(&k->poll);
- dput(de);
}
+
+ mutex_unlock(&sysfs_mutex);
}
EXPORT_SYMBOL_GPL(sysfs_notify);
@@ -440,19 +391,31 @@ const struct file_operations sysfs_file_operations = {
};
-int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
+int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr,
+ int type)
{
- struct sysfs_dirent * parent_sd = dir->d_fsdata;
umode_t mode = (attr->mode & S_IALLUGO) | S_IFREG;
- int error = -EEXIST;
+ struct sysfs_addrm_cxt acxt;
+ struct sysfs_dirent *sd;
+
+ sd = sysfs_new_dirent(attr->name, mode, type);
+ if (!sd)
+ return -ENOMEM;
+ sd->s_elem.attr.attr = (void *)attr;
- mutex_lock(&dir->d_inode->i_mutex);
- if (!sysfs_dirent_exist(parent_sd, attr->name))
- error = sysfs_make_dirent(parent_sd, NULL, (void *)attr,
- mode, type);
- mutex_unlock(&dir->d_inode->i_mutex);
+ sysfs_addrm_start(&acxt, dir_sd);
- return error;
+ if (!sysfs_find_dirent(dir_sd, attr->name)) {
+ sysfs_add_one(&acxt, sd);
+ sysfs_link_sibling(sd);
+ }
+
+ if (!sysfs_addrm_finish(&acxt)) {
+ sysfs_put(sd);
+ return -EEXIST;
+ }
+
+ return 0;
}
@@ -464,9 +427,9 @@ int sysfs_add_file(struct dentry * dir, const struct attribute * attr, int type)
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
{
- BUG_ON(!kobj || !kobj->dentry || !attr);
+ BUG_ON(!kobj || !kobj->sd || !attr);
- return sysfs_add_file(kobj->dentry, attr, SYSFS_KOBJ_ATTR);
+ return sysfs_add_file(kobj->sd, attr, SYSFS_KOBJ_ATTR);
}
@@ -480,16 +443,16 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
int sysfs_add_file_to_group(struct kobject *kobj,
const struct attribute *attr, const char *group)
{
- struct dentry *dir;
+ struct sysfs_dirent *dir_sd;
int error;
- dir = lookup_one_len(group, kobj->dentry, strlen(group));
- if (IS_ERR(dir))
- error = PTR_ERR(dir);
- else {
- error = sysfs_add_file(dir, attr, SYSFS_KOBJ_ATTR);
- dput(dir);
- }
+ dir_sd = sysfs_get_dirent(kobj->sd, group);
+ if (!dir_sd)
+ return -ENOENT;
+
+ error = sysfs_add_file(dir_sd, attr, SYSFS_KOBJ_ATTR);
+ sysfs_put(dir_sd);
+
return error;
}
EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
@@ -502,30 +465,31 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group);
*/
int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
{
- struct dentry * dir = kobj->dentry;
- struct dentry * victim;
- int res = -ENOENT;
-
- mutex_lock(&dir->d_inode->i_mutex);
- victim = lookup_one_len(attr->name, dir, strlen(attr->name));
- if (!IS_ERR(victim)) {
- /* make sure dentry is really there */
- if (victim->d_inode &&
- (victim->d_parent->d_inode == dir->d_inode)) {
- victim->d_inode->i_mtime = CURRENT_TIME;
- fsnotify_modify(victim);
- res = 0;
- } else
- d_drop(victim);
-
- /**
- * Drop the reference acquired from lookup_one_len() above.
- */
- dput(victim);
+ struct sysfs_dirent *victim_sd = NULL;
+ struct dentry *victim = NULL;
+ int rc;
+
+ rc = -ENOENT;
+ victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
+ if (!victim_sd)
+ goto out;
+
+ victim = sysfs_get_dentry(victim_sd);
+ if (IS_ERR(victim)) {
+ rc = PTR_ERR(victim);
+ victim = NULL;
+ goto out;
}
- mutex_unlock(&dir->d_inode->i_mutex);
- return res;
+ mutex_lock(&victim->d_inode->i_mutex);
+ victim->d_inode->i_mtime = CURRENT_TIME;
+ fsnotify_modify(victim);
+ mutex_unlock(&victim->d_inode->i_mutex);
+ rc = 0;
+ out:
+ dput(victim);
+ sysfs_put(victim_sd);
+ return rc;
}
@@ -538,30 +502,34 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
*/
int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
{
- struct dentry *dir = kobj->dentry;
- struct dentry *victim;
+ struct sysfs_dirent *victim_sd = NULL;
+ struct dentry *victim = NULL;
struct inode * inode;
struct iattr newattrs;
- int res = -ENOENT;
-
- mutex_lock(&dir->d_inode->i_mutex);
- victim = lookup_one_len(attr->name, dir, strlen(attr->name));
- if (!IS_ERR(victim)) {
- if (victim->d_inode &&
- (victim->d_parent->d_inode == dir->d_inode)) {
- inode = victim->d_inode;
- mutex_lock(&inode->i_mutex);
- newattrs.ia_mode = (mode & S_IALLUGO) |
- (inode->i_mode & ~S_IALLUGO);
- newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- res = notify_change(victim, &newattrs);
- mutex_unlock(&inode->i_mutex);
- }
- dput(victim);
+ int rc;
+
+ rc = -ENOENT;
+ victim_sd = sysfs_get_dirent(kobj->sd, attr->name);
+ if (!victim_sd)
+ goto out;
+
+ victim = sysfs_get_dentry(victim_sd);
+ if (IS_ERR(victim)) {
+ rc = PTR_ERR(victim);
+ victim = NULL;
+ goto out;
}
- mutex_unlock(&dir->d_inode->i_mutex);
- return res;
+ inode = victim->d_inode;
+ mutex_lock(&inode->i_mutex);
+ newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
+ newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
+ rc = notify_change(victim, &newattrs);
+ mutex_unlock(&inode->i_mutex);
+ out:
+ dput(victim);
+ sysfs_put(victim_sd);
+ return rc;
}
EXPORT_SYMBOL_GPL(sysfs_chmod_file);
@@ -576,7 +544,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
{
- sysfs_hash_and_remove(kobj->dentry, attr->name);
+ sysfs_hash_and_remove(kobj->sd, attr->name);
}
@@ -589,12 +557,12 @@ void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
void sysfs_remove_file_from_group(struct kobject *kobj,
const struct attribute *attr, const char *group)
{
- struct dentry *dir;
+ struct sysfs_dirent *dir_sd;
- dir = lookup_one_len(group, kobj->dentry, strlen(group));
- if (!IS_ERR(dir)) {
- sysfs_hash_and_remove(dir, attr->name);
- dput(dir);
+ dir_sd = sysfs_get_dirent(kobj->sd, group);
+ if (dir_sd) {
+ sysfs_hash_and_remove(dir_sd, attr->name);
+ sysfs_put(dir_sd);
}
}
EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group);
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index 52eed2a7a5ef..f318b73c790c 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -18,26 +18,25 @@
#include "sysfs.h"
-static void remove_files(struct dentry * dir,
- const struct attribute_group * grp)
+static void remove_files(struct sysfs_dirent *dir_sd,
+ const struct attribute_group *grp)
{
struct attribute *const* attr;
for (attr = grp->attrs; *attr; attr++)
- sysfs_hash_and_remove(dir,(*attr)->name);
+ sysfs_hash_and_remove(dir_sd, (*attr)->name);
}
-static int create_files(struct dentry * dir,
- const struct attribute_group * grp)
+static int create_files(struct sysfs_dirent *dir_sd,
+ const struct attribute_group *grp)
{
struct attribute *const* attr;
int error = 0;
- for (attr = grp->attrs; *attr && !error; attr++) {
- error = sysfs_add_file(dir, *attr, SYSFS_KOBJ_ATTR);
- }
+ for (attr = grp->attrs; *attr && !error; attr++)
+ error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
if (error)
- remove_files(dir,grp);
+ remove_files(dir_sd, grp);
return error;
}
@@ -45,44 +44,44 @@ static int create_files(struct dentry * dir,
int sysfs_create_group(struct kobject * kobj,
const struct attribute_group * grp)
{
- struct dentry * dir;
+ struct sysfs_dirent *sd;
int error;
- BUG_ON(!kobj || !kobj->dentry);
+ BUG_ON(!kobj || !kobj->sd);
if (grp->name) {
- error = sysfs_create_subdir(kobj,grp->name,&dir);
+ error = sysfs_create_subdir(kobj, grp->name, &sd);
if (error)
return error;
} else
- dir = kobj->dentry;
- dir = dget(dir);
- if ((error = create_files(dir,grp))) {
+ sd = kobj->sd;
+ sysfs_get(sd);
+ error = create_files(sd, grp);
+ if (error) {
if (grp->name)
- sysfs_remove_subdir(dir);
+ sysfs_remove_subdir(sd);
}
- dput(dir);
+ sysfs_put(sd);
return error;
}
void sysfs_remove_group(struct kobject * kobj,
const struct attribute_group * grp)
{
- struct dentry * dir;
+ struct sysfs_dirent *dir_sd = kobj->sd;
+ struct sysfs_dirent *sd;
if (grp->name) {
- dir = lookup_one_len_kern(grp->name, kobj->dentry,
- strlen(grp->name));
- BUG_ON(IS_ERR(dir));
- }
- else
- dir = dget(kobj->dentry);
+ sd = sysfs_get_dirent(dir_sd, grp->name);
+ BUG_ON(!sd);
+ } else
+ sd = sysfs_get(dir_sd);
- remove_files(dir,grp);
+ remove_files(sd, grp);
if (grp->name)
- sysfs_remove_subdir(dir);
- /* release the ref. taken in this routine */
- dput(dir);
+ sysfs_remove_subdir(sd);
+
+ sysfs_put(sd);
}
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 5266eec15f6e..10d1b52899f1 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -133,187 +133,94 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
*/
static struct lock_class_key sysfs_inode_imutex_key;
-struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd)
+static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
{
- struct inode * inode = new_inode(sysfs_sb);
- if (inode) {
- inode->i_blocks = 0;
- inode->i_mapping->a_ops = &sysfs_aops;
- inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
- inode->i_op = &sysfs_inode_operations;
- inode->i_ino = sd->s_ino;
- lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
-
- if (sd->s_iattr) {
- /* sysfs_dirent has non-default attributes
- * get them for the new inode from persistent copy
- * in sysfs_dirent
- */
- set_inode_attr(inode, sd->s_iattr);
- } else
- set_default_inode_attr(inode, mode);
- }
- return inode;
-}
-
-int sysfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
-{
- int error = 0;
- struct inode * inode = NULL;
- if (dentry) {
- if (!dentry->d_inode) {
- struct sysfs_dirent * sd = dentry->d_fsdata;
- if ((inode = sysfs_new_inode(mode, sd))) {
- if (dentry->d_parent && dentry->d_parent->d_inode) {
- struct inode *p_inode = dentry->d_parent->d_inode;
- p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
- }
- goto Proceed;
- }
- else
- error = -ENOMEM;
- } else
- error = -EEXIST;
- } else
- error = -ENOENT;
- goto Done;
-
- Proceed:
- if (init)
- error = init(inode);
- if (!error) {
- d_instantiate(dentry, inode);
- if (S_ISDIR(mode))
- dget(dentry); /* pin only directory dentry in core */
+ inode->i_blocks = 0;
+ inode->i_mapping->a_ops = &sysfs_aops;
+ inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
+ inode->i_op = &sysfs_inode_operations;
+ inode->i_ino = sd->s_ino;
+ lockdep_set_class(&inode->i_mutex, &sysfs_inode_imutex_key);
+
+ if (sd->s_iattr) {
+ /* sysfs_dirent has non-default attributes
+ * get them for the new inode from persistent copy
+ * in sysfs_dirent
+ */
+ set_inode_attr(inode, sd->s_iattr);
} else
- iput(inode);
- Done:
- return error;
+ set_default_inode_attr(inode, sd->s_mode);
}
-/*
- * Get the name for corresponding element represented by the given sysfs_dirent
+/**
+ * sysfs_get_inode - get inode for sysfs_dirent
+ * @sd: sysfs_dirent to allocate inode for
+ *
+ * Get inode for @sd. If such inode doesn't exist, a new inode
+ * is allocated and basics are initialized. New inode is
+ * returned locked.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * Pointer to allocated inode on success, NULL on failure.
*/
-const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
+struct inode * sysfs_get_inode(struct sysfs_dirent *sd)
{
- struct attribute * attr;
- struct bin_attribute * bin_attr;
- struct sysfs_symlink * sl;
-
- BUG_ON(!sd || !sd->s_element);
-
- switch (sd->s_type) {
- case SYSFS_DIR:
- /* Always have a dentry so use that */
- return sd->s_dentry->d_name.name;
-
- case SYSFS_KOBJ_ATTR:
- attr = sd->s_element;
- return attr->name;
-
- case SYSFS_KOBJ_BIN_ATTR:
- bin_attr = sd->s_element;
- return bin_attr->attr.name;
+ struct inode *inode;
- case SYSFS_KOBJ_LINK:
- sl = sd->s_element;
- return sl->link_name;
- }
- return NULL;
-}
+ inode = iget_locked(sysfs_sb, sd->s_ino);
+ if (inode && (inode->i_state & I_NEW))
+ sysfs_init_inode(sd, inode);
-static inline void orphan_all_buffers(struct inode *node)
-{
- struct sysfs_buffer_collection *set;
- struct sysfs_buffer *buf;
-
- mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD);
- set = node->i_private;
- if (set) {
- list_for_each_entry(buf, &set->associates, associates) {
- down(&buf->sem);
- buf->orphaned = 1;
- up(&buf->sem);
- }
- }
- mutex_unlock(&node->i_mutex);
+ return inode;
}
-
-/*
- * Unhashes the dentry corresponding to given sysfs_dirent
- * Called with parent inode's i_mutex held.
+/**
+ * sysfs_instantiate - instantiate dentry
+ * @dentry: dentry to be instantiated
+ * @inode: inode associated with @sd
+ *
+ * Unlock @inode if locked and instantiate @dentry with @inode.
+ *
+ * LOCKING:
+ * None.
*/
-void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
+void sysfs_instantiate(struct dentry *dentry, struct inode *inode)
{
- struct dentry *dentry = NULL;
- struct inode *inode;
+ BUG_ON(!dentry || dentry->d_inode);
- /* We're not holding a reference to ->s_dentry dentry but the
- * field will stay valid as long as sysfs_lock is held.
- */
- spin_lock(&sysfs_lock);
- spin_lock(&dcache_lock);
-
- /* dget dentry if it's still alive */
- if (sd->s_dentry && sd->s_dentry->d_inode)
- dentry = dget_locked(sd->s_dentry);
-
- spin_unlock(&dcache_lock);
- spin_unlock(&sysfs_lock);
-
- /* drop dentry */
- if (dentry) {
- spin_lock(&dcache_lock);
- spin_lock(&dentry->d_lock);
- if (!d_unhashed(dentry) && dentry->d_inode) {
- inode = dentry->d_inode;
- spin_lock(&inode->i_lock);
- __iget(inode);
- spin_unlock(&inode->i_lock);
- dget_locked(dentry);
- __d_drop(dentry);
- spin_unlock(&dentry->d_lock);
- spin_unlock(&dcache_lock);
- simple_unlink(parent->d_inode, dentry);
- orphan_all_buffers(inode);
- iput(inode);
- } else {
- spin_unlock(&dentry->d_lock);
- spin_unlock(&dcache_lock);
- }
+ if (inode->i_state & I_NEW)
+ unlock_new_inode(inode);
- dput(dentry);
- }
+ d_instantiate(dentry, inode);
}
-int sysfs_hash_and_remove(struct dentry * dir, const char * name)
+int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
{
- struct sysfs_dirent * sd;
- struct sysfs_dirent * parent_sd;
- int found = 0;
+ struct sysfs_addrm_cxt acxt;
+ struct sysfs_dirent **pos, *sd;
- if (!dir)
+ if (!dir_sd)
return -ENOENT;
- if (dir->d_inode == NULL)
- /* no inode means this hasn't been made visible yet */
- return -ENOENT;
+ sysfs_addrm_start(&acxt, dir_sd);
+
+ for (pos = &dir_sd->s_children; *pos; pos = &(*pos)->s_sibling) {
+ sd = *pos;
- parent_sd = dir->d_fsdata;
- mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
- list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
- if (!sd->s_element)
+ if (!sysfs_type(sd))
continue;
- if (!strcmp(sysfs_get_name(sd), name)) {
- list_del_init(&sd->s_sibling);
- sysfs_drop_dentry(sd, dir);
- sysfs_put(sd);
- found = 1;
+ if (!strcmp(sd->s_name, name)) {
+ *pos = sd->s_sibling;
+ sd->s_sibling = NULL;
+ sysfs_remove_one(&acxt, sd);
break;
}
}
- mutex_unlock(&dir->d_inode->i_mutex);
- return found ? 0 : -ENOENT;
+ if (sysfs_addrm_finish(&acxt))
+ return 0;
+ return -ENOENT;
}
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 00ab9125d398..fbc7b65fe262 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -19,28 +19,18 @@ struct vfsmount *sysfs_mount;
struct super_block * sysfs_sb = NULL;
struct kmem_cache *sysfs_dir_cachep;
-static void sysfs_clear_inode(struct inode *inode);
-
static const struct super_operations sysfs_ops = {
.statfs = simple_statfs,
.drop_inode = sysfs_delete_inode,
- .clear_inode = sysfs_clear_inode,
};
-static struct sysfs_dirent sysfs_root = {
- .s_sibling = LIST_HEAD_INIT(sysfs_root.s_sibling),
- .s_children = LIST_HEAD_INIT(sysfs_root.s_children),
- .s_element = NULL,
- .s_type = SYSFS_ROOT,
- .s_iattr = NULL,
+struct sysfs_dirent sysfs_root = {
+ .s_count = ATOMIC_INIT(1),
+ .s_flags = SYSFS_ROOT,
+ .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
.s_ino = 1,
};
-static void sysfs_clear_inode(struct inode *inode)
-{
- kfree(inode->i_private);
-}
-
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
@@ -53,24 +43,26 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_time_gran = 1;
sysfs_sb = sb;
- inode = sysfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
- &sysfs_root);
- if (inode) {
- inode->i_op = &sysfs_dir_inode_operations;
- inode->i_fop = &sysfs_dir_operations;
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
- inc_nlink(inode);
- } else {
+ /* get root inode, initialize and unlock it */
+ inode = sysfs_get_inode(&sysfs_root);
+ if (!inode) {
pr_debug("sysfs: could not get root inode\n");
return -ENOMEM;
}
+ inode->i_op = &sysfs_dir_inode_operations;
+ inode->i_fop = &sysfs_dir_operations;
+ inc_nlink(inode); /* directory, account for "." */
+ unlock_new_inode(inode);
+
+ /* instantiate and link root dentry */
root = d_alloc_root(inode);
if (!root) {
pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
iput(inode);
return -ENOMEM;
}
+ sysfs_root.s_dentry = root;
root->d_fsdata = &sysfs_root;
sb->s_root = root;
return 0;
@@ -94,7 +86,7 @@ int __init sysfs_init(void)
sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
sizeof(struct sysfs_dirent),
- 0, 0, NULL, NULL);
+ 0, 0, NULL);
if (!sysfs_dir_cachep)
goto out;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 7b9c5bfde920..4ce687f0b5d0 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -11,71 +11,39 @@
#include "sysfs.h"
-static int object_depth(struct kobject * kobj)
+static int object_depth(struct sysfs_dirent *sd)
{
- struct kobject * p = kobj;
int depth = 0;
- do { depth++; } while ((p = p->parent));
+
+ for (; sd->s_parent; sd = sd->s_parent)
+ depth++;
+
return depth;
}
-static int object_path_length(struct kobject * kobj)
+static int object_path_length(struct sysfs_dirent * sd)
{
- struct kobject * p = kobj;
int length = 1;
- do {
- length += strlen(kobject_name(p)) + 1;
- p = p->parent;
- } while (p);
+
+ for (; sd->s_parent; sd = sd->s_parent)
+ length += strlen(sd->s_name) + 1;
+
return length;
}
-static void fill_object_path(struct kobject * kobj, char * buffer, int length)
+static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length)
{
- struct kobject * p;
-
--length;
- for (p = kobj; p; p = p->parent) {
- int cur = strlen(kobject_name(p));
+ for (; sd->s_parent; sd = sd->s_parent) {
+ int cur = strlen(sd->s_name);
/* back up enough to print this bus id with '/' */
length -= cur;
- strncpy(buffer + length,kobject_name(p),cur);
+ strncpy(buffer + length, sd->s_name, cur);
*(buffer + --length) = '/';
}
}
-static int sysfs_add_link(struct dentry * parent, const char * name, struct kobject * target)
-{
- struct sysfs_dirent * parent_sd = parent->d_fsdata;
- struct sysfs_symlink * sl;
- int error = 0;
-
- error = -ENOMEM;
- sl = kmalloc(sizeof(*sl), GFP_KERNEL);
- if (!sl)
- goto exit1;
-
- sl->link_name = kmalloc(strlen(name) + 1, GFP_KERNEL);
- if (!sl->link_name)
- goto exit2;
-
- strcpy(sl->link_name, name);
- sl->target_kobj = kobject_get(target);
-
- error = sysfs_make_dirent(parent_sd, NULL, sl, S_IFLNK|S_IRWXUGO,
- SYSFS_KOBJ_LINK);
- if (!error)
- return 0;
-
- kobject_put(target);
- kfree(sl->link_name);
-exit2:
- kfree(sl);
-exit1:
- return error;
-}
-
/**
* sysfs_create_link - create symlink between two objects.
* @kobj: object whose directory we're creating the link in.
@@ -84,24 +52,61 @@ exit1:
*/
int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name)
{
- struct dentry *dentry = NULL;
- int error = -EEXIST;
+ struct sysfs_dirent *parent_sd = NULL;
+ struct sysfs_dirent *target_sd = NULL;
+ struct sysfs_dirent *sd = NULL;
+ struct sysfs_addrm_cxt acxt;
+ int error;
BUG_ON(!name);
if (!kobj) {
if (sysfs_mount && sysfs_mount->mnt_sb)
- dentry = sysfs_mount->mnt_sb->s_root;
+ parent_sd = sysfs_mount->mnt_sb->s_root->d_fsdata;
} else
- dentry = kobj->dentry;
+ parent_sd = kobj->sd;
+
+ error = -EFAULT;
+ if (!parent_sd)
+ goto out_put;
+
+ /* target->sd can go away beneath us but is protected with
+ * sysfs_assoc_lock. Fetch target_sd from it.
+ */
+ spin_lock(&sysfs_assoc_lock);
+ if (target->sd)
+ target_sd = sysfs_get(target->sd);
+ spin_unlock(&sysfs_assoc_lock);
- if (!dentry)
- return -EFAULT;
+ error = -ENOENT;
+ if (!target_sd)
+ goto out_put;
- mutex_lock(&dentry->d_inode->i_mutex);
- if (!sysfs_dirent_exist(dentry->d_fsdata, name))
- error = sysfs_add_link(dentry, name, target);
- mutex_unlock(&dentry->d_inode->i_mutex);
+ error = -ENOMEM;
+ sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
+ if (!sd)
+ goto out_put;
+
+ sd->s_elem.symlink.target_sd = target_sd;
+ target_sd = NULL; /* reference is now owned by the symlink */
+
+ sysfs_addrm_start(&acxt, parent_sd);
+
+ if (!sysfs_find_dirent(parent_sd, name)) {
+ sysfs_add_one(&acxt, sd);
+ sysfs_link_sibling(sd);
+ }
+
+ if (!sysfs_addrm_finish(&acxt)) {
+ error = -EEXIST;
+ goto out_put;
+ }
+
+ return 0;
+
+ out_put:
+ sysfs_put(target_sd);
+ sysfs_put(sd);
return error;
}
@@ -114,17 +119,17 @@ int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char
void sysfs_remove_link(struct kobject * kobj, const char * name)
{
- sysfs_hash_and_remove(kobj->dentry,name);
+ sysfs_hash_and_remove(kobj->sd, name);
}
-static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
- char *path)
+static int sysfs_get_target_path(struct sysfs_dirent * parent_sd,
+ struct sysfs_dirent * target_sd, char *path)
{
char * s;
int depth, size;
- depth = object_depth(kobj);
- size = object_path_length(target) + depth * 3 - 1;
+ depth = object_depth(parent_sd);
+ size = object_path_length(target_sd) + depth * 3 - 1;
if (size > PATH_MAX)
return -ENAMETOOLONG;
@@ -133,7 +138,7 @@ static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
for (s = path; depth--; s += 3)
strcpy(s,"../");
- fill_object_path(target, path, size);
+ fill_object_path(target_sd, path, size);
pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
return 0;
@@ -141,27 +146,16 @@ static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target,
static int sysfs_getlink(struct dentry *dentry, char * path)
{
- struct kobject *kobj, *target_kobj;
- int error = 0;
+ struct sysfs_dirent *sd = dentry->d_fsdata;
+ struct sysfs_dirent *parent_sd = sd->s_parent;
+ struct sysfs_dirent *target_sd = sd->s_elem.symlink.target_sd;
+ int error;
- kobj = sysfs_get_kobject(dentry->d_parent);
- if (!kobj)
- return -EINVAL;
+ mutex_lock(&sysfs_mutex);
+ error = sysfs_get_target_path(parent_sd, target_sd, path);
+ mutex_unlock(&sysfs_mutex);
- target_kobj = sysfs_get_kobject(dentry);
- if (!target_kobj) {
- kobject_put(kobj);
- return -EINVAL;
- }
-
- down_read(&sysfs_rename_sem);
- error = sysfs_get_target_path(kobj, target_kobj, path);
- up_read(&sysfs_rename_sem);
-
- kobject_put(kobj);
- kobject_put(target_kobj);
return error;
-
}
static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 502c949c402d..6b8c8d76d308 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -1,9 +1,40 @@
+struct sysfs_elem_dir {
+ struct kobject * kobj;
+};
+
+struct sysfs_elem_symlink {
+ struct sysfs_dirent * target_sd;
+};
+
+struct sysfs_elem_attr {
+ struct attribute * attr;
+};
+
+struct sysfs_elem_bin_attr {
+ struct bin_attribute * bin_attr;
+};
+
+/*
+ * As long as s_count reference is held, the sysfs_dirent itself is
+ * accessible. Dereferencing s_elem or any other outer entity
+ * requires s_active reference.
+ */
struct sysfs_dirent {
atomic_t s_count;
- struct list_head s_sibling;
- struct list_head s_children;
- void * s_element;
- int s_type;
+ atomic_t s_active;
+ struct sysfs_dirent * s_parent;
+ struct sysfs_dirent * s_sibling;
+ struct sysfs_dirent * s_children;
+ const char * s_name;
+
+ union {
+ struct sysfs_elem_dir dir;
+ struct sysfs_elem_symlink symlink;
+ struct sysfs_elem_attr attr;
+ struct sysfs_elem_bin_attr bin_attr;
+ } s_elem;
+
+ unsigned int s_flags;
umode_t s_mode;
ino_t s_ino;
struct dentry * s_dentry;
@@ -11,30 +42,59 @@ struct sysfs_dirent {
atomic_t s_event;
};
+#define SD_DEACTIVATED_BIAS INT_MIN
+
+struct sysfs_addrm_cxt {
+ struct sysfs_dirent *parent_sd;
+ struct inode *parent_inode;
+ struct sysfs_dirent *removed;
+ int cnt;
+};
+
extern struct vfsmount * sysfs_mount;
+extern struct sysfs_dirent sysfs_root;
extern struct kmem_cache *sysfs_dir_cachep;
-extern void sysfs_delete_inode(struct inode *inode);
-extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
-extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
+extern struct dentry *sysfs_get_dentry(struct sysfs_dirent *sd);
+extern void sysfs_link_sibling(struct sysfs_dirent *sd);
+extern void sysfs_unlink_sibling(struct sysfs_dirent *sd);
+extern struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd);
+extern void sysfs_put_active(struct sysfs_dirent *sd);
+extern struct sysfs_dirent *sysfs_get_active_two(struct sysfs_dirent *sd);
+extern void sysfs_put_active_two(struct sysfs_dirent *sd);
+extern void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt,
+ struct sysfs_dirent *parent_sd);
+extern void sysfs_add_one(struct sysfs_addrm_cxt *acxt,
+ struct sysfs_dirent *sd);
+extern void sysfs_remove_one(struct sysfs_addrm_cxt *acxt,
+ struct sysfs_dirent *sd);
+extern int sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
-extern int sysfs_dirent_exist(struct sysfs_dirent *, const unsigned char *);
-extern int sysfs_make_dirent(struct sysfs_dirent *, struct dentry *, void *,
- umode_t, int);
-
-extern int sysfs_add_file(struct dentry *, const struct attribute *, int);
-extern int sysfs_hash_and_remove(struct dentry * dir, const char * name);
+extern void sysfs_delete_inode(struct inode *inode);
+extern struct inode * sysfs_get_inode(struct sysfs_dirent *sd);
+extern void sysfs_instantiate(struct dentry *dentry, struct inode *inode);
+
+extern void release_sysfs_dirent(struct sysfs_dirent * sd);
+extern struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
+ const unsigned char *name);
+extern struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
+ const unsigned char *name);
+extern struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode,
+ int type);
+
+extern int sysfs_add_file(struct sysfs_dirent *dir_sd,
+ const struct attribute *attr, int type);
+extern int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name);
extern struct sysfs_dirent *sysfs_find(struct sysfs_dirent *dir, const char * name);
-extern int sysfs_create_subdir(struct kobject *, const char *, struct dentry **);
-extern void sysfs_remove_subdir(struct dentry *);
+extern int sysfs_create_subdir(struct kobject *kobj, const char *name,
+ struct sysfs_dirent **p_sd);
+extern void sysfs_remove_subdir(struct sysfs_dirent *sd);
-extern const unsigned char * sysfs_get_name(struct sysfs_dirent *sd);
-extern void sysfs_drop_dentry(struct sysfs_dirent *sd, struct dentry *parent);
extern int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
-extern spinlock_t sysfs_lock;
-extern struct rw_semaphore sysfs_rename_sem;
+extern spinlock_t sysfs_assoc_lock;
+extern struct mutex sysfs_mutex;
extern struct super_block * sysfs_sb;
extern const struct file_operations sysfs_dir_operations;
extern const struct file_operations sysfs_file_operations;
@@ -42,73 +102,9 @@ extern const struct file_operations bin_fops;
extern const struct inode_operations sysfs_dir_inode_operations;
extern const struct inode_operations sysfs_symlink_inode_operations;
-struct sysfs_symlink {
- char * link_name;
- struct kobject * target_kobj;
-};
-
-struct sysfs_buffer {
- struct list_head associates;
- size_t count;
- loff_t pos;
- char * page;
- struct sysfs_ops * ops;
- struct semaphore sem;
- int orphaned;
- int needs_read_fill;
- int event;
-};
-
-struct sysfs_buffer_collection {
- struct list_head associates;
-};
-
-static inline struct kobject * to_kobj(struct dentry * dentry)
-{
- struct sysfs_dirent * sd = dentry->d_fsdata;
- return ((struct kobject *) sd->s_element);
-}
-
-static inline struct attribute * to_attr(struct dentry * dentry)
+static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
{
- struct sysfs_dirent * sd = dentry->d_fsdata;
- return ((struct attribute *) sd->s_element);
-}
-
-static inline struct bin_attribute * to_bin_attr(struct dentry * dentry)
-{
- struct sysfs_dirent * sd = dentry->d_fsdata;
- return ((struct bin_attribute *) sd->s_element);
-}
-
-static inline struct kobject *sysfs_get_kobject(struct dentry *dentry)
-{
- struct kobject * kobj = NULL;
-
- spin_lock(&dcache_lock);
- if (!d_unhashed(dentry)) {
- struct sysfs_dirent * sd = dentry->d_fsdata;
- if (sd->s_type & SYSFS_KOBJ_LINK) {
- struct sysfs_symlink * sl = sd->s_element;
- kobj = kobject_get(sl->target_kobj);
- } else
- kobj = kobject_get(sd->s_element);
- }
- spin_unlock(&dcache_lock);
-
- return kobj;
-}
-
-static inline void release_sysfs_dirent(struct sysfs_dirent * sd)
-{
- if (sd->s_type & SYSFS_KOBJ_LINK) {
- struct sysfs_symlink * sl = sd->s_element;
- kfree(sl->link_name);
- kobject_put(sl->target_kobj);
- kfree(sl);
- }
- kfree(sd->s_iattr);
- kmem_cache_free(sysfs_dir_cachep, sd);
+ return sd->s_flags & SYSFS_TYPE_MASK;
}
static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
@@ -122,7 +118,7 @@ static inline struct sysfs_dirent * sysfs_get(struct sysfs_dirent * sd)
static inline void sysfs_put(struct sysfs_dirent * sd)
{
- if (atomic_dec_and_test(&sd->s_count))
+ if (sd && atomic_dec_and_test(&sd->s_count))
release_sysfs_dirent(sd);
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 564411693394..7c4e5d302abb 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -342,7 +342,7 @@ int __init sysv_init_icache(void)
sysv_inode_cachep = kmem_cache_create("sysv_inode_cache",
sizeof(struct sysv_inode_info), 0,
SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
- init_once, NULL);
+ init_once);
if (!sysv_inode_cachep)
return -ENOMEM;
return 0;
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 4cec91015681..276f7207a564 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -41,18 +41,17 @@
#define uint(x) xuint(x)
#define xuint(x) __le ## x
-static inline int find_next_one_bit (void * addr, int size, int offset)
+static inline int find_next_one_bit(void *addr, int size, int offset)
{
- uintBPL_t * p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG);
- int result = offset & ~(BITS_PER_LONG-1);
+ uintBPL_t *p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG);
+ int result = offset & ~(BITS_PER_LONG - 1);
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
- offset &= (BITS_PER_LONG-1);
- if (offset)
- {
+ offset &= (BITS_PER_LONG - 1);
+ if (offset) {
tmp = leBPL_to_cpup(p++);
tmp &= ~0UL << offset;
if (size < BITS_PER_LONG)
@@ -62,8 +61,7 @@ static inline int find_next_one_bit (void * addr, int size, int offset)
size -= BITS_PER_LONG;
result += BITS_PER_LONG;
}
- while (size & ~(BITS_PER_LONG-1))
- {
+ while (size & ~(BITS_PER_LONG - 1)) {
if ((tmp = leBPL_to_cpup(p++)))
goto found_middle;
result += BITS_PER_LONG;
@@ -73,7 +71,7 @@ static inline int find_next_one_bit (void * addr, int size, int offset)
return result;
tmp = leBPL_to_cpup(p);
found_first:
- tmp &= ~0UL >> (BITS_PER_LONG-size);
+ tmp &= ~0UL >> (BITS_PER_LONG - size);
found_middle:
return result + ffz(~tmp);
}
@@ -81,8 +79,9 @@ found_middle:
#define find_first_one_bit(addr, size)\
find_next_one_bit((addr), (size), 0)
-static int read_block_bitmap(struct super_block * sb,
- struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr)
+static int read_block_bitmap(struct super_block *sb,
+ struct udf_bitmap *bitmap, unsigned int block,
+ unsigned long bitmap_nr)
{
struct buffer_head *bh = NULL;
int retval = 0;
@@ -92,38 +91,39 @@ static int read_block_bitmap(struct super_block * sb,
loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block));
- if (!bh)
- {
+ if (!bh) {
retval = -EIO;
}
bitmap->s_block_bitmap[bitmap_nr] = bh;
return retval;
}
-static int __load_block_bitmap(struct super_block * sb,
- struct udf_bitmap *bitmap, unsigned int block_group)
+static int __load_block_bitmap(struct super_block *sb,
+ struct udf_bitmap *bitmap,
+ unsigned int block_group)
{
int retval = 0;
int nr_groups = bitmap->s_nr_groups;
- if (block_group >= nr_groups)
- {
- udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups);
+ if (block_group >= nr_groups) {
+ udf_debug("block_group (%d) > nr_groups (%d)\n", block_group,
+ nr_groups);
}
- if (bitmap->s_block_bitmap[block_group])
+ if (bitmap->s_block_bitmap[block_group]) {
return block_group;
- else
- {
- retval = read_block_bitmap(sb, bitmap, block_group, block_group);
+ } else {
+ retval = read_block_bitmap(sb, bitmap, block_group,
+ block_group);
if (retval < 0)
return retval;
return block_group;
}
}
-static inline int load_block_bitmap(struct super_block * sb,
- struct udf_bitmap *bitmap, unsigned int block_group)
+static inline int load_block_bitmap(struct super_block *sb,
+ struct udf_bitmap *bitmap,
+ unsigned int block_group)
{
int slot;
@@ -138,13 +138,14 @@ static inline int load_block_bitmap(struct super_block * sb,
return slot;
}
-static void udf_bitmap_free_blocks(struct super_block * sb,
- struct inode * inode,
- struct udf_bitmap *bitmap,
- kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+static void udf_bitmap_free_blocks(struct super_block *sb,
+ struct inode *inode,
+ struct udf_bitmap *bitmap,
+ kernel_lb_addr bloc, uint32_t offset,
+ uint32_t count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
unsigned long block;
unsigned long block_group;
unsigned long bit;
@@ -154,11 +155,10 @@ static void udf_bitmap_free_blocks(struct super_block * sb,
mutex_lock(&sbi->s_alloc_mutex);
if (bloc.logicalBlockNum < 0 ||
- (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
- {
+ (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) {
udf_debug("%d < %d || %d + %d > %d\n",
- bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
- UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+ bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+ UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
goto error_return;
}
@@ -172,8 +172,7 @@ do_more:
/*
* Check to see if we are freeing blocks across a group boundary.
*/
- if (bit + count > (sb->s_blocksize << 3))
- {
+ if (bit + count > (sb->s_blocksize << 3)) {
overflow = bit + count - (sb->s_blocksize << 3);
count -= overflow;
}
@@ -182,27 +181,21 @@ do_more:
goto error_return;
bh = bitmap->s_block_bitmap[bitmap_nr];
- for (i=0; i < count; i++)
- {
- if (udf_set_bit(bit + i, bh->b_data))
- {
+ for (i = 0; i < count; i++) {
+ if (udf_set_bit(bit + i, bh->b_data)) {
udf_debug("bit %ld already set\n", bit + i);
udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]);
- }
- else
- {
+ } else {
if (inode)
DQUOT_FREE_BLOCK(inode, 1);
- if (UDF_SB_LVIDBH(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1);
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]) + 1);
}
}
}
mark_buffer_dirty(bh);
- if (overflow)
- {
+ if (overflow) {
block += count;
count = overflow;
goto do_more;
@@ -215,10 +208,11 @@ error_return:
return;
}
-static int udf_bitmap_prealloc_blocks(struct super_block * sb,
- struct inode * inode,
- struct udf_bitmap *bitmap, uint16_t partition, uint32_t first_block,
- uint32_t block_count)
+static int udf_bitmap_prealloc_blocks(struct super_block *sb,
+ struct inode *inode,
+ struct udf_bitmap *bitmap,
+ uint16_t partition, uint32_t first_block,
+ uint32_t block_count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
int alloc_count = 0;
@@ -235,7 +229,8 @@ static int udf_bitmap_prealloc_blocks(struct super_block * sb,
repeat:
nr_groups = (UDF_SB_PARTLEN(sb, partition) +
- (sizeof(struct spaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
+ (sizeof(struct spaceBitmapDesc) << 3) +
+ (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8);
block = first_block + (sizeof(struct spaceBitmapDesc) << 3);
block_group = block >> (sb->s_blocksize_bits + 3);
group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
@@ -247,31 +242,28 @@ repeat:
bit = block % (sb->s_blocksize << 3);
- while (bit < (sb->s_blocksize << 3) && block_count > 0)
- {
- if (!udf_test_bit(bit, bh->b_data))
+ while (bit < (sb->s_blocksize << 3) && block_count > 0) {
+ if (!udf_test_bit(bit, bh->b_data)) {
goto out;
- else if (DQUOT_PREALLOC_BLOCK(inode, 1))
+ } else if (DQUOT_PREALLOC_BLOCK(inode, 1)) {
goto out;
- else if (!udf_clear_bit(bit, bh->b_data))
- {
+ } else if (!udf_clear_bit(bit, bh->b_data)) {
udf_debug("bit already cleared for block %d\n", bit);
DQUOT_FREE_BLOCK(inode, 1);
goto out;
}
- block_count --;
- alloc_count ++;
- bit ++;
- block ++;
+ block_count--;
+ alloc_count++;
+ bit++;
+ block++;
}
mark_buffer_dirty(bh);
if (block_count > 0)
goto repeat;
out:
- if (UDF_SB_LVIDBH(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - alloc_count);
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
sb->s_dirt = 1;
@@ -279,12 +271,13 @@ out:
return alloc_count;
}
-static int udf_bitmap_new_block(struct super_block * sb,
- struct inode * inode,
- struct udf_bitmap *bitmap, uint16_t partition, uint32_t goal, int *err)
+static int udf_bitmap_new_block(struct super_block *sb,
+ struct inode *inode,
+ struct udf_bitmap *bitmap, uint16_t partition,
+ uint32_t goal, int *err)
{
struct udf_sb_info *sbi = UDF_SB(sb);
- int newbit, bit=0, block, block_group, group_start;
+ int newbit, bit = 0, block, block_group, group_start;
int end_goal, nr_groups, bitmap_nr, i;
struct buffer_head *bh = NULL;
char *ptr;
@@ -306,38 +299,35 @@ repeat:
if (bitmap_nr < 0)
goto error_return;
bh = bitmap->s_block_bitmap[bitmap_nr];
- ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
+ ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+ sb->s_blocksize - group_start);
- if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
- {
+ if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
bit = block % (sb->s_blocksize << 3);
-
if (udf_test_bit(bit, bh->b_data))
- {
goto got_block;
- }
+
end_goal = (bit + 63) & ~63;
bit = udf_find_next_one_bit(bh->b_data, end_goal, bit);
if (bit < end_goal)
goto got_block;
+
ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3));
newbit = (ptr - ((char *)bh->b_data)) << 3;
- if (newbit < sb->s_blocksize << 3)
- {
+ if (newbit < sb->s_blocksize << 3) {
bit = newbit;
goto search_back;
}
+
newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit);
- if (newbit < sb->s_blocksize << 3)
- {
+ if (newbit < sb->s_blocksize << 3) {
bit = newbit;
goto got_block;
}
}
- for (i=0; i<(nr_groups*2); i++)
- {
- block_group ++;
+ for (i = 0; i < (nr_groups * 2); i++) {
+ block_group++;
if (block_group >= nr_groups)
block_group = 0;
group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc);
@@ -346,24 +336,22 @@ repeat:
if (bitmap_nr < 0)
goto error_return;
bh = bitmap->s_block_bitmap[bitmap_nr];
- if (i < nr_groups)
- {
- ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start);
- if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize)
- {
+ if (i < nr_groups) {
+ ptr = memscan((char *)bh->b_data + group_start, 0xFF,
+ sb->s_blocksize - group_start);
+ if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) {
bit = (ptr - ((char *)bh->b_data)) << 3;
break;
}
- }
- else
- {
- bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3);
+ } else {
+ bit = udf_find_next_one_bit((char *)bh->b_data,
+ sb->s_blocksize << 3,
+ group_start << 3);
if (bit < sb->s_blocksize << 3)
break;
}
}
- if (i >= (nr_groups*2))
- {
+ if (i >= (nr_groups * 2)) {
mutex_unlock(&sbi->s_alloc_mutex);
return newblock;
}
@@ -371,22 +359,21 @@ repeat:
goto search_back;
else
bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3);
- if (bit >= sb->s_blocksize << 3)
- {
+ if (bit >= sb->s_blocksize << 3) {
mutex_unlock(&sbi->s_alloc_mutex);
return 0;
}
search_back:
- for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--);
+ for (i = 0; i < 7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--)
+ ; /* empty loop */
got_block:
/*
* Check quota for allocation of this block.
*/
- if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
- {
+ if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) {
mutex_unlock(&sbi->s_alloc_mutex);
*err = -EDQUOT;
return 0;
@@ -395,18 +382,16 @@ got_block:
newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) -
(sizeof(struct spaceBitmapDesc) << 3);
- if (!udf_clear_bit(bit, bh->b_data))
- {
+ if (!udf_clear_bit(bit, bh->b_data)) {
udf_debug("bit already cleared for block %d\n", bit);
goto repeat;
}
mark_buffer_dirty(bh);
- if (UDF_SB_LVIDBH(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - 1);
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
sb->s_dirt = 1;
@@ -420,10 +405,11 @@ error_return:
return 0;
}
-static void udf_table_free_blocks(struct super_block * sb,
- struct inode * inode,
- struct inode * table,
- kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+static void udf_table_free_blocks(struct super_block *sb,
+ struct inode *inode,
+ struct inode *table,
+ kernel_lb_addr bloc, uint32_t offset,
+ uint32_t count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
uint32_t start, end;
@@ -435,11 +421,10 @@ static void udf_table_free_blocks(struct super_block * sb,
mutex_lock(&sbi->s_alloc_mutex);
if (bloc.logicalBlockNum < 0 ||
- (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum))
- {
+ (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) {
udf_debug("%d < %d || %d + %d > %d\n",
- bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
- UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
+ bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count,
+ UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum));
goto error_return;
}
@@ -447,10 +432,9 @@ static void udf_table_free_blocks(struct super_block * sb,
but.. oh well */
if (inode)
DQUOT_FREE_BLOCK(inode, count);
- if (UDF_SB_LVIDBH(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+count);
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]) + count);
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
@@ -462,74 +446,59 @@ static void udf_table_free_blocks(struct super_block * sb,
epos.block = oepos.block = UDF_I_LOCATION(table);
epos.bh = oepos.bh = NULL;
- while (count && (etype =
- udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
- {
- if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) ==
- start))
- {
- if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
- {
+ while (count &&
+ (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+ if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) == start)) {
+ if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) {
count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
start += ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
- }
- else
- {
- elen = (etype << 30) |
- (elen + (count << sb->s_blocksize_bits));
+ } else {
+ elen = (etype << 30) | (elen + (count << sb->s_blocksize_bits));
start += count;
count = 0;
}
udf_write_aext(table, &oepos, eloc, elen, 1);
- }
- else if (eloc.logicalBlockNum == (end + 1))
- {
- if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits))
- {
+ } else if (eloc.logicalBlockNum == (end + 1)) {
+ if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) {
count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
end -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
- eloc.logicalBlockNum -=
- ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
+ eloc.logicalBlockNum -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits);
elen = (etype << 30) | (0x40000000 - sb->s_blocksize);
- }
- else
- {
+ } else {
eloc.logicalBlockNum = start;
- elen = (etype << 30) |
- (elen + (count << sb->s_blocksize_bits));
+ elen = (etype << 30) | (elen + (count << sb->s_blocksize_bits));
end -= count;
count = 0;
}
udf_write_aext(table, &oepos, eloc, elen, 1);
}
- if (epos.bh != oepos.bh)
- {
+ if (epos.bh != oepos.bh) {
i = -1;
oepos.block = epos.block;
brelse(oepos.bh);
get_bh(epos.bh);
oepos.bh = epos.bh;
oepos.offset = 0;
- }
- else
+ } else {
oepos.offset = epos.offset;
+ }
}
- if (count)
- {
- /* NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
- a new block, and since we hold the super block lock already
- very bad things would happen :)
-
- We copy the behavior of udf_add_aext, but instead of
- trying to allocate a new block close to the existing one,
- we just steal a block from the extent we are trying to add.
-
- It would be nice if the blocks were close together, but it
- isn't required.
- */
+ if (count) {
+ /*
+ * NOTE: we CANNOT use udf_add_aext here, as it can try to allocate
+ * a new block, and since we hold the super block lock already
+ * very bad things would happen :)
+ *
+ * We copy the behavior of udf_add_aext, but instead of
+ * trying to allocate a new block close to the existing one,
+ * we just steal a block from the extent we are trying to add.
+ *
+ * It would be nice if the blocks were close together, but it
+ * isn't required.
+ */
int adsize;
short_ad *sad = NULL;
@@ -540,40 +509,35 @@ static void udf_table_free_blocks(struct super_block * sb,
elen = EXT_RECORDED_ALLOCATED |
(count << sb->s_blocksize_bits);
- if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT)
+ if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT) {
adsize = sizeof(short_ad);
- else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG)
+ } else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG) {
adsize = sizeof(long_ad);
- else
- {
+ } else {
brelse(oepos.bh);
brelse(epos.bh);
goto error_return;
}
- if (epos.offset + (2 * adsize) > sb->s_blocksize)
- {
+ if (epos.offset + (2 * adsize) > sb->s_blocksize) {
char *sptr, *dptr;
int loffset;
-
+
brelse(oepos.bh);
oepos = epos;
/* Steal a block from the extent being free'd */
epos.block.logicalBlockNum = eloc.logicalBlockNum;
- eloc.logicalBlockNum ++;
+ eloc.logicalBlockNum++;
elen -= sb->s_blocksize;
- if (!(epos.bh = udf_tread(sb,
- udf_get_lb_pblock(sb, epos.block, 0))))
- {
+ if (!(epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, epos.block, 0)))) {
brelse(oepos.bh);
goto error_return;
}
aed = (struct allocExtDesc *)(epos.bh->b_data);
aed->previousAllocExtLocation = cpu_to_le32(oepos.block.logicalBlockNum);
- if (epos.offset + adsize > sb->s_blocksize)
- {
+ if (epos.offset + adsize > sb->s_blocksize) {
loffset = epos.offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
sptr = UDF_I_DATA(inode) + epos.offset -
@@ -582,73 +546,59 @@ static void udf_table_free_blocks(struct super_block * sb,
dptr = epos.bh->b_data + sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
epos.offset = sizeof(struct allocExtDesc) + adsize;
- }
- else
- {
+ } else {
loffset = epos.offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
sptr = oepos.bh->b_data + epos.offset;
epos.offset = sizeof(struct allocExtDesc);
- if (oepos.bh)
- {
+ if (oepos.bh) {
aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
- }
- else
- {
+ } else {
UDF_I_LENALLOC(table) += adsize;
mark_inode_dirty(table);
}
}
if (UDF_SB_UDFREV(sb) >= 0x0200)
udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 3, 1,
- epos.block.logicalBlockNum, sizeof(tag));
+ epos.block.logicalBlockNum, sizeof(tag));
else
udf_new_tag(epos.bh->b_data, TAG_IDENT_AED, 2, 1,
- epos.block.logicalBlockNum, sizeof(tag));
- switch (UDF_I_ALLOCTYPE(table))
- {
+ epos.block.logicalBlockNum, sizeof(tag));
+
+ switch (UDF_I_ALLOCTYPE(table)) {
case ICBTAG_FLAG_AD_SHORT:
- {
sad = (short_ad *)sptr;
sad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
sb->s_blocksize);
sad->extPosition = cpu_to_le32(epos.block.logicalBlockNum);
break;
- }
case ICBTAG_FLAG_AD_LONG:
- {
lad = (long_ad *)sptr;
lad->extLength = cpu_to_le32(
EXT_NEXT_EXTENT_ALLOCDECS |
sb->s_blocksize);
lad->extLocation = cpu_to_lelb(epos.block);
break;
- }
}
- if (oepos.bh)
- {
+ if (oepos.bh) {
udf_update_tag(oepos.bh->b_data, loffset);
mark_buffer_dirty(oepos.bh);
- }
- else
+ } else {
mark_inode_dirty(table);
+ }
}
- if (elen) /* It's possible that stealing the block emptied the extent */
- {
+ if (elen) { /* It's possible that stealing the block emptied the extent */
udf_write_aext(table, &epos, eloc, elen, 1);
- if (!epos.bh)
- {
+ if (!epos.bh) {
UDF_I_LENALLOC(table) += adsize;
mark_inode_dirty(table);
- }
- else
- {
+ } else {
aed = (struct allocExtDesc *)epos.bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
@@ -667,10 +617,10 @@ error_return:
return;
}
-static int udf_table_prealloc_blocks(struct super_block * sb,
- struct inode * inode,
- struct inode *table, uint16_t partition, uint32_t first_block,
- uint32_t block_count)
+static int udf_table_prealloc_blocks(struct super_block *sb,
+ struct inode *inode,
+ struct inode *table, uint16_t partition,
+ uint32_t first_block, uint32_t block_count)
{
struct udf_sb_info *sbi = UDF_SB(sb);
int alloc_count = 0;
@@ -695,40 +645,36 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
epos.bh = NULL;
eloc.logicalBlockNum = 0xFFFFFFFF;
- while (first_block != eloc.logicalBlockNum && (etype =
- udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
- {
+ while (first_block != eloc.logicalBlockNum &&
+ (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
udf_debug("eloc=%d, elen=%d, first_block=%d\n",
- eloc.logicalBlockNum, elen, first_block);
+ eloc.logicalBlockNum, elen, first_block);
; /* empty loop body */
}
- if (first_block == eloc.logicalBlockNum)
- {
+ if (first_block == eloc.logicalBlockNum) {
epos.offset -= adsize;
alloc_count = (elen >> sb->s_blocksize_bits);
- if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count))
+ if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count)) {
alloc_count = 0;
- else if (alloc_count > block_count)
- {
+ } else if (alloc_count > block_count) {
alloc_count = block_count;
eloc.logicalBlockNum += alloc_count;
elen -= (alloc_count << sb->s_blocksize_bits);
udf_write_aext(table, &epos, eloc, (etype << 30) | elen, 1);
- }
- else
+ } else {
udf_delete_aext(table, epos, eloc, (etype << 30) | elen);
- }
- else
+ }
+ } else {
alloc_count = 0;
+ }
brelse(epos.bh);
- if (alloc_count && UDF_SB_LVIDBH(sb))
- {
+ if (alloc_count && UDF_SB_LVIDBH(sb)) {
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count);
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - alloc_count);
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
sb->s_dirt = 1;
}
@@ -736,9 +682,10 @@ static int udf_table_prealloc_blocks(struct super_block * sb,
return alloc_count;
}
-static int udf_table_new_block(struct super_block * sb,
- struct inode * inode,
- struct inode *table, uint16_t partition, uint32_t goal, int *err)
+static int udf_table_new_block(struct super_block *sb,
+ struct inode *inode,
+ struct inode *table, uint16_t partition,
+ uint32_t goal, int *err)
{
struct udf_sb_info *sbi = UDF_SB(sb);
uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
@@ -765,30 +712,26 @@ static int udf_table_new_block(struct super_block * sb,
we stop. Otherwise we keep going till we run out of extents.
We store the buffer_head, bloc, and extoffset of the current closest
match and use that when we are done.
- */
+ */
epos.offset = sizeof(struct unallocSpaceEntry);
epos.block = UDF_I_LOCATION(table);
epos.bh = goal_epos.bh = NULL;
- while (spread && (etype =
- udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
- {
- if (goal >= eloc.logicalBlockNum)
- {
+ while (spread &&
+ (etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
+ if (goal >= eloc.logicalBlockNum) {
if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits))
nspread = 0;
else
nspread = goal - eloc.logicalBlockNum -
(elen >> sb->s_blocksize_bits);
- }
- else
+ } else {
nspread = eloc.logicalBlockNum - goal;
+ }
- if (nspread < spread)
- {
+ if (nspread < spread) {
spread = nspread;
- if (goal_epos.bh != epos.bh)
- {
+ if (goal_epos.bh != epos.bh) {
brelse(goal_epos.bh);
goal_epos.bh = epos.bh;
get_bh(goal_epos.bh);
@@ -802,8 +745,7 @@ static int udf_table_new_block(struct super_block * sb,
brelse(epos.bh);
- if (spread == 0xFFFFFFFF)
- {
+ if (spread == 0xFFFFFFFF) {
brelse(goal_epos.bh);
mutex_unlock(&sbi->s_alloc_mutex);
return 0;
@@ -815,11 +757,10 @@ static int udf_table_new_block(struct super_block * sb,
/* This works, but very poorly.... */
newblock = goal_eloc.logicalBlockNum;
- goal_eloc.logicalBlockNum ++;
+ goal_eloc.logicalBlockNum++;
goal_elen -= sb->s_blocksize;
- if (inode && DQUOT_ALLOC_BLOCK(inode, 1))
- {
+ if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) {
brelse(goal_epos.bh);
mutex_unlock(&sbi->s_alloc_mutex);
*err = -EDQUOT;
@@ -832,10 +773,9 @@ static int udf_table_new_block(struct super_block * sb,
udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
brelse(goal_epos.bh);
- if (UDF_SB_LVIDBH(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
UDF_SB_LVID(sb)->freeSpaceTable[partition] =
- cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1);
+ cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition]) - 1);
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
@@ -845,105 +785,84 @@ static int udf_table_new_block(struct super_block * sb,
return newblock;
}
-inline void udf_free_blocks(struct super_block * sb,
- struct inode * inode,
- kernel_lb_addr bloc, uint32_t offset, uint32_t count)
+inline void udf_free_blocks(struct super_block *sb,
+ struct inode *inode,
+ kernel_lb_addr bloc, uint32_t offset,
+ uint32_t count)
{
uint16_t partition = bloc.partitionReferenceNum;
- if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
+ if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
return udf_bitmap_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
- bloc, offset, count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+ bloc, offset, count);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
return udf_table_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
- bloc, offset, count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+ bloc, offset, count);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
return udf_bitmap_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
- bloc, offset, count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+ bloc, offset, count);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
return udf_table_free_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
- bloc, offset, count);
- }
- else
+ UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+ bloc, offset, count);
+ } else {
return;
+ }
}
-inline int udf_prealloc_blocks(struct super_block * sb,
- struct inode * inode,
- uint16_t partition, uint32_t first_block, uint32_t block_count)
+inline int udf_prealloc_blocks(struct super_block *sb,
+ struct inode *inode,
+ uint16_t partition, uint32_t first_block,
+ uint32_t block_count)
{
- if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
+ if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
return udf_bitmap_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
- partition, first_block, block_count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+ partition, first_block, block_count);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
return udf_table_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
- partition, first_block, block_count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+ partition, first_block, block_count);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
return udf_bitmap_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
- partition, first_block, block_count);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+ partition, first_block, block_count);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
return udf_table_prealloc_blocks(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
- partition, first_block, block_count);
- }
- else
+ UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+ partition, first_block, block_count);
+ } else {
return 0;
+ }
}
-inline int udf_new_block(struct super_block * sb,
- struct inode * inode,
- uint16_t partition, uint32_t goal, int *err)
+inline int udf_new_block(struct super_block *sb,
+ struct inode *inode,
+ uint16_t partition, uint32_t goal, int *err)
{
int ret;
- if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
+ if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) {
ret = udf_bitmap_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
- partition, goal, err);
+ UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap,
+ partition, goal, err);
return ret;
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) {
return udf_table_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
- partition, goal, err);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table,
+ partition, goal, err);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) {
return udf_bitmap_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
- partition, goal, err);
- }
- else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE)
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap,
+ partition, goal, err);
+ } else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) {
return udf_table_new_block(sb, inode,
- UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
- partition, goal, err);
- }
- else
- {
+ UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table,
+ partition, goal, err);
+ } else {
*err = -EIO;
return 0;
}
diff --git a/fs/udf/crc.c b/fs/udf/crc.c
index 1b82a4adc2f7..85aaee5fab26 100644
--- a/fs/udf/crc.c
+++ b/fs/udf/crc.c
@@ -79,8 +79,7 @@ static uint16_t crc_table[256] = {
* July 21, 1997 - Andrew E. Mileski
* Adapted from OSTA-UDF(tm) 1.50 standard.
*/
-uint16_t
-udf_crc(uint8_t *data, uint32_t size, uint16_t crc)
+uint16_t udf_crc(uint8_t * data, uint32_t size, uint16_t crc)
{
while (size--)
crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8);
@@ -106,8 +105,8 @@ int main(void)
{
unsigned short x;
- x = udf_crc16(bytes, sizeof bytes);
- printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
+ x = udf_crc(bytes, sizeof bytes);
+ printf("udf_crc: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U);
return 0;
}
@@ -138,7 +137,7 @@ int main(int argc, char **argv)
/* Get the polynomial */
sscanf(argv[1], "%lo", &poly);
- if (poly & 0xffff0000U){
+ if (poly & 0xffff0000U) {
fprintf(stderr, "polynomial is too large\en");
exit(1);
}
@@ -147,22 +146,22 @@ int main(int argc, char **argv)
/* Create a table */
printf("static unsigned short crc_table[256] = {\n");
- for (n = 0; n < 256; n++){
+ for (n = 0; n < 256; n++) {
if (n % 8 == 0)
printf("\t");
crc = n << 8;
- for (i = 0; i < 8; i++){
- if(crc & 0x8000U)
+ for (i = 0; i < 8; i++) {
+ if (crc & 0x8000U)
crc = (crc << 1) ^ poly;
else
crc <<= 1;
- crc &= 0xFFFFU;
+ crc &= 0xFFFFU;
}
if (n == 255)
printf("0x%04xU ", crc);
else
printf("0x%04xU, ", crc);
- if(n % 8 == 7)
+ if (n % 8 == 7)
printf("\n");
}
printf("};\n");
diff --git a/fs/udf/dir.c b/fs/udf/dir.c
index e45f86b5e7b0..9e3b9f97ddbc 100644
--- a/fs/udf/dir.c
+++ b/fs/udf/dir.c
@@ -82,14 +82,12 @@ int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
lock_kernel();
- if ( filp->f_pos == 0 )
- {
- if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0)
- {
+ if (filp->f_pos == 0) {
+ if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) {
unlock_kernel();
return 0;
}
- filp->f_pos ++;
+ filp->f_pos++;
}
result = do_udf_readdir(dir, filp, filldir, dirent);
@@ -97,11 +95,12 @@ int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
return result;
}
-static int
-do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent)
+static int
+do_udf_readdir(struct inode *dir, struct file *filp, filldir_t filldir,
+ void *dirent)
{
struct udf_fileident_bh fibh;
- struct fileIdentDesc *fi=NULL;
+ struct fileIdentDesc *fi = NULL;
struct fileIdentDesc cfi;
int block, iblock;
loff_t nf_pos = filp->f_pos - 1;
@@ -117,7 +116,7 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
sector_t offset;
int i, num;
unsigned int dt_type;
- struct extent_position epos = { NULL, 0, {0, 0}};
+ struct extent_position epos = { NULL, 0, {0, 0} };
if (nf_pos >= size)
return 0;
@@ -126,64 +125,54 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
nf_pos = (udf_ext0_offset(dir) >> 2);
fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
fibh.sbh = fibh.ebh = NULL;
- else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
- {
+ } else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
epos.offset -= sizeof(long_ad);
- }
- else
+ } else {
offset = 0;
+ }
- if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
- {
+ if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
brelse(epos.bh);
return -EIO;
}
-
- if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
- {
+
+ if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
- if (i+offset > (elen >> dir->i_sb->s_blocksize_bits))
- i = (elen >> dir->i_sb->s_blocksize_bits)-offset;
- for (num=0; i>0; i--)
- {
- block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i);
+ if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
+ i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
+ for (num = 0; i > 0; i--) {
+ block = udf_get_lb_pblock(dir->i_sb, eloc, offset + i);
tmp = udf_tgetblk(dir->i_sb, block);
if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
bha[num++] = tmp;
else
brelse(tmp);
}
- if (num)
- {
+ if (num) {
ll_rw_block(READA, num, bha);
- for (i=0; i<num; i++)
+ for (i = 0; i < num; i++)
brelse(bha[i]);
}
}
- }
- else
- {
+ } else {
brelse(epos.bh);
return -ENOENT;
}
- while ( nf_pos < size )
- {
+ while (nf_pos < size) {
filp->f_pos = nf_pos + 1;
- fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
-
- if (!fi)
- {
+ fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
+ &elen, &offset);
+ if (!fi) {
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
@@ -194,45 +183,40 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
liu = le16_to_cpu(cfi.lengthOfImpUse);
lfi = cfi.lengthFileIdent;
- if (fibh.sbh == fibh.ebh)
+ if (fibh.sbh == fibh.ebh) {
nameptr = fi->fileIdent + liu;
- else
- {
+ } else {
int poffset; /* Unpaded ending offset */
poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
- if (poffset >= lfi)
+ if (poffset >= lfi) {
nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
- else
- {
+ } else {
nameptr = fname;
- memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
- memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset);
+ memcpy(nameptr, fi->fileIdent + liu,
+ lfi - poffset);
+ memcpy(nameptr + lfi - poffset,
+ fibh.ebh->b_data, poffset);
}
}
- if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
+ if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
continue;
}
-
- if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
+
+ if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
continue;
}
- if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT )
- {
+ if (cfi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
iblock = parent_ino(filp->f_path.dentry);
flen = 2;
memcpy(fname, "..", flen);
dt_type = DT_DIR;
- }
- else
- {
+ } else {
kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0);
@@ -240,10 +224,8 @@ do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *d
dt_type = DT_UNKNOWN;
}
- if (flen)
- {
- if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0)
- {
+ if (flen) {
+ if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) {
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
index 198caa33027a..ff8c08fd7bf5 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -19,10 +19,10 @@
#include <linux/buffer_head.h>
#if 0
-static uint8_t *
-udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
- kernel_lb_addr fe_loc, int *pos, int *offset,
- struct buffer_head **bh, int *error)
+static uint8_t *udf_filead_read(struct inode *dir, uint8_t * tmpad,
+ uint8_t ad_size, kernel_lb_addr fe_loc,
+ int *pos, int *offset, struct buffer_head **bh,
+ int *error)
{
int loffset = *offset;
int block;
@@ -34,24 +34,20 @@ udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
ad = (uint8_t *)(*bh)->b_data + *offset;
*offset += ad_size;
- if (!ad)
- {
+ if (!ad) {
brelse(*bh);
*error = 1;
return NULL;
}
- if (*offset == dir->i_sb->s_blocksize)
- {
+ if (*offset == dir->i_sb->s_blocksize) {
brelse(*bh);
block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
if (!block)
return NULL;
if (!(*bh = udf_tread(dir->i_sb, block)))
return NULL;
- }
- else if (*offset > dir->i_sb->s_blocksize)
- {
+ } else if (*offset > dir->i_sb->s_blocksize) {
ad = tmpad;
remainder = dir->i_sb->s_blocksize - loffset;
@@ -67,53 +63,51 @@ udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder);
*offset = ad_size - remainder;
}
+
return ad;
}
#endif
-struct fileIdentDesc *
-udf_fileident_read(struct inode *dir, loff_t *nf_pos,
- struct udf_fileident_bh *fibh,
- struct fileIdentDesc *cfi,
- struct extent_position *epos,
- kernel_lb_addr *eloc, uint32_t *elen,
- sector_t *offset)
+struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t * nf_pos,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi,
+ struct extent_position *epos,
+ kernel_lb_addr * eloc, uint32_t * elen,
+ sector_t * offset)
{
struct fileIdentDesc *fi;
int i, num, block;
- struct buffer_head * tmp, * bha[16];
+ struct buffer_head *tmp, *bha[16];
fibh->soffset = fibh->eoffset;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
fi = udf_get_fileident(UDF_I_DATA(dir) -
- (UDF_I_EFE(dir) ?
- sizeof(struct extendedFileEntry) :
- sizeof(struct fileEntry)),
- dir->i_sb->s_blocksize, &(fibh->eoffset));
-
+ (UDF_I_EFE(dir) ?
+ sizeof(struct extendedFileEntry) :
+ sizeof(struct fileEntry)),
+ dir->i_sb->s_blocksize, &(fibh->eoffset));
if (!fi)
return NULL;
*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
- memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+ memcpy((uint8_t *)cfi, (uint8_t *)fi,
+ sizeof(struct fileIdentDesc));
return fi;
}
- if (fibh->eoffset == dir->i_sb->s_blocksize)
- {
+ if (fibh->eoffset == dir->i_sb->s_blocksize) {
int lextoffset = epos->offset;
if (udf_next_aext(dir, epos, eloc, elen, 1) !=
- (EXT_RECORDED_ALLOCATED >> 30))
+ (EXT_RECORDED_ALLOCATED >> 30))
return NULL;
block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
- (*offset) ++;
+ (*offset)++;
if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
*offset = 0;
@@ -125,57 +119,50 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
return NULL;
fibh->soffset = fibh->eoffset = 0;
- if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
- {
+ if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
- if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits))
+ if (i + *offset > (*elen >> dir->i_sb->s_blocksize_bits))
i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
- for (num=0; i>0; i--)
- {
- block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
+ for (num = 0; i > 0; i--) {
+ block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset + i);
tmp = udf_tgetblk(dir->i_sb, block);
if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
bha[num++] = tmp;
else
brelse(tmp);
}
- if (num)
- {
+ if (num) {
ll_rw_block(READA, num, bha);
- for (i=0; i<num; i++)
+ for (i = 0; i < num; i++)
brelse(bha[i]);
}
}
- }
- else if (fibh->sbh != fibh->ebh)
- {
+ } else if (fibh->sbh != fibh->ebh) {
brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
- &(fibh->eoffset));
+ &(fibh->eoffset));
if (!fi)
return NULL;
*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
- if (fibh->eoffset <= dir->i_sb->s_blocksize)
- {
- memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
- }
- else if (fibh->eoffset > dir->i_sb->s_blocksize)
- {
+ if (fibh->eoffset <= dir->i_sb->s_blocksize) {
+ memcpy((uint8_t *)cfi, (uint8_t *)fi,
+ sizeof(struct fileIdentDesc));
+ } else if (fibh->eoffset > dir->i_sb->s_blocksize) {
int lextoffset = epos->offset;
if (udf_next_aext(dir, epos, eloc, elen, 1) !=
- (EXT_RECORDED_ALLOCATED >> 30))
+ (EXT_RECORDED_ALLOCATED >> 30))
return NULL;
block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
- (*offset) ++;
+ (*offset)++;
if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
*offset = 0;
@@ -188,62 +175,59 @@ udf_fileident_read(struct inode *dir, loff_t *nf_pos,
if (!(fibh->ebh = udf_tread(dir->i_sb, block)))
return NULL;
- if (sizeof(struct fileIdentDesc) > - fibh->soffset)
- {
+ if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
int fi_len;
- memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset);
+ memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data,
- sizeof(struct fileIdentDesc) + fibh->soffset);
+ sizeof(struct fileIdentDesc) + fibh->soffset);
fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent +
- le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
+ le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
*nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
fibh->eoffset = fibh->soffset + fi_len;
- }
- else
- {
- memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+ } else {
+ memcpy((uint8_t *)cfi, (uint8_t *)fi,
+ sizeof(struct fileIdentDesc));
}
}
return fi;
}
-struct fileIdentDesc *
-udf_get_fileident(void * buffer, int bufsize, int * offset)
+struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
{
struct fileIdentDesc *fi;
int lengthThisIdent;
- uint8_t * ptr;
+ uint8_t *ptr;
int padlen;
- if ( (!buffer) || (!offset) ) {
- udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
+ if ((!buffer) || (!offset)) {
+ udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer,
+ offset);
return NULL;
}
ptr = buffer;
- if ( (*offset > 0) && (*offset < bufsize) ) {
+ if ((*offset > 0) && (*offset < bufsize)) {
ptr += *offset;
}
- fi=(struct fileIdentDesc *)ptr;
- if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID)
- {
+ fi = (struct fileIdentDesc *)ptr;
+ if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID) {
udf_debug("0x%x != TAG_IDENT_FID\n",
- le16_to_cpu(fi->descTag.tagIdent));
+ le16_to_cpu(fi->descTag.tagIdent));
udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
- *offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize);
+ *offset, (unsigned long)sizeof(struct fileIdentDesc),
+ bufsize);
return NULL;
}
- if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize )
- {
+ if ((*offset + sizeof(struct fileIdentDesc)) > bufsize) {
lengthThisIdent = sizeof(struct fileIdentDesc);
- }
- else
+ } else {
lengthThisIdent = sizeof(struct fileIdentDesc) +
fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+ }
/* we need to figure padding, too! */
padlen = lengthThisIdent % UDF_NAME_PAD;
@@ -255,32 +239,28 @@ udf_get_fileident(void * buffer, int bufsize, int * offset)
}
#if 0
-static extent_ad *
-udf_get_fileextent(void * buffer, int bufsize, int * offset)
+static extent_ad *udf_get_fileextent(void *buffer, int bufsize, int *offset)
{
- extent_ad * ext;
+ extent_ad *ext;
struct fileEntry *fe;
- uint8_t * ptr;
+ uint8_t *ptr;
- if ( (!buffer) || (!offset) )
- {
+ if ((!buffer) || (!offset)) {
printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
return NULL;
}
fe = (struct fileEntry *)buffer;
- if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE )
- {
+ if (le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE) {
udf_debug("0x%x != TAG_IDENT_FE\n",
- le16_to_cpu(fe->descTag.tagIdent));
+ le16_to_cpu(fe->descTag.tagIdent));
return NULL;
}
- ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
+ ptr = (uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
- if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
- {
+ if ((*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs))) {
ptr += *offset;
}
@@ -291,18 +271,17 @@ udf_get_fileextent(void * buffer, int bufsize, int * offset)
}
#endif
-short_ad *
-udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
+short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset,
+ int inc)
{
short_ad *sa;
- if ( (!ptr) || (!offset) )
- {
+ if ((!ptr) || (!offset)) {
printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
return NULL;
}
- if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) )
+ if ((*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset))
return NULL;
else if ((sa = (short_ad *)ptr)->extLength == 0)
return NULL;
@@ -312,18 +291,16 @@ udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
return sa;
}
-long_ad *
-udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc)
+long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, int *offset, int inc)
{
long_ad *la;
- if ( (!ptr) || (!offset) )
- {
+ if ((!ptr) || (!offset)) {
printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
return NULL;
}
- if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) )
+ if ((*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset))
return NULL;
else if ((la = (long_ad *)ptr)->extLength == 0)
return NULL;
diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h
index f81f2ebbf508..56387711589b 100644
--- a/fs/udf/ecma_167.h
+++ b/fs/udf/ecma_167.h
@@ -38,8 +38,7 @@
#define _ECMA_167_H 1
/* Character set specification (ECMA 167r3 1/7.2.1) */
-typedef struct
-{
+typedef struct {
uint8_t charSetType;
uint8_t charSetInfo[63];
} __attribute__ ((packed)) charspec;
@@ -58,8 +57,7 @@ typedef struct
typedef uint8_t dstring;
/* Timestamp (ECMA 167r3 1/7.3) */
-typedef struct
-{
+typedef struct {
__le16 typeAndTimezone;
__le16 year;
uint8_t month;
@@ -72,8 +70,7 @@ typedef struct
uint8_t microseconds;
} __attribute__ ((packed)) timestamp;
-typedef struct
-{
+typedef struct {
uint16_t typeAndTimezone;
int16_t year;
uint8_t month;
@@ -94,8 +91,7 @@ typedef struct
#define TIMESTAMP_TIMEZONE_MASK 0x0FFF
/* Entity identifier (ECMA 167r3 1/7.4) */
-typedef struct
-{
+typedef struct {
uint8_t flags;
uint8_t ident[23];
uint8_t identSuffix[8];
@@ -107,8 +103,7 @@ typedef struct
/* Volume Structure Descriptor (ECMA 167r3 2/9.1) */
#define VSD_STD_ID_LEN 5
-struct volStructDesc
-{
+struct volStructDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
@@ -127,8 +122,7 @@ struct volStructDesc
#define VSD_STD_ID_TEA01 "TEA01" /* (2/9.3) */
/* Beginning Extended Area Descriptor (ECMA 167r3 2/9.2) */
-struct beginningExtendedAreaDesc
-{
+struct beginningExtendedAreaDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
@@ -136,8 +130,7 @@ struct beginningExtendedAreaDesc
} __attribute__ ((packed));
/* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */
-struct terminatingExtendedAreaDesc
-{
+struct terminatingExtendedAreaDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
@@ -145,8 +138,7 @@ struct terminatingExtendedAreaDesc
} __attribute__ ((packed));
/* Boot Descriptor (ECMA 167r3 2/9.4) */
-struct bootDesc
-{
+struct bootDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
@@ -167,21 +159,18 @@ struct bootDesc
#define BOOT_FLAGS_ERASE 0x01
/* Extent Descriptor (ECMA 167r3 3/7.1) */
-typedef struct
-{
+typedef struct {
__le32 extLength;
__le32 extLocation;
} __attribute__ ((packed)) extent_ad;
-typedef struct
-{
+typedef struct {
uint32_t extLength;
uint32_t extLocation;
} kernel_extent_ad;
/* Descriptor Tag (ECMA 167r3 3/7.2) */
-typedef struct
-{
+typedef struct {
__le16 tagIdent;
__le16 descVersion;
uint8_t tagChecksum;
@@ -204,18 +193,16 @@ typedef struct
#define TAG_IDENT_LVID 0x0009
/* NSR Descriptor (ECMA 167r3 3/9.1) */
-struct NSRDesc
-{
+struct NSRDesc {
uint8_t structType;
uint8_t stdIdent[VSD_STD_ID_LEN];
uint8_t structVersion;
uint8_t reserved;
uint8_t structData[2040];
} __attribute__ ((packed));
-
+
/* Primary Volume Descriptor (ECMA 167r3 3/10.1) */
-struct primaryVolDesc
-{
+struct primaryVolDesc {
tag descTag;
__le32 volDescSeqNum;
__le32 primaryVolDescNum;
@@ -244,8 +231,7 @@ struct primaryVolDesc
#define PVD_FLAGS_VSID_COMMON 0x0001
/* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) */
-struct anchorVolDescPtr
-{
+struct anchorVolDescPtr {
tag descTag;
extent_ad mainVolDescSeqExt;
extent_ad reserveVolDescSeqExt;
@@ -253,8 +239,7 @@ struct anchorVolDescPtr
} __attribute__ ((packed));
/* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */
-struct volDescPtr
-{
+struct volDescPtr {
tag descTag;
__le32 volDescSeqNum;
extent_ad nextVolDescSeqExt;
@@ -262,8 +247,7 @@ struct volDescPtr
} __attribute__ ((packed));
/* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */
-struct impUseVolDesc
-{
+struct impUseVolDesc {
tag descTag;
__le32 volDescSeqNum;
regid impIdent;
@@ -271,20 +255,19 @@ struct impUseVolDesc
} __attribute__ ((packed));
/* Partition Descriptor (ECMA 167r3 3/10.5) */
-struct partitionDesc
-{
- tag descTag;
- __le32 volDescSeqNum;
- __le16 partitionFlags;
- __le16 partitionNumber;
- regid partitionContents;
- uint8_t partitionContentsUse[128];
- __le32 accessType;
- __le32 partitionStartingLocation;
- __le32 partitionLength;
- regid impIdent;
- uint8_t impUse[128];
- uint8_t reserved[156];
+struct partitionDesc {
+ tag descTag;
+ __le32 volDescSeqNum;
+ __le16 partitionFlags;
+ __le16 partitionNumber;
+ regid partitionContents;
+ uint8_t partitionContentsUse[128];
+ __le32 accessType;
+ __le32 partitionStartingLocation;
+ __le32 partitionLength;
+ regid impIdent;
+ uint8_t impUse[128];
+ uint8_t reserved[156];
} __attribute__ ((packed));
/* Partition Flags (ECMA 167r3 3/10.5.3) */
@@ -307,8 +290,7 @@ struct partitionDesc
#define PD_ACCESS_TYPE_OVERWRITABLE 0x00000004
/* Logical Volume Descriptor (ECMA 167r3 3/10.6) */
-struct logicalVolDesc
-{
+struct logicalVolDesc {
tag descTag;
__le32 volDescSeqNum;
charspec descCharSet;
@@ -325,8 +307,7 @@ struct logicalVolDesc
} __attribute__ ((packed));
/* Generic Partition Map (ECMA 167r3 3/10.7.1) */
-struct genericPartitionMap
-{
+struct genericPartitionMap {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t partitionMapping[0];
@@ -338,8 +319,7 @@ struct genericPartitionMap
#define GP_PARTITION_MAP_TYPE_2 0x02
/* Type 1 Partition Map (ECMA 167r3 3/10.7.2) */
-struct genericPartitionMap1
-{
+struct genericPartitionMap1 {
uint8_t partitionMapType;
uint8_t partitionMapLength;
__le16 volSeqNum;
@@ -347,16 +327,14 @@ struct genericPartitionMap1
} __attribute__ ((packed));
/* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */
-struct genericPartitionMap2
-{
+struct genericPartitionMap2 {
uint8_t partitionMapType;
- uint8_t partitionMapLength;
+ uint8_t partitionMapLength;
uint8_t partitionIdent[62];
} __attribute__ ((packed));
/* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */
-struct unallocSpaceDesc
-{
+struct unallocSpaceDesc {
tag descTag;
__le32 volDescSeqNum;
__le32 numAllocDescs;
@@ -364,15 +342,13 @@ struct unallocSpaceDesc
} __attribute__ ((packed));
/* Terminating Descriptor (ECMA 167r3 3/10.9) */
-struct terminatingDesc
-{
+struct terminatingDesc {
tag descTag;
uint8_t reserved[496];
} __attribute__ ((packed));
/* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */
-struct logicalVolIntegrityDesc
-{
+struct logicalVolIntegrityDesc {
tag descTag;
timestamp recordingDateAndTime;
__le32 integrityType;
@@ -390,52 +366,45 @@ struct logicalVolIntegrityDesc
#define LVID_INTEGRITY_TYPE_CLOSE 0x00000001
/* Recorded Address (ECMA 167r3 4/7.1) */
-typedef struct
-{
+typedef struct {
__le32 logicalBlockNum;
__le16 partitionReferenceNum;
} __attribute__ ((packed)) lb_addr;
/* ... and its in-core analog */
-typedef struct
-{
+typedef struct {
uint32_t logicalBlockNum;
uint16_t partitionReferenceNum;
} kernel_lb_addr;
/* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */
-typedef struct
-{
+typedef struct {
__le32 extLength;
__le32 extPosition;
} __attribute__ ((packed)) short_ad;
/* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */
-typedef struct
-{
+typedef struct {
__le32 extLength;
lb_addr extLocation;
uint8_t impUse[6];
} __attribute__ ((packed)) long_ad;
-typedef struct
-{
+typedef struct {
uint32_t extLength;
kernel_lb_addr extLocation;
uint8_t impUse[6];
} kernel_long_ad;
/* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
-typedef struct
-{
+typedef struct {
__le32 extLength;
__le32 recordedLength;
__le32 informationLength;
lb_addr extLocation;
} __attribute__ ((packed)) ext_ad;
-typedef struct
-{
+typedef struct {
uint32_t extLength;
uint32_t recordedLength;
uint32_t informationLength;
@@ -458,8 +427,7 @@ typedef struct
#define TAG_IDENT_EFE 0x010A
/* File Set Descriptor (ECMA 167r3 4/14.1) */
-struct fileSetDesc
-{
+struct fileSetDesc {
tag descTag;
timestamp recordingDateAndTime;
__le16 interchangeLvl;
@@ -482,8 +450,7 @@ struct fileSetDesc
} __attribute__ ((packed));
/* Partition Header Descriptor (ECMA 167r3 4/14.3) */
-struct partitionHeaderDesc
-{
+struct partitionHeaderDesc {
short_ad unallocSpaceTable;
short_ad unallocSpaceBitmap;
short_ad partitionIntegrityTable;
@@ -493,8 +460,7 @@ struct partitionHeaderDesc
} __attribute__ ((packed));
/* File Identifier Descriptor (ECMA 167r3 4/14.4) */
-struct fileIdentDesc
-{
+struct fileIdentDesc {
tag descTag;
__le16 fileVersionNum;
uint8_t fileCharacteristics;
@@ -514,16 +480,14 @@ struct fileIdentDesc
#define FID_FILE_CHAR_METADATA 0x10
/* Allocation Ext Descriptor (ECMA 167r3 4/14.5) */
-struct allocExtDesc
-{
+struct allocExtDesc {
tag descTag;
__le32 previousAllocExtLocation;
__le32 lengthAllocDescs;
} __attribute__ ((packed));
/* ICB Tag (ECMA 167r3 4/14.6) */
-typedef struct
-{
+typedef struct {
__le32 priorRecordedNumDirectEntries;
__le16 strategyType;
__le16 strategyParameter;
@@ -576,23 +540,20 @@ typedef struct
#define ICBTAG_FLAG_STREAM 0x2000
/* Indirect Entry (ECMA 167r3 4/14.7) */
-struct indirectEntry
-{
+struct indirectEntry {
tag descTag;
icbtag icbTag;
long_ad indirectICB;
} __attribute__ ((packed));
/* Terminal Entry (ECMA 167r3 4/14.8) */
-struct terminalEntry
-{
+struct terminalEntry {
tag descTag;
icbtag icbTag;
} __attribute__ ((packed));
/* File Entry (ECMA 167r3 4/14.9) */
-struct fileEntry
-{
+struct fileEntry {
tag descTag;
icbtag icbTag;
__le32 uid;
@@ -655,16 +616,14 @@ struct fileEntry
#define FE_RECORD_DISPLAY_ATTR_3 0x03
/* Extended Attribute Header Descriptor (ECMA 167r3 4/14.10.1) */
-struct extendedAttrHeaderDesc
-{
+struct extendedAttrHeaderDesc {
tag descTag;
__le32 impAttrLocation;
__le32 appAttrLocation;
} __attribute__ ((packed));
/* Generic Format (ECMA 167r3 4/14.10.2) */
-struct genericFormat
-{
+struct genericFormat {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -673,8 +632,7 @@ struct genericFormat
} __attribute__ ((packed));
/* Character Set Information (ECMA 167r3 4/14.10.3) */
-struct charSetInfo
-{
+struct charSetInfo {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -685,8 +643,7 @@ struct charSetInfo
} __attribute__ ((packed));
/* Alternate Permissions (ECMA 167r3 4/14.10.4) */
-struct altPerms
-{
+struct altPerms {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -697,8 +654,7 @@ struct altPerms
} __attribute__ ((packed));
/* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */
-struct fileTimesExtAttr
-{
+struct fileTimesExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -715,8 +671,7 @@ struct fileTimesExtAttr
#define FTE_BACKUP 0x00000002
/* Information Times Extended Attribute (ECMA 167r3 4/14.10.6) */
-struct infoTimesExtAttr
-{
+struct infoTimesExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -727,8 +682,7 @@ struct infoTimesExtAttr
} __attribute__ ((packed));
/* Device Specification (ECMA 167r3 4/14.10.7) */
-struct deviceSpec
-{
+struct deviceSpec {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -740,8 +694,7 @@ struct deviceSpec
} __attribute__ ((packed));
/* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */
-struct impUseExtAttr
-{
+struct impUseExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -752,8 +705,7 @@ struct impUseExtAttr
} __attribute__ ((packed));
/* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */
-struct appUseExtAttr
-{
+struct appUseExtAttr {
__le32 attrType;
uint8_t attrSubtype;
uint8_t reserved[3];
@@ -771,10 +723,8 @@ struct appUseExtAttr
#define EXTATTR_IMP_USE 2048
#define EXTATTR_APP_USE 65536
-
/* Unallocated Space Entry (ECMA 167r3 4/14.11) */
-struct unallocSpaceEntry
-{
+struct unallocSpaceEntry {
tag descTag;
icbtag icbTag;
__le32 lengthAllocDescs;
@@ -782,8 +732,7 @@ struct unallocSpaceEntry
} __attribute__ ((packed));
/* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */
-struct spaceBitmapDesc
-{
+struct spaceBitmapDesc {
tag descTag;
__le32 numOfBits;
__le32 numOfBytes;
@@ -791,8 +740,7 @@ struct spaceBitmapDesc
} __attribute__ ((packed));
/* Partition Integrity Entry (ECMA 167r3 4/14.13) */
-struct partitionIntegrityEntry
-{
+struct partitionIntegrityEntry {
tag descTag;
icbtag icbTag;
timestamp recordingDateAndTime;
@@ -815,15 +763,13 @@ struct partitionIntegrityEntry
/* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */
/* Logical Volume Header Descriptor (ECMA 167r3 4/14.15) */
-struct logicalVolHeaderDesc
-{
+struct logicalVolHeaderDesc {
__le64 uniqueID;
uint8_t reserved[24];
} __attribute__ ((packed));
/* Path Component (ECMA 167r3 4/14.16.1) */
-struct pathComponent
-{
+struct pathComponent {
uint8_t componentType;
uint8_t lengthComponentIdent;
__le16 componentFileVersionNum;
@@ -831,8 +777,7 @@ struct pathComponent
} __attribute__ ((packed));
/* File Entry (ECMA 167r3 4/14.17) */
-struct extendedFileEntry
-{
+struct extendedFileEntry {
tag descTag;
icbtag icbTag;
__le32 uid;
diff --git a/fs/udf/file.c b/fs/udf/file.c
index df070bee8d4f..5d7a4ea27753 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -41,7 +41,7 @@
#include "udf_i.h"
#include "udf_sb.h"
-static int udf_adinicb_readpage(struct file *file, struct page * page)
+static int udf_adinicb_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
char *kaddr;
@@ -55,6 +55,7 @@ static int udf_adinicb_readpage(struct file *file, struct page * page)
SetPageUptodate(page);
kunmap(page);
unlock_page(page);
+
return 0;
}
@@ -71,22 +72,25 @@ static int udf_adinicb_writepage(struct page *page, struct writeback_control *wb
SetPageUptodate(page);
kunmap(page);
unlock_page(page);
+
return 0;
}
-static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int udf_adinicb_prepare_write(struct file *file, struct page *page,
+ unsigned offset, unsigned to)
{
kmap(page);
return 0;
}
-static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
+static int udf_adinicb_commit_write(struct file *file, struct page *page,
+ unsigned offset, unsigned to)
{
struct inode *inode = page->mapping->host;
char *kaddr = page_address(page);
memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset,
- kaddr + offset, to - offset);
+ kaddr + offset, to - offset);
mark_inode_dirty(inode);
SetPageUptodate(page);
kunmap(page);
@@ -97,15 +101,15 @@ static int udf_adinicb_commit_write(struct file *file, struct page *page, unsign
}
const struct address_space_operations udf_adinicb_aops = {
- .readpage = udf_adinicb_readpage,
- .writepage = udf_adinicb_writepage,
- .sync_page = block_sync_page,
- .prepare_write = udf_adinicb_prepare_write,
- .commit_write = udf_adinicb_commit_write,
+ .readpage = udf_adinicb_readpage,
+ .writepage = udf_adinicb_writepage,
+ .sync_page = block_sync_page,
+ .prepare_write = udf_adinicb_prepare_write,
+ .commit_write = udf_adinicb_commit_write,
};
static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t ppos)
+ unsigned long nr_segs, loff_t ppos)
{
ssize_t retval;
struct file *file = iocb->ki_filp;
@@ -113,25 +117,20 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
int err, pos;
size_t count = iocb->ki_left;
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
if (file->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = ppos;
if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
- pos + count))
- {
+ pos + count)) {
udf_expand_file_adinicb(inode, pos + count, &err);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
udf_debug("udf_expand_adinicb: err=%d\n", err);
return err;
}
- }
- else
- {
+ } else {
if (pos + count > inode->i_size)
UDF_I_LENALLOC(inode) = pos + count;
else
@@ -140,9 +139,9 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
}
retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
-
if (retval > 0)
mark_inode_dirty(inode);
+
return retval;
}
@@ -181,48 +180,42 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
* Written, tested, and released.
*/
int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+ unsigned long arg)
{
+ long old_block, new_block;
int result = -EINVAL;
- if ( file_permission(filp, MAY_READ) != 0 )
- {
+ if (file_permission(filp, MAY_READ) != 0) {
udf_debug("no permission to access inode %lu\n",
- inode->i_ino);
+ inode->i_ino);
return -EPERM;
}
- if ( !arg )
- {
+ if (!arg) {
udf_debug("invalid argument to udf_ioctl\n");
return -EINVAL;
}
- switch (cmd)
- {
- case UDF_GETVOLIDENT:
- return copy_to_user((char __user *)arg,
- UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
- case UDF_RELOCATE_BLOCKS:
- {
- long old, new;
-
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
- if (get_user(old, (long __user *)arg)) return -EFAULT;
- if ((result = udf_relocate_blocks(inode->i_sb,
- old, &new)) == 0)
- result = put_user(new, (long __user *)arg);
-
- return result;
- }
- case UDF_GETEASIZE:
- result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
- break;
-
- case UDF_GETEABLOCK:
- result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
- UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
- break;
+ switch (cmd) {
+ case UDF_GETVOLIDENT:
+ return copy_to_user((char __user *)arg,
+ UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0;
+ case UDF_RELOCATE_BLOCKS:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (get_user(old_block, (long __user *)arg))
+ return -EFAULT;
+ if ((result = udf_relocate_blocks(inode->i_sb,
+ old_block, &new_block)) == 0)
+ result = put_user(new_block, (long __user *)arg);
+ return result;
+ case UDF_GETEASIZE:
+ result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg);
+ break;
+ case UDF_GETEABLOCK:
+ result = copy_to_user((char __user *)arg, UDF_I_DATA(inode),
+ UDF_I_LENEATTR(inode)) ? -EFAULT : 0;
+ break;
}
return result;
@@ -240,10 +233,9 @@ int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
* HISTORY
*
*/
-static int udf_release_file(struct inode * inode, struct file * filp)
+static int udf_release_file(struct inode *inode, struct file *filp)
{
- if (filp->f_mode & FMODE_WRITE)
- {
+ if (filp->f_mode & FMODE_WRITE) {
lock_kernel();
udf_discard_prealloc(inode);
unlock_kernel();
@@ -265,5 +257,5 @@ const struct file_operations udf_file_operations = {
};
const struct inode_operations udf_file_inode_operations = {
- .truncate = udf_truncate,
+ .truncate = udf_truncate,
};
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c
index 6ded93e7c44f..b2c472b733b8 100644
--- a/fs/udf/fsync.c
+++ b/fs/udf/fsync.c
@@ -29,9 +29,10 @@ static int udf_fsync_inode(struct inode *, int);
* even pass file to fsync ?
*/
-int udf_fsync_file(struct file * file, struct dentry *dentry, int datasync)
+int udf_fsync_file(struct file *file, struct dentry *dentry, int datasync)
{
struct inode *inode = dentry->d_inode;
+
return udf_fsync_inode(inode, datasync);
}
@@ -45,6 +46,7 @@ static int udf_fsync_inode(struct inode *inode, int datasync)
if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
return err;
- err |= udf_sync_inode (inode);
+ err |= udf_sync_inode(inode);
+
return err ? -EIO : 0;
}
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 8206983f2ebf..636d8f613929 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -28,7 +28,7 @@
#include "udf_i.h"
#include "udf_sb.h"
-void udf_free_inode(struct inode * inode)
+void udf_free_inode(struct inode *inode)
{
struct super_block *sb = inode->i_sb;
struct udf_sb_info *sbi = UDF_SB(sb);
@@ -50,7 +50,7 @@ void udf_free_inode(struct inode * inode)
else
UDF_SB_LVIDIU(sb)->numFiles =
cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1);
-
+
mark_buffer_dirty(sbi->s_lvidbh);
}
mutex_unlock(&sbi->s_alloc_mutex);
@@ -58,18 +58,17 @@ void udf_free_inode(struct inode * inode)
udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1);
}
-struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
+struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
{
struct super_block *sb = dir->i_sb;
struct udf_sb_info *sbi = UDF_SB(sb);
- struct inode * inode;
+ struct inode *inode;
int block;
uint32_t start = UDF_I_LOCATION(dir).logicalBlockNum;
inode = new_inode(sb);
- if (!inode)
- {
+ if (!inode) {
*err = -ENOMEM;
return NULL;
}
@@ -82,16 +81,14 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
UDF_I_STRAT4096(inode) = 0;
block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum,
- start, err);
- if (*err)
- {
+ start, err);
+ if (*err) {
iput(inode);
return NULL;
}
mutex_lock(&sbi->s_alloc_mutex);
- if (UDF_SB_LVIDBH(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
struct logicalVolHeaderDesc *lvhd;
uint64_t uniqueID;
lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse);
@@ -109,14 +106,13 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
}
inode->i_mode = mode;
inode->i_uid = current->fsuid;
- if (dir->i_mode & S_ISGID)
- {
+ if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
- }
- else
+ } else {
inode->i_gid = current->fsgid;
+ }
UDF_I_LOCATION(inode).logicalBlockNum = block;
UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
@@ -125,17 +121,20 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
UDF_I_LENEATTR(inode) = 0;
UDF_I_LENALLOC(inode) = 0;
UDF_I_USE(inode) = 0;
- if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE))
- {
+ if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) {
UDF_I_EFE(inode) = 1;
UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE);
UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
- }
- else
- {
+ } else {
UDF_I_EFE(inode) = 0;
UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
}
+ if (!UDF_I_DATA(inode)) {
+ iput(inode);
+ *err = -ENOMEM;
+ mutex_unlock(&sbi->s_alloc_mutex);
+ return NULL;
+ }
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
@@ -148,8 +147,7 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
mark_inode_dirty(inode);
mutex_unlock(&sbi->s_alloc_mutex);
- if (DQUOT_ALLOC_INODE(inode))
- {
+ if (DQUOT_ALLOC_INODE(inode)) {
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index bf7de0bdbab3..0d2c41666cd2 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -49,19 +49,20 @@ MODULE_LICENSE("GPL");
static mode_t udf_convert_permissions(struct fileEntry *);
static int udf_update_inode(struct inode *, int);
static void udf_fill_inode(struct inode *, struct buffer_head *);
+static int udf_alloc_i_data(struct inode *inode, size_t size);
static struct buffer_head *inode_getblk(struct inode *, sector_t, int *,
- long *, int *);
+ long *, int *);
static int8_t udf_insert_aext(struct inode *, struct extent_position,
- kernel_lb_addr, uint32_t);
+ kernel_lb_addr, uint32_t);
static void udf_split_extents(struct inode *, int *, int, int,
- kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+ kernel_long_ad[EXTENT_MERGE_SIZE], int *);
static void udf_prealloc_extents(struct inode *, int, int,
- kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+ kernel_long_ad[EXTENT_MERGE_SIZE], int *);
static void udf_merge_extents(struct inode *,
- kernel_long_ad [EXTENT_MERGE_SIZE], int *);
+ kernel_long_ad[EXTENT_MERGE_SIZE], int *);
static void udf_update_extents(struct inode *,
- kernel_long_ad [EXTENT_MERGE_SIZE], int, int,
- struct extent_position *);
+ kernel_long_ad[EXTENT_MERGE_SIZE], int, int,
+ struct extent_position *);
static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
/*
@@ -80,7 +81,7 @@ static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int);
*
* Called at the last iput() if i_nlink is zero.
*/
-void udf_delete_inode(struct inode * inode)
+void udf_delete_inode(struct inode *inode)
{
truncate_inode_pages(&inode->i_data, 0);
@@ -96,6 +97,7 @@ void udf_delete_inode(struct inode * inode)
unlock_kernel();
return;
+
no_delete:
clear_inode(inode);
}
@@ -131,26 +133,27 @@ static int udf_readpage(struct file *file, struct page *page)
return block_read_full_page(page, udf_get_block);
}
-static int udf_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
+static int udf_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
{
return block_prepare_write(page, from, to, udf_get_block);
}
static sector_t udf_bmap(struct address_space *mapping, sector_t block)
{
- return generic_block_bmap(mapping,block,udf_get_block);
+ return generic_block_bmap(mapping, block, udf_get_block);
}
const struct address_space_operations udf_aops = {
- .readpage = udf_readpage,
- .writepage = udf_writepage,
- .sync_page = block_sync_page,
- .prepare_write = udf_prepare_write,
- .commit_write = generic_commit_write,
- .bmap = udf_bmap,
+ .readpage = udf_readpage,
+ .writepage = udf_writepage,
+ .sync_page = block_sync_page,
+ .prepare_write = udf_prepare_write,
+ .commit_write = generic_commit_write,
+ .bmap = udf_bmap,
};
-void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
+void udf_expand_file_adinicb(struct inode *inode, int newsize, int *err)
{
struct page *page;
char *kaddr;
@@ -162,8 +165,7 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
/* from now on we have normal address_space methods */
inode->i_data.a_ops = &udf_aops;
- if (!UDF_I_LENALLOC(inode))
- {
+ if (!UDF_I_LENALLOC(inode)) {
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
else
@@ -175,19 +177,18 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
page = grab_cache_page(inode->i_mapping, 0);
BUG_ON(!PageLocked(page));
- if (!PageUptodate(page))
- {
+ if (!PageUptodate(page)) {
kaddr = kmap(page);
memset(kaddr + UDF_I_LENALLOC(inode), 0x00,
- PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
+ PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode));
memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode),
- UDF_I_LENALLOC(inode));
+ UDF_I_LENALLOC(inode));
flush_dcache_page(page);
SetPageUptodate(page);
kunmap(page);
}
memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0x00,
- UDF_I_LENALLOC(inode));
+ UDF_I_LENALLOC(inode));
UDF_I_LENALLOC(inode) = 0;
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT;
@@ -200,7 +201,8 @@ void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err)
mark_inode_dirty(inode);
}
-struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err)
+struct buffer_head *udf_expand_dir_adinicb(struct inode *inode, int *block,
+ int *err)
{
int newblock;
struct buffer_head *dbh = NULL;
@@ -219,8 +221,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
else
alloctype = ICBTAG_FLAG_AD_LONG;
- if (!inode->i_size)
- {
+ if (!inode->i_size) {
UDF_I_ALLOCTYPE(inode) = alloctype;
mark_inode_dirty(inode);
return NULL;
@@ -228,13 +229,12 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
/* alloc block, and copy data to it */
*block = udf_new_block(inode->i_sb, inode,
- UDF_I_LOCATION(inode).partitionReferenceNum,
- UDF_I_LOCATION(inode).logicalBlockNum, err);
-
+ UDF_I_LOCATION(inode).partitionReferenceNum,
+ UDF_I_LOCATION(inode).logicalBlockNum, err);
if (!(*block))
return NULL;
newblock = udf_get_pblock(inode->i_sb, *block,
- UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+ UDF_I_LOCATION(inode).partitionReferenceNum, 0);
if (!newblock)
return NULL;
dbh = udf_tgetblk(inode->i_sb, newblock);
@@ -250,12 +250,10 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
sfibh.sbh = sfibh.ebh = NULL;
dfibh.soffset = dfibh.eoffset = 0;
dfibh.sbh = dfibh.ebh = dbh;
- while ( (f_pos < size) )
- {
+ while ((f_pos < size)) {
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL);
- if (!sfi)
- {
+ if (!sfi) {
brelse(dbh);
return NULL;
}
@@ -265,8 +263,7 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
dfibh.eoffset += (sfibh.eoffset - sfibh.soffset);
dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset);
if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse,
- sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse)))
- {
+ sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse))) {
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
brelse(dbh);
return NULL;
@@ -291,14 +288,14 @@ struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int
return dbh;
}
-static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create)
+static int udf_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
{
int err, new;
struct buffer_head *bh;
unsigned long phys;
- if (!create)
- {
+ if (!create) {
phys = udf_block_map(inode, block);
if (phys)
map_bh(bh_result, inode->i_sb, phys);
@@ -314,10 +311,9 @@ static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head
if (block < 0)
goto abort_negative;
- if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1)
- {
- UDF_I_NEXT_ALLOC_BLOCK(inode) ++;
- UDF_I_NEXT_ALLOC_GOAL(inode) ++;
+ if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1) {
+ UDF_I_NEXT_ALLOC_BLOCK(inode)++;
+ UDF_I_NEXT_ALLOC_GOAL(inode)++;
}
err = 0;
@@ -331,6 +327,7 @@ static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head
if (new)
set_buffer_new(bh_result);
map_bh(bh_result, inode->i_sb, phys);
+
abort:
unlock_kernel();
return err;
@@ -340,20 +337,18 @@ abort_negative:
goto abort;
}
-static struct buffer_head *
-udf_getblk(struct inode *inode, long block, int create, int *err)
+static struct buffer_head *udf_getblk(struct inode *inode, long block,
+ int create, int *err)
{
+ struct buffer_head *bh;
struct buffer_head dummy;
dummy.b_state = 0;
dummy.b_blocknr = -1000;
*err = udf_get_block(inode, block, &dummy, create);
- if (!*err && buffer_mapped(&dummy))
- {
- struct buffer_head *bh;
+ if (!*err && buffer_mapped(&dummy)) {
bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
- if (buffer_new(&dummy))
- {
+ if (buffer_new(&dummy)) {
lock_buffer(bh);
memset(bh->b_data, 0x00, inode->i_sb->s_blocksize);
set_buffer_uptodate(bh);
@@ -362,33 +357,36 @@ udf_getblk(struct inode *inode, long block, int create, int *err)
}
return bh;
}
+
return NULL;
}
/* Extend the file by 'blocks' blocks, return the number of extents added */
int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
- kernel_long_ad *last_ext, sector_t blocks)
+ kernel_long_ad * last_ext, sector_t blocks)
{
sector_t add;
int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK);
struct super_block *sb = inode->i_sb;
- kernel_lb_addr prealloc_loc = {0, 0};
+ kernel_lb_addr prealloc_loc = {};
int prealloc_len = 0;
/* The previous extent is fake and we should not extend by anything
* - there's nothing to do... */
if (!blocks && fake)
return 0;
+
/* Round the last extent up to a multiple of block size */
if (last_ext->extLength & (sb->s_blocksize - 1)) {
last_ext->extLength =
(last_ext->extLength & UDF_EXTENT_FLAG_MASK) |
(((last_ext->extLength & UDF_EXTENT_LENGTH_MASK) +
- sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
+ sb->s_blocksize - 1) & ~(sb->s_blocksize - 1));
UDF_I_LENEXTENTS(inode) =
(UDF_I_LENEXTENTS(inode) + sb->s_blocksize - 1) &
- ~(sb->s_blocksize - 1);
+ ~(sb->s_blocksize - 1);
}
+
/* Last extent are just preallocated blocks? */
if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_ALLOCATED) {
/* Save the extent so that we can reattach it to the end */
@@ -400,10 +398,11 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
last_ext->extLocation.logicalBlockNum = 0;
last_ext->extLocation.partitionReferenceNum = 0;
}
+
/* Can we merge with the previous extent? */
if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == EXT_NOT_RECORDED_NOT_ALLOCATED) {
- add = ((1<<30) - sb->s_blocksize - (last_ext->extLength &
- UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
+ add = ((1 << 30) - sb->s_blocksize - (last_ext->extLength &
+ UDF_EXTENT_LENGTH_MASK)) >> sb->s_blocksize_bits;
if (add > blocks)
add = blocks;
blocks -= add;
@@ -412,11 +411,12 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
if (fake) {
udf_add_aext(inode, last_pos, last_ext->extLocation,
- last_ext->extLength, 1);
+ last_ext->extLength, 1);
count++;
- }
- else
+ } else {
udf_write_aext(inode, last_pos, last_ext->extLocation, last_ext->extLength, 1);
+ }
+
/* Managed to do everything necessary? */
if (!blocks)
goto out;
@@ -426,11 +426,12 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
last_ext->extLocation.partitionReferenceNum = 0;
add = (1 << (30-sb->s_blocksize_bits)) - 1;
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | (add << sb->s_blocksize_bits);
+
/* Create enough extents to cover the whole hole */
while (blocks > add) {
blocks -= add;
if (udf_add_aext(inode, last_pos, last_ext->extLocation,
- last_ext->extLength, 1) == -1)
+ last_ext->extLength, 1) == -1)
return -1;
count++;
}
@@ -438,10 +439,11 @@ int udf_extend_file(struct inode *inode, struct extent_position *last_pos,
last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
(blocks << sb->s_blocksize_bits);
if (udf_add_aext(inode, last_pos, last_ext->extLocation,
- last_ext->extLength, 1) == -1)
+ last_ext->extLength, 1) == -1)
return -1;
count++;
}
+
out:
/* Do we have some preallocated blocks saved? */
if (prealloc_len) {
@@ -451,6 +453,7 @@ out:
last_ext->extLength = prealloc_len;
count++;
}
+
/* last_pos should point to the last written extent... */
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
last_pos->offset -= sizeof(short_ad);
@@ -458,11 +461,12 @@ out:
last_pos->offset -= sizeof(long_ad);
else
return -1;
+
return count;
}
-static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
- int *err, long *phys, int *new)
+static struct buffer_head *inode_getblk(struct inode *inode, sector_t block,
+ int *err, long *phys, int *new)
{
static sector_t last_block;
struct buffer_head *result = NULL;
@@ -486,18 +490,15 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
b_off = (loff_t)block << inode->i_sb->s_blocksize_bits;
/* find the extent which contains the block we are looking for.
- alternate between laarr[0] and laarr[1] for locations of the
- current extent, and the previous extent */
- do
- {
- if (prev_epos.bh != cur_epos.bh)
- {
+ alternate between laarr[0] and laarr[1] for locations of the
+ current extent, and the previous extent */
+ do {
+ if (prev_epos.bh != cur_epos.bh) {
brelse(prev_epos.bh);
get_bh(cur_epos.bh);
prev_epos.bh = cur_epos.bh;
}
- if (cur_epos.bh != next_epos.bh)
- {
+ if (cur_epos.bh != next_epos.bh) {
brelse(cur_epos.bh);
get_bh(next_epos.bh);
cur_epos.bh = next_epos.bh;
@@ -522,9 +523,9 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
pgoal = eloc.logicalBlockNum +
((elen + inode->i_sb->s_blocksize - 1) >>
- inode->i_sb->s_blocksize_bits);
+ inode->i_sb->s_blocksize_bits);
- count ++;
+ count++;
} while (lbcount + elen <= b_off);
b_off -= lbcount;
@@ -537,15 +538,13 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
udf_next_aext(inode, &cur_epos, &tmpeloc, &tmpelen, 0);
/* if the extent is allocated and recorded, return the block
- if the extent is not a multiple of the blocksize, round up */
+ if the extent is not a multiple of the blocksize, round up */
- if (etype == (EXT_RECORDED_ALLOCATED >> 30))
- {
- if (elen & (inode->i_sb->s_blocksize - 1))
- {
+ if (etype == (EXT_RECORDED_ALLOCATED >> 30)) {
+ if (elen & (inode->i_sb->s_blocksize - 1)) {
elen = EXT_RECORDED_ALLOCATED |
((elen + inode->i_sb->s_blocksize - 1) &
- ~(inode->i_sb->s_blocksize - 1));
+ ~(inode->i_sb->s_blocksize - 1));
etype = udf_write_aext(inode, &cur_epos, eloc, elen, 1);
}
brelse(prev_epos.bh);
@@ -558,16 +557,14 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
last_block = block;
/* Are we beyond EOF? */
- if (etype == -1)
- {
+ if (etype == -1) {
int ret;
if (count) {
if (c)
laarr[0] = laarr[1];
startnum = 1;
- }
- else {
+ } else {
/* Create a fake extent when there's not one */
memset(&laarr[0].extLocation, 0x00, sizeof(kernel_lb_addr));
laarr[0].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
@@ -597,18 +594,16 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
inode->i_sb->s_blocksize;
memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr));
- count ++;
- endnum ++;
+ count++;
+ endnum++;
}
- endnum = c+1;
+ endnum = c + 1;
lastblock = 1;
- }
- else {
+ } else {
endnum = startnum = ((count > 2) ? 2 : count);
/* if the current extent is in position 0, swap it with the previous */
- if (!c && count != 1)
- {
+ if (!c && count != 1) {
laarr[2] = laarr[0];
laarr[0] = laarr[1];
laarr[1] = laarr[2];
@@ -616,37 +611,33 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
}
/* if the current block is located in an extent, read the next extent */
- if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1)
- {
- laarr[c+1].extLength = (etype << 30) | elen;
- laarr[c+1].extLocation = eloc;
- count ++;
- startnum ++;
- endnum ++;
- }
- else {
+ if ((etype = udf_next_aext(inode, &next_epos, &eloc, &elen, 0)) != -1) {
+ laarr[c + 1].extLength = (etype << 30) | elen;
+ laarr[c + 1].extLocation = eloc;
+ count++;
+ startnum++;
+ endnum++;
+ } else {
lastblock = 1;
}
}
/* if the current extent is not recorded but allocated, get the
- block in the extent corresponding to the requested block */
- if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
+ * block in the extent corresponding to the requested block */
+ if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
newblocknum = laarr[c].extLocation.logicalBlockNum + offset;
- else /* otherwise, allocate a new block */
- {
+ } else { /* otherwise, allocate a new block */
if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block)
goal = UDF_I_NEXT_ALLOC_GOAL(inode);
- if (!goal)
- {
+ if (!goal) {
if (!(goal = pgoal))
goal = UDF_I_LOCATION(inode).logicalBlockNum + 1;
}
if (!(newblocknum = udf_new_block(inode->i_sb, inode,
- UDF_I_LOCATION(inode).partitionReferenceNum, goal, err)))
- {
+ UDF_I_LOCATION(inode).partitionReferenceNum,
+ goal, err))) {
brelse(prev_epos.bh);
*err = -ENOSPC;
return NULL;
@@ -655,8 +646,8 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
}
/* if the extent the requsted block is located in contains multiple blocks,
- split the extent into at most three extents. blocks prior to requested
- block, requested block, and blocks after requested block */
+ * split the extent into at most three extents. blocks prior to requested
+ * block, requested block, and blocks after requested block */
udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum);
#ifdef UDF_PREALLOCATE
@@ -668,15 +659,14 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
udf_merge_extents(inode, laarr, &endnum);
/* write back the new extents, inserting new extents if the new number
- of extents is greater than the old number, and deleting extents if
- the new number of extents is less than the old number */
+ * of extents is greater than the old number, and deleting extents if
+ * the new number of extents is less than the old number */
udf_update_extents(inode, laarr, startnum, endnum, &prev_epos);
brelse(prev_epos.bh);
if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum,
- UDF_I_LOCATION(inode).partitionReferenceNum, 0)))
- {
+ UDF_I_LOCATION(inode).partitionReferenceNum, 0))) {
return NULL;
}
*phys = newblock;
@@ -690,156 +680,139 @@ static struct buffer_head * inode_getblk(struct inode * inode, sector_t block,
udf_sync_inode(inode);
else
mark_inode_dirty(inode);
+
return result;
}
-static void udf_split_extents(struct inode *inode, int *c, int offset, int newblocknum,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+static void udf_split_extents(struct inode *inode, int *c, int offset,
+ int newblocknum,
+ kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int *endnum)
{
if ((laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30) ||
- (laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- {
+ (laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
int curr = *c;
int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
int8_t etype = (laarr[curr].extLength >> 30);
- if (blen == 1)
+ if (blen == 1) {
;
- else if (!offset || blen == offset + 1)
- {
- laarr[curr+2] = laarr[curr+1];
- laarr[curr+1] = laarr[curr];
- }
- else
- {
- laarr[curr+3] = laarr[curr+1];
- laarr[curr+2] = laarr[curr+1] = laarr[curr];
+ } else if (!offset || blen == offset + 1) {
+ laarr[curr + 2] = laarr[curr + 1];
+ laarr[curr + 1] = laarr[curr];
+ } else {
+ laarr[curr + 3] = laarr[curr + 1];
+ laarr[curr + 2] = laarr[curr + 1] = laarr[curr];
}
- if (offset)
- {
- if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
+ if (offset) {
+ if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset);
laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
(offset << inode->i_sb->s_blocksize_bits);
laarr[curr].extLocation.logicalBlockNum = 0;
laarr[curr].extLocation.partitionReferenceNum = 0;
- }
- else
+ } else {
laarr[curr].extLength = (etype << 30) |
(offset << inode->i_sb->s_blocksize_bits);
- curr ++;
- (*c) ++;
- (*endnum) ++;
+ }
+ curr++;
+ (*c)++;
+ (*endnum)++;
}
-
+
laarr[curr].extLocation.logicalBlockNum = newblocknum;
if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
laarr[curr].extLocation.partitionReferenceNum =
UDF_I_LOCATION(inode).partitionReferenceNum;
laarr[curr].extLength = EXT_RECORDED_ALLOCATED |
inode->i_sb->s_blocksize;
- curr ++;
+ curr++;
- if (blen != offset + 1)
- {
+ if (blen != offset + 1) {
if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
laarr[curr].extLocation.logicalBlockNum += (offset + 1);
laarr[curr].extLength = (etype << 30) |
((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits);
- curr ++;
- (*endnum) ++;
+ curr++;
+ (*endnum)++;
}
}
}
static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+ kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int *endnum)
{
int start, length = 0, currlength = 0, i;
- if (*endnum >= (c+1))
- {
+ if (*endnum >= (c + 1)) {
if (!lastblock)
return;
else
start = c;
- }
- else
- {
- if ((laarr[c+1].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- start = c+1;
- length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
- }
- else
+ } else {
+ if ((laarr[c + 1].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ start = c + 1;
+ length = currlength = (((laarr[c + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ } else {
start = c;
+ }
}
- for (i=start+1; i<=*endnum; i++)
- {
- if (i == *endnum)
- {
+ for (i = start + 1; i <= *endnum; i++) {
+ if (i == *endnum) {
if (lastblock)
length += UDF_DEFAULT_PREALLOC_BLOCKS;
- }
- else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
+ } else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) {
length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
- else
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ } else {
break;
+ }
}
- if (length)
- {
+ if (length) {
int next = laarr[start].extLocation.logicalBlockNum +
(((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
int numalloc = udf_prealloc_blocks(inode->i_sb, inode,
- laarr[start].extLocation.partitionReferenceNum,
- next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
- UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
-
- if (numalloc)
- {
- if (start == (c+1))
+ laarr[start].extLocation.partitionReferenceNum,
+ next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length :
+ UDF_DEFAULT_PREALLOC_BLOCKS) - currlength);
+ if (numalloc) {
+ if (start == (c + 1)) {
laarr[start].extLength +=
(numalloc << inode->i_sb->s_blocksize_bits);
- else
- {
- memmove(&laarr[c+2], &laarr[c+1],
- sizeof(long_ad) * (*endnum - (c+1)));
- (*endnum) ++;
- laarr[c+1].extLocation.logicalBlockNum = next;
- laarr[c+1].extLocation.partitionReferenceNum =
+ } else {
+ memmove(&laarr[c + 2], &laarr[c + 1],
+ sizeof(long_ad) * (*endnum - (c + 1)));
+ (*endnum)++;
+ laarr[c + 1].extLocation.logicalBlockNum = next;
+ laarr[c + 1].extLocation.partitionReferenceNum =
laarr[c].extLocation.partitionReferenceNum;
- laarr[c+1].extLength = EXT_NOT_RECORDED_ALLOCATED |
+ laarr[c + 1].extLength = EXT_NOT_RECORDED_ALLOCATED |
(numalloc << inode->i_sb->s_blocksize_bits);
- start = c+1;
+ start = c + 1;
}
- for (i=start+1; numalloc && i<*endnum; i++)
- {
+ for (i = start + 1; numalloc && i < *endnum; i++) {
int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
- if (elen > numalloc)
- {
+ if (elen > numalloc) {
laarr[i].extLength -=
(numalloc << inode->i_sb->s_blocksize_bits);
numalloc = 0;
- }
- else
- {
+ } else {
numalloc -= elen;
- if (*endnum > (i+1))
- memmove(&laarr[i], &laarr[i+1],
- sizeof(long_ad) * (*endnum - (i+1)));
- i --;
- (*endnum) --;
+ if (*endnum > (i + 1))
+ memmove(&laarr[i], &laarr[i + 1],
+ sizeof(long_ad) * (*endnum - (i + 1)));
+ i--;
+ (*endnum)--;
}
}
UDF_I_LENEXTENTS(inode) += numalloc << inode->i_sb->s_blocksize_bits;
@@ -848,82 +821,70 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock,
}
static void udf_merge_extents(struct inode *inode,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum)
+ kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int *endnum)
{
int i;
- for (i=0; i<(*endnum-1); i++)
- {
- if ((laarr[i].extLength >> 30) == (laarr[i+1].extLength >> 30))
- {
+ for (i = 0; i < (*endnum - 1); i++) {
+ if ((laarr[i].extLength >> 30) == (laarr[i + 1].extLength >> 30)) {
if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) ||
- ((laarr[i+1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
- (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits)))
- {
+ ((laarr[i + 1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) ==
+ (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits))) {
if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
- {
- laarr[i+1].extLength = (laarr[i+1].extLength -
- (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
+ (laarr[i + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+ laarr[i + 1].extLength = (laarr[i + 1].extLength -
+ (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize - 1);
laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
- laarr[i+1].extLocation.logicalBlockNum =
+ laarr[i + 1].extLocation.logicalBlockNum =
laarr[i].extLocation.logicalBlockNum +
((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >>
- inode->i_sb->s_blocksize_bits);
- }
- else
- {
- laarr[i].extLength = laarr[i+1].extLength +
+ inode->i_sb->s_blocksize_bits);
+ } else {
+ laarr[i].extLength = laarr[i + 1].extLength +
(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
- if (*endnum > (i+2))
- memmove(&laarr[i+1], &laarr[i+2],
- sizeof(long_ad) * (*endnum - (i+2)));
- i --;
- (*endnum) --;
+ inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize - 1));
+ if (*endnum > (i + 2))
+ memmove(&laarr[i + 1], &laarr[i + 2],
+ sizeof(long_ad) * (*endnum - (i + 2)));
+ i--;
+ (*endnum)--;
}
}
- }
- else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
- ((laarr[i+1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)))
- {
+ } else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) &&
+ ((laarr[i + 1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) {
udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
- ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
laarr[i].extLocation.logicalBlockNum = 0;
laarr[i].extLocation.partitionReferenceNum = 0;
if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK)
- {
- laarr[i+1].extLength = (laarr[i+1].extLength -
- (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1);
+ (laarr[i + 1].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) {
+ laarr[i + 1].extLength = (laarr[i + 1].extLength -
+ (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize - 1);
laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) +
(UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize;
- }
- else
- {
- laarr[i].extLength = laarr[i+1].extLength +
+ } else {
+ laarr[i].extLength = laarr[i + 1].extLength +
(((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1));
- if (*endnum > (i+2))
- memmove(&laarr[i+1], &laarr[i+2],
- sizeof(long_ad) * (*endnum - (i+2)));
- i --;
- (*endnum) --;
+ inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize - 1));
+ if (*endnum > (i + 2))
+ memmove(&laarr[i + 1], &laarr[i + 2],
+ sizeof(long_ad) * (*endnum - (i + 2)));
+ i--;
+ (*endnum)--;
}
- }
- else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
+ } else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0,
- ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
- inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
+ ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) +
+ inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits);
laarr[i].extLocation.logicalBlockNum = 0;
laarr[i].extLocation.partitionReferenceNum = 0;
laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) |
@@ -933,43 +894,39 @@ static void udf_merge_extents(struct inode *inode,
}
static void udf_update_extents(struct inode *inode,
- kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum,
- struct extent_position *epos)
+ kernel_long_ad laarr[EXTENT_MERGE_SIZE],
+ int startnum, int endnum,
+ struct extent_position *epos)
{
int start = 0, i;
kernel_lb_addr tmploc;
uint32_t tmplen;
- if (startnum > endnum)
- {
- for (i=0; i<(startnum-endnum); i++)
+ if (startnum > endnum) {
+ for (i = 0; i < (startnum - endnum); i++)
udf_delete_aext(inode, *epos, laarr[i].extLocation,
- laarr[i].extLength);
- }
- else if (startnum < endnum)
- {
- for (i=0; i<(endnum-startnum); i++)
- {
+ laarr[i].extLength);
+ } else if (startnum < endnum) {
+ for (i = 0; i < (endnum - startnum); i++) {
udf_insert_aext(inode, *epos, laarr[i].extLocation,
- laarr[i].extLength);
+ laarr[i].extLength);
udf_next_aext(inode, epos, &laarr[i].extLocation,
- &laarr[i].extLength, 1);
- start ++;
+ &laarr[i].extLength, 1);
+ start++;
}
}
- for (i=start; i<endnum; i++)
- {
+ for (i = start; i < endnum; i++) {
udf_next_aext(inode, epos, &tmploc, &tmplen, 0);
udf_write_aext(inode, epos, laarr[i].extLocation,
- laarr[i].extLength, 1);
+ laarr[i].extLength, 1);
}
}
-struct buffer_head * udf_bread(struct inode * inode, int block,
- int create, int * err)
+struct buffer_head *udf_bread(struct inode *inode, int block,
+ int create, int *err)
{
- struct buffer_head * bh = NULL;
+ struct buffer_head *bh = NULL;
bh = udf_getblk(inode, block, create, err);
if (!bh)
@@ -977,65 +934,61 @@ struct buffer_head * udf_bread(struct inode * inode, int block,
if (buffer_uptodate(bh))
return bh;
+
ll_rw_block(READ, 1, &bh);
+
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
+
brelse(bh);
*err = -EIO;
return NULL;
}
-void udf_truncate(struct inode * inode)
+void udf_truncate(struct inode *inode)
{
int offset;
int err;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
+ S_ISLNK(inode->i_mode)))
return;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
lock_kernel();
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
- inode->i_size))
- {
+ inode->i_size)) {
udf_expand_file_adinicb(inode, inode->i_size, &err);
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
inode->i_size = UDF_I_LENALLOC(inode);
unlock_kernel();
return;
- }
- else
+ } else {
udf_truncate_extents(inode);
- }
- else
- {
+ }
+ } else {
offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
- memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00, inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode));
+ memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00,
+ inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode));
UDF_I_LENALLOC(inode) = inode->i_size;
}
- }
- else
- {
+ } else {
block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block);
udf_truncate_extents(inode);
- }
+ }
inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb);
if (IS_SYNC(inode))
- udf_sync_inode (inode);
+ udf_sync_inode(inode);
else
mark_inode_dirty(inode);
unlock_kernel();
}
-static void
-__udf_read_inode(struct inode *inode)
+static void __udf_read_inode(struct inode *inode)
{
struct buffer_head *bh = NULL;
struct fileEntry *fe;
@@ -1054,20 +1007,17 @@ __udf_read_inode(struct inode *inode)
* i_op = NULL;
*/
bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
-
- if (!bh)
- {
+ if (!bh) {
printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n",
- inode->i_ino);
+ inode->i_ino);
make_bad_inode(inode);
return;
}
if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE &&
- ident != TAG_IDENT_USE)
- {
+ ident != TAG_IDENT_USE) {
printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n",
- inode->i_ino, ident);
+ inode->i_ino, ident);
brelse(bh);
make_bad_inode(inode);
return;
@@ -1075,51 +1025,43 @@ __udf_read_inode(struct inode *inode)
fe = (struct fileEntry *)bh->b_data;
- if (le16_to_cpu(fe->icbTag.strategyType) == 4096)
- {
+ if (le16_to_cpu(fe->icbTag.strategyType) == 4096) {
struct buffer_head *ibh = NULL, *nbh = NULL;
struct indirectEntry *ie;
ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident);
- if (ident == TAG_IDENT_IE)
- {
- if (ibh)
- {
+ if (ident == TAG_IDENT_IE) {
+ if (ibh) {
kernel_lb_addr loc;
ie = (struct indirectEntry *)ibh->b_data;
-
+
loc = lelb_to_cpu(ie->indirectICB.extLocation);
-
- if (ie->indirectICB.extLength &&
- (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident)))
- {
+
+ if (ie->indirectICB.extLength &&
+ (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident))) {
if (ident == TAG_IDENT_FE ||
- ident == TAG_IDENT_EFE)
- {
- memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr));
+ ident == TAG_IDENT_EFE) {
+ memcpy(&UDF_I_LOCATION(inode), &loc,
+ sizeof(kernel_lb_addr));
brelse(bh);
brelse(ibh);
brelse(nbh);
__udf_read_inode(inode);
return;
- }
- else
- {
+ } else {
brelse(nbh);
brelse(ibh);
}
- }
- else
+ } else {
brelse(ibh);
+ }
}
- }
- else
+ } else {
brelse(ibh);
- }
- else if (le16_to_cpu(fe->icbTag.strategyType) != 4)
- {
+ }
+ } else if (le16_to_cpu(fe->icbTag.strategyType) != 4) {
printk(KERN_ERR "udf: unsupported strategy type: %d\n",
- le16_to_cpu(fe->icbTag.strategyType));
+ le16_to_cpu(fe->icbTag.strategyType));
brelse(bh);
make_bad_inode(inode);
return;
@@ -1152,87 +1094,83 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
UDF_I_LENALLOC(inode) = 0;
UDF_I_NEXT_ALLOC_BLOCK(inode) = 0;
UDF_I_NEXT_ALLOC_GOAL(inode) = 0;
- if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE)
- {
+ if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE) {
UDF_I_EFE(inode) = 1;
UDF_I_USE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
- memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
- }
- else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE)
- {
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry))) {
+ make_bad_inode(inode);
+ return;
+ }
+ memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry),
+ inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
+ } else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE) {
UDF_I_EFE(inode) = 0;
UDF_I_USE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
- memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
- }
- else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
- {
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct fileEntry))) {
+ make_bad_inode(inode);
+ return;
+ }
+ memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry),
+ inode->i_sb->s_blocksize - sizeof(struct fileEntry));
+ } else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) {
UDF_I_EFE(inode) = 0;
UDF_I_USE(inode) = 1;
UDF_I_LENALLOC(inode) =
- le32_to_cpu(
- ((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry), GFP_KERNEL);
- memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
+ le32_to_cpu(((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs);
+ if (udf_alloc_i_data(inode, inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry))) {
+ make_bad_inode(inode);
+ return;
+ }
+ memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry),
+ inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
return;
}
inode->i_uid = le32_to_cpu(fe->uid);
if (inode->i_uid == -1 || UDF_QUERY_FLAG(inode->i_sb,
- UDF_FLAG_UID_IGNORE))
+ UDF_FLAG_UID_IGNORE))
inode->i_uid = UDF_SB(inode->i_sb)->s_uid;
inode->i_gid = le32_to_cpu(fe->gid);
if (inode->i_gid == -1 || UDF_QUERY_FLAG(inode->i_sb,
- UDF_FLAG_GID_IGNORE))
+ UDF_FLAG_GID_IGNORE))
inode->i_gid = UDF_SB(inode->i_sb)->s_gid;
inode->i_nlink = le16_to_cpu(fe->fileLinkCount);
if (!inode->i_nlink)
inode->i_nlink = 1;
-
+
inode->i_size = le64_to_cpu(fe->informationLength);
UDF_I_LENEXTENTS(inode) = inode->i_size;
inode->i_mode = udf_convert_permissions(fe);
inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask;
- if (UDF_I_EFE(inode) == 0)
- {
+ if (UDF_I_EFE(inode) == 0) {
inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) <<
(inode->i_sb->s_blocksize_bits - 9);
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(fe->accessTime)) )
- {
+ if (udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(fe->accessTime))) {
inode->i_atime.tv_sec = convtime;
inode->i_atime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
+ } else {
inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
}
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(fe->modificationTime)) )
- {
+ if (udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(fe->modificationTime))) {
inode->i_mtime.tv_sec = convtime;
inode->i_mtime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
+ } else {
inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
}
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(fe->attrTime)) )
- {
+ if (udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(fe->attrTime))) {
inode->i_ctime.tv_sec = convtime;
inode->i_ctime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
+ } else {
inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
}
@@ -1240,53 +1178,39 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr);
UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs);
offset = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode);
- }
- else
- {
- inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
- (inode->i_sb->s_blocksize_bits - 9);
+ } else {
+ inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) <<
+ (inode->i_sb->s_blocksize_bits - 9);
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->accessTime)) )
- {
+ if (udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(efe->accessTime))) {
inode->i_atime.tv_sec = convtime;
inode->i_atime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
+ } else {
inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb);
}
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->modificationTime)) )
- {
+ if (udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(efe->modificationTime))) {
inode->i_mtime.tv_sec = convtime;
inode->i_mtime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
+ } else {
inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb);
}
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->createTime)) )
- {
+ if (udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(efe->createTime))) {
UDF_I_CRTIME(inode).tv_sec = convtime;
UDF_I_CRTIME(inode).tv_nsec = convtime_usec * 1000;
- }
- else
- {
+ } else {
UDF_I_CRTIME(inode) = UDF_SB_RECORDTIME(inode->i_sb);
}
- if ( udf_stamp_to_time(&convtime, &convtime_usec,
- lets_to_cpu(efe->attrTime)) )
- {
+ if (udf_stamp_to_time(&convtime, &convtime_usec,
+ lets_to_cpu(efe->attrTime))) {
inode->i_ctime.tv_sec = convtime;
inode->i_ctime.tv_nsec = convtime_usec * 1000;
- }
- else
- {
+ } else {
inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb);
}
@@ -1296,86 +1220,74 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode);
}
- switch (fe->icbTag.fileType)
- {
- case ICBTAG_FILE_TYPE_DIRECTORY:
- {
- inode->i_op = &udf_dir_inode_operations;
- inode->i_fop = &udf_dir_operations;
- inode->i_mode |= S_IFDIR;
- inc_nlink(inode);
- break;
- }
- case ICBTAG_FILE_TYPE_REALTIME:
- case ICBTAG_FILE_TYPE_REGULAR:
- case ICBTAG_FILE_TYPE_UNDEF:
- {
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
- inode->i_data.a_ops = &udf_adinicb_aops;
- else
- inode->i_data.a_ops = &udf_aops;
- inode->i_op = &udf_file_inode_operations;
- inode->i_fop = &udf_file_operations;
- inode->i_mode |= S_IFREG;
- break;
- }
- case ICBTAG_FILE_TYPE_BLOCK:
- {
- inode->i_mode |= S_IFBLK;
- break;
- }
- case ICBTAG_FILE_TYPE_CHAR:
- {
- inode->i_mode |= S_IFCHR;
- break;
- }
- case ICBTAG_FILE_TYPE_FIFO:
- {
- init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
- break;
- }
- case ICBTAG_FILE_TYPE_SOCKET:
- {
- init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
- break;
- }
- case ICBTAG_FILE_TYPE_SYMLINK:
- {
- inode->i_data.a_ops = &udf_symlink_aops;
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mode = S_IFLNK|S_IRWXUGO;
- break;
- }
- default:
- {
- printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
- inode->i_ino, fe->icbTag.fileType);
- make_bad_inode(inode);
- return;
- }
+ switch (fe->icbTag.fileType) {
+ case ICBTAG_FILE_TYPE_DIRECTORY:
+ inode->i_op = &udf_dir_inode_operations;
+ inode->i_fop = &udf_dir_operations;
+ inode->i_mode |= S_IFDIR;
+ inc_nlink(inode);
+ break;
+ case ICBTAG_FILE_TYPE_REALTIME:
+ case ICBTAG_FILE_TYPE_REGULAR:
+ case ICBTAG_FILE_TYPE_UNDEF:
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+ inode->i_data.a_ops = &udf_adinicb_aops;
+ else
+ inode->i_data.a_ops = &udf_aops;
+ inode->i_op = &udf_file_inode_operations;
+ inode->i_fop = &udf_file_operations;
+ inode->i_mode |= S_IFREG;
+ break;
+ case ICBTAG_FILE_TYPE_BLOCK:
+ inode->i_mode |= S_IFBLK;
+ break;
+ case ICBTAG_FILE_TYPE_CHAR:
+ inode->i_mode |= S_IFCHR;
+ break;
+ case ICBTAG_FILE_TYPE_FIFO:
+ init_special_inode(inode, inode->i_mode | S_IFIFO, 0);
+ break;
+ case ICBTAG_FILE_TYPE_SOCKET:
+ init_special_inode(inode, inode->i_mode | S_IFSOCK, 0);
+ break;
+ case ICBTAG_FILE_TYPE_SYMLINK:
+ inode->i_data.a_ops = &udf_symlink_aops;
+ inode->i_op = &page_symlink_inode_operations;
+ inode->i_mode = S_IFLNK | S_IRWXUGO;
+ break;
+ default:
+ printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n",
+ inode->i_ino, fe->icbTag.fileType);
+ make_bad_inode(inode);
+ return;
}
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- {
- struct deviceSpec *dsea =
- (struct deviceSpec *)
- udf_get_extendedattr(inode, 12, 1);
-
- if (dsea)
- {
- init_special_inode(inode, inode->i_mode, MKDEV(
- le32_to_cpu(dsea->majorDeviceIdent),
- le32_to_cpu(dsea->minorDeviceIdent)));
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+ struct deviceSpec *dsea = (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
+ if (dsea) {
+ init_special_inode(inode, inode->i_mode,
+ MKDEV(le32_to_cpu(dsea->majorDeviceIdent),
+ le32_to_cpu(dsea->minorDeviceIdent)));
/* Developer ID ??? */
- }
- else
- {
+ } else {
make_bad_inode(inode);
}
}
}
-static mode_t
-udf_convert_permissions(struct fileEntry *fe)
+static int udf_alloc_i_data(struct inode *inode, size_t size)
+{
+ UDF_I_DATA(inode) = kmalloc(size, GFP_KERNEL);
+
+ if (!UDF_I_DATA(inode)) {
+ printk(KERN_ERR "udf:udf_alloc_i_data (ino %ld) no free memory\n",
+ inode->i_ino);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static mode_t udf_convert_permissions(struct fileEntry *fe)
{
mode_t mode;
uint32_t permissions;
@@ -1409,22 +1321,23 @@ udf_convert_permissions(struct fileEntry *fe)
* Written, tested, and released.
*/
-int udf_write_inode(struct inode * inode, int sync)
+int udf_write_inode(struct inode *inode, int sync)
{
int ret;
+
lock_kernel();
ret = udf_update_inode(inode, sync);
unlock_kernel();
+
return ret;
}
-int udf_sync_inode(struct inode * inode)
+int udf_sync_inode(struct inode *inode)
{
return udf_update_inode(inode, 1);
}
-static int
-udf_update_inode(struct inode *inode, int do_sync)
+static int udf_update_inode(struct inode *inode, int do_sync)
{
struct buffer_head *bh = NULL;
struct fileEntry *fe;
@@ -1436,11 +1349,8 @@ udf_update_inode(struct inode *inode, int do_sync)
kernel_timestamp cpu_time;
int err = 0;
- bh = udf_tread(inode->i_sb,
- udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
-
- if (!bh)
- {
+ bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0));
+ if (!bh) {
udf_debug("bread failure\n");
return -EIO;
}
@@ -1450,23 +1360,23 @@ udf_update_inode(struct inode *inode, int do_sync)
fe = (struct fileEntry *)bh->b_data;
efe = (struct extendedFileEntry *)bh->b_data;
- if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE)
- {
+ if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) {
struct unallocSpaceEntry *use =
(struct unallocSpaceEntry *)bh->b_data;
use->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
- memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
- crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) -
- sizeof(tag);
+ memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode),
+ inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry));
+ crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) - sizeof(tag);
use->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum);
use->descTag.descCRCLength = cpu_to_le16(crclen);
use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + sizeof(tag), crclen, 0));
use->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
+ for (i = 0; i < 16; i++) {
if (i != 4)
use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i];
+ }
mark_buffer_dirty(bh);
brelse(bh);
@@ -1475,11 +1385,13 @@ udf_update_inode(struct inode *inode, int do_sync)
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_UID_FORGET))
fe->uid = cpu_to_le32(-1);
- else fe->uid = cpu_to_le32(inode->i_uid);
+ else
+ fe->uid = cpu_to_le32(inode->i_uid);
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_GID_FORGET))
fe->gid = cpu_to_le32(-1);
- else fe->gid = cpu_to_le32(inode->i_gid);
+ else
+ fe->gid = cpu_to_le32(inode->i_gid);
udfperms = ((inode->i_mode & S_IRWXO) ) |
((inode->i_mode & S_IRWXG) << 2) |
@@ -1498,23 +1410,19 @@ udf_update_inode(struct inode *inode, int do_sync)
fe->informationLength = cpu_to_le64(inode->i_size);
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- {
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
regid *eid;
struct deviceSpec *dsea =
- (struct deviceSpec *)
- udf_get_extendedattr(inode, 12, 1);
-
- if (!dsea)
- {
+ (struct deviceSpec *)udf_get_extendedattr(inode, 12, 1);
+ if (!dsea) {
dsea = (struct deviceSpec *)
udf_add_extendedattr(inode,
- sizeof(struct deviceSpec) +
- sizeof(regid), 12, 0x3);
+ sizeof(struct deviceSpec) +
+ sizeof(regid), 12, 0x3);
dsea->attrType = cpu_to_le32(12);
dsea->attrSubtype = 1;
dsea->attrLength = cpu_to_le32(sizeof(struct deviceSpec) +
- sizeof(regid));
+ sizeof(regid));
dsea->impUseLength = cpu_to_le32(sizeof(regid));
}
eid = (regid *)dsea->impUse;
@@ -1526,9 +1434,9 @@ udf_update_inode(struct inode *inode, int do_sync)
dsea->minorDeviceIdent = cpu_to_le32(iminor(inode));
}
- if (UDF_I_EFE(inode) == 0)
- {
- memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct fileEntry));
+ if (UDF_I_EFE(inode) == 0) {
+ memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode),
+ inode->i_sb->s_blocksize - sizeof(struct fileEntry));
fe->logicalBlocksRecorded = cpu_to_le64(
(inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
(inode->i_sb->s_blocksize_bits - 9));
@@ -1548,31 +1456,27 @@ udf_update_inode(struct inode *inode, int do_sync)
fe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode));
fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE);
crclen = sizeof(struct fileEntry);
- }
- else
- {
- memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
+ } else {
+ memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode),
+ inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
efe->objectSize = cpu_to_le64(inode->i_size);
efe->logicalBlocksRecorded = cpu_to_le64(
(inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >>
(inode->i_sb->s_blocksize_bits - 9));
if (UDF_I_CRTIME(inode).tv_sec > inode->i_atime.tv_sec ||
- (UDF_I_CRTIME(inode).tv_sec == inode->i_atime.tv_sec &&
- UDF_I_CRTIME(inode).tv_nsec > inode->i_atime.tv_nsec))
- {
+ (UDF_I_CRTIME(inode).tv_sec == inode->i_atime.tv_sec &&
+ UDF_I_CRTIME(inode).tv_nsec > inode->i_atime.tv_nsec)) {
UDF_I_CRTIME(inode) = inode->i_atime;
}
if (UDF_I_CRTIME(inode).tv_sec > inode->i_mtime.tv_sec ||
- (UDF_I_CRTIME(inode).tv_sec == inode->i_mtime.tv_sec &&
- UDF_I_CRTIME(inode).tv_nsec > inode->i_mtime.tv_nsec))
- {
+ (UDF_I_CRTIME(inode).tv_sec == inode->i_mtime.tv_sec &&
+ UDF_I_CRTIME(inode).tv_nsec > inode->i_mtime.tv_nsec)) {
UDF_I_CRTIME(inode) = inode->i_mtime;
}
if (UDF_I_CRTIME(inode).tv_sec > inode->i_ctime.tv_sec ||
- (UDF_I_CRTIME(inode).tv_sec == inode->i_ctime.tv_sec &&
- UDF_I_CRTIME(inode).tv_nsec > inode->i_ctime.tv_nsec))
- {
+ (UDF_I_CRTIME(inode).tv_sec == inode->i_ctime.tv_sec &&
+ UDF_I_CRTIME(inode).tv_nsec > inode->i_ctime.tv_nsec)) {
UDF_I_CRTIME(inode) = inode->i_ctime;
}
@@ -1595,14 +1499,11 @@ udf_update_inode(struct inode *inode, int do_sync)
efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE);
crclen = sizeof(struct extendedFileEntry);
}
- if (UDF_I_STRAT4096(inode))
- {
+ if (UDF_I_STRAT4096(inode)) {
fe->icbTag.strategyType = cpu_to_le16(4096);
fe->icbTag.strategyParameter = cpu_to_le16(1);
fe->icbTag.numEntries = cpu_to_le16(2);
- }
- else
- {
+ } else {
fe->icbTag.strategyType = cpu_to_le16(4);
fe->icbTag.numEntries = cpu_to_le16(1);
}
@@ -1642,28 +1543,27 @@ udf_update_inode(struct inode *inode, int do_sync)
fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0));
fe->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
+ for (i = 0; i < 16; i++) {
if (i != 4)
fe->descTag.tagChecksum += ((uint8_t *)&(fe->descTag))[i];
+ }
/* write the data blocks */
mark_buffer_dirty(bh);
- if (do_sync)
- {
+ if (do_sync) {
sync_dirty_buffer(bh);
- if (buffer_req(bh) && !buffer_uptodate(bh))
- {
+ if (buffer_req(bh) && !buffer_uptodate(bh)) {
printk("IO error syncing udf inode [%s:%08lx]\n",
- inode->i_sb->s_id, inode->i_ino);
+ inode->i_sb->s_id, inode->i_ino);
err = -EIO;
}
}
brelse(bh);
+
return err;
}
-struct inode *
-udf_iget(struct super_block *sb, kernel_lb_addr ino)
+struct inode *udf_iget(struct super_block *sb, kernel_lb_addr ino)
{
unsigned long block = udf_get_lb_pblock(sb, ino, 0);
struct inode *inode = iget_locked(sb, block);
@@ -1682,7 +1582,7 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
if (ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum)) {
udf_debug("block=%d, partition=%d out of range\n",
- ino.logicalBlockNum, ino.partitionReferenceNum);
+ ino.logicalBlockNum, ino.partitionReferenceNum);
make_bad_inode(inode);
goto out_iput;
}
@@ -1694,8 +1594,8 @@ udf_iget(struct super_block *sb, kernel_lb_addr ino)
return NULL;
}
-int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
- kernel_lb_addr eloc, uint32_t elen, int inc)
+int8_t udf_add_aext(struct inode * inode, struct extent_position * epos,
+ kernel_lb_addr eloc, uint32_t elen, int inc)
{
int adsize;
short_ad *sad = NULL;
@@ -1716,21 +1616,19 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
else
return -1;
- if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize)
- {
+ if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
char *sptr, *dptr;
struct buffer_head *nbh;
int err, loffset;
kernel_lb_addr obloc = epos->block;
if (!(epos->block.logicalBlockNum = udf_new_block(inode->i_sb, NULL,
- obloc.partitionReferenceNum, obloc.logicalBlockNum, &err)))
- {
+ obloc.partitionReferenceNum,
+ obloc.logicalBlockNum, &err))) {
return -1;
}
if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb,
- epos->block, 0))))
- {
+ epos->block, 0)))) {
return -1;
}
lock_buffer(nbh);
@@ -1742,85 +1640,69 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
aed = (struct allocExtDesc *)(nbh->b_data);
if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum);
- if (epos->offset + adsize > inode->i_sb->s_blocksize)
- {
+ if (epos->offset + adsize > inode->i_sb->s_blocksize) {
loffset = epos->offset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
sptr = ptr - adsize;
dptr = nbh->b_data + sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
epos->offset = sizeof(struct allocExtDesc) + adsize;
- }
- else
- {
+ } else {
loffset = epos->offset + adsize;
aed->lengthAllocDescs = cpu_to_le32(0);
sptr = ptr;
epos->offset = sizeof(struct allocExtDesc);
- if (epos->bh)
- {
+ if (epos->bh) {
aed = (struct allocExtDesc *)epos->bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
- }
- else
- {
+ } else {
UDF_I_LENALLOC(inode) += adsize;
mark_inode_dirty(inode);
}
}
if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200)
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1,
- epos->block.logicalBlockNum, sizeof(tag));
+ epos->block.logicalBlockNum, sizeof(tag));
else
udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1,
- epos->block.logicalBlockNum, sizeof(tag));
- switch (UDF_I_ALLOCTYPE(inode))
- {
- case ICBTAG_FLAG_AD_SHORT:
- {
- sad = (short_ad *)sptr;
- sad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- inode->i_sb->s_blocksize);
- sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);
- break;
- }
- case ICBTAG_FLAG_AD_LONG:
- {
- lad = (long_ad *)sptr;
- lad->extLength = cpu_to_le32(
- EXT_NEXT_EXTENT_ALLOCDECS |
- inode->i_sb->s_blocksize);
- lad->extLocation = cpu_to_lelb(epos->block);
- memset(lad->impUse, 0x00, sizeof(lad->impUse));
- break;
- }
+ epos->block.logicalBlockNum, sizeof(tag));
+ switch (UDF_I_ALLOCTYPE(inode)) {
+ case ICBTAG_FLAG_AD_SHORT:
+ sad = (short_ad *)sptr;
+ sad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+ inode->i_sb->s_blocksize);
+ sad->extPosition = cpu_to_le32(epos->block.logicalBlockNum);
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ lad = (long_ad *)sptr;
+ lad->extLength = cpu_to_le32(EXT_NEXT_EXTENT_ALLOCDECS |
+ inode->i_sb->s_blocksize);
+ lad->extLocation = cpu_to_lelb(epos->block);
+ memset(lad->impUse, 0x00, sizeof(lad->impUse));
+ break;
}
- if (epos->bh)
- {
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+ if (epos->bh) {
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
udf_update_tag(epos->bh->b_data, loffset);
else
udf_update_tag(epos->bh->b_data, sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(epos->bh, inode);
brelse(epos->bh);
- }
- else
+ } else {
mark_inode_dirty(inode);
+ }
epos->bh = nbh;
}
etype = udf_write_aext(inode, epos, eloc, elen, inc);
- if (!epos->bh)
- {
+ if (!epos->bh) {
UDF_I_LENALLOC(inode) += adsize;
mark_inode_dirty(inode);
- }
- else
- {
+ } else {
aed = (struct allocExtDesc *)epos->bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize);
@@ -1834,73 +1716,68 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
return etype;
}
-int8_t udf_write_aext(struct inode *inode, struct extent_position *epos,
- kernel_lb_addr eloc, uint32_t elen, int inc)
+int8_t udf_write_aext(struct inode * inode, struct extent_position * epos,
+ kernel_lb_addr eloc, uint32_t elen, int inc)
{
int adsize;
uint8_t *ptr;
+ short_ad *sad;
+ long_ad *lad;
if (!epos->bh)
ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
else
ptr = epos->bh->b_data + epos->offset;
- switch (UDF_I_ALLOCTYPE(inode))
- {
- case ICBTAG_FLAG_AD_SHORT:
- {
- short_ad *sad = (short_ad *)ptr;
- sad->extLength = cpu_to_le32(elen);
- sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
- adsize = sizeof(short_ad);
- break;
- }
- case ICBTAG_FLAG_AD_LONG:
- {
- long_ad *lad = (long_ad *)ptr;
- lad->extLength = cpu_to_le32(elen);
- lad->extLocation = cpu_to_lelb(eloc);
- memset(lad->impUse, 0x00, sizeof(lad->impUse));
- adsize = sizeof(long_ad);
- break;
- }
- default:
- return -1;
+ switch (UDF_I_ALLOCTYPE(inode)) {
+ case ICBTAG_FLAG_AD_SHORT:
+ sad = (short_ad *)ptr;
+ sad->extLength = cpu_to_le32(elen);
+ sad->extPosition = cpu_to_le32(eloc.logicalBlockNum);
+ adsize = sizeof(short_ad);
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ lad = (long_ad *)ptr;
+ lad->extLength = cpu_to_le32(elen);
+ lad->extLocation = cpu_to_lelb(eloc);
+ memset(lad->impUse, 0x00, sizeof(lad->impUse));
+ adsize = sizeof(long_ad);
+ break;
+ default:
+ return -1;
}
- if (epos->bh)
- {
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- {
+ if (epos->bh) {
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB_UDFREV(inode->i_sb) >= 0x0201) {
struct allocExtDesc *aed = (struct allocExtDesc *)epos->bh->b_data;
udf_update_tag(epos->bh->b_data,
- le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
+ le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc));
}
mark_buffer_dirty_inode(epos->bh, inode);
- }
- else
+ } else {
mark_inode_dirty(inode);
+ }
if (inc)
epos->offset += adsize;
+
return (elen >> 30);
}
-int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
- kernel_lb_addr *eloc, uint32_t *elen, int inc)
+int8_t udf_next_aext(struct inode * inode, struct extent_position * epos,
+ kernel_lb_addr * eloc, uint32_t * elen, int inc)
{
int8_t etype;
while ((etype = udf_current_aext(inode, epos, eloc, elen, inc)) ==
- (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
- {
+ (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
epos->block = *eloc;
epos->offset = sizeof(struct allocExtDesc);
brelse(epos->bh);
- if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0))))
- {
+ if (!(epos->bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, epos->block, 0)))) {
udf_debug("reading block %d failed!\n",
- udf_get_lb_pblock(inode->i_sb, epos->block, 0));
+ udf_get_lb_pblock(inode->i_sb, epos->block, 0));
return -1;
}
}
@@ -1908,68 +1785,55 @@ int8_t udf_next_aext(struct inode *inode, struct extent_position *epos,
return etype;
}
-int8_t udf_current_aext(struct inode *inode, struct extent_position *epos,
- kernel_lb_addr *eloc, uint32_t *elen, int inc)
+int8_t udf_current_aext(struct inode * inode, struct extent_position * epos,
+ kernel_lb_addr * eloc, uint32_t * elen, int inc)
{
int alen;
int8_t etype;
uint8_t *ptr;
+ short_ad *sad;
+ long_ad *lad;
- if (!epos->bh)
- {
+
+ if (!epos->bh) {
if (!epos->offset)
epos->offset = udf_file_entry_alloc_offset(inode);
ptr = UDF_I_DATA(inode) + epos->offset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode);
alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode);
- }
- else
- {
+ } else {
if (!epos->offset)
epos->offset = sizeof(struct allocExtDesc);
ptr = epos->bh->b_data + epos->offset;
- alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);
+ alen = sizeof(struct allocExtDesc) +
+ le32_to_cpu(((struct allocExtDesc *)epos->bh->b_data)->lengthAllocDescs);
}
- switch (UDF_I_ALLOCTYPE(inode))
- {
- case ICBTAG_FLAG_AD_SHORT:
- {
- short_ad *sad;
-
- if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))
- return -1;
-
- etype = le32_to_cpu(sad->extLength) >> 30;
- eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
- eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
- *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
- break;
- }
- case ICBTAG_FLAG_AD_LONG:
- {
- long_ad *lad;
-
- if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))
- return -1;
-
- etype = le32_to_cpu(lad->extLength) >> 30;
- *eloc = lelb_to_cpu(lad->extLocation);
- *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
- break;
- }
- default:
- {
- udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+ switch (UDF_I_ALLOCTYPE(inode)) {
+ case ICBTAG_FLAG_AD_SHORT:
+ if (!(sad = udf_get_fileshortad(ptr, alen, &epos->offset, inc)))
return -1;
- }
+ etype = le32_to_cpu(sad->extLength) >> 30;
+ eloc->logicalBlockNum = le32_to_cpu(sad->extPosition);
+ eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum;
+ *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ break;
+ case ICBTAG_FLAG_AD_LONG:
+ if (!(lad = udf_get_filelongad(ptr, alen, &epos->offset, inc)))
+ return -1;
+ etype = le32_to_cpu(lad->extLength) >> 30;
+ *eloc = lelb_to_cpu(lad->extLocation);
+ *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK;
+ break;
+ default:
+ udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode));
+ return -1;
}
return etype;
}
-static int8_t
-udf_insert_aext(struct inode *inode, struct extent_position epos,
- kernel_lb_addr neloc, uint32_t nelen)
+static int8_t udf_insert_aext(struct inode *inode, struct extent_position epos,
+ kernel_lb_addr neloc, uint32_t nelen)
{
kernel_lb_addr oeloc;
uint32_t oelen;
@@ -1978,28 +1842,26 @@ udf_insert_aext(struct inode *inode, struct extent_position epos,
if (epos.bh)
get_bh(epos.bh);
- while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1)
- {
+ while ((etype = udf_next_aext(inode, &epos, &oeloc, &oelen, 0)) != -1) {
udf_write_aext(inode, &epos, neloc, nelen, 1);
-
neloc = oeloc;
nelen = (etype << 30) | oelen;
}
udf_add_aext(inode, &epos, neloc, nelen, 1);
brelse(epos.bh);
+
return (nelen >> 30);
}
-int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
- kernel_lb_addr eloc, uint32_t elen)
+int8_t udf_delete_aext(struct inode * inode, struct extent_position epos,
+ kernel_lb_addr eloc, uint32_t elen)
{
struct extent_position oepos;
int adsize;
int8_t etype;
struct allocExtDesc *aed;
- if (epos.bh)
- {
+ if (epos.bh) {
get_bh(epos.bh);
get_bh(epos.bh);
}
@@ -2015,11 +1877,9 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
if (udf_next_aext(inode, &epos, &eloc, &elen, 1) == -1)
return -1;
- while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
- {
+ while ((etype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
udf_write_aext(inode, &oepos, eloc, (etype << 30) | elen, 1);
- if (oepos.bh != epos.bh)
- {
+ if (oepos.bh != epos.bh) {
oepos.block = epos.block;
brelse(oepos.bh);
get_bh(epos.bh);
@@ -2030,62 +1890,57 @@ int8_t udf_delete_aext(struct inode *inode, struct extent_position epos,
memset(&eloc, 0x00, sizeof(kernel_lb_addr));
elen = 0;
- if (epos.bh != oepos.bh)
- {
+ if (epos.bh != oepos.bh) {
udf_free_blocks(inode->i_sb, inode, epos.block, 0, 1);
udf_write_aext(inode, &oepos, eloc, elen, 1);
udf_write_aext(inode, &oepos, eloc, elen, 1);
- if (!oepos.bh)
- {
+ if (!oepos.bh) {
UDF_I_LENALLOC(inode) -= (adsize * 2);
mark_inode_dirty(inode);
- }
- else
- {
+ } else {
aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs =
- cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize));
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
- udf_update_tag(oepos.bh->b_data, oepos.offset - (2*adsize));
+ cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2 * adsize));
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+ udf_update_tag(oepos.bh->b_data, oepos.offset - (2 * adsize));
else
udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(oepos.bh, inode);
}
- }
- else
- {
+ } else {
udf_write_aext(inode, &oepos, eloc, elen, 1);
- if (!oepos.bh)
- {
+ if (!oepos.bh) {
UDF_I_LENALLOC(inode) -= adsize;
mark_inode_dirty(inode);
- }
- else
- {
+ } else {
aed = (struct allocExtDesc *)oepos.bh->b_data;
aed->lengthAllocDescs =
cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize);
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
udf_update_tag(oepos.bh->b_data, epos.offset - adsize);
else
udf_update_tag(oepos.bh->b_data, sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(oepos.bh, inode);
}
}
-
+
brelse(epos.bh);
brelse(oepos.bh);
+
return (elen >> 30);
}
-int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *pos,
- kernel_lb_addr *eloc, uint32_t *elen, sector_t *offset)
+int8_t inode_bmap(struct inode * inode, sector_t block,
+ struct extent_position * pos, kernel_lb_addr * eloc,
+ uint32_t * elen, sector_t * offset)
{
- loff_t lbcount = 0, bcount = (loff_t)block << inode->i_sb->s_blocksize_bits;
+ loff_t lbcount = 0, bcount =
+ (loff_t) block << inode->i_sb->s_blocksize_bits;
int8_t etype;
- if (block < 0)
- {
+ if (block < 0) {
printk(KERN_ERR "udf: inode_bmap: block < 0\n");
return -1;
}
@@ -2095,10 +1950,8 @@ int8_t inode_bmap(struct inode *inode, sector_t block, struct extent_position *p
pos->bh = NULL;
*elen = 0;
- do
- {
- if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1)
- {
+ do {
+ if ((etype = udf_next_aext(inode, pos, eloc, elen, 1)) == -1) {
*offset = (bcount - lbcount) >> inode->i_sb->s_blocksize_bits;
UDF_I_LENEXTENTS(inode) = lbcount;
return -1;
@@ -2116,7 +1969,7 @@ long udf_block_map(struct inode *inode, sector_t block)
kernel_lb_addr eloc;
uint32_t elen;
sector_t offset;
- struct extent_position epos = { NULL, 0, { 0, 0}};
+ struct extent_position epos = {};
int ret;
lock_kernel();
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c
index 084216107667..579bae71e67e 100644
--- a/fs/udf/lowlevel.c
+++ b/fs/udf/lowlevel.c
@@ -26,38 +26,33 @@
#include <linux/udf_fs.h>
#include "udf_sb.h"
-unsigned int
-udf_get_last_session(struct super_block *sb)
+unsigned int udf_get_last_session(struct super_block *sb)
{
struct cdrom_multisession ms_info;
unsigned int vol_desc_start;
struct block_device *bdev = sb->s_bdev;
int i;
- vol_desc_start=0;
- ms_info.addr_format=CDROM_LBA;
- i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
+ vol_desc_start = 0;
+ ms_info.addr_format = CDROM_LBA;
+ i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long)&ms_info);
#define WE_OBEY_THE_WRITTEN_STANDARDS 1
- if (i == 0)
- {
+ if (i == 0) {
udf_debug("XA disk: %s, vol_desc_start=%d\n",
- (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
+ (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba);
#if WE_OBEY_THE_WRITTEN_STANDARDS
if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
#endif
vol_desc_start = ms_info.addr.lba;
- }
- else
- {
+ } else {
udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i);
}
return vol_desc_start;
}
-unsigned long
-udf_get_last_block(struct super_block *sb)
+unsigned long udf_get_last_block(struct super_block *sb)
{
struct block_device *bdev = sb->s_bdev;
unsigned long lblock = 0;
diff --git a/fs/udf/misc.c b/fs/udf/misc.c
index a2b2a98ce78a..15297deb5051 100644
--- a/fs/udf/misc.c
+++ b/fs/udf/misc.c
@@ -29,8 +29,7 @@
#include "udf_i.h"
#include "udf_sb.h"
-struct buffer_head *
-udf_tgetblk(struct super_block *sb, int block)
+struct buffer_head *udf_tgetblk(struct super_block *sb, int block)
{
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
return sb_getblk(sb, udf_fixed_to_variable(block));
@@ -38,8 +37,7 @@ udf_tgetblk(struct super_block *sb, int block)
return sb_getblk(sb, block);
}
-struct buffer_head *
-udf_tread(struct super_block *sb, int block)
+struct buffer_head *udf_tread(struct super_block *sb, int block)
{
if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV))
return sb_bread(sb, udf_fixed_to_variable(block));
@@ -47,9 +45,8 @@ udf_tread(struct super_block *sb, int block)
return sb_bread(sb, block);
}
-struct genericFormat *
-udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
- uint8_t loc)
+struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size,
+ uint32_t type, uint8_t loc)
{
uint8_t *ea = NULL, *ad = NULL;
int offset;
@@ -57,10 +54,9 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
int i;
ea = UDF_I_DATA(inode);
- if (UDF_I_LENEATTR(inode))
+ if (UDF_I_LENEATTR(inode)) {
ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
- else
- {
+ } else {
ad = ea;
size += sizeof(struct extendedAttrHeaderDesc);
}
@@ -70,27 +66,21 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
/* TODO - Check for FreeEASpace */
- if (loc & 0x01 && offset >= size)
- {
+ if (loc & 0x01 && offset >= size) {
struct extendedAttrHeaderDesc *eahd;
eahd = (struct extendedAttrHeaderDesc *)ea;
- if (UDF_I_LENALLOC(inode))
- {
+ if (UDF_I_LENALLOC(inode)) {
memmove(&ad[size], ad, UDF_I_LENALLOC(inode));
}
- if (UDF_I_LENEATTR(inode))
- {
+ if (UDF_I_LENEATTR(inode)) {
/* check checksum/crc */
if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
- le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
- {
+ le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) {
return NULL;
}
- }
- else
- {
+ } else {
size -= sizeof(struct extendedAttrHeaderDesc);
UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc);
eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD);
@@ -105,29 +95,23 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
}
offset = UDF_I_LENEATTR(inode);
- if (type < 2048)
- {
- if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
- {
+ if (type < 2048) {
+ if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) {
uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
memmove(&ea[offset - aal + size],
&ea[aal], offset - aal);
offset -= aal;
eahd->appAttrLocation = cpu_to_le32(aal + size);
}
- if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode))
- {
+ if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode)) {
uint32_t ial = le32_to_cpu(eahd->impAttrLocation);
memmove(&ea[offset - ial + size],
&ea[ial], offset - ial);
offset -= ial;
eahd->impAttrLocation = cpu_to_le32(ial + size);
}
- }
- else if (type < 65536)
- {
- if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode))
- {
+ } else if (type < 65536) {
+ if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) {
uint32_t aal = le32_to_cpu(eahd->appAttrLocation);
memmove(&ea[offset - aal + size],
&ea[aal], offset - aal);
@@ -138,22 +122,23 @@ udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type,
/* rewrite CRC + checksum of eahd */
crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag);
eahd->descTag.descCRCLength = cpu_to_le16(crclen);
- eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0));
+ eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd +
+ sizeof(tag), crclen, 0));
eahd->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
+ for (i = 0; i < 16; i++)
if (i != 4)
eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i];
UDF_I_LENEATTR(inode) += size;
return (struct genericFormat *)&ea[offset];
}
- if (loc & 0x02)
- {
+ if (loc & 0x02) {
}
+
return NULL;
}
-struct genericFormat *
-udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
+struct genericFormat *udf_get_extendedattr(struct inode *inode, uint32_t type,
+ uint8_t subtype)
{
struct genericFormat *gaf;
uint8_t *ea = NULL;
@@ -161,18 +146,16 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
ea = UDF_I_DATA(inode);
- if (UDF_I_LENEATTR(inode))
- {
+ if (UDF_I_LENEATTR(inode)) {
struct extendedAttrHeaderDesc *eahd;
eahd = (struct extendedAttrHeaderDesc *)ea;
/* check checksum/crc */
if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD ||
- le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum)
- {
+ le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) {
return NULL;
}
-
+
if (type < 2048)
offset = sizeof(struct extendedAttrHeaderDesc);
else if (type < 65536)
@@ -180,8 +163,7 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
else
offset = le32_to_cpu(eahd->appAttrLocation);
- while (offset < UDF_I_LENEATTR(inode))
- {
+ while (offset < UDF_I_LENEATTR(inode)) {
gaf = (struct genericFormat *)&ea[offset];
if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype)
return gaf;
@@ -189,6 +171,7 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
offset += le32_to_cpu(gaf->attrLength);
}
}
+
return NULL;
}
@@ -202,8 +185,8 @@ udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype)
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-struct buffer_head *
-udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident)
+struct buffer_head *udf_read_tagged(struct super_block *sb, uint32_t block,
+ uint32_t location, uint16_t * ident)
{
tag *tag_p;
struct buffer_head *bh = NULL;
@@ -215,9 +198,9 @@ udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint1
return NULL;
bh = udf_tread(sb, block + UDF_SB_SESSION(sb));
- if (!bh)
- {
- udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location);
+ if (!bh) {
+ udf_debug("block=%d, location=%d: read failed\n",
+ block + UDF_SB_SESSION(sb), location);
return NULL;
}
@@ -225,13 +208,12 @@ udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint1
*ident = le16_to_cpu(tag_p->tagIdent);
- if ( location != le32_to_cpu(tag_p->tagLocation) )
- {
+ if (location != le32_to_cpu(tag_p->tagLocation)) {
udf_debug("location mismatch block %u, tag %u != %u\n",
- block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
+ block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location);
goto error_out;
}
-
+
/* Verify the tag checksum */
checksum = 0U;
for (i = 0; i < 4; i++)
@@ -245,33 +227,32 @@ udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint1
/* Verify the tag version */
if (le16_to_cpu(tag_p->descVersion) != 0x0002U &&
- le16_to_cpu(tag_p->descVersion) != 0x0003U)
- {
+ le16_to_cpu(tag_p->descVersion) != 0x0003U) {
udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n",
- le16_to_cpu(tag_p->descVersion), block);
+ le16_to_cpu(tag_p->descVersion), block);
goto error_out;
}
/* Verify the descriptor CRC */
if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize ||
- le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
- le16_to_cpu(tag_p->descCRCLength), 0))
- {
+ le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag),
+ le16_to_cpu(tag_p->descCRCLength), 0)) {
return bh;
}
udf_debug("Crc failure block %d: crc = %d, crclen = %d\n",
- block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength));
+ block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC),
+ le16_to_cpu(tag_p->descCRCLength));
error_out:
brelse(bh);
return NULL;
}
-struct buffer_head *
-udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident)
+struct buffer_head *udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc,
+ uint32_t offset, uint16_t * ident)
{
return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset),
- loc.logicalBlockNum + offset, ident);
+ loc.logicalBlockNum + offset, ident);
}
void udf_update_tag(char *data, int length)
@@ -285,13 +266,13 @@ void udf_update_tag(char *data, int length)
tptr->descCRCLength = cpu_to_le16(length);
tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0));
- for (i=0; i<16; i++)
+ for (i = 0; i < 16; i++)
if (i != 4)
tptr->tagChecksum += (uint8_t)(data[i]);
}
void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum,
- uint32_t loc, int length)
+ uint32_t loc, int length)
{
tag *tptr = (tag *)data;
tptr->tagIdent = cpu_to_le16(ident);
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 51fe307dc0ec..bec96a6b3343 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -32,16 +32,18 @@
#include <linux/buffer_head.h>
#include <linux/sched.h>
-static inline int udf_match(int len1, const char *name1, int len2, const char *name2)
+static inline int udf_match(int len1, const char *name1, int len2,
+ const char *name2)
{
if (len1 != len2)
return 0;
+
return !memcmp(name1, name2, len1);
}
int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
- struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
- uint8_t *impuse, uint8_t *fileident)
+ struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
+ uint8_t * impuse, uint8_t * fileident)
{
uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
uint16_t crc;
@@ -59,14 +61,12 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
offset = fibh->soffset + sizeof(struct fileIdentDesc);
- if (impuse)
- {
- if (adinicb || (offset + liu < 0))
+ if (impuse) {
+ if (adinicb || (offset + liu < 0)) {
memcpy((uint8_t *)sfi->impUse, impuse, liu);
- else if (offset >= 0)
+ } else if (offset >= 0) {
memcpy(fibh->ebh->b_data + offset, impuse, liu);
- else
- {
+ } else {
memcpy((uint8_t *)sfi->impUse, impuse, -offset);
memcpy(fibh->ebh->b_data, impuse - offset, liu + offset);
}
@@ -74,14 +74,12 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
offset += liu;
- if (fileident)
- {
- if (adinicb || (offset + lfi < 0))
+ if (fileident) {
+ if (adinicb || (offset + lfi < 0)) {
memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);
- else if (offset >= 0)
+ } else if (offset >= 0) {
memcpy(fibh->ebh->b_data + offset, fileident, lfi);
- else
- {
+ } else {
memcpy((uint8_t *)sfi->fileIdent + liu, fileident, -offset);
memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset);
}
@@ -89,53 +87,50 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
offset += lfi;
- if (adinicb || (offset + padlen < 0))
+ if (adinicb || (offset + padlen < 0)) {
memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);
- else if (offset >= 0)
+ } else if (offset >= 0) {
memset(fibh->ebh->b_data + offset, 0x00, padlen);
- else
- {
+ } else {
memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);
memset(fibh->ebh->b_data, 0x00, padlen + offset);
}
- crc = udf_crc((uint8_t *)cfi + sizeof(tag), sizeof(struct fileIdentDesc) -
- sizeof(tag), 0);
+ crc = udf_crc((uint8_t *)cfi + sizeof(tag),
+ sizeof(struct fileIdentDesc) - sizeof(tag), 0);
- if (fibh->sbh == fibh->ebh)
+ if (fibh->sbh == fibh->ebh) {
crc = udf_crc((uint8_t *)sfi->impUse,
- crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
- else if (sizeof(struct fileIdentDesc) >= -fibh->soffset)
+ crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
+ } else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset,
- crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
- else
- {
+ crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc);
+ } else {
crc = udf_crc((uint8_t *)sfi->impUse,
- -fibh->soffset - sizeof(struct fileIdentDesc), crc);
+ -fibh->soffset - sizeof(struct fileIdentDesc), crc);
crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc);
}
cfi->descTag.descCRC = cpu_to_le16(crc);
cfi->descTag.descCRCLength = cpu_to_le16(crclen);
- for (i=0; i<16; i++)
+ for (i = 0; i < 16; i++) {
if (i != 4)
checksum += ((uint8_t *)&cfi->descTag)[i];
+ }
cfi->descTag.tagChecksum = checksum;
- if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset))
+ if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) {
memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc));
- else
- {
+ } else {
memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
- sizeof(struct fileIdentDesc) + fibh->soffset);
+ sizeof(struct fileIdentDesc) + fibh->soffset);
}
- if (adinicb)
+ if (adinicb) {
mark_inode_dirty(inode);
- else
- {
+ } else {
if (fibh->sbh != fibh->ebh)
mark_buffer_dirty_inode(fibh->ebh, inode);
mark_buffer_dirty_inode(fibh->sbh, inode);
@@ -143,12 +138,12 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
return 0;
}
-static struct fileIdentDesc *
-udf_find_entry(struct inode *dir, struct dentry *dentry,
- struct udf_fileident_bh *fibh,
- struct fileIdentDesc *cfi)
+static struct fileIdentDesc *udf_find_entry(struct inode *dir,
+ struct dentry *dentry,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi)
{
- struct fileIdentDesc *fi=NULL;
+ struct fileIdentDesc *fi = NULL;
loff_t f_pos;
int block, flen;
char fname[UDF_NAME_LEN];
@@ -159,46 +154,39 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
kernel_lb_addr eloc;
uint32_t elen;
sector_t offset;
- struct extent_position epos = { NULL, 0, { 0, 0}};
+ struct extent_position epos = {};
size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
f_pos = (udf_ext0_offset(dir) >> 2);
fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
fibh->sbh = fibh->ebh = NULL;
- else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
- {
+ } else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
epos.offset -= sizeof(long_ad);
- }
- else
+ } else {
offset = 0;
+ }
- if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
- {
+ if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) {
brelse(epos.bh);
return NULL;
}
- }
- else
- {
+ } else {
brelse(epos.bh);
return NULL;
}
- while ( (f_pos < size) )
- {
- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
-
- if (!fi)
- {
+ while ((f_pos < size)) {
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+ &elen, &offset);
+ if (!fi) {
if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh);
brelse(fibh->sbh);
@@ -209,54 +197,48 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
liu = le16_to_cpu(cfi->lengthOfImpUse);
lfi = cfi->lengthFileIdent;
- if (fibh->sbh == fibh->ebh)
- {
+ if (fibh->sbh == fibh->ebh) {
nameptr = fi->fileIdent + liu;
- }
- else
- {
+ } else {
int poffset; /* Unpaded ending offset */
poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
- if (poffset >= lfi)
+ if (poffset >= lfi) {
nameptr = (uint8_t *)(fibh->ebh->b_data + poffset - lfi);
- else
- {
+ } else {
nameptr = fname;
memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
}
}
- if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) )
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
continue;
}
-
- if ( (cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 )
- {
- if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) )
+
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
+ if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
continue;
}
if (!lfi)
continue;
- if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)))
- {
- if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
- {
+ if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi))) {
+ if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) {
brelse(epos.bh);
return fi;
}
}
}
+
if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh);
brelse(fibh->sbh);
brelse(epos.bh);
+
return NULL;
}
@@ -293,25 +275,27 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
* Written, tested, and released.
*/
-static struct dentry *
-udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
+static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
{
struct inode *inode = NULL;
struct fileIdentDesc cfi;
struct udf_fileident_bh fibh;
- if (dentry->d_name.len > UDF_NAME_LEN-2)
+ if (dentry->d_name.len > UDF_NAME_LEN - 2)
return ERR_PTR(-ENAMETOOLONG);
lock_kernel();
#ifdef UDF_RECOVERY
/* temporary shorthand for specifying files by inode number */
- if (!strncmp(dentry->d_name.name, ".B=", 3) )
- {
- kernel_lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) };
+ if (!strncmp(dentry->d_name.name, ".B=", 3)) {
+ kernel_lb_addr lb = {
+ .logicalBlockNum = 0,
+ .partitionReferenceNum = simple_strtoul(dentry->d_name.name + 3,
+ NULL, 0),
+ };
inode = udf_iget(dir->i_sb, lb);
- if (!inode)
- {
+ if (!inode) {
unlock_kernel();
return ERR_PTR(-EACCES);
}
@@ -319,31 +303,30 @@ udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
else
#endif /* UDF_RECOVERY */
- if (udf_find_entry(dir, dentry, &fibh, &cfi))
- {
+ if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
- if ( !inode )
- {
+ if (!inode) {
unlock_kernel();
return ERR_PTR(-EACCES);
}
}
unlock_kernel();
d_add(dentry, inode);
+
return NULL;
}
-static struct fileIdentDesc *
-udf_add_entry(struct inode *dir, struct dentry *dentry,
- struct udf_fileident_bh *fibh,
- struct fileIdentDesc *cfi, int *err)
+static struct fileIdentDesc *udf_add_entry(struct inode *dir,
+ struct dentry *dentry,
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi, int *err)
{
struct super_block *sb;
- struct fileIdentDesc *fi=NULL;
+ struct fileIdentDesc *fi = NULL;
char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
int namelen;
loff_t f_pos;
@@ -357,50 +340,44 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
kernel_lb_addr eloc;
uint32_t elen;
sector_t offset;
- struct extent_position epos = { NULL, 0, { 0, 0 }};
+ struct extent_position epos = {};
sb = dir->i_sb;
- if (dentry)
- {
- if (!dentry->d_name.len)
- {
+ if (dentry) {
+ if (!dentry->d_name.len) {
*err = -EINVAL;
return NULL;
}
-
- if ( !(namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len)))
- {
+ if (!(namelen = udf_put_filename(sb, dentry->d_name.name, name,
+ dentry->d_name.len))) {
*err = -ENAMETOOLONG;
return NULL;
}
- }
- else
+ } else {
namelen = 0;
+ }
nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;
f_pos = (udf_ext0_offset(dir) >> 2);
fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
fibh->sbh = fibh->ebh = NULL;
- else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
- {
+ } else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
epos.offset -= sizeof(long_ad);
- }
- else
+ } else {
offset = 0;
+ }
- if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
- {
+ if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) {
brelse(epos.bh);
*err = -EIO;
return NULL;
@@ -408,21 +385,18 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
block = UDF_I_LOCATION(dir).logicalBlockNum;
- }
- else
- {
+ } else {
block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0);
fibh->sbh = fibh->ebh = NULL;
fibh->soffset = fibh->eoffset = sb->s_blocksize;
goto add;
}
- while ( (f_pos < size) )
- {
- fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, &elen, &offset);
+ while ((f_pos < size)) {
+ fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
+ &elen, &offset);
- if (!fi)
- {
+ if (!fi) {
if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh);
brelse(fibh->sbh);
@@ -434,38 +408,33 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
liu = le16_to_cpu(cfi->lengthOfImpUse);
lfi = cfi->lengthFileIdent;
- if (fibh->sbh == fibh->ebh)
+ if (fibh->sbh == fibh->ebh) {
nameptr = fi->fileIdent + liu;
- else
- {
+ } else {
int poffset; /* Unpaded ending offset */
poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi;
- if (poffset >= lfi)
+ if (poffset >= lfi) {
nameptr = (char *)(fibh->ebh->b_data + poffset - lfi);
- else
- {
+ } else {
nameptr = fname;
memcpy(nameptr, fi->fileIdent + liu, lfi - poffset);
memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset);
}
}
- if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 )
- {
- if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen)
- {
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
+ if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) {
brelse(epos.bh);
cfi->descTag.tagSerialNum = cpu_to_le16(1);
cfi->fileVersionNum = cpu_to_le16(1);
cfi->fileCharacteristics = 0;
cfi->lengthFileIdent = namelen;
cfi->lengthOfImpUse = cpu_to_le16(0);
- if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
+ if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
return fi;
- else
- {
+ } else {
*err = -EIO;
return NULL;
}
@@ -476,8 +445,7 @@ udf_add_entry(struct inode *dir, struct dentry *dentry,
continue;
if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) &&
- udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name))
- {
+ udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) {
if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh);
brelse(fibh->sbh);
@@ -491,8 +459,7 @@ add:
f_pos += nfidlen;
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB &&
- sb->s_blocksize - fibh->eoffset < nfidlen)
- {
+ sb->s_blocksize - fibh->eoffset < nfidlen) {
brelse(epos.bh);
epos.bh = NULL;
fibh->soffset -= udf_ext0_offset(dir);
@@ -514,65 +481,54 @@ add:
epos.offset += sizeof(long_ad);
}
- if (sb->s_blocksize - fibh->eoffset >= nfidlen)
- {
+ if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
fibh->soffset = fibh->eoffset;
fibh->eoffset += nfidlen;
- if (fibh->sbh != fibh->ebh)
- {
+ if (fibh->sbh != fibh->ebh) {
brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
block = UDF_I_LOCATION(dir).logicalBlockNum;
- fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset - udf_ext0_offset(dir) + UDF_I_LENEATTR(dir));
- }
- else
- {
+ fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset -
+ udf_ext0_offset(dir) +
+ UDF_I_LENEATTR(dir));
+ } else {
block = eloc.logicalBlockNum + ((elen - 1) >>
- dir->i_sb->s_blocksize_bits);
+ dir->i_sb->s_blocksize_bits);
fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset);
}
- }
- else
- {
+ } else {
fibh->soffset = fibh->eoffset - sb->s_blocksize;
fibh->eoffset += nfidlen - sb->s_blocksize;
- if (fibh->sbh != fibh->ebh)
- {
+ if (fibh->sbh != fibh->ebh) {
brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
}
block = eloc.logicalBlockNum + ((elen - 1) >>
- dir->i_sb->s_blocksize_bits);
-
- if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err)))
- {
+ dir->i_sb->s_blocksize_bits);
+ fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err);
+ if (!fibh->ebh) {
brelse(epos.bh);
brelse(fibh->sbh);
return NULL;
}
- if (!(fibh->soffset))
- {
+ if (!fibh->soffset) {
if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
- (EXT_RECORDED_ALLOCATED >> 30))
- {
+ (EXT_RECORDED_ALLOCATED >> 30)) {
block = eloc.logicalBlockNum + ((elen - 1) >>
dir->i_sb->s_blocksize_bits);
+ } else {
+ block++;
}
- else
- block ++;
brelse(fibh->sbh);
fibh->sbh = fibh->ebh;
fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
- }
- else
- {
+ } else {
fi = (struct fileIdentDesc *)
(fibh->sbh->b_data + sb->s_blocksize + fibh->soffset);
}
@@ -586,17 +542,14 @@ add:
cfi->fileVersionNum = cpu_to_le16(1);
cfi->lengthFileIdent = namelen;
cfi->lengthOfImpUse = cpu_to_le16(0);
- if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name))
- {
+ if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
brelse(epos.bh);
dir->i_size += nfidlen;
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
UDF_I_LENALLOC(dir) += nfidlen;
mark_inode_dirty(dir);
return fi;
- }
- else
- {
+ } else {
brelse(epos.bh);
if (fibh->sbh != fibh->ebh)
brelse(fibh->ebh);
@@ -607,15 +560,19 @@ add:
}
static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
- struct udf_fileident_bh *fibh, struct fileIdentDesc *cfi)
+ struct udf_fileident_bh *fibh,
+ struct fileIdentDesc *cfi)
{
cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
+
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
memset(&(cfi->icb), 0x00, sizeof(long_ad));
+
return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
}
-static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
+static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
{
struct udf_fileident_bh fibh;
struct inode *inode;
@@ -624,8 +581,7 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
lock_kernel();
inode = udf_new_inode(dir, mode, &err);
- if (!inode)
- {
+ if (!inode) {
unlock_kernel();
return err;
}
@@ -639,9 +595,8 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
inode->i_mode = mode;
mark_inode_dirty(inode);
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
- inode->i_nlink --;
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
+ inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
unlock_kernel();
@@ -652,8 +607,7 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
mark_inode_dirty(dir);
}
if (fibh.sbh != fibh.ebh)
@@ -661,12 +615,14 @@ static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct
brelse(fibh.sbh);
unlock_kernel();
d_instantiate(dentry, inode);
+
return 0;
}
-static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t rdev)
+static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t rdev)
{
- struct inode * inode;
+ struct inode *inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc cfi, *fi;
int err;
@@ -682,9 +638,8 @@ static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t
inode->i_uid = current->fsuid;
init_special_inode(inode, mode, rdev);
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
- inode->i_nlink --;
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
+ inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
unlock_kernel();
@@ -695,8 +650,7 @@ static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t
*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
mark_inode_dirty(dir);
}
mark_inode_dirty(inode);
@@ -706,21 +660,22 @@ static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t
brelse(fibh.sbh);
d_instantiate(dentry, inode);
err = 0;
+
out:
unlock_kernel();
return err;
}
-static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
- struct inode * inode;
+ struct inode *inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc cfi, *fi;
int err;
lock_kernel();
err = -EMLINK;
- if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1)
+ if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
goto out;
err = -EIO;
@@ -730,8 +685,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_op = &udf_dir_inode_operations;
inode->i_fop = &udf_dir_operations;
- if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err)))
- {
+ if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err))) {
inode->i_nlink--;
mark_inode_dirty(inode);
iput(inode);
@@ -750,8 +704,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
inode->i_mode |= S_ISGID;
mark_inode_dirty(inode);
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
inode->i_nlink = 0;
mark_inode_dirty(inode);
iput(inode);
@@ -770,6 +723,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
brelse(fibh.ebh);
brelse(fibh.sbh);
err = 0;
+
out:
unlock_kernel();
return err;
@@ -785,47 +739,39 @@ static int empty_dir(struct inode *dir)
kernel_lb_addr eloc;
uint32_t elen;
sector_t offset;
- struct extent_position epos = { NULL, 0, { 0, 0}};
+ struct extent_position epos = {};
f_pos = (udf_ext0_offset(dir) >> 2);
fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
fibh.sbh = fibh.ebh = NULL;
- else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
- &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30))
- {
+ } else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
+ &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) {
block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
- if ((++offset << dir->i_sb->s_blocksize_bits) < elen)
- {
+ if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(short_ad);
else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG)
epos.offset -= sizeof(long_ad);
- }
- else
+ } else {
offset = 0;
+ }
- if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block)))
- {
+ if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
brelse(epos.bh);
return 0;
}
- }
- else
- {
+ } else {
brelse(epos.bh);
return 0;
}
-
- while ( (f_pos < size) )
- {
- fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset);
-
- if (!fi)
- {
+ while ((f_pos < size)) {
+ fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
+ &elen, &offset);
+ if (!fi) {
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
@@ -833,8 +779,8 @@ static int empty_dir(struct inode *dir)
return 0;
}
- if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0)
- {
+ if (cfi.lengthFileIdent &&
+ (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
@@ -842,17 +788,19 @@ static int empty_dir(struct inode *dir)
return 0;
}
}
+
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
brelse(epos.bh);
+
return 1;
}
-static int udf_rmdir(struct inode * dir, struct dentry * dentry)
+static int udf_rmdir(struct inode *dir, struct dentry *dentry)
{
int retval;
- struct inode * inode = dentry->d_inode;
+ struct inode *inode = dentry->d_inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc *fi, cfi;
kernel_lb_addr tloc;
@@ -875,8 +823,8 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry)
goto end_rmdir;
if (inode->i_nlink != 2)
udf_warning(inode->i_sb, "udf_rmdir",
- "empty directory has nlink != 2 (%d)",
- inode->i_nlink);
+ "empty directory has nlink != 2 (%d)",
+ inode->i_nlink);
clear_nlink(inode);
inode->i_size = 0;
inode_dec_link_count(dir);
@@ -887,15 +835,16 @@ end_rmdir:
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
+
out:
unlock_kernel();
return retval;
}
-static int udf_unlink(struct inode * dir, struct dentry * dentry)
+static int udf_unlink(struct inode *dir, struct dentry *dentry)
{
int retval;
- struct inode * inode = dentry->d_inode;
+ struct inode *inode = dentry->d_inode;
struct udf_fileident_bh fibh;
struct fileIdentDesc *fi;
struct fileIdentDesc cfi;
@@ -912,10 +861,9 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry)
if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
goto end_unlink;
- if (!inode->i_nlink)
- {
+ if (!inode->i_nlink) {
udf_debug("Deleting nonexistent file (%lu), %d\n",
- inode->i_ino, inode->i_nlink);
+ inode->i_ino, inode->i_nlink);
inode->i_nlink = 1;
}
retval = udf_delete_entry(dir, fi, &fibh, &cfi);
@@ -931,18 +879,20 @@ end_unlink:
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
+
out:
unlock_kernel();
return retval;
}
-static int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname)
+static int udf_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
{
- struct inode * inode;
+ struct inode *inode;
struct pathComponent *pc;
char *compstart;
struct udf_fileident_bh fibh;
- struct extent_position epos = { NULL, 0, {0, 0}};
+ struct extent_position epos = {};
int eoffset, elen = 0;
struct fileIdentDesc *fi;
struct fileIdentDesc cfi;
@@ -960,14 +910,13 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
inode->i_data.a_ops = &udf_symlink_aops;
inode->i_op = &page_symlink_inode_operations;
- if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB) {
kernel_lb_addr eloc;
uint32_t elen;
block = udf_new_block(inode->i_sb, inode,
- UDF_I_LOCATION(inode).partitionReferenceNum,
- UDF_I_LOCATION(inode).logicalBlockNum, &err);
+ UDF_I_LOCATION(inode).partitionReferenceNum,
+ UDF_I_LOCATION(inode).logicalBlockNum, &err);
if (!block)
goto out_no_entry;
epos.block = UDF_I_LOCATION(inode);
@@ -981,7 +930,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
brelse(epos.bh);
block = udf_get_pblock(inode->i_sb, block,
- UDF_I_LOCATION(inode).partitionReferenceNum, 0);
+ UDF_I_LOCATION(inode).partitionReferenceNum, 0);
epos.bh = udf_tread(inode->i_sb, block);
lock_buffer(epos.bh);
memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize);
@@ -989,17 +938,15 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
unlock_buffer(epos.bh);
mark_buffer_dirty_inode(epos.bh, inode);
ea = epos.bh->b_data + udf_ext0_offset(inode);
- }
- else
+ } else {
ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
+ }
eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
pc = (struct pathComponent *)ea;
- if (*symname == '/')
- {
- do
- {
+ if (*symname == '/') {
+ do {
symname++;
} while (*symname == '/');
@@ -1012,8 +959,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
err = -ENAMETOOLONG;
- while (*symname)
- {
+ while (*symname) {
if (elen + sizeof(struct pathComponent) > eoffset)
goto out_no_entry;
@@ -1021,25 +967,24 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
compstart = (char *)symname;
- do
- {
+ do {
symname++;
} while (*symname && *symname != '/');
pc->componentType = 5;
pc->lengthComponentIdent = 0;
pc->componentFileVersionNum = 0;
- if (compstart[0] == '.')
- {
- if ((symname-compstart) == 1)
+ if (compstart[0] == '.') {
+ if ((symname - compstart) == 1)
pc->componentType = 4;
- else if ((symname-compstart) == 2 && compstart[1] == '.')
+ else if ((symname - compstart) == 2 && compstart[1] == '.')
pc->componentType = 3;
}
- if (pc->componentType == 5)
- {
- if ( !(namelen = udf_put_filename(inode->i_sb, compstart, name, symname-compstart)))
+ if (pc->componentType == 5) {
+ namelen = udf_put_filename(inode->i_sb, compstart, name,
+ symname - compstart);
+ if (!namelen)
goto out_no_entry;
if (elen + sizeof(struct pathComponent) + namelen > eoffset)
@@ -1052,10 +997,8 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
- if (*symname)
- {
- do
- {
+ if (*symname) {
+ do {
symname++;
} while (*symname == '/');
}
@@ -1071,8 +1014,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
goto out_no_entry;
cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
- if (UDF_SB_LVIDBH(inode->i_sb))
- {
+ if (UDF_SB_LVIDBH(inode->i_sb)) {
struct logicalVolHeaderDesc *lvhd;
uint64_t uniqueID;
lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
@@ -1085,8 +1027,7 @@ static int udf_symlink(struct inode * dir, struct dentry * dentry, const char *
mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
}
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
mark_inode_dirty(dir);
}
if (fibh.sbh != fibh.ebh)
@@ -1105,8 +1046,8 @@ out_no_entry:
goto out;
}
-static int udf_link(struct dentry * old_dentry, struct inode * dir,
- struct dentry *dentry)
+static int udf_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
struct udf_fileident_bh fibh;
@@ -1114,21 +1055,18 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
int err;
lock_kernel();
- if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1)
- {
+ if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
unlock_kernel();
return -EMLINK;
}
- if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err)))
- {
+ if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) {
unlock_kernel();
return err;
}
cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode));
- if (UDF_SB_LVIDBH(inode->i_sb))
- {
+ if (UDF_SB_LVIDBH(inode->i_sb)) {
struct logicalVolHeaderDesc *lvhd;
uint64_t uniqueID;
lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse);
@@ -1141,10 +1079,10 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb));
}
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) {
mark_inode_dirty(dir);
}
+
if (fibh.sbh != fibh.ebh)
brelse(fibh.ebh);
brelse(fibh.sbh);
@@ -1154,17 +1092,18 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
atomic_inc(&inode->i_count);
d_instantiate(dentry, inode);
unlock_kernel();
+
return 0;
}
/* Anybody can rename anything with this: the permission checks are left to the
* higher-level routines.
*/
-static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
- struct inode * new_dir, struct dentry * new_dentry)
+static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
- struct inode * old_inode = old_dentry->d_inode;
- struct inode * new_inode = new_dentry->d_inode;
+ struct inode *old_inode = old_dentry->d_inode;
+ struct inode *new_inode = new_dentry->d_inode;
struct udf_fileident_bh ofibh, nfibh;
struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi;
struct buffer_head *dir_bh = NULL;
@@ -1172,49 +1111,41 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
kernel_lb_addr tloc;
lock_kernel();
- if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi)))
- {
+ if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi))) {
if (ofibh.sbh != ofibh.ebh)
brelse(ofibh.ebh);
brelse(ofibh.sbh);
}
tloc = lelb_to_cpu(ocfi.icb.extLocation);
if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
- != old_inode->i_ino)
+ != old_inode->i_ino)
goto end_rename;
nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
- if (nfi)
- {
- if (!new_inode)
- {
+ if (nfi) {
+ if (!new_inode) {
if (nfibh.sbh != nfibh.ebh)
brelse(nfibh.ebh);
brelse(nfibh.sbh);
nfi = NULL;
}
}
- if (S_ISDIR(old_inode->i_mode))
- {
+ if (S_ISDIR(old_inode->i_mode)) {
uint32_t offset = udf_ext0_offset(old_inode);
- if (new_inode)
- {
+ if (new_inode) {
retval = -ENOTEMPTY;
if (!empty_dir(new_inode))
goto end_rename;
}
retval = -EIO;
- if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) {
dir_fi = udf_get_fileident(UDF_I_DATA(old_inode) -
- (UDF_I_EFE(old_inode) ?
- sizeof(struct extendedFileEntry) :
- sizeof(struct fileEntry)),
- old_inode->i_sb->s_blocksize, &offset);
- }
- else
- {
+ (UDF_I_EFE(old_inode) ?
+ sizeof(struct extendedFileEntry) :
+ sizeof(struct fileEntry)),
+ old_inode->i_sb->s_blocksize, &offset);
+ } else {
dir_bh = udf_bread(old_inode, 0, 0, &retval);
if (!dir_bh)
goto end_rename;
@@ -1223,16 +1154,14 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
if (!dir_fi)
goto end_rename;
tloc = lelb_to_cpu(dir_fi->icb.extLocation);
- if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0)
- != old_dir->i_ino)
+ if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) != old_dir->i_ino)
goto end_rename;
retval = -EMLINK;
- if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1)
+ if (!new_inode && new_dir->i_nlink >= (256 << sizeof(new_dir->i_nlink)) - 1)
goto end_rename;
}
- if (!nfi)
- {
+ if (!nfi) {
nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval);
if (!nfi)
goto end_rename;
@@ -1257,39 +1186,32 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);
- if (new_inode)
- {
+ if (new_inode) {
new_inode->i_ctime = current_fs_time(new_inode->i_sb);
inode_dec_link_count(new_inode);
}
old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
mark_inode_dirty(old_dir);
- if (dir_fi)
- {
+ if (dir_fi) {
dir_fi->icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(new_dir));
udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) +
- le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
- if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB)
- {
+ le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
+ if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) {
mark_inode_dirty(old_inode);
- }
- else
+ } else {
mark_buffer_dirty_inode(dir_bh, old_inode);
+ }
inode_dec_link_count(old_dir);
- if (new_inode)
- {
+ if (new_inode) {
inode_dec_link_count(new_inode);
- }
- else
- {
+ } else {
inc_nlink(new_dir);
mark_inode_dirty(new_dir);
}
}
- if (ofi)
- {
+ if (ofi) {
if (ofibh.sbh != ofibh.ebh)
brelse(ofibh.ebh);
brelse(ofibh.sbh);
@@ -1299,13 +1221,13 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
end_rename:
brelse(dir_bh);
- if (nfi)
- {
+ if (nfi) {
if (nfibh.sbh != nfibh.ebh)
brelse(nfibh.ebh);
brelse(nfibh.sbh);
}
unlock_kernel();
+
return retval;
}
diff --git a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h
index e82aae652697..65ff47902bd2 100644
--- a/fs/udf/osta_udf.h
+++ b/fs/udf/osta_udf.h
@@ -65,30 +65,26 @@
#define IS_DF_HARD_WRITE_PROTECT 0x01
#define IS_DF_SOFT_WRITE_PROTECT 0x02
-struct UDFIdentSuffix
-{
+struct UDFIdentSuffix {
__le16 UDFRevision;
uint8_t OSClass;
uint8_t OSIdentifier;
uint8_t reserved[4];
} __attribute__ ((packed));
-struct impIdentSuffix
-{
+struct impIdentSuffix {
uint8_t OSClass;
uint8_t OSIdentifier;
uint8_t reserved[6];
} __attribute__ ((packed));
-struct appIdentSuffix
-{
+struct appIdentSuffix {
uint8_t impUse[8];
} __attribute__ ((packed));
/* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */
/* Implementation Use (UDF 2.50 2.2.6.4) */
-struct logicalVolIntegrityDescImpUse
-{
+struct logicalVolIntegrityDescImpUse {
regid impIdent;
__le32 numFiles;
__le32 numDirs;
@@ -100,8 +96,7 @@ struct logicalVolIntegrityDescImpUse
/* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */
/* Implementation Use (UDF 2.50 2.2.7.2) */
-struct impUseVolDescImpUse
-{
+struct impUseVolDescImpUse {
charspec LVICharset;
dstring logicalVolIdent[128];
dstring LVInfo1[36];
@@ -111,8 +106,7 @@ struct impUseVolDescImpUse
uint8_t impUse[128];
} __attribute__ ((packed));
-struct udfPartitionMap2
-{
+struct udfPartitionMap2 {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t reserved1[2];
@@ -122,8 +116,7 @@ struct udfPartitionMap2
} __attribute__ ((packed));
/* Virtual Partition Map (UDF 2.50 2.2.8) */
-struct virtualPartitionMap
-{
+struct virtualPartitionMap {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t reserved1[2];
@@ -134,24 +127,22 @@ struct virtualPartitionMap
} __attribute__ ((packed));
/* Sparable Partition Map (UDF 2.50 2.2.9) */
-struct sparablePartitionMap
-{
- uint8_t partitionMapType;
- uint8_t partitionMapLength;
- uint8_t reserved1[2];
- regid partIdent;
- __le16 volSeqNum;
- __le16 partitionNum;
- __le16 packetLength;
- uint8_t numSparingTables;
- uint8_t reserved2[1];
- __le32 sizeSparingTable;
- __le32 locSparingTable[4];
+struct sparablePartitionMap {
+ uint8_t partitionMapType;
+ uint8_t partitionMapLength;
+ uint8_t reserved1[2];
+ regid partIdent;
+ __le16 volSeqNum;
+ __le16 partitionNum;
+ __le16 packetLength;
+ uint8_t numSparingTables;
+ uint8_t reserved2[1];
+ __le32 sizeSparingTable;
+ __le32 locSparingTable[4];
} __attribute__ ((packed));
/* Metadata Partition Map (UDF 2.4.0 2.2.10) */
-struct metadataPartitionMap
-{
+struct metadataPartitionMap {
uint8_t partitionMapType;
uint8_t partitionMapLength;
uint8_t reserved1[2];
@@ -168,18 +159,16 @@ struct metadataPartitionMap
} __attribute__ ((packed));
/* Virtual Allocation Table (UDF 1.5 2.2.10) */
-struct virtualAllocationTable15
-{
+struct virtualAllocationTable15 {
__le32 VirtualSector[0];
regid vatIdent;
__le32 previousVATICBLoc;
-} __attribute__ ((packed));
+} __attribute__ ((packed));
#define ICBTAG_FILE_TYPE_VAT15 0x00U
/* Virtual Allocation Table (UDF 2.50 2.2.11) */
-struct virtualAllocationTable20
-{
+struct virtualAllocationTable20 {
__le16 lengthHeader;
__le16 lengthImpUse;
dstring logicalVolIdent[128];
@@ -197,14 +186,12 @@ struct virtualAllocationTable20
#define ICBTAG_FILE_TYPE_VAT20 0xF8U
/* Sparing Table (UDF 2.50 2.2.12) */
-struct sparingEntry
-{
+struct sparingEntry {
__le32 origLocation;
__le32 mappedLocation;
} __attribute__ ((packed));
-struct sparingTable
-{
+struct sparingTable {
tag descTag;
regid sparingIdent;
__le16 reallocationTableLen;
@@ -220,8 +207,7 @@ struct sparingTable
#define ICBTAG_FILE_TYPE_BITMAP 0xFC
/* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */
-struct allocDescImpUse
-{
+struct allocDescImpUse {
__le16 flags;
uint8_t impUse[4];
} __attribute__ ((packed));
@@ -233,15 +219,13 @@ struct allocDescImpUse
/* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */
/* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */
-struct freeEaSpace
-{
+struct freeEaSpace {
__le16 headerChecksum;
uint8_t freeEASpace[0];
} __attribute__ ((packed));
/* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */
-struct DVDCopyrightImpUse
-{
+struct DVDCopyrightImpUse {
__le16 headerChecksum;
uint8_t CGMSInfo;
uint8_t dataType;
@@ -250,8 +234,7 @@ struct DVDCopyrightImpUse
/* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */
/* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */
-struct freeAppEASpace
-{
+struct freeAppEASpace {
__le16 headerChecksum;
uint8_t freeEASpace[0];
} __attribute__ ((packed));
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index 467a26171cd9..aaab24c8c498 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -14,7 +14,7 @@
*
* HISTORY
*
- * 12/06/98 blf Created file.
+ * 12/06/98 blf Created file.
*
*/
@@ -28,12 +28,12 @@
#include <linux/slab.h>
#include <linux/buffer_head.h>
-inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
- if (partition >= UDF_SB_NUMPARTS(sb))
- {
+ if (partition >= UDF_SB_NUMPARTS(sb)) {
udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
- block, partition, offset);
+ block, partition, offset);
return 0xFFFFFFFF;
}
if (UDF_SB_PARTFUNC(sb, partition))
@@ -42,7 +42,8 @@ inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t
return UDF_SB_PARTROOT(sb, partition) + block + offset;
}
-uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
struct buffer_head *bh = NULL;
uint32_t newblock;
@@ -51,31 +52,26 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t
index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
- if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
- {
+ if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries) {
udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
- block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
+ block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
return 0xFFFFFFFF;
}
- if (block >= index)
- {
+ if (block >= index) {
block -= index;
newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
index = block % (sb->s_blocksize / sizeof(uint32_t));
- }
- else
- {
+ } else {
newblock = 0;
index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
}
loc = udf_block_map(UDF_SB_VAT(sb), newblock);
- if (!(bh = sb_bread(sb, loc)))
- {
+ if (!(bh = sb_bread(sb, loc))) {
udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
- sb, block, partition, loc, index);
+ sb, block, partition, loc, index);
return 0xFFFFFFFF;
}
@@ -83,50 +79,49 @@ uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t
brelse(bh);
- if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
- {
+ if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition) {
udf_debug("recursive call to udf_get_pblock!\n");
return 0xFFFFFFFF;
}
- return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+ return udf_get_pblock(sb, loc,
+ UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum,
+ offset);
}
-inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+inline uint32_t udf_get_pblock_virt20(struct super_block * sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
return udf_get_pblock_virt15(sb, block, partition, offset);
}
-uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_spar15(struct super_block * sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
int i;
struct sparingTable *st = NULL;
uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
- for (i=0; i<4; i++)
- {
- if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
- {
+ for (i = 0; i < 4; i++) {
+ if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL) {
st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
break;
}
}
- if (st)
- {
- for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++)
- {
- if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
+ if (st) {
+ for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
+ if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0) {
break;
- else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
- {
+ } else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet) {
return le32_to_cpu(st->mapEntry[i].mappedLocation) +
((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
- }
- else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
+ } else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet) {
break;
+ }
}
}
+
return UDF_SB_PARTROOT(sb,partition) + block + offset;
}
@@ -138,18 +133,14 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
uint32_t packet;
int i, j, k, l;
- for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
- {
+ for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
if (old_block > UDF_SB_PARTROOT(sb,i) &&
- old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
- {
+ old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i)) {
sdata = &UDF_SB_TYPESPAR(sb,i);
packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
- for (j=0; j<4; j++)
- {
- if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
- {
+ for (j = 0; j < 4; j++) {
+ if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) {
st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
break;
}
@@ -158,14 +149,10 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
if (!st)
return 1;
- for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++)
- {
- if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
- {
- for (; j<4; j++)
- {
- if (sdata->s_spar_map[j])
- {
+ for (k = 0; k < le16_to_cpu(st->reallocationTableLen); k++) {
+ if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF) {
+ for (; j < 4; j++) {
+ if (sdata->s_spar_map[j]) {
st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
st->mapEntry[k].origLocation = cpu_to_le32(packet);
udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
@@ -175,28 +162,23 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
return 0;
- }
- else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
- {
+ } else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet) {
*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
return 0;
- }
- else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
+ } else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet) {
break;
+ }
}
- for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++)
- {
- if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
- {
- for (; j<4; j++)
- {
- if (sdata->s_spar_map[j])
- {
+
+ for (l = k; l < le16_to_cpu(st->reallocationTableLen); l++) {
+ if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF) {
+ for (; j < 4; j++) {
+ if (sdata->s_spar_map[j]) {
st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
mapEntry = st->mapEntry[l];
mapEntry.origLocation = cpu_to_le32(packet);
- memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
+ memmove(&st->mapEntry[k + 1], &st->mapEntry[k], (l - k) * sizeof(struct sparingEntry));
st->mapEntry[k] = mapEntry;
udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
mark_buffer_dirty(sdata->s_spar_map[j]);
@@ -207,11 +189,12 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
return 0;
}
}
+
return 1;
- }
+ } /* if old_block */
}
- if (i == UDF_SB_NUMPARTS(sb))
- {
+
+ if (i == UDF_SB_NUMPARTS(sb)) {
/* outside of partitions */
/* for now, fail =) */
return 1;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 6658afb41cc7..7b30964665db 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -38,7 +38,7 @@
* 12/20/98 find the free space bitmap (if it exists)
*/
-#include "udfdecl.h"
+#include "udfdecl.h"
#include <linux/blkdev.h>
#include <linux/slab.h>
@@ -80,12 +80,15 @@ static int udf_remount_fs(struct super_block *, int *, char *);
static int udf_check_valid(struct super_block *, int, int);
static int udf_vrs(struct super_block *sb, int silent);
static int udf_load_partition(struct super_block *, kernel_lb_addr *);
-static int udf_load_logicalvol(struct super_block *, struct buffer_head *, kernel_lb_addr *);
+static int udf_load_logicalvol(struct super_block *, struct buffer_head *,
+ kernel_lb_addr *);
static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad);
static void udf_find_anchor(struct super_block *);
-static int udf_find_fileset(struct super_block *, kernel_lb_addr *, kernel_lb_addr *);
+static int udf_find_fileset(struct super_block *, kernel_lb_addr *,
+ kernel_lb_addr *);
static void udf_load_pvoldesc(struct super_block *, struct buffer_head *);
-static void udf_load_fileset(struct super_block *, struct buffer_head *, kernel_lb_addr *);
+static void udf_load_fileset(struct super_block *, struct buffer_head *,
+ kernel_lb_addr *);
static void udf_load_partdesc(struct super_block *, struct buffer_head *);
static void udf_open_lvid(struct super_block *);
static void udf_close_lvid(struct super_block *);
@@ -94,7 +97,8 @@ static int udf_statfs(struct dentry *, struct kstatfs *);
/* UDF filesystem type */
static int udf_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+ int flags, const char *dev_name, void *data,
+ struct vfsmount *mnt)
{
return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super, mnt);
}
@@ -107,7 +111,7 @@ static struct file_system_type udf_fstype = {
.fs_flags = FS_REQUIRES_DEV,
};
-static struct kmem_cache * udf_inode_cachep;
+static struct kmem_cache *udf_inode_cachep;
static struct inode *udf_alloc_inode(struct super_block *sb)
{
@@ -130,9 +134,9 @@ static void udf_destroy_inode(struct inode *inode)
kmem_cache_free(udf_inode_cachep, UDF_I(inode));
}
-static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
+static void init_once(void *foo, struct kmem_cache *cachep, unsigned long flags)
{
- struct udf_inode_info *ei = (struct udf_inode_info *) foo;
+ struct udf_inode_info *ei = (struct udf_inode_info *)foo;
ei->i_ext.i_data = NULL;
inode_init_once(&ei->vfs_inode);
@@ -142,10 +146,10 @@ static int init_inodecache(void)
{
udf_inode_cachep = kmem_cache_create("udf_inode_cache",
sizeof(struct udf_inode_info),
- 0, (SLAB_RECLAIM_ACCOUNT|
- SLAB_MEM_SPREAD),
- init_once, NULL);
- if (udf_inode_cachep == NULL)
+ 0, (SLAB_RECLAIM_ACCOUNT |
+ SLAB_MEM_SPREAD),
+ init_once);
+ if (!udf_inode_cachep)
return -ENOMEM;
return 0;
}
@@ -157,19 +161,18 @@ static void destroy_inodecache(void)
/* Superblock operations */
static const struct super_operations udf_sb_ops = {
- .alloc_inode = udf_alloc_inode,
- .destroy_inode = udf_destroy_inode,
- .write_inode = udf_write_inode,
- .delete_inode = udf_delete_inode,
- .clear_inode = udf_clear_inode,
- .put_super = udf_put_super,
- .write_super = udf_write_super,
- .statfs = udf_statfs,
- .remount_fs = udf_remount_fs,
+ .alloc_inode = udf_alloc_inode,
+ .destroy_inode = udf_destroy_inode,
+ .write_inode = udf_write_inode,
+ .delete_inode = udf_delete_inode,
+ .clear_inode = udf_clear_inode,
+ .put_super = udf_put_super,
+ .write_super = udf_write_super,
+ .statfs = udf_statfs,
+ .remount_fs = udf_remount_fs,
};
-struct udf_options
-{
+struct udf_options {
unsigned char novrs;
unsigned int blocksize;
unsigned int session;
@@ -189,15 +192,19 @@ struct udf_options
static int __init init_udf_fs(void)
{
int err;
+
err = init_inodecache();
if (err)
goto out1;
err = register_filesystem(&udf_fstype);
if (err)
goto out;
+
return 0;
+
out:
destroy_inodecache();
+
out1:
return err;
}
@@ -235,7 +242,7 @@ module_exit(exit_udf_fs)
*
* The remaining are for debugging and disaster recovery:
*
- * novrs Skip volume sequence recognition
+ * novrs Skip volume sequence recognition
*
* The following expect a offset from 0.
*
@@ -275,36 +282,35 @@ enum {
};
static match_table_t tokens = {
- {Opt_novrs, "novrs"},
- {Opt_nostrict, "nostrict"},
- {Opt_bs, "bs=%u"},
- {Opt_unhide, "unhide"},
- {Opt_undelete, "undelete"},
- {Opt_noadinicb, "noadinicb"},
- {Opt_adinicb, "adinicb"},
- {Opt_shortad, "shortad"},
- {Opt_longad, "longad"},
- {Opt_uforget, "uid=forget"},
- {Opt_uignore, "uid=ignore"},
- {Opt_gforget, "gid=forget"},
- {Opt_gignore, "gid=ignore"},
- {Opt_gid, "gid=%u"},
- {Opt_uid, "uid=%u"},
- {Opt_umask, "umask=%o"},
- {Opt_session, "session=%u"},
- {Opt_lastblock, "lastblock=%u"},
- {Opt_anchor, "anchor=%u"},
- {Opt_volume, "volume=%u"},
- {Opt_partition, "partition=%u"},
- {Opt_fileset, "fileset=%u"},
- {Opt_rootdir, "rootdir=%u"},
- {Opt_utf8, "utf8"},
- {Opt_iocharset, "iocharset=%s"},
- {Opt_err, NULL}
+ {Opt_novrs, "novrs"},
+ {Opt_nostrict, "nostrict"},
+ {Opt_bs, "bs=%u"},
+ {Opt_unhide, "unhide"},
+ {Opt_undelete, "undelete"},
+ {Opt_noadinicb, "noadinicb"},
+ {Opt_adinicb, "adinicb"},
+ {Opt_shortad, "shortad"},
+ {Opt_longad, "longad"},
+ {Opt_uforget, "uid=forget"},
+ {Opt_uignore, "uid=ignore"},
+ {Opt_gforget, "gid=forget"},
+ {Opt_gignore, "gid=ignore"},
+ {Opt_gid, "gid=%u"},
+ {Opt_uid, "uid=%u"},
+ {Opt_umask, "umask=%o"},
+ {Opt_session, "session=%u"},
+ {Opt_lastblock, "lastblock=%u"},
+ {Opt_anchor, "anchor=%u"},
+ {Opt_volume, "volume=%u"},
+ {Opt_partition, "partition=%u"},
+ {Opt_fileset, "fileset=%u"},
+ {Opt_rootdir, "rootdir=%u"},
+ {Opt_utf8, "utf8"},
+ {Opt_iocharset, "iocharset=%s"},
+ {Opt_err, NULL}
};
-static int
-udf_parse_options(char *options, struct udf_options *uopt)
+static int udf_parse_options(char *options, struct udf_options *uopt)
{
char *p;
int option;
@@ -323,145 +329,143 @@ udf_parse_options(char *options, struct udf_options *uopt)
if (!options)
return 1;
- while ((p = strsep(&options, ",")) != NULL)
- {
+ while ((p = strsep(&options, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int token;
if (!*p)
continue;
token = match_token(p, tokens, args);
- switch (token)
- {
- case Opt_novrs:
- uopt->novrs = 1;
- case Opt_bs:
- if (match_int(&args[0], &option))
- return 0;
- uopt->blocksize = option;
- break;
- case Opt_unhide:
- uopt->flags |= (1 << UDF_FLAG_UNHIDE);
- break;
- case Opt_undelete:
- uopt->flags |= (1 << UDF_FLAG_UNDELETE);
- break;
- case Opt_noadinicb:
- uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
- break;
- case Opt_adinicb:
- uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
- break;
- case Opt_shortad:
- uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
- break;
- case Opt_longad:
- uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
- break;
- case Opt_gid:
- if (match_int(args, &option))
- return 0;
- uopt->gid = option;
- break;
- case Opt_uid:
- if (match_int(args, &option))
- return 0;
- uopt->uid = option;
- break;
- case Opt_umask:
- if (match_octal(args, &option))
- return 0;
- uopt->umask = option;
- break;
- case Opt_nostrict:
- uopt->flags &= ~(1 << UDF_FLAG_STRICT);
- break;
- case Opt_session:
- if (match_int(args, &option))
- return 0;
- uopt->session = option;
- break;
- case Opt_lastblock:
- if (match_int(args, &option))
- return 0;
- uopt->lastblock = option;
- break;
- case Opt_anchor:
- if (match_int(args, &option))
- return 0;
- uopt->anchor = option;
- break;
- case Opt_volume:
- if (match_int(args, &option))
- return 0;
- uopt->volume = option;
- break;
- case Opt_partition:
- if (match_int(args, &option))
- return 0;
- uopt->partition = option;
- break;
- case Opt_fileset:
- if (match_int(args, &option))
- return 0;
- uopt->fileset = option;
- break;
- case Opt_rootdir:
- if (match_int(args, &option))
- return 0;
- uopt->rootdir = option;
- break;
- case Opt_utf8:
- uopt->flags |= (1 << UDF_FLAG_UTF8);
- break;
+ switch (token) {
+ case Opt_novrs:
+ uopt->novrs = 1;
+ case Opt_bs:
+ if (match_int(&args[0], &option))
+ return 0;
+ uopt->blocksize = option;
+ break;
+ case Opt_unhide:
+ uopt->flags |= (1 << UDF_FLAG_UNHIDE);
+ break;
+ case Opt_undelete:
+ uopt->flags |= (1 << UDF_FLAG_UNDELETE);
+ break;
+ case Opt_noadinicb:
+ uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB);
+ break;
+ case Opt_adinicb:
+ uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB);
+ break;
+ case Opt_shortad:
+ uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD);
+ break;
+ case Opt_longad:
+ uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD);
+ break;
+ case Opt_gid:
+ if (match_int(args, &option))
+ return 0;
+ uopt->gid = option;
+ break;
+ case Opt_uid:
+ if (match_int(args, &option))
+ return 0;
+ uopt->uid = option;
+ break;
+ case Opt_umask:
+ if (match_octal(args, &option))
+ return 0;
+ uopt->umask = option;
+ break;
+ case Opt_nostrict:
+ uopt->flags &= ~(1 << UDF_FLAG_STRICT);
+ break;
+ case Opt_session:
+ if (match_int(args, &option))
+ return 0;
+ uopt->session = option;
+ break;
+ case Opt_lastblock:
+ if (match_int(args, &option))
+ return 0;
+ uopt->lastblock = option;
+ break;
+ case Opt_anchor:
+ if (match_int(args, &option))
+ return 0;
+ uopt->anchor = option;
+ break;
+ case Opt_volume:
+ if (match_int(args, &option))
+ return 0;
+ uopt->volume = option;
+ break;
+ case Opt_partition:
+ if (match_int(args, &option))
+ return 0;
+ uopt->partition = option;
+ break;
+ case Opt_fileset:
+ if (match_int(args, &option))
+ return 0;
+ uopt->fileset = option;
+ break;
+ case Opt_rootdir:
+ if (match_int(args, &option))
+ return 0;
+ uopt->rootdir = option;
+ break;
+ case Opt_utf8:
+ uopt->flags |= (1 << UDF_FLAG_UTF8);
+ break;
#ifdef CONFIG_UDF_NLS
- case Opt_iocharset:
- uopt->nls_map = load_nls(args[0].from);
- uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
- break;
+ case Opt_iocharset:
+ uopt->nls_map = load_nls(args[0].from);
+ uopt->flags |= (1 << UDF_FLAG_NLS_MAP);
+ break;
#endif
- case Opt_uignore:
- uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
- break;
- case Opt_uforget:
- uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
- break;
- case Opt_gignore:
- uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
- break;
- case Opt_gforget:
- uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
- break;
- default:
- printk(KERN_ERR "udf: bad mount option \"%s\" "
- "or missing value\n", p);
+ case Opt_uignore:
+ uopt->flags |= (1 << UDF_FLAG_UID_IGNORE);
+ break;
+ case Opt_uforget:
+ uopt->flags |= (1 << UDF_FLAG_UID_FORGET);
+ break;
+ case Opt_gignore:
+ uopt->flags |= (1 << UDF_FLAG_GID_IGNORE);
+ break;
+ case Opt_gforget:
+ uopt->flags |= (1 << UDF_FLAG_GID_FORGET);
+ break;
+ default:
+ printk(KERN_ERR "udf: bad mount option \"%s\" "
+ "or missing value\n", p);
return 0;
}
}
return 1;
}
-void
-udf_write_super(struct super_block *sb)
+void udf_write_super(struct super_block *sb)
{
lock_kernel();
+
if (!(sb->s_flags & MS_RDONLY))
udf_open_lvid(sb);
sb->s_dirt = 0;
+
unlock_kernel();
}
-static int
-udf_remount_fs(struct super_block *sb, int *flags, char *options)
+static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
{
struct udf_options uopt;
- uopt.flags = UDF_SB(sb)->s_flags ;
- uopt.uid = UDF_SB(sb)->s_uid ;
- uopt.gid = UDF_SB(sb)->s_gid ;
- uopt.umask = UDF_SB(sb)->s_umask ;
+ uopt.flags = UDF_SB(sb)->s_flags;
+ uopt.uid = UDF_SB(sb)->s_uid;
+ uopt.gid = UDF_SB(sb)->s_gid;
+ uopt.umask = UDF_SB(sb)->s_umask;
- if ( !udf_parse_options(options, &uopt) )
+ if (!udf_parse_options(options, &uopt))
return -EINVAL;
UDF_SB(sb)->s_flags = uopt.flags;
@@ -512,27 +516,26 @@ udf_remount_fs(struct super_block *sb, int *flags, char *options)
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-static int
-udf_set_blocksize(struct super_block *sb, int bsize)
+static int udf_set_blocksize(struct super_block *sb, int bsize)
{
if (!sb_min_blocksize(sb, bsize)) {
udf_debug("Bad block size (%d)\n", bsize);
printk(KERN_ERR "udf: bad block size (%d)\n", bsize);
return 0;
}
+
return sb->s_blocksize;
}
-static int
-udf_vrs(struct super_block *sb, int silent)
+static int udf_vrs(struct super_block *sb, int silent)
{
struct volStructDesc *vsd = NULL;
int sector = 32768;
int sectorsize;
struct buffer_head *bh = NULL;
- int iso9660=0;
- int nsr02=0;
- int nsr03=0;
+ int iso9660 = 0;
+ int nsr02 = 0;
+ int nsr03 = 0;
/* Block size must be a multiple of 512 */
if (sb->s_blocksize & 511)
@@ -546,10 +549,9 @@ udf_vrs(struct super_block *sb, int silent)
sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits);
udf_debug("Starting at sector %u (%ld byte sectors)\n",
- (sector >> sb->s_blocksize_bits), sb->s_blocksize);
+ (sector >> sb->s_blocksize_bits), sb->s_blocksize);
/* Process the sequence (if applicable) */
- for (;!nsr02 && !nsr03; sector += sectorsize)
- {
+ for (; !nsr02 && !nsr03; sector += sectorsize) {
/* Read a block */
bh = udf_tread(sb, sector >> sb->s_blocksize_bits);
if (!bh)
@@ -557,52 +559,45 @@ udf_vrs(struct super_block *sb, int silent)
/* Look for ISO descriptors */
vsd = (struct volStructDesc *)(bh->b_data +
- (sector & (sb->s_blocksize - 1)));
+ (sector & (sb->s_blocksize - 1)));
- if (vsd->stdIdent[0] == 0)
- {
+ if (vsd->stdIdent[0] == 0) {
brelse(bh);
break;
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN))
- {
+ } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) {
iso9660 = sector;
- switch (vsd->structType)
- {
- case 0:
- udf_debug("ISO9660 Boot Record found\n");
- break;
- case 1:
- udf_debug("ISO9660 Primary Volume Descriptor found\n");
- break;
- case 2:
- udf_debug("ISO9660 Supplementary Volume Descriptor found\n");
- break;
- case 3:
- udf_debug("ISO9660 Volume Partition Descriptor found\n");
- break;
- case 255:
- udf_debug("ISO9660 Volume Descriptor Set Terminator found\n");
- break;
- default:
- udf_debug("ISO9660 VRS (%u) found\n", vsd->structType);
- break;
+ switch (vsd->structType) {
+ case 0:
+ udf_debug("ISO9660 Boot Record found\n");
+ break;
+ case 1:
+ udf_debug
+ ("ISO9660 Primary Volume Descriptor found\n");
+ break;
+ case 2:
+ udf_debug
+ ("ISO9660 Supplementary Volume Descriptor found\n");
+ break;
+ case 3:
+ udf_debug
+ ("ISO9660 Volume Partition Descriptor found\n");
+ break;
+ case 255:
+ udf_debug
+ ("ISO9660 Volume Descriptor Set Terminator found\n");
+ break;
+ default:
+ udf_debug("ISO9660 VRS (%u) found\n",
+ vsd->structType);
+ break;
}
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN))
- {
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN))
- {
+ } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) {
+ } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN)) {
brelse(bh);
break;
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN))
- {
+ } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) {
nsr02 = sector;
- }
- else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN))
- {
+ } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) {
nsr03 = sector;
}
brelse(bh);
@@ -635,8 +630,7 @@ udf_vrs(struct super_block *sb, int silent)
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-static void
-udf_find_anchor(struct super_block *sb)
+static void udf_find_anchor(struct super_block *sb)
{
int lastblock = UDF_SB_LASTBLOCK(sb);
struct buffer_head *bh = NULL;
@@ -644,8 +638,7 @@ udf_find_anchor(struct super_block *sb)
uint32_t location;
int i;
- if (lastblock)
- {
+ if (lastblock) {
int varlastblock = udf_variable_to_fixed(lastblock);
int last[] = { lastblock, lastblock - 2,
lastblock - 150, lastblock - 152,
@@ -663,74 +656,54 @@ udf_find_anchor(struct super_block *sb)
* however, if the disc isn't closed, it could be 512 */
for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) {
- if (last[i] < 0 || !(bh = sb_bread(sb, last[i])))
- {
+ if (last[i] < 0 || !(bh = sb_bread(sb, last[i]))) {
ident = location = 0;
- }
- else
- {
+ } else {
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
brelse(bh);
}
- if (ident == TAG_IDENT_AVDP)
- {
- if (location == last[i] - UDF_SB_SESSION(sb))
- {
+ if (ident == TAG_IDENT_AVDP) {
+ if (location == last[i] - UDF_SB_SESSION(sb)) {
lastblock = UDF_SB_ANCHOR(sb)[0] = last[i] - UDF_SB_SESSION(sb);
UDF_SB_ANCHOR(sb)[1] = last[i] - 256 - UDF_SB_SESSION(sb);
- }
- else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb))
- {
+ } else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) {
UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb);
UDF_SB_ANCHOR(sb)[1] = lastblock - 256 - UDF_SB_SESSION(sb);
- }
- else
+ } else {
udf_debug("Anchor found at block %d, location mismatch %d.\n",
- last[i], location);
- }
- else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE)
- {
+ last[i], location);
+ }
+ } else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE) {
lastblock = last[i];
UDF_SB_ANCHOR(sb)[3] = 512;
- }
- else
- {
- if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256)))
- {
+ } else {
+ if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256))) {
ident = location = 0;
- }
- else
- {
+ } else {
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
brelse(bh);
}
-
+
if (ident == TAG_IDENT_AVDP &&
- location == last[i] - 256 - UDF_SB_SESSION(sb))
- {
+ location == last[i] - 256 - UDF_SB_SESSION(sb)) {
lastblock = last[i];
UDF_SB_ANCHOR(sb)[1] = last[i] - 256;
- }
- else
- {
- if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb))))
- {
+ } else {
+ if (last[i] < 312 + UDF_SB_SESSION(sb) ||
+ !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb)))) {
ident = location = 0;
- }
- else
- {
+ } else {
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
brelse(bh);
}
-
+
if (ident == TAG_IDENT_AVDP &&
- location == udf_variable_to_fixed(last[i]) - 256)
- {
+ location == udf_variable_to_fixed(last[i]) - 256) {
UDF_SET_FLAG(sb, UDF_FLAG_VARCONV);
lastblock = udf_variable_to_fixed(last[i]);
UDF_SB_ANCHOR(sb)[1] = lastblock - 256;
@@ -740,11 +713,9 @@ udf_find_anchor(struct super_block *sb)
}
}
- if (!lastblock)
- {
+ if (!lastblock) {
/* We havn't found the lastblock. check 312 */
- if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb))))
- {
+ if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb)))) {
ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent);
location = le32_to_cpu(((tag *)bh->b_data)->tagLocation);
brelse(bh);
@@ -755,19 +726,14 @@ udf_find_anchor(struct super_block *sb)
}
for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) {
- if (UDF_SB_ANCHOR(sb)[i])
- {
- if (!(bh = udf_read_tagged(sb,
- UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
- {
+ if (UDF_SB_ANCHOR(sb)[i]) {
+ if (!(bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i],
+ UDF_SB_ANCHOR(sb)[i], &ident))) {
UDF_SB_ANCHOR(sb)[i] = 0;
- }
- else
- {
+ } else {
brelse(bh);
- if ((ident != TAG_IDENT_AVDP) && (i ||
- (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE)))
- {
+ if ((ident != TAG_IDENT_AVDP) &&
+ (i || (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE))) {
UDF_SB_ANCHOR(sb)[i] = 0;
}
}
@@ -777,89 +743,78 @@ udf_find_anchor(struct super_block *sb)
UDF_SB_LASTBLOCK(sb) = lastblock;
}
-static int
-udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root)
+static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root)
{
struct buffer_head *bh = NULL;
long lastblock;
uint16_t ident;
if (fileset->logicalBlockNum != 0xFFFFFFFF ||
- fileset->partitionReferenceNum != 0xFFFF)
- {
+ fileset->partitionReferenceNum != 0xFFFF) {
bh = udf_read_ptagged(sb, *fileset, 0, &ident);
- if (!bh)
+ if (!bh) {
return 1;
- else if (ident != TAG_IDENT_FSD)
- {
+ } else if (ident != TAG_IDENT_FSD) {
brelse(bh);
return 1;
}
-
+
}
- if (!bh) /* Search backwards through the partitions */
- {
+ if (!bh) { /* Search backwards through the partitions */
kernel_lb_addr newfileset;
+/* --> cvg: FIXME - is it reasonable? */
return 1;
-
- for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1;
- (newfileset.partitionReferenceNum != 0xFFFF &&
- fileset->logicalBlockNum == 0xFFFFFFFF &&
- fileset->partitionReferenceNum == 0xFFFF);
- newfileset.partitionReferenceNum--)
- {
+
+ for (newfileset.partitionReferenceNum = UDF_SB_NUMPARTS(sb) - 1;
+ (newfileset.partitionReferenceNum != 0xFFFF &&
+ fileset->logicalBlockNum == 0xFFFFFFFF &&
+ fileset->partitionReferenceNum == 0xFFFF);
+ newfileset.partitionReferenceNum--) {
lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum);
newfileset.logicalBlockNum = 0;
- do
- {
+ do {
bh = udf_read_ptagged(sb, newfileset, 0, &ident);
- if (!bh)
- {
- newfileset.logicalBlockNum ++;
+ if (!bh) {
+ newfileset.logicalBlockNum++;
continue;
}
- switch (ident)
+ switch (ident) {
+ case TAG_IDENT_SBD:
{
- case TAG_IDENT_SBD:
- {
- struct spaceBitmapDesc *sp;
- sp = (struct spaceBitmapDesc *)bh->b_data;
- newfileset.logicalBlockNum += 1 +
- ((le32_to_cpu(sp->numOfBytes) + sizeof(struct spaceBitmapDesc) - 1)
- >> sb->s_blocksize_bits);
- brelse(bh);
- break;
- }
- case TAG_IDENT_FSD:
- {
- *fileset = newfileset;
- break;
- }
- default:
- {
- newfileset.logicalBlockNum ++;
- brelse(bh);
- bh = NULL;
- break;
- }
+ struct spaceBitmapDesc *sp;
+ sp = (struct spaceBitmapDesc *)bh->b_data;
+ newfileset.logicalBlockNum += 1 +
+ ((le32_to_cpu(sp->numOfBytes) +
+ sizeof(struct spaceBitmapDesc) - 1)
+ >> sb->s_blocksize_bits);
+ brelse(bh);
+ break;
}
- }
- while (newfileset.logicalBlockNum < lastblock &&
- fileset->logicalBlockNum == 0xFFFFFFFF &&
- fileset->partitionReferenceNum == 0xFFFF);
+ case TAG_IDENT_FSD:
+ *fileset = newfileset;
+ break;
+ default:
+ newfileset.logicalBlockNum++;
+ brelse(bh);
+ bh = NULL;
+ break;
+ }
+ } while (newfileset.logicalBlockNum < lastblock &&
+ fileset->logicalBlockNum == 0xFFFFFFFF &&
+ fileset->partitionReferenceNum == 0xFFFF);
}
}
if ((fileset->logicalBlockNum != 0xFFFFFFFF ||
- fileset->partitionReferenceNum != 0xFFFF) && bh)
- {
+ fileset->partitionReferenceNum != 0xFFFF) && bh) {
udf_debug("Fileset at block=%d, partition=%d\n",
- fileset->logicalBlockNum, fileset->partitionReferenceNum);
+ fileset->logicalBlockNum,
+ fileset->partitionReferenceNum);
UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum;
udf_load_fileset(sb, bh, root);
@@ -869,8 +824,7 @@ udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr
return 1;
}
-static void
-udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
+static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
{
struct primaryVolDesc *pvoldesc;
time_t recording;
@@ -880,37 +834,34 @@ udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh)
pvoldesc = (struct primaryVolDesc *)bh->b_data;
- if ( udf_stamp_to_time(&recording, &recording_usec,
- lets_to_cpu(pvoldesc->recordingDateAndTime)) )
- {
+ if (udf_stamp_to_time(&recording, &recording_usec,
+ lets_to_cpu(pvoldesc->recordingDateAndTime))) {
kernel_timestamp ts;
ts = lets_to_cpu(pvoldesc->recordingDateAndTime);
udf_debug("recording time %ld/%ld, %04u/%02u/%02u %02u:%02u (%x)\n",
- recording, recording_usec,
- ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone);
+ recording, recording_usec,
+ ts.year, ts.month, ts.day, ts.hour,
+ ts.minute, ts.typeAndTimezone);
UDF_SB_RECORDTIME(sb).tv_sec = recording;
UDF_SB_RECORDTIME(sb).tv_nsec = recording_usec * 1000;
}
- if ( !udf_build_ustr(&instr, pvoldesc->volIdent, 32) )
- {
- if (udf_CS0toUTF8(&outstr, &instr))
- {
- strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name,
+ if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) {
+ if (udf_CS0toUTF8(&outstr, &instr)) {
+ strncpy(UDF_SB_VOLIDENT(sb), outstr.u_name,
outstr.u_len > 31 ? 31 : outstr.u_len);
udf_debug("volIdent[] = '%s'\n", UDF_SB_VOLIDENT(sb));
}
}
- if ( !udf_build_ustr(&instr, pvoldesc->volSetIdent, 128) )
- {
+ if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) {
if (udf_CS0toUTF8(&outstr, &instr))
udf_debug("volSetIdent[] = '%s'\n", outstr.u_name);
}
}
-static void
-udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr *root)
+static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh,
+ kernel_lb_addr *root)
{
struct fileSetDesc *fset;
@@ -920,24 +871,21 @@ udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr
UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum);
- udf_debug("Rootdir at block=%d, partition=%d\n",
- root->logicalBlockNum, root->partitionReferenceNum);
+ udf_debug("Rootdir at block=%d, partition=%d\n",
+ root->logicalBlockNum, root->partitionReferenceNum);
}
-static void
-udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
+static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
{
struct partitionDesc *p;
int i;
p = (struct partitionDesc *)bh->b_data;
- for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
- {
- udf_debug("Searching map: (%d == %d)\n",
- UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
- if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber))
- {
+ for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
+ udf_debug("Searching map: (%d == %d)\n",
+ UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber));
+ if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber)) {
UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */
UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation);
if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_READ_ONLY)
@@ -950,79 +898,76 @@ udf_load_partdesc(struct super_block *sb, struct buffer_head *bh)
UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_OVERWRITABLE;
if (!strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) ||
- !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03))
- {
+ !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) {
struct partitionHeaderDesc *phd;
phd = (struct partitionHeaderDesc *)(p->partitionContentsUse);
- if (phd->unallocSpaceTable.extLength)
- {
- kernel_lb_addr loc = { le32_to_cpu(phd->unallocSpaceTable.extPosition), i };
+ if (phd->unallocSpaceTable.extLength) {
+ kernel_lb_addr loc = {
+ .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition),
+ .partitionReferenceNum = i,
+ };
UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table =
udf_iget(sb, loc);
UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE;
udf_debug("unallocSpaceTable (part %d) @ %ld\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino);
+ i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino);
}
- if (phd->unallocSpaceBitmap.extLength)
- {
+ if (phd->unallocSpaceBitmap.extLength) {
UDF_SB_ALLOC_BITMAP(sb, i, s_uspace);
- if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL)
- {
+ if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL) {
UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extLength =
le32_to_cpu(phd->unallocSpaceBitmap.extLength);
UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition =
le32_to_cpu(phd->unallocSpaceBitmap.extPosition);
UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP;
udf_debug("unallocSpaceBitmap (part %d) @ %d\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition);
+ i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition);
}
}
if (phd->partitionIntegrityTable.extLength)
udf_debug("partitionIntegrityTable (part %d)\n", i);
- if (phd->freedSpaceTable.extLength)
- {
- kernel_lb_addr loc = { le32_to_cpu(phd->freedSpaceTable.extPosition), i };
+ if (phd->freedSpaceTable.extLength) {
+ kernel_lb_addr loc = {
+ .logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition),
+ .partitionReferenceNum = i,
+ };
UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table =
udf_iget(sb, loc);
UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE;
udf_debug("freedSpaceTable (part %d) @ %ld\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino);
+ i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino);
}
- if (phd->freedSpaceBitmap.extLength)
- {
+ if (phd->freedSpaceBitmap.extLength) {
UDF_SB_ALLOC_BITMAP(sb, i, s_fspace);
- if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL)
- {
+ if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL) {
UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extLength =
le32_to_cpu(phd->freedSpaceBitmap.extLength);
UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition =
le32_to_cpu(phd->freedSpaceBitmap.extPosition);
UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP;
udf_debug("freedSpaceBitmap (part %d) @ %d\n",
- i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition);
+ i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition);
}
}
}
break;
}
}
- if (i == UDF_SB_NUMPARTS(sb))
- {
- udf_debug("Partition (%d) not found in partition map\n", le16_to_cpu(p->partitionNumber));
- }
- else
- {
+ if (i == UDF_SB_NUMPARTS(sb)) {
+ udf_debug("Partition (%d) not found in partition map\n",
+ le16_to_cpu(p->partitionNumber));
+ } else {
udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n",
- le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
- UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
+ le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i),
+ UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i));
}
}
-static int
-udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_addr *fileset)
+static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh,
+ kernel_lb_addr *fileset)
{
struct logicalVolDesc *lvd;
int i, j, offset;
@@ -1032,37 +977,27 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
UDF_SB_ALLOC_PARTMAPS(sb, le32_to_cpu(lvd->numPartitionMaps));
- for (i=0,offset=0;
- i<UDF_SB_NUMPARTS(sb) && offset<le32_to_cpu(lvd->mapTableLength);
- i++,offset+=((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength)
- {
+ for (i = 0, offset = 0;
+ i < UDF_SB_NUMPARTS(sb) && offset < le32_to_cpu(lvd->mapTableLength);
+ i++, offset += ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength) {
type = ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType;
- if (type == 1)
- {
+ if (type == 1) {
struct genericPartitionMap1 *gpm1 = (struct genericPartitionMap1 *)&(lvd->partitionMaps[offset]);
UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15;
UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum);
UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum);
UDF_SB_PARTFUNC(sb,i) = NULL;
- }
- else if (type == 2)
- {
+ } else if (type == 2) {
struct udfPartitionMap2 *upm2 = (struct udfPartitionMap2 *)&(lvd->partitionMaps[offset]);
- if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL)))
- {
- if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150)
- {
+ if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) {
+ if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150) {
UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15;
UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt15;
- }
- else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200)
- {
+ } else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200) {
UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20;
UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt20;
}
- }
- else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE)))
- {
+ } else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) {
uint32_t loc;
uint16_t ident;
struct sparingTable *st;
@@ -1070,26 +1005,21 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15;
UDF_SB_TYPESPAR(sb,i).s_packet_len = le16_to_cpu(spm->packetLength);
- for (j=0; j<spm->numSparingTables; j++)
- {
+ for (j = 0; j < spm->numSparingTables; j++) {
loc = le32_to_cpu(spm->locSparingTable[j]);
UDF_SB_TYPESPAR(sb,i).s_spar_map[j] =
udf_read_tagged(sb, loc, loc, &ident);
- if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
- {
+ if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) {
st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,i).s_spar_map[j]->b_data;
if (ident != 0 ||
- strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
- {
+ strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) {
brelse(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]);
UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL;
}
}
}
UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15;
- }
- else
- {
+ } else {
udf_debug("Unknown ident: %s\n", upm2->partIdent.ident);
continue;
}
@@ -1097,20 +1027,20 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum);
}
udf_debug("Partition (%d:%d) type %d on volume %d\n",
- i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i));
+ i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i));
}
- if (fileset)
- {
+ if (fileset) {
long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]);
*fileset = lelb_to_cpu(la->extLocation);
udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n",
- fileset->logicalBlockNum,
- fileset->partitionReferenceNum);
+ fileset->logicalBlockNum,
+ fileset->partitionReferenceNum);
}
if (lvd->integritySeqExt.extLength)
udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt));
+
return 0;
}
@@ -1118,26 +1048,24 @@ udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_a
* udf_load_logicalvolint
*
*/
-static void
-udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
+static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
{
struct buffer_head *bh = NULL;
uint16_t ident;
while (loc.extLength > 0 &&
- (bh = udf_read_tagged(sb, loc.extLocation,
- loc.extLocation, &ident)) &&
- ident == TAG_IDENT_LVID)
- {
+ (bh = udf_read_tagged(sb, loc.extLocation,
+ loc.extLocation, &ident)) &&
+ ident == TAG_IDENT_LVID) {
UDF_SB_LVIDBH(sb) = bh;
-
+
if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength)
udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt));
-
+
if (UDF_SB_LVIDBH(sb) != bh)
brelse(bh);
loc.extLength -= sb->s_blocksize;
- loc.extLocation ++;
+ loc.extLocation++;
}
if (UDF_SB_LVIDBH(sb) != bh)
brelse(bh);
@@ -1158,15 +1086,15 @@ udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc)
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-static int
-udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_lb_addr *fileset)
+static int udf_process_sequence(struct super_block *sb, long block, long lastblock,
+ kernel_lb_addr *fileset)
{
struct buffer_head *bh = NULL;
struct udf_vds_record vds[VDS_POS_LENGTH];
struct generic_desc *gd;
struct volDescPtr *vdp;
- int done=0;
- int i,j;
+ int done = 0;
+ int i, j;
uint32_t vdsn;
uint16_t ident;
long next_s = 0, next_e = 0;
@@ -1174,93 +1102,81 @@ udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_
memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH);
/* Read the main descriptor sequence */
- for (;(!done && block <= lastblock); block++)
- {
+ for (; (!done && block <= lastblock); block++) {
bh = udf_read_tagged(sb, block, block, &ident);
- if (!bh)
+ if (!bh)
break;
/* Process each descriptor (ISO 13346 3/8.3-8.4) */
gd = (struct generic_desc *)bh->b_data;
vdsn = le32_to_cpu(gd->volDescSeqNum);
- switch (ident)
- {
- case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
- if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum)
- {
- vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
- }
- break;
- case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
- if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum)
- {
- vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
- vds[VDS_POS_VOL_DESC_PTR].block = block;
-
- vdp = (struct volDescPtr *)bh->b_data;
- next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
- next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength);
- next_e = next_e >> sb->s_blocksize_bits;
- next_e += next_s;
- }
- break;
- case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
- if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum)
- {
- vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
- }
- break;
- case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
- if (!vds[VDS_POS_PARTITION_DESC].block)
- vds[VDS_POS_PARTITION_DESC].block = block;
- break;
- case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
- if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum)
- {
- vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
- }
- break;
- case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
- if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum)
- {
- vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
- vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
- }
- break;
- case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
- vds[VDS_POS_TERMINATING_DESC].block = block;
- if (next_e)
- {
- block = next_s;
- lastblock = next_e;
- next_s = next_e = 0;
- }
- else
- done = 1;
- break;
+ switch (ident) {
+ case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */
+ if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) {
+ vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_PRIMARY_VOL_DESC].block = block;
+ }
+ break;
+ case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */
+ if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) {
+ vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn;
+ vds[VDS_POS_VOL_DESC_PTR].block = block;
+
+ vdp = (struct volDescPtr *)bh->b_data;
+ next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation);
+ next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength);
+ next_e = next_e >> sb->s_blocksize_bits;
+ next_e += next_s;
+ }
+ break;
+ case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */
+ if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) {
+ vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_IMP_USE_VOL_DESC].block = block;
+ }
+ break;
+ case TAG_IDENT_PD: /* ISO 13346 3/10.5 */
+ if (!vds[VDS_POS_PARTITION_DESC].block)
+ vds[VDS_POS_PARTITION_DESC].block = block;
+ break;
+ case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */
+ if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) {
+ vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_LOGICAL_VOL_DESC].block = block;
+ }
+ break;
+ case TAG_IDENT_USD: /* ISO 13346 3/10.8 */
+ if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) {
+ vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn;
+ vds[VDS_POS_UNALLOC_SPACE_DESC].block = block;
+ }
+ break;
+ case TAG_IDENT_TD: /* ISO 13346 3/10.9 */
+ vds[VDS_POS_TERMINATING_DESC].block = block;
+ if (next_e) {
+ block = next_s;
+ lastblock = next_e;
+ next_s = next_e = 0;
+ } else {
+ done = 1;
+ }
+ break;
}
brelse(bh);
}
- for (i=0; i<VDS_POS_LENGTH; i++)
- {
- if (vds[i].block)
- {
+ for (i = 0; i < VDS_POS_LENGTH; i++) {
+ if (vds[i].block) {
bh = udf_read_tagged(sb, vds[i].block, vds[i].block, &ident);
- if (i == VDS_POS_PRIMARY_VOL_DESC)
+ if (i == VDS_POS_PRIMARY_VOL_DESC) {
udf_load_pvoldesc(sb, bh);
- else if (i == VDS_POS_LOGICAL_VOL_DESC)
+ } else if (i == VDS_POS_LOGICAL_VOL_DESC) {
udf_load_logicalvol(sb, bh, fileset);
- else if (i == VDS_POS_PARTITION_DESC)
- {
+ } else if (i == VDS_POS_PARTITION_DESC) {
struct buffer_head *bh2 = NULL;
udf_load_partdesc(sb, bh);
- for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++)
- {
+ for (j = vds[i].block + 1; j < vds[VDS_POS_TERMINATING_DESC].block; j++) {
bh2 = udf_read_tagged(sb, j, j, &ident);
gd = (struct generic_desc *)bh2->b_data;
if (ident == TAG_IDENT_PD)
@@ -1278,31 +1194,28 @@ udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_
/*
* udf_check_valid()
*/
-static int
-udf_check_valid(struct super_block *sb, int novrs, int silent)
+static int udf_check_valid(struct super_block *sb, int novrs, int silent)
{
long block;
- if (novrs)
- {
+ if (novrs) {
udf_debug("Validity check skipped because of novrs option\n");
return 0;
}
/* Check that it is NSR02 compliant */
/* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */
- else if ((block = udf_vrs(sb, silent)) == -1)
- {
- udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
+ else if ((block = udf_vrs(sb, silent)) == -1) {
+ udf_debug("Failed to read byte 32768. Assuming open disc. "
+ "Skipping validity check\n");
if (!UDF_SB_LASTBLOCK(sb))
UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
return 0;
- }
- else
+ } else {
return !block;
+ }
}
-static int
-udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
+static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
{
struct anchorVolDescPtr *anchor;
uint16_t ident;
@@ -1314,14 +1227,14 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
return 1;
for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) {
- if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb,
- UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident)))
- {
+ if (UDF_SB_ANCHOR(sb)[i] &&
+ (bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i],
+ UDF_SB_ANCHOR(sb)[i], &ident))) {
anchor = (struct anchorVolDescPtr *)bh->b_data;
/* Locate the main sequence */
- main_s = le32_to_cpu( anchor->mainVolDescSeqExt.extLocation );
- main_e = le32_to_cpu( anchor->mainVolDescSeqExt.extLength );
+ main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation);
+ main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength );
main_e = main_e >> sb->s_blocksize_bits;
main_e += main_s;
@@ -1336,8 +1249,7 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
/* Process the main & reserve sequences */
/* responsible for finding the PartitionDesc(s) */
if (!(udf_process_sequence(sb, main_s, main_e, fileset) &&
- udf_process_sequence(sb, reserve_s, reserve_e, fileset)))
- {
+ udf_process_sequence(sb, reserve_s, reserve_e, fileset))) {
break;
}
}
@@ -1349,70 +1261,68 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
} else
udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]);
- for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
- {
- switch (UDF_SB_PARTTYPE(sb, i))
- {
- case UDF_VIRTUAL_MAP15:
- case UDF_VIRTUAL_MAP20:
- {
- kernel_lb_addr ino;
+ for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
+ kernel_lb_addr uninitialized_var(ino);
+ switch (UDF_SB_PARTTYPE(sb, i)) {
+ case UDF_VIRTUAL_MAP15:
+ case UDF_VIRTUAL_MAP20:
+ if (!UDF_SB_LASTBLOCK(sb)) {
+ UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
+ udf_find_anchor(sb);
+ }
- if (!UDF_SB_LASTBLOCK(sb))
- {
- UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb);
- udf_find_anchor(sb);
- }
+ if (!UDF_SB_LASTBLOCK(sb)) {
+ udf_debug("Unable to determine Lastblock (For "
+ "Virtual Partition)\n");
+ return 1;
+ }
- if (!UDF_SB_LASTBLOCK(sb))
- {
- udf_debug("Unable to determine Lastblock (For Virtual Partition)\n");
- return 1;
+ for (j = 0; j < UDF_SB_NUMPARTS(sb); j++) {
+ if (j != i && UDF_SB_PARTVSN(sb, i) ==
+ UDF_SB_PARTVSN(sb, j) &&
+ UDF_SB_PARTNUM(sb, i) ==
+ UDF_SB_PARTNUM(sb, j)) {
+ ino.partitionReferenceNum = j;
+ ino.logicalBlockNum =
+ UDF_SB_LASTBLOCK(sb) -
+ UDF_SB_PARTROOT(sb, j);
+ break;
}
+ }
- for (j=0; j<UDF_SB_NUMPARTS(sb); j++)
- {
- if (j != i &&
- UDF_SB_PARTVSN(sb,i) == UDF_SB_PARTVSN(sb,j) &&
- UDF_SB_PARTNUM(sb,i) == UDF_SB_PARTNUM(sb,j))
- {
- ino.partitionReferenceNum = j;
- ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) -
- UDF_SB_PARTROOT(sb,j);
- break;
- }
- }
+ if (j == UDF_SB_NUMPARTS(sb))
+ return 1;
- if (j == UDF_SB_NUMPARTS(sb))
- return 1;
+ if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
+ return 1;
- if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino)))
- return 1;
+ if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP15) {
+ UDF_SB_TYPEVIRT(sb, i).s_start_offset =
+ udf_ext0_offset(UDF_SB_VAT(sb));
+ UDF_SB_TYPEVIRT(sb, i).s_num_entries =
+ (UDF_SB_VAT(sb)->i_size - 36) >> 2;
+ } else if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP20) {
+ struct buffer_head *bh = NULL;
+ uint32_t pos;
- if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15)
- {
- UDF_SB_TYPEVIRT(sb,i).s_start_offset = udf_ext0_offset(UDF_SB_VAT(sb));
- UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) >> 2;
- }
- else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20)
- {
- struct buffer_head *bh = NULL;
- uint32_t pos;
-
- pos = udf_block_map(UDF_SB_VAT(sb), 0);
- bh = sb_bread(sb, pos);
- if (!bh)
- return 1;
- UDF_SB_TYPEVIRT(sb,i).s_start_offset =
- le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) +
- udf_ext0_offset(UDF_SB_VAT(sb));
- UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size -
- UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2;
- brelse(bh);
- }
- UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0);
- UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum);
+ pos = udf_block_map(UDF_SB_VAT(sb), 0);
+ bh = sb_bread(sb, pos);
+ if (!bh)
+ return 1;
+ UDF_SB_TYPEVIRT(sb, i).s_start_offset =
+ le16_to_cpu(((struct
+ virtualAllocationTable20 *)bh->b_data +
+ udf_ext0_offset(UDF_SB_VAT(sb)))->
+ lengthHeader) +
+ udf_ext0_offset(UDF_SB_VAT(sb));
+ UDF_SB_TYPEVIRT(sb, i).s_num_entries =
+ (UDF_SB_VAT(sb)->i_size -
+ UDF_SB_TYPEVIRT(sb, i).s_start_offset) >> 2;
+ brelse(bh);
}
+ UDF_SB_PARTROOT(sb, i) = udf_get_pblock(sb, 0, i, 0);
+ UDF_SB_PARTLEN(sb, i) = UDF_SB_PARTLEN(sb,
+ ino.partitionReferenceNum);
}
}
return 0;
@@ -1420,26 +1330,28 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset)
static void udf_open_lvid(struct super_block *sb)
{
- if (UDF_SB_LVIDBH(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
int i;
kernel_timestamp cpu_time;
UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
- UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time);
+ UDF_SB_LVID(sb)->recordingDateAndTime =
+ cpu_to_lets(cpu_time);
UDF_SB_LVID(sb)->integrityType = LVID_INTEGRITY_TYPE_OPEN;
UDF_SB_LVID(sb)->descTag.descCRC =
- cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
- le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+ cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
+ le16_to_cpu(UDF_SB_LVID(sb)->descTag.
+ descCRCLength), 0));
UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
+ for (i = 0; i < 16; i++)
if (i != 4)
UDF_SB_LVID(sb)->descTag.tagChecksum +=
- ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i];
+ ((uint8_t *) &
+ (UDF_SB_LVID(sb)->descTag))[i];
mark_buffer_dirty(UDF_SB_LVIDBH(sb));
}
@@ -1447,12 +1359,11 @@ static void udf_open_lvid(struct super_block *sb)
static void udf_close_lvid(struct super_block *sb)
{
- if (UDF_SB_LVIDBH(sb) &&
- UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN)
- {
- int i;
- kernel_timestamp cpu_time;
+ kernel_timestamp cpu_time;
+ int i;
+ if (UDF_SB_LVIDBH(sb) &&
+ UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN) {
UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
if (udf_time_to_stamp(&cpu_time, CURRENT_TIME))
@@ -1467,10 +1378,10 @@ static void udf_close_lvid(struct super_block *sb)
UDF_SB_LVID(sb)->descTag.descCRC =
cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag),
- le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
+ le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0));
UDF_SB_LVID(sb)->descTag.tagChecksum = 0;
- for (i=0; i<16; i++)
+ for (i = 0; i < 16; i++)
if (i != 4)
UDF_SB_LVID(sb)->descTag.tagChecksum +=
((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i];
@@ -1498,7 +1409,7 @@ static void udf_close_lvid(struct super_block *sb)
static int udf_fill_super(struct super_block *sb, void *options, int silent)
{
int i;
- struct inode *inode=NULL;
+ struct inode *inode = NULL;
struct udf_options uopt;
kernel_lb_addr rootdir, fileset;
struct udf_sb_info *sbi;
@@ -1511,6 +1422,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
+
sb->s_fs_info = sbi;
memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info));
@@ -1520,15 +1432,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
goto error_out;
if (uopt.flags & (1 << UDF_FLAG_UTF8) &&
- uopt.flags & (1 << UDF_FLAG_NLS_MAP))
- {
+ uopt.flags & (1 << UDF_FLAG_NLS_MAP)) {
udf_error(sb, "udf_read_super",
- "utf8 cannot be combined with iocharset\n");
+ "utf8 cannot be combined with iocharset\n");
goto error_out;
}
#ifdef CONFIG_UDF_NLS
- if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map)
- {
+ if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map) {
uopt.nls_map = load_nls_default();
if (!uopt.nls_map)
uopt.flags &= ~(1 << UDF_FLAG_NLS_MAP);
@@ -1552,7 +1462,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
if (!udf_set_blocksize(sb, uopt.blocksize))
goto error_out;
- if ( uopt.session == 0xFFFFFFFF )
+ if (uopt.session == 0xFFFFFFFF)
UDF_SB_SESSION(sb) = udf_get_last_session(sb);
else
UDF_SB_SESSION(sb) = uopt.session;
@@ -1564,10 +1474,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
UDF_SB_ANCHOR(sb)[2] = uopt.anchor;
UDF_SB_ANCHOR(sb)[3] = 256;
- if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */
- {
+ if (udf_check_valid(sb, uopt.novrs, silent)) { /* read volume recognition sequences */
printk("UDF-fs: No VRS found\n");
- goto error_out;
+ goto error_out;
}
udf_find_anchor(sb);
@@ -1579,29 +1488,24 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sb->s_magic = UDF_SUPER_MAGIC;
sb->s_time_gran = 1000;
- if (udf_load_partition(sb, &fileset))
- {
+ if (udf_load_partition(sb, &fileset)) {
printk("UDF-fs: No partition found (1)\n");
goto error_out;
}
udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb));
- if ( UDF_SB_LVIDBH(sb) )
- {
+ if (UDF_SB_LVIDBH(sb)) {
uint16_t minUDFReadRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev);
uint16_t minUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev);
/* uint16_t maxUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev); */
- if (minUDFReadRev > UDF_MAX_READ_VERSION)
- {
+ if (minUDFReadRev > UDF_MAX_READ_VERSION) {
printk("UDF-fs: minUDFReadRev=%x (max is %x)\n",
- le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev),
- UDF_MAX_READ_VERSION);
+ le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev),
+ UDF_MAX_READ_VERSION);
goto error_out;
- }
- else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION)
- {
+ } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) {
sb->s_flags |= MS_RDONLY;
}
@@ -1613,8 +1517,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS);
}
- if ( !UDF_SB_NUMPARTS(sb) )
- {
+ if (!UDF_SB_NUMPARTS(sb)) {
printk("UDF-fs: No partition found (2)\n");
goto error_out;
}
@@ -1624,20 +1527,19 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
sb->s_flags |= MS_RDONLY;
}
- if ( udf_find_fileset(sb, &fileset, &rootdir) )
- {
+ if (udf_find_fileset(sb, &fileset, &rootdir)) {
printk("UDF-fs: No fileset found\n");
goto error_out;
}
- if (!silent)
- {
+ if (!silent) {
kernel_timestamp ts;
udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb));
- udf_info("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
- UDFFS_VERSION, UDFFS_DATE,
- UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
- ts.typeAndTimezone);
+ udf_info("UDF %s (%s) Mounting volume '%s', "
+ "timestamp %04u/%02u/%02u %02u:%02u (%x)\n",
+ UDFFS_VERSION, UDFFS_DATE,
+ UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute,
+ ts.typeAndTimezone);
}
if (!(sb->s_flags & MS_RDONLY))
udf_open_lvid(sb);
@@ -1645,18 +1547,16 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
/* Assign the root inode */
/* assign inodes by physical block number */
/* perhaps it's not extensible enough, but for now ... */
- inode = udf_iget(sb, rootdir);
- if (!inode)
- {
+ inode = udf_iget(sb, rootdir);
+ if (!inode) {
printk("UDF-fs: Error in udf_iget, block=%d, partition=%d\n",
- rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
+ rootdir.logicalBlockNum, rootdir.partitionReferenceNum);
goto error_out;
}
/* Allocate a dentry for the root inode */
sb->s_root = d_alloc_root(inode);
- if (!sb->s_root)
- {
+ if (!sb->s_root) {
printk("UDF-fs: Couldn't allocate root dentry\n");
iput(inode);
goto error_out;
@@ -1667,19 +1567,17 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
error_out:
if (UDF_SB_VAT(sb))
iput(UDF_SB_VAT(sb));
- if (UDF_SB_NUMPARTS(sb))
- {
+ if (UDF_SB_NUMPARTS(sb)) {
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
+ UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace);
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
- if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
- {
- for (i=0; i<4; i++)
+ UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace);
+ if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) {
+ for (i = 0; i < 4; i++)
brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
}
}
@@ -1693,16 +1591,16 @@ error_out:
UDF_SB_FREE(sb);
kfree(sbi);
sb->s_fs_info = NULL;
+
return -EINVAL;
}
void udf_error(struct super_block *sb, const char *function,
- const char *fmt, ...)
+ const char *fmt, ...)
{
va_list args;
- if (!(sb->s_flags & MS_RDONLY))
- {
+ if (!(sb->s_flags & MS_RDONLY)) {
/* mark sb error */
sb->s_dirt = 1;
}
@@ -1714,15 +1612,15 @@ void udf_error(struct super_block *sb, const char *function,
}
void udf_warning(struct super_block *sb, const char *function,
- const char *fmt, ...)
+ const char *fmt, ...)
{
va_list args;
- va_start (args, fmt);
+ va_start(args, fmt);
vsnprintf(error_buf, sizeof(error_buf), fmt, args);
va_end(args);
printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n",
- sb->s_id, function, error_buf);
+ sb->s_id, function, error_buf);
}
/*
@@ -1738,26 +1636,23 @@ void udf_warning(struct super_block *sb, const char *function,
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-static void
-udf_put_super(struct super_block *sb)
+static void udf_put_super(struct super_block *sb)
{
int i;
if (UDF_SB_VAT(sb))
iput(UDF_SB_VAT(sb));
- if (UDF_SB_NUMPARTS(sb))
- {
+ if (UDF_SB_NUMPARTS(sb)) {
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace);
+ UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace);
if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
- UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace);
- if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15)
- {
- for (i=0; i<4; i++)
+ UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace);
+ if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) {
+ for (i = 0; i < 4; i++)
brelse(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]);
}
}
@@ -1786,8 +1681,7 @@ udf_put_super(struct super_block *sb)
* July 1, 1997 - Andrew E. Mileski
* Written, tested, and released.
*/
-static int
-udf_statfs(struct dentry *dentry, struct kstatfs *buf)
+static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
@@ -1797,11 +1691,11 @@ udf_statfs(struct dentry *dentry, struct kstatfs *buf)
buf->f_bfree = udf_count_free(sb);
buf->f_bavail = buf->f_bfree;
buf->f_files = (UDF_SB_LVIDBH(sb) ?
- (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
- le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
+ (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) +
+ le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree;
buf->f_ffree = buf->f_bfree;
/* __kernel_fsid_t f_fsid */
- buf->f_namelen = UDF_NAME_LEN-2;
+ buf->f_namelen = UDF_NAME_LEN - 2;
return 0;
}
@@ -1810,8 +1704,7 @@ static unsigned char udf_bitmap_lookup[16] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
};
-static unsigned int
-udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
+static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
{
struct buffer_head *bh = NULL;
unsigned int accum = 0;
@@ -1830,13 +1723,10 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
loc.partitionReferenceNum = UDF_SB_PARTITION(sb);
bh = udf_read_ptagged(sb, loc, 0, &ident);
- if (!bh)
- {
+ if (!bh) {
printk(KERN_ERR "udf: udf_count_free failed\n");
goto out;
- }
- else if (ident != TAG_IDENT_SBD)
- {
+ } else if (ident != TAG_IDENT_SBD) {
brelse(bh);
printk(KERN_ERR "udf: udf_count_free failed\n");
goto out;
@@ -1847,23 +1737,19 @@ udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap)
index = sizeof(struct spaceBitmapDesc); /* offset in first block only */
ptr = (uint8_t *)bh->b_data;
- while ( bytes > 0 )
- {
- while ((bytes > 0) && (index < sb->s_blocksize))
- {
+ while (bytes > 0) {
+ while ((bytes > 0) && (index < sb->s_blocksize)) {
value = ptr[index];
- accum += udf_bitmap_lookup[ value & 0x0f ];
- accum += udf_bitmap_lookup[ value >> 4 ];
+ accum += udf_bitmap_lookup[value & 0x0f];
+ accum += udf_bitmap_lookup[value >> 4];
index++;
bytes--;
}
- if ( bytes )
- {
+ if (bytes) {
brelse(bh);
newblock = udf_get_lb_pblock(sb, loc, ++block);
bh = udf_tread(sb, newblock);
- if (!bh)
- {
+ if (!bh) {
udf_debug("read failed\n");
goto out;
}
@@ -1879,8 +1765,7 @@ out:
return accum;
}
-static unsigned int
-udf_count_free_table(struct super_block *sb, struct inode * table)
+static unsigned int udf_count_free_table(struct super_block *sb, struct inode *table)
{
unsigned int accum = 0;
uint32_t elen;
@@ -1894,26 +1779,23 @@ udf_count_free_table(struct super_block *sb, struct inode * table)
epos.offset = sizeof(struct unallocSpaceEntry);
epos.bh = NULL;
- while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1)
+ while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) {
accum += (elen >> table->i_sb->s_blocksize_bits);
+ }
brelse(epos.bh);
unlock_kernel();
return accum;
}
-
-static unsigned int
-udf_count_free(struct super_block *sb)
+
+static unsigned int udf_count_free(struct super_block *sb)
{
unsigned int accum = 0;
- if (UDF_SB_LVIDBH(sb))
- {
- if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb))
- {
+ if (UDF_SB_LVIDBH(sb)) {
+ if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb)) {
accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]);
-
if (accum == 0xFFFFFFFF)
accum = 0;
}
@@ -1922,28 +1804,24 @@ udf_count_free(struct super_block *sb)
if (accum)
return accum;
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP)
- {
+ if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) {
accum += udf_count_free_bitmap(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
+ UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap);
}
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP)
- {
+ if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) {
accum += udf_count_free_bitmap(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
+ UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap);
}
if (accum)
return accum;
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE)
- {
+ if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) {
accum += udf_count_free_table(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
+ UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table);
}
- if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE)
- {
+ if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) {
accum += udf_count_free_table(sb,
- UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
+ UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table);
}
return accum;
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 12613b680cc4..e6f933dd6a7b 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -11,7 +11,7 @@
* Each contributing author retains all rights to their own work.
*
* (C) 1998-2001 Ben Fennema
- * (C) 1999 Stelias Computing Inc
+ * (C) 1999 Stelias Computing Inc
*
* HISTORY
*
@@ -39,35 +39,33 @@ static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char
int elen = 0;
char *p = to;
- while (elen < fromlen)
- {
+ while (elen < fromlen) {
pc = (struct pathComponent *)(from + elen);
- switch (pc->componentType)
- {
- case 1:
- if (pc->lengthComponentIdent == 0)
- {
- p = to;
- *p++ = '/';
- }
- break;
- case 3:
- memcpy(p, "../", 3);
- p += 3;
- break;
- case 4:
- memcpy(p, "./", 2);
- p += 2;
- /* that would be . - just ignore */
- break;
- case 5:
- p += udf_get_filename(sb, pc->componentIdent, p, pc->lengthComponentIdent);
+ switch (pc->componentType) {
+ case 1:
+ if (pc->lengthComponentIdent == 0) {
+ p = to;
*p++ = '/';
- break;
+ }
+ break;
+ case 3:
+ memcpy(p, "../", 3);
+ p += 3;
+ break;
+ case 4:
+ memcpy(p, "./", 2);
+ p += 2;
+ /* that would be . - just ignore */
+ break;
+ case 5:
+ p += udf_get_filename(sb, pc->componentIdent, p,
+ pc->lengthComponentIdent);
+ *p++ = '/';
+ break;
}
elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
}
- if (p > to+1)
+ if (p > to + 1)
p[-1] = '\0';
else
p[0] = '\0';
@@ -82,10 +80,9 @@ static int udf_symlink_filler(struct file *file, struct page *page)
char *p = kmap(page);
lock_kernel();
- if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
+ if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) {
symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode);
- else
- {
+ } else {
bh = sb_bread(inode->i_sb, udf_block_map(inode, 0));
if (!bh)
@@ -102,6 +99,7 @@ static int udf_symlink_filler(struct file *file, struct page *page)
kunmap(page);
unlock_page(page);
return 0;
+
out:
unlock_kernel();
SetPageError(page);
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c
index 60d277644248..7fc3912885a5 100644
--- a/fs/udf/truncate.c
+++ b/fs/udf/truncate.c
@@ -28,35 +28,36 @@
#include "udf_i.h"
#include "udf_sb.h"
-static void extent_trunc(struct inode * inode, struct extent_position *epos,
- kernel_lb_addr eloc, int8_t etype, uint32_t elen, uint32_t nelen)
+static void extent_trunc(struct inode *inode, struct extent_position *epos,
+ kernel_lb_addr eloc, int8_t etype, uint32_t elen,
+ uint32_t nelen)
{
- kernel_lb_addr neloc = { 0, 0 };
- int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
- int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits;
+ kernel_lb_addr neloc = {};
+ int last_block = (elen + inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits;
+ int first_block = (nelen + inode->i_sb->s_blocksize - 1) >>
+ inode->i_sb->s_blocksize_bits;
- if (nelen)
- {
- if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30))
- {
- udf_free_blocks(inode->i_sb, inode, eloc, 0, last_block);
+ if (nelen) {
+ if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) {
+ udf_free_blocks(inode->i_sb, inode, eloc, 0,
+ last_block);
etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30);
- }
- else
+ } else
neloc = eloc;
nelen = (etype << 30) | nelen;
}
- if (elen != nelen)
- {
+ if (elen != nelen) {
udf_write_aext(inode, epos, neloc, nelen, 0);
- if (last_block - first_block > 0)
- {
+ if (last_block - first_block > 0) {
if (etype == (EXT_RECORDED_ALLOCATED >> 30))
mark_inode_dirty(inode);
if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))
- udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block);
+ udf_free_blocks(inode->i_sb, inode, eloc,
+ first_block,
+ last_block - first_block);
}
}
}
@@ -67,7 +68,7 @@ static void extent_trunc(struct inode * inode, struct extent_position *epos,
*/
void udf_truncate_tail_extent(struct inode *inode)
{
- struct extent_position epos = { NULL, 0, {0, 0}};
+ struct extent_position epos = {};
kernel_lb_addr eloc;
uint32_t elen, nelen;
uint64_t lbcount = 0;
@@ -89,8 +90,7 @@ void udf_truncate_tail_extent(struct inode *inode)
BUG();
/* Find the last extent in the file */
- while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1)
- {
+ while ((netype = udf_next_aext(inode, &epos, &eloc, &elen, 1)) != -1) {
etype = netype;
lbcount += elen;
if (lbcount > inode->i_size) {
@@ -123,7 +123,7 @@ void udf_truncate_tail_extent(struct inode *inode)
void udf_discard_prealloc(struct inode *inode)
{
- struct extent_position epos = { NULL, 0, {0, 0}};
+ struct extent_position epos = { NULL, 0, {0, 0} };
kernel_lb_addr eloc;
uint32_t elen;
uint64_t lbcount = 0;
@@ -131,7 +131,7 @@ void udf_discard_prealloc(struct inode *inode)
int adsize;
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ||
- inode->i_size == UDF_I_LENEXTENTS(inode))
+ inode->i_size == UDF_I_LENEXTENTS(inode))
return;
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT)
@@ -153,15 +153,21 @@ void udf_discard_prealloc(struct inode *inode)
lbcount -= elen;
extent_trunc(inode, &epos, eloc, etype, elen, 0);
if (!epos.bh) {
- UDF_I_LENALLOC(inode) = epos.offset - udf_file_entry_alloc_offset(inode);
+ UDF_I_LENALLOC(inode) =
+ epos.offset - udf_file_entry_alloc_offset(inode);
mark_inode_dirty(inode);
} else {
- struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
- aed->lengthAllocDescs = cpu_to_le32(epos.offset - sizeof(struct allocExtDesc));
- if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
+ struct allocExtDesc *aed =
+ (struct allocExtDesc *)(epos.bh->b_data);
+ aed->lengthAllocDescs =
+ cpu_to_le32(epos.offset -
+ sizeof(struct allocExtDesc));
+ if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) ||
+ UDF_SB_UDFREV(inode->i_sb) >= 0x0201)
udf_update_tag(epos.bh->b_data, epos.offset);
else
- udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+ udf_update_tag(epos.bh->b_data,
+ sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(epos.bh, inode);
}
}
@@ -171,10 +177,10 @@ void udf_discard_prealloc(struct inode *inode)
brelse(epos.bh);
}
-void udf_truncate_extents(struct inode * inode)
+void udf_truncate_extents(struct inode *inode)
{
struct extent_position epos;
- kernel_lb_addr eloc, neloc = { 0, 0 };
+ kernel_lb_addr eloc, neloc = {};
uint32_t elen, nelen = 0, indirect_ext_len = 0, lenalloc;
int8_t etype;
struct super_block *sb = inode->i_sb;
@@ -190,9 +196,9 @@ void udf_truncate_extents(struct inode * inode)
BUG();
etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset);
- byte_offset = (offset << sb->s_blocksize_bits) + (inode->i_size & (sb->s_blocksize-1));
- if (etype != -1)
- {
+ byte_offset = (offset << sb->s_blocksize_bits) +
+ (inode->i_size & (sb->s_blocksize - 1));
+ if (etype != -1) {
epos.offset -= adsize;
extent_trunc(inode, &epos, eloc, etype, elen, byte_offset);
epos.offset += adsize;
@@ -206,35 +212,33 @@ void udf_truncate_extents(struct inode * inode)
else
lenalloc -= sizeof(struct allocExtDesc);
- while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1)
- {
- if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30))
- {
+ while ((etype = udf_current_aext(inode, &epos, &eloc, &elen, 0)) != -1) {
+ if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) {
udf_write_aext(inode, &epos, neloc, nelen, 0);
- if (indirect_ext_len)
- {
+ if (indirect_ext_len) {
/* We managed to free all extents in the
* indirect extent - free it too */
if (!epos.bh)
BUG();
- udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
- }
- else
- {
- if (!epos.bh)
- {
+ udf_free_blocks(sb, inode, epos.block,
+ 0, indirect_ext_len);
+ } else {
+ if (!epos.bh) {
UDF_I_LENALLOC(inode) = lenalloc;
mark_inode_dirty(inode);
- }
- else
- {
- struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
- aed->lengthAllocDescs = cpu_to_le32(lenalloc);
- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
- udf_update_tag(epos.bh->b_data, lenalloc +
- sizeof(struct allocExtDesc));
+ } else {
+ struct allocExtDesc *aed =
+ (struct allocExtDesc *)(epos.bh->b_data);
+ aed->lengthAllocDescs =
+ cpu_to_le32(lenalloc);
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
+ UDF_SB_UDFREV(sb) >= 0x0201)
+ udf_update_tag(epos.bh->b_data,
+ lenalloc +
+ sizeof(struct allocExtDesc));
else
- udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+ udf_update_tag(epos.bh->b_data,
+ sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(epos.bh, inode);
}
}
@@ -243,49 +247,41 @@ void udf_truncate_extents(struct inode * inode)
epos.block = eloc;
epos.bh = udf_tread(sb, udf_get_lb_pblock(sb, eloc, 0));
if (elen)
- indirect_ext_len = (elen +
- sb->s_blocksize - 1) >>
+ indirect_ext_len = (elen + sb->s_blocksize -1) >>
sb->s_blocksize_bits;
else
indirect_ext_len = 1;
- }
- else
- {
+ } else {
extent_trunc(inode, &epos, eloc, etype, elen, 0);
epos.offset += adsize;
}
}
- if (indirect_ext_len)
- {
+ if (indirect_ext_len) {
if (!epos.bh)
BUG();
- udf_free_blocks(sb, inode, epos.block, 0, indirect_ext_len);
- }
- else
- {
- if (!epos.bh)
- {
+ udf_free_blocks(sb, inode, epos.block, 0,
+ indirect_ext_len);
+ } else {
+ if (!epos.bh) {
UDF_I_LENALLOC(inode) = lenalloc;
mark_inode_dirty(inode);
- }
- else
- {
- struct allocExtDesc *aed = (struct allocExtDesc *)(epos.bh->b_data);
+ } else {
+ struct allocExtDesc *aed =
+ (struct allocExtDesc *)(epos.bh->b_data);
aed->lengthAllocDescs = cpu_to_le32(lenalloc);
- if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(sb) >= 0x0201)
- udf_update_tag(epos.bh->b_data, lenalloc +
- sizeof(struct allocExtDesc));
+ if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT) ||
+ UDF_SB_UDFREV(sb) >= 0x0201)
+ udf_update_tag(epos.bh->b_data,
+ lenalloc + sizeof(struct allocExtDesc));
else
- udf_update_tag(epos.bh->b_data, sizeof(struct allocExtDesc));
+ udf_update_tag(epos.bh->b_data,
+ sizeof(struct allocExtDesc));
mark_buffer_dirty_inode(epos.bh, inode);
}
}
- }
- else if (inode->i_size)
- {
- if (byte_offset)
- {
+ } else if (inode->i_size) {
+ if (byte_offset) {
kernel_long_ad extent;
/*
@@ -293,21 +289,23 @@ void udf_truncate_extents(struct inode * inode)
* no extent above inode->i_size => truncate is
* extending the file by 'offset' blocks.
*/
- if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) ||
+ if ((!epos.bh &&
+ epos.offset == udf_file_entry_alloc_offset(inode)) ||
(epos.bh && epos.offset == sizeof(struct allocExtDesc))) {
/* File has no extents at all or has empty last
* indirect extent! Create a fake extent... */
extent.extLocation.logicalBlockNum = 0;
extent.extLocation.partitionReferenceNum = 0;
extent.extLength = EXT_NOT_RECORDED_NOT_ALLOCATED;
- }
- else {
+ } else {
epos.offset -= adsize;
etype = udf_next_aext(inode, &epos,
- &extent.extLocation, &extent.extLength, 0);
+ &extent.extLocation,
+ &extent.extLength, 0);
extent.extLength |= etype << 30;
}
- udf_extend_file(inode, &epos, &extent, offset+((inode->i_size & (sb->s_blocksize-1)) != 0));
+ udf_extend_file(inode, &epos, &extent,
+ offset + ((inode->i_size & (sb->s_blocksize - 1)) != 0));
}
}
UDF_I_LENEXTENTS(inode) = inode->i_size;
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 3b2e6c8cb151..3e937d3fb8f9 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -41,8 +41,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
#define UDF_SB_FREE(X)\
{\
- if (UDF_SB(X))\
- {\
+ if (UDF_SB(X)) {\
kfree(UDF_SB_PARTMAPS(X));\
UDF_SB_PARTMAPS(X) = NULL;\
}\
@@ -51,13 +50,10 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
#define UDF_SB_ALLOC_PARTMAPS(X,Y)\
{\
UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\
- if (UDF_SB_PARTMAPS(X) != NULL)\
- {\
+ if (UDF_SB_PARTMAPS(X) != NULL) {\
UDF_SB_NUMPARTS(X) = Y;\
memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\
- }\
- else\
- {\
+ } else {\
UDF_SB_NUMPARTS(X) = 0;\
udf_error(X, __FUNCTION__, "Unable to allocate space for %d partition maps", Y);\
}\
@@ -72,15 +68,12 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\
else\
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\
- if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\
- {\
+ if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL) {\
memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\
(struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\
UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\
- }\
- else\
- {\
+ } else {\
udf_error(X, __FUNCTION__, "Unable to allocate space for bitmap and %d buffer_head pointers", nr_groups);\
}\
}
@@ -90,8 +83,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
int i;\
int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\
int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\
- for (i=0; i<nr_groups; i++)\
- {\
+ for (i = 0; i < nr_groups; i++) {\
if (UDF_SB_BITMAP(X,Y,Z,i))\
brelse(UDF_SB_BITMAP(X,Y,Z,i));\
}\
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index f581f2f69c0f..c8016cc9e7e6 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -50,30 +50,26 @@ extern const struct address_space_operations udf_aops;
extern const struct address_space_operations udf_adinicb_aops;
extern const struct address_space_operations udf_symlink_aops;
-struct udf_fileident_bh
-{
+struct udf_fileident_bh {
struct buffer_head *sbh;
struct buffer_head *ebh;
int soffset;
int eoffset;
};
-struct udf_vds_record
-{
+struct udf_vds_record {
uint32_t block;
uint32_t volDescSeqNum;
};
-struct generic_desc
-{
+struct generic_desc {
tag descTag;
__le32 volDescSeqNum;
};
-struct ustr
-{
+struct ustr {
uint8_t u_cmpID;
- uint8_t u_name[UDF_NAME_LEN-2];
+ uint8_t u_name[UDF_NAME_LEN - 2];
uint8_t u_len;
};
@@ -83,44 +79,58 @@ struct extent_position {
kernel_lb_addr block;
};
-
/* super.c */
extern void udf_error(struct super_block *, const char *, const char *, ...);
extern void udf_warning(struct super_block *, const char *, const char *, ...);
/* namei.c */
-extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, struct fileIdentDesc *, struct udf_fileident_bh *, uint8_t *, uint8_t *);
+extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
+ struct fileIdentDesc *, struct udf_fileident_bh *,
+ uint8_t *, uint8_t *);
/* file.c */
-extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+extern int udf_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
/* inode.c */
extern struct inode *udf_iget(struct super_block *, kernel_lb_addr);
extern int udf_sync_inode(struct inode *);
extern void udf_expand_file_adinicb(struct inode *, int, int *);
-extern struct buffer_head * udf_expand_dir_adinicb(struct inode *, int *, int *);
-extern struct buffer_head * udf_bread(struct inode *, int, int, int *);
+extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *);
+extern struct buffer_head *udf_bread(struct inode *, int, int, int *);
extern void udf_truncate(struct inode *);
extern void udf_read_inode(struct inode *);
extern void udf_delete_inode(struct inode *);
extern void udf_clear_inode(struct inode *);
extern int udf_write_inode(struct inode *, int);
extern long udf_block_map(struct inode *, sector_t);
-extern int udf_extend_file(struct inode *, struct extent_position *, kernel_long_ad *, sector_t);
-extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
-extern int8_t udf_add_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
-extern int8_t udf_write_aext(struct inode *, struct extent_position *, kernel_lb_addr, uint32_t, int);
-extern int8_t udf_delete_aext(struct inode *, struct extent_position, kernel_lb_addr, uint32_t);
-extern int8_t udf_next_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
-extern int8_t udf_current_aext(struct inode *, struct extent_position *, kernel_lb_addr *, uint32_t *, int);
+extern int udf_extend_file(struct inode *, struct extent_position *,
+ kernel_long_ad *, sector_t);
+extern int8_t inode_bmap(struct inode *, sector_t, struct extent_position *,
+ kernel_lb_addr *, uint32_t *, sector_t *);
+extern int8_t udf_add_aext(struct inode *, struct extent_position *,
+ kernel_lb_addr, uint32_t, int);
+extern int8_t udf_write_aext(struct inode *, struct extent_position *,
+ kernel_lb_addr, uint32_t, int);
+extern int8_t udf_delete_aext(struct inode *, struct extent_position,
+ kernel_lb_addr, uint32_t);
+extern int8_t udf_next_aext(struct inode *, struct extent_position *,
+ kernel_lb_addr *, uint32_t *, int);
+extern int8_t udf_current_aext(struct inode *, struct extent_position *,
+ kernel_lb_addr *, uint32_t *, int);
/* misc.c */
extern struct buffer_head *udf_tgetblk(struct super_block *, int);
extern struct buffer_head *udf_tread(struct super_block *, int);
-extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t);
-extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t);
-extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *);
-extern struct buffer_head *udf_read_ptagged(struct super_block *, kernel_lb_addr, uint32_t, uint16_t *);
+extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t,
+ uint32_t, uint8_t);
+extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t,
+ uint8_t);
+extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t,
+ uint32_t, uint16_t *);
+extern struct buffer_head *udf_read_ptagged(struct super_block *,
+ kernel_lb_addr, uint32_t,
+ uint16_t *);
extern void udf_update_tag(char *, int);
extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int);
@@ -129,21 +139,26 @@ extern unsigned int udf_get_last_session(struct super_block *);
extern unsigned long udf_get_last_block(struct super_block *);
/* partition.c */
-extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, uint32_t);
-extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, uint32_t);
+extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
+extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
+extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
+extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t,
+ uint32_t);
extern int udf_relocate_blocks(struct super_block *, long, long *);
/* unicode.c */
extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int);
-extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, int);
+extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
+ int);
extern int udf_build_ustr(struct ustr *, dstring *, int);
extern int udf_CS0toUTF8(struct ustr *, struct ustr *);
/* ialloc.c */
extern void udf_free_inode(struct inode *);
-extern struct inode * udf_new_inode (struct inode *, int, int *);
+extern struct inode *udf_new_inode(struct inode *, int, int *);
/* truncate.c */
extern void udf_truncate_tail_extent(struct inode *);
@@ -151,18 +166,27 @@ extern void udf_discard_prealloc(struct inode *);
extern void udf_truncate_extents(struct inode *);
/* balloc.c */
-extern void udf_free_blocks(struct super_block *, struct inode *, kernel_lb_addr, uint32_t, uint32_t);
-extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, uint32_t, uint32_t);
-extern int udf_new_block(struct super_block *, struct inode *, uint16_t, uint32_t, int *);
+extern void udf_free_blocks(struct super_block *, struct inode *,
+ kernel_lb_addr, uint32_t, uint32_t);
+extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t,
+ uint32_t, uint32_t);
+extern int udf_new_block(struct super_block *, struct inode *, uint16_t,
+ uint32_t, int *);
/* fsync.c */
extern int udf_fsync_file(struct file *, struct dentry *, int);
/* directory.c */
-extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, struct extent_position *, kernel_lb_addr *, uint32_t *, sector_t *);
-extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset);
-extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int);
-extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int);
+extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *,
+ struct udf_fileident_bh *,
+ struct fileIdentDesc *,
+ struct extent_position *,
+ kernel_lb_addr *, uint32_t *,
+ sector_t *);
+extern struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize,
+ int *offset);
+extern long_ad *udf_get_filelongad(uint8_t *, int, int *, int);
+extern short_ad *udf_get_fileshortad(uint8_t *, int, int *, int);
/* crc.c */
extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t);
@@ -171,4 +195,4 @@ extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t);
extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp);
extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec);
-#endif /* __UDF_DECL_H */
+#endif /* __UDF_DECL_H */
diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h
index 17d378879561..c4bd1203f857 100644
--- a/fs/udf/udfend.h
+++ b/fs/udf/udfend.h
@@ -7,74 +7,92 @@
static inline kernel_lb_addr lelb_to_cpu(lb_addr in)
{
kernel_lb_addr out;
+
out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum);
out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum);
+
return out;
}
static inline lb_addr cpu_to_lelb(kernel_lb_addr in)
{
lb_addr out;
+
out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum);
out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum);
+
return out;
}
static inline kernel_timestamp lets_to_cpu(timestamp in)
{
kernel_timestamp out;
+
memcpy(&out, &in, sizeof(timestamp));
out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone);
out.year = le16_to_cpu(in.year);
+
return out;
}
static inline short_ad lesa_to_cpu(short_ad in)
{
short_ad out;
+
out.extLength = le32_to_cpu(in.extLength);
out.extPosition = le32_to_cpu(in.extPosition);
+
return out;
}
static inline short_ad cpu_to_lesa(short_ad in)
{
short_ad out;
+
out.extLength = cpu_to_le32(in.extLength);
out.extPosition = cpu_to_le32(in.extPosition);
+
return out;
}
static inline kernel_long_ad lela_to_cpu(long_ad in)
{
kernel_long_ad out;
+
out.extLength = le32_to_cpu(in.extLength);
out.extLocation = lelb_to_cpu(in.extLocation);
+
return out;
}
static inline long_ad cpu_to_lela(kernel_long_ad in)
{
long_ad out;
+
out.extLength = cpu_to_le32(in.extLength);
out.extLocation = cpu_to_lelb(in.extLocation);
+
return out;
}
static inline kernel_extent_ad leea_to_cpu(extent_ad in)
{
kernel_extent_ad out;
+
out.extLength = le32_to_cpu(in.extLength);
out.extLocation = le32_to_cpu(in.extLocation);
+
return out;
}
static inline timestamp cpu_to_lets(kernel_timestamp in)
{
timestamp out;
+
memcpy(&out, &in, sizeof(timestamp));
out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone);
out.year = cpu_to_le16(in.year);
+
return out;
}
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index 85d8dbe843f1..3fd80eb66af3 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -18,18 +18,18 @@
Boston, MA 02111-1307, USA. */
/*
- * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time
+ * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time
* 10/04/98: added new table-based lookup after seeing how ugly the gnu code is
* blf 09/27/99: ripped out all the old code and inserted new table from
- * John Brockmeyer (without leap second corrections)
- * rewrote udf_stamp_to_time and fixed timezone accounting in
- udf_time_to_stamp.
+ * John Brockmeyer (without leap second corrections)
+ * rewrote udf_stamp_to_time and fixed timezone accounting in
+ * udf_time_to_stamp.
*/
/*
* We don't take into account leap seconds. This may be correct or incorrect.
* For more NIST information (especially dealing with leap seconds), see:
- * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
+ * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
*/
#include <linux/types.h>
@@ -46,36 +46,35 @@
#endif
/* How many days come before each month (0-12). */
-static const unsigned short int __mon_yday[2][13] =
-{
+static const unsigned short int __mon_yday[2][13] = {
/* Normal years. */
- { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
/* Leap years. */
- { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
};
#define MAX_YEAR_SECONDS 69
-#define SPD 0x15180 /*3600*24*/
-#define SPY(y,l,s) (SPD * (365*y+l)+s)
+#define SPD 0x15180 /*3600*24 */
+#define SPY(y,l,s) (SPD * (365*y+l)+s)
static time_t year_seconds[MAX_YEAR_SECONDS]= {
-/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0),
-/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0),
-/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0),
-/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0),
-/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0),
-/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0),
-/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0),
-/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0),
-/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0),
-/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0),
-/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0),
-/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0),
-/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0),
-/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0),
-/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0),
-/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0),
-/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0),
+/*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0),
+/*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0),
+/*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0),
+/*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0),
+/*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0),
+/*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0),
+/*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0),
+/*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0),
+/*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0),
+/*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0),
+/*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0),
+/*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0),
+/*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0),
+/*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0),
+/*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0),
+/*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0),
+/*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0),
/*2038*/ SPY(68,17,0)
};
@@ -84,27 +83,24 @@ extern struct timezone sys_tz;
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
-time_t *
-udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
+time_t *udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
{
int yday;
uint8_t type = src.typeAndTimezone >> 12;
int16_t offset;
- if (type == 1)
- {
+ if (type == 1) {
offset = src.typeAndTimezone << 4;
/* sign extent offset */
offset = (offset >> 4);
if (offset == -2047) /* unspecified offset */
offset = 0;
- }
- else
+ } else {
offset = 0;
+ }
if ((src.year < EPOCH_YEAR) ||
- (src.year >= EPOCH_YEAR+MAX_YEAR_SECONDS))
- {
+ (src.year >= EPOCH_YEAR + MAX_YEAR_SECONDS)) {
*dest = -1;
*dest_usec = -1;
return NULL;
@@ -113,15 +109,13 @@ udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src)
*dest -= offset * 60;
yday = ((__mon_yday[__isleap (src.year)]
- [src.month-1]) + (src.day-1));
- *dest += ( ( (yday* 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
+ [src.month - 1]) + (src.day - 1));
+ *dest += ( ( (yday * 24) + src.hour ) * 60 + src.minute ) * 60 + src.second;
*dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds;
return dest;
}
-
-kernel_timestamp *
-udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
+kernel_timestamp *udf_time_to_stamp(kernel_timestamp * dest, struct timespec ts)
{
long int days, rem, y;
const unsigned short int *ip;
@@ -146,19 +140,18 @@ udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
#define DIV(a,b) ((a) / (b) - ((a) % (b) < 0))
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
- while (days < 0 || days >= (__isleap(y) ? 366 : 365))
- {
+ while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
long int yg = y + days / 365 - (days % 365 < 0);
/* Adjust DAYS and Y to match the guessed year. */
days -= ((yg - y) * 365
- + LEAPS_THRU_END_OF (yg - 1)
- - LEAPS_THRU_END_OF (y - 1));
+ + LEAPS_THRU_END_OF (yg - 1)
+ - LEAPS_THRU_END_OF (y - 1));
y = yg;
}
dest->year = y;
ip = __mon_yday[__isleap(y)];
- for (y = 11; days < (long int) ip[y]; --y)
+ for (y = 11; days < (long int)ip[y]; --y)
continue;
days -= ip[y];
dest->month = y + 1;
@@ -167,7 +160,7 @@ udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts)
dest->centiseconds = ts.tv_nsec / 10000000;
dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000) / 100;
dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
- dest->hundredsOfMicroseconds * 100);
+ dest->hundredsOfMicroseconds * 100);
return dest;
}
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 706c92e1dcc9..9e6099c26c27 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -31,12 +31,14 @@ static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int);
static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
{
- if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) )
+ if ((!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN - 2))
return 0;
+
memset(dest, 0, sizeof(struct ustr));
memcpy(dest->u_name, src, strlen);
dest->u_cmpID = 0x08;
dest->u_len = strlen;
+
return strlen;
}
@@ -47,14 +49,15 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
{
int usesize;
- if ( (!dest) || (!ptr) || (!size) )
+ if ((!dest) || (!ptr) || (!size))
return -1;
memset(dest, 0, sizeof(struct ustr));
- usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
- dest->u_cmpID=ptr[0];
- dest->u_len=ptr[size-1];
- memcpy(dest->u_name, ptr+1, usesize-1);
+ usesize = (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size;
+ dest->u_cmpID = ptr[0];
+ dest->u_len = ptr[size - 1];
+ memcpy(dest->u_name, ptr + 1, usesize - 1);
+
return 0;
}
@@ -63,13 +66,14 @@ int udf_build_ustr(struct ustr *dest, dstring *ptr, int size)
*/
static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize)
{
- if ( (!dest) || (!ptr) || (!exactsize) )
+ if ((!dest) || (!ptr) || (!exactsize))
return -1;
memset(dest, 0, sizeof(struct ustr));
- dest->u_cmpID=ptr[0];
- dest->u_len=exactsize-1;
- memcpy(dest->u_name, ptr+1, exactsize-1);
+ dest->u_cmpID = ptr[0];
+ dest->u_len = exactsize - 1;
+ memcpy(dest->u_name, ptr + 1, exactsize - 1);
+
return 0;
}
@@ -108,22 +112,20 @@ int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
cmp_id = ocu_i->u_cmpID;
utf_o->u_len = 0;
- if (ocu_len == 0)
- {
+ if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr));
utf_o->u_cmpID = 0;
utf_o->u_len = 0;
return 0;
}
- if ((cmp_id != 8) && (cmp_id != 16))
- {
- printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+ if ((cmp_id != 8) && (cmp_id != 16)) {
+ printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
+ cmp_id, ocu_i->u_name);
return 0;
}
- for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
- {
+ for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */
c = ocu[i++];
@@ -131,21 +133,18 @@ int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i)
c = (c << 8) | ocu[i++];
/* Compress Unicode to UTF-8 */
- if (c < 0x80U)
+ if (c < 0x80U) {
utf_o->u_name[utf_o->u_len++] = (uint8_t)c;
- else if (c < 0x800U)
- {
+ } else if (c < 0x800U) {
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6));
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
- }
- else
- {
+ } else {
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12));
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f));
utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f));
}
}
- utf_o->u_cmpID=8;
+ utf_o->u_cmpID = 8;
return utf_o->u_len;
}
@@ -186,61 +185,46 @@ try_again:
u_len = 0U;
utf_char = 0U;
utf_cnt = 0U;
- for (i = 0U; i < utf->u_len; i++)
- {
+ for (i = 0U; i < utf->u_len; i++) {
c = (uint8_t)utf->u_name[i];
/* Complete a multi-byte UTF-8 character */
- if (utf_cnt)
- {
+ if (utf_cnt) {
utf_char = (utf_char << 6) | (c & 0x3fU);
if (--utf_cnt)
continue;
- }
- else
- {
+ } else {
/* Check for a multi-byte UTF-8 character */
- if (c & 0x80U)
- {
+ if (c & 0x80U) {
/* Start a multi-byte UTF-8 character */
- if ((c & 0xe0U) == 0xc0U)
- {
+ if ((c & 0xe0U) == 0xc0U) {
utf_char = c & 0x1fU;
utf_cnt = 1;
- }
- else if ((c & 0xf0U) == 0xe0U)
- {
+ } else if ((c & 0xf0U) == 0xe0U) {
utf_char = c & 0x0fU;
utf_cnt = 2;
- }
- else if ((c & 0xf8U) == 0xf0U)
- {
+ } else if ((c & 0xf8U) == 0xf0U) {
utf_char = c & 0x07U;
utf_cnt = 3;
- }
- else if ((c & 0xfcU) == 0xf8U)
- {
+ } else if ((c & 0xfcU) == 0xf8U) {
utf_char = c & 0x03U;
utf_cnt = 4;
- }
- else if ((c & 0xfeU) == 0xfcU)
- {
+ } else if ((c & 0xfeU) == 0xfcU) {
utf_char = c & 0x01U;
utf_cnt = 5;
- }
- else
+ } else {
goto error_out;
+ }
continue;
- } else
+ } else {
/* Single byte UTF-8 character (most common) */
utf_char = c;
+ }
}
/* Choose no compression if necessary */
- if (utf_char > max_val)
- {
- if ( 0xffU == max_val )
- {
+ if (utf_char > max_val) {
+ if (max_val == 0xffU) {
max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U;
goto try_again;
@@ -248,26 +232,25 @@ try_again:
goto error_out;
}
- if (max_val == 0xffffU)
- {
+ if (max_val == 0xffffU) {
ocu[++u_len] = (uint8_t)(utf_char >> 8);
}
ocu[++u_len] = (uint8_t)(utf_char & 0xffU);
}
-
- if (utf_cnt)
- {
+ if (utf_cnt) {
error_out:
ocu[++u_len] = '?';
printk(KERN_DEBUG "udf: bad UTF-8 character\n");
}
ocu[length - 1] = (uint8_t)u_len + 1;
+
return u_len + 1;
}
-static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i)
+static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o,
+ struct ustr *ocu_i)
{
uint8_t *ocu;
uint32_t c;
@@ -280,36 +263,35 @@ static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *
cmp_id = ocu_i->u_cmpID;
utf_o->u_len = 0;
- if (ocu_len == 0)
- {
+ if (ocu_len == 0) {
memset(utf_o, 0, sizeof(struct ustr));
utf_o->u_cmpID = 0;
utf_o->u_len = 0;
return 0;
}
- if ((cmp_id != 8) && (cmp_id != 16))
- {
- printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name);
+ if ((cmp_id != 8) && (cmp_id != 16)) {
+ printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n",
+ cmp_id, ocu_i->u_name);
return 0;
}
- for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;)
- {
+ for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN - 3));) {
/* Expand OSTA compressed Unicode to Unicode */
c = ocu[i++];
if (cmp_id == 16)
c = (c << 8) | ocu[i++];
- utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
- UDF_NAME_LEN - utf_o->u_len);
+ utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len],
+ UDF_NAME_LEN - utf_o->u_len);
}
- utf_o->u_cmpID=8;
+ utf_o->u_cmpID = 8;
return utf_o->u_len;
}
-static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length)
+static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni,
+ int length)
{
unsigned len, i, max_val;
uint16_t uni_char;
@@ -321,19 +303,17 @@ static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, i
try_again:
u_len = 0U;
- for (i = 0U; i < uni->u_len; i++)
- {
- len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char);
+ for (i = 0U; i < uni->u_len; i++) {
+ len = nls->char2uni(&uni->u_name[i], uni->u_len - i, &uni_char);
if (len <= 0)
continue;
- if (uni_char > max_val)
- {
+ if (uni_char > max_val) {
max_val = 0xffffU;
ocu[0] = (uint8_t)0x10U;
goto try_again;
}
-
+
if (max_val == 0xffffU)
ocu[++u_len] = (uint8_t)(uni_char >> 8);
ocu[++u_len] = (uint8_t)(uni_char & 0xffU);
@@ -344,112 +324,98 @@ try_again:
return u_len + 1;
}
-int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, int flen)
+int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
+ int flen)
{
struct ustr filename, unifilename;
int len;
- if (udf_build_ustr_exact(&unifilename, sname, flen))
- {
+ if (udf_build_ustr_exact(&unifilename, sname, flen)) {
return 0;
}
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
- {
- if (!udf_CS0toUTF8(&filename, &unifilename) )
- {
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
+ if (!udf_CS0toUTF8(&filename, &unifilename)) {
udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
return 0;
}
- }
- else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
- {
- if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) )
- {
+ } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
+ if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename)) {
udf_debug("Failed in udf_get_filename: sname = %s\n", sname);
return 0;
}
- }
- else
+ } else {
return 0;
+ }
- if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
- unifilename.u_name, unifilename.u_len)))
- {
+ len = udf_translate_to_linux(dname, filename.u_name, filename.u_len,
+ unifilename.u_name, unifilename.u_len);
+ if (len) {
return len;
}
+
return 0;
}
-int udf_put_filename(struct super_block *sb, const uint8_t *sname, uint8_t *dname, int flen)
+int udf_put_filename(struct super_block *sb, const uint8_t *sname,
+ uint8_t *dname, int flen)
{
struct ustr unifilename;
int namelen;
- if ( !(udf_char_to_ustr(&unifilename, sname, flen)) )
- {
+ if (!(udf_char_to_ustr(&unifilename, sname, flen))) {
return 0;
}
- if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8))
- {
- if ( !(namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN)) )
- {
+ if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
+ namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN);
+ if (!namelen) {
return 0;
}
- }
- else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
- {
- if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN)) )
- {
+ } else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) {
+ namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN);
+ if (!namelen) {
return 0;
}
- }
- else
+ } else {
return 0;
+ }
return namelen;
}
#define ILLEGAL_CHAR_MARK '_'
-#define EXT_MARK '.'
-#define CRC_MARK '#'
-#define EXT_SIZE 5
+#define EXT_MARK '.'
+#define CRC_MARK '#'
+#define EXT_SIZE 5
-static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen)
+static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen,
+ uint8_t *fidName, int fidNameLen)
{
- int index, newIndex = 0, needsCRC = 0;
+ int index, newIndex = 0, needsCRC = 0;
int extIndex = 0, newExtIndex = 0, hasExt = 0;
unsigned short valueCRC;
uint8_t curr;
const uint8_t hexChar[] = "0123456789ABCDEF";
- if (udfName[0] == '.' && (udfLen == 1 ||
- (udfLen == 2 && udfName[1] == '.')))
- {
+ if (udfName[0] == '.' &&
+ (udfLen == 1 || (udfLen == 2 && udfName[1] == '.'))) {
needsCRC = 1;
newIndex = udfLen;
memcpy(newName, udfName, udfLen);
- }
- else
- {
- for (index = 0; index < udfLen; index++)
- {
+ } else {
+ for (index = 0; index < udfLen; index++) {
curr = udfName[index];
- if (curr == '/' || curr == 0)
- {
+ if (curr == '/' || curr == 0) {
needsCRC = 1;
curr = ILLEGAL_CHAR_MARK;
- while (index+1 < udfLen && (udfName[index+1] == '/' ||
- udfName[index+1] == 0))
+ while (index + 1 < udfLen && (udfName[index + 1] == '/' ||
+ udfName[index + 1] == 0))
index++;
- }
- if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE)
- {
- if (udfLen == index + 1)
+ } if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE) {
+ if (udfLen == index + 1) {
hasExt = 0;
- else
- {
+ } else {
hasExt = 1;
extIndex = index;
newExtIndex = newIndex;
@@ -461,26 +427,22 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
needsCRC = 1;
}
}
- if (needsCRC)
- {
+ if (needsCRC) {
uint8_t ext[EXT_SIZE];
int localExtIndex = 0;
- if (hasExt)
- {
+ if (hasExt) {
int maxFilenameLen;
- for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen;
- index++ )
- {
+ for(index = 0; index < EXT_SIZE && extIndex + index + 1 < udfLen; index++) {
curr = udfName[extIndex + index + 1];
- if (curr == '/' || curr == 0)
- {
+ if (curr == '/' || curr == 0) {
needsCRC = 1;
curr = ILLEGAL_CHAR_MARK;
- while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE
- && (udfName[extIndex + index + 2] == '/' ||
- udfName[extIndex + index + 2] == 0)))
+ while(extIndex + index + 2 < udfLen &&
+ (index + 1 < EXT_SIZE
+ && (udfName[extIndex + index + 2] == '/' ||
+ udfName[extIndex + index + 2] == 0)))
index++;
}
ext[localExtIndex++] = curr;
@@ -490,9 +452,9 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
newIndex = maxFilenameLen;
else
newIndex = newExtIndex;
- }
- else if (newIndex > 250)
+ } else if (newIndex > 250) {
newIndex = 250;
+ }
newName[newIndex++] = CRC_MARK;
valueCRC = udf_crc(fidName, fidNameLen, 0);
newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12];
@@ -500,12 +462,12 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen
newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4];
newName[newIndex++] = hexChar[(valueCRC & 0x000f)];
- if (hasExt)
- {
+ if (hasExt) {
newName[newIndex++] = EXT_MARK;
- for (index = 0;index < localExtIndex ;index++ )
+ for (index = 0; index < localExtIndex; index++)
newName[newIndex++] = ext[index];
}
}
+
return newIndex;
}
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 22ff6ed55ce9..73402c5eeb8a 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -87,6 +87,7 @@
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/vfs.h>
+#include <linux/log2.h>
#include "swab.h"
#include "util.h"
@@ -854,7 +855,7 @@ magic_found:
uspi->s_fmask = fs32_to_cpu(sb, usb1->fs_fmask);
uspi->s_fshift = fs32_to_cpu(sb, usb1->fs_fshift);
- if (uspi->s_fsize & (uspi->s_fsize - 1)) {
+ if (!is_power_of_2(uspi->s_fsize)) {
printk(KERN_ERR "ufs_read_super: fragment size %u is not a power of 2\n",
uspi->s_fsize);
goto failed;
@@ -869,7 +870,7 @@ magic_found:
uspi->s_fsize);
goto failed;
}
- if (uspi->s_bsize & (uspi->s_bsize - 1)) {
+ if (!is_power_of_2(uspi->s_bsize)) {
printk(KERN_ERR "ufs_read_super: block size %u is not a power of 2\n",
uspi->s_bsize);
goto failed;
@@ -1239,14 +1240,14 @@ static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flag
inode_init_once(&ei->vfs_inode);
}
-
+
static int init_inodecache(void)
{
ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
sizeof(struct ufs_inode_info),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (ufs_inode_cachep == NULL)
return -ENOMEM;
return 0;
diff --git a/fs/utimes.c b/fs/utimes.c
index b3c88952465f..682eb63b20ad 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -106,7 +106,7 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
if (IS_IMMUTABLE(inode))
goto dput_and_out;
- if (current->fsuid != inode->i_uid) {
+ if (!is_owner_or_cap(inode)) {
if (f) {
if (!(f->f_mode & FMODE_WRITE))
goto dput_and_out;
diff --git a/fs/xattr.c b/fs/xattr.c
index 4523aca79659..a44fd92caca3 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -60,8 +60,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
return -EPERM;
if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
- (mask & MAY_WRITE) && (current->fsuid != inode->i_uid) &&
- !capable(CAP_FOWNER))
+ (mask & MAY_WRITE) && !is_owner_or_cap(inode))
return -EPERM;
}
diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6
index b49989bb89ad..e7a9a83f0087 100644
--- a/fs/xfs/Makefile-linux-2.6
+++ b/fs/xfs/Makefile-linux-2.6
@@ -64,6 +64,7 @@ xfs-y += xfs_alloc.o \
xfs_dir2_sf.o \
xfs_error.o \
xfs_extfree_item.o \
+ xfs_filestream.o \
xfs_fsops.o \
xfs_ialloc.o \
xfs_ialloc_btree.o \
@@ -77,6 +78,7 @@ xfs-y += xfs_alloc.o \
xfs_log.o \
xfs_log_recover.o \
xfs_mount.o \
+ xfs_mru_cache.o \
xfs_rename.o \
xfs_trans.o \
xfs_trans_ail.o \
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h
index 9ebabdf7829c..b4acc7f3c374 100644
--- a/fs/xfs/linux-2.6/kmem.h
+++ b/fs/xfs/linux-2.6/kmem.h
@@ -74,14 +74,14 @@ extern void kmem_free(void *, size_t);
static inline kmem_zone_t *
kmem_zone_init(int size, char *zone_name)
{
- return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL);
+ return kmem_cache_create(zone_name, size, 0, 0, NULL);
}
static inline kmem_zone_t *
kmem_zone_init_flags(int size, char *zone_name, unsigned long flags,
void (*construct)(void *, kmem_zone_t *, unsigned long))
{
- return kmem_cache_create(zone_name, size, 0, flags, construct, NULL);
+ return kmem_cache_create(zone_name, size, 0, flags, construct);
}
static inline void
@@ -100,25 +100,6 @@ kmem_zone_destroy(kmem_zone_t *zone)
extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
extern void *kmem_zone_zalloc(kmem_zone_t *, unsigned int __nocast);
-/*
- * Low memory cache shrinkers
- */
-
-typedef struct shrinker *kmem_shaker_t;
-typedef int (*kmem_shake_func_t)(int, gfp_t);
-
-static inline kmem_shaker_t
-kmem_shake_register(kmem_shake_func_t sfunc)
-{
- return set_shrinker(DEFAULT_SEEKS, sfunc);
-}
-
-static inline void
-kmem_shake_deregister(kmem_shaker_t shrinker)
-{
- remove_shrinker(shrinker);
-}
-
static inline int
kmem_shake_allow(gfp_t gfp_mask)
{
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 7361861e3aac..fd4105d662e0 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -108,14 +108,19 @@ xfs_page_trace(
/*
* Schedule IO completion handling on a xfsdatad if this was
- * the final hold on this ioend.
+ * the final hold on this ioend. If we are asked to wait,
+ * flush the workqueue.
*/
STATIC void
xfs_finish_ioend(
- xfs_ioend_t *ioend)
+ xfs_ioend_t *ioend,
+ int wait)
{
- if (atomic_dec_and_test(&ioend->io_remaining))
+ if (atomic_dec_and_test(&ioend->io_remaining)) {
queue_work(xfsdatad_workqueue, &ioend->io_work);
+ if (wait)
+ flush_workqueue(xfsdatad_workqueue);
+ }
}
/*
@@ -156,6 +161,8 @@ xfs_setfilesize(
xfs_fsize_t bsize;
ip = xfs_vtoi(ioend->io_vnode);
+ if (!ip)
+ return;
ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
ASSERT(ioend->io_type != IOMAP_READ);
@@ -334,7 +341,7 @@ xfs_end_bio(
bio->bi_end_io = NULL;
bio_put(bio);
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
return 0;
}
@@ -470,7 +477,7 @@ xfs_submit_ioend(
}
if (bio)
xfs_submit_ioend_bio(ioend, bio);
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
} while ((ioend = next) != NULL);
}
@@ -1003,6 +1010,8 @@ xfs_page_state_convert(
if (buffer_unwritten(bh) || buffer_delay(bh) ||
((buffer_uptodate(bh) || PageUptodate(page)) &&
!buffer_mapped(bh) && (unmapped || startio))) {
+ int new_ioend = 0;
+
/*
* Make sure we don't use a read-only iomap
*/
@@ -1021,6 +1030,15 @@ xfs_page_state_convert(
}
if (!iomap_valid) {
+ /*
+ * if we didn't have a valid mapping then we
+ * need to ensure that we put the new mapping
+ * in a new ioend structure. This needs to be
+ * done to ensure that the ioends correctly
+ * reflect the block mappings at io completion
+ * for unwritten extent conversion.
+ */
+ new_ioend = 1;
if (type == IOMAP_NEW) {
size = xfs_probe_cluster(inode,
page, bh, head, 0);
@@ -1040,7 +1058,7 @@ xfs_page_state_convert(
if (startio) {
xfs_add_to_ioend(inode, bh, offset,
type, &ioend,
- !iomap_valid);
+ new_ioend);
} else {
set_buffer_dirty(bh);
unlock_buffer(bh);
@@ -1416,6 +1434,13 @@ xfs_end_io_direct(
* This is not necessary for synchronous direct I/O, but we do
* it anyway to keep the code uniform and simpler.
*
+ * Well, if only it were that simple. Because synchronous direct I/O
+ * requires extent conversion to occur *before* we return to userspace,
+ * we have to wait for extent conversion to complete. Look at the
+ * iocb that has been passed to us to determine if this is AIO or
+ * not. If it is synchronous, tell xfs_finish_ioend() to kick the
+ * workqueue and wait for it to complete.
+ *
* The core direct I/O code might be changed to always call the
* completion handler in the future, in which case all this can
* go away.
@@ -1423,9 +1448,9 @@ xfs_end_io_direct(
ioend->io_offset = offset;
ioend->io_size = size;
if (ioend->io_type == IOMAP_READ) {
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
} else if (private && size > 0) {
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, is_sync_kiocb(iocb));
} else {
/*
* A direct I/O write ioend starts it's life in unwritten
@@ -1434,7 +1459,7 @@ xfs_end_io_direct(
* handler.
*/
INIT_WORK(&ioend->io_work, xfs_end_bio_written);
- xfs_finish_ioend(ioend);
+ xfs_finish_ioend(ioend, 0);
}
/*
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index fe4f66a5af14..b0f0e58866de 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -35,10 +35,13 @@
#include <linux/freezer.h>
static kmem_zone_t *xfs_buf_zone;
-static kmem_shaker_t xfs_buf_shake;
STATIC int xfsbufd(void *);
STATIC int xfsbufd_wakeup(int, gfp_t);
STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int);
+static struct shrinker xfs_buf_shake = {
+ .shrink = xfsbufd_wakeup,
+ .seeks = DEFAULT_SEEKS,
+};
static struct workqueue_struct *xfslogd_workqueue;
struct workqueue_struct *xfsdatad_workqueue;
@@ -314,7 +317,7 @@ xfs_buf_free(
ASSERT(list_empty(&bp->b_hash_list));
- if (bp->b_flags & _XBF_PAGE_CACHE) {
+ if (bp->b_flags & (_XBF_PAGE_CACHE|_XBF_PAGES)) {
uint i;
if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1))
@@ -323,18 +326,11 @@ xfs_buf_free(
for (i = 0; i < bp->b_page_count; i++) {
struct page *page = bp->b_pages[i];
- ASSERT(!PagePrivate(page));
+ if (bp->b_flags & _XBF_PAGE_CACHE)
+ ASSERT(!PagePrivate(page));
page_cache_release(page);
}
_xfs_buf_free_pages(bp);
- } else if (bp->b_flags & _XBF_KMEM_ALLOC) {
- /*
- * XXX(hch): bp->b_count_desired might be incorrect (see
- * xfs_buf_associate_memory for details), but fortunately
- * the Linux version of kmem_free ignores the len argument..
- */
- kmem_free(bp->b_addr, bp->b_count_desired);
- _xfs_buf_free_pages(bp);
}
xfs_buf_deallocate(bp);
@@ -764,43 +760,44 @@ xfs_buf_get_noaddr(
size_t len,
xfs_buftarg_t *target)
{
- size_t malloc_len = len;
+ unsigned long page_count = PAGE_ALIGN(len) >> PAGE_SHIFT;
+ int error, i;
xfs_buf_t *bp;
- void *data;
- int error;
bp = xfs_buf_allocate(0);
if (unlikely(bp == NULL))
goto fail;
_xfs_buf_initialize(bp, target, 0, len, 0);
- try_again:
- data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL | KM_LARGE);
- if (unlikely(data == NULL))
+ error = _xfs_buf_get_pages(bp, page_count, 0);
+ if (error)
goto fail_free_buf;
- /* check whether alignment matches.. */
- if ((__psunsigned_t)data !=
- ((__psunsigned_t)data & ~target->bt_smask)) {
- /* .. else double the size and try again */
- kmem_free(data, malloc_len);
- malloc_len <<= 1;
- goto try_again;
+ for (i = 0; i < page_count; i++) {
+ bp->b_pages[i] = alloc_page(GFP_KERNEL);
+ if (!bp->b_pages[i])
+ goto fail_free_mem;
}
+ bp->b_flags |= _XBF_PAGES;
- error = xfs_buf_associate_memory(bp, data, len);
- if (error)
+ error = _xfs_buf_map_pages(bp, XBF_MAPPED);
+ if (unlikely(error)) {
+ printk(KERN_WARNING "%s: failed to map pages\n",
+ __FUNCTION__);
goto fail_free_mem;
- bp->b_flags |= _XBF_KMEM_ALLOC;
+ }
xfs_buf_unlock(bp);
- XB_TRACE(bp, "no_daddr", data);
+ XB_TRACE(bp, "no_daddr", len);
return bp;
+
fail_free_mem:
- kmem_free(data, malloc_len);
+ while (--i >= 0)
+ __free_page(bp->b_pages[i]);
+ _xfs_buf_free_pages(bp);
fail_free_buf:
- xfs_buf_free(bp);
+ xfs_buf_deallocate(bp);
fail:
return NULL;
}
@@ -1453,6 +1450,7 @@ xfs_free_buftarg(
int external)
{
xfs_flush_buftarg(btp, 1);
+ xfs_blkdev_issue_flush(btp);
if (external)
xfs_blkdev_put(btp->bt_bdev);
xfs_free_bufhash(btp);
@@ -1837,14 +1835,9 @@ xfs_buf_init(void)
if (!xfsdatad_workqueue)
goto out_destroy_xfslogd_workqueue;
- xfs_buf_shake = kmem_shake_register(xfsbufd_wakeup);
- if (!xfs_buf_shake)
- goto out_destroy_xfsdatad_workqueue;
-
+ register_shrinker(&xfs_buf_shake);
return 0;
- out_destroy_xfsdatad_workqueue:
- destroy_workqueue(xfsdatad_workqueue);
out_destroy_xfslogd_workqueue:
destroy_workqueue(xfslogd_workqueue);
out_free_buf_zone:
@@ -1859,7 +1852,7 @@ xfs_buf_init(void)
void
xfs_buf_terminate(void)
{
- kmem_shake_deregister(xfs_buf_shake);
+ unregister_shrinker(&xfs_buf_shake);
destroy_workqueue(xfsdatad_workqueue);
destroy_workqueue(xfslogd_workqueue);
kmem_zone_destroy(xfs_buf_zone);
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index b6241f6201a5..b5908a34b15d 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -63,7 +63,7 @@ typedef enum {
/* flags used only internally */
_XBF_PAGE_CACHE = (1 << 17),/* backed by pagecache */
- _XBF_KMEM_ALLOC = (1 << 18),/* backed by kmem_alloc() */
+ _XBF_PAGES = (1 << 18), /* backed by refcounted pages */
_XBF_RUN_QUEUES = (1 << 19),/* run block device task queue */
_XBF_DELWRI_Q = (1 << 21), /* buffer on delwri queue */
} xfs_buf_flags_t;
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 8c43cd2e237a..0d4001eafd16 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -184,15 +184,6 @@ xfs_file_open(
}
STATIC int
-xfs_file_close(
- struct file *filp,
- fl_owner_t id)
-{
- return -bhv_vop_close(vn_from_inode(filp->f_path.dentry->d_inode), 0,
- file_count(filp) > 1 ? L_FALSE : L_TRUE, NULL);
-}
-
-STATIC int
xfs_file_release(
struct inode *inode,
struct file *filp)
@@ -221,19 +212,18 @@ xfs_file_fsync(
}
#ifdef CONFIG_XFS_DMAPI
-STATIC struct page *
-xfs_vm_nopage(
- struct vm_area_struct *area,
- unsigned long address,
- int *type)
+STATIC int
+xfs_vm_fault(
+ struct vm_area_struct *vma,
+ struct vm_fault *vmf)
{
- struct inode *inode = area->vm_file->f_path.dentry->d_inode;
+ struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
- if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), area, 0))
- return NULL;
- return filemap_nopage(area, address, type);
+ if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), vma, 0))
+ return VM_FAULT_SIGBUS;
+ return filemap_fault(vma, vmf);
}
#endif /* CONFIG_XFS_DMAPI */
@@ -319,6 +309,7 @@ xfs_file_mmap(
struct vm_area_struct *vma)
{
vma->vm_ops = &xfs_file_vm_ops;
+ vma->vm_flags |= VM_CAN_NONLINEAR;
#ifdef CONFIG_XFS_DMAPI
if (vn_from_inode(filp->f_path.dentry->d_inode)->v_vfsp->vfs_flag & VFS_DMI)
@@ -422,6 +413,20 @@ xfs_file_open_exec(
}
#endif /* HAVE_FOP_OPEN_EXEC */
+/*
+ * mmap()d file has taken write protection fault and is being made
+ * writable. We can set the page state up correctly for a writable
+ * page, which means we can do correct delalloc accounting (ENOSPC
+ * checking!) and unwritten extent mapping.
+ */
+STATIC int
+xfs_vm_page_mkwrite(
+ struct vm_area_struct *vma,
+ struct page *page)
+{
+ return block_page_mkwrite(vma, page, xfs_get_blocks);
+}
+
const struct file_operations xfs_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
@@ -436,7 +441,6 @@ const struct file_operations xfs_file_operations = {
#endif
.mmap = xfs_file_mmap,
.open = xfs_file_open,
- .flush = xfs_file_close,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
#ifdef HAVE_FOP_OPEN_EXEC
@@ -458,7 +462,6 @@ const struct file_operations xfs_invis_file_operations = {
#endif
.mmap = xfs_file_mmap,
.open = xfs_file_open,
- .flush = xfs_file_close,
.release = xfs_file_release,
.fsync = xfs_file_fsync,
};
@@ -475,14 +478,14 @@ const struct file_operations xfs_dir_file_operations = {
};
static struct vm_operations_struct xfs_file_vm_ops = {
- .nopage = filemap_nopage,
- .populate = filemap_populate,
+ .fault = filemap_fault,
+ .page_mkwrite = xfs_vm_page_mkwrite,
};
#ifdef CONFIG_XFS_DMAPI
static struct vm_operations_struct xfs_dmapi_file_vm_ops = {
- .nopage = xfs_vm_nopage,
- .populate = filemap_populate,
+ .fault = xfs_vm_fault,
+ .page_mkwrite = xfs_vm_page_mkwrite,
#ifdef HAVE_VMOP_MPROTECT
.mprotect = xfs_vm_mprotect,
#endif
diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c
index ed3a5e1b4b67..bb72c3d4141f 100644
--- a/fs/xfs/linux-2.6/xfs_globals.c
+++ b/fs/xfs/linux-2.6/xfs_globals.c
@@ -46,6 +46,7 @@ xfs_param_t xfs_params = {
.inherit_nosym = { 0, 0, 1 },
.rotorstep = { 1, 1, 255 },
.inherit_nodfrg = { 0, 1, 1 },
+ .fstrm_timer = { 1, 50, 3600*100},
};
/*
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index ff5c41ff8d40..5917808abbd6 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -1019,7 +1019,7 @@ xfs_ioc_bulkstat(
if (cmd == XFS_IOC_FSINUMBERS)
error = xfs_inumbers(mp, &inlast, &count,
- bulkreq.ubuffer);
+ bulkreq.ubuffer, xfs_inumbers_fmt);
else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE)
error = xfs_bulkstat_single(mp, &inlast,
bulkreq.ubuffer, &done);
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index b83cebc165f1..141cf15067c2 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -23,10 +23,25 @@
#include <linux/fs.h>
#include <asm/uaccess.h>
#include "xfs.h"
-#include "xfs_types.h"
#include "xfs_fs.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_dir2.h"
+#include "xfs_dmapi.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dir2_sf.h"
#include "xfs_vfs.h"
#include "xfs_vnode.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_itable.h"
+#include "xfs_error.h"
#include "xfs_dfrag.h"
#define _NATIVE_IOC(cmd, type) \
@@ -34,6 +49,7 @@
#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
#define BROKEN_X86_ALIGNMENT
+#define _PACKED __attribute__((packed))
/* on ia32 l_start is on a 32-bit boundary */
typedef struct xfs_flock64_32 {
__s16 l_type;
@@ -75,35 +91,276 @@ xfs_ioctl32_flock(
return (unsigned long)p;
}
+typedef struct compat_xfs_fsop_geom_v1 {
+ __u32 blocksize; /* filesystem (data) block size */
+ __u32 rtextsize; /* realtime extent size */
+ __u32 agblocks; /* fsblocks in an AG */
+ __u32 agcount; /* number of allocation groups */
+ __u32 logblocks; /* fsblocks in the log */
+ __u32 sectsize; /* (data) sector size, bytes */
+ __u32 inodesize; /* inode size in bytes */
+ __u32 imaxpct; /* max allowed inode space(%) */
+ __u64 datablocks; /* fsblocks in data subvolume */
+ __u64 rtblocks; /* fsblocks in realtime subvol */
+ __u64 rtextents; /* rt extents in realtime subvol*/
+ __u64 logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ __u32 sunit; /* stripe unit, fsblocks */
+ __u32 swidth; /* stripe width, fsblocks */
+ __s32 version; /* structure version */
+ __u32 flags; /* superblock version flags */
+ __u32 logsectsize; /* log sector size, bytes */
+ __u32 rtsectsize; /* realtime sector size, bytes */
+ __u32 dirblocksize; /* directory block size, bytes */
+} __attribute__((packed)) compat_xfs_fsop_geom_v1_t;
+
+#define XFS_IOC_FSGEOMETRY_V1_32 \
+ _IOR ('X', 100, struct compat_xfs_fsop_geom_v1)
+
+STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg)
+{
+ compat_xfs_fsop_geom_v1_t __user *p32 = (void __user *)arg;
+ xfs_fsop_geom_v1_t __user *p = compat_alloc_user_space(sizeof(*p));
+
+ if (copy_in_user(p, p32, sizeof(*p32)))
+ return -EFAULT;
+ return (unsigned long)p;
+}
+
+typedef struct compat_xfs_inogrp {
+ __u64 xi_startino; /* starting inode number */
+ __s32 xi_alloccount; /* # bits set in allocmask */
+ __u64 xi_allocmask; /* mask of allocated inodes */
+} __attribute__((packed)) compat_xfs_inogrp_t;
+
+STATIC int xfs_inumbers_fmt_compat(
+ void __user *ubuffer,
+ const xfs_inogrp_t *buffer,
+ long count,
+ long *written)
+{
+ compat_xfs_inogrp_t *p32 = ubuffer;
+ long i;
+
+ for (i = 0; i < count; i++) {
+ if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) ||
+ put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) ||
+ put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask))
+ return -EFAULT;
+ }
+ *written = count * sizeof(*p32);
+ return 0;
+}
+
#else
-typedef struct xfs_fsop_bulkreq32 {
+#define xfs_inumbers_fmt_compat xfs_inumbers_fmt
+#define _PACKED
+
+#endif
+
+/* XFS_IOC_FSBULKSTAT and friends */
+
+typedef struct compat_xfs_bstime {
+ __s32 tv_sec; /* seconds */
+ __s32 tv_nsec; /* and nanoseconds */
+} compat_xfs_bstime_t;
+
+STATIC int xfs_bstime_store_compat(
+ compat_xfs_bstime_t __user *p32,
+ const xfs_bstime_t *p)
+{
+ __s32 sec32;
+
+ sec32 = p->tv_sec;
+ if (put_user(sec32, &p32->tv_sec) ||
+ put_user(p->tv_nsec, &p32->tv_nsec))
+ return -EFAULT;
+ return 0;
+}
+
+typedef struct compat_xfs_bstat {
+ __u64 bs_ino; /* inode number */
+ __u16 bs_mode; /* type and mode */
+ __u16 bs_nlink; /* number of links */
+ __u32 bs_uid; /* user id */
+ __u32 bs_gid; /* group id */
+ __u32 bs_rdev; /* device value */
+ __s32 bs_blksize; /* block size */
+ __s64 bs_size; /* file size */
+ compat_xfs_bstime_t bs_atime; /* access time */
+ compat_xfs_bstime_t bs_mtime; /* modify time */
+ compat_xfs_bstime_t bs_ctime; /* inode change time */
+ int64_t bs_blocks; /* number of blocks */
+ __u32 bs_xflags; /* extended flags */
+ __s32 bs_extsize; /* extent size */
+ __s32 bs_extents; /* number of extents */
+ __u32 bs_gen; /* generation count */
+ __u16 bs_projid; /* project id */
+ unsigned char bs_pad[14]; /* pad space, unused */
+ __u32 bs_dmevmask; /* DMIG event mask */
+ __u16 bs_dmstate; /* DMIG state info */
+ __u16 bs_aextents; /* attribute number of extents */
+} _PACKED compat_xfs_bstat_t;
+
+STATIC int xfs_bulkstat_one_fmt_compat(
+ void __user *ubuffer,
+ const xfs_bstat_t *buffer)
+{
+ compat_xfs_bstat_t __user *p32 = ubuffer;
+
+ if (put_user(buffer->bs_ino, &p32->bs_ino) ||
+ put_user(buffer->bs_mode, &p32->bs_mode) ||
+ put_user(buffer->bs_nlink, &p32->bs_nlink) ||
+ put_user(buffer->bs_uid, &p32->bs_uid) ||
+ put_user(buffer->bs_gid, &p32->bs_gid) ||
+ put_user(buffer->bs_rdev, &p32->bs_rdev) ||
+ put_user(buffer->bs_blksize, &p32->bs_blksize) ||
+ put_user(buffer->bs_size, &p32->bs_size) ||
+ xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) ||
+ xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) ||
+ xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) ||
+ put_user(buffer->bs_blocks, &p32->bs_blocks) ||
+ put_user(buffer->bs_xflags, &p32->bs_xflags) ||
+ put_user(buffer->bs_extsize, &p32->bs_extsize) ||
+ put_user(buffer->bs_extents, &p32->bs_extents) ||
+ put_user(buffer->bs_gen, &p32->bs_gen) ||
+ put_user(buffer->bs_projid, &p32->bs_projid) ||
+ put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) ||
+ put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
+ put_user(buffer->bs_aextents, &p32->bs_aextents))
+ return -EFAULT;
+ return sizeof(*p32);
+}
+
+
+
+typedef struct compat_xfs_fsop_bulkreq {
compat_uptr_t lastip; /* last inode # pointer */
__s32 icount; /* count of entries in buffer */
compat_uptr_t ubuffer; /* user buffer for inode desc. */
- __s32 ocount; /* output count pointer */
-} xfs_fsop_bulkreq32_t;
+ compat_uptr_t ocount; /* output count pointer */
+} compat_xfs_fsop_bulkreq_t;
-STATIC unsigned long
-xfs_ioctl32_bulkstat(
- unsigned long arg)
+#define XFS_IOC_FSBULKSTAT_32 \
+ _IOWR('X', 101, struct compat_xfs_fsop_bulkreq)
+#define XFS_IOC_FSBULKSTAT_SINGLE_32 \
+ _IOWR('X', 102, struct compat_xfs_fsop_bulkreq)
+#define XFS_IOC_FSINUMBERS_32 \
+ _IOWR('X', 103, struct compat_xfs_fsop_bulkreq)
+
+/* copied from xfs_ioctl.c */
+STATIC int
+xfs_ioc_bulkstat_compat(
+ xfs_mount_t *mp,
+ unsigned int cmd,
+ void __user *arg)
{
- xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg;
- xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p));
+ compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg;
u32 addr;
+ xfs_fsop_bulkreq_t bulkreq;
+ int count; /* # of records returned */
+ xfs_ino_t inlast; /* last inode number */
+ int done;
+ int error;
+
+ /* done = 1 if there are more stats to get and if bulkstat */
+ /* should be called again (unused here, but used in dmapi) */
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (XFS_FORCED_SHUTDOWN(mp))
+ return -XFS_ERROR(EIO);
+
+ if (get_user(addr, &p32->lastip))
+ return -EFAULT;
+ bulkreq.lastip = compat_ptr(addr);
+ if (get_user(bulkreq.icount, &p32->icount) ||
+ get_user(addr, &p32->ubuffer))
+ return -EFAULT;
+ bulkreq.ubuffer = compat_ptr(addr);
+ if (get_user(addr, &p32->ocount))
+ return -EFAULT;
+ bulkreq.ocount = compat_ptr(addr);
+
+ if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64)))
+ return -XFS_ERROR(EFAULT);
+
+ if ((count = bulkreq.icount) <= 0)
+ return -XFS_ERROR(EINVAL);
+
+ if (cmd == XFS_IOC_FSINUMBERS)
+ error = xfs_inumbers(mp, &inlast, &count,
+ bulkreq.ubuffer, xfs_inumbers_fmt_compat);
+ else {
+ /* declare a var to get a warning in case the type changes */
+ bulkstat_one_fmt_pf formatter = xfs_bulkstat_one_fmt_compat;
+ error = xfs_bulkstat(mp, &inlast, &count,
+ xfs_bulkstat_one, formatter,
+ sizeof(compat_xfs_bstat_t), bulkreq.ubuffer,
+ BULKSTAT_FG_QUICK, &done);
+ }
+ if (error)
+ return -error;
+
+ if (bulkreq.ocount != NULL) {
+ if (copy_to_user(bulkreq.lastip, &inlast,
+ sizeof(xfs_ino_t)))
+ return -XFS_ERROR(EFAULT);
+
+ if (copy_to_user(bulkreq.ocount, &count, sizeof(count)))
+ return -XFS_ERROR(EFAULT);
+ }
+
+ return 0;
+}
+
+
+
+typedef struct compat_xfs_fsop_handlereq {
+ __u32 fd; /* fd for FD_TO_HANDLE */
+ compat_uptr_t path; /* user pathname */
+ __u32 oflags; /* open flags */
+ compat_uptr_t ihandle; /* user supplied handle */
+ __u32 ihandlen; /* user supplied length */
+ compat_uptr_t ohandle; /* user buffer for handle */
+ compat_uptr_t ohandlen; /* user buffer length */
+} compat_xfs_fsop_handlereq_t;
+
+#define XFS_IOC_PATH_TO_FSHANDLE_32 \
+ _IOWR('X', 104, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_PATH_TO_HANDLE_32 \
+ _IOWR('X', 105, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_FD_TO_HANDLE_32 \
+ _IOWR('X', 106, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_OPEN_BY_HANDLE_32 \
+ _IOWR('X', 107, struct compat_xfs_fsop_handlereq)
+#define XFS_IOC_READLINK_BY_HANDLE_32 \
+ _IOWR('X', 108, struct compat_xfs_fsop_handlereq)
+
+STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg)
+{
+ compat_xfs_fsop_handlereq_t __user *p32 = (void __user *)arg;
+ xfs_fsop_handlereq_t __user *p = compat_alloc_user_space(sizeof(*p));
+ u32 addr;
- if (get_user(addr, &p32->lastip) ||
- put_user(compat_ptr(addr), &p->lastip) ||
- copy_in_user(&p->icount, &p32->icount, sizeof(s32)) ||
- get_user(addr, &p32->ubuffer) ||
- put_user(compat_ptr(addr), &p->ubuffer) ||
- get_user(addr, &p32->ocount) ||
- put_user(compat_ptr(addr), &p->ocount))
+ if (copy_in_user(&p->fd, &p32->fd, sizeof(__u32)) ||
+ get_user(addr, &p32->path) ||
+ put_user(compat_ptr(addr), &p->path) ||
+ copy_in_user(&p->oflags, &p32->oflags, sizeof(__u32)) ||
+ get_user(addr, &p32->ihandle) ||
+ put_user(compat_ptr(addr), &p->ihandle) ||
+ copy_in_user(&p->ihandlen, &p32->ihandlen, sizeof(__u32)) ||
+ get_user(addr, &p32->ohandle) ||
+ put_user(compat_ptr(addr), &p->ohandle) ||
+ get_user(addr, &p32->ohandlen) ||
+ put_user(compat_ptr(addr), &p->ohandlen))
return -EFAULT;
return (unsigned long)p;
}
-#endif
+
STATIC long
xfs_compat_ioctl(
@@ -118,7 +375,6 @@ xfs_compat_ioctl(
switch (cmd) {
case XFS_IOC_DIOINFO:
- case XFS_IOC_FSGEOMETRY_V1:
case XFS_IOC_FSGEOMETRY:
case XFS_IOC_GETVERSION:
case XFS_IOC_GETXFLAGS:
@@ -131,12 +387,7 @@ xfs_compat_ioctl(
case XFS_IOC_GETBMAPA:
case XFS_IOC_GETBMAPX:
/* not handled
- case XFS_IOC_FD_TO_HANDLE:
- case XFS_IOC_PATH_TO_HANDLE:
- case XFS_IOC_PATH_TO_FSHANDLE:
- case XFS_IOC_OPEN_BY_HANDLE:
case XFS_IOC_FSSETDM_BY_HANDLE:
- case XFS_IOC_READLINK_BY_HANDLE:
case XFS_IOC_ATTRLIST_BY_HANDLE:
case XFS_IOC_ATTRMULTI_BY_HANDLE:
*/
@@ -166,6 +417,10 @@ xfs_compat_ioctl(
arg = xfs_ioctl32_flock(arg);
cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
break;
+ case XFS_IOC_FSGEOMETRY_V1_32:
+ arg = xfs_ioctl32_geom_v1(arg);
+ cmd = _NATIVE_IOC(cmd, struct xfs_fsop_geom_v1);
+ break;
#else /* These are handled fine if no alignment issues */
case XFS_IOC_ALLOCSP:
@@ -176,18 +431,28 @@ xfs_compat_ioctl(
case XFS_IOC_FREESP64:
case XFS_IOC_RESVSP64:
case XFS_IOC_UNRESVSP64:
+ case XFS_IOC_FSGEOMETRY_V1:
break;
/* xfs_bstat_t still has wrong u32 vs u64 alignment */
case XFS_IOC_SWAPEXT:
break;
- case XFS_IOC_FSBULKSTAT_SINGLE:
- case XFS_IOC_FSBULKSTAT:
- case XFS_IOC_FSINUMBERS:
- arg = xfs_ioctl32_bulkstat(arg);
- break;
#endif
+ case XFS_IOC_FSBULKSTAT_32:
+ case XFS_IOC_FSBULKSTAT_SINGLE_32:
+ case XFS_IOC_FSINUMBERS_32:
+ cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq);
+ return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount,
+ cmd, (void*)arg);
+ case XFS_IOC_FD_TO_HANDLE_32:
+ case XFS_IOC_PATH_TO_HANDLE_32:
+ case XFS_IOC_PATH_TO_FSHANDLE_32:
+ case XFS_IOC_OPEN_BY_HANDLE_32:
+ case XFS_IOC_READLINK_BY_HANDLE_32:
+ arg = xfs_ioctl32_fshandle(arg);
+ cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq);
+ break;
default:
return -ENOIOCTLCMD;
}
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index af24a457d3a3..330c4ba9d404 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -123,6 +123,7 @@
#define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
#define xfs_rotorstep xfs_params.rotorstep.val
#define xfs_inherit_nodefrag xfs_params.inherit_nodfrg.val
+#define xfs_fstrm_centisecs xfs_params.fstrm_timer.val
#define current_cpu() (raw_smp_processor_id())
#define current_pid() (current->pid)
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index bf9a9d5909be..4528f9a3f304 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -547,7 +547,8 @@ vfs_sync_worker(
if (!(vfsp->vfs_flag & VFS_RDONLY))
error = bhv_vfs_sync(vfsp, SYNC_FSDATA | SYNC_BDFLUSH | \
- SYNC_ATTR | SYNC_REFCACHE, NULL);
+ SYNC_ATTR | SYNC_REFCACHE | SYNC_SUPER,
+ NULL);
vfsp->vfs_sync_seq++;
wake_up(&vfsp->vfs_wait_single_sync_task);
}
@@ -561,6 +562,7 @@ xfssyncd(
bhv_vfs_sync_work_t *work, *n;
LIST_HEAD (tmp);
+ set_freezable();
timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10);
for (;;) {
timeleft = schedule_timeout_interruptible(timeleft);
@@ -663,7 +665,7 @@ xfs_fs_sync_super(
* occur here so don't bother flushing the buftarg (i.e
* SYNC_QUIESCE) because it'll just get dirty again.
*/
- flags = SYNC_FSDATA | SYNC_DELWRI | SYNC_WAIT | SYNC_IOWAIT;
+ flags = SYNC_DATA_QUIESCE;
} else
flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0);
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h
index 33dd1ca13245..201cc3273c84 100644
--- a/fs/xfs/linux-2.6/xfs_super.h
+++ b/fs/xfs/linux-2.6/xfs_super.h
@@ -18,6 +18,8 @@
#ifndef __XFS_SUPER_H__
#define __XFS_SUPER_H__
+#include <linux/exportfs.h>
+
#ifdef CONFIG_XFS_DMAPI
# define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops)
# define vfs_initdmapi() dmapi_init()
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c
index cd6eaa44aa2b..bb997d75c05c 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.c
+++ b/fs/xfs/linux-2.6/xfs_sysctl.c
@@ -210,6 +210,17 @@ static ctl_table xfs_table[] = {
.extra1 = &xfs_params.inherit_nodfrg.min,
.extra2 = &xfs_params.inherit_nodfrg.max
},
+ {
+ .ctl_name = XFS_FILESTREAM_TIMER,
+ .procname = "filestream_centisecs",
+ .data = &xfs_params.fstrm_timer.val,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &xfs_params.fstrm_timer.min,
+ .extra2 = &xfs_params.fstrm_timer.max,
+ },
/* please keep this the last entry */
#ifdef CONFIG_PROC_FS
{
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.h b/fs/xfs/linux-2.6/xfs_sysctl.h
index a631fb8cc5ac..98b97e399d6f 100644
--- a/fs/xfs/linux-2.6/xfs_sysctl.h
+++ b/fs/xfs/linux-2.6/xfs_sysctl.h
@@ -47,6 +47,7 @@ typedef struct xfs_param {
xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */
xfs_sysctl_val_t rotorstep; /* inode32 AG rotoring control knob */
xfs_sysctl_val_t inherit_nodfrg;/* Inherit the "nodefrag" inode flag. */
+ xfs_sysctl_val_t fstrm_timer; /* Filestream dir-AG assoc'n timeout. */
} xfs_param_t;
/*
@@ -86,6 +87,7 @@ enum {
XFS_INHERIT_NOSYM = 19,
XFS_ROTORSTEP = 20,
XFS_INHERIT_NODFRG = 21,
+ XFS_FILESTREAM_TIMER = 22,
};
extern xfs_param_t xfs_params;
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
index e2c2ce98ab5b..dca3481aaafa 100644
--- a/fs/xfs/linux-2.6/xfs_vfs.h
+++ b/fs/xfs/linux-2.6/xfs_vfs.h
@@ -92,6 +92,21 @@ typedef enum {
#define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */
#define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */
#define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */
+#define SYNC_SUPER 0x0200 /* flush superblock to disk */
+
+/*
+ * When remounting a filesystem read-only or freezing the filesystem,
+ * we have two phases to execute. This first phase is syncing the data
+ * before we quiesce the fielsystem, and the second is flushing all the
+ * inodes out after we've waited for all the transactions created by
+ * the first phase to complete. The second phase uses SYNC_INODE_QUIESCE
+ * to ensure that the inodes are written to their location on disk
+ * rather than just existing in transactions in the log. This means
+ * after a quiesce there is no log replay required to write the inodes
+ * to disk (this is the main difference between a sync and a quiesce).
+ */
+#define SYNC_DATA_QUIESCE (SYNC_DELWRI|SYNC_FSDATA|SYNC_WAIT|SYNC_IOWAIT)
+#define SYNC_INODE_QUIESCE (SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT)
#define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */
#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index 013048a92643..5742d65f0785 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -129,10 +129,7 @@ typedef enum bhv_vchange {
VCHANGE_FLAGS_IOEXCL_COUNT = 4
} bhv_vchange_t;
-typedef enum { L_FALSE, L_TRUE } lastclose_t;
-
typedef int (*vop_open_t)(bhv_desc_t *, struct cred *);
-typedef int (*vop_close_t)(bhv_desc_t *, int, lastclose_t, struct cred *);
typedef ssize_t (*vop_read_t)(bhv_desc_t *, struct kiocb *,
const struct iovec *, unsigned int,
loff_t *, int, struct cred *);
@@ -200,7 +197,6 @@ typedef int (*vop_iflush_t)(bhv_desc_t *, int);
typedef struct bhv_vnodeops {
bhv_position_t vn_position; /* position within behavior chain */
vop_open_t vop_open;
- vop_close_t vop_close;
vop_read_t vop_read;
vop_write_t vop_write;
vop_splice_read_t vop_splice_read;
@@ -245,7 +241,6 @@ typedef struct bhv_vnodeops {
#define VNHEAD(vp) ((vp)->v_bh.bh_first)
#define VOP(op, vp) (*((bhv_vnodeops_t *)VNHEAD(vp)->bd_ops)->op)
#define bhv_vop_open(vp, cr) VOP(vop_open, vp)(VNHEAD(vp),cr)
-#define bhv_vop_close(vp, f,last,cr) VOP(vop_close, vp)(VNHEAD(vp),f,last,cr)
#define bhv_vop_read(vp,file,iov,segs,offset,ioflags,cr) \
VOP(vop_read, vp)(VNHEAD(vp),file,iov,segs,offset,ioflags,cr)
#define bhv_vop_write(vp,file,iov,segs,offset,ioflags,cr) \
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 3e4a8ad8a34c..2d274b23ade5 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -62,10 +62,8 @@ uint ndquot;
kmem_zone_t *qm_dqzone;
kmem_zone_t *qm_dqtrxzone;
-static kmem_shaker_t xfs_qm_shaker;
static cred_t xfs_zerocr;
-static xfs_inode_t xfs_zeroino;
STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int);
STATIC void xfs_qm_list_destroy(xfs_dqlist_t *);
@@ -79,6 +77,11 @@ STATIC int xfs_qm_init_quotainos(xfs_mount_t *);
STATIC int xfs_qm_init_quotainfo(xfs_mount_t *);
STATIC int xfs_qm_shake(int, gfp_t);
+static struct shrinker xfs_qm_shaker = {
+ .shrink = xfs_qm_shake,
+ .seeks = DEFAULT_SEEKS,
+};
+
#ifdef DEBUG
extern mutex_t qcheck_lock;
#endif
@@ -150,7 +153,7 @@ xfs_Gqm_init(void)
} else
xqm->qm_dqzone = qm_dqzone;
- xfs_qm_shaker = kmem_shake_register(xfs_qm_shake);
+ register_shrinker(&xfs_qm_shaker);
/*
* The t_dqinfo portion of transactions.
@@ -182,7 +185,7 @@ xfs_qm_destroy(
ASSERT(xqm != NULL);
ASSERT(xqm->qm_nrefs == 0);
- kmem_shake_deregister(xfs_qm_shaker);
+ unregister_shrinker(&xfs_qm_shaker);
hsize = xqm->qm_dqhashmask + 1;
for (i = 0; i < hsize; i++) {
xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
@@ -1415,7 +1418,7 @@ xfs_qm_qino_alloc(
return error;
}
- if ((error = xfs_dir_ialloc(&tp, &xfs_zeroino, S_IFREG, 1, 0,
+ if ((error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0,
&xfs_zerocr, 0, 1, ip, &committed))) {
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT);
diff --git a/fs/xfs/xfs.h b/fs/xfs/xfs.h
index bf0a12040b13..b5a7d92c6843 100644
--- a/fs/xfs/xfs.h
+++ b/fs/xfs/xfs.h
@@ -38,6 +38,7 @@
#define XFS_RW_TRACE 1
#define XFS_BUF_TRACE 1
#define XFS_VNODE_TRACE 1
+#define XFS_FILESTREAMS_TRACE 1
#endif
#include <linux-2.6/xfs_linux.h>
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index 9ece7f87ec5b..51c09c114a20 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -68,6 +68,7 @@ typedef struct xfs_agf {
__be32 agf_flcount; /* count of blocks in freelist */
__be32 agf_freeblks; /* total free blocks */
__be32 agf_longest; /* longest free space */
+ __be32 agf_btreeblks; /* # of blocks held in AGF btrees */
} xfs_agf_t;
#define XFS_AGF_MAGICNUM 0x00000001
@@ -81,7 +82,8 @@ typedef struct xfs_agf {
#define XFS_AGF_FLCOUNT 0x00000100
#define XFS_AGF_FREEBLKS 0x00000200
#define XFS_AGF_LONGEST 0x00000400
-#define XFS_AGF_NUM_BITS 11
+#define XFS_AGF_BTREEBLKS 0x00000800
+#define XFS_AGF_NUM_BITS 12
#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1)
/* disk block (xfs_daddr_t) in the AG */
@@ -186,12 +188,15 @@ typedef struct xfs_perag
__uint32_t pagf_flcount; /* count of blocks in freelist */
xfs_extlen_t pagf_freeblks; /* total free blocks */
xfs_extlen_t pagf_longest; /* longest free space */
+ __uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */
xfs_agino_t pagi_freecount; /* number of free inodes */
+ xfs_agino_t pagi_count; /* number of allocated inodes */
+ int pagb_count; /* pagb slots in use */
#ifdef __KERNEL__
lock_t pagb_lock; /* lock for pagb_list */
#endif
- int pagb_count; /* pagb slots in use */
xfs_perag_busy_t *pagb_list; /* unstable blocks */
+ atomic_t pagf_fstrms; /* # of filestreams active in this AG */
} xfs_perag_t;
#define XFS_AG_MAXLEVELS(mp) ((mp)->m_ag_maxlevels)
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index 8e9a40aa0cd3..012a649a19c3 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -55,17 +55,17 @@ xfs_alloc_search_busy(xfs_trans_t *tp,
ktrace_t *xfs_alloc_trace_buf;
#define TRACE_ALLOC(s,a) \
- xfs_alloc_trace_alloc(fname, s, a, __LINE__)
+ xfs_alloc_trace_alloc(__FUNCTION__, s, a, __LINE__)
#define TRACE_FREE(s,a,b,x,f) \
- xfs_alloc_trace_free(fname, s, mp, a, b, x, f, __LINE__)
+ xfs_alloc_trace_free(__FUNCTION__, s, mp, a, b, x, f, __LINE__)
#define TRACE_MODAGF(s,a,f) \
- xfs_alloc_trace_modagf(fname, s, mp, a, f, __LINE__)
-#define TRACE_BUSY(fname,s,ag,agb,l,sl,tp) \
- xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__)
-#define TRACE_UNBUSY(fname,s,ag,sl,tp) \
- xfs_alloc_trace_busy(fname, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__)
-#define TRACE_BUSYSEARCH(fname,s,ag,agb,l,sl,tp) \
- xfs_alloc_trace_busy(fname, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__)
+ xfs_alloc_trace_modagf(__FUNCTION__, s, mp, a, f, __LINE__)
+#define TRACE_BUSY(__FUNCTION__,s,ag,agb,l,sl,tp) \
+ xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSY, __LINE__)
+#define TRACE_UNBUSY(__FUNCTION__,s,ag,sl,tp) \
+ xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, -1, -1, sl, tp, XFS_ALLOC_KTRACE_UNBUSY, __LINE__)
+#define TRACE_BUSYSEARCH(__FUNCTION__,s,ag,agb,l,sl,tp) \
+ xfs_alloc_trace_busy(__FUNCTION__, s, mp, ag, agb, l, sl, tp, XFS_ALLOC_KTRACE_BUSYSEARCH, __LINE__)
#else
#define TRACE_ALLOC(s,a)
#define TRACE_FREE(s,a,b,x,f)
@@ -420,7 +420,7 @@ xfs_alloc_read_agfl(
*/
STATIC void
xfs_alloc_trace_alloc(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_alloc_arg_t *args, /* allocation argument structure */
int line) /* source line number */
@@ -453,7 +453,7 @@ xfs_alloc_trace_alloc(
*/
STATIC void
xfs_alloc_trace_free(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_mount_t *mp, /* file system mount point */
xfs_agnumber_t agno, /* allocation group number */
@@ -479,7 +479,7 @@ xfs_alloc_trace_free(
*/
STATIC void
xfs_alloc_trace_modagf(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_mount_t *mp, /* file system mount point */
xfs_agf_t *agf, /* new agf value */
@@ -507,7 +507,7 @@ xfs_alloc_trace_modagf(
STATIC void
xfs_alloc_trace_busy(
- char *name, /* function tag string */
+ const char *name, /* function tag string */
char *str, /* additional string */
xfs_mount_t *mp, /* file system mount point */
xfs_agnumber_t agno, /* allocation group number */
@@ -549,9 +549,6 @@ xfs_alloc_ag_vextent(
xfs_alloc_arg_t *args) /* argument structure for allocation */
{
int error=0;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent";
-#endif
ASSERT(args->minlen > 0);
ASSERT(args->maxlen > 0);
@@ -635,9 +632,6 @@ xfs_alloc_ag_vextent_exact(
xfs_agblock_t fbno; /* start block of found extent */
xfs_agblock_t fend; /* end block of found extent */
xfs_extlen_t flen; /* length of found extent */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_exact";
-#endif
int i; /* success/failure of operation */
xfs_agblock_t maxend; /* end of maximal extent */
xfs_agblock_t minend; /* end of minimal extent */
@@ -737,9 +731,6 @@ xfs_alloc_ag_vextent_near(
xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */
xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */
xfs_btree_cur_t *cnt_cur; /* cursor for count btree */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_near";
-#endif
xfs_agblock_t gtbno; /* start bno of right side entry */
xfs_agblock_t gtbnoa; /* aligned ... */
xfs_extlen_t gtdiff; /* difference to right side entry */
@@ -1270,9 +1261,6 @@ xfs_alloc_ag_vextent_size(
int error; /* error result */
xfs_agblock_t fbno; /* start of found freespace */
xfs_extlen_t flen; /* length of found freespace */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_size";
-#endif
int i; /* temp status variable */
xfs_agblock_t rbno; /* returned block number */
xfs_extlen_t rlen; /* length of returned extent */
@@ -1427,9 +1415,6 @@ xfs_alloc_ag_vextent_small(
int error;
xfs_agblock_t fbno;
xfs_extlen_t flen;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_ag_vextent_small";
-#endif
int i;
if ((error = xfs_alloc_decrement(ccur, 0, &i)))
@@ -1447,7 +1432,8 @@ xfs_alloc_ag_vextent_small(
else if (args->minlen == 1 && args->alignment == 1 && !args->isfl &&
(be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount)
> args->minleft)) {
- if ((error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno)))
+ error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0);
+ if (error)
goto error0;
if (fbno != NULLAGBLOCK) {
if (args->userdata) {
@@ -1515,9 +1501,6 @@ xfs_free_ag_extent(
xfs_btree_cur_t *bno_cur; /* cursor for by-block btree */
xfs_btree_cur_t *cnt_cur; /* cursor for by-size btree */
int error; /* error return value */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_free_ag_extent";
-#endif
xfs_agblock_t gtbno; /* start of right neighbor block */
xfs_extlen_t gtlen; /* length of right neighbor block */
int haveleft; /* have a left neighbor block */
@@ -1923,7 +1906,8 @@ xfs_alloc_fix_freelist(
while (be32_to_cpu(agf->agf_flcount) > need) {
xfs_buf_t *bp;
- if ((error = xfs_alloc_get_freelist(tp, agbp, &bno)))
+ error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
+ if (error)
return error;
if ((error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, 1)))
return error;
@@ -1973,8 +1957,9 @@ xfs_alloc_fix_freelist(
* Put each allocated block on the list.
*/
for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) {
- if ((error = xfs_alloc_put_freelist(tp, agbp, agflbp,
- bno)))
+ error = xfs_alloc_put_freelist(tp, agbp,
+ agflbp, bno, 0);
+ if (error)
return error;
}
}
@@ -1991,16 +1976,15 @@ int /* error */
xfs_alloc_get_freelist(
xfs_trans_t *tp, /* transaction pointer */
xfs_buf_t *agbp, /* buffer containing the agf structure */
- xfs_agblock_t *bnop) /* block address retrieved from freelist */
+ xfs_agblock_t *bnop, /* block address retrieved from freelist */
+ int btreeblk) /* destination is a AGF btree */
{
xfs_agf_t *agf; /* a.g. freespace structure */
xfs_agfl_t *agfl; /* a.g. freelist structure */
xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */
xfs_agblock_t bno; /* block number returned */
int error;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_get_freelist";
-#endif
+ int logflags;
xfs_mount_t *mp; /* mount structure */
xfs_perag_t *pag; /* per allocation group data */
@@ -2032,8 +2016,16 @@ xfs_alloc_get_freelist(
be32_add(&agf->agf_flcount, -1);
xfs_trans_agflist_delta(tp, -1);
pag->pagf_flcount--;
- TRACE_MODAGF(NULL, agf, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT);
- xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT);
+
+ logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT;
+ if (btreeblk) {
+ be32_add(&agf->agf_btreeblks, 1);
+ pag->pagf_btreeblks++;
+ logflags |= XFS_AGF_BTREEBLKS;
+ }
+
+ TRACE_MODAGF(NULL, agf, logflags);
+ xfs_alloc_log_agf(tp, agbp, logflags);
*bnop = bno;
/*
@@ -2071,6 +2063,7 @@ xfs_alloc_log_agf(
offsetof(xfs_agf_t, agf_flcount),
offsetof(xfs_agf_t, agf_freeblks),
offsetof(xfs_agf_t, agf_longest),
+ offsetof(xfs_agf_t, agf_btreeblks),
sizeof(xfs_agf_t)
};
@@ -2106,15 +2099,14 @@ xfs_alloc_put_freelist(
xfs_trans_t *tp, /* transaction pointer */
xfs_buf_t *agbp, /* buffer for a.g. freelist header */
xfs_buf_t *agflbp,/* buffer for a.g. free block array */
- xfs_agblock_t bno) /* block being freed */
+ xfs_agblock_t bno, /* block being freed */
+ int btreeblk) /* block came from a AGF btree */
{
xfs_agf_t *agf; /* a.g. freespace structure */
xfs_agfl_t *agfl; /* a.g. free block array */
__be32 *blockp;/* pointer to array entry */
int error;
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_put_freelist";
-#endif
+ int logflags;
xfs_mount_t *mp; /* mount structure */
xfs_perag_t *pag; /* per allocation group data */
@@ -2132,11 +2124,22 @@ xfs_alloc_put_freelist(
be32_add(&agf->agf_flcount, 1);
xfs_trans_agflist_delta(tp, 1);
pag->pagf_flcount++;
+
+ logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT;
+ if (btreeblk) {
+ be32_add(&agf->agf_btreeblks, -1);
+ pag->pagf_btreeblks--;
+ logflags |= XFS_AGF_BTREEBLKS;
+ }
+
+ TRACE_MODAGF(NULL, agf, logflags);
+ xfs_alloc_log_agf(tp, agbp, logflags);
+
ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];
*blockp = cpu_to_be32(bno);
- TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
- xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
+ TRACE_MODAGF(NULL, agf, logflags);
+ xfs_alloc_log_agf(tp, agbp, logflags);
xfs_trans_log_buf(tp, agflbp,
(int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl),
(int)((xfs_caddr_t)blockp - (xfs_caddr_t)agfl +
@@ -2196,6 +2199,7 @@ xfs_alloc_read_agf(
pag = &mp->m_perag[agno];
if (!pag->pagf_init) {
pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);
+ pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks);
pag->pagf_flcount = be32_to_cpu(agf->agf_flcount);
pag->pagf_longest = be32_to_cpu(agf->agf_longest);
pag->pagf_levels[XFS_BTNUM_BNOi] =
@@ -2235,9 +2239,6 @@ xfs_alloc_vextent(
xfs_agblock_t agsize; /* allocation group size */
int error;
int flags; /* XFS_ALLOC_FLAG_... locking flags */
-#ifdef XFS_ALLOC_TRACE
- static char fname[] = "xfs_alloc_vextent";
-#endif
xfs_extlen_t minleft;/* minimum left value, temp copy */
xfs_mount_t *mp; /* mount structure pointer */
xfs_agnumber_t sagno; /* starting allocation group number */
diff --git a/fs/xfs/xfs_alloc.h b/fs/xfs/xfs_alloc.h
index 5a4256120ccc..5aec15d0651e 100644
--- a/fs/xfs/xfs_alloc.h
+++ b/fs/xfs/xfs_alloc.h
@@ -136,7 +136,8 @@ int /* error */
xfs_alloc_get_freelist(
struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* buffer containing the agf structure */
- xfs_agblock_t *bnop); /* block address retrieved from freelist */
+ xfs_agblock_t *bnop, /* block address retrieved from freelist */
+ int btreeblk); /* destination is a AGF btree */
/*
* Log the given fields from the agf structure.
@@ -165,7 +166,8 @@ xfs_alloc_put_freelist(
struct xfs_trans *tp, /* transaction pointer */
struct xfs_buf *agbp, /* buffer for a.g. freelist header */
struct xfs_buf *agflbp,/* buffer for a.g. free block array */
- xfs_agblock_t bno); /* block being freed */
+ xfs_agblock_t bno, /* block being freed */
+ int btreeblk); /* owner was a AGF btree */
/*
* Read in the allocation group header (free/alloc section).
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
index 74cadf95d4e8..1603ce595853 100644
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -226,8 +226,9 @@ xfs_alloc_delrec(
/*
* Put this buffer/block on the ag's freelist.
*/
- if ((error = xfs_alloc_put_freelist(cur->bc_tp,
- cur->bc_private.a.agbp, NULL, bno)))
+ error = xfs_alloc_put_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, NULL, bno, 1);
+ if (error)
return error;
/*
* Since blocks move to the free list without the
@@ -549,8 +550,9 @@ xfs_alloc_delrec(
/*
* Free the deleting block by putting it on the freelist.
*/
- if ((error = xfs_alloc_put_freelist(cur->bc_tp, cur->bc_private.a.agbp,
- NULL, rbno)))
+ error = xfs_alloc_put_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, NULL, rbno, 1);
+ if (error)
return error;
/*
* Since blocks move to the free list without the coordination
@@ -1320,8 +1322,9 @@ xfs_alloc_newroot(
/*
* Get a buffer from the freelist blocks, for the new root.
*/
- if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
- &nbno)))
+ error = xfs_alloc_get_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, &nbno, 1);
+ if (error)
return error;
/*
* None available, we fail.
@@ -1604,8 +1607,9 @@ xfs_alloc_split(
* Allocate the new block from the freelist.
* If we can't do it, we're toast. Give up.
*/
- if ((error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp,
- &rbno)))
+ error = xfs_alloc_get_freelist(cur->bc_tp,
+ cur->bc_private.a.agbp, &rbno, 1);
+ if (error)
return error;
if (rbno == NULLAGBLOCK) {
*stat = 0;
diff --git a/fs/xfs/xfs_bit.c b/fs/xfs/xfs_bit.c
index 1afe07f67e3b..fab0b6d5a41b 100644
--- a/fs/xfs/xfs_bit.c
+++ b/fs/xfs/xfs_bit.c
@@ -66,44 +66,6 @@ static const char xfs_highbit[256] = {
#endif
/*
- * Count of bits set in byte, 0..8.
- */
-static const char xfs_countbit[256] = {
- 0, 1, 1, 2, 1, 2, 2, 3, /* 00 .. 07 */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 08 .. 0f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 10 .. 17 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 18 .. 1f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 20 .. 27 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 28 .. 2f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 30 .. 37 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 38 .. 3f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 40 .. 47 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 48 .. 4f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 50 .. 57 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 58 .. 5f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 60 .. 67 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 68 .. 6f */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 70 .. 77 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* 78 .. 7f */
- 1, 2, 2, 3, 2, 3, 3, 4, /* 80 .. 87 */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 88 .. 8f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* 90 .. 97 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* 98 .. 9f */
- 2, 3, 3, 4, 3, 4, 4, 5, /* a0 .. a7 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* a8 .. af */
- 3, 4, 4, 5, 4, 5, 5, 6, /* b0 .. b7 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* b8 .. bf */
- 2, 3, 3, 4, 3, 4, 4, 5, /* c0 .. c7 */
- 3, 4, 4, 5, 4, 5, 5, 6, /* c8 .. cf */
- 3, 4, 4, 5, 4, 5, 5, 6, /* d0 .. d7 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* d8 .. df */
- 3, 4, 4, 5, 4, 5, 5, 6, /* e0 .. e7 */
- 4, 5, 5, 6, 5, 6, 6, 7, /* e8 .. ef */
- 4, 5, 5, 6, 5, 6, 6, 7, /* f0 .. f7 */
- 5, 6, 6, 7, 6, 7, 7, 8, /* f8 .. ff */
-};
-
-/*
* xfs_highbit32: get high bit set out of 32-bit argument, -1 if none set.
*/
inline int
@@ -167,56 +129,21 @@ xfs_highbit64(
/*
- * Count the number of bits set in the bitmap starting with bit
- * start_bit. Size is the size of the bitmap in words.
- *
- * Do the counting by mapping a byte value to the number of set
- * bits for that value using the xfs_countbit array, i.e.
- * xfs_countbit[0] == 0, xfs_countbit[1] == 1, xfs_countbit[2] == 1,
- * xfs_countbit[3] == 2, etc.
+ * Return whether bitmap is empty.
+ * Size is number of words in the bitmap, which is padded to word boundary
+ * Returns 1 for empty, 0 for non-empty.
*/
int
-xfs_count_bits(uint *map, uint size, uint start_bit)
+xfs_bitmap_empty(uint *map, uint size)
{
- register int bits;
- register unsigned char *bytep;
- register unsigned char *end_map;
- int byte_bit;
-
- bits = 0;
- end_map = (char*)(map + size);
- bytep = (char*)(map + (start_bit & ~0x7));
- byte_bit = start_bit & 0x7;
-
- /*
- * If the caller fell off the end of the map, return 0.
- */
- if (bytep >= end_map) {
- return (0);
- }
-
- /*
- * If start_bit is not byte aligned, then process the
- * first byte separately.
- */
- if (byte_bit != 0) {
- /*
- * Shift off the bits we don't want to look at,
- * before indexing into xfs_countbit.
- */
- bits += xfs_countbit[(*bytep >> byte_bit)];
- bytep++;
- }
+ uint i;
+ uint ret = 0;
- /*
- * Count the bits in each byte until the end of the bitmap.
- */
- while (bytep < end_map) {
- bits += xfs_countbit[*bytep];
- bytep++;
+ for (i = 0; i < size; i++) {
+ ret |= map[i];
}
- return (bits);
+ return (ret == 0);
}
/*
diff --git a/fs/xfs/xfs_bit.h b/fs/xfs/xfs_bit.h
index 0bbe56817542..082641a9782c 100644
--- a/fs/xfs/xfs_bit.h
+++ b/fs/xfs/xfs_bit.h
@@ -55,8 +55,8 @@ extern int xfs_lowbit64(__uint64_t v);
/* Get high bit set out of 64-bit argument, -1 if none set */
extern int xfs_highbit64(__uint64_t);
-/* Count set bits in map starting with start_bit */
-extern int xfs_count_bits(uint *map, uint size, uint start_bit);
+/* Return whether bitmap is empty (1 == empty) */
+extern int xfs_bitmap_empty(uint *map, uint size);
/* Count continuous one bits in map starting with start_bit */
extern int xfs_contig_bits(uint *map, uint size, uint start_bit);
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index b1ea26e40aaf..94b5c5fe2681 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -52,6 +52,7 @@
#include "xfs_quota.h"
#include "xfs_trans_space.h"
#include "xfs_buf_item.h"
+#include "xfs_filestream.h"
#ifdef DEBUG
@@ -277,7 +278,7 @@ xfs_bmap_isaeof(
STATIC void
xfs_bmap_trace_addentry(
int opcode, /* operation */
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(ies) */
@@ -291,7 +292,7 @@ xfs_bmap_trace_addentry(
*/
STATIC void
xfs_bmap_trace_delete(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) deleted */
@@ -304,7 +305,7 @@ xfs_bmap_trace_delete(
*/
STATIC void
xfs_bmap_trace_insert(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) inserted */
@@ -318,7 +319,7 @@ xfs_bmap_trace_insert(
*/
STATIC void
xfs_bmap_trace_post_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry updated */
@@ -329,17 +330,25 @@ xfs_bmap_trace_post_update(
*/
STATIC void
xfs_bmap_trace_pre_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry to be updated */
int whichfork); /* data or attr fork */
+#define XFS_BMAP_TRACE_DELETE(d,ip,i,c,w) \
+ xfs_bmap_trace_delete(__FUNCTION__,d,ip,i,c,w)
+#define XFS_BMAP_TRACE_INSERT(d,ip,i,c,r1,r2,w) \
+ xfs_bmap_trace_insert(__FUNCTION__,d,ip,i,c,r1,r2,w)
+#define XFS_BMAP_TRACE_POST_UPDATE(d,ip,i,w) \
+ xfs_bmap_trace_post_update(__FUNCTION__,d,ip,i,w)
+#define XFS_BMAP_TRACE_PRE_UPDATE(d,ip,i,w) \
+ xfs_bmap_trace_pre_update(__FUNCTION__,d,ip,i,w)
#else
-#define xfs_bmap_trace_delete(f,d,ip,i,c,w)
-#define xfs_bmap_trace_insert(f,d,ip,i,c,r1,r2,w)
-#define xfs_bmap_trace_post_update(f,d,ip,i,w)
-#define xfs_bmap_trace_pre_update(f,d,ip,i,w)
+#define XFS_BMAP_TRACE_DELETE(d,ip,i,c,w)
+#define XFS_BMAP_TRACE_INSERT(d,ip,i,c,r1,r2,w)
+#define XFS_BMAP_TRACE_POST_UPDATE(d,ip,i,w)
+#define XFS_BMAP_TRACE_PRE_UPDATE(d,ip,i,w)
#endif /* XFS_BMAP_TRACE */
/*
@@ -531,9 +540,6 @@ xfs_bmap_add_extent(
xfs_filblks_t da_new; /* new count del alloc blocks used */
xfs_filblks_t da_old; /* old count del alloc blocks used */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent";
-#endif
xfs_ifork_t *ifp; /* inode fork ptr */
int logflags; /* returned value */
xfs_extnum_t nextents; /* number of extents in file now */
@@ -551,8 +557,8 @@ xfs_bmap_add_extent(
* already extents in the list.
*/
if (nextents == 0) {
- xfs_bmap_trace_insert(fname, "insert empty", ip, 0, 1, new,
- NULL, whichfork);
+ XFS_BMAP_TRACE_INSERT("insert empty", ip, 0, 1, new, NULL,
+ whichfork);
xfs_iext_insert(ifp, 0, 1, new);
ASSERT(cur == NULL);
ifp->if_lastex = 0;
@@ -710,9 +716,6 @@ xfs_bmap_add_extent_delay_real(
int diff; /* temp value */
xfs_bmbt_rec_t *ep; /* extent entry for idx */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_delay_real";
-#endif
int i; /* temp state */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_fileoff_t new_endoff; /* end offset of new entry */
@@ -808,15 +811,14 @@ xfs_bmap_add_extent_delay_real(
* Filling in all of a previously delayed allocation extent.
* The left and right neighbors are both contiguous with new.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount +
RIGHT.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1,
- XFS_DATA_FORK);
- xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC|RC", ip, idx, 2, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 2);
ip->i_df.if_lastex = idx - 1;
ip->i_d.di_nextents--;
@@ -855,15 +857,14 @@ xfs_bmap_add_extent_delay_real(
* Filling in all of a previously delayed allocation extent.
* The left neighbor is contiguous, the right is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
- xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC", ip, idx, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 1);
if (cur == NULL)
rval = XFS_ILOG_DEXT;
@@ -892,16 +893,13 @@ xfs_bmap_add_extent_delay_real(
* Filling in all of a previously delayed allocation extent.
* The right neighbor is contiguous, the left is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|RC", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_startblock(ep, new->br_startblock);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount + RIGHT.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|RC", ip, idx, XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
- xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|RC", ip, idx + 1, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx + 1, 1);
if (cur == NULL)
rval = XFS_ILOG_DEXT;
@@ -931,11 +929,9 @@ xfs_bmap_add_extent_delay_real(
* Neither the left nor right neighbors are contiguous with
* the new one.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_startblock(ep, new->br_startblock);
- xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF", ip, idx, XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
ip->i_d.di_nextents++;
if (cur == NULL)
@@ -963,17 +959,14 @@ xfs_bmap_add_extent_delay_real(
* Filling in the first part of a previous delayed allocation.
* The left neighbor is contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx - 1, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + new->br_blockcount);
xfs_bmbt_set_startoff(ep,
PREV.br_startoff + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx - 1, XFS_DATA_FORK);
temp = PREV.br_blockcount - new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
ip->i_df.if_lastex = idx - 1;
if (cur == NULL)
@@ -995,8 +988,7 @@ xfs_bmap_add_extent_delay_real(
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
STARTBLOCKVAL(PREV.br_startblock));
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: The boundary between two in-core extents moved. */
temp = LEFT.br_startoff;
@@ -1009,11 +1001,11 @@ xfs_bmap_add_extent_delay_real(
* Filling in the first part of a previous delayed allocation.
* The left neighbor is not contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_startoff(ep, new_endoff);
temp = PREV.br_blockcount - new->br_blockcount;
xfs_bmbt_set_blockcount(ep, temp);
- xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL,
+ XFS_BMAP_TRACE_INSERT("LF", ip, idx, 1, new, NULL,
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx, 1, new);
ip->i_df.if_lastex = idx;
@@ -1046,8 +1038,7 @@ xfs_bmap_add_extent_delay_real(
(cur ? cur->bc_private.b.allocated : 0));
ep = xfs_iext_get_ext(ifp, idx + 1);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "LF", ip, idx + 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("LF", ip, idx + 1, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: One in-core extent is split in two. */
temp = PREV.br_startoff;
@@ -1060,17 +1051,14 @@ xfs_bmap_add_extent_delay_real(
* The right neighbor is contiguous with the new allocation.
*/
temp = PREV.br_blockcount - new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx,
- XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx + 1, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
new->br_startoff, new->br_startblock,
new->br_blockcount + RIGHT.br_blockcount,
RIGHT.br_state);
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx + 1, XFS_DATA_FORK);
ip->i_df.if_lastex = idx + 1;
if (cur == NULL)
rval = XFS_ILOG_DEXT;
@@ -1091,8 +1079,7 @@ xfs_bmap_add_extent_delay_real(
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
STARTBLOCKVAL(PREV.br_startblock));
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: The boundary between two in-core extents moved. */
temp = PREV.br_startoff;
@@ -1106,10 +1093,10 @@ xfs_bmap_add_extent_delay_real(
* The right neighbor is not contiguous.
*/
temp = PREV.br_blockcount - new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
- xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1,
- new, NULL, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_INSERT("RF", ip, idx + 1, 1, new, NULL,
+ XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 1, new);
ip->i_df.if_lastex = idx + 1;
ip->i_d.di_nextents++;
@@ -1141,7 +1128,7 @@ xfs_bmap_add_extent_delay_real(
(cur ? cur->bc_private.b.allocated : 0));
ep = xfs_iext_get_ext(ifp, idx);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF", ip, idx, XFS_DATA_FORK);
*dnew = temp;
/* DELTA: One in-core extent is split in two. */
temp = PREV.br_startoff;
@@ -1155,7 +1142,7 @@ xfs_bmap_add_extent_delay_real(
* This case is avoided almost all the time.
*/
temp = new->br_startoff - PREV.br_startoff;
- xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep, temp);
r[0] = *new;
r[1].br_state = PREV.br_state;
@@ -1163,7 +1150,7 @@ xfs_bmap_add_extent_delay_real(
r[1].br_startoff = new_endoff;
temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff;
r[1].br_blockcount = temp2;
- xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1],
+ XFS_BMAP_TRACE_INSERT("0", ip, idx + 1, 2, &r[0], &r[1],
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 2, &r[0]);
ip->i_df.if_lastex = idx + 1;
@@ -1222,13 +1209,11 @@ xfs_bmap_add_extent_delay_real(
}
ep = xfs_iext_get_ext(ifp, idx);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "0", ip, idx + 2,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx + 2, XFS_DATA_FORK);
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx + 2),
NULLSTARTBLOCK((int)temp2));
- xfs_bmap_trace_post_update(fname, "0", ip, idx + 2,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx + 2, XFS_DATA_FORK);
*dnew = temp + temp2;
/* DELTA: One in-core extent is split in three. */
temp = PREV.br_startoff;
@@ -1287,9 +1272,6 @@ xfs_bmap_add_extent_unwritten_real(
xfs_btree_cur_t *cur; /* btree cursor */
xfs_bmbt_rec_t *ep; /* extent entry for idx */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_unwritten_real";
-#endif
int i; /* temp state */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_fileoff_t new_endoff; /* end offset of new entry */
@@ -1390,15 +1372,14 @@ xfs_bmap_add_extent_unwritten_real(
* Setting all of a previous oldext extent to newext.
* The left and right neighbors are both contiguous with new.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount +
RIGHT.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC|RC", ip, idx - 1,
- XFS_DATA_FORK);
- xfs_bmap_trace_delete(fname, "LF|RF|LC|RC", ip, idx, 2,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC|RC", ip, idx - 1,
XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC|RC", ip, idx, 2, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 2);
ip->i_df.if_lastex = idx - 1;
ip->i_d.di_nextents -= 2;
@@ -1441,15 +1422,14 @@ xfs_bmap_add_extent_unwritten_real(
* Setting all of a previous oldext extent to newext.
* The left neighbor is contiguous, the right is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + PREV.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|RF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|LC", ip, idx - 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
- xfs_bmap_trace_delete(fname, "LF|RF|LC", ip, idx, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|LC", ip, idx, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 1);
ip->i_d.di_nextents--;
if (cur == NULL)
@@ -1484,16 +1464,15 @@ xfs_bmap_add_extent_unwritten_real(
* Setting all of a previous oldext extent to newext.
* The right neighbor is contiguous, the left is not.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF|RC", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF|RC", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount + RIGHT.br_blockcount);
xfs_bmbt_set_state(ep, newext);
- xfs_bmap_trace_post_update(fname, "LF|RF|RC", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF|RC", ip, idx,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
- xfs_bmap_trace_delete(fname, "LF|RF|RC", ip, idx + 1, 1,
- XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LF|RF|RC", ip, idx + 1, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx + 1, 1);
ip->i_d.di_nextents--;
if (cur == NULL)
@@ -1529,10 +1508,10 @@ xfs_bmap_add_extent_unwritten_real(
* Neither the left nor right neighbors are contiguous with
* the new one.
*/
- xfs_bmap_trace_pre_update(fname, "LF|RF", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|RF", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_state(ep, newext);
- xfs_bmap_trace_post_update(fname, "LF|RF", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|RF", ip, idx,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
if (cur == NULL)
@@ -1559,21 +1538,21 @@ xfs_bmap_add_extent_unwritten_real(
* Setting the first part of a previous oldext extent to newext.
* The left neighbor is contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
LEFT.br_blockcount + new->br_blockcount);
xfs_bmbt_set_startoff(ep,
PREV.br_startoff + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx - 1,
XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "LF|LC", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("LF|LC", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_startblock(ep,
new->br_startblock + new->br_blockcount);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF|LC", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("LF|LC", ip, idx,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
if (cur == NULL)
@@ -1610,15 +1589,15 @@ xfs_bmap_add_extent_unwritten_real(
* Setting the first part of a previous oldext extent to newext.
* The left neighbor is not contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "LF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("LF", ip, idx, XFS_DATA_FORK);
ASSERT(ep && xfs_bmbt_get_state(ep) == oldext);
xfs_bmbt_set_startoff(ep, new_endoff);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
xfs_bmbt_set_startblock(ep,
new->br_startblock + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LF", ip, idx, XFS_DATA_FORK);
- xfs_bmap_trace_insert(fname, "LF", ip, idx, 1, new, NULL,
+ XFS_BMAP_TRACE_POST_UPDATE("LF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_INSERT("LF", ip, idx, 1, new, NULL,
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx, 1, new);
ip->i_df.if_lastex = idx;
@@ -1653,18 +1632,18 @@ xfs_bmap_add_extent_unwritten_real(
* Setting the last part of a previous oldext extent to newext.
* The right neighbor is contiguous with the new allocation.
*/
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx,
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx,
XFS_DATA_FORK);
- xfs_bmap_trace_pre_update(fname, "RF|RC", ip, idx + 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("RF|RC", ip, idx + 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx,
XFS_DATA_FORK);
xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, idx + 1),
new->br_startoff, new->br_startblock,
new->br_blockcount + RIGHT.br_blockcount, newext);
- xfs_bmap_trace_post_update(fname, "RF|RC", ip, idx + 1,
+ XFS_BMAP_TRACE_POST_UPDATE("RF|RC", ip, idx + 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx + 1;
if (cur == NULL)
@@ -1700,12 +1679,12 @@ xfs_bmap_add_extent_unwritten_real(
* Setting the last part of a previous oldext extent to newext.
* The right neighbor is not contiguous.
*/
- xfs_bmap_trace_pre_update(fname, "RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RF", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
PREV.br_blockcount - new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "RF", ip, idx, XFS_DATA_FORK);
- xfs_bmap_trace_insert(fname, "RF", ip, idx + 1, 1,
- new, NULL, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RF", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_INSERT("RF", ip, idx + 1, 1, new, NULL,
+ XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 1, new);
ip->i_df.if_lastex = idx + 1;
ip->i_d.di_nextents++;
@@ -1744,17 +1723,17 @@ xfs_bmap_add_extent_unwritten_real(
* newext. Contiguity is impossible here.
* One extent becomes three extents.
*/
- xfs_bmap_trace_pre_update(fname, "0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx, XFS_DATA_FORK);
xfs_bmbt_set_blockcount(ep,
new->br_startoff - PREV.br_startoff);
- xfs_bmap_trace_post_update(fname, "0", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx, XFS_DATA_FORK);
r[0] = *new;
r[1].br_startoff = new_endoff;
r[1].br_blockcount =
PREV.br_startoff + PREV.br_blockcount - new_endoff;
r[1].br_startblock = new->br_startblock + new->br_blockcount;
r[1].br_state = oldext;
- xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 2, &r[0], &r[1],
+ XFS_BMAP_TRACE_INSERT("0", ip, idx + 1, 2, &r[0], &r[1],
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx + 1, 2, &r[0]);
ip->i_df.if_lastex = idx + 1;
@@ -1845,9 +1824,6 @@ xfs_bmap_add_extent_hole_delay(
int rsvd) /* OK to allocate reserved blocks */
{
xfs_bmbt_rec_t *ep; /* extent record for idx */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_hole_delay";
-#endif
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_irec_t left; /* left neighbor extent entry */
xfs_filblks_t newlen=0; /* new indirect size */
@@ -1919,7 +1895,7 @@ xfs_bmap_add_extent_hole_delay(
*/
temp = left.br_blockcount + new->br_blockcount +
right.br_blockcount;
- xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LC|RC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
oldlen = STARTBLOCKVAL(left.br_startblock) +
@@ -1928,10 +1904,9 @@ xfs_bmap_add_extent_hole_delay(
newlen = xfs_bmap_worst_indlen(ip, temp);
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
NULLSTARTBLOCK((int)newlen));
- xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1,
- XFS_DATA_FORK);
- xfs_bmap_trace_delete(fname, "LC|RC", ip, idx, 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LC|RC", ip, idx - 1,
XFS_DATA_FORK);
+ XFS_BMAP_TRACE_DELETE("LC|RC", ip, idx, 1, XFS_DATA_FORK);
xfs_iext_remove(ifp, idx, 1);
ip->i_df.if_lastex = idx - 1;
/* DELTA: Two in-core extents were replaced by one. */
@@ -1946,7 +1921,7 @@ xfs_bmap_add_extent_hole_delay(
* Merge the new allocation with the left neighbor.
*/
temp = left.br_blockcount + new->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LC", ip, idx - 1,
XFS_DATA_FORK);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1), temp);
oldlen = STARTBLOCKVAL(left.br_startblock) +
@@ -1954,7 +1929,7 @@ xfs_bmap_add_extent_hole_delay(
newlen = xfs_bmap_worst_indlen(ip, temp);
xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, idx - 1),
NULLSTARTBLOCK((int)newlen));
- xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LC", ip, idx - 1,
XFS_DATA_FORK);
ip->i_df.if_lastex = idx - 1;
/* DELTA: One in-core extent grew into a hole. */
@@ -1968,14 +1943,14 @@ xfs_bmap_add_extent_hole_delay(
* on the right.
* Merge the new allocation with the right neighbor.
*/
- xfs_bmap_trace_pre_update(fname, "RC", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_PRE_UPDATE("RC", ip, idx, XFS_DATA_FORK);
temp = new->br_blockcount + right.br_blockcount;
oldlen = STARTBLOCKVAL(new->br_startblock) +
STARTBLOCKVAL(right.br_startblock);
newlen = xfs_bmap_worst_indlen(ip, temp);
xfs_bmbt_set_allf(ep, new->br_startoff,
NULLSTARTBLOCK((int)newlen), temp, right.br_state);
- xfs_bmap_trace_post_update(fname, "RC", ip, idx, XFS_DATA_FORK);
+ XFS_BMAP_TRACE_POST_UPDATE("RC", ip, idx, XFS_DATA_FORK);
ip->i_df.if_lastex = idx;
/* DELTA: One in-core extent grew into a hole. */
temp2 = temp;
@@ -1989,7 +1964,7 @@ xfs_bmap_add_extent_hole_delay(
* Insert a new entry.
*/
oldlen = newlen = 0;
- xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL,
+ XFS_BMAP_TRACE_INSERT("0", ip, idx, 1, new, NULL,
XFS_DATA_FORK);
xfs_iext_insert(ifp, idx, 1, new);
ip->i_df.if_lastex = idx;
@@ -2039,9 +2014,6 @@ xfs_bmap_add_extent_hole_real(
{
xfs_bmbt_rec_t *ep; /* pointer to extent entry ins. point */
int error; /* error return value */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_add_extent_hole_real";
-#endif
int i; /* temp state */
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_irec_t left; /* left neighbor extent entry */
@@ -2118,15 +2090,14 @@ xfs_bmap_add_extent_hole_real(
* left and on the right.
* Merge all three into a single extent record.
*/
- xfs_bmap_trace_pre_update(fname, "LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_PRE_UPDATE("LC|RC", ip, idx - 1,
whichfork);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
left.br_blockcount + new->br_blockcount +
right.br_blockcount);
- xfs_bmap_trace_post_update(fname, "LC|RC", ip, idx - 1,
+ XFS_BMAP_TRACE_POST_UPDATE("LC|RC", ip, idx - 1,
whichfork);
- xfs_bmap_trace_delete(fname, "LC|RC", ip,
- idx, 1, whichfork);
+ XFS_BMAP_TRACE_DELETE("LC|RC", ip, idx, 1, whichfork);
xfs_iext_remove(ifp, idx, 1);
ifp->if_lastex = idx - 1;
XFS_IFORK_NEXT_SET(ip, whichfork,
@@ -2168,10 +2139,10 @@ xfs_bmap_add_extent_hole_real(
* on the left.
* Merge the new allocation with the left neighbor.
*/
- xfs_bmap_trace_pre_update(fname, "LC", ip, idx - 1, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("LC", ip, idx - 1, whichfork);
xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, idx - 1),
left.br_blockcount + new->br_blockcount);
- xfs_bmap_trace_post_update(fname, "LC", ip, idx - 1, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("LC", ip, idx - 1, whichfork);
ifp->if_lastex = idx - 1;
if (cur == NULL) {
rval = XFS_ILOG_FEXT(whichfork);
@@ -2202,11 +2173,11 @@ xfs_bmap_add_extent_hole_real(
* on the right.
* Merge the new allocation with the right neighbor.
*/
- xfs_bmap_trace_pre_update(fname, "RC", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("RC", ip, idx, whichfork);
xfs_bmbt_set_allf(ep, new->br_startoff, new->br_startblock,
new->br_blockcount + right.br_blockcount,
right.br_state);
- xfs_bmap_trace_post_update(fname, "RC", ip, idx, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("RC", ip, idx, whichfork);
ifp->if_lastex = idx;
if (cur == NULL) {
rval = XFS_ILOG_FEXT(whichfork);
@@ -2237,8 +2208,7 @@ xfs_bmap_add_extent_hole_real(
* real allocation.
* Insert a new entry.
*/
- xfs_bmap_trace_insert(fname, "0", ip, idx, 1, new, NULL,
- whichfork);
+ XFS_BMAP_TRACE_INSERT("0", ip, idx, 1, new, NULL, whichfork);
xfs_iext_insert(ifp, idx, 1, new);
ifp->if_lastex = idx;
XFS_IFORK_NEXT_SET(ip, whichfork,
@@ -2605,12 +2575,10 @@ xfs_bmap_rtalloc(
xfs_extlen_t prod = 0; /* product factor for allocators */
xfs_extlen_t ralen = 0; /* realtime allocation length */
xfs_extlen_t align; /* minimum allocation alignment */
- xfs_rtblock_t rtx; /* realtime extent number */
xfs_rtblock_t rtb;
mp = ap->ip->i_mount;
- align = ap->ip->i_d.di_extsize ?
- ap->ip->i_d.di_extsize : mp->m_sb.sb_rextsize;
+ align = xfs_get_extsz_hint(ap->ip);
prod = align / mp->m_sb.sb_rextsize;
error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
align, 1, ap->eof, 0,
@@ -2644,6 +2612,8 @@ xfs_bmap_rtalloc(
* pick an extent that will space things out in the rt area.
*/
if (ap->eof && ap->off == 0) {
+ xfs_rtblock_t uninitialized_var(rtx); /* realtime extent no */
+
error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
if (error)
return error;
@@ -2715,9 +2685,7 @@ xfs_bmap_btalloc(
int error;
mp = ap->ip->i_mount;
- align = (ap->userdata && ap->ip->i_d.di_extsize &&
- (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)) ?
- ap->ip->i_d.di_extsize : 0;
+ align = ap->userdata ? xfs_get_extsz_hint(ap->ip) : 0;
if (unlikely(align)) {
error = xfs_bmap_extsize_align(mp, ap->gotp, ap->prevp,
align, 0, ap->eof, 0, ap->conv,
@@ -2727,9 +2695,15 @@ xfs_bmap_btalloc(
}
nullfb = ap->firstblock == NULLFSBLOCK;
fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, ap->firstblock);
- if (nullfb)
- ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
- else
+ if (nullfb) {
+ if (ap->userdata && xfs_inode_is_filestream(ap->ip)) {
+ ag = xfs_filestream_lookup_ag(ap->ip);
+ ag = (ag != NULLAGNUMBER) ? ag : 0;
+ ap->rval = XFS_AGB_TO_FSB(mp, ag, 0);
+ } else {
+ ap->rval = XFS_INO_TO_FSB(mp, ap->ip->i_ino);
+ }
+ } else
ap->rval = ap->firstblock;
xfs_bmap_adjacent(ap);
@@ -2753,13 +2727,22 @@ xfs_bmap_btalloc(
args.firstblock = ap->firstblock;
blen = 0;
if (nullfb) {
- args.type = XFS_ALLOCTYPE_START_BNO;
+ if (ap->userdata && xfs_inode_is_filestream(ap->ip))
+ args.type = XFS_ALLOCTYPE_NEAR_BNO;
+ else
+ args.type = XFS_ALLOCTYPE_START_BNO;
args.total = ap->total;
+
/*
- * Find the longest available space.
- * We're going to try for the whole allocation at once.
+ * Search for an allocation group with a single extent
+ * large enough for the request.
+ *
+ * If one isn't found, then adjust the minimum allocation
+ * size to the largest space found.
*/
startag = ag = XFS_FSB_TO_AGNO(mp, args.fsbno);
+ if (startag == NULLAGNUMBER)
+ startag = ag = 0;
notinit = 0;
down_read(&mp->m_peraglock);
while (blen < ap->alen) {
@@ -2785,6 +2768,35 @@ xfs_bmap_btalloc(
blen = longest;
} else
notinit = 1;
+
+ if (xfs_inode_is_filestream(ap->ip)) {
+ if (blen >= ap->alen)
+ break;
+
+ if (ap->userdata) {
+ /*
+ * If startag is an invalid AG, we've
+ * come here once before and
+ * xfs_filestream_new_ag picked the
+ * best currently available.
+ *
+ * Don't continue looping, since we
+ * could loop forever.
+ */
+ if (startag == NULLAGNUMBER)
+ break;
+
+ error = xfs_filestream_new_ag(ap, &ag);
+ if (error) {
+ up_read(&mp->m_peraglock);
+ return error;
+ }
+
+ /* loop again to set 'blen'*/
+ startag = NULLAGNUMBER;
+ continue;
+ }
+ }
if (++ag == mp->m_sb.sb_agcount)
ag = 0;
if (ag == startag)
@@ -2809,17 +2821,27 @@ xfs_bmap_btalloc(
*/
else
args.minlen = ap->alen;
+
+ /*
+ * set the failure fallback case to look in the selected
+ * AG as the stream may have moved.
+ */
+ if (xfs_inode_is_filestream(ap->ip))
+ ap->rval = args.fsbno = XFS_AGB_TO_FSB(mp, ag, 0);
} else if (ap->low) {
- args.type = XFS_ALLOCTYPE_START_BNO;
+ if (xfs_inode_is_filestream(ap->ip))
+ args.type = XFS_ALLOCTYPE_FIRST_AG;
+ else
+ args.type = XFS_ALLOCTYPE_START_BNO;
args.total = args.minlen = ap->minlen;
} else {
args.type = XFS_ALLOCTYPE_NEAR_BNO;
args.total = ap->total;
args.minlen = ap->minlen;
}
- if (unlikely(ap->userdata && ap->ip->i_d.di_extsize &&
- (ap->ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE))) {
- args.prod = ap->ip->i_d.di_extsize;
+ /* apply extent size hints if obtained earlier */
+ if (unlikely(align)) {
+ args.prod = align;
if ((args.mod = (xfs_extlen_t)do_mod(ap->off, args.prod)))
args.mod = (xfs_extlen_t)(args.prod - args.mod);
} else if (mp->m_sb.sb_blocksize >= NBPP) {
@@ -3051,9 +3073,6 @@ xfs_bmap_del_extent(
xfs_bmbt_rec_t *ep; /* current extent entry pointer */
int error; /* error return value */
int flags; /* inode logging flags */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_del_extent";
-#endif
xfs_bmbt_irec_t got; /* current extent entry */
xfs_fileoff_t got_endoff; /* first offset past got */
int i; /* temp state */
@@ -3147,7 +3166,7 @@ xfs_bmap_del_extent(
/*
* Matches the whole extent. Delete the entry.
*/
- xfs_bmap_trace_delete(fname, "3", ip, idx, 1, whichfork);
+ XFS_BMAP_TRACE_DELETE("3", ip, idx, 1, whichfork);
xfs_iext_remove(ifp, idx, 1);
ifp->if_lastex = idx;
if (delay)
@@ -3168,7 +3187,7 @@ xfs_bmap_del_extent(
/*
* Deleting the first part of the extent.
*/
- xfs_bmap_trace_pre_update(fname, "2", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("2", ip, idx, whichfork);
xfs_bmbt_set_startoff(ep, del_endoff);
temp = got.br_blockcount - del->br_blockcount;
xfs_bmbt_set_blockcount(ep, temp);
@@ -3177,13 +3196,13 @@ xfs_bmap_del_extent(
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
da_old);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "2", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("2", ip, idx,
whichfork);
da_new = temp;
break;
}
xfs_bmbt_set_startblock(ep, del_endblock);
- xfs_bmap_trace_post_update(fname, "2", ip, idx, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("2", ip, idx, whichfork);
if (!cur) {
flags |= XFS_ILOG_FEXT(whichfork);
break;
@@ -3199,19 +3218,19 @@ xfs_bmap_del_extent(
* Deleting the last part of the extent.
*/
temp = got.br_blockcount - del->br_blockcount;
- xfs_bmap_trace_pre_update(fname, "1", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("1", ip, idx, whichfork);
xfs_bmbt_set_blockcount(ep, temp);
ifp->if_lastex = idx;
if (delay) {
temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
da_old);
xfs_bmbt_set_startblock(ep, NULLSTARTBLOCK((int)temp));
- xfs_bmap_trace_post_update(fname, "1", ip, idx,
+ XFS_BMAP_TRACE_POST_UPDATE("1", ip, idx,
whichfork);
da_new = temp;
break;
}
- xfs_bmap_trace_post_update(fname, "1", ip, idx, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("1", ip, idx, whichfork);
if (!cur) {
flags |= XFS_ILOG_FEXT(whichfork);
break;
@@ -3228,7 +3247,7 @@ xfs_bmap_del_extent(
* Deleting the middle of the extent.
*/
temp = del->br_startoff - got.br_startoff;
- xfs_bmap_trace_pre_update(fname, "0", ip, idx, whichfork);
+ XFS_BMAP_TRACE_PRE_UPDATE("0", ip, idx, whichfork);
xfs_bmbt_set_blockcount(ep, temp);
new.br_startoff = del_endoff;
temp2 = got_endoff - del_endoff;
@@ -3315,8 +3334,8 @@ xfs_bmap_del_extent(
}
}
}
- xfs_bmap_trace_post_update(fname, "0", ip, idx, whichfork);
- xfs_bmap_trace_insert(fname, "0", ip, idx + 1, 1, &new, NULL,
+ XFS_BMAP_TRACE_POST_UPDATE("0", ip, idx, whichfork);
+ XFS_BMAP_TRACE_INSERT("0", ip, idx + 1, 1, &new, NULL,
whichfork);
xfs_iext_insert(ifp, idx + 1, 1, &new);
ifp->if_lastex = idx + 1;
@@ -3556,9 +3575,6 @@ xfs_bmap_local_to_extents(
{
int error; /* error return value */
int flags; /* logging flags returned */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_local_to_extents";
-#endif
xfs_ifork_t *ifp; /* inode fork pointer */
/*
@@ -3613,7 +3629,7 @@ xfs_bmap_local_to_extents(
xfs_iext_add(ifp, 0, 1);
ep = xfs_iext_get_ext(ifp, 0);
xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM);
- xfs_bmap_trace_post_update(fname, "new", ip, 0, whichfork);
+ XFS_BMAP_TRACE_POST_UPDATE("new", ip, 0, whichfork);
XFS_IFORK_NEXT_SET(ip, whichfork, 1);
ip->i_d.di_nblocks = 1;
XFS_TRANS_MOD_DQUOT_BYINO(args.mp, tp, ip,
@@ -3736,7 +3752,7 @@ ktrace_t *xfs_bmap_trace_buf;
STATIC void
xfs_bmap_trace_addentry(
int opcode, /* operation */
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(ies) */
@@ -3795,7 +3811,7 @@ xfs_bmap_trace_addentry(
*/
STATIC void
xfs_bmap_trace_delete(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) deleted */
@@ -3817,7 +3833,7 @@ xfs_bmap_trace_delete(
*/
STATIC void
xfs_bmap_trace_insert(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry(entries) inserted */
@@ -3846,7 +3862,7 @@ xfs_bmap_trace_insert(
*/
STATIC void
xfs_bmap_trace_post_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry updated */
@@ -3864,7 +3880,7 @@ xfs_bmap_trace_post_update(
*/
STATIC void
xfs_bmap_trace_pre_update(
- char *fname, /* function name */
+ const char *fname, /* function name */
char *desc, /* operation description */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t idx, /* index of entry to be updated */
@@ -4481,9 +4497,6 @@ xfs_bmap_read_extents(
xfs_buf_t *bp; /* buffer for "block" */
int error; /* error return value */
xfs_exntfmt_t exntf; /* XFS_EXTFMT_NOSTATE, if checking */
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_bmap_read_extents";
-#endif
xfs_extnum_t i, j; /* index into the extents list */
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
@@ -4600,7 +4613,7 @@ xfs_bmap_read_extents(
}
ASSERT(i == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)));
ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork));
- xfs_bmap_trace_exlist(fname, ip, i, whichfork);
+ XFS_BMAP_TRACE_EXLIST(ip, i, whichfork);
return 0;
error0:
xfs_trans_brelse(tp, bp);
@@ -4613,7 +4626,7 @@ error0:
*/
void
xfs_bmap_trace_exlist(
- char *fname, /* function name */
+ const char *fname, /* function name */
xfs_inode_t *ip, /* incore inode pointer */
xfs_extnum_t cnt, /* count of entries in the list */
int whichfork) /* data or attr fork */
@@ -4628,7 +4641,7 @@ xfs_bmap_trace_exlist(
for (idx = 0; idx < cnt; idx++) {
ep = xfs_iext_get_ext(ifp, idx);
xfs_bmbt_get_all(ep, &s);
- xfs_bmap_trace_insert(fname, "exlist", ip, idx, 1, &s, NULL,
+ XFS_BMAP_TRACE_INSERT("exlist", ip, idx, 1, &s, NULL,
whichfork);
}
}
@@ -4868,12 +4881,7 @@ xfs_bmapi(
xfs_extlen_t extsz;
/* Figure out the extent size, adjust alen */
- if (rt) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
+ extsz = xfs_get_extsz_hint(ip);
if (extsz) {
error = xfs_bmap_extsize_align(mp,
&got, &prev, extsz,
@@ -5219,10 +5227,10 @@ xfs_bmapi(
* Else go on to the next record.
*/
ep = xfs_iext_get_ext(ifp, ++lastx);
- if (lastx >= nextents) {
+ prev = got;
+ if (lastx >= nextents)
eof = 1;
- prev = got;
- } else
+ else
xfs_bmbt_get_all(ep, &got);
}
ifp->if_lastex = lastx;
@@ -5813,8 +5821,7 @@ xfs_getbmap(
ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
return XFS_ERROR(EINVAL);
if (whichfork == XFS_DATA_FORK) {
- if ((ip->i_d.di_extsize && (ip->i_d.di_flags &
- (XFS_DIFLAG_REALTIME|XFS_DIFLAG_EXTSIZE))) ||
+ if (xfs_get_extsz_hint(ip) ||
ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
prealloced = 1;
fixlen = XFS_MAXIOFFSET(mp);
diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h
index 4f24c7e39b31..524b1c9d5246 100644
--- a/fs/xfs/xfs_bmap.h
+++ b/fs/xfs/xfs_bmap.h
@@ -144,12 +144,14 @@ extern ktrace_t *xfs_bmap_trace_buf;
*/
void
xfs_bmap_trace_exlist(
- char *fname, /* function name */
+ const char *fname, /* function name */
struct xfs_inode *ip, /* incore inode pointer */
xfs_extnum_t cnt, /* count of entries in list */
int whichfork); /* data or attr fork */
+#define XFS_BMAP_TRACE_EXLIST(ip,c,w) \
+ xfs_bmap_trace_exlist(__FUNCTION__,ip,c,w)
#else
-#define xfs_bmap_trace_exlist(f,ip,c,w)
+#define XFS_BMAP_TRACE_EXLIST(ip,c,w)
#endif
/*
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 0bf192fea3eb..89b891f51cfb 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -76,7 +76,7 @@ static char EXIT[] = "exit";
*/
STATIC void
xfs_bmbt_trace_enter(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
char *s,
int type,
@@ -117,7 +117,7 @@ xfs_bmbt_trace_enter(
*/
STATIC void
xfs_bmbt_trace_argbi(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
xfs_buf_t *b,
int i,
@@ -134,7 +134,7 @@ xfs_bmbt_trace_argbi(
*/
STATIC void
xfs_bmbt_trace_argbii(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
xfs_buf_t *b,
int i0,
@@ -153,7 +153,7 @@ xfs_bmbt_trace_argbii(
*/
STATIC void
xfs_bmbt_trace_argfffi(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
xfs_dfiloff_t o,
xfs_dfsbno_t b,
@@ -172,7 +172,7 @@ xfs_bmbt_trace_argfffi(
*/
STATIC void
xfs_bmbt_trace_argi(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
int line)
@@ -188,7 +188,7 @@ xfs_bmbt_trace_argi(
*/
STATIC void
xfs_bmbt_trace_argifk(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
xfs_fsblock_t f,
@@ -206,7 +206,7 @@ xfs_bmbt_trace_argifk(
*/
STATIC void
xfs_bmbt_trace_argifr(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
xfs_fsblock_t f,
@@ -235,7 +235,7 @@ xfs_bmbt_trace_argifr(
*/
STATIC void
xfs_bmbt_trace_argik(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
int i,
xfs_bmbt_key_t *k,
@@ -255,7 +255,7 @@ xfs_bmbt_trace_argik(
*/
STATIC void
xfs_bmbt_trace_cursor(
- char *func,
+ const char *func,
xfs_btree_cur_t *cur,
char *s,
int line)
@@ -274,21 +274,21 @@ xfs_bmbt_trace_cursor(
}
#define XFS_BMBT_TRACE_ARGBI(c,b,i) \
- xfs_bmbt_trace_argbi(fname, c, b, i, __LINE__)
+ xfs_bmbt_trace_argbi(__FUNCTION__, c, b, i, __LINE__)
#define XFS_BMBT_TRACE_ARGBII(c,b,i,j) \
- xfs_bmbt_trace_argbii(fname, c, b, i, j, __LINE__)
+ xfs_bmbt_trace_argbii(__FUNCTION__, c, b, i, j, __LINE__)
#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j) \
- xfs_bmbt_trace_argfffi(fname, c, o, b, i, j, __LINE__)
+ xfs_bmbt_trace_argfffi(__FUNCTION__, c, o, b, i, j, __LINE__)
#define XFS_BMBT_TRACE_ARGI(c,i) \
- xfs_bmbt_trace_argi(fname, c, i, __LINE__)
+ xfs_bmbt_trace_argi(__FUNCTION__, c, i, __LINE__)
#define XFS_BMBT_TRACE_ARGIFK(c,i,f,s) \
- xfs_bmbt_trace_argifk(fname, c, i, f, s, __LINE__)
+ xfs_bmbt_trace_argifk(__FUNCTION__, c, i, f, s, __LINE__)
#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) \
- xfs_bmbt_trace_argifr(fname, c, i, f, r, __LINE__)
+ xfs_bmbt_trace_argifr(__FUNCTION__, c, i, f, r, __LINE__)
#define XFS_BMBT_TRACE_ARGIK(c,i,k) \
- xfs_bmbt_trace_argik(fname, c, i, k, __LINE__)
+ xfs_bmbt_trace_argik(__FUNCTION__, c, i, k, __LINE__)
#define XFS_BMBT_TRACE_CURSOR(c,s) \
- xfs_bmbt_trace_cursor(fname, c, s, __LINE__)
+ xfs_bmbt_trace_cursor(__FUNCTION__, c, s, __LINE__)
#else
#define XFS_BMBT_TRACE_ARGBI(c,b,i)
#define XFS_BMBT_TRACE_ARGBII(c,b,i,j)
@@ -318,9 +318,6 @@ xfs_bmbt_delrec(
xfs_fsblock_t bno; /* fs-relative block number */
xfs_buf_t *bp; /* buffer for block */
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_delrec";
-#endif
int i; /* loop counter */
int j; /* temp state */
xfs_bmbt_key_t key; /* bmap btree key */
@@ -694,9 +691,6 @@ xfs_bmbt_insrec(
xfs_bmbt_block_t *block; /* bmap btree block */
xfs_buf_t *bp; /* buffer for block */
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_insrec";
-#endif
int i; /* loop index */
xfs_bmbt_key_t key; /* bmap btree key */
xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */
@@ -881,9 +875,6 @@ xfs_bmbt_killroot(
#ifdef DEBUG
int error;
#endif
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_killroot";
-#endif
int i;
xfs_bmbt_key_t *kp;
xfs_inode_t *ip;
@@ -973,9 +964,6 @@ xfs_bmbt_log_keys(
int kfirst,
int klast)
{
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_keys";
-#endif
xfs_trans_t *tp;
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
@@ -1012,9 +1000,6 @@ xfs_bmbt_log_ptrs(
int pfirst,
int plast)
{
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_ptrs";
-#endif
xfs_trans_t *tp;
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
@@ -1055,9 +1040,6 @@ xfs_bmbt_lookup(
xfs_daddr_t d;
xfs_sfiloff_t diff;
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_lookup";
-#endif
xfs_fsblock_t fsbno=0;
int high;
int i;
@@ -1195,9 +1177,6 @@ xfs_bmbt_lshift(
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_lshift";
-#endif
#ifdef DEBUG
int i; /* loop counter */
#endif
@@ -1331,9 +1310,6 @@ xfs_bmbt_rshift(
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_rshift";
-#endif
int i; /* loop counter */
xfs_bmbt_key_t key; /* bmap btree key */
xfs_buf_t *lbp; /* left buffer pointer */
@@ -1492,9 +1468,6 @@ xfs_bmbt_split(
{
xfs_alloc_arg_t args; /* block allocation args */
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_split";
-#endif
int i; /* loop counter */
xfs_fsblock_t lbno; /* left sibling block number */
xfs_buf_t *lbp; /* left buffer pointer */
@@ -1641,9 +1614,6 @@ xfs_bmbt_updkey(
#ifdef DEBUG
int error;
#endif
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_updkey";
-#endif
xfs_bmbt_key_t *kp;
int ptr;
@@ -1712,9 +1682,6 @@ xfs_bmbt_decrement(
xfs_bmbt_block_t *block;
xfs_buf_t *bp;
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_decrement";
-#endif
xfs_fsblock_t fsbno;
int lev;
xfs_mount_t *mp;
@@ -1785,9 +1752,6 @@ xfs_bmbt_delete(
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_delete";
-#endif
int i;
int level;
@@ -2000,9 +1964,6 @@ xfs_bmbt_increment(
xfs_bmbt_block_t *block;
xfs_buf_t *bp;
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_increment";
-#endif
xfs_fsblock_t fsbno;
int lev;
xfs_mount_t *mp;
@@ -2080,9 +2041,6 @@ xfs_bmbt_insert(
int *stat) /* success/failure */
{
int error; /* error return value */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_insert";
-#endif
int i;
int level;
xfs_fsblock_t nbno;
@@ -2142,9 +2100,6 @@ xfs_bmbt_log_block(
int fields)
{
int first;
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_block";
-#endif
int last;
xfs_trans_t *tp;
static const short offsets[] = {
@@ -2181,9 +2136,6 @@ xfs_bmbt_log_recs(
{
xfs_bmbt_block_t *block;
int first;
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_log_recs";
-#endif
int last;
xfs_bmbt_rec_t *rp;
xfs_trans_t *tp;
@@ -2245,9 +2197,6 @@ xfs_bmbt_newroot(
xfs_bmbt_key_t *ckp; /* child key pointer */
xfs_bmbt_ptr_t *cpp; /* child ptr pointer */
int error; /* error return code */
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_newroot";
-#endif
#ifdef DEBUG
int i; /* loop counter */
#endif
@@ -2630,9 +2579,6 @@ xfs_bmbt_update(
xfs_bmbt_block_t *block;
xfs_buf_t *bp;
int error;
-#ifdef XFS_BMBT_TRACE
- static char fname[] = "xfs_bmbt_update";
-#endif
xfs_bmbt_key_t key;
int ptr;
xfs_bmbt_rec_t *rp;
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h
index 4e27d55a1e73..6e40a0a198ff 100644
--- a/fs/xfs/xfs_btree.h
+++ b/fs/xfs/xfs_btree.h
@@ -444,30 +444,14 @@ xfs_btree_setbuf(
/*
* Min and max functions for extlen, agblock, fileoff, and filblks types.
*/
-#define XFS_EXTLEN_MIN(a,b) \
- ((xfs_extlen_t)(a) < (xfs_extlen_t)(b) ? \
- (xfs_extlen_t)(a) : (xfs_extlen_t)(b))
-#define XFS_EXTLEN_MAX(a,b) \
- ((xfs_extlen_t)(a) > (xfs_extlen_t)(b) ? \
- (xfs_extlen_t)(a) : (xfs_extlen_t)(b))
-#define XFS_AGBLOCK_MIN(a,b) \
- ((xfs_agblock_t)(a) < (xfs_agblock_t)(b) ? \
- (xfs_agblock_t)(a) : (xfs_agblock_t)(b))
-#define XFS_AGBLOCK_MAX(a,b) \
- ((xfs_agblock_t)(a) > (xfs_agblock_t)(b) ? \
- (xfs_agblock_t)(a) : (xfs_agblock_t)(b))
-#define XFS_FILEOFF_MIN(a,b) \
- ((xfs_fileoff_t)(a) < (xfs_fileoff_t)(b) ? \
- (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b))
-#define XFS_FILEOFF_MAX(a,b) \
- ((xfs_fileoff_t)(a) > (xfs_fileoff_t)(b) ? \
- (xfs_fileoff_t)(a) : (xfs_fileoff_t)(b))
-#define XFS_FILBLKS_MIN(a,b) \
- ((xfs_filblks_t)(a) < (xfs_filblks_t)(b) ? \
- (xfs_filblks_t)(a) : (xfs_filblks_t)(b))
-#define XFS_FILBLKS_MAX(a,b) \
- ((xfs_filblks_t)(a) > (xfs_filblks_t)(b) ? \
- (xfs_filblks_t)(a) : (xfs_filblks_t)(b))
+#define XFS_EXTLEN_MIN(a,b) min_t(xfs_extlen_t, (a), (b))
+#define XFS_EXTLEN_MAX(a,b) max_t(xfs_extlen_t, (a), (b))
+#define XFS_AGBLOCK_MIN(a,b) min_t(xfs_agblock_t, (a), (b))
+#define XFS_AGBLOCK_MAX(a,b) max_t(xfs_agblock_t, (a), (b))
+#define XFS_FILEOFF_MIN(a,b) min_t(xfs_fileoff_t, (a), (b))
+#define XFS_FILEOFF_MAX(a,b) max_t(xfs_fileoff_t, (a), (b))
+#define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b))
+#define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b))
#define XFS_FSB_SANITY_CHECK(mp,fsb) \
(XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index 6c1bddc04e31..b0667cb27d66 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -580,8 +580,8 @@ xfs_buf_item_unlock(
* If the buf item isn't tracking any data, free it.
* Otherwise, if XFS_BLI_HOLD is set clear it.
*/
- if (xfs_count_bits(bip->bli_format.blf_data_map,
- bip->bli_format.blf_map_size, 0) == 0) {
+ if (xfs_bitmap_empty(bip->bli_format.blf_data_map,
+ bip->bli_format.blf_map_size)) {
xfs_buf_item_relse(bp);
} else if (hold) {
bip->bli_flags &= ~XFS_BLI_HOLD;
diff --git a/fs/xfs/xfs_clnt.h b/fs/xfs/xfs_clnt.h
index 5b7eb81453be..f89196cb08d2 100644
--- a/fs/xfs/xfs_clnt.h
+++ b/fs/xfs/xfs_clnt.h
@@ -99,5 +99,7 @@ struct xfs_mount_args {
*/
#define XFSMNT2_COMPAT_IOSIZE 0x00000001 /* don't report large preferred
* I/O size in stat(2) */
+#define XFSMNT2_FILESTREAMS 0x00000002 /* enable the filestreams
+ * allocator */
#endif /* __XFS_CLNT_H__ */
diff --git a/fs/xfs/xfs_dinode.h b/fs/xfs/xfs_dinode.h
index b33826961c45..fefd0116bac9 100644
--- a/fs/xfs/xfs_dinode.h
+++ b/fs/xfs/xfs_dinode.h
@@ -257,6 +257,7 @@ typedef enum xfs_dinode_fmt
#define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */
#define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */
#define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */
+#define XFS_DIFLAG_FILESTREAM_BIT 14 /* use filestream allocator */
#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT)
#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT)
#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT)
@@ -271,12 +272,13 @@ typedef enum xfs_dinode_fmt
#define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT)
#define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT)
#define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT)
+#define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT)
#define XFS_DIFLAG_ANY \
(XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \
XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \
XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \
XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \
- XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG)
+ XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM)
#endif /* __XFS_DINODE_H__ */
diff --git a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
index 8e8e5279334a..29e091914df4 100644
--- a/fs/xfs/xfs_dir2.c
+++ b/fs/xfs/xfs_dir2.c
@@ -55,9 +55,9 @@ xfs_dir_mount(
XFS_MAX_BLOCKSIZE);
mp->m_dirblksize = 1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog);
mp->m_dirblkfsbs = 1 << mp->m_sb.sb_dirblklog;
- mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp));
- mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
- mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp));
+ mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
+ mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
+ mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
mp->m_attr_node_ents =
(mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
(uint)sizeof(xfs_da_node_entry_t);
@@ -554,7 +554,7 @@ xfs_dir2_grow_inode(
*/
if (mapp != &map)
kmem_free(mapp, sizeof(*mapp) * count);
- *dbp = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)bno);
+ *dbp = xfs_dir2_da_to_db(mp, (xfs_dablk_t)bno);
/*
* Update file's size if this is the data space and it grew.
*/
@@ -706,7 +706,7 @@ xfs_dir2_shrink_inode(
dp = args->dp;
mp = dp->i_mount;
tp = args->trans;
- da = XFS_DIR2_DB_TO_DA(mp, db);
+ da = xfs_dir2_db_to_da(mp, db);
/*
* Unmap the fsblock(s).
*/
@@ -742,7 +742,7 @@ xfs_dir2_shrink_inode(
/*
* If the block isn't the last one in the directory, we're done.
*/
- if (dp->i_d.di_size > XFS_DIR2_DB_OFF_TO_BYTE(mp, db + 1, 0))
+ if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(mp, db + 1, 0))
return 0;
bno = da;
if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) {
diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c
index 3accc1dcd6c9..e4df1aaae2a2 100644
--- a/fs/xfs/xfs_dir2_block.c
+++ b/fs/xfs/xfs_dir2_block.c
@@ -115,13 +115,13 @@ xfs_dir2_block_addname(
xfs_da_brelse(tp, bp);
return XFS_ERROR(EFSCORRUPTED);
}
- len = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ len = xfs_dir2_data_entsize(args->namelen);
/*
* Set up pointers to parts of the block.
*/
bf = block->hdr.bestfree;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* No stale entries? Need space for entry and new leaf.
*/
@@ -396,7 +396,7 @@ xfs_dir2_block_addname(
* Fill in the leaf entry.
*/
blp[mid].hashval = cpu_to_be32(args->hashval);
- blp[mid].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh);
/*
@@ -411,7 +411,7 @@ xfs_dir2_block_addname(
dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen;
memcpy(dep->name, args->name, args->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
/*
* Clean up the bestfree array and log the header, tail, and entry.
@@ -455,7 +455,7 @@ xfs_dir2_block_getdents(
/*
* If the block number in the offset is out of range, we're done.
*/
- if (XFS_DIR2_DATAPTR_TO_DB(mp, uio->uio_offset) > mp->m_dirdatablk) {
+ if (xfs_dir2_dataptr_to_db(mp, uio->uio_offset) > mp->m_dirdatablk) {
*eofp = 1;
return 0;
}
@@ -471,15 +471,15 @@ xfs_dir2_block_getdents(
* Extract the byte offset we start at from the seek pointer.
* We'll skip entries before this.
*/
- wantoff = XFS_DIR2_DATAPTR_TO_OFF(mp, uio->uio_offset);
+ wantoff = xfs_dir2_dataptr_to_off(mp, uio->uio_offset);
block = bp->data;
xfs_dir2_data_check(dp, bp);
/*
* Set up values for the loop.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
ptr = (char *)block->u;
- endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
+ endptr = (char *)xfs_dir2_block_leaf_p(btp);
p.dbp = dbp;
p.put = put;
p.uio = uio;
@@ -502,7 +502,7 @@ xfs_dir2_block_getdents(
/*
* Bump pointer for the next iteration.
*/
- ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ ptr += xfs_dir2_data_entsize(dep->namelen);
/*
* The entry is before the desired starting point, skip it.
*/
@@ -513,7 +513,7 @@ xfs_dir2_block_getdents(
*/
p.namelen = dep->namelen;
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
ptr - (char *)block);
p.ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS
@@ -531,7 +531,7 @@ xfs_dir2_block_getdents(
*/
if (!p.done) {
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(char *)dep - (char *)block);
xfs_da_brelse(tp, bp);
return error;
@@ -545,7 +545,7 @@ xfs_dir2_block_getdents(
*eofp = 1;
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0);
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
xfs_da_brelse(tp, bp);
@@ -569,8 +569,8 @@ xfs_dir2_block_log_leaf(
mp = tp->t_mountp;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block),
(uint)((char *)&blp[last + 1] - (char *)block - 1));
}
@@ -589,7 +589,7 @@ xfs_dir2_block_log_tail(
mp = tp->t_mountp;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)block),
(uint)((char *)(btp + 1) - (char *)block - 1));
}
@@ -623,13 +623,13 @@ xfs_dir2_block_lookup(
mp = dp->i_mount;
block = bp->data;
xfs_dir2_data_check(dp, bp);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Get the offset from the leaf entry, to point to the data.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
/*
* Fill in inode number, release the block.
*/
@@ -675,8 +675,8 @@ xfs_dir2_block_lookup_int(
ASSERT(bp != NULL);
block = bp->data;
xfs_dir2_data_check(dp, bp);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Loop doing a binary search for our hash value.
* Find our entry, ENOENT if it's not there.
@@ -713,7 +713,7 @@ xfs_dir2_block_lookup_int(
* Get pointer to the entry from the leaf.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
/*
* Compare, if it's right give back buffer & entry number.
*/
@@ -768,20 +768,20 @@ xfs_dir2_block_removename(
tp = args->trans;
mp = dp->i_mount;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Point to the data entry using the leaf entry.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
/*
* Mark the data entry's space free.
*/
needlog = needscan = 0;
xfs_dir2_data_make_free(tp, bp,
(xfs_dir2_data_aoff_t)((char *)dep - (char *)block),
- XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
+ xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
/*
* Fix up the block tail.
*/
@@ -843,13 +843,13 @@ xfs_dir2_block_replace(
dp = args->dp;
mp = dp->i_mount;
block = bp->data;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Point to the data entry we need to change.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(blp[ent].address)));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));
ASSERT(be64_to_cpu(dep->inumber) != args->inumber);
/*
* Change the inode number to the new value.
@@ -912,7 +912,7 @@ xfs_dir2_leaf_to_block(
mp = dp->i_mount;
leaf = lbp->data;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
/*
* If there are data blocks other than the first one, take this
* opportunity to remove trailing empty data blocks that may have
@@ -920,7 +920,7 @@ xfs_dir2_leaf_to_block(
* These will show up in the leaf bests table.
*/
while (dp->i_d.di_size > mp->m_dirblksize) {
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==
mp->m_dirblksize - (uint)sizeof(block->hdr)) {
if ((error =
@@ -974,14 +974,14 @@ xfs_dir2_leaf_to_block(
/*
* Initialize the block tail.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
btp->count = cpu_to_be32(be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));
btp->stale = 0;
xfs_dir2_block_log_tail(tp, dbp);
/*
* Initialize the block leaf area. We compact out stale entries.
*/
- lep = XFS_DIR2_BLOCK_LEAF_P(btp);
+ lep = xfs_dir2_block_leaf_p(btp);
for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) {
if (be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR)
continue;
@@ -1067,7 +1067,7 @@ xfs_dir2_sf_to_block(
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Copy the directory into the stack buffer.
* Then pitch the incore inode data so we can make extents.
@@ -1119,10 +1119,10 @@ xfs_dir2_sf_to_block(
/*
* Fill in the tail.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
btp->count = cpu_to_be32(sfp->hdr.count + 2); /* ., .. */
btp->stale = 0;
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ blp = xfs_dir2_block_leaf_p(btp);
endoffset = (uint)((char *)blp - (char *)block);
/*
* Remove the freespace, we'll manage it.
@@ -1138,25 +1138,25 @@ xfs_dir2_sf_to_block(
dep->inumber = cpu_to_be64(dp->i_ino);
dep->namelen = 1;
dep->name[0] = '.';
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
- blp[0].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
/*
* Create entry for ..
*/
dep = (xfs_dir2_data_entry_t *)
((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);
- dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
+ dep->inumber = cpu_to_be64(xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent));
dep->namelen = 2;
dep->name[0] = dep->name[1] = '.';
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
- blp[1].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
offset = XFS_DIR2_DATA_FIRST_OFFSET;
/*
@@ -1165,7 +1165,7 @@ xfs_dir2_sf_to_block(
if ((i = 0) == sfp->hdr.count)
sfep = NULL;
else
- sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ sfep = xfs_dir2_sf_firstentry(sfp);
/*
* Need to preserve the existing offset values in the sf directory.
* Insert holes (unused entries) where necessary.
@@ -1177,7 +1177,7 @@ xfs_dir2_sf_to_block(
if (sfep == NULL)
newoffset = endoffset;
else
- newoffset = XFS_DIR2_SF_GET_OFFSET(sfep);
+ newoffset = xfs_dir2_sf_get_offset(sfep);
/*
* There should be a hole here, make one.
*/
@@ -1186,7 +1186,7 @@ xfs_dir2_sf_to_block(
((char *)block + offset);
dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
dup->length = cpu_to_be16(newoffset - offset);
- *XFS_DIR2_DATA_UNUSED_TAG_P(dup) = cpu_to_be16(
+ *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16(
((char *)dup - (char *)block));
xfs_dir2_data_log_unused(tp, bp, dup);
(void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block,
@@ -1198,22 +1198,22 @@ xfs_dir2_sf_to_block(
* Copy a real entry.
*/
dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);
- dep->inumber = cpu_to_be64(XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep)));
+ dep->inumber = cpu_to_be64(xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep)));
dep->namelen = sfep->namelen;
memcpy(dep->name, sfep->name, dep->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)block);
xfs_dir2_data_log_entry(tp, bp, dep);
blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname(
(char *)sfep->name, sfep->namelen));
- blp[2 + i].address = cpu_to_be32(XFS_DIR2_BYTE_TO_DATAPTR(mp,
+ blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
(char *)dep - (char *)block));
offset = (int)((char *)(tagp + 1) - (char *)block);
if (++i == sfp->hdr.count)
sfep = NULL;
else
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
/* Done with the temporary buffer */
kmem_free(buf, buf_len);
diff --git a/fs/xfs/xfs_dir2_block.h b/fs/xfs/xfs_dir2_block.h
index 6722effd0b20..e7c2606161e9 100644
--- a/fs/xfs/xfs_dir2_block.h
+++ b/fs/xfs/xfs_dir2_block.h
@@ -60,7 +60,6 @@ typedef struct xfs_dir2_block {
/*
* Pointer to the leaf header embedded in a data block (1-block format)
*/
-#define XFS_DIR2_BLOCK_TAIL_P(mp,block) xfs_dir2_block_tail_p(mp,block)
static inline xfs_dir2_block_tail_t *
xfs_dir2_block_tail_p(struct xfs_mount *mp, xfs_dir2_block_t *block)
{
@@ -71,7 +70,6 @@ xfs_dir2_block_tail_p(struct xfs_mount *mp, xfs_dir2_block_t *block)
/*
* Pointer to the leaf entries embedded in a data block (1-block format)
*/
-#define XFS_DIR2_BLOCK_LEAF_P(btp) xfs_dir2_block_leaf_p(btp)
static inline struct xfs_dir2_leaf_entry *
xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp)
{
diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c
index c211c37ef67c..7ebe295bd6d3 100644
--- a/fs/xfs/xfs_dir2_data.c
+++ b/fs/xfs/xfs_dir2_data.c
@@ -72,8 +72,8 @@ xfs_dir2_data_check(
bf = d->hdr.bestfree;
p = (char *)d->u;
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
- lep = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, (xfs_dir2_block_t *)d);
+ lep = xfs_dir2_block_leaf_p(btp);
endp = (char *)lep;
} else
endp = (char *)d + mp->m_dirblksize;
@@ -107,7 +107,7 @@ xfs_dir2_data_check(
*/
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
ASSERT(lastfree == 0);
- ASSERT(be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)) ==
+ ASSERT(be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) ==
(char *)dup - (char *)d);
dfp = xfs_dir2_data_freefind(d, dup);
if (dfp) {
@@ -131,12 +131,12 @@ xfs_dir2_data_check(
dep = (xfs_dir2_data_entry_t *)p;
ASSERT(dep->namelen != 0);
ASSERT(xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)) == 0);
- ASSERT(be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)) ==
+ ASSERT(be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
(char *)dep - (char *)d);
count++;
lastfree = 0;
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
- addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ addr = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
(xfs_dir2_data_aoff_t)
((char *)dep - (char *)d));
hash = xfs_da_hashname((char *)dep->name, dep->namelen);
@@ -147,7 +147,7 @@ xfs_dir2_data_check(
}
ASSERT(i < be32_to_cpu(btp->count));
}
- p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ p += xfs_dir2_data_entsize(dep->namelen);
}
/*
* Need to have seen all the entries and all the bestfree slots.
@@ -346,8 +346,8 @@ xfs_dir2_data_freescan(
*/
p = (char *)d->u;
if (be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
- endp = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, (xfs_dir2_block_t *)d);
+ endp = (char *)xfs_dir2_block_leaf_p(btp);
} else
endp = (char *)d + mp->m_dirblksize;
/*
@@ -360,7 +360,7 @@ xfs_dir2_data_freescan(
*/
if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
ASSERT((char *)dup - (char *)d ==
- be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
+ be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
xfs_dir2_data_freeinsert(d, dup, loghead);
p += be16_to_cpu(dup->length);
}
@@ -370,8 +370,8 @@ xfs_dir2_data_freescan(
else {
dep = (xfs_dir2_data_entry_t *)p;
ASSERT((char *)dep - (char *)d ==
- be16_to_cpu(*XFS_DIR2_DATA_ENTRY_TAG_P(dep)));
- p += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)));
+ p += xfs_dir2_data_entsize(dep->namelen);
}
}
}
@@ -402,7 +402,7 @@ xfs_dir2_data_init(
/*
* Get the buffer set up for the block.
*/
- error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, blkno), -1, &bp,
+ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, blkno), -1, &bp,
XFS_DATA_FORK);
if (error) {
return error;
@@ -427,7 +427,7 @@ xfs_dir2_data_init(
t=mp->m_dirblksize - (uint)sizeof(d->hdr);
d->hdr.bestfree[0].length = cpu_to_be16(t);
dup->length = cpu_to_be16(t);
- *XFS_DIR2_DATA_UNUSED_TAG_P(dup) = cpu_to_be16((char *)dup - (char *)d);
+ *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)d);
/*
* Log it and return it.
*/
@@ -452,7 +452,7 @@ xfs_dir2_data_log_entry(
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_DATA_MAGIC ||
be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
xfs_da_log_buf(tp, bp, (uint)((char *)dep - (char *)d),
- (uint)((char *)(XFS_DIR2_DATA_ENTRY_TAG_P(dep) + 1) -
+ (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
(char *)d - 1));
}
@@ -497,8 +497,8 @@ xfs_dir2_data_log_unused(
* Log the end (tag) of the unused entry.
*/
xfs_da_log_buf(tp, bp,
- (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d),
- (uint)((char *)XFS_DIR2_DATA_UNUSED_TAG_P(dup) - (char *)d +
+ (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)d),
+ (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)d +
sizeof(xfs_dir2_data_off_t) - 1));
}
@@ -535,8 +535,8 @@ xfs_dir2_data_make_free(
xfs_dir2_block_tail_t *btp; /* block tail */
ASSERT(be32_to_cpu(d->hdr.magic) == XFS_DIR2_BLOCK_MAGIC);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)d);
- endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, (xfs_dir2_block_t *)d);
+ endptr = (char *)xfs_dir2_block_leaf_p(btp);
}
/*
* If this isn't the start of the block, then back up to
@@ -587,7 +587,7 @@ xfs_dir2_data_make_free(
* Fix up the new big freespace.
*/
be16_add(&prevdup->length, len + be16_to_cpu(postdup->length));
- *XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
+ *xfs_dir2_data_unused_tag_p(prevdup) =
cpu_to_be16((char *)prevdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, prevdup);
if (!needscan) {
@@ -621,7 +621,7 @@ xfs_dir2_data_make_free(
else if (prevdup) {
dfp = xfs_dir2_data_freefind(d, prevdup);
be16_add(&prevdup->length, len);
- *XFS_DIR2_DATA_UNUSED_TAG_P(prevdup) =
+ *xfs_dir2_data_unused_tag_p(prevdup) =
cpu_to_be16((char *)prevdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, prevdup);
/*
@@ -649,7 +649,7 @@ xfs_dir2_data_make_free(
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length));
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
/*
@@ -676,7 +676,7 @@ xfs_dir2_data_make_free(
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset);
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup->length = cpu_to_be16(len);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
(void)xfs_dir2_data_freeinsert(d, newdup, needlogp);
@@ -712,7 +712,7 @@ xfs_dir2_data_use_free(
ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG);
ASSERT(offset >= (char *)dup - (char *)d);
ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)d);
- ASSERT((char *)dup - (char *)d == be16_to_cpu(*XFS_DIR2_DATA_UNUSED_TAG_P(dup)));
+ ASSERT((char *)dup - (char *)d == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)));
/*
* Look up the entry in the bestfree table.
*/
@@ -745,7 +745,7 @@ xfs_dir2_data_use_free(
newdup = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup->length = cpu_to_be16(oldlen - len);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
/*
@@ -772,7 +772,7 @@ xfs_dir2_data_use_free(
else if (matchback) {
newdup = dup;
newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
/*
@@ -799,13 +799,13 @@ xfs_dir2_data_use_free(
else {
newdup = dup;
newdup->length = cpu_to_be16(((char *)d + offset) - (char *)newdup);
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup) =
+ *xfs_dir2_data_unused_tag_p(newdup) =
cpu_to_be16((char *)newdup - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup);
newdup2 = (xfs_dir2_data_unused_t *)((char *)d + offset + len);
newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);
newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length));
- *XFS_DIR2_DATA_UNUSED_TAG_P(newdup2) =
+ *xfs_dir2_data_unused_tag_p(newdup2) =
cpu_to_be16((char *)newdup2 - (char *)d);
xfs_dir2_data_log_unused(tp, bp, newdup2);
/*
diff --git a/fs/xfs/xfs_dir2_data.h b/fs/xfs/xfs_dir2_data.h
index c94c9099cfb1..b816e0252739 100644
--- a/fs/xfs/xfs_dir2_data.h
+++ b/fs/xfs/xfs_dir2_data.h
@@ -44,7 +44,7 @@ struct xfs_trans;
#define XFS_DIR2_DATA_SPACE 0
#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_DATA_FIRSTDB(mp) \
- XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATA_OFFSET)
+ xfs_dir2_byte_to_db(mp, XFS_DIR2_DATA_OFFSET)
/*
* Offsets of . and .. in data space (always block 0)
@@ -52,9 +52,9 @@ struct xfs_trans;
#define XFS_DIR2_DATA_DOT_OFFSET \
((xfs_dir2_data_aoff_t)sizeof(xfs_dir2_data_hdr_t))
#define XFS_DIR2_DATA_DOTDOT_OFFSET \
- (XFS_DIR2_DATA_DOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(1))
+ (XFS_DIR2_DATA_DOT_OFFSET + xfs_dir2_data_entsize(1))
#define XFS_DIR2_DATA_FIRST_OFFSET \
- (XFS_DIR2_DATA_DOTDOT_OFFSET + XFS_DIR2_DATA_ENTSIZE(2))
+ (XFS_DIR2_DATA_DOTDOT_OFFSET + xfs_dir2_data_entsize(2))
/*
* Structures.
@@ -123,7 +123,6 @@ typedef struct xfs_dir2_data {
/*
* Size of a data entry.
*/
-#define XFS_DIR2_DATA_ENTSIZE(n) xfs_dir2_data_entsize(n)
static inline int xfs_dir2_data_entsize(int n)
{
return (int)roundup(offsetof(xfs_dir2_data_entry_t, name[0]) + (n) + \
@@ -133,19 +132,16 @@ static inline int xfs_dir2_data_entsize(int n)
/*
* Pointer to an entry's tag word.
*/
-#define XFS_DIR2_DATA_ENTRY_TAG_P(dep) xfs_dir2_data_entry_tag_p(dep)
static inline __be16 *
xfs_dir2_data_entry_tag_p(xfs_dir2_data_entry_t *dep)
{
return (__be16 *)((char *)dep +
- XFS_DIR2_DATA_ENTSIZE(dep->namelen) - sizeof(__be16));
+ xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16));
}
/*
* Pointer to a freespace's tag word.
*/
-#define XFS_DIR2_DATA_UNUSED_TAG_P(dup) \
- xfs_dir2_data_unused_tag_p(dup)
static inline __be16 *
xfs_dir2_data_unused_tag_p(xfs_dir2_data_unused_t *dup)
{
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index db14ea71459f..1b73c9ad646a 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -92,7 +92,7 @@ xfs_dir2_block_to_leaf(
if ((error = xfs_da_grow_inode(args, &blkno))) {
return error;
}
- ldb = XFS_DIR2_DA_TO_DB(mp, blkno);
+ ldb = xfs_dir2_da_to_db(mp, blkno);
ASSERT(ldb == XFS_DIR2_LEAF_FIRSTDB(mp));
/*
* Initialize the leaf block, get a buffer for it.
@@ -104,8 +104,8 @@ xfs_dir2_block_to_leaf(
leaf = lbp->data;
block = dbp->data;
xfs_dir2_data_check(dp, dbp);
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Set the counts in the leaf header.
*/
@@ -137,9 +137,9 @@ xfs_dir2_block_to_leaf(
/*
* Set up leaf tail and bests table.
*/
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = cpu_to_be32(1);
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
bestsp[0] = block->hdr.bestfree[0].length;
/*
* Log the data header and leaf bests table.
@@ -209,9 +209,9 @@ xfs_dir2_leaf_addname(
*/
index = xfs_dir2_leaf_search_hash(args, lbp);
leaf = lbp->data;
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
- length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
+ length = xfs_dir2_data_entsize(args->namelen);
/*
* See if there are any entries with the same hash value
* and space in their block for the new entry.
@@ -223,7 +223,7 @@ xfs_dir2_leaf_addname(
index++, lep++) {
if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
continue;
- i = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ i = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
ASSERT(i < be32_to_cpu(ltp->bestcount));
ASSERT(be16_to_cpu(bestsp[i]) != NULLDATAOFF);
if (be16_to_cpu(bestsp[i]) >= length) {
@@ -378,7 +378,7 @@ xfs_dir2_leaf_addname(
*/
else {
if ((error =
- xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, use_block),
+ xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, use_block),
-1, &dbp, XFS_DATA_FORK))) {
xfs_da_brelse(tp, lbp);
return error;
@@ -407,7 +407,7 @@ xfs_dir2_leaf_addname(
dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen;
memcpy(dep->name, args->name, dep->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)data);
/*
* Need to scan fix up the bestfree table.
@@ -529,7 +529,7 @@ xfs_dir2_leaf_addname(
* Fill in the new leaf entry.
*/
lep->hashval = cpu_to_be32(args->hashval);
- lep->address = cpu_to_be32(XFS_DIR2_DB_OFF_TO_DATAPTR(mp, use_block,
+ lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp, use_block,
be16_to_cpu(*tagp)));
/*
* Log the leaf fields and give up the buffers.
@@ -567,13 +567,13 @@ xfs_dir2_leaf_check(
* Should factor in the size of the bests table as well.
* We can deduce a value for that from di_size.
*/
- ASSERT(be16_to_cpu(leaf->hdr.count) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp));
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
/*
* Leaves and bests don't overlap.
*/
ASSERT((char *)&leaf->ents[be16_to_cpu(leaf->hdr.count)] <=
- (char *)XFS_DIR2_LEAF_BESTS_P(ltp));
+ (char *)xfs_dir2_leaf_bests_p(ltp));
/*
* Check hash value order, count stale entries.
*/
@@ -815,12 +815,12 @@ xfs_dir2_leaf_getdents(
* Inside the loop we keep the main offset value as a byte offset
* in the directory file.
*/
- curoff = XFS_DIR2_DATAPTR_TO_BYTE(mp, uio->uio_offset);
+ curoff = xfs_dir2_dataptr_to_byte(mp, uio->uio_offset);
/*
* Force this conversion through db so we truncate the offset
* down to get the start of the data block.
*/
- map_off = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, curoff));
+ map_off = xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, curoff));
/*
* Loop over directory entries until we reach the end offset.
* Get more blocks and readahead as necessary.
@@ -870,7 +870,7 @@ xfs_dir2_leaf_getdents(
*/
if (1 + ra_want > map_blocks &&
map_off <
- XFS_DIR2_BYTE_TO_DA(mp, XFS_DIR2_LEAF_OFFSET)) {
+ xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
/*
* Get more bmaps, fill in after the ones
* we already have in the table.
@@ -878,7 +878,7 @@ xfs_dir2_leaf_getdents(
nmap = map_size - map_valid;
error = xfs_bmapi(tp, dp,
map_off,
- XFS_DIR2_BYTE_TO_DA(mp,
+ xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET) - map_off,
XFS_BMAPI_METADATA, NULL, 0,
&map[map_valid], &nmap, NULL, NULL);
@@ -903,7 +903,7 @@ xfs_dir2_leaf_getdents(
map[map_valid + nmap - 1].br_blockcount;
else
map_off =
- XFS_DIR2_BYTE_TO_DA(mp,
+ xfs_dir2_byte_to_da(mp,
XFS_DIR2_LEAF_OFFSET);
/*
* Look for holes in the mapping, and
@@ -931,14 +931,14 @@ xfs_dir2_leaf_getdents(
* No valid mappings, so no more data blocks.
*/
if (!map_valid) {
- curoff = XFS_DIR2_DA_TO_BYTE(mp, map_off);
+ curoff = xfs_dir2_da_to_byte(mp, map_off);
break;
}
/*
* Read the directory block starting at the first
* mapping.
*/
- curdb = XFS_DIR2_DA_TO_DB(mp, map->br_startoff);
+ curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
error = xfs_da_read_buf(tp, dp, map->br_startoff,
map->br_blockcount >= mp->m_dirblkfsbs ?
XFS_FSB_TO_DADDR(mp, map->br_startblock) :
@@ -1014,7 +1014,7 @@ xfs_dir2_leaf_getdents(
/*
* Having done a read, we need to set a new offset.
*/
- newoff = XFS_DIR2_DB_OFF_TO_BYTE(mp, curdb, 0);
+ newoff = xfs_dir2_db_off_to_byte(mp, curdb, 0);
/*
* Start of the current block.
*/
@@ -1024,7 +1024,7 @@ xfs_dir2_leaf_getdents(
* Make sure we're in the right block.
*/
else if (curoff > newoff)
- ASSERT(XFS_DIR2_BYTE_TO_DB(mp, curoff) ==
+ ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
curdb);
data = bp->data;
xfs_dir2_data_check(dp, bp);
@@ -1032,7 +1032,7 @@ xfs_dir2_leaf_getdents(
* Find our position in the block.
*/
ptr = (char *)&data->u;
- byteoff = XFS_DIR2_BYTE_TO_OFF(mp, curoff);
+ byteoff = xfs_dir2_byte_to_off(mp, curoff);
/*
* Skip past the header.
*/
@@ -1054,15 +1054,15 @@ xfs_dir2_leaf_getdents(
}
dep = (xfs_dir2_data_entry_t *)ptr;
length =
- XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ xfs_dir2_data_entsize(dep->namelen);
ptr += length;
}
/*
* Now set our real offset.
*/
curoff =
- XFS_DIR2_DB_OFF_TO_BYTE(mp,
- XFS_DIR2_BYTE_TO_DB(mp, curoff),
+ xfs_dir2_db_off_to_byte(mp,
+ xfs_dir2_byte_to_db(mp, curoff),
(char *)ptr - (char *)data);
if (ptr >= (char *)data + mp->m_dirblksize) {
continue;
@@ -1091,9 +1091,9 @@ xfs_dir2_leaf_getdents(
p->namelen = dep->namelen;
- length = XFS_DIR2_DATA_ENTSIZE(p->namelen);
+ length = xfs_dir2_data_entsize(p->namelen);
- p->cook = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff + length);
+ p->cook = xfs_dir2_byte_to_dataptr(mp, curoff + length);
p->ino = be64_to_cpu(dep->inumber);
#if XFS_BIG_INUMS
@@ -1121,10 +1121,10 @@ xfs_dir2_leaf_getdents(
* All done. Set output offset value to current offset.
*/
*eofp = eof;
- if (curoff > XFS_DIR2_DATAPTR_TO_BYTE(mp, XFS_DIR2_MAX_DATAPTR))
+ if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
uio->uio_offset = XFS_DIR2_MAX_DATAPTR;
else
- uio->uio_offset = XFS_DIR2_BYTE_TO_DATAPTR(mp, curoff);
+ uio->uio_offset = xfs_dir2_byte_to_dataptr(mp, curoff);
kmem_free(map, map_size * sizeof(*map));
kmem_free(p, sizeof(*p));
if (bp)
@@ -1159,7 +1159,7 @@ xfs_dir2_leaf_init(
/*
* Get the buffer for the block.
*/
- error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, bno), -1, &bp,
+ error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, bno), -1, &bp,
XFS_DATA_FORK);
if (error) {
return error;
@@ -1181,7 +1181,7 @@ xfs_dir2_leaf_init(
* the block.
*/
if (magic == XFS_DIR2_LEAF1_MAGIC) {
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = 0;
xfs_dir2_leaf_log_tail(tp, bp);
}
@@ -1206,9 +1206,9 @@ xfs_dir2_leaf_log_bests(
leaf = bp->data;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
- ltp = XFS_DIR2_LEAF_TAIL_P(tp->t_mountp, leaf);
- firstb = XFS_DIR2_LEAF_BESTS_P(ltp) + first;
- lastb = XFS_DIR2_LEAF_BESTS_P(ltp) + last;
+ ltp = xfs_dir2_leaf_tail_p(tp->t_mountp, leaf);
+ firstb = xfs_dir2_leaf_bests_p(ltp) + first;
+ lastb = xfs_dir2_leaf_bests_p(ltp) + last;
xfs_da_log_buf(tp, bp, (uint)((char *)firstb - (char *)leaf),
(uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1));
}
@@ -1268,7 +1268,7 @@ xfs_dir2_leaf_log_tail(
mp = tp->t_mountp;
leaf = bp->data;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
xfs_da_log_buf(tp, bp, (uint)((char *)ltp - (char *)leaf),
(uint)(mp->m_dirblksize - 1));
}
@@ -1312,7 +1312,7 @@ xfs_dir2_leaf_lookup(
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
/*
* Return the found inode number.
*/
@@ -1381,7 +1381,7 @@ xfs_dir2_leaf_lookup_int(
/*
* Get the new data block number.
*/
- newdb = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
/*
* If it's not the same as the old data block number,
* need to pitch the old one and read the new one.
@@ -1391,7 +1391,7 @@ xfs_dir2_leaf_lookup_int(
xfs_da_brelse(tp, dbp);
if ((error =
xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, newdb), -1, &dbp,
+ xfs_dir2_db_to_da(mp, newdb), -1, &dbp,
XFS_DATA_FORK))) {
xfs_da_brelse(tp, lbp);
return error;
@@ -1404,7 +1404,7 @@ xfs_dir2_leaf_lookup_int(
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/*
* If it matches then return it.
*/
@@ -1469,20 +1469,20 @@ xfs_dir2_leaf_removename(
* Point to the leaf entry, use that to point to the data entry.
*/
lep = &leaf->ents[index];
- db = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
dep = (xfs_dir2_data_entry_t *)
- ((char *)data + XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
+ ((char *)data + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
needscan = needlog = 0;
oldbest = be16_to_cpu(data->hdr.bestfree[0].length);
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
ASSERT(be16_to_cpu(bestsp[db]) == oldbest);
/*
* Mark the former data entry unused.
*/
xfs_dir2_data_make_free(tp, dbp,
(xfs_dir2_data_aoff_t)((char *)dep - (char *)data),
- XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
+ xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
/*
* We just mark the leaf entry stale by putting a null in it.
*/
@@ -1602,7 +1602,7 @@ xfs_dir2_leaf_replace(
*/
dep = (xfs_dir2_data_entry_t *)
((char *)dbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(dp->i_mount, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(dp->i_mount, be32_to_cpu(lep->address)));
ASSERT(args->inumber != be64_to_cpu(dep->inumber));
/*
* Put the new inode number in, log it.
@@ -1698,7 +1698,7 @@ xfs_dir2_leaf_trim_data(
/*
* Read the offending data block. We need its buffer.
*/
- if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, db), -1, &dbp,
+ if ((error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, db), -1, &dbp,
XFS_DATA_FORK))) {
return error;
}
@@ -1712,7 +1712,7 @@ xfs_dir2_leaf_trim_data(
*/
leaf = lbp->data;
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ASSERT(be16_to_cpu(data->hdr.bestfree[0].length) ==
mp->m_dirblksize - (uint)sizeof(data->hdr));
ASSERT(db == be32_to_cpu(ltp->bestcount) - 1);
@@ -1727,7 +1727,7 @@ xfs_dir2_leaf_trim_data(
/*
* Eliminate the last bests entry from the table.
*/
- bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
+ bestsp = xfs_dir2_leaf_bests_p(ltp);
be32_add(&ltp->bestcount, -1);
memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp));
xfs_dir2_leaf_log_tail(tp, lbp);
@@ -1838,12 +1838,12 @@ xfs_dir2_node_to_leaf(
/*
* Set up the leaf tail from the freespace block.
*/
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
ltp->bestcount = free->hdr.nvalid;
/*
* Set up the leaf bests table.
*/
- memcpy(XFS_DIR2_LEAF_BESTS_P(ltp), free->bests,
+ memcpy(xfs_dir2_leaf_bests_p(ltp), free->bests,
be32_to_cpu(ltp->bestcount) * sizeof(leaf->bests[0]));
xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1);
xfs_dir2_leaf_log_tail(tp, lbp);
diff --git a/fs/xfs/xfs_dir2_leaf.h b/fs/xfs/xfs_dir2_leaf.h
index f57ca1162412..70c97f3f815e 100644
--- a/fs/xfs/xfs_dir2_leaf.h
+++ b/fs/xfs/xfs_dir2_leaf.h
@@ -32,7 +32,7 @@ struct xfs_trans;
#define XFS_DIR2_LEAF_SPACE 1
#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_LEAF_FIRSTDB(mp) \
- XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_LEAF_OFFSET)
+ xfs_dir2_byte_to_db(mp, XFS_DIR2_LEAF_OFFSET)
/*
* Offset in data space of a data entry.
@@ -82,7 +82,6 @@ typedef struct xfs_dir2_leaf {
* DB blocks here are logical directory block numbers, not filesystem blocks.
*/
-#define XFS_DIR2_MAX_LEAF_ENTS(mp) xfs_dir2_max_leaf_ents(mp)
static inline int xfs_dir2_max_leaf_ents(struct xfs_mount *mp)
{
return (int)(((mp)->m_dirblksize - (uint)sizeof(xfs_dir2_leaf_hdr_t)) /
@@ -92,7 +91,6 @@ static inline int xfs_dir2_max_leaf_ents(struct xfs_mount *mp)
/*
* Get address of the bestcount field in the single-leaf block.
*/
-#define XFS_DIR2_LEAF_TAIL_P(mp,lp) xfs_dir2_leaf_tail_p(mp, lp)
static inline xfs_dir2_leaf_tail_t *
xfs_dir2_leaf_tail_p(struct xfs_mount *mp, xfs_dir2_leaf_t *lp)
{
@@ -104,7 +102,6 @@ xfs_dir2_leaf_tail_p(struct xfs_mount *mp, xfs_dir2_leaf_t *lp)
/*
* Get address of the bests array in the single-leaf block.
*/
-#define XFS_DIR2_LEAF_BESTS_P(ltp) xfs_dir2_leaf_bests_p(ltp)
static inline __be16 *
xfs_dir2_leaf_bests_p(xfs_dir2_leaf_tail_t *ltp)
{
@@ -114,7 +111,6 @@ xfs_dir2_leaf_bests_p(xfs_dir2_leaf_tail_t *ltp)
/*
* Convert dataptr to byte in file space
*/
-#define XFS_DIR2_DATAPTR_TO_BYTE(mp,dp) xfs_dir2_dataptr_to_byte(mp, dp)
static inline xfs_dir2_off_t
xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
@@ -124,7 +120,6 @@ xfs_dir2_dataptr_to_byte(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
/*
* Convert byte in file space to dataptr. It had better be aligned.
*/
-#define XFS_DIR2_BYTE_TO_DATAPTR(mp,by) xfs_dir2_byte_to_dataptr(mp,by)
static inline xfs_dir2_dataptr_t
xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by)
{
@@ -134,7 +129,6 @@ xfs_dir2_byte_to_dataptr(struct xfs_mount *mp, xfs_dir2_off_t by)
/*
* Convert byte in space to (DB) block
*/
-#define XFS_DIR2_BYTE_TO_DB(mp,by) xfs_dir2_byte_to_db(mp, by)
static inline xfs_dir2_db_t
xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by)
{
@@ -145,17 +139,15 @@ xfs_dir2_byte_to_db(struct xfs_mount *mp, xfs_dir2_off_t by)
/*
* Convert dataptr to a block number
*/
-#define XFS_DIR2_DATAPTR_TO_DB(mp,dp) xfs_dir2_dataptr_to_db(mp, dp)
static inline xfs_dir2_db_t
xfs_dir2_dataptr_to_db(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
- return XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp));
+ return xfs_dir2_byte_to_db(mp, xfs_dir2_dataptr_to_byte(mp, dp));
}
/*
* Convert byte in space to offset in a block
*/
-#define XFS_DIR2_BYTE_TO_OFF(mp,by) xfs_dir2_byte_to_off(mp, by)
static inline xfs_dir2_data_aoff_t
xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by)
{
@@ -166,18 +158,15 @@ xfs_dir2_byte_to_off(struct xfs_mount *mp, xfs_dir2_off_t by)
/*
* Convert dataptr to a byte offset in a block
*/
-#define XFS_DIR2_DATAPTR_TO_OFF(mp,dp) xfs_dir2_dataptr_to_off(mp, dp)
static inline xfs_dir2_data_aoff_t
xfs_dir2_dataptr_to_off(struct xfs_mount *mp, xfs_dir2_dataptr_t dp)
{
- return XFS_DIR2_BYTE_TO_OFF(mp, XFS_DIR2_DATAPTR_TO_BYTE(mp, dp));
+ return xfs_dir2_byte_to_off(mp, xfs_dir2_dataptr_to_byte(mp, dp));
}
/*
* Convert block and offset to byte in space
*/
-#define XFS_DIR2_DB_OFF_TO_BYTE(mp,db,o) \
- xfs_dir2_db_off_to_byte(mp, db, o)
static inline xfs_dir2_off_t
xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
@@ -189,7 +178,6 @@ xfs_dir2_db_off_to_byte(struct xfs_mount *mp, xfs_dir2_db_t db,
/*
* Convert block (DB) to block (dablk)
*/
-#define XFS_DIR2_DB_TO_DA(mp,db) xfs_dir2_db_to_da(mp, db)
static inline xfs_dablk_t
xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db)
{
@@ -199,29 +187,25 @@ xfs_dir2_db_to_da(struct xfs_mount *mp, xfs_dir2_db_t db)
/*
* Convert byte in space to (DA) block
*/
-#define XFS_DIR2_BYTE_TO_DA(mp,by) xfs_dir2_byte_to_da(mp, by)
static inline xfs_dablk_t
xfs_dir2_byte_to_da(struct xfs_mount *mp, xfs_dir2_off_t by)
{
- return XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_BYTE_TO_DB(mp, by));
+ return xfs_dir2_db_to_da(mp, xfs_dir2_byte_to_db(mp, by));
}
/*
* Convert block and offset to dataptr
*/
-#define XFS_DIR2_DB_OFF_TO_DATAPTR(mp,db,o) \
- xfs_dir2_db_off_to_dataptr(mp, db, o)
static inline xfs_dir2_dataptr_t
xfs_dir2_db_off_to_dataptr(struct xfs_mount *mp, xfs_dir2_db_t db,
xfs_dir2_data_aoff_t o)
{
- return XFS_DIR2_BYTE_TO_DATAPTR(mp, XFS_DIR2_DB_OFF_TO_BYTE(mp, db, o));
+ return xfs_dir2_byte_to_dataptr(mp, xfs_dir2_db_off_to_byte(mp, db, o));
}
/*
* Convert block (dablk) to block (DB)
*/
-#define XFS_DIR2_DA_TO_DB(mp,da) xfs_dir2_da_to_db(mp, da)
static inline xfs_dir2_db_t
xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da)
{
@@ -231,11 +215,10 @@ xfs_dir2_da_to_db(struct xfs_mount *mp, xfs_dablk_t da)
/*
* Convert block (dablk) to byte offset in space
*/
-#define XFS_DIR2_DA_TO_BYTE(mp,da) xfs_dir2_da_to_byte(mp, da)
static inline xfs_dir2_off_t
xfs_dir2_da_to_byte(struct xfs_mount *mp, xfs_dablk_t da)
{
- return XFS_DIR2_DB_OFF_TO_BYTE(mp, XFS_DIR2_DA_TO_DB(mp, da), 0);
+ return xfs_dir2_db_off_to_byte(mp, xfs_dir2_da_to_db(mp, da), 0);
}
/*
diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
index d083c3819934..91c61d9632c8 100644
--- a/fs/xfs/xfs_dir2_node.c
+++ b/fs/xfs/xfs_dir2_node.c
@@ -136,14 +136,14 @@ xfs_dir2_leaf_to_node(
/*
* Get the buffer for the new freespace block.
*/
- if ((error = xfs_da_get_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb), -1, &fbp,
+ if ((error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb), -1, &fbp,
XFS_DATA_FORK))) {
return error;
}
ASSERT(fbp != NULL);
free = fbp->data;
leaf = lbp->data;
- ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
+ ltp = xfs_dir2_leaf_tail_p(mp, leaf);
/*
* Initialize the freespace block header.
*/
@@ -155,7 +155,7 @@ xfs_dir2_leaf_to_node(
* Copy freespace entries from the leaf block to the new block.
* Count active entries.
*/
- for (i = n = 0, from = XFS_DIR2_LEAF_BESTS_P(ltp), to = free->bests;
+ for (i = n = 0, from = xfs_dir2_leaf_bests_p(ltp), to = free->bests;
i < be32_to_cpu(ltp->bestcount); i++, from++, to++) {
if ((off = be16_to_cpu(*from)) != NULLDATAOFF)
n++;
@@ -215,7 +215,7 @@ xfs_dir2_leafn_add(
* a compact.
*/
- if (be16_to_cpu(leaf->hdr.count) == XFS_DIR2_MAX_LEAF_ENTS(mp)) {
+ if (be16_to_cpu(leaf->hdr.count) == xfs_dir2_max_leaf_ents(mp)) {
if (!leaf->hdr.stale)
return XFS_ERROR(ENOSPC);
compact = be16_to_cpu(leaf->hdr.stale) > 1;
@@ -327,7 +327,7 @@ xfs_dir2_leafn_add(
* Insert the new entry, log everything.
*/
lep->hashval = cpu_to_be32(args->hashval);
- lep->address = cpu_to_be32(XFS_DIR2_DB_OFF_TO_DATAPTR(mp,
+ lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(mp,
args->blkno, args->index));
xfs_dir2_leaf_log_header(tp, bp);
xfs_dir2_leaf_log_ents(tp, bp, lfloglow, lfloghigh);
@@ -352,7 +352,7 @@ xfs_dir2_leafn_check(
leaf = bp->data;
mp = dp->i_mount;
ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAFN_MAGIC);
- ASSERT(be16_to_cpu(leaf->hdr.count) <= XFS_DIR2_MAX_LEAF_ENTS(mp));
+ ASSERT(be16_to_cpu(leaf->hdr.count) <= xfs_dir2_max_leaf_ents(mp));
for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {
if (i + 1 < be16_to_cpu(leaf->hdr.count)) {
ASSERT(be32_to_cpu(leaf->ents[i].hashval) <=
@@ -440,7 +440,7 @@ xfs_dir2_leafn_lookup_int(
if (args->addname) {
curfdb = curbp ? state->extrablk.blkno : -1;
curdb = -1;
- length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ length = xfs_dir2_data_entsize(args->namelen);
if ((free = (curbp ? curbp->data : NULL)))
ASSERT(be32_to_cpu(free->hdr.magic) == XFS_DIR2_FREE_MAGIC);
}
@@ -465,7 +465,7 @@ xfs_dir2_leafn_lookup_int(
/*
* Pull the data block number from the entry.
*/
- newdb = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ newdb = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
/*
* For addname, we're looking for a place to put the new entry.
* We want to use a data block with an entry of equal
@@ -482,7 +482,7 @@ xfs_dir2_leafn_lookup_int(
* Convert the data block to the free block
* holding its freespace information.
*/
- newfdb = XFS_DIR2_DB_TO_FDB(mp, newdb);
+ newfdb = xfs_dir2_db_to_fdb(mp, newdb);
/*
* If it's not the one we have in hand,
* read it in.
@@ -497,7 +497,7 @@ xfs_dir2_leafn_lookup_int(
* Read the free block.
*/
if ((error = xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp,
+ xfs_dir2_db_to_da(mp,
newfdb),
-1, &curbp,
XFS_DATA_FORK))) {
@@ -517,7 +517,7 @@ xfs_dir2_leafn_lookup_int(
/*
* Get the index for our entry.
*/
- fi = XFS_DIR2_DB_TO_FDINDEX(mp, curdb);
+ fi = xfs_dir2_db_to_fdindex(mp, curdb);
/*
* If it has room, return it.
*/
@@ -561,7 +561,7 @@ xfs_dir2_leafn_lookup_int(
*/
if ((error =
xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, newdb), -1,
+ xfs_dir2_db_to_da(mp, newdb), -1,
&curbp, XFS_DATA_FORK))) {
return error;
}
@@ -573,7 +573,7 @@ xfs_dir2_leafn_lookup_int(
*/
dep = (xfs_dir2_data_entry_t *)
((char *)curbp->data +
- XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address)));
/*
* Compare the entry, return it if it matches.
*/
@@ -876,9 +876,9 @@ xfs_dir2_leafn_remove(
/*
* Extract the data block and offset from the entry.
*/
- db = XFS_DIR2_DATAPTR_TO_DB(mp, be32_to_cpu(lep->address));
+ db = xfs_dir2_dataptr_to_db(mp, be32_to_cpu(lep->address));
ASSERT(dblk->blkno == db);
- off = XFS_DIR2_DATAPTR_TO_OFF(mp, be32_to_cpu(lep->address));
+ off = xfs_dir2_dataptr_to_off(mp, be32_to_cpu(lep->address));
ASSERT(dblk->index == off);
/*
* Kill the leaf entry by marking it stale.
@@ -898,7 +898,7 @@ xfs_dir2_leafn_remove(
longest = be16_to_cpu(data->hdr.bestfree[0].length);
needlog = needscan = 0;
xfs_dir2_data_make_free(tp, dbp, off,
- XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
+ xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
/*
* Rescan the data block freespaces for bestfree.
* Log the data block header if needed.
@@ -924,8 +924,8 @@ xfs_dir2_leafn_remove(
* Convert the data block number to a free block,
* read in the free block.
*/
- fdb = XFS_DIR2_DB_TO_FDB(mp, db);
- if ((error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, fdb),
+ fdb = xfs_dir2_db_to_fdb(mp, db);
+ if ((error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, fdb),
-1, &fbp, XFS_DATA_FORK))) {
return error;
}
@@ -937,7 +937,7 @@ xfs_dir2_leafn_remove(
/*
* Calculate which entry we need to fix.
*/
- findex = XFS_DIR2_DB_TO_FDINDEX(mp, db);
+ findex = xfs_dir2_db_to_fdindex(mp, db);
longest = be16_to_cpu(data->hdr.bestfree[0].length);
/*
* If the data block is now empty we can get rid of it
@@ -1073,7 +1073,7 @@ xfs_dir2_leafn_split(
/*
* Initialize the new leaf block.
*/
- error = xfs_dir2_leaf_init(args, XFS_DIR2_DA_TO_DB(mp, blkno),
+ error = xfs_dir2_leaf_init(args, xfs_dir2_da_to_db(mp, blkno),
&newblk->bp, XFS_DIR2_LEAFN_MAGIC);
if (error) {
return error;
@@ -1385,7 +1385,7 @@ xfs_dir2_node_addname_int(
dp = args->dp;
mp = dp->i_mount;
tp = args->trans;
- length = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ length = xfs_dir2_data_entsize(args->namelen);
/*
* If we came in with a freespace block that means that lookup
* found an entry with our hash value. This is the freespace
@@ -1438,7 +1438,7 @@ xfs_dir2_node_addname_int(
if ((error = xfs_bmap_last_offset(tp, dp, &fo, XFS_DATA_FORK)))
return error;
- lastfbno = XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo);
+ lastfbno = xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo);
fbno = ifbno;
}
/*
@@ -1474,7 +1474,7 @@ xfs_dir2_node_addname_int(
* to avoid it.
*/
if ((error = xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, fbno), -2, &fbp,
+ xfs_dir2_db_to_da(mp, fbno), -2, &fbp,
XFS_DATA_FORK))) {
return error;
}
@@ -1550,9 +1550,9 @@ xfs_dir2_node_addname_int(
* Get the freespace block corresponding to the data block
* that was just allocated.
*/
- fbno = XFS_DIR2_DB_TO_FDB(mp, dbno);
+ fbno = xfs_dir2_db_to_fdb(mp, dbno);
if (unlikely(error = xfs_da_read_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, fbno), -2, &fbp,
+ xfs_dir2_db_to_da(mp, fbno), -2, &fbp,
XFS_DATA_FORK))) {
xfs_da_buf_done(dbp);
return error;
@@ -1567,14 +1567,14 @@ xfs_dir2_node_addname_int(
return error;
}
- if (unlikely(XFS_DIR2_DB_TO_FDB(mp, dbno) != fbno)) {
+ if (unlikely(xfs_dir2_db_to_fdb(mp, dbno) != fbno)) {
cmn_err(CE_ALERT,
"xfs_dir2_node_addname_int: dir ino "
"%llu needed freesp block %lld for\n"
" data block %lld, got %lld\n"
" ifbno %llu lastfbno %d\n",
(unsigned long long)dp->i_ino,
- (long long)XFS_DIR2_DB_TO_FDB(mp, dbno),
+ (long long)xfs_dir2_db_to_fdb(mp, dbno),
(long long)dbno, (long long)fbno,
(unsigned long long)ifbno, lastfbno);
if (fblk) {
@@ -1598,7 +1598,7 @@ xfs_dir2_node_addname_int(
* Get a buffer for the new block.
*/
if ((error = xfs_da_get_buf(tp, dp,
- XFS_DIR2_DB_TO_DA(mp, fbno),
+ xfs_dir2_db_to_da(mp, fbno),
-1, &fbp, XFS_DATA_FORK))) {
return error;
}
@@ -1623,7 +1623,7 @@ xfs_dir2_node_addname_int(
/*
* Set the freespace block index from the data block number.
*/
- findex = XFS_DIR2_DB_TO_FDINDEX(mp, dbno);
+ findex = xfs_dir2_db_to_fdindex(mp, dbno);
/*
* If it's after the end of the current entries in the
* freespace block, extend that table.
@@ -1669,7 +1669,7 @@ xfs_dir2_node_addname_int(
* Read the data block in.
*/
if (unlikely(
- error = xfs_da_read_buf(tp, dp, XFS_DIR2_DB_TO_DA(mp, dbno),
+ error = xfs_da_read_buf(tp, dp, xfs_dir2_db_to_da(mp, dbno),
-1, &dbp, XFS_DATA_FORK))) {
if ((fblk == NULL || fblk->bp == NULL) && fbp != NULL)
xfs_da_buf_done(fbp);
@@ -1698,7 +1698,7 @@ xfs_dir2_node_addname_int(
dep->inumber = cpu_to_be64(args->inumber);
dep->namelen = args->namelen;
memcpy(dep->name, args->name, dep->namelen);
- tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
+ tagp = xfs_dir2_data_entry_tag_p(dep);
*tagp = cpu_to_be16((char *)dep - (char *)data);
xfs_dir2_data_log_entry(tp, dbp, dep);
/*
@@ -1904,7 +1904,7 @@ xfs_dir2_node_replace(
ASSERT(be32_to_cpu(data->hdr.magic) == XFS_DIR2_DATA_MAGIC);
dep = (xfs_dir2_data_entry_t *)
((char *)data +
- XFS_DIR2_DATAPTR_TO_OFF(state->mp, be32_to_cpu(lep->address)));
+ xfs_dir2_dataptr_to_off(state->mp, be32_to_cpu(lep->address)));
ASSERT(inum != be64_to_cpu(dep->inumber));
/*
* Fill in the new inode number and log the entry.
@@ -1980,7 +1980,7 @@ xfs_dir2_node_trim_free(
* Blow the block away.
*/
if ((error =
- xfs_dir2_shrink_inode(args, XFS_DIR2_DA_TO_DB(mp, (xfs_dablk_t)fo),
+ xfs_dir2_shrink_inode(args, xfs_dir2_da_to_db(mp, (xfs_dablk_t)fo),
bp))) {
/*
* Can't fail with ENOSPC since that only happens with no
diff --git a/fs/xfs/xfs_dir2_node.h b/fs/xfs/xfs_dir2_node.h
index c7c870ee7857..dde72db3d695 100644
--- a/fs/xfs/xfs_dir2_node.h
+++ b/fs/xfs/xfs_dir2_node.h
@@ -36,7 +36,7 @@ struct xfs_trans;
#define XFS_DIR2_FREE_SPACE 2
#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE)
#define XFS_DIR2_FREE_FIRSTDB(mp) \
- XFS_DIR2_BYTE_TO_DB(mp, XFS_DIR2_FREE_OFFSET)
+ xfs_dir2_byte_to_db(mp, XFS_DIR2_FREE_OFFSET)
#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F */
@@ -60,7 +60,6 @@ typedef struct xfs_dir2_free {
/*
* Convert data space db to the corresponding free db.
*/
-#define XFS_DIR2_DB_TO_FDB(mp,db) xfs_dir2_db_to_fdb(mp, db)
static inline xfs_dir2_db_t
xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
{
@@ -70,7 +69,6 @@ xfs_dir2_db_to_fdb(struct xfs_mount *mp, xfs_dir2_db_t db)
/*
* Convert data space db to the corresponding index in a free db.
*/
-#define XFS_DIR2_DB_TO_FDINDEX(mp,db) xfs_dir2_db_to_fdindex(mp, db)
static inline int
xfs_dir2_db_to_fdindex(struct xfs_mount *mp, xfs_dir2_db_t db)
{
diff --git a/fs/xfs/xfs_dir2_sf.c b/fs/xfs/xfs_dir2_sf.c
index 0cd77b17bf92..38fc4f22b76d 100644
--- a/fs/xfs/xfs_dir2_sf.c
+++ b/fs/xfs/xfs_dir2_sf.c
@@ -89,8 +89,8 @@ xfs_dir2_block_sfsize(
mp = dp->i_mount;
count = i8count = namelen = 0;
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
- blp = XFS_DIR2_BLOCK_LEAF_P(btp);
+ btp = xfs_dir2_block_tail_p(mp, block);
+ blp = xfs_dir2_block_leaf_p(btp);
/*
* Iterate over the block's data entries by using the leaf pointers.
@@ -102,7 +102,7 @@ xfs_dir2_block_sfsize(
* Calculate the pointer to the entry at hand.
*/
dep = (xfs_dir2_data_entry_t *)
- ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
+ ((char *)block + xfs_dir2_dataptr_to_off(mp, addr));
/*
* Detect . and .., so we can special-case them.
* . is not included in sf directories.
@@ -124,7 +124,7 @@ xfs_dir2_block_sfsize(
/*
* Calculate the new size, see if we should give up yet.
*/
- size = XFS_DIR2_SF_HDR_SIZE(i8count) + /* header */
+ size = xfs_dir2_sf_hdr_size(i8count) + /* header */
count + /* namelen */
count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */
namelen + /* name */
@@ -139,7 +139,7 @@ xfs_dir2_block_sfsize(
*/
sfhp->count = count;
sfhp->i8count = i8count;
- XFS_DIR2_SF_PUT_INUMBER((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
+ xfs_dir2_sf_put_inumber((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
return size;
}
@@ -199,15 +199,15 @@ xfs_dir2_block_to_sf(
* Copy the header into the newly allocate local space.
*/
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- memcpy(sfp, sfhp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count));
+ memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count));
dp->i_d.di_size = size;
/*
* Set up to loop over the block's entries.
*/
- btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
+ btp = xfs_dir2_block_tail_p(mp, block);
ptr = (char *)block->u;
- endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
- sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ endptr = (char *)xfs_dir2_block_leaf_p(btp);
+ sfep = xfs_dir2_sf_firstentry(sfp);
/*
* Loop over the active and unused entries.
* Stop when we reach the leaf/tail portion of the block.
@@ -233,22 +233,22 @@ xfs_dir2_block_to_sf(
else if (dep->namelen == 2 &&
dep->name[0] == '.' && dep->name[1] == '.')
ASSERT(be64_to_cpu(dep->inumber) ==
- XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
+ xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent));
/*
* Normal entry, copy it into shortform.
*/
else {
sfep->namelen = dep->namelen;
- XFS_DIR2_SF_PUT_OFFSET(sfep,
+ xfs_dir2_sf_put_offset(sfep,
(xfs_dir2_data_aoff_t)
((char *)dep - (char *)block));
memcpy(sfep->name, dep->name, dep->namelen);
temp = be64_to_cpu(dep->inumber);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &temp,
- XFS_DIR2_SF_INUMBERP(sfep));
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ xfs_dir2_sf_put_inumber(sfp, &temp,
+ xfs_dir2_sf_inumberp(sfep));
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
- ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
+ ptr += xfs_dir2_data_entsize(dep->namelen);
}
ASSERT((char *)sfep - (char *)sfp == size);
xfs_dir2_sf_check(args);
@@ -294,11 +294,11 @@ xfs_dir2_sf_addname(
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Compute entry (and change in) size.
*/
- add_entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen);
+ add_entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
incr_isize = add_entsize;
objchange = 0;
#if XFS_BIG_INUMS
@@ -392,7 +392,7 @@ xfs_dir2_sf_addname_easy(
/*
* Grow the in-inode space.
*/
- xfs_idata_realloc(dp, XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen),
+ xfs_idata_realloc(dp, xfs_dir2_sf_entsize_byname(sfp, args->namelen),
XFS_DATA_FORK);
/*
* Need to set up again due to realloc of the inode data.
@@ -403,10 +403,10 @@ xfs_dir2_sf_addname_easy(
* Fill in the new entry.
*/
sfep->namelen = args->namelen;
- XFS_DIR2_SF_PUT_OFFSET(sfep, offset);
+ xfs_dir2_sf_put_offset(sfep, offset);
memcpy(sfep->name, args->name, sfep->namelen);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber,
+ xfs_dir2_sf_inumberp(sfep));
/*
* Update the header and inode.
*/
@@ -463,14 +463,14 @@ xfs_dir2_sf_addname_hard(
* If it's going to end up at the end then oldsfep will point there.
*/
for (offset = XFS_DIR2_DATA_FIRST_OFFSET,
- oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp),
- add_datasize = XFS_DIR2_DATA_ENTSIZE(args->namelen),
+ oldsfep = xfs_dir2_sf_firstentry(oldsfp),
+ add_datasize = xfs_dir2_data_entsize(args->namelen),
eof = (char *)oldsfep == &buf[old_isize];
!eof;
- offset = new_offset + XFS_DIR2_DATA_ENTSIZE(oldsfep->namelen),
- oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep),
+ offset = new_offset + xfs_dir2_data_entsize(oldsfep->namelen),
+ oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep),
eof = (char *)oldsfep == &buf[old_isize]) {
- new_offset = XFS_DIR2_SF_GET_OFFSET(oldsfep);
+ new_offset = xfs_dir2_sf_get_offset(oldsfep);
if (offset + add_datasize <= new_offset)
break;
}
@@ -495,10 +495,10 @@ xfs_dir2_sf_addname_hard(
* Fill in the new entry, and update the header counts.
*/
sfep->namelen = args->namelen;
- XFS_DIR2_SF_PUT_OFFSET(sfep, offset);
+ xfs_dir2_sf_put_offset(sfep, offset);
memcpy(sfep->name, args->name, sfep->namelen);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber,
+ xfs_dir2_sf_inumberp(sfep));
sfp->hdr.count++;
#if XFS_BIG_INUMS
if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
@@ -508,7 +508,7 @@ xfs_dir2_sf_addname_hard(
* If there's more left to copy, do that.
*/
if (!eof) {
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
memcpy(sfep, oldsfep, old_isize - nbytes);
}
kmem_free(buf, old_isize);
@@ -544,9 +544,9 @@ xfs_dir2_sf_addname_pick(
mp = dp->i_mount;
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- size = XFS_DIR2_DATA_ENTSIZE(args->namelen);
+ size = xfs_dir2_data_entsize(args->namelen);
offset = XFS_DIR2_DATA_FIRST_OFFSET;
- sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ sfep = xfs_dir2_sf_firstentry(sfp);
holefit = 0;
/*
* Loop over sf entries.
@@ -555,10 +555,10 @@ xfs_dir2_sf_addname_pick(
*/
for (i = 0; i < sfp->hdr.count; i++) {
if (!holefit)
- holefit = offset + size <= XFS_DIR2_SF_GET_OFFSET(sfep);
- offset = XFS_DIR2_SF_GET_OFFSET(sfep) +
- XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
- sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
+ holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
+ offset = xfs_dir2_sf_get_offset(sfep) +
+ xfs_dir2_data_entsize(sfep->namelen);
+ sfep = xfs_dir2_sf_nextentry(sfp, sfep);
}
/*
* Calculate data bytes used excluding the new entry, if this
@@ -617,18 +617,18 @@ xfs_dir2_sf_check(
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
offset = XFS_DIR2_DATA_FIRST_OFFSET;
- ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
- ASSERT(XFS_DIR2_SF_GET_OFFSET(sfep) >= offset);
- ino = XFS_DIR2_SF_GET_INUMBER(sfp, XFS_DIR2_SF_INUMBERP(sfep));
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
+ ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
+ ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
offset =
- XFS_DIR2_SF_GET_OFFSET(sfep) +
- XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
+ xfs_dir2_sf_get_offset(sfep) +
+ xfs_dir2_data_entsize(sfep->namelen);
}
ASSERT(i8count == sfp->hdr.i8count);
ASSERT(XFS_BIG_INUMS || i8count == 0);
@@ -671,7 +671,7 @@ xfs_dir2_sf_create(
ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
ASSERT(dp->i_df.if_bytes == 0);
i8count = pino > XFS_DIR2_MAX_SHORT_INUM;
- size = XFS_DIR2_SF_HDR_SIZE(i8count);
+ size = xfs_dir2_sf_hdr_size(i8count);
/*
* Make a buffer for the data.
*/
@@ -684,7 +684,7 @@ xfs_dir2_sf_create(
/*
* Now can put in the inode number, since i8count is set.
*/
- XFS_DIR2_SF_PUT_INUMBER(sfp, &pino, &sfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &pino, &sfp->hdr.parent);
sfp->hdr.count = 0;
dp->i_d.di_size = size;
xfs_dir2_sf_check(args);
@@ -727,12 +727,12 @@ xfs_dir2_sf_getdents(
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* If the block number in the offset is out of range, we're done.
*/
- if (XFS_DIR2_DATAPTR_TO_DB(mp, dir_offset) > mp->m_dirdatablk) {
+ if (xfs_dir2_dataptr_to_db(mp, dir_offset) > mp->m_dirdatablk) {
*eofp = 1;
return 0;
}
@@ -747,9 +747,9 @@ xfs_dir2_sf_getdents(
* Put . entry unless we're starting past it.
*/
if (dir_offset <=
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOT_OFFSET)) {
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, 0,
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, 0,
XFS_DIR2_DATA_DOTDOT_OFFSET);
p.ino = dp->i_ino;
#if XFS_BIG_INUMS
@@ -762,7 +762,7 @@ xfs_dir2_sf_getdents(
if (!p.done) {
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOT_OFFSET);
return error;
}
@@ -772,11 +772,11 @@ xfs_dir2_sf_getdents(
* Put .. entry unless we're starting past it.
*/
if (dir_offset <=
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOTDOT_OFFSET)) {
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_FIRST_OFFSET);
- p.ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ p.ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
#if XFS_BIG_INUMS
p.ino += mp->m_inoadd;
#endif
@@ -787,7 +787,7 @@ xfs_dir2_sf_getdents(
if (!p.done) {
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
XFS_DIR2_DATA_DOTDOT_OFFSET);
return error;
}
@@ -796,23 +796,23 @@ xfs_dir2_sf_getdents(
/*
* Loop while there are more entries and put'ing works.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
- off = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
- XFS_DIR2_SF_GET_OFFSET(sfep));
+ off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+ xfs_dir2_sf_get_offset(sfep));
if (dir_offset > off)
continue;
p.namelen = sfep->namelen;
- p.cook = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk,
- XFS_DIR2_SF_GET_OFFSET(sfep) +
- XFS_DIR2_DATA_ENTSIZE(p.namelen));
+ p.cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+ xfs_dir2_sf_get_offset(sfep) +
+ xfs_dir2_data_entsize(p.namelen));
- p.ino = XFS_DIR2_SF_GET_INUMBER(sfp, XFS_DIR2_SF_INUMBERP(sfep));
+ p.ino = xfs_dir2_sf_get_inumber(sfp, xfs_dir2_sf_inumberp(sfep));
#if XFS_BIG_INUMS
p.ino += mp->m_inoadd;
#endif
@@ -832,7 +832,7 @@ xfs_dir2_sf_getdents(
*eofp = 1;
uio->uio_offset =
- XFS_DIR2_DB_OFF_TO_DATAPTR(mp, mp->m_dirdatablk + 1, 0);
+ xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0);
return 0;
}
@@ -865,7 +865,7 @@ xfs_dir2_sf_lookup(
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Special case for .
*/
@@ -878,21 +878,21 @@ xfs_dir2_sf_lookup(
*/
if (args->namelen == 2 &&
args->name[0] == '.' && args->name[1] == '.') {
- args->inumber = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ args->inumber = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
return XFS_ERROR(EEXIST);
}
/*
* Loop over all the entries trying to match ours.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
memcmp(args->name, sfep->name, args->namelen) == 0) {
args->inumber =
- XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep));
return XFS_ERROR(EEXIST);
}
}
@@ -934,19 +934,19 @@ xfs_dir2_sf_removename(
ASSERT(dp->i_df.if_bytes == oldsize);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(oldsize >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
/*
* Loop over the old directory entries.
* Find the one we're deleting.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
memcmp(sfep->name, args->name, args->namelen) == 0) {
- ASSERT(XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep)) ==
+ ASSERT(xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep)) ==
args->inumber);
break;
}
@@ -961,7 +961,7 @@ xfs_dir2_sf_removename(
* Calculate sizes.
*/
byteoff = (int)((char *)sfep - (char *)sfp);
- entsize = XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, args->namelen);
+ entsize = xfs_dir2_sf_entsize_byname(sfp, args->namelen);
newsize = oldsize - entsize;
/*
* Copy the part if any after the removed entry, sliding it down.
@@ -1027,7 +1027,7 @@ xfs_dir2_sf_replace(
ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
ASSERT(dp->i_df.if_u1.if_data != NULL);
sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
- ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
+ ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));
#if XFS_BIG_INUMS
/*
* New inode number is large, and need to convert to 8-byte inodes.
@@ -1067,28 +1067,28 @@ xfs_dir2_sf_replace(
if (args->namelen == 2 &&
args->name[0] == '.' && args->name[1] == '.') {
#if XFS_BIG_INUMS || defined(DEBUG)
- ino = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent);
ASSERT(args->inumber != ino);
#endif
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber, &sfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber, &sfp->hdr.parent);
}
/*
* Normal entry, look for the name.
*/
else {
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
if (sfep->namelen == args->namelen &&
sfep->name[0] == args->name[0] &&
memcmp(args->name, sfep->name, args->namelen) == 0) {
#if XFS_BIG_INUMS || defined(DEBUG)
- ino = XFS_DIR2_SF_GET_INUMBER(sfp,
- XFS_DIR2_SF_INUMBERP(sfep));
+ ino = xfs_dir2_sf_get_inumber(sfp,
+ xfs_dir2_sf_inumberp(sfep));
ASSERT(args->inumber != ino);
#endif
- XFS_DIR2_SF_PUT_INUMBER(sfp, &args->inumber,
- XFS_DIR2_SF_INUMBERP(sfep));
+ xfs_dir2_sf_put_inumber(sfp, &args->inumber,
+ xfs_dir2_sf_inumberp(sfep));
break;
}
}
@@ -1189,22 +1189,22 @@ xfs_dir2_sf_toino4(
*/
sfp->hdr.count = oldsfp->hdr.count;
sfp->hdr.i8count = 0;
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp, &oldsfp->hdr.parent);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
/*
* Copy the entries field by field.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp),
- oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
+ oldsfep = xfs_dir2_sf_firstentry(oldsfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep),
- oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
+ oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset;
memcpy(sfep->name, oldsfep->name, sfep->namelen);
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp,
- XFS_DIR2_SF_INUMBERP(oldsfep));
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep));
+ ino = xfs_dir2_sf_get_inumber(oldsfp,
+ xfs_dir2_sf_inumberp(oldsfep));
+ xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
}
/*
* Clean up the inode.
@@ -1266,22 +1266,22 @@ xfs_dir2_sf_toino8(
*/
sfp->hdr.count = oldsfp->hdr.count;
sfp->hdr.i8count = 1;
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp, &oldsfp->hdr.parent);
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, &sfp->hdr.parent);
+ ino = xfs_dir2_sf_get_inumber(oldsfp, &oldsfp->hdr.parent);
+ xfs_dir2_sf_put_inumber(sfp, &ino, &sfp->hdr.parent);
/*
* Copy the entries field by field.
*/
- for (i = 0, sfep = XFS_DIR2_SF_FIRSTENTRY(sfp),
- oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp);
+ for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
+ oldsfep = xfs_dir2_sf_firstentry(oldsfp);
i < sfp->hdr.count;
- i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep),
- oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep)) {
+ i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
+ oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
sfep->namelen = oldsfep->namelen;
sfep->offset = oldsfep->offset;
memcpy(sfep->name, oldsfep->name, sfep->namelen);
- ino = XFS_DIR2_SF_GET_INUMBER(oldsfp,
- XFS_DIR2_SF_INUMBERP(oldsfep));
- XFS_DIR2_SF_PUT_INUMBER(sfp, &ino, XFS_DIR2_SF_INUMBERP(sfep));
+ ino = xfs_dir2_sf_get_inumber(oldsfp,
+ xfs_dir2_sf_inumberp(oldsfep));
+ xfs_dir2_sf_put_inumber(sfp, &ino, xfs_dir2_sf_inumberp(sfep));
}
/*
* Clean up the inode.
diff --git a/fs/xfs/xfs_dir2_sf.h b/fs/xfs/xfs_dir2_sf.h
index 42f015b70018..11e503209afa 100644
--- a/fs/xfs/xfs_dir2_sf.h
+++ b/fs/xfs/xfs_dir2_sf.h
@@ -90,7 +90,6 @@ typedef struct xfs_dir2_sf {
xfs_dir2_sf_entry_t list[1]; /* shortform entries */
} xfs_dir2_sf_t;
-#define XFS_DIR2_SF_HDR_SIZE(i8count) xfs_dir2_sf_hdr_size(i8count)
static inline int xfs_dir2_sf_hdr_size(int i8count)
{
return ((uint)sizeof(xfs_dir2_sf_hdr_t) - \
@@ -98,14 +97,11 @@ static inline int xfs_dir2_sf_hdr_size(int i8count)
((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)));
}
-#define XFS_DIR2_SF_INUMBERP(sfep) xfs_dir2_sf_inumberp(sfep)
static inline xfs_dir2_inou_t *xfs_dir2_sf_inumberp(xfs_dir2_sf_entry_t *sfep)
{
return (xfs_dir2_inou_t *)&(sfep)->name[(sfep)->namelen];
}
-#define XFS_DIR2_SF_GET_INUMBER(sfp, from) \
- xfs_dir2_sf_get_inumber(sfp, from)
static inline xfs_intino_t
xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from)
{
@@ -114,8 +110,6 @@ xfs_dir2_sf_get_inumber(xfs_dir2_sf_t *sfp, xfs_dir2_inou_t *from)
(xfs_intino_t)XFS_GET_DIR_INO8((from)->i8));
}
-#define XFS_DIR2_SF_PUT_INUMBER(sfp,from,to) \
- xfs_dir2_sf_put_inumber(sfp,from,to)
static inline void xfs_dir2_sf_put_inumber(xfs_dir2_sf_t *sfp, xfs_ino_t *from,
xfs_dir2_inou_t *to)
{
@@ -125,24 +119,18 @@ static inline void xfs_dir2_sf_put_inumber(xfs_dir2_sf_t *sfp, xfs_ino_t *from,
XFS_PUT_DIR_INO8(*(from), (to)->i8);
}
-#define XFS_DIR2_SF_GET_OFFSET(sfep) \
- xfs_dir2_sf_get_offset(sfep)
static inline xfs_dir2_data_aoff_t
xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep)
{
return INT_GET_UNALIGNED_16_BE(&(sfep)->offset.i);
}
-#define XFS_DIR2_SF_PUT_OFFSET(sfep,off) \
- xfs_dir2_sf_put_offset(sfep,off)
static inline void
xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off)
{
INT_SET_UNALIGNED_16_BE(&(sfep)->offset.i, off);
}
-#define XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,len) \
- xfs_dir2_sf_entsize_byname(sfp,len)
static inline int xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len)
{
return ((uint)sizeof(xfs_dir2_sf_entry_t) - 1 + (len) - \
@@ -150,8 +138,6 @@ static inline int xfs_dir2_sf_entsize_byname(xfs_dir2_sf_t *sfp, int len)
((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)));
}
-#define XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep) \
- xfs_dir2_sf_entsize_byentry(sfp,sfep)
static inline int
xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep)
{
@@ -160,19 +146,17 @@ xfs_dir2_sf_entsize_byentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep)
((uint)sizeof(xfs_dir2_ino8_t) - (uint)sizeof(xfs_dir2_ino4_t)));
}
-#define XFS_DIR2_SF_FIRSTENTRY(sfp) xfs_dir2_sf_firstentry(sfp)
static inline xfs_dir2_sf_entry_t *xfs_dir2_sf_firstentry(xfs_dir2_sf_t *sfp)
{
return ((xfs_dir2_sf_entry_t *) \
- ((char *)(sfp) + XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count)));
+ ((char *)(sfp) + xfs_dir2_sf_hdr_size(sfp->hdr.i8count)));
}
-#define XFS_DIR2_SF_NEXTENTRY(sfp,sfep) xfs_dir2_sf_nextentry(sfp,sfep)
static inline xfs_dir2_sf_entry_t *
xfs_dir2_sf_nextentry(xfs_dir2_sf_t *sfp, xfs_dir2_sf_entry_t *sfep)
{
return ((xfs_dir2_sf_entry_t *) \
- ((char *)(sfep) + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,sfep)));
+ ((char *)(sfep) + xfs_dir2_sf_entsize_byentry(sfp,sfep)));
}
/*
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
new file mode 100644
index 000000000000..ce2278611bb7
--- /dev/null
+++ b/fs/xfs/xfs_filestream.c
@@ -0,0 +1,771 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "xfs.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inum.h"
+#include "xfs_dir2.h"
+#include "xfs_dir2_sf.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_ag.h"
+#include "xfs_dmapi.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_bmap.h"
+#include "xfs_alloc.h"
+#include "xfs_utils.h"
+#include "xfs_mru_cache.h"
+#include "xfs_filestream.h"
+
+#ifdef XFS_FILESTREAMS_TRACE
+
+ktrace_t *xfs_filestreams_trace_buf;
+
+STATIC void
+xfs_filestreams_trace(
+ xfs_mount_t *mp, /* mount point */
+ int type, /* type of trace */
+ const char *func, /* source function */
+ int line, /* source line number */
+ __psunsigned_t arg0,
+ __psunsigned_t arg1,
+ __psunsigned_t arg2,
+ __psunsigned_t arg3,
+ __psunsigned_t arg4,
+ __psunsigned_t arg5)
+{
+ ktrace_enter(xfs_filestreams_trace_buf,
+ (void *)(__psint_t)(type | (line << 16)),
+ (void *)func,
+ (void *)(__psunsigned_t)current_pid(),
+ (void *)mp,
+ (void *)(__psunsigned_t)arg0,
+ (void *)(__psunsigned_t)arg1,
+ (void *)(__psunsigned_t)arg2,
+ (void *)(__psunsigned_t)arg3,
+ (void *)(__psunsigned_t)arg4,
+ (void *)(__psunsigned_t)arg5,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
+#define TRACE0(mp,t) TRACE6(mp,t,0,0,0,0,0,0)
+#define TRACE1(mp,t,a0) TRACE6(mp,t,a0,0,0,0,0,0)
+#define TRACE2(mp,t,a0,a1) TRACE6(mp,t,a0,a1,0,0,0,0)
+#define TRACE3(mp,t,a0,a1,a2) TRACE6(mp,t,a0,a1,a2,0,0,0)
+#define TRACE4(mp,t,a0,a1,a2,a3) TRACE6(mp,t,a0,a1,a2,a3,0,0)
+#define TRACE5(mp,t,a0,a1,a2,a3,a4) TRACE6(mp,t,a0,a1,a2,a3,a4,0)
+#define TRACE6(mp,t,a0,a1,a2,a3,a4,a5) \
+ xfs_filestreams_trace(mp, t, __FUNCTION__, __LINE__, \
+ (__psunsigned_t)a0, (__psunsigned_t)a1, \
+ (__psunsigned_t)a2, (__psunsigned_t)a3, \
+ (__psunsigned_t)a4, (__psunsigned_t)a5)
+
+#define TRACE_AG_SCAN(mp, ag, ag2) \
+ TRACE2(mp, XFS_FSTRM_KTRACE_AGSCAN, ag, ag2);
+#define TRACE_AG_PICK1(mp, max_ag, maxfree) \
+ TRACE2(mp, XFS_FSTRM_KTRACE_AGPICK1, max_ag, maxfree);
+#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag) \
+ TRACE6(mp, XFS_FSTRM_KTRACE_AGPICK2, ag, ag2, \
+ cnt, free, scan, flag)
+#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2) \
+ TRACE5(mp, XFS_FSTRM_KTRACE_UPDATE, ip, ag, cnt, ag2, cnt2)
+#define TRACE_FREE(mp, ip, pip, ag, cnt) \
+ TRACE4(mp, XFS_FSTRM_KTRACE_FREE, ip, pip, ag, cnt)
+#define TRACE_LOOKUP(mp, ip, pip, ag, cnt) \
+ TRACE4(mp, XFS_FSTRM_KTRACE_ITEM_LOOKUP, ip, pip, ag, cnt)
+#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt) \
+ TRACE4(mp, XFS_FSTRM_KTRACE_ASSOCIATE, ip, pip, ag, cnt)
+#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt) \
+ TRACE6(mp, XFS_FSTRM_KTRACE_MOVEAG, ip, pip, oag, ocnt, nag, ncnt)
+#define TRACE_ORPHAN(mp, ip, ag) \
+ TRACE2(mp, XFS_FSTRM_KTRACE_ORPHAN, ip, ag);
+
+
+#else
+#define TRACE_AG_SCAN(mp, ag, ag2)
+#define TRACE_AG_PICK1(mp, max_ag, maxfree)
+#define TRACE_AG_PICK2(mp, ag, ag2, cnt, free, scan, flag)
+#define TRACE_UPDATE(mp, ip, ag, cnt, ag2, cnt2)
+#define TRACE_FREE(mp, ip, pip, ag, cnt)
+#define TRACE_LOOKUP(mp, ip, pip, ag, cnt)
+#define TRACE_ASSOCIATE(mp, ip, pip, ag, cnt)
+#define TRACE_MOVEAG(mp, ip, pip, oag, ocnt, nag, ncnt)
+#define TRACE_ORPHAN(mp, ip, ag)
+#endif
+
+static kmem_zone_t *item_zone;
+
+/*
+ * Structure for associating a file or a directory with an allocation group.
+ * The parent directory pointer is only needed for files, but since there will
+ * generally be vastly more files than directories in the cache, using the same
+ * data structure simplifies the code with very little memory overhead.
+ */
+typedef struct fstrm_item
+{
+ xfs_agnumber_t ag; /* AG currently in use for the file/directory. */
+ xfs_inode_t *ip; /* inode self-pointer. */
+ xfs_inode_t *pip; /* Parent directory inode pointer. */
+} fstrm_item_t;
+
+
+/*
+ * Scan the AGs starting at startag looking for an AG that isn't in use and has
+ * at least minlen blocks free.
+ */
+static int
+_xfs_filestream_pick_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t startag,
+ xfs_agnumber_t *agp,
+ int flags,
+ xfs_extlen_t minlen)
+{
+ int err, trylock, nscan;
+ xfs_extlen_t delta, longest, need, free, minfree, maxfree = 0;
+ xfs_agnumber_t ag, max_ag = NULLAGNUMBER;
+ struct xfs_perag *pag;
+
+ /* 2% of an AG's blocks must be free for it to be chosen. */
+ minfree = mp->m_sb.sb_agblocks / 50;
+
+ ag = startag;
+ *agp = NULLAGNUMBER;
+
+ /* For the first pass, don't sleep trying to init the per-AG. */
+ trylock = XFS_ALLOC_FLAG_TRYLOCK;
+
+ for (nscan = 0; 1; nscan++) {
+
+ TRACE_AG_SCAN(mp, ag, xfs_filestream_peek_ag(mp, ag));
+
+ pag = mp->m_perag + ag;
+
+ if (!pag->pagf_init) {
+ err = xfs_alloc_pagf_init(mp, NULL, ag, trylock);
+ if (err && !trylock)
+ return err;
+ }
+
+ /* Might fail sometimes during the 1st pass with trylock set. */
+ if (!pag->pagf_init)
+ goto next_ag;
+
+ /* Keep track of the AG with the most free blocks. */
+ if (pag->pagf_freeblks > maxfree) {
+ maxfree = pag->pagf_freeblks;
+ max_ag = ag;
+ }
+
+ /*
+ * The AG reference count does two things: it enforces mutual
+ * exclusion when examining the suitability of an AG in this
+ * loop, and it guards against two filestreams being established
+ * in the same AG as each other.
+ */
+ if (xfs_filestream_get_ag(mp, ag) > 1) {
+ xfs_filestream_put_ag(mp, ag);
+ goto next_ag;
+ }
+
+ need = XFS_MIN_FREELIST_PAG(pag, mp);
+ delta = need > pag->pagf_flcount ? need - pag->pagf_flcount : 0;
+ longest = (pag->pagf_longest > delta) ?
+ (pag->pagf_longest - delta) :
+ (pag->pagf_flcount > 0 || pag->pagf_longest > 0);
+
+ if (((minlen && longest >= minlen) ||
+ (!minlen && pag->pagf_freeblks >= minfree)) &&
+ (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) ||
+ (flags & XFS_PICK_LOWSPACE))) {
+
+ /* Break out, retaining the reference on the AG. */
+ free = pag->pagf_freeblks;
+ *agp = ag;
+ break;
+ }
+
+ /* Drop the reference on this AG, it's not usable. */
+ xfs_filestream_put_ag(mp, ag);
+next_ag:
+ /* Move to the next AG, wrapping to AG 0 if necessary. */
+ if (++ag >= mp->m_sb.sb_agcount)
+ ag = 0;
+
+ /* If a full pass of the AGs hasn't been done yet, continue. */
+ if (ag != startag)
+ continue;
+
+ /* Allow sleeping in xfs_alloc_pagf_init() on the 2nd pass. */
+ if (trylock != 0) {
+ trylock = 0;
+ continue;
+ }
+
+ /* Finally, if lowspace wasn't set, set it for the 3rd pass. */
+ if (!(flags & XFS_PICK_LOWSPACE)) {
+ flags |= XFS_PICK_LOWSPACE;
+ continue;
+ }
+
+ /*
+ * Take the AG with the most free space, regardless of whether
+ * it's already in use by another filestream.
+ */
+ if (max_ag != NULLAGNUMBER) {
+ xfs_filestream_get_ag(mp, max_ag);
+ TRACE_AG_PICK1(mp, max_ag, maxfree);
+ free = maxfree;
+ *agp = max_ag;
+ break;
+ }
+
+ /* take AG 0 if none matched */
+ TRACE_AG_PICK1(mp, max_ag, maxfree);
+ *agp = 0;
+ return 0;
+ }
+
+ TRACE_AG_PICK2(mp, startag, *agp, xfs_filestream_peek_ag(mp, *agp),
+ free, nscan, flags);
+
+ return 0;
+}
+
+/*
+ * Set the allocation group number for a file or a directory, updating inode
+ * references and per-AG references as appropriate. Must be called with the
+ * m_peraglock held in read mode.
+ */
+static int
+_xfs_filestream_update_ag(
+ xfs_inode_t *ip,
+ xfs_inode_t *pip,
+ xfs_agnumber_t ag)
+{
+ int err = 0;
+ xfs_mount_t *mp;
+ xfs_mru_cache_t *cache;
+ fstrm_item_t *item;
+ xfs_agnumber_t old_ag;
+ xfs_inode_t *old_pip;
+
+ /*
+ * Either ip is a regular file and pip is a directory, or ip is a
+ * directory and pip is NULL.
+ */
+ ASSERT(ip && (((ip->i_d.di_mode & S_IFREG) && pip &&
+ (pip->i_d.di_mode & S_IFDIR)) ||
+ ((ip->i_d.di_mode & S_IFDIR) && !pip)));
+
+ mp = ip->i_mount;
+ cache = mp->m_filestream;
+
+ item = xfs_mru_cache_lookup(cache, ip->i_ino);
+ if (item) {
+ ASSERT(item->ip == ip);
+ old_ag = item->ag;
+ item->ag = ag;
+ old_pip = item->pip;
+ item->pip = pip;
+ xfs_mru_cache_done(cache);
+
+ /*
+ * If the AG has changed, drop the old ref and take a new one,
+ * effectively transferring the reference from old to new AG.
+ */
+ if (ag != old_ag) {
+ xfs_filestream_put_ag(mp, old_ag);
+ xfs_filestream_get_ag(mp, ag);
+ }
+
+ /*
+ * If ip is a file and its pip has changed, drop the old ref and
+ * take a new one.
+ */
+ if (pip && pip != old_pip) {
+ IRELE(old_pip);
+ IHOLD(pip);
+ }
+
+ TRACE_UPDATE(mp, ip, old_ag, xfs_filestream_peek_ag(mp, old_ag),
+ ag, xfs_filestream_peek_ag(mp, ag));
+ return 0;
+ }
+
+ item = kmem_zone_zalloc(item_zone, KM_MAYFAIL);
+ if (!item)
+ return ENOMEM;
+
+ item->ag = ag;
+ item->ip = ip;
+ item->pip = pip;
+
+ err = xfs_mru_cache_insert(cache, ip->i_ino, item);
+ if (err) {
+ kmem_zone_free(item_zone, item);
+ return err;
+ }
+
+ /* Take a reference on the AG. */
+ xfs_filestream_get_ag(mp, ag);
+
+ /*
+ * Take a reference on the inode itself regardless of whether it's a
+ * regular file or a directory.
+ */
+ IHOLD(ip);
+
+ /*
+ * In the case of a regular file, take a reference on the parent inode
+ * as well to ensure it remains in-core.
+ */
+ if (pip)
+ IHOLD(pip);
+
+ TRACE_UPDATE(mp, ip, ag, xfs_filestream_peek_ag(mp, ag),
+ ag, xfs_filestream_peek_ag(mp, ag));
+
+ return 0;
+}
+
+/* xfs_fstrm_free_func(): callback for freeing cached stream items. */
+void
+xfs_fstrm_free_func(
+ xfs_ino_t ino,
+ fstrm_item_t *item)
+{
+ xfs_inode_t *ip = item->ip;
+ int ref;
+
+ ASSERT(ip->i_ino == ino);
+
+ xfs_iflags_clear(ip, XFS_IFILESTREAM);
+
+ /* Drop the reference taken on the AG when the item was added. */
+ ref = xfs_filestream_put_ag(ip->i_mount, item->ag);
+
+ ASSERT(ref >= 0);
+ TRACE_FREE(ip->i_mount, ip, item->pip, item->ag,
+ xfs_filestream_peek_ag(ip->i_mount, item->ag));
+
+ /*
+ * _xfs_filestream_update_ag() always takes a reference on the inode
+ * itself, whether it's a file or a directory. Release it here.
+ * This can result in the inode being freed and so we must
+ * not hold any inode locks when freeing filesstreams objects
+ * otherwise we can deadlock here.
+ */
+ IRELE(ip);
+
+ /*
+ * In the case of a regular file, _xfs_filestream_update_ag() also
+ * takes a ref on the parent inode to keep it in-core. Release that
+ * too.
+ */
+ if (item->pip)
+ IRELE(item->pip);
+
+ /* Finally, free the memory allocated for the item. */
+ kmem_zone_free(item_zone, item);
+}
+
+/*
+ * xfs_filestream_init() is called at xfs initialisation time to set up the
+ * memory zone that will be used for filestream data structure allocation.
+ */
+int
+xfs_filestream_init(void)
+{
+ item_zone = kmem_zone_init(sizeof(fstrm_item_t), "fstrm_item");
+#ifdef XFS_FILESTREAMS_TRACE
+ xfs_filestreams_trace_buf = ktrace_alloc(XFS_FSTRM_KTRACE_SIZE, KM_SLEEP);
+#endif
+ return item_zone ? 0 : -ENOMEM;
+}
+
+/*
+ * xfs_filestream_uninit() is called at xfs termination time to destroy the
+ * memory zone that was used for filestream data structure allocation.
+ */
+void
+xfs_filestream_uninit(void)
+{
+#ifdef XFS_FILESTREAMS_TRACE
+ ktrace_free(xfs_filestreams_trace_buf);
+#endif
+ kmem_zone_destroy(item_zone);
+}
+
+/*
+ * xfs_filestream_mount() is called when a file system is mounted with the
+ * filestream option. It is responsible for allocating the data structures
+ * needed to track the new file system's file streams.
+ */
+int
+xfs_filestream_mount(
+ xfs_mount_t *mp)
+{
+ int err;
+ unsigned int lifetime, grp_count;
+
+ /*
+ * The filestream timer tunable is currently fixed within the range of
+ * one second to four minutes, with five seconds being the default. The
+ * group count is somewhat arbitrary, but it'd be nice to adhere to the
+ * timer tunable to within about 10 percent. This requires at least 10
+ * groups.
+ */
+ lifetime = xfs_fstrm_centisecs * 10;
+ grp_count = 10;
+
+ err = xfs_mru_cache_create(&mp->m_filestream, lifetime, grp_count,
+ (xfs_mru_cache_free_func_t)xfs_fstrm_free_func);
+
+ return err;
+}
+
+/*
+ * xfs_filestream_unmount() is called when a file system that was mounted with
+ * the filestream option is unmounted. It drains the data structures created
+ * to track the file system's file streams and frees all the memory that was
+ * allocated.
+ */
+void
+xfs_filestream_unmount(
+ xfs_mount_t *mp)
+{
+ xfs_mru_cache_destroy(mp->m_filestream);
+}
+
+/*
+ * If the mount point's m_perag array is going to be reallocated, all
+ * outstanding cache entries must be flushed to avoid accessing reference count
+ * addresses that have been freed. The call to xfs_filestream_flush() must be
+ * made inside the block that holds the m_peraglock in write mode to do the
+ * reallocation.
+ */
+void
+xfs_filestream_flush(
+ xfs_mount_t *mp)
+{
+ /* point in time flush, so keep the reaper running */
+ xfs_mru_cache_flush(mp->m_filestream, 1);
+}
+
+/*
+ * Return the AG of the filestream the file or directory belongs to, or
+ * NULLAGNUMBER otherwise.
+ */
+xfs_agnumber_t
+xfs_filestream_lookup_ag(
+ xfs_inode_t *ip)
+{
+ xfs_mru_cache_t *cache;
+ fstrm_item_t *item;
+ xfs_agnumber_t ag;
+ int ref;
+
+ if (!(ip->i_d.di_mode & (S_IFREG | S_IFDIR))) {
+ ASSERT(0);
+ return NULLAGNUMBER;
+ }
+
+ cache = ip->i_mount->m_filestream;
+ item = xfs_mru_cache_lookup(cache, ip->i_ino);
+ if (!item) {
+ TRACE_LOOKUP(ip->i_mount, ip, NULL, NULLAGNUMBER, 0);
+ return NULLAGNUMBER;
+ }
+
+ ASSERT(ip == item->ip);
+ ag = item->ag;
+ ref = xfs_filestream_peek_ag(ip->i_mount, ag);
+ xfs_mru_cache_done(cache);
+
+ TRACE_LOOKUP(ip->i_mount, ip, item->pip, ag, ref);
+ return ag;
+}
+
+/*
+ * xfs_filestream_associate() should only be called to associate a regular file
+ * with its parent directory. Calling it with a child directory isn't
+ * appropriate because filestreams don't apply to entire directory hierarchies.
+ * Creating a file in a child directory of an existing filestream directory
+ * starts a new filestream with its own allocation group association.
+ *
+ * Returns < 0 on error, 0 if successful association occurred, > 0 if
+ * we failed to get an association because of locking issues.
+ */
+int
+xfs_filestream_associate(
+ xfs_inode_t *pip,
+ xfs_inode_t *ip)
+{
+ xfs_mount_t *mp;
+ xfs_mru_cache_t *cache;
+ fstrm_item_t *item;
+ xfs_agnumber_t ag, rotorstep, startag;
+ int err = 0;
+
+ ASSERT(pip->i_d.di_mode & S_IFDIR);
+ ASSERT(ip->i_d.di_mode & S_IFREG);
+ if (!(pip->i_d.di_mode & S_IFDIR) || !(ip->i_d.di_mode & S_IFREG))
+ return -EINVAL;
+
+ mp = pip->i_mount;
+ cache = mp->m_filestream;
+ down_read(&mp->m_peraglock);
+
+ /*
+ * We have a problem, Houston.
+ *
+ * Taking the iolock here violates inode locking order - we already
+ * hold the ilock. Hence if we block getting this lock we may never
+ * wake. Unfortunately, that means if we can't get the lock, we're
+ * screwed in terms of getting a stream association - we can't spin
+ * waiting for the lock because someone else is waiting on the lock we
+ * hold and we cannot drop that as we are in a transaction here.
+ *
+ * Lucky for us, this inversion is rarely a problem because it's a
+ * directory inode that we are trying to lock here and that means the
+ * only place that matters is xfs_sync_inodes() and SYNC_DELWRI is
+ * used. i.e. freeze, remount-ro, quotasync or unmount.
+ *
+ * So, if we can't get the iolock without sleeping then just give up
+ */
+ if (!xfs_ilock_nowait(pip, XFS_IOLOCK_EXCL)) {
+ up_read(&mp->m_peraglock);
+ return 1;
+ }
+
+ /* If the parent directory is already in the cache, use its AG. */
+ item = xfs_mru_cache_lookup(cache, pip->i_ino);
+ if (item) {
+ ASSERT(item->ip == pip);
+ ag = item->ag;
+ xfs_mru_cache_done(cache);
+
+ TRACE_LOOKUP(mp, pip, pip, ag, xfs_filestream_peek_ag(mp, ag));
+ err = _xfs_filestream_update_ag(ip, pip, ag);
+
+ goto exit;
+ }
+
+ /*
+ * Set the starting AG using the rotor for inode32, otherwise
+ * use the directory inode's AG.
+ */
+ if (mp->m_flags & XFS_MOUNT_32BITINODES) {
+ rotorstep = xfs_rotorstep;
+ startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount;
+ mp->m_agfrotor = (mp->m_agfrotor + 1) %
+ (mp->m_sb.sb_agcount * rotorstep);
+ } else
+ startag = XFS_INO_TO_AGNO(mp, pip->i_ino);
+
+ /* Pick a new AG for the parent inode starting at startag. */
+ err = _xfs_filestream_pick_ag(mp, startag, &ag, 0, 0);
+ if (err || ag == NULLAGNUMBER)
+ goto exit_did_pick;
+
+ /* Associate the parent inode with the AG. */
+ err = _xfs_filestream_update_ag(pip, NULL, ag);
+ if (err)
+ goto exit_did_pick;
+
+ /* Associate the file inode with the AG. */
+ err = _xfs_filestream_update_ag(ip, pip, ag);
+ if (err)
+ goto exit_did_pick;
+
+ TRACE_ASSOCIATE(mp, ip, pip, ag, xfs_filestream_peek_ag(mp, ag));
+
+exit_did_pick:
+ /*
+ * If _xfs_filestream_pick_ag() returned a valid AG, remove the
+ * reference it took on it, since the file and directory will have taken
+ * their own now if they were successfully cached.
+ */
+ if (ag != NULLAGNUMBER)
+ xfs_filestream_put_ag(mp, ag);
+
+exit:
+ xfs_iunlock(pip, XFS_IOLOCK_EXCL);
+ up_read(&mp->m_peraglock);
+ return -err;
+}
+
+/*
+ * Pick a new allocation group for the current file and its file stream. This
+ * function is called by xfs_bmap_filestreams() with the mount point's per-ag
+ * lock held.
+ */
+int
+xfs_filestream_new_ag(
+ xfs_bmalloca_t *ap,
+ xfs_agnumber_t *agp)
+{
+ int flags, err;
+ xfs_inode_t *ip, *pip = NULL;
+ xfs_mount_t *mp;
+ xfs_mru_cache_t *cache;
+ xfs_extlen_t minlen;
+ fstrm_item_t *dir, *file;
+ xfs_agnumber_t ag = NULLAGNUMBER;
+
+ ip = ap->ip;
+ mp = ip->i_mount;
+ cache = mp->m_filestream;
+ minlen = ap->alen;
+ *agp = NULLAGNUMBER;
+
+ /*
+ * Look for the file in the cache, removing it if it's found. Doing
+ * this allows it to be held across the dir lookup that follows.
+ */
+ file = xfs_mru_cache_remove(cache, ip->i_ino);
+ if (file) {
+ ASSERT(ip == file->ip);
+
+ /* Save the file's parent inode and old AG number for later. */
+ pip = file->pip;
+ ag = file->ag;
+
+ /* Look for the file's directory in the cache. */
+ dir = xfs_mru_cache_lookup(cache, pip->i_ino);
+ if (dir) {
+ ASSERT(pip == dir->ip);
+
+ /*
+ * If the directory has already moved on to a new AG,
+ * use that AG as the new AG for the file. Don't
+ * forget to twiddle the AG refcounts to match the
+ * movement.
+ */
+ if (dir->ag != file->ag) {
+ xfs_filestream_put_ag(mp, file->ag);
+ xfs_filestream_get_ag(mp, dir->ag);
+ *agp = file->ag = dir->ag;
+ }
+
+ xfs_mru_cache_done(cache);
+ }
+
+ /*
+ * Put the file back in the cache. If this fails, the free
+ * function needs to be called to tidy up in the same way as if
+ * the item had simply expired from the cache.
+ */
+ err = xfs_mru_cache_insert(cache, ip->i_ino, file);
+ if (err) {
+ xfs_fstrm_free_func(ip->i_ino, file);
+ return err;
+ }
+
+ /*
+ * If the file's AG was moved to the directory's new AG, there's
+ * nothing more to be done.
+ */
+ if (*agp != NULLAGNUMBER) {
+ TRACE_MOVEAG(mp, ip, pip,
+ ag, xfs_filestream_peek_ag(mp, ag),
+ *agp, xfs_filestream_peek_ag(mp, *agp));
+ return 0;
+ }
+ }
+
+ /*
+ * If the file's parent directory is known, take its iolock in exclusive
+ * mode to prevent two sibling files from racing each other to migrate
+ * themselves and their parent to different AGs.
+ */
+ if (pip)
+ xfs_ilock(pip, XFS_IOLOCK_EXCL);
+
+ /*
+ * A new AG needs to be found for the file. If the file's parent
+ * directory is also known, it will be moved to the new AG as well to
+ * ensure that files created inside it in future use the new AG.
+ */
+ ag = (ag == NULLAGNUMBER) ? 0 : (ag + 1) % mp->m_sb.sb_agcount;
+ flags = (ap->userdata ? XFS_PICK_USERDATA : 0) |
+ (ap->low ? XFS_PICK_LOWSPACE : 0);
+
+ err = _xfs_filestream_pick_ag(mp, ag, agp, flags, minlen);
+ if (err || *agp == NULLAGNUMBER)
+ goto exit;
+
+ /*
+ * If the file wasn't found in the file cache, then its parent directory
+ * inode isn't known. For this to have happened, the file must either
+ * be pre-existing, or it was created long enough ago that its cache
+ * entry has expired. This isn't the sort of usage that the filestreams
+ * allocator is trying to optimise, so there's no point trying to track
+ * its new AG somehow in the filestream data structures.
+ */
+ if (!pip) {
+ TRACE_ORPHAN(mp, ip, *agp);
+ goto exit;
+ }
+
+ /* Associate the parent inode with the AG. */
+ err = _xfs_filestream_update_ag(pip, NULL, *agp);
+ if (err)
+ goto exit;
+
+ /* Associate the file inode with the AG. */
+ err = _xfs_filestream_update_ag(ip, pip, *agp);
+ if (err)
+ goto exit;
+
+ TRACE_MOVEAG(mp, ip, pip, NULLAGNUMBER, 0,
+ *agp, xfs_filestream_peek_ag(mp, *agp));
+
+exit:
+ /*
+ * If _xfs_filestream_pick_ag() returned a valid AG, remove the
+ * reference it took on it, since the file and directory will have taken
+ * their own now if they were successfully cached.
+ */
+ if (*agp != NULLAGNUMBER)
+ xfs_filestream_put_ag(mp, *agp);
+ else
+ *agp = 0;
+
+ if (pip)
+ xfs_iunlock(pip, XFS_IOLOCK_EXCL);
+
+ return err;
+}
+
+/*
+ * Remove an association between an inode and a filestream object.
+ * Typically this is done on last close of an unlinked file.
+ */
+void
+xfs_filestream_deassociate(
+ xfs_inode_t *ip)
+{
+ xfs_mru_cache_t *cache = ip->i_mount->m_filestream;
+
+ xfs_mru_cache_delete(cache, ip->i_ino);
+}
diff --git a/fs/xfs/xfs_filestream.h b/fs/xfs/xfs_filestream.h
new file mode 100644
index 000000000000..f655f7dc334c
--- /dev/null
+++ b/fs/xfs/xfs_filestream.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __XFS_FILESTREAM_H__
+#define __XFS_FILESTREAM_H__
+
+#ifdef __KERNEL__
+
+struct xfs_mount;
+struct xfs_inode;
+struct xfs_perag;
+struct xfs_bmalloca;
+
+#ifdef XFS_FILESTREAMS_TRACE
+#define XFS_FSTRM_KTRACE_INFO 1
+#define XFS_FSTRM_KTRACE_AGSCAN 2
+#define XFS_FSTRM_KTRACE_AGPICK1 3
+#define XFS_FSTRM_KTRACE_AGPICK2 4
+#define XFS_FSTRM_KTRACE_UPDATE 5
+#define XFS_FSTRM_KTRACE_FREE 6
+#define XFS_FSTRM_KTRACE_ITEM_LOOKUP 7
+#define XFS_FSTRM_KTRACE_ASSOCIATE 8
+#define XFS_FSTRM_KTRACE_MOVEAG 9
+#define XFS_FSTRM_KTRACE_ORPHAN 10
+
+#define XFS_FSTRM_KTRACE_SIZE 16384
+extern ktrace_t *xfs_filestreams_trace_buf;
+
+#endif
+
+/*
+ * Allocation group filestream associations are tracked with per-ag atomic
+ * counters. These counters allow _xfs_filestream_pick_ag() to tell whether a
+ * particular AG already has active filestreams associated with it. The mount
+ * point's m_peraglock is used to protect these counters from per-ag array
+ * re-allocation during a growfs operation. When xfs_growfs_data_private() is
+ * about to reallocate the array, it calls xfs_filestream_flush() with the
+ * m_peraglock held in write mode.
+ *
+ * Since xfs_mru_cache_flush() guarantees that all the free functions for all
+ * the cache elements have finished executing before it returns, it's safe for
+ * the free functions to use the atomic counters without m_peraglock protection.
+ * This allows the implementation of xfs_fstrm_free_func() to be agnostic about
+ * whether it was called with the m_peraglock held in read mode, write mode or
+ * not held at all. The race condition this addresses is the following:
+ *
+ * - The work queue scheduler fires and pulls a filestream directory cache
+ * element off the LRU end of the cache for deletion, then gets pre-empted.
+ * - A growfs operation grabs the m_peraglock in write mode, flushes all the
+ * remaining items from the cache and reallocates the mount point's per-ag
+ * array, resetting all the counters to zero.
+ * - The work queue thread resumes and calls the free function for the element
+ * it started cleaning up earlier. In the process it decrements the
+ * filestreams counter for an AG that now has no references.
+ *
+ * With a shrinkfs feature, the above scenario could panic the system.
+ *
+ * All other uses of the following macros should be protected by either the
+ * m_peraglock held in read mode, or the cache's internal locking exposed by the
+ * interval between a call to xfs_mru_cache_lookup() and a call to
+ * xfs_mru_cache_done(). In addition, the m_peraglock must be held in read mode
+ * when new elements are added to the cache.
+ *
+ * Combined, these locking rules ensure that no associations will ever exist in
+ * the cache that reference per-ag array elements that have since been
+ * reallocated.
+ */
+STATIC_INLINE int
+xfs_filestream_peek_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ return atomic_read(&mp->m_perag[agno].pagf_fstrms);
+}
+
+STATIC_INLINE int
+xfs_filestream_get_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ return atomic_inc_return(&mp->m_perag[agno].pagf_fstrms);
+}
+
+STATIC_INLINE int
+xfs_filestream_put_ag(
+ xfs_mount_t *mp,
+ xfs_agnumber_t agno)
+{
+ return atomic_dec_return(&mp->m_perag[agno].pagf_fstrms);
+}
+
+/* allocation selection flags */
+typedef enum xfs_fstrm_alloc {
+ XFS_PICK_USERDATA = 1,
+ XFS_PICK_LOWSPACE = 2,
+} xfs_fstrm_alloc_t;
+
+/* prototypes for filestream.c */
+int xfs_filestream_init(void);
+void xfs_filestream_uninit(void);
+int xfs_filestream_mount(struct xfs_mount *mp);
+void xfs_filestream_unmount(struct xfs_mount *mp);
+void xfs_filestream_flush(struct xfs_mount *mp);
+xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip);
+int xfs_filestream_associate(struct xfs_inode *dip, struct xfs_inode *ip);
+void xfs_filestream_deassociate(struct xfs_inode *ip);
+int xfs_filestream_new_ag(struct xfs_bmalloca *ap, xfs_agnumber_t *agp);
+
+
+/* filestreams for the inode? */
+STATIC_INLINE int
+xfs_inode_is_filestream(
+ struct xfs_inode *ip)
+{
+ return (ip->i_mount->m_flags & XFS_MOUNT_FILESTREAMS) ||
+ xfs_iflags_test(ip, XFS_IFILESTREAM) ||
+ (ip->i_d.di_flags & XFS_DIFLAG_FILESTREAM);
+}
+
+#endif /* __KERNEL__ */
+
+#endif /* __XFS_FILESTREAM_H__ */
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 1335449841cd..ec3c9c27e0de 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -66,6 +66,7 @@ struct fsxattr {
#define XFS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */
#define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */
#define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */
+#define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */
#define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
/*
@@ -238,6 +239,7 @@ typedef struct xfs_fsop_resblks {
#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */
#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */
#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */
+#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */
/*
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index b599e6be9ec1..432e82347ed6 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -44,6 +44,7 @@
#include "xfs_trans_space.h"
#include "xfs_rtalloc.h"
#include "xfs_rw.h"
+#include "xfs_filestream.h"
/*
* File system operations
@@ -94,6 +95,8 @@ xfs_fs_geometry(
XFS_FSOP_GEOM_FLAGS_DIRV2 : 0) |
(XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_SECTOR : 0) |
+ (xfs_sb_version_haslazysbcount(&mp->m_sb) ?
+ XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) |
(XFS_SB_VERSION_HASATTR2(&mp->m_sb) ?
XFS_FSOP_GEOM_FLAGS_ATTR2 : 0);
geo->logsectsize = XFS_SB_VERSION_HASSECTOR(&mp->m_sb) ?
@@ -140,6 +143,8 @@ xfs_growfs_data_private(
pct = in->imaxpct;
if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100)
return XFS_ERROR(EINVAL);
+ if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb)))
+ return error;
dpct = pct - mp->m_sb.sb_imax_pct;
error = xfs_read_buf(mp, mp->m_ddev_targp,
XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1),
@@ -161,6 +166,7 @@ xfs_growfs_data_private(
new = nb - mp->m_sb.sb_dblocks;
oagcount = mp->m_sb.sb_agcount;
if (nagcount > oagcount) {
+ xfs_filestream_flush(mp);
down_write(&mp->m_peraglock);
mp->m_perag = kmem_realloc(mp->m_perag,
sizeof(xfs_perag_t) * nagcount,
@@ -173,6 +179,7 @@ xfs_growfs_data_private(
up_write(&mp->m_peraglock);
}
tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
+ tp->t_flags |= XFS_TRANS_RESERVE;
if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) {
xfs_trans_cancel(tp, 0);
@@ -328,6 +335,7 @@ xfs_growfs_data_private(
be32_add(&agf->agf_length, new);
ASSERT(be32_to_cpu(agf->agf_length) ==
be32_to_cpu(agi->agi_length));
+ xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
/*
* Free the new space.
*/
@@ -494,8 +502,9 @@ xfs_reserve_blocks(
unsigned long s;
/* If inval is null, report current values and return */
-
if (inval == (__uint64_t *)NULL) {
+ if (!outval)
+ return EINVAL;
outval->resblks = mp->m_resblks;
outval->resblks_avail = mp->m_resblks_avail;
return 0;
@@ -558,8 +567,10 @@ retry:
}
}
out:
- outval->resblks = mp->m_resblks;
- outval->resblks_avail = mp->m_resblks_avail;
+ if (outval) {
+ outval->resblks = mp->m_resblks;
+ outval->resblks_avail = mp->m_resblks_avail;
+ }
XFS_SB_UNLOCK(mp, s);
if (fdblks_delta) {
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index b5feb3e77116..f943368c9b93 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -123,6 +123,7 @@ xfs_ialloc_ag_alloc(
int blks_per_cluster; /* fs blocks per inode cluster */
xfs_btree_cur_t *cur; /* inode btree cursor */
xfs_daddr_t d; /* disk addr of buffer */
+ xfs_agnumber_t agno;
int error;
xfs_buf_t *fbuf; /* new free inodes' buffer */
xfs_dinode_t *free; /* new free inode structure */
@@ -302,15 +303,15 @@ xfs_ialloc_ag_alloc(
}
be32_add(&agi->agi_count, newlen);
be32_add(&agi->agi_freecount, newlen);
+ agno = be32_to_cpu(agi->agi_seqno);
down_read(&args.mp->m_peraglock);
- args.mp->m_perag[be32_to_cpu(agi->agi_seqno)].pagi_freecount += newlen;
+ args.mp->m_perag[agno].pagi_freecount += newlen;
up_read(&args.mp->m_peraglock);
agi->agi_newino = cpu_to_be32(newino);
/*
* Insert records describing the new inode chunk into the btree.
*/
- cur = xfs_btree_init_cursor(args.mp, tp, agbp,
- be32_to_cpu(agi->agi_seqno),
+ cur = xfs_btree_init_cursor(args.mp, tp, agbp, agno,
XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
for (thisino = newino;
thisino < newino + newlen;
@@ -1387,6 +1388,7 @@ xfs_ialloc_read_agi(
pag = &mp->m_perag[agno];
if (!pag->pagi_init) {
pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
+ pag->pagi_count = be32_to_cpu(agi->agi_count);
pag->pagi_init = 1;
} else {
/*
@@ -1410,3 +1412,23 @@ xfs_ialloc_read_agi(
*bpp = bp;
return 0;
}
+
+/*
+ * Read in the agi to initialise the per-ag data in the mount structure
+ */
+int
+xfs_ialloc_pagi_init(
+ xfs_mount_t *mp, /* file system mount structure */
+ xfs_trans_t *tp, /* transaction pointer */
+ xfs_agnumber_t agno) /* allocation group number */
+{
+ xfs_buf_t *bp = NULL;
+ int error;
+
+ error = xfs_ialloc_read_agi(mp, tp, agno, &bp);
+ if (error)
+ return error;
+ if (bp)
+ xfs_trans_brelse(tp, bp);
+ return 0;
+}
diff --git a/fs/xfs/xfs_ialloc.h b/fs/xfs/xfs_ialloc.h
index 7f5debe1acb6..97f4040931ca 100644
--- a/fs/xfs/xfs_ialloc.h
+++ b/fs/xfs/xfs_ialloc.h
@@ -149,6 +149,16 @@ xfs_ialloc_read_agi(
xfs_agnumber_t agno, /* allocation group number */
struct xfs_buf **bpp); /* allocation group hdr buf */
+/*
+ * Read in the allocation group header to initialise the per-ag data
+ * in the mount structure
+ */
+int
+xfs_ialloc_pagi_init(
+ struct xfs_mount *mp, /* file system mount structure */
+ struct xfs_trans *tp, /* transaction pointer */
+ xfs_agnumber_t agno); /* allocation group number */
+
#endif /* __KERNEL__ */
#endif /* __XFS_IALLOC_H__ */
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 3ca5d43b8345..cdc4c28926d0 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -48,7 +48,9 @@
#include "xfs_dir2_trace.h"
#include "xfs_quota.h"
#include "xfs_acl.h"
+#include "xfs_filestream.h"
+#include <linux/log2.h>
kmem_zone_t *xfs_ifork_zone;
kmem_zone_t *xfs_inode_zone;
@@ -643,8 +645,7 @@ xfs_iformat_extents(
ep->l1 = INT_GET(get_unaligned((__uint64_t*)&dp->l1),
ARCH_CONVERT);
}
- xfs_bmap_trace_exlist("xfs_iformat_extents", ip, nex,
- whichfork);
+ XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
if (whichfork != XFS_DATA_FORK ||
XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
if (unlikely(xfs_check_nostate_extents(
@@ -817,6 +818,8 @@ _xfs_dic2xflags(
flags |= XFS_XFLAG_EXTSZINHERIT;
if (di_flags & XFS_DIFLAG_NODEFRAG)
flags |= XFS_XFLAG_NODEFRAG;
+ if (di_flags & XFS_DIFLAG_FILESTREAM)
+ flags |= XFS_XFLAG_FILESTREAM;
}
return flags;
@@ -1074,6 +1077,11 @@ xfs_iread_extents(
* also returns the [locked] bp pointing to the head of the freelist
* as ialloc_context. The caller should hold this buffer across
* the commit and pass it back into this routine on the second call.
+ *
+ * If we are allocating quota inodes, we do not have a parent inode
+ * to attach to or associate with (i.e. pip == NULL) because they
+ * are not linked into the directory structure - they are attached
+ * directly to the superblock - and so have no parent.
*/
int
xfs_ialloc(
@@ -1099,7 +1107,7 @@ xfs_ialloc(
* Call the space management code to pick
* the on-disk inode to be allocated.
*/
- error = xfs_dialloc(tp, pip->i_ino, mode, okalloc,
+ error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc,
ialloc_context, call_again, &ino);
if (error != 0) {
return error;
@@ -1150,10 +1158,10 @@ xfs_ialloc(
/*
* Project ids won't be stored on disk if we are using a version 1 inode.
*/
- if ( (prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1))
+ if ((prid != 0) && (ip->i_d.di_version == XFS_DINODE_VERSION_1))
xfs_bump_ino_vers2(tp, ip);
- if (XFS_INHERIT_GID(pip, vp->v_vfsp)) {
+ if (pip && XFS_INHERIT_GID(pip, vp->v_vfsp)) {
ip->i_d.di_gid = pip->i_d.di_gid;
if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) {
ip->i_d.di_mode |= S_ISGID;
@@ -1195,8 +1203,16 @@ xfs_ialloc(
flags |= XFS_ILOG_DEV;
break;
case S_IFREG:
+ if (pip && xfs_inode_is_filestream(pip)) {
+ error = xfs_filestream_associate(pip, ip);
+ if (error < 0)
+ return -error;
+ if (!error)
+ xfs_iflags_set(ip, XFS_IFILESTREAM);
+ }
+ /* fall through */
case S_IFDIR:
- if (unlikely(pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
+ if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) {
uint di_flags = 0;
if ((mode & S_IFMT) == S_IFDIR) {
@@ -1233,6 +1249,8 @@ xfs_ialloc(
if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) &&
xfs_inherit_nodefrag)
di_flags |= XFS_DIFLAG_NODEFRAG;
+ if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM)
+ di_flags |= XFS_DIFLAG_FILESTREAM;
ip->i_d.di_flags |= di_flags;
}
/* FALLTHROUGH */
@@ -2875,9 +2893,6 @@ xfs_iextents_copy(
int copied;
xfs_bmbt_rec_t *dest_ep;
xfs_bmbt_rec_t *ep;
-#ifdef XFS_BMAP_TRACE
- static char fname[] = "xfs_iextents_copy";
-#endif
int i;
xfs_ifork_t *ifp;
int nrecs;
@@ -2888,7 +2903,7 @@ xfs_iextents_copy(
ASSERT(ifp->if_bytes > 0);
nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
- xfs_bmap_trace_exlist(fname, ip, nrecs, whichfork);
+ XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork);
ASSERT(nrecs > 0);
/*
@@ -4184,7 +4199,7 @@ xfs_iext_realloc_direct(
ifp->if_bytes = new_size;
return;
}
- if ((new_size & (new_size - 1)) != 0) {
+ if (!is_power_of_2(new_size)){
rnew_size = xfs_iroundup(new_size);
}
if (rnew_size != ifp->if_real_bytes) {
@@ -4207,7 +4222,7 @@ xfs_iext_realloc_direct(
*/
else {
new_size += ifp->if_bytes;
- if ((new_size & (new_size - 1)) != 0) {
+ if (!is_power_of_2(new_size)) {
rnew_size = xfs_iroundup(new_size);
}
xfs_iext_inline_to_direct(ifp, rnew_size);
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index f75afecef8e7..012dfd4a958c 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -379,6 +379,7 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags)
#define XFS_ISTALE 0x0010 /* inode has been staled */
#define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */
#define XFS_INEW 0x0040
+#define XFS_IFILESTREAM 0x0080 /* inode is in a filestream directory */
/*
* Flags for inode locking.
@@ -414,19 +415,22 @@ xfs_iflags_test(xfs_inode_t *ip, unsigned short flags)
* gets a lockdep subclass of 1 and the second lock will have a lockdep
* subclass of 0.
*
- * XFS_I[O]LOCK_INUMORDER - for locking several inodes at the some time
+ * XFS_LOCK_INUMORDER - for locking several inodes at the some time
* with xfs_lock_inodes(). This flag is used as the starting subclass
* and each subsequent lock acquired will increment the subclass by one.
* So the first lock acquired will have a lockdep subclass of 2, the
- * second lock will have a lockdep subclass of 3, and so on.
+ * second lock will have a lockdep subclass of 3, and so on. It is
+ * the responsibility of the class builder to shift this to the correct
+ * portion of the lock_mode lockdep mask.
*/
+#define XFS_LOCK_PARENT 1
+#define XFS_LOCK_INUMORDER 2
+
#define XFS_IOLOCK_SHIFT 16
-#define XFS_IOLOCK_PARENT (1 << XFS_IOLOCK_SHIFT)
-#define XFS_IOLOCK_INUMORDER (2 << XFS_IOLOCK_SHIFT)
+#define XFS_IOLOCK_PARENT (XFS_LOCK_PARENT << XFS_IOLOCK_SHIFT)
#define XFS_ILOCK_SHIFT 24
-#define XFS_ILOCK_PARENT (1 << XFS_ILOCK_SHIFT)
-#define XFS_ILOCK_INUMORDER (2 << XFS_ILOCK_SHIFT)
+#define XFS_ILOCK_PARENT (XFS_LOCK_PARENT << XFS_ILOCK_SHIFT)
#define XFS_IOLOCK_DEP_MASK 0x00ff0000
#define XFS_ILOCK_DEP_MASK 0xff000000
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 3f2b9f2a7b94..bf57b75acb90 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -451,19 +451,14 @@ xfs_iomap_write_direct(
return XFS_ERROR(error);
rt = XFS_IS_REALTIME_INODE(ip);
- if (unlikely(rt)) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
+ extsz = xfs_get_extsz_hint(ip);
isize = ip->i_size;
if (io->io_new_size > isize)
isize = io->io_new_size;
- offset_fsb = XFS_B_TO_FSBT(mp, offset);
- last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
+ offset_fsb = XFS_B_TO_FSBT(mp, offset);
+ last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
if ((offset + count) > isize) {
error = xfs_iomap_eof_align_last_fsb(mp, io, isize, extsz,
&last_fsb);
@@ -489,13 +484,13 @@ xfs_iomap_write_direct(
if (unlikely(rt)) {
resrtextents = qblocks = resaligned;
resrtextents /= mp->m_sb.sb_rextsize;
- resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
- quota_flag = XFS_QMOPT_RES_RTBLKS;
- } else {
- resrtextents = 0;
+ resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+ quota_flag = XFS_QMOPT_RES_RTBLKS;
+ } else {
+ resrtextents = 0;
resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned);
- quota_flag = XFS_QMOPT_RES_REGBLKS;
- }
+ quota_flag = XFS_QMOPT_RES_REGBLKS;
+ }
/*
* Allocate and setup the transaction
@@ -666,13 +661,7 @@ xfs_iomap_write_delay(
if (error)
return XFS_ERROR(error);
- if (XFS_IS_REALTIME_INODE(ip)) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
-
+ extsz = xfs_get_extsz_hint(ip);
offset_fsb = XFS_B_TO_FSBT(mp, offset);
retry:
@@ -788,18 +777,12 @@ xfs_iomap_write_allocate(
nimaps = 0;
while (nimaps == 0) {
tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
+ tp->t_flags |= XFS_TRANS_RESERVE;
nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
error = xfs_trans_reserve(tp, nres,
XFS_WRITE_LOG_RES(mp),
0, XFS_TRANS_PERM_LOG_RES,
XFS_WRITE_LOG_COUNT);
- if (error == ENOSPC) {
- error = xfs_trans_reserve(tp, 0,
- XFS_WRITE_LOG_RES(mp),
- 0,
- XFS_TRANS_PERM_LOG_RES,
- XFS_WRITE_LOG_COUNT);
- }
if (error) {
xfs_trans_cancel(tp, 0);
return XFS_ERROR(error);
@@ -917,8 +900,8 @@ xfs_iomap_write_unwritten(
* from unwritten to real. Do allocations in a loop until
* we have covered the range passed in.
*/
-
tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
+ tp->t_flags |= XFS_TRANS_RESERVE;
error = xfs_trans_reserve(tp, resblks,
XFS_WRITE_LOG_RES(mp), 0,
XFS_TRANS_PERM_LOG_RES,
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index e725ddd3de5f..4c2454bcc714 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -202,6 +202,16 @@ xfs_bulkstat_one_dinode(
return 0;
}
+STATIC int
+xfs_bulkstat_one_fmt(
+ void __user *ubuffer,
+ const xfs_bstat_t *buffer)
+{
+ if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))
+ return -EFAULT;
+ return sizeof(*buffer);
+}
+
/*
* Return stat information for one inode.
* Return 0 if ok, else errno.
@@ -221,6 +231,7 @@ xfs_bulkstat_one(
xfs_bstat_t *buf; /* return buffer */
int error = 0; /* error value */
xfs_dinode_t *dip; /* dinode inode pointer */
+ bulkstat_one_fmt_pf formatter = private_data ? : xfs_bulkstat_one_fmt;
dip = (xfs_dinode_t *)dibuff;
*stat = BULKSTAT_RV_NOTHING;
@@ -243,14 +254,15 @@ xfs_bulkstat_one(
xfs_bulkstat_one_dinode(mp, ino, dip, buf);
}
- if (copy_to_user(buffer, buf, sizeof(*buf))) {
+ error = formatter(buffer, buf);
+ if (error < 0) {
error = EFAULT;
goto out_free;
}
*stat = BULKSTAT_RV_DIDONE;
if (ubused)
- *ubused = sizeof(*buf);
+ *ubused = error;
out_free:
kmem_free(buf, sizeof(*buf));
@@ -748,6 +760,19 @@ xfs_bulkstat_single(
return 0;
}
+int
+xfs_inumbers_fmt(
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_inogrp_t *buffer, /* buffer to read from */
+ long count, /* # of elements to read */
+ long *written) /* # of bytes written */
+{
+ if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer)))
+ return -EFAULT;
+ *written = count * sizeof(*buffer);
+ return 0;
+}
+
/*
* Return inode number table for the filesystem.
*/
@@ -756,7 +781,8 @@ xfs_inumbers(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t *lastino, /* last inode returned */
int *count, /* size of buffer/count returned */
- xfs_inogrp_t __user *ubuffer)/* buffer with inode descriptions */
+ void __user *ubuffer,/* buffer with inode descriptions */
+ inumbers_fmt_pf formatter)
{
xfs_buf_t *agbp;
xfs_agino_t agino;
@@ -835,12 +861,12 @@ xfs_inumbers(
bufidx++;
left--;
if (bufidx == bcount) {
- if (copy_to_user(ubuffer, buffer,
- bufidx * sizeof(*buffer))) {
+ long written;
+ if (formatter(ubuffer, buffer, bufidx, &written)) {
error = XFS_ERROR(EFAULT);
break;
}
- ubuffer += bufidx;
+ ubuffer += written;
*count += bufidx;
bufidx = 0;
}
@@ -862,8 +888,8 @@ xfs_inumbers(
}
if (!error) {
if (bufidx) {
- if (copy_to_user(ubuffer, buffer,
- bufidx * sizeof(*buffer)))
+ long written;
+ if (formatter(ubuffer, buffer, bufidx, &written))
error = XFS_ERROR(EFAULT);
else
*count += bufidx;
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index f25a28862a17..a1f18fce9b70 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -69,6 +69,10 @@ xfs_bulkstat_single(
char __user *buffer,
int *done);
+typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_bstat_t *buffer); /* buffer to read from */
+
int
xfs_bulkstat_one(
xfs_mount_t *mp,
@@ -86,11 +90,25 @@ xfs_internal_inum(
xfs_mount_t *mp,
xfs_ino_t ino);
+typedef int (*inumbers_fmt_pf)(
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_inogrp_t *buffer, /* buffer to read from */
+ long count, /* # of elements to read */
+ long *written); /* # of bytes written */
+
+int
+xfs_inumbers_fmt(
+ void __user *ubuffer, /* buffer to write to */
+ const xfs_inogrp_t *buffer, /* buffer to read from */
+ long count, /* # of elements to read */
+ long *written); /* # of bytes written */
+
int /* error status */
xfs_inumbers(
xfs_mount_t *mp, /* mount point for filesystem */
xfs_ino_t *last, /* last inode returned */
int *count, /* size of buffer/count returned */
- xfs_inogrp_t __user *buffer);/* buffer with inode info */
+ void __user *buffer, /* buffer with inode info */
+ inumbers_fmt_pf formatter);
#endif /* __XFS_ITABLE_H__ */
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index c48bf61f17bd..9d4c4fbeb3ee 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -817,10 +817,8 @@ xfs_log_need_covered(xfs_mount_t *mp)
SPLDECL(s);
int needed = 0, gen;
xlog_t *log = mp->m_log;
- bhv_vfs_t *vfsp = XFS_MTOVFS(mp);
- if (vfs_test_for_freeze(vfsp) || XFS_FORCED_SHUTDOWN(mp) ||
- (vfsp->vfs_flag & VFS_RDONLY))
+ if (!xfs_fs_writable(mp))
return 0;
s = LOG_LOCK(log);
@@ -967,14 +965,16 @@ xlog_iodone(xfs_buf_t *bp)
} else if (iclog->ic_state & XLOG_STATE_IOERROR) {
aborted = XFS_LI_ABORTED;
}
+
+ /* log I/O is always issued ASYNC */
+ ASSERT(XFS_BUF_ISASYNC(bp));
xlog_state_done_syncing(iclog, aborted);
- if (!(XFS_BUF_ISASYNC(bp))) {
- /*
- * Corresponding psema() will be done in bwrite(). If we don't
- * vsema() here, panic.
- */
- XFS_BUF_V_IODONESEMA(bp);
- }
+ /*
+ * do not reference the buffer (bp) here as we could race
+ * with it being freed after writing the unmount record to the
+ * log.
+ */
+
} /* xlog_iodone */
/*
@@ -1199,11 +1199,18 @@ xlog_alloc_log(xfs_mount_t *mp,
*iclogp = (xlog_in_core_t *)
kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP);
iclog = *iclogp;
- iclog->hic_data = (xlog_in_core_2_t *)
- kmem_zalloc(iclogsize, KM_SLEEP | KM_LARGE);
-
iclog->ic_prev = prev_iclog;
prev_iclog = iclog;
+
+ bp = xfs_buf_get_noaddr(log->l_iclog_size, mp->m_logdev_targp);
+ if (!XFS_BUF_CPSEMA(bp))
+ ASSERT(0);
+ XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
+ XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
+ XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
+ iclog->ic_bp = bp;
+ iclog->hic_data = bp->b_addr;
+
log->l_iclog_bak[i] = (xfs_caddr_t)&(iclog->ic_header);
head = &iclog->ic_header;
@@ -1216,11 +1223,6 @@ xlog_alloc_log(xfs_mount_t *mp,
INT_SET(head->h_fmt, ARCH_CONVERT, XLOG_FMT);
memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t));
- bp = xfs_buf_get_empty(log->l_iclog_size, mp->m_logdev_targp);
- XFS_BUF_SET_IODONE_FUNC(bp, xlog_iodone);
- XFS_BUF_SET_BDSTRAT_FUNC(bp, xlog_bdstrat_cb);
- XFS_BUF_SET_FSPRIVATE2(bp, (unsigned long)1);
- iclog->ic_bp = bp;
iclog->ic_size = XFS_BUF_SIZE(bp) - log->l_iclog_hsize;
iclog->ic_state = XLOG_STATE_ACTIVE;
@@ -1432,7 +1434,7 @@ xlog_sync(xlog_t *log,
} else {
iclog->ic_bwritecnt = 1;
}
- XFS_BUF_SET_PTR(bp, (xfs_caddr_t) &(iclog->ic_header), count);
+ XFS_BUF_SET_COUNT(bp, count);
XFS_BUF_SET_FSPRIVATE(bp, iclog); /* save for later */
XFS_BUF_ZEROFLAGS(bp);
XFS_BUF_BUSY(bp);
@@ -1528,7 +1530,6 @@ xlog_dealloc_log(xlog_t *log)
}
#endif
next_iclog = iclog->ic_next;
- kmem_free(iclog->hic_data, log->l_iclog_size);
kmem_free(iclog, sizeof(xlog_in_core_t));
iclog = next_iclog;
}
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 080fabf61c92..fddbb091a86f 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -927,6 +927,14 @@ xlog_find_tail(
ASSIGN_ANY_LSN_HOST(log->l_last_sync_lsn, log->l_curr_cycle,
after_umount_blk);
*tail_blk = after_umount_blk;
+
+ /*
+ * Note that the unmount was clean. If the unmount
+ * was not clean, we need to know this to rebuild the
+ * superblock counters from the perag headers if we
+ * have a filesystem using non-persistent counters.
+ */
+ log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN;
}
}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index a96bde6df96d..a66b39805176 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -202,6 +202,27 @@ xfs_mount_free(
kmem_free(mp, sizeof(xfs_mount_t));
}
+/*
+ * Check size of device based on the (data/realtime) block count.
+ * Note: this check is used by the growfs code as well as mount.
+ */
+int
+xfs_sb_validate_fsb_count(
+ xfs_sb_t *sbp,
+ __uint64_t nblocks)
+{
+ ASSERT(PAGE_SHIFT >= sbp->sb_blocklog);
+ ASSERT(sbp->sb_blocklog >= BBSHIFT);
+
+#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */
+ if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX)
+ return E2BIG;
+#else /* Limited by UINT_MAX of sectors */
+ if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX)
+ return E2BIG;
+#endif
+ return 0;
+}
/*
* Check the validity of the SB found.
@@ -284,18 +305,8 @@ xfs_mount_validate_sb(
return XFS_ERROR(EFSCORRUPTED);
}
- ASSERT(PAGE_SHIFT >= sbp->sb_blocklog);
- ASSERT(sbp->sb_blocklog >= BBSHIFT);
-
-#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */
- if (unlikely(
- (sbp->sb_dblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX ||
- (sbp->sb_rblocks >> (PAGE_SHIFT - sbp->sb_blocklog)) > ULONG_MAX)) {
-#else /* Limited by UINT_MAX of sectors */
- if (unlikely(
- (sbp->sb_dblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX ||
- (sbp->sb_rblocks << (sbp->sb_blocklog - BBSHIFT)) > UINT_MAX)) {
-#endif
+ if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
+ xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
xfs_fs_mount_cmn_err(flags,
"file system too large to be mounted on this system.");
return XFS_ERROR(E2BIG);
@@ -632,6 +643,64 @@ xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
sbp->sb_inopblock);
mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
}
+
+/*
+ * xfs_initialize_perag_data
+ *
+ * Read in each per-ag structure so we can count up the number of
+ * allocated inodes, free inodes and used filesystem blocks as this
+ * information is no longer persistent in the superblock. Once we have
+ * this information, write it into the in-core superblock structure.
+ */
+STATIC int
+xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
+{
+ xfs_agnumber_t index;
+ xfs_perag_t *pag;
+ xfs_sb_t *sbp = &mp->m_sb;
+ uint64_t ifree = 0;
+ uint64_t ialloc = 0;
+ uint64_t bfree = 0;
+ uint64_t bfreelst = 0;
+ uint64_t btree = 0;
+ int error;
+ int s;
+
+ for (index = 0; index < agcount; index++) {
+ /*
+ * read the agf, then the agi. This gets us
+ * all the inforamtion we need and populates the
+ * per-ag structures for us.
+ */
+ error = xfs_alloc_pagf_init(mp, NULL, index, 0);
+ if (error)
+ return error;
+
+ error = xfs_ialloc_pagi_init(mp, NULL, index);
+ if (error)
+ return error;
+ pag = &mp->m_perag[index];
+ ifree += pag->pagi_freecount;
+ ialloc += pag->pagi_count;
+ bfree += pag->pagf_freeblks;
+ bfreelst += pag->pagf_flcount;
+ btree += pag->pagf_btreeblks;
+ }
+ /*
+ * Overwrite incore superblock counters with just-read data
+ */
+ s = XFS_SB_LOCK(mp);
+ sbp->sb_ifree = ifree;
+ sbp->sb_icount = ialloc;
+ sbp->sb_fdblocks = bfree + bfreelst + btree;
+ XFS_SB_UNLOCK(mp, s);
+
+ /* Fixup the per-cpu counters as well. */
+ xfs_icsb_reinit_counters(mp);
+
+ return 0;
+}
+
/*
* xfs_mountfs
*
@@ -656,7 +725,7 @@ xfs_mountfs(
bhv_vnode_t *rvp = NULL;
int readio_log, writeio_log;
xfs_daddr_t d;
- __uint64_t ret64;
+ __uint64_t resblks;
__int64_t update_flags;
uint quotamount, quotaflags;
int agno;
@@ -773,6 +842,7 @@ xfs_mountfs(
*/
if ((mfsi_flags & XFS_MFSI_SECOND) == 0 &&
(mp->m_flags & XFS_MOUNT_NOUUID) == 0) {
+ __uint64_t ret64;
if (xfs_uuid_mount(mp)) {
error = XFS_ERROR(EINVAL);
goto error1;
@@ -976,6 +1046,34 @@ xfs_mountfs(
}
/*
+ * Now the log is mounted, we know if it was an unclean shutdown or
+ * not. If it was, with the first phase of recovery has completed, we
+ * have consistent AG blocks on disk. We have not recovered EFIs yet,
+ * but they are recovered transactionally in the second recovery phase
+ * later.
+ *
+ * Hence we can safely re-initialise incore superblock counters from
+ * the per-ag data. These may not be correct if the filesystem was not
+ * cleanly unmounted, so we need to wait for recovery to finish before
+ * doing this.
+ *
+ * If the filesystem was cleanly unmounted, then we can trust the
+ * values in the superblock to be correct and we don't need to do
+ * anything here.
+ *
+ * If we are currently making the filesystem, the initialisation will
+ * fail as the perag data is in an undefined state.
+ */
+
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
+ !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) &&
+ !mp->m_sb.sb_inprogress) {
+ error = xfs_initialize_perag_data(mp, sbp->sb_agcount);
+ if (error) {
+ goto error2;
+ }
+ }
+ /*
* Get and sanity-check the root inode.
* Save the pointer to it in the mount structure.
*/
@@ -1044,6 +1142,23 @@ xfs_mountfs(
if ((error = XFS_QM_MOUNT(mp, quotamount, quotaflags, mfsi_flags)))
goto error4;
+ /*
+ * Now we are mounted, reserve a small amount of unused space for
+ * privileged transactions. This is needed so that transaction
+ * space required for critical operations can dip into this pool
+ * when at ENOSPC. This is needed for operations like create with
+ * attr, unwritten extent conversion at ENOSPC, etc. Data allocations
+ * are not allowed to use this reserved space.
+ *
+ * We default to 5% or 1024 fsbs of space reserved, whichever is smaller.
+ * This may drive us straight to ENOSPC on mount, but that implies
+ * we were already there on the last unmount.
+ */
+ resblks = mp->m_sb.sb_dblocks;
+ do_div(resblks, 20);
+ resblks = min_t(__uint64_t, resblks, 1024);
+ xfs_reserve_blocks(mp, &resblks, NULL);
+
return 0;
error4:
@@ -1083,7 +1198,19 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
#if defined(DEBUG) || defined(INDUCE_IO_ERROR)
int64_t fsid;
#endif
+ __uint64_t resblks;
+ /*
+ * We can potentially deadlock here if we have an inode cluster
+ * that has been freed has it's buffer still pinned in memory because
+ * the transaction is still sitting in a iclog. The stale inodes
+ * on that buffer will have their flush locks held until the
+ * transaction hits the disk and the callbacks run. the inode
+ * flush takes the flush lock unconditionally and with nothing to
+ * push out the iclog we will never get that unlocked. hence we
+ * need to force the log first.
+ */
+ xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
xfs_iflush_all(mp);
XFS_QM_DQPURGEALL(mp, XFS_QMOPT_QUOTALL | XFS_QMOPT_UMOUNTING);
@@ -1100,10 +1227,26 @@ xfs_unmountfs(xfs_mount_t *mp, struct cred *cr)
xfs_binval(mp->m_rtdev_targp);
}
- xfs_unmountfs_writesb(mp);
+ /*
+ * Unreserve any blocks we have so that when we unmount we don't account
+ * the reserved free space as used. This is really only necessary for
+ * lazy superblock counting because it trusts the incore superblock
+ * counters to be aboslutely correct on clean unmount.
+ *
+ * We don't bother correcting this elsewhere for lazy superblock
+ * counting because on mount of an unclean filesystem we reconstruct the
+ * correct counter value and this is irrelevant.
+ *
+ * For non-lazy counter filesystems, this doesn't matter at all because
+ * we only every apply deltas to the superblock and hence the incore
+ * value does not matter....
+ */
+ resblks = 0;
+ xfs_reserve_blocks(mp, &resblks, NULL);
+ xfs_log_sbcount(mp, 1);
+ xfs_unmountfs_writesb(mp);
xfs_unmountfs_wait(mp); /* wait for async bufs */
-
xfs_log_unmount(mp); /* Done! No more fs ops. */
xfs_freesb(mp);
@@ -1150,6 +1293,62 @@ xfs_unmountfs_wait(xfs_mount_t *mp)
}
int
+xfs_fs_writable(xfs_mount_t *mp)
+{
+ bhv_vfs_t *vfsp = XFS_MTOVFS(mp);
+
+ return !(vfs_test_for_freeze(vfsp) || XFS_FORCED_SHUTDOWN(mp) ||
+ (vfsp->vfs_flag & VFS_RDONLY));
+}
+
+/*
+ * xfs_log_sbcount
+ *
+ * Called either periodically to keep the on disk superblock values
+ * roughly up to date or from unmount to make sure the values are
+ * correct on a clean unmount.
+ *
+ * Note this code can be called during the process of freezing, so
+ * we may need to use the transaction allocator which does not not
+ * block when the transaction subsystem is in its frozen state.
+ */
+int
+xfs_log_sbcount(
+ xfs_mount_t *mp,
+ uint sync)
+{
+ xfs_trans_t *tp;
+ int error;
+
+ if (!xfs_fs_writable(mp))
+ return 0;
+
+ xfs_icsb_sync_counters(mp);
+
+ /*
+ * we don't need to do this if we are updating the superblock
+ * counters on every modification.
+ */
+ if (!xfs_sb_version_haslazysbcount(&mp->m_sb))
+ return 0;
+
+ tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT);
+ error = xfs_trans_reserve(tp, 0, mp->m_sb.sb_sectsize + 128, 0, 0,
+ XFS_DEFAULT_LOG_COUNT);
+ if (error) {
+ xfs_trans_cancel(tp, 0);
+ return error;
+ }
+
+ xfs_mod_sb(tp, XFS_SB_IFREE | XFS_SB_ICOUNT | XFS_SB_FDBLOCKS);
+ if (sync)
+ xfs_trans_set_sync(tp);
+ xfs_trans_commit(tp, 0);
+
+ return 0;
+}
+
+int
xfs_unmountfs_writesb(xfs_mount_t *mp)
{
xfs_buf_t *sbp;
@@ -1160,16 +1359,15 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
* skip superblock write if fs is read-only, or
* if we are doing a forced umount.
*/
- sbp = xfs_getsb(mp, 0);
if (!(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY ||
XFS_FORCED_SHUTDOWN(mp))) {
- xfs_icsb_sync_counters(mp);
+ sbp = xfs_getsb(mp, 0);
+ sb = XFS_BUF_TO_SBP(sbp);
/*
* mark shared-readonly if desired
*/
- sb = XFS_BUF_TO_SBP(sbp);
if (mp->m_mk_sharedro) {
if (!(sb->sb_flags & XFS_SBF_READONLY))
sb->sb_flags |= XFS_SBF_READONLY;
@@ -1178,6 +1376,7 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
xfs_fs_cmn_err(CE_NOTE, mp,
"Unmounting, marking shared read-only");
}
+
XFS_BUF_UNDONE(sbp);
XFS_BUF_UNREAD(sbp);
XFS_BUF_UNDELAYWRITE(sbp);
@@ -1192,8 +1391,8 @@ xfs_unmountfs_writesb(xfs_mount_t *mp)
mp, sbp, XFS_BUF_ADDR(sbp));
if (error && mp->m_mk_sharedro)
xfs_fs_cmn_err(CE_ALERT, mp, "Superblock write error detected while unmounting. Filesystem may not be marked shared readonly");
+ xfs_buf_relse(sbp);
}
- xfs_buf_relse(sbp);
return error;
}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 82304b94646d..76ad74758696 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -66,6 +66,7 @@ struct xfs_bmbt_irec;
struct xfs_bmap_free;
struct xfs_extdelta;
struct xfs_swapext;
+struct xfs_mru_cache;
extern struct bhv_vfsops xfs_vfsops;
extern struct bhv_vnodeops xfs_vnodeops;
@@ -424,17 +425,18 @@ typedef struct xfs_mount {
struct notifier_block m_icsb_notifier; /* hotplug cpu notifier */
struct mutex m_icsb_mutex; /* balancer sync lock */
#endif
+ struct xfs_mru_cache *m_filestream; /* per-mount filestream data */
} xfs_mount_t;
/*
* Flags for m_flags.
*/
-#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops
+#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops
must be synchronous except
for space allocations */
-#define XFS_MOUNT_INO64 (1ULL << 1)
+#define XFS_MOUNT_INO64 (1ULL << 1)
/* (1ULL << 2) -- currently unused */
- /* (1ULL << 3) -- currently unused */
+#define XFS_MOUNT_WAS_CLEAN (1ULL << 3)
#define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem
operations, typically for
disk errors in metadata */
@@ -463,6 +465,8 @@ typedef struct xfs_mount {
* I/O size in stat() */
#define XFS_MOUNT_NO_PERCPU_SB (1ULL << 23) /* don't use per-cpu superblock
counters */
+#define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams
+ allocator */
/*
@@ -511,6 +515,8 @@ xfs_preferred_iosize(xfs_mount_t *mp)
#define XFS_MAXIOFFSET(mp) ((mp)->m_maxioffset)
+#define XFS_LAST_UNMOUNT_WAS_CLEAN(mp) \
+ ((mp)->m_flags & XFS_MOUNT_WAS_CLEAN)
#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN)
#define xfs_force_shutdown(m,f) \
bhv_vfs_force_shutdown((XFS_MTOVFS(m)), f, __FILE__, __LINE__)
@@ -602,6 +608,7 @@ typedef struct xfs_mod_sb {
extern xfs_mount_t *xfs_mount_init(void);
extern void xfs_mod_sb(xfs_trans_t *, __int64_t);
+extern int xfs_log_sbcount(xfs_mount_t *, uint);
extern void xfs_mount_free(xfs_mount_t *mp, int remove_bhv);
extern int xfs_mountfs(struct bhv_vfs *, xfs_mount_t *mp, int);
extern void xfs_mountfs_check_barriers(xfs_mount_t *mp);
@@ -618,12 +625,14 @@ extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *,
extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int);
extern int xfs_readsb(xfs_mount_t *, int);
extern void xfs_freesb(xfs_mount_t *);
+extern int xfs_fs_writable(xfs_mount_t *);
extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int);
extern int xfs_syncsub(xfs_mount_t *, int, int *);
extern int xfs_sync_inodes(xfs_mount_t *, int, int *);
extern xfs_agnumber_t xfs_initialize_perag(struct bhv_vfs *, xfs_mount_t *,
xfs_agnumber_t);
extern void xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t);
+extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t);
extern struct xfs_dmops xfs_dmcore_stub;
extern struct xfs_qmops xfs_qmcore_stub;
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c
new file mode 100644
index 000000000000..7deb9e3cbbd3
--- /dev/null
+++ b/fs/xfs/xfs_mru_cache.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "xfs.h"
+#include "xfs_mru_cache.h"
+
+/*
+ * The MRU Cache data structure consists of a data store, an array of lists and
+ * a lock to protect its internal state. At initialisation time, the client
+ * supplies an element lifetime in milliseconds and a group count, as well as a
+ * function pointer to call when deleting elements. A data structure for
+ * queueing up work in the form of timed callbacks is also included.
+ *
+ * The group count controls how many lists are created, and thereby how finely
+ * the elements are grouped in time. When reaping occurs, all the elements in
+ * all the lists whose time has expired are deleted.
+ *
+ * To give an example of how this works in practice, consider a client that
+ * initialises an MRU Cache with a lifetime of ten seconds and a group count of
+ * five. Five internal lists will be created, each representing a two second
+ * period in time. When the first element is added, time zero for the data
+ * structure is initialised to the current time.
+ *
+ * All the elements added in the first two seconds are appended to the first
+ * list. Elements added in the third second go into the second list, and so on.
+ * If an element is accessed at any point, it is removed from its list and
+ * inserted at the head of the current most-recently-used list.
+ *
+ * The reaper function will have nothing to do until at least twelve seconds
+ * have elapsed since the first element was added. The reason for this is that
+ * if it were called at t=11s, there could be elements in the first list that
+ * have only been inactive for nine seconds, so it still does nothing. If it is
+ * called anywhere between t=12 and t=14 seconds, it will delete all the
+ * elements that remain in the first list. It's therefore possible for elements
+ * to remain in the data store even after they've been inactive for up to
+ * (t + t/g) seconds, where t is the inactive element lifetime and g is the
+ * number of groups.
+ *
+ * The above example assumes that the reaper function gets called at least once
+ * every (t/g) seconds. If it is called less frequently, unused elements will
+ * accumulate in the reap list until the reaper function is eventually called.
+ * The current implementation uses work queue callbacks to carefully time the
+ * reaper function calls, so this should happen rarely, if at all.
+ *
+ * From a design perspective, the primary reason for the choice of a list array
+ * representing discrete time intervals is that it's only practical to reap
+ * expired elements in groups of some appreciable size. This automatically
+ * introduces a granularity to element lifetimes, so there's no point storing an
+ * individual timeout with each element that specifies a more precise reap time.
+ * The bonus is a saving of sizeof(long) bytes of memory per element stored.
+ *
+ * The elements could have been stored in just one list, but an array of
+ * counters or pointers would need to be maintained to allow them to be divided
+ * up into discrete time groups. More critically, the process of touching or
+ * removing an element would involve walking large portions of the entire list,
+ * which would have a detrimental effect on performance. The additional memory
+ * requirement for the array of list heads is minimal.
+ *
+ * When an element is touched or deleted, it needs to be removed from its
+ * current list. Doubly linked lists are used to make the list maintenance
+ * portion of these operations O(1). Since reaper timing can be imprecise,
+ * inserts and lookups can occur when there are no free lists available. When
+ * this happens, all the elements on the LRU list need to be migrated to the end
+ * of the reap list. To keep the list maintenance portion of these operations
+ * O(1) also, list tails need to be accessible without walking the entire list.
+ * This is the reason why doubly linked list heads are used.
+ */
+
+/*
+ * An MRU Cache is a dynamic data structure that stores its elements in a way
+ * that allows efficient lookups, but also groups them into discrete time
+ * intervals based on insertion time. This allows elements to be efficiently
+ * and automatically reaped after a fixed period of inactivity.
+ *
+ * When a client data pointer is stored in the MRU Cache it needs to be added to
+ * both the data store and to one of the lists. It must also be possible to
+ * access each of these entries via the other, i.e. to:
+ *
+ * a) Walk a list, removing the corresponding data store entry for each item.
+ * b) Look up a data store entry, then access its list entry directly.
+ *
+ * To achieve both of these goals, each entry must contain both a list entry and
+ * a key, in addition to the user's data pointer. Note that it's not a good
+ * idea to have the client embed one of these structures at the top of their own
+ * data structure, because inserting the same item more than once would most
+ * likely result in a loop in one of the lists. That's a sure-fire recipe for
+ * an infinite loop in the code.
+ */
+typedef struct xfs_mru_cache_elem
+{
+ struct list_head list_node;
+ unsigned long key;
+ void *value;
+} xfs_mru_cache_elem_t;
+
+static kmem_zone_t *xfs_mru_elem_zone;
+static struct workqueue_struct *xfs_mru_reap_wq;
+
+/*
+ * When inserting, destroying or reaping, it's first necessary to update the
+ * lists relative to a particular time. In the case of destroying, that time
+ * will be well in the future to ensure that all items are moved to the reap
+ * list. In all other cases though, the time will be the current time.
+ *
+ * This function enters a loop, moving the contents of the LRU list to the reap
+ * list again and again until either a) the lists are all empty, or b) time zero
+ * has been advanced sufficiently to be within the immediate element lifetime.
+ *
+ * Case a) above is detected by counting how many groups are migrated and
+ * stopping when they've all been moved. Case b) is detected by monitoring the
+ * time_zero field, which is updated as each group is migrated.
+ *
+ * The return value is the earliest time that more migration could be needed, or
+ * zero if there's no need to schedule more work because the lists are empty.
+ */
+STATIC unsigned long
+_xfs_mru_cache_migrate(
+ xfs_mru_cache_t *mru,
+ unsigned long now)
+{
+ unsigned int grp;
+ unsigned int migrated = 0;
+ struct list_head *lru_list;
+
+ /* Nothing to do if the data store is empty. */
+ if (!mru->time_zero)
+ return 0;
+
+ /* While time zero is older than the time spanned by all the lists. */
+ while (mru->time_zero <= now - mru->grp_count * mru->grp_time) {
+
+ /*
+ * If the LRU list isn't empty, migrate its elements to the tail
+ * of the reap list.
+ */
+ lru_list = mru->lists + mru->lru_grp;
+ if (!list_empty(lru_list))
+ list_splice_init(lru_list, mru->reap_list.prev);
+
+ /*
+ * Advance the LRU group number, freeing the old LRU list to
+ * become the new MRU list; advance time zero accordingly.
+ */
+ mru->lru_grp = (mru->lru_grp + 1) % mru->grp_count;
+ mru->time_zero += mru->grp_time;
+
+ /*
+ * If reaping is so far behind that all the elements on all the
+ * lists have been migrated to the reap list, it's now empty.
+ */
+ if (++migrated == mru->grp_count) {
+ mru->lru_grp = 0;
+ mru->time_zero = 0;
+ return 0;
+ }
+ }
+
+ /* Find the first non-empty list from the LRU end. */
+ for (grp = 0; grp < mru->grp_count; grp++) {
+
+ /* Check the grp'th list from the LRU end. */
+ lru_list = mru->lists + ((mru->lru_grp + grp) % mru->grp_count);
+ if (!list_empty(lru_list))
+ return mru->time_zero +
+ (mru->grp_count + grp) * mru->grp_time;
+ }
+
+ /* All the lists must be empty. */
+ mru->lru_grp = 0;
+ mru->time_zero = 0;
+ return 0;
+}
+
+/*
+ * When inserting or doing a lookup, an element needs to be inserted into the
+ * MRU list. The lists must be migrated first to ensure that they're
+ * up-to-date, otherwise the new element could be given a shorter lifetime in
+ * the cache than it should.
+ */
+STATIC void
+_xfs_mru_cache_list_insert(
+ xfs_mru_cache_t *mru,
+ xfs_mru_cache_elem_t *elem)
+{
+ unsigned int grp = 0;
+ unsigned long now = jiffies;
+
+ /*
+ * If the data store is empty, initialise time zero, leave grp set to
+ * zero and start the work queue timer if necessary. Otherwise, set grp
+ * to the number of group times that have elapsed since time zero.
+ */
+ if (!_xfs_mru_cache_migrate(mru, now)) {
+ mru->time_zero = now;
+ if (!mru->next_reap)
+ mru->next_reap = mru->grp_count * mru->grp_time;
+ } else {
+ grp = (now - mru->time_zero) / mru->grp_time;
+ grp = (mru->lru_grp + grp) % mru->grp_count;
+ }
+
+ /* Insert the element at the tail of the corresponding list. */
+ list_add_tail(&elem->list_node, mru->lists + grp);
+}
+
+/*
+ * When destroying or reaping, all the elements that were migrated to the reap
+ * list need to be deleted. For each element this involves removing it from the
+ * data store, removing it from the reap list, calling the client's free
+ * function and deleting the element from the element zone.
+ */
+STATIC void
+_xfs_mru_cache_clear_reap_list(
+ xfs_mru_cache_t *mru)
+{
+ xfs_mru_cache_elem_t *elem, *next;
+ struct list_head tmp;
+
+ INIT_LIST_HEAD(&tmp);
+ list_for_each_entry_safe(elem, next, &mru->reap_list, list_node) {
+
+ /* Remove the element from the data store. */
+ radix_tree_delete(&mru->store, elem->key);
+
+ /*
+ * remove to temp list so it can be freed without
+ * needing to hold the lock
+ */
+ list_move(&elem->list_node, &tmp);
+ }
+ mutex_spinunlock(&mru->lock, 0);
+
+ list_for_each_entry_safe(elem, next, &tmp, list_node) {
+
+ /* Remove the element from the reap list. */
+ list_del_init(&elem->list_node);
+
+ /* Call the client's free function with the key and value pointer. */
+ mru->free_func(elem->key, elem->value);
+
+ /* Free the element structure. */
+ kmem_zone_free(xfs_mru_elem_zone, elem);
+ }
+
+ mutex_spinlock(&mru->lock);
+}
+
+/*
+ * We fire the reap timer every group expiry interval so
+ * we always have a reaper ready to run. This makes shutdown
+ * and flushing of the reaper easy to do. Hence we need to
+ * keep when the next reap must occur so we can determine
+ * at each interval whether there is anything we need to do.
+ */
+STATIC void
+_xfs_mru_cache_reap(
+ struct work_struct *work)
+{
+ xfs_mru_cache_t *mru = container_of(work, xfs_mru_cache_t, work.work);
+ unsigned long now;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return;
+
+ mutex_spinlock(&mru->lock);
+ now = jiffies;
+ if (mru->reap_all ||
+ (mru->next_reap && time_after(now, mru->next_reap))) {
+ if (mru->reap_all)
+ now += mru->grp_count * mru->grp_time * 2;
+ mru->next_reap = _xfs_mru_cache_migrate(mru, now);
+ _xfs_mru_cache_clear_reap_list(mru);
+ }
+
+ /*
+ * the process that triggered the reap_all is responsible
+ * for restating the periodic reap if it is required.
+ */
+ if (!mru->reap_all)
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
+ mru->reap_all = 0;
+ mutex_spinunlock(&mru->lock, 0);
+}
+
+int
+xfs_mru_cache_init(void)
+{
+ xfs_mru_elem_zone = kmem_zone_init(sizeof(xfs_mru_cache_elem_t),
+ "xfs_mru_cache_elem");
+ if (!xfs_mru_elem_zone)
+ return ENOMEM;
+
+ xfs_mru_reap_wq = create_singlethread_workqueue("xfs_mru_cache");
+ if (!xfs_mru_reap_wq) {
+ kmem_zone_destroy(xfs_mru_elem_zone);
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+void
+xfs_mru_cache_uninit(void)
+{
+ destroy_workqueue(xfs_mru_reap_wq);
+ kmem_zone_destroy(xfs_mru_elem_zone);
+}
+
+/*
+ * To initialise a struct xfs_mru_cache pointer, call xfs_mru_cache_create()
+ * with the address of the pointer, a lifetime value in milliseconds, a group
+ * count and a free function to use when deleting elements. This function
+ * returns 0 if the initialisation was successful.
+ */
+int
+xfs_mru_cache_create(
+ xfs_mru_cache_t **mrup,
+ unsigned int lifetime_ms,
+ unsigned int grp_count,
+ xfs_mru_cache_free_func_t free_func)
+{
+ xfs_mru_cache_t *mru = NULL;
+ int err = 0, grp;
+ unsigned int grp_time;
+
+ if (mrup)
+ *mrup = NULL;
+
+ if (!mrup || !grp_count || !lifetime_ms || !free_func)
+ return EINVAL;
+
+ if (!(grp_time = msecs_to_jiffies(lifetime_ms) / grp_count))
+ return EINVAL;
+
+ if (!(mru = kmem_zalloc(sizeof(*mru), KM_SLEEP)))
+ return ENOMEM;
+
+ /* An extra list is needed to avoid reaping up to a grp_time early. */
+ mru->grp_count = grp_count + 1;
+ mru->lists = kmem_alloc(mru->grp_count * sizeof(*mru->lists), KM_SLEEP);
+
+ if (!mru->lists) {
+ err = ENOMEM;
+ goto exit;
+ }
+
+ for (grp = 0; grp < mru->grp_count; grp++)
+ INIT_LIST_HEAD(mru->lists + grp);
+
+ /*
+ * We use GFP_KERNEL radix tree preload and do inserts under a
+ * spinlock so GFP_ATOMIC is appropriate for the radix tree itself.
+ */
+ INIT_RADIX_TREE(&mru->store, GFP_ATOMIC);
+ INIT_LIST_HEAD(&mru->reap_list);
+ spinlock_init(&mru->lock, "xfs_mru_cache");
+ INIT_DELAYED_WORK(&mru->work, _xfs_mru_cache_reap);
+
+ mru->grp_time = grp_time;
+ mru->free_func = free_func;
+
+ /* start up the reaper event */
+ mru->next_reap = 0;
+ mru->reap_all = 0;
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
+
+ *mrup = mru;
+
+exit:
+ if (err && mru && mru->lists)
+ kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists));
+ if (err && mru)
+ kmem_free(mru, sizeof(*mru));
+
+ return err;
+}
+
+/*
+ * Call xfs_mru_cache_flush() to flush out all cached entries, calling their
+ * free functions as they're deleted. When this function returns, the caller is
+ * guaranteed that all the free functions for all the elements have finished
+ * executing.
+ *
+ * While we are flushing, we stop the periodic reaper event from triggering.
+ * Normally, we want to restart this periodic event, but if we are shutting
+ * down the cache we do not want it restarted. hence the restart parameter
+ * where 0 = do not restart reaper and 1 = restart reaper.
+ */
+void
+xfs_mru_cache_flush(
+ xfs_mru_cache_t *mru,
+ int restart)
+{
+ if (!mru || !mru->lists)
+ return;
+
+ cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work);
+
+ mutex_spinlock(&mru->lock);
+ mru->reap_all = 1;
+ mutex_spinunlock(&mru->lock, 0);
+
+ queue_work(xfs_mru_reap_wq, &mru->work.work);
+ flush_workqueue(xfs_mru_reap_wq);
+
+ mutex_spinlock(&mru->lock);
+ WARN_ON_ONCE(mru->reap_all != 0);
+ mru->reap_all = 0;
+ if (restart)
+ queue_delayed_work(xfs_mru_reap_wq, &mru->work, mru->grp_time);
+ mutex_spinunlock(&mru->lock, 0);
+}
+
+void
+xfs_mru_cache_destroy(
+ xfs_mru_cache_t *mru)
+{
+ if (!mru || !mru->lists)
+ return;
+
+ /* we don't want the reaper to restart here */
+ xfs_mru_cache_flush(mru, 0);
+
+ kmem_free(mru->lists, mru->grp_count * sizeof(*mru->lists));
+ kmem_free(mru, sizeof(*mru));
+}
+
+/*
+ * To insert an element, call xfs_mru_cache_insert() with the data store, the
+ * element's key and the client data pointer. This function returns 0 on
+ * success or ENOMEM if memory for the data element couldn't be allocated.
+ */
+int
+xfs_mru_cache_insert(
+ xfs_mru_cache_t *mru,
+ unsigned long key,
+ void *value)
+{
+ xfs_mru_cache_elem_t *elem;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return EINVAL;
+
+ elem = kmem_zone_zalloc(xfs_mru_elem_zone, KM_SLEEP);
+ if (!elem)
+ return ENOMEM;
+
+ if (radix_tree_preload(GFP_KERNEL)) {
+ kmem_zone_free(xfs_mru_elem_zone, elem);
+ return ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&elem->list_node);
+ elem->key = key;
+ elem->value = value;
+
+ mutex_spinlock(&mru->lock);
+
+ radix_tree_insert(&mru->store, key, elem);
+ radix_tree_preload_end();
+ _xfs_mru_cache_list_insert(mru, elem);
+
+ mutex_spinunlock(&mru->lock, 0);
+
+ return 0;
+}
+
+/*
+ * To remove an element without calling the free function, call
+ * xfs_mru_cache_remove() with the data store and the element's key. On success
+ * the client data pointer for the removed element is returned, otherwise this
+ * function will return a NULL pointer.
+ */
+void *
+xfs_mru_cache_remove(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ xfs_mru_cache_elem_t *elem;
+ void *value = NULL;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return NULL;
+
+ mutex_spinlock(&mru->lock);
+ elem = radix_tree_delete(&mru->store, key);
+ if (elem) {
+ value = elem->value;
+ list_del(&elem->list_node);
+ }
+
+ mutex_spinunlock(&mru->lock, 0);
+
+ if (elem)
+ kmem_zone_free(xfs_mru_elem_zone, elem);
+
+ return value;
+}
+
+/*
+ * To remove and element and call the free function, call xfs_mru_cache_delete()
+ * with the data store and the element's key.
+ */
+void
+xfs_mru_cache_delete(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ void *value = xfs_mru_cache_remove(mru, key);
+
+ if (value)
+ mru->free_func(key, value);
+}
+
+/*
+ * To look up an element using its key, call xfs_mru_cache_lookup() with the
+ * data store and the element's key. If found, the element will be moved to the
+ * head of the MRU list to indicate that it's been touched.
+ *
+ * The internal data structures are protected by a spinlock that is STILL HELD
+ * when this function returns. Call xfs_mru_cache_done() to release it. Note
+ * that it is not safe to call any function that might sleep in the interim.
+ *
+ * The implementation could have used reference counting to avoid this
+ * restriction, but since most clients simply want to get, set or test a member
+ * of the returned data structure, the extra per-element memory isn't warranted.
+ *
+ * If the element isn't found, this function returns NULL and the spinlock is
+ * released. xfs_mru_cache_done() should NOT be called when this occurs.
+ */
+void *
+xfs_mru_cache_lookup(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ xfs_mru_cache_elem_t *elem;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return NULL;
+
+ mutex_spinlock(&mru->lock);
+ elem = radix_tree_lookup(&mru->store, key);
+ if (elem) {
+ list_del(&elem->list_node);
+ _xfs_mru_cache_list_insert(mru, elem);
+ }
+ else
+ mutex_spinunlock(&mru->lock, 0);
+
+ return elem ? elem->value : NULL;
+}
+
+/*
+ * To look up an element using its key, but leave its location in the internal
+ * lists alone, call xfs_mru_cache_peek(). If the element isn't found, this
+ * function returns NULL.
+ *
+ * See the comments above the declaration of the xfs_mru_cache_lookup() function
+ * for important locking information pertaining to this call.
+ */
+void *
+xfs_mru_cache_peek(
+ xfs_mru_cache_t *mru,
+ unsigned long key)
+{
+ xfs_mru_cache_elem_t *elem;
+
+ ASSERT(mru && mru->lists);
+ if (!mru || !mru->lists)
+ return NULL;
+
+ mutex_spinlock(&mru->lock);
+ elem = radix_tree_lookup(&mru->store, key);
+ if (!elem)
+ mutex_spinunlock(&mru->lock, 0);
+
+ return elem ? elem->value : NULL;
+}
+
+/*
+ * To release the internal data structure spinlock after having performed an
+ * xfs_mru_cache_lookup() or an xfs_mru_cache_peek(), call xfs_mru_cache_done()
+ * with the data store pointer.
+ */
+void
+xfs_mru_cache_done(
+ xfs_mru_cache_t *mru)
+{
+ mutex_spinunlock(&mru->lock, 0);
+}
diff --git a/fs/xfs/xfs_mru_cache.h b/fs/xfs/xfs_mru_cache.h
new file mode 100644
index 000000000000..624fd10ee8e5
--- /dev/null
+++ b/fs/xfs/xfs_mru_cache.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2006-2007 Silicon Graphics, Inc.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would 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 the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __XFS_MRU_CACHE_H__
+#define __XFS_MRU_CACHE_H__
+
+
+/* Function pointer type for callback to free a client's data pointer. */
+typedef void (*xfs_mru_cache_free_func_t)(unsigned long, void*);
+
+typedef struct xfs_mru_cache
+{
+ struct radix_tree_root store; /* Core storage data structure. */
+ struct list_head *lists; /* Array of lists, one per grp. */
+ struct list_head reap_list; /* Elements overdue for reaping. */
+ spinlock_t lock; /* Lock to protect this struct. */
+ unsigned int grp_count; /* Number of discrete groups. */
+ unsigned int grp_time; /* Time period spanned by grps. */
+ unsigned int lru_grp; /* Group containing time zero. */
+ unsigned long time_zero; /* Time first element was added. */
+ unsigned long next_reap; /* Time that the reaper should
+ next do something. */
+ unsigned int reap_all; /* if set, reap all lists */
+ xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */
+ struct delayed_work work; /* Workqueue data for reaping. */
+} xfs_mru_cache_t;
+
+int xfs_mru_cache_init(void);
+void xfs_mru_cache_uninit(void);
+int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms,
+ unsigned int grp_count,
+ xfs_mru_cache_free_func_t free_func);
+void xfs_mru_cache_flush(xfs_mru_cache_t *mru, int restart);
+void xfs_mru_cache_destroy(struct xfs_mru_cache *mru);
+int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key,
+ void *value);
+void * xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key);
+void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key);
+void *xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key);
+void *xfs_mru_cache_peek(struct xfs_mru_cache *mru, unsigned long key);
+void xfs_mru_cache_done(struct xfs_mru_cache *mru);
+
+#endif /* __XFS_MRU_CACHE_H__ */
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index b3a5f07bd073..47082c01872d 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -1882,11 +1882,13 @@ xfs_growfs_rt(
(nrblocks = in->newblocks) <= sbp->sb_rblocks ||
(sbp->sb_rblocks && (in->extsize != sbp->sb_rextsize)))
return XFS_ERROR(EINVAL);
+ if ((error = xfs_sb_validate_fsb_count(sbp, nrblocks)))
+ return error;
/*
* Read in the last block of the device, make sure it exists.
*/
error = xfs_read_buf(mp, mp->m_rtdev_targp,
- XFS_FSB_TO_BB(mp, in->newblocks - 1),
+ XFS_FSB_TO_BB(mp, nrblocks - 1),
XFS_FSB_TO_BB(mp, 1), 0, &bp);
if (error)
return error;
diff --git a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
index 188b296ff50c..fcf28dbded7c 100644
--- a/fs/xfs/xfs_rw.h
+++ b/fs/xfs/xfs_rw.h
@@ -72,6 +72,34 @@ xfs_fsb_to_db_io(struct xfs_iocore *io, xfs_fsblock_t fsb)
}
/*
+ * Flags for xfs_free_eofblocks
+ */
+#define XFS_FREE_EOF_LOCK (1<<0)
+#define XFS_FREE_EOF_NOLOCK (1<<1)
+
+
+/*
+ * helper function to extract extent size hint from inode
+ */
+STATIC_INLINE xfs_extlen_t
+xfs_get_extsz_hint(
+ xfs_inode_t *ip)
+{
+ xfs_extlen_t extsz;
+
+ if (unlikely(ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) {
+ extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
+ ? ip->i_d.di_extsize
+ : ip->i_mount->m_sb.sb_rextsize;
+ ASSERT(extsz);
+ } else {
+ extsz = (ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE)
+ ? ip->i_d.di_extsize : 0;
+ }
+ return extsz;
+}
+
+/*
* Prototypes for functions in xfs_rw.c.
*/
extern int xfs_write_clear_setuid(struct xfs_inode *ip);
@@ -91,10 +119,12 @@ extern void xfs_ioerror_alert(char *func, struct xfs_mount *mp,
extern int xfs_rwlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
extern void xfs_rwunlock(bhv_desc_t *bdp, bhv_vrwlock_t write_lock);
extern int xfs_setattr(bhv_desc_t *, bhv_vattr_t *vap, int flags,
- cred_t *credp);
+ cred_t *credp);
extern int xfs_change_file_space(bhv_desc_t *bdp, int cmd, xfs_flock64_t *bf,
- xfs_off_t offset, cred_t *credp, int flags);
+ xfs_off_t offset, cred_t *credp, int flags);
extern int xfs_set_dmattrs(bhv_desc_t *bdp, u_int evmask, u_int16_t state,
- cred_t *credp);
+ cred_t *credp);
+extern int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip,
+ int flags);
#endif /* __XFS_RW_H__ */
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index 467854b45c8f..ef42537a607a 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -74,12 +74,13 @@ struct xfs_mount;
*/
#define XFS_SB_VERSION2_REALFBITS 0x00ffffff /* Mask: features */
#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001
-#define XFS_SB_VERSION2_RESERVED2BIT 0x00000002
+#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */
#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
#define XFS_SB_VERSION2_OKREALFBITS \
- (XFS_SB_VERSION2_ATTR2BIT)
+ (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
+ XFS_SB_VERSION2_ATTR2BIT)
#define XFS_SB_VERSION2_OKSASHFBITS \
(0)
#define XFS_SB_VERSION2_OKREALBITS \
@@ -181,6 +182,9 @@ typedef enum {
#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_ICOUNT XFS_SB_MVAL(ICOUNT)
+#define XFS_SB_IFREE XFS_SB_MVAL(IFREE)
+#define XFS_SB_FDBLOCKS XFS_SB_MVAL(FDBLOCKS)
#define XFS_SB_FEATURES2 XFS_SB_MVAL(FEATURES2)
#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
@@ -188,7 +192,7 @@ typedef enum {
(XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH | \
- XFS_SB_FEATURES2)
+ XFS_SB_ICOUNT | XFS_SB_IFREE | XFS_SB_FDBLOCKS | XFS_SB_FEATURES2)
/*
@@ -414,6 +418,12 @@ static inline int xfs_sb_version_hasmorebits(xfs_sb_t *sbp)
* ((sbp)->sb_features2 & XFS_SB_VERSION2_FUNBIT)
*/
+static inline int xfs_sb_version_haslazysbcount(xfs_sb_t *sbp)
+{
+ return (XFS_SB_VERSION_HASMOREBITS(sbp) && \
+ ((sbp)->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT));
+}
+
#define XFS_SB_VERSION_HASATTR2(sbp) xfs_sb_version_hasattr2(sbp)
static inline int xfs_sb_version_hasattr2(xfs_sb_t *sbp)
{
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index cc2d60951e21..356d6627f581 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -427,6 +427,14 @@ undo_blocks:
*
* Mark the transaction structure to indicate that the superblock
* needs to be updated before committing.
+ *
+ * Because we may not be keeping track of allocated/free inodes and
+ * used filesystem blocks in the superblock, we do not mark the
+ * superblock dirty in this transaction if we modify these fields.
+ * We still need to update the transaction deltas so that they get
+ * applied to the incore superblock, but we don't want them to
+ * cause the superblock to get locked and logged if these are the
+ * only fields in the superblock that the transaction modifies.
*/
void
xfs_trans_mod_sb(
@@ -434,13 +442,19 @@ xfs_trans_mod_sb(
uint field,
int64_t delta)
{
+ uint32_t flags = (XFS_TRANS_DIRTY|XFS_TRANS_SB_DIRTY);
+ xfs_mount_t *mp = tp->t_mountp;
switch (field) {
case XFS_TRANS_SB_ICOUNT:
tp->t_icount_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_IFREE:
tp->t_ifree_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_FDBLOCKS:
/*
@@ -453,6 +467,8 @@ xfs_trans_mod_sb(
ASSERT(tp->t_blk_res_used <= tp->t_blk_res);
}
tp->t_fdblocks_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_RES_FDBLOCKS:
/*
@@ -462,6 +478,8 @@ xfs_trans_mod_sb(
*/
ASSERT(delta < 0);
tp->t_res_fdblocks_delta += delta;
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb))
+ flags &= ~XFS_TRANS_SB_DIRTY;
break;
case XFS_TRANS_SB_FREXTENTS:
/*
@@ -515,7 +533,7 @@ xfs_trans_mod_sb(
return;
}
- tp->t_flags |= (XFS_TRANS_SB_DIRTY | XFS_TRANS_DIRTY);
+ tp->t_flags |= flags;
}
/*
@@ -544,18 +562,23 @@ xfs_trans_apply_sb_deltas(
(tp->t_ag_freeblks_delta + tp->t_ag_flist_delta +
tp->t_ag_btree_delta));
- if (tp->t_icount_delta != 0) {
- INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta);
- }
- if (tp->t_ifree_delta != 0) {
- INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta);
- }
+ /*
+ * Only update the superblock counters if we are logging them
+ */
+ if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) {
+ if (tp->t_icount_delta != 0) {
+ INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta);
+ }
+ if (tp->t_ifree_delta != 0) {
+ INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta);
+ }
- if (tp->t_fdblocks_delta != 0) {
- INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta);
- }
- if (tp->t_res_fdblocks_delta != 0) {
- INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta);
+ if (tp->t_fdblocks_delta != 0) {
+ INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta);
+ }
+ if (tp->t_res_fdblocks_delta != 0) {
+ INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta);
+ }
}
if (tp->t_frextents_delta != 0) {
@@ -615,11 +638,23 @@ xfs_trans_apply_sb_deltas(
}
/*
- * xfs_trans_unreserve_and_mod_sb() is called to release unused
- * reservations and apply superblock counter changes to the in-core
- * superblock.
+ * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations
+ * and apply superblock counter changes to the in-core superblock. The
+ * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT
+ * applied to the in-core superblock. The idea is that that has already been
+ * done.
*
* This is done efficiently with a single call to xfs_mod_incore_sb_batch().
+ * However, we have to ensure that we only modify each superblock field only
+ * once because the application of the delta values may not be atomic. That can
+ * lead to ENOSPC races occurring if we have two separate modifcations of the
+ * free space counter to put back the entire reservation and then take away
+ * what we used.
+ *
+ * If we are not logging superblock counters, then the inode allocated/free and
+ * used block counts are not updated in the on disk superblock. In this case,
+ * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we
+ * still need to update the incore superblock with the changes.
*/
STATIC void
xfs_trans_unreserve_and_mod_sb(
@@ -627,40 +662,49 @@ xfs_trans_unreserve_and_mod_sb(
{
xfs_mod_sb_t msb[14]; /* If you add cases, add entries */
xfs_mod_sb_t *msbp;
+ xfs_mount_t *mp = tp->t_mountp;
/* REFERENCED */
int error;
int rsvd;
+ int64_t blkdelta = 0;
+ int64_t rtxdelta = 0;
msbp = msb;
rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
- /*
- * Release any reserved blocks. Any that were allocated
- * will be taken back again by fdblocks_delta below.
- */
- if (tp->t_blk_res > 0) {
+ /* calculate free blocks delta */
+ if (tp->t_blk_res > 0)
+ blkdelta = tp->t_blk_res;
+
+ if ((tp->t_fdblocks_delta != 0) &&
+ (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
+ (tp->t_flags & XFS_TRANS_SB_DIRTY)))
+ blkdelta += tp->t_fdblocks_delta;
+
+ if (blkdelta != 0) {
msbp->msb_field = XFS_SBS_FDBLOCKS;
- msbp->msb_delta = tp->t_blk_res;
+ msbp->msb_delta = blkdelta;
msbp++;
}
- /*
- * Release any reserved real time extents . Any that were
- * allocated will be taken back again by frextents_delta below.
- */
- if (tp->t_rtx_res > 0) {
+ /* calculate free realtime extents delta */
+ if (tp->t_rtx_res > 0)
+ rtxdelta = tp->t_rtx_res;
+
+ if ((tp->t_frextents_delta != 0) &&
+ (tp->t_flags & XFS_TRANS_SB_DIRTY))
+ rtxdelta += tp->t_frextents_delta;
+
+ if (rtxdelta != 0) {
msbp->msb_field = XFS_SBS_FREXTENTS;
- msbp->msb_delta = tp->t_rtx_res;
+ msbp->msb_delta = rtxdelta;
msbp++;
}
- /*
- * Apply any superblock modifications to the in-core version.
- * The t_res_fdblocks_delta and t_res_frextents_delta fields are
- * explicitly NOT applied to the in-core superblock.
- * The idea is that that has already been done.
- */
- if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
+ /* apply remaining deltas */
+
+ if (xfs_sb_version_haslazysbcount(&mp->m_sb) ||
+ (tp->t_flags & XFS_TRANS_SB_DIRTY)) {
if (tp->t_icount_delta != 0) {
msbp->msb_field = XFS_SBS_ICOUNT;
msbp->msb_delta = tp->t_icount_delta;
@@ -671,16 +715,9 @@ xfs_trans_unreserve_and_mod_sb(
msbp->msb_delta = tp->t_ifree_delta;
msbp++;
}
- if (tp->t_fdblocks_delta != 0) {
- msbp->msb_field = XFS_SBS_FDBLOCKS;
- msbp->msb_delta = tp->t_fdblocks_delta;
- msbp++;
- }
- if (tp->t_frextents_delta != 0) {
- msbp->msb_field = XFS_SBS_FREXTENTS;
- msbp->msb_delta = tp->t_frextents_delta;
- msbp++;
- }
+ }
+
+ if (tp->t_flags & XFS_TRANS_SB_DIRTY) {
if (tp->t_dblocks_delta != 0) {
msbp->msb_field = XFS_SBS_DBLOCKS;
msbp->msb_delta = tp->t_dblocks_delta;
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 7dfcc450366f..0e26e729023e 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -94,7 +94,8 @@ typedef struct xfs_trans_header {
#define XFS_TRANS_GROWFSRT_ZERO 38
#define XFS_TRANS_GROWFSRT_FREE 39
#define XFS_TRANS_SWAPEXT 40
-#define XFS_TRANS_TYPE_MAX 40
+#define XFS_TRANS_SB_COUNT 41
+#define XFS_TRANS_TYPE_MAX 41
/* new transaction types need to be reflected in xfs_logprint(8) */
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index 65c561201cb8..11f5ea29a038 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -51,6 +51,8 @@
#include "xfs_acl.h"
#include "xfs_attr.h"
#include "xfs_clnt.h"
+#include "xfs_mru_cache.h"
+#include "xfs_filestream.h"
#include "xfs_fsops.h"
STATIC int xfs_sync(bhv_desc_t *, int, cred_t *);
@@ -81,6 +83,8 @@ xfs_init(void)
xfs_dabuf_zone = kmem_zone_init(sizeof(xfs_dabuf_t), "xfs_dabuf");
xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork");
xfs_acl_zone_init(xfs_acl_zone, "xfs_acl");
+ xfs_mru_cache_init();
+ xfs_filestream_init();
/*
* The size of the zone allocated buf log item is the maximum
@@ -164,6 +168,8 @@ xfs_cleanup(void)
xfs_cleanup_procfs();
xfs_sysctl_unregister();
xfs_refcache_destroy();
+ xfs_filestream_uninit();
+ xfs_mru_cache_uninit();
xfs_acl_zone_destroy(xfs_acl_zone);
#ifdef XFS_DIR2_TRACE
@@ -320,6 +326,9 @@ xfs_start_flags(
else
mp->m_flags &= ~XFS_MOUNT_BARRIER;
+ if (ap->flags2 & XFSMNT2_FILESTREAMS)
+ mp->m_flags |= XFS_MOUNT_FILESTREAMS;
+
return 0;
}
@@ -518,6 +527,9 @@ xfs_mount(
if (mp->m_flags & XFS_MOUNT_BARRIER)
xfs_mountfs_check_barriers(mp);
+ if ((error = xfs_filestream_mount(mp)))
+ goto error2;
+
error = XFS_IOINIT(vfsp, args, flags);
if (error)
goto error2;
@@ -575,6 +587,13 @@ xfs_unmount(
*/
xfs_refcache_purge_mp(mp);
+ /*
+ * Blow away any referenced inode in the filestreams cache.
+ * This can and will cause log traffic as inodes go inactive
+ * here.
+ */
+ xfs_filestream_unmount(mp);
+
XFS_bflush(mp->m_ddev_targp);
error = xfs_unmount_flush(mp, 0);
if (error)
@@ -640,7 +659,7 @@ xfs_quiesce_fs(
* we can write the unmount record.
*/
do {
- xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, NULL);
+ xfs_syncsub(mp, SYNC_INODE_QUIESCE, NULL);
pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1);
if (!pincount) {
delay(50);
@@ -651,6 +670,30 @@ xfs_quiesce_fs(
return 0;
}
+/*
+ * Second stage of a quiesce. The data is already synced, now we have to take
+ * care of the metadata. New transactions are already blocked, so we need to
+ * wait for any remaining transactions to drain out before proceding.
+ */
+STATIC void
+xfs_attr_quiesce(
+ xfs_mount_t *mp)
+{
+ /* wait for all modifications to complete */
+ while (atomic_read(&mp->m_active_trans) > 0)
+ delay(100);
+
+ /* flush inodes and push all remaining buffers out to disk */
+ xfs_quiesce_fs(mp);
+
+ ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);
+
+ /* Push the superblock and write an unmount record */
+ xfs_log_sbcount(mp, 1);
+ xfs_log_unmount_write(mp);
+ xfs_unmountfs_writesb(mp);
+}
+
STATIC int
xfs_mntupdate(
bhv_desc_t *bdp,
@@ -670,10 +713,9 @@ xfs_mntupdate(
mp->m_flags &= ~XFS_MOUNT_BARRIER;
}
} else if (!(vfsp->vfs_flag & VFS_RDONLY)) { /* rw -> ro */
- bhv_vfs_sync(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL);
- xfs_quiesce_fs(mp);
- xfs_log_unmount_write(mp);
- xfs_unmountfs_writesb(mp);
+ xfs_filestream_flush(mp);
+ bhv_vfs_sync(vfsp, SYNC_DATA_QUIESCE, NULL);
+ xfs_attr_quiesce(mp);
vfsp->vfs_flag |= VFS_RDONLY;
}
return 0;
@@ -887,6 +929,9 @@ xfs_sync(
{
xfs_mount_t *mp = XFS_BHVTOM(bdp);
+ if (flags & SYNC_IOWAIT)
+ xfs_filestream_flush(mp);
+
return xfs_syncsub(mp, flags, NULL);
}
@@ -1128,58 +1173,41 @@ xfs_sync_inodes(
* in the inode list.
*/
- if ((flags & SYNC_CLOSE) && (vp != NULL)) {
- /*
- * This is the shutdown case. We just need to
- * flush and invalidate all the pages associated
- * with the inode. Drop the inode lock since
- * we can't hold it across calls to the buffer
- * cache.
- *
- * We don't set the VREMAPPING bit in the vnode
- * here, because we don't hold the vnode lock
- * exclusively. It doesn't really matter, though,
- * because we only come here when we're shutting
- * down anyway.
- */
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
- if (XFS_FORCED_SHUTDOWN(mp)) {
- bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
- } else {
- error = bhv_vop_flushinval_pages(vp, 0, -1, FI_REMAPF);
+ /*
+ * If we have to flush data or wait for I/O completion
+ * we need to drop the ilock that we currently hold.
+ * If we need to drop the lock, insert a marker if we
+ * have not already done so.
+ */
+ if ((flags & (SYNC_CLOSE|SYNC_IOWAIT)) ||
+ ((flags & SYNC_DELWRI) && VN_DIRTY(vp))) {
+ if (mount_locked) {
+ IPOINTER_INSERT(ip, mp);
}
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
- xfs_ilock(ip, XFS_ILOCK_SHARED);
-
- } else if ((flags & SYNC_DELWRI) && (vp != NULL)) {
- if (VN_DIRTY(vp)) {
- /* We need to have dropped the lock here,
- * so insert a marker if we have not already
- * done so.
- */
- if (mount_locked) {
- IPOINTER_INSERT(ip, mp);
- }
-
- /*
- * Drop the inode lock since we can't hold it
- * across calls to the buffer cache.
- */
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
+ if (flags & SYNC_CLOSE) {
+ /* Shutdown case. Flush and invalidate. */
+ if (XFS_FORCED_SHUTDOWN(mp))
+ bhv_vop_toss_pages(vp, 0, -1, FI_REMAPF);
+ else
+ error = bhv_vop_flushinval_pages(vp, 0,
+ -1, FI_REMAPF);
+ } else if ((flags & SYNC_DELWRI) && VN_DIRTY(vp)) {
error = bhv_vop_flush_pages(vp, (xfs_off_t)0,
-1, fflag, FI_NONE);
- xfs_ilock(ip, XFS_ILOCK_SHARED);
}
+ /*
+ * When freezing, we need to wait ensure all I/O (including direct
+ * I/O) is complete to ensure no further data modification can take
+ * place after this point
+ */
+ if (flags & SYNC_IOWAIT)
+ vn_iowait(vp);
+
+ xfs_ilock(ip, XFS_ILOCK_SHARED);
}
- /*
- * When freezing, we need to wait ensure all I/O (including direct
- * I/O) is complete to ensure no further data modification can take
- * place after this point
- */
- if (flags & SYNC_IOWAIT)
- vn_iowait(vp);
if (flags & SYNC_BDFLUSH) {
if ((flags & SYNC_ATTR) &&
@@ -1514,6 +1542,15 @@ xfs_syncsub(
}
/*
+ * If asked, update the disk superblock with incore counter values if we
+ * are using non-persistent counters so that they don't get too far out
+ * of sync if we crash or get a forced shutdown. We don't want to force
+ * this to disk, just get a transaction into the iclogs....
+ */
+ if (flags & SYNC_SUPER)
+ xfs_log_sbcount(mp, 0);
+
+ /*
* Now check to see if the log needs a "dummy" transaction.
*/
@@ -1645,6 +1682,7 @@ xfs_vget(
* in stat(). */
#define MNTOPT_ATTR2 "attr2" /* do use attr2 attribute format */
#define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */
+#define MNTOPT_FILESTREAM "filestreams" /* use filestreams allocator */
STATIC unsigned long
suffix_strtoul(char *s, char **endp, unsigned int base)
@@ -1831,6 +1869,8 @@ xfs_parseargs(
args->flags |= XFSMNT_ATTR2;
} else if (!strcmp(this_char, MNTOPT_NOATTR2)) {
args->flags &= ~XFSMNT_ATTR2;
+ } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) {
+ args->flags2 |= XFSMNT2_FILESTREAMS;
} else if (!strcmp(this_char, "osyncisdsync")) {
/* no-op, this is now the default */
cmn_err(CE_WARN,
@@ -1959,9 +1999,9 @@ xfs_showargs(
}
/*
- * Second stage of a freeze. The data is already frozen, now we have to take
- * care of the metadata. New transactions are already blocked, so we need to
- * wait for any remaining transactions to drain out before proceding.
+ * Second stage of a freeze. The data is already frozen so we only
+ * need to take care of themetadata. Once that's done write a dummy
+ * record to dirty the log in case of a crash while frozen.
*/
STATIC void
xfs_freeze(
@@ -1969,18 +2009,7 @@ xfs_freeze(
{
xfs_mount_t *mp = XFS_BHVTOM(bdp);
- /* wait for all modifications to complete */
- while (atomic_read(&mp->m_active_trans) > 0)
- delay(100);
-
- /* flush inodes and push all remaining buffers out to disk */
- xfs_quiesce_fs(mp);
-
- ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0);
-
- /* Push the superblock and write an unmount record */
- xfs_log_unmount_write(mp);
- xfs_unmountfs_writesb(mp);
+ xfs_attr_quiesce(mp);
xfs_fs_log_dummy(mp);
}
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 70bc82f65311..1a5ad8cd97b0 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -51,6 +51,7 @@
#include "xfs_refcache.h"
#include "xfs_trans_space.h"
#include "xfs_log_priv.h"
+#include "xfs_filestream.h"
STATIC int
xfs_open(
@@ -77,36 +78,6 @@ xfs_open(
return 0;
}
-STATIC int
-xfs_close(
- bhv_desc_t *bdp,
- int flags,
- lastclose_t lastclose,
- cred_t *credp)
-{
- bhv_vnode_t *vp = BHV_TO_VNODE(bdp);
- xfs_inode_t *ip = XFS_BHVTOI(bdp);
-
- if (XFS_FORCED_SHUTDOWN(ip->i_mount))
- return XFS_ERROR(EIO);
-
- if (lastclose != L_TRUE || !VN_ISREG(vp))
- return 0;
-
- /*
- * If we previously truncated this file and removed old data in
- * the process, we want to initiate "early" writeout on the last
- * close. This is an attempt to combat the notorious NULL files
- * problem which is particularly noticable from a truncate down,
- * buffered (re-)write (delalloc), followed by a crash. What we
- * are effectively doing here is significantly reducing the time
- * window where we'd otherwise be exposed to that problem.
- */
- if (VUNTRUNCATE(vp) && VN_DIRTY(vp) && ip->i_delayed_blks > 0)
- return bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE);
- return 0;
-}
-
/*
* xfs_getattr
*/
@@ -183,9 +154,8 @@ xfs_getattr(
* realtime extent size or the realtime volume's
* extent size.
*/
- vap->va_blocksize = ip->i_d.di_extsize ?
- (ip->i_d.di_extsize << mp->m_sb.sb_blocklog) :
- (mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog);
+ vap->va_blocksize =
+ xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog;
}
break;
}
@@ -619,7 +589,30 @@ xfs_setattr(
code = xfs_igrow_start(ip, vap->va_size, credp);
}
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- vn_iowait(vp); /* wait for the completion of any pending DIOs */
+
+ /*
+ * We are going to log the inode size change in this
+ * transaction so any previous writes that are beyond the on
+ * disk EOF and the new EOF that have not been written out need
+ * to be written here. If we do not write the data out, we
+ * expose ourselves to the null files problem.
+ *
+ * Only flush from the on disk size to the smaller of the in
+ * memory file size or the new size as that's the range we
+ * really care about here and prevents waiting for other data
+ * not within the range we care about here.
+ */
+ if (!code &&
+ (ip->i_size != ip->i_d.di_size) &&
+ (vap->va_size > ip->i_d.di_size)) {
+ code = bhv_vop_flush_pages(XFS_ITOV(ip),
+ ip->i_d.di_size, vap->va_size,
+ XFS_B_ASYNC, FI_NONE);
+ }
+
+ /* wait for all I/O to complete */
+ vn_iowait(vp);
+
if (!code)
code = xfs_itruncate_data(ip, vap->va_size);
if (code) {
@@ -814,6 +807,8 @@ xfs_setattr(
di_flags |= XFS_DIFLAG_PROJINHERIT;
if (vap->va_xflags & XFS_XFLAG_NODEFRAG)
di_flags |= XFS_DIFLAG_NODEFRAG;
+ if (vap->va_xflags & XFS_XFLAG_FILESTREAM)
+ di_flags |= XFS_DIFLAG_FILESTREAM;
if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
if (vap->va_xflags & XFS_XFLAG_RTINHERIT)
di_flags |= XFS_DIFLAG_RTINHERIT;
@@ -1201,13 +1196,15 @@ xfs_fsync(
}
/*
- * This is called by xfs_inactive to free any blocks beyond eof,
- * when the link count isn't zero.
+ * This is called by xfs_inactive to free any blocks beyond eof
+ * when the link count isn't zero and by xfs_dm_punch_hole() when
+ * punching a hole to EOF.
*/
-STATIC int
-xfs_inactive_free_eofblocks(
+int
+xfs_free_eofblocks(
xfs_mount_t *mp,
- xfs_inode_t *ip)
+ xfs_inode_t *ip,
+ int flags)
{
xfs_trans_t *tp;
int error;
@@ -1216,6 +1213,7 @@ xfs_inactive_free_eofblocks(
xfs_filblks_t map_len;
int nimaps;
xfs_bmbt_irec_t imap;
+ int use_iolock = (flags & XFS_FREE_EOF_LOCK);
/*
* Figure out if there are any blocks beyond the end
@@ -1256,11 +1254,14 @@ xfs_inactive_free_eofblocks(
* cache and we can't
* do that within a transaction.
*/
- xfs_ilock(ip, XFS_IOLOCK_EXCL);
+ if (use_iolock)
+ xfs_ilock(ip, XFS_IOLOCK_EXCL);
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
ip->i_size);
if (error) {
- xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+ xfs_trans_cancel(tp, 0);
+ if (use_iolock)
+ xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error;
}
@@ -1297,7 +1298,8 @@ xfs_inactive_free_eofblocks(
error = xfs_trans_commit(tp,
XFS_TRANS_RELEASE_LOG_RES);
}
- xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL);
+ xfs_iunlock(ip, (use_iolock ? (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)
+ : XFS_ILOCK_EXCL));
}
return error;
}
@@ -1560,6 +1562,31 @@ xfs_release(
if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
return 0;
+ if (!XFS_FORCED_SHUTDOWN(mp)) {
+ /*
+ * If we are using filestreams, and we have an unlinked
+ * file that we are processing the last close on, then nothing
+ * will be able to reopen and write to this file. Purge this
+ * inode from the filestreams cache so that it doesn't delay
+ * teardown of the inode.
+ */
+ if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
+ xfs_filestream_deassociate(ip);
+
+ /*
+ * If we previously truncated this file and removed old data
+ * in the process, we want to initiate "early" writeout on
+ * the last close. This is an attempt to combat the notorious
+ * NULL files problem which is particularly noticable from a
+ * truncate down, buffered (re-)write (delalloc), followed by
+ * a crash. What we are effectively doing here is
+ * significantly reducing the time window where we'd otherwise
+ * be exposed to that problem.
+ */
+ if (VUNTRUNCATE(vp) && VN_DIRTY(vp) && ip->i_delayed_blks > 0)
+ bhv_vop_flush_pages(vp, 0, -1, XFS_B_ASYNC, FI_NONE);
+ }
+
#ifdef HAVE_REFCACHE
/* If we are in the NFS reference cache then don't do this now */
if (ip->i_refcache)
@@ -1573,7 +1600,8 @@ xfs_release(
(ip->i_df.if_flags & XFS_IFEXTENTS)) &&
(!(ip->i_d.di_flags &
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) {
- if ((error = xfs_inactive_free_eofblocks(mp, ip)))
+ error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
+ if (error)
return error;
/* Update linux inode block count after free above */
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
@@ -1654,7 +1682,8 @@ xfs_inactive(
(!(ip->i_d.di_flags &
(XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) ||
(ip->i_delayed_blks != 0)))) {
- if ((error = xfs_inactive_free_eofblocks(mp, ip)))
+ error = xfs_free_eofblocks(mp, ip, XFS_FREE_EOF_LOCK);
+ if (error)
return VN_INACTIVE_CACHE;
/* Update linux inode block count after free above */
vn_to_inode(vp)->i_blocks = XFS_FSB_TO_BB(mp,
@@ -1680,6 +1709,7 @@ xfs_inactive(
error = xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE, 0);
if (error) {
+ xfs_trans_cancel(tp, 0);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return VN_INACTIVE_CACHE;
}
@@ -2217,9 +2247,9 @@ static inline int
xfs_lock_inumorder(int lock_mode, int subclass)
{
if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
- lock_mode |= (subclass + XFS_IOLOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
+ lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
- lock_mode |= (subclass + XFS_ILOCK_INUMORDER) << XFS_ILOCK_SHIFT;
+ lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT;
return lock_mode;
}
@@ -2546,6 +2576,15 @@ xfs_remove(
*/
xfs_refcache_purge_ip(ip);
+ /*
+ * If we are using filestreams, kill the stream association.
+ * If the file is still open it may get a new one but that
+ * will get killed on last close in xfs_close() so we don't
+ * have to worry about that.
+ */
+ if (link_zero && xfs_inode_is_filestream(ip))
+ xfs_filestream_deassociate(ip);
+
vn_trace_exit(XFS_ITOV(ip), __FUNCTION__, (inst_t *)__return_address);
/*
@@ -4047,22 +4086,16 @@ xfs_alloc_file_space(
if (XFS_FORCED_SHUTDOWN(mp))
return XFS_ERROR(EIO);
- rt = XFS_IS_REALTIME_INODE(ip);
- if (unlikely(rt)) {
- if (!(extsz = ip->i_d.di_extsize))
- extsz = mp->m_sb.sb_rextsize;
- } else {
- extsz = ip->i_d.di_extsize;
- }
-
if ((error = XFS_QM_DQATTACH(mp, ip, 0)))
return error;
if (len <= 0)
return XFS_ERROR(EINVAL);
+ rt = XFS_IS_REALTIME_INODE(ip);
+ extsz = xfs_get_extsz_hint(ip);
+
count = len;
- error = 0;
imapp = &imaps[0];
nimaps = 1;
bmapi_flag = XFS_BMAPI_WRITE | (alloc_type ? XFS_BMAPI_PREALLOC : 0);
@@ -4424,9 +4457,12 @@ xfs_free_file_space(
while (!error && !done) {
/*
- * allocate and setup the transaction
+ * allocate and setup the transaction. Allow this
+ * transaction to dip into the reserve blocks to ensure
+ * the freeing of the space succeeds at ENOSPC.
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
+ tp->t_flags |= XFS_TRANS_RESERVE;
error = xfs_trans_reserve(tp,
resblks,
XFS_WRITE_LOG_RES(mp),
@@ -4678,7 +4714,6 @@ xfs_change_file_space(
bhv_vnodeops_t xfs_vnodeops = {
BHV_IDENTITY_INIT(VN_BHV_XFS,VNODE_POSITION_XFS),
.vop_open = xfs_open,
- .vop_close = xfs_close,
.vop_read = xfs_read,
#ifdef HAVE_SPLICE
.vop_splice_read = xfs_splice_read,
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index 8948a6461834..45662f6dbdb6 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -486,6 +486,8 @@
#define ACPI_FUNCTION_NAME(name)
#endif
+#ifdef DEBUG_FUNC_TRACE
+
#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \
acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
#define ACPI_FUNCTION_TRACE_PTR(a,b) ACPI_FUNCTION_NAME(a) \
@@ -563,6 +565,27 @@
#endif /* ACPI_SIMPLE_RETURN_MACROS */
+#else /* !DEBUG_FUNC_TRACE */
+
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_TRACE_PTR(a,b)
+#define ACPI_FUNCTION_TRACE_U32(a,b)
+#define ACPI_FUNCTION_TRACE_STR(a,b)
+#define ACPI_FUNCTION_EXIT
+#define ACPI_FUNCTION_STATUS_EXIT(s)
+#define ACPI_FUNCTION_VALUE_EXIT(s)
+#define ACPI_FUNCTION_TRACE(a)
+#define ACPI_FUNCTION_ENTRY()
+
+#define return_VOID return
+#define return_ACPI_STATUS(s) return(s)
+#define return_VALUE(s) return(s)
+#define return_UINT8(s) return(s)
+#define return_UINT32(s) return(s)
+#define return_PTR(s) return(s)
+
+#endif /* DEBUG_FUNC_TRACE */
+
/* Conditional execution */
#define ACPI_DEBUG_EXEC(a) a
@@ -599,26 +622,26 @@
#define ACPI_DEBUG_EXEC(a)
#define ACPI_NORMAL_EXEC(a) a;
-#define ACPI_DEBUG_DEFINE(a)
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#define ACPI_FUNCTION_NAME(a)
-#define ACPI_FUNCTION_TRACE(a)
-#define ACPI_FUNCTION_TRACE_PTR(a,b)
-#define ACPI_FUNCTION_TRACE_U32(a,b)
-#define ACPI_FUNCTION_TRACE_STR(a,b)
-#define ACPI_FUNCTION_EXIT
-#define ACPI_FUNCTION_STATUS_EXIT(s)
-#define ACPI_FUNCTION_VALUE_EXIT(s)
-#define ACPI_FUNCTION_ENTRY()
-#define ACPI_DUMP_STACK_ENTRY(a)
-#define ACPI_DUMP_OPERANDS(a,b,c,d,e)
-#define ACPI_DUMP_ENTRY(a,b)
-#define ACPI_DUMP_TABLES(a,b)
-#define ACPI_DUMP_PATHNAME(a,b,c,d)
-#define ACPI_DUMP_RESOURCE_LIST(a)
-#define ACPI_DUMP_BUFFER(a,b)
-#define ACPI_DEBUG_PRINT(pl)
-#define ACPI_DEBUG_PRINT_RAW(pl)
+#define ACPI_DEBUG_DEFINE(a) do { } while(0)
+#define ACPI_DEBUG_ONLY_MEMBERS(a) do { } while(0)
+#define ACPI_FUNCTION_NAME(a) do { } while(0)
+#define ACPI_FUNCTION_TRACE(a) do { } while(0)
+#define ACPI_FUNCTION_TRACE_PTR(a,b) do { } while(0)
+#define ACPI_FUNCTION_TRACE_U32(a,b) do { } while(0)
+#define ACPI_FUNCTION_TRACE_STR(a,b) do { } while(0)
+#define ACPI_FUNCTION_EXIT do { } while(0)
+#define ACPI_FUNCTION_STATUS_EXIT(s) do { } while(0)
+#define ACPI_FUNCTION_VALUE_EXIT(s) do { } while(0)
+#define ACPI_FUNCTION_ENTRY() do { } while(0)
+#define ACPI_DUMP_STACK_ENTRY(a) do { } while(0)
+#define ACPI_DUMP_OPERANDS(a,b,c,d,e) do { } while(0)
+#define ACPI_DUMP_ENTRY(a,b) do { } while(0)
+#define ACPI_DUMP_TABLES(a,b) do { } while(0)
+#define ACPI_DUMP_PATHNAME(a,b,c,d) do { } while(0)
+#define ACPI_DUMP_RESOURCE_LIST(a) do { } while(0)
+#define ACPI_DUMP_BUFFER(a,b) do { } while(0)
+#define ACPI_DEBUG_PRINT(pl) do { } while(0)
+#define ACPI_DEBUG_PRINT_RAW(pl) do { } while(0)
#define return_VOID return
#define return_ACPI_STATUS(s) return(s)
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index 7812267b577f..c090a8b0bc99 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -178,8 +178,8 @@
/* Defaults for debug_level, debug and normal */
-#define ACPI_DEBUG_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
-#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
+#define ACPI_DEBUG_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
+#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
#define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL)
#endif /* __ACOUTPUT_H__ */
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c6fa5e023bc7..5e3dcf3299bf 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -321,7 +321,8 @@ struct acpi_bus_event {
};
extern struct kset acpi_subsys;
-
+extern int acpi_bus_generate_genetlink_event(struct acpi_device *device,
+ u8 type, int data);
/*
* External Functions
*/
diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h
index e2fcee2b340d..62c5ee4311da 100644
--- a/include/acpi/acpi_numa.h
+++ b/include/acpi/acpi_numa.h
@@ -13,6 +13,7 @@
extern int pxm_to_node(int);
extern int node_to_pxm(int);
+extern void __acpi_map_pxm_to_node(int, int);
extern int acpi_map_pxm_to_node(int);
extern void __cpuinit acpi_unmap_pxm_to_node(int);
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index dab2ec59a3b0..c785485e62a6 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -136,7 +136,7 @@
/*! [Begin] no source code translation */
-#if defined(__linux__)
+#if defined(_LINUX) || defined(__linux__)
#include "aclinux.h"
#elif defined(_AED_EFI)
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index a568717f98c6..6ed15a0978eb 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -91,7 +91,10 @@
#define ACPI_USE_NATIVE_DIVIDE
#endif
+#ifndef __cdecl
#define __cdecl
+#endif
+
#define ACPI_FLUSH_CPU_CACHE()
#endif /* __KERNEL__ */
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index b4b0ffdab098..f9f987f8e661 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -21,6 +21,8 @@
#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
#define ACPI_PSD_REV0_ENTRIES 5
+#define ACPI_TSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
+#define ACPI_TSD_REV0_ENTRIES 5
/*
* Types of coordination defined in ACPI 3.0. Same macros can be used across
* P, C and T states
@@ -125,17 +127,53 @@ struct acpi_processor_performance {
/* Throttling Control */
+struct acpi_tsd_package {
+ acpi_integer num_entries;
+ acpi_integer revision;
+ acpi_integer domain;
+ acpi_integer coord_type;
+ acpi_integer num_processors;
+} __attribute__ ((packed));
+
+struct acpi_ptc_register {
+ u8 descriptor;
+ u16 length;
+ u8 space_id;
+ u8 bit_width;
+ u8 bit_offset;
+ u8 reserved;
+ u64 address;
+} __attribute__ ((packed));
+
+struct acpi_processor_tx_tss {
+ acpi_integer freqpercentage; /* */
+ acpi_integer power; /* milliWatts */
+ acpi_integer transition_latency; /* microseconds */
+ acpi_integer control; /* control value */
+ acpi_integer status; /* success indicator */
+};
struct acpi_processor_tx {
u16 power;
u16 performance;
};
+struct acpi_processor;
struct acpi_processor_throttling {
- int state;
+ unsigned int state;
+ unsigned int platform_limit;
+ struct acpi_pct_register control_register;
+ struct acpi_pct_register status_register;
+ unsigned int state_count;
+ struct acpi_processor_tx_tss *states_tss;
+ struct acpi_tsd_package domain_info;
+ cpumask_t shared_cpu_map;
+ int (*acpi_processor_get_throttling) (struct acpi_processor * pr);
+ int (*acpi_processor_set_throttling) (struct acpi_processor * pr,
+ int state);
+
u32 address;
u8 duty_offset;
u8 duty_width;
- int state_count;
struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING];
};
@@ -169,6 +207,9 @@ struct acpi_processor {
u32 id;
u32 pblk;
int performance_platform_limit;
+ int throttling_platform_limit;
+ /* 0 - states 0..n-th state available */
+
struct acpi_processor_flags flags;
struct acpi_processor_power power;
struct acpi_processor_performance *performance;
@@ -270,7 +311,7 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
/* in processor_throttling.c */
int acpi_processor_get_throttling_info(struct acpi_processor *pr);
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
extern struct file_operations acpi_processor_throttling_fops;
/* in processor_idle.c */
diff --git a/include/asm-alpha/a.out.h b/include/asm-alpha/a.out.h
index d97daf42753d..e43cf61649a9 100644
--- a/include/asm-alpha/a.out.h
+++ b/include/asm-alpha/a.out.h
@@ -101,6 +101,8 @@ struct exec
#define STACK_TOP \
(current->personality & ADDR_LIMIT_32BIT ? 0x80000000 : 0x00120000000UL)
+#define STACK_TOP_MAX 0x00120000000UL
+
#endif
#endif /* __A_OUT_GNU_H__ */
diff --git a/include/asm-alpha/fb.h b/include/asm-alpha/fb.h
new file mode 100644
index 000000000000..fa9bbb96b2b3
--- /dev/null
+++ b/include/asm-alpha/fb.h
@@ -0,0 +1,13 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/device.h>
+
+/* Caching is off in the I/O space quadrant by design. */
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
index 21a86f1a05b3..ab5b60dcef19 100644
--- a/include/asm-alpha/io.h
+++ b/include/asm-alpha/io.h
@@ -4,6 +4,7 @@
#ifdef __KERNEL__
#include <linux/kernel.h>
+#include <linux/mm.h>
#include <asm/compiler.h>
#include <asm/system.h>
#include <asm/pgtable.h>
@@ -90,6 +91,11 @@ static inline void * phys_to_virt(unsigned long address)
#define page_to_phys(page) page_to_pa(page)
+static inline dma_addr_t __deprecated isa_page_to_bus(struct page *page)
+{
+ return page_to_phys(page);
+}
+
/* This depends on working iommu. */
#define BIO_VMERGE_BOUNDARY (alpha_mv.mv_pci_tbi ? PAGE_SIZE : 0)
@@ -102,12 +108,12 @@ static inline void * phys_to_virt(unsigned long address)
*
* Note that this only works for a limited range of kernel addresses,
* and very well may not span all memory. Consider this interface
- * deprecated in favour of the mapping functions in <asm/pci.h>.
+ * deprecated in favour of the DMA-mapping API.
*/
extern unsigned long __direct_map_base;
extern unsigned long __direct_map_size;
-static inline unsigned long virt_to_bus(void *address)
+static inline unsigned long __deprecated virt_to_bus(void *address)
{
unsigned long phys = virt_to_phys(address);
unsigned long bus = phys + __direct_map_base;
@@ -115,7 +121,7 @@ static inline unsigned long virt_to_bus(void *address)
}
#define isa_virt_to_bus virt_to_bus
-static inline void *bus_to_virt(unsigned long address)
+static inline void * __deprecated bus_to_virt(unsigned long address)
{
void *virt;
@@ -126,6 +132,7 @@ static inline void *bus_to_virt(unsigned long address)
virt = phys_to_virt(address);
return (long)address <= 0 ? NULL : virt;
}
+#define isa_bus_to_virt bus_to_virt
/*
* There are different chipsets to interface the Alpha CPUs to the world.
diff --git a/include/asm-alpha/irq.h b/include/asm-alpha/irq.h
index 917b9fe372cf..06377400dc09 100644
--- a/include/asm-alpha/irq.h
+++ b/include/asm-alpha/irq.h
@@ -85,10 +85,6 @@ static __inline__ int irq_canonicalize(int irq)
return ((irq == 2) ? 9 : irq);
}
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
-
struct pt_regs;
extern void (*perf_irq)(unsigned long, struct pt_regs *);
diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h
index d2bed3cb33ff..bae7f05716d4 100644
--- a/include/asm-alpha/page.h
+++ b/include/asm-alpha/page.h
@@ -17,7 +17,8 @@
extern void clear_page(void *page);
#define clear_user_page(page, vaddr, pg) clear_page(page)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vmaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vmaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
extern void copy_page(void * _to, void * _from);
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 85aa1127c903..30ee7669b19f 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -199,30 +199,6 @@ pci_dma_sync_sg_for_device(struct pci_dev *dev, struct scatterlist *sg,
extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
-/* True if the machine supports DAC addressing, and DEV can
- make use of it given MASK. */
-extern int pci_dac_dma_supported(struct pci_dev *hwdev, u64 mask);
-
-/* Convert to/from DAC dma address and struct page. */
-extern dma64_addr_t pci_dac_page_to_dma(struct pci_dev *, struct page *,
- unsigned long, int);
-extern struct page *pci_dac_dma_to_page(struct pci_dev *, dma64_addr_t);
-extern unsigned long pci_dac_dma_to_offset(struct pci_dev *, dma64_addr_t);
-
-static inline void
-pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr,
- size_t len, int direction)
-{
- /* Nothing to do. */
-}
-
-static inline void
-pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
- size_t len, int direction)
-{
- /* Nothing to do. */
-}
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -275,11 +251,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
return hose->need_domain_info;
}
-static inline void
-pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
struct pci_dev *alpha_gendev_to_pci(struct device *dev);
#endif /* __KERNEL__ */
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 616d20662ff3..99037b032357 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -264,21 +264,15 @@ extern inline void pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; }
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-extern inline int pte_read(pte_t pte) { return !(pte_val(pte) & _PAGE_FOR); }
extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_FOW); }
-extern inline int pte_exec(pte_t pte) { return !(pte_val(pte) & _PAGE_FOE); }
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 pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_FOW; return pte; }
-extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) |= _PAGE_FOR; return pte; }
-extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) |= _PAGE_FOE; return pte; }
extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~(__DIRTY_BITS); return pte; }
extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~(__ACCESS_BITS); return pte; }
extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) &= ~_PAGE_FOW; return pte; }
-extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) &= ~_PAGE_FOR; return pte; }
-extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) &= ~_PAGE_FOE; 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; }
diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h
index cf1021a97b2e..620c4d86cbf4 100644
--- a/include/asm-alpha/system.h
+++ b/include/asm-alpha/system.h
@@ -139,16 +139,6 @@ extern void halt(void) __attribute__((noreturn));
struct task_struct;
extern struct task_struct *alpha_switch_to(unsigned long, struct task_struct*);
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
#define imb() \
__asm__ __volatile__ ("call_pal %0 #imb" : : "i" (PAL_imb) : "memory")
diff --git a/include/asm-alpha/termios.h b/include/asm-alpha/termios.h
index 39e492c3bfa3..fa13716a11c3 100644
--- a/include/asm-alpha/termios.h
+++ b/include/asm-alpha/termios.h
@@ -81,7 +81,7 @@ struct termio {
#define user_termio_to_kernel_termios(a_termios, u_termio) \
({ \
- struct termios *k_termios = (a_termios); \
+ struct ktermios *k_termios = (a_termios); \
struct termio k_termio; \
int canon, ret; \
\
@@ -113,7 +113,7 @@ struct termio {
*/
#define kernel_termios_to_user_termio(u_termio, a_termios) \
({ \
- struct termios *k_termios = (a_termios); \
+ struct ktermios *k_termios = (a_termios); \
struct termio k_termio; \
int canon; \
\
diff --git a/include/asm-arm/Kbuild b/include/asm-arm/Kbuild
index c68e1680da01..73237bd130a2 100644
--- a/include/asm-arm/Kbuild
+++ b/include/asm-arm/Kbuild
@@ -1 +1,3 @@
include include/asm-generic/Kbuild.asm
+
+unifdef-y += hwcap.h
diff --git a/include/asm-arm/a.out.h b/include/asm-arm/a.out.h
index 3e5fe64c4394..d7165e86df25 100644
--- a/include/asm-arm/a.out.h
+++ b/include/asm-arm/a.out.h
@@ -30,6 +30,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP ((current->personality == PER_LINUX_32BIT) ? \
TASK_SIZE : TASK_SIZE_26)
+#define STACK_TOP_MAX TASK_SIZE
#endif
#ifndef LIBRARY_START_TEXT
diff --git a/include/asm-arm/arch-at91/at91_dbgu.h b/include/asm-arm/arch-at91/at91_dbgu.h
index b0369e176f7b..8019ffd0ad3b 100644
--- a/include/asm-arm/arch-at91/at91_dbgu.h
+++ b/include/asm-arm/arch-at91/at91_dbgu.h
@@ -16,6 +16,7 @@
#ifndef AT91_DBGU_H
#define AT91_DBGU_H
+#ifdef AT91_DBGU
#define AT91_DBGU_CR (AT91_DBGU + 0x00) /* Control Register */
#define AT91_DBGU_MR (AT91_DBGU + 0x04) /* Mode Register */
#define AT91_DBGU_IER (AT91_DBGU + 0x08) /* Interrupt Enable Register */
@@ -30,6 +31,15 @@
#define AT91_DBGU_CIDR (AT91_DBGU + 0x40) /* Chip ID Register */
#define AT91_DBGU_EXID (AT91_DBGU + 0x44) /* Chip ID Extension Register */
+#define AT91_DBGU_FNR (AT91_DBGU + 0x48) /* Force NTRST Register [SAM9 only] */
+#define AT91_DBGU_FNTRST (1 << 0) /* Force NTRST */
+
+#endif /* AT91_DBGU */
+
+/*
+ * Some AT91 parts that don't have full DEBUG units still support the ID
+ * and extensions register.
+ */
#define AT91_CIDR_VERSION (0x1f << 0) /* Version of the Device */
#define AT91_CIDR_EPROC (7 << 5) /* Embedded Processor */
#define AT91_CIDR_NVPSIZ (0xf << 8) /* Nonvolatile Program Memory Size */
@@ -53,7 +63,4 @@
#define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */
#define AT91_CIDR_EXT (1 << 31) /* Extension Flag */
-#define AT91_DBGU_FNR (AT91_DBGU + 0x48) /* Force NTRST Register [SAM9 only] */
-#define AT91_DBGU_FNTRST (1 << 0) /* Force NTRST */
-
#endif
diff --git a/include/asm-arm/arch-at91/at91_mci.h b/include/asm-arm/arch-at91/at91_mci.h
index 40a9876b661a..c2e11cc374ba 100644
--- a/include/asm-arm/arch-at91/at91_mci.h
+++ b/include/asm-arm/arch-at91/at91_mci.h
@@ -26,6 +26,9 @@
#define AT91_MCI_MR 0x04 /* Mode Register */
#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */
#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */
+#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */
+#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */
+#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */
#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */
#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */
#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */
diff --git a/include/asm-arm/arch-at91/at91x40.h b/include/asm-arm/arch-at91/at91x40.h
new file mode 100644
index 000000000000..612203e0177f
--- /dev/null
+++ b/include/asm-arm/arch-at91/at91x40.h
@@ -0,0 +1,55 @@
+/*
+ * include/asm-arm/arch-at91/at91x40.h
+ *
+ * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91X40_H
+#define AT91X40_H
+
+/*
+ * IRQ list.
+ */
+#define AT91_ID_FIQ 0 /* FIQ */
+#define AT91_ID_SYS 1 /* System Peripheral */
+#define AT91X40_ID_USART0 2 /* USART port 0 */
+#define AT91X40_ID_USART1 3 /* USART port 1 */
+#define AT91X40_ID_TC0 4 /* Timer/Counter 0 */
+#define AT91X40_ID_TC1 5 /* Timer/Counter 1*/
+#define AT91X40_ID_TC2 6 /* Timer/Counter 2*/
+#define AT91X40_ID_WD 7 /* Watchdog? */
+#define AT91X40_ID_PIOA 8 /* Parallel IO Controller A */
+
+#define AT91X40_ID_IRQ0 16 /* External IRQ 0 */
+#define AT91X40_ID_IRQ1 17 /* External IRQ 1 */
+#define AT91X40_ID_IRQ2 18 /* External IRQ 2 */
+
+/*
+ * System Peripherals (offset from AT91_BASE_SYS)
+ */
+#define AT91_BASE_SYS 0xffc00000
+
+#define AT91_EBI (0xffe00000 - AT91_BASE_SYS) /* External Bus Interface */
+#define AT91_SF (0xfff00000 - AT91_BASE_SYS) /* Special Function */
+#define AT91_USART1 (0xfffcc000 - AT91_BASE_SYS) /* USART 1 */
+#define AT91_USART0 (0xfffd0000 - AT91_BASE_SYS) /* USART 0 */
+#define AT91_TC (0xfffe0000 - AT91_BASE_SYS) /* Timer Counter */
+#define AT91_PIOA (0xffff0000 - AT91_BASE_SYS) /* PIO Controller A */
+#define AT91_PS (0xffff4000 - AT91_BASE_SYS) /* Power Save */
+#define AT91_WD (0xffff8000 - AT91_BASE_SYS) /* Watchdog Timer */
+#define AT91_AIC (0xfffff000 - AT91_BASE_SYS) /* Advanced Interrupt Controller */
+
+/*
+ * The AT91x40 series doesn't have a debug unit like the other AT91 parts.
+ * But it does have a chip identify register and extension ID, so define at
+ * least these here.
+ */
+#define AT91_DBGU_CIDR (AT91_SF + 0) /* CIDR in PS segment */
+#define AT91_DBGU_EXID (AT91_SF + 4) /* EXID in PS segment */
+
+#endif /* AT91X40_H */
diff --git a/include/asm-arm/arch-at91/board.h b/include/asm-arm/arch-at91/board.h
index 0ce6ee98ed0b..d96b10fd449f 100644
--- a/include/asm-arm/arch-at91/board.h
+++ b/include/asm-arm/arch-at91/board.h
@@ -64,6 +64,7 @@ extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
/* Ethernet (EMAC & MACB) */
struct at91_eth_data {
+ u32 phy_mask;
u8 phy_irq_pin; /* PHY IRQ */
u8 is_rmii; /* using RMII interface? */
};
diff --git a/include/asm-arm/arch-at91/cpu.h b/include/asm-arm/arch-at91/cpu.h
index ef93c30a9c5f..080cbb401a87 100644
--- a/include/asm-arm/arch-at91/cpu.h
+++ b/include/asm-arm/arch-at91/cpu.h
@@ -28,6 +28,11 @@
#define ARCH_ID_AT91SAM9RL64 0x019b03a0
+#define ARCH_ID_AT91M40800 0x14080044
+#define ARCH_ID_AT91R40807 0x44080746
+#define ARCH_ID_AT91M40807 0x14080745
+#define ARCH_ID_AT91R40008 0x44000840
+
static inline unsigned long at91_cpu_identify(void)
{
return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION);
diff --git a/include/asm-arm/arch-at91/hardware.h b/include/asm-arm/arch-at91/hardware.h
index 46835e945aea..8f1cdd38a969 100644
--- a/include/asm-arm/arch-at91/hardware.h
+++ b/include/asm-arm/arch-at91/hardware.h
@@ -26,18 +26,29 @@
#include <asm/arch/at91sam9263.h>
#elif defined(CONFIG_ARCH_AT91SAM9RL)
#include <asm/arch/at91sam9rl.h>
+#elif defined(CONFIG_ARCH_AT91X40)
+#include <asm/arch/at91x40.h>
#else
#error "Unsupported AT91 processor"
#endif
+#ifdef CONFIG_MMU
/*
* Remap the peripherals from address 0xFFF78000 .. 0xFFFFFFFF
* to 0xFEF78000 .. 0xFF000000. (544Kb)
*/
#define AT91_IO_PHYS_BASE 0xFFF78000
-#define AT91_IO_SIZE (0xFFFFFFFF - AT91_IO_PHYS_BASE + 1)
#define AT91_IO_VIRT_BASE (0xFF000000 - AT91_IO_SIZE)
+#else
+/*
+ * Identity mapping for the non MMU case.
+ */
+#define AT91_IO_PHYS_BASE AT91_BASE_SYS
+#define AT91_IO_VIRT_BASE AT91_IO_PHYS_BASE
+#endif
+
+#define AT91_IO_SIZE (0xFFFFFFFF - AT91_IO_PHYS_BASE + 1)
/* Convert a physical IO address to virtual IO address */
#define AT91_IO_P2V(x) ((x) - AT91_IO_PHYS_BASE + AT91_IO_VIRT_BASE)
@@ -66,7 +77,11 @@
#define AT91_CHIPSELECT_7 0x80000000
/* SDRAM */
+#ifdef CONFIG_DRAM_BASE
+#define AT91_SDRAM_BASE CONFIG_DRAM_BASE
+#else
#define AT91_SDRAM_BASE AT91_CHIPSELECT_1
+#endif
/* Clocks */
#define AT91_SLOW_CLOCK 32768 /* slow clock */
diff --git a/include/asm-arm/arch-at91/timex.h b/include/asm-arm/arch-at91/timex.h
index 2df1ee12dfb7..a310698fb4da 100644
--- a/include/asm-arm/arch-at91/timex.h
+++ b/include/asm-arm/arch-at91/timex.h
@@ -42,6 +42,11 @@
#define AT91SAM9_MASTER_CLOCK 100000000
#define CLOCK_TICK_RATE (AT91SAM9_MASTER_CLOCK/16)
+#elif defined(CONFIG_ARCH_AT91X40)
+
+#define AT91X40_MASTER_CLOCK 40000000
+#define CLOCK_TICK_RATE (AT91X40_MASTER_CLOCK)
+
#endif
#endif
diff --git a/include/asm-arm/arch-at91/uncompress.h b/include/asm-arm/arch-at91/uncompress.h
index 30ac587b3b41..272a7e0dc6cf 100644
--- a/include/asm-arm/arch-at91/uncompress.h
+++ b/include/asm-arm/arch-at91/uncompress.h
@@ -33,20 +33,24 @@
*/
static void putc(int c)
{
+#ifdef AT91_DBGU
void __iomem *sys = (void __iomem *) AT91_BASE_SYS; /* physical address */
while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXRDY))
barrier();
__raw_writel(c, sys + AT91_DBGU_THR);
+#endif
}
static inline void flush(void)
{
+#ifdef AT91_DBGU
void __iomem *sys = (void __iomem *) AT91_BASE_SYS; /* physical address */
/* wait for transmission to complete */
while (!(__raw_readl(sys + AT91_DBGU_SR) & AT91_DBGU_TXEMPTY))
barrier();
+#endif
}
#define arch_decomp_setup()
diff --git a/include/asm-arm/arch-davinci/clock.h b/include/asm-arm/arch-davinci/clock.h
new file mode 100644
index 000000000000..cc168b7a14f2
--- /dev/null
+++ b/include/asm-arm/arch-davinci/clock.h
@@ -0,0 +1,22 @@
+/*
+ * include/asm-arm/arch-davinci/clock.h
+ *
+ * Clock control driver for DaVinci - header file
+ *
+ * Authors: Vladimir Barinov <source@mvista.com>
+ *
+ * 2007 (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.
+ */
+#ifndef __ASM_ARCH_DAVINCI_CLOCK_H
+#define __ASM_ARCH_DAVINCI_CLOCK_H
+
+struct clk;
+
+extern int clk_register(struct clk *clk);
+extern void clk_unregister(struct clk *clk);
+extern int davinci_clk_init(void);
+
+#endif
diff --git a/include/asm-arm/arch-davinci/gpio.h b/include/asm-arm/arch-davinci/gpio.h
new file mode 100644
index 000000000000..ea24a0e0bfd6
--- /dev/null
+++ b/include/asm-arm/arch-davinci/gpio.h
@@ -0,0 +1,156 @@
+/*
+ * TI DaVinci GPIO Support
+ *
+ * Copyright (c) 2006 David Brownell
+ * Copyright (c) 2007, 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.
+ */
+
+#ifndef __DAVINCI_GPIO_H
+#define __DAVINCI_GPIO_H
+
+/*
+ * basic gpio routines
+ *
+ * board-specific init should be done by arch/.../.../board-XXX.c (maybe
+ * initializing banks together) rather than boot loaders; kexec() won't
+ * go through boot loaders.
+ *
+ * the gpio clock will be turned on when gpios are used, and you may also
+ * need to pay attention to PINMUX0 and PINMUX1 to be sure those pins are
+ * used as gpios, not with other peripherals.
+ *
+ * GPIOs are numbered 0..(DAVINCI_N_GPIO-1). For documentation, and maybe
+ * for later updates, code should write GPIO(N) or:
+ * - GPIOV18(N) for 1.8V pins, N in 0..53; same as GPIO(0)..GPIO(53)
+ * - GPIOV33(N) for 3.3V pins, N in 0..17; same as GPIO(54)..GPIO(70)
+ *
+ * For GPIO IRQs use gpio_to_irq(GPIO(N)) or gpio_to_irq(GPIOV33(N)) etc
+ * for now, that's != GPIO(N)
+ */
+#define GPIO(X) (X) /* 0 <= X <= 70 */
+#define GPIOV18(X) (X) /* 1.8V i/o; 0 <= X <= 53 */
+#define GPIOV33(X) ((X)+54) /* 3.3V i/o; 0 <= X <= 17 */
+
+struct gpio_controller {
+ u32 dir;
+ u32 out_data;
+ u32 set_data;
+ u32 clr_data;
+ u32 in_data;
+ u32 set_rising;
+ u32 clr_rising;
+ u32 set_falling;
+ u32 clr_falling;
+ u32 intstat;
+};
+
+/* The __gpio_to_controller() and __gpio_mask() functions inline to constants
+ * with constant parameters; or in outlined code they execute at runtime.
+ *
+ * You'd access the controller directly when reading or writing more than
+ * one gpio value at a time, and to support wired logic where the value
+ * being driven by the cpu need not match the value read back.
+ *
+ * These are NOT part of the cross-platform GPIO interface
+ */
+static inline struct gpio_controller *__iomem
+__gpio_to_controller(unsigned gpio)
+{
+ void *__iomem ptr;
+
+ if (gpio < 32)
+ ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
+ else if (gpio < 64)
+ ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
+ else if (gpio < DAVINCI_N_GPIO)
+ ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
+ else
+ ptr = NULL;
+ return ptr;
+}
+
+static inline u32 __gpio_mask(unsigned gpio)
+{
+ return 1 << (gpio % 32);
+}
+
+/* The get/set/clear functions will inline when called with constant
+ * parameters, for low-overhead bitbanging. Illegal constant parameters
+ * cause link-time errors.
+ *
+ * Otherwise, calls with variable parameters use outlined functions.
+ */
+extern int __error_inval_gpio(void);
+
+extern void __gpio_set(unsigned gpio, int value);
+extern int __gpio_get(unsigned gpio);
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ if (__builtin_constant_p(value)) {
+ struct gpio_controller *__iomem g;
+ u32 mask;
+
+ if (gpio >= DAVINCI_N_GPIO)
+ __error_inval_gpio();
+
+ g = __gpio_to_controller(gpio);
+ mask = __gpio_mask(gpio);
+ if (value)
+ __raw_writel(mask, &g->set_data);
+ else
+ __raw_writel(mask, &g->clr_data);
+ return;
+ }
+
+ __gpio_set(gpio, value);
+}
+
+/* Returns zero or nonzero; works for gpios configured as inputs OR
+ * as outputs.
+ *
+ * NOTE: changes in reported values are synchronized to the GPIO clock.
+ * This is most easily seen after calling gpio_set_value() and then immediatly
+ * gpio_get_value(), where the gpio_get_value() would return the old value
+ * until the GPIO clock ticks and the new value gets latched.
+ */
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ struct gpio_controller *__iomem g;
+
+ if (!__builtin_constant_p(gpio))
+ return __gpio_get(gpio);
+
+ if (gpio >= DAVINCI_N_GPIO)
+ return __error_inval_gpio();
+
+ g = __gpio_to_controller(gpio);
+ return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
+}
+
+/* powerup default direction is IN */
+extern int gpio_direction_input(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+extern int gpio_request(unsigned gpio, const char *tag);
+extern void gpio_free(unsigned gpio);
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ return DAVINCI_N_AINTC_IRQ + gpio;
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+ return irq - DAVINCI_N_AINTC_IRQ;
+}
+
+#endif /* __DAVINCI_GPIO_H */
diff --git a/include/asm-arm/arch-davinci/hardware.h b/include/asm-arm/arch-davinci/hardware.h
index 60362d80229e..a2e8969afaca 100644
--- a/include/asm-arm/arch-davinci/hardware.h
+++ b/include/asm-arm/arch-davinci/hardware.h
@@ -11,4 +11,42 @@
#ifndef __ASM_ARCH_HARDWARE_H
#define __ASM_ARCH_HARDWARE_H
+/*
+ * Base register addresses
+ */
+#define DAVINCI_DMA_3PCC_BASE (0x01C00000)
+#define DAVINCI_DMA_3PTC0_BASE (0x01C10000)
+#define DAVINCI_DMA_3PTC1_BASE (0x01C10400)
+#define DAVINCI_I2C_BASE (0x01C21000)
+#define DAVINCI_PWM0_BASE (0x01C22000)
+#define DAVINCI_PWM1_BASE (0x01C22400)
+#define DAVINCI_PWM2_BASE (0x01C22800)
+#define DAVINCI_SYSTEM_MODULE_BASE (0x01C40000)
+#define DAVINCI_PLL_CNTRL0_BASE (0x01C40800)
+#define DAVINCI_PLL_CNTRL1_BASE (0x01C40C00)
+#define DAVINCI_PWR_SLEEP_CNTRL_BASE (0x01C41000)
+#define DAVINCI_SYSTEM_DFT_BASE (0x01C42000)
+#define DAVINCI_IEEE1394_BASE (0x01C60000)
+#define DAVINCI_USB_OTG_BASE (0x01C64000)
+#define DAVINCI_CFC_ATA_BASE (0x01C66000)
+#define DAVINCI_SPI_BASE (0x01C66800)
+#define DAVINCI_GPIO_BASE (0x01C67000)
+#define DAVINCI_UHPI_BASE (0x01C67800)
+#define DAVINCI_VPSS_REGS_BASE (0x01C70000)
+#define DAVINCI_EMAC_CNTRL_REGS_BASE (0x01C80000)
+#define DAVINCI_EMAC_WRAPPER_CNTRL_REGS_BASE (0x01C81000)
+#define DAVINCI_EMAC_WRAPPER_RAM_BASE (0x01C82000)
+#define DAVINCI_MDIO_CNTRL_REGS_BASE (0x01C84000)
+#define DAVINCI_IMCOP_BASE (0x01CC0000)
+#define DAVINCI_ASYNC_EMIF_CNTRL_BASE (0x01E00000)
+#define DAVINCI_VLYNQ_BASE (0x01E01000)
+#define DAVINCI_MCBSP_BASE (0x01E02000)
+#define DAVINCI_MMC_SD_BASE (0x01E10000)
+#define DAVINCI_MS_BASE (0x01E20000)
+#define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE (0x02000000)
+#define DAVINCI_ASYNC_EMIF_DATA_CE1_BASE (0x04000000)
+#define DAVINCI_ASYNC_EMIF_DATA_CE2_BASE (0x06000000)
+#define DAVINCI_ASYNC_EMIF_DATA_CE3_BASE (0x08000000)
+#define DAVINCI_VLYNQ_REMOTE_BASE (0x0C000000)
+
#endif /* __ASM_ARCH_HARDWARE_H */
diff --git a/include/asm-arm/arch-davinci/mux.h b/include/asm-arm/arch-davinci/mux.h
new file mode 100644
index 000000000000..c24b6782804d
--- /dev/null
+++ b/include/asm-arm/arch-davinci/mux.h
@@ -0,0 +1,55 @@
+/*
+ * DaVinci pin multiplexing defines
+ *
+ * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com>
+ *
+ * 2007 (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.
+ */
+#ifndef __ASM_ARCH_MUX_H
+#define __ASM_ARCH_MUX_H
+
+#define DAVINCI_MUX_AEAW0 0
+#define DAVINCI_MUX_AEAW1 1
+#define DAVINCI_MUX_AEAW2 2
+#define DAVINCI_MUX_AEAW3 3
+#define DAVINCI_MUX_AEAW4 4
+#define DAVINCI_MUX_AECS4 10
+#define DAVINCI_MUX_AECS5 11
+#define DAVINCI_MUX_VLYNQWD0 12
+#define DAVINCI_MUX_VLYNQWD1 13
+#define DAVINCI_MUX_VLSCREN 14
+#define DAVINCI_MUX_VLYNQEN 15
+#define DAVINCI_MUX_HDIREN 16
+#define DAVINCI_MUX_ATAEN 17
+#define DAVINCI_MUX_RGB666 22
+#define DAVINCI_MUX_RGB888 23
+#define DAVINCI_MUX_LOEEN 24
+#define DAVINCI_MUX_LFLDEN 25
+#define DAVINCI_MUX_CWEN 26
+#define DAVINCI_MUX_CFLDEN 27
+#define DAVINCI_MUX_HPIEN 29
+#define DAVINCI_MUX_1394EN 30
+#define DAVINCI_MUX_EMACEN 31
+
+#define DAVINCI_MUX_LEVEL2 32
+#define DAVINCI_MUX_UART0 (DAVINCI_MUX_LEVEL2 + 0)
+#define DAVINCI_MUX_UART1 (DAVINCI_MUX_LEVEL2 + 1)
+#define DAVINCI_MUX_UART2 (DAVINCI_MUX_LEVEL2 + 2)
+#define DAVINCI_MUX_U2FLO (DAVINCI_MUX_LEVEL2 + 3)
+#define DAVINCI_MUX_PWM0 (DAVINCI_MUX_LEVEL2 + 4)
+#define DAVINCI_MUX_PWM1 (DAVINCI_MUX_LEVEL2 + 5)
+#define DAVINCI_MUX_PWM2 (DAVINCI_MUX_LEVEL2 + 6)
+#define DAVINCI_MUX_I2C (DAVINCI_MUX_LEVEL2 + 7)
+#define DAVINCI_MUX_SPI (DAVINCI_MUX_LEVEL2 + 8)
+#define DAVINCI_MUX_MSTK (DAVINCI_MUX_LEVEL2 + 9)
+#define DAVINCI_MUX_ASP (DAVINCI_MUX_LEVEL2 + 10)
+#define DAVINCI_MUX_CLK0 (DAVINCI_MUX_LEVEL2 + 16)
+#define DAVINCI_MUX_CLK1 (DAVINCI_MUX_LEVEL2 + 17)
+#define DAVINCI_MUX_TIMIN (DAVINCI_MUX_LEVEL2 + 18)
+
+extern void davinci_mux_peripheral(unsigned int mux, unsigned int enable);
+
+#endif /* __ASM_ARCH_MUX_H */
diff --git a/include/asm-arm/arch-imx/gpio.h b/include/asm-arm/arch-imx/gpio.h
new file mode 100644
index 000000000000..486023263f32
--- /dev/null
+++ b/include/asm-arm/arch-imx/gpio.h
@@ -0,0 +1,102 @@
+#ifndef _IMX_GPIO_H
+
+#include <asm/arch/imx-regs.h>
+
+#define IMX_GPIO_ALLOC_MODE_NORMAL 0
+#define IMX_GPIO_ALLOC_MODE_NO_ALLOC 1
+#define IMX_GPIO_ALLOC_MODE_TRY_ALLOC 2
+#define IMX_GPIO_ALLOC_MODE_ALLOC_ONLY 4
+#define IMX_GPIO_ALLOC_MODE_RELEASE 8
+
+extern int imx_gpio_request(unsigned gpio, const char *label);
+
+extern void imx_gpio_free(unsigned gpio);
+
+extern int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
+ int alloc_mode, const char *label);
+
+extern int imx_gpio_direction_input(unsigned gpio);
+
+extern int imx_gpio_direction_output(unsigned gpio, int value);
+
+extern void __imx_gpio_set_value(unsigned gpio, int value);
+
+static inline int imx_gpio_get_value(unsigned gpio)
+{
+ return SSR(gpio >> GPIO_PORT_SHIFT) & (1 << (gpio & GPIO_PIN_MASK));
+}
+
+static inline void imx_gpio_set_value_inline(unsigned gpio, int value)
+{
+ unsigned long flags;
+
+ raw_local_irq_save(flags);
+ if(value)
+ DR(gpio >> GPIO_PORT_SHIFT) |= (1 << (gpio & GPIO_PIN_MASK));
+ else
+ DR(gpio >> GPIO_PORT_SHIFT) &= ~(1 << (gpio & GPIO_PIN_MASK));
+ raw_local_irq_restore(flags);
+}
+
+static inline void imx_gpio_set_value(unsigned gpio, int value)
+{
+ if(__builtin_constant_p(gpio))
+ imx_gpio_set_value_inline(gpio, value);
+ else
+ __imx_gpio_set_value(gpio, value);
+}
+
+extern int imx_gpio_to_irq(unsigned gpio);
+
+extern int imx_irq_to_gpio(unsigned irq);
+
+/*-------------------------------------------------------------------------*/
+
+/* Wrappers for "new style" GPIO calls. These calls i.MX specific versions
+ * to allow future extension of GPIO logic.
+ */
+
+static inline int gpio_request(unsigned gpio, const char *label)
+{
+ return imx_gpio_request(gpio, label);
+}
+
+static inline void gpio_free(unsigned gpio)
+{
+ imx_gpio_free(gpio);
+}
+
+static inline int gpio_direction_input(unsigned gpio)
+{
+ return imx_gpio_direction_input(gpio);
+}
+
+static inline int gpio_direction_output(unsigned gpio, int value)
+{
+ return imx_gpio_direction_output(gpio, value);
+}
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ return imx_gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ imx_gpio_set_value(gpio, value);
+}
+
+#include <asm-generic/gpio.h> /* cansleep wrappers */
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ return imx_gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+ return imx_irq_to_gpio(irq);
+}
+
+
+#endif
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h
index 30de404c61f5..fb9de2733879 100644
--- a/include/asm-arm/arch-imx/imx-regs.h
+++ b/include/asm-arm/arch-imx/imx-regs.h
@@ -77,6 +77,8 @@
#define SWR(x) __REG2(IMX_GPIO_BASE + 0x3c, ((x) & 3) << 8)
#define PUEN(x) __REG2(IMX_GPIO_BASE + 0x40, ((x) & 3) << 8)
+#define GPIO_PORT_MAX 3
+
#define GPIO_PIN_MASK 0x1f
#define GPIO_PORT_MASK (0x3 << 5)
diff --git a/include/asm-arm/arch-iop13xx/adma.h b/include/asm-arm/arch-iop13xx/adma.h
new file mode 100644
index 000000000000..04006c1c5fd7
--- /dev/null
+++ b/include/asm-arm/arch-iop13xx/adma.h
@@ -0,0 +1,544 @@
+/*
+ * Copyright(c) 2006, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _ADMA_H
+#define _ADMA_H
+#include <linux/types.h>
+#include <linux/io.h>
+#include <asm/hardware.h>
+#include <asm/hardware/iop_adma.h>
+
+#define ADMA_ACCR(chan) (chan->mmr_base + 0x0)
+#define ADMA_ACSR(chan) (chan->mmr_base + 0x4)
+#define ADMA_ADAR(chan) (chan->mmr_base + 0x8)
+#define ADMA_IIPCR(chan) (chan->mmr_base + 0x18)
+#define ADMA_IIPAR(chan) (chan->mmr_base + 0x1c)
+#define ADMA_IIPUAR(chan) (chan->mmr_base + 0x20)
+#define ADMA_ANDAR(chan) (chan->mmr_base + 0x24)
+#define ADMA_ADCR(chan) (chan->mmr_base + 0x28)
+#define ADMA_CARMD(chan) (chan->mmr_base + 0x2c)
+#define ADMA_ABCR(chan) (chan->mmr_base + 0x30)
+#define ADMA_DLADR(chan) (chan->mmr_base + 0x34)
+#define ADMA_DUADR(chan) (chan->mmr_base + 0x38)
+#define ADMA_SLAR(src, chan) (chan->mmr_base + (0x3c + (src << 3)))
+#define ADMA_SUAR(src, chan) (chan->mmr_base + (0x40 + (src << 3)))
+
+struct iop13xx_adma_src {
+ u32 src_addr;
+ union {
+ u32 upper_src_addr;
+ struct {
+ unsigned int pq_upper_src_addr:24;
+ unsigned int pq_dmlt:8;
+ };
+ };
+};
+
+struct iop13xx_adma_desc_ctrl {
+ unsigned int int_en:1;
+ unsigned int xfer_dir:2;
+ unsigned int src_select:4;
+ unsigned int zero_result:1;
+ unsigned int block_fill_en:1;
+ unsigned int crc_gen_en:1;
+ unsigned int crc_xfer_dis:1;
+ unsigned int crc_seed_fetch_dis:1;
+ unsigned int status_write_back_en:1;
+ unsigned int endian_swap_en:1;
+ unsigned int reserved0:2;
+ unsigned int pq_update_xfer_en:1;
+ unsigned int dual_xor_en:1;
+ unsigned int pq_xfer_en:1;
+ unsigned int p_xfer_dis:1;
+ unsigned int reserved1:10;
+ unsigned int relax_order_en:1;
+ unsigned int no_snoop_en:1;
+};
+
+struct iop13xx_adma_byte_count {
+ unsigned int byte_count:24;
+ unsigned int host_if:3;
+ unsigned int reserved:2;
+ unsigned int zero_result_err_q:1;
+ unsigned int zero_result_err:1;
+ unsigned int tx_complete:1;
+};
+
+struct iop13xx_adma_desc_hw {
+ u32 next_desc;
+ union {
+ u32 desc_ctrl;
+ struct iop13xx_adma_desc_ctrl desc_ctrl_field;
+ };
+ union {
+ u32 crc_addr;
+ u32 block_fill_data;
+ u32 q_dest_addr;
+ };
+ union {
+ u32 byte_count;
+ struct iop13xx_adma_byte_count byte_count_field;
+ };
+ union {
+ u32 dest_addr;
+ u32 p_dest_addr;
+ };
+ union {
+ u32 upper_dest_addr;
+ u32 pq_upper_dest_addr;
+ };
+ struct iop13xx_adma_src src[1];
+};
+
+struct iop13xx_adma_desc_dual_xor {
+ u32 next_desc;
+ u32 desc_ctrl;
+ u32 reserved;
+ u32 byte_count;
+ u32 h_dest_addr;
+ u32 h_upper_dest_addr;
+ u32 src0_addr;
+ u32 upper_src0_addr;
+ u32 src1_addr;
+ u32 upper_src1_addr;
+ u32 h_src_addr;
+ u32 h_upper_src_addr;
+ u32 d_src_addr;
+ u32 d_upper_src_addr;
+ u32 d_dest_addr;
+ u32 d_upper_dest_addr;
+};
+
+struct iop13xx_adma_desc_pq_update {
+ u32 next_desc;
+ u32 desc_ctrl;
+ u32 reserved;
+ u32 byte_count;
+ u32 p_dest_addr;
+ u32 p_upper_dest_addr;
+ u32 src0_addr;
+ u32 upper_src0_addr;
+ u32 src1_addr;
+ u32 upper_src1_addr;
+ u32 p_src_addr;
+ u32 p_upper_src_addr;
+ u32 q_src_addr;
+ struct {
+ unsigned int q_upper_src_addr:24;
+ unsigned int q_dmlt:8;
+ };
+ u32 q_dest_addr;
+ u32 q_upper_dest_addr;
+};
+
+static inline int iop_adma_get_max_xor(void)
+{
+ return 16;
+}
+
+static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan)
+{
+ return __raw_readl(ADMA_ADAR(chan));
+}
+
+static inline void iop_chan_set_next_descriptor(struct iop_adma_chan *chan,
+ u32 next_desc_addr)
+{
+ __raw_writel(next_desc_addr, ADMA_ANDAR(chan));
+}
+
+#define ADMA_STATUS_BUSY (1 << 13)
+
+static inline char iop_chan_is_busy(struct iop_adma_chan *chan)
+{
+ if (__raw_readl(ADMA_ACSR(chan)) &
+ ADMA_STATUS_BUSY)
+ return 1;
+ else
+ return 0;
+}
+
+static inline int
+iop_chan_get_desc_align(struct iop_adma_chan *chan, int num_slots)
+{
+ return 1;
+}
+#define iop_desc_is_aligned(x, y) 1
+
+static inline int
+iop_chan_memcpy_slot_count(size_t len, int *slots_per_op)
+{
+ *slots_per_op = 1;
+ return 1;
+}
+
+#define iop_chan_interrupt_slot_count(s, c) iop_chan_memcpy_slot_count(0, s)
+
+static inline int
+iop_chan_memset_slot_count(size_t len, int *slots_per_op)
+{
+ *slots_per_op = 1;
+ return 1;
+}
+
+static inline int
+iop_chan_xor_slot_count(size_t len, int src_cnt, int *slots_per_op)
+{
+ int num_slots;
+ /* slots_to_find = 1 for basic descriptor + 1 per 4 sources above 1
+ * (1 source => 8 bytes) (1 slot => 32 bytes)
+ */
+ num_slots = 1 + (((src_cnt - 1) << 3) >> 5);
+ if (((src_cnt - 1) << 3) & 0x1f)
+ num_slots++;
+
+ *slots_per_op = num_slots;
+
+ return num_slots;
+}
+
+#define ADMA_MAX_BYTE_COUNT (16 * 1024 * 1024)
+#define IOP_ADMA_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT
+#define IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT
+#define IOP_ADMA_XOR_MAX_BYTE_COUNT ADMA_MAX_BYTE_COUNT
+#define iop_chan_zero_sum_slot_count(l, s, o) iop_chan_xor_slot_count(l, s, o)
+
+static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ return hw_desc->dest_addr;
+}
+
+static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ return hw_desc->byte_count_field.byte_count;
+}
+
+static inline u32 iop_desc_get_src_addr(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan,
+ int src_idx)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ return hw_desc->src[src_idx].src_addr;
+}
+
+static inline u32 iop_desc_get_src_count(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ return hw_desc->desc_ctrl_field.src_select + 1;
+}
+
+static inline void
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ union {
+ u32 value;
+ struct iop13xx_adma_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+ hw_desc->crc_addr = 0;
+}
+
+static inline void
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ union {
+ u32 value;
+ struct iop13xx_adma_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
+ u_desc_ctrl.field.block_fill_en = 1;
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+ hw_desc->crc_addr = 0;
+}
+
+/* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
+static inline void
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ union {
+ u32 value;
+ struct iop13xx_adma_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ u_desc_ctrl.field.src_select = src_cnt - 1;
+ u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+ hw_desc->crc_addr = 0;
+
+}
+#define iop_desc_init_null_xor(d, s, i) iop_desc_init_xor(d, s, i)
+
+/* to do: support buffers larger than ADMA_MAX_BYTE_COUNT */
+static inline int
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ union {
+ u32 value;
+ struct iop13xx_adma_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ u_desc_ctrl.field.src_select = src_cnt - 1;
+ u_desc_ctrl.field.xfer_dir = 3; /* local to internal bus */
+ u_desc_ctrl.field.zero_result = 1;
+ u_desc_ctrl.field.status_write_back_en = 1;
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+ hw_desc->crc_addr = 0;
+
+ return 1;
+}
+
+static inline void iop_desc_set_byte_count(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan,
+ u32 byte_count)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ hw_desc->byte_count = byte_count;
+}
+
+static inline void
+iop_desc_set_zero_sum_byte_count(struct iop_adma_desc_slot *desc, u32 len)
+{
+ int slots_per_op = desc->slots_per_op;
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc, *iter;
+ int i = 0;
+
+ if (len <= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT) {
+ hw_desc->byte_count = len;
+ } else {
+ do {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ iter->byte_count = IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT;
+ len -= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT;
+ i += slots_per_op;
+ } while (len > IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT);
+
+ if (len) {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ iter->byte_count = len;
+ }
+ }
+}
+
+
+static inline void iop_desc_set_dest_addr(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan,
+ dma_addr_t addr)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ hw_desc->dest_addr = addr;
+ hw_desc->upper_dest_addr = 0;
+}
+
+static inline void iop_desc_set_memcpy_src_addr(struct iop_adma_desc_slot *desc,
+ dma_addr_t addr)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ hw_desc->src[0].src_addr = addr;
+ hw_desc->src[0].upper_src_addr = 0;
+}
+
+static inline void iop_desc_set_xor_src_addr(struct iop_adma_desc_slot *desc,
+ int src_idx, dma_addr_t addr)
+{
+ int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op;
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc, *iter;
+ int i = 0;
+
+ do {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ iter->src[src_idx].src_addr = addr;
+ iter->src[src_idx].upper_src_addr = 0;
+ slot_cnt -= slots_per_op;
+ if (slot_cnt) {
+ i += slots_per_op;
+ addr += IOP_ADMA_XOR_MAX_BYTE_COUNT;
+ }
+ } while (slot_cnt);
+}
+
+static inline void
+iop_desc_init_interrupt(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan)
+{
+ iop_desc_init_memcpy(desc, 1);
+ iop_desc_set_byte_count(desc, chan, 0);
+ iop_desc_set_dest_addr(desc, chan, 0);
+ iop_desc_set_memcpy_src_addr(desc, 0);
+}
+
+#define iop_desc_set_zero_sum_src_addr iop_desc_set_xor_src_addr
+
+static inline void iop_desc_set_next_desc(struct iop_adma_desc_slot *desc,
+ u32 next_desc_addr)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ BUG_ON(hw_desc->next_desc);
+ hw_desc->next_desc = next_desc_addr;
+}
+
+static inline u32 iop_desc_get_next_desc(struct iop_adma_desc_slot *desc)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ return hw_desc->next_desc;
+}
+
+static inline void iop_desc_clear_next_desc(struct iop_adma_desc_slot *desc)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ hw_desc->next_desc = 0;
+}
+
+static inline void iop_desc_set_block_fill_val(struct iop_adma_desc_slot *desc,
+ u32 val)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ hw_desc->block_fill_data = val;
+}
+
+static inline int iop_desc_get_zero_result(struct iop_adma_desc_slot *desc)
+{
+ struct iop13xx_adma_desc_hw *hw_desc = desc->hw_desc;
+ struct iop13xx_adma_desc_ctrl desc_ctrl = hw_desc->desc_ctrl_field;
+ struct iop13xx_adma_byte_count byte_count = hw_desc->byte_count_field;
+
+ BUG_ON(!(byte_count.tx_complete && desc_ctrl.zero_result));
+
+ if (desc_ctrl.pq_xfer_en)
+ return byte_count.zero_result_err_q;
+ else
+ return byte_count.zero_result_err;
+}
+
+static inline void iop_chan_append(struct iop_adma_chan *chan)
+{
+ u32 adma_accr;
+
+ adma_accr = __raw_readl(ADMA_ACCR(chan));
+ adma_accr |= 0x2;
+ __raw_writel(adma_accr, ADMA_ACCR(chan));
+}
+
+static inline void iop_chan_idle(int busy, struct iop_adma_chan *chan)
+{
+ do { } while (0);
+}
+
+static inline u32 iop_chan_get_status(struct iop_adma_chan *chan)
+{
+ return __raw_readl(ADMA_ACSR(chan));
+}
+
+static inline void iop_chan_disable(struct iop_adma_chan *chan)
+{
+ u32 adma_chan_ctrl = __raw_readl(ADMA_ACCR(chan));
+ adma_chan_ctrl &= ~0x1;
+ __raw_writel(adma_chan_ctrl, ADMA_ACCR(chan));
+}
+
+static inline void iop_chan_enable(struct iop_adma_chan *chan)
+{
+ u32 adma_chan_ctrl;
+
+ adma_chan_ctrl = __raw_readl(ADMA_ACCR(chan));
+ adma_chan_ctrl |= 0x1;
+ __raw_writel(adma_chan_ctrl, ADMA_ACCR(chan));
+}
+
+static inline void iop_adma_device_clear_eot_status(struct iop_adma_chan *chan)
+{
+ u32 status = __raw_readl(ADMA_ACSR(chan));
+ status &= (1 << 12);
+ __raw_writel(status, ADMA_ACSR(chan));
+}
+
+static inline void iop_adma_device_clear_eoc_status(struct iop_adma_chan *chan)
+{
+ u32 status = __raw_readl(ADMA_ACSR(chan));
+ status &= (1 << 11);
+ __raw_writel(status, ADMA_ACSR(chan));
+}
+
+static inline void iop_adma_device_clear_err_status(struct iop_adma_chan *chan)
+{
+ u32 status = __raw_readl(ADMA_ACSR(chan));
+ status &= (1 << 9) | (1 << 5) | (1 << 4) | (1 << 3);
+ __raw_writel(status, ADMA_ACSR(chan));
+}
+
+static inline int
+iop_is_err_int_parity(unsigned long status, struct iop_adma_chan *chan)
+{
+ return test_bit(9, &status);
+}
+
+static inline int
+iop_is_err_mcu_abort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return test_bit(5, &status);
+}
+
+static inline int
+iop_is_err_int_tabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return test_bit(4, &status);
+}
+
+static inline int
+iop_is_err_int_mabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return test_bit(3, &status);
+}
+
+static inline int
+iop_is_err_pci_tabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return 0;
+}
+
+static inline int
+iop_is_err_pci_mabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return 0;
+}
+
+static inline int
+iop_is_err_split_tx(unsigned long status, struct iop_adma_chan *chan)
+{
+ return 0;
+}
+
+#endif /* _ADMA_H */
diff --git a/include/asm-arm/arch-iop13xx/iop13xx.h b/include/asm-arm/arch-iop13xx/iop13xx.h
index e6736c3d1f7f..52b7fab7ef60 100644
--- a/include/asm-arm/arch-iop13xx/iop13xx.h
+++ b/include/asm-arm/arch-iop13xx/iop13xx.h
@@ -19,6 +19,39 @@ static inline int iop13xx_cpu_id(void)
return id;
}
+/* WDTCR CP6 R7 Page 9 */
+static inline u32 read_wdtcr(void)
+{
+ u32 val;
+ asm volatile("mrc p6, 0, %0, c7, c9, 0":"=r" (val));
+ return val;
+}
+static inline void write_wdtcr(u32 val)
+{
+ asm volatile("mcr p6, 0, %0, c7, c9, 0"::"r" (val));
+}
+
+/* WDTSR CP6 R8 Page 9 */
+static inline u32 read_wdtsr(void)
+{
+ u32 val;
+ asm volatile("mrc p6, 0, %0, c8, c9, 0":"=r" (val));
+ return val;
+}
+static inline void write_wdtsr(u32 val)
+{
+ asm volatile("mcr p6, 0, %0, c8, c9, 0"::"r" (val));
+}
+
+/* RCSR - Reset Cause Status Register */
+static inline u32 read_rcsr(void)
+{
+ u32 val;
+ asm volatile("mrc p6, 0, %0, c0, c1, 0":"=r" (val));
+ return val;
+}
+
+extern unsigned long get_iop_tick_rate(void);
#endif
/*
@@ -166,12 +199,22 @@ static inline int iop13xx_cpu_id(void)
#define IOP13XX_INIT_I2C_1 (1 << 1)
#define IOP13XX_INIT_I2C_2 (1 << 2)
-#define IQ81340_NUM_UART 2
-#define IQ81340_NUM_I2C 3
-#define IQ81340_NUM_PHYS_MAP_FLASH 1
-#define IQ81340_MAX_PLAT_DEVICES (IQ81340_NUM_UART +\
- IQ81340_NUM_I2C +\
- IQ81340_NUM_PHYS_MAP_FLASH)
+/* ADMA selection flags */
+/* INIT_ADMA_DEFAULT = Rely on CONFIG_IOP13XX_ADMA* */
+#define IOP13XX_INIT_ADMA_DEFAULT (0)
+#define IOP13XX_INIT_ADMA_0 (1 << 0)
+#define IOP13XX_INIT_ADMA_1 (1 << 1)
+#define IOP13XX_INIT_ADMA_2 (1 << 2)
+
+/* Platform devices */
+#define IQ81340_NUM_UART 2
+#define IQ81340_NUM_I2C 3
+#define IQ81340_NUM_PHYS_MAP_FLASH 1
+#define IQ81340_NUM_ADMA 3
+#define IQ81340_MAX_PLAT_DEVICES (IQ81340_NUM_UART + \
+ IQ81340_NUM_I2C + \
+ IQ81340_NUM_PHYS_MAP_FLASH + \
+ IQ81340_NUM_ADMA)
/*========================== PMMR offsets for key registers ============*/
#define IOP13XX_ATU0_PMMR_OFFSET 0x00048000
@@ -444,22 +487,6 @@ static inline int iop13xx_cpu_id(void)
/*==============================ADMA UNITS===============================*/
#define IOP13XX_ADMA_PHYS_BASE(chan) IOP13XX_REG_ADDR32_PHYS((chan << 9))
#define IOP13XX_ADMA_UPPER_PA(chan) (IOP13XX_ADMA_PHYS_BASE(chan) + 0xc0)
-#define IOP13XX_ADMA_OFFSET(chan, ofs) IOP13XX_REG_ADDR32((chan << 9) + (ofs))
-
-#define IOP13XX_ADMA_ACCR(chan) IOP13XX_ADMA_OFFSET(chan, 0x0)
-#define IOP13XX_ADMA_ACSR(chan) IOP13XX_ADMA_OFFSET(chan, 0x4)
-#define IOP13XX_ADMA_ADAR(chan) IOP13XX_ADMA_OFFSET(chan, 0x8)
-#define IOP13XX_ADMA_IIPCR(chan) IOP13XX_ADMA_OFFSET(chan, 0x18)
-#define IOP13XX_ADMA_IIPAR(chan) IOP13XX_ADMA_OFFSET(chan, 0x1c)
-#define IOP13XX_ADMA_IIPUAR(chan) IOP13XX_ADMA_OFFSET(chan, 0x20)
-#define IOP13XX_ADMA_ANDAR(chan) IOP13XX_ADMA_OFFSET(chan, 0x24)
-#define IOP13XX_ADMA_ADCR(chan) IOP13XX_ADMA_OFFSET(chan, 0x28)
-#define IOP13XX_ADMA_CARMD(chan) IOP13XX_ADMA_OFFSET(chan, 0x2c)
-#define IOP13XX_ADMA_ABCR(chan) IOP13XX_ADMA_OFFSET(chan, 0x30)
-#define IOP13XX_ADMA_DLADR(chan) IOP13XX_ADMA_OFFSET(chan, 0x34)
-#define IOP13XX_ADMA_DUADR(chan) IOP13XX_ADMA_OFFSET(chan, 0x38)
-#define IOP13XX_ADMA_SLAR(src, chan) IOP13XX_ADMA_OFFSET(chan, 0x3c + (src <<3))
-#define IOP13XX_ADMA_SUAR(src, chan) IOP13XX_ADMA_OFFSET(chan, 0x40 + (src <<3))
/*==============================XSI BRIDGE===============================*/
#define IOP13XX_XBG_BECSR IOP13XX_REG_ADDR32(0x178c)
@@ -486,4 +513,14 @@ static inline int iop13xx_cpu_id(void)
#define IOP13XX_PBI_LR1 IOP13XX_PBI_OFFSET(0x14)
#define IOP13XX_PROCESSOR_FREQ IOP13XX_REG_ADDR32(0x2180)
+
+/* Watchdog timer definitions */
+#define IOP_WDTCR_EN_ARM 0x1e1e1e1e
+#define IOP_WDTCR_EN 0xe1e1e1e1
+#define IOP_WDTCR_DIS_ARM 0x1f1f1f1f
+#define IOP_WDTCR_DIS 0xf1f1f1f1
+#define IOP_RCSR_WDT (1 << 5) /* reset caused by watchdog timer */
+#define IOP13XX_WDTSR_WRITE_EN (1 << 31) /* used to speed up reset requests */
+#define IOP13XX_WDTCR_IB_RESET (1 << 0)
+
#endif /* _IOP13XX_HW_H_ */
diff --git a/include/asm-arm/arch-iop13xx/system.h b/include/asm-arm/arch-iop13xx/system.h
index 127827058e1f..8575af8db78c 100644
--- a/include/asm-arm/arch-iop13xx/system.h
+++ b/include/asm-arm/arch-iop13xx/system.h
@@ -13,43 +13,13 @@ static inline void arch_idle(void)
cpu_do_idle();
}
-/* WDTCR CP6 R7 Page 9 */
-static inline u32 read_wdtcr(void)
-{
- u32 val;
- asm volatile("mrc p6, 0, %0, c7, c9, 0":"=r" (val));
- return val;
-}
-static inline void write_wdtcr(u32 val)
-{
- asm volatile("mcr p6, 0, %0, c7, c9, 0"::"r" (val));
-}
-
-/* WDTSR CP6 R8 Page 9 */
-static inline u32 read_wdtsr(void)
-{
- u32 val;
- asm volatile("mrc p6, 0, %0, c8, c9, 0":"=r" (val));
- return val;
-}
-static inline void write_wdtsr(u32 val)
-{
- asm volatile("mcr p6, 0, %0, c8, c9, 0"::"r" (val));
-}
-
-#define IOP13XX_WDTCR_EN_ARM 0x1e1e1e1e
-#define IOP13XX_WDTCR_EN 0xe1e1e1e1
-#define IOP13XX_WDTCR_DIS_ARM 0x1f1f1f1f
-#define IOP13XX_WDTCR_DIS 0xf1f1f1f1
-#define IOP13XX_WDTSR_WRITE_EN (1 << 31)
-#define IOP13XX_WDTCR_IB_RESET (1 << 0)
static inline void arch_reset(char mode)
{
/*
* Reset the internal bus (warning both cores are reset)
*/
- write_wdtcr(IOP13XX_WDTCR_EN_ARM);
- write_wdtcr(IOP13XX_WDTCR_EN);
+ write_wdtcr(IOP_WDTCR_EN_ARM);
+ write_wdtcr(IOP_WDTCR_EN);
write_wdtsr(IOP13XX_WDTSR_WRITE_EN | IOP13XX_WDTCR_IB_RESET);
write_wdtcr(0x1000);
diff --git a/include/asm-arm/arch-iop13xx/uncompress.h b/include/asm-arm/arch-iop13xx/uncompress.h
index b9525d59b7ad..dd9c2934190e 100644
--- a/include/asm-arm/arch-iop13xx/uncompress.h
+++ b/include/asm-arm/arch-iop13xx/uncompress.h
@@ -1,7 +1,6 @@
#include <asm/types.h>
#include <linux/serial_reg.h>
#include <asm/hardware.h>
-#include <asm/processor.h>
#define UART_BASE ((volatile u32 *)IOP13XX_UART1_PHYS)
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
@@ -9,7 +8,7 @@
static inline void putc(char c)
{
while ((UART_BASE[UART_LSR] & TX_DONE) != TX_DONE)
- cpu_relax();
+ barrier();
UART_BASE[UART_TX] = c;
}
diff --git a/include/asm-arm/arch-iop32x/adma.h b/include/asm-arm/arch-iop32x/adma.h
new file mode 100644
index 000000000000..5ed92037dd10
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/adma.h
@@ -0,0 +1,5 @@
+#ifndef IOP32X_ADMA_H
+#define IOP32X_ADMA_H
+#include <asm/hardware/iop3xx-adma.h>
+#endif
+
diff --git a/include/asm-arm/arch-iop32x/uncompress.h b/include/asm-arm/arch-iop32x/uncompress.h
index e64f52bf2bce..070f15818fe7 100644
--- a/include/asm-arm/arch-iop32x/uncompress.h
+++ b/include/asm-arm/arch-iop32x/uncompress.h
@@ -26,7 +26,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
{
if (machine_is_iq80321())
uart_base = (volatile u8 *)IQ80321_UART;
- else if (machine_is_iq31244())
+ else if (machine_is_iq31244() || machine_is_em7210())
uart_base = (volatile u8 *)IQ31244_UART;
else
uart_base = (volatile u8 *)0xfe800000;
diff --git a/include/asm-arm/arch-iop33x/adma.h b/include/asm-arm/arch-iop33x/adma.h
new file mode 100644
index 000000000000..4b92f795f90e
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/adma.h
@@ -0,0 +1,5 @@
+#ifndef IOP33X_ADMA_H
+#define IOP33X_ADMA_H
+#include <asm/hardware/iop3xx-adma.h>
+#endif
+
diff --git a/include/asm-arm/arch-ixp4xx/ixdp425.h b/include/asm-arm/arch-ixp4xx/ixdp425.h
index 3d3820d7ba09..e0791af3bfea 100644
--- a/include/asm-arm/arch-ixp4xx/ixdp425.h
+++ b/include/asm-arm/arch-ixp4xx/ixdp425.h
@@ -32,4 +32,8 @@
#define IXDP425_PCI_INTC_PIN 9
#define IXDP425_PCI_INTD_PIN 8
+/* NAND Flash pins */
+#define IXDP425_NAND_NCE_PIN 12
+#define IXDP425_NAND_CMD_BYTE 0x01
+#define IXDP425_NAND_ADDR_BYTE 0x02
diff --git a/include/asm-arm/arch-ixp4xx/udc.h b/include/asm-arm/arch-ixp4xx/udc.h
index 79b850a3be47..dbdec36ff0d1 100644
--- a/include/asm-arm/arch-ixp4xx/udc.h
+++ b/include/asm-arm/arch-ixp4xx/udc.h
@@ -6,25 +6,3 @@
extern void ixp4xx_set_udc_info(struct pxa2xx_udc_mach_info *info);
-static inline int udc_gpio_to_irq(unsigned gpio)
-{
- return 0;
-}
-
-static inline void udc_gpio_init_vbus(unsigned gpio)
-{
-}
-
-static inline void udc_gpio_init_pullup(unsigned gpio)
-{
-}
-
-static inline int udc_gpio_get(unsigned gpio)
-{
- return 0;
-}
-
-static inline void udc_gpio_set(unsigned gpio, int is_on)
-{
-}
-
diff --git a/include/asm-arm/arch-ixp4xx/uncompress.h b/include/asm-arm/arch-ixp4xx/uncompress.h
index 09ae6c91be60..f7a35b78823f 100644
--- a/include/asm-arm/arch-ixp4xx/uncompress.h
+++ b/include/asm-arm/arch-ixp4xx/uncompress.h
@@ -38,9 +38,10 @@ static void flush(void)
static __inline__ void __arch_decomp_setup(unsigned long arch_id)
{
/*
- * Coyote and gtwx5715 only have UART2 connected
+ * Some boards are using UART2 as console
*/
- if (machine_is_adi_coyote() || machine_is_gtwx5715())
+ if (machine_is_adi_coyote() || machine_is_gtwx5715() ||
+ machine_is_gateway7001() || machine_is_wg302v2())
uart_base = (volatile u32*) IXP4XX_UART2_BASE_PHYS;
else
uart_base = (volatile u32*) IXP4XX_UART1_BASE_PHYS;
diff --git a/include/asm-arm/arch-ks8695/gpio.h b/include/asm-arm/arch-ks8695/gpio.h
new file mode 100644
index 000000000000..65ceea28607b
--- /dev/null
+++ b/include/asm-arm/arch-ks8695/gpio.h
@@ -0,0 +1,79 @@
+/*
+ * include/asm-arm/arch-ks8695/gpio.h
+ *
+ * Copyright (C) 2006 Andrew Victor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_GPIO_H_
+#define __ASM_ARCH_GPIO_H_
+
+#define KS8695_GPIO_0 0
+#define KS8695_GPIO_1 1
+#define KS8695_GPIO_2 2
+#define KS8695_GPIO_3 3
+#define KS8695_GPIO_4 4
+#define KS8695_GPIO_5 5
+#define KS8695_GPIO_6 6
+#define KS8695_GPIO_7 7
+#define KS8695_GPIO_8 8
+#define KS8695_GPIO_9 9
+#define KS8695_GPIO_10 10
+#define KS8695_GPIO_11 11
+#define KS8695_GPIO_12 12
+#define KS8695_GPIO_13 13
+#define KS8695_GPIO_14 14
+#define KS8695_GPIO_15 15
+
+
+/*
+ * Configure GPIO pin as external interrupt source.
+ */
+int __init_or_module ks8695_gpio_interrupt(unsigned int pin, unsigned int type);
+
+/*
+ * Configure the GPIO line as an input.
+ */
+int __init_or_module gpio_direction_input(unsigned int pin);
+
+/*
+ * Configure the GPIO line as an output, with default state.
+ */
+int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state);
+
+/*
+ * Set the state of an output GPIO line.
+ */
+void gpio_set_value(unsigned int pin, unsigned int state);
+
+/*
+ * Read the state of a GPIO line.
+ */
+int gpio_get_value(unsigned int pin);
+
+/*
+ * Map GPIO line to IRQ number.
+ */
+int gpio_to_irq(unsigned int pin);
+
+/*
+ * Map IRQ number to GPIO line.
+ */
+int irq_to_gpio(unsigned int irq);
+
+
+#include <asm-generic/gpio.h>
+
+static inline int gpio_request(unsigned int pin, const char *label)
+{
+ return 0;
+}
+
+static inline void gpio_free(unsigned int pin)
+{
+}
+
+#endif
diff --git a/include/asm-arm/arch-mxc/board-mx31ads.h b/include/asm-arm/arch-mxc/board-mx31ads.h
new file mode 100644
index 000000000000..be29b83ad4ae
--- /dev/null
+++ b/include/asm-arm/arch-mxc/board-mx31ads.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+
+/*!
+ * @name PBC Controller parameters
+ */
+/*! @{ */
+/*!
+ * Base address of PBC controller
+ */
+#define PBC_BASE_ADDRESS IO_ADDRESS(CS4_BASE_ADDR)
+/* Offsets for the PBC Controller register */
+/*!
+ * PBC Board status register offset
+ */
+#define PBC_BSTAT 0x000002
+/*!
+ * PBC Board control register 1 set address.
+ */
+#define PBC_BCTRL1_SET 0x000004
+/*!
+ * PBC Board control register 1 clear address.
+ */
+#define PBC_BCTRL1_CLEAR 0x000006
+/*!
+ * PBC Board control register 2 set address.
+ */
+#define PBC_BCTRL2_SET 0x000008
+/*!
+ * PBC Board control register 2 clear address.
+ */
+#define PBC_BCTRL2_CLEAR 0x00000A
+/*!
+ * PBC Board control register 3 set address.
+ */
+#define PBC_BCTRL3_SET 0x00000C
+/*!
+ * PBC Board control register 3 clear address.
+ */
+#define PBC_BCTRL3_CLEAR 0x00000E
+/*!
+ * PBC Board control register 4 set address.
+ */
+#define PBC_BCTRL4_SET 0x000010
+/*!
+ * PBC Board control register 4 clear address.
+ */
+#define PBC_BCTRL4_CLEAR 0x000012
+/*!
+ * PBC Board status register 1.
+ */
+#define PBC_BSTAT1 0x000014
+/*!
+ * PBC Board interrupt status register.
+ */
+#define PBC_INTSTATUS 0x000016
+/*!
+ * PBC Board interrupt current status register.
+ */
+#define PBC_INTCURR_STATUS 0x000018
+/*!
+ * PBC Interrupt mask register set address.
+ */
+#define PBC_INTMASK_SET 0x00001A
+/*!
+ * PBC Interrupt mask register clear address.
+ */
+#define PBC_INTMASK_CLEAR 0x00001C
+
+/*!
+ * External UART A.
+ */
+#define PBC_SC16C652_UARTA 0x010000
+/*!
+ * External UART B.
+ */
+#define PBC_SC16C652_UARTB 0x010010
+/*!
+ * Ethernet Controller IO base address.
+ */
+#define PBC_CS8900A_IOBASE 0x020000
+/*!
+ * Ethernet Controller Memory base address.
+ */
+#define PBC_CS8900A_MEMBASE 0x021000
+/*!
+ * Ethernet Controller DMA base address.
+ */
+#define PBC_CS8900A_DMABASE 0x022000
+/*!
+ * External chip select 0.
+ */
+#define PBC_XCS0 0x040000
+/*!
+ * LCD Display enable.
+ */
+#define PBC_LCD_EN_B 0x060000
+/*!
+ * Code test debug enable.
+ */
+#define PBC_CODE_B 0x070000
+/*!
+ * PSRAM memory select.
+ */
+#define PBC_PSRAM_B 0x5000000
+
+#define PBC_INTSTATUS_REG (PBC_INTSTATUS + PBC_BASE_ADDRESS)
+#define PBC_INTCURR_STATUS_REG (PBC_INTCURR_STATUS + PBC_BASE_ADDRESS)
+#define PBC_INTMASK_SET_REG (PBC_INTMASK_SET + PBC_BASE_ADDRESS)
+#define PBC_INTMASK_CLEAR_REG (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
+#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
+
+#define EXPIO_INT_LOW_BAT (MXC_EXP_IO_BASE + 0)
+#define EXPIO_INT_PB_IRQ (MXC_EXP_IO_BASE + 1)
+#define EXPIO_INT_OTG_FS_OVR (MXC_EXP_IO_BASE + 2)
+#define EXPIO_INT_FSH_OVR (MXC_EXP_IO_BASE + 3)
+#define EXPIO_INT_RES4 (MXC_EXP_IO_BASE + 4)
+#define EXPIO_INT_RES5 (MXC_EXP_IO_BASE + 5)
+#define EXPIO_INT_RES6 (MXC_EXP_IO_BASE + 6)
+#define EXPIO_INT_RES7 (MXC_EXP_IO_BASE + 7)
+#define EXPIO_INT_ENET_INT (MXC_EXP_IO_BASE + 8)
+#define EXPIO_INT_OTG_FS_INT (MXC_EXP_IO_BASE + 9)
+#define EXPIO_INT_XUART_INTA (MXC_EXP_IO_BASE + 10)
+#define EXPIO_INT_XUART_INTB (MXC_EXP_IO_BASE + 11)
+#define EXPIO_INT_SYNTH_IRQ (MXC_EXP_IO_BASE + 12)
+#define EXPIO_INT_CE_INT1 (MXC_EXP_IO_BASE + 13)
+#define EXPIO_INT_CE_INT2 (MXC_EXP_IO_BASE + 14)
+#define EXPIO_INT_RES15 (MXC_EXP_IO_BASE + 15)
+
+#define MXC_MAX_EXP_IO_LINES 16
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
diff --git a/include/asm-arm/arch-mxc/common.h b/include/asm-arm/arch-mxc/common.h
new file mode 100644
index 000000000000..23b4350edbd6
--- /dev/null
+++ b/include/asm-arm/arch-mxc/common.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_COMMON_H__
+#define __ASM_ARCH_MXC_COMMON_H__
+
+struct sys_timer;
+
+extern void mxc_map_io(void);
+extern void mxc_init_irq(void);
+extern struct sys_timer mxc_timer;
+
+#endif
diff --git a/include/asm-arm/arch-mxc/dma.h b/include/asm-arm/arch-mxc/dma.h
new file mode 100644
index 000000000000..65e639d51d2b
--- /dev/null
+++ b/include/asm-arm/arch-mxc/dma.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_DMA_H__
+#define __ASM_ARCH_MXC_DMA_H__
+
+/*!
+ * @file dma.h
+ * @brief This file contains Unified DMA API for all MXC platforms.
+ * The API is platform independent.
+ *
+ * @ingroup SDMA
+ */
+#endif
diff --git a/include/asm-arm/arch-mxc/entry-macro.S b/include/asm-arm/arch-mxc/entry-macro.S
new file mode 100644
index 000000000000..b542433afb1b
--- /dev/null
+++ b/include/asm-arm/arch-mxc/entry-macro.S
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+ @ this macro disables fast irq (not implemented)
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_preamble, base, tmp
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+ @ this macro checks which interrupt occured
+ @ and returns its number in irqnr
+ @ and returns if an interrupt occured in irqstat
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \base, =AVIC_IO_ADDRESS(AVIC_BASE_ADDR)
+ @ Load offset & priority of the highest priority
+ @ interrupt pending from AVIC_NIVECSR
+ ldr \irqstat, [\base, #0x40]
+ @ Shift to get the decoded IRQ number, using ASR so
+ @ 'no interrupt pending' becomes 0xffffffff
+ mov \irqnr, \irqstat, asr #16
+ @ set zero flag if IRQ + 1 == 0
+ adds \tmp, \irqnr, #1
+ .endm
+
+ @ irq priority table (not used)
+ .macro irq_prio_table
+ .endm
diff --git a/include/asm-arm/arch-mxc/hardware.h b/include/asm-arm/arch-mxc/hardware.h
new file mode 100644
index 000000000000..3c09b92fef0d
--- /dev/null
+++ b/include/asm-arm/arch-mxc/hardware.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*!
+ * @file hardware.h
+ * @brief This file contains the hardware definitions of the board.
+ *
+ * @ingroup System
+ */
+#ifndef __ASM_ARCH_MXC_HARDWARE_H__
+#define __ASM_ARCH_MXC_HARDWARE_H__
+
+#include <asm/sizes.h>
+
+#include <asm/arch/mx31.h>
+
+#include <asm/arch/mxc.h>
+
+#define MXC_MAX_GPIO_LINES (GPIO_NUM_PIN * GPIO_PORT_NUM)
+
+/*
+ * ---------------------------------------------------------------------------
+ * Board specific defines
+ * ---------------------------------------------------------------------------
+ */
+#define MXC_EXP_IO_BASE (MXC_GPIO_INT_BASE + MXC_MAX_GPIO_LINES)
+
+#include <asm/arch/board-mx31ads.h>
+
+#ifndef MXC_MAX_EXP_IO_LINES
+#define MXC_MAX_EXP_IO_LINES 0
+#endif
+
+#define MXC_MAX_VIRTUAL_INTS 16
+#define MXC_VIRTUAL_INTS_BASE (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES)
+#define MXC_SDIO1_CARD_IRQ MXC_VIRTUAL_INTS_BASE
+#define MXC_SDIO2_CARD_IRQ (MXC_VIRTUAL_INTS_BASE + 1)
+#define MXC_SDIO3_CARD_IRQ (MXC_VIRTUAL_INTS_BASE + 2)
+
+#define MXC_MAX_INTS (MXC_MAX_INT_LINES + \
+ MXC_MAX_GPIO_LINES + \
+ MXC_MAX_EXP_IO_LINES + \
+ MXC_MAX_VIRTUAL_INTS)
+
+#endif /* __ASM_ARCH_MXC_HARDWARE_H__ */
diff --git a/include/asm-arm/arch-mxc/io.h b/include/asm-arm/arch-mxc/io.h
new file mode 100644
index 000000000000..cf6c83a4b9f7
--- /dev/null
+++ b/include/asm-arm/arch-mxc/io.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*!
+ * @file io.h
+ * @brief This file contains some memory mapping macros.
+ * @note There is no real ISA or PCI buses. But have to define these macros
+ * for some drivers to compile.
+ *
+ * @ingroup System
+ */
+
+#ifndef __ASM_ARCH_MXC_IO_H__
+#define __ASM_ARCH_MXC_IO_H__
+
+/*! Allow IO space to be anywhere in the memory */
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*!
+ * io address mapping macro
+ */
+#define __io(a) ((void __iomem *)(a))
+
+#define __mem_pci(a) (a)
+
+#endif
diff --git a/include/asm-arm/arch-mxc/irqs.h b/include/asm-arm/arch-mxc/irqs.h
new file mode 100644
index 000000000000..e4686c6bc4bf
--- /dev/null
+++ b/include/asm-arm/arch-mxc/irqs.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_IRQS_H__
+#define __ASM_ARCH_MXC_IRQS_H__
+
+#include <asm/hardware.h>
+
+/*!
+ * @file irqs.h
+ * @brief This file defines the number of normal interrupts and fast interrupts
+ *
+ * @ingroup Interrupt
+ */
+
+#define MXC_IRQ_TO_EXPIO(irq) ((irq) - MXC_EXP_IO_BASE)
+
+#define MXC_IRQ_TO_GPIO(irq) ((irq) - MXC_GPIO_INT_BASE)
+#define MXC_GPIO_TO_IRQ(x) (MXC_GPIO_INT_BASE + x)
+
+/*!
+ * Number of normal interrupts
+ */
+#define NR_IRQS MXC_MAX_INTS
+
+/*!
+ * Number of fast interrupts
+ */
+#define NR_FIQS MXC_MAX_INTS
+
+#endif /* __ASM_ARCH_MXC_IRQS_H__ */
diff --git a/include/asm-arm/arch-mxc/memory.h b/include/asm-arm/arch-mxc/memory.h
new file mode 100644
index 000000000000..c89aac83a407
--- /dev/null
+++ b/include/asm-arm/arch-mxc/memory.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_MEMORY_H__
+#define __ASM_ARCH_MXC_MEMORY_H__
+
+#include <asm/hardware.h>
+
+/*!
+ * @file memory.h
+ * @brief This file contains macros needed by the Linux kernel and drivers.
+ *
+ * @ingroup Memory
+ */
+
+/*!
+ * Virtual view <-> DMA view memory address translations
+ * This macro is used to translate the virtual address to an address
+ * suitable to be passed to set_dma_addr()
+ */
+#define __virt_to_bus(a) __virt_to_phys(a)
+
+/*!
+ * Used to convert an address for DMA operations to an address that the
+ * kernel can use.
+ */
+#define __bus_to_virt(a) __phys_to_virt(a)
+
+#endif /* __ASM_ARCH_MXC_MEMORY_H__ */
diff --git a/include/asm-arm/arch-mxc/mx31.h b/include/asm-arm/arch-mxc/mx31.h
new file mode 100644
index 000000000000..85c49c9e5d15
--- /dev/null
+++ b/include/asm-arm/arch-mxc/mx31.h
@@ -0,0 +1,335 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_MX31_H__
+#define __ASM_ARCH_MXC_MX31_H__
+
+#ifndef __ASM_ARCH_MXC_HARDWARE_H__
+#error "Do not include directly."
+#endif
+
+/*!
+ * defines the hardware clock tick rate
+ */
+#define CLOCK_TICK_RATE 16625000
+
+/*
+ * MX31 memory map:
+ *
+ * Virt Phys Size What
+ * ---------------------------------------------------------------------------
+ * F8000000 1FFC0000 16K IRAM
+ * F9000000 30000000 256M L2CC
+ * FC000000 43F00000 1M AIPS 1
+ * FC100000 50000000 1M SPBA
+ * FC200000 53F00000 1M AIPS 2
+ * FC500000 60000000 128M ROMPATCH
+ * FC400000 68000000 128M AVIC
+ * 70000000 256M IPU (MAX M2)
+ * 80000000 256M CSD0 SDRAM/DDR
+ * 90000000 256M CSD1 SDRAM/DDR
+ * A0000000 128M CS0 Flash
+ * A8000000 128M CS1 Flash
+ * B0000000 32M CS2
+ * B2000000 32M CS3
+ * F4000000 B4000000 32M CS4
+ * B6000000 32M CS5
+ * FC320000 B8000000 64K NAND, SDRAM, WEIM, M3IF, EMI controllers
+ * C0000000 64M PCMCIA/CF
+ */
+
+#define CS0_BASE_ADDR 0xA0000000
+#define CS1_BASE_ADDR 0xA8000000
+#define CS2_BASE_ADDR 0xB0000000
+#define CS3_BASE_ADDR 0xB2000000
+
+#define CS4_BASE_ADDR 0xB4000000
+#define CS4_BASE_ADDR_VIRT 0xF4000000
+#define CS4_SIZE SZ_32M
+
+#define CS5_BASE_ADDR 0xB6000000
+#define PCMCIA_MEM_BASE_ADDR 0xBC000000
+
+/*
+ * IRAM
+ */
+#define IRAM_BASE_ADDR 0x1FFC0000 /* internal ram */
+#define IRAM_BASE_ADDR_VIRT 0xF8000000
+#define IRAM_SIZE SZ_16K
+
+/*
+ * L2CC
+ */
+#define L2CC_BASE_ADDR 0x30000000
+#define L2CC_BASE_ADDR_VIRT 0xF9000000
+#define L2CC_SIZE SZ_1M
+
+/*
+ * AIPS 1
+ */
+#define AIPS1_BASE_ADDR 0x43F00000
+#define AIPS1_BASE_ADDR_VIRT 0xFC000000
+#define AIPS1_SIZE SZ_1M
+
+#define MAX_BASE_ADDR (AIPS1_BASE_ADDR + 0x00004000)
+#define EVTMON_BASE_ADDR (AIPS1_BASE_ADDR + 0x00008000)
+#define CLKCTL_BASE_ADDR (AIPS1_BASE_ADDR + 0x0000C000)
+#define ETB_SLOT4_BASE_ADDR (AIPS1_BASE_ADDR + 0x00010000)
+#define ETB_SLOT5_BASE_ADDR (AIPS1_BASE_ADDR + 0x00014000)
+#define ECT_CTIO_BASE_ADDR (AIPS1_BASE_ADDR + 0x00018000)
+#define I2C_BASE_ADDR (AIPS1_BASE_ADDR + 0x00080000)
+#define I2C3_BASE_ADDR (AIPS1_BASE_ADDR + 0x00084000)
+#define OTG_BASE_ADDR (AIPS1_BASE_ADDR + 0x00088000)
+#define ATA_BASE_ADDR (AIPS1_BASE_ADDR + 0x0008C000)
+#define UART1_BASE_ADDR (AIPS1_BASE_ADDR + 0x00090000)
+#define UART2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00094000)
+#define I2C2_BASE_ADDR (AIPS1_BASE_ADDR + 0x00098000)
+#define OWIRE_BASE_ADDR (AIPS1_BASE_ADDR + 0x0009C000)
+#define SSI1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A0000)
+#define CSPI1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A4000)
+#define KPP_BASE_ADDR (AIPS1_BASE_ADDR + 0x000A8000)
+#define IOMUXC_BASE_ADDR (AIPS1_BASE_ADDR + 0x000AC000)
+#define UART4_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B0000)
+#define UART5_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B4000)
+#define ECT_IP1_BASE_ADDR (AIPS1_BASE_ADDR + 0x000B8000)
+#define ECT_IP2_BASE_ADDR (AIPS1_BASE_ADDR + 0x000BC000)
+
+/*
+ * SPBA global module enabled #0
+ */
+#define SPBA0_BASE_ADDR 0x50000000
+#define SPBA0_BASE_ADDR_VIRT 0xFC100000
+#define SPBA0_SIZE SZ_1M
+
+#define MMC_SDHC1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00004000)
+#define MMC_SDHC2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00008000)
+#define UART3_BASE_ADDR (SPBA0_BASE_ADDR + 0x0000C000)
+#define CSPI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00010000)
+#define SSI2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00014000)
+#define SIM1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00018000)
+#define IIM_BASE_ADDR (SPBA0_BASE_ADDR + 0x0001C000)
+#define ATA_DMA_BASE_ADDR (SPBA0_BASE_ADDR + 0x00020000)
+#define MSHC1_BASE_ADDR (SPBA0_BASE_ADDR + 0x00024000)
+#define MSHC2_BASE_ADDR (SPBA0_BASE_ADDR + 0x00024000)
+#define SPBA_CTRL_BASE_ADDR (SPBA0_BASE_ADDR + 0x0003C000)
+
+/*
+ * AIPS 2
+ */
+#define AIPS2_BASE_ADDR 0x53F00000
+#define AIPS2_BASE_ADDR_VIRT 0xFC200000
+#define AIPS2_SIZE SZ_1M
+#define CCM_BASE_ADDR (AIPS2_BASE_ADDR + 0x00080000)
+#define CSPI3_BASE_ADDR (AIPS2_BASE_ADDR + 0x00084000)
+#define FIRI_BASE_ADDR (AIPS2_BASE_ADDR + 0x0008C000)
+#define GPT1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00090000)
+#define EPIT1_BASE_ADDR (AIPS2_BASE_ADDR + 0x00094000)
+#define EPIT2_BASE_ADDR (AIPS2_BASE_ADDR + 0x00098000)
+#define GPIO3_BASE_ADDR (AIPS2_BASE_ADDR + 0x000A4000)
+#define SCC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AC000)
+#define SCM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AE000)
+#define SMN_BASE_ADDR (AIPS2_BASE_ADDR + 0x000AF000)
+#define RNGA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000B0000)
+#define IPU_CTRL_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C0000)
+#define AUDMUX_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C4000)
+#define MPEG4_ENC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000C8000)
+#define GPIO1_BASE_ADDR (AIPS2_BASE_ADDR + 0x000CC000)
+#define GPIO2_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D0000)
+#define SDMA_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D4000)
+#define RTC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000D8000)
+#define WDOG_BASE_ADDR (AIPS2_BASE_ADDR + 0x000DC000)
+#define PWM_BASE_ADDR (AIPS2_BASE_ADDR + 0x000E0000)
+#define RTIC_BASE_ADDR (AIPS2_BASE_ADDR + 0x000EC000)
+
+/*
+ * ROMP and AVIC
+ */
+#define ROMP_BASE_ADDR 0x60000000
+#define ROMP_BASE_ADDR_VIRT 0xFC500000
+#define ROMP_SIZE SZ_1M
+
+#define AVIC_BASE_ADDR 0x68000000
+#define AVIC_BASE_ADDR_VIRT 0xFC400000
+#define AVIC_SIZE SZ_1M
+
+/*
+ * NAND, SDRAM, WEIM, M3IF, EMI controllers
+ */
+#define X_MEMC_BASE_ADDR 0xB8000000
+#define X_MEMC_BASE_ADDR_VIRT 0xFC320000
+#define X_MEMC_SIZE SZ_64K
+
+#define NFC_BASE_ADDR (X_MEMC_BASE_ADDR + 0x0000)
+#define ESDCTL_BASE_ADDR (X_MEMC_BASE_ADDR + 0x1000)
+#define WEIM_BASE_ADDR (X_MEMC_BASE_ADDR + 0x2000)
+#define M3IF_BASE_ADDR (X_MEMC_BASE_ADDR + 0x3000)
+#define EMI_CTL_BASE_ADDR (X_MEMC_BASE_ADDR + 0x4000)
+#define PCMCIA_CTL_BASE_ADDR EMI_CTL_BASE_ADDR
+
+/*
+ * Memory regions and CS
+ */
+#define IPU_MEM_BASE_ADDR 0x70000000
+#define CSD0_BASE_ADDR 0x80000000
+#define CSD1_BASE_ADDR 0x90000000
+#define CS0_BASE_ADDR 0xA0000000
+#define CS1_BASE_ADDR 0xA8000000
+#define CS2_BASE_ADDR 0xB0000000
+#define CS3_BASE_ADDR 0xB2000000
+
+#define CS4_BASE_ADDR 0xB4000000
+#define CS4_BASE_ADDR_VIRT 0xF4000000
+#define CS4_SIZE SZ_32M
+
+#define CS5_BASE_ADDR 0xB6000000
+#define PCMCIA_MEM_BASE_ADDR 0xBC000000
+
+/*!
+ * This macro defines the physical to virtual address mapping for all the
+ * peripheral modules. It is used by passing in the physical address as x
+ * and returning the virtual address. If the physical address is not mapped,
+ * it returns 0xDEADBEEF
+ */
+#define IO_ADDRESS(x) \
+ (((x >= IRAM_BASE_ADDR) && (x < (IRAM_BASE_ADDR + IRAM_SIZE))) ? IRAM_IO_ADDRESS(x):\
+ ((x >= L2CC_BASE_ADDR) && (x < (L2CC_BASE_ADDR + L2CC_SIZE))) ? L2CC_IO_ADDRESS(x):\
+ ((x >= AIPS1_BASE_ADDR) && (x < (AIPS1_BASE_ADDR + AIPS1_SIZE))) ? AIPS1_IO_ADDRESS(x):\
+ ((x >= SPBA0_BASE_ADDR) && (x < (SPBA0_BASE_ADDR + SPBA0_SIZE))) ? SPBA0_IO_ADDRESS(x):\
+ ((x >= AIPS2_BASE_ADDR) && (x < (AIPS2_BASE_ADDR + AIPS2_SIZE))) ? AIPS2_IO_ADDRESS(x):\
+ ((x >= ROMP_BASE_ADDR) && (x < (ROMP_BASE_ADDR + ROMP_SIZE))) ? ROMP_IO_ADDRESS(x):\
+ ((x >= AVIC_BASE_ADDR) && (x < (AVIC_BASE_ADDR + AVIC_SIZE))) ? AVIC_IO_ADDRESS(x):\
+ ((x >= CS4_BASE_ADDR) && (x < (CS4_BASE_ADDR + CS4_SIZE))) ? CS4_IO_ADDRESS(x):\
+ ((x >= X_MEMC_BASE_ADDR) && (x < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ? X_MEMC_IO_ADDRESS(x):\
+ 0xDEADBEEF)
+
+/*
+ * define the address mapping macros: in physical address order
+ */
+
+#define IRAM_IO_ADDRESS(x) \
+ (((x) - IRAM_BASE_ADDR) + IRAM_BASE_ADDR_VIRT)
+
+#define L2CC_IO_ADDRESS(x) \
+ (((x) - L2CC_BASE_ADDR) + L2CC_BASE_ADDR_VIRT)
+
+#define AIPS1_IO_ADDRESS(x) \
+ (((x) - AIPS1_BASE_ADDR) + AIPS1_BASE_ADDR_VIRT)
+
+#define SPBA0_IO_ADDRESS(x) \
+ (((x) - SPBA0_BASE_ADDR) + SPBA0_BASE_ADDR_VIRT)
+
+#define AIPS2_IO_ADDRESS(x) \
+ (((x) - AIPS2_BASE_ADDR) + AIPS2_BASE_ADDR_VIRT)
+
+#define ROMP_IO_ADDRESS(x) \
+ (((x) - ROMP_BASE_ADDR) + ROMP_BASE_ADDR_VIRT)
+
+#define AVIC_IO_ADDRESS(x) \
+ (((x) - AVIC_BASE_ADDR) + AVIC_BASE_ADDR_VIRT)
+
+#define CS4_IO_ADDRESS(x) \
+ (((x) - CS4_BASE_ADDR) + CS4_BASE_ADDR_VIRT)
+
+#define X_MEMC_IO_ADDRESS(x) \
+ (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
+
+#define PCMCIA_IO_ADDRESS(x) \
+ (((x) - X_MEMC_BASE_ADDR) + X_MEMC_BASE_ADDR_VIRT)
+
+/* Start of physical RAM - On many MX31 platforms, this is the first SDRAM bank (CSD0) */
+#define PHYS_OFFSET CSD0_BASE_ADDR
+
+/*
+ * Interrupt numbers
+ */
+#define MXC_INT_PEN_ADS7843 0
+#define MXC_INT_RESV1 1
+#define MXC_INT_CS8900A 2
+#define MXC_INT_I2C3 3
+#define MXC_INT_I2C2 4
+#define MXC_INT_MPEG4_ENCODER 5
+#define MXC_INT_RTIC 6
+#define MXC_INT_FIRI 7
+#define MXC_INT_MMC_SDHC2 8
+#define MXC_INT_MMC_SDHC1 9
+#define MXC_INT_I2C 10
+#define MXC_INT_SSI2 11
+#define MXC_INT_SSI1 12
+#define MXC_INT_CSPI2 13
+#define MXC_INT_CSPI1 14
+#define MXC_INT_ATA 15
+#define MXC_INT_MBX 16
+#define MXC_INT_CSPI3 17
+#define MXC_INT_UART3 18
+#define MXC_INT_IIM 19
+#define MXC_INT_SIM2 20
+#define MXC_INT_SIM1 21
+#define MXC_INT_RNGA 22
+#define MXC_INT_EVTMON 23
+#define MXC_INT_KPP 24
+#define MXC_INT_RTC 25
+#define MXC_INT_PWM 26
+#define MXC_INT_EPIT2 27
+#define MXC_INT_EPIT1 28
+#define MXC_INT_GPT 29
+#define MXC_INT_RESV30 30
+#define MXC_INT_RESV31 31
+#define MXC_INT_UART2 32
+#define MXC_INT_NANDFC 33
+#define MXC_INT_SDMA 34
+#define MXC_INT_USB1 35
+#define MXC_INT_USB2 36
+#define MXC_INT_USB3 37
+#define MXC_INT_USB4 38
+#define MXC_INT_MSHC1 39
+#define MXC_INT_MSHC2 40
+#define MXC_INT_IPU_ERR 41
+#define MXC_INT_IPU_SYN 42
+#define MXC_INT_RESV43 43
+#define MXC_INT_RESV44 44
+#define MXC_INT_UART1 45
+#define MXC_INT_UART4 46
+#define MXC_INT_UART5 47
+#define MXC_INT_ECT 48
+#define MXC_INT_SCC_SCM 49
+#define MXC_INT_SCC_SMN 50
+#define MXC_INT_GPIO2 51
+#define MXC_INT_GPIO1 52
+#define MXC_INT_CCM 53
+#define MXC_INT_PCMCIA 54
+#define MXC_INT_WDOG 55
+#define MXC_INT_GPIO3 56
+#define MXC_INT_RESV57 57
+#define MXC_INT_EXT_POWER 58
+#define MXC_INT_EXT_TEMPER 59
+#define MXC_INT_EXT_SENSOR60 60
+#define MXC_INT_EXT_SENSOR61 61
+#define MXC_INT_EXT_WDOG 62
+#define MXC_INT_EXT_TV 63
+
+#define MXC_MAX_INT_LINES 64
+
+#define MXC_GPIO_INT_BASE MXC_MAX_INT_LINES
+
+/*!
+ * Number of GPIO port as defined in the IC Spec
+ */
+#define GPIO_PORT_NUM 3
+/*!
+ * Number of GPIO pins per port
+ */
+#define GPIO_NUM_PIN 32
+
+#define PROD_SIGNATURE 0x1 /* For MX31 */
+
+#define SYSTEM_REV_MIN CHIP_REV_1_0
+#define SYSTEM_REV_NUM 3
+
+#endif /* __ASM_ARCH_MXC_MX31_H__ */
diff --git a/include/asm-arm/arch-mxc/mxc.h b/include/asm-arm/arch-mxc/mxc.h
new file mode 100644
index 000000000000..0837f1f9ca31
--- /dev/null
+++ b/include/asm-arm/arch-mxc/mxc.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_H__
+#define __ASM_ARCH_MXC_H__
+
+#ifndef __ASM_ARCH_MXC_HARDWARE_H__
+#error "Do not include directly."
+#endif
+
+/*
+ *****************************************
+ * GPT Register definitions *
+ *****************************************
+ */
+#define MXC_GPT_GPTCR IO_ADDRESS(GPT1_BASE_ADDR + 0x00)
+#define MXC_GPT_GPTPR IO_ADDRESS(GPT1_BASE_ADDR + 0x04)
+#define MXC_GPT_GPTSR IO_ADDRESS(GPT1_BASE_ADDR + 0x08)
+#define MXC_GPT_GPTIR IO_ADDRESS(GPT1_BASE_ADDR + 0x0C)
+#define MXC_GPT_GPTOCR1 IO_ADDRESS(GPT1_BASE_ADDR + 0x10)
+#define MXC_GPT_GPTOCR2 IO_ADDRESS(GPT1_BASE_ADDR + 0x14)
+#define MXC_GPT_GPTOCR3 IO_ADDRESS(GPT1_BASE_ADDR + 0x18)
+#define MXC_GPT_GPTICR1 IO_ADDRESS(GPT1_BASE_ADDR + 0x1C)
+#define MXC_GPT_GPTICR2 IO_ADDRESS(GPT1_BASE_ADDR + 0x20)
+#define MXC_GPT_GPTCNT IO_ADDRESS(GPT1_BASE_ADDR + 0x24)
+
+/*!
+ * GPT Control register bit definitions
+ */
+#define GPTCR_FO3 (1 << 31)
+#define GPTCR_FO2 (1 << 30)
+#define GPTCR_FO1 (1 << 29)
+
+#define GPTCR_OM3_SHIFT 26
+#define GPTCR_OM3_MASK (7 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_DISCONNECTED (0 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_TOGGLE (1 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_CLEAR (2 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_SET (3 << GPTCR_OM3_SHIFT)
+#define GPTCR_OM3_GENERATE_LOW (7 << GPTCR_OM3_SHIFT)
+
+#define GPTCR_OM2_SHIFT 23
+#define GPTCR_OM2_MASK (7 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_DISCONNECTED (0 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_TOGGLE (1 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_CLEAR (2 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_SET (3 << GPTCR_OM2_SHIFT)
+#define GPTCR_OM2_GENERATE_LOW (7 << GPTCR_OM2_SHIFT)
+
+#define GPTCR_OM1_SHIFT 20
+#define GPTCR_OM1_MASK (7 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_DISCONNECTED (0 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_TOGGLE (1 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_CLEAR (2 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_SET (3 << GPTCR_OM1_SHIFT)
+#define GPTCR_OM1_GENERATE_LOW (7 << GPTCR_OM1_SHIFT)
+
+#define GPTCR_IM2_SHIFT 18
+#define GPTCR_IM2_MASK (3 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_DISABLE (0 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_RISING (1 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_FALLING (2 << GPTCR_IM2_SHIFT)
+#define GPTCR_IM2_CAPTURE_BOTH (3 << GPTCR_IM2_SHIFT)
+
+#define GPTCR_IM1_SHIFT 16
+#define GPTCR_IM1_MASK (3 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_DISABLE (0 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_RISING (1 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_FALLING (2 << GPTCR_IM1_SHIFT)
+#define GPTCR_IM1_CAPTURE_BOTH (3 << GPTCR_IM1_SHIFT)
+
+#define GPTCR_SWR (1 << 15)
+#define GPTCR_FRR (1 << 9)
+
+#define GPTCR_CLKSRC_SHIFT 6
+#define GPTCR_CLKSRC_MASK (7 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_NOCLOCK (0 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_HIGHFREQ (2 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_CLKIN (3 << GPTCR_CLKSRC_SHIFT)
+#define GPTCR_CLKSRC_CLK32K (7 << GPTCR_CLKSRC_SHIFT)
+
+#define GPTCR_STOPEN (1 << 5)
+#define GPTCR_DOZEN (1 << 4)
+#define GPTCR_WAITEN (1 << 3)
+#define GPTCR_DBGEN (1 << 2)
+
+#define GPTCR_ENMOD (1 << 1)
+#define GPTCR_ENABLE (1 << 0)
+
+#define GPTSR_OF1 (1 << 0)
+#define GPTSR_OF2 (1 << 1)
+#define GPTSR_OF3 (1 << 2)
+#define GPTSR_IF1 (1 << 3)
+#define GPTSR_IF2 (1 << 4)
+#define GPTSR_ROV (1 << 5)
+
+#define GPTIR_OF1IE GPTSR_OF1
+#define GPTIR_OF2IE GPTSR_OF2
+#define GPTIR_OF3IE GPTSR_OF3
+#define GPTIR_IF1IE GPTSR_IF1
+#define GPTIR_IF2IE GPTSR_IF2
+#define GPTIR_ROVIE GPTSR_ROV
+
+/*
+ *****************************************
+ * AVIC Registers *
+ *****************************************
+ */
+#define AVIC_BASE IO_ADDRESS(AVIC_BASE_ADDR)
+#define AVIC_INTCNTL (AVIC_BASE + 0x00) /* int control reg */
+#define AVIC_NIMASK (AVIC_BASE + 0x04) /* int mask reg */
+#define AVIC_INTENNUM (AVIC_BASE + 0x08) /* int enable number reg */
+#define AVIC_INTDISNUM (AVIC_BASE + 0x0C) /* int disable number reg */
+#define AVIC_INTENABLEH (AVIC_BASE + 0x10) /* int enable reg high */
+#define AVIC_INTENABLEL (AVIC_BASE + 0x14) /* int enable reg low */
+#define AVIC_INTTYPEH (AVIC_BASE + 0x18) /* int type reg high */
+#define AVIC_INTTYPEL (AVIC_BASE + 0x1C) /* int type reg low */
+#define AVIC_NIPRIORITY7 (AVIC_BASE + 0x20) /* norm int priority lvl7 */
+#define AVIC_NIPRIORITY6 (AVIC_BASE + 0x24) /* norm int priority lvl6 */
+#define AVIC_NIPRIORITY5 (AVIC_BASE + 0x28) /* norm int priority lvl5 */
+#define AVIC_NIPRIORITY4 (AVIC_BASE + 0x2C) /* norm int priority lvl4 */
+#define AVIC_NIPRIORITY3 (AVIC_BASE + 0x30) /* norm int priority lvl3 */
+#define AVIC_NIPRIORITY2 (AVIC_BASE + 0x34) /* norm int priority lvl2 */
+#define AVIC_NIPRIORITY1 (AVIC_BASE + 0x38) /* norm int priority lvl1 */
+#define AVIC_NIPRIORITY0 (AVIC_BASE + 0x3C) /* norm int priority lvl0 */
+#define AVIC_NIVECSR (AVIC_BASE + 0x40) /* norm int vector/status */
+#define AVIC_FIVECSR (AVIC_BASE + 0x44) /* fast int vector/status */
+#define AVIC_INTSRCH (AVIC_BASE + 0x48) /* int source reg high */
+#define AVIC_INTSRCL (AVIC_BASE + 0x4C) /* int source reg low */
+#define AVIC_INTFRCH (AVIC_BASE + 0x50) /* int force reg high */
+#define AVIC_INTFRCL (AVIC_BASE + 0x54) /* int force reg low */
+#define AVIC_NIPNDH (AVIC_BASE + 0x58) /* norm int pending high */
+#define AVIC_NIPNDL (AVIC_BASE + 0x5C) /* norm int pending low */
+#define AVIC_FIPNDH (AVIC_BASE + 0x60) /* fast int pending high */
+#define AVIC_FIPNDL (AVIC_BASE + 0x64) /* fast int pending low */
+
+#define SYSTEM_PREV_REG IO_ADDRESS(IIM_BASE_ADDR + 0x20)
+#define SYSTEM_SREV_REG IO_ADDRESS(IIM_BASE_ADDR + 0x24)
+#define IIM_PROD_REV_SH 3
+#define IIM_PROD_REV_LEN 5
+
+#endif /* __ASM_ARCH_MXC_H__ */
diff --git a/include/asm-arm/arch-mxc/system.h b/include/asm-arm/arch-mxc/system.h
new file mode 100644
index 000000000000..109956b41aca
--- /dev/null
+++ b/include/asm-arm/arch-mxc/system.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1999 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARCH_MXC_SYSTEM_H__
+#define __ASM_ARCH_MXC_SYSTEM_H__
+
+/*!
+ * @file system.h
+ * @brief This file contains idle and reset functions.
+ *
+ * @ingroup System
+ */
+
+/*!
+ * This function puts the CPU into idle mode. It is called by default_idle()
+ * in process.c file.
+ */
+static inline void arch_idle(void)
+{
+ cpu_do_idle();
+}
+
+/*
+ * This function resets the system. It is called by machine_restart().
+ *
+ * @param mode indicates different kinds of resets
+ */
+static inline void arch_reset(char mode)
+{
+ cpu_reset(0);
+}
+
+#endif /* __ASM_ARCH_MXC_SYSTEM_H__ */
diff --git a/include/asm-arm/arch-mxc/timex.h b/include/asm-arm/arch-mxc/timex.h
new file mode 100644
index 000000000000..59019fa58f82
--- /dev/null
+++ b/include/asm-arm/arch-mxc/timex.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 1999 ARM Limited
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARCH_MXC_TIMEX_H__
+#define __ASM_ARCH_MXC_TIMEX_H__
+
+#include <asm/hardware.h> /* for CLOCK_TICK_RATE */
+
+#endif /* __ASM_ARCH_MXC_TIMEX_H__ */
diff --git a/include/asm-arm/arch-mxc/uncompress.h b/include/asm-arm/arch-mxc/uncompress.h
new file mode 100644
index 000000000000..ec5787d0e78c
--- /dev/null
+++ b/include/asm-arm/arch-mxc/uncompress.h
@@ -0,0 +1,79 @@
+/*
+ * include/asm-arm/arch-mxc/uncompress.h
+ *
+ *
+ *
+ * Copyright (C) 1999 ARM Limited
+ * Copyright (C) Shane Nay (shane@minirl.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ASM_ARCH_MXC_UNCOMPRESS_H__
+#define __ASM_ARCH_MXC_UNCOMPRESS_H__
+
+#define __MXC_BOOT_UNCOMPRESS
+
+#include <asm/hardware.h>
+#include <asm/processor.h>
+
+#define UART(x) (*(volatile unsigned long *)(serial_port + (x)))
+
+#define USR2 0x98
+#define USR2_TXFE (1<<14)
+#define TXR 0x40
+#define UCR1 0x80
+#define UCR1_UARTEN 1
+
+/*
+ * The following code assumes the serial port has already been
+ * initialized by the bootloader. We search for the first enabled
+ * port in the most probable order. If you didn't setup a port in
+ * your bootloader then nothing will appear (which might be desired).
+ *
+ * This does not append a newline
+ */
+
+static void putc(int ch)
+{
+ static unsigned long serial_port = 0;
+
+ if (unlikely(serial_port == 0)) {
+ do {
+ serial_port = UART1_BASE_ADDR;
+ if (UART(UCR1) & UCR1_UARTEN)
+ break;
+ serial_port = UART2_BASE_ADDR;
+ if (UART(UCR1) & UCR1_UARTEN)
+ break;
+ return;
+ } while (0);
+ }
+
+ while (!(UART(USR2) & USR2_TXFE))
+ cpu_relax();
+
+ UART(TXR) = ch;
+}
+
+#define flush() do { } while (0)
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
+
+#endif /* __ASM_ARCH_MXC_UNCOMPRESS_H__ */
diff --git a/include/asm-arm/arch-mxc/vmalloc.h b/include/asm-arm/arch-mxc/vmalloc.h
new file mode 100644
index 000000000000..83a73da895eb
--- /dev/null
+++ b/include/asm-arm/arch-mxc/vmalloc.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2000 Russell King.
+ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __ASM_ARCH_MXC_VMALLOC_H__
+#define __ASM_ARCH_MXC_VMALLOC_H__
+
+/*!
+ * @file vmalloc.h
+ *
+ * @brief This file contains platform specific macros for vmalloc.
+ *
+ * @ingroup System
+ */
+
+/*!
+ * vmalloc ending address
+ */
+#define VMALLOC_END 0xF4000000
+
+#endif /* __ASM_ARCH_MXC_VMALLOC_H__ */
diff --git a/include/asm-arm/arch-ns9xxx/regs-bbu.h b/include/asm-arm/arch-ns9xxx/regs-bbu.h
index e26269546240..7ee194dc6354 100644
--- a/include/asm-arm/arch-ns9xxx/regs-bbu.h
+++ b/include/asm-arm/arch-ns9xxx/regs-bbu.h
@@ -15,7 +15,31 @@
/* BBus Utility */
-/* GPIO Configuration Register */
-#define BBU_GC(x) __REG2(0x9060000c, (x))
+/* GPIO Configuration Registers block 1 */
+/* NOTE: the HRM starts counting at 1 for the GPIO registers, here the start is
+ * at 0 for each block. That is, BBU_GCONFb1(0) is GPIO Configuration Register
+ * #1, BBU_GCONFb2(0) is GPIO Configuration Register #8. */
+#define BBU_GCONFb1(x) __REG2(0x90600010, (x))
+#define BBU_GCONFb2(x) __REG2(0x90600100, (x))
+
+#define BBU_GCONFx_DIR(m) __REGBIT(3 + (((m) & 7) << 2))
+#define BBU_GCONFx_DIR_INPUT(m) __REGVAL(BBU_GCONFx_DIR(m), 0)
+#define BBU_GCONFx_DIR_OUTPUT(m) __REGVAL(BBU_GCONFx_DIR(m), 1)
+#define BBU_GCONFx_INV(m) __REGBIT(2 + (((m) & 7) << 2))
+#define BBU_GCONFx_INV_NO(m) __REGVAL(BBU_GCONFx_INV(m), 0)
+#define BBU_GCONFx_INV_YES(m) __REGVAL(BBU_GCONFx_INV(m), 1)
+#define BBU_GCONFx_FUNC(m) __REGBITS(1 + (((m) & 7) << 2), ((m) & 7) << 2)
+#define BBU_GCONFx_FUNC_0(m) __REGVAL(BBU_GCONFx_FUNC(m), 0)
+#define BBU_GCONFx_FUNC_1(m) __REGVAL(BBU_GCONFx_FUNC(m), 1)
+#define BBU_GCONFx_FUNC_2(m) __REGVAL(BBU_GCONFx_FUNC(m), 2)
+#define BBU_GCONFx_FUNC_3(m) __REGVAL(BBU_GCONFx_FUNC(m), 3)
+
+#define BBU_GCTRL1 __REG(0x90600030)
+#define BBU_GCTRL2 __REG(0x90600034)
+#define BBU_GCTRL3 __REG(0x90600120)
+
+#define BBU_GSTAT1 __REG(0x90600040)
+#define BBU_GSTAT2 __REG(0x90600044)
+#define BBU_GSTAT3 __REG(0x90600130)
#endif /* ifndef __ASM_ARCH_REGSBBU_H */
diff --git a/include/asm-arm/arch-ns9xxx/regs-mem.h b/include/asm-arm/arch-ns9xxx/regs-mem.h
index 8ed8448767b9..fb455a0ed845 100644
--- a/include/asm-arm/arch-ns9xxx/regs-mem.h
+++ b/include/asm-arm/arch-ns9xxx/regs-mem.h
@@ -79,9 +79,9 @@
#define MEM_SMC(x) __REG2(0xa0700200, (x) << 3)
/* Static Memory Configuration Register x: Write protect */
-#define MEM_SMC_WSMC __REGBIT(20)
-#define MEM_SMC_WSMC_OFF __REGVAL(MEM_SMC_WSMC, 0)
-#define MEM_SMC_WSMC_ON __REGVAL(MEM_SMC_WSMC, 1)
+#define MEM_SMC_PSMC __REGBIT(20)
+#define MEM_SMC_PSMC_OFF __REGVAL(MEM_SMC_PSMC, 0)
+#define MEM_SMC_PSMC_ON __REGVAL(MEM_SMC_PSMC, 1)
/* Static Memory Configuration Register x: Buffer enable */
#define MEM_SMC_BSMC __REGBIT(19)
diff --git a/include/asm-arm/arch-ns9xxx/regs-sys.h b/include/asm-arm/arch-ns9xxx/regs-sys.h
index a42546aeb92a..749262f86204 100644
--- a/include/asm-arm/arch-ns9xxx/regs-sys.h
+++ b/include/asm-arm/arch-ns9xxx/regs-sys.h
@@ -64,7 +64,7 @@
/* Timer x Control register: Timer enable */
#define SYS_TCx_TEN __REGBIT(15)
-#define SYS_TCx_TEN_DIS __REGVAL(SYS_TCx_TEN, 1)
+#define SYS_TCx_TEN_DIS __REGVAL(SYS_TCx_TEN, 0)
#define SYS_TCx_TEN_EN __REGVAL(SYS_TCx_TEN, 1)
/* Timer x Control register: CPU debug mode */
diff --git a/include/asm-arm/arch-pxa/dma.h b/include/asm-arm/arch-pxa/dma.h
index bed042d71d68..3280ee2ddfa5 100644
--- a/include/asm-arm/arch-pxa/dma.h
+++ b/include/asm-arm/arch-pxa/dma.h
@@ -30,30 +30,12 @@ typedef enum {
DMA_PRIO_LOW = 2
} pxa_dma_prio;
-#if defined(CONFIG_PXA27x)
-
-#define PXA_DMA_CHANNELS 32
-
-#define pxa_for_each_dma_prio(ch, prio) \
-for ( \
- ch = prio * 4; \
- ch != (4 << prio) + 16; \
- ch = (ch + 1 == (4 << prio)) ? (prio * 4 + 16) : (ch + 1) \
-)
-
-#elif defined(CONFIG_PXA25x)
-
-#define PXA_DMA_CHANNELS 16
-
-#define pxa_for_each_dma_prio(ch, prio) \
- for (ch = prio * 4; ch != (4 << prio); ch++)
-
-#endif
-
/*
* DMA registration
*/
+int __init pxa_init_dma(int num_ch);
+
int pxa_request_dma (char *name,
pxa_dma_prio prio,
void (*irq_handler)(int, void *),
diff --git a/include/asm-arm/arch-pxa/entry-macro.S b/include/asm-arm/arch-pxa/entry-macro.S
index 1d5fbb9b379a..b7e730851461 100644
--- a/include/asm-arm/arch-pxa/entry-macro.S
+++ b/include/asm-arm/arch-pxa/entry-macro.S
@@ -20,20 +20,38 @@
.endm
.macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-#ifdef CONFIG_PXA27x
- mrc p6, 0, \irqstat, c0, c0, 0 @ ICIP
- mrc p6, 0, \irqnr, c1, c0, 0 @ ICMR
-#else
+ mrc p15, 0, \tmp, c0, c0, 0 @ CPUID
+ mov \tmp, \tmp, lsr #13
+ and \tmp, \tmp, #0x7 @ Core G
+ cmp \tmp, #1
+ bhi 1004f
+
mov \base, #io_p2v(0x40000000) @ IIR Ctl = 0x40d00000
add \base, \base, #0x00d00000
ldr \irqstat, [\base, #0] @ ICIP
ldr \irqnr, [\base, #4] @ ICMR
-#endif
+ b 1002f
+
+1004:
+ mrc p6, 0, \irqstat, c6, c0, 0 @ ICIP2
+ mrc p6, 0, \irqnr, c7, c0, 0 @ ICMR2
+ ands \irqstat, \irqstat, \irqnr
+ beq 1003f
+ rsb \irqstat, \irqnr, #0
+ and \irqstat, \irqstat, \irqnr
+ clz \irqnr, \irqstat
+ rsb \irqnr, \irqnr, #31
+ add \irqnr, \irqnr, #32
+ b 1001f
+1003:
+ mrc p6, 0, \irqstat, c0, c0, 0 @ ICIP
+ mrc p6, 0, \irqnr, c1, c0, 0 @ ICMR
+1002:
ands \irqnr, \irqstat, \irqnr
beq 1001f
rsb \irqstat, \irqnr, #0
and \irqstat, \irqstat, \irqnr
clz \irqnr, \irqstat
- rsb \irqnr, \irqnr, #(31 - PXA_IRQ_SKIP)
+ rsb \irqnr, \irqnr, #31
1001:
.endm
diff --git a/include/asm-arm/arch-pxa/hardware.h b/include/asm-arm/arch-pxa/hardware.h
index e2bdc2fbede1..386121746417 100644
--- a/include/asm-arm/arch-pxa/hardware.h
+++ b/include/asm-arm/arch-pxa/hardware.h
@@ -62,6 +62,42 @@
#ifndef __ASSEMBLY__
+#define __cpu_is_pxa21x(id) \
+ ({ \
+ unsigned int _id = (id) >> 4 & 0xf3f; \
+ _id == 0x212; \
+ })
+
+#define __cpu_is_pxa25x(id) \
+ ({ \
+ unsigned int _id = (id) >> 4 & 0xfff; \
+ _id == 0x2d0 || _id == 0x290; \
+ })
+
+#define __cpu_is_pxa27x(id) \
+ ({ \
+ unsigned int _id = (id) >> 4 & 0xfff; \
+ _id == 0x411; \
+ })
+
+#define cpu_is_pxa21x() \
+ ({ \
+ unsigned int id = read_cpuid(CPUID_ID); \
+ __cpu_is_pxa21x(id); \
+ })
+
+#define cpu_is_pxa25x() \
+ ({ \
+ unsigned int id = read_cpuid(CPUID_ID); \
+ __cpu_is_pxa25x(id); \
+ })
+
+#define cpu_is_pxa27x() \
+ ({ \
+ unsigned int id = read_cpuid(CPUID_ID); \
+ __cpu_is_pxa27x(id); \
+ })
+
/*
* Handy routine to set GPIO alternate functions
*/
diff --git a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h
index 67ed43674c63..a07fe0f928cd 100644
--- a/include/asm-arm/arch-pxa/irqs.h
+++ b/include/asm-arm/arch-pxa/irqs.h
@@ -11,14 +11,9 @@
*/
-#ifdef CONFIG_PXA27x
-#define PXA_IRQ_SKIP 0
-#else
-#define PXA_IRQ_SKIP 7
-#endif
-
-#define PXA_IRQ(x) ((x) - PXA_IRQ_SKIP)
+#define PXA_IRQ(x) (x)
+#ifdef CONFIG_PXA27x
#define IRQ_SSP3 PXA_IRQ(0) /* SSP3 service request */
#define IRQ_MSL PXA_IRQ(1) /* MSL Interface interrupt */
#define IRQ_USBH2 PXA_IRQ(2) /* USB Host interrupt 1 (OHCI) */
@@ -26,6 +21,8 @@
#define IRQ_KEYPAD PXA_IRQ(4) /* Key pad controller */
#define IRQ_MEMSTK PXA_IRQ(5) /* Memory Stick interrupt */
#define IRQ_PWRI2C PXA_IRQ(6) /* Power I2C interrupt */
+#endif
+
#define IRQ_HWUART PXA_IRQ(7) /* HWUART Transmit/Receive/Error (PXA26x) */
#define IRQ_OST_4_11 PXA_IRQ(7) /* OS timer 4-11 matches (PXA27x) */
#define IRQ_GPIO0 PXA_IRQ(8) /* GPIO0 Edge Detect */
@@ -58,18 +55,15 @@
#ifdef CONFIG_PXA27x
#define IRQ_TPM PXA_IRQ(32) /* TPM interrupt */
#define IRQ_CAMERA PXA_IRQ(33) /* Camera Interface */
-
-#define PXA_INTERNAL_IRQS 34
-#else
-#define PXA_INTERNAL_IRQS 32
#endif
-#define GPIO_2_x_TO_IRQ(x) \
- PXA_IRQ((x) - 2 + PXA_INTERNAL_IRQS)
+#define PXA_GPIO_IRQ_BASE (64)
+#define PXA_GPIO_IRQ_NUM (128)
+
+#define GPIO_2_x_TO_IRQ(x) (PXA_GPIO_IRQ_BASE + (x))
#define IRQ_GPIO(x) (((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIO_2_x_TO_IRQ(x))
-#define IRQ_TO_GPIO_2_x(i) \
- ((i) - IRQ_GPIO(2) + 2)
+#define IRQ_TO_GPIO_2_x(i) ((i) - PXA_GPIO_IRQ_BASE)
#define IRQ_TO_GPIO(i) (((i) < IRQ_GPIO(2)) ? ((i) - IRQ_GPIO0) : IRQ_TO_GPIO_2_x(i))
#if defined(CONFIG_PXA25x)
@@ -84,7 +78,7 @@
* these. If you need more, increase IRQ_BOARD_END, but keep it
* within sensible limits.
*/
-#define IRQ_BOARD_START (IRQ_GPIO(PXA_LAST_GPIO) + 1)
+#define IRQ_BOARD_START (PXA_GPIO_IRQ_BASE + PXA_GPIO_IRQ_NUM)
#define IRQ_BOARD_END (IRQ_BOARD_START + 16)
#define IRQ_SA1111_START (IRQ_BOARD_END)
diff --git a/include/asm-arm/arch-pxa/pm.h b/include/asm-arm/arch-pxa/pm.h
index 7a8a1cdf430d..6903db7fae15 100644
--- a/include/asm-arm/arch-pxa/pm.h
+++ b/include/asm-arm/arch-pxa/pm.h
@@ -7,6 +7,19 @@
*
*/
-extern int pxa_pm_prepare(suspend_state_t state);
+struct pxa_cpu_pm_fns {
+ int save_size;
+ void (*save)(unsigned long *);
+ void (*restore)(unsigned long *);
+ int (*valid)(suspend_state_t state);
+ void (*enter)(suspend_state_t state);
+};
+
+extern struct pxa_cpu_pm_fns *pxa_cpu_pm_fns;
+
+/* sleep.S */
+extern void pxa25x_cpu_suspend(unsigned int);
+extern void pxa27x_cpu_suspend(unsigned int);
+extern void pxa_cpu_resume(void);
+
extern int pxa_pm_enter(suspend_state_t state);
-extern int pxa_pm_finish(suspend_state_t state);
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index dbcc9298b0c8..e68b593d69da 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1765,29 +1765,9 @@
#define SSACD_P(x) (*(((x) == 1) ? &SSACD_P1 : ((x) == 2) ? &SSACD_P2 : ((x) == 3) ? &SSACD_P3 : NULL))
/*
- * MultiMediaCard (MMC) controller
+ * MultiMediaCard (MMC) controller - see drivers/mmc/host/pxamci.h
*/
-#define MMC_STRPCL __REG(0x41100000) /* Control to start and stop MMC clock */
-#define MMC_STAT __REG(0x41100004) /* MMC Status Register (read only) */
-#define MMC_CLKRT __REG(0x41100008) /* MMC clock rate */
-#define MMC_SPI __REG(0x4110000c) /* SPI mode control bits */
-#define MMC_CMDAT __REG(0x41100010) /* Command/response/data sequence control */
-#define MMC_RESTO __REG(0x41100014) /* Expected response time out */
-#define MMC_RDTO __REG(0x41100018) /* Expected data read time out */
-#define MMC_BLKLEN __REG(0x4110001c) /* Block length of data transaction */
-#define MMC_NOB __REG(0x41100020) /* Number of blocks, for block mode */
-#define MMC_PRTBUF __REG(0x41100024) /* Partial MMC_TXFIFO FIFO written */
-#define MMC_I_MASK __REG(0x41100028) /* Interrupt Mask */
-#define MMC_I_REG __REG(0x4110002c) /* Interrupt Register (read only) */
-#define MMC_CMD __REG(0x41100030) /* Index of current command */
-#define MMC_ARGH __REG(0x41100034) /* MSW part of the current command argument */
-#define MMC_ARGL __REG(0x41100038) /* LSW part of the current command argument */
-#define MMC_RES __REG(0x4110003c) /* Response FIFO (read only) */
-#define MMC_RXFIFO __REG(0x41100040) /* Receive FIFO (read only) */
-#define MMC_TXFIFO __REG(0x41100044) /* Transmit FIFO (write only) */
-
-
/*
* Core Clock
*/
diff --git a/include/asm-arm/arch-pxa/udc.h b/include/asm-arm/arch-pxa/udc.h
index 8bc6f9c3e3ea..27aa3a91012f 100644
--- a/include/asm-arm/arch-pxa/udc.h
+++ b/include/asm-arm/arch-pxa/udc.h
@@ -1,41 +1,8 @@
/*
* linux/include/asm-arm/arch-pxa/udc.h
*
- * This supports machine-specific differences in how the PXA2xx
- * USB Device Controller (UDC) is wired.
- *
*/
#include <asm/mach/udc_pxa2xx.h>
extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info);
-static inline int udc_gpio_to_irq(unsigned gpio)
-{
- return IRQ_GPIO(gpio & GPIO_MD_MASK_NR);
-}
-
-static inline void udc_gpio_init_vbus(unsigned gpio)
-{
- pxa_gpio_mode((gpio & GPIO_MD_MASK_NR) | GPIO_IN);
-}
-
-static inline void udc_gpio_init_pullup(unsigned gpio)
-{
- pxa_gpio_mode((gpio & GPIO_MD_MASK_NR) | GPIO_OUT | GPIO_DFLT_LOW);
-}
-
-static inline int udc_gpio_get(unsigned gpio)
-{
- return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
-}
-
-static inline void udc_gpio_set(unsigned gpio, int is_on)
-{
- int mask = GPIO_bit(gpio);
-
- if (is_on)
- GPSR(gpio) = mask;
- else
- GPCR(gpio) = mask;
-}
-
diff --git a/include/asm-arm/arch-s3c2400/map.h b/include/asm-arm/arch-s3c2400/map.h
new file mode 100644
index 000000000000..1184d907b31e
--- /dev/null
+++ b/include/asm-arm/arch-s3c2400/map.h
@@ -0,0 +1,66 @@
+/* linux/include/asm-arm/arch-s3c2400/map.h
+ *
+ * Copyright 2003,2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Copyright 2003, Lucas Correia Villa Real
+ *
+ * S3C2400 - Memory map definitions
+ *
+ * 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.
+*/
+
+#define S3C2400_PA_MEMCTRL (0x14000000)
+#define S3C2400_PA_USBHOST (0x14200000)
+#define S3C2400_PA_IRQ (0x14400000)
+#define S3C2400_PA_DMA (0x14600000)
+#define S3C2400_PA_CLKPWR (0x14800000)
+#define S3C2400_PA_LCD (0x14A00000)
+#define S3C2400_PA_UART (0x15000000)
+#define S3C2400_PA_TIMER (0x15100000)
+#define S3C2400_PA_USBDEV (0x15200140)
+#define S3C2400_PA_WATCHDOG (0x15300000)
+#define S3C2400_PA_IIC (0x15400000)
+#define S3C2400_PA_IIS (0x15508000)
+#define S3C2400_PA_GPIO (0x15600000)
+#define S3C2400_PA_RTC (0x15700040)
+#define S3C2400_PA_ADC (0x15800000)
+#define S3C2400_PA_SPI (0x15900000)
+
+#define S3C2400_PA_MMC (0x15A00000)
+#define S3C2400_SZ_MMC SZ_1M
+
+/* physical addresses of all the chip-select areas */
+
+#define S3C2400_CS0 (0x00000000)
+#define S3C2400_CS1 (0x02000000)
+#define S3C2400_CS2 (0x04000000)
+#define S3C2400_CS3 (0x06000000)
+#define S3C2400_CS4 (0x08000000)
+#define S3C2400_CS5 (0x0A000000)
+#define S3C2400_CS6 (0x0C000000)
+#define S3C2400_CS7 (0x0E000000)
+
+#define S3C2400_SDRAM_PA (S3C2400_CS6)
+
+/* Use a single interface for common resources between S3C24XX cpus */
+
+#define S3C24XX_PA_IRQ S3C2400_PA_IRQ
+#define S3C24XX_PA_MEMCTRL S3C2400_PA_MEMCTRL
+#define S3C24XX_PA_USBHOST S3C2400_PA_USBHOST
+#define S3C24XX_PA_DMA S3C2400_PA_DMA
+#define S3C24XX_PA_CLKPWR S3C2400_PA_CLKPWR
+#define S3C24XX_PA_LCD S3C2400_PA_LCD
+#define S3C24XX_PA_UART S3C2400_PA_UART
+#define S3C24XX_PA_TIMER S3C2400_PA_TIMER
+#define S3C24XX_PA_USBDEV S3C2400_PA_USBDEV
+#define S3C24XX_PA_WATCHDOG S3C2400_PA_WATCHDOG
+#define S3C24XX_PA_IIC S3C2400_PA_IIC
+#define S3C24XX_PA_IIS S3C2400_PA_IIS
+#define S3C24XX_PA_GPIO S3C2400_PA_GPIO
+#define S3C24XX_PA_RTC S3C2400_PA_RTC
+#define S3C24XX_PA_ADC S3C2400_PA_ADC
+#define S3C24XX_PA_SPI S3C2400_PA_SPI
diff --git a/include/asm-arm/arch-s3c2400/memory.h b/include/asm-arm/arch-s3c2400/memory.h
new file mode 100644
index 000000000000..fb0381dde704
--- /dev/null
+++ b/include/asm-arm/arch-s3c2400/memory.h
@@ -0,0 +1,23 @@
+/* linux/include/asm-arm/arch-s3c2400/memory.h
+ * from linux/include/asm-arm/arch-rpc/memory.h
+ *
+ * Copyright 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Copyright (C) 1996,1997,1998 Russell King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+#define PHYS_OFFSET UL(0x0C000000)
+
+#define __virt_to_bus(x) __virt_to_phys(x)
+#define __bus_to_virt(x) __phys_to_virt(x)
+
+#endif
diff --git a/include/asm-arm/arch-s3c2410/debug-macro.S b/include/asm-arm/arch-s3c2410/debug-macro.S
index 93064860e0e5..9c8cd9abb82b 100644
--- a/include/asm-arm/arch-s3c2410/debug-macro.S
+++ b/include/asm-arm/arch-s3c2410/debug-macro.S
@@ -13,32 +13,23 @@
*/
#include <asm/arch/map.h>
-#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
+#include <asm/plat-s3c/regs-serial.h>
#define S3C2410_UART1_OFF (0x4000)
#define SHIFT_2440TXF (14-9)
- .macro addruart, rx
+ .macro addruart, rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1
ldreq \rx, = S3C24XX_PA_UART
ldrne \rx, = S3C24XX_VA_UART
-#if CONFIG_DEBUG_S3C2410_UART != 0
- add \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C2410_UART)
+#if CONFIG_DEBUG_S3C_UART != 0
+ add \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
#endif
- .endm
+ .endm
- .macro senduart,rd,rx
- strb \rd, [\rx, # S3C2410_UTXH ]
- .endm
-
- .macro busyuart, rd, rx
- ldr \rd, [ \rx, # S3C2410_UFCON ]
- tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
- beq 1001f @
- @ FIFO enabled...
-1003:
+ .macro fifo_full_s3c24xx rd, rx
@ check for arm920 vs arm926. currently assume all arm926
@ devices have an 64 byte FIFO identical to the s3c2440
mrc p15, 0, \rd, c0, c0
@@ -57,25 +48,22 @@
ldr \rd, [ \rx, # S3C2410_UFSTAT ]
moveq \rd, \rd, lsr #SHIFT_2440TXF
tst \rd, #S3C2410_UFSTAT_TXFULL
- bne 1003b
- b 1002f
-
-1001:
- @ busy waiting for non fifo
- ldr \rd, [ \rx, # S3C2410_UTRSTAT ]
- tst \rd, #S3C2410_UTRSTAT_TXFE
- beq 1001b
+ .endm
-1002: @ exit busyuart
- .endm
+ .macro fifo_full_s3c2410 rd, rx
+ ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ tst \rd, #S3C2410_UFSTAT_TXFULL
+ .endm
- .macro waituart,rd,rx
+/* fifo level reading */
- ldr \rd, [ \rx, # S3C2410_UFCON ]
- tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
- beq 1001f @
- @ FIFO enabled...
-1003:
+ .macro fifo_level_s3c24xx rd, rx
+ @ check for arm920 vs arm926. currently assume all arm926
+ @ devices have an 64 byte FIFO identical to the s3c2440
+ mrc p15, 0, \rd, c0, c0
+ and \rd, \rd, #0xff0
+ teq \rd, #0x260
+ beq 10000f
mrc p15, 0, \rd, c1, c0
tst \rd, #1
addeq \rd, \rx, #(S3C24XX_PA_GPIO - S3C24XX_PA_UART)
@@ -85,18 +73,32 @@
and \rd, \rd, #0x00ff0000
teq \rd, #0x00440000 @ is it 2440?
+10000:
ldr \rd, [ \rx, # S3C2410_UFSTAT ]
andne \rd, \rd, #S3C2410_UFSTAT_TXMASK
andeq \rd, \rd, #S3C2440_UFSTAT_TXMASK
- teq \rd, #0
- bne 1003b
- b 1002f
+ .endm
+
+ .macro fifo_level_s3c2410 rd, rx
+ ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ and \rd, \rd, #S3C2410_UFSTAT_TXMASK
+ .endm
+
+/* Select the correct implementation depending on the configuration. The
+ * S3C2440 will get selected by default, as these are the most widely
+ * used variants of these
+*/
+
+#if defined(CONFIG_CPU_LLSERIAL_S3C2410_ONLY)
+#define fifo_full fifo_full_s3c2410
+#define fifo_level fifo_level_s3c2410
+#warning 2410only
+#elif !defined(CONFIG_CPU_LLSERIAL_S3C2440_ONLY)
+#define fifo_full fifo_full_s3c24xx
+#define fifo_level fifo_level_s3c24xx
+#warning generic
+#endif
-1001:
- @ idle waiting for non fifo
- ldr \rd, [ \rx, # S3C2410_UTRSTAT ]
- tst \rd, #S3C2410_UTRSTAT_TXFE
- beq 1001b
+/* include the reset of the code which will do the work */
-1002: @ exit busyuart
- .endm
+#include <asm/plat-s3c/debug-macro.S>
diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h
index 19e77f038042..b33ed3b05ef5 100644
--- a/include/asm-arm/arch-s3c2410/map.h
+++ b/include/asm-arm/arch-s3c2410/map.h
@@ -13,58 +13,36 @@
#ifndef __ASM_ARCH_MAP_H
#define __ASM_ARCH_MAP_H
-/* we have a bit of a tight squeeze to fit all our registers from
- * 0xF00000000 upwards, since we use all of the nGCS space in some
- * capacity, and also need to fit the S3C2410 registers in as well...
- *
- * we try to ensure stuff like the IRQ registers are available for
- * an single MOVS instruction (ie, only 8 bits of set data)
- *
- * Note, we are trying to remove some of these from the implementation
- * as they are only useful to certain drivers...
- */
-
-#ifndef __ASSEMBLY__
-#define S3C2410_ADDR(x) ((void __iomem __force *)0xF0000000 + (x))
-#else
-#define S3C2410_ADDR(x) (0xF0000000 + (x))
-#endif
+#include <asm/plat-s3c/map.h>
-#define S3C2400_ADDR(x) S3C2410_ADDR(x)
+#define S3C2410_ADDR(x) S3C_ADDR(x)
/* interrupt controller is the first thing we put in, to make
* the assembly code for the irq detection easier
*/
-#define S3C24XX_VA_IRQ S3C2410_ADDR(0x00000000)
-#define S3C2400_PA_IRQ (0x14400000)
+#define S3C24XX_VA_IRQ S3C_VA_IRQ
#define S3C2410_PA_IRQ (0x4A000000)
#define S3C24XX_SZ_IRQ SZ_1M
/* memory controller registers */
-#define S3C24XX_VA_MEMCTRL S3C2410_ADDR(0x00100000)
-#define S3C2400_PA_MEMCTRL (0x14000000)
+#define S3C24XX_VA_MEMCTRL S3C_VA_MEM
#define S3C2410_PA_MEMCTRL (0x48000000)
#define S3C24XX_SZ_MEMCTRL SZ_1M
/* USB host controller */
-#define S3C2400_PA_USBHOST (0x14200000)
#define S3C2410_PA_USBHOST (0x49000000)
#define S3C24XX_SZ_USBHOST SZ_1M
/* DMA controller */
-#define S3C2400_PA_DMA (0x14600000)
#define S3C2410_PA_DMA (0x4B000000)
#define S3C24XX_SZ_DMA SZ_1M
/* Clock and Power management */
-#define S3C24XX_VA_CLKPWR S3C2410_ADDR(0x00200000)
-#define S3C2400_PA_CLKPWR (0x14800000)
+#define S3C24XX_VA_CLKPWR S3C_VA_SYS
#define S3C2410_PA_CLKPWR (0x4C000000)
#define S3C24XX_SZ_CLKPWR SZ_1M
/* LCD controller */
-#define S3C24XX_VA_LCD S3C2410_ADDR(0x00300000)
-#define S3C2400_PA_LCD (0x14A00000)
#define S3C2410_PA_LCD (0x4D000000)
#define S3C24XX_SZ_LCD SZ_1M
@@ -72,41 +50,30 @@
#define S3C2410_PA_NAND (0x4E000000)
#define S3C24XX_SZ_NAND SZ_1M
-/* MMC controller - available on the S3C2400 */
-#define S3C2400_PA_MMC (0x15A00000)
-#define S3C2400_SZ_MMC SZ_1M
-
/* UARTs */
-#define S3C24XX_VA_UART S3C2410_ADDR(0x00400000)
-#define S3C2400_PA_UART (0x15000000)
+#define S3C24XX_VA_UART S3C_VA_UART
#define S3C2410_PA_UART (0x50000000)
#define S3C24XX_SZ_UART SZ_1M
/* Timers */
-#define S3C24XX_VA_TIMER S3C2410_ADDR(0x00500000)
-#define S3C2400_PA_TIMER (0x15100000)
+#define S3C24XX_VA_TIMER S3C_VA_TIMER
#define S3C2410_PA_TIMER (0x51000000)
#define S3C24XX_SZ_TIMER SZ_1M
/* USB Device port */
-#define S3C24XX_VA_USBDEV S3C2410_ADDR(0x00600000)
-#define S3C2400_PA_USBDEV (0x15200140)
#define S3C2410_PA_USBDEV (0x52000000)
#define S3C24XX_SZ_USBDEV SZ_1M
/* Watchdog */
-#define S3C24XX_VA_WATCHDOG S3C2410_ADDR(0x00700000)
-#define S3C2400_PA_WATCHDOG (0x15300000)
+#define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG
#define S3C2410_PA_WATCHDOG (0x53000000)
#define S3C24XX_SZ_WATCHDOG SZ_1M
/* IIC hardware controller */
-#define S3C2400_PA_IIC (0x15400000)
#define S3C2410_PA_IIC (0x54000000)
#define S3C24XX_SZ_IIC SZ_1M
/* IIS controller */
-#define S3C2400_PA_IIS (0x15508000)
#define S3C2410_PA_IIS (0x55000000)
#define S3C24XX_SZ_IIS SZ_1M
@@ -116,27 +83,23 @@
* it is the same distance apart from the UART in the
* phsyical address space, as the initial mapping for the IO
* is done as a 1:1 maping. This puts it (currently) at
- * 0xF6800000, which is not in the way of any current mapping
+ * 0xFA800000, which is not in the way of any current mapping
* by the base system.
*/
-#define S3C2400_PA_GPIO (0x15600000)
#define S3C2410_PA_GPIO (0x56000000)
#define S3C24XX_VA_GPIO ((S3C2410_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
#define S3C24XX_SZ_GPIO SZ_1M
/* RTC */
-#define S3C2400_PA_RTC (0x15700040)
#define S3C2410_PA_RTC (0x57000000)
#define S3C24XX_SZ_RTC SZ_1M
/* ADC */
-#define S3C2400_PA_ADC (0x15800000)
#define S3C2410_PA_ADC (0x58000000)
#define S3C24XX_SZ_ADC SZ_1M
/* SPI */
-#define S3C2400_PA_SPI (0x15900000)
#define S3C2410_PA_SPI (0x59000000)
#define S3C24XX_SZ_SPI SZ_1M
@@ -177,37 +140,8 @@
#define S3C2410_SDRAM_PA (S3C2410_CS6)
-#define S3C2400_CS0 (0x00000000)
-#define S3C2400_CS1 (0x02000000)
-#define S3C2400_CS2 (0x04000000)
-#define S3C2400_CS3 (0x06000000)
-#define S3C2400_CS4 (0x08000000)
-#define S3C2400_CS5 (0x0A000000)
-#define S3C2400_CS6 (0x0C000000)
-#define S3C2400_CS7 (0x0E000000)
-
-#define S3C2400_SDRAM_PA (S3C2400_CS6)
-
/* Use a single interface for common resources between S3C24XX cpus */
-#ifdef CONFIG_CPU_S3C2400
-#define S3C24XX_PA_IRQ S3C2400_PA_IRQ
-#define S3C24XX_PA_MEMCTRL S3C2400_PA_MEMCTRL
-#define S3C24XX_PA_USBHOST S3C2400_PA_USBHOST
-#define S3C24XX_PA_DMA S3C2400_PA_DMA
-#define S3C24XX_PA_CLKPWR S3C2400_PA_CLKPWR
-#define S3C24XX_PA_LCD S3C2400_PA_LCD
-#define S3C24XX_PA_UART S3C2400_PA_UART
-#define S3C24XX_PA_TIMER S3C2400_PA_TIMER
-#define S3C24XX_PA_USBDEV S3C2400_PA_USBDEV
-#define S3C24XX_PA_WATCHDOG S3C2400_PA_WATCHDOG
-#define S3C24XX_PA_IIC S3C2400_PA_IIC
-#define S3C24XX_PA_IIS S3C2400_PA_IIS
-#define S3C24XX_PA_GPIO S3C2400_PA_GPIO
-#define S3C24XX_PA_RTC S3C2400_PA_RTC
-#define S3C24XX_PA_ADC S3C2400_PA_ADC
-#define S3C24XX_PA_SPI S3C2400_PA_SPI
-#else
#define S3C24XX_PA_IRQ S3C2410_PA_IRQ
#define S3C24XX_PA_MEMCTRL S3C2410_PA_MEMCTRL
#define S3C24XX_PA_USBHOST S3C2410_PA_USBHOST
@@ -224,7 +158,6 @@
#define S3C24XX_PA_RTC S3C2410_PA_RTC
#define S3C24XX_PA_ADC S3C2410_PA_ADC
#define S3C24XX_PA_SPI S3C2410_PA_SPI
-#endif
/* deal with the registers that move under the 2412/2413 */
diff --git a/include/asm-arm/arch-s3c2410/memory.h b/include/asm-arm/arch-s3c2410/memory.h
index 4be6a74c4303..533e2436e707 100644
--- a/include/asm-arm/arch-s3c2410/memory.h
+++ b/include/asm-arm/arch-s3c2410/memory.h
@@ -11,20 +11,7 @@
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
-/*
- * DRAM starts at 0x30000000 for S3C2410/S3C2440
- * and at 0x0C000000 for S3C2400
- */
-#ifdef CONFIG_CPU_S3C2400
-#define PHYS_OFFSET UL(0x0C000000)
-#else
#define PHYS_OFFSET UL(0x30000000)
-#endif
-
-/*
- * These are exactly the same on the S3C2410 as the
- * physical memory view.
-*/
#define __virt_to_bus(x) __virt_to_phys(x)
#define __bus_to_virt(x) __phys_to_virt(x)
diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h
index b7faeb04c0ff..76fe5f693426 100644
--- a/include/asm-arm/arch-s3c2410/regs-lcd.h
+++ b/include/asm-arm/arch-s3c2410/regs-lcd.h
@@ -12,7 +12,7 @@
#ifndef ___ASM_ARCH_REGS_LCD_H
#define ___ASM_ARCH_REGS_LCD_H "$Id: lcd.h,v 1.3 2003/06/26 13:25:06 ben Exp $"
-#define S3C2410_LCDREG(x) ((x) + S3C24XX_VA_LCD)
+#define S3C2410_LCDREG(x) (x)
/* LCD control registers */
#define S3C2410_LCDCON1 S3C2410_LCDREG(0x00)
diff --git a/include/asm-arm/arch-s3c2410/system.h b/include/asm-arm/arch-s3c2410/system.h
index 1c74ef17da33..63891786dfa0 100644
--- a/include/asm-arm/arch-s3c2410/system.h
+++ b/include/asm-arm/arch-s3c2410/system.h
@@ -17,7 +17,7 @@
#include <asm/arch/idle.h>
#include <asm/arch/reset.h>
-#include <asm/arch/regs-watchdog.h>
+#include <asm/plat-s3c/regs-watchdog.h>
#include <asm/arch/regs-clock.h>
void (*s3c24xx_idle)(void);
diff --git a/include/asm-arm/arch-s3c2410/uncompress.h b/include/asm-arm/arch-s3c2410/uncompress.h
index dcb2cef38f50..48a5731ee988 100644
--- a/include/asm-arm/arch-s3c2410/uncompress.h
+++ b/include/asm-arm/arch-s3c2410/uncompress.h
@@ -1,6 +1,7 @@
/* linux/include/asm-arm/arch-s3c2410/uncompress.h
*
- * Copyright (c) 2003 Simtec Electronics
+ * Copyright (c) 2003, 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - uncompress code
@@ -13,153 +14,39 @@
#ifndef __ASM_ARCH_UNCOMPRESS_H
#define __ASM_ARCH_UNCOMPRESS_H
-typedef unsigned int upf_t; /* cannot include linux/serial_core.h */
-
-/* defines for UART registers */
-#include "asm/arch/regs-serial.h"
-#include "asm/arch/regs-gpio.h"
-#include "asm/arch/regs-watchdog.h"
-
+#include <asm/arch/regs-gpio.h>
#include <asm/arch/map.h>
/* working in physical space... */
#undef S3C2410_GPIOREG
-#undef S3C2410_WDOGREG
-
#define S3C2410_GPIOREG(x) ((S3C24XX_PA_GPIO + (x)))
-#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x)))
-/* how many bytes we allow into the FIFO at a time in FIFO mode */
-#define FIFO_MAX (14)
+#include <asm/plat-s3c/uncompress.h>
-#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C2410_LOWLEVEL_UART_PORT)
-
-static __inline__ void
-uart_wr(unsigned int reg, unsigned int val)
+static inline int is_arm926(void)
{
- volatile unsigned int *ptr;
-
- ptr = (volatile unsigned int *)(reg + uart_base);
- *ptr = val;
-}
+ unsigned int cpuid;
-static __inline__ unsigned int
-uart_rd(unsigned int reg)
-{
- volatile unsigned int *ptr;
+ asm volatile ("mrc p15, 0, %0, c1, c0, 0" : "=r" (cpuid));
- ptr = (volatile unsigned int *)(reg + uart_base);
- return *ptr;
+ return ((cpuid & 0xff0) == 0x260);
}
-
-/* we can deal with the case the UARTs are being run
- * in FIFO mode, so that we don't hold up our execution
- * waiting for tx to happen...
-*/
-
-static void putc(int ch)
+static void arch_detect_cpu(void)
{
- int cpuid = S3C2410_GSTATUS1_2410;
+ unsigned int cpuid;
-#ifndef CONFIG_CPU_S3C2400
cpuid = *((volatile unsigned int *)S3C2410_GSTATUS1);
cpuid &= S3C2410_GSTATUS1_IDMASK;
-#endif
-
- if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
- int level;
-
- while (1) {
- level = uart_rd(S3C2410_UFSTAT);
-
- if (cpuid == S3C2410_GSTATUS1_2440 ||
- cpuid == S3C2410_GSTATUS1_2442) {
- level &= S3C2440_UFSTAT_TXMASK;
- level >>= S3C2440_UFSTAT_TXSHIFT;
- } else {
- level &= S3C2410_UFSTAT_TXMASK;
- level >>= S3C2410_UFSTAT_TXSHIFT;
- }
-
- if (level < FIFO_MAX)
- break;
- }
+ if (is_arm926() || cpuid == S3C2410_GSTATUS1_2440 ||
+ cpuid == S3C2410_GSTATUS1_2442) {
+ fifo_mask = S3C2440_UFSTAT_TXMASK;
+ fifo_max = 63 << S3C2440_UFSTAT_TXSHIFT;
} else {
- /* not using fifos */
-
- while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)
- barrier();
+ fifo_mask = S3C2410_UFSTAT_TXMASK;
+ fifo_max = 15 << S3C2410_UFSTAT_TXSHIFT;
}
-
- /* write byte to transmission register */
- uart_wr(S3C2410_UTXH, ch);
}
-static inline void flush(void)
-{
-}
-
-#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
-
-/* CONFIG_S3C2410_BOOT_WATCHDOG
- *
- * Simple boot-time watchdog setup, to reboot the system if there is
- * any problem with the boot process
-*/
-
-#ifdef CONFIG_S3C2410_BOOT_WATCHDOG
-
-#define WDOG_COUNT (0xff00)
-
-static inline void arch_decomp_wdog(void)
-{
- __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
-}
-
-static void arch_decomp_wdog_start(void)
-{
- __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
- __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
- __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
-}
-
-#else
-#define arch_decomp_wdog_start()
-#define arch_decomp_wdog()
-#endif
-
-#ifdef CONFIG_S3C2410_BOOT_ERROR_RESET
-
-static void arch_decomp_error(const char *x)
-{
- putstr("\n\n");
- putstr(x);
- putstr("\n\n -- System resetting\n");
-
- __raw_writel(0x4000, S3C2410_WTDAT);
- __raw_writel(0x4000, S3C2410_WTCNT);
- __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
-
- while(1);
-}
-
-#define arch_error arch_decomp_error
-#endif
-
-static void error(char *err);
-
-static void
-arch_decomp_setup(void)
-{
- /* we may need to setup the uart(s) here if we are not running
- * on an BAST... the BAST will have left the uarts configured
- * after calling linux.
- */
-
- arch_decomp_wdog_start();
-}
-
-
#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/include/asm-arm/arch-sa1100/jornada720.h b/include/asm-arm/arch-sa1100/jornada720.h
new file mode 100644
index 000000000000..45d2bb59f9d0
--- /dev/null
+++ b/include/asm-arm/arch-sa1100/jornada720.h
@@ -0,0 +1,27 @@
+/*
+ * include/asm-arm/arch-sa1100/jornada720.h
+ *
+ * This file contains SSP/MCU communication definitions for HP Jornada 710/720/728
+ *
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ * Copyright (C) 2000 John Ankcorn <jca@lcs.mit.edu>
+ *
+ * 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.
+ *
+ */
+
+ /* HP Jornada 7xx microprocessor commands */
+#define GETBATTERYDATA 0xc0
+#define GETSCANKEYCODE 0x90
+#define GETTOUCHSAMPLES 0xa0
+#define GETCONTRAST 0xD0
+#define SETCONTRAST 0xD1
+#define GETBRIGHTNESS 0xD2
+#define SETBRIGHTNESS 0xD3
+#define CONTRASTOFF 0xD8
+#define BRIGHTNESSOFF 0xD9
+#define PWMOFF 0xDF
+#define TXDUMMY 0x11
+#define ERRORCODE 0x00
diff --git a/include/asm-arm/elf.h b/include/asm-arm/elf.h
index 3679a8a8922e..ec1c685562ce 100644
--- a/include/asm-arm/elf.h
+++ b/include/asm-arm/elf.h
@@ -1,6 +1,8 @@
#ifndef __ASMARM_ELF_H
#define __ASMARM_ELF_H
+#include <asm/hwcap.h>
+
#ifndef __ASSEMBLY__
/*
* ELF register definitions..
@@ -39,31 +41,9 @@ typedef struct user_fp elf_fpregset_t;
#endif
#define ELF_ARCH EM_ARM
-/*
- * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
- */
-#define HWCAP_SWP 1
-#define HWCAP_HALF 2
-#define HWCAP_THUMB 4
-#define HWCAP_26BIT 8 /* Play it safe */
-#define HWCAP_FAST_MULT 16
-#define HWCAP_FPA 32
-#define HWCAP_VFP 64
-#define HWCAP_EDSP 128
-#define HWCAP_JAVA 256
-#define HWCAP_IWMMXT 512
-#define HWCAP_CRUNCH 1024
-
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
/*
- * This yields a mask that user programs can use to figure out what
- * instruction set this cpu supports.
- */
-#define ELF_HWCAP (elf_hwcap)
-extern unsigned int elf_hwcap;
-
-/*
* This yields a string that ld.so will use to load implementation
* specific libraries for optimization. This is more specific in
* intent than poking at uname or /proc/cpuinfo.
diff --git a/include/asm-arm/fb.h b/include/asm-arm/fb.h
new file mode 100644
index 000000000000..d92e99cd8c8a
--- /dev/null
+++ b/include/asm-arm/fb.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-arm/floppy.h b/include/asm-arm/floppy.h
index 54b5ae44ed94..d595c15166a4 100644
--- a/include/asm-arm/floppy.h
+++ b/include/asm-arm/floppy.h
@@ -30,15 +30,21 @@
#define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK)
#define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK)
+static inline int fd_dma_setup(void *data, unsigned int length,
+ unsigned int mode, unsigned long addr)
+{
+ set_dma_mode(DMA_FLOPPY, mode);
+ __set_dma_addr(DMA_FLOPPY, data);
+ set_dma_count(DMA_FLOPPY, length);
+ virtual_dma_port = addr;
+ enable_dma(DMA_FLOPPY);
+ return 0;
+}
+#define fd_dma_setup fd_dma_setup
+
#define fd_request_dma() request_dma(DMA_FLOPPY,"floppy")
#define fd_free_dma() free_dma(DMA_FLOPPY)
#define fd_disable_dma() disable_dma(DMA_FLOPPY)
-#define fd_enable_dma() enable_dma(DMA_FLOPPY)
-#define fd_clear_dma_ff() clear_dma_ff(DMA_FLOPPY)
-#define fd_set_dma_mode(mode) set_dma_mode(DMA_FLOPPY, (mode))
-#define fd_set_dma_addr(addr) set_dma_addr(DMA_FLOPPY, virt_to_bus((addr)))
-#define fd_set_dma_count(len) set_dma_count(DMA_FLOPPY, (len))
-#define fd_cacheflush(addr,sz)
/* need to clean up dma.h */
#define DMA_FLOPPYDISK DMA_FLOPPY
diff --git a/include/asm-arm/hardware/iop3xx-adma.h b/include/asm-arm/hardware/iop3xx-adma.h
new file mode 100644
index 000000000000..10834b54f681
--- /dev/null
+++ b/include/asm-arm/hardware/iop3xx-adma.h
@@ -0,0 +1,892 @@
+/*
+ * Copyright © 2006, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _ADMA_H
+#define _ADMA_H
+#include <linux/types.h>
+#include <linux/io.h>
+#include <asm/hardware.h>
+#include <asm/hardware/iop_adma.h>
+
+/* Memory copy units */
+#define DMA_CCR(chan) (chan->mmr_base + 0x0)
+#define DMA_CSR(chan) (chan->mmr_base + 0x4)
+#define DMA_DAR(chan) (chan->mmr_base + 0xc)
+#define DMA_NDAR(chan) (chan->mmr_base + 0x10)
+#define DMA_PADR(chan) (chan->mmr_base + 0x14)
+#define DMA_PUADR(chan) (chan->mmr_base + 0x18)
+#define DMA_LADR(chan) (chan->mmr_base + 0x1c)
+#define DMA_BCR(chan) (chan->mmr_base + 0x20)
+#define DMA_DCR(chan) (chan->mmr_base + 0x24)
+
+/* Application accelerator unit */
+#define AAU_ACR(chan) (chan->mmr_base + 0x0)
+#define AAU_ASR(chan) (chan->mmr_base + 0x4)
+#define AAU_ADAR(chan) (chan->mmr_base + 0x8)
+#define AAU_ANDAR(chan) (chan->mmr_base + 0xc)
+#define AAU_SAR(src, chan) (chan->mmr_base + (0x10 + ((src) << 2)))
+#define AAU_DAR(chan) (chan->mmr_base + 0x20)
+#define AAU_ABCR(chan) (chan->mmr_base + 0x24)
+#define AAU_ADCR(chan) (chan->mmr_base + 0x28)
+#define AAU_SAR_EDCR(src_edc) (chan->mmr_base + (0x02c + ((src_edc-4) << 2)))
+#define AAU_EDCR0_IDX 8
+#define AAU_EDCR1_IDX 17
+#define AAU_EDCR2_IDX 26
+
+#define DMA0_ID 0
+#define DMA1_ID 1
+#define AAU_ID 2
+
+struct iop3xx_aau_desc_ctrl {
+ unsigned int int_en:1;
+ unsigned int blk1_cmd_ctrl:3;
+ unsigned int blk2_cmd_ctrl:3;
+ unsigned int blk3_cmd_ctrl:3;
+ unsigned int blk4_cmd_ctrl:3;
+ unsigned int blk5_cmd_ctrl:3;
+ unsigned int blk6_cmd_ctrl:3;
+ unsigned int blk7_cmd_ctrl:3;
+ unsigned int blk8_cmd_ctrl:3;
+ unsigned int blk_ctrl:2;
+ unsigned int dual_xor_en:1;
+ unsigned int tx_complete:1;
+ unsigned int zero_result_err:1;
+ unsigned int zero_result_en:1;
+ unsigned int dest_write_en:1;
+};
+
+struct iop3xx_aau_e_desc_ctrl {
+ unsigned int reserved:1;
+ unsigned int blk1_cmd_ctrl:3;
+ unsigned int blk2_cmd_ctrl:3;
+ unsigned int blk3_cmd_ctrl:3;
+ unsigned int blk4_cmd_ctrl:3;
+ unsigned int blk5_cmd_ctrl:3;
+ unsigned int blk6_cmd_ctrl:3;
+ unsigned int blk7_cmd_ctrl:3;
+ unsigned int blk8_cmd_ctrl:3;
+ unsigned int reserved2:7;
+};
+
+struct iop3xx_dma_desc_ctrl {
+ unsigned int pci_transaction:4;
+ unsigned int int_en:1;
+ unsigned int dac_cycle_en:1;
+ unsigned int mem_to_mem_en:1;
+ unsigned int crc_data_tx_en:1;
+ unsigned int crc_gen_en:1;
+ unsigned int crc_seed_dis:1;
+ unsigned int reserved:21;
+ unsigned int crc_tx_complete:1;
+};
+
+struct iop3xx_desc_dma {
+ u32 next_desc;
+ union {
+ u32 pci_src_addr;
+ u32 pci_dest_addr;
+ u32 src_addr;
+ };
+ union {
+ u32 upper_pci_src_addr;
+ u32 upper_pci_dest_addr;
+ };
+ union {
+ u32 local_pci_src_addr;
+ u32 local_pci_dest_addr;
+ u32 dest_addr;
+ };
+ u32 byte_count;
+ union {
+ u32 desc_ctrl;
+ struct iop3xx_dma_desc_ctrl desc_ctrl_field;
+ };
+ u32 crc_addr;
+};
+
+struct iop3xx_desc_aau {
+ u32 next_desc;
+ u32 src[4];
+ u32 dest_addr;
+ u32 byte_count;
+ union {
+ u32 desc_ctrl;
+ struct iop3xx_aau_desc_ctrl desc_ctrl_field;
+ };
+ union {
+ u32 src_addr;
+ u32 e_desc_ctrl;
+ struct iop3xx_aau_e_desc_ctrl e_desc_ctrl_field;
+ } src_edc[31];
+};
+
+struct iop3xx_aau_gfmr {
+ unsigned int gfmr1:8;
+ unsigned int gfmr2:8;
+ unsigned int gfmr3:8;
+ unsigned int gfmr4:8;
+};
+
+struct iop3xx_desc_pq_xor {
+ u32 next_desc;
+ u32 src[3];
+ union {
+ u32 data_mult1;
+ struct iop3xx_aau_gfmr data_mult1_field;
+ };
+ u32 dest_addr;
+ u32 byte_count;
+ union {
+ u32 desc_ctrl;
+ struct iop3xx_aau_desc_ctrl desc_ctrl_field;
+ };
+ union {
+ u32 src_addr;
+ u32 e_desc_ctrl;
+ struct iop3xx_aau_e_desc_ctrl e_desc_ctrl_field;
+ u32 data_multiplier;
+ struct iop3xx_aau_gfmr data_mult_field;
+ u32 reserved;
+ } src_edc_gfmr[19];
+};
+
+struct iop3xx_desc_dual_xor {
+ u32 next_desc;
+ u32 src0_addr;
+ u32 src1_addr;
+ u32 h_src_addr;
+ u32 d_src_addr;
+ u32 h_dest_addr;
+ u32 byte_count;
+ union {
+ u32 desc_ctrl;
+ struct iop3xx_aau_desc_ctrl desc_ctrl_field;
+ };
+ u32 d_dest_addr;
+};
+
+union iop3xx_desc {
+ struct iop3xx_desc_aau *aau;
+ struct iop3xx_desc_dma *dma;
+ struct iop3xx_desc_pq_xor *pq_xor;
+ struct iop3xx_desc_dual_xor *dual_xor;
+ void *ptr;
+};
+
+static inline int iop_adma_get_max_xor(void)
+{
+ return 32;
+}
+
+static inline u32 iop_chan_get_current_descriptor(struct iop_adma_chan *chan)
+{
+ int id = chan->device->id;
+
+ switch (id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return __raw_readl(DMA_DAR(chan));
+ case AAU_ID:
+ return __raw_readl(AAU_ADAR(chan));
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+static inline void iop_chan_set_next_descriptor(struct iop_adma_chan *chan,
+ u32 next_desc_addr)
+{
+ int id = chan->device->id;
+
+ switch (id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ __raw_writel(next_desc_addr, DMA_NDAR(chan));
+ break;
+ case AAU_ID:
+ __raw_writel(next_desc_addr, AAU_ANDAR(chan));
+ break;
+ }
+
+}
+
+#define IOP_ADMA_STATUS_BUSY (1 << 10)
+#define IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT (1024)
+#define IOP_ADMA_XOR_MAX_BYTE_COUNT (16 * 1024 * 1024)
+#define IOP_ADMA_MAX_BYTE_COUNT (16 * 1024 * 1024)
+
+static inline int iop_chan_is_busy(struct iop_adma_chan *chan)
+{
+ u32 status = __raw_readl(DMA_CSR(chan));
+ return (status & IOP_ADMA_STATUS_BUSY) ? 1 : 0;
+}
+
+static inline int iop_desc_is_aligned(struct iop_adma_desc_slot *desc,
+ int num_slots)
+{
+ /* num_slots will only ever be 1, 2, 4, or 8 */
+ return (desc->idx & (num_slots - 1)) ? 0 : 1;
+}
+
+/* to do: support large (i.e. > hw max) buffer sizes */
+static inline int iop_chan_memcpy_slot_count(size_t len, int *slots_per_op)
+{
+ *slots_per_op = 1;
+ return 1;
+}
+
+/* to do: support large (i.e. > hw max) buffer sizes */
+static inline int iop_chan_memset_slot_count(size_t len, int *slots_per_op)
+{
+ *slots_per_op = 1;
+ return 1;
+}
+
+static inline int iop3xx_aau_xor_slot_count(size_t len, int src_cnt,
+ int *slots_per_op)
+{
+ const static int slot_count_table[] = { 0,
+ 1, 1, 1, 1, /* 01 - 04 */
+ 2, 2, 2, 2, /* 05 - 08 */
+ 4, 4, 4, 4, /* 09 - 12 */
+ 4, 4, 4, 4, /* 13 - 16 */
+ 8, 8, 8, 8, /* 17 - 20 */
+ 8, 8, 8, 8, /* 21 - 24 */
+ 8, 8, 8, 8, /* 25 - 28 */
+ 8, 8, 8, 8, /* 29 - 32 */
+ };
+ *slots_per_op = slot_count_table[src_cnt];
+ return *slots_per_op;
+}
+
+static inline int
+iop_chan_interrupt_slot_count(int *slots_per_op, struct iop_adma_chan *chan)
+{
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return iop_chan_memcpy_slot_count(0, slots_per_op);
+ case AAU_ID:
+ return iop3xx_aau_xor_slot_count(0, 2, slots_per_op);
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+static inline int iop_chan_xor_slot_count(size_t len, int src_cnt,
+ int *slots_per_op)
+{
+ int slot_cnt = iop3xx_aau_xor_slot_count(len, src_cnt, slots_per_op);
+
+ if (len <= IOP_ADMA_XOR_MAX_BYTE_COUNT)
+ return slot_cnt;
+
+ len -= IOP_ADMA_XOR_MAX_BYTE_COUNT;
+ while (len > IOP_ADMA_XOR_MAX_BYTE_COUNT) {
+ len -= IOP_ADMA_XOR_MAX_BYTE_COUNT;
+ slot_cnt += *slots_per_op;
+ }
+
+ if (len)
+ slot_cnt += *slots_per_op;
+
+ return slot_cnt;
+}
+
+/* zero sum on iop3xx is limited to 1k at a time so it requires multiple
+ * descriptors
+ */
+static inline int iop_chan_zero_sum_slot_count(size_t len, int src_cnt,
+ int *slots_per_op)
+{
+ int slot_cnt = iop3xx_aau_xor_slot_count(len, src_cnt, slots_per_op);
+
+ if (len <= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT)
+ return slot_cnt;
+
+ len -= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT;
+ while (len > IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT) {
+ len -= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT;
+ slot_cnt += *slots_per_op;
+ }
+
+ if (len)
+ slot_cnt += *slots_per_op;
+
+ return slot_cnt;
+}
+
+static inline u32 iop_desc_get_dest_addr(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan)
+{
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return hw_desc.dma->dest_addr;
+ case AAU_ID:
+ return hw_desc.aau->dest_addr;
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+static inline u32 iop_desc_get_byte_count(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan)
+{
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return hw_desc.dma->byte_count;
+ case AAU_ID:
+ return hw_desc.aau->byte_count;
+ default:
+ BUG();
+ }
+ return 0;
+}
+
+/* translate the src_idx to a descriptor word index */
+static inline int __desc_idx(int src_idx)
+{
+ const static int desc_idx_table[] = { 0, 0, 0, 0,
+ 0, 1, 2, 3,
+ 5, 6, 7, 8,
+ 9, 10, 11, 12,
+ 14, 15, 16, 17,
+ 18, 19, 20, 21,
+ 23, 24, 25, 26,
+ 27, 28, 29, 30,
+ };
+
+ return desc_idx_table[src_idx];
+}
+
+static inline u32 iop_desc_get_src_addr(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan,
+ int src_idx)
+{
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return hw_desc.dma->src_addr;
+ case AAU_ID:
+ break;
+ default:
+ BUG();
+ }
+
+ if (src_idx < 4)
+ return hw_desc.aau->src[src_idx];
+ else
+ return hw_desc.aau->src_edc[__desc_idx(src_idx)].src_addr;
+}
+
+static inline void iop3xx_aau_desc_set_src_addr(struct iop3xx_desc_aau *hw_desc,
+ int src_idx, dma_addr_t addr)
+{
+ if (src_idx < 4)
+ hw_desc->src[src_idx] = addr;
+ else
+ hw_desc->src_edc[__desc_idx(src_idx)].src_addr = addr;
+}
+
+static inline void
+iop_desc_init_memcpy(struct iop_adma_desc_slot *desc, int int_en)
+{
+ struct iop3xx_desc_dma *hw_desc = desc->hw_desc;
+ union {
+ u32 value;
+ struct iop3xx_dma_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ u_desc_ctrl.field.mem_to_mem_en = 1;
+ u_desc_ctrl.field.pci_transaction = 0xe; /* memory read block */
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+ hw_desc->upper_pci_src_addr = 0;
+ hw_desc->crc_addr = 0;
+}
+
+static inline void
+iop_desc_init_memset(struct iop_adma_desc_slot *desc, int int_en)
+{
+ struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
+ union {
+ u32 value;
+ struct iop3xx_aau_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ u_desc_ctrl.field.blk1_cmd_ctrl = 0x2; /* memory block fill */
+ u_desc_ctrl.field.dest_write_en = 1;
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+}
+
+static inline u32
+iop3xx_desc_init_xor(struct iop3xx_desc_aau *hw_desc, int src_cnt, int int_en)
+{
+ int i, shift;
+ u32 edcr;
+ union {
+ u32 value;
+ struct iop3xx_aau_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ switch (src_cnt) {
+ case 25 ... 32:
+ u_desc_ctrl.field.blk_ctrl = 0x3; /* use EDCR[2:0] */
+ edcr = 0;
+ shift = 1;
+ for (i = 24; i < src_cnt; i++) {
+ edcr |= (1 << shift);
+ shift += 3;
+ }
+ hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = edcr;
+ src_cnt = 24;
+ /* fall through */
+ case 17 ... 24:
+ if (!u_desc_ctrl.field.blk_ctrl) {
+ hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = 0;
+ u_desc_ctrl.field.blk_ctrl = 0x3; /* use EDCR[2:0] */
+ }
+ edcr = 0;
+ shift = 1;
+ for (i = 16; i < src_cnt; i++) {
+ edcr |= (1 << shift);
+ shift += 3;
+ }
+ hw_desc->src_edc[AAU_EDCR1_IDX].e_desc_ctrl = edcr;
+ src_cnt = 16;
+ /* fall through */
+ case 9 ... 16:
+ if (!u_desc_ctrl.field.blk_ctrl)
+ u_desc_ctrl.field.blk_ctrl = 0x2; /* use EDCR0 */
+ edcr = 0;
+ shift = 1;
+ for (i = 8; i < src_cnt; i++) {
+ edcr |= (1 << shift);
+ shift += 3;
+ }
+ hw_desc->src_edc[AAU_EDCR0_IDX].e_desc_ctrl = edcr;
+ src_cnt = 8;
+ /* fall through */
+ case 2 ... 8:
+ shift = 1;
+ for (i = 0; i < src_cnt; i++) {
+ u_desc_ctrl.value |= (1 << shift);
+ shift += 3;
+ }
+
+ if (!u_desc_ctrl.field.blk_ctrl && src_cnt > 4)
+ u_desc_ctrl.field.blk_ctrl = 0x1; /* use mini-desc */
+ }
+
+ u_desc_ctrl.field.dest_write_en = 1;
+ u_desc_ctrl.field.blk1_cmd_ctrl = 0x7; /* direct fill */
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+
+ return u_desc_ctrl.value;
+}
+
+static inline void
+iop_desc_init_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+{
+ iop3xx_desc_init_xor(desc->hw_desc, src_cnt, int_en);
+}
+
+/* return the number of operations */
+static inline int
+iop_desc_init_zero_sum(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+{
+ int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op;
+ struct iop3xx_desc_aau *hw_desc, *prev_hw_desc, *iter;
+ union {
+ u32 value;
+ struct iop3xx_aau_desc_ctrl field;
+ } u_desc_ctrl;
+ int i, j;
+
+ hw_desc = desc->hw_desc;
+
+ for (i = 0, j = 0; (slot_cnt -= slots_per_op) >= 0;
+ i += slots_per_op, j++) {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ u_desc_ctrl.value = iop3xx_desc_init_xor(iter, src_cnt, int_en);
+ u_desc_ctrl.field.dest_write_en = 0;
+ u_desc_ctrl.field.zero_result_en = 1;
+ u_desc_ctrl.field.int_en = int_en;
+ iter->desc_ctrl = u_desc_ctrl.value;
+
+ /* for the subsequent descriptors preserve the store queue
+ * and chain them together
+ */
+ if (i) {
+ prev_hw_desc =
+ iop_hw_desc_slot_idx(hw_desc, i - slots_per_op);
+ prev_hw_desc->next_desc =
+ (u32) (desc->async_tx.phys + (i << 5));
+ }
+ }
+
+ return j;
+}
+
+static inline void
+iop_desc_init_null_xor(struct iop_adma_desc_slot *desc, int src_cnt, int int_en)
+{
+ struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
+ union {
+ u32 value;
+ struct iop3xx_aau_desc_ctrl field;
+ } u_desc_ctrl;
+
+ u_desc_ctrl.value = 0;
+ switch (src_cnt) {
+ case 25 ... 32:
+ u_desc_ctrl.field.blk_ctrl = 0x3; /* use EDCR[2:0] */
+ hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = 0;
+ /* fall through */
+ case 17 ... 24:
+ if (!u_desc_ctrl.field.blk_ctrl) {
+ hw_desc->src_edc[AAU_EDCR2_IDX].e_desc_ctrl = 0;
+ u_desc_ctrl.field.blk_ctrl = 0x3; /* use EDCR[2:0] */
+ }
+ hw_desc->src_edc[AAU_EDCR1_IDX].e_desc_ctrl = 0;
+ /* fall through */
+ case 9 ... 16:
+ if (!u_desc_ctrl.field.blk_ctrl)
+ u_desc_ctrl.field.blk_ctrl = 0x2; /* use EDCR0 */
+ hw_desc->src_edc[AAU_EDCR0_IDX].e_desc_ctrl = 0;
+ /* fall through */
+ case 1 ... 8:
+ if (!u_desc_ctrl.field.blk_ctrl && src_cnt > 4)
+ u_desc_ctrl.field.blk_ctrl = 0x1; /* use mini-desc */
+ }
+
+ u_desc_ctrl.field.dest_write_en = 0;
+ u_desc_ctrl.field.int_en = int_en;
+ hw_desc->desc_ctrl = u_desc_ctrl.value;
+}
+
+static inline void iop_desc_set_byte_count(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan,
+ u32 byte_count)
+{
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ hw_desc.dma->byte_count = byte_count;
+ break;
+ case AAU_ID:
+ hw_desc.aau->byte_count = byte_count;
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline void
+iop_desc_init_interrupt(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan)
+{
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ iop_desc_init_memcpy(desc, 1);
+ hw_desc.dma->byte_count = 0;
+ hw_desc.dma->dest_addr = 0;
+ hw_desc.dma->src_addr = 0;
+ break;
+ case AAU_ID:
+ iop_desc_init_null_xor(desc, 2, 1);
+ hw_desc.aau->byte_count = 0;
+ hw_desc.aau->dest_addr = 0;
+ hw_desc.aau->src[0] = 0;
+ hw_desc.aau->src[1] = 0;
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline void
+iop_desc_set_zero_sum_byte_count(struct iop_adma_desc_slot *desc, u32 len)
+{
+ int slots_per_op = desc->slots_per_op;
+ struct iop3xx_desc_aau *hw_desc = desc->hw_desc, *iter;
+ int i = 0;
+
+ if (len <= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT) {
+ hw_desc->byte_count = len;
+ } else {
+ do {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ iter->byte_count = IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT;
+ len -= IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT;
+ i += slots_per_op;
+ } while (len > IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT);
+
+ if (len) {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ iter->byte_count = len;
+ }
+ }
+}
+
+static inline void iop_desc_set_dest_addr(struct iop_adma_desc_slot *desc,
+ struct iop_adma_chan *chan,
+ dma_addr_t addr)
+{
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ hw_desc.dma->dest_addr = addr;
+ break;
+ case AAU_ID:
+ hw_desc.aau->dest_addr = addr;
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline void iop_desc_set_memcpy_src_addr(struct iop_adma_desc_slot *desc,
+ dma_addr_t addr)
+{
+ struct iop3xx_desc_dma *hw_desc = desc->hw_desc;
+ hw_desc->src_addr = addr;
+}
+
+static inline void
+iop_desc_set_zero_sum_src_addr(struct iop_adma_desc_slot *desc, int src_idx,
+ dma_addr_t addr)
+{
+
+ struct iop3xx_desc_aau *hw_desc = desc->hw_desc, *iter;
+ int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op;
+ int i;
+
+ for (i = 0; (slot_cnt -= slots_per_op) >= 0;
+ i += slots_per_op, addr += IOP_ADMA_ZERO_SUM_MAX_BYTE_COUNT) {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ iop3xx_aau_desc_set_src_addr(iter, src_idx, addr);
+ }
+}
+
+static inline void iop_desc_set_xor_src_addr(struct iop_adma_desc_slot *desc,
+ int src_idx, dma_addr_t addr)
+{
+
+ struct iop3xx_desc_aau *hw_desc = desc->hw_desc, *iter;
+ int slot_cnt = desc->slot_cnt, slots_per_op = desc->slots_per_op;
+ int i;
+
+ for (i = 0; (slot_cnt -= slots_per_op) >= 0;
+ i += slots_per_op, addr += IOP_ADMA_XOR_MAX_BYTE_COUNT) {
+ iter = iop_hw_desc_slot_idx(hw_desc, i);
+ iop3xx_aau_desc_set_src_addr(iter, src_idx, addr);
+ }
+}
+
+static inline void iop_desc_set_next_desc(struct iop_adma_desc_slot *desc,
+ u32 next_desc_addr)
+{
+ /* hw_desc->next_desc is the same location for all channels */
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+ BUG_ON(hw_desc.dma->next_desc);
+ hw_desc.dma->next_desc = next_desc_addr;
+}
+
+static inline u32 iop_desc_get_next_desc(struct iop_adma_desc_slot *desc)
+{
+ /* hw_desc->next_desc is the same location for all channels */
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+ return hw_desc.dma->next_desc;
+}
+
+static inline void iop_desc_clear_next_desc(struct iop_adma_desc_slot *desc)
+{
+ /* hw_desc->next_desc is the same location for all channels */
+ union iop3xx_desc hw_desc = { .ptr = desc->hw_desc, };
+ hw_desc.dma->next_desc = 0;
+}
+
+static inline void iop_desc_set_block_fill_val(struct iop_adma_desc_slot *desc,
+ u32 val)
+{
+ struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
+ hw_desc->src[0] = val;
+}
+
+static inline int iop_desc_get_zero_result(struct iop_adma_desc_slot *desc)
+{
+ struct iop3xx_desc_aau *hw_desc = desc->hw_desc;
+ struct iop3xx_aau_desc_ctrl desc_ctrl = hw_desc->desc_ctrl_field;
+
+ BUG_ON(!(desc_ctrl.tx_complete && desc_ctrl.zero_result_en));
+ return desc_ctrl.zero_result_err;
+}
+
+static inline void iop_chan_append(struct iop_adma_chan *chan)
+{
+ u32 dma_chan_ctrl;
+ /* workaround dropped interrupts on 3xx */
+ mod_timer(&chan->cleanup_watchdog, jiffies + msecs_to_jiffies(3));
+
+ dma_chan_ctrl = __raw_readl(DMA_CCR(chan));
+ dma_chan_ctrl |= 0x2;
+ __raw_writel(dma_chan_ctrl, DMA_CCR(chan));
+}
+
+static inline void iop_chan_idle(int busy, struct iop_adma_chan *chan)
+{
+ if (!busy)
+ del_timer(&chan->cleanup_watchdog);
+}
+
+static inline u32 iop_chan_get_status(struct iop_adma_chan *chan)
+{
+ return __raw_readl(DMA_CSR(chan));
+}
+
+static inline void iop_chan_disable(struct iop_adma_chan *chan)
+{
+ u32 dma_chan_ctrl = __raw_readl(DMA_CCR(chan));
+ dma_chan_ctrl &= ~1;
+ __raw_writel(dma_chan_ctrl, DMA_CCR(chan));
+}
+
+static inline void iop_chan_enable(struct iop_adma_chan *chan)
+{
+ u32 dma_chan_ctrl = __raw_readl(DMA_CCR(chan));
+
+ dma_chan_ctrl |= 1;
+ __raw_writel(dma_chan_ctrl, DMA_CCR(chan));
+}
+
+static inline void iop_adma_device_clear_eot_status(struct iop_adma_chan *chan)
+{
+ u32 status = __raw_readl(DMA_CSR(chan));
+ status &= (1 << 9);
+ __raw_writel(status, DMA_CSR(chan));
+}
+
+static inline void iop_adma_device_clear_eoc_status(struct iop_adma_chan *chan)
+{
+ u32 status = __raw_readl(DMA_CSR(chan));
+ status &= (1 << 8);
+ __raw_writel(status, DMA_CSR(chan));
+}
+
+static inline void iop_adma_device_clear_err_status(struct iop_adma_chan *chan)
+{
+ u32 status = __raw_readl(DMA_CSR(chan));
+
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ status &= (1 << 5) | (1 << 3) | (1 << 2) | (1 << 1);
+ break;
+ case AAU_ID:
+ status &= (1 << 5);
+ break;
+ default:
+ BUG();
+ }
+
+ __raw_writel(status, DMA_CSR(chan));
+}
+
+static inline int
+iop_is_err_int_parity(unsigned long status, struct iop_adma_chan *chan)
+{
+ return 0;
+}
+
+static inline int
+iop_is_err_mcu_abort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return 0;
+}
+
+static inline int
+iop_is_err_int_tabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return 0;
+}
+
+static inline int
+iop_is_err_int_mabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ return test_bit(5, &status);
+}
+
+static inline int
+iop_is_err_pci_tabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return test_bit(2, &status);
+ default:
+ return 0;
+ }
+}
+
+static inline int
+iop_is_err_pci_mabort(unsigned long status, struct iop_adma_chan *chan)
+{
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return test_bit(3, &status);
+ default:
+ return 0;
+ }
+}
+
+static inline int
+iop_is_err_split_tx(unsigned long status, struct iop_adma_chan *chan)
+{
+ switch (chan->device->id) {
+ case DMA0_ID:
+ case DMA1_ID:
+ return test_bit(1, &status);
+ default:
+ return 0;
+ }
+}
+#endif /* _ADMA_H */
diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h
index 63feceb7ede5..fb90b421f31c 100644
--- a/include/asm-arm/hardware/iop3xx.h
+++ b/include/asm-arm/hardware/iop3xx.h
@@ -144,24 +144,9 @@ extern int init_atu;
#define IOP3XX_IAR (volatile u32 *)IOP3XX_REG_ADDR(0x0380)
/* DMA Controller */
-#define IOP3XX_DMA0_CCR (volatile u32 *)IOP3XX_REG_ADDR(0x0400)
-#define IOP3XX_DMA0_CSR (volatile u32 *)IOP3XX_REG_ADDR(0x0404)
-#define IOP3XX_DMA0_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x040c)
-#define IOP3XX_DMA0_NDAR (volatile u32 *)IOP3XX_REG_ADDR(0x0410)
-#define IOP3XX_DMA0_PADR (volatile u32 *)IOP3XX_REG_ADDR(0x0414)
-#define IOP3XX_DMA0_PUADR (volatile u32 *)IOP3XX_REG_ADDR(0x0418)
-#define IOP3XX_DMA0_LADR (volatile u32 *)IOP3XX_REG_ADDR(0x041c)
-#define IOP3XX_DMA0_BCR (volatile u32 *)IOP3XX_REG_ADDR(0x0420)
-#define IOP3XX_DMA0_DCR (volatile u32 *)IOP3XX_REG_ADDR(0x0424)
-#define IOP3XX_DMA1_CCR (volatile u32 *)IOP3XX_REG_ADDR(0x0440)
-#define IOP3XX_DMA1_CSR (volatile u32 *)IOP3XX_REG_ADDR(0x0444)
-#define IOP3XX_DMA1_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x044c)
-#define IOP3XX_DMA1_NDAR (volatile u32 *)IOP3XX_REG_ADDR(0x0450)
-#define IOP3XX_DMA1_PADR (volatile u32 *)IOP3XX_REG_ADDR(0x0454)
-#define IOP3XX_DMA1_PUADR (volatile u32 *)IOP3XX_REG_ADDR(0x0458)
-#define IOP3XX_DMA1_LADR (volatile u32 *)IOP3XX_REG_ADDR(0x045c)
-#define IOP3XX_DMA1_BCR (volatile u32 *)IOP3XX_REG_ADDR(0x0460)
-#define IOP3XX_DMA1_DCR (volatile u32 *)IOP3XX_REG_ADDR(0x0464)
+#define IOP3XX_DMA_PHYS_BASE(chan) (IOP3XX_PERIPHERAL_PHYS_BASE + \
+ (0x400 + (chan << 6)))
+#define IOP3XX_DMA_UPPER_PA(chan) (IOP3XX_DMA_PHYS_BASE(chan) + 0x27)
/* Peripheral bus interface */
#define IOP3XX_PBCR (volatile u32 *)IOP3XX_REG_ADDR(0x0680)
@@ -209,49 +194,16 @@ extern int init_atu;
#define IOP_TMR_PRIVILEGED 0x08
#define IOP_TMR_RATIO_1_1 0x00
+/* Watchdog timer definitions */
+#define IOP_WDTCR_EN_ARM 0x1e1e1e1e
+#define IOP_WDTCR_EN 0xe1e1e1e1
+/* iop3xx does not support stopping the watchdog, so we just re-arm */
+#define IOP_WDTCR_DIS_ARM (IOP_WDTCR_EN_ARM)
+#define IOP_WDTCR_DIS (IOP_WDTCR_EN)
+
/* Application accelerator unit */
-#define IOP3XX_AAU_ACR (volatile u32 *)IOP3XX_REG_ADDR(0x0800)
-#define IOP3XX_AAU_ASR (volatile u32 *)IOP3XX_REG_ADDR(0x0804)
-#define IOP3XX_AAU_ADAR (volatile u32 *)IOP3XX_REG_ADDR(0x0808)
-#define IOP3XX_AAU_ANDAR (volatile u32 *)IOP3XX_REG_ADDR(0x080c)
-#define IOP3XX_AAU_SAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0810)
-#define IOP3XX_AAU_SAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0814)
-#define IOP3XX_AAU_SAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0818)
-#define IOP3XX_AAU_SAR4 (volatile u32 *)IOP3XX_REG_ADDR(0x081c)
-#define IOP3XX_AAU_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x0820)
-#define IOP3XX_AAU_ABCR (volatile u32 *)IOP3XX_REG_ADDR(0x0824)
-#define IOP3XX_AAU_ADCR (volatile u32 *)IOP3XX_REG_ADDR(0x0828)
-#define IOP3XX_AAU_SAR5 (volatile u32 *)IOP3XX_REG_ADDR(0x082c)
-#define IOP3XX_AAU_SAR6 (volatile u32 *)IOP3XX_REG_ADDR(0x0830)
-#define IOP3XX_AAU_SAR7 (volatile u32 *)IOP3XX_REG_ADDR(0x0834)
-#define IOP3XX_AAU_SAR8 (volatile u32 *)IOP3XX_REG_ADDR(0x0838)
-#define IOP3XX_AAU_EDCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x083c)
-#define IOP3XX_AAU_SAR9 (volatile u32 *)IOP3XX_REG_ADDR(0x0840)
-#define IOP3XX_AAU_SAR10 (volatile u32 *)IOP3XX_REG_ADDR(0x0844)
-#define IOP3XX_AAU_SAR11 (volatile u32 *)IOP3XX_REG_ADDR(0x0848)
-#define IOP3XX_AAU_SAR12 (volatile u32 *)IOP3XX_REG_ADDR(0x084c)
-#define IOP3XX_AAU_SAR13 (volatile u32 *)IOP3XX_REG_ADDR(0x0850)
-#define IOP3XX_AAU_SAR14 (volatile u32 *)IOP3XX_REG_ADDR(0x0854)
-#define IOP3XX_AAU_SAR15 (volatile u32 *)IOP3XX_REG_ADDR(0x0858)
-#define IOP3XX_AAU_SAR16 (volatile u32 *)IOP3XX_REG_ADDR(0x085c)
-#define IOP3XX_AAU_EDCR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0860)
-#define IOP3XX_AAU_SAR17 (volatile u32 *)IOP3XX_REG_ADDR(0x0864)
-#define IOP3XX_AAU_SAR18 (volatile u32 *)IOP3XX_REG_ADDR(0x0868)
-#define IOP3XX_AAU_SAR19 (volatile u32 *)IOP3XX_REG_ADDR(0x086c)
-#define IOP3XX_AAU_SAR20 (volatile u32 *)IOP3XX_REG_ADDR(0x0870)
-#define IOP3XX_AAU_SAR21 (volatile u32 *)IOP3XX_REG_ADDR(0x0874)
-#define IOP3XX_AAU_SAR22 (volatile u32 *)IOP3XX_REG_ADDR(0x0878)
-#define IOP3XX_AAU_SAR23 (volatile u32 *)IOP3XX_REG_ADDR(0x087c)
-#define IOP3XX_AAU_SAR24 (volatile u32 *)IOP3XX_REG_ADDR(0x0880)
-#define IOP3XX_AAU_EDCR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0884)
-#define IOP3XX_AAU_SAR25 (volatile u32 *)IOP3XX_REG_ADDR(0x0888)
-#define IOP3XX_AAU_SAR26 (volatile u32 *)IOP3XX_REG_ADDR(0x088c)
-#define IOP3XX_AAU_SAR27 (volatile u32 *)IOP3XX_REG_ADDR(0x0890)
-#define IOP3XX_AAU_SAR28 (volatile u32 *)IOP3XX_REG_ADDR(0x0894)
-#define IOP3XX_AAU_SAR29 (volatile u32 *)IOP3XX_REG_ADDR(0x0898)
-#define IOP3XX_AAU_SAR30 (volatile u32 *)IOP3XX_REG_ADDR(0x089c)
-#define IOP3XX_AAU_SAR31 (volatile u32 *)IOP3XX_REG_ADDR(0x08a0)
-#define IOP3XX_AAU_SAR32 (volatile u32 *)IOP3XX_REG_ADDR(0x08a4)
+#define IOP3XX_AAU_PHYS_BASE (IOP3XX_PERIPHERAL_PHYS_BASE + 0x800)
+#define IOP3XX_AAU_UPPER_PA (IOP3XX_AAU_PHYS_BASE + 0xa7)
/* I2C bus interface unit */
#define IOP3XX_ICR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1680)
@@ -329,6 +281,35 @@ static inline void write_tisr(u32 val)
asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (val));
}
+static inline u32 read_wdtcr(void)
+{
+ u32 val;
+ asm volatile("mrc p6, 0, %0, c7, c1, 0":"=r" (val));
+ return val;
+}
+static inline void write_wdtcr(u32 val)
+{
+ asm volatile("mcr p6, 0, %0, c7, c1, 0"::"r" (val));
+}
+
+extern unsigned long get_iop_tick_rate(void);
+
+/* only iop13xx has these registers, we define these to present a
+ * common register interface for the iop_wdt driver.
+ */
+#define IOP_RCSR_WDT (0)
+static inline u32 read_rcsr(void)
+{
+ return 0;
+}
+static inline void write_wdtsr(u32 val)
+{
+ do { } while (0);
+}
+
+extern struct platform_device iop3xx_dma_0_channel;
+extern struct platform_device iop3xx_dma_1_channel;
+extern struct platform_device iop3xx_aau_channel;
extern struct platform_device iop3xx_i2c0_device;
extern struct platform_device iop3xx_i2c1_device;
diff --git a/include/asm-arm/hardware/iop_adma.h b/include/asm-arm/hardware/iop_adma.h
new file mode 100644
index 000000000000..ca8e71f44346
--- /dev/null
+++ b/include/asm-arm/hardware/iop_adma.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2006, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef IOP_ADMA_H
+#define IOP_ADMA_H
+#include <linux/types.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+
+#define IOP_ADMA_SLOT_SIZE 32
+#define IOP_ADMA_THRESHOLD 4
+
+/**
+ * struct iop_adma_device - internal representation of an ADMA device
+ * @pdev: Platform device
+ * @id: HW ADMA Device selector
+ * @dma_desc_pool: base of DMA descriptor region (DMA address)
+ * @dma_desc_pool_virt: base of DMA descriptor region (CPU address)
+ * @common: embedded struct dma_device
+ */
+struct iop_adma_device {
+ struct platform_device *pdev;
+ int id;
+ dma_addr_t dma_desc_pool;
+ void *dma_desc_pool_virt;
+ struct dma_device common;
+};
+
+/**
+ * struct iop_adma_chan - internal representation of an ADMA device
+ * @pending: allows batching of hardware operations
+ * @completed_cookie: identifier for the most recently completed operation
+ * @lock: serializes enqueue/dequeue operations to the slot pool
+ * @mmr_base: memory mapped register base
+ * @chain: device chain view of the descriptors
+ * @device: parent device
+ * @common: common dmaengine channel object members
+ * @last_used: place holder for allocation to continue from where it left off
+ * @all_slots: complete domain of slots usable by the channel
+ * @cleanup_watchdog: workaround missed interrupts on iop3xx
+ * @slots_allocated: records the actual size of the descriptor slot pool
+ * @irq_tasklet: bottom half where iop_adma_slot_cleanup runs
+ */
+struct iop_adma_chan {
+ int pending;
+ dma_cookie_t completed_cookie;
+ spinlock_t lock; /* protects the descriptor slot pool */
+ void __iomem *mmr_base;
+ struct list_head chain;
+ struct iop_adma_device *device;
+ struct dma_chan common;
+ struct iop_adma_desc_slot *last_used;
+ struct list_head all_slots;
+ struct timer_list cleanup_watchdog;
+ int slots_allocated;
+ struct tasklet_struct irq_tasklet;
+};
+
+/**
+ * struct iop_adma_desc_slot - IOP-ADMA software descriptor
+ * @slot_node: node on the iop_adma_chan.all_slots list
+ * @chain_node: node on the op_adma_chan.chain list
+ * @hw_desc: virtual address of the hardware descriptor chain
+ * @phys: hardware address of the hardware descriptor chain
+ * @group_head: first operation in a transaction
+ * @slot_cnt: total slots used in an transaction (group of operations)
+ * @slots_per_op: number of slots per operation
+ * @idx: pool index
+ * @unmap_src_cnt: number of xor sources
+ * @unmap_len: transaction bytecount
+ * @async_tx: support for the async_tx api
+ * @group_list: list of slots that make up a multi-descriptor transaction
+ * for example transfer lengths larger than the supported hw max
+ * @xor_check_result: result of zero sum
+ * @crc32_result: result crc calculation
+ */
+struct iop_adma_desc_slot {
+ struct list_head slot_node;
+ struct list_head chain_node;
+ void *hw_desc;
+ struct iop_adma_desc_slot *group_head;
+ u16 slot_cnt;
+ u16 slots_per_op;
+ u16 idx;
+ u16 unmap_src_cnt;
+ size_t unmap_len;
+ struct dma_async_tx_descriptor async_tx;
+ union {
+ u32 *xor_check_result;
+ u32 *crc32_result;
+ };
+};
+
+struct iop_adma_platform_data {
+ int hw_id;
+ dma_cap_mask_t cap_mask;
+ size_t pool_size;
+};
+
+#define to_iop_sw_desc(addr_hw_desc) \
+ container_of(addr_hw_desc, struct iop_adma_desc_slot, hw_desc)
+#define iop_hw_desc_slot_idx(hw_desc, idx) \
+ ( (void *) (((unsigned long) hw_desc) + ((idx) << 5)) )
+#endif
diff --git a/include/asm-arm/hwcap.h b/include/asm-arm/hwcap.h
new file mode 100644
index 000000000000..01a1391d3014
--- /dev/null
+++ b/include/asm-arm/hwcap.h
@@ -0,0 +1,28 @@
+#ifndef __ASMARM_HWCAP_H
+#define __ASMARM_HWCAP_H
+
+/*
+ * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
+ */
+#define HWCAP_SWP 1
+#define HWCAP_HALF 2
+#define HWCAP_THUMB 4
+#define HWCAP_26BIT 8 /* Play it safe */
+#define HWCAP_FAST_MULT 16
+#define HWCAP_FPA 32
+#define HWCAP_VFP 64
+#define HWCAP_EDSP 128
+#define HWCAP_JAVA 256
+#define HWCAP_IWMMXT 512
+#define HWCAP_CRUNCH 1024
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+/*
+ * This yields a mask that user programs can use to figure out what
+ * instruction set this cpu supports.
+ */
+#define ELF_HWCAP (elf_hwcap)
+extern unsigned int elf_hwcap;
+#endif
+
+#endif
diff --git a/include/asm-arm/pci.h b/include/asm-arm/pci.h
index f21abd4ddac6..ed3f898191f4 100644
--- a/include/asm-arm/pci.h
+++ b/include/asm-arm/pci.h
@@ -26,11 +26,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
#define PCI_DMA_BUS_IS_PHYS (0)
/*
- * We don't support DAC DMA cycles.
- */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
-/*
* Whether pci_unmap_{single,page} is a nop depends upon the
* configuration.
*/
@@ -76,10 +71,6 @@ pcibios_select_root(struct pci_dev *pdev, struct resource *res)
return root;
}
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
index 0c8be19fd66b..b186bc820e30 100644
--- a/include/asm-arm/pgtable-nommu.h
+++ b/include/asm-arm/pgtable-nommu.h
@@ -102,7 +102,8 @@ extern int is_in_rom(unsigned long);
#define v4_tlb_fns (0)
#define v4wb_tlb_fns (0)
#define v4wbi_tlb_fns (0)
-#define v6_tlb_fns (0)
+#define v6wbi_tlb_fns (0)
+#define v7wbi_tlb_fns (0)
#define v3_user_fns (0)
#define v4_user_fns (0)
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 21dec9f258d8..d2e8171d1d4e 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -83,14 +83,14 @@
* means that a write to a clean page will cause a permission fault, and
* the Linux MM layer will mark the page dirty via handle_pte_fault().
* For the hardware to notice the permission change, the TLB entry must
- * be flushed, and ptep_establish() does that for us.
+ * be flushed, and ptep_set_access_flags() does that for us.
*
* The "accessed" or "young" bit is emulated by a similar method; we only
* allow accesses to the page if the "young" bit is set. Accesses to the
* page will cause a fault, and handle_pte_fault() will set the young bit
* for us as long as the page is marked present in the corresponding Linux
- * PTE entry. Again, ptep_establish() will ensure that the TLB is up to
- * date.
+ * PTE entry. Again, ptep_set_access_flags() will ensure that the TLB is
+ * up to date.
*
* However, when the "young" bit is cleared, we deny access to the page
* by clearing the hardware PTE. Currently Linux does not flush the TLB
@@ -257,9 +257,7 @@ extern struct page *empty_zero_page;
* Undefined behaviour if not..
*/
#define pte_present(pte) (pte_val(pte) & L_PTE_PRESENT)
-#define pte_read(pte) (pte_val(pte) & L_PTE_USER)
#define pte_write(pte) (pte_val(pte) & L_PTE_WRITE)
-#define pte_exec(pte) (pte_val(pte) & L_PTE_EXEC)
#define pte_dirty(pte) (pte_val(pte) & L_PTE_DIRTY)
#define pte_young(pte) (pte_val(pte) & L_PTE_YOUNG)
@@ -275,12 +273,8 @@ extern struct page *empty_zero_page;
#define PTE_BIT_FUNC(fn,op) \
static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
-/*PTE_BIT_FUNC(rdprotect, &= ~L_PTE_USER);*/
-/*PTE_BIT_FUNC(mkread, |= L_PTE_USER);*/
PTE_BIT_FUNC(wrprotect, &= ~L_PTE_WRITE);
PTE_BIT_FUNC(mkwrite, |= L_PTE_WRITE);
-PTE_BIT_FUNC(exprotect, &= ~L_PTE_EXEC);
-PTE_BIT_FUNC(mkexec, |= L_PTE_EXEC);
PTE_BIT_FUNC(mkclean, &= ~L_PTE_DIRTY);
PTE_BIT_FUNC(mkdirty, |= L_PTE_DIRTY);
PTE_BIT_FUNC(mkold, &= ~L_PTE_YOUNG);
diff --git a/include/asm-arm/plat-s3c/debug-macro.S b/include/asm-arm/plat-s3c/debug-macro.S
new file mode 100644
index 000000000000..84c40b847da8
--- /dev/null
+++ b/include/asm-arm/plat-s3c/debug-macro.S
@@ -0,0 +1,75 @@
+/* linux/include/asm-arm/plat-s3c/debug-macro.S
+ *
+ * Copyright 2005, 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <asm/plat-s3c/regs-serial.h>
+
+/* The S3C2440 implementations are used by default as they are the
+ * most widely re-used */
+
+ .macro fifo_level_s3c2440 rd, rx
+ ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ and \rd, \rd, #S3C2440_UFSTAT_TXMASK
+ .endm
+
+#ifndef fifo_level
+#define fifo_level fifo_level_s3c2410
+#endif
+
+ .macro fifo_full_s3c2440 rd, rx
+ ldr \rd, [ \rx, # S3C2410_UFSTAT ]
+ tst \rd, #S3C2440_UFSTAT_TXFULL
+ .endm
+
+#ifndef fifo_full
+#define fifo_full fifo_full_s3c2440
+#endif
+
+ .macro senduart,rd,rx
+ strb \rd, [\rx, # S3C2410_UTXH ]
+ .endm
+
+ .macro busyuart, rd, rx
+ ldr \rd, [ \rx, # S3C2410_UFCON ]
+ tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
+ beq 1001f @
+ @ FIFO enabled...
+1003:
+ fifo_full \rd, \rx
+ bne 1003b
+ b 1002f
+
+1001:
+ @ busy waiting for non fifo
+ ldr \rd, [ \rx, # S3C2410_UTRSTAT ]
+ tst \rd, #S3C2410_UTRSTAT_TXFE
+ beq 1001b
+
+1002: @ exit busyuart
+ .endm
+
+ .macro waituart,rd,rx
+ ldr \rd, [ \rx, # S3C2410_UFCON ]
+ tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
+ beq 1001f @
+ @ FIFO enabled...
+1003:
+ fifo_level \rd, \rx
+ teq \rd, #0
+ bne 1003b
+ b 1002f
+1001:
+ @ idle waiting for non fifo
+ ldr \rd, [ \rx, # S3C2410_UTRSTAT ]
+ tst \rd, #S3C2410_UTRSTAT_TXFE
+ beq 1001b
+
+1002: @ exit busyuart
+ .endm
diff --git a/include/asm-arm/arch-s3c2410/iic.h b/include/asm-arm/plat-s3c/iic.h
index 71211c8b5384..71211c8b5384 100644
--- a/include/asm-arm/arch-s3c2410/iic.h
+++ b/include/asm-arm/plat-s3c/iic.h
diff --git a/include/asm-arm/plat-s3c/map.h b/include/asm-arm/plat-s3c/map.h
new file mode 100644
index 000000000000..95a82b0e84a1
--- /dev/null
+++ b/include/asm-arm/plat-s3c/map.h
@@ -0,0 +1,40 @@
+/* linux/include/asm-arm/plat-s3c/map.h
+ *
+ * Copyright 2003, 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - Memory map definitions (virtual addresses)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_PLAT_MAP_H
+#define __ASM_PLAT_MAP_H __FILE__
+
+/* Fit all our registers in at 0xF4000000 upwards, trying to use as
+ * little of the VA space as possible so vmalloc and friends have a
+ * better chance of getting memory.
+ *
+ * we try to ensure stuff like the IRQ registers are available for
+ * an single MOVS instruction (ie, only 8 bits of set data)
+ */
+
+#define S3C_ADDR_BASE (0xF4000000)
+
+#ifndef __ASSEMBLY__
+#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
+#else
+#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
+#endif
+
+#define S3C_VA_IRQ S3C_ADDR(0x000000000) /* irq controller(s) */
+#define S3C_VA_SYS S3C_ADDR(0x001000000) /* system control */
+#define S3C_VA_MEM S3C_ADDR(0x002000000) /* system control */
+#define S3C_VA_TIMER S3C_ADDR(0x003000000) /* timer block */
+#define S3C_VA_WATCHDOG S3C_ADDR(0x004000000) /* watchdog */
+#define S3C_VA_UART S3C_ADDR(0x010000000) /* UART */
+
+#endif /* __ASM_PLAT_MAP_H */
diff --git a/include/asm-arm/arch-s3c2410/nand.h b/include/asm-arm/plat-s3c/nand.h
index 8816f7f9cee1..8816f7f9cee1 100644
--- a/include/asm-arm/arch-s3c2410/nand.h
+++ b/include/asm-arm/plat-s3c/nand.h
diff --git a/include/asm-arm/arch-s3c2410/regs-ac97.h b/include/asm-arm/plat-s3c/regs-ac97.h
index b004dee6bcaf..b004dee6bcaf 100644
--- a/include/asm-arm/arch-s3c2410/regs-ac97.h
+++ b/include/asm-arm/plat-s3c/regs-ac97.h
diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/plat-s3c/regs-adc.h
index c7f231963e76..c7f231963e76 100644
--- a/include/asm-arm/arch-s3c2410/regs-adc.h
+++ b/include/asm-arm/plat-s3c/regs-adc.h
diff --git a/include/asm-arm/arch-s3c2410/regs-iic.h b/include/asm-arm/plat-s3c/regs-iic.h
index 2ae29522f253..2ae29522f253 100644
--- a/include/asm-arm/arch-s3c2410/regs-iic.h
+++ b/include/asm-arm/plat-s3c/regs-iic.h
diff --git a/include/asm-arm/arch-s3c2410/regs-nand.h b/include/asm-arm/plat-s3c/regs-nand.h
index b824d371ae0b..b824d371ae0b 100644
--- a/include/asm-arm/arch-s3c2410/regs-nand.h
+++ b/include/asm-arm/plat-s3c/regs-nand.h
diff --git a/include/asm-arm/arch-s3c2410/regs-rtc.h b/include/asm-arm/plat-s3c/regs-rtc.h
index 93b03c49710a..93b03c49710a 100644
--- a/include/asm-arm/arch-s3c2410/regs-rtc.h
+++ b/include/asm-arm/plat-s3c/regs-rtc.h
diff --git a/include/asm-arm/arch-s3c2410/regs-serial.h b/include/asm-arm/plat-s3c/regs-serial.h
index 8946702a87f5..923e114db663 100644
--- a/include/asm-arm/arch-s3c2410/regs-serial.h
+++ b/include/asm-arm/plat-s3c/regs-serial.h
@@ -32,10 +32,10 @@
#ifndef __ASM_ARM_REGS_SERIAL_H
#define __ASM_ARM_REGS_SERIAL_H
-#define S3C24XX_VA_UART0 (S3C24XX_VA_UART)
-#define S3C24XX_VA_UART1 (S3C24XX_VA_UART + 0x4000 )
-#define S3C24XX_VA_UART2 (S3C24XX_VA_UART + 0x8000 )
-#define S3C24XX_VA_UART3 (S3C24XX_VA_UART + 0xC000 )
+#define S3C24XX_VA_UART0 (S3C_VA_UART)
+#define S3C24XX_VA_UART1 (S3C_VA_UART + 0x4000 )
+#define S3C24XX_VA_UART2 (S3C_VA_UART + 0x8000 )
+#define S3C24XX_VA_UART3 (S3C_VA_UART + 0xC000 )
#define S3C2410_PA_UART0 (S3C24XX_PA_UART)
#define S3C2410_PA_UART1 (S3C24XX_PA_UART + 0x4000 )
diff --git a/include/asm-arm/arch-s3c2410/regs-timer.h b/include/asm-arm/plat-s3c/regs-timer.h
index 6f8fe432fe3a..8b0d594397b1 100644
--- a/include/asm-arm/arch-s3c2410/regs-timer.h
+++ b/include/asm-arm/plat-s3c/regs-timer.h
@@ -14,12 +14,12 @@
#ifndef __ASM_ARCH_REGS_TIMER_H
#define __ASM_ARCH_REGS_TIMER_H "$Id: timer.h,v 1.4 2003/05/06 19:30:50 ben Exp $"
-#define S3C2410_TIMERREG(x) (S3C24XX_VA_TIMER + (x))
-#define S3C2410_TIMERREG2(tmr,reg) S3C2410_TIMERREG((reg)+0x0c+((tmr)*0x0c))
+#define S3C_TIMERREG(x) (S3C_VA_TIMER + (x))
+#define S3C_TIMERREG2(tmr,reg) S3C_TIMERREG((reg)+0x0c+((tmr)*0x0c))
-#define S3C2410_TCFG0 S3C2410_TIMERREG(0x00)
-#define S3C2410_TCFG1 S3C2410_TIMERREG(0x04)
-#define S3C2410_TCON S3C2410_TIMERREG(0x08)
+#define S3C2410_TCFG0 S3C_TIMERREG(0x00)
+#define S3C2410_TCFG1 S3C_TIMERREG(0x04)
+#define S3C2410_TCON S3C_TIMERREG(0x08)
#define S3C2410_TCFG_PRESCALER0_MASK (255<<0)
#define S3C2410_TCFG_PRESCALER1_MASK (255<<8)
@@ -71,9 +71,9 @@
/* WARNING - timer 4 has no buffer reg, and it's observation is at +4 */
-#define S3C2410_TCNTB(tmr) S3C2410_TIMERREG2(tmr, 0x00)
-#define S3C2410_TCMPB(tmr) S3C2410_TIMERREG2(tmr, 0x04)
-#define S3C2410_TCNTO(tmr) S3C2410_TIMERREG2(tmr, (((tmr) == 4) ? 0x04 : 0x08))
+#define S3C2410_TCNTB(tmr) S3C_TIMERREG2(tmr, 0x00)
+#define S3C2410_TCMPB(tmr) S3C_TIMERREG2(tmr, 0x04)
+#define S3C2410_TCNTO(tmr) S3C_TIMERREG2(tmr, (((tmr) == 4) ? 0x04 : 0x08))
#define S3C2410_TCON_T4RELOAD (1<<22)
#define S3C2410_TCON_T4MANUALUPD (1<<21)
diff --git a/include/asm-arm/arch-s3c2410/regs-watchdog.h b/include/asm-arm/plat-s3c/regs-watchdog.h
index a9c5d491bdb6..56c4193b7a46 100644
--- a/include/asm-arm/arch-s3c2410/regs-watchdog.h
+++ b/include/asm-arm/plat-s3c/regs-watchdog.h
@@ -14,11 +14,11 @@
#ifndef __ASM_ARCH_REGS_WATCHDOG_H
#define __ASM_ARCH_REGS_WATCHDOG_H "$Id: watchdog.h,v 1.2 2003/04/29 13:31:09 ben Exp $"
-#define S3C2410_WDOGREG(x) ((x) + S3C24XX_VA_WATCHDOG)
+#define S3C_WDOGREG(x) ((x) + S3C_VA_WATCHDOG)
-#define S3C2410_WTCON S3C2410_WDOGREG(0x00)
-#define S3C2410_WTDAT S3C2410_WDOGREG(0x04)
-#define S3C2410_WTCNT S3C2410_WDOGREG(0x08)
+#define S3C2410_WTCON S3C_WDOGREG(0x00)
+#define S3C2410_WTDAT S3C_WDOGREG(0x04)
+#define S3C2410_WTCNT S3C_WDOGREG(0x08)
/* the watchdog can either generate a reset pulse, or an
* interrupt.
diff --git a/include/asm-arm/plat-s3c/uncompress.h b/include/asm-arm/plat-s3c/uncompress.h
new file mode 100644
index 000000000000..b5e6208175d1
--- /dev/null
+++ b/include/asm-arm/plat-s3c/uncompress.h
@@ -0,0 +1,155 @@
+/* linux/include/asm-arm/plat-s3c/uncompress.h
+ *
+ * Copyright 2003, 2007 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C - uncompress code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_PLAT_UNCOMPRESS_H
+#define __ASM_PLAT_UNCOMPRESS_H
+
+typedef unsigned int upf_t; /* cannot include linux/serial_core.h */
+
+/* uart setup */
+
+static unsigned int fifo_mask;
+static unsigned int fifo_max;
+
+/* forward declerations */
+
+static void arch_detect_cpu(void);
+
+/* defines for UART registers */
+
+#include "asm/plat-s3c/regs-serial.h"
+#include "asm/plat-s3c/regs-watchdog.h"
+
+/* working in physical space... */
+#undef S3C2410_WDOGREG
+#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x)))
+
+/* how many bytes we allow into the FIFO at a time in FIFO mode */
+#define FIFO_MAX (14)
+
+#define uart_base S3C24XX_PA_UART + (0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT)
+
+static __inline__ void
+uart_wr(unsigned int reg, unsigned int val)
+{
+ volatile unsigned int *ptr;
+
+ ptr = (volatile unsigned int *)(reg + uart_base);
+ *ptr = val;
+}
+
+static __inline__ unsigned int
+uart_rd(unsigned int reg)
+{
+ volatile unsigned int *ptr;
+
+ ptr = (volatile unsigned int *)(reg + uart_base);
+ return *ptr;
+}
+
+/* we can deal with the case the UARTs are being run
+ * in FIFO mode, so that we don't hold up our execution
+ * waiting for tx to happen...
+*/
+
+static void putc(int ch)
+{
+ if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
+ int level;
+
+ while (1) {
+ level = uart_rd(S3C2410_UFSTAT);
+ level &= fifo_mask;
+
+ if (level < fifo_max)
+ break;
+ }
+
+ } else {
+ /* not using fifos */
+
+ while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)
+ barrier();
+ }
+
+ /* write byte to transmission register */
+ uart_wr(S3C2410_UTXH, ch);
+}
+
+static inline void flush(void)
+{
+}
+
+#define __raw_writel(d,ad) do { *((volatile unsigned int *)(ad)) = (d); } while(0)
+
+/* CONFIG_S3C_BOOT_WATCHDOG
+ *
+ * Simple boot-time watchdog setup, to reboot the system if there is
+ * any problem with the boot process
+*/
+
+#ifdef CONFIG_S3C_BOOT_WATCHDOG
+
+#define WDOG_COUNT (0xff00)
+
+static inline void arch_decomp_wdog(void)
+{
+ __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+}
+
+static void arch_decomp_wdog_start(void)
+{
+ __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
+ __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+ __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
+}
+
+#else
+#define arch_decomp_wdog_start()
+#define arch_decomp_wdog()
+#endif
+
+#ifdef CONFIG_S3C_BOOT_ERROR_RESET
+
+static void arch_decomp_error(const char *x)
+{
+ putstr("\n\n");
+ putstr(x);
+ putstr("\n\n -- System resetting\n");
+
+ __raw_writel(0x4000, S3C2410_WTDAT);
+ __raw_writel(0x4000, S3C2410_WTCNT);
+ __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+
+ while(1);
+}
+
+#define arch_error arch_decomp_error
+#endif
+
+static void error(char *err);
+
+static void
+arch_decomp_setup(void)
+{
+ /* we may need to setup the uart(s) here if we are not running
+ * on an BAST... the BAST will have left the uarts configured
+ * after calling linux.
+ */
+
+ arch_detect_cpu();
+ arch_decomp_wdog_start();
+}
+
+
+#endif /* __ASM_PLAT_UNCOMPRESS_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/plat-s3c24xx/regs-iis.h
index eaf77916a602..eaf77916a602 100644
--- a/include/asm-arm/arch-s3c2410/regs-iis.h
+++ b/include/asm-arm/plat-s3c24xx/regs-iis.h
diff --git a/include/asm-arm/arch-s3c2410/regs-spi.h b/include/asm-arm/plat-s3c24xx/regs-spi.h
index 4a499a138256..4a499a138256 100644
--- a/include/asm-arm/arch-s3c2410/regs-spi.h
+++ b/include/asm-arm/plat-s3c24xx/regs-spi.h
diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/plat-s3c24xx/regs-udc.h
index e1e9805d2d9a..e1e9805d2d9a 100644
--- a/include/asm-arm/arch-s3c2410/regs-udc.h
+++ b/include/asm-arm/plat-s3c24xx/regs-udc.h
diff --git a/include/asm-arm/arch-s3c2410/udc.h b/include/asm-arm/plat-s3c24xx/udc.h
index b8aa6cb69b58..b8aa6cb69b58 100644
--- a/include/asm-arm/arch-s3c2410/udc.h
+++ b/include/asm-arm/plat-s3c24xx/udc.h
diff --git a/include/asm-arm/ptrace.h b/include/asm-arm/ptrace.h
index ee3d93c281d8..7aaa206cb54e 100644
--- a/include/asm-arm/ptrace.h
+++ b/include/asm-arm/ptrace.h
@@ -10,6 +10,8 @@
#ifndef __ASM_ARM_PTRACE_H
#define __ASM_ARM_PTRACE_H
+#include <asm/hwcap.h>
+
#define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13
#define PTRACE_GETFPREGS 14
@@ -45,6 +47,7 @@
#define PSR_T_BIT 0x00000020
#define PSR_F_BIT 0x00000040
#define PSR_I_BIT 0x00000080
+#define PSR_A_BIT 0x00000100
#define PSR_J_BIT 0x01000000
#define PSR_Q_BIT 0x08000000
#define PSR_V_BIT 0x10000000
@@ -103,6 +106,10 @@ struct pt_regs {
#define thumb_mode(regs) (0)
#endif
+#define isa_mode(regs) \
+ ((((regs)->ARM_cpsr & PSR_J_BIT) >> 23) | \
+ (((regs)->ARM_cpsr & PSR_T_BIT) >> 5))
+
#define processor_mode(regs) \
((regs)->ARM_cpsr & MODE_MASK)
@@ -117,14 +124,17 @@ struct pt_regs {
*/
static inline int valid_user_regs(struct pt_regs *regs)
{
- if (user_mode(regs) &&
- (regs->ARM_cpsr & (PSR_F_BIT|PSR_I_BIT)) == 0)
+ if (user_mode(regs) && (regs->ARM_cpsr & PSR_I_BIT) == 0) {
+ regs->ARM_cpsr &= ~(PSR_F_BIT | PSR_A_BIT);
return 1;
+ }
/*
* Force CPSR to something logical...
*/
- regs->ARM_cpsr &= PSR_f | PSR_s | PSR_x | PSR_T_BIT | MODE32_BIT;
+ regs->ARM_cpsr &= PSR_f | PSR_s | (PSR_x & ~PSR_A_BIT) | PSR_T_BIT | MODE32_BIT;
+ if (!(elf_hwcap & HWCAP_26BIT))
+ regs->ARM_cpsr |= USR_MODE;
return 0;
}
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 6f8e6a69dc5f..94ea8c6dc1a4 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -254,16 +254,6 @@ do { \
last = __switch_to(prev,task_thread_info(prev), task_thread_info(next)); \
} while (0)
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
#if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
/*
* On the StrongARM, "swp" is terminally broken since it bypasses the
diff --git a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
index eae85b09db2e..69c65d56a6ac 100644
--- a/include/asm-arm/thread_info.h
+++ b/include/asm-arm/thread_info.h
@@ -24,7 +24,6 @@
struct task_struct;
struct exec_domain;
-#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/domain.h>
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index bfdbebebdc1b..d327b25c986c 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -441,7 +441,6 @@
/*
* Unimplemented (or alternatively implemented) syscalls
*/
-#define __IGNORE_sync_file_range 1
#define __IGNORE_fadvise64_64 1
#endif /* __KERNEL__ */
diff --git a/include/asm-arm/vfp.h b/include/asm-arm/vfp.h
index 14c5e0946c47..bd6be9d7f772 100644
--- a/include/asm-arm/vfp.h
+++ b/include/asm-arm/vfp.h
@@ -26,8 +26,8 @@
#define FPSID_REV_MASK (0xF << FPSID_REV_BIT)
/* FPEXC bits */
-#define FPEXC_EXCEPTION (1<<31)
-#define FPEXC_ENABLE (1<<30)
+#define FPEXC_EX (1 << 31)
+#define FPEXC_EN (1 << 30)
/* FPSCR bits */
#define FPSCR_DEFAULT_NAN (1<<25)
diff --git a/include/asm-arm26/a.out.h b/include/asm-arm26/a.out.h
index 9b2702c42c87..7167f54ae3fc 100644
--- a/include/asm-arm26/a.out.h
+++ b/include/asm-arm26/a.out.h
@@ -29,6 +29,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
#ifndef LIBRARY_START_TEXT
diff --git a/include/asm-arm26/dma-mapping.h b/include/asm-arm26/dma-mapping.h
deleted file mode 100644
index a95eae0aeb77..000000000000
--- a/include/asm-arm26/dma-mapping.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#include <asm-generic/dma-mapping-broken.h>
-
diff --git a/include/asm-arm26/fb.h b/include/asm-arm26/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-arm26/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-arm26/ioctls.h b/include/asm-arm26/ioctls.h
index ba9c7d81d24e..8a3296200be1 100644
--- a/include/asm-arm26/ioctls.h
+++ b/include/asm-arm26/ioctls.h
@@ -47,6 +47,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-arm26/irq.h b/include/asm-arm26/irq.h
index 9aaac87efba9..52971b49ed3b 100644
--- a/include/asm-arm26/irq.h
+++ b/include/asm-arm26/irq.h
@@ -24,11 +24,6 @@
struct irqaction;
-#define disable_irq_nosync(i) disable_irq(i)
-
-extern void disable_irq(unsigned int);
-extern void enable_irq(unsigned int);
-
#define __IRQT_FALEDGE (1 << 0)
#define __IRQT_RISEDGE (1 << 1)
#define __IRQT_LOWLVL (1 << 2)
diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h
index 2b20e9f08857..55a1a697d12b 100644
--- a/include/asm-arm26/pgtable.h
+++ b/include/asm-arm26/pgtable.h
@@ -218,9 +218,7 @@ extern struct page *empty_zero_page;
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-#define pte_read(pte) (!(pte_val(pte) & _PAGE_NOT_USER))
#define pte_write(pte) (!(pte_val(pte) & _PAGE_READONLY))
-#define pte_exec(pte) (!(pte_val(pte) & _PAGE_NOT_USER))
#define pte_dirty(pte) (!(pte_val(pte) & _PAGE_CLEAN))
#define pte_young(pte) (!(pte_val(pte) & _PAGE_OLD))
//ONLY when !pte_present() I think. nicked from arm32 (FIXME!)
@@ -231,8 +229,6 @@ static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
PTE_BIT_FUNC(wrprotect, |= _PAGE_READONLY);
PTE_BIT_FUNC(mkwrite, &= ~_PAGE_READONLY);
-PTE_BIT_FUNC(exprotect, |= _PAGE_NOT_USER);
-PTE_BIT_FUNC(mkexec, &= ~_PAGE_NOT_USER);
PTE_BIT_FUNC(mkclean, |= _PAGE_CLEAN);
PTE_BIT_FUNC(mkdirty, &= ~_PAGE_CLEAN);
PTE_BIT_FUNC(mkold, |= _PAGE_OLD);
diff --git a/include/asm-arm26/system.h b/include/asm-arm26/system.h
index 4703593b3bb5..e09da5ff1f54 100644
--- a/include/asm-arm26/system.h
+++ b/include/asm-arm26/system.h
@@ -110,16 +110,6 @@ do { \
} while (0)
/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
-/*
* Save the current interrupt enable state & disable IRQs
*/
#define local_irq_save(x) \
diff --git a/include/asm-arm26/termbits.h b/include/asm-arm26/termbits.h
index f66b51804736..48d2f5c7bcb8 100644
--- a/include/asm-arm26/termbits.h
+++ b/include/asm-arm26/termbits.h
@@ -138,6 +138,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -153,10 +154,12 @@ struct ktermios {
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
diff --git a/include/asm-arm26/termios.h b/include/asm-arm26/termios.h
index 329c324c4040..293e3f1bc3f2 100644
--- a/include/asm-arm26/termios.h
+++ b/include/asm-arm26/termios.h
@@ -82,8 +82,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-avr32/a.out.h b/include/asm-avr32/a.out.h
index 50bf6e31a143..9f398ab28ed0 100644
--- a/include/asm-avr32/a.out.h
+++ b/include/asm-avr32/a.out.h
@@ -20,6 +20,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index 9fd2e32f84b8..0215965dc586 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -21,6 +21,7 @@ void at32_map_usart(unsigned int hw_id, unsigned int line);
struct platform_device *at32_add_device_usart(unsigned int id);
struct eth_platform_data {
+ u32 phy_mask;
u8 is_rmii;
};
struct platform_device *
@@ -35,4 +36,18 @@ struct platform_device *
at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
unsigned long fbmem_start, unsigned long fbmem_len);
+/* depending on what's hooked up, not all SSC pins will be used */
+#define ATMEL_SSC_TK 0x01
+#define ATMEL_SSC_TF 0x02
+#define ATMEL_SSC_TD 0x04
+#define ATMEL_SSC_TX (ATMEL_SSC_TK | ATMEL_SSC_TF | ATMEL_SSC_TD)
+
+#define ATMEL_SSC_RK 0x10
+#define ATMEL_SSC_RF 0x20
+#define ATMEL_SSC_RD 0x40
+#define ATMEL_SSC_RX (ATMEL_SSC_RK | ATMEL_SSC_RF | ATMEL_SSC_RD)
+
+struct platform_device *
+at32_add_device_ssc(unsigned int id, unsigned int flags);
+
#endif /* __ASM_ARCH_BOARD_H */
diff --git a/include/asm-avr32/arch-at32ap/sm.h b/include/asm-avr32/arch-at32ap/sm.h
deleted file mode 100644
index 265a9ead20bf..000000000000
--- a/include/asm-avr32/arch-at32ap/sm.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * AT32 System Manager interface.
- *
- * Copyright (C) 2006 Atmel 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.
- */
-#ifndef __ASM_AVR32_AT32_SM_H__
-#define __ASM_AVR32_AT32_SM_H__
-
-struct irq_chip;
-struct platform_device;
-
-struct at32_sm {
- spinlock_t lock;
- void __iomem *regs;
- struct irq_chip *eim_chip;
- unsigned int eim_first_irq;
- struct platform_device *pdev;
-};
-
-extern struct platform_device at32_sm_device;
-extern struct at32_sm system_manager;
-
-#endif /* __ASM_AVR32_AT32_SM_H__ */
diff --git a/include/asm-avr32/atomic.h b/include/asm-avr32/atomic.h
index b9c2548a52f3..7ef3862a73d0 100644
--- a/include/asm-avr32/atomic.h
+++ b/include/asm-avr32/atomic.h
@@ -101,7 +101,7 @@ static inline int atomic_sub_unless(atomic_t *v, int a, int u)
" mov %1, 1\n"
"1:"
: "=&r"(tmp), "=&r"(result), "=o"(v->counter)
- : "m"(v->counter), "rKs21"(a), "rKs21"(u)
+ : "m"(v->counter), "rKs21"(a), "rKs21"(u), "1"(result)
: "cc", "memory");
return result;
@@ -137,7 +137,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
" mov %1, 1\n"
"1:"
: "=&r"(tmp), "=&r"(result), "=o"(v->counter)
- : "m"(v->counter), "r"(a), "ir"(u)
+ : "m"(v->counter), "r"(a), "ir"(u), "1"(result)
: "cc", "memory");
}
diff --git a/include/asm-avr32/fb.h b/include/asm-avr32/fb.h
new file mode 100644
index 000000000000..41baf84ad402
--- /dev/null
+++ b/include/asm-avr32/fb.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = __pgprot((pgprot_val(vma->vm_page_prot)
+ & ~_PAGE_CACHABLE)
+ | (_PAGE_BUFFER | _PAGE_DIRTY));
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-avr32/pgtable.h b/include/asm-avr32/pgtable.h
index f6cc2b0f75c3..c07bdd10b891 100644
--- a/include/asm-avr32/pgtable.h
+++ b/include/asm-avr32/pgtable.h
@@ -201,18 +201,10 @@ extern struct page *empty_zero_page;
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte)
-{
- return pte_val(pte) & _PAGE_USER;
-}
static inline int pte_write(pte_t pte)
{
return pte_val(pte) & _PAGE_RW;
}
-static inline int pte_exec(pte_t pte)
-{
- return pte_val(pte) & _PAGE_EXECUTE;
-}
static inline int pte_dirty(pte_t pte)
{
return pte_val(pte) & _PAGE_DIRTY;
@@ -231,21 +223,11 @@ static inline int pte_file(pte_t pte)
}
/* Mutator functions for PTE bits */
-static inline pte_t pte_rdprotect(pte_t pte)
-{
- set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER));
- return pte;
-}
static inline pte_t pte_wrprotect(pte_t pte)
{
set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW));
return pte;
}
-static inline pte_t pte_exprotect(pte_t pte)
-{
- set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_EXECUTE));
- return pte;
-}
static inline pte_t pte_mkclean(pte_t pte)
{
set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY));
@@ -256,21 +238,11 @@ static inline pte_t pte_mkold(pte_t pte)
set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED));
return pte;
}
-static inline pte_t pte_mkread(pte_t pte)
-{
- set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER));
- return pte;
-}
static inline pte_t pte_mkwrite(pte_t pte)
{
set_pte(&pte, __pte(pte_val(pte) | _PAGE_RW));
return pte;
}
-static inline pte_t pte_mkexec(pte_t pte)
-{
- set_pte(&pte, __pte(pte_val(pte) | _PAGE_EXECUTE));
- return pte;
-}
static inline pte_t pte_mkdirty(pte_t pte)
{
set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY));
diff --git a/include/asm-avr32/unaligned.h b/include/asm-avr32/unaligned.h
index 3042723fcbfd..36f5fd430543 100644
--- a/include/asm-avr32/unaligned.h
+++ b/include/asm-avr32/unaligned.h
@@ -7,19 +7,10 @@
* words, but halfwords must be halfword-aligned, and doublewords must
* be word-aligned.
*
- * TODO: Make all this CPU-specific and optimize.
+ * However, swapped word loads must be word-aligned so we can't
+ * optimize word loads in general.
*/
-#include <linux/string.h>
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
- ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr) \
- ({ __typeof__(*(ptr)) __tmp = (val); \
- memmove((ptr), &__tmp, sizeof(*(ptr))); \
- (void)0; })
+#include <asm-generic/unaligned.h>
#endif /* __ASM_AVR32_UNALIGNED_H */
diff --git a/include/asm-blackfin/Kbuild b/include/asm-blackfin/Kbuild
index c68e1680da01..71f8fe783258 100644
--- a/include/asm-blackfin/Kbuild
+++ b/include/asm-blackfin/Kbuild
@@ -1 +1,3 @@
include include/asm-generic/Kbuild.asm
+
+header-y += fixed_code.h
diff --git a/include/asm-blackfin/bfin-global.h b/include/asm-blackfin/bfin-global.h
index 57f37ccdcdf1..c4d6cbbf96d4 100644
--- a/include/asm-blackfin/bfin-global.h
+++ b/include/asm-blackfin/bfin-global.h
@@ -67,6 +67,18 @@ extern void evt14_softirq(void);
extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
extern void bfin_gpio_interrupt_setup(int irq, int irq_pfx, int type);
+extern asmlinkage void finish_atomic_sections (struct pt_regs *regs);
+extern char fixed_code_start;
+extern char fixed_code_end;
+extern int atomic_xchg32(void);
+extern int atomic_cas32(void);
+extern int atomic_add32(void);
+extern int atomic_sub32(void);
+extern int atomic_ior32(void);
+extern int atomic_and32(void);
+extern int atomic_xor32(void);
+extern void sigreturn_stub(void);
+
extern void *l1_data_A_sram_alloc(size_t);
extern void *l1_data_B_sram_alloc(size_t);
extern void *l1_inst_sram_alloc(size_t);
diff --git a/include/asm-blackfin/cplbinit.h b/include/asm-blackfin/cplbinit.h
index 3bad2d1e6a8c..bec6ecdf1bdb 100644
--- a/include/asm-blackfin/cplbinit.h
+++ b/include/asm-blackfin/cplbinit.h
@@ -57,8 +57,8 @@ struct cplb_tab {
u16 size;
};
-u_long icplb_table[MAX_CPLBS+1];
-u_long dcplb_table[MAX_CPLBS+1];
+extern u_long icplb_table[MAX_CPLBS+1];
+extern u_long dcplb_table[MAX_CPLBS+1];
/* Till here we are discussing about the static memory management model.
* However, the operating envoronments commonly define more CPLB
@@ -70,134 +70,27 @@ u_long dcplb_table[MAX_CPLBS+1];
*/
#ifdef CONFIG_CPLB_SWITCH_TAB_L1
-u_long ipdt_table[MAX_SWITCH_I_CPLBS+1]__attribute__((l1_data));
-u_long dpdt_table[MAX_SWITCH_D_CPLBS+1]__attribute__((l1_data));
+extern u_long ipdt_table[MAX_SWITCH_I_CPLBS+1]__attribute__((l1_data));
+extern u_long dpdt_table[MAX_SWITCH_D_CPLBS+1]__attribute__((l1_data));
#ifdef CONFIG_CPLB_INFO
-u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS]__attribute__((l1_data));
-u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS]__attribute__((l1_data));
+extern u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS]__attribute__((l1_data));
+extern u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS]__attribute__((l1_data));
#endif /* CONFIG_CPLB_INFO */
#else
-u_long ipdt_table[MAX_SWITCH_I_CPLBS+1];
-u_long dpdt_table[MAX_SWITCH_D_CPLBS+1];
+extern u_long ipdt_table[MAX_SWITCH_I_CPLBS+1];
+extern u_long dpdt_table[MAX_SWITCH_D_CPLBS+1];
#ifdef CONFIG_CPLB_INFO
-u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS];
-u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS];
+extern u_long ipdt_swapcount_table[MAX_SWITCH_I_CPLBS];
+extern u_long dpdt_swapcount_table[MAX_SWITCH_D_CPLBS];
#endif /* CONFIG_CPLB_INFO */
#endif /*CONFIG_CPLB_SWITCH_TAB_L1*/
-struct s_cplb {
- struct cplb_tab init_i;
- struct cplb_tab init_d;
- struct cplb_tab switch_i;
- struct cplb_tab switch_d;
-};
+extern unsigned long reserved_mem_dcache_on;
+extern unsigned long reserved_mem_icache_on;
-#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE)
-static struct cplb_desc cplb_data[] = {
- {
- .start = 0,
- .end = SIZE_4K,
- .psize = SIZE_4K,
- .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
- .i_conf = SDRAM_OOPS,
- .d_conf = SDRAM_OOPS,
-#if defined(CONFIG_DEBUG_HUNT_FOR_ZERO)
- .valid = 1,
-#else
- .valid = 0,
-#endif
- .name = "ZERO Pointer Saveguard",
- },
- {
- .start = L1_CODE_START,
- .end = L1_CODE_START + L1_CODE_LENGTH,
- .psize = SIZE_4M,
- .attr = INITIAL_T | SWITCH_T | I_CPLB,
- .i_conf = L1_IMEMORY,
- .d_conf = 0,
- .valid = 1,
- .name = "L1 I-Memory",
- },
- {
- .start = L1_DATA_A_START,
- .end = L1_DATA_B_START + L1_DATA_B_LENGTH,
- .psize = SIZE_4M,
- .attr = INITIAL_T | SWITCH_T | D_CPLB,
- .i_conf = 0,
- .d_conf = L1_DMEMORY,
-#if ((L1_DATA_A_LENGTH > 0) || (L1_DATA_B_LENGTH > 0))
- .valid = 1,
-#else
- .valid = 0,
-#endif
- .name = "L1 D-Memory",
- },
- {
- .start = 0,
- .end = 0, /* dynamic */
- .psize = 0,
- .attr = INITIAL_T | SWITCH_T | I_CPLB | D_CPLB,
- .i_conf = SDRAM_IGENERIC,
- .d_conf = SDRAM_DGENERIC,
- .valid = 1,
- .name = "SDRAM Kernel",
- },
- {
- .start = 0, /* dynamic */
- .end = 0, /* dynamic */
- .psize = 0,
- .attr = INITIAL_T | SWITCH_T | D_CPLB,
- .i_conf = SDRAM_IGENERIC,
- .d_conf = SDRAM_DNON_CHBL,
- .valid = 1,
- .name = "SDRAM RAM MTD",
- },
- {
- .start = 0, /* dynamic */
- .end = 0, /* dynamic */
- .psize = SIZE_1M,
- .attr = INITIAL_T | SWITCH_T | D_CPLB,
- .d_conf = SDRAM_DNON_CHBL,
- .valid = 1,//(DMA_UNCACHED_REGION > 0),
- .name = "SDRAM Uncached DMA ZONE",
- },
- {
- .start = 0, /* dynamic */
- .end = 0, /* dynamic */
- .psize = 0,
- .attr = SWITCH_T | D_CPLB,
- .i_conf = 0, /* dynamic */
- .d_conf = 0, /* dynamic */
- .valid = 1,
- .name = "SDRAM Reserved Memory",
- },
- {
- .start = ASYNC_BANK0_BASE,
- .end = ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE,
- .psize = 0,
- .attr = SWITCH_T | D_CPLB,
- .d_conf = SDRAM_EBIU,
- .valid = 1,
- .name = "ASYNC Memory",
- },
- {
-#if defined(CONFIG_BF561)
- .start = L2_SRAM,
- .end = L2_SRAM_END,
- .psize = SIZE_1M,
- .attr = SWITCH_T | D_CPLB,
- .i_conf = L2_MEMORY,
- .d_conf = L2_MEMORY,
- .valid = 1,
-#else
- .valid = 0,
-#endif
- .name = "L2 Memory",
- }
-};
-#endif
+extern void generate_cpl_tables(void);
diff --git a/include/asm-blackfin/fb.h b/include/asm-blackfin/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-blackfin/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-blackfin/fixed_code.h b/include/asm-blackfin/fixed_code.h
new file mode 100644
index 000000000000..e6df84ee1557
--- /dev/null
+++ b/include/asm-blackfin/fixed_code.h
@@ -0,0 +1,20 @@
+/* This file defines the fixed addresses where userspace programs can find
+ atomic code sequences. */
+
+#define FIXED_CODE_START 0x400
+
+#define SIGRETURN_STUB 0x400
+
+#define ATOMIC_SEQS_START 0x410
+
+#define ATOMIC_XCHG32 0x410
+#define ATOMIC_CAS32 0x420
+#define ATOMIC_ADD32 0x430
+#define ATOMIC_SUB32 0x440
+#define ATOMIC_IOR32 0x450
+#define ATOMIC_AND32 0x460
+#define ATOMIC_XOR32 0x470
+
+#define ATOMIC_SEQS_END 0x480
+
+#define FIXED_CODE_END 0x480
diff --git a/include/asm-blackfin/gpio.h b/include/asm-blackfin/gpio.h
index d98d77ad71f7..7480cfa7e2d6 100644
--- a/include/asm-blackfin/gpio.h
+++ b/include/asm-blackfin/gpio.h
@@ -204,8 +204,62 @@
#endif
+#ifdef BF548_FAMILY
+#include <asm-blackfin/mach-bf548/gpio.h>
+#endif
+
#ifdef BF561_FAMILY
#define MAX_BLACKFIN_GPIOS 48
+
+#define GPIO_PF0 0
+#define GPIO_PF1 1
+#define GPIO_PF2 2
+#define GPIO_PF3 3
+#define GPIO_PF4 4
+#define GPIO_PF5 5
+#define GPIO_PF6 6
+#define GPIO_PF7 7
+#define GPIO_PF8 8
+#define GPIO_PF9 9
+#define GPIO_PF10 10
+#define GPIO_PF11 11
+#define GPIO_PF12 12
+#define GPIO_PF13 13
+#define GPIO_PF14 14
+#define GPIO_PF15 15
+#define GPIO_PF16 16
+#define GPIO_PF17 17
+#define GPIO_PF18 18
+#define GPIO_PF19 19
+#define GPIO_PF20 20
+#define GPIO_PF21 21
+#define GPIO_PF22 22
+#define GPIO_PF23 23
+#define GPIO_PF24 24
+#define GPIO_PF25 25
+#define GPIO_PF26 26
+#define GPIO_PF27 27
+#define GPIO_PF28 28
+#define GPIO_PF29 29
+#define GPIO_PF30 30
+#define GPIO_PF31 31
+#define GPIO_PF32 32
+#define GPIO_PF33 33
+#define GPIO_PF34 34
+#define GPIO_PF35 35
+#define GPIO_PF36 36
+#define GPIO_PF37 37
+#define GPIO_PF38 38
+#define GPIO_PF39 39
+#define GPIO_PF40 40
+#define GPIO_PF41 41
+#define GPIO_PF42 42
+#define GPIO_PF43 43
+#define GPIO_PF44 44
+#define GPIO_PF45 45
+#define GPIO_PF46 46
+#define GPIO_PF47 47
+
#define PORT_FIO0 GPIO_0
#define PORT_FIO1 GPIO_16
#define PORT_FIO2 GPIO_32
@@ -230,6 +284,7 @@
* MODIFICATION HISTORY :
**************************************************************/
+#ifndef BF548_FAMILY
void set_gpio_dir(unsigned short, unsigned short);
void set_gpio_inen(unsigned short, unsigned short);
void set_gpio_polar(unsigned short, unsigned short);
@@ -299,6 +354,7 @@ struct gpio_port_t {
unsigned short dummy16;
unsigned short inen;
};
+#endif
#ifdef CONFIG_PM
#define PM_WAKE_RISING 0x1
@@ -357,8 +413,10 @@ void gpio_free(unsigned short);
void gpio_set_value(unsigned short gpio, unsigned short arg);
unsigned short gpio_get_value(unsigned short gpio);
+#ifndef BF548_FAMILY
#define gpio_get_value(gpio) get_gpio_data(gpio)
#define gpio_set_value(gpio, value) set_gpio_data(gpio, value)
+#endif
void gpio_direction_input(unsigned short gpio);
void gpio_direction_output(unsigned short gpio);
diff --git a/include/asm-blackfin/hardirq.h b/include/asm-blackfin/hardirq.h
index 0cab0d35badc..b6b19f1b9dab 100644
--- a/include/asm-blackfin/hardirq.h
+++ b/include/asm-blackfin/hardirq.h
@@ -28,7 +28,11 @@ typedef struct {
* SOFTIRQ_MASK: 0x00ff0000
*/
+#if NR_IRQS > 256
+#define HARDIRQ_BITS 9
+#else
#define HARDIRQ_BITS 8
+#endif
#ifdef NR_IRQS
# if (1 << HARDIRQ_BITS) < NR_IRQS
diff --git a/include/asm-blackfin/kgdb.h b/include/asm-blackfin/kgdb.h
new file mode 100644
index 000000000000..532bd9052004
--- /dev/null
+++ b/include/asm-blackfin/kgdb.h
@@ -0,0 +1,183 @@
+/*
+ * File: include/asm-blackfin/kgdb.h
+ * Based on:
+ * Author: Sonic Zhang
+ *
+ * Created:
+ * Description:
+ *
+ * Rev: $Id: kgdb_bfin_linux-2.6.x.patch 4934 2007-02-13 09:32:11Z sonicz $
+ *
+ * Modified:
+ * Copyright 2005-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __ASM_BLACKFIN_KGDB_H__
+#define __ASM_BLACKFIN_KGDB_H__
+
+#include <linux/ptrace.h>
+
+/* gdb locks */
+#define KGDB_MAX_NO_CPUS 8
+
+/************************************************************************/
+/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
+/* at least NUMREGBYTES*2 are needed for register packets */
+/* Longer buffer is needed to list all threads */
+#define BUFMAX 2048
+
+/*
+ * Note that this register image is different from
+ * the register image that Linux produces at interrupt time.
+ *
+ * Linux's register image is defined by struct pt_regs in ptrace.h.
+ */
+enum regnames {
+ /* Core Registers */
+ BFIN_R0 = 0,
+ BFIN_R1,
+ BFIN_R2,
+ BFIN_R3,
+ BFIN_R4,
+ BFIN_R5,
+ BFIN_R6,
+ BFIN_R7,
+ BFIN_P0,
+ BFIN_P1,
+ BFIN_P2,
+ BFIN_P3,
+ BFIN_P4,
+ BFIN_P5,
+ BFIN_SP,
+ BFIN_FP,
+ BFIN_I0,
+ BFIN_I1,
+ BFIN_I2,
+ BFIN_I3,
+ BFIN_M0,
+ BFIN_M1,
+ BFIN_M2,
+ BFIN_M3,
+ BFIN_B0,
+ BFIN_B1,
+ BFIN_B2,
+ BFIN_B3,
+ BFIN_L0,
+ BFIN_L1,
+ BFIN_L2,
+ BFIN_L3,
+ BFIN_A0_DOT_X,
+ BFIN_A0_DOT_W,
+ BFIN_A1_DOT_X,
+ BFIN_A1_DOT_W,
+ BFIN_ASTAT,
+ BFIN_RETS,
+ BFIN_LC0,
+ BFIN_LT0,
+ BFIN_LB0,
+ BFIN_LC1,
+ BFIN_LT1,
+ BFIN_LB1,
+ BFIN_CYCLES,
+ BFIN_CYCLES2,
+ BFIN_USP,
+ BFIN_SEQSTAT,
+ BFIN_SYSCFG,
+ BFIN_RETI,
+ BFIN_RETX,
+ BFIN_RETN,
+ BFIN_RETE,
+
+ /* Pseudo Registers */
+ BFIN_PC,
+ BFIN_CC,
+ BFIN_EXTRA1, /* Address of .text section. */
+ BFIN_EXTRA2, /* Address of .data section. */
+ BFIN_EXTRA3, /* Address of .bss section. */
+ BFIN_FDPIC_EXEC,
+ BFIN_FDPIC_INTERP,
+
+ /* MMRs */
+ BFIN_IPEND,
+
+ /* LAST ENTRY SHOULD NOT BE CHANGED. */
+ BFIN_NUM_REGS /* The number of all registers. */
+};
+
+/* Number of bytes of registers. */
+#define NUMREGBYTES BFIN_NUM_REGS*4
+
+#define BREAKPOINT() asm(" EXCPT 2;");
+#define BREAK_INSTR_SIZE 2
+#define HW_BREAKPOINT_NUM 6
+
+/* Instruction watchpoint address control register bits mask */
+#define WPPWR 0x1
+#define WPIREN01 0x2
+#define WPIRINV01 0x4
+#define WPIAEN0 0x8
+#define WPIAEN1 0x10
+#define WPICNTEN0 0x20
+#define WPICNTEN1 0x40
+#define EMUSW0 0x80
+#define EMUSW1 0x100
+#define WPIREN23 0x200
+#define WPIRINV23 0x400
+#define WPIAEN2 0x800
+#define WPIAEN3 0x1000
+#define WPICNTEN2 0x2000
+#define WPICNTEN3 0x4000
+#define EMUSW2 0x8000
+#define EMUSW3 0x10000
+#define WPIREN45 0x20000
+#define WPIRINV45 0x40000
+#define WPIAEN4 0x80000
+#define WPIAEN5 0x100000
+#define WPICNTEN4 0x200000
+#define WPICNTEN5 0x400000
+#define EMUSW4 0x800000
+#define EMUSW5 0x1000000
+#define WPAND 0x2000000
+
+/* Data watchpoint address control register bits mask */
+#define WPDREN01 0x1
+#define WPDRINV01 0x2
+#define WPDAEN0 0x4
+#define WPDAEN1 0x8
+#define WPDCNTEN0 0x10
+#define WPDCNTEN1 0x20
+#define WPDSRC0 0xc0
+#define WPDACC0 0x300
+#define WPDSRC1 0xc00
+#define WPDACC1 0x3000
+
+/* Watchpoint status register bits mask */
+#define STATIA0 0x1
+#define STATIA1 0x2
+#define STATIA2 0x4
+#define STATIA3 0x8
+#define STATIA4 0x10
+#define STATIA5 0x20
+#define STATDA0 0x40
+#define STATDA1 0x80
+
+extern void kgdb_print(const char *fmt, ...);
+
+#endif
diff --git a/include/asm-blackfin/mach-bf533/dma.h b/include/asm-blackfin/mach-bf533/dma.h
index bd9d5e94307d..16c672c01d80 100644
--- a/include/asm-blackfin/mach-bf533/dma.h
+++ b/include/asm-blackfin/mach-bf533/dma.h
@@ -51,4 +51,7 @@
#define CH_MEM_STREAM1_DEST 10 /* TX */
#define CH_MEM_STREAM1_SRC 11 /* RX */
+extern int channel2irq(unsigned int channel);
+extern struct dma_register *base_addr[];
+
#endif
diff --git a/include/asm-blackfin/mach-bf533/portmux.h b/include/asm-blackfin/mach-bf533/portmux.h
new file mode 100644
index 000000000000..b88d7a03ee3e
--- /dev/null
+++ b/include/asm-blackfin/mach-bf533/portmux.h
@@ -0,0 +1,65 @@
+#ifndef _MACH_PORTMUX_H_
+#define _MACH_PORTMUX_H_
+
+#define P_PPI0_CLK (P_DONTCARE)
+#define P_PPI0_FS1 (P_DONTCARE)
+#define P_PPI0_FS2 (P_DONTCARE)
+#define P_PPI0_FS3 (P_DEFINED | P_IDENT(GPIO_PF3))
+#define P_PPI0_D15 (P_DEFINED | P_IDENT(GPIO_PF4))
+#define P_PPI0_D14 (P_DEFINED | P_IDENT(GPIO_PF5))
+#define P_PPI0_D13 (P_DEFINED | P_IDENT(GPIO_PF6))
+#define P_PPI0_D12 (P_DEFINED | P_IDENT(GPIO_PF7))
+#define P_PPI0_D11 (P_DEFINED | P_IDENT(GPIO_PF8))
+#define P_PPI0_D10 (P_DEFINED | P_IDENT(GPIO_PF9))
+#define P_PPI0_D9 (P_DEFINED | P_IDENT(GPIO_PF10))
+#define P_PPI0_D8 (P_DEFINED | P_IDENT(GPIO_PF11))
+#define P_PPI0_D0 (P_DONTCARE)
+#define P_PPI0_D1 (P_DONTCARE)
+#define P_PPI0_D2 (P_DONTCARE)
+#define P_PPI0_D3 (P_DONTCARE)
+#define P_PPI0_D4 (P_DEFINED | P_IDENT(GPIO_PF15))
+#define P_PPI0_D5 (P_DEFINED | P_IDENT(GPIO_PF14))
+#define P_PPI0_D6 (P_DEFINED | P_IDENT(GPIO_PF13))
+#define P_PPI0_D7 (P_DEFINED | P_IDENT(GPIO_PF12))
+
+#define P_SPORT1_TSCLK (P_DONTCARE)
+#define P_SPORT1_RSCLK (P_DONTCARE)
+#define P_SPORT0_TSCLK (P_DONTCARE)
+#define P_SPORT0_RSCLK (P_DONTCARE)
+#define P_UART0_RX (P_DONTCARE)
+#define P_UART0_TX (P_DONTCARE)
+#define P_SPORT1_DRSEC (P_DONTCARE)
+#define P_SPORT1_RFS (P_DONTCARE)
+#define P_SPORT1_DTPRI (P_DONTCARE)
+#define P_SPORT1_DTSEC (P_DONTCARE)
+#define P_SPORT1_TFS (P_DONTCARE)
+#define P_SPORT1_DRPRI (P_DONTCARE)
+#define P_SPORT0_DRSEC (P_DONTCARE)
+#define P_SPORT0_RFS (P_DONTCARE)
+#define P_SPORT0_DTPRI (P_DONTCARE)
+#define P_SPORT0_DTSEC (P_DONTCARE)
+#define P_SPORT0_TFS (P_DONTCARE)
+#define P_SPORT0_DRPRI (P_DONTCARE)
+
+#define P_SPI0_MOSI (P_DONTCARE)
+#define P_SPI0_MIS0 (P_DONTCARE)
+#define P_SPI0_SCK (P_DONTCARE)
+#define P_SPI0_SSEL7 (P_DEFINED | P_IDENT(GPIO_PF7))
+#define P_SPI0_SSEL6 (P_DEFINED | P_IDENT(GPIO_PF6))
+#define P_SPI0_SSEL5 (P_DEFINED | P_IDENT(GPIO_PF5))
+#define P_SPI0_SSEL4 (P_DEFINED | P_IDENT(GPIO_PF4))
+#define P_SPI0_SSEL3 (P_DEFINED | P_IDENT(GPIO_PF3))
+#define P_SPI0_SSEL2 (P_DEFINED | P_IDENT(GPIO_PF2))
+#define P_SPI0_SSEL1 (P_DEFINED | P_IDENT(GPIO_PF1))
+#define P_SPI0_SS (P_DEFINED | P_IDENT(GPIO_PF0))
+
+#define P_TMR2 (P_DONTCARE)
+#define P_TMR1 (P_DONTCARE)
+#define P_TMR0 (P_DONTCARE)
+#define P_TMRCLK (P_DEFINED | P_IDENT(GPIO_PF1))
+
+
+
+
+
+#endif /* _MACH_PORTMUX_H_ */
diff --git a/include/asm-blackfin/mach-bf537/dma.h b/include/asm-blackfin/mach-bf537/dma.h
index 7a964040870a..021991984e6e 100644
--- a/include/asm-blackfin/mach-bf537/dma.h
+++ b/include/asm-blackfin/mach-bf537/dma.h
@@ -52,4 +52,7 @@
#define CH_MEM_STREAM1_DEST 14 /* TX */
#define CH_MEM_STREAM1_SRC 15 /* RX */
+extern int channel2irq(unsigned int channel);
+extern struct dma_register *base_addr[];
+
#endif
diff --git a/include/asm-blackfin/mach-bf537/portmux.h b/include/asm-blackfin/mach-bf537/portmux.h
new file mode 100644
index 000000000000..23e13c5abc4d
--- /dev/null
+++ b/include/asm-blackfin/mach-bf537/portmux.h
@@ -0,0 +1,109 @@
+#ifndef _MACH_PORTMUX_H_
+#define _MACH_PORTMUX_H_
+
+#define P_UART0_TX (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
+#define P_UART0_RX (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
+#define P_UART1_TX (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
+#define P_UART1_RX (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(0))
+#define P_TMR5 (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(0))
+#define P_TMR4 (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(0))
+#define P_TMR3 (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(0))
+#define P_TMR2 (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(0))
+#define P_TMR1 (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(0))
+#define P_TMR0 (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(0))
+#define P_SPI0_SSEL1 (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(0))
+#define P_SPI0_MOSI (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(0))
+#define P_SPI0_MISO (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(0))
+#define P_SPI0_SCK (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(0))
+#define P_SPI0_SS (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(0))
+#define P_PPI0_CLK (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(0))
+#define P_DMAR0 (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(1))
+#define P_DMAR1 (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(1))
+#define P_TMR7 (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(1))
+#define P_TMR6 (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(1))
+#define P_SPI0_SSEL6 (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(1))
+#define P_SPI0_SSEL5 (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(1))
+#define P_SPI0_SSEL4 (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(1))
+#define P_PPI0_FS3 (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(1))
+#define P_PPI0_FS2 (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(1))
+#define P_PPI0_FS1 (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(1))
+#define P_TACLK0 (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1))
+#define P_TMRCLK (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1))
+
+#define P_PPI0_D0 (P_DEFINED | P_IDENT(GPIO_PG0) | P_FUNCT(0))
+#define P_PPI0_D1 (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
+#define P_PPI0_D2 (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(0))
+#define P_PPI0_D3 (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(0))
+#define P_PPI0_D4 (P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(0))
+#define P_PPI0_D5 (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(0))
+#define P_PPI0_D6 (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(0))
+#define P_PPI0_D7 (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(0))
+#define P_PPI0_D8 (P_DEFINED | P_IDENT(GPIO_PG8) | P_FUNCT(0))
+#define P_PPI0_D9 (P_DEFINED | P_IDENT(GPIO_PG9) | P_FUNCT(0))
+#define P_PPI0_D10 (P_DEFINED | P_IDENT(GPIO_PG10) | P_FUNCT(0))
+#define P_PPI0_D11 (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(0))
+#define P_PPI0_D12 (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(0))
+#define P_PPI0_D13 (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(0))
+#define P_PPI0_D14 (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(0))
+#define P_PPI0_D15 (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(0))
+#define P_SPORT1_DRSEC (P_DEFINED | P_IDENT(GPIO_PG8) | P_FUNCT(1))
+#define P_SPORT1_DTSEC (P_DEFINED | P_IDENT(GPIO_PG9) | P_FUNCT(1))
+#define P_SPORT1_RSCLK (P_DEFINED | P_IDENT(GPIO_PG10) | P_FUNCT(1))
+#define P_SPORT1_RFS (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(1))
+#define P_SPORT1_DRPRI (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(1))
+#define P_SPORT1_TSCLK (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(1))
+#define P_SPORT1_TFS (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(1))
+#define P_SPORT1_DTPRI (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(1))
+
+#define P_MII0_ETxD0 (P_DEFINED | P_IDENT(GPIO_PH0) | P_FUNCT(0))
+#define P_MII0_ETxD1 (P_DEFINED | P_IDENT(GPIO_PH1) | P_FUNCT(0))
+#define P_MII0_ETxD2 (P_DEFINED | P_IDENT(GPIO_PH2) | P_FUNCT(0))
+#define P_MII0_ETxD3 (P_DEFINED | P_IDENT(GPIO_PH3) | P_FUNCT(0))
+#define P_MII0_ETxEN (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(0))
+#define P_MII0_TxCLK (P_DEFINED | P_IDENT(GPIO_PH5) | P_FUNCT(0))
+#define P_MII0_PHYINT (P_DEFINED | P_IDENT(GPIO_PH6) | P_FUNCT(0))
+#define P_MII0_COL (P_DEFINED | P_IDENT(GPIO_PH7) | P_FUNCT(0))
+#define P_MII0_ERxD0 (P_DEFINED | P_IDENT(GPIO_PH8) | P_FUNCT(0))
+#define P_MII0_ERxD1 (P_DEFINED | P_IDENT(GPIO_PH9) | P_FUNCT(0))
+#define P_MII0_ERxD2 (P_DEFINED | P_IDENT(GPIO_PH10) | P_FUNCT(0))
+#define P_MII0_ERxD3 (P_DEFINED | P_IDENT(GPIO_PH11) | P_FUNCT(0))
+#define P_MII0_ERxDV (P_DEFINED | P_IDENT(GPIO_PH12) | P_FUNCT(0))
+#define P_MII0_ERxCLK (P_DEFINED | P_IDENT(GPIO_PH13) | P_FUNCT(0))
+#define P_MII0_ERxER (P_DEFINED | P_IDENT(GPIO_PH14) | P_FUNCT(0))
+#define P_MII0_CRS (P_DEFINED | P_IDENT(GPIO_PH15) | P_FUNCT(0))
+#define P_RMII0_REF_CLK (P_DEFINED | P_IDENT(GPIO_PH5) | P_FUNCT(1))
+#define P_RMII0_MDINT (P_DEFINED | P_IDENT(GPIO_PH6) | P_FUNCT(1))
+#define P_RMII0_CRS_DV (P_DEFINED | P_IDENT(GPIO_PH15) | P_FUNCT(1))
+
+#define PORT_PJ0 (GPIO_PH15 + 1)
+#define PORT_PJ1 (GPIO_PH15 + 2)
+#define PORT_PJ2 (GPIO_PH15 + 3)
+#define PORT_PJ3 (GPIO_PH15 + 4)
+#define PORT_PJ4 (GPIO_PH15 + 5)
+#define PORT_PJ5 (GPIO_PH15 + 6)
+#define PORT_PJ6 (GPIO_PH15 + 7)
+#define PORT_PJ7 (GPIO_PH15 + 8)
+#define PORT_PJ8 (GPIO_PH15 + 9)
+#define PORT_PJ9 (GPIO_PH15 + 10)
+#define PORT_PJ10 (GPIO_PH15 + 11)
+#define PORT_PJ11 (GPIO_PH15 + 12)
+
+#define P_MDC (P_DEFINED | P_IDENT(PORT_PJ0) | P_FUNCT(0))
+#define P_MDIO (P_DEFINED | P_IDENT(PORT_PJ1) | P_FUNCT(0))
+#define P_TWI0_SCL (P_DEFINED | P_IDENT(PORT_PJ2) | P_FUNCT(0))
+#define P_TWI0_SDA (P_DEFINED | P_IDENT(PORT_PJ3) | P_FUNCT(0))
+#define P_SPORT0_DRSEC (P_DEFINED | P_IDENT(PORT_PJ4) | P_FUNCT(0))
+#define P_SPORT0_DTSEC (P_DEFINED | P_IDENT(PORT_PJ5) | P_FUNCT(0))
+#define P_SPORT0_RSCLK (P_DEFINED | P_IDENT(PORT_PJ6) | P_FUNCT(0))
+#define P_SPORT0_RFS (P_DEFINED | P_IDENT(PORT_PJ7) | P_FUNCT(0))
+#define P_SPORT0_DRPRI (P_DEFINED | P_IDENT(PORT_PJ8) | P_FUNCT(0))
+#define P_SPORT0_TSCLK (P_DEFINED | P_IDENT(PORT_PJ9) | P_FUNCT(0))
+#define P_SPORT0_TFS (P_DEFINED | P_IDENT(PORT_PJ10) | P_FUNCT(0))
+#define P_SPORT0_DTPRI (P_DEFINED | P_IDENT(PORT_PJ11) | P_FUNCT(1))
+#define P_CAN0_RX (P_DEFINED | P_IDENT(PORT_PJ4) | P_FUNCT(1))
+#define P_CAN0_TX (P_DEFINED | P_IDENT(PORT_PJ5) | P_FUNCT(1))
+#define P_SPI0_SSEL3 (P_DEFINED | P_IDENT(PORT_PJ10) | P_FUNCT(1))
+#define P_SPI0_SSEL2 (P_DEFINED | P_IDENT(PORT_PJ11) | P_FUNCT(1))
+#define P_SPI0_SSEL7 (P_DEFINED | P_IDENT(PORT_PJ5) | P_FUNCT(2))
+
+#endif /* _MACH_PORTMUX_H_ */
diff --git a/include/asm-blackfin/mach-bf548/anomaly.h b/include/asm-blackfin/mach-bf548/anomaly.h
new file mode 100644
index 000000000000..aca1d4ba145c
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/anomaly.h
@@ -0,0 +1,74 @@
+
+/*
+ * File: include/asm-blackfin/mach-bf548/anomaly.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_ANOMALY_H_
+#define _MACH_ANOMALY_H_
+#define ANOMALY_05000074 /* A multi issue instruction with dsp32shiftimm in
+ slot1 and store of a P register in slot 2 is not
+ supported */
+#define ANOMALY_05000119 /* DMA_RUN bit is not valid after a Peripheral Receive
+ Channel DMA stops */
+#define ANOMALY_05000122 /* Rx.H can not be used to access 16-bit System MMR
+ registers. */
+#define ANOMALY_05000245 /* Spurious Hardware Error from an Access in the
+ Shadow of a Conditional Branch */
+#define ANOMALY_05000255 /* Entering Hibernate Mode with RTC Seconds event
+ interrupt not functional */
+#define ANOMALY_05000265 /* Sensitivity to noise with slow input edge rates on
+ SPORT external receive and transmit clocks. */
+#define ANOMALY_05000272 /* Certain data cache write through modes fail for
+ VDDint <=0.9V */
+#define ANOMALY_05000281 /* False Hardware Error Exception when ISR context is
+ not restored */
+#define ANOMALY_05000310 /* False Hardware Errors Caused by Fetches at the
+ Boundary of Reserved Memory */
+#define ANOMALY_05000312 /* Errors When SSYNC, CSYNC, or Loads to LT, LB and
+ LC Registers Are Interrupted */
+#define ANOMALY_05000324 /* TWI Slave Boot Mode Is Not Functional */
+#define ANOMALY_05000325 /* External FIFO Boot Mode Is Not Functional */
+#define ANOMALY_05000327 /* Data Lost When Core and DMA Accesses Are Made to
+ the USB FIFO Simultaneously */
+#define ANOMALY_05000328 /* Incorrect Access of OTP_STATUS During otp_write()
+ function */
+#define ANOMALY_05000329 /* Synchronous Burst Flash Boot Mode Is Not Functional
+ */
+#define ANOMALY_05000330 /* Host DMA Boot Mode Is Not Functional */
+#define ANOMALY_05000334 /* Inadequate Timing Margins on DDR DQS to DQ and DQM
+ Skew */
+#define ANOMALY_05000335 /* Inadequate Rotary Debounce Logic Duration */
+#define ANOMALY_05000336 /* Phantom Interrupt Occurs After First Configuration
+ of Host DMA Port */
+#define ANOMALY_05000337 /* Disallowed Configuration Prevents Subsequent
+ Allowed Configuration on Host DMA Port */
+#define ANOMALY_05000338 /* Slave-Mode SPI0 MISO Failure With CPHA = 0 */
+
+#endif /* _MACH_ANOMALY_H_ */
diff --git a/include/asm-blackfin/mach-bf548/bf548.h b/include/asm-blackfin/mach-bf548/bf548.h
new file mode 100644
index 000000000000..9498313a2cb7
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/bf548.h
@@ -0,0 +1,271 @@
+/*
+ * File: include/asm-blackfin/mach-bf548/bf548.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description: System MMR register and memory map for ADSP-BF548
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __MACH_BF548_H__
+#define __MACH_BF548_H__
+
+#define SUPPORTED_REVID 0
+
+#define OFFSET_(x) ((x) & 0x0000FFFF)
+
+/*some misc defines*/
+#define IMASK_IVG15 0x8000
+#define IMASK_IVG14 0x4000
+#define IMASK_IVG13 0x2000
+#define IMASK_IVG12 0x1000
+
+#define IMASK_IVG11 0x0800
+#define IMASK_IVG10 0x0400
+#define IMASK_IVG9 0x0200
+#define IMASK_IVG8 0x0100
+
+#define IMASK_IVG7 0x0080
+#define IMASK_IVGTMR 0x0040
+#define IMASK_IVGHW 0x0020
+
+/***************************/
+
+
+#define BLKFIN_DSUBBANKS 4
+#define BLKFIN_DWAYS 2
+#define BLKFIN_DLINES 64
+#define BLKFIN_ISUBBANKS 4
+#define BLKFIN_IWAYS 4
+#define BLKFIN_ILINES 32
+
+#define WAY0_L 0x1
+#define WAY1_L 0x2
+#define WAY01_L 0x3
+#define WAY2_L 0x4
+#define WAY02_L 0x5
+#define WAY12_L 0x6
+#define WAY012_L 0x7
+
+#define WAY3_L 0x8
+#define WAY03_L 0x9
+#define WAY13_L 0xA
+#define WAY013_L 0xB
+
+#define WAY32_L 0xC
+#define WAY320_L 0xD
+#define WAY321_L 0xE
+#define WAYALL_L 0xF
+
+#define DMC_ENABLE (2<<2) /*yes, 2, not 1 */
+
+/********************************* EBIU Settings ************************************/
+#define AMBCTL0VAL ((CONFIG_BANK_1 << 16) | CONFIG_BANK_0)
+#define AMBCTL1VAL ((CONFIG_BANK_3 << 16) | CONFIG_BANK_2)
+
+#ifdef CONFIG_C_AMBEN_ALL
+#define V_AMBEN AMBEN_ALL
+#endif
+#ifdef CONFIG_C_AMBEN
+#define V_AMBEN 0x0
+#endif
+#ifdef CONFIG_C_AMBEN_B0
+#define V_AMBEN AMBEN_B0
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1
+#define V_AMBEN AMBEN_B0_B1
+#endif
+#ifdef CONFIG_C_AMBEN_B0_B1_B2
+#define V_AMBEN AMBEN_B0_B1_B2
+#endif
+#ifdef CONFIG_C_AMCKEN
+#define V_AMCKEN AMCKEN
+#else
+#define V_AMCKEN 0x0
+#endif
+
+#define AMGCTLVAL (V_AMBEN | V_AMCKEN)
+
+#define MAX_VC 650000000
+#define MIN_VC 50000000
+
+/********************************PLL Settings **************************************/
+#ifdef CONFIG_BFIN_KERNEL_CLOCK
+#if (CONFIG_VCO_MULT < 0)
+#error "VCO Multiplier is less than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT == 0)
+#error "VCO Multiplier should be greater than 0. Please select a different value"
+#endif
+
+#if (CONFIG_VCO_MULT > 64)
+#error "VCO Multiplier is more than 64. Please select a different value"
+#endif
+
+#ifndef CONFIG_CLKIN_HALF
+#define CONFIG_VCO_HZ (CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)
+#else
+#define CONFIG_VCO_HZ ((CONFIG_CLKIN_HZ * CONFIG_VCO_MULT)/2)
+#endif
+
+#ifndef CONFIG_PLL_BYPASS
+#define CONFIG_CCLK_HZ (CONFIG_VCO_HZ/CONFIG_CCLK_DIV)
+#define CONFIG_SCLK_HZ (CONFIG_VCO_HZ/CONFIG_SCLK_DIV)
+#else
+#define CONFIG_CCLK_HZ CONFIG_CLKIN_HZ
+#define CONFIG_SCLK_HZ CONFIG_CLKIN_HZ
+#endif
+
+#if (CONFIG_SCLK_DIV < 1)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_SCLK_DIV > 15)
+#error "SCLK DIV cannot be less than 1 or more than 15. Please select a proper value"
+#endif
+
+#if (CONFIG_CCLK_DIV != 1)
+#if (CONFIG_CCLK_DIV != 2)
+#if (CONFIG_CCLK_DIV != 4)
+#if (CONFIG_CCLK_DIV != 8)
+#error "CCLK DIV can be 1,2,4 or 8 only. Please select a proper value"
+#endif
+#endif
+#endif
+#endif
+
+#if (CONFIG_VCO_HZ > MAX_VC)
+#error "VCO selected is more than maximum value. Please change the VCO multipler"
+#endif
+
+#if (CONFIG_SCLK_HZ > 133000000)
+#error "Sclk value selected is more than maximum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ < 27000000)
+#error "Sclk value selected is less than minimum. Please select a proper value for SCLK multiplier"
+#endif
+
+#if (CONFIG_SCLK_HZ >= CONFIG_CCLK_HZ)
+#if (CONFIG_SCLK_HZ != CONFIG_CLKIN_HZ)
+#if (CONFIG_CCLK_HZ != CONFIG_CLKIN_HZ)
+#error "Please select sclk less than cclk"
+#endif
+#endif
+#endif
+
+#if (CONFIG_CCLK_DIV == 1)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV1
+#endif
+#if (CONFIG_CCLK_DIV == 2)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV2
+#endif
+#if (CONFIG_CCLK_DIV == 4)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV4
+#endif
+#if (CONFIG_CCLK_DIV == 8)
+#define CONFIG_CCLK_ACT_DIV CCLK_DIV8
+#endif
+#ifndef CONFIG_CCLK_ACT_DIV
+#define CONFIG_CCLK_ACT_DIV CONFIG_CCLK_DIV_not_defined_properly
+#endif
+
+#endif /* CONFIG_BFIN_KERNEL_CLOCK */
+
+#ifdef CONFIG_BF542
+#define CPU "BF542"
+#define CPUID 0x027c8000
+#endif
+#ifdef CONFIG_BF544
+#define CPU "BF544"
+#define CPUID 0x027c8000
+#endif
+#ifdef CONFIG_BF548
+#define CPU "BF548"
+#define CPUID 0x027c6000
+#endif
+#ifdef CONFIG_BF549
+#define CPU "BF549"
+#endif
+#ifndef CPU
+#define CPU "UNKNOWN"
+#define CPUID 0x0
+#endif
+
+#if (CONFIG_MEM_SIZE % 4)
+#error "SDRAM mem size must be multible of 4MB"
+#endif
+
+#define SDRAM_IGENERIC (CPLB_L1_CHBL | CPLB_USER_RD | CPLB_VALID | CPLB_PORTPRIO)
+#define SDRAM_IKERNEL (SDRAM_IGENERIC | CPLB_LOCK)
+#define L1_IMEMORY ( CPLB_USER_RD | CPLB_VALID | CPLB_LOCK)
+#define SDRAM_INON_CHBL ( CPLB_USER_RD | CPLB_VALID)
+
+/*Use the menuconfig cache policy here - CONFIG_BLKFIN_WT/CONFIG_BLKFIN_WB*/
+
+#define ANOMALY_05000158_WORKAROUND 0x200
+#ifdef CONFIG_BLKFIN_WB /*Write Back Policy */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_DIRTY \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND)
+#else /*Write Through */
+#define SDRAM_DGENERIC (CPLB_L1_CHBL | CPLB_WT | CPLB_L1_AOW \
+ | CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#endif
+
+
+#define L1_DMEMORY (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY )
+#define SDRAM_DNON_CHBL (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#define SDRAM_EBIU (CPLB_SUPV_WR | CPLB_USER_WR | CPLB_USER_RD | CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_DIRTY )
+#define SDRAM_OOPS (CPLB_VALID | ANOMALY_05000158_WORKAROUND | CPLB_LOCK | CPLB_DIRTY )
+
+#define SIZE_1K 0x00000400 /* 1K */
+#define SIZE_4K 0x00001000 /* 4K */
+#define SIZE_1M 0x00100000 /* 1M */
+#define SIZE_4M 0x00400000 /* 4M */
+
+#define MAX_CPLBS (16 * 2)
+
+/*
+* Number of required data CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 16 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Data Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+* 1 for ASYNC Memory
+*/
+
+
+#define MAX_SWITCH_D_CPLBS (((CONFIG_MEM_SIZE / 4) + 16 + 1 + 1 + 1) * 2)
+
+/*
+* Number of required instruction CPLB switchtable entries
+* MEMSIZE / 4 (we mostly install 4M page size CPLBs
+* approx 12 for smaller 1MB page size CPLBs for allignment purposes
+* 1 for L1 Instruction Memory
+* 1 for CONFIG_DEBUG_HUNT_FOR_ZERO
+*/
+
+#define MAX_SWITCH_I_CPLBS (((CONFIG_MEM_SIZE / 4) + 12 + 1 + 1) * 2)
+
+#endif /* __MACH_BF48_H__ */
diff --git a/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
new file mode 100644
index 000000000000..2f4afc90db11
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
@@ -0,0 +1,193 @@
+#include <linux/serial.h>
+#include <asm/dma.h>
+
+#define NR_PORTS 4
+
+#define OFFSET_DLL 0x00 /* Divisor Latch (Low-Byte) */
+#define OFFSET_DLH 0x04 /* Divisor Latch (High-Byte) */
+#define OFFSET_GCTL 0x08 /* Global Control Register */
+#define OFFSET_LCR 0x0C /* Line Control Register */
+#define OFFSET_MCR 0x10 /* Modem Control Register */
+#define OFFSET_LSR 0x14 /* Line Status Register */
+#define OFFSET_MSR 0x18 /* Modem Status Register */
+#define OFFSET_SCR 0x1C /* SCR Scratch Register */
+#define OFFSET_IER_SET 0x20 /* Set Interrupt Enable Register */
+#define OFFSET_IER_CLEAR 0x24 /* Clear Interrupt Enable Register */
+#define OFFSET_THR 0x28 /* Transmit Holding register */
+#define OFFSET_RBR 0x2C /* Receive Buffer register */
+
+#define UART_GET_CHAR(uart) bfin_read16(((uart)->port.membase + OFFSET_RBR))
+#define UART_GET_DLL(uart) bfin_read16(((uart)->port.membase + OFFSET_DLL))
+#define UART_GET_DLH(uart) bfin_read16(((uart)->port.membase + OFFSET_DLH))
+#define UART_GET_IER(uart) bfin_read16(((uart)->port.membase + OFFSET_IER_SET))
+#define UART_GET_LCR(uart) bfin_read16(((uart)->port.membase + OFFSET_LCR))
+#define UART_GET_LSR(uart) bfin_read16(((uart)->port.membase + OFFSET_LSR))
+#define UART_GET_GCTL(uart) bfin_read16(((uart)->port.membase + OFFSET_GCTL))
+
+#define UART_PUT_CHAR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_THR),v)
+#define UART_PUT_DLL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLL),v)
+#define UART_SET_IER(uart,v) bfin_write16(((uart)->port.membase + OFFSET_IER_SET),v)
+#define UART_CLEAR_IER(uart,v) bfin_write16(((uart)->port.membase + OFFSET_IER_CLEAR),v)
+#define UART_PUT_DLH(uart,v) bfin_write16(((uart)->port.membase + OFFSET_DLH),v)
+#define UART_PUT_LSR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LSR),v)
+#define UART_PUT_LCR(uart,v) bfin_write16(((uart)->port.membase + OFFSET_LCR),v)
+#define UART_PUT_GCTL(uart,v) bfin_write16(((uart)->port.membase + OFFSET_GCTL),v)
+
+#if defined(CONFIG_BFIN_UART0_CTSRTS) || defined(CONFIG_BFIN_UART1_CTSRTS)
+# define CONFIG_SERIAL_BFIN_CTSRTS
+
+# ifndef CONFIG_UART0_CTS_PIN
+# define CONFIG_UART0_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART0_RTS_PIN
+# define CONFIG_UART0_RTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_CTS_PIN
+# define CONFIG_UART1_CTS_PIN -1
+# endif
+
+# ifndef CONFIG_UART1_RTS_PIN
+# define CONFIG_UART1_RTS_PIN -1
+# endif
+#endif
+/*
+ * The pin configuration is different from schematic
+ */
+struct bfin_serial_port {
+ struct uart_port port;
+ unsigned int old_status;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ int tx_done;
+ int tx_count;
+ struct circ_buf rx_dma_buf;
+ struct timer_list rx_dma_timer;
+ int rx_dma_nrows;
+ unsigned int tx_dma_channel;
+ unsigned int rx_dma_channel;
+ struct work_struct tx_dma_workqueue;
+#else
+ struct work_struct cts_workqueue;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int cts_pin;
+ int rts_pin;
+#endif
+};
+
+struct bfin_serial_port bfin_serial_ports[NR_PORTS];
+struct bfin_serial_res {
+ unsigned long uart_base_addr;
+ int uart_irq;
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ unsigned int uart_tx_dma_channel;
+ unsigned int uart_rx_dma_channel;
+#endif
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ int uart_cts_pin;
+ int uart_rts_pin;
+#endif
+};
+
+struct bfin_serial_res bfin_serial_resource[] = {
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ {
+ 0xFFC00400,
+ IRQ_UART0_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART0_TX,
+ CH_UART0_RX,
+#endif
+#ifdef CONFIG_BFIN_UART0_CTSRTS
+ CONFIG_UART0_CTS_PIN,
+ CONFIG_UART0_RTS_PIN,
+#endif
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART1
+ {
+ 0xFFC02000,
+ IRQ_UART1_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART1_TX,
+ CH_UART1_RX,
+#endif
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART2
+ {
+ 0xFFC02100,
+ IRQ_UART2_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART2_TX,
+ CH_UART2_RX,
+#endif
+#ifdef CONFIG_BFIN_UART2_CTSRTS
+ CONFIG_UART2_CTS_PIN,
+ CONFIG_UART2_RTS_PIN,
+#endif
+ },
+#endif
+#ifdef CONFIG_SERIAL_BFIN_UART3
+ {
+ 0xFFC03100,
+ IRQ_UART3_RX,
+#ifdef CONFIG_SERIAL_BFIN_DMA
+ CH_UART3_TX,
+ CH_UART3_RX,
+#endif
+ },
+#endif
+};
+
+int nr_ports = ARRAY_SIZE(bfin_serial_resource);
+
+static void bfin_serial_hw_init(struct bfin_serial_port *uart)
+{
+#ifdef CONFIG_SERIAL_BFIN_UART0
+ /* Enable UART0 RX and TX on pin 7 & 8 of PORT E */
+ bfin_write_PORTE_FER(0x180 | bfin_read_PORTE_FER());
+ bfin_write_PORTE_MUX(0x3C000 | bfin_read_PORTE_MUX());
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART1
+ /* Enable UART1 RX and TX on pin 0 & 1 of PORT H */
+ bfin_write_PORTH_FER(0x3 | bfin_read_PORTH_FER());
+ bfin_write_PORTH_MUX(~0xF & bfin_read_PORTH_MUX());
+#ifdef CONFIG_BFIN_UART1_CTSRTS
+ /* Enable UART1 RTS and CTS on pin 9 & 10 of PORT E */
+ bfin_write_PORTE_FER(0x600 | bfin_read_PORTE_FER());
+ bfin_write_PORTE_MUX(~0x3C0000 & bfin_read_PORTE_MUX());
+#endif
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART2
+ /* Enable UART2 RX and TX on pin 4 & 5 of PORT B */
+ bfin_write_PORTB_FER(0x30 | bfin_read_PORTB_FER());
+ bfin_write_PORTB_MUX(~0xF00 & bfin_read_PORTB_MUX());
+#endif
+
+#ifdef CONFIG_SERIAL_BFIN_UART3
+ /* Enable UART3 RX and TX on pin 6 & 7 of PORT B */
+ bfin_write_PORTB_FER(0xC0 | bfin_read_PORTB_FER());
+ bfin_write_PORTB_MUX(~0xF000 | bfin_read_PORTB_MUX());
+#ifdef CONFIG_BFIN_UART3_CTSRTS
+ /* Enable UART3 RTS and CTS on pin 2 & 3 of PORT B */
+ bfin_write_PORTB_FER(0xC | bfin_read_PORTB_FER());
+ bfin_write_PORTB_MUX(~0xF0 | bfin_read_PORTB_MUX());
+#endif
+#endif
+ SSYNC();
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+ if (uart->cts_pin >= 0) {
+ gpio_request(uart->cts_pin, NULL);
+ gpio_direction_input(uart->cts_pin);
+ }
+
+ if (uart->rts_pin >= 0) {
+ gpio_request(uart->rts_pin, NULL);
+ gpio_direction_output(uart->rts_pin);
+ }
+#endif
+}
diff --git a/include/asm-blackfin/mach-bf548/blackfin.h b/include/asm-blackfin/mach-bf548/blackfin.h
new file mode 100644
index 000000000000..791218fe7d94
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/blackfin.h
@@ -0,0 +1,168 @@
+/*
+ * File: include/asm-blackfin/mach-bf548/blackfin.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ *
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _MACH_BLACKFIN_H_
+#define _MACH_BLACKFIN_H_
+
+#define BF548_FAMILY
+
+#include "bf548.h"
+#include "mem_map.h"
+#include "anomaly.h"
+
+#ifdef CONFIG_BF542
+#include "defBF542.h"
+#endif
+
+#ifdef CONFIG_BF544
+#include "defBF544.h"
+#endif
+
+#ifdef CONFIG_BF548
+#include "defBF548.h"
+#endif
+
+#ifdef CONFIG_BF549
+#include "defBF549.h"
+#endif
+
+#if !(defined(__ASSEMBLY__) || defined(ASSEMBLY))
+#ifdef CONFIG_BF542
+#include "cdefBF542.h"
+#endif
+
+#ifdef CONFIG_BF544
+#include "cdefBF544.h"
+#endif
+#ifdef CONFIG_BF548
+#include "cdefBF548.h"
+#endif
+#ifdef CONFIG_BF549
+#include "cdefBF549.h"
+#endif
+
+/* UART 1*/
+#define bfin_read_UART_THR() bfin_read_UART1_THR()
+#define bfin_write_UART_THR(val) bfin_write_UART1_THR(val)
+#define bfin_read_UART_RBR() bfin_read_UART1_RBR()
+#define bfin_write_UART_RBR(val) bfin_write_UART1_RBR(val)
+#define bfin_read_UART_DLL() bfin_read_UART1_DLL()
+#define bfin_write_UART_DLL(val) bfin_write_UART1_DLL(val)
+#define bfin_read_UART_IER() bfin_read_UART1_IER()
+#define bfin_write_UART_IER(val) bfin_write_UART1_IER(val)
+#define bfin_read_UART_DLH() bfin_read_UART1_DLH()
+#define bfin_write_UART_DLH(val) bfin_write_UART1_DLH(val)
+#define bfin_read_UART_IIR() bfin_read_UART1_IIR()
+#define bfin_write_UART_IIR(val) bfin_write_UART1_IIR(val)
+#define bfin_read_UART_LCR() bfin_read_UART1_LCR()
+#define bfin_write_UART_LCR(val) bfin_write_UART1_LCR(val)
+#define bfin_read_UART_MCR() bfin_read_UART1_MCR()
+#define bfin_write_UART_MCR(val) bfin_write_UART1_MCR(val)
+#define bfin_read_UART_LSR() bfin_read_UART1_LSR()
+#define bfin_write_UART_LSR(val) bfin_write_UART1_LSR(val)
+#define bfin_read_UART_SCR() bfin_read_UART1_SCR()
+#define bfin_write_UART_SCR(val) bfin_write_UART1_SCR(val)
+#define bfin_read_UART_GCTL() bfin_read_UART1_GCTL()
+#define bfin_write_UART_GCTL(val) bfin_write_UART1_GCTL(val)
+
+#endif
+
+/* MAP used DEFINES from BF533 to BF54x - so we don't need to change
+ * them in the driver, kernel, etc. */
+
+/* UART_IIR Register */
+#define STATUS(x) ((x << 1) & 0x06)
+#define STATUS_P1 0x02
+#define STATUS_P0 0x01
+
+/* UART 0*/
+
+/* DMA Channnel */
+#define bfin_read_CH_UART_RX() bfin_read_CH_UART1_RX()
+#define bfin_write_CH_UART_RX(val) bfin_write_CH_UART1_RX(val)
+#define bfin_read_CH_UART_TX() bfin_read_CH_UART1_TX()
+#define bfin_write_CH_UART_TX(val) bfin_write_CH_UART1_TX(val)
+#define CH_UART_RX CH_UART1_RX
+#define CH_UART_TX CH_UART1_TX
+
+/* System Interrupt Controller */
+#define bfin_read_IRQ_UART_RX() bfin_read_IRQ_UART1_RX()
+#define bfin_write_IRQ_UART_RX(val) bfin_write_IRQ_UART1_RX(val)
+#define bfin_read_IRQ_UART_TX() bfin_read_IRQ_UART1_TX()
+#define bfin_write_IRQ_UART_TX(val) bfin_write_IRQ_UART1_TX(val)
+#define bfin_read_IRQ_UART_ERROR() bfin_read_IRQ_UART1_ERROR()
+#define bfin_write_IRQ_UART_ERROR(val) bfin_write_IRQ_UART1_ERROR(val)
+#define IRQ_UART_RX IRQ_UART1_RX
+#define IRQ_UART_TX IRQ_UART1_TX
+#define IRQ_UART_ERROR IRQ_UART1_ERROR
+
+/* MMR Registers*/
+#define bfin_read_UART_THR() bfin_read_UART1_THR()
+#define bfin_write_UART_THR(val) bfin_write_UART1_THR(val)
+#define bfin_read_UART_RBR() bfin_read_UART1_RBR()
+#define bfin_write_UART_RBR(val) bfin_write_UART1_RBR(val)
+#define bfin_read_UART_DLL() bfin_read_UART1_DLL()
+#define bfin_write_UART_DLL(val) bfin_write_UART1_DLL(val)
+#define bfin_read_UART_IER() bfin_read_UART1_IER()
+#define bfin_write_UART_IER(val) bfin_write_UART1_IER(val)
+#define bfin_read_UART_DLH() bfin_read_UART1_DLH()
+#define bfin_write_UART_DLH(val) bfin_write_UART1_DLH(val)
+#define bfin_read_UART_IIR() bfin_read_UART1_IIR()
+#define bfin_write_UART_IIR(val) bfin_write_UART1_IIR(val)
+#define bfin_read_UART_LCR() bfin_read_UART1_LCR()
+#define bfin_write_UART_LCR(val) bfin_write_UART1_LCR(val)
+#define bfin_read_UART_MCR() bfin_read_UART1_MCR()
+#define bfin_write_UART_MCR(val) bfin_write_UART1_MCR(val)
+#define bfin_read_UART_LSR() bfin_read_UART1_LSR()
+#define bfin_write_UART_LSR(val) bfin_write_UART1_LSR(val)
+#define bfin_read_UART_SCR() bfin_read_UART1_SCR()
+#define bfin_write_UART_SCR(val) bfin_write_UART1_SCR(val)
+#define bfin_read_UART_GCTL() bfin_read_UART1_GCTL()
+#define bfin_write_UART_GCTL(val) bfin_write_UART1_GCTL(val)
+#define UART_THR UART1_THR
+#define UART_RBR UART1_RBR
+#define UART_DLL UART1_DLL
+#define UART_IER UART1_IER
+#define UART_DLH UART1_DLH
+#define UART_IIR UART1_IIR
+#define UART_LCR UART1_LCR
+#define UART_MCR UART1_MCR
+#define UART_LSR UART1_LSR
+#define UART_SCR UART1_SCR
+#define UART_GCTL UART1_GCTL
+
+/* PLL_DIV Masks */
+#define CCLK_DIV1 CSEL_DIV1 /* CCLK = VCO / 1 */
+#define CCLK_DIV2 CSEL_DIV2 /* CCLK = VCO / 2 */
+#define CCLK_DIV4 CSEL_DIV4 /* CCLK = VCO / 4 */
+#define CCLK_DIV8 CSEL_DIV8 /* CCLK = VCO / 8 */
+
+#endif
diff --git a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
index 6bbcefeb3627..98d35a929116 100644
--- a/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
+++ b/include/asm-blackfin/mach-bf548/cdefBF54x_base.h
@@ -31,7 +31,8 @@
#ifndef _CDEF_BF54X_H
#define _CDEF_BF54X_H
-#include <defBF54x_base.h>
+#include "defBF54x_base.h"
+#include <asm/system.h>
/* ************************************************************** */
/* SYSTEM & MMR ADDRESS DEFINITIONS COMMON TO ALL ADSP-BF54x */
@@ -44,7 +45,30 @@
#define bfin_read_PLL_DIV() bfin_read16(PLL_DIV)
#define bfin_write_PLL_DIV(val) bfin_write16(PLL_DIV, val)
#define bfin_read_VR_CTL() bfin_read16(VR_CTL)
-#define bfin_write_VR_CTL(val) bfin_write16(VR_CTL, val)
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+ unsigned long flags, iwr0, iwr1, iwr2;
+
+ /* Enable the PLL Wakeup bit in SIC IWR */
+ iwr0 = bfin_read32(SIC_IWR0);
+ iwr1 = bfin_read32(SIC_IWR1);
+ iwr2 = bfin_read32(SIC_IWR2);
+ /* Only allow PPL Wakeup) */
+ bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+ bfin_write32(SIC_IWR1, 0);
+ bfin_write32(SIC_IWR2, 0);
+
+ bfin_write16(VR_CTL, val);
+ __builtin_bfin_ssync();
+
+ local_irq_save(flags);
+ asm("IDLE;");
+ local_irq_restore(flags);
+ bfin_write32(SIC_IWR0, iwr0);
+ bfin_write32(SIC_IWR1, iwr1);
+ bfin_write32(SIC_IWR2, iwr2);
+}
#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT, val)
#define bfin_read_PLL_LOCKCNT() bfin_read16(PLL_LOCKCNT)
@@ -70,12 +94,18 @@
#define bfin_write_SIC_IMASK1(val) bfin_write32(SIC_IMASK1, val)
#define bfin_read_SIC_IMASK2() bfin_read32(SIC_IMASK2)
#define bfin_write_SIC_IMASK2(val) bfin_write32(SIC_IMASK2, val)
+#define bfin_read_SIC_IMASK(x) bfin_read32(SIC_IMASK0 + (x << 2))
+#define bfin_write_SIC_IMASK(x, val) bfin_write32((SIC_IMASK0 + (x << 2)), val)
+
#define bfin_read_SIC_ISR0() bfin_read32(SIC_ISR0)
#define bfin_write_SIC_ISR0(val) bfin_write32(SIC_ISR0, val)
#define bfin_read_SIC_ISR1() bfin_read32(SIC_ISR1)
#define bfin_write_SIC_ISR1(val) bfin_write32(SIC_ISR1, val)
#define bfin_read_SIC_ISR2() bfin_read32(SIC_ISR2)
#define bfin_write_SIC_ISR2(val) bfin_write32(SIC_ISR2, val)
+#define bfin_read_SIC_ISR(x) bfin_read32(SIC_ISR0 + (x << 2))
+#define bfin_write_SIC_ISR(x, val) bfin_write32((SIC_ISR0 + (x << 2)), val)
+
#define bfin_read_SIC_IWR0() bfin_read32(SIC_IWR0)
#define bfin_write_SIC_IWR0(val) bfin_write32(SIC_IWR0, val)
#define bfin_read_SIC_IWR1() bfin_read32(SIC_IWR1)
@@ -710,21 +740,21 @@
#define bfin_read_MDMA_D0_NEXT_DESC_PTR() bfin_read32(MDMA_D0_NEXT_DESC_PTR)
#define bfin_write_MDMA_D0_NEXT_DESC_PTR(val) bfin_write32(MDMA_D0_NEXT_DESC_PTR)
#define bfin_read_MDMA_D0_START_ADDR() bfin_read32(MDMA_D0_START_ADDR)
-#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write32(MDMA_D0_START_ADDR)
+#define bfin_write_MDMA_D0_START_ADDR(val) bfin_write32(MDMA_D0_START_ADDR, val)
#define bfin_read_MDMA_D0_CONFIG() bfin_read16(MDMA_D0_CONFIG)
#define bfin_write_MDMA_D0_CONFIG(val) bfin_write16(MDMA_D0_CONFIG, val)
#define bfin_read_MDMA_D0_X_COUNT() bfin_read16(MDMA_D0_X_COUNT)
#define bfin_write_MDMA_D0_X_COUNT(val) bfin_write16(MDMA_D0_X_COUNT, val)
#define bfin_read_MDMA_D0_X_MODIFY() bfin_read16(MDMA_D0_X_MODIFY)
-#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write16(MDMA_D0_X_MODIFY)
+#define bfin_write_MDMA_D0_X_MODIFY(val) bfin_write16(MDMA_D0_X_MODIFY, val)
#define bfin_read_MDMA_D0_Y_COUNT() bfin_read16(MDMA_D0_Y_COUNT)
#define bfin_write_MDMA_D0_Y_COUNT(val) bfin_write16(MDMA_D0_Y_COUNT, val)
#define bfin_read_MDMA_D0_Y_MODIFY() bfin_read16(MDMA_D0_Y_MODIFY)
-#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write16(MDMA_D0_Y_MODIFY)
+#define bfin_write_MDMA_D0_Y_MODIFY(val) bfin_write16(MDMA_D0_Y_MODIFY, val)
#define bfin_read_MDMA_D0_CURR_DESC_PTR() bfin_read32(MDMA_D0_CURR_DESC_PTR)
-#define bfin_write_MDMA_D0_CURR_DESC_PTR(val) bfin_write32(MDMA_D0_CURR_DESC_PTR)
+#define bfin_write_MDMA_D0_CURR_DESC_PTR(val) bfin_write32(MDMA_D0_CURR_DESC_PTR, val)
#define bfin_read_MDMA_D0_CURR_ADDR() bfin_read32(MDMA_D0_CURR_ADDR)
-#define bfin_write_MDMA_D0_CURR_ADDR(val) bfin_write32(MDMA_D0_CURR_ADDR)
+#define bfin_write_MDMA_D0_CURR_ADDR(val) bfin_write32(MDMA_D0_CURR_ADDR, val)
#define bfin_read_MDMA_D0_IRQ_STATUS() bfin_read16(MDMA_D0_IRQ_STATUS)
#define bfin_write_MDMA_D0_IRQ_STATUS(val) bfin_write16(MDMA_D0_IRQ_STATUS, val)
#define bfin_read_MDMA_D0_PERIPHERAL_MAP() bfin_read16(MDMA_D0_PERIPHERAL_MAP)
@@ -734,23 +764,23 @@
#define bfin_read_MDMA_D0_CURR_Y_COUNT() bfin_read16(MDMA_D0_CURR_Y_COUNT)
#define bfin_write_MDMA_D0_CURR_Y_COUNT(val) bfin_write16(MDMA_D0_CURR_Y_COUNT, val)
#define bfin_read_MDMA_S0_NEXT_DESC_PTR() bfin_read32(MDMA_S0_NEXT_DESC_PTR)
-#define bfin_write_MDMA_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA_S0_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S0_NEXT_DESC_PTR(val) bfin_write32(MDMA_S0_NEXT_DESC_PTR, val)
#define bfin_read_MDMA_S0_START_ADDR() bfin_read32(MDMA_S0_START_ADDR)
-#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write32(MDMA_S0_START_ADDR)
+#define bfin_write_MDMA_S0_START_ADDR(val) bfin_write32(MDMA_S0_START_ADDR, val)
#define bfin_read_MDMA_S0_CONFIG() bfin_read16(MDMA_S0_CONFIG)
#define bfin_write_MDMA_S0_CONFIG(val) bfin_write16(MDMA_S0_CONFIG, val)
#define bfin_read_MDMA_S0_X_COUNT() bfin_read16(MDMA_S0_X_COUNT)
#define bfin_write_MDMA_S0_X_COUNT(val) bfin_write16(MDMA_S0_X_COUNT, val)
#define bfin_read_MDMA_S0_X_MODIFY() bfin_read16(MDMA_S0_X_MODIFY)
-#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write16(MDMA_S0_X_MODIFY)
+#define bfin_write_MDMA_S0_X_MODIFY(val) bfin_write16(MDMA_S0_X_MODIFY, val)
#define bfin_read_MDMA_S0_Y_COUNT() bfin_read16(MDMA_S0_Y_COUNT)
#define bfin_write_MDMA_S0_Y_COUNT(val) bfin_write16(MDMA_S0_Y_COUNT, val)
#define bfin_read_MDMA_S0_Y_MODIFY() bfin_read16(MDMA_S0_Y_MODIFY)
-#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write16(MDMA_S0_Y_MODIFY)
+#define bfin_write_MDMA_S0_Y_MODIFY(val) bfin_write16(MDMA_S0_Y_MODIFY, val)
#define bfin_read_MDMA_S0_CURR_DESC_PTR() bfin_read32(MDMA_S0_CURR_DESC_PTR)
-#define bfin_write_MDMA_S0_CURR_DESC_PTR(val) bfin_write32(MDMA_S0_CURR_DESC_PTR)
+#define bfin_write_MDMA_S0_CURR_DESC_PTR(val) bfin_write32(MDMA_S0_CURR_DESC_PTR, val)
#define bfin_read_MDMA_S0_CURR_ADDR() bfin_read32(MDMA_S0_CURR_ADDR)
-#define bfin_write_MDMA_S0_CURR_ADDR(val) bfin_write32(MDMA_S0_CURR_ADDR)
+#define bfin_write_MDMA_S0_CURR_ADDR(val) bfin_write32(MDMA_S0_CURR_ADDR, val)
#define bfin_read_MDMA_S0_IRQ_STATUS() bfin_read16(MDMA_S0_IRQ_STATUS)
#define bfin_write_MDMA_S0_IRQ_STATUS(val) bfin_write16(MDMA_S0_IRQ_STATUS, val)
#define bfin_read_MDMA_S0_PERIPHERAL_MAP() bfin_read16(MDMA_S0_PERIPHERAL_MAP)
@@ -763,9 +793,9 @@
/* MDMA Stream 1 Registers */
#define bfin_read_MDMA_D1_NEXT_DESC_PTR() bfin_read32(MDMA_D1_NEXT_DESC_PTR)
-#define bfin_write_MDMA_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA_D1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_D1_NEXT_DESC_PTR(val) bfin_write32(MDMA_D1_NEXT_DESC_PTR, val)
#define bfin_read_MDMA_D1_START_ADDR() bfin_read32(MDMA_D1_START_ADDR)
-#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write32(MDMA_D1_START_ADDR)
+#define bfin_write_MDMA_D1_START_ADDR(val) bfin_write32(MDMA_D1_START_ADDR, val)
#define bfin_read_MDMA_D1_CONFIG() bfin_read16(MDMA_D1_CONFIG)
#define bfin_write_MDMA_D1_CONFIG(val) bfin_write16(MDMA_D1_CONFIG, val)
#define bfin_read_MDMA_D1_X_COUNT() bfin_read16(MDMA_D1_X_COUNT)
@@ -777,9 +807,9 @@
#define bfin_read_MDMA_D1_Y_MODIFY() bfin_read16(MDMA_D1_Y_MODIFY)
#define bfin_write_MDMA_D1_Y_MODIFY(val) bfin_write16(MDMA_D1_Y_MODIFY)
#define bfin_read_MDMA_D1_CURR_DESC_PTR() bfin_read32(MDMA_D1_CURR_DESC_PTR)
-#define bfin_write_MDMA_D1_CURR_DESC_PTR(val) bfin_write32(MDMA_D1_CURR_DESC_PTR)
+#define bfin_write_MDMA_D1_CURR_DESC_PTR(val) bfin_write32(MDMA_D1_CURR_DESC_PTR, val)
#define bfin_read_MDMA_D1_CURR_ADDR() bfin_read32(MDMA_D1_CURR_ADDR)
-#define bfin_write_MDMA_D1_CURR_ADDR(val) bfin_write32(MDMA_D1_CURR_ADDR)
+#define bfin_write_MDMA_D1_CURR_ADDR(val) bfin_write32(MDMA_D1_CURR_ADDR, val)
#define bfin_read_MDMA_D1_IRQ_STATUS() bfin_read16(MDMA_D1_IRQ_STATUS)
#define bfin_write_MDMA_D1_IRQ_STATUS(val) bfin_write16(MDMA_D1_IRQ_STATUS, val)
#define bfin_read_MDMA_D1_PERIPHERAL_MAP() bfin_read16(MDMA_D1_PERIPHERAL_MAP)
@@ -789,9 +819,9 @@
#define bfin_read_MDMA_D1_CURR_Y_COUNT() bfin_read16(MDMA_D1_CURR_Y_COUNT)
#define bfin_write_MDMA_D1_CURR_Y_COUNT(val) bfin_write16(MDMA_D1_CURR_Y_COUNT, val)
#define bfin_read_MDMA_S1_NEXT_DESC_PTR() bfin_read32(MDMA_S1_NEXT_DESC_PTR)
-#define bfin_write_MDMA_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA_S1_NEXT_DESC_PTR)
+#define bfin_write_MDMA_S1_NEXT_DESC_PTR(val) bfin_write32(MDMA_S1_NEXT_DESC_PTR, val)
#define bfin_read_MDMA_S1_START_ADDR() bfin_read32(MDMA_S1_START_ADDR)
-#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write32(MDMA_S1_START_ADDR)
+#define bfin_write_MDMA_S1_START_ADDR(val) bfin_write32(MDMA_S1_START_ADDR, val)
#define bfin_read_MDMA_S1_CONFIG() bfin_read16(MDMA_S1_CONFIG)
#define bfin_write_MDMA_S1_CONFIG(val) bfin_write16(MDMA_S1_CONFIG, val)
#define bfin_read_MDMA_S1_X_COUNT() bfin_read16(MDMA_S1_X_COUNT)
@@ -803,9 +833,9 @@
#define bfin_read_MDMA_S1_Y_MODIFY() bfin_read16(MDMA_S1_Y_MODIFY)
#define bfin_write_MDMA_S1_Y_MODIFY(val) bfin_write16(MDMA_S1_Y_MODIFY)
#define bfin_read_MDMA_S1_CURR_DESC_PTR() bfin_read32(MDMA_S1_CURR_DESC_PTR)
-#define bfin_write_MDMA_S1_CURR_DESC_PTR(val) bfin_write32(MDMA_S1_CURR_DESC_PTR)
+#define bfin_write_MDMA_S1_CURR_DESC_PTR(val) bfin_write32(MDMA_S1_CURR_DESC_PTR, val)
#define bfin_read_MDMA_S1_CURR_ADDR() bfin_read32(MDMA_S1_CURR_ADDR)
-#define bfin_write_MDMA_S1_CURR_ADDR(val) bfin_write32(MDMA_S1_CURR_ADDR)
+#define bfin_write_MDMA_S1_CURR_ADDR(val) bfin_write32(MDMA_S1_CURR_ADDR, val)
#define bfin_read_MDMA_S1_IRQ_STATUS() bfin_read16(MDMA_S1_IRQ_STATUS)
#define bfin_write_MDMA_S1_IRQ_STATUS(val) bfin_write16(MDMA_S1_IRQ_STATUS, val)
#define bfin_read_MDMA_S1_PERIPHERAL_MAP() bfin_read16(MDMA_S1_PERIPHERAL_MAP)
diff --git a/include/asm-blackfin/mach-bf548/defBF542.h b/include/asm-blackfin/mach-bf548/defBF542.h
index ac968fca5cc5..32d07130200c 100644
--- a/include/asm-blackfin/mach-bf548/defBF542.h
+++ b/include/asm-blackfin/mach-bf548/defBF542.h
@@ -362,7 +362,6 @@
/* Bit masks for KPAD_CTL */
#define KPAD_EN 0x1 /* Keypad Enable */
-#define nKPAD_EN 0x0
#define KPAD_IRQMODE 0x6 /* Key Press Interrupt Enable */
#define KPAD_ROWEN 0x1c00 /* Row Enable Width */
#define KPAD_COLEN 0xe000 /* Column Enable Width */
@@ -384,29 +383,21 @@
/* Bit masks for KPAD_STAT */
#define KPAD_IRQ 0x1 /* Keypad Interrupt Status */
-#define nKPAD_IRQ 0x0
#define KPAD_MROWCOL 0x6 /* Multiple Row/Column Keypress Status */
#define KPAD_PRESSED 0x8 /* Key press current status */
-#define nKPAD_PRESSED 0x0
/* Bit masks for KPAD_SOFTEVAL */
#define KPAD_SOFTEVAL_E 0x2 /* Software Programmable Force Evaluate */
-#define nKPAD_SOFTEVAL_E 0x0
/* Bit masks for SDH_COMMAND */
#define CMD_IDX 0x3f /* Command Index */
#define CMD_RSP 0x40 /* Response */
-#define nCMD_RSP 0x0
#define CMD_L_RSP 0x80 /* Long Response */
-#define nCMD_L_RSP 0x0
#define CMD_INT_E 0x100 /* Command Interrupt */
-#define nCMD_INT_E 0x0
#define CMD_PEND_E 0x200 /* Command Pending */
-#define nCMD_PEND_E 0x0
#define CMD_E 0x400 /* Command Enable */
-#define nCMD_E 0x0
/* Bit masks for SDH_PWR_CTL */
@@ -415,21 +406,15 @@
#define TBD 0x3c /* TBD */
#endif
#define SD_CMD_OD 0x40 /* Open Drain Output */
-#define nSD_CMD_OD 0x0
#define ROD_CTL 0x80 /* Rod Control */
-#define nROD_CTL 0x0
/* Bit masks for SDH_CLK_CTL */
#define CLKDIV 0xff /* MC_CLK Divisor */
#define CLK_E 0x100 /* MC_CLK Bus Clock Enable */
-#define nCLK_E 0x0
#define PWR_SV_E 0x200 /* Power Save Enable */
-#define nPWR_SV_E 0x0
#define CLKDIV_BYPASS 0x400 /* Bypass Divisor */
-#define nCLKDIV_BYPASS 0x0
#define WIDE_BUS 0x800 /* Wide Bus Mode Enable */
-#define nWIDE_BUS 0x0
/* Bit masks for SDH_RESP_CMD */
@@ -438,133 +423,74 @@
/* Bit masks for SDH_DATA_CTL */
#define DTX_E 0x1 /* Data Transfer Enable */
-#define nDTX_E 0x0
#define DTX_DIR 0x2 /* Data Transfer Direction */
-#define nDTX_DIR 0x0
#define DTX_MODE 0x4 /* Data Transfer Mode */
-#define nDTX_MODE 0x0
#define DTX_DMA_E 0x8 /* Data Transfer DMA Enable */
-#define nDTX_DMA_E 0x0
#define DTX_BLK_LGTH 0xf0 /* Data Transfer Block Length */
/* Bit masks for SDH_STATUS */
#define CMD_CRC_FAIL 0x1 /* CMD CRC Fail */
-#define nCMD_CRC_FAIL 0x0
#define DAT_CRC_FAIL 0x2 /* Data CRC Fail */
-#define nDAT_CRC_FAIL 0x0
#define CMD_TIMEOUT 0x4 /* CMD Time Out */
-#define nCMD_TIMEOUT 0x0
#define DAT_TIMEOUT 0x8 /* Data Time Out */
-#define nDAT_TIMEOUT 0x0
#define TX_UNDERRUN 0x10 /* Transmit Underrun */
-#define nTX_UNDERRUN 0x0
#define RX_OVERRUN 0x20 /* Receive Overrun */
-#define nRX_OVERRUN 0x0
#define CMD_RESP_END 0x40 /* CMD Response End */
-#define nCMD_RESP_END 0x0
#define CMD_SENT 0x80 /* CMD Sent */
-#define nCMD_SENT 0x0
#define DAT_END 0x100 /* Data End */
-#define nDAT_END 0x0
#define START_BIT_ERR 0x200 /* Start Bit Error */
-#define nSTART_BIT_ERR 0x0
#define DAT_BLK_END 0x400 /* Data Block End */
-#define nDAT_BLK_END 0x0
#define CMD_ACT 0x800 /* CMD Active */
-#define nCMD_ACT 0x0
#define TX_ACT 0x1000 /* Transmit Active */
-#define nTX_ACT 0x0
#define RX_ACT 0x2000 /* Receive Active */
-#define nRX_ACT 0x0
#define TX_FIFO_STAT 0x4000 /* Transmit FIFO Status */
-#define nTX_FIFO_STAT 0x0
#define RX_FIFO_STAT 0x8000 /* Receive FIFO Status */
-#define nRX_FIFO_STAT 0x0
#define TX_FIFO_FULL 0x10000 /* Transmit FIFO Full */
-#define nTX_FIFO_FULL 0x0
#define RX_FIFO_FULL 0x20000 /* Receive FIFO Full */
-#define nRX_FIFO_FULL 0x0
#define TX_FIFO_ZERO 0x40000 /* Transmit FIFO Empty */
-#define nTX_FIFO_ZERO 0x0
#define RX_DAT_ZERO 0x80000 /* Receive FIFO Empty */
-#define nRX_DAT_ZERO 0x0
#define TX_DAT_RDY 0x100000 /* Transmit Data Available */
-#define nTX_DAT_RDY 0x0
#define RX_FIFO_RDY 0x200000 /* Receive Data Available */
-#define nRX_FIFO_RDY 0x0
/* Bit masks for SDH_STATUS_CLR */
#define CMD_CRC_FAIL_STAT 0x1 /* CMD CRC Fail Status */
-#define nCMD_CRC_FAIL_STAT 0x0
#define DAT_CRC_FAIL_STAT 0x2 /* Data CRC Fail Status */
-#define nDAT_CRC_FAIL_STAT 0x0
#define CMD_TIMEOUT_STAT 0x4 /* CMD Time Out Status */
-#define nCMD_TIMEOUT_STAT 0x0
#define DAT_TIMEOUT_STAT 0x8 /* Data Time Out status */
-#define nDAT_TIMEOUT_STAT 0x0
#define TX_UNDERRUN_STAT 0x10 /* Transmit Underrun Status */
-#define nTX_UNDERRUN_STAT 0x0
#define RX_OVERRUN_STAT 0x20 /* Receive Overrun Status */
-#define nRX_OVERRUN_STAT 0x0
#define CMD_RESP_END_STAT 0x40 /* CMD Response End Status */
-#define nCMD_RESP_END_STAT 0x0
#define CMD_SENT_STAT 0x80 /* CMD Sent Status */
-#define nCMD_SENT_STAT 0x0
#define DAT_END_STAT 0x100 /* Data End Status */
-#define nDAT_END_STAT 0x0
#define START_BIT_ERR_STAT 0x200 /* Start Bit Error Status */
-#define nSTART_BIT_ERR_STAT 0x0
#define DAT_BLK_END_STAT 0x400 /* Data Block End Status */
-#define nDAT_BLK_END_STAT 0x0
/* Bit masks for SDH_MASK0 */
#define CMD_CRC_FAIL_MASK 0x1 /* CMD CRC Fail Mask */
-#define nCMD_CRC_FAIL_MASK 0x0
#define DAT_CRC_FAIL_MASK 0x2 /* Data CRC Fail Mask */
-#define nDAT_CRC_FAIL_MASK 0x0
#define CMD_TIMEOUT_MASK 0x4 /* CMD Time Out Mask */
-#define nCMD_TIMEOUT_MASK 0x0
#define DAT_TIMEOUT_MASK 0x8 /* Data Time Out Mask */
-#define nDAT_TIMEOUT_MASK 0x0
#define TX_UNDERRUN_MASK 0x10 /* Transmit Underrun Mask */
-#define nTX_UNDERRUN_MASK 0x0
#define RX_OVERRUN_MASK 0x20 /* Receive Overrun Mask */
-#define nRX_OVERRUN_MASK 0x0
#define CMD_RESP_END_MASK 0x40 /* CMD Response End Mask */
-#define nCMD_RESP_END_MASK 0x0
#define CMD_SENT_MASK 0x80 /* CMD Sent Mask */
-#define nCMD_SENT_MASK 0x0
#define DAT_END_MASK 0x100 /* Data End Mask */
-#define nDAT_END_MASK 0x0
#define START_BIT_ERR_MASK 0x200 /* Start Bit Error Mask */
-#define nSTART_BIT_ERR_MASK 0x0
#define DAT_BLK_END_MASK 0x400 /* Data Block End Mask */
-#define nDAT_BLK_END_MASK 0x0
#define CMD_ACT_MASK 0x800 /* CMD Active Mask */
-#define nCMD_ACT_MASK 0x0
#define TX_ACT_MASK 0x1000 /* Transmit Active Mask */
-#define nTX_ACT_MASK 0x0
#define RX_ACT_MASK 0x2000 /* Receive Active Mask */
-#define nRX_ACT_MASK 0x0
#define TX_FIFO_STAT_MASK 0x4000 /* Transmit FIFO Status Mask */
-#define nTX_FIFO_STAT_MASK 0x0
#define RX_FIFO_STAT_MASK 0x8000 /* Receive FIFO Status Mask */
-#define nRX_FIFO_STAT_MASK 0x0
#define TX_FIFO_FULL_MASK 0x10000 /* Transmit FIFO Full Mask */
-#define nTX_FIFO_FULL_MASK 0x0
#define RX_FIFO_FULL_MASK 0x20000 /* Receive FIFO Full Mask */
-#define nRX_FIFO_FULL_MASK 0x0
#define TX_FIFO_ZERO_MASK 0x40000 /* Transmit FIFO Empty Mask */
-#define nTX_FIFO_ZERO_MASK 0x0
#define RX_DAT_ZERO_MASK 0x80000 /* Receive FIFO Empty Mask */
-#define nRX_DAT_ZERO_MASK 0x0
#define TX_DAT_RDY_MASK 0x100000 /* Transmit Data Available Mask */
-#define nTX_DAT_RDY_MASK 0x0
#define RX_FIFO_RDY_MASK 0x200000 /* Receive Data Available Mask */
-#define nRX_FIFO_RDY_MASK 0x0
/* Bit masks for SDH_FIFO_CNT */
@@ -573,73 +499,47 @@
/* Bit masks for SDH_E_STATUS */
#define SDIO_INT_DET 0x2 /* SDIO Int Detected */
-#define nSDIO_INT_DET 0x0
#define SD_CARD_DET 0x10 /* SD Card Detect */
-#define nSD_CARD_DET 0x0
/* Bit masks for SDH_E_MASK */
#define SDIO_MSK 0x2 /* Mask SDIO Int Detected */
-#define nSDIO_MSK 0x0
#define SCD_MSK 0x40 /* Mask Card Detect */
-#define nSCD_MSK 0x0
/* Bit masks for SDH_CFG */
#define CLKS_EN 0x1 /* Clocks Enable */
-#define nCLKS_EN 0x0
#define SD4E 0x4 /* SDIO 4-Bit Enable */
-#define nSD4E 0x0
#define MWE 0x8 /* Moving Window Enable */
-#define nMWE 0x0
#define SD_RST 0x10 /* SDMMC Reset */
-#define nSD_RST 0x0
#define PUP_SDDAT 0x20 /* Pull-up SD_DAT */
-#define nPUP_SDDAT 0x0
#define PUP_SDDAT3 0x40 /* Pull-up SD_DAT3 */
-#define nPUP_SDDAT3 0x0
#define PD_SDDAT3 0x80 /* Pull-down SD_DAT3 */
-#define nPD_SDDAT3 0x0
/* Bit masks for SDH_RD_WAIT_EN */
#define RWR 0x1 /* Read Wait Request */
-#define nRWR 0x0
/* Bit masks for ATAPI_CONTROL */
#define PIO_START 0x1 /* Start PIO/Reg Op */
-#define nPIO_START 0x0
#define MULTI_START 0x2 /* Start Multi-DMA Op */
-#define nMULTI_START 0x0
#define ULTRA_START 0x4 /* Start Ultra-DMA Op */
-#define nULTRA_START 0x0
#define XFER_DIR 0x8 /* Transfer Direction */
-#define nXFER_DIR 0x0
#define IORDY_EN 0x10 /* IORDY Enable */
-#define nIORDY_EN 0x0
#define FIFO_FLUSH 0x20 /* Flush FIFOs */
-#define nFIFO_FLUSH 0x0
#define SOFT_RST 0x40 /* Soft Reset */
-#define nSOFT_RST 0x0
#define DEV_RST 0x80 /* Device Reset */
-#define nDEV_RST 0x0
#define TFRCNT_RST 0x100 /* Trans Count Reset */
-#define nTFRCNT_RST 0x0
#define END_ON_TERM 0x200 /* End/Terminate Select */
-#define nEND_ON_TERM 0x0
#define PIO_USE_DMA 0x400 /* PIO-DMA Enable */
-#define nPIO_USE_DMA 0x0
#define UDMAIN_FIFO_THRS 0xf000 /* Ultra DMA-IN FIFO Threshold */
/* Bit masks for ATAPI_STATUS */
#define PIO_XFER_ON 0x1 /* PIO transfer in progress */
-#define nPIO_XFER_ON 0x0
#define MULTI_XFER_ON 0x2 /* Multi-word DMA transfer in progress */
-#define nMULTI_XFER_ON 0x0
#define ULTRA_XFER_ON 0x4 /* Ultra DMA transfer in progress */
-#define nULTRA_XFER_ON 0x0
#define ULTRA_IN_FL 0xf0 /* Ultra DMA Input FIFO Level */
/* Bit masks for ATAPI_DEV_ADDR */
@@ -649,66 +549,39 @@
/* Bit masks for ATAPI_INT_MASK */
#define ATAPI_DEV_INT_MASK 0x1 /* Device interrupt mask */
-#define nATAPI_DEV_INT_MASK 0x0
#define PIO_DONE_MASK 0x2 /* PIO transfer done interrupt mask */
-#define nPIO_DONE_MASK 0x0
#define MULTI_DONE_MASK 0x4 /* Multi-DMA transfer done interrupt mask */
-#define nMULTI_DONE_MASK 0x0
#define UDMAIN_DONE_MASK 0x8 /* Ultra-DMA in transfer done interrupt mask */
-#define nUDMAIN_DONE_MASK 0x0
#define UDMAOUT_DONE_MASK 0x10 /* Ultra-DMA out transfer done interrupt mask */
-#define nUDMAOUT_DONE_MASK 0x0
#define HOST_TERM_XFER_MASK 0x20 /* Host terminate current transfer interrupt mask */
-#define nHOST_TERM_XFER_MASK 0x0
#define MULTI_TERM_MASK 0x40 /* Device terminate Multi-DMA transfer interrupt mask */
-#define nMULTI_TERM_MASK 0x0
#define UDMAIN_TERM_MASK 0x80 /* Device terminate Ultra-DMA-in transfer interrupt mask */
-#define nUDMAIN_TERM_MASK 0x0
#define UDMAOUT_TERM_MASK 0x100 /* Device terminate Ultra-DMA-out transfer interrupt mask */
-#define nUDMAOUT_TERM_MASK 0x0
/* Bit masks for ATAPI_INT_STATUS */
#define ATAPI_DEV_INT 0x1 /* Device interrupt status */
-#define nATAPI_DEV_INT 0x0
#define PIO_DONE_INT 0x2 /* PIO transfer done interrupt status */
-#define nPIO_DONE_INT 0x0
#define MULTI_DONE_INT 0x4 /* Multi-DMA transfer done interrupt status */
-#define nMULTI_DONE_INT 0x0
#define UDMAIN_DONE_INT 0x8 /* Ultra-DMA in transfer done interrupt status */
-#define nUDMAIN_DONE_INT 0x0
#define UDMAOUT_DONE_INT 0x10 /* Ultra-DMA out transfer done interrupt status */
-#define nUDMAOUT_DONE_INT 0x0
#define HOST_TERM_XFER_INT 0x20 /* Host terminate current transfer interrupt status */
-#define nHOST_TERM_XFER_INT 0x0
#define MULTI_TERM_INT 0x40 /* Device terminate Multi-DMA transfer interrupt status */
-#define nMULTI_TERM_INT 0x0
#define UDMAIN_TERM_INT 0x80 /* Device terminate Ultra-DMA-in transfer interrupt status */
-#define nUDMAIN_TERM_INT 0x0
#define UDMAOUT_TERM_INT 0x100 /* Device terminate Ultra-DMA-out transfer interrupt status */
-#define nUDMAOUT_TERM_INT 0x0
/* Bit masks for ATAPI_LINE_STATUS */
#define ATAPI_INTR 0x1 /* Device interrupt to host line status */
-#define nATAPI_INTR 0x0
#define ATAPI_DASP 0x2 /* Device dasp to host line status */
-#define nATAPI_DASP 0x0
#define ATAPI_CS0N 0x4 /* ATAPI chip select 0 line status */
-#define nATAPI_CS0N 0x0
#define ATAPI_CS1N 0x8 /* ATAPI chip select 1 line status */
-#define nATAPI_CS1N 0x0
#define ATAPI_ADDR 0x70 /* ATAPI address line status */
#define ATAPI_DMAREQ 0x80 /* ATAPI DMA request line status */
-#define nATAPI_DMAREQ 0x0
#define ATAPI_DMAACKN 0x100 /* ATAPI DMA acknowledge line status */
-#define nATAPI_DMAACKN 0x0
#define ATAPI_DIOWN 0x200 /* ATAPI write line status */
-#define nATAPI_DIOWN 0x0
#define ATAPI_DIORN 0x400 /* ATAPI read line status */
-#define nATAPI_DIORN 0x0
#define ATAPI_IORDY 0x800 /* ATAPI IORDY line status */
-#define nATAPI_IORDY 0x0
/* Bit masks for ATAPI_SM_STATE */
@@ -720,7 +593,6 @@
/* Bit masks for ATAPI_TERMINATE */
#define ATAPI_HOST_TERM 0x1 /* Host terminationation */
-#define nATAPI_HOST_TERM 0x0
/* Bit masks for ATAPI_REG_TIM_0 */
@@ -779,131 +651,77 @@
/* Bit masks for USB_POWER */
#define ENABLE_SUSPENDM 0x1 /* enable SuspendM output */
-#define nENABLE_SUSPENDM 0x0
#define SUSPEND_MODE 0x2 /* Suspend Mode indicator */
-#define nSUSPEND_MODE 0x0
#define RESUME_MODE 0x4 /* DMA Mode */
-#define nRESUME_MODE 0x0
#define RESET 0x8 /* Reset indicator */
-#define nRESET 0x0
#define HS_MODE 0x10 /* High Speed mode indicator */
-#define nHS_MODE 0x0
#define HS_ENABLE 0x20 /* high Speed Enable */
-#define nHS_ENABLE 0x0
#define SOFT_CONN 0x40 /* Soft connect */
-#define nSOFT_CONN 0x0
#define ISO_UPDATE 0x80 /* Isochronous update */
-#define nISO_UPDATE 0x0
/* Bit masks for USB_INTRTX */
#define EP0_TX 0x1 /* Tx Endpoint 0 interrupt */
-#define nEP0_TX 0x0
#define EP1_TX 0x2 /* Tx Endpoint 1 interrupt */
-#define nEP1_TX 0x0
#define EP2_TX 0x4 /* Tx Endpoint 2 interrupt */
-#define nEP2_TX 0x0
#define EP3_TX 0x8 /* Tx Endpoint 3 interrupt */
-#define nEP3_TX 0x0
#define EP4_TX 0x10 /* Tx Endpoint 4 interrupt */
-#define nEP4_TX 0x0
#define EP5_TX 0x20 /* Tx Endpoint 5 interrupt */
-#define nEP5_TX 0x0
#define EP6_TX 0x40 /* Tx Endpoint 6 interrupt */
-#define nEP6_TX 0x0
#define EP7_TX 0x80 /* Tx Endpoint 7 interrupt */
-#define nEP7_TX 0x0
/* Bit masks for USB_INTRRX */
#define EP1_RX 0x2 /* Rx Endpoint 1 interrupt */
-#define nEP1_RX 0x0
#define EP2_RX 0x4 /* Rx Endpoint 2 interrupt */
-#define nEP2_RX 0x0
#define EP3_RX 0x8 /* Rx Endpoint 3 interrupt */
-#define nEP3_RX 0x0
#define EP4_RX 0x10 /* Rx Endpoint 4 interrupt */
-#define nEP4_RX 0x0
#define EP5_RX 0x20 /* Rx Endpoint 5 interrupt */
-#define nEP5_RX 0x0
#define EP6_RX 0x40 /* Rx Endpoint 6 interrupt */
-#define nEP6_RX 0x0
#define EP7_RX 0x80 /* Rx Endpoint 7 interrupt */
-#define nEP7_RX 0x0
/* Bit masks for USB_INTRTXE */
#define EP0_TX_E 0x1 /* Endpoint 0 interrupt Enable */
-#define nEP0_TX_E 0x0
#define EP1_TX_E 0x2 /* Tx Endpoint 1 interrupt Enable */
-#define nEP1_TX_E 0x0
#define EP2_TX_E 0x4 /* Tx Endpoint 2 interrupt Enable */
-#define nEP2_TX_E 0x0
#define EP3_TX_E 0x8 /* Tx Endpoint 3 interrupt Enable */
-#define nEP3_TX_E 0x0
#define EP4_TX_E 0x10 /* Tx Endpoint 4 interrupt Enable */
-#define nEP4_TX_E 0x0
#define EP5_TX_E 0x20 /* Tx Endpoint 5 interrupt Enable */
-#define nEP5_TX_E 0x0
#define EP6_TX_E 0x40 /* Tx Endpoint 6 interrupt Enable */
-#define nEP6_TX_E 0x0
#define EP7_TX_E 0x80 /* Tx Endpoint 7 interrupt Enable */
-#define nEP7_TX_E 0x0
/* Bit masks for USB_INTRRXE */
#define EP1_RX_E 0x2 /* Rx Endpoint 1 interrupt Enable */
-#define nEP1_RX_E 0x0
#define EP2_RX_E 0x4 /* Rx Endpoint 2 interrupt Enable */
-#define nEP2_RX_E 0x0
#define EP3_RX_E 0x8 /* Rx Endpoint 3 interrupt Enable */
-#define nEP3_RX_E 0x0
#define EP4_RX_E 0x10 /* Rx Endpoint 4 interrupt Enable */
-#define nEP4_RX_E 0x0
#define EP5_RX_E 0x20 /* Rx Endpoint 5 interrupt Enable */
-#define nEP5_RX_E 0x0
#define EP6_RX_E 0x40 /* Rx Endpoint 6 interrupt Enable */
-#define nEP6_RX_E 0x0
#define EP7_RX_E 0x80 /* Rx Endpoint 7 interrupt Enable */
-#define nEP7_RX_E 0x0
/* Bit masks for USB_INTRUSB */
#define SUSPEND_B 0x1 /* Suspend indicator */
-#define nSUSPEND_B 0x0
#define RESUME_B 0x2 /* Resume indicator */
-#define nRESUME_B 0x0
#define RESET_OR_BABLE_B 0x4 /* Reset/babble indicator */
-#define nRESET_OR_BABLE_B 0x0
#define SOF_B 0x8 /* Start of frame */
-#define nSOF_B 0x0
#define CONN_B 0x10 /* Connection indicator */
-#define nCONN_B 0x0
#define DISCON_B 0x20 /* Disconnect indicator */
-#define nDISCON_B 0x0
#define SESSION_REQ_B 0x40 /* Session Request */
-#define nSESSION_REQ_B 0x0
#define VBUS_ERROR_B 0x80 /* Vbus threshold indicator */
-#define nVBUS_ERROR_B 0x0
/* Bit masks for USB_INTRUSBE */
#define SUSPEND_BE 0x1 /* Suspend indicator int enable */
-#define nSUSPEND_BE 0x0
#define RESUME_BE 0x2 /* Resume indicator int enable */
-#define nRESUME_BE 0x0
#define RESET_OR_BABLE_BE 0x4 /* Reset/babble indicator int enable */
-#define nRESET_OR_BABLE_BE 0x0
#define SOF_BE 0x8 /* Start of frame int enable */
-#define nSOF_BE 0x0
#define CONN_BE 0x10 /* Connection indicator int enable */
-#define nCONN_BE 0x0
#define DISCON_BE 0x20 /* Disconnect indicator int enable */
-#define nDISCON_BE 0x0
#define SESSION_REQ_BE 0x40 /* Session Request int enable */
-#define nSESSION_REQ_BE 0x0
#define VBUS_ERROR_BE 0x80 /* Vbus threshold indicator int enable */
-#define nVBUS_ERROR_BE 0x0
/* Bit masks for USB_FRAME */
@@ -916,117 +734,67 @@
/* Bit masks for USB_GLOBAL_CTL */
#define GLOBAL_ENA 0x1 /* enables USB module */
-#define nGLOBAL_ENA 0x0
#define EP1_TX_ENA 0x2 /* Transmit endpoint 1 enable */
-#define nEP1_TX_ENA 0x0
#define EP2_TX_ENA 0x4 /* Transmit endpoint 2 enable */
-#define nEP2_TX_ENA 0x0
#define EP3_TX_ENA 0x8 /* Transmit endpoint 3 enable */
-#define nEP3_TX_ENA 0x0
#define EP4_TX_ENA 0x10 /* Transmit endpoint 4 enable */
-#define nEP4_TX_ENA 0x0
#define EP5_TX_ENA 0x20 /* Transmit endpoint 5 enable */
-#define nEP5_TX_ENA 0x0
#define EP6_TX_ENA 0x40 /* Transmit endpoint 6 enable */
-#define nEP6_TX_ENA 0x0
#define EP7_TX_ENA 0x80 /* Transmit endpoint 7 enable */
-#define nEP7_TX_ENA 0x0
#define EP1_RX_ENA 0x100 /* Receive endpoint 1 enable */
-#define nEP1_RX_ENA 0x0
#define EP2_RX_ENA 0x200 /* Receive endpoint 2 enable */
-#define nEP2_RX_ENA 0x0
#define EP3_RX_ENA 0x400 /* Receive endpoint 3 enable */
-#define nEP3_RX_ENA 0x0
#define EP4_RX_ENA 0x800 /* Receive endpoint 4 enable */
-#define nEP4_RX_ENA 0x0
#define EP5_RX_ENA 0x1000 /* Receive endpoint 5 enable */
-#define nEP5_RX_ENA 0x0
#define EP6_RX_ENA 0x2000 /* Receive endpoint 6 enable */
-#define nEP6_RX_ENA 0x0
#define EP7_RX_ENA 0x4000 /* Receive endpoint 7 enable */
-#define nEP7_RX_ENA 0x0
/* Bit masks for USB_OTG_DEV_CTL */
#define SESSION 0x1 /* session indicator */
-#define nSESSION 0x0
#define HOST_REQ 0x2 /* Host negotiation request */
-#define nHOST_REQ 0x0
#define HOST_MODE 0x4 /* indicates USBDRC is a host */
-#define nHOST_MODE 0x0
#define VBUS0 0x8 /* Vbus level indicator[0] */
-#define nVBUS0 0x0
#define VBUS1 0x10 /* Vbus level indicator[1] */
-#define nVBUS1 0x0
#define LSDEV 0x20 /* Low-speed indicator */
-#define nLSDEV 0x0
#define FSDEV 0x40 /* Full or High-speed indicator */
-#define nFSDEV 0x0
#define B_DEVICE 0x80 /* A' or 'B' device indicator */
-#define nB_DEVICE 0x0
/* Bit masks for USB_OTG_VBUS_IRQ */
#define DRIVE_VBUS_ON 0x1 /* indicator to drive VBUS control circuit */
-#define nDRIVE_VBUS_ON 0x0
#define DRIVE_VBUS_OFF 0x2 /* indicator to shut off charge pump */
-#define nDRIVE_VBUS_OFF 0x0
#define CHRG_VBUS_START 0x4 /* indicator for external circuit to start charging VBUS */
-#define nCHRG_VBUS_START 0x0
#define CHRG_VBUS_END 0x8 /* indicator for external circuit to end charging VBUS */
-#define nCHRG_VBUS_END 0x0
#define DISCHRG_VBUS_START 0x10 /* indicator to start discharging VBUS */
-#define nDISCHRG_VBUS_START 0x0
#define DISCHRG_VBUS_END 0x20 /* indicator to stop discharging VBUS */
-#define nDISCHRG_VBUS_END 0x0
/* Bit masks for USB_OTG_VBUS_MASK */
#define DRIVE_VBUS_ON_ENA 0x1 /* enable DRIVE_VBUS_ON interrupt */
-#define nDRIVE_VBUS_ON_ENA 0x0
#define DRIVE_VBUS_OFF_ENA 0x2 /* enable DRIVE_VBUS_OFF interrupt */
-#define nDRIVE_VBUS_OFF_ENA 0x0
#define CHRG_VBUS_START_ENA 0x4 /* enable CHRG_VBUS_START interrupt */
-#define nCHRG_VBUS_START_ENA 0x0
#define CHRG_VBUS_END_ENA 0x8 /* enable CHRG_VBUS_END interrupt */
-#define nCHRG_VBUS_END_ENA 0x0
#define DISCHRG_VBUS_START_ENA 0x10 /* enable DISCHRG_VBUS_START interrupt */
-#define nDISCHRG_VBUS_START_ENA 0x0
#define DISCHRG_VBUS_END_ENA 0x20 /* enable DISCHRG_VBUS_END interrupt */
-#define nDISCHRG_VBUS_END_ENA 0x0
/* Bit masks for USB_CSR0 */
#define RXPKTRDY 0x1 /* data packet receive indicator */
-#define nRXPKTRDY 0x0
#define TXPKTRDY 0x2 /* data packet in FIFO indicator */
-#define nTXPKTRDY 0x0
#define STALL_SENT 0x4 /* STALL handshake sent */
-#define nSTALL_SENT 0x0
#define DATAEND 0x8 /* Data end indicator */
-#define nDATAEND 0x0
#define SETUPEND 0x10 /* Setup end */
-#define nSETUPEND 0x0
#define SENDSTALL 0x20 /* Send STALL handshake */
-#define nSENDSTALL 0x0
#define SERVICED_RXPKTRDY 0x40 /* used to clear the RxPktRdy bit */
-#define nSERVICED_RXPKTRDY 0x0
#define SERVICED_SETUPEND 0x80 /* used to clear the SetupEnd bit */
-#define nSERVICED_SETUPEND 0x0
#define FLUSHFIFO 0x100 /* flush endpoint FIFO */
-#define nFLUSHFIFO 0x0
#define STALL_RECEIVED_H 0x4 /* STALL handshake received host mode */
-#define nSTALL_RECEIVED_H 0x0
#define SETUPPKT_H 0x8 /* send Setup token host mode */
-#define nSETUPPKT_H 0x0
#define ERROR_H 0x10 /* timeout error indicator host mode */
-#define nERROR_H 0x0
#define REQPKT_H 0x20 /* Request an IN transaction host mode */
-#define nREQPKT_H 0x0
#define STATUSPKT_H 0x40 /* Status stage transaction host mode */
-#define nSTATUSPKT_H 0x0
#define NAK_TIMEOUT_H 0x80 /* EP0 halted after a NAK host mode */
-#define nNAK_TIMEOUT_H 0x0
/* Bit masks for USB_COUNT0 */
@@ -1047,37 +815,21 @@
/* Bit masks for USB_TXCSR */
#define TXPKTRDY_T 0x1 /* data packet in FIFO indicator */
-#define nTXPKTRDY_T 0x0
#define FIFO_NOT_EMPTY_T 0x2 /* FIFO not empty */
-#define nFIFO_NOT_EMPTY_T 0x0
#define UNDERRUN_T 0x4 /* TxPktRdy not set for an IN token */
-#define nUNDERRUN_T 0x0
#define FLUSHFIFO_T 0x8 /* flush endpoint FIFO */
-#define nFLUSHFIFO_T 0x0
#define STALL_SEND_T 0x10 /* issue a Stall handshake */
-#define nSTALL_SEND_T 0x0
#define STALL_SENT_T 0x20 /* Stall handshake transmitted */
-#define nSTALL_SENT_T 0x0
#define CLEAR_DATATOGGLE_T 0x40 /* clear endpoint data toggle */
-#define nCLEAR_DATATOGGLE_T 0x0
#define INCOMPTX_T 0x80 /* indicates that a large packet is split */
-#define nINCOMPTX_T 0x0
#define DMAREQMODE_T 0x400 /* DMA mode (0 or 1) selection */
-#define nDMAREQMODE_T 0x0
#define FORCE_DATATOGGLE_T 0x800 /* Force data toggle */
-#define nFORCE_DATATOGGLE_T 0x0
#define DMAREQ_ENA_T 0x1000 /* Enable DMA request for Tx EP */
-#define nDMAREQ_ENA_T 0x0
#define ISO_T 0x4000 /* enable Isochronous transfers */
-#define nISO_T 0x0
#define AUTOSET_T 0x8000 /* allows TxPktRdy to be set automatically */
-#define nAUTOSET_T 0x0
#define ERROR_TH 0x4 /* error condition host mode */
-#define nERROR_TH 0x0
#define STALL_RECEIVED_TH 0x20 /* Stall handshake received host mode */
-#define nSTALL_RECEIVED_TH 0x0
#define NAK_TIMEOUT_TH 0x80 /* NAK timeout host mode */
-#define nNAK_TIMEOUT_TH 0x0
/* Bit masks for USB_TXCOUNT */
@@ -1086,45 +838,25 @@
/* Bit masks for USB_RXCSR */
#define RXPKTRDY_R 0x1 /* data packet in FIFO indicator */
-#define nRXPKTRDY_R 0x0
#define FIFO_FULL_R 0x2 /* FIFO not empty */
-#define nFIFO_FULL_R 0x0
#define OVERRUN_R 0x4 /* TxPktRdy not set for an IN token */
-#define nOVERRUN_R 0x0
#define DATAERROR_R 0x8 /* Out packet cannot be loaded into Rx FIFO */
-#define nDATAERROR_R 0x0
#define FLUSHFIFO_R 0x10 /* flush endpoint FIFO */
-#define nFLUSHFIFO_R 0x0
#define STALL_SEND_R 0x20 /* issue a Stall handshake */
-#define nSTALL_SEND_R 0x0
#define STALL_SENT_R 0x40 /* Stall handshake transmitted */
-#define nSTALL_SENT_R 0x0
#define CLEAR_DATATOGGLE_R 0x80 /* clear endpoint data toggle */
-#define nCLEAR_DATATOGGLE_R 0x0
#define INCOMPRX_R 0x100 /* indicates that a large packet is split */
-#define nINCOMPRX_R 0x0
#define DMAREQMODE_R 0x800 /* DMA mode (0 or 1) selection */
-#define nDMAREQMODE_R 0x0
#define DISNYET_R 0x1000 /* disable Nyet handshakes */
-#define nDISNYET_R 0x0
#define DMAREQ_ENA_R 0x2000 /* Enable DMA request for Tx EP */
-#define nDMAREQ_ENA_R 0x0
#define ISO_R 0x4000 /* enable Isochronous transfers */
-#define nISO_R 0x0
#define AUTOCLEAR_R 0x8000 /* allows TxPktRdy to be set automatically */
-#define nAUTOCLEAR_R 0x0
#define ERROR_RH 0x4 /* TxPktRdy not set for an IN token host mode */
-#define nERROR_RH 0x0
#define REQPKT_RH 0x20 /* request an IN transaction host mode */
-#define nREQPKT_RH 0x0
#define STALL_RECEIVED_RH 0x40 /* Stall handshake received host mode */
-#define nSTALL_RECEIVED_RH 0x0
#define INCOMPRX_RH 0x100 /* indicates that a large packet is split host mode */
-#define nINCOMPRX_RH 0x0
#define DMAREQMODE_RH 0x800 /* DMA mode (0 or 1) selection host mode */
-#define nDMAREQMODE_RH 0x0
#define AUTOREQ_RH 0x4000 /* sets ReqPkt automatically host mode */
-#define nAUTOREQ_RH 0x0
/* Bit masks for USB_RXCOUNT */
@@ -1151,35 +883,22 @@
/* Bit masks for USB_DMA_INTERRUPT */
#define DMA0_INT 0x1 /* DMA0 pending interrupt */
-#define nDMA0_INT 0x0
#define DMA1_INT 0x2 /* DMA1 pending interrupt */
-#define nDMA1_INT 0x0
#define DMA2_INT 0x4 /* DMA2 pending interrupt */
-#define nDMA2_INT 0x0
#define DMA3_INT 0x8 /* DMA3 pending interrupt */
-#define nDMA3_INT 0x0
#define DMA4_INT 0x10 /* DMA4 pending interrupt */
-#define nDMA4_INT 0x0
#define DMA5_INT 0x20 /* DMA5 pending interrupt */
-#define nDMA5_INT 0x0
#define DMA6_INT 0x40 /* DMA6 pending interrupt */
-#define nDMA6_INT 0x0
#define DMA7_INT 0x80 /* DMA7 pending interrupt */
-#define nDMA7_INT 0x0
/* Bit masks for USB_DMAxCONTROL */
#define DMA_ENA 0x1 /* DMA enable */
-#define nDMA_ENA 0x0
#define DIRECTION 0x2 /* direction of DMA transfer */
-#define nDIRECTION 0x0
#define MODE 0x4 /* DMA Bus error */
-#define nMODE 0x0
#define INT_ENA 0x8 /* Interrupt enable */
-#define nINT_ENA 0x0
#define EPNUM 0xf0 /* EP number */
#define BUSERROR 0x100 /* DMA Bus error */
-#define nBUSERROR 0x0
/* Bit masks for USB_DMAxADDRHIGH */
diff --git a/include/asm-blackfin/mach-bf548/defBF544.h b/include/asm-blackfin/mach-bf548/defBF544.h
index 8fc77ea12aa9..dd955dcd39b8 100644
--- a/include/asm-blackfin/mach-bf548/defBF544.h
+++ b/include/asm-blackfin/mach-bf548/defBF544.h
@@ -538,21 +538,13 @@
/* Bit masks for PIXC_CTL */
#define PIXC_EN 0x1 /* Pixel Compositor Enable */
-#define nPIXC_EN 0x0
#define OVR_A_EN 0x2 /* Overlay A Enable */
-#define nOVR_A_EN 0x0
#define OVR_B_EN 0x4 /* Overlay B Enable */
-#define nOVR_B_EN 0x0
#define IMG_FORM 0x8 /* Image Data Format */
-#define nIMG_FORM 0x0
#define OVR_FORM 0x10 /* Overlay Data Format */
-#define nOVR_FORM 0x0
#define OUT_FORM 0x20 /* Output Data Format */
-#define nOUT_FORM 0x0
#define UDS_MOD 0x40 /* Resampling Mode */
-#define nUDS_MOD 0x0
#define TC_EN 0x80 /* Transparent Color Enable */
-#define nTC_EN 0x0
#define IMG_STAT 0x300 /* Image FIFO Status */
#define OVR_STAT 0xc00 /* Overlay FIFO Status */
#define WM_LVL 0x3000 /* FIFO Watermark Level */
@@ -600,13 +592,9 @@
/* Bit masks for PIXC_INTRSTAT */
#define OVR_INT_EN 0x1 /* Interrupt at End of Last Valid Overlay */
-#define nOVR_INT_EN 0x0
#define FRM_INT_EN 0x2 /* Interrupt at End of Frame */
-#define nFRM_INT_EN 0x0
#define OVR_INT_STAT 0x4 /* Overlay Interrupt Status */
-#define nOVR_INT_STAT 0x0
#define FRM_INT_STAT 0x8 /* Frame Interrupt Status */
-#define nFRM_INT_STAT 0x0
/* Bit masks for PIXC_RYCON */
@@ -614,7 +602,6 @@
#define A12 0xffc00 /* A12 in the Coefficient Matrix */
#define A13 0x3ff00000 /* A13 in the Coefficient Matrix */
#define RY_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nRY_MULT4 0x0
/* Bit masks for PIXC_GUCON */
@@ -622,7 +609,6 @@
#define A22 0xffc00 /* A22 in the Coefficient Matrix */
#define A23 0x3ff00000 /* A23 in the Coefficient Matrix */
#define GU_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nGU_MULT4 0x0
/* Bit masks for PIXC_BVCON */
@@ -630,7 +616,6 @@
#define A32 0xffc00 /* A32 in the Coefficient Matrix */
#define A33 0x3ff00000 /* A33 in the Coefficient Matrix */
#define BV_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nBV_MULT4 0x0
/* Bit masks for PIXC_CCBIAS */
@@ -647,48 +632,28 @@
/* Bit masks for HOST_CONTROL */
#define HOST_EN 0x1 /* Host Enable */
-#define nHOST_EN 0x0
#define HOST_END 0x2 /* Host Endianess */
-#define nHOST_END 0x0
#define DATA_SIZE 0x4 /* Data Size */
-#define nDATA_SIZE 0x0
#define HOST_RST 0x8 /* Host Reset */
-#define nHOST_RST 0x0
#define HRDY_OVR 0x20 /* Host Ready Override */
-#define nHRDY_OVR 0x0
#define INT_MODE 0x40 /* Interrupt Mode */
-#define nINT_MODE 0x0
#define BT_EN 0x80 /* Bus Timeout Enable */
-#define nBT_EN 0x0
#define EHW 0x100 /* Enable Host Write */
-#define nEHW 0x0
#define EHR 0x200 /* Enable Host Read */
-#define nEHR 0x0
#define BDR 0x400 /* Burst DMA Requests */
-#define nBDR 0x0
/* Bit masks for HOST_STATUS */
#define READY 0x1 /* DMA Ready */
-#define nREADY 0x0
#define FIFOFULL 0x2 /* FIFO Full */
-#define nFIFOFULL 0x0
#define FIFOEMPTY 0x4 /* FIFO Empty */
-#define nFIFOEMPTY 0x0
#define COMPLETE 0x8 /* DMA Complete */
-#define nCOMPLETE 0x0
#define HSHK 0x10 /* Host Handshake */
-#define nHSHK 0x0
#define TIMEOUT 0x20 /* Host Timeout */
-#define nTIMEOUT 0x0
#define HIRQ 0x40 /* Host Interrupt Request */
-#define nHIRQ 0x0
#define ALLOW_CNFG 0x80 /* Allow New Configuration */
-#define nALLOW_CNFG 0x0
#define DMA_DIR 0x100 /* DMA Direction */
-#define nDMA_DIR 0x0
#define BTE 0x200 /* Bus Timeout Enabled */
-#define nBTE 0x0
/* Bit masks for HOST_TIMEOUT */
@@ -697,67 +662,42 @@
/* Bit masks for TIMER_ENABLE1 */
#define TIMEN8 0x1 /* Timer 8 Enable */
-#define nTIMEN8 0x0
#define TIMEN9 0x2 /* Timer 9 Enable */
-#define nTIMEN9 0x0
#define TIMEN10 0x4 /* Timer 10 Enable */
-#define nTIMEN10 0x0
/* Bit masks for TIMER_DISABLE1 */
#define TIMDIS8 0x1 /* Timer 8 Disable */
-#define nTIMDIS8 0x0
#define TIMDIS9 0x2 /* Timer 9 Disable */
-#define nTIMDIS9 0x0
#define TIMDIS10 0x4 /* Timer 10 Disable */
-#define nTIMDIS10 0x0
/* Bit masks for TIMER_STATUS1 */
#define TIMIL8 0x1 /* Timer 8 Interrupt */
-#define nTIMIL8 0x0
#define TIMIL9 0x2 /* Timer 9 Interrupt */
-#define nTIMIL9 0x0
#define TIMIL10 0x4 /* Timer 10 Interrupt */
-#define nTIMIL10 0x0
#define TOVF_ERR8 0x10 /* Timer 8 Counter Overflow */
-#define nTOVF_ERR8 0x0
#define TOVF_ERR9 0x20 /* Timer 9 Counter Overflow */
-#define nTOVF_ERR9 0x0
#define TOVF_ERR10 0x40 /* Timer 10 Counter Overflow */
-#define nTOVF_ERR10 0x0
#define TRUN8 0x1000 /* Timer 8 Slave Enable Status */
-#define nTRUN8 0x0
#define TRUN9 0x2000 /* Timer 9 Slave Enable Status */
-#define nTRUN9 0x0
#define TRUN10 0x4000 /* Timer 10 Slave Enable Status */
-#define nTRUN10 0x0
/* Bit masks for EPPI0 are obtained from common base header for EPPIx (EPPI1 and EPPI2) */
/* Bit masks for HMDMAx_CONTROL */
#define HMDMAEN 0x1 /* Handshake MDMA Enable */
-#define nHMDMAEN 0x0
#define REP 0x2 /* Handshake MDMA Request Polarity */
-#define nREP 0x0
#define UTE 0x8 /* Urgency Threshold Enable */
-#define nUTE 0x0
#define OIE 0x10 /* Overflow Interrupt Enable */
-#define nOIE 0x0
#define BDIE 0x20 /* Block Done Interrupt Enable */
-#define nBDIE 0x0
#define MBDI 0x40 /* Mask Block Done Interrupt */
-#define nMBDI 0x0
#define DRQ 0x300 /* Handshake MDMA Request Type */
#define RBC 0x1000 /* Force Reload of BCOUNT */
-#define nRBC 0x0
#define PS 0x2000 /* Pin Status */
-#define nPS 0x0
#define OI 0x4000 /* Overflow Interrupt Generated */
-#define nOI 0x0
#define BDI 0x8000 /* Block Done Interrupt Generated */
-#define nBDI 0x0
/* ******************************************* */
/* MULTI BIT MACRO ENUMERATIONS */
diff --git a/include/asm-blackfin/mach-bf548/defBF548.h b/include/asm-blackfin/mach-bf548/defBF548.h
index d9e3062a9117..8d4214e0807c 100644
--- a/include/asm-blackfin/mach-bf548/defBF548.h
+++ b/include/asm-blackfin/mach-bf548/defBF548.h
@@ -899,21 +899,13 @@
/* Bit masks for PIXC_CTL */
#define PIXC_EN 0x1 /* Pixel Compositor Enable */
-#define nPIXC_EN 0x0
#define OVR_A_EN 0x2 /* Overlay A Enable */
-#define nOVR_A_EN 0x0
#define OVR_B_EN 0x4 /* Overlay B Enable */
-#define nOVR_B_EN 0x0
#define IMG_FORM 0x8 /* Image Data Format */
-#define nIMG_FORM 0x0
#define OVR_FORM 0x10 /* Overlay Data Format */
-#define nOVR_FORM 0x0
#define OUT_FORM 0x20 /* Output Data Format */
-#define nOUT_FORM 0x0
#define UDS_MOD 0x40 /* Resampling Mode */
-#define nUDS_MOD 0x0
#define TC_EN 0x80 /* Transparent Color Enable */
-#define nTC_EN 0x0
#define IMG_STAT 0x300 /* Image FIFO Status */
#define OVR_STAT 0xc00 /* Overlay FIFO Status */
#define WM_LVL 0x3000 /* FIFO Watermark Level */
@@ -961,13 +953,9 @@
/* Bit masks for PIXC_INTRSTAT */
#define OVR_INT_EN 0x1 /* Interrupt at End of Last Valid Overlay */
-#define nOVR_INT_EN 0x0
#define FRM_INT_EN 0x2 /* Interrupt at End of Frame */
-#define nFRM_INT_EN 0x0
#define OVR_INT_STAT 0x4 /* Overlay Interrupt Status */
-#define nOVR_INT_STAT 0x0
#define FRM_INT_STAT 0x8 /* Frame Interrupt Status */
-#define nFRM_INT_STAT 0x0
/* Bit masks for PIXC_RYCON */
@@ -975,7 +963,6 @@
#define A12 0xffc00 /* A12 in the Coefficient Matrix */
#define A13 0x3ff00000 /* A13 in the Coefficient Matrix */
#define RY_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nRY_MULT4 0x0
/* Bit masks for PIXC_GUCON */
@@ -983,7 +970,6 @@
#define A22 0xffc00 /* A22 in the Coefficient Matrix */
#define A23 0x3ff00000 /* A23 in the Coefficient Matrix */
#define GU_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nGU_MULT4 0x0
/* Bit masks for PIXC_BVCON */
@@ -991,7 +977,6 @@
#define A32 0xffc00 /* A32 in the Coefficient Matrix */
#define A33 0x3ff00000 /* A33 in the Coefficient Matrix */
#define BV_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nBV_MULT4 0x0
/* Bit masks for PIXC_CCBIAS */
@@ -1008,48 +993,28 @@
/* Bit masks for HOST_CONTROL */
#define HOST_EN 0x1 /* Host Enable */
-#define nHOST_EN 0x0
#define HOST_END 0x2 /* Host Endianess */
-#define nHOST_END 0x0
#define DATA_SIZE 0x4 /* Data Size */
-#define nDATA_SIZE 0x0
#define HOST_RST 0x8 /* Host Reset */
-#define nHOST_RST 0x0
#define HRDY_OVR 0x20 /* Host Ready Override */
-#define nHRDY_OVR 0x0
#define INT_MODE 0x40 /* Interrupt Mode */
-#define nINT_MODE 0x0
#define BT_EN 0x80 /* Bus Timeout Enable */
-#define nBT_EN 0x0
#define EHW 0x100 /* Enable Host Write */
-#define nEHW 0x0
#define EHR 0x200 /* Enable Host Read */
-#define nEHR 0x0
#define BDR 0x400 /* Burst DMA Requests */
-#define nBDR 0x0
/* Bit masks for HOST_STATUS */
#define READY 0x1 /* DMA Ready */
-#define nREADY 0x0
#define FIFOFULL 0x2 /* FIFO Full */
-#define nFIFOFULL 0x0
#define FIFOEMPTY 0x4 /* FIFO Empty */
-#define nFIFOEMPTY 0x0
#define COMPLETE 0x8 /* DMA Complete */
-#define nCOMPLETE 0x0
#define HSHK 0x10 /* Host Handshake */
-#define nHSHK 0x0
#define TIMEOUT 0x20 /* Host Timeout */
-#define nTIMEOUT 0x0
#define HIRQ 0x40 /* Host Interrupt Request */
-#define nHIRQ 0x0
#define ALLOW_CNFG 0x80 /* Allow New Configuration */
-#define nALLOW_CNFG 0x0
#define DMA_DIR 0x100 /* DMA Direction */
-#define nDMA_DIR 0x0
#define BTE 0x200 /* Bus Timeout Enabled */
-#define nBTE 0x0
/* Bit masks for HOST_TIMEOUT */
@@ -1058,7 +1023,6 @@
/* Bit masks for KPAD_CTL */
#define KPAD_EN 0x1 /* Keypad Enable */
-#define nKPAD_EN 0x0
#define KPAD_IRQMODE 0x6 /* Key Press Interrupt Enable */
#define KPAD_ROWEN 0x1c00 /* Row Enable Width */
#define KPAD_COLEN 0xe000 /* Column Enable Width */
@@ -1080,29 +1044,21 @@
/* Bit masks for KPAD_STAT */
#define KPAD_IRQ 0x1 /* Keypad Interrupt Status */
-#define nKPAD_IRQ 0x0
#define KPAD_MROWCOL 0x6 /* Multiple Row/Column Keypress Status */
#define KPAD_PRESSED 0x8 /* Key press current status */
-#define nKPAD_PRESSED 0x0
/* Bit masks for KPAD_SOFTEVAL */
#define KPAD_SOFTEVAL_E 0x2 /* Software Programmable Force Evaluate */
-#define nKPAD_SOFTEVAL_E 0x0
/* Bit masks for SDH_COMMAND */
#define CMD_IDX 0x3f /* Command Index */
#define CMD_RSP 0x40 /* Response */
-#define nCMD_RSP 0x0
#define CMD_L_RSP 0x80 /* Long Response */
-#define nCMD_L_RSP 0x0
#define CMD_INT_E 0x100 /* Command Interrupt */
-#define nCMD_INT_E 0x0
#define CMD_PEND_E 0x200 /* Command Pending */
-#define nCMD_PEND_E 0x0
#define CMD_E 0x400 /* Command Enable */
-#define nCMD_E 0x0
/* Bit masks for SDH_PWR_CTL */
@@ -1111,21 +1067,15 @@
#define TBD 0x3c /* TBD */
#endif
#define SD_CMD_OD 0x40 /* Open Drain Output */
-#define nSD_CMD_OD 0x0
#define ROD_CTL 0x80 /* Rod Control */
-#define nROD_CTL 0x0
/* Bit masks for SDH_CLK_CTL */
#define CLKDIV 0xff /* MC_CLK Divisor */
#define CLK_E 0x100 /* MC_CLK Bus Clock Enable */
-#define nCLK_E 0x0
#define PWR_SV_E 0x200 /* Power Save Enable */
-#define nPWR_SV_E 0x0
#define CLKDIV_BYPASS 0x400 /* Bypass Divisor */
-#define nCLKDIV_BYPASS 0x0
#define WIDE_BUS 0x800 /* Wide Bus Mode Enable */
-#define nWIDE_BUS 0x0
/* Bit masks for SDH_RESP_CMD */
@@ -1134,133 +1084,74 @@
/* Bit masks for SDH_DATA_CTL */
#define DTX_E 0x1 /* Data Transfer Enable */
-#define nDTX_E 0x0
#define DTX_DIR 0x2 /* Data Transfer Direction */
-#define nDTX_DIR 0x0
#define DTX_MODE 0x4 /* Data Transfer Mode */
-#define nDTX_MODE 0x0
#define DTX_DMA_E 0x8 /* Data Transfer DMA Enable */
-#define nDTX_DMA_E 0x0
#define DTX_BLK_LGTH 0xf0 /* Data Transfer Block Length */
/* Bit masks for SDH_STATUS */
#define CMD_CRC_FAIL 0x1 /* CMD CRC Fail */
-#define nCMD_CRC_FAIL 0x0
#define DAT_CRC_FAIL 0x2 /* Data CRC Fail */
-#define nDAT_CRC_FAIL 0x0
#define CMD_TIMEOUT 0x4 /* CMD Time Out */
-#define nCMD_TIMEOUT 0x0
#define DAT_TIMEOUT 0x8 /* Data Time Out */
-#define nDAT_TIMEOUT 0x0
#define TX_UNDERRUN 0x10 /* Transmit Underrun */
-#define nTX_UNDERRUN 0x0
#define RX_OVERRUN 0x20 /* Receive Overrun */
-#define nRX_OVERRUN 0x0
#define CMD_RESP_END 0x40 /* CMD Response End */
-#define nCMD_RESP_END 0x0
#define CMD_SENT 0x80 /* CMD Sent */
-#define nCMD_SENT 0x0
#define DAT_END 0x100 /* Data End */
-#define nDAT_END 0x0
#define START_BIT_ERR 0x200 /* Start Bit Error */
-#define nSTART_BIT_ERR 0x0
#define DAT_BLK_END 0x400 /* Data Block End */
-#define nDAT_BLK_END 0x0
#define CMD_ACT 0x800 /* CMD Active */
-#define nCMD_ACT 0x0
#define TX_ACT 0x1000 /* Transmit Active */
-#define nTX_ACT 0x0
#define RX_ACT 0x2000 /* Receive Active */
-#define nRX_ACT 0x0
#define TX_FIFO_STAT 0x4000 /* Transmit FIFO Status */
-#define nTX_FIFO_STAT 0x0
#define RX_FIFO_STAT 0x8000 /* Receive FIFO Status */
-#define nRX_FIFO_STAT 0x0
#define TX_FIFO_FULL 0x10000 /* Transmit FIFO Full */
-#define nTX_FIFO_FULL 0x0
#define RX_FIFO_FULL 0x20000 /* Receive FIFO Full */
-#define nRX_FIFO_FULL 0x0
#define TX_FIFO_ZERO 0x40000 /* Transmit FIFO Empty */
-#define nTX_FIFO_ZERO 0x0
#define RX_DAT_ZERO 0x80000 /* Receive FIFO Empty */
-#define nRX_DAT_ZERO 0x0
#define TX_DAT_RDY 0x100000 /* Transmit Data Available */
-#define nTX_DAT_RDY 0x0
#define RX_FIFO_RDY 0x200000 /* Receive Data Available */
-#define nRX_FIFO_RDY 0x0
/* Bit masks for SDH_STATUS_CLR */
#define CMD_CRC_FAIL_STAT 0x1 /* CMD CRC Fail Status */
-#define nCMD_CRC_FAIL_STAT 0x0
#define DAT_CRC_FAIL_STAT 0x2 /* Data CRC Fail Status */
-#define nDAT_CRC_FAIL_STAT 0x0
#define CMD_TIMEOUT_STAT 0x4 /* CMD Time Out Status */
-#define nCMD_TIMEOUT_STAT 0x0
#define DAT_TIMEOUT_STAT 0x8 /* Data Time Out status */
-#define nDAT_TIMEOUT_STAT 0x0
#define TX_UNDERRUN_STAT 0x10 /* Transmit Underrun Status */
-#define nTX_UNDERRUN_STAT 0x0
#define RX_OVERRUN_STAT 0x20 /* Receive Overrun Status */
-#define nRX_OVERRUN_STAT 0x0
#define CMD_RESP_END_STAT 0x40 /* CMD Response End Status */
-#define nCMD_RESP_END_STAT 0x0
#define CMD_SENT_STAT 0x80 /* CMD Sent Status */
-#define nCMD_SENT_STAT 0x0
#define DAT_END_STAT 0x100 /* Data End Status */
-#define nDAT_END_STAT 0x0
#define START_BIT_ERR_STAT 0x200 /* Start Bit Error Status */
-#define nSTART_BIT_ERR_STAT 0x0
#define DAT_BLK_END_STAT 0x400 /* Data Block End Status */
-#define nDAT_BLK_END_STAT 0x0
/* Bit masks for SDH_MASK0 */
#define CMD_CRC_FAIL_MASK 0x1 /* CMD CRC Fail Mask */
-#define nCMD_CRC_FAIL_MASK 0x0
#define DAT_CRC_FAIL_MASK 0x2 /* Data CRC Fail Mask */
-#define nDAT_CRC_FAIL_MASK 0x0
#define CMD_TIMEOUT_MASK 0x4 /* CMD Time Out Mask */
-#define nCMD_TIMEOUT_MASK 0x0
#define DAT_TIMEOUT_MASK 0x8 /* Data Time Out Mask */
-#define nDAT_TIMEOUT_MASK 0x0
#define TX_UNDERRUN_MASK 0x10 /* Transmit Underrun Mask */
-#define nTX_UNDERRUN_MASK 0x0
#define RX_OVERRUN_MASK 0x20 /* Receive Overrun Mask */
-#define nRX_OVERRUN_MASK 0x0
#define CMD_RESP_END_MASK 0x40 /* CMD Response End Mask */
-#define nCMD_RESP_END_MASK 0x0
#define CMD_SENT_MASK 0x80 /* CMD Sent Mask */
-#define nCMD_SENT_MASK 0x0
#define DAT_END_MASK 0x100 /* Data End Mask */
-#define nDAT_END_MASK 0x0
#define START_BIT_ERR_MASK 0x200 /* Start Bit Error Mask */
-#define nSTART_BIT_ERR_MASK 0x0
#define DAT_BLK_END_MASK 0x400 /* Data Block End Mask */
-#define nDAT_BLK_END_MASK 0x0
#define CMD_ACT_MASK 0x800 /* CMD Active Mask */
-#define nCMD_ACT_MASK 0x0
#define TX_ACT_MASK 0x1000 /* Transmit Active Mask */
-#define nTX_ACT_MASK 0x0
#define RX_ACT_MASK 0x2000 /* Receive Active Mask */
-#define nRX_ACT_MASK 0x0
#define TX_FIFO_STAT_MASK 0x4000 /* Transmit FIFO Status Mask */
-#define nTX_FIFO_STAT_MASK 0x0
#define RX_FIFO_STAT_MASK 0x8000 /* Receive FIFO Status Mask */
-#define nRX_FIFO_STAT_MASK 0x0
#define TX_FIFO_FULL_MASK 0x10000 /* Transmit FIFO Full Mask */
-#define nTX_FIFO_FULL_MASK 0x0
#define RX_FIFO_FULL_MASK 0x20000 /* Receive FIFO Full Mask */
-#define nRX_FIFO_FULL_MASK 0x0
#define TX_FIFO_ZERO_MASK 0x40000 /* Transmit FIFO Empty Mask */
-#define nTX_FIFO_ZERO_MASK 0x0
#define RX_DAT_ZERO_MASK 0x80000 /* Receive FIFO Empty Mask */
-#define nRX_DAT_ZERO_MASK 0x0
#define TX_DAT_RDY_MASK 0x100000 /* Transmit Data Available Mask */
-#define nTX_DAT_RDY_MASK 0x0
#define RX_FIFO_RDY_MASK 0x200000 /* Receive Data Available Mask */
-#define nRX_FIFO_RDY_MASK 0x0
/* Bit masks for SDH_FIFO_CNT */
@@ -1269,73 +1160,47 @@
/* Bit masks for SDH_E_STATUS */
#define SDIO_INT_DET 0x2 /* SDIO Int Detected */
-#define nSDIO_INT_DET 0x0
#define SD_CARD_DET 0x10 /* SD Card Detect */
-#define nSD_CARD_DET 0x0
/* Bit masks for SDH_E_MASK */
#define SDIO_MSK 0x2 /* Mask SDIO Int Detected */
-#define nSDIO_MSK 0x0
#define SCD_MSK 0x40 /* Mask Card Detect */
-#define nSCD_MSK 0x0
/* Bit masks for SDH_CFG */
#define CLKS_EN 0x1 /* Clocks Enable */
-#define nCLKS_EN 0x0
#define SD4E 0x4 /* SDIO 4-Bit Enable */
-#define nSD4E 0x0
#define MWE 0x8 /* Moving Window Enable */
-#define nMWE 0x0
#define SD_RST 0x10 /* SDMMC Reset */
-#define nSD_RST 0x0
#define PUP_SDDAT 0x20 /* Pull-up SD_DAT */
-#define nPUP_SDDAT 0x0
#define PUP_SDDAT3 0x40 /* Pull-up SD_DAT3 */
-#define nPUP_SDDAT3 0x0
#define PD_SDDAT3 0x80 /* Pull-down SD_DAT3 */
-#define nPD_SDDAT3 0x0
/* Bit masks for SDH_RD_WAIT_EN */
#define RWR 0x1 /* Read Wait Request */
-#define nRWR 0x0
/* Bit masks for ATAPI_CONTROL */
#define PIO_START 0x1 /* Start PIO/Reg Op */
-#define nPIO_START 0x0
#define MULTI_START 0x2 /* Start Multi-DMA Op */
-#define nMULTI_START 0x0
#define ULTRA_START 0x4 /* Start Ultra-DMA Op */
-#define nULTRA_START 0x0
#define XFER_DIR 0x8 /* Transfer Direction */
-#define nXFER_DIR 0x0
#define IORDY_EN 0x10 /* IORDY Enable */
-#define nIORDY_EN 0x0
#define FIFO_FLUSH 0x20 /* Flush FIFOs */
-#define nFIFO_FLUSH 0x0
#define SOFT_RST 0x40 /* Soft Reset */
-#define nSOFT_RST 0x0
#define DEV_RST 0x80 /* Device Reset */
-#define nDEV_RST 0x0
#define TFRCNT_RST 0x100 /* Trans Count Reset */
-#define nTFRCNT_RST 0x0
#define END_ON_TERM 0x200 /* End/Terminate Select */
-#define nEND_ON_TERM 0x0
#define PIO_USE_DMA 0x400 /* PIO-DMA Enable */
-#define nPIO_USE_DMA 0x0
#define UDMAIN_FIFO_THRS 0xf000 /* Ultra DMA-IN FIFO Threshold */
/* Bit masks for ATAPI_STATUS */
#define PIO_XFER_ON 0x1 /* PIO transfer in progress */
-#define nPIO_XFER_ON 0x0
#define MULTI_XFER_ON 0x2 /* Multi-word DMA transfer in progress */
-#define nMULTI_XFER_ON 0x0
#define ULTRA_XFER_ON 0x4 /* Ultra DMA transfer in progress */
-#define nULTRA_XFER_ON 0x0
#define ULTRA_IN_FL 0xf0 /* Ultra DMA Input FIFO Level */
/* Bit masks for ATAPI_DEV_ADDR */
@@ -1345,66 +1210,39 @@
/* Bit masks for ATAPI_INT_MASK */
#define ATAPI_DEV_INT_MASK 0x1 /* Device interrupt mask */
-#define nATAPI_DEV_INT_MASK 0x0
#define PIO_DONE_MASK 0x2 /* PIO transfer done interrupt mask */
-#define nPIO_DONE_MASK 0x0
#define MULTI_DONE_MASK 0x4 /* Multi-DMA transfer done interrupt mask */
-#define nMULTI_DONE_MASK 0x0
#define UDMAIN_DONE_MASK 0x8 /* Ultra-DMA in transfer done interrupt mask */
-#define nUDMAIN_DONE_MASK 0x0
#define UDMAOUT_DONE_MASK 0x10 /* Ultra-DMA out transfer done interrupt mask */
-#define nUDMAOUT_DONE_MASK 0x0
#define HOST_TERM_XFER_MASK 0x20 /* Host terminate current transfer interrupt mask */
-#define nHOST_TERM_XFER_MASK 0x0
#define MULTI_TERM_MASK 0x40 /* Device terminate Multi-DMA transfer interrupt mask */
-#define nMULTI_TERM_MASK 0x0
#define UDMAIN_TERM_MASK 0x80 /* Device terminate Ultra-DMA-in transfer interrupt mask */
-#define nUDMAIN_TERM_MASK 0x0
#define UDMAOUT_TERM_MASK 0x100 /* Device terminate Ultra-DMA-out transfer interrupt mask */
-#define nUDMAOUT_TERM_MASK 0x0
/* Bit masks for ATAPI_INT_STATUS */
#define ATAPI_DEV_INT 0x1 /* Device interrupt status */
-#define nATAPI_DEV_INT 0x0
#define PIO_DONE_INT 0x2 /* PIO transfer done interrupt status */
-#define nPIO_DONE_INT 0x0
#define MULTI_DONE_INT 0x4 /* Multi-DMA transfer done interrupt status */
-#define nMULTI_DONE_INT 0x0
#define UDMAIN_DONE_INT 0x8 /* Ultra-DMA in transfer done interrupt status */
-#define nUDMAIN_DONE_INT 0x0
#define UDMAOUT_DONE_INT 0x10 /* Ultra-DMA out transfer done interrupt status */
-#define nUDMAOUT_DONE_INT 0x0
#define HOST_TERM_XFER_INT 0x20 /* Host terminate current transfer interrupt status */
-#define nHOST_TERM_XFER_INT 0x0
#define MULTI_TERM_INT 0x40 /* Device terminate Multi-DMA transfer interrupt status */
-#define nMULTI_TERM_INT 0x0
#define UDMAIN_TERM_INT 0x80 /* Device terminate Ultra-DMA-in transfer interrupt status */
-#define nUDMAIN_TERM_INT 0x0
#define UDMAOUT_TERM_INT 0x100 /* Device terminate Ultra-DMA-out transfer interrupt status */
-#define nUDMAOUT_TERM_INT 0x0
/* Bit masks for ATAPI_LINE_STATUS */
#define ATAPI_INTR 0x1 /* Device interrupt to host line status */
-#define nATAPI_INTR 0x0
#define ATAPI_DASP 0x2 /* Device dasp to host line status */
-#define nATAPI_DASP 0x0
#define ATAPI_CS0N 0x4 /* ATAPI chip select 0 line status */
-#define nATAPI_CS0N 0x0
#define ATAPI_CS1N 0x8 /* ATAPI chip select 1 line status */
-#define nATAPI_CS1N 0x0
#define ATAPI_ADDR 0x70 /* ATAPI address line status */
#define ATAPI_DMAREQ 0x80 /* ATAPI DMA request line status */
-#define nATAPI_DMAREQ 0x0
#define ATAPI_DMAACKN 0x100 /* ATAPI DMA acknowledge line status */
-#define nATAPI_DMAACKN 0x0
#define ATAPI_DIOWN 0x200 /* ATAPI write line status */
-#define nATAPI_DIOWN 0x0
#define ATAPI_DIORN 0x400 /* ATAPI read line status */
-#define nATAPI_DIORN 0x0
#define ATAPI_IORDY 0x800 /* ATAPI IORDY line status */
-#define nATAPI_IORDY 0x0
/* Bit masks for ATAPI_SM_STATE */
@@ -1416,7 +1254,6 @@
/* Bit masks for ATAPI_TERMINATE */
#define ATAPI_HOST_TERM 0x1 /* Host terminationation */
-#define nATAPI_HOST_TERM 0x0
/* Bit masks for ATAPI_REG_TIM_0 */
@@ -1471,41 +1308,26 @@
/* Bit masks for TIMER_ENABLE1 */
#define TIMEN8 0x1 /* Timer 8 Enable */
-#define nTIMEN8 0x0
#define TIMEN9 0x2 /* Timer 9 Enable */
-#define nTIMEN9 0x0
#define TIMEN10 0x4 /* Timer 10 Enable */
-#define nTIMEN10 0x0
/* Bit masks for TIMER_DISABLE1 */
#define TIMDIS8 0x1 /* Timer 8 Disable */
-#define nTIMDIS8 0x0
#define TIMDIS9 0x2 /* Timer 9 Disable */
-#define nTIMDIS9 0x0
#define TIMDIS10 0x4 /* Timer 10 Disable */
-#define nTIMDIS10 0x0
/* Bit masks for TIMER_STATUS1 */
#define TIMIL8 0x1 /* Timer 8 Interrupt */
-#define nTIMIL8 0x0
#define TIMIL9 0x2 /* Timer 9 Interrupt */
-#define nTIMIL9 0x0
#define TIMIL10 0x4 /* Timer 10 Interrupt */
-#define nTIMIL10 0x0
#define TOVF_ERR8 0x10 /* Timer 8 Counter Overflow */
-#define nTOVF_ERR8 0x0
#define TOVF_ERR9 0x20 /* Timer 9 Counter Overflow */
-#define nTOVF_ERR9 0x0
#define TOVF_ERR10 0x40 /* Timer 10 Counter Overflow */
-#define nTOVF_ERR10 0x0
#define TRUN8 0x1000 /* Timer 8 Slave Enable Status */
-#define nTRUN8 0x0
#define TRUN9 0x2000 /* Timer 9 Slave Enable Status */
-#define nTRUN9 0x0
#define TRUN10 0x4000 /* Timer 10 Slave Enable Status */
-#define nTRUN10 0x0
/* Bit masks for EPPI0 are obtained from common base header for EPPIx (EPPI1 and EPPI2) */
@@ -1516,131 +1338,77 @@
/* Bit masks for USB_POWER */
#define ENABLE_SUSPENDM 0x1 /* enable SuspendM output */
-#define nENABLE_SUSPENDM 0x0
#define SUSPEND_MODE 0x2 /* Suspend Mode indicator */
-#define nSUSPEND_MODE 0x0
#define RESUME_MODE 0x4 /* DMA Mode */
-#define nRESUME_MODE 0x0
#define RESET 0x8 /* Reset indicator */
-#define nRESET 0x0
#define HS_MODE 0x10 /* High Speed mode indicator */
-#define nHS_MODE 0x0
#define HS_ENABLE 0x20 /* high Speed Enable */
-#define nHS_ENABLE 0x0
#define SOFT_CONN 0x40 /* Soft connect */
-#define nSOFT_CONN 0x0
#define ISO_UPDATE 0x80 /* Isochronous update */
-#define nISO_UPDATE 0x0
/* Bit masks for USB_INTRTX */
#define EP0_TX 0x1 /* Tx Endpoint 0 interrupt */
-#define nEP0_TX 0x0
#define EP1_TX 0x2 /* Tx Endpoint 1 interrupt */
-#define nEP1_TX 0x0
#define EP2_TX 0x4 /* Tx Endpoint 2 interrupt */
-#define nEP2_TX 0x0
#define EP3_TX 0x8 /* Tx Endpoint 3 interrupt */
-#define nEP3_TX 0x0
#define EP4_TX 0x10 /* Tx Endpoint 4 interrupt */
-#define nEP4_TX 0x0
#define EP5_TX 0x20 /* Tx Endpoint 5 interrupt */
-#define nEP5_TX 0x0
#define EP6_TX 0x40 /* Tx Endpoint 6 interrupt */
-#define nEP6_TX 0x0
#define EP7_TX 0x80 /* Tx Endpoint 7 interrupt */
-#define nEP7_TX 0x0
/* Bit masks for USB_INTRRX */
#define EP1_RX 0x2 /* Rx Endpoint 1 interrupt */
-#define nEP1_RX 0x0
#define EP2_RX 0x4 /* Rx Endpoint 2 interrupt */
-#define nEP2_RX 0x0
#define EP3_RX 0x8 /* Rx Endpoint 3 interrupt */
-#define nEP3_RX 0x0
#define EP4_RX 0x10 /* Rx Endpoint 4 interrupt */
-#define nEP4_RX 0x0
#define EP5_RX 0x20 /* Rx Endpoint 5 interrupt */
-#define nEP5_RX 0x0
#define EP6_RX 0x40 /* Rx Endpoint 6 interrupt */
-#define nEP6_RX 0x0
#define EP7_RX 0x80 /* Rx Endpoint 7 interrupt */
-#define nEP7_RX 0x0
/* Bit masks for USB_INTRTXE */
#define EP0_TX_E 0x1 /* Endpoint 0 interrupt Enable */
-#define nEP0_TX_E 0x0
#define EP1_TX_E 0x2 /* Tx Endpoint 1 interrupt Enable */
-#define nEP1_TX_E 0x0
#define EP2_TX_E 0x4 /* Tx Endpoint 2 interrupt Enable */
-#define nEP2_TX_E 0x0
#define EP3_TX_E 0x8 /* Tx Endpoint 3 interrupt Enable */
-#define nEP3_TX_E 0x0
#define EP4_TX_E 0x10 /* Tx Endpoint 4 interrupt Enable */
-#define nEP4_TX_E 0x0
#define EP5_TX_E 0x20 /* Tx Endpoint 5 interrupt Enable */
-#define nEP5_TX_E 0x0
#define EP6_TX_E 0x40 /* Tx Endpoint 6 interrupt Enable */
-#define nEP6_TX_E 0x0
#define EP7_TX_E 0x80 /* Tx Endpoint 7 interrupt Enable */
-#define nEP7_TX_E 0x0
/* Bit masks for USB_INTRRXE */
#define EP1_RX_E 0x2 /* Rx Endpoint 1 interrupt Enable */
-#define nEP1_RX_E 0x0
#define EP2_RX_E 0x4 /* Rx Endpoint 2 interrupt Enable */
-#define nEP2_RX_E 0x0
#define EP3_RX_E 0x8 /* Rx Endpoint 3 interrupt Enable */
-#define nEP3_RX_E 0x0
#define EP4_RX_E 0x10 /* Rx Endpoint 4 interrupt Enable */
-#define nEP4_RX_E 0x0
#define EP5_RX_E 0x20 /* Rx Endpoint 5 interrupt Enable */
-#define nEP5_RX_E 0x0
#define EP6_RX_E 0x40 /* Rx Endpoint 6 interrupt Enable */
-#define nEP6_RX_E 0x0
#define EP7_RX_E 0x80 /* Rx Endpoint 7 interrupt Enable */
-#define nEP7_RX_E 0x0
/* Bit masks for USB_INTRUSB */
#define SUSPEND_B 0x1 /* Suspend indicator */
-#define nSUSPEND_B 0x0
#define RESUME_B 0x2 /* Resume indicator */
-#define nRESUME_B 0x0
#define RESET_OR_BABLE_B 0x4 /* Reset/babble indicator */
-#define nRESET_OR_BABLE_B 0x0
#define SOF_B 0x8 /* Start of frame */
-#define nSOF_B 0x0
#define CONN_B 0x10 /* Connection indicator */
-#define nCONN_B 0x0
#define DISCON_B 0x20 /* Disconnect indicator */
-#define nDISCON_B 0x0
#define SESSION_REQ_B 0x40 /* Session Request */
-#define nSESSION_REQ_B 0x0
#define VBUS_ERROR_B 0x80 /* Vbus threshold indicator */
-#define nVBUS_ERROR_B 0x0
/* Bit masks for USB_INTRUSBE */
#define SUSPEND_BE 0x1 /* Suspend indicator int enable */
-#define nSUSPEND_BE 0x0
#define RESUME_BE 0x2 /* Resume indicator int enable */
-#define nRESUME_BE 0x0
#define RESET_OR_BABLE_BE 0x4 /* Reset/babble indicator int enable */
-#define nRESET_OR_BABLE_BE 0x0
#define SOF_BE 0x8 /* Start of frame int enable */
-#define nSOF_BE 0x0
#define CONN_BE 0x10 /* Connection indicator int enable */
-#define nCONN_BE 0x0
#define DISCON_BE 0x20 /* Disconnect indicator int enable */
-#define nDISCON_BE 0x0
#define SESSION_REQ_BE 0x40 /* Session Request int enable */
-#define nSESSION_REQ_BE 0x0
#define VBUS_ERROR_BE 0x80 /* Vbus threshold indicator int enable */
-#define nVBUS_ERROR_BE 0x0
/* Bit masks for USB_FRAME */
@@ -1653,117 +1421,67 @@
/* Bit masks for USB_GLOBAL_CTL */
#define GLOBAL_ENA 0x1 /* enables USB module */
-#define nGLOBAL_ENA 0x0
#define EP1_TX_ENA 0x2 /* Transmit endpoint 1 enable */
-#define nEP1_TX_ENA 0x0
#define EP2_TX_ENA 0x4 /* Transmit endpoint 2 enable */
-#define nEP2_TX_ENA 0x0
#define EP3_TX_ENA 0x8 /* Transmit endpoint 3 enable */
-#define nEP3_TX_ENA 0x0
#define EP4_TX_ENA 0x10 /* Transmit endpoint 4 enable */
-#define nEP4_TX_ENA 0x0
#define EP5_TX_ENA 0x20 /* Transmit endpoint 5 enable */
-#define nEP5_TX_ENA 0x0
#define EP6_TX_ENA 0x40 /* Transmit endpoint 6 enable */
-#define nEP6_TX_ENA 0x0
#define EP7_TX_ENA 0x80 /* Transmit endpoint 7 enable */
-#define nEP7_TX_ENA 0x0
#define EP1_RX_ENA 0x100 /* Receive endpoint 1 enable */
-#define nEP1_RX_ENA 0x0
#define EP2_RX_ENA 0x200 /* Receive endpoint 2 enable */
-#define nEP2_RX_ENA 0x0
#define EP3_RX_ENA 0x400 /* Receive endpoint 3 enable */
-#define nEP3_RX_ENA 0x0
#define EP4_RX_ENA 0x800 /* Receive endpoint 4 enable */
-#define nEP4_RX_ENA 0x0
#define EP5_RX_ENA 0x1000 /* Receive endpoint 5 enable */
-#define nEP5_RX_ENA 0x0
#define EP6_RX_ENA 0x2000 /* Receive endpoint 6 enable */
-#define nEP6_RX_ENA 0x0
#define EP7_RX_ENA 0x4000 /* Receive endpoint 7 enable */
-#define nEP7_RX_ENA 0x0
/* Bit masks for USB_OTG_DEV_CTL */
#define SESSION 0x1 /* session indicator */
-#define nSESSION 0x0
#define HOST_REQ 0x2 /* Host negotiation request */
-#define nHOST_REQ 0x0
#define HOST_MODE 0x4 /* indicates USBDRC is a host */
-#define nHOST_MODE 0x0
#define VBUS0 0x8 /* Vbus level indicator[0] */
-#define nVBUS0 0x0
#define VBUS1 0x10 /* Vbus level indicator[1] */
-#define nVBUS1 0x0
#define LSDEV 0x20 /* Low-speed indicator */
-#define nLSDEV 0x0
#define FSDEV 0x40 /* Full or High-speed indicator */
-#define nFSDEV 0x0
#define B_DEVICE 0x80 /* A' or 'B' device indicator */
-#define nB_DEVICE 0x0
/* Bit masks for USB_OTG_VBUS_IRQ */
#define DRIVE_VBUS_ON 0x1 /* indicator to drive VBUS control circuit */
-#define nDRIVE_VBUS_ON 0x0
#define DRIVE_VBUS_OFF 0x2 /* indicator to shut off charge pump */
-#define nDRIVE_VBUS_OFF 0x0
#define CHRG_VBUS_START 0x4 /* indicator for external circuit to start charging VBUS */
-#define nCHRG_VBUS_START 0x0
#define CHRG_VBUS_END 0x8 /* indicator for external circuit to end charging VBUS */
-#define nCHRG_VBUS_END 0x0
#define DISCHRG_VBUS_START 0x10 /* indicator to start discharging VBUS */
-#define nDISCHRG_VBUS_START 0x0
#define DISCHRG_VBUS_END 0x20 /* indicator to stop discharging VBUS */
-#define nDISCHRG_VBUS_END 0x0
/* Bit masks for USB_OTG_VBUS_MASK */
#define DRIVE_VBUS_ON_ENA 0x1 /* enable DRIVE_VBUS_ON interrupt */
-#define nDRIVE_VBUS_ON_ENA 0x0
#define DRIVE_VBUS_OFF_ENA 0x2 /* enable DRIVE_VBUS_OFF interrupt */
-#define nDRIVE_VBUS_OFF_ENA 0x0
#define CHRG_VBUS_START_ENA 0x4 /* enable CHRG_VBUS_START interrupt */
-#define nCHRG_VBUS_START_ENA 0x0
#define CHRG_VBUS_END_ENA 0x8 /* enable CHRG_VBUS_END interrupt */
-#define nCHRG_VBUS_END_ENA 0x0
#define DISCHRG_VBUS_START_ENA 0x10 /* enable DISCHRG_VBUS_START interrupt */
-#define nDISCHRG_VBUS_START_ENA 0x0
#define DISCHRG_VBUS_END_ENA 0x20 /* enable DISCHRG_VBUS_END interrupt */
-#define nDISCHRG_VBUS_END_ENA 0x0
/* Bit masks for USB_CSR0 */
#define RXPKTRDY 0x1 /* data packet receive indicator */
-#define nRXPKTRDY 0x0
#define TXPKTRDY 0x2 /* data packet in FIFO indicator */
-#define nTXPKTRDY 0x0
#define STALL_SENT 0x4 /* STALL handshake sent */
-#define nSTALL_SENT 0x0
#define DATAEND 0x8 /* Data end indicator */
-#define nDATAEND 0x0
#define SETUPEND 0x10 /* Setup end */
-#define nSETUPEND 0x0
#define SENDSTALL 0x20 /* Send STALL handshake */
-#define nSENDSTALL 0x0
#define SERVICED_RXPKTRDY 0x40 /* used to clear the RxPktRdy bit */
-#define nSERVICED_RXPKTRDY 0x0
#define SERVICED_SETUPEND 0x80 /* used to clear the SetupEnd bit */
-#define nSERVICED_SETUPEND 0x0
#define FLUSHFIFO 0x100 /* flush endpoint FIFO */
-#define nFLUSHFIFO 0x0
#define STALL_RECEIVED_H 0x4 /* STALL handshake received host mode */
-#define nSTALL_RECEIVED_H 0x0
#define SETUPPKT_H 0x8 /* send Setup token host mode */
-#define nSETUPPKT_H 0x0
#define ERROR_H 0x10 /* timeout error indicator host mode */
-#define nERROR_H 0x0
#define REQPKT_H 0x20 /* Request an IN transaction host mode */
-#define nREQPKT_H 0x0
#define STATUSPKT_H 0x40 /* Status stage transaction host mode */
-#define nSTATUSPKT_H 0x0
#define NAK_TIMEOUT_H 0x80 /* EP0 halted after a NAK host mode */
-#define nNAK_TIMEOUT_H 0x0
/* Bit masks for USB_COUNT0 */
@@ -1784,37 +1502,21 @@
/* Bit masks for USB_TXCSR */
#define TXPKTRDY_T 0x1 /* data packet in FIFO indicator */
-#define nTXPKTRDY_T 0x0
#define FIFO_NOT_EMPTY_T 0x2 /* FIFO not empty */
-#define nFIFO_NOT_EMPTY_T 0x0
#define UNDERRUN_T 0x4 /* TxPktRdy not set for an IN token */
-#define nUNDERRUN_T 0x0
#define FLUSHFIFO_T 0x8 /* flush endpoint FIFO */
-#define nFLUSHFIFO_T 0x0
#define STALL_SEND_T 0x10 /* issue a Stall handshake */
-#define nSTALL_SEND_T 0x0
#define STALL_SENT_T 0x20 /* Stall handshake transmitted */
-#define nSTALL_SENT_T 0x0
#define CLEAR_DATATOGGLE_T 0x40 /* clear endpoint data toggle */
-#define nCLEAR_DATATOGGLE_T 0x0
#define INCOMPTX_T 0x80 /* indicates that a large packet is split */
-#define nINCOMPTX_T 0x0
#define DMAREQMODE_T 0x400 /* DMA mode (0 or 1) selection */
-#define nDMAREQMODE_T 0x0
#define FORCE_DATATOGGLE_T 0x800 /* Force data toggle */
-#define nFORCE_DATATOGGLE_T 0x0
#define DMAREQ_ENA_T 0x1000 /* Enable DMA request for Tx EP */
-#define nDMAREQ_ENA_T 0x0
#define ISO_T 0x4000 /* enable Isochronous transfers */
-#define nISO_T 0x0
#define AUTOSET_T 0x8000 /* allows TxPktRdy to be set automatically */
-#define nAUTOSET_T 0x0
#define ERROR_TH 0x4 /* error condition host mode */
-#define nERROR_TH 0x0
#define STALL_RECEIVED_TH 0x20 /* Stall handshake received host mode */
-#define nSTALL_RECEIVED_TH 0x0
#define NAK_TIMEOUT_TH 0x80 /* NAK timeout host mode */
-#define nNAK_TIMEOUT_TH 0x0
/* Bit masks for USB_TXCOUNT */
@@ -1823,45 +1525,25 @@
/* Bit masks for USB_RXCSR */
#define RXPKTRDY_R 0x1 /* data packet in FIFO indicator */
-#define nRXPKTRDY_R 0x0
#define FIFO_FULL_R 0x2 /* FIFO not empty */
-#define nFIFO_FULL_R 0x0
#define OVERRUN_R 0x4 /* TxPktRdy not set for an IN token */
-#define nOVERRUN_R 0x0
#define DATAERROR_R 0x8 /* Out packet cannot be loaded into Rx FIFO */
-#define nDATAERROR_R 0x0
#define FLUSHFIFO_R 0x10 /* flush endpoint FIFO */
-#define nFLUSHFIFO_R 0x0
#define STALL_SEND_R 0x20 /* issue a Stall handshake */
-#define nSTALL_SEND_R 0x0
#define STALL_SENT_R 0x40 /* Stall handshake transmitted */
-#define nSTALL_SENT_R 0x0
#define CLEAR_DATATOGGLE_R 0x80 /* clear endpoint data toggle */
-#define nCLEAR_DATATOGGLE_R 0x0
#define INCOMPRX_R 0x100 /* indicates that a large packet is split */
-#define nINCOMPRX_R 0x0
#define DMAREQMODE_R 0x800 /* DMA mode (0 or 1) selection */
-#define nDMAREQMODE_R 0x0
#define DISNYET_R 0x1000 /* disable Nyet handshakes */
-#define nDISNYET_R 0x0
#define DMAREQ_ENA_R 0x2000 /* Enable DMA request for Tx EP */
-#define nDMAREQ_ENA_R 0x0
#define ISO_R 0x4000 /* enable Isochronous transfers */
-#define nISO_R 0x0
#define AUTOCLEAR_R 0x8000 /* allows TxPktRdy to be set automatically */
-#define nAUTOCLEAR_R 0x0
#define ERROR_RH 0x4 /* TxPktRdy not set for an IN token host mode */
-#define nERROR_RH 0x0
#define REQPKT_RH 0x20 /* request an IN transaction host mode */
-#define nREQPKT_RH 0x0
#define STALL_RECEIVED_RH 0x40 /* Stall handshake received host mode */
-#define nSTALL_RECEIVED_RH 0x0
#define INCOMPRX_RH 0x100 /* indicates that a large packet is split host mode */
-#define nINCOMPRX_RH 0x0
#define DMAREQMODE_RH 0x800 /* DMA mode (0 or 1) selection host mode */
-#define nDMAREQMODE_RH 0x0
#define AUTOREQ_RH 0x4000 /* sets ReqPkt automatically host mode */
-#define nAUTOREQ_RH 0x0
/* Bit masks for USB_RXCOUNT */
@@ -1888,35 +1570,22 @@
/* Bit masks for USB_DMA_INTERRUPT */
#define DMA0_INT 0x1 /* DMA0 pending interrupt */
-#define nDMA0_INT 0x0
#define DMA1_INT 0x2 /* DMA1 pending interrupt */
-#define nDMA1_INT 0x0
#define DMA2_INT 0x4 /* DMA2 pending interrupt */
-#define nDMA2_INT 0x0
#define DMA3_INT 0x8 /* DMA3 pending interrupt */
-#define nDMA3_INT 0x0
#define DMA4_INT 0x10 /* DMA4 pending interrupt */
-#define nDMA4_INT 0x0
#define DMA5_INT 0x20 /* DMA5 pending interrupt */
-#define nDMA5_INT 0x0
#define DMA6_INT 0x40 /* DMA6 pending interrupt */
-#define nDMA6_INT 0x0
#define DMA7_INT 0x80 /* DMA7 pending interrupt */
-#define nDMA7_INT 0x0
/* Bit masks for USB_DMAxCONTROL */
#define DMA_ENA 0x1 /* DMA enable */
-#define nDMA_ENA 0x0
#define DIRECTION 0x2 /* direction of DMA transfer */
-#define nDIRECTION 0x0
#define MODE 0x4 /* DMA Bus error */
-#define nMODE 0x0
#define INT_ENA 0x8 /* Interrupt enable */
-#define nINT_ENA 0x0
#define EPNUM 0xf0 /* EP number */
#define BUSERROR 0x100 /* DMA Bus error */
-#define nBUSERROR 0x0
/* Bit masks for USB_DMAxADDRHIGH */
@@ -1937,26 +1606,16 @@
/* Bit masks for HMDMAx_CONTROL */
#define HMDMAEN 0x1 /* Handshake MDMA Enable */
-#define nHMDMAEN 0x0
#define REP 0x2 /* Handshake MDMA Request Polarity */
-#define nREP 0x0
#define UTE 0x8 /* Urgency Threshold Enable */
-#define nUTE 0x0
#define OIE 0x10 /* Overflow Interrupt Enable */
-#define nOIE 0x0
#define BDIE 0x20 /* Block Done Interrupt Enable */
-#define nBDIE 0x0
#define MBDI 0x40 /* Mask Block Done Interrupt */
-#define nMBDI 0x0
#define DRQ 0x300 /* Handshake MDMA Request Type */
#define RBC 0x1000 /* Force Reload of BCOUNT */
-#define nRBC 0x0
#define PS 0x2000 /* Pin Status */
-#define nPS 0x0
#define OI 0x4000 /* Overflow Interrupt Generated */
-#define nOI 0x0
#define BDI 0x8000 /* Block Done Interrupt Generated */
-#define nBDI 0x0
/* ******************************************* */
/* MULTI BIT MACRO ENUMERATIONS */
diff --git a/include/asm-blackfin/mach-bf548/defBF549.h b/include/asm-blackfin/mach-bf548/defBF549.h
index b1cc1c073b41..c2f4734da48d 100644
--- a/include/asm-blackfin/mach-bf548/defBF549.h
+++ b/include/asm-blackfin/mach-bf548/defBF549.h
@@ -1070,21 +1070,13 @@
/* Bit masks for PIXC_CTL */
#define PIXC_EN 0x1 /* Pixel Compositor Enable */
-#define nPIXC_EN 0x0
#define OVR_A_EN 0x2 /* Overlay A Enable */
-#define nOVR_A_EN 0x0
#define OVR_B_EN 0x4 /* Overlay B Enable */
-#define nOVR_B_EN 0x0
#define IMG_FORM 0x8 /* Image Data Format */
-#define nIMG_FORM 0x0
#define OVR_FORM 0x10 /* Overlay Data Format */
-#define nOVR_FORM 0x0
#define OUT_FORM 0x20 /* Output Data Format */
-#define nOUT_FORM 0x0
#define UDS_MOD 0x40 /* Resampling Mode */
-#define nUDS_MOD 0x0
#define TC_EN 0x80 /* Transparent Color Enable */
-#define nTC_EN 0x0
#define IMG_STAT 0x300 /* Image FIFO Status */
#define OVR_STAT 0xc00 /* Overlay FIFO Status */
#define WM_LVL 0x3000 /* FIFO Watermark Level */
@@ -1132,13 +1124,9 @@
/* Bit masks for PIXC_INTRSTAT */
#define OVR_INT_EN 0x1 /* Interrupt at End of Last Valid Overlay */
-#define nOVR_INT_EN 0x0
#define FRM_INT_EN 0x2 /* Interrupt at End of Frame */
-#define nFRM_INT_EN 0x0
#define OVR_INT_STAT 0x4 /* Overlay Interrupt Status */
-#define nOVR_INT_STAT 0x0
#define FRM_INT_STAT 0x8 /* Frame Interrupt Status */
-#define nFRM_INT_STAT 0x0
/* Bit masks for PIXC_RYCON */
@@ -1146,7 +1134,6 @@
#define A12 0xffc00 /* A12 in the Coefficient Matrix */
#define A13 0x3ff00000 /* A13 in the Coefficient Matrix */
#define RY_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nRY_MULT4 0x0
/* Bit masks for PIXC_GUCON */
@@ -1154,7 +1141,6 @@
#define A22 0xffc00 /* A22 in the Coefficient Matrix */
#define A23 0x3ff00000 /* A23 in the Coefficient Matrix */
#define GU_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nGU_MULT4 0x0
/* Bit masks for PIXC_BVCON */
@@ -1162,7 +1148,6 @@
#define A32 0xffc00 /* A32 in the Coefficient Matrix */
#define A33 0x3ff00000 /* A33 in the Coefficient Matrix */
#define BV_MULT4 0x40000000 /* Multiply Row by 4 */
-#define nBV_MULT4 0x0
/* Bit masks for PIXC_CCBIAS */
@@ -1179,48 +1164,28 @@
/* Bit masks for HOST_CONTROL */
#define HOST_EN 0x1 /* Host Enable */
-#define nHOST_EN 0x0
#define HOST_END 0x2 /* Host Endianess */
-#define nHOST_END 0x0
#define DATA_SIZE 0x4 /* Data Size */
-#define nDATA_SIZE 0x0
#define HOST_RST 0x8 /* Host Reset */
-#define nHOST_RST 0x0
#define HRDY_OVR 0x20 /* Host Ready Override */
-#define nHRDY_OVR 0x0
#define INT_MODE 0x40 /* Interrupt Mode */
-#define nINT_MODE 0x0
#define BT_EN 0x80 /* Bus Timeout Enable */
-#define nBT_EN 0x0
#define EHW 0x100 /* Enable Host Write */
-#define nEHW 0x0
#define EHR 0x200 /* Enable Host Read */
-#define nEHR 0x0
#define BDR 0x400 /* Burst DMA Requests */
-#define nBDR 0x0
/* Bit masks for HOST_STATUS */
#define READY 0x1 /* DMA Ready */
-#define nREADY 0x0
#define FIFOFULL 0x2 /* FIFO Full */
-#define nFIFOFULL 0x0
#define FIFOEMPTY 0x4 /* FIFO Empty */
-#define nFIFOEMPTY 0x0
-#define COMPLETE 0x8 /* DMA Complete */
-#define nCOMPLETE 0x0
+#define DMA_COMPLETE 0x8 /* DMA Complete */
#define HSHK 0x10 /* Host Handshake */
-#define nHSHK 0x0
#define TIMEOUT 0x20 /* Host Timeout */
-#define nTIMEOUT 0x0
#define HIRQ 0x40 /* Host Interrupt Request */
-#define nHIRQ 0x0
#define ALLOW_CNFG 0x80 /* Allow New Configuration */
-#define nALLOW_CNFG 0x0
#define DMA_DIR 0x100 /* DMA Direction */
-#define nDMA_DIR 0x0
#define BTE 0x200 /* Bus Timeout Enabled */
-#define nBTE 0x0
/* Bit masks for HOST_TIMEOUT */
@@ -1229,71 +1194,41 @@
/* Bit masks for MXVR_CONFIG */
#define MXVREN 0x1 /* MXVR Enable */
-#define nMXVREN 0x0
#define MMSM 0x2 /* MXVR Master/Slave Mode Select */
-#define nMMSM 0x0
#define ACTIVE 0x4 /* Active Mode */
-#define nACTIVE 0x0
#define SDELAY 0x8 /* Synchronous Data Delay */
-#define nSDELAY 0x0
#define NCMRXEN 0x10 /* Normal Control Message Receive Enable */
-#define nNCMRXEN 0x0
#define RWRRXEN 0x20 /* Remote Write Receive Enable */
-#define nRWRRXEN 0x0
#define MTXEN 0x40 /* MXVR Transmit Data Enable */
-#define nMTXEN 0x0
#define MTXONB 0x80 /* MXVR Phy Transmitter On */
-#define nMTXONB 0x0
#define EPARITY 0x100 /* Even Parity Select */
-#define nEPARITY 0x0
#define MSB 0x1e00 /* Master Synchronous Boundary */
#define APRXEN 0x2000 /* Asynchronous Packet Receive Enable */
-#define nAPRXEN 0x0
#define WAKEUP 0x4000 /* Wake-Up */
-#define nWAKEUP 0x0
#define LMECH 0x8000 /* Lock Mechanism Select */
-#define nLMECH 0x0
/* Bit masks for MXVR_STATE_0 */
#define NACT 0x1 /* Network Activity */
-#define nNACT 0x0
#define SBLOCK 0x2 /* Super Block Lock */
-#define nSBLOCK 0x0
#define FMPLLST 0xc /* Frequency Multiply PLL SM State */
#define CDRPLLST 0xe0 /* Clock/Data Recovery PLL SM State */
#define APBSY 0x100 /* Asynchronous Packet Transmit Buffer Busy */
-#define nAPBSY 0x0
#define APARB 0x200 /* Asynchronous Packet Arbitrating */
-#define nAPARB 0x0
#define APTX 0x400 /* Asynchronous Packet Transmitting */
-#define nAPTX 0x0
#define APRX 0x800 /* Receiving Asynchronous Packet */
-#define nAPRX 0x0
#define CMBSY 0x1000 /* Control Message Transmit Buffer Busy */
-#define nCMBSY 0x0
#define CMARB 0x2000 /* Control Message Arbitrating */
-#define nCMARB 0x0
#define CMTX 0x4000 /* Control Message Transmitting */
-#define nCMTX 0x0
#define CMRX 0x8000 /* Receiving Control Message */
-#define nCMRX 0x0
#define MRXONB 0x10000 /* MRXONB Pin State */
-#define nMRXONB 0x0
#define RGSIP 0x20000 /* Remote Get Source In Progress */
-#define nRGSIP 0x0
#define DALIP 0x40000 /* Resource Deallocate In Progress */
-#define nDALIP 0x0
#define ALIP 0x80000 /* Resource Allocate In Progress */
-#define nALIP 0x0
#define RRDIP 0x100000 /* Remote Read In Progress */
-#define nRRDIP 0x0
#define RWRIP 0x200000 /* Remote Write In Progress */
-#define nRWRIP 0x0
#define FLOCK 0x400000 /* Frame Lock */
-#define nFLOCK 0x0
#define BLOCK 0x800000 /* Block Lock */
-#define nBLOCK 0x0
#define RSB 0xf000000 /* Received Synchronous Boundary */
#define DERRNUM 0xf0000000 /* DMA Error Channel Number */
@@ -1302,535 +1237,343 @@
#define SRXNUMB 0xf /* Synchronous Receive FIFO Number of Bytes */
#define STXNUMB 0xf0 /* Synchronous Transmit FIFO Number of Bytes */
#define APCONT 0x100 /* Asynchronous Packet Continuation */
-#define nAPCONT 0x0
#define OBERRNUM 0xe00 /* DMA Out of Bounds Error Channel Number */
#define DMAACTIVE0 0x10000 /* DMA0 Active */
-#define nDMAACTIVE0 0x0
#define DMAACTIVE1 0x20000 /* DMA1 Active */
-#define nDMAACTIVE1 0x0
#define DMAACTIVE2 0x40000 /* DMA2 Active */
-#define nDMAACTIVE2 0x0
#define DMAACTIVE3 0x80000 /* DMA3 Active */
-#define nDMAACTIVE3 0x0
#define DMAACTIVE4 0x100000 /* DMA4 Active */
-#define nDMAACTIVE4 0x0
#define DMAACTIVE5 0x200000 /* DMA5 Active */
-#define nDMAACTIVE5 0x0
#define DMAACTIVE6 0x400000 /* DMA6 Active */
-#define nDMAACTIVE6 0x0
#define DMAACTIVE7 0x800000 /* DMA7 Active */
-#define nDMAACTIVE7 0x0
#define DMAPMEN0 0x1000000 /* DMA0 Pattern Matching Enabled */
-#define nDMAPMEN0 0x0
#define DMAPMEN1 0x2000000 /* DMA1 Pattern Matching Enabled */
-#define nDMAPMEN1 0x0
#define DMAPMEN2 0x4000000 /* DMA2 Pattern Matching Enabled */
-#define nDMAPMEN2 0x0
#define DMAPMEN3 0x8000000 /* DMA3 Pattern Matching Enabled */
-#define nDMAPMEN3 0x0
#define DMAPMEN4 0x10000000 /* DMA4 Pattern Matching Enabled */
-#define nDMAPMEN4 0x0
#define DMAPMEN5 0x20000000 /* DMA5 Pattern Matching Enabled */
-#define nDMAPMEN5 0x0
#define DMAPMEN6 0x40000000 /* DMA6 Pattern Matching Enabled */
-#define nDMAPMEN6 0x0
#define DMAPMEN7 0x80000000 /* DMA7 Pattern Matching Enabled */
-#define nDMAPMEN7 0x0
/* Bit masks for MXVR_INT_STAT_0 */
#define NI2A 0x1 /* Network Inactive to Active */
-#define nNI2A 0x0
#define NA2I 0x2 /* Network Active to Inactive */
-#define nNA2I 0x0
#define SBU2L 0x4 /* Super Block Unlock to Lock */
-#define nSBU2L 0x0
#define SBL2U 0x8 /* Super Block Lock to Unlock */
-#define nSBL2U 0x0
#define PRU 0x10 /* Position Register Updated */
-#define nPRU 0x0
#define MPRU 0x20 /* Maximum Position Register Updated */
-#define nMPRU 0x0
#define DRU 0x40 /* Delay Register Updated */
-#define nDRU 0x0
#define MDRU 0x80 /* Maximum Delay Register Updated */
-#define nMDRU 0x0
#define SBU 0x100 /* Synchronous Boundary Updated */
-#define nSBU 0x0
#define ATU 0x200 /* Allocation Table Updated */
-#define nATU 0x0
#define FCZ0 0x400 /* Frame Counter 0 Zero */
-#define nFCZ0 0x0
#define FCZ1 0x800 /* Frame Counter 1 Zero */
-#define nFCZ1 0x0
#define PERR 0x1000 /* Parity Error */
-#define nPERR 0x0
#define MH2L 0x2000 /* MRXONB High to Low */
-#define nMH2L 0x0
#define ML2H 0x4000 /* MRXONB Low to High */
-#define nML2H 0x0
#define WUP 0x8000 /* Wake-Up Preamble Received */
-#define nWUP 0x0
#define FU2L 0x10000 /* Frame Unlock to Lock */
-#define nFU2L 0x0
#define FL2U 0x20000 /* Frame Lock to Unlock */
-#define nFL2U 0x0
#define BU2L 0x40000 /* Block Unlock to Lock */
-#define nBU2L 0x0
#define BL2U 0x80000 /* Block Lock to Unlock */
-#define nBL2U 0x0
#define OBERR 0x100000 /* DMA Out of Bounds Error */
-#define nOBERR 0x0
#define PFL 0x200000 /* PLL Frequency Locked */
-#define nPFL 0x0
#define SCZ 0x400000 /* System Clock Counter Zero */
-#define nSCZ 0x0
#define FERR 0x800000 /* FIFO Error */
-#define nFERR 0x0
#define CMR 0x1000000 /* Control Message Received */
-#define nCMR 0x0
#define CMROF 0x2000000 /* Control Message Receive Buffer Overflow */
-#define nCMROF 0x0
#define CMTS 0x4000000 /* Control Message Transmit Buffer Successfully Sent */
-#define nCMTS 0x0
#define CMTC 0x8000000 /* Control Message Transmit Buffer Successfully Cancelled */
-#define nCMTC 0x0
#define RWRC 0x10000000 /* Remote Write Control Message Completed */
-#define nRWRC 0x0
#define BCZ 0x20000000 /* Block Counter Zero */
-#define nBCZ 0x0
#define BMERR 0x40000000 /* Biphase Mark Coding Error */
-#define nBMERR 0x0
#define DERR 0x80000000 /* DMA Error */
-#define nDERR 0x0
/* Bit masks for MXVR_INT_STAT_1 */
#define HDONE0 0x1 /* DMA0 Half Done */
-#define nHDONE0 0x0
#define DONE0 0x2 /* DMA0 Done */
-#define nDONE0 0x0
#define APR 0x4 /* Asynchronous Packet Received */
-#define nAPR 0x0
#define APROF 0x8 /* Asynchronous Packet Receive Buffer Overflow */
-#define nAPROF 0x0
#define HDONE1 0x10 /* DMA1 Half Done */
-#define nHDONE1 0x0
#define DONE1 0x20 /* DMA1 Done */
-#define nDONE1 0x0
#define APTS 0x40 /* Asynchronous Packet Transmit Buffer Successfully Sent */
-#define nAPTS 0x0
#define APTC 0x80 /* Asynchronous Packet Transmit Buffer Successfully Cancelled */
-#define nAPTC 0x0
#define HDONE2 0x100 /* DMA2 Half Done */
-#define nHDONE2 0x0
#define DONE2 0x200 /* DMA2 Done */
-#define nDONE2 0x0
#define APRCE 0x400 /* Asynchronous Packet Receive CRC Error */
-#define nAPRCE 0x0
#define APRPE 0x800 /* Asynchronous Packet Receive Packet Error */
-#define nAPRPE 0x0
#define HDONE3 0x1000 /* DMA3 Half Done */
-#define nHDONE3 0x0
#define DONE3 0x2000 /* DMA3 Done */
-#define nDONE3 0x0
#define HDONE4 0x10000 /* DMA4 Half Done */
-#define nHDONE4 0x0
#define DONE4 0x20000 /* DMA4 Done */
-#define nDONE4 0x0
#define HDONE5 0x100000 /* DMA5 Half Done */
-#define nHDONE5 0x0
#define DONE5 0x200000 /* DMA5 Done */
-#define nDONE5 0x0
#define HDONE6 0x1000000 /* DMA6 Half Done */
-#define nHDONE6 0x0
#define DONE6 0x2000000 /* DMA6 Done */
-#define nDONE6 0x0
#define HDONE7 0x10000000 /* DMA7 Half Done */
-#define nHDONE7 0x0
#define DONE7 0x20000000 /* DMA7 Done */
-#define nDONE7 0x0
/* Bit masks for MXVR_INT_EN_0 */
#define NI2AEN 0x1 /* Network Inactive to Active Interrupt Enable */
-#define nNI2AEN 0x0
#define NA2IEN 0x2 /* Network Active to Inactive Interrupt Enable */
-#define nNA2IEN 0x0
#define SBU2LEN 0x4 /* Super Block Unlock to Lock Interrupt Enable */
-#define nSBU2LEN 0x0
#define SBL2UEN 0x8 /* Super Block Lock to Unlock Interrupt Enable */
-#define nSBL2UEN 0x0
#define PRUEN 0x10 /* Position Register Updated Interrupt Enable */
-#define nPRUEN 0x0
#define MPRUEN 0x20 /* Maximum Position Register Updated Interrupt Enable */
-#define nMPRUEN 0x0
#define DRUEN 0x40 /* Delay Register Updated Interrupt Enable */
-#define nDRUEN 0x0
#define MDRUEN 0x80 /* Maximum Delay Register Updated Interrupt Enable */
-#define nMDRUEN 0x0
#define SBUEN 0x100 /* Synchronous Boundary Updated Interrupt Enable */
-#define nSBUEN 0x0
#define ATUEN 0x200 /* Allocation Table Updated Interrupt Enable */
-#define nATUEN 0x0
#define FCZ0EN 0x400 /* Frame Counter 0 Zero Interrupt Enable */
-#define nFCZ0EN 0x0
#define FCZ1EN 0x800 /* Frame Counter 1 Zero Interrupt Enable */
-#define nFCZ1EN 0x0
#define PERREN 0x1000 /* Parity Error Interrupt Enable */
-#define nPERREN 0x0
#define MH2LEN 0x2000 /* MRXONB High to Low Interrupt Enable */
-#define nMH2LEN 0x0
#define ML2HEN 0x4000 /* MRXONB Low to High Interrupt Enable */
-#define nML2HEN 0x0
#define WUPEN 0x8000 /* Wake-Up Preamble Received Interrupt Enable */
-#define nWUPEN 0x0
#define FU2LEN 0x10000 /* Frame Unlock to Lock Interrupt Enable */
-#define nFU2LEN 0x0
#define FL2UEN 0x20000 /* Frame Lock to Unlock Interrupt Enable */
-#define nFL2UEN 0x0
#define BU2LEN 0x40000 /* Block Unlock to Lock Interrupt Enable */
-#define nBU2LEN 0x0
#define BL2UEN 0x80000 /* Block Lock to Unlock Interrupt Enable */
-#define nBL2UEN 0x0
#define OBERREN 0x100000 /* DMA Out of Bounds Error Interrupt Enable */
-#define nOBERREN 0x0
#define PFLEN 0x200000 /* PLL Frequency Locked Interrupt Enable */
-#define nPFLEN 0x0
#define SCZEN 0x400000 /* System Clock Counter Zero Interrupt Enable */
-#define nSCZEN 0x0
#define FERREN 0x800000 /* FIFO Error Interrupt Enable */
-#define nFERREN 0x0
#define CMREN 0x1000000 /* Control Message Received Interrupt Enable */
-#define nCMREN 0x0
#define CMROFEN 0x2000000 /* Control Message Receive Buffer Overflow Interrupt Enable */
-#define nCMROFEN 0x0
#define CMTSEN 0x4000000 /* Control Message Transmit Buffer Successfully Sent Interrupt Enable */
-#define nCMTSEN 0x0
#define CMTCEN 0x8000000 /* Control Message Transmit Buffer Successfully Cancelled Interrupt Enable */
-#define nCMTCEN 0x0
#define RWRCEN 0x10000000 /* Remote Write Control Message Completed Interrupt Enable */
-#define nRWRCEN 0x0
#define BCZEN 0x20000000 /* Block Counter Zero Interrupt Enable */
-#define nBCZEN 0x0
#define BMERREN 0x40000000 /* Biphase Mark Coding Error Interrupt Enable */
-#define nBMERREN 0x0
#define DERREN 0x80000000 /* DMA Error Interrupt Enable */
-#define nDERREN 0x0
/* Bit masks for MXVR_INT_EN_1 */
#define HDONEEN0 0x1 /* DMA0 Half Done Interrupt Enable */
-#define nHDONEEN0 0x0
#define DONEEN0 0x2 /* DMA0 Done Interrupt Enable */
-#define nDONEEN0 0x0
#define APREN 0x4 /* Asynchronous Packet Received Interrupt Enable */
-#define nAPREN 0x0
#define APROFEN 0x8 /* Asynchronous Packet Receive Buffer Overflow Interrupt Enable */
-#define nAPROFEN 0x0
#define HDONEEN1 0x10 /* DMA1 Half Done Interrupt Enable */
-#define nHDONEEN1 0x0
#define DONEEN1 0x20 /* DMA1 Done Interrupt Enable */
-#define nDONEEN1 0x0
#define APTSEN 0x40 /* Asynchronous Packet Transmit Buffer Successfully Sent Interrupt Enable */
-#define nAPTSEN 0x0
#define APTCEN 0x80 /* Asynchronous Packet Transmit Buffer Successfully Cancelled Interrupt Enable */
-#define nAPTCEN 0x0
#define HDONEEN2 0x100 /* DMA2 Half Done Interrupt Enable */
-#define nHDONEEN2 0x0
#define DONEEN2 0x200 /* DMA2 Done Interrupt Enable */
-#define nDONEEN2 0x0
#define APRCEEN 0x400 /* Asynchronous Packet Receive CRC Error Interrupt Enable */
-#define nAPRCEEN 0x0
#define APRPEEN 0x800 /* Asynchronous Packet Receive Packet Error Interrupt Enable */
-#define nAPRPEEN 0x0
#define HDONEEN3 0x1000 /* DMA3 Half Done Interrupt Enable */
-#define nHDONEEN3 0x0
#define DONEEN3 0x2000 /* DMA3 Done Interrupt Enable */
-#define nDONEEN3 0x0
#define HDONEEN4 0x10000 /* DMA4 Half Done Interrupt Enable */
-#define nHDONEEN4 0x0
#define DONEEN4 0x20000 /* DMA4 Done Interrupt Enable */
-#define nDONEEN4 0x0
#define HDONEEN5 0x100000 /* DMA5 Half Done Interrupt Enable */
-#define nHDONEEN5 0x0
#define DONEEN5 0x200000 /* DMA5 Done Interrupt Enable */
-#define nDONEEN5 0x0
#define HDONEEN6 0x1000000 /* DMA6 Half Done Interrupt Enable */
-#define nHDONEEN6 0x0
#define DONEEN6 0x2000000 /* DMA6 Done Interrupt Enable */
-#define nDONEEN6 0x0
#define HDONEEN7 0x10000000 /* DMA7 Half Done Interrupt Enable */
-#define nHDONEEN7 0x0
#define DONEEN7 0x20000000 /* DMA7 Done Interrupt Enable */
-#define nDONEEN7 0x0
/* Bit masks for MXVR_POSITION */
#define POSITION 0x3f /* Node Position */
#define PVALID 0x8000 /* Node Position Valid */
-#define nPVALID 0x0
/* Bit masks for MXVR_MAX_POSITION */
#define MPOSITION 0x3f /* Maximum Node Position */
#define MPVALID 0x8000 /* Maximum Node Position Valid */
-#define nMPVALID 0x0
/* Bit masks for MXVR_DELAY */
#define DELAY 0x3f /* Node Frame Delay */
#define DVALID 0x8000 /* Node Frame Delay Valid */
-#define nDVALID 0x0
/* Bit masks for MXVR_MAX_DELAY */
#define MDELAY 0x3f /* Maximum Node Frame Delay */
#define MDVALID 0x8000 /* Maximum Node Frame Delay Valid */
-#define nMDVALID 0x0
/* Bit masks for MXVR_LADDR */
#define LADDR 0xffff /* Logical Address */
#define LVALID 0x80000000 /* Logical Address Valid */
-#define nLVALID 0x0
/* Bit masks for MXVR_GADDR */
#define GADDRL 0xff /* Group Address Lower Byte */
#define GVALID 0x8000 /* Group Address Valid */
-#define nGVALID 0x0
/* Bit masks for MXVR_AADDR */
#define AADDR 0xffff /* Alternate Address */
#define AVALID 0x80000000 /* Alternate Address Valid */
-#define nAVALID 0x0
/* Bit masks for MXVR_ALLOC_0 */
#define CL0 0x7f /* Channel 0 Connection Label */
#define CIU0 0x80 /* Channel 0 In Use */
-#define nCIU0 0x0
#define CL1 0x7f00 /* Channel 0 Connection Label */
#define CIU1 0x8000 /* Channel 0 In Use */
-#define nCIU1 0x0
#define CL2 0x7f0000 /* Channel 0 Connection Label */
#define CIU2 0x800000 /* Channel 0 In Use */
-#define nCIU2 0x0
#define CL3 0x7f000000 /* Channel 0 Connection Label */
#define CIU3 0x80000000 /* Channel 0 In Use */
-#define nCIU3 0x0
/* Bit masks for MXVR_ALLOC_1 */
#define CL4 0x7f /* Channel 4 Connection Label */
#define CIU4 0x80 /* Channel 4 In Use */
-#define nCIU4 0x0
#define CL5 0x7f00 /* Channel 5 Connection Label */
#define CIU5 0x8000 /* Channel 5 In Use */
-#define nCIU5 0x0
#define CL6 0x7f0000 /* Channel 6 Connection Label */
#define CIU6 0x800000 /* Channel 6 In Use */
-#define nCIU6 0x0
#define CL7 0x7f000000 /* Channel 7 Connection Label */
#define CIU7 0x80000000 /* Channel 7 In Use */
-#define nCIU7 0x0
/* Bit masks for MXVR_ALLOC_2 */
#define CL8 0x7f /* Channel 8 Connection Label */
#define CIU8 0x80 /* Channel 8 In Use */
-#define nCIU8 0x0
#define CL9 0x7f00 /* Channel 9 Connection Label */
#define CIU9 0x8000 /* Channel 9 In Use */
-#define nCIU9 0x0
#define CL10 0x7f0000 /* Channel 10 Connection Label */
#define CIU10 0x800000 /* Channel 10 In Use */
-#define nCIU10 0x0
#define CL11 0x7f000000 /* Channel 11 Connection Label */
#define CIU11 0x80000000 /* Channel 11 In Use */
-#define nCIU11 0x0
/* Bit masks for MXVR_ALLOC_3 */
#define CL12 0x7f /* Channel 12 Connection Label */
#define CIU12 0x80 /* Channel 12 In Use */
-#define nCIU12 0x0
#define CL13 0x7f00 /* Channel 13 Connection Label */
#define CIU13 0x8000 /* Channel 13 In Use */
-#define nCIU13 0x0
#define CL14 0x7f0000 /* Channel 14 Connection Label */
#define CIU14 0x800000 /* Channel 14 In Use */
-#define nCIU14 0x0
#define CL15 0x7f000000 /* Channel 15 Connection Label */
#define CIU15 0x80000000 /* Channel 15 In Use */
-#define nCIU15 0x0
/* Bit masks for MXVR_ALLOC_4 */
#define CL16 0x7f /* Channel 16 Connection Label */
#define CIU16 0x80 /* Channel 16 In Use */
-#define nCIU16 0x0
#define CL17 0x7f00 /* Channel 17 Connection Label */
#define CIU17 0x8000 /* Channel 17 In Use */
-#define nCIU17 0x0
#define CL18 0x7f0000 /* Channel 18 Connection Label */
#define CIU18 0x800000 /* Channel 18 In Use */
-#define nCIU18 0x0
#define CL19 0x7f000000 /* Channel 19 Connection Label */
#define CIU19 0x80000000 /* Channel 19 In Use */
-#define nCIU19 0x0
/* Bit masks for MXVR_ALLOC_5 */
#define CL20 0x7f /* Channel 20 Connection Label */
#define CIU20 0x80 /* Channel 20 In Use */
-#define nCIU20 0x0
#define CL21 0x7f00 /* Channel 21 Connection Label */
#define CIU21 0x8000 /* Channel 21 In Use */
-#define nCIU21 0x0
#define CL22 0x7f0000 /* Channel 22 Connection Label */
#define CIU22 0x800000 /* Channel 22 In Use */
-#define nCIU22 0x0
#define CL23 0x7f000000 /* Channel 23 Connection Label */
#define CIU23 0x80000000 /* Channel 23 In Use */
-#define nCIU23 0x0
/* Bit masks for MXVR_ALLOC_6 */
#define CL24 0x7f /* Channel 24 Connection Label */
#define CIU24 0x80 /* Channel 24 In Use */
-#define nCIU24 0x0
#define CL25 0x7f00 /* Channel 25 Connection Label */
#define CIU25 0x8000 /* Channel 25 In Use */
-#define nCIU25 0x0
#define CL26 0x7f0000 /* Channel 26 Connection Label */
#define CIU26 0x800000 /* Channel 26 In Use */
-#define nCIU26 0x0
#define CL27 0x7f000000 /* Channel 27 Connection Label */
#define CIU27 0x80000000 /* Channel 27 In Use */
-#define nCIU27 0x0
/* Bit masks for MXVR_ALLOC_7 */
#define CL28 0x7f /* Channel 28 Connection Label */
#define CIU28 0x80 /* Channel 28 In Use */
-#define nCIU28 0x0
#define CL29 0x7f00 /* Channel 29 Connection Label */
#define CIU29 0x8000 /* Channel 29 In Use */
-#define nCIU29 0x0
#define CL30 0x7f0000 /* Channel 30 Connection Label */
#define CIU30 0x800000 /* Channel 30 In Use */
-#define nCIU30 0x0
#define CL31 0x7f000000 /* Channel 31 Connection Label */
#define CIU31 0x80000000 /* Channel 31 In Use */
-#define nCIU31 0x0
/* Bit masks for MXVR_ALLOC_8 */
#define CL32 0x7f /* Channel 32 Connection Label */
#define CIU32 0x80 /* Channel 32 In Use */
-#define nCIU32 0x0
#define CL33 0x7f00 /* Channel 33 Connection Label */
#define CIU33 0x8000 /* Channel 33 In Use */
-#define nCIU33 0x0
#define CL34 0x7f0000 /* Channel 34 Connection Label */
#define CIU34 0x800000 /* Channel 34 In Use */
-#define nCIU34 0x0
#define CL35 0x7f000000 /* Channel 35 Connection Label */
#define CIU35 0x80000000 /* Channel 35 In Use */
-#define nCIU35 0x0
/* Bit masks for MXVR_ALLOC_9 */
#define CL36 0x7f /* Channel 36 Connection Label */
#define CIU36 0x80 /* Channel 36 In Use */
-#define nCIU36 0x0
#define CL37 0x7f00 /* Channel 37 Connection Label */
#define CIU37 0x8000 /* Channel 37 In Use */
-#define nCIU37 0x0
#define CL38 0x7f0000 /* Channel 38 Connection Label */
#define CIU38 0x800000 /* Channel 38 In Use */
-#define nCIU38 0x0
#define CL39 0x7f000000 /* Channel 39 Connection Label */
#define CIU39 0x80000000 /* Channel 39 In Use */
-#define nCIU39 0x0
/* Bit masks for MXVR_ALLOC_10 */
#define CL40 0x7f /* Channel 40 Connection Label */
#define CIU40 0x80 /* Channel 40 In Use */
-#define nCIU40 0x0
#define CL41 0x7f00 /* Channel 41 Connection Label */
#define CIU41 0x8000 /* Channel 41 In Use */
-#define nCIU41 0x0
#define CL42 0x7f0000 /* Channel 42 Connection Label */
#define CIU42 0x800000 /* Channel 42 In Use */
-#define nCIU42 0x0
#define CL43 0x7f000000 /* Channel 43 Connection Label */
#define CIU43 0x80000000 /* Channel 43 In Use */
-#define nCIU43 0x0
/* Bit masks for MXVR_ALLOC_11 */
#define CL44 0x7f /* Channel 44 Connection Label */
#define CIU44 0x80 /* Channel 44 In Use */
-#define nCIU44 0x0
#define CL45 0x7f00 /* Channel 45 Connection Label */
#define CIU45 0x8000 /* Channel 45 In Use */
-#define nCIU45 0x0
#define CL46 0x7f0000 /* Channel 46 Connection Label */
#define CIU46 0x800000 /* Channel 46 In Use */
-#define nCIU46 0x0
#define CL47 0x7f000000 /* Channel 47 Connection Label */
#define CIU47 0x80000000 /* Channel 47 In Use */
-#define nCIU47 0x0
/* Bit masks for MXVR_ALLOC_12 */
#define CL48 0x7f /* Channel 48 Connection Label */
#define CIU48 0x80 /* Channel 48 In Use */
-#define nCIU48 0x0
#define CL49 0x7f00 /* Channel 49 Connection Label */
#define CIU49 0x8000 /* Channel 49 In Use */
-#define nCIU49 0x0
#define CL50 0x7f0000 /* Channel 50 Connection Label */
#define CIU50 0x800000 /* Channel 50 In Use */
-#define nCIU50 0x0
#define CL51 0x7f000000 /* Channel 51 Connection Label */
#define CIU51 0x80000000 /* Channel 51 In Use */
-#define nCIU51 0x0
/* Bit masks for MXVR_ALLOC_13 */
#define CL52 0x7f /* Channel 52 Connection Label */
#define CIU52 0x80 /* Channel 52 In Use */
-#define nCIU52 0x0
#define CL53 0x7f00 /* Channel 53 Connection Label */
#define CIU53 0x8000 /* Channel 53 In Use */
-#define nCIU53 0x0
#define CL54 0x7f0000 /* Channel 54 Connection Label */
#define CIU54 0x800000 /* Channel 54 In Use */
-#define nCIU54 0x0
#define CL55 0x7f000000 /* Channel 55 Connection Label */
#define CIU55 0x80000000 /* Channel 55 In Use */
-#define nCIU55 0x0
/* Bit masks for MXVR_ALLOC_14 */
#define CL56 0x7f /* Channel 56 Connection Label */
#define CIU56 0x80 /* Channel 56 In Use */
-#define nCIU56 0x0
#define CL57 0x7f00 /* Channel 57 Connection Label */
#define CIU57 0x8000 /* Channel 57 In Use */
-#define nCIU57 0x0
#define CL58 0x7f0000 /* Channel 58 Connection Label */
#define CIU58 0x800000 /* Channel 58 In Use */
-#define nCIU58 0x0
#define CL59 0x7f000000 /* Channel 59 Connection Label */
#define CIU59 0x80000000 /* Channel 59 In Use */
-#define nCIU59 0x0
/* MXVR_SYNC_LCHAN_0 Masks */
@@ -1926,19 +1669,13 @@
/* Bit masks for MXVR_DMAx_CONFIG */
#define MDMAEN 0x1 /* DMA Channel Enable */
-#define nMDMAEN 0x0
#define DD 0x2 /* DMA Channel Direction */
-#define nDD 0x0
#define BY4SWAPEN 0x20 /* DMA Channel Four Byte Swap Enable */
-#define nBY4SWAPEN 0x0
#define LCHAN 0x3c0 /* DMA Channel Logical Channel */
#define BITSWAPEN 0x400 /* DMA Channel Bit Swap Enable */
-#define nBITSWAPEN 0x0
#define BY2SWAPEN 0x800 /* DMA Channel Two Byte Swap Enable */
-#define nBY2SWAPEN 0x0
#define MFLOW 0x7000 /* DMA Channel Operation Flow */
#define FIXEDPM 0x80000 /* DMA Channel Fixed Pattern Matching Select */
-#define nFIXEDPM 0x0
#define STARTPAT 0x300000 /* DMA Channel Start Pattern Select */
#define STOPPAT 0xc00000 /* DMA Channel Stop Pattern Select */
#define COUNTPOS 0x1c000000 /* DMA Channel Count Position */
@@ -1946,94 +1683,71 @@
/* Bit masks for MXVR_AP_CTL */
#define STARTAP 0x1 /* Start Asynchronous Packet Transmission */
-#define nSTARTAP 0x0
#define CANCELAP 0x2 /* Cancel Asynchronous Packet Transmission */
-#define nCANCELAP 0x0
#define RESETAP 0x4 /* Reset Asynchronous Packet Arbitration */
-#define nRESETAP 0x0
#define APRBE0 0x4000 /* Asynchronous Packet Receive Buffer Entry 0 */
-#define nAPRBE0 0x0
#define APRBE1 0x8000 /* Asynchronous Packet Receive Buffer Entry 1 */
-#define nAPRBE1 0x0
/* Bit masks for MXVR_APRB_START_ADDR */
-#define MXVR_APRB_START_ADDR 0x1fffffe /* Asynchronous Packet Receive Buffer Start Address */
+#define MXVR_APRB_START_ADDR_MASK 0x1fffffe /* Asynchronous Packet Receive Buffer Start Address */
/* Bit masks for MXVR_APRB_CURR_ADDR */
-#define MXVR_APRB_CURR_ADDR 0xffffffff /* Asynchronous Packet Receive Buffer Current Address */
+#define MXVR_APRB_CURR_ADDR_MASK 0xffffffff /* Asynchronous Packet Receive Buffer Current Address */
/* Bit masks for MXVR_APTB_START_ADDR */
-#define MXVR_APTB_START_ADDR 0x1fffffe /* Asynchronous Packet Transmit Buffer Start Address */
+#define MXVR_APTB_START_ADDR_MASK 0x1fffffe /* Asynchronous Packet Transmit Buffer Start Address */
/* Bit masks for MXVR_APTB_CURR_ADDR */
-#define MXVR_APTB_CURR_ADDR 0xffffffff /* Asynchronous Packet Transmit Buffer Current Address */
+#define MXVR_APTB_CURR_ADDR_MASK 0xffffffff /* Asynchronous Packet Transmit Buffer Current Address */
/* Bit masks for MXVR_CM_CTL */
#define STARTCM 0x1 /* Start Control Message Transmission */
-#define nSTARTCM 0x0
#define CANCELCM 0x2 /* Cancel Control Message Transmission */
-#define nCANCELCM 0x0
#define CMRBE0 0x10000 /* Control Message Receive Buffer Entry 0 */
-#define nCMRBE0 0x0
#define CMRBE1 0x20000 /* Control Message Receive Buffer Entry 1 */
-#define nCMRBE1 0x0
#define CMRBE2 0x40000 /* Control Message Receive Buffer Entry 2 */
-#define nCMRBE2 0x0
#define CMRBE3 0x80000 /* Control Message Receive Buffer Entry 3 */
-#define nCMRBE3 0x0
#define CMRBE4 0x100000 /* Control Message Receive Buffer Entry 4 */
-#define nCMRBE4 0x0
#define CMRBE5 0x200000 /* Control Message Receive Buffer Entry 5 */
-#define nCMRBE5 0x0
#define CMRBE6 0x400000 /* Control Message Receive Buffer Entry 6 */
-#define nCMRBE6 0x0
#define CMRBE7 0x800000 /* Control Message Receive Buffer Entry 7 */
-#define nCMRBE7 0x0
#define CMRBE8 0x1000000 /* Control Message Receive Buffer Entry 8 */
-#define nCMRBE8 0x0
#define CMRBE9 0x2000000 /* Control Message Receive Buffer Entry 9 */
-#define nCMRBE9 0x0
#define CMRBE10 0x4000000 /* Control Message Receive Buffer Entry 10 */
-#define nCMRBE10 0x0
#define CMRBE11 0x8000000 /* Control Message Receive Buffer Entry 11 */
-#define nCMRBE11 0x0
#define CMRBE12 0x10000000 /* Control Message Receive Buffer Entry 12 */
-#define nCMRBE12 0x0
#define CMRBE13 0x20000000 /* Control Message Receive Buffer Entry 13 */
-#define nCMRBE13 0x0
#define CMRBE14 0x40000000 /* Control Message Receive Buffer Entry 14 */
-#define nCMRBE14 0x0
#define CMRBE15 0x80000000 /* Control Message Receive Buffer Entry 15 */
-#define nCMRBE15 0x0
/* Bit masks for MXVR_CMRB_START_ADDR */
-#define MXVR_CMRB_START_ADDR 0x1fffffe /* Control Message Receive Buffer Start Address */
+#define MXVR_CMRB_START_ADDR_MASK 0x1fffffe /* Control Message Receive Buffer Start Address */
/* Bit masks for MXVR_CMRB_CURR_ADDR */
-#define MXVR_CMRB_CURR_ADDR 0xffffffff /* Control Message Receive Buffer Current Address */
+#define MXVR_CMRB_CURR_ADDR_MASK 0xffffffff /* Control Message Receive Buffer Current Address */
/* Bit masks for MXVR_CMTB_START_ADDR */
-#define MXVR_CMTB_START_ADDR 0x1fffffe /* Control Message Transmit Buffer Start Address */
+#define MXVR_CMTB_START_ADDR_MASK 0x1fffffe /* Control Message Transmit Buffer Start Address */
/* Bit masks for MXVR_CMTB_CURR_ADDR */
-#define MXVR_CMTB_CURR_ADDR 0xffffffff /* Control Message Transmit Buffer Current Address */
+#define MXVR_CMTB_CURR_ADDR_MASK 0xffffffff /* Control Message Transmit Buffer Current Address */
/* Bit masks for MXVR_RRDB_START_ADDR */
-#define MXVR_RRDB_START_ADDR 0x1fffffe /* Remote Read Buffer Start Address */
+#define MXVR_RRDB_START_ADDR_MASK 0x1fffffe /* Remote Read Buffer Start Address */
/* Bit masks for MXVR_RRDB_CURR_ADDR */
-#define MXVR_RRDB_CURR_ADDR 0xffffffff /* Remote Read Buffer Current Address */
+#define MXVR_RRDB_CURR_ADDR_MASK 0xffffffff /* Remote Read Buffer Current Address */
/* Bit masks for MXVR_PAT_DATAx */
@@ -2045,136 +1759,72 @@
/* Bit masks for MXVR_PAT_EN_0 */
#define MATCH_EN_0_0 0x1 /* Pattern Match Enable Byte 0 Bit 0 */
-#define nMATCH_EN_0_0 0x0
#define MATCH_EN_0_1 0x2 /* Pattern Match Enable Byte 0 Bit 1 */
-#define nMATCH_EN_0_1 0x0
#define MATCH_EN_0_2 0x4 /* Pattern Match Enable Byte 0 Bit 2 */
-#define nMATCH_EN_0_2 0x0
#define MATCH_EN_0_3 0x8 /* Pattern Match Enable Byte 0 Bit 3 */
-#define nMATCH_EN_0_3 0x0
#define MATCH_EN_0_4 0x10 /* Pattern Match Enable Byte 0 Bit 4 */
-#define nMATCH_EN_0_4 0x0
#define MATCH_EN_0_5 0x20 /* Pattern Match Enable Byte 0 Bit 5 */
-#define nMATCH_EN_0_5 0x0
#define MATCH_EN_0_6 0x40 /* Pattern Match Enable Byte 0 Bit 6 */
-#define nMATCH_EN_0_6 0x0
#define MATCH_EN_0_7 0x80 /* Pattern Match Enable Byte 0 Bit 7 */
-#define nMATCH_EN_0_7 0x0
#define MATCH_EN_1_0 0x100 /* Pattern Match Enable Byte 1 Bit 0 */
-#define nMATCH_EN_1_0 0x0
#define MATCH_EN_1_1 0x200 /* Pattern Match Enable Byte 1 Bit 1 */
-#define nMATCH_EN_1_1 0x0
#define MATCH_EN_1_2 0x400 /* Pattern Match Enable Byte 1 Bit 2 */
-#define nMATCH_EN_1_2 0x0
#define MATCH_EN_1_3 0x800 /* Pattern Match Enable Byte 1 Bit 3 */
-#define nMATCH_EN_1_3 0x0
#define MATCH_EN_1_4 0x1000 /* Pattern Match Enable Byte 1 Bit 4 */
-#define nMATCH_EN_1_4 0x0
#define MATCH_EN_1_5 0x2000 /* Pattern Match Enable Byte 1 Bit 5 */
-#define nMATCH_EN_1_5 0x0
#define MATCH_EN_1_6 0x4000 /* Pattern Match Enable Byte 1 Bit 6 */
-#define nMATCH_EN_1_6 0x0
#define MATCH_EN_1_7 0x8000 /* Pattern Match Enable Byte 1 Bit 7 */
-#define nMATCH_EN_1_7 0x0
#define MATCH_EN_2_0 0x10000 /* Pattern Match Enable Byte 2 Bit 0 */
-#define nMATCH_EN_2_0 0x0
#define MATCH_EN_2_1 0x20000 /* Pattern Match Enable Byte 2 Bit 1 */
-#define nMATCH_EN_2_1 0x0
#define MATCH_EN_2_2 0x40000 /* Pattern Match Enable Byte 2 Bit 2 */
-#define nMATCH_EN_2_2 0x0
#define MATCH_EN_2_3 0x80000 /* Pattern Match Enable Byte 2 Bit 3 */
-#define nMATCH_EN_2_3 0x0
#define MATCH_EN_2_4 0x100000 /* Pattern Match Enable Byte 2 Bit 4 */
-#define nMATCH_EN_2_4 0x0
#define MATCH_EN_2_5 0x200000 /* Pattern Match Enable Byte 2 Bit 5 */
-#define nMATCH_EN_2_5 0x0
#define MATCH_EN_2_6 0x400000 /* Pattern Match Enable Byte 2 Bit 6 */
-#define nMATCH_EN_2_6 0x0
#define MATCH_EN_2_7 0x800000 /* Pattern Match Enable Byte 2 Bit 7 */
-#define nMATCH_EN_2_7 0x0
#define MATCH_EN_3_0 0x1000000 /* Pattern Match Enable Byte 3 Bit 0 */
-#define nMATCH_EN_3_0 0x0
#define MATCH_EN_3_1 0x2000000 /* Pattern Match Enable Byte 3 Bit 1 */
-#define nMATCH_EN_3_1 0x0
#define MATCH_EN_3_2 0x4000000 /* Pattern Match Enable Byte 3 Bit 2 */
-#define nMATCH_EN_3_2 0x0
#define MATCH_EN_3_3 0x8000000 /* Pattern Match Enable Byte 3 Bit 3 */
-#define nMATCH_EN_3_3 0x0
#define MATCH_EN_3_4 0x10000000 /* Pattern Match Enable Byte 3 Bit 4 */
-#define nMATCH_EN_3_4 0x0
#define MATCH_EN_3_5 0x20000000 /* Pattern Match Enable Byte 3 Bit 5 */
-#define nMATCH_EN_3_5 0x0
#define MATCH_EN_3_6 0x40000000 /* Pattern Match Enable Byte 3 Bit 6 */
-#define nMATCH_EN_3_6 0x0
#define MATCH_EN_3_7 0x80000000 /* Pattern Match Enable Byte 3 Bit 7 */
-#define nMATCH_EN_3_7 0x0
/* Bit masks for MXVR_PAT_EN_1 */
#define MATCH_EN_0_0 0x1 /* Pattern Match Enable Byte 0 Bit 0 */
-#define nMATCH_EN_0_0 0x0
#define MATCH_EN_0_1 0x2 /* Pattern Match Enable Byte 0 Bit 1 */
-#define nMATCH_EN_0_1 0x0
#define MATCH_EN_0_2 0x4 /* Pattern Match Enable Byte 0 Bit 2 */
-#define nMATCH_EN_0_2 0x0
#define MATCH_EN_0_3 0x8 /* Pattern Match Enable Byte 0 Bit 3 */
-#define nMATCH_EN_0_3 0x0
#define MATCH_EN_0_4 0x10 /* Pattern Match Enable Byte 0 Bit 4 */
-#define nMATCH_EN_0_4 0x0
#define MATCH_EN_0_5 0x20 /* Pattern Match Enable Byte 0 Bit 5 */
-#define nMATCH_EN_0_5 0x0
#define MATCH_EN_0_6 0x40 /* Pattern Match Enable Byte 0 Bit 6 */
-#define nMATCH_EN_0_6 0x0
#define MATCH_EN_0_7 0x80 /* Pattern Match Enable Byte 0 Bit 7 */
-#define nMATCH_EN_0_7 0x0
#define MATCH_EN_1_0 0x100 /* Pattern Match Enable Byte 1 Bit 0 */
-#define nMATCH_EN_1_0 0x0
#define MATCH_EN_1_1 0x200 /* Pattern Match Enable Byte 1 Bit 1 */
-#define nMATCH_EN_1_1 0x0
#define MATCH_EN_1_2 0x400 /* Pattern Match Enable Byte 1 Bit 2 */
-#define nMATCH_EN_1_2 0x0
#define MATCH_EN_1_3 0x800 /* Pattern Match Enable Byte 1 Bit 3 */
-#define nMATCH_EN_1_3 0x0
#define MATCH_EN_1_4 0x1000 /* Pattern Match Enable Byte 1 Bit 4 */
-#define nMATCH_EN_1_4 0x0
#define MATCH_EN_1_5 0x2000 /* Pattern Match Enable Byte 1 Bit 5 */
-#define nMATCH_EN_1_5 0x0
#define MATCH_EN_1_6 0x4000 /* Pattern Match Enable Byte 1 Bit 6 */
-#define nMATCH_EN_1_6 0x0
#define MATCH_EN_1_7 0x8000 /* Pattern Match Enable Byte 1 Bit 7 */
-#define nMATCH_EN_1_7 0x0
#define MATCH_EN_2_0 0x10000 /* Pattern Match Enable Byte 2 Bit 0 */
-#define nMATCH_EN_2_0 0x0
#define MATCH_EN_2_1 0x20000 /* Pattern Match Enable Byte 2 Bit 1 */
-#define nMATCH_EN_2_1 0x0
#define MATCH_EN_2_2 0x40000 /* Pattern Match Enable Byte 2 Bit 2 */
-#define nMATCH_EN_2_2 0x0
#define MATCH_EN_2_3 0x80000 /* Pattern Match Enable Byte 2 Bit 3 */
-#define nMATCH_EN_2_3 0x0
#define MATCH_EN_2_4 0x100000 /* Pattern Match Enable Byte 2 Bit 4 */
-#define nMATCH_EN_2_4 0x0
#define MATCH_EN_2_5 0x200000 /* Pattern Match Enable Byte 2 Bit 5 */
-#define nMATCH_EN_2_5 0x0
#define MATCH_EN_2_6 0x400000 /* Pattern Match Enable Byte 2 Bit 6 */
-#define nMATCH_EN_2_6 0x0
#define MATCH_EN_2_7 0x800000 /* Pattern Match Enable Byte 2 Bit 7 */
-#define nMATCH_EN_2_7 0x0
#define MATCH_EN_3_0 0x1000000 /* Pattern Match Enable Byte 3 Bit 0 */
-#define nMATCH_EN_3_0 0x0
#define MATCH_EN_3_1 0x2000000 /* Pattern Match Enable Byte 3 Bit 1 */
-#define nMATCH_EN_3_1 0x0
#define MATCH_EN_3_2 0x4000000 /* Pattern Match Enable Byte 3 Bit 2 */
-#define nMATCH_EN_3_2 0x0
#define MATCH_EN_3_3 0x8000000 /* Pattern Match Enable Byte 3 Bit 3 */
-#define nMATCH_EN_3_3 0x0
#define MATCH_EN_3_4 0x10000000 /* Pattern Match Enable Byte 3 Bit 4 */
-#define nMATCH_EN_3_4 0x0
#define MATCH_EN_3_5 0x20000000 /* Pattern Match Enable Byte 3 Bit 5 */
-#define nMATCH_EN_3_5 0x0
#define MATCH_EN_3_6 0x40000000 /* Pattern Match Enable Byte 3 Bit 6 */
-#define nMATCH_EN_3_6 0x0
#define MATCH_EN_3_7 0x80000000 /* Pattern Match Enable Byte 3 Bit 7 */
-#define nMATCH_EN_3_7 0x0
/* Bit masks for MXVR_FRAME_CNT_0 */
@@ -2188,226 +1838,166 @@
#define TX_CH0 0x3f /* Transmit Channel 0 */
#define MUTE_CH0 0x80 /* Mute Channel 0 */
-#define nMUTE_CH0 0x0
#define TX_CH1 0x3f00 /* Transmit Channel 0 */
#define MUTE_CH1 0x8000 /* Mute Channel 0 */
-#define nMUTE_CH1 0x0
#define TX_CH2 0x3f0000 /* Transmit Channel 0 */
#define MUTE_CH2 0x800000 /* Mute Channel 0 */
-#define nMUTE_CH2 0x0
#define TX_CH3 0x3f000000 /* Transmit Channel 0 */
#define MUTE_CH3 0x80000000 /* Mute Channel 0 */
-#define nMUTE_CH3 0x0
/* Bit masks for MXVR_ROUTING_1 */
#define TX_CH4 0x3f /* Transmit Channel 4 */
#define MUTE_CH4 0x80 /* Mute Channel 4 */
-#define nMUTE_CH4 0x0
#define TX_CH5 0x3f00 /* Transmit Channel 5 */
#define MUTE_CH5 0x8000 /* Mute Channel 5 */
-#define nMUTE_CH5 0x0
#define TX_CH6 0x3f0000 /* Transmit Channel 6 */
#define MUTE_CH6 0x800000 /* Mute Channel 6 */
-#define nMUTE_CH6 0x0
#define TX_CH7 0x3f000000 /* Transmit Channel 7 */
#define MUTE_CH7 0x80000000 /* Mute Channel 7 */
-#define nMUTE_CH7 0x0
/* Bit masks for MXVR_ROUTING_2 */
#define TX_CH8 0x3f /* Transmit Channel 8 */
#define MUTE_CH8 0x80 /* Mute Channel 8 */
-#define nMUTE_CH8 0x0
#define TX_CH9 0x3f00 /* Transmit Channel 9 */
#define MUTE_CH9 0x8000 /* Mute Channel 9 */
-#define nMUTE_CH9 0x0
#define TX_CH10 0x3f0000 /* Transmit Channel 10 */
#define MUTE_CH10 0x800000 /* Mute Channel 10 */
-#define nMUTE_CH10 0x0
#define TX_CH11 0x3f000000 /* Transmit Channel 11 */
#define MUTE_CH11 0x80000000 /* Mute Channel 11 */
-#define nMUTE_CH11 0x0
/* Bit masks for MXVR_ROUTING_3 */
#define TX_CH12 0x3f /* Transmit Channel 12 */
#define MUTE_CH12 0x80 /* Mute Channel 12 */
-#define nMUTE_CH12 0x0
#define TX_CH13 0x3f00 /* Transmit Channel 13 */
#define MUTE_CH13 0x8000 /* Mute Channel 13 */
-#define nMUTE_CH13 0x0
#define TX_CH14 0x3f0000 /* Transmit Channel 14 */
#define MUTE_CH14 0x800000 /* Mute Channel 14 */
-#define nMUTE_CH14 0x0
#define TX_CH15 0x3f000000 /* Transmit Channel 15 */
#define MUTE_CH15 0x80000000 /* Mute Channel 15 */
-#define nMUTE_CH15 0x0
/* Bit masks for MXVR_ROUTING_4 */
#define TX_CH16 0x3f /* Transmit Channel 16 */
#define MUTE_CH16 0x80 /* Mute Channel 16 */
-#define nMUTE_CH16 0x0
#define TX_CH17 0x3f00 /* Transmit Channel 17 */
#define MUTE_CH17 0x8000 /* Mute Channel 17 */
-#define nMUTE_CH17 0x0
#define TX_CH18 0x3f0000 /* Transmit Channel 18 */
#define MUTE_CH18 0x800000 /* Mute Channel 18 */
-#define nMUTE_CH18 0x0
#define TX_CH19 0x3f000000 /* Transmit Channel 19 */
#define MUTE_CH19 0x80000000 /* Mute Channel 19 */
-#define nMUTE_CH19 0x0
/* Bit masks for MXVR_ROUTING_5 */
#define TX_CH20 0x3f /* Transmit Channel 20 */
#define MUTE_CH20 0x80 /* Mute Channel 20 */
-#define nMUTE_CH20 0x0
#define TX_CH21 0x3f00 /* Transmit Channel 21 */
#define MUTE_CH21 0x8000 /* Mute Channel 21 */
-#define nMUTE_CH21 0x0
#define TX_CH22 0x3f0000 /* Transmit Channel 22 */
#define MUTE_CH22 0x800000 /* Mute Channel 22 */
-#define nMUTE_CH22 0x0
#define TX_CH23 0x3f000000 /* Transmit Channel 23 */
#define MUTE_CH23 0x80000000 /* Mute Channel 23 */
-#define nMUTE_CH23 0x0
/* Bit masks for MXVR_ROUTING_6 */
#define TX_CH24 0x3f /* Transmit Channel 24 */
#define MUTE_CH24 0x80 /* Mute Channel 24 */
-#define nMUTE_CH24 0x0
#define TX_CH25 0x3f00 /* Transmit Channel 25 */
#define MUTE_CH25 0x8000 /* Mute Channel 25 */
-#define nMUTE_CH25 0x0
#define TX_CH26 0x3f0000 /* Transmit Channel 26 */
#define MUTE_CH26 0x800000 /* Mute Channel 26 */
-#define nMUTE_CH26 0x0
#define TX_CH27 0x3f000000 /* Transmit Channel 27 */
#define MUTE_CH27 0x80000000 /* Mute Channel 27 */
-#define nMUTE_CH27 0x0
/* Bit masks for MXVR_ROUTING_7 */
#define TX_CH28 0x3f /* Transmit Channel 28 */
#define MUTE_CH28 0x80 /* Mute Channel 28 */
-#define nMUTE_CH28 0x0
#define TX_CH29 0x3f00 /* Transmit Channel 29 */
#define MUTE_CH29 0x8000 /* Mute Channel 29 */
-#define nMUTE_CH29 0x0
#define TX_CH30 0x3f0000 /* Transmit Channel 30 */
#define MUTE_CH30 0x800000 /* Mute Channel 30 */
-#define nMUTE_CH30 0x0
#define TX_CH31 0x3f000000 /* Transmit Channel 31 */
#define MUTE_CH31 0x80000000 /* Mute Channel 31 */
-#define nMUTE_CH31 0x0
/* Bit masks for MXVR_ROUTING_8 */
#define TX_CH32 0x3f /* Transmit Channel 32 */
#define MUTE_CH32 0x80 /* Mute Channel 32 */
-#define nMUTE_CH32 0x0
#define TX_CH33 0x3f00 /* Transmit Channel 33 */
#define MUTE_CH33 0x8000 /* Mute Channel 33 */
-#define nMUTE_CH33 0x0
#define TX_CH34 0x3f0000 /* Transmit Channel 34 */
#define MUTE_CH34 0x800000 /* Mute Channel 34 */
-#define nMUTE_CH34 0x0
#define TX_CH35 0x3f000000 /* Transmit Channel 35 */
#define MUTE_CH35 0x80000000 /* Mute Channel 35 */
-#define nMUTE_CH35 0x0
/* Bit masks for MXVR_ROUTING_9 */
#define TX_CH36 0x3f /* Transmit Channel 36 */
#define MUTE_CH36 0x80 /* Mute Channel 36 */
-#define nMUTE_CH36 0x0
#define TX_CH37 0x3f00 /* Transmit Channel 37 */
#define MUTE_CH37 0x8000 /* Mute Channel 37 */
-#define nMUTE_CH37 0x0
#define TX_CH38 0x3f0000 /* Transmit Channel 38 */
#define MUTE_CH38 0x800000 /* Mute Channel 38 */
-#define nMUTE_CH38 0x0
#define TX_CH39 0x3f000000 /* Transmit Channel 39 */
#define MUTE_CH39 0x80000000 /* Mute Channel 39 */
-#define nMUTE_CH39 0x0
/* Bit masks for MXVR_ROUTING_10 */
#define TX_CH40 0x3f /* Transmit Channel 40 */
#define MUTE_CH40 0x80 /* Mute Channel 40 */
-#define nMUTE_CH40 0x0
#define TX_CH41 0x3f00 /* Transmit Channel 41 */
#define MUTE_CH41 0x8000 /* Mute Channel 41 */
-#define nMUTE_CH41 0x0
#define TX_CH42 0x3f0000 /* Transmit Channel 42 */
#define MUTE_CH42 0x800000 /* Mute Channel 42 */
-#define nMUTE_CH42 0x0
#define TX_CH43 0x3f000000 /* Transmit Channel 43 */
#define MUTE_CH43 0x80000000 /* Mute Channel 43 */
-#define nMUTE_CH43 0x0
/* Bit masks for MXVR_ROUTING_11 */
#define TX_CH44 0x3f /* Transmit Channel 44 */
#define MUTE_CH44 0x80 /* Mute Channel 44 */
-#define nMUTE_CH44 0x0
#define TX_CH45 0x3f00 /* Transmit Channel 45 */
#define MUTE_CH45 0x8000 /* Mute Channel 45 */
-#define nMUTE_CH45 0x0
#define TX_CH46 0x3f0000 /* Transmit Channel 46 */
#define MUTE_CH46 0x800000 /* Mute Channel 46 */
-#define nMUTE_CH46 0x0
#define TX_CH47 0x3f000000 /* Transmit Channel 47 */
#define MUTE_CH47 0x80000000 /* Mute Channel 47 */
-#define nMUTE_CH47 0x0
/* Bit masks for MXVR_ROUTING_12 */
#define TX_CH48 0x3f /* Transmit Channel 48 */
#define MUTE_CH48 0x80 /* Mute Channel 48 */
-#define nMUTE_CH48 0x0
#define TX_CH49 0x3f00 /* Transmit Channel 49 */
#define MUTE_CH49 0x8000 /* Mute Channel 49 */
-#define nMUTE_CH49 0x0
#define TX_CH50 0x3f0000 /* Transmit Channel 50 */
#define MUTE_CH50 0x800000 /* Mute Channel 50 */
-#define nMUTE_CH50 0x0
#define TX_CH51 0x3f000000 /* Transmit Channel 51 */
#define MUTE_CH51 0x80000000 /* Mute Channel 51 */
-#define nMUTE_CH51 0x0
/* Bit masks for MXVR_ROUTING_13 */
#define TX_CH52 0x3f /* Transmit Channel 52 */
#define MUTE_CH52 0x80 /* Mute Channel 52 */
-#define nMUTE_CH52 0x0
#define TX_CH53 0x3f00 /* Transmit Channel 53 */
#define MUTE_CH53 0x8000 /* Mute Channel 53 */
-#define nMUTE_CH53 0x0
#define TX_CH54 0x3f0000 /* Transmit Channel 54 */
#define MUTE_CH54 0x800000 /* Mute Channel 54 */
-#define nMUTE_CH54 0x0
#define TX_CH55 0x3f000000 /* Transmit Channel 55 */
#define MUTE_CH55 0x80000000 /* Mute Channel 55 */
-#define nMUTE_CH55 0x0
/* Bit masks for MXVR_ROUTING_14 */
#define TX_CH56 0x3f /* Transmit Channel 56 */
#define MUTE_CH56 0x80 /* Mute Channel 56 */
-#define nMUTE_CH56 0x0
#define TX_CH57 0x3f00 /* Transmit Channel 57 */
#define MUTE_CH57 0x8000 /* Mute Channel 57 */
-#define nMUTE_CH57 0x0
#define TX_CH58 0x3f0000 /* Transmit Channel 58 */
#define MUTE_CH58 0x800000 /* Mute Channel 58 */
-#define nMUTE_CH58 0x0
#define TX_CH59 0x3f000000 /* Transmit Channel 59 */
#define MUTE_CH59 0x80000000 /* Mute Channel 59 */
-#define nMUTE_CH59 0x0
/* Bit masks for MXVR_BLOCK_CNT */
@@ -2416,53 +2006,37 @@
/* Bit masks for MXVR_CLK_CTL */
#define MXTALCEN 0x1 /* MXVR Crystal Oscillator Clock Enable */
-#define nMXTALCEN 0x0
#define MXTALFEN 0x2 /* MXVR Crystal Oscillator Feedback Enable */
-#define nMXTALFEN 0x0
#define MXTALMUL 0x30 /* MXVR Crystal Multiplier */
#define CLKX3SEL 0x80 /* Clock Generation Source Select */
-#define nCLKX3SEL 0x0
#define MMCLKEN 0x100 /* Master Clock Enable */
-#define nMMCLKEN 0x0
#define MMCLKMUL 0x1e00 /* Master Clock Multiplication Factor */
#define PLLSMPS 0xe000 /* MXVR PLL State Machine Prescaler */
#define MBCLKEN 0x10000 /* Bit Clock Enable */
-#define nMBCLKEN 0x0
#define MBCLKDIV 0x1e0000 /* Bit Clock Divide Factor */
#define INVRX 0x800000 /* Invert Receive Data */
-#define nINVRX 0x0
#define MFSEN 0x1000000 /* Frame Sync Enable */
-#define nMFSEN 0x0
#define MFSDIV 0x1e000000 /* Frame Sync Divide Factor */
#define MFSSEL 0x60000000 /* Frame Sync Select */
#define MFSSYNC 0x80000000 /* Frame Sync Synchronization Select */
-#define nMFSSYNC 0x0
/* Bit masks for MXVR_CDRPLL_CTL */
#define CDRSMEN 0x1 /* MXVR CDRPLL State Machine Enable */
-#define nCDRSMEN 0x0
#define CDRRSTB 0x2 /* MXVR CDRPLL Reset */
-#define nCDRRSTB 0x0
#define CDRSVCO 0x4 /* MXVR CDRPLL Start VCO */
-#define nCDRSVCO 0x0
#define CDRMODE 0x8 /* MXVR CDRPLL CDR Mode Select */
-#define nCDRMODE 0x0
#define CDRSCNT 0x3f0 /* MXVR CDRPLL Start Counter */
#define CDRLCNT 0xfc00 /* MXVR CDRPLL Lock Counter */
#define CDRSHPSEL 0x3f0000 /* MXVR CDRPLL Shaper Select */
#define CDRSHPEN 0x800000 /* MXVR CDRPLL Shaper Enable */
-#define nCDRSHPEN 0x0
#define CDRCPSEL 0xff000000 /* MXVR CDRPLL Charge Pump Current Select */
/* Bit masks for MXVR_FMPLL_CTL */
#define FMSMEN 0x1 /* MXVR FMPLL State Machine Enable */
-#define nFMSMEN 0x0
#define FMRSTB 0x2 /* MXVR FMPLL Reset */
-#define nFMRSTB 0x0
#define FMSVCO 0x4 /* MXVR FMPLL Start VCO */
-#define nFMSVCO 0x0
#define FMSCNT 0x3f0 /* MXVR FMPLL Start Counter */
#define FMLCNT 0xfc00 /* MXVR FMPLL Lock Counter */
#define FMCPSEL 0xff000000 /* MXVR FMPLL Charge Pump Current Select */
@@ -2470,15 +2044,10 @@
/* Bit masks for MXVR_PIN_CTL */
#define MTXONBOD 0x1 /* MTXONB Open Drain Select */
-#define nMTXONBOD 0x0
#define MTXONBG 0x2 /* MTXONB Gates MTX Select */
-#define nMTXONBG 0x0
#define MFSOE 0x10 /* MFS Output Enable */
-#define nMFSOE 0x0
#define MFSGPSEL 0x20 /* MFS General Purpose Output Select */
-#define nMFSGPSEL 0x0
#define MFSGPDAT 0x40 /* MFS General Purpose Output Data */
-#define nMFSGPDAT 0x0
/* Bit masks for MXVR_SCLK_CNT */
@@ -2487,7 +2056,6 @@
/* Bit masks for KPAD_CTL */
#define KPAD_EN 0x1 /* Keypad Enable */
-#define nKPAD_EN 0x0
#define KPAD_IRQMODE 0x6 /* Key Press Interrupt Enable */
#define KPAD_ROWEN 0x1c00 /* Row Enable Width */
#define KPAD_COLEN 0xe000 /* Column Enable Width */
@@ -2509,29 +2077,21 @@
/* Bit masks for KPAD_STAT */
#define KPAD_IRQ 0x1 /* Keypad Interrupt Status */
-#define nKPAD_IRQ 0x0
#define KPAD_MROWCOL 0x6 /* Multiple Row/Column Keypress Status */
#define KPAD_PRESSED 0x8 /* Key press current status */
-#define nKPAD_PRESSED 0x0
/* Bit masks for KPAD_SOFTEVAL */
#define KPAD_SOFTEVAL_E 0x2 /* Software Programmable Force Evaluate */
-#define nKPAD_SOFTEVAL_E 0x0
/* Bit masks for SDH_COMMAND */
#define CMD_IDX 0x3f /* Command Index */
#define CMD_RSP 0x40 /* Response */
-#define nCMD_RSP 0x0
#define CMD_L_RSP 0x80 /* Long Response */
-#define nCMD_L_RSP 0x0
#define CMD_INT_E 0x100 /* Command Interrupt */
-#define nCMD_INT_E 0x0
#define CMD_PEND_E 0x200 /* Command Pending */
-#define nCMD_PEND_E 0x0
#define CMD_E 0x400 /* Command Enable */
-#define nCMD_E 0x0
/* Bit masks for SDH_PWR_CTL */
@@ -2540,21 +2100,15 @@
#define TBD 0x3c /* TBD */
#endif
#define SD_CMD_OD 0x40 /* Open Drain Output */
-#define nSD_CMD_OD 0x0
#define ROD_CTL 0x80 /* Rod Control */
-#define nROD_CTL 0x0
/* Bit masks for SDH_CLK_CTL */
#define CLKDIV 0xff /* MC_CLK Divisor */
#define CLK_E 0x100 /* MC_CLK Bus Clock Enable */
-#define nCLK_E 0x0
#define PWR_SV_E 0x200 /* Power Save Enable */
-#define nPWR_SV_E 0x0
#define CLKDIV_BYPASS 0x400 /* Bypass Divisor */
-#define nCLKDIV_BYPASS 0x0
#define WIDE_BUS 0x800 /* Wide Bus Mode Enable */
-#define nWIDE_BUS 0x0
/* Bit masks for SDH_RESP_CMD */
@@ -2563,133 +2117,74 @@
/* Bit masks for SDH_DATA_CTL */
#define DTX_E 0x1 /* Data Transfer Enable */
-#define nDTX_E 0x0
#define DTX_DIR 0x2 /* Data Transfer Direction */
-#define nDTX_DIR 0x0
#define DTX_MODE 0x4 /* Data Transfer Mode */
-#define nDTX_MODE 0x0
#define DTX_DMA_E 0x8 /* Data Transfer DMA Enable */
-#define nDTX_DMA_E 0x0
#define DTX_BLK_LGTH 0xf0 /* Data Transfer Block Length */
/* Bit masks for SDH_STATUS */
#define CMD_CRC_FAIL 0x1 /* CMD CRC Fail */
-#define nCMD_CRC_FAIL 0x0
#define DAT_CRC_FAIL 0x2 /* Data CRC Fail */
-#define nDAT_CRC_FAIL 0x0
-#define CMD_TIMEOUT 0x4 /* CMD Time Out */
-#define nCMD_TIMEOUT 0x0
-#define DAT_TIMEOUT 0x8 /* Data Time Out */
-#define nDAT_TIMEOUT 0x0
+#define CMD_TIME_OUT 0x4 /* CMD Time Out */
+#define DAT_TIME_OUT 0x8 /* Data Time Out */
#define TX_UNDERRUN 0x10 /* Transmit Underrun */
-#define nTX_UNDERRUN 0x0
#define RX_OVERRUN 0x20 /* Receive Overrun */
-#define nRX_OVERRUN 0x0
#define CMD_RESP_END 0x40 /* CMD Response End */
-#define nCMD_RESP_END 0x0
#define CMD_SENT 0x80 /* CMD Sent */
-#define nCMD_SENT 0x0
#define DAT_END 0x100 /* Data End */
-#define nDAT_END 0x0
#define START_BIT_ERR 0x200 /* Start Bit Error */
-#define nSTART_BIT_ERR 0x0
#define DAT_BLK_END 0x400 /* Data Block End */
-#define nDAT_BLK_END 0x0
#define CMD_ACT 0x800 /* CMD Active */
-#define nCMD_ACT 0x0
#define TX_ACT 0x1000 /* Transmit Active */
-#define nTX_ACT 0x0
#define RX_ACT 0x2000 /* Receive Active */
-#define nRX_ACT 0x0
#define TX_FIFO_STAT 0x4000 /* Transmit FIFO Status */
-#define nTX_FIFO_STAT 0x0
#define RX_FIFO_STAT 0x8000 /* Receive FIFO Status */
-#define nRX_FIFO_STAT 0x0
#define TX_FIFO_FULL 0x10000 /* Transmit FIFO Full */
-#define nTX_FIFO_FULL 0x0
#define RX_FIFO_FULL 0x20000 /* Receive FIFO Full */
-#define nRX_FIFO_FULL 0x0
#define TX_FIFO_ZERO 0x40000 /* Transmit FIFO Empty */
-#define nTX_FIFO_ZERO 0x0
#define RX_DAT_ZERO 0x80000 /* Receive FIFO Empty */
-#define nRX_DAT_ZERO 0x0
#define TX_DAT_RDY 0x100000 /* Transmit Data Available */
-#define nTX_DAT_RDY 0x0
#define RX_FIFO_RDY 0x200000 /* Receive Data Available */
-#define nRX_FIFO_RDY 0x0
/* Bit masks for SDH_STATUS_CLR */
#define CMD_CRC_FAIL_STAT 0x1 /* CMD CRC Fail Status */
-#define nCMD_CRC_FAIL_STAT 0x0
#define DAT_CRC_FAIL_STAT 0x2 /* Data CRC Fail Status */
-#define nDAT_CRC_FAIL_STAT 0x0
#define CMD_TIMEOUT_STAT 0x4 /* CMD Time Out Status */
-#define nCMD_TIMEOUT_STAT 0x0
#define DAT_TIMEOUT_STAT 0x8 /* Data Time Out status */
-#define nDAT_TIMEOUT_STAT 0x0
#define TX_UNDERRUN_STAT 0x10 /* Transmit Underrun Status */
-#define nTX_UNDERRUN_STAT 0x0
#define RX_OVERRUN_STAT 0x20 /* Receive Overrun Status */
-#define nRX_OVERRUN_STAT 0x0
#define CMD_RESP_END_STAT 0x40 /* CMD Response End Status */
-#define nCMD_RESP_END_STAT 0x0
#define CMD_SENT_STAT 0x80 /* CMD Sent Status */
-#define nCMD_SENT_STAT 0x0
#define DAT_END_STAT 0x100 /* Data End Status */
-#define nDAT_END_STAT 0x0
#define START_BIT_ERR_STAT 0x200 /* Start Bit Error Status */
-#define nSTART_BIT_ERR_STAT 0x0
#define DAT_BLK_END_STAT 0x400 /* Data Block End Status */
-#define nDAT_BLK_END_STAT 0x0
/* Bit masks for SDH_MASK0 */
#define CMD_CRC_FAIL_MASK 0x1 /* CMD CRC Fail Mask */
-#define nCMD_CRC_FAIL_MASK 0x0
#define DAT_CRC_FAIL_MASK 0x2 /* Data CRC Fail Mask */
-#define nDAT_CRC_FAIL_MASK 0x0
#define CMD_TIMEOUT_MASK 0x4 /* CMD Time Out Mask */
-#define nCMD_TIMEOUT_MASK 0x0
#define DAT_TIMEOUT_MASK 0x8 /* Data Time Out Mask */
-#define nDAT_TIMEOUT_MASK 0x0
#define TX_UNDERRUN_MASK 0x10 /* Transmit Underrun Mask */
-#define nTX_UNDERRUN_MASK 0x0
#define RX_OVERRUN_MASK 0x20 /* Receive Overrun Mask */
-#define nRX_OVERRUN_MASK 0x0
#define CMD_RESP_END_MASK 0x40 /* CMD Response End Mask */
-#define nCMD_RESP_END_MASK 0x0
#define CMD_SENT_MASK 0x80 /* CMD Sent Mask */
-#define nCMD_SENT_MASK 0x0
#define DAT_END_MASK 0x100 /* Data End Mask */
-#define nDAT_END_MASK 0x0
#define START_BIT_ERR_MASK 0x200 /* Start Bit Error Mask */
-#define nSTART_BIT_ERR_MASK 0x0
#define DAT_BLK_END_MASK 0x400 /* Data Block End Mask */
-#define nDAT_BLK_END_MASK 0x0
#define CMD_ACT_MASK 0x800 /* CMD Active Mask */
-#define nCMD_ACT_MASK 0x0
#define TX_ACT_MASK 0x1000 /* Transmit Active Mask */
-#define nTX_ACT_MASK 0x0
#define RX_ACT_MASK 0x2000 /* Receive Active Mask */
-#define nRX_ACT_MASK 0x0
#define TX_FIFO_STAT_MASK 0x4000 /* Transmit FIFO Status Mask */
-#define nTX_FIFO_STAT_MASK 0x0
#define RX_FIFO_STAT_MASK 0x8000 /* Receive FIFO Status Mask */
-#define nRX_FIFO_STAT_MASK 0x0
#define TX_FIFO_FULL_MASK 0x10000 /* Transmit FIFO Full Mask */
-#define nTX_FIFO_FULL_MASK 0x0
#define RX_FIFO_FULL_MASK 0x20000 /* Receive FIFO Full Mask */
-#define nRX_FIFO_FULL_MASK 0x0
#define TX_FIFO_ZERO_MASK 0x40000 /* Transmit FIFO Empty Mask */
-#define nTX_FIFO_ZERO_MASK 0x0
#define RX_DAT_ZERO_MASK 0x80000 /* Receive FIFO Empty Mask */
-#define nRX_DAT_ZERO_MASK 0x0
#define TX_DAT_RDY_MASK 0x100000 /* Transmit Data Available Mask */
-#define nTX_DAT_RDY_MASK 0x0
#define RX_FIFO_RDY_MASK 0x200000 /* Receive Data Available Mask */
-#define nRX_FIFO_RDY_MASK 0x0
/* Bit masks for SDH_FIFO_CNT */
@@ -2698,73 +2193,47 @@
/* Bit masks for SDH_E_STATUS */
#define SDIO_INT_DET 0x2 /* SDIO Int Detected */
-#define nSDIO_INT_DET 0x0
#define SD_CARD_DET 0x10 /* SD Card Detect */
-#define nSD_CARD_DET 0x0
/* Bit masks for SDH_E_MASK */
#define SDIO_MSK 0x2 /* Mask SDIO Int Detected */
-#define nSDIO_MSK 0x0
#define SCD_MSK 0x40 /* Mask Card Detect */
-#define nSCD_MSK 0x0
/* Bit masks for SDH_CFG */
#define CLKS_EN 0x1 /* Clocks Enable */
-#define nCLKS_EN 0x0
#define SD4E 0x4 /* SDIO 4-Bit Enable */
-#define nSD4E 0x0
#define MWE 0x8 /* Moving Window Enable */
-#define nMWE 0x0
#define SD_RST 0x10 /* SDMMC Reset */
-#define nSD_RST 0x0
#define PUP_SDDAT 0x20 /* Pull-up SD_DAT */
-#define nPUP_SDDAT 0x0
#define PUP_SDDAT3 0x40 /* Pull-up SD_DAT3 */
-#define nPUP_SDDAT3 0x0
#define PD_SDDAT3 0x80 /* Pull-down SD_DAT3 */
-#define nPD_SDDAT3 0x0
/* Bit masks for SDH_RD_WAIT_EN */
#define RWR 0x1 /* Read Wait Request */
-#define nRWR 0x0
/* Bit masks for ATAPI_CONTROL */
#define PIO_START 0x1 /* Start PIO/Reg Op */
-#define nPIO_START 0x0
#define MULTI_START 0x2 /* Start Multi-DMA Op */
-#define nMULTI_START 0x0
#define ULTRA_START 0x4 /* Start Ultra-DMA Op */
-#define nULTRA_START 0x0
#define XFER_DIR 0x8 /* Transfer Direction */
-#define nXFER_DIR 0x0
#define IORDY_EN 0x10 /* IORDY Enable */
-#define nIORDY_EN 0x0
#define FIFO_FLUSH 0x20 /* Flush FIFOs */
-#define nFIFO_FLUSH 0x0
#define SOFT_RST 0x40 /* Soft Reset */
-#define nSOFT_RST 0x0
#define DEV_RST 0x80 /* Device Reset */
-#define nDEV_RST 0x0
#define TFRCNT_RST 0x100 /* Trans Count Reset */
-#define nTFRCNT_RST 0x0
#define END_ON_TERM 0x200 /* End/Terminate Select */
-#define nEND_ON_TERM 0x0
#define PIO_USE_DMA 0x400 /* PIO-DMA Enable */
-#define nPIO_USE_DMA 0x0
#define UDMAIN_FIFO_THRS 0xf000 /* Ultra DMA-IN FIFO Threshold */
/* Bit masks for ATAPI_STATUS */
#define PIO_XFER_ON 0x1 /* PIO transfer in progress */
-#define nPIO_XFER_ON 0x0
#define MULTI_XFER_ON 0x2 /* Multi-word DMA transfer in progress */
-#define nMULTI_XFER_ON 0x0
#define ULTRA_XFER_ON 0x4 /* Ultra DMA transfer in progress */
-#define nULTRA_XFER_ON 0x0
#define ULTRA_IN_FL 0xf0 /* Ultra DMA Input FIFO Level */
/* Bit masks for ATAPI_DEV_ADDR */
@@ -2774,66 +2243,39 @@
/* Bit masks for ATAPI_INT_MASK */
#define ATAPI_DEV_INT_MASK 0x1 /* Device interrupt mask */
-#define nATAPI_DEV_INT_MASK 0x0
#define PIO_DONE_MASK 0x2 /* PIO transfer done interrupt mask */
-#define nPIO_DONE_MASK 0x0
#define MULTI_DONE_MASK 0x4 /* Multi-DMA transfer done interrupt mask */
-#define nMULTI_DONE_MASK 0x0
#define UDMAIN_DONE_MASK 0x8 /* Ultra-DMA in transfer done interrupt mask */
-#define nUDMAIN_DONE_MASK 0x0
#define UDMAOUT_DONE_MASK 0x10 /* Ultra-DMA out transfer done interrupt mask */
-#define nUDMAOUT_DONE_MASK 0x0
#define HOST_TERM_XFER_MASK 0x20 /* Host terminate current transfer interrupt mask */
-#define nHOST_TERM_XFER_MASK 0x0
#define MULTI_TERM_MASK 0x40 /* Device terminate Multi-DMA transfer interrupt mask */
-#define nMULTI_TERM_MASK 0x0
#define UDMAIN_TERM_MASK 0x80 /* Device terminate Ultra-DMA-in transfer interrupt mask */
-#define nUDMAIN_TERM_MASK 0x0
#define UDMAOUT_TERM_MASK 0x100 /* Device terminate Ultra-DMA-out transfer interrupt mask */
-#define nUDMAOUT_TERM_MASK 0x0
/* Bit masks for ATAPI_INT_STATUS */
#define ATAPI_DEV_INT 0x1 /* Device interrupt status */
-#define nATAPI_DEV_INT 0x0
#define PIO_DONE_INT 0x2 /* PIO transfer done interrupt status */
-#define nPIO_DONE_INT 0x0
#define MULTI_DONE_INT 0x4 /* Multi-DMA transfer done interrupt status */
-#define nMULTI_DONE_INT 0x0
#define UDMAIN_DONE_INT 0x8 /* Ultra-DMA in transfer done interrupt status */
-#define nUDMAIN_DONE_INT 0x0
#define UDMAOUT_DONE_INT 0x10 /* Ultra-DMA out transfer done interrupt status */
-#define nUDMAOUT_DONE_INT 0x0
#define HOST_TERM_XFER_INT 0x20 /* Host terminate current transfer interrupt status */
-#define nHOST_TERM_XFER_INT 0x0
#define MULTI_TERM_INT 0x40 /* Device terminate Multi-DMA transfer interrupt status */
-#define nMULTI_TERM_INT 0x0
#define UDMAIN_TERM_INT 0x80 /* Device terminate Ultra-DMA-in transfer interrupt status */
-#define nUDMAIN_TERM_INT 0x0
#define UDMAOUT_TERM_INT 0x100 /* Device terminate Ultra-DMA-out transfer interrupt status */
-#define nUDMAOUT_TERM_INT 0x0
/* Bit masks for ATAPI_LINE_STATUS */
#define ATAPI_INTR 0x1 /* Device interrupt to host line status */
-#define nATAPI_INTR 0x0
#define ATAPI_DASP 0x2 /* Device dasp to host line status */
-#define nATAPI_DASP 0x0
#define ATAPI_CS0N 0x4 /* ATAPI chip select 0 line status */
-#define nATAPI_CS0N 0x0
#define ATAPI_CS1N 0x8 /* ATAPI chip select 1 line status */
-#define nATAPI_CS1N 0x0
#define ATAPI_ADDR 0x70 /* ATAPI address line status */
#define ATAPI_DMAREQ 0x80 /* ATAPI DMA request line status */
-#define nATAPI_DMAREQ 0x0
#define ATAPI_DMAACKN 0x100 /* ATAPI DMA acknowledge line status */
-#define nATAPI_DMAACKN 0x0
#define ATAPI_DIOWN 0x200 /* ATAPI write line status */
-#define nATAPI_DIOWN 0x0
#define ATAPI_DIORN 0x400 /* ATAPI read line status */
-#define nATAPI_DIORN 0x0
#define ATAPI_IORDY 0x800 /* ATAPI IORDY line status */
-#define nATAPI_IORDY 0x0
/* Bit masks for ATAPI_SM_STATE */
@@ -2845,7 +2287,6 @@
/* Bit masks for ATAPI_TERMINATE */
#define ATAPI_HOST_TERM 0x1 /* Host terminationation */
-#define nATAPI_HOST_TERM 0x0
/* Bit masks for ATAPI_REG_TIM_0 */
@@ -2900,41 +2341,26 @@
/* Bit masks for TIMER_ENABLE1 */
#define TIMEN8 0x1 /* Timer 8 Enable */
-#define nTIMEN8 0x0
#define TIMEN9 0x2 /* Timer 9 Enable */
-#define nTIMEN9 0x0
#define TIMEN10 0x4 /* Timer 10 Enable */
-#define nTIMEN10 0x0
/* Bit masks for TIMER_DISABLE1 */
#define TIMDIS8 0x1 /* Timer 8 Disable */
-#define nTIMDIS8 0x0
#define TIMDIS9 0x2 /* Timer 9 Disable */
-#define nTIMDIS9 0x0
#define TIMDIS10 0x4 /* Timer 10 Disable */
-#define nTIMDIS10 0x0
/* Bit masks for TIMER_STATUS1 */
#define TIMIL8 0x1 /* Timer 8 Interrupt */
-#define nTIMIL8 0x0
#define TIMIL9 0x2 /* Timer 9 Interrupt */
-#define nTIMIL9 0x0
#define TIMIL10 0x4 /* Timer 10 Interrupt */
-#define nTIMIL10 0x0
#define TOVF_ERR8 0x10 /* Timer 8 Counter Overflow */
-#define nTOVF_ERR8 0x0
#define TOVF_ERR9 0x20 /* Timer 9 Counter Overflow */
-#define nTOVF_ERR9 0x0
#define TOVF_ERR10 0x40 /* Timer 10 Counter Overflow */
-#define nTOVF_ERR10 0x0
#define TRUN8 0x1000 /* Timer 8 Slave Enable Status */
-#define nTRUN8 0x0
#define TRUN9 0x2000 /* Timer 9 Slave Enable Status */
-#define nTRUN9 0x0
#define TRUN10 0x4000 /* Timer 10 Slave Enable Status */
-#define nTRUN10 0x0
/* Bit masks for EPPI0 are obtained from common base header for EPPIx (EPPI1 and EPPI2) */
@@ -2945,131 +2371,77 @@
/* Bit masks for USB_POWER */
#define ENABLE_SUSPENDM 0x1 /* enable SuspendM output */
-#define nENABLE_SUSPENDM 0x0
#define SUSPEND_MODE 0x2 /* Suspend Mode indicator */
-#define nSUSPEND_MODE 0x0
#define RESUME_MODE 0x4 /* DMA Mode */
-#define nRESUME_MODE 0x0
#define RESET 0x8 /* Reset indicator */
-#define nRESET 0x0
#define HS_MODE 0x10 /* High Speed mode indicator */
-#define nHS_MODE 0x0
#define HS_ENABLE 0x20 /* high Speed Enable */
-#define nHS_ENABLE 0x0
#define SOFT_CONN 0x40 /* Soft connect */
-#define nSOFT_CONN 0x0
#define ISO_UPDATE 0x80 /* Isochronous update */
-#define nISO_UPDATE 0x0
/* Bit masks for USB_INTRTX */
#define EP0_TX 0x1 /* Tx Endpoint 0 interrupt */
-#define nEP0_TX 0x0
#define EP1_TX 0x2 /* Tx Endpoint 1 interrupt */
-#define nEP1_TX 0x0
#define EP2_TX 0x4 /* Tx Endpoint 2 interrupt */
-#define nEP2_TX 0x0
#define EP3_TX 0x8 /* Tx Endpoint 3 interrupt */
-#define nEP3_TX 0x0
#define EP4_TX 0x10 /* Tx Endpoint 4 interrupt */
-#define nEP4_TX 0x0
#define EP5_TX 0x20 /* Tx Endpoint 5 interrupt */
-#define nEP5_TX 0x0
#define EP6_TX 0x40 /* Tx Endpoint 6 interrupt */
-#define nEP6_TX 0x0
#define EP7_TX 0x80 /* Tx Endpoint 7 interrupt */
-#define nEP7_TX 0x0
/* Bit masks for USB_INTRRX */
#define EP1_RX 0x2 /* Rx Endpoint 1 interrupt */
-#define nEP1_RX 0x0
#define EP2_RX 0x4 /* Rx Endpoint 2 interrupt */
-#define nEP2_RX 0x0
#define EP3_RX 0x8 /* Rx Endpoint 3 interrupt */
-#define nEP3_RX 0x0
#define EP4_RX 0x10 /* Rx Endpoint 4 interrupt */
-#define nEP4_RX 0x0
#define EP5_RX 0x20 /* Rx Endpoint 5 interrupt */
-#define nEP5_RX 0x0
#define EP6_RX 0x40 /* Rx Endpoint 6 interrupt */
-#define nEP6_RX 0x0
#define EP7_RX 0x80 /* Rx Endpoint 7 interrupt */
-#define nEP7_RX 0x0
/* Bit masks for USB_INTRTXE */
#define EP0_TX_E 0x1 /* Endpoint 0 interrupt Enable */
-#define nEP0_TX_E 0x0
#define EP1_TX_E 0x2 /* Tx Endpoint 1 interrupt Enable */
-#define nEP1_TX_E 0x0
#define EP2_TX_E 0x4 /* Tx Endpoint 2 interrupt Enable */
-#define nEP2_TX_E 0x0
#define EP3_TX_E 0x8 /* Tx Endpoint 3 interrupt Enable */
-#define nEP3_TX_E 0x0
#define EP4_TX_E 0x10 /* Tx Endpoint 4 interrupt Enable */
-#define nEP4_TX_E 0x0
#define EP5_TX_E 0x20 /* Tx Endpoint 5 interrupt Enable */
-#define nEP5_TX_E 0x0
#define EP6_TX_E 0x40 /* Tx Endpoint 6 interrupt Enable */
-#define nEP6_TX_E 0x0
#define EP7_TX_E 0x80 /* Tx Endpoint 7 interrupt Enable */
-#define nEP7_TX_E 0x0
/* Bit masks for USB_INTRRXE */
#define EP1_RX_E 0x2 /* Rx Endpoint 1 interrupt Enable */
-#define nEP1_RX_E 0x0
#define EP2_RX_E 0x4 /* Rx Endpoint 2 interrupt Enable */
-#define nEP2_RX_E 0x0
#define EP3_RX_E 0x8 /* Rx Endpoint 3 interrupt Enable */
-#define nEP3_RX_E 0x0
#define EP4_RX_E 0x10 /* Rx Endpoint 4 interrupt Enable */
-#define nEP4_RX_E 0x0
#define EP5_RX_E 0x20 /* Rx Endpoint 5 interrupt Enable */
-#define nEP5_RX_E 0x0
#define EP6_RX_E 0x40 /* Rx Endpoint 6 interrupt Enable */
-#define nEP6_RX_E 0x0
#define EP7_RX_E 0x80 /* Rx Endpoint 7 interrupt Enable */
-#define nEP7_RX_E 0x0
/* Bit masks for USB_INTRUSB */
#define SUSPEND_B 0x1 /* Suspend indicator */
-#define nSUSPEND_B 0x0
#define RESUME_B 0x2 /* Resume indicator */
-#define nRESUME_B 0x0
#define RESET_OR_BABLE_B 0x4 /* Reset/babble indicator */
-#define nRESET_OR_BABLE_B 0x0
#define SOF_B 0x8 /* Start of frame */
-#define nSOF_B 0x0
#define CONN_B 0x10 /* Connection indicator */
-#define nCONN_B 0x0
#define DISCON_B 0x20 /* Disconnect indicator */
-#define nDISCON_B 0x0
#define SESSION_REQ_B 0x40 /* Session Request */
-#define nSESSION_REQ_B 0x0
#define VBUS_ERROR_B 0x80 /* Vbus threshold indicator */
-#define nVBUS_ERROR_B 0x0
/* Bit masks for USB_INTRUSBE */
#define SUSPEND_BE 0x1 /* Suspend indicator int enable */
-#define nSUSPEND_BE 0x0
#define RESUME_BE 0x2 /* Resume indicator int enable */
-#define nRESUME_BE 0x0
#define RESET_OR_BABLE_BE 0x4 /* Reset/babble indicator int enable */
-#define nRESET_OR_BABLE_BE 0x0
#define SOF_BE 0x8 /* Start of frame int enable */
-#define nSOF_BE 0x0
#define CONN_BE 0x10 /* Connection indicator int enable */
-#define nCONN_BE 0x0
#define DISCON_BE 0x20 /* Disconnect indicator int enable */
-#define nDISCON_BE 0x0
#define SESSION_REQ_BE 0x40 /* Session Request int enable */
-#define nSESSION_REQ_BE 0x0
#define VBUS_ERROR_BE 0x80 /* Vbus threshold indicator int enable */
-#define nVBUS_ERROR_BE 0x0
/* Bit masks for USB_FRAME */
@@ -3082,117 +2454,67 @@
/* Bit masks for USB_GLOBAL_CTL */
#define GLOBAL_ENA 0x1 /* enables USB module */
-#define nGLOBAL_ENA 0x0
#define EP1_TX_ENA 0x2 /* Transmit endpoint 1 enable */
-#define nEP1_TX_ENA 0x0
#define EP2_TX_ENA 0x4 /* Transmit endpoint 2 enable */
-#define nEP2_TX_ENA 0x0
#define EP3_TX_ENA 0x8 /* Transmit endpoint 3 enable */
-#define nEP3_TX_ENA 0x0
#define EP4_TX_ENA 0x10 /* Transmit endpoint 4 enable */
-#define nEP4_TX_ENA 0x0
#define EP5_TX_ENA 0x20 /* Transmit endpoint 5 enable */
-#define nEP5_TX_ENA 0x0
#define EP6_TX_ENA 0x40 /* Transmit endpoint 6 enable */
-#define nEP6_TX_ENA 0x0
#define EP7_TX_ENA 0x80 /* Transmit endpoint 7 enable */
-#define nEP7_TX_ENA 0x0
#define EP1_RX_ENA 0x100 /* Receive endpoint 1 enable */
-#define nEP1_RX_ENA 0x0
#define EP2_RX_ENA 0x200 /* Receive endpoint 2 enable */
-#define nEP2_RX_ENA 0x0
#define EP3_RX_ENA 0x400 /* Receive endpoint 3 enable */
-#define nEP3_RX_ENA 0x0
#define EP4_RX_ENA 0x800 /* Receive endpoint 4 enable */
-#define nEP4_RX_ENA 0x0
#define EP5_RX_ENA 0x1000 /* Receive endpoint 5 enable */
-#define nEP5_RX_ENA 0x0
#define EP6_RX_ENA 0x2000 /* Receive endpoint 6 enable */
-#define nEP6_RX_ENA 0x0
#define EP7_RX_ENA 0x4000 /* Receive endpoint 7 enable */
-#define nEP7_RX_ENA 0x0
/* Bit masks for USB_OTG_DEV_CTL */
#define SESSION 0x1 /* session indicator */
-#define nSESSION 0x0
#define HOST_REQ 0x2 /* Host negotiation request */
-#define nHOST_REQ 0x0
#define HOST_MODE 0x4 /* indicates USBDRC is a host */
-#define nHOST_MODE 0x0
#define VBUS0 0x8 /* Vbus level indicator[0] */
-#define nVBUS0 0x0
#define VBUS1 0x10 /* Vbus level indicator[1] */
-#define nVBUS1 0x0
#define LSDEV 0x20 /* Low-speed indicator */
-#define nLSDEV 0x0
#define FSDEV 0x40 /* Full or High-speed indicator */
-#define nFSDEV 0x0
#define B_DEVICE 0x80 /* A' or 'B' device indicator */
-#define nB_DEVICE 0x0
/* Bit masks for USB_OTG_VBUS_IRQ */
#define DRIVE_VBUS_ON 0x1 /* indicator to drive VBUS control circuit */
-#define nDRIVE_VBUS_ON 0x0
#define DRIVE_VBUS_OFF 0x2 /* indicator to shut off charge pump */
-#define nDRIVE_VBUS_OFF 0x0
#define CHRG_VBUS_START 0x4 /* indicator for external circuit to start charging VBUS */
-#define nCHRG_VBUS_START 0x0
#define CHRG_VBUS_END 0x8 /* indicator for external circuit to end charging VBUS */
-#define nCHRG_VBUS_END 0x0
#define DISCHRG_VBUS_START 0x10 /* indicator to start discharging VBUS */
-#define nDISCHRG_VBUS_START 0x0
#define DISCHRG_VBUS_END 0x20 /* indicator to stop discharging VBUS */
-#define nDISCHRG_VBUS_END 0x0
/* Bit masks for USB_OTG_VBUS_MASK */
#define DRIVE_VBUS_ON_ENA 0x1 /* enable DRIVE_VBUS_ON interrupt */
-#define nDRIVE_VBUS_ON_ENA 0x0
#define DRIVE_VBUS_OFF_ENA 0x2 /* enable DRIVE_VBUS_OFF interrupt */
-#define nDRIVE_VBUS_OFF_ENA 0x0
#define CHRG_VBUS_START_ENA 0x4 /* enable CHRG_VBUS_START interrupt */
-#define nCHRG_VBUS_START_ENA 0x0
#define CHRG_VBUS_END_ENA 0x8 /* enable CHRG_VBUS_END interrupt */
-#define nCHRG_VBUS_END_ENA 0x0
#define DISCHRG_VBUS_START_ENA 0x10 /* enable DISCHRG_VBUS_START interrupt */
-#define nDISCHRG_VBUS_START_ENA 0x0
#define DISCHRG_VBUS_END_ENA 0x20 /* enable DISCHRG_VBUS_END interrupt */
-#define nDISCHRG_VBUS_END_ENA 0x0
/* Bit masks for USB_CSR0 */
#define RXPKTRDY 0x1 /* data packet receive indicator */
-#define nRXPKTRDY 0x0
#define TXPKTRDY 0x2 /* data packet in FIFO indicator */
-#define nTXPKTRDY 0x0
#define STALL_SENT 0x4 /* STALL handshake sent */
-#define nSTALL_SENT 0x0
#define DATAEND 0x8 /* Data end indicator */
-#define nDATAEND 0x0
#define SETUPEND 0x10 /* Setup end */
-#define nSETUPEND 0x0
#define SENDSTALL 0x20 /* Send STALL handshake */
-#define nSENDSTALL 0x0
#define SERVICED_RXPKTRDY 0x40 /* used to clear the RxPktRdy bit */
-#define nSERVICED_RXPKTRDY 0x0
#define SERVICED_SETUPEND 0x80 /* used to clear the SetupEnd bit */
-#define nSERVICED_SETUPEND 0x0
#define FLUSHFIFO 0x100 /* flush endpoint FIFO */
-#define nFLUSHFIFO 0x0
#define STALL_RECEIVED_H 0x4 /* STALL handshake received host mode */
-#define nSTALL_RECEIVED_H 0x0
#define SETUPPKT_H 0x8 /* send Setup token host mode */
-#define nSETUPPKT_H 0x0
#define ERROR_H 0x10 /* timeout error indicator host mode */
-#define nERROR_H 0x0
#define REQPKT_H 0x20 /* Request an IN transaction host mode */
-#define nREQPKT_H 0x0
#define STATUSPKT_H 0x40 /* Status stage transaction host mode */
-#define nSTATUSPKT_H 0x0
#define NAK_TIMEOUT_H 0x80 /* EP0 halted after a NAK host mode */
-#define nNAK_TIMEOUT_H 0x0
/* Bit masks for USB_COUNT0 */
@@ -3213,37 +2535,21 @@
/* Bit masks for USB_TXCSR */
#define TXPKTRDY_T 0x1 /* data packet in FIFO indicator */
-#define nTXPKTRDY_T 0x0
#define FIFO_NOT_EMPTY_T 0x2 /* FIFO not empty */
-#define nFIFO_NOT_EMPTY_T 0x0
#define UNDERRUN_T 0x4 /* TxPktRdy not set for an IN token */
-#define nUNDERRUN_T 0x0
#define FLUSHFIFO_T 0x8 /* flush endpoint FIFO */
-#define nFLUSHFIFO_T 0x0
#define STALL_SEND_T 0x10 /* issue a Stall handshake */
-#define nSTALL_SEND_T 0x0
#define STALL_SENT_T 0x20 /* Stall handshake transmitted */
-#define nSTALL_SENT_T 0x0
#define CLEAR_DATATOGGLE_T 0x40 /* clear endpoint data toggle */
-#define nCLEAR_DATATOGGLE_T 0x0
#define INCOMPTX_T 0x80 /* indicates that a large packet is split */
-#define nINCOMPTX_T 0x0
#define DMAREQMODE_T 0x400 /* DMA mode (0 or 1) selection */
-#define nDMAREQMODE_T 0x0
#define FORCE_DATATOGGLE_T 0x800 /* Force data toggle */
-#define nFORCE_DATATOGGLE_T 0x0
#define DMAREQ_ENA_T 0x1000 /* Enable DMA request for Tx EP */
-#define nDMAREQ_ENA_T 0x0
#define ISO_T 0x4000 /* enable Isochronous transfers */
-#define nISO_T 0x0
#define AUTOSET_T 0x8000 /* allows TxPktRdy to be set automatically */
-#define nAUTOSET_T 0x0
#define ERROR_TH 0x4 /* error condition host mode */
-#define nERROR_TH 0x0
#define STALL_RECEIVED_TH 0x20 /* Stall handshake received host mode */
-#define nSTALL_RECEIVED_TH 0x0
#define NAK_TIMEOUT_TH 0x80 /* NAK timeout host mode */
-#define nNAK_TIMEOUT_TH 0x0
/* Bit masks for USB_TXCOUNT */
@@ -3252,45 +2558,25 @@
/* Bit masks for USB_RXCSR */
#define RXPKTRDY_R 0x1 /* data packet in FIFO indicator */
-#define nRXPKTRDY_R 0x0
#define FIFO_FULL_R 0x2 /* FIFO not empty */
-#define nFIFO_FULL_R 0x0
#define OVERRUN_R 0x4 /* TxPktRdy not set for an IN token */
-#define nOVERRUN_R 0x0
#define DATAERROR_R 0x8 /* Out packet cannot be loaded into Rx FIFO */
-#define nDATAERROR_R 0x0
#define FLUSHFIFO_R 0x10 /* flush endpoint FIFO */
-#define nFLUSHFIFO_R 0x0
#define STALL_SEND_R 0x20 /* issue a Stall handshake */
-#define nSTALL_SEND_R 0x0
#define STALL_SENT_R 0x40 /* Stall handshake transmitted */
-#define nSTALL_SENT_R 0x0
#define CLEAR_DATATOGGLE_R 0x80 /* clear endpoint data toggle */
-#define nCLEAR_DATATOGGLE_R 0x0
#define INCOMPRX_R 0x100 /* indicates that a large packet is split */
-#define nINCOMPRX_R 0x0
#define DMAREQMODE_R 0x800 /* DMA mode (0 or 1) selection */
-#define nDMAREQMODE_R 0x0
#define DISNYET_R 0x1000 /* disable Nyet handshakes */
-#define nDISNYET_R 0x0
#define DMAREQ_ENA_R 0x2000 /* Enable DMA request for Tx EP */
-#define nDMAREQ_ENA_R 0x0
#define ISO_R 0x4000 /* enable Isochronous transfers */
-#define nISO_R 0x0
#define AUTOCLEAR_R 0x8000 /* allows TxPktRdy to be set automatically */
-#define nAUTOCLEAR_R 0x0
#define ERROR_RH 0x4 /* TxPktRdy not set for an IN token host mode */
-#define nERROR_RH 0x0
#define REQPKT_RH 0x20 /* request an IN transaction host mode */
-#define nREQPKT_RH 0x0
#define STALL_RECEIVED_RH 0x40 /* Stall handshake received host mode */
-#define nSTALL_RECEIVED_RH 0x0
#define INCOMPRX_RH 0x100 /* indicates that a large packet is split host mode */
-#define nINCOMPRX_RH 0x0
#define DMAREQMODE_RH 0x800 /* DMA mode (0 or 1) selection host mode */
-#define nDMAREQMODE_RH 0x0
#define AUTOREQ_RH 0x4000 /* sets ReqPkt automatically host mode */
-#define nAUTOREQ_RH 0x0
/* Bit masks for USB_RXCOUNT */
@@ -3317,35 +2603,22 @@
/* Bit masks for USB_DMA_INTERRUPT */
#define DMA0_INT 0x1 /* DMA0 pending interrupt */
-#define nDMA0_INT 0x0
#define DMA1_INT 0x2 /* DMA1 pending interrupt */
-#define nDMA1_INT 0x0
#define DMA2_INT 0x4 /* DMA2 pending interrupt */
-#define nDMA2_INT 0x0
#define DMA3_INT 0x8 /* DMA3 pending interrupt */
-#define nDMA3_INT 0x0
#define DMA4_INT 0x10 /* DMA4 pending interrupt */
-#define nDMA4_INT 0x0
#define DMA5_INT 0x20 /* DMA5 pending interrupt */
-#define nDMA5_INT 0x0
#define DMA6_INT 0x40 /* DMA6 pending interrupt */
-#define nDMA6_INT 0x0
#define DMA7_INT 0x80 /* DMA7 pending interrupt */
-#define nDMA7_INT 0x0
/* Bit masks for USB_DMAxCONTROL */
#define DMA_ENA 0x1 /* DMA enable */
-#define nDMA_ENA 0x0
#define DIRECTION 0x2 /* direction of DMA transfer */
-#define nDIRECTION 0x0
#define MODE 0x4 /* DMA Bus error */
-#define nMODE 0x0
#define INT_ENA 0x8 /* Interrupt enable */
-#define nINT_ENA 0x0
#define EPNUM 0xf0 /* EP number */
#define BUSERROR 0x100 /* DMA Bus error */
-#define nBUSERROR 0x0
/* Bit masks for USB_DMAxADDRHIGH */
@@ -3366,26 +2639,16 @@
/* Bit masks for HMDMAx_CONTROL */
#define HMDMAEN 0x1 /* Handshake MDMA Enable */
-#define nHMDMAEN 0x0
#define REP 0x2 /* Handshake MDMA Request Polarity */
-#define nREP 0x0
#define UTE 0x8 /* Urgency Threshold Enable */
-#define nUTE 0x0
#define OIE 0x10 /* Overflow Interrupt Enable */
-#define nOIE 0x0
#define BDIE 0x20 /* Block Done Interrupt Enable */
-#define nBDIE 0x0
#define MBDI 0x40 /* Mask Block Done Interrupt */
-#define nMBDI 0x0
#define DRQ 0x300 /* Handshake MDMA Request Type */
#define RBC 0x1000 /* Force Reload of BCOUNT */
-#define nRBC 0x0
#define PS 0x2000 /* Pin Status */
-#define nPS 0x0
#define OI 0x4000 /* Overflow Interrupt Generated */
-#define nOI 0x0
#define BDI 0x8000 /* Block Done Interrupt Generated */
-#define nBDI 0x0
/* ******************************************* */
/* MULTI BIT MACRO ENUMERATIONS */
diff --git a/include/asm-blackfin/mach-bf548/defBF54x_base.h b/include/asm-blackfin/mach-bf548/defBF54x_base.h
index a1b200fe6a1f..895ddd40a838 100644
--- a/include/asm-blackfin/mach-bf548/defBF54x_base.h
+++ b/include/asm-blackfin/mach-bf548/defBF54x_base.h
@@ -46,7 +46,7 @@
/* Debug/MP/Emulation Registers (0xFFC00014 - 0xFFC00014) */
-#define CHIPID 0xffc00014
+#define CHIPID 0xffc00014
/* System Reset and Interrupt Controller (0xFFC00100 - 0xFFC00104) */
@@ -1512,231 +1512,144 @@
/* and MULTI BIT READ MACROS */
/* ********************************************************** */
+/* SIC_IMASK Masks */
+#define SIC_UNMASK_ALL 0x00000000 /* Unmask all peripheral interrupts */
+#define SIC_MASK_ALL 0xFFFFFFFF /* Mask all peripheral interrupts */
+#define SIC_MASK(x) (1 << (x)) /* Mask Peripheral #x interrupt */
+#define SIC_UNMASK(x) (0xFFFFFFFF ^ (1 << (x))) /* Unmask Peripheral #x interrupt */
+
+/* SIC_IWR Masks */
+#define IWR_DISABLE_ALL 0x00000000 /* Wakeup Disable all peripherals */
+#define IWR_ENABLE_ALL 0xFFFFFFFF /* Wakeup Enable all peripherals */
+#define IWR_ENABLE(x) (1 << (x)) /* Wakeup Enable Peripheral #x */
+#define IWR_DISABLE(x) (0xFFFFFFFF ^ (1 << (x))) /* Wakeup Disable Peripheral #x */
+
/* Bit masks for SIC_IAR0 */
-#define IRQ_PLL_WAKEUP 0x1 /* PLL Wakeup */
-#define nIRQ_PLL_WAKEUP 0x0
+#define PLL_WAKEUP 0x1 /* PLL Wakeup */
/* Bit masks for SIC_IWR0, SIC_IMASK0, SIC_ISR0 */
-#define IRQ_DMA0_ERR 0x2 /* DMA Controller 0 Error */
-#define nIRQ_DMA0_ERR 0x0
-#define IRQ_EPPI0_ERR 0x4 /* EPPI0 Error */
-#define nIRQ_EPPI0_ERR 0x0
-#define IRQ_SPORT0_ERR 0x8 /* SPORT0 Error */
-#define nIRQ_SPORT0_ERR 0x0
-#define IRQ_SPORT1_ERR 0x10 /* SPORT1 Error */
-#define nIRQ_SPORT1_ERR 0x0
-#define IRQ_SPI0_ERR 0x20 /* SPI0 Error */
-#define nIRQ_SPI0_ERR 0x0
-#define IRQ_UART0_ERR 0x40 /* UART0 Error */
-#define nIRQ_UART0_ERR 0x0
-#define IRQ_RTC 0x80 /* Real-Time Clock */
-#define nIRQ_RTC 0x0
-#define IRQ_DMA12 0x100 /* DMA Channel 12 */
-#define nIRQ_DMA12 0x0
-#define IRQ_DMA0 0x200 /* DMA Channel 0 */
-#define nIRQ_DMA0 0x0
-#define IRQ_DMA1 0x400 /* DMA Channel 1 */
-#define nIRQ_DMA1 0x0
-#define IRQ_DMA2 0x800 /* DMA Channel 2 */
-#define nIRQ_DMA2 0x0
-#define IRQ_DMA3 0x1000 /* DMA Channel 3 */
-#define nIRQ_DMA3 0x0
-#define IRQ_DMA4 0x2000 /* DMA Channel 4 */
-#define nIRQ_DMA4 0x0
-#define IRQ_DMA6 0x4000 /* DMA Channel 6 */
-#define nIRQ_DMA6 0x0
-#define IRQ_DMA7 0x8000 /* DMA Channel 7 */
-#define nIRQ_DMA7 0x0
-#define IRQ_PINT0 0x80000 /* Pin Interrupt 0 */
-#define nIRQ_PINT0 0x0
-#define IRQ_PINT1 0x100000 /* Pin Interrupt 1 */
-#define nIRQ_PINT1 0x0
-#define IRQ_MDMA0 0x200000 /* Memory DMA Stream 0 */
-#define nIRQ_MDMA0 0x0
-#define IRQ_MDMA1 0x400000 /* Memory DMA Stream 1 */
-#define nIRQ_MDMA1 0x0
-#define IRQ_WDOG 0x800000 /* Watchdog Timer */
-#define nIRQ_WDOG 0x0
-#define IRQ_DMA1_ERR 0x1000000 /* DMA Controller 1 Error */
-#define nIRQ_DMA1_ERR 0x0
-#define IRQ_SPORT2_ERR 0x2000000 /* SPORT2 Error */
-#define nIRQ_SPORT2_ERR 0x0
-#define IRQ_SPORT3_ERR 0x4000000 /* SPORT3 Error */
-#define nIRQ_SPORT3_ERR 0x0
-#define IRQ_MXVR_SD 0x8000000 /* MXVR Synchronous Data */
-#define nIRQ_MXVR_SD 0x0
-#define IRQ_SPI1_ERR 0x10000000 /* SPI1 Error */
-#define nIRQ_SPI1_ERR 0x0
-#define IRQ_SPI2_ERR 0x20000000 /* SPI2 Error */
-#define nIRQ_SPI2_ERR 0x0
-#define IRQ_UART1_ERR 0x40000000 /* UART1 Error */
-#define nIRQ_UART1_ERR 0x0
-#define IRQ_UART2_ERR 0x80000000 /* UART2 Error */
-#define nIRQ_UART2_ERR 0x0
+#define DMA0_ERR 0x2 /* DMA Controller 0 Error */
+#define EPPI0_ERR 0x4 /* EPPI0 Error */
+#define SPORT0_ERR 0x8 /* SPORT0 Error */
+#define SPORT1_ERR 0x10 /* SPORT1 Error */
+#define SPI0_ERR 0x20 /* SPI0 Error */
+#define UART0_ERR 0x40 /* UART0 Error */
+#define RTC 0x80 /* Real-Time Clock */
+#define DMA12 0x100 /* DMA Channel 12 */
+#define DMA0 0x200 /* DMA Channel 0 */
+#define DMA1 0x400 /* DMA Channel 1 */
+#define DMA2 0x800 /* DMA Channel 2 */
+#define DMA3 0x1000 /* DMA Channel 3 */
+#define DMA4 0x2000 /* DMA Channel 4 */
+#define DMA6 0x4000 /* DMA Channel 6 */
+#define DMA7 0x8000 /* DMA Channel 7 */
+#define PINT0 0x80000 /* Pin Interrupt 0 */
+#define PINT1 0x100000 /* Pin Interrupt 1 */
+#define MDMA0 0x200000 /* Memory DMA Stream 0 */
+#define MDMA1 0x400000 /* Memory DMA Stream 1 */
+#define WDOG 0x800000 /* Watchdog Timer */
+#define DMA1_ERR 0x1000000 /* DMA Controller 1 Error */
+#define SPORT2_ERR 0x2000000 /* SPORT2 Error */
+#define SPORT3_ERR 0x4000000 /* SPORT3 Error */
+#define MXVR_SD 0x8000000 /* MXVR Synchronous Data */
+#define SPI1_ERR 0x10000000 /* SPI1 Error */
+#define SPI2_ERR 0x20000000 /* SPI2 Error */
+#define UART1_ERR 0x40000000 /* UART1 Error */
+#define UART2_ERR 0x80000000 /* UART2 Error */
/* Bit masks for SIC_IWR1, SIC_IMASK1, SIC_ISR1 */
-#define IRQ_CAN0_ERR 0x1 /* CAN0 Error */
-#define nIRQ_CAN0_ERR 0x0
-#define IRQ_DMA18 0x2 /* DMA Channel 18 */
-#define nIRQ_DMA18 0x0
-#define IRQ_DMA19 0x4 /* DMA Channel 19 */
-#define nIRQ_DMA19 0x0
-#define IRQ_DMA20 0x8 /* DMA Channel 20 */
-#define nIRQ_DMA20 0x0
-#define IRQ_DMA21 0x10 /* DMA Channel 21 */
-#define nIRQ_DMA21 0x0
-#define IRQ_DMA13 0x20 /* DMA Channel 13 */
-#define nIRQ_DMA13 0x0
-#define IRQ_DMA14 0x40 /* DMA Channel 14 */
-#define nIRQ_DMA14 0x0
-#define IRQ_DMA5 0x80 /* DMA Channel 5 */
-#define nIRQ_DMA5 0x0
-#define IRQ_DMA23 0x100 /* DMA Channel 23 */
-#define nIRQ_DMA23 0x0
-#define IRQ_DMA8 0x200 /* DMA Channel 8 */
-#define nIRQ_DMA8 0x0
-#define IRQ_DMA9 0x400 /* DMA Channel 9 */
-#define nIRQ_DMA9 0x0
-#define IRQ_DMA10 0x800 /* DMA Channel 10 */
-#define nIRQ_DMA10 0x0
-#define IRQ_DMA11 0x1000 /* DMA Channel 11 */
-#define nIRQ_DMA11 0x0
-#define IRQ_TWI0 0x2000 /* TWI0 */
-#define nIRQ_TWI0 0x0
-#define IRQ_TWI1 0x4000 /* TWI1 */
-#define nIRQ_TWI1 0x0
-#define IRQ_CAN0_RX 0x8000 /* CAN0 Receive */
-#define nIRQ_CAN0_RX 0x0
-#define IRQ_CAN0_TX 0x10000 /* CAN0 Transmit */
-#define nIRQ_CAN0_TX 0x0
-#define IRQ_MDMA2 0x20000 /* Memory DMA Stream 0 */
-#define nIRQ_MDMA2 0x0
-#define IRQ_MDMA3 0x40000 /* Memory DMA Stream 1 */
-#define nIRQ_MDMA3 0x0
-#define IRQ_MXVR_STAT 0x80000 /* MXVR Status */
-#define nIRQ_MXVR_STAT 0x0
-#define IRQ_MXVR_CM 0x100000 /* MXVR Control Message */
-#define nIRQ_MXVR_CM 0x0
-#define IRQ_MXVR_AP 0x200000 /* MXVR Asynchronous Packet */
-#define nIRQ_MXVR_AP 0x0
-#define IRQ_EPPI1_ERR 0x400000 /* EPPI1 Error */
-#define nIRQ_EPPI1_ERR 0x0
-#define IRQ_EPPI2_ERR 0x800000 /* EPPI2 Error */
-#define nIRQ_EPPI2_ERR 0x0
-#define IRQ_UART3_ERR 0x1000000 /* UART3 Error */
-#define nIRQ_UART3_ERR 0x0
-#define IRQ_HOST_ERR 0x2000000 /* Host DMA Port Error */
-#define nIRQ_HOST_ERR 0x0
-#define IRQ_USB_ERR 0x4000000 /* USB Error */
-#define nIRQ_USB_ERR 0x0
-#define IRQ_PIXC_ERR 0x8000000 /* Pixel Compositor Error */
-#define nIRQ_PIXC_ERR 0x0
-#define IRQ_NFC_ERR 0x10000000 /* Nand Flash Controller Error */
-#define nIRQ_NFC_ERR 0x0
-#define IRQ_ATAPI_ERR 0x20000000 /* ATAPI Error */
-#define nIRQ_ATAPI_ERR 0x0
-#define IRQ_CAN1_ERR 0x40000000 /* CAN1 Error */
-#define nIRQ_CAN1_ERR 0x0
-#define IRQ_DMAR0_ERR 0x80000000 /* DMAR0 Overflow Error */
-#define nIRQ_DMAR0_ERR 0x0
-#define IRQ_DMAR1_ERR 0x80000000 /* DMAR1 Overflow Error */
-#define nIRQ_DMAR1_ERR 0x0
-#define IRQ_DMAR0 0x80000000 /* DMAR0 Block */
-#define nIRQ_DMAR0 0x0
-#define IRQ_DMAR1 0x80000000 /* DMAR1 Block */
-#define nIRQ_DMAR1 0x0
+#define CAN0_ERR 0x1 /* CAN0 Error */
+#define DMA18 0x2 /* DMA Channel 18 */
+#define DMA19 0x4 /* DMA Channel 19 */
+#define DMA20 0x8 /* DMA Channel 20 */
+#define DMA21 0x10 /* DMA Channel 21 */
+#define DMA13 0x20 /* DMA Channel 13 */
+#define DMA14 0x40 /* DMA Channel 14 */
+#define DMA5 0x80 /* DMA Channel 5 */
+#define DMA23 0x100 /* DMA Channel 23 */
+#define DMA8 0x200 /* DMA Channel 8 */
+#define DMA9 0x400 /* DMA Channel 9 */
+#define DMA10 0x800 /* DMA Channel 10 */
+#define DMA11 0x1000 /* DMA Channel 11 */
+#define TWI0 0x2000 /* TWI0 */
+#define TWI1 0x4000 /* TWI1 */
+#define CAN0_RX 0x8000 /* CAN0 Receive */
+#define CAN0_TX 0x10000 /* CAN0 Transmit */
+#define MDMA2 0x20000 /* Memory DMA Stream 0 */
+#define MDMA3 0x40000 /* Memory DMA Stream 1 */
+#define MXVR_STAT 0x80000 /* MXVR Status */
+#define MXVR_CM 0x100000 /* MXVR Control Message */
+#define MXVR_AP 0x200000 /* MXVR Asynchronous Packet */
+#define EPPI1_ERR 0x400000 /* EPPI1 Error */
+#define EPPI2_ERR 0x800000 /* EPPI2 Error */
+#define UART3_ERR 0x1000000 /* UART3 Error */
+#define HOST_ERR 0x2000000 /* Host DMA Port Error */
+#define USB_ERR 0x4000000 /* USB Error */
+#define PIXC_ERR 0x8000000 /* Pixel Compositor Error */
+#define NFC_ERR 0x10000000 /* Nand Flash Controller Error */
+#define ATAPI_ERR 0x20000000 /* ATAPI Error */
+#define CAN1_ERR 0x40000000 /* CAN1 Error */
+#define DMAR0_ERR 0x80000000 /* DMAR0 Overflow Error */
+#define DMAR1_ERR 0x80000000 /* DMAR1 Overflow Error */
+#define DMAR0 0x80000000 /* DMAR0 Block */
+#define DMAR1 0x80000000 /* DMAR1 Block */
/* Bit masks for SIC_IWR2, SIC_IMASK2, SIC_ISR2 */
-#define IRQ_DMA15 0x1 /* DMA Channel 15 */
-#define nIRQ_DMA15 0x0
-#define IRQ_DMA16 0x2 /* DMA Channel 16 */
-#define nIRQ_DMA16 0x0
-#define IRQ_DMA17 0x4 /* DMA Channel 17 */
-#define nIRQ_DMA17 0x0
-#define IRQ_DMA22 0x8 /* DMA Channel 22 */
-#define nIRQ_DMA22 0x0
-#define IRQ_CNT 0x10 /* Counter */
-#define nIRQ_CNT 0x0
-#define IRQ_KEY 0x20 /* Keypad */
-#define nIRQ_KEY 0x0
-#define IRQ_CAN1_RX 0x40 /* CAN1 Receive */
-#define nIRQ_CAN1_RX 0x0
-#define IRQ_CAN1_TX 0x80 /* CAN1 Transmit */
-#define nIRQ_CAN1_TX 0x0
-#define IRQ_SDH_MASK0 0x100 /* SDH Mask 0 */
-#define nIRQ_SDH_MASK0 0x0
-#define IRQ_SDH_MASK1 0x200 /* SDH Mask 1 */
-#define nIRQ_SDH_MASK1 0x0
-#define IRQ_USB_EINT 0x400 /* USB Exception */
-#define nIRQ_USB_EINT 0x0
-#define IRQ_USB_INT0 0x800 /* USB Interrupt 0 */
-#define nIRQ_USB_INT0 0x0
-#define IRQ_USB_INT1 0x1000 /* USB Interrupt 1 */
-#define nIRQ_USB_INT1 0x0
-#define IRQ_USB_INT2 0x2000 /* USB Interrupt 2 */
-#define nIRQ_USB_INT2 0x0
-#define IRQ_USB_DMAINT 0x4000 /* USB DMA */
-#define nIRQ_USB_DMAINT 0x0
-#define IRQ_OTPSEC 0x8000 /* OTP Access Complete */
-#define nIRQ_OTPSEC 0x0
-#define IRQ_TIMER0 0x400000 /* Timer 0 */
-#define nIRQ_TIMER0 0x0
-#define IRQ_TIMER1 0x800000 /* Timer 1 */
-#define nIRQ_TIMER1 0x0
-#define IRQ_TIMER2 0x1000000 /* Timer 2 */
-#define nIRQ_TIMER2 0x0
-#define IRQ_TIMER3 0x2000000 /* Timer 3 */
-#define nIRQ_TIMER3 0x0
-#define IRQ_TIMER4 0x4000000 /* Timer 4 */
-#define nIRQ_TIMER4 0x0
-#define IRQ_TIMER5 0x8000000 /* Timer 5 */
-#define nIRQ_TIMER5 0x0
-#define IRQ_TIMER6 0x10000000 /* Timer 6 */
-#define nIRQ_TIMER6 0x0
-#define IRQ_TIMER7 0x20000000 /* Timer 7 */
-#define nIRQ_TIMER7 0x0
-#define IRQ_PINT2 0x40000000 /* Pin Interrupt 2 */
-#define nIRQ_PINT2 0x0
-#define IRQ_PINT3 0x80000000 /* Pin Interrupt 3 */
-#define nIRQ_PINT3 0x0
+#define DMA15 0x1 /* DMA Channel 15 */
+#define DMA16 0x2 /* DMA Channel 16 */
+#define DMA17 0x4 /* DMA Channel 17 */
+#define DMA22 0x8 /* DMA Channel 22 */
+#define CNT 0x10 /* Counter */
+#define KEY 0x20 /* Keypad */
+#define CAN1_RX 0x40 /* CAN1 Receive */
+#define CAN1_TX 0x80 /* CAN1 Transmit */
+#define SDH_INT_MASK0 0x100 /* SDH Mask 0 */
+#define SDH_INT_MASK1 0x200 /* SDH Mask 1 */
+#define USB_EINT 0x400 /* USB Exception */
+#define USB_INT0 0x800 /* USB Interrupt 0 */
+#define USB_INT1 0x1000 /* USB Interrupt 1 */
+#define USB_INT2 0x2000 /* USB Interrupt 2 */
+#define USB_DMAINT 0x4000 /* USB DMA */
+#define OTPSEC 0x8000 /* OTP Access Complete */
+#define TIMER0 0x400000 /* Timer 0 */
+#define TIMER1 0x800000 /* Timer 1 */
+#define TIMER2 0x1000000 /* Timer 2 */
+#define TIMER3 0x2000000 /* Timer 3 */
+#define TIMER4 0x4000000 /* Timer 4 */
+#define TIMER5 0x8000000 /* Timer 5 */
+#define TIMER6 0x10000000 /* Timer 6 */
+#define TIMER7 0x20000000 /* Timer 7 */
+#define PINT2 0x40000000 /* Pin Interrupt 2 */
+#define PINT3 0x80000000 /* Pin Interrupt 3 */
/* Bit masks for DMAx_CONFIG, MDMA_Sx_CONFIG, MDMA_Dx_CONFIG */
#define DMAEN 0x1 /* DMA Channel Enable */
-#define nDMAEN 0x0
#define WNR 0x2 /* DMA Direction */
-#define nWNR 0x0
-#define WDSIZE 0xc /* Transfer Word Size */
+#define WDSIZE_8 0x0 /* Transfer Word Size = 8 */
+#define WDSIZE_16 0x4 /* Transfer Word Size = 16 */
+#define WDSIZE_32 0x8 /* Transfer Word Size = 32 */
#define DMA2D 0x10 /* DMA Mode */
-#define nDMA2D 0x0
#define RESTART 0x20 /* Work Unit Transitions */
-#define nRESTART 0x0
#define DI_SEL 0x40 /* Data Interrupt Timing Select */
-#define nDI_SEL 0x0
#define DI_EN 0x80 /* Data Interrupt Enable */
-#define nDI_EN 0x0
#define NDSIZE 0xf00 /* Flex Descriptor Size */
#define DMAFLOW 0xf000 /* Next Operation */
/* Bit masks for DMAx_IRQ_STATUS, MDMA_Sx_IRQ_STATUS, MDMA_Dx_IRQ_STATUS */
#define DMA_DONE 0x1 /* DMA Completion Interrupt Status */
-#define nDMA_DONE 0x0
#define DMA_ERR 0x2 /* DMA Error Interrupt Status */
-#define nDMA_ERR 0x0
#define DFETCH 0x4 /* DMA Descriptor Fetch */
-#define nDFETCH 0x0
#define DMA_RUN 0x8 /* DMA Channel Running */
-#define nDMA_RUN 0x0
/* Bit masks for DMAx_PERIPHERAL_MAP, MDMA_Sx_IRQ_STATUS, MDMA_Dx_IRQ_STATUS */
#define CTYPE 0x40 /* DMA Channel Type */
-#define nCTYPE 0x0
#define PMAP 0xf000 /* Peripheral Mapped To This Channel */
/* Bit masks for DMACx_TCPER */
@@ -1756,29 +1669,28 @@
/* Bit masks for DMAC1_PERIMUX */
#define PMUXSDH 0x1 /* Peripheral Select for DMA22 channel */
-#define nPMUXSDH 0x0
-/* Bit masks for EBIU_AMGCTL */
+/* ********************* ASYNCHRONOUS MEMORY CONTROLLER MASKS *************************/
+/* EBIU_AMGCTL Masks */
+#define AMCKEN 0x0001 /* Enable CLKOUT */
+#define AMBEN_NONE 0x0000 /* All Banks Disabled */
+#define AMBEN_B0 0x0002 /* Enable Async Memory Bank 0 only */
+#define AMBEN_B0_B1 0x0004 /* Enable Async Memory Banks 0 & 1 only */
+#define AMBEN_B0_B1_B2 0x0006 /* Enable Async Memory Banks 0, 1, and 2 */
+#define AMBEN_ALL 0x0008 /* Enable Async Memory Banks (all) 0, 1, 2, and 3 */
-#define AMCKEN 0x1 /* Async Memory Enable */
-#define nAMCKEN 0x0
-#define AMBEN 0xe /* Async bank enable */
/* Bit masks for EBIU_AMBCTL0 */
#define B0RDYEN 0x1 /* Bank 0 ARDY Enable */
-#define nB0RDYEN 0x0
#define B0RDYPOL 0x2 /* Bank 0 ARDY Polarity */
-#define nB0RDYPOL 0x0
#define B0TT 0xc /* Bank 0 transition time */
#define B0ST 0x30 /* Bank 0 Setup time */
#define B0HT 0xc0 /* Bank 0 Hold time */
#define B0RAT 0xf00 /* Bank 0 Read access time */
#define B0WAT 0xf000 /* Bank 0 write access time */
#define B1RDYEN 0x10000 /* Bank 1 ARDY Enable */
-#define nB1RDYEN 0x0
#define B1RDYPOL 0x20000 /* Bank 1 ARDY Polarity */
-#define nB1RDYPOL 0x0
#define B1TT 0xc0000 /* Bank 1 transition time */
#define B1ST 0x300000 /* Bank 1 Setup time */
#define B1HT 0xc00000 /* Bank 1 Hold time */
@@ -1788,18 +1700,14 @@
/* Bit masks for EBIU_AMBCTL1 */
#define B2RDYEN 0x1 /* Bank 2 ARDY Enable */
-#define nB2RDYEN 0x0
#define B2RDYPOL 0x2 /* Bank 2 ARDY Polarity */
-#define nB2RDYPOL 0x0
#define B2TT 0xc /* Bank 2 transition time */
#define B2ST 0x30 /* Bank 2 Setup time */
#define B2HT 0xc0 /* Bank 2 Hold time */
#define B2RAT 0xf00 /* Bank 2 Read access time */
#define B2WAT 0xf000 /* Bank 2 write access time */
#define B3RDYEN 0x10000 /* Bank 3 ARDY Enable */
-#define nB3RDYEN 0x0
#define B3RDYPOL 0x20000 /* Bank 3 ARDY Polarity */
-#define nB3RDYPOL 0x0
#define B3TT 0xc0000 /* Bank 3 transition time */
#define B3ST 0x300000 /* Bank 3 Setup time */
#define B3HT 0xc00000 /* Bank 3 Hold time */
@@ -1823,19 +1731,15 @@
/* Bit masks for EBIU_FCTL */
#define TESTSETLOCK 0x1 /* Test set lock */
-#define nTESTSETLOCK 0x0
#define BCLK 0x6 /* Burst clock frequency */
#define PGWS 0x38 /* Page wait states */
#define PGSZ 0x40 /* Page size */
-#define nPGSZ 0x0
#define RDDL 0x380 /* Read data delay */
/* Bit masks for EBIU_ARBSTAT */
#define ARBSTAT 0x1 /* Arbitration status */
-#define nARBSTAT 0x0
#define BGSTAT 0x2 /* Bus grant status */
-#define nBGSTAT 0x0
/* Bit masks for EBIU_DDRCTL0 */
@@ -1861,9 +1765,7 @@
#define BURSTLENGTH 0x7 /* Burst length */
#define CASLATENCY 0x70 /* CAS latency */
#define DLLRESET 0x100 /* DLL Reset */
-#define nDLLRESET 0x0
#define REGE 0x1000 /* Register mode enable */
-#define nREGE 0x0
/* Bit masks for EBIU_DDRCTL3 */
@@ -1876,30 +1778,19 @@
#define DEB3_PFLEN 0x30 /* Pre fetch length for DEB3 accesses */
#define DEB_ARB_PRIORITY 0x700 /* Arbitration between DEB busses */
#define DEB1_URGENT 0x1000 /* DEB1 Urgent */
-#define nDEB1_URGENT 0x0
#define DEB2_URGENT 0x2000 /* DEB2 Urgent */
-#define nDEB2_URGENT 0x0
#define DEB3_URGENT 0x4000 /* DEB3 Urgent */
-#define nDEB3_URGENT 0x0
/* Bit masks for EBIU_ERRMST */
#define DEB1_ERROR 0x1 /* DEB1 Error */
-#define nDEB1_ERROR 0x0
#define DEB2_ERROR 0x2 /* DEB2 Error */
-#define nDEB2_ERROR 0x0
#define DEB3_ERROR 0x4 /* DEB3 Error */
-#define nDEB3_ERROR 0x0
#define CORE_ERROR 0x8 /* Core error */
-#define nCORE_ERROR 0x0
#define DEB_MERROR 0x10 /* DEB1 Error (2nd) */
-#define nDEB_MERROR 0x0
#define DEB2_MERROR 0x20 /* DEB2 Error (2nd) */
-#define nDEB2_MERROR 0x0
#define DEB3_MERROR 0x40 /* DEB3 Error (2nd) */
-#define nDEB3_MERROR 0x0
#define CORE_MERROR 0x80 /* Core Error (2nd) */
-#define nCORE_MERROR 0x0
/* Bit masks for EBIU_ERRADD */
@@ -1908,15 +1799,10 @@
/* Bit masks for EBIU_RSTCTL */
#define DDRSRESET 0x1 /* DDR soft reset */
-#define nDDRSRESET 0x0
#define PFTCHSRESET 0x4 /* DDR prefetch reset */
-#define nPFTCHSRESET 0x0
#define SRREQ 0x8 /* Self-refresh request */
-#define nSRREQ 0x0
#define SRACK 0x10 /* Self-refresh acknowledge */
-#define nSRACK 0x0
#define MDDRENABLE 0x20 /* Mobile DDR enable */
-#define nMDDRENABLE 0x0
/* Bit masks for EBIU_DDRBRC0 */
@@ -2013,136 +1899,74 @@
/* Bit masks for EBIU_DDRMCEN */
#define B0WCENABLE 0x1 /* Bank 0 write count enable */
-#define nB0WCENABLE 0x0
#define B1WCENABLE 0x2 /* Bank 1 write count enable */
-#define nB1WCENABLE 0x0
#define B2WCENABLE 0x4 /* Bank 2 write count enable */
-#define nB2WCENABLE 0x0
#define B3WCENABLE 0x8 /* Bank 3 write count enable */
-#define nB3WCENABLE 0x0
#define B4WCENABLE 0x10 /* Bank 4 write count enable */
-#define nB4WCENABLE 0x0
#define B5WCENABLE 0x20 /* Bank 5 write count enable */
-#define nB5WCENABLE 0x0
#define B6WCENABLE 0x40 /* Bank 6 write count enable */
-#define nB6WCENABLE 0x0
#define B7WCENABLE 0x80 /* Bank 7 write count enable */
-#define nB7WCENABLE 0x0
#define B0RCENABLE 0x100 /* Bank 0 read count enable */
-#define nB0RCENABLE 0x0
#define B1RCENABLE 0x200 /* Bank 1 read count enable */
-#define nB1RCENABLE 0x0
#define B2RCENABLE 0x400 /* Bank 2 read count enable */
-#define nB2RCENABLE 0x0
#define B3RCENABLE 0x800 /* Bank 3 read count enable */
-#define nB3RCENABLE 0x0
#define B4RCENABLE 0x1000 /* Bank 4 read count enable */
-#define nB4RCENABLE 0x0
#define B5RCENABLE 0x2000 /* Bank 5 read count enable */
-#define nB5RCENABLE 0x0
#define B6RCENABLE 0x4000 /* Bank 6 read count enable */
-#define nB6RCENABLE 0x0
#define B7RCENABLE 0x8000 /* Bank 7 read count enable */
-#define nB7RCENABLE 0x0
#define ROWACTCENABLE 0x10000 /* DDR Row activate count enable */
-#define nROWACTCENABLE 0x0
#define RWTCENABLE 0x20000 /* DDR R/W Turn around count enable */
-#define nRWTCENABLE 0x0
#define ARCENABLE 0x40000 /* DDR Auto-refresh count enable */
-#define nARCENABLE 0x0
#define GC0ENABLE 0x100000 /* DDR Grant count 0 enable */
-#define nGC0ENABLE 0x0
#define GC1ENABLE 0x200000 /* DDR Grant count 1 enable */
-#define nGC1ENABLE 0x0
#define GC2ENABLE 0x400000 /* DDR Grant count 2 enable */
-#define nGC2ENABLE 0x0
#define GC3ENABLE 0x800000 /* DDR Grant count 3 enable */
-#define nGC3ENABLE 0x0
#define GCCONTROL 0x3000000 /* DDR Grant Count Control */
/* Bit masks for EBIU_DDRMCCL */
#define CB0WCOUNT 0x1 /* Clear write count 0 */
-#define nCB0WCOUNT 0x0
#define CB1WCOUNT 0x2 /* Clear write count 1 */
-#define nCB1WCOUNT 0x0
#define CB2WCOUNT 0x4 /* Clear write count 2 */
-#define nCB2WCOUNT 0x0
#define CB3WCOUNT 0x8 /* Clear write count 3 */
-#define nCB3WCOUNT 0x0
#define CB4WCOUNT 0x10 /* Clear write count 4 */
-#define nCB4WCOUNT 0x0
#define CB5WCOUNT 0x20 /* Clear write count 5 */
-#define nCB5WCOUNT 0x0
#define CB6WCOUNT 0x40 /* Clear write count 6 */
-#define nCB6WCOUNT 0x0
#define CB7WCOUNT 0x80 /* Clear write count 7 */
-#define nCB7WCOUNT 0x0
#define CBRCOUNT 0x100 /* Clear read count 0 */
-#define nCBRCOUNT 0x0
#define CB1RCOUNT 0x200 /* Clear read count 1 */
-#define nCB1RCOUNT 0x0
#define CB2RCOUNT 0x400 /* Clear read count 2 */
-#define nCB2RCOUNT 0x0
#define CB3RCOUNT 0x800 /* Clear read count 3 */
-#define nCB3RCOUNT 0x0
#define CB4RCOUNT 0x1000 /* Clear read count 4 */
-#define nCB4RCOUNT 0x0
#define CB5RCOUNT 0x2000 /* Clear read count 5 */
-#define nCB5RCOUNT 0x0
#define CB6RCOUNT 0x4000 /* Clear read count 6 */
-#define nCB6RCOUNT 0x0
#define CB7RCOUNT 0x8000 /* Clear read count 7 */
-#define nCB7RCOUNT 0x0
#define CRACOUNT 0x10000 /* Clear row activation count */
-#define nCRACOUNT 0x0
#define CRWTACOUNT 0x20000 /* Clear R/W turn-around count */
-#define nCRWTACOUNT 0x0
#define CARCOUNT 0x40000 /* Clear auto-refresh count */
-#define nCARCOUNT 0x0
#define CG0COUNT 0x100000 /* Clear grant count 0 */
-#define nCG0COUNT 0x0
#define CG1COUNT 0x200000 /* Clear grant count 1 */
-#define nCG1COUNT 0x0
#define CG2COUNT 0x400000 /* Clear grant count 2 */
-#define nCG2COUNT 0x0
#define CG3COUNT 0x800000 /* Clear grant count 3 */
-#define nCG3COUNT 0x0
/* Bit masks for (PORTx is PORTA - PORTJ) includes PORTx_FER, PORTx_SET, PORTx_CLEAR, PORTx_DIR_SET, PORTx_DIR_CLEAR, PORTx_INEN */
#define Px0 0x1 /* GPIO 0 */
-#define nPx0 0x0
#define Px1 0x2 /* GPIO 1 */
-#define nPx1 0x0
#define Px2 0x4 /* GPIO 2 */
-#define nPx2 0x0
#define Px3 0x8 /* GPIO 3 */
-#define nPx3 0x0
#define Px4 0x10 /* GPIO 4 */
-#define nPx4 0x0
#define Px5 0x20 /* GPIO 5 */
-#define nPx5 0x0
#define Px6 0x40 /* GPIO 6 */
-#define nPx6 0x0
#define Px7 0x80 /* GPIO 7 */
-#define nPx7 0x0
#define Px8 0x100 /* GPIO 8 */
-#define nPx8 0x0
#define Px9 0x200 /* GPIO 9 */
-#define nPx9 0x0
#define Px10 0x400 /* GPIO 10 */
-#define nPx10 0x0
#define Px11 0x800 /* GPIO 11 */
-#define nPx11 0x0
#define Px12 0x1000 /* GPIO 12 */
-#define nPx12 0x0
#define Px13 0x2000 /* GPIO 13 */
-#define nPx13 0x0
#define Px14 0x4000 /* GPIO 14 */
-#define nPx14 0x0
#define Px15 0x8000 /* GPIO 15 */
-#define nPx15 0x0
/* Bit masks for PORTA_MUX - PORTJ_MUX */
@@ -2167,223 +1991,129 @@
/* Bit masks for PINTx_MASK_SET/CLEAR, PINTx_REQUEST, PINTx_LATCH, PINTx_EDGE_SET/CLEAR, PINTx_INVERT_SET/CLEAR, PINTx_PINTSTATE */
#define IB0 0x1 /* Interrupt Bit 0 */
-#define nIB0 0x0
#define IB1 0x2 /* Interrupt Bit 1 */
-#define nIB1 0x0
#define IB2 0x4 /* Interrupt Bit 2 */
-#define nIB2 0x0
#define IB3 0x8 /* Interrupt Bit 3 */
-#define nIB3 0x0
#define IB4 0x10 /* Interrupt Bit 4 */
-#define nIB4 0x0
#define IB5 0x20 /* Interrupt Bit 5 */
-#define nIB5 0x0
#define IB6 0x40 /* Interrupt Bit 6 */
-#define nIB6 0x0
#define IB7 0x80 /* Interrupt Bit 7 */
-#define nIB7 0x0
#define IB8 0x100 /* Interrupt Bit 8 */
-#define nIB8 0x0
#define IB9 0x200 /* Interrupt Bit 9 */
-#define nIB9 0x0
#define IB10 0x400 /* Interrupt Bit 10 */
-#define nIB10 0x0
#define IB11 0x800 /* Interrupt Bit 11 */
-#define nIB11 0x0
#define IB12 0x1000 /* Interrupt Bit 12 */
-#define nIB12 0x0
#define IB13 0x2000 /* Interrupt Bit 13 */
-#define nIB13 0x0
#define IB14 0x4000 /* Interrupt Bit 14 */
-#define nIB14 0x0
#define IB15 0x8000 /* Interrupt Bit 15 */
-#define nIB15 0x0
/* Bit masks for TIMERx_CONFIG */
#define TMODE 0x3 /* Timer Mode */
#define PULSE_HI 0x4 /* Pulse Polarity */
-#define nPULSE_HI 0x0
#define PERIOD_CNT 0x8 /* Period Count */
-#define nPERIOD_CNT 0x0
#define IRQ_ENA 0x10 /* Interrupt Request Enable */
-#define nIRQ_ENA 0x0
#define TIN_SEL 0x20 /* Timer Input Select */
-#define nTIN_SEL 0x0
#define OUT_DIS 0x40 /* Output Pad Disable */
-#define nOUT_DIS 0x0
#define CLK_SEL 0x80 /* Timer Clock Select */
-#define nCLK_SEL 0x0
#define TOGGLE_HI 0x100 /* Toggle Mode */
-#define nTOGGLE_HI 0x0
#define EMU_RUN 0x200 /* Emulation Behavior Select */
-#define nEMU_RUN 0x0
#define ERR_TYP 0xc000 /* Error Type */
/* Bit masks for TIMER_ENABLE0 */
#define TIMEN0 0x1 /* Timer 0 Enable */
-#define nTIMEN0 0x0
#define TIMEN1 0x2 /* Timer 1 Enable */
-#define nTIMEN1 0x0
#define TIMEN2 0x4 /* Timer 2 Enable */
-#define nTIMEN2 0x0
#define TIMEN3 0x8 /* Timer 3 Enable */
-#define nTIMEN3 0x0
#define TIMEN4 0x10 /* Timer 4 Enable */
-#define nTIMEN4 0x0
#define TIMEN5 0x20 /* Timer 5 Enable */
-#define nTIMEN5 0x0
#define TIMEN6 0x40 /* Timer 6 Enable */
-#define nTIMEN6 0x0
#define TIMEN7 0x80 /* Timer 7 Enable */
-#define nTIMEN7 0x0
/* Bit masks for TIMER_DISABLE0 */
#define TIMDIS0 0x1 /* Timer 0 Disable */
-#define nTIMDIS0 0x0
#define TIMDIS1 0x2 /* Timer 1 Disable */
-#define nTIMDIS1 0x0
#define TIMDIS2 0x4 /* Timer 2 Disable */
-#define nTIMDIS2 0x0
#define TIMDIS3 0x8 /* Timer 3 Disable */
-#define nTIMDIS3 0x0
#define TIMDIS4 0x10 /* Timer 4 Disable */
-#define nTIMDIS4 0x0
#define TIMDIS5 0x20 /* Timer 5 Disable */
-#define nTIMDIS5 0x0
#define TIMDIS6 0x40 /* Timer 6 Disable */
-#define nTIMDIS6 0x0
#define TIMDIS7 0x80 /* Timer 7 Disable */
-#define nTIMDIS7 0x0
/* Bit masks for TIMER_STATUS0 */
#define TIMIL0 0x1 /* Timer 0 Interrupt */
-#define nTIMIL0 0x0
#define TIMIL1 0x2 /* Timer 1 Interrupt */
-#define nTIMIL1 0x0
#define TIMIL2 0x4 /* Timer 2 Interrupt */
-#define nTIMIL2 0x0
#define TIMIL3 0x8 /* Timer 3 Interrupt */
-#define nTIMIL3 0x0
#define TOVF_ERR0 0x10 /* Timer 0 Counter Overflow */
-#define nTOVF_ERR0 0x0
#define TOVF_ERR1 0x20 /* Timer 1 Counter Overflow */
-#define nTOVF_ERR1 0x0
#define TOVF_ERR2 0x40 /* Timer 2 Counter Overflow */
-#define nTOVF_ERR2 0x0
#define TOVF_ERR3 0x80 /* Timer 3 Counter Overflow */
-#define nTOVF_ERR3 0x0
#define TRUN0 0x1000 /* Timer 0 Slave Enable Status */
-#define nTRUN0 0x0
#define TRUN1 0x2000 /* Timer 1 Slave Enable Status */
-#define nTRUN1 0x0
#define TRUN2 0x4000 /* Timer 2 Slave Enable Status */
-#define nTRUN2 0x0
#define TRUN3 0x8000 /* Timer 3 Slave Enable Status */
-#define nTRUN3 0x0
#define TIMIL4 0x10000 /* Timer 4 Interrupt */
-#define nTIMIL4 0x0
#define TIMIL5 0x20000 /* Timer 5 Interrupt */
-#define nTIMIL5 0x0
#define TIMIL6 0x40000 /* Timer 6 Interrupt */
-#define nTIMIL6 0x0
#define TIMIL7 0x80000 /* Timer 7 Interrupt */
-#define nTIMIL7 0x0
#define TOVF_ERR4 0x100000 /* Timer 4 Counter Overflow */
-#define nTOVF_ERR4 0x0
#define TOVF_ERR5 0x200000 /* Timer 5 Counter Overflow */
-#define nTOVF_ERR5 0x0
#define TOVF_ERR6 0x400000 /* Timer 6 Counter Overflow */
-#define nTOVF_ERR6 0x0
#define TOVF_ERR7 0x800000 /* Timer 7 Counter Overflow */
-#define nTOVF_ERR7 0x0
#define TRUN4 0x10000000 /* Timer 4 Slave Enable Status */
-#define nTRUN4 0x0
#define TRUN5 0x20000000 /* Timer 5 Slave Enable Status */
-#define nTRUN5 0x0
#define TRUN6 0x40000000 /* Timer 6 Slave Enable Status */
-#define nTRUN6 0x0
#define TRUN7 0x80000000 /* Timer 7 Slave Enable Status */
-#define nTRUN7 0x0
/* Bit masks for WDOG_CTL */
#define WDEV 0x6 /* Watchdog Event */
#define WDEN 0xff0 /* Watchdog Enable */
#define WDRO 0x8000 /* Watchdog Rolled Over */
-#define nWDRO 0x0
/* Bit masks for CNT_CONFIG */
#define CNTE 0x1 /* Counter Enable */
-#define nCNTE 0x0
#define DEBE 0x2 /* Debounce Enable */
-#define nDEBE 0x0
#define CDGINV 0x10 /* CDG Pin Polarity Invert */
-#define nCDGINV 0x0
#define CUDINV 0x20 /* CUD Pin Polarity Invert */
-#define nCUDINV 0x0
#define CZMINV 0x40 /* CZM Pin Polarity Invert */
-#define nCZMINV 0x0
#define CNTMODE 0x700 /* Counter Operating Mode */
#define ZMZC 0x800 /* CZM Zeroes Counter Enable */
-#define nZMZC 0x0
#define BNDMODE 0x3000 /* Boundary register Mode */
#define INPDIS 0x8000 /* CUG and CDG Input Disable */
-#define nINPDIS 0x0
/* Bit masks for CNT_IMASK */
#define ICIE 0x1 /* Illegal Gray/Binary Code Interrupt Enable */
-#define nICIE 0x0
#define UCIE 0x2 /* Up count Interrupt Enable */
-#define nUCIE 0x0
#define DCIE 0x4 /* Down count Interrupt Enable */
-#define nDCIE 0x0
#define MINCIE 0x8 /* Min Count Interrupt Enable */
-#define nMINCIE 0x0
#define MAXCIE 0x10 /* Max Count Interrupt Enable */
-#define nMAXCIE 0x0
#define COV31IE 0x20 /* Bit 31 Overflow Interrupt Enable */
-#define nCOV31IE 0x0
#define COV15IE 0x40 /* Bit 15 Overflow Interrupt Enable */
-#define nCOV15IE 0x0
#define CZEROIE 0x80 /* Count to Zero Interrupt Enable */
-#define nCZEROIE 0x0
#define CZMIE 0x100 /* CZM Pin Interrupt Enable */
-#define nCZMIE 0x0
#define CZMEIE 0x200 /* CZM Error Interrupt Enable */
-#define nCZMEIE 0x0
#define CZMZIE 0x400 /* CZM Zeroes Counter Interrupt Enable */
-#define nCZMZIE 0x0
/* Bit masks for CNT_STATUS */
#define ICII 0x1 /* Illegal Gray/Binary Code Interrupt Identifier */
-#define nICII 0x0
#define UCII 0x2 /* Up count Interrupt Identifier */
-#define nUCII 0x0
#define DCII 0x4 /* Down count Interrupt Identifier */
-#define nDCII 0x0
#define MINCII 0x8 /* Min Count Interrupt Identifier */
-#define nMINCII 0x0
#define MAXCII 0x10 /* Max Count Interrupt Identifier */
-#define nMAXCII 0x0
#define COV31II 0x20 /* Bit 31 Overflow Interrupt Identifier */
-#define nCOV31II 0x0
#define COV15II 0x40 /* Bit 15 Overflow Interrupt Identifier */
-#define nCOV15II 0x0
#define CZEROII 0x80 /* Count to Zero Interrupt Identifier */
-#define nCZEROII 0x0
#define CZMII 0x100 /* CZM Pin Interrupt Identifier */
-#define nCZMII 0x0
#define CZMEII 0x200 /* CZM Error Interrupt Identifier */
-#define nCZMEII 0x0
#define CZMZII 0x400 /* CZM Zeroes Counter Interrupt Identifier */
-#define nCZMZII 0x0
/* Bit masks for CNT_COMMAND */
@@ -2391,7 +2121,6 @@
#define W1LMIN 0xf0 /* Load Min Register */
#define W1LMAX 0xf00 /* Load Max Register */
#define W1ZMONCE 0x1000 /* Enable CZM Clear Counter Once */
-#define nW1ZMONCE 0x0
/* Bit masks for CNT_DEBOUNCE */
@@ -2407,42 +2136,25 @@
/* Bit masks for RTC_ICTL */
#define STOPWATCH_INTERRUPT_ENABLE 0x1 /* Stopwatch Interrupt Enable */
-#define nSTOPWATCH_INTERRUPT_ENABLE 0x0
#define ALARM_INTERRUPT_ENABLE 0x2 /* Alarm Interrupt Enable */
-#define nALARM_INTERRUPT_ENABLE 0x0
#define SECONDS_INTERRUPT_ENABLE 0x4 /* Seconds Interrupt Enable */
-#define nSECONDS_INTERRUPT_ENABLE 0x0
#define MINUTES_INTERRUPT_ENABLE 0x8 /* Minutes Interrupt Enable */
-#define nMINUTES_INTERRUPT_ENABLE 0x0
#define HOURS_INTERRUPT_ENABLE 0x10 /* Hours Interrupt Enable */
-#define nHOURS_INTERRUPT_ENABLE 0x0
#define TWENTY_FOUR_HOURS_INTERRUPT_ENABLE 0x20 /* 24 Hours Interrupt Enable */
-#define nTWENTY_FOUR_HOURS_INTERRUPT_ENABLE 0x0
#define DAY_ALARM_INTERRUPT_ENABLE 0x40 /* Day Alarm Interrupt Enable */
-#define nDAY_ALARM_INTERRUPT_ENABLE 0x0
#define WRITE_COMPLETE_INTERRUPT_ENABLE 0x8000 /* Write Complete Interrupt Enable */
-#define nWRITE_COMPLETE_INTERRUPT_ENABLE 0x0
/* Bit masks for RTC_ISTAT */
#define STOPWATCH_EVENT_FLAG 0x1 /* Stopwatch Event Flag */
-#define nSTOPWATCH_EVENT_FLAG 0x0
#define ALARM_EVENT_FLAG 0x2 /* Alarm Event Flag */
-#define nALARM_EVENT_FLAG 0x0
#define SECONDS_EVENT_FLAG 0x4 /* Seconds Event Flag */
-#define nSECONDS_EVENT_FLAG 0x0
#define MINUTES_EVENT_FLAG 0x8 /* Minutes Event Flag */
-#define nMINUTES_EVENT_FLAG 0x0
#define HOURS_EVENT_FLAG 0x10 /* Hours Event Flag */
-#define nHOURS_EVENT_FLAG 0x0
#define TWENTY_FOUR_HOURS_EVENT_FLAG 0x20 /* 24 Hours Event Flag */
-#define nTWENTY_FOUR_HOURS_EVENT_FLAG 0x0
#define DAY_ALARM_EVENT_FLAG 0x40 /* Day Alarm Event Flag */
-#define nDAY_ALARM_EVENT_FLAG 0x0
#define WRITE_PENDING__STATUS 0x4000 /* Write Pending Status */
-#define nWRITE_PENDING__STATUS 0x0
#define WRITE_COMPLETE 0x8000 /* Write Complete */
-#define nWRITE_COMPLETE 0x0
/* Bit masks for RTC_SWCNT */
@@ -2458,21 +2170,15 @@
/* Bit masks for RTC_PREN */
#define PREN 0x1 /* Prescaler Enable */
-#define nPREN 0x0
/* Bit masks for OTP_CONTROL */
#define FUSE_FADDR 0x1ff /* OTP/Fuse Address */
#define FIEN 0x800 /* OTP/Fuse Interrupt Enable */
-#define nFIEN 0x0
#define FTESTDEC 0x1000 /* OTP/Fuse Test Decoder */
-#define nFTESTDEC 0x0
#define FWRTEST 0x2000 /* OTP/Fuse Write Test */
-#define nFWRTEST 0x0
#define FRDEN 0x4000 /* OTP/Fuse Read Enable */
-#define nFRDEN 0x0
#define FWREN 0x8000 /* OTP/Fuse Write Enable */
-#define nFWREN 0x0
/* Bit masks for OTP_BEN */
@@ -2481,15 +2187,10 @@
/* Bit masks for OTP_STATUS */
#define FCOMP 0x1 /* OTP/Fuse Access Complete */
-#define nFCOMP 0x0
#define FERROR 0x2 /* OTP/Fuse Access Error */
-#define nFERROR 0x0
#define MMRGLOAD 0x10 /* Memory Mapped Register Gasket Load */
-#define nMMRGLOAD 0x0
#define MMRGLOCK 0x20 /* Memory Mapped Register Gasket Lock */
-#define nMMRGLOCK 0x0
#define FPGMEN 0x40 /* OTP/Fuse Program Enable */
-#define nFPGMEN 0x0
/* Bit masks for OTP_TIMING */
@@ -2503,42 +2204,29 @@
/* Bit masks for SECURE_SYSSWT */
#define EMUDABL 0x1 /* Emulation Disable. */
-#define nEMUDABL 0x0
#define RSTDABL 0x2 /* Reset Disable */
-#define nRSTDABL 0x0
#define L1IDABL 0x1c /* L1 Instruction Memory Disable. */
#define L1DADABL 0xe0 /* L1 Data Bank A Memory Disable. */
#define L1DBDABL 0x700 /* L1 Data Bank B Memory Disable. */
#define DMA0OVR 0x800 /* DMA0 Memory Access Override */
-#define nDMA0OVR 0x0
#define DMA1OVR 0x1000 /* DMA1 Memory Access Override */
-#define nDMA1OVR 0x0
#define EMUOVR 0x4000 /* Emulation Override */
-#define nEMUOVR 0x0
#define OTPSEN 0x8000 /* OTP Secrets Enable. */
-#define nOTPSEN 0x0
#define L2DABL 0x70000 /* L2 Memory Disable. */
/* Bit masks for SECURE_CONTROL */
#define SECURE0 0x1 /* SECURE 0 */
-#define nSECURE0 0x0
#define SECURE1 0x2 /* SECURE 1 */
-#define nSECURE1 0x0
#define SECURE2 0x4 /* SECURE 2 */
-#define nSECURE2 0x0
#define SECURE3 0x8 /* SECURE 3 */
-#define nSECURE3 0x0
/* Bit masks for SECURE_STATUS */
#define SECMODE 0x3 /* Secured Mode Control State */
#define NMI 0x4 /* Non Maskable Interrupt */
-#define nNMI 0x0
#define AFVALID 0x8 /* Authentication Firmware Valid */
-#define nAFVALID 0x0
#define AFEXIT 0x10 /* Authentication Firmware Exit */
-#define nAFEXIT 0x0
#define SECSTAT 0xe0 /* Secure Status */
/* Bit masks for PLL_DIV */
@@ -2550,42 +2238,25 @@
#define MSEL 0x7e00 /* Multiplier Select */
#define BYPASS 0x100 /* PLL Bypass Enable */
-#define nBYPASS 0x0
#define OUTPUT_DELAY 0x80 /* External Memory Output Delay Enable */
-#define nOUTPUT_DELAY 0x0
#define INPUT_DELAY 0x40 /* External Memory Input Delay Enable */
-#define nINPUT_DELAY 0x0
#define PDWN 0x20 /* Power Down */
-#define nPDWN 0x0
#define STOPCK 0x8 /* Stop Clock */
-#define nSTOPCK 0x0
#define PLL_OFF 0x2 /* Disable PLL */
-#define nPLL_OFF 0x0
#define DF 0x1 /* Divide Frequency */
-#define nDF 0x0
/* Bit masks for PLL_STAT */
#define PLL_LOCKED 0x20 /* PLL Locked Status */
-#define nPLL_LOCKED 0x0
#define ACTIVE_PLLDISABLED 0x4 /* Active Mode With PLL Disabled */
-#define nACTIVE_PLLDISABLED 0x0
#define FULL_ON 0x2 /* Full-On Mode */
-#define nFULL_ON 0x0
#define ACTIVE_PLLENABLED 0x1 /* Active Mode With PLL Enabled */
-#define nACTIVE_PLLENABLED 0x0
#define RTCWS 0x400 /* RTC/Reset Wake-Up Status */
-#define nRTCWS 0x0
#define CANWS 0x800 /* CAN Wake-Up Status */
-#define nCANWS 0x0
#define USBWS 0x2000 /* USB Wake-Up Status */
-#define nUSBWS 0x0
#define KPADWS 0x4000 /* Keypad Wake-Up Status */
-#define nKPADWS 0x0
#define ROTWS 0x8000 /* Rotary Wake-Up Status */
-#define nROTWS 0x0
#define GPWS 0x1000 /* General-Purpose Wake-Up Status */
-#define nGPWS 0x0
/* Bit masks for VR_CTL */
@@ -2593,79 +2264,52 @@
#define GAIN 0xc /* Voltage Output Level Gain */
#define VLEV 0xf0 /* Internal Voltage Level */
#define SCKELOW 0x8000 /* Drive SCKE Low During Reset Enable */
-#define nSCKELOW 0x0
#define WAKE 0x100 /* RTC/Reset Wake-Up Enable */
-#define nWAKE 0x0
#define CANWE 0x200 /* CAN0/1 Wake-Up Enable */
-#define nCANWE 0x0
#define GPWE 0x400 /* General-Purpose Wake-Up Enable */
-#define nGPWE 0x0
#define USBWE 0x800 /* USB Wake-Up Enable */
-#define nUSBWE 0x0
#define KPADWE 0x1000 /* Keypad Wake-Up Enable */
-#define nKPADWE 0x0
#define ROTWE 0x2000 /* Rotary Wake-Up Enable */
-#define nROTWE 0x0
/* Bit masks for NFC_CTL */
#define WR_DLY 0xf /* Write Strobe Delay */
#define RD_DLY 0xf0 /* Read Strobe Delay */
#define NWIDTH 0x100 /* NAND Data Width */
-#define nNWIDTH 0x0
#define PG_SIZE 0x200 /* Page Size */
-#define nPG_SIZE 0x0
/* Bit masks for NFC_STAT */
#define NBUSY 0x1 /* Not Busy */
-#define nNBUSY 0x0
#define WB_FULL 0x2 /* Write Buffer Full */
-#define nWB_FULL 0x0
#define PG_WR_STAT 0x4 /* Page Write Pending */
-#define nPG_WR_STAT 0x0
#define PG_RD_STAT 0x8 /* Page Read Pending */
-#define nPG_RD_STAT 0x0
#define WB_EMPTY 0x10 /* Write Buffer Empty */
-#define nWB_EMPTY 0x0
/* Bit masks for NFC_IRQSTAT */
#define NBUSYIRQ 0x1 /* Not Busy IRQ */
-#define nNBUSYIRQ 0x0
#define WB_OVF 0x2 /* Write Buffer Overflow */
-#define nWB_OVF 0x0
#define WB_EDGE 0x4 /* Write Buffer Edge Detect */
-#define nWB_EDGE 0x0
#define RD_RDY 0x8 /* Read Data Ready */
-#define nRD_RDY 0x0
#define WR_DONE 0x10 /* Page Write Done */
-#define nWR_DONE 0x0
/* Bit masks for NFC_IRQMASK */
#define MASK_BUSYIRQ 0x1 /* Mask Not Busy IRQ */
-#define nMASK_BUSYIRQ 0x0
#define MASK_WBOVF 0x2 /* Mask Write Buffer Overflow */
-#define nMASK_WBOVF 0x0
#define MASK_WBEMPTY 0x4 /* Mask Write Buffer Empty */
-#define nMASK_WBEMPTY 0x0
#define MASK_RDRDY 0x8 /* Mask Read Data Ready */
-#define nMASK_RDRDY 0x0
#define MASK_WRDONE 0x10 /* Mask Write Done */
-#define nMASK_WRDONE 0x0
/* Bit masks for NFC_RST */
#define ECC_RST 0x1 /* ECC (and NFC counters) Reset */
-#define nECC_RST 0x0
/* Bit masks for NFC_PGCTL */
#define PG_RD_START 0x1 /* Page Read Start */
-#define nPG_RD_START 0x0
#define PG_WR_START 0x2 /* Page Write Start */
-#define nPG_WR_START 0x0
/* Bit masks for NFC_ECC0 */
@@ -2690,56 +2334,34 @@
/* Bit masks for CAN0_CONTROL */
#define SRS 0x1 /* Software Reset */
-#define nSRS 0x0
#define DNM 0x2 /* DeviceNet Mode */
-#define nDNM 0x0
#define ABO 0x4 /* Auto Bus On */
-#define nABO 0x0
#define WBA 0x10 /* Wakeup On CAN Bus Activity */
-#define nWBA 0x0
#define SMR 0x20 /* Sleep Mode Request */
-#define nSMR 0x0
#define CSR 0x40 /* CAN Suspend Mode Request */
-#define nCSR 0x0
#define CCR 0x80 /* CAN Configuration Mode Request */
-#define nCCR 0x0
/* Bit masks for CAN0_STATUS */
#define WT 0x1 /* CAN Transmit Warning Flag */
-#define nWT 0x0
#define WR 0x2 /* CAN Receive Warning Flag */
-#define nWR 0x0
#define EP 0x4 /* CAN Error Passive Mode */
-#define nEP 0x0
#define EBO 0x8 /* CAN Error Bus Off Mode */
-#define nEBO 0x0
#define CSA 0x40 /* CAN Suspend Mode Acknowledge */
-#define nCSA 0x0
#define CCA 0x80 /* CAN Configuration Mode Acknowledge */
-#define nCCA 0x0
#define MBPTR 0x1f00 /* Mailbox Pointer */
#define TRM 0x4000 /* Transmit Mode Status */
-#define nTRM 0x0
#define REC 0x8000 /* Receive Mode Status */
-#define nREC 0x0
/* Bit masks for CAN0_DEBUG */
#define DEC 0x1 /* Disable Transmit/Receive Error Counters */
-#define nDEC 0x0
#define DRI 0x2 /* Disable CANRX Input Pin */
-#define nDRI 0x0
#define DTO 0x4 /* Disable CANTX Output Pin */
-#define nDTO 0x0
#define DIL 0x8 /* Disable Internal Loop */
-#define nDIL 0x0
#define MAA 0x10 /* Mode Auto-Acknowledge */
-#define nMAA 0x0
#define MRB 0x20 /* Mode Read Back */
-#define nMRB 0x0
#define CDE 0x8000 /* CAN Debug Mode Enable */
-#define nCDE 0x0
/* Bit masks for CAN0_CLOCK */
@@ -2749,111 +2371,69 @@
#define SJW 0x300 /* Synchronization Jump Width */
#define SAM 0x80 /* Sampling */
-#define nSAM 0x0
#define TSEG2 0x70 /* Time Segment 2 */
#define TSEG1 0xf /* Time Segment 1 */
/* Bit masks for CAN0_INTR */
#define CANRX 0x80 /* Serial Input From Transceiver */
-#define nCANRX 0x0
#define CANTX 0x40 /* Serial Output To Transceiver */
-#define nCANTX 0x0
#define SMACK 0x8 /* Sleep Mode Acknowledge */
-#define nSMACK 0x0
#define GIRQ 0x4 /* Global Interrupt Request Status */
-#define nGIRQ 0x0
#define MBTIRQ 0x2 /* Mailbox Transmit Interrupt Request */
-#define nMBTIRQ 0x0
#define MBRIRQ 0x1 /* Mailbox Receive Interrupt Request */
-#define nMBRIRQ 0x0
/* Bit masks for CAN0_GIM */
#define EWTIM 0x1 /* Error Warning Transmit Interrupt Mask */
-#define nEWTIM 0x0
#define EWRIM 0x2 /* Error Warning Receive Interrupt Mask */
-#define nEWRIM 0x0
#define EPIM 0x4 /* Error Passive Interrupt Mask */
-#define nEPIM 0x0
#define BOIM 0x8 /* Bus Off Interrupt Mask */
-#define nBOIM 0x0
#define WUIM 0x10 /* Wakeup Interrupt Mask */
-#define nWUIM 0x0
#define UIAIM 0x20 /* Unimplemented Address Interrupt Mask */
-#define nUIAIM 0x0
#define AAIM 0x40 /* Abort Acknowledge Interrupt Mask */
-#define nAAIM 0x0
#define RMLIM 0x80 /* Receive Message Lost Interrupt Mask */
-#define nRMLIM 0x0
#define UCEIM 0x100 /* Universal Counter Exceeded Interrupt Mask */
-#define nUCEIM 0x0
#define ADIM 0x400 /* Access Denied Interrupt Mask */
-#define nADIM 0x0
/* Bit masks for CAN0_GIS */
#define EWTIS 0x1 /* Error Warning Transmit Interrupt Status */
-#define nEWTIS 0x0
#define EWRIS 0x2 /* Error Warning Receive Interrupt Status */
-#define nEWRIS 0x0
#define EPIS 0x4 /* Error Passive Interrupt Status */
-#define nEPIS 0x0
#define BOIS 0x8 /* Bus Off Interrupt Status */
-#define nBOIS 0x0
#define WUIS 0x10 /* Wakeup Interrupt Status */
-#define nWUIS 0x0
#define UIAIS 0x20 /* Unimplemented Address Interrupt Status */
-#define nUIAIS 0x0
#define AAIS 0x40 /* Abort Acknowledge Interrupt Status */
-#define nAAIS 0x0
#define RMLIS 0x80 /* Receive Message Lost Interrupt Status */
-#define nRMLIS 0x0
#define UCEIS 0x100 /* Universal Counter Exceeded Interrupt Status */
-#define nUCEIS 0x0
#define ADIS 0x400 /* Access Denied Interrupt Status */
-#define nADIS 0x0
/* Bit masks for CAN0_GIF */
#define EWTIF 0x1 /* Error Warning Transmit Interrupt Flag */
-#define nEWTIF 0x0
#define EWRIF 0x2 /* Error Warning Receive Interrupt Flag */
-#define nEWRIF 0x0
#define EPIF 0x4 /* Error Passive Interrupt Flag */
-#define nEPIF 0x0
#define BOIF 0x8 /* Bus Off Interrupt Flag */
-#define nBOIF 0x0
#define WUIF 0x10 /* Wakeup Interrupt Flag */
-#define nWUIF 0x0
#define UIAIF 0x20 /* Unimplemented Address Interrupt Flag */
-#define nUIAIF 0x0
#define AAIF 0x40 /* Abort Acknowledge Interrupt Flag */
-#define nAAIF 0x0
#define RMLIF 0x80 /* Receive Message Lost Interrupt Flag */
-#define nRMLIF 0x0
#define UCEIF 0x100 /* Universal Counter Exceeded Interrupt Flag */
-#define nUCEIF 0x0
#define ADIF 0x400 /* Access Denied Interrupt Flag */
-#define nADIF 0x0
/* Bit masks for CAN0_MBTD */
#define TDR 0x80 /* Temporary Disable Request */
-#define nTDR 0x0
#define TDA 0x40 /* Temporary Disable Acknowledge */
-#define nTDA 0x0
#define TDPTR 0x1f /* Temporary Disable Pointer */
/* Bit masks for CAN0_UCCNF */
#define UCCNF 0xf /* Universal Counter Configuration */
#define UCRC 0x20 /* Universal Counter Reload/Clear */
-#define nUCRC 0x0
#define UCCT 0x40 /* Universal Counter CAN Trigger */
-#define nUCCT 0x0
#define UCE 0x80 /* Universal Counter Enable */
-#define nUCE 0x0
/* Bit masks for CAN0_UCCNT */
@@ -2871,17 +2451,11 @@
/* Bit masks for CAN0_ESR */
#define FER 0x80 /* Form Error */
-#define nFER 0x0
#define BEF 0x40 /* Bit Error Flag */
-#define nBEF 0x0
#define SA0 0x20 /* Stuck At Dominant */
-#define nSA0 0x0
#define CRCE 0x10 /* CRC Error */
-#define nCRCE 0x0
#define SER 0x8 /* Stuff Bit Error */
-#define nSER 0x0
#define ACKE 0x4 /* Acknowledge Error */
-#define nACKE 0x0
/* Bit masks for CAN0_EWR */
@@ -2891,11 +2465,8 @@
/* Bit masks for CAN0_AMxx_H */
#define FDF 0x8000 /* Filter On Data Field */
-#define nFDF 0x0
#define FMD 0x4000 /* Full Mask Data */
-#define nFMD 0x0
#define AMIDE 0x2000 /* Acceptance Mask Identifier Extension */
-#define nAMIDE 0x0
#define BASEID 0x1ffc /* Base Identifier */
#define EXTID_HI 0x3 /* Extended Identifier High Bits */
@@ -2907,11 +2478,8 @@
/* Bit masks for CAN0_MBxx_ID1 */
#define AME 0x8000 /* Acceptance Mask Enable */
-#define nAME 0x0
#define RTR 0x4000 /* Remote Transmission Request */
-#define nRTR 0x0
#define IDE 0x2000 /* Identifier Extension */
-#define nIDE 0x0
#define BASEID 0x1ffc /* Base Identifier */
#define EXTID_HI 0x3 /* Extended Identifier High Bits */
@@ -2951,980 +2519,546 @@
/* Bit masks for CAN0_MC1 */
#define MC0 0x1 /* Mailbox 0 Enable */
-#define nMC0 0x0
#define MC1 0x2 /* Mailbox 1 Enable */
-#define nMC1 0x0
#define MC2 0x4 /* Mailbox 2 Enable */
-#define nMC2 0x0
#define MC3 0x8 /* Mailbox 3 Enable */
-#define nMC3 0x0
#define MC4 0x10 /* Mailbox 4 Enable */
-#define nMC4 0x0
#define MC5 0x20 /* Mailbox 5 Enable */
-#define nMC5 0x0
#define MC6 0x40 /* Mailbox 6 Enable */
-#define nMC6 0x0
#define MC7 0x80 /* Mailbox 7 Enable */
-#define nMC7 0x0
#define MC8 0x100 /* Mailbox 8 Enable */
-#define nMC8 0x0
#define MC9 0x200 /* Mailbox 9 Enable */
-#define nMC9 0x0
#define MC10 0x400 /* Mailbox 10 Enable */
-#define nMC10 0x0
#define MC11 0x800 /* Mailbox 11 Enable */
-#define nMC11 0x0
#define MC12 0x1000 /* Mailbox 12 Enable */
-#define nMC12 0x0
#define MC13 0x2000 /* Mailbox 13 Enable */
-#define nMC13 0x0
#define MC14 0x4000 /* Mailbox 14 Enable */
-#define nMC14 0x0
#define MC15 0x8000 /* Mailbox 15 Enable */
-#define nMC15 0x0
/* Bit masks for CAN0_MC2 */
#define MC16 0x1 /* Mailbox 16 Enable */
-#define nMC16 0x0
#define MC17 0x2 /* Mailbox 17 Enable */
-#define nMC17 0x0
#define MC18 0x4 /* Mailbox 18 Enable */
-#define nMC18 0x0
#define MC19 0x8 /* Mailbox 19 Enable */
-#define nMC19 0x0
#define MC20 0x10 /* Mailbox 20 Enable */
-#define nMC20 0x0
#define MC21 0x20 /* Mailbox 21 Enable */
-#define nMC21 0x0
#define MC22 0x40 /* Mailbox 22 Enable */
-#define nMC22 0x0
#define MC23 0x80 /* Mailbox 23 Enable */
-#define nMC23 0x0
#define MC24 0x100 /* Mailbox 24 Enable */
-#define nMC24 0x0
#define MC25 0x200 /* Mailbox 25 Enable */
-#define nMC25 0x0
#define MC26 0x400 /* Mailbox 26 Enable */
-#define nMC26 0x0
#define MC27 0x800 /* Mailbox 27 Enable */
-#define nMC27 0x0
#define MC28 0x1000 /* Mailbox 28 Enable */
-#define nMC28 0x0
#define MC29 0x2000 /* Mailbox 29 Enable */
-#define nMC29 0x0
#define MC30 0x4000 /* Mailbox 30 Enable */
-#define nMC30 0x0
#define MC31 0x8000 /* Mailbox 31 Enable */
-#define nMC31 0x0
/* Bit masks for CAN0_MD1 */
#define MD0 0x1 /* Mailbox 0 Receive Enable */
-#define nMD0 0x0
#define MD1 0x2 /* Mailbox 1 Receive Enable */
-#define nMD1 0x0
#define MD2 0x4 /* Mailbox 2 Receive Enable */
-#define nMD2 0x0
#define MD3 0x8 /* Mailbox 3 Receive Enable */
-#define nMD3 0x0
#define MD4 0x10 /* Mailbox 4 Receive Enable */
-#define nMD4 0x0
#define MD5 0x20 /* Mailbox 5 Receive Enable */
-#define nMD5 0x0
#define MD6 0x40 /* Mailbox 6 Receive Enable */
-#define nMD6 0x0
#define MD7 0x80 /* Mailbox 7 Receive Enable */
-#define nMD7 0x0
#define MD8 0x100 /* Mailbox 8 Receive Enable */
-#define nMD8 0x0
#define MD9 0x200 /* Mailbox 9 Receive Enable */
-#define nMD9 0x0
#define MD10 0x400 /* Mailbox 10 Receive Enable */
-#define nMD10 0x0
#define MD11 0x800 /* Mailbox 11 Receive Enable */
-#define nMD11 0x0
#define MD12 0x1000 /* Mailbox 12 Receive Enable */
-#define nMD12 0x0
#define MD13 0x2000 /* Mailbox 13 Receive Enable */
-#define nMD13 0x0
#define MD14 0x4000 /* Mailbox 14 Receive Enable */
-#define nMD14 0x0
#define MD15 0x8000 /* Mailbox 15 Receive Enable */
-#define nMD15 0x0
/* Bit masks for CAN0_MD2 */
#define MD16 0x1 /* Mailbox 16 Receive Enable */
-#define nMD16 0x0
#define MD17 0x2 /* Mailbox 17 Receive Enable */
-#define nMD17 0x0
#define MD18 0x4 /* Mailbox 18 Receive Enable */
-#define nMD18 0x0
#define MD19 0x8 /* Mailbox 19 Receive Enable */
-#define nMD19 0x0
#define MD20 0x10 /* Mailbox 20 Receive Enable */
-#define nMD20 0x0
#define MD21 0x20 /* Mailbox 21 Receive Enable */
-#define nMD21 0x0
#define MD22 0x40 /* Mailbox 22 Receive Enable */
-#define nMD22 0x0
#define MD23 0x80 /* Mailbox 23 Receive Enable */
-#define nMD23 0x0
#define MD24 0x100 /* Mailbox 24 Receive Enable */
-#define nMD24 0x0
#define MD25 0x200 /* Mailbox 25 Receive Enable */
-#define nMD25 0x0
#define MD26 0x400 /* Mailbox 26 Receive Enable */
-#define nMD26 0x0
#define MD27 0x800 /* Mailbox 27 Receive Enable */
-#define nMD27 0x0
#define MD28 0x1000 /* Mailbox 28 Receive Enable */
-#define nMD28 0x0
#define MD29 0x2000 /* Mailbox 29 Receive Enable */
-#define nMD29 0x0
#define MD30 0x4000 /* Mailbox 30 Receive Enable */
-#define nMD30 0x0
#define MD31 0x8000 /* Mailbox 31 Receive Enable */
-#define nMD31 0x0
/* Bit masks for CAN0_RMP1 */
#define RMP0 0x1 /* Mailbox 0 Receive Message Pending */
-#define nRMP0 0x0
#define RMP1 0x2 /* Mailbox 1 Receive Message Pending */
-#define nRMP1 0x0
#define RMP2 0x4 /* Mailbox 2 Receive Message Pending */
-#define nRMP2 0x0
#define RMP3 0x8 /* Mailbox 3 Receive Message Pending */
-#define nRMP3 0x0
#define RMP4 0x10 /* Mailbox 4 Receive Message Pending */
-#define nRMP4 0x0
#define RMP5 0x20 /* Mailbox 5 Receive Message Pending */
-#define nRMP5 0x0
#define RMP6 0x40 /* Mailbox 6 Receive Message Pending */
-#define nRMP6 0x0
#define RMP7 0x80 /* Mailbox 7 Receive Message Pending */
-#define nRMP7 0x0
#define RMP8 0x100 /* Mailbox 8 Receive Message Pending */
-#define nRMP8 0x0
#define RMP9 0x200 /* Mailbox 9 Receive Message Pending */
-#define nRMP9 0x0
#define RMP10 0x400 /* Mailbox 10 Receive Message Pending */
-#define nRMP10 0x0
#define RMP11 0x800 /* Mailbox 11 Receive Message Pending */
-#define nRMP11 0x0
#define RMP12 0x1000 /* Mailbox 12 Receive Message Pending */
-#define nRMP12 0x0
#define RMP13 0x2000 /* Mailbox 13 Receive Message Pending */
-#define nRMP13 0x0
#define RMP14 0x4000 /* Mailbox 14 Receive Message Pending */
-#define nRMP14 0x0
#define RMP15 0x8000 /* Mailbox 15 Receive Message Pending */
-#define nRMP15 0x0
/* Bit masks for CAN0_RMP2 */
#define RMP16 0x1 /* Mailbox 16 Receive Message Pending */
-#define nRMP16 0x0
#define RMP17 0x2 /* Mailbox 17 Receive Message Pending */
-#define nRMP17 0x0
#define RMP18 0x4 /* Mailbox 18 Receive Message Pending */
-#define nRMP18 0x0
#define RMP19 0x8 /* Mailbox 19 Receive Message Pending */
-#define nRMP19 0x0
#define RMP20 0x10 /* Mailbox 20 Receive Message Pending */
-#define nRMP20 0x0
#define RMP21 0x20 /* Mailbox 21 Receive Message Pending */
-#define nRMP21 0x0
#define RMP22 0x40 /* Mailbox 22 Receive Message Pending */
-#define nRMP22 0x0
#define RMP23 0x80 /* Mailbox 23 Receive Message Pending */
-#define nRMP23 0x0
#define RMP24 0x100 /* Mailbox 24 Receive Message Pending */
-#define nRMP24 0x0
#define RMP25 0x200 /* Mailbox 25 Receive Message Pending */
-#define nRMP25 0x0
#define RMP26 0x400 /* Mailbox 26 Receive Message Pending */
-#define nRMP26 0x0
#define RMP27 0x800 /* Mailbox 27 Receive Message Pending */
-#define nRMP27 0x0
#define RMP28 0x1000 /* Mailbox 28 Receive Message Pending */
-#define nRMP28 0x0
#define RMP29 0x2000 /* Mailbox 29 Receive Message Pending */
-#define nRMP29 0x0
#define RMP30 0x4000 /* Mailbox 30 Receive Message Pending */
-#define nRMP30 0x0
#define RMP31 0x8000 /* Mailbox 31 Receive Message Pending */
-#define nRMP31 0x0
/* Bit masks for CAN0_RML1 */
#define RML0 0x1 /* Mailbox 0 Receive Message Lost */
-#define nRML0 0x0
#define RML1 0x2 /* Mailbox 1 Receive Message Lost */
-#define nRML1 0x0
#define RML2 0x4 /* Mailbox 2 Receive Message Lost */
-#define nRML2 0x0
#define RML3 0x8 /* Mailbox 3 Receive Message Lost */
-#define nRML3 0x0
#define RML4 0x10 /* Mailbox 4 Receive Message Lost */
-#define nRML4 0x0
#define RML5 0x20 /* Mailbox 5 Receive Message Lost */
-#define nRML5 0x0
#define RML6 0x40 /* Mailbox 6 Receive Message Lost */
-#define nRML6 0x0
#define RML7 0x80 /* Mailbox 7 Receive Message Lost */
-#define nRML7 0x0
#define RML8 0x100 /* Mailbox 8 Receive Message Lost */
-#define nRML8 0x0
#define RML9 0x200 /* Mailbox 9 Receive Message Lost */
-#define nRML9 0x0
#define RML10 0x400 /* Mailbox 10 Receive Message Lost */
-#define nRML10 0x0
#define RML11 0x800 /* Mailbox 11 Receive Message Lost */
-#define nRML11 0x0
#define RML12 0x1000 /* Mailbox 12 Receive Message Lost */
-#define nRML12 0x0
#define RML13 0x2000 /* Mailbox 13 Receive Message Lost */
-#define nRML13 0x0
#define RML14 0x4000 /* Mailbox 14 Receive Message Lost */
-#define nRML14 0x0
#define RML15 0x8000 /* Mailbox 15 Receive Message Lost */
-#define nRML15 0x0
/* Bit masks for CAN0_RML2 */
#define RML16 0x1 /* Mailbox 16 Receive Message Lost */
-#define nRML16 0x0
#define RML17 0x2 /* Mailbox 17 Receive Message Lost */
-#define nRML17 0x0
#define RML18 0x4 /* Mailbox 18 Receive Message Lost */
-#define nRML18 0x0
#define RML19 0x8 /* Mailbox 19 Receive Message Lost */
-#define nRML19 0x0
#define RML20 0x10 /* Mailbox 20 Receive Message Lost */
-#define nRML20 0x0
#define RML21 0x20 /* Mailbox 21 Receive Message Lost */
-#define nRML21 0x0
#define RML22 0x40 /* Mailbox 22 Receive Message Lost */
-#define nRML22 0x0
#define RML23 0x80 /* Mailbox 23 Receive Message Lost */
-#define nRML23 0x0
#define RML24 0x100 /* Mailbox 24 Receive Message Lost */
-#define nRML24 0x0
#define RML25 0x200 /* Mailbox 25 Receive Message Lost */
-#define nRML25 0x0
#define RML26 0x400 /* Mailbox 26 Receive Message Lost */
-#define nRML26 0x0
#define RML27 0x800 /* Mailbox 27 Receive Message Lost */
-#define nRML27 0x0
#define RML28 0x1000 /* Mailbox 28 Receive Message Lost */
-#define nRML28 0x0
#define RML29 0x2000 /* Mailbox 29 Receive Message Lost */
-#define nRML29 0x0
#define RML30 0x4000 /* Mailbox 30 Receive Message Lost */
-#define nRML30 0x0
#define RML31 0x8000 /* Mailbox 31 Receive Message Lost */
-#define nRML31 0x0
/* Bit masks for CAN0_OPSS1 */
#define OPSS0 0x1 /* Mailbox 0 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS0 0x0
#define OPSS1 0x2 /* Mailbox 1 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS1 0x0
#define OPSS2 0x4 /* Mailbox 2 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS2 0x0
#define OPSS3 0x8 /* Mailbox 3 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS3 0x0
#define OPSS4 0x10 /* Mailbox 4 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS4 0x0
#define OPSS5 0x20 /* Mailbox 5 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS5 0x0
#define OPSS6 0x40 /* Mailbox 6 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS6 0x0
#define OPSS7 0x80 /* Mailbox 7 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS7 0x0
#define OPSS8 0x100 /* Mailbox 8 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS8 0x0
#define OPSS9 0x200 /* Mailbox 9 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS9 0x0
#define OPSS10 0x400 /* Mailbox 10 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS10 0x0
#define OPSS11 0x800 /* Mailbox 11 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS11 0x0
#define OPSS12 0x1000 /* Mailbox 12 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS12 0x0
#define OPSS13 0x2000 /* Mailbox 13 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS13 0x0
#define OPSS14 0x4000 /* Mailbox 14 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS14 0x0
#define OPSS15 0x8000 /* Mailbox 15 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS15 0x0
/* Bit masks for CAN0_OPSS2 */
#define OPSS16 0x1 /* Mailbox 16 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS16 0x0
#define OPSS17 0x2 /* Mailbox 17 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS17 0x0
#define OPSS18 0x4 /* Mailbox 18 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS18 0x0
#define OPSS19 0x8 /* Mailbox 19 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS19 0x0
#define OPSS20 0x10 /* Mailbox 20 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS20 0x0
#define OPSS21 0x20 /* Mailbox 21 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS21 0x0
#define OPSS22 0x40 /* Mailbox 22 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS22 0x0
#define OPSS23 0x80 /* Mailbox 23 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS23 0x0
#define OPSS24 0x100 /* Mailbox 24 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS24 0x0
#define OPSS25 0x200 /* Mailbox 25 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS25 0x0
#define OPSS26 0x400 /* Mailbox 26 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS26 0x0
#define OPSS27 0x800 /* Mailbox 27 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS27 0x0
#define OPSS28 0x1000 /* Mailbox 28 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS28 0x0
#define OPSS29 0x2000 /* Mailbox 29 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS29 0x0
#define OPSS30 0x4000 /* Mailbox 30 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS30 0x0
#define OPSS31 0x8000 /* Mailbox 31 Overwrite Protection/Single-Shot Transmission Enable */
-#define nOPSS31 0x0
/* Bit masks for CAN0_TRS1 */
#define TRS0 0x1 /* Mailbox 0 Transmit Request Set */
-#define nTRS0 0x0
#define TRS1 0x2 /* Mailbox 1 Transmit Request Set */
-#define nTRS1 0x0
#define TRS2 0x4 /* Mailbox 2 Transmit Request Set */
-#define nTRS2 0x0
#define TRS3 0x8 /* Mailbox 3 Transmit Request Set */
-#define nTRS3 0x0
#define TRS4 0x10 /* Mailbox 4 Transmit Request Set */
-#define nTRS4 0x0
#define TRS5 0x20 /* Mailbox 5 Transmit Request Set */
-#define nTRS5 0x0
#define TRS6 0x40 /* Mailbox 6 Transmit Request Set */
-#define nTRS6 0x0
#define TRS7 0x80 /* Mailbox 7 Transmit Request Set */
-#define nTRS7 0x0
#define TRS8 0x100 /* Mailbox 8 Transmit Request Set */
-#define nTRS8 0x0
#define TRS9 0x200 /* Mailbox 9 Transmit Request Set */
-#define nTRS9 0x0
#define TRS10 0x400 /* Mailbox 10 Transmit Request Set */
-#define nTRS10 0x0
#define TRS11 0x800 /* Mailbox 11 Transmit Request Set */
-#define nTRS11 0x0
#define TRS12 0x1000 /* Mailbox 12 Transmit Request Set */
-#define nTRS12 0x0
#define TRS13 0x2000 /* Mailbox 13 Transmit Request Set */
-#define nTRS13 0x0
#define TRS14 0x4000 /* Mailbox 14 Transmit Request Set */
-#define nTRS14 0x0
#define TRS15 0x8000 /* Mailbox 15 Transmit Request Set */
-#define nTRS15 0x0
/* Bit masks for CAN0_TRS2 */
#define TRS16 0x1 /* Mailbox 16 Transmit Request Set */
-#define nTRS16 0x0
#define TRS17 0x2 /* Mailbox 17 Transmit Request Set */
-#define nTRS17 0x0
#define TRS18 0x4 /* Mailbox 18 Transmit Request Set */
-#define nTRS18 0x0
#define TRS19 0x8 /* Mailbox 19 Transmit Request Set */
-#define nTRS19 0x0
#define TRS20 0x10 /* Mailbox 20 Transmit Request Set */
-#define nTRS20 0x0
#define TRS21 0x20 /* Mailbox 21 Transmit Request Set */
-#define nTRS21 0x0
#define TRS22 0x40 /* Mailbox 22 Transmit Request Set */
-#define nTRS22 0x0
#define TRS23 0x80 /* Mailbox 23 Transmit Request Set */
-#define nTRS23 0x0
#define TRS24 0x100 /* Mailbox 24 Transmit Request Set */
-#define nTRS24 0x0
#define TRS25 0x200 /* Mailbox 25 Transmit Request Set */
-#define nTRS25 0x0
#define TRS26 0x400 /* Mailbox 26 Transmit Request Set */
-#define nTRS26 0x0
#define TRS27 0x800 /* Mailbox 27 Transmit Request Set */
-#define nTRS27 0x0
#define TRS28 0x1000 /* Mailbox 28 Transmit Request Set */
-#define nTRS28 0x0
#define TRS29 0x2000 /* Mailbox 29 Transmit Request Set */
-#define nTRS29 0x0
#define TRS30 0x4000 /* Mailbox 30 Transmit Request Set */
-#define nTRS30 0x0
#define TRS31 0x8000 /* Mailbox 31 Transmit Request Set */
-#define nTRS31 0x0
/* Bit masks for CAN0_TRR1 */
#define TRR0 0x1 /* Mailbox 0 Transmit Request Reset */
-#define nTRR0 0x0
#define TRR1 0x2 /* Mailbox 1 Transmit Request Reset */
-#define nTRR1 0x0
#define TRR2 0x4 /* Mailbox 2 Transmit Request Reset */
-#define nTRR2 0x0
#define TRR3 0x8 /* Mailbox 3 Transmit Request Reset */
-#define nTRR3 0x0
#define TRR4 0x10 /* Mailbox 4 Transmit Request Reset */
-#define nTRR4 0x0
#define TRR5 0x20 /* Mailbox 5 Transmit Request Reset */
-#define nTRR5 0x0
#define TRR6 0x40 /* Mailbox 6 Transmit Request Reset */
-#define nTRR6 0x0
#define TRR7 0x80 /* Mailbox 7 Transmit Request Reset */
-#define nTRR7 0x0
#define TRR8 0x100 /* Mailbox 8 Transmit Request Reset */
-#define nTRR8 0x0
#define TRR9 0x200 /* Mailbox 9 Transmit Request Reset */
-#define nTRR9 0x0
#define TRR10 0x400 /* Mailbox 10 Transmit Request Reset */
-#define nTRR10 0x0
#define TRR11 0x800 /* Mailbox 11 Transmit Request Reset */
-#define nTRR11 0x0
#define TRR12 0x1000 /* Mailbox 12 Transmit Request Reset */
-#define nTRR12 0x0
#define TRR13 0x2000 /* Mailbox 13 Transmit Request Reset */
-#define nTRR13 0x0
#define TRR14 0x4000 /* Mailbox 14 Transmit Request Reset */
-#define nTRR14 0x0
#define TRR15 0x8000 /* Mailbox 15 Transmit Request Reset */
-#define nTRR15 0x0
/* Bit masks for CAN0_TRR2 */
#define TRR16 0x1 /* Mailbox 16 Transmit Request Reset */
-#define nTRR16 0x0
#define TRR17 0x2 /* Mailbox 17 Transmit Request Reset */
-#define nTRR17 0x0
#define TRR18 0x4 /* Mailbox 18 Transmit Request Reset */
-#define nTRR18 0x0
#define TRR19 0x8 /* Mailbox 19 Transmit Request Reset */
-#define nTRR19 0x0
#define TRR20 0x10 /* Mailbox 20 Transmit Request Reset */
-#define nTRR20 0x0
#define TRR21 0x20 /* Mailbox 21 Transmit Request Reset */
-#define nTRR21 0x0
#define TRR22 0x40 /* Mailbox 22 Transmit Request Reset */
-#define nTRR22 0x0
#define TRR23 0x80 /* Mailbox 23 Transmit Request Reset */
-#define nTRR23 0x0
#define TRR24 0x100 /* Mailbox 24 Transmit Request Reset */
-#define nTRR24 0x0
#define TRR25 0x200 /* Mailbox 25 Transmit Request Reset */
-#define nTRR25 0x0
#define TRR26 0x400 /* Mailbox 26 Transmit Request Reset */
-#define nTRR26 0x0
#define TRR27 0x800 /* Mailbox 27 Transmit Request Reset */
-#define nTRR27 0x0
#define TRR28 0x1000 /* Mailbox 28 Transmit Request Reset */
-#define nTRR28 0x0
#define TRR29 0x2000 /* Mailbox 29 Transmit Request Reset */
-#define nTRR29 0x0
#define TRR30 0x4000 /* Mailbox 30 Transmit Request Reset */
-#define nTRR30 0x0
#define TRR31 0x8000 /* Mailbox 31 Transmit Request Reset */
-#define nTRR31 0x0
/* Bit masks for CAN0_AA1 */
#define AA0 0x1 /* Mailbox 0 Abort Acknowledge */
-#define nAA0 0x0
#define AA1 0x2 /* Mailbox 1 Abort Acknowledge */
-#define nAA1 0x0
#define AA2 0x4 /* Mailbox 2 Abort Acknowledge */
-#define nAA2 0x0
#define AA3 0x8 /* Mailbox 3 Abort Acknowledge */
-#define nAA3 0x0
#define AA4 0x10 /* Mailbox 4 Abort Acknowledge */
-#define nAA4 0x0
#define AA5 0x20 /* Mailbox 5 Abort Acknowledge */
-#define nAA5 0x0
#define AA6 0x40 /* Mailbox 6 Abort Acknowledge */
-#define nAA6 0x0
#define AA7 0x80 /* Mailbox 7 Abort Acknowledge */
-#define nAA7 0x0
#define AA8 0x100 /* Mailbox 8 Abort Acknowledge */
-#define nAA8 0x0
#define AA9 0x200 /* Mailbox 9 Abort Acknowledge */
-#define nAA9 0x0
#define AA10 0x400 /* Mailbox 10 Abort Acknowledge */
-#define nAA10 0x0
#define AA11 0x800 /* Mailbox 11 Abort Acknowledge */
-#define nAA11 0x0
#define AA12 0x1000 /* Mailbox 12 Abort Acknowledge */
-#define nAA12 0x0
#define AA13 0x2000 /* Mailbox 13 Abort Acknowledge */
-#define nAA13 0x0
#define AA14 0x4000 /* Mailbox 14 Abort Acknowledge */
-#define nAA14 0x0
#define AA15 0x8000 /* Mailbox 15 Abort Acknowledge */
-#define nAA15 0x0
/* Bit masks for CAN0_AA2 */
#define AA16 0x1 /* Mailbox 16 Abort Acknowledge */
-#define nAA16 0x0
#define AA17 0x2 /* Mailbox 17 Abort Acknowledge */
-#define nAA17 0x0
#define AA18 0x4 /* Mailbox 18 Abort Acknowledge */
-#define nAA18 0x0
#define AA19 0x8 /* Mailbox 19 Abort Acknowledge */
-#define nAA19 0x0
#define AA20 0x10 /* Mailbox 20 Abort Acknowledge */
-#define nAA20 0x0
#define AA21 0x20 /* Mailbox 21 Abort Acknowledge */
-#define nAA21 0x0
#define AA22 0x40 /* Mailbox 22 Abort Acknowledge */
-#define nAA22 0x0
#define AA23 0x80 /* Mailbox 23 Abort Acknowledge */
-#define nAA23 0x0
#define AA24 0x100 /* Mailbox 24 Abort Acknowledge */
-#define nAA24 0x0
#define AA25 0x200 /* Mailbox 25 Abort Acknowledge */
-#define nAA25 0x0
#define AA26 0x400 /* Mailbox 26 Abort Acknowledge */
-#define nAA26 0x0
#define AA27 0x800 /* Mailbox 27 Abort Acknowledge */
-#define nAA27 0x0
#define AA28 0x1000 /* Mailbox 28 Abort Acknowledge */
-#define nAA28 0x0
#define AA29 0x2000 /* Mailbox 29 Abort Acknowledge */
-#define nAA29 0x0
#define AA30 0x4000 /* Mailbox 30 Abort Acknowledge */
-#define nAA30 0x0
#define AA31 0x8000 /* Mailbox 31 Abort Acknowledge */
-#define nAA31 0x0
/* Bit masks for CAN0_TA1 */
#define TA0 0x1 /* Mailbox 0 Transmit Acknowledge */
-#define nTA0 0x0
#define TA1 0x2 /* Mailbox 1 Transmit Acknowledge */
-#define nTA1 0x0
#define TA2 0x4 /* Mailbox 2 Transmit Acknowledge */
-#define nTA2 0x0
#define TA3 0x8 /* Mailbox 3 Transmit Acknowledge */
-#define nTA3 0x0
#define TA4 0x10 /* Mailbox 4 Transmit Acknowledge */
-#define nTA4 0x0
#define TA5 0x20 /* Mailbox 5 Transmit Acknowledge */
-#define nTA5 0x0
#define TA6 0x40 /* Mailbox 6 Transmit Acknowledge */
-#define nTA6 0x0
#define TA7 0x80 /* Mailbox 7 Transmit Acknowledge */
-#define nTA7 0x0
#define TA8 0x100 /* Mailbox 8 Transmit Acknowledge */
-#define nTA8 0x0
#define TA9 0x200 /* Mailbox 9 Transmit Acknowledge */
-#define nTA9 0x0
#define TA10 0x400 /* Mailbox 10 Transmit Acknowledge */
-#define nTA10 0x0
#define TA11 0x800 /* Mailbox 11 Transmit Acknowledge */
-#define nTA11 0x0
#define TA12 0x1000 /* Mailbox 12 Transmit Acknowledge */
-#define nTA12 0x0
#define TA13 0x2000 /* Mailbox 13 Transmit Acknowledge */
-#define nTA13 0x0
#define TA14 0x4000 /* Mailbox 14 Transmit Acknowledge */
-#define nTA14 0x0
#define TA15 0x8000 /* Mailbox 15 Transmit Acknowledge */
-#define nTA15 0x0
/* Bit masks for CAN0_TA2 */
#define TA16 0x1 /* Mailbox 16 Transmit Acknowledge */
-#define nTA16 0x0
#define TA17 0x2 /* Mailbox 17 Transmit Acknowledge */
-#define nTA17 0x0
#define TA18 0x4 /* Mailbox 18 Transmit Acknowledge */
-#define nTA18 0x0
#define TA19 0x8 /* Mailbox 19 Transmit Acknowledge */
-#define nTA19 0x0
#define TA20 0x10 /* Mailbox 20 Transmit Acknowledge */
-#define nTA20 0x0
#define TA21 0x20 /* Mailbox 21 Transmit Acknowledge */
-#define nTA21 0x0
#define TA22 0x40 /* Mailbox 22 Transmit Acknowledge */
-#define nTA22 0x0
#define TA23 0x80 /* Mailbox 23 Transmit Acknowledge */
-#define nTA23 0x0
#define TA24 0x100 /* Mailbox 24 Transmit Acknowledge */
-#define nTA24 0x0
#define TA25 0x200 /* Mailbox 25 Transmit Acknowledge */
-#define nTA25 0x0
#define TA26 0x400 /* Mailbox 26 Transmit Acknowledge */
-#define nTA26 0x0
#define TA27 0x800 /* Mailbox 27 Transmit Acknowledge */
-#define nTA27 0x0
#define TA28 0x1000 /* Mailbox 28 Transmit Acknowledge */
-#define nTA28 0x0
#define TA29 0x2000 /* Mailbox 29 Transmit Acknowledge */
-#define nTA29 0x0
#define TA30 0x4000 /* Mailbox 30 Transmit Acknowledge */
-#define nTA30 0x0
#define TA31 0x8000 /* Mailbox 31 Transmit Acknowledge */
-#define nTA31 0x0
/* Bit masks for CAN0_RFH1 */
#define RFH0 0x1 /* Mailbox 0 Remote Frame Handling Enable */
-#define nRFH0 0x0
#define RFH1 0x2 /* Mailbox 1 Remote Frame Handling Enable */
-#define nRFH1 0x0
#define RFH2 0x4 /* Mailbox 2 Remote Frame Handling Enable */
-#define nRFH2 0x0
#define RFH3 0x8 /* Mailbox 3 Remote Frame Handling Enable */
-#define nRFH3 0x0
#define RFH4 0x10 /* Mailbox 4 Remote Frame Handling Enable */
-#define nRFH4 0x0
#define RFH5 0x20 /* Mailbox 5 Remote Frame Handling Enable */
-#define nRFH5 0x0
#define RFH6 0x40 /* Mailbox 6 Remote Frame Handling Enable */
-#define nRFH6 0x0
#define RFH7 0x80 /* Mailbox 7 Remote Frame Handling Enable */
-#define nRFH7 0x0
#define RFH8 0x100 /* Mailbox 8 Remote Frame Handling Enable */
-#define nRFH8 0x0
#define RFH9 0x200 /* Mailbox 9 Remote Frame Handling Enable */
-#define nRFH9 0x0
#define RFH10 0x400 /* Mailbox 10 Remote Frame Handling Enable */
-#define nRFH10 0x0
#define RFH11 0x800 /* Mailbox 11 Remote Frame Handling Enable */
-#define nRFH11 0x0
#define RFH12 0x1000 /* Mailbox 12 Remote Frame Handling Enable */
-#define nRFH12 0x0
#define RFH13 0x2000 /* Mailbox 13 Remote Frame Handling Enable */
-#define nRFH13 0x0
#define RFH14 0x4000 /* Mailbox 14 Remote Frame Handling Enable */
-#define nRFH14 0x0
#define RFH15 0x8000 /* Mailbox 15 Remote Frame Handling Enable */
-#define nRFH15 0x0
/* Bit masks for CAN0_RFH2 */
#define RFH16 0x1 /* Mailbox 16 Remote Frame Handling Enable */
-#define nRFH16 0x0
#define RFH17 0x2 /* Mailbox 17 Remote Frame Handling Enable */
-#define nRFH17 0x0
#define RFH18 0x4 /* Mailbox 18 Remote Frame Handling Enable */
-#define nRFH18 0x0
#define RFH19 0x8 /* Mailbox 19 Remote Frame Handling Enable */
-#define nRFH19 0x0
#define RFH20 0x10 /* Mailbox 20 Remote Frame Handling Enable */
-#define nRFH20 0x0
#define RFH21 0x20 /* Mailbox 21 Remote Frame Handling Enable */
-#define nRFH21 0x0
#define RFH22 0x40 /* Mailbox 22 Remote Frame Handling Enable */
-#define nRFH22 0x0
#define RFH23 0x80 /* Mailbox 23 Remote Frame Handling Enable */
-#define nRFH23 0x0
#define RFH24 0x100 /* Mailbox 24 Remote Frame Handling Enable */
-#define nRFH24 0x0
#define RFH25 0x200 /* Mailbox 25 Remote Frame Handling Enable */
-#define nRFH25 0x0
#define RFH26 0x400 /* Mailbox 26 Remote Frame Handling Enable */
-#define nRFH26 0x0
#define RFH27 0x800 /* Mailbox 27 Remote Frame Handling Enable */
-#define nRFH27 0x0
#define RFH28 0x1000 /* Mailbox 28 Remote Frame Handling Enable */
-#define nRFH28 0x0
#define RFH29 0x2000 /* Mailbox 29 Remote Frame Handling Enable */
-#define nRFH29 0x0
#define RFH30 0x4000 /* Mailbox 30 Remote Frame Handling Enable */
-#define nRFH30 0x0
#define RFH31 0x8000 /* Mailbox 31 Remote Frame Handling Enable */
-#define nRFH31 0x0
/* Bit masks for CAN0_MBIM1 */
#define MBIM0 0x1 /* Mailbox 0 Mailbox Interrupt Mask */
-#define nMBIM0 0x0
#define MBIM1 0x2 /* Mailbox 1 Mailbox Interrupt Mask */
-#define nMBIM1 0x0
#define MBIM2 0x4 /* Mailbox 2 Mailbox Interrupt Mask */
-#define nMBIM2 0x0
#define MBIM3 0x8 /* Mailbox 3 Mailbox Interrupt Mask */
-#define nMBIM3 0x0
#define MBIM4 0x10 /* Mailbox 4 Mailbox Interrupt Mask */
-#define nMBIM4 0x0
#define MBIM5 0x20 /* Mailbox 5 Mailbox Interrupt Mask */
-#define nMBIM5 0x0
#define MBIM6 0x40 /* Mailbox 6 Mailbox Interrupt Mask */
-#define nMBIM6 0x0
#define MBIM7 0x80 /* Mailbox 7 Mailbox Interrupt Mask */
-#define nMBIM7 0x0
#define MBIM8 0x100 /* Mailbox 8 Mailbox Interrupt Mask */
-#define nMBIM8 0x0
#define MBIM9 0x200 /* Mailbox 9 Mailbox Interrupt Mask */
-#define nMBIM9 0x0
#define MBIM10 0x400 /* Mailbox 10 Mailbox Interrupt Mask */
-#define nMBIM10 0x0
#define MBIM11 0x800 /* Mailbox 11 Mailbox Interrupt Mask */
-#define nMBIM11 0x0
#define MBIM12 0x1000 /* Mailbox 12 Mailbox Interrupt Mask */
-#define nMBIM12 0x0
#define MBIM13 0x2000 /* Mailbox 13 Mailbox Interrupt Mask */
-#define nMBIM13 0x0
#define MBIM14 0x4000 /* Mailbox 14 Mailbox Interrupt Mask */
-#define nMBIM14 0x0
#define MBIM15 0x8000 /* Mailbox 15 Mailbox Interrupt Mask */
-#define nMBIM15 0x0
/* Bit masks for CAN0_MBIM2 */
#define MBIM16 0x1 /* Mailbox 16 Mailbox Interrupt Mask */
-#define nMBIM16 0x0
#define MBIM17 0x2 /* Mailbox 17 Mailbox Interrupt Mask */
-#define nMBIM17 0x0
#define MBIM18 0x4 /* Mailbox 18 Mailbox Interrupt Mask */
-#define nMBIM18 0x0
#define MBIM19 0x8 /* Mailbox 19 Mailbox Interrupt Mask */
-#define nMBIM19 0x0
#define MBIM20 0x10 /* Mailbox 20 Mailbox Interrupt Mask */
-#define nMBIM20 0x0
#define MBIM21 0x20 /* Mailbox 21 Mailbox Interrupt Mask */
-#define nMBIM21 0x0
#define MBIM22 0x40 /* Mailbox 22 Mailbox Interrupt Mask */
-#define nMBIM22 0x0
#define MBIM23 0x80 /* Mailbox 23 Mailbox Interrupt Mask */
-#define nMBIM23 0x0
#define MBIM24 0x100 /* Mailbox 24 Mailbox Interrupt Mask */
-#define nMBIM24 0x0
#define MBIM25 0x200 /* Mailbox 25 Mailbox Interrupt Mask */
-#define nMBIM25 0x0
#define MBIM26 0x400 /* Mailbox 26 Mailbox Interrupt Mask */
-#define nMBIM26 0x0
#define MBIM27 0x800 /* Mailbox 27 Mailbox Interrupt Mask */
-#define nMBIM27 0x0
#define MBIM28 0x1000 /* Mailbox 28 Mailbox Interrupt Mask */
-#define nMBIM28 0x0
#define MBIM29 0x2000 /* Mailbox 29 Mailbox Interrupt Mask */
-#define nMBIM29 0x0
#define MBIM30 0x4000 /* Mailbox 30 Mailbox Interrupt Mask */
-#define nMBIM30 0x0
#define MBIM31 0x8000 /* Mailbox 31 Mailbox Interrupt Mask */
-#define nMBIM31 0x0
/* Bit masks for CAN0_MBTIF1 */
#define MBTIF0 0x1 /* Mailbox 0 Mailbox Transmit Interrupt Flag */
-#define nMBTIF0 0x0
#define MBTIF1 0x2 /* Mailbox 1 Mailbox Transmit Interrupt Flag */
-#define nMBTIF1 0x0
#define MBTIF2 0x4 /* Mailbox 2 Mailbox Transmit Interrupt Flag */
-#define nMBTIF2 0x0
#define MBTIF3 0x8 /* Mailbox 3 Mailbox Transmit Interrupt Flag */
-#define nMBTIF3 0x0
#define MBTIF4 0x10 /* Mailbox 4 Mailbox Transmit Interrupt Flag */
-#define nMBTIF4 0x0
#define MBTIF5 0x20 /* Mailbox 5 Mailbox Transmit Interrupt Flag */
-#define nMBTIF5 0x0
#define MBTIF6 0x40 /* Mailbox 6 Mailbox Transmit Interrupt Flag */
-#define nMBTIF6 0x0
#define MBTIF7 0x80 /* Mailbox 7 Mailbox Transmit Interrupt Flag */
-#define nMBTIF7 0x0
#define MBTIF8 0x100 /* Mailbox 8 Mailbox Transmit Interrupt Flag */
-#define nMBTIF8 0x0
#define MBTIF9 0x200 /* Mailbox 9 Mailbox Transmit Interrupt Flag */
-#define nMBTIF9 0x0
#define MBTIF10 0x400 /* Mailbox 10 Mailbox Transmit Interrupt Flag */
-#define nMBTIF10 0x0
#define MBTIF11 0x800 /* Mailbox 11 Mailbox Transmit Interrupt Flag */
-#define nMBTIF11 0x0
#define MBTIF12 0x1000 /* Mailbox 12 Mailbox Transmit Interrupt Flag */
-#define nMBTIF12 0x0
#define MBTIF13 0x2000 /* Mailbox 13 Mailbox Transmit Interrupt Flag */
-#define nMBTIF13 0x0
#define MBTIF14 0x4000 /* Mailbox 14 Mailbox Transmit Interrupt Flag */
-#define nMBTIF14 0x0
#define MBTIF15 0x8000 /* Mailbox 15 Mailbox Transmit Interrupt Flag */
-#define nMBTIF15 0x0
/* Bit masks for CAN0_MBTIF2 */
#define MBTIF16 0x1 /* Mailbox 16 Mailbox Transmit Interrupt Flag */
-#define nMBTIF16 0x0
#define MBTIF17 0x2 /* Mailbox 17 Mailbox Transmit Interrupt Flag */
-#define nMBTIF17 0x0
#define MBTIF18 0x4 /* Mailbox 18 Mailbox Transmit Interrupt Flag */
-#define nMBTIF18 0x0
#define MBTIF19 0x8 /* Mailbox 19 Mailbox Transmit Interrupt Flag */
-#define nMBTIF19 0x0
#define MBTIF20 0x10 /* Mailbox 20 Mailbox Transmit Interrupt Flag */
-#define nMBTIF20 0x0
#define MBTIF21 0x20 /* Mailbox 21 Mailbox Transmit Interrupt Flag */
-#define nMBTIF21 0x0
#define MBTIF22 0x40 /* Mailbox 22 Mailbox Transmit Interrupt Flag */
-#define nMBTIF22 0x0
#define MBTIF23 0x80 /* Mailbox 23 Mailbox Transmit Interrupt Flag */
-#define nMBTIF23 0x0
#define MBTIF24 0x100 /* Mailbox 24 Mailbox Transmit Interrupt Flag */
-#define nMBTIF24 0x0
#define MBTIF25 0x200 /* Mailbox 25 Mailbox Transmit Interrupt Flag */
-#define nMBTIF25 0x0
#define MBTIF26 0x400 /* Mailbox 26 Mailbox Transmit Interrupt Flag */
-#define nMBTIF26 0x0
#define MBTIF27 0x800 /* Mailbox 27 Mailbox Transmit Interrupt Flag */
-#define nMBTIF27 0x0
#define MBTIF28 0x1000 /* Mailbox 28 Mailbox Transmit Interrupt Flag */
-#define nMBTIF28 0x0
#define MBTIF29 0x2000 /* Mailbox 29 Mailbox Transmit Interrupt Flag */
-#define nMBTIF29 0x0
#define MBTIF30 0x4000 /* Mailbox 30 Mailbox Transmit Interrupt Flag */
-#define nMBTIF30 0x0
#define MBTIF31 0x8000 /* Mailbox 31 Mailbox Transmit Interrupt Flag */
-#define nMBTIF31 0x0
/* Bit masks for CAN0_MBRIF1 */
#define MBRIF0 0x1 /* Mailbox 0 Mailbox Receive Interrupt Flag */
-#define nMBRIF0 0x0
#define MBRIF1 0x2 /* Mailbox 1 Mailbox Receive Interrupt Flag */
-#define nMBRIF1 0x0
#define MBRIF2 0x4 /* Mailbox 2 Mailbox Receive Interrupt Flag */
-#define nMBRIF2 0x0
#define MBRIF3 0x8 /* Mailbox 3 Mailbox Receive Interrupt Flag */
-#define nMBRIF3 0x0
#define MBRIF4 0x10 /* Mailbox 4 Mailbox Receive Interrupt Flag */
-#define nMBRIF4 0x0
#define MBRIF5 0x20 /* Mailbox 5 Mailbox Receive Interrupt Flag */
-#define nMBRIF5 0x0
#define MBRIF6 0x40 /* Mailbox 6 Mailbox Receive Interrupt Flag */
-#define nMBRIF6 0x0
#define MBRIF7 0x80 /* Mailbox 7 Mailbox Receive Interrupt Flag */
-#define nMBRIF7 0x0
#define MBRIF8 0x100 /* Mailbox 8 Mailbox Receive Interrupt Flag */
-#define nMBRIF8 0x0
#define MBRIF9 0x200 /* Mailbox 9 Mailbox Receive Interrupt Flag */
-#define nMBRIF9 0x0
#define MBRIF10 0x400 /* Mailbox 10 Mailbox Receive Interrupt Flag */
-#define nMBRIF10 0x0
#define MBRIF11 0x800 /* Mailbox 11 Mailbox Receive Interrupt Flag */
-#define nMBRIF11 0x0
#define MBRIF12 0x1000 /* Mailbox 12 Mailbox Receive Interrupt Flag */
-#define nMBRIF12 0x0
#define MBRIF13 0x2000 /* Mailbox 13 Mailbox Receive Interrupt Flag */
-#define nMBRIF13 0x0
#define MBRIF14 0x4000 /* Mailbox 14 Mailbox Receive Interrupt Flag */
-#define nMBRIF14 0x0
#define MBRIF15 0x8000 /* Mailbox 15 Mailbox Receive Interrupt Flag */
-#define nMBRIF15 0x0
/* Bit masks for CAN0_MBRIF2 */
#define MBRIF16 0x1 /* Mailbox 16 Mailbox Receive Interrupt Flag */
-#define nMBRIF16 0x0
#define MBRIF17 0x2 /* Mailbox 17 Mailbox Receive Interrupt Flag */
-#define nMBRIF17 0x0
#define MBRIF18 0x4 /* Mailbox 18 Mailbox Receive Interrupt Flag */
-#define nMBRIF18 0x0
#define MBRIF19 0x8 /* Mailbox 19 Mailbox Receive Interrupt Flag */
-#define nMBRIF19 0x0
#define MBRIF20 0x10 /* Mailbox 20 Mailbox Receive Interrupt Flag */
-#define nMBRIF20 0x0
#define MBRIF21 0x20 /* Mailbox 21 Mailbox Receive Interrupt Flag */
-#define nMBRIF21 0x0
#define MBRIF22 0x40 /* Mailbox 22 Mailbox Receive Interrupt Flag */
-#define nMBRIF22 0x0
#define MBRIF23 0x80 /* Mailbox 23 Mailbox Receive Interrupt Flag */
-#define nMBRIF23 0x0
#define MBRIF24 0x100 /* Mailbox 24 Mailbox Receive Interrupt Flag */
-#define nMBRIF24 0x0
#define MBRIF25 0x200 /* Mailbox 25 Mailbox Receive Interrupt Flag */
-#define nMBRIF25 0x0
#define MBRIF26 0x400 /* Mailbox 26 Mailbox Receive Interrupt Flag */
-#define nMBRIF26 0x0
#define MBRIF27 0x800 /* Mailbox 27 Mailbox Receive Interrupt Flag */
-#define nMBRIF27 0x0
#define MBRIF28 0x1000 /* Mailbox 28 Mailbox Receive Interrupt Flag */
-#define nMBRIF28 0x0
#define MBRIF29 0x2000 /* Mailbox 29 Mailbox Receive Interrupt Flag */
-#define nMBRIF29 0x0
#define MBRIF30 0x4000 /* Mailbox 30 Mailbox Receive Interrupt Flag */
-#define nMBRIF30 0x0
#define MBRIF31 0x8000 /* Mailbox 31 Mailbox Receive Interrupt Flag */
-#define nMBRIF31 0x0
/* Bit masks for EPPIx_STATUS */
#define CFIFO_ERR 0x1 /* Chroma FIFO Error */
-#define nCFIFO_ERR 0x0
#define YFIFO_ERR 0x2 /* Luma FIFO Error */
-#define nYFIFO_ERR 0x0
#define LTERR_OVR 0x4 /* Line Track Overflow */
-#define nLTERR_OVR 0x0
#define LTERR_UNDR 0x8 /* Line Track Underflow */
-#define nLTERR_UNDR 0x0
#define FTERR_OVR 0x10 /* Frame Track Overflow */
-#define nFTERR_OVR 0x0
#define FTERR_UNDR 0x20 /* Frame Track Underflow */
-#define nFTERR_UNDR 0x0
#define ERR_NCOR 0x40 /* Preamble Error Not Corrected */
-#define nERR_NCOR 0x0
#define DMA1URQ 0x80 /* DMA1 Urgent Request */
-#define nDMA1URQ 0x0
#define DMA0URQ 0x100 /* DMA0 Urgent Request */
-#define nDMA0URQ 0x0
#define ERR_DET 0x4000 /* Preamble Error Detected */
-#define nERR_DET 0x0
#define FLD 0x8000 /* Field */
-#define nFLD 0x0
/* Bit masks for EPPIx_CONTROL */
#define EPPI_EN 0x1 /* Enable */
-#define nEPPI_EN 0x0
#define EPPI_DIR 0x2 /* Direction */
-#define nEPPI_DIR 0x0
#define XFR_TYPE 0xc /* Operating Mode */
#define FS_CFG 0x30 /* Frame Sync Configuration */
#define FLD_SEL 0x40 /* Field Select/Trigger */
-#define nFLD_SEL 0x0
#define ITU_TYPE 0x80 /* ITU Interlaced or Progressive */
-#define nITU_TYPE 0x0
#define BLANKGEN 0x100 /* ITU Output Mode with Internal Blanking Generation */
-#define nBLANKGEN 0x0
#define ICLKGEN 0x200 /* Internal Clock Generation */
-#define nICLKGEN 0x0
#define IFSGEN 0x400 /* Internal Frame Sync Generation */
-#define nIFSGEN 0x0
#define POLC 0x1800 /* Frame Sync and Data Driving/Sampling Edges */
#define POLS 0x6000 /* Frame Sync Polarity */
#define DLENGTH 0x38000 /* Data Length */
#define SKIP_EN 0x40000 /* Skip Enable */
-#define nSKIP_EN 0x0
#define SKIP_EO 0x80000 /* Skip Even or Odd */
-#define nSKIP_EO 0x0
#define PACKEN 0x100000 /* Packing/Unpacking Enable */
-#define nPACKEN 0x0
#define SWAPEN 0x200000 /* Swap Enable */
-#define nSWAPEN 0x0
#define SIGN_EXT 0x400000 /* Sign Extension or Zero-filled / Data Split Format */
-#define nSIGN_EXT 0x0
#define SPLT_EVEN_ODD 0x800000 /* Split Even and Odd Data Samples */
-#define nSPLT_EVEN_ODD 0x0
#define SUBSPLT_ODD 0x1000000 /* Sub-split Odd Samples */
-#define nSUBSPLT_ODD 0x0
#define DMACFG 0x2000000 /* One or Two DMA Channels Mode */
-#define nDMACFG 0x0
#define RGB_FMT_EN 0x4000000 /* RGB Formatting Enable */
-#define nRGB_FMT_EN 0x0
#define FIFO_RWM 0x18000000 /* FIFO Regular Watermarks */
#define FIFO_UWM 0x60000000 /* FIFO Urgent Watermarks */
+#define DLEN_8 (0 << 15) /* 000 - 8 bits */
+#define DLEN_10 (1 << 15) /* 001 - 10 bits */
+#define DLEN_12 (2 << 15) /* 010 - 12 bits */
+#define DLEN_14 (3 << 15) /* 011 - 14 bits */
+#define DLEN_16 (4 << 15) /* 100 - 16 bits */
+#define DLEN_18 (5 << 15) /* 101 - 18 bits */
+#define DLEN_24 (6 << 15) /* 110 - 24 bits */
+
+
/* Bit masks for EPPIx_FS2W_LVB */
#define F1VB_BD 0xff /* Vertical Blanking before Field 1 Active Data */
@@ -3951,60 +3085,36 @@
/* Bit masks for SPIx_CTL */
#define SPE 0x4000 /* SPI Enable */
-#define nSPE 0x0
#define WOM 0x2000 /* Write Open Drain Master */
-#define nWOM 0x0
#define MSTR 0x1000 /* Master Mode */
-#define nMSTR 0x0
#define CPOL 0x800 /* Clock Polarity */
-#define nCPOL 0x0
#define CPHA 0x400 /* Clock Phase */
-#define nCPHA 0x0
#define LSBF 0x200 /* LSB First */
-#define nLSBF 0x0
#define SIZE 0x100 /* Size of Words */
-#define nSIZE 0x0
#define EMISO 0x20 /* Enable MISO Output */
-#define nEMISO 0x0
#define PSSE 0x10 /* Slave-Select Enable */
-#define nPSSE 0x0
#define GM 0x8 /* Get More Data */
-#define nGM 0x0
#define SZ 0x4 /* Send Zero */
-#define nSZ 0x0
#define TIMOD 0x3 /* Transfer Initiation Mode */
/* Bit masks for SPIx_FLG */
#define FLS1 0x2 /* Slave Select Enable 1 */
-#define nFLS1 0x0
#define FLS2 0x4 /* Slave Select Enable 2 */
-#define nFLS2 0x0
#define FLS3 0x8 /* Slave Select Enable 3 */
-#define nFLS3 0x0
#define FLG1 0x200 /* Slave Select Value 1 */
-#define nFLG1 0x0
#define FLG2 0x400 /* Slave Select Value 2 */
-#define nFLG2 0x0
#define FLG3 0x800 /* Slave Select Value 3 */
-#define nFLG3 0x0
/* Bit masks for SPIx_STAT */
#define TXCOL 0x40 /* Transmit Collision Error */
-#define nTXCOL 0x0
#define RXS 0x20 /* RDBR Data Buffer Status */
-#define nRXS 0x0
#define RBSY 0x10 /* Receive Error */
-#define nRBSY 0x0
#define TXS 0x8 /* TDBR Data Buffer Status */
-#define nTXS 0x0
#define TXE 0x4 /* Transmission Error */
-#define nTXE 0x0
#define MODF 0x2 /* Mode Fault Error */
-#define nMODF 0x0
#define SPIF 0x1 /* SPI Finished */
-#define nSPIF 0x0
/* Bit masks for SPIx_TDBR */
@@ -4028,9 +3138,7 @@
#define PRESCALE 0x7f /* Prescale Value */
#define TWI_ENA 0x80 /* TWI Enable */
-#define nTWI_ENA 0x0
#define SCCB 0x200 /* Serial Camera Control Bus */
-#define nSCCB 0x0
/* Bit maskes for TWIx_CLKDIV */
@@ -4040,13 +3148,9 @@
/* Bit maskes for TWIx_SLAVE_CTL */
#define SEN 0x1 /* Slave Enable */
-#define nSEN 0x0
#define STDVAL 0x4 /* Slave Transmit Data Valid */
-#define nSTDVAL 0x0
#define NAK 0x8 /* Not Acknowledge */
-#define nNAK 0x0
#define GEN 0x10 /* General Call Enable */
-#define nGEN 0x0
/* Bit maskes for TWIx_SLAVE_ADDR */
@@ -4055,27 +3159,18 @@
/* Bit maskes for TWIx_SLAVE_STAT */
#define SDIR 0x1 /* Slave Transfer Direction */
-#define nSDIR 0x0
#define GCALL 0x2 /* General Call */
-#define nGCALL 0x0
/* Bit maskes for TWIx_MASTER_CTL */
#define MEN 0x1 /* Master Mode Enable */
-#define nMEN 0x0
#define MDIR 0x4 /* Master Transfer Direction */
-#define nMDIR 0x0
#define FAST 0x8 /* Fast Mode */
-#define nFAST 0x0
#define STOP 0x10 /* Issue Stop Condition */
-#define nSTOP 0x0
#define RSTART 0x20 /* Repeat Start */
-#define nRSTART 0x0
#define DCNT 0x3fc0 /* Data Transfer Count */
#define SDAOVR 0x4000 /* Serial Data Override */
-#define nSDAOVR 0x0
#define SCLOVR 0x8000 /* Serial Clock Override */
-#define nSCLOVR 0x0
/* Bit maskes for TWIx_MASTER_ADDR */
@@ -4084,34 +3179,21 @@
/* Bit maskes for TWIx_MASTER_STAT */
#define MPROG 0x1 /* Master Transfer in Progress */
-#define nMPROG 0x0
#define LOSTARB 0x2 /* Lost Arbitration */
-#define nLOSTARB 0x0
#define ANAK 0x4 /* Address Not Acknowledged */
-#define nANAK 0x0
#define DNAK 0x8 /* Data Not Acknowledged */
-#define nDNAK 0x0
#define BUFRDERR 0x10 /* Buffer Read Error */
-#define nBUFRDERR 0x0
#define BUFWRERR 0x20 /* Buffer Write Error */
-#define nBUFWRERR 0x0
#define SDASEN 0x40 /* Serial Data Sense */
-#define nSDASEN 0x0
#define SCLSEN 0x80 /* Serial Clock Sense */
-#define nSCLSEN 0x0
#define BUSBUSY 0x100 /* Bus Busy */
-#define nBUSBUSY 0x0
/* Bit maskes for TWIx_FIFO_CTL */
#define XMTFLUSH 0x1 /* Transmit Buffer Flush */
-#define nXMTFLUSH 0x0
#define RCVFLUSH 0x2 /* Receive Buffer Flush */
-#define nRCVFLUSH 0x0
#define XMTINTLEN 0x4 /* Transmit Buffer Interrupt Length */
-#define nXMTINTLEN 0x0
#define RCVINTLEN 0x8 /* Receive Buffer Interrupt Length */
-#define nRCVINTLEN 0x0
/* Bit maskes for TWIx_FIFO_STAT */
@@ -4121,40 +3203,24 @@
/* Bit maskes for TWIx_INT_MASK */
#define SINITM 0x1 /* Slave Transfer Initiated Interrupt Mask */
-#define nSINITM 0x0
#define SCOMPM 0x2 /* Slave Transfer Complete Interrupt Mask */
-#define nSCOMPM 0x0
#define SERRM 0x4 /* Slave Transfer Error Interrupt Mask */
-#define nSERRM 0x0
#define SOVFM 0x8 /* Slave Overflow Interrupt Mask */
-#define nSOVFM 0x0
#define MCOMPM 0x10 /* Master Transfer Complete Interrupt Mask */
-#define nMCOMPM 0x0
#define MERRM 0x20 /* Master Transfer Error Interrupt Mask */
-#define nMERRM 0x0
#define XMTSERVM 0x40 /* Transmit FIFO Service Interrupt Mask */
-#define nXMTSERVM 0x0
#define RCVSERVM 0x80 /* Receive FIFO Service Interrupt Mask */
-#define nRCVSERVM 0x0
/* Bit maskes for TWIx_INT_STAT */
#define SINIT 0x1 /* Slave Transfer Initiated */
-#define nSINIT 0x0
#define SCOMP 0x2 /* Slave Transfer Complete */
-#define nSCOMP 0x0
#define SERR 0x4 /* Slave Transfer Error */
-#define nSERR 0x0
#define SOVF 0x8 /* Slave Overflow */
-#define nSOVF 0x0
#define MCOMP 0x10 /* Master Transfer Complete */
-#define nMCOMP 0x0
#define MERR 0x20 /* Master Transfer Error */
-#define nMERR 0x0
#define XMTSERV 0x40 /* Transmit FIFO Service */
-#define nXMTSERV 0x0
#define RCVSERV 0x80 /* Receive FIFO Service */
-#define nRCVSERV 0x0
/* Bit maskes for TWIx_XMT_DATA8 */
@@ -4175,81 +3241,51 @@
/* Bit masks for SPORTx_TCR1 */
#define TCKFE 0x4000 /* Clock Falling Edge Select */
-#define nTCKFE 0x0
#define LATFS 0x2000 /* Late Transmit Frame Sync */
-#define nLATFS 0x0
#define LTFS 0x1000 /* Low Transmit Frame Sync Select */
-#define nLTFS 0x0
#define DITFS 0x800 /* Data-Independent Transmit Frame Sync Select */
-#define nDITFS 0x0
#define TFSR 0x400 /* Transmit Frame Sync Required Select */
-#define nTFSR 0x0
#define ITFS 0x200 /* Internal Transmit Frame Sync Select */
-#define nITFS 0x0
#define TLSBIT 0x10 /* Transmit Bit Order */
-#define nTLSBIT 0x0
#define TDTYPE 0xc /* Data Formatting Type Select */
#define ITCLK 0x2 /* Internal Transmit Clock Select */
-#define nITCLK 0x0
#define TSPEN 0x1 /* Transmit Enable */
-#define nTSPEN 0x0
/* Bit masks for SPORTx_TCR2 */
#define TRFST 0x400 /* Left/Right Order */
-#define nTRFST 0x0
#define TSFSE 0x200 /* Transmit Stereo Frame Sync Enable */
-#define nTSFSE 0x0
#define TXSE 0x100 /* TxSEC Enable */
-#define nTXSE 0x0
#define SLEN_T 0x1f /* SPORT Word Length */
/* Bit masks for SPORTx_RCR1 */
#define RCKFE 0x4000 /* Clock Falling Edge Select */
-#define nRCKFE 0x0
#define LARFS 0x2000 /* Late Receive Frame Sync */
-#define nLARFS 0x0
#define LRFS 0x1000 /* Low Receive Frame Sync Select */
-#define nLRFS 0x0
#define RFSR 0x400 /* Receive Frame Sync Required Select */
-#define nRFSR 0x0
#define IRFS 0x200 /* Internal Receive Frame Sync Select */
-#define nIRFS 0x0
#define RLSBIT 0x10 /* Receive Bit Order */
-#define nRLSBIT 0x0
#define RDTYPE 0xc /* Data Formatting Type Select */
#define IRCLK 0x2 /* Internal Receive Clock Select */
-#define nIRCLK 0x0
#define RSPEN 0x1 /* Receive Enable */
-#define nRSPEN 0x0
/* Bit masks for SPORTx_RCR2 */
#define RRFST 0x400 /* Left/Right Order */
-#define nRRFST 0x0
#define RSFSE 0x200 /* Receive Stereo Frame Sync Enable */
-#define nRSFSE 0x0
#define RXSE 0x100 /* RxSEC Enable */
-#define nRXSE 0x0
#define SLEN_R 0x1f /* SPORT Word Length */
/* Bit masks for SPORTx_STAT */
#define TXHRE 0x40 /* Transmit Hold Register Empty */
-#define nTXHRE 0x0
#define TOVF 0x20 /* Sticky Transmit Overflow Status */
-#define nTOVF 0x0
#define TUVF 0x10 /* Sticky Transmit Underflow Status */
-#define nTUVF 0x0
#define TXF 0x8 /* Transmit FIFO Full Status */
-#define nTXF 0x0
#define ROVF 0x4 /* Sticky Receive Overflow Status */
-#define nROVF 0x0
#define RUVF 0x2 /* Sticky Receive Underflow Status */
-#define nRUVF 0x0
#define RXNE 0x1 /* Receive FIFO Not Empty Status */
-#define nRXNE 0x0
/* Bit masks for SPORTx_MCMC1 */
@@ -4260,13 +3296,9 @@
#define MFD 0xf000 /* Multi channel Frame Delay */
#define FSDR 0x80 /* Frame Sync to Data Relationship */
-#define nFSDR 0x0
#define MCMEM 0x10 /* Multi channel Frame Mode Enable */
-#define nMCMEM 0x0
#define MCDRXPE 0x8 /* Multi channel DMA Receive Packing */
-#define nMCDRXPE 0x0
#define MCDTXPE 0x4 /* Multi channel DMA Transmit Packing */
-#define nMCDTXPE 0x0
#define MCCRM 0x3 /* 2X Clock Recovery Mode */
/* Bit masks for SPORTx_CHNL */
@@ -4280,115 +3312,59 @@
#define WLS 0x3 /* Word Length Select */
#endif
#define STB 0x4 /* Stop Bits */
-#define nSTB 0x0
#define PEN 0x8 /* Parity Enable */
-#define nPEN 0x0
#define EPS 0x10 /* Even Parity Select */
-#define nEPS 0x0
#define STP 0x20 /* Sticky Parity */
-#define nSTP 0x0
#define SB 0x40 /* Set Break */
-#define nSB 0x0
/* Bit masks for UARTx_MCR */
#define XOFF 0x1 /* Transmitter Off */
-#define nXOFF 0x0
#define MRTS 0x2 /* Manual Request To Send */
-#define nMRTS 0x0
#define RFIT 0x4 /* Receive FIFO IRQ Threshold */
-#define nRFIT 0x0
#define RFRT 0x8 /* Receive FIFO RTS Threshold */
-#define nRFRT 0x0
#define LOOP_ENA 0x10 /* Loopback Mode Enable */
-#define nLOOP_ENA 0x0
#define FCPOL 0x20 /* Flow Control Pin Polarity */
-#define nFCPOL 0x0
#define ARTS 0x40 /* Automatic Request To Send */
-#define nARTS 0x0
#define ACTS 0x80 /* Automatic Clear To Send */
-#define nACTS 0x0
/* Bit masks for UARTx_LSR */
#define DR 0x1 /* Data Ready */
-#define nDR 0x0
#define OE 0x2 /* Overrun Error */
-#define nOE 0x0
#define PE 0x4 /* Parity Error */
-#define nPE 0x0
#define FE 0x8 /* Framing Error */
-#define nFE 0x0
#define BI 0x10 /* Break Interrupt */
-#define nBI 0x0
#define THRE 0x20 /* THR Empty */
-#define nTHRE 0x0
#define TEMT 0x40 /* Transmitter Empty */
-#define nTEMT 0x0
#define TFI 0x80 /* Transmission Finished Indicator */
-#define nTFI 0x0
/* Bit masks for UARTx_MSR */
#define SCTS 0x1 /* Sticky CTS */
-#define nSCTS 0x0
#define CTS 0x10 /* Clear To Send */
-#define nCTS 0x0
#define RFCS 0x20 /* Receive FIFO Count Status */
-#define nRFCS 0x0
-
-/* Bit masks for UARTx_IER_SET */
-
-#define ERBFI_S 0x1 /* Enable Receive Buffer Full Interrupt */
-#define nERBFI_S 0x0
-#define ETBEI_S 0x2 /* Enable Transmit Buffer Empty Interrupt */
-#define nETBEI_S 0x0
-#define ELSI_S 0x4 /* Enable Receive Status Interrupt */
-#define nELSI_S 0x0
-#define EDSSI_S 0x8 /* Enable Modem Status Interrupt */
-#define nEDSSI_S 0x0
-#define EDTPTI_S 0x10 /* Enable DMA Transmit PIRQ Interrupt */
-#define nEDTPTI_S 0x0
-#define ETFI_S 0x20 /* Enable Transmission Finished Interrupt */
-#define nETFI_S 0x0
-#define ERFCI_S 0x40 /* Enable Receive FIFO Count Interrupt */
-#define nERFCI_S 0x0
-
-/* Bit masks for UARTx_IER_CLEAR */
-
-#define ERBFI_C 0x1 /* Enable Receive Buffer Full Interrupt */
-#define nERBFI_C 0x0
-#define ETBEI_C 0x2 /* Enable Transmit Buffer Empty Interrupt */
-#define nETBEI_C 0x0
-#define ELSI_C 0x4 /* Enable Receive Status Interrupt */
-#define nELSI_C 0x0
-#define EDSSI_C 0x8 /* Enable Modem Status Interrupt */
-#define nEDSSI_C 0x0
-#define EDTPTI_C 0x10 /* Enable DMA Transmit PIRQ Interrupt */
-#define nEDTPTI_C 0x0
-#define ETFI_C 0x20 /* Enable Transmission Finished Interrupt */
-#define nETFI_C 0x0
-#define ERFCI_C 0x40 /* Enable Receive FIFO Count Interrupt */
-#define nERFCI_C 0x0
+
+/* Bit masks for UARTx_IER_SET & UARTx_IER_CLEAR */
+
+#define ERBFI 0x1 /* Enable Receive Buffer Full Interrupt */
+#define ETBEI 0x2 /* Enable Transmit Buffer Empty Interrupt */
+#define ELSI 0x4 /* Enable Receive Status Interrupt */
+#define EDSSI 0x8 /* Enable Modem Status Interrupt */
+#define EDTPTI 0x10 /* Enable DMA Transmit PIRQ Interrupt */
+#define ETFI 0x20 /* Enable Transmission Finished Interrupt */
+#define ERFCI 0x40 /* Enable Receive FIFO Count Interrupt */
/* Bit masks for UARTx_GCTL */
#define UCEN 0x1 /* UART Enable */
-#define nUCEN 0x0
#define IREN 0x2 /* IrDA Mode Enable */
-#define nIREN 0x0
#define TPOLC 0x4 /* IrDA TX Polarity Change */
-#define nTPOLC 0x0
#define RPOLC 0x8 /* IrDA RX Polarity Change */
-#define nRPOLC 0x0
#define FPE 0x10 /* Force Parity Error */
-#define nFPE 0x0
#define FFE 0x20 /* Force Framing Error */
-#define nFFE 0x0
#define EDBO 0x40 /* Enable Divide-by-One */
-#define nEDBO 0x0
#define EGLSI 0x80 /* Enable Global LS Interrupt */
-#define nEGLSI 0x0
/* ******************************************* */
@@ -4398,32 +3374,32 @@
/* BCODE bit field options (SYSCFG register) */
#define BCODE_WAKEUP 0x0000 /* boot according to wake-up condition */
-#define BCODE_FULLBOOT 0x0010 /* always perform full boot */
+#define BCODE_FULLBOOT 0x0010 /* always perform full boot */
#define BCODE_QUICKBOOT 0x0020 /* always perform quick boot */
#define BCODE_NOBOOT 0x0030 /* always perform full boot */
/* CNT_COMMAND bit field options */
-
+
#define W1LCNT_ZERO 0x0001 /* write 1 to load CNT_COUNTER with zero */
#define W1LCNT_MIN 0x0004 /* write 1 to load CNT_COUNTER from CNT_MIN */
#define W1LCNT_MAX 0x0008 /* write 1 to load CNT_COUNTER from CNT_MAX */
-
+
#define W1LMIN_ZERO 0x0010 /* write 1 to load CNT_MIN with zero */
#define W1LMIN_CNT 0x0020 /* write 1 to load CNT_MIN from CNT_COUNTER */
#define W1LMIN_MAX 0x0080 /* write 1 to load CNT_MIN from CNT_MAX */
-
+
#define W1LMAX_ZERO 0x0100 /* write 1 to load CNT_MAX with zero */
#define W1LMAX_CNT 0x0200 /* write 1 to load CNT_MAX from CNT_COUNTER */
#define W1LMAX_MIN 0x0400 /* write 1 to load CNT_MAX from CNT_MIN */
-
+
/* CNT_CONFIG bit field options */
-
+
#define CNTMODE_QUADENC 0x0000 /* quadrature encoder mode */
#define CNTMODE_BINENC 0x0100 /* binary encoder mode */
#define CNTMODE_UDCNT 0x0200 /* up/down counter mode */
#define CNTMODE_DIRCNT 0x0400 /* direction counter mode */
#define CNTMODE_DIRTMR 0x0500 /* direction timer mode */
-
+
#define BNDMODE_COMP 0x0000 /* boundary compare mode */
#define BNDMODE_ZERO 0x1000 /* boundary compare and zero mode */
#define BNDMODE_CAPT 0x2000 /* boundary capture mode */
@@ -4436,7 +3412,7 @@
#define EXT_CLK 0x0003
/* UARTx_LCR bit field options */
-
+
#define WLS_5 0x0000 /* 5 data bits */
#define WLS_6 0x0001 /* 6 data bits */
#define WLS_7 0x0002 /* 7 data bits */
@@ -4484,7 +3460,7 @@
#define PIQ30 0x40000000
#define PIQ31 0x80000000
-/* PORT A Bit Definitions for the registers
+/* PORT A Bit Definitions for the registers
PORTA, PORTA_SET, PORTA_CLEAR,
PORTA_DIR_SET, PORTA_DIR_CLEAR, PORTA_INEN,
PORTA_FER registers
@@ -4507,7 +3483,7 @@ PORTA_FER registers
#define PA14 0x4000
#define PA15 0x8000
-/* PORT B Bit Definitions for the registers
+/* PORT B Bit Definitions for the registers
PORTB, PORTB_SET, PORTB_CLEAR,
PORTB_DIR_SET, PORTB_DIR_CLEAR, PORTB_INEN,
PORTB_FER registers
@@ -4530,7 +3506,7 @@ PORTB_FER registers
#define PB14 0x4000
-/* PORT C Bit Definitions for the registers
+/* PORT C Bit Definitions for the registers
PORTC, PORTC_SET, PORTC_CLEAR,
PORTC_DIR_SET, PORTC_DIR_CLEAR, PORTC_INEN,
PORTC_FER registers
@@ -4553,7 +3529,7 @@ PORTC_FER registers
#define PC13 0x2000
-/* PORT D Bit Definitions for the registers
+/* PORT D Bit Definitions for the registers
PORTD, PORTD_SET, PORTD_CLEAR,
PORTD_DIR_SET, PORTD_DIR_CLEAR, PORTD_INEN,
PORTD_FER registers
@@ -4576,7 +3552,7 @@ PORTD_FER registers
#define PD14 0x4000
#define PD15 0x8000
-/* PORT E Bit Definitions for the registers
+/* PORT E Bit Definitions for the registers
PORTE, PORTE_SET, PORTE_CLEAR,
PORTE_DIR_SET, PORTE_DIR_CLEAR, PORTE_INEN,
PORTE_FER registers
@@ -4600,7 +3576,7 @@ PORTE_FER registers
#define PE14 0x4000
#define PE15 0x8000
-/* PORT F Bit Definitions for the registers
+/* PORT F Bit Definitions for the registers
PORTF, PORTF_SET, PORTF_CLEAR,
PORTF_DIR_SET, PORTF_DIR_CLEAR, PORTF_INEN,
PORTF_FER registers
@@ -4624,7 +3600,7 @@ PORTF_FER registers
#define PF14 0x4000
#define PF15 0x8000
-/* PORT G Bit Definitions for the registers
+/* PORT G Bit Definitions for the registers
PORTG, PORTG_SET, PORTG_CLEAR,
PORTG_DIR_SET, PORTG_DIR_CLEAR, PORTG_INEN,
PORTG_FER registers
@@ -4648,7 +3624,7 @@ PORTG_FER registers
#define PG14 0x4000
#define PG15 0x8000
-/* PORT H Bit Definitions for the registers
+/* PORT H Bit Definitions for the registers
PORTH, PORTH_SET, PORTH_CLEAR,
PORTH_DIR_SET, PORTH_DIR_CLEAR, PORTH_INEN,
PORTH_FER registers
@@ -4671,7 +3647,7 @@ PORTH_FER registers
#define PH13 0x2000
-/* PORT I Bit Definitions for the registers
+/* PORT I Bit Definitions for the registers
PORTI, PORTI_SET, PORTI_CLEAR,
PORTI_DIR_SET, PORTI_DIR_CLEAR, PORTI_INEN,
PORTI_FER registers
@@ -4695,7 +3671,7 @@ PORTI_FER registers
#define PI14 0x4000
#define PI15 0x8000
-/* PORT J Bit Definitions for the registers
+/* PORT J Bit Definitions for the registers
PORTJ, PORTJ_SET, PORTJ_CLEAR,
PORTJ_DIR_SET, PORTJ_DIR_CLEAR, PORTJ_INEN,
PORTJ_FER registers
@@ -4716,7 +3692,7 @@ PORTJ_FER registers
#define PJ11 0x0800
#define PJ12 0x1000
#define PJ13 0x2000
-
+
/* Port Muxing Bit Fields for PORTx_MUX Registers */
@@ -4860,7 +3836,7 @@ PORTJ_FER registers
#define B0MAP_PIL 0x00000006 /* Map Port I Low to Byte 0 */
#define B0MAP_PJL 0x00000007 /* Map Port J Low to Byte 0 */
-#define B1MAP_PCH 0x00000000 /* Map Port C High to Byte 1 */
+#define B1MAP_PCH 0x00000000 /* Map Port C High to Byte 1 */
#define B1MAP_PDH 0x00000100 /* Map Port D High to Byte 1 */
#define B1MAP_PEH 0x00000200 /* Map Port E High to Byte 1 */
#define B1MAP_PFH 0x00000300 /* Map Port F High to Byte 1 */
@@ -4869,27 +3845,27 @@ PORTJ_FER registers
#define B1MAP_PIH 0x00000600 /* Map Port I High to Byte 1 */
#define B1MAP_PJH 0x00000700 /* Map Port J High to Byte 1 */
-#define B2MAP_PCL 0x00000000 /* Map Port C Low to Byte 2 */
-#define B2MAP_PDL 0x00010000 /* Map Port D Low to Byte 2 */
-#define B2MAP_PEL 0x00020000 /* Map Port E Low to Byte 2 */
-#define B2MAP_PFL 0x00030000 /* Map Port F Low to Byte 2 */
-#define B2MAP_PGL 0x00040000 /* Map Port G Low to Byte 2 */
-#define B2MAP_PHL 0x00050000 /* Map Port H Low to Byte 2 */
-#define B2MAP_PIL 0x00060000 /* Map Port I Low to Byte 2 */
-#define B2MAP_PJL 0x00070000 /* Map Port J Low to Byte 2 */
-
-#define B3MAP_PCH 0x00000000 /* Map Port C High to Byte 3 */
-#define B3MAP_PDH 0x01000000 /* Map Port D High to Byte 3 */
-#define B3MAP_PEH 0x02000000 /* Map Port E High to Byte 3 */
-#define B3MAP_PFH 0x03000000 /* Map Port F High to Byte 3 */
-#define B3MAP_PGH 0x04000000 /* Map Port G High to Byte 3 */
-#define B3MAP_PHH 0x05000000 /* Map Port H High to Byte 3 */
-#define B3MAP_PIH 0x06000000 /* Map Port I High to Byte 3 */
-#define B3MAP_PJH 0x07000000 /* Map Port J High to Byte 3 */
+#define B2MAP_PCL 0x00000000 /* Map Port C Low to Byte 2 */
+#define B2MAP_PDL 0x00010000 /* Map Port D Low to Byte 2 */
+#define B2MAP_PEL 0x00020000 /* Map Port E Low to Byte 2 */
+#define B2MAP_PFL 0x00030000 /* Map Port F Low to Byte 2 */
+#define B2MAP_PGL 0x00040000 /* Map Port G Low to Byte 2 */
+#define B2MAP_PHL 0x00050000 /* Map Port H Low to Byte 2 */
+#define B2MAP_PIL 0x00060000 /* Map Port I Low to Byte 2 */
+#define B2MAP_PJL 0x00070000 /* Map Port J Low to Byte 2 */
+
+#define B3MAP_PCH 0x00000000 /* Map Port C High to Byte 3 */
+#define B3MAP_PDH 0x01000000 /* Map Port D High to Byte 3 */
+#define B3MAP_PEH 0x02000000 /* Map Port E High to Byte 3 */
+#define B3MAP_PFH 0x03000000 /* Map Port F High to Byte 3 */
+#define B3MAP_PGH 0x04000000 /* Map Port G High to Byte 3 */
+#define B3MAP_PHH 0x05000000 /* Map Port H High to Byte 3 */
+#define B3MAP_PIH 0x06000000 /* Map Port I High to Byte 3 */
+#define B3MAP_PJH 0x07000000 /* Map Port J High to Byte 3 */
/* for legacy compatibility */
-
+
#define WLS(x) (((x)-5) & 0x03) /* Word Length Select */
#define W1LMAX_MAX W1LMAX_MIN
#define EBIU_AMCBCTL0 EBIU_AMBCTL0
diff --git a/include/asm-blackfin/mach-bf548/dma.h b/include/asm-blackfin/mach-bf548/dma.h
new file mode 100644
index 000000000000..fcc8b4c34c6a
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/dma.h
@@ -0,0 +1,73 @@
+/*
+ * file: include/asm-blackfin/mach-bf548/dma.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ * system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs: enter bugs at http://blackfin.uclinux.org/
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MACH_DMA_H_
+#define _MACH_DMA_H_
+
+#define CH_SPORT0_RX 0
+#define CH_SPORT0_TX 1
+#define CH_SPORT1_RX 2
+#define CH_SPORT1_TX 3
+#define CH_SPI0 4
+#define CH_SPI1 5
+#define CH_UART0_RX 6
+#define CH_UART0_TX 7
+#define CH_UART1_RX 8
+#define CH_UART1_TX 9
+#define CH_ATAPI_RX 10
+#define CH_ATAPI_TX 11
+#define CH_EPPI0 12
+#define CH_EPPI1 13
+#define CH_EPPI2 14
+#define CH_PIXC_IMAGE 15
+#define CH_PIXC_OVERLAY 16
+#define CH_PIXC_OUTPUT 17
+#define CH_SPORT2_RX 18
+#define CH_SPORT2_TX 19
+#define CH_SPORT3_RX 20
+#define CH_SPORT3_TX 21
+#define CH_SDH 22
+#define CH_SPI2 23
+
+#define CH_MEM_STREAM0_DEST 24
+#define CH_MEM_STREAM0_SRC 25
+#define CH_MEM_STREAM1_DEST 26
+#define CH_MEM_STREAM1_SRC 27
+#define CH_MEM_STREAM2_DEST 28
+#define CH_MEM_STREAM2_SRC 29
+#define CH_MEM_STREAM3_DEST 30
+#define CH_MEM_STREAM3_SRC 31
+
+#define MAX_BLACKFIN_DMA_CHANNEL 32
+
+extern int channel2irq(unsigned int channel);
+extern struct dma_register *base_addr[];
+#endif
diff --git a/include/asm-blackfin/mach-bf548/gpio.h b/include/asm-blackfin/mach-bf548/gpio.h
new file mode 100644
index 000000000000..dbf66bcabe35
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/gpio.h
@@ -0,0 +1,216 @@
+/*
+ * File: include/asm-blackfin/mach-bf548/gpio.h
+ * Based on:
+ * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ * Copyright 2004-2007 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+
+#define GPIO_PA0 0
+#define GPIO_PA1 1
+#define GPIO_PA2 2
+#define GPIO_PA3 3
+#define GPIO_PA4 4
+#define GPIO_PA5 5
+#define GPIO_PA6 6
+#define GPIO_PA7 7
+#define GPIO_PA8 8
+#define GPIO_PA9 9
+#define GPIO_PA10 10
+#define GPIO_PA11 11
+#define GPIO_PA12 12
+#define GPIO_PA13 13
+#define GPIO_PA14 14
+#define GPIO_PA15 15
+#define GPIO_PB0 16
+#define GPIO_PB1 17
+#define GPIO_PB2 18
+#define GPIO_PB3 19
+#define GPIO_PB4 20
+#define GPIO_PB5 21
+#define GPIO_PB6 22
+#define GPIO_PB7 23
+#define GPIO_PB8 24
+#define GPIO_PB9 25
+#define GPIO_PB10 26
+#define GPIO_PB11 27
+#define GPIO_PB12 28
+#define GPIO_PB13 29
+#define GPIO_PB14 30
+#define GPIO_PB15 31 /* N/A */
+#define GPIO_PC0 32
+#define GPIO_PC1 33
+#define GPIO_PC2 34
+#define GPIO_PC3 35
+#define GPIO_PC4 36
+#define GPIO_PC5 37
+#define GPIO_PC6 38
+#define GPIO_PC7 39
+#define GPIO_PC8 40
+#define GPIO_PC9 41
+#define GPIO_PC10 42
+#define GPIO_PC11 43
+#define GPIO_PC12 44
+#define GPIO_PC13 45
+#define GPIO_PC14 46 /* N/A */
+#define GPIO_PC15 47 /* N/A */
+#define GPIO_PD0 48
+#define GPIO_PD1 49
+#define GPIO_PD2 50
+#define GPIO_PD3 51
+#define GPIO_PD4 52
+#define GPIO_PD5 53
+#define GPIO_PD6 54
+#define GPIO_PD7 55
+#define GPIO_PD8 56
+#define GPIO_PD9 57
+#define GPIO_PD10 58
+#define GPIO_PD11 59
+#define GPIO_PD12 60
+#define GPIO_PD13 61
+#define GPIO_PD14 62
+#define GPIO_PD15 63
+#define GPIO_PE0 64
+#define GPIO_PE1 65
+#define GPIO_PE2 66
+#define GPIO_PE3 67
+#define GPIO_PE4 68
+#define GPIO_PE5 69
+#define GPIO_PE6 70
+#define GPIO_PE7 71
+#define GPIO_PE8 72
+#define GPIO_PE9 73
+#define GPIO_PE10 74
+#define GPIO_PE11 75
+#define GPIO_PE12 76
+#define GPIO_PE13 77
+#define GPIO_PE14 78
+#define GPIO_PE15 79
+#define GPIO_PF0 80
+#define GPIO_PF1 81
+#define GPIO_PF2 82
+#define GPIO_PF3 83
+#define GPIO_PF4 84
+#define GPIO_PF5 85
+#define GPIO_PF6 86
+#define GPIO_PF7 87
+#define GPIO_PF8 88
+#define GPIO_PF9 89
+#define GPIO_PF10 90
+#define GPIO_PF11 91
+#define GPIO_PF12 92
+#define GPIO_PF13 93
+#define GPIO_PF14 94
+#define GPIO_PF15 95
+#define GPIO_PG0 96
+#define GPIO_PG1 97
+#define GPIO_PG2 98
+#define GPIO_PG3 99
+#define GPIO_PG4 100
+#define GPIO_PG5 101
+#define GPIO_PG6 102
+#define GPIO_PG7 103
+#define GPIO_PG8 104
+#define GPIO_PG9 105
+#define GPIO_PG10 106
+#define GPIO_PG11 107
+#define GPIO_PG12 108
+#define GPIO_PG13 109
+#define GPIO_PG14 110
+#define GPIO_PG15 111
+#define GPIO_PH0 112
+#define GPIO_PH1 113
+#define GPIO_PH2 114
+#define GPIO_PH3 115
+#define GPIO_PH4 116
+#define GPIO_PH5 117
+#define GPIO_PH6 118
+#define GPIO_PH7 119
+#define GPIO_PH8 120
+#define GPIO_PH9 121
+#define GPIO_PH10 122
+#define GPIO_PH11 123
+#define GPIO_PH12 124
+#define GPIO_PH13 125
+#define GPIO_PH14 126 /* N/A */
+#define GPIO_PH15 127 /* N/A */
+#define GPIO_PI0 128
+#define GPIO_PI1 129
+#define GPIO_PI2 130
+#define GPIO_PI3 131
+#define GPIO_PI4 132
+#define GPIO_PI5 133
+#define GPIO_PI6 134
+#define GPIO_PI7 135
+#define GPIO_PI8 136
+#define GPIO_PI9 137
+#define GPIO_PI10 138
+#define GPIO_PI11 139
+#define GPIO_PI12 140
+#define GPIO_PI13 141
+#define GPIO_PI14 142
+#define GPIO_PI15 143
+#define GPIO_PJ0 144
+#define GPIO_PJ1 145
+#define GPIO_PJ2 146
+#define GPIO_PJ3 147
+#define GPIO_PJ4 148
+#define GPIO_PJ5 149
+#define GPIO_PJ6 150
+#define GPIO_PJ7 151
+#define GPIO_PJ8 152
+#define GPIO_PJ9 153
+#define GPIO_PJ10 154
+#define GPIO_PJ11 155
+#define GPIO_PJ12 156
+#define GPIO_PJ13 157
+#define GPIO_PJ14 158 /* N/A */
+#define GPIO_PJ15 159 /* N/A */
+
+#define MAX_BLACKFIN_GPIOS 160
+
+struct gpio_port_t {
+ unsigned short port_fer;
+ unsigned short dummy1;
+ unsigned short port_data;
+ unsigned short dummy2;
+ unsigned short port_set;
+ unsigned short dummy3;
+ unsigned short port_clear;
+ unsigned short dummy4;
+ unsigned short port_dir_set;
+ unsigned short dummy5;
+ unsigned short port_dir_clear;
+ unsigned short dummy6;
+ unsigned short port_inen;
+ unsigned short dummy7;
+ unsigned int port_mux;
+};
+
+int gpio_request(unsigned short gpio, const char *label);
+void peripheral_free(unsigned short per);
+int peripheral_request_list(unsigned short per[], const char *label);
+void peripheral_free_list(unsigned short per[]);
diff --git a/include/asm-blackfin/mach-bf548/irq.h b/include/asm-blackfin/mach-bf548/irq.h
new file mode 100644
index 000000000000..0b3325bb1fff
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/irq.h
@@ -0,0 +1,467 @@
+/*
+ * file: include/asm-blackfin/mach-bf548/irq.h
+ * based on: include/asm-blackfin/mach-bf537/irq.h
+ * author: Roy Huang (roy.huang@analog.com)
+ *
+ * created:
+ * description:
+ * system mmr register map
+ * rev:
+ *
+ * modified:
+ *
+ *
+ * bugs: enter bugs at http://blackfin.uclinux.org/
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _BF548_IRQ_H_
+#define _BF548_IRQ_H_
+
+/*
+ * Interrupt source definitions
+ Event Source Core Event Name
+Core Emulation **
+Events (highest priority) EMU 0
+ Reset RST 1
+ NMI NMI 2
+ Exception EVX 3
+ Reserved -- 4
+ Hardware Error IVHW 5
+ Core Timer IVTMR 6 *
+
+.....
+
+ Software Interrupt 1 IVG14 31
+ Software Interrupt 2 --
+ (lowest priority) IVG15 32 *
+ */
+
+#define NR_PERI_INTS (32 * 3)
+
+/* The ABSTRACT IRQ definitions */
+/** the first seven of the following are fixed, the rest you change if you need to **/
+#define IRQ_EMU 0 /* Emulation */
+#define IRQ_RST 1 /* reset */
+#define IRQ_NMI 2 /* Non Maskable */
+#define IRQ_EVX 3 /* Exception */
+#define IRQ_UNUSED 4 /* - unused interrupt*/
+#define IRQ_HWERR 5 /* Hardware Error */
+#define IRQ_CORETMR 6 /* Core timer */
+
+#define BFIN_IRQ(x) ((x) + 7)
+
+#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
+#define IRQ_DMAC0_ERR BFIN_IRQ(1) /* DMAC0 Status Interrupt */
+#define IRQ_EPPI0_ERR BFIN_IRQ(2) /* EPPI0 Error Interrupt */
+#define IRQ_SPORT0_ERR BFIN_IRQ(3) /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERR BFIN_IRQ(4) /* SPORT1 Error Interrupt */
+#define IRQ_SPI0_ERR BFIN_IRQ(5) /* SPI0 Status(Error) Interrupt */
+#define IRQ_UART0_ERR BFIN_IRQ(6) /* UART0 Status(Error) Interrupt */
+#define IRQ_RTC BFIN_IRQ(7) /* RTC Interrupt */
+#define IRQ_EPPI0 BFIN_IRQ(8) /* EPPI0 Interrupt (DMA12) */
+#define IRQ_SPORT0_RX BFIN_IRQ(9) /* SPORT0 RX Interrupt (DMA0) */
+#define IRQ_SPORT0_TX BFIN_IRQ(10) /* SPORT0 TX Interrupt (DMA1) */
+#define IRQ_SPORT1_RX BFIN_IRQ(11) /* SPORT1 RX Interrupt (DMA2) */
+#define IRQ_SPORT1_TX BFIN_IRQ(12) /* SPORT1 TX Interrupt (DMA3) */
+#define IRQ_SPI0 BFIN_IRQ(13) /* SPI0 Interrupt (DMA4) */
+#define IRQ_UART0_RX BFIN_IRQ(14) /* UART0 RX Interrupt (DMA6) */
+#define IRQ_UART0_TX BFIN_IRQ(15) /* UART0 TX Interrupt (DMA7) */
+#define IRQ_TIMER8 BFIN_IRQ(16) /* TIMER 8 Interrupt */
+#define IRQ_TIMER9 BFIN_IRQ(17) /* TIMER 9 Interrupt */
+#define IRQ_TIMER10 BFIN_IRQ(18) /* TIMER 10 Interrupt */
+#define IRQ_PINT0 BFIN_IRQ(19) /* PINT0 Interrupt */
+#define IRQ_PINT1 BFIN_IRQ(20) /* PINT1 Interrupt */
+#define IRQ_MDMAS0 BFIN_IRQ(21) /* MDMA Stream 0 Interrupt */
+#define IRQ_MDMAS1 BFIN_IRQ(22) /* MDMA Stream 1 Interrupt */
+#define IRQ_WATCHDOG BFIN_IRQ(23) /* Watchdog Interrupt */
+#define IRQ_DMAC1_ERR BFIN_IRQ(24) /* DMAC1 Status (Error) Interrupt */
+#define IRQ_SPORT2_ERR BFIN_IRQ(25) /* SPORT2 Error Interrupt */
+#define IRQ_SPORT3_ERR BFIN_IRQ(26) /* SPORT3 Error Interrupt */
+#define IRQ_MXVR_DATA BFIN_IRQ(27) /* MXVR Data Interrupt */
+#define IRQ_SPI1_ERR BFIN_IRQ(28) /* SPI1 Status (Error) Interrupt */
+#define IRQ_SPI2_ERR BFIN_IRQ(29) /* SPI2 Status (Error) Interrupt */
+#define IRQ_UART1_ERR BFIN_IRQ(30) /* UART1 Status (Error) Interrupt */
+#define IRQ_UART2_ERR BFIN_IRQ(31) /* UART2 Status (Error) Interrupt */
+#define IRQ_CAN0_ERR BFIN_IRQ(32) /* CAN0 Status (Error) Interrupt */
+#define IRQ_SPORT2_RX BFIN_IRQ(33) /* SPORT2 RX (DMA18) Interrupt */
+#define IRQ_SPORT2_TX BFIN_IRQ(34) /* SPORT2 TX (DMA19) Interrupt */
+#define IRQ_SPORT3_RX BFIN_IRQ(35) /* SPORT3 RX (DMA20) Interrupt */
+#define IRQ_SPORT3_TX BFIN_IRQ(36) /* SPORT3 TX (DMA21) Interrupt */
+#define IRQ_EPPI1 BFIN_IRQ(37) /* EPP1 (DMA13) Interrupt */
+#define IRQ_EPPI2 BFIN_IRQ(38) /* EPP2 (DMA14) Interrupt */
+#define IRQ_SPI1 BFIN_IRQ(39) /* SPI1 (DMA5) Interrupt */
+#define IRQ_SPI2 BFIN_IRQ(40) /* SPI2 (DMA23) Interrupt */
+#define IRQ_UART1_RX BFIN_IRQ(41) /* UART1 RX (DMA8) Interrupt */
+#define IRQ_UART1_TX BFIN_IRQ(42) /* UART1 TX (DMA9) Interrupt */
+#define IRQ_ATAPI_RX BFIN_IRQ(43) /* ATAPI RX (DMA10) Interrupt */
+#define IRQ_ATAPI_TX BFIN_IRQ(44) /* ATAPI TX (DMA11) Interrupt */
+#define IRQ_TWI0 BFIN_IRQ(45) /* TWI0 Interrupt */
+#define IRQ_TWI1 BFIN_IRQ(46) /* TWI1 Interrupt */
+#define IRQ_CAN0_RX BFIN_IRQ(47) /* CAN0 Receive Interrupt */
+#define IRQ_CAN0_TX BFIN_IRQ(48) /* CAN0 Transmit Interrupt */
+#define IRQ_MDMAS2 BFIN_IRQ(49) /* MDMA Stream 2 Interrupt */
+#define IRQ_MDMAS3 BFIN_IRQ(50) /* MDMA Stream 3 Interrupt */
+#define IRQ_MXVR_ERR BFIN_IRQ(51) /* MXVR Status (Error) Interrupt */
+#define IRQ_MXVR_MSG BFIN_IRQ(52) /* MXVR Message Interrupt */
+#define IRQ_MXVR_PKT BFIN_IRQ(53) /* MXVR Packet Interrupt */
+#define IRQ_EPP1_ERR BFIN_IRQ(54) /* EPPI1 Error Interrupt */
+#define IRQ_EPP2_ERR BFIN_IRQ(55) /* EPPI2 Error Interrupt */
+#define IRQ_UART3_ERR BFIN_IRQ(56) /* UART3 Status (Error) Interrupt */
+#define IRQ_HOST_ERR BFIN_IRQ(57) /* HOST Status (Error) Interrupt */
+#define IRQ_PIXC_ERR BFIN_IRQ(59) /* PIXC Status (Error) Interrupt */
+#define IRQ_NFC_ERR BFIN_IRQ(60) /* NFC Error Interrupt */
+#define IRQ_ATAPI_ERR BFIN_IRQ(61) /* ATAPI Error Interrupt */
+#define IRQ_CAN1_ERR BFIN_IRQ(62) /* CAN1 Status (Error) Interrupt */
+#define IRQ_HS_DMA_ERR BFIN_IRQ(63) /* Handshake DMA Status Interrupt */
+#define IRQ_PIXC_IN0 BFIN_IRQ(64) /* PIXC IN0 (DMA15) Interrupt */
+#define IRQ_PIXC_IN1 BFIN_IRQ(65) /* PIXC IN1 (DMA16) Interrupt */
+#define IRQ_PIXC_OUT BFIN_IRQ(66) /* PIXC OUT (DMA17) Interrupt */
+#define IRQ_SDH BFIN_IRQ(67) /* SDH/NFC (DMA22) Interrupt */
+#define IRQ_CNT BFIN_IRQ(68) /* CNT Interrupt */
+#define IRQ_KEY BFIN_IRQ(69) /* KEY Interrupt */
+#define IRQ_CAN1_RX BFIN_IRQ(70) /* CAN1 RX Interrupt */
+#define IRQ_CAN1_TX BFIN_IRQ(71) /* CAN1 TX Interrupt */
+#define IRQ_SDH_MASK0 BFIN_IRQ(72) /* SDH Mask 0 Interrupt */
+#define IRQ_SDH_MASK1 BFIN_IRQ(73) /* SDH Mask 1 Interrupt */
+#define IRQ_USB_INT0 BFIN_IRQ(75) /* USB INT0 Interrupt */
+#define IRQ_USB_INT1 BFIN_IRQ(76) /* USB INT1 Interrupt */
+#define IRQ_USB_INT2 BFIN_IRQ(77) /* USB INT2 Interrupt */
+#define IRQ_USB_DMA BFIN_IRQ(78) /* USB DMA Interrupt */
+#define IRQ_OPTSEC BFIN_IRQ(79) /* OTPSEC Interrupt */
+#define IRQ_TIMER0 BFIN_IRQ(86) /* Timer 0 Interrupt */
+#define IRQ_TIMER1 BFIN_IRQ(87) /* Timer 1 Interrupt */
+#define IRQ_TIMER2 BFIN_IRQ(88) /* Timer 2 Interrupt */
+#define IRQ_TIMER3 BFIN_IRQ(89) /* Timer 3 Interrupt */
+#define IRQ_TIMER4 BFIN_IRQ(90) /* Timer 4 Interrupt */
+#define IRQ_TIMER5 BFIN_IRQ(91) /* Timer 5 Interrupt */
+#define IRQ_TIMER6 BFIN_IRQ(92) /* Timer 6 Interrupt */
+#define IRQ_TIMER7 BFIN_IRQ(93) /* Timer 7 Interrupt */
+#define IRQ_PINT2 BFIN_IRQ(94) /* PINT2 Interrupt */
+#define IRQ_PINT3 BFIN_IRQ(95) /* PINT3 Interrupt */
+
+#define SYS_IRQS IRQ_PINT3
+
+#define BFIN_PA_IRQ(x) ((x) + SYS_IRQS + 1)
+#define IRQ_PA0 BFIN_PA_IRQ(0)
+#define IRQ_PA1 BFIN_PA_IRQ(1)
+#define IRQ_PA2 BFIN_PA_IRQ(2)
+#define IRQ_PA3 BFIN_PA_IRQ(3)
+#define IRQ_PA4 BFIN_PA_IRQ(4)
+#define IRQ_PA5 BFIN_PA_IRQ(5)
+#define IRQ_PA6 BFIN_PA_IRQ(6)
+#define IRQ_PA7 BFIN_PA_IRQ(7)
+#define IRQ_PA8 BFIN_PA_IRQ(8)
+#define IRQ_PA9 BFIN_PA_IRQ(9)
+#define IRQ_PA10 BFIN_PA_IRQ(10)
+#define IRQ_PA11 BFIN_PA_IRQ(11)
+#define IRQ_PA12 BFIN_PA_IRQ(12)
+#define IRQ_PA13 BFIN_PA_IRQ(13)
+#define IRQ_PA14 BFIN_PA_IRQ(14)
+#define IRQ_PA15 BFIN_PA_IRQ(15)
+
+#define BFIN_PB_IRQ(x) ((x) + IRQ_PA15 + 1)
+#define IRQ_PB0 BFIN_PB_IRQ(0)
+#define IRQ_PB1 BFIN_PB_IRQ(1)
+#define IRQ_PB2 BFIN_PB_IRQ(2)
+#define IRQ_PB3 BFIN_PB_IRQ(3)
+#define IRQ_PB4 BFIN_PB_IRQ(4)
+#define IRQ_PB5 BFIN_PB_IRQ(5)
+#define IRQ_PB6 BFIN_PB_IRQ(6)
+#define IRQ_PB7 BFIN_PB_IRQ(7)
+#define IRQ_PB8 BFIN_PB_IRQ(8)
+#define IRQ_PB9 BFIN_PB_IRQ(9)
+#define IRQ_PB10 BFIN_PB_IRQ(10)
+#define IRQ_PB11 BFIN_PB_IRQ(11)
+#define IRQ_PB12 BFIN_PB_IRQ(12)
+#define IRQ_PB13 BFIN_PB_IRQ(13)
+#define IRQ_PB14 BFIN_PB_IRQ(14)
+#define IRQ_PB15 BFIN_PB_IRQ(15) /* N/A */
+
+#define BFIN_PC_IRQ(x) ((x) + IRQ_PB15 + 1)
+#define IRQ_PC0 BFIN_PC_IRQ(0)
+#define IRQ_PC1 BFIN_PC_IRQ(1)
+#define IRQ_PC2 BFIN_PC_IRQ(2)
+#define IRQ_PC3 BFIN_PC_IRQ(3)
+#define IRQ_PC4 BFIN_PC_IRQ(4)
+#define IRQ_PC5 BFIN_PC_IRQ(5)
+#define IRQ_PC6 BFIN_PC_IRQ(6)
+#define IRQ_PC7 BFIN_PC_IRQ(7)
+#define IRQ_PC8 BFIN_PC_IRQ(8)
+#define IRQ_PC9 BFIN_PC_IRQ(9)
+#define IRQ_PC10 BFIN_PC_IRQ(10)
+#define IRQ_PC11 BFIN_PC_IRQ(11)
+#define IRQ_PC12 BFIN_PC_IRQ(12)
+#define IRQ_PC13 BFIN_PC_IRQ(13)
+#define IRQ_PC14 BFIN_PC_IRQ(14) /* N/A */
+#define IRQ_PC15 BFIN_PC_IRQ(15) /* N/A */
+
+#define BFIN_PD_IRQ(x) ((x) + IRQ_PC15 + 1)
+#define IRQ_PD0 BFIN_PD_IRQ(0)
+#define IRQ_PD1 BFIN_PD_IRQ(1)
+#define IRQ_PD2 BFIN_PD_IRQ(2)
+#define IRQ_PD3 BFIN_PD_IRQ(3)
+#define IRQ_PD4 BFIN_PD_IRQ(4)
+#define IRQ_PD5 BFIN_PD_IRQ(5)
+#define IRQ_PD6 BFIN_PD_IRQ(6)
+#define IRQ_PD7 BFIN_PD_IRQ(7)
+#define IRQ_PD8 BFIN_PD_IRQ(8)
+#define IRQ_PD9 BFIN_PD_IRQ(9)
+#define IRQ_PD10 BFIN_PD_IRQ(10)
+#define IRQ_PD11 BFIN_PD_IRQ(11)
+#define IRQ_PD12 BFIN_PD_IRQ(12)
+#define IRQ_PD13 BFIN_PD_IRQ(13)
+#define IRQ_PD14 BFIN_PD_IRQ(14)
+#define IRQ_PD15 BFIN_PD_IRQ(15)
+
+#define BFIN_PE_IRQ(x) ((x) + IRQ_PD15 + 1)
+#define IRQ_PE0 BFIN_PE_IRQ(0)
+#define IRQ_PE1 BFIN_PE_IRQ(1)
+#define IRQ_PE2 BFIN_PE_IRQ(2)
+#define IRQ_PE3 BFIN_PE_IRQ(3)
+#define IRQ_PE4 BFIN_PE_IRQ(4)
+#define IRQ_PE5 BFIN_PE_IRQ(5)
+#define IRQ_PE6 BFIN_PE_IRQ(6)
+#define IRQ_PE7 BFIN_PE_IRQ(7)
+#define IRQ_PE8 BFIN_PE_IRQ(8)
+#define IRQ_PE9 BFIN_PE_IRQ(9)
+#define IRQ_PE10 BFIN_PE_IRQ(10)
+#define IRQ_PE11 BFIN_PE_IRQ(11)
+#define IRQ_PE12 BFIN_PE_IRQ(12)
+#define IRQ_PE13 BFIN_PE_IRQ(13)
+#define IRQ_PE14 BFIN_PE_IRQ(14)
+#define IRQ_PE15 BFIN_PE_IRQ(15)
+
+#define BFIN_PF_IRQ(x) ((x) + IRQ_PE15 + 1)
+#define IRQ_PF0 BFIN_PF_IRQ(0)
+#define IRQ_PF1 BFIN_PF_IRQ(1)
+#define IRQ_PF2 BFIN_PF_IRQ(2)
+#define IRQ_PF3 BFIN_PF_IRQ(3)
+#define IRQ_PF4 BFIN_PF_IRQ(4)
+#define IRQ_PF5 BFIN_PF_IRQ(5)
+#define IRQ_PF6 BFIN_PF_IRQ(6)
+#define IRQ_PF7 BFIN_PF_IRQ(7)
+#define IRQ_PF8 BFIN_PF_IRQ(8)
+#define IRQ_PF9 BFIN_PF_IRQ(9)
+#define IRQ_PF10 BFIN_PF_IRQ(10)
+#define IRQ_PF11 BFIN_PF_IRQ(11)
+#define IRQ_PF12 BFIN_PF_IRQ(12)
+#define IRQ_PF13 BFIN_PF_IRQ(13)
+#define IRQ_PF14 BFIN_PF_IRQ(14)
+#define IRQ_PF15 BFIN_PF_IRQ(15)
+
+#define BFIN_PG_IRQ(x) ((x) + IRQ_PF15 + 1)
+#define IRQ_PG0 BFIN_PG_IRQ(0)
+#define IRQ_PG1 BFIN_PG_IRQ(1)
+#define IRQ_PG2 BFIN_PG_IRQ(2)
+#define IRQ_PG3 BFIN_PG_IRQ(3)
+#define IRQ_PG4 BFIN_PG_IRQ(4)
+#define IRQ_PG5 BFIN_PG_IRQ(5)
+#define IRQ_PG6 BFIN_PG_IRQ(6)
+#define IRQ_PG7 BFIN_PG_IRQ(7)
+#define IRQ_PG8 BFIN_PG_IRQ(8)
+#define IRQ_PG9 BFIN_PG_IRQ(9)
+#define IRQ_PG10 BFIN_PG_IRQ(10)
+#define IRQ_PG11 BFIN_PG_IRQ(11)
+#define IRQ_PG12 BFIN_PG_IRQ(12)
+#define IRQ_PG13 BFIN_PG_IRQ(13)
+#define IRQ_PG14 BFIN_PG_IRQ(14)
+#define IRQ_PG15 BFIN_PG_IRQ(15)
+
+#define BFIN_PH_IRQ(x) ((x) + IRQ_PG15 + 1)
+#define IRQ_PH0 BFIN_PH_IRQ(0)
+#define IRQ_PH1 BFIN_PH_IRQ(1)
+#define IRQ_PH2 BFIN_PH_IRQ(2)
+#define IRQ_PH3 BFIN_PH_IRQ(3)
+#define IRQ_PH4 BFIN_PH_IRQ(4)
+#define IRQ_PH5 BFIN_PH_IRQ(5)
+#define IRQ_PH6 BFIN_PH_IRQ(6)
+#define IRQ_PH7 BFIN_PH_IRQ(7)
+#define IRQ_PH8 BFIN_PH_IRQ(8)
+#define IRQ_PH9 BFIN_PH_IRQ(9)
+#define IRQ_PH10 BFIN_PH_IRQ(10)
+#define IRQ_PH11 BFIN_PH_IRQ(11)
+#define IRQ_PH12 BFIN_PH_IRQ(12)
+#define IRQ_PH13 BFIN_PH_IRQ(13)
+#define IRQ_PH14 BFIN_PH_IRQ(14) /* N/A */
+#define IRQ_PH15 BFIN_PH_IRQ(15) /* N/A */
+
+#define BFIN_PI_IRQ(x) ((x) + IRQ_PH15 + 1)
+#define IRQ_PI0 BFIN_PI_IRQ(0)
+#define IRQ_PI1 BFIN_PI_IRQ(1)
+#define IRQ_PI2 BFIN_PI_IRQ(2)
+#define IRQ_PI3 BFIN_PI_IRQ(3)
+#define IRQ_PI4 BFIN_PI_IRQ(4)
+#define IRQ_PI5 BFIN_PI_IRQ(5)
+#define IRQ_PI6 BFIN_PI_IRQ(6)
+#define IRQ_PI7 BFIN_PI_IRQ(7)
+#define IRQ_PI8 BFIN_PI_IRQ(8)
+#define IRQ_PI9 BFIN_PI_IRQ(9)
+#define IRQ_PI10 BFIN_PI_IRQ(10)
+#define IRQ_PI11 BFIN_PI_IRQ(11)
+#define IRQ_PI12 BFIN_PI_IRQ(12)
+#define IRQ_PI13 BFIN_PI_IRQ(13)
+#define IRQ_PI14 BFIN_PI_IRQ(14)
+#define IRQ_PI15 BFIN_PI_IRQ(15)
+
+#define BFIN_PJ_IRQ(x) ((x) + IRQ_PI15 + 1)
+#define IRQ_PJ0 BFIN_PJ_IRQ(0)
+#define IRQ_PJ1 BFIN_PJ_IRQ(1)
+#define IRQ_PJ2 BFIN_PJ_IRQ(2)
+#define IRQ_PJ3 BFIN_PJ_IRQ(3)
+#define IRQ_PJ4 BFIN_PJ_IRQ(4)
+#define IRQ_PJ5 BFIN_PJ_IRQ(5)
+#define IRQ_PJ6 BFIN_PJ_IRQ(6)
+#define IRQ_PJ7 BFIN_PJ_IRQ(7)
+#define IRQ_PJ8 BFIN_PJ_IRQ(8)
+#define IRQ_PJ9 BFIN_PJ_IRQ(9)
+#define IRQ_PJ10 BFIN_PJ_IRQ(10)
+#define IRQ_PJ11 BFIN_PJ_IRQ(11)
+#define IRQ_PJ12 BFIN_PJ_IRQ(12)
+#define IRQ_PJ13 BFIN_PJ_IRQ(13)
+#define IRQ_PJ14 BFIN_PJ_IRQ(14) /* N/A */
+#define IRQ_PJ15 BFIN_PJ_IRQ(15) /* N/A */
+
+#ifdef CONFIG_IRQCHIP_DEMUX_GPIO
+#define NR_IRQS (IRQ_PJ15+1)
+#else
+#define NR_IRQS (SYS_IRQS+1)
+#endif
+
+#define IVG7 7
+#define IVG8 8
+#define IVG9 9
+#define IVG10 10
+#define IVG11 11
+#define IVG12 12
+#define IVG13 13
+#define IVG14 14
+#define IVG15 15
+
+/* IAR0 BIT FIELDS */
+#define IRQ_PLL_WAKEUP_POS 0
+#define IRQ_DMAC0_ERR_POS 4
+#define IRQ_EPPI0_ERR_POS 8
+#define IRQ_SPORT0_ERR_POS 12
+#define IRQ_SPORT1_ERR_POS 16
+#define IRQ_SPI0_ERR_POS 20
+#define IRQ_UART0_ERR_POS 24
+#define IRQ_RTC_POS 28
+
+/* IAR1 BIT FIELDS */
+#define IRQ_EPPI0_POS 0
+#define IRQ_SPORT0_RX_POS 4
+#define IRQ_SPORT0_TX_POS 8
+#define IRQ_SPORT1_RX_POS 12
+#define IRQ_SPORT1_TX_POS 16
+#define IRQ_SPI0_POS 20
+#define IRQ_UART0_RX_POS 24
+#define IRQ_UART0_TX_POS 28
+
+/* IAR2 BIT FIELDS */
+#define IRQ_TIMER8_POS 0
+#define IRQ_TIMER9_POS 4
+#define IRQ_TIMER10_POS 8
+#define IRQ_PINT0_POS 12
+#define IRQ_PINT1_POS 16
+#define IRQ_MDMAS0_POS 20
+#define IRQ_MDMAS1_POS 24
+#define IRQ_WATCHDOG_POS 28
+
+/* IAR3 BIT FIELDS */
+#define IRQ_DMAC1_ERR_POS 0
+#define IRQ_SPORT2_ERR_POS 4
+#define IRQ_SPORT3_ERR_POS 8
+#define IRQ_MXVR_DATA_POS 12
+#define IRQ_SPI1_ERR_POS 16
+#define IRQ_SPI2_ERR_POS 20
+#define IRQ_UART1_ERR_POS 24
+#define IRQ_UART2_ERR_POS 28
+
+/* IAR4 BIT FILEDS */
+#define IRQ_CAN0_ERR_POS 0
+#define IRQ_SPORT2_RX_POS 4
+#define IRQ_SPORT2_TX_POS 8
+#define IRQ_SPORT3_RX_POS 12
+#define IRQ_SPORT3_TX_POS 16
+#define IRQ_EPPI1_POS 20
+#define IRQ_EPPI2_POS 24
+#define IRQ_SPI1_POS 28
+
+/* IAR5 BIT FIELDS */
+#define IRQ_SPI2_POS 0
+#define IRQ_UART1_RX_POS 4
+#define IRQ_UART1_TX_POS 8
+#define IRQ_ATAPI_RX_POS 12
+#define IRQ_ATAPI_TX_POS 16
+#define IRQ_TWI0_POS 20
+#define IRQ_TWI1_POS 24
+#define IRQ_CAN0_RX_POS 28
+
+/* IAR6 BIT FIELDS */
+#define IRQ_CAN0_TX_POS 0
+#define IRQ_MDMAS2_POS 4
+#define IRQ_MDMAS3_POS 8
+#define IRQ_MXVR_ERR_POS 12
+#define IRQ_MXVR_MSG_POS 16
+#define IRQ_MXVR_PKT_POS 20
+#define IRQ_EPPI1_ERR_POS 24
+#define IRQ_EPPI2_ERR_POS 28
+
+/* IAR7 BIT FIELDS */
+#define IRQ_UART3_ERR_POS 0
+#define IRQ_HOST_ERR_POS 4
+#define IRQ_PIXC_ERR_POS 12
+#define IRQ_NFC_ERR_POS 16
+#define IRQ_ATAPI_ERR_POS 20
+#define IRQ_CAN1_ERR_POS 24
+#define IRQ_HS_DMA_ERR_POS 28
+
+/* IAR8 BIT FIELDS */
+#define IRQ_PIXC_IN0_POS 0
+#define IRQ_PIXC_IN1_POS 4
+#define IRQ_PIXC_OUT_POS 8
+#define IRQ_SDH_POS 12
+#define IRQ_CNT_POS 16
+#define IRQ_KEY_POS 20
+#define IRQ_CAN1_RX_POS 24
+#define IRQ_CAN1_TX_POS 28
+
+/* IAR9 BIT FIELDS */
+#define IRQ_SDH_MASK0_POS 0
+#define IRQ_SDH_MASK1_POS 4
+#define IRQ_USB_INT0_POS 12
+#define IRQ_USB_INT1_POS 16
+#define IRQ_USB_INT2_POS 20
+#define IRQ_USB_DMA_POS 24
+#define IRQ_OTPSEC_POS 28
+
+/* IAR10 BIT FIELDS */
+#define IRQ_TIMER0_POS 24
+#define IRQ_TIMER1_POS 28
+
+/* IAR11 BIT FIELDS */
+#define IRQ_TIMER2_POS 0
+#define IRQ_TIMER3_POS 4
+#define IRQ_TIMER4_POS 8
+#define IRQ_TIMER5_POS 12
+#define IRQ_TIMER6_POS 16
+#define IRQ_TIMER7_POS 20
+#define IRQ_PINT2_POS 24
+#define IRQ_PINT3_POS 28
+
+#endif /* _BF548_IRQ_H_ */
diff --git a/include/asm-blackfin/mach-bf548/mem_init.h b/include/asm-blackfin/mach-bf548/mem_init.h
new file mode 100644
index 000000000000..0cb279e973d7
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/mem_init.h
@@ -0,0 +1,189 @@
+/*
+ * File: include/asm-blackfin/mach-bf548/mem_init.h
+ * Based on:
+ * Author:
+ *
+ * Created:
+ * Description:
+ *
+ * Rev:
+ *
+ * Modified:
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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; see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#if (CONFIG_MEM_MT46V32M16)
+
+#if defined CONFIG_CLKIN_HALF
+#define CLKIN_HALF 1
+#else
+#define CLKIN_HALF 0
+#endif
+
+#if defined CONFIG_PLL_BYPASS
+#define PLL_BYPASS 1
+#else
+#define PLL_BYPASS 0
+#endif
+
+/***************************************Currently Not Being Used *********************************/
+#define flash_EBIU_AMBCTL_WAT ((CONFIG_FLASH_SPEED_BWAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_RAT ((CONFIG_FLASH_SPEED_BRAT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_HT ((CONFIG_FLASH_SPEED_BHT * 4) / (4000000000 / CONFIG_SCLK_HZ))
+#define flash_EBIU_AMBCTL_ST ((CONFIG_FLASH_SPEED_BST * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+#define flash_EBIU_AMBCTL_TT ((CONFIG_FLASH_SPEED_BTT * 4) / (4000000000 / CONFIG_SCLK_HZ)) + 1
+
+#if (flash_EBIU_AMBCTL_TT > 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_4
+#endif
+#if (flash_EBIU_AMBCTL_TT == 3)
+#define flash_EBIU_AMBCTL0_TT B0TT_3
+#endif
+#if (flash_EBIU_AMBCTL_TT == 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_2
+#endif
+#if (flash_EBIU_AMBCTL_TT < 2)
+#define flash_EBIU_AMBCTL0_TT B0TT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_ST > 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_4
+#endif
+#if (flash_EBIU_AMBCTL_ST == 3)
+#define flash_EBIU_AMBCTL0_ST B0ST_3
+#endif
+#if (flash_EBIU_AMBCTL_ST == 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_2
+#endif
+#if (flash_EBIU_AMBCTL_ST < 2)
+#define flash_EBIU_AMBCTL0_ST B0ST_1
+#endif
+
+#if (flash_EBIU_AMBCTL_HT > 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_3
+#endif
+#if (flash_EBIU_AMBCTL_HT == 2)
+#define flash_EBIU_AMBCTL0_HT B0HT_2
+#endif
+#if (flash_EBIU_AMBCTL_HT == 1)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT == 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_0
+#endif
+#if (flash_EBIU_AMBCTL_HT == 0 && CONFIG_FLASH_SPEED_BHT != 0)
+#define flash_EBIU_AMBCTL0_HT B0HT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_WAT > 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_15
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 14)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_14
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 13)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_13
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 12)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_12
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 11)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_11
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 10)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_10
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 9)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_9
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 8)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_8
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 7)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_7
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 6)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_6
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 5)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_5
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 4)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_4
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 3)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_3
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 2)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_2
+#endif
+#if (flash_EBIU_AMBCTL_WAT == 1)
+#define flash_EBIU_AMBCTL0_WAT B0WAT_1
+#endif
+
+#if (flash_EBIU_AMBCTL_RAT > 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_15
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 14)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_14
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 13)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_13
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 12)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_12
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 11)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_11
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 10)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_10
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 9)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_9
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 8)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_8
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 7)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_7
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 6)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_6
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 5)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_5
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 4)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_4
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 3)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_3
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 2)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_2
+#endif
+#if (flash_EBIU_AMBCTL_RAT == 1)
+#define flash_EBIU_AMBCTL0_RAT B0RAT_1
+#endif
+
+#define flash_EBIU_AMBCTL0 \
+ (flash_EBIU_AMBCTL0_WAT | flash_EBIU_AMBCTL0_RAT | flash_EBIU_AMBCTL0_HT | \
+ flash_EBIU_AMBCTL0_ST | flash_EBIU_AMBCTL0_TT | CONFIG_FLASH_SPEED_RDYEN)
diff --git a/include/asm-blackfin/mach-bf548/mem_map.h b/include/asm-blackfin/mach-bf548/mem_map.h
new file mode 100644
index 000000000000..72d80e8a6e81
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/mem_map.h
@@ -0,0 +1,97 @@
+/*
+ * file: include/asm-blackfin/mach-bf548/mem_map.h
+ * based on:
+ * author:
+ *
+ * created:
+ * description:
+ * Memory MAP Common header file for blackfin BF537/6/4 of processors.
+ * rev:
+ *
+ * modified:
+ *
+ * bugs: enter bugs at http://blackfin.uclinux.org/
+ *
+ * this program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license as published by
+ * the free software foundation; either version 2, 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; see the file copying.
+ * if not, write to the free software foundation,
+ * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ */
+
+#ifndef _MEM_MAP_548_H_
+#define _MEM_MAP_548_H_
+
+#define COREMMR_BASE 0xFFE00000 /* Core MMRs */
+#define SYSMMR_BASE 0xFFC00000 /* System MMRs */
+
+/* Async Memory Banks */
+#define ASYNC_BANK3_BASE 0x2C000000 /* Async Bank 3 */
+#define ASYNC_BANK3_SIZE 0x04000000 /* 64M */
+#define ASYNC_BANK2_BASE 0x28000000 /* Async Bank 2 */
+#define ASYNC_BANK2_SIZE 0x04000000 /* 64M */
+#define ASYNC_BANK1_BASE 0x24000000 /* Async Bank 1 */
+#define ASYNC_BANK1_SIZE 0x04000000 /* 64M */
+#define ASYNC_BANK0_BASE 0x20000000 /* Async Bank 0 */
+#define ASYNC_BANK0_SIZE 0x04000000 /* 64M */
+
+/* Boot ROM Memory */
+
+#define BOOT_ROM_START 0xEF000000
+
+/* Level 1 Memory */
+
+/* Memory Map for ADSP-BF548 processors */
+#ifdef CONFIG_BLKFIN_ICACHE
+#define BLKFIN_ICACHESIZE (16*1024)
+#else
+#define BLKFIN_ICACHESIZE (0*1024)
+#endif
+
+#define L1_CODE_START 0xFFA00000
+#define L1_DATA_A_START 0xFF800000
+#define L1_DATA_B_START 0xFF900000
+
+#define L1_CODE_LENGTH 0xC000
+
+#ifdef CONFIG_BLKFIN_DCACHE
+
+#ifdef CONFIG_BLKFIN_DCACHE_BANKA
+#define DMEM_CNTR (ACACHE_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (16*1024)
+#define BLKFIN_DSUPBANKS 1
+#else
+#define DMEM_CNTR (ACACHE_BCACHE | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH (0x8000 - 0x4000)
+#define L1_DATA_B_LENGTH (0x8000 - 0x4000)
+#define BLKFIN_DCACHESIZE (32*1024)
+#define BLKFIN_DSUPBANKS 2
+#endif
+
+#else
+#define DMEM_CNTR (ASRAM_BSRAM | ENDCPLB | PORT_PREF0)
+#define L1_DATA_A_LENGTH 0x8000
+#define L1_DATA_B_LENGTH 0x8000
+#define BLKFIN_DCACHESIZE (0*1024)
+#define BLKFIN_DSUPBANKS 0
+#endif /*CONFIG_BLKFIN_DCACHE*/
+
+/* Scratch Pad Memory */
+
+#if defined(CONFIG_BF54x)
+#define L1_SCRATCH_START 0xFFB00000
+#define L1_SCRATCH_LENGTH 0x1000
+#endif
+
+#endif/* _MEM_MAP_548_H_ */
diff --git a/include/asm-blackfin/mach-bf548/portmux.h b/include/asm-blackfin/mach-bf548/portmux.h
new file mode 100644
index 000000000000..b382deb501a7
--- /dev/null
+++ b/include/asm-blackfin/mach-bf548/portmux.h
@@ -0,0 +1,270 @@
+#ifndef _MACH_PORTMUX_H_
+#define _MACH_PORTMUX_H_
+
+#define P_SPORT2_TFS (P_DEFINED | P_IDENT(GPIO_PA0) | P_FUNCT(0))
+#define P_SPORT2_DTSEC (P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(0))
+#define P_SPORT2_DTPRI (P_DEFINED | P_IDENT(GPIO_PA2) | P_FUNCT(0))
+#define P_SPORT2_TSCLK (P_DEFINED | P_IDENT(GPIO_PA3) | P_FUNCT(0))
+#define P_SPORT2_RFS (P_DEFINED | P_IDENT(GPIO_PA4) | P_FUNCT(0))
+#define P_SPORT2_DRSEC (P_DEFINED | P_IDENT(GPIO_PA5) | P_FUNCT(0))
+#define P_SPORT2_DRPRI (P_DEFINED | P_IDENT(GPIO_PA6) | P_FUNCT(0))
+#define P_SPORT2_RSCLK (P_DEFINED | P_IDENT(GPIO_PA7) | P_FUNCT(0))
+#define P_SPORT3_TFS (P_DEFINED | P_IDENT(GPIO_PA8) | P_FUNCT(0))
+#define P_SPORT3_DTSEC (P_DEFINED | P_IDENT(GPIO_PA9) | P_FUNCT(0))
+#define P_SPORT3_DTPRI (P_DEFINED | P_IDENT(GPIO_PA10) | P_FUNCT(0))
+#define P_SPORT3_TSCLK (P_DEFINED | P_IDENT(GPIO_PA11) | P_FUNCT(0))
+#define P_SPORT3_RFS (P_DEFINED | P_IDENT(GPIO_PA12) | P_FUNCT(0))
+#define P_SPORT3_DRSEC (P_DEFINED | P_IDENT(GPIO_PA13) | P_FUNCT(0))
+#define P_SPORT3_DRPRI (P_DEFINED | P_IDENT(GPIO_PA14) | P_FUNCT(0))
+#define P_SPORT3_RSCLK (P_DEFINED | P_IDENT(GPIO_PA15) | P_FUNCT(0))
+#define P_TMR4 (P_DEFINED | P_IDENT(GPIO_PA1) | P_FUNCT(1))
+#define P_TMR5 (P_DEFINED | P_IDENT(GPIO_PA5) | P_FUNCT(1))
+#define P_TMR6 (P_DEFINED | P_IDENT(GPIO_PA9) | P_FUNCT(1))
+#define P_TMR7 (P_DEFINED | P_IDENT(GPIO_PA13) | P_FUNCT(1))
+
+#define P_TWI1_SCL (P_DEFINED | P_IDENT(GPIO_PB0) | P_FUNCT(0))
+#define P_TWI1_SDA (P_DEFINED | P_IDENT(GPIO_PB1) | P_FUNCT(0))
+#define P_UART3_RTS (P_DEFINED | P_IDENT(GPIO_PB2) | P_FUNCT(0))
+#define P_UART3_CTS (P_DEFINED | P_IDENT(GPIO_PB3) | P_FUNCT(0))
+#define P_UART2_TX (P_DEFINED | P_IDENT(GPIO_PB4) | P_FUNCT(0))
+#define P_UART2_RX (P_DEFINED | P_IDENT(GPIO_PB5) | P_FUNCT(0))
+#define P_UART3_TX (P_DEFINED | P_IDENT(GPIO_PB6) | P_FUNCT(0))
+#define P_UART3_RX (P_DEFINED | P_IDENT(GPIO_PB7) | P_FUNCT(0))
+#define P_SPI2_SS (P_DEFINED | P_IDENT(GPIO_PB8) | P_FUNCT(0))
+#define P_SPI2_SSEL1 (P_DEFINED | P_IDENT(GPIO_PB9) | P_FUNCT(0))
+#define P_SPI2_SSEL2 (P_DEFINED | P_IDENT(GPIO_PB10) | P_FUNCT(0))
+#define P_SPI2_SSEL3 (P_DEFINED | P_IDENT(GPIO_PB11) | P_FUNCT(0))
+#define P_SPI2_SCK (P_DEFINED | P_IDENT(GPIO_PB12) | P_FUNCT(0))
+#define P_SPI2_MOSI (P_DEFINED | P_IDENT(GPIO_PB13) | P_FUNCT(0))
+#define P_SPI2_MISO (P_DEFINED | P_IDENT(GPIO_PB14) | P_FUNCT(0))
+#define P_TMR0 (P_DEFINED | P_IDENT(GPIO_PB8) | P_FUNCT(1))
+#define P_TMR1 (P_DEFINED | P_IDENT(GPIO_PB9) | P_FUNCT(1))
+#define P_TMR2 (P_DEFINED | P_IDENT(GPIO_PB10) | P_FUNCT(1))
+#define P_TMR3 (P_DEFINED | P_IDENT(GPIO_PB11) | P_FUNCT(1))
+
+#define P_SPORT0_TFS (P_DEFINED | P_IDENT(GPIO_PC0) | P_FUNCT(0))
+#define P_SPORT0_DTSEC (P_DEFINED | P_IDENT(GPIO_PC1) | P_FUNCT(0))
+#define P_SPORT0_DTPRI (P_DEFINED | P_IDENT(GPIO_PC2) | P_FUNCT(0))
+#define P_SPORT0_TSCLK (P_DEFINED | P_IDENT(GPIO_PC3) | P_FUNCT(0))
+#define P_SPORT0_RFS (P_DEFINED | P_IDENT(GPIO_PC4) | P_FUNCT(0))
+#define P_SPORT0_DRSEC (P_DEFINED | P_IDENT(GPIO_PC5) | P_FUNCT(0))
+#define P_SPORT0_DRPRI (P_DEFINED | P_IDENT(GPIO_PC6) | P_FUNCT(0))
+#define P_SPORT0_RSCLK (P_DEFINED | P_IDENT(GPIO_PC7) | P_FUNCT(0))
+#define P_SD_D0 (P_DEFINED | P_IDENT(GPIO_PC8) | P_FUNCT(0))
+#define P_SD_D1 (P_DEFINED | P_IDENT(GPIO_PC9) | P_FUNCT(0))
+#define P_SD_D2 (P_DEFINED | P_IDENT(GPIO_PC10) | P_FUNCT(0))
+#define P_SD_D3 (P_DEFINED | P_IDENT(GPIO_PC11) | P_FUNCT(0))
+#define P_SD_CLK (P_DEFINED | P_IDENT(GPIO_PC12) | P_FUNCT(0))
+#define P_SD_CMD (P_DEFINED | P_IDENT(GPIO_PC13) | P_FUNCT(0))
+#define P_MMCLK (P_DEFINED | P_IDENT(GPIO_PC1) | P_FUNCT(1))
+#define P_MBCLK (P_DEFINED | P_IDENT(GPIO_PC5) | P_FUNCT(1))
+
+#define P_PPI1_D0 (P_DEFINED | P_IDENT(GPIO_PD0) | P_FUNCT(0))
+#define P_PPI1_D1 (P_DEFINED | P_IDENT(GPIO_PD1) | P_FUNCT(0))
+#define P_PPI1_D2 (P_DEFINED | P_IDENT(GPIO_PD2) | P_FUNCT(0))
+#define P_PPI1_D3 (P_DEFINED | P_IDENT(GPIO_PD3) | P_FUNCT(0))
+#define P_PPI1_D4 (P_DEFINED | P_IDENT(GPIO_PD4) | P_FUNCT(0))
+#define P_PPI1_D5 (P_DEFINED | P_IDENT(GPIO_PD5) | P_FUNCT(0))
+#define P_PPI1_D6 (P_DEFINED | P_IDENT(GPIO_PD6) | P_FUNCT(0))
+#define P_PPI1_D7 (P_DEFINED | P_IDENT(GPIO_PD7) | P_FUNCT(0))
+#define P_PPI1_D8 (P_DEFINED | P_IDENT(GPIO_PD8) | P_FUNCT(0))
+#define P_PPI1_D9 (P_DEFINED | P_IDENT(GPIO_PD9) | P_FUNCT(0))
+#define P_PPI1_D10 (P_DEFINED | P_IDENT(GPIO_PD10) | P_FUNCT(0))
+#define P_PPI1_D11 (P_DEFINED | P_IDENT(GPIO_PD11) | P_FUNCT(0))
+#define P_PPI1_D12 (P_DEFINED | P_IDENT(GPIO_PD12) | P_FUNCT(0))
+#define P_PPI1_D13 (P_DEFINED | P_IDENT(GPIO_PD13) | P_FUNCT(0))
+#define P_PPI1_D14 (P_DEFINED | P_IDENT(GPIO_PD14) | P_FUNCT(0))
+#define P_PPI1_D15 (P_DEFINED | P_IDENT(GPIO_PD15) | P_FUNCT(0))
+
+#define P_HOST_D8 (P_DEFINED | P_IDENT(GPIO_PD0) | P_FUNCT(1))
+#define P_HOST_D9 (P_DEFINED | P_IDENT(GPIO_PD1) | P_FUNCT(1))
+#define P_HOST_D10 (P_DEFINED | P_IDENT(GPIO_PD2) | P_FUNCT(1))
+#define P_HOST_D11 (P_DEFINED | P_IDENT(GPIO_PD3) | P_FUNCT(1))
+#define P_HOST_D12 (P_DEFINED | P_IDENT(GPIO_PD4) | P_FUNCT(1))
+#define P_HOST_D13 (P_DEFINED | P_IDENT(GPIO_PD5) | P_FUNCT(1))
+#define P_HOST_D14 (P_DEFINED | P_IDENT(GPIO_PD6) | P_FUNCT(1))
+#define P_HOST_D15 (P_DEFINED | P_IDENT(GPIO_PD7) | P_FUNCT(1))
+#define P_HOST_D0 (P_DEFINED | P_IDENT(GPIO_PD8) | P_FUNCT(1))
+#define P_HOST_D1 (P_DEFINED | P_IDENT(GPIO_PD9) | P_FUNCT(1))
+#define P_HOST_D2 (P_DEFINED | P_IDENT(GPIO_PD10) | P_FUNCT(1))
+#define P_HOST_D3 (P_DEFINED | P_IDENT(GPIO_PD11) | P_FUNCT(1))
+#define P_HOST_D4 (P_DEFINED | P_IDENT(GPIO_PD12) | P_FUNCT(1))
+#define P_HOST_D5 (P_DEFINED | P_IDENT(GPIO_PD13) | P_FUNCT(1))
+#define P_HOST_D6 (P_DEFINED | P_IDENT(GPIO_PD14) | P_FUNCT(1))
+#define P_HOST_D7 (P_DEFINED | P_IDENT(GPIO_PD15) | P_FUNCT(1))
+#define P_SPORT1_TFS (P_DEFINED | P_IDENT(GPIO_PD0) | P_FUNCT(2))
+#define P_SPORT1_DTSEC (P_DEFINED | P_IDENT(GPIO_PD1) | P_FUNCT(2))
+#define P_SPORT1_DTPRI (P_DEFINED | P_IDENT(GPIO_PD2) | P_FUNCT(2))
+#define P_SPORT1_TSCLK (P_DEFINED | P_IDENT(GPIO_PD3) | P_FUNCT(2))
+#define P_SPORT1_RFS (P_DEFINED | P_IDENT(GPIO_PD4) | P_FUNCT(2))
+#define P_SPORT1_DRSEC (P_DEFINED | P_IDENT(GPIO_PD5) | P_FUNCT(2))
+#define P_SPORT1_DRPRI (P_DEFINED | P_IDENT(GPIO_PD6) | P_FUNCT(2))
+#define P_SPORT1_RSCLK (P_DEFINED | P_IDENT(GPIO_PD7) | P_FUNCT(2))
+#define P_PPI2_D0 (P_DEFINED | P_IDENT(GPIO_PD8) | P_FUNCT(2))
+#define P_PPI2_D1 (P_DEFINED | P_IDENT(GPIO_PD9) | P_FUNCT(2))
+#define P_PPI2_D2 (P_DEFINED | P_IDENT(GPIO_PD10) | P_FUNCT(2))
+#define P_PPI2_D3 (P_DEFINED | P_IDENT(GPIO_PD11) | P_FUNCT(2))
+#define P_PPI2_D4 (P_DEFINED | P_IDENT(GPIO_PD12) | P_FUNCT(2))
+#define P_PPI2_D5 (P_DEFINED | P_IDENT(GPIO_PD13) | P_FUNCT(2))
+#define P_PPI2_D6 (P_DEFINED | P_IDENT(GPIO_PD14) | P_FUNCT(2))
+#define P_PPI2_D7 (P_DEFINED | P_IDENT(GPIO_PD15) | P_FUNCT(2))
+#define P_PPI0_D18 (P_DEFINED | P_IDENT(GPIO_PD0) | P_FUNCT(3))
+#define P_PPI0_D19 (P_DEFINED | P_IDENT(GPIO_PD1) | P_FUNCT(3))
+#define P_PPI0_D20 (P_DEFINED | P_IDENT(GPIO_PD2) | P_FUNCT(3))
+#define P_PPI0_D21 (P_DEFINED | P_IDENT(GPIO_PD3) | P_FUNCT(3))
+#define P_PPI0_D22 (P_DEFINED | P_IDENT(GPIO_PD4) | P_FUNCT(3))
+#define P_PPI0_D23 (P_DEFINED | P_IDENT(GPIO_PD5) | P_FUNCT(3))
+#define P_KEY_ROW0 (P_DEFINED | P_IDENT(GPIO_PD8) | P_FUNCT(3))
+#define P_KEY_ROW1 (P_DEFINED | P_IDENT(GPIO_PD9) | P_FUNCT(3))
+#define P_KEY_ROW2 (P_DEFINED | P_IDENT(GPIO_PD10) | P_FUNCT(3))
+#define P_KEY_ROW3 (P_DEFINED | P_IDENT(GPIO_PD11) | P_FUNCT(3))
+#define P_KEY_COL0 (P_DEFINED | P_IDENT(GPIO_PD12) | P_FUNCT(3))
+#define P_KEY_COL1 (P_DEFINED | P_IDENT(GPIO_PD13) | P_FUNCT(3))
+#define P_KEY_COL2 (P_DEFINED | P_IDENT(GPIO_PD14) | P_FUNCT(3))
+#define P_KEY_COL3 (P_DEFINED | P_IDENT(GPIO_PD15) | P_FUNCT(3))
+
+#define P_SPI0_SCK (P_DEFINED | P_IDENT(GPIO_PE0) | P_FUNCT(0))
+#define P_SPI0_MISO (P_DEFINED | P_IDENT(GPIO_PE1) | P_FUNCT(0))
+#define P_SPI0_MOSI (P_DEFINED | P_IDENT(GPIO_PE2) | P_FUNCT(0))
+#define P_SPI0_SS (P_DEFINED | P_IDENT(GPIO_PE3) | P_FUNCT(0))
+#define P_SPI0_SSEL1 (P_DEFINED | P_IDENT(GPIO_PE4) | P_FUNCT(0))
+#define P_SPI0_SSEL2 (P_DEFINED | P_IDENT(GPIO_PE5) | P_FUNCT(0))
+#define P_SPI0_SSEL3 (P_DEFINED | P_IDENT(GPIO_PE6) | P_FUNCT(0))
+#define P_UART0_TX (P_DEFINED | P_IDENT(GPIO_PE7) | P_FUNCT(0))
+#define P_UART0_RX (P_DEFINED | P_IDENT(GPIO_PE8) | P_FUNCT(0))
+#define P_UART1_RTS (P_DEFINED | P_IDENT(GPIO_PE9) | P_FUNCT(0))
+#define P_UART1_CTS (P_DEFINED | P_IDENT(GPIO_PE10) | P_FUNCT(0))
+#define P_PPI1_CLK (P_DEFINED | P_IDENT(GPIO_PE11) | P_FUNCT(0))
+#define P_PPI1_FS1 (P_DEFINED | P_IDENT(GPIO_PE12) | P_FUNCT(0))
+#define P_PPI1_FS2 (P_DEFINED | P_IDENT(GPIO_PE13) | P_FUNCT(0))
+#define P_TWI0_SCL (P_DEFINED | P_IDENT(GPIO_PE14) | P_FUNCT(0))
+#define P_TWI0_SDA (P_DEFINED | P_IDENT(GPIO_PE15) | P_FUNCT(0))
+#define P_KEY_COL7 (P_DEFINED | P_IDENT(GPIO_PE0) | P_FUNCT(1))
+#define P_KEY_ROW6 (P_DEFINED | P_IDENT(GPIO_PE1) | P_FUNCT(1))
+#define P_KEY_COL6 (P_DEFINED | P_IDENT(GPIO_PE2) | P_FUNCT(1))
+#define P_KEY_ROW5 (P_DEFINED | P_IDENT(GPIO_PE3) | P_FUNCT(1))
+#define P_KEY_COL5 (P_DEFINED | P_IDENT(GPIO_PE4) | P_FUNCT(1))
+#define P_KEY_ROW4 (P_DEFINED | P_IDENT(GPIO_PE5) | P_FUNCT(1))
+#define P_KEY_COL4 (P_DEFINED | P_IDENT(GPIO_PE6) | P_FUNCT(1))
+#define P_KEY_ROW7 (P_DEFINED | P_IDENT(GPIO_PE7) | P_FUNCT(1))
+
+#define P_PPI0_D0 (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(0))
+#define P_PPI0_D1 (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(0))
+#define P_PPI0_D2 (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(0))
+#define P_PPI0_D3 (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(0))
+#define P_PPI0_D4 (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(0))
+#define P_PPI0_D5 (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(0))
+#define P_PPI0_D6 (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(0))
+#define P_PPI0_D7 (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(0))
+#define P_PPI0_D8 (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(0))
+#define P_PPI0_D9 (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(0))
+#define P_PPI0_D10 (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(0))
+#define P_PPI0_D11 (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(0))
+#define P_PPI0_D12 (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(0))
+#define P_PPI0_D13 (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(0))
+#define P_PPI0_D14 (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(0))
+#define P_PPI0_D15 (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(0))
+#define P_ATAPI_D0A (P_DEFINED | P_IDENT(GPIO_PF0) | P_FUNCT(1))
+#define P_ATAPI_D1A (P_DEFINED | P_IDENT(GPIO_PF1) | P_FUNCT(1))
+#define P_ATAPI_D2A (P_DEFINED | P_IDENT(GPIO_PF2) | P_FUNCT(1))
+#define P_ATAPI_D3A (P_DEFINED | P_IDENT(GPIO_PF3) | P_FUNCT(1))
+#define P_ATAPI_D4A (P_DEFINED | P_IDENT(GPIO_PF4) | P_FUNCT(1))
+#define P_ATAPI_D5A (P_DEFINED | P_IDENT(GPIO_PF5) | P_FUNCT(1))
+#define P_ATAPI_D6A (P_DEFINED | P_IDENT(GPIO_PF6) | P_FUNCT(1))
+#define P_ATAPI_D7A (P_DEFINED | P_IDENT(GPIO_PF7) | P_FUNCT(1))
+#define P_ATAPI_D8A (P_DEFINED | P_IDENT(GPIO_PF8) | P_FUNCT(1))
+#define P_ATAPI_D9A (P_DEFINED | P_IDENT(GPIO_PF9) | P_FUNCT(1))
+#define P_ATAPI_D10A (P_DEFINED | P_IDENT(GPIO_PF10) | P_FUNCT(1))
+#define P_ATAPI_D11A (P_DEFINED | P_IDENT(GPIO_PF11) | P_FUNCT(1))
+#define P_ATAPI_D12A (P_DEFINED | P_IDENT(GPIO_PF12) | P_FUNCT(1))
+#define P_ATAPI_D13A (P_DEFINED | P_IDENT(GPIO_PF13) | P_FUNCT(1))
+#define P_ATAPI_D14A (P_DEFINED | P_IDENT(GPIO_PF14) | P_FUNCT(1))
+#define P_ATAPI_D15A (P_DEFINED | P_IDENT(GPIO_PF15) | P_FUNCT(1))
+
+#define P_PPI0_CLK (P_DEFINED | P_IDENT(GPIO_PG0) | P_FUNCT(0))
+#define P_PPI0_FS1 (P_DEFINED | P_IDENT(GPIO_PG1) | P_FUNCT(0))
+#define P_PPI0_FS2 (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(0))
+#define P_PPI0_D16 (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(0))
+#define P_PPI0_D17 (P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(0))
+#define P_SPI1_SSEL1 (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(0))
+#define P_SPI1_SSEL2 (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(0))
+#define P_SPI1_SSEL3 (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(0))
+#define P_SPI1_SCK (P_DEFINED | P_IDENT(GPIO_PG8) | P_FUNCT(0))
+#define P_SPI1_MISO (P_DEFINED | P_IDENT(GPIO_PG9) | P_FUNCT(0))
+#define P_SPI1_MOSI (P_DEFINED | P_IDENT(GPIO_PG10) | P_FUNCT(0))
+#define P_SPI1_SS (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(0))
+#define P_CAN0_TX (P_DEFINED | P_IDENT(GPIO_PG12) | P_FUNCT(0))
+#define P_CAN0_RX (P_DEFINED | P_IDENT(GPIO_PG13) | P_FUNCT(0))
+#define P_CAN1_TX (P_DEFINED | P_IDENT(GPIO_PG14) | P_FUNCT(0))
+#define P_CAN1_RX (P_DEFINED | P_IDENT(GPIO_PG15) | P_FUNCT(0))
+#define P_ATAPI_A0A (P_DEFINED | P_IDENT(GPIO_PG2) | P_FUNCT(1))
+#define P_ATAPI_A1A (P_DEFINED | P_IDENT(GPIO_PG3) | P_FUNCT(1))
+#define P_ATAPI_A2A (P_DEFINED | P_IDENT(GPIO_PG4) | P_FUNCT(1))
+#define P_HOST_CE (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(1))
+#define P_HOST_RD (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(1))
+#define P_HOST_WR (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(1))
+#define P_MTXONB (P_DEFINED | P_IDENT(GPIO_PG11) | P_FUNCT(1))
+#define P_PPI2_FS2 (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(2))
+#define P_PPI2_FS1 (P_DEFINED | P_IDENT(GPIO_PG6) | P_FUNCT(2))
+#define P_PPI2_CLK (P_DEFINED | P_IDENT(GPIO_PG7) | P_FUNCT(2))
+#define P_CNT_CZM (P_DEFINED | P_IDENT(GPIO_PG5) | P_FUNCT(3))
+
+#define P_UART1_TX (P_DEFINED | P_IDENT(GPIO_PH0) | P_FUNCT(0))
+#define P_UART1_RX (P_DEFINED | P_IDENT(GPIO_PH1) | P_FUNCT(0))
+#define P_ATAPI_RESET (P_DEFINED | P_IDENT(GPIO_PH2) | P_FUNCT(0))
+#define P_HOST_ADDR (P_DEFINED | P_IDENT(GPIO_PH3) | P_FUNCT(0))
+#define P_HOST_ACK (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(0))
+#define P_MTX (P_DEFINED | P_IDENT(GPIO_PH5) | P_FUNCT(0))
+#define P_MRX (P_DEFINED | P_IDENT(GPIO_PH6) | P_FUNCT(0))
+#define P_MRXONB (P_DEFINED | P_IDENT(GPIO_PH7) | P_FUNCT(0))
+#define P_A4 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PH8) | P_FUNCT(0))
+#define P_A5 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PH9) | P_FUNCT(0))
+#define P_A6 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PH10) | P_FUNCT(0))
+#define P_A7 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PH11) | P_FUNCT(0))
+#define P_A8 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PH12) | P_FUNCT(0))
+#define P_A9 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PH13) | P_FUNCT(0))
+#define P_PPI1_FS3 (P_DEFINED | P_IDENT(GPIO_PH0) | P_FUNCT(1))
+#define P_PPI2_FS3 (P_DEFINED | P_IDENT(GPIO_PH1) | P_FUNCT(1))
+#define P_TMR8 (P_DEFINED | P_IDENT(GPIO_PH2) | P_FUNCT(1))
+#define P_TMR9 (P_DEFINED | P_IDENT(GPIO_PH3) | P_FUNCT(1))
+#define P_TMR10 (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(1))
+#define P_DMAR0 (P_DEFINED | P_IDENT(GPIO_PH5) | P_FUNCT(1))
+#define P_DMAR1 (P_DEFINED | P_IDENT(GPIO_PH6) | P_FUNCT(1))
+#define P_PPI0_FS3 (P_DEFINED | P_IDENT(GPIO_PH2) | P_FUNCT(2))
+#define P_CNT_CDG (P_DEFINED | P_IDENT(GPIO_PH3) | P_FUNCT(2))
+#define P_CNT_CUD (P_DEFINED | P_IDENT(GPIO_PH4) | P_FUNCT(2))
+
+#define P_A10 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI0) | P_FUNCT(0))
+#define P_A11 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI1) | P_FUNCT(0))
+#define P_A12 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI2) | P_FUNCT(0))
+#define P_A13 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI3) | P_FUNCT(0))
+#define P_A14 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI4) | P_FUNCT(0))
+#define P_A15 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI5) | P_FUNCT(0))
+#define P_A16 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI6) | P_FUNCT(0))
+#define P_A17 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI7) | P_FUNCT(0))
+#define P_A18 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI8) | P_FUNCT(0))
+#define P_A19 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI9) | P_FUNCT(0))
+#define P_A20 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI10) | P_FUNCT(0))
+#define P_A21 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI11) | P_FUNCT(0))
+#define P_A22 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI12) | P_FUNCT(0))
+#define P_A23 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI13) | P_FUNCT(0))
+#define P_A24 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI14) | P_FUNCT(0))
+#define P_A25 (P_MAYSHARE | P_DEFINED | P_IDENT(GPIO_PI15) | P_FUNCT(0))
+#define P_NOR_CLK (P_DEFINED | P_IDENT(GPIO_PI15) | P_FUNCT(1))
+
+#define P_AMC_ARDY_NOR_WAIT (P_DEFINED | P_IDENT(GPIO_PJ0) | P_FUNCT(0))
+#define P_NAND_CE (P_DEFINED | P_IDENT(GPIO_PJ1) | P_FUNCT(0))
+#define P_NAND_RB (P_DEFINED | P_IDENT(GPIO_PJ2) | P_FUNCT(0))
+#define P_ATAPI_DIOR (P_DEFINED | P_IDENT(GPIO_PJ3) | P_FUNCT(0))
+#define P_ATAPI_DIOW (P_DEFINED | P_IDENT(GPIO_PJ4) | P_FUNCT(0))
+#define P_ATAPI_CS0 (P_DEFINED | P_IDENT(GPIO_PJ5) | P_FUNCT(0))
+#define P_ATAPI_CS1 (P_DEFINED | P_IDENT(GPIO_PJ6) | P_FUNCT(0))
+#define P_ATAPI_DMACK (P_DEFINED | P_IDENT(GPIO_PJ7) | P_FUNCT(0))
+#define P_ATAPI_DMARQ (P_DEFINED | P_IDENT(GPIO_PJ8) | P_FUNCT(0))
+#define P_ATAPI_INTRQ (P_DEFINED | P_IDENT(GPIO_PJ9) | P_FUNCT(0))
+#define P_ATAPI_IORDY (P_DEFINED | P_IDENT(GPIO_PJ10) | P_FUNCT(0))
+#define P_AMC_BR (P_DEFINED | P_IDENT(GPIO_PJ11) | P_FUNCT(0))
+#define P_AMC_BG (P_DEFINED | P_IDENT(GPIO_PJ12) | P_FUNCT(0))
+#define P_AMC_BGH (P_DEFINED | P_IDENT(GPIO_PJ13) | P_FUNCT(0))
+
+#endif /* _MACH_PORTMUX_H_ */
diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h
index b14f872e5703..1a8ec9e46922 100644
--- a/include/asm-blackfin/mach-bf561/cdefBF561.h
+++ b/include/asm-blackfin/mach-bf561/cdefBF561.h
@@ -57,12 +57,14 @@
/* Writing to VR_CTL initiates a PLL relock sequence. */
static __inline__ void bfin_write_VR_CTL(unsigned int val)
{
- unsigned long flags, iwr;
+ unsigned long flags, iwr0, iwr1;
/* Enable the PLL Wakeup bit in SIC IWR */
- iwr = bfin_read32(SICA_IWR0);
+ iwr0 = bfin_read32(SICA_IWR0);
+ iwr1 = bfin_read32(SICA_IWR1);
/* Only allow PPL Wakeup) */
bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+ bfin_write32(SICA_IWR1, 0);
bfin_write16(VR_CTL, val);
__builtin_bfin_ssync();
@@ -70,7 +72,8 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val)
local_irq_save(flags);
asm("IDLE;");
local_irq_restore(flags);
- bfin_write32(SICA_IWR0, iwr);
+ bfin_write32(SICA_IWR0, iwr0);
+ bfin_write32(SICA_IWR1, iwr1);
}
#define bfin_read_PLL_STAT() bfin_read16(PLL_STAT)
#define bfin_write_PLL_STAT(val) bfin_write16(PLL_STAT,val)
diff --git a/include/asm-blackfin/mach-bf561/dma.h b/include/asm-blackfin/mach-bf561/dma.h
index 21d982003e75..766334b7d8ab 100644
--- a/include/asm-blackfin/mach-bf561/dma.h
+++ b/include/asm-blackfin/mach-bf561/dma.h
@@ -32,4 +32,7 @@
#define CH_IMEM_STREAM1_SRC 34
#define CH_IMEM_STREAM1_DEST 35
+extern int channel2irq(unsigned int channel);
+extern struct dma_register *base_addr[];
+
#endif
diff --git a/include/asm-blackfin/mach-bf561/portmux.h b/include/asm-blackfin/mach-bf561/portmux.h
new file mode 100644
index 000000000000..10d11d5ffe23
--- /dev/null
+++ b/include/asm-blackfin/mach-bf561/portmux.h
@@ -0,0 +1,87 @@
+#ifndef _MACH_PORTMUX_H_
+#define _MACH_PORTMUX_H_
+
+#define P_PPI0_CLK (P_DONTCARE)
+#define P_PPI0_FS1 (P_DONTCARE)
+#define P_PPI0_FS2 (P_DONTCARE)
+#define P_PPI0_FS3 (P_DONTCARE)
+#define P_PPI0_D15 (P_DEFINED | P_IDENT(GPIO_PF47))
+#define P_PPI0_D14 (P_DEFINED | P_IDENT(GPIO_PF46))
+#define P_PPI0_D13 (P_DEFINED | P_IDENT(GPIO_PF45))
+#define P_PPI0_D12 (P_DEFINED | P_IDENT(GPIO_PF44))
+#define P_PPI0_D11 (P_DEFINED | P_IDENT(GPIO_PF43))
+#define P_PPI0_D10 (P_DEFINED | P_IDENT(GPIO_PF42))
+#define P_PPI0_D9 (P_DEFINED | P_IDENT(GPIO_PF41))
+#define P_PPI0_D8 (P_DEFINED | P_IDENT(GPIO_PF40))
+#define P_PPI0_D0 (P_DONTCARE)
+#define P_PPI0_D1 (P_DONTCARE)
+#define P_PPI0_D2 (P_DONTCARE)
+#define P_PPI0_D3 (P_DONTCARE)
+#define P_PPI0_D4 (P_DONTCARE)
+#define P_PPI0_D5 (P_DONTCARE)
+#define P_PPI0_D6 (P_DONTCARE)
+#define P_PPI0_D7 (P_DONTCARE)
+#define P_PPI1_CLK (P_DONTCARE)
+#define P_PPI1_FS1 (P_DONTCARE)
+#define P_PPI1_FS2 (P_DONTCARE)
+#define P_PPI1_FS3 (P_DONTCARE)
+#define P_PPI1_D15 (P_DEFINED | P_IDENT(GPIO_PF39))
+#define P_PPI1_D14 (P_DEFINED | P_IDENT(GPIO_PF38))
+#define P_PPI1_D13 (P_DEFINED | P_IDENT(GPIO_PF37))
+#define P_PPI1_D12 (P_DEFINED | P_IDENT(GPIO_PF36))
+#define P_PPI1_D11 (P_DEFINED | P_IDENT(GPIO_PF35))
+#define P_PPI1_D10 (P_DEFINED | P_IDENT(GPIO_PF34))
+#define P_PPI1_D9 (P_DEFINED | P_IDENT(GPIO_PF33))
+#define P_PPI1_D8 (P_DEFINED | P_IDENT(GPIO_PF32))
+#define P_PPI1_D0 (P_DONTCARE)
+#define P_PPI1_D1 (P_DONTCARE)
+#define P_PPI1_D2 (P_DONTCARE)
+#define P_PPI1_D3 (P_DONTCARE)
+#define P_PPI1_D4 (P_DONTCARE)
+#define P_PPI1_D5 (P_DONTCARE)
+#define P_PPI1_D6 (P_DONTCARE)
+#define P_PPI1_D7 (P_DONTCARE)
+#define P_SPORT1_TSCLK (P_DEFINED | P_IDENT(GPIO_PF31))
+#define P_SPORT1_RSCLK (P_DEFINED | P_IDENT(GPIO_PF30))
+#define P_SPORT0_TSCLK (P_DEFINED | P_IDENT(GPIO_PF29))
+#define P_SPORT0_RSCLK (P_DEFINED | P_IDENT(GPIO_PF28))
+#define P_UART0_RX (P_DEFINED | P_IDENT(GPIO_PF27))
+#define P_UART0_TX (P_DEFINED | P_IDENT(GPIO_PF26))
+#define P_SPORT1_DRSEC (P_DEFINED | P_IDENT(GPIO_PF25))
+#define P_SPORT1_RFS (P_DEFINED | P_IDENT(GPIO_PF24))
+#define P_SPORT1_DTPRI (P_DEFINED | P_IDENT(GPIO_PF23))
+#define P_SPORT1_DTSEC (P_DEFINED | P_IDENT(GPIO_PF22))
+#define P_SPORT1_TFS (P_DEFINED | P_IDENT(GPIO_PF21))
+#define P_SPORT1_DRPRI (P_DONTCARE)
+#define P_SPORT0_DRSEC (P_DEFINED | P_IDENT(GPIO_PF20))
+#define P_SPORT0_RFS (P_DEFINED | P_IDENT(GPIO_PF19))
+#define P_SPORT0_DTPRI (P_DEFINED | P_IDENT(GPIO_PF18))
+#define P_SPORT0_DTSEC (P_DEFINED | P_IDENT(GPIO_PF17))
+#define P_SPORT0_TFS (P_DEFINED | P_IDENT(GPIO_PF16))
+#define P_SPORT0_DRPRI (P_DONTCARE)
+#define P_TMRCLK (P_DEFINED | P_IDENT(GPIO_PF15))
+#define P_SPI0_SSEL7 (P_DEFINED | P_IDENT(GPIO_PF7))
+#define P_SPI0_SSEL6 (P_DEFINED | P_IDENT(GPIO_PF6))
+#define P_SPI0_SSEL5 (P_DEFINED | P_IDENT(GPIO_PF5))
+#define P_SPI0_SSEL4 (P_DEFINED | P_IDENT(GPIO_PF4))
+#define P_SPI0_SSEL3 (P_DEFINED | P_IDENT(GPIO_PF3))
+#define P_SPI0_SSEL2 (P_DEFINED | P_IDENT(GPIO_PF2))
+#define P_SPI0_SSEL1 (P_DEFINED | P_IDENT(GPIO_PF1))
+#define P_SPI0_SS (P_DEFINED | P_IDENT(GPIO_PF0))
+#define P_TMR11 (P_DONTCARE)
+#define P_TMR10 (P_DONTCARE)
+#define P_TMR9 (P_DONTCARE)
+#define P_TMR8 (P_DONTCARE)
+#define P_TMR7 (P_DEFINED | P_IDENT(GPIO_PF7))
+#define P_TMR6 (P_DEFINED | P_IDENT(GPIO_PF6))
+#define P_TMR5 (P_DEFINED | P_IDENT(GPIO_PF5))
+#define P_TMR4 (P_DEFINED | P_IDENT(GPIO_PF4))
+#define P_TMR3 (P_DEFINED | P_IDENT(GPIO_PF3))
+#define P_TMR2 (P_DEFINED | P_IDENT(GPIO_PF2))
+#define P_TMR1 (P_DEFINED | P_IDENT(GPIO_PF1))
+#define P_TMR0 (P_DEFINED | P_IDENT(GPIO_PF0))
+#define P_SPI0_MOSI (P_DONTCARE)
+#define P_SPI0_MIS0 (P_DONTCARE)
+#define P_SPI0_SCK (P_DONTCARE)
+
+#endif /* _MACH_PORTMUX_H_ */
diff --git a/include/asm-blackfin/mach-common/cdef_LPBlackfin.h b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h
index 58f878947cbc..94ed381e5606 100644
--- a/include/asm-blackfin/mach-common/cdef_LPBlackfin.h
+++ b/include/asm-blackfin/mach-common/cdef_LPBlackfin.h
@@ -40,16 +40,7 @@
#define bfin_write_SRAM_BASE_ADDRESS(val) bfin_write32(SRAM_BASE_ADDRESS,val)
#define bfin_read_DMEM_CONTROL() bfin_read32(DMEM_CONTROL)
#ifdef ANOMALY_05000125
-static __inline__ void bfin_write_DMEM_CONTROL(unsigned int val)
-{
- unsigned long flags, iwr;
-
- local_irq_save(flags);
- __asm__(".align 8\n");
- bfin_write32(IMEM_CONTROL, val);
- __builtin_bfin_ssync();
- local_irq_restore(flags);
-}
+extern void bfin_write_DMEM_CONTROL(unsigned int val);
#else
#define bfin_write_DMEM_CONTROL(val) bfin_write32(DMEM_CONTROL,val)
#endif
@@ -139,17 +130,7 @@ static __inline__ void bfin_write_DMEM_CONTROL(unsigned int val)
*/
#define bfin_read_IMEM_CONTROL() bfin_read32(IMEM_CONTROL)
#ifdef ANOMALY_05000125
-static __inline__ void bfin_write_IMEM_CONTROL(unsigned int val)
-{
- unsigned long flags, iwr;
-
- local_irq_save(flags);
- __asm__(".align 8\n");
- bfin_write32(IMEM_CONTROL, val);
- __builtin_bfin_ssync();
- local_irq_restore(flags);
-
-}
+extern void bfin_write_IMEM_CONTROL(unsigned int val);
#else
#define bfin_write_IMEM_CONTROL(val) bfin_write32(IMEM_CONTROL,val)
#endif
diff --git a/include/asm-blackfin/mman.h b/include/asm-blackfin/mman.h
index 4d504f908c0c..b58f5ad3f024 100644
--- a/include/asm-blackfin/mman.h
+++ b/include/asm-blackfin/mman.h
@@ -22,8 +22,6 @@
#define MAP_NORESERVE 0x4000 /* don't check for reservations */
#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */
#define MAP_NONBLOCK 0x10000 /* do not block on IO */
-#define MAP_UNINITIALIZE 0x4000000 /* For anonymous mmap, memory could
- be uninitialized. */
#define MS_ASYNC 1 /* sync memory asynchronously */
#define MS_INVALIDATE 2 /* invalidate the caches */
diff --git a/include/asm-blackfin/page.h b/include/asm-blackfin/page.h
index ffad947f1b2a..8bc86717021c 100644
--- a/include/asm-blackfin/page.h
+++ b/include/asm-blackfin/page.h
@@ -4,7 +4,11 @@
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#else
#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#endif
#define PAGE_MASK (~(PAGE_SIZE-1))
#ifdef __KERNEL__
diff --git a/include/asm-blackfin/portmux.h b/include/asm-blackfin/portmux.h
new file mode 100644
index 000000000000..9d3681e42111
--- /dev/null
+++ b/include/asm-blackfin/portmux.h
@@ -0,0 +1,1133 @@
+/*
+ * Common header file for blackfin family of processors.
+ *
+ */
+
+#ifndef _PORTMUX_H_
+#define _PORTMUX_H_
+
+#define P_IDENT(x) ((x) & 0x1FF)
+#define P_FUNCT(x) (((x) & 0x3) << 9)
+#define P_FUNCT2MUX(x) (((x) >> 9) & 0x3)
+#define P_DEFINED 0x8000
+#define P_UNDEF 0x4000
+#define P_MAYSHARE 0x2000
+#define P_DONTCARE 0x1000
+
+#include <asm/gpio.h>
+#include <asm/mach/portmux.h>
+
+#ifndef P_SPORT2_TFS
+#define P_SPORT2_TFS P_UNDEF
+#endif
+
+#ifndef P_SPORT2_DTSEC
+#define P_SPORT2_DTSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT2_DTPRI
+#define P_SPORT2_DTPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT2_TSCLK
+#define P_SPORT2_TSCLK P_UNDEF
+#endif
+
+#ifndef P_SPORT2_RFS
+#define P_SPORT2_RFS P_UNDEF
+#endif
+
+#ifndef P_SPORT2_DRSEC
+#define P_SPORT2_DRSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT2_DRPRI
+#define P_SPORT2_DRPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT2_RSCLK
+#define P_SPORT2_RSCLK P_UNDEF
+#endif
+
+#ifndef P_SPORT3_TFS
+#define P_SPORT3_TFS P_UNDEF
+#endif
+
+#ifndef P_SPORT3_DTSEC
+#define P_SPORT3_DTSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT3_DTPRI
+#define P_SPORT3_DTPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT3_TSCLK
+#define P_SPORT3_TSCLK P_UNDEF
+#endif
+
+#ifndef P_SPORT3_RFS
+#define P_SPORT3_RFS P_UNDEF
+#endif
+
+#ifndef P_SPORT3_DRSEC
+#define P_SPORT3_DRSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT3_DRPRI
+#define P_SPORT3_DRPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT3_RSCLK
+#define P_SPORT3_RSCLK P_UNDEF
+#endif
+
+#ifndef P_TMR4
+#define P_TMR4 P_UNDEF
+#endif
+
+#ifndef P_TMR5
+#define P_TMR5 P_UNDEF
+#endif
+
+#ifndef P_TMR6
+#define P_TMR6 P_UNDEF
+#endif
+
+#ifndef P_TMR7
+#define P_TMR7 P_UNDEF
+#endif
+
+#ifndef P_TWI1_SCL
+#define P_TWI1_SCL P_UNDEF
+#endif
+
+#ifndef P_TWI1_SDA
+#define P_TWI1_SDA P_UNDEF
+#endif
+
+#ifndef P_UART3_RTS
+#define P_UART3_RTS P_UNDEF
+#endif
+
+#ifndef P_UART3_CTS
+#define P_UART3_CTS P_UNDEF
+#endif
+
+#ifndef P_UART2_TX
+#define P_UART2_TX P_UNDEF
+#endif
+
+#ifndef P_UART2_RX
+#define P_UART2_RX P_UNDEF
+#endif
+
+#ifndef P_UART3_TX
+#define P_UART3_TX P_UNDEF
+#endif
+
+#ifndef P_UART3_RX
+#define P_UART3_RX P_UNDEF
+#endif
+
+#ifndef P_SPI2_SS
+#define P_SPI2_SS P_UNDEF
+#endif
+
+#ifndef P_SPI2_SSEL1
+#define P_SPI2_SSEL1 P_UNDEF
+#endif
+
+#ifndef P_SPI2_SSEL2
+#define P_SPI2_SSEL2 P_UNDEF
+#endif
+
+#ifndef P_SPI2_SSEL3
+#define P_SPI2_SSEL3 P_UNDEF
+#endif
+
+#ifndef P_SPI2_SCK
+#define P_SPI2_SCK P_UNDEF
+#endif
+
+#ifndef P_SPI2_MOSI
+#define P_SPI2_MOSI P_UNDEF
+#endif
+
+#ifndef P_SPI2_MISO
+#define P_SPI2_MISO P_UNDEF
+#endif
+
+#ifndef P_TMR0
+#define P_TMR0 P_UNDEF
+#endif
+
+#ifndef P_TMR1
+#define P_TMR1 P_UNDEF
+#endif
+
+#ifndef P_TMR2
+#define P_TMR2 P_UNDEF
+#endif
+
+#ifndef P_TMR3
+#define P_TMR3 P_UNDEF
+#endif
+
+#ifndef P_SPORT0_TFS
+#define P_SPORT0_TFS P_UNDEF
+#endif
+
+#ifndef P_SPORT0_DTSEC
+#define P_SPORT0_DTSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT0_DTPRI
+#define P_SPORT0_DTPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT0_TSCLK
+#define P_SPORT0_TSCLK P_UNDEF
+#endif
+
+#ifndef P_SPORT0_RFS
+#define P_SPORT0_RFS P_UNDEF
+#endif
+
+#ifndef P_SPORT0_DRSEC
+#define P_SPORT0_DRSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT0_DRPRI
+#define P_SPORT0_DRPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT0_RSCLK
+#define P_SPORT0_RSCLK P_UNDEF
+#endif
+
+#ifndef P_SD_D0
+#define P_SD_D0 P_UNDEF
+#endif
+
+#ifndef P_SD_D1
+#define P_SD_D1 P_UNDEF
+#endif
+
+#ifndef P_SD_D2
+#define P_SD_D2 P_UNDEF
+#endif
+
+#ifndef P_SD_D3
+#define P_SD_D3 P_UNDEF
+#endif
+
+#ifndef P_SD_CLK
+#define P_SD_CLK P_UNDEF
+#endif
+
+#ifndef P_SD_CMD
+#define P_SD_CMD P_UNDEF
+#endif
+
+#ifndef P_MMCLK
+#define P_MMCLK P_UNDEF
+#endif
+
+#ifndef P_MBCLK
+#define P_MBCLK P_UNDEF
+#endif
+
+#ifndef P_PPI1_D0
+#define P_PPI1_D0 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D1
+#define P_PPI1_D1 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D2
+#define P_PPI1_D2 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D3
+#define P_PPI1_D3 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D4
+#define P_PPI1_D4 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D5
+#define P_PPI1_D5 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D6
+#define P_PPI1_D6 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D7
+#define P_PPI1_D7 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D8
+#define P_PPI1_D8 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D9
+#define P_PPI1_D9 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D10
+#define P_PPI1_D10 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D11
+#define P_PPI1_D11 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D12
+#define P_PPI1_D12 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D13
+#define P_PPI1_D13 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D14
+#define P_PPI1_D14 P_UNDEF
+#endif
+
+#ifndef P_PPI1_D15
+#define P_PPI1_D15 P_UNDEF
+#endif
+
+#ifndef P_HOST_D8
+#define P_HOST_D8 P_UNDEF
+#endif
+
+#ifndef P_HOST_D9
+#define P_HOST_D9 P_UNDEF
+#endif
+
+#ifndef P_HOST_D10
+#define P_HOST_D10 P_UNDEF
+#endif
+
+#ifndef P_HOST_D11
+#define P_HOST_D11 P_UNDEF
+#endif
+
+#ifndef P_HOST_D12
+#define P_HOST_D12 P_UNDEF
+#endif
+
+#ifndef P_HOST_D13
+#define P_HOST_D13 P_UNDEF
+#endif
+
+#ifndef P_HOST_D14
+#define P_HOST_D14 P_UNDEF
+#endif
+
+#ifndef P_HOST_D15
+#define P_HOST_D15 P_UNDEF
+#endif
+
+#ifndef P_HOST_D0
+#define P_HOST_D0 P_UNDEF
+#endif
+
+#ifndef P_HOST_D1
+#define P_HOST_D1 P_UNDEF
+#endif
+
+#ifndef P_HOST_D2
+#define P_HOST_D2 P_UNDEF
+#endif
+
+#ifndef P_HOST_D3
+#define P_HOST_D3 P_UNDEF
+#endif
+
+#ifndef P_HOST_D4
+#define P_HOST_D4 P_UNDEF
+#endif
+
+#ifndef P_HOST_D5
+#define P_HOST_D5 P_UNDEF
+#endif
+
+#ifndef P_HOST_D6
+#define P_HOST_D6 P_UNDEF
+#endif
+
+#ifndef P_HOST_D7
+#define P_HOST_D7 P_UNDEF
+#endif
+
+#ifndef P_SPORT1_TFS
+#define P_SPORT1_TFS P_UNDEF
+#endif
+
+#ifndef P_SPORT1_DTSEC
+#define P_SPORT1_DTSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT1_DTPRI
+#define P_SPORT1_DTPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT1_TSCLK
+#define P_SPORT1_TSCLK P_UNDEF
+#endif
+
+#ifndef P_SPORT1_RFS
+#define P_SPORT1_RFS P_UNDEF
+#endif
+
+#ifndef P_SPORT1_DRSEC
+#define P_SPORT1_DRSEC P_UNDEF
+#endif
+
+#ifndef P_SPORT1_DRPRI
+#define P_SPORT1_DRPRI P_UNDEF
+#endif
+
+#ifndef P_SPORT1_RSCLK
+#define P_SPORT1_RSCLK P_UNDEF
+#endif
+
+#ifndef P_PPI2_D0
+#define P_PPI2_D0 P_UNDEF
+#endif
+
+#ifndef P_PPI2_D1
+#define P_PPI2_D1 P_UNDEF
+#endif
+
+#ifndef P_PPI2_D2
+#define P_PPI2_D2 P_UNDEF
+#endif
+
+#ifndef P_PPI2_D3
+#define P_PPI2_D3 P_UNDEF
+#endif
+
+#ifndef P_PPI2_D4
+#define P_PPI2_D4 P_UNDEF
+#endif
+
+#ifndef P_PPI2_D5
+#define P_PPI2_D5 P_UNDEF
+#endif
+
+#ifndef P_PPI2_D6
+#define P_PPI2_D6 P_UNDEF
+#endif
+
+#ifndef P_PPI2_D7
+#define P_PPI2_D7 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D18
+#define P_PPI0_D18 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D19
+#define P_PPI0_D19 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D20
+#define P_PPI0_D20 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D21
+#define P_PPI0_D21 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D22
+#define P_PPI0_D22 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D23
+#define P_PPI0_D23 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW0
+#define P_KEY_ROW0 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW1
+#define P_KEY_ROW1 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW2
+#define P_KEY_ROW2 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW3
+#define P_KEY_ROW3 P_UNDEF
+#endif
+
+#ifndef P_KEY_COL0
+#define P_KEY_COL0 P_UNDEF
+#endif
+
+#ifndef P_KEY_COL1
+#define P_KEY_COL1 P_UNDEF
+#endif
+
+#ifndef P_KEY_COL2
+#define P_KEY_COL2 P_UNDEF
+#endif
+
+#ifndef P_KEY_COL3
+#define P_KEY_COL3 P_UNDEF
+#endif
+
+#ifndef P_SPI0_SCK
+#define P_SPI0_SCK P_UNDEF
+#endif
+
+#ifndef P_SPI0_MISO
+#define P_SPI0_MISO P_UNDEF
+#endif
+
+#ifndef P_SPI0_MOSI
+#define P_SPI0_MOSI P_UNDEF
+#endif
+
+#ifndef P_SPI0_SS
+#define P_SPI0_SS P_UNDEF
+#endif
+
+#ifndef P_SPI0_SSEL1
+#define P_SPI0_SSEL1 P_UNDEF
+#endif
+
+#ifndef P_SPI0_SSEL2
+#define P_SPI0_SSEL2 P_UNDEF
+#endif
+
+#ifndef P_SPI0_SSEL3
+#define P_SPI0_SSEL3 P_UNDEF
+#endif
+
+#ifndef P_UART0_TX
+#define P_UART0_TX P_UNDEF
+#endif
+
+#ifndef P_UART0_RX
+#define P_UART0_RX P_UNDEF
+#endif
+
+#ifndef P_UART1_RTS
+#define P_UART1_RTS P_UNDEF
+#endif
+
+#ifndef P_UART1_CTS
+#define P_UART1_CTS P_UNDEF
+#endif
+
+#ifndef P_PPI1_CLK
+#define P_PPI1_CLK P_UNDEF
+#endif
+
+#ifndef P_PPI1_FS1
+#define P_PPI1_FS1 P_UNDEF
+#endif
+
+#ifndef P_PPI1_FS2
+#define P_PPI1_FS2 P_UNDEF
+#endif
+
+#ifndef P_TWI0_SCL
+#define P_TWI0_SCL P_UNDEF
+#endif
+
+#ifndef P_TWI0_SDA
+#define P_TWI0_SDA P_UNDEF
+#endif
+
+#ifndef P_KEY_COL7
+#define P_KEY_COL7 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW6
+#define P_KEY_ROW6 P_UNDEF
+#endif
+
+#ifndef P_KEY_COL6
+#define P_KEY_COL6 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW5
+#define P_KEY_ROW5 P_UNDEF
+#endif
+
+#ifndef P_KEY_COL5
+#define P_KEY_COL5 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW4
+#define P_KEY_ROW4 P_UNDEF
+#endif
+
+#ifndef P_KEY_COL4
+#define P_KEY_COL4 P_UNDEF
+#endif
+
+#ifndef P_KEY_ROW7
+#define P_KEY_ROW7 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D0
+#define P_PPI0_D0 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D1
+#define P_PPI0_D1 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D2
+#define P_PPI0_D2 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D3
+#define P_PPI0_D3 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D4
+#define P_PPI0_D4 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D5
+#define P_PPI0_D5 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D6
+#define P_PPI0_D6 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D7
+#define P_PPI0_D7 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D8
+#define P_PPI0_D8 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D9
+#define P_PPI0_D9 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D10
+#define P_PPI0_D10 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D11
+#define P_PPI0_D11 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D12
+#define P_PPI0_D12 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D13
+#define P_PPI0_D13 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D14
+#define P_PPI0_D14 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D15
+#define P_PPI0_D15 P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D0A
+#define P_ATAPI_D0A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D1A
+#define P_ATAPI_D1A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D2A
+#define P_ATAPI_D2A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D3A
+#define P_ATAPI_D3A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D4A
+#define P_ATAPI_D4A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D5A
+#define P_ATAPI_D5A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D6A
+#define P_ATAPI_D6A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D7A
+#define P_ATAPI_D7A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D8A
+#define P_ATAPI_D8A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D9A
+#define P_ATAPI_D9A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D10A
+#define P_ATAPI_D10A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D11A
+#define P_ATAPI_D11A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D12A
+#define P_ATAPI_D12A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D13A
+#define P_ATAPI_D13A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D14A
+#define P_ATAPI_D14A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_D15A
+#define P_ATAPI_D15A P_UNDEF
+#endif
+
+#ifndef P_PPI0_CLK
+#define P_PPI0_CLK P_UNDEF
+#endif
+
+#ifndef P_PPI0_FS1
+#define P_PPI0_FS1 P_UNDEF
+#endif
+
+#ifndef P_PPI0_FS2
+#define P_PPI0_FS2 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D16
+#define P_PPI0_D16 P_UNDEF
+#endif
+
+#ifndef P_PPI0_D17
+#define P_PPI0_D17 P_UNDEF
+#endif
+
+#ifndef P_SPI1_SSEL1
+#define P_SPI1_SSEL1 P_UNDEF
+#endif
+
+#ifndef P_SPI1_SSEL2
+#define P_SPI1_SSEL2 P_UNDEF
+#endif
+
+#ifndef P_SPI1_SSEL3
+#define P_SPI1_SSEL3 P_UNDEF
+#endif
+
+#ifndef P_SPI1_SCK
+#define P_SPI1_SCK P_UNDEF
+#endif
+
+#ifndef P_SPI1_MISO
+#define P_SPI1_MISO P_UNDEF
+#endif
+
+#ifndef P_SPI1_MOSI
+#define P_SPI1_MOSI P_UNDEF
+#endif
+
+#ifndef P_SPI1_SS
+#define P_SPI1_SS P_UNDEF
+#endif
+
+#ifndef P_CAN0_TX
+#define P_CAN0_TX P_UNDEF
+#endif
+
+#ifndef P_CAN0_RX
+#define P_CAN0_RX P_UNDEF
+#endif
+
+#ifndef P_CAN1_TX
+#define P_CAN1_TX P_UNDEF
+#endif
+
+#ifndef P_CAN1_RX
+#define P_CAN1_RX P_UNDEF
+#endif
+
+#ifndef P_ATAPI_A0A
+#define P_ATAPI_A0A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_A1A
+#define P_ATAPI_A1A P_UNDEF
+#endif
+
+#ifndef P_ATAPI_A2A
+#define P_ATAPI_A2A P_UNDEF
+#endif
+
+#ifndef P_HOST_CE
+#define P_HOST_CE P_UNDEF
+#endif
+
+#ifndef P_HOST_RD
+#define P_HOST_RD P_UNDEF
+#endif
+
+#ifndef P_HOST_WR
+#define P_HOST_WR P_UNDEF
+#endif
+
+#ifndef P_MTXONB
+#define P_MTXONB P_UNDEF
+#endif
+
+#ifndef P_PPI2_FS2
+#define P_PPI2_FS2 P_UNDEF
+#endif
+
+#ifndef P_PPI2_FS1
+#define P_PPI2_FS1 P_UNDEF
+#endif
+
+#ifndef P_PPI2_CLK
+#define P_PPI2_CLK P_UNDEF
+#endif
+
+#ifndef P_CNT_CZM
+#define P_CNT_CZM P_UNDEF
+#endif
+
+#ifndef P_UART1_TX
+#define P_UART1_TX P_UNDEF
+#endif
+
+#ifndef P_UART1_RX
+#define P_UART1_RX P_UNDEF
+#endif
+
+#ifndef P_ATAPI_RESET
+#define P_ATAPI_RESET P_UNDEF
+#endif
+
+#ifndef P_HOST_ADDR
+#define P_HOST_ADDR P_UNDEF
+#endif
+
+#ifndef P_HOST_ACK
+#define P_HOST_ACK P_UNDEF
+#endif
+
+#ifndef P_MTX
+#define P_MTX P_UNDEF
+#endif
+
+#ifndef P_MRX
+#define P_MRX P_UNDEF
+#endif
+
+#ifndef P_MRXONB
+#define P_MRXONB P_UNDEF
+#endif
+
+#ifndef P_A4
+#define P_A4 P_UNDEF
+#endif
+
+#ifndef P_A5
+#define P_A5 P_UNDEF
+#endif
+
+#ifndef P_A6
+#define P_A6 P_UNDEF
+#endif
+
+#ifndef P_A7
+#define P_A7 P_UNDEF
+#endif
+
+#ifndef P_A8
+#define P_A8 P_UNDEF
+#endif
+
+#ifndef P_A9
+#define P_A9 P_UNDEF
+#endif
+
+#ifndef P_PPI1_FS3
+#define P_PPI1_FS3 P_UNDEF
+#endif
+
+#ifndef P_PPI2_FS3
+#define P_PPI2_FS3 P_UNDEF
+#endif
+
+#ifndef P_TMR8
+#define P_TMR8 P_UNDEF
+#endif
+
+#ifndef P_TMR9
+#define P_TMR9 P_UNDEF
+#endif
+
+#ifndef P_TMR10
+#define P_TMR10 P_UNDEF
+#endif
+#ifndef P_TMR11
+#define P_TMR11 P_UNDEF
+#endif
+
+#ifndef P_DMAR0
+#define P_DMAR0 P_UNDEF
+#endif
+
+#ifndef P_DMAR1
+#define P_DMAR1 P_UNDEF
+#endif
+
+#ifndef P_PPI0_FS3
+#define P_PPI0_FS3 P_UNDEF
+#endif
+
+#ifndef P_CNT_CDG
+#define P_CNT_CDG P_UNDEF
+#endif
+
+#ifndef P_CNT_CUD
+#define P_CNT_CUD P_UNDEF
+#endif
+
+#ifndef P_A10
+#define P_A10 P_UNDEF
+#endif
+
+#ifndef P_A11
+#define P_A11 P_UNDEF
+#endif
+
+#ifndef P_A12
+#define P_A12 P_UNDEF
+#endif
+
+#ifndef P_A13
+#define P_A13 P_UNDEF
+#endif
+
+#ifndef P_A14
+#define P_A14 P_UNDEF
+#endif
+
+#ifndef P_A15
+#define P_A15 P_UNDEF
+#endif
+
+#ifndef P_A16
+#define P_A16 P_UNDEF
+#endif
+
+#ifndef P_A17
+#define P_A17 P_UNDEF
+#endif
+
+#ifndef P_A18
+#define P_A18 P_UNDEF
+#endif
+
+#ifndef P_A19
+#define P_A19 P_UNDEF
+#endif
+
+#ifndef P_A20
+#define P_A20 P_UNDEF
+#endif
+
+#ifndef P_A21
+#define P_A21 P_UNDEF
+#endif
+
+#ifndef P_A22
+#define P_A22 P_UNDEF
+#endif
+
+#ifndef P_A23
+#define P_A23 P_UNDEF
+#endif
+
+#ifndef P_A24
+#define P_A24 P_UNDEF
+#endif
+
+#ifndef P_A25
+#define P_A25 P_UNDEF
+#endif
+
+#ifndef P_NOR_CLK
+#define P_NOR_CLK P_UNDEF
+#endif
+
+#ifndef P_TMRCLK
+#define P_TMRCLK P_UNDEF
+#endif
+
+#ifndef P_AMC_ARDY_NOR_WAIT
+#define P_AMC_ARDY_NOR_WAIT P_UNDEF
+#endif
+
+#ifndef P_NAND_CE
+#define P_NAND_CE P_UNDEF
+#endif
+
+#ifndef P_NAND_RB
+#define P_NAND_RB P_UNDEF
+#endif
+
+#ifndef P_ATAPI_DIOR
+#define P_ATAPI_DIOR P_UNDEF
+#endif
+
+#ifndef P_ATAPI_DIOW
+#define P_ATAPI_DIOW P_UNDEF
+#endif
+
+#ifndef P_ATAPI_CS0
+#define P_ATAPI_CS0 P_UNDEF
+#endif
+
+#ifndef P_ATAPI_CS1
+#define P_ATAPI_CS1 P_UNDEF
+#endif
+
+#ifndef P_ATAPI_DMACK
+#define P_ATAPI_DMACK P_UNDEF
+#endif
+
+#ifndef P_ATAPI_DMARQ
+#define P_ATAPI_DMARQ P_UNDEF
+#endif
+
+#ifndef P_ATAPI_INTRQ
+#define P_ATAPI_INTRQ P_UNDEF
+#endif
+
+#ifndef P_ATAPI_IORDY
+#define P_ATAPI_IORDY P_UNDEF
+#endif
+
+#ifndef P_AMC_BR
+#define P_AMC_BR P_UNDEF
+#endif
+
+#ifndef P_AMC_BG
+#define P_AMC_BG P_UNDEF
+#endif
+
+#ifndef P_AMC_BGH
+#define P_AMC_BGH P_UNDEF
+#endif
+
+/* EMAC */
+
+#ifndef P_MII0_ETxD0
+#define P_MII0_ETxD0 P_UNDEF
+#endif
+
+#ifndef P_MII0_ETxD1
+#define P_MII0_ETxD1 P_UNDEF
+#endif
+
+#ifndef P_MII0_ETxD2
+#define P_MII0_ETxD2 P_UNDEF
+#endif
+
+#ifndef P_MII0_ETxD3
+#define P_MII0_ETxD3 P_UNDEF
+#endif
+
+#ifndef P_MII0_ETxEN
+#define P_MII0_ETxEN P_UNDEF
+#endif
+
+#ifndef P_MII0_TxCLK
+#define P_MII0_TxCLK P_UNDEF
+#endif
+
+#ifndef P_MII0_PHYINT
+#define P_MII0_PHYINT P_UNDEF
+#endif
+
+#ifndef P_MII0_COL
+#define P_MII0_COL P_UNDEF
+#endif
+
+#ifndef P_MII0_ERxD0
+#define P_MII0_ERxD0 P_UNDEF
+#endif
+
+#ifndef P_MII0_ERxD1
+#define P_MII0_ERxD1 P_UNDEF
+#endif
+
+#ifndef P_MII0_ERxD2
+#define P_MII0_ERxD2 P_UNDEF
+#endif
+
+#ifndef P_MII0_ERxD3
+#define P_MII0_ERxD3 P_UNDEF
+#endif
+
+#ifndef P_MII0_ERxDV
+#define P_MII0_ERxDV P_UNDEF
+#endif
+
+#ifndef P_MII0_ERxCLK
+#define P_MII0_ERxCLK P_UNDEF
+#endif
+
+#ifndef P_MII0_ERxER
+#define P_MII0_ERxER P_UNDEF
+#endif
+
+#ifndef P_MII0_CRS
+#define P_MII0_CRS P_UNDEF
+#endif
+
+#ifndef P_RMII0_REF_CLK
+#define P_RMII0_REF_CLK P_UNDEF
+#endif
+
+#ifndef P_RMII0_MDINT
+#define P_RMII0_MDINT P_UNDEF
+#endif
+
+#ifndef P_RMII0_CRS_DV
+#define P_RMII0_CRS_DV P_UNDEF
+#endif
+
+#ifndef P_MDC
+#define P_MDC P_UNDEF
+#endif
+
+#ifndef P_MDIO
+#define P_MDIO P_UNDEF
+#endif
+
+#endif /* _PORTMUX_H_ */
diff --git a/include/asm-blackfin/trace.h b/include/asm-blackfin/trace.h
new file mode 100644
index 000000000000..9c2474c9a589
--- /dev/null
+++ b/include/asm-blackfin/trace.h
@@ -0,0 +1,52 @@
+/*
+ * Common header file for blackfin family of processors.
+ *
+ */
+
+#ifndef _BLACKFIN_TRACE_
+#define _BLACKFIN_TRACE_
+
+#ifndef __ASSEMBLY__
+/* Trace Macros for C files */
+
+#define trace_buffer_save(x) \
+ do { \
+ (x) = bfin_read_TBUFCTL(); \
+ bfin_write_TBUFCTL((x) & ~TBUFEN); \
+ } while (0)
+
+#define trace_buffer_restore(x) \
+ do { \
+ bfin_write_TBUFCTL((x)); \
+ } while (0)
+
+#else
+/* Trace Macros for Assembly files */
+
+#define TRACE_BUFFER_START(preg, dreg) trace_buffer_start(preg, dreg)
+#define TRACE_BUFFER_STOP(preg, dreg) trace_buffer_stop(preg, dreg)
+
+#define trace_buffer_stop(preg, dreg) \
+ preg.L = LO(TBUFCTL); \
+ preg.H = HI(TBUFCTL); \
+ dreg = 0x1; \
+ [preg] = dreg;
+
+#define trace_buffer_start(preg, dreg) \
+ preg.L = LO(TBUFCTL); \
+ preg.H = HI(TBUFCTL); \
+ dreg = 0x13; \
+ [preg] = dreg;
+
+#ifdef CONFIG_DEBUG_BFIN_NO_KERN_HWTRACE
+# define DEBUG_START_HWTRACE(preg, dreg) trace_buffer_start(preg, dreg)
+# define DEBUG_STOP_HWTRACE(preg, dreg) trace_buffer_stop(preg, dreg)
+
+#else
+# define DEBUG_START_HWTRACE(preg, dreg)
+# define DEBUG_STOP_HWTRACE(preg, dreg)
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _BLACKFIN_TRACE_ */
diff --git a/include/asm-cris/a.out.h b/include/asm-cris/a.out.h
index 770734ce54a6..919b34a084f8 100644
--- a/include/asm-cris/a.out.h
+++ b/include/asm-cris/a.out.h
@@ -8,6 +8,7 @@
/* grabbed from the intel stuff */
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
struct exec
diff --git a/include/asm-cris/fb.h b/include/asm-cris/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-cris/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-cris/ioctls.h b/include/asm-cris/ioctls.h
index 97787c3c575f..4f4e52531fa0 100644
--- a/include/asm-cris/ioctls.h
+++ b/include/asm-cris/ioctls.h
@@ -48,6 +48,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h
index 9f13c32552bf..0648e3153f81 100644
--- a/include/asm-cris/page.h
+++ b/include/asm-cris/page.h
@@ -20,7 +20,8 @@
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/*
diff --git a/include/asm-cris/pci.h b/include/asm-cris/pci.h
index b2ac8a331da1..730ce40fdd0f 100644
--- a/include/asm-cris/pci.h
+++ b/include/asm-cris/pci.h
@@ -52,47 +52,11 @@ struct pci_dev;
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
-/* This is always fine. */
-#define pci_dac_dma_supported(pci_dev, mask) (1)
-
-static inline dma64_addr_t
-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
-{
- return ((dma64_addr_t) page_to_phys(page) +
- (dma64_addr_t) offset);
-}
-
-static inline struct page *
-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return pfn_to_page(dma_addr >> PAGE_SHIFT);
-}
-
-static inline unsigned long
-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return (dma_addr & ~PAGE_MASK);
-}
-
-static inline void
-pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
-}
-
-static inline void
-pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
-}
-
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* __KERNEL__ */
/* implement the pci_ DMA API in terms of the generic device dma_ one */
diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h
index c94a7107019c..417f71116215 100644
--- a/include/asm-cris/pgtable.h
+++ b/include/asm-cris/pgtable.h
@@ -111,9 +111,7 @@ extern unsigned long empty_zero_page;
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
-static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
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; }
@@ -124,18 +122,6 @@ static inline pte_t pte_wrprotect(pte_t pte)
return pte;
}
-static inline pte_t pte_rdprotect(pte_t pte)
-{
- pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
- return pte;
-}
-
-static inline pte_t pte_exprotect(pte_t pte)
-{
- pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
- return pte;
-}
-
static inline pte_t pte_mkclean(pte_t pte)
{
pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE);
@@ -156,22 +142,6 @@ static inline pte_t pte_mkwrite(pte_t pte)
return pte;
}
-static inline pte_t pte_mkread(pte_t pte)
-{
- pte_val(pte) |= _PAGE_READ;
- if (pte_val(pte) & _PAGE_ACCESSED)
- pte_val(pte) |= _PAGE_SILENT_READ;
- return pte;
-}
-
-static inline pte_t pte_mkexec(pte_t pte)
-{
- pte_val(pte) |= _PAGE_READ;
- if (pte_val(pte) & _PAGE_ACCESSED)
- pte_val(pte) |= _PAGE_SILENT_READ;
- return pte;
-}
-
static inline pte_t pte_mkdirty(pte_t pte)
{
pte_val(pte) |= _PAGE_MODIFIED;
diff --git a/include/asm-cris/termbits.h b/include/asm-cris/termbits.h
index 6cc2e2736f7b..71c1b36269b8 100644
--- a/include/asm-cris/termbits.h
+++ b/include/asm-cris/termbits.h
@@ -166,6 +166,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
diff --git a/include/asm-cris/termios.h b/include/asm-cris/termios.h
index c9dbd4d43368..b0124e6c2e41 100644
--- a/include/asm-cris/termios.h
+++ b/include/asm-cris/termios.h
@@ -81,8 +81,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-frv/fb.h b/include/asm-frv/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-frv/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-frv/mem-layout.h b/include/asm-frv/mem-layout.h
index a025dd4514e7..aaf2a773d9d3 100644
--- a/include/asm-frv/mem-layout.h
+++ b/include/asm-frv/mem-layout.h
@@ -60,6 +60,7 @@
*/
#define BRK_BASE __UL(2 * 1024 * 1024 + PAGE_SIZE)
#define STACK_TOP __UL(2 * 1024 * 1024)
+#define STACK_TOP_MAX STACK_TOP
/* userspace process size */
#ifdef CONFIG_MMU
diff --git a/include/asm-frv/pci.h b/include/asm-frv/pci.h
index f35a4511e7b9..585d9b49949a 100644
--- a/include/asm-frv/pci.h
+++ b/include/asm-frv/pci.h
@@ -22,10 +22,6 @@ struct pci_dev;
#define pcibios_assign_all_busses() 0
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
extern void pcibios_set_master(struct pci_dev *dev);
extern void pcibios_penalize_isa_irq(int irq);
@@ -44,9 +40,6 @@ extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
void *vaddr, dma_addr_t dma_handle);
-/* This is always fine. */
-#define pci_dac_dma_supported(pci_dev, mask) (1)
-
/* Return the index of the PCI controller for device PDEV. */
#define pci_controller_num(PDEV) (0)
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 114aefae2701..147e995bec24 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -377,30 +377,17 @@ static inline pmd_t *pmd_offset(pud_t *dir, unsigned long address)
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte) { return !((pte).pte & _PAGE_SUPER); }
-static inline int pte_exec(pte_t pte) { return !((pte).pte & _PAGE_SUPER); }
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 pte_t pte_rdprotect(pte_t pte) { (pte).pte |= _PAGE_SUPER; return pte; }
-static inline pte_t pte_exprotect(pte_t pte) { (pte).pte |= _PAGE_SUPER; return pte; }
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; }
static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte |= _PAGE_WP; return pte; }
-static inline pte_t pte_mkread(pte_t pte) { (pte).pte &= ~_PAGE_SUPER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) { (pte).pte &= ~_PAGE_SUPER; 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 int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
- int i = test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
- asm volatile("dcf %M0" :: "U"(*ptep));
- return i;
-}
-
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
{
int i = test_and_clear_bit(_PAGE_BIT_ACCESSED, ptep);
@@ -510,7 +497,6 @@ static inline int pte_file(pte_t pte)
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
diff --git a/include/asm-frv/uaccess.h b/include/asm-frv/uaccess.h
index 3d90e1018ee2..53650c958f41 100644
--- a/include/asm-frv/uaccess.h
+++ b/include/asm-frv/uaccess.h
@@ -277,6 +277,8 @@ extern long __memcpy_user(void *dst, const void *src, unsigned long count);
#endif
+#define __clear_user clear_user
+
static inline unsigned long __must_check
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
index d0ea6789b31e..7306c71a8926 100644
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -326,10 +326,14 @@
#define __NR_move_pages 317
#define __NR_getcpu 318
#define __NR_epoll_pwait 319
+#define __NR_utimensat 320
+#define __NR_signalfd 321
+#define __NR_timerfd 322
+#define __NR_eventfd 323
#ifdef __KERNEL__
-#define NR_syscalls 320
+#define NR_syscalls 324
#define __ARCH_WANT_IPC_PARSE_VERSION
/* #define __ARCH_WANT_OLD_READDIR */
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 7f30cce52857..344e3091af24 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -28,7 +28,7 @@ struct bug_entry {
#endif
#ifndef HAVE_ARCH_BUG_ON
-#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)
#endif
#ifndef HAVE_ARCH_WARN_ON
diff --git a/include/asm-generic/dma-mapping-broken.h b/include/asm-generic/dma-mapping-broken.h
index 29413d3d4605..e2468f894d2a 100644
--- a/include/asm-generic/dma-mapping-broken.h
+++ b/include/asm-generic/dma-mapping-broken.h
@@ -1,24 +1,82 @@
#ifndef _ASM_GENERIC_DMA_MAPPING_H
#define _ASM_GENERIC_DMA_MAPPING_H
-/* This is used for archs that do not support DMA */
+/* define the dma api to allow compilation but not linking of
+ * dma dependent code. Code that depends on the dma-mapping
+ * API needs to set 'depends on HAS_DMA' in its Kconfig
+ */
-static inline void *
+struct scatterlist;
+
+extern void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
- gfp_t flag)
-{
- BUG();
- return NULL;
-}
+ gfp_t flag);
-static inline void
+extern void
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t dma_handle)
-{
- BUG();
-}
+ dma_addr_t dma_handle);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+extern dma_addr_t
+dma_map_single(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction direction);
+
+extern void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction direction);
+
+extern int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction);
+
+extern void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+ enum dma_data_direction direction);
+
+extern dma_addr_t
+dma_map_page(struct device *dev, struct page *page, unsigned long offset,
+ size_t size, enum dma_data_direction direction);
+
+extern void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction);
+
+extern void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction);
+
+extern void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+
+extern void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction);
+
+#define dma_sync_single_for_device dma_sync_single_for_cpu
+#define dma_sync_single_range_for_device dma_sync_single_range_for_cpu
+#define dma_sync_sg_for_device dma_sync_sg_for_cpu
+
+extern int
+dma_mapping_error(dma_addr_t dma_addr);
+
+extern int
+dma_supported(struct device *dev, u64 mask);
+
+extern int
+dma_set_mask(struct device *dev, u64 mask);
+
+extern int
+dma_get_cache_alignment(void);
+
+extern int
+dma_is_consistent(struct device *dev, dma_addr_t dma_handle);
+
+extern void
+dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ enum dma_data_direction direction);
+
#endif /* _ASM_GENERIC_DMA_MAPPING_H */
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
index c154b9d6e7e5..b8477414c5c8 100644
--- a/include/asm-generic/fcntl.h
+++ b/include/asm-generic/fcntl.h
@@ -48,6 +48,9 @@
#ifndef O_NOATIME
#define O_NOATIME 01000000
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 02000000 /* set close_on_exec */
+#endif
#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index d984a9041436..d85172e9ed45 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -14,6 +14,11 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ __attribute__((__section__(".data.percpu.shared_aligned"))) \
+ __typeof__(type) per_cpu__##name \
+ ____cacheline_aligned_in_smp
+
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*({ \
extern int simple_identifier_##var(void); \
@@ -34,6 +39,9 @@ do { \
#define DEFINE_PER_CPU(type, name) \
__typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ DEFINE_PER_CPU(type, name)
+
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
#define __raw_get_cpu_var(var) per_cpu__##var
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 7d7bcf990e99..f605e8d0eed3 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -3,25 +3,6 @@
#ifndef __ASSEMBLY__
-#ifndef __HAVE_ARCH_PTEP_ESTABLISH
-/*
- * Establish a new mapping:
- * - flush the old one
- * - update the page tables
- * - inform the TLB about the new one
- *
- * We hold the mm semaphore for reading, and the pte lock.
- *
- * Note: the old pte is known to not be writable, so we don't need to
- * worry about dirty bits etc getting lost.
- */
-#define ptep_establish(__vma, __address, __ptep, __entry) \
-do { \
- set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \
- flush_tlb_page(__vma, __address); \
-} while (0)
-#endif
-
#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
/*
* Largely same as above, but only sets the access flags (dirty,
@@ -68,31 +49,6 @@ do { \
})
#endif
-#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define ptep_test_and_clear_dirty(__vma, __address, __ptep) \
-({ \
- pte_t __pte = *__ptep; \
- int r = 1; \
- if (!pte_dirty(__pte)) \
- r = 0; \
- else \
- set_pte_at((__vma)->vm_mm, (__address), (__ptep), \
- pte_mkclean(__pte)); \
- r; \
-})
-#endif
-
-#ifndef __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
-#define ptep_clear_flush_dirty(__vma, __address, __ptep) \
-({ \
- int __dirty; \
- __dirty = ptep_test_and_clear_dirty(__vma, __address, __ptep); \
- if (__dirty) \
- flush_tlb_page(__vma, __address); \
- __dirty; \
-})
-#endif
-
#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define ptep_get_and_clear(__mm, __address, __ptep) \
({ \
diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h
index 09ec447fe2af..16a466e50681 100644
--- a/include/asm-generic/unaligned.h
+++ b/include/asm-generic/unaligned.h
@@ -18,7 +18,8 @@
#define get_unaligned(ptr) \
__get_unaligned((ptr), sizeof(*(ptr)))
#define put_unaligned(x,ptr) \
- __put_unaligned((__u64)(x), (ptr), sizeof(*(ptr)))
+ ((void)sizeof(*(ptr)=(x)),\
+ __put_unaligned((__force __u64)(x), (ptr), sizeof(*(ptr))))
/*
* This function doesn't actually exist. The idea is that when
@@ -95,21 +96,21 @@ static inline void __ustw(__u16 val, __u16 *addr)
default: \
bad_unaligned_access_length(); \
}; \
- (__typeof__(*(ptr)))val; \
+ (__force __typeof__(*(ptr)))val; \
})
#define __put_unaligned(val, ptr, size) \
-do { \
+({ \
void *__gu_p = ptr; \
switch (size) { \
case 1: \
- *(__u8 *)__gu_p = val; \
+ *(__u8 *)__gu_p = (__force __u8)val; \
break; \
case 2: \
- __ustw(val, __gu_p); \
+ __ustw((__force __u16)val, __gu_p); \
break; \
case 4: \
- __ustl(val, __gu_p); \
+ __ustl((__force __u32)val, __gu_p); \
break; \
case 8: \
__ustq(val, __gu_p); \
@@ -117,6 +118,7 @@ do { \
default: \
bad_unaligned_access_length(); \
}; \
-} while(0)
+ (void)0; \
+})
#endif /* _ASM_GENERIC_UNALIGNED_H */
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 84155eb67f1d..0240e0506a07 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -224,7 +224,11 @@
}
#define NOTES \
- .notes : { *(.note.*) } :note
+ .notes : AT(ADDR(.notes) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start_notes) = .; \
+ *(.note.*) \
+ VMLINUX_SYMBOL(__stop_notes) = .; \
+ }
#define INITCALLS \
*(.initcall0.init) \
@@ -245,3 +249,11 @@
*(.initcall7.init) \
*(.initcall7s.init)
+#define PERCPU(align) \
+ . = ALIGN(align); \
+ __per_cpu_start = .; \
+ .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \
+ *(.data.percpu) \
+ *(.data.percpu.shared_aligned) \
+ } \
+ __per_cpu_end = .;
diff --git a/include/asm-h8300/a.out.h b/include/asm-h8300/a.out.h
index 3c70939f9f00..aa5d22778235 100644
--- a/include/asm-h8300/a.out.h
+++ b/include/asm-h8300/a.out.h
@@ -20,6 +20,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
diff --git a/include/asm-h8300/dma-mapping.h b/include/asm-h8300/dma-mapping.h
deleted file mode 100644
index d00e40099165..000000000000
--- a/include/asm-h8300/dma-mapping.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/dma-mapping-broken.h>
diff --git a/include/asm-h8300/fb.h b/include/asm-h8300/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-h8300/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-h8300/ioctls.h b/include/asm-h8300/ioctls.h
index ac20457e5978..98a53d067269 100644
--- a/include/asm-h8300/ioctls.h
+++ b/include/asm-h8300/ioctls.h
@@ -47,6 +47,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-h8300/irq.h b/include/asm-h8300/irq.h
index 41be646c3514..56eec28cc2c4 100644
--- a/include/asm-h8300/irq.h
+++ b/include/asm-h8300/irq.h
@@ -59,7 +59,4 @@ static __inline__ int irq_canonicalize(int irq)
return irq;
}
-extern void enable_irq(unsigned int);
-extern void disable_irq(unsigned int);
-
#endif /* _H8300_IRQ_H_ */
diff --git a/include/asm-h8300/page.h b/include/asm-h8300/page.h
index 3b4f2903f91d..c8cc81a3aca5 100644
--- a/include/asm-h8300/page.h
+++ b/include/asm-h8300/page.h
@@ -22,7 +22,8 @@
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/*
diff --git a/include/asm-h8300/pci.h b/include/asm-h8300/pci.h
index 0c771b05fdd5..97389b35aa35 100644
--- a/include/asm-h8300/pci.h
+++ b/include/asm-h8300/pci.h
@@ -22,8 +22,4 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
#define PCI_DMA_BUS_IS_PHYS (1)
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* _ASM_H8300_PCI_H */
diff --git a/include/asm-h8300/termbits.h b/include/asm-h8300/termbits.h
index e877b40ac5ba..31eca81db3f7 100644
--- a/include/asm-h8300/termbits.h
+++ b/include/asm-h8300/termbits.h
@@ -141,6 +141,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -156,10 +157,12 @@ struct ktermios {
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 16 /* shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
diff --git a/include/asm-h8300/termios.h b/include/asm-h8300/termios.h
index fb2925d08c49..70eea64b4213 100644
--- a/include/asm-h8300/termios.h
+++ b/include/asm-h8300/termios.h
@@ -82,8 +82,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-h8300/thread_info.h b/include/asm-h8300/thread_info.h
index 45f09dc9caff..aee4009a498e 100644
--- a/include/asm-h8300/thread_info.h
+++ b/include/asm-h8300/thread_info.h
@@ -92,6 +92,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling
TIF_NEED_RESCHED */
#define TIF_MEMDIE 5
+#define TIF_RESTORE_SIGMASK 6 /* restore signal mask in do_signal() */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -99,6 +100,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
diff --git a/include/asm-i386/a.out.h b/include/asm-i386/a.out.h
index ab17bb8e5465..851a60f8258c 100644
--- a/include/asm-i386/a.out.h
+++ b/include/asm-i386/a.out.h
@@ -20,6 +20,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index eb7da5402bfa..bda6c810c0f4 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -149,4 +149,6 @@ apply_paravirt(struct paravirt_patch_site *start,
#define __parainstructions_end NULL
#endif
+extern void text_poke(void *addr, unsigned char *opcode, int len);
+
#endif /* _I386_ALTERNATIVE_H */
diff --git a/include/asm-i386/boot.h b/include/asm-i386/boot.h
index bd024ab4fe53..ed8affbf96cb 100644
--- a/include/asm-i386/boot.h
+++ b/include/asm-i386/boot.h
@@ -1,5 +1,5 @@
-#ifndef _LINUX_BOOT_H
-#define _LINUX_BOOT_H
+#ifndef _ASM_BOOT_H
+#define _ASM_BOOT_H
/* Don't touch these, unless you really know what you're doing. */
#define DEF_INITSEG 0x9000
@@ -17,4 +17,4 @@
+ (CONFIG_PHYSICAL_ALIGN - 1)) \
& ~(CONFIG_PHYSICAL_ALIGN - 1))
-#endif /* _LINUX_BOOT_H */
+#endif /* _ASM_BOOT_H */
diff --git a/include/asm-i386/bootparam.h b/include/asm-i386/bootparam.h
new file mode 100644
index 000000000000..427d8652bfde
--- /dev/null
+++ b/include/asm-i386/bootparam.h
@@ -0,0 +1,85 @@
+#ifndef _ASM_BOOTPARAM_H
+#define _ASM_BOOTPARAM_H
+
+#include <linux/types.h>
+#include <linux/screen_info.h>
+#include <linux/apm_bios.h>
+#include <asm/e820.h>
+#include <linux/edd.h>
+#include <video/edid.h>
+
+struct setup_header {
+ u8 setup_sects;
+ u16 root_flags;
+ u32 syssize;
+ u16 ram_size;
+ u16 vid_mode;
+ u16 root_dev;
+ u16 boot_flag;
+ u16 jump;
+ u32 header;
+ u16 version;
+ u32 realmode_swtch;
+ u16 start_sys;
+ u16 kernel_version;
+ u8 type_of_loader;
+ u8 loadflags;
+#define LOADED_HIGH 0x01
+#define CAN_USE_HEAP 0x80
+ u16 setup_move_size;
+ u32 code32_start;
+ u32 ramdisk_image;
+ u32 ramdisk_size;
+ u32 bootsect_kludge;
+ u16 heap_end_ptr;
+ u16 _pad1;
+ u32 cmd_line_ptr;
+ u32 initrd_addr_max;
+ u32 kernel_alignment;
+ u8 relocatable_kernel;
+} __attribute__((packed));
+
+struct sys_desc_table {
+ u16 length;
+ u8 table[14];
+};
+
+struct efi_info {
+ u32 _pad1;
+ u32 efi_systab;
+ u32 efi_memdesc_size;
+ u32 efi_memdec_version;
+ u32 efi_memmap;
+ u32 fi_memmap_size;
+ u32 _pad2[2];
+};
+
+/* The so-called "zeropage" */
+struct boot_params {
+ struct screen_info screen_info; /* 0x000 */
+ struct apm_bios_info apm_bios_info; /* 0x040 */
+ u8 _pad2[12]; /* 0x054 */
+ u32 speedstep_info[4]; /* 0x060 */
+ u8 _pad3[16]; /* 0x070 */
+ u8 hd0_info[16]; /* obsolete! */ /* 0x080 */
+ u8 hd1_info[16]; /* obsolete! */ /* 0x090 */
+ struct sys_desc_table sys_desc_table; /* 0x0a0 */
+ u8 _pad4[144]; /* 0x0b0 */
+ struct edid_info edid_info; /* 0x140 */
+ struct efi_info efi_info; /* 0x1c0 */
+ u32 alt_mem_k; /* 0x1e0 */
+ u32 scratch; /* Scratch field! */ /* 0x1e4 */
+ u8 e820_entries; /* 0x1e8 */
+ u8 eddbuf_entries; /* 0x1e9 */
+ u8 edd_mbr_sig_buf_entries; /* 0x1ea */
+ u8 _pad6[6]; /* 0x1eb */
+ struct setup_header hdr; /* setup header */ /* 0x1f1 */
+ u8 _pad7[0x290-0x1f1-sizeof(struct setup_header)];
+ u32 edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]; /* 0x290 */
+ struct e820entry e820_map[E820MAX]; /* 0x2d0 */
+ u8 _pad8[48]; /* 0xcd0 */
+ struct edd_info eddbuf[EDDMAXNR]; /* 0xd00 */
+ u8 _pad9[276]; /* 0xeec */
+} __attribute__((packed));
+
+#endif /* _ASM_BOOTPARAM_H */
diff --git a/include/asm-i386/cmpxchg.h b/include/asm-i386/cmpxchg.h
index 7adcef0cd53b..f86ede28f6dc 100644
--- a/include/asm-i386/cmpxchg.h
+++ b/include/asm-i386/cmpxchg.h
@@ -3,14 +3,16 @@
#include <linux/bitops.h> /* for LOCK_PREFIX */
+/*
+ * Note: if you use set64_bit(), __cmpxchg64(), or their variants, you
+ * you need to test for the feature in boot_cpu_data.
+ */
+
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))
-
-#ifdef CONFIG_X86_CMPXCHG64
-
/*
* The semantics of XCHGCMP8B are a bit strange, this is why
* there is a loop and the loading of %%eax and %%edx has to
@@ -32,7 +34,7 @@ static inline void __set_64bit (unsigned long long * ptr,
"\n1:\t"
"movl (%0), %%eax\n\t"
"movl 4(%0), %%edx\n\t"
- "lock cmpxchg8b (%0)\n\t"
+ LOCK_PREFIX "cmpxchg8b (%0)\n\t"
"jnz 1b"
: /* no outputs */
: "D"(ptr),
@@ -65,8 +67,6 @@ static inline void __set_64bit_var (unsigned long long *ptr,
__set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
__set_64bit(ptr, ll_low(value), ll_high(value)) )
-#endif
-
/*
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
* Note 2: xchg has side effect, so that attribute volatile is necessary,
@@ -252,8 +252,6 @@ static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
})
#endif
-#ifdef CONFIG_X86_CMPXCHG64
-
static inline unsigned long long __cmpxchg64(volatile void *ptr, unsigned long long old,
unsigned long long new)
{
@@ -289,5 +287,3 @@ static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
((__typeof__(*(ptr)))__cmpxchg64_local((ptr),(unsigned long long)(o),\
(unsigned long long)(n)))
#endif
-
-#endif
diff --git a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
index f514e906643a..c961c03cf1e2 100644
--- a/include/asm-i386/cpufeature.h
+++ b/include/asm-i386/cpufeature.h
@@ -12,7 +12,7 @@
#endif
#include <asm/required-features.h>
-#define NCAPINTS 7 /* N 32-bit words worth of info */
+#define NCAPINTS 8 /* N 32-bit words worth of info */
/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
@@ -81,6 +81,7 @@
#define X86_FEATURE_BTS (3*32+13) /* Branch Trace Store */
#define X86_FEATURE_LAPIC_TIMER_BROKEN (3*32+ 14) /* lapic timer broken in C1 */
#define X86_FEATURE_SYNC_RDTSC (3*32+15) /* RDTSC synchronizes the CPU */
+#define X86_FEATURE_REP_GOOD (3*32+16) /* rep microcode works well on this CPU */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
@@ -108,11 +109,24 @@
#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */
#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
-#define cpu_has(c, bit) \
- ((__builtin_constant_p(bit) && (bit) < 32 && \
- (1UL << (bit)) & REQUIRED_MASK1) ? \
- 1 : \
- test_bit(bit, (c)->x86_capability))
+/*
+ * Auxiliary flags: Linux defined - For features scattered in various
+ * CPUID levels like 0x6, 0xA etc
+ */
+#define X86_FEATURE_IDA (7*32+ 0) /* Intel Dynamic Acceleration */
+
+#define cpu_has(c, bit) \
+ (__builtin_constant_p(bit) && \
+ ( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \
+ (((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \
+ (((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \
+ (((bit)>>5)==3 && (1UL<<((bit)&31) & REQUIRED_MASK3)) || \
+ (((bit)>>5)==4 && (1UL<<((bit)&31) & REQUIRED_MASK4)) || \
+ (((bit)>>5)==5 && (1UL<<((bit)&31) & REQUIRED_MASK5)) || \
+ (((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \
+ (((bit)>>5)==7 && (1UL<<((bit)&31) & REQUIRED_MASK7)) ) \
+ ? 1 : \
+ test_bit(bit, (c)->x86_capability))
#define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
#define cpu_has_fpu boot_cpu_has(X86_FEATURE_FPU)
diff --git a/include/asm-i386/e820.h b/include/asm-i386/e820.h
index 096a2a8eb1da..43114c824608 100644
--- a/include/asm-i386/e820.h
+++ b/include/asm-i386/e820.h
@@ -25,13 +25,15 @@
#ifndef __ASSEMBLY__
+struct e820entry {
+ u64 addr; /* start of memory segment */
+ u64 size; /* size of memory segment */
+ u32 type; /* type of memory segment */
+} __attribute__((packed));
+
struct e820map {
- int nr_map;
- struct e820entry {
- unsigned long long addr; /* start of memory segment */
- unsigned long long size; /* size of memory segment */
- unsigned long type; /* type of memory segment */
- } map[E820MAX];
+ u32 nr_map;
+ struct e820entry map[E820MAX];
};
extern struct e820map e820;
@@ -45,6 +47,14 @@ extern void e820_register_memory(void);
extern void limit_regions(unsigned long long size);
extern void print_memory_map(char *who);
+#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+extern void e820_mark_nosave_regions(void);
+#else
+static inline void e820_mark_nosave_regions(void)
+{
+}
+#endif
+
#endif/*!__ASSEMBLY__*/
#endif/*__E820_HEADER*/
diff --git a/include/asm-i386/fb.h b/include/asm-i386/fb.h
new file mode 100644
index 000000000000..d1c6297d4a61
--- /dev/null
+++ b/include/asm-i386/fb.h
@@ -0,0 +1,17 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+extern int fb_is_primary_device(struct fb_info *info);
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
index 80ea052ee3a4..249e753ac805 100644
--- a/include/asm-i386/fixmap.h
+++ b/include/asm-i386/fixmap.h
@@ -54,6 +54,8 @@ extern unsigned long __FIXADDR_TOP;
enum fixed_addresses {
FIX_HOLE,
FIX_VDSO,
+ FIX_DBGP_BASE,
+ FIX_EARLYCON_MEM_BASE,
#ifdef CONFIG_X86_LOCAL_APIC
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
#endif
diff --git a/include/asm-i386/geode.h b/include/asm-i386/geode.h
new file mode 100644
index 000000000000..6da4bbbea3dc
--- /dev/null
+++ b/include/asm-i386/geode.h
@@ -0,0 +1,159 @@
+/*
+ * AMD Geode definitions
+ * Copyright (C) 2006, Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+#ifndef _ASM_GEODE_H_
+#define _ASM_GEODE_H_
+
+#include <asm/processor.h>
+#include <linux/io.h>
+
+/* Generic southbridge functions */
+
+#define GEODE_DEV_PMS 0
+#define GEODE_DEV_ACPI 1
+#define GEODE_DEV_GPIO 2
+#define GEODE_DEV_MFGPT 3
+
+extern int geode_get_dev_base(unsigned int dev);
+
+/* Useful macros */
+#define geode_pms_base() geode_get_dev_base(GEODE_DEV_PMS)
+#define geode_acpi_base() geode_get_dev_base(GEODE_DEV_ACPI)
+#define geode_gpio_base() geode_get_dev_base(GEODE_DEV_GPIO)
+#define geode_mfgpt_base() geode_get_dev_base(GEODE_DEV_MFGPT)
+
+/* MSRS */
+
+#define GX_GLCP_SYS_RSTPLL 0x4C000014
+
+#define MSR_LBAR_SMB 0x5140000B
+#define MSR_LBAR_GPIO 0x5140000C
+#define MSR_LBAR_MFGPT 0x5140000D
+#define MSR_LBAR_ACPI 0x5140000E
+#define MSR_LBAR_PMS 0x5140000F
+
+#define MSR_PIC_YSEL_LOW 0x51400020
+#define MSR_PIC_YSEL_HIGH 0x51400021
+#define MSR_PIC_ZSEL_LOW 0x51400022
+#define MSR_PIC_ZSEL_HIGH 0x51400023
+
+#define MFGPT_IRQ_MSR 0x51400028
+#define MFGPT_NR_MSR 0x51400029
+
+/* Resource Sizes */
+
+#define LBAR_GPIO_SIZE 0xFF
+#define LBAR_MFGPT_SIZE 0x40
+#define LBAR_ACPI_SIZE 0x40
+#define LBAR_PMS_SIZE 0x80
+
+/* ACPI registers (PMS block) */
+
+/*
+ * PM1_EN is only valid when VSA is enabled for 16 bit reads.
+ * When VSA is not enabled, *always* read both PM1_STS and PM1_EN
+ * with a 32 bit read at offset 0x0
+ */
+
+#define PM1_STS 0x00
+#define PM1_EN 0x02
+#define PM1_CNT 0x08
+#define PM2_CNT 0x0C
+#define PM_TMR 0x10
+#define PM_GPE0_STS 0x18
+#define PM_GPE0_EN 0x1C
+
+/* PMC registers (PMS block) */
+
+#define PM_SSD 0x00
+#define PM_SCXA 0x04
+#define PM_SCYA 0x08
+#define PM_OUT_SLPCTL 0x0C
+#define PM_SCLK 0x10
+#define PM_SED 0x1
+#define PM_SCXD 0x18
+#define PM_SCYD 0x1C
+#define PM_IN_SLPCTL 0x20
+#define PM_WKD 0x30
+#define PM_WKXD 0x34
+#define PM_RD 0x38
+#define PM_WKXA 0x3C
+#define PM_FSD 0x40
+#define PM_TSD 0x44
+#define PM_PSD 0x48
+#define PM_NWKD 0x4C
+#define PM_AWKD 0x50
+#define PM_SSC 0x54
+
+/* GPIO */
+
+#define GPIO_OUTPUT_VAL 0x00
+#define GPIO_OUTPUT_ENABLE 0x04
+#define GPIO_OUTPUT_OPEN_DRAIN 0x08
+#define GPIO_OUTPUT_INVERT 0x0C
+#define GPIO_OUTPUT_AUX1 0x10
+#define GPIO_OUTPUT_AUX2 0x14
+#define GPIO_PULL_UP 0x18
+#define GPIO_PULL_DOWN 0x1C
+#define GPIO_INPUT_ENABLE 0x20
+#define GPIO_INPUT_INVERT 0x24
+#define GPIO_INPUT_FILTER 0x28
+#define GPIO_INPUT_EVENT_COUNT 0x2C
+#define GPIO_READ_BACK 0x30
+#define GPIO_INPUT_AUX1 0x34
+#define GPIO_EVENTS_ENABLE 0x38
+#define GPIO_LOCK_ENABLE 0x3C
+#define GPIO_POSITIVE_EDGE_EN 0x40
+#define GPIO_NEGATIVE_EDGE_EN 0x44
+#define GPIO_POSITIVE_EDGE_STS 0x48
+#define GPIO_NEGATIVE_EDGE_STS 0x4C
+
+#define GPIO_MAP_X 0xE0
+#define GPIO_MAP_Y 0xE4
+#define GPIO_MAP_Z 0xE8
+#define GPIO_MAP_W 0xEC
+
+extern void geode_gpio_set(unsigned int, unsigned int);
+extern void geode_gpio_clear(unsigned int, unsigned int);
+extern int geode_gpio_isset(unsigned int, unsigned int);
+extern void geode_gpio_setup_event(unsigned int, int, int);
+extern void geode_gpio_set_irq(unsigned int, unsigned int);
+
+static inline void geode_gpio_event_irq(unsigned int gpio, int pair)
+{
+ geode_gpio_setup_event(gpio, pair, 0);
+}
+
+static inline void geode_gpio_event_pme(unsigned int gpio, int pair)
+{
+ geode_gpio_setup_event(gpio, pair, 1);
+}
+
+/* Specific geode tests */
+
+static inline int is_geode_gx(void)
+{
+ return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) &&
+ (boot_cpu_data.x86 == 5) &&
+ (boot_cpu_data.x86_model == 5));
+}
+
+static inline int is_geode_lx(void)
+{
+ return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
+ (boot_cpu_data.x86 == 5) &&
+ (boot_cpu_data.x86_model == 10));
+}
+
+static inline int is_geode(void)
+{
+ return (is_geode_gx() || is_geode_lx());
+}
+
+#endif
diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h
index dddeedf504b7..c82dc7ed96b3 100644
--- a/include/asm-i386/hpet.h
+++ b/include/asm-i386/hpet.h
@@ -4,112 +4,82 @@
#ifdef CONFIG_HPET_TIMER
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/irq.h>
-#include <asm/msr.h>
-#include <asm/delay.h>
-#include <asm/mpspec.h>
-#include <asm/uaccess.h>
-#include <asm/processor.h>
-
-#include <linux/timex.h>
-
/*
* Documentation on HPET can be found at:
* http://www.intel.com/ial/home/sp/pcmmspec.htm
* ftp://download.intel.com/ial/home/sp/mmts098.pdf
*/
-#define HPET_MMAP_SIZE 1024
-
-#define HPET_ID 0x000
-#define HPET_PERIOD 0x004
-#define HPET_CFG 0x010
-#define HPET_STATUS 0x020
-#define HPET_COUNTER 0x0f0
-#define HPET_T0_CFG 0x100
-#define HPET_T0_CMP 0x108
-#define HPET_T0_ROUTE 0x110
-#define HPET_T1_CFG 0x120
-#define HPET_T1_CMP 0x128
-#define HPET_T1_ROUTE 0x130
-#define HPET_T2_CFG 0x140
-#define HPET_T2_CMP 0x148
-#define HPET_T2_ROUTE 0x150
-
-#define HPET_ID_LEGSUP 0x00008000
-#define HPET_ID_NUMBER 0x00001f00
-#define HPET_ID_REV 0x000000ff
+#define HPET_MMAP_SIZE 1024
+
+#define HPET_ID 0x000
+#define HPET_PERIOD 0x004
+#define HPET_CFG 0x010
+#define HPET_STATUS 0x020
+#define HPET_COUNTER 0x0f0
+#define HPET_T0_CFG 0x100
+#define HPET_T0_CMP 0x108
+#define HPET_T0_ROUTE 0x110
+#define HPET_T1_CFG 0x120
+#define HPET_T1_CMP 0x128
+#define HPET_T1_ROUTE 0x130
+#define HPET_T2_CFG 0x140
+#define HPET_T2_CMP 0x148
+#define HPET_T2_ROUTE 0x150
+
+#define HPET_ID_REV 0x000000ff
+#define HPET_ID_NUMBER 0x00001f00
+#define HPET_ID_64BIT 0x00002000
+#define HPET_ID_LEGSUP 0x00008000
+#define HPET_ID_VENDOR 0xffff0000
#define HPET_ID_NUMBER_SHIFT 8
+#define HPET_ID_VENDOR_SHIFT 16
-#define HPET_CFG_ENABLE 0x001
-#define HPET_CFG_LEGACY 0x002
+#define HPET_ID_VENDOR_8086 0x8086
+
+#define HPET_CFG_ENABLE 0x001
+#define HPET_CFG_LEGACY 0x002
#define HPET_LEGACY_8254 2
#define HPET_LEGACY_RTC 8
-#define HPET_TN_ENABLE 0x004
-#define HPET_TN_PERIODIC 0x008
-#define HPET_TN_PERIODIC_CAP 0x010
-#define HPET_TN_SETVAL 0x040
-#define HPET_TN_32BIT 0x100
-
-/* Use our own asm for 64 bit multiply/divide */
-#define ASM_MUL64_REG(eax_out,edx_out,reg_in,eax_in) \
- __asm__ __volatile__("mull %2" \
- :"=a" (eax_out), "=d" (edx_out) \
- :"r" (reg_in), "0" (eax_in))
+#define HPET_TN_LEVEL 0x0002
+#define HPET_TN_ENABLE 0x0004
+#define HPET_TN_PERIODIC 0x0008
+#define HPET_TN_PERIODIC_CAP 0x0010
+#define HPET_TN_64BIT_CAP 0x0020
+#define HPET_TN_SETVAL 0x0040
+#define HPET_TN_32BIT 0x0100
+#define HPET_TN_ROUTE 0x3e00
+#define HPET_TN_FSB 0x4000
+#define HPET_TN_FSB_CAP 0x8000
+#define HPET_TN_ROUTE_SHIFT 9
-#define ASM_DIV64_REG(eax_out,edx_out,reg_in,eax_in,edx_in) \
- __asm__ __volatile__("divl %2" \
- :"=a" (eax_out), "=d" (edx_out) \
- :"r" (reg_in), "0" (eax_in), "1" (edx_in))
-
-#define KERNEL_TICK_USEC (1000000UL/HZ) /* tick value in microsec */
/* Max HPET Period is 10^8 femto sec as in HPET spec */
-#define HPET_MAX_PERIOD (100000000UL)
+#define HPET_MAX_PERIOD 100000000UL
/*
* Min HPET period is 10^5 femto sec just for safety. If it is less than this,
* then 32 bit HPET counter wrapsaround in less than 0.5 sec.
*/
-#define HPET_MIN_PERIOD (100000UL)
-#define HPET_TICK_RATE (HZ * 100000UL)
+#define HPET_MIN_PERIOD 100000UL
-extern unsigned long hpet_address; /* hpet memory map physical address */
+/* hpet memory map physical address */
+extern unsigned long hpet_address;
extern int is_hpet_enabled(void);
-
-#ifdef CONFIG_X86_64
-extern unsigned long hpet_tick; /* hpet clks count per tick */
-extern int hpet_use_timer;
-extern int hpet_rtc_timer_init(void);
extern int hpet_enable(void);
-extern int is_hpet_capable(void);
-extern int hpet_readl(unsigned long a);
-#else
-extern int hpet_enable(void);
-#endif
#ifdef CONFIG_HPET_EMULATE_RTC
+
+#include <linux/interrupt.h>
+
extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec);
+extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min,
+ unsigned char sec);
extern int hpet_set_periodic_freq(unsigned long freq);
extern int hpet_rtc_dropped_irq(void);
extern int hpet_rtc_timer_init(void);
extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
+
#endif /* CONFIG_HPET_EMULATE_RTC */
#else
diff --git a/include/asm-i386/i8253.h b/include/asm-i386/i8253.h
index 6cb0dd4dcdde..7577d058d86e 100644
--- a/include/asm-i386/i8253.h
+++ b/include/asm-i386/i8253.h
@@ -3,19 +3,15 @@
#include <linux/clockchips.h>
+/* i8253A PIT registers */
+#define PIT_MODE 0x43
+#define PIT_CH0 0x40
+#define PIT_CH2 0x42
+
extern spinlock_t i8253_lock;
extern struct clock_event_device *global_clock_event;
-/**
- * pit_interrupt_hook - hook into timer tick
- * @regs: standard registers from interrupt
- *
- * Call the global clock event handler.
- **/
-static inline void pit_interrupt_hook(void)
-{
- global_clock_event->event_handler(global_clock_event);
-}
+extern void setup_pit_timer(void);
#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h
index 0fc240c80f49..e7817a3d6578 100644
--- a/include/asm-i386/ide.h
+++ b/include/asm-i386/ide.h
@@ -40,14 +40,13 @@ static __inline__ int ide_default_irq(unsigned long base)
static __inline__ unsigned long ide_default_io_base(int index)
{
- struct pci_dev *pdev;
/*
* If PCI is present then it is not safe to poke around
* the other legacy IDE ports. Only 0x1f0 and 0x170 are
* defined compatibility mode ports for PCI. A user can
* override this using ide= but we must default safe.
*/
- if ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, NULL)) == NULL) {
+ if (no_pci_devices()) {
switch(index) {
case 2: return 0x1e8;
case 3: return 0x168;
@@ -55,7 +54,6 @@ static __inline__ unsigned long ide_default_io_base(int index)
case 5: return 0x160;
}
}
- pci_dev_put(pdev);
switch (index) {
case 0: return 0x1f0;
case 1: return 0x170;
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index e797586a5bfc..7b65b5b00034 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -129,6 +129,7 @@ extern void iounmap(volatile void __iomem *addr);
*/
extern void *bt_ioremap(unsigned long offset, unsigned long size);
extern void bt_iounmap(void *addr, unsigned long size);
+extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
/* Use early IO mappings for DMI because it's initialized early */
#define dmi_ioremap bt_ioremap
diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h
index 9e15ce0006eb..36f310632c49 100644
--- a/include/asm-i386/irq.h
+++ b/include/asm-i386/irq.h
@@ -41,6 +41,7 @@ extern int irqbalance_disable(char *str);
extern void fixup_irqs(cpumask_t map);
#endif
+unsigned int do_IRQ(struct pt_regs *regs);
void init_IRQ(void);
void __init native_init_IRQ(void);
diff --git a/include/asm-i386/kprobes.h b/include/asm-i386/kprobes.h
index 8774d06689da..06f7303c30ca 100644
--- a/include/asm-i386/kprobes.h
+++ b/include/asm-i386/kprobes.h
@@ -42,7 +42,6 @@ typedef u8 kprobe_opcode_t;
? (MAX_STACK_SIZE) \
: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 0
#define flush_insn_slot(p) do { } while (0)
diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-i386/mach-default/do_timer.h
index 56e5689863ae..23ecda0b28a0 100644
--- a/include/asm-i386/mach-default/do_timer.h
+++ b/include/asm-i386/mach-default/do_timer.h
@@ -12,5 +12,5 @@
static inline void do_timer_interrupt_hook(void)
{
- pit_interrupt_hook();
+ global_clock_event->event_handler(global_clock_event);
}
diff --git a/include/asm-i386/mach-default/io_ports.h b/include/asm-i386/mach-default/io_ports.h
index a96d9f6604ee..48540ba97166 100644
--- a/include/asm-i386/mach-default/io_ports.h
+++ b/include/asm-i386/mach-default/io_ports.h
@@ -7,11 +7,6 @@
#ifndef _MACH_IO_PORTS_H
#define _MACH_IO_PORTS_H
-/* i8253A PIT registers */
-#define PIT_MODE 0x43
-#define PIT_CH0 0x40
-#define PIT_CH2 0x42
-
/* i8259A PIC registers */
#define PIC_MASTER_CMD 0x20
#define PIC_MASTER_IMR 0x21
diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h
index 7f161e760be6..a90c7a60109f 100644
--- a/include/asm-i386/mach-default/irq_vectors_limits.h
+++ b/include/asm-i386/mach-default/irq_vectors_limits.h
@@ -1,7 +1,7 @@
#ifndef _ASM_IRQ_VECTORS_LIMITS_H
#define _ASM_IRQ_VECTORS_LIMITS_H
-#ifdef CONFIG_X86_IO_APIC
+#if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT)
#define NR_IRQS 224
# if (224 >= 32 * NR_CPUS)
# define NR_IRQ_VECTORS NR_IRQS
diff --git a/include/asm-i386/mach-default/mach_reboot.h b/include/asm-i386/mach-default/mach_reboot.h
index a955e57ad016..e23fd9fbebb3 100644
--- a/include/asm-i386/mach-default/mach_reboot.h
+++ b/include/asm-i386/mach-default/mach_reboot.h
@@ -19,14 +19,37 @@ static inline void kb_wait(void)
static inline void mach_reboot(void)
{
int i;
+
+ /* old method, works on most machines */
for (i = 0; i < 10; i++) {
kb_wait();
udelay(50);
+ outb(0xfe, 0x64); /* pulse reset low */
+ udelay(50);
+ }
+
+ /* New method: sets the "System flag" which, when set, indicates
+ * successful completion of the keyboard controller self-test (Basic
+ * Assurance Test, BAT). This is needed for some machines with no
+ * keyboard plugged in. This read-modify-write sequence sets only the
+ * system flag
+ */
+ for (i = 0; i < 10; i++) {
+ int cmd;
+
+ outb(0x20, 0x64); /* read Controller Command Byte */
+ udelay(50);
+ kb_wait();
+ udelay(50);
+ cmd = inb(0x60);
+ udelay(50);
+ kb_wait();
+ udelay(50);
outb(0x60, 0x64); /* write Controller Command Byte */
udelay(50);
kb_wait();
udelay(50);
- outb(0x14, 0x60); /* set "System flag" */
+ outb(cmd | 0x04, 0x60); /* set "System flag" */
udelay(50);
kb_wait();
udelay(50);
diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-i386/mach-voyager/do_timer.h
index 60f9dcc15d54..bc2b58926308 100644
--- a/include/asm-i386/mach-voyager/do_timer.h
+++ b/include/asm-i386/mach-voyager/do_timer.h
@@ -12,7 +12,7 @@
**/
static inline void do_timer_interrupt_hook(void)
{
- pit_interrupt_hook();
+ global_clock_event->event_handler(global_clock_event);
voyager_timer_interrupt();
}
diff --git a/include/asm-i386/mc146818rtc.h b/include/asm-i386/mc146818rtc.h
index 99a890047023..1613b42eaf58 100644
--- a/include/asm-i386/mc146818rtc.h
+++ b/include/asm-i386/mc146818rtc.h
@@ -6,6 +6,7 @@
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/processor.h>
#include <linux/mc146818rtc.h>
#ifndef RTC_PORT
@@ -43,8 +44,10 @@ static inline void lock_cmos(unsigned char reg)
unsigned long new;
new = ((smp_processor_id()+1) << 8) | reg;
for (;;) {
- if (cmos_lock)
+ if (cmos_lock) {
+ cpu_relax();
continue;
+ }
if (__cmpxchg(&cmos_lock, 0, new, sizeof(cmos_lock)) == 0)
return;
}
diff --git a/include/asm-i386/mce.h b/include/asm-i386/mce.h
index b0a02ee34ffd..d56d89742e8f 100644
--- a/include/asm-i386/mce.h
+++ b/include/asm-i386/mce.h
@@ -5,3 +5,7 @@ extern void mcheck_init(struct cpuinfo_x86 *c);
#endif
extern int mce_disabled;
+
+extern void stop_mce(void);
+extern void restart_mce(void);
+
diff --git a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h
index 8198d1cca1f3..7eb0b0b1fb3c 100644
--- a/include/asm-i386/mmu_context.h
+++ b/include/asm-i386/mmu_context.h
@@ -32,6 +32,8 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
#endif
}
+void leave_mm(unsigned long cpu);
+
static inline void switch_mm(struct mm_struct *prev,
struct mm_struct *next,
struct task_struct *tsk)
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index fb1e133efd9f..ff30c98f87b0 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -57,5 +57,7 @@ unsigned lapic_adjust_nmi_hz(unsigned hz);
int lapic_watchdog_ok(void);
void disable_lapic_nmi_watchdog(void);
void enable_lapic_nmi_watchdog(void);
+void stop_nmi(void);
+void restart_nmi(void);
#endif /* ASM_NMI_H */
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index 818ac8bf01e2..80ecc66b6d86 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -34,7 +34,8 @@
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/*
@@ -43,7 +44,6 @@
extern int nx_enabled;
#ifdef CONFIG_X86_PAE
-extern unsigned long long __supported_pte_mask;
typedef struct { unsigned long pte_low, pte_high; } pte_t;
typedef struct { unsigned long long pmd; } pmd_t;
typedef struct { unsigned long long pgd; } pgd_t;
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index 7f846a7d6bcc..7df88be2dd9e 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -52,6 +52,8 @@ struct paravirt_ops
/* Basic arch-specific setup */
void (*arch_setup)(void);
char *(*memory_setup)(void);
+ void (*post_allocator_init)(void);
+
void (*init_IRQ)(void);
void (*time_init)(void);
@@ -116,7 +118,7 @@ struct paravirt_ops
u64 (*read_tsc)(void);
u64 (*read_pmc)(void);
- u64 (*get_scheduled_cycles)(void);
+ unsigned long long (*sched_clock)(void);
unsigned long (*get_cpu_khz)(void);
/* Segment descriptor handling */
@@ -173,7 +175,7 @@ struct paravirt_ops
unsigned long va);
/* Hooks for allocating/releasing pagetable pages */
- void (*alloc_pt)(u32 pfn);
+ void (*alloc_pt)(struct mm_struct *mm, u32 pfn);
void (*alloc_pd)(u32 pfn);
void (*alloc_pd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
void (*release_pt)(u32 pfn);
@@ -260,6 +262,7 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len)
unsigned paravirt_patch_insns(void *site, unsigned len,
const char *start, const char *end);
+int paravirt_disable_iospace(void);
/*
* This generates an indirect call based on the operation type number.
@@ -563,7 +566,10 @@ static inline u64 paravirt_read_tsc(void)
#define rdtscll(val) (val = paravirt_read_tsc())
-#define get_scheduled_cycles(val) (val = paravirt_ops.get_scheduled_cycles())
+static inline unsigned long long paravirt_sched_clock(void)
+{
+ return PVOP_CALL0(unsigned long long, sched_clock);
+}
#define calculate_cpu_khz() (paravirt_ops.get_cpu_khz())
#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
@@ -669,6 +675,12 @@ static inline void setup_secondary_clock(void)
}
#endif
+static inline void paravirt_post_allocator_init(void)
+{
+ if (paravirt_ops.post_allocator_init)
+ (*paravirt_ops.post_allocator_init)();
+}
+
static inline void paravirt_pagetable_setup_start(pgd_t *base)
{
if (paravirt_ops.pagetable_setup_start)
@@ -725,9 +737,9 @@ static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
PVOP_VCALL3(flush_tlb_others, &cpumask, mm, va);
}
-static inline void paravirt_alloc_pt(unsigned pfn)
+static inline void paravirt_alloc_pt(struct mm_struct *mm, unsigned pfn)
{
- PVOP_VCALL1(alloc_pt, pfn);
+ PVOP_VCALL2(alloc_pt, mm, pfn);
}
static inline void paravirt_release_pt(unsigned pfn)
{
diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h
index 64b6d0baedbc..d790343e9982 100644
--- a/include/asm-i386/pci.h
+++ b/include/asm-i386/pci.h
@@ -3,6 +3,11 @@
#ifdef __KERNEL__
+
+struct pci_sysdata {
+ int node; /* NUMA node */
+};
+
#include <linux/mm.h> /* for struct page */
/* Can be used to override the logic in pci_scan_bus for skipping
@@ -56,48 +61,11 @@ struct pci_dev;
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
-/* This is always fine. */
-#define pci_dac_dma_supported(pci_dev, mask) (1)
-
-static inline dma64_addr_t
-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
-{
- return ((dma64_addr_t) page_to_phys(page) +
- (dma64_addr_t) offset);
-}
-
-static inline struct page *
-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return pfn_to_page(dma_addr >> PAGE_SHIFT);
-}
-
-static inline unsigned long
-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return (dma_addr & ~PAGE_MASK);
-}
-
-static inline void
-pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
-}
-
-static inline void
-pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
- flush_write_buffers();
-}
-
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
diff --git a/include/asm-i386/percpu.h b/include/asm-i386/percpu.h
index f54830b5d5ac..a7ebd436f3cc 100644
--- a/include/asm-i386/percpu.h
+++ b/include/asm-i386/percpu.h
@@ -54,6 +54,11 @@ extern unsigned long __per_cpu_offset[];
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ __attribute__((__section__(".data.percpu.shared_aligned"))) \
+ __typeof__(type) per_cpu__##name \
+ ____cacheline_aligned_in_smp
+
/* We can use this directly for local CPU (faster). */
DECLARE_PER_CPU(unsigned long, this_cpu_off);
diff --git a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
index d07b7afc2692..f2fc33ceb9f2 100644
--- a/include/asm-i386/pgalloc.h
+++ b/include/asm-i386/pgalloc.h
@@ -7,7 +7,7 @@
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
#else
-#define paravirt_alloc_pt(pfn) do { } while (0)
+#define paravirt_alloc_pt(mm, pfn) do { } while (0)
#define paravirt_alloc_pd(pfn) do { } while (0)
#define paravirt_alloc_pd(pfn) do { } while (0)
#define paravirt_alloc_pd_clone(pfn, clonepfn, start, count) do { } while (0)
@@ -17,13 +17,13 @@
#define pmd_populate_kernel(mm, pmd, pte) \
do { \
- paravirt_alloc_pt(__pa(pte) >> PAGE_SHIFT); \
+ paravirt_alloc_pt(mm, __pa(pte) >> PAGE_SHIFT); \
set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))); \
} while (0)
#define pmd_populate(mm, pmd, pte) \
do { \
- paravirt_alloc_pt(page_to_pfn(pte)); \
+ paravirt_alloc_pt(mm, page_to_pfn(pte)); \
set_pmd(pmd, __pmd(_PAGE_TABLE + \
((unsigned long long)page_to_pfn(pte) << \
(unsigned long long) PAGE_SHIFT))); \
diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
index a50fd1773de8..84b03cf56a79 100644
--- a/include/asm-i386/pgtable-2level.h
+++ b/include/asm-i386/pgtable-2level.h
@@ -57,14 +57,6 @@ static inline pte_t native_ptep_get_and_clear(pte_t *xp)
#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
/*
- * All present user pages are user-executable:
- */
-static inline int pte_exec(pte_t pte)
-{
- return pte_user(pte);
-}
-
-/*
* All present pages are kernel-executable:
*/
static inline int pte_exec_kernel(pte_t pte)
diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
index eb0f1d7e96a1..948a33414118 100644
--- a/include/asm-i386/pgtable-3level.h
+++ b/include/asm-i386/pgtable-3level.h
@@ -20,26 +20,11 @@
#define pud_present(pud) 1
/*
- * Is the pte executable?
- */
-static inline int pte_x(pte_t pte)
-{
- return !(pte_val(pte) & _PAGE_NX);
-}
-
-/*
- * All present user-pages with !NX bit are user-executable:
- */
-static inline int pte_exec(pte_t pte)
-{
- return pte_user(pte) && pte_x(pte);
-}
-/*
* All present pages with !NX bit are kernel-executable:
*/
static inline int pte_exec_kernel(pte_t pte)
{
- return pte_x(pte);
+ return !(pte_val(pte) & _PAGE_NX);
}
/* Rules for using set_pte: the pte being assigned *must* be
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index 628fa7747d0c..c7fefa6b12fd 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -79,7 +79,7 @@ void paging_init(void);
* area for the same reason. ;)
*/
#define VMALLOC_OFFSET (8*1024*1024)
-#define VMALLOC_START (((unsigned long) high_memory + vmalloc_earlyreserve + \
+#define VMALLOC_START (((unsigned long) high_memory + \
2*VMALLOC_OFFSET-1) & ~(VMALLOC_OFFSET-1))
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
@@ -218,8 +218,6 @@ extern unsigned long pg0[];
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_user(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
-static inline int pte_read(pte_t pte) { return (pte).pte_low & _PAGE_USER; }
static inline int pte_dirty(pte_t pte) { return (pte).pte_low & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return (pte).pte_low & _PAGE_ACCESSED; }
static inline int pte_write(pte_t pte) { return (pte).pte_low & _PAGE_RW; }
@@ -230,13 +228,9 @@ static inline int pte_huge(pte_t pte) { return (pte).pte_low & _PAGE_PSE; }
*/
static inline int pte_file(pte_t pte) { return (pte).pte_low & _PAGE_FILE; }
-static inline pte_t pte_rdprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
-static inline pte_t pte_exprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_USER; return pte; }
static inline pte_t pte_mkclean(pte_t pte) { (pte).pte_low &= ~_PAGE_DIRTY; return pte; }
static inline pte_t pte_mkold(pte_t pte) { (pte).pte_low &= ~_PAGE_ACCESSED; return pte; }
static inline pte_t pte_wrprotect(pte_t pte) { (pte).pte_low &= ~_PAGE_RW; return pte; }
-static inline pte_t pte_mkread(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) { (pte).pte_low |= _PAGE_USER; return pte; }
static inline pte_t pte_mkdirty(pte_t pte) { (pte).pte_low |= _PAGE_DIRTY; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { (pte).pte_low |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { (pte).pte_low |= _PAGE_RW; return pte; }
@@ -295,17 +289,6 @@ static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
__changed; \
})
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define ptep_test_and_clear_dirty(vma, addr, ptep) ({ \
- int __ret = 0; \
- if (pte_dirty(*(ptep))) \
- __ret = test_and_clear_bit(_PAGE_BIT_DIRTY, \
- &(ptep)->pte_low); \
- if (__ret) \
- pte_update((vma)->vm_mm, addr, ptep); \
- __ret; \
-})
-
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define ptep_test_and_clear_young(vma, addr, ptep) ({ \
int __ret = 0; \
@@ -317,27 +300,6 @@ static inline pte_t native_local_ptep_get_and_clear(pte_t *ptep)
__ret; \
})
-/*
- * Rules for using ptep_establish: the pte MUST be a user pte, and
- * must be a present->present transition.
- */
-#define __HAVE_ARCH_PTEP_ESTABLISH
-#define ptep_establish(vma, address, ptep, pteval) \
-do { \
- set_pte_present((vma)->vm_mm, address, ptep, pteval); \
- flush_tlb_page(vma, address); \
-} while (0)
-
-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
-#define ptep_clear_flush_dirty(vma, address, ptep) \
-({ \
- int __dirty; \
- __dirty = ptep_test_and_clear_dirty((vma), (address), (ptep)); \
- if (__dirty) \
- flush_tlb_page(vma, address); \
- __dirty; \
-})
-
#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
#define ptep_clear_flush_young(vma, address, ptep) \
({ \
diff --git a/include/asm-i386/processor-cyrix.h b/include/asm-i386/processor-cyrix.h
new file mode 100644
index 000000000000..97568ada1f97
--- /dev/null
+++ b/include/asm-i386/processor-cyrix.h
@@ -0,0 +1,30 @@
+/*
+ * NSC/Cyrix CPU indexed register access. Must be inlined instead of
+ * macros to ensure correct access ordering
+ * Access order is always 0x22 (=offset), 0x23 (=value)
+ *
+ * When using the old macros a line like
+ * setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x88);
+ * gets expanded to:
+ * do {
+ * outb((CX86_CCR2), 0x22);
+ * outb((({
+ * outb((CX86_CCR2), 0x22);
+ * inb(0x23);
+ * }) | 0x88), 0x23);
+ * } while (0);
+ *
+ * which in fact violates the access order (= 0x22, 0x22, 0x23, 0x23).
+ */
+
+static inline u8 getCx86(u8 reg)
+{
+ outb(reg, 0x22);
+ return inb(0x23);
+}
+
+static inline void setCx86(u8 reg, u8 data)
+{
+ outb(reg, 0x22);
+ outb(data, 0x23);
+}
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 338668bfb0a2..3845fe72383e 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -88,7 +88,6 @@ struct cpuinfo_x86 {
#define X86_VENDOR_UMC 3
#define X86_VENDOR_NEXGEN 4
#define X86_VENDOR_CENTAUR 5
-#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NSC 8
#define X86_VENDOR_NUM 9
@@ -119,6 +118,7 @@ void __init cpu_detect(struct cpuinfo_x86 *c);
extern void identify_boot_cpu(void);
extern void identify_secondary_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *);
+extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c);
extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
extern unsigned short num_cache_leaves;
@@ -168,17 +168,6 @@ static inline void clear_in_cr4 (unsigned long mask)
write_cr4(cr4);
}
-/*
- * NSC/Cyrix CPU indexed register access macros
- */
-
-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
-
-#define setCx86(reg, data) do { \
- outb((reg), 0x22); \
- outb((data), 0x23); \
-} while (0)
-
/* Stop speculative execution */
static inline void sync_core(void)
{
@@ -227,6 +216,10 @@ extern int bootloader_type;
#define HAVE_ARCH_PICK_MMAP_LAYOUT
+extern void hard_disable_TSC(void);
+extern void disable_TSC(void);
+extern void hard_enable_TSC(void);
+
/*
* Size of io_bitmap.
*/
diff --git a/include/asm-i386/required-features.h b/include/asm-i386/required-features.h
index 9db866c1e64c..618feb98f9f5 100644
--- a/include/asm-i386/required-features.h
+++ b/include/asm-i386/required-features.h
@@ -3,32 +3,53 @@
/* Define minimum CPUID feature set for kernel These bits are checked
really early to actually display a visible error message before the
- kernel dies. Only add word 0 bits here
+ kernel dies. Make sure to assign features to the proper mask!
Some requirements that are not in CPUID yet are also in the
- CONFIG_X86_MINIMUM_CPU mode which is checked too.
+ CONFIG_X86_MINIMUM_CPU_FAMILY which is checked too.
The real information is in arch/i386/Kconfig.cpu, this just converts
the CONFIGs into a bitmask */
+#ifndef CONFIG_MATH_EMULATION
+# define NEED_FPU (1<<(X86_FEATURE_FPU & 31))
+#else
+# define NEED_FPU 0
+#endif
+
#ifdef CONFIG_X86_PAE
-#define NEED_PAE (1<<X86_FEATURE_PAE)
+# define NEED_PAE (1<<(X86_FEATURE_PAE & 31))
#else
-#define NEED_PAE 0
+# define NEED_PAE 0
#endif
#ifdef CONFIG_X86_CMOV
-#define NEED_CMOV (1<<X86_FEATURE_CMOV)
+# define NEED_CMOV (1<<(X86_FEATURE_CMOV & 31))
#else
-#define NEED_CMOV 0
+# define NEED_CMOV 0
#endif
-#ifdef CONFIG_X86_CMPXCHG64
-#define NEED_CMPXCHG64 (1<<X86_FEATURE_CX8)
+#ifdef CONFIG_X86_PAE
+# define NEED_CX8 (1<<(X86_FEATURE_CX8 & 31))
#else
-#define NEED_CMPXCHG64 0
+# define NEED_CX8 0
#endif
-#define REQUIRED_MASK1 (NEED_PAE|NEED_CMOV|NEED_CMPXCHG64)
+#define REQUIRED_MASK0 (NEED_FPU|NEED_PAE|NEED_CMOV|NEED_CX8)
+
+#ifdef CONFIG_X86_USE_3DNOW
+# define NEED_3DNOW (1<<(X86_FEATURE_3DNOW & 31))
+#else
+# define NEED_3DNOW 0
+#endif
+
+#define REQUIRED_MASK1 (NEED_3DNOW)
+
+#define REQUIRED_MASK2 0
+#define REQUIRED_MASK3 0
+#define REQUIRED_MASK4 0
+#define REQUIRED_MASK5 0
+#define REQUIRED_MASK6 0
+#define REQUIRED_MASK7 0
#endif
diff --git a/include/asm-i386/resume-trace.h b/include/asm-i386/resume-trace.h
new file mode 100644
index 000000000000..ec9cfd656230
--- /dev/null
+++ b/include/asm-i386/resume-trace.h
@@ -0,0 +1,13 @@
+#define TRACE_RESUME(user) do { \
+ if (pm_trace_enabled) { \
+ void *tracedata; \
+ asm volatile("movl $1f,%0\n" \
+ ".section .tracedata,\"a\"\n" \
+ "1:\t.word %c1\n" \
+ "\t.long %c2\n" \
+ ".previous" \
+ :"=r" (tracedata) \
+ : "i" (__LINE__), "i" (__FILE__)); \
+ generate_resume_trace(tracedata, user); \
+ } \
+} while (0)
diff --git a/include/asm-i386/setup.h b/include/asm-i386/setup.h
index 0e8077cbfdac..7862fe858a9e 100644
--- a/include/asm-i386/setup.h
+++ b/include/asm-i386/setup.h
@@ -26,12 +26,15 @@
#define NEW_CL_POINTER 0x228 /* Relative to real mode data */
#ifndef __ASSEMBLY__
+
+#include <asm/bootparam.h>
+
/*
* This is set up by the setup-routine at boot-time
*/
-extern unsigned char boot_params[PARAM_SIZE];
+extern struct boot_params boot_params;
-#define PARAM (boot_params)
+#define PARAM ((char *)&boot_params)
#define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
#define EXT_MEM_K (*(unsigned short *) (PARAM+2))
#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
@@ -39,8 +42,7 @@ extern unsigned char boot_params[PARAM_SIZE];
#define E820_MAP ((struct e820entry *) (PARAM+E820MAP))
#define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
#define IST_INFO (*(struct ist_info *) (PARAM+0x60))
-#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
-#define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
+#define SYS_DESC_TABLE (*(struct sys_desc_table *)(PARAM+0xa0))
#define EFI_SYSTAB ((efi_system_table_t *) *((unsigned long *)(PARAM+0x1c4)))
#define EFI_MEMDESC_SIZE (*((unsigned long *) (PARAM+0x1c8)))
#define EFI_MEMDESC_VERSION (*((unsigned long *) (PARAM+0x1cc)))
@@ -79,6 +81,10 @@ void __init add_memory_region(unsigned long long start,
extern unsigned long init_pg_tables_end;
+#ifndef CONFIG_PARAVIRT
+#define paravirt_post_allocator_init() do {} while (0)
+#endif
+
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 0c7132787062..1f73bde165b1 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -43,9 +43,12 @@ extern u8 x86_cpu_to_apicid[];
#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu]
+extern void set_cpu_sibling_map(int cpu);
+
#ifdef CONFIG_HOTPLUG_CPU
extern void cpu_exit_clear(void);
extern void cpu_uninit(void);
+extern void remove_siblinginfo(int cpu);
#endif
struct smp_ops
@@ -129,6 +132,8 @@ extern int __cpu_disable(void);
extern void __cpu_die(unsigned int cpu);
extern unsigned int num_processors;
+void __cpuinit smp_store_cpu_info(int id);
+
#endif /* !__ASSEMBLY__ */
#else /* CONFIG_SMP */
diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h
index b9277361954b..a9b64453bdf5 100644
--- a/include/asm-i386/string.h
+++ b/include/asm-i386/string.h
@@ -2,203 +2,35 @@
#define _I386_STRING_H_
#ifdef __KERNEL__
-/*
- * On a 486 or Pentium, we are better off not using the
- * byte string operations. But on a 386 or a PPro the
- * byte string ops are faster than doing it by hand
- * (MUCH faster on a Pentium).
- */
-
-/*
- * This string-include defines all string functions as inline
- * functions. Use gcc. It also assumes ds=es=data space, this should be
- * normal. Most of the string-functions are rather heavily hand-optimized,
- * see especially strsep,strstr,str[c]spn. They should work, but are not
- * very easy to understand. Everything is done entirely within the register
- * set, making the functions fast and clean. String instructions have been
- * used through-out, making for "slightly" unclear code :-)
- *
- * NO Copyright (C) 1991, 1992 Linus Torvalds,
- * consider these trivial functions to be PD.
- */
-/* AK: in fact I bet it would be better to move this stuff all out of line.
- */
+/* Let gcc decide wether to inline or use the out of line functions */
#define __HAVE_ARCH_STRCPY
-static inline char * strcpy(char * dest,const char *src)
-{
-int d0, d1, d2;
-__asm__ __volatile__(
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- : "=&S" (d0), "=&D" (d1), "=&a" (d2)
- :"0" (src),"1" (dest) : "memory");
-return dest;
-}
+extern char *strcpy(char *dest, const char *src);
#define __HAVE_ARCH_STRNCPY
-static inline char * strncpy(char * dest,const char *src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
- "1:\tdecl %2\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "rep\n\t"
- "stosb\n"
- "2:"
- : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
- :"0" (src),"1" (dest),"2" (count) : "memory");
-return dest;
-}
+extern char *strncpy(char *dest, const char *src, size_t count);
#define __HAVE_ARCH_STRCAT
-static inline char * strcat(char * dest,const char * src)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n"
- "1:\tlodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b"
- : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
- : "0" (src), "1" (dest), "2" (0), "3" (0xffffffffu):"memory");
-return dest;
-}
+extern char *strcat(char *dest, const char *src);
#define __HAVE_ARCH_STRNCAT
-static inline char * strncat(char * dest,const char * src,size_t count)
-{
-int d0, d1, d2, d3;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "decl %1\n\t"
- "movl %8,%3\n"
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "stosb\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %2,%2\n\t"
- "stosb"
- : "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
- : "0" (src),"1" (dest),"2" (0),"3" (0xffffffffu), "g" (count)
- : "memory");
-return dest;
-}
+extern char *strncat(char *dest, const char *src, size_t count);
#define __HAVE_ARCH_STRCMP
-static inline int strcmp(const char * cs,const char * ct)
-{
-int d0, d1;
-register int __res;
-__asm__ __volatile__(
- "1:\tlodsb\n\t"
- "scasb\n\t"
- "jne 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "xorl %%eax,%%eax\n\t"
- "jmp 3f\n"
- "2:\tsbbl %%eax,%%eax\n\t"
- "orb $1,%%al\n"
- "3:"
- :"=a" (__res), "=&S" (d0), "=&D" (d1)
- :"1" (cs),"2" (ct)
- :"memory");
-return __res;
-}
+extern int strcmp(const char *cs, const char *ct);
#define __HAVE_ARCH_STRNCMP
-static inline int strncmp(const char * cs,const char * ct,size_t count)
-{
-register int __res;
-int d0, d1, d2;
-__asm__ __volatile__(
- "1:\tdecl %3\n\t"
- "js 2f\n\t"
- "lodsb\n\t"
- "scasb\n\t"
- "jne 3f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n"
- "2:\txorl %%eax,%%eax\n\t"
- "jmp 4f\n"
- "3:\tsbbl %%eax,%%eax\n\t"
- "orb $1,%%al\n"
- "4:"
- :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
- :"1" (cs),"2" (ct),"3" (count)
- :"memory");
-return __res;
-}
+extern int strncmp(const char *cs, const char *ct, size_t count);
#define __HAVE_ARCH_STRCHR
-static inline char * strchr(const char * s, int c)
-{
-int d0;
-register char * __res;
-__asm__ __volatile__(
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "je 2f\n\t"
- "testb %%al,%%al\n\t"
- "jne 1b\n\t"
- "movl $1,%1\n"
- "2:\tmovl %1,%0\n\t"
- "decl %0"
- :"=a" (__res), "=&S" (d0)
- :"1" (s),"0" (c)
- :"memory");
-return __res;
-}
+extern char *strchr(const char *s, int c);
#define __HAVE_ARCH_STRRCHR
-static inline char * strrchr(const char * s, int c)
-{
-int d0, d1;
-register char * __res;
-__asm__ __volatile__(
- "movb %%al,%%ah\n"
- "1:\tlodsb\n\t"
- "cmpb %%ah,%%al\n\t"
- "jne 2f\n\t"
- "leal -1(%%esi),%0\n"
- "2:\ttestb %%al,%%al\n\t"
- "jne 1b"
- :"=g" (__res), "=&S" (d0), "=&a" (d1)
- :"0" (0),"1" (s),"2" (c)
- :"memory");
-return __res;
-}
+extern char *strrchr(const char *s, int c);
#define __HAVE_ARCH_STRLEN
-static inline size_t strlen(const char * s)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "notl %0\n\t"
- "decl %0"
- :"=c" (__res), "=&D" (d0)
- :"1" (s),"a" (0), "0" (0xffffffffu)
- :"memory");
-return __res;
-}
+extern size_t strlen(const char *s);
static __always_inline void * __memcpy(void * to, const void * from, size_t n)
{
@@ -207,9 +39,7 @@ __asm__ __volatile__(
"rep ; movsl\n\t"
"movl %4,%%ecx\n\t"
"andl $3,%%ecx\n\t"
-#if 1 /* want to pay 2 byte penalty for a chance to skip microcoded rep? */
"jz 1f\n\t"
-#endif
"rep ; movsb\n\t"
"1:"
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
@@ -328,23 +158,7 @@ void *memmove(void * dest,const void * src, size_t n);
#define memcmp __builtin_memcmp
#define __HAVE_ARCH_MEMCHR
-static inline void * memchr(const void * cs,int c,size_t count)
-{
-int d0;
-register void * __res;
-if (!count)
- return NULL;
-__asm__ __volatile__(
- "repne\n\t"
- "scasb\n\t"
- "je 1f\n\t"
- "movl $1,%0\n"
- "1:\tdecl %0"
- :"=D" (__res), "=&c" (d0)
- :"a" (c),"0" (cs),"1" (count)
- :"memory");
-return __res;
-}
+extern void *memchr(const void * cs,int c,size_t count);
static inline void * __memset_generic(void * s, char c,size_t count)
{
@@ -386,29 +200,10 @@ return (s);
/* Added by Gertjan van Wingerde to make minix and sysv module work */
#define __HAVE_ARCH_STRNLEN
-static inline size_t strnlen(const char * s, size_t count)
-{
-int d0;
-register int __res;
-__asm__ __volatile__(
- "movl %2,%0\n\t"
- "jmp 2f\n"
- "1:\tcmpb $0,(%0)\n\t"
- "je 3f\n\t"
- "incl %0\n"
- "2:\tdecl %1\n\t"
- "cmpl $-1,%1\n\t"
- "jne 1b\n"
- "3:\tsubl %2,%0"
- :"=a" (__res), "=&d" (d0)
- :"c" (s),"1" (count)
- :"memory");
-return __res;
-}
+extern size_t strnlen(const char * s, size_t count);
/* end of additional stuff */
#define __HAVE_ARCH_STRSTR
-
extern char *strstr(const char *cs, const char *ct);
/*
@@ -474,19 +269,7 @@ __asm__ __volatile__( \
* find the first occurrence of byte 'c', or 1 past the area if none
*/
#define __HAVE_ARCH_MEMSCAN
-static inline void * memscan(void * addr, int c, size_t size)
-{
- if (!size)
- return addr;
- __asm__("repnz; scasb\n\t"
- "jnz 1f\n\t"
- "dec %%edi\n"
- "1:"
- : "=D" (addr), "=c" (size)
- : "0" (addr), "1" (size), "a" (c)
- : "memory");
- return addr;
-}
+extern void *memscan(void * addr, int c, size_t size);
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 94ed3686a5f3..609756c61676 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -310,15 +310,6 @@ void enable_hlt(void);
extern int es7000_plat;
void cpu_idle_wait(void);
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible:
- */
-static inline void sched_cacheflush(void)
-{
- wbinvd();
-}
-
extern unsigned long arch_align_stack(unsigned long sp);
extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index 4cb0f91ae64f..54424e045e01 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -137,6 +137,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_DEBUG 17 /* uses debug registers */
#define TIF_IO_BITMAP 18 /* uses I/O bitmap */
#define TIF_FREEZE 19 /* is freezing for suspend */
+#define TIF_NOTSC 20 /* TSC is not accessible in userland */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
@@ -151,6 +152,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_DEBUG (1<<TIF_DEBUG)
#define _TIF_IO_BITMAP (1<<TIF_IO_BITMAP)
#define _TIF_FREEZE (1<<TIF_FREEZE)
+#define _TIF_NOTSC (1<<TIF_NOTSC)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK \
@@ -160,7 +162,8 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_ALLWORK_MASK (0x0000FFFF & ~_TIF_SECCOMP)
/* flags to check in __switch_to() */
-#define _TIF_WORK_CTXSW (_TIF_DEBUG|_TIF_IO_BITMAP)
+#define _TIF_WORK_CTXSW_NEXT (_TIF_IO_BITMAP | _TIF_NOTSC | _TIF_DEBUG)
+#define _TIF_WORK_CTXSW_PREV (_TIF_IO_BITMAP | _TIF_NOTSC)
/*
* Thread-synchronous status.
diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h
index 153770e25faa..0db7e994fb8b 100644
--- a/include/asm-i386/timer.h
+++ b/include/asm-i386/timer.h
@@ -5,18 +5,46 @@
#define TICK_SIZE (tick_nsec / 1000)
-void setup_pit_timer(void);
unsigned long long native_sched_clock(void);
unsigned long native_calculate_cpu_khz(void);
extern int timer_ack;
extern int no_timer_check;
-extern int no_sync_cmos_clock;
extern int recalibrate_cpu_khz(void);
#ifndef CONFIG_PARAVIRT
-#define get_scheduled_cycles(val) rdtscll(val)
#define calculate_cpu_khz() native_calculate_cpu_khz()
#endif
+/* Accellerators for sched_clock()
+ * convert from cycles(64bits) => nanoseconds (64bits)
+ * basic equation:
+ * ns = cycles / (freq / ns_per_sec)
+ * ns = cycles * (ns_per_sec / freq)
+ * ns = cycles * (10^9 / (cpu_khz * 10^3))
+ * ns = cycles * (10^6 / cpu_khz)
+ *
+ * Then we use scaling math (suggested by george@mvista.com) to get:
+ * ns = cycles * (10^6 * SC / cpu_khz) / SC
+ * ns = cycles * cyc2ns_scale / SC
+ *
+ * And since SC is a constant power of two, we can convert the div
+ * into a shift.
+ *
+ * We can use khz divisor instead of mhz to keep a better percision, since
+ * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
+ * (mathieu.desnoyers@polymtl.ca)
+ *
+ * -johnstul@us.ibm.com "math is hard, lets go shopping!"
+ */
+extern unsigned long cyc2ns_scale __read_mostly;
+
+#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
+
+static inline unsigned long long cycles_2_ns(unsigned long long cyc)
+{
+ return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
+}
+
+
#endif
diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
index fc525c5cd5a9..a50fa6741486 100644
--- a/include/asm-i386/tlbflush.h
+++ b/include/asm-i386/tlbflush.h
@@ -160,7 +160,11 @@ DECLARE_PER_CPU(struct tlb_state, cpu_tlbstate);
native_flush_tlb_others(&mask, mm, va)
#endif
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ flush_tlb_all();
+}
static inline void flush_tlb_pgtables(struct mm_struct *mm,
unsigned long start, unsigned long end)
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index 7fc512d90ea8..19b2dafd0c81 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -67,7 +67,7 @@ static inline int node_to_first_cpu(int node)
return first_cpu(mask);
}
-#define pcibus_to_node(bus) ((long) (bus)->sysdata)
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
#define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus))
/* sched_domains SD_NODE_INIT for NUMAQ machines */
diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h
index 62c091ffcccc..a4d806610b7f 100644
--- a/include/asm-i386/tsc.h
+++ b/include/asm-i386/tsc.h
@@ -63,6 +63,7 @@ extern void tsc_init(void);
extern void mark_tsc_unstable(char *reason);
extern int unsynchronized_tsc(void);
extern void init_tsc_clocksource(void);
+int check_tsc_unstable(void);
/*
* Boot-time check whether the TSCs are synchronized across
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index e2aa5e0d0cc7..d2a4f7be9c2c 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -581,7 +581,7 @@ long __must_check __strncpy_from_user(char *dst,
* If there is a limit on the length of a valid string, you may wish to
* consider using strnlen_user() instead.
*/
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+#define strlen_user(str) strnlen_user(str, LONG_MAX)
long strnlen_user(const char __user *str, long n);
unsigned long __must_check clear_user(void __user *mem, unsigned long len);
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index e84ace1ec8bf..9b15545eb9b5 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -329,10 +329,11 @@
#define __NR_signalfd 321
#define __NR_timerfd 322
#define __NR_eventfd 323
+#define __NR_fallocate 324
#ifdef __KERNEL__
-#define NR_syscalls 324
+#define NR_syscalls 325
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-i386/vmi_time.h b/include/asm-i386/vmi_time.h
index 213930b995cb..478188130328 100644
--- a/include/asm-i386/vmi_time.h
+++ b/include/asm-i386/vmi_time.h
@@ -49,7 +49,7 @@ extern struct vmi_timer_ops {
extern void __init vmi_time_init(void);
extern unsigned long vmi_get_wallclock(void);
extern int vmi_set_wallclock(unsigned long now);
-extern unsigned long long vmi_get_sched_cycles(void);
+extern unsigned long long vmi_sched_clock(void);
extern unsigned long vmi_cpu_khz(void);
#ifdef CONFIG_X86_LOCAL_APIC
diff --git a/include/asm-i386/xen/hypercall.h b/include/asm-i386/xen/hypercall.h
new file mode 100644
index 000000000000..bc0ee7d961ca
--- /dev/null
+++ b/include/asm-i386/xen/hypercall.h
@@ -0,0 +1,413 @@
+/******************************************************************************
+ * hypercall.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A 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 __HYPERCALL_H__
+#define __HYPERCALL_H__
+
+#include <linux/errno.h>
+#include <linux/string.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/sched.h>
+#include <xen/interface/physdev.h>
+
+extern struct { char _entry[32]; } hypercall_page[];
+
+#define _hypercall0(type, name) \
+({ \
+ long __res; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res) \
+ : [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall1(type, name, a1) \
+({ \
+ long __res, __ign1; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1) \
+ : "1" ((long)(a1)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall2(type, name, a1, a2) \
+({ \
+ long __res, __ign1, __ign2; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall3(type, name, a1, a2, a3) \
+({ \
+ long __res, __ign1, __ign2, __ign3; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall4(type, name, a1, a2, a3, a4) \
+({ \
+ long __res, __ign1, __ign2, __ign3, __ign4; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+#define _hypercall5(type, name, a1, a2, a3, a4, a5) \
+({ \
+ long __res, __ign1, __ign2, __ign3, __ign4, __ign5; \
+ asm volatile ( \
+ "call %[call]" \
+ : "=a" (__res), "=b" (__ign1), "=c" (__ign2), \
+ "=d" (__ign3), "=S" (__ign4), "=D" (__ign5) \
+ : "1" ((long)(a1)), "2" ((long)(a2)), \
+ "3" ((long)(a3)), "4" ((long)(a4)), \
+ "5" ((long)(a5)), \
+ [call] "m" (hypercall_page[__HYPERVISOR_##name]) \
+ : "memory" ); \
+ (type)__res; \
+})
+
+static inline int
+HYPERVISOR_set_trap_table(struct trap_info *table)
+{
+ return _hypercall1(int, set_trap_table, table);
+}
+
+static inline int
+HYPERVISOR_mmu_update(struct mmu_update *req, int count,
+ int *success_count, domid_t domid)
+{
+ return _hypercall4(int, mmu_update, req, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_mmuext_op(struct mmuext_op *op, int count,
+ int *success_count, domid_t domid)
+{
+ return _hypercall4(int, mmuext_op, op, count, success_count, domid);
+}
+
+static inline int
+HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
+{
+ return _hypercall2(int, set_gdt, frame_list, entries);
+}
+
+static inline int
+HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
+{
+ return _hypercall2(int, stack_switch, ss, esp);
+}
+
+static inline int
+HYPERVISOR_set_callbacks(unsigned long event_selector,
+ unsigned long event_address,
+ unsigned long failsafe_selector,
+ unsigned long failsafe_address)
+{
+ return _hypercall4(int, set_callbacks,
+ event_selector, event_address,
+ failsafe_selector, failsafe_address);
+}
+
+static inline int
+HYPERVISOR_fpu_taskswitch(int set)
+{
+ return _hypercall1(int, fpu_taskswitch, set);
+}
+
+static inline int
+HYPERVISOR_sched_op(int cmd, unsigned long arg)
+{
+ return _hypercall2(int, sched_op, cmd, arg);
+}
+
+static inline long
+HYPERVISOR_set_timer_op(u64 timeout)
+{
+ unsigned long timeout_hi = (unsigned long)(timeout>>32);
+ unsigned long timeout_lo = (unsigned long)timeout;
+ return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
+}
+
+static inline int
+HYPERVISOR_set_debugreg(int reg, unsigned long value)
+{
+ return _hypercall2(int, set_debugreg, reg, value);
+}
+
+static inline unsigned long
+HYPERVISOR_get_debugreg(int reg)
+{
+ return _hypercall1(unsigned long, get_debugreg, reg);
+}
+
+static inline int
+HYPERVISOR_update_descriptor(u64 ma, u64 desc)
+{
+ return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
+}
+
+static inline int
+HYPERVISOR_memory_op(unsigned int cmd, void *arg)
+{
+ return _hypercall2(int, memory_op, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_multicall(void *call_list, int nr_calls)
+{
+ return _hypercall2(int, multicall, call_list, nr_calls);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping(unsigned long va, pte_t new_val,
+ unsigned long flags)
+{
+ unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+ pte_hi = new_val.pte_high;
+#endif
+ return _hypercall4(int, update_va_mapping, va,
+ new_val.pte_low, pte_hi, flags);
+}
+
+static inline int
+HYPERVISOR_event_channel_op(int cmd, void *arg)
+{
+ int rc = _hypercall2(int, event_channel_op, cmd, arg);
+ if (unlikely(rc == -ENOSYS)) {
+ struct evtchn_op op;
+ op.cmd = cmd;
+ memcpy(&op.u, arg, sizeof(op.u));
+ rc = _hypercall1(int, event_channel_op_compat, &op);
+ memcpy(arg, &op.u, sizeof(op.u));
+ }
+ return rc;
+}
+
+static inline int
+HYPERVISOR_xen_version(int cmd, void *arg)
+{
+ return _hypercall2(int, xen_version, cmd, arg);
+}
+
+static inline int
+HYPERVISOR_console_io(int cmd, int count, char *str)
+{
+ return _hypercall3(int, console_io, cmd, count, str);
+}
+
+static inline int
+HYPERVISOR_physdev_op(int cmd, void *arg)
+{
+ int rc = _hypercall2(int, physdev_op, cmd, arg);
+ if (unlikely(rc == -ENOSYS)) {
+ struct physdev_op op;
+ op.cmd = cmd;
+ memcpy(&op.u, arg, sizeof(op.u));
+ rc = _hypercall1(int, physdev_op_compat, &op);
+ memcpy(arg, &op.u, sizeof(op.u));
+ }
+ return rc;
+}
+
+static inline int
+HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count)
+{
+ return _hypercall3(int, grant_table_op, cmd, uop, count);
+}
+
+static inline int
+HYPERVISOR_update_va_mapping_otherdomain(unsigned long va, pte_t new_val,
+ unsigned long flags, domid_t domid)
+{
+ unsigned long pte_hi = 0;
+#ifdef CONFIG_X86_PAE
+ pte_hi = new_val.pte_high;
+#endif
+ return _hypercall5(int, update_va_mapping_otherdomain, va,
+ new_val.pte_low, pte_hi, flags, domid);
+}
+
+static inline int
+HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type)
+{
+ return _hypercall2(int, vm_assist, cmd, type);
+}
+
+static inline int
+HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args)
+{
+ return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
+}
+
+static inline int
+HYPERVISOR_suspend(unsigned long srec)
+{
+ return _hypercall3(int, sched_op, SCHEDOP_shutdown,
+ SHUTDOWN_suspend, srec);
+}
+
+static inline int
+HYPERVISOR_nmi_op(unsigned long op, unsigned long arg)
+{
+ return _hypercall2(int, nmi_op, op, arg);
+}
+
+static inline void
+MULTI_update_va_mapping(struct multicall_entry *mcl, unsigned long va,
+ pte_t new_val, unsigned long flags)
+{
+ mcl->op = __HYPERVISOR_update_va_mapping;
+ mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = new_val.pte_high;
+#else
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = 0;
+#endif
+ mcl->args[3] = flags;
+}
+
+static inline void
+MULTI_grant_table_op(struct multicall_entry *mcl, unsigned int cmd,
+ void *uop, unsigned int count)
+{
+ mcl->op = __HYPERVISOR_grant_table_op;
+ mcl->args[0] = cmd;
+ mcl->args[1] = (unsigned long)uop;
+ mcl->args[2] = count;
+}
+
+static inline void
+MULTI_update_va_mapping_otherdomain(struct multicall_entry *mcl, unsigned long va,
+ pte_t new_val, unsigned long flags,
+ domid_t domid)
+{
+ mcl->op = __HYPERVISOR_update_va_mapping_otherdomain;
+ mcl->args[0] = va;
+#ifdef CONFIG_X86_PAE
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = new_val.pte_high;
+#else
+ mcl->args[1] = new_val.pte_low;
+ mcl->args[2] = 0;
+#endif
+ mcl->args[3] = flags;
+ mcl->args[4] = domid;
+}
+
+static inline void
+MULTI_update_descriptor(struct multicall_entry *mcl, u64 maddr,
+ struct desc_struct desc)
+{
+ mcl->op = __HYPERVISOR_update_descriptor;
+ mcl->args[0] = maddr;
+ mcl->args[1] = maddr >> 32;
+ mcl->args[2] = desc.a;
+ mcl->args[3] = desc.b;
+}
+
+static inline void
+MULTI_memory_op(struct multicall_entry *mcl, unsigned int cmd, void *arg)
+{
+ mcl->op = __HYPERVISOR_memory_op;
+ mcl->args[0] = cmd;
+ mcl->args[1] = (unsigned long)arg;
+}
+
+static inline void
+MULTI_mmu_update(struct multicall_entry *mcl, struct mmu_update *req,
+ int count, int *success_count, domid_t domid)
+{
+ mcl->op = __HYPERVISOR_mmu_update;
+ mcl->args[0] = (unsigned long)req;
+ mcl->args[1] = count;
+ mcl->args[2] = (unsigned long)success_count;
+ mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_mmuext_op(struct multicall_entry *mcl, struct mmuext_op *op, int count,
+ int *success_count, domid_t domid)
+{
+ mcl->op = __HYPERVISOR_mmuext_op;
+ mcl->args[0] = (unsigned long)op;
+ mcl->args[1] = count;
+ mcl->args[2] = (unsigned long)success_count;
+ mcl->args[3] = domid;
+}
+
+static inline void
+MULTI_set_gdt(struct multicall_entry *mcl, unsigned long *frames, int entries)
+{
+ mcl->op = __HYPERVISOR_set_gdt;
+ mcl->args[0] = (unsigned long)frames;
+ mcl->args[1] = entries;
+}
+
+static inline void
+MULTI_stack_switch(struct multicall_entry *mcl,
+ unsigned long ss, unsigned long esp)
+{
+ mcl->op = __HYPERVISOR_stack_switch;
+ mcl->args[0] = ss;
+ mcl->args[1] = esp;
+}
+
+#endif /* __HYPERCALL_H__ */
diff --git a/include/asm-i386/xen/hypervisor.h b/include/asm-i386/xen/hypervisor.h
new file mode 100644
index 000000000000..8e15dd28c91f
--- /dev/null
+++ b/include/asm-i386/xen/hypervisor.h
@@ -0,0 +1,73 @@
+/******************************************************************************
+ * hypervisor.h
+ *
+ * Linux-specific hypervisor handling.
+ *
+ * Copyright (c) 2002-2004, K A 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 __HYPERVISOR_H__
+#define __HYPERVISOR_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+
+#include <xen/interface/xen.h>
+#include <xen/interface/version.h>
+
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/desc.h>
+#if defined(__i386__)
+# ifdef CONFIG_X86_PAE
+# include <asm-generic/pgtable-nopud.h>
+# else
+# include <asm-generic/pgtable-nopmd.h>
+# endif
+#endif
+#include <asm/xen/hypercall.h>
+
+/* arch/i386/kernel/setup.c */
+extern struct shared_info *HYPERVISOR_shared_info;
+extern struct start_info *xen_start_info;
+#define is_initial_xendomain() (xen_start_info->flags & SIF_INITDOMAIN)
+
+/* arch/i386/mach-xen/evtchn.c */
+/* Force a proper event-channel callback from Xen. */
+extern void force_evtchn_callback(void);
+
+/* Turn jiffies into Xen system time. */
+u64 jiffies_to_st(unsigned long jiffies);
+
+
+#define MULTI_UVMFLAGS_INDEX 3
+#define MULTI_UVMDOMID_INDEX 4
+
+#define is_running_on_xen() (xen_start_info ? 1 : 0)
+
+#endif /* __HYPERVISOR_H__ */
diff --git a/include/asm-i386/xen/interface.h b/include/asm-i386/xen/interface.h
new file mode 100644
index 000000000000..165c3968e138
--- /dev/null
+++ b/include/asm-i386/xen/interface.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ * arch-x86_32.h
+ *
+ * Guest OS interface to x86 32-bit Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_ARCH_X86_32_H__
+#define __XEN_PUBLIC_ARCH_X86_32_H__
+
+#ifdef __XEN__
+#define __DEFINE_GUEST_HANDLE(name, type) \
+ typedef struct { type *p; } __guest_handle_ ## name
+#else
+#define __DEFINE_GUEST_HANDLE(name, type) \
+ typedef type * __guest_handle_ ## name
+#endif
+
+#define DEFINE_GUEST_HANDLE_STRUCT(name) \
+ __DEFINE_GUEST_HANDLE(name, struct name)
+#define DEFINE_GUEST_HANDLE(name) __DEFINE_GUEST_HANDLE(name, name)
+#define GUEST_HANDLE(name) __guest_handle_ ## name
+
+#ifndef __ASSEMBLY__
+/* Guest handles for primitive C types. */
+__DEFINE_GUEST_HANDLE(uchar, unsigned char);
+__DEFINE_GUEST_HANDLE(uint, unsigned int);
+__DEFINE_GUEST_HANDLE(ulong, unsigned long);
+DEFINE_GUEST_HANDLE(char);
+DEFINE_GUEST_HANDLE(int);
+DEFINE_GUEST_HANDLE(long);
+DEFINE_GUEST_HANDLE(void);
+#endif
+
+/*
+ * SEGMENT DESCRIPTOR TABLES
+ */
+/*
+ * A number of GDT entries are reserved by Xen. These are not situated at the
+ * start of the GDT because some stupid OSes export hard-coded selector values
+ * in their ABI. These hard-coded values are always near the start of the GDT,
+ * so Xen places itself out of the way, at the far end of the GDT.
+ */
+#define FIRST_RESERVED_GDT_PAGE 14
+#define FIRST_RESERVED_GDT_BYTE (FIRST_RESERVED_GDT_PAGE * 4096)
+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
+
+/*
+ * These flat segments are in the Xen-private section of every GDT. Since these
+ * are also present in the initial GDT, many OSes will be able to avoid
+ * installing their own GDT.
+ */
+#define FLAT_RING1_CS 0xe019 /* GDT index 259 */
+#define FLAT_RING1_DS 0xe021 /* GDT index 260 */
+#define FLAT_RING1_SS 0xe021 /* GDT index 260 */
+#define FLAT_RING3_CS 0xe02b /* GDT index 261 */
+#define FLAT_RING3_DS 0xe033 /* GDT index 262 */
+#define FLAT_RING3_SS 0xe033 /* GDT index 262 */
+
+#define FLAT_KERNEL_CS FLAT_RING1_CS
+#define FLAT_KERNEL_DS FLAT_RING1_DS
+#define FLAT_KERNEL_SS FLAT_RING1_SS
+#define FLAT_USER_CS FLAT_RING3_CS
+#define FLAT_USER_DS FLAT_RING3_DS
+#define FLAT_USER_SS FLAT_RING3_SS
+
+/* And the trap vector is... */
+#define TRAP_INSTR "int $0x82"
+
+/*
+ * Virtual addresses beyond this are not modifiable by guest OSes. The
+ * machine->physical mapping table starts at this address, read-only.
+ */
+#ifdef CONFIG_X86_PAE
+#define __HYPERVISOR_VIRT_START 0xF5800000
+#else
+#define __HYPERVISOR_VIRT_START 0xFC000000
+#endif
+
+#ifndef HYPERVISOR_VIRT_START
+#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
+#endif
+
+#ifndef machine_to_phys_mapping
+#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
+#endif
+
+/* Maximum number of virtual CPUs in multi-processor guests. */
+#define MAX_VIRT_CPUS 32
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Send an array of these to HYPERVISOR_set_trap_table()
+ */
+#define TI_GET_DPL(_ti) ((_ti)->flags & 3)
+#define TI_GET_IF(_ti) ((_ti)->flags & 4)
+#define TI_SET_DPL(_ti, _dpl) ((_ti)->flags |= (_dpl))
+#define TI_SET_IF(_ti, _if) ((_ti)->flags |= ((!!(_if))<<2))
+
+struct trap_info {
+ uint8_t vector; /* exception vector */
+ uint8_t flags; /* 0-3: privilege level; 4: clear event enable? */
+ uint16_t cs; /* code selector */
+ unsigned long address; /* code offset */
+};
+DEFINE_GUEST_HANDLE_STRUCT(trap_info);
+
+struct cpu_user_regs {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint16_t error_code; /* private */
+ uint16_t entry_vector; /* private */
+ uint32_t eip;
+ uint16_t cs;
+ uint8_t saved_upcall_mask;
+ uint8_t _pad0;
+ uint32_t eflags; /* eflags.IF == !saved_upcall_mask */
+ uint32_t esp;
+ uint16_t ss, _pad1;
+ uint16_t es, _pad2;
+ uint16_t ds, _pad3;
+ uint16_t fs, _pad4;
+ uint16_t gs, _pad5;
+};
+DEFINE_GUEST_HANDLE_STRUCT(cpu_user_regs);
+
+typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
+
+/*
+ * The following is all CPU context. Note that the fpu_ctxt block is filled
+ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
+ */
+struct vcpu_guest_context {
+ /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
+ struct { char x[512]; } fpu_ctxt; /* User-level FPU registers */
+#define VGCF_I387_VALID (1<<0)
+#define VGCF_HVM_GUEST (1<<1)
+#define VGCF_IN_KERNEL (1<<2)
+ unsigned long flags; /* VGCF_* flags */
+ struct cpu_user_regs user_regs; /* User-level CPU registers */
+ struct trap_info trap_ctxt[256]; /* Virtual IDT */
+ unsigned long ldt_base, ldt_ents; /* LDT (linear address, # ents) */
+ unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
+ unsigned long kernel_ss, kernel_sp; /* Virtual TSS (only SS1/SP1) */
+ unsigned long ctrlreg[8]; /* CR0-CR7 (control registers) */
+ unsigned long debugreg[8]; /* DB0-DB7 (debug registers) */
+ unsigned long event_callback_cs; /* CS:EIP of event callback */
+ unsigned long event_callback_eip;
+ unsigned long failsafe_callback_cs; /* CS:EIP of failsafe callback */
+ unsigned long failsafe_callback_eip;
+ unsigned long vm_assist; /* VMASST_TYPE_* bitmap */
+};
+DEFINE_GUEST_HANDLE_STRUCT(vcpu_guest_context);
+
+struct arch_shared_info {
+ unsigned long max_pfn; /* max pfn that appears in table */
+ /* Frame containing list of mfns containing list of mfns containing p2m. */
+ unsigned long pfn_to_mfn_frame_list_list;
+ unsigned long nmi_reason;
+};
+
+struct arch_vcpu_info {
+ unsigned long cr2;
+ unsigned long pad[5]; /* sizeof(struct vcpu_info) == 64 */
+};
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Prefix forces emulation of some non-trapping instructions.
+ * Currently only CPUID.
+ */
+#ifdef __ASSEMBLY__
+#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
+#define XEN_CPUID XEN_EMULATE_PREFIX cpuid
+#else
+#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
+#define XEN_CPUID XEN_EMULATE_PREFIX "cpuid"
+#endif
+
+#endif
diff --git a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h
index 40d01d80610d..0f6e5264ab8f 100644
--- a/include/asm-ia64/compat.h
+++ b/include/asm-ia64/compat.h
@@ -31,8 +31,10 @@ typedef s32 compat_timer_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
+typedef s64 __attribute__((aligned(4))) compat_s64;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
+typedef u64 __attribute__((aligned(4))) compat_u64;
struct compat_timespec {
compat_time_t tv_sec;
diff --git a/include/asm-ia64/fb.h b/include/asm-ia64/fb.h
new file mode 100644
index 000000000000..89a397cee90a
--- /dev/null
+++ b/include/asm-ia64/fb.h
@@ -0,0 +1,23 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <linux/efi.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
index c054d7a9aaa7..efa1b8f7251d 100644
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -90,13 +90,27 @@ enum {
extern __u8 isa_irq_to_vector_map[16];
#define isa_irq_to_vector(x) isa_irq_to_vector_map[(x)]
+struct irq_cfg {
+ ia64_vector vector;
+ cpumask_t domain;
+};
+extern spinlock_t vector_lock;
+extern struct irq_cfg irq_cfg[NR_IRQS];
+#define irq_to_domain(x) irq_cfg[(x)].domain
+DECLARE_PER_CPU(int[IA64_NUM_VECTORS], vector_irq);
+
extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */
+extern int bind_irq_vector(int irq, int vector, cpumask_t domain);
extern int assign_irq_vector (int irq); /* allocate a free vector */
extern void free_irq_vector (int vector);
extern int reserve_irq_vector (int vector);
+extern void __setup_vector_irq(int cpu);
+extern int reassign_irq_vector(int irq, int cpu);
extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
extern void register_percpu_irq (ia64_vector vec, struct irqaction *action);
+extern int check_irq_used (int irq);
+extern void destroy_and_reserve_irq (unsigned int irq);
static inline void ia64_resend_irq(unsigned int vector)
{
@@ -113,7 +127,7 @@ extern irq_desc_t irq_desc[NR_IRQS];
static inline unsigned int
__ia64_local_vector_to_irq (ia64_vector vec)
{
- return (unsigned int) vec;
+ return __get_cpu_var(vector_irq)[vec];
}
#endif
@@ -131,7 +145,7 @@ __ia64_local_vector_to_irq (ia64_vector vec)
static inline ia64_vector
irq_to_vector (int irq)
{
- return (ia64_vector) irq;
+ return irq_cfg[irq].vector;
}
/*
diff --git a/include/asm-ia64/ioctls.h b/include/asm-ia64/ioctls.h
index 31ee521aeb7a..f41b636a0bf6 100644
--- a/include/asm-ia64/ioctls.h
+++ b/include/asm-ia64/ioctls.h
@@ -53,6 +53,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h
index 421cb6b62a7c..b8f712859140 100644
--- a/include/asm-ia64/iosapic.h
+++ b/include/asm-ia64/iosapic.h
@@ -47,19 +47,21 @@
#define IOSAPIC_MASK_SHIFT 16
#define IOSAPIC_MASK (1<<IOSAPIC_MASK_SHIFT)
+#define IOSAPIC_VECTOR_MASK 0xffffff00
+
#ifndef __ASSEMBLY__
#ifdef CONFIG_IOSAPIC
#define NR_IOSAPICS 256
-static inline unsigned int iosapic_read(char __iomem *iosapic, unsigned int reg)
+static inline unsigned int __iosapic_read(char __iomem *iosapic, unsigned int reg)
{
writel(reg, iosapic + IOSAPIC_REG_SELECT);
return readl(iosapic + IOSAPIC_WINDOW);
}
-static inline void iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
+static inline void __iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
{
writel(reg, iosapic + IOSAPIC_REG_SELECT);
writel(val, iosapic + IOSAPIC_WINDOW);
diff --git a/include/asm-ia64/irq.h b/include/asm-ia64/irq.h
index 67221615e317..a66d26827cbb 100644
--- a/include/asm-ia64/irq.h
+++ b/include/asm-ia64/irq.h
@@ -14,8 +14,13 @@
#include <linux/types.h>
#include <linux/cpumask.h>
-#define NR_IRQS 256
-#define NR_IRQ_VECTORS NR_IRQS
+#define NR_VECTORS 256
+
+#if (NR_VECTORS + 32 * NR_CPUS) < 1024
+#define NR_IRQS (NR_VECTORS + 32 * NR_CPUS)
+#else
+#define NR_IRQS 1024
+#endif
static __inline__ int
irq_canonicalize (int irq)
@@ -28,9 +33,6 @@ irq_canonicalize (int irq)
return ((irq == 2) ? 9 : irq);
}
-extern void disable_irq (unsigned int);
-extern void disable_irq_nosync (unsigned int);
-extern void enable_irq (unsigned int);
extern void set_irq_affinity_info (unsigned int irq, int dest, int redir);
bool is_affinity_mask_valid(cpumask_t cpumask);
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index 6382e52ec227..067d9dea68f9 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -82,8 +82,6 @@ struct kprobe_ctlblk {
struct prev_kprobe prev_kprobe[ARCH_PREV_KPROBE_SZ];
};
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
-
#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 1
diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h
index 41098f459684..edd5d01028df 100644
--- a/include/asm-ia64/mca.h
+++ b/include/asm-ia64/mca.h
@@ -48,6 +48,7 @@ enum {
IA64_MCA_RENDEZ_CHECKIN_NOTDONE = 0x0,
IA64_MCA_RENDEZ_CHECKIN_DONE = 0x1,
IA64_MCA_RENDEZ_CHECKIN_INIT = 0x2,
+ IA64_MCA_RENDEZ_CHECKIN_CONCURRENT_MCA = 0x3,
};
/* Information maintained by the MC infrastructure */
diff --git a/include/asm-ia64/page.h b/include/asm-ia64/page.h
index 485759ba9e36..d6345464a2b3 100644
--- a/include/asm-ia64/page.h
+++ b/include/asm-ia64/page.h
@@ -87,12 +87,13 @@ do { \
} while (0)
-#define alloc_zeroed_user_highpage(vma, vaddr) \
-({ \
- struct page *page = alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr); \
- if (page) \
- flush_dcache_page(page); \
- page; \
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+({ \
+ struct page *page = alloc_page_vma( \
+ GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr); \
+ if (page) \
+ flush_dcache_page(page); \
+ page; \
})
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
index 5a5d1c2ce39d..0149097b736d 100644
--- a/include/asm-ia64/pci.h
+++ b/include/asm-ia64/pci.h
@@ -71,14 +71,6 @@ pcibios_penalize_isa_irq (int irq, int active)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
-/* The ia64 platform always supports 64-bit addressing. */
-#define pci_dac_dma_supported(pci_dev, mask) (1)
-#define pci_dac_page_to_dma(dev,pg,off,dir) ((dma_addr_t) page_to_bus(pg) + (off))
-#define pci_dac_dma_to_page(dev,dma_addr) (virt_to_page(bus_to_virt(dma_addr)))
-#define pci_dac_dma_to_offset(dev,dma_addr) offset_in_page(dma_addr)
-#define pci_dac_dma_sync_single_for_cpu(dev,dma_addr,len,dir) do { } while (0)
-#define pci_dac_dma_sync_single_for_device(dev,dma_addr,len,dir) do { mb(); } while (0)
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -104,10 +96,12 @@ extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
#define HAVE_PCI_LEGACY
extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
struct vm_area_struct *vma);
-extern ssize_t pci_read_legacy_io(struct kobject *kobj, char *buf, loff_t off,
- size_t count);
-extern ssize_t pci_write_legacy_io(struct kobject *kobj, char *buf, loff_t off,
- size_t count);
+extern ssize_t pci_read_legacy_io(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count);
+extern ssize_t pci_write_legacy_io(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count);
extern int pci_mmap_legacy_mem(struct kobject *kobj,
struct bin_attribute *attr,
struct vm_area_struct *vma);
@@ -143,10 +137,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
return (pci_domain_nr(bus) != 0);
}
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
extern void pcibios_resource_to_bus(struct pci_dev *dev,
struct pci_bus_region *region, struct resource *res);
diff --git a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
index fbe5cf3ab8dc..43a7aac414e0 100644
--- a/include/asm-ia64/percpu.h
+++ b/include/asm-ia64/percpu.h
@@ -29,6 +29,16 @@
__attribute__((__section__(".data.percpu"))) \
__SMALL_ADDR_AREA __typeof__(type) per_cpu__##name
+#ifdef CONFIG_SMP
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ __attribute__((__section__(".data.percpu.shared_aligned"))) \
+ __SMALL_ADDR_AREA __typeof__(type) per_cpu__##name \
+ ____cacheline_aligned_in_smp
+#else
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ DEFINE_PER_CPU(type, name)
+#endif
+
/*
* Pretty much a literal copy of asm-generic/percpu.h, except that percpu_modcopy() is an
* external routine, to avoid include-hell.
diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h
index 6580f31b3135..de6d01e24dd0 100644
--- a/include/asm-ia64/pgtable.h
+++ b/include/asm-ia64/pgtable.h
@@ -297,8 +297,6 @@ ia64_phys_addr_valid (unsigned long addr)
/*
* The following have defined behavior only work if pte_present() is true.
*/
-#define pte_user(pte) ((pte_val(pte) & _PAGE_PL_MASK) == _PAGE_PL_3)
-#define pte_read(pte) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) < 6)
#define pte_write(pte) ((unsigned) (((pte_val(pte) & _PAGE_AR_MASK) >> _PAGE_AR_SHIFT) - 2) <= 4)
#define pte_exec(pte) ((pte_val(pte) & _PAGE_AR_RX) != 0)
#define pte_dirty(pte) ((pte_val(pte) & _PAGE_D) != 0)
@@ -310,7 +308,6 @@ ia64_phys_addr_valid (unsigned long addr)
*/
#define pte_wrprotect(pte) (__pte(pte_val(pte) & ~_PAGE_AR_RW))
#define pte_mkwrite(pte) (__pte(pte_val(pte) | _PAGE_AR_RW))
-#define pte_mkexec(pte) (__pte(pte_val(pte) | _PAGE_AR_RX))
#define pte_mkold(pte) (__pte(pte_val(pte) & ~_PAGE_A))
#define pte_mkyoung(pte) (__pte(pte_val(pte) | _PAGE_A))
#define pte_mkclean(pte) (__pte(pte_val(pte) & ~_PAGE_D))
@@ -398,22 +395,6 @@ ptep_test_and_clear_young (struct vm_area_struct *vma, unsigned long addr, pte_t
#endif
}
-static inline int
-ptep_test_and_clear_dirty (struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
-#ifdef CONFIG_SMP
- if (!pte_dirty(*ptep))
- return 0;
- return test_and_clear_bit(_PAGE_D_BIT, ptep);
-#else
- pte_t pte = *ptep;
- if (!pte_dirty(pte))
- return 0;
- set_pte_at(vma->vm_mm, addr, ptep, pte_mkclean(pte));
- return 1;
-#endif
-}
-
static inline pte_t
ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
@@ -546,8 +527,10 @@ extern void lazy_mmu_prot_update (pte_t pte);
# define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __safely_writable) \
({ \
int __changed = !pte_same(*(__ptep), __entry); \
- if (__changed) \
- ptep_establish(__vma, __addr, __ptep, __entry); \
+ if (__changed) { \
+ set_pte_at((__vma)->vm_mm, (__addr), __ptep, __entry); \
+ flush_tlb_page(__vma, __addr); \
+ } \
__changed; \
})
#endif
@@ -591,7 +574,6 @@ extern void lazy_mmu_prot_update (pte_t pte);
#endif
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index db81ba406cef..6251c76437d2 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -295,9 +295,9 @@ struct thread_struct {
regs->ar_bspstore = current->thread.rbs_bot; \
regs->ar_fpsr = FPSR_DEFAULT; \
regs->loadrs = 0; \
- regs->r8 = current->mm->dumpable; /* set "don't zap registers" flag */ \
+ regs->r8 = get_dumpable(current->mm); /* set "don't zap registers" flag */ \
regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \
- if (unlikely(!current->mm->dumpable)) { \
+ if (unlikely(!get_dumpable(current->mm))) { \
/* \
* Zap scratch regs to avoid leaking bits between processes with different \
* uid/privileges. \
diff --git a/include/asm-ia64/rwsem.h b/include/asm-ia64/rwsem.h
index 2d1640cc240a..8aba06a7b038 100644
--- a/include/asm-ia64/rwsem.h
+++ b/include/asm-ia64/rwsem.h
@@ -21,6 +21,10 @@
#ifndef _ASM_IA64_RWSEM_H
#define _ASM_IA64_RWSEM_H
+#ifndef _LINUX_RWSEM_H
+#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
+#endif
+
#include <linux/list.h>
#include <linux/spinlock.h>
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index d3566a298fa4..676b31a08c61 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -32,6 +32,7 @@
#define SN_SAL_NO_FAULT_ZONE_VIRTUAL 0x02000010
#define SN_SAL_NO_FAULT_ZONE_PHYSICAL 0x02000011
#define SN_SAL_PRINT_ERROR 0x02000012
+#define SN_SAL_REGISTER_PMI_HANDLER 0x02000014
#define SN_SAL_SET_ERROR_HANDLING_FEATURES 0x0200001a // reentrant
#define SN_SAL_GET_FIT_COMPT 0x0200001b // reentrant
#define SN_SAL_GET_SAPIC_INFO 0x0200001d
@@ -680,6 +681,25 @@ sn_register_nofault_code(u64 start_addr, u64 end_addr, u64 return_addr,
}
/*
+ * Register or unregister a function to handle a PMI received by a CPU.
+ * Before calling the registered handler, SAL sets r1 to the value that
+ * was passed in as the global_pointer.
+ *
+ * If the handler pointer is NULL, then the currently registered handler
+ * will be unregistered.
+ *
+ * Returns 0 on success, or a negative value if an error occurred.
+ */
+static inline int
+sn_register_pmi_handler(u64 handler, u64 global_pointer)
+{
+ struct ia64_sal_retval ret_stuff;
+ ia64_sal_oemcall(&ret_stuff, SN_SAL_REGISTER_PMI_HANDLER, handler,
+ global_pointer, 0, 0, 0, 0, 0);
+ return ret_stuff.status;
+}
+
+/*
* Change or query the coherence domain for this partition. Each cpu-based
* nasid is represented by a bit in an array of 64-bit words:
* 0 = not in this partition's coherency domain
diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h
index 384fbf7f2a0f..91bb8e00066c 100644
--- a/include/asm-ia64/system.h
+++ b/include/asm-ia64/system.h
@@ -259,7 +259,6 @@ extern void ia64_load_extra (struct task_struct *task);
#define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
void cpu_idle_wait(void);
-void sched_cacheflush(void);
#define arch_align_stack(x) (x)
diff --git a/include/asm-ia64/termbits.h b/include/asm-ia64/termbits.h
index 7fae3109ef47..9f162e0089ad 100644
--- a/include/asm-ia64/termbits.h
+++ b/include/asm-ia64/termbits.h
@@ -149,6 +149,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -164,10 +165,12 @@ struct ktermios {
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
diff --git a/include/asm-ia64/termios.h b/include/asm-ia64/termios.h
index 08750c2d3607..689d218c0c28 100644
--- a/include/asm-ia64/termios.h
+++ b/include/asm-ia64/termios.h
@@ -87,8 +87,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
# endif /* __KERNEL__ */
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index 441c9e001776..315f8de950a2 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -292,7 +292,7 @@
#define __NR_sync_file_range 1300
#define __NR_tee 1301
#define __NR_vmsplice 1302
-/* 1303 reserved for move_pages */
+#define __NR_fallocate 1303
#define __NR_getcpu 1304
#define __NR_epoll_pwait 1305
#define __NR_utimensat 1306
diff --git a/include/asm-ia64/ustack.h b/include/asm-ia64/ustack.h
index a349467913ea..504167c35b8b 100644
--- a/include/asm-ia64/ustack.h
+++ b/include/asm-ia64/ustack.h
@@ -11,6 +11,7 @@
/* The absolute hard limit for stack size is 1/2 of the mappable space in the region */
#define MAX_USER_STACK_SIZE (RGN_MAP_LIMIT/2)
#define STACK_TOP (0x6000000000000000UL + RGN_MAP_LIMIT)
+#define STACK_TOP_MAX STACK_TOP
#endif
/* Make a default stack size of 2GiB */
diff --git a/include/asm-m32r/a.out.h b/include/asm-m32r/a.out.h
index 9a4a5d20160a..6a1b5d42f328 100644
--- a/include/asm-m32r/a.out.h
+++ b/include/asm-m32r/a.out.h
@@ -20,6 +20,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
diff --git a/include/asm-m32r/dma-mapping.h b/include/asm-m32r/dma-mapping.h
deleted file mode 100644
index f9b58ebba361..000000000000
--- a/include/asm-m32r/dma-mapping.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_M32R_DMA_MAPPING_H
-#define _ASM_M32R_DMA_MAPPING_H
-
-#include <asm-generic/dma-mapping-broken.h>
-
-#endif /* _ASM_M32R_DMA_MAPPING_H */
diff --git a/include/asm-m32r/fb.h b/include/asm-m32r/fb.h
new file mode 100644
index 000000000000..d92e99cd8c8a
--- /dev/null
+++ b/include/asm-m32r/fb.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-m32r/ioctls.h b/include/asm-m32r/ioctls.h
index d23cfc45738a..b9f54bb5d7cf 100644
--- a/include/asm-m32r/ioctls.h
+++ b/include/asm-m32r/ioctls.h
@@ -47,6 +47,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-m32r/page.h b/include/asm-m32r/page.h
index 6f6ecf7d14a3..04fd183a2c58 100644
--- a/include/asm-m32r/page.h
+++ b/include/asm-m32r/page.h
@@ -15,7 +15,8 @@ extern void copy_page(void *to, void *from);
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/*
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 6604303fc47c..92d7266783fd 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -191,16 +191,6 @@ extern unsigned long empty_zero_page[1024];
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte)
-{
- return pte_val(pte) & _PAGE_READ;
-}
-
-static inline int pte_exec(pte_t pte)
-{
- return pte_val(pte) & _PAGE_EXEC;
-}
-
static inline int pte_dirty(pte_t pte)
{
return pte_val(pte) & _PAGE_DIRTY;
@@ -224,18 +214,6 @@ static inline int pte_file(pte_t pte)
return pte_val(pte) & _PAGE_FILE;
}
-static inline pte_t pte_rdprotect(pte_t pte)
-{
- pte_val(pte) &= ~_PAGE_READ;
- return pte;
-}
-
-static inline pte_t pte_exprotect(pte_t pte)
-{
- pte_val(pte) &= ~_PAGE_EXEC;
- return pte;
-}
-
static inline pte_t pte_mkclean(pte_t pte)
{
pte_val(pte) &= ~_PAGE_DIRTY;
@@ -254,18 +232,6 @@ static inline pte_t pte_wrprotect(pte_t pte)
return pte;
}
-static inline pte_t pte_mkread(pte_t pte)
-{
- pte_val(pte) |= _PAGE_READ;
- return pte;
-}
-
-static inline pte_t pte_mkexec(pte_t pte)
-{
- pte_val(pte) |= _PAGE_EXEC;
- return pte;
-}
-
static inline pte_t pte_mkdirty(pte_t pte)
{
pte_val(pte) |= _PAGE_DIRTY;
@@ -284,11 +250,6 @@ static inline pte_t pte_mkwrite(pte_t pte)
return pte;
}
-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
- return test_and_clear_bit(_PAGE_BIT_DIRTY, ptep);
-}
-
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);
@@ -382,7 +343,6 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep)
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 8ee73d3f316d..2365de5c2955 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -54,16 +54,6 @@
); \
} while(0)
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
/* Interrupt Control */
#if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
#define local_irq_enable() \
diff --git a/include/asm-m32r/termbits.h b/include/asm-m32r/termbits.h
index 6be3b8a39841..bc104008b55b 100644
--- a/include/asm-m32r/termbits.h
+++ b/include/asm-m32r/termbits.h
@@ -140,6 +140,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -155,11 +156,13 @@ struct ktermios {
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /** input baud rate */
#define CTVB 004000000000 /* VisioBraille Terminal flow control */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
diff --git a/include/asm-m32r/termios.h b/include/asm-m32r/termios.h
index 4943dd8db44d..93ce79fd342a 100644
--- a/include/asm-m32r/termios.h
+++ b/include/asm-m32r/termios.h
@@ -81,8 +81,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-m68k/a.out.h b/include/asm-m68k/a.out.h
index eda1662773b8..6fc86a221a94 100644
--- a/include/asm-m68k/a.out.h
+++ b/include/asm-m68k/a.out.h
@@ -20,6 +20,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
diff --git a/include/asm-m68k/atari_SLM.h b/include/asm-m68k/atari_SLM.h
deleted file mode 100644
index 42f4fcdd8bc7..000000000000
--- a/include/asm-m68k/atari_SLM.h
+++ /dev/null
@@ -1,28 +0,0 @@
-
-#ifndef _ATARI_SLM_H
-#define _ATARI_SLM_H
-
-/* Atari SLM laser printer specific ioctls */
-
-#define SLMIOGSTAT 0xa100
-#define SLMIOGPSIZE 0xa101
-#define SLMIOGMFEED 0xa102
-
-#define SLMIORESET 0xa140
-
-#define SLMIOSPSIZE 0xa181
-#define SLMIOSMFEED 0xa182
-
-/* Status returning structure (SLMIOGSTAT) */
-struct SLM_status {
- int stat; /* numeric status code */
- char str[40]; /* status string */
-};
-
-/* Paper size structure (SLMIO[GS]PSIZE) */
-struct SLM_paper_size {
- int width;
- int height;
-};
-
-#endif /* _ATARI_SLM_H */
diff --git a/include/asm-m68k/atari_acsi.h b/include/asm-m68k/atari_acsi.h
deleted file mode 100644
index 10fea68f191a..000000000000
--- a/include/asm-m68k/atari_acsi.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef _ASM_ATARI_ACSI_H
-#define _ASM_ATARI_ACSI_H
-
-/* Functions exported by drivers/block/acsi.c */
-
-void acsi_delay_start( void );
-void acsi_delay_end( long usec );
-int acsi_wait_for_IRQ( unsigned timeout );
-int acsi_wait_for_noIRQ( unsigned timeout );
-int acsicmd_nodma( const char *cmd, int enable);
-int acsi_getstatus( void );
-int acsi_extstatus( char *buffer, int cnt );
-void acsi_end_extstatus( void );
-int acsi_extcmd( unsigned char *buffer, int cnt );
-
-/* The ACSI buffer is guarantueed to reside in ST-RAM and may be used by other
- * drivers that work on the ACSI bus, too. It's data are valid only as long as
- * the ST-DMA is locked. */
-extern char *acsi_buffer;
-extern unsigned long phys_acsi_buffer;
-
-/* Utility macros */
-
-/* Send one data byte over the bus and set mode for next operation
- * with one move.l -- Atari recommends this...
- */
-
-#define DMA_LONG_WRITE(data,mode) \
- do { \
- *((unsigned long *)&dma_wd.fdc_acces_seccount) = \
- ((data)<<16) | (mode); \
- } while(0)
-
-#define ENABLE_IRQ() atari_turnon_irq( IRQ_MFP_ACSI )
-#define DISABLE_IRQ() atari_turnoff_irq( IRQ_MFP_ACSI )
-
-#endif /* _ASM_ATARI_ACSI_H */
diff --git a/include/asm-m68k/fb.h b/include/asm-m68k/fb.h
new file mode 100644
index 000000000000..380b97ae8157
--- /dev/null
+++ b/include/asm-m68k/fb.h
@@ -0,0 +1,34 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+
+#ifdef CONFIG_SUN3
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
+}
+#else
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ if (CPU_IS_020_OR_030)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
+ if (CPU_IS_040_OR_060) {
+ pgprot_val(vma->vm_page_prot) &= _CACHEMASK040;
+ /* Use no-cache mode, serialized */
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE_S;
+ }
+}
+#endif /* CONFIG_SUN3 */
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-m68k/io.h b/include/asm-m68k/io.h
index 5e0fcf41804d..47bb9cf107b7 100644
--- a/include/asm-m68k/io.h
+++ b/include/asm-m68k/io.h
@@ -27,6 +27,7 @@
#include <asm/raw_io.h>
#include <asm/virtconvert.h>
+#include <asm-generic/iomap.h>
#ifdef CONFIG_ATARI
#include <asm/atarihw.h>
@@ -152,6 +153,16 @@ static inline u16 __iomem *isa_itw(unsigned long addr)
default: return NULL; /* avoid warnings, just in case */
}
}
+static inline u32 __iomem *isa_itl(unsigned long addr)
+{
+ switch(ISA_TYPE)
+ {
+#ifdef CONFIG_AMIGA_PCMCIA
+ case AG_ISA: return (u32 __iomem *)AG_ISA_IO_W(addr);
+#endif
+ default: return 0; /* avoid warnings, just in case */
+ }
+}
static inline u8 __iomem *isa_mtb(unsigned long addr)
{
switch(ISA_TYPE)
@@ -188,8 +199,10 @@ static inline u16 __iomem *isa_mtw(unsigned long addr)
#define isa_inb(port) in_8(isa_itb(port))
#define isa_inw(port) (ISA_SEX ? in_be16(isa_itw(port)) : in_le16(isa_itw(port)))
+#define isa_inl(port) (ISA_SEX ? in_be32(isa_itl(port)) : in_le32(isa_itl(port)))
#define isa_outb(val,port) out_8(isa_itb(port),(val))
#define isa_outw(val,port) (ISA_SEX ? out_be16(isa_itw(port),(val)) : out_le16(isa_itw(port),(val)))
+#define isa_outl(val,port) (ISA_SEX ? out_be32(isa_itl(port),(val)) : out_le32(isa_itl(port),(val)))
#define isa_readb(p) in_8(isa_mtb((unsigned long)(p)))
#define isa_readw(p) \
@@ -234,6 +247,15 @@ static inline void isa_delay(void)
#define isa_outsw(port, buf, nr) \
(ISA_SEX ? raw_outsw(isa_itw(port), (u16 *)(buf), (nr)) : \
raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)))
+
+#define isa_insl(port, buf, nr) \
+ (ISA_SEX ? raw_insl(isa_itl(port), (u32 *)(buf), (nr)) : \
+ raw_insw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
+#define isa_outsl(port, buf, nr) \
+ (ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) : \
+ raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
+
#endif /* CONFIG_ISA */
@@ -246,14 +268,16 @@ static inline void isa_delay(void)
#define inw_p isa_inw_p
#define outw isa_outw
#define outw_p isa_outw_p
-#define inl isa_inw
-#define inl_p isa_inw_p
-#define outl isa_outw
-#define outl_p isa_outw_p
+#define inl isa_inl
+#define inl_p isa_inl_p
+#define outl isa_outl
+#define outl_p isa_outl_p
#define insb isa_insb
#define insw isa_insw
+#define insl isa_insl
#define outsb isa_outsb
#define outsw isa_outsw
+#define outsl isa_outsl
#define readb isa_readb
#define readw isa_readw
#define writeb isa_writeb
@@ -262,8 +286,6 @@ static inline void isa_delay(void)
#if defined(CONFIG_PCI)
-#define inl(port) in_le32(port)
-#define outl(val,port) out_le32((port),(val))
#define readl(addr) in_le32(addr)
#define writel(val,addr) out_le32((addr),(val))
@@ -282,6 +304,8 @@ static inline void isa_delay(void)
#define outb(val,port) out_8((port),(val))
#define inw(port) in_le16(port)
#define outw(val,port) out_le16((port),(val))
+#define inl(port) in_le32(port)
+#define outl(val,port) out_le32((port),(val))
#else
/*
@@ -306,20 +330,35 @@ static inline void isa_delay(void)
#endif
#endif /* CONFIG_PCI */
-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI) && defined(CONFIG_HP300)
+#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI)
/*
- * We need to define dummy functions otherwise drivers/serial/8250.c doesn't link
+ * We need to define dummy functions for GENERIC_IOMAP support.
*/
-#define inb(port) 0xff
-#define inb_p(port) 0xff
-#define outb(val,port) do { } while (0)
-#define outb_p(val,port) do { } while (0)
+#define inb(port) 0xff
+#define inb_p(port) 0xff
+#define outb(val,port) ((void)0)
+#define outb_p(val,port) ((void)0)
+#define inw(port) 0xffff
+#define outw(val,port) ((void)0)
+#define inl(port) 0xffffffffUL
+#define outl(val,port) ((void)0)
+
+#define insb(port,buf,nr) ((void)0)
+#define outsb(port,buf,nr) ((void)0)
+#define insw(port,buf,nr) ((void)0)
+#define outsw(port,buf,nr) ((void)0)
+#define insl(port,buf,nr) ((void)0)
+#define outsl(port,buf,nr) ((void)0)
/*
* These should be valid on any ioremap()ed region
*/
#define readb(addr) in_8(addr)
#define writeb(val,addr) out_8((addr),(val))
+#define readw(addr) in_le16(addr)
+#define writew(val,addr) out_le16((addr),(val))
+#endif
+#if !defined(CONFIG_PCI)
#define readl(addr) in_le32(addr)
#define writel(val,addr) out_le32((addr),(val))
#endif
@@ -351,6 +390,18 @@ extern void dma_cache_wback_inv(unsigned long start, unsigned long size);
extern void dma_cache_wback(unsigned long start, unsigned long size);
extern void dma_cache_inv(unsigned long start, unsigned long size);
+static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
+{
+ __builtin_memset((void __force *) addr, val, count);
+}
+static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
+{
+ __builtin_memcpy(dst, (void __force *) src, count);
+}
+static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
+{
+ __builtin_memcpy((void __force *) dst, src, count);
+}
#ifndef CONFIG_SUN3
#define IO_SPACE_LIMIT 0xffff
diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h
index 4901cb105e2f..eb29a5260591 100644
--- a/include/asm-m68k/irq.h
+++ b/include/asm-m68k/irq.h
@@ -59,9 +59,6 @@
#define IRQ_USER 8
extern unsigned int irq_canonicalize(unsigned int irq);
-extern void enable_irq(unsigned int);
-extern void disable_irq(unsigned int);
-#define disable_irq_nosync disable_irq
struct pt_regs;
diff --git a/include/asm-m68k/motorola_pgtable.h b/include/asm-m68k/motorola_pgtable.h
index b5b78c01eb6c..d029b75bcf04 100644
--- a/include/asm-m68k/motorola_pgtable.h
+++ b/include/asm-m68k/motorola_pgtable.h
@@ -164,21 +164,15 @@ static inline void pgd_set(pgd_t *pgdp, pmd_t *pmdp)
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte) { return 1; }
static inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_RONLY); }
-static inline int pte_exec(pte_t pte) { return 1; }
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 pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_RONLY; return pte; }
-static inline pte_t pte_rdprotect(pte_t pte) { return pte; }
-static inline pte_t pte_exprotect(pte_t pte) { return pte; }
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; }
static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) &= ~_PAGE_RONLY; return pte; }
-static inline pte_t pte_mkread(pte_t pte) { return pte; }
-static inline pte_t pte_mkexec(pte_t pte) { return pte; }
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_mknocache(pte_t pte)
diff --git a/include/asm-m68k/pci.h b/include/asm-m68k/pci.h
index 9d2c07abe44f..678cb0b52314 100644
--- a/include/asm-m68k/pci.h
+++ b/include/asm-m68k/pci.h
@@ -54,8 +54,4 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
*/
#define PCI_DMA_BUS_IS_PHYS (1)
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* _ASM_M68K_PCI_H */
diff --git a/include/asm-m68k/raw_io.h b/include/asm-m68k/raw_io.h
index 811ccd25d4a6..91c623f0994c 100644
--- a/include/asm-m68k/raw_io.h
+++ b/include/asm-m68k/raw_io.h
@@ -49,10 +49,16 @@ extern void __iounmap(void *addr, unsigned long size);
#define raw_inb in_8
#define raw_inw in_be16
#define raw_inl in_be32
+#define __raw_readb in_8
+#define __raw_readw in_be16
+#define __raw_readl in_be32
#define raw_outb(val,port) out_8((port),(val))
#define raw_outw(val,port) out_be16((port),(val))
#define raw_outl(val,port) out_be32((port),(val))
+#define __raw_writeb(val,addr) out_8((addr),(val))
+#define __raw_writew(val,addr) out_be16((addr),(val))
+#define __raw_writel(val,addr) out_be32((addr),(val))
static inline void raw_insb(volatile u8 __iomem *port, u8 *buf, unsigned int len)
{
@@ -336,8 +342,6 @@ static inline void raw_outsw_swapw(volatile u16 __iomem *port, const u16 *buf,
: "d0", "a0", "a1", "d6");
}
-#define __raw_writel raw_outl
-
#endif /* __KERNEL__ */
#endif /* _RAW_IO_H */
diff --git a/include/asm-m68k/sun3_pgtable.h b/include/asm-m68k/sun3_pgtable.h
index b9e62c1e7ae3..b766fc261bde 100644
--- a/include/asm-m68k/sun3_pgtable.h
+++ b/include/asm-m68k/sun3_pgtable.h
@@ -165,21 +165,15 @@ static inline void pgd_clear (pgd_t *pgdp) {}
* Undefined behaviour if not...
* [we have the full set here even if they don't change from m68k]
*/
-static inline int pte_read(pte_t pte) { return 1; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & SUN3_PAGE_WRITEABLE; }
-static inline int pte_exec(pte_t pte) { return 1; }
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 pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_WRITEABLE; return pte; }
-static inline pte_t pte_rdprotect(pte_t pte) { return pte; }
-static inline pte_t pte_exprotect(pte_t pte) { return pte; }
static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_MODIFIED; return pte; }
static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~SUN3_PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= SUN3_PAGE_WRITEABLE; return pte; }
-static inline pte_t pte_mkread(pte_t pte) { return pte; }
-static inline pte_t pte_mkexec(pte_t pte) { return pte; }
static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= SUN3_PAGE_MODIFIED; return pte; }
static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= SUN3_PAGE_ACCESSED; return pte; }
static inline pte_t pte_mknocache(pte_t pte) { pte_val(pte) |= SUN3_PAGE_NOCACHE; return pte; }
diff --git a/include/asm-m68knommu/fb.h b/include/asm-m68knommu/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-m68knommu/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-m68knommu/irq.h b/include/asm-m68knommu/irq.h
index 7b8f874f8429..9373c31ac87d 100644
--- a/include/asm-m68knommu/irq.h
+++ b/include/asm-m68knommu/irq.h
@@ -1,7 +1,5 @@
-#ifndef _M68K_IRQ_H_
-#define _M68K_IRQ_H_
-
-#include <asm/ptrace.h>
+#ifndef _M68KNOMMU_IRQ_H_
+#define _M68KNOMMU_IRQ_H_
#ifdef CONFIG_COLDFIRE
/*
@@ -17,75 +15,12 @@
/*
* # of m68k interrupts
*/
-#define SYS_IRQS 8
-#define NR_IRQS (24+SYS_IRQS)
+#define SYS_IRQS 8
+#define NR_IRQS (24 + SYS_IRQS)
#endif /* CONFIG_COLDFIRE */
-/*
- * Interrupt source definitions
- * General interrupt sources are the level 1-7.
- * Adding an interrupt service routine for one of these sources
- * results in the addition of that routine to a chain of routines.
- * Each one is called in succession. Each individual interrupt
- * service routine should determine if the device associated with
- * that routine requires service.
- */
-#define IRQ1 (1) /* level 1 interrupt */
-#define IRQ2 (2) /* level 2 interrupt */
-#define IRQ3 (3) /* level 3 interrupt */
-#define IRQ4 (4) /* level 4 interrupt */
-#define IRQ5 (5) /* level 5 interrupt */
-#define IRQ6 (6) /* level 6 interrupt */
-#define IRQ7 (7) /* level 7 interrupt (non-maskable) */
-
-/*
- * Machine specific interrupt sources.
- *
- * Adding an interrupt service routine for a source with this bit
- * set indicates a special machine specific interrupt source.
- * The machine specific files define these sources.
- *
- * The IRQ_MACHSPEC bit is now gone - the only thing it did was to
- * introduce unnecessary overhead.
- *
- * All interrupt handling is actually machine specific so it is better
- * to use function pointers, as used by the Sparc port, and select the
- * interrupt handling functions when initializing the kernel. This way
- * we save some unnecessary overhead at run-time.
- * 01/11/97 - Jes
- */
-
-extern void (*mach_enable_irq)(unsigned int);
-extern void (*mach_disable_irq)(unsigned int);
-
-/*
- * various flags for request_irq() - the Amiga now uses the standard
- * mechanism like all other architectures - IRQF_DISABLED and
- * IRQF_SHARED are your friends.
- */
-#define IRQ_FLG_LOCK (0x0001) /* handler is not replaceable */
-#define IRQ_FLG_REPLACE (0x0002) /* replace existing handler */
-#define IRQ_FLG_FAST (0x0004)
-#define IRQ_FLG_SLOW (0x0008)
-#define IRQ_FLG_STD (0x8000) /* internally used */
-
-#ifdef CONFIG_M68360
-
-#define CPM_INTERRUPT IRQ4
-
-/* see MC68360 User's Manual, p. 7-377 */
-#define CPM_VECTOR_BASE 0x04 /* 3 MSbits of CPM vector */
-
-#endif /* CONFIG_M68360 */
-
-/*
- * Some drivers want these entry points
- */
-#define enable_irq(x) do { } while (0)
-#define disable_irq(x) do { } while (0)
-#define disable_irq_nosync(x) disable_irq(x)
#define irq_canonicalize(irq) (irq)
-#endif /* _M68K_IRQ_H_ */
+#endif /* _M68KNOMMU_IRQ_H_ */
diff --git a/include/asm-m68knommu/irqnode.h b/include/asm-m68knommu/irqnode.h
deleted file mode 100644
index 6132a9858b52..000000000000
--- a/include/asm-m68knommu/irqnode.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef _M68K_IRQNODE_H_
-#define _M68K_IRQNODE_H_
-
-#include <linux/interrupt.h>
-
-/*
- * This structure is used to chain together the ISRs for a particular
- * interrupt source (if it supports chaining).
- */
-typedef struct irq_node {
- irq_handler_t handler;
- unsigned long flags;
- void *dev_id;
- const char *devname;
- struct irq_node *next;
-} irq_node_t;
-
-/*
- * This structure has only 4 elements for speed reasons
- */
-struct irq_entry {
- irq_handler_t handler;
- unsigned long flags;
- void *dev_id;
- const char *devname;
-};
-
-/* count of spurious interrupts */
-extern volatile unsigned int num_spurious;
-
-/*
- * This function returns a new irq_node_t
- */
-extern irq_node_t *new_irq_node(void);
-
-#endif /* _M68K_IRQNODE_H_ */
diff --git a/include/asm-m68knommu/m68360.h b/include/asm-m68knommu/m68360.h
index dd11b070884b..eb7d39ef2855 100644
--- a/include/asm-m68knommu/m68360.h
+++ b/include/asm-m68knommu/m68360.h
@@ -3,3 +3,11 @@
#include "m68360_quicc.h"
#include "m68360_enet.h"
+#ifdef CONFIG_M68360
+
+#define CPM_INTERRUPT 4
+
+/* see MC68360 User's Manual, p. 7-377 */
+#define CPM_VECTOR_BASE 0x04 /* 3 MSbits of CPM vector */
+
+#endif /* CONFIG_M68360 */
diff --git a/include/asm-m68knommu/page.h b/include/asm-m68knommu/page.h
index 2a1b8bdcb29c..9efa0a9851b1 100644
--- a/include/asm-m68knommu/page.h
+++ b/include/asm-m68knommu/page.h
@@ -22,7 +22,8 @@
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/*
diff --git a/include/asm-m68knommu/pci.h b/include/asm-m68knommu/pci.h
index e04c77e1184d..a13f3cc87451 100644
--- a/include/asm-m68knommu/pci.h
+++ b/include/asm-m68knommu/pci.h
@@ -24,16 +24,6 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
return 1;
}
-/*
- * Not supporting more than 32-bit PCI bus addresses now, but
- * must satisfy references to this function. Change if needed.
- */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* CONFIG_COMEMPCI */
#endif /* M68KNOMMU_PCI_H */
diff --git a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h
index 9dfbbc24aa71..e1e6a1d2333a 100644
--- a/include/asm-m68knommu/pgtable.h
+++ b/include/asm-m68knommu/pgtable.h
@@ -49,7 +49,6 @@ static inline int pte_file(pte_t pte) { return 0; }
* These would be in other places but having them here reduces the diffs.
*/
extern unsigned int kobjsize(const void *objp);
-extern int is_in_rom(unsigned long);
/*
* No page table caches to initialise.
diff --git a/include/asm-m68knommu/traps.h b/include/asm-m68knommu/traps.h
index f2a81317cc10..d0671e5f8e29 100644
--- a/include/asm-m68knommu/traps.h
+++ b/include/asm-m68knommu/traps.h
@@ -16,6 +16,10 @@
typedef void (*e_vector)(void);
extern e_vector vectors[];
+extern void init_vectors(void);
+extern void enable_vector(unsigned int irq);
+extern void disable_vector(unsigned int irq);
+extern void ack_vector(unsigned int irq);
#endif
diff --git a/include/asm-m68knommu/uaccess.h b/include/asm-m68knommu/uaccess.h
index 62b29b10bc6d..9ed9169a8849 100644
--- a/include/asm-m68knommu/uaccess.h
+++ b/include/asm-m68knommu/uaccess.h
@@ -15,12 +15,15 @@
#define access_ok(type,addr,size) _access_ok((unsigned long)(addr),(size))
+/*
+ * It is not enough to just have access_ok check for a real RAM address.
+ * This would disallow the case of code/ro-data running XIP in flash/rom.
+ * Ideally we would check the possible flash ranges too, but that is
+ * currently not so easy.
+ */
static inline int _access_ok(unsigned long addr, unsigned long size)
{
- extern unsigned long memory_start, memory_end;
-
- return (((addr >= memory_start) && (addr+size < memory_end)) ||
- (is_in_rom(addr) && is_in_rom(addr+size)));
+ return 1;
}
/*
diff --git a/include/asm-mips/a.out.h b/include/asm-mips/a.out.h
index ef33c3f13484..1ad60ba186d0 100644
--- a/include/asm-mips/a.out.h
+++ b/include/asm-mips/a.out.h
@@ -40,6 +40,7 @@ struct exec
#ifdef CONFIG_64BIT
#define STACK_TOP (current->thread.mflags & MF_32BIT_ADDR ? TASK_SIZE32 : TASK_SIZE)
#endif
+#define STACK_TOP_MAX TASK_SIZE
#endif
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 1b60624dab7e..7d8003769a44 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -138,7 +138,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
{
unsigned long result;
- smp_mb();
+ smp_llsc_mb();
if (cpu_has_llsc && R10000_LLSC_WAR) {
unsigned long temp;
@@ -181,7 +181,7 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return result;
}
@@ -190,7 +190,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
{
unsigned long result;
- smp_mb();
+ smp_llsc_mb();
if (cpu_has_llsc && R10000_LLSC_WAR) {
unsigned long temp;
@@ -233,7 +233,7 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return result;
}
@@ -250,7 +250,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
{
unsigned long result;
- smp_mb();
+ smp_llsc_mb();
if (cpu_has_llsc && R10000_LLSC_WAR) {
unsigned long temp;
@@ -302,7 +302,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return result;
}
@@ -519,7 +519,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
{
unsigned long result;
- smp_mb();
+ smp_llsc_mb();
if (cpu_has_llsc && R10000_LLSC_WAR) {
unsigned long temp;
@@ -562,7 +562,7 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return result;
}
@@ -571,7 +571,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
{
unsigned long result;
- smp_mb();
+ smp_llsc_mb();
if (cpu_has_llsc && R10000_LLSC_WAR) {
unsigned long temp;
@@ -614,7 +614,7 @@ static __inline__ long atomic64_sub_return(long i, atomic64_t * v)
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return result;
}
@@ -631,7 +631,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
{
unsigned long result;
- smp_mb();
+ smp_llsc_mb();
if (cpu_has_llsc && R10000_LLSC_WAR) {
unsigned long temp;
@@ -683,7 +683,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return result;
}
@@ -791,10 +791,11 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
* atomic*_return operations are serializing but not the non-*_return
* versions.
*/
-#define smp_mb__before_atomic_dec() smp_mb()
-#define smp_mb__after_atomic_dec() smp_mb()
-#define smp_mb__before_atomic_inc() smp_mb()
-#define smp_mb__after_atomic_inc() smp_mb()
+#define smp_mb__before_atomic_dec() smp_llsc_mb()
+#define smp_mb__after_atomic_dec() smp_llsc_mb()
+#define smp_mb__before_atomic_inc() smp_llsc_mb()
+#define smp_mb__after_atomic_inc() smp_llsc_mb()
#include <asm-generic/atomic.h>
+
#endif /* _ASM_ATOMIC_H */
diff --git a/include/asm-mips/barrier.h b/include/asm-mips/barrier.h
index ed82631b0017..9d8cfbb5e796 100644
--- a/include/asm-mips/barrier.h
+++ b/include/asm-mips/barrier.h
@@ -121,6 +121,11 @@
#else
#define __WEAK_ORDERING_MB " \n"
#endif
+#if defined(CONFIG_WEAK_REORDERING_BEYOND_LLSC) && defined(CONFIG_SMP)
+#define __WEAK_LLSC_MB " sync \n"
+#else
+#define __WEAK_LLSC_MB " \n"
+#endif
#define smp_mb() __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
#define smp_rmb() __asm__ __volatile__(__WEAK_ORDERING_MB : : :"memory")
@@ -129,4 +134,8 @@
#define set_mb(var, value) \
do { var = value; smp_mb(); } while (0)
+#define smp_llsc_mb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_rmb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+#define smp_llsc_wmb() __asm__ __volatile__(__WEAK_LLSC_MB : : :"memory")
+
#endif /* __ASM_BARRIER_H */
diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h
index d9e81af53f78..148bc79557f1 100644
--- a/include/asm-mips/bitops.h
+++ b/include/asm-mips/bitops.h
@@ -38,8 +38,8 @@
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
-#define smp_mb__before_clear_bit() smp_mb()
-#define smp_mb__after_clear_bit() smp_mb()
+#define smp_mb__before_clear_bit() smp_llsc_mb()
+#define smp_mb__after_clear_bit() smp_llsc_mb()
/*
* set_bit - Atomically set a bit in memory
@@ -289,7 +289,7 @@ static inline int test_and_set_bit(unsigned long nr,
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return res != 0;
}
@@ -377,7 +377,7 @@ static inline int test_and_clear_bit(unsigned long nr,
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return res != 0;
}
@@ -445,7 +445,7 @@ static inline int test_and_change_bit(unsigned long nr,
raw_local_irq_restore(flags);
}
- smp_mb();
+ smp_llsc_mb();
return res != 0;
}
diff --git a/include/asm-mips/compat.h b/include/asm-mips/compat.h
index 432653d7ae09..568c76cdd900 100644
--- a/include/asm-mips/compat.h
+++ b/include/asm-mips/compat.h
@@ -37,8 +37,10 @@ typedef s32 compat_key_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
+typedef s64 compat_s64;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
+typedef u64 compat_u64;
struct compat_timespec {
compat_time_t tv_sec;
@@ -132,7 +134,8 @@ typedef u32 compat_uptr_t;
static inline void __user *compat_ptr(compat_uptr_t uptr)
{
- return (void __user *)(long)uptr;
+ /* cast to a __user pointer via "unsigned long" makes sparse happy */
+ return (void __user *)(unsigned long)(long)uptr;
}
static inline compat_uptr_t ptr_to_compat(void __user *uptr)
diff --git a/include/asm-mips/dec/serial.h b/include/asm-mips/dec/serial.h
deleted file mode 100644
index acad75890a05..000000000000
--- a/include/asm-mips/dec/serial.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * include/asm-mips/dec/serial.h
- *
- * Definitions common to all DECstation serial devices.
- *
- * Copyright (C) 2004 Maciej W. Rozycki
- *
- * Based on bits extracted from drivers/tc/zs.h for which
- * the following copyrights apply:
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) Harald Koerfgen
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef __ASM_MIPS_DEC_SERIAL_H
-#define __ASM_MIPS_DEC_SERIAL_H
-
-struct dec_serial_hook {
- int (*init_channel)(void *handle);
- void (*init_info)(void *handle);
- void (*rx_char)(unsigned char ch, unsigned char fl);
- int (*poll_rx_char)(void *handle);
- int (*poll_tx_char)(void *handle, unsigned char ch);
- unsigned int cflags;
-};
-
-extern int register_dec_serial_hook(unsigned int channel,
- struct dec_serial_hook *hook);
-extern int unregister_dec_serial_hook(unsigned int channel);
-
-#endif /* __ASM_MIPS_DEC_SERIAL_H */
diff --git a/include/asm-mips/ds1216.h b/include/asm-mips/ds1216.h
deleted file mode 100644
index 1ff8b73f7a6a..000000000000
--- a/include/asm-mips/ds1216.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _DS1216_H
-#define _DS1216_H
-
-extern volatile unsigned char *ds1216_base;
-unsigned long ds1216_get_cmos_time(void);
-int ds1216_set_rtc_mmss(unsigned long nowtime);
-
-#define DS1216_SEC_BYTE 1
-#define DS1216_MIN_BYTE 2
-#define DS1216_HOUR_BYTE 3
-#define DS1216_HOUR_MASK (0x1f)
-#define DS1216_AMPM_MASK (1<<5)
-#define DS1216_1224_MASK (1<<7)
-#define DS1216_DAY_BYTE 4
-#define DS1216_DAY_MASK (0x7)
-#define DS1216_DATE_BYTE 5
-#define DS1216_DATE_MASK (0x3f)
-#define DS1216_MONTH_BYTE 6
-#define DS1216_MONTH_MASK (0x1f)
-#define DS1216_YEAR_BYTE 7
-
-#define DS1216_SEC(buf) (buf[DS1216_SEC_BYTE])
-#define DS1216_MIN(buf) (buf[DS1216_MIN_BYTE])
-#define DS1216_HOUR(buf) (buf[DS1216_HOUR_BYTE] & DS1216_HOUR_MASK)
-#define DS1216_AMPM(buf) (buf[DS1216_HOUR_BYTE] & DS1216_AMPM_MASK)
-#define DS1216_1224(buf) (buf[DS1216_HOUR_BYTE] & DS1216_1224_MASK)
-#define DS1216_DATE(buf) (buf[DS1216_DATE_BYTE] & DS1216_DATE_MASK)
-#define DS1216_MONTH(buf) (buf[DS1216_MONTH_BYTE] & DS1216_MONTH_MASK)
-#define DS1216_YEAR(buf) (buf[DS1216_YEAR_BYTE])
-
-#endif
diff --git a/include/asm-mips/fb.h b/include/asm-mips/fb.h
new file mode 100644
index 000000000000..bd3f68c9ddfc
--- /dev/null
+++ b/include/asm-mips/fb.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h
index 47e5679c2353..b623882bce19 100644
--- a/include/asm-mips/futex.h
+++ b/include/asm-mips/futex.h
@@ -29,7 +29,7 @@
" .set mips3 \n" \
"2: sc $1, %2 \n" \
" beqzl $1, 1b \n" \
- __WEAK_ORDERING_MB \
+ __WEAK_LLSC_MB \
"3: \n" \
" .set pop \n" \
" .set mips0 \n" \
@@ -55,7 +55,7 @@
" .set mips3 \n" \
"2: sc $1, %2 \n" \
" beqz $1, 1b \n" \
- __WEAK_ORDERING_MB \
+ __WEAK_LLSC_MB \
"3: \n" \
" .set pop \n" \
" .set mips0 \n" \
@@ -152,7 +152,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set mips3 \n"
"2: sc $1, %1 \n"
" beqzl $1, 1b \n"
- __WEAK_ORDERING_MB
+ __WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
@@ -179,7 +179,7 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
" .set mips3 \n"
"2: sc $1, %1 \n"
" beqz $1, 1b \n"
- __WEAK_ORDERING_MB
+ __WEAK_LLSC_MB
"3: \n"
" .set pop \n"
" .section .fixup,\"ax\" \n"
diff --git a/include/asm-mips/gfx.h b/include/asm-mips/gfx.h
deleted file mode 100644
index 37235e41a6fd..000000000000
--- a/include/asm-mips/gfx.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * This is the user-visible SGI GFX interface.
- *
- * This must be used verbatim into the GNU libc. It does not include
- * any kernel-only bits on it.
- *
- * miguel@nuclecu.unam.mx
- */
-#ifndef _ASM_GFX_H
-#define _ASM_GFX_H
-
-/* The iocls, yes, they do not make sense, but such is life */
-#define GFX_BASE 100
-#define GFX_GETNUM_BOARDS (GFX_BASE + 1)
-#define GFX_GETBOARD_INFO (GFX_BASE + 2)
-#define GFX_ATTACH_BOARD (GFX_BASE + 3)
-#define GFX_DETACH_BOARD (GFX_BASE + 4)
-#define GFX_IS_MANAGED (GFX_BASE + 5)
-
-#define GFX_MAPALL (GFX_BASE + 10)
-#define GFX_LABEL (GFX_BASE + 11)
-
-#define GFX_INFO_NAME_SIZE 16
-#define GFX_INFO_LABEL_SIZE 16
-
-struct gfx_info {
- char name [GFX_INFO_NAME_SIZE]; /* board name */
- char label [GFX_INFO_LABEL_SIZE]; /* label name */
- unsigned short int xpmax, ypmax; /* screen resolution */
- unsigned int lenght; /* size of a complete gfx_info for this board */
-};
-
-struct gfx_getboardinfo_args {
- unsigned int board; /* board number. starting from zero */
- void *buf; /* pointer to gfx_info */
- unsigned int len; /* buffer size of buf */
-};
-
-struct gfx_attach_board_args {
- unsigned int board; /* board number, starting from zero */
- void *vaddr; /* address where the board registers should be mapped */
-};
-
-#ifdef __KERNEL__
-/* umap.c */
-extern void remove_mapping (struct vm_area_struct *vma, struct task_struct *, unsigned long, unsigned long);
-extern void *vmalloc_uncached (unsigned long size);
-extern int vmap_page_range (struct vm_area_struct *vma, unsigned long from, unsigned long size, unsigned long vaddr);
-#endif
-
-#endif /* _ASM_GFX_H */
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index 12bcc1f9fba9..7ba92890ea13 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -212,7 +212,8 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
*/
if (__IS_LOW512(phys_addr) && __IS_LOW512(last_addr) &&
flags == _CACHE_UNCACHED)
- return (void __iomem *)CKSEG1ADDR(phys_addr);
+ return (void __iomem *)
+ (unsigned long)CKSEG1ADDR(phys_addr);
}
return __ioremap(offset, size, flags);
diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h
index 3ca6a076124d..97102ebc54b1 100644
--- a/include/asm-mips/irq.h
+++ b/include/asm-mips/irq.h
@@ -24,7 +24,7 @@ static inline int irq_canonicalize(int irq)
#define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */
#endif
-#ifdef CONFIG_MIPS_MT_SMTC
+#ifdef CONFIG_MIPS_MT_SMTC_IM_BACKSTOP
/*
* Clear interrupt mask handling "backstop" if irq_hwmask
* entry so indicates. This implies that the ack() or end()
diff --git a/include/asm-mips/mach-cobalt/cpu-feature-overrides.h b/include/asm-mips/mach-cobalt/cpu-feature-overrides.h
index c6dfa59d1986..d38f069d9e95 100644
--- a/include/asm-mips/mach-cobalt/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-cobalt/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2006, 07 Ralf Baechle (ralf@linux-mips.org)
*/
#ifndef __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
#define __ASM_COBALT_CPU_FEATURE_OVERRIDES_H
@@ -46,6 +46,8 @@
#define cpu_has_ic_fills_f_dc 0
#define cpu_icache_snoops_remote_store 0
#define cpu_has_dsp 0
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_has_mips32r1 0
#define cpu_has_mips32r2 0
diff --git a/include/asm-mips/mach-excite/cpu-feature-overrides.h b/include/asm-mips/mach-excite/cpu-feature-overrides.h
index 0d31854222f9..07f4322c235d 100644
--- a/include/asm-mips/mach-excite/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-excite/cpu-feature-overrides.h
@@ -4,6 +4,7 @@
* for more details.
*
* Copyright (C) 2004 Thomas Koeller <thomas.koeller@baslerweb.com>
+ * Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
*/
#ifndef __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_EXCITE_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +28,8 @@
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
#define cpu_icache_snoops_remote_store 0
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_has_nofpuex 0
#define cpu_has_64bits 1
diff --git a/include/asm-mips/mach-ip22/cpu-feature-overrides.h b/include/asm-mips/mach-ip22/cpu-feature-overrides.h
index f7c5dc8a5336..9c8735158da1 100644
--- a/include/asm-mips/mach-ip22/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-ip22/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
*/
#ifndef __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
@@ -30,6 +30,8 @@
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_has_nofpuex 0
#define cpu_has_64bits 1
diff --git a/include/asm-mips/mach-ip27/cpu-feature-overrides.h b/include/asm-mips/mach-ip27/cpu-feature-overrides.h
index a071974b67bb..fe076380c189 100644
--- a/include/asm-mips/mach-ip27/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-ip27/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
*/
#ifndef __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
@@ -27,6 +27,8 @@
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
#define cpu_icache_snoops_remote_store 1
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_has_nofpuex 0
#define cpu_has_64bits 1
diff --git a/include/asm-mips/mach-ip32/cpu-feature-overrides.h b/include/asm-mips/mach-ip32/cpu-feature-overrides.h
index 2a3de092bf13..6782fccebe8d 100644
--- a/include/asm-mips/mach-ip32/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-ip32/cpu-feature-overrides.h
@@ -4,7 +4,7 @@
* for more details.
*
* Copyright (C) 2005 Ilya A. Volynets-Evenbakh
- * Copyright (C) 2005 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2005, 07 Ralf Baechle (ralf@linux-mips.org)
*/
#ifndef __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_IP32_CPU_FEATURE_OVERRIDES_H
@@ -38,6 +38,8 @@
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
#define cpu_has_4k_cache 1
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_has_mips32r1 0
diff --git a/include/asm-mips/mach-qemu/cpu-feature-overrides.h b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
index 529445dacedb..d2daaed235d5 100644
--- a/include/asm-mips/mach-qemu/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003 Ralf Baechle
+ * Copyright (C) 2003, 07 Ralf Baechle
*/
#ifndef __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_QEMU_CPU_FEATURE_OVERRIDES_H
@@ -24,6 +24,7 @@
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
+#define cpu_has_mipsmt 0
#define cpu_has_nofpuex 0
#define cpu_has_64bits 0
diff --git a/include/asm-mips/mach-rm/cpu-feature-overrides.h b/include/asm-mips/mach-rm/cpu-feature-overrides.h
index 7e07283140a3..ccf543363537 100644
--- a/include/asm-mips/mach-rm/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-rm/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
*
* SNI RM200 C apparently was only shipped with R4600 V2.0 and R5000 processors.
*/
@@ -32,6 +32,8 @@
#define cpu_has_dsp 0
#define cpu_has_nofpuex 0
#define cpu_has_64bits 1
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_has_mips32r1 0
#define cpu_has_mips32r2 0
diff --git a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h b/include/asm-mips/mach-sibyte/cpu-feature-overrides.h
index a25968f277a2..63d5bf649af1 100644
--- a/include/asm-mips/mach-sibyte/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-sibyte/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
*/
#ifndef __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_SIBYTE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
#define cpu_has_dc_aliases 0
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_icache_snoops_remote_store 0
#define cpu_has_nofpuex 0
diff --git a/include/asm-mips/mach-tx49xx/ioremap.h b/include/asm-mips/mach-tx49xx/ioremap.h
index 88cf546719b8..1e7beae72229 100644
--- a/include/asm-mips/mach-tx49xx/ioremap.h
+++ b/include/asm-mips/mach-tx49xx/ioremap.h
@@ -36,7 +36,8 @@ static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size,
static inline int plat_iounmap(const volatile void __iomem *addr)
{
- return (unsigned long)addr >= (unsigned long)(int)TXX9_DIRECTMAP_BASE;
+ return (unsigned long)addr >=
+ (unsigned long)(int)(TXX9_DIRECTMAP_BASE & 0xffffffff);
}
#endif /* __ASM_MACH_TX49XX_IOREMAP_H */
diff --git a/include/asm-mips/mach-yosemite/cpu-feature-overrides.h b/include/asm-mips/mach-yosemite/cpu-feature-overrides.h
index 42cebb7ce7a6..470e5e9e10d6 100644
--- a/include/asm-mips/mach-yosemite/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-yosemite/cpu-feature-overrides.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2003, 04, 07 Ralf Baechle (ralf@linux-mips.org)
*/
#ifndef __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
#define __ASM_MACH_YOSEMITE_CPU_FEATURE_OVERRIDES_H
@@ -26,6 +26,8 @@
#define cpu_has_dc_aliases 0
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
#define cpu_icache_snoops_remote_store 0
#define cpu_has_nofpuex 0
diff --git a/include/asm-mips/mipsregs.h b/include/asm-mips/mipsregs.h
index 706b3691f57e..18f47f1e8cd5 100644
--- a/include/asm-mips/mipsregs.h
+++ b/include/asm-mips/mipsregs.h
@@ -707,10 +707,10 @@ do { \
*/
#define __read_64bit_c0_split(source, sel) \
({ \
- unsigned long long val; \
- unsigned long flags; \
+ unsigned long long __val; \
+ unsigned long __flags; \
\
- local_irq_save(flags); \
+ local_irq_save(__flags); \
if (sel == 0) \
__asm__ __volatile__( \
".set\tmips64\n\t" \
@@ -719,7 +719,7 @@ do { \
"dsrl\t%M0, %M0, 32\n\t" \
"dsrl\t%L0, %L0, 32\n\t" \
".set\tmips0" \
- : "=r" (val)); \
+ : "=r" (__val)); \
else \
__asm__ __volatile__( \
".set\tmips64\n\t" \
@@ -728,17 +728,17 @@ do { \
"dsrl\t%M0, %M0, 32\n\t" \
"dsrl\t%L0, %L0, 32\n\t" \
".set\tmips0" \
- : "=r" (val)); \
- local_irq_restore(flags); \
+ : "=r" (__val)); \
+ local_irq_restore(__flags); \
\
- val; \
+ __val; \
})
#define __write_64bit_c0_split(source, sel, val) \
do { \
- unsigned long flags; \
+ unsigned long __flags; \
\
- local_irq_save(flags); \
+ local_irq_save(__flags); \
if (sel == 0) \
__asm__ __volatile__( \
".set\tmips64\n\t" \
@@ -759,7 +759,7 @@ do { \
"dmtc0\t%L0, " #source ", " #sel "\n\t" \
".set\tmips0" \
: : "r" (val)); \
- local_irq_restore(flags); \
+ local_irq_restore(__flags); \
} while (0)
#define read_c0_index() __read_32bit_c0_register($0, 0)
diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h
index a59d54749eef..4fcc185cb2d1 100644
--- a/include/asm-mips/pci.h
+++ b/include/asm-mips/pci.h
@@ -121,20 +121,6 @@ extern unsigned int PCI_DMA_BUS_IS_PHYS;
#endif /* CONFIG_DMA_NEED_PCI_MAP_STATE */
-/* This is always fine. */
-#define pci_dac_dma_supported(pci_dev, mask) (1)
-
-extern dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev,
- struct page *page, unsigned long offset, int direction);
-extern struct page *pci_dac_dma_to_page(struct pci_dev *pdev,
- dma64_addr_t dma_addr);
-extern unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev,
- dma64_addr_t dma_addr);
-extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
- dma64_addr_t dma_addr, size_t len, int direction);
-extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
- dma64_addr_t dma_addr, size_t len, int direction);
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -181,10 +167,6 @@ static inline int pci_proc_domain(struct pci_bus *bus)
/* implement the pci_ DMA API in terms of the generic device dma_ one */
#include <asm-generic/pci-dma-compat.h>
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
/* Do platform specific device initialization at pci_enable_device() time */
extern int pcibios_plat_dev_init(struct pci_dev *dev);
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 27d77d981937..2e2d70d13ff6 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -178,9 +178,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_user(pte_t pte) { BUG(); return 0; }
#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1)
-static inline int pte_read(pte_t pte) { return pte.pte_low & _PAGE_READ; }
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; }
@@ -193,13 +191,6 @@ static inline pte_t pte_wrprotect(pte_t pte)
return pte;
}
-static inline pte_t pte_rdprotect(pte_t pte)
-{
- pte.pte_low &= ~(_PAGE_READ | _PAGE_SILENT_READ);
- pte.pte_high &= ~_PAGE_SILENT_READ;
- return pte;
-}
-
static inline pte_t pte_mkclean(pte_t pte)
{
pte.pte_low &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE);
@@ -224,16 +215,6 @@ static inline pte_t pte_mkwrite(pte_t pte)
return pte;
}
-static inline pte_t pte_mkread(pte_t pte)
-{
- pte.pte_low |= _PAGE_READ;
- if (pte.pte_low & _PAGE_ACCESSED) {
- pte.pte_low |= _PAGE_SILENT_READ;
- pte.pte_high |= _PAGE_SILENT_READ;
- }
- return pte;
-}
-
static inline pte_t pte_mkdirty(pte_t pte)
{
pte.pte_low |= _PAGE_MODIFIED;
@@ -253,7 +234,6 @@ static inline pte_t pte_mkyoung(pte_t pte)
return pte;
}
#else
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
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_MODIFIED; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
@@ -265,12 +245,6 @@ static inline pte_t pte_wrprotect(pte_t pte)
return pte;
}
-static inline pte_t pte_rdprotect(pte_t pte)
-{
- pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ);
- return pte;
-}
-
static inline pte_t pte_mkclean(pte_t pte)
{
pte_val(pte) &= ~(_PAGE_MODIFIED|_PAGE_SILENT_WRITE);
@@ -291,14 +265,6 @@ static inline pte_t pte_mkwrite(pte_t pte)
return pte;
}
-static inline pte_t pte_mkread(pte_t pte)
-{
- pte_val(pte) |= _PAGE_READ;
- if (pte_val(pte) & _PAGE_ACCESSED)
- pte_val(pte) |= _PAGE_SILENT_READ;
- return pte;
-}
-
static inline pte_t pte_mkdirty(pte_t pte)
{
pte_val(pte) |= _PAGE_MODIFIED;
diff --git a/include/asm-mips/rtc.h b/include/asm-mips/rtc.h
deleted file mode 100644
index 82ad401c7dca..000000000000
--- a/include/asm-mips/rtc.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * include/asm-mips/rtc.h
- *
- * (Really an interface for drivers/char/genrtc.c)
- *
- * Copyright (C) 2004 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * Please read the COPYING file for all license details.
- */
-
-#ifndef _MIPS_RTC_H
-#define _MIPS_RTC_H
-
-#ifdef __KERNEL__
-
-#include <linux/rtc.h>
-#include <asm/time.h>
-
-#define RTC_PIE 0x40 /* periodic interrupt enable */
-#define RTC_AIE 0x20 /* alarm interrupt enable */
-#define RTC_UIE 0x10 /* update-finished interrupt enable */
-
-/* some dummy definitions */
-#define RTC_BATT_BAD 0x100 /* battery bad */
-#define RTC_SQWE 0x08 /* enable square-wave output */
-#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
-#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
-#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
-
-static inline unsigned int get_rtc_time(struct rtc_time *time)
-{
- unsigned long nowtime;
-
- nowtime = rtc_mips_get_time();
- to_tm(nowtime, time);
- time->tm_year -= 1900;
-
- return RTC_24H;
-}
-
-static inline int set_rtc_time(struct rtc_time *time)
-{
- unsigned long nowtime;
- int ret;
-
- nowtime = mktime(time->tm_year+1900, time->tm_mon+1,
- time->tm_mday, time->tm_hour, time->tm_min,
- time->tm_sec);
- ret = rtc_mips_set_time(nowtime);
-
- return ret;
-}
-
-static inline unsigned int get_rtc_ss(void)
-{
- struct rtc_time h;
-
- get_rtc_time(&h);
- return h.tm_sec;
-}
-
-static inline int get_rtc_pll(struct rtc_pll_info *pll)
-{
- return -EINVAL;
-}
-
-static inline int set_rtc_pll(struct rtc_pll_info *pll)
-{
- return -EINVAL;
-}
-#endif
-#endif
diff --git a/include/asm-mips/sibyte/bcm1480_regs.h b/include/asm-mips/sibyte/bcm1480_regs.h
index bda391d3af85..2738c1366f66 100644
--- a/include/asm-mips/sibyte/bcm1480_regs.h
+++ b/include/asm-mips/sibyte/bcm1480_regs.h
@@ -220,17 +220,25 @@
#define A_BCM1480_DUART(chan) ((((chan)&2) == 0)? A_BCM1480_DUART0 : A_BCM1480_DUART1)
#define BCM1480_DUART_CHANREG_SPACING 0x100
-#define A_BCM1480_DUART_CHANREG(chan,reg) (A_BCM1480_DUART(chan) \
- + BCM1480_DUART_CHANREG_SPACING*((chan)&1) \
- + (reg))
-#define R_BCM1480_DUART_CHANREG(chan,reg) (BCM1480_DUART_CHANREG_SPACING*((chan)&1) + (reg))
-
-#define R_BCM1480_DUART_IMRREG(chan) (R_DUART_IMR_A + ((chan)&1)*DUART_IMRISR_SPACING)
-#define R_BCM1480_DUART_ISRREG(chan) (R_DUART_ISR_A + ((chan)&1)*DUART_IMRISR_SPACING)
-
-#define A_BCM1480_DUART_IMRREG(chan) (A_BCM1480_DUART(chan) + R_BCM1480_DUART_IMRREG(chan))
-#define A_BCM1480_DUART_ISRREG(chan) (A_BCM1480_DUART(chan) + R_BCM1480_DUART_ISRREG(chan))
-#define A_BCM1480_DUART_IN_PORT(chan) (A_BCM1480_DUART(chan) + R_DUART_INP_ORT)
+#define A_BCM1480_DUART_CHANREG(chan, reg) \
+ (A_BCM1480_DUART(chan) + \
+ BCM1480_DUART_CHANREG_SPACING * (((chan) & 1) + 1) + (reg))
+#define A_BCM1480_DUART_CTRLREG(chan, reg) \
+ (A_BCM1480_DUART(chan) + \
+ BCM1480_DUART_CHANREG_SPACING * 3 + (reg))
+
+#define R_BCM1480_DUART_IMRREG(chan) \
+ (R_DUART_IMR_A + ((chan) & 1) * DUART_IMRISR_SPACING)
+#define R_BCM1480_DUART_ISRREG(chan) \
+ (R_DUART_ISR_A + ((chan) & 1) * DUART_IMRISR_SPACING)
+
+#define A_BCM1480_DUART_IMRREG(chan) \
+ (A_BCM1480_DUART_CTRLREG((chan), R_BCM1480_DUART_IMRREG(chan)))
+#define A_BCM1480_DUART_ISRREG(chan) \
+ (A_BCM1480_DUART_CTRLREG((chan), R_BCM1480_DUART_ISRREG(chan)))
+
+#define A_BCM1480_DUART_IN_PORT(chan) \
+ (A_BCM1480_DUART_CTRLREG((chan), R_DUART_IN_PORT))
/*
* These constants are the absolute addresses.
diff --git a/include/asm-mips/sibyte/sb1250_regs.h b/include/asm-mips/sibyte/sb1250_regs.h
index da7c188993c9..220b7e94f1bf 100644
--- a/include/asm-mips/sibyte/sb1250_regs.h
+++ b/include/asm-mips/sibyte/sb1250_regs.h
@@ -272,59 +272,69 @@
********************************************************************* */
-#if SIBYTE_HDR_FEATURE_1250_112x /* This MC only on 1250 & 112x */
+#if SIBYTE_HDR_FEATURE_1250_112x /* This MC only on 1250 & 112x */
#define R_DUART_NUM_PORTS 2
#define A_DUART 0x0010060000
#define DUART_CHANREG_SPACING 0x100
-#define A_DUART_CHANREG(chan,reg) (A_DUART + DUART_CHANREG_SPACING*(chan) + (reg))
-#define R_DUART_CHANREG(chan,reg) (DUART_CHANREG_SPACING*(chan) + (reg))
+
+#define A_DUART_CHANREG(chan, reg) \
+ (A_DUART + DUART_CHANREG_SPACING * ((chan) + 1) + (reg))
#endif /* 1250 & 112x */
-#define R_DUART_MODE_REG_1 0x100
-#define R_DUART_MODE_REG_2 0x110
-#define R_DUART_STATUS 0x120
-#define R_DUART_CLK_SEL 0x130
-#define R_DUART_CMD 0x150
-#define R_DUART_RX_HOLD 0x160
-#define R_DUART_TX_HOLD 0x170
+#define R_DUART_MODE_REG_1 0x000
+#define R_DUART_MODE_REG_2 0x010
+#define R_DUART_STATUS 0x020
+#define R_DUART_CLK_SEL 0x030
+#define R_DUART_CMD 0x050
+#define R_DUART_RX_HOLD 0x060
+#define R_DUART_TX_HOLD 0x070
#if SIBYTE_HDR_FEATURE(1250, PASS2) || SIBYTE_HDR_FEATURE(112x, PASS1) || SIBYTE_HDR_FEATURE_CHIP(1480)
-#define R_DUART_FULL_CTL 0x140
-#define R_DUART_OPCR_X 0x180
-#define R_DUART_AUXCTL_X 0x190
-#endif /* 1250 PASS2 || 112x PASS1 || 1480*/
+#define R_DUART_FULL_CTL 0x040
+#define R_DUART_OPCR_X 0x080
+#define R_DUART_AUXCTL_X 0x090
+#endif /* 1250 PASS2 || 112x PASS1 || 1480 */
/*
* The IMR and ISR can't be addressed with A_DUART_CHANREG,
- * so use this macro instead.
+ * so use these macros instead.
*/
-#define R_DUART_AUX_CTRL 0x310
-#define R_DUART_ISR_A 0x320
-#define R_DUART_IMR_A 0x330
-#define R_DUART_ISR_B 0x340
-#define R_DUART_IMR_B 0x350
-#define R_DUART_OUT_PORT 0x360
-#define R_DUART_OPCR 0x370
-#define R_DUART_IN_PORT 0x380
+#if SIBYTE_HDR_FEATURE_1250_112x /* This MC only on 1250 & 112x */
+#define DUART_IMRISR_SPACING 0x20
+#define DUART_INCHNG_SPACING 0x10
-#define R_DUART_SET_OPR 0x3B0
-#define R_DUART_CLEAR_OPR 0x3C0
+#define A_DUART_CTRLREG(reg) \
+ (A_DUART + DUART_CHANREG_SPACING * 3 + (reg))
-#define DUART_IMRISR_SPACING 0x20
+#define R_DUART_IMRREG(chan) \
+ (R_DUART_IMR_A + (chan) * DUART_IMRISR_SPACING)
+#define R_DUART_ISRREG(chan) \
+ (R_DUART_ISR_A + (chan) * DUART_IMRISR_SPACING)
+#define R_DUART_INCHREG(chan) \
+ (R_DUART_IN_CHNG_A + (chan) * DUART_INCHNG_SPACING)
-#if SIBYTE_HDR_FEATURE_1250_112x /* This MC only on 1250 & 112x */
-#define R_DUART_IMRREG(chan) (R_DUART_IMR_A + (chan)*DUART_IMRISR_SPACING)
-#define R_DUART_ISRREG(chan) (R_DUART_ISR_A + (chan)*DUART_IMRISR_SPACING)
-
-#define A_DUART_IMRREG(chan) (A_DUART + R_DUART_IMRREG(chan))
-#define A_DUART_ISRREG(chan) (A_DUART + R_DUART_ISRREG(chan))
+#define A_DUART_IMRREG(chan) A_DUART_CTRLREG(R_DUART_IMRREG(chan))
+#define A_DUART_ISRREG(chan) A_DUART_CTRLREG(R_DUART_ISRREG(chan))
+#define A_DUART_INCHREG(chan) A_DUART_CTRLREG(R_DUART_INCHREG(chan))
#endif /* 1250 & 112x */
-
+#define R_DUART_AUX_CTRL 0x010
+#define R_DUART_ISR_A 0x020
+#define R_DUART_IMR_A 0x030
+#define R_DUART_ISR_B 0x040
+#define R_DUART_IMR_B 0x050
+#define R_DUART_OUT_PORT 0x060
+#define R_DUART_OPCR 0x070
+#define R_DUART_IN_PORT 0x080
+
+#define R_DUART_SET_OPR 0x0B0
+#define R_DUART_CLEAR_OPR 0x0C0
+#define R_DUART_IN_CHNG_A 0x0D0
+#define R_DUART_IN_CHNG_B 0x0E0
/*
diff --git a/include/asm-mips/sibyte/sb1250_uart.h b/include/asm-mips/sibyte/sb1250_uart.h
index e87045e62bf0..cf74fedcbef1 100644
--- a/include/asm-mips/sibyte/sb1250_uart.h
+++ b/include/asm-mips/sibyte/sb1250_uart.h
@@ -75,7 +75,8 @@
#define V_DUART_PARITY_MODE_ADD_FIXED V_DUART_PARITY_MODE(K_DUART_PARITY_MODE_ADD_FIXED)
#define V_DUART_PARITY_MODE_NONE V_DUART_PARITY_MODE(K_DUART_PARITY_MODE_NONE)
-#define M_DUART_ERR_MODE _SB_MAKEMASK1(5) /* must be zero */
+#define M_DUART_TX_IRQ_SEL_TXRDY 0
+#define M_DUART_TX_IRQ_SEL_TXEMPT _SB_MAKEMASK1(5)
#define M_DUART_RX_IRQ_SEL_RXRDY 0
#define M_DUART_RX_IRQ_SEL_RXFULL _SB_MAKEMASK1(6)
@@ -246,10 +247,13 @@
#define M_DUART_ISR_BRK_A _SB_MAKEMASK1(2)
#define M_DUART_ISR_IN_A _SB_MAKEMASK1(3)
+#define M_DUART_ISR_ALL_A _SB_MAKEMASK(4,0)
+
#define M_DUART_ISR_TX_B _SB_MAKEMASK1(4)
#define M_DUART_ISR_RX_B _SB_MAKEMASK1(5)
#define M_DUART_ISR_BRK_B _SB_MAKEMASK1(6)
#define M_DUART_ISR_IN_B _SB_MAKEMASK1(7)
+#define M_DUART_ISR_ALL_B _SB_MAKEMASK(4,4)
/*
* DUART Channel A Interrupt Status Register (Table 10-17)
@@ -262,6 +266,7 @@
#define M_DUART_ISR_RX _SB_MAKEMASK1(1)
#define M_DUART_ISR_BRK _SB_MAKEMASK1(2)
#define M_DUART_ISR_IN _SB_MAKEMASK1(3)
+#define M_DUART_ISR_ALL _SB_MAKEMASK(4,0)
#define M_DUART_ISR_RESERVED _SB_MAKEMASK(4,4)
/*
diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
index 35e431cd796b..bb897016c491 100644
--- a/include/asm-mips/spinlock.h
+++ b/include/asm-mips/spinlock.h
@@ -67,7 +67,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
: "memory");
}
- smp_mb();
+ smp_llsc_mb();
}
static inline void __raw_spin_unlock(raw_spinlock_t *lock)
@@ -118,7 +118,7 @@ static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
: "memory");
}
- smp_mb();
+ smp_llsc_mb();
return res == 0;
}
@@ -183,7 +183,7 @@ static inline void __raw_read_lock(raw_rwlock_t *rw)
: "memory");
}
- smp_mb();
+ smp_llsc_mb();
}
/* Note the use of sub, not subu which will make the kernel die with an
@@ -193,7 +193,7 @@ static inline void __raw_read_unlock(raw_rwlock_t *rw)
{
unsigned int tmp;
- smp_mb();
+ smp_llsc_mb();
if (R10000_LLSC_WAR) {
__asm__ __volatile__(
@@ -262,7 +262,7 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
: "memory");
}
- smp_mb();
+ smp_llsc_mb();
}
static inline void __raw_write_unlock(raw_rwlock_t *rw)
@@ -293,7 +293,7 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
" .set reorder \n"
" beqzl %1, 1b \n"
" nop \n"
- __WEAK_ORDERING_MB
+ __WEAK_LLSC_MB
" li %2, 1 \n"
"2: \n"
: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -310,7 +310,7 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
" beqz %1, 1b \n"
" nop \n"
" .set reorder \n"
- __WEAK_ORDERING_MB
+ __WEAK_LLSC_MB
" li %2, 1 \n"
"2: \n"
: "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
@@ -336,7 +336,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
" sc %1, %0 \n"
" beqzl %1, 1b \n"
" nop \n"
- __WEAK_ORDERING_MB
+ __WEAK_LLSC_MB
" li %2, 1 \n"
" .set reorder \n"
"2: \n"
@@ -354,7 +354,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
" beqz %1, 3f \n"
" li %2, 1 \n"
"2: \n"
- __WEAK_ORDERING_MB
+ __WEAK_LLSC_MB
" .subsection 2 \n"
"3: b 1b \n"
" li %2, 0 \n"
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 46bdb3f566f9..8d0b1cd4a45e 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -71,16 +71,6 @@ do { \
write_c0_userlocal(task_thread_info(current)->tp_value);\
} while(0)
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
{
__u32 retval;
@@ -127,7 +117,7 @@ static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
raw_local_irq_restore(flags); /* implies memory barrier */
}
- smp_mb();
+ smp_llsc_mb();
return retval;
}
@@ -175,7 +165,7 @@ static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
raw_local_irq_restore(flags); /* implies memory barrier */
}
- smp_mb();
+ smp_llsc_mb();
return retval;
}
@@ -256,7 +246,7 @@ static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
raw_local_irq_restore(flags); /* implies memory barrier */
}
- smp_mb();
+ smp_llsc_mb();
return retval;
}
@@ -362,7 +352,7 @@ static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old,
raw_local_irq_restore(flags); /* implies memory barrier */
}
- smp_mb();
+ smp_llsc_mb();
return retval;
}
@@ -480,6 +470,6 @@ extern int stop_a_enabled;
*/
#define __ARCH_WANT_UNLOCKED_CTXSW
-#define arch_align_stack(x) (x)
+extern unsigned long arch_align_stack(unsigned long sp);
#endif /* _ASM_SYSTEM_H */
diff --git a/include/asm-mips/tlbdebug.h b/include/asm-mips/tlbdebug.h
index fff7a73e22d0..bb8f5c29c3d9 100644
--- a/include/asm-mips/tlbdebug.h
+++ b/include/asm-mips/tlbdebug.h
@@ -11,10 +11,6 @@
/*
* TLB debugging functions:
*/
-extern void dump_tlb(int first, int last);
extern void dump_tlb_all(void);
-extern void dump_tlb_wired(void);
-extern void dump_tlb_addr(unsigned long addr);
-extern void dump_tlb_nonwired(void);
#endif /* __ASM_TLBDEBUG_H */
diff --git a/include/asm-mips/vr41xx/giu.h b/include/asm-mips/vr41xx/giu.h
index 8109cda557dc..0bcdd3a5c256 100644
--- a/include/asm-mips/vr41xx/giu.h
+++ b/include/asm-mips/vr41xx/giu.h
@@ -20,6 +20,15 @@
#ifndef __NEC_VR41XX_GIU_H
#define __NEC_VR41XX_GIU_H
+/*
+ * NEC VR4100 series GIU platform device IDs.
+ */
+enum {
+ GPIO_50PINS_PULLUPDOWN,
+ GPIO_36PINS,
+ GPIO_48PINS_EDGE_SELECT,
+};
+
typedef enum {
IRQ_TRIGGER_LEVEL,
IRQ_TRIGGER_EDGE,
diff --git a/include/asm-mips/vr41xx/siu.h b/include/asm-mips/vr41xx/siu.h
index 1fcf6e8082b4..98cdb4096485 100644
--- a/include/asm-mips/vr41xx/siu.h
+++ b/include/asm-mips/vr41xx/siu.h
@@ -20,6 +20,8 @@
#ifndef __NEC_VR41XX_SIU_H
#define __NEC_VR41XX_SIU_H
+#define SIU_PORTS_MAX 2
+
typedef enum {
SIU_INTERFACE_RS232C,
SIU_INTERFACE_IRDA,
diff --git a/include/asm-parisc/a.out.h b/include/asm-parisc/a.out.h
index 2a490cc9ec91..23e2c90943e5 100644
--- a/include/asm-parisc/a.out.h
+++ b/include/asm-parisc/a.out.h
@@ -23,6 +23,7 @@ struct exec
* prumpf */
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX DEFAULT_TASK_SIZE
#endif
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 11f4222597a0..5a85d1b025c8 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -31,8 +31,10 @@ typedef s32 compat_timer_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
+typedef s64 compat_s64;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
+typedef u64 compat_u64;
struct compat_timespec {
compat_time_t tv_sec;
diff --git a/include/asm-parisc/fb.h b/include/asm-parisc/fb.h
new file mode 100644
index 000000000000..4d503a023ab2
--- /dev/null
+++ b/include/asm-parisc/fb.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-parisc/fcntl.h b/include/asm-parisc/fcntl.h
index 317851fa78f3..1e1c824764ee 100644
--- a/include/asm-parisc/fcntl.h
+++ b/include/asm-parisc/fcntl.h
@@ -3,21 +3,22 @@
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
-#define O_APPEND 00000010
-#define O_BLKSEEK 00000100 /* HPUX only */
-#define O_CREAT 00000400 /* not fcntl */
-#define O_EXCL 00002000 /* not fcntl */
-#define O_LARGEFILE 00004000
-#define O_SYNC 00100000
-#define O_NONBLOCK 00200004 /* HPUX has separate NDELAY & NONBLOCK */
-#define O_NOCTTY 00400000 /* not fcntl */
-#define O_DSYNC 01000000 /* HPUX only */
-#define O_RSYNC 02000000 /* HPUX only */
-#define O_NOATIME 04000000
+#define O_APPEND 000000010
+#define O_BLKSEEK 000000100 /* HPUX only */
+#define O_CREAT 000000400 /* not fcntl */
+#define O_EXCL 000002000 /* not fcntl */
+#define O_LARGEFILE 000004000
+#define O_SYNC 000100000
+#define O_NONBLOCK 000200004 /* HPUX has separate NDELAY & NONBLOCK */
+#define O_NOCTTY 000400000 /* not fcntl */
+#define O_DSYNC 001000000 /* HPUX only */
+#define O_RSYNC 002000000 /* HPUX only */
+#define O_NOATIME 004000000
+#define O_CLOEXEC 010000000 /* set close_on_exec */
-#define O_DIRECTORY 00010000 /* must be a directory */
-#define O_NOFOLLOW 00000200 /* don't follow links */
-#define O_INVISIBLE 04000000 /* invisible I/O, for DMAPI/XDSM */
+#define O_DIRECTORY 000010000 /* must be a directory */
+#define O_NOFOLLOW 000000200 /* don't follow links */
+#define O_INVISIBLE 004000000 /* invisible I/O, for DMAPI/XDSM */
#define F_GETLK64 8
#define F_SETLK64 9
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
index 7b3be9ac0dda..61fbd57a8323 100644
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -238,9 +238,6 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x)
#define PCIBIOS_MIN_IO 0x10
#define PCIBIOS_MIN_MEM 0x1000 /* NBPG - but pci/setup-res.c dies */
-/* Don't support DAC yet. */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
/* export the pci_ DMA API in terms of the dma_ one */
#include <asm-generic/pci-dma-compat.h>
@@ -284,10 +281,6 @@ pcibios_select_root(struct pci_dev *pdev, struct resource *res)
return root;
}
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't need to penalize isa irq's */
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index beb2adb979d9..e88cacd63724 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -335,18 +335,14 @@ extern inline void pgd_clear(pgd_t * pgdp) { }
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
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_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
-extern inline int pte_user(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
-extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_READ; return pte; }
extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_WRITE; return pte; }
-extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_READ; return pte; }
extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_WRITE; return pte; }
@@ -451,21 +447,6 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
#endif
}
-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
-#ifdef CONFIG_SMP
- if (!pte_dirty(*ptep))
- return 0;
- return test_and_clear_bit(xlate_pabit(_PAGE_DIRTY_BIT), &pte_val(*ptep));
-#else
- pte_t pte = *ptep;
- if (!pte_dirty(pte))
- return 0;
- set_pte_at(vma->vm_mm, addr, ptep, pte_mkclean(pte));
- return 1;
-#endif
-}
-
extern spinlock_t pa_dbit_lock;
struct mm_struct;
@@ -533,7 +514,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
#define HAVE_ARCH_UNMAPPED_AREA
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTE_SAME
diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h
index 21fbfc5afd02..ee80c920b464 100644
--- a/include/asm-parisc/system.h
+++ b/include/asm-parisc/system.h
@@ -48,17 +48,6 @@ extern struct task_struct *_switch_to(struct task_struct *, struct task_struct *
(last) = _switch_to(prev, next); \
} while(0)
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
-
/* interrupt control */
#define local_save_flags(x) __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
#define local_irq_disable() __asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
diff --git a/include/asm-powerpc/a.out.h b/include/asm-powerpc/a.out.h
index c7393a977364..5c5ea83f9349 100644
--- a/include/asm-powerpc/a.out.h
+++ b/include/asm-powerpc/a.out.h
@@ -26,9 +26,12 @@ struct exec
#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
STACK_TOP_USER32 : STACK_TOP_USER64)
+#define STACK_TOP_MAX STACK_TOP_USER64
+
#else /* __powerpc64__ */
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif /* __powerpc64__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/cache.h b/include/asm-powerpc/cache.h
index 642be62cf393..53507046a1b1 100644
--- a/include/asm-powerpc/cache.h
+++ b/include/asm-powerpc/cache.h
@@ -34,5 +34,9 @@ struct ppc64_caches {
extern struct ppc64_caches ppc64_caches;
#endif /* __powerpc64__ && ! __ASSEMBLY__ */
+#if !defined(__ASSEMBLY__)
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#endif
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_CACHE_H */
diff --git a/include/asm-powerpc/compat.h b/include/asm-powerpc/compat.h
index aacaabd28ac1..64ab1ddbdf85 100644
--- a/include/asm-powerpc/compat.h
+++ b/include/asm-powerpc/compat.h
@@ -33,8 +33,10 @@ typedef s32 compat_timer_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
+typedef s64 compat_s64;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
+typedef u64 compat_u64;
struct compat_timespec {
compat_time_t tv_sec;
diff --git a/include/asm-powerpc/cputable.h b/include/asm-powerpc/cputable.h
index 82d595a52109..3dc8e2dfca84 100644
--- a/include/asm-powerpc/cputable.h
+++ b/include/asm-powerpc/cputable.h
@@ -111,7 +111,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
/* CPU kernel features */
/* Retain the 32b definitions all use bottom half of word */
-#define CPU_FTR_SPLIT_ID_CACHE ASM_CONST(0x0000000000000001)
+#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000000000000001)
#define CPU_FTR_L2CR ASM_CONST(0x0000000000000002)
#define CPU_FTR_SPEC7450 ASM_CONST(0x0000000000000004)
#define CPU_FTR_ALTIVEC ASM_CONST(0x0000000000000008)
@@ -135,6 +135,7 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000)
#define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000)
#define CPU_FTR_FPU_UNAVAILABLE ASM_CONST(0x0000000000800000)
+#define CPU_FTR_UNIFIED_ID_CACHE ASM_CONST(0x0000000001000000)
/*
* Add the 64-bit processor unique features in the top half of the word;
@@ -154,7 +155,6 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
#define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000)
#define CPU_FTR_CTRL LONG_ASM_CONST(0x0000008000000000)
#define CPU_FTR_SMT LONG_ASM_CONST(0x0000010000000000)
-#define CPU_FTR_COHERENT_ICACHE LONG_ASM_CONST(0x0000020000000000)
#define CPU_FTR_LOCKLESS_TLBIE LONG_ASM_CONST(0x0000040000000000)
#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000)
#define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000)
@@ -206,164 +206,149 @@ extern void do_feature_fixups(unsigned long value, void *fixup_start,
!defined(CONFIG_POWER3) && !defined(CONFIG_POWER4) && \
!defined(CONFIG_BOOKE))
-#define CPU_FTRS_PPC601 (CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE)
-#define CPU_FTRS_603 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_PPC601 (CPU_FTR_COMMON | CPU_FTR_601 | CPU_FTR_HPTE_TABLE | \
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_UNIFIED_ID_CACHE)
+#define CPU_FTRS_603 (CPU_FTR_COMMON | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
-#define CPU_FTRS_604 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_604 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON | CPU_FTR_HPTE_TABLE | \
CPU_FTR_PPC_LE)
-#define CPU_FTRS_740_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_740_NOTAU (CPU_FTR_COMMON | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
-#define CPU_FTRS_740 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_740 (CPU_FTR_COMMON | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_PPC_LE)
-#define CPU_FTRS_750 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_750 (CPU_FTR_COMMON | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
CPU_FTR_PPC_LE)
-#define CPU_FTRS_750CL (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750FX1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750FX2 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_NO_DPM | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750FX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_750GX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
- CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
- CPU_FTR_TAU | CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP | \
- CPU_FTR_DUAL_PLL_750FX | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7400_NOTAU (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_750CL (CPU_FTRS_750 | CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_750FX1 (CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX | CPU_FTR_NO_DPM)
+#define CPU_FTRS_750FX2 (CPU_FTRS_750 | CPU_FTR_NO_DPM)
+#define CPU_FTRS_750FX (CPU_FTRS_750 | CPU_FTR_DUAL_PLL_750FX | \
+ CPU_FTR_HAS_HIGH_BATS)
+#define CPU_FTRS_750GX (CPU_FTRS_750FX)
+#define CPU_FTRS_7400_NOTAU (CPU_FTR_COMMON | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7400 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7400 (CPU_FTR_COMMON | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB | CPU_FTR_L2CR | \
CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7450_20 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7450_20 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7450_21 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7450_21 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7450_23 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7450_23 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7455_1 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7455_1 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_L3CR | \
CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7455_20 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7455_20 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_L3_DISABLE_NAP | \
CPU_FTR_NEED_COHERENT | CPU_FTR_HAS_HIGH_BATS | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7455 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7455 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7447_10 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7447_10 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_NEED_COHERENT | CPU_FTR_NO_BTIC | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7447 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7447 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_L3CR | CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7447A (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7447A (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_NEED_COHERENT | CPU_FTR_PPC_LE)
-#define CPU_FTRS_7448 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_7448 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | \
CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | \
CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450 | \
CPU_FTR_NAP_DISABLE_L2_PR | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_PPC_LE)
-#define CPU_FTRS_82XX (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_82XX (CPU_FTR_COMMON | \
CPU_FTR_MAYBE_CAN_DOZE | CPU_FTR_USE_TB)
-#define CPU_FTRS_G2_LE (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+#define CPU_FTRS_G2_LE (CPU_FTR_MAYBE_CAN_DOZE | \
CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS)
-#define CPU_FTRS_E300 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+#define CPU_FTRS_E300 (CPU_FTR_MAYBE_CAN_DOZE | \
CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_COMMON)
-#define CPU_FTRS_E300C2 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE | \
+#define CPU_FTRS_E300C2 (CPU_FTR_MAYBE_CAN_DOZE | \
CPU_FTR_USE_TB | CPU_FTR_MAYBE_CAN_NAP | CPU_FTR_HAS_HIGH_BATS | \
CPU_FTR_COMMON | CPU_FTR_FPU_UNAVAILABLE)
-#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | CPU_FTR_SPLIT_ID_CACHE | \
+#define CPU_FTRS_CLASSIC32 (CPU_FTR_COMMON | \
CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE)
-#define CPU_FTRS_8XX (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB)
-#define CPU_FTRS_40X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
- CPU_FTR_NODSISRALIGN)
-#define CPU_FTRS_44X (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
- CPU_FTR_NODSISRALIGN)
-#define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN)
-#define CPU_FTRS_E500 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
- CPU_FTR_NODSISRALIGN)
-#define CPU_FTRS_E500_2 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_8XX (CPU_FTR_USE_TB)
+#define CPU_FTRS_40X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_44X (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_E200 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_UNIFIED_ID_CACHE)
+#define CPU_FTRS_E500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN)
+#define CPU_FTRS_E500_2 (CPU_FTR_USE_TB | \
CPU_FTR_BIG_PHYS | CPU_FTR_NODSISRALIGN)
#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
/* 64-bit CPUs */
-#define CPU_FTRS_POWER3 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_POWER3 (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | CPU_FTR_PPC_LE)
-#define CPU_FTRS_RS64 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_RS64 (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_IABR | \
CPU_FTR_MMCRA | CPU_FTR_CTRL)
-#define CPU_FTRS_POWER4 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_POWER4 (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA)
-#define CPU_FTRS_PPC970 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_PPC970 (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA)
-#define CPU_FTRS_POWER5 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
CPU_FTR_PURR)
-#define CPU_FTRS_POWER6 (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
CPU_FTR_DSCR)
-#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_CELL (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
-#define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_PA6T (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
CPU_FTR_PURR | CPU_FTR_REAL_LE)
-#define CPU_FTRS_COMPATIBLE (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
+#define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2)
#ifdef __powerpc64__
diff --git a/include/asm-powerpc/dma-mapping.h b/include/asm-powerpc/dma-mapping.h
index a19a6f1a1cf1..f6bd804d9090 100644
--- a/include/asm-powerpc/dma-mapping.h
+++ b/include/asm-powerpc/dma-mapping.h
@@ -61,7 +61,6 @@ struct dma_mapping_ops {
void (*unmap_sg)(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction);
int (*dma_supported)(struct device *dev, u64 mask);
- int (*dac_dma_supported)(struct device *dev, u64 mask);
int (*set_dma_mask)(struct device *dev, u64 dma_mask);
};
diff --git a/include/asm-powerpc/fb.h b/include/asm-powerpc/fb.h
new file mode 100644
index 000000000000..411af8d17a69
--- /dev/null
+++ b/include/asm-powerpc/fb.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = phys_mem_access_prot(file, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-powerpc/floppy.h b/include/asm-powerpc/floppy.h
index afa700ded877..34146f0eea63 100644
--- a/include/asm-powerpc/floppy.h
+++ b/include/asm-powerpc/floppy.h
@@ -29,7 +29,7 @@
#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL);
#include <linux/pci.h>
-#include <asm/ppc-pci.h> /* for ppc64_isabridge_dev */
+#include <asm/ppc-pci.h> /* for isa_bridge_pcidev */
#define fd_dma_setup(addr,size,mode,io) fd_ops->_dma_setup(addr,size,mode,io)
@@ -139,12 +139,12 @@ static int hard_dma_setup(char *addr, unsigned long size, int mode, int io)
if (bus_addr
&& (addr != prev_addr || size != prev_size || dir != prev_dir)) {
/* different from last time -- unmap prev */
- pci_unmap_single(ppc64_isabridge_dev, bus_addr, prev_size, prev_dir);
+ pci_unmap_single(isa_bridge_pcidev, bus_addr, prev_size, prev_dir);
bus_addr = 0;
}
if (!bus_addr) /* need to map it */
- bus_addr = pci_map_single(ppc64_isabridge_dev, addr, size, dir);
+ bus_addr = pci_map_single(isa_bridge_pcidev, addr, size, dir);
/* remember this one as prev */
prev_addr = addr;
diff --git a/include/asm-powerpc/hvcall.h b/include/asm-powerpc/hvcall.h
index 62efd9d7a43d..bf6cd7cb996c 100644
--- a/include/asm-powerpc/hvcall.h
+++ b/include/asm-powerpc/hvcall.h
@@ -206,6 +206,7 @@
#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
#define H_QUERY_INT_STATE 0x1E4
#define H_POLL_PENDING 0x1D8
+#define H_ILLAN_ATTRIBUTES 0x244
#define H_JOIN 0x298
#define H_VASI_STATE 0x2A4
#define H_ENABLE_CRQ 0x2B0
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 350c9bdb31dc..bb8d965f96c6 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -607,9 +607,9 @@ static inline void iosync(void)
*
* * iounmap undoes such a mapping and can be hooked
*
- * * __ioremap_explicit (and the pending __iounmap_explicit) are low level
- * functions to create hand-made mappings for use only by the PCI code
- * and cannot currently be hooked.
+ * * __ioremap_at (and the pending __iounmap_at) are low level functions to
+ * create hand-made mappings for use only by the PCI code and cannot
+ * currently be hooked. Must be page aligned.
*
* * __ioremap is the low level implementation used by ioremap and
* ioremap_flags and cannot be hooked (but can be used by a hook on one
@@ -629,19 +629,9 @@ extern void __iomem *__ioremap(phys_addr_t, unsigned long size,
unsigned long flags);
extern void __iounmap(volatile void __iomem *addr);
-extern int __ioremap_explicit(phys_addr_t p_addr, unsigned long v_addr,
- unsigned long size, unsigned long flags);
-extern int __iounmap_explicit(volatile void __iomem *start,
- unsigned long size);
-
-extern void __iomem * reserve_phb_iospace(unsigned long size);
-
-/* Those are more 32 bits only functions */
-extern unsigned long iopa(unsigned long addr);
-extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
-extern void io_block_mapping(unsigned long virt, phys_addr_t phys,
- unsigned int size, int flags);
-
+extern void __iomem * __ioremap_at(phys_addr_t pa, void *ea,
+ unsigned long size, unsigned long flags);
+extern void __iounmap_at(void *ea, unsigned long size);
/*
* When CONFIG_PPC_INDIRECT_IO is set, we use the generic iomap implementation
@@ -651,8 +641,8 @@ extern void io_block_mapping(unsigned long virt, phys_addr_t phys,
*/
#define HAVE_ARCH_PIO_SIZE 1
#define PIO_OFFSET 0x00000000UL
-#define PIO_MASK 0x3fffffffUL
-#define PIO_RESERVED 0x40000000UL
+#define PIO_MASK (FULL_IO_SIZE - 1)
+#define PIO_RESERVED (FULL_IO_SIZE)
#define mmio_read16be(addr) readw_be(addr)
#define mmio_read32be(addr) readl_be(addr)
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 05dd5a3eb3aa..0485c53db2b5 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -223,6 +223,15 @@ extern void irq_dispose_mapping(unsigned int virq);
extern unsigned int irq_find_mapping(struct irq_host *host,
irq_hw_number_t hwirq);
+/**
+ * irq_create_direct_mapping - Allocate a virq for direct mapping
+ * @host: host to allocate the virq for or NULL for default host
+ *
+ * This routine is used for irq controllers which can choose the hardware
+ * interrupt numbers they generate. In such a case it's simplest to use
+ * the linux virq as the hardware interrupt number.
+ */
+extern unsigned int irq_create_direct_mapping(struct irq_host *host);
/**
* irq_radix_revmap - Find a linux virq from a hw irq number.
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index b0e40ff32ee0..8b08b447d6f3 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -65,20 +65,18 @@ typedef unsigned int kprobe_opcode_t;
} else if (name[0] != '.') \
addr = *(kprobe_opcode_t **)addr; \
} else { \
- char dot_name[KSYM_NAME_LEN+1]; \
+ char dot_name[KSYM_NAME_LEN]; \
dot_name[0] = '.'; \
dot_name[1] = '\0'; \
- strncat(dot_name, name, KSYM_NAME_LEN); \
+ strncat(dot_name, name, KSYM_NAME_LEN - 2); \
addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \
} \
}
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry)
#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
IS_TWI(instr) || IS_TDI(instr))
#else
/* Use stock kprobe_lookup_name since ppc32 doesn't use function descriptors */
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)(pentry)
#define is_trap(instr) (IS_TW(instr) || IS_TWI(instr))
#endif
diff --git a/include/asm-powerpc/lppaca.h b/include/asm-powerpc/lppaca.h
index 821ea0c512b4..567ed92cd91f 100644
--- a/include/asm-powerpc/lppaca.h
+++ b/include/asm-powerpc/lppaca.h
@@ -98,7 +98,7 @@ struct lppaca {
u64 saved_gpr5; // Saved GPR5 x30-x37
u8 reserved4; // Reserved x38-x38
- u8 cpuctls_task_attrs; // Task attributes for cpuctls x39-x39
+ u8 donate_dedicated_cpu; // Donate dedicated CPU cycles x39-x39
u8 fpregs_in_use; // FP regs in use x3A-x3A
u8 pmcregs_in_use; // PMC regs in use x3B-x3B
volatile u32 saved_decr; // Saved Decr Value x3C-x3F
diff --git a/include/asm-powerpc/lv1call.h b/include/asm-powerpc/lv1call.h
index f733beeea63a..81713acf7529 100644
--- a/include/asm-powerpc/lv1call.h
+++ b/include/asm-powerpc/lv1call.h
@@ -238,6 +238,7 @@ LV1_CALL(destruct_virtual_address_space, 1, 0, 10 )
LV1_CALL(configure_irq_state_bitmap, 3, 0, 11 )
LV1_CALL(connect_irq_plug_ext, 5, 0, 12 )
LV1_CALL(release_memory, 1, 0, 13 )
+LV1_CALL(put_iopte, 5, 0, 15 )
LV1_CALL(disconnect_irq_plug_ext, 3, 0, 17 )
LV1_CALL(construct_event_receive_port, 0, 1, 18 )
LV1_CALL(destruct_event_receive_port, 1, 0, 19 )
@@ -268,6 +269,8 @@ LV1_CALL(remove_repository_node, 4, 0, 93 )
LV1_CALL(read_htab_entries, 2, 5, 95 )
LV1_CALL(set_dabr, 2, 0, 96 )
LV1_CALL(get_total_execution_time, 2, 1, 103 )
+LV1_CALL(allocate_io_segment, 3, 1, 116 )
+LV1_CALL(release_io_segment, 2, 0, 117 )
LV1_CALL(construct_io_irq_outlet, 1, 1, 120 )
LV1_CALL(destruct_io_irq_outlet, 1, 0, 121 )
LV1_CALL(map_htab, 1, 1, 122 )
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index 6cf1a831f550..71c6e7eb2a26 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -218,7 +218,7 @@ struct machdep_calls {
int (*pcibios_enable_device_hook)(struct pci_dev *, int initial);
/* Called in indirect_* to avoid touching devices */
- int (*pci_exclude_device)(unsigned char, unsigned char);
+ int (*pci_exclude_device)(struct pci_controller *, unsigned char, unsigned char);
/* Called at then very end of pcibios_init() */
void (*pcibios_after_init)(void);
diff --git a/include/asm-powerpc/mmu-8xx.h b/include/asm-powerpc/mmu-8xx.h
new file mode 100644
index 000000000000..952bd8899f2f
--- /dev/null
+++ b/include/asm-powerpc/mmu-8xx.h
@@ -0,0 +1,147 @@
+#ifndef _ASM_POWERPC_MMU_8XX_H_
+#define _ASM_POWERPC_MMU_8XX_H_
+/*
+ * PPC8xx support
+ */
+
+/* Control/status registers for the MPC8xx.
+ * A write operation to these registers causes serialized access.
+ * During software tablewalk, the registers used perform mask/shift-add
+ * operations when written/read. A TLB entry is created when the Mx_RPN
+ * is written, and the contents of several registers are used to
+ * create the entry.
+ */
+#define SPRN_MI_CTR 784 /* Instruction TLB control register */
+#define MI_GPM 0x80000000 /* Set domain manager mode */
+#define MI_PPM 0x40000000 /* Set subpage protection */
+#define MI_CIDEF 0x20000000 /* Set cache inhibit when MMU dis */
+#define MI_RSV4I 0x08000000 /* Reserve 4 TLB entries */
+#define MI_PPCS 0x02000000 /* Use MI_RPN prob/priv state */
+#define MI_IDXMASK 0x00001f00 /* TLB index to be loaded */
+#define MI_RESETVAL 0x00000000 /* Value of register at reset */
+
+/* These are the Ks and Kp from the PowerPC books. For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define SPRN_MI_AP 786
+#define MI_Ks 0x80000000 /* Should not be set */
+#define MI_Kp 0x40000000 /* Should always be set */
+
+/* The effective page number register. When read, contains the information
+ * about the last instruction TLB miss. When MI_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define SPRN_MI_EPN 787
+#define MI_EPNMASK 0xfffff000 /* Effective page number for entry */
+#define MI_EVALID 0x00000200 /* Entry is valid */
+#define MI_ASIDMASK 0x0000000f /* ASID match value */
+ /* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the instruction TLB, it contains bits that get loaded into the
+ * TLB entry when the MI_RPN is written.
+ */
+#define SPRN_MI_TWC 789
+#define MI_APG 0x000001e0 /* Access protection group (0) */
+#define MI_GUARDED 0x00000010 /* Guarded storage */
+#define MI_PSMASK 0x0000000c /* Mask of page size bits */
+#define MI_PS8MEG 0x0000000c /* 8M page size */
+#define MI_PS512K 0x00000004 /* 512K page size */
+#define MI_PS4K_16K 0x00000000 /* 4K or 16K page size */
+#define MI_SVALID 0x00000001 /* Segment entry is valid */
+ /* Reset value is undefined */
+
+/* Real page number. Defined by the pte. Writing this register
+ * causes a TLB entry to be created for the instruction TLB, using
+ * additional information from the MI_EPN, and MI_TWC registers.
+ */
+#define SPRN_MI_RPN 790
+
+/* Define an RPN value for mapping kernel memory to large virtual
+ * pages for boot initialization. This has real page number of 0,
+ * large page size, shared page, cache enabled, and valid.
+ * Also mark all subpages valid and write access.
+ */
+#define MI_BOOTINIT 0x000001fd
+
+#define SPRN_MD_CTR 792 /* Data TLB control register */
+#define MD_GPM 0x80000000 /* Set domain manager mode */
+#define MD_PPM 0x40000000 /* Set subpage protection */
+#define MD_CIDEF 0x20000000 /* Set cache inhibit when MMU dis */
+#define MD_WTDEF 0x10000000 /* Set writethrough when MMU dis */
+#define MD_RSV4I 0x08000000 /* Reserve 4 TLB entries */
+#define MD_TWAM 0x04000000 /* Use 4K page hardware assist */
+#define MD_PPCS 0x02000000 /* Use MI_RPN prob/priv state */
+#define MD_IDXMASK 0x00001f00 /* TLB index to be loaded */
+#define MD_RESETVAL 0x04000000 /* Value of register at reset */
+
+#define SPRN_M_CASID 793 /* Address space ID (context) to match */
+#define MC_ASIDMASK 0x0000000f /* Bits used for ASID value */
+
+
+/* These are the Ks and Kp from the PowerPC books. For proper operation,
+ * Ks = 0, Kp = 1.
+ */
+#define SPRN_MD_AP 794
+#define MD_Ks 0x80000000 /* Should not be set */
+#define MD_Kp 0x40000000 /* Should always be set */
+
+/* The effective page number register. When read, contains the information
+ * about the last instruction TLB miss. When MD_RPN is written, bits in
+ * this register are used to create the TLB entry.
+ */
+#define SPRN_MD_EPN 795
+#define MD_EPNMASK 0xfffff000 /* Effective page number for entry */
+#define MD_EVALID 0x00000200 /* Entry is valid */
+#define MD_ASIDMASK 0x0000000f /* ASID match value */
+ /* Reset value is undefined */
+
+/* The pointer to the base address of the first level page table.
+ * During a software tablewalk, reading this register provides the address
+ * of the entry associated with MD_EPN.
+ */
+#define SPRN_M_TWB 796
+#define M_L1TB 0xfffff000 /* Level 1 table base address */
+#define M_L1INDX 0x00000ffc /* Level 1 index, when read */
+ /* Reset value is undefined */
+
+/* A "level 1" or "segment" or whatever you want to call it register.
+ * For the data TLB, it contains bits that get loaded into the TLB entry
+ * when the MD_RPN is written. It is also provides the hardware assist
+ * for finding the PTE address during software tablewalk.
+ */
+#define SPRN_MD_TWC 797
+#define MD_L2TB 0xfffff000 /* Level 2 table base address */
+#define MD_L2INDX 0xfffffe00 /* Level 2 index (*pte), when read */
+#define MD_APG 0x000001e0 /* Access protection group (0) */
+#define MD_GUARDED 0x00000010 /* Guarded storage */
+#define MD_PSMASK 0x0000000c /* Mask of page size bits */
+#define MD_PS8MEG 0x0000000c /* 8M page size */
+#define MD_PS512K 0x00000004 /* 512K page size */
+#define MD_PS4K_16K 0x00000000 /* 4K or 16K page size */
+#define MD_WT 0x00000002 /* Use writethrough page attribute */
+#define MD_SVALID 0x00000001 /* Segment entry is valid */
+ /* Reset value is undefined */
+
+
+/* Real page number. Defined by the pte. Writing this register
+ * causes a TLB entry to be created for the data TLB, using
+ * additional information from the MD_EPN, and MD_TWC registers.
+ */
+#define SPRN_MD_RPN 798
+
+/* This is a temporary storage register that could be used to save
+ * a processor working register during a tablewalk.
+ */
+#define SPRN_M_TW 799
+
+#ifndef __ASSEMBLY__
+typedef unsigned long phys_addr_t;
+
+typedef struct {
+ unsigned long id;
+ unsigned long vdso_base;
+} mm_context_t;
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_MMU_8XX_H_ */
diff --git a/include/asm-powerpc/mmu-fsl-booke.h b/include/asm-powerpc/mmu-fsl-booke.h
new file mode 100644
index 000000000000..37580004cd7a
--- /dev/null
+++ b/include/asm-powerpc/mmu-fsl-booke.h
@@ -0,0 +1,88 @@
+#ifndef _ASM_POWERPC_MMU_FSL_BOOKE_H_
+#define _ASM_POWERPC_MMU_FSL_BOOKE_H_
+/*
+ * Freescale Book-E MMU support
+ */
+
+/* Book-E defined page sizes */
+#define BOOKE_PAGESZ_1K 0
+#define BOOKE_PAGESZ_4K 1
+#define BOOKE_PAGESZ_16K 2
+#define BOOKE_PAGESZ_64K 3
+#define BOOKE_PAGESZ_256K 4
+#define BOOKE_PAGESZ_1M 5
+#define BOOKE_PAGESZ_4M 6
+#define BOOKE_PAGESZ_16M 7
+#define BOOKE_PAGESZ_64M 8
+#define BOOKE_PAGESZ_256M 9
+#define BOOKE_PAGESZ_1GB 10
+#define BOOKE_PAGESZ_4GB 11
+#define BOOKE_PAGESZ_16GB 12
+#define BOOKE_PAGESZ_64GB 13
+#define BOOKE_PAGESZ_256GB 14
+#define BOOKE_PAGESZ_1TB 15
+
+#define MAS0_TLBSEL(x) ((x << 28) & 0x30000000)
+#define MAS0_ESEL(x) ((x << 16) & 0x0FFF0000)
+#define MAS0_NV(x) ((x) & 0x00000FFF)
+
+#define MAS1_VALID 0x80000000
+#define MAS1_IPROT 0x40000000
+#define MAS1_TID(x) ((x << 16) & 0x3FFF0000)
+#define MAS1_TS 0x00001000
+#define MAS1_TSIZE(x) ((x << 8) & 0x00000F00)
+
+#define MAS2_EPN 0xFFFFF000
+#define MAS2_X0 0x00000040
+#define MAS2_X1 0x00000020
+#define MAS2_W 0x00000010
+#define MAS2_I 0x00000008
+#define MAS2_M 0x00000004
+#define MAS2_G 0x00000002
+#define MAS2_E 0x00000001
+
+#define MAS3_RPN 0xFFFFF000
+#define MAS3_U0 0x00000200
+#define MAS3_U1 0x00000100
+#define MAS3_U2 0x00000080
+#define MAS3_U3 0x00000040
+#define MAS3_UX 0x00000020
+#define MAS3_SX 0x00000010
+#define MAS3_UW 0x00000008
+#define MAS3_SW 0x00000004
+#define MAS3_UR 0x00000002
+#define MAS3_SR 0x00000001
+
+#define MAS4_TLBSELD(x) MAS0_TLBSEL(x)
+#define MAS4_TIDDSEL 0x000F0000
+#define MAS4_TSIZED(x) MAS1_TSIZE(x)
+#define MAS4_X0D 0x00000040
+#define MAS4_X1D 0x00000020
+#define MAS4_WD 0x00000010
+#define MAS4_ID 0x00000008
+#define MAS4_MD 0x00000004
+#define MAS4_GD 0x00000002
+#define MAS4_ED 0x00000001
+
+#define MAS6_SPID0 0x3FFF0000
+#define MAS6_SPID1 0x00007FFE
+#define MAS6_SAS 0x00000001
+#define MAS6_SPID MAS6_SPID0
+
+#define MAS7_RPN 0xFFFFFFFF
+
+#ifndef __ASSEMBLY__
+
+#ifndef CONFIG_PHYS_64BIT
+typedef unsigned long phys_addr_t;
+#else
+typedef unsigned long long phys_addr_t;
+#endif
+
+typedef struct {
+ unsigned long id;
+ unsigned long vdso_base;
+} mm_context_t;
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_MMU_FSL_BOOKE_H_ */
diff --git a/include/asm-powerpc/mmu-hash32.h b/include/asm-powerpc/mmu-hash32.h
new file mode 100644
index 000000000000..4bd735be3833
--- /dev/null
+++ b/include/asm-powerpc/mmu-hash32.h
@@ -0,0 +1,91 @@
+#ifndef _ASM_POWERPC_MMU_HASH32_H_
+#define _ASM_POWERPC_MMU_HASH32_H_
+/*
+ * 32-bit hash table MMU support
+ */
+
+/*
+ * BATs
+ */
+
+/* Block size masks */
+#define BL_128K 0x000
+#define BL_256K 0x001
+#define BL_512K 0x003
+#define BL_1M 0x007
+#define BL_2M 0x00F
+#define BL_4M 0x01F
+#define BL_8M 0x03F
+#define BL_16M 0x07F
+#define BL_32M 0x0FF
+#define BL_64M 0x1FF
+#define BL_128M 0x3FF
+#define BL_256M 0x7FF
+
+/* BAT Access Protection */
+#define BPP_XX 0x00 /* No access */
+#define BPP_RX 0x01 /* Read only */
+#define BPP_RW 0x02 /* Read/write */
+
+#ifndef __ASSEMBLY__
+struct ppc_bat {
+ struct {
+ unsigned long bepi:15; /* Effective page index (virtual address) */
+ unsigned long :4; /* Unused */
+ unsigned long bl:11; /* Block size mask */
+ unsigned long vs:1; /* Supervisor valid */
+ unsigned long vp:1; /* User valid */
+ } batu; /* Upper register */
+ struct {
+ unsigned long brpn:15; /* Real page index (physical address) */
+ unsigned long :10; /* Unused */
+ unsigned long w:1; /* Write-thru cache */
+ unsigned long i:1; /* Cache inhibit */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long g:1; /* Guarded (MBZ in IBAT) */
+ unsigned long :1; /* Unused */
+ unsigned long pp:2; /* Page access protections */
+ } batl; /* Lower register */
+};
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Hash table
+ */
+
+/* Values for PP (assumes Ks=0, Kp=1) */
+#define PP_RWXX 0 /* Supervisor read/write, User none */
+#define PP_RWRX 1 /* Supervisor read/write, User read */
+#define PP_RWRW 2 /* Supervisor read/write, User read/write */
+#define PP_RXRX 3 /* Supervisor read, User read */
+
+#ifndef __ASSEMBLY__
+
+/* Hardware Page Table Entry */
+struct hash_pte {
+ unsigned long v:1; /* Entry is valid */
+ unsigned long vsid:24; /* Virtual segment identifier */
+ unsigned long h:1; /* Hash algorithm indicator */
+ unsigned long api:6; /* Abbreviated page index */
+ unsigned long rpn:20; /* Real (physical) page number */
+ unsigned long :3; /* Unused */
+ unsigned long r:1; /* Referenced */
+ unsigned long c:1; /* Changed */
+ unsigned long w:1; /* Write-thru cache mode */
+ unsigned long i:1; /* Cache inhibited */
+ unsigned long m:1; /* Memory coherence */
+ unsigned long g:1; /* Guarded */
+ unsigned long :1; /* Unused */
+ unsigned long pp:2; /* Page protection */
+};
+
+typedef struct {
+ unsigned long id;
+ unsigned long vdso_base;
+} mm_context_t;
+
+typedef unsigned long phys_addr_t;
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_MMU_HASH32_H_ */
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h
index b8dca30bd0b5..695962f02059 100644
--- a/include/asm-powerpc/mmu-hash64.h
+++ b/include/asm-powerpc/mmu-hash64.h
@@ -94,6 +94,9 @@ extern char initial_stab[];
#define HPTE_R_C ASM_CONST(0x0000000000000080)
#define HPTE_R_R ASM_CONST(0x0000000000000100)
+#define HPTE_V_1TB_SEG ASM_CONST(0x4000000000000000)
+#define HPTE_V_VRMA_MASK ASM_CONST(0x4001ffffff000000)
+
/* Values for PP (assumes Ks=0, Kp=1) */
/* pp0 will always be 0 for linux */
#define PP_RWXX 0 /* Supervisor read/write, User none */
@@ -103,12 +106,12 @@ extern char initial_stab[];
#ifndef __ASSEMBLY__
-typedef struct {
+struct hash_pte {
unsigned long v;
unsigned long r;
-} hpte_t;
+};
-extern hpte_t *htab_address;
+extern struct hash_pte *htab_address;
extern unsigned long htab_size_bytes;
extern unsigned long htab_hash_mask;
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index fe510fff8907..d44d211e7588 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -5,13 +5,18 @@
#ifdef CONFIG_PPC64
/* 64-bit classic hash table MMU */
# include <asm/mmu-hash64.h>
+#elif defined(CONFIG_PPC_STD_MMU)
+/* 32-bit classic hash table MMU */
+# include <asm/mmu-hash32.h>
#elif defined(CONFIG_44x)
/* 44x-style software loaded TLB */
# include <asm/mmu-44x.h>
-#else
-/* Other 32-bit. FIXME: split up the other 32-bit MMU types, and
- * revise for arch/powerpc */
-# include <asm-ppc/mmu.h>
+#elif defined(CONFIG_FSL_BOOKE)
+/* Freescale Book-E software loaded TLB */
+# include <asm/mmu-fsl-booke.h>
+#elif defined (CONFIG_PPC_8xx)
+/* Motorola/Freescale 8xx software loaded TLB */
+# include <asm/mmu-8xx.h>
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mmu_context.h b/include/asm-powerpc/mmu_context.h
index 40c9e5a13ff1..f863ac21409e 100644
--- a/include/asm-powerpc/mmu_context.h
+++ b/include/asm-powerpc/mmu_context.h
@@ -2,16 +2,210 @@
#define __ASM_POWERPC_MMU_CONTEXT_H
#ifdef __KERNEL__
+#include <asm/mmu.h>
+#include <asm/cputable.h>
+#include <asm-generic/mm_hooks.h>
+
#ifndef CONFIG_PPC64
-#include <asm-ppc/mmu_context.h>
+#include <asm/atomic.h>
+#include <asm/bitops.h>
+
+/*
+ * On 32-bit PowerPC 6xx/7xx/7xxx CPUs, we use a set of 16 VSIDs
+ * (virtual segment identifiers) for each context. Although the
+ * hardware supports 24-bit VSIDs, and thus >1 million contexts,
+ * we only use 32,768 of them. That is ample, since there can be
+ * at most around 30,000 tasks in the system anyway, and it means
+ * that we can use a bitmap to indicate which contexts are in use.
+ * Using a bitmap means that we entirely avoid all of the problems
+ * that we used to have when the context number overflowed,
+ * particularly on SMP systems.
+ * -- paulus.
+ */
+
+/*
+ * This function defines the mapping from contexts to VSIDs (virtual
+ * segment IDs). We use a skew on both the context and the high 4 bits
+ * of the 32-bit virtual address (the "effective segment ID") in order
+ * to spread out the entries in the MMU hash table. Note, if this
+ * function is changed then arch/ppc/mm/hashtable.S will have to be
+ * changed to correspond.
+ */
+#define CTX_TO_VSID(ctx, va) (((ctx) * (897 * 16) + ((va) >> 28) * 0x111) \
+ & 0xffffff)
+
+/*
+ The MPC8xx has only 16 contexts. We rotate through them on each
+ task switch. A better way would be to keep track of tasks that
+ own contexts, and implement an LRU usage. That way very active
+ tasks don't always have to pay the TLB reload overhead. The
+ kernel pages are mapped shared, so the kernel can run on behalf
+ of any task that makes a kernel entry. Shared does not mean they
+ are not protected, just that the ASID comparison is not performed.
+ -- Dan
+
+ The IBM4xx has 256 contexts, so we can just rotate through these
+ as a way of "switching" contexts. If the TID of the TLB is zero,
+ the PID/TID comparison is disabled, so we can use a TID of zero
+ to represent all kernel pages as shared among all contexts.
+ -- Dan
+ */
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+#ifdef CONFIG_8xx
+#define NO_CONTEXT 16
+#define LAST_CONTEXT 15
+#define FIRST_CONTEXT 0
+
+#elif defined(CONFIG_4xx)
+#define NO_CONTEXT 256
+#define LAST_CONTEXT 255
+#define FIRST_CONTEXT 1
+
+#elif defined(CONFIG_E200) || defined(CONFIG_E500)
+#define NO_CONTEXT 256
+#define LAST_CONTEXT 255
+#define FIRST_CONTEXT 1
+
+#else
+
+/* PPC 6xx, 7xx CPUs */
+#define NO_CONTEXT ((unsigned long) -1)
+#define LAST_CONTEXT 32767
+#define FIRST_CONTEXT 1
+#endif
+
+/*
+ * Set the current MMU context.
+ * On 32-bit PowerPCs (other than the 8xx embedded chips), this is done by
+ * loading up the segment registers for the user part of the address space.
+ *
+ * Since the PGD is immediately available, it is much faster to simply
+ * pass this along as a second parameter, which is required for 8xx and
+ * can be used for debugging on all processors (if you happen to have
+ * an Abatron).
+ */
+extern void set_context(unsigned long contextid, pgd_t *pgd);
+
+/*
+ * Bitmap of contexts in use.
+ * The size of this bitmap is LAST_CONTEXT + 1 bits.
+ */
+extern unsigned long context_map[];
+
+/*
+ * This caches the next context number that we expect to be free.
+ * Its use is an optimization only, we can't rely on this context
+ * number to be free, but it usually will be.
+ */
+extern unsigned long next_mmu_context;
+
+/*
+ * If we don't have sufficient contexts to give one to every task
+ * that could be in the system, we need to be able to steal contexts.
+ * These variables support that.
+ */
+#if LAST_CONTEXT < 30000
+#define FEW_CONTEXTS 1
+extern atomic_t nr_free_contexts;
+extern struct mm_struct *context_mm[LAST_CONTEXT+1];
+extern void steal_context(void);
+#endif
+
+/*
+ * Get a new mmu context for the address space described by `mm'.
+ */
+static inline void get_mmu_context(struct mm_struct *mm)
+{
+ unsigned long ctx;
+
+ if (mm->context.id != NO_CONTEXT)
+ return;
+#ifdef FEW_CONTEXTS
+ while (atomic_dec_if_positive(&nr_free_contexts) < 0)
+ steal_context();
+#endif
+ ctx = next_mmu_context;
+ while (test_and_set_bit(ctx, context_map)) {
+ ctx = find_next_zero_bit(context_map, LAST_CONTEXT+1, ctx);
+ if (ctx > LAST_CONTEXT)
+ ctx = 0;
+ }
+ next_mmu_context = (ctx + 1) & LAST_CONTEXT;
+ mm->context.id = ctx;
+#ifdef FEW_CONTEXTS
+ context_mm[ctx] = mm;
+#endif
+}
+
+/*
+ * Set up the context for a new address space.
+ */
+static inline int init_new_context(struct task_struct *t, struct mm_struct *mm)
+{
+ mm->context.id = NO_CONTEXT;
+ mm->context.vdso_base = 0;
+ return 0;
+}
+
+/*
+ * We're finished using the context for an address space.
+ */
+static inline void destroy_context(struct mm_struct *mm)
+{
+ preempt_disable();
+ if (mm->context.id != NO_CONTEXT) {
+ clear_bit(mm->context.id, context_map);
+ mm->context.id = NO_CONTEXT;
+#ifdef FEW_CONTEXTS
+ atomic_inc(&nr_free_contexts);
+#endif
+ }
+ preempt_enable();
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk)
+{
+#ifdef CONFIG_ALTIVEC
+ if (cpu_has_feature(CPU_FTR_ALTIVEC))
+ asm volatile ("dssall;\n"
+#ifndef CONFIG_POWER4
+ "sync;\n" /* G4 needs a sync here, G5 apparently not */
+#endif
+ : : );
+#endif /* CONFIG_ALTIVEC */
+
+ tsk->thread.pgdir = next->pgd;
+
+ /* No need to flush userspace segments if the mm doesnt change */
+ if (prev == next)
+ return;
+
+ /* Setup new userspace context */
+ get_mmu_context(next);
+ set_context(next->context.id, next->pgd);
+}
+
+#define deactivate_mm(tsk,mm) do { } while (0)
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+#define activate_mm(active_mm, mm) switch_mm(active_mm, mm, current)
+
+extern void mmu_context_init(void);
+
+
#else
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/sched.h>
-#include <asm/mmu.h>
-#include <asm/cputable.h>
-#include <asm-generic/mm_hooks.h>
/*
* Copyright (C) 2001 PPC 64 Team, IBM Corp
diff --git a/include/asm-powerpc/mpc86xx.h b/include/asm-powerpc/mpc86xx.h
index b85df45b1a84..15f650f987e7 100644
--- a/include/asm-powerpc/mpc86xx.h
+++ b/include/asm-powerpc/mpc86xx.h
@@ -19,12 +19,6 @@
#ifdef CONFIG_PPC_86xx
-#define _IO_BASE isa_io_base
-#define _ISA_MEM_BASE isa_mem_base
-#ifdef CONFIG_PCI
-#define PCI_DRAM_OFFSET pci_dram_offset
-#endif
-
#define CPU0_BOOT_RELEASE 0x01000000
#define CPU1_BOOT_RELEASE 0x02000000
#define CPU_ALL_RELEASED (CPU0_BOOT_RELEASE | CPU1_BOOT_RELEASE)
diff --git a/include/asm-powerpc/mpc8xx.h b/include/asm-powerpc/mpc8xx.h
index 580371120e1a..2be014b6f57c 100644
--- a/include/asm-powerpc/mpc8xx.h
+++ b/include/asm-powerpc/mpc8xx.h
@@ -23,6 +23,10 @@
#include <platforms/8xx/mpc885ads.h>
#endif
+#ifdef CONFIG_PCMCIA_M8XX
+extern struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops;
+#endif
+
#endif /* CONFIG_8xx */
#endif /* __CONFIG_8xx_DEFS */
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index 2ffb06abe881..262db6b8da73 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -296,6 +296,9 @@ struct mpic
unsigned int dcr_base;
#endif
+ /* Protected sources */
+ unsigned long *protected;
+
#ifdef CONFIG_MPIC_WEIRD
/* Pointer to HW info array */
u32 *hw_set;
diff --git a/include/asm-powerpc/of_device.h b/include/asm-powerpc/of_device.h
index e9af49eb1aa8..ec2a8a2c737c 100644
--- a/include/asm-powerpc/of_device.h
+++ b/include/asm-powerpc/of_device.h
@@ -3,14 +3,12 @@
#ifdef __KERNEL__
#include <linux/device.h>
-#include <linux/mod_devicetable.h>
-#include <asm/prom.h>
-
+#include <linux/of.h>
/*
* The of_device is a kind of "base class" that is a superset of
* struct device for use by devices attached to an OF node and
- * probed using OF properties
+ * probed using OF properties.
*/
struct of_device
{
@@ -18,24 +16,14 @@ struct of_device
u64 dma_mask; /* DMA mask */
struct device dev; /* Generic device interface */
};
-#define to_of_device(d) container_of(d, struct of_device, dev)
-
-extern const struct of_device_id *of_match_node(
- const struct of_device_id *matches, const struct device_node *node);
-extern const struct of_device_id *of_match_device(
- const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern void of_release_dev(struct device *dev);
extern ssize_t of_device_get_modalias(struct of_device *ofdev,
char *str, ssize_t len);
extern int of_device_uevent(struct device *dev,
char **envp, int num_envp, char *buffer, int buffer_size);
+/* This is just here during the transition */
+#include <linux/of_device.h>
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/include/asm-powerpc/of_platform.h b/include/asm-powerpc/of_platform.h
index 217eafb167e9..80e6fad28b4f 100644
--- a/include/asm-powerpc/of_platform.h
+++ b/include/asm-powerpc/of_platform.h
@@ -1,3 +1,5 @@
+#ifndef _ASM_POWERPC_OF_PLATFORM_H
+#define _ASM_POWERPC_OF_PLATFORM_H
/*
* Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
* <benh@kernel.crashing.org>
@@ -9,37 +11,8 @@
*
*/
-#include <asm/of_device.h>
-
-/*
- * The of_platform_bus_type is a bus type used by drivers that do not
- * attach to a macio or similar bus but still use OF probing
- * mechanism
- */
-extern struct bus_type of_platform_bus_type;
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the "platform bus" (of_platform_bus_type)
- */
-struct of_platform_driver
-{
- char *name;
- struct of_device_id *match_table;
- struct module *owner;
-
- int (*probe)(struct of_device* dev,
- const struct of_device_id *match);
- int (*remove)(struct of_device* dev);
-
- int (*suspend)(struct of_device* dev, pm_message_t state);
- int (*resume)(struct of_device* dev);
- int (*shutdown)(struct of_device* dev);
-
- struct device_driver driver;
-};
-#define to_of_platform_driver(drv) \
- container_of(drv,struct of_platform_driver, driver)
+/* This is just here during the transition */
+#include <linux/of_platform.h>
/* Platform drivers register/unregister */
extern int of_register_platform_driver(struct of_platform_driver *drv);
@@ -56,5 +29,6 @@ extern int of_platform_bus_probe(struct device_node *root,
struct of_device_id *matches,
struct device *parent);
-extern struct of_device *of_find_device_by_node(struct device_node *np);
extern struct of_device *of_find_device_by_phandle(phandle ph);
+
+#endif /* _ASM_POWERPC_OF_PLATFORM_H */
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index 8d6b47f7b300..938fefb4c4bc 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -39,14 +39,16 @@ struct op_system_config {
/* Per-arch configuration */
struct op_powerpc_model {
- void (*reg_setup) (struct op_counter_config *,
+ int (*reg_setup) (struct op_counter_config *,
struct op_system_config *,
int num_counters);
- void (*cpu_setup) (struct op_counter_config *);
- void (*start) (struct op_counter_config *);
- void (*global_start) (struct op_counter_config *);
+ int (*cpu_setup) (struct op_counter_config *);
+ int (*start) (struct op_counter_config *);
+ int (*global_start) (struct op_counter_config *);
void (*stop) (void);
void (*global_stop) (void);
+ int (*sync_start)(void);
+ int (*sync_stop)(void);
void (*handle_interrupt) (struct pt_regs *,
struct op_counter_config *);
int num_counters;
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index d9bf5aba96cb..e72c2a60853c 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -2,12 +2,91 @@
#define _ASM_POWERPC_PCI_BRIDGE_H
#ifdef __KERNEL__
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/ioport.h>
+
#ifndef CONFIG_PPC64
-#include <asm-ppc/pci-bridge.h>
+
+struct device_node;
+struct pci_controller;
+
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+struct pci_controller {
+ struct pci_bus *bus;
+ char is_dynamic;
+ void *arch_data;
+ struct list_head list_node;
+ struct device *parent;
+
+ int first_busno;
+ int last_busno;
+ int self_busno;
+
+ void __iomem *io_base_virt;
+ resource_size_t io_base_phys;
+
+ /* Some machines (PReP) have a non 1:1 mapping of
+ * the PCI memory space in the CPU bus space
+ */
+ resource_size_t pci_mem_offset;
+
+ struct pci_ops *ops;
+ volatile unsigned int __iomem *cfg_addr;
+ volatile void __iomem *cfg_data;
+
+ /*
+ * Used for variants of PCI indirect handling and possible quirks:
+ * SET_CFG_TYPE - used on 4xx or any PHB that does explicit type0/1
+ * EXT_REG - provides access to PCI-e extended registers
+ * SURPRESS_PRIMARY_BUS - we surpress the setting of PCI_PRIMARY_BUS
+ * on Freescale PCI-e controllers since they used the PCI_PRIMARY_BUS
+ * to determine which bus number to match on when generating type0
+ * config cycles
+ */
+#define PPC_INDIRECT_TYPE_SET_CFG_TYPE (0x00000001)
+#define PPC_INDIRECT_TYPE_EXT_REG (0x00000002)
+#define PPC_INDIRECT_TYPE_SURPRESS_PRIMARY_BUS (0x00000004)
+ u32 indirect_type;
+
+ /* Currently, we limit ourselves to 1 IO range and 3 mem
+ * ranges since the common pci_bus structure can't handle more
+ */
+ struct resource io_resource;
+ struct resource mem_resources[3];
+ int global_number; /* PCI domain number */
+};
+
+static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
+{
+ return bus->sysdata;
+}
+
+/* These are used for config access before all the PCI probing
+ has been done. */
+int early_read_config_byte(struct pci_controller *hose, int bus, int dev_fn,
+ int where, u8 *val);
+int early_read_config_word(struct pci_controller *hose, int bus, int dev_fn,
+ int where, u16 *val);
+int early_read_config_dword(struct pci_controller *hose, int bus, int dev_fn,
+ int where, u32 *val);
+int early_write_config_byte(struct pci_controller *hose, int bus, int dev_fn,
+ int where, u8 val);
+int early_write_config_word(struct pci_controller *hose, int bus, int dev_fn,
+ int where, u16 val);
+int early_write_config_dword(struct pci_controller *hose, int bus, int dev_fn,
+ int where, u32 val);
+
+extern void setup_indirect_pci_nomap(struct pci_controller* hose,
+ void __iomem *cfg_addr, void __iomem *cfg_data);
+extern void setup_indirect_pci(struct pci_controller* hose,
+ u32 cfg_addr, u32 cfg_data);
+extern void setup_grackle(struct pci_controller *hose);
+
#else
-#include <linux/pci.h>
-#include <linux/list.h>
/*
* This program is free software; you can redistribute it and/or
@@ -31,6 +110,7 @@ struct pci_controller {
int last_busno;
void __iomem *io_base_virt;
+ void *io_base_alloc;
resource_size_t io_base_phys;
/* Some machines have a non 1:1 mapping of
@@ -48,8 +128,7 @@ struct pci_controller {
*/
struct resource io_resource;
struct resource mem_resources[3];
- int global_number;
- int local_number;
+ int global_number;
unsigned long buid;
unsigned long dma_window_base_cur;
unsigned long dma_window_size;
@@ -70,19 +149,22 @@ struct pci_dn {
int devfn; /* pci device and function number */
int class_code; /* pci device class */
-#ifdef CONFIG_PPC_PSERIES
+ struct pci_controller *phb; /* for pci devices */
+ struct iommu_table *iommu_table; /* for phb's or bridges */
+ struct pci_dev *pcidev; /* back-pointer to the pci device */
+ struct device_node *node; /* back-pointer to the device_node */
+
+ int pci_ext_config_space; /* for pci devices */
+
+#ifdef CONFIG_EEH
int eeh_mode; /* See eeh.h for possible EEH_MODEs */
int eeh_config_addr;
int eeh_pe_config_addr; /* new-style partition endpoint address */
int eeh_check_count; /* # times driver ignored error */
int eeh_freeze_count; /* # times this device froze up. */
-#endif
- int pci_ext_config_space; /* for pci devices */
- struct pci_controller *phb; /* for pci devices */
- struct iommu_table *iommu_table; /* for phb's or bridges */
- struct pci_dev *pcidev; /* back-pointer to the pci device */
- struct device_node *node; /* back-pointer to the device_node */
+ int eeh_false_positives; /* # times this device reported #ff's */
u32 config_space[16]; /* saved PCI config space */
+#endif
};
/* Get the pointer to a device_node's pci_dn */
@@ -128,9 +210,6 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
/** Find the bus corresponding to the indicated device node */
struct pci_bus * pcibios_find_pci_bus(struct device_node *dn);
-extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
- struct device_node *dev, int primary);
-
/** Remove all of the PCI devices under this bus */
void pcibios_remove_pci_devices(struct pci_bus *bus);
@@ -148,13 +227,38 @@ static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
return PCI_DN(busdn)->phb;
}
+extern void pcibios_free_controller(struct pci_controller *phb);
+
+extern void isa_bridge_find_early(struct pci_controller *hose);
+
+extern int pcibios_unmap_io_space(struct pci_bus *bus);
+extern int pcibios_map_io_space(struct pci_bus *bus);
+
+/* Return values for ppc_md.pci_probe_mode function */
+#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */
+#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
+#define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */
+
+#ifdef CONFIG_NUMA
+#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = (NODE))
+#else
+#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = -1)
+#endif
+
+#endif /* CONFIG_PPC64 */
+
+/* Get the PCI host controller for an OF device */
extern struct pci_controller*
pci_find_hose_for_OF_device(struct device_node* node);
+/* Fill up host controller resources from the OF node */
+extern void
+pci_process_bridge_OF_ranges(struct pci_controller *hose,
+ struct device_node *dev, int primary);
+
+/* Allocate a new PCI host bridge structure */
extern struct pci_controller *
pcibios_alloc_controller(struct device_node *dev);
-extern void pcibios_free_controller(struct pci_controller *phb);
-
#ifdef CONFIG_PCI
extern unsigned long pci_address_to_pio(phys_addr_t address);
#else
@@ -164,17 +268,7 @@ static inline unsigned long pci_address_to_pio(phys_addr_t address)
}
#endif
-/* Return values for ppc_md.pci_probe_mode function */
-#define PCI_PROBE_NONE -1 /* Don't look at this bus at all */
-#define PCI_PROBE_NORMAL 0 /* Do normal PCI probing */
-#define PCI_PROBE_DEVTREE 1 /* Instantiate from device tree */
-#ifdef CONFIG_NUMA
-#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = (NODE))
-#else
-#define PHB_SET_NODE(PHB, NODE) ((PHB)->node = -1)
-#endif
-#endif /* CONFIG_PPC64 */
#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h
index ce0f13e8eb14..7b11765c6865 100644
--- a/include/asm-powerpc/pci.h
+++ b/include/asm-powerpc/pci.h
@@ -74,18 +74,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
extern struct dma_mapping_ops *get_pci_dma_ops(void);
-/* For DAC DMA, we currently don't support it by default, but
- * we let 64-bit platforms override this.
- */
-static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
-{
- struct dma_mapping_ops *d = get_pci_dma_ops();
-
- if (d && d->dac_dma_supported)
- return d->dac_dma_supported(&hwdev->dev, mask);
- return 0;
-}
-
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
unsigned long *strategy_parameter)
@@ -107,8 +95,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
#define get_pci_dma_ops() NULL
#endif
-extern int pci_domain_nr(struct pci_bus *bus);
-
/* Decide whether to display the domain number in /proc */
extern int pci_proc_domain(struct pci_bus *bus);
@@ -124,15 +110,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
}
#endif
-/*
- * At present there are very few 32-bit PPC machines that can have
- * memory above the 4GB point, and we don't support that.
- */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
-/* Return the index of the PCI controller for device PDEV. */
-#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
-
/* Set the name of the bus as it appears in /proc/bus/pci */
static inline int pci_proc_domain(struct pci_bus *bus)
{
@@ -141,6 +118,8 @@ static inline int pci_proc_domain(struct pci_bus *bus)
#endif /* CONFIG_PPC64 */
+extern int pci_domain_nr(struct pci_bus *bus);
+
struct vm_area_struct;
/* Map a range of PCI memory or I/O space for a device into user space */
int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
@@ -220,10 +199,6 @@ static inline struct resource *pcibios_select_root(struct pci_dev *pdev,
return root;
}
-extern int unmap_bus_range(struct pci_bus *bus);
-
-extern int remap_bus_range(struct pci_bus *bus);
-
extern void pcibios_fixup_device_resources(struct pci_dev *dev,
struct pci_bus *bus);
@@ -243,8 +218,6 @@ extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
extern int pci_read_irq_line(struct pci_dev *dev);
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
-
struct file;
extern pgprot_t pci_phys_mem_access_prot(struct file *file,
unsigned long pfn,
diff --git a/include/asm-powerpc/percpu.h b/include/asm-powerpc/percpu.h
index 2f2e3024fa61..73dc8ba4010d 100644
--- a/include/asm-powerpc/percpu.h
+++ b/include/asm-powerpc/percpu.h
@@ -20,6 +20,11 @@
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ __attribute__((__section__(".data.percpu.shared_aligned"))) \
+ __typeof__(type) per_cpu__##name \
+ ____cacheline_aligned_in_smp
+
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)))
#define __get_cpu_var(var) (*RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()))
@@ -40,6 +45,8 @@ extern void setup_per_cpu_areas(void);
#define DEFINE_PER_CPU(type, name) \
__typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ DEFINE_PER_CPU(type, name)
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
diff --git a/include/asm-powerpc/pgtable-ppc32.h b/include/asm-powerpc/pgtable-ppc32.h
index 7fb730c62f83..86a54a4a8a2a 100644
--- a/include/asm-powerpc/pgtable-ppc32.h
+++ b/include/asm-powerpc/pgtable-ppc32.h
@@ -6,11 +6,7 @@
#ifndef __ASSEMBLY__
#include <linux/sched.h>
#include <linux/threads.h>
-#include <asm/processor.h> /* For TASK_SIZE */
-#include <asm/mmu.h>
-#include <asm/page.h>
#include <asm/io.h> /* For sub-arch specific PPC_PIN_SIZE */
-struct mm_struct;
extern unsigned long va_to_phys(unsigned long address);
extern pte_t *va_to_pte(unsigned long address);
@@ -488,14 +484,6 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
#define pfn_pte(pfn, prot) __pte(((pte_basic_t)(pfn) << PFN_SHIFT_OFFSET) |\
pgprot_val(prot))
#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)
-
-/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern unsigned long empty_zero_page[1024];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
-
#endif /* __ASSEMBLY__ */
#define pte_none(pte) ((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
@@ -512,9 +500,7 @@ extern unsigned long empty_zero_page[1024];
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
-static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; }
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; }
@@ -522,21 +508,13 @@ static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
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; }
-static inline pte_t pte_rdprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_USER; return pte; }
static inline pte_t pte_wrprotect(pte_t pte) {
pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
-static inline pte_t pte_exprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_EXEC; return pte; }
static inline pte_t pte_mkclean(pte_t pte) {
pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
static inline pte_t pte_mkold(pte_t pte) {
pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkread(pte_t pte) {
- pte_val(pte) |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) {
- pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) {
pte_val(pte) |= _PAGE_RW; return pte; }
static inline pte_t pte_mkdirty(pte_t pte) {
@@ -643,13 +621,6 @@ static inline int __ptep_test_and_clear_young(unsigned int context, unsigned lon
#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
__ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep)
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma,
- unsigned long addr, pte_t *ptep)
-{
- return (pte_update(ptep, (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0;
-}
-
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
@@ -734,10 +705,6 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-
-extern void paging_init(void);
-
/*
* Encode and decode a swap entry.
* Note that the bits we use in a PTE for representing a swap entry
@@ -755,40 +722,6 @@ extern void paging_init(void);
#define pte_to_pgoff(pte) (pte_val(pte) >> 3)
#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE })
-/* CONFIG_APUS */
-/* For virtual address to physical address conversion */
-extern void cache_clear(__u32 addr, int length);
-extern void cache_push(__u32 addr, int length);
-extern int mm_end_of_chunk (unsigned long addr, int len);
-extern unsigned long iopa(unsigned long addr);
-extern unsigned long mm_ptov(unsigned long addr) __attribute_const__;
-
-/* Values for nocacheflag and cmode */
-/* These are not used by the APUS kernel_map, but prevents
- compilation errors. */
-#define KERNELMAP_FULL_CACHING 0
-#define KERNELMAP_NOCACHE_SER 1
-#define KERNELMAP_NOCACHE_NONSER 2
-#define KERNELMAP_NO_COPYBACK 3
-
-/*
- * Map some physical address range into the kernel address space.
- */
-extern unsigned long kernel_map(unsigned long paddr, unsigned long size,
- int nocacheflag, unsigned long *memavailp );
-
-/*
- * Set cache mode of (kernel space) address range.
- */
-extern void kernel_set_cachemode (unsigned long address, unsigned long size,
- unsigned int cmode);
-
-/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
-#define kern_addr_valid(addr) (1)
-
-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
- remap_pfn_range(vma, vaddr, pfn, size, prot)
-
/*
* No page table caches to initialise
*/
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h
index 3cfd98f44bfe..300f9a199bf2 100644
--- a/include/asm-powerpc/pgtable-ppc64.h
+++ b/include/asm-powerpc/pgtable-ppc64.h
@@ -7,11 +7,7 @@
#ifndef __ASSEMBLY__
#include <linux/stddef.h>
-#include <asm/processor.h> /* For TASK_SIZE */
-#include <asm/mmu.h>
-#include <asm/page.h>
#include <asm/tlbflush.h>
-struct mm_struct;
#endif /* __ASSEMBLY__ */
#ifdef CONFIG_PPC_64K_PAGES
@@ -27,7 +23,7 @@ struct mm_struct;
*/
#define PGTABLE_EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
PUD_INDEX_SIZE + PGD_INDEX_SIZE + PAGE_SHIFT)
-#define PGTABLE_RANGE (1UL << PGTABLE_EADDR_SIZE)
+#define PGTABLE_RANGE (ASM_CONST(1) << PGTABLE_EADDR_SIZE)
#if TASK_SIZE_USER64 > PGTABLE_RANGE
#error TASK_SIZE_USER64 exceeds pagetable range
@@ -37,19 +33,28 @@ struct mm_struct;
#error TASK_SIZE_USER64 exceeds user VSID range
#endif
+
/*
* Define the address range of the vmalloc VM area.
*/
#define VMALLOC_START ASM_CONST(0xD000000000000000)
-#define VMALLOC_SIZE ASM_CONST(0x80000000000)
+#define VMALLOC_SIZE (PGTABLE_RANGE >> 1)
#define VMALLOC_END (VMALLOC_START + VMALLOC_SIZE)
/*
- * Define the address range of the imalloc VM area.
+ * Define the address ranges for MMIO and IO space :
+ *
+ * ISA_IO_BASE = VMALLOC_END, 64K reserved area
+ * PHB_IO_BASE = ISA_IO_BASE + 64K to ISA_IO_BASE + 2G, PHB IO spaces
+ * IOREMAP_BASE = ISA_IO_BASE + 2G to VMALLOC_START + PGTABLE_RANGE
*/
-#define PHBS_IO_BASE VMALLOC_END
-#define IMALLOC_BASE (PHBS_IO_BASE + 0x80000000ul) /* Reserve 2 gigs for PHBs */
-#define IMALLOC_END (VMALLOC_START + PGTABLE_RANGE)
+#define FULL_IO_SIZE 0x80000000ul
+#define ISA_IO_BASE (VMALLOC_END)
+#define ISA_IO_END (VMALLOC_END + 0x10000ul)
+#define PHB_IO_BASE (ISA_IO_END)
+#define PHB_IO_END (VMALLOC_END + FULL_IO_SIZE)
+#define IOREMAP_BASE (PHB_IO_END)
+#define IOREMAP_END (VMALLOC_START + PGTABLE_RANGE)
/*
* Region IDs
@@ -134,16 +139,6 @@ struct mm_struct;
#define __S110 PAGE_SHARED_X
#define __S111 PAGE_SHARED_X
-#ifndef __ASSEMBLY__
-
-/*
- * ZERO_PAGE is a global shared page that is always zero: used
- * for zero-mapped memory areas etc..
- */
-extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
-#endif /* __ASSEMBLY__ */
-
#ifdef CONFIG_HUGETLB_PAGE
#define HAVE_ARCH_UNMAPPED_AREA
@@ -232,9 +227,7 @@ static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER;}
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW;}
-static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC;}
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;}
@@ -242,20 +235,12 @@ static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE;}
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; }
-static inline pte_t pte_rdprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_USER; return pte; }
-static inline pte_t pte_exprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_EXEC; return pte; }
static inline pte_t pte_wrprotect(pte_t pte) {
pte_val(pte) &= ~(_PAGE_RW); return pte; }
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; }
-static inline pte_t pte_mkread(pte_t pte) {
- pte_val(pte) |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) {
- pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) {
pte_val(pte) |= _PAGE_RW; return pte; }
static inline pte_t pte_mkdirty(pte_t pte) {
@@ -307,29 +292,6 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
__r; \
})
-/*
- * On RW/DIRTY bit transitions we can avoid flushing the hpte. For the
- * moment we always flush but we need to fix hpte_update and test if the
- * optimisation is worth it.
- */
-static inline int __ptep_test_and_clear_dirty(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- unsigned long old;
-
- if ((pte_val(*ptep) & _PAGE_DIRTY) == 0)
- return 0;
- old = pte_update(mm, addr, ptep, _PAGE_DIRTY, 0);
- return (old & _PAGE_DIRTY) != 0;
-}
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define ptep_test_and_clear_dirty(__vma, __addr, __ptep) \
-({ \
- int __r; \
- __r = __ptep_test_and_clear_dirty((__vma)->vm_mm, __addr, __ptep); \
- __r; \
-})
-
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
@@ -357,14 +319,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
__young; \
})
-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
-#define ptep_clear_flush_dirty(__vma, __address, __ptep) \
-({ \
- int __dirty = __ptep_test_and_clear_dirty((__vma)->vm_mm, __address, \
- __ptep); \
- __dirty; \
-})
-
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
@@ -442,10 +396,6 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
-extern pgd_t swapper_pg_dir[];
-
-extern void paging_init(void);
-
/* Encode and de-code a swap entry */
#define __swp_type(entry) (((entry).val >> 1) & 0x3f)
#define __swp_offset(entry) ((entry).val >> 8)
@@ -456,17 +406,6 @@ extern void paging_init(void);
#define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE})
#define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT)
-/*
- * kern_addr_valid is intended to indicate whether an address is a valid
- * kernel address. Most 32-bit archs define it as always true (like this)
- * but most 64-bit archs actually perform a test. What should we do here?
- * The only use is in fs/ncpfs/dir.c
- */
-#define kern_addr_valid(addr) (1)
-
-#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
- remap_pfn_range(vma, vaddr, pfn, size, prot)
-
void pgtable_cache_init(void);
/*
diff --git a/include/asm-powerpc/pgtable.h b/include/asm-powerpc/pgtable.h
index 78bf4ae712a6..d18ffe7bc7c4 100644
--- a/include/asm-powerpc/pgtable.h
+++ b/include/asm-powerpc/pgtable.h
@@ -2,6 +2,13 @@
#define _ASM_POWERPC_PGTABLE_H
#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+#include <asm/processor.h> /* For TASK_SIZE */
+#include <asm/mmu.h>
+#include <asm/page.h>
+struct mm_struct;
+#endif /* !__ASSEMBLY__ */
+
#if defined(CONFIG_PPC64)
# include <asm/pgtable-ppc64.h>
#else
@@ -9,6 +16,27 @@
#endif
#ifndef __ASSEMBLY__
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern pgd_t swapper_pg_dir[];
+
+extern void paging_init(void);
+
+/*
+ * kern_addr_valid is intended to indicate whether an address is a valid
+ * kernel address. Most 32-bit archs define it as always true (like this)
+ * but most 64-bit archs actually perform a test. What should we do here?
+ */
+#define kern_addr_valid(addr) (1)
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
#include <asm-generic/pgtable.h>
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-powerpc/pmi.h b/include/asm-powerpc/pmi.h
index cb0f8aa43088..2259d4ce3846 100644
--- a/include/asm-powerpc/pmi.h
+++ b/include/asm-powerpc/pmi.h
@@ -55,13 +55,13 @@ typedef struct {
struct pmi_handler {
struct list_head node;
u8 type;
- void (*handle_pmi_message) (struct of_device *, pmi_message_t);
+ void (*handle_pmi_message) (pmi_message_t);
};
-void pmi_register_handler(struct of_device *, struct pmi_handler *);
-void pmi_unregister_handler(struct of_device *, struct pmi_handler *);
+int pmi_register_handler(struct pmi_handler *);
+void pmi_unregister_handler(struct pmi_handler *);
-void pmi_send_message(struct of_device *, pmi_message_t);
+int pmi_send_message(pmi_message_t);
#endif /* __KERNEL__ */
#endif /* _POWERPC_PMI_H */
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index 8e2005159ffd..b847aa10074b 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -26,7 +26,7 @@ extern int global_phb_number;
extern void find_and_init_phbs(void);
-extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */
+extern struct pci_dev *isa_bridge_pcidev; /* may be NULL if no ISA bus */
/** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
#define BUID_HI(buid) ((buid) >> 32)
@@ -47,8 +47,8 @@ extern void init_pci_config_tokens (void);
extern unsigned long get_phb_buid (struct device_node *);
extern int rtas_setup_phb(struct pci_controller *phb);
-/* From pSeries_pci.h */
-extern void pSeries_final_fixup(void);
+/* From iSeries PCI */
+extern void iSeries_pcibios_init(void);
extern unsigned long pci_probe_only;
@@ -139,6 +139,9 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag);
*/
struct device_node * find_device_pe(struct device_node *dn);
+void eeh_sysfs_add_device(struct pci_dev *pdev);
+void eeh_sysfs_remove_device(struct pci_dev *pdev);
+
#endif /* CONFIG_EEH */
#else /* CONFIG_PCI */
diff --git a/include/asm-powerpc/processor.h b/include/asm-powerpc/processor.h
index d947b1609491..e28b10805159 100644
--- a/include/asm-powerpc/processor.h
+++ b/include/asm-powerpc/processor.h
@@ -43,14 +43,6 @@ extern int _chrp_type;
/* what kind of prep workstation we are */
extern int _prep_type;
-/*
- * This is used to identify the board type from a given PReP board
- * vendor. Board revision is also made available. This will be moved
- * elsewhere soon
- */
-extern unsigned char ucBoardRev;
-extern unsigned char ucBoardRevMaj, ucBoardRevMin;
-
#endif /* CONFIG_PPC_PREP */
#endif /* defined(__KERNEL__) && defined(CONFIG_PPC32) */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 6845af93ba91..672083787a1d 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -21,6 +21,13 @@
#include <asm/irq.h>
#include <asm/atomic.h>
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+
+#define of_compat_cmp(s1, s2, l) strncasecmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
+#define of_node_cmp(s1, s2) strcasecmp((s1), (s2))
+
/* Definitions used by the flattened device tree */
#define OF_DT_HEADER 0xd00dfeed /* marker */
#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */
@@ -97,11 +104,16 @@ struct device_node {
extern struct device_node *of_chosen;
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
+static inline int of_node_check_flag(struct device_node *n, unsigned long flag)
+{
+ return test_bit(flag, &n->_flags);
+}
+
+static inline void of_node_set_flag(struct device_node *n, unsigned long flag)
+{
+ set_bit(flag, &n->_flags);
+}
-#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
-#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
#define HAVE_ARCH_DEVTREE_FIXUPS
@@ -111,28 +123,7 @@ static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_e
}
-/* New style node lookup */
-extern struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name);
-#define for_each_node_by_name(dn, name) \
- for (dn = of_find_node_by_name(NULL, name); dn; \
- dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
- const char *type);
-#define for_each_node_by_type(dn, type) \
- for (dn = of_find_node_by_type(NULL, type); dn; \
- dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
- const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
extern struct device_node *of_find_all_nodes(struct device_node *prev);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
- struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp);
extern struct device_node *of_node_get(struct device_node *node);
extern void of_node_put(struct device_node *node);
@@ -148,23 +139,15 @@ extern unsigned long __init of_get_flat_dt_root(void);
/* For updating the device tree at runtime */
extern void of_attach_node(struct device_node *);
-extern void of_detach_node(const struct device_node *);
+extern void of_detach_node(struct device_node *);
/* Other Prototypes */
extern void finish_device_tree(void);
extern void unflatten_device_tree(void);
extern void early_init_devtree(void *);
-extern int of_device_is_compatible(const struct device_node *device,
- const char *);
#define device_is_compatible(d, c) of_device_is_compatible((d), (c))
extern int machine_is_compatible(const char *compat);
-extern const void *of_get_property(const struct device_node *node,
- const char *name,
- int *lenp);
-#define get_property(a, b, c) of_get_property((a), (b), (c))
extern void print_properties(struct device_node *node);
-extern int of_n_addr_cells(struct device_node* np);
-extern int of_n_size_cells(struct device_node* np);
extern int prom_n_intr_cells(struct device_node* np);
extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
extern int prom_add_property(struct device_node* np, struct property* prop);
@@ -218,7 +201,6 @@ static inline unsigned long of_read_ulong(const u32 *cell, int size)
/* Translate an OF address block into a CPU physical address
*/
-#define OF_BAD_ADDR ((u64)-1)
extern u64 of_translate_address(struct device_node *np, const u32 *addr);
/* Extract an address from a device, returns the region size and
@@ -345,5 +327,11 @@ extern int of_irq_to_resource(struct device_node *dev, int index,
*/
extern void __iomem *of_iomap(struct device_node *device, int index);
+/*
+ * NB: This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
#endif /* __KERNEL__ */
#endif /* _POWERPC_PROM_H */
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 1e04651eedc4..a6f3f5ee7ca7 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -35,7 +35,8 @@ union ps3_firmware_version {
};
};
-int ps3_get_firmware_version(union ps3_firmware_version *v);
+void ps3_get_firmware_version(union ps3_firmware_version *v);
+int ps3_compare_firmware_version(u16 major, u16 minor, u16 rev);
/* 'Other OS' area */
@@ -48,18 +49,6 @@ enum ps3_param_av_multi_out {
enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void);
-/**
- * struct ps3_device_id - HV bus device identifier from the system repository
- * @bus_id: HV bus id, {1..} (zero invalid)
- * @dev_id: HV device id, {0..}
- */
-
-struct ps3_device_id {
- unsigned int bus_id;
- unsigned int dev_id;
-};
-
-
/* dma routines */
enum ps3_dma_page_size {
@@ -74,6 +63,8 @@ enum ps3_dma_region_type {
PS3_DMA_INTERNAL = 2,
};
+struct ps3_dma_region_ops;
+
/**
* struct ps3_dma_region - A per device dma state variables structure
* @did: The HV device id.
@@ -81,21 +72,42 @@ enum ps3_dma_region_type {
* @region_type: The HV region type.
* @bus_addr: The 'translated' bus address of the region.
* @len: The length in bytes of the region.
+ * @offset: The offset from the start of memory of the region.
+ * @ioid: The IOID of the device who owns this region
* @chunk_list: Opaque variable used by the ioc page manager.
+ * @region_ops: struct ps3_dma_region_ops - dma region operations
*/
struct ps3_dma_region {
- struct ps3_device_id did;
+ struct ps3_system_bus_device *dev;
+ /* device variables */
+ const struct ps3_dma_region_ops *region_ops;
+ unsigned char ioid;
enum ps3_dma_page_size page_size;
enum ps3_dma_region_type region_type;
- unsigned long bus_addr;
unsigned long len;
+ unsigned long offset;
+
+ /* driver variables (set by ps3_dma_region_create) */
+ unsigned long bus_addr;
struct {
spinlock_t lock;
struct list_head head;
} chunk_list;
};
+struct ps3_dma_region_ops {
+ int (*create)(struct ps3_dma_region *);
+ int (*free)(struct ps3_dma_region *);
+ int (*map)(struct ps3_dma_region *,
+ unsigned long virt_addr,
+ unsigned long len,
+ unsigned long *bus_addr,
+ u64 iopte_pp);
+ int (*unmap)(struct ps3_dma_region *,
+ unsigned long bus_addr,
+ unsigned long len);
+};
/**
* struct ps3_dma_region_init - Helper to initialize structure variables
*
@@ -103,18 +115,16 @@ struct ps3_dma_region {
* ps3_system_bus_device_register.
*/
-static inline void ps3_dma_region_init(struct ps3_dma_region *r,
- const struct ps3_device_id* did, enum ps3_dma_page_size page_size,
- enum ps3_dma_region_type region_type)
-{
- r->did = *did;
- r->page_size = page_size;
- r->region_type = region_type;
-}
+struct ps3_system_bus_device;
+
+int ps3_dma_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_dma_region *r, enum ps3_dma_page_size page_size,
+ enum ps3_dma_region_type region_type, void *addr, unsigned long len);
int ps3_dma_region_create(struct ps3_dma_region *r);
int ps3_dma_region_free(struct ps3_dma_region *r);
int ps3_dma_map(struct ps3_dma_region *r, unsigned long virt_addr,
- unsigned long len, unsigned long *bus_addr);
+ unsigned long len, unsigned long *bus_addr,
+ u64 iopte_pp);
int ps3_dma_unmap(struct ps3_dma_region *r, unsigned long bus_addr,
unsigned long len);
@@ -125,6 +135,7 @@ enum ps3_mmio_page_size {
PS3_MMIO_64K = 16U
};
+struct ps3_mmio_region_ops;
/**
* struct ps3_mmio_region - a per device mmio state variables structure
*
@@ -132,13 +143,18 @@ enum ps3_mmio_page_size {
*/
struct ps3_mmio_region {
- struct ps3_device_id did;
+ struct ps3_system_bus_device *dev;
+ const struct ps3_mmio_region_ops *mmio_ops;
unsigned long bus_addr;
unsigned long len;
enum ps3_mmio_page_size page_size;
unsigned long lpar_addr;
};
+struct ps3_mmio_region_ops {
+ int (*create)(struct ps3_mmio_region *);
+ int (*free)(struct ps3_mmio_region *);
+};
/**
* struct ps3_mmio_region_init - Helper to initialize structure variables
*
@@ -146,15 +162,9 @@ struct ps3_mmio_region {
* ps3_system_bus_device_register.
*/
-static inline void ps3_mmio_region_init(struct ps3_mmio_region *r,
- const struct ps3_device_id* did, unsigned long bus_addr,
- unsigned long len, enum ps3_mmio_page_size page_size)
-{
- r->did = *did;
- r->bus_addr = bus_addr;
- r->len = len;
- r->page_size = page_size;
-}
+int ps3_mmio_region_init(struct ps3_system_bus_device *dev,
+ struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len,
+ enum ps3_mmio_page_size page_size);
int ps3_mmio_region_create(struct ps3_mmio_region *r);
int ps3_free_mmio_region(struct ps3_mmio_region *r);
unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr);
@@ -187,11 +197,10 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
unsigned int class, unsigned int *virq);
int ps3_spe_irq_destroy(unsigned int virq);
-int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu,
- const struct ps3_device_id *did, unsigned int interrupt_id,
- unsigned int *virq);
-int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did,
- unsigned int interrupt_id, unsigned int virq);
+int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
+ enum ps3_cpu_binding cpu, unsigned int *virq);
+int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
+ unsigned int virq);
/* lv1 result codes */
@@ -289,11 +298,33 @@ static inline const char* ps3_result(int result)
/* system bus routines */
enum ps3_match_id {
- PS3_MATCH_ID_EHCI = 1,
- PS3_MATCH_ID_OHCI,
- PS3_MATCH_ID_GELIC,
- PS3_MATCH_ID_AV_SETTINGS,
- PS3_MATCH_ID_SYSTEM_MANAGER,
+ PS3_MATCH_ID_EHCI = 1,
+ PS3_MATCH_ID_OHCI = 2,
+ PS3_MATCH_ID_GELIC = 3,
+ PS3_MATCH_ID_AV_SETTINGS = 4,
+ PS3_MATCH_ID_SYSTEM_MANAGER = 5,
+ PS3_MATCH_ID_STOR_DISK = 6,
+ PS3_MATCH_ID_STOR_ROM = 7,
+ PS3_MATCH_ID_STOR_FLASH = 8,
+ PS3_MATCH_ID_SOUND = 9,
+ PS3_MATCH_ID_GRAPHICS = 10,
+};
+
+#define PS3_MODULE_ALIAS_EHCI "ps3:1"
+#define PS3_MODULE_ALIAS_OHCI "ps3:2"
+#define PS3_MODULE_ALIAS_GELIC "ps3:3"
+#define PS3_MODULE_ALIAS_AV_SETTINGS "ps3:4"
+#define PS3_MODULE_ALIAS_SYSTEM_MANAGER "ps3:5"
+#define PS3_MODULE_ALIAS_STOR_DISK "ps3:6"
+#define PS3_MODULE_ALIAS_STOR_ROM "ps3:7"
+#define PS3_MODULE_ALIAS_STOR_FLASH "ps3:8"
+#define PS3_MODULE_ALIAS_SOUND "ps3:9"
+#define PS3_MODULE_ALIAS_GRAPHICS "ps3:10"
+
+enum ps3_system_bus_device_type {
+ PS3_DEVICE_TYPE_IOC0 = 1,
+ PS3_DEVICE_TYPE_SB,
+ PS3_DEVICE_TYPE_VUART,
};
/**
@@ -302,14 +333,23 @@ enum ps3_match_id {
struct ps3_system_bus_device {
enum ps3_match_id match_id;
- struct ps3_device_id did;
- unsigned int interrupt_id;
-/* struct iommu_table *iommu_table; -- waiting for Ben's cleanups */
- struct ps3_dma_region *d_region;
- struct ps3_mmio_region *m_region;
+ enum ps3_system_bus_device_type dev_type;
+
+ unsigned int bus_id; /* SB */
+ unsigned int dev_id; /* SB */
+ unsigned int interrupt_id; /* SB */
+ struct ps3_dma_region *d_region; /* SB, IOC0 */
+ struct ps3_mmio_region *m_region; /* SB, IOC0*/
+ unsigned int port_number; /* VUART */
+
+/* struct iommu_table *iommu_table; -- waiting for BenH's cleanups */
struct device core;
+ void *driver_priv; /* private driver variables */
};
+int ps3_open_hv_device(struct ps3_system_bus_device *dev);
+int ps3_close_hv_device(struct ps3_system_bus_device *dev);
+
/**
* struct ps3_system_bus_driver - a driver for a device on the system bus
*/
@@ -319,6 +359,7 @@ struct ps3_system_bus_driver {
struct device_driver core;
int (*probe)(struct ps3_system_bus_device *);
int (*remove)(struct ps3_system_bus_device *);
+ int (*shutdown)(struct ps3_system_bus_device *);
/* int (*suspend)(struct ps3_system_bus_device *, pm_message_t); */
/* int (*resume)(struct ps3_system_bus_device *); */
};
@@ -326,16 +367,24 @@ struct ps3_system_bus_driver {
int ps3_system_bus_device_register(struct ps3_system_bus_device *dev);
int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv);
void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv);
-static inline struct ps3_system_bus_driver *to_ps3_system_bus_driver(
+
+static inline struct ps3_system_bus_driver *ps3_drv_to_system_bus_drv(
struct device_driver *_drv)
{
return container_of(_drv, struct ps3_system_bus_driver, core);
}
-static inline struct ps3_system_bus_device *to_ps3_system_bus_device(
+static inline struct ps3_system_bus_device *ps3_dev_to_system_bus_dev(
struct device *_dev)
{
return container_of(_dev, struct ps3_system_bus_device, core);
}
+static inline struct ps3_system_bus_driver *
+ ps3_system_bus_dev_to_system_bus_drv(struct ps3_system_bus_device *_dev)
+{
+ BUG_ON(!_dev);
+ BUG_ON(!_dev->core.driver);
+ return ps3_drv_to_system_bus_drv(_dev->core.driver);
+}
/**
* ps3_system_bus_set_drvdata -
@@ -358,32 +407,17 @@ static inline void *ps3_system_bus_get_driver_data(
extern struct bus_type ps3_system_bus_type;
-/* vuart routines */
-
-struct ps3_vuart_port_priv;
-
-/**
- * struct ps3_vuart_port_device - a device on a vuart port
- */
-
-struct ps3_vuart_port_device {
- enum ps3_match_id match_id;
- struct device core;
- struct ps3_vuart_port_priv* priv; /* private driver variables */
+/* system manager */
+struct ps3_sys_manager_ops {
+ struct ps3_system_bus_device *dev;
+ void (*power_off)(struct ps3_system_bus_device *dev);
+ void (*restart)(struct ps3_system_bus_device *dev);
};
-int ps3_vuart_port_device_register(struct ps3_vuart_port_device *dev);
-
-/* system manager */
-
-#ifdef CONFIG_PS3_SYS_MANAGER
-void ps3_sys_manager_restart(void);
+void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops);
void ps3_sys_manager_power_off(void);
-#else
-static inline void ps3_sys_manager_restart(void) {}
-static inline void ps3_sys_manager_power_off(void) {}
-#endif
+void ps3_sys_manager_restart(void);
struct ps3_prealloc {
const char *name;
@@ -393,5 +427,7 @@ struct ps3_prealloc {
};
extern struct ps3_prealloc ps3fb_videomemory;
+extern struct ps3_prealloc ps3flash_bounce_buffer;
+
#endif
diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h
index 9efc40f1c778..7df4250802de 100644
--- a/include/asm-powerpc/ps3av.h
+++ b/include/asm-powerpc/ps3av.h
@@ -1,20 +1,23 @@
/*
- * Copyright (C) 2006 Sony Computer Entertainment Inc.
- * Copyright 2006, 2007 Sony Corporation
+ * PS3 AV backend 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; version 2 of the License.
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
*
- * 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.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
*
- * 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.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+
#ifndef _ASM_POWERPC_PS3AV_H_
#define _ASM_POWERPC_PS3AV_H_
@@ -159,6 +162,9 @@
#define PS3AV_CMD_VIDEO_FMT_X8R8G8B8 0x0000
/* video_out_format */
#define PS3AV_CMD_VIDEO_OUT_FORMAT_RGB_12BIT 0x0000
+/* video_cl_cnv */
+#define PS3AV_CMD_VIDEO_CL_CNV_ENABLE_LUT 0x0000
+#define PS3AV_CMD_VIDEO_CL_CNV_DISABLE_LUT 0x0010
/* video_sync */
#define PS3AV_CMD_VIDEO_SYNC_VSYNC 0x0001
#define PS3AV_CMD_VIDEO_SYNC_CSYNC 0x0004
@@ -311,6 +317,8 @@
#define PS3AV_MODE_MASK 0x000F
#define PS3AV_MODE_HDCP_OFF 0x1000 /* Retail PS3 product doesn't support this */
#define PS3AV_MODE_DITHER 0x0800
+#define PS3AV_MODE_COLOR 0x0400
+#define PS3AV_MODE_WHITE 0x0200
#define PS3AV_MODE_FULL 0x0080
#define PS3AV_MODE_DVI 0x0040
#define PS3AV_MODE_RGB 0x0020
@@ -529,9 +537,9 @@ struct ps3av_pkt_video_mode {
u32 video_out_format; /* in: out format */
u32 video_format; /* in: input frame buffer format */
u8 reserved3;
- u8 reserved4;
+ u8 video_cl_cnv; /* in: color conversion */
u16 video_order; /* in: input RGB order */
- u32 reserved5;
+ u32 reserved4;
};
/* video: format */
@@ -539,7 +547,8 @@ struct ps3av_pkt_video_format {
struct ps3av_send_hdr send_hdr;
u32 video_head; /* in: head */
u32 video_format; /* in: frame buffer format */
- u16 reserved;
+ u8 reserved;
+ u8 video_cl_cnv; /* in: color conversion */
u16 video_order; /* in: input RGB order */
};
@@ -698,12 +707,6 @@ static inline void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_
extern int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *,
u32);
-struct ps3_vuart_port_device;
-extern int ps3av_vuart_write(struct ps3_vuart_port_device *dev,
- const void *buf, unsigned long size);
-extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf,
- unsigned long size, int timeout);
-
extern int ps3av_set_video_mode(u32, int);
extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32);
extern int ps3av_get_auto_mode(int);
@@ -716,5 +719,8 @@ extern int ps3av_video_mute(int);
extern int ps3av_audio_mute(int);
extern int ps3av_dev_open(void);
extern int ps3av_dev_close(void);
+extern void ps3av_register_flip_ctl(void (*flip_ctl)(int on, void *data),
+ void *flip_data);
+extern void ps3av_flip_ctl(int on);
#endif /* _ASM_POWERPC_PS3AV_H_ */
diff --git a/include/asm-powerpc/ps3fb.h b/include/asm-powerpc/ps3fb.h
index ad81cf431964..3f121fe4010d 100644
--- a/include/asm-powerpc/ps3fb.h
+++ b/include/asm-powerpc/ps3fb.h
@@ -41,16 +41,4 @@ struct ps3fb_ioctl_res {
__u32 num_frames; /* num of frame buffers */
};
-#ifdef __KERNEL__
-
-#ifdef CONFIG_FB_PS3
-extern void ps3fb_flip_ctl(int on);
-extern void ps3fb_cleanup(void);
-#else
-static inline void ps3fb_flip_ctl(int on) {}
-static inline void ps3fb_cleanup(void) {}
-#endif
-
-#endif /* __KERNEL__ */
-
#endif /* _ASM_POWERPC_PS3FB_H_ */
diff --git a/include/asm-powerpc/ps3stor.h b/include/asm-powerpc/ps3stor.h
new file mode 100644
index 000000000000..6fcaf714fa50
--- /dev/null
+++ b/include/asm-powerpc/ps3stor.h
@@ -0,0 +1,71 @@
+/*
+ * PS3 Storage Devices
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony 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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef _ASM_POWERPC_PS3STOR_H_
+#define _ASM_POWERPC_PS3STOR_H_
+
+#include <linux/interrupt.h>
+
+#include <asm/ps3.h>
+
+
+struct ps3_storage_region {
+ unsigned int id;
+ u64 start;
+ u64 size;
+};
+
+struct ps3_storage_device {
+ struct ps3_system_bus_device sbd;
+
+ struct ps3_dma_region dma_region;
+ unsigned int irq;
+ u64 blk_size;
+
+ u64 tag;
+ u64 lv1_status;
+ struct completion done;
+
+ unsigned long bounce_size;
+ void *bounce_buf;
+ u64 bounce_lpar;
+ dma_addr_t bounce_dma;
+
+ unsigned int num_regions;
+ unsigned long accessible_regions;
+ unsigned int region_idx; /* first accessible region */
+ struct ps3_storage_region regions[0]; /* Must be last */
+};
+
+static inline struct ps3_storage_device *to_ps3_storage_device(struct device *dev)
+{
+ return container_of(dev, struct ps3_storage_device, sbd.core);
+}
+
+extern int ps3stor_setup(struct ps3_storage_device *dev,
+ irq_handler_t handler);
+extern void ps3stor_teardown(struct ps3_storage_device *dev);
+extern u64 ps3stor_read_write_sectors(struct ps3_storage_device *dev, u64 lpar,
+ u64 start_sector, u64 sectors,
+ int write);
+extern u64 ps3stor_send_command(struct ps3_storage_device *dev, u64 cmd,
+ u64 arg1, u64 arg2, u64 arg3, u64 arg4);
+
+#endif /* _ASM_POWERPC_PS3STOR_H_ */
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 4ad77a13f865..13fccc5a4119 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -92,6 +92,11 @@ extern unsigned long profile_pc(struct pt_regs *regs);
set_thread_flag(TIF_NOERROR); \
} while(0)
+struct task_struct;
+extern unsigned long ptrace_get_reg(struct task_struct *task, int regno);
+extern int ptrace_put_reg(struct task_struct *task, int regno,
+ unsigned long data);
+
/*
* We use the least-significant bit of the trap field to indicate
* whether we have saved the full set of registers, or only a
@@ -158,9 +163,7 @@ do { \
#define PT_NIP 32
#define PT_MSR 33
-#ifdef __KERNEL__
#define PT_ORIG_R3 34
-#endif
#define PT_CTR 35
#define PT_LNK 36
#define PT_XER 37
@@ -169,11 +172,12 @@ do { \
#define PT_MQ 39
#else
#define PT_SOFTE 39
+#endif
#define PT_TRAP 40
#define PT_DAR 41
#define PT_DSISR 42
#define PT_RESULT 43
-#endif
+#define PT_REGS_COUNT 44
#define PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
@@ -229,7 +233,17 @@ do { \
#define PTRACE_GET_DEBUGREG 25
#define PTRACE_SET_DEBUGREG 26
-/* Additional PTRACE requests implemented on PowerPC. */
+/* (new) PTRACE requests using the same numbers as x86 and the same
+ * argument ordering. Additionally, they support more registers too
+ */
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+#define PTRACE_GETREGS64 22
+#define PTRACE_SETREGS64 23
+
+/* (old) PTRACE requests with inverted arguments */
#define PPC_PTRACE_GETREGS 0x99 /* Get GPRs 0 - 31 */
#define PPC_PTRACE_SETREGS 0x98 /* Set GPRs 0 - 31 */
#define PPC_PTRACE_GETFPREGS 0x97 /* Get FPRs 0 - 31 */
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 749c7f953b58..281011e953ec 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -453,6 +453,8 @@
#define SPRN_MMCRA 0x312
#define MMCRA_SIHV 0x10000000UL /* state of MSR HV when SIAR set */
#define MMCRA_SIPR 0x08000000UL /* state of MSR PR when SIAR set */
+#define MMCRA_SLOT 0x07000000UL /* SLOT bits (37-39) */
+#define MMCRA_SLOT_SHIFT 24
#define MMCRA_SAMPLE_ENABLE 0x00000001UL /* enable sampling */
#define POWER6_MMCRA_SIHV 0x0000040000000000ULL
#define POWER6_MMCRA_SIPR 0x0000020000000000ULL
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index 31d5054be20f..8836c0f1f2f7 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -106,6 +106,14 @@ struct spu_context;
struct spu_runqueue;
struct device_node;
+enum spu_utilization_state {
+ SPU_UTIL_USER,
+ SPU_UTIL_SYSTEM,
+ SPU_UTIL_IOWAIT,
+ SPU_UTIL_IDLE_LOADED,
+ SPU_UTIL_MAX
+};
+
struct spu {
const char *name;
unsigned long local_store_phys;
@@ -113,9 +121,9 @@ struct spu {
unsigned long problem_phys;
struct spu_problem __iomem *problem;
struct spu_priv2 __iomem *priv2;
- struct list_head list;
- struct list_head sched_list;
+ struct list_head cbe_list;
struct list_head full_list;
+ enum { SPU_FREE, SPU_USED } alloc_state;
int number;
unsigned int irqs[3];
u32 node;
@@ -129,6 +137,7 @@ struct spu {
struct spu_runqueue *rq;
unsigned long long timestamp;
pid_t pid;
+ pid_t tgid;
int class_0_pending;
spinlock_t register_lock;
@@ -156,15 +165,49 @@ struct spu {
u64 shadow_int_mask_RW[3];
struct sys_device sysdev;
+
+ int has_mem_affinity;
+ struct list_head aff_list;
+
+ struct {
+ /* protected by interrupt reentrancy */
+ enum spu_utilization_state util_state;
+ unsigned long long tstamp;
+ unsigned long long times[SPU_UTIL_MAX];
+ unsigned long long vol_ctx_switch;
+ unsigned long long invol_ctx_switch;
+ unsigned long long min_flt;
+ unsigned long long maj_flt;
+ unsigned long long hash_flt;
+ unsigned long long slb_flt;
+ unsigned long long class2_intr;
+ unsigned long long libassist;
+ } stats;
};
-struct spu *spu_alloc(void);
-struct spu *spu_alloc_node(int node);
-void spu_free(struct spu *spu);
+struct cbe_spu_info {
+ struct mutex list_mutex;
+ struct list_head spus;
+ int n_spus;
+ int nr_active;
+ atomic_t reserved_spus;
+};
+
+extern struct cbe_spu_info cbe_spu_info[];
+
+void spu_init_channels(struct spu *spu);
int spu_irq_class_0_bottom(struct spu *spu);
int spu_irq_class_1_bottom(struct spu *spu);
void spu_irq_setaffinity(struct spu *spu, int cpu);
+#ifdef CONFIG_KEXEC
+void crash_register_spus(struct list_head *list);
+#else
+static inline void crash_register_spus(struct list_head *list)
+{
+}
+#endif
+
extern void spu_invalidate_slbs(struct spu *spu);
extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
@@ -172,6 +215,20 @@ extern void spu_associate_mm(struct spu *spu, struct mm_struct *mm);
struct mm_struct;
extern void spu_flush_all_slbs(struct mm_struct *mm);
+/* This interface allows a profiler (e.g., OProfile) to store a ref
+ * to spu context information that it creates. This caching technique
+ * avoids the need to recreate this information after a save/restore operation.
+ *
+ * Assumes the caller has already incremented the ref count to
+ * profile_info; then spu_context_destroy must call kref_put
+ * on prof_info_kref.
+ */
+void spu_set_profile_private_kref(struct spu_context *ctx,
+ struct kref *prof_info_kref,
+ void ( * prof_info_release) (struct kref *kref));
+
+void *spu_get_profile_private_kref(struct spu_context *ctx);
+
/* system callbacks from the SPU */
struct spu_syscall_block {
u64 nr_ret;
@@ -183,7 +240,8 @@ extern long spu_sys_callback(struct spu_syscall_block *s);
struct file;
extern struct spufs_calls {
asmlinkage long (*create_thread)(const char __user *name,
- unsigned int flags, mode_t mode);
+ unsigned int flags, mode_t mode,
+ struct file *neighbor);
asmlinkage long (*spu_run)(struct file *filp, __u32 __user *unpc,
__u32 __user *ustatus);
struct module *owner;
@@ -210,8 +268,10 @@ struct spu_coredump_calls {
#define SPU_CREATE_GANG 0x0002
#define SPU_CREATE_NOSCHED 0x0004
#define SPU_CREATE_ISOLATE 0x0008
+#define SPU_CREATE_AFFINITY_SPU 0x0010
+#define SPU_CREATE_AFFINITY_MEM 0x0020
-#define SPU_CREATE_FLAG_ALL 0x000f /* mask of all valid flags */
+#define SPU_CREATE_FLAG_ALL 0x003f /* mask of all valid flags */
#ifdef CONFIG_SPU_FS_MODULE
@@ -380,6 +440,7 @@ struct spu_priv2 {
#define MFC_CNTL_RESUME_DMA_QUEUE (0ull << 0)
#define MFC_CNTL_SUSPEND_DMA_QUEUE (1ull << 0)
#define MFC_CNTL_SUSPEND_DMA_QUEUE_MASK (1ull << 0)
+#define MFC_CNTL_SUSPEND_MASK (1ull << 4)
#define MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION (0ull << 8)
#define MFC_CNTL_SUSPEND_IN_PROGRESS (1ull << 8)
#define MFC_CNTL_SUSPEND_COMPLETE (3ull << 8)
@@ -448,6 +509,7 @@ struct spu_priv1 {
#define MFC_STATE1_PROBLEM_STATE_MASK 0x08ull
#define MFC_STATE1_RELOCATE_MASK 0x10ull
#define MFC_STATE1_MASTER_RUN_CONTROL_MASK 0x20ull
+#define MFC_STATE1_TABLE_SEARCH_MASK 0x40ull
u64 mfc_lpid_RW; /* 0x008 */
u64 spu_idr_RW; /* 0x010 */
u64 mfc_vr_RO; /* 0x018 */
diff --git a/include/asm-powerpc/spu_csa.h b/include/asm-powerpc/spu_csa.h
index c48ae185c874..e87794d5d4ea 100644
--- a/include/asm-powerpc/spu_csa.h
+++ b/include/asm-powerpc/spu_csa.h
@@ -50,6 +50,12 @@
#define SPU_STOPPED_STATUS_P_I 8
#define SPU_STOPPED_STATUS_R 9
+/*
+ * Definitions for software decrementer status flag.
+ */
+#define SPU_DECR_STATUS_RUNNING 0x1
+#define SPU_DECR_STATUS_WRAPPED 0x2
+
#ifndef __ASSEMBLY__
/**
* spu_reg128 - generic 128-bit register definition.
@@ -63,7 +69,7 @@ struct spu_reg128 {
* @gprs: Array of saved registers.
* @fpcr: Saved floating point status control register.
* @decr: Saved decrementer value.
- * @decr_status: Indicates decrementer run status.
+ * @decr_status: Indicates software decrementer status flags.
* @ppu_mb: Saved PPU mailbox data.
* @ppuint_mb: Saved PPU interrupting mailbox data.
* @tag_mask: Saved tag group mask.
diff --git a/include/asm-powerpc/syscalls.h b/include/asm-powerpc/syscalls.h
index c2fe79d4f90f..b3ca41fc8bb1 100644
--- a/include/asm-powerpc/syscalls.h
+++ b/include/asm-powerpc/syscalls.h
@@ -43,16 +43,9 @@ asmlinkage long ppc_newuname(struct new_utsname __user * name);
asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset,
size_t sigsetsize);
-
-#ifndef __powerpc64__
-asmlinkage long sys_sigaltstack(const stack_t __user *uss,
- stack_t __user *uoss, int r5, int r6, int r7, int r8,
- struct pt_regs *regs);
-#else /* __powerpc64__ */
asmlinkage long sys_sigaltstack(const stack_t __user *uss,
stack_t __user *uoss, unsigned long r5, unsigned long r6,
unsigned long r7, unsigned long r8, struct pt_regs *regs);
-#endif /* __powerpc64__ */
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_SYSCALLS_H */
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index 1cc3f9cb6f4e..cc6d87228258 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -308,6 +308,7 @@ COMPAT_SYS_SPU(move_pages)
SYSCALL_SPU(getcpu)
COMPAT_SYS(epoll_pwait)
COMPAT_SYS_SPU(utimensat)
+COMPAT_SYS(fallocate)
COMPAT_SYS_SPU(signalfd)
COMPAT_SYS_SPU(timerfd)
SYSCALL_SPU(eventfd)
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 09621f611dbc..41520b7a7b76 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -43,7 +43,7 @@
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
-#define smp_wmb() __asm__ __volatile__ ("eieio" : : : "memory")
+#define smp_wmb() eieio()
#define smp_read_barrier_depends() read_barrier_depends()
#else
#define smp_mb() barrier()
@@ -184,16 +184,6 @@ struct thread_struct;
extern struct task_struct *_switch(struct thread_struct *prev,
struct thread_struct *next);
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
extern unsigned int rtas_data;
extern int mem_init_done; /* set on boot once kmalloc can be called */
extern unsigned long memory_limit;
@@ -559,5 +549,7 @@ static inline void create_function_call(unsigned long addr, void * func)
extern void account_system_vtime(struct task_struct *);
#endif
+extern struct dentry *powerpc_debugfs_root;
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_SYSTEM_H */
diff --git a/include/asm-powerpc/termbits.h b/include/asm-powerpc/termbits.h
index 5e79198f7d18..6698188ca550 100644
--- a/include/asm-powerpc/termbits.h
+++ b/include/asm-powerpc/termbits.h
@@ -152,6 +152,10 @@ struct ktermios {
#define B3000000 00034
#define B3500000 00035
#define B4000000 00036
+#define BOTHER 00037
+
+#define CIBAUD 077600000
+#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
#define CSIZE 00001400
#define CS5 00000000
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h
index 3f32ca8bfec9..9d9aeca8ad22 100644
--- a/include/asm-powerpc/thread_info.h
+++ b/include/asm-powerpc/thread_info.h
@@ -113,8 +113,8 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_POLLING_NRFLAG 4 /* true if poll_idle() is polling
TIF_NEED_RESCHED */
#define TIF_32BIT 5 /* 32 bit binary */
-#define TIF_RUNLATCH 6 /* Is the runlatch enabled? */
-#define TIF_ABI_PENDING 7 /* 32/64 bit switch needed */
+#define TIF_PERFMON_WORK 6 /* work for pfm_handle_work() */
+#define TIF_PERFMON_CTXSW 7 /* perfmon needs ctxsw calls */
#define TIF_SYSCALL_AUDIT 8 /* syscall auditing active */
#define TIF_SINGLESTEP 9 /* singlestepping active */
#define TIF_MEMDIE 10
@@ -123,6 +123,8 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NOERROR 14 /* Force successful syscall return */
#define TIF_RESTORE_SIGMASK 15 /* Restore signal mask in do_signal */
#define TIF_FREEZE 16 /* Freezing for suspend */
+#define TIF_RUNLATCH 17 /* Is the runlatch enabled? */
+#define TIF_ABI_PENDING 18 /* 32/64 bit switch needed */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -131,8 +133,8 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_32BIT (1<<TIF_32BIT)
-#define _TIF_RUNLATCH (1<<TIF_RUNLATCH)
-#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
+#define _TIF_PERFMON_WORK (1<<TIF_PERFMON_WORK)
+#define _TIF_PERFMON_CTXSW (1<<TIF_PERFMON_CTXSW)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
@@ -140,6 +142,8 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_NOERROR (1<<TIF_NOERROR)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_FREEZE (1<<TIF_FREEZE)
+#define _TIF_RUNLATCH (1<<TIF_RUNLATCH)
+#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
#define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
index 3fd57c048f59..d7f5ddfbaac7 100644
--- a/include/asm-powerpc/time.h
+++ b/include/asm-powerpc/time.h
@@ -232,7 +232,7 @@ extern void account_process_vtime(struct task_struct *tsk);
#define account_process_vtime(tsk) do { } while (0)
#endif
-#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR)
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING)
extern void calculate_steal_time(void);
extern void snapshot_timebases(void);
#else
@@ -240,5 +240,7 @@ extern void snapshot_timebases(void);
#define snapshot_timebases() do { } while (0)
#endif
+extern void iSeries_time_init_early(void);
+
#endif /* __KERNEL__ */
#endif /* __POWERPC_TIME_H */
diff --git a/include/asm-powerpc/tlbflush.h b/include/asm-powerpc/tlbflush.h
index 86e6266a028b..99a0439baa50 100644
--- a/include/asm-powerpc/tlbflush.h
+++ b/include/asm-powerpc/tlbflush.h
@@ -155,6 +155,11 @@ static inline void flush_tlb_kernel_range(unsigned long start,
{
}
+/* Private function for use by PCI IO mapping code */
+extern void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
+ unsigned long end);
+
+
#endif
/*
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index f71c6061f1ec..97d82b6a9406 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -331,10 +331,11 @@
#define __NR_timerfd 306
#define __NR_eventfd 307
#define __NR_sync_file_range2 308
+#define __NR_fallocate 309
#ifdef __KERNEL__
-#define __NR_syscalls 309
+#define __NR_syscalls 310
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
index 9d162028dab9..d2442cd72a59 100644
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -102,12 +102,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
}
#endif
-/*
- * At present there are very few 32-bit PPC machines that can have
- * memory above the 4GB point, and we don't support that.
- */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
/* Return the index of the PCI controller for device PDEV. */
#define pci_domain_nr(bus) ((struct pci_controller *)(bus)->sysdata)->index
@@ -145,8 +139,6 @@ pcibios_select_root(struct pci_dev *pdev, struct resource *res)
return root;
}
-extern void pcibios_add_platform_entries(struct pci_dev *dev);
-
struct file;
extern pgprot_t pci_phys_mem_access_prot(struct file *file,
unsigned long pfn,
diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
index 9d0ce9ff5840..c159315d2c8f 100644
--- a/include/asm-ppc/pgtable.h
+++ b/include/asm-ppc/pgtable.h
@@ -533,9 +533,7 @@ static inline int pgd_present(pgd_t pgd) { return 1; }
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
-static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXEC; }
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; }
@@ -543,21 +541,13 @@ static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
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; }
-static inline pte_t pte_rdprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_USER; return pte; }
static inline pte_t pte_wrprotect(pte_t pte) {
pte_val(pte) &= ~(_PAGE_RW | _PAGE_HWWRITE); return pte; }
-static inline pte_t pte_exprotect(pte_t pte) {
- pte_val(pte) &= ~_PAGE_EXEC; return pte; }
static inline pte_t pte_mkclean(pte_t pte) {
pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HWWRITE); return pte; }
static inline pte_t pte_mkold(pte_t pte) {
pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
-static inline pte_t pte_mkread(pte_t pte) {
- pte_val(pte) |= _PAGE_USER; return pte; }
-static inline pte_t pte_mkexec(pte_t pte) {
- pte_val(pte) |= _PAGE_USER | _PAGE_EXEC; return pte; }
static inline pte_t pte_mkwrite(pte_t pte) {
pte_val(pte) |= _PAGE_RW; return pte; }
static inline pte_t pte_mkdirty(pte_t pte) {
@@ -664,13 +654,6 @@ static inline int __ptep_test_and_clear_young(unsigned int context, unsigned lon
#define ptep_test_and_clear_young(__vma, __addr, __ptep) \
__ptep_test_and_clear_young((__vma)->vm_mm->context.id, __addr, __ptep)
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma,
- unsigned long addr, pte_t *ptep)
-{
- return (pte_update(ptep, (_PAGE_DIRTY | _PAGE_HWWRITE), 0) & _PAGE_DIRTY) != 0;
-}
-
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h
index d84a3cf4d033..cc45780421ca 100644
--- a/include/asm-ppc/system.h
+++ b/include/asm-ppc/system.h
@@ -54,6 +54,7 @@ extern void show_regs(struct pt_regs * regs);
extern void flush_instruction_cache(void);
extern void hard_reset_now(void);
extern void poweroff_now(void);
+extern int set_dabr(unsigned long dabr);
#ifdef CONFIG_6xx
extern long _get_L2CR(void);
extern long _get_L3CR(void);
@@ -129,16 +130,6 @@ extern struct task_struct *__switch_to(struct task_struct *,
struct task_struct *);
#define switch_to(prev, next, last) ((last) = __switch_to((prev), (next)))
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
struct thread_struct;
extern struct task_struct *_switch(struct thread_struct *prev,
struct thread_struct *next);
diff --git a/include/asm-s390/a.out.h b/include/asm-s390/a.out.h
index 72adee6ef338..46158dcaf517 100644
--- a/include/asm-s390/a.out.h
+++ b/include/asm-s390/a.out.h
@@ -32,6 +32,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX DEFAULT_TASK_SIZE
#endif
diff --git a/include/asm-s390/compat.h b/include/asm-s390/compat.h
index 296f4f1a20e1..7f4ad623f7d5 100644
--- a/include/asm-s390/compat.h
+++ b/include/asm-s390/compat.h
@@ -60,8 +60,10 @@ typedef s32 compat_timer_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
+typedef s64 compat_s64;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
+typedef u64 compat_u64;
struct compat_timespec {
compat_time_t tv_sec;
diff --git a/include/asm-s390/dma-mapping.h b/include/asm-s390/dma-mapping.h
deleted file mode 100644
index 3f8c12fde0f0..000000000000
--- a/include/asm-s390/dma-mapping.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * include/asm-s390/dma-mapping.h
- *
- * S390 version
- *
- * This file exists so that #include <dma-mapping.h> doesn't break anything.
- */
-
-#ifndef _ASM_DMA_MAPPING_H
-#define _ASM_DMA_MAPPING_H
-
-#endif /* _ASM_DMA_MAPPING_H */
diff --git a/include/asm-s390/fb.h b/include/asm-s390/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-s390/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-s390/kprobes.h b/include/asm-s390/kprobes.h
index 830fe4c4eea6..340ba10446ea 100644
--- a/include/asm-s390/kprobes.h
+++ b/include/asm-s390/kprobes.h
@@ -46,8 +46,6 @@ typedef u16 kprobe_opcode_t;
? (MAX_STACK_SIZE) \
: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)(pentry)
-
#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 0
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index 05ea6f172786..f326451ed6ec 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -64,7 +64,8 @@ static inline void copy_page(void *to, void *from)
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/*
diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h
index 9ea7f1023e57..545857e64443 100644
--- a/include/asm-s390/percpu.h
+++ b/include/asm-s390/percpu.h
@@ -41,6 +41,11 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
__attribute__((__section__(".data.percpu"))) \
__typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ __attribute__((__section__(".data.percpu.shared_aligned"))) \
+ __typeof__(type) per_cpu__##name \
+ ____cacheline_aligned_in_smp
+
#define __get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
#define __raw_get_cpu_var(var) __reloc_hide(var,S390_lowcore.percpu_offset)
#define per_cpu(var,cpu) __reloc_hide(var,__per_cpu_offset[cpu])
@@ -59,6 +64,8 @@ do { \
#define DEFINE_PER_CPU(type, name) \
__typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ DEFINE_PER_CPU(type, name)
#define __get_cpu_var(var) __reloc_hide(var,0)
#define __raw_get_cpu_var(var) __reloc_hide(var,0)
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index 0a307bb2f353..3208dc6c412c 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -530,14 +530,6 @@ static inline int pte_young(pte_t pte)
return 0;
}
-static inline int pte_read(pte_t pte)
-{
- /* All pages are readable since we don't use the fetch
- * protection bit in the storage key.
- */
- return 1;
-}
-
/*
* pgd/pmd/pte modification functions
*/
@@ -677,19 +669,6 @@ ptep_clear_flush_young(struct vm_area_struct *vma,
return ptep_test_and_clear_young(vma, address, ptep);
}
-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
- return 0;
-}
-
-static inline int
-ptep_clear_flush_dirty(struct vm_area_struct *vma,
- unsigned long address, pte_t *ptep)
-{
- /* No need to flush TLB; bits are in storage key */
- return ptep_test_and_clear_dirty(vma, address, ptep);
-}
-
static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
pte_t pte = *ptep;
@@ -715,16 +694,19 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
}
-static inline pte_t
-ptep_clear_flush(struct vm_area_struct *vma,
- unsigned long address, pte_t *ptep)
+static inline void ptep_invalidate(unsigned long address, pte_t *ptep)
{
- pte_t pte = *ptep;
- pte_t *shadow_pte = get_shadow_pte(ptep);
-
__ptep_ipte(address, ptep);
- if (shadow_pte)
- __ptep_ipte(address, shadow_pte);
+ ptep = get_shadow_pte(ptep);
+ if (ptep)
+ __ptep_ipte(address, ptep);
+}
+
+static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep)
+{
+ pte_t pte = *ptep;
+ ptep_invalidate(address, ptep);
return pte;
}
@@ -734,21 +716,14 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
set_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
}
-static inline void
-ptep_establish(struct vm_area_struct *vma,
- unsigned long address, pte_t *ptep,
- pte_t entry)
-{
- ptep_clear_flush(vma, address, ptep);
- set_pte(ptep, entry);
-}
-
-#define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
-({ \
- int __changed = !pte_same(*(__ptep), __entry); \
- if (__changed) \
- ptep_establish(__vma, __address, __ptep, __entry); \
- __changed; \
+#define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
+({ \
+ int __changed = !pte_same(*(__ptep), __entry); \
+ if (__changed) { \
+ ptep_invalidate(__addr, __ptep); \
+ set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \
+ } \
+ __changed; \
})
/*
@@ -948,12 +923,9 @@ extern int remove_shared_memory(unsigned long start, unsigned long size);
#define __HAVE_ARCH_MEMMAP_INIT
extern void memmap_init(unsigned long, int, unsigned long, unsigned long);
-#define __HAVE_ARCH_PTEP_ESTABLISH
#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_CLEAR_FLUSH
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index bbe137c3ed69..64a3cd05cae1 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -97,16 +97,6 @@ static inline void restore_access_regs(unsigned int *acrs)
prev = __switch_to(prev,next); \
} while (0)
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
extern void account_vtime(struct task_struct *);
extern void account_tick_vtime(struct task_struct *);
diff --git a/include/asm-sh/a.out.h b/include/asm-sh/a.out.h
index 6e9fca9ee333..685d0f6125fa 100644
--- a/include/asm-sh/a.out.h
+++ b/include/asm-sh/a.out.h
@@ -20,6 +20,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h
index 5a117ec43c77..aeee8da9c54f 100644
--- a/include/asm-sh/bugs.h
+++ b/include/asm-sh/bugs.h
@@ -22,7 +22,7 @@ static void __init check_bugs(void)
current_cpu_data.loops_per_jiffy = loops_per_jiffy;
switch (current_cpu_data.type) {
- case CPU_SH7604 ... CPU_SH7619:
+ case CPU_SH7619:
*p++ = '2';
break;
case CPU_SH7206:
@@ -35,7 +35,7 @@ static void __init check_bugs(void)
case CPU_SH7750 ... CPU_SH4_501:
*p++ = '4';
break;
- case CPU_SH7770 ... CPU_SH7785:
+ case CPU_SH7770 ... CPU_SHX3:
*p++ = '4';
*p++ = 'a';
break;
diff --git a/include/asm-sh/cache.h b/include/asm-sh/cache.h
index 9a3cb6ba9d15..7a18649d1ccb 100644
--- a/include/asm-sh/cache.h
+++ b/include/asm-sh/cache.h
@@ -9,6 +9,7 @@
#define __ASM_SH_CACHE_H
#ifdef __KERNEL__
+#include <linux/init.h>
#include <asm/cpu/cache.h>
#define SH_CACHE_VALID 1
@@ -48,6 +49,9 @@ struct cache_info {
unsigned long flags;
};
+
+int __init detect_cpu_and_cache_system(void);
+
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* __ASM_SH_CACHE_H */
diff --git a/include/asm-sh/clock.h b/include/asm-sh/clock.h
index 386d797d86b7..b550a27a7042 100644
--- a/include/asm-sh/clock.h
+++ b/include/asm-sh/clock.h
@@ -14,6 +14,7 @@ struct clk_ops {
void (*disable)(struct clk *clk);
void (*recalc)(struct clk *clk);
int (*set_rate)(struct clk *clk, unsigned long rate, int algo_id);
+ long (*round_rate)(struct clk *clk, unsigned long rate);
};
struct clk {
diff --git a/include/asm-sh/cpu-sh2/cache.h b/include/asm-sh/cpu-sh2/cache.h
index 20b9796842dc..f02ba7a672b2 100644
--- a/include/asm-sh/cpu-sh2/cache.h
+++ b/include/asm-sh/cpu-sh2/cache.h
@@ -12,23 +12,7 @@
#define L1_CACHE_SHIFT 4
-#if defined(CONFIG_CPU_SUBTYPE_SH7604)
-#define CCR 0xfffffe92 /* Address of Cache Control Register */
-
-#define CCR_CACHE_CE 0x01 /* Cache enable */
-#define CCR_CACHE_ID 0x02 /* Instruction Replacement disable */
-#define CCR_CACHE_OD 0x04 /* Data Replacement disable */
-#define CCR_CACHE_TW 0x08 /* Two-way mode */
-#define CCR_CACHE_CP 0x10 /* Cache purge */
-
-#define CACHE_OC_ADDRESS_ARRAY 0x60000000
-
-#define CCR_CACHE_ENABLE CCR_CACHE_CE
-#define CCR_CACHE_INVALIDATE CCR_CACHE_CP
-#define CCR_CACHE_ORA CCR_CACHE_TW
-#define CCR_CACHE_WT 0x00 /* SH-2 is _always_ write-through */
-
-#elif defined(CONFIG_CPU_SUBTYPE_SH7619)
+#if defined(CONFIG_CPU_SUBTYPE_SH7619)
#define CCR1 0xffffffec
#define CCR CCR1
@@ -49,5 +33,5 @@
#define CCR_CACHE_ENABLE CCR_CACHE_CE
#define CCR_CACHE_INVALIDATE CCR_CACHE_CF
#endif
-#endif /* __ASM_CPU_SH2_CACHE_H */
+#endif /* __ASM_CPU_SH2_CACHE_H */
diff --git a/include/asm-sh/cpu-sh3/timer.h b/include/asm-sh/cpu-sh3/timer.h
index b2394cf76f49..4928b08f9d19 100644
--- a/include/asm-sh/cpu-sh3/timer.h
+++ b/include/asm-sh/cpu-sh3/timer.h
@@ -29,7 +29,7 @@
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
-#define TMU_TSTR 0xa412fe92 /* Byte access */
+#define TMU_012_TSTR 0xa412fe92 /* Byte access */
#define TMU0_TCOR 0xa412fe94 /* Long access */
#define TMU0_TCNT 0xa412fe98 /* Long access */
@@ -44,7 +44,7 @@
#define TMU2_TCR 0xa412feb4 /* Word access */
#else
-#define TMU_TSTR 0xfffffe92 /* Byte access */
+#define TMU_012_TSTR 0xfffffe92 /* Byte access */
#define TMU0_TCOR 0xfffffe94 /* Long access */
#define TMU0_TCNT 0xfffffe98 /* Long access */
diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h
index 39f41fcd509d..026025b51cea 100644
--- a/include/asm-sh/cpu-sh4/freq.h
+++ b/include/asm-sh/cpu-sh4/freq.h
@@ -22,6 +22,8 @@
#define FRQCR0 0xffc80000
#define FRQCR1 0xffc80004
#define FRQMR1 0xffc80014
+#elif defined(CONFIG_CPU_SUBTYPE_SHX3)
+#define FRQCR 0xffc00014
#else
#define FRQCR 0xffc00000
#define FRQCR_PSTBY 0x0200
diff --git a/include/asm-sh/cpu-sh4/timer.h b/include/asm-sh/cpu-sh4/timer.h
index 8a4af126c890..d1e796b96888 100644
--- a/include/asm-sh/cpu-sh4/timer.h
+++ b/include/asm-sh/cpu-sh4/timer.h
@@ -1,7 +1,7 @@
/*
* include/asm-sh/cpu-sh4/timer.h
*
- * Copyright (C) 2004 Lineo Solutions, Inc.
+ * Copyright (C) 2004 Lineo Solutions, Inc.
*
* 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
@@ -16,36 +16,45 @@
* SH7750S/SH7750R
* SH7751/SH7751R
* SH7760
+ * SH-X3
* ---------------------------------------------------------------------------
*/
-
-#if !defined(CONFIG_CPU_SUBTYPE_SH7760)
-#define TMU_TOCR 0xffd80000 /* Byte access */
+#ifdef CONFIG_CPU_SUBTYPE_SHX3
+#define TMU_012_BASE 0xffc10000
+#define TMU_345_BASE 0xffc20000
+#else
+#define TMU_012_BASE 0xffd80000
+#define TMU_345_BASE 0xfe100000
#endif
-#define TMU_TSTR 0xffd80004 /* Byte access */
-#define TMU0_TCOR 0xffd80008 /* Long access */
-#define TMU0_TCNT 0xffd8000c /* Long access */
-#define TMU0_TCR 0xffd80010 /* Word access */
+#define TMU_TOCR TMU_012_BASE /* Not supported on all CPUs */
-#define TMU1_TCOR 0xffd80014 /* Long access */
-#define TMU1_TCNT 0xffd80018 /* Long access */
-#define TMU1_TCR 0xffd8001c /* Word access */
+#define TMU_012_TSTR (TMU_012_BASE + 0x04)
+#define TMU_345_TSTR (TMU_345_BASE + 0x04)
-#define TMU2_TCOR 0xffd80020 /* Long access */
-#define TMU2_TCNT 0xffd80024 /* Long access */
-#define TMU2_TCR 0xffd80028 /* Word access */
-#define TMU2_TCPR 0xffd8002c /* Long access */
+#define TMU0_TCOR (TMU_012_BASE + 0x08)
+#define TMU0_TCNT (TMU_012_BASE + 0x0c)
+#define TMU0_TCR (TMU_012_BASE + 0x10)
-#if !defined(CONFIG_CPU_SUBTYPE_SH7760)
-#define TMU3_TCOR 0xfe100008 /* Long access */
-#define TMU3_TCNT 0xfe10000c /* Long access */
-#define TMU3_TCR 0xfe100010 /* Word access */
+#define TMU1_TCOR (TMU_012_BASE + 0x14)
+#define TMU1_TCNT (TMU_012_BASE + 0x18)
+#define TMU1_TCR (TMU_012_BASE + 0x1c)
-#define TMU4_TCOR 0xfe100014 /* Long access */
-#define TMU4_TCNT 0xfe100018 /* Long access */
-#define TMU4_TCR 0xfe10001c /* Word access */
-#endif
+#define TMU2_TCOR (TMU_012_BASE + 0x20)
+#define TMU2_TCNT (TMU_012_BASE + 0x24)
+#define TMU2_TCR (TMU_012_BASE + 0x28)
+#define TMU2_TCPR (TMU_012_BASE + 0x2c)
-#endif /* __ASM_CPU_SH4_TIMER_H */
+#define TMU3_TCOR (TMU_345_BASE + 0x08)
+#define TMU3_TCNT (TMU_345_BASE + 0x0c)
+#define TMU3_TCR (TMU_345_BASE + 0x10)
+#define TMU4_TCOR (TMU_345_BASE + 0x14)
+#define TMU4_TCNT (TMU_345_BASE + 0x18)
+#define TMU4_TCR (TMU_345_BASE + 0x1c)
+
+#define TMU5_TCOR (TMU_345_BASE + 0x20)
+#define TMU5_TCNT (TMU_345_BASE + 0x24)
+#define TMU5_TCR (TMU_345_BASE + 0x28)
+
+#endif /* __ASM_CPU_SH4_TIMER_H */
diff --git a/include/asm-sh/fb.h b/include/asm-sh/fb.h
new file mode 100644
index 000000000000..d92e99cd8c8a
--- /dev/null
+++ b/include/asm-sh/fb.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-sh/futex-irq.h b/include/asm-sh/futex-irq.h
new file mode 100644
index 000000000000..a9f16a7f9aea
--- /dev/null
+++ b/include/asm-sh/futex-irq.h
@@ -0,0 +1,111 @@
+#ifndef __ASM_SH_FUTEX_IRQ_H
+#define __ASM_SH_FUTEX_IRQ_H
+
+#include <asm/system.h>
+
+static inline int atomic_futex_op_xchg_set(int oparg, int __user *uaddr,
+ int *oldval)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+
+ ret = get_user(*oldval, uaddr);
+ if (!ret)
+ ret = put_user(oparg, uaddr);
+
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_futex_op_xchg_add(int oparg, int __user *uaddr,
+ int *oldval)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+
+ ret = get_user(*oldval, uaddr);
+ if (!ret)
+ ret = put_user(*oldval + oparg, uaddr);
+
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_futex_op_xchg_or(int oparg, int __user *uaddr,
+ int *oldval)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+
+ ret = get_user(*oldval, uaddr);
+ if (!ret)
+ ret = put_user(*oldval | oparg, uaddr);
+
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_futex_op_xchg_and(int oparg, int __user *uaddr,
+ int *oldval)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+
+ ret = get_user(*oldval, uaddr);
+ if (!ret)
+ ret = put_user(*oldval & oparg, uaddr);
+
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_futex_op_xchg_xor(int oparg, int __user *uaddr,
+ int *oldval)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+
+ ret = get_user(*oldval, uaddr);
+ if (!ret)
+ ret = put_user(*oldval ^ oparg, uaddr);
+
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline int atomic_futex_op_cmpxchg_inatomic(int __user *uaddr,
+ int oldval, int newval)
+{
+ unsigned long flags;
+ int ret, prev = 0;
+
+ local_irq_save(flags);
+
+ ret = get_user(prev, uaddr);
+ if (!ret && oldval == prev)
+ ret = put_user(newval, uaddr);
+
+ local_irq_restore(flags);
+
+ if (ret)
+ return ret;
+
+ return prev;
+}
+
+#endif /* __ASM_SH_FUTEX_IRQ_H */
diff --git a/include/asm-sh/futex.h b/include/asm-sh/futex.h
index 6a332a9f099c..74ed3681d33c 100644
--- a/include/asm-sh/futex.h
+++ b/include/asm-sh/futex.h
@@ -1,6 +1,77 @@
-#ifndef _ASM_FUTEX_H
-#define _ASM_FUTEX_H
+#ifndef __ASM_SH_FUTEX_H
+#define __ASM_SH_FUTEX_H
-#include <asm-generic/futex.h>
+#ifdef __KERNEL__
-#endif
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+/* XXX: UP variants, fix for SH-4A and SMP.. */
+#include <asm/futex-irq.h>
+
+static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ pagefault_disable();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_ADD:
+ ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_OR:
+ ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_ANDN:
+ ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval);
+ break;
+ case FUTEX_OP_XOR:
+ ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ pagefault_enable();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+
+ return ret;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ return atomic_futex_op_cmpxchg_inatomic(uaddr, oldval, newval);
+}
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_SH_FUTEX_H */
diff --git a/include/asm-sh/hd64461.h b/include/asm-sh/hd64461.h
index 27e5c34e2659..4dd8592ca014 100644
--- a/include/asm-sh/hd64461.h
+++ b/include/asm-sh/hd64461.h
@@ -1,200 +1,241 @@
#ifndef __ASM_SH_HD64461
#define __ASM_SH_HD64461
/*
- * $Id: hd64461.h,v 1.5 2004/03/16 00:07:51 lethal Exp $
+ * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com>
+ * Copyright (C) 2004 Paul Mundt
* Copyright (C) 2000 YAEGASHI Takeshi
- * Hitachi HD64461 companion chip support
+ *
+ * Hitachi HD64461 companion chip support
+ * (please note manual reference 0x10000000 = 0xb0000000)
*/
/* Constants for PCMCIA mappings */
-#define HD64461_PCC_WINDOW 0x01000000
-
-#define HD64461_PCC0_BASE 0xb8000000 /* area 6 */
-#define HD64461_PCC0_ATTR (HD64461_PCC0_BASE)
-#define HD64461_PCC0_COMM (HD64461_PCC0_BASE+HD64461_PCC_WINDOW)
-#define HD64461_PCC0_IO (HD64461_PCC0_BASE+2*HD64461_PCC_WINDOW)
-
-#define HD64461_PCC1_BASE 0xb4000000 /* area 5 */
-#define HD64461_PCC1_ATTR (HD64461_PCC1_BASE)
-#define HD64461_PCC1_COMM (HD64461_PCC1_BASE+HD64461_PCC_WINDOW)
-
-#define HD64461_STBCR 0x10000
-#define HD64461_STBCR_CKIO_STBY 0x2000
-#define HD64461_STBCR_SAFECKE_IST 0x1000
-#define HD64461_STBCR_SLCKE_IST 0x0800
-#define HD64461_STBCR_SAFECKE_OST 0x0400
-#define HD64461_STBCR_SLCKE_OST 0x0200
-#define HD64461_STBCR_SMIAST 0x0100
-#define HD64461_STBCR_SLCDST 0x0080
-#define HD64461_STBCR_SPC0ST 0x0040
-#define HD64461_STBCR_SPC1ST 0x0020
-#define HD64461_STBCR_SAFEST 0x0010
-#define HD64461_STBCR_STM0ST 0x0008
-#define HD64461_STBCR_STM1ST 0x0004
-#define HD64461_STBCR_SIRST 0x0002
-#define HD64461_STBCR_SURTST 0x0001
-
-#define HD64461_SYSCR 0x10002
-#define HD64461_SCPUCR 0x10004
-
-#define HD64461_LCDCBAR 0x11000
-#define HD64461_LCDCLOR 0x11002
-#define HD64461_LCDCCR 0x11004
-#define HD64461_LCDCCR_STBACK 0x0400
-#define HD64461_LCDCCR_STREQ 0x0100
-#define HD64461_LCDCCR_MOFF 0x0080
-#define HD64461_LCDCCR_REFSEL 0x0040
-#define HD64461_LCDCCR_EPON 0x0020
-#define HD64461_LCDCCR_SPON 0x0010
-
-#define HD64461_LDR1 0x11010
-#define HD64461_LDR1_DON 0x01
-#define HD64461_LDR1_DINV 0x80
-
-#define HD64461_LDR2 0x11012
-#define HD64461_LDHNCR 0x11014
-#define HD64461_LDHNSR 0x11016
-#define HD64461_LDVNTR 0x11018
-#define HD64461_LDVNDR 0x1101a
-#define HD64461_LDVSPR 0x1101c
-#define HD64461_LDR3 0x1101e
-
-#define HD64461_CPTWAR 0x11030
-#define HD64461_CPTWDR 0x11032
-#define HD64461_CPTRAR 0x11034
-#define HD64461_CPTRDR 0x11036
-
-#define HD64461_GRDOR 0x11040
-#define HD64461_GRSCR 0x11042
-#define HD64461_GRCFGR 0x11044
-#define HD64461_GRCFGR_ACCSTATUS 0x10
-#define HD64461_GRCFGR_ACCRESET 0x08
-#define HD64461_GRCFGR_ACCSTART_BITBLT 0x06
-#define HD64461_GRCFGR_ACCSTART_LINE 0x04
-#define HD64461_GRCFGR_COLORDEPTH16 0x01
-
-#define HD64461_LNSARH 0x11046
-#define HD64461_LNSARL 0x11048
-#define HD64461_LNAXLR 0x1104a
-#define HD64461_LNDGR 0x1104c
-#define HD64461_LNAXR 0x1104e
-#define HD64461_LNERTR 0x11050
-#define HD64461_LNMDR 0x11052
-#define HD64461_BBTSSARH 0x11054
-#define HD64461_BBTSSARL 0x11056
-#define HD64461_BBTDSARH 0x11058
-#define HD64461_BBTDSARL 0x1105a
-#define HD64461_BBTDWR 0x1105c
-#define HD64461_BBTDHR 0x1105e
-#define HD64461_BBTPARH 0x11060
-#define HD64461_BBTPARL 0x11062
-#define HD64461_BBTMARH 0x11064
-#define HD64461_BBTMARL 0x11066
-#define HD64461_BBTROPR 0x11068
-#define HD64461_BBTMDR 0x1106a
+#define HD64461_PCC_WINDOW 0x01000000
+
+/* Area 6 - Slot 0 - memory and/or IO card */
+#define HD64461_PCC0_BASE (CONFIG_HD64461_IOBASE + 0x8000000)
+#define HD64461_PCC0_ATTR (HD64461_PCC0_BASE) /* 0xb80000000 */
+#define HD64461_PCC0_COMM (HD64461_PCC0_BASE+HD64461_PCC_WINDOW) /* 0xb90000000 */
+#define HD64461_PCC0_IO (HD64461_PCC0_BASE+2*HD64461_PCC_WINDOW) /* 0xba0000000 */
+
+/* Area 5 - Slot 1 - memory card only */
+#define HD64461_PCC1_BASE (CONFIG_HD64461_IOBASE + 0x4000000)
+#define HD64461_PCC1_ATTR (HD64461_PCC1_BASE) /* 0xb4000000 */
+#define HD64461_PCC1_COMM (HD64461_PCC1_BASE+HD64461_PCC_WINDOW) /* 0xb5000000 */
+
+/* Standby Control Register for HD64461 */
+#define HD64461_STBCR CONFIG_HD64461_IOBASE
+#define HD64461_STBCR_CKIO_STBY 0x2000
+#define HD64461_STBCR_SAFECKE_IST 0x1000
+#define HD64461_STBCR_SLCKE_IST 0x0800
+#define HD64461_STBCR_SAFECKE_OST 0x0400
+#define HD64461_STBCR_SLCKE_OST 0x0200
+#define HD64461_STBCR_SMIAST 0x0100
+#define HD64461_STBCR_SLCDST 0x0080
+#define HD64461_STBCR_SPC0ST 0x0040
+#define HD64461_STBCR_SPC1ST 0x0020
+#define HD64461_STBCR_SAFEST 0x0010
+#define HD64461_STBCR_STM0ST 0x0008
+#define HD64461_STBCR_STM1ST 0x0004
+#define HD64461_STBCR_SIRST 0x0002
+#define HD64461_STBCR_SURTST 0x0001
+
+/* System Configuration Register */
+#define HD64461_SYSCR (CONFIG_HD64461_IOBASE + 0x02)
+
+/* CPU Data Bus Control Register */
+#define HD64461_SCPUCR (CONFIG_HD64461_IOBASE + 0x04)
+
+/* Base Adress Register */
+#define HD64461_LCDCBAR (CONFIG_HD64461_IOBASE + 0x1000)
+
+/* Line increment adress */
+#define HD64461_LCDCLOR (CONFIG_HD64461_IOBASE + 0x1002)
+
+/* Controls LCD controller */
+#define HD64461_LCDCCR (CONFIG_HD64461_IOBASE + 0x1004)
+
+/* LCCDR control bits */
+#define HD64461_LCDCCR_STBACK 0x0400 /* Standby Back */
+#define HD64461_LCDCCR_STREQ 0x0100 /* Standby Request */
+#define HD64461_LCDCCR_MOFF 0x0080 /* Memory Off */
+#define HD64461_LCDCCR_REFSEL 0x0040 /* Refresh Select */
+#define HD64461_LCDCCR_EPON 0x0020 /* End Power On */
+#define HD64461_LCDCCR_SPON 0x0010 /* Start Power On */
+
+/* Controls LCD (1) */
+#define HD64461_LDR1 (CONFIG_HD64461_IOBASE + 0x1010)
+#define HD64461_LDR1_DON 0x01 /* Display On */
+#define HD64461_LDR1_DINV 0x80 /* Display Invert */
+
+/* Controls LCD (2) */
+#define HD64461_LDR2 (CONFIG_HD64461_IOBASE + 0x1012)
+#define HD64461_LDHNCR (CONFIG_HD64461_IOBASE + 0x1014) /* Number of horizontal characters */
+#define HD64461_LDHNSR (CONFIG_HD64461_IOBASE + 0x1016) /* Specify output start position + width of CL1 */
+#define HD64461_LDVNTR (CONFIG_HD64461_IOBASE + 0x1018) /* Specify total vertical lines */
+#define HD64461_LDVNDR (CONFIG_HD64461_IOBASE + 0x101a) /* specify number of display vertical lines */
+#define HD64461_LDVSPR (CONFIG_HD64461_IOBASE + 0x101c) /* specify vertical synchronization pos and AC nr */
+
+/* Controls LCD (3) */
+#define HD64461_LDR3 (CONFIG_HD64461_IOBASE + 0x101e)
+
+/* Palette Registers */
+#define HD64461_CPTWAR (CONFIG_HD64461_IOBASE + 0x1030) /* Color Palette Write Adress Register */
+#define HD64461_CPTWDR (CONFIG_HD64461_IOBASE + 0x1032) /* Color Palette Write Data Register */
+#define HD64461_CPTRAR (CONFIG_HD64461_IOBASE + 0x1034) /* Color Palette Read Adress Register */
+#define HD64461_CPTRDR (CONFIG_HD64461_IOBASE + 0x1036) /* Color Palette Read Data Register */
+
+#define HD64461_GRDOR (CONFIG_HD64461_IOBASE + 0x1040) /* Display Resolution Offset Register */
+#define HD64461_GRSCR (CONFIG_HD64461_IOBASE + 0x1042) /* Solid Color Register */
+#define HD64461_GRCFGR (CONFIG_HD64461_IOBASE + 0x1044) /* Accelerator Configuration Register */
+
+#define HD64461_GRCFGR_ACCSTATUS 0x10 /* Accelerator Status */
+#define HD64461_GRCFGR_ACCRESET 0x08 /* Accelerator Reset */
+#define HD64461_GRCFGR_ACCSTART_BITBLT 0x06 /* Accelerator Start BITBLT */
+#define HD64461_GRCFGR_ACCSTART_LINE 0x04 /* Accelerator Start Line Drawing */
+#define HD64461_GRCFGR_COLORDEPTH16 0x01 /* Sets Colordepth 16 for Accelerator */
+#define HD64461_GRCFGR_COLORDEPTH8 0x01 /* Sets Colordepth 8 for Accelerator */
+
+/* Line Drawing Registers */
+#define HD64461_LNSARH (CONFIG_HD64461_IOBASE + 0x1046) /* Line Start Adress Register (H) */
+#define HD64461_LNSARL (CONFIG_HD64461_IOBASE + 0x1048) /* Line Start Adress Register (L) */
+#define HD64461_LNAXLR (CONFIG_HD64461_IOBASE + 0x104a) /* Axis Pixel Length Register */
+#define HD64461_LNDGR (CONFIG_HD64461_IOBASE + 0x104c) /* Diagonal Register */
+#define HD64461_LNAXR (CONFIG_HD64461_IOBASE + 0x104e) /* Axial Register */
+#define HD64461_LNERTR (CONFIG_HD64461_IOBASE + 0x1050) /* Start Error Term Register */
+#define HD64461_LNMDR (CONFIG_HD64461_IOBASE + 0x1052) /* Line Mode Register */
+
+/* BitBLT Registers */
+#define HD64461_BBTSSARH (CONFIG_HD64461_IOBASE + 0x1054) /* Source Start Adress Register (H) */
+#define HD64461_BBTSSARL (CONFIG_HD64461_IOBASE + 0x1056) /* Source Start Adress Register (L) */
+#define HD64461_BBTDSARH (CONFIG_HD64461_IOBASE + 0x1058) /* Destination Start Adress Register (H) */
+#define HD64461_BBTDSARL (CONFIG_HD64461_IOBASE + 0x105a) /* Destination Start Adress Register (L) */
+#define HD64461_BBTDWR (CONFIG_HD64461_IOBASE + 0x105c) /* Destination Block Width Register */
+#define HD64461_BBTDHR (CONFIG_HD64461_IOBASE + 0x105e) /* Destination Block Height Register */
+#define HD64461_BBTPARH (CONFIG_HD64461_IOBASE + 0x1060) /* Pattern Start Adress Register (H) */
+#define HD64461_BBTPARL (CONFIG_HD64461_IOBASE + 0x1062) /* Pattern Start Adress Register (L) */
+#define HD64461_BBTMARH (CONFIG_HD64461_IOBASE + 0x1064) /* Mask Start Adress Register (H) */
+#define HD64461_BBTMARL (CONFIG_HD64461_IOBASE + 0x1066) /* Mask Start Adress Register (L) */
+#define HD64461_BBTROPR (CONFIG_HD64461_IOBASE + 0x1068) /* ROP Register */
+#define HD64461_BBTMDR (CONFIG_HD64461_IOBASE + 0x106a) /* BitBLT Mode Register */
/* PC Card Controller Registers */
-#define HD64461_PCC0ISR 0x12000 /* socket 0 interface status */
-#define HD64461_PCC0GCR 0x12002 /* socket 0 general control */
-#define HD64461_PCC0CSCR 0x12004 /* socket 0 card status change */
-#define HD64461_PCC0CSCIER 0x12006 /* socket 0 card status change interrupt enable */
-#define HD64461_PCC0SCR 0x12008 /* socket 0 software control */
-#define HD64461_PCC1ISR 0x12010 /* socket 1 interface status */
-#define HD64461_PCC1GCR 0x12012 /* socket 1 general control */
-#define HD64461_PCC1CSCR 0x12014 /* socket 1 card status change */
-#define HD64461_PCC1CSCIER 0x12016 /* socket 1 card status change interrupt enable */
-#define HD64461_PCC1SCR 0x12018 /* socket 1 software control */
+/* Maps to Physical Area 6 */
+#define HD64461_PCC0ISR (CONFIG_HD64461_IOBASE + 0x2000) /* socket 0 interface status */
+#define HD64461_PCC0GCR (CONFIG_HD64461_IOBASE + 0x2002) /* socket 0 general control */
+#define HD64461_PCC0CSCR (CONFIG_HD64461_IOBASE + 0x2004) /* socket 0 card status change */
+#define HD64461_PCC0CSCIER (CONFIG_HD64461_IOBASE + 0x2006) /* socket 0 card status change interrupt enable */
+#define HD64461_PCC0SCR (CONFIG_HD64461_IOBASE + 0x2008) /* socket 0 software control */
+/* Maps to Physical Area 5 */
+#define HD64461_PCC1ISR (CONFIG_HD64461_IOBASE + 0x2010) /* socket 1 interface status */
+#define HD64461_PCC1GCR (CONFIG_HD64461_IOBASE + 0x2012) /* socket 1 general control */
+#define HD64461_PCC1CSCR (CONFIG_HD64461_IOBASE + 0x2014) /* socket 1 card status change */
+#define HD64461_PCC1CSCIER (CONFIG_HD64461_IOBASE + 0x2016) /* socket 1 card status change interrupt enable */
+#define HD64461_PCC1SCR (CONFIG_HD64461_IOBASE + 0x2018) /* socket 1 software control */
/* PCC Interface Status Register */
-#define HD64461_PCCISR_READY 0x80 /* card ready */
-#define HD64461_PCCISR_MWP 0x40 /* card write-protected */
-#define HD64461_PCCISR_VS2 0x20 /* voltage select pin 2 */
-#define HD64461_PCCISR_VS1 0x10 /* voltage select pin 1 */
-#define HD64461_PCCISR_CD2 0x08 /* card detect 2 */
-#define HD64461_PCCISR_CD1 0x04 /* card detect 1 */
-#define HD64461_PCCISR_BVD2 0x02 /* battery 1 */
-#define HD64461_PCCISR_BVD1 0x01 /* battery 1 */
-
-#define HD64461_PCCISR_PCD_MASK 0x0c /* card detect */
-#define HD64461_PCCISR_BVD_MASK 0x03 /* battery voltage */
-#define HD64461_PCCISR_BVD_BATGOOD 0x03 /* battery good */
-#define HD64461_PCCISR_BVD_BATWARN 0x01 /* battery low warning */
-#define HD64461_PCCISR_BVD_BATDEAD1 0x02 /* battery dead */
-#define HD64461_PCCISR_BVD_BATDEAD2 0x00 /* battery dead */
+#define HD64461_PCCISR_READY 0x80 /* card ready */
+#define HD64461_PCCISR_MWP 0x40 /* card write-protected */
+#define HD64461_PCCISR_VS2 0x20 /* voltage select pin 2 */
+#define HD64461_PCCISR_VS1 0x10 /* voltage select pin 1 */
+#define HD64461_PCCISR_CD2 0x08 /* card detect 2 */
+#define HD64461_PCCISR_CD1 0x04 /* card detect 1 */
+#define HD64461_PCCISR_BVD2 0x02 /* battery 1 */
+#define HD64461_PCCISR_BVD1 0x01 /* battery 1 */
+
+#define HD64461_PCCISR_PCD_MASK 0x0c /* card detect */
+#define HD64461_PCCISR_BVD_MASK 0x03 /* battery voltage */
+#define HD64461_PCCISR_BVD_BATGOOD 0x03 /* battery good */
+#define HD64461_PCCISR_BVD_BATWARN 0x01 /* battery low warning */
+#define HD64461_PCCISR_BVD_BATDEAD1 0x02 /* battery dead */
+#define HD64461_PCCISR_BVD_BATDEAD2 0x00 /* battery dead */
/* PCC General Control Register */
-#define HD64461_PCCGCR_DRVE 0x80 /* output drive */
-#define HD64461_PCCGCR_PCCR 0x40 /* PC card reset */
-#define HD64461_PCCGCR_PCCT 0x20 /* PC card type, 1=IO&mem, 0=mem */
-#define HD64461_PCCGCR_VCC0 0x10 /* voltage control pin VCC0SEL0 */
-#define HD64461_PCCGCR_PMMOD 0x08 /* memory mode */
-#define HD64461_PCCGCR_PA25 0x04 /* pin A25 */
-#define HD64461_PCCGCR_PA24 0x02 /* pin A24 */
-#define HD64461_PCCGCR_REG 0x01 /* pin PCC0REG# */
+#define HD64461_PCCGCR_DRVE 0x80 /* output drive */
+#define HD64461_PCCGCR_PCCR 0x40 /* PC card reset */
+#define HD64461_PCCGCR_PCCT 0x20 /* PC card type, 1=IO&mem, 0=mem */
+#define HD64461_PCCGCR_VCC0 0x10 /* voltage control pin VCC0SEL0 */
+#define HD64461_PCCGCR_PMMOD 0x08 /* memory mode */
+#define HD64461_PCCGCR_PA25 0x04 /* pin A25 */
+#define HD64461_PCCGCR_PA24 0x02 /* pin A24 */
+#define HD64461_PCCGCR_REG 0x01 /* pin PCC0REG# */
/* PCC Card Status Change Register */
-#define HD64461_PCCCSCR_SCDI 0x80 /* sw card detect intr */
-#define HD64461_PCCCSCR_SRV1 0x40 /* reserved */
-#define HD64461_PCCCSCR_IREQ 0x20 /* IREQ intr req */
-#define HD64461_PCCCSCR_SC 0x10 /* STSCHG (status change) pin */
-#define HD64461_PCCCSCR_CDC 0x08 /* CD (card detect) change */
-#define HD64461_PCCCSCR_RC 0x04 /* READY change */
-#define HD64461_PCCCSCR_BW 0x02 /* battery warning change */
-#define HD64461_PCCCSCR_BD 0x01 /* battery dead change */
+#define HD64461_PCCCSCR_SCDI 0x80 /* sw card detect intr */
+#define HD64461_PCCCSCR_SRV1 0x40 /* reserved */
+#define HD64461_PCCCSCR_IREQ 0x20 /* IREQ intr req */
+#define HD64461_PCCCSCR_SC 0x10 /* STSCHG (status change) pin */
+#define HD64461_PCCCSCR_CDC 0x08 /* CD (card detect) change */
+#define HD64461_PCCCSCR_RC 0x04 /* READY change */
+#define HD64461_PCCCSCR_BW 0x02 /* battery warning change */
+#define HD64461_PCCCSCR_BD 0x01 /* battery dead change */
/* PCC Card Status Change Interrupt Enable Register */
-#define HD64461_PCCCSCIER_CRE 0x80 /* change reset enable */
-#define HD64461_PCCCSCIER_IREQE_MASK 0x60 /* IREQ enable */
-#define HD64461_PCCCSCIER_IREQE_DISABLED 0x00 /* IREQ disabled */
-#define HD64461_PCCCSCIER_IREQE_LEVEL 0x20 /* IREQ level-triggered */
-#define HD64461_PCCCSCIER_IREQE_FALLING 0x40 /* IREQ falling-edge-trig */
-#define HD64461_PCCCSCIER_IREQE_RISING 0x60 /* IREQ rising-edge-trig */
-
-#define HD64461_PCCCSCIER_SCE 0x10 /* status change enable */
-#define HD64461_PCCCSCIER_CDE 0x08 /* card detect change enable */
-#define HD64461_PCCCSCIER_RE 0x04 /* ready change enable */
-#define HD64461_PCCCSCIER_BWE 0x02 /* battery warn change enable */
-#define HD64461_PCCCSCIER_BDE 0x01 /* battery dead change enable*/
+#define HD64461_PCCCSCIER_CRE 0x80 /* change reset enable */
+#define HD64461_PCCCSCIER_IREQE_MASK 0x60 /* IREQ enable */
+#define HD64461_PCCCSCIER_IREQE_DISABLED 0x00 /* IREQ disabled */
+#define HD64461_PCCCSCIER_IREQE_LEVEL 0x20 /* IREQ level-triggered */
+#define HD64461_PCCCSCIER_IREQE_FALLING 0x40 /* IREQ falling-edge-trig */
+#define HD64461_PCCCSCIER_IREQE_RISING 0x60 /* IREQ rising-edge-trig */
+
+#define HD64461_PCCCSCIER_SCE 0x10 /* status change enable */
+#define HD64461_PCCCSCIER_CDE 0x08 /* card detect change enable */
+#define HD64461_PCCCSCIER_RE 0x04 /* ready change enable */
+#define HD64461_PCCCSCIER_BWE 0x02 /* battery warn change enable */
+#define HD64461_PCCCSCIER_BDE 0x01 /* battery dead change enable*/
/* PCC Software Control Register */
-#define HD64461_PCCSCR_VCC1 0x02 /* voltage control pin 1 */
-#define HD64461_PCCSCR_SWP 0x01 /* write protect */
-
-#define HD64461_P0OCR 0x1202a
-#define HD64461_P1OCR 0x1202c
-#define HD64461_PGCR 0x1202e
-
-#define HD64461_GPACR 0x14000
-#define HD64461_GPBCR 0x14002
-#define HD64461_GPCCR 0x14004
-#define HD64461_GPDCR 0x14006
-#define HD64461_GPADR 0x14010
-#define HD64461_GPBDR 0x14012
-#define HD64461_GPCDR 0x14014
-#define HD64461_GPDDR 0x14016
-#define HD64461_GPAICR 0x14020
-#define HD64461_GPBICR 0x14022
-#define HD64461_GPCICR 0x14024
-#define HD64461_GPDICR 0x14026
-#define HD64461_GPAISR 0x14040
-#define HD64461_GPBISR 0x14042
-#define HD64461_GPCISR 0x14044
-#define HD64461_GPDISR 0x14046
-
-#define HD64461_NIRR 0x15000
-#define HD64461_NIMR 0x15002
-
-#define HD64461_IRQBASE OFFCHIP_IRQ_BASE
-#define HD64461_IRQ_NUM 16
-
-#define HD64461_IRQ_UART (HD64461_IRQBASE+5)
-#define HD64461_IRQ_IRDA (HD64461_IRQBASE+6)
-#define HD64461_IRQ_TMU1 (HD64461_IRQBASE+9)
-#define HD64461_IRQ_TMU0 (HD64461_IRQBASE+10)
-#define HD64461_IRQ_GPIO (HD64461_IRQBASE+11)
-#define HD64461_IRQ_AFE (HD64461_IRQBASE+12)
-#define HD64461_IRQ_PCC1 (HD64461_IRQBASE+13)
-#define HD64461_IRQ_PCC0 (HD64461_IRQBASE+14)
+#define HD64461_PCCSCR_VCC1 0x02 /* voltage control pin 1 */
+#define HD64461_PCCSCR_SWP 0x01 /* write protect */
+
+/* PCC0 Output Pins Control Register */
+#define HD64461_P0OCR (CONFIG_HD64461_IOBASE + 0x202a)
+
+/* PCC1 Output Pins Control Register */
+#define HD64461_P1OCR (CONFIG_HD64461_IOBASE + 0x202c)
+
+/* PC Card General Control Register */
+#define HD64461_PGCR (CONFIG_HD64461_IOBASE + 0x202e)
+
+/* Port Control Registers */
+#define HD64461_GPACR (CONFIG_HD64461_IOBASE + 0x4000) /* Port A - Handles IRDA/TIMER */
+#define HD64461_GPBCR (CONFIG_HD64461_IOBASE + 0x4002) /* Port B - Handles UART */
+#define HD64461_GPCCR (CONFIG_HD64461_IOBASE + 0x4004) /* Port C - Handles PCMCIA 1 */
+#define HD64461_GPDCR (CONFIG_HD64461_IOBASE + 0x4006) /* Port D - Handles PCMCIA 1 */
+
+/* Port Control Data Registers */
+#define HD64461_GPADR (CONFIG_HD64461_IOBASE + 0x4010) /* A */
+#define HD64461_GPBDR (CONFIG_HD64461_IOBASE + 0x4012) /* B */
+#define HD64461_GPCDR (CONFIG_HD64461_IOBASE + 0x4014) /* C */
+#define HD64461_GPDDR (CONFIG_HD64461_IOBASE + 0x4016) /* D */
+
+/* Interrupt Control Registers */
+#define HD64461_GPAICR (CONFIG_HD64461_IOBASE + 0x4020) /* A */
+#define HD64461_GPBICR (CONFIG_HD64461_IOBASE + 0x4022) /* B */
+#define HD64461_GPCICR (CONFIG_HD64461_IOBASE + 0x4024) /* C */
+#define HD64461_GPDICR (CONFIG_HD64461_IOBASE + 0x4026) /* D */
+
+/* Interrupt Status Registers */
+#define HD64461_GPAISR (CONFIG_HD64461_IOBASE + 0x4040) /* A */
+#define HD64461_GPBISR (CONFIG_HD64461_IOBASE + 0x4042) /* B */
+#define HD64461_GPCISR (CONFIG_HD64461_IOBASE + 0x4044) /* C */
+#define HD64461_GPDISR (CONFIG_HD64461_IOBASE + 0x4046) /* D */
+
+/* Interrupt Request Register & Interrupt Mask Register */
+#define HD64461_NIRR (CONFIG_HD64461_IOBASE + 0x5000)
+#define HD64461_NIMR (CONFIG_HD64461_IOBASE + 0x5002)
+
+#define HD64461_IRQBASE OFFCHIP_IRQ_BASE
+#define HD64461_IRQ_NUM 16
+
+#define HD64461_IRQ_UART (HD64461_IRQBASE+5)
+#define HD64461_IRQ_IRDA (HD64461_IRQBASE+6)
+#define HD64461_IRQ_TMU1 (HD64461_IRQBASE+9)
+#define HD64461_IRQ_TMU0 (HD64461_IRQBASE+10)
+#define HD64461_IRQ_GPIO (HD64461_IRQBASE+11)
+#define HD64461_IRQ_AFE (HD64461_IRQBASE+12)
+#define HD64461_IRQ_PCC1 (HD64461_IRQBASE+13)
+#define HD64461_IRQ_PCC0 (HD64461_IRQBASE+14)
#define __IO_PREFIX hd64461
#include <asm/io_generic.h>
diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h
index 80ee1cda7498..20d42959f52a 100644
--- a/include/asm-sh/hw_irq.h
+++ b/include/asm-sh/hw_irq.h
@@ -1,8 +1,121 @@
#ifndef __ASM_SH_HW_IRQ_H
#define __ASM_SH_HW_IRQ_H
+#include <linux/init.h>
#include <asm/atomic.h>
extern atomic_t irq_err_count;
+struct intc2_data {
+ unsigned short irq;
+ unsigned char ipr_offset, ipr_shift;
+ unsigned char msk_offset, msk_shift;
+ unsigned char priority;
+};
+
+struct intc2_desc {
+ unsigned long prio_base;
+ unsigned long msk_base;
+ unsigned long mskclr_base;
+ struct intc2_data *intc2_data;
+ unsigned int nr_irqs;
+ struct irq_chip chip;
+};
+
+void register_intc2_controller(struct intc2_desc *);
+
+struct ipr_data {
+ unsigned char irq;
+ unsigned char ipr_idx; /* Index for the IPR registered */
+ unsigned char shift; /* Number of bits to shift the data */
+ unsigned char priority; /* The priority */
+};
+
+struct ipr_desc {
+ unsigned long *ipr_offsets;
+ unsigned int nr_offsets;
+ struct ipr_data *ipr_data;
+ unsigned int nr_irqs;
+ struct irq_chip chip;
+};
+
+void register_ipr_controller(struct ipr_desc *);
+
+/*
+ * Enable individual interrupt mode for external IPR IRQs.
+ */
+void __init ipr_irq_enable_irlm(void);
+
+typedef unsigned char intc_enum;
+
+struct intc_vect {
+ intc_enum enum_id;
+ unsigned short vect;
+};
+
+#define INTC_VECT(enum_id, vect) { enum_id, vect }
+
+struct intc_prio {
+ intc_enum enum_id;
+ unsigned char priority;
+};
+
+#define INTC_PRIO(enum_id, prio) { enum_id, prio }
+
+struct intc_group {
+ intc_enum enum_id;
+ intc_enum *enum_ids;
+};
+
+#define INTC_GROUP(enum_id, ids...) { enum_id, (intc_enum []) { ids, 0 } }
+
+struct intc_mask_reg {
+ unsigned long set_reg, clr_reg, reg_width;
+ intc_enum enum_ids[32];
+};
+
+struct intc_prio_reg {
+ unsigned long reg, reg_width, field_width;
+ intc_enum enum_ids[16];
+};
+
+struct intc_sense_reg {
+ unsigned long reg, reg_width, field_width;
+ intc_enum enum_ids[16];
+};
+
+struct intc_desc {
+ struct intc_vect *vectors;
+ unsigned int nr_vectors;
+ struct intc_group *groups;
+ unsigned int nr_groups;
+ struct intc_prio *priorities;
+ unsigned int nr_priorities;
+ struct intc_mask_reg *mask_regs;
+ unsigned int nr_mask_regs;
+ struct intc_prio_reg *prio_regs;
+ unsigned int nr_prio_regs;
+ struct intc_sense_reg *sense_regs;
+ unsigned int nr_sense_regs;
+ struct irq_chip chip;
+};
+
+#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a)
+#define DECLARE_INTC_DESC(symbol, chipname, vectors, groups, \
+ priorities, mask_regs, prio_regs, sense_regs) \
+struct intc_desc symbol = { \
+ _INTC_ARRAY(vectors), _INTC_ARRAY(groups), \
+ _INTC_ARRAY(priorities), \
+ _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \
+ _INTC_ARRAY(sense_regs), \
+ .chip.name = chipname, \
+}
+
+void __init register_intc_controller(struct intc_desc *desc);
+
+void __init plat_irq_setup(void);
+
+enum { IRQ_MODE_IRQ, IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 };
+void __init plat_irq_setup_pins(int mode);
+
#endif /* __ASM_SH_HW_IRQ_H */
diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
index e81bf21c801e..c61d902b8bff 100644
--- a/include/asm-sh/irq.h
+++ b/include/asm-sh/irq.h
@@ -31,47 +31,7 @@ extern unsigned short *irq_mask_register;
* PINT IRQs
*/
void init_IRQ_pint(void);
-
-/*
- * The shift value is now the number of bits to shift, not the number of
- * bits/4. This is to make it easier to read the value directly from the
- * datasheets. The IPR address, addr, will be set from ipr_idx via the
- * map_ipridx_to_addr function.
- */
-struct ipr_data {
- unsigned int irq;
- int ipr_idx; /* Index for the IPR registered */
- int shift; /* Number of bits to shift the data */
- int priority; /* The priority */
- unsigned int addr; /* Address of Interrupt Priority Register */
-};
-
-/*
- * Given an IPR IDX, map the value to an IPR register address.
- */
-unsigned int map_ipridx_to_addr(int idx);
-
-/*
- * Enable individual interrupt mode for external IPR IRQs.
- */
-void ipr_irq_enable_irlm(void);
-
-/*
- * Function for "on chip support modules".
- */
-void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs);
void make_imask_irq(unsigned int irq);
-void init_IRQ_ipr(void);
-
-struct intc2_data {
- unsigned short irq;
- unsigned char ipr_offset, ipr_shift;
- unsigned char msk_offset, msk_shift;
- unsigned char priority;
-};
-
-void make_intc2_irq(struct intc2_data *, unsigned int nr_irqs);
-void init_IRQ_intc2(void);
static inline int generic_irq_demux(int irq)
{
diff --git a/include/asm-sh/machvec.h b/include/asm-sh/machvec.h
index 70389b72ffef..088698bacf2f 100644
--- a/include/asm-sh/machvec.h
+++ b/include/asm-sh/machvec.h
@@ -13,7 +13,6 @@
#include <linux/types.h>
#include <linux/time.h>
#include <asm/machtypes.h>
-#include <asm/machvec_init.h>
struct device;
@@ -68,4 +67,7 @@ extern struct sh_machine_vector sh_mv;
#define get_system_type() sh_mv.mv_name
+#define __initmv \
+ __attribute_used__ __attribute__((__section__ (".machvec.init")))
+
#endif /* _ASM_SH_MACHVEC_H */
diff --git a/include/asm-sh/machvec_init.h b/include/asm-sh/machvec_init.h
deleted file mode 100644
index e397798ebd94..000000000000
--- a/include/asm-sh/machvec_init.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * include/asm-sh/machvec_init.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * This file has goodies to help simplify instantiation of machine vectors.
- */
-
-#ifndef __SH_MACHVEC_INIT_H
-#define __SH_MACHVEC_INIT_H
-
-
-/*
- * In a GENERIC kernel, we have lots of these vectors floating about,
- * all but one of which we want to go away. In a non-GENERIC kernel,
- * we want only one, ever.
- *
- * Accomplish this in the GENERIC kernel by puting all of the vectors
- * in the .init.data section where they'll go away. We'll copy the
- * one we want to the real alpha_mv vector in setup_arch.
- *
- * Accomplish this in a non-GENERIC kernel by ifdef'ing out all but
- * one of the vectors, which will not reside in .init.data. We then
- * alias this one vector to alpha_mv, so no copy is needed.
- *
- * Upshot: set __initdata to nothing for non-GENERIC kernels.
- *
- * Note we do the same thing for the UNKNOWN kernel, as we need to write
- * to the machine vector while setting it up.
- */
-
-#if defined(CONFIG_SH_GENERIC) || defined(CONFIG_SH_UNKNOWN)
-#define __initmv __attribute__((unused,__section__ (".machvec.init")))
-#define ALIAS_MV(x)
-#else
-#define __initmv
-
-/* GCC actually has a syntax for defining aliases, but is under some
- delusion that you shouldn't be able to declare it extern somewhere
- else beforehand. Fine. We'll do it ourselves. */
-#if 0
-#define ALIAS_MV(system) \
- struct sh_machine_vector sh_mv __attribute__((alias("mv_"#system)));
-#else
-#define ALIAS_MV(system) \
- asm(".global sh_mv\nsh_mv = mv_"#system );
-#endif
-#endif /* GENERIC */
-
-#endif /* __SH_MACHVEC_INIT_H */
diff --git a/include/asm-sh/mmzone.h b/include/asm-sh/mmzone.h
new file mode 100644
index 000000000000..7969f381dff2
--- /dev/null
+++ b/include/asm-sh/mmzone.h
@@ -0,0 +1,46 @@
+#ifndef __ASM_SH_MMZONE_H
+#define __ASM_SH_MMZONE_H
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_NEED_MULTIPLE_NODES
+extern struct pglist_data *node_data[];
+#define NODE_DATA(nid) (node_data[nid])
+
+#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid) (NODE_DATA(nid)->node_start_pfn + \
+ NODE_DATA(nid)->node_spanned_pages)
+
+static inline int pfn_to_nid(unsigned long pfn)
+{
+ int nid;
+
+ for (nid = 0; nid < MAX_NUMNODES; nid++)
+ if (pfn >= node_start_pfn(nid) && pfn <= node_end_pfn(nid))
+ break;
+
+ return nid;
+}
+
+static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn)
+{
+ return NODE_DATA(pfn_to_nid(pfn));
+}
+
+/* arch/sh/mm/numa.c */
+void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end);
+#else
+static inline void
+setup_bootmem_node(int nid, unsigned long start, unsigned long end)
+{
+}
+#endif /* CONFIG_NEED_MULTIPLE_NODES */
+
+/* Platform specific mem init */
+void __init plat_mem_setup(void);
+
+/* arch/sh/kernel/setup.c */
+void __init setup_bootmem_allocator(unsigned long start_pfn);
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_SH_MMZONE_H */
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index 7464de4ba07d..6bc9bba10105 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -60,6 +60,7 @@ extern void (*copy_page)(void *to, void *from);
extern unsigned long shm_align_mask;
extern unsigned long max_low_pfn, min_low_pfn;
+extern unsigned long memory_start, memory_end;
#ifdef CONFIG_MMU
extern void clear_page_slow(void *to);
@@ -134,7 +135,9 @@ typedef struct { unsigned long pgd; } pgd_t;
#define PFN_START (__MEMORY_START >> PAGE_SHIFT)
#define ARCH_PFN_OFFSET (PFN_START)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#ifdef CONFIG_FLATMEM
#define pfn_valid(pfn) ((pfn) >= min_low_pfn && (pfn) < max_low_pfn)
+#endif
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
@@ -148,5 +151,12 @@ typedef struct { unsigned long pgd; } pgd_t;
#define __HAVE_ARCH_GATE_AREA
#endif
+/*
+ * Slub defaults to 8-byte alignment, we're only interested in 4.
+ * Slab defaults to BYTES_PER_WORD, which ends up being the same anyways.
+ */
+#define ARCH_KMALLOC_MINALIGN 4
+#define ARCH_SLAB_MINALIGN 4
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_PAGE_H */
diff --git a/include/asm-sh/parport.h b/include/asm-sh/parport.h
new file mode 100644
index 000000000000..f67ba60a2acd
--- /dev/null
+++ b/include/asm-sh/parport.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 1999, 2000 Tim Waugh <tim@cyberelk.demon.co.uk>
+ *
+ * This file should only be included by drivers/parport/parport_pc.c.
+ */
+#ifndef __ASM_SH_PARPORT_H
+#define __ASM_SH_PARPORT_H
+
+static int __devinit parport_pc_find_isa_ports(int autoirq, int autodma);
+
+static int __devinit parport_pc_find_nonpci_ports(int autoirq, int autodma)
+{
+ return parport_pc_find_isa_ports(autoirq, autodma);
+}
+
+#endif /* __ASM_SH_PARPORT_H */
diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
index b1f9a9e0231e..2757ce096ff7 100644
--- a/include/asm-sh/pci.h
+++ b/include/asm-sh/pci.h
@@ -110,11 +110,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
#endif
-/* Not supporting more than 32-bit PCI bus addresses now, but
- * must satisfy references to this function. Change if needed.
- */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -134,10 +129,6 @@ int pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
int pciauto_assign_resources(int busno, struct pci_channel *hose);
#endif
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* __KERNEL__ */
/* generic pci stuff */
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index 5b523c7e7d99..22efffe45019 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -402,12 +402,8 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
#define pte_file(pte) (pte_val(pte) & _PAGE_FILE)
#ifdef CONFIG_X2TLB
-#define pte_read(pte) ((pte).pte_high & _PAGE_EXT_USER_READ)
-#define pte_exec(pte) ((pte).pte_high & _PAGE_EXT_USER_EXEC)
#define pte_write(pte) ((pte).pte_high & _PAGE_EXT_USER_WRITE)
#else
-#define pte_read(pte) (pte_val(pte) & _PAGE_USER)
-#define pte_exec(pte) (pte_val(pte) & _PAGE_USER)
#define pte_write(pte) (pte_val(pte) & _PAGE_RW)
#endif
@@ -420,20 +416,12 @@ static inline pte_t pte_##fn(pte_t pte) { pte.pte_##h op; return pte; }
* individually toggled (and user permissions are entirely decoupled from
* kernel permissions), we attempt to couple them a bit more sanely here.
*/
-PTE_BIT_FUNC(high, rdprotect, &= ~_PAGE_EXT_USER_READ);
-PTE_BIT_FUNC(high, mkread, |= _PAGE_EXT_USER_READ | _PAGE_EXT_KERN_READ);
PTE_BIT_FUNC(high, wrprotect, &= ~_PAGE_EXT_USER_WRITE);
PTE_BIT_FUNC(high, mkwrite, |= _PAGE_EXT_USER_WRITE | _PAGE_EXT_KERN_WRITE);
-PTE_BIT_FUNC(high, exprotect, &= ~_PAGE_EXT_USER_EXEC);
-PTE_BIT_FUNC(high, mkexec, |= _PAGE_EXT_USER_EXEC | _PAGE_EXT_KERN_EXEC);
PTE_BIT_FUNC(high, mkhuge, |= _PAGE_SZHUGE);
#else
-PTE_BIT_FUNC(low, rdprotect, &= ~_PAGE_USER);
-PTE_BIT_FUNC(low, mkread, |= _PAGE_USER);
PTE_BIT_FUNC(low, wrprotect, &= ~_PAGE_RW);
PTE_BIT_FUNC(low, mkwrite, |= _PAGE_RW);
-PTE_BIT_FUNC(low, exprotect, &= ~_PAGE_USER);
-PTE_BIT_FUNC(low, mkexec, |= _PAGE_USER);
PTE_BIT_FUNC(low, mkhuge, |= _PAGE_SZHUGE);
#endif
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
index d42f68e724fa..2252e75daa26 100644
--- a/include/asm-sh/processor.h
+++ b/include/asm-sh/processor.h
@@ -36,7 +36,7 @@
*/
enum cpu_type {
/* SH-2 types */
- CPU_SH7604, CPU_SH7619,
+ CPU_SH7619,
/* SH-2A types */
CPU_SH7206,
@@ -52,7 +52,7 @@ enum cpu_type {
CPU_SH7760, CPU_ST40RA, CPU_ST40GX1, CPU_SH4_202, CPU_SH4_501,
/* SH-4A types */
- CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785,
+ CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SHX3,
/* SH4AL-DSP types */
CPU_SH73180, CPU_SH7343, CPU_SH7722,
@@ -228,11 +228,7 @@ static __inline__ void grab_fpu(struct pt_regs *regs)
regs->sr &= ~SR_FD;
}
-#ifdef CONFIG_CPU_SH4
extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs);
-#else
-#define save_fpu(tsk) do { } while (0)
-#endif
#define unlazy_fpu(tsk, regs) do { \
if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { \
diff --git a/include/asm-sh/rwsem.h b/include/asm-sh/rwsem.h
index 4931ba817d73..1987f3ea7f1b 100644
--- a/include/asm-sh/rwsem.h
+++ b/include/asm-sh/rwsem.h
@@ -1,11 +1,15 @@
/*
- * include/asm-ppc/rwsem.h: R/W semaphores for SH using the stuff
+ * include/asm-sh/rwsem.h: R/W semaphores for SH using the stuff
* in lib/rwsem.c.
*/
#ifndef _ASM_SH_RWSEM_H
#define _ASM_SH_RWSEM_H
+#ifndef _LINUX_RWSEM_H
+#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
+#endif
+
#ifdef __KERNEL__
#include <linux/list.h>
#include <linux/spinlock.h>
diff --git a/include/asm-sh/saturn/io.h b/include/asm-sh/saturn/io.h
deleted file mode 100644
index f1b9b5d633f4..000000000000
--- a/include/asm-sh/saturn/io.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * include/asm-sh/saturn/io.h
- *
- * I/O functions for use on the Sega Saturn.
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#ifndef __ASM_SH_SATURN_IO_H
-#define __ASM_SH_SATURN_IO_H
-
-/* arch/sh/boards/saturn/io.c */
-extern unsigned long saturn_isa_port2addr(unsigned long offset);
-extern void *saturn_ioremap(unsigned long offset, unsigned long size);
-extern void saturn_iounmap(void *addr);
-
-#endif /* __ASM_SH_SATURN_IO_H */
-
diff --git a/include/asm-sh/saturn/smpc.h b/include/asm-sh/saturn/smpc.h
deleted file mode 100644
index 5de5c12d6347..000000000000
--- a/include/asm-sh/saturn/smpc.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * include/asm-sh/saturn/smpc.h
- *
- * System Manager / Peripheral Control definitions.
- *
- * Copyright (C) 2002 Paul Mundt
- *
- * Released under the terms of the GNU GPL v2.0.
- */
-#ifndef __ASM_SH_SATURN_SMPC_H
-#define __ASM_SH_SATURN_SMPC_H
-
-#include <asm/io.h>
-
-#define SMPC_COMMAND 0x2010001f /* SMPC command register */
-#define SMPC_RESULT 0x2010005f /* SMPC result register */
-#define SMPC_STATUS 0x20100063 /* SMPC status register */
-
-#define SMPC_CMD_MSHON 0x0001 /* Master SH On */
-#define SMPC_CMD_SSHON 0x0002 /* Slave SH On */
-#define SMPC_CMD_SSHOFF 0x0003 /* Slave SH Off */
-#define SMPC_CMD_SNDON 0x0004 /* Sound On */
-#define SMPC_CMD_SNDOFF 0x0005 /* Sound Off */
-#define SMPC_CMD_CDON 0x0006 /* CD On */
-#define SMPC_CMD_CDOFF 0x0007 /* CD Off */
-
-static inline void smpc_barrier(void)
-{
- while ((ctrl_inb(SMPC_STATUS) & 0x0001) == 0x0001)
- ;
-}
-
-#endif /* __ASM_SH_SATURN_SMPC_H */
-
diff --git a/include/asm-sh/se7722.h b/include/asm-sh/se7722.h
index b3b31e4725c6..e0e89fcb8388 100644
--- a/include/asm-sh/se7722.h
+++ b/include/asm-sh/se7722.h
@@ -81,36 +81,32 @@
/* IRQ */
#define IRQ0_IRQ 32
#define IRQ1_IRQ 33
-#define INTC_ICR0 0xA4140000UL
-#define INTC_ICR1 0xA414001CUL
-
-#define INTMSK0 0xa4140044
-#define INTMSKCLR0 0xa4140064
-#define INTC_INTPRI0 0xa4140010
#define IRQ01_MODE 0xb1800000
#define IRQ01_STS 0xb1800004
#define IRQ01_MASK 0xb1800008
-#define EXT_BIT (0x3fc0) /* SH IRQ1 */
-#define MRSHPC_BIT0 (0x0004) /* SH IRQ1 */
-#define MRSHPC_BIT1 (0x0008) /* SH IRQ1 */
-#define MRSHPC_BIT2 (0x0010) /* SH IRQ1 */
-#define MRSHPC_BIT3 (0x0020) /* SH IRQ1 */
-#define SMC_BIT (0x0002) /* SH IRQ0 */
-#define USB_BIT (0x0001) /* SH IRQ0 */
-
-#define MRSHPC_IRQ3 11
-#define MRSHPC_IRQ2 12
-#define MRSHPC_IRQ1 13
-#define MRSHPC_IRQ0 14
-#define SMC_IRQ 10
-#define EXT_IRQ 5
-#define USB_IRQ 6
+/* Bits in IRQ01_* registers */
+
+#define SE7722_FPGA_IRQ_USB 0 /* IRQ0 */
+#define SE7722_FPGA_IRQ_SMC 1 /* IRQ0 */
+#define SE7722_FPGA_IRQ_MRSHPC0 2 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC1 3 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC2 4 /* IRQ1 */
+#define SE7722_FPGA_IRQ_MRSHPC3 5 /* IRQ1 */
+
+#define SE7722_FPGA_IRQ_NR 6
+#define SE7722_FPGA_IRQ_BASE 110
+
+#define MRSHPC_IRQ3 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC3)
+#define MRSHPC_IRQ2 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC2)
+#define MRSHPC_IRQ1 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC1)
+#define MRSHPC_IRQ0 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC0)
+#define SMC_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_SMC)
+#define USB_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_USB)
/* arch/sh/boards/se/7722/irq.c */
void init_se7722_IRQ(void);
-int se7722_irq_demux(int);
#define __IO_PREFIX se7722
#include <asm/io_generic.h>
diff --git a/include/asm-sh/sections.h b/include/asm-sh/sections.h
index 57abd708b236..2a696b8ee4f5 100644
--- a/include/asm-sh/sections.h
+++ b/include/asm-sh/sections.h
@@ -3,7 +3,7 @@
#include <asm-generic/sections.h>
-extern char _end[];
+extern long __machvec_start, __machvec_end;
#endif /* __ASM_SH_SECTIONS_H */
diff --git a/include/asm-sh/setup.h b/include/asm-sh/setup.h
index 1583c6b7bdaa..586a9711a75d 100644
--- a/include/asm-sh/setup.h
+++ b/include/asm-sh/setup.h
@@ -6,6 +6,7 @@
#ifdef __KERNEL__
int setup_early_printk(char *);
+void sh_mv_setup(void);
#endif /* __KERNEL__ */
diff --git a/include/asm-sh/sh03/io.h b/include/asm-sh/sh03/io.h
index df3b187ef883..4ff1eb900301 100644
--- a/include/asm-sh/sh03/io.h
+++ b/include/asm-sh/sh03/io.h
@@ -14,22 +14,18 @@
#define INTC_IPRD 0xffd00010UL
#define IRL0_IRQ 2
-#define IRL0_IPR_ADDR INTC_IPRD
#define IRL0_IPR_POS 3
#define IRL0_PRIORITY 13
#define IRL1_IRQ 5
-#define IRL1_IPR_ADDR INTC_IPRD
#define IRL1_IPR_POS 2
#define IRL1_PRIORITY 10
#define IRL2_IRQ 8
-#define IRL2_IPR_ADDR INTC_IPRD
#define IRL2_IPR_POS 1
#define IRL2_PRIORITY 7
#define IRL3_IRQ 11
-#define IRL3_IPR_ADDR INTC_IPRD
#define IRL3_IPR_POS 0
#define IRL3_PRIORITY 4
diff --git a/include/asm-sh/smp.h b/include/asm-sh/smp.h
index caa7b93f1bce..b99ca786c0c1 100644
--- a/include/asm-sh/smp.h
+++ b/include/asm-sh/smp.h
@@ -39,4 +39,6 @@ extern struct smp_fn_call_struct smp_fn_call;
#endif /* CONFIG_SMP */
+#define hard_smp_processor_id() (0)
+
#endif /* __ASM_SH_SMP_H */
diff --git a/include/asm-sh/snapgear.h b/include/asm-sh/snapgear.h
index 2d712e72c9e5..3554e3a74e99 100644
--- a/include/asm-sh/snapgear.h
+++ b/include/asm-sh/snapgear.h
@@ -20,22 +20,18 @@
*/
#define IRL0_IRQ 2
-#define IRL0_IPR_ADDR INTC_IPRD
#define IRL0_IPR_POS 3
#define IRL0_PRIORITY 13
#define IRL1_IRQ 5
-#define IRL1_IPR_ADDR INTC_IPRD
#define IRL1_IPR_POS 2
#define IRL1_PRIORITY 10
#define IRL2_IRQ 8
-#define IRL2_IPR_ADDR INTC_IPRD
#define IRL2_IPR_POS 1
#define IRL2_PRIORITY 7
#define IRL3_IRQ 11
-#define IRL3_IPR_ADDR INTC_IPRD
#define IRL3_IPR_POS 0
#define IRL3_PRIORITY 4
#endif
diff --git a/include/asm-sh/sparsemem.h b/include/asm-sh/sparsemem.h
new file mode 100644
index 000000000000..547a540b6667
--- /dev/null
+++ b/include/asm-sh/sparsemem.h
@@ -0,0 +1,16 @@
+#ifndef __ASM_SH_SPARSEMEM_H
+#define __ASM_SH_SPARSEMEM_H
+
+#ifdef __KERNEL__
+/*
+ * SECTION_SIZE_BITS 2^N: how big each section will be
+ * MAX_PHYSADDR_BITS 2^N: how much physical address space we have
+ * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space
+ */
+#define SECTION_SIZE_BITS 26
+#define MAX_PHYSADDR_BITS 32
+#define MAX_PHYSMEM_BITS 32
+
+#endif
+
+#endif /* __ASM_SH_SPARSEMEM_H */
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index 82f3e229e621..245042537205 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -8,9 +8,13 @@
#include <linux/irqflags.h>
#include <linux/compiler.h>
+#include <linux/linkage.h>
#include <asm/types.h>
#include <asm/ptrace.h>
+struct task_struct *__switch_to(struct task_struct *prev,
+ struct task_struct *next);
+
/*
* switch_to() should switch tasks to task nr n, first
*/
@@ -60,16 +64,6 @@
last = __last; \
} while (0)
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
#ifdef CONFIG_CPU_SH4A
#define __icbi() \
{ \
@@ -122,7 +116,7 @@ static inline void sched_cacheflush(void)
#define smp_read_barrier_depends() do { } while(0)
#endif
-#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#define set_mb(var, value) do { (void)xchg(&var, value); } while (0)
/*
* Jump to P2 area.
@@ -271,6 +265,16 @@ extern unsigned int instruction_size(unsigned int insn);
void disable_hlt(void);
void enable_hlt(void);
+void default_idle(void);
+
+asmlinkage void break_point_trap(void);
+asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs);
+asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs __regs);
+
#define arch_align_stack(x) (x)
#endif
diff --git a/include/asm-sh/topology.h b/include/asm-sh/topology.h
index cff001c316fe..f402a3b1cfa4 100644
--- a/include/asm-sh/topology.h
+++ b/include/asm-sh/topology.h
@@ -1,6 +1,36 @@
#ifndef _ASM_SH_TOPOLOGY_H
#define _ASM_SH_TOPOLOGY_H
+#ifdef CONFIG_NUMA
+
+/* sched_domains SD_NODE_INIT for sh machines */
+#define SD_NODE_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
+ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 8, \
+ .max_interval = 32, \
+ .busy_factor = 32, \
+ .imbalance_pct = 125, \
+ .cache_nice_tries = 2, \
+ .busy_idx = 3, \
+ .idle_idx = 2, \
+ .newidle_idx = 0, \
+ .wake_idx = 1, \
+ .forkexec_idx = 1, \
+ .flags = SD_LOAD_BALANCE \
+ | SD_BALANCE_FORK \
+ | SD_BALANCE_EXEC \
+ | SD_SERIALIZE \
+ | SD_WAKE_BALANCE, \
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+ .nr_balance_failed = 0, \
+}
+
+#endif
+
#include <asm-generic/topology.h>
#endif /* _ASM_SH_TOPOLOGY_H */
diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
index 5c49ed6715f2..f18a1a5c95c0 100644
--- a/include/asm-sh/uaccess.h
+++ b/include/asm-sh/uaccess.h
@@ -61,8 +61,6 @@ static inline void set_fs(mm_segment_t s)
*/
static inline int __access_ok(unsigned long addr, unsigned long size)
{
- extern unsigned long memory_start, memory_end;
-
return ((addr >= memory_start) && ((addr + size) < memory_end));
}
#else /* CONFIG_MMU */
@@ -76,7 +74,7 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
* __access_ok: Check if address with size is OK or not.
*
* We do three checks:
- * (1) is it user space?
+ * (1) is it user space?
* (2) addr + size --> carry?
* (3) addr + size >= 0x80000000 (PAGE_OFFSET)
*
@@ -142,11 +140,12 @@ static inline int access_ok(int type, const void __user *p, unsigned long size)
__get_user_nocheck((x),(ptr),sizeof(*(ptr)))
struct __large_struct { unsigned long buf[100]; };
-#define __m(x) (*(struct __large_struct *)(x))
+#define __m(x) (*(struct __large_struct __user *)(x))
#define __get_user_size(x,ptr,size,retval) \
do { \
retval = 0; \
+ __chk_user_ptr(ptr); \
switch (size) { \
case 1: \
__get_user_asm(x, ptr, retval, "b"); \
@@ -175,6 +174,7 @@ do { \
#define __get_user_check(x,ptr,size) \
({ \
long __gu_err, __gu_val; \
+ __chk_user_ptr(ptr); \
switch (size) { \
case 1: \
__get_user_1(__gu_val, (ptr), __gu_err); \
@@ -300,6 +300,7 @@ extern void __get_user_unknown(void);
#define __put_user_size(x,ptr,size,retval) \
do { \
retval = 0; \
+ __chk_user_ptr(ptr); \
switch (size) { \
case 1: \
__put_user_asm(x, ptr, retval, "b"); \
@@ -328,7 +329,7 @@ do { \
#define __put_user_check(x,ptr,size) \
({ \
long __pu_err = -EFAULT; \
- __typeof__(*(ptr)) *__pu_addr = (ptr); \
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
\
if (__access_ok((unsigned long)__pu_addr,size)) \
__put_user_size((x),__pu_addr,(size),__pu_err); \
@@ -406,10 +407,10 @@ __asm__ __volatile__( \
#endif
extern void __put_user_unknown(void);
-
+
/* Generic arbitrary sized copy. */
/* Return the number of bytes NOT copied */
-extern __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
+__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n);
#define copy_to_user(to,from,n) ({ \
void *__copy_to = (void *) (to); \
@@ -420,14 +421,6 @@ __copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \
} else __copy_res = __copy_size; \
__copy_res; })
-#define __copy_to_user(to,from,n) \
- __copy_user((void *)(to), \
- (void *)(from), n)
-
-#define __copy_to_user_inatomic __copy_to_user
-#define __copy_from_user_inatomic __copy_from_user
-
-
#define copy_from_user(to,from,n) ({ \
void *__copy_to = (void *) (to); \
void *__copy_from = (void *) (from); \
@@ -438,9 +431,20 @@ __copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \
} else __copy_res = __copy_size; \
__copy_res; })
-#define __copy_from_user(to,from,n) \
- __copy_user((void *)(to), \
- (void *)(from), n)
+static __always_inline unsigned long
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+ return __copy_user(to, (__force void *)from, n);
+}
+
+static __always_inline unsigned long __must_check
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ return __copy_user((__force void *)to, from, n);
+}
+
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
/*
* Clear the area and return remaining number of bytes
diff --git a/include/asm-sh/ubc.h b/include/asm-sh/ubc.h
index ae9bbdeefbe1..38d46e01b846 100644
--- a/include/asm-sh/ubc.h
+++ b/include/asm-sh/ubc.h
@@ -51,9 +51,14 @@
#define BRCR_UBDE (1 << 0)
#ifndef __ASSEMBLY__
-/* arch/sh/kernel/ubc.S */
-extern void ubc_wakeup(void);
+/* arch/sh/kernel/cpu/ubc.S */
extern void ubc_sleep(void);
+
+#ifdef CONFIG_UBC_WAKEUP
+extern void ubc_wakeup(void);
+#else
+#define ubc_wakeup() do { } while (0)
+#endif
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 77bcb09d6ac8..b182b1cb05fd 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -332,8 +332,9 @@
#define __NR_signalfd 321
#define __NR_timerfd 322
#define __NR_eventfd 323
+#define __NR_fallocate 324
-#define NR_syscalls 324
+#define NR_syscalls 325
#ifdef __KERNEL__
diff --git a/include/asm-sh64/a.out.h b/include/asm-sh64/a.out.h
index e1995e86b663..237ee4e5b72a 100644
--- a/include/asm-sh64/a.out.h
+++ b/include/asm-sh64/a.out.h
@@ -31,6 +31,7 @@ struct exec
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
#endif
diff --git a/include/asm-sh64/fb.h b/include/asm-sh64/fb.h
new file mode 100644
index 000000000000..d92e99cd8c8a
--- /dev/null
+++ b/include/asm-sh64/fb.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-sh64/irq.h b/include/asm-sh64/irq.h
index 1ca49e29288a..5c9e6a873aeb 100644
--- a/include/asm-sh64/irq.h
+++ b/include/asm-sh64/irq.h
@@ -114,10 +114,6 @@
#define IRL0_PRIORITY 13
#define TOP_PRIORITY 15
-extern void disable_irq(unsigned int);
-extern void disable_irq_nosync(unsigned int);
-extern void enable_irq(unsigned int);
-
extern int intc_evt_to_irq[(0xE20/0x20)+1];
int intc_irq_describe(char* p, int irq);
diff --git a/include/asm-sh64/pci.h b/include/asm-sh64/pci.h
index aa8043089bb6..57a67cf7a5c4 100644
--- a/include/asm-sh64/pci.h
+++ b/include/asm-sh64/pci.h
@@ -72,11 +72,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
#endif
-/* Not supporting more than 32-bit PCI bus addresses now, but
- * must satisfy references to this function. Change if needed.
- */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
/* These macros should be used after a pci_map_sg call has been done
* to get bus addresses of each of the SG entries and their lengths.
* You should only work with the number of sg entries pci_map_sg
@@ -104,10 +99,6 @@ extern void pcibios_fixup_irqs(void);
extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
#endif
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* __KERNEL__ */
/* generic pci stuff */
diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h
index b875482eb592..3488fe32e436 100644
--- a/include/asm-sh64/pgtable.h
+++ b/include/asm-sh64/pgtable.h
@@ -415,22 +415,15 @@ 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_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; }
-static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_EXECUTE; }
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 pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_READ)); return pte; }
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_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_EXECUTE)); return pte; }
static inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
static inline pte_t pte_mkold(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
-
-static inline pte_t pte_mkread(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_READ)); return pte; }
static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_WRITE)); return pte; }
-static inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_EXECUTE)); return 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; }
diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h
index ea3adc600b41..1a5197f369b2 100644
--- a/include/asm-sh64/unistd.h
+++ b/include/asm-sh64/unistd.h
@@ -374,10 +374,11 @@
#define __NR_signalfd 349
#define __NR_timerfd 350
#define __NR_eventfd 351
+#define __NR_fallocate 352
#ifdef __KERNEL__
-#define NR_syscalls 352
+#define NR_syscalls 353
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-sparc/a.out.h b/include/asm-sparc/a.out.h
index 9090060a23e6..917e04250696 100644
--- a/include/asm-sparc/a.out.h
+++ b/include/asm-sparc/a.out.h
@@ -92,6 +92,7 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */
#include <asm/page.h>
#define STACK_TOP (PAGE_OFFSET - PAGE_SIZE)
+#define STACK_TOP_MAX STACK_TOP
#endif /* __KERNEL__ */
diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h
index d8f9872b0e2d..4a56d84d69c4 100644
--- a/include/asm-sparc/device.h
+++ b/include/asm-sparc/device.h
@@ -3,5 +3,17 @@
*
* This file is released under the GPLv2
*/
-#include <asm-generic/device.h>
+#ifndef _ASM_SPARC_DEVICE_H
+#define _ASM_SPARC_DEVICE_H
+
+struct device_node;
+struct of_device;
+
+struct dev_archdata {
+ struct device_node *prom_node;
+ struct of_device *op;
+};
+
+#endif /* _ASM_SPARC_DEVICE_H */
+
diff --git a/include/asm-sparc/fb.h b/include/asm-sparc/fb.h
new file mode 100644
index 000000000000..c73ca081e1f5
--- /dev/null
+++ b/include/asm-sparc/fb.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+#include <asm/prom.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ struct device *dev = info->device;
+ struct device_node *node;
+
+ node = dev->archdata.prom_node;
+ if (node &&
+ node == of_console_device)
+ return 1;
+
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
index ff520ea97473..61fb99643afd 100644
--- a/include/asm-sparc/irq.h
+++ b/include/asm-sparc/irq.h
@@ -7,178 +7,12 @@
#ifndef _SPARC_IRQ_H
#define _SPARC_IRQ_H
-#include <linux/linkage.h>
-#include <linux/threads.h> /* For NR_CPUS */
#include <linux/interrupt.h>
-#include <asm/system.h> /* For SUN4M_NCPUS */
-#include <asm/btfixup.h>
-
-#define __irq_ino(irq) irq
-#define __irq_pil(irq) irq
-
#define NR_IRQS 16
#define irq_canonicalize(irq) (irq)
-/* Dave Redman (djhr@tadpole.co.uk)
- * changed these to function pointers.. it saves cycles and will allow
- * the irq dependencies to be split into different files at a later date
- * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size.
- * Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Changed these to btfixup entities... It saves cycles :)
- */
-BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, clear_clock_irq, void)
-BTFIXUPDEF_CALL(void, clear_profile_irq, int)
-BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
-
-static inline void disable_irq_nosync(unsigned int irq)
-{
- BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void disable_irq(unsigned int irq)
-{
- BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void enable_irq(unsigned int irq)
-{
- BTFIXUP_CALL(enable_irq)(irq);
-}
-
-static inline void disable_pil_irq(unsigned int irq)
-{
- BTFIXUP_CALL(disable_pil_irq)(irq);
-}
-
-static inline void enable_pil_irq(unsigned int irq)
-{
- BTFIXUP_CALL(enable_pil_irq)(irq);
-}
-
-static inline void clear_clock_irq(void)
-{
- BTFIXUP_CALL(clear_clock_irq)();
-}
-
-static inline void clear_profile_irq(int irq)
-{
- BTFIXUP_CALL(clear_profile_irq)(irq);
-}
-
-static inline void load_profile_irq(int cpu, int limit)
-{
- BTFIXUP_CALL(load_profile_irq)(cpu, limit);
-}
-
-extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
-extern void claim_ticker14(irq_handler_t irq_handler,
- int irq,
- unsigned int timeout);
-
-#ifdef CONFIG_SMP
-BTFIXUPDEF_CALL(void, set_cpu_int, int, int)
-BTFIXUPDEF_CALL(void, clear_cpu_int, int, int)
-BTFIXUPDEF_CALL(void, set_irq_udt, int)
-
-#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
-#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
-#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
-#endif
-
extern int request_fast_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, __const__ char *devname);
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
- unsigned int tbt; /* Interrupts still pending for this cpu. */
-
- /* These next two registers are WRITE-ONLY and are only
- * "on bit" sensitive, "off bits" written have NO affect.
- */
- unsigned int clear; /* Clear this cpus irqs here. */
- unsigned int set; /* Set this cpus irqs here. */
- unsigned char space[PAGE_SIZE - 12];
-};
-
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- * sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
- struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
- unsigned int tbt; /* IRQ's that are still pending. */
- unsigned int irqs; /* Master IRQ bits. */
-
- /* Again, like the above, two these registers are WRITE-ONLY. */
- unsigned int clear; /* Clear master IRQ's by setting bits here. */
- unsigned int set; /* Set master IRQ's by setting bits here. */
-
- /* This register is both READ and WRITE. */
- unsigned int undirected_target; /* Which cpu gets undirected irqs. */
-};
-
-extern struct sun4m_intregs *sun4m_interrupts;
-
-/*
- * Bit field defines for the interrupt registers on various
- * Sparc machines.
- */
-
-/* The sun4c interrupt register. */
-#define SUN4C_INT_ENABLE 0x01 /* Allow interrupts. */
-#define SUN4C_INT_E14 0x80 /* Enable level 14 IRQ. */
-#define SUN4C_INT_E10 0x20 /* Enable level 10 IRQ. */
-#define SUN4C_INT_E8 0x10 /* Enable level 8 IRQ. */
-#define SUN4C_INT_E6 0x08 /* Enable level 6 IRQ. */
-#define SUN4C_INT_E4 0x04 /* Enable level 4 IRQ. */
-#define SUN4C_INT_E1 0x02 /* Enable level 1 IRQ. */
-
-/* Dave Redman (djhr@tadpole.co.uk)
- * The sun4m interrupt registers.
- */
-#define SUN4M_INT_ENABLE 0x80000000
-#define SUN4M_INT_E14 0x00000080
-#define SUN4M_INT_E10 0x00080000
-
-#define SUN4M_HARD_INT(x) (0x000000001 << (x))
-#define SUN4M_SOFT_INT(x) (0x000010000 << (x))
-
-#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
-#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
-#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
-#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
-#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
-#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
-#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
-#define SUN4M_INT_REALTIME 0x00080000 /* system timer */
-#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */
-#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */
-#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */
-#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
-#define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */
-#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
-
-#define SUN4M_INT_SBUS(x) (1 << (x+7))
-#define SUN4M_INT_VME(x) (1 << (x))
-
#endif
diff --git a/include/asm-sparc/of_device.h b/include/asm-sparc/of_device.h
index 7cb00c1b09c6..e5f5aedc2293 100644
--- a/include/asm-sparc/of_device.h
+++ b/include/asm-sparc/of_device.h
@@ -3,13 +3,9 @@
#ifdef __KERNEL__
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/mod_devicetable.h>
#include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
/*
* The of_device is a kind of "base class" that is a superset of
@@ -30,50 +26,13 @@ struct of_device
int portid;
int clock_freq;
};
-#define to_of_device(d) container_of(d, struct of_device, dev)
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
- const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
- char *name;
- struct of_device_id *match_table;
- struct module *owner;
-
- int (*probe)(struct of_device* dev, const struct of_device_id *match);
- int (*remove)(struct of_device* dev);
-
- int (*suspend)(struct of_device* dev, pm_message_t state);
- int (*resume)(struct of_device* dev);
- int (*shutdown)(struct of_device* dev);
-
- struct device_driver driver;
-};
-#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
- struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent,
- struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
#endif /* __KERNEL__ */
#endif /* _ASM_SPARC_OF_DEVICE_H */
diff --git a/include/asm-sparc/of_platform.h b/include/asm-sparc/of_platform.h
new file mode 100644
index 000000000000..64a230064ef2
--- /dev/null
+++ b/include/asm-sparc/of_platform.h
@@ -0,0 +1,32 @@
+#ifndef _ASM_SPARC_OF_PLATFORM_H
+#define _ASM_SPARC_OF_PLATFORM_H
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ * Modified for Sparc by merging parts of asm-sparc/of_device.h
+ * by Stephen Rothwell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+/* This is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type of_platform_bus_type /* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+ struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent,
+ struct bus_type *bus);
+
+#endif /* _ASM_SPARC_OF_PLATFORM_H */
diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h
index 91691e52c058..17ba82ee220a 100644
--- a/include/asm-sparc/oplib.h
+++ b/include/asm-sparc/oplib.h
@@ -158,32 +158,6 @@ extern void prom_putchar(char character);
extern void prom_printf(char *fmt, ...);
extern void prom_write(const char *buf, unsigned int len);
-/* Query for input device type */
-
-enum prom_input_device {
- PROMDEV_IKBD, /* input from keyboard */
- PROMDEV_ITTYA, /* input from ttya */
- PROMDEV_ITTYB, /* input from ttyb */
- PROMDEV_IRSC, /* input from rsc */
- PROMDEV_IVCONS, /* input from virtual-console */
- PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
- PROMDEV_OSCREEN, /* to screen */
- PROMDEV_OTTYA, /* to ttya */
- PROMDEV_OTTYB, /* to ttyb */
- PROMDEV_ORSC, /* to rsc */
- PROMDEV_OVCONS, /* to virtual-console */
- PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
/* Multiprocessor operations... */
/* Start the CPU with the given device tree node, context table, and context
diff --git a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h
index a750c688408b..b93b6c79e08f 100644
--- a/include/asm-sparc/pci.h
+++ b/include/asm-sparc/pci.h
@@ -142,8 +142,6 @@ static inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
return 1;
}
-#define pci_dac_dma_supported(dev, mask) (0)
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -154,10 +152,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
}
#endif
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#define PCI_DMA_ERROR_CODE (~(dma_addr_t)0x0)
static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
diff --git a/include/asm-sparc/pgtable.h b/include/asm-sparc/pgtable.h
index 59229aeba27b..2cc235b74d94 100644
--- a/include/asm-sparc/pgtable.h
+++ b/include/asm-sparc/pgtable.h
@@ -46,7 +46,6 @@ BTFIXUPDEF_SIMM13(user_ptrs_per_pgd)
#define pgd_ERROR(e) __builtin_trap()
BTFIXUPDEF_INT(page_none)
-BTFIXUPDEF_INT(page_shared)
BTFIXUPDEF_INT(page_copy)
BTFIXUPDEF_INT(page_readonly)
BTFIXUPDEF_INT(page_kernel)
@@ -66,7 +65,7 @@ BTFIXUPDEF_INT(page_kernel)
#define PTE_SIZE (PTRS_PER_PTE*4)
#define PAGE_NONE __pgprot(BTFIXUP_INT(page_none))
-#define PAGE_SHARED __pgprot(BTFIXUP_INT(page_shared))
+extern pgprot_t PAGE_SHARED;
#define PAGE_COPY __pgprot(BTFIXUP_INT(page_copy))
#define PAGE_READONLY __pgprot(BTFIXUP_INT(page_readonly))
@@ -151,7 +150,6 @@ BTFIXUPDEF_CALL_CONST(unsigned long, pgd_page_vaddr, pgd_t)
BTFIXUPDEF_SETHI(none_mask)
BTFIXUPDEF_CALL_CONST(int, pte_present, pte_t)
BTFIXUPDEF_CALL(void, pte_clear, pte_t *)
-BTFIXUPDEF_CALL(int, pte_read, pte_t)
static inline int pte_none(pte_t pte)
{
@@ -160,7 +158,6 @@ static inline int pte_none(pte_t pte)
#define pte_present(pte) BTFIXUP_CALL(pte_present)(pte)
#define pte_clear(mm,addr,pte) BTFIXUP_CALL(pte_clear)(pte)
-#define pte_read(pte) BTFIXUP_CALL(pte_read)(pte)
BTFIXUPDEF_CALL_CONST(int, pmd_bad, pmd_t)
BTFIXUPDEF_CALL_CONST(int, pmd_present, pmd_t)
diff --git a/include/asm-sparc/prom.h b/include/asm-sparc/prom.h
index 9ea105ebe2ff..350676c589f9 100644
--- a/include/asm-sparc/prom.h
+++ b/include/asm-sparc/prom.h
@@ -2,7 +2,6 @@
#define _SPARC_PROM_H
#ifdef __KERNEL__
-
/*
* Definitions for talking to the Open Firmware PROM on
* Power Macintosh computers.
@@ -17,11 +16,17 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <asm/atomic.h>
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+
+#define of_compat_cmp(s1, s2, l) strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2) strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2) strcmp((s1), (s2))
+
typedef u32 phandle;
typedef u32 ihandle;
@@ -55,53 +60,34 @@ struct device_node {
unsigned int unique_id;
};
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
-#define OF_BAD_ADDR ((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
- dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name);
-#define for_each_node_by_name(dn, name) \
- for (dn = of_find_node_by_name(NULL, name); dn; \
- dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
- const char *type);
-#define for_each_node_by_type(dn, type) \
- for (dn = of_find_node_by_type(NULL, type); dn; \
- dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
- const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
- struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
- const char *);
-extern const void *of_get_property(const struct device_node *node,
- const char *name,
- int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
extern int of_getintprop_default(struct device_node *np,
const char *name,
int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
extern void prom_build_devicetree(void);
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+ return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB: This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
#endif /* __KERNEL__ */
#endif /* _SPARC_PROM_H */
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index 8b4e23b3bb38..d1a2572e3f55 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -165,16 +165,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
} while(0)
/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
-/*
* Changing the IRQ level on the Sparc.
*/
extern void local_irq_restore(unsigned long);
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index 64471bcd96f9..029b3e0d5e4c 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.74 2002/02/08 03:57:18 davem Exp $ */
#ifndef _SPARC_UNISTD_H
#define _SPARC_UNISTD_H
@@ -9,7 +8,7 @@
* think of right now to force the arguments into fixed registers
* before the trap into the system call with gcc 'asm' statements.
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
*
* SunOS compatibility based upon preliminary work which is:
*
@@ -330,8 +329,9 @@
#define __NR_signalfd 311
#define __NR_timerfd 312
#define __NR_eventfd 313
+#define __NR_fallocate 314
-#define NR_SYSCALLS 314
+#define NR_SYSCALLS 315
#ifdef __KERNEL__
#define __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/include/asm-sparc64/a.out.h b/include/asm-sparc64/a.out.h
index eb3b8e90b279..902e07f89a42 100644
--- a/include/asm-sparc64/a.out.h
+++ b/include/asm-sparc64/a.out.h
@@ -101,6 +101,8 @@ struct relocation_info /* used when header.a_machtype == M_SPARC */
#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
STACK_TOP32 : STACK_TOP64)
+#define STACK_TOP_MAX STACK_TOP64
+
#endif
#endif /* !(__ASSEMBLY__) */
diff --git a/include/asm-sparc64/bugs.h b/include/asm-sparc64/bugs.h
index bf39d86c0c9e..11ade6841971 100644
--- a/include/asm-sparc64/bugs.h
+++ b/include/asm-sparc64/bugs.h
@@ -4,12 +4,7 @@
*/
#include <asm/sstate.h>
-extern unsigned long loops_per_jiffy;
-
static void __init check_bugs(void)
{
-#ifndef CONFIG_SMP
- cpu_data(0).udelay_val = loops_per_jiffy;
-#endif
sstate_running();
}
diff --git a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h
index 36511ca51416..01fe6682b405 100644
--- a/include/asm-sparc64/compat.h
+++ b/include/asm-sparc64/compat.h
@@ -31,8 +31,10 @@ typedef s32 compat_timer_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
+typedef s64 compat_s64;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
+typedef u64 compat_u64;
struct compat_timespec {
compat_time_t tv_sec;
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index 445026fbec35..98a6e609163e 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -19,7 +19,7 @@ typedef struct {
unsigned int __softirq_pending; /* must be 1st, see rtrap.S */
unsigned int __pad0;
unsigned long clock_tick; /* %tick's per second */
- unsigned long udelay_val;
+ unsigned long __pad;
unsigned int __pad1;
unsigned int __pad2;
@@ -80,7 +80,8 @@ struct trap_per_cpu {
unsigned int dev_mondo_qmask;
unsigned int resum_qmask;
unsigned int nonresum_qmask;
- unsigned int __pad2[3];
+ unsigned int __pad2[1];
+ void *hdesc;
} __attribute__((aligned(64)));
extern struct trap_per_cpu trap_block[NR_CPUS];
extern void init_cur_cpu_trap(struct thread_info *);
diff --git a/include/asm-sparc64/delay.h b/include/asm-sparc64/delay.h
index a4aae6f80627..a77aa622d762 100644
--- a/include/asm-sparc64/delay.h
+++ b/include/asm-sparc64/delay.h
@@ -1,37 +1,17 @@
/* delay.h: Linux delay routines on sparc64.
*
- * Copyright (C) 1996, 2004 David S. Miller (davem@davemloft.net).
- *
- * Based heavily upon x86 variant which is:
- * Copyright (C) 1993 Linus Torvalds
- *
- * Delay routines calling functions in arch/sparc64/lib/delay.c
+ * Copyright (C) 1996, 2004, 2007 David S. Miller (davem@davemloft.net).
*/
-#ifndef __SPARC64_DELAY_H
-#define __SPARC64_DELAY_H
-
-#include <linux/param.h>
-#include <asm/cpudata.h>
+#ifndef _SPARC64_DELAY_H
+#define _SPARC64_DELAY_H
#ifndef __ASSEMBLY__
-extern void __bad_udelay(void);
-extern void __bad_ndelay(void);
-
-extern void __udelay(unsigned long usecs);
-extern void __ndelay(unsigned long nsecs);
-extern void __const_udelay(unsigned long usecs);
extern void __delay(unsigned long loops);
-
-#define udelay(n) (__builtin_constant_p(n) ? \
- ((n) > 20000 ? __bad_udelay() : __const_udelay((n) * 0x10c7ul)) : \
- __udelay(n))
-
-#define ndelay(n) (__builtin_constant_p(n) ? \
- ((n) > 20000 ? __bad_ndelay() : __const_udelay((n) * 5ul)) : \
- __ndelay(n))
+extern void udelay(unsigned long usecs);
+#define mdelay(n) udelay((n) * 1000)
#endif /* !__ASSEMBLY__ */
-#endif /* defined(__SPARC64_DELAY_H) */
+#endif /* _SPARC64_DELAY_H */
diff --git a/include/asm-sparc64/fb.h b/include/asm-sparc64/fb.h
new file mode 100644
index 000000000000..389012e5fbad
--- /dev/null
+++ b/include/asm-sparc64/fb.h
@@ -0,0 +1,27 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+#include <asm/prom.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ struct device *dev = info->device;
+ struct device_node *node;
+
+ node = dev->archdata.prom_node;
+ if (node &&
+ node == of_console_device)
+ return 1;
+
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-sparc64/hvtramp.h b/include/asm-sparc64/hvtramp.h
new file mode 100644
index 000000000000..c7dd6ad056df
--- /dev/null
+++ b/include/asm-sparc64/hvtramp.h
@@ -0,0 +1,37 @@
+#ifndef _SPARC64_HVTRAP_H
+#define _SPARC64_HVTRAP_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+struct hvtramp_mapping {
+ __u64 vaddr;
+ __u64 tte;
+};
+
+struct hvtramp_descr {
+ __u32 cpu;
+ __u32 num_mappings;
+ __u64 fault_info_va;
+ __u64 fault_info_pa;
+ __u64 thread_reg;
+ struct hvtramp_mapping maps[2];
+};
+
+extern void hv_cpu_startup(unsigned long hvdescr_pa);
+
+#endif
+
+#define HVTRAMP_DESCR_CPU 0x00
+#define HVTRAMP_DESCR_NUM_MAPPINGS 0x04
+#define HVTRAMP_DESCR_FAULT_INFO_VA 0x08
+#define HVTRAMP_DESCR_FAULT_INFO_PA 0x10
+#define HVTRAMP_DESCR_THREAD_REG 0x18
+#define HVTRAMP_DESCR_MAPS 0x20
+
+#define HVTRAMP_MAPPING_VADDR 0x00
+#define HVTRAMP_MAPPING_TTE 0x08
+#define HVTRAMP_MAPPING_SIZE 0x10
+
+#endif /* _SPARC64_HVTRAP_H */
diff --git a/include/asm-sparc64/hypervisor.h b/include/asm-sparc64/hypervisor.h
index db2130a95d68..524d49835dfd 100644
--- a/include/asm-sparc64/hypervisor.h
+++ b/include/asm-sparc64/hypervisor.h
@@ -98,7 +98,7 @@
#define HV_FAST_MACH_EXIT 0x00
#ifndef __ASSEMBLY__
-extern void sun4v_mach_exit(unsigned long exit_core);
+extern void sun4v_mach_exit(unsigned long exit_code);
#endif
/* Domain services. */
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index ad595b679842..9565a892801e 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -14,11 +14,6 @@
#define __SLOW_DOWN_IO do { } while (0)
#define SLOW_DOWN_IO do { } while (0)
-extern unsigned long virt_to_bus_not_defined_use_pci_map(volatile void *addr);
-#define virt_to_bus virt_to_bus_not_defined_use_pci_map
-extern unsigned long bus_to_virt_not_defined_use_pci_map(volatile void *addr);
-#define bus_to_virt bus_to_virt_not_defined_use_pci_map
-
/* BIO layer definitions. */
extern unsigned long kern_base, kern_size;
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
index 90781e34a95c..e6c436ef9356 100644
--- a/include/asm-sparc64/irq.h
+++ b/include/asm-sparc64/irq.h
@@ -53,6 +53,8 @@ extern unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
extern void sun4v_destroy_msi(unsigned int virt_irq);
extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
+extern void fixup_irqs(void);
+
static __inline__ void set_softint(unsigned long bits)
{
__asm__ __volatile__("wr %0, 0x0, %%set_softint"
diff --git a/include/asm-sparc64/kprobes.h b/include/asm-sparc64/kprobes.h
index a331b7b0dff2..7f6774dca5f4 100644
--- a/include/asm-sparc64/kprobes.h
+++ b/include/asm-sparc64/kprobes.h
@@ -10,7 +10,6 @@ typedef u32 kprobe_opcode_t;
#define BREAKPOINT_INSTRUCTION_2 0x91d02071 /* ta 0x71 */
#define MAX_INSN_SIZE 2
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
#define arch_remove_kprobe(p) do {} while (0)
#define ARCH_INACTIVE_KPROBE_COUNT 0
diff --git a/include/asm-sparc64/ldc.h b/include/asm-sparc64/ldc.h
new file mode 100644
index 000000000000..bdb524a7b814
--- /dev/null
+++ b/include/asm-sparc64/ldc.h
@@ -0,0 +1,138 @@
+#ifndef _SPARC64_LDC_H
+#define _SPARC64_LDC_H
+
+#include <asm/hypervisor.h>
+
+extern int ldom_domaining_enabled;
+extern void ldom_set_var(const char *var, const char *value);
+extern void ldom_reboot(const char *boot_command);
+extern void ldom_power_off(void);
+
+/* The event handler will be evoked when link state changes
+ * or data becomes available on the receive side.
+ *
+ * For non-RAW links, if the LDC_EVENT_RESET event arrives the
+ * driver should reset all of it's internal state and reinvoke
+ * ldc_connect() to try and bring the link up again.
+ *
+ * For RAW links, ldc_connect() is not used. Instead the driver
+ * just waits for the LDC_EVENT_UP event.
+ */
+struct ldc_channel_config {
+ void (*event)(void *arg, int event);
+
+ u32 mtu;
+ unsigned int rx_irq;
+ unsigned int tx_irq;
+ u8 mode;
+#define LDC_MODE_RAW 0x00
+#define LDC_MODE_UNRELIABLE 0x01
+#define LDC_MODE_RESERVED 0x02
+#define LDC_MODE_STREAM 0x03
+
+ u8 debug;
+#define LDC_DEBUG_HS 0x01
+#define LDC_DEBUG_STATE 0x02
+#define LDC_DEBUG_RX 0x04
+#define LDC_DEBUG_TX 0x08
+#define LDC_DEBUG_DATA 0x10
+};
+
+#define LDC_EVENT_RESET 0x01
+#define LDC_EVENT_UP 0x02
+#define LDC_EVENT_DATA_READY 0x04
+
+#define LDC_STATE_INVALID 0x00
+#define LDC_STATE_INIT 0x01
+#define LDC_STATE_BOUND 0x02
+#define LDC_STATE_READY 0x03
+#define LDC_STATE_CONNECTED 0x04
+
+struct ldc_channel;
+
+/* Allocate state for a channel. */
+extern struct ldc_channel *ldc_alloc(unsigned long id,
+ const struct ldc_channel_config *cfgp,
+ void *event_arg);
+
+/* Shut down and free state for a channel. */
+extern void ldc_free(struct ldc_channel *lp);
+
+/* Register TX and RX queues of the link with the hypervisor. */
+extern int ldc_bind(struct ldc_channel *lp, const char *name);
+
+/* For non-RAW protocols we need to complete a handshake before
+ * communication can proceed. ldc_connect() does that, if the
+ * handshake completes successfully, an LDC_EVENT_UP event will
+ * be sent up to the driver.
+ */
+extern int ldc_connect(struct ldc_channel *lp);
+extern int ldc_disconnect(struct ldc_channel *lp);
+
+extern int ldc_state(struct ldc_channel *lp);
+
+/* Read and write operations. Only valid when the link is up. */
+extern int ldc_write(struct ldc_channel *lp, const void *buf,
+ unsigned int size);
+extern int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size);
+
+#define LDC_MAP_SHADOW 0x01
+#define LDC_MAP_DIRECT 0x02
+#define LDC_MAP_IO 0x04
+#define LDC_MAP_R 0x08
+#define LDC_MAP_W 0x10
+#define LDC_MAP_X 0x20
+#define LDC_MAP_RW (LDC_MAP_R | LDC_MAP_W)
+#define LDC_MAP_RWX (LDC_MAP_R | LDC_MAP_W | LDC_MAP_X)
+#define LDC_MAP_ALL 0x03f
+
+struct ldc_trans_cookie {
+ u64 cookie_addr;
+ u64 cookie_size;
+};
+
+struct scatterlist;
+extern int ldc_map_sg(struct ldc_channel *lp,
+ struct scatterlist *sg, int num_sg,
+ struct ldc_trans_cookie *cookies, int ncookies,
+ unsigned int map_perm);
+
+extern int ldc_map_single(struct ldc_channel *lp,
+ void *buf, unsigned int len,
+ struct ldc_trans_cookie *cookies, int ncookies,
+ unsigned int map_perm);
+
+extern void ldc_unmap(struct ldc_channel *lp, struct ldc_trans_cookie *cookies,
+ int ncookies);
+
+extern int ldc_copy(struct ldc_channel *lp, int copy_dir,
+ void *buf, unsigned int len, unsigned long offset,
+ struct ldc_trans_cookie *cookies, int ncookies);
+
+static inline int ldc_get_dring_entry(struct ldc_channel *lp,
+ void *buf, unsigned int len,
+ unsigned long offset,
+ struct ldc_trans_cookie *cookies,
+ int ncookies)
+{
+ return ldc_copy(lp, LDC_COPY_IN, buf, len, offset, cookies, ncookies);
+}
+
+static inline int ldc_put_dring_entry(struct ldc_channel *lp,
+ void *buf, unsigned int len,
+ unsigned long offset,
+ struct ldc_trans_cookie *cookies,
+ int ncookies)
+{
+ return ldc_copy(lp, LDC_COPY_OUT, buf, len, offset, cookies, ncookies);
+}
+
+extern void *ldc_alloc_exp_dring(struct ldc_channel *lp, unsigned int len,
+ struct ldc_trans_cookie *cookies,
+ int *ncookies, unsigned int map_perm);
+
+extern void ldc_free_exp_dring(struct ldc_channel *lp, void *buf,
+ unsigned int len,
+ struct ldc_trans_cookie *cookies, int ncookies);
+
+#endif /* _SPARC64_LDC_H */
diff --git a/include/asm-sparc64/mdesc.h b/include/asm-sparc64/mdesc.h
index c6383982b53d..1acc7272e537 100644
--- a/include/asm-sparc64/mdesc.h
+++ b/include/asm-sparc64/mdesc.h
@@ -2,38 +2,76 @@
#define _SPARC64_MDESC_H
#include <linux/types.h>
+#include <linux/cpumask.h>
#include <asm/prom.h>
-struct mdesc_node;
-struct mdesc_arc {
- const char *name;
- struct mdesc_node *arc;
-};
+struct mdesc_handle;
+
+/* Machine description operations are to be surrounded by grab and
+ * release calls. The mdesc_handle returned from the grab is
+ * the first argument to all of the operational calls that work
+ * on mdescs.
+ */
+extern struct mdesc_handle *mdesc_grab(void);
+extern void mdesc_release(struct mdesc_handle *);
+
+#define MDESC_NODE_NULL (~(u64)0)
+
+extern u64 mdesc_node_by_name(struct mdesc_handle *handle,
+ u64 from_node, const char *name);
+#define mdesc_for_each_node_by_name(__hdl, __node, __name) \
+ for (__node = mdesc_node_by_name(__hdl, MDESC_NODE_NULL, __name); \
+ (__node) != MDESC_NODE_NULL; \
+ __node = mdesc_node_by_name(__hdl, __node, __name))
+
+/* Access to property values returned from mdesc_get_property() are
+ * only valid inside of a mdesc_grab()/mdesc_release() sequence.
+ * Once mdesc_release() is called, the memory backed up by these
+ * pointers may reference freed up memory.
+ *
+ * Therefore callers must make copies of any property values
+ * they need.
+ *
+ * These same rules apply to mdesc_node_name().
+ */
+extern const void *mdesc_get_property(struct mdesc_handle *handle,
+ u64 node, const char *name, int *lenp);
+extern const char *mdesc_node_name(struct mdesc_handle *hp, u64 node);
+
+/* MD arc iteration, the standard sequence is:
+ *
+ * unsigned long arc;
+ * mdesc_for_each_arc(arc, handle, node, MDESC_ARC_TYPE_{FWD,BACK}) {
+ * unsigned long target = mdesc_arc_target(handle, arc);
+ * ...
+ * }
+ */
-struct mdesc_node {
- const char *name;
- u64 node;
- unsigned int unique_id;
- unsigned int num_arcs;
- unsigned int irqs[2];
- struct property *properties;
- struct mdesc_node *hash_next;
- struct mdesc_node *allnodes_next;
- struct mdesc_arc arcs[0];
+#define MDESC_ARC_TYPE_FWD "fwd"
+#define MDESC_ARC_TYPE_BACK "back"
+
+extern u64 mdesc_next_arc(struct mdesc_handle *handle, u64 from,
+ const char *arc_type);
+#define mdesc_for_each_arc(__arc, __hdl, __node, __type) \
+ for (__arc = mdesc_next_arc(__hdl, __node, __type); \
+ (__arc) != MDESC_NODE_NULL; \
+ __arc = mdesc_next_arc(__hdl, __arc, __type))
+
+extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
+
+extern void mdesc_update(void);
+
+struct mdesc_notifier_client {
+ void (*add)(struct mdesc_handle *handle, u64 node);
+ void (*remove)(struct mdesc_handle *handle, u64 node);
+
+ const char *node_name;
+ struct mdesc_notifier_client *next;
};
-extern struct mdesc_node *md_find_node_by_name(struct mdesc_node *from,
- const char *name);
-#define md_for_each_node_by_name(__mn, __name) \
- for (__mn = md_find_node_by_name(NULL, __name); __mn; \
- __mn = md_find_node_by_name(__mn, __name))
-
-extern struct property *md_find_property(const struct mdesc_node *mp,
- const char *name,
- int *lenp);
-extern const void *md_get_property(const struct mdesc_node *mp,
- const char *name,
- int *lenp);
+extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
+
+extern void mdesc_fill_in_cpu_data(cpumask_t mask);
extern void sun4v_mdesc_init(void);
diff --git a/include/asm-sparc64/mmu_context.h b/include/asm-sparc64/mmu_context.h
index 8d129032013e..9fc225ed5500 100644
--- a/include/asm-sparc64/mmu_context.h
+++ b/include/asm-sparc64/mmu_context.h
@@ -76,6 +76,9 @@ static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, str
unsigned long ctx_valid, flags;
int cpu;
+ if (unlikely(mm == &init_mm))
+ return;
+
spin_lock_irqsave(&mm->context.lock, flags);
ctx_valid = CTX_VALID(mm->context);
if (!ctx_valid)
diff --git a/include/asm-sparc64/of_device.h b/include/asm-sparc64/of_device.h
index 60e9173c9acb..46d69b3223c5 100644
--- a/include/asm-sparc64/of_device.h
+++ b/include/asm-sparc64/of_device.h
@@ -3,14 +3,9 @@
#ifdef __KERNEL__
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/mod_devicetable.h>
#include <asm/openprom.h>
-#include <asm/prom.h>
-
-extern struct bus_type isa_bus_type;
-extern struct bus_type ebus_bus_type;
-extern struct bus_type sbus_bus_type;
-extern struct bus_type of_bus_type;
/*
* The of_device is a kind of "base class" that is a superset of
@@ -31,50 +26,13 @@ struct of_device
int portid;
int clock_freq;
};
-#define to_of_device(d) container_of(d, struct of_device, dev)
extern void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name);
extern void of_iounmap(struct resource *res, void __iomem *base, unsigned long size);
-extern struct of_device *of_find_device_by_node(struct device_node *);
-
-extern const struct of_device_id *of_match_device(
- const struct of_device_id *matches, const struct of_device *dev);
-
-extern struct of_device *of_dev_get(struct of_device *dev);
-extern void of_dev_put(struct of_device *dev);
-
-/*
- * An of_platform_driver driver is attached to a basic of_device on
- * the ISA, EBUS, and SBUS busses on sparc64.
- */
-struct of_platform_driver
-{
- char *name;
- struct of_device_id *match_table;
- struct module *owner;
-
- int (*probe)(struct of_device* dev, const struct of_device_id *match);
- int (*remove)(struct of_device* dev);
-
- int (*suspend)(struct of_device* dev, pm_message_t state);
- int (*resume)(struct of_device* dev);
- int (*shutdown)(struct of_device* dev);
-
- struct device_driver driver;
-};
-#define to_of_platform_driver(drv) container_of(drv,struct of_platform_driver, driver)
-
-extern int of_register_driver(struct of_platform_driver *drv,
- struct bus_type *bus);
-extern void of_unregister_driver(struct of_platform_driver *drv);
-extern int of_device_register(struct of_device *ofdev);
-extern void of_device_unregister(struct of_device *ofdev);
-extern struct of_device *of_platform_device_create(struct device_node *np,
- const char *bus_id,
- struct device *parent,
- struct bus_type *bus);
-extern void of_release_dev(struct device *dev);
+/* These are just here during the transition */
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
#endif /* __KERNEL__ */
#endif /* _ASM_SPARC64_OF_DEVICE_H */
diff --git a/include/asm-sparc64/of_platform.h b/include/asm-sparc64/of_platform.h
new file mode 100644
index 000000000000..f7c1f17c7d52
--- /dev/null
+++ b/include/asm-sparc64/of_platform.h
@@ -0,0 +1,33 @@
+#ifndef _ASM_SPARC64_OF_PLATFORM_H
+#define _ASM_SPARC64_OF_PLATFORM_H
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ * Modified for Sparc by merging parts of asm-sparc/of_device.h
+ * by Stephen Rothwell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+/* This is just here during the transition */
+#include <linux/of_platform.h>
+
+extern struct bus_type isa_bus_type;
+extern struct bus_type ebus_bus_type;
+extern struct bus_type sbus_bus_type;
+extern struct bus_type of_platform_bus_type;
+#define of_bus_type of_platform_bus_type /* for compatibility */
+
+extern int of_register_driver(struct of_platform_driver *drv,
+ struct bus_type *bus);
+extern void of_unregister_driver(struct of_platform_driver *drv);
+extern struct of_device *of_platform_device_create(struct device_node *np,
+ const char *bus_id,
+ struct device *parent,
+ struct bus_type *bus);
+
+#endif /* _ASM_SPARC64_OF_PLATFORM_H */
diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h
index 992f9f7a476c..3f23c5dc5f21 100644
--- a/include/asm-sparc64/oplib.h
+++ b/include/asm-sparc64/oplib.h
@@ -140,32 +140,6 @@ extern void prom_putchar(char character);
extern void prom_printf(const char *fmt, ...);
extern void prom_write(const char *buf, unsigned int len);
-/* Query for input device type */
-
-enum prom_input_device {
- PROMDEV_IKBD, /* input from keyboard */
- PROMDEV_ITTYA, /* input from ttya */
- PROMDEV_ITTYB, /* input from ttyb */
- PROMDEV_IRSC, /* input from rsc */
- PROMDEV_IVCONS, /* input from virtual-console */
- PROMDEV_I_UNK,
-};
-
-extern enum prom_input_device prom_query_input_device(void);
-
-/* Query for output device type */
-
-enum prom_output_device {
- PROMDEV_OSCREEN, /* to screen */
- PROMDEV_OTTYA, /* to ttya */
- PROMDEV_OTTYB, /* to ttyb */
- PROMDEV_ORSC, /* to rsc */
- PROMDEV_OVCONS, /* to virtual-console */
- PROMDEV_O_UNK,
-};
-
-extern enum prom_output_device prom_query_output_device(void);
-
/* Multiprocessor operations... */
#ifdef CONFIG_SMP
/* Start the CPU with the given device tree node at the passed program
@@ -319,6 +293,8 @@ extern int prom_inst2pkg(int);
extern int prom_service_exists(const char *service_name);
extern void prom_sun4v_guest_soft_state(void);
+extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
+
/* Client interface level routines. */
extern void prom_set_trap_table(unsigned long tba);
extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index 23cc63f049a8..600afe5ae2e3 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -8,8 +8,9 @@
#define _ASM_SPARC64_PARPORT_H 1
#include <asm/ebus.h>
-#include <asm/isa.h>
#include <asm/ns87303.h>
+#include <asm/of_device.h>
+#include <asm/prom.h>
#define PARPORT_PC_MAX_PORTS PARPORT_MAX
@@ -35,8 +36,12 @@ static struct sparc_ebus_info {
unsigned int addr;
unsigned int count;
int lock;
+
+ struct parport *port;
} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
+static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS);
+
static __inline__ int request_dma(unsigned int dmanr, const char *device_id)
{
if (dmanr >= PARPORT_PC_MAX_PORTS)
@@ -98,117 +103,145 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
}
-static int ebus_ecpp_p(struct linux_ebus_device *edev)
+static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match)
{
- if (!strcmp(edev->prom_node->name, "ecpp"))
- return 1;
- if (!strcmp(edev->prom_node->name, "parallel")) {
- const char *compat;
-
- compat = of_get_property(edev->prom_node,
- "compatible", NULL);
- if (compat &&
- (!strcmp(compat, "ecpp") ||
- !strcmp(compat, "ns87317-ecpp") ||
- !strcmp(compat + 13, "ecpp")))
- return 1;
+ unsigned long base = op->resource[0].start;
+ unsigned long config = op->resource[1].start;
+ unsigned long d_base = op->resource[2].start;
+ unsigned long d_len;
+ struct device_node *parent;
+ struct parport *p;
+ int slot, err;
+
+ parent = op->node->parent;
+ if (!strcmp(parent->name, "dma")) {
+ p = parport_pc_probe_port(base, base + 0x400,
+ op->irqs[0], PARPORT_DMA_NOFIFO,
+ op->dev.parent);
+ if (!p)
+ return -ENOMEM;
+ dev_set_drvdata(&op->dev, p);
+ return 0;
}
+
+ for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) {
+ if (!test_and_set_bit(slot, dma_slot_map))
+ break;
+ }
+ err = -ENODEV;
+ if (slot >= PARPORT_PC_MAX_PORTS)
+ goto out_err;
+
+ spin_lock_init(&sparc_ebus_dmas[slot].info.lock);
+
+ d_len = (op->resource[2].end - d_base) + 1UL;
+ sparc_ebus_dmas[slot].info.regs =
+ of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA");
+
+ if (!sparc_ebus_dmas[slot].info.regs)
+ goto out_clear_map;
+
+ sparc_ebus_dmas[slot].info.flags = 0;
+ sparc_ebus_dmas[slot].info.callback = NULL;
+ sparc_ebus_dmas[slot].info.client_cookie = NULL;
+ sparc_ebus_dmas[slot].info.irq = 0xdeadbeef;
+ strcpy(sparc_ebus_dmas[slot].info.name, "parport");
+ if (ebus_dma_register(&sparc_ebus_dmas[slot].info))
+ goto out_unmap_regs;
+
+ ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1);
+
+ /* Configure IRQ to Push Pull, Level Low */
+ /* Enable ECP, set bit 2 of the CTR first */
+ outb(0x04, base + 0x02);
+ ns87303_modify(config, PCR,
+ PCR_EPP_ENABLE |
+ PCR_IRQ_ODRAIN,
+ PCR_ECP_ENABLE |
+ PCR_ECP_CLK_ENA |
+ PCR_IRQ_POLAR);
+
+ /* CTR bit 5 controls direction of port */
+ ns87303_modify(config, PTR,
+ 0, PTR_LPT_REG_DIR);
+
+ p = parport_pc_probe_port(base, base + 0x400,
+ op->irqs[0],
+ slot,
+ op->dev.parent);
+ err = -ENOMEM;
+ if (!p)
+ goto out_disable_irq;
+
+ dev_set_drvdata(&op->dev, p);
+
return 0;
+
+out_disable_irq:
+ ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+ ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+
+out_unmap_regs:
+ of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len);
+
+out_clear_map:
+ clear_bit(slot, dma_slot_map);
+
+out_err:
+ return err;
}
-static int parport_isa_probe(int count)
+static int __devexit ecpp_remove(struct of_device *op)
{
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev;
-
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- struct sparc_isa_device *child;
- unsigned long base;
-
- if (strcmp(isa_dev->prom_node->name, "dma"))
- continue;
-
- child = isa_dev->child;
- while (child) {
- if (!strcmp(child->prom_node->name, "parallel"))
- break;
- child = child->next;
- }
- if (!child)
- continue;
-
- base = child->resource.start;
-
- /* No DMA, see commentary in
- * asm-sparc64/floppy.h:isa_floppy_init()
- */
- if (parport_pc_probe_port(base, base + 0x400,
- child->irq, PARPORT_DMA_NOFIFO,
- &child->bus->self->dev))
- count++;
- }
+ struct parport *p = dev_get_drvdata(&op->dev);
+ int slot = p->dma;
+
+ parport_pc_unregister_port(p);
+
+ if (slot != PARPORT_DMA_NOFIFO) {
+ unsigned long d_base = op->resource[2].start;
+ unsigned long d_len;
+
+ d_len = (op->resource[2].end - d_base) + 1UL;
+
+ ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
+ ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
+ of_iounmap(&op->resource[2],
+ sparc_ebus_dmas[slot].info.regs,
+ d_len);
+ clear_bit(slot, dma_slot_map);
}
- return count;
+ return 0;
}
-static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
+static struct of_device_id ecpp_match[] = {
+ {
+ .name = "ecpp",
+ },
+ {
+ .name = "parallel",
+ .compatible = "ecpp",
+ },
+ {
+ .name = "parallel",
+ .compatible = "ns87317-ecpp",
+ },
+ {},
+};
+
+static struct of_platform_driver ecpp_driver = {
+ .name = "ecpp",
+ .match_table = ecpp_match,
+ .probe = ecpp_probe,
+ .remove = __devexit_p(ecpp_remove),
+};
+
+static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
{
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
- int count = 0;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (ebus_ecpp_p(edev)) {
- unsigned long base = edev->resource[0].start;
- unsigned long config = edev->resource[1].start;
- unsigned long d_base = edev->resource[2].start;
- unsigned long d_len;
-
- spin_lock_init(&sparc_ebus_dmas[count].info.lock);
- d_len = (edev->resource[2].end -
- d_base) + 1;
- sparc_ebus_dmas[count].info.regs =
- ioremap(d_base, d_len);
- if (!sparc_ebus_dmas[count].info.regs)
- continue;
- sparc_ebus_dmas[count].info.flags = 0;
- sparc_ebus_dmas[count].info.callback = NULL;
- sparc_ebus_dmas[count].info.client_cookie = NULL;
- sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
- strcpy(sparc_ebus_dmas[count].info.name, "parport");
- if (ebus_dma_register(&sparc_ebus_dmas[count].info))
- continue;
- ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
-
- /* Configure IRQ to Push Pull, Level Low */
- /* Enable ECP, set bit 2 of the CTR first */
- outb(0x04, base + 0x02);
- ns87303_modify(config, PCR,
- PCR_EPP_ENABLE |
- PCR_IRQ_ODRAIN,
- PCR_ECP_ENABLE |
- PCR_ECP_CLK_ENA |
- PCR_IRQ_POLAR);
-
- /* CTR bit 5 controls direction of port */
- ns87303_modify(config, PTR,
- 0, PTR_LPT_REG_DIR);
-
- if (parport_pc_probe_port(base, base + 0x400,
- edev->irqs[0],
- count,
- &ebus->self->dev))
- count++;
- }
- }
- }
+ of_register_driver(&ecpp_driver, &of_bus_type);
- count = parport_isa_probe(count);
-
- return count;
+ return 0;
}
#endif /* !(_ASM_SPARC64_PARPORT_H */
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
index 47cea16e1bad..e11ac100f043 100644
--- a/include/asm-sparc64/pci.h
+++ b/include/asm-sparc64/pci.h
@@ -206,49 +206,6 @@ extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask);
#define PCI64_REQUIRED_MASK (~(dma64_addr_t)0)
#define PCI64_ADDR_BASE 0xfffc000000000000UL
-/* Usage of the pci_dac_foo interfaces is only valid if this
- * test passes.
- */
-#define pci_dac_dma_supported(pci_dev, mask) \
- ((((mask) & PCI64_REQUIRED_MASK) == PCI64_REQUIRED_MASK) ? 1 : 0)
-
-static inline dma64_addr_t
-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
-{
- return (PCI64_ADDR_BASE +
- __pa(page_address(page)) + offset);
-}
-
-static inline struct page *
-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- unsigned long paddr = (dma_addr & PAGE_MASK) - PCI64_ADDR_BASE;
-
- return virt_to_page(__va(paddr));
-}
-
-static inline unsigned long
-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return (dma_addr & ~PAGE_MASK);
-}
-
-static inline void
-pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
- /* DAC cycle addressing does not make use of the
- * PCI controller's streaming cache, so nothing to do.
- */
-}
-
-static inline void
-pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
- /* DAC cycle addressing does not make use of the
- * PCI controller's streaming cache, so nothing to do.
- */
-}
-
#define PCI_DMA_ERROR_CODE (~(dma_addr_t)0x0)
static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
@@ -303,10 +260,6 @@ pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
extern struct resource *pcibios_select_root(struct pci_dev *, struct resource *);
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
return PCI_IRQ_NONE;
diff --git a/include/asm-sparc64/percpu.h b/include/asm-sparc64/percpu.h
index 88db872ce2f8..caf8750792ff 100644
--- a/include/asm-sparc64/percpu.h
+++ b/include/asm-sparc64/percpu.h
@@ -18,6 +18,11 @@ extern unsigned long __per_cpu_shift;
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ __attribute__((__section__(".data.percpu.shared_aligned"))) \
+ __typeof__(type) per_cpu__##name \
+ ____cacheline_aligned_in_smp
+
register unsigned long __local_per_cpu_offset asm("g5");
/* var is in discarded region: offset to particular copy we want */
@@ -38,6 +43,8 @@ do { \
#define real_setup_per_cpu_areas() do { } while (0)
#define DEFINE_PER_CPU(type, name) \
__typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ DEFINE_PER_CPU(type, name)
#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h
index 9e80ad43b29c..0393380d754a 100644
--- a/include/asm-sparc64/pgtable.h
+++ b/include/asm-sparc64/pgtable.h
@@ -573,24 +573,6 @@ static inline unsigned long pte_exec(pte_t pte)
return (pte_val(pte) & mask);
}
-static inline unsigned long pte_read(pte_t pte)
-{
- unsigned long mask;
-
- __asm__ __volatile__(
- "\n661: mov %1, %0\n"
- " nop\n"
- " .section .sun4v_2insn_patch, \"ax\"\n"
- " .word 661b\n"
- " sethi %%uhi(%2), %0\n"
- " sllx %0, 32, %0\n"
- " .previous\n"
- : "=r" (mask)
- : "i" (_PAGE_READ_4U), "i" (_PAGE_READ_4V));
-
- return (pte_val(pte) & mask);
-}
-
static inline unsigned long pte_file(pte_t pte)
{
unsigned long val = pte_val(pte);
diff --git a/include/asm-sparc64/prom.h b/include/asm-sparc64/prom.h
index b4df3042add0..31dcb92fbae0 100644
--- a/include/asm-sparc64/prom.h
+++ b/include/asm-sparc64/prom.h
@@ -2,7 +2,6 @@
#define _SPARC64_PROM_H
#ifdef __KERNEL__
-
/*
* Definitions for talking to the Open Firmware PROM on
* Power Macintosh computers.
@@ -17,11 +16,17 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <asm/atomic.h>
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 2
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+
+#define of_compat_cmp(s1, s2, l) strncmp((s1), (s2), (l))
+#define of_prop_cmp(s1, s2) strcasecmp((s1), (s2))
+#define of_node_cmp(s1, s2) strcmp((s1), (s2))
+
typedef u32 phandle;
typedef u32 ihandle;
@@ -63,54 +68,35 @@ struct of_irq_controller {
void *data;
};
-/* flag descriptions */
-#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
-
#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
-#define OF_BAD_ADDR ((u64)-1)
-
-static inline void set_node_proc_entry(struct device_node *dn, struct proc_dir_entry *de)
-{
- dn->pde = de;
-}
-
-extern struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name);
-#define for_each_node_by_name(dn, name) \
- for (dn = of_find_node_by_name(NULL, name); dn; \
- dn = of_find_node_by_name(dn, name))
-extern struct device_node *of_find_node_by_type(struct device_node *from,
- const char *type);
-#define for_each_node_by_type(dn, type) \
- for (dn = of_find_node_by_type(NULL, type); dn; \
- dn = of_find_node_by_type(dn, type))
-extern struct device_node *of_find_compatible_node(struct device_node *from,
- const char *type, const char *compat);
-extern struct device_node *of_find_node_by_path(const char *path);
-extern struct device_node *of_find_node_by_phandle(phandle handle);
extern struct device_node *of_find_node_by_cpuid(int cpuid);
-extern struct device_node *of_get_parent(const struct device_node *node);
-extern struct device_node *of_get_next_child(const struct device_node *node,
- struct device_node *prev);
-extern struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp);
-extern int of_device_is_compatible(const struct device_node *device,
- const char *);
-extern const void *of_get_property(const struct device_node *node,
- const char *name,
- int *lenp);
-#define get_property(node,name,lenp) of_get_property(node,name,lenp)
extern int of_set_property(struct device_node *node, const char *name, void *val, int len);
extern int of_getintprop_default(struct device_node *np,
const char *name,
int def);
-extern int of_n_addr_cells(struct device_node *np);
-extern int of_n_size_cells(struct device_node *np);
extern void prom_build_devicetree(void);
+/* Dummy ref counting routines - to be implemented later */
+static inline struct device_node *of_node_get(struct device_node *node)
+{
+ return node;
+}
+static inline void of_node_put(struct device_node *node)
+{
+}
+
+/*
+ * NB: This is here while we transition from using asm/prom.h
+ * to linux/of.h
+ */
+#include <linux/of.h>
+
+extern struct device_node *of_console_device;
+extern char *of_console_path;
+extern char *of_console_options;
+
#endif /* __KERNEL__ */
#endif /* _SPARC64_PROM_H */
diff --git a/include/asm-sparc64/smp.h b/include/asm-sparc64/smp.h
index 4fb8c4bfb848..e8a96a31761b 100644
--- a/include/asm-sparc64/smp.h
+++ b/include/asm-sparc64/smp.h
@@ -29,9 +29,6 @@
#include <asm/bitops.h>
#include <asm/atomic.h>
-extern cpumask_t phys_cpu_present_map;
-#define cpu_possible_map phys_cpu_present_map
-
extern cpumask_t cpu_sibling_map[NR_CPUS];
extern cpumask_t cpu_core_map[NR_CPUS];
extern int sparc64_multi_core;
@@ -44,7 +41,12 @@ extern int hard_smp_processor_id(void);
#define raw_smp_processor_id() (current_thread_info()->cpu)
extern void smp_fill_in_sib_core_maps(void);
-extern unsigned char boot_cpu_id;
+extern void cpu_play_dead(void);
+
+#ifdef CONFIG_HOTPLUG_CPU
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
+#endif
#endif /* !(__ASSEMBLY__) */
@@ -52,7 +54,6 @@ extern unsigned char boot_cpu_id;
#define hard_smp_processor_id() 0
#define smp_fill_in_sib_core_maps() do { } while (0)
-#define boot_cpu_id (0)
#endif /* !(CONFIG_SMP) */
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 8ba380ec6daa..64891cb10f05 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -115,14 +115,8 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#ifndef __ASSEMBLY__
extern void sun_do_break(void);
-extern int serial_console;
extern int stop_a_enabled;
-static __inline__ int con_is_present(void)
-{
- return serial_console ? 0 : 1;
-}
-
extern void synchronize_user_stack(void);
extern void __flushw_user(void);
@@ -204,16 +198,6 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
} \
} while(0)
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- *
- * TODO: fill this in!
- */
-static inline void sched_cacheflush(void)
-{
-}
-
static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val)
{
unsigned long tmp1, tmp2;
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index 53e96ed9c024..cb751b4d0f56 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -1,4 +1,3 @@
-/* $Id: unistd.h,v 1.50 2002/02/08 03:57:18 davem Exp $ */
#ifndef _SPARC64_UNISTD_H
#define _SPARC64_UNISTD_H
@@ -9,7 +8,7 @@
* think of right now to force the arguments into fixed registers
* before the trap into the system call with gcc 'asm' statements.
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
*
* SunOS compatibility based upon preliminary work which is:
*
@@ -332,8 +331,9 @@
#define __NR_signalfd 311
#define __NR_timerfd 312
#define __NR_eventfd 313
+#define __NR_fallocate 314
-#define NR_SYSCALLS 314
+#define NR_SYSCALLS 315
#ifdef __KERNEL__
/* sysconf options, for SunOS compatibility */
diff --git a/include/asm-sparc64/vio.h b/include/asm-sparc64/vio.h
new file mode 100644
index 000000000000..f7417e91b170
--- /dev/null
+++ b/include/asm-sparc64/vio.h
@@ -0,0 +1,406 @@
+#ifndef _SPARC64_VIO_H
+#define _SPARC64_VIO_H
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+
+#include <asm/ldc.h>
+#include <asm/mdesc.h>
+
+struct vio_msg_tag {
+ u8 type;
+#define VIO_TYPE_CTRL 0x01
+#define VIO_TYPE_DATA 0x02
+#define VIO_TYPE_ERR 0x04
+
+ u8 stype;
+#define VIO_SUBTYPE_INFO 0x01
+#define VIO_SUBTYPE_ACK 0x02
+#define VIO_SUBTYPE_NACK 0x04
+
+ u16 stype_env;
+#define VIO_VER_INFO 0x0001
+#define VIO_ATTR_INFO 0x0002
+#define VIO_DRING_REG 0x0003
+#define VIO_DRING_UNREG 0x0004
+#define VIO_RDX 0x0005
+#define VIO_PKT_DATA 0x0040
+#define VIO_DESC_DATA 0x0041
+#define VIO_DRING_DATA 0x0042
+#define VNET_MCAST_INFO 0x0101
+
+ u32 sid;
+};
+
+struct vio_rdx {
+ struct vio_msg_tag tag;
+ u64 resv[6];
+};
+
+struct vio_ver_info {
+ struct vio_msg_tag tag;
+ u16 major;
+ u16 minor;
+ u8 dev_class;
+#define VDEV_NETWORK 0x01
+#define VDEV_NETWORK_SWITCH 0x02
+#define VDEV_DISK 0x03
+#define VDEV_DISK_SERVER 0x04
+
+ u8 resv1[3];
+ u64 resv2[5];
+};
+
+struct vio_dring_register {
+ struct vio_msg_tag tag;
+ u64 dring_ident;
+ u32 num_descr;
+ u32 descr_size;
+ u16 options;
+#define VIO_TX_DRING 0x0001
+#define VIO_RX_DRING 0x0002
+ u16 resv;
+ u32 num_cookies;
+ struct ldc_trans_cookie cookies[0];
+};
+
+struct vio_dring_unregister {
+ struct vio_msg_tag tag;
+ u64 dring_ident;
+ u64 resv[5];
+};
+
+/* Data transfer modes */
+#define VIO_PKT_MODE 0x01 /* Packet based transfer */
+#define VIO_DESC_MODE 0x02 /* In-band descriptors */
+#define VIO_DRING_MODE 0x03 /* Descriptor rings */
+
+struct vio_dring_data {
+ struct vio_msg_tag tag;
+ u64 seq;
+ u64 dring_ident;
+ u32 start_idx;
+ u32 end_idx;
+ u8 state;
+#define VIO_DRING_ACTIVE 0x01
+#define VIO_DRING_STOPPED 0x02
+
+ u8 __pad1;
+ u16 __pad2;
+ u32 __pad3;
+ u64 __par4[2];
+};
+
+struct vio_dring_hdr {
+ u8 state;
+#define VIO_DESC_FREE 0x01
+#define VIO_DESC_READY 0x02
+#define VIO_DESC_ACCEPTED 0x03
+#define VIO_DESC_DONE 0x04
+ u8 ack;
+#define VIO_ACK_ENABLE 0x01
+#define VIO_ACK_DISABLE 0x00
+
+ u16 __pad1;
+ u32 __pad2;
+};
+
+/* VIO disk specific structures and defines */
+struct vio_disk_attr_info {
+ struct vio_msg_tag tag;
+ u8 xfer_mode;
+ u8 vdisk_type;
+#define VD_DISK_TYPE_SLICE 0x01 /* Slice in block device */
+#define VD_DISK_TYPE_DISK 0x02 /* Entire block device */
+ u16 resv1;
+ u32 vdisk_block_size;
+ u64 operations;
+ u64 vdisk_size;
+ u64 max_xfer_size;
+ u64 resv2[2];
+};
+
+struct vio_disk_desc {
+ struct vio_dring_hdr hdr;
+ u64 req_id;
+ u8 operation;
+#define VD_OP_BREAD 0x01 /* Block read */
+#define VD_OP_BWRITE 0x02 /* Block write */
+#define VD_OP_FLUSH 0x03 /* Flush disk contents */
+#define VD_OP_GET_WCE 0x04 /* Get write-cache status */
+#define VD_OP_SET_WCE 0x05 /* Enable/disable write-cache */
+#define VD_OP_GET_VTOC 0x06 /* Get VTOC */
+#define VD_OP_SET_VTOC 0x07 /* Set VTOC */
+#define VD_OP_GET_DISKGEOM 0x08 /* Get disk geometry */
+#define VD_OP_SET_DISKGEOM 0x09 /* Set disk geometry */
+#define VD_OP_SCSICMD 0x0a /* SCSI control command */
+#define VD_OP_GET_DEVID 0x0b /* Get device ID */
+#define VD_OP_GET_EFI 0x0c /* Get EFI */
+#define VD_OP_SET_EFI 0x0d /* Set EFI */
+ u8 slice;
+ u16 resv1;
+ u32 status;
+ u64 offset;
+ u64 size;
+ u32 ncookies;
+ u32 resv2;
+ struct ldc_trans_cookie cookies[0];
+};
+
+#define VIO_DISK_VNAME_LEN 8
+#define VIO_DISK_ALABEL_LEN 128
+#define VIO_DISK_NUM_PART 8
+
+struct vio_disk_vtoc {
+ u8 volume_name[VIO_DISK_VNAME_LEN];
+ u16 sector_size;
+ u16 num_partitions;
+ u8 ascii_label[VIO_DISK_ALABEL_LEN];
+ struct {
+ u16 id;
+ u16 perm_flags;
+ u32 resv;
+ u64 start_block;
+ u64 num_blocks;
+ } partitions[VIO_DISK_NUM_PART];
+};
+
+struct vio_disk_geom {
+ u16 num_cyl; /* Num data cylinders */
+ u16 alt_cyl; /* Num alternate cylinders */
+ u16 beg_cyl; /* Cyl off of fixed head area */
+ u16 num_hd; /* Num heads */
+ u16 num_sec; /* Num sectors */
+ u16 ifact; /* Interleave factor */
+ u16 apc; /* Alts per cylinder (SCSI) */
+ u16 rpm; /* Revolutions per minute */
+ u16 phy_cyl; /* Num physical cylinders */
+ u16 wr_skip; /* Num sects to skip, writes */
+ u16 rd_skip; /* Num sects to skip, writes */
+};
+
+struct vio_disk_devid {
+ u16 resv;
+ u16 type;
+ u32 len;
+ char id[0];
+};
+
+struct vio_disk_efi {
+ u64 lba;
+ u64 len;
+ char data[0];
+};
+
+/* VIO net specific structures and defines */
+struct vio_net_attr_info {
+ struct vio_msg_tag tag;
+ u8 xfer_mode;
+ u8 addr_type;
+#define VNET_ADDR_ETHERMAC 0x01
+ u16 ack_freq;
+ u32 resv1;
+ u64 addr;
+ u64 mtu;
+ u64 resv2[3];
+};
+
+#define VNET_NUM_MCAST 7
+
+struct vio_net_mcast_info {
+ struct vio_msg_tag tag;
+ u8 set;
+ u8 count;
+ u8 mcast_addr[VNET_NUM_MCAST * 6];
+ u32 resv;
+};
+
+struct vio_net_desc {
+ struct vio_dring_hdr hdr;
+ u32 size;
+ u32 ncookies;
+ struct ldc_trans_cookie cookies[0];
+};
+
+#define VIO_MAX_RING_COOKIES 24
+
+struct vio_dring_state {
+ u64 ident;
+ void *base;
+ u64 snd_nxt;
+ u64 rcv_nxt;
+ u32 entry_size;
+ u32 num_entries;
+ u32 prod;
+ u32 cons;
+ u32 pending;
+ int ncookies;
+ struct ldc_trans_cookie cookies[VIO_MAX_RING_COOKIES];
+};
+
+static inline void *vio_dring_cur(struct vio_dring_state *dr)
+{
+ return dr->base + (dr->entry_size * dr->prod);
+}
+
+static inline void *vio_dring_entry(struct vio_dring_state *dr,
+ unsigned int index)
+{
+ return dr->base + (dr->entry_size * index);
+}
+
+static inline u32 vio_dring_avail(struct vio_dring_state *dr,
+ unsigned int ring_size)
+{
+ /* Ensure build-time power-of-2. */
+ BUILD_BUG_ON(ring_size & (ring_size - 1));
+
+ return (dr->pending -
+ ((dr->prod - dr->cons) & (ring_size - 1)));
+}
+
+#define VIO_MAX_TYPE_LEN 32
+#define VIO_MAX_COMPAT_LEN 64
+
+struct vio_dev {
+ u64 mp;
+ struct device_node *dp;
+
+ char type[VIO_MAX_TYPE_LEN];
+ char compat[VIO_MAX_COMPAT_LEN];
+ int compat_len;
+
+ u64 dev_no;
+
+ unsigned long channel_id;
+
+ unsigned int tx_irq;
+ unsigned int rx_irq;
+
+ struct device dev;
+};
+
+struct vio_driver {
+ struct list_head node;
+ const struct vio_device_id *id_table;
+ int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
+ int (*remove)(struct vio_dev *dev);
+ void (*shutdown)(struct vio_dev *dev);
+ unsigned long driver_data;
+ struct device_driver driver;
+};
+
+struct vio_version {
+ u16 major;
+ u16 minor;
+};
+
+struct vio_driver_state;
+struct vio_driver_ops {
+ int (*send_attr)(struct vio_driver_state *vio);
+ int (*handle_attr)(struct vio_driver_state *vio, void *pkt);
+ void (*handshake_complete)(struct vio_driver_state *vio);
+};
+
+struct vio_completion {
+ struct completion com;
+ int err;
+ int waiting_for;
+};
+
+struct vio_driver_state {
+ /* Protects VIO handshake and, optionally, driver private state. */
+ spinlock_t lock;
+
+ struct ldc_channel *lp;
+
+ u32 _peer_sid;
+ u32 _local_sid;
+ struct vio_dring_state drings[2];
+#define VIO_DRIVER_TX_RING 0
+#define VIO_DRIVER_RX_RING 1
+
+ u8 hs_state;
+#define VIO_HS_INVALID 0x00
+#define VIO_HS_GOTVERS 0x01
+#define VIO_HS_GOT_ATTR 0x04
+#define VIO_HS_SENT_DREG 0x08
+#define VIO_HS_SENT_RDX 0x10
+#define VIO_HS_GOT_RDX_ACK 0x20
+#define VIO_HS_GOT_RDX 0x40
+#define VIO_HS_SENT_RDX_ACK 0x80
+#define VIO_HS_COMPLETE (VIO_HS_GOT_RDX_ACK | VIO_HS_SENT_RDX_ACK)
+
+ u8 dev_class;
+
+ u8 dr_state;
+#define VIO_DR_STATE_TXREG 0x01
+#define VIO_DR_STATE_RXREG 0x02
+#define VIO_DR_STATE_TXREQ 0x10
+#define VIO_DR_STATE_RXREQ 0x20
+
+ u8 debug;
+#define VIO_DEBUG_HS 0x01
+#define VIO_DEBUG_DATA 0x02
+
+ void *desc_buf;
+ unsigned int desc_buf_len;
+
+ struct vio_completion *cmp;
+
+ struct vio_dev *vdev;
+
+ struct timer_list timer;
+
+ struct vio_version ver;
+
+ struct vio_version *ver_table;
+ int ver_table_entries;
+
+ char *name;
+
+ struct vio_driver_ops *ops;
+};
+
+#define viodbg(TYPE, f, a...) \
+do { if (vio->debug & VIO_DEBUG_##TYPE) \
+ printk(KERN_INFO "vio: ID[%lu] " f, \
+ vio->vdev->channel_id, ## a); \
+} while (0)
+
+extern int vio_register_driver(struct vio_driver *drv);
+extern void vio_unregister_driver(struct vio_driver *drv);
+
+static inline struct vio_driver *to_vio_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct vio_driver, driver);
+}
+
+static inline struct vio_dev *to_vio_dev(struct device *dev)
+{
+ return container_of(dev, struct vio_dev, dev);
+}
+
+extern int vio_ldc_send(struct vio_driver_state *vio, void *data, int len);
+extern void vio_link_state_change(struct vio_driver_state *vio, int event);
+extern void vio_conn_reset(struct vio_driver_state *vio);
+extern int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt);
+extern int vio_validate_sid(struct vio_driver_state *vio,
+ struct vio_msg_tag *tp);
+extern u32 vio_send_sid(struct vio_driver_state *vio);
+extern int vio_ldc_alloc(struct vio_driver_state *vio,
+ struct ldc_channel_config *base_cfg, void *event_arg);
+extern void vio_ldc_free(struct vio_driver_state *vio);
+extern int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
+ u8 dev_class, struct vio_version *ver_table,
+ int ver_table_size, struct vio_driver_ops *ops,
+ char *name);
+
+extern void vio_port_up(struct vio_driver_state *vio);
+
+#endif /* _SPARC64_VIO_H */
diff --git a/include/asm-um/a.out.h b/include/asm-um/a.out.h
index 7016b893ac9d..78bc9eed26b2 100644
--- a/include/asm-um/a.out.h
+++ b/include/asm-um/a.out.h
@@ -17,4 +17,6 @@ extern int honeypot;
#define STACK_TOP \
CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size)
+#define STACK_TOP_MAX STACK_TOP
+
#endif
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index 1b1090a91a58..830fc6e5d49d 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -175,12 +175,6 @@ static inline int pte_none(pte_t pte)
* The following only work if pte_present() is true.
* Undefined behaviour if not..
*/
-static inline int pte_user(pte_t pte)
-{
- return((pte_get_bits(pte, _PAGE_USER)) &&
- !(pte_get_bits(pte, _PAGE_PROTNONE)));
-}
-
static inline int pte_read(pte_t pte)
{
return((pte_get_bits(pte, _PAGE_USER)) &&
@@ -238,18 +232,6 @@ static inline pte_t pte_mknewprot(pte_t pte)
return(pte);
}
-static inline pte_t pte_rdprotect(pte_t pte)
-{
- pte_clear_bits(pte, _PAGE_USER);
- return(pte_mknewprot(pte));
-}
-
-static inline pte_t pte_exprotect(pte_t pte)
-{
- pte_clear_bits(pte, _PAGE_USER);
- return(pte_mknewprot(pte));
-}
-
static inline pte_t pte_mkclean(pte_t pte)
{
pte_clear_bits(pte, _PAGE_DIRTY);
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 18a13ba74605..6e5fd5c892d0 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -52,10 +52,21 @@ static inline struct thread_info *current_thread_info(void)
return ti;
}
+#ifdef CONFIG_DEBUG_STACK_USAGE
+
+#define alloc_thread_info(tsk) \
+ ((struct thread_info *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, \
+ CONFIG_KERNEL_STACK_ORDER))
+#else
+
/* thread information allocation */
#define alloc_thread_info(tsk) \
- ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL))
-#define free_thread_info(ti) kfree(ti)
+ ((struct thread_info *) __get_free_pages(GFP_KERNEL, \
+ CONFIG_KERNEL_STACK_ORDER))
+#endif
+
+#define free_thread_info(ti) \
+ free_pages((unsigned long)(ti),CONFIG_KERNEL_STACK_ORDER)
#endif
diff --git a/include/asm-v850/fb.h b/include/asm-v850/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-v850/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-v850/ioctls.h b/include/asm-v850/ioctls.h
index 05c0dc9ce1ea..5313abd5f388 100644
--- a/include/asm-v850/ioctls.h
+++ b/include/asm-v850/ioctls.h
@@ -46,6 +46,10 @@
#define TIOCSBRK 0x5427 /* BSD compatibility */
#define TIOCCBRK 0x5428 /* BSD compatibility */
#define TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
diff --git a/include/asm-v850/irq.h b/include/asm-v850/irq.h
index 88687c181f01..7d0d4cd1ce54 100644
--- a/include/asm-v850/irq.h
+++ b/include/asm-v850/irq.h
@@ -50,16 +50,6 @@ init_irq_handlers (int base_irq, int num, int interval,
interrupt. */
extern unsigned int handle_irq (int irq, struct pt_regs *regs);
-
-/* Enable interrupt handling on an irq. */
-extern void enable_irq(unsigned int irq);
-
-/* Disable an irq and wait for completion. */
-extern void disable_irq (unsigned int irq);
-
-/* Disable an irq without waiting. */
-extern void disable_irq_nosync (unsigned int irq);
-
#endif /* !__ASSEMBLY__ */
#endif /* __V850_IRQ_H__ */
diff --git a/include/asm-v850/pci.h b/include/asm-v850/pci.h
index 4581826e1cac..de2a7d0a81cc 100644
--- a/include/asm-v850/pci.h
+++ b/include/asm-v850/pci.h
@@ -116,8 +116,4 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
extern void pci_iounmap (struct pci_dev *dev, void __iomem *addr);
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* __V850_PCI_H__ */
diff --git a/include/asm-v850/rte_cb.h b/include/asm-v850/rte_cb.h
index 9f7f02cb0391..e85d261b79bf 100644
--- a/include/asm-v850/rte_cb.h
+++ b/include/asm-v850/rte_cb.h
@@ -64,7 +64,6 @@
/* As we don't really support PCI DMA to cpu memory, and use bounce-buffers
instead, perversely enough, this becomes always true! */
# define pci_dma_supported(dev, mask) 1
-# define pci_dac_dma_supported(dev, mask) 0
# define pcibios_assign_all_busses() 1
#endif /* CONFIG_RTE_MB_A_PCI */
diff --git a/include/asm-v850/termbits.h b/include/asm-v850/termbits.h
index 35412f7f3eea..295d7bf69451 100644
--- a/include/asm-v850/termbits.h
+++ b/include/asm-v850/termbits.h
@@ -141,6 +141,7 @@ struct ktermios {
#define HUPCL 0002000
#define CLOCAL 0004000
#define CBAUDEX 0010000
+#define BOTHER 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
@@ -156,10 +157,12 @@ struct ktermios {
#define B3000000 0010015
#define B3500000 0010016
#define B4000000 0010017
-#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CIBAUD 002003600000 /* input baud rate */
#define CMSPAR 010000000000 /* mark or space (stick) parity */
#define CRTSCTS 020000000000 /* flow control */
+#define IBSHIFT 16 /* Shifr from CBAUD to CIBAUD */
+
/* c_lflag bits */
#define ISIG 0000001
#define ICANON 0000002
diff --git a/include/asm-v850/termios.h b/include/asm-v850/termios.h
index c2c2b1d58776..fcd171838d9c 100644
--- a/include/asm-v850/termios.h
+++ b/include/asm-v850/termios.h
@@ -80,8 +80,10 @@ struct termio {
copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
})
-#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
-#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2))
+#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios))
#endif /* __KERNEL__ */
diff --git a/include/asm-x86_64/a.out.h b/include/asm-x86_64/a.out.h
index 7255cde06538..e789300e41a5 100644
--- a/include/asm-x86_64/a.out.h
+++ b/include/asm-x86_64/a.out.h
@@ -21,7 +21,8 @@ struct exec
#ifdef __KERNEL__
#include <linux/thread_info.h>
-#define STACK_TOP TASK_SIZE
+#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX TASK_SIZE64
#endif
#endif /* __A_OUT_GNU_H__ */
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index a29f05087a31..1da8f49c0fe2 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -29,6 +29,7 @@
#ifdef __KERNEL__
#include <acpi/pdc_intel.h>
+#include <asm/numa.h>
#define COMPILER_DEPENDENT_INT64 long long
#define COMPILER_DEPENDENT_UINT64 unsigned long long
@@ -141,6 +142,16 @@ extern int acpi_pci_disabled;
extern int acpi_skip_timer_override;
extern int acpi_use_timer_override;
+#ifdef CONFIG_ACPI_NUMA
+extern void __init acpi_fake_nodes(const struct bootnode *fake_nodes,
+ int num_nodes);
+#else
+static inline void acpi_fake_nodes(const struct bootnode *fake_nodes,
+ int num_nodes)
+{
+}
+#endif
+
#endif /*__KERNEL__*/
#endif /*_ASM_ACPI_H*/
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h
index a09427640764..ab161e810151 100644
--- a/include/asm-x86_64/alternative.h
+++ b/include/asm-x86_64/alternative.h
@@ -5,6 +5,41 @@
#include <linux/types.h>
#include <linux/stddef.h>
+
+/*
+ * Alternative inline assembly for SMP.
+ *
+ * The LOCK_PREFIX macro defined here replaces the LOCK and
+ * LOCK_PREFIX macros used everywhere in the source tree.
+ *
+ * SMP alternatives use the same data structures as the other
+ * alternatives and the X86_FEATURE_UP flag to indicate the case of a
+ * UP system running a SMP kernel. The existing apply_alternatives()
+ * works fine for patching a SMP kernel for UP.
+ *
+ * The SMP alternative tables can be kept after boot and contain both
+ * UP and SMP versions of the instructions to allow switching back to
+ * SMP at runtime, when hotplugging in a new CPU, which is especially
+ * useful in virtualized environments.
+ *
+ * The very common lock prefix is handled as special case in a
+ * separate table which is a pure address list without replacement ptr
+ * and size information. That keeps the table sizes small.
+ */
+
+#ifdef CONFIG_SMP
+#define LOCK_PREFIX \
+ ".section .smp_locks,\"a\"\n" \
+ " .align 8\n" \
+ " .quad 661f\n" /* address */ \
+ ".previous\n" \
+ "661:\n\tlock; "
+
+#else /* ! CONFIG_SMP */
+#define LOCK_PREFIX ""
+#endif
+
+/* This must be included *after* the definition of LOCK_PREFIX */
#include <asm/cpufeature.h>
struct alt_instr {
@@ -108,39 +143,6 @@ static inline void alternatives_smp_switch(int smp) {}
*/
#define ASM_OUTPUT2(a, b) a, b
-/*
- * Alternative inline assembly for SMP.
- *
- * The LOCK_PREFIX macro defined here replaces the LOCK and
- * LOCK_PREFIX macros used everywhere in the source tree.
- *
- * SMP alternatives use the same data structures as the other
- * alternatives and the X86_FEATURE_UP flag to indicate the case of a
- * UP system running a SMP kernel. The existing apply_alternatives()
- * works fine for patching a SMP kernel for UP.
- *
- * The SMP alternative tables can be kept after boot and contain both
- * UP and SMP versions of the instructions to allow switching back to
- * SMP at runtime, when hotplugging in a new CPU, which is especially
- * useful in virtualized environments.
- *
- * The very common lock prefix is handled as special case in a
- * separate table which is a pure address list without replacement ptr
- * and size information. That keeps the table sizes small.
- */
-
-#ifdef CONFIG_SMP
-#define LOCK_PREFIX \
- ".section .smp_locks,\"a\"\n" \
- " .align 8\n" \
- " .quad 661f\n" /* address */ \
- ".previous\n" \
- "661:\n\tlock; "
-
-#else /* ! CONFIG_SMP */
-#define LOCK_PREFIX ""
-#endif
-
struct paravirt_patch;
#ifdef CONFIG_PARAVIRT
void apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end);
@@ -152,4 +154,6 @@ apply_paravirt(struct paravirt_patch *start, struct paravirt_patch *end)
#define __parainstructions_end NULL
#endif
+extern void text_poke(void *addr, unsigned char *opcode, int len);
+
#endif /* _X86_64_ALTERNATIVE_H */
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index 45e9fca1febc..85125ef3c414 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -83,8 +83,10 @@ extern void disable_APIC_timer(void);
extern void enable_APIC_timer(void);
extern void setup_apic_routing(void);
-extern void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
- unsigned char msg_type, unsigned char mask);
+extern void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+ unsigned char msg_type, unsigned char mask);
+
+extern int apic_is_clustered_box(void);
#define K8_APIC_EXT_LVT_BASE 0x500
#define K8_APIC_EXT_INT_MSG_FIX 0x0
diff --git a/include/asm-x86_64/auxvec.h b/include/asm-x86_64/auxvec.h
index 2403c4cfced2..1d5ab0d03950 100644
--- a/include/asm-x86_64/auxvec.h
+++ b/include/asm-x86_64/auxvec.h
@@ -1,4 +1,6 @@
#ifndef __ASM_X86_64_AUXVEC_H
#define __ASM_X86_64_AUXVEC_H
+#define AT_SYSINFO_EHDR 33
+
#endif
diff --git a/include/asm-x86_64/boot.h b/include/asm-x86_64/boot.h
index 96b228e6e79c..3c46cea8db7f 100644
--- a/include/asm-x86_64/boot.h
+++ b/include/asm-x86_64/boot.h
@@ -1,15 +1 @@
-#ifndef _LINUX_BOOT_H
-#define _LINUX_BOOT_H
-
-/* Don't touch these, unless you really know what you're doing. */
-#define DEF_INITSEG 0x9000
-#define DEF_SYSSEG 0x1000
-#define DEF_SETUPSEG 0x9020
-#define DEF_SYSSIZE 0x7F00
-
-/* Internal svga startup constants */
-#define NORMAL_VGA 0xffff /* 80x25 mode */
-#define EXTENDED_VGA 0xfffe /* 80x50 mode */
-#define ASK_VGA 0xfffd /* ask for it at bootup */
-
-#endif
+#include <asm-i386/boot.h>
diff --git a/include/asm-x86_64/bootparam.h b/include/asm-x86_64/bootparam.h
new file mode 100644
index 000000000000..aa82e5238d82
--- /dev/null
+++ b/include/asm-x86_64/bootparam.h
@@ -0,0 +1 @@
+#include <asm-i386/bootparam.h>
diff --git a/include/asm-x86_64/calgary.h b/include/asm-x86_64/calgary.h
index 4d5747a0923c..67f60406e2d8 100644
--- a/include/asm-x86_64/calgary.h
+++ b/include/asm-x86_64/calgary.h
@@ -1,7 +1,7 @@
/*
* Derived from include/asm-powerpc/iommu.h
*
- * Copyright (C) IBM Corporation, 2006
+ * Copyright IBM Corporation, 2006-2007
*
* Author: Jon Mason <jdmason@us.ibm.com>
* Author: Muli Ben-Yehuda <muli@il.ibm.com>
@@ -31,6 +31,7 @@
#include <asm/types.h>
struct iommu_table {
+ struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
unsigned long it_base; /* mapped address of tce table */
unsigned long it_hint; /* Hint for next alloc */
unsigned long *it_map; /* A simple allocation bitmap for now */
@@ -42,6 +43,12 @@ struct iommu_table {
unsigned char it_busno; /* Bus number this table belongs to */
};
+struct cal_chipset_ops {
+ void (*handle_quirks)(struct iommu_table *tbl, struct pci_dev *dev);
+ void (*tce_cache_blast)(struct iommu_table *tbl);
+ void (*dump_error_regs)(struct iommu_table *tbl);
+};
+
#define TCE_TABLE_SIZE_UNSPECIFIED ~0
#define TCE_TABLE_SIZE_64K 0
#define TCE_TABLE_SIZE_128K 1
diff --git a/include/asm-x86_64/cmpxchg.h b/include/asm-x86_64/cmpxchg.h
index 09a6b6b6b74d..5e182062e6ec 100644
--- a/include/asm-x86_64/cmpxchg.h
+++ b/include/asm-x86_64/cmpxchg.h
@@ -128,7 +128,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
(unsigned long)(n),sizeof(*(ptr))))
#define cmpxchg_local(ptr,o,n)\
- ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
+ ((__typeof__(*(ptr)))__cmpxchg_local((ptr),(unsigned long)(o),\
(unsigned long)(n),sizeof(*(ptr))))
#endif
diff --git a/include/asm-x86_64/compat.h b/include/asm-x86_64/compat.h
index b37ab8218ef0..53cb96b68a62 100644
--- a/include/asm-x86_64/compat.h
+++ b/include/asm-x86_64/compat.h
@@ -33,8 +33,10 @@ typedef s32 compat_key_t;
typedef s32 compat_int_t;
typedef s32 compat_long_t;
+typedef s64 __attribute__((aligned(4))) compat_s64;
typedef u32 compat_uint_t;
typedef u32 compat_ulong_t;
+typedef u64 __attribute__((aligned(4))) compat_u64;
struct compat_timespec {
compat_time_t tv_sec;
diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
index 0b3c686139f1..8baefc3beb2e 100644
--- a/include/asm-x86_64/cpufeature.h
+++ b/include/asm-x86_64/cpufeature.h
@@ -7,115 +7,24 @@
#ifndef __ASM_X8664_CPUFEATURE_H
#define __ASM_X8664_CPUFEATURE_H
-#define NCAPINTS 7 /* N 32-bit words worth of info */
+#include <asm-i386/cpufeature.h>
-/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
-#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
-#define X86_FEATURE_VME (0*32+ 1) /* Virtual Mode Extensions */
-#define X86_FEATURE_DE (0*32+ 2) /* Debugging Extensions */
-#define X86_FEATURE_PSE (0*32+ 3) /* Page Size Extensions */
-#define X86_FEATURE_TSC (0*32+ 4) /* Time Stamp Counter */
-#define X86_FEATURE_MSR (0*32+ 5) /* Model-Specific Registers, RDMSR, WRMSR */
-#define X86_FEATURE_PAE (0*32+ 6) /* Physical Address Extensions */
-#define X86_FEATURE_MCE (0*32+ 7) /* Machine Check Architecture */
-#define X86_FEATURE_CX8 (0*32+ 8) /* CMPXCHG8 instruction */
-#define X86_FEATURE_APIC (0*32+ 9) /* Onboard APIC */
-#define X86_FEATURE_SEP (0*32+11) /* SYSENTER/SYSEXIT */
-#define X86_FEATURE_MTRR (0*32+12) /* Memory Type Range Registers */
-#define X86_FEATURE_PGE (0*32+13) /* Page Global Enable */
-#define X86_FEATURE_MCA (0*32+14) /* Machine Check Architecture */
-#define X86_FEATURE_CMOV (0*32+15) /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
-#define X86_FEATURE_PAT (0*32+16) /* Page Attribute Table */
-#define X86_FEATURE_PSE36 (0*32+17) /* 36-bit PSEs */
-#define X86_FEATURE_PN (0*32+18) /* Processor serial number */
-#define X86_FEATURE_CLFLSH (0*32+19) /* Supports the CLFLUSH instruction */
-#define X86_FEATURE_DS (0*32+21) /* Debug Store */
-#define X86_FEATURE_ACPI (0*32+22) /* ACPI via MSR */
-#define X86_FEATURE_MMX (0*32+23) /* Multimedia Extensions */
-#define X86_FEATURE_FXSR (0*32+24) /* FXSAVE and FXRSTOR instructions (fast save and restore */
- /* of FPU context), and CR4.OSFXSR available */
-#define X86_FEATURE_XMM (0*32+25) /* Streaming SIMD Extensions */
-#define X86_FEATURE_XMM2 (0*32+26) /* Streaming SIMD Extensions-2 */
-#define X86_FEATURE_SELFSNOOP (0*32+27) /* CPU self snoop */
-#define X86_FEATURE_HT (0*32+28) /* Hyper-Threading */
-#define X86_FEATURE_ACC (0*32+29) /* Automatic clock control */
-#define X86_FEATURE_IA64 (0*32+30) /* IA-64 processor */
-
-/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
-/* Don't duplicate feature flags which are redundant with Intel! */
-#define X86_FEATURE_SYSCALL (1*32+11) /* SYSCALL/SYSRET */
-#define X86_FEATURE_MMXEXT (1*32+22) /* AMD MMX extensions */
-#define X86_FEATURE_FXSR_OPT (1*32+25) /* FXSR optimizations */
-#define X86_FEATURE_RDTSCP (1*32+27) /* RDTSCP */
-#define X86_FEATURE_LM (1*32+29) /* Long Mode (x86-64) */
-#define X86_FEATURE_3DNOWEXT (1*32+30) /* AMD 3DNow! extensions */
-#define X86_FEATURE_3DNOW (1*32+31) /* 3DNow! */
-
-/* Transmeta-defined CPU features, CPUID level 0x80860001, word 2 */
-#define X86_FEATURE_RECOVERY (2*32+ 0) /* CPU in recovery mode */
-#define X86_FEATURE_LONGRUN (2*32+ 1) /* Longrun power control */
-#define X86_FEATURE_LRTI (2*32+ 3) /* LongRun table interface */
-
-/* Other features, Linux-defined mapping, word 3 */
-/* This range is used for feature bits which conflict or are synthesized */
-#define X86_FEATURE_CXMMX (3*32+ 0) /* Cyrix MMX extensions */
-#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */
-#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
-#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */
-#define X86_FEATURE_REP_GOOD (3*32+ 4) /* rep microcode works well on this CPU */
-#define X86_FEATURE_CONSTANT_TSC (3*32+5) /* TSC runs at constant rate */
-#define X86_FEATURE_SYNC_RDTSC (3*32+6) /* RDTSC syncs CPU core */
-#define X86_FEATURE_FXSAVE_LEAK (3*32+7) /* FIP/FOP/FDP leaks through FXSAVE */
-#define X86_FEATURE_UP (3*32+8) /* SMP kernel running on UP */
-#define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */
-#define X86_FEATURE_PEBS (3*32+10) /* Precise-Event Based Sampling */
-#define X86_FEATURE_BTS (3*32+11) /* Branch Trace Store */
-
-/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
-#define X86_FEATURE_XMM3 (4*32+ 0) /* Streaming SIMD Extensions-3 */
-#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */
-#define X86_FEATURE_DSCPL (4*32+ 4) /* CPL Qualified Debug Store */
-#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
-#define X86_FEATURE_TM2 (4*32+ 8) /* Thermal Monitor 2 */
-#define X86_FEATURE_CID (4*32+10) /* Context ID */
-#define X86_FEATURE_CX16 (4*32+13) /* CMPXCHG16B */
-#define X86_FEATURE_XTPR (4*32+14) /* Send Task Priority Messages */
-
-/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
-#define X86_FEATURE_XSTORE (5*32+ 2) /* on-CPU RNG present (xstore insn) */
-#define X86_FEATURE_XSTORE_EN (5*32+ 3) /* on-CPU RNG enabled */
-#define X86_FEATURE_XCRYPT (5*32+ 6) /* on-CPU crypto (xcrypt insn) */
-#define X86_FEATURE_XCRYPT_EN (5*32+ 7) /* on-CPU crypto enabled */
-
-/* More extended AMD flags: CPUID level 0x80000001, ecx, word 6 */
-#define X86_FEATURE_LAHF_LM (6*32+ 0) /* LAHF/SAHF in long mode */
-#define X86_FEATURE_CMP_LEGACY (6*32+ 1) /* If yes HyperThreading not valid */
-
-#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
-#define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability)
-
-#define cpu_has_fpu 1
+#undef cpu_has_vme
#define cpu_has_vme 0
-#define cpu_has_de 1
-#define cpu_has_pse 1
-#define cpu_has_tsc 1
+
+#undef cpu_has_pae
#define cpu_has_pae ___BUG___
-#define cpu_has_pge 1
-#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC)
-#define cpu_has_mtrr 1
-#define cpu_has_mmx 1
-#define cpu_has_fxsr 1
-#define cpu_has_xmm 1
-#define cpu_has_xmm2 1
-#define cpu_has_xmm3 boot_cpu_has(X86_FEATURE_XMM3)
-#define cpu_has_ht boot_cpu_has(X86_FEATURE_HT)
+
+#undef cpu_has_mp
#define cpu_has_mp 1 /* XXX */
+
+#undef cpu_has_k6_mtrr
#define cpu_has_k6_mtrr 0
+
+#undef cpu_has_cyrix_arr
#define cpu_has_cyrix_arr 0
+
+#undef cpu_has_centaur_mcr
#define cpu_has_centaur_mcr 0
-#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLSH)
-#define cpu_has_ds boot_cpu_has(X86_FEATURE_DS)
-#define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS)
-#define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS)
#endif /* __ASM_X8664_CPUFEATURE_H */
diff --git a/include/asm-x86_64/dmi.h b/include/asm-x86_64/dmi.h
index 93b2b15d4325..d02e32e3c3f0 100644
--- a/include/asm-x86_64/dmi.h
+++ b/include/asm-x86_64/dmi.h
@@ -3,15 +3,12 @@
#include <asm/io.h>
-extern void *dmi_ioremap(unsigned long addr, unsigned long size);
-extern void dmi_iounmap(void *addr, unsigned long size);
-
#define DMI_MAX_DATA 2048
extern int dmi_alloc_index;
extern char dmi_alloc_data[DMI_MAX_DATA];
-/* This is so early that there is no good way to allocate dynamic memory.
+/* This is so early that there is no good way to allocate dynamic memory.
Allocate data in an BSS array. */
static inline void *dmi_alloc(unsigned len)
{
diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
index 6216fa3f2802..3486e701bd86 100644
--- a/include/asm-x86_64/e820.h
+++ b/include/asm-x86_64/e820.h
@@ -11,8 +11,6 @@
#ifndef __E820_HEADER
#define __E820_HEADER
-#include <linux/mmzone.h>
-
#define E820MAP 0x2d0 /* our map */
#define E820MAX 128 /* number of entries in E820MAP */
#define E820NR 0x1e8 /* # entries in E820MAP */
@@ -30,7 +28,7 @@ struct e820entry {
} __attribute__((packed));
struct e820map {
- int nr_map;
+ u32 nr_map;
struct e820entry map[E820MAX];
};
diff --git a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h
index 6d24ea7c4d9d..b4fbe47f6ccd 100644
--- a/include/asm-x86_64/elf.h
+++ b/include/asm-x86_64/elf.h
@@ -162,6 +162,19 @@ extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
/* 1GB for 64bit, 8MB for 32bit */
#define STACK_RND_MASK (test_thread_flag(TIF_IA32) ? 0x7ff : 0x3fffff)
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack);
+
+extern int vdso_enabled;
+
+#define ARCH_DLINFO \
+do if (vdso_enabled) { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR,(unsigned long)current->mm->context.vdso);\
+} while (0)
+
#endif
#endif
diff --git a/include/asm-x86_64/fb.h b/include/asm-x86_64/fb.h
new file mode 100644
index 000000000000..60548e651d12
--- /dev/null
+++ b/include/asm-x86_64/fb.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+#include <linux/fs.h>
+#include <asm/page.h>
+
+static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
+ unsigned long off)
+{
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+}
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-x86_64/fixmap.h b/include/asm-x86_64/fixmap.h
index e90e1677531b..cdfbe4a6ae6f 100644
--- a/include/asm-x86_64/fixmap.h
+++ b/include/asm-x86_64/fixmap.h
@@ -22,9 +22,9 @@
* compile time, but to set the physical address only
* in the boot process.
*
- * 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
+ * These 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages (or larger if used with an increment
+ * higher than 1). Use set_fixmap(idx,phys) to associate
* physical memory with fixmap indices.
*
* TLB entries of such buffers will not be flushed across
@@ -35,6 +35,8 @@ enum fixed_addresses {
VSYSCALL_LAST_PAGE,
VSYSCALL_FIRST_PAGE = VSYSCALL_LAST_PAGE + ((VSYSCALL_END-VSYSCALL_START) >> PAGE_SHIFT) - 1,
VSYSCALL_HPET,
+ FIX_DBGP_BASE,
+ FIX_EARLYCON_MEM_BASE,
FIX_HPET_BASE,
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
FIX_IO_APIC_BASE_0,
@@ -84,7 +86,7 @@ static __always_inline unsigned long fix_to_virt(const unsigned int idx)
if (idx >= __end_of_fixed_addresses)
__this_fixmap_does_not_exist();
- return __fix_to_virt(idx);
+ return __fix_to_virt(idx);
}
#endif
diff --git a/include/asm-x86_64/hpet.h b/include/asm-x86_64/hpet.h
index 59a66f084611..79bb950f82c5 100644
--- a/include/asm-x86_64/hpet.h
+++ b/include/asm-x86_64/hpet.h
@@ -1,78 +1,18 @@
#ifndef _ASM_X8664_HPET_H
#define _ASM_X8664_HPET_H 1
-/*
- * Documentation on HPET can be found at:
- * http://www.intel.com/ial/home/sp/pcmmspec.htm
- * ftp://download.intel.com/ial/home/sp/mmts098.pdf
- */
-
-#define HPET_MMAP_SIZE 1024
-
-#define HPET_ID 0x000
-#define HPET_PERIOD 0x004
-#define HPET_CFG 0x010
-#define HPET_STATUS 0x020
-#define HPET_COUNTER 0x0f0
-#define HPET_Tn_OFFSET 0x20
-#define HPET_Tn_CFG(n) (0x100 + (n) * HPET_Tn_OFFSET)
-#define HPET_Tn_ROUTE(n) (0x104 + (n) * HPET_Tn_OFFSET)
-#define HPET_Tn_CMP(n) (0x108 + (n) * HPET_Tn_OFFSET)
-#define HPET_T0_CFG HPET_Tn_CFG(0)
-#define HPET_T0_CMP HPET_Tn_CMP(0)
-#define HPET_T1_CFG HPET_Tn_CFG(1)
-#define HPET_T1_CMP HPET_Tn_CMP(1)
-
-#define HPET_ID_VENDOR 0xffff0000
-#define HPET_ID_LEGSUP 0x00008000
-#define HPET_ID_64BIT 0x00002000
-#define HPET_ID_NUMBER 0x00001f00
-#define HPET_ID_REV 0x000000ff
-#define HPET_ID_NUMBER_SHIFT 8
-
-#define HPET_ID_VENDOR_SHIFT 16
-#define HPET_ID_VENDOR_8086 0x8086
-
-#define HPET_CFG_ENABLE 0x001
-#define HPET_CFG_LEGACY 0x002
-#define HPET_LEGACY_8254 2
-#define HPET_LEGACY_RTC 8
-
-#define HPET_TN_LEVEL 0x0002
-#define HPET_TN_ENABLE 0x0004
-#define HPET_TN_PERIODIC 0x0008
-#define HPET_TN_PERIODIC_CAP 0x0010
-#define HPET_TN_64BIT_CAP 0x0020
-#define HPET_TN_SETVAL 0x0040
-#define HPET_TN_32BIT 0x0100
-#define HPET_TN_ROUTE 0x3e00
-#define HPET_TN_FSB 0x4000
-#define HPET_TN_FSB_CAP 0x8000
-
-#define HPET_TN_ROUTE_SHIFT 9
+#include <asm-i386/hpet.h>
#define HPET_TICK_RATE (HZ * 100000UL)
-extern int is_hpet_enabled(void);
extern int hpet_rtc_timer_init(void);
-extern int apic_is_clustered_box(void);
extern int hpet_arch_init(void);
extern int hpet_timer_stop_set_go(unsigned long tick);
extern int hpet_reenable(void);
extern unsigned int hpet_calibrate_tsc(void);
extern int hpet_use_timer;
-extern unsigned long hpet_address;
extern unsigned long hpet_period;
extern unsigned long hpet_tick;
-#ifdef CONFIG_HPET_EMULATE_RTC
-extern int hpet_mask_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_rtc_irq_bit(unsigned long bit_mask);
-extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec);
-extern int hpet_set_periodic_freq(unsigned long freq);
-extern int hpet_rtc_dropped_irq(void);
-extern int hpet_rtc_timer_init(void);
-#endif /* CONFIG_HPET_EMULATE_RTC */
-
#endif
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index 6153ae5df2e8..09dfc18a6dd0 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -95,6 +95,26 @@
#ifndef __ASSEMBLY__
+
+/* Interrupt handlers registered during init_IRQ */
+void apic_timer_interrupt(void);
+void spurious_interrupt(void);
+void error_interrupt(void);
+void reschedule_interrupt(void);
+void call_function_interrupt(void);
+void irq_move_cleanup_interrupt(void);
+void invalidate_interrupt0(void);
+void invalidate_interrupt1(void);
+void invalidate_interrupt2(void);
+void invalidate_interrupt3(void);
+void invalidate_interrupt4(void);
+void invalidate_interrupt5(void);
+void invalidate_interrupt6(void);
+void invalidate_interrupt7(void);
+void thermal_interrupt(void);
+void threshold_interrupt(void);
+void i8254_timer_resume(void);
+
typedef int vector_irq_t[NR_VECTORS];
DECLARE_PER_CPU(vector_irq_t, vector_irq);
extern void __setup_vector_irq(int cpu);
diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h
index c16c6ff4bdd7..5cbf9fa5e0b5 100644
--- a/include/asm-x86_64/hypertransport.h
+++ b/include/asm-x86_64/hypertransport.h
@@ -1,42 +1 @@
-#ifndef ASM_HYPERTRANSPORT_H
-#define ASM_HYPERTRANSPORT_H
-
-/*
- * Constants for x86 Hypertransport Interrupts.
- */
-
-#define HT_IRQ_LOW_BASE 0xf8000000
-
-#define HT_IRQ_LOW_VECTOR_SHIFT 16
-#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000
-#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
-
-#define HT_IRQ_LOW_DEST_ID_SHIFT 8
-#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00
-#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
-
-#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000
-#define HT_IRQ_LOW_DM_LOGICAL 0x0000040
-
-#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000
-#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020
-
-
-#define HT_IRQ_LOW_MT_FIXED 0x0000000
-#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004
-#define HT_IRQ_LOW_MT_SMI 0x0000008
-#define HT_IRQ_LOW_MT_NMI 0x000000c
-#define HT_IRQ_LOW_MT_INIT 0x0000010
-#define HT_IRQ_LOW_MT_STARTUP 0x0000014
-#define HT_IRQ_LOW_MT_EXTINT 0x0000018
-#define HT_IRQ_LOW_MT_LINT1 0x000008c
-#define HT_IRQ_LOW_MT_LINT0 0x0000098
-
-#define HT_IRQ_LOW_IRQ_MASKED 0x0000001
-
-
-#define HT_IRQ_HIGH_DEST_ID_SHIFT 0
-#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff
-#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
-
-#endif /* ASM_HYPERTRANSPORT_H */
+#include <asm-i386/hypertransport.h>
diff --git a/include/asm-x86_64/i8253.h b/include/asm-x86_64/i8253.h
new file mode 100644
index 000000000000..015d8df07690
--- /dev/null
+++ b/include/asm-x86_64/i8253.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+extern spinlock_t i8253_lock;
+
+#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
index de2cd9a2303a..7475095c5061 100644
--- a/include/asm-x86_64/io.h
+++ b/include/asm-x86_64/io.h
@@ -144,6 +144,7 @@ extern void early_iounmap(void *addr, unsigned long size);
*/
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap(volatile void __iomem *addr);
+extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
/*
* ISA I/O bus memory addresses are 1:1 with the physical address.
diff --git a/include/asm-x86_64/iommu.h b/include/asm-x86_64/iommu.h
new file mode 100644
index 000000000000..5af471f228ee
--- /dev/null
+++ b/include/asm-x86_64/iommu.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_X8664_IOMMU_H
+#define _ASM_X8664_IOMMU_H 1
+
+extern void pci_iommu_shutdown(void);
+extern void no_iommu_init(void);
+extern int force_iommu, no_iommu;
+extern int iommu_detected;
+#ifdef CONFIG_IOMMU
+extern void gart_iommu_init(void);
+extern void gart_iommu_shutdown(void);
+extern void __init gart_parse_options(char *);
+extern void iommu_hole_init(void);
+extern int fallback_aper_order;
+extern int fallback_aper_force;
+extern int iommu_aperture;
+extern int iommu_aperture_allowed;
+extern int iommu_aperture_disabled;
+extern int fix_aperture;
+#else
+#define iommu_aperture 0
+#define iommu_aperture_allowed 0
+
+static inline void gart_iommu_shutdown(void)
+{
+}
+
+#endif
+
+#endif
diff --git a/include/asm-x86_64/kprobes.h b/include/asm-x86_64/kprobes.h
index cf5317898fb0..7db825403e01 100644
--- a/include/asm-x86_64/kprobes.h
+++ b/include/asm-x86_64/kprobes.h
@@ -41,7 +41,6 @@ typedef u8 kprobe_opcode_t;
? (MAX_STACK_SIZE) \
: (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR)))
-#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
#define ARCH_SUPPORTS_KRETPROBES
#define ARCH_INACTIVE_KPROBE_COUNT 1
diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h
index 177e92b4019b..7bc030a1996d 100644
--- a/include/asm-x86_64/mce.h
+++ b/include/asm-x86_64/mce.h
@@ -105,6 +105,11 @@ extern atomic_t mce_entry;
extern void do_machine_check(struct pt_regs *, long);
+extern int mce_notify_user(void);
+
+extern void stop_mce(void);
+extern void restart_mce(void);
+
#endif
#endif
diff --git a/include/asm-x86_64/mmu.h b/include/asm-x86_64/mmu.h
index 5dc6ed79859a..d2cd4a9d984d 100644
--- a/include/asm-x86_64/mmu.h
+++ b/include/asm-x86_64/mmu.h
@@ -15,6 +15,7 @@ typedef struct {
rwlock_t ldtlock;
int size;
struct semaphore sem;
+ void *vdso;
} mm_context_t;
#endif
diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h
index 5b8acddb70fb..083ad5827e48 100644
--- a/include/asm-x86_64/msidef.h
+++ b/include/asm-x86_64/msidef.h
@@ -1,47 +1 @@
-#ifndef ASM_MSIDEF_H
-#define ASM_MSIDEF_H
-
-/*
- * Constants for Intel APIC based MSI messages.
- */
-
-/*
- * Shifts for MSI data
- */
-
-#define MSI_DATA_VECTOR_SHIFT 0
-#define MSI_DATA_VECTOR_MASK 0x000000ff
-#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
-
-#define MSI_DATA_DELIVERY_MODE_SHIFT 8
-#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
-#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
-
-#define MSI_DATA_LEVEL_SHIFT 14
-#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
-#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
-
-#define MSI_DATA_TRIGGER_SHIFT 15
-#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
-#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
-
-/*
- * Shift/mask fields for msi address
- */
-
-#define MSI_ADDR_BASE_HI 0
-#define MSI_ADDR_BASE_LO 0xfee00000
-
-#define MSI_ADDR_DEST_MODE_SHIFT 2
-#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
-#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
-
-#define MSI_ADDR_REDIRECTION_SHIFT 3
-#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
-#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
-
-#define MSI_ADDR_DEST_ID_SHIFT 12
-#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
-#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
-
-#endif /* ASM_MSIDEF_H */
+#include <asm-i386/msidef.h>
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index d0a7f53b1497..5fb3c0de5ccc 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -88,5 +88,7 @@ unsigned lapic_adjust_nmi_hz(unsigned hz);
int lapic_watchdog_ok(void);
void disable_lapic_nmi_watchdog(void);
void enable_lapic_nmi_watchdog(void);
+void stop_nmi(void);
+void restart_nmi(void);
#endif /* ASM_NMI_H */
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index e327c830da0c..88adf1afb0a2 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -48,7 +48,8 @@ void copy_page(void *, void *);
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#define alloc_zeroed_user_highpage(vma, vaddr) alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO, vma, vaddr)
+#define __alloc_zeroed_user_highpage(movableflags, vma, vaddr) \
+ alloc_page_vma(GFP_HIGHUSER | __GFP_ZERO | movableflags, vma, vaddr)
#define __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
/*
* These are used to make use of C type-checking..
diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
index 49c5e9280598..88926eb44f5c 100644
--- a/include/asm-x86_64/pci.h
+++ b/include/asm-x86_64/pci.h
@@ -5,6 +5,25 @@
#ifdef __KERNEL__
+struct pci_sysdata {
+ int node; /* NUMA node */
+ void* iommu; /* IOMMU private data */
+};
+
+#ifdef CONFIG_CALGARY_IOMMU
+static inline void* pci_iommu(struct pci_bus *bus)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ return sd->iommu;
+}
+
+static inline void set_pci_iommu(struct pci_bus *bus, void *val)
+{
+ struct pci_sysdata *sd = bus->sysdata;
+ sd->iommu = val;
+}
+#endif /* CONFIG_CALGARY_IOMMU */
+
#include <linux/mm.h> /* for struct page */
/* Can be used to override the logic in pci_scan_bus for skipping
@@ -54,14 +73,6 @@ extern int iommu_setup(char *opt);
#if defined(CONFIG_IOMMU) || defined(CONFIG_CALGARY_IOMMU)
-/*
- * x86-64 always supports DAC, but sometimes it is useful to force
- * devices through the IOMMU to get automatic sg list merging.
- * Optional right now.
- */
-extern int iommu_sac_force;
-#define pci_dac_dma_supported(pci_dev, mask) (!iommu_sac_force)
-
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
dma_addr_t ADDR_NAME;
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
@@ -78,8 +89,6 @@ extern int iommu_sac_force;
#else
/* No IOMMU */
-#define pci_dac_dma_supported(pci_dev, mask) 1
-
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
#define pci_unmap_addr(PTR, ADDR_NAME) (0)
@@ -91,36 +100,6 @@ extern int iommu_sac_force;
#include <asm-generic/pci-dma-compat.h>
-static inline dma64_addr_t
-pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction)
-{
- return ((dma64_addr_t) page_to_phys(page) +
- (dma64_addr_t) offset);
-}
-
-static inline struct page *
-pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return virt_to_page(__va(dma_addr));
-}
-
-static inline unsigned long
-pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
-{
- return (dma_addr & ~PAGE_MASK);
-}
-
-static inline void
-pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
-}
-
-static inline void
-pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction)
-{
- flush_write_buffers();
-}
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -135,10 +114,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* __KERNEL__ */
/* generic pci stuff */
diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
index c6fbb67eac90..5abd48270101 100644
--- a/include/asm-x86_64/percpu.h
+++ b/include/asm-x86_64/percpu.h
@@ -20,6 +20,11 @@
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ __attribute__((__section__(".data.percpu.shared_aligned"))) \
+ __typeof__(type) per_cpu__##name \
+ ____cacheline_internodealigned_in_smp
+
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*({ \
extern int simple_identifier_##var(void); \
@@ -46,6 +51,8 @@ extern void setup_per_cpu_areas(void);
#define DEFINE_PER_CPU(type, name) \
__typeof__(type) per_cpu__##name
+#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \
+ DEFINE_PER_CPU(type, name)
#define per_cpu(var, cpu) (*((void)(cpu), &per_cpu__##var))
#define __get_cpu_var(var) per_cpu__##var
diff --git a/include/asm-x86_64/pgalloc.h b/include/asm-x86_64/pgalloc.h
index 8bb564687860..b467be6d367f 100644
--- a/include/asm-x86_64/pgalloc.h
+++ b/include/asm-x86_64/pgalloc.h
@@ -4,6 +4,10 @@
#include <asm/pda.h>
#include <linux/threads.h>
#include <linux/mm.h>
+#include <linux/quicklist.h>
+
+#define QUICK_PGD 0 /* We preserve special mappings over free */
+#define QUICK_PT 1 /* Other page table pages that are zero on free */
#define pmd_populate_kernel(mm, pmd, pte) \
set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte)))
@@ -20,23 +24,23 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *p
static inline void pmd_free(pmd_t *pmd)
{
BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
- free_page((unsigned long)pmd);
+ quicklist_free(QUICK_PT, NULL, 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);
+ return (pmd_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
}
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- return (pud_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+ return (pud_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
}
static inline void pud_free (pud_t *pud)
{
BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
- free_page((unsigned long)pud);
+ quicklist_free(QUICK_PT, NULL, pud);
}
static inline void pgd_list_add(pgd_t *pgd)
@@ -57,41 +61,57 @@ static inline void pgd_list_del(pgd_t *pgd)
spin_unlock(&pgd_lock);
}
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline void pgd_ctor(void *x)
{
unsigned boundary;
- pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
- if (!pgd)
- return NULL;
- pgd_list_add(pgd);
+ pgd_t *pgd = x;
+ struct page *page = virt_to_page(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));
+ init_level4_pgt + boundary,
+ (PTRS_PER_PGD - boundary) * sizeof(pgd_t));
+
+ spin_lock(&pgd_lock);
+ list_add(&page->lru, &pgd_list);
+ spin_unlock(&pgd_lock);
+}
+
+static inline void pgd_dtor(void *x)
+{
+ pgd_t *pgd = x;
+ struct page *page = virt_to_page(pgd);
+
+ spin_lock(&pgd_lock);
+ list_del(&page->lru);
+ spin_unlock(&pgd_lock);
+}
+
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *pgd = (pgd_t *)quicklist_alloc(QUICK_PGD,
+ GFP_KERNEL|__GFP_REPEAT, pgd_ctor);
return pgd;
}
static inline void pgd_free(pgd_t *pgd)
{
BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
- pgd_list_del(pgd);
- free_page((unsigned long)pgd);
+ quicklist_free(QUICK_PGD, pgd_dtor, 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);
+ return (pte_t *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
}
static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
{
- void *p = (void *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT);
+ void *p = (void *)quicklist_alloc(QUICK_PT, GFP_KERNEL|__GFP_REPEAT, NULL);
+
if (!p)
return NULL;
return virt_to_page(p);
@@ -103,17 +123,22 @@ static inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long add
static inline void pte_free_kernel(pte_t *pte)
{
BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
- free_page((unsigned long)pte);
+ quicklist_free(QUICK_PT, NULL, pte);
}
static inline void pte_free(struct page *pte)
{
- __free_page(pte);
-}
+ quicklist_free_page(QUICK_PT, NULL, pte);
+}
-#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
+#define __pte_free_tlb(tlb,pte) quicklist_free_page(QUICK_PT, NULL,(pte))
-#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))
+#define __pmd_free_tlb(tlb,x) quicklist_free(QUICK_PT, NULL, (x))
+#define __pud_free_tlb(tlb,x) quicklist_free(QUICK_PT, NULL, (x))
+static inline void check_pgt_cache(void)
+{
+ quicklist_trim(QUICK_PGD, pgd_dtor, 25, 16);
+ quicklist_trim(QUICK_PT, NULL, 25, 16);
+}
#endif /* _X86_64_PGALLOC_H */
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 0a71e0b9a619..c9d8764c89d1 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -266,21 +266,15 @@ static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
* Undefined behaviour if not..
*/
#define __LARGE_PTE (_PAGE_PSE|_PAGE_PRESENT)
-static inline int pte_user(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
-static inline int pte_exec(pte_t pte) { return !(pte_val(pte) & _PAGE_NX); }
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_RW; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
static inline int pte_huge(pte_t pte) { return pte_val(pte) & _PAGE_PSE; }
-static inline pte_t pte_rdprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
-static inline pte_t pte_exprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_USER)); return pte; }
static inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; }
static inline pte_t pte_mkold(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; }
static inline pte_t pte_wrprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_RW)); return pte; }
-static inline pte_t pte_mkread(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_USER)); return pte; }
static inline pte_t pte_mkexec(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_NX)); return 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; }
@@ -290,13 +284,6 @@ static inline pte_t pte_clrhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) &
struct vm_area_struct;
-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
- if (!pte_dirty(*ptep))
- return 0;
- return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte);
-}
-
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
{
if (!pte_young(*ptep))
@@ -416,13 +403,14 @@ extern struct list_head pgd_list;
extern int kern_addr_valid(unsigned long addr);
+pte_t *lookup_address(unsigned long addr);
+
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
remap_pfn_range(vma, vaddr, pfn, size, prot)
#define HAVE_ARCH_UNMAPPED_AREA
#define pgtable_cache_init() do { } while (0)
-#define check_pgt_cache() do { } while (0)
#define PAGE_AGP PAGE_KERNEL_NOCACHE
#define HAVE_PAGE_AGP 1
@@ -433,7 +421,6 @@ extern int kern_addr_valid(unsigned long addr);
(((o) & (1UL << (__VIRTUAL_MASK_SHIFT-1))) ? ((o) | (~__VIRTUAL_MASK)) : (o))
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index 461ffe4c1fcc..19525175b91c 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -83,7 +83,6 @@ struct cpuinfo_x86 {
#define X86_VENDOR_UMC 3
#define X86_VENDOR_NEXGEN 4
#define X86_VENDOR_CENTAUR 5
-#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NUM 8
#define X86_VENDOR_UNKNOWN 0xff
@@ -100,6 +99,7 @@ extern char ignore_irq13;
extern void identify_cpu(struct cpuinfo_x86 *);
extern void print_cpu_info(struct cpuinfo_x86 *);
+extern void init_scattered_cpuid_features(struct cpuinfo_x86 *c);
extern unsigned int init_intel_cacheinfo(struct cpuinfo_x86 *c);
extern unsigned short num_cache_leaves;
@@ -368,8 +368,6 @@ static inline void sync_core(void)
asm volatile("cpuid" : "=a" (tmp) : "0" (1) : "ebx","ecx","edx","memory");
}
-#define cpu_has_fpu 1
-
#define ARCH_HAS_PREFETCH
static inline void prefetch(void *x)
{
@@ -391,17 +389,6 @@ static inline void prefetchw(void *x)
#define cpu_relax() rep_nop()
-/*
- * NSC/Cyrix CPU indexed register access macros
- */
-
-#define getCx86(reg) ({ outb((reg), 0x22); inb(0x23); })
-
-#define setCx86(reg, data) do { \
- outb((reg), 0x22); \
- outb((data), 0x23); \
-} while (0)
-
static inline void serialize_cpu(void)
{
__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index 85255db1e82d..31f20ad65876 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -75,8 +75,6 @@ extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
extern void early_quirks(void);
extern void check_efer(void);
-extern int unhandled_signal(struct task_struct *tsk, int sig);
-
extern void select_idle_routine(const struct cpuinfo_x86 *c);
extern unsigned long table_start, table_end;
@@ -85,24 +83,6 @@ extern int exception_trace;
extern unsigned cpu_khz;
extern unsigned tsc_khz;
-extern void no_iommu_init(void);
-extern int force_iommu, no_iommu;
-extern int iommu_detected;
-#ifdef CONFIG_IOMMU
-extern void gart_iommu_init(void);
-extern void __init gart_parse_options(char *);
-extern void iommu_hole_init(void);
-extern int fallback_aper_order;
-extern int fallback_aper_force;
-extern int iommu_aperture;
-extern int iommu_aperture_allowed;
-extern int iommu_aperture_disabled;
-extern int fix_aperture;
-#else
-#define iommu_aperture 0
-#define iommu_aperture_allowed 0
-#endif
-
extern int reboot_force;
extern int notsc_setup(char *);
diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
index 5ea84dbb1e9c..7f166ccb0606 100644
--- a/include/asm-x86_64/ptrace.h
+++ b/include/asm-x86_64/ptrace.h
@@ -1,6 +1,7 @@
#ifndef _X86_64_PTRACE_H
#define _X86_64_PTRACE_H
+#include <linux/compiler.h> /* For __user */
#include <asm/ptrace-abi.h>
#ifndef __ASSEMBLY__
diff --git a/include/asm-x86_64/required-features.h b/include/asm-x86_64/required-features.h
new file mode 100644
index 000000000000..e80d5761b00a
--- /dev/null
+++ b/include/asm-x86_64/required-features.h
@@ -0,0 +1,46 @@
+#ifndef _ASM_REQUIRED_FEATURES_H
+#define _ASM_REQUIRED_FEATURES_H 1
+
+/* Define minimum CPUID feature set for kernel These bits are checked
+ really early to actually display a visible error message before the
+ kernel dies. Make sure to assign features to the proper mask!
+
+ The real information is in arch/x86_64/Kconfig.cpu, this just converts
+ the CONFIGs into a bitmask */
+
+/* x86-64 baseline features */
+#define NEED_FPU (1<<(X86_FEATURE_FPU & 31))
+#define NEED_PSE (1<<(X86_FEATURE_PSE & 31))
+#define NEED_MSR (1<<(X86_FEATURE_MSR & 31))
+#define NEED_PAE (1<<(X86_FEATURE_PAE & 31))
+#define NEED_CX8 (1<<(X86_FEATURE_CX8 & 31))
+#define NEED_PGE (1<<(X86_FEATURE_PGE & 31))
+#define NEED_FXSR (1<<(X86_FEATURE_FXSR & 31))
+#define NEED_CMOV (1<<(X86_FEATURE_CMOV & 31))
+#define NEED_XMM (1<<(X86_FEATURE_XMM & 31))
+#define NEED_XMM2 (1<<(X86_FEATURE_XMM2 & 31))
+
+#define REQUIRED_MASK0 (NEED_FPU|NEED_PSE|NEED_MSR|NEED_PAE|\
+ NEED_CX8|NEED_PGE|NEED_FXSR|NEED_CMOV|\
+ NEED_XMM|NEED_XMM2)
+#define SSE_MASK (NEED_XMM|NEED_XMM2)
+
+/* x86-64 baseline features */
+#define NEED_LM (1<<(X86_FEATURE_LM & 31))
+
+#ifdef CONFIG_X86_USE_3DNOW
+# define NEED_3DNOW (1<<(X86_FEATURE_3DNOW & 31))
+#else
+# define NEED_3DNOW 0
+#endif
+
+#define REQUIRED_MASK1 (NEED_LM|NEED_3DNOW)
+
+#define REQUIRED_MASK2 0
+#define REQUIRED_MASK3 0
+#define REQUIRED_MASK4 0
+#define REQUIRED_MASK5 0
+#define REQUIRED_MASK6 0
+#define REQUIRED_MASK7 0
+
+#endif
diff --git a/include/asm-x86_64/resume-trace.h b/include/asm-x86_64/resume-trace.h
new file mode 100644
index 000000000000..34bf998fdf62
--- /dev/null
+++ b/include/asm-x86_64/resume-trace.h
@@ -0,0 +1,13 @@
+#define TRACE_RESUME(user) do { \
+ if (pm_trace_enabled) { \
+ void *tracedata; \
+ asm volatile("movq $1f,%0\n" \
+ ".section .tracedata,\"a\"\n" \
+ "1:\t.word %c1\n" \
+ "\t.quad %c2\n" \
+ ".previous" \
+ :"=r" (tracedata) \
+ : "i" (__LINE__), "i" (__FILE__)); \
+ generate_resume_trace(tracedata, user); \
+ } \
+} while (0)
diff --git a/include/asm-x86_64/segment.h b/include/asm-x86_64/segment.h
index adf2bf1e187c..04b8ab21328f 100644
--- a/include/asm-x86_64/segment.h
+++ b/include/asm-x86_64/segment.h
@@ -3,6 +3,14 @@
#include <asm/cache.h>
+/* Simple and small GDT entries for booting only */
+
+#define GDT_ENTRY_BOOT_CS 2
+#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8)
+
+#define GDT_ENTRY_BOOT_DS (GDT_ENTRY_BOOT_CS + 1)
+#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8)
+
#define __KERNEL_CS 0x10
#define __KERNEL_DS 0x18
diff --git a/include/asm-x86_64/string.h b/include/asm-x86_64/string.h
index 9505d9f4bead..e583da7918fb 100644
--- a/include/asm-x86_64/string.h
+++ b/include/asm-x86_64/string.h
@@ -29,6 +29,9 @@ return (to);
function. */
#define __HAVE_ARCH_MEMCPY 1
+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
+extern void *memcpy(void *to, const void *from, size_t len);
+#else
extern void *__memcpy(void *to, const void *from, size_t len);
#define memcpy(dst,src,len) \
({ size_t __len = (len); \
@@ -38,7 +41,7 @@ extern void *__memcpy(void *to, const void *from, size_t len);
else \
__ret = __builtin_memcpy((dst),(src),__len); \
__ret; })
-
+#endif
#define __HAVE_ARCH_MEMSET
void *memset(void *s, int c, size_t n);
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index ead9f9a56234..02175aa1d16a 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -75,19 +75,31 @@ static inline unsigned long read_cr0(void)
unsigned long cr0;
asm volatile("movq %%cr0,%0" : "=r" (cr0));
return cr0;
-}
+}
static inline void write_cr0(unsigned long val)
{
asm volatile("movq %0,%%cr0" :: "r" (val));
-}
+}
+
+static inline unsigned long read_cr2(void)
+{
+ unsigned long cr2;
+ asm("movq %%cr2,%0" : "=r" (cr2));
+ return cr2;
+}
+
+static inline void write_cr2(unsigned long val)
+{
+ asm volatile("movq %0,%%cr2" :: "r" (val));
+}
static inline unsigned long read_cr3(void)
{
unsigned long cr3;
asm("movq %%cr3,%0" : "=r" (cr3));
return cr3;
-}
+}
static inline void write_cr3(unsigned long val)
{
@@ -99,27 +111,30 @@ static inline unsigned long read_cr4(void)
unsigned long cr4;
asm("movq %%cr4,%0" : "=r" (cr4));
return cr4;
-}
+}
static inline void write_cr4(unsigned long val)
{
asm volatile("movq %0,%%cr4" :: "r" (val) : "memory");
-}
-
-#define stts() write_cr0(8 | read_cr0())
+}
-#define wbinvd() \
- __asm__ __volatile__ ("wbinvd": : :"memory");
+static inline unsigned long read_cr8(void)
+{
+ unsigned long cr8;
+ asm("movq %%cr8,%0" : "=r" (cr8));
+ return cr8;
+}
-/*
- * On SMP systems, when the scheduler does migration-cost autodetection,
- * it needs a way to flush as much of the CPU's caches as possible.
- */
-static inline void sched_cacheflush(void)
+static inline void write_cr8(unsigned long val)
{
- wbinvd();
+ asm volatile("movq %0,%%cr8" :: "r" (val) : "memory");
}
+#define stts() write_cr0(8 | read_cr0())
+
+#define wbinvd() \
+ __asm__ __volatile__ ("wbinvd": : :"memory")
+
#endif /* __KERNEL__ */
#define nop() __asm__ __volatile__ ("nop")
diff --git a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h
index 10bb5a8ed688..33c72ef15a0c 100644
--- a/include/asm-x86_64/thread_info.h
+++ b/include/asm-x86_64/thread_info.h
@@ -115,6 +115,7 @@ static inline struct thread_info *stack_thread_info(void)
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */
+#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
/* 16 free */
#define TIF_IA32 17 /* 32bit process */
#define TIF_FORK 18 /* ret_from_fork */
@@ -133,6 +134,7 @@ static inline struct thread_info *stack_thread_info(void)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
+#define _TIF_MCE_NOTIFY (1<<TIF_MCE_NOTIFY)
#define _TIF_IA32 (1<<TIF_IA32)
#define _TIF_FORK (1<<TIF_FORK)
#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
diff --git a/include/asm-x86_64/timex.h b/include/asm-x86_64/timex.h
index f6527e1b6c1c..6ed21f44d308 100644
--- a/include/asm-x86_64/timex.h
+++ b/include/asm-x86_64/timex.h
@@ -9,7 +9,6 @@
#include <asm/8253pit.h>
#include <asm/msr.h>
#include <asm/vsyscall.h>
-#include <asm/hpet.h>
#include <asm/system.h>
#include <asm/processor.h>
#include <asm/tsc.h>
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
index 8516225a8389..888eb4abdd07 100644
--- a/include/asm-x86_64/tlbflush.h
+++ b/include/asm-x86_64/tlbflush.h
@@ -92,7 +92,11 @@ static inline void flush_tlb_range(struct vm_area_struct * vma, unsigned long st
#endif
-#define flush_tlb_kernel_range(start, end) flush_tlb_all()
+static inline void flush_tlb_kernel_range(unsigned long start,
+ unsigned long end)
+{
+ flush_tlb_all();
+}
static inline void flush_tlb_pgtables(struct mm_struct *mm,
unsigned long start, unsigned long end)
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 4fd6fb23953e..36e52fba7960 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -22,7 +22,7 @@ extern int __node_distance(int, int);
#define parent_node(node) (node)
#define node_to_first_cpu(node) (first_cpu(node_to_cpumask[node]))
#define node_to_cpumask(node) (node_to_cpumask[node])
-#define pcibus_to_node(bus) ((long)(bus->sysdata))
+#define pcibus_to_node(bus) ((struct pci_sysdata *)((bus)->sysdata))->node
#define pcibus_to_cpumask(bus) node_to_cpumask(pcibus_to_node(bus));
#define numa_node_id() read_pda(nodenumber)
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index 8696f8ad401e..fc4e73f5f1fa 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -630,6 +630,8 @@ __SYSCALL(__NR_signalfd, sys_signalfd)
__SYSCALL(__NR_timerfd, sys_timerfd)
#define __NR_eventfd 284
__SYSCALL(__NR_eventfd, sys_eventfd)
+#define __NR_fallocate 285
+__SYSCALL(__NR_fallocate, sys_fallocate)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-x86_64/vgtod.h b/include/asm-x86_64/vgtod.h
new file mode 100644
index 000000000000..3301f0929342
--- /dev/null
+++ b/include/asm-x86_64/vgtod.h
@@ -0,0 +1,29 @@
+#ifndef _ASM_VGTOD_H
+#define _ASM_VGTOD_H 1
+
+#include <asm/vsyscall.h>
+#include <linux/clocksource.h>
+
+struct vsyscall_gtod_data {
+ seqlock_t lock;
+
+ /* open coded 'struct timespec' */
+ time_t wall_time_sec;
+ u32 wall_time_nsec;
+
+ int sysctl_enabled;
+ struct timezone sys_tz;
+ struct { /* extract of a clocksource struct */
+ cycle_t (*vread)(void);
+ cycle_t cycle_last;
+ cycle_t mask;
+ u32 mult;
+ u32 shift;
+ } clock;
+ struct timespec wall_to_monotonic;
+};
+extern struct vsyscall_gtod_data __vsyscall_gtod_data
+__section_vsyscall_gtod_data;
+extern struct vsyscall_gtod_data vsyscall_gtod_data;
+
+#endif
diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h
index 82b4afe65c91..3b8ceb4af2cf 100644
--- a/include/asm-x86_64/vsyscall.h
+++ b/include/asm-x86_64/vsyscall.h
@@ -22,6 +22,8 @@ enum vsyscall_num {
/* Definitions for CONFIG_GENERIC_TIME definitions */
#define __section_vsyscall_gtod_data __attribute__ \
((unused, __section__ (".vsyscall_gtod_data"),aligned(16)))
+#define __section_vsyscall_clock __attribute__ \
+ ((unused, __section__ (".vsyscall_clock"),aligned(16)))
#define __vsyscall_fn __attribute__ ((unused,__section__(".vsyscall_fn")))
#define VGETCPU_RDTSCP 1
@@ -36,7 +38,6 @@ extern volatile unsigned long __jiffies;
/* kernel space (writeable) */
extern int vgetcpu_mode;
extern struct timezone sys_tz;
-extern struct vsyscall_gtod_data_t vsyscall_gtod_data;
#endif /* __KERNEL__ */
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
index ffc4dcfd6ac1..05a2f67c6768 100644
--- a/include/asm-xtensa/a.out.h
+++ b/include/asm-xtensa/a.out.h
@@ -17,6 +17,7 @@
/* Note: the kernel needs the a.out definitions, even if only ELF is used. */
#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
struct exec
{
diff --git a/include/asm-xtensa/fb.h b/include/asm-xtensa/fb.h
new file mode 100644
index 000000000000..c7df38030992
--- /dev/null
+++ b/include/asm-xtensa/fb.h
@@ -0,0 +1,12 @@
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+#include <linux/fb.h>
+
+#define fb_pgprotect(...) do {} while (0)
+
+static inline int fb_is_primary_device(struct fb_info *info)
+{
+ return 0;
+}
+
+#endif /* _ASM_FB_H_ */
diff --git a/include/asm-xtensa/pci.h b/include/asm-xtensa/pci.h
index 24eb7fc25da8..66410acf18b4 100644
--- a/include/asm-xtensa/pci.h
+++ b/include/asm-xtensa/pci.h
@@ -64,9 +64,6 @@ struct pci_dev;
#define pci_ubnmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
-/* We cannot access memory above 4GB */
-#define pci_dac_dma_supported(pci_dev, mask) (0)
-
/* Map a range of PCI memory or I/O space for a device into user space */
int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
@@ -74,10 +71,6 @@ int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
#define HAVE_PCI_MMAP 1
-static inline void pcibios_add_platform_entries(struct pci_dev *dev)
-{
-}
-
#endif /* __KERNEL__ */
/* Implement the pci_ DMA API in terms of the generic device dma_ one */
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
index 2d4b5db6ea63..06850f3b26a7 100644
--- a/include/asm-xtensa/pgtable.h
+++ b/include/asm-xtensa/pgtable.h
@@ -197,16 +197,13 @@ extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)];
/* Note: We use the _PAGE_USER bit to indicate write-protect kernel memory */
-static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
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 pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_RW | _PAGE_WRENABLE); return pte; }
-static inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; }
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; }
-static inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; }
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_RW; return pte; }
@@ -270,17 +267,6 @@ ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr,
return 1;
}
-static inline int
-ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr,
- pte_t *ptep)
-{
- pte_t pte = *ptep;
- if (!pte_dirty(pte))
- return 0;
- update_pte(ptep, pte_mkclean(pte));
- return 1;
-}
-
static inline pte_t
ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
@@ -421,7 +407,6 @@ typedef pte_t *pte_addr_t;
#endif /* !defined (__ASSEMBLY__) */
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
#define __HAVE_ARCH_PTEP_MKDIRTY
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index afae306b177c..bcf875e844fe 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -91,7 +91,6 @@ header-y += in6.h
header-y += in_route.h
header-y += ioctl.h
header-y += ipmi_msgdefs.h
-header-y += ip_mp_alg.h
header-y += ipsec.h
header-y += ipx.h
header-y += irda.h
@@ -226,6 +225,7 @@ unifdef-y += if_fddi.h
unifdef-y += if_frad.h
unifdef-y += if_ltalk.h
unifdef-y += if_link.h
+unifdef-y += if_pppol2tp.h
unifdef-y += if_pppox.h
unifdef-y += if_shaper.h
unifdef-y += if_tr.h
@@ -247,7 +247,6 @@ unifdef-y += isdn.h
unifdef-y += isdnif.h
unifdef-y += isdn_divertif.h
unifdef-y += isdn_ppp.h
-unifdef-y += isicom.h
unifdef-y += jbd.h
unifdef-y += joystick.h
unifdef-y += kdev_t.h
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index fccd8b548d93..d5680cd7746a 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -88,10 +88,8 @@ int acpi_table_parse (char *id, acpi_table_handler handler);
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
int entry_id, acpi_table_entry_handler handler, unsigned int max_entries);
int acpi_table_parse_madt (enum acpi_madt_type id, acpi_table_entry_handler handler, unsigned int max_entries);
-int acpi_table_parse_srat (enum acpi_srat_type id, acpi_table_entry_handler handler, unsigned int max_entries);
int acpi_parse_mcfg (struct acpi_table_header *header);
void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
-void acpi_table_print_srat_entry (struct acpi_subtable_header *srat);
/* the following four functions are architecture-dependent */
#ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
@@ -122,7 +120,7 @@ extern struct acpi_mcfg_allocation *pci_mmcfg_config;
extern int pci_mmcfg_config_num;
extern int sbf_port;
-extern unsigned long acpi_video_flags;
+extern unsigned long acpi_realmode_flags;
#else /* !CONFIG_ACPI */
@@ -233,6 +231,9 @@ extern int acpi_paddr_to_node(u64 start_addr, u64 size);
extern int pnpacpi_disabled;
+#define PXM_INVAL (-1)
+#define NID_INVAL (-1)
+
#else /* CONFIG_ACPI */
static inline int acpi_boot_init(void)
diff --git a/include/linux/aer.h b/include/linux/aer.h
index 402e178b38eb..509656286e53 100644
--- a/include/linux/aer.h
+++ b/include/linux/aer.h
@@ -13,11 +13,13 @@ extern int pci_enable_pcie_error_reporting(struct pci_dev *dev);
extern int pci_find_aer_capability(struct pci_dev *dev);
extern int pci_disable_pcie_error_reporting(struct pci_dev *dev);
extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
+extern int pci_cleanup_aer_correct_error_status(struct pci_dev *dev);
#else
-#define pci_enable_pcie_error_reporting(dev) do { } while (0)
-#define pci_find_aer_capability(dev) do { } while (0)
-#define pci_disable_pcie_error_reporting(dev) do { } while (0)
-#define pci_cleanup_aer_uncorrect_error_status(dev) do { } while (0)
+#define pci_enable_pcie_error_reporting(dev) (-EINVAL)
+#define pci_find_aer_capability(dev) (0)
+#define pci_disable_pcie_error_reporting(dev) (-EINVAL)
+#define pci_cleanup_aer_uncorrect_error_status(dev) (-EINVAL)
+#define pci_cleanup_aer_correct_error_status(dev) (-EINVAL)
#endif
#endif //_AER_H_
diff --git a/include/linux/aio.h b/include/linux/aio.h
index b903fc02bdb7..d10e608f232d 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -86,7 +86,7 @@ struct kioctx;
*/
struct kiocb {
struct list_head ki_run_list;
- long ki_flags;
+ unsigned long ki_flags;
int ki_users;
unsigned ki_key; /* id of this request */
diff --git a/include/linux/async_tx.h b/include/linux/async_tx.h
new file mode 100644
index 000000000000..bdca3f1b3213
--- /dev/null
+++ b/include/linux/async_tx.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright © 2006, 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.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+#ifndef _ASYNC_TX_H_
+#define _ASYNC_TX_H_
+#include <linux/dmaengine.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+/**
+ * dma_chan_ref - object used to manage dma channels received from the
+ * dmaengine core.
+ * @chan - the channel being tracked
+ * @node - node for the channel to be placed on async_tx_master_list
+ * @rcu - for list_del_rcu
+ * @count - number of times this channel is listed in the pool
+ * (for channels with multiple capabiities)
+ */
+struct dma_chan_ref {
+ struct dma_chan *chan;
+ struct list_head node;
+ struct rcu_head rcu;
+ atomic_t count;
+};
+
+/**
+ * async_tx_flags - modifiers for the async_* calls
+ * @ASYNC_TX_XOR_ZERO_DST: this flag must be used for xor operations where the
+ * the destination address is not a source. The asynchronous case handles this
+ * implicitly, the synchronous case needs to zero the destination block.
+ * @ASYNC_TX_XOR_DROP_DST: this flag must be used if the destination address is
+ * also one of the source addresses. In the synchronous case the destination
+ * address is an implied source, whereas the asynchronous case it must be listed
+ * as a source. The destination address must be the first address in the source
+ * array.
+ * @ASYNC_TX_ASSUME_COHERENT: skip cache maintenance operations
+ * @ASYNC_TX_ACK: immediately ack the descriptor, precludes setting up a
+ * dependency chain
+ * @ASYNC_TX_DEP_ACK: ack the dependency descriptor. Useful for chaining.
+ */
+enum async_tx_flags {
+ ASYNC_TX_XOR_ZERO_DST = (1 << 0),
+ ASYNC_TX_XOR_DROP_DST = (1 << 1),
+ ASYNC_TX_ASSUME_COHERENT = (1 << 2),
+ ASYNC_TX_ACK = (1 << 3),
+ ASYNC_TX_DEP_ACK = (1 << 4),
+};
+
+#ifdef CONFIG_DMA_ENGINE
+void async_tx_issue_pending_all(void);
+enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
+void async_tx_run_dependencies(struct dma_async_tx_descriptor *tx);
+struct dma_chan *
+async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+ enum dma_transaction_type tx_type);
+#else
+static inline void async_tx_issue_pending_all(void)
+{
+ do { } while (0);
+}
+
+static inline enum dma_status
+dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
+{
+ return DMA_SUCCESS;
+}
+
+static inline void
+async_tx_run_dependencies(struct dma_async_tx_descriptor *tx,
+ struct dma_chan *host_chan)
+{
+ do { } while (0);
+}
+
+static inline struct dma_chan *
+async_tx_find_channel(struct dma_async_tx_descriptor *depend_tx,
+ enum dma_transaction_type tx_type)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * async_tx_sync_epilog - actions to take if an operation is run synchronously
+ * @flags: async_tx flags
+ * @depend_tx: transaction depends on depend_tx
+ * @cb_fn: function to call when the transaction completes
+ * @cb_fn_param: parameter to pass to the callback routine
+ */
+static inline void
+async_tx_sync_epilog(unsigned long flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_fn_param)
+{
+ if (cb_fn)
+ cb_fn(cb_fn_param);
+
+ if (depend_tx && (flags & ASYNC_TX_DEP_ACK))
+ async_tx_ack(depend_tx);
+}
+
+void
+async_tx_submit(struct dma_chan *chan, struct dma_async_tx_descriptor *tx,
+ enum async_tx_flags flags, struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_fn_param);
+
+struct dma_async_tx_descriptor *
+async_xor(struct page *dest, struct page **src_list, unsigned int offset,
+ int src_cnt, size_t len, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_fn_param);
+
+struct dma_async_tx_descriptor *
+async_xor_zero_sum(struct page *dest, struct page **src_list,
+ unsigned int offset, int src_cnt, size_t len,
+ u32 *result, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_fn_param);
+
+struct dma_async_tx_descriptor *
+async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
+ unsigned int src_offset, size_t len, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_fn_param);
+
+struct dma_async_tx_descriptor *
+async_memset(struct page *dest, int val, unsigned int offset,
+ size_t len, enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_fn_param);
+
+struct dma_async_tx_descriptor *
+async_trigger_callback(enum async_tx_flags flags,
+ struct dma_async_tx_descriptor *depend_tx,
+ dma_async_tx_callback cb_fn, void *cb_fn_param);
+#endif /* _ASYNC_TX_H_ */
diff --git a/include/linux/ata.h b/include/linux/ata.h
index 407dc7e098bc..23a22df039d8 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -64,6 +64,15 @@ enum {
ATA_ID_PROD_LEN = 40,
ATA_PCI_CTL_OFS = 2,
+
+ ATA_PIO0 = (1 << 0),
+ ATA_PIO1 = ATA_PIO0 | (1 << 1),
+ ATA_PIO2 = ATA_PIO1 | (1 << 2),
+ ATA_PIO3 = ATA_PIO2 | (1 << 3),
+ ATA_PIO4 = ATA_PIO3 | (1 << 4),
+ ATA_PIO5 = ATA_PIO4 | (1 << 5),
+ ATA_PIO6 = ATA_PIO5 | (1 << 6),
+
ATA_UDMA0 = (1 << 0),
ATA_UDMA1 = ATA_UDMA0 | (1 << 1),
ATA_UDMA2 = ATA_UDMA1 | (1 << 2),
@@ -164,6 +173,8 @@ enum {
ATA_CMD_SET_MAX = 0xF9,
ATA_CMD_SET_MAX_EXT = 0x37,
ATA_CMD_READ_LOG_EXT = 0x2f,
+ ATA_CMD_PMP_READ = 0xE4,
+ ATA_CMD_PMP_WRITE = 0xE8,
/* READ_LOG_EXT pages */
ATA_LOG_SATA_NCQ = 0x10,
@@ -212,6 +223,28 @@ enum {
0=to device, 1=to host */
ATAPI_CDB_LEN = 16,
+ /* PMP stuff */
+ SATA_PMP_MAX_PORTS = 15,
+ SATA_PMP_CTRL_PORT = 15,
+
+ SATA_PMP_GSCR_DWORDS = 128,
+ SATA_PMP_GSCR_PROD_ID = 0,
+ SATA_PMP_GSCR_REV = 1,
+ SATA_PMP_GSCR_PORT_INFO = 2,
+ SATA_PMP_GSCR_ERROR = 32,
+ SATA_PMP_GSCR_ERROR_EN = 33,
+ SATA_PMP_GSCR_FEAT = 64,
+ SATA_PMP_GSCR_FEAT_EN = 96,
+
+ SATA_PMP_PSCR_STATUS = 0,
+ SATA_PMP_PSCR_ERROR = 1,
+ SATA_PMP_PSCR_CONTROL = 2,
+
+ SATA_PMP_FEAT_BIST = (1 << 0),
+ SATA_PMP_FEAT_PMREQ = (1 << 1),
+ SATA_PMP_FEAT_DYNSSC = (1 << 2),
+ SATA_PMP_FEAT_NOTIFY = (1 << 3),
+
/* cable types */
ATA_CBL_NONE = 0,
ATA_CBL_PATA40 = 1,
@@ -418,4 +451,9 @@ static inline int lba_48_ok(u64 block, u32 n_block)
return ((block + n_block - 1) < ((u64)1 << 48)) && (n_block <= 65536);
}
+#define sata_pmp_gscr_vendor(gscr) ((gscr)[SATA_PMP_GSCR_PROD_ID] & 0xffff)
+#define sata_pmp_gscr_devid(gscr) ((gscr)[SATA_PMP_GSCR_PROD_ID] >> 16)
+#define sata_pmp_gscr_rev(gscr) (((gscr)[SATA_PMP_GSCR_REV] >> 8) & 0xff)
+#define sata_pmp_gscr_ports(gscr) ((gscr)[SATA_PMP_GSCR_PORT_INFO] & 0xf)
+
#endif /* __LINUX_ATA_H__ */
diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h
index 93bfb0beb62a..8ff274933948 100644
--- a/include/linux/attribute_container.h
+++ b/include/linux/attribute_container.h
@@ -12,7 +12,6 @@
#include <linux/device.h>
#include <linux/list.h>
#include <linux/klist.h>
-#include <linux/spinlock.h>
struct attribute_container {
struct list_head node;
diff --git a/include/linux/audit.h b/include/linux/audit.h
index fccc6e50298a..4bbd8601b8f0 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -63,9 +63,12 @@
#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */
#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */
#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */
+#define AUDIT_TTY_GET 1014 /* Get TTY auditing status */
+#define AUDIT_TTY_SET 1015 /* Set TTY auditing status */
#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */
#define AUDIT_USER_AVC 1107 /* We filter this differently */
+#define AUDIT_USER_TTY 1124 /* Non-ICANON TTY input meaning */
#define AUDIT_LAST_USER_MSG 1199
#define AUDIT_FIRST_USER_MSG2 2100 /* More user space messages */
#define AUDIT_LAST_USER_MSG2 2999
@@ -92,6 +95,7 @@
#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */
#define AUDIT_FD_PAIR 1317 /* audit record for pipe/socketpair */
#define AUDIT_OBJ_PID 1318 /* ptrace target */
+#define AUDIT_TTY 1319 /* Input on an administrative TTY */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -157,7 +161,7 @@
* are currently used in an audit field constant understood by the kernel.
* If you are adding a new #define AUDIT_<whatever>, please ensure that
* AUDIT_UNUSED_BITS is updated if need be. */
-#define AUDIT_UNUSED_BITS 0x0FFFFC00
+#define AUDIT_UNUSED_BITS 0x07FFFC00
/* Rule fields */
@@ -209,25 +213,29 @@
#define AUDIT_NEGATE 0x80000000
/* These are the supported operators.
- * 4 2 1
- * = > <
- * -------
- * 0 0 0 0 nonsense
- * 0 0 1 1 <
- * 0 1 0 2 >
- * 0 1 1 3 !=
- * 1 0 0 4 =
- * 1 0 1 5 <=
- * 1 1 0 6 >=
- * 1 1 1 7 all operators
+ * 4 2 1 8
+ * = > < ?
+ * ----------
+ * 0 0 0 0 00 nonsense
+ * 0 0 0 1 08 & bit mask
+ * 0 0 1 0 10 <
+ * 0 1 0 0 20 >
+ * 0 1 1 0 30 !=
+ * 1 0 0 0 40 =
+ * 1 0 0 1 48 &= bit test
+ * 1 0 1 0 50 <=
+ * 1 1 0 0 60 >=
+ * 1 1 1 1 78 all operators
*/
+#define AUDIT_BIT_MASK 0x08000000
#define AUDIT_LESS_THAN 0x10000000
#define AUDIT_GREATER_THAN 0x20000000
#define AUDIT_NOT_EQUAL 0x30000000
#define AUDIT_EQUAL 0x40000000
+#define AUDIT_BIT_TEST (AUDIT_BIT_MASK|AUDIT_EQUAL)
#define AUDIT_LESS_THAN_OR_EQUAL (AUDIT_LESS_THAN|AUDIT_EQUAL)
#define AUDIT_GREATER_THAN_OR_EQUAL (AUDIT_GREATER_THAN|AUDIT_EQUAL)
-#define AUDIT_OPERATORS (AUDIT_EQUAL|AUDIT_NOT_EQUAL)
+#define AUDIT_OPERATORS (AUDIT_EQUAL|AUDIT_NOT_EQUAL|AUDIT_BIT_MASK)
/* Status symbols */
/* Mask values */
@@ -289,6 +297,10 @@ struct audit_status {
__u32 backlog; /* messages waiting in queue */
};
+struct audit_tty_status {
+ __u32 enabled; /* 1 = enabled, 0 = disabled */
+};
+
/* audit_rule_data supports filter rules with both integer and string
* fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
* AUDIT_LIST_RULES requests.
@@ -399,7 +411,6 @@ extern int audit_bprm(struct linux_binprm *bprm);
extern int audit_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr);
extern int __audit_fd_pair(int fd1, int fd2);
-extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
extern int audit_set_macxattr(const char *name);
extern int __audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
extern int __audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
@@ -479,7 +490,6 @@ extern int audit_signals;
#define audit_socketcall(n,a) ({ 0; })
#define audit_fd_pair(n,a) ({ 0; })
#define audit_sockaddr(len, addr) ({ 0; })
-#define audit_avc_path(dentry, mnt) ({ 0; })
#define audit_set_macxattr(n) do { ; } while (0)
#define audit_mq_open(o,m,a) ({ 0; })
#define audit_mq_timedsend(d,l,p,t) ({ 0; })
@@ -515,11 +525,13 @@ extern void audit_log_d_path(struct audit_buffer *ab,
const char *prefix,
struct dentry *dentry,
struct vfsmount *vfsmnt);
+extern void audit_log_lost(const char *message);
/* Private API (for audit.c only) */
extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
extern int audit_filter_type(int type);
extern int audit_receive_filter(int type, int pid, int uid, int seq,
void *data, size_t datasz, uid_t loginuid, u32 sid);
+extern int audit_enabled;
#else
#define audit_log(c,g,t,f,...) do { ; } while (0)
#define audit_log_start(c,g,t) ({ NULL; })
@@ -530,6 +542,7 @@ extern int audit_receive_filter(int type, int pid, int uid, int seq,
#define audit_log_untrustedstring(a,s) do { ; } while (0)
#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0)
#define audit_log_d_path(b,p,d,v) do { ; } while (0)
+#define audit_enabled 0
#endif
#endif
#endif
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index f2542c24b328..7011d6255593 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -93,7 +93,6 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
void clear_bdi_congested(struct backing_dev_info *bdi, int rw);
void set_bdi_congested(struct backing_dev_info *bdi, int rw);
long congestion_wait(int rw, long timeout);
-long congestion_wait_interruptible(int rw, long timeout);
void congestion_end(int rw);
#define bdi_cap_writeback_dirty(bdi) \
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 1023ba0d6e55..c897c7b03858 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -69,8 +69,8 @@ struct backlight_device {
/* The framebuffer notifier block */
struct notifier_block fb_notif;
- /* The class device structure */
- struct class_device class_dev;
+
+ struct device dev;
};
static inline void backlight_update_status(struct backlight_device *bd)
@@ -85,6 +85,11 @@ extern struct backlight_device *backlight_device_register(const char *name,
struct device *dev, void *devdata, struct backlight_ops *ops);
extern void backlight_device_unregister(struct backlight_device *bd);
-#define to_backlight_device(obj) container_of(obj, struct backlight_device, class_dev)
+#define to_backlight_device(obj) container_of(obj, struct backlight_device, dev)
+
+static inline void * bl_get_data(struct backlight_device *bl_dev)
+{
+ return dev_get_drvdata(&bl_dev->dev);
+}
#endif
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index e1a708337be3..91c8c07fe8b7 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -6,11 +6,13 @@
struct pt_regs;
/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB w/4KB pages!
+ * These are the maximum length and maximum number of strings passed to the
+ * execve() system call. MAX_ARG_STRLEN is essentially random but serves to
+ * prevent the kernel from being unduly impacted by misaddressed pointers.
+ * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer.
*/
-#define MAX_ARG_PAGES 32
+#define MAX_ARG_STRLEN (PAGE_SIZE * 32)
+#define MAX_ARG_STRINGS 0x7FFFFFFF
/* sizeof(linux_binprm->buf) */
#define BINPRM_BUF_SIZE 128
@@ -24,7 +26,12 @@ struct pt_regs;
*/
struct linux_binprm{
char buf[BINPRM_BUF_SIZE];
+#ifdef CONFIG_MMU
+ struct vm_area_struct *vma;
+#else
+# define MAX_ARG_PAGES 32
struct page *page[MAX_ARG_PAGES];
+#endif
struct mm_struct *mm;
unsigned long p; /* current top of mem */
int sh_bang;
@@ -40,6 +47,7 @@ struct linux_binprm{
unsigned interp_flags;
unsigned interp_data;
unsigned long loader, exec;
+ unsigned long argv_len;
};
#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
@@ -68,7 +76,7 @@ extern int register_binfmt(struct linux_binfmt *);
extern int unregister_binfmt(struct linux_binfmt *);
extern int prepare_binprm(struct linux_binprm *);
-extern void remove_arg_zero(struct linux_binprm *);
+extern int __must_check remove_arg_zero(struct linux_binprm *);
extern int search_binary_handler(struct linux_binprm *,struct pt_regs *);
extern int flush_old_exec(struct linux_binprm * bprm);
@@ -85,6 +93,7 @@ extern int suid_dumpable;
extern int setup_arg_pages(struct linux_binprm * bprm,
unsigned long stack_top,
int executable_stack);
+extern int bprm_mm_init(struct linux_binprm *bprm);
extern int copy_strings_kernel(int argc,char ** argv,struct linux_binprm *bprm);
extern void compute_creds(struct linux_binprm *binprm);
extern int do_coredump(long signr, int exit_code, struct pt_regs * regs);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index fae138bd2207..695e34964cb7 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -14,6 +14,7 @@
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/stringify.h>
+#include <linux/bsg.h>
#include <asm/scatterlist.h>
@@ -41,6 +42,8 @@ struct elevator_queue;
typedef struct elevator_queue elevator_t;
struct request_pm_state;
struct blk_trace;
+struct request;
+struct sg_io_hdr;
#define BLKDEV_MIN_RQ 4
#define BLKDEV_MAX_RQ 128 /* Default maximum */
@@ -314,6 +317,9 @@ struct request {
*/
rq_end_io_fn *end_io;
void *end_io_data;
+
+ /* for bidi */
+ struct request *next_rq;
};
/*
@@ -468,6 +474,10 @@ struct request_queue
unsigned int bi_size;
struct mutex sysfs_lock;
+
+#if defined(CONFIG_BLK_DEV_BSG)
+ struct bsg_class_device bsg_dev;
+#endif
};
#define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */
@@ -479,6 +489,7 @@ struct request_queue
#define QUEUE_FLAG_REENTER 6 /* Re-entrancy avoidance */
#define QUEUE_FLAG_PLUGGED 7 /* queue is plugged */
#define QUEUE_FLAG_ELVSWITCH 8 /* don't use elevator, just do FIFO */
+#define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */
enum {
/*
@@ -543,6 +554,7 @@ enum {
#define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED)
#define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER)
#define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA)
+#define blk_bidi_rq(rq) ((rq)->next_rq != NULL)
#define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist)
@@ -607,7 +619,12 @@ extern unsigned long blk_max_low_pfn, blk_max_pfn;
#define BLK_BOUNCE_ANY ((u64)blk_max_pfn << PAGE_SHIFT)
#define BLK_BOUNCE_ISA (ISA_DMA_THRESHOLD)
-#ifdef CONFIG_MMU
+/*
+ * default timeout for SG_IO if none specified
+ */
+#define BLK_DEFAULT_SG_TIMEOUT (60 * HZ)
+
+#ifdef CONFIG_BOUNCE
extern int init_emergency_isa_pool(void);
extern void blk_queue_bounce(request_queue_t *q, struct bio **bio);
#else
@@ -637,7 +654,8 @@ extern void blk_requeue_request(request_queue_t *, struct request *);
extern void blk_plug_device(request_queue_t *);
extern int blk_remove_plug(request_queue_t *);
extern void blk_recount_segments(request_queue_t *, struct bio *);
-extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
+extern int scsi_cmd_ioctl(struct file *, struct request_queue *,
+ struct gendisk *, unsigned int, void __user *);
extern int sg_scsi_ioctl(struct file *, struct request_queue *,
struct gendisk *, struct scsi_ioctl_command __user *);
@@ -680,6 +698,7 @@ extern int blk_execute_rq(request_queue_t *, struct gendisk *,
struct request *, int);
extern void blk_execute_rq_nowait(request_queue_t *, struct gendisk *,
struct request *, int, rq_end_io_fn *);
+extern int blk_verify_command(unsigned char *, int);
static inline request_queue_t *bdev_get_queue(struct block_device *bdev)
{
diff --git a/include/linux/bsg.h b/include/linux/bsg.h
new file mode 100644
index 000000000000..f415f89e0ac8
--- /dev/null
+++ b/include/linux/bsg.h
@@ -0,0 +1,69 @@
+#ifndef BSG_H
+#define BSG_H
+
+#define BSG_PROTOCOL_SCSI 0
+
+#define BSG_SUB_PROTOCOL_SCSI_CMD 0
+#define BSG_SUB_PROTOCOL_SCSI_TMF 1
+#define BSG_SUB_PROTOCOL_SCSI_TRANSPORT 2
+
+struct sg_io_v4 {
+ __s32 guard; /* [i] 'Q' to differentiate from v3 */
+ __u32 protocol; /* [i] 0 -> SCSI , .... */
+ __u32 subprotocol; /* [i] 0 -> SCSI command, 1 -> SCSI task
+ management function, .... */
+
+ __u32 request_len; /* [i] in bytes */
+ __u64 request; /* [i], [*i] {SCSI: cdb} */
+ __u32 request_attr; /* [i] {SCSI: task attribute} */
+ __u32 request_tag; /* [i] {SCSI: task tag (only if flagged)} */
+ __u32 request_priority; /* [i] {SCSI: task priority} */
+ __u32 max_response_len; /* [i] in bytes */
+ __u64 response; /* [i], [*o] {SCSI: (auto)sense data} */
+
+ /* "din_" for data in (from device); "dout_" for data out (to device) */
+ __u32 dout_xfer_len; /* [i] bytes to be transferred to device */
+ __u32 din_xfer_len; /* [i] bytes to be transferred from device */
+ __u64 dout_xferp; /* [i], [*i] */
+ __u64 din_xferp; /* [i], [*o] */
+
+ __u32 timeout; /* [i] units: millisecond */
+ __u32 flags; /* [i] bit mask */
+ __u64 usr_ptr; /* [i->o] unused internally */
+ __u32 spare_in; /* [i] */
+
+ __u32 driver_status; /* [o] 0 -> ok */
+ __u32 transport_status; /* [o] 0 -> ok */
+ __u32 device_status; /* [o] {SCSI: command completion status} */
+ __u32 retry_delay; /* [o] {SCSI: status auxiliary information} */
+ __u32 info; /* [o] additional information */
+ __u32 duration; /* [o] time to complete, in milliseconds */
+ __u32 response_len; /* [o] bytes of response actually written */
+ __s32 din_resid; /* [o] actual_din_xfer_len - din_xfer_len */
+ __u32 generated_tag; /* [o] {SCSI: task tag that transport chose} */
+ __u32 spare_out; /* [o] */
+
+ __u32 padding;
+};
+
+#ifdef __KERNEL__
+
+#if defined(CONFIG_BLK_DEV_BSG)
+struct bsg_class_device {
+ struct class_device *class_dev;
+ struct device *dev;
+ int minor;
+ struct list_head list;
+ struct request_queue *queue;
+};
+
+extern int bsg_register_queue(struct request_queue *, struct device *, const char *);
+extern void bsg_unregister_queue(struct request_queue *);
+#else
+#define bsg_register_queue(disk, dev, name) (0)
+#define bsg_unregister_queue(disk) do { } while (0)
+#endif
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 5c6e12853a9b..35cadad84b14 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -209,6 +209,8 @@ int cont_prepare_write(struct page*, unsigned, unsigned, get_block_t*,
int generic_cont_expand(struct inode *inode, loff_t size);
int generic_cont_expand_simple(struct inode *inode, loff_t size);
int block_commit_write(struct page *page, unsigned from, unsigned to);
+int block_page_mkwrite(struct vm_area_struct *vma, struct page *page,
+ get_block_t get_block);
void block_sync_page(struct page *);
sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 42aa0a54b6f4..54398d2c6d8d 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -10,6 +10,8 @@ enum bug_trap_type {
BUG_TRAP_TYPE_BUG = 2,
};
+struct pt_regs;
+
#ifdef CONFIG_GENERIC_BUG
#include <asm-generic/bug.h>
@@ -20,7 +22,7 @@ static inline int is_warning_bug(const struct bug_entry *bug)
const struct bug_entry *find_bug(unsigned long bugaddr);
-enum bug_trap_type report_bug(unsigned long bug_addr);
+enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs);
int module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *,
struct module *);
@@ -31,7 +33,8 @@ int is_valid_bugaddr(unsigned long addr);
#else /* !CONFIG_GENERIC_BUG */
-static inline enum bug_trap_type report_bug(unsigned long bug_addr)
+static inline enum bug_trap_type report_bug(unsigned long bug_addr,
+ struct pt_regs *regs)
{
return BUG_TRAP_TYPE_BUG;
}
diff --git a/include/linux/capability.h b/include/linux/capability.h
index bbf8df7de28f..2dfa58555934 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -44,7 +44,6 @@ typedef struct __user_cap_data_struct {
#ifdef __KERNEL__
-#include <linux/spinlock.h>
#include <asm/current.h>
/* #define STRICT_CAP_T_TYPECHECKS */
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
index f50f04bdbc16..2b641b176e7f 100644
--- a/include/linux/cdrom.h
+++ b/include/linux/cdrom.h
@@ -414,8 +414,8 @@ struct cdrom_generic_command
#define CDO_CHECK_TYPE 0x10 /* check type on open for data */
/* Special codes used when specifying changer slots. */
-#define CDSL_NONE ((int) (~0U>>1)-1)
-#define CDSL_CURRENT ((int) (~0U>>1))
+#define CDSL_NONE (INT_MAX-1)
+#define CDSL_CURRENT INT_MAX
/* For partition based multisession access. IDE can handle 64 partitions
* per drive - SCSI CD-ROM's use minors to differentiate between the
diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h
index 8486e78f7335..e0bd46eb2414 100644
--- a/include/linux/clockchips.h
+++ b/include/linux/clockchips.h
@@ -23,6 +23,7 @@ enum clock_event_mode {
CLOCK_EVT_MODE_SHUTDOWN,
CLOCK_EVT_MODE_PERIODIC,
CLOCK_EVT_MODE_ONESHOT,
+ CLOCK_EVT_MODE_RESUME,
};
/* Clock event notification values */
@@ -119,10 +120,6 @@ extern void clockevents_register_device(struct clock_event_device *dev);
extern void clockevents_exchange_device(struct clock_event_device *old,
struct clock_event_device *new);
-extern
-struct clock_event_device *clockevents_request_device(unsigned int features,
- cpumask_t cpumask);
-extern void clockevents_release_device(struct clock_event_device *dev);
extern void clockevents_set_mode(struct clock_event_device *dev,
enum clock_event_mode mode);
extern int clockevents_register_notifier(struct notifier_block *nb);
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index bf297b03a4e4..16ea3374dddf 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -67,6 +67,12 @@ struct clocksource {
unsigned long flags;
cycle_t (*vread)(void);
void (*resume)(void);
+#ifdef CONFIG_IA64
+ void *fsys_mmio; /* used by fsyscall asm code */
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr) ((mmio) = (addr))
+#else
+#define CLKSRC_FSYS_MMIO_SET(mmio, addr) do { } while (0)
+#endif
/* timekeeping specific data, ignore */
cycle_t cycle_interval;
diff --git a/include/linux/cobalt-nvram.h b/include/linux/cobalt-nvram.h
deleted file mode 100644
index ea429562ff36..000000000000
--- a/include/linux/cobalt-nvram.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * $Id: cobalt-nvram.h,v 1.20 2001/10/17 23:16:55 thockin Exp $
- * cobalt-nvram.h : defines for the various fields in the cobalt NVRAM
- *
- * Copyright 2001,2002 Sun Microsystems, Inc.
- */
-
-#ifndef COBALT_NVRAM_H
-#define COBALT_NVRAM_H
-
-#include <linux/nvram.h>
-
-#define COBT_CMOS_INFO_MAX 0x7f /* top address allowed */
-#define COBT_CMOS_BIOS_DRIVE_INFO 0x12 /* drive info would go here */
-
-#define COBT_CMOS_CKS_START NVRAM_OFFSET(0x0e)
-#define COBT_CMOS_CKS_END NVRAM_OFFSET(0x7f)
-
-/* flag bytes - 16 flags for now, leave room for more */
-#define COBT_CMOS_FLAG_BYTE_0 NVRAM_OFFSET(0x10)
-#define COBT_CMOS_FLAG_BYTE_1 NVRAM_OFFSET(0x11)
-
-/* flags in flag bytes - up to 16 */
-#define COBT_CMOS_FLAG_MIN 0x0001
-#define COBT_CMOS_CONSOLE_FLAG 0x0001 /* console on/off */
-#define COBT_CMOS_DEBUG_FLAG 0x0002 /* ROM debug messages */
-#define COBT_CMOS_AUTO_PROMPT_FLAG 0x0004 /* boot to ROM prompt? */
-#define COBT_CMOS_CLEAN_BOOT_FLAG 0x0008 /* set by a clean shutdown */
-#define COBT_CMOS_HW_NOPROBE_FLAG 0x0010 /* go easy on the probing */
-#define COBT_CMOS_SYSFAULT_FLAG 0x0020 /* system fault detected */
-#define COBT_CMOS_OOPSPANIC_FLAG 0x0040 /* panic on oops */
-#define COBT_CMOS_DELAY_CACHE_FLAG 0x0080 /* delay cache initialization */
-#define COBT_CMOS_NOLOGO_FLAG 0x0100 /* hide "C" logo @ boot */
-#define COBT_CMOS_VERSION_FLAG 0x0200 /* the version field is valid */
-#define COBT_CMOS_FLAG_MAX 0x0200
-
-/* leave byte 0x12 blank - Linux looks for drive info here */
-
-/* CMOS structure version, valid if COBT_CMOS_VERSION_FLAG is true */
-#define COBT_CMOS_VERSION NVRAM_OFFSET(0x13)
-#define COBT_CMOS_VER_BTOCODE 1 /* min. version needed for btocode */
-
-/* index of default boot method */
-#define COBT_CMOS_BOOT_METHOD NVRAM_OFFSET(0x20)
-#define COBT_CMOS_BOOT_METHOD_DISK 0
-#define COBT_CMOS_BOOT_METHOD_ROM 1
-#define COBT_CMOS_BOOT_METHOD_NET 2
-
-#define COBT_CMOS_BOOT_DEV_MIN NVRAM_OFFSET(0x21)
-/* major #, minor # of first through fourth boot device */
-#define COBT_CMOS_BOOT_DEV0_MAJ NVRAM_OFFSET(0x21)
-#define COBT_CMOS_BOOT_DEV0_MIN NVRAM_OFFSET(0x22)
-#define COBT_CMOS_BOOT_DEV1_MAJ NVRAM_OFFSET(0x23)
-#define COBT_CMOS_BOOT_DEV1_MIN NVRAM_OFFSET(0x24)
-#define COBT_CMOS_BOOT_DEV2_MAJ NVRAM_OFFSET(0x25)
-#define COBT_CMOS_BOOT_DEV2_MIN NVRAM_OFFSET(0x26)
-#define COBT_CMOS_BOOT_DEV3_MAJ NVRAM_OFFSET(0x27)
-#define COBT_CMOS_BOOT_DEV3_MIN NVRAM_OFFSET(0x28)
-#define COBT_CMOS_BOOT_DEV_MAX NVRAM_OFFSET(0x28)
-
-/* checksum of bytes 0xe-0x7f */
-#define COBT_CMOS_CHECKSUM NVRAM_OFFSET(0x2e)
-
-/* running uptime counter, units of 5 minutes (32 bits =~ 41000 years) */
-#define COBT_CMOS_UPTIME_0 NVRAM_OFFSET(0x30)
-#define COBT_CMOS_UPTIME_1 NVRAM_OFFSET(0x31)
-#define COBT_CMOS_UPTIME_2 NVRAM_OFFSET(0x32)
-#define COBT_CMOS_UPTIME_3 NVRAM_OFFSET(0x33)
-
-/* count of successful boots (32 bits) */
-#define COBT_CMOS_BOOTCOUNT_0 NVRAM_OFFSET(0x38)
-#define COBT_CMOS_BOOTCOUNT_1 NVRAM_OFFSET(0x39)
-#define COBT_CMOS_BOOTCOUNT_2 NVRAM_OFFSET(0x3a)
-#define COBT_CMOS_BOOTCOUNT_3 NVRAM_OFFSET(0x3b)
-
-/* 13 bytes: system serial number, same as on the back of the system */
-#define COBT_CMOS_SYS_SERNUM_LEN 13
-#define COBT_CMOS_SYS_SERNUM_0 NVRAM_OFFSET(0x40)
-#define COBT_CMOS_SYS_SERNUM_1 NVRAM_OFFSET(0x41)
-#define COBT_CMOS_SYS_SERNUM_2 NVRAM_OFFSET(0x42)
-#define COBT_CMOS_SYS_SERNUM_3 NVRAM_OFFSET(0x43)
-#define COBT_CMOS_SYS_SERNUM_4 NVRAM_OFFSET(0x44)
-#define COBT_CMOS_SYS_SERNUM_5 NVRAM_OFFSET(0x45)
-#define COBT_CMOS_SYS_SERNUM_6 NVRAM_OFFSET(0x46)
-#define COBT_CMOS_SYS_SERNUM_7 NVRAM_OFFSET(0x47)
-#define COBT_CMOS_SYS_SERNUM_8 NVRAM_OFFSET(0x48)
-#define COBT_CMOS_SYS_SERNUM_9 NVRAM_OFFSET(0x49)
-#define COBT_CMOS_SYS_SERNUM_10 NVRAM_OFFSET(0x4a)
-#define COBT_CMOS_SYS_SERNUM_11 NVRAM_OFFSET(0x4b)
-#define COBT_CMOS_SYS_SERNUM_12 NVRAM_OFFSET(0x4c)
-/* checksum for serial num - 1 byte */
-#define COBT_CMOS_SYS_SERNUM_CSUM NVRAM_OFFSET(0x4f)
-
-#define COBT_CMOS_ROM_REV_MAJ NVRAM_OFFSET(0x50)
-#define COBT_CMOS_ROM_REV_MIN NVRAM_OFFSET(0x51)
-#define COBT_CMOS_ROM_REV_REV NVRAM_OFFSET(0x52)
-
-#define COBT_CMOS_BTO_CODE_0 NVRAM_OFFSET(0x53)
-#define COBT_CMOS_BTO_CODE_1 NVRAM_OFFSET(0x54)
-#define COBT_CMOS_BTO_CODE_2 NVRAM_OFFSET(0x55)
-#define COBT_CMOS_BTO_CODE_3 NVRAM_OFFSET(0x56)
-
-#define COBT_CMOS_BTO_IP_CSUM NVRAM_OFFSET(0x57)
-#define COBT_CMOS_BTO_IP_0 NVRAM_OFFSET(0x58)
-#define COBT_CMOS_BTO_IP_1 NVRAM_OFFSET(0x59)
-#define COBT_CMOS_BTO_IP_2 NVRAM_OFFSET(0x5a)
-#define COBT_CMOS_BTO_IP_3 NVRAM_OFFSET(0x5b)
-
-#endif /* COBALT_NVRAM_H */
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index e4ac016ad272..1c47a34aa794 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -36,16 +36,12 @@ extern const struct file_operations coda_ioctl_operations;
/* operations shared over more than one file */
int coda_open(struct inode *i, struct file *f);
-int coda_flush(struct file *f, fl_owner_t id);
int coda_release(struct inode *i, struct file *f);
int coda_permission(struct inode *inode, int mask, struct nameidata *nd);
int coda_revalidate_inode(struct dentry *);
int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *);
int coda_setattr(struct dentry *, struct iattr *);
-/* global variables */
-extern int coda_fake_statfs;
-
/* this file: heloers */
static __inline__ struct CodaFid *coda_i2f(struct inode *);
static __inline__ char *coda_i2s(struct inode *);
diff --git a/include/linux/coda_proc.h b/include/linux/coda_proc.h
deleted file mode 100644
index 0dc1b0458e75..000000000000
--- a/include/linux/coda_proc.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * coda_statis.h
- *
- * CODA operation statistics
- *
- * (c) March, 1998
- * by Michihiro Kuramochi, Zhenyu Xia and Zhanyong Wan
- * zhanyong.wan@yale.edu
- *
- */
-
-#ifndef _CODA_PROC_H
-#define _CODA_PROC_H
-
-void coda_sysctl_init(void);
-void coda_sysctl_clean(void);
-
-#include <linux/sysctl.h>
-#include <linux/coda_fs_i.h>
-#include <linux/coda.h>
-
-/* these four files are presented to show the result of the statistics:
- *
- * /proc/fs/coda/vfs_stats
- * cache_inv_stats
- *
- * these four files are presented to reset the statistics to 0:
- *
- * /proc/sys/coda/vfs_stats
- * cache_inv_stats
- */
-
-/* VFS operation statistics */
-struct coda_vfs_stats
-{
- /* file operations */
- int open;
- int flush;
- int release;
- int fsync;
-
- /* dir operations */
- int readdir;
-
- /* inode operations */
- int create;
- int lookup;
- int link;
- int unlink;
- int symlink;
- int mkdir;
- int rmdir;
- int rename;
- int permission;
-
- /* symlink operatoins*/
- int follow_link;
- int readlink;
-};
-
-/* cache invalidation statistics */
-struct coda_cache_inv_stats
-{
- int flush;
- int purge_user;
- int zap_dir;
- int zap_file;
- int zap_vnode;
- int purge_fid;
- int replace;
-};
-
-/* these global variables hold the actual statistics data */
-extern struct coda_vfs_stats coda_vfs_stat;
-
-#endif /* _CODA_PROC_H */
diff --git a/include/linux/coda_psdev.h b/include/linux/coda_psdev.h
index b541bb3d1f4b..07ae8f846055 100644
--- a/include/linux/coda_psdev.h
+++ b/include/linux/coda_psdev.h
@@ -8,11 +8,6 @@
struct kstatfs;
-struct coda_sb_info
-{
- struct venus_comm *sbi_vcomm;
-};
-
/* communication pending/processing queues */
struct venus_comm {
u_long vc_seq;
@@ -24,9 +19,9 @@ struct venus_comm {
};
-static inline struct coda_sb_info *coda_sbp(struct super_block *sb)
+static inline struct venus_comm *coda_vcp(struct super_block *sb)
{
- return ((struct coda_sb_info *)((sb)->s_fs_info));
+ return (struct venus_comm *)((sb)->s_fs_info);
}
@@ -38,9 +33,6 @@ int venus_setattr(struct super_block *, struct CodaFid *, struct coda_vattr *);
int venus_lookup(struct super_block *sb, struct CodaFid *fid,
const char *name, int length, int *type,
struct CodaFid *resfid);
-int venus_store(struct super_block *sb, struct CodaFid *fid, int flags,
- vuid_t uid);
-int venus_release(struct super_block *sb, struct CodaFid *fid, int flags);
int venus_close(struct super_block *sb, struct CodaFid *fid, int flags,
vuid_t uid);
int venus_open(struct super_block *sb, struct CodaFid *fid, int flags,
@@ -74,8 +66,6 @@ int venus_statfs(struct dentry *dentry, struct kstatfs *sfs);
/* messages between coda filesystem in kernel and Venus */
-extern int coda_hard;
-extern unsigned long coda_timeout;
struct upc_req {
struct list_head uc_chain;
caddr_t uc_data;
@@ -85,7 +75,6 @@ struct upc_req {
u_short uc_opcode; /* copied from data to save lookup */
int uc_unique;
wait_queue_head_t uc_sleep; /* process' wait queue */
- unsigned long uc_posttime;
};
#define REQ_ASYNC 0x1
diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
index a03e9398a6c2..14f7494280f0 100644
--- a/include/linux/compiler-gcc4.h
+++ b/include/linux/compiler-gcc4.h
@@ -23,3 +23,21 @@
* code
*/
#define uninitialized_var(x) x = x
+
+#if !(__GNUC__ == 4 && __GNUC_MINOR__ < 3)
+/* Mark functions as cold. gcc will assume any path leading to a call
+ to them will be unlikely. This means a lot of manual unlikely()s
+ are unnecessary now for any paths leading to the usual suspects
+ like BUG(), printk(), panic() etc. [but let's keep them for now for
+ older compilers]
+
+ Early snapshots of gcc 4.3 don't support this and we can't detect this
+ in the preprocessor, but we can live with this because they're unreleased.
+ Maketime probing would be overkill here.
+
+ gcc also has a __attribute__((__hot__)) to move hot functions into
+ a special section, but I don't see any sense in this right now in
+ the kernel context */
+#define __cold __attribute__((__cold__))
+
+#endif
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 8287a72bb6a9..12a1291855e2 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -174,4 +174,13 @@ extern void __chk_io_ptr(const void __iomem *);
# define __attribute_const__ /* unimplemented */
#endif
+/*
+ * Tell gcc if a function is cold. The compiler will assume any path
+ * directly leading to the call is unlikely.
+ */
+
+#ifndef __cold
+#define __cold
+#endif
+
#endif /* __LINUX_COMPILER_H */
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index fef6f3d0a4a7..8c6967f3fb11 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -40,9 +40,9 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/kref.h>
+#include <linux/mutex.h>
#include <asm/atomic.h>
-#include <asm/semaphore.h>
#define CONFIGFS_ITEM_NAME_LEN 20
@@ -75,7 +75,6 @@ extern void config_item_init(struct config_item *);
extern void config_item_init_type_name(struct config_item *item,
const char *name,
struct config_item_type *type);
-extern void config_item_cleanup(struct config_item *);
extern struct config_item * config_item_get(struct config_item *);
extern void config_item_put(struct config_item *);
@@ -87,12 +86,10 @@ struct config_item_type {
struct configfs_attribute **ct_attrs;
};
-
/**
* group - a group of config_items of a specific type, belonging
* to a specific subsystem.
*/
-
struct config_group {
struct config_item cg_item;
struct list_head cg_children;
@@ -100,13 +97,11 @@ struct config_group {
struct config_group **default_groups;
};
-
extern void config_group_init(struct config_group *group);
extern void config_group_init_type_name(struct config_group *group,
const char *name,
struct config_item_type *type);
-
static inline struct config_group *to_config_group(struct config_item *item)
{
return item ? container_of(item,struct config_group,cg_item) : NULL;
@@ -122,7 +117,8 @@ static inline void config_group_put(struct config_group *group)
config_item_put(&group->cg_item);
}
-extern struct config_item *config_group_find_obj(struct config_group *, const char *);
+extern struct config_item *config_group_find_item(struct config_group *,
+ const char *);
struct configfs_attribute {
@@ -131,6 +127,22 @@ struct configfs_attribute {
mode_t ca_mode;
};
+/*
+ * Users often need to create attribute structures for their configurable
+ * attributes, containing a configfs_attribute member and function pointers
+ * for the show() and store() operations on that attribute. They can use
+ * this macro (similar to sysfs' __ATTR) to make defining attributes easier.
+ */
+#define __CONFIGFS_ATTR(_name, _mode, _show, _store) \
+{ \
+ .attr = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = _mode, \
+ .ca_owner = THIS_MODULE, \
+ }, \
+ .show = _show, \
+ .store = _store, \
+}
/*
* If allow_link() exists, the item can symlink(2) out to other
@@ -157,12 +169,13 @@ struct configfs_group_operations {
struct config_item *(*make_item)(struct config_group *group, const char *name);
struct config_group *(*make_group)(struct config_group *group, const char *name);
int (*commit_item)(struct config_item *item);
+ void (*disconnect_notify)(struct config_group *group, struct config_item *item);
void (*drop_item)(struct config_group *group, struct config_item *item);
};
struct configfs_subsystem {
struct config_group su_group;
- struct semaphore su_sem;
+ struct mutex su_mutex;
};
static inline struct configfs_subsystem *to_configfs_subsystem(struct config_group *group)
@@ -175,6 +188,11 @@ static inline struct configfs_subsystem *to_configfs_subsystem(struct config_gro
int configfs_register_subsystem(struct configfs_subsystem *subsys);
void configfs_unregister_subsystem(struct configfs_subsystem *subsys);
+/* These functions can sleep and can alloc with GFP_KERNEL */
+/* WARNING: These cannot be called underneath configfs callbacks!! */
+int configfs_depend_item(struct configfs_subsystem *subsys, struct config_item *target);
+void configfs_undepend_item(struct configfs_subsystem *subsys, struct config_item *target);
+
#endif /* __KERNEL__ */
#endif /* _CONFIGFS_H_ */
diff --git a/include/linux/console.h b/include/linux/console.h
index 62ef6e11d0d2..56a7bcda49cb 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -15,7 +15,6 @@
#define _LINUX_CONSOLE_H_ 1
#include <linux/types.h>
-#include <linux/spinlock.h>
struct vc_data;
struct console_font_op;
@@ -99,6 +98,7 @@ struct console {
struct tty_driver *(*device)(struct console *, int *);
void (*unblank)(void);
int (*setup)(struct console *, char *);
+ int (*early_setup)(void);
short flags;
short index;
int cflag;
@@ -107,6 +107,7 @@ struct console {
};
extern int add_preferred_console(char *name, int idx, char *options);
+extern int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options);
extern void register_console(struct console *);
extern int unregister_console(struct console *);
extern struct console *console_drivers;
diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h
index 82c9a1f11020..06b2768c603f 100644
--- a/include/linux/consolemap.h
+++ b/include/linux/consolemap.h
@@ -8,9 +8,12 @@
#define IBMPC_MAP 2
#define USER_MAP 3
+#include <linux/types.h>
+
struct vc_data;
-extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
+extern u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode);
extern unsigned short *set_translate(int m, struct vc_data *vc);
extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
+extern u32 conv_8bit_to_uni(unsigned char c);
void console_map_init(void);
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 3b2df2523f1d..c2236bbff412 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -120,7 +120,6 @@ static inline void cpuhotplug_mutex_unlock(struct mutex *cpu_hp_mutex)
#define lock_cpu_hotplug() do { } while (0)
#define unlock_cpu_hotplug() do { } while (0)
-#define lock_cpu_hotplug_interruptible() 0
#define hotcpu_notifier(fn, pri) do { (void)(fn); } while (0)
#define register_hotcpu_notifier(nb) do { (void)(nb); } while (0)
#define unregister_hotcpu_notifier(nb) do { (void)(nb); } while (0)
diff --git a/include/linux/crc7.h b/include/linux/crc7.h
new file mode 100644
index 000000000000..1786e772d5c6
--- /dev/null
+++ b/include/linux/crc7.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_CRC7_H
+#define _LINUX_CRC7_H
+#include <linux/types.h>
+
+extern const u8 crc7_syndrome_table[256];
+
+static inline u8 crc7_byte(u8 crc, u8 data)
+{
+ return crc7_syndrome_table[(crc << 1) ^ data];
+}
+
+extern u8 crc7(u8 crc, const u8 *buffer, size_t len);
+
+#endif
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 0de7e2ace822..357e8cfedc37 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -295,28 +295,8 @@ struct blkcipher_tfm {
};
struct cipher_tfm {
- void *cit_iv;
- unsigned int cit_ivsize;
- u32 cit_mode;
int (*cit_setkey)(struct crypto_tfm *tfm,
const u8 *key, unsigned int keylen);
- int (*cit_encrypt)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
- int (*cit_encrypt_iv)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv);
- int (*cit_decrypt)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes);
- int (*cit_decrypt_iv)(struct crypto_tfm *tfm,
- struct scatterlist *dst,
- struct scatterlist *src,
- unsigned int nbytes, u8 *iv);
- void (*cit_xor_block)(u8 *dst, const u8 *src);
void (*cit_encrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
void (*cit_decrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src);
};
diff --git a/include/linux/dcookies.h b/include/linux/dcookies.h
index 0fe7cdf326f7..98c69ab80c84 100644
--- a/include/linux/dcookies.h
+++ b/include/linux/dcookies.h
@@ -12,6 +12,7 @@
#ifdef CONFIG_PROFILING
+#include <linux/dcache.h>
#include <linux/types.h>
struct dcookie_user;
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 5a9c49534d08..104e51e20e14 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -38,6 +38,9 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
void debugfs_remove(struct dentry *dentry);
+struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
+ struct dentry *new_dir, const char *new_name);
+
struct dentry *debugfs_create_u8(const char *name, mode_t mode,
struct dentry *parent, u8 *value);
struct dentry *debugfs_create_u16(const char *name, mode_t mode,
@@ -85,6 +88,12 @@ static inline struct dentry *debugfs_create_symlink(const char *name,
static inline void debugfs_remove(struct dentry *dentry)
{ }
+static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
+ struct dentry *new_dir, char *new_name)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline struct dentry *debugfs_create_u8(const char *name, mode_t mode,
struct dentry *parent,
u8 *value)
diff --git a/include/linux/device.h b/include/linux/device.h
index 2e1a2988b7e1..d9f0a57f5a2f 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -238,7 +238,6 @@ extern int __must_check class_device_create_file(struct class_device *,
* @devt: for internal use by the driver core only.
* @node: for internal use by the driver core only.
* @kobj: for internal use by the driver core only.
- * @devt_attr: for internal use by the driver core only.
* @groups: optional additional groups to be created
* @dev: if set, a symlink to the struct device is created in the sysfs
* directory for this struct class device.
@@ -263,8 +262,6 @@ struct class_device {
struct kobject kobj;
struct class * class; /* required */
dev_t devt; /* dev_t, creates the sysfs "dev" */
- struct class_device_attribute *devt_attr;
- struct class_device_attribute uevent_attr;
struct device * dev; /* not necessary, but nice to have */
void * class_data; /* class-specific data */
struct class_device *parent; /* parent of this child device, if there is one */
@@ -419,8 +416,6 @@ struct device {
struct device_type *type;
unsigned is_registered:1;
unsigned uevent_suppress:1;
- struct device_attribute uevent_attr;
- struct device_attribute *devt_attr;
struct semaphore sem; /* semaphore to synchronize calls to
* its driver.
@@ -577,6 +572,16 @@ dev_dbg(struct device * dev, const char * fmt, ...)
}
#endif
+#ifdef VERBOSE_DEBUG
+#define dev_vdbg dev_dbg
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+dev_vdbg(struct device * dev, const char * fmt, ...)
+{
+ return 0;
+}
+#endif
+
#define dev_err(dev, format, arg...) \
dev_printk(KERN_ERR , dev , format , ## arg)
#define dev_info(dev, format, arg...) \
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 9a663c6db16a..2dc21cbeb304 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -31,7 +31,11 @@ static inline int valid_dma_direction(int dma_direction)
(dma_direction == DMA_FROM_DEVICE));
}
+#ifdef CONFIG_HAS_DMA
#include <asm/dma-mapping.h>
+#else
+#include <asm-generic/dma-mapping-broken.h>
+#endif
/* Backwards compat, remove in 2.7.x */
#define dma_sync_single dma_sync_single_for_cpu
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c94d8f1d62e5..a3b6035b6c86 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -21,29 +21,40 @@
#ifndef DMAENGINE_H
#define DMAENGINE_H
-#ifdef CONFIG_DMA_ENGINE
-
#include <linux/device.h>
#include <linux/uio.h>
#include <linux/kref.h>
#include <linux/completion.h>
#include <linux/rcupdate.h>
+#include <linux/dma-mapping.h>
/**
- * enum dma_event - resource PNP/power managment events
+ * enum dma_state - resource PNP/power managment state
* @DMA_RESOURCE_SUSPEND: DMA device going into low power state
* @DMA_RESOURCE_RESUME: DMA device returning to full power
- * @DMA_RESOURCE_ADDED: DMA device added to the system
+ * @DMA_RESOURCE_AVAILABLE: DMA device available to the system
* @DMA_RESOURCE_REMOVED: DMA device removed from the system
*/
-enum dma_event {
+enum dma_state {
DMA_RESOURCE_SUSPEND,
DMA_RESOURCE_RESUME,
- DMA_RESOURCE_ADDED,
+ DMA_RESOURCE_AVAILABLE,
DMA_RESOURCE_REMOVED,
};
/**
+ * enum dma_state_client - state of the channel in the client
+ * @DMA_ACK: client would like to use, or was using this channel
+ * @DMA_DUP: client has already seen this channel, or is not using this channel
+ * @DMA_NAK: client does not want to see any more channels
+ */
+enum dma_state_client {
+ DMA_ACK,
+ DMA_DUP,
+ DMA_NAK,
+};
+
+/**
* typedef dma_cookie_t - an opaque DMA cookie
*
* if dma_cookie_t is >0 it's a DMA request cookie, <0 it's an error code
@@ -65,6 +76,31 @@ enum dma_status {
};
/**
+ * enum dma_transaction_type - DMA transaction types/indexes
+ */
+enum dma_transaction_type {
+ DMA_MEMCPY,
+ DMA_XOR,
+ DMA_PQ_XOR,
+ DMA_DUAL_XOR,
+ DMA_PQ_UPDATE,
+ DMA_ZERO_SUM,
+ DMA_PQ_ZERO_SUM,
+ DMA_MEMSET,
+ DMA_MEMCPY_CRC32C,
+ DMA_INTERRUPT,
+};
+
+/* last transaction type for creation of the capabilities mask */
+#define DMA_TX_TYPE_END (DMA_INTERRUPT + 1)
+
+/**
+ * dma_cap_mask_t - capabilities bitmap modeled after cpumask_t.
+ * See linux/cpumask.h
+ */
+typedef struct { DECLARE_BITMAP(bits, DMA_TX_TYPE_END); } dma_cap_mask_t;
+
+/**
* struct dma_chan_percpu - the per-CPU part of struct dma_chan
* @refcount: local_t used for open-coded "bigref" counting
* @memcpy_count: transaction counter
@@ -80,7 +116,6 @@ struct dma_chan_percpu {
/**
* struct dma_chan - devices supply DMA channels, clients use them
- * @client: ptr to the client user of this chan, will be %NULL when unused
* @device: ptr to the dma device who supplies this channel, always !%NULL
* @cookie: last cookie value returned to client
* @chan_id: channel ID for sysfs
@@ -88,12 +123,10 @@ struct dma_chan_percpu {
* @refcount: kref, used in "bigref" slow-mode
* @slow_ref: indicates that the DMA channel is free
* @rcu: the DMA channel's RCU head
- * @client_node: used to add this to the client chan list
* @device_node: used to add this to the device chan list
* @local: per-cpu pointer to a struct dma_chan_percpu
*/
struct dma_chan {
- struct dma_client *client;
struct dma_device *device;
dma_cookie_t cookie;
@@ -105,11 +138,11 @@ struct dma_chan {
int slow_ref;
struct rcu_head rcu;
- struct list_head client_node;
struct list_head device_node;
struct dma_chan_percpu *local;
};
+
void dma_chan_cleanup(struct kref *kref);
static inline void dma_chan_get(struct dma_chan *chan)
@@ -134,169 +167,206 @@ static inline void dma_chan_put(struct dma_chan *chan)
/*
* typedef dma_event_callback - function pointer to a DMA event callback
+ * For each channel added to the system this routine is called for each client.
+ * If the client would like to use the channel it returns '1' to signal (ack)
+ * the dmaengine core to take out a reference on the channel and its
+ * corresponding device. A client must not 'ack' an available channel more
+ * than once. When a channel is removed all clients are notified. If a client
+ * is using the channel it must 'ack' the removal. A client must not 'ack' a
+ * removed channel more than once.
+ * @client - 'this' pointer for the client context
+ * @chan - channel to be acted upon
+ * @state - available or removed
*/
-typedef void (*dma_event_callback) (struct dma_client *client,
- struct dma_chan *chan, enum dma_event event);
+struct dma_client;
+typedef enum dma_state_client (*dma_event_callback) (struct dma_client *client,
+ struct dma_chan *chan, enum dma_state state);
/**
* struct dma_client - info on the entity making use of DMA services
* @event_callback: func ptr to call when something happens
- * @chan_count: number of chans allocated
- * @chans_desired: number of chans requested. Can be +/- chan_count
- * @lock: protects access to the channels list
- * @channels: the list of DMA channels allocated
+ * @cap_mask: only return channels that satisfy the requested capabilities
+ * a value of zero corresponds to any capability
* @global_node: list_head for global dma_client_list
*/
struct dma_client {
dma_event_callback event_callback;
- unsigned int chan_count;
- unsigned int chans_desired;
-
- spinlock_t lock;
- struct list_head channels;
+ dma_cap_mask_t cap_mask;
struct list_head global_node;
};
+typedef void (*dma_async_tx_callback)(void *dma_async_param);
+/**
+ * struct dma_async_tx_descriptor - async transaction descriptor
+ * ---dma generic offload fields---
+ * @cookie: tracking cookie for this transaction, set to -EBUSY if
+ * this tx is sitting on a dependency list
+ * @ack: the descriptor can not be reused until the client acknowledges
+ * receipt, i.e. has has a chance to establish any dependency chains
+ * @phys: physical address of the descriptor
+ * @tx_list: driver common field for operations that require multiple
+ * descriptors
+ * @chan: target channel for this operation
+ * @tx_submit: set the prepared descriptor(s) to be executed by the engine
+ * @tx_set_dest: set a destination address in a hardware descriptor
+ * @tx_set_src: set a source address in a hardware descriptor
+ * @callback: routine to call after this operation is complete
+ * @callback_param: general parameter to pass to the callback routine
+ * ---async_tx api specific fields---
+ * @depend_list: at completion this list of transactions are submitted
+ * @depend_node: allow this transaction to be executed after another
+ * transaction has completed, possibly on another channel
+ * @parent: pointer to the next level up in the dependency chain
+ * @lock: protect the dependency list
+ */
+struct dma_async_tx_descriptor {
+ dma_cookie_t cookie;
+ int ack;
+ dma_addr_t phys;
+ struct list_head tx_list;
+ struct dma_chan *chan;
+ dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
+ void (*tx_set_dest)(dma_addr_t addr,
+ struct dma_async_tx_descriptor *tx, int index);
+ void (*tx_set_src)(dma_addr_t addr,
+ struct dma_async_tx_descriptor *tx, int index);
+ dma_async_tx_callback callback;
+ void *callback_param;
+ struct list_head depend_list;
+ struct list_head depend_node;
+ struct dma_async_tx_descriptor *parent;
+ spinlock_t lock;
+};
+
/**
* struct dma_device - info on the entity supplying DMA services
* @chancnt: how many DMA channels are supported
* @channels: the list of struct dma_chan
* @global_node: list_head for global dma_device_list
+ * @cap_mask: one or more dma_capability flags
+ * @max_xor: maximum number of xor sources, 0 if no capability
* @refcount: reference count
* @done: IO completion struct
* @dev_id: unique device ID
+ * @dev: struct device reference for dma mapping api
* @device_alloc_chan_resources: allocate resources and return the
* number of allocated descriptors
* @device_free_chan_resources: release DMA channel's resources
- * @device_memcpy_buf_to_buf: memcpy buf pointer to buf pointer
- * @device_memcpy_buf_to_pg: memcpy buf pointer to struct page
- * @device_memcpy_pg_to_pg: memcpy struct page/offset to struct page/offset
- * @device_memcpy_complete: poll the status of an IOAT DMA transaction
- * @device_memcpy_issue_pending: push appended descriptors to hardware
+ * @device_prep_dma_memcpy: prepares a memcpy operation
+ * @device_prep_dma_xor: prepares a xor operation
+ * @device_prep_dma_zero_sum: prepares a zero_sum operation
+ * @device_prep_dma_memset: prepares a memset operation
+ * @device_prep_dma_interrupt: prepares an end of chain interrupt operation
+ * @device_dependency_added: async_tx notifies the channel about new deps
+ * @device_issue_pending: push pending transactions to hardware
*/
struct dma_device {
unsigned int chancnt;
struct list_head channels;
struct list_head global_node;
+ dma_cap_mask_t cap_mask;
+ int max_xor;
struct kref refcount;
struct completion done;
int dev_id;
+ struct device *dev;
int (*device_alloc_chan_resources)(struct dma_chan *chan);
void (*device_free_chan_resources)(struct dma_chan *chan);
- dma_cookie_t (*device_memcpy_buf_to_buf)(struct dma_chan *chan,
- void *dest, void *src, size_t len);
- dma_cookie_t (*device_memcpy_buf_to_pg)(struct dma_chan *chan,
- struct page *page, unsigned int offset, void *kdata,
- size_t len);
- dma_cookie_t (*device_memcpy_pg_to_pg)(struct dma_chan *chan,
- struct page *dest_pg, unsigned int dest_off,
- struct page *src_pg, unsigned int src_off, size_t len);
- enum dma_status (*device_memcpy_complete)(struct dma_chan *chan,
+
+ struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)(
+ struct dma_chan *chan, size_t len, int int_en);
+ struct dma_async_tx_descriptor *(*device_prep_dma_xor)(
+ struct dma_chan *chan, unsigned int src_cnt, size_t len,
+ int int_en);
+ struct dma_async_tx_descriptor *(*device_prep_dma_zero_sum)(
+ struct dma_chan *chan, unsigned int src_cnt, size_t len,
+ u32 *result, int int_en);
+ struct dma_async_tx_descriptor *(*device_prep_dma_memset)(
+ struct dma_chan *chan, int value, size_t len, int int_en);
+ struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
+ struct dma_chan *chan);
+
+ void (*device_dependency_added)(struct dma_chan *chan);
+ enum dma_status (*device_is_tx_complete)(struct dma_chan *chan,
dma_cookie_t cookie, dma_cookie_t *last,
dma_cookie_t *used);
- void (*device_memcpy_issue_pending)(struct dma_chan *chan);
+ void (*device_issue_pending)(struct dma_chan *chan);
};
/* --- public DMA engine API --- */
-struct dma_client *dma_async_client_register(dma_event_callback event_callback);
+void dma_async_client_register(struct dma_client *client);
void dma_async_client_unregister(struct dma_client *client);
-void dma_async_client_chan_request(struct dma_client *client,
- unsigned int number);
+void dma_async_client_chan_request(struct dma_client *client);
+dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan,
+ void *dest, void *src, size_t len);
+dma_cookie_t dma_async_memcpy_buf_to_pg(struct dma_chan *chan,
+ struct page *page, unsigned int offset, void *kdata, size_t len);
+dma_cookie_t dma_async_memcpy_pg_to_pg(struct dma_chan *chan,
+ struct page *dest_pg, unsigned int dest_off, struct page *src_pg,
+ unsigned int src_off, size_t len);
+void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
+ struct dma_chan *chan);
-/**
- * dma_async_memcpy_buf_to_buf - offloaded copy between virtual addresses
- * @chan: DMA channel to offload copy to
- * @dest: destination address (virtual)
- * @src: source address (virtual)
- * @len: length
- *
- * Both @dest and @src must be mappable to a bus address according to the
- * DMA mapping API rules for streaming mappings.
- * Both @dest and @src must stay memory resident (kernel memory or locked
- * user space pages).
- */
-static inline dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan,
- void *dest, void *src, size_t len)
+static inline void
+async_tx_ack(struct dma_async_tx_descriptor *tx)
{
- int cpu = get_cpu();
- per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
- per_cpu_ptr(chan->local, cpu)->memcpy_count++;
- put_cpu();
-
- return chan->device->device_memcpy_buf_to_buf(chan, dest, src, len);
+ tx->ack = 1;
}
-/**
- * dma_async_memcpy_buf_to_pg - offloaded copy from address to page
- * @chan: DMA channel to offload copy to
- * @page: destination page
- * @offset: offset in page to copy to
- * @kdata: source address (virtual)
- * @len: length
- *
- * Both @page/@offset and @kdata must be mappable to a bus address according
- * to the DMA mapping API rules for streaming mappings.
- * Both @page/@offset and @kdata must stay memory resident (kernel memory or
- * locked user space pages)
- */
-static inline dma_cookie_t dma_async_memcpy_buf_to_pg(struct dma_chan *chan,
- struct page *page, unsigned int offset, void *kdata, size_t len)
+#define first_dma_cap(mask) __first_dma_cap(&(mask))
+static inline int __first_dma_cap(const dma_cap_mask_t *srcp)
{
- int cpu = get_cpu();
- per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
- per_cpu_ptr(chan->local, cpu)->memcpy_count++;
- put_cpu();
+ return min_t(int, DMA_TX_TYPE_END,
+ find_first_bit(srcp->bits, DMA_TX_TYPE_END));
+}
- return chan->device->device_memcpy_buf_to_pg(chan, page, offset,
- kdata, len);
+#define next_dma_cap(n, mask) __next_dma_cap((n), &(mask))
+static inline int __next_dma_cap(int n, const dma_cap_mask_t *srcp)
+{
+ return min_t(int, DMA_TX_TYPE_END,
+ find_next_bit(srcp->bits, DMA_TX_TYPE_END, n+1));
}
-/**
- * dma_async_memcpy_pg_to_pg - offloaded copy from page to page
- * @chan: DMA channel to offload copy to
- * @dest_pg: destination page
- * @dest_off: offset in page to copy to
- * @src_pg: source page
- * @src_off: offset in page to copy from
- * @len: length
- *
- * Both @dest_page/@dest_off and @src_page/@src_off must be mappable to a bus
- * address according to the DMA mapping API rules for streaming mappings.
- * Both @dest_page/@dest_off and @src_page/@src_off must stay memory resident
- * (kernel memory or locked user space pages).
- */
-static inline dma_cookie_t dma_async_memcpy_pg_to_pg(struct dma_chan *chan,
- struct page *dest_pg, unsigned int dest_off, struct page *src_pg,
- unsigned int src_off, size_t len)
+#define dma_cap_set(tx, mask) __dma_cap_set((tx), &(mask))
+static inline void
+__dma_cap_set(enum dma_transaction_type tx_type, dma_cap_mask_t *dstp)
{
- int cpu = get_cpu();
- per_cpu_ptr(chan->local, cpu)->bytes_transferred += len;
- per_cpu_ptr(chan->local, cpu)->memcpy_count++;
- put_cpu();
+ set_bit(tx_type, dstp->bits);
+}
- return chan->device->device_memcpy_pg_to_pg(chan, dest_pg, dest_off,
- src_pg, src_off, len);
+#define dma_has_cap(tx, mask) __dma_has_cap((tx), &(mask))
+static inline int
+__dma_has_cap(enum dma_transaction_type tx_type, dma_cap_mask_t *srcp)
+{
+ return test_bit(tx_type, srcp->bits);
}
+#define for_each_dma_cap_mask(cap, mask) \
+ for ((cap) = first_dma_cap(mask); \
+ (cap) < DMA_TX_TYPE_END; \
+ (cap) = next_dma_cap((cap), (mask)))
+
/**
- * dma_async_memcpy_issue_pending - flush pending copies to HW
+ * dma_async_issue_pending - flush pending transactions to HW
* @chan: target DMA channel
*
* This allows drivers to push copies to HW in batches,
* reducing MMIO writes where possible.
*/
-static inline void dma_async_memcpy_issue_pending(struct dma_chan *chan)
+static inline void dma_async_issue_pending(struct dma_chan *chan)
{
- return chan->device->device_memcpy_issue_pending(chan);
+ return chan->device->device_issue_pending(chan);
}
+#define dma_async_memcpy_issue_pending(chan) dma_async_issue_pending(chan)
+
/**
- * dma_async_memcpy_complete - poll for transaction completion
+ * dma_async_is_tx_complete - poll for transaction completion
* @chan: DMA channel
* @cookie: transaction identifier to check status of
* @last: returns last completed cookie, can be NULL
@@ -306,12 +376,15 @@ static inline void dma_async_memcpy_issue_pending(struct dma_chan *chan)
* internal state and can be used with dma_async_is_complete() to check
* the status of multiple cookies without re-checking hardware state.
*/
-static inline enum dma_status dma_async_memcpy_complete(struct dma_chan *chan,
+static inline enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
{
- return chan->device->device_memcpy_complete(chan, cookie, last, used);
+ return chan->device->device_is_tx_complete(chan, cookie, last, used);
}
+#define dma_async_memcpy_complete(chan, cookie, last, used)\
+ dma_async_is_tx_complete(chan, cookie, last, used)
+
/**
* dma_async_is_complete - test a cookie against chan state
* @cookie: transaction identifier to test status of
@@ -334,6 +407,7 @@ static inline enum dma_status dma_async_is_complete(dma_cookie_t cookie,
return DMA_IN_PROGRESS;
}
+enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
/* --- DMA device --- */
@@ -362,5 +436,4 @@ dma_cookie_t dma_memcpy_pg_to_iovec(struct dma_chan *chan, struct iovec *iov,
struct dma_pinned_list *pinned_list, struct page *page,
unsigned int offset, size_t len);
-#endif /* CONFIG_DMA_ENGINE */
#endif /* DMAENGINE_H */
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 904bf3d2d90b..b8ac7b01c45e 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -12,9 +12,17 @@ enum dmi_field {
DMI_PRODUCT_NAME,
DMI_PRODUCT_VERSION,
DMI_PRODUCT_SERIAL,
+ DMI_PRODUCT_UUID,
DMI_BOARD_VENDOR,
DMI_BOARD_NAME,
DMI_BOARD_VERSION,
+ DMI_BOARD_SERIAL,
+ DMI_BOARD_ASSET_TAG,
+ DMI_CHASSIS_VENDOR,
+ DMI_CHASSIS_TYPE,
+ DMI_CHASSIS_VERSION,
+ DMI_CHASSIS_SERIAL,
+ DMI_CHASSIS_ASSET_TAG,
DMI_STRING_MAX,
};
diff --git a/include/linux/ds17287rtc.h b/include/linux/ds17287rtc.h
index c281ba42e28f..d85d3f497b96 100644
--- a/include/linux/ds17287rtc.h
+++ b/include/linux/ds17287rtc.h
@@ -11,7 +11,6 @@
#define __LINUX_DS17287RTC_H
#include <linux/rtc.h> /* get the user-level API */
-#include <linux/spinlock.h> /* spinlock_t */
#include <linux/mc146818rtc.h>
/* Register A */
diff --git a/include/linux/edac.h b/include/linux/edac.h
new file mode 100644
index 000000000000..eab451e69a91
--- /dev/null
+++ b/include/linux/edac.h
@@ -0,0 +1,29 @@
+/*
+ * Generic EDAC defs
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2006-2007 (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.
+ *
+ */
+#ifndef _LINUX_EDAC_H_
+#define _LINUX_EDAC_H_
+
+#include <asm/atomic.h>
+
+#define EDAC_OPSTATE_INVAL -1
+#define EDAC_OPSTATE_POLL 0
+#define EDAC_OPSTATE_NMI 1
+#define EDAC_OPSTATE_INT 2
+
+extern int edac_op_state;
+extern int edac_err_assert;
+extern atomic_t edac_handlers;
+
+extern int edac_handler_set(void);
+extern void edac_atomic_assert_error(void);
+
+#endif
diff --git a/include/linux/edd.h b/include/linux/edd.h
index b2b3e68aa512..7b647822d6dc 100644
--- a/include/linux/edd.h
+++ b/include/linux/edd.h
@@ -49,10 +49,6 @@
#define EDD_MBR_SIG_MAX 16 /* max number of signatures to store */
#define EDD_MBR_SIG_NR_BUF 0x1ea /* addr of number of MBR signtaures at EDD_MBR_SIG_BUF
in boot_params - treat this as 1 byte */
-#define EDD_CL_EQUALS 0x3d646465 /* "edd=" */
-#define EDD_CL_OFF 0x666f /* "of" for off */
-#define EDD_CL_SKIP 0x6b73 /* "sk" for skipmbr */
-#define EDD_CL_ON 0x6e6f /* "on" for on */
#ifndef __ASSEMBLY__
diff --git a/include/linux/efs_fs.h b/include/linux/efs_fs.h
index dfed8009ebff..16cb25cbf7c5 100644
--- a/include/linux/efs_fs.h
+++ b/include/linux/efs_fs.h
@@ -45,6 +45,7 @@ extern efs_block_t efs_map_block(struct inode *, efs_block_t);
extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp);
extern struct dentry *efs_get_parent(struct dentry *);
extern int efs_bmap(struct inode *, int);
diff --git a/include/linux/elf-em.h b/include/linux/elf-em.h
index 0311bad838b1..5834e843a946 100644
--- a/include/linux/elf-em.h
+++ b/include/linux/elf-em.h
@@ -20,7 +20,8 @@
#define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_PPC 20 /* PowerPC */
-#define EM_PPC64 21 /* PowerPC64 */
+#define EM_PPC64 21 /* PowerPC64 */
+#define EM_SPU 23 /* Cell BE SPU */
#define EM_SH 42 /* SuperH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_IA_64 50 /* HP/Intel IA-64 */
diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h
index 9a1e0674e56c..e831759b2fb5 100644
--- a/include/linux/elfnote.h
+++ b/include/linux/elfnote.h
@@ -38,17 +38,25 @@
* e.g. ELFNOTE(XYZCo, 42, .asciz, "forty-two")
* ELFNOTE(XYZCo, 12, .long, 0xdeadbeef)
*/
-#define ELFNOTE(name, type, desctype, descdata) \
-.pushsection .note.name, "",@note ; \
- .align 4 ; \
+#define ELFNOTE_START(name, type, flags) \
+.pushsection .note.name, flags,@note ; \
+ .balign 4 ; \
.long 2f - 1f /* namesz */ ; \
- .long 4f - 3f /* descsz */ ; \
+ .long 4484f - 3f /* descsz */ ; \
.long type ; \
1:.asciz #name ; \
-2:.align 4 ; \
-3:desctype descdata ; \
-4:.align 4 ; \
+2:.balign 4 ; \
+3:
+
+#define ELFNOTE_END \
+4484:.balign 4 ; \
.popsection ;
+
+#define ELFNOTE(name, type, desc) \
+ ELFNOTE_START(name, type, "") \
+ desc ; \
+ ELFNOTE_END
+
#else /* !__ASSEMBLER__ */
#include <linux/elf.h>
/*
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 071c67abed86..6cdb97365e47 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -39,13 +39,8 @@ extern void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev
extern int eth_header_cache(struct neighbour *neigh,
struct hh_cache *hh);
-extern struct net_device *alloc_etherdev(int sizeof_priv);
-static inline void eth_copy_and_sum (struct sk_buff *dest,
- const unsigned char *src,
- int len, int base)
-{
- memcpy (dest->data, src, len);
-}
+extern struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count);
+#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
/**
* is_zero_ether_addr - Determine if give Ethernet address is all zeros.
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index f2d248f8cc92..3a632244f31b 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -265,6 +265,7 @@ u32 ethtool_op_get_link(struct net_device *dev);
u32 ethtool_op_get_tx_csum(struct net_device *dev);
int ethtool_op_set_tx_csum(struct net_device *dev, u32 data);
int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data);
+int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data);
u32 ethtool_op_get_sg(struct net_device *dev);
int ethtool_op_set_sg(struct net_device *dev, u32 data);
u32 ethtool_op_get_tso(struct net_device *dev);
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
new file mode 100644
index 000000000000..8872fe8392d6
--- /dev/null
+++ b/include/linux/exportfs.h
@@ -0,0 +1,126 @@
+#ifndef LINUX_EXPORTFS_H
+#define LINUX_EXPORTFS_H 1
+
+#include <linux/types.h>
+
+struct dentry;
+struct super_block;
+struct vfsmount;
+
+
+/**
+ * struct export_operations - for nfsd to communicate with file systems
+ * @decode_fh: decode a file handle fragment and return a &struct dentry
+ * @encode_fh: encode a file handle fragment from a dentry
+ * @get_name: find the name for a given inode in a given directory
+ * @get_parent: find the parent of a given directory
+ * @get_dentry: find a dentry for the inode given a file handle sub-fragment
+ * @find_exported_dentry:
+ * set by the exporting module to a standard helper function.
+ *
+ * Description:
+ * The export_operations structure provides a means for nfsd to communicate
+ * with a particular exported file system - particularly enabling nfsd and
+ * the filesystem to co-operate when dealing with file handles.
+ *
+ * export_operations contains two basic operation for dealing with file
+ * handles, decode_fh() and encode_fh(), and allows for some other
+ * operations to be defined which standard helper routines use to get
+ * specific information from the filesystem.
+ *
+ * nfsd encodes information use to determine which filesystem a filehandle
+ * applies to in the initial part of the file handle. The remainder, termed
+ * a file handle fragment, is controlled completely by the filesystem. The
+ * standard helper routines assume that this fragment will contain one or
+ * two sub-fragments, one which identifies the file, and one which may be
+ * used to identify the (a) directory containing the file.
+ *
+ * In some situations, nfsd needs to get a dentry which is connected into a
+ * specific part of the file tree. To allow for this, it passes the
+ * function acceptable() together with a @context which can be used to see
+ * if the dentry is acceptable. As there can be multiple dentrys for a
+ * given file, the filesystem should check each one for acceptability before
+ * looking for the next. As soon as an acceptable one is found, it should
+ * be returned.
+ *
+ * decode_fh:
+ * @decode_fh is given a &struct super_block (@sb), a file handle fragment
+ * (@fh, @fh_len) and an acceptability testing function (@acceptable,
+ * @context). It should return a &struct dentry which refers to the same
+ * file that the file handle fragment refers to, and which passes the
+ * acceptability test. If it cannot, it should return a %NULL pointer if
+ * the file was found but no acceptable &dentries were available, or a
+ * %ERR_PTR error code indicating why it couldn't be found (e.g. %ENOENT or
+ * %ENOMEM).
+ *
+ * encode_fh:
+ * @encode_fh should store in the file handle fragment @fh (using at most
+ * @max_len bytes) information that can be used by @decode_fh to recover the
+ * file refered to by the &struct dentry @de. If the @connectable flag is
+ * set, the encode_fh() should store sufficient information so that a good
+ * attempt can be made to find not only the file but also it's place in the
+ * filesystem. This typically means storing a reference to de->d_parent in
+ * the filehandle fragment. encode_fh() should return the number of bytes
+ * stored or a negative error code such as %-ENOSPC
+ *
+ * get_name:
+ * @get_name should find a name for the given @child in the given @parent
+ * directory. The name should be stored in the @name (with the
+ * understanding that it is already pointing to a a %NAME_MAX+1 sized
+ * buffer. get_name() should return %0 on success, a negative error code
+ * or error. @get_name will be called without @parent->i_mutex held.
+ *
+ * get_parent:
+ * @get_parent should find the parent directory for the given @child which
+ * is also a directory. In the event that it cannot be found, or storage
+ * space cannot be allocated, a %ERR_PTR should be returned.
+ *
+ * get_dentry:
+ * Given a &super_block (@sb) and a pointer to a file-system specific inode
+ * identifier, possibly an inode number, (@inump) get_dentry() should find
+ * the identified inode and return a dentry for that inode. Any suitable
+ * dentry can be returned including, if necessary, a new dentry created with
+ * d_alloc_root. The caller can then find any other extant dentrys by
+ * following the d_alias links. If a new dentry was created using
+ * d_alloc_root, DCACHE_NFSD_DISCONNECTED should be set, and the dentry
+ * should be d_rehash()ed.
+ *
+ * If the inode cannot be found, either a %NULL pointer or an %ERR_PTR code
+ * can be returned. The @inump will be whatever was passed to
+ * nfsd_find_fh_dentry() in either the @obj or @parent parameters.
+ *
+ * Locking rules:
+ * get_parent is called with child->d_inode->i_mutex down
+ * get_name is not (which is possibly inconsistent)
+ */
+
+struct export_operations {
+ struct dentry *(*decode_fh)(struct super_block *sb, __u32 *fh,
+ int fh_len, int fh_type,
+ int (*acceptable)(void *context, struct dentry *de),
+ void *context);
+ int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len,
+ int connectable);
+ int (*get_name)(struct dentry *parent, char *name,
+ struct dentry *child);
+ struct dentry * (*get_parent)(struct dentry *child);
+ struct dentry * (*get_dentry)(struct super_block *sb, void *inump);
+
+ /* This is set by the exporting module to a standard helper */
+ struct dentry * (*find_exported_dentry)(
+ struct super_block *sb, void *obj, void *parent,
+ int (*acceptable)(void *context, struct dentry *de),
+ void *context);
+};
+
+extern struct dentry *find_exported_dentry(struct super_block *sb, void *obj,
+ void *parent, int (*acceptable)(void *context, struct dentry *de),
+ void *context);
+
+extern int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len,
+ int connectable);
+extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh,
+ int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *),
+ void *context);
+
+#endif /* LINUX_EXPORTFS_H */
diff --git a/include/linux/ext2_fs_sb.h b/include/linux/ext2_fs_sb.h
index 4eda0ed76a48..d149f2959e67 100644
--- a/include/linux/ext2_fs_sb.h
+++ b/include/linux/ext2_fs_sb.h
@@ -33,6 +33,8 @@ struct ext2_sb_info {
unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */
unsigned long s_groups_count; /* Number of groups in the fs */
+ unsigned long s_overhead_last; /* Last calculated overhead */
+ unsigned long s_blocks_last; /* Last seen block count */
struct buffer_head * s_sbh; /* Buffer containing the super block */
struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */
struct buffer_head ** s_group_desc;
diff --git a/include/linux/ext3_fs_sb.h b/include/linux/ext3_fs_sb.h
index f61309c81cc4..d3c08353edf6 100644
--- a/include/linux/ext3_fs_sb.h
+++ b/include/linux/ext3_fs_sb.h
@@ -38,6 +38,8 @@ struct ext3_sb_info {
unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */
unsigned long s_groups_count; /* Number of groups in the fs */
+ unsigned long s_overhead_last; /* Last calculated overhead */
+ unsigned long s_blocks_last; /* Last seen block count */
struct buffer_head * s_sbh; /* Buffer containing the super block */
struct ext3_super_block * s_es; /* Pointer to the super block in the buffer */
struct buffer_head ** s_group_desc;
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
index de1f9f78625a..cdee7aaa57aa 100644
--- a/include/linux/ext4_fs.h
+++ b/include/linux/ext4_fs.h
@@ -71,7 +71,7 @@
/*
* Maximal count of links to a file
*/
-#define EXT4_LINK_MAX 32000
+#define EXT4_LINK_MAX 65000
/*
* Macro-instructions used to manage several block sizes
@@ -102,6 +102,7 @@
EXT4_GOOD_OLD_FIRST_INO : \
(s)->s_first_ino)
#endif
+#define EXT4_BLOCK_ALIGN(size, blkbits) ALIGN((size), (1 << (blkbits)))
/*
* Macro-instructions used to manage fragments
@@ -201,6 +202,7 @@ struct ext4_group_desc
#define EXT4_STATE_JDATA 0x00000001 /* journaled data exists */
#define EXT4_STATE_NEW 0x00000002 /* inode is newly created */
#define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */
+#define EXT4_STATE_NO_EXPAND 0x00000008 /* No space for expansion */
/* Used to pass group descriptor data when online resize is done */
struct ext4_new_group_input {
@@ -225,6 +227,11 @@ struct ext4_new_group_data {
__u32 free_blocks_count;
};
+/*
+ * Following is used by preallocation code to tell get_blocks() that we
+ * want uninitialzed extents.
+ */
+#define EXT4_CREATE_UNINITIALIZED_EXT 2
/*
* ioctl commands
@@ -237,7 +244,7 @@ struct ext4_new_group_data {
#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input)
#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION
#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
#define EXT4_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
#endif
#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
@@ -253,7 +260,7 @@ struct ext4_new_group_data {
#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int)
#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int)
#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
#define EXT4_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
#endif
#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
@@ -282,7 +289,7 @@ struct ext4_inode {
__le16 i_uid; /* Low 16 bits of Owner Uid */
__le32 i_size; /* Size in bytes */
__le32 i_atime; /* Access time */
- __le32 i_ctime; /* Creation time */
+ __le32 i_ctime; /* Inode Change time */
__le32 i_mtime; /* Modification time */
__le32 i_dtime; /* Deletion Time */
__le16 i_gid; /* Low 16 bits of Group Id */
@@ -331,10 +338,85 @@ struct ext4_inode {
} osd2; /* OS dependent 2 */
__le16 i_extra_isize;
__le16 i_pad1;
+ __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
+ __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */
+ __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
+ __le32 i_crtime; /* File Creation time */
+ __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
};
#define i_size_high i_dir_acl
+#define EXT4_EPOCH_BITS 2
+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
+#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
+
+/*
+ * Extended fields will fit into an inode if the filesystem was formatted
+ * with large inodes (-I 256 or larger) and there are not currently any EAs
+ * consuming all of the available space. For new inodes we always reserve
+ * enough space for the kernel's known extended fields, but for inodes
+ * created with an old kernel this might not have been the case. None of
+ * the extended inode fields is critical for correct filesystem operation.
+ * This macro checks if a certain field fits in the inode. Note that
+ * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
+ */
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field) \
+ ((offsetof(typeof(*ext4_inode), field) + \
+ sizeof((ext4_inode)->field)) \
+ <= (EXT4_GOOD_OLD_INODE_SIZE + \
+ (einode)->i_extra_isize)) \
+
+static inline __le32 ext4_encode_extra_time(struct timespec *time)
+{
+ return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
+ time->tv_sec >> 32 : 0) |
+ ((time->tv_nsec << 2) & EXT4_NSEC_MASK));
+}
+
+static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
+{
+ if (sizeof(time->tv_sec) > 4)
+ time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
+ << 32;
+ time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> 2;
+}
+
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \
+do { \
+ (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
+ if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
+ (raw_inode)->xtime ## _extra = \
+ ext4_encode_extra_time(&(inode)->xtime); \
+} while (0)
+
+#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode) \
+do { \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
+ (raw_inode)->xtime = cpu_to_le32((einode)->xtime.tv_sec); \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
+ (raw_inode)->xtime ## _extra = \
+ ext4_encode_extra_time(&(einode)->xtime); \
+} while (0)
+
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode) \
+do { \
+ (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
+ if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \
+ ext4_decode_extra_time(&(inode)->xtime, \
+ raw_inode->xtime ## _extra); \
+} while (0)
+
+#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode) \
+do { \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
+ (einode)->xtime.tv_sec = \
+ (signed)le32_to_cpu((raw_inode)->xtime); \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
+ ext4_decode_extra_time(&(einode)->xtime, \
+ raw_inode->xtime ## _extra); \
+} while (0)
+
#if defined(__KERNEL__) || defined(__linux__)
#define i_reserved1 osd1.linux1.l_i_reserved1
#define i_frag osd2.linux2.l_i_frag
@@ -533,6 +615,13 @@ static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
return container_of(inode, struct ext4_inode_info, vfs_inode);
}
+static inline struct timespec ext4_current_time(struct inode *inode)
+{
+ return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ?
+ current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
+}
+
+
static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
{
return ino == EXT4_ROOT_INO ||
@@ -603,6 +692,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
@@ -620,6 +711,8 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
EXT4_FEATURE_INCOMPAT_64BIT)
#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
/*
@@ -862,6 +955,7 @@ extern int ext4_change_inode_journal_flag(struct inode *, int);
extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
extern void ext4_truncate (struct inode *);
extern void ext4_set_inode_flags(struct inode *);
+extern void ext4_get_inode_flags(struct ext4_inode_info *);
extern void ext4_set_aops(struct inode *inode);
extern int ext4_writepage_trans_blocks(struct inode *);
extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
@@ -983,6 +1077,8 @@ extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
extern void ext4_ext_truncate(struct inode *, struct page *);
extern void ext4_ext_init(struct super_block *);
extern void ext4_ext_release(struct super_block *);
+extern long ext4_fallocate(struct inode *inode, int mode, loff_t offset,
+ loff_t len);
static inline int
ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
unsigned long max_blocks, struct buffer_head *bh,
diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h
index acfe59740b03..81406f3655d4 100644
--- a/include/linux/ext4_fs_extents.h
+++ b/include/linux/ext4_fs_extents.h
@@ -141,7 +141,25 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
#define EXT_MAX_BLOCK 0xffffffff
-#define EXT_MAX_LEN ((1UL << 15) - 1)
+/*
+ * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an
+ * initialized extent. This is 2^15 and not (2^16 - 1), since we use the
+ * MSB of ee_len field in the extent datastructure to signify if this
+ * particular extent is an initialized extent or an uninitialized (i.e.
+ * preallocated).
+ * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an
+ * uninitialized extent.
+ * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an
+ * uninitialized one. In other words, if MSB of ee_len is set, it is an
+ * uninitialized extent with only one special scenario when ee_len = 0x8000.
+ * In this case we can not have an uninitialized extent of zero length and
+ * thus we make it as a special case of initialized extent with 0x8000 length.
+ * This way we get better extent-to-group alignment for initialized extents.
+ * Hence, the maximum number of blocks we can have in an *initialized*
+ * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767).
+ */
+#define EXT_INIT_MAX_LEN (1UL << 15)
+#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1)
#define EXT_FIRST_EXTENT(__hdr__) \
@@ -188,8 +206,31 @@ ext4_ext_invalidate_cache(struct inode *inode)
EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO;
}
+static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext)
+{
+ /* We can not have an uninitialized extent of zero length! */
+ BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0);
+ ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext)
+{
+ /* Extent with ee_len of 0x8000 is treated as an initialized extent */
+ return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN);
+}
+
+static inline int ext4_ext_get_actual_len(struct ext4_extent *ext)
+{
+ return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ?
+ le16_to_cpu(ext->ee_len) :
+ (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN));
+}
+
extern int ext4_extent_tree_init(handle_t *, struct inode *);
extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
+extern int ext4_ext_try_to_merge(struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *);
extern unsigned int ext4_ext_check_overlap(struct inode *, struct ext4_extent *, struct ext4_ext_path *);
extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *);
diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h
index 9de494406995..1a511e9905aa 100644
--- a/include/linux/ext4_fs_i.h
+++ b/include/linux/ext4_fs_i.h
@@ -153,6 +153,11 @@ struct ext4_inode_info {
unsigned long i_ext_generation;
struct ext4_ext_cache i_cached_extent;
+ /*
+ * File creation time. Its function is same as that of
+ * struct timespec i_{a,c,m}time in the generic inode.
+ */
+ struct timespec i_crtime;
};
#endif /* _LINUX_EXT4_FS_I */
diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h
index 691a713139ce..1b2ffee12be9 100644
--- a/include/linux/ext4_fs_sb.h
+++ b/include/linux/ext4_fs_sb.h
@@ -39,6 +39,8 @@ struct ext4_sb_info {
unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */
unsigned long s_groups_count; /* Number of groups in the fs */
+ unsigned long s_overhead_last; /* Last calculated overhead */
+ unsigned long s_blocks_last; /* Last seen block count */
struct buffer_head * s_sbh; /* Buffer containing the super block */
struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
struct buffer_head ** s_group_desc;
@@ -71,7 +73,7 @@ struct ext4_sb_info {
struct list_head s_orphan;
unsigned long s_commit_interval;
struct block_device *journal_bdev;
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */
wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */
#endif
@@ -79,6 +81,7 @@ struct ext4_sb_info {
char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */
int s_jquota_fmt; /* Format of quota to use */
#endif
+ unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */
#ifdef EXTENTS_STATS
/* ext4 extents stats */
diff --git a/include/linux/falloc.h b/include/linux/falloc.h
new file mode 100644
index 000000000000..8e912ab6a072
--- /dev/null
+++ b/include/linux/falloc.h
@@ -0,0 +1,6 @@
+#ifndef _FALLOC_H_
+#define _FALLOC_H_
+
+#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */
+
+#endif /* _FALLOC_H_ */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 66226824ab68..cec54106aa87 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -119,6 +119,7 @@ struct dentry;
#define FB_ACCEL_NV_40 46 /* nVidia Arch 40 */
#define FB_ACCEL_XGI_VOLARI_V 47 /* XGI Volari V3XT, V5, V8 */
#define FB_ACCEL_XGI_VOLARI_Z 48 /* XGI Volari Z7 */
+#define FB_ACCEL_OMAP1610 49 /* TI OMAP16xx */
#define FB_ACCEL_NEOMAGIC_NM2070 90 /* NeoMagic NM2070 */
#define FB_ACCEL_NEOMAGIC_NM2090 91 /* NeoMagic NM2090 */
#define FB_ACCEL_NEOMAGIC_NM2093 92 /* NeoMagic NM2093 */
@@ -529,6 +530,8 @@ struct fb_cursor_user {
#define FB_EVENT_CONBLANK 0x0C
/* Get drawing requirements */
#define FB_EVENT_GET_REQ 0x0D
+/* Unbind from the console if possible */
+#define FB_EVENT_FB_UNBIND 0x0E
struct fb_event {
struct fb_info *info;
diff --git a/include/linux/file.h b/include/linux/file.h
index a59001e9ea58..0114fbc78061 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -73,6 +73,7 @@ extern struct file * FASTCALL(fget_light(unsigned int fd, int *fput_needed));
extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag));
extern void put_filp(struct file *);
extern int get_unused_fd(void);
+extern int get_unused_fd_flags(int flags);
extern void FASTCALL(put_unused_fd(unsigned int fd));
struct kmem_cache;
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 4631086f5060..c8e02de737f6 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -1,5 +1,8 @@
/* Freezer declarations */
+#ifndef FREEZER_H_INCLUDED
+#define FREEZER_H_INCLUDED
+
#include <linux/sched.h>
#ifdef CONFIG_PM
@@ -22,7 +25,7 @@ static inline int freezing(struct task_struct *p)
/*
* Request that a process be frozen
*/
-static inline void freeze(struct task_struct *p)
+static inline void set_freeze_flag(struct task_struct *p)
{
set_tsk_thread_flag(p, TIF_FREEZE);
}
@@ -30,7 +33,7 @@ static inline void freeze(struct task_struct *p)
/*
* Sometimes we may need to cancel the previous 'freeze' request
*/
-static inline void do_not_freeze(struct task_struct *p)
+static inline void clear_freeze_flag(struct task_struct *p)
{
clear_tsk_thread_flag(p, TIF_FREEZE);
}
@@ -53,7 +56,7 @@ static inline int thaw_process(struct task_struct *p)
wake_up_process(p);
return 1;
}
- clear_tsk_thread_flag(p, TIF_FREEZE);
+ clear_freeze_flag(p);
task_unlock(p);
return 0;
}
@@ -115,10 +118,19 @@ static inline int freezer_should_skip(struct task_struct *p)
return !!(p->flags & PF_FREEZER_SKIP);
}
+/*
+ * Tell the freezer that the current task should be frozen by it
+ */
+static inline void set_freezable(void)
+{
+ current->flags &= ~PF_NOFREEZE;
+}
+
#else
static inline int frozen(struct task_struct *p) { return 0; }
static inline int freezing(struct task_struct *p) { return 0; }
-static inline void freeze(struct task_struct *p) { BUG(); }
+static inline void set_freeze_flag(struct task_struct *p) {}
+static inline void clear_freeze_flag(struct task_struct *p) {}
static inline int thaw_process(struct task_struct *p) { return 1; }
static inline void refrigerator(void) {}
@@ -130,4 +142,7 @@ static inline int try_to_freeze(void) { return 0; }
static inline void freezer_do_not_count(void) {}
static inline void freezer_count(void) {}
static inline int freezer_should_skip(struct task_struct *p) { return 0; }
+static inline void set_freezable(void) {}
#endif
+
+#endif /* FREEZER_H_INCLUDED */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4f0b3bf5983c..d33beadd9a43 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -44,7 +44,7 @@ extern int get_max_files(void);
struct inodes_stat_t {
int nr_inodes;
int nr_unused;
- int dummy[5];
+ int dummy[5]; /* padding for sysctl ABI compatibility */
};
extern struct inodes_stat_t inodes_stat;
@@ -283,11 +283,14 @@ extern int dir_notify_enable;
#include <linux/init.h>
#include <linux/pid.h>
#include <linux/mutex.h>
+#include <linux/sysctl.h>
+#include <linux/capability.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
#include <asm/byteorder.h>
+struct export_operations;
struct hd_geometry;
struct iovec;
struct nameidata;
@@ -694,20 +697,26 @@ struct fown_struct {
* Track a single file's readahead state
*/
struct file_ra_state {
- unsigned long start; /* Current window */
- unsigned long size;
- unsigned long flags; /* ra flags RA_FLAG_xxx*/
- unsigned long cache_hit; /* cache hit count*/
- unsigned long prev_index; /* Cache last read() position */
- unsigned long ahead_start; /* Ahead window */
- unsigned long ahead_size;
+ pgoff_t start; /* where readahead started */
+ unsigned long size; /* # of readahead pages */
+ unsigned long async_size; /* do asynchronous readahead when
+ there are only # of pages ahead */
+
unsigned long ra_pages; /* Maximum readahead window */
unsigned long mmap_hit; /* Cache hit stat for mmap accesses */
unsigned long mmap_miss; /* Cache miss stat for mmap accesses */
+ unsigned long prev_index; /* Cache last read() position */
unsigned int prev_offset; /* Offset where last read() ended in a page */
};
-#define RA_FLAG_MISS 0x01 /* a cache miss occured against this file */
-#define RA_FLAG_INCACHE 0x02 /* file is already in cache */
+
+/*
+ * Check if @index falls in the readahead windows.
+ */
+static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index)
+{
+ return (index >= ra->start &&
+ index < ra->start + ra->size);
+}
struct file {
/*
@@ -820,6 +829,10 @@ struct file_lock {
union {
struct nfs_lock_info nfs_fl;
struct nfs4_lock_info nfs4_fl;
+ struct {
+ struct list_head link; /* link in AFS vnode's pending_locks list */
+ int state; /* state of grant or error if -ve */
+ } afs;
} fl_u;
};
@@ -855,7 +868,7 @@ extern void locks_init_lock(struct file_lock *);
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
extern void locks_remove_posix(struct file *, fl_owner_t);
extern void locks_remove_flock(struct file *);
-extern int posix_test_lock(struct file *, struct file_lock *);
+extern void posix_test_lock(struct file *, struct file_lock *);
extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
extern int posix_lock_file_wait(struct file *, struct file_lock *);
extern int posix_unblock_lock(struct file *, struct file_lock *);
@@ -866,6 +879,7 @@ extern int flock_lock_file_wait(struct file *filp, struct file_lock *fl);
extern int __break_lease(struct inode *inode, unsigned int flags);
extern void lease_get_mtime(struct inode *, struct timespec *time);
extern int setlease(struct file *, long, struct file_lock **);
+extern int vfs_setlease(struct file *, long, struct file_lock **);
extern int lease_modify(struct file_lock **, int);
extern int lock_may_read(struct inode *, loff_t start, unsigned long count);
extern int lock_may_write(struct inode *, loff_t start, unsigned long count);
@@ -984,6 +998,9 @@ enum {
#define put_fs_excl() atomic_dec(&current->fs_excl)
#define has_fs_excl() atomic_read(&current->fs_excl)
+#define is_owner_or_cap(inode) \
+ ((current->fsuid == (inode)->i_uid) || capable(CAP_FOWNER))
+
/* not quite ready to be deprecated, but... */
extern void lock_super(struct super_block *);
extern void unlock_super(struct super_block *);
@@ -1112,6 +1129,7 @@ struct file_operations {
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
+ int (*setlease)(struct file *, long, struct file_lock **);
};
struct inode_operations {
@@ -1137,6 +1155,8 @@ struct inode_operations {
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*removexattr) (struct dentry *, const char *);
void (*truncate_range)(struct inode *, loff_t, loff_t);
+ long (*fallocate)(struct inode *inode, int mode, loff_t offset,
+ loff_t len);
};
struct seq_file;
@@ -1273,119 +1293,6 @@ static inline void file_accessed(struct file *file)
int sync_inode(struct inode *inode, struct writeback_control *wbc);
-/**
- * struct export_operations - for nfsd to communicate with file systems
- * @decode_fh: decode a file handle fragment and return a &struct dentry
- * @encode_fh: encode a file handle fragment from a dentry
- * @get_name: find the name for a given inode in a given directory
- * @get_parent: find the parent of a given directory
- * @get_dentry: find a dentry for the inode given a file handle sub-fragment
- * @find_exported_dentry:
- * set by the exporting module to a standard helper function.
- *
- * Description:
- * The export_operations structure provides a means for nfsd to communicate
- * with a particular exported file system - particularly enabling nfsd and
- * the filesystem to co-operate when dealing with file handles.
- *
- * export_operations contains two basic operation for dealing with file
- * handles, decode_fh() and encode_fh(), and allows for some other
- * operations to be defined which standard helper routines use to get
- * specific information from the filesystem.
- *
- * nfsd encodes information use to determine which filesystem a filehandle
- * applies to in the initial part of the file handle. The remainder, termed
- * a file handle fragment, is controlled completely by the filesystem. The
- * standard helper routines assume that this fragment will contain one or
- * two sub-fragments, one which identifies the file, and one which may be
- * used to identify the (a) directory containing the file.
- *
- * In some situations, nfsd needs to get a dentry which is connected into a
- * specific part of the file tree. To allow for this, it passes the
- * function acceptable() together with a @context which can be used to see
- * if the dentry is acceptable. As there can be multiple dentrys for a
- * given file, the filesystem should check each one for acceptability before
- * looking for the next. As soon as an acceptable one is found, it should
- * be returned.
- *
- * decode_fh:
- * @decode_fh is given a &struct super_block (@sb), a file handle fragment
- * (@fh, @fh_len) and an acceptability testing function (@acceptable,
- * @context). It should return a &struct dentry which refers to the same
- * file that the file handle fragment refers to, and which passes the
- * acceptability test. If it cannot, it should return a %NULL pointer if
- * the file was found but no acceptable &dentries were available, or a
- * %ERR_PTR error code indicating why it couldn't be found (e.g. %ENOENT or
- * %ENOMEM).
- *
- * encode_fh:
- * @encode_fh should store in the file handle fragment @fh (using at most
- * @max_len bytes) information that can be used by @decode_fh to recover the
- * file refered to by the &struct dentry @de. If the @connectable flag is
- * set, the encode_fh() should store sufficient information so that a good
- * attempt can be made to find not only the file but also it's place in the
- * filesystem. This typically means storing a reference to de->d_parent in
- * the filehandle fragment. encode_fh() should return the number of bytes
- * stored or a negative error code such as %-ENOSPC
- *
- * get_name:
- * @get_name should find a name for the given @child in the given @parent
- * directory. The name should be stored in the @name (with the
- * understanding that it is already pointing to a a %NAME_MAX+1 sized
- * buffer. get_name() should return %0 on success, a negative error code
- * or error. @get_name will be called without @parent->i_mutex held.
- *
- * get_parent:
- * @get_parent should find the parent directory for the given @child which
- * is also a directory. In the event that it cannot be found, or storage
- * space cannot be allocated, a %ERR_PTR should be returned.
- *
- * get_dentry:
- * Given a &super_block (@sb) and a pointer to a file-system specific inode
- * identifier, possibly an inode number, (@inump) get_dentry() should find
- * the identified inode and return a dentry for that inode. Any suitable
- * dentry can be returned including, if necessary, a new dentry created with
- * d_alloc_root. The caller can then find any other extant dentrys by
- * following the d_alias links. If a new dentry was created using
- * d_alloc_root, DCACHE_NFSD_DISCONNECTED should be set, and the dentry
- * should be d_rehash()ed.
- *
- * If the inode cannot be found, either a %NULL pointer or an %ERR_PTR code
- * can be returned. The @inump will be whatever was passed to
- * nfsd_find_fh_dentry() in either the @obj or @parent parameters.
- *
- * Locking rules:
- * get_parent is called with child->d_inode->i_mutex down
- * get_name is not (which is possibly inconsistent)
- */
-
-struct export_operations {
- struct dentry *(*decode_fh)(struct super_block *sb, __u32 *fh, int fh_len, int fh_type,
- int (*acceptable)(void *context, struct dentry *de),
- void *context);
- int (*encode_fh)(struct dentry *de, __u32 *fh, int *max_len,
- int connectable);
-
- /* the following are only called from the filesystem itself */
- int (*get_name)(struct dentry *parent, char *name,
- struct dentry *child);
- struct dentry * (*get_parent)(struct dentry *child);
- struct dentry * (*get_dentry)(struct super_block *sb, void *inump);
-
- /* This is set by the exporting module to a standard helper */
- struct dentry * (*find_exported_dentry)(
- struct super_block *sb, void *obj, void *parent,
- int (*acceptable)(void *context, struct dentry *de),
- void *context);
-
-
-};
-
-extern struct dentry *
-find_exported_dentry(struct super_block *sb, void *obj, void *parent,
- int (*acceptable)(void *context, struct dentry *de),
- void *context);
-
struct file_system_type {
const char *name;
int fs_flags;
@@ -1522,7 +1429,7 @@ extern void putname(const char *name);
#ifdef CONFIG_BLOCK
extern int register_blkdev(unsigned int, const char *);
-extern int unregister_blkdev(unsigned int, const char *);
+extern void unregister_blkdev(unsigned int, const char *);
extern struct block_device *bdget(dev_t);
extern void bd_set_size(struct block_device *, loff_t size);
extern void bd_forget(struct inode *inode);
@@ -1562,7 +1469,7 @@ extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *);
extern int register_chrdev_region(dev_t, unsigned, const char *);
extern int register_chrdev(unsigned int, const char *,
const struct file_operations *);
-extern int unregister_chrdev(unsigned int, const char *);
+extern void unregister_chrdev(unsigned int, const char *);
extern void unregister_chrdev_region(dev_t, unsigned);
extern int chrdev_open(struct inode *, struct file *);
extern void chrdev_show(struct seq_file *,off_t);
@@ -1610,6 +1517,9 @@ extern int __invalidate_device(struct block_device *);
extern int invalidate_partition(struct gendisk *, int);
#endif
extern int invalidate_inodes(struct super_block *);
+unsigned long __invalidate_mapping_pages(struct address_space *mapping,
+ pgoff_t start, pgoff_t end,
+ bool be_atomic);
unsigned long invalidate_mapping_pages(struct address_space *mapping,
pgoff_t start, pgoff_t end);
@@ -2043,5 +1953,9 @@ static inline void free_secdata(void *secdata)
{ }
#endif /* CONFIG_SECURITY */
+int proc_nr_files(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+
+
#endif /* __KERNEL__ */
#endif /* _LINUX_FS_H */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 73710d617775..1831b196c70a 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -53,6 +53,7 @@ struct gianfar_platform_data {
u32 bus_id;
u32 phy_id;
u8 mac_addr[6];
+ phy_interface_t interface;
};
struct gianfar_mdio_data {
@@ -112,7 +113,7 @@ struct fsl_usb2_platform_data {
struct fsl_spi_platform_data {
u32 initial_spmode; /* initial SPMODE value */
u16 bus_num;
-
+ bool qe_mode;
/* board specific information */
u16 max_chipselect;
void (*activate_cs)(u8 cs, u8 polarity);
@@ -120,5 +121,10 @@ struct fsl_spi_platform_data {
u32 sysclk;
};
+struct mpc8xx_pcmcia_ops {
+ void(*hw_ctrl)(int slot, int enable);
+ int(*voltage_set)(int slot, int vcc, int vpp);
+};
+
#endif /* _FSL_DEVICE_H_ */
#endif /* __KERNEL__ */
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index 534744efe30d..9fbe9d258e22 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -339,7 +339,7 @@ struct fuse_dirent {
char name[0];
};
-#define FUSE_NAME_OFFSET ((unsigned) ((struct fuse_dirent *) 0)->name)
+#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
#define FUSE_DIRENT_ALIGN(x) (((x) + sizeof(__u64) - 1) & ~(sizeof(__u64) - 1))
#define FUSE_DIRENT_SIZE(d) \
FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
diff --git a/include/linux/genetlink.h b/include/linux/genetlink.h
index f7a93770e1be..7da02c93002b 100644
--- a/include/linux/genetlink.h
+++ b/include/linux/genetlink.h
@@ -39,6 +39,9 @@ enum {
CTRL_CMD_NEWOPS,
CTRL_CMD_DELOPS,
CTRL_CMD_GETOPS,
+ CTRL_CMD_NEWMCAST_GRP,
+ CTRL_CMD_DELMCAST_GRP,
+ CTRL_CMD_GETMCAST_GRP, /* unused */
__CTRL_CMD_MAX,
};
@@ -52,6 +55,7 @@ enum {
CTRL_ATTR_HDRSIZE,
CTRL_ATTR_MAXATTR,
CTRL_ATTR_OPS,
+ CTRL_ATTR_MCAST_GROUPS,
__CTRL_ATTR_MAX,
};
@@ -66,4 +70,13 @@ enum {
#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1)
+enum {
+ CTRL_ATTR_MCAST_GRP_UNSPEC,
+ CTRL_ATTR_MCAST_GRP_NAME,
+ CTRL_ATTR_MCAST_GRP_ID,
+ __CTRL_ATTR_MCAST_GRP_MAX,
+};
+
+#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
+
#endif /* __LINUX_GENERIC_NETLINK_H */
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 0d2ef0b082a6..bc68dd9a6d41 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -30,6 +30,9 @@ struct vm_area_struct;
* cannot handle allocation failures.
*
* __GFP_NORETRY: The VM implementation must not retry indefinitely.
+ *
+ * __GFP_MOVABLE: Flag that this page will be movable by the page migration
+ * mechanism or reclaimed
*/
#define __GFP_WAIT ((__force gfp_t)0x10u) /* Can wait and reschedule? */
#define __GFP_HIGH ((__force gfp_t)0x20u) /* Should access emergency pools? */
@@ -45,6 +48,7 @@ struct vm_area_struct;
#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
#define __GFP_HARDWALL ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
#define __GFP_THISNODE ((__force gfp_t)0x40000u)/* No fallback, no policies */
+#define __GFP_MOVABLE ((__force gfp_t)0x80000u) /* Page is movable */
#define __GFP_BITS_SHIFT 20 /* Room for 20 __GFP_FOO bits */
#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
@@ -53,7 +57,8 @@ struct vm_area_struct;
#define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
__GFP_NOFAIL|__GFP_NORETRY|__GFP_COMP| \
- __GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE)
+ __GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_THISNODE| \
+ __GFP_MOVABLE)
/* This equals 0, but use constants in case they ever change */
#define GFP_NOWAIT (GFP_ATOMIC & ~__GFP_HIGH)
@@ -65,6 +70,15 @@ struct vm_area_struct;
#define GFP_USER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
#define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \
__GFP_HIGHMEM)
+#define GFP_HIGHUSER_MOVABLE (__GFP_WAIT | __GFP_IO | __GFP_FS | \
+ __GFP_HARDWALL | __GFP_HIGHMEM | \
+ __GFP_MOVABLE)
+#define GFP_NOFS_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_MOVABLE)
+#define GFP_USER_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_FS | \
+ __GFP_HARDWALL | __GFP_MOVABLE)
+#define GFP_HIGHUSER_PAGECACHE (__GFP_WAIT | __GFP_IO | __GFP_FS | \
+ __GFP_HARDWALL | __GFP_HIGHMEM | \
+ __GFP_MOVABLE)
#ifdef CONFIG_NUMA
#define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
@@ -92,6 +106,9 @@ static inline enum zone_type gfp_zone(gfp_t flags)
if (flags & __GFP_DMA32)
return ZONE_DMA32;
#endif
+ if ((flags & (__GFP_HIGHMEM | __GFP_MOVABLE)) ==
+ (__GFP_HIGHMEM | __GFP_MOVABLE))
+ return ZONE_MOVABLE;
#ifdef CONFIG_HIGHMEM
if (flags & __GFP_HIGHMEM)
return ZONE_HIGHMEM;
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 98e2cce996a4..1fcb0033179e 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -73,10 +73,27 @@ static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
}
#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE
+/**
+ * __alloc_zeroed_user_highpage - Allocate a zeroed HIGHMEM page for a VMA with caller-specified movable GFP flags
+ * @movableflags: The GFP flags related to the pages future ability to move like __GFP_MOVABLE
+ * @vma: The VMA the page is to be allocated for
+ * @vaddr: The virtual address the page will be inserted into
+ *
+ * This function will allocate a page for a VMA but the caller is expected
+ * to specify via movableflags whether the page will be movable in the
+ * future or not
+ *
+ * An architecture may override this function by defining
+ * __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE and providing their own
+ * implementation.
+ */
static inline struct page *
-alloc_zeroed_user_highpage(struct vm_area_struct *vma, unsigned long vaddr)
+__alloc_zeroed_user_highpage(gfp_t movableflags,
+ struct vm_area_struct *vma,
+ unsigned long vaddr)
{
- struct page *page = alloc_page_vma(GFP_HIGHUSER, vma, vaddr);
+ struct page *page = alloc_page_vma(GFP_HIGHUSER | movableflags,
+ vma, vaddr);
if (page)
clear_user_highpage(page, vaddr);
@@ -85,6 +102,21 @@ alloc_zeroed_user_highpage(struct vm_area_struct *vma, unsigned long vaddr)
}
#endif
+/**
+ * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move
+ * @vma: The VMA the page is to be allocated for
+ * @vaddr: The virtual address the page will be inserted into
+ *
+ * This function will allocate a page for a VMA that the caller knows will
+ * be able to migrate in the future using move_pages() or reclaimed
+ */
+static inline struct page *
+alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma,
+ unsigned long vaddr)
+{
+ return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr);
+}
+
static inline void clear_highpage(struct page *page)
{
void *kaddr = kmap_atomic(page, KM_USER0);
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 17c29dca8354..540799bc85f8 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -329,12 +329,13 @@ extern void sysrq_timer_list_show(void);
#ifdef CONFIG_TIMER_STATS
extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
- void *timerf, char * comm);
+ void *timerf, char *comm,
+ unsigned int timer_flag);
static inline void timer_stats_account_hrtimer(struct hrtimer *timer)
{
timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
- timer->function, timer->start_comm);
+ timer->function, timer->start_comm, 0);
}
extern void __timer_stats_hrtimer_set_start_info(struct hrtimer *timer,
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 2c13715e9dde..49b7053043ad 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -15,6 +15,7 @@ static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
}
int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *);
+int hugetlb_treat_movable_handler(struct ctl_table *, int, struct file *, void __user *, size_t *, loff_t *);
int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *);
int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int);
void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
@@ -29,6 +30,7 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to);
void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
extern unsigned long max_huge_pages;
+extern unsigned long hugepages_treat_as_movable;
extern const unsigned long hugetlb_zero, hugetlb_infinity;
extern int sysctl_hugetlb_shm_group;
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index aa83d4163096..b69014865714 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -115,9 +115,10 @@
#define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */
#define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */
#define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */
-#define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */
-#define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */
-#define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */
+#define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */
+#define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */
+#define I2C_DRIVERID_LM4857 92 /* LM4857 Audio Amplifier */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
diff --git a/include/linux/i2c-isa.h b/include/linux/i2c-isa.h
deleted file mode 100644
index 67e3598c4cec..000000000000
--- a/include/linux/i2c-isa.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * i2c-isa.h - definitions for the i2c-isa pseudo-i2c-adapter interface
- *
- * Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _LINUX_I2C_ISA_H
-#define _LINUX_I2C_ISA_H
-
-#include <linux/i2c.h>
-
-extern int i2c_isa_add_driver(struct i2c_driver *driver);
-extern int i2c_isa_del_driver(struct i2c_driver *driver);
-
-/* Detect whether we are on the isa bus. This is only useful to hybrid
- (i2c+isa) drivers. */
-#define i2c_is_isa_adapter(adapptr) \
- ((adapptr)->id == I2C_HW_ISA)
-#define i2c_is_isa_client(clientptr) \
- i2c_is_isa_adapter((clientptr)->adapter)
-
-#endif /* _LINUX_I2C_ISA_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index cae7d618030c..0c37a737a2b2 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -90,7 +90,7 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
const u8 *values);
/* Returns the number of read bytes */
extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client,
- u8 command, u8 *values);
+ u8 command, u8 length, u8 *values);
extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
u8 command, u8 length,
const u8 *values);
@@ -150,15 +150,20 @@ struct i2c_driver {
/**
* struct i2c_client - represent an I2C slave device
+ * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
+ * I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
* @addr: Address used on the I2C bus connected to the parent adapter.
* @name: Indicates the type of the device, usually a chip name that's
* generic enough to hide second-sourcing and compatible revisions.
+ * @adapter: manages the bus segment hosting this I2C device
* @dev: Driver model device node for the slave.
+ * @irq: indicates the IRQ generated by this device (if any)
* @driver_name: Identifies new-style driver used with this device; also
* used as the module name for hotplug/coldplug modprobe support.
*
* An i2c_client identifies a single device (i.e. chip) connected to an
- * i2c bus. The behaviour is defined by the routines of the driver.
+ * i2c bus. The behaviour exposed to Linux is defined by the driver
+ * managing the device.
*/
struct i2c_client {
unsigned short flags; /* div., see below */
@@ -180,7 +185,8 @@ struct i2c_client {
static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj)
{
- return to_i2c_client(container_of(kobj, struct device, kobj));
+ struct device * const dev = container_of(kobj, struct device, kobj);
+ return to_i2c_client(dev);
}
static inline void *i2c_get_clientdata (struct i2c_client *dev)
@@ -201,7 +207,7 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
* @addr: stored in i2c_client.addr
* @platform_data: stored in i2c_client.dev.platform_data
* @irq: stored in i2c_client.irq
-
+ *
* I2C doesn't actually support hardware probing, although controllers and
* devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
* a device at a given address. Drivers commonly need more information than
@@ -210,7 +216,7 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data)
* i2c_board_info is used to build tables of information listing I2C devices
* that are present. This information is used to grow the driver model tree
* for "new style" I2C drivers. For mainboards this is done statically using
- * i2c_register_board_info(), where @bus_num represents an adapter that isn't
+ * i2c_register_board_info(); bus numbers identify adapters that aren't
* yet available. For add-on boards, i2c_new_device() does this dynamically
* with the adapter already known.
*/
@@ -362,7 +368,6 @@ struct i2c_client_address_data {
/* The numbers to use to set I2C bus address */
#define ANY_I2C_BUS 0xffff
-#define ANY_I2C_ISA_BUS 9191
/* ----- functions exported by i2c.o */
@@ -518,8 +523,9 @@ union i2c_smbus_data {
#define I2C_SMBUS_WORD_DATA 3
#define I2C_SMBUS_PROC_CALL 4
#define I2C_SMBUS_BLOCK_DATA 5
-#define I2C_SMBUS_I2C_BLOCK_DATA 6
+#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
+#define I2C_SMBUS_I2C_BLOCK_DATA 8
/* ----- commands for the ioctl like i2c_command call:
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index 52f53e2e70c3..9752307d16ba 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h> /* work_struct */
#include <linux/mempool.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/semaphore.h> /* Needed for MUTEX init macros */
@@ -425,7 +426,7 @@ struct i2o_device {
struct device device;
- struct semaphore lock; /* device lock */
+ struct mutex lock; /* device lock */
};
/*
@@ -544,7 +545,7 @@ struct i2o_controller {
struct i2o_dma hrt; /* HW Resource Table */
i2o_lct *lct; /* Logical Config Table */
struct i2o_dma dlct; /* Temp LCT */
- struct semaphore lct_lock; /* Lock for LCT updates */
+ struct mutex lct_lock; /* Lock for LCT updates */
struct i2o_dma status_block; /* IOP status block */
struct i2o_io base; /* controller messaging unit */
@@ -945,8 +946,7 @@ static inline int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
strcpy(pool->name, name);
pool->slab =
- kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL,
- NULL);
+ kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
if (!pool->slab)
goto free_name;
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 19ab25804056..5f5daad8bc54 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -681,6 +681,10 @@ typedef struct hwif_s {
u8 straight8; /* Alan's straight 8 check */
u8 bus_state; /* power state of the IDE bus */
+ u8 host_flags;
+
+ u8 pio_mask;
+
u8 atapi_dma; /* host supports atapi_dma */
u8 ultra_mask;
u8 mwdma_mask;
@@ -1244,7 +1248,13 @@ typedef struct ide_pci_enablebit_s {
enum {
/* Uses ISA control ports not PCI ones. */
- IDEPCI_FLAG_ISA_PORTS = (1 << 0),
+ IDE_HFLAG_ISA_PORTS = (1 << 0),
+ /* single port device */
+ 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),
};
typedef struct ide_pci_device_s {
@@ -1256,13 +1266,13 @@ typedef struct ide_pci_device_s {
void (*init_hwif)(ide_hwif_t *);
void (*init_dma)(ide_hwif_t *, unsigned long);
void (*fixup)(ide_hwif_t *);
- u8 channels;
u8 autodma;
ide_pci_enablebit_t enablebits[2];
u8 bootable;
unsigned int extra;
struct ide_pci_device_s *next;
- u8 flags;
+ u8 host_flags;
+ u8 pio_mask;
u8 udma_mask;
} ide_pci_device_t;
@@ -1363,6 +1373,11 @@ extern void ide_toggle_bounce(ide_drive_t *drive, int on);
extern int ide_set_xfer_rate(ide_drive_t *drive, u8 rate);
int ide_use_fast_pio(ide_drive_t *);
+static inline int ide_dev_has_iordy(struct hd_driveid *id)
+{
+ return ((id->field_valid & 2) && (id->capability & 8)) ? 1 : 0;
+}
+
u8 ide_dump_status(ide_drive_t *, const char *, u8);
typedef struct ide_pio_timings_s {
@@ -1372,14 +1387,8 @@ typedef struct ide_pio_timings_s {
/* active + recovery (+ setup for some chips) */
} ide_pio_timings_t;
-typedef struct ide_pio_data_s {
- u8 pio_mode;
- u8 use_iordy;
- u8 overridden;
- unsigned int cycle_time;
-} ide_pio_data_t;
-
-extern u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d);
+unsigned int ide_pio_cycle_time(ide_drive_t *, u8);
+u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8);
extern const ide_pio_timings_t ide_pio_timings[6];
diff --git a/include/linux/idr.h b/include/linux/idr.h
index 826803449db7..0edda411959c 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -78,9 +78,41 @@ void *idr_find(struct idr *idp, int id);
int idr_pre_get(struct idr *idp, gfp_t gfp_mask);
int idr_get_new(struct idr *idp, void *ptr, int *id);
int idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
+int idr_for_each(struct idr *idp,
+ int (*fn)(int id, void *p, void *data), void *data);
void *idr_replace(struct idr *idp, void *ptr, int id);
void idr_remove(struct idr *idp, int id);
+void idr_remove_all(struct idr *idp);
void idr_destroy(struct idr *idp);
void idr_init(struct idr *idp);
+
+/*
+ * IDA - IDR based id allocator, use when translation from id to
+ * pointer isn't necessary.
+ */
+#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */
+#define IDA_BITMAP_LONGS (128 / sizeof(long) - 1)
+#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8)
+
+struct ida_bitmap {
+ long nr_busy;
+ unsigned long bitmap[IDA_BITMAP_LONGS];
+};
+
+struct ida {
+ struct idr idr;
+ struct ida_bitmap *free_bitmap;
+};
+
+#define IDA_INIT(name) { .idr = IDR_INIT(name), .free_bitmap = NULL, }
+#define DEFINE_IDA(name) struct ida name = IDA_INIT(name)
+
+int ida_pre_get(struct ida *ida, gfp_t gfp_mask);
+int ida_get_new_above(struct ida *ida, int starting_id, int *p_id);
+int ida_get_new(struct ida *ida, int *p_id);
+void ida_remove(struct ida *ida, int id);
+void ida_destroy(struct ida *ida);
+void ida_init(struct ida *ida);
+
#endif /* __IDR_H__ */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index ecd61e8438a5..272f8c8c90da 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -227,6 +227,17 @@ struct ieee80211_cts {
#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10)
#define WLAN_CAPABILITY_DSSS_OFDM (1<<13)
+/* 802.11g ERP information element */
+#define WLAN_ERP_NON_ERP_PRESENT (1<<0)
+#define WLAN_ERP_USE_PROTECTION (1<<1)
+#define WLAN_ERP_BARKER_PREAMBLE (1<<2)
+
+/* WLAN_ERP_BARKER_PREAMBLE values */
+enum {
+ WLAN_ERP_PREAMBLE_SHORT = 0,
+ WLAN_ERP_PREAMBLE_LONG = 1,
+};
+
/* Status codes */
enum ieee80211_statuscode {
WLAN_STATUS_SUCCESS = 0,
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 604c2434f71c..422084d18ce1 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -76,6 +76,8 @@ enum
#define IFLA_WEIGHT IFLA_WEIGHT
IFLA_OPERSTATE,
IFLA_LINKMODE,
+ IFLA_LINKINFO,
+#define IFLA_LINKINFO IFLA_LINKINFO
__IFLA_MAX
};
@@ -140,4 +142,49 @@ struct ifla_cacheinfo
__u32 retrans_time;
};
+enum
+{
+ IFLA_INFO_UNSPEC,
+ IFLA_INFO_KIND,
+ IFLA_INFO_DATA,
+ IFLA_INFO_XSTATS,
+ __IFLA_INFO_MAX,
+};
+
+#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1)
+
+/* VLAN section */
+
+enum
+{
+ IFLA_VLAN_UNSPEC,
+ IFLA_VLAN_ID,
+ IFLA_VLAN_FLAGS,
+ IFLA_VLAN_EGRESS_QOS,
+ IFLA_VLAN_INGRESS_QOS,
+ __IFLA_VLAN_MAX,
+};
+
+#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1)
+
+struct ifla_vlan_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+enum
+{
+ IFLA_VLAN_QOS_UNSPEC,
+ IFLA_VLAN_QOS_MAPPING,
+ __IFLA_VLAN_QOS_MAX
+};
+
+#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1)
+
+struct ifla_vlan_qos_mapping
+{
+ __u32 from;
+ __u32 to;
+};
+
#endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
new file mode 100644
index 000000000000..0d9d7ea2c1cc
--- /dev/null
+++ b/include/linux/if_macvlan.h
@@ -0,0 +1,9 @@
+#ifndef _LINUX_IF_MACVLAN_H
+#define _LINUX_IF_MACVLAN_H
+
+#ifdef __KERNEL__
+
+extern struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_IF_MACVLAN_H */
diff --git a/include/linux/if_ppp.h b/include/linux/if_ppp.h
index 768372f07caa..0f2f70d4e48c 100644
--- a/include/linux/if_ppp.h
+++ b/include/linux/if_ppp.h
@@ -110,6 +110,21 @@ struct ifpppcstatsreq {
struct ppp_comp_stats stats;
};
+/* For PPPIOCGL2TPSTATS */
+struct pppol2tp_ioc_stats {
+ __u16 tunnel_id; /* redundant */
+ __u16 session_id; /* if zero, get tunnel stats */
+ __u32 using_ipsec:1; /* valid only for session_id == 0 */
+ aligned_u64 tx_packets;
+ aligned_u64 tx_bytes;
+ aligned_u64 tx_errors;
+ aligned_u64 rx_packets;
+ aligned_u64 rx_bytes;
+ aligned_u64 rx_seq_discards;
+ aligned_u64 rx_oos_packets;
+ aligned_u64 rx_errors;
+};
+
#define ifr__name b.ifr_ifrn.ifrn_name
#define stats_ptr b.ifr_ifru.ifru_data
@@ -146,6 +161,7 @@ struct ifpppcstatsreq {
#define PPPIOCDISCONN _IO('t', 57) /* disconnect channel */
#define PPPIOCATTCHAN _IOW('t', 56, int) /* attach to ppp channel */
#define PPPIOCGCHAN _IOR('t', 55, int) /* get ppp channel number */
+#define PPPIOCGL2TPSTATS _IOR('t', 54, struct pppol2tp_ioc_stats)
#define SIOCGPPPSTATS (SIOCDEVPRIVATE + 0)
#define SIOCGPPPVER (SIOCDEVPRIVATE + 1) /* NEVER change this!! */
diff --git a/include/linux/if_pppol2tp.h b/include/linux/if_pppol2tp.h
new file mode 100644
index 000000000000..516203b6fdeb
--- /dev/null
+++ b/include/linux/if_pppol2tp.h
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * Linux PPP over L2TP (PPPoL2TP) Socket Implementation (RFC 2661)
+ *
+ * This file supplies definitions required by the PPP over L2TP driver
+ * (pppol2tp.c). All version information wrt this file is located in pppol2tp.c
+ *
+ * License:
+ * 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 __LINUX_IF_PPPOL2TP_H
+#define __LINUX_IF_PPPOL2TP_H
+
+#include <asm/types.h>
+
+#ifdef __KERNEL__
+#include <linux/in.h>
+#endif
+
+/* Structure used to connect() the socket to a particular tunnel UDP
+ * socket.
+ */
+struct pppol2tp_addr
+{
+ pid_t pid; /* pid that owns the fd.
+ * 0 => current */
+ int fd; /* FD of UDP socket to use */
+
+ struct sockaddr_in addr; /* IP address and port to send to */
+
+ __be16 s_tunnel, s_session; /* For matching incoming packets */
+ __be16 d_tunnel, d_session; /* For sending outgoing packets */
+};
+
+/* Socket options:
+ * DEBUG - bitmask of debug message categories
+ * SENDSEQ - 0 => don't send packets with sequence numbers
+ * 1 => send packets with sequence numbers
+ * RECVSEQ - 0 => receive packet sequence numbers are optional
+ * 1 => drop receive packets without sequence numbers
+ * LNSMODE - 0 => act as LAC.
+ * 1 => act as LNS.
+ * REORDERTO - reorder timeout (in millisecs). If 0, don't try to reorder.
+ */
+enum {
+ PPPOL2TP_SO_DEBUG = 1,
+ PPPOL2TP_SO_RECVSEQ = 2,
+ PPPOL2TP_SO_SENDSEQ = 3,
+ PPPOL2TP_SO_LNSMODE = 4,
+ PPPOL2TP_SO_REORDERTO = 5,
+};
+
+/* Debug message categories for the DEBUG socket option */
+enum {
+ PPPOL2TP_MSG_DEBUG = (1 << 0), /* verbose debug (if
+ * compiled in) */
+ PPPOL2TP_MSG_CONTROL = (1 << 1), /* userspace - kernel
+ * interface */
+ PPPOL2TP_MSG_SEQ = (1 << 2), /* sequence numbers */
+ PPPOL2TP_MSG_DATA = (1 << 3), /* data packets */
+};
+
+
+
+#endif
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index 6f987be60fe2..25652545ba6e 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -27,6 +27,7 @@
#include <asm/semaphore.h>
#include <linux/ppp_channel.h>
#endif /* __KERNEL__ */
+#include <linux/if_pppol2tp.h>
/* For user-space programs to pick up these definitions
* which they wouldn't get otherwise without defining __KERNEL__
@@ -50,8 +51,9 @@ struct pppoe_addr{
* Protocols supported by AF_PPPOX
*/
#define PX_PROTO_OE 0 /* Currently just PPPoE */
-#define PX_MAX_PROTO 1
-
+#define PX_PROTO_OL2TP 1 /* Now L2TP also */
+#define PX_MAX_PROTO 2
+
struct sockaddr_pppox {
sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
@@ -60,6 +62,16 @@ struct sockaddr_pppox {
}sa_addr;
}__attribute__ ((packed));
+/* The use of the above union isn't viable because the size of this
+ * struct must stay fixed over time -- applications use sizeof(struct
+ * sockaddr_pppox) to fill it. We use a protocol specific sockaddr
+ * type instead.
+ */
+struct sockaddr_pppol2tp {
+ sa_family_t sa_family; /* address family, AF_PPPOX */
+ unsigned int sa_protocol; /* protocol identifier */
+ struct pppol2tp_addr pppol2tp;
+}__attribute__ ((packed));
/*********************************************************************
*
diff --git a/include/linux/if_tun.h b/include/linux/if_tun.h
index 88aef7b86ef4..42eb6945b93e 100644
--- a/include/linux/if_tun.h
+++ b/include/linux/if_tun.h
@@ -36,6 +36,7 @@ struct tun_struct {
unsigned long flags;
int attached;
uid_t owner;
+ gid_t group;
wait_queue_head_t read_wait;
struct sk_buff_head readq;
@@ -78,6 +79,7 @@ struct tun_struct {
#define TUNSETPERSIST _IOW('T', 203, int)
#define TUNSETOWNER _IOW('T', 204, int)
#define TUNSETLINK _IOW('T', 205, int)
+#define TUNSETGROUP _IOW('T', 206, int)
/* TUNSETIFF ifr flags */
#define IFF_TUN 0x0001
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 81e9bc93569b..f8443fdb124a 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -99,7 +99,7 @@ static inline void vlan_group_set_device(struct vlan_group *vg, int vlan_id,
}
struct vlan_priority_tci_mapping {
- unsigned long priority;
+ u32 priority;
unsigned short vlan_qos; /* This should be shifted when first set, so we only do it
* at provisioning time.
* ((skb->priority << 13) & 0xE000)
@@ -112,7 +112,10 @@ struct vlan_dev_info {
/** This will be the mapping that correlates skb->priority to
* 3 bits of VLAN QOS tags...
*/
- unsigned long ingress_priority_map[8];
+ unsigned int nr_ingress_mappings;
+ u32 ingress_priority_map[8];
+
+ unsigned int nr_egress_mappings;
struct vlan_priority_tci_mapping *egress_priority_map[16]; /* hash table */
unsigned short vlan_id; /* The VLAN Identifier for this interface. */
@@ -124,14 +127,8 @@ struct vlan_dev_info {
* like DHCP that use packet-filtering and don't understand
* 802.1Q
*/
- struct dev_mc_list *old_mc_list; /* old multi-cast list for the VLAN interface..
- * we save this so we can tell what changes were
- * made, in order to feed the right changes down
- * to the real hardware...
- */
- int old_allmulti; /* similar to above. */
- int old_promiscuity; /* similar to above. */
struct net_device *real_dev; /* the underlying device/interface */
+ unsigned char real_dev_addr[ETH_ALEN];
struct proc_dir_entry *dent; /* Holds the proc data */
unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */
unsigned long cnt_encap_on_xmit; /* How many times did we have to encapsulate the skb on TX. */
@@ -395,6 +392,10 @@ enum vlan_ioctl_cmds {
GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */
};
+enum vlan_flags {
+ VLAN_FLAG_REORDER_HDR = 0x1,
+};
+
enum vlan_name_types {
VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */
VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */
diff --git a/include/linux/init.h b/include/linux/init.h
index 56ec4c62eee0..f0d0e3295a9b 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -40,10 +40,10 @@
/* These are for everybody (although not all archs will actually
discard it in modules) */
-#define __init __attribute__ ((__section__ (".init.text")))
+#define __init __attribute__ ((__section__ (".init.text"))) __cold
#define __initdata __attribute__ ((__section__ (".init.data")))
#define __exitdata __attribute__ ((__section__(".exit.data")))
-#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
+#define __exit_call __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) __cold
/* modpost check for section mismatches during the kernel build.
* A section mismatch happens when there are references from a
@@ -59,9 +59,9 @@
#define __initdata_refok __attribute__ ((__section__ (".data.init.refok")))
#ifdef MODULE
-#define __exit __attribute__ ((__section__(".exit.text")))
+#define __exit __attribute__ ((__section__(".exit.text"))) __cold
#else
-#define __exit __attribute_used__ __attribute__ ((__section__(".exit.text")))
+#define __exit __attribute_used__ __attribute__ ((__section__(".exit.text"))) __cold
#endif
/* For assembly routines */
@@ -171,9 +171,6 @@ struct obs_kernel_param {
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
-#define __obsolete_setup(str) \
- __setup_null_param(str, __LINE__)
-
/* NOTE: fn is as per module_param, not __setup! Emits warning if fn
* returns non-zero. */
#define early_param(str, fn) \
@@ -239,7 +236,6 @@ void __init parse_early_param(void);
#define __setup_param(str, unique_id, fn) /* nothing */
#define __setup_null_param(str, unique_id) /* nothing */
#define __setup(str, func) /* nothing */
-#define __obsolete_setup(str) /* nothing */
#endif
/* Data marked not to be saved by software suspend */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 276ccaa2670c..cab741c2d603 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -8,6 +8,7 @@
#include <linux/lockdep.h>
#include <linux/ipc.h>
#include <linux/pid_namespace.h>
+#include <linux/user_namespace.h>
#define INIT_FDTABLE \
{ \
@@ -78,6 +79,7 @@ extern struct nsproxy init_nsproxy;
.uts_ns = &init_uts_ns, \
.mnt_ns = NULL, \
INIT_IPC_NS(ipc_ns) \
+ .user_ns = &init_user_ns, \
}
#define INIT_SIGHAND(sighand) { \
diff --git a/include/linux/input.h b/include/linux/input.h
index 18c98b543030..e02c6a66b2ba 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -344,7 +344,8 @@ struct input_absinfo {
#define KEY_BRIGHTNESSUP 225
#define KEY_MEDIA 226
-#define KEY_SWITCHVIDEOMODE 227
+#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video
+ outputs (Monitor/LCD/TV-out/etc) */
#define KEY_KBDILLUMTOGGLE 228
#define KEY_KBDILLUMDOWN 229
#define KEY_KBDILLUMUP 230
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 5323f6275854..0a3c2ebf2008 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -120,11 +120,11 @@ extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
# define local_irq_enable_in_hardirq() local_irq_enable()
#endif
-#ifdef CONFIG_GENERIC_HARDIRQS
extern void disable_irq_nosync(unsigned int irq);
extern void disable_irq(unsigned int irq);
extern void enable_irq(unsigned int irq);
+#ifdef CONFIG_GENERIC_HARDIRQS
/*
* Special lockdep variants of irq disabling/enabling.
* These should be used for locking constructs that
diff --git a/include/linux/io.h b/include/linux/io.h
index 8423dd376514..e3b2dda6c8eb 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -63,32 +63,7 @@ void __iomem * devm_ioremap(struct device *dev, unsigned long offset,
void __iomem * devm_ioremap_nocache(struct device *dev, unsigned long offset,
unsigned long size);
void devm_iounmap(struct device *dev, void __iomem *addr);
-
-/**
- * check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the mmio address io_addr. This
- * address should have been obtained by ioremap.
- * Returns 1 on a match.
- */
-
-static inline int check_signature(const volatile void __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
+int check_signature(const volatile void __iomem *io_addr,
+ const unsigned char *signature, int length);
#endif /* _LINUX_IO_H */
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
index 2eaa142cd061..baf29387cab4 100644
--- a/include/linux/ioprio.h
+++ b/include/linux/ioprio.h
@@ -53,6 +53,14 @@ static inline int task_ioprio(struct task_struct *task)
return IOPRIO_NORM;
}
+static inline int task_ioprio_class(struct task_struct *task)
+{
+ if (ioprio_valid(task->ioprio))
+ return IOPRIO_PRIO_CLASS(task->ioprio);
+
+ return IOPRIO_CLASS_BE;
+}
+
static inline int task_nice_ioprio(struct task_struct *task)
{
return (task_nice(task) + 20) / 5;
diff --git a/include/linux/ip_mp_alg.h b/include/linux/ip_mp_alg.h
deleted file mode 100644
index e234e2008f5d..000000000000
--- a/include/linux/ip_mp_alg.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
- *
- * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
- * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
- */
-
-#ifndef _LINUX_IP_MP_ALG_H
-#define _LINUX_IP_MP_ALG_H
-
-enum ip_mp_alg {
- IP_MP_ALG_NONE,
- IP_MP_ALG_RR,
- IP_MP_ALG_DRR,
- IP_MP_ALG_RANDOM,
- IP_MP_ALG_WRANDOM,
- __IP_MP_ALG_MAX
-};
-
-#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1)
-
-#endif /* _LINUX_IP_MP_ALG_H */
-
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 1980867a64a4..3fd3ddd5f0d9 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -52,6 +52,7 @@ struct ipc_perm
#ifdef __KERNEL__
#include <linux/kref.h>
+#include <linux/spinlock.h>
#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
@@ -92,6 +93,7 @@ extern struct ipc_namespace init_ipc_ns;
#ifdef CONFIG_SYSVIPC
#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
+extern void free_ipc_ns(struct kref *kref);
extern struct ipc_namespace *copy_ipcs(unsigned long flags,
struct ipc_namespace *ns);
#else
@@ -103,13 +105,9 @@ static inline struct ipc_namespace *copy_ipcs(unsigned long flags,
}
#endif
-#ifdef CONFIG_IPC_NS
-extern void free_ipc_ns(struct kref *kref);
-#endif
-
static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
{
-#ifdef CONFIG_IPC_NS
+#ifdef CONFIG_SYSVIPC
if (ns)
kref_get(&ns->kref);
#endif
@@ -118,7 +116,7 @@ static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
static inline void put_ipc_ns(struct ipc_namespace *ns)
{
-#ifdef CONFIG_IPC_NS
+#ifdef CONFIG_SYSVIPC
kref_put(&ns->kref, free_ipc_ns);
#endif
}
@@ -126,5 +124,3 @@ static inline void put_ipc_ns(struct ipc_namespace *ns)
#endif /* __KERNEL__ */
#endif /* _LINUX_IPC_H */
-
-
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 648bd1f0912d..97983dc9df13 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -27,8 +27,8 @@ struct in6_ifreq {
int ifr6_ifindex;
};
-#define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */
-#define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */
+#define IPV6_SRCRT_STRICT 0x01 /* Deprecated; will be removed */
+#define IPV6_SRCRT_TYPE_0 0 /* Deprecated; will be removed */
#define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */
/*
@@ -247,7 +247,7 @@ struct inet6_skb_parm {
__u16 lastopt;
__u32 nhoff;
__u16 flags;
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
__u16 dsthao;
#endif
@@ -299,8 +299,8 @@ struct ipv6_pinfo {
/* pktoption flags */
union {
struct {
- __u16 srcrt:2,
- osrcrt:2,
+ __u16 srcrt:1,
+ osrcrt:1,
rxinfo:1,
rxoinfo:1,
rxhlim:1,
diff --git a/include/linux/irda.h b/include/linux/irda.h
index 945ba3110874..28f88ecba344 100644
--- a/include/linux/irda.h
+++ b/include/linux/irda.h
@@ -77,6 +77,7 @@ typedef enum {
IRDA_ACT200L_DONGLE = 10,
IRDA_MA600_DONGLE = 11,
IRDA_TOIM3232_DONGLE = 12,
+ IRDA_EP7211_DONGLE = 13,
} IRDA_DONGLE;
/* Protocol types to be used for SOCK_DGRAM */
@@ -216,6 +217,34 @@ struct if_irda_req {
#define ifr_dtr ifr_ifru.ifru_line.dtr
#define ifr_rts ifr_ifru.ifru_line.rts
+
+/* IrDA netlink definitions */
+#define IRDA_NL_NAME "irda"
+#define IRDA_NL_VERSION 1
+
+enum irda_nl_commands {
+ IRDA_NL_CMD_UNSPEC,
+ IRDA_NL_CMD_SET_MODE,
+ IRDA_NL_CMD_GET_MODE,
+
+ __IRDA_NL_CMD_AFTER_LAST
+};
+#define IRDA_NL_CMD_MAX (__IRDA_NL_CMD_AFTER_LAST - 1)
+
+enum nl80211_attrs {
+ IRDA_NL_ATTR_UNSPEC,
+ IRDA_NL_ATTR_IFNAME,
+ IRDA_NL_ATTR_MODE,
+
+ __IRDA_NL_ATTR_AFTER_LAST
+};
+#define IRDA_NL_ATTR_MAX (__IRDA_NL_ATTR_AFTER_LAST - 1)
+
+/* IrDA modes */
+#define IRDA_MODE_PRIMARY 0x1
+#define IRDA_MODE_SECONDARY 0x2
+#define IRDA_MODE_MONITOR 0x4
+
#endif /* KERNEL_IRDA_H */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 1695054e8c63..44657197fcb0 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -161,6 +161,7 @@ struct irq_desc {
unsigned int wake_depth; /* nested wake enables */
unsigned int irq_count; /* For detecting broken IRQs */
unsigned int irqs_unhandled;
+ unsigned long last_unhandled; /* Aging timer for unhandled count */
spinlock_t lock;
#ifdef CONFIG_SMP
cpumask_t affinity;
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 0e0fedd2039a..260d6d76c5f3 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -50,14 +50,14 @@
*/
#define JBD_DEFAULT_MAX_COMMIT_AGE 5
-#ifdef CONFIG_JBD_DEBUG
+#ifdef CONFIG_JBD2_DEBUG
/*
* Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
* consistency checks. By default we don't do this unless
- * CONFIG_JBD_DEBUG is on.
+ * CONFIG_JBD2_DEBUG is on.
*/
#define JBD_EXPENSIVE_CHECKING
-extern int jbd2_journal_enable_debug;
+extern u8 jbd2_journal_enable_debug;
#define jbd_debug(n, f, a...) \
do { \
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 5f06527dca21..f73de6fb5c68 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -7,9 +7,9 @@
#include <linux/errno.h>
-#define KSYM_NAME_LEN 127
-#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN + \
- 2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1)
+#define KSYM_NAME_LEN 128
+#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \
+ 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1)
#ifdef CONFIG_KALLSYMS
/* Lookup the address for a symbol. Returns 0 if not found. */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 7a4852505914..4300bb462d29 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -106,7 +106,7 @@ extern int cond_resched(void);
extern struct atomic_notifier_head panic_notifier_list;
extern long (*panic_blink)(long time);
NORET_TYPE void panic(const char * fmt, ...)
- __attribute__ ((NORET_AND format (printf, 1, 2)));
+ __attribute__ ((NORET_AND format (printf, 1, 2))) __cold;
extern void oops_enter(void);
extern void oops_exit(void);
extern int oops_may_print(void);
@@ -155,14 +155,14 @@ extern void dump_thread(struct pt_regs *regs, struct user *dump);
asmlinkage int vprintk(const char *fmt, va_list args)
__attribute__ ((format (printf, 1, 0)));
asmlinkage int printk(const char * fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
+ __attribute__ ((format (printf, 1, 2))) __cold;
#else
static inline int vprintk(const char *s, va_list args)
__attribute__ ((format (printf, 1, 0)));
static inline int vprintk(const char *s, va_list args) { return 0; }
static inline int printk(const char *s, ...)
__attribute__ ((format (printf, 1, 2)));
-static inline int printk(const char *s, ...) { return 0; }
+static inline int __cold printk(const char *s, ...) { return 0; }
#endif
unsigned long int_sqrt(unsigned long);
@@ -210,8 +210,9 @@ extern enum system_states {
#define TAINT_MACHINE_CHECK (1<<4)
#define TAINT_BAD_PAGE (1<<5)
#define TAINT_USER (1<<6)
+#define TAINT_DIE (1<<7)
-extern void dump_stack(void);
+extern void dump_stack(void) __cold;
enum {
DUMP_PREFIX_NONE,
diff --git a/include/linux/kernelcapi.h b/include/linux/kernelcapi.h
index aea34e74c496..8c4350a9ed87 100644
--- a/include/linux/kernelcapi.h
+++ b/include/linux/kernelcapi.h
@@ -64,7 +64,7 @@ struct capi20_appl {
unsigned long nrecvdatapkt;
unsigned long nsentctlpkt;
unsigned long nsentdatapkt;
- struct semaphore recv_sem;
+ struct mutex recv_mtx;
struct sk_buff_head recv_queue;
struct work_struct recv_work;
int release_in_progress;
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 10f505c8431d..5dc13848891b 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -36,13 +36,57 @@ static inline int request_module(const char * name, ...) { return -ENOSYS; }
#define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
struct key;
-extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
- struct key *session_keyring, int wait);
+struct file;
+struct subprocess_info;
+
+/* Allocate a subprocess_info structure */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+ char **argv, char **envp);
+
+/* Set various pieces of state into the subprocess_info structure */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+ struct key *session_keyring);
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+ struct file **filp);
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+ void (*cleanup)(char **argv, char **envp));
+
+enum umh_wait {
+ UMH_NO_WAIT = -1, /* don't wait at all */
+ UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */
+ UMH_WAIT_PROC = 1, /* wait for the process to complete */
+};
+
+/* Actually execute the sub-process */
+int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait);
+
+/* Free the subprocess_info. This is only needed if you're not going
+ to call call_usermodehelper_exec */
+void call_usermodehelper_freeinfo(struct subprocess_info *info);
static inline int
-call_usermodehelper(char *path, char **argv, char **envp, int wait)
+call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait)
{
- return call_usermodehelper_keys(path, argv, envp, NULL, wait);
+ struct subprocess_info *info;
+
+ info = call_usermodehelper_setup(path, argv, envp);
+ if (info == NULL)
+ return -ENOMEM;
+ return call_usermodehelper_exec(info, wait);
+}
+
+static inline int
+call_usermodehelper_keys(char *path, char **argv, char **envp,
+ struct key *session_keyring, enum umh_wait wait)
+{
+ struct subprocess_info *info;
+
+ info = call_usermodehelper_setup(path, argv, envp);
+ if (info == NULL)
+ return -ENOMEM;
+
+ call_usermodehelper_setkeys(info, session_keyring);
+ return call_usermodehelper_exec(info, wait);
}
extern void usermodehelper_init(void);
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index c288e41ba331..aa2fe22b1baa 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -36,15 +36,24 @@ extern char uevent_helper[];
/* counter to tag the uevent, read only except for the kobject core */
extern u64 uevent_seqnum;
-/* the actions here must match the proper string in lib/kobject_uevent.c */
-typedef int __bitwise kobject_action_t;
+/*
+ * The actions here must match the index to the string array
+ * in lib/kobject_uevent.c
+ *
+ * Do not add new actions here without checking with the driver-core
+ * maintainers. Action strings are not meant to express subsystem
+ * or device specific properties. In most cases you want to send a
+ * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
+ * specific variables added to the event environment.
+ */
enum kobject_action {
- KOBJ_ADD = (__force kobject_action_t) 0x01, /* exclusive to core */
- KOBJ_REMOVE = (__force kobject_action_t) 0x02, /* exclusive to core */
- KOBJ_CHANGE = (__force kobject_action_t) 0x03, /* device state change */
- KOBJ_OFFLINE = (__force kobject_action_t) 0x04, /* device offline */
- KOBJ_ONLINE = (__force kobject_action_t) 0x05, /* device online */
- KOBJ_MOVE = (__force kobject_action_t) 0x06, /* device move */
+ KOBJ_ADD,
+ KOBJ_REMOVE,
+ KOBJ_CHANGE,
+ KOBJ_MOVE,
+ KOBJ_ONLINE,
+ KOBJ_OFFLINE,
+ KOBJ_MAX
};
struct kobject {
@@ -55,7 +64,7 @@ struct kobject {
struct kobject * parent;
struct kset * kset;
struct kobj_type * ktype;
- struct dentry * dentry;
+ struct sysfs_dirent * sd;
wait_queue_head_t poll;
};
@@ -71,13 +80,14 @@ extern void kobject_init(struct kobject *);
extern void kobject_cleanup(struct kobject *);
extern int __must_check kobject_add(struct kobject *);
-extern int __must_check kobject_shadow_add(struct kobject *, struct dentry *);
+extern int __must_check kobject_shadow_add(struct kobject *kobj,
+ struct sysfs_dirent *shadow_parent);
extern void kobject_del(struct kobject *);
extern int __must_check kobject_rename(struct kobject *, const char *new_name);
extern int __must_check kobject_shadow_rename(struct kobject *kobj,
- struct dentry *new_parent,
- const char *new_name);
+ struct sysfs_dirent *new_parent,
+ const char *new_name);
extern int __must_check kobject_move(struct kobject *, struct kobject *);
extern int __must_check kobject_register(struct kobject *);
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 23adf6075ae4..51464d12a4e5 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -116,9 +116,12 @@ struct kprobe {
*/
struct jprobe {
struct kprobe kp;
- kprobe_opcode_t *entry; /* probe handling code to jump to */
+ void *entry; /* probe handling code to jump to */
};
+/* For backward compatibility with old code using JPROBE_ENTRY() */
+#define JPROBE_ENTRY(handler) (handler)
+
DECLARE_PER_CPU(struct kprobe *, current_kprobe);
DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -211,6 +214,7 @@ int longjmp_break_handler(struct kprobe *, struct pt_regs *);
int register_jprobe(struct jprobe *p);
void unregister_jprobe(struct jprobe *p);
void jprobe_return(void);
+unsigned long arch_deref_entry_point(void *);
int register_kretprobe(struct kretprobe *rp);
void unregister_kretprobe(struct kretprobe *rp);
diff --git a/include/linux/ktime.h b/include/linux/ktime.h
index 2b139f66027f..dae7143644fe 100644
--- a/include/linux/ktime.h
+++ b/include/linux/ktime.h
@@ -279,6 +279,16 @@ static inline s64 ktime_to_us(const ktime_t kt)
return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
}
+static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier)
+{
+ return ktime_to_us(ktime_sub(later, earlier));
+}
+
+static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec)
+{
+ return ktime_add_ns(kt, usec * 1000);
+}
+
/*
* The resolution of the clocks. The resolution value is returned in
* the clock_getres() system call to give application programmers an
diff --git a/include/linux/lcd.h b/include/linux/lcd.h
index 598793c0745b..1d379787f2e7 100644
--- a/include/linux/lcd.h
+++ b/include/linux/lcd.h
@@ -62,8 +62,8 @@ struct lcd_device {
struct mutex update_lock;
/* The framebuffer notifier block */
struct notifier_block fb_notif;
- /* The class device structure */
- struct class_device class_dev;
+
+ struct device dev;
};
static inline void lcd_set_power(struct lcd_device *ld, int power)
@@ -75,9 +75,15 @@ static inline void lcd_set_power(struct lcd_device *ld, int power)
}
extern struct lcd_device *lcd_device_register(const char *name,
- void *devdata, struct lcd_ops *ops);
+ struct device *parent, void *devdata, struct lcd_ops *ops);
extern void lcd_device_unregister(struct lcd_device *ld);
-#define to_lcd_device(obj) container_of(obj, struct lcd_device, class_dev)
+#define to_lcd_device(obj) container_of(obj, struct lcd_device, dev)
+
+static inline void * lcd_get_data(struct lcd_device *ld_dev)
+{
+ return dev_get_drvdata(&ld_dev->dev);
+}
+
#endif
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 88afceffb7cb..421175092ee2 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -13,10 +13,8 @@
#define __LINUX_LEDS_H_INCLUDED
#include <linux/list.h>
-#include <linux/spinlock.h>
struct device;
-struct class_device;
/*
* LED Core
*/
@@ -38,7 +36,7 @@ struct led_classdev {
void (*brightness_set)(struct led_classdev *led_cdev,
enum led_brightness brightness);
- struct class_device *class_dev;
+ struct device *dev;
struct list_head node; /* LED Device list */
char *default_trigger; /* Trigger to use */
@@ -110,4 +108,18 @@ extern void ledtrig_ide_activity(void);
#define ledtrig_ide_activity() do {} while(0)
#endif
+/* For the leds-gpio driver */
+struct gpio_led {
+ const char *name;
+ char *default_trigger;
+ unsigned gpio;
+ u8 active_low;
+};
+
+struct gpio_led_platform_data {
+ int num_leds;
+ struct gpio_led *leds;
+};
+
+
#endif /* __LINUX_LEDS_H_INCLUDED */
diff --git a/include/linux/lguest.h b/include/linux/lguest.h
new file mode 100644
index 000000000000..500aace21ca7
--- /dev/null
+++ b/include/linux/lguest.h
@@ -0,0 +1,85 @@
+/* Things the lguest guest needs to know. Note: like all lguest interfaces,
+ * this is subject to wild and random change between versions. */
+#ifndef _ASM_LGUEST_H
+#define _ASM_LGUEST_H
+
+#ifndef __ASSEMBLY__
+#include <asm/irq.h>
+
+#define LHCALL_FLUSH_ASYNC 0
+#define LHCALL_LGUEST_INIT 1
+#define LHCALL_CRASH 2
+#define LHCALL_LOAD_GDT 3
+#define LHCALL_NEW_PGTABLE 4
+#define LHCALL_FLUSH_TLB 5
+#define LHCALL_LOAD_IDT_ENTRY 6
+#define LHCALL_SET_STACK 7
+#define LHCALL_TS 8
+#define LHCALL_SET_CLOCKEVENT 9
+#define LHCALL_HALT 10
+#define LHCALL_GET_WALLCLOCK 11
+#define LHCALL_BIND_DMA 12
+#define LHCALL_SEND_DMA 13
+#define LHCALL_SET_PTE 14
+#define LHCALL_SET_PMD 15
+#define LHCALL_LOAD_TLS 16
+
+#define LG_CLOCK_MIN_DELTA 100UL
+#define LG_CLOCK_MAX_DELTA ULONG_MAX
+
+#define LGUEST_TRAP_ENTRY 0x1F
+
+static inline unsigned long
+hcall(unsigned long call,
+ unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+ asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY)
+ : "=a"(call)
+ : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3)
+ : "memory");
+ return call;
+}
+
+void async_hcall(unsigned long call,
+ unsigned long arg1, unsigned long arg2, unsigned long arg3);
+
+/* Can't use our min() macro here: needs to be a constant */
+#define LGUEST_IRQS (NR_IRQS < 32 ? NR_IRQS: 32)
+
+#define LHCALL_RING_SIZE 64
+struct hcall_ring
+{
+ u32 eax, edx, ebx, ecx;
+};
+
+/* All the good stuff happens here: guest registers it with LGUEST_INIT */
+struct lguest_data
+{
+/* Fields which change during running: */
+ /* 512 == enabled (same as eflags) */
+ unsigned int irq_enabled;
+ /* Interrupts blocked by guest. */
+ DECLARE_BITMAP(blocked_interrupts, LGUEST_IRQS);
+
+ /* Virtual address of page fault. */
+ unsigned long cr2;
+
+ /* Async hypercall ring. 0xFF == done, 0 == pending. */
+ u8 hcall_status[LHCALL_RING_SIZE];
+ struct hcall_ring hcalls[LHCALL_RING_SIZE];
+
+/* Fields initialized by the hypervisor at boot: */
+ /* Memory not to try to access */
+ unsigned long reserve_mem;
+ /* ID of this guest (used by network driver to set ethernet address) */
+ u16 guestid;
+ /* KHz for the TSC clock. */
+ u32 tsc_khz;
+
+/* Fields initialized by the guest at boot: */
+ /* Instruction range to suppress interrupts even if enabled */
+ unsigned long noirq_start, noirq_end;
+};
+extern struct lguest_data lguest_data;
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_LGUEST_H */
diff --git a/include/linux/lguest_bus.h b/include/linux/lguest_bus.h
new file mode 100644
index 000000000000..c9b4e05fee49
--- /dev/null
+++ b/include/linux/lguest_bus.h
@@ -0,0 +1,48 @@
+#ifndef _ASM_LGUEST_DEVICE_H
+#define _ASM_LGUEST_DEVICE_H
+/* Everything you need to know about lguest devices. */
+#include <linux/device.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+
+struct lguest_device {
+ /* Unique busid, and index into lguest_page->devices[] */
+ unsigned int index;
+
+ struct device dev;
+
+ /* Driver can hang data off here. */
+ void *private;
+};
+
+/* By convention, each device can use irq index+1 if it wants to. */
+static inline int lgdev_irq(const struct lguest_device *dev)
+{
+ return dev->index + 1;
+}
+
+/* dma args must not be vmalloced! */
+void lguest_send_dma(unsigned long key, struct lguest_dma *dma);
+int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
+ unsigned int num, u8 irq);
+void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas);
+
+/* Map the virtual device space */
+void *lguest_map(unsigned long phys_addr, unsigned long pages);
+void lguest_unmap(void *);
+
+struct lguest_driver {
+ const char *name;
+ struct module *owner;
+ u16 device_type;
+ int (*probe)(struct lguest_device *dev);
+ void (*remove)(struct lguest_device *dev);
+
+ struct device_driver drv;
+};
+
+extern int register_lguest_driver(struct lguest_driver *drv);
+extern void unregister_lguest_driver(struct lguest_driver *drv);
+
+extern struct lguest_device_desc *lguest_devices; /* Just past max_pfn */
+#endif /* _ASM_LGUEST_DEVICE_H */
diff --git a/include/linux/lguest_launcher.h b/include/linux/lguest_launcher.h
new file mode 100644
index 000000000000..0ba414a40c80
--- /dev/null
+++ b/include/linux/lguest_launcher.h
@@ -0,0 +1,73 @@
+#ifndef _ASM_LGUEST_USER
+#define _ASM_LGUEST_USER
+/* Everything the "lguest" userspace program needs to know. */
+/* They can register up to 32 arrays of lguest_dma. */
+#define LGUEST_MAX_DMA 32
+/* At most we can dma 16 lguest_dma in one op. */
+#define LGUEST_MAX_DMA_SECTIONS 16
+
+/* How many devices? Assume each one wants up to two dma arrays per device. */
+#define LGUEST_MAX_DEVICES (LGUEST_MAX_DMA/2)
+
+struct lguest_dma
+{
+ /* 0 if free to be used, filled by hypervisor. */
+ u32 used_len;
+ unsigned long addr[LGUEST_MAX_DMA_SECTIONS];
+ u16 len[LGUEST_MAX_DMA_SECTIONS];
+};
+
+struct lguest_block_page
+{
+ /* 0 is a read, 1 is a write. */
+ int type;
+ u32 sector; /* Offset in device = sector * 512. */
+ u32 bytes; /* Length expected to be read/written in bytes */
+ /* 0 = pending, 1 = done, 2 = done, error */
+ int result;
+ u32 num_sectors; /* Disk length = num_sectors * 512 */
+};
+
+/* There is a shared page of these. */
+struct lguest_net
+{
+ /* Simply the mac address (with multicast bit meaning promisc). */
+ unsigned char mac[6];
+};
+
+/* Where the Host expects the Guest to SEND_DMA console output to. */
+#define LGUEST_CONSOLE_DMA_KEY 0
+
+/* We have a page of these descriptors in the lguest_device page. */
+struct lguest_device_desc {
+ u16 type;
+#define LGUEST_DEVICE_T_CONSOLE 1
+#define LGUEST_DEVICE_T_NET 2
+#define LGUEST_DEVICE_T_BLOCK 3
+
+ u16 features;
+#define LGUEST_NET_F_NOCSUM 0x4000 /* Don't bother checksumming */
+#define LGUEST_DEVICE_F_RANDOMNESS 0x8000 /* IRQ is fairly random */
+
+ u16 status;
+/* 256 and above are device specific. */
+#define LGUEST_DEVICE_S_ACKNOWLEDGE 1 /* We have seen device. */
+#define LGUEST_DEVICE_S_DRIVER 2 /* We have found a driver */
+#define LGUEST_DEVICE_S_DRIVER_OK 4 /* Driver says OK! */
+#define LGUEST_DEVICE_S_REMOVED 8 /* Device has gone away. */
+#define LGUEST_DEVICE_S_REMOVED_ACK 16 /* Driver has been told. */
+#define LGUEST_DEVICE_S_FAILED 128 /* Something actually failed */
+
+ u16 num_pages;
+ u32 pfn;
+};
+
+/* Write command first word is a request. */
+enum lguest_req
+{
+ LHREQ_INITIALIZE, /* + pfnlimit, pgdir, start, pageoffset */
+ LHREQ_GETDMA, /* + addr (returns &lguest_dma, irq in ->used_len) */
+ LHREQ_IRQ, /* + irq */
+ LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
+};
+#endif /* _ASM_LGUEST_USER */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index a3df64677ac3..9aa6c10f7bb1 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -196,7 +196,6 @@ enum {
ATA_PFLAG_SCSI_HOTPLUG = (1 << 6), /* SCSI hotplug scheduled */
ATA_PFLAG_INITIALIZING = (1 << 7), /* being initialized, don't touch */
- ATA_PFLAG_FLUSH_PORT_TASK = (1 << 16), /* flush port task */
ATA_PFLAG_SUSPENDED = (1 << 17), /* port is suspended (power) */
ATA_PFLAG_PM_PENDING = (1 << 18), /* PM operation pending */
ATA_PFLAG_GTM_VALID = (1 << 19), /* acpi_gtm data valid */
@@ -324,6 +323,7 @@ enum ata_completion_errors {
AC_ERR_INVALID = (1 << 7), /* invalid argument */
AC_ERR_OTHER = (1 << 8), /* unknown */
AC_ERR_NODEV_HINT = (1 << 9), /* polling device detection hint */
+ AC_ERR_NCQ = (1 << 10), /* marker for offending NCQ qc */
};
/* forward declarations */
@@ -412,6 +412,7 @@ struct ata_queued_cmd {
ata_qc_cb_t complete_fn;
void *private_data;
+ void *lldd_task;
};
struct ata_port_stats {
@@ -435,6 +436,7 @@ struct ata_device {
struct ata_port *ap;
unsigned int devno; /* 0 or 1 */
unsigned long flags; /* ATA_DFLAG_xxx */
+ unsigned int horkage; /* List of broken features */
struct scsi_device *sdev; /* attached SCSI device */
#ifdef CONFIG_ATA_ACPI
acpi_handle acpi_handle;
@@ -466,7 +468,6 @@ struct ata_device {
/* error history */
struct ata_ering ering;
int spdn_cnt;
- unsigned int horkage; /* List of broken features */
};
/* Offset into struct ata_device. Fields above it are maintained
@@ -531,6 +532,7 @@ struct ata_port {
unsigned int cbl; /* cable type; ATA_CBL_xxx */
unsigned int hw_sata_spd_limit;
unsigned int sata_spd_limit; /* SATA PHY speed limit */
+ unsigned int sata_spd; /* current SATA PHY speed */
/* record runtime error info, protected by host lock */
struct ata_eh_info eh_info;
@@ -564,6 +566,9 @@ struct ata_port {
pm_message_t pm_mesg;
int *pm_result;
+ struct timer_list fastdrain_timer;
+ unsigned long fastdrain_cnt;
+
void *private_data;
#ifdef CONFIG_ATA_ACPI
@@ -620,9 +625,8 @@ struct ata_port_operations {
u8 (*irq_on) (struct ata_port *);
u8 (*irq_ack) (struct ata_port *ap, unsigned int chk_drq);
- u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
- void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
- u32 val);
+ int (*scr_read) (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+ int (*scr_write) (struct ata_port *ap, unsigned int sc_reg, u32 val);
int (*port_suspend) (struct ata_port *ap, pm_message_t mesg);
int (*port_resume) (struct ata_port *ap);
@@ -765,7 +769,8 @@ extern unsigned int ata_dev_try_classify(struct ata_port *, unsigned int, u8 *);
*/
extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+ u8 pmp, int is_cmd, u8 *fis);
extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
@@ -794,7 +799,6 @@ extern void ata_id_string(const u16 *id, unsigned char *s,
extern void ata_id_c_string(const u16 *id, unsigned char *s,
unsigned int ofs, unsigned int len);
extern void ata_id_to_dma_mode(struct ata_device *dev, u8 unknown);
-extern unsigned long ata_device_blacklisted(const struct ata_device *dev);
extern void ata_bmdma_setup (struct ata_queued_cmd *qc);
extern void ata_bmdma_start (struct ata_queued_cmd *qc);
extern void ata_bmdma_stop(struct ata_queued_cmd *qc);
@@ -871,11 +875,11 @@ struct pci_bits {
unsigned long val;
};
-extern int ata_pci_init_native_host(struct ata_host *host);
+extern int ata_pci_init_sff_host(struct ata_host *host);
extern int ata_pci_init_bmdma(struct ata_host *host);
-extern int ata_pci_prepare_native_host(struct pci_dev *pdev,
- const struct ata_port_info * const * ppi,
- struct ata_host **r_host);
+extern int ata_pci_prepare_sff_host(struct pci_dev *pdev,
+ const struct ata_port_info * const * ppi,
+ struct ata_host **r_host);
extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits);
extern unsigned long ata_pci_default_filter(struct ata_device *, unsigned long);
#endif /* CONFIG_PCI */
@@ -911,27 +915,21 @@ extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
/*
* ata_eh_info helpers
*/
-#define ata_ehi_push_desc(ehi, fmt, args...) do { \
- (ehi)->desc_len += scnprintf((ehi)->desc + (ehi)->desc_len, \
- ATA_EH_DESC_LEN - (ehi)->desc_len, \
- fmt , ##args); \
-} while (0)
-
-#define ata_ehi_clear_desc(ehi) do { \
- (ehi)->desc[0] = '\0'; \
- (ehi)->desc_len = 0; \
-} while (0)
-
-static inline void __ata_ehi_hotplugged(struct ata_eh_info *ehi)
+extern void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...);
+extern void ata_ehi_clear_desc(struct ata_eh_info *ehi);
+
+static inline void ata_ehi_schedule_probe(struct ata_eh_info *ehi)
{
- ehi->flags |= ATA_EHI_HOTPLUGGED | ATA_EHI_RESUME_LINK;
+ ehi->flags |= ATA_EHI_RESUME_LINK;
ehi->action |= ATA_EH_SOFTRESET;
ehi->probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
}
static inline void ata_ehi_hotplugged(struct ata_eh_info *ehi)
{
- __ata_ehi_hotplugged(ehi);
+ ata_ehi_schedule_probe(ehi);
+ ehi->flags |= ATA_EHI_HOTPLUGGED;
ehi->err_mask |= AC_ERR_ATA_BUS;
}
diff --git a/include/linux/limits.h b/include/linux/limits.h
index eaf2e099f125..2d0f94162fb3 100644
--- a/include/linux/limits.h
+++ b/include/linux/limits.h
@@ -5,8 +5,6 @@
#define NGROUPS_MAX 65536 /* supplemental group IDs are available */
#define ARG_MAX 131072 /* # bytes of args + environ for exec() */
-#define CHILD_MAX 999 /* no limit :-) */
-#define OPEN_MAX 256 /* # open files a process may have */
#define LINK_MAX 127 /* # links a file may have */
#define MAX_CANON 255 /* size of the canonical input queue */
#define MAX_INPUT 255 /* size of the type-ahead buffer */
diff --git a/include/linux/linux_logo.h b/include/linux/linux_logo.h
index 9c01bde5bf1b..08a92969c76e 100644
--- a/include/linux/linux_logo.h
+++ b/include/linux/linux_logo.h
@@ -33,5 +33,13 @@ struct linux_logo {
};
extern const struct linux_logo *fb_find_logo(int depth);
+#ifdef CONFIG_FB_LOGO_EXTRA
+extern void fb_append_extra_logo(const struct linux_logo *logo,
+ unsigned int n);
+#else
+static inline void fb_append_extra_logo(const struct linux_logo *logo,
+ unsigned int n)
+{}
+#endif
#endif /* _LINUX_LINUX_LOGO_H */
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 246de1d84a26..6f1637c61e10 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -27,6 +27,7 @@ struct nlmsvc_binding {
struct nfs_fh *,
struct file **);
void (*fclose)(struct file *);
+ unsigned long (*get_grace_period)(void);
};
extern struct nlmsvc_binding * nlmsvc_ops;
@@ -38,4 +39,12 @@ extern int nlmclnt_proc(struct inode *, int, struct file_lock *);
extern int lockd_up(int proto);
extern void lockd_down(void);
+unsigned long get_nfs_grace_period(void);
+
+#ifdef CONFIG_NFSD_V4
+unsigned long get_nfs4_grace_period(void);
+#else
+static inline unsigned long get_nfs4_grace_period(void) {return 0;}
+#endif
+
#endif /* LINUX_LOCKD_BIND_H */
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 05707e2fccae..e2d1ce36b367 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -39,6 +39,7 @@
struct nlm_host {
struct hlist_node h_hash; /* doubly linked list */
struct sockaddr_in h_addr; /* peer address */
+ struct sockaddr_in h_saddr; /* our address (optional) */
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
char * h_name; /* remote hostname */
u32 h_version; /* interface version */
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 14c937d345cb..0e843bf65877 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -1,7 +1,8 @@
/*
* Runtime locking correctness validator
*
- * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
*
* see Documentation/lockdep-design.txt for more details.
*/
@@ -9,6 +10,7 @@
#define __LINUX_LOCKDEP_H
struct task_struct;
+struct lockdep_map;
#ifdef CONFIG_LOCKDEP
@@ -114,8 +116,44 @@ struct lock_class {
const char *name;
int name_version;
+
+#ifdef CONFIG_LOCK_STAT
+ unsigned long contention_point[4];
+#endif
+};
+
+#ifdef CONFIG_LOCK_STAT
+struct lock_time {
+ s64 min;
+ s64 max;
+ s64 total;
+ unsigned long nr;
+};
+
+enum bounce_type {
+ bounce_acquired_write,
+ bounce_acquired_read,
+ bounce_contended_write,
+ bounce_contended_read,
+ nr_bounce_types,
+
+ bounce_acquired = bounce_acquired_write,
+ bounce_contended = bounce_contended_write,
};
+struct lock_class_stats {
+ unsigned long contention_point[4];
+ struct lock_time read_waittime;
+ struct lock_time write_waittime;
+ struct lock_time read_holdtime;
+ struct lock_time write_holdtime;
+ unsigned long bounces[nr_bounce_types];
+};
+
+struct lock_class_stats lock_stats(struct lock_class *class);
+void clear_lock_stats(struct lock_class *class);
+#endif
+
/*
* Map the lock object (the lock instance) to the lock-class object.
* This is embedded into specific lock instances:
@@ -124,6 +162,9 @@ struct lockdep_map {
struct lock_class_key *key;
struct lock_class *class_cache;
const char *name;
+#ifdef CONFIG_LOCK_STAT
+ int cpu;
+#endif
};
/*
@@ -165,6 +206,10 @@ struct held_lock {
unsigned long acquire_ip;
struct lockdep_map *instance;
+#ifdef CONFIG_LOCK_STAT
+ u64 waittime_stamp;
+ u64 holdtime_stamp;
+#endif
/*
* The lock-stack is unified in that the lock chains of interrupt
* contexts nest ontop of process context chains, but we 'separate'
@@ -281,6 +326,30 @@ struct lock_class_key { };
#endif /* !LOCKDEP */
+#ifdef CONFIG_LOCK_STAT
+
+extern void lock_contended(struct lockdep_map *lock, unsigned long ip);
+extern void lock_acquired(struct lockdep_map *lock);
+
+#define LOCK_CONTENDED(_lock, try, lock) \
+do { \
+ if (!try(_lock)) { \
+ lock_contended(&(_lock)->dep_map, _RET_IP_); \
+ lock(_lock); \
+ } \
+ lock_acquired(&(_lock)->dep_map); \
+} while (0)
+
+#else /* CONFIG_LOCK_STAT */
+
+#define lock_contended(lockdep_map, ip) do {} while (0)
+#define lock_acquired(lockdep_map) do {} while (0)
+
+#define LOCK_CONTENDED(_lock, try, lock) \
+ lock(_lock)
+
+#endif /* CONFIG_LOCK_STAT */
+
#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_GENERIC_HARDIRQS)
extern void early_init_irq_lock_class(void);
#else
diff --git a/include/linux/lzo.h b/include/linux/lzo.h
index 582d8b711a13..d793497ec1ca 100644
--- a/include/linux/lzo.h
+++ b/include/linux/lzo.h
@@ -17,7 +17,7 @@
#define LZO1X_MEM_COMPRESS (16384 * sizeof(unsigned char *))
#define LZO1X_1_MEM_COMPRESS LZO1X_MEM_COMPRESS
-#define lzo1x_worst_compress(x) (x + (x / 64) + 16 + 3)
+#define lzo1x_worst_compress(x) ((x) + ((x) / 16) + 64 + 3)
/* This requires 'workmem' of size LZO1X_1_MEM_COMPRESS */
int lzo1x_1_compress(const unsigned char *src, size_t src_len,
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 9d713c03e3da..36cc20dfd142 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -13,7 +13,6 @@
#define HPFS_SUPER_MAGIC 0xf995e849
#define ISOFS_SUPER_MAGIC 0x9660
#define JFFS2_SUPER_MAGIC 0x72b6
-#define KVMFS_SUPER_MAGIC 0x19700426
#define ANON_INODE_FS_MAGIC 0x09041934
#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
diff --git a/include/linux/major.h b/include/linux/major.h
index 7e7c9093919a..0cb98053537a 100644
--- a/include/linux/major.h
+++ b/include/linux/major.h
@@ -158,6 +158,8 @@
#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */
#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */
+#define XENVBD_MAJOR 202 /* Xen virtual block device */
+
#define MSR_MAJOR 202
#define CPUID_MAJOR 203
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index daabb3aa1ec6..e147cf50529f 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -159,7 +159,7 @@ 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);
+ unsigned long addr, gfp_t gfp_flags);
extern unsigned slab_node(struct mempolicy *policy);
extern enum zone_type policy_zone;
@@ -256,9 +256,9 @@ static inline void mpol_fix_fork_child_flag(struct task_struct *p)
#define set_cpuset_being_rebound(x) do {} while (0)
static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma,
- unsigned long addr)
+ unsigned long addr, gfp_t gfp_flags)
{
- return NODE_DATA(0)->node_zonelists + gfp_zone(GFP_HIGHUSER);
+ return NODE_DATA(0)->node_zonelists + gfp_zone(gfp_flags);
}
static inline int do_migrate_pages(struct mm_struct *mm,
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index b372f5910fc1..cfb78fb2c046 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -172,6 +172,7 @@ struct mlx4_caps {
int num_pds;
int reserved_pds;
int mtt_entry_sz;
+ u32 max_msg_sz;
u32 page_size_cap;
u32 flags;
u16 stat_rate_support;
@@ -322,6 +323,7 @@ int mlx4_srq_alloc(struct mlx4_dev *dev, u32 pdn, struct mlx4_mtt *mtt,
u64 db_rec, struct mlx4_srq *srq);
void mlx4_srq_free(struct mlx4_dev *dev, struct mlx4_srq *srq);
int mlx4_srq_arm(struct mlx4_dev *dev, struct mlx4_srq *srq, int limit_watermark);
+int mlx4_srq_query(struct mlx4_dev *dev, struct mlx4_srq *srq, int *limit_watermark);
int mlx4_INIT_PORT(struct mlx4_dev *dev, int port);
int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port);
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
index 10c57d279144..3968b943259a 100644
--- a/include/linux/mlx4/qp.h
+++ b/include/linux/mlx4/qp.h
@@ -282,6 +282,9 @@ int mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar,
int sqd_event, struct mlx4_qp *qp);
+int mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp,
+ struct mlx4_qp_context *context);
+
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 1c1207472bb4..c456c3a1c28e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,7 +2,6 @@
#define _LINUX_MM_H
#include <linux/errno.h>
-#include <linux/capability.h>
#ifdef __KERNEL__
@@ -27,7 +26,6 @@ extern unsigned long max_mapnr;
extern unsigned long num_physpages;
extern void * high_memory;
-extern unsigned long vmalloc_earlyreserve;
extern int page_cluster;
#ifdef CONFIG_SYSCTL
@@ -170,6 +168,8 @@ extern unsigned int kobjsize(const void *objp);
#define VM_INSERTPAGE 0x02000000 /* The vma has had "vm_insert_page()" done on it */
#define VM_ALWAYSDUMP 0x04000000 /* Always include in core dumps */
+#define VM_CAN_NONLINEAR 0x08000000 /* Has ->fault & does nonlinear pages */
+
#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
#endif
@@ -192,6 +192,30 @@ extern unsigned int kobjsize(const void *objp);
*/
extern pgprot_t protection_map[16];
+#define FAULT_FLAG_WRITE 0x01 /* Fault was a write access */
+#define FAULT_FLAG_NONLINEAR 0x02 /* Fault was via a nonlinear mapping */
+
+
+/*
+ * vm_fault is filled by the the pagefault handler and passed to the vma's
+ * ->fault function. The vma's ->fault is responsible for returning a bitmask
+ * of VM_FAULT_xxx flags that give details about how the fault was handled.
+ *
+ * pgoff should be used in favour of virtual_address, if possible. If pgoff
+ * is used, one may set VM_CAN_NONLINEAR in the vma->vm_flags to get nonlinear
+ * mapping support.
+ */
+struct vm_fault {
+ unsigned int flags; /* FAULT_FLAG_xxx flags */
+ pgoff_t pgoff; /* Logical page offset based on vma */
+ void __user *virtual_address; /* Faulting virtual address */
+
+ struct page *page; /* ->fault handlers should return a
+ * page here, unless VM_FAULT_NOPAGE
+ * is set (which is also implied by
+ * VM_FAULT_ERROR).
+ */
+};
/*
* These are the virtual MM functions - opening of an area, closing and
@@ -201,9 +225,11 @@ extern pgprot_t protection_map[16];
struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
- struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type);
- unsigned long (*nopfn)(struct vm_area_struct * area, unsigned long address);
- int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);
+ 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);
/* notification that a previously read-only page is about to become
* writable, if an error is returned it will cause a SIGBUS */
@@ -601,6 +627,7 @@ static inline struct address_space *page_mapping(struct page *page)
{
struct address_space *mapping = page->mapping;
+ VM_BUG_ON(PageSlab(page));
if (unlikely(PageSwapCache(page)))
mapping = &swapper_space;
#ifdef CONFIG_SLUB
@@ -656,7 +683,6 @@ static inline int page_mapped(struct page *page)
*/
#define NOPAGE_SIGBUS (NULL)
#define NOPAGE_OOM ((struct page *) (-1))
-#define NOPAGE_REFAULT ((struct page *) (-2)) /* Return to userspace, rerun */
/*
* Error return values for the *_nopfn functions
@@ -670,16 +696,18 @@ static inline int page_mapped(struct page *page)
* Used to decide whether a process gets delivered SIGBUS or
* just gets major/minor fault counters bumped up.
*/
-#define VM_FAULT_OOM 0x00
-#define VM_FAULT_SIGBUS 0x01
-#define VM_FAULT_MINOR 0x02
-#define VM_FAULT_MAJOR 0x03
-
-/*
- * Special case for get_user_pages.
- * Must be in a distinct bit from the above VM_FAULT_ flags.
- */
-#define VM_FAULT_WRITE 0x10
+
+#define VM_FAULT_MINOR 0 /* For backwards compat. Remove me quickly. */
+
+#define VM_FAULT_OOM 0x0001
+#define VM_FAULT_SIGBUS 0x0002
+#define VM_FAULT_MAJOR 0x0004
+#define VM_FAULT_WRITE 0x0008 /* Special case for get_user_pages */
+
+#define VM_FAULT_NOPAGE 0x0100 /* ->fault installed the pte, not return page */
+#define VM_FAULT_LOCKED 0x0200 /* ->fault locked the returned page */
+
+#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS)
#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
@@ -763,20 +791,10 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping,
extern int vmtruncate(struct inode * inode, loff_t offset);
extern int vmtruncate_range(struct inode * inode, loff_t offset, loff_t end);
-extern int install_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, struct page *page, pgprot_t prot);
-extern int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, unsigned long pgoff, pgprot_t prot);
#ifdef CONFIG_MMU
-extern int __handle_mm_fault(struct mm_struct *mm,struct vm_area_struct *vma,
+extern int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, int write_access);
-
-static inline int handle_mm_fault(struct mm_struct *mm,
- struct vm_area_struct *vma, unsigned long address,
- int write_access)
-{
- return __handle_mm_fault(mm, vma, address, write_access) &
- (~VM_FAULT_WRITE);
-}
#else
static inline int handle_mm_fault(struct mm_struct *mm,
struct vm_area_struct *vma, unsigned long address,
@@ -790,7 +808,6 @@ static inline int handle_mm_fault(struct mm_struct *mm,
extern int make_pages_present(unsigned long addr, unsigned long end);
extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write);
-void install_arg_page(struct vm_area_struct *, struct page *, unsigned long);
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
@@ -807,32 +824,42 @@ int FASTCALL(set_page_dirty(struct page *page));
int set_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struct page *page);
+extern unsigned long move_page_tables(struct vm_area_struct *vma,
+ unsigned long old_addr, struct vm_area_struct *new_vma,
+ unsigned long new_addr, unsigned long len);
extern unsigned long do_mremap(unsigned long addr,
unsigned long old_len, unsigned long new_len,
unsigned long flags, unsigned long new_addr);
+extern int mprotect_fixup(struct vm_area_struct *vma,
+ struct vm_area_struct **pprev, unsigned long start,
+ unsigned long end, unsigned long newflags);
/*
- * Prototype to add a shrinker callback for ageable caches.
- *
- * These functions are passed a count `nr_to_scan' and a gfpmask. They should
- * scan `nr_to_scan' objects, attempting to free them.
+ * A callback you can register to apply pressure to ageable caches.
*
- * The callback must return the number of objects which remain in the cache.
+ * 'shrink' is passed a count 'nr_to_scan' and a 'gfpmask'. It should
+ * look through the least-recently-used 'nr_to_scan' entries and
+ * attempt to free them up. It should return the number of objects
+ * which remain in the cache. If it returns -1, it means it cannot do
+ * any scanning at this time (eg. there is a risk of deadlock).
*
- * The callback will be passed nr_to_scan == 0 when the VM is querying the
- * cache size, so a fastpath for that case is appropriate.
- */
-typedef int (*shrinker_t)(int nr_to_scan, gfp_t gfp_mask);
-
-/*
- * Add an aging callback. The int is the number of 'seeks' it takes
- * to recreate one of the objects that these functions age.
+ * The 'gfpmask' refers to the allocation we are currently trying to
+ * fulfil.
+ *
+ * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is
+ * querying the cache size, so a fastpath for that case is appropriate.
*/
+struct shrinker {
+ int (*shrink)(int nr_to_scan, gfp_t gfp_mask);
+ int seeks; /* seeks to recreate an obj */
-#define DEFAULT_SEEKS 2
-struct shrinker;
-extern struct shrinker *set_shrinker(int, shrinker_t);
-extern void remove_shrinker(struct shrinker *shrinker);
+ /* These are for internal use */
+ struct list_head list;
+ long nr; /* objs pending delete */
+};
+#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */
+extern void register_shrinker(struct shrinker *);
+extern void unregister_shrinker(struct shrinker *);
/*
* Some shared mappigns will want the pages marked read-only
@@ -1072,6 +1099,10 @@ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned lo
extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
unsigned long flag, unsigned long pgoff);
+extern unsigned long mmap_region(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long flags,
+ unsigned int vm_flags, unsigned long pgoff,
+ int accountable);
static inline unsigned long do_mmap(struct file *file, unsigned long addr,
unsigned long len, unsigned long prot,
@@ -1097,9 +1128,7 @@ extern void truncate_inode_pages_range(struct address_space *,
loff_t lstart, loff_t lend);
/* generic vm_area_ops exported for stackable file systems */
-extern struct page *filemap_nopage(struct vm_area_struct *, unsigned long, int *);
-extern int filemap_populate(struct vm_area_struct *, unsigned long,
- unsigned long, pgprot_t, unsigned long, int);
+extern int filemap_fault(struct vm_area_struct *, struct vm_fault *);
/* mm/page-writeback.c */
int write_one_page(struct page *page, int wait);
@@ -1114,13 +1143,20 @@ int do_page_cache_readahead(struct address_space *mapping, struct file *filp,
pgoff_t offset, unsigned long nr_to_read);
int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
pgoff_t offset, unsigned long nr_to_read);
-unsigned long page_cache_readahead(struct address_space *mapping,
- struct file_ra_state *ra,
- struct file *filp,
- pgoff_t offset,
- unsigned long size);
-void handle_ra_miss(struct address_space *mapping,
- struct file_ra_state *ra, pgoff_t offset);
+
+void page_cache_sync_readahead(struct address_space *mapping,
+ struct file_ra_state *ra,
+ struct file *filp,
+ pgoff_t offset,
+ unsigned long size);
+
+void page_cache_async_readahead(struct address_space *mapping,
+ struct file_ra_state *ra,
+ struct file *filp,
+ struct page *pg,
+ pgoff_t offset,
+ unsigned long size);
+
unsigned long max_sane_readahead(unsigned long nr);
/* Do stack extension */
@@ -1128,6 +1164,8 @@ extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
#ifdef CONFIG_IA64
extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
#endif
+extern int expand_stack_downwards(struct vm_area_struct *vma,
+ unsigned long address);
/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */
extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index d09b1345a3a1..da8eb8ad9e9b 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -24,6 +24,14 @@
#endif
#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))
+/*
+ * PAGE_ALLOC_COSTLY_ORDER is the order at which allocations are deemed
+ * costly to service. That is between allocation orders which should
+ * coelesce naturally under reasonable reclaim pressure and those which
+ * will not.
+ */
+#define PAGE_ALLOC_COSTLY_ORDER 3
+
struct free_area {
struct list_head free_list;
unsigned long nr_free;
@@ -146,6 +154,7 @@ enum zone_type {
*/
ZONE_HIGHMEM,
#endif
+ ZONE_MOVABLE,
MAX_NR_ZONES
};
@@ -167,6 +176,7 @@ enum zone_type {
+ defined(CONFIG_ZONE_DMA32) \
+ 1 \
+ defined(CONFIG_HIGHMEM) \
+ + 1 \
)
#if __ZONE_COUNT < 2
#define ZONES_SHIFT 0
@@ -499,10 +509,22 @@ static inline int populated_zone(struct zone *zone)
return (!!zone->present_pages);
}
+extern int movable_zone;
+
+static inline int zone_movable_is_highmem(void)
+{
+#if defined(CONFIG_HIGHMEM) && defined(CONFIG_ARCH_POPULATES_NODE_MAP)
+ return movable_zone == ZONE_HIGHMEM;
+#else
+ return 0;
+#endif
+}
+
static inline int is_highmem_idx(enum zone_type idx)
{
#ifdef CONFIG_HIGHMEM
- return (idx == ZONE_HIGHMEM);
+ return (idx == ZONE_HIGHMEM ||
+ (idx == ZONE_MOVABLE && zone_movable_is_highmem()));
#else
return 0;
#endif
@@ -522,7 +544,9 @@ static inline int is_normal_idx(enum zone_type idx)
static inline int is_highmem(struct zone *zone)
{
#ifdef CONFIG_HIGHMEM
- return zone == zone->zone_pgdat->node_zones + ZONE_HIGHMEM;
+ int zone_idx = zone - zone->zone_pgdat->node_zones;
+ return zone_idx == ZONE_HIGHMEM ||
+ (zone_idx == ZONE_MOVABLE && zone_movable_is_highmem());
#else
return 0;
#endif
@@ -566,6 +590,11 @@ int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *, int,
int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *, int,
struct file *, void __user *, size_t *, loff_t *);
+extern int numa_zonelist_order_handler(struct ctl_table *, int,
+ struct file *, void __user *, size_t *, loff_t *);
+extern char numa_zonelist_order[];
+#define NUMA_ZONELIST_ORDER_LEN 16 /* string buffer size */
+
#include <linux/topology.h>
/* Returns the number of the current Node. */
#ifndef numa_node_id
diff --git a/include/linux/mnt_namespace.h b/include/linux/mnt_namespace.h
index 1fa4d9813b31..8eed44f8ca73 100644
--- a/include/linux/mnt_namespace.h
+++ b/include/linux/mnt_namespace.h
@@ -14,7 +14,7 @@ struct mnt_namespace {
int event;
};
-extern struct mnt_namespace *copy_mnt_ns(int, struct mnt_namespace *,
+extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
struct fs_struct *);
extern void __put_mnt_ns(struct mnt_namespace *ns);
diff --git a/include/linux/module.h b/include/linux/module.h
index e6e0f86ef5fc..b6a646cea1cb 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -6,7 +6,6 @@
* Rewritten by Richard Henderson <rth@tamu.edu> Dec 1996
* Rewritten again by Rusty Russell, 2002
*/
-#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/stat.h>
#include <linux/compiler.h>
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 0e09c005dda8..f950921523f5 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -146,7 +146,7 @@ struct fat_boot_fsinfo {
};
struct msdos_dir_entry {
- __u8 name[8],ext[3]; /* name and extension */
+ __u8 name[MSDOS_NAME];/* name and extension */
__u8 attr; /* attribute bits */
__u8 lcase; /* Case for base and extension */
__u8 ctime_cs; /* Creation time, centiseconds (0-199) */
diff --git a/include/linux/namei.h b/include/linux/namei.h
index b7dd24917f0d..6c38efbd810f 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -69,8 +69,8 @@ extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struc
#define user_path_walk_link(name,nd) \
__user_walk_fd(AT_FDCWD, name, 0, nd)
extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
-extern int FASTCALL(path_walk(const char *, struct nameidata *));
-extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
+extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+ const char *, unsigned int, struct nameidata *);
extern void path_release(struct nameidata *);
extern void path_release_on_umount(struct nameidata *);
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index 83e39eb054d3..88766e43e121 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -148,8 +148,6 @@ struct ncp_nls_ioctl
#include <linux/ncp_fs_i.h>
#include <linux/ncp_fs_sb.h>
-/* undef because public define in umsdos_fs.h (ncp_fs.h isn't public) */
-#undef PRINTK
/* define because it is easy to change PRINTK to {*}PRINTK */
#define PRINTK(format, args...) printk(KERN_DEBUG format , ## args)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3a70f553b28f..4a616d73cc25 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -108,6 +108,14 @@ struct wireless_dev;
#define MAX_HEADER (LL_MAX_HEADER + 48)
#endif
+struct net_device_subqueue
+{
+ /* Give a control state for each queue. This struct may contain
+ * per-queue locks in the future.
+ */
+ unsigned long state;
+};
+
/*
* Network device statistics. Akin to the 2.0 ether stats but
* with byte counters.
@@ -177,19 +185,25 @@ struct netif_rx_stats
DECLARE_PER_CPU(struct netif_rx_stats, netdev_rx_stat);
+struct dev_addr_list
+{
+ struct dev_addr_list *next;
+ u8 da_addr[MAX_ADDR_LEN];
+ u8 da_addrlen;
+ u8 da_synced;
+ int da_users;
+ int da_gusers;
+};
/*
* We tag multicasts with these structures.
*/
-
-struct dev_mc_list
-{
- struct dev_mc_list *next;
- __u8 dmi_addr[MAX_ADDR_LEN];
- unsigned char dmi_addrlen;
- int dmi_users;
- int dmi_gusers;
-};
+
+#define dev_mc_list dev_addr_list
+#define dmi_addr da_addr
+#define dmi_addrlen da_addrlen
+#define dmi_users da_users
+#define dmi_gusers da_gusers
struct hh_cache
{
@@ -314,9 +328,10 @@ struct net_device
/* Net device features */
unsigned long features;
#define NETIF_F_SG 1 /* Scatter/gather IO. */
-#define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */
+#define NETIF_F_IP_CSUM 2 /* Can checksum TCP/UDP over IPv4. */
#define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */
#define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */
+#define NETIF_F_IPV6_CSUM 16 /* Can checksum TCP/UDP over IPV6 */
#define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */
#define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */
#define NETIF_F_HW_VLAN_TX 128 /* Transmit VLAN hw acceleration */
@@ -325,6 +340,7 @@ struct net_device
#define NETIF_F_VLAN_CHALLENGED 1024 /* Device cannot handle VLAN packets */
#define NETIF_F_GSO 2048 /* Enable software GSO. */
#define NETIF_F_LLTX 4096 /* LockLess TX */
+#define NETIF_F_MULTI_QUEUE 16384 /* Has multiple TX/RX queues */
/* Segmentation offload features */
#define NETIF_F_GSO_SHIFT 16
@@ -338,8 +354,11 @@ struct net_device
/* List of features with software fallbacks. */
#define NETIF_F_GSO_SOFTWARE (NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6)
+
#define NETIF_F_GEN_CSUM (NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
-#define NETIF_F_ALL_CSUM (NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
+#define NETIF_F_V4_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IP_CSUM)
+#define NETIF_F_V6_CSUM (NETIF_F_GEN_CSUM | NETIF_F_IPV6_CSUM)
+#define NETIF_F_ALL_CSUM (NETIF_F_V4_CSUM | NETIF_F_V6_CSUM)
struct net_device *next_sched;
@@ -388,7 +407,10 @@ struct net_device
unsigned char addr_len; /* hardware address length */
unsigned short dev_id; /* for shared network cards */
- struct dev_mc_list *mc_list; /* Multicast mac addresses */
+ struct dev_addr_list *uc_list; /* Secondary unicast mac addresses */
+ int uc_count; /* Number of installed ucasts */
+ int uc_promisc;
+ struct dev_addr_list *mc_list; /* Multicast mac addresses */
int mc_count; /* Number of installed mcasts */
int promiscuity;
int allmulti;
@@ -493,6 +515,11 @@ struct net_device
void *saddr,
unsigned len);
int (*rebuild_header)(struct sk_buff *skb);
+#define HAVE_CHANGE_RX_FLAGS
+ void (*change_rx_flags)(struct net_device *dev,
+ int flags);
+#define HAVE_SET_RX_MODE
+ void (*set_rx_mode)(struct net_device *dev);
#define HAVE_MULTICAST
void (*set_multicast_list)(struct net_device *dev);
#define HAVE_SET_MAC_ADDR
@@ -535,22 +562,29 @@ struct net_device
/* bridge stuff */
struct net_bridge_port *br_port;
+ /* macvlan */
+ struct macvlan_port *macvlan_port;
/* class/net/name entry */
struct device dev;
/* space for optional statistics and wireless sysfs groups */
struct attribute_group *sysfs_groups[3];
+
+ /* rtnetlink link ops */
+ const struct rtnl_link_ops *rtnl_link_ops;
+
+ /* The TX queue control structures */
+ unsigned int egress_subqueue_count;
+ struct net_device_subqueue egress_subqueue[1];
};
#define to_net_dev(d) container_of(d, struct net_device, dev)
#define NETDEV_ALIGN 32
#define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1)
-static inline void *netdev_priv(struct net_device *dev)
+static inline void *netdev_priv(const struct net_device *dev)
{
- return (char *)dev + ((sizeof(struct net_device)
- + NETDEV_ALIGN_CONST)
- & ~NETDEV_ALIGN_CONST);
+ return dev->priv;
}
#define SET_MODULE_OWNER(dev) do { } while (0)
@@ -702,6 +736,62 @@ static inline int netif_running(const struct net_device *dev)
return test_bit(__LINK_STATE_START, &dev->state);
}
+/*
+ * Routines to manage the subqueues on a device. We only need start
+ * stop, and a check if it's stopped. All other device management is
+ * done at the overall netdevice level.
+ * Also test the device if we're multiqueue.
+ */
+static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ clear_bit(__LINK_STATE_XOFF, &dev->egress_subqueue[queue_index].state);
+#endif
+}
+
+static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+#ifdef CONFIG_NETPOLL_TRAP
+ if (netpoll_trap())
+ return;
+#endif
+ set_bit(__LINK_STATE_XOFF, &dev->egress_subqueue[queue_index].state);
+#endif
+}
+
+static inline int netif_subqueue_stopped(const struct net_device *dev,
+ u16 queue_index)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ return test_bit(__LINK_STATE_XOFF,
+ &dev->egress_subqueue[queue_index].state);
+#else
+ return 0;
+#endif
+}
+
+static inline void netif_wake_subqueue(struct net_device *dev, u16 queue_index)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+#ifdef CONFIG_NETPOLL_TRAP
+ if (netpoll_trap())
+ return;
+#endif
+ if (test_and_clear_bit(__LINK_STATE_XOFF,
+ &dev->egress_subqueue[queue_index].state))
+ __netif_schedule(dev);
+#endif
+}
+
+static inline int netif_is_multiqueue(const struct net_device *dev)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ return (!!(NETIF_F_MULTI_QUEUE & dev->features));
+#else
+ return 0;
+#endif
+}
/* Use this variant when it is known for sure that it
* is executing from interrupt context.
@@ -992,15 +1082,24 @@ static inline void netif_tx_disable(struct net_device *dev)
extern void ether_setup(struct net_device *dev);
/* Support for loadable net-drivers */
-extern struct net_device *alloc_netdev(int sizeof_priv, const char *name,
- void (*setup)(struct net_device *));
+extern struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
+ void (*setup)(struct net_device *),
+ unsigned int queue_count);
+#define alloc_netdev(sizeof_priv, name, setup) \
+ alloc_netdev_mq(sizeof_priv, name, setup, 1)
extern int register_netdev(struct net_device *dev);
extern void unregister_netdev(struct net_device *dev);
-/* Functions used for multicast support */
-extern void dev_mc_upload(struct net_device *dev);
+/* Functions used for secondary unicast and multicast support */
+extern void dev_set_rx_mode(struct net_device *dev);
+extern void __dev_set_rx_mode(struct net_device *dev);
+extern int dev_unicast_delete(struct net_device *dev, void *addr, int alen);
+extern int dev_unicast_add(struct net_device *dev, void *addr, int alen);
extern int dev_mc_delete(struct net_device *dev, void *addr, int alen, int all);
extern int dev_mc_add(struct net_device *dev, void *addr, int alen, int newonly);
-extern void dev_mc_discard(struct net_device *dev);
+extern int dev_mc_sync(struct net_device *to, struct net_device *from);
+extern void dev_mc_unsync(struct net_device *to, struct net_device *from);
+extern int __dev_addr_delete(struct dev_addr_list **list, int *count, void *addr, int alen, int all);
+extern int __dev_addr_add(struct dev_addr_list **list, int *count, void *addr, int alen, int newonly);
extern void dev_set_promiscuity(struct net_device *dev, int inc);
extern void dev_set_allmulti(struct net_device *dev, int inc);
extern void netdev_state_change(struct net_device *dev);
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 10b5c6275706..0eed0b7ab2df 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -275,7 +275,8 @@ struct nf_queue_handler {
};
extern int nf_register_queue_handler(int pf,
struct nf_queue_handler *qh);
-extern int nf_unregister_queue_handler(int pf);
+extern int nf_unregister_queue_handler(int pf,
+ struct nf_queue_handler *qh);
extern void nf_unregister_queue_handlers(struct nf_queue_handler *qh);
extern void nf_reinject(struct sk_buff *skb,
struct nf_info *info,
diff --git a/include/linux/netfilter/nf_conntrack_pptp.h b/include/linux/netfilter/nf_conntrack_pptp.h
index 9d8144a488cd..c93061f33144 100644
--- a/include/linux/netfilter/nf_conntrack_pptp.h
+++ b/include/linux/netfilter/nf_conntrack_pptp.h
@@ -4,6 +4,8 @@
#include <linux/netfilter/nf_conntrack_common.h>
+extern const char *pptp_msg_name[];
+
/* state of the control session */
enum pptp_ctrlsess_state {
PPTP_SESSION_NONE, /* no session present */
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 7e733a6ba4f6..64f425a855bb 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -141,22 +141,22 @@ struct xt_match
/* Arguments changed since 2.6.9, as this must now handle
non-linear skb, using skb_header_pointer and
skb_ip_make_writable. */
- int (*match)(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct xt_match *match,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop);
+ bool (*match)(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop);
/* Called when user tries to insert an entry of this type. */
/* Should return true or false. */
- int (*checkentry)(const char *tablename,
- const void *ip,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int hook_mask);
+ bool (*checkentry)(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask);
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_match *match, void *matchinfo);
@@ -202,11 +202,11 @@ struct xt_target
hook_mask is a bitmask of hooks from which it can be
called. */
/* Should return true or false. */
- int (*checkentry)(const char *tablename,
- const void *entry,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask);
+ bool (*checkentry)(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask);
/* Called when entry of this type deleted. */
void (*destroy)(const struct xt_target *target, void *targinfo);
diff --git a/include/linux/netfilter/xt_connlimit.h b/include/linux/netfilter/xt_connlimit.h
new file mode 100644
index 000000000000..90ae8b474cb8
--- /dev/null
+++ b/include/linux/netfilter/xt_connlimit.h
@@ -0,0 +1,17 @@
+#ifndef _XT_CONNLIMIT_H
+#define _XT_CONNLIMIT_H
+
+struct xt_connlimit_data;
+
+struct xt_connlimit_info {
+ union {
+ u_int32_t v4_mask;
+ u_int32_t v6_mask[4];
+ };
+ unsigned int limit, inverse;
+
+ /* this needs to be at the end */
+ struct xt_connlimit_data *data __attribute__((aligned(8)));
+};
+
+#endif /* _XT_CONNLIMIT_H */
diff --git a/include/linux/netfilter/xt_u32.h b/include/linux/netfilter/xt_u32.h
new file mode 100644
index 000000000000..9947f56cdbdd
--- /dev/null
+++ b/include/linux/netfilter/xt_u32.h
@@ -0,0 +1,40 @@
+#ifndef _XT_U32_H
+#define _XT_U32_H 1
+
+enum xt_u32_ops {
+ XT_U32_AND,
+ XT_U32_LEFTSH,
+ XT_U32_RIGHTSH,
+ XT_U32_AT,
+};
+
+struct xt_u32_location_element {
+ u_int32_t number;
+ u_int8_t nextop;
+};
+
+struct xt_u32_value_element {
+ u_int32_t min;
+ u_int32_t max;
+};
+
+/*
+ * Any way to allow for an arbitrary number of elements?
+ * For now, I settle with a limit of 10 each.
+ */
+#define XT_U32_MAXSIZE 10
+
+struct xt_u32_test {
+ struct xt_u32_location_element location[XT_U32_MAXSIZE+1];
+ struct xt_u32_value_element value[XT_U32_MAXSIZE+1];
+ u_int8_t nnums;
+ u_int8_t nvalues;
+};
+
+struct xt_u32 {
+ struct xt_u32_test tests[XT_U32_MAXSIZE+1];
+ u_int8_t ntests;
+ u_int8_t invert;
+};
+
+#endif /* _XT_U32_H */
diff --git a/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h b/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h
index d9bceedfb3dc..daf50be22c9d 100644
--- a/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h
+++ b/include/linux/netfilter_ipv4/ipt_CLUSTERIP.h
@@ -18,13 +18,13 @@ struct clusterip_config;
struct ipt_clusterip_tgt_info {
u_int32_t flags;
-
+
/* only relevant for new ones */
u_int8_t clustermac[6];
u_int16_t num_total_nodes;
u_int16_t num_local_nodes;
u_int16_t local_nodes[CLUSTERIP_MAX_NODES];
- enum clusterip_hashmode hash_mode;
+ u_int32_t hash_mode;
u_int32_t hash_initval;
struct clusterip_config *config;
diff --git a/include/linux/netfilter_ipv4/ipt_iprange.h b/include/linux/netfilter_ipv4/ipt_iprange.h
index 34ab0fb736e2..a92fefc3c7ec 100644
--- a/include/linux/netfilter_ipv4/ipt_iprange.h
+++ b/include/linux/netfilter_ipv4/ipt_iprange.h
@@ -1,6 +1,8 @@
#ifndef _IPT_IPRANGE_H
#define _IPT_IPRANGE_H
+#include <linux/types.h>
+
#define IPRANGE_SRC 0x01 /* Match source IP address */
#define IPRANGE_DST 0x02 /* Match destination IP address */
#define IPRANGE_SRC_INV 0x10 /* Negate the condition */
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 4686f8342cbd..9a720f05888f 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -44,8 +44,14 @@ struct ip6t_ip6 {
char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
- /* ARGH, HopByHop uses 0, so can't do 0 = ANY,
- instead IP6T_F_NOPROTO must be set */
+ /* Upper protocol number
+ * - The allowed value is 0 (any) or protocol number of last parsable
+ * header, which is 50 (ESP), 59 (No Next Header), 135 (MH), or
+ * the non IPv6 extension headers.
+ * - The protocol numbers of IPv6 extension headers except of ESP and
+ * MH do not match any packets.
+ * - You also need to set IP6T_FLAGS_PROTO to "flags" to check protocol.
+ */
u_int16_t proto;
/* TOS to match iff flags & IP6T_F_TOS */
u_int8_t tos;
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 2e23353c28a5..83d8239f0cce 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -161,6 +161,8 @@ extern struct sock *netlink_kernel_create(int unit, unsigned int groups,
void (*input)(struct sock *sk, int len),
struct mutex *cb_mutex,
struct module *module);
+extern int netlink_change_ngroups(struct sock *sk, unsigned int groups);
+extern void netlink_clear_multicast_users(struct sock *sk, unsigned int group);
extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err);
extern int netlink_has_listeners(struct sock *sk, unsigned int group);
extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 pid, int nonblock);
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 7e7f33a38fc0..8726491de154 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
+#define NFS4_BITMAP_SIZE 2
#define NFS4_VERIFIER_SIZE 8
#define NFS4_STATEID_SIZE 16
#define NFS4_FHSIZE 128
diff --git a/include/linux/nfs4_mount.h b/include/linux/nfs4_mount.h
index 26b4c83f831d..a0dcf6655657 100644
--- a/include/linux/nfs4_mount.h
+++ b/include/linux/nfs4_mount.h
@@ -65,6 +65,7 @@ struct nfs4_mount_data {
#define NFS4_MOUNT_NOCTO 0x0010 /* 1 */
#define NFS4_MOUNT_NOAC 0x0020 /* 1 */
#define NFS4_MOUNT_STRICTLOCK 0x1000 /* 1 */
-#define NFS4_MOUNT_FLAGMASK 0xFFFF
+#define NFS4_MOUNT_UNSHARED 0x8000 /* 1 */
+#define NFS4_MOUNT_FLAGMASK 0x9033
#endif
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 0543439a97af..9ba4aec37c50 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -30,7 +30,9 @@
#ifdef __KERNEL__
#include <linux/in.h>
+#include <linux/kref.h>
#include <linux/mm.h>
+#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/rbtree.h>
#include <linux/rwsem.h>
@@ -69,9 +71,8 @@ struct nfs_access_entry {
struct nfs4_state;
struct nfs_open_context {
- atomic_t count;
- struct vfsmount *vfsmnt;
- struct dentry *dentry;
+ struct kref kref;
+ struct path path;
struct rpc_cred *cred;
struct nfs4_state *state;
fl_owner_t lockowner;
@@ -155,13 +156,9 @@ struct nfs_inode {
/*
* This is the list of dirty unwritten pages.
*/
- spinlock_t req_lock;
- struct list_head dirty;
- struct list_head commit;
struct radix_tree_root nfs_page_tree;
- unsigned int ndirty,
- ncommit,
+ unsigned long ncommit,
npages;
/* Open contexts for shared mmap writes */
@@ -187,6 +184,7 @@ struct nfs_inode {
#define NFS_INO_INVALID_ACCESS 0x0008 /* cached access cred invalid */
#define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */
#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */
+#define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */
/*
* Bit offsets in flags field
@@ -409,8 +407,8 @@ extern void nfs_release_automount_timer(void);
/*
* linux/fs/nfs/unlink.c
*/
-extern int nfs_async_unlink(struct dentry *);
-extern void nfs_complete_unlink(struct dentry *);
+extern int nfs_async_unlink(struct inode *dir, struct dentry *dentry);
+extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
/*
* linux/fs/nfs/write.c
@@ -496,21 +494,18 @@ static inline void nfs3_forget_cached_acls(struct inode *inode)
/*
* linux/fs/mount_clnt.c
- * (Used only by nfsroot module)
*/
-extern int nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *,
- int, int);
+extern int nfs_mount(struct sockaddr *, size_t, char *, char *,
+ int, int, struct nfs_fh *);
/*
* inline functions
*/
-static inline loff_t
-nfs_size_to_loff_t(__u64 size)
+static inline loff_t nfs_size_to_loff_t(__u64 size)
{
- loff_t maxsz = (((loff_t) ULONG_MAX) << PAGE_CACHE_SHIFT) + PAGE_CACHE_SIZE - 1;
- if (size > maxsz)
- return maxsz;
+ if (size > (__u64) OFFSET_MAX - 1)
+ return OFFSET_MAX - 1;
return (loff_t) size;
}
@@ -557,6 +552,7 @@ extern void * nfs_root_data(void);
#define NFSDBG_ROOT 0x0080
#define NFSDBG_CALLBACK 0x0100
#define NFSDBG_CLIENT 0x0200
+#define NFSDBG_MOUNT 0x0400
#define NFSDBG_ALL 0xFFFF
#ifdef __KERNEL__
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 52b4378311c8..0cac49bc0955 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -16,7 +16,6 @@ struct nfs_client {
#define NFS_CS_INITING 1 /* busy initialising */
int cl_nfsversion; /* NFS protocol version */
unsigned long cl_res_state; /* NFS resources state */
-#define NFS_CS_RPCIOD 0 /* - rpciod started */
#define NFS_CS_CALLBACK 1 /* - callback started */
#define NFS_CS_IDMAP 2 /* - idmap started */
#define NFS_CS_RENEWD 3 /* - renewd started */
@@ -35,7 +34,8 @@ struct nfs_client {
nfs4_verifier cl_confirm;
unsigned long cl_state;
- u32 cl_lockowner_id;
+ struct rb_root cl_openowner_id;
+ struct rb_root cl_lockowner_id;
/*
* The following rwsem ensures exclusive access to the server
@@ -44,9 +44,7 @@ struct nfs_client {
struct rw_semaphore cl_sem;
struct list_head cl_delegations;
- struct list_head cl_state_owners;
- struct list_head cl_unused;
- int cl_nunused;
+ struct rb_root cl_state_owners;
spinlock_t cl_lock;
unsigned long cl_lease_time;
diff --git a/include/linux/nfs_mount.h b/include/linux/nfs_mount.h
index cc8b9c59acb8..a3ade89a64d2 100644
--- a/include/linux/nfs_mount.h
+++ b/include/linux/nfs_mount.h
@@ -37,7 +37,7 @@ struct nfs_mount_data {
int acdirmin; /* 1 */
int acdirmax; /* 1 */
struct sockaddr_in addr; /* 1 */
- char hostname[256]; /* 1 */
+ char hostname[NFS_MAXNAMLEN + 1]; /* 1 */
int namlen; /* 2 */
unsigned int bsize; /* 3 */
struct nfs3_fh root; /* 4 */
@@ -62,6 +62,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
#define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */
+#define NFS_MOUNT_UNSHARED 0x8000 /* 5 */
#define NFS_MOUNT_FLAGMASK 0xFFFF
#endif
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index bd193af80162..78e60798d10e 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -16,12 +16,13 @@
#include <linux/sunrpc/auth.h>
#include <linux/nfs_xdr.h>
-#include <asm/atomic.h>
+#include <linux/kref.h>
/*
* Valid flags for the radix tree
*/
-#define NFS_PAGE_TAG_WRITEBACK 0
+#define NFS_PAGE_TAG_LOCKED 0
+#define NFS_PAGE_TAG_COMMIT 1
/*
* Valid flags for a dirty buffer
@@ -33,8 +34,7 @@
struct nfs_inode;
struct nfs_page {
- struct list_head wb_list, /* Defines state of page: */
- *wb_list_head; /* read/write/commit */
+ struct list_head wb_list; /* Defines state of page: */
struct page *wb_page; /* page to read in/write out */
struct nfs_open_context *wb_context; /* File state context info */
atomic_t wb_complete; /* i/os we're waiting for */
@@ -42,7 +42,7 @@ struct nfs_page {
unsigned int wb_offset, /* Offset & ~PAGE_CACHE_MASK */
wb_pgbase, /* Start of page data */
wb_bytes; /* Length of request */
- atomic_t wb_count; /* reference count */
+ struct kref wb_kref; /* reference count */
unsigned long wb_flags;
struct nfs_writeverf wb_verf; /* Commit cookie */
};
@@ -71,8 +71,8 @@ extern void nfs_clear_request(struct nfs_page *req);
extern void nfs_release_request(struct nfs_page *req);
-extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *head, struct list_head *dst,
- pgoff_t idx_start, unsigned int npages);
+extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst,
+ pgoff_t idx_start, unsigned int npages, int tag);
extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
struct inode *inode,
int (*doio)(struct inode *, struct list_head *, unsigned int, size_t, int),
@@ -84,12 +84,11 @@ extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc);
extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t);
extern int nfs_wait_on_request(struct nfs_page *);
extern void nfs_unlock_request(struct nfs_page *req);
-extern int nfs_set_page_writeback_locked(struct nfs_page *req);
-extern void nfs_clear_page_writeback(struct nfs_page *req);
+extern void nfs_clear_page_tag_locked(struct nfs_page *req);
/*
- * Lock the page of an asynchronous request without incrementing the wb_count
+ * Lock the page of an asynchronous request without getting a new reference
*/
static inline int
nfs_lock_request_dontget(struct nfs_page *req)
@@ -98,14 +97,14 @@ nfs_lock_request_dontget(struct nfs_page *req)
}
/*
- * Lock the page of an asynchronous request
+ * Lock the page of an asynchronous request and take a reference
*/
static inline int
nfs_lock_request(struct nfs_page *req)
{
if (test_and_set_bit(PG_BUSY, &req->wb_flags))
return 0;
- atomic_inc(&req->wb_count);
+ kref_get(&req->wb_kref);
return 1;
}
@@ -118,7 +117,6 @@ static inline void
nfs_list_add_request(struct nfs_page *req, struct list_head *head)
{
list_add_tail(&req->wb_list, head);
- req->wb_list_head = head;
}
@@ -132,7 +130,6 @@ nfs_list_remove_request(struct nfs_page *req)
if (list_empty(&req->wb_list))
return;
list_del_init(&req->wb_list);
- req->wb_list_head = NULL;
}
static inline struct nfs_page *
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 10c26ed0db71..cf74a4db84a5 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -119,7 +119,7 @@ struct nfs_openargs {
struct nfs_seqid * seqid;
int open_flags;
__u64 clientid;
- __u32 id;
+ __u64 id;
union {
struct iattr * attrs; /* UNCHECKED, GUARDED */
nfs4_verifier verifier; /* EXCLUSIVE */
@@ -144,6 +144,7 @@ struct nfs_openres {
nfs4_stateid delegation;
__u32 do_recall;
__u64 maxsize;
+ __u32 attrset[NFS4_BITMAP_SIZE];
};
/*
@@ -180,7 +181,7 @@ struct nfs_closeres {
* */
struct nfs_lowner {
__u64 clientid;
- u32 id;
+ __u64 id;
};
struct nfs_lock_args {
@@ -277,6 +278,21 @@ struct nfs_writeres {
};
/*
+ * Common arguments to the unlink call
+ */
+struct nfs_removeargs {
+ const struct nfs_fh *fh;
+ struct qstr name;
+ const u32 * bitmask;
+};
+
+struct nfs_removeres {
+ const struct nfs_server *server;
+ struct nfs4_change_info cinfo;
+ struct nfs_fattr dir_attr;
+};
+
+/*
* Argument struct for decode_entry function
*/
struct nfs_entry {
@@ -630,18 +646,6 @@ struct nfs4_readlink {
struct page ** pages; /* zero-copy data */
};
-struct nfs4_remove_arg {
- const struct nfs_fh * fh;
- const struct qstr * name;
- const u32 * bitmask;
-};
-
-struct nfs4_remove_res {
- const struct nfs_server * server;
- struct nfs4_change_info cinfo;
- struct nfs_fattr * dir_attr;
-};
-
struct nfs4_rename_arg {
const struct nfs_fh * old_dir;
const struct nfs_fh * new_dir;
@@ -787,9 +791,8 @@ struct nfs_rpc_ops {
int (*create) (struct inode *, struct dentry *,
struct iattr *, int, struct nameidata *);
int (*remove) (struct inode *, struct qstr *);
- int (*unlink_setup) (struct rpc_message *,
- struct dentry *, struct qstr *);
- int (*unlink_done) (struct dentry *, struct rpc_task *);
+ void (*unlink_setup) (struct rpc_message *, struct inode *dir);
+ int (*unlink_done) (struct rpc_task *, struct inode *);
int (*rename) (struct inode *, struct qstr *,
struct inode *, struct qstr *);
int (*link) (struct inode *, struct inode *, struct qstr *);
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index 9f62d6182d32..5cd192469096 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -42,6 +42,9 @@
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
#define NFSEXP_ALLFLAGS 0xFE3F
+/* The flags that may vary depending on security flavor: */
+#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
+ | NFSEXP_ALLSQUASH)
#ifdef __KERNEL__
@@ -64,6 +67,19 @@ struct nfsd4_fs_locations {
int migrated;
};
+/*
+ * We keep an array of pseudoflavors with the export, in order from most
+ * to least preferred. For the forseeable future, we don't expect more
+ * than the eight pseudoflavors null, unix, krb5, krb5i, krb5p, skpm3,
+ * spkm3i, and spkm3p (and using all 8 at once should be rare).
+ */
+#define MAX_SECINFO_LIST 8
+
+struct exp_flavor_info {
+ u32 pseudoflavor;
+ u32 flags;
+};
+
struct svc_export {
struct cache_head h;
struct auth_domain * ex_client;
@@ -76,6 +92,8 @@ struct svc_export {
int ex_fsid;
unsigned char * ex_uuid; /* 16 byte fsid */
struct nfsd4_fs_locations ex_fslocs;
+ int ex_nflavors;
+ struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST];
};
/* an "export key" (expkey) maps a filehandlefragement to an
@@ -95,10 +113,11 @@ struct svc_expkey {
#define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
#define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC))
-#define EX_RDONLY(exp) ((exp)->ex_flags & NFSEXP_READONLY)
#define EX_NOHIDE(exp) ((exp)->ex_flags & NFSEXP_NOHIDE)
#define EX_WGATHER(exp) ((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
+int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp);
+__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
/*
* Function declarations
@@ -112,13 +131,19 @@ struct svc_export * exp_get_by_name(struct auth_domain *clp,
struct vfsmount *mnt,
struct dentry *dentry,
struct cache_req *reqp);
+struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
+ struct vfsmount *,
+ struct dentry *);
struct svc_export * exp_parent(struct auth_domain *clp,
struct vfsmount *mnt,
struct dentry *dentry,
struct cache_req *reqp);
+struct svc_export * rqst_exp_parent(struct svc_rqst *,
+ struct vfsmount *mnt,
+ struct dentry *dentry);
int exp_rootfh(struct auth_domain *,
char *path, struct knfsd_fh *, int maxsize);
-__be32 exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
+__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
__be32 nfserrno(int errno);
extern struct cache_detail svc_export_cache;
@@ -135,6 +160,7 @@ static inline void exp_get(struct svc_export *exp)
extern struct svc_export *
exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
struct cache_req *reqp);
+struct svc_export * rqst_exp_find(struct svc_rqst *, int, u32 *);
#endif /* __KERNEL__ */
diff --git a/include/linux/nfsd/interface.h b/include/linux/nfsd/interface.h
deleted file mode 100644
index af0979704afb..000000000000
--- a/include/linux/nfsd/interface.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * include/linux/nfsd/interface.h
- *
- * defines interface between nfsd and other bits of
- * the kernel. Particularly filesystems (eventually).
- *
- * Copyright (C) 2000 Neil Brown <neilb@cse.unsw.edu.au>
- */
-
-#ifndef LINUX_NFSD_INTERFACE_H
-#define LINUX_NFSD_INTERFACE_H
-
-#endif /* LINUX_NFSD_INTERFACE_H */
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 72feac581aa3..e452256d3f72 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -22,7 +22,6 @@
#include <linux/nfsd/export.h>
#include <linux/nfsd/auth.h>
#include <linux/nfsd/stats.h>
-#include <linux/nfsd/interface.h>
/*
* nfsd version
*/
@@ -72,6 +71,9 @@ int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct svc_export **expp);
__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
const char *, int, struct svc_fh *);
+__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
+ const char *, int,
+ struct svc_export **, struct dentry **);
__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct iattr *, int, time_t);
#ifdef CONFIG_NFSD_V4
@@ -120,7 +122,8 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct kstatfs *);
int nfsd_notify_change(struct inode *, struct iattr *);
-__be32 nfsd_permission(struct svc_export *, struct dentry *, int);
+__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
+ struct dentry *, int);
int nfsd_sync_dir(struct dentry *dp);
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
@@ -149,6 +152,7 @@ extern int nfsd_max_blksize;
* NFSv4 State
*/
#ifdef CONFIG_NFSD_V4
+extern unsigned int max_delegations;
void nfs4_state_init(void);
int nfs4_state_start(void);
void nfs4_state_shutdown(void);
@@ -236,6 +240,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_badname __constant_htonl(NFSERR_BADNAME)
#define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN)
#define nfserr_locked __constant_htonl(NFSERR_LOCKED)
+#define nfserr_wrongsec __constant_htonl(NFSERR_WRONGSEC)
#define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME)
/* error codes for internal use */
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index ab5c236bd9a7..db348f749376 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -67,7 +67,7 @@ struct nfs4_cb_recall {
int cbr_trunc;
stateid_t cbr_stateid;
u32 cbr_fhlen;
- u32 cbr_fhval[NFS4_FHSIZE];
+ char cbr_fhval[NFS4_FHSIZE];
struct nfs4_delegation *cbr_dp;
};
@@ -224,6 +224,7 @@ struct nfs4_file {
struct inode *fi_inode;
u32 fi_id; /* used with stateowner->so_id
* for stateid_hashtbl hash */
+ bool fi_had_conflict;
};
/*
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 09799bcee0ac..1b653267133a 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -293,6 +293,12 @@ struct nfsd4_rename {
struct nfsd4_change_info rn_tinfo; /* response */
};
+struct nfsd4_secinfo {
+ u32 si_namelen; /* request */
+ char *si_name; /* request */
+ struct svc_export *si_exp; /* response */
+};
+
struct nfsd4_setattr {
stateid_t sa_stateid; /* request */
u32 sa_bmval[2]; /* request */
@@ -365,6 +371,7 @@ struct nfsd4_op {
struct nfsd4_remove remove;
struct nfsd4_rename rename;
clientid_t renew;
+ struct nfsd4_secinfo secinfo;
struct nfsd4_setattr setattr;
struct nfsd4_setclientid setclientid;
struct nfsd4_setclientid_confirm setclientid_confirm;
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 9431101bf876..be3f2bb6fcf3 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -196,6 +196,8 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */
#define CPU_LOCK_ACQUIRE 0x0008 /* Acquire all hotcpu locks */
#define CPU_LOCK_RELEASE 0x0009 /* Release all hotcpu locks */
+#define CPU_DYING 0x000A /* CPU (unsigned)v not running any task,
+ * not handling interrupts, soon dead */
/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
* operation in progress
@@ -208,6 +210,13 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN)
#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN)
#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN)
+#define CPU_DYING_FROZEN (CPU_DYING | CPU_TASKS_FROZEN)
+
+/* Hibernation and suspend events */
+#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */
+#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */
+#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */
+#define PM_POST_SUSPEND 0x0004 /* Suspend finished */
#endif /* __KERNEL__ */
#endif /* _LINUX_NOTIFIER_H */
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index 189e0dc993ab..ce06188b7a56 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -28,10 +28,11 @@ struct nsproxy {
struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns;
struct pid_namespace *pid_ns;
+ struct user_namespace *user_ns;
};
extern struct nsproxy init_nsproxy;
-int copy_namespaces(int flags, struct task_struct *tsk);
+int copy_namespaces(unsigned long flags, struct task_struct *tsk);
void get_task_namespaces(struct task_struct *tsk);
void free_nsproxy(struct nsproxy *ns);
int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **,
diff --git a/include/linux/of.h b/include/linux/of.h
new file mode 100644
index 000000000000..47734ffd9745
--- /dev/null
+++ b/include/linux/of.h
@@ -0,0 +1,61 @@
+#ifndef _LINUX_OF_H
+#define _LINUX_OF_H
+/*
+ * Definitions for talking to the Open Firmware PROM on
+ * Power Macintosh and other computers.
+ *
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp.
+ * Updates for SPARC64 by David S. Miller
+ * Derived from PowerPC and Sparc prom.h files by Stephen Rothwell, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/types.h>
+
+#include <asm/bitops.h>
+#include <asm/prom.h>
+
+/* flag descriptions */
+#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */
+#define OF_DETACHED 2 /* node has been detached from the device tree */
+
+#define OF_BAD_ADDR ((u64)-1)
+
+extern struct device_node *of_find_node_by_name(struct device_node *from,
+ const char *name);
+#define for_each_node_by_name(dn, name) \
+ for (dn = of_find_node_by_name(NULL, name); dn; \
+ dn = of_find_node_by_name(dn, name))
+extern struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type);
+#define for_each_node_by_type(dn, type) \
+ for (dn = of_find_node_by_type(NULL, type); dn; \
+ dn = of_find_node_by_type(dn, type))
+extern struct device_node *of_find_compatible_node(struct device_node *from,
+ const char *type, const char *compat);
+#define for_each_compatible_node(dn, type, compatible) \
+ for (dn = of_find_compatible_node(NULL, type, compatible); dn; \
+ dn = of_find_compatible_node(dn, type, compatible))
+extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_by_phandle(phandle handle);
+extern struct device_node *of_get_parent(const struct device_node *node);
+extern struct device_node *of_get_next_child(const struct device_node *node,
+ struct device_node *prev);
+extern struct property *of_find_property(const struct device_node *np,
+ const char *name,
+ int *lenp);
+extern int of_device_is_compatible(const struct device_node *device,
+ const char *);
+extern const void *of_get_property(const struct device_node *node,
+ const char *name,
+ int *lenp);
+#define get_property(a, b, c) of_get_property((a), (b), (c))
+extern int of_n_addr_cells(struct device_node *np);
+extern int of_n_size_cells(struct device_node *np);
+
+#endif /* _LINUX_OF_H */
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
new file mode 100644
index 000000000000..91bf84b9d144
--- /dev/null
+++ b/include/linux/of_device.h
@@ -0,0 +1,26 @@
+#ifndef _LINUX_OF_DEVICE_H
+#define _LINUX_OF_DEVICE_H
+#ifdef __KERNEL__
+
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/mod_devicetable.h>
+
+#include <asm/of_device.h>
+
+#define to_of_device(d) container_of(d, struct of_device, dev)
+
+extern const struct of_device_id *of_match_node(
+ const struct of_device_id *matches, const struct device_node *node);
+extern const struct of_device_id *of_match_device(
+ const struct of_device_id *matches, const struct of_device *dev);
+
+extern struct of_device *of_dev_get(struct of_device *dev);
+extern void of_dev_put(struct of_device *dev);
+
+extern int of_device_register(struct of_device *ofdev);
+extern void of_device_unregister(struct of_device *ofdev);
+extern void of_release_dev(struct device *dev);
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
new file mode 100644
index 000000000000..448f70b30a0c
--- /dev/null
+++ b/include/linux/of_platform.h
@@ -0,0 +1,57 @@
+#ifndef _LINUX_OF_PLATFORM_H
+#define _LINUX_OF_PLATFORM_H
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ * <benh@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm.h>
+#include <linux/of_device.h>
+
+/*
+ * The of_platform_bus_type is a bus type used by drivers that do not
+ * attach to a macio or similar bus but still use OF probing
+ * mechanism
+ */
+extern struct bus_type of_platform_bus_type;
+
+/*
+ * An of_platform_driver driver is attached to a basic of_device on
+ * the "platform bus" (of_platform_bus_type) (or ISA, EBUS and SBUS
+ * busses on sparc).
+ */
+struct of_platform_driver
+{
+ const char *name;
+ const struct of_device_id *match_table;
+ struct module *owner;
+
+ int (*probe)(struct of_device* dev,
+ const struct of_device_id *match);
+ int (*remove)(struct of_device* dev);
+
+ int (*suspend)(struct of_device* dev, pm_message_t state);
+ int (*resume)(struct of_device* dev);
+ int (*shutdown)(struct of_device* dev);
+
+ struct device_driver driver;
+};
+#define to_of_platform_driver(drv) \
+ container_of(drv,struct of_platform_driver, driver)
+
+#include <asm/of_platform.h>
+
+extern struct of_device *of_find_device_by_node(struct device_node *np);
+
+extern int of_bus_type_init(struct bus_type *bus, const char *name);
+
+#endif /* _LINUX_OF_PLATFORM_H */
diff --git a/include/linux/oprofile.h b/include/linux/oprofile.h
index 0d514b252454..041bb31100f4 100644
--- a/include/linux/oprofile.h
+++ b/include/linux/oprofile.h
@@ -17,6 +17,26 @@
#include <linux/spinlock.h>
#include <asm/atomic.h>
+/* Each escaped entry is prefixed by ESCAPE_CODE
+ * then one of the following codes, then the
+ * relevant data.
+ * These #defines live in this file so that arch-specific
+ * buffer sync'ing code can access them.
+ */
+#define ESCAPE_CODE ~0UL
+#define CTX_SWITCH_CODE 1
+#define CPU_SWITCH_CODE 2
+#define COOKIE_SWITCH_CODE 3
+#define KERNEL_ENTER_SWITCH_CODE 4
+#define KERNEL_EXIT_SWITCH_CODE 5
+#define MODULE_LOADED_CODE 6
+#define CTX_TGID_CODE 7
+#define TRACE_BEGIN_CODE 8
+#define TRACE_END_CODE 9
+#define XEN_ENTER_SWITCH_CODE 10
+#define SPU_PROFILING_CODE 11
+#define SPU_CTX_SWITCH_CODE 12
+
struct super_block;
struct dentry;
struct file_operations;
@@ -35,6 +55,14 @@ struct oprofile_operations {
int (*start)(void);
/* Stop delivering interrupts. */
void (*stop)(void);
+ /* Arch-specific buffer sync functions.
+ * Return value = 0: Success
+ * Return value = -1: Failure
+ * Return value = 1: Run generic sync function
+ */
+ int (*sync_start)(void);
+ int (*sync_stop)(void);
+
/* Initiate a stack backtrace. Optional. */
void (*backtrace)(struct pt_regs * const regs, unsigned int depth);
/* CPU identification string. */
@@ -56,6 +84,13 @@ int oprofile_arch_init(struct oprofile_operations * ops);
void oprofile_arch_exit(void);
/**
+ * Add data to the event buffer.
+ * The data passed is free-form, but typically consists of
+ * file offsets, dcookies, context information, and ESCAPE codes.
+ */
+void add_event_entry(unsigned long data);
+
+/**
* Add a sample. This may be called from any context. Pass
* smp_processor_id() as cpu.
*/
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index ae2d79f2107e..209d3a47f50f 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -90,8 +90,12 @@
#define PG_reclaim 17 /* To be reclaimed asap */
#define PG_buddy 19 /* Page is free, on buddy lists */
+/* 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 */
#if (BITS_PER_LONG > 32)
/*
@@ -170,6 +174,10 @@ static inline void SetPageUptodate(struct page *page)
#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)
+
#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)
@@ -181,37 +189,15 @@ static inline void SetPageUptodate(struct page *page)
#define __SetPagePrivate(page) __set_bit(PG_private, &(page)->flags)
#define __ClearPagePrivate(page) __clear_bit(PG_private, &(page)->flags)
+/*
+ * Only test-and-set exist for PG_writeback. The unconditional operators are
+ * risky: they bypass page accounting.
+ */
#define PageWriteback(page) test_bit(PG_writeback, &(page)->flags)
-#define SetPageWriteback(page) \
- do { \
- if (!test_and_set_bit(PG_writeback, \
- &(page)->flags)) \
- inc_zone_page_state(page, NR_WRITEBACK); \
- } while (0)
-#define TestSetPageWriteback(page) \
- ({ \
- int ret; \
- ret = test_and_set_bit(PG_writeback, \
- &(page)->flags); \
- if (!ret) \
- inc_zone_page_state(page, NR_WRITEBACK); \
- ret; \
- })
-#define ClearPageWriteback(page) \
- do { \
- if (test_and_clear_bit(PG_writeback, \
- &(page)->flags)) \
- dec_zone_page_state(page, NR_WRITEBACK); \
- } while (0)
-#define TestClearPageWriteback(page) \
- ({ \
- int ret; \
- ret = test_and_clear_bit(PG_writeback, \
- &(page)->flags); \
- if (ret) \
- dec_zone_page_state(page, NR_WRITEBACK); \
- ret; \
- })
+#define TestSetPageWriteback(page) test_and_set_bit(PG_writeback, \
+ &(page)->flags)
+#define TestClearPageWriteback(page) test_and_clear_bit(PG_writeback, \
+ &(page)->flags)
#define PageBuddy(page) test_bit(PG_buddy, &(page)->flags)
#define __SetPageBuddy(page) __set_bit(PG_buddy, &(page)->flags)
@@ -221,6 +207,10 @@ static inline void SetPageUptodate(struct page *page)
#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)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 086a0e5a6318..5e84f2e8d54c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -111,7 +111,8 @@ enum pcie_reset_state {
typedef unsigned short __bitwise pci_bus_flags_t;
enum pci_bus_flags {
- PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
+ PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
+ PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2,
};
struct pci_cap_saved_state {
@@ -138,6 +139,7 @@ struct pci_dev {
unsigned short subsystem_vendor;
unsigned short subsystem_device;
unsigned int class; /* 3 bytes: (base,sub,prog-if) */
+ u8 revision; /* PCI revision, low byte of class word */
u8 hdr_type; /* PCI header type (`multi' flag masked out) */
u8 rom_base_reg; /* which config register controls the ROM */
u8 pin; /* which interrupt pin this device uses */
@@ -313,7 +315,7 @@ struct pci_dynids {
/* ---------------------------------------------------------------- */
/** PCI Error Recovery System (PCI-ERS). If a PCI device driver provides
- * a set fof callbacks in struct pci_error_handlers, then that device driver
+ * a set of callbacks in struct pci_error_handlers, then that device driver
* will be notified of PCI bus errors, and will be driven to recovery
* when an error occurs.
*/
@@ -370,7 +372,6 @@ struct pci_driver {
int (*suspend_late) (struct pci_dev *dev, pm_message_t state);
int (*resume_early) (struct pci_dev *dev);
int (*resume) (struct pci_dev *dev); /* Device woken up */
- int (*enable_wake) (struct pci_dev *dev, pci_power_t state, int enable); /* Enable wake event */
void (*shutdown) (struct pci_dev *dev);
struct pci_error_handlers *err_handler;
@@ -431,6 +432,8 @@ extern struct bus_type pci_bus_type;
* code, or pci core code. */
extern struct list_head pci_root_buses; /* list of all known PCI buses */
extern struct list_head pci_devices; /* list of all devices */
+/* Some device drivers need know if pci is initiated */
+extern int no_pci_devices(void);
void pcibios_fixup_bus(struct pci_bus *);
int __must_check pcibios_enable_device(struct pci_dev *, int mask);
@@ -475,7 +478,7 @@ extern void pci_sort_breadthfirst(void);
/* Generic PCI functions exported to card drivers */
struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
-struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
+struct pci_dev __deprecated *pci_find_slot (unsigned int bus, unsigned int devfn);
int pci_find_capability (struct pci_dev *dev, int cap);
int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
int pci_find_ext_capability (struct pci_dev *dev, int cap);
@@ -544,11 +547,16 @@ void pci_set_master(struct pci_dev *dev);
int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
#define HAVE_PCI_SET_MWI
int __must_check pci_set_mwi(struct pci_dev *dev);
+int pci_try_set_mwi(struct pci_dev *dev);
void pci_clear_mwi(struct pci_dev *dev);
void pci_intx(struct pci_dev *dev, int enable);
void pci_msi_off(struct pci_dev *dev);
int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask);
+int pcix_get_max_mmrbc(struct pci_dev *dev);
+int pcix_get_mmrbc(struct pci_dev *dev);
+int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc);
+int pcie_set_readrq(struct pci_dev *dev, int rq);
void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
int __must_check pci_assign_resource(struct pci_dev *dev, int i);
int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
@@ -560,6 +568,7 @@ void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size);
void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
void pci_remove_rom(struct pci_dev *pdev);
+size_t pci_get_rom_size(void __iomem *rom, size_t size);
/* Power management related routines */
int pci_save_state(struct pci_dev *dev);
@@ -717,6 +726,7 @@ static inline struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *
{ return NULL; }
#define pci_dev_present(ids) (0)
+#define no_pci_devices() (1)
#define pci_find_present(ids) (NULL)
#define pci_dev_put(dev) do { } while (0)
@@ -876,5 +886,7 @@ extern int pci_pci_problems;
extern unsigned long pci_cardbus_io_size;
extern unsigned long pci_cardbus_mem_size;
+extern int pcibios_add_platform_entries(struct pci_dev *dev);
+
#endif /* __KERNEL__ */
#endif /* LINUX_PCI_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 75c4d4d06892..cbabb9c675c9 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -133,6 +133,9 @@
/* Vendors and devices. Sort key: vendor first, device next. */
+#define PCI_VENDOR_ID_TTTECH 0x0357
+#define PCI_DEVICE_ID_TTTECH_MC322 0x000a
+
#define PCI_VENDOR_ID_DYNALINK 0x0675
#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702
@@ -371,6 +374,7 @@
#define PCI_DEVICE_ID_ATI_IXP600_SMBUS 0x4385
#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c
#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390
+#define PCI_DEVICE_ID_ATI_IXP700_SMBUS 0x4395
#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c
#define PCI_VENDOR_ID_VLSI 0x1004
@@ -475,6 +479,9 @@
#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361
#define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252
+#define PCI_VENDOR_ID_UNISYS 0x1018
+#define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C
+
#define PCI_VENDOR_ID_COMPEX2 0x101a /* pci.ids says "AT&T GIS (NCR)" */
#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005
@@ -488,6 +495,8 @@
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_K8_NB 0x1100
+#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP 0x1101
+#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL 0x1102
#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
@@ -732,7 +741,6 @@
#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000
#define PCI_DEVICE_ID_ELSA_QS3000 0x3000
-
#define PCI_VENDOR_ID_BUSLOGIC 0x104B
#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140
#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040
@@ -778,7 +786,6 @@
#define PCI_VENDOR_ID_SONY 0x104d
-
/* Winbond have two vendor IDs! See 0x10ad as well */
#define PCI_VENDOR_ID_WINBOND2 0x1050
#define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a
@@ -816,7 +823,6 @@
#define PCI_DEVICE_ID_PROMISE_20276 0x5275
#define PCI_DEVICE_ID_PROMISE_20277 0x7275
-
#define PCI_VENDOR_ID_UMC 0x1060
#define PCI_DEVICE_ID_UMC_UM8673F 0x0101
#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a
@@ -832,7 +838,6 @@
#define PCI_DEVICE_ID_MYLEX_DAC960_BA 0xBA56
#define PCI_DEVICE_ID_MYLEX_DAC960_GEM 0xB166
-
#define PCI_VENDOR_ID_APPLE 0x106b
#define PCI_DEVICE_ID_APPLE_BANDIT 0x0001
#define PCI_DEVICE_ID_APPLE_HYDRA 0x000e
@@ -868,7 +873,6 @@
#define PCI_DEVICE_ID_YAMAHA_744 0x0010
#define PCI_DEVICE_ID_YAMAHA_754 0x0012
-
#define PCI_VENDOR_ID_QLOGIC 0x1077
#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016
#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020
@@ -899,12 +903,9 @@
#define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103
#define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104
-
-
#define PCI_VENDOR_ID_CONTAQ 0x1080
#define PCI_DEVICE_ID_CONTAQ_82C693 0xc693
-
#define PCI_VENDOR_ID_OLICOM 0x108d
#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012
#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013
@@ -936,23 +937,19 @@
#define PCI_DEVICE_ID_SII_3112 0x3112
#define PCI_DEVICE_ID_SII_1210SA 0x0240
-
#define PCI_VENDOR_ID_BROOKTREE 0x109e
#define PCI_DEVICE_ID_BROOKTREE_878 0x0878
#define PCI_DEVICE_ID_BROOKTREE_879 0x0879
-
#define PCI_VENDOR_ID_SGI 0x10a9
#define PCI_DEVICE_ID_SGI_IOC3 0x0003
+#define PCI_DEVICE_ID_SGI_LITHIUM 0x1002
#define PCI_DEVICE_ID_SGI_IOC4 0x100a
-#define PCI_VENDOR_ID_SGI_LITHIUM 0x1002
-
#define PCI_VENDOR_ID_WINBOND 0x10ad
#define PCI_DEVICE_ID_WINBOND_82C105 0x0105
#define PCI_DEVICE_ID_WINBOND_83C553 0x0565
-
#define PCI_VENDOR_ID_PLX 0x10b5
#define PCI_DEVICE_ID_PLX_R685 0x1030
#define PCI_DEVICE_ID_PLX_ROMULUS 0x106a
@@ -986,7 +983,6 @@
#define PCI_DEVICE_ID_3COM_3CR990SVR97 0x9909
#define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a
-
#define PCI_VENDOR_ID_AL 0x10b9
#define PCI_DEVICE_ID_AL_M1533 0x1533
#define PCI_DEVICE_ID_AL_M1535 0x1535
@@ -1009,18 +1005,14 @@
#define PCI_DEVICE_ID_AL_M5451 0x5451
#define PCI_DEVICE_ID_AL_M7101 0x7101
-
-
#define PCI_VENDOR_ID_NEOMAGIC 0x10c8
#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016
-
#define PCI_VENDOR_ID_TCONRAD 0x10da
#define PCI_DEVICE_ID_TCONRAD_TOKENRING 0x0508
-
#define PCI_VENDOR_ID_NVIDIA 0x10de
#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020
#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028
@@ -1241,9 +1233,6 @@
#define PCI_DEVICE_ID_IMS_TT128 0x9128
#define PCI_DEVICE_ID_IMS_TT3D 0x9135
-
-
-
#define PCI_VENDOR_ID_INTERG 0x10ea
#define PCI_DEVICE_ID_INTERG_1682 0x1682
#define PCI_DEVICE_ID_INTERG_2000 0x2000
@@ -1262,7 +1251,6 @@
#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5
#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6
-
#define PCI_VENDOR_ID_INIT 0x1101
#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */
@@ -1357,7 +1345,6 @@
#define PCI_VENDOR_ID_SIEMENS 0x110A
#define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102
-
#define PCI_VENDOR_ID_VORTEX 0x1119
#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000
#define PCI_DEVICE_ID_VORTEX_GDT6000B 0x0001
@@ -1383,8 +1370,8 @@
#define PCI_VENDOR_ID_EF 0x111a
#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000
#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002
-#define PCI_VENDOR_ID_EF_ATM_LANAI2 0x0003
-#define PCI_VENDOR_ID_EF_ATM_LANAIHB 0x0005
+#define PCI_DEVICE_ID_EF_ATM_LANAI2 0x0003
+#define PCI_DEVICE_ID_EF_ATM_LANAIHB 0x0005
#define PCI_VENDOR_ID_IDT 0x111d
#define PCI_DEVICE_ID_IDT_IDT77201 0x0001
@@ -1392,7 +1379,6 @@
#define PCI_VENDOR_ID_FORE 0x1127
#define PCI_DEVICE_ID_FORE_PCA200E 0x0300
-
#define PCI_VENDOR_ID_PHILIPS 0x1131
#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146
#define PCI_DEVICE_ID_PHILIPS_SAA9730 0x9730
@@ -1411,7 +1397,6 @@
#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550
-
#define PCI_VENDOR_ID_SYSKONNECT 0x1148
#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200
#define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300
@@ -1419,7 +1404,6 @@
#define PCI_DEVICE_ID_SYSKONNECT_9DXX 0x4400
#define PCI_DEVICE_ID_SYSKONNECT_9MXX 0x4500
-
#define PCI_VENDOR_ID_DIGI 0x114f
#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070
#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071
@@ -1430,12 +1414,10 @@
#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA
#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB
-
#define PCI_VENDOR_ID_XIRCOM 0x115d
#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101
#define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103
-
#define PCI_VENDOR_ID_SERVERWORKS 0x1166
#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008
#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009
@@ -1504,7 +1486,6 @@
#define PCI_DEVICE_ID_ZEITNET_1221 0x0001
#define PCI_DEVICE_ID_ZEITNET_1225 0x0002
-
#define PCI_VENDOR_ID_FUJITSU_ME 0x119e
#define PCI_DEVICE_ID_FUJITSU_FS155 0x0001
#define PCI_DEVICE_ID_FUJITSU_FS50 0x0003
@@ -1522,28 +1503,23 @@
#define PCI_DEVICE_ID_V3_V960 0x0001
#define PCI_DEVICE_ID_V3_V351 0x0002
-
#define PCI_VENDOR_ID_ATT 0x11c1
#define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480
-
#define PCI_VENDOR_ID_SPECIALIX 0x11cb
#define PCI_DEVICE_ID_SPECIALIX_IO8 0x2000
#define PCI_DEVICE_ID_SPECIALIX_RIO 0x8000
#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004
-
#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4
#define PCI_DEVICE_ID_AD1889JS 0x1889
-
#define PCI_DEVICE_ID_SEGA_BBA 0x1234
#define PCI_VENDOR_ID_ZORAN 0x11de
#define PCI_DEVICE_ID_ZORAN_36057 0x6057
#define PCI_DEVICE_ID_ZORAN_36120 0x6120
-
#define PCI_VENDOR_ID_COMPEX 0x11f6
#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112
@@ -1602,8 +1578,6 @@
#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005
#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009
-
-
#define PCI_VENDOR_ID_AVM 0x1244
#define PCI_DEVICE_ID_AVM_B1 0x0700
#define PCI_DEVICE_ID_AVM_C4 0x0800
@@ -1612,7 +1586,6 @@
#define PCI_DEVICE_ID_AVM_C2 0x1100
#define PCI_DEVICE_ID_AVM_T1 0x1200
-
#define PCI_VENDOR_ID_STALLION 0x124d
/* Allied Telesyn */
@@ -1635,7 +1608,6 @@
#define PCI_VENDOR_ID_SATSAGEM 0x1267
#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016
-
#define PCI_VENDOR_ID_ENSONIQ 0x1274
#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880
#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
@@ -1658,7 +1630,6 @@
#define PCI_VENDOR_ID_ALTEON 0x12ae
-
#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4
#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001
#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232 0x0002
@@ -1689,7 +1660,6 @@
#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485 0x0331
#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485 0x0332
-
#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2
#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018
@@ -1799,7 +1769,6 @@
#define PCI_DEVICE_ID_LMC_SSI 0x0005
#define PCI_DEVICE_ID_LMC_T1 0x0006
-
#define PCI_VENDOR_ID_NETGEAR 0x1385
#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a
@@ -1902,6 +1871,8 @@
#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521
#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523
+#define PCI_VENDOR_ID_CHELSIO 0x1425
+
#define PCI_VENDOR_ID_SAMSUNG 0x144d
#define PCI_VENDOR_ID_MYRICOM 0x14c1
@@ -2010,13 +1981,10 @@
#define PCI_DEVICE_ID_ENE_720 0x1421
#define PCI_DEVICE_ID_ENE_722 0x1422
-#define PCI_VENDOR_ID_CHELSIO 0x1425
-
#define PCI_SUBVENDOR_ID_PERLE 0x155f
#define PCI_SUBDEVICE_ID_PCI_RAS4 0xf001
#define PCI_SUBDEVICE_ID_PCI_RAS8 0xf010
-
#define PCI_VENDOR_ID_SYBA 0x1592
#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782
#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783
@@ -2035,8 +2003,10 @@
#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c
#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274
-#define PCI_VENDOR_ID_PDC 0x15e9
+#define PCI_VENDOR_ID_QUICKNET 0x15e2
+#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
+#define PCI_VENDOR_ID_PDC 0x15e9
#define PCI_VENDOR_ID_FARSITE 0x1619
#define PCI_DEVICE_ID_FARSITE_T2P 0x0400
@@ -2049,10 +2019,14 @@
#define PCI_VENDOR_ID_ARIMA 0x161f
+#define PCI_VENDOR_ID_BROCADE 0x1657
+
#define PCI_VENDOR_ID_SIBYTE 0x166d
#define PCI_DEVICE_ID_BCM1250_PCI 0x0001
#define PCI_DEVICE_ID_BCM1250_HT 0x0002
+#define PCI_VENDOR_ID_ATHEROS 0x168c
+
#define PCI_VENDOR_ID_NETCELL 0x169c
#define PCI_DEVICE_ID_REVOLUTION 0x0044
@@ -2068,6 +2042,8 @@
#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb
+#define PCI_VENDOR_ID_LENOVO 0x17aa
+
#define PCI_VENDOR_ID_ARECA 0x17d3
#define PCI_DEVICE_ID_ARECA_1110 0x1110
#define PCI_DEVICE_ID_ARECA_1120 0x1120
@@ -2091,7 +2067,6 @@
#define PCI_DEVICE_ID_HERC_WIN 0x5732
#define PCI_DEVICE_ID_HERC_UNI 0x5832
-
#define PCI_VENDOR_ID_SITECOM 0x182d
#define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069
@@ -2127,12 +2102,9 @@
#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007
#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009
-
#define PCI_VENDOR_ID_AKS 0x416c
#define PCI_DEVICE_ID_AKS_ALADDINCARD 0x0100
-
-
#define PCI_VENDOR_ID_S3 0x5333
#define PCI_DEVICE_ID_S3_TRIO 0x8811
#define PCI_DEVICE_ID_S3_868 0x8880
@@ -2144,7 +2116,6 @@
#define PCI_VENDOR_ID_DUNORD 0x5544
#define PCI_DEVICE_ID_DUNORD_I3000 0x0001
-
#define PCI_VENDOR_ID_DCI 0x6666
#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001
#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002
@@ -2244,6 +2215,7 @@
#define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592
#define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770
#define PCI_DEVICE_ID_INTEL_82945G_IG 0x2772
+#define PCI_DEVICE_ID_INTEL_3000_HB 0x2778
#define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0
#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2
#define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640
@@ -2388,7 +2360,6 @@
#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN 0x0500
#define PCI_DEVICE_ID_ADAPTEC2_SCAMP 0x0503
-
#define PCI_VENDOR_ID_HOLTEK 0x9412
#define PCI_DEVICE_ID_HOLTEK_6565 0x6565
@@ -2404,6 +2375,8 @@
#define PCI_DEVICE_ID_NETMOS_9845 0x9845
#define PCI_DEVICE_ID_NETMOS_9855 0x9855
+#define PCI_VENDOR_ID_3COM_2 0xa727
+
#define PCI_SUBVENDOR_ID_EXSYS 0xd84d
#define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014
#define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055
@@ -2412,13 +2385,7 @@
#define PCI_DEVICE_ID_TIGERJET_300 0x0001
#define PCI_DEVICE_ID_TIGERJET_100 0x0002
-#define PCI_VENDOR_ID_TTTECH 0x0357
-#define PCI_DEVICE_ID_TTTECH_MC322 0x000A
-
#define PCI_VENDOR_ID_XILINX_RME 0xea60
#define PCI_DEVICE_ID_RME_DIGI32 0x9896
#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897
#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
-
-#define PCI_VENDOR_ID_QUICKNET 0x15E2
-#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index b72be2f79e6a..926adaae0f96 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -1,7 +1,7 @@
#ifndef __LINUX_PERCPU_H
#define __LINUX_PERCPU_H
-#include <linux/spinlock.h> /* For preempt_disable() */
+#include <linux/preempt.h>
#include <linux/slab.h> /* For kmalloc() */
#include <linux/smp.h>
#include <linux/string.h> /* For memset() */
diff --git a/include/linux/percpu_counter.h b/include/linux/percpu_counter.h
index f5aa593ccf32..3d9f70972cdf 100644
--- a/include/linux/percpu_counter.h
+++ b/include/linux/percpu_counter.h
@@ -8,6 +8,7 @@
#include <linux/spinlock.h>
#include <linux/smp.h>
+#include <linux/list.h>
#include <linux/threads.h>
#include <linux/percpu.h>
#include <linux/types.h>
@@ -17,6 +18,9 @@
struct percpu_counter {
spinlock_t lock;
s64 count;
+#ifdef CONFIG_HOTPLUG_CPU
+ struct list_head list; /* All percpu_counters are on a list */
+#endif
s32 *counters;
};
@@ -26,18 +30,8 @@ struct percpu_counter {
#define FBC_BATCH (NR_CPUS*4)
#endif
-static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
-{
- spin_lock_init(&fbc->lock);
- fbc->count = amount;
- fbc->counters = alloc_percpu(s32);
-}
-
-static inline void percpu_counter_destroy(struct percpu_counter *fbc)
-{
- free_percpu(fbc->counters);
-}
-
+void percpu_counter_init(struct percpu_counter *fbc, s64 amount);
+void percpu_counter_destroy(struct percpu_counter *fbc);
void percpu_counter_mod(struct percpu_counter *fbc, s32 amount);
s64 percpu_counter_sum(struct percpu_counter *fbc);
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 169c6c24209b..b9a17e08ff0f 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -29,7 +29,7 @@ static inline void get_pid_ns(struct pid_namespace *ns)
kref_get(&ns->kref);
}
-extern struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *ns);
+extern struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *ns);
extern void free_pid_ns(struct kref *kref);
static inline void put_pid_ns(struct pid_namespace *ns)
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index c3f01b3085a4..30b8571e6b34 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -403,16 +403,13 @@ enum
* 1..32767 Reserved for ematches inside kernel tree
* 32768..65535 Free to use, not reliable
*/
-enum
-{
- TCF_EM_CONTAINER,
- TCF_EM_CMP,
- TCF_EM_NBYTE,
- TCF_EM_U32,
- TCF_EM_META,
- TCF_EM_TEXT,
- __TCF_EM_MAX
-};
+#define TCF_EM_CONTAINER 0
+#define TCF_EM_CMP 1
+#define TCF_EM_NBYTE 2
+#define TCF_EM_U32 3
+#define TCF_EM_META 4
+#define TCF_EM_TEXT 5
+#define TCF_EM_MAX 5
enum
{
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index d10f35338507..268c51599eb8 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -101,6 +101,15 @@ struct tc_prio_qopt
__u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */
};
+enum
+{
+ TCA_PRIO_UNSPEC,
+ TCA_PRIO_MQ,
+ __TCA_PRIO_MAX
+};
+
+#define TCA_PRIO_MAX (__TCA_PRIO_MAX - 1)
+
/* TBF section */
struct tc_tbf_qopt
diff --git a/include/linux/pm.h b/include/linux/pm.h
index b2c4fde4e994..ad3cc2eb0d34 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -101,6 +101,7 @@ struct pm_dev
*/
extern void (*pm_idle)(void);
extern void (*pm_power_off)(void);
+extern void (*pm_power_off_prepare)(void);
typedef int __bitwise suspend_state_t;
@@ -267,15 +268,10 @@ struct dev_pm_info {
unsigned can_wakeup:1;
#ifdef CONFIG_PM
unsigned should_wakeup:1;
- pm_message_t prev_state;
- void * saved_state;
- struct device * pm_parent;
struct list_head entry;
#endif
};
-extern void device_pm_set_parent(struct device * dev, struct device * parent);
-
extern int device_power_down(pm_message_t state);
extern void device_power_up(void);
extern void device_resume(void);
@@ -289,8 +285,6 @@ extern int device_prepare_suspend(pm_message_t state);
#define device_may_wakeup(dev) \
(device_can_wakeup(dev) && (dev)->power.should_wakeup)
-extern int dpm_runtime_suspend(struct device *, pm_message_t);
-extern void dpm_runtime_resume(struct device *);
extern void __suspend_report_result(const char *function, void *fn, int ret);
#define suspend_report_result(fn, ret) \
@@ -322,15 +316,6 @@ static inline int device_suspend(pm_message_t state)
#define device_set_wakeup_enable(dev,val) do{}while(0)
#define device_may_wakeup(dev) (0)
-static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
- return 0;
-}
-
-static inline void dpm_runtime_resume(struct device * dev)
-{
-}
-
#define suspend_report_result(fn, ret) do { } while (0)
static inline int call_platform_enable_wakeup(struct device *dev, int is_on)
diff --git a/include/linux/prctl.h b/include/linux/prctl.h
index 52a9be41250d..e2eff9079fe9 100644
--- a/include/linux/prctl.h
+++ b/include/linux/prctl.h
@@ -59,4 +59,8 @@
# define PR_ENDIAN_LITTLE 1 /* True little endian mode */
# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */
+/* Get/set process seccomp mode */
+#define PR_GET_SECCOMP 21
+#define PR_SET_SECCOMP 22
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/linux/prefetch.h b/include/linux/prefetch.h
index fc86f274147f..1adfe668d031 100644
--- a/include/linux/prefetch.h
+++ b/include/linux/prefetch.h
@@ -27,7 +27,7 @@
prefetch(x) - prefetches the cacheline at "x" for read
prefetchw(x) - prefetches the cacheline at "x" for write
- spin_lock_prefetch(x) - prefectches the spinlock *x for taking
+ spin_lock_prefetch(x) - prefetches the spinlock *x for taking
there is also PREFETCH_STRIDE which is the architecure-prefered
"lookahead" size for prefetching streamed operations.
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 3469f96bc8b2..28e3664fdf1b 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -7,6 +7,8 @@
#include <linux/magic.h>
#include <asm/atomic.h>
+struct completion;
+
/*
* The proc filesystem constants/structures
*/
@@ -56,6 +58,14 @@ struct proc_dir_entry {
gid_t gid;
loff_t size;
const struct inode_operations *proc_iops;
+ /*
+ * NULL ->proc_fops means "PDE is going away RSN" or
+ * "PDE is just created". In either case, e.g. ->read_proc won't be
+ * called because it's too late or too early, respectively.
+ *
+ * If you're allocating ->proc_fops dynamically, save a pointer
+ * somewhere.
+ */
const struct file_operations *proc_fops;
get_info_t *get_info;
struct module *owner;
@@ -66,6 +76,9 @@ struct proc_dir_entry {
atomic_t count; /* use count */
int deleted; /* delete flag */
void *set;
+ int pde_users; /* number of callers into module in progress */
+ spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
+ struct completion *pde_unload_completion;
};
struct kcore_list {
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index eeb1976ef7bf..ae8146abd746 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -110,6 +110,8 @@ static inline void ptrace_unlink(struct task_struct *child)
__ptrace_unlink(child);
}
+int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data);
+int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data);
#ifndef force_successful_syscall_return
/*
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index dd5a05d03d4f..75e17a05540e 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -262,7 +262,7 @@ int bitmap_active(struct bitmap *bitmap);
char *file_path(struct file *file, char *buf, int count);
void bitmap_print_sb(struct bitmap *bitmap);
-int bitmap_update_sb(struct bitmap *bitmap);
+void bitmap_update_sb(struct bitmap *bitmap);
int bitmap_setallbits(struct bitmap *bitmap);
void bitmap_write_all(struct bitmap *bitmap);
@@ -278,8 +278,8 @@ int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int d
void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted);
void bitmap_close_sync(struct bitmap *bitmap);
-int bitmap_unplug(struct bitmap *bitmap);
-int bitmap_daemon_work(struct bitmap *bitmap);
+void bitmap_unplug(struct bitmap *bitmap);
+void bitmap_daemon_work(struct bitmap *bitmap);
#endif
#endif
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index de72c49747c8..28ac632b42dd 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -51,7 +51,7 @@ struct mdk_rdev_s
sector_t size; /* Device size (in blocks) */
mddev_t *mddev; /* RAID array if running */
- unsigned long last_events; /* IO event timestamp */
+ long last_events; /* IO event timestamp */
struct block_device *bdev; /* block device handle */
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
index d8286db60b96..93678f57ccbe 100644
--- a/include/linux/raid/raid5.h
+++ b/include/linux/raid/raid5.h
@@ -116,13 +116,46 @@
* attach a request to an active stripe (add_stripe_bh())
* lockdev attach-buffer unlockdev
* handle a stripe (handle_stripe())
- * lockstripe clrSTRIPE_HANDLE ... (lockdev check-buffers unlockdev) .. change-state .. record io needed unlockstripe schedule io
+ * lockstripe clrSTRIPE_HANDLE ...
+ * (lockdev check-buffers unlockdev) ..
+ * change-state ..
+ * record io/ops needed unlockstripe schedule io/ops
* release an active stripe (release_stripe())
* lockdev if (!--cnt) { if STRIPE_HANDLE, add to handle_list else add to inactive-list } unlockdev
*
* The refcount counts each thread that have activated the stripe,
* plus raid5d if it is handling it, plus one for each active request
- * on a cached buffer.
+ * on a cached buffer, and plus one if the stripe is undergoing stripe
+ * operations.
+ *
+ * Stripe operations are performed outside the stripe lock,
+ * the stripe operations are:
+ * -copying data between the stripe cache and user application buffers
+ * -computing blocks to save a disk access, or to recover a missing block
+ * -updating the parity on a write operation (reconstruct write and
+ * read-modify-write)
+ * -checking parity correctness
+ * -running i/o to disk
+ * These operations are carried out by raid5_run_ops which uses the async_tx
+ * api to (optionally) offload operations to dedicated hardware engines.
+ * When requesting an operation handle_stripe sets the pending bit for the
+ * operation and increments the count. raid5_run_ops is then run whenever
+ * the count is non-zero.
+ * There are some critical dependencies between the operations that prevent some
+ * from being requested while another is in flight.
+ * 1/ Parity check operations destroy the in cache version of the parity block,
+ * so we prevent parity dependent operations like writes and compute_blocks
+ * from starting while a check is in progress. Some dma engines can perform
+ * the check without damaging the parity block, in these cases the parity
+ * block is re-marked up to date (assuming the check was successful) and is
+ * not re-read from disk.
+ * 2/ When a write operation is requested we immediately lock the affected
+ * blocks, and mark them as not up to date. This causes new read requests
+ * to be held off, as well as parity checks and compute block operations.
+ * 3/ Once a compute block operation has been requested handle_stripe treats
+ * that block as if it is up to date. raid5_run_ops guaruntees that any
+ * operation that is dependent on the compute block result is initiated after
+ * the compute block completes.
*/
struct stripe_head {
@@ -136,15 +169,46 @@ struct stripe_head {
spinlock_t lock;
int bm_seq; /* sequence number for bitmap flushes */
int disks; /* disks in stripe */
+ /* stripe_operations
+ * @pending - pending ops flags (set for request->issue->complete)
+ * @ack - submitted ops flags (set for issue->complete)
+ * @complete - completed ops flags (set for complete)
+ * @target - STRIPE_OP_COMPUTE_BLK target
+ * @count - raid5_runs_ops is set to run when this is non-zero
+ */
+ struct stripe_operations {
+ unsigned long pending;
+ unsigned long ack;
+ unsigned long complete;
+ int target;
+ int count;
+ u32 zero_sum_result;
+ } ops;
struct r5dev {
struct bio req;
struct bio_vec vec;
struct page *page;
- struct bio *toread, *towrite, *written;
+ struct bio *toread, *read, *towrite, *written;
sector_t sector; /* sector of this page */
unsigned long flags;
} dev[1]; /* allocated with extra space depending of RAID geometry */
};
+
+/* stripe_head_state - collects and tracks the dynamic state of a stripe_head
+ * for handle_stripe. It is only valid under spin_lock(sh->lock);
+ */
+struct stripe_head_state {
+ int syncing, expanding, expanded;
+ int locked, uptodate, to_read, to_write, failed, written;
+ int to_fill, compute, req_compute, non_overwrite;
+ int failed_num;
+};
+
+/* r6_state - extra state data only relevant to r6 */
+struct r6_state {
+ int p_failed, q_failed, qd_idx, failed_num[2];
+};
+
/* Flags */
#define R5_UPTODATE 0 /* page contains current data */
#define R5_LOCKED 1 /* IO has been submitted on "req" */
@@ -158,6 +222,15 @@ struct stripe_head {
#define R5_ReWrite 9 /* have tried to over-write the readerror */
#define R5_Expanded 10 /* This block now has post-expand data */
+#define R5_Wantcompute 11 /* compute_block in progress treat as
+ * uptodate
+ */
+#define R5_Wantfill 12 /* dev->toread contains a bio that needs
+ * filling
+ */
+#define R5_Wantprexor 13 /* distinguish blocks ready for rmw from
+ * other "towrites"
+ */
/*
* Write method
*/
@@ -180,6 +253,24 @@ struct stripe_head {
#define STRIPE_EXPAND_SOURCE 10
#define STRIPE_EXPAND_READY 11
/*
+ * Operations flags (in issue order)
+ */
+#define STRIPE_OP_BIOFILL 0
+#define STRIPE_OP_COMPUTE_BLK 1
+#define STRIPE_OP_PREXOR 2
+#define STRIPE_OP_BIODRAIN 3
+#define STRIPE_OP_POSTXOR 4
+#define STRIPE_OP_CHECK 5
+#define STRIPE_OP_IO 6
+
+/* modifiers to the base operations
+ * STRIPE_OP_MOD_REPAIR_PD - compute the parity block and write it back
+ * STRIPE_OP_MOD_DMA_CHECK - parity is not corrupted by the check
+ */
+#define STRIPE_OP_MOD_REPAIR_PD 7
+#define STRIPE_OP_MOD_DMA_CHECK 8
+
+/*
* Plugging:
*
* To improve write throughput, we need to delay the handling of some
diff --git a/include/linux/raid/xor.h b/include/linux/raid/xor.h
index f0d67cbdea40..3e120587eada 100644
--- a/include/linux/raid/xor.h
+++ b/include/linux/raid/xor.h
@@ -3,9 +3,10 @@
#include <linux/raid/md.h>
-#define MAX_XOR_BLOCKS 5
+#define MAX_XOR_BLOCKS 4
-extern void xor_block(unsigned int count, unsigned int bytes, void **ptr);
+extern void xor_blocks(unsigned int count, unsigned int bytes,
+ void *dest, void **srcs);
struct xor_block_template {
struct xor_block_template *next;
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index 1dd1c707311f..85ea63f462af 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -67,6 +67,11 @@ extern void kernel_power_off(void);
void ctrl_alt_del(void);
+#define POWEROFF_CMD_PATH_LEN 256
+extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN];
+
+extern int orderly_poweroff(bool force);
+
/*
* Emergency restart, callable from an interrupt handler.
*/
diff --git a/include/linux/resume-trace.h b/include/linux/resume-trace.h
index 81e9299ca148..f3f4f28c6960 100644
--- a/include/linux/resume-trace.h
+++ b/include/linux/resume-trace.h
@@ -2,6 +2,7 @@
#define RESUME_TRACE_H
#ifdef CONFIG_PM_TRACE
+#include <asm/resume-trace.h>
extern int pm_trace_enabled;
@@ -9,20 +10,10 @@ struct device;
extern void set_trace_device(struct device *);
extern void generate_resume_trace(void *tracedata, unsigned int user);
-#define TRACE_DEVICE(dev) set_trace_device(dev)
-#define TRACE_RESUME(user) do { \
- if (pm_trace_enabled) { \
- void *tracedata; \
- asm volatile("movl $1f,%0\n" \
- ".section .tracedata,\"a\"\n" \
- "1:\t.word %c1\n" \
- "\t.long %c2\n" \
- ".previous" \
- :"=r" (tracedata) \
- : "i" (__LINE__), "i" (__FILE__)); \
- generate_resume_trace(tracedata, user); \
- } \
-} while (0)
+#define TRACE_DEVICE(dev) do { \
+ if (pm_trace_enabled) \
+ set_trace_device(dev); \
+ } while(0)
#else
diff --git a/include/linux/rtc/m48t59.h b/include/linux/rtc/m48t59.h
new file mode 100644
index 000000000000..e8c7c21ceb1f
--- /dev/null
+++ b/include/linux/rtc/m48t59.h
@@ -0,0 +1,57 @@
+/*
+ * include/linux/rtc/m48t59.h
+ *
+ * Definitions for the platform data of m48t59 RTC chip driver.
+ *
+ * Copyright (c) 2007 Wind River Systems, Inc.
+ *
+ * Mark Zhan <rongkai.zhan@windriver.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.
+ */
+
+#ifndef _LINUX_RTC_M48T59_H_
+#define _LINUX_RTC_M48T59_H_
+
+/*
+ * M48T59 Register Offset
+ */
+#define M48T59_YEAR 0x1fff
+#define M48T59_MONTH 0x1ffe
+#define M48T59_MDAY 0x1ffd /* Day of Month */
+#define M48T59_WDAY 0x1ffc /* Day of Week */
+#define M48T59_WDAY_CB 0x20 /* Century Bit */
+#define M48T59_WDAY_CEB 0x10 /* Century Enable Bit */
+#define M48T59_HOUR 0x1ffb
+#define M48T59_MIN 0x1ffa
+#define M48T59_SEC 0x1ff9
+#define M48T59_CNTL 0x1ff8
+#define M48T59_CNTL_READ 0x40
+#define M48T59_CNTL_WRITE 0x80
+#define M48T59_WATCHDOG 0x1ff7
+#define M48T59_INTR 0x1ff6
+#define M48T59_INTR_AFE 0x80 /* Alarm Interrupt Enable */
+#define M48T59_INTR_ABE 0x20
+#define M48T59_ALARM_DATE 0x1ff5
+#define M48T59_ALARM_HOUR 0x1ff4
+#define M48T59_ALARM_MIN 0x1ff3
+#define M48T59_ALARM_SEC 0x1ff2
+#define M48T59_UNUSED 0x1ff1
+#define M48T59_FLAGS 0x1ff0
+#define M48T59_FLAGS_WDT 0x80 /* watchdog timer expired */
+#define M48T59_FLAGS_AF 0x40 /* alarm */
+#define M48T59_FLAGS_BF 0x10 /* low battery */
+
+#define M48T59_NVRAM_SIZE 0x1ff0
+
+struct m48t59_plat_data {
+ /* The method to access M48T59 registers,
+ * NOTE: The 'ofs' should be 0x00~0x1fff
+ */
+ void (*write_byte)(struct device *dev, u32 ofs, u8 val);
+ unsigned char (*read_byte)(struct device *dev, u32 ofs);
+};
+
+#endif /* _LINUX_RTC_M48T59_H_ */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 1fae30af91f3..c91476ce314a 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -261,7 +261,7 @@ enum rtattr_type_t
RTA_FLOW,
RTA_CACHEINFO,
RTA_SESSION,
- RTA_MP_ALGO,
+ RTA_MP_ALGO, /* no longer used */
RTA_TABLE,
__RTA_MAX
};
@@ -570,10 +570,16 @@ static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
}
extern int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len);
+extern int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
+ struct rtattr *rta, int len);
#define rtattr_parse_nested(tb, max, rta) \
rtattr_parse((tb), (max), RTA_DATA((rta)), RTA_PAYLOAD((rta)))
+#define rtattr_parse_nested_compat(tb, max, rta, data, len) \
+({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL; \
+ __rtattr_parse_nested_compat(tb, max, rta, len); })
+
extern int rtnetlink_send(struct sk_buff *skb, u32 pid, u32 group, int echo);
extern int rtnl_unicast(struct sk_buff *skb, u32 pid);
extern int rtnl_notify(struct sk_buff *skb, u32 pid, u32 group,
@@ -638,6 +644,18 @@ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const voi
({ (start)->rta_len = skb_tail_pointer(skb) - (unsigned char *)(start); \
(skb)->len; })
+#define RTA_NEST_COMPAT(skb, type, attrlen, data) \
+({ struct rtattr *__start = (struct rtattr *)skb_tail_pointer(skb); \
+ RTA_PUT(skb, type, attrlen, data); \
+ RTA_NEST(skb, type); \
+ __start; })
+
+#define RTA_NEST_COMPAT_END(skb, start) \
+({ struct rtattr *__nest = (void *)(start) + NLMSG_ALIGN((start)->rta_len); \
+ (start)->rta_len = skb_tail_pointer(skb) - (unsigned char *)(start); \
+ RTA_NEST_END(skb, __nest); \
+ (skb)->len; })
+
#define RTA_NEST_CANCEL(skb, start) \
({ if (start) \
skb_trim(skb, (unsigned char *) (start) - (skb)->data); \
diff --git a/include/linux/sched.h b/include/linux/sched.h
index cfb680585ab8..33b9b4841ee7 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -26,6 +26,7 @@
#define CLONE_STOPPED 0x02000000 /* Start in stopped state */
#define CLONE_NEWUTS 0x04000000 /* New utsname group? */
#define CLONE_NEWIPC 0x08000000 /* New ipcs */
+#define CLONE_NEWUSER 0x10000000 /* New user namespace */
/*
* Scheduling policies
@@ -287,6 +288,7 @@ extern signed long schedule_timeout_uninterruptible(signed long timeout);
asmlinkage void schedule(void);
struct nsproxy;
+struct user_namespace;
/* Maximum number of active map areas.. This is a random (large) number */
#define DEFAULT_MAX_MAP_COUNT 65536
@@ -343,6 +345,27 @@ typedef unsigned long mm_counter_t;
(mm)->hiwater_vm = (mm)->total_vm; \
} while (0)
+extern void set_dumpable(struct mm_struct *mm, int value);
+extern int get_dumpable(struct mm_struct *mm);
+
+/* mm flags */
+/* dumpable bits */
+#define MMF_DUMPABLE 0 /* core dump is permitted */
+#define MMF_DUMP_SECURELY 1 /* core file is readable only by root */
+#define MMF_DUMPABLE_BITS 2
+
+/* coredump filter bits */
+#define MMF_DUMP_ANON_PRIVATE 2
+#define MMF_DUMP_ANON_SHARED 3
+#define MMF_DUMP_MAPPED_PRIVATE 4
+#define MMF_DUMP_MAPPED_SHARED 5
+#define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS
+#define MMF_DUMP_FILTER_BITS 4
+#define MMF_DUMP_FILTER_MASK \
+ (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT)
+#define MMF_DUMP_FILTER_DEFAULT \
+ ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED))
+
struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */
struct rb_root mm_rb;
@@ -400,7 +423,7 @@ struct mm_struct {
unsigned int token_priority;
unsigned int last_interval;
- unsigned char dumpable:2;
+ unsigned long flags; /* Must use atomic bitops to access the bits */
/* coredumping support */
int core_waiters;
@@ -529,6 +552,10 @@ struct signal_struct {
#ifdef CONFIG_TASKSTATS
struct taskstats *stats;
#endif
+#ifdef CONFIG_AUDIT
+ unsigned audit_tty;
+ struct tty_audit_buf *tty_audit_buf;
+#endif
};
/* Context switch must be unlocked if interrupts are to be enabled */
@@ -972,7 +999,8 @@ struct task_struct {
unsigned int rt_priority;
cputime_t utime, stime;
unsigned long nvcsw, nivcsw; /* context switch counts */
- struct timespec start_time;
+ struct timespec start_time; /* monotonic time */
+ struct timespec real_start_time; /* boot based time */
/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
unsigned long min_flt, maj_flt;
@@ -1320,6 +1348,13 @@ static inline int set_cpus_allowed(struct task_struct *p, cpumask_t new_mask)
#endif
extern unsigned long long sched_clock(void);
+
+/*
+ * For kernel-internal use: high-speed (but slightly incorrect) per-cpu
+ * clock constructed from sched_clock():
+ */
+extern unsigned long long cpu_clock(int cpu);
+
extern unsigned long long
task_sched_runtime(struct task_struct *task);
@@ -1403,7 +1438,7 @@ extern struct task_struct *find_task_by_pid_type(int type, int pid);
extern void __set_special_pids(pid_t session, pid_t pgrp);
/* per-UID process charging. */
-extern struct user_struct * alloc_uid(uid_t);
+extern struct user_struct * alloc_uid(struct user_namespace *, uid_t);
static inline struct user_struct *get_uid(struct user_struct *u)
{
atomic_inc(&u->__count);
diff --git a/include/linux/screen_info.h b/include/linux/screen_info.h
index b02308ee7667..3ee412bc00ec 100644
--- a/include/linux/screen_info.h
+++ b/include/linux/screen_info.h
@@ -10,7 +10,7 @@
struct screen_info {
u8 orig_x; /* 0x00 */
u8 orig_y; /* 0x01 */
- u16 dontuse1; /* 0x02 -- EXT_MEM_K sits here */
+ u16 ext_mem_k; /* 0x02 */
u16 orig_video_page; /* 0x04 */
u8 orig_video_mode; /* 0x06 */
u8 orig_video_cols; /* 0x07 */
@@ -27,7 +27,7 @@ struct screen_info {
u16 lfb_depth; /* 0x16 */
u32 lfb_base; /* 0x18 */
u32 lfb_size; /* 0x1c */
- u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
+ u16 cl_magic, cl_offset; /* 0x20 */
u16 lfb_linelength; /* 0x24 */
u8 red_size; /* 0x26 */
u8 red_pos; /* 0x27 */
@@ -42,9 +42,8 @@ struct screen_info {
u16 pages; /* 0x32 */
u16 vesa_attributes; /* 0x34 */
u32 capabilities; /* 0x36 */
- /* 0x3a -- 0x3b reserved for future expansion */
- /* 0x3c -- 0x3f micro stack for relocatable kernels */
-};
+ u8 _reserved[6]; /* 0x3a */
+} __attribute__((packed));
extern struct screen_info screen_info;
diff --git a/include/linux/scx200_gpio.h b/include/linux/scx200_gpio.h
index 1a82d30c4b17..d2b058130eb1 100644
--- a/include/linux/scx200_gpio.h
+++ b/include/linux/scx200_gpio.h
@@ -1,5 +1,3 @@
-#include <linux/spinlock.h>
-
u32 scx200_gpio_configure(unsigned index, u32 set, u32 clear);
extern unsigned scx200_gpio_base;
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 3e8b1cf54303..262a8dccfa81 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -4,8 +4,6 @@
#ifdef CONFIG_SECCOMP
-#define NR_SECCOMP_MODES 1
-
#include <linux/thread_info.h>
#include <asm/seccomp.h>
@@ -18,20 +16,23 @@ static inline void secure_computing(int this_syscall)
__secure_computing(this_syscall);
}
-static inline int has_secure_computing(struct thread_info *ti)
-{
- return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP));
-}
+extern long prctl_get_seccomp(void);
+extern long prctl_set_seccomp(unsigned long);
#else /* CONFIG_SECCOMP */
typedef struct { } seccomp_t;
#define secure_computing(x) do { } while (0)
-/* static inline to preserve typechecking */
-static inline int has_secure_computing(struct thread_info *ti)
+
+static inline long prctl_get_seccomp(void)
+{
+ return -EINVAL;
+}
+
+static inline long prctl_set_seccomp(unsigned long arg2)
{
- return 0;
+ return -EINVAL;
}
#endif /* CONFIG_SECCOMP */
diff --git a/include/linux/security.h b/include/linux/security.h
index 9eb9e0fe0331..c11dc8aa0351 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -71,6 +71,7 @@ struct xfrm_user_sec_ctx;
extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb);
extern int cap_netlink_recv(struct sk_buff *skb, int cap);
+extern unsigned long mmap_min_addr;
/*
* Values used in the task_security_ops calls
*/
@@ -1241,8 +1242,9 @@ struct security_operations {
int (*file_ioctl) (struct file * file, unsigned int cmd,
unsigned long arg);
int (*file_mmap) (struct file * file,
- unsigned long reqprot,
- unsigned long prot, unsigned long flags);
+ unsigned long reqprot, unsigned long prot,
+ unsigned long flags, unsigned long addr,
+ unsigned long addr_only);
int (*file_mprotect) (struct vm_area_struct * vma,
unsigned long reqprot,
unsigned long prot);
@@ -1814,9 +1816,12 @@ static inline int security_file_ioctl (struct file *file, unsigned int cmd,
static inline int security_file_mmap (struct file *file, unsigned long reqprot,
unsigned long prot,
- unsigned long flags)
+ unsigned long flags,
+ unsigned long addr,
+ unsigned long addr_only)
{
- return security_ops->file_mmap (file, reqprot, prot, flags);
+ return security_ops->file_mmap (file, reqprot, prot, flags, addr,
+ addr_only);
}
static inline int security_file_mprotect (struct vm_area_struct *vma,
@@ -2489,7 +2494,9 @@ static inline int security_file_ioctl (struct file *file, unsigned int cmd,
static inline int security_file_mmap (struct file *file, unsigned long reqprot,
unsigned long prot,
- unsigned long flags)
+ unsigned long flags,
+ unsigned long addr,
+ unsigned long addr_only)
{
return 0;
}
diff --git a/include/linux/serial.h b/include/linux/serial.h
index 33fc8cb8ddfb..deb714314fb1 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -177,11 +177,5 @@ struct serial_icounter_struct {
#ifdef __KERNEL__
#include <linux/compiler.h>
-/* Allow architectures to override entries in serial8250_ports[] at run time: */
-struct uart_port; /* forward declaration */
-extern int early_serial_setup(struct uart_port *port);
-extern int early_serial_console_init(char *options);
-extern int serial8250_start_console(struct uart_port *port, char *options);
-
#endif /* __KERNEL__ */
#endif /* _LINUX_SERIAL_H */
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 71310d80c09a..8518fa2a6f89 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -60,4 +60,10 @@ void serial8250_unregister_port(int line);
void serial8250_suspend_port(int line);
void serial8250_resume_port(int line);
+extern int early_serial_setup(struct uart_port *port);
+
+extern int serial8250_find_port(struct uart_port *p);
+extern int serial8250_find_port_for_earlycon(void);
+extern int setup_early_serial8250_console(char *cmdline);
+
#endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 7f2c99d66e9d..773d8d8828ad 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -62,8 +62,9 @@
/* NEC v850. */
#define PORT_V850E_UART 40
-/* DZ */
-#define PORT_DZ 47
+/* DEC */
+#define PORT_DZ 46
+#define PORT_ZS 47
/* Parisc type numbers. */
#define PORT_MUX 48
@@ -142,6 +143,9 @@
/* Micrel KS8695 */
#define PORT_KS8695 76
+/* Broadcom SB1250, etc. SOC */
+#define PORT_SB1250_DUART 77
+
#ifdef __KERNEL__
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 1ebf0455e224..9f3825014674 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -209,5 +209,7 @@ static inline void serio_unpin_driver(struct serio *serio)
#define SERIO_PENMOUNT 0x31
#define SERIO_TOUCHRIGHT 0x32
#define SERIO_TOUCHWIN 0x33
+#define SERIO_TAOSEVM 0x34
+#define SERIO_FUJITSU 0x35
#endif
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 9a5eac508e5e..0ae338866240 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -6,7 +6,6 @@
#ifdef __KERNEL__
#include <linux/list.h>
-#include <linux/spinlock.h>
/*
* Real Time signals may be queued.
@@ -238,12 +237,15 @@ extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct
extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
extern long do_sigpending(void __user *, unsigned long);
extern int sigprocmask(int, sigset_t *, sigset_t *);
+extern int show_unhandled_signals;
struct pt_regs;
extern int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, struct pt_regs *regs, void *cookie);
extern struct kmem_cache *sighand_cachep;
+int unhandled_signal(struct task_struct *tsk, int sig);
+
/*
* In POSIX a signal is sent either to a specific thread (Linux task)
* or to the process as a whole (Linux thread group). How the signal
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 6f0b2f7d0010..ce256438e619 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -65,13 +65,20 @@
* is able to produce some skb->csum, it MUST use COMPLETE,
* not UNNECESSARY.
*
+ * PARTIAL: identical to the case for output below. This may occur
+ * on a packet received directly from another Linux OS, e.g.,
+ * a virtualised Linux kernel on the same host. The packet can
+ * be treated in the same way as UNNECESSARY except that on
+ * output (i.e., forwarding) the checksum must be filled in
+ * by the OS or the hardware.
+ *
* B. Checksumming on output.
*
* NONE: skb is checksummed by protocol or csum is not required.
*
* PARTIAL: device is required to csum packet as seen by hard_start_xmit
- * from skb->transport_header to the end and to record the checksum
- * at skb->transport_header + skb->csum.
+ * from skb->csum_start to the end and to record the checksum
+ * at skb->csum_start + skb->csum_offset.
*
* Device must show its capabilities in dev->features, set
* at device setup time.
@@ -82,6 +89,7 @@
* TCP/UDP over IPv4. Sigh. Vendors like this
* way by an unknown reason. Though, see comment above
* about CHECKSUM_UNNECESSARY. 8)
+ * NETIF_F_IPV6_CSUM about as dumb as the last one but does IPv6 instead.
*
* Any questions? No questions, good. --ANK
*/
@@ -147,8 +155,8 @@ struct skb_shared_info {
/* We divide dataref into two halves. The higher 16 bits hold references
* to the payload part of skb->data. The lower 16 bits hold references to
- * the entire skb->data. It is up to the users of the skb to agree on
- * where the payload starts.
+ * the entire skb->data. A clone of a headerless skb holds the length of
+ * the header in skb->hdr_len.
*
* All users must obey the rule that the skb->data reference count must be
* greater than or equal to the payload reference count.
@@ -196,7 +204,6 @@ typedef unsigned char *sk_buff_data_t;
* @sk: Socket we are owned by
* @tstamp: Time we arrived
* @dev: Device we arrived on/are leaving by
- * @iif: ifindex of device we arrived on
* @transport_header: Transport layer header
* @network_header: Network layer header
* @mac_header: Link layer header
@@ -206,6 +213,7 @@ typedef unsigned char *sk_buff_data_t;
* @len: Length of actual data
* @data_len: Data length
* @mac_len: Length of link layer header
+ * @hdr_len: writable header length of cloned skb
* @csum: Checksum (must include start/offset pair)
* @csum_start: Offset from skb->head where checksumming should start
* @csum_offset: Offset from csum_start where checksum should be stored
@@ -227,9 +235,12 @@ typedef unsigned char *sk_buff_data_t;
* @mark: Generic packet mark
* @nfct: Associated connection, if any
* @ipvs_property: skbuff is owned by ipvs
+ * @nf_trace: netfilter packet trace flag
* @nfctinfo: Relationship of this skb to the connection
* @nfct_reasm: netfilter conntrack re-assembly pointer
* @nf_bridge: Saved data about a bridged frame - see br_netfilter.c
+ * @iif: ifindex of device we arrived on
+ * @queue_mapping: Queue mapping for multiqueue devices
* @tc_index: Traffic control index
* @tc_verd: traffic control verdict
* @dma_cookie: a cookie to one of several possible DMA operations
@@ -245,8 +256,6 @@ struct sk_buff {
struct sock *sk;
ktime_t tstamp;
struct net_device *dev;
- int iif;
- /* 4 byte hole on 64 bit*/
struct dst_entry *dst;
struct sec_path *sp;
@@ -260,8 +269,9 @@ struct sk_buff {
char cb[48];
unsigned int len,
- data_len,
- mac_len;
+ data_len;
+ __u16 mac_len,
+ hdr_len;
union {
__wsum csum;
struct {
@@ -277,7 +287,8 @@ struct sk_buff {
nfctinfo:3;
__u8 pkt_type:3,
fclone:2,
- ipvs_property:1;
+ ipvs_property:1,
+ nf_trace:1;
__be16 protocol;
void (*destructor)(struct sk_buff *skb);
@@ -288,12 +299,18 @@ struct sk_buff {
#ifdef CONFIG_BRIDGE_NETFILTER
struct nf_bridge_info *nf_bridge;
#endif
+
+ int iif;
+ __u16 queue_mapping;
+
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
__u16 tc_verd; /* traffic control verdict */
#endif
#endif
+ /* 2 byte hole */
+
#ifdef CONFIG_NET_DMA
dma_cookie_t dma_cookie;
#endif
@@ -1322,6 +1339,20 @@ static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
}
/**
+ * skb_clone_writable - is the header of a clone writable
+ * @skb: buffer to check
+ * @len: length up to which to write
+ *
+ * Returns true if modifying the header part of the cloned buffer
+ * does not requires the data to be copied.
+ */
+static inline int skb_clone_writable(struct sk_buff *skb, int len)
+{
+ return !skb_header_cloned(skb) &&
+ skb_headroom(skb) + len <= skb->hdr_len;
+}
+
+/**
* skb_cow - copy header of skb when it is required
* @skb: buffer to cow
* @headroom: needed headroom
@@ -1608,7 +1639,7 @@ static inline int skb_csum_unnecessary(const struct sk_buff *skb)
* if skb->ip_summed is CHECKSUM_UNNECESSARY which indicates that the
* hardware has already verified the correctness of the checksum.
*/
-static inline unsigned int skb_checksum_complete(struct sk_buff *skb)
+static inline __sum16 skb_checksum_complete(struct sk_buff *skb)
{
return skb_csum_unnecessary(skb) ?
0 : __skb_checksum_complete(skb);
@@ -1709,6 +1740,20 @@ static inline void skb_init_secmark(struct sk_buff *skb)
{ }
#endif
+static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ skb->queue_mapping = queue_mapping;
+#endif
+}
+
+static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_buff *from)
+{
+#ifdef CONFIG_NETDEVICES_MULTIQUEUE
+ to->queue_mapping = from->queue_mapping;
+#endif
+}
+
static inline int skb_is_gso(const struct sk_buff *skb)
{
return skb_shinfo(skb)->gso_size;
diff --git a/include/linux/slab.h b/include/linux/slab.h
index cebcd3833c76..d859354b9e51 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -14,8 +14,6 @@
#include <linux/gfp.h>
#include <linux/types.h>
-typedef struct kmem_cache kmem_cache_t __deprecated;
-
/*
* Flags to pass to kmem_cache_create().
* The ones marked DEBUG are only valid if CONFIG_SLAB_DEBUG is set.
@@ -33,6 +31,19 @@ typedef struct kmem_cache kmem_cache_t __deprecated;
#define SLAB_TRACE 0x00200000UL /* Trace allocations and frees */
/*
+ * ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
+ *
+ * Dereferencing ZERO_SIZE_PTR will lead to a distinct access fault.
+ *
+ * ZERO_SIZE_PTR can be passed to kfree though in the same way that NULL can.
+ * Both make kfree a no-op.
+ */
+#define ZERO_SIZE_PTR ((void *)16)
+
+#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
+ (unsigned long)ZERO_SIZE_PTR)
+
+/*
* struct kmem_cache related prototypes
*/
void __init kmem_cache_init(void);
@@ -40,12 +51,9 @@ int slab_is_available(void);
struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
unsigned long,
- void (*)(void *, struct kmem_cache *, unsigned long),
void (*)(void *, struct kmem_cache *, unsigned long));
void kmem_cache_destroy(struct kmem_cache *);
int kmem_cache_shrink(struct kmem_cache *);
-void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
-void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
void kmem_cache_free(struct kmem_cache *, void *);
unsigned int kmem_cache_size(struct kmem_cache *);
const char *kmem_cache_name(struct kmem_cache *);
@@ -61,17 +69,7 @@ int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
*/
#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\
sizeof(struct __struct), __alignof__(struct __struct),\
- (__flags), NULL, NULL)
-
-#ifdef CONFIG_NUMA
-extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
-#else
-static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
- gfp_t flags, int node)
-{
- return kmem_cache_alloc(cachep, flags);
-}
-#endif
+ (__flags), NULL)
/*
* The largest kmalloc size supported by the slab allocators is
@@ -91,59 +89,50 @@ static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
/*
* Common kmalloc functions provided by all allocators
*/
-void *__kmalloc(size_t, gfp_t);
-void *__kzalloc(size_t, gfp_t);
void * __must_check krealloc(const void *, size_t, gfp_t);
void kfree(const void *);
size_t ksize(const void *);
-/**
- * kcalloc - allocate memory for an array. The memory is set to zero.
- * @n: number of elements.
- * @size: element size.
- * @flags: the type of memory to allocate.
- */
-static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
-{
- if (n != 0 && size > ULONG_MAX / n)
- return NULL;
- return __kzalloc(n * size, flags);
-}
-
/*
* Allocator specific definitions. These are mainly used to establish optimized
- * ways to convert kmalloc() calls to kmem_cache_alloc() invocations by selecting
- * the appropriate general cache at compile time.
+ * ways to convert kmalloc() calls to kmem_cache_alloc() invocations by
+ * selecting the appropriate general cache at compile time.
+ *
+ * Allocators must define at least:
+ *
+ * kmem_cache_alloc()
+ * __kmalloc()
+ * kmalloc()
+ *
+ * Those wishing to support NUMA must also define:
+ *
+ * kmem_cache_alloc_node()
+ * kmalloc_node()
+ *
+ * See each allocator definition file for additional comments and
+ * implementation notes.
*/
-
-#if defined(CONFIG_SLAB) || defined(CONFIG_SLUB)
#ifdef CONFIG_SLUB
#include <linux/slub_def.h>
+#elif defined(CONFIG_SLOB)
+#include <linux/slob_def.h>
#else
#include <linux/slab_def.h>
-#endif /* !CONFIG_SLUB */
-#else
-
-/*
- * Fallback definitions for an allocator not wanting to provide
- * its own optimized kmalloc definitions (like SLOB).
- */
+#endif
/**
- * kmalloc - allocate memory
- * @size: how many bytes of memory are required.
+ * kcalloc - allocate memory for an array. The memory is set to zero.
+ * @n: number of elements.
+ * @size: element size.
* @flags: the type of memory to allocate.
*
- * kmalloc is the normal method of allocating memory
- * in the kernel.
- *
* The @flags argument may be one of:
*
* %GFP_USER - Allocate memory on behalf of user. May sleep.
*
* %GFP_KERNEL - Allocate normal kernel ram. May sleep.
*
- * %GFP_ATOMIC - Allocation will not sleep.
+ * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools.
* For example, use this inside interrupt handlers.
*
* %GFP_HIGHUSER - Allocate pages from high memory.
@@ -152,18 +141,22 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
*
* %GFP_NOFS - Do not make any fs calls while trying to get memory.
*
+ * %GFP_NOWAIT - Allocation will not sleep.
+ *
+ * %GFP_THISNODE - Allocate node-local memory only.
+ *
+ * %GFP_DMA - Allocation suitable for DMA.
+ * Should only be used for kmalloc() caches. Otherwise, use a
+ * slab created with SLAB_DMA.
+ *
* Also it is possible to set different flags by OR'ing
* in one or more of the following additional @flags:
*
* %__GFP_COLD - Request cache-cold pages instead of
* trying to return cache-warm pages.
*
- * %__GFP_DMA - Request memory from the DMA-capable zone.
- *
* %__GFP_HIGH - This allocation has high priority and may use emergency pools.
*
- * %__GFP_HIGHMEM - Allocated memory may be from highmem.
- *
* %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail
* (think twice before using).
*
@@ -173,24 +166,29 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
* %__GFP_NOWARN - If allocation fails, don't issue any warnings.
*
* %__GFP_REPEAT - If allocation fails initially, try once more before failing.
+ *
+ * There are other flags available as well, but these are not intended
+ * for general use, and so are not documented here. For a full list of
+ * potential flags, always refer to linux/gfp.h.
*/
-static inline void *kmalloc(size_t size, gfp_t flags)
+static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
{
- return __kmalloc(size, flags);
+ if (n != 0 && size > ULONG_MAX / n)
+ return NULL;
+ return __kmalloc(n * size, flags | __GFP_ZERO);
}
+#if !defined(CONFIG_NUMA) && !defined(CONFIG_SLOB)
/**
- * kzalloc - allocate memory. The memory is set to zero.
+ * kmalloc_node - allocate memory from a specific node
* @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate (see kmalloc).
+ * @flags: the type of memory to allocate (see kcalloc).
+ * @node: node to allocate from.
+ *
+ * kmalloc() for non-local nodes, used to allocate from a specific node
+ * if available. Equivalent to kmalloc() in the non-NUMA single-node
+ * case.
*/
-static inline void *kzalloc(size_t size, gfp_t flags)
-{
- return __kzalloc(size, flags);
-}
-#endif
-
-#ifndef CONFIG_NUMA
static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
return kmalloc(size, flags);
@@ -200,7 +198,15 @@ static inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
{
return __kmalloc(size, flags);
}
-#endif /* !CONFIG_NUMA */
+
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+
+static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
+ gfp_t flags, int node)
+{
+ return kmem_cache_alloc(cachep, flags);
+}
+#endif /* !CONFIG_NUMA && !CONFIG_SLOB */
/*
* kmalloc_track_caller is a special version of kmalloc that records the
@@ -245,6 +251,23 @@ extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, void *);
#endif /* DEBUG_SLAB */
+/*
+ * Shortcuts
+ */
+static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
+{
+ return kmem_cache_alloc(k, flags | __GFP_ZERO);
+}
+
+/**
+ * kzalloc - allocate memory. The memory is set to zero.
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate (see kmalloc).
+ */
+static inline void *kzalloc(size_t size, gfp_t flags)
+{
+ return kmalloc(size, flags | __GFP_ZERO);
+}
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SLAB_H */
-
diff --git a/include/linux/slab_def.h b/include/linux/slab_def.h
index 8d81a60518e4..32bdc2ffd715 100644
--- a/include/linux/slab_def.h
+++ b/include/linux/slab_def.h
@@ -25,10 +25,17 @@ struct cache_sizes {
};
extern struct cache_sizes malloc_sizes[];
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+void *__kmalloc(size_t size, gfp_t flags);
+
static inline void *kmalloc(size_t size, gfp_t flags)
{
if (__builtin_constant_p(size)) {
int i = 0;
+
+ if (!size)
+ return ZERO_SIZE_PTR;
+
#define CACHE(x) \
if (size <= x) \
goto found; \
@@ -51,39 +58,18 @@ found:
return __kmalloc(size, flags);
}
-static inline void *kzalloc(size_t size, gfp_t flags)
-{
- if (__builtin_constant_p(size)) {
- int i = 0;
-#define CACHE(x) \
- if (size <= x) \
- goto found; \
- else \
- i++;
-#include "kmalloc_sizes.h"
-#undef CACHE
- {
- extern void __you_cannot_kzalloc_that_much(void);
- __you_cannot_kzalloc_that_much();
- }
-found:
-#ifdef CONFIG_ZONE_DMA
- if (flags & GFP_DMA)
- return kmem_cache_zalloc(malloc_sizes[i].cs_dmacachep,
- flags);
-#endif
- return kmem_cache_zalloc(malloc_sizes[i].cs_cachep, flags);
- }
- return __kzalloc(size, flags);
-}
-
#ifdef CONFIG_NUMA
extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
+extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
if (__builtin_constant_p(size)) {
int i = 0;
+
+ if (!size)
+ return ZERO_SIZE_PTR;
+
#define CACHE(x) \
if (size <= x) \
goto found; \
diff --git a/include/linux/slob_def.h b/include/linux/slob_def.h
new file mode 100644
index 000000000000..59a3fa476ab9
--- /dev/null
+++ b/include/linux/slob_def.h
@@ -0,0 +1,36 @@
+#ifndef __LINUX_SLOB_DEF_H
+#define __LINUX_SLOB_DEF_H
+
+void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
+
+static inline void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
+{
+ return kmem_cache_alloc_node(cachep, flags, -1);
+}
+
+void *__kmalloc_node(size_t size, gfp_t flags, int node);
+
+static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
+{
+ return __kmalloc_node(size, flags, node);
+}
+
+/**
+ * kmalloc - allocate memory
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate (see kcalloc).
+ *
+ * kmalloc is the normal method of allocating memory
+ * in the kernel.
+ */
+static inline void *kmalloc(size_t size, gfp_t flags)
+{
+ return __kmalloc_node(size, flags, -1);
+}
+
+static inline void *__kmalloc(size_t size, gfp_t flags)
+{
+ return kmalloc(size, flags);
+}
+
+#endif /* __LINUX_SLOB_DEF_H */
diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h
index 6207a3d8da71..124270df8734 100644
--- a/include/linux/slub_def.h
+++ b/include/linux/slub_def.h
@@ -16,7 +16,9 @@ struct kmem_cache_node {
unsigned long nr_partial;
atomic_long_t nr_slabs;
struct list_head partial;
+#ifdef CONFIG_SLUB_DEBUG
struct list_head full;
+#endif
};
/*
@@ -44,7 +46,9 @@ struct kmem_cache {
int align; /* Alignment */
const char *name; /* Name (only for display!) */
struct list_head list; /* List of slab caches */
+#ifdef CONFIG_SLUB_DEBUG
struct kobject kobj; /* For sysfs */
+#endif
#ifdef CONFIG_NUMA
int defrag_ratio;
@@ -156,20 +160,11 @@ static inline struct kmem_cache *kmalloc_slab(size_t size)
#define SLUB_DMA __GFP_DMA
#else
/* Disable DMA functionality */
-#define SLUB_DMA 0
+#define SLUB_DMA (__force gfp_t)0
#endif
-
-/*
- * ZERO_SIZE_PTR will be returned for zero sized kmalloc requests.
- *
- * Dereferencing ZERO_SIZE_PTR will lead to a distinct access fault.
- *
- * ZERO_SIZE_PTR can be passed to kfree though in the same way that NULL can.
- * Both make kfree a no-op.
- */
-#define ZERO_SIZE_PTR ((void *)16)
-
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
+void *__kmalloc(size_t size, gfp_t flags);
static inline void *kmalloc(size_t size, gfp_t flags)
{
@@ -184,21 +179,9 @@ static inline void *kmalloc(size_t size, gfp_t flags)
return __kmalloc(size, flags);
}
-static inline void *kzalloc(size_t size, gfp_t flags)
-{
- if (__builtin_constant_p(size) && !(flags & SLUB_DMA)) {
- struct kmem_cache *s = kmalloc_slab(size);
-
- if (!s)
- return ZERO_SIZE_PTR;
-
- return kmem_cache_zalloc(s, flags);
- } else
- return __kzalloc(size, flags);
-}
-
#ifdef CONFIG_NUMA
-extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
+void *__kmalloc_node(size_t size, gfp_t flags, int node);
+void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
{
diff --git a/include/linux/smp.h b/include/linux/smp.h
index 96ac21f8dd73..259a13c3bd98 100644
--- a/include/linux/smp.h
+++ b/include/linux/smp.h
@@ -99,11 +99,14 @@ static inline int up_smp_call_function(void)
static inline void smp_send_reschedule(int cpu) { }
#define num_booting_cpus() 1
#define smp_prepare_boot_cpu() do {} while (0)
-static inline int smp_call_function_single(int cpuid, void (*func) (void *info),
- void *info, int retry, int wait)
-{
- return -EBUSY;
-}
+#define smp_call_function_single(cpuid, func, info, retry, wait) \
+({ \
+ WARN_ON(cpuid != 0); \
+ local_irq_disable(); \
+ (func)(info); \
+ local_irq_enable(); \
+ 0; \
+})
#endif /* !SMP */
diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h
index cf715a40d833..58962c51dee1 100644
--- a/include/linux/smp_lock.h
+++ b/include/linux/smp_lock.h
@@ -3,7 +3,6 @@
#ifdef CONFIG_LOCK_KERNEL
#include <linux/sched.h>
-#include <linux/spinlock.h>
#define kernel_locked() (current->lock_depth >= 0)
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 6e7c9483a6a6..f852e1afd65a 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -253,6 +253,9 @@ struct ucred {
#define MSG_EOF MSG_FIN
+#define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exit for file
+ descriptor received through
+ SCM_RIGHTS */
#if defined(CONFIG_COMPAT)
#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */
#else
@@ -287,6 +290,7 @@ struct ucred {
#define SOL_NETLINK 270
#define SOL_TIPC 271
#define SOL_RXRPC 272
+#define SOL_PPPOL2TP 273
/* IPX options */
#define IPX_TYPE 1
diff --git a/include/linux/sonypi.h b/include/linux/sonypi.h
index 34d4b075f7b8..40c7b5d993b9 100644
--- a/include/linux/sonypi.h
+++ b/include/linux/sonypi.h
@@ -153,8 +153,6 @@
#define SONYPI_COMMAND_GETCAMERAROMVERSION 18 /* obsolete */
#define SONYPI_COMMAND_GETCAMERAREVISION 19 /* obsolete */
-int sonypi_camera_command(int command, u8 value);
-
#endif /* __KERNEL__ */
#endif /* _SONYPI_H_ */
diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
index 3387e44dfd13..334d31411629 100644
--- a/include/linux/spi/ads7846.h
+++ b/include/linux/spi/ads7846.h
@@ -16,6 +16,20 @@ struct ads7846_platform_data {
u16 vref_delay_usecs; /* 0 for external vref; etc */
int keep_vref_on:1; /* set to keep vref on for differential
* measurements as well */
+
+ /* Settling time of the analog signals; a function of Vcc and the
+ * capacitance on the X/Y drivers. If set to non-zero, two samples
+ * are taken with settle_delay us apart, and the second one is used.
+ * ~150 uSec with 0.01uF caps.
+ */
+ u16 settle_delay_usecs;
+
+ /* If set to non-zero, after samples are taken this delay is applied
+ * and penirq is rechecked, to help avoid false events. This value
+ * is affected by the material used to build the touch layer.
+ */
+ u16 penirq_recheck_delay_usecs;
+
u16 x_plate_ohms;
u16 y_plate_ohms;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 1be5ea059477..302b81d1d117 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -76,6 +76,7 @@ struct spi_device {
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
+#define SPI_3WIRE 0x10 /* SI/SO signals shared */
u8 bits_per_word;
int irq;
void *controller_state;
diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h
index 9dbca629dcfb..b8db32cea1de 100644
--- a/include/linux/spi/spi_bitbang.h
+++ b/include/linux/spi/spi_bitbang.h
@@ -26,6 +26,7 @@ struct spi_bitbang {
struct list_head queue;
u8 busy;
u8 use_dma;
+ u8 flags; /* extra spi->mode support */
struct spi_master *master;
diff --git a/include/linux/spi/tle62x0.h b/include/linux/spi/tle62x0.h
new file mode 100644
index 000000000000..60b59187e590
--- /dev/null
+++ b/include/linux/spi/tle62x0.h
@@ -0,0 +1,24 @@
+/*
+ * tle62x0.h - platform glue to Infineon TLE62x0 driver chips
+ *
+ * Copyright 2007 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+struct tle62x0_pdata {
+ unsigned int init_state;
+ unsigned int gpio_count;
+};
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index a946176db638..c376f3b36c89 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -282,6 +282,13 @@ do { \
1 : ({ local_irq_restore(flags); 0; }); \
})
+#define write_trylock_irqsave(lock, flags) \
+({ \
+ local_irq_save(flags); \
+ write_trylock(lock) ? \
+ 1 : ({ local_irq_restore(flags); 0; }); \
+})
+
/*
* Locks two spinlocks l1 and l2.
* l1_first indicates if spinlock l1 should be taken first.
diff --git a/include/linux/spinlock_types.h b/include/linux/spinlock_types.h
index 210549ba4ef4..f6a3a951b79e 100644
--- a/include/linux/spinlock_types.h
+++ b/include/linux/spinlock_types.h
@@ -9,14 +9,14 @@
* Released under the General Public License (GPL).
*/
-#include <linux/lockdep.h>
-
#if defined(CONFIG_SMP)
# include <asm/spinlock_types.h>
#else
# include <linux/spinlock_types_up.h>
#endif
+#include <linux/lockdep.h>
+
typedef struct {
raw_spinlock_t raw_lock;
#if defined(CONFIG_PREEMPT) && defined(CONFIG_SMP)
diff --git a/include/linux/spinlock_types_up.h b/include/linux/spinlock_types_up.h
index 27644af20b7c..04135b0e198e 100644
--- a/include/linux/spinlock_types_up.h
+++ b/include/linux/spinlock_types_up.h
@@ -12,14 +12,10 @@
* Released under the General Public License (GPL).
*/
-#if defined(CONFIG_DEBUG_SPINLOCK) || \
- defined(CONFIG_DEBUG_LOCK_ALLOC)
+#ifdef CONFIG_DEBUG_SPINLOCK
typedef struct {
volatile unsigned int slock;
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
- struct lockdep_map dep_map;
-#endif
} raw_spinlock_t;
#define __RAW_SPIN_LOCK_UNLOCKED { 1 }
@@ -34,9 +30,6 @@ typedef struct { } raw_spinlock_t;
typedef struct {
/* no debug version on UP */
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
- struct lockdep_map dep_map;
-#endif
} raw_rwlock_t;
#define __RAW_RW_LOCK_UNLOCKED { }
diff --git a/include/linux/stacktrace.h b/include/linux/stacktrace.h
index 1d2b084c0185..e7fa657d0c49 100644
--- a/include/linux/stacktrace.h
+++ b/include/linux/stacktrace.h
@@ -13,7 +13,7 @@ extern void save_stack_trace(struct stack_trace *trace);
extern void print_stack_trace(struct stack_trace *trace, int spaces);
#else
# define save_stack_trace(trace) do { } while (0)
-# define print_stack_trace(trace) do { } while (0)
+# define print_stack_trace(trace, spaces) do { } while (0)
#endif
#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index 7f2eb6a477f9..836062b7582a 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -105,8 +105,12 @@ extern void * memchr(const void *,int,__kernel_size_t);
#endif
extern char *kstrdup(const char *s, gfp_t gfp);
+extern char *kstrndup(const char *s, size_t len, gfp_t gfp);
extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
+extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
+extern void argv_free(char **argv);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 534cdc7be58d..7a69ca3bebaf 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -16,6 +16,7 @@
#include <linux/sunrpc/xdr.h>
#include <asm/atomic.h>
+#include <linux/rcupdate.h>
/* size of the nodename buffer */
#define UNX_MAXNODENAME 32
@@ -30,22 +31,28 @@ struct auth_cred {
/*
* Client user credentials
*/
+struct rpc_auth;
+struct rpc_credops;
struct rpc_cred {
struct hlist_node cr_hash; /* hash chain */
- struct rpc_credops * cr_ops;
- unsigned long cr_expire; /* when to gc */
- atomic_t cr_count; /* ref count */
- unsigned short cr_flags; /* various flags */
+ struct list_head cr_lru; /* lru garbage collection */
+ struct rcu_head cr_rcu;
+ struct rpc_auth * cr_auth;
+ const struct rpc_credops *cr_ops;
#ifdef RPC_DEBUG
unsigned long cr_magic; /* 0x0f4aa4f0 */
#endif
+ unsigned long cr_expire; /* when to gc */
+ unsigned long cr_flags; /* various flags */
+ atomic_t cr_count; /* ref count */
uid_t cr_uid;
/* per-flavor data */
};
-#define RPCAUTH_CRED_NEW 0x0001
-#define RPCAUTH_CRED_UPTODATE 0x0002
+#define RPCAUTH_CRED_NEW 0
+#define RPCAUTH_CRED_UPTODATE 1
+#define RPCAUTH_CRED_HASHED 2
#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0
@@ -56,10 +63,10 @@ struct rpc_cred {
#define RPC_CREDCACHE_MASK (RPC_CREDCACHE_NR - 1)
struct rpc_cred_cache {
struct hlist_head hashtable[RPC_CREDCACHE_NR];
- unsigned long nextgc; /* next garbage collection */
- unsigned long expire; /* cache expiry interval */
+ spinlock_t lock;
};
+struct rpc_authops;
struct rpc_auth {
unsigned int au_cslack; /* call cred size estimate */
/* guess at number of u32's auth adds before
@@ -69,7 +76,7 @@ struct rpc_auth {
unsigned int au_verfsize;
unsigned int au_flags; /* various flags */
- struct rpc_authops * au_ops; /* operations */
+ const struct rpc_authops *au_ops; /* operations */
rpc_authflavor_t au_flavor; /* pseudoflavor (note may
* differ from the flavor in
* au_ops->au_flavor in gss
@@ -115,17 +122,19 @@ struct rpc_credops {
void *, __be32 *, void *);
};
-extern struct rpc_authops authunix_ops;
-extern struct rpc_authops authnull_ops;
-#ifdef CONFIG_SUNRPC_SECURE
-extern struct rpc_authops authdes_ops;
-#endif
+extern const struct rpc_authops authunix_ops;
+extern const struct rpc_authops authnull_ops;
+
+void __init rpc_init_authunix(void);
+void __init rpcauth_init_module(void);
+void __exit rpcauth_remove_module(void);
-int rpcauth_register(struct rpc_authops *);
-int rpcauth_unregister(struct rpc_authops *);
+int rpcauth_register(const struct rpc_authops *);
+int rpcauth_unregister(const struct rpc_authops *);
struct rpc_auth * rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
-void rpcauth_destroy(struct rpc_auth *);
+void rpcauth_release(struct rpc_auth *);
struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int);
+void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *);
struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int);
struct rpc_cred * rpcauth_bindcred(struct rpc_task *);
void rpcauth_holdcred(struct rpc_task *);
@@ -138,8 +147,9 @@ int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
int rpcauth_refreshcred(struct rpc_task *);
void rpcauth_invalcred(struct rpc_task *);
int rpcauth_uptodatecred(struct rpc_task *);
-int rpcauth_init_credcache(struct rpc_auth *, unsigned long);
-void rpcauth_free_credcache(struct rpc_auth *);
+int rpcauth_init_credcache(struct rpc_auth *);
+void rpcauth_destroy_credcache(struct rpc_auth *);
+void rpcauth_clear_credcache(struct rpc_cred_cache *);
static inline
struct rpc_cred * get_rpccred(struct rpc_cred *cred)
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h
index 2db2fbf34947..67658e17a375 100644
--- a/include/linux/sunrpc/auth_gss.h
+++ b/include/linux/sunrpc/auth_gss.h
@@ -75,6 +75,7 @@ struct gss_cl_ctx {
struct xdr_netobj gc_wire_ctx;
u32 gc_win;
unsigned long gc_expiry;
+ struct rcu_head gc_rcu;
};
struct gss_upcall_msg;
@@ -85,11 +86,6 @@ struct gss_cred {
struct gss_upcall_msg *gc_upcall;
};
-#define gc_uid gc_base.cr_uid
-#define gc_count gc_base.cr_count
-#define gc_flags gc_base.cr_flags
-#define gc_expire gc_base.cr_expire
-
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_AUTH_GSS_H */
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 66611423c8ee..c0d9d14983b3 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -24,8 +24,10 @@ struct rpc_inode;
* The high-level client handle
*/
struct rpc_clnt {
- atomic_t cl_count; /* Number of clones */
- atomic_t cl_users; /* number of references */
+ struct kref cl_kref; /* Number of references */
+ struct list_head cl_clients; /* Global list of clients */
+ struct list_head cl_tasks; /* List of tasks */
+ spinlock_t cl_lock; /* spinlock */
struct rpc_xprt * cl_xprt; /* transport */
struct rpc_procinfo * cl_procinfo; /* procedure info */
u32 cl_prog, /* RPC program number */
@@ -41,9 +43,7 @@ struct rpc_clnt {
unsigned int cl_softrtry : 1,/* soft timeouts */
cl_intr : 1,/* interruptible */
cl_discrtry : 1,/* disconnect before retry */
- cl_autobind : 1,/* use getport() */
- cl_oneshot : 1,/* dispose after use */
- cl_dead : 1;/* abandoned */
+ cl_autobind : 1;/* use getport() */
struct rpc_rtt * cl_rtt; /* RTO estimator data */
@@ -98,6 +98,7 @@ struct rpc_create_args {
int protocol;
struct sockaddr *address;
size_t addrsize;
+ struct sockaddr *saddress;
struct rpc_timeout *timeout;
char *servername;
struct rpc_program *program;
@@ -110,20 +111,20 @@ struct rpc_create_args {
#define RPC_CLNT_CREATE_HARDRTRY (1UL << 0)
#define RPC_CLNT_CREATE_INTR (1UL << 1)
#define RPC_CLNT_CREATE_AUTOBIND (1UL << 2)
-#define RPC_CLNT_CREATE_ONESHOT (1UL << 3)
-#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 4)
-#define RPC_CLNT_CREATE_NOPING (1UL << 5)
-#define RPC_CLNT_CREATE_DISCRTRY (1UL << 6)
+#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 3)
+#define RPC_CLNT_CREATE_NOPING (1UL << 4)
+#define RPC_CLNT_CREATE_DISCRTRY (1UL << 5)
struct rpc_clnt *rpc_create(struct rpc_create_args *args);
struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *,
struct rpc_program *, int);
struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
-int rpc_shutdown_client(struct rpc_clnt *);
-int rpc_destroy_client(struct rpc_clnt *);
+void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
+
int rpcb_register(u32, u32, int, unsigned short, int *);
-void rpcb_getport(struct rpc_task *);
+int rpcb_getport_sync(struct sockaddr_in *, __u32, __u32, int);
+void rpcb_getport_async(struct rpc_task *);
void rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
@@ -132,20 +133,16 @@ int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg,
void *calldata);
int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
int flags);
+struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
+ int flags);
void rpc_restart_call(struct rpc_task *);
void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
size_t rpc_max_payload(struct rpc_clnt *);
void rpc_force_rebind(struct rpc_clnt *);
-int rpc_ping(struct rpc_clnt *clnt, int flags);
size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
char * rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
-/*
- * Helper function for NFSroot support
- */
-int rpcb_getport_external(struct sockaddr_in *, __u32, __u32, int);
-
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_CLNT_H */
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index 5eca9e442051..459c5fc11d51 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -58,6 +58,7 @@ u32 gss_unwrap(
u32 gss_delete_sec_context(
struct gss_ctx **ctx_id);
+u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service);
u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
@@ -77,7 +78,7 @@ struct gss_api_mech {
struct module *gm_owner;
struct xdr_netobj gm_oid;
char *gm_name;
- struct gss_api_ops *gm_ops;
+ const struct gss_api_ops *gm_ops;
/* pseudoflavors supported by this mechanism: */
int gm_pf_num;
struct pf_desc * gm_pfs;
diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
index ad293760f6eb..51b977a4ca20 100644
--- a/include/linux/sunrpc/rpc_pipe_fs.h
+++ b/include/linux/sunrpc/rpc_pipe_fs.h
@@ -23,9 +23,11 @@ struct rpc_inode {
void *private;
struct list_head pipe;
struct list_head in_upcall;
+ struct list_head in_downcall;
int pipelen;
int nreaders;
int nwriters;
+ int nkern_readwriters;
wait_queue_head_t waitq;
#define RPC_PIPE_WAIT_FOR_OPEN 1
int flags;
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 2047fb202a13..8ea077db0099 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -98,7 +98,6 @@ struct rpc_task {
unsigned short tk_pid; /* debugging aid */
#endif
};
-#define tk_auth tk_client->cl_auth
#define tk_xprt tk_client->cl_xprt
/* support walking a list of tasks on a wait queue */
@@ -110,11 +109,6 @@ struct rpc_task {
if (!list_empty(head) && \
((task=list_entry((head)->next, struct rpc_task, u.tk_wait.list)),1))
-/* .. and walking list of all tasks */
-#define alltask_for_each(task, pos, head) \
- list_for_each(pos, head) \
- if ((task=list_entry(pos, struct rpc_task, tk_task)),1)
-
typedef void (*rpc_action)(struct rpc_task *);
struct rpc_call_ops {
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 129d50f2225c..8531a70da73d 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -212,6 +212,7 @@ struct svc_rqst {
struct svc_pool * rq_pool; /* thread pool */
struct svc_procedure * rq_procinfo; /* procedure info */
struct auth_ops * rq_authop; /* authentication flavour */
+ u32 rq_flavor; /* pseudoflavor */
struct svc_cred rq_cred; /* auth info */
struct sk_buff * rq_skbuff; /* fast recv inet buffer */
struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
@@ -248,6 +249,7 @@ struct svc_rqst {
*/
/* Catering to nfsd */
struct auth_domain * rq_client; /* RPC peer info */
+ struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
struct svc_cacherep * rq_cacherep; /* cache info */
struct knfsd_fh * rq_reffh; /* Referrence filehandle, used to
* determine what device number
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index de92619b0826..22e1ef8e200e 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -127,6 +127,7 @@ extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
extern void svcauth_unix_info_release(void *);
+extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
static inline unsigned long hash_str(char *name, int bits)
{
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
index 5a5db16ab660..417a1def56db 100644
--- a/include/linux/sunrpc/svcauth_gss.h
+++ b/include/linux/sunrpc/svcauth_gss.h
@@ -22,6 +22,7 @@
int gss_svc_init(void);
void gss_svc_shutdown(void);
int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
+u32 svcauth_gss_flavor(struct auth_domain *dom);
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index e21dd93ac4b7..a53e0fa855d2 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -59,6 +59,7 @@ struct svc_sock {
/* cache of various info for TCP sockets */
void *sk_info_authunix;
+ struct sockaddr_storage sk_local; /* local address */
struct sockaddr_storage sk_remote; /* remote peer's address */
int sk_remotelen; /* length of address */
};
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index 9e340fa23c06..c6b53d181bfa 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -12,6 +12,7 @@
#include <linux/uio.h>
#include <asm/byteorder.h>
#include <linux/scatterlist.h>
+#include <linux/smp_lock.h>
/*
* Buffer adjustment
@@ -36,6 +37,21 @@ struct xdr_netobj {
typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
/*
+ * We're still requiring the BKL in the xdr code until it's been
+ * more carefully audited, at which point this wrapper will become
+ * unnecessary.
+ */
+static inline int rpc_call_xdrproc(kxdrproc_t xdrproc, void *rqstp, __be32 *data, void *obj)
+{
+ int ret;
+
+ lock_kernel();
+ ret = xdrproc(rqstp, data, obj);
+ unlock_kernel();
+ return ret;
+}
+
+/*
* Basic structure for transmission/reception of a client XDR message.
* Features a header (for a linear buffer containing RPC headers
* and the data payload for short messages), and then an array of
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 34f7590506fa..d11cedd14f0f 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -17,6 +17,8 @@
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h>
+#ifdef __KERNEL__
+
extern unsigned int xprt_udp_slot_table_entries;
extern unsigned int xprt_tcp_slot_table_entries;
@@ -194,7 +196,13 @@ struct rpc_xprt {
char * address_strings[RPC_DISPLAY_MAX];
};
-#ifdef __KERNEL__
+struct rpc_xprtsock_create {
+ int proto; /* IPPROTO_UDP or IPPROTO_TCP */
+ struct sockaddr * srcaddr; /* optional local address */
+ struct sockaddr * dstaddr; /* remote peer address */
+ size_t addrlen;
+ struct rpc_timeout * timeout; /* optional timeout parameters */
+};
/*
* Transport operations used by ULPs
@@ -204,7 +212,7 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long
/*
* Generic internal transport functions
*/
-struct rpc_xprt * xprt_create_transport(int proto, struct sockaddr *addr, size_t size, struct rpc_timeout *toparms);
+struct rpc_xprt * xprt_create_transport(struct rpc_xprtsock_create *args);
void xprt_connect(struct rpc_task *task);
void xprt_reserve(struct rpc_task *task);
int xprt_reserve_xprt(struct rpc_task *task);
@@ -242,8 +250,8 @@ void xprt_disconnect(struct rpc_xprt *xprt);
/*
* Socket transport setup operations
*/
-struct rpc_xprt * xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to);
-struct rpc_xprt * xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to);
+struct rpc_xprt * xs_setup_udp(struct rpc_xprtsock_create *args);
+struct rpc_xprt * xs_setup_tcp(struct rpc_xprtsock_create *args);
int init_socket_xprt(void);
void cleanup_socket_xprt(void);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 9c7cb6430666..e8e6da394c92 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -43,14 +43,19 @@ static inline void pm_restore_console(void) {}
* @prepare: prepare system for hibernation
* @enter: shut down system after state has been saved to disk
* @finish: finish/clean up after state has been reloaded
+ * @pre_restore: prepare system for the restoration from a hibernation image
+ * @restore_cleanup: clean up after a failing image restoration
*/
struct hibernation_ops {
int (*prepare)(void);
int (*enter)(void);
void (*finish)(void);
+ int (*pre_restore)(void);
+ void (*restore_cleanup)(void);
};
-#if defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND)
+#ifdef CONFIG_PM
+#ifdef CONFIG_SOFTWARE_SUSPEND
/* kernel/power/snapshot.c */
extern void __register_nosave_region(unsigned long b, unsigned long e, int km);
static inline void register_nosave_region(unsigned long b, unsigned long e)
@@ -68,16 +73,14 @@ extern unsigned long get_safe_page(gfp_t gfp_mask);
extern void hibernation_set_ops(struct hibernation_ops *ops);
extern int hibernate(void);
-#else
-static inline void register_nosave_region(unsigned long b, unsigned long e) {}
-static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
+#else /* CONFIG_SOFTWARE_SUSPEND */
static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
static inline void swsusp_set_page_free(struct page *p) {}
static inline void swsusp_unset_page_free(struct page *p) {}
static inline void hibernation_set_ops(struct hibernation_ops *ops) {}
static inline int hibernate(void) { return -ENOSYS; }
-#endif /* defined(CONFIG_PM) && defined(CONFIG_SOFTWARE_SUSPEND) */
+#endif /* CONFIG_SOFTWARE_SUSPEND */
void save_processor_state(void);
void restore_processor_state(void);
@@ -85,4 +88,43 @@ struct saved_context;
void __save_processor_state(struct saved_context *ctxt);
void __restore_processor_state(struct saved_context *ctxt);
+/* kernel/power/main.c */
+extern struct blocking_notifier_head pm_chain_head;
+
+static inline int register_pm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&pm_chain_head, nb);
+}
+
+static inline int unregister_pm_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&pm_chain_head, nb);
+}
+
+#define pm_notifier(fn, pri) { \
+ static struct notifier_block fn##_nb = \
+ { .notifier_call = fn, .priority = pri }; \
+ register_pm_notifier(&fn##_nb); \
+}
+#else /* CONFIG_PM */
+
+static inline int register_pm_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int unregister_pm_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+#define pm_notifier(fn, pri) do { (void)(fn); } while (0)
+#endif /* CONFIG_PM */
+
+#if !defined CONFIG_SOFTWARE_SUSPEND || !defined(CONFIG_PM)
+static inline void register_nosave_region(unsigned long b, unsigned long e)
+{
+}
+#endif
+
#endif /* _LINUX_SWSUSP_H */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 006868881346..665f85f2a3af 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -188,7 +188,8 @@ extern int rotate_reclaimable_page(struct page *page);
extern void swap_setup(void);
/* linux/mm/vmscan.c */
-extern unsigned long try_to_free_pages(struct zone **, gfp_t);
+extern unsigned long try_to_free_pages(struct zone **zones, int order,
+ gfp_t gfp_mask);
extern unsigned long shrink_all_memory(unsigned long nr_pages);
extern int vm_swappiness;
extern int remove_mapping(struct address_space *mapping, struct page *page);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 83d0ec11235e..61def7c8fbb3 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -549,7 +549,7 @@ asmlinkage long sys_inotify_rm_watch(int fd, u32 wd);
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc,
__u32 __user *ustatus);
asmlinkage long sys_spu_create(const char __user *name,
- unsigned int flags, mode_t mode);
+ unsigned int flags, mode_t mode, int fd);
asmlinkage long sys_mknodat(int dfd, const char __user * filename, int mode,
unsigned dev);
@@ -610,6 +610,7 @@ asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemas
asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
const struct itimerspec __user *utmr);
asmlinkage long sys_eventfd(unsigned int count);
+asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
diff --git a/include/linux/sysdev.h b/include/linux/sysdev.h
index e699ab279c2c..e285746588d6 100644
--- a/include/linux/sysdev.h
+++ b/include/linux/sysdev.h
@@ -101,8 +101,7 @@ struct sysdev_attribute {
#define _SYSDEV_ATTR(_name,_mode,_show,_store) \
{ \
- .attr = { .name = __stringify(_name), .mode = _mode, \
- .owner = THIS_MODULE }, \
+ .attr = { .name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index 7d5d1ec95c2e..be8228e50a27 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -19,10 +19,15 @@ struct kobject;
struct module;
struct nameidata;
struct dentry;
+struct sysfs_dirent;
+/* FIXME
+ * The *owner field is no longer used, but leave around
+ * until the tree gets cleaned up fully.
+ */
struct attribute {
const char * name;
- struct module * owner;
+ struct module * owner;
mode_t mode;
};
@@ -39,14 +44,14 @@ struct attribute_group {
*/
#define __ATTR(_name,_mode,_show,_store) { \
- .attr = {.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE }, \
+ .attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
#define __ATTR_RO(_name) { \
- .attr = { .name = __stringify(_name), .mode = 0444, .owner = THIS_MODULE }, \
- .show = _name##_show, \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = _name##_show, \
}
#define __ATTR_NULL { .attr = { .name = NULL } }
@@ -59,8 +64,10 @@ struct bin_attribute {
struct attribute attr;
size_t size;
void *private;
- ssize_t (*read)(struct kobject *, char *, loff_t, size_t);
- ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
+ ssize_t (*read)(struct kobject *, struct bin_attribute *,
+ char *, loff_t, size_t);
+ ssize_t (*write)(struct kobject *, struct bin_attribute *,
+ char *, loff_t, size_t);
int (*mmap)(struct kobject *, struct bin_attribute *attr,
struct vm_area_struct *vma);
};
@@ -70,12 +77,16 @@ struct sysfs_ops {
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
+#define SYSFS_TYPE_MASK 0x00ff
#define SYSFS_ROOT 0x0001
#define SYSFS_DIR 0x0002
#define SYSFS_KOBJ_ATTR 0x0004
#define SYSFS_KOBJ_BIN_ATTR 0x0008
#define SYSFS_KOBJ_LINK 0x0020
-#define SYSFS_NOT_PINNED (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR | SYSFS_KOBJ_LINK)
+#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
+
+#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
+#define SYSFS_FLAG_REMOVED 0x0100
#ifdef CONFIG_SYSFS
@@ -83,13 +94,14 @@ extern int sysfs_schedule_callback(struct kobject *kobj,
void (*func)(void *), void *data, struct module *owner);
extern int __must_check
-sysfs_create_dir(struct kobject *, struct dentry *);
+sysfs_create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent_sd);
extern void
sysfs_remove_dir(struct kobject *);
extern int __must_check
-sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name);
+sysfs_rename_dir(struct kobject *kobj, struct sysfs_dirent *new_parent_sd,
+ const char *new_name);
extern int __must_check
sysfs_move_dir(struct kobject *, struct kobject *);
@@ -129,8 +141,8 @@ void sysfs_notify(struct kobject * k, char *dir, char *attr);
extern int sysfs_make_shadowed_dir(struct kobject *kobj,
void * (*follow_link)(struct dentry *, struct nameidata *));
-extern struct dentry *sysfs_create_shadow_dir(struct kobject *kobj);
-extern void sysfs_remove_shadow_dir(struct dentry *dir);
+extern struct sysfs_dirent *sysfs_create_shadow_dir(struct kobject *kobj);
+extern void sysfs_remove_shadow_dir(struct sysfs_dirent *shadow_sd);
extern int __must_check sysfs_init(void);
@@ -142,7 +154,8 @@ static inline int sysfs_schedule_callback(struct kobject *kobj,
return -ENOSYS;
}
-static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow)
+static inline int sysfs_create_dir(struct kobject *kobj,
+ struct sysfs_dirent *shadow_parent_sd)
{
return 0;
}
@@ -152,9 +165,9 @@ static inline void sysfs_remove_dir(struct kobject * k)
;
}
-static inline int sysfs_rename_dir(struct kobject * k,
- struct dentry *new_parent,
- const char *new_name)
+static inline int sysfs_rename_dir(struct kobject *kobj,
+ struct sysfs_dirent *new_parent_sd,
+ const char *new_name)
{
return 0;
}
diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h
index a46104a28f66..dce1ed204972 100644
--- a/include/linux/taskstats.h
+++ b/include/linux/taskstats.h
@@ -31,7 +31,7 @@
*/
-#define TASKSTATS_VERSION 4
+#define TASKSTATS_VERSION 5
#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
* in linux/sched.h */
@@ -149,6 +149,9 @@ struct taskstats {
__u64 read_bytes; /* bytes of read I/O */
__u64 write_bytes; /* bytes of write I/O */
__u64 cancelled_write_bytes; /* bytes of cancelled write I/O */
+
+ __u64 nvcsw; /* voluntary_ctxt_switches */
+ __u64 nivcsw; /* nonvoluntary_ctxt_switches */
};
diff --git a/include/linux/time.h b/include/linux/time.h
index dda9be685ab6..e6aea5146e5d 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -4,6 +4,7 @@
#include <linux/types.h>
#ifdef __KERNEL__
+# include <linux/cache.h>
# include <linux/seqlock.h>
#endif
@@ -36,7 +37,8 @@ struct timezone {
#define NSEC_PER_SEC 1000000000L
#define FSEC_PER_SEC 1000000000000000L
-static inline int timespec_equal(struct timespec *a, struct timespec *b)
+static inline int timespec_equal(const struct timespec *a,
+ const struct timespec *b)
{
return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec);
}
@@ -93,6 +95,8 @@ extern struct timespec wall_to_monotonic;
extern seqlock_t xtime_lock __attribute__((weak));
extern unsigned long read_persistent_clock(void);
+extern int update_persistent_clock(struct timespec now);
+extern int no_sync_cmos_clock __read_mostly;
void timekeeping_init(void);
static inline unsigned long get_seconds(void)
@@ -116,6 +120,8 @@ extern int do_setitimer(int which, struct itimerval *value,
extern unsigned int alarm_setitimer(unsigned int seconds);
extern int do_getitimer(int which, struct itimerval *value);
extern void getnstimeofday(struct timespec *tv);
+extern void getboottime(struct timespec *ts);
+extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_is_continuous(void);
diff --git a/include/linux/timer.h b/include/linux/timer.h
index c661710d3627..78cf899b4409 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -3,7 +3,6 @@
#include <linux/list.h>
#include <linux/ktime.h>
-#include <linux/spinlock.h>
#include <linux/stddef.h>
struct tvec_t_base_s;
@@ -91,16 +90,13 @@ extern unsigned long get_next_timer_interrupt(unsigned long now);
*/
#ifdef CONFIG_TIMER_STATS
+#define TIMER_STATS_FLAG_DEFERRABLE 0x1
+
extern void init_timer_stats(void);
extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
- void *timerf, char * comm);
-
-static inline void timer_stats_account_timer(struct timer_list *timer)
-{
- timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
- timer->function, timer->start_comm);
-}
+ void *timerf, char *comm,
+ unsigned int timer_flag);
extern void __timer_stats_timer_set_start_info(struct timer_list *timer,
void *addr);
@@ -119,10 +115,6 @@ static inline void init_timer_stats(void)
{
}
-static inline void timer_stats_account_timer(struct timer_list *timer)
-{
-}
-
static inline void timer_stats_timer_set_start_info(struct timer_list *timer)
{
}
diff --git a/include/linux/timex.h b/include/linux/timex.h
index da929dbbea2a..37ac3ff90faf 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -224,66 +224,6 @@ static inline int ntp_synced(void)
__x < 0 ? -(-__x >> __s) : __x >> __s; \
})
-
-#ifdef CONFIG_TIME_INTERPOLATION
-
-#define TIME_SOURCE_CPU 0
-#define TIME_SOURCE_MMIO64 1
-#define TIME_SOURCE_MMIO32 2
-#define TIME_SOURCE_FUNCTION 3
-
-/* For proper operations time_interpolator clocks must run slightly slower
- * than the standard clock since the interpolator may only correct by having
- * time jump forward during a tick. A slower clock is usually a side effect
- * of the integer divide of the nanoseconds in a second by the frequency.
- * The accuracy of the division can be increased by specifying a shift.
- * However, this may cause the clock not to be slow enough.
- * The interpolator will self-tune the clock by slowing down if no
- * resets occur or speeding up if the time jumps per analysis cycle
- * become too high.
- *
- * Setting jitter compensates for a fluctuating timesource by comparing
- * to the last value read from the timesource to insure that an earlier value
- * is not returned by a later call. The price to pay
- * for the compensation is that the timer routines are not as scalable anymore.
- */
-
-struct time_interpolator {
- u16 source; /* time source flags */
- u8 shift; /* increases accuracy of multiply by shifting. */
- /* Note that bits may be lost if shift is set too high */
- u8 jitter; /* if set compensate for fluctuations */
- u32 nsec_per_cyc; /* set by register_time_interpolator() */
- void *addr; /* address of counter or function */
- cycles_t mask; /* mask the valid bits of the counter */
- unsigned long offset; /* nsec offset at last update of interpolator */
- u64 last_counter; /* counter value in units of the counter at last update */
- cycles_t last_cycle; /* Last timer value if TIME_SOURCE_JITTER is set */
- u64 frequency; /* frequency in counts/second */
- long drift; /* drift in parts-per-million (or -1) */
- unsigned long skips; /* skips forward */
- unsigned long ns_skipped; /* nanoseconds skipped */
- struct time_interpolator *next;
-};
-
-extern void register_time_interpolator(struct time_interpolator *);
-extern void unregister_time_interpolator(struct time_interpolator *);
-extern void time_interpolator_reset(void);
-extern unsigned long time_interpolator_get_offset(void);
-extern void time_interpolator_update(long delta_nsec);
-
-#else /* !CONFIG_TIME_INTERPOLATION */
-
-static inline void time_interpolator_reset(void)
-{
-}
-
-static inline void time_interpolator_update(long delta_nsec)
-{
-}
-
-#endif /* !CONFIG_TIME_INTERPOLATION */
-
#define TICK_LENGTH_SHIFT 32
#ifdef CONFIG_NO_HZ
diff --git a/include/linux/topology.h b/include/linux/topology.h
index da6c39b2d051..d0890a7e5bab 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -50,10 +50,10 @@
for_each_online_node(node) \
if (nr_cpus_node(node))
-#ifndef node_distance
/* Conform to ACPI 2.0 SLIT distance definitions */
#define LOCAL_DISTANCE 10
#define REMOTE_DISTANCE 20
+#ifndef node_distance
#define node_distance(from,to) ((from) == (to) ? LOCAL_DISTANCE : REMOTE_DISTANCE)
#endif
#ifndef RECLAIM_DISTANCE
diff --git a/include/linux/tty.h b/include/linux/tty.h
index bb4576085203..691a1748d9d2 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -178,6 +178,7 @@ struct tty_bufhead {
#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN)
struct device;
+struct signal_struct;
/*
* Where all of the state associated with a tty is kept while the tty
* is open. Since the termios state should be kept even if the tty
@@ -310,6 +311,7 @@ extern void tty_hangup(struct tty_struct * tty);
extern void tty_vhangup(struct tty_struct * tty);
extern void tty_unhangup(struct file *filp);
extern int tty_hung_up_p(struct file * filp);
+extern int is_tty(struct file *filp);
extern void do_SAK(struct tty_struct *tty);
extern void __do_SAK(struct tty_struct *tty);
extern void disassociate_ctty(int priv);
@@ -338,9 +340,46 @@ extern struct tty_struct *get_current_tty(void);
extern struct mutex tty_mutex;
+extern void tty_write_unlock(struct tty_struct *tty);
+extern int tty_write_lock(struct tty_struct *tty, int ndelay);
+#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock))
+
+
+
/* n_tty.c */
extern struct tty_ldisc tty_ldisc_N_TTY;
+/* tty_audit.c */
+#ifdef CONFIG_AUDIT
+extern void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+ size_t size);
+extern void tty_audit_exit(void);
+extern void tty_audit_fork(struct signal_struct *sig);
+extern void tty_audit_push(struct tty_struct *tty);
+extern void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid);
+extern void tty_audit_opening(void);
+#else
+static inline void tty_audit_add_data(struct tty_struct *tty,
+ unsigned char *data, size_t size)
+{
+}
+static inline void tty_audit_exit(void)
+{
+}
+static inline void tty_audit_fork(struct signal_struct *sig)
+{
+}
+static inline void tty_audit_push(struct tty_struct *tty)
+{
+}
+static inline void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
+{
+}
+static inline void tty_audit_opening(void)
+{
+}
+#endif
+
/* tty_ioctl.c */
extern int n_tty_ioctl(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 6de445c31a64..8ec703f462da 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -42,6 +42,7 @@ static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
/* UDP encapsulation types */
#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */
#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */
+#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */
#ifdef __KERNEL__
#include <linux/types.h>
@@ -70,6 +71,11 @@ struct udp_sock {
#define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */
#define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */
__u8 pcflag; /* marks socket as UDP-Lite if > 0 */
+ __u8 unused[3];
+ /*
+ * For encapsulation sockets.
+ */
+ int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
};
static inline struct udp_sock *udp_sk(const struct sock *sk)
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 9af8bbcd8963..b7fe13883bdb 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -13,10 +13,6 @@
* 2 of the License, or (at your option) any later version.
*/
-
-/* A word of warning: Our uio structure will clash with the C library one (which is now obsolete). Remove the C
- library one from sys/uio.h if you have a very old library set */
-
struct iovec
{
void __user *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
@@ -38,11 +34,6 @@ struct kvec {
#define UIO_FASTIOV 8
#define UIO_MAXIOV 1024
-#if 0
-#define UIO_MAXIOV 16 /* Maximum iovec's in one operation
- 16 matches BSD */
- /* Beg pardon: BSD has 1024 --ANK */
-#endif
/*
* Total number of bytes covered by an iovec.
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
new file mode 100644
index 000000000000..44c28e94df50
--- /dev/null
+++ b/include/linux/uio_driver.h
@@ -0,0 +1,91 @@
+/*
+ * include/linux/uio_driver.h
+ *
+ * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * Userspace IO driver.
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#ifndef _UIO_DRIVER_H_
+#define _UIO_DRIVER_H_
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+
+/**
+ * struct uio_mem - description of a UIO memory region
+ * @kobj: kobject for this mapping
+ * @addr: address of the device's memory
+ * @size: size of IO
+ * @memtype: type of memory addr points to
+ * @internal_addr: ioremap-ped version of addr, for driver internal use
+ */
+struct uio_mem {
+ struct kobject kobj;
+ unsigned long addr;
+ unsigned long size;
+ int memtype;
+ void __iomem *internal_addr;
+};
+
+#define MAX_UIO_MAPS 5
+
+struct uio_device;
+
+/**
+ * struct uio_info - UIO device capabilities
+ * @uio_dev: the UIO device this info belongs to
+ * @name: device name
+ * @version: device driver version
+ * @mem: list of mappable memory regions, size==0 for end of list
+ * @irq: interrupt number or UIO_IRQ_CUSTOM
+ * @irq_flags: flags for request_irq()
+ * @priv: optional private data
+ * @handler: the device's irq handler
+ * @mmap: mmap operation for this uio device
+ * @open: open operation for this uio device
+ * @release: release operation for this uio device
+ */
+struct uio_info {
+ struct uio_device *uio_dev;
+ char *name;
+ char *version;
+ struct uio_mem mem[MAX_UIO_MAPS];
+ long irq;
+ unsigned long irq_flags;
+ void *priv;
+ irqreturn_t (*handler)(int irq, struct uio_info *dev_info);
+ int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
+ int (*open)(struct uio_info *info, struct inode *inode);
+ int (*release)(struct uio_info *info, struct inode *inode);
+};
+
+extern int __must_check
+ __uio_register_device(struct module *owner,
+ struct device *parent,
+ struct uio_info *info);
+static inline int __must_check
+ uio_register_device(struct device *parent, struct uio_info *info)
+{
+ return __uio_register_device(THIS_MODULE, parent, info);
+}
+extern void uio_unregister_device(struct uio_info *info);
+extern void uio_event_notify(struct uio_info *info);
+
+/* defines for uio_device->irq */
+#define UIO_IRQ_CUSTOM -1
+#define UIO_IRQ_NONE -2
+
+/* defines for uio_device->memtype */
+#define UIO_MEM_NONE 0
+#define UIO_MEM_PHYS 1
+#define UIO_MEM_LOGICAL 2
+#define UIO_MEM_VIRTUAL 3
+
+#endif /* _LINUX_UIO_DRIVER_H_ */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 56aa2ee21f1b..7a60946df3b6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -146,6 +146,10 @@ struct usb_interface {
* active alternate setting */
unsigned num_altsetting; /* number of alternate settings */
+ /* If there is an interface association descriptor then it will list
+ * the associated interfaces */
+ struct usb_interface_assoc_descriptor *intf_assoc;
+
int minor; /* minor number this interface is
* bound to */
enum usb_interface_condition condition; /* state of binding */
@@ -175,6 +179,7 @@ void usb_put_intf(struct usb_interface *intf);
/* this maximum is arbitrary */
#define USB_MAXINTERFACES 32
+#define USB_MAXIADS USB_MAXINTERFACES/2
/**
* struct usb_interface_cache - long-term representation of a device interface
@@ -245,6 +250,11 @@ struct usb_host_config {
struct usb_config_descriptor desc;
char *string; /* iConfiguration string, if present */
+
+ /* List of any Interface Association Descriptors in this
+ * configuration. */
+ struct usb_interface_assoc_descriptor *intf_assoc[USB_MAXIADS];
+
/* the interfaces associated with this configuration,
* stored in no particular order */
struct usb_interface *interface[USB_MAXINTERFACES];
@@ -403,6 +413,8 @@ struct usb_device {
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 */
#endif
@@ -770,6 +782,28 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
.bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+/**
+ * USB_DEVICE_AND_INTERFACE_INFO - macro used to describe a specific usb device
+ * with a class of usb interfaces
+ * @vend: the 16 bit USB Vendor ID
+ * @prod: the 16 bit USB Product ID
+ * @cl: bInterfaceClass value
+ * @sc: bInterfaceSubClass value
+ * @pr: bInterfaceProtocol value
+ *
+ * This macro is used to create a struct usb_device_id that matches a
+ * specific device with a specific class of interfaces.
+ *
+ * This is especially useful when explicitly matching devices that have
+ * vendor specific bDeviceClass values, but standards-compliant interfaces.
+ */
+#define USB_DEVICE_AND_INTERFACE_INFO(vend,prod,cl,sc,pr) \
+ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO \
+ | USB_DEVICE_ID_MATCH_DEVICE, \
+ .idVendor = (vend), .idProduct = (prod), \
+ .bInterfaceClass = (cl), \
+ .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+
/* ----------------------------------------------------------------------- */
/* Stuff for dynamic usb ids */
@@ -816,10 +850,15 @@ struct usbdrv_wrap {
* do (or don't) show up otherwise in the filesystem.
* @suspend: Called when the device is going to be suspended by the system.
* @resume: Called when the device is being resumed by the system.
+ * @reset_resume: Called when the suspended device has been reset instead
+ * of being resumed.
* @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.
+ * 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.
* @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.
@@ -859,9 +898,10 @@ struct usb_driver {
int (*suspend) (struct usb_interface *intf, pm_message_t message);
int (*resume) (struct usb_interface *intf);
+ int (*reset_resume)(struct usb_interface *intf);
- void (*pre_reset) (struct usb_interface *intf);
- void (*post_reset) (struct usb_interface *intf);
+ int (*pre_reset)(struct usb_interface *intf);
+ int (*post_reset)(struct usb_interface *intf);
const struct usb_device_id *id_table;
@@ -964,6 +1004,7 @@ extern int usb_disabled(void);
#define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */
#define URB_NO_INTERRUPT 0x0080 /* HINT: no non-error interrupt
* needed */
+#define URB_FREE_BUFFER 0x0100 /* Free transfer buffer with the URB */
struct usb_iso_packet_descriptor {
unsigned int offset;
@@ -974,11 +1015,26 @@ struct usb_iso_packet_descriptor {
struct urb;
+struct usb_anchor {
+ struct list_head urb_list;
+ wait_queue_head_t wait;
+ spinlock_t lock;
+};
+
+static inline void init_usb_anchor(struct usb_anchor *anchor)
+{
+ INIT_LIST_HEAD(&anchor->urb_list);
+ init_waitqueue_head(&anchor->wait);
+ spin_lock_init(&anchor->lock);
+}
+
typedef void (*usb_complete_t)(struct urb *);
/**
* struct urb - USB Request Block
* @urb_list: For use by current owner of the URB.
+ * @anchor_list: membership in the list of an anchor
+ * @anchor: to anchor URBs to a common mooring
* @pipe: Holds endpoint number, direction, type, and more.
* Create these values with the eight macros available;
* usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is "ctrl"
@@ -1151,6 +1207,8 @@ struct urb
/* public: documented fields in the urb that can be used by drivers */
struct list_head urb_list; /* list head for use by the urb's
* current owner */
+ struct list_head anchor_list; /* the URB may be anchored by the driver */
+ struct usb_anchor *anchor;
struct usb_device *dev; /* (in) pointer to associated device */
unsigned int pipe; /* (in) pipe information */
int status; /* (return) non-ISO status */
@@ -1286,6 +1344,11 @@ extern struct urb *usb_get_urb(struct urb *urb);
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_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,
+ unsigned int timeout);
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
gfp_t mem_flags, dma_addr_t *dma);
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
index 43f160cfe003..6ce42bf9f743 100644
--- a/include/linux/usb/Kbuild
+++ b/include/linux/usb/Kbuild
@@ -1,5 +1,6 @@
unifdef-y += audio.h
unifdef-y += cdc.h
unifdef-y += ch9.h
+unifdef-y += gadgetfs.h
unifdef-y += midi.h
diff --git a/include/linux/usb_gadgetfs.h b/include/linux/usb/gadgetfs.h
index 8086d5a9b94e..e8654c338729 100644
--- a/include/linux/usb_gadgetfs.h
+++ b/include/linux/usb/gadgetfs.h
@@ -1,3 +1,5 @@
+#ifndef __LINUX_USB_GADGETFS_H
+#define __LINUX_USB_GADGETFS_H
#include <asm/types.h>
#include <asm/ioctl.h>
@@ -7,11 +9,12 @@
/*
* Filesystem based user-mode API to USB Gadget controller hardware
*
- * Almost everything can be done with only read and write operations,
+ * Other than ep0 operations, most things are done by read() and write()
* on endpoint files found in one directory. They are configured by
* writing descriptors, and then may be used for normal stream style
* i/o requests. When ep0 is configured, the device can enumerate;
- * when it's closed, the device disconnects from usb.
+ * when it's closed, the device disconnects from usb. Operations on
+ * ep0 require ioctl() operations.
*
* Configuration and device descriptors get written to /dev/gadget/$CHIP,
* which may then be used to read usb_gadgetfs_event structs. The driver
@@ -21,9 +24,9 @@
*/
/*
- * Events are delivered on the ep0 file descriptor, if the user mode driver
+ * Events are delivered on the ep0 file descriptor, when the user mode driver
* reads from this file descriptor after writing the descriptors. Don't
- * stop polling this descriptor, if you write that kind of driver.
+ * stop polling this descriptor.
*/
enum usb_gadgetfs_event_type {
@@ -36,8 +39,10 @@ enum usb_gadgetfs_event_type {
// and likely more !
};
+/* NOTE: this structure must stay the same size and layout on
+ * both 32-bit and 64-bit kernels.
+ */
struct usb_gadgetfs_event {
- enum usb_gadgetfs_event_type type;
union {
// NOP, DISCONNECT, SUSPEND: nothing
// ... some hardware can't report disconnection
@@ -46,19 +51,20 @@ struct usb_gadgetfs_event {
enum usb_device_speed speed;
// SETUP: packet; DATA phase i/o precedes next event
- // (setup.bmRequestType & USB_DIR_IN) flags direction
+ // (setup.bmRequestType & USB_DIR_IN) flags direction
// ... includes SET_CONFIGURATION, SET_INTERFACE
struct usb_ctrlrequest setup;
} u;
+ enum usb_gadgetfs_event_type type;
};
/* endpoint ioctls */
/* IN transfers may be reported to the gadget driver as complete
- * when the fifo is loaded, before the host reads the data;
+ * when the fifo is loaded, before the host reads the data;
* OUT transfers may be reported to the host's "client" driver as
- * complete when they're sitting in the FIFO unread.
+ * complete when they're sitting in the FIFO unread.
* THIS returns how many bytes are "unclaimed" in the endpoint fifo
* (needed for precise fault handling, when the hardware allows it)
*/
@@ -72,4 +78,4 @@ struct usb_gadgetfs_event {
*/
#define GADGETFS_CLEAR_HALT _IO('g',3)
-
+#endif /* __LINUX_USB_GADGETFS_H */
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 6bac8faacbc6..8da374caf582 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -9,3 +9,6 @@
/* string descriptors must not be fetched using a 255-byte read */
#define USB_QUIRK_STRING_FETCH_255 0x00000002
+
+/* device can't resume correctly so reset it instead */
+#define USB_QUIRK_RESET_RESUME 0x00000004
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 32acbae28d24..e8b8928232c8 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -221,6 +221,9 @@ struct usb_serial_driver {
int (*port_probe) (struct usb_serial_port *port);
int (*port_remove) (struct usb_serial_port *port);
+ int (*suspend) (struct usb_serial *serial, pm_message_t message);
+ int (*resume) (struct usb_serial *serial);
+
/* serial function calls */
int (*open) (struct usb_serial_port *port, struct file * filp);
void (*close) (struct usb_serial_port *port, struct file * filp);
@@ -249,6 +252,9 @@ extern void usb_serial_port_softint(struct usb_serial_port *port);
extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
extern void usb_serial_disconnect(struct usb_interface *iface);
+extern int usb_serial_suspend(struct usb_interface *intf, pm_message_t message);
+extern int usb_serial_resume(struct usb_interface *intf);
+
extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
@@ -269,6 +275,7 @@ extern void usb_serial_put(struct usb_serial *serial);
extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
+extern int usb_serial_generic_resume (struct usb_serial *serial);
extern int usb_serial_generic_write_room (struct usb_serial_port *port);
extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
extern void usb_serial_generic_read_bulk_callback (struct urb *urb);
diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
index e17186dbcdca..4f59b2aa8a9e 100644
--- a/include/linux/usb_gadget.h
+++ b/include/linux/usb_gadget.h
@@ -110,13 +110,6 @@ struct usb_ep_ops {
gfp_t gfp_flags);
void (*free_request) (struct usb_ep *ep, struct usb_request *req);
- void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes,
- dma_addr_t *dma, gfp_t gfp_flags);
- void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
- unsigned bytes);
- // NOTE: on 2.6, drivers may also use dma_map() and
- // dma_sync_single_*() to directly manage dma overhead.
-
int (*queue) (struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags);
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
@@ -235,47 +228,6 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
}
/**
- * usb_ep_alloc_buffer - allocate an I/O buffer
- * @ep:the endpoint associated with the buffer
- * @len:length of the desired buffer
- * @dma:pointer to the buffer's DMA address; must be valid
- * @gfp_flags:GFP_* flags to use
- *
- * Returns a new buffer, or null if one could not be allocated.
- * The buffer is suitably aligned for dma, if that endpoint uses DMA,
- * and the caller won't have to care about dma-inconsistency
- * or any hidden "bounce buffer" mechanism. No additional per-request
- * DMA mapping will be required for such buffers.
- * Free it later with usb_ep_free_buffer().
- *
- * You don't need to use this call to allocate I/O buffers unless you
- * want to make sure drivers don't incur costs for such "bounce buffer"
- * copies or per-request DMA mappings.
- */
-static inline void *
-usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma,
- gfp_t gfp_flags)
-{
- return ep->ops->alloc_buffer (ep, len, dma, gfp_flags);
-}
-
-/**
- * usb_ep_free_buffer - frees an i/o buffer
- * @ep:the endpoint associated with the buffer
- * @buf:CPU view address of the buffer
- * @dma:the buffer's DMA address
- * @len:length of the buffer
- *
- * reverses the effect of usb_ep_alloc_buffer().
- * caller guarantees the buffer will no longer be accessed
- */
-static inline void
-usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len)
-{
- ep->ops->free_buffer (ep, buf, dma, len);
-}
-
-/**
* usb_ep_queue - queues (submits) an I/O request to an endpoint.
* @ep:the endpoint associated with the request
* @req:the request being submitted
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
new file mode 100644
index 000000000000..1101b0ce878f
--- /dev/null
+++ b/include/linux/user_namespace.h
@@ -0,0 +1,61 @@
+#ifndef _LINUX_USER_NAMESPACE_H
+#define _LINUX_USER_NAMESPACE_H
+
+#include <linux/kref.h>
+#include <linux/nsproxy.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+
+#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 8)
+#define UIDHASH_SZ (1 << UIDHASH_BITS)
+
+struct user_namespace {
+ struct kref kref;
+ struct list_head uidhash_table[UIDHASH_SZ];
+ struct user_struct *root_user;
+};
+
+extern struct user_namespace init_user_ns;
+
+#ifdef CONFIG_USER_NS
+
+static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
+{
+ if (ns)
+ kref_get(&ns->kref);
+ return ns;
+}
+
+extern struct user_namespace *copy_user_ns(int flags,
+ struct user_namespace *old_ns);
+extern void free_user_ns(struct kref *kref);
+
+static inline void put_user_ns(struct user_namespace *ns)
+{
+ if (ns)
+ kref_put(&ns->kref, free_user_ns);
+}
+
+#else
+
+static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
+{
+ return &init_user_ns;
+}
+
+static inline struct user_namespace *copy_user_ns(int flags,
+ struct user_namespace *old_ns)
+{
+ if (flags & CLONE_NEWUSER)
+ return ERR_PTR(-EINVAL);
+
+ return old_ns;
+}
+
+static inline void put_user_ns(struct user_namespace *ns)
+{
+}
+
+#endif
+
+#endif /* _LINUX_USER_H */
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index f8d3b326e93a..923db99175f2 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -48,26 +48,14 @@ static inline void get_uts_ns(struct uts_namespace *ns)
kref_get(&ns->kref);
}
-#ifdef CONFIG_UTS_NS
-extern struct uts_namespace *copy_utsname(int flags, struct uts_namespace *ns);
+extern struct uts_namespace *copy_utsname(unsigned long flags,
+ struct uts_namespace *ns);
extern void free_uts_ns(struct kref *kref);
static inline void put_uts_ns(struct uts_namespace *ns)
{
kref_put(&ns->kref, free_uts_ns);
}
-#else
-static inline struct uts_namespace *copy_utsname(int flags,
- struct uts_namespace *ns)
-{
- return ns;
-}
-
-static inline void put_uts_ns(struct uts_namespace *ns)
-{
-}
-#endif
-
static inline struct new_utsname *utsname(void)
{
return &current->nsproxy->uts_ns->name;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index d16a2b57dc81..c66c8a3410b9 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -60,6 +60,7 @@
#include <linux/compiler.h> /* need __user */
#else
#define __user
+#include <sys/time.h>
#endif
#include <linux/types.h>
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 4b7ee83787c1..89338b468d0d 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -58,6 +58,13 @@ void vmalloc_sync_all(void);
/*
* Lowlevel-APIs (not for driver use!)
*/
+
+static inline size_t get_vm_area_size(const struct vm_struct *area)
+{
+ /* return actual size without guard page */
+ return area->size - PAGE_SIZE;
+}
+
extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end);
@@ -65,9 +72,14 @@ extern struct vm_struct *get_vm_area_node(unsigned long size,
unsigned long flags, int node,
gfp_t gfp_mask);
extern struct vm_struct *remove_vm_area(void *addr);
+
extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
struct page ***pages);
-extern void unmap_vm_area(struct vm_struct *area);
+extern void unmap_kernel_range(unsigned long addr, unsigned long size);
+
+/* Allocate/destroy a 'vmalloc' VM area. */
+extern struct vm_struct *alloc_vm_area(size_t size);
+extern void free_vm_area(struct vm_struct *area);
/*
* Internals. Dont't use..
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index d9325cf8a134..75370ec0923e 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -25,7 +25,7 @@
#define HIGHMEM_ZONE(xx)
#endif
-#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL HIGHMEM_ZONE(xx)
+#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,
FOR_ALL_ZONES(PGALLOC),
@@ -170,7 +170,8 @@ static inline unsigned long node_page_state(int node,
#ifdef CONFIG_HIGHMEM
zone_page_state(&zones[ZONE_HIGHMEM], item) +
#endif
- zone_page_state(&zones[ZONE_NORMAL], item);
+ zone_page_state(&zones[ZONE_NORMAL], item) +
+ zone_page_state(&zones[ZONE_MOVABLE], item);
}
extern void zone_statistics(struct zonelist *, struct zone *);
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index d961635d0e61..699b7e9864fa 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -75,6 +75,8 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
int vt_waitactive(int vt);
void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc);
+extern int unbind_con_driver(const struct consw *csw, int first, int last,
+ int deflt);
/*
* vc_screen.c shares this temporary buffer with the console write code so that
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index ce0719a2cfeb..ce6badc98f6d 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -148,7 +148,7 @@ extern int keventd_up(void);
extern void init_workqueues(void);
int execute_in_process_context(work_func_t fn, struct execute_work *);
-extern void cancel_work_sync(struct work_struct *work);
+extern int cancel_work_sync(struct work_struct *work);
/*
* Kill off a pending schedule_delayed_work(). Note that the work callback
@@ -166,14 +166,21 @@ static inline int cancel_delayed_work(struct delayed_work *work)
return ret;
}
-extern void cancel_rearming_delayed_work(struct delayed_work *work);
+extern int cancel_delayed_work_sync(struct delayed_work *work);
-/* Obsolete. use cancel_rearming_delayed_work() */
+/* Obsolete. use cancel_delayed_work_sync() */
static inline
void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,
struct delayed_work *work)
{
- cancel_rearming_delayed_work(work);
+ cancel_delayed_work_sync(work);
+}
+
+/* Obsolete. use cancel_delayed_work_sync() */
+static inline
+void cancel_rearming_delayed_work(struct delayed_work *work)
+{
+ cancel_delayed_work_sync(work);
}
#endif
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index d3f4f5a38214..67703249b245 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -114,7 +114,7 @@ struct saa7146_dev
struct mutex lock;
unsigned char __iomem *mem; /* pointer to mapped IO memory */
- int revision; /* chip revision; needed for bug-workarounds*/
+ u32 revision; /* chip revision; needed for bug-workarounds*/
/* pci-device & irq stuff*/
char name[32];
@@ -157,8 +157,8 @@ struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc);
int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt);
void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt);
int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int length );
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt);
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt);
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt);
void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data);
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop);
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 6dcf3c45707d..160381c72e4b 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -23,8 +23,6 @@
#define _TUNER_H
#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <media/tuner-types.h>
extern int tuner_debug;
@@ -124,6 +122,7 @@ extern int tuner_debug;
#define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */
#define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */
#define TUNER_TDA9887 74 /* This tuner should be used only internally */
+#define TUNER_TEA5761 75 /* Only FM Radio Tuner */
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
@@ -182,74 +181,6 @@ struct tuner_setup {
int (*tuner_callback) (void *dev, int command,int arg);
};
-struct tuner {
- /* device */
- struct i2c_client i2c;
-
- unsigned int type; /* chip type */
-
- unsigned int mode;
- unsigned int mode_mask; /* Combination of allowable modes */
-
- unsigned int tv_freq; /* keep track of the current settings */
- unsigned int radio_freq;
- u16 last_div;
- unsigned int audmode;
- v4l2_std_id std;
-
- int using_v4l2;
-
- /* used by tda9887 */
- unsigned int tda9887_config;
- unsigned char tda9887_data[4];
-
- /* used by MT2032 */
- unsigned int xogc;
- unsigned int radio_if2;
-
- /* used by tda8290 */
- unsigned char tda8290_easy_mode;
- unsigned char tda827x_lpsel;
- unsigned char tda827x_addr;
- unsigned char tda827x_ver;
- unsigned int sgIF;
-
- unsigned int config;
- int (*tuner_callback) (void *dev, int command,int arg);
-
- /* function ptrs */
- void (*set_tv_freq)(struct i2c_client *c, unsigned int freq);
- void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
- int (*has_signal)(struct i2c_client *c);
- int (*is_stereo)(struct i2c_client *c);
- int (*get_afc)(struct i2c_client *c);
- void (*tuner_status)(struct i2c_client *c);
- void (*standby)(struct i2c_client *c);
-};
-
-extern unsigned const int tuner_count;
-
-extern int microtune_init(struct i2c_client *c);
-extern int xc3028_init(struct i2c_client *c);
-extern int tda8290_init(struct i2c_client *c);
-extern int tda8290_probe(struct i2c_client *c);
-extern int tea5767_tuner_init(struct i2c_client *c);
-extern int default_tuner_init(struct i2c_client *c);
-extern int tea5767_autodetection(struct i2c_client *c);
-extern int tda9887_tuner_init(struct i2c_client *c);
-
-#define tuner_warn(fmt, arg...) do {\
- printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_info(fmt, arg...) do {\
- printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-#define tuner_dbg(fmt, arg...) do {\
- extern int tuner_debug; \
- if (tuner_debug) \
- printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
- i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-
#endif /* __KERNEL__ */
#endif /* _TUNER_H */
diff --git a/include/mtd/ubi-header.h b/include/mtd/ubi-header.h
index fa479c71aa34..74efa7763479 100644
--- a/include/mtd/ubi-header.h
+++ b/include/mtd/ubi-header.h
@@ -74,42 +74,13 @@ enum {
UBI_COMPAT_REJECT = 5
};
-/*
- * ubi16_t/ubi32_t/ubi64_t - 16, 32, and 64-bit integers used in UBI on-flash
- * data structures.
- */
-typedef struct {
- uint16_t int16;
-} __attribute__ ((packed)) ubi16_t;
-
-typedef struct {
- uint32_t int32;
-} __attribute__ ((packed)) ubi32_t;
-
-typedef struct {
- uint64_t int64;
-} __attribute__ ((packed)) ubi64_t;
-
-/*
- * In this implementation of UBI uses the big-endian format for on-flash
- * integers. The below are the corresponding conversion macros.
- */
-#define cpu_to_ubi16(x) ((ubi16_t){__cpu_to_be16(x)})
-#define ubi16_to_cpu(x) ((uint16_t)__be16_to_cpu((x).int16))
-
-#define cpu_to_ubi32(x) ((ubi32_t){__cpu_to_be32(x)})
-#define ubi32_to_cpu(x) ((uint32_t)__be32_to_cpu((x).int32))
-
-#define cpu_to_ubi64(x) ((ubi64_t){__cpu_to_be64(x)})
-#define ubi64_to_cpu(x) ((uint64_t)__be64_to_cpu((x).int64))
-
/* Sizes of UBI headers */
#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
/* Sizes of UBI headers without the ending CRC */
-#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(ubi32_t))
-#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(ubi32_t))
+#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32))
+#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
/**
* struct ubi_ec_hdr - UBI erase counter header.
@@ -137,14 +108,14 @@ typedef struct {
* eraseblocks.
*/
struct ubi_ec_hdr {
- ubi32_t magic;
- uint8_t version;
- uint8_t padding1[3];
- ubi64_t ec; /* Warning: the current limit is 31-bit anyway! */
- ubi32_t vid_hdr_offset;
- ubi32_t data_offset;
- uint8_t padding2[36];
- ubi32_t hdr_crc;
+ __be32 magic;
+ __u8 version;
+ __u8 padding1[3];
+ __be64 ec; /* Warning: the current limit is 31-bit anyway! */
+ __be32 vid_hdr_offset;
+ __be32 data_offset;
+ __u8 padding2[36];
+ __be32 hdr_crc;
} __attribute__ ((packed));
/**
@@ -262,22 +233,22 @@ struct ubi_ec_hdr {
* software (say, cramfs) on top of the UBI volume.
*/
struct ubi_vid_hdr {
- ubi32_t magic;
- uint8_t version;
- uint8_t vol_type;
- uint8_t copy_flag;
- uint8_t compat;
- ubi32_t vol_id;
- ubi32_t lnum;
- ubi32_t leb_ver; /* obsolete, to be removed, don't use */
- ubi32_t data_size;
- ubi32_t used_ebs;
- ubi32_t data_pad;
- ubi32_t data_crc;
- uint8_t padding1[4];
- ubi64_t sqnum;
- uint8_t padding2[12];
- ubi32_t hdr_crc;
+ __be32 magic;
+ __u8 version;
+ __u8 vol_type;
+ __u8 copy_flag;
+ __u8 compat;
+ __be32 vol_id;
+ __be32 lnum;
+ __be32 leb_ver; /* obsolete, to be removed, don't use */
+ __be32 data_size;
+ __be32 used_ebs;
+ __be32 data_pad;
+ __be32 data_crc;
+ __u8 padding1[4];
+ __be64 sqnum;
+ __u8 padding2[12];
+ __be32 hdr_crc;
} __attribute__ ((packed));
/* Internal UBI volumes count */
@@ -306,7 +277,7 @@ struct ubi_vid_hdr {
#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
/* Size of the volume table record without the ending CRC */
-#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(ubi32_t))
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
/**
* struct ubi_vtbl_record - a record in the volume table.
@@ -346,15 +317,15 @@ struct ubi_vid_hdr {
* Empty records contain all zeroes and the CRC checksum of those zeroes.
*/
struct ubi_vtbl_record {
- ubi32_t reserved_pebs;
- ubi32_t alignment;
- ubi32_t data_pad;
- uint8_t vol_type;
- uint8_t upd_marker;
- ubi16_t name_len;
- uint8_t name[UBI_VOL_NAME_MAX+1];
- uint8_t padding2[24];
- ubi32_t crc;
+ __be32 reserved_pebs;
+ __be32 alignment;
+ __be32 data_pad;
+ __u8 vol_type;
+ __u8 upd_marker;
+ __be16 name_len;
+ __u8 name[UBI_VOL_NAME_MAX+1];
+ __u8 padding2[24];
+ __be32 crc;
} __attribute__ ((packed));
#endif /* !__UBI_HEADER_H__ */
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
new file mode 100644
index 000000000000..88884d39f28f
--- /dev/null
+++ b/include/net/9p/9p.h
@@ -0,0 +1,417 @@
+/*
+ * include/net/9p/9p.h
+ *
+ * 9P protocol definitions.
+ *
+ * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ * 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:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#ifndef NET_9P_H
+#define NET_9P_H
+
+#ifdef CONFIG_NET_9P_DEBUG
+
+#define P9_DEBUG_ERROR (1<<0)
+#define P9_DEBUG_9P (1<<2)
+#define P9_DEBUG_VFS (1<<3)
+#define P9_DEBUG_CONV (1<<4)
+#define P9_DEBUG_MUX (1<<5)
+#define P9_DEBUG_TRANS (1<<6)
+#define P9_DEBUG_SLABS (1<<7)
+#define P9_DEBUG_FCALL (1<<8)
+
+extern unsigned int p9_debug_level;
+
+#define P9_DPRINTK(level, format, arg...) \
+do { \
+ if ((p9_debug_level & level) == level) \
+ printk(KERN_NOTICE "-- %s (%d): " \
+ format , __FUNCTION__, current->pid , ## arg); \
+} while (0)
+
+#define PRINT_FCALL_ERROR(s, fcall) P9_DPRINTK(P9_DEBUG_ERROR, \
+ "%s: %.*s\n", s, fcall?fcall->params.rerror.error.len:0, \
+ fcall?fcall->params.rerror.error.str:"");
+
+#else
+#define P9_DPRINTK(level, format, arg...) do { } while (0)
+#define PRINT_FCALL_ERROR(s, fcall) do { } while (0)
+#endif
+
+#define P9_EPRINTK(level, format, arg...) \
+do { \
+ printk(level "9p: %s (%d): " \
+ format , __FUNCTION__, current->pid , ## arg); \
+} while (0)
+
+
+/* Message Types */
+enum {
+ P9_TVERSION = 100,
+ P9_RVERSION,
+ P9_TAUTH = 102,
+ P9_RAUTH,
+ P9_TATTACH = 104,
+ P9_RATTACH,
+ P9_TERROR = 106,
+ P9_RERROR,
+ P9_TFLUSH = 108,
+ P9_RFLUSH,
+ P9_TWALK = 110,
+ P9_RWALK,
+ P9_TOPEN = 112,
+ P9_ROPEN,
+ P9_TCREATE = 114,
+ P9_RCREATE,
+ P9_TREAD = 116,
+ P9_RREAD,
+ P9_TWRITE = 118,
+ P9_RWRITE,
+ P9_TCLUNK = 120,
+ P9_RCLUNK,
+ P9_TREMOVE = 122,
+ P9_RREMOVE,
+ P9_TSTAT = 124,
+ P9_RSTAT,
+ P9_TWSTAT = 126,
+ P9_RWSTAT,
+};
+
+/* open modes */
+enum {
+ P9_OREAD = 0x00,
+ P9_OWRITE = 0x01,
+ P9_ORDWR = 0x02,
+ P9_OEXEC = 0x03,
+ P9_OEXCL = 0x04,
+ P9_OTRUNC = 0x10,
+ P9_OREXEC = 0x20,
+ P9_ORCLOSE = 0x40,
+ P9_OAPPEND = 0x80,
+};
+
+/* permissions */
+enum {
+ P9_DMDIR = 0x80000000,
+ P9_DMAPPEND = 0x40000000,
+ P9_DMEXCL = 0x20000000,
+ P9_DMMOUNT = 0x10000000,
+ P9_DMAUTH = 0x08000000,
+ P9_DMTMP = 0x04000000,
+ P9_DMSYMLINK = 0x02000000,
+ P9_DMLINK = 0x01000000,
+ /* 9P2000.u extensions */
+ P9_DMDEVICE = 0x00800000,
+ P9_DMNAMEDPIPE = 0x00200000,
+ P9_DMSOCKET = 0x00100000,
+ P9_DMSETUID = 0x00080000,
+ P9_DMSETGID = 0x00040000,
+};
+
+/* qid.types */
+enum {
+ P9_QTDIR = 0x80,
+ P9_QTAPPEND = 0x40,
+ P9_QTEXCL = 0x20,
+ P9_QTMOUNT = 0x10,
+ P9_QTAUTH = 0x08,
+ P9_QTTMP = 0x04,
+ P9_QTSYMLINK = 0x02,
+ P9_QTLINK = 0x01,
+ P9_QTFILE = 0x00,
+};
+
+#define P9_NOTAG (u16)(~0)
+#define P9_NOFID (u32)(~0)
+#define P9_MAXWELEM 16
+
+/* ample room for Twrite/Rread header */
+#define P9_IOHDRSZ 24
+
+struct p9_str {
+ u16 len;
+ char *str;
+};
+
+/* qids are the unique ID for a file (like an inode */
+struct p9_qid {
+ u8 type;
+ u32 version;
+ u64 path;
+};
+
+/* Plan 9 file metadata (stat) structure */
+struct p9_stat {
+ u16 size;
+ u16 type;
+ u32 dev;
+ struct p9_qid qid;
+ u32 mode;
+ u32 atime;
+ u32 mtime;
+ u64 length;
+ struct p9_str name;
+ struct p9_str uid;
+ struct p9_str gid;
+ struct p9_str muid;
+ struct p9_str extension; /* 9p2000.u extensions */
+ u32 n_uid; /* 9p2000.u extensions */
+ u32 n_gid; /* 9p2000.u extensions */
+ u32 n_muid; /* 9p2000.u extensions */
+};
+
+/* file metadata (stat) structure used to create Twstat message
+ The is similar to p9_stat, but the strings don't point to
+ the same memory block and should be freed separately
+*/
+struct p9_wstat {
+ u16 size;
+ u16 type;
+ u32 dev;
+ struct p9_qid qid;
+ u32 mode;
+ u32 atime;
+ u32 mtime;
+ u64 length;
+ char *name;
+ char *uid;
+ char *gid;
+ char *muid;
+ char *extension; /* 9p2000.u extensions */
+ u32 n_uid; /* 9p2000.u extensions */
+ u32 n_gid; /* 9p2000.u extensions */
+ u32 n_muid; /* 9p2000.u extensions */
+};
+
+/* Structures for Protocol Operations */
+struct p9_tversion {
+ u32 msize;
+ struct p9_str version;
+};
+
+struct p9_rversion {
+ u32 msize;
+ struct p9_str version;
+};
+
+struct p9_tauth {
+ u32 afid;
+ struct p9_str uname;
+ struct p9_str aname;
+};
+
+struct p9_rauth {
+ struct p9_qid qid;
+};
+
+struct p9_rerror {
+ struct p9_str error;
+ u32 errno; /* 9p2000.u extension */
+};
+
+struct p9_tflush {
+ u16 oldtag;
+};
+
+struct p9_rflush {
+};
+
+struct p9_tattach {
+ u32 fid;
+ u32 afid;
+ struct p9_str uname;
+ struct p9_str aname;
+};
+
+struct p9_rattach {
+ struct p9_qid qid;
+};
+
+struct p9_twalk {
+ u32 fid;
+ u32 newfid;
+ u16 nwname;
+ struct p9_str wnames[16];
+};
+
+struct p9_rwalk {
+ u16 nwqid;
+ struct p9_qid wqids[16];
+};
+
+struct p9_topen {
+ u32 fid;
+ u8 mode;
+};
+
+struct p9_ropen {
+ struct p9_qid qid;
+ u32 iounit;
+};
+
+struct p9_tcreate {
+ u32 fid;
+ struct p9_str name;
+ u32 perm;
+ u8 mode;
+ struct p9_str extension;
+};
+
+struct p9_rcreate {
+ struct p9_qid qid;
+ u32 iounit;
+};
+
+struct p9_tread {
+ u32 fid;
+ u64 offset;
+ u32 count;
+};
+
+struct p9_rread {
+ u32 count;
+ u8 *data;
+};
+
+struct p9_twrite {
+ u32 fid;
+ u64 offset;
+ u32 count;
+ u8 *data;
+};
+
+struct p9_rwrite {
+ u32 count;
+};
+
+struct p9_tclunk {
+ u32 fid;
+};
+
+struct p9_rclunk {
+};
+
+struct p9_tremove {
+ u32 fid;
+};
+
+struct p9_rremove {
+};
+
+struct p9_tstat {
+ u32 fid;
+};
+
+struct p9_rstat {
+ struct p9_stat stat;
+};
+
+struct p9_twstat {
+ u32 fid;
+ struct p9_stat stat;
+};
+
+struct p9_rwstat {
+};
+
+/*
+ * fcall is the primary packet structure
+ *
+ */
+
+struct p9_fcall {
+ u32 size;
+ u8 id;
+ u16 tag;
+ void *sdata;
+
+ union {
+ struct p9_tversion tversion;
+ struct p9_rversion rversion;
+ struct p9_tauth tauth;
+ struct p9_rauth rauth;
+ struct p9_rerror rerror;
+ struct p9_tflush tflush;
+ struct p9_rflush rflush;
+ struct p9_tattach tattach;
+ struct p9_rattach rattach;
+ struct p9_twalk twalk;
+ struct p9_rwalk rwalk;
+ struct p9_topen topen;
+ struct p9_ropen ropen;
+ struct p9_tcreate tcreate;
+ struct p9_rcreate rcreate;
+ struct p9_tread tread;
+ struct p9_rread rread;
+ struct p9_twrite twrite;
+ struct p9_rwrite rwrite;
+ struct p9_tclunk tclunk;
+ struct p9_rclunk rclunk;
+ struct p9_tremove tremove;
+ struct p9_rremove rremove;
+ struct p9_tstat tstat;
+ struct p9_rstat rstat;
+ struct p9_twstat twstat;
+ struct p9_rwstat rwstat;
+ } params;
+};
+
+struct p9_idpool;
+
+int p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
+ int dotu);
+int p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *fc, int dotu);
+void p9_set_tag(struct p9_fcall *fc, u16 tag);
+struct p9_fcall *p9_create_tversion(u32 msize, char *version);
+struct p9_fcall *p9_create_tattach(u32 fid, u32 afid, char *uname,
+ char *aname);
+struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname);
+struct p9_fcall *p9_create_tflush(u16 oldtag);
+struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
+ char **wnames);
+struct p9_fcall *p9_create_topen(u32 fid, u8 mode);
+struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
+ char *extension, int dotu);
+struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count);
+struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
+ const char *data);
+struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
+ const char __user *data);
+struct p9_fcall *p9_create_tclunk(u32 fid);
+struct p9_fcall *p9_create_tremove(u32 fid);
+struct p9_fcall *p9_create_tstat(u32 fid);
+struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
+ int dotu);
+
+int p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int dotu);
+int p9_errstr2errno(char *errstr, int len);
+
+struct p9_idpool *p9_idpool_create(void);
+void p9_idpool_destroy(struct p9_idpool *);
+int p9_idpool_get(struct p9_idpool *p);
+void p9_idpool_put(int id, struct p9_idpool *p);
+int p9_idpool_check(int id, struct p9_idpool *p);
+
+int p9_error_init(void);
+int p9_errstr2errno(char *, int);
+int __init p9_sysctl_register(void);
+void __exit p9_sysctl_unregister(void);
+#endif /* NET_9P_H */
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
new file mode 100644
index 000000000000..d65ed7c69063
--- /dev/null
+++ b/include/net/9p/client.h
@@ -0,0 +1,80 @@
+/*
+ * include/net/9p/client.h
+ *
+ * 9P Client Definitions
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ * 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:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#ifndef NET_9P_CLIENT_H
+#define NET_9P_CLIENT_H
+
+struct p9_client {
+ spinlock_t lock; /* protect client structure */
+ int msize;
+ unsigned char dotu;
+ struct p9_transport *trans;
+ struct p9_conn *conn;
+
+ struct p9_idpool *fidpool;
+ struct list_head fidlist;
+};
+
+struct p9_fid {
+ struct p9_client *clnt;
+ u32 fid;
+ int mode;
+ struct p9_qid qid;
+ u32 iounit;
+ uid_t uid;
+ void *aux;
+
+ int rdir_fpos;
+ int rdir_pos;
+ struct p9_fcall *rdir_fcall;
+ struct list_head flist;
+ struct list_head dlist; /* list of all fids attached to a dentry */
+};
+
+struct p9_client *p9_client_create(struct p9_transport *trans, int msize,
+ int dotu);
+void p9_client_destroy(struct p9_client *clnt);
+void p9_client_disconnect(struct p9_client *clnt);
+struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
+ char *uname, char *aname);
+struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname);
+struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
+ int clone);
+int p9_client_open(struct p9_fid *fid, int mode);
+int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
+ char *extension);
+int p9_client_clunk(struct p9_fid *fid);
+int p9_client_remove(struct p9_fid *fid);
+int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count);
+int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count);
+int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count);
+int p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset,
+ u32 count);
+int p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
+ u32 count);
+struct p9_stat *p9_client_stat(struct p9_fid *fid);
+int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
+struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset);
+
+#endif /* NET_9P_CLIENT_H */
diff --git a/fs/9p/mux.h b/include/net/9p/conn.h
index fb10c50186a1..583b6a2cb3df 100644
--- a/fs/9p/mux.h
+++ b/include/net/9p/conn.h
@@ -1,7 +1,7 @@
/*
- * linux/fs/9p/mux.h
+ * include/net/9p/conn.h
*
- * Multiplexer Definitions
+ * Connection Definitions
*
* Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net>
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
@@ -23,33 +23,35 @@
*
*/
-struct v9fs_mux_data;
-struct v9fs_req;
+#ifndef NET_9P_CONN_H
+#define NET_9P_CONN_H
+
+#undef P9_NONBLOCK
+
+struct p9_conn;
+struct p9_req;
/**
- * v9fs_mux_req_callback - callback function that is called when the
+ * p9_mux_req_callback - callback function that is called when the
* response of a request is received. The callback is called from
* a workqueue and shouldn't block.
*
+ * @req - request
* @a - the pointer that was specified when the request was send to be
* passed to the callback
- * @tc - request call
- * @rc - response call
- * @err - error code (non-zero if error occured)
*/
-typedef void (*v9fs_mux_req_callback)(struct v9fs_req *req, void *a);
+typedef void (*p9_conn_req_callback)(struct p9_req *req, void *a);
-int v9fs_mux_global_init(void);
-void v9fs_mux_global_exit(void);
+struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize,
+ unsigned char *dotu);
+void p9_conn_destroy(struct p9_conn *);
+int p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc, struct p9_fcall **rc);
-struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
- unsigned char *extended);
-void v9fs_mux_destroy(struct v9fs_mux_data *);
+#ifdef P9_NONBLOCK
+int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *a);
+#endif /* P9_NONBLOCK */
-int v9fs_mux_send(struct v9fs_mux_data *m, struct v9fs_fcall *tc);
-struct v9fs_fcall *v9fs_mux_recv(struct v9fs_mux_data *m);
-int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc);
+void p9_conn_cancel(struct p9_conn *m, int err);
-void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush);
-void v9fs_mux_cancel(struct v9fs_mux_data *m, int err);
-int v9fs_errstr2errno(char *errstr, int len);
+#endif /* NET_9P_CONN_H */
diff --git a/fs/9p/transport.h b/include/net/9p/transport.h
index b38a4b8a41ce..462d42279fb0 100644
--- a/fs/9p/transport.h
+++ b/include/net/9p/transport.h
@@ -1,5 +1,5 @@
/*
- * linux/fs/9p/transport.h
+ * include/net/9p/transport.h
*
* Transport Definition
*
@@ -23,23 +23,27 @@
*
*/
-enum v9fs_transport_status {
+#ifndef NET_9P_TRANSPORT_H
+#define NET_9P_TRANSPORT_H
+
+enum p9_transport_status {
Connected,
Disconnected,
Hung,
};
-struct v9fs_transport {
- enum v9fs_transport_status status;
+struct p9_transport {
+ enum p9_transport_status status;
void *priv;
- int (*init) (struct v9fs_session_info *, const char *, char *);
- int (*write) (struct v9fs_transport *, void *, int);
- int (*read) (struct v9fs_transport *, void *, int);
- void (*close) (struct v9fs_transport *);
- unsigned int (*poll)(struct v9fs_transport *, struct poll_table_struct *);
+ int (*write) (struct p9_transport *, void *, int);
+ int (*read) (struct p9_transport *, void *, int);
+ void (*close) (struct p9_transport *);
+ unsigned int (*poll)(struct p9_transport *, struct poll_table_struct *);
};
-extern struct v9fs_transport v9fs_trans_tcp;
-extern struct v9fs_transport v9fs_trans_unix;
-extern struct v9fs_transport v9fs_trans_fd;
+struct p9_transport *p9_trans_create_tcp(const char *addr, int port);
+struct p9_transport *p9_trans_create_unix(const char *addr);
+struct p9_transport *p9_trans_create_fd(int rfd, int wfd);
+
+#endif /* NET_9P_TRANSPORT_H */
diff --git a/include/net/act_api.h b/include/net/act_api.h
index 8b06c2f3657f..68b4eaf7719d 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -19,7 +19,6 @@ struct tcf_common {
struct gnet_stats_basic tcfc_bstats;
struct gnet_stats_queue tcfc_qstats;
struct gnet_stats_rate_est tcfc_rate_est;
- spinlock_t *tcfc_stats_lock;
spinlock_t tcfc_lock;
};
#define tcf_next common.tcfc_next
@@ -32,7 +31,6 @@ struct tcf_common {
#define tcf_bstats common.tcfc_bstats
#define tcf_qstats common.tcfc_qstats
#define tcf_rate_est common.tcfc_rate_est
-#define tcf_stats_lock common.tcfc_stats_lock
#define tcf_lock common.tcfc_lock
struct tcf_police {
@@ -123,34 +121,4 @@ extern int tcf_action_dump_old(struct sk_buff *skb, struct tc_action *a, int, in
extern int tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
extern int tcf_action_copy_stats (struct sk_buff *,struct tc_action *, int);
#endif /* CONFIG_NET_CLS_ACT */
-
-extern int tcf_police(struct sk_buff *skb, struct tcf_police *p);
-extern void tcf_police_destroy(struct tcf_police *p);
-extern struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est);
-extern int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p);
-extern int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *p);
-
-static inline int
-tcf_police_release(struct tcf_police *p, int bind)
-{
- int ret = 0;
-#ifdef CONFIG_NET_CLS_ACT
- if (p) {
- if (bind)
- p->tcf_bindcnt--;
-
- p->tcf_refcnt--;
- if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
- tcf_police_destroy(p);
- ret = 1;
- }
- }
-#else
- if (p && --p->tcf_refcnt == 0)
- tcf_police_destroy(p);
-
-#endif /* CONFIG_NET_CLS_ACT */
- return ret;
-}
-
#endif
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index f3531d0bcd05..33b593e17441 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -61,7 +61,7 @@ extern int addrconf_set_dstaddr(void __user *arg);
extern int ipv6_chk_addr(struct in6_addr *addr,
struct net_device *dev,
int strict);
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
extern int ipv6_chk_home_addr(struct in6_addr *addr);
#endif
extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr,
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 65f49fd7deff..6de1e9e35c73 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -79,9 +79,10 @@ struct unix_sock {
struct mutex readlock;
struct sock *peer;
struct sock *other;
- struct sock *gc_tree;
+ struct list_head link;
atomic_t inflight;
spinlock_t lock;
+ unsigned int gc_candidate : 1;
wait_queue_head_t peer_wait;
};
#define unix_sk(__sk) ((struct unix_sock *)__sk)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 93ce272a5d27..ebfb96b41106 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -107,14 +107,14 @@ enum {
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
-/* HCI Packet types */
+/* HCI data types */
#define HCI_COMMAND_PKT 0x01
#define HCI_ACLDATA_PKT 0x02
#define HCI_SCODATA_PKT 0x03
#define HCI_EVENT_PKT 0x04
#define HCI_VENDOR_PKT 0xff
-/* HCI Packet types */
+/* HCI packet types */
#define HCI_DM1 0x0008
#define HCI_DM3 0x0400
#define HCI_DM5 0x4000
@@ -129,6 +129,14 @@ enum {
#define SCO_PTYPE_MASK (HCI_HV1 | HCI_HV2 | HCI_HV3)
#define ACL_PTYPE_MASK (~SCO_PTYPE_MASK)
+/* eSCO packet types */
+#define ESCO_HV1 0x0001
+#define ESCO_HV2 0x0002
+#define ESCO_HV3 0x0004
+#define ESCO_EV3 0x0008
+#define ESCO_EV4 0x0010
+#define ESCO_EV5 0x0020
+
/* ACL flags */
#define ACL_CONT 0x01
#define ACL_START 0x02
@@ -138,6 +146,7 @@ enum {
/* Baseband links */
#define SCO_LINK 0x00
#define ACL_LINK 0x01
+#define ESCO_LINK 0x02
/* LMP features */
#define LMP_3SLOT 0x01
@@ -162,6 +171,11 @@ enum {
#define LMP_PSCHEME 0x02
#define LMP_PCONTROL 0x04
+#define LMP_ESCO 0x80
+
+#define LMP_EV4 0x01
+#define LMP_EV5 0x02
+
#define LMP_SNIFF_SUBR 0x02
/* Connection modes */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c0fc39620f36..8f67c8a7169b 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -78,6 +78,7 @@ struct hci_dev {
__u16 voice_setting;
__u16 pkt_type;
+ __u16 esco_type;
__u16 link_policy;
__u16 link_mode;
@@ -109,6 +110,7 @@ struct hci_dev {
struct sk_buff_head cmd_q;
struct sk_buff *sent_cmd;
+ struct sk_buff *reassembly[3];
struct semaphore req_lock;
wait_queue_head_t req_wait_q;
@@ -437,6 +439,8 @@ static inline int hci_recv_frame(struct sk_buff *skb)
return 0;
}
+int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
+
int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
void hci_conn_add_sysfs(struct hci_conn *conn);
@@ -449,6 +453,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT)
#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF)
#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
+#define lmp_esco_capable(dev) ((dev)->features[3] & LMP_ESCO)
/* ----- HCI protocols ----- */
struct hci_proto {
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 3c563f02907c..25aa575db807 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -323,6 +323,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc
#define RFCOMM_RELEASE_ONHUP 1
#define RFCOMM_HANGUP_NOW 2
#define RFCOMM_TTY_ATTACHED 3
+#define RFCOMM_TTY_RELEASED 4
struct rfcomm_dev_req {
s16 dev_id;
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 88171f8ce58a..7edaef6b29d6 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -11,6 +11,44 @@
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
*/
+
+/* Radiotap header iteration
+ * implemented in net/wireless/radiotap.c
+ * docs in Documentation/networking/radiotap-headers.txt
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ u8 *this_arg;
+
+ int arg_index;
+ u8 *arg;
+ __le32 *next_bitmap;
+ u32 bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+
/* from net/wireless.h */
struct wiphy;
diff --git a/include/net/dn.h b/include/net/dn.h
index ac4ce9091747..627778384c84 100644
--- a/include/net/dn.h
+++ b/include/net/dn.h
@@ -3,7 +3,6 @@
#include <linux/dn.h>
#include <net/sock.h>
-#include <net/tcp.h>
#include <asm/byteorder.h>
#define dn_ntohs(x) le16_to_cpu(x)
diff --git a/include/net/dst.h b/include/net/dst.h
index 82270f9332db..e9ff4a4caef9 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -47,7 +47,6 @@ struct dst_entry
#define DST_NOXFRM 2
#define DST_NOPOLICY 4
#define DST_NOHASH 8
-#define DST_BALANCED 0x10
unsigned long expires;
unsigned short header_len; /* more space at head required */
diff --git a/include/net/flow.h b/include/net/flow.h
index f3cc1f812619..af59fa5cc1f8 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -67,20 +67,16 @@ struct flowi {
__be32 spi;
-#ifdef CONFIG_IPV6_MIP6
struct {
__u8 type;
} mht;
-#endif
} uli_u;
#define fl_ip_sport uli_u.ports.sport
#define fl_ip_dport uli_u.ports.dport
#define fl_icmp_type uli_u.icmpt.type
#define fl_icmp_code uli_u.icmpt.code
#define fl_ipsec_spi uli_u.spi
-#ifdef CONFIG_IPV6_MIP6
#define fl_mh_type uli_u.mht.type
-#endif
__u32 secid; /* used by xfrm; see secid.txt */
} __attribute__((__aligned__(BITS_PER_LONG/8)));
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index b6eaca122db8..decdda546829 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -5,6 +5,22 @@
#include <net/netlink.h>
/**
+ * struct genl_multicast_group - generic netlink multicast group
+ * @name: name of the multicast group, names are per-family
+ * @id: multicast group ID, assigned by the core, to use with
+ * genlmsg_multicast().
+ * @list: list entry for linking
+ * @family: pointer to family, need not be set before registering
+ */
+struct genl_multicast_group
+{
+ struct genl_family *family; /* private */
+ struct list_head list; /* private */
+ char name[GENL_NAMSIZ];
+ u32 id;
+};
+
+/**
* struct genl_family - generic netlink family
* @id: protocol family idenfitier
* @hdrsize: length of user specific header in bytes
@@ -14,6 +30,7 @@
* @attrbuf: buffer to store parsed attributes
* @ops_list: list of all assigned operations
* @family_list: family list
+ * @mcast_groups: multicast groups list
*/
struct genl_family
{
@@ -25,6 +42,7 @@ struct genl_family
struct nlattr ** attrbuf; /* private */
struct list_head ops_list; /* private */
struct list_head family_list; /* private */
+ struct list_head mcast_groups; /* private */
};
/**
@@ -73,6 +91,10 @@ extern int genl_register_family(struct genl_family *family);
extern int genl_unregister_family(struct genl_family *family);
extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
+extern int genl_register_mc_group(struct genl_family *family,
+ struct genl_multicast_group *grp);
+extern void genl_unregister_mc_group(struct genl_family *family,
+ struct genl_multicast_group *grp);
extern struct sock *genl_sock;
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 09a2532699b2..47d52b2414db 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -209,9 +209,6 @@ static inline void inet_twsk_put(struct inet_timewait_sock *tw)
extern struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
const int state);
-extern void __inet_twsk_kill(struct inet_timewait_sock *tw,
- struct inet_hashinfo *hashinfo);
-
extern void __inet_twsk_hashdance(struct inet_timewait_sock *tw,
struct sock *sk,
struct inet_hashinfo *hashinfo);
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 69252cbe05b0..8cadc77c7df4 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -39,7 +39,6 @@ struct fib_config {
int fc_mx_len;
int fc_mp_len;
u32 fc_flow;
- u32 fc_mp_alg;
u32 fc_nlflags;
struct nl_info fc_nlinfo;
};
@@ -86,9 +85,6 @@ struct fib_info {
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_power;
#endif
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- u32 fib_mp_alg;
-#endif
struct fib_nh fib_nh[0];
#define fib_dev fib_nh[0].nh_dev
};
@@ -103,10 +99,6 @@ struct fib_result {
unsigned char nh_sel;
unsigned char type;
unsigned char scope;
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- __be32 network;
- __be32 netmask;
-#endif
struct fib_info *fi;
#ifdef CONFIG_IP_MULTIPLE_TABLES
struct fib_rule *r;
@@ -145,14 +137,6 @@ struct fib_result_nl {
#define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev)
#define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif)
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
-#define FIB_RES_NETWORK(res) ((res).network)
-#define FIB_RES_NETMASK(res) ((res).netmask)
-#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
-#define FIB_RES_NETWORK(res) (0)
-#define FIB_RES_NETMASK(res) (0)
-#endif /* CONFIG_IP_ROUTE_MULTIPATH_WRANDOM */
-
struct fib_table {
struct hlist_node tb_hlist;
u32 tb_id;
diff --git a/include/net/ip_mp_alg.h b/include/net/ip_mp_alg.h
deleted file mode 100644
index 25b56571e54b..000000000000
--- a/include/net/ip_mp_alg.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/* ip_mp_alg.h: IPV4 multipath algorithm support.
- *
- * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
- * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
- */
-
-#ifndef _NET_IP_MP_ALG_H
-#define _NET_IP_MP_ALG_H
-
-#include <linux/ip_mp_alg.h>
-#include <net/flow.h>
-#include <net/route.h>
-
-struct fib_nh;
-
-struct ip_mp_alg_ops {
- void (*mp_alg_select_route)(const struct flowi *flp,
- struct rtable *rth, struct rtable **rp);
- void (*mp_alg_flush)(void);
- void (*mp_alg_set_nhinfo)(__be32 network, __be32 netmask,
- unsigned char prefixlen,
- const struct fib_nh *nh);
- void (*mp_alg_remove)(struct rtable *rth);
-};
-
-extern int multipath_alg_register(struct ip_mp_alg_ops *, enum ip_mp_alg);
-extern void multipath_alg_unregister(struct ip_mp_alg_ops *, enum ip_mp_alg);
-
-extern struct ip_mp_alg_ops *ip_mp_alg_table[];
-
-static inline int multipath_select_route(const struct flowi *flp,
- struct rtable *rth,
- struct rtable **rp)
-{
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];
-
- /* mp_alg_select_route _MUST_ be implemented */
- if (ops && (rth->u.dst.flags & DST_BALANCED)) {
- ops->mp_alg_select_route(flp, rth, rp);
- return 1;
- }
-#endif
- return 0;
-}
-
-static inline void multipath_flush(void)
-{
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- int i;
-
- for (i = IP_MP_ALG_NONE; i <= IP_MP_ALG_MAX; i++) {
- struct ip_mp_alg_ops *ops = ip_mp_alg_table[i];
-
- if (ops && ops->mp_alg_flush)
- ops->mp_alg_flush();
- }
-#endif
-}
-
-static inline void multipath_set_nhinfo(struct rtable *rth,
- __be32 network, __be32 netmask,
- unsigned char prefixlen,
- const struct fib_nh *nh)
-{
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];
-
- if (ops && ops->mp_alg_set_nhinfo)
- ops->mp_alg_set_nhinfo(network, netmask, prefixlen, nh);
-#endif
-}
-
-static inline void multipath_remove(struct rtable *rth)
-{
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- struct ip_mp_alg_ops *ops = ip_mp_alg_table[rth->rt_multipath_alg];
-
- if (ops && ops->mp_alg_remove &&
- (rth->u.dst.flags & DST_BALANCED))
- ops->mp_alg_remove(rth);
-#endif
-}
-
-static inline int multipath_comparekeys(const struct flowi *flp1,
- const struct flowi *flp2)
-{
- return flp1->fl4_dst == flp2->fl4_dst &&
- flp1->fl4_src == flp2->fl4_src &&
- flp1->oif == flp2->oif &&
- flp1->mark == flp2->mark &&
- !((flp1->fl4_tos ^ flp2->fl4_tos) &
- (IPTOS_RT_MASK | RTO_ONLINK));
-}
-
-#endif /* _NET_IP_MP_ALG_H */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 78a0d06d98d5..46b9dce82f6e 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -512,10 +512,6 @@ extern int ipv6_ext_hdr(u8 nexthdr);
extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type);
-extern struct ipv6_txoptions * ipv6_invert_rthdr(struct sock *sk,
- struct ipv6_rt_hdr *hdr);
-
-
/*
* socket options (ipv6_sockglue.c)
*/
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 36bee441aa56..08387553b57e 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -125,6 +125,9 @@ extern void irda_sysctl_unregister(void);
extern int irsock_init(void);
extern void irsock_cleanup(void);
+extern int irda_nl_register(void);
+extern void irda_nl_unregister(void);
+
extern int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *ptype,
struct net_device *orig_dev);
diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h
index a3d370efb903..9d0c78ea92f5 100644
--- a/include/net/irda/irlap.h
+++ b/include/net/irda/irlap.h
@@ -208,6 +208,8 @@ struct irlap_cb {
int xbofs_delay; /* Nr of XBOF's used to MTT */
int bofs_count; /* Negotiated extra BOFs */
int next_bofs; /* Negotiated extra BOFs after next frame */
+
+ int mode; /* IrLAP mode (primary, secondary or monitor) */
};
/*
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h
index f9bd11be1891..b6c468cd7f5b 100644
--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -60,6 +60,7 @@ struct iucv_sock {
char dst_user_id[8];
char dst_name[8];
struct list_head accept_q;
+ spinlock_t accept_q_lock;
struct sock *parent;
struct iucv_path *path;
struct sk_buff_head send_skb_q;
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index a7f122b79948..c34fd9a6160a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -347,9 +347,16 @@ enum ieee80211_if_types {
* @mac_addr: pointer to MAC address of the interface. This pointer is valid
* until the interface is removed (i.e. it cannot be used after
* remove_interface() callback was called for this interface).
+ * This pointer will be %NULL for monitor interfaces, be careful.
*
* This structure is used in add_interface() and remove_interface()
* callbacks of &struct ieee80211_hw.
+ *
+ * When you allow multiple interfaces to be added to your PHY, take care
+ * that the hardware can actually handle multiple MAC addresses. However,
+ * also take care that when there's no interface left with mac_addr != %NULL
+ * you remove the MAC address from the device to avoid acknowledging packets
+ * in pure monitor mode.
*/
struct ieee80211_if_init_conf {
int if_id;
@@ -574,10 +581,11 @@ struct ieee80211_ops {
* to returning zero. By returning non-zero addition of the interface
* is inhibited. Unless monitor_during_oper is set, it is guaranteed
* that monitor interfaces and normal interfaces are mutually
- * exclusive. The open() handler is called after add_interface()
- * if this is the first device added. At least one of the open()
- * open() and add_interface() callbacks has to be assigned. If
- * add_interface() is NULL, one STA interface is permitted only. */
+ * exclusive. If assigned, the open() handler is called after
+ * add_interface() if this is the first device added. The
+ * add_interface() callback has to be assigned because it is the only
+ * way to obtain the requested MAC address for any interface.
+ */
int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_if_init_conf *conf);
@@ -921,12 +929,6 @@ struct sk_buff *
ieee80211_get_buffered_bc(struct ieee80211_hw *hw, int if_id,
struct ieee80211_tx_control *control);
-/* Low level drivers that have their own MLME and MAC indicate
- * the aid for an associating station with this call */
-int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw,
- u8 *peer_address, u16 aid);
-
-
/* Given an sk_buff with a raw 802.11 header at the data pointer this function
* returns the 802.11 header length in bytes (not including encryption
* headers). If the data in the sk_buff is too short to contain a valid 802.11
diff --git a/include/net/mip6.h b/include/net/mip6.h
index 68263c6d9996..63272610a24a 100644
--- a/include/net/mip6.h
+++ b/include/net/mip6.h
@@ -54,8 +54,4 @@ struct ip6_mh {
#define IP6_MH_TYPE_BERROR 7 /* Binding Error */
#define IP6_MH_TYPE_MAX IP6_MH_TYPE_BERROR
-extern int mip6_init(void);
-extern void mip6_fini(void);
-extern int mip6_mh_filter(struct sock *sk, struct sk_buff *skb);
-
#endif
diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
index 1401ccc051c4..7a671603fca6 100644
--- a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
+++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h
@@ -9,29 +9,10 @@
#ifndef _NF_CONNTRACK_IPV4_H
#define _NF_CONNTRACK_IPV4_H
-#ifdef CONFIG_NF_NAT_NEEDED
-#include <net/netfilter/nf_nat.h>
-#include <linux/netfilter/nf_conntrack_pptp.h>
-
-/* per conntrack: nat application helper private data */
-union nf_conntrack_nat_help {
- /* insert nat helper private data here */
- struct nf_nat_pptp nat_pptp_info;
-};
-
-struct nf_conn_nat {
- struct nf_nat_info info;
- union nf_conntrack_nat_help help;
-#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
- defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
- int masq_index;
-#endif
-};
-#endif /* CONFIG_NF_NAT_NEEDED */
-
/* Returns new sk_buff, or NULL */
-struct sk_buff *
-nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
+struct sk_buff *nf_ct_ipv4_ct_gather_frags(struct sk_buff *skb);
+
+extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4;
diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
index b4b6049e01fa..5a8965904377 100644
--- a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
+++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h
@@ -7,7 +7,7 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6;
extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6;
-extern int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start,
+extern int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start,
u8 *nexthdrp, int len);
extern int nf_ct_frag6_init(void);
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 4732432f8eb0..810020ec345d 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -82,6 +82,8 @@ struct nf_conn_help {
union nf_conntrack_help help;
+ struct hlist_head expectations;
+
/* Current number of expected connections */
unsigned int expecting;
};
@@ -117,9 +119,6 @@ struct nf_conn
/* Unique ID that identifies this conntrack*/
unsigned int id;
- /* features - nat, helper, ... used by allocating system */
- u_int32_t features;
-
#if defined(CONFIG_NF_CONNTRACK_MARK)
u_int32_t mark;
#endif
@@ -131,8 +130,8 @@ struct nf_conn
/* Storage reserved for other modules: */
union nf_conntrack_proto proto;
- /* features dynamically at the end: helper, nat (both optional) */
- char data[0];
+ /* Extensions */
+ struct nf_ct_ext *ext;
};
static inline struct nf_conn *
@@ -175,6 +174,10 @@ static inline void nf_ct_put(struct nf_conn *ct)
extern int nf_ct_l3proto_try_module_get(unsigned short l3proto);
extern void nf_ct_l3proto_module_put(unsigned short l3proto);
+extern struct hlist_head *nf_ct_alloc_hashtable(int *sizep, int *vmalloced);
+extern void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced,
+ int size);
+
extern struct nf_conntrack_tuple_hash *
__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *ignored_conntrack);
@@ -183,6 +186,10 @@ extern void nf_conntrack_hash_insert(struct nf_conn *ct);
extern void nf_conntrack_flush(void);
+extern int nf_ct_get_tuplepr(const struct sk_buff *skb,
+ unsigned int nhoff,
+ u_int16_t l3num,
+ struct nf_conntrack_tuple *tuple);
extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig);
@@ -216,9 +223,6 @@ extern void nf_conntrack_tcp_update(struct sk_buff *skb,
struct nf_conn *conntrack,
int dir);
-/* Call me when a conntrack is destroyed. */
-extern void (*nf_conntrack_destroyed)(struct nf_conn *conntrack);
-
/* Fake conntrack entry for untracked connections */
extern struct nf_conn nf_conntrack_untracked;
@@ -262,60 +266,10 @@ do { \
local_bh_enable(); \
} while (0)
-/* no helper, no nat */
-#define NF_CT_F_BASIC 0
-/* for helper */
-#define NF_CT_F_HELP 1
-/* for nat. */
-#define NF_CT_F_NAT 2
-#define NF_CT_F_NUM 4
-
extern int
nf_conntrack_register_cache(u_int32_t features, const char *name, size_t size);
extern void
nf_conntrack_unregister_cache(u_int32_t features);
-/* valid combinations:
- * basic: nf_conn, nf_conn .. nf_conn_help
- * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat .. nf_conn help
- */
-#ifdef CONFIG_NF_NAT_NEEDED
-static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct)
-{
- unsigned int offset = sizeof(struct nf_conn);
-
- if (!(ct->features & NF_CT_F_NAT))
- return NULL;
-
- offset = ALIGN(offset, __alignof__(struct nf_conn_nat));
- return (struct nf_conn_nat *) ((void *)ct + offset);
-}
-
-static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
-{
- unsigned int offset = sizeof(struct nf_conn);
-
- if (!(ct->features & NF_CT_F_HELP))
- return NULL;
- if (ct->features & NF_CT_F_NAT) {
- offset = ALIGN(offset, __alignof__(struct nf_conn_nat));
- offset += sizeof(struct nf_conn_nat);
- }
-
- offset = ALIGN(offset, __alignof__(struct nf_conn_help));
- return (struct nf_conn_help *) ((void *)ct + offset);
-}
-#else /* No NAT */
-static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
-{
- unsigned int offset = sizeof(struct nf_conn);
-
- if (!(ct->features & NF_CT_F_HELP))
- return NULL;
-
- offset = ALIGN(offset, __alignof__(struct nf_conn_help));
- return (struct nf_conn_help *) ((void *)ct + offset);
-}
-#endif /* CONFIG_NF_NAT_NEEDED */
#endif /* __KERNEL__ */
#endif /* _NF_CONNTRACK_H */
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 9fb906688ffa..4056f5f08da1 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -30,6 +30,9 @@ extern void nf_conntrack_cleanup(void);
extern int nf_conntrack_proto_init(void);
extern void nf_conntrack_proto_fini(void);
+extern int nf_conntrack_helper_init(void);
+extern void nf_conntrack_helper_fini(void);
+
struct nf_conntrack_l3proto;
extern struct nf_conntrack_l3proto *nf_ct_find_l3proto(u_int16_t pf);
/* Like above, but you already have conntrack read lock. */
@@ -55,8 +58,7 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
/* Find a connection corresponding to a tuple. */
extern struct nf_conntrack_tuple_hash *
-nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
- const struct nf_conn *ignored_conntrack);
+nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple);
extern int __nf_conntrack_confirm(struct sk_buff **pskb);
@@ -81,9 +83,8 @@ print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *proto);
-extern struct list_head *nf_conntrack_hash;
-extern struct list_head nf_conntrack_expect_list;
+extern struct hlist_head *nf_conntrack_hash;
extern rwlock_t nf_conntrack_lock ;
-extern struct list_head unconfirmed;
+extern struct hlist_head unconfirmed;
#endif /* _NF_CONNTRACK_CORE_H */
diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h
index 811c9073c532..f0b9078235c9 100644
--- a/include/net/netfilter/nf_conntrack_ecache.h
+++ b/include/net/netfilter/nf_conntrack_ecache.h
@@ -49,15 +49,15 @@ static inline void nf_conntrack_event(enum ip_conntrack_events event,
atomic_notifier_call_chain(&nf_conntrack_chain, event, ct);
}
-extern struct atomic_notifier_head nf_conntrack_expect_chain;
-extern int nf_conntrack_expect_register_notifier(struct notifier_block *nb);
-extern int nf_conntrack_expect_unregister_notifier(struct notifier_block *nb);
+extern struct atomic_notifier_head nf_ct_expect_chain;
+extern int nf_ct_expect_register_notifier(struct notifier_block *nb);
+extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb);
static inline void
-nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
- struct nf_conntrack_expect *exp)
+nf_ct_expect_event(enum ip_conntrack_expect_events event,
+ struct nf_conntrack_expect *exp)
{
- atomic_notifier_call_chain(&nf_conntrack_expect_chain, event, exp);
+ atomic_notifier_call_chain(&nf_ct_expect_chain, event, exp);
}
#else /* CONFIG_NF_CONNTRACK_EVENTS */
@@ -67,9 +67,8 @@ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event,
static inline void nf_conntrack_event(enum ip_conntrack_events event,
struct nf_conn *ct) {}
static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {}
-static inline void
-nf_conntrack_expect_event(enum ip_conntrack_expect_events event,
- struct nf_conntrack_expect *exp) {}
+static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event,
+ struct nf_conntrack_expect *exp) {}
static inline void nf_ct_event_cache_flush(void) {}
#endif /* CONFIG_NF_CONNTRACK_EVENTS */
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 173c7c1eff23..cae1a0dce365 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -6,17 +6,21 @@
#define _NF_CONNTRACK_EXPECT_H
#include <net/netfilter/nf_conntrack.h>
-extern struct list_head nf_conntrack_expect_list;
-extern struct kmem_cache *nf_conntrack_expect_cachep;
-extern const struct file_operations exp_file_ops;
+extern struct hlist_head *nf_ct_expect_hash;
+extern unsigned int nf_ct_expect_hsize;
+extern unsigned int nf_ct_expect_max;
struct nf_conntrack_expect
{
- /* Internal linked list (global expectation list) */
- struct list_head list;
+ /* Conntrack expectation list member */
+ struct hlist_node lnode;
+
+ /* Hash member */
+ struct hlist_node hnode;
/* We expect this tuple, with the following mask */
- struct nf_conntrack_tuple tuple, mask;
+ struct nf_conntrack_tuple tuple;
+ struct nf_conntrack_tuple_mask mask;
/* Function to call after setup and insertion */
void (*expectfn)(struct nf_conn *new,
@@ -52,29 +56,31 @@ struct nf_conntrack_expect
#define NF_CT_EXPECT_PERMANENT 0x1
+int nf_conntrack_expect_init(void);
+void nf_conntrack_expect_fini(void);
struct nf_conntrack_expect *
-__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
+__nf_ct_expect_find(const struct nf_conntrack_tuple *tuple);
struct nf_conntrack_expect *
-nf_conntrack_expect_find_get(const struct nf_conntrack_tuple *tuple);
+nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple);
struct nf_conntrack_expect *
-find_expectation(const struct nf_conntrack_tuple *tuple);
+nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple);
void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
void nf_ct_remove_expectations(struct nf_conn *ct);
-void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp);
+void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
/* Allocate space for an expectation: this is mandatory before calling
- nf_conntrack_expect_related. You will have to call put afterwards. */
-struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me);
-void nf_conntrack_expect_init(struct nf_conntrack_expect *, int,
- union nf_conntrack_address *,
- union nf_conntrack_address *,
- u_int8_t, __be16 *, __be16 *);
-void nf_conntrack_expect_put(struct nf_conntrack_expect *exp);
-int nf_conntrack_expect_related(struct nf_conntrack_expect *expect);
+ nf_ct_expect_related. You will have to call put afterwards. */
+struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me);
+void nf_ct_expect_init(struct nf_conntrack_expect *, int,
+ union nf_conntrack_address *,
+ union nf_conntrack_address *,
+ u_int8_t, __be16 *, __be16 *);
+void nf_ct_expect_put(struct nf_conntrack_expect *exp);
+int nf_ct_expect_related(struct nf_conntrack_expect *expect);
#endif /*_NF_CONNTRACK_EXPECT_H*/
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
new file mode 100644
index 000000000000..73b5711faf32
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -0,0 +1,85 @@
+#ifndef _NF_CONNTRACK_EXTEND_H
+#define _NF_CONNTRACK_EXTEND_H
+
+#include <net/netfilter/nf_conntrack.h>
+
+enum nf_ct_ext_id
+{
+ NF_CT_EXT_HELPER,
+ NF_CT_EXT_NAT,
+ NF_CT_EXT_NUM,
+};
+
+#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
+#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
+
+/* Extensions: optional stuff which isn't permanently in struct. */
+struct nf_ct_ext {
+ u8 offset[NF_CT_EXT_NUM];
+ u8 len;
+ u8 real_len;
+ char data[0];
+};
+
+static inline int nf_ct_ext_exist(const struct nf_conn *ct, u8 id)
+{
+ return (ct->ext && ct->ext->offset[id]);
+}
+
+static inline void *__nf_ct_ext_find(const struct nf_conn *ct, u8 id)
+{
+ if (!nf_ct_ext_exist(ct, id))
+ return NULL;
+
+ return (void *)ct->ext + ct->ext->offset[id];
+}
+#define nf_ct_ext_find(ext, id) \
+ ((id##_TYPE *)__nf_ct_ext_find((ext), (id)))
+
+/* Destroy all relationships */
+extern void __nf_ct_ext_destroy(struct nf_conn *ct);
+static inline void nf_ct_ext_destroy(struct nf_conn *ct)
+{
+ if (ct->ext)
+ __nf_ct_ext_destroy(ct);
+}
+
+/* Free operation. If you want to free a object referred from private area,
+ * please implement __nf_ct_ext_free() and call it.
+ */
+static inline void nf_ct_ext_free(struct nf_conn *ct)
+{
+ if (ct->ext)
+ kfree(ct->ext);
+}
+
+/* Add this type, returns pointer to data or NULL. */
+void *
+__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp);
+#define nf_ct_ext_add(ct, id, gfp) \
+ ((id##_TYPE *)__nf_ct_ext_add((ct), (id), (gfp)))
+
+#define NF_CT_EXT_F_PREALLOC 0x0001
+
+struct nf_ct_ext_type
+{
+ /* Destroys relationships (can be NULL). */
+ void (*destroy)(struct nf_conn *ct);
+ /* Called when realloacted (can be NULL).
+ Contents has already been moved. */
+ void (*move)(struct nf_conn *ct, void *old);
+
+ enum nf_ct_ext_id id;
+
+ unsigned int flags;
+
+ /* Length and min alignment. */
+ u8 len;
+ u8 align;
+ /* initial size of nf_ct_ext. */
+ u8 alloc_size;
+};
+
+int nf_ct_extend_register(struct nf_ct_ext_type *type);
+void nf_ct_extend_unregister(struct nf_ct_ext_type *type);
+#endif /* _NF_CONNTRACK_EXTEND_H */
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index 8c72ac9f0ab8..d04f99964d94 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -10,12 +10,13 @@
#ifndef _NF_CONNTRACK_HELPER_H
#define _NF_CONNTRACK_HELPER_H
#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_extend.h>
struct module;
struct nf_conntrack_helper
-{
- struct list_head list; /* Internal use. */
+{
+ struct hlist_node hnode; /* Internal use. */
const char *name; /* name of the module */
struct module *me; /* pointer to self */
@@ -23,10 +24,9 @@ struct nf_conntrack_helper
* expected connections */
unsigned int timeout; /* timeout for expecteds */
- /* Mask of things we will help (compared against server response) */
+ /* Tuple of things we will help (compared against server response) */
struct nf_conntrack_tuple tuple;
- struct nf_conntrack_tuple mask;
-
+
/* Function to call when data passes; return verdict, or -1 to
invalidate. */
int (*help)(struct sk_buff **pskb,
@@ -52,4 +52,10 @@ extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
+extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
+
+static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
+{
+ return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
+}
#endif /*_NF_CONNTRACK_HELPER_H*/
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 96a58d8e1d3f..3c58a2c4df28 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -58,13 +58,11 @@ struct nf_conntrack_l3proto
/*
* Called before tracking.
- * *dataoff: offset of protocol header (TCP, UDP,...) in *pskb
+ * *dataoff: offset of protocol header (TCP, UDP,...) in skb
* *protonum: protocol number
*/
- int (*prepare)(struct sk_buff **pskb, unsigned int hooknum,
- unsigned int *dataoff, u_int8_t *protonum);
-
- u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple);
+ int (*get_l4proto)(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum);
int (*tuple_to_nfattr)(struct sk_buff *skb,
const struct nf_conntrack_tuple *t);
@@ -91,8 +89,6 @@ extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto);
extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
/* Existing built-in protocols */
-extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
-extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_generic;
static inline struct nf_conntrack_l3proto *
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
index 5d72b16e876f..040dae5f0c9e 100644
--- a/include/net/netfilter/nf_conntrack_tuple.h
+++ b/include/net/netfilter/nf_conntrack_tuple.h
@@ -100,6 +100,14 @@ struct nf_conntrack_tuple
} dst;
};
+struct nf_conntrack_tuple_mask
+{
+ struct {
+ union nf_conntrack_address u3;
+ union nf_conntrack_man_proto u;
+ } src;
+};
+
/* This is optimized opposed to a memset of the whole structure. Everything we
* really care about is the source/destination unions */
#define NF_CT_TUPLE_U_BLANK(tuple) \
@@ -112,11 +120,11 @@ struct nf_conntrack_tuple
#ifdef __KERNEL__
-#define NF_CT_DUMP_TUPLE(tp) \
-DEBUGP("tuple %p: %u %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n", \
- (tp), (tp)->src.l3num, (tp)->dst.protonum, \
- NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \
- NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all))
+#define NF_CT_DUMP_TUPLE(tp) \
+pr_debug("tuple %p: %u %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n", \
+ (tp), (tp)->src.l3num, (tp)->dst.protonum, \
+ NIP6(*(struct in6_addr *)(tp)->src.u3.all), ntohs((tp)->src.u.all), \
+ NIP6(*(struct in6_addr *)(tp)->dst.u3.all), ntohs((tp)->dst.u.all))
/* If we're the first tuple, it's the original dir. */
#define NF_CT_DIRECTION(h) \
@@ -125,8 +133,7 @@ DEBUGP("tuple %p: %u %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n", \
/* Connections have two entries in the hash table: one for each way */
struct nf_conntrack_tuple_hash
{
- struct list_head list;
-
+ struct hlist_node hnode;
struct nf_conntrack_tuple tuple;
};
@@ -162,31 +169,44 @@ static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1,
return nf_ct_tuple_src_equal(t1, t2) && nf_ct_tuple_dst_equal(t1, t2);
}
+static inline int nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1,
+ const struct nf_conntrack_tuple_mask *m2)
+{
+ return (m1->src.u3.all[0] == m2->src.u3.all[0] &&
+ m1->src.u3.all[1] == m2->src.u3.all[1] &&
+ m1->src.u3.all[2] == m2->src.u3.all[2] &&
+ m1->src.u3.all[3] == m2->src.u3.all[3] &&
+ m1->src.u.all == m2->src.u.all);
+}
+
+static inline int nf_ct_tuple_src_mask_cmp(const struct nf_conntrack_tuple *t1,
+ const struct nf_conntrack_tuple *t2,
+ const struct nf_conntrack_tuple_mask *mask)
+{
+ int count;
+
+ for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++) {
+ if ((t1->src.u3.all[count] ^ t2->src.u3.all[count]) &
+ mask->src.u3.all[count])
+ return 0;
+ }
+
+ if ((t1->src.u.all ^ t2->src.u.all) & mask->src.u.all)
+ return 0;
+
+ if (t1->src.l3num != t2->src.l3num ||
+ t1->dst.protonum != t2->dst.protonum)
+ return 0;
+
+ return 1;
+}
+
static inline int nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t,
const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_tuple *mask)
+ const struct nf_conntrack_tuple_mask *mask)
{
- int count = 0;
-
- for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
- if ((t->src.u3.all[count] ^ tuple->src.u3.all[count]) &
- mask->src.u3.all[count])
- return 0;
- }
-
- for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
- if ((t->dst.u3.all[count] ^ tuple->dst.u3.all[count]) &
- mask->dst.u3.all[count])
- return 0;
- }
-
- if ((t->src.u.all ^ tuple->src.u.all) & mask->src.u.all ||
- (t->dst.u.all ^ tuple->dst.u.all) & mask->dst.u.all ||
- (t->src.l3num ^ tuple->src.l3num) & mask->src.l3num ||
- (t->dst.protonum ^ tuple->dst.protonum) & mask->dst.protonum)
- return 0;
-
- return 1;
+ return nf_ct_tuple_src_mask_cmp(t, tuple, mask) &&
+ nf_ct_tuple_dst_equal(t, tuple);
}
#endif /* _NF_CONNTRACK_TUPLE_H */
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h
index bc57dd7b9b5c..6ae52f7c9f55 100644
--- a/include/net/netfilter/nf_nat.h
+++ b/include/net/netfilter/nf_nat.h
@@ -51,16 +51,31 @@ struct nf_nat_multi_range_compat
#ifdef __KERNEL__
#include <linux/list.h>
+#include <linux/netfilter/nf_conntrack_pptp.h>
+#include <net/netfilter/nf_conntrack_extend.h>
-/* The structure embedded in the conntrack structure. */
-struct nf_nat_info
+/* per conntrack: nat application helper private data */
+union nf_conntrack_nat_help
{
- struct list_head bysource;
- struct nf_nat_seq seq[IP_CT_DIR_MAX];
+ /* insert nat helper private data here */
+ struct nf_nat_pptp nat_pptp_info;
};
struct nf_conn;
+/* The structure embedded in the conntrack structure. */
+struct nf_conn_nat
+{
+ struct hlist_node bysource;
+ struct nf_nat_seq seq[IP_CT_DIR_MAX];
+ struct nf_conn *ct;
+ union nf_conntrack_nat_help help;
+#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \
+ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE)
+ int masq_index;
+#endif
+};
+
/* Set up the info structure to map into this range. */
extern unsigned int nf_nat_setup_info(struct nf_conn *ct,
const struct nf_nat_range *range,
@@ -70,7 +85,10 @@ extern unsigned int nf_nat_setup_info(struct nf_conn *ct,
extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *ignored_conntrack);
-extern int nf_nat_module_is_loaded;
+static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct)
+{
+ return nf_ct_ext_find(ct, NF_CT_EXT_NAT);
+}
#else /* !__KERNEL__: iptables wants this to compile. */
#define nf_nat_multi_range nf_nat_multi_range_compat
diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h
index 9778ffa93440..c3cd127ba4bb 100644
--- a/include/net/netfilter/nf_nat_core.h
+++ b/include/net/netfilter/nf_nat_core.h
@@ -2,6 +2,7 @@
#define _NF_NAT_CORE_H
#include <linux/list.h>
#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_nat.h>
/* This header used to share core functionality between the standalone
NAT module, and the compatibility layer's use of NAT for masquerading. */
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 9b7d6f2ac9a3..ffbc7f28335a 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -144,10 +144,9 @@ struct netlbl_lsm_secattr {
};
/*
- * LSM security attribute operations
+ * LSM security attribute operations (inline)
*/
-
/**
* netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache
* @flags: the memory allocation flags
@@ -283,6 +282,9 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
}
#ifdef CONFIG_NETLABEL
+/*
+ * LSM security attribute operations
+ */
int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
u32 offset);
int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
@@ -294,6 +296,25 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
u32 start,
u32 end,
gfp_t flags);
+
+/*
+ * LSM protocol operations
+ */
+int netlbl_enabled(void);
+int netlbl_sock_setattr(struct sock *sk,
+ const struct netlbl_lsm_secattr *secattr);
+int netlbl_sock_getattr(struct sock *sk,
+ struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_getattr(const struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr);
+void netlbl_skbuff_err(struct sk_buff *skb, int error);
+
+/*
+ * LSM label mapping cache operations
+ */
+void netlbl_cache_invalidate(void);
+int netlbl_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr);
#else
static inline int netlbl_secattr_catmap_walk(
struct netlbl_lsm_secattr_catmap *catmap,
@@ -301,14 +322,12 @@ static inline int netlbl_secattr_catmap_walk(
{
return -ENOENT;
}
-
static inline int netlbl_secattr_catmap_walk_rng(
struct netlbl_lsm_secattr_catmap *catmap,
u32 offset)
{
return -ENOENT;
}
-
static inline int netlbl_secattr_catmap_setbit(
struct netlbl_lsm_secattr_catmap *catmap,
u32 bit,
@@ -316,7 +335,6 @@ static inline int netlbl_secattr_catmap_setbit(
{
return 0;
}
-
static inline int netlbl_secattr_catmap_setrng(
struct netlbl_lsm_secattr_catmap *catmap,
u32 start,
@@ -325,59 +343,33 @@ static inline int netlbl_secattr_catmap_setrng(
{
return 0;
}
-#endif
-
-/*
- * LSM protocol operations
- */
-
-#ifdef CONFIG_NETLABEL
-int netlbl_sock_setattr(struct sock *sk,
- const struct netlbl_lsm_secattr *secattr);
-int netlbl_sock_getattr(struct sock *sk,
- struct netlbl_lsm_secattr *secattr);
-int netlbl_skbuff_getattr(const struct sk_buff *skb,
- struct netlbl_lsm_secattr *secattr);
-void netlbl_skbuff_err(struct sk_buff *skb, int error);
-#else
+static inline int netlbl_enabled(void)
+{
+ return 0;
+}
static inline int netlbl_sock_setattr(struct sock *sk,
const struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
-
static inline int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
-
static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
-
static inline void netlbl_skbuff_err(struct sk_buff *skb, int error)
{
return;
}
-#endif /* CONFIG_NETLABEL */
-
-/*
- * LSM label mapping cache operations
- */
-
-#ifdef CONFIG_NETLABEL
-void netlbl_cache_invalidate(void);
-int netlbl_cache_add(const struct sk_buff *skb,
- const struct netlbl_lsm_secattr *secattr);
-#else
static inline void netlbl_cache_invalidate(void)
{
return;
}
-
static inline int netlbl_cache_add(const struct sk_buff *skb,
const struct netlbl_lsm_secattr *secattr)
{
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 7b510a9edb91..d7b824be5422 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -118,6 +118,9 @@
* Nested Attributes Construction:
* nla_nest_start(skb, type) start a nested attribute
* nla_nest_end(skb, nla) finalize a nested attribute
+ * nla_nest_compat_start(skb, type, start a nested compat attribute
+ * len, data)
+ * nla_nest_compat_end(skb, type) finalize a nested compat attribute
* nla_nest_cancel(skb, nla) cancel nested attribute construction
*
* Attribute Length Calculations:
@@ -152,6 +155,7 @@
* nla_find_nested() find attribute in nested attributes
* nla_parse() parse and validate stream of attrs
* nla_parse_nested() parse nested attribuets
+ * nla_parse_nested_compat() parse nested compat attributes
* nla_for_each_attr() loop over all attributes
* nla_for_each_nested() loop over the nested attributes
*=========================================================================
@@ -170,6 +174,7 @@ enum {
NLA_FLAG,
NLA_MSECS,
NLA_NESTED,
+ NLA_NESTED_COMPAT,
NLA_NUL_STRING,
NLA_BINARY,
__NLA_TYPE_MAX,
@@ -190,6 +195,7 @@ enum {
* NLA_NUL_STRING Maximum length of string (excluding NUL)
* NLA_FLAG Unused
* NLA_BINARY Maximum length of attribute payload
+ * NLA_NESTED_COMPAT Exact length of structure payload
* All other Exact length of attribute payload
*
* Example:
@@ -733,6 +739,39 @@ static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
{
return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
}
+
+/**
+ * nla_parse_nested_compat - parse nested compat attributes
+ * @tb: destination array with maxtype+1 elements
+ * @maxtype: maximum attribute type to be expected
+ * @nla: attribute containing the nested attributes
+ * @data: pointer to point to contained structure
+ * @len: length of contained structure
+ * @policy: validation policy
+ *
+ * Parse a nested compat attribute. The compat attribute contains a structure
+ * and optionally a set of nested attributes. On success the data pointer
+ * points to the nested data and tb contains the parsed attributes
+ * (see nla_parse).
+ */
+static inline int __nla_parse_nested_compat(struct nlattr *tb[], int maxtype,
+ struct nlattr *nla,
+ const struct nla_policy *policy,
+ int len)
+{
+ if (nla_len(nla) < len)
+ return -1;
+ if (nla_len(nla) >= NLA_ALIGN(len) + sizeof(struct nlattr))
+ return nla_parse_nested(tb, maxtype,
+ nla_data(nla) + NLA_ALIGN(len),
+ policy);
+ memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
+ return 0;
+}
+
+#define nla_parse_nested_compat(tb, maxtype, nla, policy, data, len) \
+({ data = nla_len(nla) >= len ? nla_data(nla) : NULL; \
+ __nla_parse_nested_compat(tb, maxtype, nla, policy, len); })
/**
* nla_put_u8 - Add a u16 netlink attribute to a socket buffer
* @skb: socket buffer to add attribute to
@@ -965,6 +1004,51 @@ static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start)
}
/**
+ * nla_nest_compat_start - Start a new level of nested compat attributes
+ * @skb: socket buffer to add attributes to
+ * @attrtype: attribute type of container
+ * @attrlen: length of structure
+ * @data: pointer to structure
+ *
+ * Start a nested compat attribute that contains both a structure and
+ * a set of nested attributes.
+ *
+ * Returns the container attribute
+ */
+static inline struct nlattr *nla_nest_compat_start(struct sk_buff *skb,
+ int attrtype, int attrlen,
+ const void *data)
+{
+ struct nlattr *start = (struct nlattr *)skb_tail_pointer(skb);
+
+ if (nla_put(skb, attrtype, attrlen, data) < 0)
+ return NULL;
+ if (nla_nest_start(skb, attrtype) == NULL) {
+ nlmsg_trim(skb, start);
+ return NULL;
+ }
+ return start;
+}
+
+/**
+ * nla_nest_compat_end - Finalize nesting of compat attributes
+ * @skb: socket buffer the attribtues are stored in
+ * @start: container attribute
+ *
+ * Corrects the container attribute header to include the all
+ * appeneded attributes.
+ *
+ * Returns the total data length of the skb.
+ */
+static inline int nla_nest_compat_end(struct sk_buff *skb, struct nlattr *start)
+{
+ struct nlattr *nest = (void *)start + NLMSG_ALIGN(start->nla_len);
+
+ start->nla_len = skb_tail_pointer(skb) - (unsigned char *)start;
+ return nla_nest_end(skb, nest);
+}
+
+/**
* nla_nest_cancel - Cancel nesting of attributes
* @skb: socket buffer the message is stored in
* @start: container attribute
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index 4129df708079..7968b1d66369 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -65,8 +65,6 @@ struct tcf_exts
{
#ifdef CONFIG_NET_CLS_ACT
struct tc_action *action;
-#elif defined CONFIG_NET_CLS_POLICE
- struct tcf_police *police;
#endif
};
@@ -91,8 +89,6 @@ tcf_exts_is_predicative(struct tcf_exts *exts)
{
#ifdef CONFIG_NET_CLS_ACT
return !!exts->action;
-#elif defined CONFIG_NET_CLS_POLICE
- return !!exts->police;
#else
return 0;
#endif
@@ -129,11 +125,7 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
#ifdef CONFIG_NET_CLS_ACT
if (exts->action)
return tcf_action_exec(skb, exts->action, res);
-#elif defined CONFIG_NET_CLS_POLICE
- if (exts->police)
- return tcf_police(skb, exts->police);
#endif
-
return 0;
}
@@ -306,6 +298,8 @@ static inline int tcf_em_tree_match(struct sk_buff *skb,
return 1;
}
+#define MODULE_ALIAS_TCF_EMATCH(kind) MODULE_ALIAS("ematch-kind-" __stringify(kind))
+
#else /* CONFIG_NET_EMATCH */
struct tcf_ematch_tree
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index 5754d53d9efc..9e22526e80e7 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -89,8 +89,10 @@ static inline void qdisc_run(struct net_device *dev)
__qdisc_run(dev);
}
+extern int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp,
+ struct tcf_result *res);
extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
- struct tcf_result *res);
+ struct tcf_result *res);
/* Calculate maximal size of packet seen by hard_start_xmit
routine of this device.
diff --git a/include/net/rawv6.h b/include/net/rawv6.h
index af8960878ef4..a5819891d525 100644
--- a/include/net/rawv6.h
+++ b/include/net/rawv6.h
@@ -3,6 +3,8 @@
#ifdef __KERNEL__
+#include <net/protocol.h>
+
#define RAWV6_HTABLE_SIZE MAX_INET_PROTOS
extern struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE];
extern rwlock_t raw_v6_lock;
@@ -23,6 +25,13 @@ extern void rawv6_err(struct sock *sk,
int type, int code,
int offset, __be32 info);
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+int rawv6_mh_filter_register(int (*filter)(struct sock *sock,
+ struct sk_buff *skb));
+int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock,
+ struct sk_buff *skb));
+#endif
+
#endif
#endif
diff --git a/include/net/route.h b/include/net/route.h
index 749e4dfe5ff3..f7ce6259f86f 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -62,7 +62,6 @@ struct rtable
unsigned rt_flags;
__u16 rt_type;
- __u16 rt_multipath_alg;
__be32 rt_dst; /* Path destination */
__be32 rt_src; /* Path source */
@@ -136,7 +135,7 @@ static inline void ip_rt_put(struct rtable * rt)
#define IPTOS_RT_MASK (IPTOS_TOS_MASK & ~3)
-extern __u8 ip_tos2prio[16];
+extern const __u8 ip_tos2prio[16];
static inline char rt_tos2priority(u8 tos)
{
diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h
index 3b3d4745618d..3861c05cdf0f 100644
--- a/include/net/rtnetlink.h
+++ b/include/net/rtnetlink.h
@@ -22,4 +22,62 @@ static inline int rtnl_msg_family(struct nlmsghdr *nlh)
return AF_UNSPEC;
}
+/**
+ * struct rtnl_link_ops - rtnetlink link operations
+ *
+ * @list: Used internally
+ * @kind: Identifier
+ * @maxtype: Highest device specific netlink attribute number
+ * @policy: Netlink policy for device specific attribute validation
+ * @validate: Optional validation function for netlink/changelink parameters
+ * @priv_size: sizeof net_device private space
+ * @setup: net_device setup function
+ * @newlink: Function for configuring and registering a new device
+ * @changelink: Function for changing parameters of an existing device
+ * @dellink: Function to remove a device
+ * @get_size: Function to calculate required room for dumping device
+ * specific netlink attributes
+ * @fill_info: Function to dump device specific netlink attributes
+ * @get_xstats_size: Function to calculate required room for dumping devic
+ * specific statistics
+ * @fill_xstats: Function to dump device specific statistics
+ */
+struct rtnl_link_ops {
+ struct list_head list;
+
+ const char *kind;
+
+ size_t priv_size;
+ void (*setup)(struct net_device *dev);
+
+ int maxtype;
+ const struct nla_policy *policy;
+ int (*validate)(struct nlattr *tb[],
+ struct nlattr *data[]);
+
+ int (*newlink)(struct net_device *dev,
+ struct nlattr *tb[],
+ struct nlattr *data[]);
+ int (*changelink)(struct net_device *dev,
+ struct nlattr *tb[],
+ struct nlattr *data[]);
+ void (*dellink)(struct net_device *dev);
+
+ size_t (*get_size)(const struct net_device *dev);
+ int (*fill_info)(struct sk_buff *skb,
+ const struct net_device *dev);
+
+ size_t (*get_xstats_size)(const struct net_device *dev);
+ int (*fill_xstats)(struct sk_buff *skb,
+ const struct net_device *dev);
+};
+
+extern int __rtnl_link_register(struct rtnl_link_ops *ops);
+extern void __rtnl_link_unregister(struct rtnl_link_ops *ops);
+
+extern int rtnl_link_register(struct rtnl_link_ops *ops);
+extern void rtnl_link_unregister(struct rtnl_link_ops *ops);
+
+#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
+
#endif
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 1b8e35197ebe..8a67f24cbe02 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -290,7 +290,7 @@ static inline int qdisc_reshape_fail(struct sk_buff *skb, struct Qdisc *sch)
{
sch->qstats.drops++;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch))
goto drop;
diff --git a/include/net/scm.h b/include/net/scm.h
index 5637d5e22d5f..423cb1d5ac25 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -8,7 +8,7 @@
/* Well, we should have at least one descriptor open
* to accept passed FDs 8)
*/
-#define SCM_MAX_FD (OPEN_MAX-1)
+#define SCM_MAX_FD 255
struct scm_fp_list
{
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a8af9ae00177..8b404b1ef7c8 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -652,8 +652,7 @@ struct tcp_congestion_ops {
/* lower bound for congestion window (optional) */
u32 (*min_cwnd)(const struct sock *sk);
/* do new cwnd calculation (required) */
- void (*cong_avoid)(struct sock *sk, u32 ack,
- u32 rtt, u32 in_flight, int good_ack);
+ void (*cong_avoid)(struct sock *sk, u32 ack, u32 in_flight, int good_ack);
/* call before changing ca_state (optional) */
void (*set_state)(struct sock *sk, u8 new_state);
/* call when cwnd event occurs (optional) */
@@ -684,8 +683,7 @@ extern void tcp_slow_start(struct tcp_sock *tp);
extern struct tcp_congestion_ops tcp_init_congestion_ops;
extern u32 tcp_reno_ssthresh(struct sock *sk);
-extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack,
- u32 rtt, u32 in_flight, int flag);
+extern void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag);
extern u32 tcp_reno_min_cwnd(const struct sock *sk);
extern struct tcp_congestion_ops tcp_reno;
diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h
index 333bba6dc522..cfc4ba46de8f 100644
--- a/include/net/tipc/tipc_port.h
+++ b/include/net/tipc/tipc_port.h
@@ -1,8 +1,8 @@
/*
* include/net/tipc/tipc_port.h: Include file for privileged access to TIPC ports
*
- * Copyright (c) 1994-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 1994-2007, Ericsson AB
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,6 +55,7 @@
* @conn_unacked: number of unacknowledged messages received from peer port
* @published: non-zero if port has one or more associated names
* @congested: non-zero if cannot send because of link or port congestion
+ * @max_pkt: maximum packet size "hint" used when building messages sent by port
* @ref: unique reference to port in TIPC object registry
* @phdr: preformatted message header used when sending messages
*/
@@ -68,6 +69,7 @@ struct tipc_port {
u32 conn_unacked;
int published;
u32 congested;
+ u32 max_pkt;
u32 ref;
struct tipc_msg phdr;
};
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 311f25af5e1a..a5f80bfbaaa4 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -19,9 +19,19 @@
#include <net/ipv6.h>
#include <net/ip6_fib.h>
+#define XFRM_PROTO_ESP 50
+#define XFRM_PROTO_AH 51
+#define XFRM_PROTO_COMP 108
+#define XFRM_PROTO_IPIP 4
+#define XFRM_PROTO_IPV6 41
+#define XFRM_PROTO_ROUTING IPPROTO_ROUTING
+#define XFRM_PROTO_DSTOPTS IPPROTO_DSTOPTS
+
#define XFRM_ALIGN8(len) (((len) + 7) & ~7)
#define MODULE_ALIAS_XFRM_MODE(family, encap) \
MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap))
+#define MODULE_ALIAS_XFRM_TYPE(family, proto) \
+ MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto))
extern struct sock *xfrm_nl;
extern u32 sysctl_xfrm_aevent_etime;
@@ -509,11 +519,9 @@ __be16 xfrm_flowi_sport(struct flowi *fl)
case IPPROTO_ICMPV6:
port = htons(fl->fl_icmp_type);
break;
-#ifdef CONFIG_IPV6_MIP6
case IPPROTO_MH:
port = htons(fl->fl_mh_type);
break;
-#endif
default:
port = 0; /*XXX*/
}
@@ -577,7 +585,6 @@ static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ct
struct xfrm_dst
{
union {
- struct xfrm_dst *next;
struct dst_entry dst;
struct rtable rt;
struct rt6_info rt6;
@@ -920,6 +927,10 @@ extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t
struct flowi *fl, struct xfrm_tmpl *tmpl,
struct xfrm_policy *pol, int *err,
unsigned short family);
+extern struct xfrm_state * xfrm_stateonly_find(xfrm_address_t *daddr,
+ xfrm_address_t *saddr,
+ unsigned short family,
+ u8 mode, u8 proto, u32 reqid);
extern int xfrm_state_check_expire(struct xfrm_state *x);
extern void xfrm_state_insert(struct xfrm_state *x);
extern int xfrm_state_add(struct xfrm_state *x);
@@ -991,7 +1002,7 @@ extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
u8 **prevhdr);
#ifdef CONFIG_XFRM
-extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
+extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb);
extern int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen);
extern int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family);
#else
@@ -1000,12 +1011,13 @@ static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optv
return -ENOPROTOOPT;
}
-static inline int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
+static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
{
/* should not happen */
kfree_skb(skb);
return 0;
}
+
static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsigned short family)
{
return -EINVAL;
diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h
index 5c070176d9ab..12243e80c706 100644
--- a/include/rdma/ib_cm.h
+++ b/include/rdma/ib_cm.h
@@ -385,7 +385,6 @@ struct ib_cm_rep_param {
u8 private_data_len;
u8 responder_resources;
u8 initiator_depth;
- u8 target_ack_delay;
u8 failover_accepted;
u8 flow_control;
u8 rnr_retry_count;
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h
index 739fa4d0e539..30712ddd8a5e 100644
--- a/include/rdma/ib_mad.h
+++ b/include/rdma/ib_mad.h
@@ -111,6 +111,9 @@
#define IB_QP1_QKEY 0x80010000
#define IB_QP_SET_QKEY 0x80000000
+#define IB_DEFAULT_PKEY_PARTIAL 0x7FFF
+#define IB_DEFAULT_PKEY_FULL 0xFFFF
+
enum {
IB_MGMT_MAD_HDR = 24,
IB_MGMT_MAD_DATA = 232,
diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h
index 55ebf035e620..50e907f42048 100644
--- a/include/scsi/iscsi_if.h
+++ b/include/scsi/iscsi_if.h
@@ -48,6 +48,7 @@ enum iscsi_uevent_e {
ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14,
ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15,
+ ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16,
/* up events */
ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1,
@@ -71,6 +72,8 @@ struct iscsi_uevent {
/* messages u -> k */
struct msg_create_session {
uint32_t initial_cmdsn;
+ uint16_t cmds_max;
+ uint16_t queue_depth;
} c_session;
struct msg_destroy_session {
uint32_t sid;
@@ -136,6 +139,11 @@ struct iscsi_uevent {
*/
uint32_t enable;
} tgt_dscvr;
+ struct msg_set_host_param {
+ uint32_t host_no;
+ uint32_t param; /* enum iscsi_host_param */
+ uint32_t len;
+ } set_host_param;
} u;
union {
/* messages k -> u */
@@ -223,6 +231,11 @@ enum iscsi_param {
ISCSI_PARAM_CONN_PORT,
ISCSI_PARAM_CONN_ADDRESS,
+ ISCSI_PARAM_USERNAME,
+ ISCSI_PARAM_USERNAME_IN,
+ ISCSI_PARAM_PASSWORD,
+ ISCSI_PARAM_PASSWORD_IN,
+
/* must always be last */
ISCSI_PARAM_MAX,
};
@@ -249,6 +262,24 @@ enum iscsi_param {
#define ISCSI_SESS_RECOVERY_TMO (1 << ISCSI_PARAM_SESS_RECOVERY_TMO)
#define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT)
#define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS)
+#define ISCSI_USERNAME (1 << ISCSI_PARAM_USERNAME)
+#define ISCSI_USERNAME_IN (1 << ISCSI_PARAM_USERNAME_IN)
+#define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD)
+#define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN)
+
+/* iSCSI HBA params */
+enum iscsi_host_param {
+ ISCSI_HOST_PARAM_HWADDRESS,
+ ISCSI_HOST_PARAM_INITIATOR_NAME,
+ ISCSI_HOST_PARAM_NETDEV_NAME,
+ ISCSI_HOST_PARAM_IPADDRESS,
+ ISCSI_HOST_PARAM_MAX,
+};
+
+#define ISCSI_HOST_HWADDRESS (1 << ISCSI_HOST_PARAM_HWADDRESS)
+#define ISCSI_HOST_INITIATOR_NAME (1 << ISCSI_HOST_PARAM_INITIATOR_NAME)
+#define ISCSI_HOST_NETDEV_NAME (1 << ISCSI_HOST_PARAM_NETDEV_NAME)
+#define ISCSI_HOST_IPADDRESS (1 << ISCSI_HOST_PARAM_IPADDRESS)
#define iscsi_ptr(_handle) ((void*)(unsigned long)_handle)
#define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr)
@@ -272,6 +303,9 @@ enum iscsi_param {
#define CAP_MULTI_CONN 0x40
#define CAP_TEXT_NEGO 0x80
#define CAP_MARKERS 0x100
+#define CAP_FW_DB 0x200
+#define CAP_SENDTARGETS_OFFLOAD 0x400
+#define CAP_DATA_PATH_OFFLOAD 0x800
/*
* These flags describes reason of stop_conn() call
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index ea0816d4904d..3f631b08a1ab 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -48,9 +48,8 @@ struct iscsi_nopin;
#define debug_scsi(fmt...)
#endif
-#define ISCSI_XMIT_CMDS_MAX 128 /* must be power of 2 */
-#define ISCSI_MGMT_CMDS_MAX 32 /* must be power of 2 */
-#define ISCSI_CONN_MAX 1
+#define ISCSI_DEF_XMIT_CMDS_MAX 128 /* must be power of 2 */
+#define ISCSI_MGMT_CMDS_MAX 16 /* must be power of 2 */
#define ISCSI_MGMT_ITT_OFFSET 0xa00
@@ -73,6 +72,8 @@ struct iscsi_nopin;
#define ISCSI_AGE_SHIFT 28
#define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT)
+#define ISCSI_ADDRESS_BUF_LEN 64
+
struct iscsi_mgmt_task {
/*
* Becuae LLDs allocate their hdr differently, this is a pointer to
@@ -80,7 +81,7 @@ struct iscsi_mgmt_task {
*/
struct iscsi_hdr *hdr;
char *data; /* mgmt payload */
- int data_count; /* counts data to be sent */
+ unsigned data_count; /* counts data to be sent */
uint32_t itt; /* this ITT */
void *dd_data; /* driver/transport data */
struct list_head running;
@@ -90,6 +91,7 @@ enum {
ISCSI_TASK_COMPLETED,
ISCSI_TASK_PENDING,
ISCSI_TASK_RUNNING,
+ ISCSI_TASK_ABORTING,
};
struct iscsi_cmd_task {
@@ -99,16 +101,14 @@ struct iscsi_cmd_task {
*/
struct iscsi_cmd *hdr;
int itt; /* this ITT */
- int datasn; /* DataSN */
uint32_t unsol_datasn;
- int imm_count; /* imm-data (bytes) */
- int unsol_count; /* unsolicited (bytes)*/
+ unsigned imm_count; /* imm-data (bytes) */
+ unsigned unsol_count; /* unsolicited (bytes)*/
/* offset in unsolicited stream (bytes); */
- int unsol_offset;
- int data_count; /* remaining Data-Out */
+ unsigned unsol_offset;
+ unsigned data_count; /* remaining Data-Out */
struct scsi_cmnd *sc; /* associated SCSI cmd*/
- int total_length;
struct iscsi_conn *conn; /* used connection */
struct iscsi_mgmt_task *mtask; /* tmf mtask in progr */
@@ -152,18 +152,11 @@ struct iscsi_conn {
struct iscsi_cmd_task *ctask; /* xmit ctask in progress */
/* xmit */
- struct kfifo *immqueue; /* immediate xmit queue */
struct kfifo *mgmtqueue; /* mgmt (control) xmit queue */
struct list_head mgmt_run_list; /* list of control tasks */
struct list_head xmitqueue; /* data-path cmd queue */
struct list_head run_list; /* list of cmds in progress */
struct work_struct xmitwork; /* per-conn. xmit workqueue */
- /*
- * serializes connection xmit, access to kfifos:
- * xmitqueue, immqueue, mgmtqueue
- */
- struct mutex xmitmutex;
-
unsigned long suspend_tx; /* suspend Tx */
unsigned long suspend_rx; /* suspend Rx */
@@ -174,8 +167,8 @@ struct iscsi_conn {
int tmabort_state; /* see TMABORT_INITIAL, etc.*/
/* negotiated params */
- int max_recv_dlength; /* initiator_max_recv_dsl*/
- int max_xmit_dlength; /* target_max_recv_dsl */
+ unsigned max_recv_dlength; /* initiator_max_recv_dsl*/
+ unsigned max_xmit_dlength; /* target_max_recv_dsl */
int hdrdgst_en;
int datadgst_en;
int ifmarker_en;
@@ -183,6 +176,12 @@ struct iscsi_conn {
/* values userspace uses to id a conn */
int persistent_port;
char *persistent_address;
+ /* remote portal currently connected to */
+ int portal_port;
+ char portal_address[ISCSI_ADDRESS_BUF_LEN];
+ /* local address */
+ int local_port;
+ char local_address[ISCSI_ADDRESS_BUF_LEN];
/* MIB-statistics */
uint64_t txdata_octets;
@@ -213,18 +212,25 @@ struct iscsi_session {
/* configuration */
int initial_r2t_en;
- int max_r2t;
+ unsigned max_r2t;
int imm_data_en;
- int first_burst;
- int max_burst;
+ unsigned first_burst;
+ unsigned max_burst;
int time2wait;
int time2retain;
int pdu_inorder_en;
int dataseq_inorder_en;
int erl;
int tpgt;
+ char *username;
+ char *username_in;
+ char *password;
+ char *password_in;
char *targetname;
-
+ char *initiatorname;
+ /* hw address or netdev iscsi connection is bound to */
+ char *hwaddress;
+ char *netdev;
/* control data */
struct iscsi_transport *tt;
struct Scsi_Host *host;
@@ -255,12 +261,22 @@ extern int iscsi_eh_host_reset(struct scsi_cmnd *sc);
extern int iscsi_queuecommand(struct scsi_cmnd *sc,
void (*done)(struct scsi_cmnd *));
+
+/*
+ * iSCSI host helpers.
+ */
+extern int iscsi_host_set_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf,
+ int buflen);
+extern int iscsi_host_get_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+
/*
* session management
*/
extern struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *,
- int, int, uint32_t, uint32_t *);
+ uint16_t, uint16_t, int, int, uint32_t, uint32_t *);
extern void iscsi_session_teardown(struct iscsi_cls_session *);
extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *);
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
@@ -289,8 +305,7 @@ extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
/*
* pdu and task processing
*/
-extern int iscsi_check_assign_cmdsn(struct iscsi_session *,
- struct iscsi_nopin *);
+extern void iscsi_update_cmdsn(struct iscsi_session *, struct iscsi_nopin *);
extern void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *,
struct iscsi_data *hdr);
extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *,
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index 2e6bdc4e7a0a..df36461fe881 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -30,6 +30,7 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <scsi/sas.h>
+#include <linux/libata.h>
#include <linux/list.h>
#include <asm/semaphore.h>
#include <scsi/scsi_device.h>
@@ -165,6 +166,13 @@ struct sata_device {
u8 port_no; /* port number, if this is a PM (Port) */
struct list_head children; /* PM Ports if this is a PM */
+
+ struct ata_port *ap;
+ struct ata_host ata_host;
+ struct ata_taskfile tf;
+ u32 sstatus;
+ u32 serror;
+ u32 scontrol;
};
/* ---------- Domain device ---------- */
@@ -624,6 +632,7 @@ int sas_set_phy_speed(struct sas_phy *phy,
struct sas_phy_linkrates *rates);
int sas_phy_enable(struct sas_phy *phy, int enabled);
int sas_phy_reset(struct sas_phy *phy, int hard_reset);
+int sas_queue_up(struct sas_task *task);
extern int sas_queuecommand(struct scsi_cmnd *,
void (*scsi_done)(struct scsi_cmnd *));
extern int sas_target_alloc(struct scsi_target *);
@@ -661,4 +670,10 @@ int __sas_task_abort(struct sas_task *);
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd);
int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd);
+extern void sas_target_destroy(struct scsi_target *);
+extern int sas_slave_alloc(struct scsi_device *);
+extern int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg);
+
+extern int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+ struct request *req);
#endif /* _SASLIB_H_ */
diff --git a/include/scsi/sas_ata.h b/include/scsi/sas_ata.h
new file mode 100644
index 000000000000..dd5edc915417
--- /dev/null
+++ b/include/scsi/sas_ata.h
@@ -0,0 +1,60 @@
+/*
+ * Support for SATA devices on Serial Attached SCSI (SAS) controllers
+ *
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Written by: Darrick J. Wong <djwong@us.ibm.com>, 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 program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ *
+ */
+
+#ifndef _SAS_ATA_H_
+#define _SAS_ATA_H_
+
+#include <linux/libata.h>
+#include <scsi/libsas.h>
+
+#ifdef CONFIG_SCSI_SAS_ATA
+
+static inline int dev_is_sata(struct domain_device *dev)
+{
+ return (dev->rphy->identify.target_port_protocols & SAS_PROTOCOL_SATA);
+}
+
+int sas_ata_init_host_and_port(struct domain_device *found_dev,
+ struct scsi_target *starget);
+
+void sas_ata_task_abort(struct sas_task *task);
+
+#else
+
+
+static inline int dev_is_sata(struct domain_device *dev)
+{
+ return 0;
+}
+int sas_ata_init_host_and_port(struct domain_device *found_dev,
+ struct scsi_target *starget)
+{
+ return 0;
+}
+void sas_ata_task_abort(struct sas_task *task)
+{
+}
+#endif
+
+#endif /* _SAS_ATA_H_ */
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index a2e0c1032491..53e170586c26 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -135,4 +135,24 @@ extern void scsi_kunmap_atomic_sg(void *virt);
extern struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *, gfp_t);
extern void scsi_free_sgtable(struct scatterlist *, int);
+extern int scsi_dma_map(struct scsi_cmnd *cmd);
+extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
+
+#define scsi_sg_count(cmd) ((cmd)->use_sg)
+#define scsi_sglist(cmd) ((struct scatterlist *)(cmd)->request_buffer)
+#define scsi_bufflen(cmd) ((cmd)->request_bufflen)
+
+static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid)
+{
+ cmd->resid = resid;
+}
+
+static inline int scsi_get_resid(struct scsi_cmnd *cmd)
+{
+ return cmd->resid;
+}
+
+#define scsi_for_each_sg(cmd, sg, nseg, __i) \
+ for (__i = 0, sg = scsi_sglist(cmd); __i < (nseg); __i++, (sg)++)
+
#endif /* _SCSI_SCSI_CMND_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 2f3c5b8b1d6a..d5057bc338ff 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -209,7 +209,6 @@ extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
extern int scsi_add_device(struct Scsi_Host *host, uint channel,
uint target, uint lun);
extern void scsi_remove_device(struct scsi_device *);
-extern int scsi_device_cancel(struct scsi_device *, int);
extern int scsi_device_get(struct scsi_device *);
extern void scsi_device_put(struct scsi_device *);
@@ -287,6 +286,7 @@ extern void scsi_target_block(struct device *);
extern void scsi_target_unblock(struct device *);
extern void scsi_remove_target(struct device *);
extern void int_to_scsilun(unsigned int, struct scsi_lun *);
+extern int scsilun_to_int(struct scsi_lun *);
extern const char *scsi_device_state_name(enum scsi_device_state);
extern int scsi_is_sdev_device(const struct device *);
extern int scsi_is_target_device(const struct device *);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 68f461b7a835..3b8a6a85c2f8 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -339,15 +339,9 @@ struct scsi_host_template {
enum scsi_eh_timer_return (* eh_timed_out)(struct scsi_cmnd *);
/*
- * suspend support
- */
- int (*resume)(struct scsi_device *);
- int (*suspend)(struct scsi_device *, pm_message_t state);
-
- /*
* Name of proc directory
*/
- char *proc_name;
+ const char *proc_name;
/*
* Used to store the procfs directory if a driver implements the
@@ -677,6 +671,10 @@ struct Scsi_Host {
#define shost_printk(prefix, shost, fmt, a...) \
dev_printk(prefix, &(shost)->shost_gendev, fmt, ##a)
+static inline void *shost_priv(struct Scsi_Host *shost)
+{
+ return (void *)shost->hostdata;
+}
int scsi_is_host_device(const struct device *);
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index 1e797308640a..a0d80bcaa93d 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -1,4 +1,4 @@
-/*
+/*
* FiberChannel transport specific attributes exported to sysfs.
*
* Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved.
@@ -19,7 +19,7 @@
*
* ========
*
- * Copyright (C) 2004-2005 James Smart, Emulex Corporation
+ * Copyright (C) 2004-2007 James Smart, Emulex Corporation
* Rewrite for host, target, device, and remote port attributes,
* statistics, and service functions...
*
@@ -62,8 +62,10 @@ enum fc_port_type {
FC_PORTTYPE_NLPORT, /* (Public) Loop w/ FLPort */
FC_PORTTYPE_LPORT, /* (Private) Loop w/o FLPort */
FC_PORTTYPE_PTP, /* Point to Point w/ another NPort */
+ FC_PORTTYPE_NPIV, /* VPORT based on NPIV */
};
+
/*
* fc_port_state: If you alter this, you also need to alter scsi_transport_fc.c
* (for the ascii descriptions).
@@ -83,7 +85,26 @@ enum fc_port_state {
};
-/*
+/*
+ * fc_vport_state: If you alter this, you also need to alter
+ * scsi_transport_fc.c (for the ascii descriptions).
+ */
+enum fc_vport_state {
+ FC_VPORT_UNKNOWN,
+ FC_VPORT_ACTIVE,
+ FC_VPORT_DISABLED,
+ FC_VPORT_LINKDOWN,
+ FC_VPORT_INITIALIZING,
+ FC_VPORT_NO_FABRIC_SUPP,
+ FC_VPORT_NO_FABRIC_RSCS,
+ FC_VPORT_FABRIC_LOGOUT,
+ FC_VPORT_FABRIC_REJ_WWN,
+ FC_VPORT_FAILED,
+};
+
+
+
+/*
* FC Classes of Service
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report supported_classes). If you alter this list,
@@ -96,7 +117,7 @@ enum fc_port_state {
#define FC_COS_CLASS4 0x10
#define FC_COS_CLASS6 0x40
-/*
+/*
* FC Port Speeds
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report supported_speeds). If you alter this list,
@@ -124,16 +145,114 @@ enum fc_tgtid_binding_type {
};
/*
- * FC Remote Port Roles
+ * FC Port Roles
* Note: values are not enumerated, as they can be "or'd" together
* for reporting (e.g. report roles). If you alter this list,
* you also need to alter scsi_transport_fc.c (for the ascii descriptions).
*/
-#define FC_RPORT_ROLE_UNKNOWN 0x00
-#define FC_RPORT_ROLE_FCP_TARGET 0x01
-#define FC_RPORT_ROLE_FCP_INITIATOR 0x02
-#define FC_RPORT_ROLE_IP_PORT 0x04
+#define FC_PORT_ROLE_UNKNOWN 0x00
+#define FC_PORT_ROLE_FCP_TARGET 0x01
+#define FC_PORT_ROLE_FCP_INITIATOR 0x02
+#define FC_PORT_ROLE_IP_PORT 0x04
+
+/* The following are for compatibility */
+#define FC_RPORT_ROLE_UNKNOWN FC_PORT_ROLE_UNKNOWN
+#define FC_RPORT_ROLE_FCP_TARGET FC_PORT_ROLE_FCP_TARGET
+#define FC_RPORT_ROLE_FCP_INITIATOR FC_PORT_ROLE_FCP_INITIATOR
+#define FC_RPORT_ROLE_IP_PORT FC_PORT_ROLE_IP_PORT
+
+
+/* Macro for use in defining Virtual Port attributes */
+#define FC_VPORT_ATTR(_name,_mode,_show,_store) \
+struct class_device_attribute class_device_attr_vport_##_name = \
+ __ATTR(_name,_mode,_show,_store)
+
+
+/*
+ * FC Virtual Port Attributes
+ *
+ * This structure exists for each FC port is a virtual FC port. Virtual
+ * ports share the physical link with the Physical port. Each virtual
+ * ports has a unique presense on the SAN, and may be instantiated via
+ * NPIV, Virtual Fabrics, or via additional ALPAs. As the vport is a
+ * unique presense, each vport has it's own view of the fabric,
+ * authentication priviledge, and priorities.
+ *
+ * A virtual port may support 1 or more FC4 roles. Typically it is a
+ * FCP Initiator. It could be a FCP Target, or exist sole for an IP over FC
+ * roles. FC port attributes for the vport will be reported on any
+ * fc_host class object allocated for an FCP Initiator.
+ *
+ * --
+ *
+ * Fixed attributes are not expected to change. The driver is
+ * expected to set these values after receiving the fc_vport structure
+ * via the vport_create() call from the transport.
+ * The transport fully manages all get functions w/o driver interaction.
+ *
+ * Dynamic attributes are expected to change. The driver participates
+ * in all get/set operations via functions provided by the driver.
+ *
+ * Private attributes are transport-managed values. They are fully
+ * managed by the transport w/o driver interaction.
+ */
+#define FC_VPORT_SYMBOLIC_NAMELEN 64
+struct fc_vport {
+ /* Fixed Attributes */
+
+ /* Dynamic Attributes */
+
+ /* Private (Transport-managed) Attributes */
+ enum fc_vport_state vport_state;
+ enum fc_vport_state vport_last_state;
+ u64 node_name;
+ u64 port_name;
+ u32 roles;
+ u32 vport_id; /* Admin Identifier for the vport */
+ enum fc_port_type vport_type;
+ char symbolic_name[FC_VPORT_SYMBOLIC_NAMELEN];
+
+ /* exported data */
+ void *dd_data; /* Used for driver-specific storage */
+
+ /* internal data */
+ struct Scsi_Host *shost; /* Physical Port Parent */
+ unsigned int channel;
+ u32 number;
+ u8 flags;
+ struct list_head peers;
+ struct device dev;
+ struct work_struct vport_delete_work;
+} __attribute__((aligned(sizeof(unsigned long))));
+
+/* bit field values for struct fc_vport "flags" field: */
+#define FC_VPORT_CREATING 0x01
+#define FC_VPORT_DELETING 0x02
+#define FC_VPORT_DELETED 0x04
+#define FC_VPORT_DEL 0x06 /* Any DELETE state */
+
+#define dev_to_vport(d) \
+ container_of(d, struct fc_vport, dev)
+#define transport_class_to_vport(classdev) \
+ dev_to_vport(classdev->dev)
+#define vport_to_shost(v) \
+ (v->shost)
+#define vport_to_shost_channel(v) \
+ (v->channel)
+#define vport_to_parent(v) \
+ (v->dev.parent)
+
+
+/* Error return codes for vport_create() callback */
+#define VPCERR_UNSUPPORTED -ENOSYS /* no driver/adapter
+ support */
+#define VPCERR_BAD_WWN -ENOTUNIQ /* driver validation
+ of WWNs failed */
+#define VPCERR_NO_FABRIC_SUPP -EOPNOTSUPP /* Fabric connection
+ is loop or the
+ Fabric Port does
+ not support NPIV */
/*
* fc_rport_identifiers: This set of data contains all elements
@@ -149,6 +268,7 @@ struct fc_rport_identifiers {
u32 roles;
};
+
/* Macro for use in defining Remote Port attributes */
#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
struct class_device_attribute class_device_attr_rport_##_name = \
@@ -278,7 +398,7 @@ struct fc_host_statistics {
u64 prim_seq_protocol_err_count;
u64 invalid_tx_word_count;
u64 invalid_crc_count;
-
+
/* fc4 statistics (only FCP supported currently) */
u64 fcp_input_requests;
u64 fcp_output_requests;
@@ -343,6 +463,7 @@ struct fc_host_attrs {
u8 supported_fc4s[FC_FC4_LIST_SIZE];
u32 supported_speeds;
u32 maxframe_size;
+ u16 max_npiv_vports;
char serial_number[FC_SERIAL_NUMBER_SIZE];
/* Dynamic Attributes */
@@ -361,8 +482,11 @@ struct fc_host_attrs {
/* internal data */
struct list_head rports;
struct list_head rport_bindings;
+ struct list_head vports;
u32 next_rport_number;
u32 next_target_id;
+ u32 next_vport_number;
+ u16 npiv_vports_inuse;
/* work queues for rport state manipulation */
char work_q_name[KOBJ_NAME_LEN];
@@ -388,6 +512,8 @@ struct fc_host_attrs {
(((struct fc_host_attrs *)(x)->shost_data)->supported_speeds)
#define fc_host_maxframe_size(x) \
(((struct fc_host_attrs *)(x)->shost_data)->maxframe_size)
+#define fc_host_max_npiv_vports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->max_npiv_vports)
#define fc_host_serial_number(x) \
(((struct fc_host_attrs *)(x)->shost_data)->serial_number)
#define fc_host_port_id(x) \
@@ -412,10 +538,16 @@ struct fc_host_attrs {
(((struct fc_host_attrs *)(x)->shost_data)->rports)
#define fc_host_rport_bindings(x) \
(((struct fc_host_attrs *)(x)->shost_data)->rport_bindings)
+#define fc_host_vports(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->vports)
#define fc_host_next_rport_number(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
#define fc_host_next_target_id(x) \
(((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
+#define fc_host_next_vport_number(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->next_vport_number)
+#define fc_host_npiv_vports_inuse(x) \
+ (((struct fc_host_attrs *)(x)->shost_data)->npiv_vports_inuse)
#define fc_host_work_q_name(x) \
(((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
#define fc_host_work_q(x) \
@@ -452,14 +584,20 @@ struct fc_function_template {
void (*dev_loss_tmo_callbk)(struct fc_rport *);
void (*terminate_rport_io)(struct fc_rport *);
+ void (*set_vport_symbolic_name)(struct fc_vport *);
+ int (*vport_create)(struct fc_vport *, bool);
+ int (*vport_disable)(struct fc_vport *, bool);
+ int (*vport_delete)(struct fc_vport *);
+
/* allocation lengths for host-specific data */
u32 dd_fcrport_size;
+ u32 dd_fcvport_size;
- /*
+ /*
* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
* is not set, the attribute will be private to the transport
- * class
+ * class
*/
/* remote port fixed attributes */
@@ -512,7 +650,7 @@ fc_remote_port_chkready(struct fc_rport *rport)
switch (rport->port_state) {
case FC_PORTSTATE_ONLINE:
- if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ if (rport->roles & FC_PORT_ROLE_FCP_TARGET)
result = 0;
else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
result = DID_IMM_RETRY << 16;
@@ -549,6 +687,27 @@ static inline void u64_to_wwn(u64 inm, u8 *wwn)
wwn[7] = inm & 0xff;
}
+/**
+ * fc_vport_set_state() - called to set a vport's state. Saves the old state,
+ * excepting the transitory states of initializing and sending the ELS
+ * traffic to instantiate the vport on the link.
+ *
+ * Assumes the driver has surrounded this with the proper locking to ensure
+ * a coherent state change.
+ *
+ * @vport: virtual port whose state is changing
+ * @new_state: new state
+ **/
+static inline void
+fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
+{
+ if ((new_state != FC_VPORT_UNKNOWN) &&
+ (new_state != FC_VPORT_INITIALIZING))
+ vport->vport_last_state = vport->vport_state;
+ vport->vport_state = new_state;
+}
+
+
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
void fc_release_transport(struct scsi_transport_template *);
@@ -567,5 +726,6 @@ void fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
* be sure to read the Vendor Type and ID formatting requirements
* specified in scsi_netlink.h
*/
+int fc_vport_terminate(struct fc_vport *vport);
#endif /* SCSI_TRANSPORT_FC_H */
diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h
index d5c218ddc527..706c0cd36c14 100644
--- a/include/scsi/scsi_transport_iscsi.h
+++ b/include/scsi/scsi_transport_iscsi.h
@@ -79,7 +79,8 @@ struct iscsi_transport {
char *name;
unsigned int caps;
/* LLD sets this to indicate what values it can export to sysfs */
- unsigned int param_mask;
+ uint64_t param_mask;
+ uint64_t host_param_mask;
struct scsi_host_template *host_template;
/* LLD connection data size */
int conndata_size;
@@ -89,7 +90,8 @@ struct iscsi_transport {
unsigned int max_conn;
unsigned int max_cmd_len;
struct iscsi_cls_session *(*create_session) (struct iscsi_transport *it,
- struct scsi_transport_template *t, uint32_t sn, uint32_t *hn);
+ struct scsi_transport_template *t, uint16_t, uint16_t,
+ uint32_t sn, uint32_t *hn);
void (*destroy_session) (struct iscsi_cls_session *session);
struct iscsi_cls_conn *(*create_conn) (struct iscsi_cls_session *sess,
uint32_t cid);
@@ -105,14 +107,18 @@ struct iscsi_transport {
enum iscsi_param param, char *buf);
int (*get_session_param) (struct iscsi_cls_session *session,
enum iscsi_param param, char *buf);
+ int (*get_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+ int (*set_host_param) (struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf,
+ int buflen);
int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
char *data, uint32_t data_size);
void (*get_stats) (struct iscsi_cls_conn *conn,
struct iscsi_stats *stats);
void (*init_cmd_task) (struct iscsi_cmd_task *ctask);
void (*init_mgmt_task) (struct iscsi_conn *conn,
- struct iscsi_mgmt_task *mtask,
- char *data, uint32_t data_size);
+ struct iscsi_mgmt_task *mtask);
int (*xmit_cmd_task) (struct iscsi_conn *conn,
struct iscsi_cmd_task *ctask);
void (*cleanup_cmd_task) (struct iscsi_conn *conn,
@@ -124,7 +130,7 @@ struct iscsi_transport {
uint64_t *ep_handle);
int (*ep_poll) (uint64_t ep_handle, int timeout_ms);
void (*ep_disconnect) (uint64_t ep_handle);
- int (*tgt_dscvr) (enum iscsi_tgt_dscvr type, uint32_t host_no,
+ int (*tgt_dscvr) (struct Scsi_Host *shost, enum iscsi_tgt_dscvr type,
uint32_t enable, struct sockaddr *dst_addr);
};
diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h
index 9aedc19820b0..abdfd2e27dd7 100644
--- a/include/scsi/scsi_transport_sas.h
+++ b/include/scsi/scsi_transport_sas.h
@@ -7,7 +7,7 @@
struct scsi_transport_template;
struct sas_rphy;
-
+struct request;
enum sas_device_type {
SAS_PHY_UNUSED,
@@ -23,6 +23,12 @@ enum sas_protocol {
SAS_PROTOCOL_SSP = 0x08,
};
+static inline int sas_protocol_ata(enum sas_protocol proto)
+{
+ return ((proto & SAS_PROTOCOL_SATA) ||
+ (proto & SAS_PROTOCOL_STP))? 1 : 0;
+}
+
enum sas_linkrate {
/* These Values are defined in the SAS standard */
SAS_LINK_RATE_UNKNOWN = 0,
@@ -85,10 +91,12 @@ struct sas_phy {
#define phy_to_shost(phy) \
dev_to_shost((phy)->dev.parent)
+struct request_queue;
struct sas_rphy {
struct device dev;
struct sas_identify identify;
struct list_head list;
+ struct request_queue *q;
u32 scsi_target_id;
};
@@ -166,6 +174,7 @@ struct sas_function_template {
int (*phy_reset)(struct sas_phy *, int);
int (*phy_enable)(struct sas_phy *, int);
int (*set_phy_speed)(struct sas_phy *, struct sas_phy_linkrates *);
+ int (*smp_handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
};
diff --git a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h
index aa49dda4f410..fd0a6c46f497 100644
--- a/include/sound/ak4xxx-adda.h
+++ b/include/sound/ak4xxx-adda.h
@@ -43,6 +43,7 @@ struct snd_ak4xxx_ops {
struct snd_akm4xxx_dac_channel {
char *name; /* mixer volume name */
unsigned int num_channels;
+ char *switch_name; /* mixer switch*/
};
/* ADC labels and channels */
diff --git a/include/sound/cs46xx.h b/include/sound/cs46xx.h
index 685928e6f65a..353910ce9755 100644
--- a/include/sound/cs46xx.h
+++ b/include/sound/cs46xx.h
@@ -1723,6 +1723,10 @@ struct snd_cs46xx {
struct snd_cs46xx_pcm *playback_pcm;
unsigned int play_ctl;
#endif
+
+#ifdef CONFIG_PM
+ u32 *saved_regs;
+#endif
};
int snd_cs46xx_create(struct snd_card *card,
diff --git a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h
index da934def31e9..d9da9e59cf37 100644
--- a/include/sound/cs46xx_dsp_spos.h
+++ b/include/sound/cs46xx_dsp_spos.h
@@ -107,6 +107,7 @@ struct dsp_scb_descriptor {
char scb_name[DSP_MAX_SCB_NAME];
u32 address;
int index;
+ u32 *data;
struct dsp_scb_descriptor * sub_list_ptr;
struct dsp_scb_descriptor * next_scb_ptr;
@@ -127,6 +128,7 @@ struct dsp_task_descriptor {
int size;
u32 address;
int index;
+ u32 *data;
};
struct dsp_pcm_channel_descriptor {
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 23e45a4cf0e4..529d0a564367 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1120,6 +1120,16 @@
/************************************************************************************************/
/* EMU1010m HANA Destinations */
/************************************************************************************************/
+/* 32-bit destinations of signal in the Hana FPGA. Destinations are either
+ * physical outputs of Hana, or outputs going to Alice2 (audigy) for capture
+ * - 16 x EMU_DST_ALICE2_EMU32_X.
+ */
+/* EMU32 = 32-bit serial channel between Alice2 (audigy) and Hana (FPGA) */
+/* EMU_DST_ALICE2_EMU32_X - data channels from Hana to Alice2 used for capture.
+ * Which data is fed into a EMU_DST_ALICE2_EMU32_X channel in Hana depends on
+ * setup of mixer control for each destination - see emumixer.c -
+ * snd_emu1010_output_enum_ctls[], snd_emu1010_input_enum_ctls[]
+ */
#define EMU_DST_ALICE2_EMU32_0 0x000f /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_1 0x0000 /* 16 EMU32 channels to Alice2 +0 to +0xf */
#define EMU_DST_ALICE2_EMU32_2 0x0001 /* 16 EMU32 channels to Alice2 +0 to +0xf */
@@ -1199,6 +1209,12 @@
/************************************************************************************************/
/* EMU1010m HANA Sources */
/************************************************************************************************/
+/* 32-bit sources of signal in the Hana FPGA. The sources are routed to
+ * destinations using mixer control for each destination - see emumixer.c
+ * Sources are either physical inputs of FPGA,
+ * or outputs from Alice (audigy) - 16 x EMU_SRC_ALICE_EMU32A +
+ * 16 x EMU_SRC_ALICE_EMU32B
+ */
#define EMU_SRC_SILENCE 0x0000 /* Silence */
#define EMU_SRC_DOCK_MIC_A1 0x0100 /* Audio Dock Mic A, 1st or 48kHz only */
#define EMU_SRC_DOCK_MIC_A2 0x0101 /* Audio Dock Mic A, 2nd or 96kHz */
diff --git a/include/sound/sb.h b/include/sound/sb.h
index 2dd5c8e5b4fe..3ad854b397d2 100644
--- a/include/sound/sb.h
+++ b/include/sound/sb.h
@@ -38,6 +38,7 @@ enum sb_hw_type {
SB_HW_ALS100, /* Avance Logic ALS100 chip */
SB_HW_ALS4000, /* Avance Logic ALS4000 chip */
SB_HW_DT019X, /* Diamond Tech. DT-019X / Avance Logic ALS-007 */
+ SB_HW_CS5530, /* Cyrix/NatSemi 5530 VSA1 */
};
#define SB_OPEN_PCM 0x01
diff --git a/include/sound/version.h b/include/sound/version.h
index 8e5b2f0f5946..6bbcfefd2c38 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
/* include/version.h. Generated by alsa/ksync script. */
#define CONFIG_SND_VERSION "1.0.14"
-#define CONFIG_SND_DATE " (Thu May 31 09:03:25 2007 UTC)"
+#define CONFIG_SND_DATE " (Fri Jul 20 09:12:58 2007 UTC)"
diff --git a/include/sound/wavefront_fx.h b/include/sound/wavefront_fx.h
deleted file mode 100644
index cec92b141796..000000000000
--- a/include/sound/wavefront_fx.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __SOUND_WAVEFRONT_FX_H
-#define __SOUND_WAVEFRONT_FX_H
-
-extern int snd_wavefront_fx_detect (snd_wavefront_t *);
-extern void snd_wavefront_fx_ioctl (snd_synth_t *sdev,
- unsigned int cmd,
- unsigned long arg);
-
-#endif __SOUND_WAVEFRONT_FX_H
diff --git a/include/video/tgafb.h b/include/video/tgafb.h
index 03d0dbe293a8..7bc5e2c14826 100644
--- a/include/video/tgafb.h
+++ b/include/video/tgafb.h
@@ -216,6 +216,7 @@ struct tga_par {
u32 pll_freq; /* pixclock in mhz */
u32 bits_per_pixel; /* bits per pixel */
u32 sync_on_green; /* set if sync is on green */
+ u32 palette[16];
};
diff --git a/include/xen/events.h b/include/xen/events.h
new file mode 100644
index 000000000000..2bde54d29be5
--- /dev/null
+++ b/include/xen/events.h
@@ -0,0 +1,48 @@
+#ifndef _XEN_EVENTS_H
+#define _XEN_EVENTS_H
+
+#include <linux/interrupt.h>
+
+#include <xen/interface/event_channel.h>
+#include <asm/xen/hypercall.h>
+
+enum ipi_vector {
+ XEN_RESCHEDULE_VECTOR,
+ XEN_CALL_FUNCTION_VECTOR,
+
+ XEN_NR_IPIS,
+};
+
+int bind_evtchn_to_irq(unsigned int evtchn);
+int bind_evtchn_to_irqhandler(unsigned int evtchn,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname,
+ void *dev_id);
+int bind_virq_to_irqhandler(unsigned int virq, unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags, const char *devname,
+ void *dev_id);
+int bind_ipi_to_irqhandler(enum ipi_vector ipi,
+ unsigned int cpu,
+ irq_handler_t handler,
+ unsigned long irqflags,
+ const char *devname,
+ void *dev_id);
+
+/*
+ * Common unbind function for all event sources. Takes IRQ to unbind from.
+ * Automatically closes the underlying event channel (even for bindings
+ * made with bind_evtchn_to_irqhandler()).
+ */
+void unbind_from_irqhandler(unsigned int irq, void *dev_id);
+
+void xen_send_IPI_one(unsigned int cpu, enum ipi_vector vector);
+
+static inline void notify_remote_via_evtchn(int port)
+{
+ struct evtchn_send send = { .port = port };
+ (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
+}
+
+extern void notify_remote_via_irq(int irq);
+#endif /* _XEN_EVENTS_H */
diff --git a/include/xen/features.h b/include/xen/features.h
new file mode 100644
index 000000000000..27292d4d2a6a
--- /dev/null
+++ b/include/xen/features.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * features.h
+ *
+ * Query the features reported by Xen.
+ *
+ * Copyright (c) 2006, Ian Campbell
+ */
+
+#ifndef __XEN_FEATURES_H__
+#define __XEN_FEATURES_H__
+
+#include <xen/interface/features.h>
+
+void xen_setup_features(void);
+
+extern u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
+
+static inline int xen_feature(int flag)
+{
+ return xen_features[flag];
+}
+
+#endif /* __ASM_XEN_FEATURES_H__ */
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
new file mode 100644
index 000000000000..761c83498e03
--- /dev/null
+++ b/include/xen/grant_table.h
@@ -0,0 +1,107 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Two sets of functionality:
+ * 1. Granting foreign access to our memory reservation.
+ * 2. Accessing others' memory reservations via grant references.
+ * (i.e., mechanisms for both sender and recipient of grant references)
+ *
+ * Copyright (c) 2004-2005, K A Fraser
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * 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 __ASM_GNTTAB_H__
+#define __ASM_GNTTAB_H__
+
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/grant_table.h>
+
+/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
+#define NR_GRANT_FRAMES 4
+
+struct gnttab_free_callback {
+ struct gnttab_free_callback *next;
+ void (*fn)(void *);
+ void *arg;
+ u16 count;
+};
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+ int readonly);
+
+/*
+ * End access through the given grant reference, iff the grant entry is no
+ * longer in use. Return 1 if the grant entry was freed, 0 if it is still in
+ * use.
+ */
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
+
+/*
+ * Eventually end access through the given grant reference, and once that
+ * access has been ended, free the given page too. Access will be ended
+ * immediately iff the grant entry is not in use, otherwise it will happen
+ * some time later. page may be 0, in which case no freeing will occur.
+ */
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+ unsigned long page);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
+
+int gnttab_query_foreign_access(grant_ref_t ref);
+
+/*
+ * operations on reserved batches of grant references
+ */
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *pprivate_head);
+
+void gnttab_free_grant_reference(grant_ref_t ref);
+
+void gnttab_free_grant_references(grant_ref_t head);
+
+int gnttab_empty_grant_references(const grant_ref_t *pprivate_head);
+
+int gnttab_claim_grant_reference(grant_ref_t *pprivate_head);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+ grant_ref_t release);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+ void (*fn)(void *), void *arg, u16 count);
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback);
+
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+ unsigned long frame, int readonly);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t, domid_t domid,
+ unsigned long pfn);
+
+#define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
+
+#endif /* __ASM_GNTTAB_H__ */
diff --git a/include/xen/hvc-console.h b/include/xen/hvc-console.h
new file mode 100644
index 000000000000..21c0ecfd786d
--- /dev/null
+++ b/include/xen/hvc-console.h
@@ -0,0 +1,6 @@
+#ifndef XEN_HVC_CONSOLE_H
+#define XEN_HVC_CONSOLE_H
+
+extern struct console xenboot_console;
+
+#endif /* XEN_HVC_CONSOLE_H */
diff --git a/include/xen/interface/elfnote.h b/include/xen/interface/elfnote.h
new file mode 100644
index 000000000000..a64d3df5bd95
--- /dev/null
+++ b/include/xen/interface/elfnote.h
@@ -0,0 +1,133 @@
+/******************************************************************************
+ * elfnote.h
+ *
+ * Definitions used for the Xen ELF notes.
+ *
+ * Copyright (c) 2006, Ian Campbell, XenSource Ltd.
+ */
+
+#ifndef __XEN_PUBLIC_ELFNOTE_H__
+#define __XEN_PUBLIC_ELFNOTE_H__
+
+/*
+ * The notes should live in a SHT_NOTE segment and have "Xen" in the
+ * name field.
+ *
+ * Numeric types are either 4 or 8 bytes depending on the content of
+ * the desc field.
+ *
+ * LEGACY indicated the fields in the legacy __xen_guest string which
+ * this a note type replaces.
+ */
+
+/*
+ * NAME=VALUE pair (string).
+ *
+ * LEGACY: FEATURES and PAE
+ */
+#define XEN_ELFNOTE_INFO 0
+
+/*
+ * The virtual address of the entry point (numeric).
+ *
+ * LEGACY: VIRT_ENTRY
+ */
+#define XEN_ELFNOTE_ENTRY 1
+
+/* The virtual address of the hypercall transfer page (numeric).
+ *
+ * LEGACY: HYPERCALL_PAGE. (n.b. legacy value is a physical page
+ * number not a virtual address)
+ */
+#define XEN_ELFNOTE_HYPERCALL_PAGE 2
+
+/* The virtual address where the kernel image should be mapped (numeric).
+ *
+ * Defaults to 0.
+ *
+ * LEGACY: VIRT_BASE
+ */
+#define XEN_ELFNOTE_VIRT_BASE 3
+
+/*
+ * The offset of the ELF paddr field from the acutal required
+ * psuedo-physical address (numeric).
+ *
+ * This is used to maintain backwards compatibility with older kernels
+ * which wrote __PAGE_OFFSET into that field. This field defaults to 0
+ * if not present.
+ *
+ * LEGACY: ELF_PADDR_OFFSET. (n.b. legacy default is VIRT_BASE)
+ */
+#define XEN_ELFNOTE_PADDR_OFFSET 4
+
+/*
+ * The version of Xen that we work with (string).
+ *
+ * LEGACY: XEN_VER
+ */
+#define XEN_ELFNOTE_XEN_VERSION 5
+
+/*
+ * The name of the guest operating system (string).
+ *
+ * LEGACY: GUEST_OS
+ */
+#define XEN_ELFNOTE_GUEST_OS 6
+
+/*
+ * The version of the guest operating system (string).
+ *
+ * LEGACY: GUEST_VER
+ */
+#define XEN_ELFNOTE_GUEST_VERSION 7
+
+/*
+ * The loader type (string).
+ *
+ * LEGACY: LOADER
+ */
+#define XEN_ELFNOTE_LOADER 8
+
+/*
+ * The kernel supports PAE (x86/32 only, string = "yes" or "no").
+ *
+ * LEGACY: PAE (n.b. The legacy interface included a provision to
+ * indicate 'extended-cr3' support allowing L3 page tables to be
+ * placed above 4G. It is assumed that any kernel new enough to use
+ * these ELF notes will include this and therefore "yes" here is
+ * equivalent to "yes[entended-cr3]" in the __xen_guest interface.
+ */
+#define XEN_ELFNOTE_PAE_MODE 9
+
+/*
+ * The features supported/required by this kernel (string).
+ *
+ * The string must consist of a list of feature names (as given in
+ * features.h, without the "XENFEAT_" prefix) separated by '|'
+ * characters. If a feature is required for the kernel to function
+ * then the feature name must be preceded by a '!' character.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_FEATURES 10
+
+/*
+ * The kernel requires the symbol table to be loaded (string = "yes" or "no")
+ * LEGACY: BSD_SYMTAB (n.b. The legacy treated the presence or absence
+ * of this string as a boolean flag rather than requiring "yes" or
+ * "no".
+ */
+#define XEN_ELFNOTE_BSD_SYMTAB 11
+
+#endif /* __XEN_PUBLIC_ELFNOTE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/include/xen/interface/event_channel.h b/include/xen/interface/event_channel.h
new file mode 100644
index 000000000000..919b5bdcb2bd
--- /dev/null
+++ b/include/xen/interface/event_channel.h
@@ -0,0 +1,195 @@
+/******************************************************************************
+ * event_channel.h
+ *
+ * Event channels between domains.
+ *
+ * Copyright (c) 2003-2004, K A Fraser.
+ */
+
+#ifndef __XEN_PUBLIC_EVENT_CHANNEL_H__
+#define __XEN_PUBLIC_EVENT_CHANNEL_H__
+
+typedef uint32_t evtchn_port_t;
+DEFINE_GUEST_HANDLE(evtchn_port_t);
+
+/*
+ * EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as
+ * accepting interdomain bindings from domain <remote_dom>. A fresh port
+ * is allocated in <dom> and returned as <port>.
+ * NOTES:
+ * 1. If the caller is unprivileged then <dom> must be DOMID_SELF.
+ * 2. <rdom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_alloc_unbound 6
+struct evtchn_alloc_unbound {
+ /* IN parameters */
+ domid_t dom, remote_dom;
+ /* OUT parameters */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
+ * the calling domain and <remote_dom>. <remote_dom,remote_port> must identify
+ * a port that is unbound and marked as accepting bindings from the calling
+ * domain. A fresh port is allocated in the calling domain and returned as
+ * <local_port>.
+ * NOTES:
+ * 2. <remote_dom> may be DOMID_SELF, allowing loopback connections.
+ */
+#define EVTCHNOP_bind_interdomain 0
+struct evtchn_bind_interdomain {
+ /* IN parameters. */
+ domid_t remote_dom;
+ evtchn_port_t remote_port;
+ /* OUT parameters. */
+ evtchn_port_t local_port;
+};
+
+/*
+ * EVTCHNOP_bind_virq: Bind a local event channel to VIRQ <irq> on specified
+ * vcpu.
+ * NOTES:
+ * 1. A virtual IRQ may be bound to at most one event channel per vcpu.
+ * 2. The allocated event channel is bound to the specified vcpu. The binding
+ * may not be changed.
+ */
+#define EVTCHNOP_bind_virq 1
+struct evtchn_bind_virq {
+ /* IN parameters. */
+ uint32_t virq;
+ uint32_t vcpu;
+ /* OUT parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ <irq>.
+ * NOTES:
+ * 1. A physical IRQ may be bound to at most one event channel per domain.
+ * 2. Only a sufficiently-privileged domain may bind to a physical IRQ.
+ */
+#define EVTCHNOP_bind_pirq 2
+struct evtchn_bind_pirq {
+ /* IN parameters. */
+ uint32_t pirq;
+#define BIND_PIRQ__WILL_SHARE 1
+ uint32_t flags; /* BIND_PIRQ__* */
+ /* OUT parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
+ * NOTES:
+ * 1. The allocated event channel is bound to the specified vcpu. The binding
+ * may not be changed.
+ */
+#define EVTCHNOP_bind_ipi 7
+struct evtchn_bind_ipi {
+ uint32_t vcpu;
+ /* OUT parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_close: Close a local event channel <port>. If the channel is
+ * interdomain then the remote end is placed in the unbound state
+ * (EVTCHNSTAT_unbound), awaiting a new connection.
+ */
+#define EVTCHNOP_close 3
+struct evtchn_close {
+ /* IN parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_send: Send an event to the remote end of the channel whose local
+ * endpoint is <port>.
+ */
+#define EVTCHNOP_send 4
+struct evtchn_send {
+ /* IN parameters. */
+ evtchn_port_t port;
+};
+
+/*
+ * EVTCHNOP_status: Get the current status of the communication channel which
+ * has an endpoint at <dom, port>.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may obtain the status of an event
+ * channel for which <dom> is not DOMID_SELF.
+ */
+#define EVTCHNOP_status 5
+struct evtchn_status {
+ /* IN parameters */
+ domid_t dom;
+ evtchn_port_t port;
+ /* OUT parameters */
+#define EVTCHNSTAT_closed 0 /* Channel is not in use. */
+#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/
+#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
+#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
+#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
+#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */
+ uint32_t status;
+ uint32_t vcpu; /* VCPU to which this channel is bound. */
+ union {
+ struct {
+ domid_t dom;
+ } unbound; /* EVTCHNSTAT_unbound */
+ struct {
+ domid_t dom;
+ evtchn_port_t port;
+ } interdomain; /* EVTCHNSTAT_interdomain */
+ uint32_t pirq; /* EVTCHNSTAT_pirq */
+ uint32_t virq; /* EVTCHNSTAT_virq */
+ } u;
+};
+
+/*
+ * EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
+ * event is pending.
+ * NOTES:
+ * 1. IPI- and VIRQ-bound channels always notify the vcpu that initialised
+ * the binding. This binding cannot be changed.
+ * 2. All other channels notify vcpu0 by default. This default is set when
+ * the channel is allocated (a port that is freed and subsequently reused
+ * has its binding reset to vcpu0).
+ */
+#define EVTCHNOP_bind_vcpu 8
+struct evtchn_bind_vcpu {
+ /* IN parameters. */
+ evtchn_port_t port;
+ uint32_t vcpu;
+};
+
+/*
+ * EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
+ * a notification to the appropriate VCPU if an event is pending.
+ */
+#define EVTCHNOP_unmask 9
+struct evtchn_unmask {
+ /* IN parameters. */
+ evtchn_port_t port;
+};
+
+struct evtchn_op {
+ uint32_t cmd; /* EVTCHNOP_* */
+ union {
+ struct evtchn_alloc_unbound alloc_unbound;
+ struct evtchn_bind_interdomain bind_interdomain;
+ struct evtchn_bind_virq bind_virq;
+ struct evtchn_bind_pirq bind_pirq;
+ struct evtchn_bind_ipi bind_ipi;
+ struct evtchn_close close;
+ struct evtchn_send send;
+ struct evtchn_status status;
+ struct evtchn_bind_vcpu bind_vcpu;
+ struct evtchn_unmask unmask;
+ } u;
+};
+DEFINE_GUEST_HANDLE_STRUCT(evtchn_op);
+
+#endif /* __XEN_PUBLIC_EVENT_CHANNEL_H__ */
diff --git a/include/xen/interface/features.h b/include/xen/interface/features.h
new file mode 100644
index 000000000000..d73228d16488
--- /dev/null
+++ b/include/xen/interface/features.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ * features.h
+ *
+ * Feature flags, reported by XENVER_get_features.
+ *
+ * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_FEATURES_H__
+#define __XEN_PUBLIC_FEATURES_H__
+
+/*
+ * If set, the guest does not need to write-protect its pagetables, and can
+ * update them via direct writes.
+ */
+#define XENFEAT_writable_page_tables 0
+
+/*
+ * If set, the guest does not need to write-protect its segment descriptor
+ * tables, and can update them via direct writes.
+ */
+#define XENFEAT_writable_descriptor_tables 1
+
+/*
+ * If set, translation between the guest's 'pseudo-physical' address space
+ * and the host's machine address space are handled by the hypervisor. In this
+ * mode the guest does not need to perform phys-to/from-machine translations
+ * when performing page table operations.
+ */
+#define XENFEAT_auto_translated_physmap 2
+
+/* If set, the guest is running in supervisor mode (e.g., x86 ring 0). */
+#define XENFEAT_supervisor_mode_kernel 3
+
+/*
+ * If set, the guest does not need to allocate x86 PAE page directories
+ * below 4GB. This flag is usually implied by auto_translated_physmap.
+ */
+#define XENFEAT_pae_pgdir_above_4gb 4
+
+#define XENFEAT_NR_SUBMAPS 1
+
+#endif /* __XEN_PUBLIC_FEATURES_H__ */
diff --git a/include/xen/interface/grant_table.h b/include/xen/interface/grant_table.h
new file mode 100644
index 000000000000..219049802cf2
--- /dev/null
+++ b/include/xen/interface/grant_table.h
@@ -0,0 +1,375 @@
+/******************************************************************************
+ * grant_table.h
+ *
+ * Interface for granting foreign access to page frames, and receiving
+ * page-ownership transfers.
+ *
+ * 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) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_GRANT_TABLE_H__
+#define __XEN_PUBLIC_GRANT_TABLE_H__
+
+
+/***********************************
+ * GRANT TABLE REPRESENTATION
+ */
+
+/* Some rough guidelines on accessing and updating grant-table entries
+ * in a concurrency-safe manner. For more information, Linux contains a
+ * reference implementation for guest OSes (arch/xen/kernel/grant_table.c).
+ *
+ * NB. WMB is a no-op on current-generation x86 processors. However, a
+ * compiler barrier will still be required.
+ *
+ * Introducing a valid entry into the grant table:
+ * 1. Write ent->domid.
+ * 2. Write ent->frame:
+ * GTF_permit_access: Frame to which access is permitted.
+ * GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+ * frame, or zero if none.
+ * 3. Write memory barrier (WMB).
+ * 4. Write ent->flags, inc. valid type.
+ *
+ * Invalidating an unused GTF_permit_access entry:
+ * 1. flags = ent->flags.
+ * 2. Observe that !(flags & (GTF_reading|GTF_writing)).
+ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ * NB. No need for WMB as reuse of entry is control-dependent on success of
+ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ *
+ * Invalidating an in-use GTF_permit_access entry:
+ * This cannot be done directly. Request assistance from the domain controller
+ * which can set a timeout on the use of a grant entry and take necessary
+ * action. (NB. This is not yet implemented!).
+ *
+ * Invalidating an unused GTF_accept_transfer entry:
+ * 1. flags = ent->flags.
+ * 2. Observe that !(flags & GTF_transfer_committed). [*]
+ * 3. Check result of SMP-safe CMPXCHG(&ent->flags, flags, 0).
+ * NB. No need for WMB as reuse of entry is control-dependent on success of
+ * step 3, and all architectures guarantee ordering of ctrl-dep writes.
+ * [*] If GTF_transfer_committed is set then the grant entry is 'committed'.
+ * The guest must /not/ modify the grant entry until the address of the
+ * transferred frame is written. It is safe for the guest to spin waiting
+ * for this to occur (detect by observing GTF_transfer_completed in
+ * ent->flags).
+ *
+ * Invalidating a committed GTF_accept_transfer entry:
+ * 1. Wait for (ent->flags & GTF_transfer_completed).
+ *
+ * Changing a GTF_permit_access from writable to read-only:
+ * Use SMP-safe CMPXCHG to set GTF_readonly, while checking !GTF_writing.
+ *
+ * Changing a GTF_permit_access from read-only to writable:
+ * Use SMP-safe bit-setting instruction.
+ */
+
+/*
+ * A grant table comprises a packed array of grant entries in one or more
+ * page frames shared between Xen and a guest.
+ * [XEN]: This field is written by Xen and read by the sharing guest.
+ * [GST]: This field is written by the guest and read by Xen.
+ */
+struct grant_entry {
+ /* GTF_xxx: various type and flag information. [XEN,GST] */
+ uint16_t flags;
+ /* The domain being granted foreign privileges. [GST] */
+ domid_t domid;
+ /*
+ * GTF_permit_access: Frame that @domid is allowed to map and access. [GST]
+ * GTF_accept_transfer: Frame whose ownership transferred by @domid. [XEN]
+ */
+ uint32_t frame;
+};
+
+/*
+ * Type of grant entry.
+ * GTF_invalid: This grant entry grants no privileges.
+ * GTF_permit_access: Allow @domid to map/access @frame.
+ * GTF_accept_transfer: Allow @domid to transfer ownership of one page frame
+ * to this guest. Xen writes the page number to @frame.
+ */
+#define GTF_invalid (0U<<0)
+#define GTF_permit_access (1U<<0)
+#define GTF_accept_transfer (2U<<0)
+#define GTF_type_mask (3U<<0)
+
+/*
+ * Subflags for GTF_permit_access.
+ * GTF_readonly: Restrict @domid to read-only mappings and accesses. [GST]
+ * GTF_reading: Grant entry is currently mapped for reading by @domid. [XEN]
+ * GTF_writing: Grant entry is currently mapped for writing by @domid. [XEN]
+ */
+#define _GTF_readonly (2)
+#define GTF_readonly (1U<<_GTF_readonly)
+#define _GTF_reading (3)
+#define GTF_reading (1U<<_GTF_reading)
+#define _GTF_writing (4)
+#define GTF_writing (1U<<_GTF_writing)
+
+/*
+ * Subflags for GTF_accept_transfer:
+ * GTF_transfer_committed: Xen sets this flag to indicate that it is committed
+ * to transferring ownership of a page frame. When a guest sees this flag
+ * it must /not/ modify the grant entry until GTF_transfer_completed is
+ * set by Xen.
+ * GTF_transfer_completed: It is safe for the guest to spin-wait on this flag
+ * after reading GTF_transfer_committed. Xen will always write the frame
+ * address, followed by ORing this flag, in a timely manner.
+ */
+#define _GTF_transfer_committed (2)
+#define GTF_transfer_committed (1U<<_GTF_transfer_committed)
+#define _GTF_transfer_completed (3)
+#define GTF_transfer_completed (1U<<_GTF_transfer_completed)
+
+
+/***********************************
+ * GRANT TABLE QUERIES AND USES
+ */
+
+/*
+ * Reference to a grant entry in a specified domain's grant table.
+ */
+typedef uint32_t grant_ref_t;
+
+/*
+ * Handle to track a mapping created via a grant reference.
+ */
+typedef uint32_t grant_handle_t;
+
+/*
+ * GNTTABOP_map_grant_ref: Map the grant entry (<dom>,<ref>) for access
+ * by devices and/or host CPUs. If successful, <handle> is a tracking number
+ * that must be presented later to destroy the mapping(s). On error, <handle>
+ * is a negative status code.
+ * NOTES:
+ * 1. If GNTMAP_device_map is specified then <dev_bus_addr> is the address
+ * via which I/O devices may access the granted frame.
+ * 2. If GNTMAP_host_map is specified then a mapping will be added at
+ * either a host virtual address in the current address space, or at
+ * a PTE at the specified machine address. The type of mapping to
+ * perform is selected through the GNTMAP_contains_pte flag, and the
+ * address is specified in <host_addr>.
+ * 3. Mappings should only be destroyed via GNTTABOP_unmap_grant_ref. If a
+ * host mapping is destroyed by other means then it is *NOT* guaranteed
+ * to be accounted to the correct grant reference!
+ */
+#define GNTTABOP_map_grant_ref 0
+struct gnttab_map_grant_ref {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint32_t flags; /* GNTMAP_* */
+ grant_ref_t ref;
+ domid_t dom;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+ grant_handle_t handle;
+ uint64_t dev_bus_addr;
+};
+
+/*
+ * GNTTABOP_unmap_grant_ref: Destroy one or more grant-reference mappings
+ * tracked by <handle>. If <host_addr> or <dev_bus_addr> is zero, that
+ * field is ignored. If non-zero, they must refer to a device/host mapping
+ * that is tracked by <handle>
+ * NOTES:
+ * 1. The call may fail in an undefined manner if either mapping is not
+ * tracked by <handle>.
+ * 3. After executing a batch of unmaps, it is guaranteed that no stale
+ * mappings will remain in the device or host TLBs.
+ */
+#define GNTTABOP_unmap_grant_ref 1
+struct gnttab_unmap_grant_ref {
+ /* IN parameters. */
+ uint64_t host_addr;
+ uint64_t dev_bus_addr;
+ grant_handle_t handle;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_setup_table: Set up a grant table for <dom> comprising at least
+ * <nr_frames> pages. The frame addresses are written to the <frame_list>.
+ * Only <nr_frames> addresses are written, even if the table is larger.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ * 3. Xen may not support more than a single grant-table page per domain.
+ */
+#define GNTTABOP_setup_table 2
+struct gnttab_setup_table {
+ /* IN parameters. */
+ domid_t dom;
+ uint32_t nr_frames;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+ ulong *frame_list;
+};
+
+/*
+ * GNTTABOP_dump_table: Dump the contents of the grant table to the
+ * xen console. Debugging use only.
+ */
+#define GNTTABOP_dump_table 3
+struct gnttab_dump_table {
+ /* IN parameters. */
+ domid_t dom;
+ /* OUT parameters. */
+ int16_t status; /* GNTST_* */
+};
+
+/*
+ * GNTTABOP_transfer_grant_ref: Transfer <frame> to a foreign domain. The
+ * foreign domain has previously registered its interest in the transfer via
+ * <domid, ref>.
+ *
+ * Note that, even if the transfer fails, the specified page no longer belongs
+ * to the calling domain *unless* the error is GNTST_bad_page.
+ */
+#define GNTTABOP_transfer 4
+struct gnttab_transfer {
+ /* IN parameters. */
+ unsigned long mfn;
+ domid_t domid;
+ grant_ref_t ref;
+ /* OUT parameters. */
+ int16_t status;
+};
+
+
+/*
+ * GNTTABOP_copy: Hypervisor based copy
+ * source and destinations can be eithers MFNs or, for foreign domains,
+ * grant references. the foreign domain has to grant read/write access
+ * in its grant table.
+ *
+ * The flags specify what type source and destinations are (either MFN
+ * or grant reference).
+ *
+ * Note that this can also be used to copy data between two domains
+ * via a third party if the source and destination domains had previously
+ * grant appropriate access to their pages to the third party.
+ *
+ * source_offset specifies an offset in the source frame, dest_offset
+ * the offset in the target frame and len specifies the number of
+ * bytes to be copied.
+ */
+
+#define _GNTCOPY_source_gref (0)
+#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref)
+#define _GNTCOPY_dest_gref (1)
+#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref)
+
+#define GNTTABOP_copy 5
+struct gnttab_copy {
+ /* IN parameters. */
+ struct {
+ union {
+ grant_ref_t ref;
+ unsigned long gmfn;
+ } u;
+ domid_t domid;
+ uint16_t offset;
+ } source, dest;
+ uint16_t len;
+ uint16_t flags; /* GNTCOPY_* */
+ /* OUT parameters. */
+ int16_t status;
+};
+
+/*
+ * GNTTABOP_query_size: Query the current and maximum sizes of the shared
+ * grant table.
+ * NOTES:
+ * 1. <dom> may be specified as DOMID_SELF.
+ * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF.
+ */
+#define GNTTABOP_query_size 6
+struct gnttab_query_size {
+ /* IN parameters. */
+ domid_t dom;
+ /* OUT parameters. */
+ uint32_t nr_frames;
+ uint32_t max_nr_frames;
+ int16_t status; /* GNTST_* */
+};
+
+
+/*
+ * Bitfield values for update_pin_status.flags.
+ */
+ /* Map the grant entry for access by I/O devices. */
+#define _GNTMAP_device_map (0)
+#define GNTMAP_device_map (1<<_GNTMAP_device_map)
+ /* Map the grant entry for access by host CPUs. */
+#define _GNTMAP_host_map (1)
+#define GNTMAP_host_map (1<<_GNTMAP_host_map)
+ /* Accesses to the granted frame will be restricted to read-only access. */
+#define _GNTMAP_readonly (2)
+#define GNTMAP_readonly (1<<_GNTMAP_readonly)
+ /*
+ * GNTMAP_host_map subflag:
+ * 0 => The host mapping is usable only by the guest OS.
+ * 1 => The host mapping is usable by guest OS + current application.
+ */
+#define _GNTMAP_application_map (3)
+#define GNTMAP_application_map (1<<_GNTMAP_application_map)
+
+ /*
+ * GNTMAP_contains_pte subflag:
+ * 0 => This map request contains a host virtual address.
+ * 1 => This map request contains the machine addess of the PTE to update.
+ */
+#define _GNTMAP_contains_pte (4)
+#define GNTMAP_contains_pte (1<<_GNTMAP_contains_pte)
+
+/*
+ * Values for error status returns. All errors are -ve.
+ */
+#define GNTST_okay (0) /* Normal return. */
+#define GNTST_general_error (-1) /* General undefined error. */
+#define GNTST_bad_domain (-2) /* Unrecognsed domain id. */
+#define GNTST_bad_gntref (-3) /* Unrecognised or inappropriate gntref. */
+#define GNTST_bad_handle (-4) /* Unrecognised or inappropriate handle. */
+#define GNTST_bad_virt_addr (-5) /* Inappropriate virtual address to map. */
+#define GNTST_bad_dev_addr (-6) /* Inappropriate device address to unmap.*/
+#define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */
+#define GNTST_permission_denied (-8) /* Not enough privilege for operation. */
+#define GNTST_bad_page (-9) /* Specified page was invalid for op. */
+#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary */
+
+#define GNTTABOP_error_msgs { \
+ "okay", \
+ "undefined error", \
+ "unrecognised domain id", \
+ "invalid grant reference", \
+ "invalid mapping handle", \
+ "invalid virtual address", \
+ "invalid device address", \
+ "no spare translation slot in the I/O MMU", \
+ "permission denied", \
+ "bad page", \
+ "copy arguments cross page boundary" \
+}
+
+#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
diff --git a/include/xen/interface/io/blkif.h b/include/xen/interface/io/blkif.h
new file mode 100644
index 000000000000..c2d1fa4dc1ee
--- /dev/null
+++ b/include/xen/interface/io/blkif.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * blkif.h
+ *
+ * Unified block-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_BLKIF_H__
+#define __XEN_PUBLIC_IO_BLKIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Front->back notifications: When enqueuing a new request, sending a
+ * notification can be made conditional on req_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Backends must set
+ * req_event appropriately (e.g., using RING_FINAL_CHECK_FOR_REQUESTS()).
+ *
+ * Back->front notifications: When enqueuing a new response, sending a
+ * notification can be made conditional on rsp_event (i.e., the generic
+ * hold-off mechanism provided by the ring macros). Frontends must set
+ * rsp_event appropriately (e.g., using RING_FINAL_CHECK_FOR_RESPONSES()).
+ */
+
+typedef uint16_t blkif_vdev_t;
+typedef uint64_t blkif_sector_t;
+
+/*
+ * REQUEST CODES.
+ */
+#define BLKIF_OP_READ 0
+#define BLKIF_OP_WRITE 1
+/*
+ * Recognised only if "feature-barrier" is present in backend xenbus info.
+ * The "feature_barrier" node contains a boolean indicating whether barrier
+ * requests are likely to succeed or fail. Either way, a barrier request
+ * may fail at any time with BLKIF_RSP_EOPNOTSUPP if it is unsupported by
+ * the underlying block-device hardware. The boolean simply indicates whether
+ * or not it is worthwhile for the frontend to attempt barrier requests.
+ * If a backend does not recognise BLKIF_OP_WRITE_BARRIER, it should *not*
+ * create the "feature-barrier" node!
+ */
+#define BLKIF_OP_WRITE_BARRIER 2
+
+/*
+ * Maximum scatter/gather segments per request.
+ * This is carefully chosen so that sizeof(struct blkif_ring) <= PAGE_SIZE.
+ * NB. This could be 12 if the ring indexes weren't stored in the same page.
+ */
+#define BLKIF_MAX_SEGMENTS_PER_REQUEST 11
+
+struct blkif_request {
+ uint8_t operation; /* BLKIF_OP_??? */
+ uint8_t nr_segments; /* number of segments */
+ blkif_vdev_t handle; /* only for read/write requests */
+ uint64_t id; /* private guest value, echoed in resp */
+ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
+ struct blkif_request_segment {
+ grant_ref_t gref; /* reference to I/O buffer frame */
+ /* @first_sect: first sector in frame to transfer (inclusive). */
+ /* @last_sect: last sector in frame to transfer (inclusive). */
+ uint8_t first_sect, last_sect;
+ } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+struct blkif_response {
+ uint64_t id; /* copied from request */
+ uint8_t operation; /* copied from request */
+ int16_t status; /* BLKIF_RSP_??? */
+};
+
+/*
+ * STATUS RETURN CODES.
+ */
+ /* Operation not supported (only happens on barrier writes). */
+#define BLKIF_RSP_EOPNOTSUPP -2
+ /* Operation failed for some unspecified reason (-EIO). */
+#define BLKIF_RSP_ERROR -1
+ /* Operation completed successfully. */
+#define BLKIF_RSP_OKAY 0
+
+/*
+ * Generate blkif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(blkif, struct blkif_request, struct blkif_response);
+
+#define VDISK_CDROM 0x1
+#define VDISK_REMOVABLE 0x2
+#define VDISK_READONLY 0x4
+
+#endif /* __XEN_PUBLIC_IO_BLKIF_H__ */
diff --git a/include/xen/interface/io/console.h b/include/xen/interface/io/console.h
new file mode 100644
index 000000000000..e563de70f784
--- /dev/null
+++ b/include/xen/interface/io/console.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * console.h
+ *
+ * Console I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2005, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
+#define __XEN_PUBLIC_IO_CONSOLE_H__
+
+typedef uint32_t XENCONS_RING_IDX;
+
+#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
+
+struct xencons_interface {
+ char in[1024];
+ char out[2048];
+ XENCONS_RING_IDX in_cons, in_prod;
+ XENCONS_RING_IDX out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h
new file mode 100644
index 000000000000..518481c95f18
--- /dev/null
+++ b/include/xen/interface/io/netif.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * netif.h
+ *
+ * Unified network-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_NETIF_H__
+#define __XEN_PUBLIC_IO_NETIF_H__
+
+#include "ring.h"
+#include "../grant_table.h"
+
+/*
+ * Notifications after enqueuing any type of message should be conditional on
+ * the appropriate req_event or rsp_event field in the shared ring.
+ * If the client sends notification for rx requests then it should specify
+ * feature 'feature-rx-notify' via xenbus. Otherwise the backend will assume
+ * that it cannot safely queue packets (as it may not be kicked to send them).
+ */
+
+/*
+ * This is the 'wire' format for packets:
+ * Request 1: netif_tx_request -- NETTXF_* (any flags)
+ * [Request 2: netif_tx_extra] (only if request 1 has NETTXF_extra_info)
+ * [Request 3: netif_tx_extra] (only if request 2 has XEN_NETIF_EXTRA_MORE)
+ * Request 4: netif_tx_request -- NETTXF_more_data
+ * Request 5: netif_tx_request -- NETTXF_more_data
+ * ...
+ * Request N: netif_tx_request -- 0
+ */
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETTXF_csum_blank (0)
+#define NETTXF_csum_blank (1U<<_NETTXF_csum_blank)
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETTXF_data_validated (1)
+#define NETTXF_data_validated (1U<<_NETTXF_data_validated)
+
+/* Packet continues in the next request descriptor. */
+#define _NETTXF_more_data (2)
+#define NETTXF_more_data (1U<<_NETTXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETTXF_extra_info (3)
+#define NETTXF_extra_info (1U<<_NETTXF_extra_info)
+
+struct xen_netif_tx_request {
+ grant_ref_t gref; /* Reference to buffer page */
+ uint16_t offset; /* Offset within buffer page */
+ uint16_t flags; /* NETTXF_* */
+ uint16_t id; /* Echoed in response message. */
+ uint16_t size; /* Packet size in bytes. */
+};
+
+/* Types of netif_extra_info descriptors. */
+#define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */
+#define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */
+#define XEN_NETIF_EXTRA_TYPE_MAX (2)
+
+/* netif_extra_info flags. */
+#define _XEN_NETIF_EXTRA_FLAG_MORE (0)
+#define XEN_NETIF_EXTRA_FLAG_MORE (1U<<_XEN_NETIF_EXTRA_FLAG_MORE)
+
+/* GSO types - only TCPv4 currently supported. */
+#define XEN_NETIF_GSO_TYPE_TCPV4 (1)
+
+/*
+ * This structure needs to fit within both netif_tx_request and
+ * netif_rx_response for compatibility.
+ */
+struct xen_netif_extra_info {
+ uint8_t type; /* XEN_NETIF_EXTRA_TYPE_* */
+ uint8_t flags; /* XEN_NETIF_EXTRA_FLAG_* */
+
+ union {
+ struct {
+ /*
+ * Maximum payload size of each segment. For
+ * example, for TCP this is just the path MSS.
+ */
+ uint16_t size;
+
+ /*
+ * GSO type. This determines the protocol of
+ * the packet and any extra features required
+ * to segment the packet properly.
+ */
+ uint8_t type; /* XEN_NETIF_GSO_TYPE_* */
+
+ /* Future expansion. */
+ uint8_t pad;
+
+ /*
+ * GSO features. This specifies any extra GSO
+ * features required to process this packet,
+ * such as ECN support for TCPv4.
+ */
+ uint16_t features; /* XEN_NETIF_GSO_FEAT_* */
+ } gso;
+
+ uint16_t pad[3];
+ } u;
+};
+
+struct xen_netif_tx_response {
+ uint16_t id;
+ int16_t status; /* NETIF_RSP_* */
+};
+
+struct xen_netif_rx_request {
+ uint16_t id; /* Echoed in response message. */
+ grant_ref_t gref; /* Reference to incoming granted frame */
+};
+
+/* Packet data has been validated against protocol checksum. */
+#define _NETRXF_data_validated (0)
+#define NETRXF_data_validated (1U<<_NETRXF_data_validated)
+
+/* Protocol checksum field is blank in the packet (hardware offload)? */
+#define _NETRXF_csum_blank (1)
+#define NETRXF_csum_blank (1U<<_NETRXF_csum_blank)
+
+/* Packet continues in the next request descriptor. */
+#define _NETRXF_more_data (2)
+#define NETRXF_more_data (1U<<_NETRXF_more_data)
+
+/* Packet to be followed by extra descriptor(s). */
+#define _NETRXF_extra_info (3)
+#define NETRXF_extra_info (1U<<_NETRXF_extra_info)
+
+struct xen_netif_rx_response {
+ uint16_t id;
+ uint16_t offset; /* Offset in page of start of received packet */
+ uint16_t flags; /* NETRXF_* */
+ int16_t status; /* -ve: BLKIF_RSP_* ; +ve: Rx'ed pkt size. */
+};
+
+/*
+ * Generate netif ring structures and types.
+ */
+
+DEFINE_RING_TYPES(xen_netif_tx,
+ struct xen_netif_tx_request,
+ struct xen_netif_tx_response);
+DEFINE_RING_TYPES(xen_netif_rx,
+ struct xen_netif_rx_request,
+ struct xen_netif_rx_response);
+
+#define NETIF_RSP_DROPPED -2
+#define NETIF_RSP_ERROR -1
+#define NETIF_RSP_OKAY 0
+/* No response: used for auxiliary requests (e.g., netif_tx_extra). */
+#define NETIF_RSP_NULL 1
+
+#endif
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
new file mode 100644
index 000000000000..e8cbf431c8cc
--- /dev/null
+++ b/include/xen/interface/io/ring.h
@@ -0,0 +1,260 @@
+/******************************************************************************
+ * ring.h
+ *
+ * Shared producer-consumer ring macros.
+ *
+ * Tim Deegan and Andrew Warfield November 2004.
+ */
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+typedef unsigned int RING_IDX;
+
+/* Round a 32-bit unsigned constant down to the nearest power of two. */
+#define __RD2(_x) (((_x) & 0x00000002) ? 0x2 : ((_x) & 0x1))
+#define __RD4(_x) (((_x) & 0x0000000c) ? __RD2((_x)>>2)<<2 : __RD2(_x))
+#define __RD8(_x) (((_x) & 0x000000f0) ? __RD4((_x)>>4)<<4 : __RD4(_x))
+#define __RD16(_x) (((_x) & 0x0000ff00) ? __RD8((_x)>>8)<<8 : __RD8(_x))
+#define __RD32(_x) (((_x) & 0xffff0000) ? __RD16((_x)>>16)<<16 : __RD16(_x))
+
+/*
+ * Calculate size of a shared ring, given the total available space for the
+ * ring and indexes (_sz), and the name tag of the request/response structure.
+ * A ring contains as many entries as will fit, rounded down to the nearest
+ * power of two (so we can mask with (size-1) to loop around).
+ */
+#define __RING_SIZE(_s, _sz) \
+ (__RD32(((_sz) - (long)&(_s)->ring + (long)(_s)) / sizeof((_s)->ring[0])))
+
+/*
+ * Macros to make the correct C datatypes for a new kind of ring.
+ *
+ * To make a new ring datatype, you need to have two message structures,
+ * let's say struct request, and struct response already defined.
+ *
+ * In a header where you want the ring datatype declared, you then do:
+ *
+ * DEFINE_RING_TYPES(mytag, struct request, struct response);
+ *
+ * These expand out to give you a set of types, as you can see below.
+ * The most important of these are:
+ *
+ * struct mytag_sring - The shared ring.
+ * struct mytag_front_ring - The 'front' half of the ring.
+ * struct mytag_back_ring - The 'back' half of the ring.
+ *
+ * To initialize a ring in your code you need to know the location and size
+ * of the shared memory area (PAGE_SIZE, for instance). To initialise
+ * the front half:
+ *
+ * struct mytag_front_ring front_ring;
+ * SHARED_RING_INIT((struct mytag_sring *)shared_page);
+ * FRONT_RING_INIT(&front_ring, (struct mytag_sring *)shared_page,
+ * PAGE_SIZE);
+ *
+ * Initializing the back follows similarly (note that only the front
+ * initializes the shared ring):
+ *
+ * struct mytag_back_ring back_ring;
+ * BACK_RING_INIT(&back_ring, (struct mytag_sring *)shared_page,
+ * PAGE_SIZE);
+ */
+
+#define DEFINE_RING_TYPES(__name, __req_t, __rsp_t) \
+ \
+/* Shared ring entry */ \
+union __name##_sring_entry { \
+ __req_t req; \
+ __rsp_t rsp; \
+}; \
+ \
+/* Shared ring page */ \
+struct __name##_sring { \
+ RING_IDX req_prod, req_event; \
+ RING_IDX rsp_prod, rsp_event; \
+ uint8_t pad[48]; \
+ union __name##_sring_entry ring[1]; /* variable-length */ \
+}; \
+ \
+/* "Front" end's private variables */ \
+struct __name##_front_ring { \
+ RING_IDX req_prod_pvt; \
+ RING_IDX rsp_cons; \
+ unsigned int nr_ents; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* "Back" end's private variables */ \
+struct __name##_back_ring { \
+ RING_IDX rsp_prod_pvt; \
+ RING_IDX req_cons; \
+ unsigned int nr_ents; \
+ struct __name##_sring *sring; \
+};
+
+/*
+ * Macros for manipulating rings.
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
+ * requests are pushed on to the ring and responses taken off it.
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
+ * requests are taken off the ring and responses put on.
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
+ * requestor (front end) never has more than RING_SIZE()-1
+ * outstanding requests.
+ */
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_s) do { \
+ (_s)->req_prod = (_s)->rsp_prod = 0; \
+ (_s)->req_event = (_s)->rsp_event = 1; \
+ memset((_s)->pad, 0, sizeof((_s)->pad)); \
+} while(0)
+
+#define FRONT_RING_INIT(_r, _s, __size) do { \
+ (_r)->req_prod_pvt = 0; \
+ (_r)->rsp_cons = 0; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+ (_r)->sring = (_s); \
+} while (0)
+
+#define BACK_RING_INIT(_r, _s, __size) do { \
+ (_r)->rsp_prod_pvt = 0; \
+ (_r)->req_cons = 0; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+ (_r)->sring = (_s); \
+} while (0)
+
+/* Initialize to existing shared indexes -- for recovery */
+#define FRONT_RING_ATTACH(_r, _s, __size) do { \
+ (_r)->sring = (_s); \
+ (_r)->req_prod_pvt = (_s)->req_prod; \
+ (_r)->rsp_cons = (_s)->rsp_prod; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+} while (0)
+
+#define BACK_RING_ATTACH(_r, _s, __size) do { \
+ (_r)->sring = (_s); \
+ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \
+ (_r)->req_cons = (_s)->req_prod; \
+ (_r)->nr_ents = __RING_SIZE(_s, __size); \
+} while (0)
+
+/* How big is this ring? */
+#define RING_SIZE(_r) \
+ ((_r)->nr_ents)
+
+/* Number of free requests (for use on front side only). */
+#define RING_FREE_REQUESTS(_r) \
+ (RING_SIZE(_r) - ((_r)->req_prod_pvt - (_r)->rsp_cons))
+
+/* Test if there is an empty slot available on the front ring.
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_r) \
+ (RING_FREE_REQUESTS(_r) == 0)
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
+ ((_r)->sring->rsp_prod - (_r)->rsp_cons)
+
+#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
+ ({ \
+ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
+ unsigned int rsp = RING_SIZE(_r) - \
+ ((_r)->req_cons - (_r)->rsp_prod_pvt); \
+ req < rsp ? req : rsp; \
+ })
+
+/* Direct access to individual ring elements, by index. */
+#define RING_GET_REQUEST(_r, _idx) \
+ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
+
+#define RING_GET_RESPONSE(_r, _idx) \
+ (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
+
+/* Loop termination condition: Would the specified index overflow the ring? */
+#define RING_REQUEST_CONS_OVERFLOW(_r, _cons) \
+ (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
+
+#define RING_PUSH_REQUESTS(_r) do { \
+ wmb(); /* back sees requests /before/ updated producer index */ \
+ (_r)->sring->req_prod = (_r)->req_prod_pvt; \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_r) do { \
+ wmb(); /* front sees responses /before/ updated producer index */ \
+ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
+} while (0)
+
+/*
+ * Notification hold-off (req_event and rsp_event):
+ *
+ * When queueing requests or responses on a shared ring, it may not always be
+ * necessary to notify the remote end. For example, if requests are in flight
+ * in a backend, the front may be able to queue further requests without
+ * notifying the back (if the back checks for new requests when it queues
+ * responses).
+ *
+ * When enqueuing requests or responses:
+ *
+ * Use RING_PUSH_{REQUESTS,RESPONSES}_AND_CHECK_NOTIFY(). The second argument
+ * is a boolean return value. True indicates that the receiver requires an
+ * asynchronous notification.
+ *
+ * After dequeuing requests or responses (before sleeping the connection):
+ *
+ * Use RING_FINAL_CHECK_FOR_REQUESTS() or RING_FINAL_CHECK_FOR_RESPONSES().
+ * The second argument is a boolean return value. True indicates that there
+ * are pending messages on the ring (i.e., the connection should not be put
+ * to sleep).
+ *
+ * These macros will set the req_event/rsp_event field to trigger a
+ * notification on the very next message that is enqueued. If you want to
+ * create batches of work (i.e., only receive a notification after several
+ * messages have been enqueued) then you will need to create a customised
+ * version of the FINAL_CHECK macro in your own code, which sets the event
+ * field appropriately.
+ */
+
+#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do { \
+ RING_IDX __old = (_r)->sring->req_prod; \
+ RING_IDX __new = (_r)->req_prod_pvt; \
+ wmb(); /* back sees requests /before/ updated producer index */ \
+ (_r)->sring->req_prod = __new; \
+ mb(); /* back sees new requests /before/ we check req_event */ \
+ (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) < \
+ (RING_IDX)(__new - __old)); \
+} while (0)
+
+#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do { \
+ RING_IDX __old = (_r)->sring->rsp_prod; \
+ RING_IDX __new = (_r)->rsp_prod_pvt; \
+ wmb(); /* front sees responses /before/ updated producer index */ \
+ (_r)->sring->rsp_prod = __new; \
+ mb(); /* front sees new responses /before/ we check rsp_event */ \
+ (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) < \
+ (RING_IDX)(__new - __old)); \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_REQUESTS(_r, _work_to_do) do { \
+ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
+ if (_work_to_do) break; \
+ (_r)->sring->req_event = (_r)->req_cons + 1; \
+ mb(); \
+ (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r); \
+} while (0)
+
+#define RING_FINAL_CHECK_FOR_RESPONSES(_r, _work_to_do) do { \
+ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
+ if (_work_to_do) break; \
+ (_r)->sring->rsp_event = (_r)->rsp_cons + 1; \
+ mb(); \
+ (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r); \
+} while (0)
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */
diff --git a/include/xen/interface/io/xenbus.h b/include/xen/interface/io/xenbus.h
new file mode 100644
index 000000000000..46508c7fa399
--- /dev/null
+++ b/include/xen/interface/io/xenbus.h
@@ -0,0 +1,44 @@
+/*****************************************************************************
+ * xenbus.h
+ *
+ * Xenbus protocol details.
+ *
+ * Copyright (C) 2005 XenSource Ltd.
+ */
+
+#ifndef _XEN_PUBLIC_IO_XENBUS_H
+#define _XEN_PUBLIC_IO_XENBUS_H
+
+/* The state of either end of the Xenbus, i.e. the current communication
+ status of initialisation across the bus. States here imply nothing about
+ the state of the connection between the driver and the kernel's device
+ layers. */
+enum xenbus_state
+{
+ XenbusStateUnknown = 0,
+ XenbusStateInitialising = 1,
+ XenbusStateInitWait = 2, /* Finished early
+ initialisation, but waiting
+ for information from the peer
+ or hotplug scripts. */
+ XenbusStateInitialised = 3, /* Initialised and waiting for a
+ connection from the peer. */
+ XenbusStateConnected = 4,
+ XenbusStateClosing = 5, /* The device is being closed
+ due to an error or an unplug
+ event. */
+ XenbusStateClosed = 6
+
+};
+
+#endif /* _XEN_PUBLIC_IO_XENBUS_H */
+
+/*
+ * Local variables:
+ * c-file-style: "linux"
+ * indent-tabs-mode: t
+ * c-indent-level: 8
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/include/xen/interface/io/xs_wire.h b/include/xen/interface/io/xs_wire.h
new file mode 100644
index 000000000000..99fcffb372d1
--- /dev/null
+++ b/include/xen/interface/io/xs_wire.h
@@ -0,0 +1,87 @@
+/*
+ * Details of the "wire" protocol between Xen Store Daemon and client
+ * library or guest kernel.
+ * Copyright (C) 2005 Rusty Russell IBM Corporation
+ */
+
+#ifndef _XS_WIRE_H
+#define _XS_WIRE_H
+
+enum xsd_sockmsg_type
+{
+ XS_DEBUG,
+ XS_DIRECTORY,
+ XS_READ,
+ XS_GET_PERMS,
+ XS_WATCH,
+ XS_UNWATCH,
+ XS_TRANSACTION_START,
+ XS_TRANSACTION_END,
+ XS_INTRODUCE,
+ XS_RELEASE,
+ XS_GET_DOMAIN_PATH,
+ XS_WRITE,
+ XS_MKDIR,
+ XS_RM,
+ XS_SET_PERMS,
+ XS_WATCH_EVENT,
+ XS_ERROR,
+ XS_IS_DOMAIN_INTRODUCED
+};
+
+#define XS_WRITE_NONE "NONE"
+#define XS_WRITE_CREATE "CREATE"
+#define XS_WRITE_CREATE_EXCL "CREATE|EXCL"
+
+/* We hand errors as strings, for portability. */
+struct xsd_errors
+{
+ int errnum;
+ const char *errstring;
+};
+#define XSD_ERROR(x) { x, #x }
+static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
+ XSD_ERROR(EINVAL),
+ XSD_ERROR(EACCES),
+ XSD_ERROR(EEXIST),
+ XSD_ERROR(EISDIR),
+ XSD_ERROR(ENOENT),
+ XSD_ERROR(ENOMEM),
+ XSD_ERROR(ENOSPC),
+ XSD_ERROR(EIO),
+ XSD_ERROR(ENOTEMPTY),
+ XSD_ERROR(ENOSYS),
+ XSD_ERROR(EROFS),
+ XSD_ERROR(EBUSY),
+ XSD_ERROR(EAGAIN),
+ XSD_ERROR(EISCONN)
+};
+
+struct xsd_sockmsg
+{
+ uint32_t type; /* XS_??? */
+ uint32_t req_id;/* Request identifier, echoed in daemon's response. */
+ uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */
+ uint32_t len; /* Length of data following this. */
+
+ /* Generally followed by nul-terminated string(s). */
+};
+
+enum xs_watch_type
+{
+ XS_WATCH_PATH = 0,
+ XS_WATCH_TOKEN
+};
+
+/* Inter-domain shared memory communications. */
+#define XENSTORE_RING_SIZE 1024
+typedef uint32_t XENSTORE_RING_IDX;
+#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))
+struct xenstore_domain_interface {
+ char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */
+ char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
+ XENSTORE_RING_IDX req_cons, req_prod;
+ XENSTORE_RING_IDX rsp_cons, rsp_prod;
+};
+
+#endif /* _XS_WIRE_H */
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
new file mode 100644
index 000000000000..af36ead16817
--- /dev/null
+++ b/include/xen/interface/memory.h
@@ -0,0 +1,145 @@
+/******************************************************************************
+ * memory.h
+ *
+ * Memory reservation and information.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_MEMORY_H__
+#define __XEN_PUBLIC_MEMORY_H__
+
+/*
+ * Increase or decrease the specified domain's memory reservation. Returns a
+ * -ve errcode on failure, or the # extents successfully allocated or freed.
+ * arg == addr of struct xen_memory_reservation.
+ */
+#define XENMEM_increase_reservation 0
+#define XENMEM_decrease_reservation 1
+#define XENMEM_populate_physmap 6
+struct xen_memory_reservation {
+
+ /*
+ * XENMEM_increase_reservation:
+ * OUT: MFN (*not* GMFN) bases of extents that were allocated
+ * XENMEM_decrease_reservation:
+ * IN: GMFN bases of extents to free
+ * XENMEM_populate_physmap:
+ * IN: GPFN bases of extents to populate with memory
+ * OUT: GMFN bases of extents that were allocated
+ * (NB. This command also updates the mach_to_phys translation table)
+ */
+ GUEST_HANDLE(ulong) extent_start;
+
+ /* Number of extents, and size/alignment of each (2^extent_order pages). */
+ unsigned long nr_extents;
+ unsigned int extent_order;
+
+ /*
+ * Maximum # bits addressable by the user of the allocated region (e.g.,
+ * I/O devices often have a 32-bit limitation even in 64-bit systems). If
+ * zero then the user has no addressing restriction.
+ * This field is not used by XENMEM_decrease_reservation.
+ */
+ unsigned int address_bits;
+
+ /*
+ * Domain whose reservation is being changed.
+ * Unprivileged domains can specify only DOMID_SELF.
+ */
+ domid_t domid;
+
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_memory_reservation);
+
+/*
+ * Returns the maximum machine frame number of mapped RAM in this system.
+ * This command always succeeds (it never returns an error code).
+ * arg == NULL.
+ */
+#define XENMEM_maximum_ram_page 2
+
+/*
+ * Returns the current or maximum memory reservation, in pages, of the
+ * specified domain (may be DOMID_SELF). Returns -ve errcode on failure.
+ * arg == addr of domid_t.
+ */
+#define XENMEM_current_reservation 3
+#define XENMEM_maximum_reservation 4
+
+/*
+ * Returns a list of MFN bases of 2MB extents comprising the machine_to_phys
+ * mapping table. Architectures which do not have a m2p table do not implement
+ * this command.
+ * arg == addr of xen_machphys_mfn_list_t.
+ */
+#define XENMEM_machphys_mfn_list 5
+struct xen_machphys_mfn_list {
+ /*
+ * Size of the 'extent_start' array. Fewer entries will be filled if the
+ * machphys table is smaller than max_extents * 2MB.
+ */
+ unsigned int max_extents;
+
+ /*
+ * Pointer to buffer to fill with list of extent starts. If there are
+ * 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;
+
+ /*
+ * Number of extents written to the above array. This will be smaller
+ * than 'max_extents' if the machphys table is smaller than max_e * 2MB.
+ */
+ 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
+ * pseudophysical address space.
+ * arg == addr of xen_add_to_physmap_t.
+ */
+#define XENMEM_add_to_physmap 7
+struct xen_add_to_physmap {
+ /* Which domain to change the mapping for. */
+ domid_t domid;
+
+ /* Source mapping space. */
+#define XENMAPSPACE_shared_info 0 /* shared info page */
+#define XENMAPSPACE_grant_table 1 /* grant table page */
+ unsigned int space;
+
+ /* Index into source mapping space. */
+ unsigned long idx;
+
+ /* 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
+ * code on failure. This call only works for auto-translated guests.
+ */
+#define XENMEM_translate_gpfn_list 8
+struct xen_translate_gpfn_list {
+ /* Which domain to translate for? */
+ domid_t domid;
+
+ /* Length of list. */
+ unsigned long nr_gpfns;
+
+ /* List of GPFNs to translate. */
+ GUEST_HANDLE(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;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xen_translate_gpfn_list);
+
+#endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/interface/physdev.h b/include/xen/interface/physdev.h
new file mode 100644
index 000000000000..cd6939147cb6
--- /dev/null
+++ b/include/xen/interface/physdev.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#ifndef __XEN_PUBLIC_PHYSDEV_H__
+#define __XEN_PUBLIC_PHYSDEV_H__
+
+/*
+ * Prototype for this hypercall is:
+ * int physdev_op(int cmd, void *args)
+ * @cmd == PHYSDEVOP_??? (physdev operation).
+ * @args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Notify end-of-interrupt (EOI) for the specified IRQ.
+ * @arg == pointer to physdev_eoi structure.
+ */
+#define PHYSDEVOP_eoi 12
+struct physdev_eoi {
+ /* IN */
+ uint32_t irq;
+};
+
+/*
+ * Query the status of an IRQ line.
+ * @arg == pointer to physdev_irq_status_query structure.
+ */
+#define PHYSDEVOP_irq_status_query 5
+struct physdev_irq_status_query {
+ /* IN */
+ uint32_t irq;
+ /* OUT */
+ uint32_t flags; /* XENIRQSTAT_* */
+};
+
+/* Need to call PHYSDEVOP_eoi when the IRQ has been serviced? */
+#define _XENIRQSTAT_needs_eoi (0)
+#define XENIRQSTAT_needs_eoi (1U<<_XENIRQSTAT_needs_eoi)
+
+/* IRQ shared by multiple guests? */
+#define _XENIRQSTAT_shared (1)
+#define XENIRQSTAT_shared (1U<<_XENIRQSTAT_shared)
+
+/*
+ * Set the current VCPU's I/O privilege level.
+ * @arg == pointer to physdev_set_iopl structure.
+ */
+#define PHYSDEVOP_set_iopl 6
+struct physdev_set_iopl {
+ /* IN */
+ uint32_t iopl;
+};
+
+/*
+ * Set the current VCPU's I/O-port permissions bitmap.
+ * @arg == pointer to physdev_set_iobitmap structure.
+ */
+#define PHYSDEVOP_set_iobitmap 7
+struct physdev_set_iobitmap {
+ /* IN */
+ uint8_t * bitmap;
+ uint32_t nr_ports;
+};
+
+/*
+ * Read or write an IO-APIC register.
+ * @arg == pointer to physdev_apic structure.
+ */
+#define PHYSDEVOP_apic_read 8
+#define PHYSDEVOP_apic_write 9
+struct physdev_apic {
+ /* IN */
+ unsigned long apic_physbase;
+ uint32_t reg;
+ /* IN or OUT */
+ uint32_t value;
+};
+
+/*
+ * Allocate or free a physical upcall vector for the specified IRQ line.
+ * @arg == pointer to physdev_irq structure.
+ */
+#define PHYSDEVOP_alloc_irq_vector 10
+#define PHYSDEVOP_free_irq_vector 11
+struct physdev_irq {
+ /* IN */
+ uint32_t irq;
+ /* IN or OUT */
+ uint32_t vector;
+};
+
+/*
+ * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
+ * hypercall since 0x00030202.
+ */
+struct physdev_op {
+ uint32_t cmd;
+ union {
+ struct physdev_irq_status_query irq_status_query;
+ struct physdev_set_iopl set_iopl;
+ struct physdev_set_iobitmap set_iobitmap;
+ struct physdev_apic apic_op;
+ struct physdev_irq irq_op;
+ } u;
+};
+
+/*
+ * Notify that some PIRQ-bound event channels have been unmasked.
+ * ** This command is obsolete since interface version 0x00030202 and is **
+ * ** unsupported by newer versions of Xen. **
+ */
+#define PHYSDEVOP_IRQ_UNMASK_NOTIFY 4
+
+/*
+ * These all-capitals physdev operation names are superceded by the new names
+ * (defined above) since interface version 0x00030202.
+ */
+#define PHYSDEVOP_IRQ_STATUS_QUERY PHYSDEVOP_irq_status_query
+#define PHYSDEVOP_SET_IOPL PHYSDEVOP_set_iopl
+#define PHYSDEVOP_SET_IOBITMAP PHYSDEVOP_set_iobitmap
+#define PHYSDEVOP_APIC_READ PHYSDEVOP_apic_read
+#define PHYSDEVOP_APIC_WRITE PHYSDEVOP_apic_write
+#define PHYSDEVOP_ASSIGN_VECTOR PHYSDEVOP_alloc_irq_vector
+#define PHYSDEVOP_FREE_VECTOR PHYSDEVOP_free_irq_vector
+#define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi
+#define PHYSDEVOP_IRQ_SHARED XENIRQSTAT_shared
+
+#endif /* __XEN_PUBLIC_PHYSDEV_H__ */
diff --git a/include/xen/interface/sched.h b/include/xen/interface/sched.h
new file mode 100644
index 000000000000..5fec575a800a
--- /dev/null
+++ b/include/xen/interface/sched.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * sched.h
+ *
+ * Scheduler state interactions
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_SCHED_H__
+#define __XEN_PUBLIC_SCHED_H__
+
+#include "event_channel.h"
+
+/*
+ * The prototype for this hypercall is:
+ * long sched_op_new(int cmd, void *arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == Operation-specific extra argument(s), as described below.
+ *
+ * **NOTE**:
+ * Versions of Xen prior to 3.0.2 provide only the following legacy version
+ * of this hypercall, supporting only the commands yield, block and shutdown:
+ * long sched_op(int cmd, unsigned long arg)
+ * @cmd == SCHEDOP_??? (scheduler operation).
+ * @arg == 0 (SCHEDOP_yield and SCHEDOP_block)
+ * == SHUTDOWN_* code (SCHEDOP_shutdown)
+ */
+
+/*
+ * Voluntarily yield the CPU.
+ * @arg == NULL.
+ */
+#define SCHEDOP_yield 0
+
+/*
+ * Block execution of this VCPU until an event is received for processing.
+ * If called with event upcalls masked, this operation will atomically
+ * reenable event delivery and check for pending events before blocking the
+ * VCPU. This avoids a "wakeup waiting" race.
+ * @arg == NULL.
+ */
+#define SCHEDOP_block 1
+
+/*
+ * Halt execution of this domain (all VCPUs) and notify the system controller.
+ * @arg == pointer to sched_shutdown structure.
+ */
+#define SCHEDOP_shutdown 2
+struct sched_shutdown {
+ unsigned int reason; /* SHUTDOWN_* */
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_shutdown);
+
+/*
+ * Poll a set of event-channel ports. Return when one or more are pending. An
+ * optional timeout may be specified.
+ * @arg == pointer to sched_poll structure.
+ */
+#define SCHEDOP_poll 3
+struct sched_poll {
+ GUEST_HANDLE(evtchn_port_t) ports;
+ unsigned int nr_ports;
+ uint64_t timeout;
+};
+DEFINE_GUEST_HANDLE_STRUCT(sched_poll);
+
+/*
+ * Reason codes for SCHEDOP_shutdown. These may be interpreted by control
+ * software to determine the appropriate action. For the most part, Xen does
+ * not care about the shutdown code.
+ */
+#define SHUTDOWN_poweroff 0 /* Domain exited normally. Clean up and kill. */
+#define SHUTDOWN_reboot 1 /* Clean up, kill, and then restart. */
+#define SHUTDOWN_suspend 2 /* Clean up, save suspend info, kill. */
+#define SHUTDOWN_crash 3 /* Tell controller we've crashed. */
+
+#endif /* __XEN_PUBLIC_SCHED_H__ */
diff --git a/include/xen/interface/vcpu.h b/include/xen/interface/vcpu.h
new file mode 100644
index 000000000000..ff61ea365997
--- /dev/null
+++ b/include/xen/interface/vcpu.h
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * vcpu.h
+ *
+ * VCPU initialisation, query, and hotplug.
+ *
+ * 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, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VCPU_H__
+#define __XEN_PUBLIC_VCPU_H__
+
+/*
+ * Prototype for this hypercall is:
+ * int vcpu_op(int cmd, int vcpuid, void *extra_args)
+ * @cmd == VCPUOP_??? (VCPU operation).
+ * @vcpuid == VCPU to operate on.
+ * @extra_args == Operation-specific extra arguments (NULL if none).
+ */
+
+/*
+ * Initialise a VCPU. Each VCPU can be initialised only once. A
+ * newly-initialised VCPU will not run until it is brought up by VCPUOP_up.
+ *
+ * @extra_arg == pointer to vcpu_guest_context structure containing initial
+ * state for the VCPU.
+ */
+#define VCPUOP_initialise 0
+
+/*
+ * Bring up a VCPU. This makes the VCPU runnable. This operation will fail
+ * if the VCPU has not been initialised (VCPUOP_initialise).
+ */
+#define VCPUOP_up 1
+
+/*
+ * Bring down a VCPU (i.e., make it non-runnable).
+ * There are a few caveats that callers should observe:
+ * 1. This operation may return, and VCPU_is_up may return false, before the
+ * VCPU stops running (i.e., the command is asynchronous). It is a good
+ * idea to ensure that the VCPU has entered a non-critical loop before
+ * bringing it down. Alternatively, this operation is guaranteed
+ * synchronous if invoked by the VCPU itself.
+ * 2. After a VCPU is initialised, there is currently no way to drop all its
+ * references to domain memory. Even a VCPU that is down still holds
+ * memory references via its pagetable base pointer and GDT. It is good
+ * practise to move a VCPU onto an 'idle' or default page table, LDT and
+ * GDT before bringing it down.
+ */
+#define VCPUOP_down 2
+
+/* Returns 1 if the given VCPU is up. */
+#define VCPUOP_is_up 3
+
+/*
+ * Return information about the state and running time of a VCPU.
+ * @extra_arg == pointer to vcpu_runstate_info structure.
+ */
+#define VCPUOP_get_runstate_info 4
+struct vcpu_runstate_info {
+ /* VCPU's current state (RUNSTATE_*). */
+ int state;
+ /* When was current state entered (system time, ns)? */
+ uint64_t state_entry_time;
+ /*
+ * Time spent in each RUNSTATE_* (ns). The sum of these times is
+ * guaranteed not to drift from system time.
+ */
+ uint64_t time[4];
+};
+
+/* VCPU is currently running on a physical CPU. */
+#define RUNSTATE_running 0
+
+/* VCPU is runnable, but not currently scheduled on any physical CPU. */
+#define RUNSTATE_runnable 1
+
+/* VCPU is blocked (a.k.a. idle). It is therefore not runnable. */
+#define RUNSTATE_blocked 2
+
+/*
+ * VCPU is not runnable, but it is not blocked.
+ * This is a 'catch all' state for things like hotplug and pauses by the
+ * system administrator (or for critical sections in the hypervisor).
+ * RUNSTATE_blocked dominates this state (it is the preferred state).
+ */
+#define RUNSTATE_offline 3
+
+/*
+ * Register a shared memory area from which the guest may obtain its own
+ * runstate information without needing to execute a hypercall.
+ * Notes:
+ * 1. The registered address may be virtual or physical, depending on the
+ * platform. The virtual address should be registered on x86 systems.
+ * 2. Only one shared area may be registered per VCPU. The shared area is
+ * updated by the hypervisor each time the VCPU is scheduled. Thus
+ * runstate.state will always be RUNSTATE_running and
+ * runstate.state_entry_time will indicate the system time at which the
+ * VCPU was last scheduled to run.
+ * @extra_arg == pointer to vcpu_register_runstate_memory_area structure.
+ */
+#define VCPUOP_register_runstate_memory_area 5
+struct vcpu_register_runstate_memory_area {
+ union {
+ struct vcpu_runstate_info *v;
+ uint64_t p;
+ } addr;
+};
+
+/*
+ * Set or stop a VCPU's periodic timer. Every VCPU has one periodic timer
+ * which can be set via these commands. Periods smaller than one millisecond
+ * may not be supported.
+ */
+#define VCPUOP_set_periodic_timer 6 /* arg == vcpu_set_periodic_timer_t */
+#define VCPUOP_stop_periodic_timer 7 /* arg == NULL */
+struct vcpu_set_periodic_timer {
+ uint64_t period_ns;
+};
+
+/*
+ * Set or stop a VCPU's single-shot timer. Every VCPU has one single-shot
+ * timer which can be set via these commands.
+ */
+#define VCPUOP_set_singleshot_timer 8 /* arg == vcpu_set_singleshot_timer_t */
+#define VCPUOP_stop_singleshot_timer 9 /* arg == NULL */
+struct vcpu_set_singleshot_timer {
+ uint64_t timeout_abs_ns;
+ uint32_t flags; /* VCPU_SSHOTTMR_??? */
+};
+
+/* Flags to VCPUOP_set_singleshot_timer. */
+ /* Require the timeout to be in the future (return -ETIME if it's passed). */
+#define _VCPU_SSHOTTMR_future (0)
+#define VCPU_SSHOTTMR_future (1U << _VCPU_SSHOTTMR_future)
+
+/*
+ * Register a memory location in the guest address space for the
+ * vcpu_info structure. This allows the guest to place the vcpu_info
+ * structure in a convenient place, such as in a per-cpu data area.
+ * The pointer need not be page aligned, but the structure must not
+ * cross a page boundary.
+ */
+#define VCPUOP_register_vcpu_info 10 /* arg == struct vcpu_info */
+struct vcpu_register_vcpu_info {
+ uint32_t mfn; /* mfn of page to place vcpu_info */
+ uint32_t offset; /* offset within page */
+};
+
+#endif /* __XEN_PUBLIC_VCPU_H__ */
diff --git a/include/xen/interface/version.h b/include/xen/interface/version.h
new file mode 100644
index 000000000000..453235e923f0
--- /dev/null
+++ b/include/xen/interface/version.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * version.h
+ *
+ * Xen version, type, and compile information.
+ *
+ * Copyright (c) 2005, Nguyen Anh Quynh <aquynh@gmail.com>
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_VERSION_H__
+#define __XEN_PUBLIC_VERSION_H__
+
+/* NB. All ops return zero on success, except XENVER_version. */
+
+/* arg == NULL; returns major:minor (16:16). */
+#define XENVER_version 0
+
+/* arg == xen_extraversion_t. */
+#define XENVER_extraversion 1
+struct xen_extraversion {
+ char extraversion[16];
+};
+#define XEN_EXTRAVERSION_LEN (sizeof(struct xen_extraversion))
+
+/* arg == xen_compile_info_t. */
+#define XENVER_compile_info 2
+struct xen_compile_info {
+ char compiler[64];
+ char compile_by[16];
+ char compile_domain[32];
+ char compile_date[32];
+};
+
+#define XENVER_capabilities 3
+struct xen_capabilities_info {
+ char info[1024];
+};
+#define XEN_CAPABILITIES_INFO_LEN (sizeof(struct xen_capabilities_info))
+
+#define XENVER_changeset 4
+struct xen_changeset_info {
+ char info[64];
+};
+#define XEN_CHANGESET_INFO_LEN (sizeof(struct xen_changeset_info))
+
+#define XENVER_platform_parameters 5
+struct xen_platform_parameters {
+ unsigned long virt_start;
+};
+
+#define XENVER_get_features 6
+struct xen_feature_info {
+ unsigned int submap_idx; /* IN: which 32-bit submap to return */
+ uint32_t submap; /* OUT: 32-bit submap */
+};
+
+/* Declares the features reported by XENVER_get_features. */
+#include "features.h"
+
+#endif /* __XEN_PUBLIC_VERSION_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
new file mode 100644
index 000000000000..518a5bf79ed3
--- /dev/null
+++ b/include/xen/interface/xen.h
@@ -0,0 +1,447 @@
+/******************************************************************************
+ * xen.h
+ *
+ * Guest OS interface to Xen.
+ *
+ * Copyright (c) 2004, K A Fraser
+ */
+
+#ifndef __XEN_PUBLIC_XEN_H__
+#define __XEN_PUBLIC_XEN_H__
+
+#include <asm/xen/interface.h>
+
+/*
+ * XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
+ */
+
+/*
+ * x86_32: EAX = vector; EBX, ECX, EDX, ESI, EDI = args 1, 2, 3, 4, 5.
+ * EAX = return value
+ * (argument registers may be clobbered on return)
+ * x86_64: RAX = vector; RDI, RSI, RDX, R10, R8, R9 = args 1, 2, 3, 4, 5, 6.
+ * RAX = return value
+ * (argument registers not clobbered on return; RCX, R11 are)
+ */
+#define __HYPERVISOR_set_trap_table 0
+#define __HYPERVISOR_mmu_update 1
+#define __HYPERVISOR_set_gdt 2
+#define __HYPERVISOR_stack_switch 3
+#define __HYPERVISOR_set_callbacks 4
+#define __HYPERVISOR_fpu_taskswitch 5
+#define __HYPERVISOR_sched_op 6
+#define __HYPERVISOR_dom0_op 7
+#define __HYPERVISOR_set_debugreg 8
+#define __HYPERVISOR_get_debugreg 9
+#define __HYPERVISOR_update_descriptor 10
+#define __HYPERVISOR_memory_op 12
+#define __HYPERVISOR_multicall 13
+#define __HYPERVISOR_update_va_mapping 14
+#define __HYPERVISOR_set_timer_op 15
+#define __HYPERVISOR_event_channel_op_compat 16
+#define __HYPERVISOR_xen_version 17
+#define __HYPERVISOR_console_io 18
+#define __HYPERVISOR_physdev_op_compat 19
+#define __HYPERVISOR_grant_table_op 20
+#define __HYPERVISOR_vm_assist 21
+#define __HYPERVISOR_update_va_mapping_otherdomain 22
+#define __HYPERVISOR_iret 23 /* x86 only */
+#define __HYPERVISOR_vcpu_op 24
+#define __HYPERVISOR_set_segment_base 25 /* x86/64 only */
+#define __HYPERVISOR_mmuext_op 26
+#define __HYPERVISOR_acm_op 27
+#define __HYPERVISOR_nmi_op 28
+#define __HYPERVISOR_sched_op_new 29
+#define __HYPERVISOR_callback_op 30
+#define __HYPERVISOR_xenoprof_op 31
+#define __HYPERVISOR_event_channel_op 32
+#define __HYPERVISOR_physdev_op 33
+#define __HYPERVISOR_hvm_op 34
+
+/*
+ * VIRTUAL INTERRUPTS
+ *
+ * Virtual interrupts that a guest OS may receive from Xen.
+ */
+#define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */
+#define VIRQ_DEBUG 1 /* Request guest to dump debug info. */
+#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
+
+/*
+ * MMU-UPDATE REQUESTS
+ *
+ * HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ * ptr[1:0] specifies the appropriate MMU_* command.
+ *
+ * ptr[1:0] == MMU_NORMAL_PT_UPDATE:
+ * Updates an entry in a page table. If updating an L1 table, and the new
+ * table entry is valid/present, the mapped frame must belong to the FD, if
+ * an FD has been specified. If attempting to map an I/O page then the
+ * caller assumes the privilege of the FD.
+ * FD == DOMID_IO: Permit /only/ I/O mappings, at the priv level of the caller.
+ * FD == DOMID_XEN: Map restricted areas of Xen's heap space.
+ * ptr[:2] -- Machine address of the page-table entry to modify.
+ * val -- Value to write.
+ *
+ * ptr[1:0] == MMU_MACHPHYS_UPDATE:
+ * Updates an entry in the machine->pseudo-physical mapping table.
+ * ptr[:2] -- Machine address within the frame whose mapping to modify.
+ * The frame must belong to the FD, if one is specified.
+ * val -- Value to write into the mapping entry.
+ */
+#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
+#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */
+
+/*
+ * MMU EXTENDED OPERATIONS
+ *
+ * HYPERVISOR_mmuext_op() accepts a list of mmuext_op structures.
+ * A foreigndom (FD) can be specified (or DOMID_SELF for none).
+ * Where the FD has some effect, it is described below.
+ *
+ * cmd: MMUEXT_(UN)PIN_*_TABLE
+ * mfn: Machine frame number to be (un)pinned as a p.t. page.
+ * The frame must belong to the FD, if one is specified.
+ *
+ * cmd: MMUEXT_NEW_BASEPTR
+ * mfn: Machine frame number of new page-table base to install in MMU.
+ *
+ * cmd: MMUEXT_NEW_USER_BASEPTR [x86/64 only]
+ * mfn: Machine frame number of new page-table base to install in MMU
+ * when in user space.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_LOCAL
+ * No additional arguments. Flushes local TLB.
+ *
+ * cmd: MMUEXT_INVLPG_LOCAL
+ * linear_addr: Linear address to be flushed from the local TLB.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_MULTI
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_INVLPG_MULTI
+ * linear_addr: Linear address to be flushed.
+ * vcpumask: Pointer to bitmap of VCPUs to be flushed.
+ *
+ * cmd: MMUEXT_TLB_FLUSH_ALL
+ * No additional arguments. Flushes all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_INVLPG_ALL
+ * linear_addr: Linear address to be flushed from all VCPUs' TLBs.
+ *
+ * cmd: MMUEXT_FLUSH_CACHE
+ * No additional arguments. Writes back and flushes cache contents.
+ *
+ * cmd: MMUEXT_SET_LDT
+ * linear_addr: Linear address of LDT base (NB. must be page-aligned).
+ * nr_ents: Number of entries in LDT.
+ */
+#define MMUEXT_PIN_L1_TABLE 0
+#define MMUEXT_PIN_L2_TABLE 1
+#define MMUEXT_PIN_L3_TABLE 2
+#define MMUEXT_PIN_L4_TABLE 3
+#define MMUEXT_UNPIN_TABLE 4
+#define MMUEXT_NEW_BASEPTR 5
+#define MMUEXT_TLB_FLUSH_LOCAL 6
+#define MMUEXT_INVLPG_LOCAL 7
+#define MMUEXT_TLB_FLUSH_MULTI 8
+#define MMUEXT_INVLPG_MULTI 9
+#define MMUEXT_TLB_FLUSH_ALL 10
+#define MMUEXT_INVLPG_ALL 11
+#define MMUEXT_FLUSH_CACHE 12
+#define MMUEXT_SET_LDT 13
+#define MMUEXT_NEW_USER_BASEPTR 15
+
+#ifndef __ASSEMBLY__
+struct mmuext_op {
+ unsigned int cmd;
+ union {
+ /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
+ unsigned long mfn;
+ /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
+ unsigned long linear_addr;
+ } arg1;
+ union {
+ /* SET_LDT */
+ unsigned int nr_ents;
+ /* TLB_FLUSH_MULTI, INVLPG_MULTI */
+ void *vcpumask;
+ } arg2;
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmuext_op);
+#endif
+
+/* These are passed as 'flags' to update_va_mapping. They can be ORed. */
+/* When specifying UVMF_MULTI, also OR in a pointer to a CPU bitmap. */
+/* UVMF_LOCAL is merely UVMF_MULTI with a NULL bitmap pointer. */
+#define UVMF_NONE (0UL<<0) /* No flushing at all. */
+#define UVMF_TLB_FLUSH (1UL<<0) /* Flush entire TLB(s). */
+#define UVMF_INVLPG (2UL<<0) /* Flush only one entry. */
+#define UVMF_FLUSHTYPE_MASK (3UL<<0)
+#define UVMF_MULTI (0UL<<2) /* Flush subset of TLBs. */
+#define UVMF_LOCAL (0UL<<2) /* Flush local TLB. */
+#define UVMF_ALL (1UL<<2) /* Flush all TLBs. */
+
+/*
+ * Commands to HYPERVISOR_console_io().
+ */
+#define CONSOLEIO_write 0
+#define CONSOLEIO_read 1
+
+/*
+ * Commands to HYPERVISOR_vm_assist().
+ */
+#define VMASST_CMD_enable 0
+#define VMASST_CMD_disable 1
+#define VMASST_TYPE_4gb_segments 0
+#define VMASST_TYPE_4gb_segments_notify 1
+#define VMASST_TYPE_writable_pagetables 2
+#define VMASST_TYPE_pae_extended_cr3 3
+#define MAX_VMASST_TYPE 3
+
+#ifndef __ASSEMBLY__
+
+typedef uint16_t domid_t;
+
+/* Domain ids >= DOMID_FIRST_RESERVED cannot be used for ordinary domains. */
+#define DOMID_FIRST_RESERVED (0x7FF0U)
+
+/* DOMID_SELF is used in certain contexts to refer to oneself. */
+#define DOMID_SELF (0x7FF0U)
+
+/*
+ * DOMID_IO is used to restrict page-table updates to mapping I/O memory.
+ * Although no Foreign Domain need be specified to map I/O pages, DOMID_IO
+ * is useful to ensure that no mappings to the OS's own heap are accidentally
+ * installed. (e.g., in Linux this could cause havoc as reference counts
+ * aren't adjusted on the I/O-mapping code path).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, but in that context can
+ * be specified by any calling domain.
+ */
+#define DOMID_IO (0x7FF1U)
+
+/*
+ * DOMID_XEN is used to allow privileged domains to map restricted parts of
+ * Xen's heap space (e.g., the machine_to_phys table).
+ * This only makes sense in MMUEXT_SET_FOREIGNDOM, and is only permitted if
+ * the caller is privileged.
+ */
+#define DOMID_XEN (0x7FF2U)
+
+/*
+ * Send an array of these to HYPERVISOR_mmu_update().
+ * NB. The fields are natural pointer/address size for this architecture.
+ */
+struct mmu_update {
+ uint64_t ptr; /* Machine address of PTE. */
+ uint64_t val; /* New contents of PTE. */
+};
+DEFINE_GUEST_HANDLE_STRUCT(mmu_update);
+
+/*
+ * Send an array of these to HYPERVISOR_multicall().
+ * NB. The fields are natural register size for this architecture.
+ */
+struct multicall_entry {
+ unsigned long op;
+ long result;
+ unsigned long args[6];
+};
+DEFINE_GUEST_HANDLE_STRUCT(multicall_entry);
+
+/*
+ * Event channel endpoints per domain:
+ * 1024 if a long is 32 bits; 4096 if a long is 64 bits.
+ */
+#define NR_EVENT_CHANNELS (sizeof(unsigned long) * sizeof(unsigned long) * 64)
+
+struct vcpu_time_info {
+ /*
+ * Updates to the following values are preceded and followed
+ * by an increment of 'version'. The guest can therefore
+ * detect updates by looking for changes to 'version'. If the
+ * least-significant bit of the version number is set then an
+ * update is in progress and the guest must wait to read a
+ * consistent set of values. The correct way to interact with
+ * the version number is similar to Linux's seqlock: see the
+ * implementations of read_seqbegin/read_seqretry.
+ */
+ uint32_t version;
+ uint32_t pad0;
+ uint64_t tsc_timestamp; /* TSC at last update of time vals. */
+ uint64_t system_time; /* Time, in nanosecs, since boot. */
+ /*
+ * Current system time:
+ * system_time + ((tsc - tsc_timestamp) << tsc_shift) * tsc_to_system_mul
+ * CPU frequency (Hz):
+ * ((10^9 << 32) / tsc_to_system_mul) >> tsc_shift
+ */
+ uint32_t tsc_to_system_mul;
+ int8_t tsc_shift;
+ int8_t pad1[3];
+}; /* 32 bytes */
+
+struct vcpu_info {
+ /*
+ * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
+ * a pending notification for a particular VCPU. It is then cleared
+ * by the guest OS /before/ checking for pending work, thus avoiding
+ * a set-and-check race. Note that the mask is only accessed by Xen
+ * on the CPU that is currently hosting the VCPU. This means that the
+ * pending and mask flags can be updated by the guest without special
+ * synchronisation (i.e., no need for the x86 LOCK prefix).
+ * This may seem suboptimal because if the pending flag is set by
+ * a different CPU then an IPI may be scheduled even when the mask
+ * is set. However, note:
+ * 1. The task of 'interrupt holdoff' is covered by the per-event-
+ * channel mask bits. A 'noisy' event that is continually being
+ * triggered can be masked at source at this very precise
+ * granularity.
+ * 2. The main purpose of the per-VCPU mask is therefore to restrict
+ * reentrant execution: whether for concurrency control, or to
+ * prevent unbounded stack usage. Whatever the purpose, we expect
+ * that the mask will be asserted only for short periods at a time,
+ * and so the likelihood of a 'spurious' IPI is suitably small.
+ * The mask is read before making an event upcall to the guest: a
+ * non-zero mask therefore guarantees that the VCPU will not receive
+ * an upcall activation. The mask is cleared when the VCPU requests
+ * to block: this avoids wakeup-waiting races.
+ */
+ uint8_t evtchn_upcall_pending;
+ uint8_t evtchn_upcall_mask;
+ unsigned long evtchn_pending_sel;
+ struct arch_vcpu_info arch;
+ struct vcpu_time_info time;
+}; /* 64 bytes (x86) */
+
+/*
+ * Xen/kernel shared data -- pointer provided in start_info.
+ * NB. We expect that this struct is smaller than a page.
+ */
+struct shared_info {
+ struct vcpu_info vcpu_info[MAX_VIRT_CPUS];
+
+ /*
+ * A domain can create "event channels" on which it can send and receive
+ * asynchronous event notifications. There are three classes of event that
+ * are delivered by this mechanism:
+ * 1. Bi-directional inter- and intra-domain connections. Domains must
+ * arrange out-of-band to set up a connection (usually by allocating
+ * an unbound 'listener' port and avertising that via a storage service
+ * such as xenstore).
+ * 2. Physical interrupts. A domain with suitable hardware-access
+ * privileges can bind an event-channel port to a physical interrupt
+ * source.
+ * 3. Virtual interrupts ('events'). A domain can bind an event-channel
+ * port to a virtual interrupt source, such as the virtual-timer
+ * device or the emergency console.
+ *
+ * Event channels are addressed by a "port index". Each channel is
+ * associated with two bits of information:
+ * 1. PENDING -- notifies the domain that there is a pending notification
+ * to be processed. This bit is cleared by the guest.
+ * 2. MASK -- if this bit is clear then a 0->1 transition of PENDING
+ * will cause an asynchronous upcall to be scheduled. This bit is only
+ * updated by the guest. It is read-only within Xen. If a channel
+ * becomes pending while the channel is masked then the 'edge' is lost
+ * (i.e., when the channel is unmasked, the guest must manually handle
+ * pending notifications as no upcall will be scheduled by Xen).
+ *
+ * To expedite scanning of pending notifications, any 0->1 pending
+ * transition on an unmasked channel causes a corresponding bit in a
+ * per-vcpu selector word to be set. Each bit in the selector covers a
+ * 'C long' in the PENDING bitfield array.
+ */
+ unsigned long evtchn_pending[sizeof(unsigned long) * 8];
+ unsigned long evtchn_mask[sizeof(unsigned long) * 8];
+
+ /*
+ * Wallclock time: updated only by control software. Guests should base
+ * their gettimeofday() syscall on this wallclock-base value.
+ */
+ uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
+ uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
+ uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
+
+ struct arch_shared_info arch;
+
+};
+
+/*
+ * Start-of-day memory layout for the initial domain (DOM0):
+ * 1. The domain is started within contiguous virtual-memory region.
+ * 2. The contiguous region begins and ends on an aligned 4MB boundary.
+ * 3. The region start corresponds to the load address of the OS image.
+ * If the load address is not 4MB aligned then the address is rounded down.
+ * 4. This the order of bootstrap elements in the initial virtual region:
+ * a. relocated kernel image
+ * b. initial ram disk [mod_start, mod_len]
+ * c. list of allocated page frames [mfn_list, nr_pages]
+ * d. start_info_t structure [register ESI (x86)]
+ * e. bootstrap page tables [pt_base, CR3 (x86)]
+ * f. bootstrap stack [register ESP (x86)]
+ * 5. Bootstrap elements are packed together, but each is 4kB-aligned.
+ * 6. The initial ram disk may be omitted.
+ * 7. The list of page frames forms a contiguous 'pseudo-physical' memory
+ * layout for the domain. In particular, the bootstrap virtual-memory
+ * region is a 1:1 mapping to the first section of the pseudo-physical map.
+ * 8. All bootstrap elements are mapped read-writable for the guest OS. The
+ * only exception is the bootstrap page table, which is mapped read-only.
+ * 9. There is guaranteed to be at least 512kB padding after the final
+ * bootstrap element. If necessary, the bootstrap virtual region is
+ * extended by an extra 4MB to ensure this.
+ */
+
+#define MAX_GUEST_CMDLINE 1024
+struct start_info {
+ /* THE FOLLOWING ARE FILLED IN BOTH ON INITIAL BOOT AND ON RESUME. */
+ char magic[32]; /* "xen-<version>-<platform>". */
+ unsigned long nr_pages; /* Total pages allocated to this domain. */
+ unsigned long shared_info; /* MACHINE address of shared info struct. */
+ uint32_t flags; /* SIF_xxx flags. */
+ unsigned long store_mfn; /* MACHINE page number of shared page. */
+ uint32_t store_evtchn; /* Event channel for store communication. */
+ union {
+ struct {
+ unsigned long mfn; /* MACHINE page number of console page. */
+ uint32_t evtchn; /* Event channel for console page. */
+ } domU;
+ struct {
+ uint32_t info_off; /* Offset of console_info struct. */
+ uint32_t info_size; /* Size of console_info struct from start.*/
+ } dom0;
+ } console;
+ /* THE FOLLOWING ARE ONLY FILLED IN ON INITIAL BOOT (NOT RESUME). */
+ unsigned long pt_base; /* VIRTUAL address of page directory. */
+ unsigned long nr_pt_frames; /* Number of bootstrap p.t. frames. */
+ unsigned long mfn_list; /* VIRTUAL address of page-frame list. */
+ unsigned long mod_start; /* VIRTUAL address of pre-loaded module. */
+ unsigned long mod_len; /* Size (bytes) of pre-loaded module. */
+ int8_t cmd_line[MAX_GUEST_CMDLINE];
+};
+
+/* These flags are passed in the 'flags' field of start_info_t. */
+#define SIF_PRIVILEGED (1<<0) /* Is the domain privileged? */
+#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
+
+typedef uint64_t cpumap_t;
+
+typedef uint8_t xen_domain_handle_t[16];
+
+/* Turn a plain number into a C unsigned long constant. */
+#define __mk_unsigned_long(x) x ## UL
+#define mk_unsigned_long(x) __mk_unsigned_long(x)
+
+#else /* __ASSEMBLY__ */
+
+/* In assembly code we cannot use C numeric constant suffixes. */
+#define mk_unsigned_long(x) x
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* __XEN_PUBLIC_XEN_H__ */
diff --git a/include/xen/page.h b/include/xen/page.h
new file mode 100644
index 000000000000..1df6c1930578
--- /dev/null
+++ b/include/xen/page.h
@@ -0,0 +1,179 @@
+#ifndef __XEN_PAGE_H
+#define __XEN_PAGE_H
+
+#include <linux/pfn.h>
+
+#include <asm/uaccess.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 ((unsigned long long)x.pte_high << 32) | x.pte_low;
+}
+#define pmd_val_ma(v) ((v).pmd)
+#define pud_val_ma(v) ((v).pgd.pgd)
+#define __pte_ma(x) ((pte_t) { .pte_low = (x), .pte_high = (x)>>32 } )
+#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_low)
+#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 */
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
new file mode 100644
index 000000000000..6f7c290651ae
--- /dev/null
+++ b/include/xen/xenbus.h
@@ -0,0 +1,234 @@
+/******************************************************************************
+ * xenbus.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource 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; 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_XENBUS_H
+#define _XEN_XENBUS_H
+
+#include <linux/device.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/xenbus.h>
+#include <xen/interface/io/xs_wire.h>
+
+/* Register callback to watch this node. */
+struct xenbus_watch
+{
+ struct list_head list;
+
+ /* Path being watched. */
+ const char *node;
+
+ /* Callback (executed in a process context with no locks held). */
+ void (*callback)(struct xenbus_watch *,
+ const char **vec, unsigned int len);
+};
+
+
+/* A xenbus device. */
+struct xenbus_device {
+ const char *devicetype;
+ const char *nodename;
+ const char *otherend;
+ int otherend_id;
+ struct xenbus_watch otherend_watch;
+ struct device dev;
+ enum xenbus_state state;
+ struct completion down;
+};
+
+static inline struct xenbus_device *to_xenbus_device(struct device *dev)
+{
+ return container_of(dev, struct xenbus_device, dev);
+}
+
+struct xenbus_device_id
+{
+ /* .../device/<device_type>/<identifier> */
+ char devicetype[32]; /* General class of device. */
+};
+
+/* A xenbus driver. */
+struct xenbus_driver {
+ char *name;
+ struct module *owner;
+ const struct xenbus_device_id *ids;
+ int (*probe)(struct xenbus_device *dev,
+ const struct xenbus_device_id *id);
+ void (*otherend_changed)(struct xenbus_device *dev,
+ enum xenbus_state backend_state);
+ int (*remove)(struct xenbus_device *dev);
+ int (*suspend)(struct xenbus_device *dev);
+ int (*suspend_cancel)(struct xenbus_device *dev);
+ int (*resume)(struct xenbus_device *dev);
+ int (*uevent)(struct xenbus_device *, char **, int, char *, int);
+ struct device_driver driver;
+ int (*read_otherend_details)(struct xenbus_device *dev);
+};
+
+static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct xenbus_driver, driver);
+}
+
+int __must_check __xenbus_register_frontend(struct xenbus_driver *drv,
+ struct module *owner,
+ const char *mod_name);
+
+static inline int __must_check
+xenbus_register_frontend(struct xenbus_driver *drv)
+{
+ WARN_ON(drv->owner != THIS_MODULE);
+ return __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+int __must_check __xenbus_register_backend(struct xenbus_driver *drv,
+ struct module *owner,
+ const char *mod_name);
+static inline int __must_check
+xenbus_register_backend(struct xenbus_driver *drv)
+{
+ WARN_ON(drv->owner != THIS_MODULE);
+ return __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME);
+}
+
+void xenbus_unregister_driver(struct xenbus_driver *drv);
+
+struct xenbus_transaction
+{
+ u32 id;
+};
+
+/* Nil transaction ID. */
+#define XBT_NIL ((struct xenbus_transaction) { 0 })
+
+int __init xenbus_dev_init(void);
+
+char **xenbus_directory(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *num);
+void *xenbus_read(struct xenbus_transaction t,
+ const char *dir, const char *node, unsigned int *len);
+int xenbus_write(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *string);
+int xenbus_mkdir(struct xenbus_transaction t,
+ const char *dir, const char *node);
+int xenbus_exists(struct xenbus_transaction t,
+ const char *dir, const char *node);
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node);
+int xenbus_transaction_start(struct xenbus_transaction *t);
+int xenbus_transaction_end(struct xenbus_transaction t, int abort);
+
+/* Single read and scanf: returns -errno or num scanned if > 0. */
+int xenbus_scanf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+ __attribute__((format(scanf, 4, 5)));
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+ const char *dir, const char *node, const char *fmt, ...)
+ __attribute__((format(printf, 4, 5)));
+
+/* Generic read function: NULL-terminated triples of name,
+ * sprintf-style type string, and pointer. Returns 0 or errno.*/
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...);
+
+/* notifer routines for when the xenstore comes up */
+extern int xenstored_ready;
+int register_xenstore_notifier(struct notifier_block *nb);
+void unregister_xenstore_notifier(struct notifier_block *nb);
+
+int register_xenbus_watch(struct xenbus_watch *watch);
+void unregister_xenbus_watch(struct xenbus_watch *watch);
+void xs_suspend(void);
+void xs_resume(void);
+void xs_suspend_cancel(void);
+
+/* Used by xenbus_dev to borrow kernel's store connection. */
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg);
+
+struct work_struct;
+
+/* Prepare for domain suspend: then resume or cancel the suspend. */
+void xenbus_suspend(void);
+void xenbus_resume(void);
+void xenbus_probe(struct work_struct *);
+void xenbus_suspend_cancel(void);
+
+#define XENBUS_IS_ERR_READ(str) ({ \
+ if (!IS_ERR(str) && strlen(str) == 0) { \
+ kfree(str); \
+ str = ERR_PTR(-ERANGE); \
+ } \
+ IS_ERR(str); \
+})
+
+#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE)
+
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+ struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int));
+int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
+ void (*callback)(struct xenbus_watch *,
+ const char **, unsigned int),
+ const char *pathfmt, ...)
+ __attribute__ ((format (printf, 4, 5)));
+
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn);
+int xenbus_map_ring_valloc(struct xenbus_device *dev,
+ int gnt_ref, void **vaddr);
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+ grant_handle_t *handle, void *vaddr);
+
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
+int xenbus_unmap_ring(struct xenbus_device *dev,
+ grant_handle_t handle, void *vaddr);
+
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port);
+int xenbus_free_evtchn(struct xenbus_device *dev, int port);
+
+enum xenbus_state xenbus_read_driver_state(const char *path);
+
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...);
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...);
+
+const char *xenbus_strstate(enum xenbus_state state);
+int xenbus_dev_is_online(struct xenbus_device *dev);
+int xenbus_frontend_closed(struct xenbus_device *dev);
+
+#endif /* _XEN_XENBUS_H */
diff --git a/init/Kconfig b/init/Kconfig
index d9d878a3bb46..e2056828dc64 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -120,15 +120,6 @@ config SYSVIPC
section 6.4 of the Linux Programmer's Guide, available from
<http://www.tldp.org/guides.html>.
-config IPC_NS
- bool "IPC Namespaces"
- depends on SYSVIPC
- default n
- help
- Support ipc namespaces. This allows containers, i.e. virtual
- environments, to use ipc namespaces to provide different ipc
- objects for different servers. If unsure, say N.
-
config SYSVIPC_SYSCTL
bool
depends on SYSVIPC
@@ -218,13 +209,14 @@ config TASK_IO_ACCOUNTING
Say N if unsure.
-config UTS_NS
- bool "UTS Namespaces"
+config USER_NS
+ bool "User Namespaces (EXPERIMENTAL)"
default n
+ depends on EXPERIMENTAL
help
- Support uts namespaces. This allows containers, i.e.
- vservers, to use uts namespaces to provide different
- uts info for different servers. If unsure, say N.
+ Support user namespaces. This allows containers, i.e.
+ vservers, to use user namespaces to provide different
+ user info for different servers. If unsure, say N.
config AUDIT
bool "Auditing support"
@@ -554,7 +546,7 @@ config SLUB_DEBUG
choice
prompt "Choose SLAB allocator"
- default SLAB
+ default SLUB
help
This option allows to select a slab allocator.
@@ -576,7 +568,7 @@ config SLUB
and has enhanced diagnostics.
config SLOB
- depends on EMBEDDED && !SPARSEMEM
+ depends on EMBEDDED
bool "SLOB (Simple Allocator)"
help
SLOB replaces the SLAB allocator with a drastically simpler
@@ -602,9 +594,7 @@ config BASE_SMALL
default 0 if BASE_FULL
default 1 if !BASE_FULL
-menu "Loadable module support"
-
-config MODULES
+menuconfig MODULES
bool "Enable loadable module support"
help
Kernel modules are small pieces of compiled code which can
@@ -684,6 +674,5 @@ config STOP_MACHINE
depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU
help
Need stop_machine() primitive.
-endmenu
source "block/Kconfig"
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 46fe407fb03e..4efa1e5385e3 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -25,6 +25,7 @@ int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */
int root_mountflags = MS_RDONLY | MS_SILENT;
char * __initdata root_device_name;
static char __initdata saved_root_name[64];
+static int __initdata root_wait;
dev_t ROOT_DEV;
@@ -216,6 +217,16 @@ static int __init root_dev_setup(char *line)
__setup("root=", root_dev_setup);
+static int __init rootwait_setup(char *str)
+{
+ if (*str)
+ return 0;
+ root_wait = 1;
+ return 1;
+}
+
+__setup("rootwait", rootwait_setup);
+
static char * __initdata root_mount_data;
static int __init root_data_setup(char *str)
{
@@ -438,11 +449,20 @@ void __init prepare_namespace(void)
root_device_name += 5;
}
- is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
-
if (initrd_load())
goto out;
+ /* wait for any asynchronous scanning to complete */
+ if ((ROOT_DEV == 0) && root_wait) {
+ printk(KERN_INFO "Waiting for root device %s...\n",
+ saved_root_name);
+ while (driver_probe_done() != 0 ||
+ (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
+ msleep(100);
+ }
+
+ is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
+
if (is_floppy && rd_doload && rd_load_disk(0))
ROOT_DEV = Root_RAM0;
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index b222ce9e1c8b..a6b4c0c08e13 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -56,12 +56,9 @@ static void __init handle_initrd(void)
sys_chroot(".");
pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
- if (pid > 0) {
- while (pid != sys_wait4(-1, NULL, 0, NULL)) {
- try_to_freeze();
+ if (pid > 0)
+ while (pid != sys_wait4(-1, NULL, 0, NULL))
yield();
- }
- }
/* move initrd to rootfs' /old */
sys_fchdir(old_fd);
diff --git a/init/main.c b/init/main.c
index 0eb1c7463fe4..d3bcb3b11620 100644
--- a/init/main.c
+++ b/init/main.c
@@ -132,20 +132,9 @@ static char *static_command_line;
static char *execute_command;
static char *ramdisk_execute_command;
+#ifdef CONFIG_SMP
/* Setup configured maximum number of CPUs to activate */
-static unsigned int max_cpus = NR_CPUS;
-
-/*
- * If set, this is an indication to the drivers that reset the underlying
- * device before going ahead with the initialization otherwise driver might
- * rely on the BIOS and skip the reset operation.
- *
- * This is useful if kernel is booting in an unreliable environment.
- * For ex. kdump situaiton where previous kernel has crashed, BIOS has been
- * skipped and devices will be in unknown state.
- */
-unsigned int reset_devices;
-EXPORT_SYMBOL(reset_devices);
+static unsigned int __initdata max_cpus = NR_CPUS;
/*
* Setup routine for controlling SMP activation
@@ -160,10 +149,10 @@ EXPORT_SYMBOL(reset_devices);
static int __init nosmp(char *str)
{
max_cpus = 0;
- return 1;
+ return 0;
}
-__setup("nosmp", nosmp);
+early_param("nosmp", nosmp);
static int __init maxcpus(char *str)
{
@@ -172,6 +161,21 @@ static int __init maxcpus(char *str)
}
__setup("maxcpus=", maxcpus);
+#else
+#define max_cpus NR_CPUS
+#endif
+
+/*
+ * If set, this is an indication to the drivers that reset the underlying
+ * device before going ahead with the initialization otherwise driver might
+ * rely on the BIOS and skip the reset operation.
+ *
+ * This is useful if kernel is booting in an unreliable environment.
+ * For ex. kdump situaiton where previous kernel has crashed, BIOS has been
+ * skipped and devices will be in unknown state.
+ */
+unsigned int reset_devices;
+EXPORT_SYMBOL(reset_devices);
static int __init set_reset_devices(char *str)
{
@@ -385,6 +389,10 @@ static void __init smp_init(void)
{
unsigned int cpu;
+#ifndef CONFIG_HOTPLUG_CPU
+ cpu_possible_map = cpu_present_map;
+#endif
+
/* FIXME: This should be done in userspace --RR */
for_each_present_cpu(cpu) {
if (num_online_cpus() >= max_cpus)
@@ -453,7 +461,10 @@ static int __init do_early_param(char *param, char *val)
struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) {
- if (p->early && strcmp(param, p->str) == 0) {
+ if ((p->early && strcmp(param, p->str) == 0) ||
+ (strcmp(param, "console") == 0 &&
+ strcmp(p->str, "earlycon") == 0)
+ ) {
if (p->setup_func(val) != 0)
printk(KERN_WARNING
"Malformed early option '%s'\n", param);
@@ -526,6 +537,10 @@ asmlinkage void __init start_kernel(void)
setup_arch(&command_line);
setup_command_line(command_line);
unwind_setup();
+#ifndef CONFIG_HOTPLUG_CPU
+ if (max_cpus < 2)
+ cpu_possible_map = cpu_online_map;
+#endif
setup_per_cpu_areas();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
@@ -725,6 +740,15 @@ static void __init do_basic_setup(void)
do_initcalls();
}
+static int __initdata nosoftlockup;
+
+static int __init nosoftlockup_setup(char *str)
+{
+ nosoftlockup = 1;
+ return 1;
+}
+__setup("nosoftlockup", nosoftlockup_setup);
+
static void __init do_pre_smp_initcalls(void)
{
extern int spawn_ksoftirqd(void);
@@ -734,7 +758,8 @@ static void __init do_pre_smp_initcalls(void)
migration_init();
#endif
spawn_ksoftirqd();
- spawn_softlockup_task();
+ if (!nosoftlockup)
+ spawn_softlockup_task();
}
static void run_init_process(char *init_filename)
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index a242c83d89d6..145d5a0d299f 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1253,7 +1253,7 @@ static int __init init_mqueue_fs(void)
mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
sizeof(struct mqueue_inode_info), 0,
- SLAB_HWCACHE_ALIGN, init_once, NULL);
+ SLAB_HWCACHE_ALIGN, init_once);
if (mqueue_inode_cachep == NULL)
return -ENOMEM;
diff --git a/ipc/msg.c b/ipc/msg.c
index a388824740e7..a03fcb522fff 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -87,7 +87,7 @@ static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
#endif
-static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
+static void __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
{
ns->ids[IPC_MSG_IDS] = ids;
ns->msg_ctlmax = MSGMAX;
@@ -96,7 +96,6 @@ static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *i
ipc_init_ids(ids, ns->msg_ctlmni);
}
-#ifdef CONFIG_IPC_NS
int msg_init_ns(struct ipc_namespace *ns)
{
struct ipc_ids *ids;
@@ -128,7 +127,6 @@ void msg_exit_ns(struct ipc_namespace *ns)
kfree(ns->ids[IPC_MSG_IDS]);
ns->ids[IPC_MSG_IDS] = NULL;
}
-#endif
void __init msg_init(void)
{
@@ -387,7 +385,7 @@ copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version)
asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
{
struct kern_ipc_perm *ipcp;
- struct msq_setbuf setbuf;
+ struct msq_setbuf uninitialized_var(setbuf);
struct msg_queue *msq;
int err, version;
struct ipc_namespace *ns;
@@ -511,7 +509,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
err = audit_ipc_obj(ipcp);
if (err)
goto out_unlock_up;
- if (cmd==IPC_SET) {
+ if (cmd == IPC_SET) {
err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid,
setbuf.mode);
if (err)
diff --git a/ipc/sem.c b/ipc/sem.c
index 9964b2224c70..b676fef6d208 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -121,7 +121,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
#define sc_semopm sem_ctls[2]
#define sc_semmni sem_ctls[3]
-static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
+static void __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
{
ns->ids[IPC_SEM_IDS] = ids;
ns->sc_semmsl = SEMMSL;
@@ -132,7 +132,6 @@ static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *i
ipc_init_ids(ids, ns->sc_semmni);
}
-#ifdef CONFIG_IPC_NS
int sem_init_ns(struct ipc_namespace *ns)
{
struct ipc_ids *ids;
@@ -164,7 +163,6 @@ void sem_exit_ns(struct ipc_namespace *ns)
kfree(ns->ids[IPC_SEM_IDS]);
ns->ids[IPC_SEM_IDS] = NULL;
}
-#endif
void __init sem_init (void)
{
@@ -858,7 +856,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
{
struct sem_array *sma;
int err;
- struct sem_setbuf setbuf;
+ struct sem_setbuf uninitialized_var(setbuf);
struct kern_ipc_perm *ipcp;
if(cmd == IPC_SET) {
diff --git a/ipc/shm.c b/ipc/shm.c
index 0852f206d895..d0259e3ad1c0 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -77,7 +77,7 @@ static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
#endif
-static void __ipc_init __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
+static void __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
{
ns->ids[IPC_SHM_IDS] = ids;
ns->shm_ctlmax = SHMMAX;
@@ -98,7 +98,6 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
shm_destroy(ns, shp);
}
-#ifdef CONFIG_IPC_NS
int shm_init_ns(struct ipc_namespace *ns)
{
struct ipc_ids *ids;
@@ -130,7 +129,6 @@ void shm_exit_ns(struct ipc_namespace *ns)
kfree(ns->ids[IPC_SHM_IDS]);
ns->ids[IPC_SHM_IDS] = NULL;
}
-#endif
void __init shm_init (void)
{
@@ -226,13 +224,12 @@ static void shm_close(struct vm_area_struct *vma)
mutex_unlock(&shm_ids(ns).mutex);
}
-static struct page *shm_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct file *file = vma->vm_file;
struct shm_file_data *sfd = shm_file_data(file);
- return sfd->vm_ops->nopage(vma, address, type);
+ return sfd->vm_ops->fault(vma, vmf);
}
#ifdef CONFIG_NUMA
@@ -271,6 +268,7 @@ static int shm_mmap(struct file * file, struct vm_area_struct * vma)
if (ret != 0)
return ret;
sfd->vm_ops = vma->vm_ops;
+ BUG_ON(!sfd->vm_ops->fault);
vma->vm_ops = &shm_vm_ops;
shm_open(vma);
@@ -329,7 +327,7 @@ static const struct file_operations shm_file_operations = {
static struct vm_operations_struct shm_vm_ops = {
.open = shm_open, /* callback for a new vm-area open */
.close = shm_close, /* callback for when the vm-area is released */
- .nopage = shm_nopage,
+ .fault = shm_fault,
#if defined(CONFIG_NUMA)
.set_policy = shm_set_policy,
.get_policy = shm_get_policy,
diff --git a/ipc/util.c b/ipc/util.c
index 7536a7292d48..44e5135aee47 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -50,7 +50,6 @@ struct ipc_namespace init_ipc_ns = {
},
};
-#ifdef CONFIG_IPC_NS
static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
{
int err;
@@ -110,14 +109,6 @@ void free_ipc_ns(struct kref *kref)
shm_exit_ns(ns);
kfree(ns);
}
-#else
-struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
-{
- if (flags & CLONE_NEWIPC)
- return ERR_PTR(-EINVAL);
- return ns;
-}
-#endif
/**
* ipc_init - initialise IPC subsystem
@@ -145,7 +136,7 @@ __initcall(ipc_init);
* array itself.
*/
-void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size)
+void ipc_init_ids(struct ipc_ids* ids, int size)
{
int i;
diff --git a/ipc/util.h b/ipc/util.h
index e3aa2c5c97dc..333e891bcaca 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -41,12 +41,8 @@ struct ipc_ids {
};
struct seq_file;
-#ifdef CONFIG_IPC_NS
-#define __ipc_init
-#else
-#define __ipc_init __init
-#endif
-void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size);
+
+void ipc_init_ids(struct ipc_ids *ids, int size);
#ifdef CONFIG_PROC_FS
void __init ipc_init_proc_interface(const char *path, const char *header,
int ids, int (*show)(struct seq_file *, void *));
diff --git a/kernel/Makefile b/kernel/Makefile
index 642d4277c2ea..2a999836ca18 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -4,11 +4,12 @@
obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
exit.o itimer.o time.o softirq.o resource.o \
- sysctl.o capability.o ptrace.o timer.o user.o \
+ sysctl.o capability.o ptrace.o timer.o user.o user_namespace.o \
signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
- hrtimer.o rwsem.o latency.o nsproxy.o srcu.o die_notifier.o
+ hrtimer.o rwsem.o latency.o nsproxy.o srcu.o die_notifier.o \
+ utsname.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += time/
@@ -48,7 +49,6 @@ obj-$(CONFIG_SECCOMP) += seccomp.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
obj-$(CONFIG_RELAY) += relay.o
obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
-obj-$(CONFIG_UTS_NS) += utsname.o
obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
diff --git a/kernel/audit.c b/kernel/audit.c
index d13276d41410..eb0f9165b401 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -58,6 +58,7 @@
#include <linux/selinux.h>
#include <linux/inotify.h>
#include <linux/freezer.h>
+#include <linux/tty.h>
#include "audit.h"
@@ -391,6 +392,7 @@ static int kauditd_thread(void *dummy)
{
struct sk_buff *skb;
+ set_freezable();
while (!kthread_should_stop()) {
skb = skb_dequeue(&audit_skb_queue);
wake_up(&audit_backlog_wait);
@@ -423,6 +425,31 @@ static int kauditd_thread(void *dummy)
return 0;
}
+static int audit_prepare_user_tty(pid_t pid, uid_t loginuid)
+{
+ struct task_struct *tsk;
+ int err;
+
+ read_lock(&tasklist_lock);
+ tsk = find_task_by_pid(pid);
+ err = -ESRCH;
+ if (!tsk)
+ goto out;
+ err = 0;
+
+ spin_lock_irq(&tsk->sighand->siglock);
+ if (!tsk->signal->audit_tty)
+ err = -EPERM;
+ spin_unlock_irq(&tsk->sighand->siglock);
+ if (err)
+ goto out;
+
+ tty_audit_push_task(tsk, loginuid);
+out:
+ read_unlock(&tasklist_lock);
+ return err;
+}
+
int audit_send_list(void *_dest)
{
struct audit_netlink_list *dest = _dest;
@@ -511,6 +538,8 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
case AUDIT_DEL:
case AUDIT_DEL_RULE:
case AUDIT_SIGNAL_INFO:
+ case AUDIT_TTY_GET:
+ case AUDIT_TTY_SET:
if (security_netlink_recv(skb, CAP_AUDIT_CONTROL))
err = -EPERM;
break;
@@ -622,6 +651,11 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
err = audit_filter_user(&NETLINK_CB(skb), msg_type);
if (err == 1) {
err = 0;
+ if (msg_type == AUDIT_USER_TTY) {
+ err = audit_prepare_user_tty(pid, loginuid);
+ if (err)
+ break;
+ }
ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
if (ab) {
audit_log_format(ab,
@@ -638,8 +672,17 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
" subj=%s", ctx);
kfree(ctx);
}
- audit_log_format(ab, " msg='%.1024s'",
- (char *)data);
+ if (msg_type != AUDIT_USER_TTY)
+ audit_log_format(ab, " msg='%.1024s'",
+ (char *)data);
+ else {
+ int size;
+
+ audit_log_format(ab, " msg=");
+ size = nlmsg_len(nlh);
+ audit_log_n_untrustedstring(ab, size,
+ data);
+ }
audit_set_pid(ab, pid);
audit_log_end(ab);
}
@@ -730,6 +773,45 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
0, 0, sig_data, sizeof(*sig_data) + len);
kfree(sig_data);
break;
+ case AUDIT_TTY_GET: {
+ struct audit_tty_status s;
+ struct task_struct *tsk;
+
+ read_lock(&tasklist_lock);
+ tsk = find_task_by_pid(pid);
+ if (!tsk)
+ err = -ESRCH;
+ else {
+ spin_lock_irq(&tsk->sighand->siglock);
+ s.enabled = tsk->signal->audit_tty != 0;
+ spin_unlock_irq(&tsk->sighand->siglock);
+ }
+ read_unlock(&tasklist_lock);
+ audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_TTY_GET, 0, 0,
+ &s, sizeof(s));
+ break;
+ }
+ case AUDIT_TTY_SET: {
+ struct audit_tty_status *s;
+ struct task_struct *tsk;
+
+ if (nlh->nlmsg_len < sizeof(struct audit_tty_status))
+ return -EINVAL;
+ s = data;
+ if (s->enabled != 0 && s->enabled != 1)
+ return -EINVAL;
+ read_lock(&tasklist_lock);
+ tsk = find_task_by_pid(pid);
+ if (!tsk)
+ err = -ESRCH;
+ else {
+ spin_lock_irq(&tsk->sighand->siglock);
+ tsk->signal->audit_tty = s->enabled != 0;
+ spin_unlock_irq(&tsk->sighand->siglock);
+ }
+ read_unlock(&tasklist_lock);
+ break;
+ }
default:
err = -EINVAL;
break;
@@ -1185,7 +1267,7 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
}
/**
- * audit_log_n_unstrustedstring - log a string that may contain random characters
+ * audit_log_n_untrustedstring - log a string that may contain random characters
* @ab: audit_buffer
* @len: lenth of string (not including trailing null)
* @string: string to be logged
@@ -1201,25 +1283,24 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
const char *string)
{
- const unsigned char *p = string;
+ const unsigned char *p;
- while (*p) {
+ for (p = string; p < (const unsigned char *)string + len && *p; p++) {
if (*p == '"' || *p < 0x21 || *p > 0x7f) {
audit_log_hex(ab, string, len);
return string + len + 1;
}
- p++;
}
audit_log_n_string(ab, len, string);
return p + 1;
}
/**
- * audit_log_unstrustedstring - log a string that may contain random characters
+ * audit_log_untrustedstring - log a string that may contain random characters
* @ab: audit_buffer
* @string: string to be logged
*
- * Same as audit_log_n_unstrustedstring(), except that strlen is used to
+ * Same as audit_log_n_untrustedstring(), except that strlen is used to
* determine string length.
*/
const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
diff --git a/kernel/audit.h b/kernel/audit.h
index 815d6f5c04ee..95877435c347 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -115,7 +115,6 @@ extern struct sk_buff * audit_make_reply(int pid, int seq, int type,
extern void audit_send_reply(int pid, int seq, int type,
int done, int multi,
void *payload, int size);
-extern void audit_log_lost(const char *message);
extern void audit_panic(const char *message);
struct audit_netlink_list {
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index ce61f423542c..359645cff5b2 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -304,7 +304,7 @@ int __init audit_register_class(int class, unsigned *list)
int audit_match_class(int class, unsigned syscall)
{
- if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32)))
+ if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
return 0;
if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class]))
return 0;
@@ -456,6 +456,13 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
case AUDIT_DEVMINOR:
case AUDIT_EXIT:
case AUDIT_SUCCESS:
+ /* bit ops are only useful on syscall args */
+ if (f->op == AUDIT_BIT_MASK ||
+ f->op == AUDIT_BIT_TEST) {
+ err = -EINVAL;
+ goto exit_free;
+ }
+ break;
case AUDIT_ARG0:
case AUDIT_ARG1:
case AUDIT_ARG2:
@@ -1210,8 +1217,8 @@ static inline int audit_add_rule(struct audit_entry *entry,
struct audit_entry *e;
struct audit_field *inode_f = entry->rule.inode_f;
struct audit_watch *watch = entry->rule.watch;
- struct nameidata *ndp, *ndw;
- int h, err, putnd_needed = 0;
+ struct nameidata *ndp = NULL, *ndw = NULL;
+ int h, err;
#ifdef CONFIG_AUDITSYSCALL
int dont_count = 0;
@@ -1239,7 +1246,6 @@ static inline int audit_add_rule(struct audit_entry *entry,
err = audit_get_nd(watch->path, &ndp, &ndw);
if (err)
goto error;
- putnd_needed = 1;
}
mutex_lock(&audit_filter_mutex);
@@ -1269,14 +1275,11 @@ static inline int audit_add_rule(struct audit_entry *entry,
#endif
mutex_unlock(&audit_filter_mutex);
- if (putnd_needed)
- audit_put_nd(ndp, ndw);
-
+ audit_put_nd(ndp, ndw); /* NULL args OK */
return 0;
error:
- if (putnd_needed)
- audit_put_nd(ndp, ndw);
+ audit_put_nd(ndp, ndw); /* NULL args OK */
if (watch)
audit_put_watch(watch); /* tmp watch, matches initial get */
return err;
@@ -1570,6 +1573,10 @@ int audit_comparator(const u32 left, const u32 op, const u32 right)
return (left > right);
case AUDIT_GREATER_THAN_OR_EQUAL:
return (left >= right);
+ case AUDIT_BIT_MASK:
+ return (left & right);
+ case AUDIT_BIT_TEST:
+ return ((left & right) == right);
}
BUG();
return 0;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e36481ed61b4..bde1124d5908 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -71,9 +71,6 @@
extern struct list_head audit_filter_list[];
-/* No syscall auditing will take place unless audit_enabled != 0. */
-extern int audit_enabled;
-
/* AUDIT_NAMES is the number of slots we reserve in the audit_context
* for saving names from getname(). */
#define AUDIT_NAMES 20
@@ -156,7 +153,7 @@ struct audit_aux_data_execve {
struct audit_aux_data d;
int argc;
int envc;
- char mem[0];
+ struct mm_struct *mm;
};
struct audit_aux_data_socketcall {
@@ -176,12 +173,6 @@ struct audit_aux_data_fd_pair {
int fd[2];
};
-struct audit_aux_data_path {
- struct audit_aux_data d;
- struct dentry *dentry;
- struct vfsmount *mnt;
-};
-
struct audit_aux_data_pids {
struct audit_aux_data d;
pid_t target_pid[AUDIT_AUX_PIDS];
@@ -657,12 +648,6 @@ static inline void audit_free_aux(struct audit_context *context)
struct audit_aux_data *aux;
while ((aux = context->aux)) {
- if (aux->type == AUDIT_AVC_PATH) {
- struct audit_aux_data_path *axi = (void *)aux;
- dput(axi->dentry);
- mntput(axi->mnt);
- }
-
context->aux = aux->next;
kfree(aux);
}
@@ -834,6 +819,55 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
return rc;
}
+static void audit_log_execve_info(struct audit_buffer *ab,
+ struct audit_aux_data_execve *axi)
+{
+ int i;
+ long len, ret;
+ const char __user *p = (const char __user *)axi->mm->arg_start;
+ char *buf;
+
+ if (axi->mm != current->mm)
+ return; /* execve failed, no additional info */
+
+ for (i = 0; i < axi->argc; i++, p += len) {
+ len = strnlen_user(p, MAX_ARG_STRLEN);
+ /*
+ * We just created this mm, if we can't find the strings
+ * we just copied into it something is _very_ wrong. Similar
+ * for strings that are too long, we should not have created
+ * any.
+ */
+ if (!len || len > MAX_ARG_STRLEN) {
+ WARN_ON(1);
+ send_sig(SIGKILL, current, 0);
+ }
+
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf) {
+ audit_panic("out of memory for argv string\n");
+ break;
+ }
+
+ ret = copy_from_user(buf, p, len);
+ /*
+ * There is no reason for this copy to be short. We just
+ * copied them here, and the mm hasn't been exposed to user-
+ * space yet.
+ */
+ if (!ret) {
+ WARN_ON(1);
+ send_sig(SIGKILL, current, 0);
+ }
+
+ audit_log_format(ab, "a%d=", i);
+ audit_log_untrustedstring(ab, buf);
+ audit_log_format(ab, "\n");
+
+ kfree(buf);
+ }
+}
+
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
int i, call_panic = 0;
@@ -949,7 +983,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- "ouid=%u ogid=%u mode=%x",
+ "ouid=%u ogid=%u mode=%#o",
axi->uid, axi->gid, axi->mode);
if (axi->osid != 0) {
char *ctx = NULL;
@@ -968,19 +1002,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
case AUDIT_IPC_SET_PERM: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- "qbytes=%lx ouid=%u ogid=%u mode=%x",
+ "qbytes=%lx ouid=%u ogid=%u mode=%#o",
axi->qbytes, axi->uid, axi->gid, axi->mode);
break; }
case AUDIT_EXECVE: {
struct audit_aux_data_execve *axi = (void *)aux;
- int i;
- const char *p;
- for (i = 0, p = axi->mem; i < axi->argc; i++) {
- audit_log_format(ab, "a%d=", i);
- p = audit_log_untrustedstring(ab, p);
- audit_log_format(ab, "\n");
- }
+ audit_log_execve_info(ab, axi);
break; }
case AUDIT_SOCKETCALL: {
@@ -998,11 +1026,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_hex(ab, axs->a, axs->len);
break; }
- case AUDIT_AVC_PATH: {
- struct audit_aux_data_path *axi = (void *)aux;
- audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
- break; }
-
case AUDIT_FD_PAIR: {
struct audit_aux_data_fd_pair *axs = (void *)aux;
audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
@@ -1824,32 +1847,31 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
return 0;
}
+int audit_argv_kb = 32;
+
int audit_bprm(struct linux_binprm *bprm)
{
struct audit_aux_data_execve *ax;
struct audit_context *context = current->audit_context;
- unsigned long p, next;
- void *to;
if (likely(!audit_enabled || !context || context->dummy))
return 0;
- ax = kmalloc(sizeof(*ax) + PAGE_SIZE * MAX_ARG_PAGES - bprm->p,
- GFP_KERNEL);
+ /*
+ * Even though the stack code doesn't limit the arg+env size any more,
+ * the audit code requires that _all_ arguments be logged in a single
+ * netlink skb. Hence cap it :-(
+ */
+ if (bprm->argv_len > (audit_argv_kb << 10))
+ return -E2BIG;
+
+ ax = kmalloc(sizeof(*ax), GFP_KERNEL);
if (!ax)
return -ENOMEM;
ax->argc = bprm->argc;
ax->envc = bprm->envc;
- for (p = bprm->p, to = ax->mem; p < MAX_ARG_PAGES*PAGE_SIZE; p = next) {
- struct page *page = bprm->page[p / PAGE_SIZE];
- void *kaddr = kmap(page);
- next = (p + PAGE_SIZE) & ~(PAGE_SIZE - 1);
- memcpy(to, kaddr + (p & (PAGE_SIZE - 1)), next - p);
- to += next - p;
- kunmap(page);
- }
-
+ ax->mm = bprm->mm;
ax->d.type = AUDIT_EXECVE;
ax->d.next = context->aux;
context->aux = (void *)ax;
@@ -1952,36 +1974,6 @@ void __audit_ptrace(struct task_struct *t)
}
/**
- * audit_avc_path - record the granting or denial of permissions
- * @dentry: dentry to record
- * @mnt: mnt to record
- *
- * Returns 0 for success or NULL context or < 0 on error.
- *
- * Called from security/selinux/avc.c::avc_audit()
- */
-int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt)
-{
- struct audit_aux_data_path *ax;
- struct audit_context *context = current->audit_context;
-
- if (likely(!context))
- return 0;
-
- ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
- if (!ax)
- return -ENOMEM;
-
- ax->dentry = dget(dentry);
- ax->mnt = mntget(mnt);
-
- ax->d.type = AUDIT_AVC_PATH;
- ax->d.next = context->aux;
- context->aux = (void *)ax;
- return 0;
-}
-
-/**
* audit_signal_info - record signal info for shutting down audit subsystem
* @sig: signal value
* @t: task being signaled
@@ -2040,7 +2032,7 @@ int __audit_signal_info(int sig, struct task_struct *t)
/**
* audit_core_dumps - record information about processes that end abnormally
- * @sig: signal value
+ * @signr: signal value
*
* If a process ends with a core dump, something fishy is going on and we
* should record the event for investigation.
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 208cf3497c10..181ae7086029 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -103,11 +103,19 @@ static inline void check_for_tasks(int cpu)
write_unlock_irq(&tasklist_lock);
}
+struct take_cpu_down_param {
+ unsigned long mod;
+ void *hcpu;
+};
+
/* Take this CPU down. */
-static int take_cpu_down(void *unused)
+static int take_cpu_down(void *_param)
{
+ struct take_cpu_down_param *param = _param;
int err;
+ raw_notifier_call_chain(&cpu_chain, CPU_DYING | param->mod,
+ param->hcpu);
/* Ensure this CPU doesn't handle any more interrupts. */
err = __cpu_disable();
if (err < 0)
@@ -127,6 +135,10 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
cpumask_t old_allowed, tmp;
void *hcpu = (void *)(long)cpu;
unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
+ struct take_cpu_down_param tcd_param = {
+ .mod = mod,
+ .hcpu = hcpu,
+ };
if (num_online_cpus() == 1)
return -EBUSY;
@@ -153,7 +165,7 @@ static int _cpu_down(unsigned int cpu, int tasks_frozen)
set_cpus_allowed(current, tmp);
mutex_lock(&cpu_bitmask_lock);
- p = __stop_machine_run(take_cpu_down, NULL, cpu);
+ p = __stop_machine_run(take_cpu_down, &tcd_param, cpu);
mutex_unlock(&cpu_bitmask_lock);
if (IS_ERR(p) || cpu_online(cpu)) {
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 4c49188cc49b..57e6448b171e 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -516,7 +516,7 @@ static void cpuset_release_agent(const char *pathbuf)
envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp[i] = NULL;
- call_usermodehelper(argv[0], argv, envp, 0);
+ call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);
kfree(pathbuf);
}
@@ -981,10 +981,10 @@ static int update_nodemask(struct cpuset *cs, char *buf)
mmarray = kmalloc(ntasks * sizeof(*mmarray), GFP_KERNEL);
if (!mmarray)
goto done;
- write_lock_irq(&tasklist_lock); /* block fork */
+ read_lock(&tasklist_lock); /* block fork */
if (atomic_read(&cs->count) <= ntasks)
break; /* got enough */
- write_unlock_irq(&tasklist_lock); /* try again */
+ read_unlock(&tasklist_lock); /* try again */
kfree(mmarray);
}
@@ -1006,7 +1006,7 @@ static int update_nodemask(struct cpuset *cs, char *buf)
continue;
mmarray[n++] = mm;
} while_each_thread(g, p);
- write_unlock_irq(&tasklist_lock);
+ read_unlock(&tasklist_lock);
/*
* Now that we've dropped the tasklist spinlock, we can
@@ -2138,6 +2138,9 @@ static void common_cpu_mem_hotplug_unplug(void)
static int cpuset_handle_cpuhp(struct notifier_block *nb,
unsigned long phase, void *cpu)
{
+ if (phase == CPU_DYING || phase == CPU_DYING_FROZEN)
+ return NOTIFY_DONE;
+
common_cpu_mem_hotplug_unplug();
return 0;
}
diff --git a/kernel/exit.c b/kernel/exit.c
index ca6a11b73023..464c2b172f07 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -31,6 +31,7 @@
#include <linux/mempolicy.h>
#include <linux/taskstats_kern.h>
#include <linux/delayacct.h>
+#include <linux/freezer.h>
#include <linux/cpuset.h>
#include <linux/syscalls.h>
#include <linux/signal.h>
@@ -44,6 +45,7 @@
#include <linux/resource.h>
#include <linux/blkdev.h>
#include <linux/task_io_accounting_ops.h>
+#include <linux/freezer.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -387,6 +389,11 @@ void daemonize(const char *name, ...)
* they would be locked into memory.
*/
exit_mm(current);
+ /*
+ * We don't want to have TIF_FREEZE set if the system-wide hibernation
+ * or suspend transition begins right now.
+ */
+ current->flags |= PF_NOFREEZE;
set_special_pids(1, 1);
proc_clear_tty(current);
@@ -588,6 +595,8 @@ static void exit_mm(struct task_struct * tsk)
tsk->mm = NULL;
up_read(&mm->mmap_sem);
enter_lazy_tlb(mm, current);
+ /* We don't want this task to be frozen prematurely */
+ clear_freeze_flag(tsk);
task_unlock(tsk);
mmput(mm);
}
@@ -858,6 +867,34 @@ static void exit_notify(struct task_struct *tsk)
release_task(tsk);
}
+#ifdef CONFIG_DEBUG_STACK_USAGE
+static void check_stack_usage(void)
+{
+ static DEFINE_SPINLOCK(low_water_lock);
+ static int lowest_to_date = THREAD_SIZE;
+ unsigned long *n = end_of_stack(current);
+ unsigned long free;
+
+ while (*n == 0)
+ n++;
+ free = (unsigned long)n - (unsigned long)end_of_stack(current);
+
+ if (free >= lowest_to_date)
+ return;
+
+ spin_lock(&low_water_lock);
+ if (free < lowest_to_date) {
+ printk(KERN_WARNING "%s used greatest stack depth: %lu bytes "
+ "left\n",
+ current->comm, free);
+ lowest_to_date = free;
+ }
+ spin_unlock(&low_water_lock);
+}
+#else
+static inline void check_stack_usage(void) {}
+#endif
+
fastcall NORET_TYPE void do_exit(long code)
{
struct task_struct *tsk = current;
@@ -937,6 +974,8 @@ fastcall NORET_TYPE void do_exit(long code)
if (unlikely(tsk->compat_robust_list))
compat_exit_robust_list(tsk);
#endif
+ if (group_dead)
+ tty_audit_exit();
if (unlikely(tsk->audit_context))
audit_free(tsk);
@@ -949,6 +988,7 @@ fastcall NORET_TYPE void do_exit(long code)
exit_sem(tsk);
__exit_files(tsk);
__exit_fs(tsk);
+ check_stack_usage();
exit_thread();
cpuset_exit(tsk);
exit_keys(tsk);
diff --git a/kernel/fork.c b/kernel/fork.c
index da3a155bba0d..7332e236d367 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -49,6 +49,7 @@
#include <linux/delayacct.h>
#include <linux/taskstats_kern.h>
#include <linux/random.h>
+#include <linux/tty.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -136,7 +137,7 @@ void __init fork_init(unsigned long mempages)
/* create a slab on which task_structs can be allocated */
task_struct_cachep =
kmem_cache_create("task_struct", sizeof(struct task_struct),
- ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL, NULL);
+ ARCH_MIN_TASKALIGN, SLAB_PANIC, NULL);
#endif
/*
@@ -333,6 +334,8 @@ static struct mm_struct * mm_init(struct mm_struct * mm)
atomic_set(&mm->mm_count, 1);
init_rwsem(&mm->mmap_sem);
INIT_LIST_HEAD(&mm->mmlist);
+ mm->flags = (current->mm) ? current->mm->flags
+ : MMF_DUMP_FILTER_DEFAULT;
mm->core_waiters = 0;
mm->nr_ptes = 0;
set_mm_counter(mm, file_rss, 0);
@@ -897,6 +900,8 @@ static inline int copy_signal(unsigned long clone_flags, struct task_struct * ts
}
acct_init_pacct(&sig->pacct);
+ tty_audit_fork(sig);
+
return 0;
}
@@ -920,7 +925,7 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p)
{
unsigned long new_flags = p->flags;
- new_flags &= ~(PF_SUPERPRIV | PF_NOFREEZE);
+ new_flags &= ~PF_SUPERPRIV;
new_flags |= PF_FORKNOEXEC;
if (!(clone_flags & CLONE_PTRACE))
p->ptrace = 0;
@@ -999,7 +1004,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
if (atomic_read(&p->user->processes) >=
p->signal->rlim[RLIMIT_NPROC].rlim_cur) {
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
- p->user != &root_user)
+ p->user != current->nsproxy->user_ns->root_user)
goto bad_fork_free;
}
@@ -1059,6 +1064,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->lock_depth = -1; /* -1 = no lock */
do_posix_clock_monotonic_gettime(&p->start_time);
+ p->real_start_time = p->start_time;
+ monotonic_to_bootbased(&p->real_start_time);
p->security = NULL;
p->io_context = NULL;
p->io_wait = NULL;
@@ -1439,22 +1446,22 @@ void __init proc_caches_init(void)
sighand_cachep = kmem_cache_create("sighand_cache",
sizeof(struct sighand_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU,
- sighand_ctor, NULL);
+ sighand_ctor);
signal_cachep = kmem_cache_create("signal_cache",
sizeof(struct signal_struct), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
- files_cachep = kmem_cache_create("files_cache",
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ files_cachep = kmem_cache_create("files_cache",
sizeof(struct files_struct), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
- fs_cachep = kmem_cache_create("fs_cache",
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
+ fs_cachep = kmem_cache_create("fs_cache",
sizeof(struct fs_struct), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
vm_area_cachep = kmem_cache_create("vm_area_struct",
sizeof(struct vm_area_struct), 0,
- SLAB_PANIC, NULL, NULL);
+ SLAB_PANIC, NULL);
mm_cachep = kmem_cache_create("mm_struct",
sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
}
/*
@@ -1601,7 +1608,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
err = -EINVAL;
if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
- CLONE_NEWUTS|CLONE_NEWIPC))
+ CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWUSER))
goto bad_unshare_out;
if ((err = unshare_thread(unshare_flags)))
diff --git a/kernel/futex.c b/kernel/futex.c
index 45490bec5831..a12425051ee9 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -121,6 +121,24 @@ static struct futex_hash_bucket futex_queues[1<<FUTEX_HASHBITS];
static struct vfsmount *futex_mnt;
/*
+ * Take mm->mmap_sem, when futex is shared
+ */
+static inline void futex_lock_mm(struct rw_semaphore *fshared)
+{
+ if (fshared)
+ down_read(fshared);
+}
+
+/*
+ * Release mm->mmap_sem, when the futex is shared
+ */
+static inline void futex_unlock_mm(struct rw_semaphore *fshared)
+{
+ if (fshared)
+ up_read(fshared);
+}
+
+/*
* We hash on the keys returned from get_futex_key (see below).
*/
static struct futex_hash_bucket *hash_futex(union futex_key *key)
@@ -287,7 +305,18 @@ void drop_futex_key_refs(union futex_key *key)
}
EXPORT_SYMBOL_GPL(drop_futex_key_refs);
-static inline int get_futex_value_locked(u32 *dest, u32 __user *from)
+static u32 cmpxchg_futex_value_locked(u32 __user *uaddr, u32 uval, u32 newval)
+{
+ u32 curval;
+
+ pagefault_disable();
+ curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
+ pagefault_enable();
+
+ return curval;
+}
+
+static int get_futex_value_locked(u32 *dest, u32 __user *from)
{
int ret;
@@ -317,15 +346,20 @@ static int futex_handle_fault(unsigned long address,
vma = find_vma(mm, address);
if (vma && address >= vma->vm_start &&
(vma->vm_flags & VM_WRITE)) {
- switch (handle_mm_fault(mm, vma, address, 1)) {
- case VM_FAULT_MINOR:
- ret = 0;
- current->min_flt++;
- break;
- case VM_FAULT_MAJOR:
+ int fault;
+ fault = handle_mm_fault(mm, vma, address, 1);
+ if (unlikely((fault & VM_FAULT_ERROR))) {
+#if 0
+ /* XXX: let's do this when we verify it is OK */
+ if (ret & VM_FAULT_OOM)
+ ret = -ENOMEM;
+#endif
+ } else {
ret = 0;
- current->maj_flt++;
- break;
+ if (fault & VM_FAULT_MAJOR)
+ current->maj_flt++;
+ else
+ current->min_flt++;
}
}
if (!fshared)
@@ -620,9 +654,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this)
newval = FUTEX_WAITERS | new_owner->pid;
- pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
- pagefault_enable();
+ curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
if (curval == -EFAULT)
ret = -EFAULT;
@@ -659,9 +691,7 @@ static int unlock_futex_pi(u32 __user *uaddr, u32 uval)
* There is no waiter, so we unlock the futex. The owner died
* bit has not to be preserved here. We are the owner:
*/
- pagefault_disable();
- oldval = futex_atomic_cmpxchg_inatomic(uaddr, uval, 0);
- pagefault_enable();
+ oldval = cmpxchg_futex_value_locked(uaddr, uval, 0);
if (oldval == -EFAULT)
return oldval;
@@ -700,8 +730,7 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
union futex_key key;
int ret;
- if (fshared)
- down_read(fshared);
+ futex_lock_mm(fshared);
ret = get_futex_key(uaddr, fshared, &key);
if (unlikely(ret != 0))
@@ -725,8 +754,7 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
spin_unlock(&hb->lock);
out:
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
return ret;
}
@@ -746,8 +774,7 @@ futex_wake_op(u32 __user *uaddr1, struct rw_semaphore *fshared,
int ret, op_ret, attempt = 0;
retryfull:
- if (fshared)
- down_read(fshared);
+ futex_lock_mm(fshared);
ret = get_futex_key(uaddr1, fshared, &key1);
if (unlikely(ret != 0))
@@ -793,7 +820,7 @@ retry:
*/
if (attempt++) {
ret = futex_handle_fault((unsigned long)uaddr2,
- fshared, attempt);
+ fshared, attempt);
if (ret)
goto out;
goto retry;
@@ -803,8 +830,7 @@ retry:
* If we would have faulted, release mmap_sem,
* fault it in and start all over again.
*/
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
ret = get_user(dummy, uaddr2);
if (ret)
@@ -841,8 +867,8 @@ retry:
if (hb1 != hb2)
spin_unlock(&hb2->lock);
out:
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
+
return ret;
}
@@ -861,8 +887,7 @@ static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
int ret, drop_count = 0;
retry:
- if (fshared)
- down_read(fshared);
+ futex_lock_mm(fshared);
ret = get_futex_key(uaddr1, fshared, &key1);
if (unlikely(ret != 0))
@@ -890,8 +915,7 @@ static int futex_requeue(u32 __user *uaddr1, struct rw_semaphore *fshared,
* If we would have faulted, release mmap_sem, fault
* it in and start all over again.
*/
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
ret = get_user(curval, uaddr1);
@@ -944,8 +968,7 @@ out_unlock:
drop_futex_key_refs(&key1);
out:
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
return ret;
}
@@ -1113,10 +1136,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
while (!ret) {
newval = (uval & FUTEX_OWNER_DIED) | newtid;
- pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr,
- uval, newval);
- pagefault_enable();
+ curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
if (curval == -EFAULT)
ret = -EFAULT;
@@ -1134,6 +1154,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
#define ARG3_SHARED 1
static long futex_wait_restart(struct restart_block *restart);
+
static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
u32 val, ktime_t *abs_time)
{
@@ -1148,8 +1169,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
q.pi_state = NULL;
retry:
- if (fshared)
- down_read(fshared);
+ futex_lock_mm(fshared);
ret = get_futex_key(uaddr, fshared, &q.key);
if (unlikely(ret != 0))
@@ -1186,8 +1206,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
* If we would have faulted, release mmap_sem, fault it in and
* start all over again.
*/
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
ret = get_user(uval, uaddr);
@@ -1206,8 +1225,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
* Now the futex is queued and we have checked the data, we
* don't want to hold mmap_sem while we sleep.
*/
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
/*
* There might have been scheduling since the queue_me(), as we
@@ -1285,8 +1303,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
queue_unlock(&q, hb);
out_release_sem:
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
return ret;
}
@@ -1333,8 +1350,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
q.pi_state = NULL;
retry:
- if (fshared)
- down_read(fshared);
+ futex_lock_mm(fshared);
ret = get_futex_key(uaddr, fshared, &q.key);
if (unlikely(ret != 0))
@@ -1353,9 +1369,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
*/
newval = current->pid;
- pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr, 0, newval);
- pagefault_enable();
+ curval = cmpxchg_futex_value_locked(uaddr, 0, newval);
if (unlikely(curval == -EFAULT))
goto uaddr_faulted;
@@ -1398,9 +1412,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
lock_taken = 1;
}
- pagefault_disable();
- curval = futex_atomic_cmpxchg_inatomic(uaddr, uval, newval);
- pagefault_enable();
+ curval = cmpxchg_futex_value_locked(uaddr, uval, newval);
if (unlikely(curval == -EFAULT))
goto uaddr_faulted;
@@ -1428,8 +1440,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
* exit to complete.
*/
queue_unlock(&q, hb);
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
cond_resched();
goto retry;
@@ -1465,8 +1476,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
* Now the futex is queued and we have checked the data, we
* don't want to hold mmap_sem while we sleep.
*/
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
WARN_ON(!q.pi_state);
/*
@@ -1480,8 +1490,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
ret = ret ? 0 : -EWOULDBLOCK;
}
- if (fshared)
- down_read(fshared);
+ futex_lock_mm(fshared);
spin_lock(q.lock_ptr);
if (!ret) {
@@ -1518,8 +1527,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
/* Unqueue and drop the lock */
unqueue_me_pi(&q);
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
return ret != -EINTR ? ret : -ERESTARTNOINTR;
@@ -1527,8 +1535,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
queue_unlock(&q, hb);
out_release_sem:
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
return ret;
uaddr_faulted:
@@ -1550,8 +1557,7 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
goto retry_unlocked;
}
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
ret = get_user(uval, uaddr);
if (!ret && (uval != -EFAULT))
@@ -1585,8 +1591,7 @@ retry:
/*
* First take all the futex related locks:
*/
- if (fshared)
- down_read(fshared);
+ futex_lock_mm(fshared);
ret = get_futex_key(uaddr, fshared, &key);
if (unlikely(ret != 0))
@@ -1601,11 +1606,9 @@ retry_unlocked:
* again. If it succeeds then we can return without waking
* anyone else up:
*/
- if (!(uval & FUTEX_OWNER_DIED)) {
- pagefault_disable();
- uval = futex_atomic_cmpxchg_inatomic(uaddr, current->pid, 0);
- pagefault_enable();
- }
+ if (!(uval & FUTEX_OWNER_DIED))
+ uval = cmpxchg_futex_value_locked(uaddr, current->pid, 0);
+
if (unlikely(uval == -EFAULT))
goto pi_faulted;
@@ -1647,8 +1650,7 @@ retry_unlocked:
out_unlock:
spin_unlock(&hb->lock);
out:
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
return ret;
@@ -1671,8 +1673,7 @@ pi_faulted:
goto retry_unlocked;
}
- if (fshared)
- up_read(fshared);
+ futex_unlock_mm(fshared);
ret = get_user(uval, uaddr);
if (!ret && (uval != -EFAULT))
@@ -1729,8 +1730,8 @@ static int futex_fd(u32 __user *uaddr, int signal)
if (printk_timed_ratelimit(&printk_interval, 60 * 60 * 1000)) {
printk(KERN_WARNING "Process `%s' used FUTEX_FD, which "
- "will be removed from the kernel in June 2007\n",
- current->comm);
+ "will be removed from the kernel in June 2007\n",
+ current->comm);
}
ret = -EINVAL;
@@ -1908,10 +1909,8 @@ retry:
* Wake robust non-PI futexes here. The wakeup of
* PI futexes happens in exit_pi_state():
*/
- if (!pi) {
- if (uval & FUTEX_WAITERS)
+ if (!pi && (uval & FUTEX_WAITERS))
futex_wake(uaddr, &curr->mm->mmap_sem, 1);
- }
}
return 0;
}
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 23c03f43e196..eb1ddebd2c04 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -558,7 +558,8 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
*/
static int hrtimer_switch_to_hres(void)
{
- struct hrtimer_cpu_base *base = &__get_cpu_var(hrtimer_bases);
+ int cpu = smp_processor_id();
+ struct hrtimer_cpu_base *base = &per_cpu(hrtimer_bases, cpu);
unsigned long flags;
if (base->hres_active)
@@ -568,6 +569,8 @@ static int hrtimer_switch_to_hres(void)
if (tick_init_highres()) {
local_irq_restore(flags);
+ printk(KERN_WARNING "Could not switch to high resolution "
+ "mode on CPU %d\n", cpu);
return 0;
}
base->hres_active = 1;
@@ -683,6 +686,7 @@ static void enqueue_hrtimer(struct hrtimer *timer,
struct rb_node **link = &base->active.rb_node;
struct rb_node *parent = NULL;
struct hrtimer *entry;
+ int leftmost = 1;
/*
* Find the right place in the rbtree:
@@ -694,18 +698,19 @@ static void enqueue_hrtimer(struct hrtimer *timer,
* We dont care about collisions. Nodes with
* the same expiry time stay together.
*/
- if (timer->expires.tv64 < entry->expires.tv64)
+ if (timer->expires.tv64 < entry->expires.tv64) {
link = &(*link)->rb_left;
- else
+ } else {
link = &(*link)->rb_right;
+ leftmost = 0;
+ }
}
/*
* Insert the timer to the rbtree and check whether it
* replaces the first pending timer
*/
- if (!base->first || timer->expires.tv64 <
- rb_entry(base->first, struct hrtimer, node)->expires.tv64) {
+ if (leftmost) {
/*
* Reprogram the clock event device. When the timer is already
* expired hrtimer_enqueue_reprogram has either called the
@@ -1406,7 +1411,7 @@ static void migrate_hrtimers(int cpu)
static int __cpuinit hrtimer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
- long cpu = (long)hcpu;
+ unsigned int cpu = (long)hcpu;
switch (action) {
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index b4f1674fca79..50b81b98046a 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -19,7 +19,15 @@ static struct proc_dir_entry *root_irq_dir;
static int irq_affinity_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- int len = cpumask_scnprintf(page, count, irq_desc[(long)data].affinity);
+ struct irq_desc *desc = irq_desc + (long)data;
+ cpumask_t *mask = &desc->affinity;
+ int len;
+
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+ if (desc->status & IRQ_MOVE_PENDING)
+ mask = &desc->pending_mask;
+#endif
+ len = cpumask_scnprintf(page, count, *mask);
if (count - len < 2)
return -EINVAL;
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index bd9e272d55e9..32b161972fad 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -172,7 +172,17 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
irqreturn_t action_ret)
{
if (unlikely(action_ret != IRQ_HANDLED)) {
- desc->irqs_unhandled++;
+ /*
+ * If we are seeing only the odd spurious IRQ caused by
+ * bus asynchronicity then don't eventually trigger an error,
+ * otherwise the couter becomes a doomsday timer for otherwise
+ * working systems
+ */
+ if (jiffies - desc->last_unhandled > HZ/10)
+ desc->irqs_unhandled = 1;
+ else
+ desc->irqs_unhandled++;
+ desc->last_unhandled = jiffies;
if (unlikely(action_ret != IRQ_NONE))
report_bad_irq(irq, desc, action_ret);
}
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index fed54418626c..474219a41929 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -152,7 +152,7 @@ static unsigned int get_symbol_offset(unsigned long pos)
/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
{
- char namebuf[KSYM_NAME_LEN+1];
+ char namebuf[KSYM_NAME_LEN];
unsigned long i;
unsigned int off;
@@ -248,7 +248,7 @@ const char *kallsyms_lookup(unsigned long addr,
{
const char *msym;
- namebuf[KSYM_NAME_LEN] = 0;
+ namebuf[KSYM_NAME_LEN - 1] = 0;
namebuf[0] = 0;
if (is_ksym_addr(addr)) {
@@ -265,7 +265,7 @@ const char *kallsyms_lookup(unsigned long addr,
/* see if it's in a module */
msym = module_address_lookup(addr, symbolsize, offset, modname);
if (msym)
- return strncpy(namebuf, msym, KSYM_NAME_LEN);
+ return strncpy(namebuf, msym, KSYM_NAME_LEN - 1);
return NULL;
}
@@ -273,7 +273,7 @@ const char *kallsyms_lookup(unsigned long addr,
int lookup_symbol_name(unsigned long addr, char *symname)
{
symname[0] = '\0';
- symname[KSYM_NAME_LEN] = '\0';
+ symname[KSYM_NAME_LEN - 1] = '\0';
if (is_ksym_addr(addr)) {
unsigned long pos;
@@ -291,7 +291,7 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
unsigned long *offset, char *modname, char *name)
{
name[0] = '\0';
- name[KSYM_NAME_LEN] = '\0';
+ name[KSYM_NAME_LEN - 1] = '\0';
if (is_ksym_addr(addr)) {
unsigned long pos;
@@ -312,18 +312,17 @@ int sprint_symbol(char *buffer, unsigned long address)
char *modname;
const char *name;
unsigned long offset, size;
- char namebuf[KSYM_NAME_LEN+1];
+ char namebuf[KSYM_NAME_LEN];
name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
if (!name)
return sprintf(buffer, "0x%lx", address);
- else {
- if (modname)
- return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
+
+ if (modname)
+ return sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
size, modname);
- else
- return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
- }
+ else
+ return sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
}
/* Look up a kernel symbol and print it to the kernel messages. */
@@ -343,8 +342,8 @@ struct kallsym_iter
unsigned long value;
unsigned int nameoff; /* If iterating in core kernel symbols */
char type;
- char name[KSYM_NAME_LEN+1];
- char module_name[MODULE_NAME_LEN + 1];
+ char name[KSYM_NAME_LEN];
+ char module_name[MODULE_NAME_LEN];
int exported;
};
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index cee419143fd4..bc41ad0f24f8 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/kfifo.h>
+#include <linux/log2.h>
/**
* kfifo_init - allocates a new FIFO using a preallocated buffer
@@ -41,7 +42,7 @@ struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
struct kfifo *fifo;
/* size must be a power of 2 */
- BUG_ON(size & (size - 1));
+ BUG_ON(!is_power_of_2(size));
fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
if (!fifo)
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 4d32eb077179..beedbdc64608 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -33,6 +33,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/resource.h>
+#include <linux/notifier.h>
+#include <linux/suspend.h>
#include <asm/uaccess.h>
extern int max_threads;
@@ -119,9 +121,10 @@ struct subprocess_info {
char **argv;
char **envp;
struct key *ring;
- int wait;
+ enum umh_wait wait;
int retval;
struct file *stdin;
+ void (*cleanup)(char **argv, char **envp);
};
/*
@@ -180,6 +183,14 @@ static int ____call_usermodehelper(void *data)
do_exit(0);
}
+void call_usermodehelper_freeinfo(struct subprocess_info *info)
+{
+ if (info->cleanup)
+ (*info->cleanup)(info->argv, info->envp);
+ kfree(info);
+}
+EXPORT_SYMBOL(call_usermodehelper_freeinfo);
+
/* Keventd can't block, but this (a child) can. */
static int wait_for_helper(void *data)
{
@@ -216,8 +227,8 @@ static int wait_for_helper(void *data)
sub_info->retval = ret;
}
- if (sub_info->wait < 0)
- kfree(sub_info);
+ if (sub_info->wait == UMH_NO_WAIT)
+ call_usermodehelper_freeinfo(sub_info);
else
complete(sub_info->complete);
return 0;
@@ -229,34 +240,204 @@ static void __call_usermodehelper(struct work_struct *work)
struct subprocess_info *sub_info =
container_of(work, struct subprocess_info, work);
pid_t pid;
- int wait = sub_info->wait;
+ enum umh_wait wait = sub_info->wait;
/* CLONE_VFORK: wait until the usermode helper has execve'd
* successfully We need the data structures to stay around
* until that is done. */
- if (wait)
+ if (wait == UMH_WAIT_PROC || wait == UMH_NO_WAIT)
pid = kernel_thread(wait_for_helper, sub_info,
CLONE_FS | CLONE_FILES | SIGCHLD);
else
pid = kernel_thread(____call_usermodehelper, sub_info,
CLONE_VFORK | SIGCHLD);
- if (wait < 0)
- return;
+ switch (wait) {
+ case UMH_NO_WAIT:
+ break;
- if (pid < 0) {
+ case UMH_WAIT_PROC:
+ if (pid > 0)
+ break;
sub_info->retval = pid;
+ /* FALLTHROUGH */
+
+ case UMH_WAIT_EXEC:
complete(sub_info->complete);
- } else if (!wait)
- complete(sub_info->complete);
+ }
+}
+
+#ifdef CONFIG_PM
+/*
+ * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
+ * (used for preventing user land processes from being created after the user
+ * land has been frozen during a system-wide hibernation or suspend operation).
+ */
+static int usermodehelper_disabled;
+
+/* Number of helpers running */
+static atomic_t running_helpers = ATOMIC_INIT(0);
+
+/*
+ * Wait queue head used by usermodehelper_pm_callback() to wait for all running
+ * helpers to finish.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
+
+/*
+ * Time to wait for running_helpers to become zero before the setting of
+ * usermodehelper_disabled in usermodehelper_pm_callback() fails
+ */
+#define RUNNING_HELPERS_TIMEOUT (5 * HZ)
+
+static int usermodehelper_pm_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *ignored)
+{
+ long retval;
+
+ switch (action) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE:
+ usermodehelper_disabled = 1;
+ smp_mb();
+ /*
+ * From now on call_usermodehelper_exec() won't start any new
+ * helpers, so it is sufficient if running_helpers turns out to
+ * be zero at one point (it may be increased later, but that
+ * doesn't matter).
+ */
+ retval = wait_event_timeout(running_helpers_waitq,
+ atomic_read(&running_helpers) == 0,
+ RUNNING_HELPERS_TIMEOUT);
+ if (retval) {
+ return NOTIFY_OK;
+ } else {
+ usermodehelper_disabled = 0;
+ return NOTIFY_BAD;
+ }
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ usermodehelper_disabled = 0;
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static void helper_lock(void)
+{
+ atomic_inc(&running_helpers);
+ smp_mb__after_atomic_inc();
+}
+
+static void helper_unlock(void)
+{
+ if (atomic_dec_and_test(&running_helpers))
+ wake_up(&running_helpers_waitq);
+}
+
+static void register_pm_notifier_callback(void)
+{
+ pm_notifier(usermodehelper_pm_callback, 0);
}
+#else /* CONFIG_PM */
+#define usermodehelper_disabled 0
+
+static inline void helper_lock(void) {}
+static inline void helper_unlock(void) {}
+static inline void register_pm_notifier_callback(void) {}
+#endif /* CONFIG_PM */
/**
- * call_usermodehelper_keys - start a usermode application
- * @path: pathname for the application
- * @argv: null-terminated argument list
- * @envp: null-terminated environment list
- * @session_keyring: session keyring for process (NULL for an empty keyring)
+ * call_usermodehelper_setup - prepare to call a usermode helper
+ * @path - path to usermode executable
+ * @argv - arg vector for process
+ * @envp - environment for process
+ *
+ * Returns either NULL on allocation failure, or a subprocess_info
+ * structure. This should be passed to call_usermodehelper_exec to
+ * exec the process and free the structure.
+ */
+struct subprocess_info *call_usermodehelper_setup(char *path,
+ char **argv, char **envp)
+{
+ struct subprocess_info *sub_info;
+ sub_info = kzalloc(sizeof(struct subprocess_info), GFP_ATOMIC);
+ if (!sub_info)
+ goto out;
+
+ INIT_WORK(&sub_info->work, __call_usermodehelper);
+ sub_info->path = path;
+ sub_info->argv = argv;
+ sub_info->envp = envp;
+
+ out:
+ return sub_info;
+}
+EXPORT_SYMBOL(call_usermodehelper_setup);
+
+/**
+ * call_usermodehelper_setkeys - set the session keys for usermode helper
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @session_keyring: the session keyring for the process
+ */
+void call_usermodehelper_setkeys(struct subprocess_info *info,
+ struct key *session_keyring)
+{
+ info->ring = session_keyring;
+}
+EXPORT_SYMBOL(call_usermodehelper_setkeys);
+
+/**
+ * call_usermodehelper_setcleanup - set a cleanup function
+ * @info: a subprocess_info returned by call_usermodehelper_setup
+ * @cleanup: a cleanup function
+ *
+ * The cleanup function is just befor ethe subprocess_info is about to
+ * be freed. This can be used for freeing the argv and envp. The
+ * Function must be runnable in either a process context or the
+ * context in which call_usermodehelper_exec is called.
+ */
+void call_usermodehelper_setcleanup(struct subprocess_info *info,
+ void (*cleanup)(char **argv, char **envp))
+{
+ info->cleanup = cleanup;
+}
+EXPORT_SYMBOL(call_usermodehelper_setcleanup);
+
+/**
+ * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin
+ * @sub_info: a subprocess_info returned by call_usermodehelper_setup
+ * @filp: set to the write-end of a pipe
+ *
+ * This constructs a pipe, and sets the read end to be the stdin of the
+ * subprocess, and returns the write-end in *@filp.
+ */
+int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info,
+ struct file **filp)
+{
+ struct file *f;
+
+ f = create_write_pipe();
+ if (IS_ERR(f))
+ return PTR_ERR(f);
+ *filp = f;
+
+ f = create_read_pipe(f);
+ if (IS_ERR(f)) {
+ free_write_pipe(*filp);
+ return PTR_ERR(f);
+ }
+ sub_info->stdin = f;
+
+ return 0;
+}
+EXPORT_SYMBOL(call_usermodehelper_stdinpipe);
+
+/**
+ * call_usermodehelper_exec - start a usermode application
+ * @sub_info: information about the subprocessa
* @wait: wait for the application to finish and return status.
* when -1 don't wait at all, but you get no useful error back when
* the program couldn't be exec'ed. This makes it safe to call
@@ -265,81 +446,70 @@ static void __call_usermodehelper(struct work_struct *work)
* Runs a user-space application. The application is started
* asynchronously if wait is not set, and runs as a child of keventd.
* (ie. it runs with full root capabilities).
- *
- * Must be called from process context. Returns a negative error code
- * if program was not execed successfully, or 0.
*/
-int call_usermodehelper_keys(char *path, char **argv, char **envp,
- struct key *session_keyring, int wait)
+int call_usermodehelper_exec(struct subprocess_info *sub_info,
+ enum umh_wait wait)
{
DECLARE_COMPLETION_ONSTACK(done);
- struct subprocess_info *sub_info;
int retval;
- if (!khelper_wq)
- return -EBUSY;
-
- if (path[0] == '\0')
- return 0;
+ helper_lock();
+ if (sub_info->path[0] == '\0') {
+ retval = 0;
+ goto out;
+ }
- sub_info = kzalloc(sizeof(struct subprocess_info), GFP_ATOMIC);
- if (!sub_info)
- return -ENOMEM;
+ if (!khelper_wq || usermodehelper_disabled) {
+ retval = -EBUSY;
+ goto out;
+ }
- INIT_WORK(&sub_info->work, __call_usermodehelper);
sub_info->complete = &done;
- sub_info->path = path;
- sub_info->argv = argv;
- sub_info->envp = envp;
- sub_info->ring = session_keyring;
sub_info->wait = wait;
queue_work(khelper_wq, &sub_info->work);
- if (wait < 0) /* task has freed sub_info */
+ if (wait == UMH_NO_WAIT) /* task has freed sub_info */
return 0;
wait_for_completion(&done);
retval = sub_info->retval;
- kfree(sub_info);
+
+ out:
+ call_usermodehelper_freeinfo(sub_info);
+ helper_unlock();
return retval;
}
-EXPORT_SYMBOL(call_usermodehelper_keys);
+EXPORT_SYMBOL(call_usermodehelper_exec);
+/**
+ * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin
+ * @path: path to usermode executable
+ * @argv: arg vector for process
+ * @envp: environment for process
+ * @filp: set to the write-end of a pipe
+ *
+ * This is a simple wrapper which executes a usermode-helper function
+ * with a pipe as stdin. It is implemented entirely in terms of
+ * lower-level call_usermodehelper_* functions.
+ */
int call_usermodehelper_pipe(char *path, char **argv, char **envp,
struct file **filp)
{
- DECLARE_COMPLETION(done);
- struct subprocess_info sub_info = {
- .work = __WORK_INITIALIZER(sub_info.work,
- __call_usermodehelper),
- .complete = &done,
- .path = path,
- .argv = argv,
- .envp = envp,
- .retval = 0,
- };
- struct file *f;
-
- if (!khelper_wq)
- return -EBUSY;
+ struct subprocess_info *sub_info;
+ int ret;
- if (path[0] == '\0')
- return 0;
+ sub_info = call_usermodehelper_setup(path, argv, envp);
+ if (sub_info == NULL)
+ return -ENOMEM;
- f = create_write_pipe();
- if (IS_ERR(f))
- return PTR_ERR(f);
- *filp = f;
+ ret = call_usermodehelper_stdinpipe(sub_info, filp);
+ if (ret < 0)
+ goto out;
- f = create_read_pipe(f);
- if (IS_ERR(f)) {
- free_write_pipe(*filp);
- return PTR_ERR(f);
- }
- sub_info.stdin = f;
+ return call_usermodehelper_exec(sub_info, 1);
- queue_work(khelper_wq, &sub_info.work);
- wait_for_completion(&done);
- return sub_info.retval;
+ out:
+ call_usermodehelper_freeinfo(sub_info);
+ return ret;
}
EXPORT_SYMBOL(call_usermodehelper_pipe);
@@ -347,4 +517,5 @@ void __init usermodehelper_init(void)
{
khelper_wq = create_singlethread_workqueue("khelper");
BUG_ON(!khelper_wq);
+ register_pm_notifier_callback();
}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 9e47d8c493f3..3e9f513a728d 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -675,9 +675,18 @@ static struct notifier_block kprobe_exceptions_nb = {
.priority = 0x7fffffff /* we need to be notified first */
};
+unsigned long __weak arch_deref_entry_point(void *entry)
+{
+ return (unsigned long)entry;
+}
int __kprobes register_jprobe(struct jprobe *jp)
{
+ unsigned long addr = arch_deref_entry_point(jp->entry);
+
+ if (!kernel_text_address(addr))
+ return -EINVAL;
+
/* Todo: Verify probepoint is a function entry point */
jp->kp.pre_handler = setjmp_pre_handler;
jp->kp.break_handler = longjmp_break_handler;
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index 559deca5ed15..d0e5c48e18c7 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -62,6 +62,28 @@ static ssize_t kexec_crash_loaded_show(struct kset *kset, char *page)
KERNEL_ATTR_RO(kexec_crash_loaded);
#endif /* CONFIG_KEXEC */
+/*
+ * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
+ */
+extern const void __start_notes __attribute__((weak));
+extern const void __stop_notes __attribute__((weak));
+#define notes_size (&__stop_notes - &__start_notes)
+
+static ssize_t notes_read(struct kobject *kobj, struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ memcpy(buf, &__start_notes + off, count);
+ return count;
+}
+
+static struct bin_attribute notes_attr = {
+ .attr = {
+ .name = "notes",
+ .mode = S_IRUGO,
+ },
+ .read = &notes_read,
+};
+
decl_subsys(kernel, NULL, NULL);
EXPORT_SYMBOL_GPL(kernel_subsys);
@@ -88,6 +110,12 @@ static int __init ksysfs_init(void)
error = sysfs_create_group(&kernel_subsys.kobj,
&kernel_attr_group);
+ if (!error && notes_size > 0) {
+ notes_attr.size = notes_size;
+ error = sysfs_create_bin_file(&kernel_subsys.kobj,
+ &notes_attr);
+ }
+
return error;
}
diff --git a/kernel/kthread.c b/kernel/kthread.c
index bbd51b81a3e8..a404f7ee7395 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -215,7 +215,7 @@ int kthread_stop(struct task_struct *k)
EXPORT_SYMBOL(kthread_stop);
-static __init void kthreadd_setup(void)
+static noinline __init_refok void kthreadd_setup(void)
{
struct task_struct *tsk = current;
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index 1a5ff2211d88..734da579ad13 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -5,7 +5,8 @@
*
* Started by Ingo Molnar:
*
- * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
*
* this code maps all the lock dependencies as they occur in a live kernel
* and will warn about the following classes of locking bugs:
@@ -37,11 +38,26 @@
#include <linux/debug_locks.h>
#include <linux/irqflags.h>
#include <linux/utsname.h>
+#include <linux/hash.h>
#include <asm/sections.h>
#include "lockdep_internals.h"
+#ifdef CONFIG_PROVE_LOCKING
+int prove_locking = 1;
+module_param(prove_locking, int, 0644);
+#else
+#define prove_locking 0
+#endif
+
+#ifdef CONFIG_LOCK_STAT
+int lock_stat = 1;
+module_param(lock_stat, int, 0644);
+#else
+#define lock_stat 0
+#endif
+
/*
* lockdep_lock: protects the lockdep graph, the hashes and the
* class/list/hash allocators.
@@ -96,23 +112,6 @@ unsigned long nr_list_entries;
static struct lock_list list_entries[MAX_LOCKDEP_ENTRIES];
/*
- * Allocate a lockdep entry. (assumes the graph_lock held, returns
- * with NULL on failure)
- */
-static struct lock_list *alloc_list_entry(void)
-{
- if (nr_list_entries >= MAX_LOCKDEP_ENTRIES) {
- if (!debug_locks_off_graph_unlock())
- return NULL;
-
- printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
- printk("turning off the locking correctness validator.\n");
- return NULL;
- }
- return list_entries + nr_list_entries++;
-}
-
-/*
* All data structures here are protected by the global debug_lock.
*
* Mutex key structs only get allocated, once during bootup, and never
@@ -121,6 +120,117 @@ static struct lock_list *alloc_list_entry(void)
unsigned long nr_lock_classes;
static struct lock_class lock_classes[MAX_LOCKDEP_KEYS];
+#ifdef CONFIG_LOCK_STAT
+static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats);
+
+static int lock_contention_point(struct lock_class *class, unsigned long ip)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
+ if (class->contention_point[i] == 0) {
+ class->contention_point[i] = ip;
+ break;
+ }
+ if (class->contention_point[i] == ip)
+ break;
+ }
+
+ return i;
+}
+
+static void lock_time_inc(struct lock_time *lt, s64 time)
+{
+ if (time > lt->max)
+ lt->max = time;
+
+ if (time < lt->min || !lt->min)
+ lt->min = time;
+
+ lt->total += time;
+ lt->nr++;
+}
+
+static inline void lock_time_add(struct lock_time *src, struct lock_time *dst)
+{
+ dst->min += src->min;
+ dst->max += src->max;
+ dst->total += src->total;
+ dst->nr += src->nr;
+}
+
+struct lock_class_stats lock_stats(struct lock_class *class)
+{
+ struct lock_class_stats stats;
+ int cpu, i;
+
+ memset(&stats, 0, sizeof(struct lock_class_stats));
+ for_each_possible_cpu(cpu) {
+ struct lock_class_stats *pcs =
+ &per_cpu(lock_stats, cpu)[class - lock_classes];
+
+ for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++)
+ stats.contention_point[i] += pcs->contention_point[i];
+
+ lock_time_add(&pcs->read_waittime, &stats.read_waittime);
+ lock_time_add(&pcs->write_waittime, &stats.write_waittime);
+
+ lock_time_add(&pcs->read_holdtime, &stats.read_holdtime);
+ lock_time_add(&pcs->write_holdtime, &stats.write_holdtime);
+
+ for (i = 0; i < ARRAY_SIZE(stats.bounces); i++)
+ stats.bounces[i] += pcs->bounces[i];
+ }
+
+ return stats;
+}
+
+void clear_lock_stats(struct lock_class *class)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct lock_class_stats *cpu_stats =
+ &per_cpu(lock_stats, cpu)[class - lock_classes];
+
+ memset(cpu_stats, 0, sizeof(struct lock_class_stats));
+ }
+ memset(class->contention_point, 0, sizeof(class->contention_point));
+}
+
+static struct lock_class_stats *get_lock_stats(struct lock_class *class)
+{
+ return &get_cpu_var(lock_stats)[class - lock_classes];
+}
+
+static void put_lock_stats(struct lock_class_stats *stats)
+{
+ put_cpu_var(lock_stats);
+}
+
+static void lock_release_holdtime(struct held_lock *hlock)
+{
+ struct lock_class_stats *stats;
+ s64 holdtime;
+
+ if (!lock_stat)
+ return;
+
+ holdtime = sched_clock() - hlock->holdtime_stamp;
+
+ stats = get_lock_stats(hlock->class);
+ if (hlock->read)
+ lock_time_inc(&stats->read_holdtime, holdtime);
+ else
+ lock_time_inc(&stats->write_holdtime, holdtime);
+ put_lock_stats(stats);
+}
+#else
+static inline void lock_release_holdtime(struct held_lock *hlock)
+{
+}
+#endif
+
/*
* We keep a global list of all lock classes. The list only grows,
* never shrinks. The list is only accessed with the lockdep
@@ -133,24 +243,18 @@ LIST_HEAD(all_lock_classes);
*/
#define CLASSHASH_BITS (MAX_LOCKDEP_KEYS_BITS - 1)
#define CLASSHASH_SIZE (1UL << CLASSHASH_BITS)
-#define CLASSHASH_MASK (CLASSHASH_SIZE - 1)
-#define __classhashfn(key) ((((unsigned long)key >> CLASSHASH_BITS) + (unsigned long)key) & CLASSHASH_MASK)
+#define __classhashfn(key) hash_long((unsigned long)key, CLASSHASH_BITS)
#define classhashentry(key) (classhash_table + __classhashfn((key)))
static struct list_head classhash_table[CLASSHASH_SIZE];
-unsigned long nr_lock_chains;
-static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
-
/*
* We put the lock dependency chains into a hash-table as well, to cache
* their existence:
*/
#define CHAINHASH_BITS (MAX_LOCKDEP_CHAINS_BITS-1)
#define CHAINHASH_SIZE (1UL << CHAINHASH_BITS)
-#define CHAINHASH_MASK (CHAINHASH_SIZE - 1)
-#define __chainhashfn(chain) \
- (((chain >> CHAINHASH_BITS) + chain) & CHAINHASH_MASK)
+#define __chainhashfn(chain) hash_long(chain, CHAINHASH_BITS)
#define chainhashentry(chain) (chainhash_table + __chainhashfn((chain)))
static struct list_head chainhash_table[CHAINHASH_SIZE];
@@ -223,26 +327,6 @@ static int verbose(struct lock_class *class)
return 0;
}
-#ifdef CONFIG_TRACE_IRQFLAGS
-
-static int hardirq_verbose(struct lock_class *class)
-{
-#if HARDIRQ_VERBOSE
- return class_filter(class);
-#endif
- return 0;
-}
-
-static int softirq_verbose(struct lock_class *class)
-{
-#if SOFTIRQ_VERBOSE
- return class_filter(class);
-#endif
- return 0;
-}
-
-#endif
-
/*
* Stack-trace: tightly packed array of stack backtrace
* addresses. Protected by the graph_lock.
@@ -291,6 +375,11 @@ unsigned int max_recursion_depth;
* about it later on, in lockdep_info().
*/
static int lockdep_init_error;
+static unsigned long lockdep_init_trace_data[20];
+static struct stack_trace lockdep_init_trace = {
+ .max_entries = ARRAY_SIZE(lockdep_init_trace_data),
+ .entries = lockdep_init_trace_data,
+};
/*
* Various lockdep statistics:
@@ -379,7 +468,7 @@ get_usage_chars(struct lock_class *class, char *c1, char *c2, char *c3, char *c4
static void print_lock_name(struct lock_class *class)
{
- char str[KSYM_NAME_LEN + 1], c1, c2, c3, c4;
+ char str[KSYM_NAME_LEN], c1, c2, c3, c4;
const char *name;
get_usage_chars(class, &c1, &c2, &c3, &c4);
@@ -401,7 +490,7 @@ static void print_lock_name(struct lock_class *class)
static void print_lockdep_cache(struct lockdep_map *lock)
{
const char *name;
- char str[KSYM_NAME_LEN + 1];
+ char str[KSYM_NAME_LEN];
name = lock->name;
if (!name)
@@ -482,6 +571,262 @@ static void print_lock_dependencies(struct lock_class *class, int depth)
}
}
+static void print_kernel_version(void)
+{
+ printk("%s %.*s\n", init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+}
+
+static int very_verbose(struct lock_class *class)
+{
+#if VERY_VERBOSE
+ return class_filter(class);
+#endif
+ return 0;
+}
+
+/*
+ * Is this the address of a static object:
+ */
+static int static_obj(void *obj)
+{
+ unsigned long start = (unsigned long) &_stext,
+ end = (unsigned long) &_end,
+ addr = (unsigned long) obj;
+#ifdef CONFIG_SMP
+ int i;
+#endif
+
+ /*
+ * static variable?
+ */
+ if ((addr >= start) && (addr < end))
+ return 1;
+
+#ifdef CONFIG_SMP
+ /*
+ * percpu var?
+ */
+ for_each_possible_cpu(i) {
+ start = (unsigned long) &__per_cpu_start + per_cpu_offset(i);
+ end = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM
+ + per_cpu_offset(i);
+
+ if ((addr >= start) && (addr < end))
+ return 1;
+ }
+#endif
+
+ /*
+ * module var?
+ */
+ return is_module_address(addr);
+}
+
+/*
+ * To make lock name printouts unique, we calculate a unique
+ * class->name_version generation counter:
+ */
+static int count_matching_names(struct lock_class *new_class)
+{
+ struct lock_class *class;
+ int count = 0;
+
+ if (!new_class->name)
+ return 0;
+
+ list_for_each_entry(class, &all_lock_classes, lock_entry) {
+ if (new_class->key - new_class->subclass == class->key)
+ return class->name_version;
+ if (class->name && !strcmp(class->name, new_class->name))
+ count = max(count, class->name_version);
+ }
+
+ return count + 1;
+}
+
+/*
+ * Register a lock's class in the hash-table, if the class is not present
+ * yet. Otherwise we look it up. We cache the result in the lock object
+ * itself, so actual lookup of the hash should be once per lock object.
+ */
+static inline struct lock_class *
+look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
+{
+ struct lockdep_subclass_key *key;
+ struct list_head *hash_head;
+ struct lock_class *class;
+
+#ifdef CONFIG_DEBUG_LOCKDEP
+ /*
+ * If the architecture calls into lockdep before initializing
+ * the hashes then we'll warn about it later. (we cannot printk
+ * right now)
+ */
+ if (unlikely(!lockdep_initialized)) {
+ lockdep_init();
+ lockdep_init_error = 1;
+ save_stack_trace(&lockdep_init_trace);
+ }
+#endif
+
+ /*
+ * Static locks do not have their class-keys yet - for them the key
+ * is the lock object itself:
+ */
+ if (unlikely(!lock->key))
+ lock->key = (void *)lock;
+
+ /*
+ * NOTE: the class-key must be unique. For dynamic locks, a static
+ * lock_class_key variable is passed in through the mutex_init()
+ * (or spin_lock_init()) call - which acts as the key. For static
+ * locks we use the lock object itself as the key.
+ */
+ BUILD_BUG_ON(sizeof(struct lock_class_key) >
+ sizeof(struct lockdep_map));
+
+ key = lock->key->subkeys + subclass;
+
+ hash_head = classhashentry(key);
+
+ /*
+ * We can walk the hash lockfree, because the hash only
+ * grows, and we are careful when adding entries to the end:
+ */
+ list_for_each_entry(class, hash_head, hash_entry) {
+ if (class->key == key) {
+ WARN_ON_ONCE(class->name != lock->name);
+ return class;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Register a lock's class in the hash-table, if the class is not present
+ * yet. Otherwise we look it up. We cache the result in the lock object
+ * itself, so actual lookup of the hash should be once per lock object.
+ */
+static inline struct lock_class *
+register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
+{
+ struct lockdep_subclass_key *key;
+ struct list_head *hash_head;
+ struct lock_class *class;
+ unsigned long flags;
+
+ class = look_up_lock_class(lock, subclass);
+ if (likely(class))
+ return class;
+
+ /*
+ * Debug-check: all keys must be persistent!
+ */
+ if (!static_obj(lock->key)) {
+ debug_locks_off();
+ printk("INFO: trying to register non-static key.\n");
+ printk("the code is fine but needs lockdep annotation.\n");
+ printk("turning off the locking correctness validator.\n");
+ dump_stack();
+
+ return NULL;
+ }
+
+ key = lock->key->subkeys + subclass;
+ hash_head = classhashentry(key);
+
+ raw_local_irq_save(flags);
+ if (!graph_lock()) {
+ raw_local_irq_restore(flags);
+ return NULL;
+ }
+ /*
+ * We have to do the hash-walk again, to avoid races
+ * with another CPU:
+ */
+ list_for_each_entry(class, hash_head, hash_entry)
+ if (class->key == key)
+ goto out_unlock_set;
+ /*
+ * Allocate a new key from the static array, and add it to
+ * the hash:
+ */
+ if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
+ if (!debug_locks_off_graph_unlock()) {
+ raw_local_irq_restore(flags);
+ return NULL;
+ }
+ raw_local_irq_restore(flags);
+
+ printk("BUG: MAX_LOCKDEP_KEYS too low!\n");
+ printk("turning off the locking correctness validator.\n");
+ return NULL;
+ }
+ class = lock_classes + nr_lock_classes++;
+ debug_atomic_inc(&nr_unused_locks);
+ class->key = key;
+ class->name = lock->name;
+ class->subclass = subclass;
+ INIT_LIST_HEAD(&class->lock_entry);
+ INIT_LIST_HEAD(&class->locks_before);
+ INIT_LIST_HEAD(&class->locks_after);
+ class->name_version = count_matching_names(class);
+ /*
+ * We use RCU's safe list-add method to make
+ * parallel walking of the hash-list safe:
+ */
+ list_add_tail_rcu(&class->hash_entry, hash_head);
+
+ if (verbose(class)) {
+ graph_unlock();
+ raw_local_irq_restore(flags);
+
+ printk("\nnew class %p: %s", class->key, class->name);
+ if (class->name_version > 1)
+ printk("#%d", class->name_version);
+ printk("\n");
+ dump_stack();
+
+ raw_local_irq_save(flags);
+ if (!graph_lock()) {
+ raw_local_irq_restore(flags);
+ return NULL;
+ }
+ }
+out_unlock_set:
+ graph_unlock();
+ raw_local_irq_restore(flags);
+
+ if (!subclass || force)
+ lock->class_cache = class;
+
+ if (DEBUG_LOCKS_WARN_ON(class->subclass != subclass))
+ return NULL;
+
+ return class;
+}
+
+#ifdef CONFIG_PROVE_LOCKING
+/*
+ * Allocate a lockdep entry. (assumes the graph_lock held, returns
+ * with NULL on failure)
+ */
+static struct lock_list *alloc_list_entry(void)
+{
+ if (nr_list_entries >= MAX_LOCKDEP_ENTRIES) {
+ if (!debug_locks_off_graph_unlock())
+ return NULL;
+
+ printk("BUG: MAX_LOCKDEP_ENTRIES too low!\n");
+ printk("turning off the locking correctness validator.\n");
+ return NULL;
+ }
+ return list_entries + nr_list_entries++;
+}
+
/*
* Add a new dependency to the head of the list:
*/
@@ -542,13 +887,6 @@ print_circular_bug_entry(struct lock_list *target, unsigned int depth)
return 0;
}
-static void print_kernel_version(void)
-{
- printk("%s %.*s\n", init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
-}
-
/*
* When a circular dependency is detected, print the
* header first:
@@ -640,15 +978,7 @@ check_noncircular(struct lock_class *source, unsigned int depth)
return 1;
}
-static int very_verbose(struct lock_class *class)
-{
-#if VERY_VERBOSE
- return class_filter(class);
-#endif
- return 0;
-}
#ifdef CONFIG_TRACE_IRQFLAGS
-
/*
* Forwards and backwards subgraph searching, for the purposes of
* proving that two subgraphs can be connected by a new dependency
@@ -821,6 +1151,78 @@ check_usage(struct task_struct *curr, struct held_lock *prev,
bit_backwards, bit_forwards, irqclass);
}
+static int
+check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
+ struct held_lock *next)
+{
+ /*
+ * Prove that the new dependency does not connect a hardirq-safe
+ * lock with a hardirq-unsafe lock - to achieve this we search
+ * the backwards-subgraph starting at <prev>, and the
+ * forwards-subgraph starting at <next>:
+ */
+ if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ,
+ LOCK_ENABLED_HARDIRQS, "hard"))
+ return 0;
+
+ /*
+ * Prove that the new dependency does not connect a hardirq-safe-read
+ * lock with a hardirq-unsafe lock - to achieve this we search
+ * the backwards-subgraph starting at <prev>, and the
+ * forwards-subgraph starting at <next>:
+ */
+ if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ_READ,
+ LOCK_ENABLED_HARDIRQS, "hard-read"))
+ return 0;
+
+ /*
+ * Prove that the new dependency does not connect a softirq-safe
+ * lock with a softirq-unsafe lock - to achieve this we search
+ * the backwards-subgraph starting at <prev>, and the
+ * forwards-subgraph starting at <next>:
+ */
+ if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ,
+ LOCK_ENABLED_SOFTIRQS, "soft"))
+ return 0;
+ /*
+ * Prove that the new dependency does not connect a softirq-safe-read
+ * lock with a softirq-unsafe lock - to achieve this we search
+ * the backwards-subgraph starting at <prev>, and the
+ * forwards-subgraph starting at <next>:
+ */
+ if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ_READ,
+ LOCK_ENABLED_SOFTIRQS, "soft"))
+ return 0;
+
+ return 1;
+}
+
+static void inc_chains(void)
+{
+ if (current->hardirq_context)
+ nr_hardirq_chains++;
+ else {
+ if (current->softirq_context)
+ nr_softirq_chains++;
+ else
+ nr_process_chains++;
+ }
+}
+
+#else
+
+static inline int
+check_prev_add_irq(struct task_struct *curr, struct held_lock *prev,
+ struct held_lock *next)
+{
+ return 1;
+}
+
+static inline void inc_chains(void)
+{
+ nr_process_chains++;
+}
+
#endif
static int
@@ -922,47 +1324,10 @@ check_prev_add(struct task_struct *curr, struct held_lock *prev,
if (!(check_noncircular(next->class, 0)))
return print_circular_bug_tail();
-#ifdef CONFIG_TRACE_IRQFLAGS
- /*
- * Prove that the new dependency does not connect a hardirq-safe
- * lock with a hardirq-unsafe lock - to achieve this we search
- * the backwards-subgraph starting at <prev>, and the
- * forwards-subgraph starting at <next>:
- */
- if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ,
- LOCK_ENABLED_HARDIRQS, "hard"))
+ if (!check_prev_add_irq(curr, prev, next))
return 0;
/*
- * Prove that the new dependency does not connect a hardirq-safe-read
- * lock with a hardirq-unsafe lock - to achieve this we search
- * the backwards-subgraph starting at <prev>, and the
- * forwards-subgraph starting at <next>:
- */
- if (!check_usage(curr, prev, next, LOCK_USED_IN_HARDIRQ_READ,
- LOCK_ENABLED_HARDIRQS, "hard-read"))
- return 0;
-
- /*
- * Prove that the new dependency does not connect a softirq-safe
- * lock with a softirq-unsafe lock - to achieve this we search
- * the backwards-subgraph starting at <prev>, and the
- * forwards-subgraph starting at <next>:
- */
- if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ,
- LOCK_ENABLED_SOFTIRQS, "soft"))
- return 0;
- /*
- * Prove that the new dependency does not connect a softirq-safe-read
- * lock with a softirq-unsafe lock - to achieve this we search
- * the backwards-subgraph starting at <prev>, and the
- * forwards-subgraph starting at <next>:
- */
- if (!check_usage(curr, prev, next, LOCK_USED_IN_SOFTIRQ_READ,
- LOCK_ENABLED_SOFTIRQS, "soft"))
- return 0;
-#endif
- /*
* For recursive read-locks we do all the dependency checks,
* but we dont store read-triggered dependencies (only
* write-triggered dependencies). This ensures that only the
@@ -1088,224 +1453,8 @@ out_bug:
return 0;
}
-
-/*
- * Is this the address of a static object:
- */
-static int static_obj(void *obj)
-{
- unsigned long start = (unsigned long) &_stext,
- end = (unsigned long) &_end,
- addr = (unsigned long) obj;
-#ifdef CONFIG_SMP
- int i;
-#endif
-
- /*
- * static variable?
- */
- if ((addr >= start) && (addr < end))
- return 1;
-
-#ifdef CONFIG_SMP
- /*
- * percpu var?
- */
- for_each_possible_cpu(i) {
- start = (unsigned long) &__per_cpu_start + per_cpu_offset(i);
- end = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM
- + per_cpu_offset(i);
-
- if ((addr >= start) && (addr < end))
- return 1;
- }
-#endif
-
- /*
- * module var?
- */
- return is_module_address(addr);
-}
-
-/*
- * To make lock name printouts unique, we calculate a unique
- * class->name_version generation counter:
- */
-static int count_matching_names(struct lock_class *new_class)
-{
- struct lock_class *class;
- int count = 0;
-
- if (!new_class->name)
- return 0;
-
- list_for_each_entry(class, &all_lock_classes, lock_entry) {
- if (new_class->key - new_class->subclass == class->key)
- return class->name_version;
- if (class->name && !strcmp(class->name, new_class->name))
- count = max(count, class->name_version);
- }
-
- return count + 1;
-}
-
-/*
- * Register a lock's class in the hash-table, if the class is not present
- * yet. Otherwise we look it up. We cache the result in the lock object
- * itself, so actual lookup of the hash should be once per lock object.
- */
-static inline struct lock_class *
-look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
-{
- struct lockdep_subclass_key *key;
- struct list_head *hash_head;
- struct lock_class *class;
-
-#ifdef CONFIG_DEBUG_LOCKDEP
- /*
- * If the architecture calls into lockdep before initializing
- * the hashes then we'll warn about it later. (we cannot printk
- * right now)
- */
- if (unlikely(!lockdep_initialized)) {
- lockdep_init();
- lockdep_init_error = 1;
- }
-#endif
-
- /*
- * Static locks do not have their class-keys yet - for them the key
- * is the lock object itself:
- */
- if (unlikely(!lock->key))
- lock->key = (void *)lock;
-
- /*
- * NOTE: the class-key must be unique. For dynamic locks, a static
- * lock_class_key variable is passed in through the mutex_init()
- * (or spin_lock_init()) call - which acts as the key. For static
- * locks we use the lock object itself as the key.
- */
- BUILD_BUG_ON(sizeof(struct lock_class_key) > sizeof(struct lock_class));
-
- key = lock->key->subkeys + subclass;
-
- hash_head = classhashentry(key);
-
- /*
- * We can walk the hash lockfree, because the hash only
- * grows, and we are careful when adding entries to the end:
- */
- list_for_each_entry(class, hash_head, hash_entry)
- if (class->key == key)
- return class;
-
- return NULL;
-}
-
-/*
- * Register a lock's class in the hash-table, if the class is not present
- * yet. Otherwise we look it up. We cache the result in the lock object
- * itself, so actual lookup of the hash should be once per lock object.
- */
-static inline struct lock_class *
-register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
-{
- struct lockdep_subclass_key *key;
- struct list_head *hash_head;
- struct lock_class *class;
- unsigned long flags;
-
- class = look_up_lock_class(lock, subclass);
- if (likely(class))
- return class;
-
- /*
- * Debug-check: all keys must be persistent!
- */
- if (!static_obj(lock->key)) {
- debug_locks_off();
- printk("INFO: trying to register non-static key.\n");
- printk("the code is fine but needs lockdep annotation.\n");
- printk("turning off the locking correctness validator.\n");
- dump_stack();
-
- return NULL;
- }
-
- key = lock->key->subkeys + subclass;
- hash_head = classhashentry(key);
-
- raw_local_irq_save(flags);
- if (!graph_lock()) {
- raw_local_irq_restore(flags);
- return NULL;
- }
- /*
- * We have to do the hash-walk again, to avoid races
- * with another CPU:
- */
- list_for_each_entry(class, hash_head, hash_entry)
- if (class->key == key)
- goto out_unlock_set;
- /*
- * Allocate a new key from the static array, and add it to
- * the hash:
- */
- if (nr_lock_classes >= MAX_LOCKDEP_KEYS) {
- if (!debug_locks_off_graph_unlock()) {
- raw_local_irq_restore(flags);
- return NULL;
- }
- raw_local_irq_restore(flags);
-
- printk("BUG: MAX_LOCKDEP_KEYS too low!\n");
- printk("turning off the locking correctness validator.\n");
- return NULL;
- }
- class = lock_classes + nr_lock_classes++;
- debug_atomic_inc(&nr_unused_locks);
- class->key = key;
- class->name = lock->name;
- class->subclass = subclass;
- INIT_LIST_HEAD(&class->lock_entry);
- INIT_LIST_HEAD(&class->locks_before);
- INIT_LIST_HEAD(&class->locks_after);
- class->name_version = count_matching_names(class);
- /*
- * We use RCU's safe list-add method to make
- * parallel walking of the hash-list safe:
- */
- list_add_tail_rcu(&class->hash_entry, hash_head);
-
- if (verbose(class)) {
- graph_unlock();
- raw_local_irq_restore(flags);
-
- printk("\nnew class %p: %s", class->key, class->name);
- if (class->name_version > 1)
- printk("#%d", class->name_version);
- printk("\n");
- dump_stack();
-
- raw_local_irq_save(flags);
- if (!graph_lock()) {
- raw_local_irq_restore(flags);
- return NULL;
- }
- }
-out_unlock_set:
- graph_unlock();
- raw_local_irq_restore(flags);
-
- if (!subclass || force)
- lock->class_cache = class;
-
- if (DEBUG_LOCKS_WARN_ON(class->subclass != subclass))
- return NULL;
-
- return class;
-}
+unsigned long nr_lock_chains;
+static struct lock_chain lock_chains[MAX_LOCKDEP_CHAINS];
/*
* Look up a dependency chain. If the key is not present yet then
@@ -1366,21 +1515,72 @@ cache_hit:
chain->chain_key = chain_key;
list_add_tail_rcu(&chain->entry, hash_head);
debug_atomic_inc(&chain_lookup_misses);
-#ifdef CONFIG_TRACE_IRQFLAGS
- if (current->hardirq_context)
- nr_hardirq_chains++;
- else {
- if (current->softirq_context)
- nr_softirq_chains++;
- else
- nr_process_chains++;
- }
-#else
- nr_process_chains++;
-#endif
+ inc_chains();
+
+ return 1;
+}
+
+static int validate_chain(struct task_struct *curr, struct lockdep_map *lock,
+ struct held_lock *hlock, int chain_head)
+{
+ /*
+ * Trylock needs to maintain the stack of held locks, but it
+ * does not add new dependencies, because trylock can be done
+ * in any order.
+ *
+ * We look up the chain_key and do the O(N^2) check and update of
+ * the dependencies only if this is a new dependency chain.
+ * (If lookup_chain_cache() returns with 1 it acquires
+ * graph_lock for us)
+ */
+ if (!hlock->trylock && (hlock->check == 2) &&
+ lookup_chain_cache(curr->curr_chain_key, hlock->class)) {
+ /*
+ * Check whether last held lock:
+ *
+ * - is irq-safe, if this lock is irq-unsafe
+ * - is softirq-safe, if this lock is hardirq-unsafe
+ *
+ * And check whether the new lock's dependency graph
+ * could lead back to the previous lock.
+ *
+ * any of these scenarios could lead to a deadlock. If
+ * All validations
+ */
+ int ret = check_deadlock(curr, hlock, lock, hlock->read);
+
+ if (!ret)
+ return 0;
+ /*
+ * Mark recursive read, as we jump over it when
+ * building dependencies (just like we jump over
+ * trylock entries):
+ */
+ if (ret == 2)
+ hlock->read = 2;
+ /*
+ * Add dependency only if this lock is not the head
+ * of the chain, and if it's not a secondary read-lock:
+ */
+ if (!chain_head && ret != 2)
+ if (!check_prevs_add(curr, hlock))
+ return 0;
+ graph_unlock();
+ } else
+ /* after lookup_chain_cache(): */
+ if (unlikely(!debug_locks))
+ return 0;
return 1;
}
+#else
+static inline int validate_chain(struct task_struct *curr,
+ struct lockdep_map *lock, struct held_lock *hlock,
+ int chain_head)
+{
+ return 1;
+}
+#endif
/*
* We are building curr_chain_key incrementally, so double-check
@@ -1425,6 +1625,57 @@ static void check_chain_key(struct task_struct *curr)
#endif
}
+static int
+print_usage_bug(struct task_struct *curr, struct held_lock *this,
+ enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
+{
+ if (!debug_locks_off_graph_unlock() || debug_locks_silent)
+ return 0;
+
+ printk("\n=================================\n");
+ printk( "[ INFO: inconsistent lock state ]\n");
+ print_kernel_version();
+ printk( "---------------------------------\n");
+
+ printk("inconsistent {%s} -> {%s} usage.\n",
+ usage_str[prev_bit], usage_str[new_bit]);
+
+ printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
+ curr->comm, curr->pid,
+ trace_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
+ trace_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
+ trace_hardirqs_enabled(curr),
+ trace_softirqs_enabled(curr));
+ print_lock(this);
+
+ printk("{%s} state was registered at:\n", usage_str[prev_bit]);
+ print_stack_trace(this->class->usage_traces + prev_bit, 1);
+
+ print_irqtrace_events(curr);
+ printk("\nother info that might help us debug this:\n");
+ lockdep_print_held_locks(curr);
+
+ printk("\nstack backtrace:\n");
+ dump_stack();
+
+ return 0;
+}
+
+/*
+ * Print out an error if an invalid bit is set:
+ */
+static inline int
+valid_state(struct task_struct *curr, struct held_lock *this,
+ enum lock_usage_bit new_bit, enum lock_usage_bit bad_bit)
+{
+ if (unlikely(this->class->usage_mask & (1 << bad_bit)))
+ return print_usage_bug(curr, this, bad_bit, new_bit);
+ return 1;
+}
+
+static int mark_lock(struct task_struct *curr, struct held_lock *this,
+ enum lock_usage_bit new_bit);
+
#ifdef CONFIG_TRACE_IRQFLAGS
/*
@@ -1518,90 +1769,30 @@ void print_irqtrace_events(struct task_struct *curr)
print_ip_sym(curr->softirq_disable_ip);
}
-#endif
-
-static int
-print_usage_bug(struct task_struct *curr, struct held_lock *this,
- enum lock_usage_bit prev_bit, enum lock_usage_bit new_bit)
+static int hardirq_verbose(struct lock_class *class)
{
- if (!debug_locks_off_graph_unlock() || debug_locks_silent)
- return 0;
-
- printk("\n=================================\n");
- printk( "[ INFO: inconsistent lock state ]\n");
- print_kernel_version();
- printk( "---------------------------------\n");
-
- printk("inconsistent {%s} -> {%s} usage.\n",
- usage_str[prev_bit], usage_str[new_bit]);
-
- printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] takes:\n",
- curr->comm, curr->pid,
- trace_hardirq_context(curr), hardirq_count() >> HARDIRQ_SHIFT,
- trace_softirq_context(curr), softirq_count() >> SOFTIRQ_SHIFT,
- trace_hardirqs_enabled(curr),
- trace_softirqs_enabled(curr));
- print_lock(this);
-
- printk("{%s} state was registered at:\n", usage_str[prev_bit]);
- print_stack_trace(this->class->usage_traces + prev_bit, 1);
-
- print_irqtrace_events(curr);
- printk("\nother info that might help us debug this:\n");
- lockdep_print_held_locks(curr);
-
- printk("\nstack backtrace:\n");
- dump_stack();
-
+#if HARDIRQ_VERBOSE
+ return class_filter(class);
+#endif
return 0;
}
-/*
- * Print out an error if an invalid bit is set:
- */
-static inline int
-valid_state(struct task_struct *curr, struct held_lock *this,
- enum lock_usage_bit new_bit, enum lock_usage_bit bad_bit)
+static int softirq_verbose(struct lock_class *class)
{
- if (unlikely(this->class->usage_mask & (1 << bad_bit)))
- return print_usage_bug(curr, this, bad_bit, new_bit);
- return 1;
+#if SOFTIRQ_VERBOSE
+ return class_filter(class);
+#endif
+ return 0;
}
#define STRICT_READ_CHECKS 1
-/*
- * Mark a lock with a usage bit, and validate the state transition:
- */
-static int mark_lock(struct task_struct *curr, struct held_lock *this,
- enum lock_usage_bit new_bit)
+static int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
+ enum lock_usage_bit new_bit)
{
- unsigned int new_mask = 1 << new_bit, ret = 1;
-
- /*
- * If already set then do not dirty the cacheline,
- * nor do any checks:
- */
- if (likely(this->class->usage_mask & new_mask))
- return 1;
-
- if (!graph_lock())
- return 0;
- /*
- * Make sure we didnt race:
- */
- if (unlikely(this->class->usage_mask & new_mask)) {
- graph_unlock();
- return 1;
- }
-
- this->class->usage_mask |= new_mask;
+ int ret = 1;
- if (!save_trace(this->class->usage_traces + new_bit))
- return 0;
-
- switch (new_bit) {
-#ifdef CONFIG_TRACE_IRQFLAGS
+ switch(new_bit) {
case LOCK_USED_IN_HARDIRQ:
if (!valid_state(curr, this, new_bit, LOCK_ENABLED_HARDIRQS))
return 0;
@@ -1760,37 +1951,14 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
if (softirq_verbose(this->class))
ret = 2;
break;
-#endif
- case LOCK_USED:
- /*
- * Add it to the global list of classes:
- */
- list_add_tail_rcu(&this->class->lock_entry, &all_lock_classes);
- debug_atomic_dec(&nr_unused_locks);
- break;
default:
- if (!debug_locks_off_graph_unlock())
- return 0;
WARN_ON(1);
- return 0;
- }
-
- graph_unlock();
-
- /*
- * We must printk outside of the graph_lock:
- */
- if (ret == 2) {
- printk("\nmarked lock as {%s}:\n", usage_str[new_bit]);
- print_lock(this);
- print_irqtrace_events(curr);
- dump_stack();
+ break;
}
return ret;
}
-#ifdef CONFIG_TRACE_IRQFLAGS
/*
* Mark all held locks with a usage bit:
*/
@@ -1973,9 +2141,176 @@ void trace_softirqs_off(unsigned long ip)
debug_atomic_inc(&redundant_softirqs_off);
}
+static int mark_irqflags(struct task_struct *curr, struct held_lock *hlock)
+{
+ /*
+ * If non-trylock use in a hardirq or softirq context, then
+ * mark the lock as used in these contexts:
+ */
+ if (!hlock->trylock) {
+ if (hlock->read) {
+ if (curr->hardirq_context)
+ if (!mark_lock(curr, hlock,
+ LOCK_USED_IN_HARDIRQ_READ))
+ return 0;
+ if (curr->softirq_context)
+ if (!mark_lock(curr, hlock,
+ LOCK_USED_IN_SOFTIRQ_READ))
+ return 0;
+ } else {
+ if (curr->hardirq_context)
+ if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
+ return 0;
+ if (curr->softirq_context)
+ if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ))
+ return 0;
+ }
+ }
+ if (!hlock->hardirqs_off) {
+ if (hlock->read) {
+ if (!mark_lock(curr, hlock,
+ LOCK_ENABLED_HARDIRQS_READ))
+ return 0;
+ if (curr->softirqs_enabled)
+ if (!mark_lock(curr, hlock,
+ LOCK_ENABLED_SOFTIRQS_READ))
+ return 0;
+ } else {
+ if (!mark_lock(curr, hlock,
+ LOCK_ENABLED_HARDIRQS))
+ return 0;
+ if (curr->softirqs_enabled)
+ if (!mark_lock(curr, hlock,
+ LOCK_ENABLED_SOFTIRQS))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int separate_irq_context(struct task_struct *curr,
+ struct held_lock *hlock)
+{
+ unsigned int depth = curr->lockdep_depth;
+
+ /*
+ * Keep track of points where we cross into an interrupt context:
+ */
+ hlock->irq_context = 2*(curr->hardirq_context ? 1 : 0) +
+ curr->softirq_context;
+ if (depth) {
+ struct held_lock *prev_hlock;
+
+ prev_hlock = curr->held_locks + depth-1;
+ /*
+ * If we cross into another context, reset the
+ * hash key (this also prevents the checking and the
+ * adding of the dependency to 'prev'):
+ */
+ if (prev_hlock->irq_context != hlock->irq_context)
+ return 1;
+ }
+ return 0;
+}
+
+#else
+
+static inline
+int mark_lock_irq(struct task_struct *curr, struct held_lock *this,
+ enum lock_usage_bit new_bit)
+{
+ WARN_ON(1);
+ return 1;
+}
+
+static inline int mark_irqflags(struct task_struct *curr,
+ struct held_lock *hlock)
+{
+ return 1;
+}
+
+static inline int separate_irq_context(struct task_struct *curr,
+ struct held_lock *hlock)
+{
+ return 0;
+}
+
#endif
/*
+ * Mark a lock with a usage bit, and validate the state transition:
+ */
+static int mark_lock(struct task_struct *curr, struct held_lock *this,
+ enum lock_usage_bit new_bit)
+{
+ unsigned int new_mask = 1 << new_bit, ret = 1;
+
+ /*
+ * If already set then do not dirty the cacheline,
+ * nor do any checks:
+ */
+ if (likely(this->class->usage_mask & new_mask))
+ return 1;
+
+ if (!graph_lock())
+ return 0;
+ /*
+ * Make sure we didnt race:
+ */
+ if (unlikely(this->class->usage_mask & new_mask)) {
+ graph_unlock();
+ return 1;
+ }
+
+ this->class->usage_mask |= new_mask;
+
+ if (!save_trace(this->class->usage_traces + new_bit))
+ return 0;
+
+ switch (new_bit) {
+ case LOCK_USED_IN_HARDIRQ:
+ case LOCK_USED_IN_SOFTIRQ:
+ case LOCK_USED_IN_HARDIRQ_READ:
+ case LOCK_USED_IN_SOFTIRQ_READ:
+ case LOCK_ENABLED_HARDIRQS:
+ case LOCK_ENABLED_SOFTIRQS:
+ case LOCK_ENABLED_HARDIRQS_READ:
+ case LOCK_ENABLED_SOFTIRQS_READ:
+ ret = mark_lock_irq(curr, this, new_bit);
+ if (!ret)
+ return 0;
+ break;
+ case LOCK_USED:
+ /*
+ * Add it to the global list of classes:
+ */
+ list_add_tail_rcu(&this->class->lock_entry, &all_lock_classes);
+ debug_atomic_dec(&nr_unused_locks);
+ break;
+ default:
+ if (!debug_locks_off_graph_unlock())
+ return 0;
+ WARN_ON(1);
+ return 0;
+ }
+
+ graph_unlock();
+
+ /*
+ * We must printk outside of the graph_lock:
+ */
+ if (ret == 2) {
+ printk("\nmarked lock as {%s}:\n", usage_str[new_bit]);
+ print_lock(this);
+ print_irqtrace_events(curr);
+ dump_stack();
+ }
+
+ return ret;
+}
+
+/*
* Initialize a lock instance's lock-class mapping info:
*/
void lockdep_init_map(struct lockdep_map *lock, const char *name,
@@ -1999,6 +2334,9 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
lock->name = name;
lock->key = key;
lock->class_cache = NULL;
+#ifdef CONFIG_LOCK_STAT
+ lock->cpu = raw_smp_processor_id();
+#endif
if (subclass)
register_lock_class(lock, subclass, 1);
}
@@ -2020,6 +2358,9 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
int chain_head = 0;
u64 chain_key;
+ if (!prove_locking)
+ check = 1;
+
if (unlikely(!debug_locks))
return 0;
@@ -2070,57 +2411,18 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
hlock->read = read;
hlock->check = check;
hlock->hardirqs_off = hardirqs_off;
-
- if (check != 2)
- goto out_calc_hash;
-#ifdef CONFIG_TRACE_IRQFLAGS
- /*
- * If non-trylock use in a hardirq or softirq context, then
- * mark the lock as used in these contexts:
- */
- if (!trylock) {
- if (read) {
- if (curr->hardirq_context)
- if (!mark_lock(curr, hlock,
- LOCK_USED_IN_HARDIRQ_READ))
- return 0;
- if (curr->softirq_context)
- if (!mark_lock(curr, hlock,
- LOCK_USED_IN_SOFTIRQ_READ))
- return 0;
- } else {
- if (curr->hardirq_context)
- if (!mark_lock(curr, hlock, LOCK_USED_IN_HARDIRQ))
- return 0;
- if (curr->softirq_context)
- if (!mark_lock(curr, hlock, LOCK_USED_IN_SOFTIRQ))
- return 0;
- }
- }
- if (!hardirqs_off) {
- if (read) {
- if (!mark_lock(curr, hlock,
- LOCK_ENABLED_HARDIRQS_READ))
- return 0;
- if (curr->softirqs_enabled)
- if (!mark_lock(curr, hlock,
- LOCK_ENABLED_SOFTIRQS_READ))
- return 0;
- } else {
- if (!mark_lock(curr, hlock,
- LOCK_ENABLED_HARDIRQS))
- return 0;
- if (curr->softirqs_enabled)
- if (!mark_lock(curr, hlock,
- LOCK_ENABLED_SOFTIRQS))
- return 0;
- }
- }
+#ifdef CONFIG_LOCK_STAT
+ hlock->waittime_stamp = 0;
+ hlock->holdtime_stamp = sched_clock();
#endif
+
+ if (check == 2 && !mark_irqflags(curr, hlock))
+ return 0;
+
/* mark it as used: */
if (!mark_lock(curr, hlock, LOCK_USED))
return 0;
-out_calc_hash:
+
/*
* Calculate the chain hash: it's the combined has of all the
* lock keys along the dependency chain. We save the hash value
@@ -2143,77 +2445,15 @@ out_calc_hash:
}
hlock->prev_chain_key = chain_key;
-
-#ifdef CONFIG_TRACE_IRQFLAGS
- /*
- * Keep track of points where we cross into an interrupt context:
- */
- hlock->irq_context = 2*(curr->hardirq_context ? 1 : 0) +
- curr->softirq_context;
- if (depth) {
- struct held_lock *prev_hlock;
-
- prev_hlock = curr->held_locks + depth-1;
- /*
- * If we cross into another context, reset the
- * hash key (this also prevents the checking and the
- * adding of the dependency to 'prev'):
- */
- if (prev_hlock->irq_context != hlock->irq_context) {
- chain_key = 0;
- chain_head = 1;
- }
+ if (separate_irq_context(curr, hlock)) {
+ chain_key = 0;
+ chain_head = 1;
}
-#endif
chain_key = iterate_chain_key(chain_key, id);
curr->curr_chain_key = chain_key;
- /*
- * Trylock needs to maintain the stack of held locks, but it
- * does not add new dependencies, because trylock can be done
- * in any order.
- *
- * We look up the chain_key and do the O(N^2) check and update of
- * the dependencies only if this is a new dependency chain.
- * (If lookup_chain_cache() returns with 1 it acquires
- * graph_lock for us)
- */
- if (!trylock && (check == 2) && lookup_chain_cache(chain_key, class)) {
- /*
- * Check whether last held lock:
- *
- * - is irq-safe, if this lock is irq-unsafe
- * - is softirq-safe, if this lock is hardirq-unsafe
- *
- * And check whether the new lock's dependency graph
- * could lead back to the previous lock.
- *
- * any of these scenarios could lead to a deadlock. If
- * All validations
- */
- int ret = check_deadlock(curr, hlock, lock, read);
-
- if (!ret)
- return 0;
- /*
- * Mark recursive read, as we jump over it when
- * building dependencies (just like we jump over
- * trylock entries):
- */
- if (ret == 2)
- hlock->read = 2;
- /*
- * Add dependency only if this lock is not the head
- * of the chain, and if it's not a secondary read-lock:
- */
- if (!chain_head && ret != 2)
- if (!check_prevs_add(curr, hlock))
- return 0;
- graph_unlock();
- } else
- /* after lookup_chain_cache(): */
- if (unlikely(!debug_locks))
- return 0;
+ if (!validate_chain(curr, lock, hlock, chain_head))
+ return 0;
curr->lockdep_depth++;
check_chain_key(curr);
@@ -2315,6 +2555,8 @@ lock_release_non_nested(struct task_struct *curr,
return print_unlock_inbalance_bug(curr, lock, ip);
found_it:
+ lock_release_holdtime(hlock);
+
/*
* We have the right lock to unlock, 'hlock' points to it.
* Now we remove it from the stack, and add back the other
@@ -2367,6 +2609,8 @@ static int lock_release_nested(struct task_struct *curr,
curr->curr_chain_key = hlock->prev_chain_key;
+ lock_release_holdtime(hlock);
+
#ifdef CONFIG_DEBUG_LOCKDEP
hlock->prev_chain_key = 0;
hlock->class = NULL;
@@ -2441,6 +2685,9 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
{
unsigned long flags;
+ if (unlikely(!lock_stat && !prove_locking))
+ return;
+
if (unlikely(current->lockdep_recursion))
return;
@@ -2460,6 +2707,9 @@ void lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
{
unsigned long flags;
+ if (unlikely(!lock_stat && !prove_locking))
+ return;
+
if (unlikely(current->lockdep_recursion))
return;
@@ -2473,6 +2723,166 @@ void lock_release(struct lockdep_map *lock, int nested, unsigned long ip)
EXPORT_SYMBOL_GPL(lock_release);
+#ifdef CONFIG_LOCK_STAT
+static int
+print_lock_contention_bug(struct task_struct *curr, struct lockdep_map *lock,
+ unsigned long ip)
+{
+ if (!debug_locks_off())
+ return 0;
+ if (debug_locks_silent)
+ return 0;
+
+ printk("\n=================================\n");
+ printk( "[ BUG: bad contention detected! ]\n");
+ printk( "---------------------------------\n");
+ printk("%s/%d is trying to contend lock (",
+ curr->comm, curr->pid);
+ print_lockdep_cache(lock);
+ printk(") at:\n");
+ print_ip_sym(ip);
+ printk("but there are no locks held!\n");
+ printk("\nother info that might help us debug this:\n");
+ lockdep_print_held_locks(curr);
+
+ printk("\nstack backtrace:\n");
+ dump_stack();
+
+ return 0;
+}
+
+static void
+__lock_contended(struct lockdep_map *lock, unsigned long ip)
+{
+ struct task_struct *curr = current;
+ struct held_lock *hlock, *prev_hlock;
+ struct lock_class_stats *stats;
+ unsigned int depth;
+ int i, point;
+
+ depth = curr->lockdep_depth;
+ if (DEBUG_LOCKS_WARN_ON(!depth))
+ return;
+
+ prev_hlock = NULL;
+ for (i = depth-1; i >= 0; i--) {
+ hlock = curr->held_locks + i;
+ /*
+ * We must not cross into another context:
+ */
+ if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
+ break;
+ if (hlock->instance == lock)
+ goto found_it;
+ prev_hlock = hlock;
+ }
+ print_lock_contention_bug(curr, lock, ip);
+ return;
+
+found_it:
+ hlock->waittime_stamp = sched_clock();
+
+ point = lock_contention_point(hlock->class, ip);
+
+ stats = get_lock_stats(hlock->class);
+ if (point < ARRAY_SIZE(stats->contention_point))
+ stats->contention_point[i]++;
+ if (lock->cpu != smp_processor_id())
+ stats->bounces[bounce_contended + !!hlock->read]++;
+ put_lock_stats(stats);
+}
+
+static void
+__lock_acquired(struct lockdep_map *lock)
+{
+ struct task_struct *curr = current;
+ struct held_lock *hlock, *prev_hlock;
+ struct lock_class_stats *stats;
+ unsigned int depth;
+ u64 now;
+ s64 waittime = 0;
+ int i, cpu;
+
+ depth = curr->lockdep_depth;
+ if (DEBUG_LOCKS_WARN_ON(!depth))
+ return;
+
+ prev_hlock = NULL;
+ for (i = depth-1; i >= 0; i--) {
+ hlock = curr->held_locks + i;
+ /*
+ * We must not cross into another context:
+ */
+ if (prev_hlock && prev_hlock->irq_context != hlock->irq_context)
+ break;
+ if (hlock->instance == lock)
+ goto found_it;
+ prev_hlock = hlock;
+ }
+ print_lock_contention_bug(curr, lock, _RET_IP_);
+ return;
+
+found_it:
+ cpu = smp_processor_id();
+ if (hlock->waittime_stamp) {
+ now = sched_clock();
+ waittime = now - hlock->waittime_stamp;
+ hlock->holdtime_stamp = now;
+ }
+
+ stats = get_lock_stats(hlock->class);
+ if (waittime) {
+ if (hlock->read)
+ lock_time_inc(&stats->read_waittime, waittime);
+ else
+ lock_time_inc(&stats->write_waittime, waittime);
+ }
+ if (lock->cpu != cpu)
+ stats->bounces[bounce_acquired + !!hlock->read]++;
+ put_lock_stats(stats);
+
+ lock->cpu = cpu;
+}
+
+void lock_contended(struct lockdep_map *lock, unsigned long ip)
+{
+ unsigned long flags;
+
+ if (unlikely(!lock_stat))
+ return;
+
+ if (unlikely(current->lockdep_recursion))
+ return;
+
+ raw_local_irq_save(flags);
+ check_flags(flags);
+ current->lockdep_recursion = 1;
+ __lock_contended(lock, ip);
+ current->lockdep_recursion = 0;
+ raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(lock_contended);
+
+void lock_acquired(struct lockdep_map *lock)
+{
+ unsigned long flags;
+
+ if (unlikely(!lock_stat))
+ return;
+
+ if (unlikely(current->lockdep_recursion))
+ return;
+
+ raw_local_irq_save(flags);
+ check_flags(flags);
+ current->lockdep_recursion = 1;
+ __lock_acquired(lock);
+ current->lockdep_recursion = 0;
+ raw_local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(lock_acquired);
+#endif
+
/*
* Used by the testsuite, sanitize the validator state
* after a simulated failure:
@@ -2636,8 +3046,11 @@ void __init lockdep_info(void)
sizeof(struct held_lock) * MAX_LOCK_DEPTH);
#ifdef CONFIG_DEBUG_LOCKDEP
- if (lockdep_init_error)
- printk("WARNING: lockdep init error! Arch code didnt call lockdep_init() early enough?\n");
+ if (lockdep_init_error) {
+ printk("WARNING: lockdep init error! Arch code didn't call lockdep_init() early enough?\n");
+ printk("Call stack leading to lockdep invocation was:\n");
+ print_stack_trace(&lockdep_init_trace, 0);
+ }
#endif
}
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c
index 58f35e586ee3..9f17af4a2490 100644
--- a/kernel/lockdep_proc.c
+++ b/kernel/lockdep_proc.c
@@ -5,7 +5,8 @@
*
* Started by Ingo Molnar:
*
- * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
*
* Code for /proc/lockdep and /proc/lockdep_stats:
*
@@ -15,6 +16,10 @@
#include <linux/seq_file.h>
#include <linux/kallsyms.h>
#include <linux/debug_locks.h>
+#include <linux/vmalloc.h>
+#include <linux/sort.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
#include "lockdep_internals.h"
@@ -271,8 +276,10 @@ static int lockdep_stats_show(struct seq_file *m, void *v)
if (nr_list_entries)
factor = sum_forward_deps / nr_list_entries;
+#ifdef CONFIG_PROVE_LOCKING
seq_printf(m, " dependency chains: %11lu [max: %lu]\n",
nr_lock_chains, MAX_LOCKDEP_CHAINS);
+#endif
#ifdef CONFIG_TRACE_IRQFLAGS
seq_printf(m, " in-hardirq chains: %11u\n",
@@ -342,6 +349,292 @@ static const struct file_operations proc_lockdep_stats_operations = {
.release = seq_release,
};
+#ifdef CONFIG_LOCK_STAT
+
+struct lock_stat_data {
+ struct lock_class *class;
+ struct lock_class_stats stats;
+};
+
+struct lock_stat_seq {
+ struct lock_stat_data *iter;
+ struct lock_stat_data *iter_end;
+ struct lock_stat_data stats[MAX_LOCKDEP_KEYS];
+};
+
+/*
+ * sort on absolute number of contentions
+ */
+static int lock_stat_cmp(const void *l, const void *r)
+{
+ const struct lock_stat_data *dl = l, *dr = r;
+ unsigned long nl, nr;
+
+ nl = dl->stats.read_waittime.nr + dl->stats.write_waittime.nr;
+ nr = dr->stats.read_waittime.nr + dr->stats.write_waittime.nr;
+
+ return nr - nl;
+}
+
+static void seq_line(struct seq_file *m, char c, int offset, int length)
+{
+ int i;
+
+ for (i = 0; i < offset; i++)
+ seq_puts(m, " ");
+ for (i = 0; i < length; i++)
+ seq_printf(m, "%c", c);
+ seq_puts(m, "\n");
+}
+
+static void snprint_time(char *buf, size_t bufsiz, s64 nr)
+{
+ unsigned long rem;
+
+ rem = do_div(nr, 1000); /* XXX: do_div_signed */
+ snprintf(buf, bufsiz, "%lld.%02d", (long long)nr, ((int)rem+5)/10);
+}
+
+static void seq_time(struct seq_file *m, s64 time)
+{
+ char num[15];
+
+ snprint_time(num, sizeof(num), time);
+ seq_printf(m, " %14s", num);
+}
+
+static void seq_lock_time(struct seq_file *m, struct lock_time *lt)
+{
+ seq_printf(m, "%14lu", lt->nr);
+ seq_time(m, lt->min);
+ seq_time(m, lt->max);
+ seq_time(m, lt->total);
+}
+
+static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
+{
+ char name[39];
+ struct lock_class *class;
+ struct lock_class_stats *stats;
+ int i, namelen;
+
+ class = data->class;
+ stats = &data->stats;
+
+ namelen = 38;
+ if (class->name_version > 1)
+ namelen -= 2; /* XXX truncates versions > 9 */
+ if (class->subclass)
+ namelen -= 2;
+
+ if (!class->name) {
+ char str[KSYM_NAME_LEN];
+ const char *key_name;
+
+ key_name = __get_key_name(class->key, str);
+ snprintf(name, namelen, "%s", key_name);
+ } else {
+ snprintf(name, namelen, "%s", class->name);
+ }
+ namelen = strlen(name);
+ if (class->name_version > 1) {
+ snprintf(name+namelen, 3, "#%d", class->name_version);
+ namelen += 2;
+ }
+ if (class->subclass) {
+ snprintf(name+namelen, 3, "/%d", class->subclass);
+ namelen += 2;
+ }
+
+ if (stats->write_holdtime.nr) {
+ if (stats->read_holdtime.nr)
+ seq_printf(m, "%38s-W:", name);
+ else
+ seq_printf(m, "%40s:", name);
+
+ seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]);
+ seq_lock_time(m, &stats->write_waittime);
+ seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]);
+ seq_lock_time(m, &stats->write_holdtime);
+ seq_puts(m, "\n");
+ }
+
+ if (stats->read_holdtime.nr) {
+ seq_printf(m, "%38s-R:", name);
+ seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]);
+ seq_lock_time(m, &stats->read_waittime);
+ seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]);
+ seq_lock_time(m, &stats->read_holdtime);
+ seq_puts(m, "\n");
+ }
+
+ if (stats->read_waittime.nr + stats->write_waittime.nr == 0)
+ return;
+
+ if (stats->read_holdtime.nr)
+ namelen += 2;
+
+ for (i = 0; i < ARRAY_SIZE(class->contention_point); i++) {
+ char sym[KSYM_SYMBOL_LEN];
+ char ip[32];
+
+ if (class->contention_point[i] == 0)
+ break;
+
+ if (!i)
+ seq_line(m, '-', 40-namelen, namelen);
+
+ sprint_symbol(sym, class->contention_point[i]);
+ snprintf(ip, sizeof(ip), "[<%p>]",
+ (void *)class->contention_point[i]);
+ seq_printf(m, "%40s %14lu %29s %s\n", name,
+ stats->contention_point[i],
+ ip, sym);
+ }
+ if (i) {
+ seq_puts(m, "\n");
+ seq_line(m, '.', 0, 40 + 1 + 10 * (14 + 1));
+ seq_puts(m, "\n");
+ }
+}
+
+static void seq_header(struct seq_file *m)
+{
+ seq_printf(m, "lock_stat version 0.2\n");
+ seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
+ seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s "
+ "%14s %14s\n",
+ "class name",
+ "con-bounces",
+ "contentions",
+ "waittime-min",
+ "waittime-max",
+ "waittime-total",
+ "acq-bounces",
+ "acquisitions",
+ "holdtime-min",
+ "holdtime-max",
+ "holdtime-total");
+ seq_line(m, '-', 0, 40 + 1 + 10 * (14 + 1));
+ seq_printf(m, "\n");
+}
+
+static void *ls_start(struct seq_file *m, loff_t *pos)
+{
+ struct lock_stat_seq *data = m->private;
+
+ if (data->iter == data->stats)
+ seq_header(m);
+
+ if (data->iter == data->iter_end)
+ data->iter = NULL;
+
+ return data->iter;
+}
+
+static void *ls_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct lock_stat_seq *data = m->private;
+
+ (*pos)++;
+
+ data->iter = v;
+ data->iter++;
+ if (data->iter == data->iter_end)
+ data->iter = NULL;
+
+ return data->iter;
+}
+
+static void ls_stop(struct seq_file *m, void *v)
+{
+}
+
+static int ls_show(struct seq_file *m, void *v)
+{
+ struct lock_stat_seq *data = m->private;
+
+ seq_stats(m, data->iter);
+ return 0;
+}
+
+static struct seq_operations lockstat_ops = {
+ .start = ls_start,
+ .next = ls_next,
+ .stop = ls_stop,
+ .show = ls_show,
+};
+
+static int lock_stat_open(struct inode *inode, struct file *file)
+{
+ int res;
+ struct lock_class *class;
+ struct lock_stat_seq *data = vmalloc(sizeof(struct lock_stat_seq));
+
+ if (!data)
+ return -ENOMEM;
+
+ res = seq_open(file, &lockstat_ops);
+ if (!res) {
+ struct lock_stat_data *iter = data->stats;
+ struct seq_file *m = file->private_data;
+
+ data->iter = iter;
+ list_for_each_entry(class, &all_lock_classes, lock_entry) {
+ iter->class = class;
+ iter->stats = lock_stats(class);
+ iter++;
+ }
+ data->iter_end = iter;
+
+ sort(data->stats, data->iter_end - data->iter,
+ sizeof(struct lock_stat_data),
+ lock_stat_cmp, NULL);
+
+ m->private = data;
+ } else
+ vfree(data);
+
+ return res;
+}
+
+static ssize_t lock_stat_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct lock_class *class;
+ char c;
+
+ if (count) {
+ if (get_user(c, buf))
+ return -EFAULT;
+
+ if (c != '0')
+ return count;
+
+ list_for_each_entry(class, &all_lock_classes, lock_entry)
+ clear_lock_stats(class);
+ }
+ return count;
+}
+
+static int lock_stat_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+
+ vfree(seq->private);
+ seq->private = NULL;
+ return seq_release(inode, file);
+}
+
+static const struct file_operations proc_lock_stat_operations = {
+ .open = lock_stat_open,
+ .write = lock_stat_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = lock_stat_release,
+};
+#endif /* CONFIG_LOCK_STAT */
+
static int __init lockdep_proc_init(void)
{
struct proc_dir_entry *entry;
@@ -354,6 +647,12 @@ static int __init lockdep_proc_init(void)
if (entry)
entry->proc_fops = &proc_lockdep_stats_operations;
+#ifdef CONFIG_LOCK_STAT
+ entry = create_proc_entry("lock_stat", S_IRUSR, NULL);
+ if (entry)
+ entry->proc_fops = &proc_lock_stat_operations;
+#endif
+
return 0;
}
diff --git a/kernel/module.c b/kernel/module.c
index 9bd93de01f4a..33c04ad51175 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -61,10 +61,8 @@ extern int module_sysfs_initialized;
/* If this is set, the section belongs in the init part of the module */
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
-/* Protects module list */
-static DEFINE_SPINLOCK(modlist_lock);
-
-/* List of modules, protected by module_mutex AND modlist_lock */
+/* List of modules, protected by module_mutex or preempt_disable
+ * (add/delete uses stop_machine). */
static DEFINE_MUTEX(module_mutex);
static LIST_HEAD(modules);
@@ -488,8 +486,7 @@ static void free_modinfo_##field(struct module *mod) \
mod->field = NULL; \
} \
static struct module_attribute modinfo_##field = { \
- .attr = { .name = __stringify(field), .mode = 0444, \
- .owner = THIS_MODULE }, \
+ .attr = { .name = __stringify(field), .mode = 0444 }, \
.show = show_modinfo_##field, \
.setup = setup_modinfo_##field, \
.test = modinfo_##field##_exists, \
@@ -761,14 +758,13 @@ static void print_unload_info(struct seq_file *m, struct module *mod)
void __symbol_put(const char *symbol)
{
struct module *owner;
- unsigned long flags;
const unsigned long *crc;
- spin_lock_irqsave(&modlist_lock, flags);
+ preempt_disable();
if (!__find_symbol(symbol, &owner, &crc, 1))
BUG();
module_put(owner);
- spin_unlock_irqrestore(&modlist_lock, flags);
+ preempt_enable();
}
EXPORT_SYMBOL(__symbol_put);
@@ -793,7 +789,7 @@ static ssize_t show_refcnt(struct module_attribute *mattr,
}
static struct module_attribute refcnt = {
- .attr = { .name = "refcnt", .mode = 0444, .owner = THIS_MODULE },
+ .attr = { .name = "refcnt", .mode = 0444 },
.show = show_refcnt,
};
@@ -851,7 +847,7 @@ static ssize_t show_initstate(struct module_attribute *mattr,
}
static struct module_attribute initstate = {
- .attr = { .name = "initstate", .mode = 0444, .owner = THIS_MODULE },
+ .attr = { .name = "initstate", .mode = 0444 },
.show = show_initstate,
};
@@ -1032,7 +1028,6 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
sattr->mattr.show = module_sect_show;
sattr->mattr.store = NULL;
sattr->mattr.attr.name = sattr->name;
- sattr->mattr.attr.owner = mod;
sattr->mattr.attr.mode = S_IRUGO;
*(gattr++) = &(sattr++)->mattr.attr;
}
@@ -1090,7 +1085,6 @@ int module_add_modinfo_attrs(struct module *mod)
if (!attr->test ||
(attr->test && attr->test(mod))) {
memcpy(temp_attr, attr, sizeof(*temp_attr));
- temp_attr->attr.owner = mod;
error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
++temp_attr;
}
@@ -1231,14 +1225,14 @@ static void free_module(struct module *mod)
void *__symbol_get(const char *symbol)
{
struct module *owner;
- unsigned long value, flags;
+ unsigned long value;
const unsigned long *crc;
- spin_lock_irqsave(&modlist_lock, flags);
+ preempt_disable();
value = __find_symbol(symbol, &owner, &crc, 1);
if (value && !strong_try_module_get(owner))
value = 0;
- spin_unlock_irqrestore(&modlist_lock, flags);
+ preempt_enable();
return (void *)value;
}
@@ -2139,7 +2133,7 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
sym = get_ksymbol(mod, addr, NULL, NULL);
if (!sym)
goto out;
- strlcpy(symname, sym, KSYM_NAME_LEN + 1);
+ strlcpy(symname, sym, KSYM_NAME_LEN);
mutex_unlock(&module_mutex);
return 0;
}
@@ -2164,9 +2158,9 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
if (!sym)
goto out;
if (modname)
- strlcpy(modname, mod->name, MODULE_NAME_LEN + 1);
+ strlcpy(modname, mod->name, MODULE_NAME_LEN);
if (name)
- strlcpy(name, sym, KSYM_NAME_LEN + 1);
+ strlcpy(name, sym, KSYM_NAME_LEN);
mutex_unlock(&module_mutex);
return 0;
}
@@ -2187,8 +2181,8 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
*value = mod->symtab[symnum].st_value;
*type = mod->symtab[symnum].st_info;
strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
- KSYM_NAME_LEN + 1);
- strlcpy(module_name, mod->name, MODULE_NAME_LEN + 1);
+ KSYM_NAME_LEN);
+ strlcpy(module_name, mod->name, MODULE_NAME_LEN);
*exported = is_exported(name, mod);
mutex_unlock(&module_mutex);
return 0;
@@ -2235,26 +2229,13 @@ unsigned long module_kallsyms_lookup_name(const char *name)
/* Called by the /proc file system to return a list of modules. */
static void *m_start(struct seq_file *m, loff_t *pos)
{
- struct list_head *i;
- loff_t n = 0;
-
mutex_lock(&module_mutex);
- list_for_each(i, &modules) {
- if (n++ == *pos)
- break;
- }
- if (i == &modules)
- return NULL;
- return i;
+ return seq_list_start(&modules, *pos);
}
static void *m_next(struct seq_file *m, void *p, loff_t *pos)
{
- struct list_head *i = p;
- (*pos)++;
- if (i->next == &modules)
- return NULL;
- return i->next;
+ return seq_list_next(p, &modules, pos);
}
static void m_stop(struct seq_file *m, void *p)
@@ -2324,11 +2305,10 @@ const struct seq_operations modules_op = {
/* Given an address, look for it in the module exception tables. */
const struct exception_table_entry *search_module_extables(unsigned long addr)
{
- unsigned long flags;
const struct exception_table_entry *e = NULL;
struct module *mod;
- spin_lock_irqsave(&modlist_lock, flags);
+ preempt_disable();
list_for_each_entry(mod, &modules, list) {
if (mod->num_exentries == 0)
continue;
@@ -2339,7 +2319,7 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
if (e)
break;
}
- spin_unlock_irqrestore(&modlist_lock, flags);
+ preempt_enable();
/* Now, if we found one, we are running inside it now, hence
we cannot unload the module, hence no refcnt needed. */
@@ -2351,25 +2331,24 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
*/
int is_module_address(unsigned long addr)
{
- unsigned long flags;
struct module *mod;
- spin_lock_irqsave(&modlist_lock, flags);
+ preempt_disable();
list_for_each_entry(mod, &modules, list) {
if (within(addr, mod->module_core, mod->core_size)) {
- spin_unlock_irqrestore(&modlist_lock, flags);
+ preempt_enable();
return 1;
}
}
- spin_unlock_irqrestore(&modlist_lock, flags);
+ preempt_enable();
return 0;
}
-/* Is this a valid kernel address? We don't grab the lock: we are oopsing. */
+/* Is this a valid kernel address? */
struct module *__module_text_address(unsigned long addr)
{
struct module *mod;
@@ -2384,11 +2363,10 @@ struct module *__module_text_address(unsigned long addr)
struct module *module_text_address(unsigned long addr)
{
struct module *mod;
- unsigned long flags;
- spin_lock_irqsave(&modlist_lock, flags);
+ preempt_disable();
mod = __module_text_address(addr);
- spin_unlock_irqrestore(&modlist_lock, flags);
+ preempt_enable();
return mod;
}
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 303eab18484b..691b86564dd9 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -139,6 +139,12 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
list_add_tail(&waiter.list, &lock->wait_list);
waiter.task = task;
+ old_val = atomic_xchg(&lock->count, -1);
+ if (old_val == 1)
+ goto done;
+
+ lock_contended(&lock->dep_map, _RET_IP_);
+
for (;;) {
/*
* Lets try to take the lock again - this is needed even if
@@ -174,6 +180,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass)
spin_lock_mutex(&lock->wait_lock, flags);
}
+done:
+ lock_acquired(&lock->dep_map);
/* got the lock - rejoice! */
mutex_remove_waiter(lock, &waiter, task_thread_info(task));
debug_mutex_set_owner(lock, task_thread_info(task));
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 9e83b589f754..a4fb7d46971f 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -21,6 +21,8 @@
#include <linux/utsname.h>
#include <linux/pid_namespace.h>
+static struct kmem_cache *nsproxy_cachep;
+
struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
static inline void get_nsproxy(struct nsproxy *ns)
@@ -43,9 +45,11 @@ static inline struct nsproxy *clone_nsproxy(struct nsproxy *orig)
{
struct nsproxy *ns;
- ns = kmemdup(orig, sizeof(struct nsproxy), GFP_KERNEL);
- if (ns)
+ ns = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL);
+ if (ns) {
+ memcpy(ns, orig, sizeof(struct nsproxy));
atomic_set(&ns->count, 1);
+ }
return ns;
}
@@ -54,33 +58,51 @@ static inline struct nsproxy *clone_nsproxy(struct nsproxy *orig)
* Return the newly created nsproxy. Do not attach this to the task,
* leave it to the caller to do proper locking and attach it to task.
*/
-static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk,
- struct fs_struct *new_fs)
+static struct nsproxy *create_new_namespaces(unsigned long flags,
+ struct task_struct *tsk, struct fs_struct *new_fs)
{
struct nsproxy *new_nsp;
+ int err;
new_nsp = clone_nsproxy(tsk->nsproxy);
if (!new_nsp)
return ERR_PTR(-ENOMEM);
new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs);
- if (IS_ERR(new_nsp->mnt_ns))
+ if (IS_ERR(new_nsp->mnt_ns)) {
+ err = PTR_ERR(new_nsp->mnt_ns);
goto out_ns;
+ }
new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns);
- if (IS_ERR(new_nsp->uts_ns))
+ if (IS_ERR(new_nsp->uts_ns)) {
+ err = PTR_ERR(new_nsp->uts_ns);
goto out_uts;
+ }
new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns);
- if (IS_ERR(new_nsp->ipc_ns))
+ if (IS_ERR(new_nsp->ipc_ns)) {
+ err = PTR_ERR(new_nsp->ipc_ns);
goto out_ipc;
+ }
new_nsp->pid_ns = copy_pid_ns(flags, tsk->nsproxy->pid_ns);
- if (IS_ERR(new_nsp->pid_ns))
+ if (IS_ERR(new_nsp->pid_ns)) {
+ err = PTR_ERR(new_nsp->pid_ns);
goto out_pid;
+ }
+
+ new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns);
+ if (IS_ERR(new_nsp->user_ns)) {
+ err = PTR_ERR(new_nsp->user_ns);
+ goto out_user;
+ }
return new_nsp;
+out_user:
+ if (new_nsp->pid_ns)
+ put_pid_ns(new_nsp->pid_ns);
out_pid:
if (new_nsp->ipc_ns)
put_ipc_ns(new_nsp->ipc_ns);
@@ -91,15 +113,15 @@ out_uts:
if (new_nsp->mnt_ns)
put_mnt_ns(new_nsp->mnt_ns);
out_ns:
- kfree(new_nsp);
- return ERR_PTR(-ENOMEM);
+ kmem_cache_free(nsproxy_cachep, new_nsp);
+ return ERR_PTR(err);
}
/*
* called from clone. This now handles copy for nsproxy and all
* namespaces therein.
*/
-int copy_namespaces(int flags, struct task_struct *tsk)
+int copy_namespaces(unsigned long flags, struct task_struct *tsk)
{
struct nsproxy *old_ns = tsk->nsproxy;
struct nsproxy *new_ns;
@@ -110,7 +132,7 @@ int copy_namespaces(int flags, struct task_struct *tsk)
get_nsproxy(old_ns);
- if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
+ if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER)))
return 0;
if (!capable(CAP_SYS_ADMIN)) {
@@ -140,7 +162,9 @@ void free_nsproxy(struct nsproxy *ns)
put_ipc_ns(ns->ipc_ns);
if (ns->pid_ns)
put_pid_ns(ns->pid_ns);
- kfree(ns);
+ if (ns->user_ns)
+ put_user_ns(ns->user_ns);
+ kmem_cache_free(nsproxy_cachep, ns);
}
/*
@@ -152,19 +176,10 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
{
int err = 0;
- if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
+ if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
+ CLONE_NEWUSER)))
return 0;
-#ifndef CONFIG_IPC_NS
- if (unshare_flags & CLONE_NEWIPC)
- return -EINVAL;
-#endif
-
-#ifndef CONFIG_UTS_NS
- if (unshare_flags & CLONE_NEWUTS)
- return -EINVAL;
-#endif
-
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -174,3 +189,12 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
err = PTR_ERR(*new_nsp);
return err;
}
+
+static int __init nsproxy_cache_init(void)
+{
+ nsproxy_cachep = kmem_cache_create("nsproxy", sizeof(struct nsproxy),
+ 0, SLAB_PANIC, NULL);
+ return 0;
+}
+
+module_init(nsproxy_cache_init);
diff --git a/kernel/panic.c b/kernel/panic.c
index 623d1828259a..f64f4c1ac11f 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -159,14 +159,15 @@ const char *print_tainted(void)
{
static char buf[20];
if (tainted) {
- snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c",
+ snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c",
tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
tainted & TAINT_FORCED_RMMOD ? 'R' : ' ',
tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
tainted & TAINT_BAD_PAGE ? 'B' : ' ',
- tainted & TAINT_USER ? 'U' : ' ');
+ tainted & TAINT_USER ? 'U' : ' ',
+ tainted & TAINT_DIE ? 'D' : ' ');
}
else
snprintf(buf, sizeof(buf), "Not tainted");
diff --git a/kernel/params.c b/kernel/params.c
index e61c46c97ce7..effbaaedd7f3 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -491,7 +491,6 @@ param_sysfs_setup(struct module_kobject *mk,
pattr->mattr.show = param_attr_show;
pattr->mattr.store = param_attr_store;
pattr->mattr.attr.name = (char *)&kp->name[name_skip];
- pattr->mattr.attr.owner = mk->mod;
pattr->mattr.attr.mode = kp->perm;
*(gattr++) = &(pattr++)->mattr.attr;
}
diff --git a/kernel/pid.c b/kernel/pid.c
index eb66bd2953ab..c6e3f9ffff87 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -365,7 +365,7 @@ struct pid *find_ge_pid(int nr)
}
EXPORT_SYMBOL_GPL(find_get_pid);
-struct pid_namespace *copy_pid_ns(int flags, struct pid_namespace *old_ns)
+struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns)
{
BUG_ON(!old_ns);
get_pid_ns(old_ns);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 329ce0172074..55b3761edaa9 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -241,7 +241,7 @@ static __init int init_posix_timers(void)
register_posix_clock(CLOCK_MONOTONIC, &clock_monotonic);
posix_timers_cache = kmem_cache_create("posix_timers_cache",
- sizeof (struct k_itimer), 0, 0, NULL, NULL);
+ sizeof (struct k_itimer), 0, 0, NULL);
idr_init(&posix_timers_id);
return 0;
}
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 495b7d4dd330..c1a106d87d90 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -33,13 +33,20 @@ config PM_DEBUG
bool "Power Management Debug Support"
depends on PM
---help---
- This option enables verbose debugging support in the Power Management
- code. This is helpful when debugging and reporting various PM bugs,
- like suspend support.
+ This option enables various debugging support in the Power Management
+ code. This is helpful when debugging and reporting PM bugs, like
+ suspend support.
+
+config PM_VERBOSE
+ bool "Verbose Power Management debugging"
+ depends on PM_DEBUG
+ default n
+ ---help---
+ This option enables verbose messages from the Power Management code.
config DISABLE_CONSOLE_SUSPEND
bool "Keep console(s) enabled during suspend/resume (DANGEROUS)"
- depends on PM && PM_DEBUG
+ depends on PM_DEBUG
default n
---help---
This option turns off the console suspend mechanism that prevents
@@ -50,7 +57,7 @@ config DISABLE_CONSOLE_SUSPEND
config PM_TRACE
bool "Suspend/resume event tracing"
- depends on PM && PM_DEBUG && X86_32 && EXPERIMENTAL
+ depends on PM_DEBUG && X86 && EXPERIMENTAL
default n
---help---
This enables some cheesy code to save the last PM event point in the
@@ -65,18 +72,6 @@ config PM_TRACE
CAUTION: this option will cause your machine's real-time clock to be
set to an invalid time after a resume.
-config PM_SYSFS_DEPRECATED
- bool "Driver model /sys/devices/.../power/state files (DEPRECATED)"
- depends on PM && SYSFS
- default n
- help
- The driver model started out with a sysfs file intended to provide
- a userspace hook for device power management. This feature has never
- worked very well, except for limited testing purposes, and so it will
- be removed. It's not clear that a generic mechanism could really
- handle the wide variability of device power states; any replacements
- are likely to be bus or driver specific.
-
config SOFTWARE_SUSPEND
bool "Software Suspend (Hibernation)"
depends on PM && SWAP && (((X86 || PPC64_SWSUSP) && (!SMP || SUSPEND_SMP)) || ((FRV || PPC32) && !SMP))
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index f445b9cd60fb..324ac0188ce1 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -45,7 +45,7 @@ enum {
static int hibernation_mode = HIBERNATION_SHUTDOWN;
-struct hibernation_ops *hibernation_ops;
+static struct hibernation_ops *hibernation_ops;
/**
* hibernation_set_ops - set the global hibernate operations
@@ -54,7 +54,8 @@ struct hibernation_ops *hibernation_ops;
void hibernation_set_ops(struct hibernation_ops *ops)
{
- if (ops && !(ops->prepare && ops->enter && ops->finish)) {
+ if (ops && !(ops->prepare && ops->enter && ops->finish
+ && ops->pre_restore && ops->restore_cleanup)) {
WARN_ON(1);
return;
}
@@ -74,9 +75,9 @@ void hibernation_set_ops(struct hibernation_ops *ops)
* platform driver if so configured and return an error code if it fails
*/
-static int platform_prepare(void)
+static int platform_prepare(int platform_mode)
{
- return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ?
+ return (platform_mode && hibernation_ops) ?
hibernation_ops->prepare() : 0;
}
@@ -85,13 +86,145 @@ static int platform_prepare(void)
* using the platform driver (must be called after platform_prepare())
*/
-static void platform_finish(void)
+static void platform_finish(int platform_mode)
{
- if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops)
+ if (platform_mode && hibernation_ops)
hibernation_ops->finish();
}
/**
+ * platform_pre_restore - prepare the platform for the restoration from a
+ * hibernation image. If the restore fails after this function has been
+ * called, platform_restore_cleanup() must be called.
+ */
+
+static int platform_pre_restore(int platform_mode)
+{
+ return (platform_mode && hibernation_ops) ?
+ hibernation_ops->pre_restore() : 0;
+}
+
+/**
+ * platform_restore_cleanup - switch the platform to the normal mode of
+ * operation after a failing restore. If platform_pre_restore() has been
+ * called before the failing restore, this function must be called too,
+ * regardless of the result of platform_pre_restore().
+ */
+
+static void platform_restore_cleanup(int platform_mode)
+{
+ if (platform_mode && hibernation_ops)
+ hibernation_ops->restore_cleanup();
+}
+
+/**
+ * hibernation_snapshot - quiesce devices and create the hibernation
+ * snapshot image.
+ * @platform_mode - if set, use the platform driver, if available, to
+ * prepare the platform frimware for the power transition.
+ *
+ * Must be called with pm_mutex held
+ */
+
+int hibernation_snapshot(int platform_mode)
+{
+ int error;
+
+ /* Free memory before shutting down devices. */
+ error = swsusp_shrink_memory();
+ if (error)
+ return error;
+
+ suspend_console();
+ error = device_suspend(PMSG_FREEZE);
+ if (error)
+ goto Resume_console;
+
+ error = platform_prepare(platform_mode);
+ if (error)
+ goto Resume_devices;
+
+ error = disable_nonboot_cpus();
+ if (!error) {
+ if (hibernation_mode != HIBERNATION_TEST) {
+ in_suspend = 1;
+ error = swsusp_suspend();
+ /* Control returns here after successful restore */
+ } else {
+ printk("swsusp debug: Waiting for 5 seconds.\n");
+ mdelay(5000);
+ }
+ }
+ enable_nonboot_cpus();
+ Resume_devices:
+ platform_finish(platform_mode);
+ device_resume();
+ Resume_console:
+ resume_console();
+ return error;
+}
+
+/**
+ * hibernation_restore - quiesce devices and restore the hibernation
+ * snapshot image. If successful, control returns in hibernation_snaphot()
+ * @platform_mode - if set, use the platform driver, if available, to
+ * prepare the platform frimware for the transition.
+ *
+ * Must be called with pm_mutex held
+ */
+
+int hibernation_restore(int platform_mode)
+{
+ int error;
+
+ pm_prepare_console();
+ suspend_console();
+ error = device_suspend(PMSG_PRETHAW);
+ if (error)
+ goto Finish;
+
+ error = platform_pre_restore(platform_mode);
+ if (!error) {
+ error = disable_nonboot_cpus();
+ if (!error)
+ error = swsusp_resume();
+ enable_nonboot_cpus();
+ }
+ platform_restore_cleanup(platform_mode);
+ device_resume();
+ Finish:
+ resume_console();
+ pm_restore_console();
+ return error;
+}
+
+/**
+ * hibernation_platform_enter - enter the hibernation state using the
+ * platform driver (if available)
+ */
+
+int hibernation_platform_enter(void)
+{
+ int error;
+
+ if (hibernation_ops) {
+ kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
+ /*
+ * We have cancelled the power transition by running
+ * hibernation_ops->finish() before saving the image, so we
+ * should let the firmware know that we're going to enter the
+ * sleep state after all
+ */
+ error = hibernation_ops->prepare();
+ if (!error)
+ error = hibernation_ops->enter();
+ } else {
+ error = -ENOSYS;
+ }
+ return error;
+}
+
+/**
* power_down - Shut the machine down for hibernation.
*
* Use the platform driver, if configured so; otherwise try
@@ -111,11 +244,7 @@ static void power_down(void)
kernel_restart(NULL);
break;
case HIBERNATION_PLATFORM:
- if (hibernation_ops) {
- kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
- hibernation_ops->enter();
- break;
- }
+ hibernation_platform_enter();
}
kernel_halt();
/*
@@ -152,9 +281,16 @@ int hibernate(void)
{
int error;
+ mutex_lock(&pm_mutex);
/* The snapshot device should not be opened while we're running */
- if (!atomic_add_unless(&snapshot_device_available, -1, 0))
- return -EBUSY;
+ if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
+ error = -EBUSY;
+ goto Unlock;
+ }
+
+ error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+ if (error)
+ goto Exit;
/* Allocate memory management structures */
error = create_basic_memory_bitmaps();
@@ -165,75 +301,35 @@ int hibernate(void)
if (error)
goto Finish;
- mutex_lock(&pm_mutex);
if (hibernation_mode == HIBERNATION_TESTPROC) {
printk("swsusp debug: Waiting for 5 seconds.\n");
mdelay(5000);
goto Thaw;
}
+ error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
+ if (in_suspend && !error) {
+ unsigned int flags = 0;
- /* Free memory before shutting down devices. */
- error = swsusp_shrink_memory();
- if (error)
- goto Thaw;
-
- error = platform_prepare();
- if (error)
- goto Thaw;
-
- suspend_console();
- error = device_suspend(PMSG_FREEZE);
- if (error) {
- printk(KERN_ERR "PM: Some devices failed to suspend\n");
- goto Resume_devices;
- }
- error = disable_nonboot_cpus();
- if (error)
- goto Enable_cpus;
-
- if (hibernation_mode == HIBERNATION_TEST) {
- printk("swsusp debug: Waiting for 5 seconds.\n");
- mdelay(5000);
- goto Enable_cpus;
- }
-
- pr_debug("PM: snapshotting memory.\n");
- in_suspend = 1;
- error = swsusp_suspend();
- if (error)
- goto Enable_cpus;
-
- if (in_suspend) {
- enable_nonboot_cpus();
- platform_finish();
- device_resume();
- resume_console();
+ if (hibernation_mode == HIBERNATION_PLATFORM)
+ flags |= SF_PLATFORM_MODE;
pr_debug("PM: writing image.\n");
- error = swsusp_write();
+ error = swsusp_write(flags);
+ swsusp_free();
if (!error)
power_down();
- else {
- swsusp_free();
- goto Thaw;
- }
} else {
pr_debug("PM: Image restored successfully.\n");
+ swsusp_free();
}
-
- swsusp_free();
- Enable_cpus:
- enable_nonboot_cpus();
- Resume_devices:
- platform_finish();
- device_resume();
- resume_console();
Thaw:
- mutex_unlock(&pm_mutex);
unprepare_processes();
Finish:
free_basic_memory_bitmaps();
Exit:
+ pm_notifier_call_chain(PM_POST_HIBERNATION);
atomic_inc(&snapshot_device_available);
+ Unlock:
+ mutex_unlock(&pm_mutex);
return error;
}
@@ -253,6 +349,7 @@ int hibernate(void)
static int software_resume(void)
{
int error;
+ unsigned int flags;
mutex_lock(&pm_mutex);
if (!swsusp_resume_device) {
@@ -300,30 +397,12 @@ static int software_resume(void)
pr_debug("PM: Reading swsusp image.\n");
- error = swsusp_read();
- if (error) {
- swsusp_free();
- goto Thaw;
- }
-
- pr_debug("PM: Preparing devices for restore.\n");
-
- suspend_console();
- error = device_suspend(PMSG_PRETHAW);
- if (error)
- goto Free;
-
- error = disable_nonboot_cpus();
+ error = swsusp_read(&flags);
if (!error)
- swsusp_resume();
+ hibernation_restore(flags & SF_PLATFORM_MODE);
- enable_nonboot_cpus();
- Free:
- swsusp_free();
- device_resume();
- resume_console();
- Thaw:
printk(KERN_ERR "PM: Restore failed, recovering.\n");
+ swsusp_free();
unprepare_processes();
Done:
free_basic_memory_bitmaps();
@@ -333,7 +412,7 @@ static int software_resume(void)
Unlock:
mutex_unlock(&pm_mutex);
pr_debug("PM: Resume from disk failed.\n");
- return 0;
+ return error;
}
late_initcall(software_resume);
diff --git a/kernel/power/main.c b/kernel/power/main.c
index fc45ed22620f..32147b57c3bf 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -23,6 +23,8 @@
#include "power.h"
+BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+
/*This is just an arbitrary number */
#define FREE_PAGE_NUMBER (100)
@@ -63,14 +65,11 @@ static inline void pm_finish(suspend_state_t state)
/**
* suspend_prepare - Do prep work before entering low-power state.
- * @state: State we're entering.
*
- * This is common code that is called for each state that we're
- * entering. Allocate a console, stop all processes, then make sure
- * the platform can enter the requested state.
+ * This is common code that is called for each state that we're entering.
+ * Run suspend notifiers, allocate a console and stop all processes.
*/
-
-static int suspend_prepare(suspend_state_t state)
+static int suspend_prepare(void)
{
int error;
unsigned int free_pages;
@@ -78,6 +77,10 @@ static int suspend_prepare(suspend_state_t state)
if (!pm_ops || !pm_ops->enter)
return -EPERM;
+ error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
+ if (error)
+ goto Finish;
+
pm_prepare_console();
if (freeze_processes()) {
@@ -85,46 +88,23 @@ static int suspend_prepare(suspend_state_t state)
goto Thaw;
}
- if ((free_pages = global_page_state(NR_FREE_PAGES))
- < FREE_PAGE_NUMBER) {
+ free_pages = global_page_state(NR_FREE_PAGES);
+ if (free_pages < FREE_PAGE_NUMBER) {
pr_debug("PM: free some memory\n");
shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
if (nr_free_pages() < FREE_PAGE_NUMBER) {
error = -ENOMEM;
printk(KERN_ERR "PM: No enough memory\n");
- goto Thaw;
}
}
-
- if (pm_ops->set_target) {
- error = pm_ops->set_target(state);
- if (error)
- goto Thaw;
- }
- suspend_console();
- error = device_suspend(PMSG_SUSPEND);
- if (error) {
- printk(KERN_ERR "Some devices failed to suspend\n");
- goto Resume_console;
- }
- if (pm_ops->prepare) {
- if ((error = pm_ops->prepare(state)))
- goto Resume_devices;
- }
-
- error = disable_nonboot_cpus();
if (!error)
return 0;
- enable_nonboot_cpus();
- pm_finish(state);
- Resume_devices:
- device_resume();
- Resume_console:
- resume_console();
Thaw:
thaw_processes();
pm_restore_console();
+ Finish:
+ pm_notifier_call_chain(PM_POST_SUSPEND);
return error;
}
@@ -140,6 +120,12 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
local_irq_enable();
}
+/**
+ * suspend_enter - enter the desired system sleep state.
+ * @state: state to enter
+ *
+ * This function should be called after devices have been suspended.
+ */
int suspend_enter(suspend_state_t state)
{
int error = 0;
@@ -159,23 +145,58 @@ int suspend_enter(suspend_state_t state)
return error;
}
+/**
+ * suspend_devices_and_enter - suspend devices and enter the desired system sleep
+ * state.
+ * @state: state to enter
+ */
+int suspend_devices_and_enter(suspend_state_t state)
+{
+ int error;
+
+ if (!pm_ops)
+ return -ENOSYS;
+
+ if (pm_ops->set_target) {
+ error = pm_ops->set_target(state);
+ if (error)
+ return error;
+ }
+ suspend_console();
+ error = device_suspend(PMSG_SUSPEND);
+ if (error) {
+ printk(KERN_ERR "Some devices failed to suspend\n");
+ goto Resume_console;
+ }
+ if (pm_ops->prepare) {
+ error = pm_ops->prepare(state);
+ if (error)
+ goto Resume_devices;
+ }
+ error = disable_nonboot_cpus();
+ if (!error)
+ suspend_enter(state);
+
+ enable_nonboot_cpus();
+ pm_finish(state);
+ Resume_devices:
+ device_resume();
+ Resume_console:
+ resume_console();
+ return error;
+}
/**
* suspend_finish - Do final work before exiting suspend sequence.
- * @state: State we're coming out of.
*
* Call platform code to clean up, restart processes, and free the
* console that we've allocated. This is not called for suspend-to-disk.
*/
-
-static void suspend_finish(suspend_state_t state)
+static void suspend_finish(void)
{
- enable_nonboot_cpus();
- pm_finish(state);
- device_resume();
- resume_console();
thaw_processes();
pm_restore_console();
+ pm_notifier_call_chain(PM_POST_SUSPEND);
}
@@ -207,7 +228,6 @@ static inline int valid_state(suspend_state_t state)
* Then, do the setup for suspend, enter the state, and cleaup (after
* we've woken up).
*/
-
static int enter_state(suspend_state_t state)
{
int error;
@@ -218,14 +238,14 @@ static int enter_state(suspend_state_t state)
return -EBUSY;
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
- if ((error = suspend_prepare(state)))
+ if ((error = suspend_prepare()))
goto Unlock;
pr_debug("PM: Entering %s sleep\n", pm_states[state]);
- error = suspend_enter(state);
+ error = suspend_devices_and_enter(state);
pr_debug("PM: Finishing wakeup.\n");
- suspend_finish(state);
+ suspend_finish();
Unlock:
mutex_unlock(&pm_mutex);
return error;
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 51381487103f..5f24c786f8ec 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -25,7 +25,10 @@ struct swsusp_info {
*/
#define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT)
-extern struct hibernation_ops *hibernation_ops;
+/* kernel/power/disk.c */
+extern int hibernation_snapshot(int platform_mode);
+extern int hibernation_restore(int platform_mode);
+extern int hibernation_platform_enter(void);
#endif
extern int pfn_is_nosave(unsigned long);
@@ -152,16 +155,34 @@ extern sector_t alloc_swapdev_block(int swap);
extern void free_all_swap_pages(int swap);
extern int swsusp_swap_in_use(void);
+/*
+ * Flags that can be passed from the hibernatig hernel to the "boot" kernel in
+ * the image header.
+ */
+#define SF_PLATFORM_MODE 1
+
+/* kernel/power/disk.c */
extern int swsusp_check(void);
extern int swsusp_shrink_memory(void);
extern void swsusp_free(void);
extern int swsusp_suspend(void);
extern int swsusp_resume(void);
-extern int swsusp_read(void);
-extern int swsusp_write(void);
+extern int swsusp_read(unsigned int *flags_p);
+extern int swsusp_write(unsigned int flags);
extern void swsusp_close(void);
-extern int suspend_enter(suspend_state_t state);
struct timeval;
+/* kernel/power/swsusp.c */
extern void swsusp_show_speed(struct timeval *, struct timeval *,
unsigned int, char *);
+
+/* kernel/power/main.c */
+extern int suspend_enter(suspend_state_t state);
+extern int suspend_devices_and_enter(suspend_state_t state);
+extern struct blocking_notifier_head pm_chain_head;
+
+static inline int pm_notifier_call_chain(unsigned long val)
+{
+ return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
+ == NOTIFY_BAD) ? -EINVAL : 0;
+}
diff --git a/kernel/power/process.c b/kernel/power/process.c
index e0233d8422b9..3434940a3df1 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -40,7 +40,7 @@ static inline void frozen_process(void)
current->flags |= PF_FROZEN;
wmb();
}
- clear_tsk_thread_flag(current, TIF_FREEZE);
+ clear_freeze_flag(current);
}
/* Refrigerator is place where frozen processes are stored :-). */
@@ -72,20 +72,19 @@ void refrigerator(void)
schedule();
}
pr_debug("%s left refrigerator\n", current->comm);
- current->state = save;
+ __set_current_state(save);
}
-static inline void freeze_process(struct task_struct *p)
+static void freeze_task(struct task_struct *p)
{
unsigned long flags;
if (!freezing(p)) {
rmb();
if (!frozen(p)) {
+ set_freeze_flag(p);
if (p->state == TASK_STOPPED)
force_sig_specific(SIGSTOP, p);
-
- freeze(p);
spin_lock_irqsave(&p->sighand->siglock, flags);
signal_wake_up(p, p->state == TASK_STOPPED);
spin_unlock_irqrestore(&p->sighand->siglock, flags);
@@ -99,19 +98,14 @@ static void cancel_freezing(struct task_struct *p)
if (freezing(p)) {
pr_debug(" clean up: %s\n", p->comm);
- do_not_freeze(p);
+ clear_freeze_flag(p);
spin_lock_irqsave(&p->sighand->siglock, flags);
recalc_sigpending_and_wake(p);
spin_unlock_irqrestore(&p->sighand->siglock, flags);
}
}
-static inline int is_user_space(struct task_struct *p)
-{
- return p->mm && !(p->flags & PF_BORROWED_MM);
-}
-
-static unsigned int try_to_freeze_tasks(int freeze_user_space)
+static int try_to_freeze_tasks(int freeze_user_space)
{
struct task_struct *g, *p;
unsigned long end_time;
@@ -122,26 +116,40 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space)
todo = 0;
read_lock(&tasklist_lock);
do_each_thread(g, p) {
- if (!freezeable(p))
+ if (frozen(p) || !freezeable(p))
continue;
- if (frozen(p))
- continue;
-
- if (p->state == TASK_TRACED && frozen(p->parent)) {
- cancel_freezing(p);
- continue;
+ if (freeze_user_space) {
+ if (p->state == TASK_TRACED &&
+ frozen(p->parent)) {
+ cancel_freezing(p);
+ continue;
+ }
+ /*
+ * Kernel threads should not have TIF_FREEZE set
+ * at this point, so we must ensure that either
+ * p->mm is not NULL *and* PF_BORROWED_MM is
+ * unset, or TIF_FRREZE is left unset.
+ * The task_lock() is necessary to prevent races
+ * with exit_mm() or use_mm()/unuse_mm() from
+ * occuring.
+ */
+ task_lock(p);
+ if (!p->mm || (p->flags & PF_BORROWED_MM)) {
+ task_unlock(p);
+ continue;
+ }
+ freeze_task(p);
+ task_unlock(p);
+ } else {
+ freeze_task(p);
}
- if (freeze_user_space && !is_user_space(p))
- continue;
-
- freeze_process(p);
if (!freezer_should_skip(p))
todo++;
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
yield(); /* Yield is okay here */
- if (todo && time_after(jiffies, end_time))
+ if (time_after(jiffies, end_time))
break;
} while (todo);
@@ -152,49 +160,41 @@ static unsigned int try_to_freeze_tasks(int freeze_user_space)
* but it cleans up leftover PF_FREEZE requests.
*/
printk("\n");
- printk(KERN_ERR "Stopping %s timed out after %d seconds "
+ printk(KERN_ERR "Freezing of %s timed out after %d seconds "
"(%d tasks refusing to freeze):\n",
- freeze_user_space ? "user space processes" :
- "kernel threads",
+ freeze_user_space ? "user space " : "tasks ",
TIMEOUT / HZ, todo);
+ show_state();
read_lock(&tasklist_lock);
do_each_thread(g, p) {
- if (freeze_user_space && !is_user_space(p))
- continue;
-
task_lock(p);
- if (freezeable(p) && !frozen(p) &&
- !freezer_should_skip(p))
+ if (freezing(p) && !freezer_should_skip(p))
printk(KERN_ERR " %s\n", p->comm);
-
cancel_freezing(p);
task_unlock(p);
} while_each_thread(g, p);
read_unlock(&tasklist_lock);
}
- return todo;
+ return todo ? -EBUSY : 0;
}
/**
* freeze_processes - tell processes to enter the refrigerator
- *
- * Returns 0 on success, or the number of processes that didn't freeze,
- * although they were told to.
*/
int freeze_processes(void)
{
- unsigned int nr_unfrozen;
+ int error;
printk("Stopping tasks ... ");
- nr_unfrozen = try_to_freeze_tasks(FREEZER_USER_SPACE);
- if (nr_unfrozen)
- return nr_unfrozen;
+ error = try_to_freeze_tasks(FREEZER_USER_SPACE);
+ if (error)
+ return error;
sys_sync();
- nr_unfrozen = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
- if (nr_unfrozen)
- return nr_unfrozen;
+ error = try_to_freeze_tasks(FREEZER_KERNEL_THREADS);
+ if (error)
+ return error;
printk("done.\n");
BUG_ON(in_atomic());
@@ -210,7 +210,7 @@ static void thaw_tasks(int thaw_user_space)
if (!freezeable(p))
continue;
- if (is_user_space(p) == !thaw_user_space)
+ if (!p->mm == thaw_user_space)
continue;
thaw_process(p);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 8b1a1b837145..917aba100575 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -33,8 +33,9 @@ extern char resume_file[];
#define SWSUSP_SIG "S1SUSPEND"
struct swsusp_header {
- char reserved[PAGE_SIZE - 20 - sizeof(sector_t)];
+ char reserved[PAGE_SIZE - 20 - sizeof(sector_t) - sizeof(int)];
sector_t image;
+ unsigned int flags; /* Flags to pass to the "boot" kernel */
char orig_sig[10];
char sig[10];
} __attribute__((packed));
@@ -138,7 +139,7 @@ static int wait_on_bio_chain(struct bio **bio_chain)
* Saving part
*/
-static int mark_swapfiles(sector_t start)
+static int mark_swapfiles(sector_t start, unsigned int flags)
{
int error;
@@ -148,6 +149,7 @@ static int mark_swapfiles(sector_t start)
memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
swsusp_header->image = start;
+ swsusp_header->flags = flags;
error = bio_write_page(swsusp_resume_block,
swsusp_header, NULL);
} else {
@@ -369,6 +371,7 @@ static int enough_swap(unsigned int nr_pages)
/**
* swsusp_write - Write entire image and metadata.
+ * @flags: flags to pass to the "boot" kernel in the image header
*
* It is important _NOT_ to umount filesystems at this point. We want
* them synced (in case something goes wrong) but we DO not want to mark
@@ -376,7 +379,7 @@ static int enough_swap(unsigned int nr_pages)
* correctly, we'll mark system clean, anyway.)
*/
-int swsusp_write(void)
+int swsusp_write(unsigned int flags)
{
struct swap_map_handle handle;
struct snapshot_handle snapshot;
@@ -415,7 +418,7 @@ int swsusp_write(void)
if (!error) {
flush_swap_writer(&handle);
printk("S");
- error = mark_swapfiles(start);
+ error = mark_swapfiles(start, flags);
printk("|\n");
}
}
@@ -540,13 +543,20 @@ static int load_image(struct swap_map_handle *handle,
return error;
}
-int swsusp_read(void)
+/**
+ * swsusp_read - read the hibernation image.
+ * @flags_p: flags passed by the "frozen" kernel in the image header should
+ * be written into this memeory location
+ */
+
+int swsusp_read(unsigned int *flags_p)
{
int error;
struct swap_map_handle handle;
struct snapshot_handle snapshot;
struct swsusp_info *header;
+ *flags_p = swsusp_header->flags;
if (IS_ERR(resume_bdev)) {
pr_debug("swsusp: block device not initialised\n");
return PTR_ERR(resume_bdev);
diff --git a/kernel/power/user.c b/kernel/power/user.c
index d65305b515b1..bd0723a7df3f 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -128,92 +128,6 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
return res;
}
-static inline int platform_prepare(void)
-{
- int error = 0;
-
- if (hibernation_ops)
- error = hibernation_ops->prepare();
-
- return error;
-}
-
-static inline void platform_finish(void)
-{
- if (hibernation_ops)
- hibernation_ops->finish();
-}
-
-static inline int snapshot_suspend(int platform_suspend)
-{
- int error;
-
- mutex_lock(&pm_mutex);
- /* Free memory before shutting down devices. */
- error = swsusp_shrink_memory();
- if (error)
- goto Finish;
-
- if (platform_suspend) {
- error = platform_prepare();
- if (error)
- goto Finish;
- }
- suspend_console();
- error = device_suspend(PMSG_FREEZE);
- if (error)
- goto Resume_devices;
-
- error = disable_nonboot_cpus();
- if (!error) {
- in_suspend = 1;
- error = swsusp_suspend();
- }
- enable_nonboot_cpus();
- Resume_devices:
- if (platform_suspend)
- platform_finish();
-
- device_resume();
- resume_console();
- Finish:
- mutex_unlock(&pm_mutex);
- return error;
-}
-
-static inline int snapshot_restore(int platform_suspend)
-{
- int error;
-
- mutex_lock(&pm_mutex);
- pm_prepare_console();
- if (platform_suspend) {
- error = platform_prepare();
- if (error)
- goto Finish;
- }
- suspend_console();
- error = device_suspend(PMSG_PRETHAW);
- if (error)
- goto Resume_devices;
-
- error = disable_nonboot_cpus();
- if (!error)
- error = swsusp_resume();
-
- enable_nonboot_cpus();
- Resume_devices:
- if (platform_suspend)
- platform_finish();
-
- device_resume();
- resume_console();
- Finish:
- pm_restore_console();
- mutex_unlock(&pm_mutex);
- return error;
-}
-
static int snapshot_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
@@ -237,10 +151,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
if (data->frozen)
break;
mutex_lock(&pm_mutex);
- if (freeze_processes()) {
- thaw_processes();
- error = -EBUSY;
+ error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+ if (!error) {
+ error = freeze_processes();
+ if (error)
+ thaw_processes();
}
+ if (error)
+ pm_notifier_call_chain(PM_POST_HIBERNATION);
mutex_unlock(&pm_mutex);
if (!error)
data->frozen = 1;
@@ -251,6 +169,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
break;
mutex_lock(&pm_mutex);
thaw_processes();
+ pm_notifier_call_chain(PM_POST_HIBERNATION);
mutex_unlock(&pm_mutex);
data->frozen = 0;
break;
@@ -260,7 +179,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -EPERM;
break;
}
- error = snapshot_suspend(data->platform_suspend);
+ error = hibernation_snapshot(data->platform_suspend);
if (!error)
error = put_user(in_suspend, (unsigned int __user *)arg);
if (!error)
@@ -274,7 +193,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = -EPERM;
break;
}
- error = snapshot_restore(data->platform_suspend);
+ error = hibernation_restore(data->platform_suspend);
break;
case SNAPSHOT_FREE:
@@ -336,47 +255,19 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
break;
case SNAPSHOT_S2RAM:
- if (!pm_ops) {
- error = -ENOSYS;
- break;
- }
-
if (!data->frozen) {
error = -EPERM;
break;
}
-
if (!mutex_trylock(&pm_mutex)) {
error = -EBUSY;
break;
}
-
- if (pm_ops->prepare) {
- error = pm_ops->prepare(PM_SUSPEND_MEM);
- if (error)
- goto OutS3;
- }
-
- /* Put devices to sleep */
- suspend_console();
- error = device_suspend(PMSG_SUSPEND);
- if (error) {
- printk(KERN_ERR "Failed to suspend some devices.\n");
- } else {
- error = disable_nonboot_cpus();
- if (!error) {
- /* Enter S3, system is already frozen */
- suspend_enter(PM_SUSPEND_MEM);
- enable_nonboot_cpus();
- }
- /* Wake up devices */
- device_resume();
- }
- resume_console();
- if (pm_ops->finish)
- pm_ops->finish(PM_SUSPEND_MEM);
-
- OutS3:
+ /*
+ * Tasks are frozen and the notifiers have been called with
+ * PM_HIBERNATION_PREPARE
+ */
+ error = suspend_devices_and_enter(PM_SUSPEND_MEM);
mutex_unlock(&pm_mutex);
break;
@@ -386,19 +277,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
switch (arg) {
case PMOPS_PREPARE:
- if (hibernation_ops) {
- data->platform_suspend = 1;
- error = 0;
- } else {
- error = -ENOSYS;
- }
+ data->platform_suspend = 1;
+ error = 0;
break;
case PMOPS_ENTER:
- if (data->platform_suspend) {
- kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK);
- error = hibernation_ops->enter();
- }
+ if (data->platform_suspend)
+ error = hibernation_platform_enter();
+
break;
case PMOPS_FINISH:
diff --git a/kernel/printk.c b/kernel/printk.c
index 0bbdeac2810c..051d27e36a6c 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -449,13 +449,16 @@ static int printk_time = 1;
#else
static int printk_time = 0;
#endif
-module_param(printk_time, int, S_IRUGO | S_IWUSR);
+module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
static int __init printk_time_setup(char *str)
{
if (*str)
return 0;
printk_time = 1;
+ printk(KERN_NOTICE "The 'time' option is deprecated and "
+ "is scheduled for removal in early 2008\n");
+ printk(KERN_NOTICE "Use 'printk.time=<value>' instead\n");
return 1;
}
@@ -483,6 +486,9 @@ static int have_callable_console(void)
* @fmt: format string
*
* This is printk(). It can be called from any context. We want it to work.
+ * Be aware of the fact that if oops_in_progress is not set, we might try to
+ * wake klogd up which could deadlock on runqueue lock if printk() is called
+ * from scheduler code.
*
* We try to grab the console_sem. If we succeed, it's easy - we log the output and
* call the console drivers. If we fail to get the semaphore we place the output
@@ -654,7 +660,7 @@ static void call_console_drivers(unsigned long start, unsigned long end)
*/
static int __init console_setup(char *str)
{
- char name[sizeof(console_cmdline[0].name)];
+ char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
char *s, *options;
int idx;
@@ -662,27 +668,27 @@ static int __init console_setup(char *str)
* Decode str into name, index, options.
*/
if (str[0] >= '0' && str[0] <= '9') {
- strcpy(name, "ttyS");
- strncpy(name + 4, str, sizeof(name) - 5);
+ strcpy(buf, "ttyS");
+ strncpy(buf + 4, str, sizeof(buf) - 5);
} else {
- strncpy(name, str, sizeof(name) - 1);
+ strncpy(buf, str, sizeof(buf) - 1);
}
- name[sizeof(name) - 1] = 0;
+ buf[sizeof(buf) - 1] = 0;
if ((options = strchr(str, ',')) != NULL)
*(options++) = 0;
#ifdef __sparc__
if (!strcmp(str, "ttya"))
- strcpy(name, "ttyS0");
+ strcpy(buf, "ttyS0");
if (!strcmp(str, "ttyb"))
- strcpy(name, "ttyS1");
+ strcpy(buf, "ttyS1");
#endif
- for (s = name; *s; s++)
+ for (s = buf; *s; s++)
if ((*s >= '0' && *s <= '9') || *s == ',')
break;
idx = simple_strtoul(s, NULL, 10);
*s = 0;
- add_preferred_console(name, idx, options);
+ add_preferred_console(buf, idx, options);
return 1;
}
__setup("console=", console_setup);
@@ -709,7 +715,7 @@ int __init add_preferred_console(char *name, int idx, char *options)
* See if this tty is not yet registered, and
* if we have a slot free.
*/
- for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+ for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
if (strcmp(console_cmdline[i].name, name) == 0 &&
console_cmdline[i].index == idx) {
selected_console = i;
@@ -726,6 +732,25 @@ int __init add_preferred_console(char *name, int idx, char *options)
return 0;
}
+int __init update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options)
+{
+ struct console_cmdline *c;
+ int i;
+
+ for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+ if (strcmp(console_cmdline[i].name, name) == 0 &&
+ console_cmdline[i].index == idx) {
+ c = &console_cmdline[i];
+ memcpy(c->name, name_new, sizeof(c->name));
+ c->name[sizeof(c->name) - 1] = 0;
+ c->options = options;
+ c->index = idx_new;
+ return i;
+ }
+ /* not found */
+ return -1;
+}
+
#ifndef CONFIG_DISABLE_CONSOLE_SUSPEND
/**
* suspend_console - suspend the console subsystem
@@ -942,6 +967,9 @@ void register_console(struct console *console)
if (preferred_console < 0 || bootconsole || !console_drivers)
preferred_console = selected_console;
+ if (console->early_setup)
+ console->early_setup();
+
/*
* See if we want to use this console driver. If we
* didn't select a console we take the first one
@@ -985,12 +1013,15 @@ void register_console(struct console *console)
if (!(console->flags & CON_ENABLED))
return;
- if (bootconsole) {
+ if (bootconsole && (console->flags & CON_CONSDEV)) {
printk(KERN_INFO "console handover: boot [%s%d] -> real [%s%d]\n",
bootconsole->name, bootconsole->index,
console->name, console->index);
unregister_console(bootconsole);
console->flags &= ~CON_PRINTBUFFER;
+ } else {
+ printk(KERN_INFO "console [%s%d] enabled\n",
+ console->name, console->index);
}
/*
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index ad7949a589dd..82a558b655da 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -142,7 +142,7 @@ static int may_attach(struct task_struct *task)
return -EPERM;
smp_rmb();
if (task->mm)
- dumpable = task->mm->dumpable;
+ dumpable = get_dumpable(task->mm);
if (!dumpable && !capable(CAP_SYS_PTRACE))
return -EPERM;
@@ -161,6 +161,7 @@ int ptrace_may_attach(struct task_struct *task)
int ptrace_attach(struct task_struct *task)
{
int retval;
+ unsigned long flags;
audit_ptrace(task);
@@ -181,9 +182,7 @@ repeat:
* cpu's that may have task_lock).
*/
task_lock(task);
- local_irq_disable();
- if (!write_trylock(&tasklist_lock)) {
- local_irq_enable();
+ if (!write_trylock_irqsave(&tasklist_lock, flags)) {
task_unlock(task);
do {
cpu_relax();
@@ -211,7 +210,7 @@ repeat:
force_sig_specific(SIGSTOP, task);
bad:
- write_unlock_irq(&tasklist_lock);
+ write_unlock_irqrestore(&tasklist_lock, flags);
task_unlock(task);
out:
return retval;
@@ -491,3 +490,22 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
return ret;
}
#endif /* __ARCH_SYS_PTRACE */
+
+int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
+{
+ unsigned long tmp;
+ int copied;
+
+ copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), 0);
+ if (copied != sizeof(tmp))
+ return -EIO;
+ return put_user(tmp, (unsigned long __user *)data);
+}
+
+int generic_ptrace_pokedata(struct task_struct *tsk, long addr, long data)
+{
+ int copied;
+
+ copied = access_process_vm(tsk, addr, &data, sizeof(data), 1);
+ return (copied == sizeof(data)) ? 0 : -EIO;
+}
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 55ba82a85a66..ddff33247785 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -40,6 +40,7 @@
#include <linux/moduleparam.h>
#include <linux/percpu.h>
#include <linux/notifier.h>
+#include <linux/freezer.h>
#include <linux/cpu.h>
#include <linux/random.h>
#include <linux/delay.h>
@@ -518,7 +519,6 @@ rcu_torture_writer(void *arg)
VERBOSE_PRINTK_STRING("rcu_torture_writer task started");
set_user_nice(current, 19);
- current->flags |= PF_NOFREEZE;
do {
schedule_timeout_uninterruptible(1);
@@ -558,7 +558,6 @@ rcu_torture_fakewriter(void *arg)
VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
set_user_nice(current, 19);
- current->flags |= PF_NOFREEZE;
do {
schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
@@ -589,7 +588,6 @@ rcu_torture_reader(void *arg)
VERBOSE_PRINTK_STRING("rcu_torture_reader task started");
set_user_nice(current, 19);
- current->flags |= PF_NOFREEZE;
do {
idx = cur_ops->readlock();
diff --git a/kernel/relay.c b/kernel/relay.c
index 3b299fb3855c..510fbbd7b500 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -80,7 +80,7 @@ static struct vm_operations_struct relay_file_mmap_ops = {
*
* Caller should already have grabbed mmap_sem.
*/
-int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
+static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
{
unsigned long length = vma->vm_end - vma->vm_start;
struct file *filp = vma->vm_file;
@@ -145,7 +145,7 @@ depopulate:
*
* Returns channel buffer if successful, %NULL otherwise.
*/
-struct rchan_buf *relay_create_buf(struct rchan *chan)
+static struct rchan_buf *relay_create_buf(struct rchan *chan)
{
struct rchan_buf *buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
if (!buf)
@@ -175,7 +175,7 @@ free_buf:
*
* Should only be called from kref_put().
*/
-void relay_destroy_channel(struct kref *kref)
+static void relay_destroy_channel(struct kref *kref)
{
struct rchan *chan = container_of(kref, struct rchan, kref);
kfree(chan);
@@ -185,7 +185,7 @@ void relay_destroy_channel(struct kref *kref)
* relay_destroy_buf - destroy an rchan_buf struct and associated buffer
* @buf: the buffer struct
*/
-void relay_destroy_buf(struct rchan_buf *buf)
+static void relay_destroy_buf(struct rchan_buf *buf)
{
struct rchan *chan = buf->chan;
unsigned int i;
@@ -210,7 +210,7 @@ void relay_destroy_buf(struct rchan_buf *buf)
* rchan_buf_struct and the channel buffer. Should only be called from
* kref_put().
*/
-void relay_remove_buf(struct kref *kref)
+static void relay_remove_buf(struct kref *kref)
{
struct rchan_buf *buf = container_of(kref, struct rchan_buf, kref);
buf->chan->cb->remove_buf_file(buf->dentry);
@@ -223,11 +223,10 @@ void relay_remove_buf(struct kref *kref)
*
* Returns 1 if the buffer is empty, 0 otherwise.
*/
-int relay_buf_empty(struct rchan_buf *buf)
+static int relay_buf_empty(struct rchan_buf *buf)
{
return (buf->subbufs_produced - buf->subbufs_consumed) ? 0 : 1;
}
-EXPORT_SYMBOL_GPL(relay_buf_empty);
/**
* relay_buf_full - boolean, is the channel buffer full?
@@ -1061,7 +1060,7 @@ static struct pipe_buf_operations relay_pipe_buf_ops = {
.get = generic_pipe_buf_get,
};
-/**
+/*
* subbuf_splice_actor - splice up to one subbuf's worth of data
*/
static int subbuf_splice_actor(struct file *in,
@@ -1074,7 +1073,9 @@ static int subbuf_splice_actor(struct file *in,
unsigned int pidx, poff, total_len, subbuf_pages, ret;
struct rchan_buf *rbuf = in->private_data;
unsigned int subbuf_size = rbuf->chan->subbuf_size;
- size_t read_start = ((size_t)*ppos) % rbuf->chan->alloc_size;
+ uint64_t pos = (uint64_t) *ppos;
+ uint32_t alloc_size = (uint32_t) rbuf->chan->alloc_size;
+ size_t read_start = (size_t) do_div(pos, alloc_size);
size_t read_subbuf = read_start / subbuf_size;
size_t padding = rbuf->padding[read_subbuf];
size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding;
diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c
index da8d6bf46457..5aedbee014df 100644
--- a/kernel/rtmutex-debug.c
+++ b/kernel/rtmutex-debug.c
@@ -29,12 +29,6 @@
#include "rtmutex_common.h"
-#ifdef CONFIG_DEBUG_RT_MUTEXES
-# include "rtmutex-debug.h"
-#else
-# include "rtmutex.h"
-#endif
-
# define TRACE_WARN_ON(x) WARN_ON(x)
# define TRACE_BUG_ON(x) BUG_ON(x)
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
index 015fc633c96c..e3055ba69159 100644
--- a/kernel/rtmutex-tester.c
+++ b/kernel/rtmutex-tester.c
@@ -260,6 +260,7 @@ static int test_func(void *data)
int ret;
current->flags |= PF_MUTEX_TESTER;
+ set_freezable();
allow_signal(SIGHUP);
for(;;) {
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
index 17d28ce20300..8cd9bd2cdb34 100644
--- a/kernel/rtmutex.c
+++ b/kernel/rtmutex.c
@@ -17,12 +17,6 @@
#include "rtmutex_common.h"
-#ifdef CONFIG_DEBUG_RT_MUTEXES
-# include "rtmutex-debug.h"
-#else
-# include "rtmutex.h"
-#endif
-
/*
* lock->owner state tracking:
*
diff --git a/kernel/rtmutex_common.h b/kernel/rtmutex_common.h
index 9c75856e791e..2d3b83593ca3 100644
--- a/kernel/rtmutex_common.h
+++ b/kernel/rtmutex_common.h
@@ -103,7 +103,7 @@ static inline struct task_struct *rt_mutex_owner(struct rt_mutex *lock)
static inline struct task_struct *rt_mutex_real_owner(struct rt_mutex *lock)
{
- return (struct task_struct *)
+ return (struct task_struct *)
((unsigned long)lock->owner & ~RT_MUTEX_HAS_WAITERS);
}
@@ -120,4 +120,11 @@ extern void rt_mutex_init_proxy_locked(struct rt_mutex *lock,
struct task_struct *proxy_owner);
extern void rt_mutex_proxy_unlock(struct rt_mutex *lock,
struct task_struct *proxy_owner);
+
+#ifdef CONFIG_DEBUG_RT_MUTEXES
+# include "rtmutex-debug.h"
+#else
+# include "rtmutex.h"
+#endif
+
#endif
diff --git a/kernel/rwsem.c b/kernel/rwsem.c
index 9a87886b022e..1ec620c03064 100644
--- a/kernel/rwsem.c
+++ b/kernel/rwsem.c
@@ -20,7 +20,7 @@ void down_read(struct rw_semaphore *sem)
might_sleep();
rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_);
- __down_read(sem);
+ LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
}
EXPORT_SYMBOL(down_read);
@@ -47,7 +47,7 @@ void down_write(struct rw_semaphore *sem)
might_sleep();
rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_);
- __down_write(sem);
+ LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
}
EXPORT_SYMBOL(down_write);
@@ -111,7 +111,7 @@ void down_read_nested(struct rw_semaphore *sem, int subclass)
might_sleep();
rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_);
- __down_read(sem);
+ LOCK_CONTENDED(sem, __down_read_trylock, __down_read);
}
EXPORT_SYMBOL(down_read_nested);
@@ -130,7 +130,7 @@ void down_write_nested(struct rw_semaphore *sem, int subclass)
might_sleep();
rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_);
- __down_write_nested(sem, subclass);
+ LOCK_CONTENDED(sem, __down_write_trylock, __down_write);
}
EXPORT_SYMBOL(down_write_nested);
diff --git a/kernel/sched.c b/kernel/sched.c
index 9fbced64bfee..93cf241cfbe9 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -301,7 +301,7 @@ struct rq {
struct lock_class_key rq_lock_key;
};
-static DEFINE_PER_CPU(struct rq, runqueues) ____cacheline_aligned_in_smp;
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues);
static DEFINE_MUTEX(sched_hotcpu_mutex);
static inline void check_preempt_curr(struct rq *rq, struct task_struct *p)
@@ -379,6 +379,23 @@ static inline unsigned long long rq_clock(struct rq *rq)
#define task_rq(p) cpu_rq(task_cpu(p))
#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
+/*
+ * For kernel-internal use: high-speed (but slightly incorrect) per-cpu
+ * clock constructed from sched_clock():
+ */
+unsigned long long cpu_clock(int cpu)
+{
+ struct rq *rq = cpu_rq(cpu);
+ unsigned long long now;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rq->lock, flags);
+ now = rq_clock(rq);
+ spin_unlock_irqrestore(&rq->lock, flags);
+
+ return now;
+}
+
#ifdef CONFIG_FAIR_GROUP_SCHED
/* Change a task's ->cfs_rq if it moves across CPUs */
static inline void set_task_cfs_rq(struct task_struct *p)
@@ -736,7 +753,9 @@ static void update_curr_load(struct rq *rq, u64 now)
*
* The "10% effect" is relative and cumulative: from _any_ nice level,
* if you go up 1 level, it's -10% CPU usage, if you go down 1 level
- * it's +10% CPU usage.
+ * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
+ * If a task goes up by ~10% and another task goes down by ~10% then
+ * the relative distance between them is ~25%.)
*/
static const int prio_to_weight[40] = {
/* -20 */ 88818, 71054, 56843, 45475, 36380, 29104, 23283, 18626, 14901, 11921,
@@ -746,15 +765,22 @@ static const int prio_to_weight[40] = {
/* 10 */ 110, 87, 70, 56, 45, 36, 29, 23, 18, 15,
};
+/*
+ * Inverse (2^32/x) values of the prio_to_weight[] array, precalculated.
+ *
+ * In cases where the weight does not change often, we can use the
+ * precalculated inverse to speed up arithmetics by turning divisions
+ * into multiplications:
+ */
static const u32 prio_to_wmult[40] = {
- 48356, 60446, 75558, 94446, 118058, 147573,
- 184467, 230589, 288233, 360285, 450347,
- 562979, 703746, 879575, 1099582, 1374389,
- 717986, 2147483, 2684354, 3355443, 4194304,
- 244160, 6557201, 8196502, 10250518, 12782640,
- 16025997, 19976592, 24970740, 31350126, 39045157,
- 49367440, 61356675, 76695844, 95443717, 119304647,
- 148102320, 186737708, 238609294, 286331153,
+/* -20 */ 48356, 60446, 75558, 94446, 118058,
+/* -15 */ 147573, 184467, 230589, 288233, 360285,
+/* -10 */ 450347, 562979, 703746, 879575, 1099582,
+/* -5 */ 1374389, 1717986, 2147483, 2684354, 3355443,
+/* 0 */ 4194304, 5244160, 6557201, 8196502, 10250518,
+/* 5 */ 12782640, 16025997, 19976592, 24970740, 31350126,
+/* 10 */ 39045157, 49367440, 61356675, 76695844, 95443717,
+/* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
};
static inline void
@@ -2226,7 +2252,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
rq = cpu_rq(i);
- if (*sd_idle && !idle_cpu(i))
+ if (*sd_idle && rq->nr_running)
*sd_idle = 0;
/* Bias balancing toward cpus of our domain */
@@ -2248,9 +2274,11 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
/*
* First idle cpu or the first cpu(busiest) in this sched group
* is eligible for doing load balancing at this and above
- * domains.
+ * domains. In the newly idle case, we will allow all the cpu's
+ * to do the newly idle load balance.
*/
- if (local_group && balance_cpu != this_cpu && balance) {
+ if (idle != CPU_NEWLY_IDLE && local_group &&
+ balance_cpu != this_cpu && balance) {
*balance = 0;
goto ret;
}
@@ -2668,6 +2696,7 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
unsigned long imbalance;
int nr_moved = 0;
int sd_idle = 0;
+ int all_pinned = 0;
cpumask_t cpus = CPU_MASK_ALL;
/*
@@ -2706,10 +2735,11 @@ redo:
double_lock_balance(this_rq, busiest);
nr_moved = move_tasks(this_rq, this_cpu, busiest,
minus_1_or_zero(busiest->nr_running),
- imbalance, sd, CPU_NEWLY_IDLE, NULL);
+ imbalance, sd, CPU_NEWLY_IDLE,
+ &all_pinned);
spin_unlock(&busiest->lock);
- if (!nr_moved) {
+ if (unlikely(all_pinned)) {
cpu_clear(cpu_of(busiest), cpus);
if (!cpus_empty(cpus))
goto redo;
@@ -4647,14 +4677,14 @@ static void show_task(struct task_struct *p)
state = p->state ? __ffs(p->state) + 1 : 0;
printk("%-13.13s %c", p->comm,
state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?');
-#if (BITS_PER_LONG == 32)
+#if BITS_PER_LONG == 32
if (state == TASK_RUNNING)
- printk(" running ");
+ printk(" running ");
else
- printk(" %08lX ", thread_saved_pc(p));
+ printk(" %08lx ", thread_saved_pc(p));
#else
if (state == TASK_RUNNING)
- printk(" running task ");
+ printk(" running task ");
else
printk(" %016lx ", thread_saved_pc(p));
#endif
@@ -4666,11 +4696,7 @@ static void show_task(struct task_struct *p)
free = (unsigned long)n - (unsigned long)end_of_stack(p);
}
#endif
- printk("%5lu %5d %6d", free, p->pid, p->parent->pid);
- if (!p->mm)
- printk(" (L-TLB)\n");
- else
- printk(" (NOTLB)\n");
+ printk("%5lu %5d %6d\n", free, p->pid, p->parent->pid);
if (state != TASK_RUNNING)
show_stack(p, NULL);
@@ -4680,14 +4706,12 @@ void show_state_filter(unsigned long state_filter)
{
struct task_struct *g, *p;
-#if (BITS_PER_LONG == 32)
- printk("\n"
- " free sibling\n");
- printk(" task PC stack pid father child younger older\n");
+#if BITS_PER_LONG == 32
+ printk(KERN_INFO
+ " task PC stack pid father\n");
#else
- printk("\n"
- " free sibling\n");
- printk(" task PC stack pid father child younger older\n");
+ printk(KERN_INFO
+ " task PC stack pid father\n");
#endif
read_lock(&tasklist_lock);
do_each_thread(g, p) {
@@ -4778,7 +4802,7 @@ cpumask_t nohz_cpu_mask = CPU_MASK_NONE;
static inline void sched_init_granularity(void)
{
unsigned int factor = 1 + ilog2(num_online_cpus());
- const unsigned long gran_limit = 10000000;
+ const unsigned long gran_limit = 100000000;
sysctl_sched_granularity *= factor;
if (sysctl_sched_granularity > gran_limit)
@@ -4909,8 +4933,6 @@ static int migration_thread(void *data)
struct migration_req *req;
struct list_head *head;
- try_to_freeze();
-
spin_lock_irq(&rq->lock);
if (cpu_is_offline(cpu)) {
@@ -5144,7 +5166,6 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
p = kthread_create(migration_thread, hcpu, "migration/%d", cpu);
if (IS_ERR(p))
return NOTIFY_BAD;
- p->flags |= PF_NOFREEZE;
kthread_bind(p, cpu);
/* Must be high prio: stop_machine expects to yield to it. */
rq = task_rq_lock(p, &flags);
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index 1baf87cceb7c..29f2c21e7da2 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -171,7 +171,7 @@ static int sched_debug_show(struct seq_file *m, void *v)
u64 now = ktime_to_ns(ktime_get());
int cpu;
- SEQ_printf(m, "Sched Debug Version: v0.04, cfs-v20, %s %.*s\n",
+ SEQ_printf(m, "Sched Debug Version: v0.05, %s %.*s\n",
init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
init_utsname()->version);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index c3391b6020e8..ad64fcb731f2 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
/* #define SECCOMP_DEBUG 1 */
+#define NR_SECCOMP_MODES 1
/*
* Secure computing mode 1 allows only read/write/exit/sigreturn.
@@ -54,3 +55,31 @@ void __secure_computing(int this_syscall)
#endif
do_exit(SIGKILL);
}
+
+long prctl_get_seccomp(void)
+{
+ return current->seccomp.mode;
+}
+
+long prctl_set_seccomp(unsigned long seccomp_mode)
+{
+ long ret;
+
+ /* can set it only once to be even more secure */
+ ret = -EPERM;
+ if (unlikely(current->seccomp.mode))
+ goto out;
+
+ ret = -EINVAL;
+ if (seccomp_mode && seccomp_mode <= NR_SECCOMP_MODES) {
+ current->seccomp.mode = seccomp_mode;
+ set_thread_flag(TIF_SECCOMP);
+#ifdef TIF_NOTSC
+ disable_TSC();
+#endif
+ ret = 0;
+ }
+
+ out:
+ return ret;
+}
diff --git a/kernel/signal.c b/kernel/signal.c
index f9405609774e..ef8156a6aad5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -255,6 +255,16 @@ flush_signal_handlers(struct task_struct *t, int force_default)
}
}
+int unhandled_signal(struct task_struct *tsk, int sig)
+{
+ if (is_init(tsk))
+ return 1;
+ if (tsk->ptrace & PT_PTRACED)
+ return 0;
+ return (tsk->sighand->action[sig-1].sa.sa_handler == SIG_IGN) ||
+ (tsk->sighand->action[sig-1].sa.sa_handler == SIG_DFL);
+}
+
/* Notify the system that a driver wants to block all signals for this
* process, and wants to be notified if any signals at all were to be
@@ -718,6 +728,37 @@ out_set:
#define LEGACY_QUEUE(sigptr, sig) \
(((sig) < SIGRTMIN) && sigismember(&(sigptr)->signal, (sig)))
+int print_fatal_signals;
+
+static void print_fatal_signal(struct pt_regs *regs, int signr)
+{
+ printk("%s/%d: potentially unexpected fatal signal %d.\n",
+ current->comm, current->pid, signr);
+
+#ifdef __i386__
+ printk("code at %08lx: ", regs->eip);
+ {
+ int i;
+ for (i = 0; i < 16; i++) {
+ unsigned char insn;
+
+ __get_user(insn, (unsigned char *)(regs->eip + i));
+ printk("%02x ", insn);
+ }
+ }
+#endif
+ printk("\n");
+ show_regs(regs);
+}
+
+static int __init setup_print_fatal_signals(char *str)
+{
+ get_option (&str, &print_fatal_signals);
+
+ return 1;
+}
+
+__setup("print-fatal-signals=", setup_print_fatal_signals);
static int
specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
@@ -1855,6 +1896,8 @@ relock:
* Anything else is fatal, maybe with a core dump.
*/
current->flags |= PF_SIGNALED;
+ if ((signr != SIGKILL) && print_fatal_signals)
+ print_fatal_signal(regs, signr);
if (sig_kernel_coredump(signr)) {
/*
* If it was able to dump core, this kills all
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 73217a9e2875..0f546ddea43d 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -14,6 +14,7 @@
#include <linux/notifier.h>
#include <linux/percpu.h>
#include <linux/cpu.h>
+#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/rcupdate.h>
#include <linux/smp.h>
@@ -488,8 +489,6 @@ void __init softirq_init(void)
static int ksoftirqd(void * __bind_cpu)
{
- current->flags |= PF_NOFREEZE;
-
set_current_state(TASK_INTERRUPTIBLE);
while (!kthread_should_stop()) {
@@ -614,12 +613,16 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
kthread_bind(per_cpu(ksoftirqd, hotcpu),
any_online_cpu(cpu_online_map));
case CPU_DEAD:
- case CPU_DEAD_FROZEN:
+ case CPU_DEAD_FROZEN: {
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+
p = per_cpu(ksoftirqd, hotcpu);
per_cpu(ksoftirqd, hotcpu) = NULL;
+ sched_setscheduler(p, SCHED_FIFO, &param);
kthread_stop(p);
takeover_tasklets(hotcpu);
break;
+ }
#endif /* CONFIG_HOTPLUG_CPU */
}
return NOTIFY_OK;
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 0131e296ffb4..708d4882c0c3 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -10,6 +10,7 @@
#include <linux/cpu.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/notifier.h>
#include <linux/module.h>
@@ -116,7 +117,6 @@ static int watchdog(void * __bind_cpu)
struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
sched_setscheduler(current, SCHED_FIFO, &param);
- current->flags |= PF_NOFREEZE;
/* initialize timestamp */
touch_softlockup_watchdog();
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
index 2c6c2bf85514..cd72424c2662 100644
--- a/kernel/spinlock.c
+++ b/kernel/spinlock.c
@@ -72,7 +72,7 @@ void __lockfunc _read_lock(rwlock_t *lock)
{
preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_read_lock(lock);
+ LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
}
EXPORT_SYMBOL(_read_lock);
@@ -88,8 +88,8 @@ unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
* _raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
-#ifdef CONFIG_PROVE_LOCKING
- _raw_spin_lock(lock);
+#ifdef CONFIG_LOCKDEP
+ LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
#else
_raw_spin_lock_flags(lock, &flags);
#endif
@@ -102,7 +102,7 @@ void __lockfunc _spin_lock_irq(spinlock_t *lock)
local_irq_disable();
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_spin_lock(lock);
+ LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
EXPORT_SYMBOL(_spin_lock_irq);
@@ -111,7 +111,7 @@ void __lockfunc _spin_lock_bh(spinlock_t *lock)
local_bh_disable();
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_spin_lock(lock);
+ LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
EXPORT_SYMBOL(_spin_lock_bh);
@@ -122,7 +122,7 @@ unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
local_irq_save(flags);
preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_read_lock(lock);
+ LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
return flags;
}
EXPORT_SYMBOL(_read_lock_irqsave);
@@ -132,7 +132,7 @@ void __lockfunc _read_lock_irq(rwlock_t *lock)
local_irq_disable();
preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_read_lock(lock);
+ LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
}
EXPORT_SYMBOL(_read_lock_irq);
@@ -141,7 +141,7 @@ void __lockfunc _read_lock_bh(rwlock_t *lock)
local_bh_disable();
preempt_disable();
rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_read_lock(lock);
+ LOCK_CONTENDED(lock, _raw_read_trylock, _raw_read_lock);
}
EXPORT_SYMBOL(_read_lock_bh);
@@ -152,7 +152,7 @@ unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
local_irq_save(flags);
preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_write_lock(lock);
+ LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
return flags;
}
EXPORT_SYMBOL(_write_lock_irqsave);
@@ -162,7 +162,7 @@ void __lockfunc _write_lock_irq(rwlock_t *lock)
local_irq_disable();
preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_write_lock(lock);
+ LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
}
EXPORT_SYMBOL(_write_lock_irq);
@@ -171,7 +171,7 @@ void __lockfunc _write_lock_bh(rwlock_t *lock)
local_bh_disable();
preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_write_lock(lock);
+ LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
}
EXPORT_SYMBOL(_write_lock_bh);
@@ -179,7 +179,7 @@ void __lockfunc _spin_lock(spinlock_t *lock)
{
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_spin_lock(lock);
+ LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
EXPORT_SYMBOL(_spin_lock);
@@ -188,7 +188,7 @@ void __lockfunc _write_lock(rwlock_t *lock)
{
preempt_disable();
rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_);
- _raw_write_lock(lock);
+ LOCK_CONTENDED(lock, _raw_write_trylock, _raw_write_lock);
}
EXPORT_SYMBOL(_write_lock);
@@ -289,7 +289,7 @@ void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
{
preempt_disable();
spin_acquire(&lock->dep_map, subclass, 0, _RET_IP_);
- _raw_spin_lock(lock);
+ LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
}
EXPORT_SYMBOL(_spin_lock_nested);
@@ -305,8 +305,8 @@ unsigned long __lockfunc _spin_lock_irqsave_nested(spinlock_t *lock, int subclas
* _raw_spin_lock_flags() code, because lockdep assumes
* that interrupts are not re-enabled during lock-acquire:
*/
-#ifdef CONFIG_PROVE_SPIN_LOCKING
- _raw_spin_lock(lock);
+#ifdef CONFIG_LOCKDEP
+ LOCK_CONTENDED(lock, _raw_spin_trylock, _raw_spin_lock);
#else
_raw_spin_lock_flags(lock, &flags);
#endif
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index fcee2a8e6da3..319821ef78af 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -93,10 +93,6 @@ static void stopmachine_set_state(enum stopmachine_state state)
static int stop_machine(void)
{
int i, ret = 0;
- struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-
- /* One high-prio thread per cpu. We'll do this one. */
- sched_setscheduler(current, SCHED_FIFO, &param);
atomic_set(&stopmachine_thread_ack, 0);
stopmachine_num_threads = 0;
@@ -189,6 +185,10 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data,
p = kthread_create(do_stop, &smdata, "kstopmachine");
if (!IS_ERR(p)) {
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+
+ /* One high-prio thread per cpu. We'll do this one. */
+ sched_setscheduler(p, SCHED_FIFO, &param);
kthread_bind(p, cpu);
wake_up_process(p);
wait_for_completion(&smdata.done);
diff --git a/kernel/sys.c b/kernel/sys.c
index 872271ccc384..08562f419768 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -31,10 +31,12 @@
#include <linux/cn_proc.h>
#include <linux/getcpu.h>
#include <linux/task_io_accounting_ops.h>
+#include <linux/seccomp.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
#include <linux/kprobes.h>
+#include <linux/user_namespace.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -98,6 +100,13 @@ struct pid *cad_pid;
EXPORT_SYMBOL(cad_pid);
/*
+ * If set, this is used for preparing the system to power off.
+ */
+
+void (*pm_power_off_prepare)(void);
+EXPORT_SYMBOL(pm_power_off_prepare);
+
+/*
* Notifier list for kernel code which wants to be called
* at shutdown. This is used to stop any idling DMA operations
* and the like.
@@ -865,6 +874,8 @@ EXPORT_SYMBOL_GPL(kernel_halt);
void kernel_power_off(void)
{
kernel_shutdown_prepare(SYSTEM_POWER_OFF);
+ if (pm_power_off_prepare)
+ pm_power_off_prepare();
printk(KERN_EMERG "Power down.\n");
machine_power_off();
}
@@ -1025,7 +1036,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
return -EPERM;
}
if (new_egid != old_egid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
if (rgid != (gid_t) -1 ||
@@ -1055,13 +1066,13 @@ asmlinkage long sys_setgid(gid_t gid)
if (capable(CAP_SETGID)) {
if (old_egid != gid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->gid = current->egid = current->sgid = current->fsgid = gid;
} else if ((gid == current->gid) || (gid == current->sgid)) {
if (old_egid != gid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->egid = current->fsgid = gid;
@@ -1078,13 +1089,13 @@ static int set_user(uid_t new_ruid, int dumpclear)
{
struct user_struct *new_user;
- new_user = alloc_uid(new_ruid);
+ new_user = alloc_uid(current->nsproxy->user_ns, new_ruid);
if (!new_user)
return -EAGAIN;
if (atomic_read(&new_user->processes) >=
current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
- new_user != &root_user) {
+ new_user != current->nsproxy->user_ns->root_user) {
free_uid(new_user);
return -EAGAIN;
}
@@ -1092,7 +1103,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
switch_uid(new_user);
if (dumpclear) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->uid = new_ruid;
@@ -1148,7 +1159,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
return -EAGAIN;
if (new_euid != old_euid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->fsuid = current->euid = new_euid;
@@ -1198,7 +1209,7 @@ asmlinkage long sys_setuid(uid_t uid)
return -EPERM;
if (old_euid != uid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->fsuid = current->euid = uid;
@@ -1243,7 +1254,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
}
if (euid != (uid_t) -1) {
if (euid != current->euid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->euid = euid;
@@ -1293,7 +1304,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
}
if (egid != (gid_t) -1) {
if (egid != current->egid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->egid = egid;
@@ -1339,7 +1350,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
uid == current->suid || uid == current->fsuid ||
capable(CAP_SETUID)) {
if (uid != old_fsuid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->fsuid = uid;
@@ -1368,7 +1379,7 @@ asmlinkage long sys_setfsgid(gid_t gid)
gid == current->sgid || gid == current->fsgid ||
capable(CAP_SETGID)) {
if (gid != old_fsgid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
smp_wmb();
}
current->fsgid = gid;
@@ -2165,14 +2176,14 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
error = put_user(current->pdeath_signal, (int __user *)arg2);
break;
case PR_GET_DUMPABLE:
- error = current->mm->dumpable;
+ error = get_dumpable(current->mm);
break;
case PR_SET_DUMPABLE:
if (arg2 < 0 || arg2 > 1) {
error = -EINVAL;
break;
}
- current->mm->dumpable = arg2;
+ set_dumpable(current->mm, arg2);
break;
case PR_SET_UNALIGN:
@@ -2241,6 +2252,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
error = SET_ENDIAN(current, arg2);
break;
+ case PR_GET_SECCOMP:
+ error = prctl_get_seccomp();
+ break;
+ case PR_SET_SECCOMP:
+ error = prctl_set_seccomp(arg2);
+ break;
+
default:
error = -EINVAL;
break;
@@ -2277,3 +2295,61 @@ asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep,
}
return err ? -EFAULT : 0;
}
+
+char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff";
+
+static void argv_cleanup(char **argv, char **envp)
+{
+ argv_free(argv);
+}
+
+/**
+ * orderly_poweroff - Trigger an orderly system poweroff
+ * @force: force poweroff if command execution fails
+ *
+ * This may be called from any context to trigger a system shutdown.
+ * If the orderly shutdown fails, it will force an immediate shutdown.
+ */
+int orderly_poweroff(bool force)
+{
+ int argc;
+ char **argv = argv_split(GFP_ATOMIC, poweroff_cmd, &argc);
+ static char *envp[] = {
+ "HOME=/",
+ "PATH=/sbin:/bin:/usr/sbin:/usr/bin",
+ NULL
+ };
+ int ret = -ENOMEM;
+ struct subprocess_info *info;
+
+ if (argv == NULL) {
+ printk(KERN_WARNING "%s failed to allocate memory for \"%s\"\n",
+ __func__, poweroff_cmd);
+ goto out;
+ }
+
+ info = call_usermodehelper_setup(argv[0], argv, envp);
+ if (info == NULL) {
+ argv_free(argv);
+ goto out;
+ }
+
+ call_usermodehelper_setcleanup(info, argv_cleanup);
+
+ ret = call_usermodehelper_exec(info, UMH_NO_WAIT);
+
+ out:
+ if (ret && force) {
+ printk(KERN_WARNING "Failed to start orderly shutdown: "
+ "forcing the issue\n");
+
+ /* I guess this should try to kick off some daemon to
+ sync and poweroff asap. Or not even bother syncing
+ if we're doing an emergency shutdown? */
+ emergency_sync();
+ kernel_power_off();
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(orderly_poweroff);
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 7e11e2c98bf9..b0ec498a18d9 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -14,6 +14,7 @@ asmlinkage long sys_ni_syscall(void)
cond_syscall(sys_nfsservctl);
cond_syscall(sys_quotactl);
+cond_syscall(sys32_quotactl);
cond_syscall(sys_acct);
cond_syscall(sys_lookup_dcookie);
cond_syscall(sys_swapon);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 51f5dac42a00..ddebf3f2affe 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -29,6 +29,7 @@
#include <linux/utsname.h>
#include <linux/capability.h>
#include <linux/smp_lock.h>
+#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
@@ -45,13 +46,11 @@
#include <linux/syscalls.h>
#include <linux/nfs_fs.h>
#include <linux/acpi.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/processor.h>
-extern int proc_nr_files(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos);
-
#ifdef CONFIG_X86
#include <asm/nmi.h>
#include <asm/stacktrace.h>
@@ -61,6 +60,7 @@ extern int proc_nr_files(ctl_table *table, int write, struct file *filp,
/* External variables not in a header file. */
extern int C_A_D;
+extern int print_fatal_signals;
extern int sysctl_overcommit_memory;
extern int sysctl_overcommit_ratio;
extern int sysctl_panic_on_oom;
@@ -78,6 +78,7 @@ extern int percpu_pagelist_fraction;
extern int compat_log;
extern int maps_protect;
extern int sysctl_stat_interval;
+extern int audit_argv_kb;
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
static int maxolduid = 65535;
@@ -160,6 +161,8 @@ extern ctl_table inotify_table[];
int sysctl_legacy_va_layout;
#endif
+extern int prove_locking;
+extern int lock_stat;
/* The default sysctl tables: */
@@ -202,7 +205,10 @@ static ctl_table root_table[] = {
.mode = 0555,
.child = dev_table,
},
-
+/*
+ * NOTE: do not add new entries to this table unless you have read
+ * Documentation/sysctl/ctl_unnumbered.txt
+ */
{ .ctl_name = 0 }
};
@@ -278,6 +284,26 @@ static ctl_table kern_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+#ifdef CONFIG_PROVE_LOCKING
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "prove_locking",
+ .data = &prove_locking,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif
+#ifdef CONFIG_LOCK_STAT
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "lock_stat",
+ .data = &lock_stat,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif
{
.ctl_name = CTL_UNNUMBERED,
.procname = "sched_features",
@@ -303,6 +329,16 @@ static ctl_table kern_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+#ifdef CONFIG_AUDITSYSCALL
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "audit_argv_kb",
+ .data = &audit_argv_kb,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif
{
.ctl_name = KERN_CORE_PATTERN,
.procname = "core_pattern",
@@ -340,6 +376,14 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "print-fatal-signals",
+ .data = &print_fatal_signals,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
#ifdef __sparc__
{
.ctl_name = KERN_SPARC_REBOOT,
@@ -649,7 +693,7 @@ static ctl_table kern_table[] = {
{
.ctl_name = KERN_ACPI_VIDEO_FLAGS,
.procname = "acpi_video_flags",
- .data = &acpi_video_flags,
+ .data = &acpi_realmode_flags,
.maxlen = sizeof (unsigned long),
.mode = 0644,
.proc_handler = &proc_doulongvec_minmax,
@@ -695,13 +739,26 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
-
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "poweroff_cmd",
+ .data = &poweroff_cmd,
+ .maxlen = POWEROFF_CMD_PATH_LEN,
+ .mode = 0644,
+ .proc_handler = &proc_dostring,
+ .strategy = &sysctl_string,
+ },
+/*
+ * NOTE: do not add new entries to this table unless you have read
+ * Documentation/sysctl/ctl_unnumbered.txt
+ */
{ .ctl_name = 0 }
};
/* Constants for minimum and maximum testing in vm_table.
We use these as one-element integer vectors. */
static int zero;
+static int two = 2;
static int one_hundred = 100;
@@ -814,6 +871,14 @@ static ctl_table vm_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "hugepages_treat_as_movable",
+ .data = &hugepages_treat_as_movable,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &hugetlb_treat_movable_handler,
+ },
#endif
{
.ctl_name = VM_LOWMEM_RESERVE_RATIO,
@@ -949,6 +1014,27 @@ static ctl_table vm_table[] = {
.strategy = &sysctl_jiffies,
},
#endif
+#ifdef CONFIG_SECURITY
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "mmap_min_addr",
+ .data = &mmap_min_addr,
+ .maxlen = sizeof(unsigned long),
+ .mode = 0644,
+ .proc_handler = &proc_doulongvec_minmax,
+ },
+#ifdef CONFIG_NUMA
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "numa_zonelist_order",
+ .data = &numa_zonelist_order,
+ .maxlen = NUMA_ZONELIST_ORDER_LEN,
+ .mode = 0644,
+ .proc_handler = &numa_zonelist_order_handler,
+ .strategy = &sysctl_string,
+ },
+#endif
+#endif
#if defined(CONFIG_X86_32) || \
(defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
{
@@ -962,6 +1048,10 @@ static ctl_table vm_table[] = {
.extra1 = &zero,
},
#endif
+/*
+ * NOTE: do not add new entries to this table unless you have read
+ * Documentation/sysctl/ctl_unnumbered.txt
+ */
{ .ctl_name = 0 }
};
@@ -1059,7 +1149,10 @@ static ctl_table fs_table[] = {
.data = &lease_break_time,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &zero,
+ .extra2 = &two,
},
{
.ctl_name = FS_AIO_NR,
@@ -1102,10 +1195,24 @@ static ctl_table fs_table[] = {
.child = binfmt_misc_table,
},
#endif
+/*
+ * NOTE: do not add new entries to this table unless you have read
+ * Documentation/sysctl/ctl_unnumbered.txt
+ */
{ .ctl_name = 0 }
};
static ctl_table debug_table[] = {
+#ifdef CONFIG_X86
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "exception-trace",
+ .data = &show_unhandled_signals,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+#endif
{ .ctl_name = 0 }
};
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 906cae771585..059431ed67db 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -196,6 +196,8 @@ static int fill_pid(pid_t pid, struct task_struct *tsk,
/* fill in basic acct fields */
stats->version = TASKSTATS_VERSION;
+ stats->nvcsw = tsk->nvcsw;
+ stats->nivcsw = tsk->nivcsw;
bacct_add_tsk(stats, tsk);
/* fill in extended acct fields */
@@ -242,6 +244,8 @@ static int fill_tgid(pid_t tgid, struct task_struct *first,
*/
delayacct_add_tsk(stats, tsk);
+ stats->nvcsw += tsk->nvcsw;
+ stats->nivcsw += tsk->nivcsw;
} while_each_thread(first, tsk);
unlock_task_sighand(first, &flags);
diff --git a/kernel/time.c b/kernel/time.c
index f04791f69408..5b81da08bbdb 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -58,9 +58,9 @@ EXPORT_SYMBOL(sys_tz);
asmlinkage long sys_time(time_t __user * tloc)
{
time_t i;
- struct timeval tv;
+ struct timespec tv;
- do_gettimeofday(&tv);
+ getnstimeofday(&tv);
i = tv.tv_sec;
if (tloc) {
@@ -133,7 +133,6 @@ static inline void warp_clock(void)
write_seqlock_irq(&xtime_lock);
wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
- time_interpolator_reset();
write_sequnlock_irq(&xtime_lock);
clock_was_set();
}
@@ -306,79 +305,6 @@ struct timespec timespec_trunc(struct timespec t, unsigned gran)
}
EXPORT_SYMBOL(timespec_trunc);
-#ifdef CONFIG_TIME_INTERPOLATION
-void getnstimeofday (struct timespec *tv)
-{
- unsigned long seq,sec,nsec;
-
- do {
- seq = read_seqbegin(&xtime_lock);
- sec = xtime.tv_sec;
- nsec = xtime.tv_nsec+time_interpolator_get_offset();
- } while (unlikely(read_seqretry(&xtime_lock, seq)));
-
- while (unlikely(nsec >= NSEC_PER_SEC)) {
- nsec -= NSEC_PER_SEC;
- ++sec;
- }
- tv->tv_sec = sec;
- tv->tv_nsec = nsec;
-}
-EXPORT_SYMBOL_GPL(getnstimeofday);
-
-int do_settimeofday (struct timespec *tv)
-{
- time_t wtm_sec, sec = tv->tv_sec;
- long wtm_nsec, nsec = tv->tv_nsec;
-
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_seqlock_irq(&xtime_lock);
- {
- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
- set_normalized_timespec(&xtime, sec, nsec);
- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
- time_interpolator_reset();
- }
- write_sequnlock_irq(&xtime_lock);
- clock_was_set();
- return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
-
-void do_gettimeofday (struct timeval *tv)
-{
- unsigned long seq, nsec, usec, sec, offset;
- do {
- seq = read_seqbegin(&xtime_lock);
- offset = time_interpolator_get_offset();
- sec = xtime.tv_sec;
- nsec = xtime.tv_nsec;
- } while (unlikely(read_seqretry(&xtime_lock, seq)));
-
- usec = (nsec + offset) / 1000;
-
- while (unlikely(usec >= USEC_PER_SEC)) {
- usec -= USEC_PER_SEC;
- ++sec;
- }
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-
-#else
#ifndef CONFIG_GENERIC_TIME
/*
* Simulate gettimeofday using do_gettimeofday which only allows a timeval
@@ -394,7 +320,6 @@ void getnstimeofday(struct timespec *tv)
}
EXPORT_SYMBOL_GPL(getnstimeofday);
#endif
-#endif
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c
index 76212b2a99de..2ad1c37b8dfe 100644
--- a/kernel/time/clockevents.c
+++ b/kernel/time/clockevents.c
@@ -205,47 +205,6 @@ void clockevents_exchange_device(struct clock_event_device *old,
}
/**
- * clockevents_request_device
- */
-struct clock_event_device *clockevents_request_device(unsigned int features,
- cpumask_t cpumask)
-{
- struct clock_event_device *cur, *dev = NULL;
- struct list_head *tmp;
-
- spin_lock(&clockevents_lock);
-
- list_for_each(tmp, &clockevent_devices) {
- cur = list_entry(tmp, struct clock_event_device, list);
-
- if ((cur->features & features) == features &&
- cpus_equal(cpumask, cur->cpumask)) {
- if (!dev || dev->rating < cur->rating)
- dev = cur;
- }
- }
-
- clockevents_exchange_device(NULL, dev);
-
- spin_unlock(&clockevents_lock);
-
- return dev;
-}
-
-/**
- * clockevents_release_device
- */
-void clockevents_release_device(struct clock_event_device *dev)
-{
- spin_lock(&clockevents_lock);
-
- clockevents_exchange_device(dev, NULL);
- clockevents_notify_released();
-
- spin_unlock(&clockevents_lock);
-}
-
-/**
* clockevents_notify - notification about relevant events
*/
void clockevents_notify(unsigned long reason, void *arg)
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index cf53bb5814cb..cd91237dbfe3 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -10,10 +10,11 @@
#include <linux/mm.h>
#include <linux/time.h>
+#include <linux/timer.h>
#include <linux/timex.h>
#include <linux/jiffies.h>
#include <linux/hrtimer.h>
-
+#include <linux/capability.h>
#include <asm/div64.h>
#include <asm/timex.h>
@@ -116,11 +117,6 @@ void second_overflow(void)
if (xtime.tv_sec % 86400 == 0) {
xtime.tv_sec--;
wall_to_monotonic.tv_sec++;
- /*
- * The timer interpolator will make time change
- * gradually instead of an immediate jump by one second
- */
- time_interpolator_update(-NSEC_PER_SEC);
time_state = TIME_OOP;
printk(KERN_NOTICE "Clock: inserting leap second "
"23:59:60 UTC\n");
@@ -130,11 +126,6 @@ void second_overflow(void)
if ((xtime.tv_sec + 1) % 86400 == 0) {
xtime.tv_sec++;
wall_to_monotonic.tv_sec--;
- /*
- * Use of time interpolator for a gradual change of
- * time
- */
- time_interpolator_update(NSEC_PER_SEC);
time_state = TIME_WAIT;
printk(KERN_NOTICE "Clock: deleting leap second "
"23:59:59 UTC\n");
@@ -185,12 +176,64 @@ u64 current_tick_length(void)
return tick_length;
}
+#ifdef CONFIG_GENERIC_CMOS_UPDATE
+
+/* Disable the cmos update - used by virtualization and embedded */
+int no_sync_cmos_clock __read_mostly;
+
+static void sync_cmos_clock(unsigned long dummy);
+
+static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+static void sync_cmos_clock(unsigned long dummy)
{
- return;
+ struct timespec now, next;
+ int fail = 1;
+
+ /*
+ * If we have an externally synchronized Linux clock, then update
+ * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
+ * called as close as possible to 500 ms before the new second starts.
+ * This code is run on a timer. If the clock is set, that timer
+ * may not expire at the correct time. Thus, we adjust...
+ */
+ if (!ntp_synced())
+ /*
+ * Not synced, exit, do not restart a timer (if one is
+ * running, let it run out).
+ */
+ return;
+
+ getnstimeofday(&now);
+ if (abs(xtime.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec / 2)
+ fail = update_persistent_clock(now);
+
+ next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec;
+ if (next.tv_nsec <= 0)
+ next.tv_nsec += NSEC_PER_SEC;
+
+ if (!fail)
+ next.tv_sec = 659;
+ else
+ next.tv_sec = 0;
+
+ if (next.tv_nsec >= NSEC_PER_SEC) {
+ next.tv_sec++;
+ next.tv_nsec -= NSEC_PER_SEC;
+ }
+ mod_timer(&sync_cmos_timer, jiffies + timespec_to_jiffies(&next));
}
+static void notify_cmos_timer(void)
+{
+ if (no_sync_cmos_clock)
+ mod_timer(&sync_cmos_timer, jiffies + 1);
+}
+
+#else
+static inline void notify_cmos_timer(void) { }
+#endif
+
/* adjtimex mainly allows reading (and writing, if superuser) of
* kernel time-keeping variables. used by xntpd.
*/
@@ -355,6 +398,6 @@ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
txc->stbcnt = 0;
write_sequnlock_irq(&xtime_lock);
do_gettimeofday(&txc->time);
- notify_arch_cmos_timer();
+ notify_cmos_timer();
return(result);
}
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 8001d37071f5..db8e0f3d409b 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -31,6 +31,12 @@ struct tick_device tick_broadcast_device;
static cpumask_t tick_broadcast_mask;
static DEFINE_SPINLOCK(tick_broadcast_lock);
+#ifdef CONFIG_TICK_ONESHOT
+static void tick_broadcast_clear_oneshot(int cpu);
+#else
+static inline void tick_broadcast_clear_oneshot(int cpu) { }
+#endif
+
/*
* Debugging: see timer_list.c
*/
@@ -49,7 +55,7 @@ cpumask_t *tick_get_broadcast_mask(void)
*/
static void tick_broadcast_start_periodic(struct clock_event_device *bc)
{
- if (bc && bc->mode == CLOCK_EVT_MODE_SHUTDOWN)
+ if (bc)
tick_setup_periodic(bc, 1);
}
@@ -99,8 +105,19 @@ int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu)
cpu_set(cpu, tick_broadcast_mask);
tick_broadcast_start_periodic(tick_broadcast_device.evtdev);
ret = 1;
- }
+ } else {
+ /*
+ * When the new device is not affected by the stop
+ * feature and the cpu is marked in the broadcast mask
+ * then clear the broadcast bit.
+ */
+ if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) {
+ int cpu = smp_processor_id();
+ cpu_clear(cpu, tick_broadcast_mask);
+ tick_broadcast_clear_oneshot(cpu);
+ }
+ }
spin_unlock_irqrestore(&tick_broadcast_lock, flags);
return ret;
}
@@ -299,7 +316,7 @@ void tick_suspend_broadcast(void)
spin_lock_irqsave(&tick_broadcast_lock, flags);
bc = tick_broadcast_device.evtdev;
- if (bc && tick_broadcast_device.mode == TICKDEV_MODE_PERIODIC)
+ if (bc)
clockevents_set_mode(bc, CLOCK_EVT_MODE_SHUTDOWN);
spin_unlock_irqrestore(&tick_broadcast_lock, flags);
@@ -316,6 +333,8 @@ int tick_resume_broadcast(void)
bc = tick_broadcast_device.evtdev;
if (bc) {
+ clockevents_set_mode(bc, CLOCK_EVT_MODE_RESUME);
+
switch (tick_broadcast_device.mode) {
case TICKDEV_MODE_PERIODIC:
if(!cpus_empty(tick_broadcast_mask))
@@ -485,6 +504,16 @@ out:
spin_unlock_irqrestore(&tick_broadcast_lock, flags);
}
+/*
+ * Reset the one shot broadcast for a cpu
+ *
+ * Called with tick_broadcast_lock held
+ */
+static void tick_broadcast_clear_oneshot(int cpu)
+{
+ cpu_clear(cpu, tick_broadcast_oneshot_mask);
+}
+
/**
* tick_broadcast_setup_highres - setup the broadcast device for highres
*/
diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
index a96ec9ab3454..77a21abc8716 100644
--- a/kernel/time/tick-common.c
+++ b/kernel/time/tick-common.c
@@ -318,12 +318,17 @@ static void tick_resume(void)
{
struct tick_device *td = &__get_cpu_var(tick_cpu_device);
unsigned long flags;
+ int broadcast = tick_resume_broadcast();
spin_lock_irqsave(&tick_device_lock, flags);
- if (td->mode == TICKDEV_MODE_PERIODIC)
- tick_setup_periodic(td->evtdev, 0);
- else
- tick_resume_oneshot();
+ clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);
+
+ if (!broadcast) {
+ if (td->mode == TICKDEV_MODE_PERIODIC)
+ tick_setup_periodic(td->evtdev, 0);
+ else
+ tick_resume_oneshot();
+ }
spin_unlock_irqrestore(&tick_device_lock, flags);
}
@@ -360,8 +365,7 @@ static int tick_notify(struct notifier_block *nb, unsigned long reason,
break;
case CLOCK_EVT_NOTIFY_RESUME:
- if (!tick_resume_broadcast())
- tick_resume();
+ tick_resume();
break;
default:
diff --git a/kernel/time/tick-oneshot.c b/kernel/time/tick-oneshot.c
index f6997ab0c3c9..0258d3115d54 100644
--- a/kernel/time/tick-oneshot.c
+++ b/kernel/time/tick-oneshot.c
@@ -73,8 +73,21 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
struct clock_event_device *dev = td->evtdev;
if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) ||
- !tick_device_is_functional(dev))
+ !tick_device_is_functional(dev)) {
+
+ printk(KERN_INFO "Clockevents: "
+ "could not switch to one-shot mode:");
+ if (!dev) {
+ printk(" no tick device\n");
+ } else {
+ if (!tick_device_is_functional(dev))
+ printk(" %s is not functional.\n", dev->name);
+ else
+ printk(" %s does not support one-shot mode.\n",
+ dev->name);
+ }
return -EINVAL;
+ }
td->mode = TICKDEV_MODE_ONESHOT;
dev->event_handler = handler;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 52db9e3c526e..b416995b9757 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -546,6 +546,7 @@ void tick_setup_sched_timer(void)
{
struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
ktime_t now = ktime_get();
+ u64 offset;
/*
* Emulate tick processing via per-CPU hrtimers:
@@ -554,8 +555,12 @@ void tick_setup_sched_timer(void)
ts->sched_timer.function = tick_sched_timer;
ts->sched_timer.cb_mode = HRTIMER_CB_IRQSAFE_NO_SOFTIRQ;
- /* Get the next period */
+ /* Get the next period (per cpu) */
ts->sched_timer.expires = tick_init_jiffy_update();
+ offset = ktime_to_ns(tick_period) >> 1;
+ do_div(offset, NR_CPUS);
+ offset *= smp_processor_id();
+ ts->sched_timer.expires = ktime_add_ns(ts->sched_timer.expires, offset);
for (;;) {
hrtimer_forward(&ts->sched_timer, now, tick_period);
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 3d1042f82a68..88c81026e003 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -36,9 +36,17 @@ EXPORT_SYMBOL(xtime_lock);
* at zero at system boot time, so wall_to_monotonic will be negative,
* however, we will ALWAYS keep the tv_nsec part positive so we can use
* the usual normalization.
+ *
+ * wall_to_monotonic is moved after resume from suspend for the monotonic
+ * time not to jump. We need to add total_sleep_time to wall_to_monotonic
+ * to get the real boot based time offset.
+ *
+ * - wall_to_monotonic is no longer the boot time, getboottime must be
+ * used instead.
*/
struct timespec xtime __attribute__ ((aligned (16)));
struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
+static unsigned long total_sleep_time; /* seconds */
EXPORT_SYMBOL(xtime);
@@ -251,6 +259,7 @@ void __init timekeeping_init(void)
xtime.tv_nsec = 0;
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
+ total_sleep_time = 0;
write_sequnlock_irqrestore(&xtime_lock, flags);
}
@@ -282,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev)
xtime.tv_sec += sleep_length;
wall_to_monotonic.tv_sec -= sleep_length;
+ total_sleep_time += sleep_length;
}
/* re-base the last cycle value */
clock->cycle_last = clocksource_read(clock);
@@ -391,7 +401,7 @@ static __always_inline int clocksource_bigadjust(s64 error, s64 *interval,
* this is optimized for the most common adjustments of -1,0,1,
* for other values we can do a bit more work.
*/
-static void clocksource_adjust(struct clocksource *clock, s64 offset)
+static void clocksource_adjust(s64 offset)
{
s64 error, interval = clock->cycle_interval;
int adj;
@@ -456,17 +466,13 @@ void update_wall_time(void)
second_overflow();
}
- /* interpolator bits */
- time_interpolator_update(clock->xtime_interval
- >> clock->shift);
-
/* accumulate error between NTP and clock interval */
clock->error += current_tick_length();
clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
}
/* correct the clock when NTP error is too big */
- clocksource_adjust(clock, offset);
+ clocksource_adjust(offset);
/* store full nanoseconds into xtime */
xtime.tv_nsec = (s64)clock->xtime_nsec >> clock->shift;
@@ -476,3 +482,30 @@ void update_wall_time(void)
change_clocksource();
update_vsyscall(&xtime, clock);
}
+
+/**
+ * getboottime - Return the real time of system boot.
+ * @ts: pointer to the timespec to be set
+ *
+ * Returns the time of day in a timespec.
+ *
+ * This is based on the wall_to_monotonic offset and the total suspend
+ * time. Calls to settimeofday will affect the value returned (which
+ * basically means that however wrong your real time clock is at boot time,
+ * you get the right time here).
+ */
+void getboottime(struct timespec *ts)
+{
+ set_normalized_timespec(ts,
+ - (wall_to_monotonic.tv_sec + total_sleep_time),
+ - wall_to_monotonic.tv_nsec);
+}
+
+/**
+ * monotonic_to_bootbased - Convert the monotonic time to boot based.
+ * @ts: pointer to the timespec to be converted
+ */
+void monotonic_to_bootbased(struct timespec *ts)
+{
+ ts->tv_sec += total_sleep_time;
+}
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 8bbcfb77f7d2..e5edc3a22a08 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -38,7 +38,7 @@ DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases);
static void print_name_offset(struct seq_file *m, void *sym)
{
- char symname[KSYM_NAME_LEN+1];
+ char symname[KSYM_NAME_LEN];
if (lookup_symbol_name((unsigned long)sym, symname) < 0)
SEQ_printf(m, "<%p>", sym);
diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c
index 321693724ad7..8ed62fda16c6 100644
--- a/kernel/time/timer_stats.c
+++ b/kernel/time/timer_stats.c
@@ -68,6 +68,7 @@ struct entry {
* Number of timeout events:
*/
unsigned long count;
+ unsigned int timer_flag;
/*
* We save the command-line string to preserve
@@ -231,7 +232,8 @@ static struct entry *tstat_lookup(struct entry *entry, char *comm)
* incremented. Otherwise the timer is registered in a free slot.
*/
void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
- void *timerf, char * comm)
+ void *timerf, char *comm,
+ unsigned int timer_flag)
{
/*
* It doesnt matter which lock we take:
@@ -249,6 +251,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
input.start_func = startf;
input.expire_func = timerf;
input.pid = pid;
+ input.timer_flag = timer_flag;
spin_lock_irqsave(lock, flags);
if (!active)
@@ -266,7 +269,7 @@ void timer_stats_update_stats(void *timer, pid_t pid, void *startf,
static void print_name_offset(struct seq_file *m, unsigned long addr)
{
- char symname[KSYM_NAME_LEN+1];
+ char symname[KSYM_NAME_LEN];
if (lookup_symbol_name(addr, symname) < 0)
seq_printf(m, "<%p>", (void *)addr);
@@ -295,7 +298,7 @@ static int tstats_show(struct seq_file *m, void *v)
period = ktime_to_timespec(time);
ms = period.tv_nsec / 1000000;
- seq_puts(m, "Timer Stats Version: v0.1\n");
+ seq_puts(m, "Timer Stats Version: v0.2\n");
seq_printf(m, "Sample period: %ld.%03ld s\n", period.tv_sec, ms);
if (atomic_read(&overflow_count))
seq_printf(m, "Overflow: %d entries\n",
@@ -303,8 +306,13 @@ static int tstats_show(struct seq_file *m, void *v)
for (i = 0; i < nr_entries; i++) {
entry = entries + i;
- seq_printf(m, "%4lu, %5d %-16s ",
+ if (entry->timer_flag & TIMER_STATS_FLAG_DEFERRABLE) {
+ seq_printf(m, "%4luD, %5d %-16s ",
entry->count, entry->pid, entry->comm);
+ } else {
+ seq_printf(m, " %4lu, %5d %-16s ",
+ entry->count, entry->pid, entry->comm);
+ }
print_name_offset(m, (unsigned long)entry->start_func);
seq_puts(m, " (");
diff --git a/kernel/timer.c b/kernel/timer.c
index 1a69705c2fb9..6ce1952eea7d 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -103,14 +103,14 @@ static inline tvec_base_t *tbase_get_base(tvec_base_t *base)
static inline void timer_set_deferrable(struct timer_list *timer)
{
timer->base = ((tvec_base_t *)((unsigned long)(timer->base) |
- TBASE_DEFERRABLE_FLAG));
+ TBASE_DEFERRABLE_FLAG));
}
static inline void
timer_set_base(struct timer_list *timer, tvec_base_t *new_base)
{
timer->base = (tvec_base_t *)((unsigned long)(new_base) |
- tbase_get_deferrable(timer->base));
+ tbase_get_deferrable(timer->base));
}
/**
@@ -305,6 +305,20 @@ void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
timer->start_pid = current->pid;
}
+
+static void timer_stats_account_timer(struct timer_list *timer)
+{
+ unsigned int flag = 0;
+
+ if (unlikely(tbase_get_deferrable(timer->base)))
+ flag |= TIMER_STATS_FLAG_DEFERRABLE;
+
+ timer_stats_update_stats(timer, timer->start_pid, timer->start_site,
+ timer->function, timer->start_comm, flag);
+}
+
+#else
+static void timer_stats_account_timer(struct timer_list *timer) {}
#endif
/**
@@ -431,10 +445,10 @@ EXPORT_SYMBOL(__mod_timer);
void add_timer_on(struct timer_list *timer, int cpu)
{
tvec_base_t *base = per_cpu(tvec_bases, cpu);
- unsigned long flags;
+ unsigned long flags;
timer_stats_timer_set_start_info(timer);
- BUG_ON(timer_pending(timer) || !timer->function);
+ BUG_ON(timer_pending(timer) || !timer->function);
spin_lock_irqsave(&base->lock, flags);
timer_set_base(timer, base);
internal_add_timer(base, timer);
@@ -613,7 +627,7 @@ static inline void __run_timers(tvec_base_t *base)
while (time_after_eq(jiffies, base->timer_jiffies)) {
struct list_head work_list;
struct list_head *head = &work_list;
- int index = base->timer_jiffies & TVR_MASK;
+ int index = base->timer_jiffies & TVR_MASK;
/*
* Cascade timers:
@@ -630,8 +644,8 @@ static inline void __run_timers(tvec_base_t *base)
unsigned long data;
timer = list_first_entry(head, struct timer_list,entry);
- fn = timer->function;
- data = timer->data;
+ fn = timer->function;
+ data = timer->data;
timer_stats_account_timer(timer);
@@ -675,8 +689,8 @@ static unsigned long __next_timer_interrupt(tvec_base_t *base)
index = slot = timer_jiffies & TVR_MASK;
do {
list_for_each_entry(nte, base->tv1.vec + slot, entry) {
- if (tbase_get_deferrable(nte->base))
- continue;
+ if (tbase_get_deferrable(nte->base))
+ continue;
found = 1;
expires = nte->expires;
@@ -820,7 +834,7 @@ void update_process_times(int user_tick)
if (rcu_pending(cpu))
rcu_check_callbacks(cpu, user_tick);
scheduler_tick();
- run_posix_cpu_timers(p);
+ run_posix_cpu_timers(p);
}
/*
@@ -895,7 +909,7 @@ static inline void update_times(unsigned long ticks)
update_wall_time();
calc_load(ticks);
}
-
+
/*
* The 64-bit jiffies value is not atomic - you MUST NOT read it
* without sampling the sequence number in xtime_lock.
@@ -1091,7 +1105,7 @@ asmlinkage long sys_gettid(void)
/**
* do_sysinfo - fill in sysinfo struct
* @info: pointer to buffer to fill
- */
+ */
int do_sysinfo(struct sysinfo *info)
{
unsigned long mem_total, sav_total;
@@ -1114,6 +1128,7 @@ int do_sysinfo(struct sysinfo *info)
getnstimeofday(&tp);
tp.tv_sec += wall_to_monotonic.tv_sec;
tp.tv_nsec += wall_to_monotonic.tv_nsec;
+ monotonic_to_bootbased(&tp);
if (tp.tv_nsec - NSEC_PER_SEC >= 0) {
tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC;
tp.tv_sec++;
@@ -1206,7 +1221,8 @@ static int __devinit init_timers_cpu(int cpu)
/*
* The APs use this path later in boot
*/
- base = kmalloc_node(sizeof(*base), GFP_KERNEL,
+ base = kmalloc_node(sizeof(*base),
+ GFP_KERNEL | __GFP_ZERO,
cpu_to_node(cpu));
if (!base)
return -ENOMEM;
@@ -1217,7 +1233,6 @@ static int __devinit init_timers_cpu(int cpu)
kfree(base);
return -ENOMEM;
}
- memset(base, 0, sizeof(*base));
per_cpu(tvec_bases, cpu) = base;
} else {
/*
@@ -1334,194 +1349,6 @@ void __init init_timers(void)
open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
}
-#ifdef CONFIG_TIME_INTERPOLATION
-
-struct time_interpolator *time_interpolator __read_mostly;
-static struct time_interpolator *time_interpolator_list __read_mostly;
-static DEFINE_SPINLOCK(time_interpolator_lock);
-
-static inline cycles_t time_interpolator_get_cycles(unsigned int src)
-{
- unsigned long (*x)(void);
-
- switch (src)
- {
- case TIME_SOURCE_FUNCTION:
- x = time_interpolator->addr;
- return x();
-
- case TIME_SOURCE_MMIO64 :
- return readq_relaxed((void __iomem *)time_interpolator->addr);
-
- case TIME_SOURCE_MMIO32 :
- return readl_relaxed((void __iomem *)time_interpolator->addr);
-
- default: return get_cycles();
- }
-}
-
-static inline u64 time_interpolator_get_counter(int writelock)
-{
- unsigned int src = time_interpolator->source;
-
- if (time_interpolator->jitter)
- {
- cycles_t lcycle;
- cycles_t now;
-
- do {
- lcycle = time_interpolator->last_cycle;
- now = time_interpolator_get_cycles(src);
- if (lcycle && time_after(lcycle, now))
- return lcycle;
-
- /* When holding the xtime write lock, there's no need
- * to add the overhead of the cmpxchg. Readers are
- * force to retry until the write lock is released.
- */
- if (writelock) {
- time_interpolator->last_cycle = now;
- return now;
- }
- /* Keep track of the last timer value returned. The use of cmpxchg here
- * will cause contention in an SMP environment.
- */
- } while (unlikely(cmpxchg(&time_interpolator->last_cycle, lcycle, now) != lcycle));
- return now;
- }
- else
- return time_interpolator_get_cycles(src);
-}
-
-void time_interpolator_reset(void)
-{
- time_interpolator->offset = 0;
- time_interpolator->last_counter = time_interpolator_get_counter(1);
-}
-
-#define GET_TI_NSECS(count,i) (((((count) - i->last_counter) & (i)->mask) * (i)->nsec_per_cyc) >> (i)->shift)
-
-unsigned long time_interpolator_get_offset(void)
-{
- /* If we do not have a time interpolator set up then just return zero */
- if (!time_interpolator)
- return 0;
-
- return time_interpolator->offset +
- GET_TI_NSECS(time_interpolator_get_counter(0), time_interpolator);
-}
-
-#define INTERPOLATOR_ADJUST 65536
-#define INTERPOLATOR_MAX_SKIP 10*INTERPOLATOR_ADJUST
-
-void time_interpolator_update(long delta_nsec)
-{
- u64 counter;
- unsigned long offset;
-
- /* If there is no time interpolator set up then do nothing */
- if (!time_interpolator)
- return;
-
- /*
- * The interpolator compensates for late ticks by accumulating the late
- * time in time_interpolator->offset. A tick earlier than expected will
- * lead to a reset of the offset and a corresponding jump of the clock
- * forward. Again this only works if the interpolator clock is running
- * slightly slower than the regular clock and the tuning logic insures
- * that.
- */
-
- counter = time_interpolator_get_counter(1);
- offset = time_interpolator->offset +
- GET_TI_NSECS(counter, time_interpolator);
-
- if (delta_nsec < 0 || (unsigned long) delta_nsec < offset)
- time_interpolator->offset = offset - delta_nsec;
- else {
- time_interpolator->skips++;
- time_interpolator->ns_skipped += delta_nsec - offset;
- time_interpolator->offset = 0;
- }
- time_interpolator->last_counter = counter;
-
- /* Tuning logic for time interpolator invoked every minute or so.
- * Decrease interpolator clock speed if no skips occurred and an offset is carried.
- * Increase interpolator clock speed if we skip too much time.
- */
- if (jiffies % INTERPOLATOR_ADJUST == 0)
- {
- if (time_interpolator->skips == 0 && time_interpolator->offset > tick_nsec)
- time_interpolator->nsec_per_cyc--;
- if (time_interpolator->ns_skipped > INTERPOLATOR_MAX_SKIP && time_interpolator->offset == 0)
- time_interpolator->nsec_per_cyc++;
- time_interpolator->skips = 0;
- time_interpolator->ns_skipped = 0;
- }
-}
-
-static inline int
-is_better_time_interpolator(struct time_interpolator *new)
-{
- if (!time_interpolator)
- return 1;
- return new->frequency > 2*time_interpolator->frequency ||
- (unsigned long)new->drift < (unsigned long)time_interpolator->drift;
-}
-
-void
-register_time_interpolator(struct time_interpolator *ti)
-{
- unsigned long flags;
-
- /* Sanity check */
- BUG_ON(ti->frequency == 0 || ti->mask == 0);
-
- ti->nsec_per_cyc = ((u64)NSEC_PER_SEC << ti->shift) / ti->frequency;
- spin_lock(&time_interpolator_lock);
- write_seqlock_irqsave(&xtime_lock, flags);
- if (is_better_time_interpolator(ti)) {
- time_interpolator = ti;
- time_interpolator_reset();
- }
- write_sequnlock_irqrestore(&xtime_lock, flags);
-
- ti->next = time_interpolator_list;
- time_interpolator_list = ti;
- spin_unlock(&time_interpolator_lock);
-}
-
-void
-unregister_time_interpolator(struct time_interpolator *ti)
-{
- struct time_interpolator *curr, **prev;
- unsigned long flags;
-
- spin_lock(&time_interpolator_lock);
- prev = &time_interpolator_list;
- for (curr = *prev; curr; curr = curr->next) {
- if (curr == ti) {
- *prev = curr->next;
- break;
- }
- prev = &curr->next;
- }
-
- write_seqlock_irqsave(&xtime_lock, flags);
- if (ti == time_interpolator) {
- /* we lost the best time-interpolator: */
- time_interpolator = NULL;
- /* find the next-best interpolator */
- for (curr = time_interpolator_list; curr; curr = curr->next)
- if (is_better_time_interpolator(curr))
- time_interpolator = curr;
- time_interpolator_reset();
- }
- write_sequnlock_irqrestore(&xtime_lock, flags);
- spin_unlock(&time_interpolator_lock);
-}
-#endif /* CONFIG_TIME_INTERPOLATION */
-
/**
* msleep - sleep safely even with waitqueue interruptions
* @msecs: Time in milliseconds to sleep for
diff --git a/kernel/user.c b/kernel/user.c
index 4869563080e9..e7d11cef6998 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -14,20 +14,19 @@
#include <linux/bitops.h>
#include <linux/key.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/user_namespace.h>
/*
* UID task count cache, to get fast user lookup in "alloc_uid"
* when changing user ID's (ie setuid() and friends).
*/
-#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 8)
-#define UIDHASH_SZ (1 << UIDHASH_BITS)
#define UIDHASH_MASK (UIDHASH_SZ - 1)
#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK)
-#define uidhashentry(uid) (uidhash_table + __uidhashfn((uid)))
+#define uidhashentry(ns, uid) ((ns)->uidhash_table + __uidhashfn((uid)))
static struct kmem_cache *uid_cachep;
-static struct list_head uidhash_table[UIDHASH_SZ];
/*
* The uidhash_lock is mostly taken from process context, but it is
@@ -94,9 +93,10 @@ struct user_struct *find_user(uid_t uid)
{
struct user_struct *ret;
unsigned long flags;
+ struct user_namespace *ns = current->nsproxy->user_ns;
spin_lock_irqsave(&uidhash_lock, flags);
- ret = uid_hash_find(uid, uidhashentry(uid));
+ ret = uid_hash_find(uid, uidhashentry(ns, uid));
spin_unlock_irqrestore(&uidhash_lock, flags);
return ret;
}
@@ -120,9 +120,9 @@ void free_uid(struct user_struct *up)
}
}
-struct user_struct * alloc_uid(uid_t uid)
+struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
{
- struct list_head *hashent = uidhashentry(uid);
+ struct list_head *hashent = uidhashentry(ns, uid);
struct user_struct *up;
spin_lock_irq(&uidhash_lock);
@@ -208,14 +208,14 @@ static int __init uid_cache_init(void)
int n;
uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
for(n = 0; n < UIDHASH_SZ; ++n)
- INIT_LIST_HEAD(uidhash_table + n);
+ INIT_LIST_HEAD(init_user_ns.uidhash_table + n);
/* Insert the root user immediately (init already runs as root) */
spin_lock_irq(&uidhash_lock);
- uid_hash_insert(&root_user, uidhashentry(0));
+ uid_hash_insert(&root_user, uidhashentry(&init_user_ns, 0));
spin_unlock_irq(&uidhash_lock);
return 0;
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
new file mode 100644
index 000000000000..d055d987850c
--- /dev/null
+++ b/kernel/user_namespace.c
@@ -0,0 +1,87 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/nsproxy.h>
+#include <linux/user_namespace.h>
+
+struct user_namespace init_user_ns = {
+ .kref = {
+ .refcount = ATOMIC_INIT(2),
+ },
+ .root_user = &root_user,
+};
+
+EXPORT_SYMBOL_GPL(init_user_ns);
+
+#ifdef CONFIG_USER_NS
+
+/*
+ * Clone a new ns copying an original user ns, setting refcount to 1
+ * @old_ns: namespace to clone
+ * Return NULL on error (failure to kmalloc), new ns otherwise
+ */
+static struct user_namespace *clone_user_ns(struct user_namespace *old_ns)
+{
+ struct user_namespace *ns;
+ struct user_struct *new_user;
+ int n;
+
+ ns = kmalloc(sizeof(struct user_namespace), GFP_KERNEL);
+ if (!ns)
+ return ERR_PTR(-ENOMEM);
+
+ kref_init(&ns->kref);
+
+ for (n = 0; n < UIDHASH_SZ; ++n)
+ INIT_LIST_HEAD(ns->uidhash_table + n);
+
+ /* Insert new root user. */
+ ns->root_user = alloc_uid(ns, 0);
+ if (!ns->root_user) {
+ kfree(ns);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Reset current->user with a new one */
+ new_user = alloc_uid(ns, current->uid);
+ if (!new_user) {
+ free_uid(ns->root_user);
+ kfree(ns);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ switch_uid(new_user);
+ return ns;
+}
+
+struct user_namespace * copy_user_ns(int flags, struct user_namespace *old_ns)
+{
+ struct user_namespace *new_ns;
+
+ BUG_ON(!old_ns);
+ get_user_ns(old_ns);
+
+ if (!(flags & CLONE_NEWUSER))
+ return old_ns;
+
+ new_ns = clone_user_ns(old_ns);
+
+ put_user_ns(old_ns);
+ return new_ns;
+}
+
+void free_user_ns(struct kref *kref)
+{
+ struct user_namespace *ns;
+
+ ns = container_of(kref, struct user_namespace, kref);
+ kfree(ns);
+}
+
+#endif /* CONFIG_USER_NS */
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 160c8c5136bd..9d8180a0f0d8 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -13,6 +13,7 @@
#include <linux/uts.h>
#include <linux/utsname.h>
#include <linux/version.h>
+#include <linux/err.h>
/*
* Clone a new ns copying an original utsname, setting refcount to 1
@@ -24,10 +25,11 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
struct uts_namespace *ns;
ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL);
- if (ns) {
- memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
- kref_init(&ns->kref);
- }
+ if (!ns)
+ return ERR_PTR(-ENOMEM);
+
+ memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
+ kref_init(&ns->kref);
return ns;
}
@@ -37,7 +39,7 @@ static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
* utsname of this process won't be seen by parent, and vice
* versa.
*/
-struct uts_namespace *copy_utsname(int flags, struct uts_namespace *old_ns)
+struct uts_namespace *copy_utsname(unsigned long flags, struct uts_namespace *old_ns)
{
struct uts_namespace *new_ns;
diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c
index f22b9dbd2a9c..c76c06466bfd 100644
--- a/kernel/utsname_sysctl.c
+++ b/kernel/utsname_sysctl.c
@@ -18,10 +18,7 @@
static void *get_uts(ctl_table *table, int write)
{
char *which = table->data;
-#ifdef CONFIG_UTS_NS
- struct uts_namespace *uts_ns = current->nsproxy->uts_ns;
- which = (which - (char *)&init_uts_ns) + (char *)uts_ns;
-#endif
+
if (!write)
down_read(&uts_sem);
else
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 3bebf73be976..58e5c152a6bb 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -282,8 +282,8 @@ static int worker_thread(void *__cwq)
struct cpu_workqueue_struct *cwq = __cwq;
DEFINE_WAIT(wait);
- if (!cwq->wq->freezeable)
- current->flags |= PF_NOFREEZE;
+ if (cwq->wq->freezeable)
+ set_freezable();
set_user_nice(current, -5);
@@ -382,16 +382,16 @@ void fastcall flush_workqueue(struct workqueue_struct *wq)
EXPORT_SYMBOL_GPL(flush_workqueue);
/*
- * Upon a successful return, the caller "owns" WORK_STRUCT_PENDING bit,
+ * Upon a successful return (>= 0), the caller "owns" WORK_STRUCT_PENDING bit,
* so this work can't be re-armed in any way.
*/
static int try_to_grab_pending(struct work_struct *work)
{
struct cpu_workqueue_struct *cwq;
- int ret = 0;
+ int ret = -1;
if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work)))
- return 1;
+ return 0;
/*
* The queueing is in progress, or it is already queued. Try to
@@ -457,10 +457,28 @@ static void wait_on_work(struct work_struct *work)
wait_on_cpu_work(per_cpu_ptr(wq->cpu_wq, cpu), work);
}
+static int __cancel_work_timer(struct work_struct *work,
+ struct timer_list* timer)
+{
+ int ret;
+
+ do {
+ ret = (timer && likely(del_timer(timer)));
+ if (!ret)
+ ret = try_to_grab_pending(work);
+ wait_on_work(work);
+ } while (unlikely(ret < 0));
+
+ work_clear_pending(work);
+ return ret;
+}
+
/**
* cancel_work_sync - block until a work_struct's callback has terminated
* @work: the work which is to be flushed
*
+ * Returns true if @work was pending.
+ *
* cancel_work_sync() will cancel the work if it is queued. If the work's
* callback appears to be running, cancel_work_sync() will block until it
* has completed.
@@ -476,31 +494,26 @@ static void wait_on_work(struct work_struct *work)
* The caller must ensure that workqueue_struct on which this work was last
* queued can't be destroyed before this function returns.
*/
-void cancel_work_sync(struct work_struct *work)
+int cancel_work_sync(struct work_struct *work)
{
- while (!try_to_grab_pending(work))
- cpu_relax();
- wait_on_work(work);
- work_clear_pending(work);
+ return __cancel_work_timer(work, NULL);
}
EXPORT_SYMBOL_GPL(cancel_work_sync);
/**
- * cancel_rearming_delayed_work - reliably kill off a delayed work.
+ * cancel_delayed_work_sync - reliably kill off a delayed work.
* @dwork: the delayed work struct
*
+ * Returns true if @dwork was pending.
+ *
* It is possible to use this function if @dwork rearms itself via queue_work()
* or queue_delayed_work(). See also the comment for cancel_work_sync().
*/
-void cancel_rearming_delayed_work(struct delayed_work *dwork)
+int cancel_delayed_work_sync(struct delayed_work *dwork)
{
- while (!del_timer(&dwork->timer) &&
- !try_to_grab_pending(&dwork->work))
- cpu_relax();
- wait_on_work(&dwork->work);
- work_clear_pending(&dwork->work);
+ return __cancel_work_timer(&dwork->work, &dwork->timer);
}
-EXPORT_SYMBOL(cancel_rearming_delayed_work);
+EXPORT_SYMBOL(cancel_delayed_work_sync);
static struct workqueue_struct *keventd_wq __read_mostly;
@@ -739,18 +752,17 @@ static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
if (cwq->thread == NULL)
return;
+ flush_cpu_workqueue(cwq);
/*
- * If the caller is CPU_DEAD the single flush_cpu_workqueue()
- * is not enough, a concurrent flush_workqueue() can insert a
- * barrier after us.
+ * If the caller is CPU_DEAD and cwq->worklist was not empty,
+ * a concurrent flush_workqueue() can insert a barrier after us.
+ * However, in that case run_workqueue() won't return and check
+ * kthread_should_stop() until it flushes all work_struct's.
* When ->worklist becomes empty it is safe to exit because no
* more work_structs can be queued on this cwq: flush_workqueue
* checks list_empty(), and a "normal" queue_work() can't use
* a dead CPU.
*/
- while (flush_cpu_workqueue(cwq))
- ;
-
kthread_stop(cwq->thread);
cwq->thread = NULL;
}
diff --git a/lib/Kconfig b/lib/Kconfig
index 3eb29d5dc4f5..e5c2c514174a 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -41,6 +41,14 @@ config CRC32
kernel tree does. Such modules that use library CRC32 functions
require M here.
+config CRC7
+ tristate "CRC7 functions"
+ help
+ This option is provided for the case where no in-kernel-tree
+ modules require CRC7 functions, but a module built outside
+ the kernel tree does. Such modules that use library CRC7
+ functions require M here.
+
config LIBCRC32C
tristate "CRC32c (Castagnoli, et al) Cyclic Redundancy-Check"
help
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index fab32a286371..f3e0c2abcbd0 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -152,6 +152,19 @@ config DEBUG_SLAB_LEAK
bool "Memory leak debugging"
depends on DEBUG_SLAB
+config SLUB_DEBUG_ON
+ bool "SLUB debugging on by default"
+ depends on SLUB && SLUB_DEBUG
+ default n
+ help
+ Boot with debugging on by default. SLUB boots by default with
+ the runtime debug capabilities switched off. Enabling this is
+ equivalent to specifying the "slub_debug" parameter on boot.
+ There is no support for more fine grained debug control like
+ possible with slub_debug=xxx. SLUB debugging may be switched
+ off in a kernel built with CONFIG_SLUB_DEBUG_ON by specifying
+ "slub_debug=-".
+
config DEBUG_PREEMPT
bool "Debug preemptible kernel"
depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT
@@ -270,6 +283,17 @@ config LOCKDEP
select KALLSYMS
select KALLSYMS_ALL
+config LOCK_STAT
+ bool "Lock usage statisitics"
+ depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
+ select LOCKDEP
+ select DEBUG_SPINLOCK
+ select DEBUG_MUTEXES
+ select DEBUG_LOCK_ALLOC
+ default n
+ help
+ This feature enables tracking lock contention points
+
config DEBUG_LOCKDEP
bool "Lock dependency engine debugging"
depends on DEBUG_KERNEL && LOCKDEP
diff --git a/lib/Makefile b/lib/Makefile
index d1b366bdf86e..614966387402 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,7 +5,7 @@
lib-y := ctype.o string.o vsprintf.o cmdline.o \
rbtree.o radix-tree.o dump_stack.o \
idr.o int_sqrt.o bitmap.o extable.o prio_tree.o \
- sha1.o irq_regs.o reciprocal_div.o
+ sha1.o irq_regs.o reciprocal_div.o argv_split.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
@@ -21,7 +21,7 @@ CFLAGS_kobject_uevent.o += -DDEBUG
endif
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
-obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
+obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o check_signature.o
obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
@@ -43,6 +43,7 @@ obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.o
obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o
obj-$(CONFIG_CRC32) += crc32.o
+obj-$(CONFIG_CRC7) += crc7.o
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
diff --git a/lib/argv_split.c b/lib/argv_split.c
new file mode 100644
index 000000000000..4096ed42f490
--- /dev/null
+++ b/lib/argv_split.c
@@ -0,0 +1,105 @@
+/*
+ * Helper function for splitting a string into an argv-like array.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+static const char *skip_sep(const char *cp)
+{
+ while (*cp && isspace(*cp))
+ cp++;
+
+ return cp;
+}
+
+static const char *skip_arg(const char *cp)
+{
+ while (*cp && !isspace(*cp))
+ cp++;
+
+ return cp;
+}
+
+static int count_argc(const char *str)
+{
+ int count = 0;
+
+ while (*str) {
+ str = skip_sep(str);
+ if (*str) {
+ count++;
+ str = skip_arg(str);
+ }
+ }
+
+ return count;
+}
+
+/**
+ * argv_free - free an argv
+ * @argv - the argument vector to be freed
+ *
+ * Frees an argv and the strings it points to.
+ */
+void argv_free(char **argv)
+{
+ char **p;
+ for (p = argv; *p; p++)
+ kfree(*p);
+
+ kfree(argv);
+}
+EXPORT_SYMBOL(argv_free);
+
+/**
+ * argv_split - split a string at whitespace, returning an argv
+ * @gfp: the GFP mask used to allocate memory
+ * @str: the string to be split
+ * @argcp: returned argument count
+ *
+ * Returns an array of pointers to strings which are split out from
+ * @str. This is performed by strictly splitting on white-space; no
+ * quote processing is performed. Multiple whitespace characters are
+ * considered to be a single argument separator. The returned array
+ * is always NULL-terminated. Returns NULL on memory allocation
+ * failure.
+ */
+char **argv_split(gfp_t gfp, const char *str, int *argcp)
+{
+ int argc = count_argc(str);
+ char **argv = kzalloc(sizeof(*argv) * (argc+1), gfp);
+ char **argvp;
+
+ if (argv == NULL)
+ goto out;
+
+ *argcp = argc;
+ argvp = argv;
+
+ while (*str) {
+ str = skip_sep(str);
+
+ if (*str) {
+ const char *p = str;
+ char *t;
+
+ str = skip_arg(str);
+
+ t = kstrndup(p, str-p, gfp);
+ if (t == NULL)
+ goto fail;
+ *argvp++ = t;
+ }
+ }
+ *argvp = NULL;
+
+ out:
+ return argv;
+
+ fail:
+ argv_free(argv);
+ return NULL;
+}
+EXPORT_SYMBOL(argv_split);
diff --git a/lib/bug.c b/lib/bug.c
index 014b582c5c4b..530f38f55787 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -38,6 +38,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/bug.h>
+#include <linux/sched.h>
extern const struct bug_entry __start___bug_table[], __stop___bug_table[];
@@ -112,7 +113,7 @@ const struct bug_entry *find_bug(unsigned long bugaddr)
return module_find_bug(bugaddr);
}
-enum bug_trap_type report_bug(unsigned long bugaddr)
+enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
{
const struct bug_entry *bug;
const char *file;
@@ -147,7 +148,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr)
"[verbose debug info unavailable]\n",
(void *)bugaddr);
- dump_stack();
+ show_regs(regs);
return BUG_TRAP_TYPE_WARN;
}
diff --git a/lib/check_signature.c b/lib/check_signature.c
new file mode 100644
index 000000000000..fd6af199247b
--- /dev/null
+++ b/lib/check_signature.c
@@ -0,0 +1,26 @@
+#include <linux/io.h>
+#include <linux/module.h>
+
+/**
+ * check_signature - find BIOS signatures
+ * @io_addr: mmio address to check
+ * @signature: signature block
+ * @length: length of signature
+ *
+ * Perform a signature comparison with the mmio address io_addr. This
+ * address should have been obtained by ioremap.
+ * Returns 1 on a match.
+ */
+
+int check_signature(const volatile void __iomem *io_addr,
+ const unsigned char *signature, int length)
+{
+ while (length--) {
+ if (readb(io_addr) != *signature)
+ return 0;
+ io_addr++;
+ signature++;
+ }
+ return 1;
+}
+EXPORT_SYMBOL(check_signature);
diff --git a/lib/crc7.c b/lib/crc7.c
new file mode 100644
index 000000000000..f1c3a144cec1
--- /dev/null
+++ b/lib/crc7.c
@@ -0,0 +1,68 @@
+/*
+ * crc7.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/crc7.h>
+
+
+/* Table for CRC-7 (polynomial x^7 + x^3 + 1) */
+const u8 crc7_syndrome_table[256] = {
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
+ 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
+ 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
+ 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
+ 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
+ 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
+ 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
+ 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
+ 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
+ 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
+ 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
+ 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
+ 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
+ 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
+ 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
+ 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
+ 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
+ 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
+ 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
+ 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
+ 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
+ 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
+ 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
+ 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
+ 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
+ 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
+ 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
+ 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
+ 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
+ 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
+ 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
+ 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
+};
+EXPORT_SYMBOL(crc7_syndrome_table);
+
+/**
+ * crc7 - update the CRC7 for the data buffer
+ * @crc: previous CRC7 value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
+ * Context: any
+ *
+ * Returns the updated CRC7 value.
+ */
+u8 crc7(u8 crc, const u8 *buffer, size_t len)
+{
+ while (len--)
+ crc = crc7_byte(crc, *buffer++);
+ return crc;
+}
+EXPORT_SYMBOL(crc7);
+
+MODULE_DESCRIPTION("CRC7 calculations");
+MODULE_LICENSE("GPL");
diff --git a/lib/genalloc.c b/lib/genalloc.c
index eb7c2bab9ebf..f6d276db2d58 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -54,11 +54,10 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
int nbytes = sizeof(struct gen_pool_chunk) +
(nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
- chunk = kmalloc_node(nbytes, GFP_KERNEL, nid);
+ chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
if (unlikely(chunk == NULL))
return -1;
- memset(chunk, 0, nbytes);
spin_lock_init(&chunk->lock);
chunk->start_addr = addr;
chunk->end_addr = addr + size;
diff --git a/lib/idr.c b/lib/idr.c
index 305117ca2d41..ffd61941e75d 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -70,6 +70,26 @@ static void free_layer(struct idr *idp, struct idr_layer *p)
spin_unlock_irqrestore(&idp->lock, flags);
}
+static void idr_mark_full(struct idr_layer **pa, int id)
+{
+ struct idr_layer *p = pa[0];
+ int l = 0;
+
+ __set_bit(id & IDR_MASK, &p->bitmap);
+ /*
+ * If this layer is full mark the bit in the layer above to
+ * show that this part of the radix tree is full. This may
+ * complete the layer above and require walking up the radix
+ * tree.
+ */
+ while (p->bitmap == IDR_FULL) {
+ if (!(p = pa[++l]))
+ break;
+ id = id >> IDR_BITS;
+ __set_bit((id & IDR_MASK), &p->bitmap);
+ }
+}
+
/**
* idr_pre_get - reserver resources for idr allocation
* @idp: idr handle
@@ -95,15 +115,15 @@ int idr_pre_get(struct idr *idp, gfp_t gfp_mask)
}
EXPORT_SYMBOL(idr_pre_get);
-static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
+static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa)
{
int n, m, sh;
struct idr_layer *p, *new;
- struct idr_layer *pa[MAX_LEVEL];
- int l, id;
+ int l, id, oid;
long bm;
id = *starting_id;
+ restart:
p = idp->top;
l = idp->layers;
pa[l--] = NULL;
@@ -117,12 +137,23 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
if (m == IDR_SIZE) {
/* no space available go back to previous layer. */
l++;
+ oid = id;
id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1;
+
+ /* if already at the top layer, we need to grow */
if (!(p = pa[l])) {
*starting_id = id;
return -2;
}
- continue;
+
+ /* If we need to go up one layer, continue the
+ * loop; otherwise, restart from the top.
+ */
+ sh = IDR_BITS * (l + 1);
+ if (oid >> sh == id >> sh)
+ continue;
+ else
+ goto restart;
}
if (m != n) {
sh = IDR_BITS*l;
@@ -144,30 +175,13 @@ static int sub_alloc(struct idr *idp, void *ptr, int *starting_id)
pa[l--] = p;
p = p->ary[m];
}
- /*
- * We have reached the leaf node, plant the
- * users pointer and return the raw id.
- */
- p->ary[m] = (struct idr_layer *)ptr;
- __set_bit(m, &p->bitmap);
- p->count++;
- /*
- * If this layer is full mark the bit in the layer above
- * to show that this part of the radix tree is full.
- * This may complete the layer above and require walking
- * up the radix tree.
- */
- n = id;
- while (p->bitmap == IDR_FULL) {
- if (!(p = pa[++l]))
- break;
- n = n >> IDR_BITS;
- __set_bit((n & IDR_MASK), &p->bitmap);
- }
- return(id);
+
+ pa[l] = p;
+ return id;
}
-static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
+static int idr_get_empty_slot(struct idr *idp, int starting_id,
+ struct idr_layer **pa)
{
struct idr_layer *p, *new;
int layers, v, id;
@@ -213,12 +227,31 @@ build_up:
}
idp->top = p;
idp->layers = layers;
- v = sub_alloc(idp, ptr, &id);
+ v = sub_alloc(idp, &id, pa);
if (v == -2)
goto build_up;
return(v);
}
+static int idr_get_new_above_int(struct idr *idp, void *ptr, int starting_id)
+{
+ struct idr_layer *pa[MAX_LEVEL];
+ int id;
+
+ id = idr_get_empty_slot(idp, starting_id, pa);
+ if (id >= 0) {
+ /*
+ * Successfully found an empty slot. Install the user
+ * pointer and mark the slot full.
+ */
+ pa[0]->ary[id & IDR_MASK] = (struct idr_layer *)ptr;
+ pa[0]->count++;
+ idr_mark_full(pa, id);
+ }
+
+ return id;
+}
+
/**
* idr_get_new_above - allocate new idr entry above or equal to a start id
* @idp: idr handle
@@ -358,6 +391,53 @@ void idr_remove(struct idr *idp, int id)
EXPORT_SYMBOL(idr_remove);
/**
+ * idr_remove_all - remove all ids from the given idr tree
+ * @idp: idr handle
+ *
+ * idr_destroy() only frees up unused, cached idp_layers, but this
+ * function will remove all id mappings and leave all idp_layers
+ * unused.
+ *
+ * A typical clean-up sequence for objects stored in an idr tree, will
+ * use idr_for_each() to free all objects, if necessay, then
+ * idr_remove_all() to remove all ids, and idr_destroy() to free
+ * up the cached idr_layers.
+ */
+void idr_remove_all(struct idr *idp)
+{
+ int n, id, max, error = 0;
+ struct idr_layer *p;
+ struct idr_layer *pa[MAX_LEVEL];
+ struct idr_layer **paa = &pa[0];
+
+ n = idp->layers * IDR_BITS;
+ p = idp->top;
+ max = 1 << n;
+
+ id = 0;
+ while (id < max && !error) {
+ while (n > IDR_BITS && p) {
+ n -= IDR_BITS;
+ *paa++ = p;
+ p = p->ary[(id >> n) & IDR_MASK];
+ }
+
+ id += 1 << n;
+ while (n < fls(id)) {
+ if (p) {
+ memset(p, 0, sizeof *p);
+ free_layer(idp, p);
+ }
+ n += IDR_BITS;
+ p = *--paa;
+ }
+ }
+ idp->top = NULL;
+ idp->layers = 0;
+}
+EXPORT_SYMBOL(idr_remove_all);
+
+/**
* idr_destroy - release all cached layers within an idr tree
* idp: idr handle
*/
@@ -404,6 +484,61 @@ void *idr_find(struct idr *idp, int id)
EXPORT_SYMBOL(idr_find);
/**
+ * idr_for_each - iterate through all stored pointers
+ * @idp: idr handle
+ * @fn: function to be called for each pointer
+ * @data: data passed back to callback function
+ *
+ * Iterate over the pointers registered with the given idr. The
+ * callback function will be called for each pointer currently
+ * registered, passing the id, the pointer and the data pointer passed
+ * to this function. It is not safe to modify the idr tree while in
+ * the callback, so functions such as idr_get_new and idr_remove are
+ * not allowed.
+ *
+ * We check the return of @fn each time. If it returns anything other
+ * than 0, we break out and return that value.
+ *
+ * The caller must serialize idr_for_each() vs idr_get_new() and idr_remove().
+ */
+int idr_for_each(struct idr *idp,
+ int (*fn)(int id, void *p, void *data), void *data)
+{
+ int n, id, max, error = 0;
+ struct idr_layer *p;
+ struct idr_layer *pa[MAX_LEVEL];
+ struct idr_layer **paa = &pa[0];
+
+ n = idp->layers * IDR_BITS;
+ p = idp->top;
+ max = 1 << n;
+
+ id = 0;
+ while (id < max) {
+ while (n > 0 && p) {
+ n -= IDR_BITS;
+ *paa++ = p;
+ p = p->ary[(id >> n) & IDR_MASK];
+ }
+
+ if (p) {
+ error = fn(id, (void *)p, data);
+ if (error)
+ break;
+ }
+
+ id += 1 << n;
+ while (n < fls(id)) {
+ n += IDR_BITS;
+ p = *--paa;
+ }
+ }
+
+ return error;
+}
+EXPORT_SYMBOL(idr_for_each);
+
+/**
* idr_replace - replace pointer for given id
* @idp: idr handle
* @ptr: pointer you want associated with the id
@@ -455,7 +590,7 @@ static int init_id_cache(void)
{
if (!idr_layer_cache)
idr_layer_cache = kmem_cache_create("idr_layer_cache",
- sizeof(struct idr_layer), 0, 0, idr_cache_ctor, NULL);
+ sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
return 0;
}
@@ -473,3 +608,248 @@ void idr_init(struct idr *idp)
spin_lock_init(&idp->lock);
}
EXPORT_SYMBOL(idr_init);
+
+
+/*
+ * IDA - IDR based ID allocator
+ *
+ * this is id allocator without id -> pointer translation. Memory
+ * usage is much lower than full blown idr because each id only
+ * occupies a bit. ida uses a custom leaf node which contains
+ * IDA_BITMAP_BITS slots.
+ *
+ * 2007-04-25 written by Tejun Heo <htejun@gmail.com>
+ */
+
+static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap)
+{
+ unsigned long flags;
+
+ if (!ida->free_bitmap) {
+ spin_lock_irqsave(&ida->idr.lock, flags);
+ if (!ida->free_bitmap) {
+ ida->free_bitmap = bitmap;
+ bitmap = NULL;
+ }
+ spin_unlock_irqrestore(&ida->idr.lock, flags);
+ }
+
+ kfree(bitmap);
+}
+
+/**
+ * ida_pre_get - reserve resources for ida allocation
+ * @ida: ida handle
+ * @gfp_mask: memory allocation flag
+ *
+ * This function should be called prior to locking and calling the
+ * following function. It preallocates enough memory to satisfy the
+ * worst possible allocation.
+ *
+ * If the system is REALLY out of memory this function returns 0,
+ * otherwise 1.
+ */
+int ida_pre_get(struct ida *ida, gfp_t gfp_mask)
+{
+ /* allocate idr_layers */
+ if (!idr_pre_get(&ida->idr, gfp_mask))
+ return 0;
+
+ /* allocate free_bitmap */
+ if (!ida->free_bitmap) {
+ struct ida_bitmap *bitmap;
+
+ bitmap = kmalloc(sizeof(struct ida_bitmap), gfp_mask);
+ if (!bitmap)
+ return 0;
+
+ free_bitmap(ida, bitmap);
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL(ida_pre_get);
+
+/**
+ * ida_get_new_above - allocate new ID above or equal to a start id
+ * @ida: ida handle
+ * @staring_id: id to start search at
+ * @p_id: pointer to the allocated handle
+ *
+ * Allocate new ID above or equal to @ida. It should be called with
+ * any required locks.
+ *
+ * If memory is required, it will return -EAGAIN, you should unlock
+ * and go back to the ida_pre_get() call. If the ida is full, it will
+ * return -ENOSPC.
+ *
+ * @p_id returns a value in the range 0 ... 0x7fffffff.
+ */
+int ida_get_new_above(struct ida *ida, int starting_id, int *p_id)
+{
+ struct idr_layer *pa[MAX_LEVEL];
+ struct ida_bitmap *bitmap;
+ unsigned long flags;
+ int idr_id = starting_id / IDA_BITMAP_BITS;
+ int offset = starting_id % IDA_BITMAP_BITS;
+ int t, id;
+
+ restart:
+ /* get vacant slot */
+ t = idr_get_empty_slot(&ida->idr, idr_id, pa);
+ if (t < 0) {
+ if (t == -1)
+ return -EAGAIN;
+ else /* will be -3 */
+ return -ENOSPC;
+ }
+
+ if (t * IDA_BITMAP_BITS >= MAX_ID_BIT)
+ return -ENOSPC;
+
+ if (t != idr_id)
+ offset = 0;
+ idr_id = t;
+
+ /* if bitmap isn't there, create a new one */
+ bitmap = (void *)pa[0]->ary[idr_id & IDR_MASK];
+ if (!bitmap) {
+ spin_lock_irqsave(&ida->idr.lock, flags);
+ bitmap = ida->free_bitmap;
+ ida->free_bitmap = NULL;
+ spin_unlock_irqrestore(&ida->idr.lock, flags);
+
+ if (!bitmap)
+ return -EAGAIN;
+
+ memset(bitmap, 0, sizeof(struct ida_bitmap));
+ pa[0]->ary[idr_id & IDR_MASK] = (void *)bitmap;
+ pa[0]->count++;
+ }
+
+ /* lookup for empty slot */
+ t = find_next_zero_bit(bitmap->bitmap, IDA_BITMAP_BITS, offset);
+ if (t == IDA_BITMAP_BITS) {
+ /* no empty slot after offset, continue to the next chunk */
+ idr_id++;
+ offset = 0;
+ goto restart;
+ }
+
+ id = idr_id * IDA_BITMAP_BITS + t;
+ if (id >= MAX_ID_BIT)
+ return -ENOSPC;
+
+ __set_bit(t, bitmap->bitmap);
+ if (++bitmap->nr_busy == IDA_BITMAP_BITS)
+ idr_mark_full(pa, idr_id);
+
+ *p_id = id;
+
+ /* Each leaf node can handle nearly a thousand slots and the
+ * whole idea of ida is to have small memory foot print.
+ * Throw away extra resources one by one after each successful
+ * allocation.
+ */
+ if (ida->idr.id_free_cnt || ida->free_bitmap) {
+ struct idr_layer *p = alloc_layer(&ida->idr);
+ if (p)
+ kmem_cache_free(idr_layer_cache, p);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ida_get_new_above);
+
+/**
+ * ida_get_new - allocate new ID
+ * @ida: idr handle
+ * @p_id: pointer to the allocated handle
+ *
+ * Allocate new ID. It should be called with any required locks.
+ *
+ * If memory is required, it will return -EAGAIN, you should unlock
+ * and go back to the idr_pre_get() call. If the idr is full, it will
+ * return -ENOSPC.
+ *
+ * @id returns a value in the range 0 ... 0x7fffffff.
+ */
+int ida_get_new(struct ida *ida, int *p_id)
+{
+ return ida_get_new_above(ida, 0, p_id);
+}
+EXPORT_SYMBOL(ida_get_new);
+
+/**
+ * ida_remove - remove the given ID
+ * @ida: ida handle
+ * @id: ID to free
+ */
+void ida_remove(struct ida *ida, int id)
+{
+ struct idr_layer *p = ida->idr.top;
+ int shift = (ida->idr.layers - 1) * IDR_BITS;
+ int idr_id = id / IDA_BITMAP_BITS;
+ int offset = id % IDA_BITMAP_BITS;
+ int n;
+ struct ida_bitmap *bitmap;
+
+ /* clear full bits while looking up the leaf idr_layer */
+ while ((shift > 0) && p) {
+ n = (idr_id >> shift) & IDR_MASK;
+ __clear_bit(n, &p->bitmap);
+ p = p->ary[n];
+ shift -= IDR_BITS;
+ }
+
+ if (p == NULL)
+ goto err;
+
+ n = idr_id & IDR_MASK;
+ __clear_bit(n, &p->bitmap);
+
+ bitmap = (void *)p->ary[n];
+ if (!test_bit(offset, bitmap->bitmap))
+ goto err;
+
+ /* update bitmap and remove it if empty */
+ __clear_bit(offset, bitmap->bitmap);
+ if (--bitmap->nr_busy == 0) {
+ __set_bit(n, &p->bitmap); /* to please idr_remove() */
+ idr_remove(&ida->idr, idr_id);
+ free_bitmap(ida, bitmap);
+ }
+
+ return;
+
+ err:
+ printk(KERN_WARNING
+ "ida_remove called for id=%d which is not allocated.\n", id);
+}
+EXPORT_SYMBOL(ida_remove);
+
+/**
+ * ida_destroy - release all cached layers within an ida tree
+ * ida: ida handle
+ */
+void ida_destroy(struct ida *ida)
+{
+ idr_destroy(&ida->idr);
+ kfree(ida->free_bitmap);
+}
+EXPORT_SYMBOL(ida_destroy);
+
+/**
+ * ida_init - initialize ida handle
+ * @ida: ida handle
+ *
+ * This function is use to set up the handle (@ida) that you will pass
+ * to the rest of the functions.
+ */
+void ida_init(struct ida *ida)
+{
+ memset(ida, 0, sizeof(struct ida));
+ idr_init(&ida->idr);
+
+}
+EXPORT_SYMBOL(ida_init);
diff --git a/lib/kobject.c b/lib/kobject.c
index ac1520651b9b..4b08e0ff95c8 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -44,7 +44,7 @@ static int populate_dir(struct kobject * kobj)
return error;
}
-static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
+static int create_dir(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
{
int error = 0;
if (kobject_name(kobj)) {
@@ -162,7 +162,7 @@ static void unlink(struct kobject * kobj)
* @shadow_parent: sysfs directory to add to.
*/
-int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
+int kobject_shadow_add(struct kobject *kobj, struct sysfs_dirent *shadow_parent)
{
int error = 0;
struct kobject * parent;
@@ -338,7 +338,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
/* Note : if we want to send the new name alone, not the full path,
* we could probably use kobject_name(kobj); */
- error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
+ error = sysfs_rename_dir(kobj, kobj->parent->sd, new_name);
/* This function is mostly/only used for network interface.
* Some hotplug package track interfaces by their name and
@@ -361,8 +361,8 @@ out:
* @new_name: object's new name
*/
-int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent,
- const char *new_name)
+int kobject_shadow_rename(struct kobject *kobj,
+ struct sysfs_dirent *new_parent, const char *new_name)
{
int error = 0;
@@ -597,10 +597,17 @@ int kset_add(struct kset * k)
int kset_register(struct kset * k)
{
+ int err;
+
if (!k)
return -EINVAL;
+
kset_init(k);
- return kset_add(k);
+ err = kset_add(k);
+ if (err)
+ return err;
+ kobject_uevent(&k->kobj, KOBJ_ADD);
+ return 0;
}
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 12e311dc664c..6a80c784a8fb 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -33,25 +33,15 @@ static DEFINE_SPINLOCK(sequence_lock);
static struct sock *uevent_sock;
#endif
-static char *action_to_string(enum kobject_action action)
-{
- switch (action) {
- case KOBJ_ADD:
- return "add";
- case KOBJ_REMOVE:
- return "remove";
- case KOBJ_CHANGE:
- return "change";
- case KOBJ_OFFLINE:
- return "offline";
- case KOBJ_ONLINE:
- return "online";
- case KOBJ_MOVE:
- return "move";
- default:
- return NULL;
- }
-}
+/* the strings here must match the enum in include/linux/kobject.h */
+const char *kobject_actions[] = {
+ "add",
+ "remove",
+ "change",
+ "move",
+ "online",
+ "offline",
+};
/**
* kobject_uevent_env - send an uevent with environmental data
@@ -83,7 +73,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
pr_debug("%s\n", __FUNCTION__);
- action_string = action_to_string(action);
+ action_string = kobject_actions[action];
if (!action_string) {
pr_debug("kobject attempted to send uevent without action_string!\n");
return -EINVAL;
@@ -208,7 +198,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
argv [0] = uevent_helper;
argv [1] = (char *)subsystem;
argv [2] = NULL;
- call_usermodehelper (argv[0], argv, envp, 0);
+ call_usermodehelper (argv[0], argv, envp, UMH_WAIT_EXEC);
}
exit:
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
index 850449080e1c..cf22c617baa4 100644
--- a/lib/percpu_counter.c
+++ b/lib/percpu_counter.c
@@ -3,8 +3,17 @@
*/
#include <linux/percpu_counter.h>
+#include <linux/notifier.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
#include <linux/module.h>
+#ifdef CONFIG_HOTPLUG_CPU
+static LIST_HEAD(percpu_counters);
+static DEFINE_MUTEX(percpu_counters_lock);
+#endif
+
void percpu_counter_mod(struct percpu_counter *fbc, s32 amount)
{
long count;
@@ -36,7 +45,7 @@ s64 percpu_counter_sum(struct percpu_counter *fbc)
spin_lock(&fbc->lock);
ret = fbc->count;
- for_each_possible_cpu(cpu) {
+ for_each_online_cpu(cpu) {
s32 *pcount = per_cpu_ptr(fbc->counters, cpu);
ret += *pcount;
}
@@ -44,3 +53,60 @@ s64 percpu_counter_sum(struct percpu_counter *fbc)
return ret < 0 ? 0 : ret;
}
EXPORT_SYMBOL(percpu_counter_sum);
+
+void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
+{
+ spin_lock_init(&fbc->lock);
+ fbc->count = amount;
+ fbc->counters = alloc_percpu(s32);
+#ifdef CONFIG_HOTPLUG_CPU
+ mutex_lock(&percpu_counters_lock);
+ list_add(&fbc->list, &percpu_counters);
+ mutex_unlock(&percpu_counters_lock);
+#endif
+}
+EXPORT_SYMBOL(percpu_counter_init);
+
+void percpu_counter_destroy(struct percpu_counter *fbc)
+{
+ free_percpu(fbc->counters);
+#ifdef CONFIG_HOTPLUG_CPU
+ mutex_lock(&percpu_counters_lock);
+ list_del(&fbc->list);
+ mutex_unlock(&percpu_counters_lock);
+#endif
+}
+EXPORT_SYMBOL(percpu_counter_destroy);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int __cpuinit percpu_counter_hotcpu_callback(struct notifier_block *nb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu;
+ struct percpu_counter *fbc;
+
+ if (action != CPU_DEAD)
+ return NOTIFY_OK;
+
+ cpu = (unsigned long)hcpu;
+ mutex_lock(&percpu_counters_lock);
+ list_for_each_entry(fbc, &percpu_counters, list) {
+ s32 *pcount;
+
+ spin_lock(&fbc->lock);
+ pcount = per_cpu_ptr(fbc->counters, cpu);
+ fbc->count += *pcount;
+ *pcount = 0;
+ spin_unlock(&fbc->lock);
+ }
+ mutex_unlock(&percpu_counters_lock);
+ return NOTIFY_OK;
+}
+
+static int __init percpu_counter_startup(void)
+{
+ hotcpu_notifier(percpu_counter_hotcpu_callback, 0);
+ return 0;
+}
+module_init(percpu_counter_startup);
+#endif
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 402eb4eb6b23..514efb200be6 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -151,6 +151,7 @@ int radix_tree_preload(gfp_t gfp_mask)
out:
return ret;
}
+EXPORT_SYMBOL(radix_tree_preload);
static inline void tag_set(struct radix_tree_node *node, unsigned int tag,
int offset)
@@ -1020,7 +1021,7 @@ 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, NULL);
+ SLAB_PANIC, radix_tree_node_ctor);
radix_tree_init_maxindex();
hotcpu_notifier(radix_tree_callback, 0);
}
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 10c13ad0d82d..a7381d55663a 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -357,7 +357,8 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
* This is needed when we sync the memory. Then we sync the buffer if
* needed.
*/
- io_tlb_orig_addr[index] = buffer;
+ for (i = 0; i < nslots; i++)
+ io_tlb_orig_addr[index+i] = buffer + (i << IO_TLB_SHIFT);
if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
memcpy(dma_addr, buffer, size);
@@ -418,6 +419,8 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
char *buffer = io_tlb_orig_addr[index];
+ buffer += ((unsigned long)dma_addr & ((1 << IO_TLB_SHIFT) - 1));
+
switch (target) {
case SYNC_FOR_CPU:
if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 017290241261..6b6734df6d2d 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -135,6 +135,103 @@ static int skip_atoi(const char **s)
return i;
}
+/* Decimal conversion is by far the most typical, and is used
+ * for /proc and /sys data. This directly impacts e.g. top performance
+ * with many processes running. We optimize it for speed
+ * using code from
+ * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
+ * (with permission from the author, Douglas W. Jones). */
+
+/* Formats correctly any integer in [0,99999].
+ * Outputs from one to five digits depending on input.
+ * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
+static char* put_dec_trunc(char *buf, unsigned q)
+{
+ unsigned d3, d2, d1, d0;
+ d1 = (q>>4) & 0xf;
+ d2 = (q>>8) & 0xf;
+ d3 = (q>>12);
+
+ d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+ q = (d0 * 0xcd) >> 11;
+ d0 = d0 - 10*q;
+ *buf++ = d0 + '0'; /* least significant digit */
+ d1 = q + 9*d3 + 5*d2 + d1;
+ if (d1 != 0) {
+ q = (d1 * 0xcd) >> 11;
+ d1 = d1 - 10*q;
+ *buf++ = d1 + '0'; /* next digit */
+
+ d2 = q + 2*d2;
+ if ((d2 != 0) || (d3 != 0)) {
+ q = (d2 * 0xd) >> 7;
+ d2 = d2 - 10*q;
+ *buf++ = d2 + '0'; /* next digit */
+
+ d3 = q + 4*d3;
+ if (d3 != 0) {
+ q = (d3 * 0xcd) >> 11;
+ d3 = d3 - 10*q;
+ *buf++ = d3 + '0'; /* next digit */
+ if (q != 0)
+ *buf++ = q + '0'; /* most sign. digit */
+ }
+ }
+ }
+ return buf;
+}
+/* Same with if's removed. Always emits five digits */
+static char* put_dec_full(char *buf, unsigned q)
+{
+ /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
+ /* but anyway, gcc produces better code with full-sized ints */
+ unsigned d3, d2, d1, d0;
+ d1 = (q>>4) & 0xf;
+ d2 = (q>>8) & 0xf;
+ d3 = (q>>12);
+
+ /* Possible ways to approx. divide by 10 */
+ /* gcc -O2 replaces multiply with shifts and adds */
+ // (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
+ // (x * 0x67) >> 10: 1100111
+ // (x * 0x34) >> 9: 110100 - same
+ // (x * 0x1a) >> 8: 11010 - same
+ // (x * 0x0d) >> 7: 1101 - same, shortest code (on i386)
+
+ d0 = 6*(d3 + d2 + d1) + (q & 0xf);
+ q = (d0 * 0xcd) >> 11;
+ d0 = d0 - 10*q;
+ *buf++ = d0 + '0';
+ d1 = q + 9*d3 + 5*d2 + d1;
+ q = (d1 * 0xcd) >> 11;
+ d1 = d1 - 10*q;
+ *buf++ = d1 + '0';
+
+ d2 = q + 2*d2;
+ q = (d2 * 0xd) >> 7;
+ d2 = d2 - 10*q;
+ *buf++ = d2 + '0';
+
+ d3 = q + 4*d3;
+ q = (d3 * 0xcd) >> 11; /* - shorter code */
+ /* q = (d3 * 0x67) >> 10; - would also work */
+ d3 = d3 - 10*q;
+ *buf++ = d3 + '0';
+ *buf++ = q + '0';
+ return buf;
+}
+/* No inlining helps gcc to use registers better */
+static noinline char* put_dec(char *buf, unsigned long long num)
+{
+ while (1) {
+ unsigned rem;
+ if (num < 100000)
+ return put_dec_trunc(buf, num);
+ rem = do_div(num, 100000);
+ buf = put_dec_full(buf, rem);
+ }
+}
+
#define ZEROPAD 1 /* pad with zero */
#define SIGN 2 /* unsigned/signed long */
#define PLUS 4 /* show plus */
@@ -143,12 +240,14 @@ static int skip_atoi(const char **s)
#define SPECIAL 32 /* 0x */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
-static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
+static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type)
{
- char c,sign,tmp[66];
+ char sign,tmp[66];
const char *digits;
- static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ /* we are called with base 8, 10 or 16, only, thus don't need "g..." */
+ static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */
+ static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
+ int need_pfx = ((type & SPECIAL) && base != 10);
int i;
digits = (type & LARGE) ? large_digits : small_digits;
@@ -156,7 +255,6 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return NULL;
- c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if ((signed long long) num < 0) {
@@ -171,64 +269,85 @@ static char * number(char * buf, char * end, unsigned long long num, int base, i
size--;
}
}
- if (type & SPECIAL) {
+ if (need_pfx) {
+ size--;
if (base == 16)
- size -= 2;
- else if (base == 8)
size--;
}
+
+ /* generate full string in tmp[], in reverse order */
i = 0;
if (num == 0)
- tmp[i++]='0';
- else while (num != 0)
+ tmp[i++] = '0';
+ /* Generic code, for any base:
+ else do {
tmp[i++] = digits[do_div(num,base)];
+ } while (num != 0);
+ */
+ else if (base != 10) { /* 8 or 16 */
+ int mask = base - 1;
+ int shift = 3;
+ if (base == 16) shift = 4;
+ do {
+ tmp[i++] = digits[((unsigned char)num) & mask];
+ num >>= shift;
+ } while (num);
+ } else { /* base 10 */
+ i = put_dec(tmp, num) - tmp;
+ }
+
+ /* printing 100 using %2d gives "100", not "00" */
if (i > precision)
precision = i;
+ /* leading space padding */
size -= precision;
- if (!(type&(ZEROPAD+LEFT))) {
- while(size-->0) {
+ if (!(type & (ZEROPAD+LEFT))) {
+ while(--size >= 0) {
if (buf < end)
*buf = ' ';
++buf;
}
}
+ /* sign */
if (sign) {
if (buf < end)
*buf = sign;
++buf;
}
- if (type & SPECIAL) {
- if (base==8) {
- if (buf < end)
- *buf = '0';
- ++buf;
- } else if (base==16) {
- if (buf < end)
- *buf = '0';
- ++buf;
+ /* "0x" / "0" prefix */
+ if (need_pfx) {
+ if (buf < end)
+ *buf = '0';
+ ++buf;
+ if (base == 16) {
if (buf < end)
- *buf = digits[33];
+ *buf = digits[16]; /* for arbitrary base: digits[33]; */
++buf;
}
}
+ /* zero or space padding */
if (!(type & LEFT)) {
- while (size-- > 0) {
+ char c = (type & ZEROPAD) ? '0' : ' ';
+ while (--size >= 0) {
if (buf < end)
*buf = c;
++buf;
}
}
- while (i < precision--) {
+ /* hmm even more zero padding? */
+ while (i <= --precision) {
if (buf < end)
*buf = '0';
++buf;
}
- while (i-- > 0) {
+ /* actual digits of result */
+ while (--i >= 0) {
if (buf < end)
*buf = tmp[i];
++buf;
}
- while (size-- > 0) {
+ /* trailing space padding */
+ while (--size >= 0) {
if (buf < end)
*buf = ' ';
++buf;
@@ -276,7 +395,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
used for unknown buffer sizes. */
if (unlikely((int) size < 0)) {
/* There can be only one.. */
- static int warn = 1;
+ static char warn = 1;
WARN_ON(warn);
warn = 0;
return 0;
diff --git a/mm/Kconfig b/mm/Kconfig
index 8ac412b45f18..86187221e78f 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -117,7 +117,7 @@ config MEMORY_HOTPLUG
bool "Allow for memory hot-add"
depends on SPARSEMEM || X86_64_ACPI_NUMA
depends on HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
- depends on (IA64 || X86 || PPC64)
+ depends on (IA64 || X86 || PPC64 || SUPERH)
comment "Memory hotplug is currently incompatible with Software Suspend"
depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
@@ -163,8 +163,16 @@ config ZONE_DMA_FLAG
default "0" if !ZONE_DMA
default "1"
+config BOUNCE
+ def_bool y
+ depends on BLOCK && MMU && (ZONE_DMA || HIGHMEM)
+
config NR_QUICK
int
depends on QUICKLIST
default "2" if (SUPERH && !SUPERH64)
default "1"
+
+config VIRT_TO_BUS
+ def_bool y
+ depends on !ARCH_NO_VIRT_TO_BUS
diff --git a/mm/Makefile b/mm/Makefile
index a9148ea329aa..245e33ab00c4 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -13,9 +13,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
$(mmu-y)
-ifeq ($(CONFIG_MMU)$(CONFIG_BLOCK),yy)
-obj-y += bounce.o
-endif
+obj-$(CONFIG_BOUNCE) += bounce.o
obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o
obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o
diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c
index b2486cf887a0..00b02623f008 100644
--- a/mm/allocpercpu.c
+++ b/mm/allocpercpu.c
@@ -53,12 +53,9 @@ void *percpu_populate(void *__pdata, size_t size, gfp_t gfp, int cpu)
int node = cpu_to_node(cpu);
BUG_ON(pdata->ptrs[cpu]);
- if (node_online(node)) {
- /* FIXME: kzalloc_node(size, gfp, node) */
- pdata->ptrs[cpu] = kmalloc_node(size, gfp, node);
- if (pdata->ptrs[cpu])
- memset(pdata->ptrs[cpu], 0, size);
- } else
+ if (node_online(node))
+ pdata->ptrs[cpu] = kmalloc_node(size, gfp|__GFP_ZERO, node);
+ else
pdata->ptrs[cpu] = kzalloc(size, gfp);
return pdata->ptrs[cpu];
}
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index e5de3781d3fe..f50a2811f9dc 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -55,22 +55,6 @@ long congestion_wait(int rw, long timeout)
}
EXPORT_SYMBOL(congestion_wait);
-long congestion_wait_interruptible(int rw, long timeout)
-{
- long ret;
- DEFINE_WAIT(wait);
- wait_queue_head_t *wqh = &congestion_wqh[rw];
-
- prepare_to_wait(wqh, &wait, TASK_INTERRUPTIBLE);
- if (signal_pending(current))
- ret = -ERESTARTSYS;
- else
- ret = io_schedule_timeout(timeout);
- finish_wait(wqh, &wait);
- return ret;
-}
-EXPORT_SYMBOL(congestion_wait_interruptible);
-
/**
* congestion_end - wake up sleepers on a congested backing_dev_info
* @rw: READ or WRITE
diff --git a/mm/filemap.c b/mm/filemap.c
index c6ebd9f912ab..49a6fe375d01 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -120,6 +120,7 @@ void __remove_from_page_cache(struct page *page)
page->mapping = NULL;
mapping->nrpages--;
__dec_zone_page_state(page, NR_FILE_PAGES);
+ BUG_ON(page_mapped(page));
}
void remove_from_page_cache(struct page *page)
@@ -866,13 +867,11 @@ void do_generic_mapping_read(struct address_space *mapping,
{
struct inode *inode = mapping->host;
unsigned long index;
- unsigned long end_index;
unsigned long offset;
unsigned long last_index;
unsigned long next_index;
unsigned long prev_index;
unsigned int prev_offset;
- loff_t isize;
struct page *cached_page;
int error;
struct file_ra_state ra = *_ra;
@@ -885,42 +884,58 @@ void do_generic_mapping_read(struct address_space *mapping,
last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
offset = *ppos & ~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 end_index;
+ loff_t isize;
unsigned long nr, ret;
+ cond_resched();
+find_page:
+ page = find_get_page(mapping, index);
+ if (!page) {
+ page_cache_sync_readahead(mapping,
+ &ra, filp,
+ index, last_index - index);
+ page = find_get_page(mapping, index);
+ if (unlikely(page == NULL))
+ goto no_cached_page;
+ }
+ if (PageReadahead(page)) {
+ page_cache_async_readahead(mapping,
+ &ra, filp, page,
+ index, last_index - index);
+ }
+ if (!PageUptodate(page))
+ goto page_not_up_to_date;
+page_ok:
+ /*
+ * i_size must be checked after we know the page is Uptodate.
+ *
+ * Checking i_size after the check allows us to calculate
+ * the correct value for "nr", which means the zero-filled
+ * part of the page is not copied back to userspace (unless
+ * another truncate extends the file - this is desired though).
+ */
+
+ isize = i_size_read(inode);
+ end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
+ if (unlikely(!isize || index > end_index)) {
+ page_cache_release(page);
+ goto out;
+ }
+
/* nr is the maximum number of bytes to copy from this page */
nr = PAGE_CACHE_SIZE;
- if (index >= end_index) {
- if (index > end_index)
- goto out;
+ if (index == end_index) {
nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
if (nr <= offset) {
+ page_cache_release(page);
goto out;
}
}
nr = nr - offset;
- cond_resched();
- if (index == next_index)
- next_index = page_cache_readahead(mapping, &ra, filp,
- index, last_index - index);
-
-find_page:
- page = find_get_page(mapping, index);
- if (unlikely(page == NULL)) {
- handle_ra_miss(mapping, &ra, index);
- goto no_cached_page;
- }
- if (!PageUptodate(page))
- goto page_not_up_to_date;
-page_ok:
-
/* If users can be writing to this page using arbitrary
* virtual addresses, take care about potential aliasing
* before reading the page on the kernel side.
@@ -1006,31 +1021,6 @@ readpage:
unlock_page(page);
}
- /*
- * i_size must be checked after we have done ->readpage.
- *
- * Checking i_size after the readpage allows us to calculate
- * the correct value for "nr", which means the zero-filled
- * part of the page is not copied back to userspace (unless
- * another truncate extends the file - this is desired though).
- */
- isize = i_size_read(inode);
- end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
- if (unlikely(!isize || index > end_index)) {
- page_cache_release(page);
- goto out;
- }
-
- /* nr is the maximum number of bytes to copy from this page */
- nr = PAGE_CACHE_SIZE;
- if (index == end_index) {
- nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
- if (nr <= offset) {
- page_cache_release(page);
- goto out;
- }
- }
- nr = nr - offset;
goto page_ok;
readpage_error:
@@ -1066,6 +1056,7 @@ no_cached_page:
out:
*_ra = ra;
+ _ra->prev_index = prev_index;
*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
if (cached_page)
@@ -1218,6 +1209,8 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
retval = retval ?: desc.error;
break;
}
+ if (desc.count > 0)
+ break;
}
}
out:
@@ -1314,62 +1307,62 @@ static int fastcall page_cache_read(struct file * file, unsigned long offset)
#define MMAP_LOTSAMISS (100)
/**
- * filemap_nopage - read in file data for page fault handling
- * @area: the applicable vm_area
- * @address: target address to read in
- * @type: returned with VM_FAULT_{MINOR,MAJOR} if not %NULL
+ * filemap_fault - read in file data for page fault handling
+ * @vma: vma in which the fault was taken
+ * @vmf: struct vm_fault containing details of the fault
*
- * filemap_nopage() is invoked via the vma operations vector for a
+ * filemap_fault() is invoked via the vma operations vector for a
* mapped memory region to read in file data during a page fault.
*
* The goto's are kind of ugly, but this streamlines the normal case of having
* it in the page cache, and handles the special cases reasonably without
* having a lot of duplicated code.
*/
-struct page *filemap_nopage(struct vm_area_struct *area,
- unsigned long address, int *type)
+int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
int error;
- struct file *file = area->vm_file;
+ struct file *file = vma->vm_file;
struct address_space *mapping = file->f_mapping;
struct file_ra_state *ra = &file->f_ra;
struct inode *inode = mapping->host;
struct page *page;
- unsigned long size, pgoff;
- int did_readaround = 0, majmin = VM_FAULT_MINOR;
-
- pgoff = ((address-area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff;
+ unsigned long size;
+ int did_readaround = 0;
+ int ret = 0;
-retry_all:
size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (pgoff >= size)
+ if (vmf->pgoff >= size)
goto outside_data_content;
/* If we don't want any read-ahead, don't bother */
- if (VM_RandomReadHint(area))
+ if (VM_RandomReadHint(vma))
goto no_cached_page;
/*
- * The readahead code wants to be told about each and every page
- * so it can build and shrink its windows appropriately
- *
- * For sequential accesses, we use the generic readahead logic.
- */
- if (VM_SequentialReadHint(area))
- page_cache_readahead(mapping, ra, file, pgoff, 1);
-
- /*
* Do we have something in the page cache already?
*/
retry_find:
- page = find_get_page(mapping, pgoff);
+ page = find_lock_page(mapping, vmf->pgoff);
+ /*
+ * For sequential accesses, we use the generic readahead logic.
+ */
+ if (VM_SequentialReadHint(vma)) {
+ if (!page) {
+ page_cache_sync_readahead(mapping, ra, file,
+ vmf->pgoff, 1);
+ page = find_lock_page(mapping, vmf->pgoff);
+ if (!page)
+ goto no_cached_page;
+ }
+ if (PageReadahead(page)) {
+ page_cache_async_readahead(mapping, ra, file, page,
+ vmf->pgoff, 1);
+ }
+ }
+
if (!page) {
unsigned long ra_pages;
- if (VM_SequentialReadHint(area)) {
- handle_ra_miss(mapping, ra, pgoff);
- goto no_cached_page;
- }
ra->mmap_miss++;
/*
@@ -1384,7 +1377,7 @@ retry_find:
* check did_readaround, as this is an inner loop.
*/
if (!did_readaround) {
- majmin = VM_FAULT_MAJOR;
+ ret = VM_FAULT_MAJOR;
count_vm_event(PGMAJFAULT);
}
did_readaround = 1;
@@ -1392,11 +1385,11 @@ retry_find:
if (ra_pages) {
pgoff_t start = 0;
- if (pgoff > ra_pages / 2)
- start = pgoff - ra_pages / 2;
+ if (vmf->pgoff > ra_pages / 2)
+ start = vmf->pgoff - ra_pages / 2;
do_page_cache_readahead(mapping, file, start, ra_pages);
}
- page = find_get_page(mapping, pgoff);
+ page = find_lock_page(mapping, vmf->pgoff);
if (!page)
goto no_cached_page;
}
@@ -1405,35 +1398,42 @@ retry_find:
ra->mmap_hit++;
/*
- * Ok, found a page in the page cache, now we need to check
- * that it's up-to-date.
+ * We have a locked page in the page cache, now we need to check
+ * that it's up-to-date. If not, it is going to be due to an error.
*/
- if (!PageUptodate(page))
+ if (unlikely(!PageUptodate(page)))
goto page_not_uptodate;
-success:
+ /* Must recheck i_size under page lock */
+ size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (unlikely(vmf->pgoff >= size)) {
+ unlock_page(page);
+ goto outside_data_content;
+ }
+
/*
* Found the page and have a reference on it.
*/
mark_page_accessed(page);
- if (type)
- *type = majmin;
- return page;
+ ra->prev_index = page->index;
+ vmf->page = page;
+ return ret | VM_FAULT_LOCKED;
outside_data_content:
/*
* An external ptracer can access pages that normally aren't
* accessible..
*/
- if (area->vm_mm == current->mm)
- return NOPAGE_SIGBUS;
+ if (vma->vm_mm == current->mm)
+ return VM_FAULT_SIGBUS;
+
/* Fall through to the non-read-ahead case */
no_cached_page:
/*
* We're only likely to ever get here if MADV_RANDOM is in
* effect.
*/
- error = page_cache_read(file, pgoff);
+ error = page_cache_read(file, vmf->pgoff);
/*
* The page we want has now been added to the page cache.
@@ -1449,12 +1449,13 @@ no_cached_page:
* to schedule I/O.
*/
if (error == -ENOMEM)
- return NOPAGE_OOM;
- return NOPAGE_SIGBUS;
+ return VM_FAULT_OOM;
+ return VM_FAULT_SIGBUS;
page_not_uptodate:
+ /* IO error path */
if (!did_readaround) {
- majmin = VM_FAULT_MAJOR;
+ ret = VM_FAULT_MAJOR;
count_vm_event(PGMAJFAULT);
}
@@ -1464,217 +1465,21 @@ page_not_uptodate:
* because there really aren't any performance issues here
* and we need to check for errors.
*/
- lock_page(page);
-
- /* Somebody truncated the page on us? */
- if (!page->mapping) {
- unlock_page(page);
- page_cache_release(page);
- goto retry_all;
- }
-
- /* Somebody else successfully read it in? */
- if (PageUptodate(page)) {
- unlock_page(page);
- goto success;
- }
ClearPageError(page);
error = mapping->a_ops->readpage(file, page);
- if (!error) {
- wait_on_page_locked(page);
- if (PageUptodate(page))
- goto success;
- } else if (error == AOP_TRUNCATED_PAGE) {
- page_cache_release(page);
- goto retry_find;
- }
-
- /*
- * Things didn't work out. Return zero to tell the
- * mm layer so, possibly freeing the page cache page first.
- */
- shrink_readahead_size_eio(file, ra);
page_cache_release(page);
- return NOPAGE_SIGBUS;
-}
-EXPORT_SYMBOL(filemap_nopage);
-static struct page * filemap_getpage(struct file *file, unsigned long pgoff,
- int nonblock)
-{
- struct address_space *mapping = file->f_mapping;
- struct page *page;
- int error;
-
- /*
- * Do we have something in the page cache already?
- */
-retry_find:
- page = find_get_page(mapping, pgoff);
- if (!page) {
- if (nonblock)
- return NULL;
- goto no_cached_page;
- }
-
- /*
- * Ok, found a page in the page cache, now we need to check
- * that it's up-to-date.
- */
- if (!PageUptodate(page)) {
- if (nonblock) {
- page_cache_release(page);
- return NULL;
- }
- goto page_not_uptodate;
- }
-
-success:
- /*
- * Found the page and have a reference on it.
- */
- mark_page_accessed(page);
- return page;
-
-no_cached_page:
- error = page_cache_read(file, pgoff);
-
- /*
- * The page we want has now been added to the page cache.
- * In the unlikely event that someone removed it in the
- * meantime, we'll just come back here and read it again.
- */
- if (error >= 0)
+ if (!error || error == AOP_TRUNCATED_PAGE)
goto retry_find;
- /*
- * An error return from page_cache_read can result if the
- * system is low on memory, or a problem occurs while trying
- * to schedule I/O.
- */
- return NULL;
-
-page_not_uptodate:
- lock_page(page);
-
- /* Did it get truncated while we waited for it? */
- if (!page->mapping) {
- unlock_page(page);
- goto err;
- }
-
- /* Did somebody else get it up-to-date? */
- if (PageUptodate(page)) {
- unlock_page(page);
- goto success;
- }
-
- error = mapping->a_ops->readpage(file, page);
- if (!error) {
- wait_on_page_locked(page);
- if (PageUptodate(page))
- goto success;
- } else if (error == AOP_TRUNCATED_PAGE) {
- page_cache_release(page);
- goto retry_find;
- }
-
- /*
- * Umm, take care of errors if the page isn't up-to-date.
- * Try to re-read it _once_. We do this synchronously,
- * because there really aren't any performance issues here
- * and we need to check for errors.
- */
- lock_page(page);
-
- /* Somebody truncated the page on us? */
- if (!page->mapping) {
- unlock_page(page);
- goto err;
- }
- /* Somebody else successfully read it in? */
- if (PageUptodate(page)) {
- unlock_page(page);
- goto success;
- }
-
- ClearPageError(page);
- error = mapping->a_ops->readpage(file, page);
- if (!error) {
- wait_on_page_locked(page);
- if (PageUptodate(page))
- goto success;
- } else if (error == AOP_TRUNCATED_PAGE) {
- page_cache_release(page);
- goto retry_find;
- }
-
- /*
- * Things didn't work out. Return zero to tell the
- * mm layer so, possibly freeing the page cache page first.
- */
-err:
- page_cache_release(page);
-
- return NULL;
-}
-
-int filemap_populate(struct vm_area_struct *vma, unsigned long addr,
- unsigned long len, pgprot_t prot, unsigned long pgoff,
- int nonblock)
-{
- struct file *file = vma->vm_file;
- struct address_space *mapping = file->f_mapping;
- struct inode *inode = mapping->host;
- unsigned long size;
- struct mm_struct *mm = vma->vm_mm;
- struct page *page;
- int err;
-
- if (!nonblock)
- force_page_cache_readahead(mapping, vma->vm_file,
- pgoff, len >> PAGE_CACHE_SHIFT);
-
-repeat:
- size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (pgoff + (len >> PAGE_CACHE_SHIFT) > size)
- return -EINVAL;
-
- page = filemap_getpage(file, pgoff, nonblock);
-
- /* XXX: This is wrong, a filesystem I/O error may have happened. Fix that as
- * done in shmem_populate calling shmem_getpage */
- if (!page && !nonblock)
- return -ENOMEM;
-
- if (page) {
- err = install_page(mm, vma, addr, page, prot);
- if (err) {
- page_cache_release(page);
- return err;
- }
- } else if (vma->vm_flags & VM_NONLINEAR) {
- /* No page was found just because we can't read it in now (being
- * here implies nonblock != 0), but the page may exist, so set
- * the PTE to fault it in later. */
- err = install_file_pte(mm, vma, addr, pgoff, prot);
- if (err)
- return err;
- }
-
- len -= PAGE_SIZE;
- addr += PAGE_SIZE;
- pgoff++;
- if (len)
- goto repeat;
-
- return 0;
+ /* Things didn't work out. Return zero to tell the mm layer so. */
+ shrink_readahead_size_eio(file, ra);
+ return VM_FAULT_SIGBUS;
}
-EXPORT_SYMBOL(filemap_populate);
+EXPORT_SYMBOL(filemap_fault);
struct vm_operations_struct generic_file_vm_ops = {
- .nopage = filemap_nopage,
- .populate = filemap_populate,
+ .fault = filemap_fault,
};
/* This is used for a general mmap of a disk file */
@@ -1687,6 +1492,7 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
return -ENOEXEC;
file_accessed(file);
vma->vm_ops = &generic_file_vm_ops;
+ vma->vm_flags |= VM_CAN_NONLINEAR;
return 0;
}
@@ -1964,7 +1770,6 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, i
if (unlikely(*pos + *count > MAX_NON_LFS &&
!(file->f_flags & O_LARGEFILE))) {
if (*pos >= MAX_NON_LFS) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
if (*count > MAX_NON_LFS - (unsigned long)*pos) {
@@ -1982,7 +1787,6 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, i
if (likely(!isblk)) {
if (unlikely(*pos >= inode->i_sb->s_maxbytes)) {
if (*count || *pos > inode->i_sb->s_maxbytes) {
- send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
/* zero-length writes at ->s_maxbytes are OK */
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
index 65ffc321f0c0..53ee6a299635 100644
--- a/mm/filemap_xip.c
+++ b/mm/filemap_xip.c
@@ -205,62 +205,58 @@ __xip_unmap (struct address_space * mapping,
}
/*
- * xip_nopage() is invoked via the vma operations vector for a
+ * xip_fault() is invoked via the vma operations vector for a
* mapped memory region to read in file data during a page fault.
*
- * This function is derived from filemap_nopage, but used for execute in place
+ * This function is derived from filemap_fault, but used for execute in place
*/
-static struct page *
-xip_file_nopage(struct vm_area_struct * area,
- unsigned long address,
- int *type)
+static int xip_file_fault(struct vm_area_struct *area, struct vm_fault *vmf)
{
struct file *file = area->vm_file;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
struct page *page;
- unsigned long size, pgoff, endoff;
+ pgoff_t size;
- pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT)
- + area->vm_pgoff;
- endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT)
- + area->vm_pgoff;
+ /* XXX: are VM_FAULT_ codes OK? */
size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (pgoff >= size)
- return NOPAGE_SIGBUS;
+ if (vmf->pgoff >= size)
+ return VM_FAULT_SIGBUS;
- page = mapping->a_ops->get_xip_page(mapping, pgoff*(PAGE_SIZE/512), 0);
+ 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)
- return NOPAGE_SIGBUS;
+ return VM_FAULT_OOM;
/* sparse block */
if ((area->vm_flags & (VM_WRITE | VM_MAYWRITE)) &&
(area->vm_flags & (VM_SHARED| VM_MAYSHARE)) &&
(!(mapping->host->i_sb->s_flags & MS_RDONLY))) {
/* maybe shared writable, allocate new block */
- page = mapping->a_ops->get_xip_page (mapping,
- pgoff*(PAGE_SIZE/512), 1);
+ page = mapping->a_ops->get_xip_page(mapping,
+ vmf->pgoff*(PAGE_SIZE/512), 1);
if (IS_ERR(page))
- return NOPAGE_SIGBUS;
+ return VM_FAULT_SIGBUS;
/* unmap page at pgoff from all other vmas */
- __xip_unmap(mapping, pgoff);
+ __xip_unmap(mapping, vmf->pgoff);
} else {
/* not shared and writable, use xip_sparse_page() */
page = xip_sparse_page();
if (!page)
- return NOPAGE_OOM;
+ return VM_FAULT_OOM;
}
out:
page_cache_get(page);
- return page;
+ vmf->page = page;
+ return 0;
}
static struct vm_operations_struct xip_file_vm_ops = {
- .nopage = xip_file_nopage,
+ .fault = xip_file_fault,
};
int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
@@ -269,6 +265,7 @@ int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
file_accessed(file);
vma->vm_ops = &xip_file_vm_ops;
+ vma->vm_flags |= VM_CAN_NONLINEAR;
return 0;
}
EXPORT_SYMBOL_GPL(xip_file_mmap);
diff --git a/mm/fremap.c b/mm/fremap.c
index 4e3f53dd5fd4..c395b1abf082 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -20,13 +20,14 @@
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
-static int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+static void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
pte_t pte = *ptep;
- struct page *page = NULL;
if (pte_present(pte)) {
+ struct page *page;
+
flush_cache_page(vma, addr, pte_pfn(pte));
pte = ptep_clear_flush(vma, addr, ptep);
page = vm_normal_page(vma, addr, pte);
@@ -35,68 +36,21 @@ static int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
set_page_dirty(page);
page_remove_rmap(page, vma);
page_cache_release(page);
+ update_hiwater_rss(mm);
+ dec_mm_counter(mm, file_rss);
}
} else {
if (!pte_file(pte))
free_swap_and_cache(pte_to_swp_entry(pte));
pte_clear_not_present_full(mm, addr, ptep, 0);
}
- return !!page;
}
/*
- * Install a file page to a given virtual memory address, release any
- * previously existing mapping.
- */
-int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
- unsigned long addr, struct page *page, pgprot_t prot)
-{
- struct inode *inode;
- pgoff_t size;
- int err = -ENOMEM;
- pte_t *pte;
- pte_t pte_val;
- spinlock_t *ptl;
-
- pte = get_locked_pte(mm, addr, &ptl);
- if (!pte)
- goto out;
-
- /*
- * This page may have been truncated. Tell the
- * caller about it.
- */
- err = -EINVAL;
- inode = vma->vm_file->f_mapping->host;
- size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
- if (!page->mapping || page->index >= size)
- goto unlock;
- err = -ENOMEM;
- if (page_mapcount(page) > INT_MAX/2)
- goto unlock;
-
- if (pte_none(*pte) || !zap_pte(mm, vma, addr, pte))
- inc_mm_counter(mm, file_rss);
-
- flush_icache_page(vma, page);
- pte_val = mk_pte(page, prot);
- set_pte_at(mm, addr, pte, pte_val);
- page_add_file_rmap(page);
- update_mmu_cache(vma, addr, pte_val);
- lazy_mmu_prot_update(pte_val);
- err = 0;
-unlock:
- pte_unmap_unlock(pte, ptl);
-out:
- return err;
-}
-EXPORT_SYMBOL(install_page);
-
-/*
* Install a file pte to a given virtual memory address, release any
* previously existing mapping.
*/
-int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+static int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long addr, unsigned long pgoff, pgprot_t prot)
{
int err = -ENOMEM;
@@ -107,10 +61,8 @@ int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
if (!pte)
goto out;
- if (!pte_none(*pte) && zap_pte(mm, vma, addr, pte)) {
- update_hiwater_rss(mm);
- dec_mm_counter(mm, file_rss);
- }
+ if (!pte_none(*pte))
+ zap_pte(mm, vma, addr, pte);
set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff));
/*
@@ -126,6 +78,25 @@ out:
return err;
}
+static int populate_range(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long addr, unsigned long size, pgoff_t pgoff)
+{
+ int err;
+
+ do {
+ err = install_file_pte(mm, vma, addr, pgoff, vma->vm_page_prot);
+ if (err)
+ return err;
+
+ size -= PAGE_SIZE;
+ addr += PAGE_SIZE;
+ pgoff++;
+ } while (size);
+
+ return 0;
+
+}
+
/***
* sys_remap_file_pages - remap arbitrary pages of a shared backing store
* file within an existing vma.
@@ -183,41 +154,77 @@ asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
* the single existing vma. vm_private_data is used as a
* swapout cursor in a VM_NONLINEAR vma.
*/
- if (vma && (vma->vm_flags & VM_SHARED) &&
- (!vma->vm_private_data || (vma->vm_flags & VM_NONLINEAR)) &&
- vma->vm_ops && vma->vm_ops->populate &&
- end > start && start >= vma->vm_start &&
- end <= vma->vm_end) {
-
- /* Must set VM_NONLINEAR before any pages are populated. */
- if (pgoff != linear_page_index(vma, start) &&
- !(vma->vm_flags & VM_NONLINEAR)) {
- if (!has_write_lock) {
- up_read(&mm->mmap_sem);
- down_write(&mm->mmap_sem);
- has_write_lock = 1;
- goto retry;
- }
- mapping = vma->vm_file->f_mapping;
- spin_lock(&mapping->i_mmap_lock);
- flush_dcache_mmap_lock(mapping);
- vma->vm_flags |= VM_NONLINEAR;
- vma_prio_tree_remove(vma, &mapping->i_mmap);
- vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
- flush_dcache_mmap_unlock(mapping);
- spin_unlock(&mapping->i_mmap_lock);
- }
+ if (!vma || !(vma->vm_flags & VM_SHARED))
+ goto out;
- err = vma->vm_ops->populate(vma, start, size,
- vma->vm_page_prot,
- pgoff, flags & MAP_NONBLOCK);
+ if (vma->vm_private_data && !(vma->vm_flags & VM_NONLINEAR))
+ goto out;
+
+ if (!vma->vm_flags & VM_CAN_NONLINEAR)
+ goto out;
+ if (end <= start || start < vma->vm_start || end > vma->vm_end)
+ goto out;
+
+ /* Must set VM_NONLINEAR before any pages are populated. */
+ if (!(vma->vm_flags & VM_NONLINEAR)) {
+ /* Don't need a nonlinear mapping, exit success */
+ if (pgoff == linear_page_index(vma, start)) {
+ err = 0;
+ goto out;
+ }
+
+ if (!has_write_lock) {
+ up_read(&mm->mmap_sem);
+ down_write(&mm->mmap_sem);
+ has_write_lock = 1;
+ goto retry;
+ }
+ mapping = vma->vm_file->f_mapping;
/*
- * We can't clear VM_NONLINEAR because we'd have to do
- * it after ->populate completes, and that would prevent
- * downgrading the lock. (Locks can't be upgraded).
+ * page_mkclean doesn't work on nonlinear vmas, so if
+ * dirty pages need to be accounted, emulate with linear
+ * vmas.
*/
+ if (mapping_cap_account_dirty(mapping)) {
+ unsigned long addr;
+
+ flags &= MAP_NONBLOCK;
+ addr = mmap_region(vma->vm_file, start, size,
+ flags, vma->vm_flags, pgoff, 1);
+ if (IS_ERR_VALUE(addr)) {
+ err = addr;
+ } else {
+ BUG_ON(addr != start);
+ err = 0;
+ }
+ goto out;
+ }
+ spin_lock(&mapping->i_mmap_lock);
+ flush_dcache_mmap_lock(mapping);
+ vma->vm_flags |= VM_NONLINEAR;
+ vma_prio_tree_remove(vma, &mapping->i_mmap);
+ vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
+ flush_dcache_mmap_unlock(mapping);
+ spin_unlock(&mapping->i_mmap_lock);
+ }
+
+ err = populate_range(mm, vma, start, size, pgoff);
+ if (!err && !(flags & MAP_NONBLOCK)) {
+ if (unlikely(has_write_lock)) {
+ downgrade_write(&mm->mmap_sem);
+ has_write_lock = 0;
+ }
+ make_pages_present(start, start+size);
}
+
+ /*
+ * We can't clear VM_NONLINEAR because we'd have to do
+ * it after ->populate completes, and that would prevent
+ * downgrading the lock. (Locks can't be upgraded).
+ */
+
+out:
if (likely(!has_write_lock))
up_read(&mm->mmap_sem);
else
diff --git a/mm/highmem.c b/mm/highmem.c
index be8f8d36a8b9..7a967bc35152 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -46,9 +46,14 @@ unsigned int nr_free_highpages (void)
pg_data_t *pgdat;
unsigned int pages = 0;
- for_each_online_pgdat(pgdat)
+ for_each_online_pgdat(pgdat) {
pages += zone_page_state(&pgdat->node_zones[ZONE_HIGHMEM],
NR_FREE_PAGES);
+ if (zone_movable_is_highmem())
+ pages += zone_page_state(
+ &pgdat->node_zones[ZONE_MOVABLE],
+ NR_FREE_PAGES);
+ }
return pages;
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index a45d1f0691ce..f127940ec24f 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -27,6 +27,9 @@ unsigned long max_huge_pages;
static struct list_head hugepage_freelists[MAX_NUMNODES];
static unsigned int nr_huge_pages_node[MAX_NUMNODES];
static unsigned int free_huge_pages_node[MAX_NUMNODES];
+static gfp_t htlb_alloc_mask = GFP_HIGHUSER;
+unsigned long hugepages_treat_as_movable;
+
/*
* Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages
*/
@@ -66,24 +69,22 @@ static void enqueue_huge_page(struct page *page)
static struct page *dequeue_huge_page(struct vm_area_struct *vma,
unsigned long address)
{
- int nid = numa_node_id();
+ int nid;
struct page *page = NULL;
- struct zonelist *zonelist = huge_zonelist(vma, address);
+ struct zonelist *zonelist = huge_zonelist(vma, address,
+ htlb_alloc_mask);
struct zone **z;
for (z = zonelist->zones; *z; z++) {
nid = zone_to_nid(*z);
- if (cpuset_zone_allowed_softwall(*z, GFP_HIGHUSER) &&
- !list_empty(&hugepage_freelists[nid]))
- break;
- }
-
- if (*z) {
- page = list_entry(hugepage_freelists[nid].next,
- struct page, lru);
- list_del(&page->lru);
- free_huge_pages--;
- free_huge_pages_node[nid]--;
+ if (cpuset_zone_allowed_softwall(*z, htlb_alloc_mask) &&
+ !list_empty(&hugepage_freelists[nid])) {
+ page = list_entry(hugepage_freelists[nid].next,
+ struct page, lru);
+ list_del(&page->lru);
+ free_huge_pages--;
+ free_huge_pages_node[nid]--;
+ }
}
return page;
}
@@ -101,13 +102,24 @@ static void free_huge_page(struct page *page)
static int alloc_fresh_huge_page(void)
{
- static int nid = 0;
+ static int prev_nid;
struct page *page;
- page = alloc_pages_node(nid, GFP_HIGHUSER|__GFP_COMP|__GFP_NOWARN,
- HUGETLB_PAGE_ORDER);
- nid = next_node(nid, node_online_map);
+ int nid;
+
+ /*
+ * Copy static prev_nid to local nid, work on that, then copy it
+ * back to prev_nid afterwards: otherwise there's a window in which
+ * a racer might pass invalid nid MAX_NUMNODES to alloc_pages_node.
+ * But we don't need to use a spin_lock here: it really doesn't
+ * matter if occasionally a racer chooses the same nid as we do.
+ */
+ nid = next_node(prev_nid, node_online_map);
if (nid == MAX_NUMNODES)
nid = first_node(node_online_map);
+ prev_nid = nid;
+
+ page = alloc_pages_node(nid, htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN,
+ HUGETLB_PAGE_ORDER);
if (page) {
set_compound_page_dtor(page, free_huge_page);
spin_lock(&hugetlb_lock);
@@ -196,7 +208,7 @@ static void update_and_free_page(struct page *page)
1 << PG_dirty | 1 << PG_active | 1 << PG_reserved |
1 << PG_private | 1<< PG_writeback);
}
- page[1].lru.next = NULL;
+ set_compound_page_dtor(page, NULL);
set_page_refcounted(page);
__free_pages(page, HUGETLB_PAGE_ORDER);
}
@@ -256,6 +268,19 @@ int hugetlb_sysctl_handler(struct ctl_table *table, int write,
max_huge_pages = set_max_huge_pages(max_huge_pages);
return 0;
}
+
+int hugetlb_treat_movable_handler(struct ctl_table *table, int write,
+ struct file *file, void __user *buffer,
+ size_t *length, loff_t *ppos)
+{
+ proc_dointvec(table, write, file, buffer, length, ppos);
+ if (hugepages_treat_as_movable)
+ htlb_alloc_mask = GFP_HIGHUSER_MOVABLE;
+ else
+ htlb_alloc_mask = GFP_HIGHUSER;
+ return 0;
+}
+
#endif /* CONFIG_SYSCTL */
int hugetlb_report_meminfo(char *buf)
@@ -292,15 +317,14 @@ unsigned long hugetlb_total_pages(void)
* hugegpage VMA. do_page_fault() is supposed to trap this, so BUG is we get
* this far.
*/
-static struct page *hugetlb_nopage(struct vm_area_struct *vma,
- unsigned long address, int *unused)
+static int hugetlb_vm_op_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
BUG();
- return NULL;
+ return 0;
}
struct vm_operations_struct hugetlb_vm_ops = {
- .nopage = hugetlb_nopage,
+ .fault = hugetlb_vm_op_fault,
};
static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page,
@@ -446,7 +470,7 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
avoidcopy = (page_count(old_page) == 1);
if (avoidcopy) {
set_huge_ptep_writable(vma, address, ptep);
- return VM_FAULT_MINOR;
+ return 0;
}
page_cache_get(old_page);
@@ -471,10 +495,10 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
}
page_cache_release(new_page);
page_cache_release(old_page);
- return VM_FAULT_MINOR;
+ return 0;
}
-int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
+static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, pte_t *ptep, int write_access)
{
int ret = VM_FAULT_SIGBUS;
@@ -528,7 +552,7 @@ retry:
if (idx >= size)
goto backout;
- ret = VM_FAULT_MINOR;
+ ret = 0;
if (!pte_none(*ptep))
goto backout;
@@ -579,7 +603,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
return ret;
}
- ret = VM_FAULT_MINOR;
+ ret = 0;
spin_lock(&mm->page_table_lock);
/* Check for a racing update before calling hugetlb_cow */
@@ -618,7 +642,7 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
spin_unlock(&mm->page_table_lock);
ret = hugetlb_fault(mm, vma, vaddr, 0);
spin_lock(&mm->page_table_lock);
- if (ret == VM_FAULT_MINOR)
+ if (!(ret & VM_FAULT_MAJOR))
continue;
remainder = 0;
diff --git a/mm/madvise.c b/mm/madvise.c
index 60542d006ec1..93ee375b38e7 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -287,9 +287,11 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
struct vm_area_struct * vma, *prev;
int unmapped_error = 0;
int error = -EINVAL;
+ int write;
size_t len;
- if (madvise_need_mmap_write(behavior))
+ write = madvise_need_mmap_write(behavior);
+ if (write)
down_write(&current->mm->mmap_sem);
else
down_read(&current->mm->mmap_sem);
@@ -354,7 +356,7 @@ asmlinkage long sys_madvise(unsigned long start, size_t len_in, int behavior)
vma = find_vma(current->mm, start);
}
out:
- if (madvise_need_mmap_write(behavior))
+ if (write)
up_write(&current->mm->mmap_sem);
else
up_read(&current->mm->mmap_sem);
diff --git a/mm/memory.c b/mm/memory.c
index f64cbf9baa36..ca8cac11bd2c 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -78,11 +78,9 @@ unsigned long num_physpages;
* and ZONE_HIGHMEM.
*/
void * high_memory;
-unsigned long vmalloc_earlyreserve;
EXPORT_SYMBOL(num_physpages);
EXPORT_SYMBOL(high_memory);
-EXPORT_SYMBOL(vmalloc_earlyreserve);
int randomize_va_space __read_mostly = 1;
@@ -1049,43 +1047,51 @@ 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 || (!vma->vm_ops->nopage &&
+ !vma->vm_ops->fault)))
foll_flags |= FOLL_ANON;
do {
struct page *page;
+ /*
+ * If tsk is ooming, cut off its access to large memory
+ * allocations. It has a pending SIGKILL, but it can't
+ * be processed until returning to user space.
+ */
+ if (unlikely(test_tsk_thread_flag(tsk, TIF_MEMDIE)))
+ return -ENOMEM;
+
if (write)
foll_flags |= FOLL_WRITE;
cond_resched();
while (!(page = follow_page(vma, start, foll_flags))) {
int ret;
- ret = __handle_mm_fault(mm, vma, start,
+ ret = handle_mm_fault(mm, vma, start,
foll_flags & FOLL_WRITE);
+ if (ret & VM_FAULT_ERROR) {
+ if (ret & VM_FAULT_OOM)
+ return i ? i : -ENOMEM;
+ else if (ret & VM_FAULT_SIGBUS)
+ return i ? i : -EFAULT;
+ BUG();
+ }
+ if (ret & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+
/*
- * The VM_FAULT_WRITE bit tells us that do_wp_page has
- * broken COW when necessary, even if maybe_mkwrite
- * decided not to set pte_write. We can thus safely do
- * subsequent page lookups as if they were reads.
+ * The VM_FAULT_WRITE bit tells us that
+ * do_wp_page has broken COW when necessary,
+ * even if maybe_mkwrite decided not to set
+ * pte_write. We can thus safely do subsequent
+ * page lookups as if they were reads.
*/
if (ret & VM_FAULT_WRITE)
foll_flags &= ~FOLL_WRITE;
-
- switch (ret & ~VM_FAULT_WRITE) {
- case VM_FAULT_MINOR:
- tsk->min_flt++;
- break;
- case VM_FAULT_MAJOR:
- tsk->maj_flt++;
- break;
- case VM_FAULT_SIGBUS:
- return i ? i : -EFAULT;
- case VM_FAULT_OOM:
- return i ? i : -ENOMEM;
- default:
- BUG();
- }
+
cond_resched();
}
if (pages) {
@@ -1632,7 +1638,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
{
struct page *old_page, *new_page;
pte_t entry;
- int reuse = 0, ret = VM_FAULT_MINOR;
+ int reuse = 0, ret = 0;
struct page *dirty_page = NULL;
old_page = vm_normal_page(vma, address, orig_pte);
@@ -1709,11 +1715,11 @@ gotten:
if (unlikely(anon_vma_prepare(vma)))
goto oom;
if (old_page == ZERO_PAGE(address)) {
- new_page = alloc_zeroed_user_highpage(vma, address);
+ new_page = alloc_zeroed_user_highpage_movable(vma, address);
if (!new_page)
goto oom;
} else {
- new_page = alloc_page_vma(GFP_HIGHUSER, vma, address);
+ new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
if (!new_page)
goto oom;
cow_user_page(new_page, old_page, address, vma);
@@ -1759,6 +1765,15 @@ gotten:
unlock:
pte_unmap_unlock(page_table, ptl);
if (dirty_page) {
+ /*
+ * Yes, Virginia, this is actually required to prevent a race
+ * with clear_page_dirty_for_io() from clearing the page dirty
+ * bit after it clear all dirty ptes, but before a racing
+ * do_wp_page installs a dirty pte.
+ *
+ * do_no_page is protected similarly.
+ */
+ wait_on_page_locked(dirty_page);
set_page_dirty_balance(dirty_page);
put_page(dirty_page);
}
@@ -1825,6 +1840,13 @@ static int unmap_mapping_range_vma(struct vm_area_struct *vma,
unsigned long restart_addr;
int need_break;
+ /*
+ * files that support invalidating or truncating portions of the
+ * file from under mmaped areas must have their ->fault function
+ * return a locked page (and set VM_FAULT_LOCKED in the return).
+ * This provides synchronisation against concurrent unmapping here.
+ */
+
again:
restart_addr = vma->vm_truncate_count;
if (is_restart_addr(restart_addr) && start_addr < restart_addr) {
@@ -1953,17 +1975,8 @@ void unmap_mapping_range(struct address_space *mapping,
spin_lock(&mapping->i_mmap_lock);
- /* serialize i_size write against truncate_count write */
- smp_wmb();
- /* Protect against page faults, and endless unmapping loops */
+ /* Protect against endless unmapping loops */
mapping->truncate_count++;
- /*
- * For archs where spin_lock has inclusive semantics like ia64
- * this smp_mb() will prevent to read pagetable contents
- * before the truncate_count increment is visible to
- * other cpus.
- */
- smp_mb();
if (unlikely(is_restart_addr(mapping->truncate_count))) {
if (mapping->truncate_count == 0)
reset_vma_truncate_counts(mapping);
@@ -2002,8 +2015,18 @@ int vmtruncate(struct inode * inode, loff_t offset)
if (IS_SWAPFILE(inode))
goto out_busy;
i_size_write(inode, offset);
+
+ /*
+ * unmap_mapping_range is called twice, first simply for efficiency
+ * so that truncate_inode_pages does fewer single-page unmaps. However
+ * after this first call, and before truncate_inode_pages finishes,
+ * it is possible for private pages to be COWed, which remain after
+ * truncate_inode_pages finishes, hence the second unmap_mapping_range
+ * call must be made for correctness.
+ */
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
truncate_inode_pages(mapping, offset);
+ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
goto out_truncate;
do_expand:
@@ -2043,6 +2066,7 @@ int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end)
down_write(&inode->i_alloc_sem);
unmap_mapping_range(mapping, offset, (end - offset), 1);
truncate_inode_pages_range(mapping, offset, end);
+ unmap_mapping_range(mapping, offset, (end - offset), 1);
inode->i_op->truncate_range(inode, offset, end);
up_write(&inode->i_alloc_sem);
mutex_unlock(&inode->i_mutex);
@@ -2124,7 +2148,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
struct page *page;
swp_entry_t entry;
pte_t pte;
- int ret = VM_FAULT_MINOR;
+ int ret = 0;
if (!pte_unmap_same(mm, pmd, page_table, orig_pte))
goto out;
@@ -2192,15 +2216,15 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
unlock_page(page);
if (write_access) {
+ /* XXX: We could OR the do_wp_page code with this one? */
if (do_wp_page(mm, vma, address,
- page_table, pmd, ptl, pte) == VM_FAULT_OOM)
+ page_table, pmd, ptl, pte) & VM_FAULT_OOM)
ret = VM_FAULT_OOM;
goto out;
}
/* No need to invalidate - it was non-present before */
update_mmu_cache(vma, address, pte);
- lazy_mmu_prot_update(pte);
unlock:
pte_unmap_unlock(page_table, ptl);
out:
@@ -2231,7 +2255,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
if (unlikely(anon_vma_prepare(vma)))
goto oom;
- page = alloc_zeroed_user_highpage(vma, address);
+ page = alloc_zeroed_user_highpage_movable(vma, address);
if (!page)
goto oom;
@@ -2265,7 +2289,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
lazy_mmu_prot_update(entry);
unlock:
pte_unmap_unlock(page_table, ptl);
- return VM_FAULT_MINOR;
+ return 0;
release:
page_cache_release(page);
goto unlock;
@@ -2274,10 +2298,10 @@ oom:
}
/*
- * do_no_page() tries to create a new page mapping. It aggressively
+ * __do_fault() tries to create a new page mapping. It aggressively
* tries to share with existing pages, but makes a separate copy if
- * the "write_access" parameter is true in order to avoid the next
- * page fault.
+ * the FAULT_FLAG_WRITE is set in the flags parameter in order to avoid
+ * the next page fault.
*
* As this is called only for pages that do not currently exist, we
* do not need to flush old virtual caches or the TLB.
@@ -2286,89 +2310,100 @@ oom:
* but allow concurrent faults), and pte mapped but not yet locked.
* We return with mmap_sem still held, but pte unmapped and unlocked.
*/
-static int do_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
+static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, pte_t *page_table, pmd_t *pmd,
- int write_access)
+ pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
{
spinlock_t *ptl;
- struct page *new_page;
- struct address_space *mapping = NULL;
+ struct page *page;
pte_t entry;
- unsigned int sequence = 0;
- int ret = VM_FAULT_MINOR;
int anon = 0;
struct page *dirty_page = NULL;
+ struct vm_fault vmf;
+ int ret;
+
+ vmf.virtual_address = (void __user *)(address & PAGE_MASK);
+ vmf.pgoff = pgoff;
+ vmf.flags = flags;
+ vmf.page = NULL;
pte_unmap(page_table);
BUG_ON(vma->vm_flags & VM_PFNMAP);
- if (vma->vm_file) {
- mapping = vma->vm_file->f_mapping;
- sequence = mapping->truncate_count;
- smp_rmb(); /* serializes i_size against truncate_count */
+ 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;
}
-retry:
- new_page = vma->vm_ops->nopage(vma, address & PAGE_MASK, &ret);
+
/*
- * No smp_rmb is needed here as long as there's a full
- * spin_lock/unlock sequence inside the ->nopage callback
- * (for the pagecache lookup) that acts as an implicit
- * smp_mb() and prevents the i_size read to happen
- * after the next truncate_count read.
+ * For consistency in subsequent calls, make the faulted page always
+ * locked.
*/
-
- /* no page was available -- either SIGBUS, OOM or REFAULT */
- if (unlikely(new_page == NOPAGE_SIGBUS))
- return VM_FAULT_SIGBUS;
- else if (unlikely(new_page == NOPAGE_OOM))
- return VM_FAULT_OOM;
- else if (unlikely(new_page == NOPAGE_REFAULT))
- return VM_FAULT_MINOR;
+ if (unlikely(!(ret & VM_FAULT_LOCKED)))
+ lock_page(vmf.page);
+ else
+ VM_BUG_ON(!PageLocked(vmf.page));
/*
* Should we do an early C-O-W break?
*/
- if (write_access) {
+ page = vmf.page;
+ if (flags & FAULT_FLAG_WRITE) {
if (!(vma->vm_flags & VM_SHARED)) {
- struct page *page;
-
- if (unlikely(anon_vma_prepare(vma)))
- goto oom;
- page = alloc_page_vma(GFP_HIGHUSER, vma, address);
- if (!page)
- goto oom;
- copy_user_highpage(page, new_page, address, vma);
- page_cache_release(new_page);
- new_page = page;
anon = 1;
-
+ if (unlikely(anon_vma_prepare(vma))) {
+ ret = VM_FAULT_OOM;
+ goto out;
+ }
+ page = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
+ vma, address);
+ if (!page) {
+ ret = VM_FAULT_OOM;
+ goto out;
+ }
+ copy_user_highpage(page, vmf.page, address, vma);
} else {
- /* if the page will be shareable, see if the backing
+ /*
+ * If the page will be shareable, see if the backing
* address space wants to know that the page is about
- * to become writable */
- if (vma->vm_ops->page_mkwrite &&
- vma->vm_ops->page_mkwrite(vma, new_page) < 0
- ) {
- page_cache_release(new_page);
- return VM_FAULT_SIGBUS;
+ * to become writable
+ */
+ if (vma->vm_ops->page_mkwrite) {
+ unlock_page(page);
+ if (vma->vm_ops->page_mkwrite(vma, page) < 0) {
+ ret = VM_FAULT_SIGBUS;
+ anon = 1; /* no anon but release vmf.page */
+ goto out_unlocked;
+ }
+ lock_page(page);
+ /*
+ * XXX: this is not quite right (racy vs
+ * invalidate) to unlock and relock the page
+ * like this, however a better fix requires
+ * reworking page_mkwrite locking API, which
+ * is better done later.
+ */
+ if (!page->mapping) {
+ ret = 0;
+ anon = 1; /* no anon but release vmf.page */
+ goto out;
+ }
}
}
+
}
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
- /*
- * For a file-backed vma, someone could have truncated or otherwise
- * invalidated this page. If unmap_mapping_range got called,
- * retry getting the page.
- */
- if (mapping && unlikely(sequence != mapping->truncate_count)) {
- pte_unmap_unlock(page_table, ptl);
- page_cache_release(new_page);
- cond_resched();
- sequence = mapping->truncate_count;
- smp_rmb();
- goto retry;
- }
/*
* This silly early PAGE_DIRTY setting removes a race
@@ -2381,45 +2416,63 @@ retry:
* handle that later.
*/
/* Only go through if we didn't race with anybody else... */
- if (pte_none(*page_table)) {
- flush_icache_page(vma, new_page);
- entry = mk_pte(new_page, vma->vm_page_prot);
- if (write_access)
+ if (likely(pte_same(*page_table, orig_pte))) {
+ flush_icache_page(vma, page);
+ entry = mk_pte(page, vma->vm_page_prot);
+ if (flags & FAULT_FLAG_WRITE)
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
set_pte_at(mm, address, page_table, entry);
if (anon) {
- inc_mm_counter(mm, anon_rss);
- lru_cache_add_active(new_page);
- page_add_new_anon_rmap(new_page, vma, address);
+ inc_mm_counter(mm, anon_rss);
+ lru_cache_add_active(page);
+ page_add_new_anon_rmap(page, vma, address);
} else {
inc_mm_counter(mm, file_rss);
- page_add_file_rmap(new_page);
- if (write_access) {
- dirty_page = new_page;
+ page_add_file_rmap(page);
+ if (flags & FAULT_FLAG_WRITE) {
+ dirty_page = page;
get_page(dirty_page);
}
}
+
+ /* no need to invalidate: a not-present page won't be cached */
+ update_mmu_cache(vma, address, entry);
+ lazy_mmu_prot_update(entry);
} else {
- /* One of our sibling threads was faster, back out. */
- page_cache_release(new_page);
- goto unlock;
+ if (anon)
+ page_cache_release(page);
+ else
+ anon = 1; /* no anon but release faulted_page */
}
- /* no need to invalidate: a not-present page shouldn't be cached */
- update_mmu_cache(vma, address, entry);
- lazy_mmu_prot_update(entry);
-unlock:
pte_unmap_unlock(page_table, ptl);
- if (dirty_page) {
+
+out:
+ unlock_page(vmf.page);
+out_unlocked:
+ if (anon)
+ page_cache_release(vmf.page);
+ else if (dirty_page) {
set_page_dirty_balance(dirty_page);
put_page(dirty_page);
}
+
return ret;
-oom:
- page_cache_release(new_page);
- return VM_FAULT_OOM;
}
+static int do_linear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long address, pte_t *page_table, pmd_t *pmd,
+ int write_access, pte_t orig_pte)
+{
+ pgoff_t pgoff = (((address & PAGE_MASK)
+ - vma->vm_start) >> PAGE_CACHE_SHIFT) + vma->vm_pgoff;
+ unsigned int flags = (write_access ? FAULT_FLAG_WRITE : 0);
+
+ return __do_fault(mm, vma, address, page_table, pmd, pgoff,
+ flags, orig_pte);
+}
+
+
/*
* do_no_pfn() tries to create a new page mapping for a page without
* a struct_page backing it
@@ -2443,7 +2496,6 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
spinlock_t *ptl;
pte_t entry;
unsigned long pfn;
- int ret = VM_FAULT_MINOR;
pte_unmap(page_table);
BUG_ON(!(vma->vm_flags & VM_PFNMAP));
@@ -2455,7 +2507,7 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
else if (unlikely(pfn == NOPFN_SIGBUS))
return VM_FAULT_SIGBUS;
else if (unlikely(pfn == NOPFN_REFAULT))
- return VM_FAULT_MINOR;
+ return 0;
page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
@@ -2467,7 +2519,7 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
set_pte_at(mm, address, page_table, entry);
}
pte_unmap_unlock(page_table, ptl);
- return ret;
+ return 0;
}
/*
@@ -2479,33 +2531,30 @@ static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
* but allow concurrent faults), and pte mapped but not yet locked.
* We return with mmap_sem still held, but pte unmapped and unlocked.
*/
-static int do_file_page(struct mm_struct *mm, struct vm_area_struct *vma,
+static int do_nonlinear_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, pte_t *page_table, pmd_t *pmd,
int write_access, pte_t orig_pte)
{
+ unsigned int flags = FAULT_FLAG_NONLINEAR |
+ (write_access ? FAULT_FLAG_WRITE : 0);
pgoff_t pgoff;
- int err;
if (!pte_unmap_same(mm, pmd, page_table, orig_pte))
- return VM_FAULT_MINOR;
+ return 0;
- if (unlikely(!(vma->vm_flags & VM_NONLINEAR))) {
+ if (unlikely(!(vma->vm_flags & VM_NONLINEAR) ||
+ !(vma->vm_flags & VM_CAN_NONLINEAR))) {
/*
* Page table corrupted: show pte and kill process.
*/
print_bad_pte(vma, orig_pte, address);
return VM_FAULT_OOM;
}
- /* We can then assume vm->vm_ops && vma->vm_ops->populate */
pgoff = pte_to_pgoff(orig_pte);
- err = vma->vm_ops->populate(vma, address & PAGE_MASK, PAGE_SIZE,
- vma->vm_page_prot, pgoff, 0);
- if (err == -ENOMEM)
- return VM_FAULT_OOM;
- if (err)
- return VM_FAULT_SIGBUS;
- return VM_FAULT_MAJOR;
+
+ return __do_fault(mm, vma, address, page_table, pmd, pgoff,
+ flags, orig_pte);
}
/*
@@ -2532,10 +2581,9 @@ 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->nopage)
- return do_no_page(mm, vma, address,
- pte, pmd,
- write_access);
+ if (vma->vm_ops->fault || vma->vm_ops->nopage)
+ return do_linear_fault(mm, vma, address,
+ pte, pmd, write_access, entry);
if (unlikely(vma->vm_ops->nopfn))
return do_no_pfn(mm, vma, address, pte,
pmd, write_access);
@@ -2544,7 +2592,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
pte, pmd, write_access);
}
if (pte_file(entry))
- return do_file_page(mm, vma, address,
+ return do_nonlinear_fault(mm, vma, address,
pte, pmd, write_access, entry);
return do_swap_page(mm, vma, address,
pte, pmd, write_access, entry);
@@ -2576,13 +2624,13 @@ static inline int handle_pte_fault(struct mm_struct *mm,
}
unlock:
pte_unmap_unlock(pte, ptl);
- return VM_FAULT_MINOR;
+ return 0;
}
/*
* By the time we get here, we already hold the mm semaphore
*/
-int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
unsigned long address, int write_access)
{
pgd_t *pgd;
@@ -2611,8 +2659,6 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
}
-EXPORT_SYMBOL_GPL(__handle_mm_fault);
-
#ifndef __PAGETABLE_PUD_FOLDED
/*
* Allocate page upper directory.
@@ -2673,7 +2719,7 @@ int make_pages_present(unsigned long addr, unsigned long end)
write = (vma->vm_flags & VM_WRITE) != 0;
BUG_ON(addr >= end);
BUG_ON(end > vma->vm_end);
- len = (end+PAGE_SIZE-1)/PAGE_SIZE-addr/PAGE_SIZE;
+ len = DIV_ROUND_UP(end, PAGE_SIZE) - addr/PAGE_SIZE;
ret = get_user_pages(current, current->mm, addr,
len, write, 0, NULL, NULL);
if (ret < 0)
@@ -2817,3 +2863,4 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
return buf - old_buf;
}
+EXPORT_SYMBOL_GPL(access_process_vm);
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index d76e8eb342d0..71b84b45154a 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -101,8 +101,6 @@
static struct kmem_cache *policy_cache;
static struct kmem_cache *sn_cache;
-#define PDprintk(fmt...)
-
/* Highest zone. An specific allocation for a zone below that is not
policied. */
enum zone_type policy_zone = 0;
@@ -175,7 +173,9 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)
{
struct mempolicy *policy;
- PDprintk("setting mode %d nodes[0] %lx\n", mode, nodes_addr(*nodes)[0]);
+ pr_debug("setting mode %d nodes[0] %lx\n",
+ mode, nodes ? nodes_addr(*nodes)[0] : -1);
+
if (mode == MPOL_DEFAULT)
return NULL;
policy = kmem_cache_alloc(policy_cache, GFP_KERNEL);
@@ -379,7 +379,7 @@ static int policy_vma(struct vm_area_struct *vma, struct mempolicy *new)
int err = 0;
struct mempolicy *old = vma->vm_policy;
- PDprintk("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n",
+ pr_debug("vma %lx-%lx/%lx vm_ops %p vm_file %p set_policy %p\n",
vma->vm_start, vma->vm_end, vma->vm_pgoff,
vma->vm_ops, vma->vm_file,
vma->vm_ops ? vma->vm_ops->set_policy : NULL);
@@ -594,7 +594,7 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
static struct page *new_node_page(struct page *page, unsigned long node, int **x)
{
- return alloc_pages_node(node, GFP_HIGHUSER, 0);
+ return alloc_pages_node(node, GFP_HIGHUSER_MOVABLE, 0);
}
/*
@@ -710,7 +710,8 @@ static struct page *new_vma_page(struct page *page, unsigned long private, int *
{
struct vm_area_struct *vma = (struct vm_area_struct *)private;
- return alloc_page_vma(GFP_HIGHUSER, vma, page_address_in_vma(page, vma));
+ return alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma,
+ page_address_in_vma(page, vma));
}
#else
@@ -776,8 +777,8 @@ long do_mbind(unsigned long start, unsigned long len,
if (!new)
flags |= MPOL_MF_DISCONTIG_OK;
- PDprintk("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len,
- mode,nodes_addr(nodes)[0]);
+ pr_debug("mbind %lx-%lx mode:%ld nodes:%lx\n",start,start+len,
+ mode, nmask ? nodes_addr(*nmask)[0] : -1);
down_write(&mm->mmap_sem);
vma = check_range(mm, start, end, nmask,
@@ -1202,7 +1203,8 @@ static inline unsigned interleave_nid(struct mempolicy *pol,
#ifdef CONFIG_HUGETLBFS
/* Return a zonelist suitable for a huge page allocation. */
-struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr)
+struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
+ gfp_t gfp_flags)
{
struct mempolicy *pol = get_vma_policy(current, vma, addr);
@@ -1210,7 +1212,7 @@ struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr)
unsigned nid;
nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT);
- return NODE_DATA(nid)->node_zonelists + gfp_zone(GFP_HIGHUSER);
+ return NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_flags);
}
return zonelist_policy(GFP_HIGHUSER, pol);
}
@@ -1434,7 +1436,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);
- PDprintk("inserting %lx-%lx: %d\n", new->start, new->end,
+ pr_debug("inserting %lx-%lx: %d\n", new->start, new->end,
new->policy ? new->policy->policy : 0);
}
@@ -1459,7 +1461,7 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
static void sp_delete(struct shared_policy *sp, struct sp_node *n)
{
- PDprintk("deleting %lx-l%x\n", n->start, n->end);
+ pr_debug("deleting %lx-l%lx\n", n->start, n->end);
rb_erase(&n->nd, &sp->root);
mpol_free(n->policy);
kmem_cache_free(sn_cache, n);
@@ -1558,10 +1560,10 @@ int mpol_set_shared_policy(struct shared_policy *info,
struct sp_node *new = NULL;
unsigned long sz = vma_pages(vma);
- PDprintk("set_shared_policy %lx sz %lu %d %lx\n",
+ pr_debug("set_shared_policy %lx sz %lu %d %lx\n",
vma->vm_pgoff,
sz, npol? npol->policy : -1,
- npol ? nodes_addr(npol->v.nodes)[0] : -1);
+ npol ? nodes_addr(npol->v.nodes)[0] : -1);
if (npol) {
new = sp_alloc(vma->vm_pgoff, vma->vm_pgoff + sz, npol);
@@ -1597,18 +1599,43 @@ void mpol_free_shared_policy(struct shared_policy *p)
/* assumes fs == KERNEL_DS */
void __init numa_policy_init(void)
{
+ nodemask_t interleave_nodes;
+ unsigned long largest = 0;
+ int nid, prefer = 0;
+
policy_cache = kmem_cache_create("numa_policy",
sizeof(struct mempolicy),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
sn_cache = kmem_cache_create("shared_policy_node",
sizeof(struct sp_node),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
+
+ /*
+ * Set interleaving policy for system init. Interleaving is only
+ * enabled across suitably sized nodes (default is >= 16MB), or
+ * fall back to the largest node if they're all smaller.
+ */
+ nodes_clear(interleave_nodes);
+ for_each_online_node(nid) {
+ unsigned long total_pages = node_present_pages(nid);
+
+ /* Preserve the largest node */
+ if (largest < total_pages) {
+ largest = total_pages;
+ prefer = nid;
+ }
+
+ /* Interleave this node? */
+ if ((total_pages << PAGE_SHIFT) >= (16 << 20))
+ node_set(nid, interleave_nodes);
+ }
- /* Set interleaving policy for system init. This way not all
- the data structures allocated at system boot end up in node zero. */
+ /* All too small, use the largest */
+ if (unlikely(nodes_empty(interleave_nodes)))
+ node_set(prefer, interleave_nodes);
- if (do_set_mempolicy(MPOL_INTERLEAVE, &node_online_map))
+ if (do_set_mempolicy(MPOL_INTERLEAVE, &interleave_nodes))
printk("numa_policy_init: interleaving failed\n");
}
diff --git a/mm/mempool.c b/mm/mempool.c
index cc1ca86dfc24..02d5ec3feabc 100644
--- a/mm/mempool.c
+++ b/mm/mempool.c
@@ -62,10 +62,9 @@ mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn,
mempool_free_t *free_fn, void *pool_data, int node_id)
{
mempool_t *pool;
- pool = kmalloc_node(sizeof(*pool), GFP_KERNEL, node_id);
+ pool = kmalloc_node(sizeof(*pool), GFP_KERNEL | __GFP_ZERO, node_id);
if (!pool)
return NULL;
- memset(pool, 0, sizeof(*pool));
pool->elements = kmalloc_node(min_nr * sizeof(void *),
GFP_KERNEL, node_id);
if (!pool->elements) {
@@ -263,6 +262,9 @@ void mempool_free(void *element, mempool_t *pool)
{
unsigned long flags;
+ if (unlikely(element == NULL))
+ return;
+
smp_mb();
if (pool->curr_nr < pool->min_nr) {
spin_lock_irqsave(&pool->lock, flags);
diff --git a/mm/migrate.c b/mm/migrate.c
index a91ca00abebe..34d8ada053e4 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -761,7 +761,8 @@ static struct page *new_page_node(struct page *p, unsigned long private,
*result = &pm->status;
- return alloc_pages_node(pm->node, GFP_HIGHUSER | GFP_THISNODE, 0);
+ return alloc_pages_node(pm->node,
+ GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
}
/*
diff --git a/mm/mlock.c b/mm/mlock.c
index 4d3fea267e0d..7b2656055d6a 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -244,9 +244,12 @@ int user_shm_lock(size_t size, struct user_struct *user)
locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
+ if (lock_limit == RLIM_INFINITY)
+ allowed = 1;
lock_limit >>= PAGE_SHIFT;
spin_lock(&shmlock_user_lock);
- if (locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))
+ if (!allowed &&
+ locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))
goto out;
get_uid(user);
user->locked_shm += locked;
diff --git a/mm/mmap.c b/mm/mmap.c
index 906ed402f7ca..7afc7a7cec6f 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -894,14 +894,11 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
unsigned long flags, unsigned long pgoff)
{
struct mm_struct * mm = current->mm;
- struct vm_area_struct * vma, * prev;
struct inode *inode;
unsigned int vm_flags;
- int correct_wcount = 0;
int error;
- struct rb_node ** rb_link, * rb_parent;
int accountable = 1;
- unsigned long charged = 0, reqprot = prot;
+ unsigned long reqprot = prot;
/*
* Does the application expect PROT_READ to imply PROT_EXEC?
@@ -1023,10 +1020,28 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
}
}
- error = security_file_mmap(file, reqprot, prot, flags);
+ error = security_file_mmap(file, reqprot, prot, flags, addr, 0);
if (error)
return error;
-
+
+ return mmap_region(file, addr, len, flags, vm_flags, pgoff,
+ accountable);
+}
+EXPORT_SYMBOL(do_mmap_pgoff);
+
+unsigned long mmap_region(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long flags,
+ unsigned int vm_flags, unsigned long pgoff,
+ int accountable)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma, *prev;
+ int correct_wcount = 0;
+ int error;
+ struct rb_node **rb_link, *rb_parent;
+ unsigned long charged = 0;
+ struct inode *inode = file ? file->f_path.dentry->d_inode : NULL;
+
/* Clear old maps */
error = -ENOMEM;
munmap_back:
@@ -1150,12 +1165,8 @@ out:
mm->locked_vm += len >> PAGE_SHIFT;
make_pages_present(addr, addr + len);
}
- if (flags & MAP_POPULATE) {
- up_write(&mm->mmap_sem);
- sys_remap_file_pages(addr, len, 0,
- pgoff, flags & MAP_NONBLOCK);
- down_write(&mm->mmap_sem);
- }
+ if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK))
+ make_pages_present(addr, addr + len);
return addr;
unmap_and_free_vma:
@@ -1175,8 +1186,6 @@ unacct_error:
return error;
}
-EXPORT_SYMBOL(do_mmap_pgoff);
-
/* Get an address range which is currently unmapped.
* For shmat() with addr=0.
*
@@ -1562,33 +1571,11 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address)
}
#endif /* CONFIG_STACK_GROWSUP || CONFIG_IA64 */
-#ifdef CONFIG_STACK_GROWSUP
-int expand_stack(struct vm_area_struct *vma, unsigned long address)
-{
- return expand_upwards(vma, address);
-}
-
-struct vm_area_struct *
-find_extend_vma(struct mm_struct *mm, unsigned long addr)
-{
- struct vm_area_struct *vma, *prev;
-
- addr &= PAGE_MASK;
- vma = find_vma_prev(mm, addr, &prev);
- if (vma && (vma->vm_start <= addr))
- return vma;
- if (!prev || expand_stack(prev, addr))
- return NULL;
- if (prev->vm_flags & VM_LOCKED) {
- make_pages_present(addr, prev->vm_end);
- }
- return prev;
-}
-#else
/*
* vma is the first one with address < vma->vm_start. Have to extend vma.
*/
-int expand_stack(struct vm_area_struct *vma, unsigned long address)
+static inline int expand_downwards(struct vm_area_struct *vma,
+ unsigned long address)
{
int error;
@@ -1625,6 +1612,38 @@ int expand_stack(struct vm_area_struct *vma, unsigned long address)
return error;
}
+int expand_stack_downwards(struct vm_area_struct *vma, unsigned long address)
+{
+ return expand_downwards(vma, address);
+}
+
+#ifdef CONFIG_STACK_GROWSUP
+int expand_stack(struct vm_area_struct *vma, unsigned long address)
+{
+ return expand_upwards(vma, address);
+}
+
+struct vm_area_struct *
+find_extend_vma(struct mm_struct *mm, unsigned long addr)
+{
+ struct vm_area_struct *vma, *prev;
+
+ addr &= PAGE_MASK;
+ vma = find_vma_prev(mm, addr, &prev);
+ if (vma && (vma->vm_start <= addr))
+ return vma;
+ if (!prev || expand_stack(prev, addr))
+ return NULL;
+ if (prev->vm_flags & VM_LOCKED)
+ make_pages_present(addr, prev->vm_end);
+ return prev;
+}
+#else
+int expand_stack(struct vm_area_struct *vma, unsigned long address)
+{
+ return expand_downwards(vma, address);
+}
+
struct vm_area_struct *
find_extend_vma(struct mm_struct * mm, unsigned long addr)
{
@@ -1642,9 +1661,8 @@ find_extend_vma(struct mm_struct * mm, unsigned long addr)
start = vma->vm_start;
if (expand_stack(vma, addr))
return NULL;
- if (vma->vm_flags & VM_LOCKED) {
+ if (vma->vm_flags & VM_LOCKED)
make_pages_present(addr, start);
- }
return vma;
}
#endif
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 3b8f3c0c63f3..e8346c30abec 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -128,7 +128,7 @@ static void change_protection(struct vm_area_struct *vma,
flush_tlb_range(vma, start, end);
}
-static int
+int
mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
unsigned long start, unsigned long end, unsigned long newflags)
{
diff --git a/mm/mremap.c b/mm/mremap.c
index 5d4bd4f95b8e..8ea5c2412c6e 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -120,7 +120,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
#define LATENCY_LIMIT (64 * PAGE_SIZE)
-static unsigned long move_page_tables(struct vm_area_struct *vma,
+unsigned long move_page_tables(struct vm_area_struct *vma,
unsigned long old_addr, struct vm_area_struct *new_vma,
unsigned long new_addr, unsigned long len)
{
@@ -291,6 +291,10 @@ unsigned long do_mremap(unsigned long addr,
if ((addr <= new_addr) && (addr+old_len) > new_addr)
goto out;
+ ret = security_file_mmap(0, 0, 0, 0, new_addr, 1);
+ if (ret)
+ goto out;
+
ret = do_munmap(mm, new_addr, new_len);
if (ret)
goto out;
@@ -390,8 +394,13 @@ unsigned long do_mremap(unsigned long addr,
new_addr = get_unmapped_area(vma->vm_file, 0, new_len,
vma->vm_pgoff, map_flags);
- ret = new_addr;
- if (new_addr & ~PAGE_MASK)
+ if (new_addr & ~PAGE_MASK) {
+ ret = new_addr;
+ goto out;
+ }
+
+ ret = security_file_mmap(0, 0, 0, 0, new_addr, 1);
+ if (ret)
goto out;
}
ret = move_vma(vma, addr, old_len, new_len, new_addr);
diff --git a/mm/nommu.c b/mm/nommu.c
index 2b16b00a5b11..9eef6a398555 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -54,12 +54,6 @@ DECLARE_RWSEM(nommu_vma_sem);
struct vm_operations_struct generic_file_vm_ops = {
};
-EXPORT_SYMBOL(vfree);
-EXPORT_SYMBOL(vmalloc_to_page);
-EXPORT_SYMBOL(vmalloc_32);
-EXPORT_SYMBOL(vmap);
-EXPORT_SYMBOL(vunmap);
-
/*
* Handle all mappings that got truncated by a "truncate()"
* system call.
@@ -168,7 +162,6 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
finish_or_fault:
return i ? : -EFAULT;
}
-
EXPORT_SYMBOL(get_user_pages);
DEFINE_RWLOCK(vmlist_lock);
@@ -178,6 +171,7 @@ void vfree(void *addr)
{
kfree(addr);
}
+EXPORT_SYMBOL(vfree);
void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
{
@@ -186,17 +180,19 @@ void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
*/
return kmalloc(size, (gfp_mask | __GFP_COMP) & ~__GFP_HIGHMEM);
}
+EXPORT_SYMBOL(__vmalloc);
struct page * vmalloc_to_page(void *addr)
{
return virt_to_page(addr);
}
+EXPORT_SYMBOL(vmalloc_to_page);
unsigned long vmalloc_to_pfn(void *addr)
{
return page_to_pfn(virt_to_page(addr));
}
-
+EXPORT_SYMBOL(vmalloc_to_pfn);
long vread(char *buf, char *addr, unsigned long count)
{
@@ -237,9 +233,8 @@ void *vmalloc_node(unsigned long size, int node)
}
EXPORT_SYMBOL(vmalloc_node);
-/*
- * vmalloc_32 - allocate virtually continguos memory (32bit addressable)
- *
+/**
+ * vmalloc_32 - allocate virtually contiguous memory (32bit addressable)
* @size: allocation size
*
* Allocate enough 32bit PA addressable pages to cover @size from the
@@ -249,17 +244,33 @@ void *vmalloc_32(unsigned long size)
{
return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
}
+EXPORT_SYMBOL(vmalloc_32);
+
+/**
+ * vmalloc_32_user - allocate zeroed virtually contiguous 32bit memory
+ * @size: allocation size
+ *
+ * The resulting memory area is 32bit addressable and zeroed so it can be
+ * mapped to userspace without leaking data.
+ */
+void *vmalloc_32_user(unsigned long size)
+{
+ return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+}
+EXPORT_SYMBOL(vmalloc_32_user);
void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot)
{
BUG();
return NULL;
}
+EXPORT_SYMBOL(vmap);
void vunmap(void *addr)
{
BUG();
}
+EXPORT_SYMBOL(vunmap);
/*
* Implement a stub for vmalloc_sync_all() if the architecture chose not to
@@ -269,6 +280,13 @@ void __attribute__((weak)) vmalloc_sync_all(void)
{
}
+int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,
+ struct page *page)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(vm_insert_page);
+
/*
* sys_brk() for the most part doesn't need the global kernel
* lock, except when an application is doing something nasty
@@ -367,6 +385,11 @@ struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
return find_vma(mm, addr);
}
+int expand_stack(struct vm_area_struct *vma, unsigned long address)
+{
+ return -ENOMEM;
+}
+
/*
* look up the first VMA exactly that exactly matches addr
* - should be called with mm->mmap_sem at least held readlocked
@@ -639,7 +662,7 @@ static int validate_mmap_request(struct file *file,
}
/* allow the security API to have its say */
- ret = security_file_mmap(file, reqprot, prot, flags);
+ ret = security_file_mmap(file, reqprot, prot, flags, addr, 0);
if (ret < 0)
return ret;
@@ -989,6 +1012,7 @@ unsigned long do_mmap_pgoff(struct file *file,
show_free_areas();
return -ENOMEM;
}
+EXPORT_SYMBOL(do_mmap_pgoff);
/*
* handle mapping disposal for uClinux
@@ -1069,6 +1093,7 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
return 0;
}
+EXPORT_SYMBOL(do_munmap);
asmlinkage long sys_munmap(unsigned long addr, size_t len)
{
@@ -1159,6 +1184,7 @@ unsigned long do_mremap(unsigned long addr,
return vma->vm_start;
}
+EXPORT_SYMBOL(do_mremap);
asmlinkage unsigned long sys_mremap(unsigned long addr,
unsigned long old_len, unsigned long new_len,
@@ -1226,7 +1252,6 @@ unsigned long get_unmapped_area(struct file *file, unsigned long addr,
return get_area(file, addr, len, pgoff, flags);
}
-
EXPORT_SYMBOL(get_unmapped_area);
/*
@@ -1336,12 +1361,12 @@ int in_gate_area_no_task(unsigned long addr)
return 0;
}
-struct page *filemap_nopage(struct vm_area_struct *area,
- unsigned long address, int *type)
+int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
BUG();
- return NULL;
+ return 0;
}
+EXPORT_SYMBOL(filemap_fault);
/*
* Access another process' address space.
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index eec1481ba44f..63512a9ed57e 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -476,15 +476,13 @@ static void wb_kupdate(unsigned long arg)
* sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
*/
int dirty_writeback_centisecs_handler(ctl_table *table, int write,
- struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
+ struct file *file, void __user *buffer, size_t *length, loff_t *ppos)
{
proc_dointvec_userhz_jiffies(table, write, file, buffer, length, ppos);
- if (dirty_writeback_interval) {
- mod_timer(&wb_timer,
- jiffies + dirty_writeback_interval);
- } else {
+ if (dirty_writeback_interval)
+ mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
+ else
del_timer(&wb_timer);
- }
return 0;
}
@@ -826,6 +824,7 @@ int __set_page_dirty_nobuffers(struct page *page)
mapping2 = page_mapping(page);
if (mapping2) { /* Race with truncate? */
BUG_ON(mapping2 != mapping);
+ WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
if (mapping_cap_account_dirty(mapping)) {
__inc_zone_page_state(page, NR_FILE_DIRTY);
task_io_account_write(PAGE_CACHE_SIZE);
@@ -919,6 +918,9 @@ int clear_page_dirty_for_io(struct page *page)
{
struct address_space *mapping = page_mapping(page);
+ BUG_ON(!PageLocked(page));
+
+ ClearPageReclaim(page);
if (mapping && mapping_cap_account_dirty(mapping)) {
/*
* Yes, Virginia, this is indeed insane.
@@ -944,14 +946,19 @@ int clear_page_dirty_for_io(struct page *page)
* We basically use the page "master dirty bit"
* as a serialization point for all the different
* threads doing their things.
- *
- * FIXME! We still have a race here: if somebody
- * adds the page back to the page tables in
- * between the "page_mkclean()" and the "TestClearPageDirty()",
- * we might have it mapped without the dirty bit set.
*/
if (page_mkclean(page))
set_page_dirty(page);
+ /*
+ * We carefully synchronise fault handlers against
+ * installing a dirty pte and marking the page dirty
+ * at this point. We do this by having them hold the
+ * page lock at some point after installing their
+ * pte, but before marking the page dirty.
+ * Pages are always locked coming in here, so we get
+ * the desired exclusion. See mm/memory.c:do_wp_page()
+ * for more comments.
+ */
if (TestClearPageDirty(page)) {
dec_zone_page_state(page, NR_FILE_DIRTY);
return 1;
@@ -980,6 +987,8 @@ int test_clear_page_writeback(struct page *page)
} else {
ret = TestClearPageWriteback(page);
}
+ if (ret)
+ dec_zone_page_state(page, NR_WRITEBACK);
return ret;
}
@@ -1005,6 +1014,8 @@ int test_set_page_writeback(struct page *page)
} else {
ret = TestSetPageWriteback(page);
}
+ if (!ret)
+ inc_zone_page_state(page, NR_WRITEBACK);
return ret;
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 05ace44852eb..40954fb81598 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -80,8 +80,9 @@ int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = {
256,
#endif
#ifdef CONFIG_HIGHMEM
- 32
+ 32,
#endif
+ 32,
};
EXPORT_SYMBOL(totalram_pages);
@@ -95,8 +96,9 @@ static char * const zone_names[MAX_NR_ZONES] = {
#endif
"Normal",
#ifdef CONFIG_HIGHMEM
- "HighMem"
+ "HighMem",
#endif
+ "Movable",
};
int min_free_kbytes = 1024;
@@ -126,14 +128,21 @@ static unsigned long __meminitdata dma_reserve;
#endif
#endif
- struct node_active_region __meminitdata early_node_map[MAX_ACTIVE_REGIONS];
- int __meminitdata nr_nodemap_entries;
- unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
- unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
+ static struct node_active_region __meminitdata early_node_map[MAX_ACTIVE_REGIONS];
+ static int __meminitdata nr_nodemap_entries;
+ static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
+ static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
- unsigned long __initdata node_boundary_start_pfn[MAX_NUMNODES];
- unsigned long __initdata node_boundary_end_pfn[MAX_NUMNODES];
+ static unsigned long __meminitdata node_boundary_start_pfn[MAX_NUMNODES];
+ static unsigned long __meminitdata node_boundary_end_pfn[MAX_NUMNODES];
#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
+ unsigned long __initdata required_kernelcore;
+ unsigned long __initdata required_movablecore;
+ unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES];
+
+ /* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */
+ int movable_zone;
+ EXPORT_SYMBOL(movable_zone);
#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
#if MAX_NUMNODES > 1
@@ -444,12 +453,6 @@ static inline int free_pages_check(struct page *page)
1 << PG_reserved |
1 << PG_buddy ))))
bad_page(page);
- /*
- * PageReclaim == PageTail. It is only an error
- * for PageReclaim to be set if PageCompound is clear.
- */
- if (unlikely(!PageCompound(page) && PageReclaim(page)))
- bad_page(page);
if (PageDirty(page))
__ClearPageDirty(page);
/*
@@ -593,7 +596,6 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags)
1 << PG_locked |
1 << PG_active |
1 << PG_dirty |
- 1 << PG_reclaim |
1 << PG_slab |
1 << PG_swapcache |
1 << PG_writeback |
@@ -608,7 +610,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 |
+ page->flags &= ~(1 << PG_uptodate | 1 << PG_error | 1 << PG_readahead |
1 << PG_referenced | 1 << PG_arch_1 |
1 << PG_owner_priv_1 | 1 << PG_mappedtodisk);
set_page_private(page, 0);
@@ -900,11 +902,13 @@ static struct fail_page_alloc_attr {
u32 ignore_gfp_highmem;
u32 ignore_gfp_wait;
+ u32 min_order;
#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS
struct dentry *ignore_gfp_highmem_file;
struct dentry *ignore_gfp_wait_file;
+ struct dentry *min_order_file;
#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */
@@ -912,6 +916,7 @@ static struct fail_page_alloc_attr {
.attr = FAULT_ATTR_INITIALIZER,
.ignore_gfp_wait = 1,
.ignore_gfp_highmem = 1,
+ .min_order = 1,
};
static int __init setup_fail_page_alloc(char *str)
@@ -922,6 +927,8 @@ __setup("fail_page_alloc=", setup_fail_page_alloc);
static int should_fail_alloc_page(gfp_t gfp_mask, unsigned int order)
{
+ if (order < fail_page_alloc.min_order)
+ return 0;
if (gfp_mask & __GFP_NOFAIL)
return 0;
if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM))
@@ -953,12 +960,17 @@ static int __init fail_page_alloc_debugfs(void)
fail_page_alloc.ignore_gfp_highmem_file =
debugfs_create_bool("ignore-gfp-highmem", mode, dir,
&fail_page_alloc.ignore_gfp_highmem);
+ fail_page_alloc.min_order_file =
+ debugfs_create_u32("min-order", mode, dir,
+ &fail_page_alloc.min_order);
if (!fail_page_alloc.ignore_gfp_wait_file ||
- !fail_page_alloc.ignore_gfp_highmem_file) {
+ !fail_page_alloc.ignore_gfp_highmem_file ||
+ !fail_page_alloc.min_order_file) {
err = -ENOMEM;
debugfs_remove(fail_page_alloc.ignore_gfp_wait_file);
debugfs_remove(fail_page_alloc.ignore_gfp_highmem_file);
+ debugfs_remove(fail_page_alloc.min_order_file);
cleanup_fault_attr_dentries(&fail_page_alloc.attr);
}
@@ -1314,7 +1326,7 @@ nofail_alloc:
reclaim_state.reclaimed_slab = 0;
p->reclaim_state = &reclaim_state;
- did_some_progress = try_to_free_pages(zonelist->zones, gfp_mask);
+ did_some_progress = try_to_free_pages(zonelist->zones, order, gfp_mask);
p->reclaim_state = NULL;
p->flags &= ~PF_MEMALLOC;
@@ -1351,7 +1363,8 @@ nofail_alloc:
*/
do_retry = 0;
if (!(gfp_mask & __GFP_NORETRY)) {
- if ((order <= 3) || (gfp_mask & __GFP_REPEAT))
+ if ((order <= PAGE_ALLOC_COSTLY_ORDER) ||
+ (gfp_mask & __GFP_REPEAT))
do_retry = 1;
if (gfp_mask & __GFP_NOFAIL)
do_retry = 1;
@@ -1464,13 +1477,14 @@ unsigned int nr_free_buffer_pages(void)
{
return nr_free_zone_pages(gfp_zone(GFP_USER));
}
+EXPORT_SYMBOL_GPL(nr_free_buffer_pages);
/*
* Amount of free RAM allocatable within all zones
*/
unsigned int nr_free_pagecache_pages(void)
{
- return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER));
+ return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER_MOVABLE));
}
static inline void show_node(struct zone *zone)
@@ -1621,8 +1635,8 @@ void show_free_areas(void)
*
* Add all populated zones of a node to the zonelist.
*/
-static int __meminit build_zonelists_node(pg_data_t *pgdat,
- struct zonelist *zonelist, int nr_zones, enum zone_type zone_type)
+static int build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist,
+ int nr_zones, enum zone_type zone_type)
{
struct zone *zone;
@@ -1641,9 +1655,102 @@ static int __meminit build_zonelists_node(pg_data_t *pgdat,
return nr_zones;
}
+
+/*
+ * zonelist_order:
+ * 0 = automatic detection of better ordering.
+ * 1 = order by ([node] distance, -zonetype)
+ * 2 = order by (-zonetype, [node] distance)
+ *
+ * If not NUMA, ZONELIST_ORDER_ZONE and ZONELIST_ORDER_NODE will create
+ * the same zonelist. So only NUMA can configure this param.
+ */
+#define ZONELIST_ORDER_DEFAULT 0
+#define ZONELIST_ORDER_NODE 1
+#define ZONELIST_ORDER_ZONE 2
+
+/* zonelist order in the kernel.
+ * set_zonelist_order() will set this to NODE or ZONE.
+ */
+static int current_zonelist_order = ZONELIST_ORDER_DEFAULT;
+static char zonelist_order_name[3][8] = {"Default", "Node", "Zone"};
+
+
#ifdef CONFIG_NUMA
+/* The value user specified ....changed by config */
+static int user_zonelist_order = ZONELIST_ORDER_DEFAULT;
+/* string for sysctl */
+#define NUMA_ZONELIST_ORDER_LEN 16
+char numa_zonelist_order[16] = "default";
+
+/*
+ * interface for configure zonelist ordering.
+ * command line option "numa_zonelist_order"
+ * = "[dD]efault - default, automatic configuration.
+ * = "[nN]ode - order by node locality, then by zone within node
+ * = "[zZ]one - order by zone, then by locality within zone
+ */
+
+static int __parse_numa_zonelist_order(char *s)
+{
+ if (*s == 'd' || *s == 'D') {
+ user_zonelist_order = ZONELIST_ORDER_DEFAULT;
+ } else if (*s == 'n' || *s == 'N') {
+ user_zonelist_order = ZONELIST_ORDER_NODE;
+ } else if (*s == 'z' || *s == 'Z') {
+ user_zonelist_order = ZONELIST_ORDER_ZONE;
+ } else {
+ printk(KERN_WARNING
+ "Ignoring invalid numa_zonelist_order value: "
+ "%s\n", s);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static __init int setup_numa_zonelist_order(char *s)
+{
+ if (s)
+ return __parse_numa_zonelist_order(s);
+ return 0;
+}
+early_param("numa_zonelist_order", setup_numa_zonelist_order);
+
+/*
+ * sysctl handler for numa_zonelist_order
+ */
+int numa_zonelist_order_handler(ctl_table *table, int write,
+ struct file *file, void __user *buffer, size_t *length,
+ loff_t *ppos)
+{
+ char saved_string[NUMA_ZONELIST_ORDER_LEN];
+ int ret;
+
+ if (write)
+ strncpy(saved_string, (char*)table->data,
+ NUMA_ZONELIST_ORDER_LEN);
+ ret = proc_dostring(table, write, file, buffer, length, ppos);
+ if (ret)
+ return ret;
+ if (write) {
+ int oldval = user_zonelist_order;
+ if (__parse_numa_zonelist_order((char*)table->data)) {
+ /*
+ * bogus value. restore saved string
+ */
+ strncpy((char*)table->data, saved_string,
+ NUMA_ZONELIST_ORDER_LEN);
+ user_zonelist_order = oldval;
+ } else if (oldval != user_zonelist_order)
+ build_all_zonelists();
+ }
+ return 0;
+}
+
+
#define MAX_NODE_LOAD (num_online_nodes())
-static int __meminitdata node_load[MAX_NUMNODES];
+static int node_load[MAX_NUMNODES];
+
/**
* find_next_best_node - find the next node that should appear in a given node's fallback list
* @node: node whose fallback list we're appending
@@ -1658,7 +1765,7 @@ static int __meminitdata node_load[MAX_NUMNODES];
* on them otherwise.
* It returns -1 if no node is found.
*/
-static int __meminit find_next_best_node(int node, nodemask_t *used_node_mask)
+static int find_next_best_node(int node, nodemask_t *used_node_mask)
{
int n, val;
int min_val = INT_MAX;
@@ -1704,13 +1811,129 @@ static int __meminit find_next_best_node(int node, nodemask_t *used_node_mask)
return best_node;
}
-static void __meminit build_zonelists(pg_data_t *pgdat)
+
+/*
+ * Build zonelists ordered by node and zones within node.
+ * This results in maximum locality--normal zone overflows into local
+ * DMA zone, if any--but risks exhausting DMA zone.
+ */
+static void build_zonelists_in_node_order(pg_data_t *pgdat, int node)
{
- int j, node, local_node;
enum zone_type i;
- int prev_node, load;
+ 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;
+ }
+}
+
+/*
+ * Build zonelists ordered by zone and nodes within zones.
+ * This results in conserving DMA zone[s] until all Normal memory is
+ * exhausted, but results in overflowing to remote node while memory
+ * may still exist in local DMA zone.
+ */
+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->zones[pos] = NULL;
+ }
+}
+
+static int default_zonelist_order(void)
+{
+ int nid, zone_type;
+ unsigned long low_kmem_size,total_size;
+ struct zone *z;
+ int average_size;
+ /*
+ * ZONE_DMA and ZONE_DMA32 can be very small area in the sytem.
+ * If they are really small and used heavily, the system can fall
+ * into OOM very easily.
+ * This function detect ZONE_DMA/DMA32 size and confgigures zone order.
+ */
+ /* Is there ZONE_NORMAL ? (ex. ppc has only DMA zone..) */
+ low_kmem_size = 0;
+ total_size = 0;
+ for_each_online_node(nid) {
+ for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) {
+ z = &NODE_DATA(nid)->node_zones[zone_type];
+ if (populated_zone(z)) {
+ if (zone_type < ZONE_NORMAL)
+ low_kmem_size += z->present_pages;
+ total_size += z->present_pages;
+ }
+ }
+ }
+ if (!low_kmem_size || /* there are no DMA area. */
+ low_kmem_size > total_size/2) /* DMA/DMA32 is big. */
+ return ZONELIST_ORDER_NODE;
+ /*
+ * look into each node's config.
+ * If there is a node whose DMA/DMA32 memory is very big area on
+ * local memory, NODE_ORDER may be suitable.
+ */
+ average_size = total_size / (num_online_nodes() + 1);
+ for_each_online_node(nid) {
+ low_kmem_size = 0;
+ total_size = 0;
+ for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) {
+ z = &NODE_DATA(nid)->node_zones[zone_type];
+ if (populated_zone(z)) {
+ if (zone_type < ZONE_NORMAL)
+ low_kmem_size += z->present_pages;
+ total_size += z->present_pages;
+ }
+ }
+ if (low_kmem_size &&
+ total_size > average_size && /* ignore small node */
+ low_kmem_size > total_size * 70/100)
+ return ZONELIST_ORDER_NODE;
+ }
+ return ZONELIST_ORDER_ZONE;
+}
+
+static void set_zonelist_order(void)
+{
+ if (user_zonelist_order == ZONELIST_ORDER_DEFAULT)
+ current_zonelist_order = default_zonelist_order();
+ else
+ current_zonelist_order = user_zonelist_order;
+}
+
+static void build_zonelists(pg_data_t *pgdat)
+{
+ int j, node, load;
+ enum zone_type i;
nodemask_t used_mask;
+ int local_node, prev_node;
+ struct zonelist *zonelist;
+ int order = current_zonelist_order;
/* initialize zonelists */
for (i = 0; i < MAX_NR_ZONES; i++) {
@@ -1723,6 +1946,11 @@ static void __meminit build_zonelists(pg_data_t *pgdat)
load = num_online_nodes();
prev_node = local_node;
nodes_clear(used_mask);
+
+ memset(node_load, 0, sizeof(node_load));
+ memset(node_order, 0, sizeof(node_order));
+ j = 0;
+
while ((node = find_next_best_node(local_node, &used_mask)) >= 0) {
int distance = node_distance(local_node, node);
@@ -1738,23 +1966,25 @@ static void __meminit build_zonelists(pg_data_t *pgdat)
* So adding penalty to the first node in same
* distance group to make it round-robin.
*/
-
if (distance != node_distance(local_node, prev_node))
- node_load[node] += load;
+ node_load[node] = load;
+
prev_node = node;
load--;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- zonelist = pgdat->node_zonelists + i;
- for (j = 0; zonelist->zones[j] != NULL; j++);
+ if (order == ZONELIST_ORDER_NODE)
+ build_zonelists_in_node_order(pgdat, node);
+ else
+ node_order[j++] = node; /* remember order */
+ }
- j = build_zonelists_node(NODE_DATA(node), zonelist, j, i);
- zonelist->zones[j] = NULL;
- }
+ if (order == ZONELIST_ORDER_ZONE) {
+ /* calculate node order -- i.e., DMA last! */
+ build_zonelists_in_zone_order(pgdat, j);
}
}
/* Construct the zonelist performance cache - see further mmzone.h */
-static void __meminit build_zonelist_cache(pg_data_t *pgdat)
+static void build_zonelist_cache(pg_data_t *pgdat)
{
int i;
@@ -1771,9 +2001,15 @@ static void __meminit build_zonelist_cache(pg_data_t *pgdat)
}
}
+
#else /* CONFIG_NUMA */
-static void __meminit build_zonelists(pg_data_t *pgdat)
+static void set_zonelist_order(void)
+{
+ current_zonelist_order = ZONELIST_ORDER_ZONE;
+}
+
+static void build_zonelists(pg_data_t *pgdat)
{
int node, local_node;
enum zone_type i,j;
@@ -1809,7 +2045,7 @@ static void __meminit build_zonelists(pg_data_t *pgdat)
}
/* non-NUMA variant of zonelist performance cache - just NULL zlcache_ptr */
-static void __meminit build_zonelist_cache(pg_data_t *pgdat)
+static void build_zonelist_cache(pg_data_t *pgdat)
{
int i;
@@ -1820,7 +2056,7 @@ static void __meminit build_zonelist_cache(pg_data_t *pgdat)
#endif /* CONFIG_NUMA */
/* return values int ....just for stop_machine_run() */
-static int __meminit __build_all_zonelists(void *dummy)
+static int __build_all_zonelists(void *dummy)
{
int nid;
@@ -1831,8 +2067,10 @@ static int __meminit __build_all_zonelists(void *dummy)
return 0;
}
-void __meminit build_all_zonelists(void)
+void build_all_zonelists(void)
{
+ set_zonelist_order();
+
if (system_state == SYSTEM_BOOTING) {
__build_all_zonelists(NULL);
cpuset_init_current_mems_allowed();
@@ -1843,8 +2081,13 @@ void __meminit build_all_zonelists(void)
/* cpuset refresh routine should be here */
}
vm_total_pages = nr_free_pagecache_pages();
- printk("Built %i zonelists. Total pages: %ld\n",
- num_online_nodes(), vm_total_pages);
+ printk("Built %i zonelists in %s order. Total pages: %ld\n",
+ num_online_nodes(),
+ zonelist_order_name[current_zonelist_order],
+ vm_total_pages);
+#ifdef CONFIG_NUMA
+ printk("Policy zone: %s\n", zone_names[policy_zone]);
+#endif
}
/*
@@ -1953,8 +2196,8 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
}
}
-void zone_init_free_lists(struct pglist_data *pgdat, struct zone *zone,
- unsigned long size)
+static void __meminit zone_init_free_lists(struct pglist_data *pgdat,
+ struct zone *zone, unsigned long size)
{
int order;
for (order = 0; order < MAX_ORDER ; order++) {
@@ -2370,7 +2613,7 @@ void __init push_node_boundaries(unsigned int nid,
}
/* If necessary, push the node boundary out for reserve hotadd */
-static void __init account_node_boundary(unsigned int nid,
+static void __meminit account_node_boundary(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn)
{
printk(KERN_DEBUG "Entering account_node_boundary(%u, %lu, %lu)\n",
@@ -2390,7 +2633,7 @@ static void __init account_node_boundary(unsigned int nid,
void __init push_node_boundaries(unsigned int nid,
unsigned long start_pfn, unsigned long end_pfn) {}
-static void __init account_node_boundary(unsigned int nid,
+static void __meminit account_node_boundary(unsigned int nid,
unsigned long *start_pfn, unsigned long *end_pfn) {}
#endif
@@ -2428,10 +2671,67 @@ void __meminit get_pfn_range_for_nid(unsigned int nid,
}
/*
+ * This finds a zone that can be used for ZONE_MOVABLE pages. The
+ * assumption is made that zones within a node are ordered in monotonic
+ * increasing memory addresses so that the "highest" populated zone is used
+ */
+void __init find_usable_zone_for_movable(void)
+{
+ int zone_index;
+ for (zone_index = MAX_NR_ZONES - 1; zone_index >= 0; zone_index--) {
+ if (zone_index == ZONE_MOVABLE)
+ continue;
+
+ if (arch_zone_highest_possible_pfn[zone_index] >
+ arch_zone_lowest_possible_pfn[zone_index])
+ break;
+ }
+
+ VM_BUG_ON(zone_index == -1);
+ movable_zone = zone_index;
+}
+
+/*
+ * The zone ranges provided by the architecture do not include ZONE_MOVABLE
+ * because it is sized independant of architecture. Unlike the other zones,
+ * the starting point for ZONE_MOVABLE is not fixed. It may be different
+ * in each node depending on the size of each node and how evenly kernelcore
+ * is distributed. This helper function adjusts the zone ranges
+ * provided by the architecture for a given node by using the end of the
+ * highest usable zone for ZONE_MOVABLE. This preserves the assumption that
+ * zones within a node are in order of monotonic increases memory addresses
+ */
+void __meminit adjust_zone_range_for_zone_movable(int nid,
+ unsigned long zone_type,
+ unsigned long node_start_pfn,
+ unsigned long node_end_pfn,
+ unsigned long *zone_start_pfn,
+ unsigned long *zone_end_pfn)
+{
+ /* Only adjust if ZONE_MOVABLE is on this node */
+ if (zone_movable_pfn[nid]) {
+ /* Size ZONE_MOVABLE */
+ if (zone_type == ZONE_MOVABLE) {
+ *zone_start_pfn = zone_movable_pfn[nid];
+ *zone_end_pfn = min(node_end_pfn,
+ arch_zone_highest_possible_pfn[movable_zone]);
+
+ /* Adjust for ZONE_MOVABLE starting within this range */
+ } else if (*zone_start_pfn < zone_movable_pfn[nid] &&
+ *zone_end_pfn > zone_movable_pfn[nid]) {
+ *zone_end_pfn = zone_movable_pfn[nid];
+
+ /* Check if this whole range is within ZONE_MOVABLE */
+ } else if (*zone_start_pfn >= zone_movable_pfn[nid])
+ *zone_start_pfn = *zone_end_pfn;
+ }
+}
+
+/*
* Return the number of pages a zone spans in a node, including holes
* present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node()
*/
-unsigned long __meminit zone_spanned_pages_in_node(int nid,
+static unsigned long __meminit zone_spanned_pages_in_node(int nid,
unsigned long zone_type,
unsigned long *ignored)
{
@@ -2442,6 +2742,9 @@ unsigned long __meminit zone_spanned_pages_in_node(int nid,
get_pfn_range_for_nid(nid, &node_start_pfn, &node_end_pfn);
zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
+ adjust_zone_range_for_zone_movable(nid, zone_type,
+ node_start_pfn, node_end_pfn,
+ &zone_start_pfn, &zone_end_pfn);
/* Check that this node has pages within the zone's required range */
if (zone_end_pfn < node_start_pfn || zone_start_pfn > node_end_pfn)
@@ -2519,7 +2822,7 @@ unsigned long __init absent_pages_in_range(unsigned long start_pfn,
}
/* Return the number of page frames in holes in a zone on a node */
-unsigned long __meminit zone_absent_pages_in_node(int nid,
+static unsigned long __meminit zone_absent_pages_in_node(int nid,
unsigned long zone_type,
unsigned long *ignored)
{
@@ -2532,18 +2835,21 @@ unsigned long __meminit zone_absent_pages_in_node(int nid,
zone_end_pfn = min(arch_zone_highest_possible_pfn[zone_type],
node_end_pfn);
+ adjust_zone_range_for_zone_movable(nid, zone_type,
+ node_start_pfn, node_end_pfn,
+ &zone_start_pfn, &zone_end_pfn);
return __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn);
}
#else
-static inline unsigned long zone_spanned_pages_in_node(int nid,
+static inline unsigned long __meminit zone_spanned_pages_in_node(int nid,
unsigned long zone_type,
unsigned long *zones_size)
{
return zones_size[zone_type];
}
-static inline unsigned long zone_absent_pages_in_node(int nid,
+static inline unsigned long __meminit zone_absent_pages_in_node(int nid,
unsigned long zone_type,
unsigned long *zholes_size)
{
@@ -2909,6 +3215,157 @@ unsigned long __init find_max_pfn_with_active_regions(void)
return max_pfn;
}
+unsigned long __init early_calculate_totalpages(void)
+{
+ int i;
+ unsigned long totalpages = 0;
+
+ for (i = 0; i < nr_nodemap_entries; i++)
+ totalpages += early_node_map[i].end_pfn -
+ early_node_map[i].start_pfn;
+
+ return totalpages;
+}
+
+/*
+ * Find the PFN the Movable zone begins in each node. Kernel memory
+ * is spread evenly between nodes as long as the nodes have enough
+ * memory. When they don't, some nodes will have more kernelcore than
+ * others
+ */
+void __init find_zone_movable_pfns_for_nodes(unsigned long *movable_pfn)
+{
+ int i, nid;
+ unsigned long usable_startpfn;
+ unsigned long kernelcore_node, kernelcore_remaining;
+ int usable_nodes = num_online_nodes();
+
+ /*
+ * If movablecore was specified, calculate what size of
+ * kernelcore that corresponds so that memory usable for
+ * any allocation type is evenly spread. If both kernelcore
+ * and movablecore are specified, then the value of kernelcore
+ * will be used for required_kernelcore if it's greater than
+ * what movablecore would have allowed.
+ */
+ if (required_movablecore) {
+ unsigned long totalpages = early_calculate_totalpages();
+ unsigned long corepages;
+
+ /*
+ * Round-up so that ZONE_MOVABLE is at least as large as what
+ * was requested by the user
+ */
+ required_movablecore =
+ roundup(required_movablecore, MAX_ORDER_NR_PAGES);
+ corepages = totalpages - required_movablecore;
+
+ required_kernelcore = max(required_kernelcore, corepages);
+ }
+
+ /* If kernelcore was not specified, there is no ZONE_MOVABLE */
+ if (!required_kernelcore)
+ return;
+
+ /* usable_startpfn is the lowest possible pfn ZONE_MOVABLE can be at */
+ find_usable_zone_for_movable();
+ usable_startpfn = arch_zone_lowest_possible_pfn[movable_zone];
+
+restart:
+ /* Spread kernelcore memory as evenly as possible throughout nodes */
+ kernelcore_node = required_kernelcore / usable_nodes;
+ for_each_online_node(nid) {
+ /*
+ * Recalculate kernelcore_node if the division per node
+ * now exceeds what is necessary to satisfy the requested
+ * amount of memory for the kernel
+ */
+ if (required_kernelcore < kernelcore_node)
+ kernelcore_node = required_kernelcore / usable_nodes;
+
+ /*
+ * As the map is walked, we track how much memory is usable
+ * by the kernel using kernelcore_remaining. When it is
+ * 0, the rest of the node is usable by ZONE_MOVABLE
+ */
+ kernelcore_remaining = kernelcore_node;
+
+ /* Go through each range of PFNs within this node */
+ for_each_active_range_index_in_nid(i, nid) {
+ unsigned long start_pfn, end_pfn;
+ unsigned long size_pages;
+
+ start_pfn = max(early_node_map[i].start_pfn,
+ zone_movable_pfn[nid]);
+ end_pfn = early_node_map[i].end_pfn;
+ if (start_pfn >= end_pfn)
+ continue;
+
+ /* Account for what is only usable for kernelcore */
+ if (start_pfn < usable_startpfn) {
+ unsigned long kernel_pages;
+ kernel_pages = min(end_pfn, usable_startpfn)
+ - start_pfn;
+
+ kernelcore_remaining -= min(kernel_pages,
+ kernelcore_remaining);
+ required_kernelcore -= min(kernel_pages,
+ required_kernelcore);
+
+ /* Continue if range is now fully accounted */
+ if (end_pfn <= usable_startpfn) {
+
+ /*
+ * Push zone_movable_pfn to the end so
+ * that if we have to rebalance
+ * kernelcore across nodes, we will
+ * not double account here
+ */
+ zone_movable_pfn[nid] = end_pfn;
+ continue;
+ }
+ start_pfn = usable_startpfn;
+ }
+
+ /*
+ * The usable PFN range for ZONE_MOVABLE is from
+ * start_pfn->end_pfn. Calculate size_pages as the
+ * number of pages used as kernelcore
+ */
+ size_pages = end_pfn - start_pfn;
+ if (size_pages > kernelcore_remaining)
+ size_pages = kernelcore_remaining;
+ zone_movable_pfn[nid] = start_pfn + size_pages;
+
+ /*
+ * Some kernelcore has been met, update counts and
+ * break if the kernelcore for this node has been
+ * satisified
+ */
+ required_kernelcore -= min(required_kernelcore,
+ size_pages);
+ kernelcore_remaining -= size_pages;
+ if (!kernelcore_remaining)
+ break;
+ }
+ }
+
+ /*
+ * If there is still required_kernelcore, we do another pass with one
+ * less node in the count. This will push zone_movable_pfn[nid] further
+ * along on the nodes that still have memory until kernelcore is
+ * satisified
+ */
+ usable_nodes--;
+ if (usable_nodes && required_kernelcore > usable_nodes)
+ goto restart;
+
+ /* Align start of ZONE_MOVABLE on all nids to MAX_ORDER_NR_PAGES */
+ for (nid = 0; nid < MAX_NUMNODES; nid++)
+ zone_movable_pfn[nid] =
+ roundup(zone_movable_pfn[nid], MAX_ORDER_NR_PAGES);
+}
+
/**
* free_area_init_nodes - Initialise all pg_data_t and zone data
* @max_zone_pfn: an array of max PFNs for each zone
@@ -2938,19 +3395,37 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();
arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];
for (i = 1; i < MAX_NR_ZONES; i++) {
+ if (i == ZONE_MOVABLE)
+ continue;
arch_zone_lowest_possible_pfn[i] =
arch_zone_highest_possible_pfn[i-1];
arch_zone_highest_possible_pfn[i] =
max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]);
}
+ arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0;
+ arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0;
+
+ /* Find the PFNs that ZONE_MOVABLE begins at in each node */
+ memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn));
+ find_zone_movable_pfns_for_nodes(zone_movable_pfn);
/* Print out the zone ranges */
printk("Zone PFN ranges:\n");
- for (i = 0; i < MAX_NR_ZONES; i++)
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ if (i == ZONE_MOVABLE)
+ continue;
printk(" %-8s %8lu -> %8lu\n",
zone_names[i],
arch_zone_lowest_possible_pfn[i],
arch_zone_highest_possible_pfn[i]);
+ }
+
+ /* Print out the PFNs ZONE_MOVABLE begins at in each node */
+ printk("Movable zone start PFN for each node\n");
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ if (zone_movable_pfn[i])
+ printk(" Node %d: %lu\n", i, zone_movable_pfn[i]);
+ }
/* Print out the early_node_map[] */
printk("early_node_map[%d] active PFN ranges\n", nr_nodemap_entries);
@@ -2967,6 +3442,43 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
find_min_pfn_for_node(nid), NULL);
}
}
+
+static int __init cmdline_parse_core(char *p, unsigned long *core)
+{
+ unsigned long long coremem;
+ if (!p)
+ return -EINVAL;
+
+ coremem = memparse(p, &p);
+ *core = coremem >> PAGE_SHIFT;
+
+ /* Paranoid check that UL is enough for the coremem value */
+ WARN_ON((coremem >> PAGE_SHIFT) > ULONG_MAX);
+
+ return 0;
+}
+
+/*
+ * kernelcore=size sets the amount of memory for use for allocations that
+ * cannot be reclaimed or migrated.
+ */
+static int __init cmdline_parse_kernelcore(char *p)
+{
+ return cmdline_parse_core(p, &required_kernelcore);
+}
+
+/*
+ * movablecore=size sets the amount of memory for use for allocations that
+ * can be reclaimed or migrated.
+ */
+static int __init cmdline_parse_movablecore(char *p)
+{
+ return cmdline_parse_core(p, &required_movablecore);
+}
+
+early_param("kernelcore", cmdline_parse_kernelcore);
+early_param("movablecore", cmdline_parse_movablecore);
+
#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
/**
@@ -3355,13 +3867,28 @@ void *__init alloc_large_system_hash(const char *tablename,
for (order = 0; ((1UL << order) << PAGE_SHIFT) < size; order++)
;
table = (void*) __get_free_pages(GFP_ATOMIC, order);
+ /*
+ * If bucketsize is not a power-of-two, we may free
+ * some pages at the end of hash table.
+ */
+ if (table) {
+ unsigned long alloc_end = (unsigned long)table +
+ (PAGE_SIZE << order);
+ unsigned long used = (unsigned long)table +
+ PAGE_ALIGN(size);
+ split_page(virt_to_page(table), order);
+ while (used < alloc_end) {
+ free_page(used);
+ used += PAGE_SIZE;
+ }
+ }
}
} while (!table && size > PAGE_SIZE && --log2qty);
if (!table)
panic("Failed to allocate %s hash table\n", tablename);
- printk("%s hash table entries: %d (order: %d, %lu bytes)\n",
+ printk(KERN_INFO "%s hash table entries: %d (order: %d, %lu bytes)\n",
tablename,
(1U << log2qty),
ilog2(size) - PAGE_SHIFT,
diff --git a/mm/pdflush.c b/mm/pdflush.c
index 8ce0900dc95c..8f6ee073c0e3 100644
--- a/mm/pdflush.c
+++ b/mm/pdflush.c
@@ -92,6 +92,7 @@ struct pdflush_work {
static int __pdflush(struct pdflush_work *my_work)
{
current->flags |= PF_FLUSHER | PF_SWAPWRITE;
+ set_freezable();
my_work->fn = NULL;
my_work->who = current;
INIT_LIST_HEAD(&my_work->list);
diff --git a/mm/readahead.c b/mm/readahead.c
index 9861e883fe57..39bf45d43320 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -21,8 +21,16 @@ void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
}
EXPORT_SYMBOL(default_unplug_io_fn);
+/*
+ * Convienent macros for min/max read-ahead pages.
+ * Note that MAX_RA_PAGES is rounded down, while MIN_RA_PAGES is rounded up.
+ * The latter is necessary for systems with large page size(i.e. 64k).
+ */
+#define MAX_RA_PAGES (VM_MAX_READAHEAD*1024 / PAGE_CACHE_SIZE)
+#define MIN_RA_PAGES DIV_ROUND_UP(VM_MIN_READAHEAD*1024, PAGE_CACHE_SIZE)
+
struct backing_dev_info default_backing_dev_info = {
- .ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE,
+ .ra_pages = MAX_RA_PAGES,
.state = 0,
.capabilities = BDI_CAP_MAP_COPY,
.unplug_io_fn = default_unplug_io_fn,
@@ -41,82 +49,6 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
}
EXPORT_SYMBOL_GPL(file_ra_state_init);
-/*
- * Return max readahead size for this inode in number-of-pages.
- */
-static inline unsigned long get_max_readahead(struct file_ra_state *ra)
-{
- return ra->ra_pages;
-}
-
-static inline unsigned long get_min_readahead(struct file_ra_state *ra)
-{
- return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE;
-}
-
-static inline void reset_ahead_window(struct file_ra_state *ra)
-{
- /*
- * ... but preserve ahead_start + ahead_size value,
- * see 'recheck:' label in page_cache_readahead().
- * Note: We never use ->ahead_size as rvalue without
- * checking ->ahead_start != 0 first.
- */
- ra->ahead_size += ra->ahead_start;
- ra->ahead_start = 0;
-}
-
-static inline void ra_off(struct file_ra_state *ra)
-{
- ra->start = 0;
- ra->flags = 0;
- ra->size = 0;
- reset_ahead_window(ra);
- return;
-}
-
-/*
- * Set the initial window size, round to next power of 2 and square
- * for small size, x 4 for medium, and x 2 for large
- * for 128k (32 page) max ra
- * 1-8 page = 32k initial, > 8 page = 128k initial
- */
-static unsigned long get_init_ra_size(unsigned long size, unsigned long max)
-{
- unsigned long newsize = roundup_pow_of_two(size);
-
- if (newsize <= max / 32)
- newsize = newsize * 4;
- else if (newsize <= max / 4)
- newsize = newsize * 2;
- else
- newsize = max;
- return newsize;
-}
-
-/*
- * Set the new window size, this is called only when I/O is to be submitted,
- * not for each call to readahead. If a cache miss occured, reduce next I/O
- * size, else increase depending on how close to max we are.
- */
-static inline unsigned long get_next_ra_size(struct file_ra_state *ra)
-{
- unsigned long max = get_max_readahead(ra);
- unsigned long min = get_min_readahead(ra);
- unsigned long cur = ra->size;
- unsigned long newsize;
-
- if (ra->flags & RA_FLAG_MISS) {
- ra->flags &= ~RA_FLAG_MISS;
- newsize = max((cur - 2), min);
- } else if (cur < max / 16) {
- newsize = 4 * cur;
- } else {
- newsize = 2 * cur;
- }
- return min(newsize, max);
-}
-
#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
/**
@@ -193,66 +125,6 @@ out:
}
/*
- * Readahead design.
- *
- * The fields in struct file_ra_state represent the most-recently-executed
- * readahead attempt:
- *
- * start: Page index at which we started the readahead
- * size: Number of pages in that read
- * Together, these form the "current window".
- * Together, start and size represent the `readahead window'.
- * prev_index: The page which the readahead algorithm most-recently inspected.
- * It is mainly used to detect sequential file reading.
- * If page_cache_readahead sees that it is again being called for
- * a page which it just looked at, it can return immediately without
- * making any state changes.
- * offset: Offset in the prev_index where the last read ended - used for
- * detection of sequential file reading.
- * ahead_start,
- * ahead_size: Together, these form the "ahead window".
- * ra_pages: The externally controlled max readahead for this fd.
- *
- * When readahead is in the off state (size == 0), readahead is disabled.
- * In this state, prev_index is used to detect the resumption of sequential I/O.
- *
- * The readahead code manages two windows - the "current" and the "ahead"
- * windows. The intent is that while the application is walking the pages
- * in the current window, I/O is underway on the ahead window. When the
- * current window is fully traversed, it is replaced by the ahead window
- * and the ahead window is invalidated. When this copying happens, the
- * new current window's pages are probably still locked. So
- * we submit a new batch of I/O immediately, creating a new ahead window.
- *
- * So:
- *
- * ----|----------------|----------------|-----
- * ^start ^start+size
- * ^ahead_start ^ahead_start+ahead_size
- *
- * ^ When this page is read, we submit I/O for the
- * ahead window.
- *
- * A `readahead hit' occurs when a read request is made against a page which is
- * the next sequential page. Ahead window calculations are done only when it
- * is time to submit a new IO. The code ramps up the size agressively at first,
- * but slow down as it approaches max_readhead.
- *
- * Any seek/ramdom IO will result in readahead being turned off. It will resume
- * at the first sequential access.
- *
- * There is a special-case: if the first page which the application tries to
- * read happens to be the first page of the file, it is assumed that a linear
- * read is about to happen and the window is immediately set to the initial size
- * based on I/O request size and the max_readahead.
- *
- * This function is to be called for every read request, rather than when
- * it is time to perform readahead. It is called only once for the entire I/O
- * regardless of size unless readahead is unable to start enough I/O to satisfy
- * the request (I/O request > max_readahead).
- */
-
-/*
* do_page_cache_readahead actually reads a chunk of disk. It allocates all
* the pages first, then submits them all for I/O. This avoids the very bad
* behaviour which would occur if page allocations are causing VM writeback.
@@ -265,7 +137,8 @@ out:
*/
static int
__do_page_cache_readahead(struct address_space *mapping, struct file *filp,
- pgoff_t offset, unsigned long nr_to_read)
+ pgoff_t offset, unsigned long nr_to_read,
+ unsigned long lookahead_size)
{
struct inode *inode = mapping->host;
struct page *page;
@@ -278,7 +151,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
if (isize == 0)
goto out;
- end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
+ end_index = ((isize - 1) >> PAGE_CACHE_SHIFT);
/*
* Preallocate as many pages as we will need.
@@ -286,7 +159,7 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
read_lock_irq(&mapping->tree_lock);
for (page_idx = 0; page_idx < nr_to_read; page_idx++) {
pgoff_t page_offset = offset + page_idx;
-
+
if (page_offset > end_index)
break;
@@ -301,6 +174,8 @@ __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
break;
page->index = page_offset;
list_add(&page->lru, &page_pool);
+ if (page_idx == nr_to_read - lookahead_size)
+ SetPageReadahead(page);
ret++;
}
read_unlock_irq(&mapping->tree_lock);
@@ -337,7 +212,7 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
if (this_chunk > nr_to_read)
this_chunk = nr_to_read;
err = __do_page_cache_readahead(mapping, filp,
- offset, this_chunk);
+ offset, this_chunk, 0);
if (err < 0) {
ret = err;
break;
@@ -350,28 +225,6 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
}
/*
- * Check how effective readahead is being. If the amount of started IO is
- * less than expected then the file is partly or fully in pagecache and
- * readahead isn't helping.
- *
- */
-static inline int check_ra_success(struct file_ra_state *ra,
- unsigned long nr_to_read, unsigned long actual)
-{
- if (actual == 0) {
- ra->cache_hit += nr_to_read;
- if (ra->cache_hit >= VM_MAX_CACHE_HIT) {
- ra_off(ra);
- ra->flags |= RA_FLAG_INCACHE;
- return 0;
- }
- } else {
- ra->cache_hit=0;
- }
- return 1;
-}
-
-/*
* This version skips the IO if the queue is read-congested, and will tell the
* block layer to abandon the readahead if request allocation would block.
*
@@ -384,200 +237,237 @@ int do_page_cache_readahead(struct address_space *mapping, struct file *filp,
if (bdi_read_congested(mapping->backing_dev_info))
return -1;
- return __do_page_cache_readahead(mapping, filp, offset, nr_to_read);
+ return __do_page_cache_readahead(mapping, filp, offset, nr_to_read, 0);
}
/*
- * Read 'nr_to_read' pages starting at page 'offset'. If the flag 'block'
- * is set wait till the read completes. Otherwise attempt to read without
- * blocking.
- * Returns 1 meaning 'success' if read is successful without switching off
- * readahead mode. Otherwise return failure.
+ * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
+ * sensible upper limit.
*/
-static int
-blockable_page_cache_readahead(struct address_space *mapping, struct file *filp,
- pgoff_t offset, unsigned long nr_to_read,
- struct file_ra_state *ra, int block)
+unsigned long max_sane_readahead(unsigned long nr)
+{
+ return min(nr, (node_page_state(numa_node_id(), NR_INACTIVE)
+ + node_page_state(numa_node_id(), NR_FREE_PAGES)) / 2);
+}
+
+/*
+ * Submit IO for the read-ahead request in file_ra_state.
+ */
+static unsigned long ra_submit(struct file_ra_state *ra,
+ struct address_space *mapping, struct file *filp)
{
int actual;
- if (!block && bdi_read_congested(mapping->backing_dev_info))
- return 0;
+ actual = __do_page_cache_readahead(mapping, filp,
+ ra->start, ra->size, ra->async_size);
+
+ return actual;
+}
- actual = __do_page_cache_readahead(mapping, filp, offset, nr_to_read);
+/*
+ * Set the initial window size, round to next power of 2 and square
+ * for small size, x 4 for medium, and x 2 for large
+ * for 128k (32 page) max ra
+ * 1-8 page = 32k initial, > 8 page = 128k initial
+ */
+static unsigned long get_init_ra_size(unsigned long size, unsigned long max)
+{
+ unsigned long newsize = roundup_pow_of_two(size);
- return check_ra_success(ra, nr_to_read, actual);
+ if (newsize <= max / 32)
+ newsize = newsize * 4;
+ else if (newsize <= max / 4)
+ newsize = newsize * 2;
+ else
+ newsize = max;
+
+ return newsize;
}
-static int make_ahead_window(struct address_space *mapping, struct file *filp,
- struct file_ra_state *ra, int force)
+/*
+ * Get the previous window size, ramp it up, and
+ * return it as the new window size.
+ */
+static unsigned long get_next_ra_size(struct file_ra_state *ra,
+ unsigned long max)
{
- int block, ret;
-
- ra->ahead_size = get_next_ra_size(ra);
- ra->ahead_start = ra->start + ra->size;
-
- block = force || (ra->prev_index >= ra->ahead_start);
- ret = blockable_page_cache_readahead(mapping, filp,
- ra->ahead_start, ra->ahead_size, ra, block);
-
- if (!ret && !force) {
- /* A read failure in blocking mode, implies pages are
- * all cached. So we can safely assume we have taken
- * care of all the pages requested in this call.
- * A read failure in non-blocking mode, implies we are
- * reading more pages than requested in this call. So
- * we safely assume we have taken care of all the pages
- * requested in this call.
- *
- * Just reset the ahead window in case we failed due to
- * congestion. The ahead window will any way be closed
- * in case we failed due to excessive page cache hits.
- */
- reset_ahead_window(ra);
- }
+ unsigned long cur = ra->size;
+ unsigned long newsize;
- return ret;
+ if (cur < max / 16)
+ newsize = 4 * cur;
+ else
+ newsize = 2 * cur;
+
+ return min(newsize, max);
}
-/**
- * page_cache_readahead - generic adaptive readahead
- * @mapping: address_space which holds the pagecache and I/O vectors
- * @ra: file_ra_state which holds the readahead state
- * @filp: passed on to ->readpage() and ->readpages()
- * @offset: start offset into @mapping, in PAGE_CACHE_SIZE units
- * @req_size: hint: total size of the read which the caller is performing in
- * PAGE_CACHE_SIZE units
+/*
+ * On-demand readahead design.
+ *
+ * The fields in struct file_ra_state represent the most-recently-executed
+ * readahead attempt:
+ *
+ * |<----- async_size ---------|
+ * |------------------- size -------------------->|
+ * |==================#===========================|
+ * ^start ^page marked with PG_readahead
*
- * page_cache_readahead() is the main function. If performs the adaptive
- * readahead window size management and submits the readahead I/O.
+ * To overlap application thinking time and disk I/O time, we do
+ * `readahead pipelining': Do not wait until the application consumed all
+ * readahead pages and stalled on the missing page at readahead_index;
+ * Instead, submit an asynchronous readahead I/O as soon as there are
+ * only async_size pages left in the readahead window. Normally async_size
+ * will be equal to size, for maximum pipelining.
*
- * Note that @filp is purely used for passing on to the ->readpage[s]()
- * handler: it may refer to a different file from @mapping (so we may not use
- * @filp->f_mapping or @filp->f_path.dentry->d_inode here).
- * Also, @ra may not be equal to &@filp->f_ra.
+ * In interleaved sequential reads, concurrent streams on the same fd can
+ * be invalidating each other's readahead state. So we flag the new readahead
+ * page at (start+size-async_size) with PG_readahead, and use it as readahead
+ * indicator. The flag won't be set on already cached pages, to avoid the
+ * readahead-for-nothing fuss, saving pointless page cache lookups.
+ *
+ * prev_index tracks the last visited page in the _previous_ read request.
+ * It should be maintained by the caller, and will be used for detecting
+ * small random reads. Note that the readahead algorithm checks loosely
+ * for sequential patterns. Hence interleaved reads might be served as
+ * sequential ones.
+ *
+ * There is a special-case: if the first page which the application tries to
+ * read happens to be the first page of the file, it is assumed that a linear
+ * read is about to happen and the window is immediately set to the initial size
+ * based on I/O request size and the max_readahead.
*
+ * The code ramps up the readahead size aggressively at first, but slow down as
+ * it approaches max_readhead.
+ */
+
+/*
+ * A minimal readahead algorithm for trivial sequential/random reads.
*/
-unsigned long
-page_cache_readahead(struct address_space *mapping, struct file_ra_state *ra,
- struct file *filp, pgoff_t offset, unsigned long req_size)
+static unsigned long
+ondemand_readahead(struct address_space *mapping,
+ struct file_ra_state *ra, struct file *filp,
+ bool hit_readahead_marker, pgoff_t offset,
+ unsigned long req_size)
{
- unsigned long max, newsize;
+ unsigned long max; /* max readahead pages */
int sequential;
- /*
- * We avoid doing extra work and bogusly perturbing the readahead
- * window expansion logic.
- */
- if (offset == ra->prev_index && --req_size)
- ++offset;
-
- /* Note that prev_index == -1 if it is a first read */
- sequential = (offset == ra->prev_index + 1);
- ra->prev_index = offset;
- ra->prev_offset = 0;
-
- max = get_max_readahead(ra);
- newsize = min(req_size, max);
-
- /* No readahead or sub-page sized read or file already in cache */
- if (newsize == 0 || (ra->flags & RA_FLAG_INCACHE))
- goto out;
-
- ra->prev_index += newsize - 1;
+ max = ra->ra_pages;
+ sequential = (offset - ra->prev_index <= 1UL) || (req_size > max);
/*
- * Special case - first read at start of file. We'll assume it's
- * a whole-file read and grow the window fast. Or detect first
- * sequential access
+ * It's the expected callback offset, assume sequential access.
+ * Ramp up sizes, and push forward the readahead window.
*/
- if (sequential && ra->size == 0) {
- ra->size = get_init_ra_size(newsize, max);
- ra->start = offset;
- if (!blockable_page_cache_readahead(mapping, filp, offset,
- ra->size, ra, 1))
- goto out;
-
- /*
- * If the request size is larger than our max readahead, we
- * at least want to be sure that we get 2 IOs in flight and
- * we know that we will definitly need the new I/O.
- * once we do this, subsequent calls should be able to overlap
- * IOs,* thus preventing stalls. so issue the ahead window
- * immediately.
- */
- if (req_size >= max)
- make_ahead_window(mapping, filp, ra, 1);
-
- goto out;
+ if (offset && (offset == (ra->start + ra->size - ra->async_size) ||
+ offset == (ra->start + ra->size))) {
+ ra->start += ra->size;
+ ra->size = get_next_ra_size(ra, max);
+ ra->async_size = ra->size;
+ goto readit;
}
/*
- * Now handle the random case:
- * partial page reads and first access were handled above,
- * so this must be the next page otherwise it is random
+ * Standalone, small read.
+ * Read as is, and do not pollute the readahead state.
*/
- if (!sequential) {
- ra_off(ra);
- blockable_page_cache_readahead(mapping, filp, offset,
- newsize, ra, 1);
- goto out;
+ if (!hit_readahead_marker && !sequential) {
+ return __do_page_cache_readahead(mapping, filp,
+ offset, req_size, 0);
}
/*
- * If we get here we are doing sequential IO and this was not the first
- * occurence (ie we have an existing window)
+ * It may be one of
+ * - first read on start of file
+ * - sequential cache miss
+ * - oversize random read
+ * Start readahead for it.
*/
- if (ra->ahead_start == 0) { /* no ahead window yet */
- if (!make_ahead_window(mapping, filp, ra, 0))
- goto recheck;
- }
+ ra->start = offset;
+ ra->size = get_init_ra_size(req_size, max);
+ ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size;
/*
- * Already have an ahead window, check if we crossed into it.
- * If so, shift windows and issue a new ahead window.
- * Only return the #pages that are in the current window, so that
- * we get called back on the first page of the ahead window which
- * will allow us to submit more IO.
+ * Hit on a marked page without valid readahead state.
+ * E.g. interleaved reads.
+ * Not knowing its readahead pos/size, bet on the minimal possible one.
*/
- if (ra->prev_index >= ra->ahead_start) {
- ra->start = ra->ahead_start;
- ra->size = ra->ahead_size;
- make_ahead_window(mapping, filp, ra, 0);
-recheck:
- /* prev_index shouldn't overrun the ahead window */
- ra->prev_index = min(ra->prev_index,
- ra->ahead_start + ra->ahead_size - 1);
+ if (hit_readahead_marker) {
+ ra->start++;
+ ra->size = get_next_ra_size(ra, max);
}
-out:
- return ra->prev_index + 1;
+readit:
+ return ra_submit(ra, mapping, filp);
}
-EXPORT_SYMBOL_GPL(page_cache_readahead);
-/*
- * handle_ra_miss() is called when it is known that a page which should have
- * been present in the pagecache (we just did some readahead there) was in fact
- * not found. This will happen if it was evicted by the VM (readahead
- * thrashing)
+/**
+ * page_cache_sync_readahead - generic file readahead
+ * @mapping: address_space which holds the pagecache and I/O vectors
+ * @ra: file_ra_state which holds the readahead state
+ * @filp: passed on to ->readpage() and ->readpages()
+ * @offset: start offset into @mapping, in pagecache page-sized units
+ * @req_size: hint: total size of the read which the caller is performing in
+ * pagecache pages
*
- * Turn on the cache miss flag in the RA struct, this will cause the RA code
- * to reduce the RA size on the next read.
+ * page_cache_sync_readahead() should be called when a cache miss happened:
+ * it will submit the read. The readahead logic may decide to piggyback more
+ * pages onto the read request if access patterns suggest it will improve
+ * performance.
*/
-void handle_ra_miss(struct address_space *mapping,
- struct file_ra_state *ra, pgoff_t offset)
+void page_cache_sync_readahead(struct address_space *mapping,
+ struct file_ra_state *ra, struct file *filp,
+ pgoff_t offset, unsigned long req_size)
{
- ra->flags |= RA_FLAG_MISS;
- ra->flags &= ~RA_FLAG_INCACHE;
- ra->cache_hit = 0;
+ /* no read-ahead */
+ if (!ra->ra_pages)
+ return;
+
+ /* do read-ahead */
+ ondemand_readahead(mapping, ra, filp, false, offset, req_size);
}
+EXPORT_SYMBOL_GPL(page_cache_sync_readahead);
-/*
- * Given a desired number of PAGE_CACHE_SIZE readahead pages, return a
- * sensible upper limit.
- */
-unsigned long max_sane_readahead(unsigned long nr)
+/**
+ * page_cache_async_readahead - file readahead for marked pages
+ * @mapping: address_space which holds the pagecache and I/O vectors
+ * @ra: file_ra_state which holds the readahead state
+ * @filp: passed on to ->readpage() and ->readpages()
+ * @page: the page at @offset which has the PG_readahead flag set
+ * @offset: start offset into @mapping, in pagecache page-sized units
+ * @req_size: hint: total size of the read which the caller is performing in
+ * pagecache pages
+ *
+ * page_cache_async_ondemand() should be called when a page is used which
+ * has the PG_readahead flag: this is a marker to suggest that the application
+ * has used up enough of the readahead window that we should start pulling in
+ * more pages. */
+void
+page_cache_async_readahead(struct address_space *mapping,
+ struct file_ra_state *ra, struct file *filp,
+ struct page *page, pgoff_t offset,
+ unsigned long req_size)
{
- return min(nr, (node_page_state(numa_node_id(), NR_INACTIVE)
- + node_page_state(numa_node_id(), NR_FREE_PAGES)) / 2);
+ /* no read-ahead */
+ if (!ra->ra_pages)
+ return;
+
+ /*
+ * Same bit is used for PG_readahead and PG_reclaim.
+ */
+ if (PageWriteback(page))
+ return;
+
+ ClearPageReadahead(page);
+
+ /*
+ * Defer asynchronous read-ahead on IO congestion.
+ */
+ if (bdi_read_congested(mapping->backing_dev_info))
+ return;
+
+ /* do read-ahead */
+ ondemand_readahead(mapping, ra, filp, true, offset, req_size);
}
+EXPORT_SYMBOL_GPL(page_cache_async_readahead);
diff --git a/mm/rmap.c b/mm/rmap.c
index 61e492597a0b..41ac39749ef4 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -149,7 +149,7 @@ static void anon_vma_ctor(void *data, struct kmem_cache *cachep,
void __init anon_vma_init(void)
{
anon_vma_cachep = kmem_cache_create("anon_vma", sizeof(struct anon_vma),
- 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor, NULL);
+ 0, SLAB_DESTROY_BY_RCU|SLAB_PANIC, anon_vma_ctor);
}
/*
@@ -621,8 +621,10 @@ void page_remove_rmap(struct page *page, struct vm_area_struct *vma)
printk (KERN_EMERG " page->count = %x\n", page_count(page));
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)
+ 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)
print_symbol (KERN_EMERG " vma->vm_file->f_op->mmap = %s\n", (unsigned long)vma->vm_file->f_op->mmap);
BUG();
diff --git a/mm/shmem.c b/mm/shmem.c
index 0493e4d0bcaa..fcd19d323f9f 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -27,6 +27,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/xattr.h>
+#include <linux/exportfs.h>
#include <linux/generic_acl.h>
#include <linux/mm.h>
#include <linux/mman.h>
@@ -82,6 +83,7 @@ enum sgp_type {
SGP_READ, /* don't exceed i_size, don't allocate page */
SGP_CACHE, /* don't exceed i_size, may allocate page */
SGP_WRITE, /* may exceed i_size, may allocate page */
+ SGP_FAULT, /* same as SGP_CACHE, return with page locked */
};
static int shmem_getpage(struct inode *inode, unsigned long idx,
@@ -93,8 +95,11 @@ static inline struct page *shmem_dir_alloc(gfp_t gfp_mask)
* The above definition of ENTRIES_PER_PAGE, and the use of
* BLOCKS_PER_PAGE on indirect pages, assume PAGE_CACHE_SIZE:
* might be reconsidered if it ever diverges from PAGE_SIZE.
+ *
+ * __GFP_MOVABLE is masked out as swap vectors cannot move
*/
- return alloc_pages(gfp_mask, PAGE_CACHE_SHIFT-PAGE_SHIFT);
+ return alloc_pages((gfp_mask & ~__GFP_MOVABLE) | __GFP_ZERO,
+ PAGE_CACHE_SHIFT-PAGE_SHIFT);
}
static inline void shmem_dir_free(struct page *page)
@@ -372,7 +377,7 @@ static swp_entry_t *shmem_swp_alloc(struct shmem_inode_info *info, unsigned long
}
spin_unlock(&info->lock);
- page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO);
+ page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping));
if (page)
set_page_private(page, 0);
spin_lock(&info->lock);
@@ -1096,6 +1101,10 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,
if (idx >= SHMEM_MAX_INDEX)
return -EFBIG;
+
+ if (type)
+ *type = 0;
+
/*
* Normally, filepage is NULL on entry, and either found
* uptodate immediately, or allocated and zeroed, or read
@@ -1129,9 +1138,9 @@ repeat:
if (!swappage) {
shmem_swp_unmap(entry);
/* here we actually do the io */
- if (type && *type == VM_FAULT_MINOR) {
+ if (type && !(*type & VM_FAULT_MAJOR)) {
__count_vm_event(PGMAJFAULT);
- *type = VM_FAULT_MAJOR;
+ *type |= VM_FAULT_MAJOR;
}
spin_unlock(&info->lock);
swappage = shmem_swapin(info, swap, idx);
@@ -1285,8 +1294,10 @@ repeat:
}
done:
if (*pagep != filepage) {
- unlock_page(filepage);
*pagep = filepage;
+ if (sgp != SGP_FAULT)
+ unlock_page(filepage);
+
}
return 0;
@@ -1298,72 +1309,21 @@ failed:
return error;
}
-static struct page *shmem_nopage(struct vm_area_struct *vma,
- unsigned long address, int *type)
+static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
- struct page *page = NULL;
- unsigned long idx;
int error;
+ int ret;
- idx = (address - vma->vm_start) >> PAGE_SHIFT;
- idx += vma->vm_pgoff;
- idx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
- if (((loff_t) idx << PAGE_CACHE_SHIFT) >= i_size_read(inode))
- return NOPAGE_SIGBUS;
+ if (((loff_t)vmf->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode))
+ return VM_FAULT_SIGBUS;
- error = shmem_getpage(inode, idx, &page, SGP_CACHE, type);
+ error = shmem_getpage(inode, vmf->pgoff, &vmf->page, SGP_FAULT, &ret);
if (error)
- return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS;
-
- mark_page_accessed(page);
- return page;
-}
-
-static int shmem_populate(struct vm_area_struct *vma,
- unsigned long addr, unsigned long len,
- pgprot_t prot, unsigned long pgoff, int nonblock)
-{
- struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
- struct mm_struct *mm = vma->vm_mm;
- enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE;
- unsigned long size;
+ return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS);
- size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
- if (pgoff >= size || pgoff + (len >> PAGE_SHIFT) > size)
- return -EINVAL;
-
- while ((long) len > 0) {
- struct page *page = NULL;
- int err;
- /*
- * Will need changing if PAGE_CACHE_SIZE != PAGE_SIZE
- */
- err = shmem_getpage(inode, pgoff, &page, sgp, NULL);
- if (err)
- return err;
- /* Page may still be null, but only if nonblock was set. */
- if (page) {
- mark_page_accessed(page);
- err = install_page(mm, vma, addr, page, prot);
- if (err) {
- page_cache_release(page);
- return err;
- }
- } else if (vma->vm_flags & VM_NONLINEAR) {
- /* No page was found just because we can't read it in
- * now (being here implies nonblock != 0), but the page
- * may exist, so set the PTE to fault it in later. */
- err = install_file_pte(mm, vma, addr, pgoff, prot);
- if (err)
- return err;
- }
-
- len -= PAGE_SIZE;
- addr += PAGE_SIZE;
- pgoff++;
- }
- return 0;
+ mark_page_accessed(vmf->page);
+ return ret | VM_FAULT_LOCKED;
}
#ifdef CONFIG_NUMA
@@ -1410,6 +1370,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
{
file_accessed(file);
vma->vm_ops = &shmem_vm_ops;
+ vma->vm_flags |= VM_CAN_NONLINEAR;
return 0;
}
@@ -2361,7 +2322,7 @@ static int init_inodecache(void)
{
shmem_inode_cachep = kmem_cache_create("shmem_inode_cache",
sizeof(struct shmem_inode_info),
- 0, 0, init_once, NULL);
+ 0, 0, init_once);
if (shmem_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -2455,8 +2416,7 @@ static const struct super_operations shmem_ops = {
};
static struct vm_operations_struct shmem_vm_ops = {
- .nopage = shmem_nopage,
- .populate = shmem_populate,
+ .fault = shmem_fault,
#ifdef CONFIG_NUMA
.set_policy = shmem_set_policy,
.get_policy = shmem_get_policy,
diff --git a/mm/slab.c b/mm/slab.c
index b344e6707128..bde271c001ba 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -775,6 +775,9 @@ static inline struct kmem_cache *__find_general_cachep(size_t size,
*/
BUG_ON(malloc_sizes[INDEX_AC].cs_cachep == NULL);
#endif
+ if (!size)
+ return ZERO_SIZE_PTR;
+
while (size > csizep->cs_size)
csizep++;
@@ -929,7 +932,7 @@ static void next_reap_node(void)
* the CPUs getting into lockstep and contending for the global cache chain
* lock.
*/
-static void __devinit start_cpu_timer(int cpu)
+static void __cpuinit start_cpu_timer(int cpu)
{
struct delayed_work *reap_work = &per_cpu(reap_work, cpu);
@@ -1160,7 +1163,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,
struct kmem_cache *cachep;
struct kmem_list3 *l3 = NULL;
int node = cpu_to_node(cpu);
- int memsize = sizeof(struct kmem_list3);
+ const int memsize = sizeof(struct kmem_list3);
switch (action) {
case CPU_LOCK_ACQUIRE:
@@ -1481,7 +1484,7 @@ void __init kmem_cache_init(void)
sizes[INDEX_AC].cs_size,
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_PANIC,
- NULL, NULL);
+ NULL);
if (INDEX_AC != INDEX_L3) {
sizes[INDEX_L3].cs_cachep =
@@ -1489,7 +1492,7 @@ void __init kmem_cache_init(void)
sizes[INDEX_L3].cs_size,
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_PANIC,
- NULL, NULL);
+ NULL);
}
slab_early_init = 0;
@@ -1507,7 +1510,7 @@ void __init kmem_cache_init(void)
sizes->cs_size,
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_PANIC,
- NULL, NULL);
+ NULL);
}
#ifdef CONFIG_ZONE_DMA
sizes->cs_dmacachep = kmem_cache_create(
@@ -1516,7 +1519,7 @@ void __init kmem_cache_init(void)
ARCH_KMALLOC_MINALIGN,
ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA|
SLAB_PANIC,
- NULL, NULL);
+ NULL);
#endif
sizes++;
names++;
@@ -2098,12 +2101,10 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep)
* @align: The required alignment for the objects.
* @flags: SLAB flags
* @ctor: A constructor for the objects.
- * @dtor: A destructor for the objects (not implemented anymore).
*
* Returns a ptr to the cache on success, NULL on failure.
* Cannot be called within a int, but can be interrupted.
- * The @ctor is run when new pages are allocated by the cache
- * and the @dtor is run before the pages are handed back.
+ * The @ctor is run when new pages are allocated by the cache.
*
* @name must be valid until the cache is destroyed. This implies that
* the module calling this has to destroy the cache before getting unloaded.
@@ -2123,8 +2124,7 @@ static int __init_refok setup_cpu_cache(struct kmem_cache *cachep)
struct kmem_cache *
kmem_cache_create (const char *name, size_t size, size_t align,
unsigned long flags,
- void (*ctor)(void*, struct kmem_cache *, unsigned long),
- void (*dtor)(void*, struct kmem_cache *, unsigned long))
+ void (*ctor)(void*, struct kmem_cache *, unsigned long))
{
size_t left_over, slab_size, ralign;
struct kmem_cache *cachep = NULL, *pc;
@@ -2133,7 +2133,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
* Sanity checks... these are all serious usage bugs.
*/
if (!name || in_interrupt() || (size < BYTES_PER_WORD) ||
- size > KMALLOC_MAX_SIZE || dtor) {
+ size > KMALLOC_MAX_SIZE) {
printk(KERN_ERR "%s: Early error in slab %s\n", __FUNCTION__,
name);
BUG();
@@ -2351,7 +2351,7 @@ kmem_cache_create (const char *name, size_t size, size_t align,
* this should not happen at all.
* But leave a BUG_ON for some lucky dude.
*/
- BUG_ON(!cachep->slabp_cache);
+ BUG_ON(ZERO_OR_NULL_PTR(cachep->slabp_cache));
}
cachep->ctor = ctor;
cachep->name = name;
@@ -2743,7 +2743,7 @@ static int cache_grow(struct kmem_cache *cachep,
* Be lazy and only check for valid flags here, keeping it out of the
* critical path in kmem_cache_alloc().
*/
- BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK));
+ BUG_ON(flags & ~(GFP_DMA | __GFP_ZERO | GFP_LEVEL_MASK));
local_flags = (flags & GFP_LEVEL_MASK);
/* Take the l3 list lock to change the colour_next on this node */
@@ -3389,6 +3389,9 @@ __cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int nodeid,
local_irq_restore(save_flags);
ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller);
+ if (unlikely((flags & __GFP_ZERO) && ptr))
+ memset(ptr, 0, obj_size(cachep));
+
return ptr;
}
@@ -3440,6 +3443,9 @@ __cache_alloc(struct kmem_cache *cachep, gfp_t flags, void *caller)
objp = cache_alloc_debugcheck_after(cachep, flags, objp, caller);
prefetchw(objp);
+ if (unlikely((flags & __GFP_ZERO) && objp))
+ memset(objp, 0, obj_size(cachep));
+
return objp;
}
@@ -3581,23 +3587,6 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
EXPORT_SYMBOL(kmem_cache_alloc);
/**
- * kmem_cache_zalloc - Allocate an object. The memory is set to zero.
- * @cache: The cache to allocate from.
- * @flags: See kmalloc().
- *
- * Allocate an object from this cache and set the allocated memory to zero.
- * The flags are only relevant if the cache has no available objects.
- */
-void *kmem_cache_zalloc(struct kmem_cache *cache, gfp_t flags)
-{
- void *ret = __cache_alloc(cache, flags, __builtin_return_address(0));
- if (ret)
- memset(ret, 0, obj_size(cache));
- return ret;
-}
-EXPORT_SYMBOL(kmem_cache_zalloc);
-
-/**
* kmem_ptr_validate - check if an untrusted pointer might
* be a slab entry.
* @cachep: the cache we're checking against
@@ -3653,8 +3642,8 @@ __do_kmalloc_node(size_t size, gfp_t flags, int node, void *caller)
struct kmem_cache *cachep;
cachep = kmem_find_general_cachep(size, flags);
- if (unlikely(cachep == NULL))
- return NULL;
+ if (unlikely(ZERO_OR_NULL_PTR(cachep)))
+ return cachep;
return kmem_cache_alloc_node(cachep, flags, node);
}
@@ -3698,8 +3687,8 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
* functions.
*/
cachep = __find_general_cachep(size, flags);
- if (unlikely(cachep == NULL))
- return NULL;
+ if (unlikely(ZERO_OR_NULL_PTR(cachep)))
+ return cachep;
return __cache_alloc(cachep, flags, caller);
}
@@ -3726,52 +3715,6 @@ EXPORT_SYMBOL(__kmalloc);
#endif
/**
- * krealloc - reallocate memory. The contents will remain unchanged.
- * @p: object to reallocate memory for.
- * @new_size: how many bytes of memory are required.
- * @flags: the type of memory to allocate.
- *
- * The contents of the object pointed to are preserved up to the
- * lesser of the new and old sizes. If @p is %NULL, krealloc()
- * behaves exactly like kmalloc(). If @size is 0 and @p is not a
- * %NULL pointer, the object pointed to is freed.
- */
-void *krealloc(const void *p, size_t new_size, gfp_t flags)
-{
- struct kmem_cache *cache, *new_cache;
- void *ret;
-
- if (unlikely(!p))
- return kmalloc_track_caller(new_size, flags);
-
- if (unlikely(!new_size)) {
- kfree(p);
- return NULL;
- }
-
- cache = virt_to_cache(p);
- new_cache = __find_general_cachep(new_size, flags);
-
- /*
- * If new size fits in the current cache, bail out.
- */
- if (likely(cache == new_cache))
- return (void *)p;
-
- /*
- * We are on the slow-path here so do not use __cache_alloc
- * because it bloats kernel text.
- */
- ret = kmalloc_track_caller(new_size, flags);
- if (ret) {
- memcpy(ret, p, min(new_size, ksize(p)));
- kfree(p);
- }
- return ret;
-}
-EXPORT_SYMBOL(krealloc);
-
-/**
* kmem_cache_free - Deallocate an object
* @cachep: The cache the allocation was from.
* @objp: The previously allocated object.
@@ -3806,7 +3749,7 @@ void kfree(const void *objp)
struct kmem_cache *c;
unsigned long flags;
- if (unlikely(!objp))
+ if (unlikely(ZERO_OR_NULL_PTR(objp)))
return;
local_irq_save(flags);
kfree_debugcheck(objp);
@@ -4157,26 +4100,17 @@ static void print_slabinfo_header(struct seq_file *m)
static void *s_start(struct seq_file *m, loff_t *pos)
{
loff_t n = *pos;
- struct list_head *p;
mutex_lock(&cache_chain_mutex);
if (!n)
print_slabinfo_header(m);
- p = cache_chain.next;
- while (n--) {
- p = p->next;
- if (p == &cache_chain)
- return NULL;
- }
- return list_entry(p, struct kmem_cache, next);
+
+ return seq_list_start(&cache_chain, *pos);
}
static void *s_next(struct seq_file *m, void *p, loff_t *pos)
{
- struct kmem_cache *cachep = p;
- ++*pos;
- return cachep->next.next == &cache_chain ?
- NULL : list_entry(cachep->next.next, struct kmem_cache, next);
+ return seq_list_next(p, &cache_chain, pos);
}
static void s_stop(struct seq_file *m, void *p)
@@ -4186,7 +4120,7 @@ static void s_stop(struct seq_file *m, void *p)
static int s_show(struct seq_file *m, void *p)
{
- struct kmem_cache *cachep = p;
+ struct kmem_cache *cachep = list_entry(p, struct kmem_cache, next);
struct slab *slabp;
unsigned long active_objs;
unsigned long num_objs;
@@ -4355,17 +4289,8 @@ ssize_t slabinfo_write(struct file *file, const char __user * buffer,
static void *leaks_start(struct seq_file *m, loff_t *pos)
{
- loff_t n = *pos;
- struct list_head *p;
-
mutex_lock(&cache_chain_mutex);
- p = cache_chain.next;
- while (n--) {
- p = p->next;
- if (p == &cache_chain)
- return NULL;
- }
- return list_entry(p, struct kmem_cache, next);
+ return seq_list_start(&cache_chain, *pos);
}
static inline int add_caller(unsigned long *n, unsigned long v)
@@ -4416,7 +4341,7 @@ static void show_symbol(struct seq_file *m, unsigned long address)
{
#ifdef CONFIG_KALLSYMS
unsigned long offset, size;
- char modname[MODULE_NAME_LEN + 1], name[KSYM_NAME_LEN + 1];
+ char modname[MODULE_NAME_LEN], name[KSYM_NAME_LEN];
if (lookup_symbol_attrs(address, &size, &offset, modname, name) == 0) {
seq_printf(m, "%s+%#lx/%#lx", name, offset, size);
@@ -4430,7 +4355,7 @@ static void show_symbol(struct seq_file *m, unsigned long address)
static int leaks_show(struct seq_file *m, void *p)
{
- struct kmem_cache *cachep = p;
+ struct kmem_cache *cachep = list_entry(p, struct kmem_cache, next);
struct slab *slabp;
struct kmem_list3 *l3;
const char *name;
@@ -4511,7 +4436,7 @@ const struct seq_operations slabstats_op = {
*/
size_t ksize(const void *objp)
{
- if (unlikely(objp == NULL))
+ if (unlikely(ZERO_OR_NULL_PTR(objp)))
return 0;
return obj_size(virt_to_cache(objp));
diff --git a/mm/slob.c b/mm/slob.c
index 71976c5d40d3..ec33fcdc852e 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -3,57 +3,159 @@
*
* Matt Mackall <mpm@selenic.com> 12/30/03
*
+ * NUMA support by Paul Mundt, 2007.
+ *
* How SLOB works:
*
* The core of SLOB is a traditional K&R style heap allocator, with
* support for returning aligned objects. The granularity of this
- * allocator is 8 bytes on x86, though it's perhaps possible to reduce
- * this to 4 if it's deemed worth the effort. The slob heap is a
- * singly-linked list of pages from __get_free_page, grown on demand
- * and allocation from the heap is currently first-fit.
+ * allocator is as little as 2 bytes, however typically most architectures
+ * will require 4 bytes on 32-bit and 8 bytes on 64-bit.
+ *
+ * The slob heap is a linked list of pages from alloc_pages(), and
+ * within each page, there is a singly-linked list of free blocks (slob_t).
+ * The heap is grown on demand and allocation from the heap is currently
+ * first-fit.
*
* Above this is an implementation of kmalloc/kfree. Blocks returned
- * from kmalloc are 8-byte aligned and prepended with a 8-byte header.
+ * from kmalloc are prepended with a 4-byte header with the kmalloc size.
* If kmalloc is asked for objects of PAGE_SIZE or larger, it calls
- * __get_free_pages directly so that it can return page-aligned blocks
- * and keeps a linked list of such pages and their orders. These
- * objects are detected in kfree() by their page alignment.
+ * alloc_pages() directly, allocating compound pages so the page order
+ * does not have to be separately tracked, and also stores the exact
+ * allocation size in page->private so that it can be used to accurately
+ * provide ksize(). These objects are detected in kfree() because slob_page()
+ * is false for them.
*
* SLAB is emulated on top of SLOB by simply calling constructors and
- * destructors for every SLAB allocation. Objects are returned with
- * the 8-byte alignment unless the SLAB_HWCACHE_ALIGN flag is
- * set, in which case the low-level allocator will fragment blocks to
- * create the proper alignment. Again, objects of page-size or greater
- * are allocated by calling __get_free_pages. As SLAB objects know
- * their size, no separate size bookkeeping is necessary and there is
- * essentially no allocation space overhead.
+ * destructors for every SLAB allocation. Objects are returned with the
+ * 4-byte alignment unless the SLAB_HWCACHE_ALIGN flag is set, in which
+ * case the low-level allocator will fragment blocks to create the proper
+ * alignment. Again, objects of page-size or greater are allocated by
+ * calling alloc_pages(). As SLAB objects know their size, no separate
+ * size bookkeeping is necessary and there is essentially no allocation
+ * space overhead, and compound pages aren't needed for multi-page
+ * allocations.
+ *
+ * NUMA support in SLOB is fairly simplistic, pushing most of the real
+ * logic down to the page allocator, and simply doing the node accounting
+ * on the upper levels. In the event that a node id is explicitly
+ * provided, alloc_pages_node() with the specified node id is used
+ * instead. The common case (or when the node id isn't explicitly provided)
+ * will default to the current node, as per numa_node_id().
+ *
+ * Node aware pages are still inserted in to the global freelist, and
+ * these are scanned for by matching against the node id encoded in the
+ * page flags. As a result, block allocations that can be satisfied from
+ * the freelist will only be done so on pages residing on the same node,
+ * in order to prevent random node placement.
*/
+#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/cache.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/timer.h>
#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <asm/atomic.h>
+
+/*
+ * slob_block has a field 'units', which indicates size of block if +ve,
+ * or offset of next block if -ve (in SLOB_UNITs).
+ *
+ * Free blocks of size 1 unit simply contain the offset of the next block.
+ * Those with larger size contain their size in the first SLOB_UNIT of
+ * memory, and the offset of the next free block in the second SLOB_UNIT.
+ */
+#if PAGE_SIZE <= (32767 * 2)
+typedef s16 slobidx_t;
+#else
+typedef s32 slobidx_t;
+#endif
struct slob_block {
- int units;
- struct slob_block *next;
+ slobidx_t units;
};
typedef struct slob_block slob_t;
+/*
+ * We use struct page fields to manage some slob allocation aspects,
+ * however to avoid the horrible mess in include/linux/mm_types.h, we'll
+ * just define our own struct page type variant here.
+ */
+struct slob_page {
+ union {
+ struct {
+ unsigned long flags; /* mandatory */
+ atomic_t _count; /* mandatory */
+ slobidx_t units; /* free units left in page */
+ unsigned long pad[2];
+ slob_t *free; /* first free slob_t in page */
+ struct list_head list; /* linked list of free pages */
+ };
+ struct page page;
+ };
+};
+static inline void struct_slob_page_wrong_size(void)
+{ BUILD_BUG_ON(sizeof(struct slob_page) != sizeof(struct page)); }
+
+/*
+ * free_slob_page: call before a slob_page is returned to the page allocator.
+ */
+static inline void free_slob_page(struct slob_page *sp)
+{
+ reset_page_mapcount(&sp->page);
+ sp->page.mapping = NULL;
+}
+
+/*
+ * All (partially) free slob pages go on this list.
+ */
+static LIST_HEAD(free_slob_pages);
+
+/*
+ * slob_page: True for all slob pages (false for bigblock pages)
+ */
+static inline int slob_page(struct slob_page *sp)
+{
+ return test_bit(PG_active, &sp->flags);
+}
+
+static inline void set_slob_page(struct slob_page *sp)
+{
+ __set_bit(PG_active, &sp->flags);
+}
+
+static inline void clear_slob_page(struct slob_page *sp)
+{
+ __clear_bit(PG_active, &sp->flags);
+}
+
+/*
+ * slob_page_free: true for pages on free_slob_pages list.
+ */
+static inline int slob_page_free(struct slob_page *sp)
+{
+ return test_bit(PG_private, &sp->flags);
+}
+
+static inline void set_slob_page_free(struct slob_page *sp)
+{
+ list_add(&sp->list, &free_slob_pages);
+ __set_bit(PG_private, &sp->flags);
+}
+
+static inline void clear_slob_page_free(struct slob_page *sp)
+{
+ list_del(&sp->list);
+ __clear_bit(PG_private, &sp->flags);
+}
+
#define SLOB_UNIT sizeof(slob_t)
#define SLOB_UNITS(size) (((size) + SLOB_UNIT - 1)/SLOB_UNIT)
#define SLOB_ALIGN L1_CACHE_BYTES
-struct bigblock {
- int order;
- void *pages;
- struct bigblock *next;
-};
-typedef struct bigblock bigblock_t;
-
/*
* struct slob_rcu is inserted at the tail of allocated slob blocks, which
* were created with a SLAB_DESTROY_BY_RCU slab. slob_rcu is used to free
@@ -64,215 +166,332 @@ struct slob_rcu {
int size;
};
-static slob_t arena = { .next = &arena, .units = 1 };
-static slob_t *slobfree = &arena;
-static bigblock_t *bigblocks;
+/*
+ * slob_lock protects all slob allocator structures.
+ */
static DEFINE_SPINLOCK(slob_lock);
-static DEFINE_SPINLOCK(block_lock);
-static void slob_free(void *b, int size);
-static void slob_timer_cbk(void);
+/*
+ * Encode the given size and next info into a free slob block s.
+ */
+static void set_slob(slob_t *s, slobidx_t size, slob_t *next)
+{
+ slob_t *base = (slob_t *)((unsigned long)s & PAGE_MASK);
+ slobidx_t offset = next - base;
+
+ if (size > 1) {
+ s[0].units = size;
+ s[1].units = offset;
+ } else
+ s[0].units = -offset;
+}
+
+/*
+ * Return the size of a slob block.
+ */
+static slobidx_t slob_units(slob_t *s)
+{
+ if (s->units > 0)
+ return s->units;
+ return 1;
+}
+
+/*
+ * Return the next free slob block pointer after this one.
+ */
+static slob_t *slob_next(slob_t *s)
+{
+ slob_t *base = (slob_t *)((unsigned long)s & PAGE_MASK);
+ slobidx_t next;
+
+ if (s[0].units < 0)
+ next = -s[0].units;
+ else
+ next = s[1].units;
+ return base+next;
+}
+
+/*
+ * Returns true if s is the last free block in its page.
+ */
+static int slob_last(slob_t *s)
+{
+ return !((unsigned long)slob_next(s) & ~PAGE_MASK);
+}
+
+static void *slob_new_page(gfp_t gfp, int order, int node)
+{
+ void *page;
+
+#ifdef CONFIG_NUMA
+ if (node != -1)
+ page = alloc_pages_node(node, gfp, order);
+ else
+#endif
+ page = alloc_pages(gfp, order);
+ if (!page)
+ return NULL;
-static void *slob_alloc(size_t size, gfp_t gfp, int align)
+ return page_address(page);
+}
+
+/*
+ * Allocate a slob block within a given slob_page sp.
+ */
+static void *slob_page_alloc(struct slob_page *sp, size_t size, int align)
{
slob_t *prev, *cur, *aligned = 0;
int delta = 0, units = SLOB_UNITS(size);
- unsigned long flags;
- spin_lock_irqsave(&slob_lock, flags);
- prev = slobfree;
- for (cur = prev->next; ; prev = cur, cur = cur->next) {
+ for (prev = NULL, cur = sp->free; ; prev = cur, cur = slob_next(cur)) {
+ slobidx_t avail = slob_units(cur);
+
if (align) {
aligned = (slob_t *)ALIGN((unsigned long)cur, align);
delta = aligned - cur;
}
- if (cur->units >= units + delta) { /* room enough? */
+ if (avail >= units + delta) { /* room enough? */
+ slob_t *next;
+
if (delta) { /* need to fragment head to align? */
- aligned->units = cur->units - delta;
- aligned->next = cur->next;
- cur->next = aligned;
- cur->units = delta;
+ next = slob_next(cur);
+ set_slob(aligned, avail - delta, next);
+ set_slob(cur, delta, aligned);
prev = cur;
cur = aligned;
+ avail = slob_units(cur);
}
- if (cur->units == units) /* exact fit? */
- prev->next = cur->next; /* unlink */
- else { /* fragment */
- prev->next = cur + units;
- prev->next->units = cur->units - units;
- prev->next->next = cur->next;
- cur->units = units;
+ next = slob_next(cur);
+ if (avail == units) { /* exact fit? unlink. */
+ if (prev)
+ set_slob(prev, slob_units(prev), next);
+ else
+ sp->free = next;
+ } else { /* fragment */
+ if (prev)
+ set_slob(prev, slob_units(prev), cur + units);
+ else
+ sp->free = cur + units;
+ set_slob(cur + units, avail - units, next);
}
- slobfree = prev;
- spin_unlock_irqrestore(&slob_lock, flags);
+ sp->units -= units;
+ if (!sp->units)
+ clear_slob_page_free(sp);
return cur;
}
- if (cur == slobfree) {
- spin_unlock_irqrestore(&slob_lock, flags);
+ if (slob_last(cur))
+ return NULL;
+ }
+}
- if (size == PAGE_SIZE) /* trying to shrink arena? */
- return 0;
+/*
+ * slob_alloc: entry point into the slob allocator.
+ */
+static void *slob_alloc(size_t size, gfp_t gfp, int align, int node)
+{
+ struct slob_page *sp;
+ struct list_head *prev;
+ slob_t *b = NULL;
+ unsigned long flags;
- cur = (slob_t *)__get_free_page(gfp);
- if (!cur)
- return 0;
+ spin_lock_irqsave(&slob_lock, flags);
+ /* Iterate through each partially free page, try to find room */
+ list_for_each_entry(sp, &free_slob_pages, list) {
+#ifdef CONFIG_NUMA
+ /*
+ * If there's a node specification, search for a partial
+ * page with a matching node id in the freelist.
+ */
+ if (node != -1 && page_to_nid(&sp->page) != node)
+ continue;
+#endif
+ /* Enough room on this page? */
+ if (sp->units < SLOB_UNITS(size))
+ continue;
+
+ /* Attempt to alloc */
+ prev = sp->list.prev;
+ b = slob_page_alloc(sp, size, align);
+ if (!b)
+ continue;
+
+ /* Improve fragment distribution and reduce our average
+ * search time by starting our next search here. (see
+ * Knuth vol 1, sec 2.5, pg 449) */
+ if (free_slob_pages.next != prev->next)
+ list_move_tail(&free_slob_pages, prev->next);
+ break;
+ }
+ spin_unlock_irqrestore(&slob_lock, flags);
- slob_free(cur, PAGE_SIZE);
- spin_lock_irqsave(&slob_lock, flags);
- cur = slobfree;
- }
+ /* Not enough space: must allocate a new page */
+ if (!b) {
+ b = slob_new_page(gfp, 0, node);
+ if (!b)
+ return 0;
+ sp = (struct slob_page *)virt_to_page(b);
+ set_slob_page(sp);
+
+ spin_lock_irqsave(&slob_lock, flags);
+ sp->units = SLOB_UNITS(PAGE_SIZE);
+ sp->free = b;
+ INIT_LIST_HEAD(&sp->list);
+ set_slob(b, SLOB_UNITS(PAGE_SIZE), b + SLOB_UNITS(PAGE_SIZE));
+ set_slob_page_free(sp);
+ b = slob_page_alloc(sp, size, align);
+ BUG_ON(!b);
+ spin_unlock_irqrestore(&slob_lock, flags);
}
+ if (unlikely((gfp & __GFP_ZERO) && b))
+ memset(b, 0, size);
+ return b;
}
+/*
+ * slob_free: entry point into the slob allocator.
+ */
static void slob_free(void *block, int size)
{
- slob_t *cur, *b = (slob_t *)block;
+ struct slob_page *sp;
+ slob_t *prev, *next, *b = (slob_t *)block;
+ slobidx_t units;
unsigned long flags;
- if (!block)
+ if (ZERO_OR_NULL_PTR(block))
return;
+ BUG_ON(!size);
- if (size)
- b->units = SLOB_UNITS(size);
+ sp = (struct slob_page *)virt_to_page(block);
+ units = SLOB_UNITS(size);
- /* Find reinsertion point */
spin_lock_irqsave(&slob_lock, flags);
- for (cur = slobfree; !(b > cur && b < cur->next); cur = cur->next)
- if (cur >= cur->next && (b > cur || b < cur->next))
- break;
-
- if (b + b->units == cur->next) {
- b->units += cur->next->units;
- b->next = cur->next->next;
- } else
- b->next = cur->next;
-
- if (cur + cur->units == b) {
- cur->units += b->units;
- cur->next = b->next;
- } else
- cur->next = b;
- slobfree = cur;
-
- spin_unlock_irqrestore(&slob_lock, flags);
-}
-
-void *__kmalloc(size_t size, gfp_t gfp)
-{
- slob_t *m;
- bigblock_t *bb;
- unsigned long flags;
+ if (sp->units + units == SLOB_UNITS(PAGE_SIZE)) {
+ /* Go directly to page allocator. Do not pass slob allocator */
+ if (slob_page_free(sp))
+ clear_slob_page_free(sp);
+ clear_slob_page(sp);
+ free_slob_page(sp);
+ free_page((unsigned long)b);
+ goto out;
+ }
- if (size < PAGE_SIZE - SLOB_UNIT) {
- m = slob_alloc(size + SLOB_UNIT, gfp, 0);
- return m ? (void *)(m + 1) : 0;
+ if (!slob_page_free(sp)) {
+ /* This slob page is about to become partially free. Easy! */
+ sp->units = units;
+ sp->free = b;
+ set_slob(b, units,
+ (void *)((unsigned long)(b +
+ SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));
+ set_slob_page_free(sp);
+ goto out;
}
- bb = slob_alloc(sizeof(bigblock_t), gfp, 0);
- if (!bb)
- return 0;
+ /*
+ * Otherwise the page is already partially free, so find reinsertion
+ * point.
+ */
+ sp->units += units;
- bb->order = get_order(size);
- bb->pages = (void *)__get_free_pages(gfp, bb->order);
+ if (b < sp->free) {
+ set_slob(b, units, sp->free);
+ sp->free = b;
+ } else {
+ prev = sp->free;
+ next = slob_next(prev);
+ while (b > next) {
+ prev = next;
+ next = slob_next(prev);
+ }
- if (bb->pages) {
- spin_lock_irqsave(&block_lock, flags);
- bb->next = bigblocks;
- bigblocks = bb;
- spin_unlock_irqrestore(&block_lock, flags);
- return bb->pages;
+ if (!slob_last(prev) && b + units == next) {
+ units += slob_units(next);
+ set_slob(b, units, slob_next(next));
+ } else
+ set_slob(b, units, next);
+
+ if (prev + slob_units(prev) == b) {
+ units = slob_units(b) + slob_units(prev);
+ set_slob(prev, units, slob_next(b));
+ } else
+ set_slob(prev, slob_units(prev), b);
}
-
- slob_free(bb, sizeof(bigblock_t));
- return 0;
+out:
+ spin_unlock_irqrestore(&slob_lock, flags);
}
-EXPORT_SYMBOL(__kmalloc);
-/**
- * krealloc - reallocate memory. The contents will remain unchanged.
- *
- * @p: object to reallocate memory for.
- * @new_size: how many bytes of memory are required.
- * @flags: the type of memory to allocate.
- *
- * The contents of the object pointed to are preserved up to the
- * lesser of the new and old sizes. If @p is %NULL, krealloc()
- * behaves exactly like kmalloc(). If @size is 0 and @p is not a
- * %NULL pointer, the object pointed to is freed.
+/*
+ * End of slob allocator proper. Begin kmem_cache_alloc and kmalloc frontend.
*/
-void *krealloc(const void *p, size_t new_size, gfp_t flags)
+
+#ifndef ARCH_KMALLOC_MINALIGN
+#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long)
+#endif
+
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long)
+#endif
+
+void *__kmalloc_node(size_t size, gfp_t gfp, int node)
{
- void *ret;
+ unsigned int *m;
+ int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
- if (unlikely(!p))
- return kmalloc_track_caller(new_size, flags);
+ if (size < PAGE_SIZE - align) {
+ if (!size)
+ return ZERO_SIZE_PTR;
- if (unlikely(!new_size)) {
- kfree(p);
- return NULL;
- }
+ m = slob_alloc(size + align, gfp, align, node);
+ if (m)
+ *m = size;
+ return (void *)m + align;
+ } else {
+ void *ret;
- ret = kmalloc_track_caller(new_size, flags);
- if (ret) {
- memcpy(ret, p, min(new_size, ksize(p)));
- kfree(p);
+ ret = slob_new_page(gfp | __GFP_COMP, get_order(size), node);
+ if (ret) {
+ struct page *page;
+ page = virt_to_page(ret);
+ page->private = size;
+ }
+ return ret;
}
- return ret;
}
-EXPORT_SYMBOL(krealloc);
+EXPORT_SYMBOL(__kmalloc_node);
void kfree(const void *block)
{
- bigblock_t *bb, **last = &bigblocks;
- unsigned long flags;
+ struct slob_page *sp;
- if (!block)
+ if (ZERO_OR_NULL_PTR(block))
return;
- if (!((unsigned long)block & (PAGE_SIZE-1))) {
- /* might be on the big block list */
- spin_lock_irqsave(&block_lock, flags);
- for (bb = bigblocks; bb; last = &bb->next, bb = bb->next) {
- if (bb->pages == block) {
- *last = bb->next;
- spin_unlock_irqrestore(&block_lock, flags);
- free_pages((unsigned long)block, bb->order);
- slob_free(bb, sizeof(bigblock_t));
- return;
- }
- }
- spin_unlock_irqrestore(&block_lock, flags);
- }
-
- slob_free((slob_t *)block - 1, 0);
- return;
+ sp = (struct slob_page *)virt_to_page(block);
+ if (slob_page(sp)) {
+ int align = max(ARCH_KMALLOC_MINALIGN, ARCH_SLAB_MINALIGN);
+ unsigned int *m = (unsigned int *)(block - align);
+ slob_free(m, *m + align);
+ } else
+ put_page(&sp->page);
}
-
EXPORT_SYMBOL(kfree);
+/* can't use ksize for kmem_cache_alloc memory, only kmalloc */
size_t ksize(const void *block)
{
- bigblock_t *bb;
- unsigned long flags;
+ struct slob_page *sp;
- if (!block)
+ if (ZERO_OR_NULL_PTR(block))
return 0;
- if (!((unsigned long)block & (PAGE_SIZE-1))) {
- spin_lock_irqsave(&block_lock, flags);
- for (bb = bigblocks; bb; bb = bb->next)
- if (bb->pages == block) {
- spin_unlock_irqrestore(&slob_lock, flags);
- return PAGE_SIZE << bb->order;
- }
- spin_unlock_irqrestore(&block_lock, flags);
- }
-
- return ((slob_t *)block - 1)->units * SLOB_UNIT;
+ sp = (struct slob_page *)virt_to_page(block);
+ if (slob_page(sp))
+ return ((slob_t *)block - 1)->units + SLOB_UNIT;
+ else
+ return sp->page.private;
}
struct kmem_cache {
@@ -284,12 +503,11 @@ struct kmem_cache {
struct kmem_cache *kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags,
- void (*ctor)(void*, struct kmem_cache *, unsigned long),
- void (*dtor)(void*, struct kmem_cache *, unsigned long))
+ void (*ctor)(void*, struct kmem_cache *, unsigned long))
{
struct kmem_cache *c;
- c = slob_alloc(sizeof(struct kmem_cache), flags, 0);
+ c = slob_alloc(sizeof(struct kmem_cache), flags, 0, -1);
if (c) {
c->name = name;
@@ -302,6 +520,8 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
c->ctor = ctor;
/* ignore alignment unless it's forced */
c->align = (flags & SLAB_HWCACHE_ALIGN) ? SLOB_ALIGN : 0;
+ if (c->align < ARCH_SLAB_MINALIGN)
+ c->align = ARCH_SLAB_MINALIGN;
if (c->align < align)
c->align = align;
} else if (flags & SLAB_PANIC)
@@ -317,31 +537,21 @@ void kmem_cache_destroy(struct kmem_cache *c)
}
EXPORT_SYMBOL(kmem_cache_destroy);
-void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags)
+void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
{
void *b;
if (c->size < PAGE_SIZE)
- b = slob_alloc(c->size, flags, c->align);
+ b = slob_alloc(c->size, flags, c->align, node);
else
- b = (void *)__get_free_pages(flags, get_order(c->size));
+ b = slob_new_page(flags, get_order(c->size), node);
if (c->ctor)
c->ctor(b, c, 0);
return b;
}
-EXPORT_SYMBOL(kmem_cache_alloc);
-
-void *kmem_cache_zalloc(struct kmem_cache *c, gfp_t flags)
-{
- void *ret = kmem_cache_alloc(c, flags);
- if (ret)
- memset(ret, 0, c->size);
-
- return ret;
-}
-EXPORT_SYMBOL(kmem_cache_zalloc);
+EXPORT_SYMBOL(kmem_cache_alloc_node);
static void __kmem_cache_free(void *b, int size)
{
@@ -385,9 +595,6 @@ const char *kmem_cache_name(struct kmem_cache *c)
}
EXPORT_SYMBOL(kmem_cache_name);
-static struct timer_list slob_timer = TIMER_INITIALIZER(
- (void (*)(unsigned long))slob_timer_cbk, 0, 0);
-
int kmem_cache_shrink(struct kmem_cache *d)
{
return 0;
@@ -399,17 +606,14 @@ int kmem_ptr_validate(struct kmem_cache *a, const void *b)
return 0;
}
-void __init kmem_cache_init(void)
+static unsigned int slob_ready __read_mostly;
+
+int slab_is_available(void)
{
- slob_timer_cbk();
+ return slob_ready;
}
-static void slob_timer_cbk(void)
+void __init kmem_cache_init(void)
{
- void *p = slob_alloc(PAGE_SIZE, 0, PAGE_SIZE-1);
-
- if (p)
- free_page((unsigned long)p);
-
- mod_timer(&slob_timer, jiffies + HZ);
+ slob_ready = 1;
}
diff --git a/mm/slub.c b/mm/slub.c
index e0cf6213abc0..9b2d6178d06c 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -205,6 +205,11 @@ static inline void ClearSlabDebug(struct page *page)
#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
#endif
+/*
+ * The page->inuse field is 16 bit thus we have this limitation
+ */
+#define MAX_OBJECTS_PER_SLAB 65535
+
/* Internal SLUB flags */
#define __OBJECT_POISON 0x80000000 /* Poison object */
@@ -228,7 +233,7 @@ static enum {
/* A list of all slab caches on the system */
static DECLARE_RWSEM(slub_lock);
-LIST_HEAD(slab_caches);
+static LIST_HEAD(slab_caches);
/*
* Tracking user of a slab.
@@ -247,9 +252,10 @@ static int sysfs_slab_add(struct kmem_cache *);
static int sysfs_slab_alias(struct kmem_cache *, const char *);
static void sysfs_slab_remove(struct kmem_cache *);
#else
-static int sysfs_slab_add(struct kmem_cache *s) { return 0; }
-static int sysfs_slab_alias(struct kmem_cache *s, const char *p) { return 0; }
-static void sysfs_slab_remove(struct kmem_cache *s) {}
+static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; }
+static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
+ { return 0; }
+static inline void sysfs_slab_remove(struct kmem_cache *s) {}
#endif
/********************************************************************
@@ -323,7 +329,11 @@ static inline int slab_index(void *p, struct kmem_cache *s, void *addr)
/*
* Debug settings:
*/
+#ifdef CONFIG_SLUB_DEBUG_ON
+static int slub_debug = DEBUG_DEFAULT_FLAGS;
+#else
static int slub_debug;
+#endif
static char *slub_debug_slabs;
@@ -340,7 +350,7 @@ static void print_section(char *text, u8 *addr, unsigned int length)
for (i = 0; i < length; i++) {
if (newline) {
- printk(KERN_ERR "%10s 0x%p: ", text, addr + i);
+ printk(KERN_ERR "%8s 0x%p: ", text, addr + i);
newline = 0;
}
printk(" %02x", addr[i]);
@@ -397,10 +407,11 @@ static void set_track(struct kmem_cache *s, void *object,
static void init_tracking(struct kmem_cache *s, void *object)
{
- if (s->flags & SLAB_STORE_USER) {
- set_track(s, object, TRACK_FREE, NULL);
- set_track(s, object, TRACK_ALLOC, NULL);
- }
+ if (!(s->flags & SLAB_STORE_USER))
+ return;
+
+ set_track(s, object, TRACK_FREE, NULL);
+ set_track(s, object, TRACK_ALLOC, NULL);
}
static void print_track(const char *s, struct track *t)
@@ -408,65 +419,106 @@ static void print_track(const char *s, struct track *t)
if (!t->addr)
return;
- printk(KERN_ERR "%s: ", s);
+ printk(KERN_ERR "INFO: %s in ", s);
__print_symbol("%s", (unsigned long)t->addr);
- printk(" jiffies_ago=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid);
+ printk(" age=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid);
+}
+
+static void print_tracking(struct kmem_cache *s, void *object)
+{
+ if (!(s->flags & SLAB_STORE_USER))
+ return;
+
+ print_track("Allocated", get_track(s, object, TRACK_ALLOC));
+ print_track("Freed", get_track(s, object, TRACK_FREE));
+}
+
+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);
+
+}
+
+static void slab_bug(struct kmem_cache *s, char *fmt, ...)
+{
+ va_list args;
+ char buf[100];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ printk(KERN_ERR "========================================"
+ "=====================================\n");
+ printk(KERN_ERR "BUG %s: %s\n", s->name, buf);
+ printk(KERN_ERR "----------------------------------------"
+ "-------------------------------------\n\n");
}
-static void print_trailer(struct kmem_cache *s, u8 *p)
+static void slab_fix(struct kmem_cache *s, char *fmt, ...)
+{
+ va_list args;
+ char buf[100];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ printk(KERN_ERR "FIX %s: %s\n", s->name, buf);
+}
+
+static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p)
{
unsigned int off; /* Offset of last byte */
+ u8 *addr = page_address(page);
+
+ print_tracking(s, p);
+
+ print_page_info(page);
+
+ printk(KERN_ERR "INFO: Object 0x%p @offset=%tu fp=0x%p\n\n",
+ p, p - addr, get_freepointer(s, p));
+
+ if (p > addr + 16)
+ print_section("Bytes b4", p - 16, 16);
+
+ print_section("Object", p, min(s->objsize, 128));
if (s->flags & SLAB_RED_ZONE)
print_section("Redzone", p + s->objsize,
s->inuse - s->objsize);
- printk(KERN_ERR "FreePointer 0x%p -> 0x%p\n",
- p + s->offset,
- get_freepointer(s, p));
-
if (s->offset)
off = s->offset + sizeof(void *);
else
off = s->inuse;
- if (s->flags & SLAB_STORE_USER) {
- print_track("Last alloc", get_track(s, p, TRACK_ALLOC));
- print_track("Last free ", get_track(s, p, TRACK_FREE));
+ if (s->flags & SLAB_STORE_USER)
off += 2 * sizeof(struct track);
- }
if (off != s->size)
/* Beginning of the filler is the free pointer */
- print_section("Filler", p + off, s->size - off);
+ print_section("Padding", p + off, s->size - off);
+
+ dump_stack();
}
static void object_err(struct kmem_cache *s, struct page *page,
u8 *object, char *reason)
{
- u8 *addr = page_address(page);
-
- printk(KERN_ERR "*** SLUB %s: %s@0x%p slab 0x%p\n",
- s->name, reason, object, page);
- printk(KERN_ERR " offset=%tu flags=0x%04lx inuse=%u freelist=0x%p\n",
- object - addr, page->flags, page->inuse, page->freelist);
- if (object > addr + 16)
- print_section("Bytes b4", object - 16, 16);
- print_section("Object", object, min(s->objsize, 128));
- print_trailer(s, object);
- dump_stack();
+ slab_bug(s, reason);
+ print_trailer(s, page, object);
}
-static void slab_err(struct kmem_cache *s, struct page *page, char *reason, ...)
+static void slab_err(struct kmem_cache *s, struct page *page, char *fmt, ...)
{
va_list args;
char buf[100];
- va_start(args, reason);
- vsnprintf(buf, sizeof(buf), reason, args);
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- printk(KERN_ERR "*** SLUB %s: %s in slab @0x%p\n", s->name, buf,
- page);
+ slab_bug(s, fmt);
+ print_page_info(page);
dump_stack();
}
@@ -485,15 +537,46 @@ static void init_object(struct kmem_cache *s, void *object, int active)
s->inuse - s->objsize);
}
-static int check_bytes(u8 *start, unsigned int value, unsigned int bytes)
+static u8 *check_bytes(u8 *start, unsigned int value, unsigned int bytes)
{
while (bytes) {
if (*start != (u8)value)
- return 0;
+ return start;
start++;
bytes--;
}
- return 1;
+ return NULL;
+}
+
+static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
+ void *from, void *to)
+{
+ slab_fix(s, "Restoring 0x%p-0x%p=0x%x\n", from, to - 1, data);
+ memset(from, data, to - from);
+}
+
+static int check_bytes_and_report(struct kmem_cache *s, struct page *page,
+ u8 *object, char *what,
+ u8* start, unsigned int value, unsigned int bytes)
+{
+ u8 *fault;
+ u8 *end;
+
+ fault = check_bytes(start, value, bytes);
+ if (!fault)
+ return 1;
+
+ end = start + bytes;
+ while (end > fault && end[-1] == value)
+ end--;
+
+ slab_bug(s, "%s overwritten", what);
+ printk(KERN_ERR "INFO: 0x%p-0x%p. First byte 0x%x instead of 0x%x\n",
+ fault, end - 1, fault[0], value);
+ print_trailer(s, page, object);
+
+ restore_bytes(s, what, value, fault, end);
+ return 0;
}
/*
@@ -534,14 +617,6 @@ static int check_bytes(u8 *start, unsigned int value, unsigned int bytes)
* may be used with merged slabcaches.
*/
-static void restore_bytes(struct kmem_cache *s, char *message, u8 data,
- void *from, void *to)
-{
- printk(KERN_ERR "@@@ SLUB %s: Restoring %s (0x%x) from 0x%p-0x%p\n",
- s->name, message, data, from, to - 1);
- memset(from, data, to - from);
-}
-
static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
{
unsigned long off = s->inuse; /* The end of info */
@@ -557,39 +632,39 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p)
if (s->size == off)
return 1;
- if (check_bytes(p + off, POISON_INUSE, s->size - off))
- return 1;
-
- object_err(s, page, p, "Object padding check fails");
-
- /*
- * Restore padding
- */
- restore_bytes(s, "object padding", POISON_INUSE, p + off, p + s->size);
- return 0;
+ return check_bytes_and_report(s, page, p, "Object padding",
+ p + off, POISON_INUSE, s->size - off);
}
static int slab_pad_check(struct kmem_cache *s, struct page *page)
{
- u8 *p;
- int length, remainder;
+ u8 *start;
+ u8 *fault;
+ u8 *end;
+ int length;
+ int remainder;
if (!(s->flags & SLAB_POISON))
return 1;
- p = page_address(page);
+ start = page_address(page);
+ end = start + (PAGE_SIZE << s->order);
length = s->objects * s->size;
- remainder = (PAGE_SIZE << s->order) - length;
+ remainder = end - (start + length);
if (!remainder)
return 1;
- if (!check_bytes(p + length, POISON_INUSE, remainder)) {
- slab_err(s, page, "Padding check failed");
- restore_bytes(s, "slab padding", POISON_INUSE, p + length,
- p + length + remainder);
- return 0;
- }
- return 1;
+ fault = check_bytes(start + length, 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);
+
+ restore_bytes(s, "slab padding", POISON_INUSE, start, end);
+ return 0;
}
static int check_object(struct kmem_cache *s, struct page *page,
@@ -602,41 +677,22 @@ static int check_object(struct kmem_cache *s, struct page *page,
unsigned int red =
active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE;
- if (!check_bytes(endobject, red, s->inuse - s->objsize)) {
- object_err(s, page, object,
- active ? "Redzone Active" : "Redzone Inactive");
- restore_bytes(s, "redzone", red,
- endobject, object + s->inuse);
+ if (!check_bytes_and_report(s, page, object, "Redzone",
+ endobject, red, s->inuse - s->objsize))
return 0;
- }
} else {
- if ((s->flags & SLAB_POISON) && s->objsize < s->inuse &&
- !check_bytes(endobject, POISON_INUSE,
- s->inuse - s->objsize)) {
- object_err(s, page, p, "Alignment padding check fails");
- /*
- * Fix it so that there will not be another report.
- *
- * Hmmm... We may be corrupting an object that now expects
- * to be longer than allowed.
- */
- restore_bytes(s, "alignment padding", POISON_INUSE,
- endobject, object + s->inuse);
- }
+ if ((s->flags & SLAB_POISON) && s->objsize < s->inuse)
+ check_bytes_and_report(s, page, p, "Alignment padding", endobject,
+ POISON_INUSE, s->inuse - s->objsize);
}
if (s->flags & SLAB_POISON) {
if (!active && (s->flags & __OBJECT_POISON) &&
- (!check_bytes(p, POISON_FREE, s->objsize - 1) ||
- p[s->objsize - 1] != POISON_END)) {
-
- object_err(s, page, p, "Poison check failed");
- restore_bytes(s, "Poison", POISON_FREE,
- p, p + s->objsize -1);
- restore_bytes(s, "Poison", POISON_END,
- p + s->objsize - 1, p + s->objsize);
+ (!check_bytes_and_report(s, page, p, "Poison", p,
+ POISON_FREE, s->objsize - 1) ||
+ !check_bytes_and_report(s, page, p, "Poison",
+ p + s->objsize -1, POISON_END, 1)))
return 0;
- }
/*
* check_pad_bytes cleans up on its own.
*/
@@ -669,25 +725,17 @@ static int check_slab(struct kmem_cache *s, struct page *page)
VM_BUG_ON(!irqs_disabled());
if (!PageSlab(page)) {
- slab_err(s, page, "Not a valid slab page flags=%lx "
- "mapping=0x%p count=%d", page->flags, page->mapping,
- page_count(page));
+ slab_err(s, page, "Not a valid slab page");
return 0;
}
if (page->offset * sizeof(void *) != s->offset) {
- slab_err(s, page, "Corrupted offset %lu flags=0x%lx "
- "mapping=0x%p count=%d",
- (unsigned long)(page->offset * sizeof(void *)),
- page->flags,
- page->mapping,
- page_count(page));
+ slab_err(s, page, "Corrupted offset %lu",
+ (unsigned long)(page->offset * sizeof(void *)));
return 0;
}
if (page->inuse > s->objects) {
- slab_err(s, page, "inuse %u > max %u @0x%p flags=%lx "
- "mapping=0x%p count=%d",
- s->name, page->inuse, s->objects, page->flags,
- page->mapping, page_count(page));
+ slab_err(s, page, "inuse %u > max %u",
+ s->name, page->inuse, s->objects);
return 0;
}
/* Slab_pad_check fixes things up after itself */
@@ -715,13 +763,10 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
set_freepointer(s, object, NULL);
break;
} else {
- slab_err(s, page, "Freepointer 0x%p corrupt",
- fp);
+ slab_err(s, page, "Freepointer corrupt");
page->freelist = NULL;
page->inuse = s->objects;
- printk(KERN_ERR "@@@ SLUB %s: Freelist "
- "cleared. Slab 0x%p\n",
- s->name, page);
+ slab_fix(s, "Freelist cleared");
return 0;
}
break;
@@ -733,11 +778,9 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
if (page->inuse != s->objects - nr) {
slab_err(s, page, "Wrong object count. Counter is %d but "
- "counted were %d", s, page, page->inuse,
- s->objects - nr);
+ "counted were %d", page->inuse, s->objects - nr);
page->inuse = s->objects - nr;
- printk(KERN_ERR "@@@ SLUB %s: Object count adjusted. "
- "Slab @0x%p\n", s->name, page);
+ slab_fix(s, "Object count adjusted.");
}
return search == NULL;
}
@@ -799,7 +842,7 @@ static int alloc_debug_processing(struct kmem_cache *s, struct page *page,
goto bad;
if (object && !on_freelist(s, page, object)) {
- slab_err(s, page, "Object 0x%p already allocated", object);
+ object_err(s, page, object, "Object already allocated");
goto bad;
}
@@ -825,8 +868,7 @@ bad:
* to avoid issues in the future. Marking all objects
* as used avoids touching the remaining objects.
*/
- printk(KERN_ERR "@@@ SLUB: %s slab 0x%p. Marking all objects used.\n",
- s->name, page);
+ slab_fix(s, "Marking all objects used");
page->inuse = s->objects;
page->freelist = NULL;
/* Fix up fields that may be corrupted */
@@ -847,7 +889,7 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page,
}
if (on_freelist(s, page, object)) {
- slab_err(s, page, "Object 0x%p already free", object);
+ object_err(s, page, object, "Object already free");
goto fail;
}
@@ -866,8 +908,8 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page,
dump_stack();
}
else
- slab_err(s, page, "object at 0x%p belongs "
- "to slab %s", object, page->slab->name);
+ object_err(s, page, object,
+ "page slab pointer corrupt.");
goto fail;
}
@@ -881,45 +923,63 @@ static int free_debug_processing(struct kmem_cache *s, struct page *page,
return 1;
fail:
- printk(KERN_ERR "@@@ SLUB: %s slab 0x%p object at 0x%p not freed.\n",
- s->name, page, object);
+ slab_fix(s, "Object at 0x%p not freed", object);
return 0;
}
static int __init setup_slub_debug(char *str)
{
- if (!str || *str != '=')
- slub_debug = DEBUG_DEFAULT_FLAGS;
- else {
- str++;
- if (*str == 0 || *str == ',')
- slub_debug = DEBUG_DEFAULT_FLAGS;
- else
- for( ;*str && *str != ','; str++)
- switch (*str) {
- case 'f' : case 'F' :
- slub_debug |= SLAB_DEBUG_FREE;
- break;
- case 'z' : case 'Z' :
- slub_debug |= SLAB_RED_ZONE;
- break;
- case 'p' : case 'P' :
- slub_debug |= SLAB_POISON;
- break;
- case 'u' : case 'U' :
- slub_debug |= SLAB_STORE_USER;
- break;
- case 't' : case 'T' :
- slub_debug |= SLAB_TRACE;
- break;
- default:
- printk(KERN_ERR "slub_debug option '%c' "
- "unknown. skipped\n",*str);
- }
+ slub_debug = DEBUG_DEFAULT_FLAGS;
+ if (*str++ != '=' || !*str)
+ /*
+ * No options specified. Switch on full debugging.
+ */
+ goto out;
+
+ if (*str == ',')
+ /*
+ * No options but restriction on slabs. This means full
+ * debugging for slabs matching a pattern.
+ */
+ goto check_slabs;
+
+ slub_debug = 0;
+ if (*str == '-')
+ /*
+ * Switch off all debugging measures.
+ */
+ goto out;
+
+ /*
+ * Determine which debug features should be switched on
+ */
+ for ( ;*str && *str != ','; str++) {
+ switch (tolower(*str)) {
+ case 'f':
+ slub_debug |= SLAB_DEBUG_FREE;
+ break;
+ case 'z':
+ slub_debug |= SLAB_RED_ZONE;
+ break;
+ case 'p':
+ slub_debug |= SLAB_POISON;
+ break;
+ case 'u':
+ slub_debug |= SLAB_STORE_USER;
+ break;
+ case 't':
+ slub_debug |= SLAB_TRACE;
+ break;
+ default:
+ printk(KERN_ERR "slub_debug option '%c' "
+ "unknown. skipped\n",*str);
+ }
}
+check_slabs:
if (*str == ',')
slub_debug_slabs = str + 1;
+out:
return 1;
}
@@ -1018,7 +1078,7 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
void *last;
void *p;
- BUG_ON(flags & ~(GFP_DMA | GFP_LEVEL_MASK));
+ BUG_ON(flags & ~(GFP_DMA | __GFP_ZERO | GFP_LEVEL_MASK));
if (flags & __GFP_WAIT)
local_irq_enable();
@@ -1336,7 +1396,7 @@ static void deactivate_slab(struct kmem_cache *s, struct page *page, int cpu)
unfreeze_slab(s, page);
}
-static void flush_slab(struct kmem_cache *s, struct page *page, int cpu)
+static inline void flush_slab(struct kmem_cache *s, struct page *page, int cpu)
{
slab_lock(page);
deactivate_slab(s, page, cpu);
@@ -1346,7 +1406,7 @@ static void flush_slab(struct kmem_cache *s, struct page *page, int cpu)
* Flush cpu slab.
* Called from IPI handler with interrupts disabled.
*/
-static void __flush_cpu_slab(struct kmem_cache *s, int cpu)
+static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
struct page *page = s->cpu_slab[cpu];
@@ -1481,7 +1541,7 @@ debug:
* Otherwise we can simply pick the next object from the lockless free list.
*/
static void __always_inline *slab_alloc(struct kmem_cache *s,
- gfp_t gfpflags, int node, void *addr)
+ gfp_t gfpflags, int node, void *addr)
{
struct page *page;
void **object;
@@ -1499,6 +1559,10 @@ static void __always_inline *slab_alloc(struct kmem_cache *s,
page->lockless_freelist = object[page->offset];
}
local_irq_restore(flags);
+
+ if (unlikely((gfpflags & __GFP_ZERO) && object))
+ memset(object, 0, s->objsize);
+
return object;
}
@@ -1682,8 +1746,17 @@ static inline int slab_order(int size, int min_objects,
{
int order;
int rem;
+ int min_order = slub_min_order;
+
+ /*
+ * If we would create too many object per slab then reduce
+ * the slab order even if it goes below slub_min_order.
+ */
+ while (min_order > 0 &&
+ (PAGE_SIZE << min_order) >= MAX_OBJECTS_PER_SLAB * size)
+ min_order--;
- for (order = max(slub_min_order,
+ for (order = max(min_order,
fls(min_objects * size - 1) - PAGE_SHIFT);
order <= max_order; order++) {
@@ -1697,6 +1770,9 @@ static inline int slab_order(int size, int min_objects,
if (rem <= slab_size / fract_leftover)
break;
+ /* If the next size is too high then exit now */
+ if (slab_size * 2 >= MAX_OBJECTS_PER_SLAB * size)
+ break;
}
return order;
@@ -1777,7 +1853,9 @@ static void init_kmem_cache_node(struct kmem_cache_node *n)
atomic_long_set(&n->nr_slabs, 0);
spin_lock_init(&n->list_lock);
INIT_LIST_HEAD(&n->partial);
+#ifdef CONFIG_SLUB_DEBUG
INIT_LIST_HEAD(&n->full);
+#endif
}
#ifdef CONFIG_NUMA
@@ -1805,7 +1883,10 @@ static struct kmem_cache_node * __init early_kmem_cache_node_alloc(gfp_t gfpflag
page->freelist = get_freepointer(kmalloc_caches, n);
page->inuse++;
kmalloc_caches->node[node] = n;
- setup_object_debug(kmalloc_caches, page, n);
+#ifdef CONFIG_SLUB_DEBUG
+ init_object(kmalloc_caches, n, 1);
+ init_tracking(kmalloc_caches, n);
+#endif
init_kmem_cache_node(n);
atomic_long_inc(&n->nr_slabs);
add_partial(n, page);
@@ -1983,7 +2064,7 @@ static int calculate_sizes(struct kmem_cache *s)
* The page->inuse field is only 16 bit wide! So we cannot have
* more than 64k objects per slab.
*/
- if (!s->objects || s->objects > 65535)
+ if (!s->objects || s->objects > MAX_OBJECTS_PER_SLAB)
return 0;
return 1;
@@ -2087,7 +2168,7 @@ static int free_list(struct kmem_cache *s, struct kmem_cache_node *n,
/*
* Release all resources used by a slab cache.
*/
-static int kmem_cache_close(struct kmem_cache *s)
+static inline int kmem_cache_close(struct kmem_cache *s)
{
int node;
@@ -2115,12 +2196,13 @@ void kmem_cache_destroy(struct kmem_cache *s)
s->refcount--;
if (!s->refcount) {
list_del(&s->list);
+ up_write(&slub_lock);
if (kmem_cache_close(s))
WARN_ON(1);
sysfs_slab_remove(s);
kfree(s);
- }
- up_write(&slub_lock);
+ } else
+ up_write(&slub_lock);
}
EXPORT_SYMBOL(kmem_cache_destroy);
@@ -2193,47 +2275,92 @@ panic:
panic("Creation of kmalloc slab %s size=%d failed.\n", name, size);
}
-static struct kmem_cache *get_slab(size_t size, gfp_t flags)
+#ifdef CONFIG_ZONE_DMA
+static noinline struct kmem_cache *dma_kmalloc_cache(int index, gfp_t flags)
{
- int index = kmalloc_index(size);
+ struct kmem_cache *s;
+ struct kmem_cache *x;
+ char *text;
+ size_t realsize;
- if (!index)
- return NULL;
+ s = kmalloc_caches_dma[index];
+ if (s)
+ return s;
- /* Allocation too large? */
- BUG_ON(index < 0);
+ /* Dynamically create dma cache */
+ x = kmalloc(kmem_size, flags & ~SLUB_DMA);
+ if (!x)
+ panic("Unable to allocate memory for dma cache\n");
-#ifdef CONFIG_ZONE_DMA
- if ((flags & SLUB_DMA)) {
- struct kmem_cache *s;
- struct kmem_cache *x;
- char *text;
- size_t realsize;
-
- s = kmalloc_caches_dma[index];
- if (s)
- return s;
+ realsize = kmalloc_caches[index].objsize;
+ text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d",
+ (unsigned int)realsize);
+ s = create_kmalloc_cache(x, text, realsize, flags);
+ down_write(&slub_lock);
+ if (!kmalloc_caches_dma[index]) {
+ kmalloc_caches_dma[index] = s;
+ up_write(&slub_lock);
+ return s;
+ }
+ up_write(&slub_lock);
+ kmem_cache_destroy(s);
+ return kmalloc_caches_dma[index];
+}
+#endif
- /* Dynamically create dma cache */
- x = kmalloc(kmem_size, flags & ~SLUB_DMA);
- if (!x)
- panic("Unable to allocate memory for dma cache\n");
+/*
+ * Conversion table for small slabs sizes / 8 to the index in the
+ * kmalloc array. This is necessary for slabs < 192 since we have non power
+ * of two cache sizes there. The size of larger slabs can be determined using
+ * fls.
+ */
+static s8 size_index[24] = {
+ 3, /* 8 */
+ 4, /* 16 */
+ 5, /* 24 */
+ 5, /* 32 */
+ 6, /* 40 */
+ 6, /* 48 */
+ 6, /* 56 */
+ 6, /* 64 */
+ 1, /* 72 */
+ 1, /* 80 */
+ 1, /* 88 */
+ 1, /* 96 */
+ 7, /* 104 */
+ 7, /* 112 */
+ 7, /* 120 */
+ 7, /* 128 */
+ 2, /* 136 */
+ 2, /* 144 */
+ 2, /* 152 */
+ 2, /* 160 */
+ 2, /* 168 */
+ 2, /* 176 */
+ 2, /* 184 */
+ 2 /* 192 */
+};
- if (index <= KMALLOC_SHIFT_HIGH)
- realsize = 1 << index;
- else {
- if (index == 1)
- realsize = 96;
- else
- realsize = 192;
- }
+static struct kmem_cache *get_slab(size_t size, gfp_t flags)
+{
+ int index;
- text = kasprintf(flags & ~SLUB_DMA, "kmalloc_dma-%d",
- (unsigned int)realsize);
- s = create_kmalloc_cache(x, text, realsize, flags);
- kmalloc_caches_dma[index] = s;
- return s;
+ if (size <= 192) {
+ if (!size)
+ return ZERO_SIZE_PTR;
+
+ index = size_index[(size - 1) / 8];
+ } else {
+ if (size > KMALLOC_MAX_SIZE)
+ return NULL;
+
+ index = fls(size - 1);
}
+
+#ifdef CONFIG_ZONE_DMA
+ if (unlikely((flags & SLUB_DMA)))
+ return dma_kmalloc_cache(index, flags);
+
#endif
return &kmalloc_caches[index];
}
@@ -2242,9 +2369,10 @@ void *__kmalloc(size_t size, gfp_t flags)
{
struct kmem_cache *s = get_slab(size, flags);
- if (s)
- return slab_alloc(s, flags, -1, __builtin_return_address(0));
- return ZERO_SIZE_PTR;
+ if (ZERO_OR_NULL_PTR(s))
+ return s;
+
+ return slab_alloc(s, flags, -1, __builtin_return_address(0));
}
EXPORT_SYMBOL(__kmalloc);
@@ -2253,9 +2381,10 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node)
{
struct kmem_cache *s = get_slab(size, flags);
- if (s)
- return slab_alloc(s, flags, node, __builtin_return_address(0));
- return ZERO_SIZE_PTR;
+ if (ZERO_OR_NULL_PTR(s))
+ return s;
+
+ return slab_alloc(s, flags, node, __builtin_return_address(0));
}
EXPORT_SYMBOL(__kmalloc_node);
#endif
@@ -2265,7 +2394,7 @@ size_t ksize(const void *object)
struct page *page;
struct kmem_cache *s;
- if (object == ZERO_SIZE_PTR)
+ if (ZERO_OR_NULL_PTR(object))
return 0;
page = get_object_page(object);
@@ -2306,7 +2435,7 @@ void kfree(const void *x)
* this comparison would be true for all "negative" pointers
* (which would cover the whole upper half of the address space).
*/
- if ((unsigned long)x <= (unsigned long)ZERO_SIZE_PTR)
+ if (ZERO_OR_NULL_PTR(x))
return;
page = virt_to_head_page(x);
@@ -2395,43 +2524,6 @@ int kmem_cache_shrink(struct kmem_cache *s)
}
EXPORT_SYMBOL(kmem_cache_shrink);
-/**
- * krealloc - reallocate memory. The contents will remain unchanged.
- * @p: object to reallocate memory for.
- * @new_size: how many bytes of memory are required.
- * @flags: the type of memory to allocate.
- *
- * The contents of the object pointed to are preserved up to the
- * lesser of the new and old sizes. If @p is %NULL, krealloc()
- * behaves exactly like kmalloc(). If @size is 0 and @p is not a
- * %NULL pointer, the object pointed to is freed.
- */
-void *krealloc(const void *p, size_t new_size, gfp_t flags)
-{
- void *ret;
- size_t ks;
-
- if (unlikely(!p || p == ZERO_SIZE_PTR))
- return kmalloc(new_size, flags);
-
- if (unlikely(!new_size)) {
- kfree(p);
- return ZERO_SIZE_PTR;
- }
-
- ks = ksize(p);
- if (ks >= new_size)
- return (void *)p;
-
- ret = kmalloc(new_size, flags);
- if (ret) {
- memcpy(ret, p, min(new_size, ks));
- kfree(p);
- }
- return ret;
-}
-EXPORT_SYMBOL(krealloc);
-
/********************************************************************
* Basic setup of slabs
*******************************************************************/
@@ -2474,6 +2566,24 @@ void __init kmem_cache_init(void)
caches++;
}
+
+ /*
+ * Patch up the size_index table if we have strange large alignment
+ * requirements for the kmalloc array. This is only the case for
+ * mips it seems. The standard arches will not generate any code here.
+ *
+ * Largest permitted alignment is 256 bytes due to the way we
+ * handle the index determination for the smaller caches.
+ *
+ * Make sure that nothing crazy happens if someone starts tinkering
+ * around with ARCH_KMALLOC_MINALIGN
+ */
+ BUILD_BUG_ON(KMALLOC_MIN_SIZE > 256 ||
+ (KMALLOC_MIN_SIZE & (KMALLOC_MIN_SIZE - 1)));
+
+ for (i = 8; i < KMALLOC_MIN_SIZE; i += 8)
+ size_index[(i - 1) / 8] = KMALLOC_SHIFT_LOW;
+
slab_state = UP;
/* Provide the correct kmalloc names now that the caches are up */
@@ -2519,7 +2629,7 @@ static struct kmem_cache *find_mergeable(size_t size,
size_t align, unsigned long flags,
void (*ctor)(void *, struct kmem_cache *, unsigned long))
{
- struct list_head *h;
+ struct kmem_cache *s;
if (slub_nomerge || (flags & SLUB_NEVER_MERGE))
return NULL;
@@ -2531,10 +2641,7 @@ static struct kmem_cache *find_mergeable(size_t size,
align = calculate_alignment(flags, align, size);
size = ALIGN(size, align);
- list_for_each(h, &slab_caches) {
- struct kmem_cache *s =
- container_of(h, struct kmem_cache, list);
-
+ list_for_each_entry(s, &slab_caches, list) {
if (slab_unmergeable(s))
continue;
@@ -2561,12 +2668,10 @@ static struct kmem_cache *find_mergeable(size_t size,
struct kmem_cache *kmem_cache_create(const char *name, size_t size,
size_t align, unsigned long flags,
- void (*ctor)(void *, struct kmem_cache *, unsigned long),
- void (*dtor)(void *, struct kmem_cache *, unsigned long))
+ void (*ctor)(void *, struct kmem_cache *, unsigned long))
{
struct kmem_cache *s;
- BUG_ON(dtor);
down_write(&slub_lock);
s = find_mergeable(size, align, flags, ctor);
if (s) {
@@ -2577,25 +2682,26 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
*/
s->objsize = max(s->objsize, (int)size);
s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
+ up_write(&slub_lock);
if (sysfs_slab_alias(s, name))
goto err;
- } else {
- s = kmalloc(kmem_size, GFP_KERNEL);
- if (s && kmem_cache_open(s, GFP_KERNEL, name,
+ return s;
+ }
+ s = kmalloc(kmem_size, GFP_KERNEL);
+ if (s) {
+ if (kmem_cache_open(s, GFP_KERNEL, name,
size, align, flags, ctor)) {
- if (sysfs_slab_add(s)) {
- kfree(s);
- goto err;
- }
list_add(&s->list, &slab_caches);
- } else
- kfree(s);
+ up_write(&slub_lock);
+ if (sysfs_slab_add(s))
+ goto err;
+ return s;
+ }
+ kfree(s);
}
up_write(&slub_lock);
- return s;
err:
- up_write(&slub_lock);
if (flags & SLAB_PANIC)
panic("Cannot create slabcache %s\n", name);
else
@@ -2604,45 +2710,7 @@ err:
}
EXPORT_SYMBOL(kmem_cache_create);
-void *kmem_cache_zalloc(struct kmem_cache *s, gfp_t flags)
-{
- void *x;
-
- x = slab_alloc(s, flags, -1, __builtin_return_address(0));
- if (x)
- memset(x, 0, s->objsize);
- return x;
-}
-EXPORT_SYMBOL(kmem_cache_zalloc);
-
#ifdef CONFIG_SMP
-static void for_all_slabs(void (*func)(struct kmem_cache *, int), int cpu)
-{
- struct list_head *h;
-
- down_read(&slub_lock);
- list_for_each(h, &slab_caches) {
- struct kmem_cache *s =
- container_of(h, struct kmem_cache, list);
-
- func(s, cpu);
- }
- up_read(&slub_lock);
-}
-
-/*
- * Version of __flush_cpu_slab for the case that interrupts
- * are enabled.
- */
-static void cpu_slab_flush(struct kmem_cache *s, int cpu)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- __flush_cpu_slab(s, cpu);
- local_irq_restore(flags);
-}
-
/*
* Use the cpu notifier to insure that the cpu slabs are flushed when
* necessary.
@@ -2651,13 +2719,21 @@ static int __cpuinit slab_cpuup_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
long cpu = (long)hcpu;
+ struct kmem_cache *s;
+ unsigned long flags;
switch (action) {
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
- for_all_slabs(cpu_slab_flush, cpu);
+ down_read(&slub_lock);
+ list_for_each_entry(s, &slab_caches, list) {
+ local_irq_save(flags);
+ __flush_cpu_slab(s, cpu);
+ local_irq_restore(flags);
+ }
+ up_read(&slub_lock);
break;
default:
break;
@@ -2674,8 +2750,8 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller)
{
struct kmem_cache *s = get_slab(size, gfpflags);
- if (!s)
- return ZERO_SIZE_PTR;
+ if (ZERO_OR_NULL_PTR(s))
+ return s;
return slab_alloc(s, gfpflags, -1, caller);
}
@@ -2685,18 +2761,18 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
{
struct kmem_cache *s = get_slab(size, gfpflags);
- if (!s)
- return ZERO_SIZE_PTR;
+ if (ZERO_OR_NULL_PTR(s))
+ return s;
return slab_alloc(s, gfpflags, node, caller);
}
#if defined(CONFIG_SYSFS) && defined(CONFIG_SLUB_DEBUG)
-static int validate_slab(struct kmem_cache *s, struct page *page)
+static int validate_slab(struct kmem_cache *s, struct page *page,
+ unsigned long *map)
{
void *p;
void *addr = page_address(page);
- DECLARE_BITMAP(map, s->objects);
if (!check_slab(s, page) ||
!on_freelist(s, page, NULL))
@@ -2718,10 +2794,11 @@ static int validate_slab(struct kmem_cache *s, struct page *page)
return 1;
}
-static void validate_slab_slab(struct kmem_cache *s, struct page *page)
+static void validate_slab_slab(struct kmem_cache *s, struct page *page,
+ unsigned long *map)
{
if (slab_trylock(page)) {
- validate_slab(s, page);
+ validate_slab(s, page, map);
slab_unlock(page);
} else
printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
@@ -2738,7 +2815,8 @@ static void validate_slab_slab(struct kmem_cache *s, struct page *page)
}
}
-static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
+static int validate_slab_node(struct kmem_cache *s,
+ struct kmem_cache_node *n, unsigned long *map)
{
unsigned long count = 0;
struct page *page;
@@ -2747,7 +2825,7 @@ static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
spin_lock_irqsave(&n->list_lock, flags);
list_for_each_entry(page, &n->partial, lru) {
- validate_slab_slab(s, page);
+ validate_slab_slab(s, page, map);
count++;
}
if (count != n->nr_partial)
@@ -2758,7 +2836,7 @@ static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
goto out;
list_for_each_entry(page, &n->full, lru) {
- validate_slab_slab(s, page);
+ validate_slab_slab(s, page, map);
count++;
}
if (count != atomic_long_read(&n->nr_slabs))
@@ -2771,17 +2849,23 @@ out:
return count;
}
-static unsigned long validate_slab_cache(struct kmem_cache *s)
+static long validate_slab_cache(struct kmem_cache *s)
{
int node;
unsigned long count = 0;
+ unsigned long *map = kmalloc(BITS_TO_LONGS(s->objects) *
+ sizeof(unsigned long), GFP_KERNEL);
+
+ if (!map)
+ return -ENOMEM;
flush_all(s);
for_each_online_node(node) {
struct kmem_cache_node *n = get_node(s, node);
- count += validate_slab_node(s, n);
+ count += validate_slab_node(s, n, map);
}
+ kfree(map);
return count;
}
@@ -2870,18 +2954,14 @@ static void free_loc_track(struct loc_track *t)
get_order(sizeof(struct location) * t->max));
}
-static int alloc_loc_track(struct loc_track *t, unsigned long max)
+static int alloc_loc_track(struct loc_track *t, unsigned long max, gfp_t flags)
{
struct location *l;
int order;
- if (!max)
- max = PAGE_SIZE / sizeof(struct location);
-
order = get_order(sizeof(struct location) * max);
- l = (void *)__get_free_pages(GFP_ATOMIC, order);
-
+ l = (void *)__get_free_pages(flags, order);
if (!l)
return 0;
@@ -2947,7 +3027,7 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
/*
* Not found. Insert new tracking element.
*/
- if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max))
+ if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max, GFP_ATOMIC))
return 0;
l = t->loc + pos;
@@ -2990,11 +3070,12 @@ static int list_locations(struct kmem_cache *s, char *buf,
{
int n = 0;
unsigned long i;
- struct loc_track t;
+ struct loc_track t = { 0, 0, NULL };
int node;
- t.count = 0;
- t.max = 0;
+ if (!alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location),
+ GFP_KERNEL))
+ return sprintf(buf, "Out of memory\n");
/* Push back cpu slabs */
flush_all(s);
@@ -3398,11 +3479,14 @@ static ssize_t validate_show(struct kmem_cache *s, char *buf)
static ssize_t validate_store(struct kmem_cache *s,
const char *buf, size_t length)
{
- if (buf[0] == '1')
- validate_slab_cache(s);
- else
- return -EINVAL;
- return length;
+ int ret = -EINVAL;
+
+ if (buf[0] == '1') {
+ ret = validate_slab_cache(s);
+ if (ret >= 0)
+ ret = length;
+ }
+ return ret;
}
SLAB_ATTR(validate);
@@ -3556,7 +3640,7 @@ static struct kset_uevent_ops slab_uevent_ops = {
.filter = uevent_filter,
};
-decl_subsys(slab, &slab_ktype, &slab_uevent_ops);
+static decl_subsys(slab, &slab_ktype, &slab_uevent_ops);
#define ID_STR_LENGTH 64
@@ -3654,7 +3738,7 @@ struct saved_alias {
struct saved_alias *next;
};
-struct saved_alias *alias_list;
+static struct saved_alias *alias_list;
static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
{
@@ -3682,7 +3766,7 @@ static int sysfs_slab_alias(struct kmem_cache *s, const char *name)
static int __init slab_sysfs_init(void)
{
- struct list_head *h;
+ struct kmem_cache *s;
int err;
err = subsystem_register(&slab_subsys);
@@ -3693,10 +3777,7 @@ static int __init slab_sysfs_init(void)
slab_state = SYSFS;
- list_for_each(h, &slab_caches) {
- struct kmem_cache *s =
- container_of(h, struct kmem_cache, list);
-
+ list_for_each_entry(s, &slab_caches, list) {
err = sysfs_slab_add(s);
BUG_ON(err);
}
diff --git a/mm/sparse.c b/mm/sparse.c
index e03b39f3540f..3047bf06c1f3 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -209,7 +209,7 @@ static int __meminit sparse_init_one_section(struct mem_section *ms,
return 1;
}
-__attribute__((weak))
+__attribute__((weak)) __init
void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
{
return NULL;
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 5f7cf2a4cb55..67daecb6031a 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -21,7 +21,7 @@
/*
* swapper_space is a fiction, retained to simplify the path through
- * vmscan's shrink_list, to make sync_page look nicer, and to allow
+ * vmscan's shrink_page_list, to make sync_page look nicer, and to allow
* future use of radix_tree tags in the swap cache.
*/
static const struct address_space_operations swap_aops = {
@@ -334,7 +334,8 @@ struct page *read_swap_cache_async(swp_entry_t entry,
* Get a new page to read into from swap.
*/
if (!new_page) {
- new_page = alloc_page_vma(GFP_HIGHUSER, vma, addr);
+ new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE,
+ vma, addr);
if (!new_page)
break; /* Out of memory */
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index acc172cbe3aa..7ff0a81c7b01 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -885,7 +885,7 @@ static int try_to_unuse(unsigned int type)
/*
* So we could skip searching mms once swap count went
* to 1, we did not mark any present ptes as dirty: must
- * mark page dirty so shrink_list will preserve it.
+ * mark page dirty so shrink_page_list will preserve it.
*/
SetPageDirty(page);
unlock_page(page);
diff --git a/mm/truncate.c b/mm/truncate.c
index 4fbe1a2da5fb..5cdfbc1a59fd 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -82,7 +82,7 @@ EXPORT_SYMBOL(cancel_dirty_page);
/*
* If truncate cannot remove the fs-private metadata from the page, the page
* becomes anonymous. It will be left on the LRU and may even be mapped into
- * user pagetables if we're racing with filemap_nopage().
+ * user pagetables if we're racing with filemap_fault().
*
* We need to bale out if page->mapping is no longer equal to the original
* mapping. This happens a) when the VM reclaimed the page while we waited on
@@ -100,9 +100,9 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
if (PagePrivate(page))
do_invalidatepage(page, 0);
+ remove_from_page_cache(page);
ClearPageUptodate(page);
ClearPageMappedToDisk(page);
- remove_from_page_cache(page);
page_cache_release(page); /* pagecache ref */
}
@@ -192,6 +192,11 @@ void truncate_inode_pages_range(struct address_space *mapping,
unlock_page(page);
continue;
}
+ if (page_mapped(page)) {
+ unmap_mapping_range(mapping,
+ (loff_t)page_index<<PAGE_CACHE_SHIFT,
+ PAGE_CACHE_SIZE, 0);
+ }
truncate_complete_page(mapping, page);
unlock_page(page);
}
@@ -229,6 +234,11 @@ void truncate_inode_pages_range(struct address_space *mapping,
break;
lock_page(page);
wait_on_page_writeback(page);
+ if (page_mapped(page)) {
+ unmap_mapping_range(mapping,
+ (loff_t)page->index<<PAGE_CACHE_SHIFT,
+ PAGE_CACHE_SIZE, 0);
+ }
if (page->index > next)
next = page->index;
next++;
@@ -253,21 +263,8 @@ void truncate_inode_pages(struct address_space *mapping, loff_t lstart)
}
EXPORT_SYMBOL(truncate_inode_pages);
-/**
- * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode
- * @mapping: the address_space which holds the pages to invalidate
- * @start: the offset 'from' which to invalidate
- * @end: the offset 'to' which to invalidate (inclusive)
- *
- * This function only removes the unlocked pages, if you want to
- * remove all the pages of one inode, you must call truncate_inode_pages.
- *
- * invalidate_mapping_pages() will not block on IO activity. It will not
- * invalidate pages which are dirty, locked, under writeback or mapped into
- * pagetables.
- */
-unsigned long invalidate_mapping_pages(struct address_space *mapping,
- pgoff_t start, pgoff_t end)
+unsigned long __invalidate_mapping_pages(struct address_space *mapping,
+ pgoff_t start, pgoff_t end, bool be_atomic)
{
struct pagevec pvec;
pgoff_t next = start;
@@ -308,17 +305,38 @@ unlock:
break;
}
pagevec_release(&pvec);
+ if (likely(!be_atomic))
+ cond_resched();
}
return ret;
}
+
+/**
+ * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode
+ * @mapping: the address_space which holds the pages to invalidate
+ * @start: the offset 'from' which to invalidate
+ * @end: the offset 'to' which to invalidate (inclusive)
+ *
+ * This function only removes the unlocked pages, if you want to
+ * remove all the pages of one inode, you must call truncate_inode_pages.
+ *
+ * invalidate_mapping_pages() will not block on IO activity. It will not
+ * invalidate pages which are dirty, locked, under writeback or mapped into
+ * pagetables.
+ */
+unsigned long invalidate_mapping_pages(struct address_space *mapping,
+ pgoff_t start, pgoff_t end)
+{
+ return __invalidate_mapping_pages(mapping, start, end, false);
+}
EXPORT_SYMBOL(invalidate_mapping_pages);
/*
* This is like invalidate_complete_page(), except it ignores the page's
* refcount. We do this because invalidate_inode_pages2() needs stronger
* invalidation guarantees, and cannot afford to leave pages behind because
- * shrink_list() has a temp ref on them, or because they're transiently sitting
- * in the lru_cache_add() pagevecs.
+ * shrink_page_list() has a temp ref on them, or because they're transiently
+ * sitting in the lru_cache_add() pagevecs.
*/
static int
invalidate_complete_page2(struct address_space *mapping, struct page *page)
@@ -397,7 +415,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
break;
}
wait_on_page_writeback(page);
- while (page_mapped(page)) {
+ if (page_mapped(page)) {
if (!did_range_unmap) {
/*
* Zap the rest of the file in one hit.
@@ -417,6 +435,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
PAGE_CACHE_SIZE, 0);
}
}
+ BUG_ON(page_mapped(page));
ret = do_launder_page(mapping, page);
if (ret == 0 && !invalidate_complete_page2(mapping, page))
ret = -EIO;
diff --git a/mm/util.c b/mm/util.c
index ace2aea69f1a..bf340d806868 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -5,22 +5,7 @@
#include <asm/uaccess.h>
/**
- * __kzalloc - allocate memory. The memory is set to zero.
- * @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate.
- */
-void *__kzalloc(size_t size, gfp_t flags)
-{
- void *ret = kmalloc_track_caller(size, flags);
- if (ret)
- memset(ret, 0, size);
- return ret;
-}
-EXPORT_SYMBOL(__kzalloc);
-
-/*
* kstrdup - allocate space for and copy an existing string
- *
* @s: the string to duplicate
* @gfp: the GFP mask used in the kmalloc() call when allocating memory
*/
@@ -41,6 +26,30 @@ char *kstrdup(const char *s, gfp_t gfp)
EXPORT_SYMBOL(kstrdup);
/**
+ * kstrndup - allocate space for and copy an existing string
+ * @s: the string to duplicate
+ * @max: read at most @max chars from @s
+ * @gfp: the GFP mask used in the kmalloc() call when allocating memory
+ */
+char *kstrndup(const char *s, size_t max, gfp_t gfp)
+{
+ size_t len;
+ char *buf;
+
+ if (!s)
+ return NULL;
+
+ len = strnlen(s, max);
+ buf = kmalloc_track_caller(len+1, gfp);
+ if (buf) {
+ memcpy(buf, s, len);
+ buf[len] = '\0';
+ }
+ return buf;
+}
+EXPORT_SYMBOL(kstrndup);
+
+/**
* kmemdup - duplicate region of memory
*
* @src: memory region to duplicate
@@ -58,9 +67,42 @@ void *kmemdup(const void *src, size_t len, gfp_t gfp)
}
EXPORT_SYMBOL(kmemdup);
+/**
+ * krealloc - reallocate memory. The contents will remain unchanged.
+ * @p: object to reallocate memory for.
+ * @new_size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate.
+ *
+ * The contents of the object pointed to are preserved up to the
+ * lesser of the new and old sizes. If @p is %NULL, krealloc()
+ * behaves exactly like kmalloc(). If @size is 0 and @p is not a
+ * %NULL pointer, the object pointed to is freed.
+ */
+void *krealloc(const void *p, size_t new_size, gfp_t flags)
+{
+ void *ret;
+ size_t ks;
+
+ if (unlikely(!new_size)) {
+ kfree(p);
+ return ZERO_SIZE_PTR;
+ }
+
+ ks = ksize(p);
+ if (ks >= new_size)
+ return (void *)p;
+
+ ret = kmalloc_track_caller(new_size, flags);
+ if (ret) {
+ memcpy(ret, p, min(new_size, ks));
+ kfree(p);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(krealloc);
+
/*
* strndup_user - duplicate an existing string from user space
- *
* @s: The string to duplicate
* @n: Maximum number of bytes to copy, including the trailing NUL.
*/
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index d3a9c5368257..3cee76a8c9f0 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -68,12 +68,12 @@ static inline void vunmap_pud_range(pgd_t *pgd, unsigned long addr,
} while (pud++, addr = next, addr != end);
}
-void unmap_vm_area(struct vm_struct *area)
+void unmap_kernel_range(unsigned long addr, unsigned long size)
{
pgd_t *pgd;
unsigned long next;
- unsigned long addr = (unsigned long) area->addr;
- unsigned long end = addr + area->size;
+ unsigned long start = addr;
+ unsigned long end = addr + size;
BUG_ON(addr >= end);
pgd = pgd_offset_k(addr);
@@ -84,7 +84,12 @@ void unmap_vm_area(struct vm_struct *area)
continue;
vunmap_pud_range(pgd, addr, next);
} while (pgd++, addr = next, addr != end);
- flush_tlb_kernel_range((unsigned long) area->addr, end);
+ flush_tlb_kernel_range(start, end);
+}
+
+static void unmap_vm_area(struct vm_struct *area)
+{
+ unmap_kernel_range((unsigned long)area->addr, area->size);
}
static int vmap_pte_range(pmd_t *pmd, unsigned long addr,
@@ -159,6 +164,7 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
flush_cache_vmap((unsigned long) area->addr, end);
return err;
}
+EXPORT_SYMBOL_GPL(map_vm_area);
static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end,
@@ -237,6 +243,7 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
{
return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL);
}
+EXPORT_SYMBOL_GPL(__get_vm_area);
/**
* get_vm_area - reserve a contingous kernel virtual area
@@ -427,11 +434,12 @@ void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
area->nr_pages = nr_pages;
/* Please note that the recursion is strictly bounded. */
if (array_size > PAGE_SIZE) {
- pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);
+ pages = __vmalloc_node(array_size, gfp_mask | __GFP_ZERO,
+ PAGE_KERNEL, node);
area->flags |= VM_VPAGES;
} else {
pages = kmalloc_node(array_size,
- (gfp_mask & GFP_LEVEL_MASK),
+ (gfp_mask & GFP_LEVEL_MASK) | __GFP_ZERO,
node);
}
area->pages = pages;
@@ -440,7 +448,6 @@ void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
kfree(area);
return NULL;
}
- memset(area->pages, 0, array_size);
for (i = 0; i < area->nr_pages; i++) {
if (node < 0)
@@ -578,9 +585,9 @@ void *vmalloc_exec(unsigned long size)
}
#if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
-#define GFP_VMALLOC32 GFP_DMA32
+#define GFP_VMALLOC32 GFP_DMA32 | GFP_KERNEL
#elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)
-#define GFP_VMALLOC32 GFP_DMA
+#define GFP_VMALLOC32 GFP_DMA | GFP_KERNEL
#else
#define GFP_VMALLOC32 GFP_KERNEL
#endif
@@ -762,3 +769,56 @@ EXPORT_SYMBOL(remap_vmalloc_range);
void __attribute__((weak)) vmalloc_sync_all(void)
{
}
+
+
+static int f(pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
+{
+ /* apply_to_page_range() does all the hard work. */
+ return 0;
+}
+
+/**
+ * alloc_vm_area - allocate a range of kernel address space
+ * @size: size of the area
+ * @returns: NULL on failure, vm_struct on success
+ *
+ * This function reserves a range of kernel address space, and
+ * allocates pagetables to map that range. No actual mappings
+ * are created. If the kernel address space is not shared
+ * between processes, it syncs the pagetable across all
+ * processes.
+ */
+struct vm_struct *alloc_vm_area(size_t size)
+{
+ struct vm_struct *area;
+
+ area = get_vm_area(size, VM_IOREMAP);
+ if (area == NULL)
+ return NULL;
+
+ /*
+ * This ensures that page tables are constructed for this region
+ * of kernel virtual address space and mapped into init_mm.
+ */
+ if (apply_to_page_range(&init_mm, (unsigned long)area->addr,
+ area->size, f, NULL)) {
+ free_vm_area(area);
+ return NULL;
+ }
+
+ /* Make sure the pagetables are constructed in process kernel
+ mappings */
+ vmalloc_sync_all();
+
+ return area;
+}
+EXPORT_SYMBOL_GPL(alloc_vm_area);
+
+void free_vm_area(struct vm_struct *area)
+{
+ struct vm_struct *ret;
+ ret = remove_vm_area(area->addr);
+ BUG_ON(ret != area);
+ kfree(area);
+}
+EXPORT_SYMBOL_GPL(free_vm_area);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 1be5a6376ef0..d419e10e3daa 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -66,17 +66,8 @@ struct scan_control {
int swappiness;
int all_unreclaimable;
-};
-/*
- * The list of shrinker callbacks used by to apply pressure to
- * ageable caches.
- */
-struct shrinker {
- shrinker_t shrinker;
- struct list_head list;
- int seeks; /* seeks to recreate an obj */
- long nr; /* objs pending delete */
+ int order;
};
#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru))
@@ -121,34 +112,25 @@ static DECLARE_RWSEM(shrinker_rwsem);
/*
* Add a shrinker callback to be called from the vm
*/
-struct shrinker *set_shrinker(int seeks, shrinker_t theshrinker)
+void register_shrinker(struct shrinker *shrinker)
{
- struct shrinker *shrinker;
-
- shrinker = kmalloc(sizeof(*shrinker), GFP_KERNEL);
- if (shrinker) {
- shrinker->shrinker = theshrinker;
- shrinker->seeks = seeks;
- shrinker->nr = 0;
- down_write(&shrinker_rwsem);
- list_add_tail(&shrinker->list, &shrinker_list);
- up_write(&shrinker_rwsem);
- }
- return shrinker;
+ shrinker->nr = 0;
+ down_write(&shrinker_rwsem);
+ list_add_tail(&shrinker->list, &shrinker_list);
+ up_write(&shrinker_rwsem);
}
-EXPORT_SYMBOL(set_shrinker);
+EXPORT_SYMBOL(register_shrinker);
/*
* Remove one
*/
-void remove_shrinker(struct shrinker *shrinker)
+void unregister_shrinker(struct shrinker *shrinker)
{
down_write(&shrinker_rwsem);
list_del(&shrinker->list);
up_write(&shrinker_rwsem);
- kfree(shrinker);
}
-EXPORT_SYMBOL(remove_shrinker);
+EXPORT_SYMBOL(unregister_shrinker);
#define SHRINK_BATCH 128
/*
@@ -185,7 +167,7 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
list_for_each_entry(shrinker, &shrinker_list, list) {
unsigned long long delta;
unsigned long total_scan;
- unsigned long max_pass = (*shrinker->shrinker)(0, gfp_mask);
+ unsigned long max_pass = (*shrinker->shrink)(0, gfp_mask);
delta = (4 * scanned) / shrinker->seeks;
delta *= max_pass;
@@ -213,8 +195,8 @@ unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
int shrink_ret;
int nr_before;
- nr_before = (*shrinker->shrinker)(0, gfp_mask);
- shrink_ret = (*shrinker->shrinker)(this_scan, gfp_mask);
+ nr_before = (*shrinker->shrink)(0, gfp_mask);
+ shrink_ret = (*shrinker->shrink)(this_scan, gfp_mask);
if (shrink_ret == -1)
break;
if (shrink_ret < nr_before)
@@ -481,7 +463,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
referenced = page_referenced(page, 1);
/* In active use or really unfreeable? Activate it. */
- if (referenced && page_mapping_inuse(page))
+ if (sc->order <= PAGE_ALLOC_COSTLY_ORDER &&
+ referenced && page_mapping_inuse(page))
goto activate_locked;
#ifdef CONFIG_SWAP
@@ -514,7 +497,7 @@ static unsigned long shrink_page_list(struct list_head *page_list,
}
if (PageDirty(page)) {
- if (referenced)
+ if (sc->order <= PAGE_ALLOC_COSTLY_ORDER && referenced)
goto keep_locked;
if (!may_enter_fs)
goto keep_locked;
@@ -598,6 +581,51 @@ keep:
return nr_reclaimed;
}
+/* LRU Isolation modes. */
+#define ISOLATE_INACTIVE 0 /* Isolate inactive pages. */
+#define ISOLATE_ACTIVE 1 /* Isolate active pages. */
+#define ISOLATE_BOTH 2 /* Isolate both active and inactive pages. */
+
+/*
+ * Attempt to remove the specified page from its LRU. Only take this page
+ * if it is of the appropriate PageActive status. Pages which are being
+ * freed elsewhere are also ignored.
+ *
+ * page: page to consider
+ * mode: one of the LRU isolation modes defined above
+ *
+ * returns 0 on success, -ve errno on failure.
+ */
+static int __isolate_lru_page(struct page *page, int mode)
+{
+ int ret = -EINVAL;
+
+ /* Only take pages on the LRU. */
+ if (!PageLRU(page))
+ return ret;
+
+ /*
+ * When checking the active state, we need to be sure we are
+ * dealing with comparible boolean values. Take the logical not
+ * of each.
+ */
+ if (mode != ISOLATE_BOTH && (!PageActive(page) != !mode))
+ return ret;
+
+ ret = -EBUSY;
+ if (likely(get_page_unless_zero(page))) {
+ /*
+ * Be careful not to clear PageLRU until after we're
+ * sure the page is not being freed elsewhere -- the
+ * page release code relies on it.
+ */
+ ClearPageLRU(page);
+ ret = 0;
+ }
+
+ return ret;
+}
+
/*
* zone->lru_lock is heavily contended. Some of the functions that
* shrink the lists perform better by taking out a batch of pages
@@ -612,38 +640,90 @@ keep:
* @src: The LRU list to pull pages off.
* @dst: The temp list to put pages on to.
* @scanned: The number of pages that were scanned.
+ * @order: The caller's attempted allocation order
+ * @mode: One of the LRU isolation modes
*
* returns how many pages were moved onto *@dst.
*/
static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
struct list_head *src, struct list_head *dst,
- unsigned long *scanned)
+ unsigned long *scanned, int order, int mode)
{
unsigned long nr_taken = 0;
- struct page *page;
unsigned long scan;
for (scan = 0; scan < nr_to_scan && !list_empty(src); scan++) {
- struct list_head *target;
+ struct page *page;
+ unsigned long pfn;
+ unsigned long end_pfn;
+ unsigned long page_pfn;
+ int zone_id;
+
page = lru_to_page(src);
prefetchw_prev_lru_page(page, src, flags);
VM_BUG_ON(!PageLRU(page));
- list_del(&page->lru);
- target = src;
- if (likely(get_page_unless_zero(page))) {
- /*
- * Be careful not to clear PageLRU until after we're
- * sure the page is not being freed elsewhere -- the
- * page release code relies on it.
- */
- ClearPageLRU(page);
- target = dst;
+ switch (__isolate_lru_page(page, mode)) {
+ case 0:
+ list_move(&page->lru, dst);
nr_taken++;
- } /* else it is being freed elsewhere */
+ break;
+
+ case -EBUSY:
+ /* else it is being freed elsewhere */
+ list_move(&page->lru, src);
+ continue;
+
+ default:
+ BUG();
+ }
+
+ if (!order)
+ continue;
- list_add(&page->lru, target);
+ /*
+ * Attempt to take all pages in the order aligned region
+ * surrounding the tag page. Only take those pages of
+ * the same active state as that tag page. We may safely
+ * round the target page pfn down to the requested order
+ * as the mem_map is guarenteed valid out to MAX_ORDER,
+ * where that page is in a different zone we will detect
+ * it from its zone id and abort this block scan.
+ */
+ zone_id = page_zone_id(page);
+ page_pfn = page_to_pfn(page);
+ pfn = page_pfn & ~((1 << order) - 1);
+ end_pfn = pfn + (1 << order);
+ for (; pfn < end_pfn; pfn++) {
+ struct page *cursor_page;
+
+ /* The target page is in the block, ignore it. */
+ if (unlikely(pfn == page_pfn))
+ continue;
+
+ /* Avoid holes within the zone. */
+ if (unlikely(!pfn_valid_within(pfn)))
+ break;
+
+ cursor_page = pfn_to_page(pfn);
+ /* Check that we have not crossed a zone boundary. */
+ if (unlikely(page_zone_id(cursor_page) != zone_id))
+ continue;
+ switch (__isolate_lru_page(cursor_page, mode)) {
+ case 0:
+ list_move(&cursor_page->lru, dst);
+ nr_taken++;
+ scan++;
+ break;
+
+ case -EBUSY:
+ /* else it is being freed elsewhere */
+ list_move(&cursor_page->lru, src);
+ default:
+ break;
+ }
+ }
}
*scanned = scan;
@@ -651,6 +731,24 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan,
}
/*
+ * clear_active_flags() is a helper for shrink_active_list(), clearing
+ * any active bits from the pages in the list.
+ */
+static unsigned long clear_active_flags(struct list_head *page_list)
+{
+ int nr_active = 0;
+ struct page *page;
+
+ list_for_each_entry(page, page_list, lru)
+ if (PageActive(page)) {
+ ClearPageActive(page);
+ nr_active++;
+ }
+
+ return nr_active;
+}
+
+/*
* shrink_inactive_list() is a helper for shrink_zone(). It returns the number
* of reclaimed pages
*/
@@ -671,11 +769,18 @@ static unsigned long shrink_inactive_list(unsigned long max_scan,
unsigned long nr_taken;
unsigned long nr_scan;
unsigned long nr_freed;
+ unsigned long nr_active;
nr_taken = isolate_lru_pages(sc->swap_cluster_max,
- &zone->inactive_list,
- &page_list, &nr_scan);
- __mod_zone_page_state(zone, NR_INACTIVE, -nr_taken);
+ &zone->inactive_list,
+ &page_list, &nr_scan, sc->order,
+ (sc->order > PAGE_ALLOC_COSTLY_ORDER)?
+ ISOLATE_BOTH : ISOLATE_INACTIVE);
+ nr_active = clear_active_flags(&page_list);
+
+ __mod_zone_page_state(zone, NR_ACTIVE, -nr_active);
+ __mod_zone_page_state(zone, NR_INACTIVE,
+ -(nr_taken - nr_active));
zone->pages_scanned += nr_scan;
spin_unlock_irq(&zone->lru_lock);
@@ -820,7 +925,7 @@ force_reclaim_mapped:
lru_add_drain();
spin_lock_irq(&zone->lru_lock);
pgmoved = isolate_lru_pages(nr_pages, &zone->active_list,
- &l_hold, &pgscanned);
+ &l_hold, &pgscanned, sc->order, ISOLATE_ACTIVE);
zone->pages_scanned += pgscanned;
__mod_zone_page_state(zone, NR_ACTIVE, -pgmoved);
spin_unlock_irq(&zone->lru_lock);
@@ -1011,7 +1116,7 @@ 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.
*/
-unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask)
+unsigned long try_to_free_pages(struct zone **zones, int order, gfp_t gfp_mask)
{
int priority;
int ret = 0;
@@ -1026,6 +1131,7 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask)
.swap_cluster_max = SWAP_CLUSTER_MAX,
.may_swap = 1,
.swappiness = vm_swappiness,
+ .order = order,
};
count_vm_event(ALLOCSTALL);
@@ -1131,6 +1237,7 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order)
.may_swap = 1,
.swap_cluster_max = SWAP_CLUSTER_MAX,
.swappiness = vm_swappiness,
+ .order = order,
};
/*
* temp_priority is used to remember the scanning priority at which
@@ -1314,6 +1421,7 @@ static int kswapd(void *p)
* trying to free the first piece of memory in the first place).
*/
tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD;
+ set_freezable();
order = 0;
for ( ; ; ) {
diff --git a/mm/vmstat.c b/mm/vmstat.c
index eceaf496210f..fadf791cd7e6 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -472,7 +472,7 @@ const struct seq_operations fragmentation_op = {
#endif
#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \
- TEXT_FOR_HIGHMEM(xx)
+ TEXT_FOR_HIGHMEM(xx) xx "_movable",
static const char * const vmstat_text[] = {
/* Zoned VM counters */
diff --git a/net/802/tr.c b/net/802/tr.c
index 0ba1946211c9..e56e61a7f545 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -567,7 +567,7 @@ static int rif_seq_show(struct seq_file *seq, void *v)
}
-static struct seq_operations rif_seq_ops = {
+static const struct seq_operations rif_seq_ops = {
.start = rif_seq_start,
.next = rif_seq_next,
.stop = rif_seq_stop,
diff --git a/net/8021q/Makefile b/net/8021q/Makefile
index 97feb44dbdce..10ca7f486c3a 100644
--- a/net/8021q/Makefile
+++ b/net/8021q/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_VLAN_8021Q) += 8021q.o
-8021q-objs := vlan.o vlan_dev.o
+8021q-objs := vlan.o vlan_dev.o vlan_netlink.o
ifeq ($(CONFIG_PROC_FS),y)
8021q-objs += vlanproc.o
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index de78c9dd713b..cda936b77d22 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -97,35 +97,22 @@ static int __init vlan_proto_init(void)
/* Register us to receive netdevice events */
err = register_netdevice_notifier(&vlan_notifier_block);
- if (err < 0) {
- dev_remove_pack(&vlan_packet_type);
- vlan_proc_cleanup();
- return err;
- }
+ if (err < 0)
+ goto err1;
- vlan_ioctl_set(vlan_ioctl_handler);
+ err = vlan_netlink_init();
+ if (err < 0)
+ goto err2;
+ vlan_ioctl_set(vlan_ioctl_handler);
return 0;
-}
-
-/* Cleanup all vlan devices
- * Note: devices that have been registered that but not
- * brought up will exist but have no module ref count.
- */
-static void __exit vlan_cleanup_devices(void)
-{
- struct net_device *dev, *nxt;
-
- rtnl_lock();
- for_each_netdev_safe(dev, nxt) {
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
- VLAN_DEV_INFO(dev)->vlan_id);
- unregister_netdevice(dev);
- }
- }
- rtnl_unlock();
+err2:
+ unregister_netdevice_notifier(&vlan_notifier_block);
+err1:
+ vlan_proc_cleanup();
+ dev_remove_pack(&vlan_packet_type);
+ return err;
}
/*
@@ -136,13 +123,13 @@ static void __exit vlan_cleanup_module(void)
{
int i;
+ vlan_netlink_fini();
vlan_ioctl_set(NULL);
/* Un-register us from receiving netdevice events */
unregister_netdevice_notifier(&vlan_notifier_block);
dev_remove_pack(&vlan_packet_type);
- vlan_cleanup_devices();
/* This table must be empty if there are no module
* references left.
@@ -197,6 +184,34 @@ static void vlan_group_free(struct vlan_group *grp)
kfree(grp);
}
+static struct vlan_group *vlan_group_alloc(int ifindex)
+{
+ struct vlan_group *grp;
+ unsigned int size;
+ unsigned int i;
+
+ grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
+ if (!grp)
+ return NULL;
+
+ size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN;
+
+ for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {
+ grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL);
+ if (!grp->vlan_devices_arrays[i])
+ goto err;
+ }
+
+ grp->real_dev_ifindex = ifindex;
+ hlist_add_head_rcu(&grp->hlist,
+ &vlan_group_hash[vlan_grp_hashfn(ifindex)]);
+ return grp;
+
+err:
+ vlan_group_free(grp);
+ return NULL;
+}
+
static void vlan_rcu_free(struct rcu_head *rcu)
{
vlan_group_free(container_of(rcu, struct vlan_group, rcu));
@@ -278,50 +293,66 @@ static int unregister_vlan_dev(struct net_device *real_dev,
return ret;
}
-static int unregister_vlan_device(const char *vlan_IF_name)
+int unregister_vlan_device(struct net_device *dev)
{
- struct net_device *dev = NULL;
int ret;
+ ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
+ VLAN_DEV_INFO(dev)->vlan_id);
+ unregister_netdevice(dev);
- dev = dev_get_by_name(vlan_IF_name);
- ret = -EINVAL;
- if (dev) {
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- rtnl_lock();
+ if (ret == 1)
+ ret = 0;
+ return ret;
+}
- ret = unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
- VLAN_DEV_INFO(dev)->vlan_id);
+/*
+ * vlan network devices have devices nesting below it, and are a special
+ * "super class" of normal network devices; split their locks off into a
+ * separate class since they always nest.
+ */
+static struct lock_class_key vlan_netdev_xmit_lock_key;
- dev_put(dev);
- unregister_netdevice(dev);
+static int vlan_dev_init(struct net_device *dev)
+{
+ struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
- rtnl_unlock();
+ /* IFF_BROADCAST|IFF_MULTICAST; ??? */
+ dev->flags = real_dev->flags & ~IFF_UP;
+ dev->iflink = real_dev->ifindex;
+ dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
+ (1<<__LINK_STATE_DORMANT))) |
+ (1<<__LINK_STATE_PRESENT);
- if (ret == 1)
- ret = 0;
- } else {
- printk(VLAN_ERR
- "%s: ERROR: Tried to remove a non-vlan device "
- "with VLAN code, name: %s priv_flags: %hX\n",
- __FUNCTION__, dev->name, dev->priv_flags);
- dev_put(dev);
- ret = -EPERM;
- }
+ if (is_zero_ether_addr(dev->dev_addr))
+ memcpy(dev->dev_addr, real_dev->dev_addr, dev->addr_len);
+ if (is_zero_ether_addr(dev->broadcast))
+ memcpy(dev->broadcast, real_dev->broadcast, dev->addr_len);
+
+ if (real_dev->features & NETIF_F_HW_VLAN_TX) {
+ dev->hard_header = real_dev->hard_header;
+ dev->hard_header_len = real_dev->hard_header_len;
+ dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
+ dev->rebuild_header = real_dev->rebuild_header;
} else {
-#ifdef VLAN_DEBUG
- printk(VLAN_DBG "%s: WARNING: Could not find dev.\n", __FUNCTION__);
-#endif
- ret = -EINVAL;
+ dev->hard_header = vlan_dev_hard_header;
+ dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
+ dev->hard_start_xmit = vlan_dev_hard_start_xmit;
+ dev->rebuild_header = vlan_dev_rebuild_header;
}
+ dev->hard_header_parse = real_dev->hard_header_parse;
+ dev->hard_header_cache = NULL;
- return ret;
+ lockdep_set_class(&dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
+ return 0;
}
-static void vlan_setup(struct net_device *new_dev)
+void vlan_setup(struct net_device *new_dev)
{
SET_MODULE_OWNER(new_dev);
+ ether_setup(new_dev);
+
/* new_dev->ifindex = 0; it will be set when added to
* the global list.
* iflink is set as well.
@@ -338,12 +369,15 @@ static void vlan_setup(struct net_device *new_dev)
/* set up method calls */
new_dev->change_mtu = vlan_dev_change_mtu;
+ new_dev->init = vlan_dev_init;
new_dev->open = vlan_dev_open;
new_dev->stop = vlan_dev_stop;
- new_dev->set_mac_address = vlan_dev_set_mac_address;
new_dev->set_multicast_list = vlan_dev_set_multicast_list;
+ new_dev->change_rx_flags = vlan_change_rx_flags;
new_dev->destructor = free_netdev;
new_dev->do_ioctl = vlan_dev_ioctl;
+
+ memset(new_dev->broadcast, 0, ETH_ALEN);
}
static void vlan_transfer_operstate(const struct net_device *dev, struct net_device *vlandev)
@@ -366,77 +400,110 @@ static void vlan_transfer_operstate(const struct net_device *dev, struct net_dev
}
}
-/*
- * vlan network devices have devices nesting below it, and are a special
- * "super class" of normal network devices; split their locks off into a
- * separate class since they always nest.
- */
-static struct lock_class_key vlan_netdev_xmit_lock_key;
-
-
-/* Attach a VLAN device to a mac address (ie Ethernet Card).
- * Returns the device that was created, or NULL if there was
- * an error of some kind.
- */
-static struct net_device *register_vlan_device(const char *eth_IF_name,
- unsigned short VLAN_ID)
+int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id)
{
- struct vlan_group *grp;
- struct net_device *new_dev;
- struct net_device *real_dev; /* the ethernet device */
- char name[IFNAMSIZ];
- int i;
-
-#ifdef VLAN_DEBUG
- printk(VLAN_DBG "%s: if_name -:%s:- vid: %i\n",
- __FUNCTION__, eth_IF_name, VLAN_ID);
-#endif
-
- if (VLAN_ID >= VLAN_VID_MASK)
- goto out_ret_null;
-
- /* find the device relating to eth_IF_name. */
- real_dev = dev_get_by_name(eth_IF_name);
- if (!real_dev)
- goto out_ret_null;
-
if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
printk(VLAN_DBG "%s: VLANs not supported on %s.\n",
__FUNCTION__, real_dev->name);
- goto out_put_dev;
+ return -EOPNOTSUPP;
}
if ((real_dev->features & NETIF_F_HW_VLAN_RX) &&
!real_dev->vlan_rx_register) {
printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
__FUNCTION__, real_dev->name);
- goto out_put_dev;
+ return -EOPNOTSUPP;
}
if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
(!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) {
printk(VLAN_DBG "%s: Device %s has buggy VLAN hw accel.\n",
__FUNCTION__, real_dev->name);
- goto out_put_dev;
+ return -EOPNOTSUPP;
}
- /* From this point on, all the data structures must remain
- * consistent.
- */
- rtnl_lock();
-
/* The real device must be up and operating in order to
* assosciate a VLAN device with it.
*/
if (!(real_dev->flags & IFF_UP))
- goto out_unlock;
+ return -ENETDOWN;
- if (__find_vlan_dev(real_dev, VLAN_ID) != NULL) {
+ if (__find_vlan_dev(real_dev, vlan_id) != NULL) {
/* was already registered. */
printk(VLAN_DBG "%s: ALREADY had VLAN registered\n", __FUNCTION__);
- goto out_unlock;
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+int register_vlan_dev(struct net_device *dev)
+{
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+ struct net_device *real_dev = vlan->real_dev;
+ unsigned short vlan_id = vlan->vlan_id;
+ struct vlan_group *grp, *ngrp = NULL;
+ int err;
+
+ grp = __vlan_find_group(real_dev->ifindex);
+ if (!grp) {
+ ngrp = grp = vlan_group_alloc(real_dev->ifindex);
+ if (!grp)
+ return -ENOBUFS;
}
+ err = register_netdevice(dev);
+ if (err < 0)
+ goto out_free_group;
+
+ /* Account for reference in struct vlan_dev_info */
+ dev_hold(real_dev);
+
+ vlan_transfer_operstate(real_dev, dev);
+ linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
+
+ /* So, got the sucker initialized, now lets place
+ * it into our local structure.
+ */
+ vlan_group_set_device(grp, vlan_id, dev);
+ if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX)
+ real_dev->vlan_rx_register(real_dev, ngrp);
+ if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
+ real_dev->vlan_rx_add_vid(real_dev, vlan_id);
+
+ if (vlan_proc_add_dev(dev) < 0)
+ printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
+ dev->name);
+ return 0;
+
+out_free_group:
+ if (ngrp)
+ vlan_group_free(ngrp);
+ return err;
+}
+
+/* Attach a VLAN device to a mac address (ie Ethernet Card).
+ * Returns 0 if the device was created or a negative error code otherwise.
+ */
+static int register_vlan_device(struct net_device *real_dev,
+ unsigned short VLAN_ID)
+{
+ struct net_device *new_dev;
+ char name[IFNAMSIZ];
+ int err;
+
+#ifdef VLAN_DEBUG
+ printk(VLAN_DBG "%s: if_name -:%s:- vid: %i\n",
+ __FUNCTION__, eth_IF_name, VLAN_ID);
+#endif
+
+ if (VLAN_ID >= VLAN_VID_MASK)
+ return -ERANGE;
+
+ err = vlan_check_real_dev(real_dev, VLAN_ID);
+ if (err < 0)
+ return err;
+
/* Gotta set up the fields for the device. */
#ifdef VLAN_DEBUG
printk(VLAN_DBG "About to allocate name, vlan_name_type: %i\n",
@@ -471,138 +538,64 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
vlan_setup);
if (new_dev == NULL)
- goto out_unlock;
-
-#ifdef VLAN_DEBUG
- printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
-#endif
- /* IFF_BROADCAST|IFF_MULTICAST; ??? */
- new_dev->flags = real_dev->flags;
- new_dev->flags &= ~IFF_UP;
-
- new_dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
- (1<<__LINK_STATE_DORMANT))) |
- (1<<__LINK_STATE_PRESENT);
+ return -ENOBUFS;
/* need 4 bytes for extra VLAN header info,
* hope the underlying device can handle it.
*/
new_dev->mtu = real_dev->mtu;
- /* TODO: maybe just assign it to be ETHERNET? */
- new_dev->type = real_dev->type;
-
- new_dev->hard_header_len = real_dev->hard_header_len;
- if (!(real_dev->features & NETIF_F_HW_VLAN_TX)) {
- /* Regular ethernet + 4 bytes (18 total). */
- new_dev->hard_header_len += VLAN_HLEN;
- }
-
+#ifdef VLAN_DEBUG
+ printk(VLAN_DBG "Allocated new name -:%s:-\n", new_dev->name);
VLAN_MEM_DBG("new_dev->priv malloc, addr: %p size: %i\n",
new_dev->priv,
sizeof(struct vlan_dev_info));
-
- memcpy(new_dev->broadcast, real_dev->broadcast, real_dev->addr_len);
- memcpy(new_dev->dev_addr, real_dev->dev_addr, real_dev->addr_len);
- new_dev->addr_len = real_dev->addr_len;
-
- if (real_dev->features & NETIF_F_HW_VLAN_TX) {
- new_dev->hard_header = real_dev->hard_header;
- new_dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit;
- new_dev->rebuild_header = real_dev->rebuild_header;
- } else {
- new_dev->hard_header = vlan_dev_hard_header;
- new_dev->hard_start_xmit = vlan_dev_hard_start_xmit;
- new_dev->rebuild_header = vlan_dev_rebuild_header;
- }
- new_dev->hard_header_parse = real_dev->hard_header_parse;
+#endif
VLAN_DEV_INFO(new_dev)->vlan_id = VLAN_ID; /* 1 through VLAN_VID_MASK */
VLAN_DEV_INFO(new_dev)->real_dev = real_dev;
VLAN_DEV_INFO(new_dev)->dent = NULL;
- VLAN_DEV_INFO(new_dev)->flags = 1;
+ VLAN_DEV_INFO(new_dev)->flags = VLAN_FLAG_REORDER_HDR;
-#ifdef VLAN_DEBUG
- printk(VLAN_DBG "About to go find the group for idx: %i\n",
- real_dev->ifindex);
-#endif
-
- if (register_netdevice(new_dev))
+ new_dev->rtnl_link_ops = &vlan_link_ops;
+ err = register_vlan_dev(new_dev);
+ if (err < 0)
goto out_free_newdev;
- lockdep_set_class(&new_dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
-
- new_dev->iflink = real_dev->ifindex;
- vlan_transfer_operstate(real_dev, new_dev);
- linkwatch_fire_event(new_dev); /* _MUST_ call rfc2863_policy() */
-
- /* So, got the sucker initialized, now lets place
- * it into our local structure.
- */
- grp = __vlan_find_group(real_dev->ifindex);
-
- /* Note, we are running under the RTNL semaphore
- * so it cannot "appear" on us.
- */
- if (!grp) { /* need to add a new group */
- grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL);
- if (!grp)
- goto out_free_unregister;
-
- for (i=0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) {
- grp->vlan_devices_arrays[i] = kzalloc(
- sizeof(struct net_device *)*VLAN_GROUP_ARRAY_PART_LEN,
- GFP_KERNEL);
-
- if (!grp->vlan_devices_arrays[i])
- goto out_free_arrays;
- }
-
- /* printk(KERN_ALERT "VLAN REGISTER: Allocated new group.\n"); */
- grp->real_dev_ifindex = real_dev->ifindex;
-
- hlist_add_head_rcu(&grp->hlist,
- &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]);
-
- if (real_dev->features & NETIF_F_HW_VLAN_RX)
- real_dev->vlan_rx_register(real_dev, grp);
- }
-
- vlan_group_set_device(grp, VLAN_ID, new_dev);
-
- if (vlan_proc_add_dev(new_dev)<0)/* create it's proc entry */
- printk(KERN_WARNING "VLAN: failed to add proc entry for %s\n",
- new_dev->name);
-
- if (real_dev->features & NETIF_F_HW_VLAN_FILTER)
- real_dev->vlan_rx_add_vid(real_dev, VLAN_ID);
-
- rtnl_unlock();
-
-
+ /* Account for reference in struct vlan_dev_info */
+ dev_hold(real_dev);
#ifdef VLAN_DEBUG
printk(VLAN_DBG "Allocated new device successfully, returning.\n");
#endif
- return new_dev;
-
-out_free_arrays:
- vlan_group_free(grp);
-
-out_free_unregister:
- unregister_netdev(new_dev);
- goto out_unlock;
+ return 0;
out_free_newdev:
free_netdev(new_dev);
+ return err;
+}
-out_unlock:
- rtnl_unlock();
+static void vlan_sync_address(struct net_device *dev,
+ struct net_device *vlandev)
+{
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(vlandev);
-out_put_dev:
- dev_put(real_dev);
+ /* May be called without an actual change */
+ if (!compare_ether_addr(vlan->real_dev_addr, dev->dev_addr))
+ return;
-out_ret_null:
- return NULL;
+ /* vlan address was different from the old address and is equal to
+ * the new address */
+ if (compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
+ !compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
+ dev_unicast_delete(dev, vlandev->dev_addr, ETH_ALEN);
+
+ /* vlan address was equal to the old address and is different from
+ * the new address */
+ if (!compare_ether_addr(vlandev->dev_addr, vlan->real_dev_addr) &&
+ compare_ether_addr(vlandev->dev_addr, dev->dev_addr))
+ dev_unicast_add(dev, vlandev->dev_addr, ETH_ALEN);
+
+ memcpy(vlan->real_dev_addr, dev->dev_addr, ETH_ALEN);
}
static int vlan_device_event(struct notifier_block *unused, unsigned long event, void *ptr)
@@ -631,6 +624,17 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
}
break;
+ case NETDEV_CHANGEADDR:
+ /* Adjust unicast filters on underlying device */
+ for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+ vlandev = vlan_group_get_device(grp, i);
+ if (!vlandev)
+ continue;
+
+ vlan_sync_address(dev, vlandev);
+ }
+ break;
+
case NETDEV_DOWN:
/* Put all VLANs for this dev in the down state too. */
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
@@ -693,9 +697,10 @@ out:
*/
static int vlan_ioctl_handler(void __user *arg)
{
- int err = 0;
+ int err;
unsigned short vid = 0;
struct vlan_ioctl_args args;
+ struct net_device *dev = NULL;
if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args)))
return -EFAULT;
@@ -708,35 +713,61 @@ static int vlan_ioctl_handler(void __user *arg)
printk(VLAN_DBG "%s: args.cmd: %x\n", __FUNCTION__, args.cmd);
#endif
+ rtnl_lock();
+
+ switch (args.cmd) {
+ case SET_VLAN_INGRESS_PRIORITY_CMD:
+ case SET_VLAN_EGRESS_PRIORITY_CMD:
+ case SET_VLAN_FLAG_CMD:
+ case ADD_VLAN_CMD:
+ case DEL_VLAN_CMD:
+ case GET_VLAN_REALDEV_NAME_CMD:
+ case GET_VLAN_VID_CMD:
+ err = -ENODEV;
+ dev = __dev_get_by_name(args.device1);
+ if (!dev)
+ goto out;
+
+ err = -EINVAL;
+ if (args.cmd != ADD_VLAN_CMD &&
+ !(dev->priv_flags & IFF_802_1Q_VLAN))
+ goto out;
+ }
+
switch (args.cmd) {
case SET_VLAN_INGRESS_PRIORITY_CMD:
+ err = -EPERM;
if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- err = vlan_dev_set_ingress_priority(args.device1,
- args.u.skb_priority,
- args.vlan_qos);
+ break;
+ vlan_dev_set_ingress_priority(dev,
+ args.u.skb_priority,
+ args.vlan_qos);
break;
case SET_VLAN_EGRESS_PRIORITY_CMD:
+ err = -EPERM;
if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- err = vlan_dev_set_egress_priority(args.device1,
+ break;
+ err = vlan_dev_set_egress_priority(dev,
args.u.skb_priority,
args.vlan_qos);
break;
case SET_VLAN_FLAG_CMD:
+ err = -EPERM;
if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- err = vlan_dev_set_vlan_flag(args.device1,
+ break;
+ err = vlan_dev_set_vlan_flag(dev,
args.u.flag,
args.vlan_qos);
break;
case SET_VLAN_NAME_TYPE_CMD:
+ err = -EPERM;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (args.u.name_type < VLAN_NAME_TYPE_HIGHEST) {
+ if ((args.u.name_type >= 0) &&
+ (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) {
vlan_name_type = args.u.name_type;
err = 0;
} else {
@@ -745,26 +776,17 @@ static int vlan_ioctl_handler(void __user *arg)
break;
case ADD_VLAN_CMD:
+ err = -EPERM;
if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- /* we have been given the name of the Ethernet Device we want to
- * talk to: args.dev1 We also have the
- * VLAN ID: args.u.VID
- */
- if (register_vlan_device(args.device1, args.u.VID)) {
- err = 0;
- } else {
- err = -EINVAL;
- }
+ break;
+ err = register_vlan_device(dev, args.u.VID);
break;
case DEL_VLAN_CMD:
+ err = -EPERM;
if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- /* Here, the args.dev1 is the actual VLAN we want
- * to get rid of.
- */
- err = unregister_vlan_device(args.device1);
+ break;
+ err = unregister_vlan_device(dev);
break;
case GET_VLAN_INGRESS_PRIORITY_CMD:
@@ -788,9 +810,7 @@ static int vlan_ioctl_handler(void __user *arg)
err = -EINVAL;
break;
case GET_VLAN_REALDEV_NAME_CMD:
- err = vlan_dev_get_realdev_name(args.device1, args.u.device2);
- if (err)
- goto out;
+ vlan_dev_get_realdev_name(dev, args.u.device2);
if (copy_to_user(arg, &args,
sizeof(struct vlan_ioctl_args))) {
err = -EFAULT;
@@ -798,9 +818,7 @@ static int vlan_ioctl_handler(void __user *arg)
break;
case GET_VLAN_VID_CMD:
- err = vlan_dev_get_vid(args.device1, &vid);
- if (err)
- goto out;
+ vlan_dev_get_vid(dev, &vid);
args.u.VID = vid;
if (copy_to_user(arg, &args,
sizeof(struct vlan_ioctl_args))) {
@@ -812,9 +830,11 @@ static int vlan_ioctl_handler(void __user *arg)
/* pass on to underlying device instead?? */
printk(VLAN_DBG "%s: Unknown VLAN CMD: %x \n",
__FUNCTION__, args.cmd);
- return -EINVAL;
+ err = -EINVAL;
+ break;
}
out:
+ rtnl_unlock();
return err;
}
diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h
index 1976cdba8f72..7df5b2935579 100644
--- a/net/8021q/vlan.h
+++ b/net/8021q/vlan.h
@@ -58,15 +58,28 @@ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev);
int vlan_dev_change_mtu(struct net_device *dev, int new_mtu);
-int vlan_dev_set_mac_address(struct net_device *dev, void* addr);
int vlan_dev_open(struct net_device* dev);
int vlan_dev_stop(struct net_device* dev);
int vlan_dev_ioctl(struct net_device* dev, struct ifreq *ifr, int cmd);
-int vlan_dev_set_ingress_priority(char* dev_name, __u32 skb_prio, short vlan_prio);
-int vlan_dev_set_egress_priority(char* dev_name, __u32 skb_prio, short vlan_prio);
-int vlan_dev_set_vlan_flag(char* dev_name, __u32 flag, short flag_val);
-int vlan_dev_get_realdev_name(const char* dev_name, char* result);
-int vlan_dev_get_vid(const char* dev_name, unsigned short* result);
+void vlan_dev_set_ingress_priority(const struct net_device *dev,
+ u32 skb_prio, short vlan_prio);
+int vlan_dev_set_egress_priority(const struct net_device *dev,
+ u32 skb_prio, short vlan_prio);
+int vlan_dev_set_vlan_flag(const struct net_device *dev,
+ u32 flag, short flag_val);
+void vlan_dev_get_realdev_name(const struct net_device *dev, char *result);
+void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result);
+void vlan_change_rx_flags(struct net_device *dev, int change);
void vlan_dev_set_multicast_list(struct net_device *vlan_dev);
+int vlan_check_real_dev(struct net_device *real_dev, unsigned short vlan_id);
+void vlan_setup(struct net_device *dev);
+int register_vlan_dev(struct net_device *dev);
+int unregister_vlan_device(struct net_device *dev);
+
+int vlan_netlink_init(void);
+void vlan_netlink_fini(void);
+
+extern struct rtnl_link_ops vlan_link_ops;
+
#endif /* !(__BEN_VLAN_802_1Q_INC__) */
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index ec46084f44b4..4d2aa4dd42ac 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -73,7 +73,7 @@ int vlan_dev_rebuild_header(struct sk_buff *skb)
static inline struct sk_buff *vlan_check_reorder_header(struct sk_buff *skb)
{
- if (VLAN_DEV_INFO(skb->dev)->flags & 1) {
+ if (VLAN_DEV_INFO(skb->dev)->flags & VLAN_FLAG_REORDER_HDR) {
if (skb_shared(skb) || skb_cloned(skb)) {
struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC);
kfree_skb(skb);
@@ -350,7 +350,8 @@ int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
* header shuffling in the hard_start_xmit. Users can turn off this
* REORDER behaviour with the vconfig tool.
*/
- build_vlan_header = ((VLAN_DEV_INFO(dev)->flags & 1) == 0);
+ if (!(VLAN_DEV_INFO(dev)->flags & VLAN_FLAG_REORDER_HDR))
+ build_vlan_header = 1;
if (build_vlan_header) {
vhdr = (struct vlan_hdr *) skb_push(skb, VLAN_HLEN);
@@ -534,272 +535,123 @@ int vlan_dev_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
-int vlan_dev_set_ingress_priority(char *dev_name, __u32 skb_prio, short vlan_prio)
+void vlan_dev_set_ingress_priority(const struct net_device *dev,
+ u32 skb_prio, short vlan_prio)
{
- struct net_device *dev = dev_get_by_name(dev_name);
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
- if (dev) {
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- /* see if a priority mapping exists.. */
- VLAN_DEV_INFO(dev)->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
- dev_put(dev);
- return 0;
- }
+ if (vlan->ingress_priority_map[vlan_prio & 0x7] && !skb_prio)
+ vlan->nr_ingress_mappings--;
+ else if (!vlan->ingress_priority_map[vlan_prio & 0x7] && skb_prio)
+ vlan->nr_ingress_mappings++;
- dev_put(dev);
- }
- return -EINVAL;
+ vlan->ingress_priority_map[vlan_prio & 0x7] = skb_prio;
}
-int vlan_dev_set_egress_priority(char *dev_name, __u32 skb_prio, short vlan_prio)
+int vlan_dev_set_egress_priority(const struct net_device *dev,
+ u32 skb_prio, short vlan_prio)
{
- struct net_device *dev = dev_get_by_name(dev_name);
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
struct vlan_priority_tci_mapping *mp = NULL;
struct vlan_priority_tci_mapping *np;
+ u32 vlan_qos = (vlan_prio << 13) & 0xE000;
- if (dev) {
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- /* See if a priority mapping exists.. */
- mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
- while (mp) {
- if (mp->priority == skb_prio) {
- mp->vlan_qos = ((vlan_prio << 13) & 0xE000);
- dev_put(dev);
- return 0;
- }
- mp = mp->next;
- }
-
- /* Create a new mapping then. */
- mp = VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF];
- np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
- if (np) {
- np->next = mp;
- np->priority = skb_prio;
- np->vlan_qos = ((vlan_prio << 13) & 0xE000);
- VLAN_DEV_INFO(dev)->egress_priority_map[skb_prio & 0xF] = np;
- dev_put(dev);
- return 0;
- } else {
- dev_put(dev);
- return -ENOBUFS;
- }
- }
- dev_put(dev);
- }
- return -EINVAL;
-}
-
-/* Flags are defined in the vlan_dev_info class in include/linux/if_vlan.h file. */
-int vlan_dev_set_vlan_flag(char *dev_name, __u32 flag, short flag_val)
-{
- struct net_device *dev = dev_get_by_name(dev_name);
-
- if (dev) {
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- /* verify flag is supported */
- if (flag == 1) {
- if (flag_val) {
- VLAN_DEV_INFO(dev)->flags |= 1;
- } else {
- VLAN_DEV_INFO(dev)->flags &= ~1;
- }
- dev_put(dev);
- return 0;
- } else {
- printk(KERN_ERR "%s: flag %i is not valid.\n",
- __FUNCTION__, (int)(flag));
- dev_put(dev);
- return -EINVAL;
- }
- } else {
- printk(KERN_ERR
- "%s: %s is not a vlan device, priv_flags: %hX.\n",
- __FUNCTION__, dev->name, dev->priv_flags);
- dev_put(dev);
+ /* See if a priority mapping exists.. */
+ mp = vlan->egress_priority_map[skb_prio & 0xF];
+ while (mp) {
+ if (mp->priority == skb_prio) {
+ if (mp->vlan_qos && !vlan_qos)
+ vlan->nr_egress_mappings--;
+ else if (!mp->vlan_qos && vlan_qos)
+ vlan->nr_egress_mappings++;
+ mp->vlan_qos = vlan_qos;
+ return 0;
}
- } else {
- printk(KERN_ERR "%s: Could not find device: %s\n",
- __FUNCTION__, dev_name);
+ mp = mp->next;
}
- return -EINVAL;
-}
-
-
-int vlan_dev_get_realdev_name(const char *dev_name, char* result)
-{
- struct net_device *dev = dev_get_by_name(dev_name);
- int rv = 0;
- if (dev) {
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23);
- rv = 0;
- } else {
- rv = -EINVAL;
- }
- dev_put(dev);
- } else {
- rv = -ENODEV;
- }
- return rv;
+ /* Create a new mapping then. */
+ mp = vlan->egress_priority_map[skb_prio & 0xF];
+ np = kmalloc(sizeof(struct vlan_priority_tci_mapping), GFP_KERNEL);
+ if (!np)
+ return -ENOBUFS;
+
+ np->next = mp;
+ np->priority = skb_prio;
+ np->vlan_qos = vlan_qos;
+ vlan->egress_priority_map[skb_prio & 0xF] = np;
+ if (vlan_qos)
+ vlan->nr_egress_mappings++;
+ return 0;
}
-int vlan_dev_get_vid(const char *dev_name, unsigned short* result)
+/* Flags are defined in the vlan_flags enum in include/linux/if_vlan.h file. */
+int vlan_dev_set_vlan_flag(const struct net_device *dev,
+ u32 flag, short flag_val)
{
- struct net_device *dev = dev_get_by_name(dev_name);
- int rv = 0;
- if (dev) {
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- *result = VLAN_DEV_INFO(dev)->vlan_id;
- rv = 0;
+ /* verify flag is supported */
+ if (flag == VLAN_FLAG_REORDER_HDR) {
+ if (flag_val) {
+ VLAN_DEV_INFO(dev)->flags |= VLAN_FLAG_REORDER_HDR;
} else {
- rv = -EINVAL;
+ VLAN_DEV_INFO(dev)->flags &= ~VLAN_FLAG_REORDER_HDR;
}
- dev_put(dev);
- } else {
- rv = -ENODEV;
+ return 0;
}
- return rv;
+ printk(KERN_ERR "%s: flag %i is not valid.\n", __FUNCTION__, flag);
+ return -EINVAL;
}
-
-int vlan_dev_set_mac_address(struct net_device *dev, void *addr_struct_p)
+void vlan_dev_get_realdev_name(const struct net_device *dev, char *result)
{
- struct sockaddr *addr = (struct sockaddr *)(addr_struct_p);
- int i;
-
- if (netif_running(dev))
- return -EBUSY;
-
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-
- printk("%s: Setting MAC address to ", dev->name);
- for (i = 0; i < 6; i++)
- printk(" %2.2x", dev->dev_addr[i]);
- printk(".\n");
-
- if (memcmp(VLAN_DEV_INFO(dev)->real_dev->dev_addr,
- dev->dev_addr,
- dev->addr_len) != 0) {
- if (!(VLAN_DEV_INFO(dev)->real_dev->flags & IFF_PROMISC)) {
- int flgs = VLAN_DEV_INFO(dev)->real_dev->flags;
-
- /* Increment our in-use promiscuity counter */
- dev_set_promiscuity(VLAN_DEV_INFO(dev)->real_dev, 1);
-
- /* Make PROMISC visible to the user. */
- flgs |= IFF_PROMISC;
- printk("VLAN (%s): Setting underlying device (%s) to promiscious mode.\n",
- dev->name, VLAN_DEV_INFO(dev)->real_dev->name);
- dev_change_flags(VLAN_DEV_INFO(dev)->real_dev, flgs);
- }
- } else {
- printk("VLAN (%s): Underlying device (%s) has same MAC, not checking promiscious mode.\n",
- dev->name, VLAN_DEV_INFO(dev)->real_dev->name);
- }
-
- return 0;
+ strncpy(result, VLAN_DEV_INFO(dev)->real_dev->name, 23);
}
-static inline int vlan_dmi_equals(struct dev_mc_list *dmi1,
- struct dev_mc_list *dmi2)
+void vlan_dev_get_vid(const struct net_device *dev, unsigned short *result)
{
- return ((dmi1->dmi_addrlen == dmi2->dmi_addrlen) &&
- (memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0));
+ *result = VLAN_DEV_INFO(dev)->vlan_id;
}
-/** dmi is a single entry into a dev_mc_list, a single node. mc_list is
- * an entire list, and we'll iterate through it.
- */
-static int vlan_should_add_mc(struct dev_mc_list *dmi, struct dev_mc_list *mc_list)
+int vlan_dev_open(struct net_device *dev)
{
- struct dev_mc_list *idmi;
-
- for (idmi = mc_list; idmi != NULL; ) {
- if (vlan_dmi_equals(dmi, idmi)) {
- if (dmi->dmi_users > idmi->dmi_users)
- return 1;
- else
- return 0;
- } else {
- idmi = idmi->next;
- }
- }
-
- return 1;
-}
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+ struct net_device *real_dev = vlan->real_dev;
+ int err;
-static inline void vlan_destroy_mc_list(struct dev_mc_list *mc_list)
-{
- struct dev_mc_list *dmi = mc_list;
- struct dev_mc_list *next;
+ if (!(real_dev->flags & IFF_UP))
+ return -ENETDOWN;
- while(dmi) {
- next = dmi->next;
- kfree(dmi);
- dmi = next;
+ if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr)) {
+ err = dev_unicast_add(real_dev, dev->dev_addr, ETH_ALEN);
+ if (err < 0)
+ return err;
}
-}
-
-static void vlan_copy_mc_list(struct dev_mc_list *mc_list, struct vlan_dev_info *vlan_info)
-{
- struct dev_mc_list *dmi, *new_dmi;
+ memcpy(vlan->real_dev_addr, real_dev->dev_addr, ETH_ALEN);
- vlan_destroy_mc_list(vlan_info->old_mc_list);
- vlan_info->old_mc_list = NULL;
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(real_dev, 1);
+ if (dev->flags & IFF_PROMISC)
+ dev_set_promiscuity(real_dev, 1);
- for (dmi = mc_list; dmi != NULL; dmi = dmi->next) {
- new_dmi = kmalloc(sizeof(*new_dmi), GFP_ATOMIC);
- if (new_dmi == NULL) {
- printk(KERN_ERR "vlan: cannot allocate memory. "
- "Multicast may not work properly from now.\n");
- return;
- }
-
- /* Copy whole structure, then make new 'next' pointer */
- *new_dmi = *dmi;
- new_dmi->next = vlan_info->old_mc_list;
- vlan_info->old_mc_list = new_dmi;
- }
+ return 0;
}
-static void vlan_flush_mc_list(struct net_device *dev)
+int vlan_dev_stop(struct net_device *dev)
{
- struct dev_mc_list *dmi = dev->mc_list;
-
- while (dmi) {
- printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from vlan interface\n",
- dev->name,
- dmi->dmi_addr[0],
- dmi->dmi_addr[1],
- dmi->dmi_addr[2],
- dmi->dmi_addr[3],
- dmi->dmi_addr[4],
- dmi->dmi_addr[5]);
- dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
- dmi = dev->mc_list;
- }
+ struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
- /* dev->mc_list is NULL by the time we get here. */
- vlan_destroy_mc_list(VLAN_DEV_INFO(dev)->old_mc_list);
- VLAN_DEV_INFO(dev)->old_mc_list = NULL;
-}
+ dev_mc_unsync(real_dev, dev);
+ if (dev->flags & IFF_ALLMULTI)
+ dev_set_allmulti(real_dev, -1);
+ if (dev->flags & IFF_PROMISC)
+ dev_set_promiscuity(real_dev, -1);
-int vlan_dev_open(struct net_device *dev)
-{
- if (!(VLAN_DEV_INFO(dev)->real_dev->flags & IFF_UP))
- return -ENETDOWN;
+ if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
+ dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len);
return 0;
}
-int vlan_dev_stop(struct net_device *dev)
-{
- vlan_flush_mc_list(dev);
- return 0;
-}
-
int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
@@ -827,68 +679,18 @@ int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return err;
}
-/** Taken from Gleb + Lennert's VLAN code, and modified... */
-void vlan_dev_set_multicast_list(struct net_device *vlan_dev)
+void vlan_change_rx_flags(struct net_device *dev, int change)
{
- struct dev_mc_list *dmi;
- struct net_device *real_dev;
- int inc;
-
- if (vlan_dev && (vlan_dev->priv_flags & IFF_802_1Q_VLAN)) {
- /* Then it's a real vlan device, as far as we can tell.. */
- real_dev = VLAN_DEV_INFO(vlan_dev)->real_dev;
-
- /* compare the current promiscuity to the last promisc we had.. */
- inc = vlan_dev->promiscuity - VLAN_DEV_INFO(vlan_dev)->old_promiscuity;
- if (inc) {
- printk(KERN_INFO "%s: dev_set_promiscuity(master, %d)\n",
- vlan_dev->name, inc);
- dev_set_promiscuity(real_dev, inc); /* found in dev.c */
- VLAN_DEV_INFO(vlan_dev)->old_promiscuity = vlan_dev->promiscuity;
- }
-
- inc = vlan_dev->allmulti - VLAN_DEV_INFO(vlan_dev)->old_allmulti;
- if (inc) {
- printk(KERN_INFO "%s: dev_set_allmulti(master, %d)\n",
- vlan_dev->name, inc);
- dev_set_allmulti(real_dev, inc); /* dev.c */
- VLAN_DEV_INFO(vlan_dev)->old_allmulti = vlan_dev->allmulti;
- }
-
- /* looking for addresses to add to master's list */
- for (dmi = vlan_dev->mc_list; dmi != NULL; dmi = dmi->next) {
- if (vlan_should_add_mc(dmi, VLAN_DEV_INFO(vlan_dev)->old_mc_list)) {
- dev_mc_add(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
- printk(KERN_DEBUG "%s: add %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address to master interface\n",
- vlan_dev->name,
- dmi->dmi_addr[0],
- dmi->dmi_addr[1],
- dmi->dmi_addr[2],
- dmi->dmi_addr[3],
- dmi->dmi_addr[4],
- dmi->dmi_addr[5]);
- }
- }
+ struct net_device *real_dev = VLAN_DEV_INFO(dev)->real_dev;
- /* looking for addresses to delete from master's list */
- for (dmi = VLAN_DEV_INFO(vlan_dev)->old_mc_list; dmi != NULL; dmi = dmi->next) {
- if (vlan_should_add_mc(dmi, vlan_dev->mc_list)) {
- /* if we think we should add it to the new list, then we should really
- * delete it from the real list on the underlying device.
- */
- dev_mc_delete(real_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
- printk(KERN_DEBUG "%s: del %.2x:%.2x:%.2x:%.2x:%.2x:%.2x mcast address from master interface\n",
- vlan_dev->name,
- dmi->dmi_addr[0],
- dmi->dmi_addr[1],
- dmi->dmi_addr[2],
- dmi->dmi_addr[3],
- dmi->dmi_addr[4],
- dmi->dmi_addr[5]);
- }
- }
+ if (change & IFF_ALLMULTI)
+ dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1);
+ if (change & IFF_PROMISC)
+ dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1);
+}
- /* save multicast list */
- vlan_copy_mc_list(vlan_dev->mc_list, VLAN_DEV_INFO(vlan_dev));
- }
+/** Taken from Gleb + Lennert's VLAN code, and modified... */
+void vlan_dev_set_multicast_list(struct net_device *vlan_dev)
+{
+ dev_mc_sync(VLAN_DEV_INFO(vlan_dev)->real_dev, vlan_dev);
}
diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c
new file mode 100644
index 000000000000..6cdd1e015e2d
--- /dev/null
+++ b/net/8021q/vlan_netlink.c
@@ -0,0 +1,243 @@
+/*
+ * VLAN netlink control interface
+ *
+ * Copyright (c) 2007 Patrick McHardy <kaber@trash.net>
+ *
+ * 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/netdevice.h>
+#include <linux/if_vlan.h>
+#include <net/netlink.h>
+#include <net/rtnetlink.h>
+#include "vlan.h"
+
+
+static const struct nla_policy vlan_policy[IFLA_VLAN_MAX + 1] = {
+ [IFLA_VLAN_ID] = { .type = NLA_U16 },
+ [IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) },
+ [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
+ [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
+};
+
+static const struct nla_policy vlan_map_policy[IFLA_VLAN_QOS_MAX + 1] = {
+ [IFLA_VLAN_QOS_MAPPING] = { .len = sizeof(struct ifla_vlan_qos_mapping) },
+};
+
+
+static inline int vlan_validate_qos_map(struct nlattr *attr)
+{
+ if (!attr)
+ return 0;
+ return nla_validate_nested(attr, IFLA_VLAN_QOS_MAX, vlan_map_policy);
+}
+
+static int vlan_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+ struct ifla_vlan_flags *flags;
+ u16 id;
+ int err;
+
+ if (tb[IFLA_ADDRESS]) {
+ if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+ return -EINVAL;
+ if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+ return -EADDRNOTAVAIL;
+ }
+
+ if (!data)
+ return -EINVAL;
+
+ if (data[IFLA_VLAN_ID]) {
+ id = nla_get_u16(data[IFLA_VLAN_ID]);
+ if (id >= VLAN_VID_MASK)
+ return -ERANGE;
+ }
+ if (data[IFLA_VLAN_FLAGS]) {
+ flags = nla_data(data[IFLA_VLAN_FLAGS]);
+ if ((flags->flags & flags->mask) & ~VLAN_FLAG_REORDER_HDR)
+ return -EINVAL;
+ }
+
+ err = vlan_validate_qos_map(data[IFLA_VLAN_INGRESS_QOS]);
+ if (err < 0)
+ return err;
+ err = vlan_validate_qos_map(data[IFLA_VLAN_EGRESS_QOS]);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int vlan_changelink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+ struct ifla_vlan_flags *flags;
+ struct ifla_vlan_qos_mapping *m;
+ struct nlattr *attr;
+ int rem;
+
+ if (data[IFLA_VLAN_FLAGS]) {
+ flags = nla_data(data[IFLA_VLAN_FLAGS]);
+ vlan->flags = (vlan->flags & ~flags->mask) |
+ (flags->flags & flags->mask);
+ }
+ if (data[IFLA_VLAN_INGRESS_QOS]) {
+ nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
+ m = nla_data(attr);
+ vlan_dev_set_ingress_priority(dev, m->to, m->from);
+ }
+ }
+ if (data[IFLA_VLAN_EGRESS_QOS]) {
+ nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
+ m = nla_data(attr);
+ vlan_dev_set_egress_priority(dev, m->from, m->to);
+ }
+ }
+ return 0;
+}
+
+static int vlan_newlink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+ struct net_device *real_dev;
+ int err;
+
+ if (!data[IFLA_VLAN_ID])
+ return -EINVAL;
+
+ if (!tb[IFLA_LINK])
+ return -EINVAL;
+ real_dev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+ if (!real_dev)
+ return -ENODEV;
+
+ vlan->vlan_id = nla_get_u16(data[IFLA_VLAN_ID]);
+ vlan->real_dev = real_dev;
+ vlan->flags = VLAN_FLAG_REORDER_HDR;
+
+ err = vlan_check_real_dev(real_dev, vlan->vlan_id);
+ if (err < 0)
+ return err;
+
+ if (!tb[IFLA_MTU])
+ dev->mtu = real_dev->mtu;
+ else if (dev->mtu > real_dev->mtu)
+ return -EINVAL;
+
+ err = vlan_changelink(dev, tb, data);
+ if (err < 0)
+ return err;
+
+ return register_vlan_dev(dev);
+}
+
+static void vlan_dellink(struct net_device *dev)
+{
+ unregister_vlan_device(dev);
+}
+
+static inline size_t vlan_qos_map_size(unsigned int n)
+{
+ if (n == 0)
+ return 0;
+ /* IFLA_VLAN_{EGRESS,INGRESS}_QOS + n * IFLA_VLAN_QOS_MAPPING */
+ return nla_total_size(sizeof(struct nlattr)) +
+ nla_total_size(sizeof(struct ifla_vlan_qos_mapping)) * n;
+}
+
+static size_t vlan_get_size(const struct net_device *dev)
+{
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+
+ return nla_total_size(2) + /* IFLA_VLAN_ID */
+ vlan_qos_map_size(vlan->nr_ingress_mappings) +
+ vlan_qos_map_size(vlan->nr_egress_mappings);
+}
+
+static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+ struct vlan_dev_info *vlan = VLAN_DEV_INFO(dev);
+ struct vlan_priority_tci_mapping *pm;
+ struct ifla_vlan_flags f;
+ struct ifla_vlan_qos_mapping m;
+ struct nlattr *nest;
+ unsigned int i;
+
+ NLA_PUT_U16(skb, IFLA_VLAN_ID, VLAN_DEV_INFO(dev)->vlan_id);
+ if (vlan->flags) {
+ f.flags = vlan->flags;
+ f.mask = ~0;
+ NLA_PUT(skb, IFLA_VLAN_FLAGS, sizeof(f), &f);
+ }
+ if (vlan->nr_ingress_mappings) {
+ nest = nla_nest_start(skb, IFLA_VLAN_INGRESS_QOS);
+ if (nest == NULL)
+ goto nla_put_failure;
+
+ for (i = 0; i < ARRAY_SIZE(vlan->ingress_priority_map); i++) {
+ if (!vlan->ingress_priority_map[i])
+ continue;
+
+ m.from = i;
+ m.to = vlan->ingress_priority_map[i];
+ NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
+ sizeof(m), &m);
+ }
+ nla_nest_end(skb, nest);
+ }
+
+ if (vlan->nr_egress_mappings) {
+ nest = nla_nest_start(skb, IFLA_VLAN_EGRESS_QOS);
+ if (nest == NULL)
+ goto nla_put_failure;
+
+ for (i = 0; i < ARRAY_SIZE(vlan->egress_priority_map); i++) {
+ for (pm = vlan->egress_priority_map[i]; pm;
+ pm = pm->next) {
+ if (!pm->vlan_qos)
+ continue;
+
+ m.from = pm->priority;
+ m.to = (pm->vlan_qos >> 13) & 0x7;
+ NLA_PUT(skb, IFLA_VLAN_QOS_MAPPING,
+ sizeof(m), &m);
+ }
+ }
+ nla_nest_end(skb, nest);
+ }
+ return 0;
+
+nla_put_failure:
+ return -EMSGSIZE;
+}
+
+struct rtnl_link_ops vlan_link_ops __read_mostly = {
+ .kind = "vlan",
+ .maxtype = IFLA_VLAN_MAX,
+ .policy = vlan_policy,
+ .priv_size = sizeof(struct vlan_dev_info),
+ .setup = vlan_setup,
+ .validate = vlan_validate,
+ .newlink = vlan_newlink,
+ .changelink = vlan_changelink,
+ .dellink = vlan_dellink,
+ .get_size = vlan_get_size,
+ .fill_info = vlan_fill_info,
+};
+
+int __init vlan_netlink_init(void)
+{
+ return rtnl_link_register(&vlan_link_ops);
+}
+
+void __exit vlan_netlink_fini(void)
+{
+ rtnl_link_unregister(&vlan_link_ops);
+}
+
+MODULE_ALIAS_RTNL_LINK("vlan");
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index d216a64421cd..c0040c9064a1 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -69,7 +69,7 @@ static const char name_conf[] = "config";
* Generic /proc/net/vlan/<file> file and inode operations
*/
-static struct seq_operations vlan_seq_ops = {
+static const struct seq_operations vlan_seq_ops = {
.start = vlan_seq_start,
.next = vlan_seq_next,
.stop = vlan_seq_stop,
@@ -342,7 +342,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "Device: %s", dev_info->real_dev->name);
/* now show all PRIORITY mappings relating to this VLAN */
seq_printf(seq,
- "\nINGRESS priority mappings: 0:%lu 1:%lu 2:%lu 3:%lu 4:%lu 5:%lu 6:%lu 7:%lu\n",
+ "\nINGRESS priority mappings: 0:%u 1:%u 2:%u 3:%u 4:%u 5:%u 6:%u 7:%u\n",
dev_info->ingress_priority_map[0],
dev_info->ingress_priority_map[1],
dev_info->ingress_priority_map[2],
@@ -357,7 +357,7 @@ static int vlandev_seq_show(struct seq_file *seq, void *offset)
const struct vlan_priority_tci_mapping *mp
= dev_info->egress_priority_map[i];
while (mp) {
- seq_printf(seq, "%lu:%hu ",
+ seq_printf(seq, "%u:%hu ",
mp->priority, ((mp->vlan_qos >> 13) & 0x7));
mp = mp->next;
}
diff --git a/net/9p/Kconfig b/net/9p/Kconfig
new file mode 100644
index 000000000000..66821cd64a76
--- /dev/null
+++ b/net/9p/Kconfig
@@ -0,0 +1,21 @@
+#
+# 9P protocol configuration
+#
+
+menuconfig NET_9P
+ depends on NET && EXPERIMENTAL
+ tristate "Plan 9 Resource Sharing Support (9P2000) (Experimental)"
+ help
+ If you say Y here, you will get experimental support for
+ Plan 9 resource sharing via the 9P2000 protocol.
+
+ See <http://v9fs.sf.net> for more information.
+
+ If unsure, say N.
+
+config NET_9P_DEBUG
+ bool "Debug information"
+ depends on NET_9P
+ help
+ Say Y if you want the 9P subsistem to log debug information.
+
diff --git a/net/9p/Makefile b/net/9p/Makefile
new file mode 100644
index 000000000000..85b3a7838acf
--- /dev/null
+++ b/net/9p/Makefile
@@ -0,0 +1,13 @@
+obj-$(CONFIG_NET_9P) := 9pnet.o
+
+9pnet-objs := \
+ mod.o \
+ trans_fd.o \
+ mux.o \
+ client.o \
+ conv.o \
+ error.o \
+ fcprint.o \
+ util.o \
+
+9pnet-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/9p/client.c b/net/9p/client.c
new file mode 100644
index 000000000000..cb170750337c
--- /dev/null
+++ b/net/9p/client.c
@@ -0,0 +1,965 @@
+/*
+ * net/9p/clnt.c
+ *
+ * 9P Client
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ * 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:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/idr.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+#include <net/9p/conn.h>
+#include <net/9p/client.h>
+
+static struct p9_fid *p9_fid_create(struct p9_client *clnt);
+static void p9_fid_destroy(struct p9_fid *fid);
+static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu);
+
+struct p9_client *p9_client_create(struct p9_transport *trans, int msize,
+ int dotu)
+{
+ int err, n;
+ struct p9_client *clnt;
+ struct p9_fcall *tc, *rc;
+ struct p9_str *version;
+
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
+ if (!clnt)
+ return ERR_PTR(-ENOMEM);
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p trans %p msize %d dotu %d\n",
+ clnt, trans, msize, dotu);
+ spin_lock_init(&clnt->lock);
+ clnt->trans = trans;
+ clnt->msize = msize;
+ clnt->dotu = dotu;
+ INIT_LIST_HEAD(&clnt->fidlist);
+ clnt->fidpool = p9_idpool_create();
+ if (!clnt->fidpool) {
+ err = PTR_ERR(clnt->fidpool);
+ clnt->fidpool = NULL;
+ goto error;
+ }
+
+ clnt->conn = p9_conn_create(clnt->trans, clnt->msize, &clnt->dotu);
+ if (IS_ERR(clnt->conn)) {
+ err = PTR_ERR(clnt->conn);
+ clnt->conn = NULL;
+ goto error;
+ }
+
+ tc = p9_create_tversion(clnt->msize, clnt->dotu?"9P2000.u":"9P2000");
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ version = &rc->params.rversion.version;
+ if (version->len == 8 && !memcmp(version->str, "9P2000.u", 8))
+ clnt->dotu = 1;
+ else if (version->len == 6 && !memcmp(version->str, "9P2000", 6))
+ clnt->dotu = 0;
+ else {
+ err = -EREMOTEIO;
+ goto error;
+ }
+
+ n = rc->params.rversion.msize;
+ if (n < clnt->msize)
+ clnt->msize = n;
+
+ kfree(tc);
+ kfree(rc);
+ return clnt;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ p9_client_destroy(clnt);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_create);
+
+void p9_client_destroy(struct p9_client *clnt)
+{
+ struct p9_fid *fid, *fidptr;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ if (clnt->conn) {
+ p9_conn_destroy(clnt->conn);
+ clnt->conn = NULL;
+ }
+
+ if (clnt->trans) {
+ clnt->trans->close(clnt->trans);
+ kfree(clnt->trans);
+ clnt->trans = NULL;
+ }
+
+ list_for_each_entry_safe(fid, fidptr, &clnt->fidlist, flist)
+ p9_fid_destroy(fid);
+
+ if (clnt->fidpool)
+ p9_idpool_destroy(clnt->fidpool);
+
+ kfree(clnt);
+}
+EXPORT_SYMBOL(p9_client_destroy);
+
+void p9_client_disconnect(struct p9_client *clnt)
+{
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ clnt->trans->status = Disconnected;
+ p9_conn_cancel(clnt->conn, -EIO);
+}
+EXPORT_SYMBOL(p9_client_disconnect);
+
+struct p9_fid *p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
+ char *uname, char *aname)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p afid %d uname %s aname %s\n",
+ clnt, afid?afid->fid:-1, uname, aname);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+
+ fid = p9_fid_create(clnt);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+
+ tc = p9_create_tattach(fid->fid, afid?afid->fid:P9_NOFID, uname, aname);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ memmove(&fid->qid, &rc->params.rattach.qid, sizeof(struct p9_qid));
+ kfree(tc);
+ kfree(rc);
+ return fid;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ if (fid)
+ p9_fid_destroy(fid);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_attach);
+
+struct p9_fid *p9_client_auth(struct p9_client *clnt, char *uname, char *aname)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p uname %s aname %s\n", clnt, uname,
+ aname);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+
+ fid = p9_fid_create(clnt);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+
+ tc = p9_create_tauth(fid->fid, uname, aname);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ memmove(&fid->qid, &rc->params.rauth.qid, sizeof(struct p9_qid));
+ kfree(tc);
+ kfree(rc);
+ return fid;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ if (fid)
+ p9_fid_destroy(fid);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_auth);
+
+struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
+ int clone)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d nwname %d wname[0] %s\n",
+ oldfid->fid, nwname, wnames?wnames[0]:NULL);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = oldfid->clnt;
+ if (clone) {
+ fid = p9_fid_create(clnt);
+ if (IS_ERR(fid)) {
+ err = PTR_ERR(fid);
+ fid = NULL;
+ goto error;
+ }
+
+ fid->uid = oldfid->uid;
+ } else
+ fid = oldfid;
+
+ tc = p9_create_twalk(oldfid->fid, fid->fid, nwname, wnames);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err) {
+ if (rc && rc->id == P9_RWALK)
+ goto clunk_fid;
+ else
+ goto error;
+ }
+
+ if (rc->params.rwalk.nwqid != nwname) {
+ err = -ENOENT;
+ goto clunk_fid;
+ }
+
+ if (nwname)
+ memmove(&fid->qid,
+ &rc->params.rwalk.wqids[rc->params.rwalk.nwqid - 1],
+ sizeof(struct p9_qid));
+ else
+ fid->qid = oldfid->qid;
+
+ kfree(tc);
+ kfree(rc);
+ return fid;
+
+clunk_fid:
+ kfree(tc);
+ kfree(rc);
+ rc = NULL;
+ tc = p9_create_tclunk(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ p9_conn_rpc(clnt->conn, tc, &rc);
+
+error:
+ kfree(tc);
+ kfree(rc);
+ if (fid && (fid != oldfid))
+ p9_fid_destroy(fid);
+
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_walk);
+
+int p9_client_open(struct p9_fid *fid, int mode)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d mode %d\n", fid->fid, mode);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ if (fid->mode != -1)
+ return -EINVAL;
+
+ tc = p9_create_topen(fid->fid, mode);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ fid->mode = mode;
+ fid->iounit = rc->params.ropen.iounit;
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_open);
+
+int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
+ char *extension)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d name %s perm %d mode %d\n", fid->fid,
+ name, perm, mode);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ if (fid->mode != -1)
+ return -EINVAL;
+
+ tc = p9_create_tcreate(fid->fid, name, perm, mode, extension,
+ clnt->dotu);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ fid->mode = mode;
+ fid->iounit = rc->params.ropen.iounit;
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_fcreate);
+
+int p9_client_clunk(struct p9_fid *fid)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_tclunk(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ p9_fid_destroy(fid);
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_clunk);
+
+int p9_client_remove(struct p9_fid *fid)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_tremove(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto done;
+
+ p9_fid_destroy(fid);
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_remove);
+
+int p9_client_read(struct p9_fid *fid, char *data, u64 offset, u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_tread(fid->fid, offset, rsize);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ if (n > count)
+ n = count;
+
+ memmove(data, rc->params.rread.data, n);
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0 && n == rsize);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_read);
+
+int p9_client_write(struct p9_fid *fid, char *data, u64 offset, u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_twrite(fid->fid, offset, rsize, data);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_write);
+
+int
+p9_client_uread(struct p9_fid *fid, char __user *data, u64 offset, u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_tread(fid->fid, offset, rsize);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ if (n > count)
+ n = count;
+
+ err = copy_to_user(data, rc->params.rread.data, n);
+ if (err) {
+ err = -EFAULT;
+ goto error;
+ }
+
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0 && n == rsize);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_uread);
+
+int
+p9_client_uwrite(struct p9_fid *fid, const char __user *data, u64 offset,
+ u32 count)
+{
+ int err, n, rsize, total;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
+ rsize = clnt->msize - P9_IOHDRSZ;
+
+ do {
+ if (count < rsize)
+ rsize = count;
+
+ tc = p9_create_twrite_u(fid->fid, offset, rsize, data);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ count -= n;
+ data += n;
+ offset += n;
+ total += n;
+ kfree(tc);
+ tc = NULL;
+ kfree(rc);
+ rc = NULL;
+ } while (count > 0);
+
+ return total;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_uwrite);
+
+int p9_client_readn(struct p9_fid *fid, char *data, u64 offset, u32 count)
+{
+ int n, total;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu count %d\n", fid->fid,
+ (long long unsigned) offset, count);
+ n = 0;
+ total = 0;
+ while (count) {
+ n = p9_client_read(fid, data, offset, count);
+ if (n <= 0)
+ break;
+
+ data += n;
+ offset += n;
+ count -= n;
+ total += n;
+ }
+
+ if (n < 0)
+ total = n;
+
+ return total;
+}
+EXPORT_SYMBOL(p9_client_readn);
+
+struct p9_stat *p9_client_stat(struct p9_fid *fid)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+ struct p9_stat *ret;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ ret = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_tstat(fid->fid);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ ret = p9_clone_stat(&rc->params.rstat.stat, clnt->dotu);
+ if (IS_ERR(ret)) {
+ err = PTR_ERR(ret);
+ ret = NULL;
+ goto error;
+ }
+
+ kfree(tc);
+ kfree(rc);
+ return ret;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ kfree(ret);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_stat);
+
+int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst)
+{
+ int err;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ clnt = fid->clnt;
+
+ tc = p9_create_twstat(fid->fid, wst, clnt->dotu);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto done;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return err;
+}
+EXPORT_SYMBOL(p9_client_wstat);
+
+struct p9_stat *p9_client_dirread(struct p9_fid *fid, u64 offset)
+{
+ int err, n, m;
+ struct p9_fcall *tc, *rc;
+ struct p9_client *clnt;
+ struct p9_stat st, *ret;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d offset %llu\n", fid->fid,
+ (long long unsigned) offset);
+ err = 0;
+ tc = NULL;
+ rc = NULL;
+ ret = NULL;
+ clnt = fid->clnt;
+
+ /* if the offset is below or above the current response, free it */
+ if (offset < fid->rdir_fpos || (fid->rdir_fcall &&
+ offset >= fid->rdir_fpos+fid->rdir_fcall->params.rread.count)) {
+ fid->rdir_pos = 0;
+ if (fid->rdir_fcall)
+ fid->rdir_fpos += fid->rdir_fcall->params.rread.count;
+
+ kfree(fid->rdir_fcall);
+ fid->rdir_fcall = NULL;
+ if (offset < fid->rdir_fpos)
+ fid->rdir_fpos = 0;
+ }
+
+ if (!fid->rdir_fcall) {
+ n = fid->iounit;
+ if (!n || n > clnt->msize-P9_IOHDRSZ)
+ n = clnt->msize - P9_IOHDRSZ;
+
+ while (1) {
+ if (fid->rdir_fcall) {
+ fid->rdir_fpos +=
+ fid->rdir_fcall->params.rread.count;
+ kfree(fid->rdir_fcall);
+ fid->rdir_fcall = NULL;
+ }
+
+ tc = p9_create_tread(fid->fid, fid->rdir_fpos, n);
+ if (IS_ERR(tc)) {
+ err = PTR_ERR(tc);
+ tc = NULL;
+ goto error;
+ }
+
+ err = p9_conn_rpc(clnt->conn, tc, &rc);
+ if (err)
+ goto error;
+
+ n = rc->params.rread.count;
+ if (n == 0)
+ goto done;
+
+ fid->rdir_fcall = rc;
+ rc = NULL;
+ if (offset >= fid->rdir_fpos &&
+ offset < fid->rdir_fpos+n)
+ break;
+ }
+
+ fid->rdir_pos = 0;
+ }
+
+ m = offset - fid->rdir_fpos;
+ if (m < 0)
+ goto done;
+
+ n = p9_deserialize_stat(fid->rdir_fcall->params.rread.data + m,
+ fid->rdir_fcall->params.rread.count - m, &st, clnt->dotu);
+
+ if (!n) {
+ err = -EIO;
+ goto error;
+ }
+
+ fid->rdir_pos += n;
+ st.size = n;
+ ret = p9_clone_stat(&st, clnt->dotu);
+ if (IS_ERR(ret)) {
+ err = PTR_ERR(ret);
+ ret = NULL;
+ goto error;
+ }
+
+done:
+ kfree(tc);
+ kfree(rc);
+ return ret;
+
+error:
+ kfree(tc);
+ kfree(rc);
+ kfree(ret);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_client_dirread);
+
+static struct p9_stat *p9_clone_stat(struct p9_stat *st, int dotu)
+{
+ int n;
+ char *p;
+ struct p9_stat *ret;
+
+ n = sizeof(struct p9_stat) + st->name.len + st->uid.len + st->gid.len +
+ st->muid.len;
+
+ if (dotu)
+ n += st->extension.len;
+
+ ret = kmalloc(n, GFP_KERNEL);
+ if (!ret)
+ return ERR_PTR(-ENOMEM);
+
+ memmove(ret, st, sizeof(struct p9_stat));
+ p = ((char *) ret) + sizeof(struct p9_stat);
+ memmove(p, st->name.str, st->name.len);
+ p += st->name.len;
+ memmove(p, st->uid.str, st->uid.len);
+ p += st->uid.len;
+ memmove(p, st->gid.str, st->gid.len);
+ p += st->gid.len;
+ memmove(p, st->muid.str, st->muid.len);
+ p += st->muid.len;
+
+ if (dotu) {
+ memmove(p, st->extension.str, st->extension.len);
+ p += st->extension.len;
+ }
+
+ return ret;
+}
+
+static struct p9_fid *p9_fid_create(struct p9_client *clnt)
+{
+ int err;
+ struct p9_fid *fid;
+
+ P9_DPRINTK(P9_DEBUG_9P, "clnt %p\n", clnt);
+ fid = kmalloc(sizeof(struct p9_fid), GFP_KERNEL);
+ if (!fid)
+ return ERR_PTR(-ENOMEM);
+
+ fid->fid = p9_idpool_get(clnt->fidpool);
+ if (fid->fid < 0) {
+ err = -ENOSPC;
+ goto error;
+ }
+
+ memset(&fid->qid, 0, sizeof(struct p9_qid));
+ fid->mode = -1;
+ fid->rdir_fpos = 0;
+ fid->rdir_pos = 0;
+ fid->rdir_fcall = NULL;
+ fid->uid = current->fsuid;
+ fid->clnt = clnt;
+ fid->aux = NULL;
+
+ spin_lock(&clnt->lock);
+ list_add(&fid->flist, &clnt->fidlist);
+ spin_unlock(&clnt->lock);
+
+ return fid;
+
+error:
+ kfree(fid);
+ return ERR_PTR(err);
+}
+
+static void p9_fid_destroy(struct p9_fid *fid)
+{
+ struct p9_client *clnt;
+
+ P9_DPRINTK(P9_DEBUG_9P, "fid %d\n", fid->fid);
+ clnt = fid->clnt;
+ p9_idpool_put(fid->fid, clnt->fidpool);
+ spin_lock(&clnt->lock);
+ list_del(&fid->flist);
+ spin_unlock(&clnt->lock);
+ kfree(fid->rdir_fcall);
+ kfree(fid);
+}
diff --git a/fs/9p/conv.c b/net/9p/conv.c
index a3ed571eee31..37451178e761 100644
--- a/fs/9p/conv.c
+++ b/net/9p/conv.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/9p/conv.c
+ * net/9p/conv.c
*
* 9P protocol conversion functions
*
@@ -29,11 +29,8 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/idr.h>
-#include <asm/uaccess.h>
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
+#include <linux/uaccess.h>
+#include <net/9p/9p.h>
/*
* Buffer to help with string parsing
@@ -59,8 +56,9 @@ static int buf_check_size(struct cbuf *buf, int len)
{
if (buf->p + len > buf->ep) {
if (buf->p < buf->ep) {
- eprintk(KERN_ERR, "buffer overflow: want %d has %d\n",
- len, (int)(buf->ep - buf->p));
+ P9_EPRINTK(KERN_ERR,
+ "buffer overflow: want %d has %d\n", len,
+ (int)(buf->ep - buf->p));
dump_stack();
buf->p = buf->ep + 1;
}
@@ -183,7 +181,7 @@ static u64 buf_get_int64(struct cbuf *buf)
return ret;
}
-static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
+static void buf_get_str(struct cbuf *buf, struct p9_str *vstr)
{
vstr->len = buf_get_int16(buf);
if (!buf_check_overflow(buf) && buf_check_size(buf, vstr->len)) {
@@ -195,7 +193,7 @@ static void buf_get_str(struct cbuf *buf, struct v9fs_str *vstr)
}
}
-static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
+static void buf_get_qid(struct cbuf *bufp, struct p9_qid *qid)
{
qid->type = buf_get_int8(bufp);
qid->version = buf_get_int32(bufp);
@@ -203,18 +201,18 @@ static void buf_get_qid(struct cbuf *bufp, struct v9fs_qid *qid)
}
/**
- * v9fs_size_wstat - calculate the size of a variable length stat struct
+ * p9_size_wstat - calculate the size of a variable length stat struct
* @stat: metadata (stat) structure
- * @extended: non-zero if 9P2000.u
+ * @dotu: non-zero if 9P2000.u
*
*/
-static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
+static int p9_size_wstat(struct p9_wstat *wstat, int dotu)
{
int size = 0;
if (wstat == NULL) {
- eprintk(KERN_ERR, "v9fs_size_stat: got a NULL stat pointer\n");
+ P9_EPRINTK(KERN_ERR, "p9_size_stat: got a NULL stat pointer\n");
return 0;
}
@@ -239,7 +237,7 @@ static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
if (wstat->muid)
size += strlen(wstat->muid);
- if (extended) {
+ if (dotu) {
size += 4 + /* n_uid[4] */
4 + /* n_gid[4] */
4 + /* n_muid[4] */
@@ -255,12 +253,12 @@ static int v9fs_size_wstat(struct v9fs_wstat *wstat, int extended)
* buf_get_stat - safely decode a recieved metadata (stat) structure
* @bufp: buffer to deserialize
* @stat: metadata (stat) structure
- * @extended: non-zero if 9P2000.u
+ * @dotu: non-zero if 9P2000.u
*
*/
static void
-buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
+buf_get_stat(struct cbuf *bufp, struct p9_stat *stat, int dotu)
{
stat->size = buf_get_int16(bufp);
stat->type = buf_get_int16(bufp);
@@ -277,7 +275,7 @@ buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
buf_get_str(bufp, &stat->gid);
buf_get_str(bufp, &stat->muid);
- if (extended) {
+ if (dotu) {
buf_get_str(bufp, &stat->extension);
stat->n_uid = buf_get_int32(bufp);
stat->n_gid = buf_get_int32(bufp);
@@ -286,18 +284,18 @@ buf_get_stat(struct cbuf *bufp, struct v9fs_stat *stat, int extended)
}
/**
- * v9fs_deserialize_stat - decode a received metadata structure
+ * p9_deserialize_stat - decode a received metadata structure
* @buf: buffer to deserialize
* @buflen: length of received buffer
* @stat: metadata structure to decode into
- * @extended: non-zero if 9P2000.u
+ * @dotu: non-zero if 9P2000.u
*
* Note: stat will point to the buf region.
*/
int
-v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
- int extended)
+p9_deserialize_stat(void *buf, u32 buflen, struct p9_stat *stat,
+ int dotu)
{
struct cbuf buffer;
struct cbuf *bufp = &buffer;
@@ -305,13 +303,14 @@ v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
buf_init(bufp, buf, buflen);
p = bufp->p;
- buf_get_stat(bufp, stat, extended);
+ buf_get_stat(bufp, stat, dotu);
if (buf_check_overflow(bufp))
return 0;
else
return bufp->p - p;
}
+EXPORT_SYMBOL(p9_deserialize_stat);
/**
* deserialize_fcall - unmarshal a response
@@ -319,13 +318,13 @@ v9fs_deserialize_stat(void *buf, u32 buflen, struct v9fs_stat *stat,
* @buflen: length of received buffer
* @rcall: fcall structure to populate
* @rcalllen: length of fcall structure to populate
- * @extended: non-zero if 9P2000.u
+ * @dotu: non-zero if 9P2000.u
*
*/
int
-v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
- int extended)
+p9_deserialize_fcall(void *buf, u32 buflen, struct p9_fcall *rcall,
+ int dotu)
{
struct cbuf buffer;
@@ -338,102 +337,104 @@ v9fs_deserialize_fcall(void *buf, u32 buflen, struct v9fs_fcall *rcall,
rcall->id = buf_get_int8(bufp);
rcall->tag = buf_get_int16(bufp);
- dprintk(DEBUG_CONV, "size %d id %d tag %d\n", rcall->size, rcall->id,
- rcall->tag);
+ P9_DPRINTK(P9_DEBUG_CONV, "size %d id %d tag %d\n", rcall->size,
+ rcall->id, rcall->tag);
switch (rcall->id) {
default:
- eprintk(KERN_ERR, "unknown message type: %d\n", rcall->id);
+ P9_EPRINTK(KERN_ERR, "unknown message type: %d\n", rcall->id);
return -EPROTO;
- case RVERSION:
+ case P9_RVERSION:
rcall->params.rversion.msize = buf_get_int32(bufp);
buf_get_str(bufp, &rcall->params.rversion.version);
break;
- case RFLUSH:
+ case P9_RFLUSH:
break;
- case RATTACH:
+ case P9_RATTACH:
rcall->params.rattach.qid.type = buf_get_int8(bufp);
rcall->params.rattach.qid.version = buf_get_int32(bufp);
rcall->params.rattach.qid.path = buf_get_int64(bufp);
break;
- case RWALK:
+ case P9_RWALK:
rcall->params.rwalk.nwqid = buf_get_int16(bufp);
- if (rcall->params.rwalk.nwqid > V9FS_MAXWELEM) {
- eprintk(KERN_ERR, "Rwalk with more than %d qids: %d\n",
- V9FS_MAXWELEM, rcall->params.rwalk.nwqid);
+ if (rcall->params.rwalk.nwqid > P9_MAXWELEM) {
+ P9_EPRINTK(KERN_ERR,
+ "Rwalk with more than %d qids: %d\n",
+ P9_MAXWELEM, rcall->params.rwalk.nwqid);
return -EPROTO;
}
for (i = 0; i < rcall->params.rwalk.nwqid; i++)
buf_get_qid(bufp, &rcall->params.rwalk.wqids[i]);
break;
- case ROPEN:
+ case P9_ROPEN:
buf_get_qid(bufp, &rcall->params.ropen.qid);
rcall->params.ropen.iounit = buf_get_int32(bufp);
break;
- case RCREATE:
+ case P9_RCREATE:
buf_get_qid(bufp, &rcall->params.rcreate.qid);
rcall->params.rcreate.iounit = buf_get_int32(bufp);
break;
- case RREAD:
+ case P9_RREAD:
rcall->params.rread.count = buf_get_int32(bufp);
rcall->params.rread.data = bufp->p;
buf_check_size(bufp, rcall->params.rread.count);
break;
- case RWRITE:
+ case P9_RWRITE:
rcall->params.rwrite.count = buf_get_int32(bufp);
break;
- case RCLUNK:
+ case P9_RCLUNK:
break;
- case RREMOVE:
+ case P9_RREMOVE:
break;
- case RSTAT:
+ case P9_RSTAT:
buf_get_int16(bufp);
- buf_get_stat(bufp, &rcall->params.rstat.stat, extended);
+ buf_get_stat(bufp, &rcall->params.rstat.stat, dotu);
break;
- case RWSTAT:
+ case P9_RWSTAT:
break;
- case RERROR:
+ case P9_RERROR:
buf_get_str(bufp, &rcall->params.rerror.error);
- if (extended)
+ if (dotu)
rcall->params.rerror.errno = buf_get_int16(bufp);
break;
}
if (buf_check_overflow(bufp)) {
- dprintk(DEBUG_ERROR, "buffer overflow\n");
+ P9_DPRINTK(P9_DEBUG_ERROR, "buffer overflow\n");
return -EIO;
}
return bufp->p - bufp->sp;
}
+EXPORT_SYMBOL(p9_deserialize_fcall);
-static inline void v9fs_put_int8(struct cbuf *bufp, u8 val, u8 * p)
+static inline void p9_put_int8(struct cbuf *bufp, u8 val, u8 * p)
{
*p = val;
buf_put_int8(bufp, val);
}
-static inline void v9fs_put_int16(struct cbuf *bufp, u16 val, u16 * p)
+static inline void p9_put_int16(struct cbuf *bufp, u16 val, u16 * p)
{
*p = val;
buf_put_int16(bufp, val);
}
-static inline void v9fs_put_int32(struct cbuf *bufp, u32 val, u32 * p)
+static inline void p9_put_int32(struct cbuf *bufp, u32 val, u32 * p)
{
*p = val;
buf_put_int32(bufp, val);
}
-static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
+static inline void p9_put_int64(struct cbuf *bufp, u64 val, u64 * p)
{
*p = val;
buf_put_int64(bufp, val);
}
static void
-v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
+p9_put_str(struct cbuf *bufp, char *data, struct p9_str *str)
{
int len;
char *s;
@@ -451,7 +452,16 @@ v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
}
static int
-v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
+p9_put_data(struct cbuf *bufp, const char *data, int count,
+ unsigned char **pdata)
+{
+ *pdata = buf_alloc(bufp, count);
+ memmove(*pdata, data, count);
+ return count;
+}
+
+static int
+p9_put_user_data(struct cbuf *bufp, const char __user *data, int count,
unsigned char **pdata)
{
*pdata = buf_alloc(bufp, count);
@@ -459,162 +469,167 @@ v9fs_put_user_data(struct cbuf *bufp, const char __user * data, int count,
}
static void
-v9fs_put_wstat(struct cbuf *bufp, struct v9fs_wstat *wstat,
- struct v9fs_stat *stat, int statsz, int extended)
+p9_put_wstat(struct cbuf *bufp, struct p9_wstat *wstat,
+ struct p9_stat *stat, int statsz, int dotu)
{
- v9fs_put_int16(bufp, statsz, &stat->size);
- v9fs_put_int16(bufp, wstat->type, &stat->type);
- v9fs_put_int32(bufp, wstat->dev, &stat->dev);
- v9fs_put_int8(bufp, wstat->qid.type, &stat->qid.type);
- v9fs_put_int32(bufp, wstat->qid.version, &stat->qid.version);
- v9fs_put_int64(bufp, wstat->qid.path, &stat->qid.path);
- v9fs_put_int32(bufp, wstat->mode, &stat->mode);
- v9fs_put_int32(bufp, wstat->atime, &stat->atime);
- v9fs_put_int32(bufp, wstat->mtime, &stat->mtime);
- v9fs_put_int64(bufp, wstat->length, &stat->length);
+ p9_put_int16(bufp, statsz, &stat->size);
+ p9_put_int16(bufp, wstat->type, &stat->type);
+ p9_put_int32(bufp, wstat->dev, &stat->dev);
+ p9_put_int8(bufp, wstat->qid.type, &stat->qid.type);
+ p9_put_int32(bufp, wstat->qid.version, &stat->qid.version);
+ p9_put_int64(bufp, wstat->qid.path, &stat->qid.path);
+ p9_put_int32(bufp, wstat->mode, &stat->mode);
+ p9_put_int32(bufp, wstat->atime, &stat->atime);
+ p9_put_int32(bufp, wstat->mtime, &stat->mtime);
+ p9_put_int64(bufp, wstat->length, &stat->length);
- v9fs_put_str(bufp, wstat->name, &stat->name);
- v9fs_put_str(bufp, wstat->uid, &stat->uid);
- v9fs_put_str(bufp, wstat->gid, &stat->gid);
- v9fs_put_str(bufp, wstat->muid, &stat->muid);
+ p9_put_str(bufp, wstat->name, &stat->name);
+ p9_put_str(bufp, wstat->uid, &stat->uid);
+ p9_put_str(bufp, wstat->gid, &stat->gid);
+ p9_put_str(bufp, wstat->muid, &stat->muid);
- if (extended) {
- v9fs_put_str(bufp, wstat->extension, &stat->extension);
- v9fs_put_int32(bufp, wstat->n_uid, &stat->n_uid);
- v9fs_put_int32(bufp, wstat->n_gid, &stat->n_gid);
- v9fs_put_int32(bufp, wstat->n_muid, &stat->n_muid);
+ if (dotu) {
+ p9_put_str(bufp, wstat->extension, &stat->extension);
+ p9_put_int32(bufp, wstat->n_uid, &stat->n_uid);
+ p9_put_int32(bufp, wstat->n_gid, &stat->n_gid);
+ p9_put_int32(bufp, wstat->n_muid, &stat->n_muid);
}
}
-static struct v9fs_fcall *
-v9fs_create_common(struct cbuf *bufp, u32 size, u8 id)
+static struct p9_fcall *
+p9_create_common(struct cbuf *bufp, u32 size, u8 id)
{
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
size += 4 + 1 + 2; /* size[4] id[1] tag[2] */
- fc = kmalloc(sizeof(struct v9fs_fcall) + size, GFP_KERNEL);
+ fc = kmalloc(sizeof(struct p9_fcall) + size, GFP_KERNEL);
if (!fc)
return ERR_PTR(-ENOMEM);
fc->sdata = (char *)fc + sizeof(*fc);
buf_init(bufp, (char *)fc->sdata, size);
- v9fs_put_int32(bufp, size, &fc->size);
- v9fs_put_int8(bufp, id, &fc->id);
- v9fs_put_int16(bufp, V9FS_NOTAG, &fc->tag);
+ p9_put_int32(bufp, size, &fc->size);
+ p9_put_int8(bufp, id, &fc->id);
+ p9_put_int16(bufp, P9_NOTAG, &fc->tag);
return fc;
}
-void v9fs_set_tag(struct v9fs_fcall *fc, u16 tag)
+void p9_set_tag(struct p9_fcall *fc, u16 tag)
{
fc->tag = tag;
*(__le16 *) (fc->sdata + 5) = cpu_to_le16(tag);
}
+EXPORT_SYMBOL(p9_set_tag);
-struct v9fs_fcall *v9fs_create_tversion(u32 msize, char *version)
+struct p9_fcall *p9_create_tversion(u32 msize, char *version)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
size = 4 + 2 + strlen(version); /* msize[4] version[s] */
- fc = v9fs_create_common(bufp, size, TVERSION);
+ fc = p9_create_common(bufp, size, P9_TVERSION);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, msize, &fc->params.tversion.msize);
- v9fs_put_str(bufp, version, &fc->params.tversion.version);
+ p9_put_int32(bufp, msize, &fc->params.tversion.msize);
+ p9_put_str(bufp, version, &fc->params.tversion.version);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_tversion);
-#if 0
-struct v9fs_fcall *v9fs_create_tauth(u32 afid, char *uname, char *aname)
+struct p9_fcall *p9_create_tauth(u32 afid, char *uname, char *aname)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
- size = 4 + 2 + strlen(uname) + 2 + strlen(aname); /* afid[4] uname[s] aname[s] */
- fc = v9fs_create_common(bufp, size, TAUTH);
+ /* afid[4] uname[s] aname[s] */
+ size = 4 + 2 + strlen(uname) + 2 + strlen(aname);
+ fc = p9_create_common(bufp, size, P9_TAUTH);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, afid, &fc->params.tauth.afid);
- v9fs_put_str(bufp, uname, &fc->params.tauth.uname);
- v9fs_put_str(bufp, aname, &fc->params.tauth.aname);
+ p9_put_int32(bufp, afid, &fc->params.tauth.afid);
+ p9_put_str(bufp, uname, &fc->params.tauth.uname);
+ p9_put_str(bufp, aname, &fc->params.tauth.aname);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
-#endif /* 0 */
+EXPORT_SYMBOL(p9_create_tauth);
-struct v9fs_fcall *
-v9fs_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
+struct p9_fcall *
+p9_create_tattach(u32 fid, u32 afid, char *uname, char *aname)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
- size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname); /* fid[4] afid[4] uname[s] aname[s] */
- fc = v9fs_create_common(bufp, size, TATTACH);
+ /* fid[4] afid[4] uname[s] aname[s] */
+ size = 4 + 4 + 2 + strlen(uname) + 2 + strlen(aname);
+ fc = p9_create_common(bufp, size, P9_TATTACH);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.tattach.fid);
- v9fs_put_int32(bufp, afid, &fc->params.tattach.afid);
- v9fs_put_str(bufp, uname, &fc->params.tattach.uname);
- v9fs_put_str(bufp, aname, &fc->params.tattach.aname);
+ p9_put_int32(bufp, fid, &fc->params.tattach.fid);
+ p9_put_int32(bufp, afid, &fc->params.tattach.afid);
+ p9_put_str(bufp, uname, &fc->params.tattach.uname);
+ p9_put_str(bufp, aname, &fc->params.tattach.aname);
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_tattach);
-struct v9fs_fcall *v9fs_create_tflush(u16 oldtag)
+struct p9_fcall *p9_create_tflush(u16 oldtag)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
size = 2; /* oldtag[2] */
- fc = v9fs_create_common(bufp, size, TFLUSH);
+ fc = p9_create_common(bufp, size, P9_TFLUSH);
if (IS_ERR(fc))
goto error;
- v9fs_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
+ p9_put_int16(bufp, oldtag, &fc->params.tflush.oldtag);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_tflush);
-struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
+struct p9_fcall *p9_create_twalk(u32 fid, u32 newfid, u16 nwname,
char **wnames)
{
int i, size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
- if (nwname > V9FS_MAXWELEM) {
- dprintk(DEBUG_ERROR, "nwname > %d\n", V9FS_MAXWELEM);
+ if (nwname > P9_MAXWELEM) {
+ P9_DPRINTK(P9_DEBUG_ERROR, "nwname > %d\n", P9_MAXWELEM);
return NULL;
}
@@ -623,122 +638,160 @@ struct v9fs_fcall *v9fs_create_twalk(u32 fid, u32 newfid, u16 nwname,
size += 2 + strlen(wnames[i]); /* wname[s] */
}
- fc = v9fs_create_common(bufp, size, TWALK);
+ fc = p9_create_common(bufp, size, P9_TWALK);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.twalk.fid);
- v9fs_put_int32(bufp, newfid, &fc->params.twalk.newfid);
- v9fs_put_int16(bufp, nwname, &fc->params.twalk.nwname);
+ p9_put_int32(bufp, fid, &fc->params.twalk.fid);
+ p9_put_int32(bufp, newfid, &fc->params.twalk.newfid);
+ p9_put_int16(bufp, nwname, &fc->params.twalk.nwname);
for (i = 0; i < nwname; i++) {
- v9fs_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
+ p9_put_str(bufp, wnames[i], &fc->params.twalk.wnames[i]);
}
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_twalk);
-struct v9fs_fcall *v9fs_create_topen(u32 fid, u8 mode)
+struct p9_fcall *p9_create_topen(u32 fid, u8 mode)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
size = 4 + 1; /* fid[4] mode[1] */
- fc = v9fs_create_common(bufp, size, TOPEN);
+ fc = p9_create_common(bufp, size, P9_TOPEN);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.topen.fid);
- v9fs_put_int8(bufp, mode, &fc->params.topen.mode);
+ p9_put_int32(bufp, fid, &fc->params.topen.fid);
+ p9_put_int8(bufp, mode, &fc->params.topen.mode);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_topen);
-struct v9fs_fcall *v9fs_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
- char *extension, int extended)
+struct p9_fcall *p9_create_tcreate(u32 fid, char *name, u32 perm, u8 mode,
+ char *extension, int dotu)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
- size = 4 + 2 + strlen(name) + 4 + 1; /* fid[4] name[s] perm[4] mode[1] */
- if (extended) {
+ /* fid[4] name[s] perm[4] mode[1] */
+ size = 4 + 2 + strlen(name) + 4 + 1;
+ if (dotu) {
size += 2 + /* extension[s] */
(extension == NULL ? 0 : strlen(extension));
}
- fc = v9fs_create_common(bufp, size, TCREATE);
+ fc = p9_create_common(bufp, size, P9_TCREATE);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.tcreate.fid);
- v9fs_put_str(bufp, name, &fc->params.tcreate.name);
- v9fs_put_int32(bufp, perm, &fc->params.tcreate.perm);
- v9fs_put_int8(bufp, mode, &fc->params.tcreate.mode);
- if (extended)
- v9fs_put_str(bufp, extension, &fc->params.tcreate.extension);
+ p9_put_int32(bufp, fid, &fc->params.tcreate.fid);
+ p9_put_str(bufp, name, &fc->params.tcreate.name);
+ p9_put_int32(bufp, perm, &fc->params.tcreate.perm);
+ p9_put_int8(bufp, mode, &fc->params.tcreate.mode);
+ if (dotu)
+ p9_put_str(bufp, extension, &fc->params.tcreate.extension);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_tcreate);
-struct v9fs_fcall *v9fs_create_tread(u32 fid, u64 offset, u32 count)
+struct p9_fcall *p9_create_tread(u32 fid, u64 offset, u32 count)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
size = 4 + 8 + 4; /* fid[4] offset[8] count[4] */
- fc = v9fs_create_common(bufp, size, TREAD);
+ fc = p9_create_common(bufp, size, P9_TREAD);
+ if (IS_ERR(fc))
+ goto error;
+
+ p9_put_int32(bufp, fid, &fc->params.tread.fid);
+ p9_put_int64(bufp, offset, &fc->params.tread.offset);
+ p9_put_int32(bufp, count, &fc->params.tread.count);
+
+ if (buf_check_overflow(bufp)) {
+ kfree(fc);
+ fc = ERR_PTR(-ENOMEM);
+ }
+error:
+ return fc;
+}
+EXPORT_SYMBOL(p9_create_tread);
+
+struct p9_fcall *p9_create_twrite(u32 fid, u64 offset, u32 count,
+ const char *data)
+{
+ int size, err;
+ struct p9_fcall *fc;
+ struct cbuf buffer;
+ struct cbuf *bufp = &buffer;
+
+ /* fid[4] offset[8] count[4] data[count] */
+ size = 4 + 8 + 4 + count;
+ fc = p9_create_common(bufp, size, P9_TWRITE);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.tread.fid);
- v9fs_put_int64(bufp, offset, &fc->params.tread.offset);
- v9fs_put_int32(bufp, count, &fc->params.tread.count);
+ p9_put_int32(bufp, fid, &fc->params.twrite.fid);
+ p9_put_int64(bufp, offset, &fc->params.twrite.offset);
+ p9_put_int32(bufp, count, &fc->params.twrite.count);
+ err = p9_put_data(bufp, data, count, &fc->params.twrite.data);
+ if (err) {
+ kfree(fc);
+ fc = ERR_PTR(err);
+ }
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_twrite);
-struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
- const char __user * data)
+struct p9_fcall *p9_create_twrite_u(u32 fid, u64 offset, u32 count,
+ const char __user *data)
{
int size, err;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
- size = 4 + 8 + 4 + count; /* fid[4] offset[8] count[4] data[count] */
- fc = v9fs_create_common(bufp, size, TWRITE);
+ /* fid[4] offset[8] count[4] data[count] */
+ size = 4 + 8 + 4 + count;
+ fc = p9_create_common(bufp, size, P9_TWRITE);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.twrite.fid);
- v9fs_put_int64(bufp, offset, &fc->params.twrite.offset);
- v9fs_put_int32(bufp, count, &fc->params.twrite.count);
- err = v9fs_put_user_data(bufp, data, count, &fc->params.twrite.data);
+ p9_put_int32(bufp, fid, &fc->params.twrite.fid);
+ p9_put_int64(bufp, offset, &fc->params.twrite.offset);
+ p9_put_int32(bufp, count, &fc->params.twrite.count);
+ err = p9_put_user_data(bufp, data, count, &fc->params.twrite.data);
if (err) {
kfree(fc);
fc = ERR_PTR(err);
@@ -748,98 +801,103 @@ struct v9fs_fcall *v9fs_create_twrite(u32 fid, u64 offset, u32 count,
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_twrite_u);
-struct v9fs_fcall *v9fs_create_tclunk(u32 fid)
+struct p9_fcall *p9_create_tclunk(u32 fid)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
size = 4; /* fid[4] */
- fc = v9fs_create_common(bufp, size, TCLUNK);
+ fc = p9_create_common(bufp, size, P9_TCLUNK);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.tclunk.fid);
+ p9_put_int32(bufp, fid, &fc->params.tclunk.fid);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_tclunk);
-struct v9fs_fcall *v9fs_create_tremove(u32 fid)
+struct p9_fcall *p9_create_tremove(u32 fid)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
size = 4; /* fid[4] */
- fc = v9fs_create_common(bufp, size, TREMOVE);
+ fc = p9_create_common(bufp, size, P9_TREMOVE);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.tremove.fid);
+ p9_put_int32(bufp, fid, &fc->params.tremove.fid);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_tremove);
-struct v9fs_fcall *v9fs_create_tstat(u32 fid)
+struct p9_fcall *p9_create_tstat(u32 fid)
{
int size;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
size = 4; /* fid[4] */
- fc = v9fs_create_common(bufp, size, TSTAT);
+ fc = p9_create_common(bufp, size, P9_TSTAT);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.tstat.fid);
+ p9_put_int32(bufp, fid, &fc->params.tstat.fid);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_tstat);
-struct v9fs_fcall *v9fs_create_twstat(u32 fid, struct v9fs_wstat *wstat,
- int extended)
+struct p9_fcall *p9_create_twstat(u32 fid, struct p9_wstat *wstat,
+ int dotu)
{
int size, statsz;
- struct v9fs_fcall *fc;
+ struct p9_fcall *fc;
struct cbuf buffer;
struct cbuf *bufp = &buffer;
- statsz = v9fs_size_wstat(wstat, extended);
+ statsz = p9_size_wstat(wstat, dotu);
size = 4 + 2 + 2 + statsz; /* fid[4] stat[n] */
- fc = v9fs_create_common(bufp, size, TWSTAT);
+ fc = p9_create_common(bufp, size, P9_TWSTAT);
if (IS_ERR(fc))
goto error;
- v9fs_put_int32(bufp, fid, &fc->params.twstat.fid);
+ p9_put_int32(bufp, fid, &fc->params.twstat.fid);
buf_put_int16(bufp, statsz + 2);
- v9fs_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, extended);
+ p9_put_wstat(bufp, wstat, &fc->params.twstat.stat, statsz, dotu);
if (buf_check_overflow(bufp)) {
kfree(fc);
fc = ERR_PTR(-ENOMEM);
}
- error:
+error:
return fc;
}
+EXPORT_SYMBOL(p9_create_twstat);
diff --git a/fs/9p/error.h b/net/9p/error.c
index 5f3ca522b316..ab2458b6c903 100644
--- a/fs/9p/error.h
+++ b/net/9p/error.c
@@ -1,12 +1,11 @@
/*
- * linux/fs/9p/error.h
+ * linux/fs/9p/error.c
*
- * Huge Nasty Error Table
+ * Error string handling
*
- * Plan 9 uses error strings, Unix uses error numbers. This table tries to
- * match UNIX strings and Plan 9 strings to unix error numbers. It is used
- * to preload the dynamic error table which can also track user-specific error
- * strings.
+ * Plan 9 uses error strings, Unix uses error numbers. These functions
+ * try to help manage that and provide for dynamically adding error
+ * mappings.
*
* Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
* Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
@@ -28,8 +27,11 @@
*
*/
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
#include <linux/errno.h>
-#include <asm/errno.h>
+#include <net/9p/9p.h>
struct errormap {
char *name;
@@ -174,4 +176,65 @@ static struct errormap errmap[] = {
{NULL, -1}
};
-extern int v9fs_error_init(void);
+/**
+ * p9_error_init - preload
+ * @errstr: error string
+ *
+ */
+
+int p9_error_init(void)
+{
+ struct errormap *c;
+ int bucket;
+
+ /* initialize hash table */
+ for (bucket = 0; bucket < ERRHASHSZ; bucket++)
+ INIT_HLIST_HEAD(&hash_errmap[bucket]);
+
+ /* load initial error map into hash table */
+ for (c = errmap; c->name != NULL; c++) {
+ c->namelen = strlen(c->name);
+ bucket = jhash(c->name, c->namelen, 0) % ERRHASHSZ;
+ INIT_HLIST_NODE(&c->list);
+ hlist_add_head(&c->list, &hash_errmap[bucket]);
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL(p9_error_init);
+
+/**
+ * errstr2errno - convert error string to error number
+ * @errstr: error string
+ *
+ */
+
+int p9_errstr2errno(char *errstr, int len)
+{
+ int errno;
+ struct hlist_node *p;
+ struct errormap *c;
+ int bucket;
+
+ errno = 0;
+ p = NULL;
+ c = NULL;
+ bucket = jhash(errstr, len, 0) % ERRHASHSZ;
+ hlist_for_each_entry(c, p, &hash_errmap[bucket], list) {
+ if (c->namelen == len && !memcmp(c->name, errstr, len)) {
+ errno = c->val;
+ break;
+ }
+ }
+
+ if (errno == 0) {
+ /* TODO: if error isn't found, add it dynamically */
+ errstr[len] = 0;
+ printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__,
+ errstr);
+ errno = 1;
+ }
+
+ return -errno;
+}
+EXPORT_SYMBOL(p9_errstr2errno);
diff --git a/fs/9p/fcprint.c b/net/9p/fcprint.c
index 34b96114a28d..b1ae8ec57d54 100644
--- a/fs/9p/fcprint.c
+++ b/net/9p/fcprint.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/9p/fcprint.c
+ * net/9p/fcprint.c
*
* Print 9P call.
*
@@ -25,61 +25,59 @@
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/idr.h>
+#include <net/9p/9p.h>
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "mux.h"
+#ifdef CONFIG_NET_9P_DEBUG
static int
-v9fs_printqid(char *buf, int buflen, struct v9fs_qid *q)
+p9_printqid(char *buf, int buflen, struct p9_qid *q)
{
int n;
char b[10];
n = 0;
- if (q->type & V9FS_QTDIR)
+ if (q->type & P9_QTDIR)
b[n++] = 'd';
- if (q->type & V9FS_QTAPPEND)
+ if (q->type & P9_QTAPPEND)
b[n++] = 'a';
- if (q->type & V9FS_QTAUTH)
+ if (q->type & P9_QTAUTH)
b[n++] = 'A';
- if (q->type & V9FS_QTEXCL)
+ if (q->type & P9_QTEXCL)
b[n++] = 'l';
- if (q->type & V9FS_QTTMP)
+ if (q->type & P9_QTTMP)
b[n++] = 't';
- if (q->type & V9FS_QTSYMLINK)
+ if (q->type & P9_QTSYMLINK)
b[n++] = 'L';
b[n] = '\0';
- return scnprintf(buf, buflen, "(%.16llx %x %s)", (long long int) q->path,
- q->version, b);
+ return scnprintf(buf, buflen, "(%.16llx %x %s)",
+ (long long int) q->path, q->version, b);
}
static int
-v9fs_printperm(char *buf, int buflen, int perm)
+p9_printperm(char *buf, int buflen, int perm)
{
int n;
char b[15];
n = 0;
- if (perm & V9FS_DMDIR)
+ if (perm & P9_DMDIR)
b[n++] = 'd';
- if (perm & V9FS_DMAPPEND)
+ if (perm & P9_DMAPPEND)
b[n++] = 'a';
- if (perm & V9FS_DMAUTH)
+ if (perm & P9_DMAUTH)
b[n++] = 'A';
- if (perm & V9FS_DMEXCL)
+ if (perm & P9_DMEXCL)
b[n++] = 'l';
- if (perm & V9FS_DMTMP)
+ if (perm & P9_DMTMP)
b[n++] = 't';
- if (perm & V9FS_DMDEVICE)
+ if (perm & P9_DMDEVICE)
b[n++] = 'D';
- if (perm & V9FS_DMSOCKET)
+ if (perm & P9_DMSOCKET)
b[n++] = 'S';
- if (perm & V9FS_DMNAMEDPIPE)
+ if (perm & P9_DMNAMEDPIPE)
b[n++] = 'P';
- if (perm & V9FS_DMSYMLINK)
+ if (perm & P9_DMSYMLINK)
b[n++] = 'L';
b[n] = '\0';
@@ -87,7 +85,7 @@ v9fs_printperm(char *buf, int buflen, int perm)
}
static int
-v9fs_printstat(char *buf, int buflen, struct v9fs_stat *st, int extended)
+p9_printstat(char *buf, int buflen, struct p9_stat *st, int extended)
{
int n;
@@ -105,9 +103,9 @@ v9fs_printstat(char *buf, int buflen, struct v9fs_stat *st, int extended)
n += scnprintf(buf+n, buflen-n, "(%d)", st->n_muid);
n += scnprintf(buf+n, buflen-n, " q ");
- n += v9fs_printqid(buf+n, buflen-n, &st->qid);
+ n += p9_printqid(buf+n, buflen-n, &st->qid);
n += scnprintf(buf+n, buflen-n, " m ");
- n += v9fs_printperm(buf+n, buflen-n, st->mode);
+ n += p9_printperm(buf+n, buflen-n, st->mode);
n += scnprintf(buf+n, buflen-n, " at %d mt %d l %lld",
st->atime, st->mtime, (long long int) st->length);
@@ -119,7 +117,7 @@ v9fs_printstat(char *buf, int buflen, struct v9fs_stat *st, int extended)
}
static int
-v9fs_dumpdata(char *buf, int buflen, u8 *data, int datalen)
+p9_dumpdata(char *buf, int buflen, u8 *data, int datalen)
{
int i, n;
@@ -139,13 +137,13 @@ v9fs_dumpdata(char *buf, int buflen, u8 *data, int datalen)
}
static int
-v9fs_printdata(char *buf, int buflen, u8 *data, int datalen)
+p9_printdata(char *buf, int buflen, u8 *data, int datalen)
{
- return v9fs_dumpdata(buf, buflen, data, datalen<16?datalen:16);
+ return p9_dumpdata(buf, buflen, data, datalen < 16?datalen:16);
}
int
-v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
+p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
{
int i, ret, type, tag;
@@ -157,21 +155,23 @@ v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
ret = 0;
switch (type) {
- case TVERSION:
+ case P9_TVERSION:
ret += scnprintf(buf+ret, buflen-ret,
- "Tversion tag %u msize %u version '%.*s'", tag,
- fc->params.tversion.msize, fc->params.tversion.version.len,
- fc->params.tversion.version.str);
+ "Tversion tag %u msize %u version '%.*s'", tag,
+ fc->params.tversion.msize,
+ fc->params.tversion.version.len,
+ fc->params.tversion.version.str);
break;
- case RVERSION:
+ case P9_RVERSION:
ret += scnprintf(buf+ret, buflen-ret,
- "Rversion tag %u msize %u version '%.*s'", tag,
- fc->params.rversion.msize, fc->params.rversion.version.len,
- fc->params.rversion.version.str);
+ "Rversion tag %u msize %u version '%.*s'", tag,
+ fc->params.rversion.msize,
+ fc->params.rversion.version.len,
+ fc->params.rversion.version.str);
break;
- case TAUTH:
+ case P9_TAUTH:
ret += scnprintf(buf+ret, buflen-ret,
"Tauth tag %u afid %d uname '%.*s' aname '%.*s'", tag,
fc->params.tauth.afid, fc->params.tauth.uname.len,
@@ -179,93 +179,97 @@ v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
fc->params.tauth.aname.str);
break;
- case RAUTH:
+ case P9_RAUTH:
ret += scnprintf(buf+ret, buflen-ret, "Rauth tag %u qid ", tag);
- v9fs_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
+ p9_printqid(buf+ret, buflen-ret, &fc->params.rauth.qid);
break;
- case TATTACH:
+ case P9_TATTACH:
ret += scnprintf(buf+ret, buflen-ret,
- "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'",
- tag, fc->params.tattach.fid, fc->params.tattach.afid,
- fc->params.tattach.uname.len, fc->params.tattach.uname.str,
- fc->params.tattach.aname.len, fc->params.tattach.aname.str);
+ "Tattach tag %u fid %d afid %d uname '%.*s' aname '%.*s'", tag,
+ fc->params.tattach.fid, fc->params.tattach.afid,
+ fc->params.tattach.uname.len, fc->params.tattach.uname.str,
+ fc->params.tattach.aname.len, fc->params.tattach.aname.str);
break;
- case RATTACH:
- ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ", tag);
- v9fs_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
+ case P9_RATTACH:
+ ret += scnprintf(buf+ret, buflen-ret, "Rattach tag %u qid ",
+ tag);
+ p9_printqid(buf+ret, buflen-ret, &fc->params.rattach.qid);
break;
- case RERROR:
- ret += scnprintf(buf+ret, buflen-ret, "Rerror tag %u ename '%.*s'",
- tag, fc->params.rerror.error.len,
- fc->params.rerror.error.str);
+ case P9_RERROR:
+ ret += scnprintf(buf+ret, buflen-ret,
+ "Rerror tag %u ename '%.*s'", tag,
+ fc->params.rerror.error.len,
+ fc->params.rerror.error.str);
if (extended)
ret += scnprintf(buf+ret, buflen-ret, " ecode %d\n",
fc->params.rerror.errno);
break;
- case TFLUSH:
+ case P9_TFLUSH:
ret += scnprintf(buf+ret, buflen-ret, "Tflush tag %u oldtag %u",
tag, fc->params.tflush.oldtag);
break;
- case RFLUSH:
+ case P9_RFLUSH:
ret += scnprintf(buf+ret, buflen-ret, "Rflush tag %u", tag);
break;
- case TWALK:
+ case P9_TWALK:
ret += scnprintf(buf+ret, buflen-ret,
"Twalk tag %u fid %d newfid %d nwname %d", tag,
fc->params.twalk.fid, fc->params.twalk.newfid,
fc->params.twalk.nwname);
- for(i = 0; i < fc->params.twalk.nwname; i++)
- ret += scnprintf(buf+ret, buflen-ret," '%.*s'",
+ for (i = 0; i < fc->params.twalk.nwname; i++)
+ ret += scnprintf(buf+ret, buflen-ret, " '%.*s'",
fc->params.twalk.wnames[i].len,
fc->params.twalk.wnames[i].str);
break;
- case RWALK:
+ case P9_RWALK:
ret += scnprintf(buf+ret, buflen-ret, "Rwalk tag %u nwqid %d",
tag, fc->params.rwalk.nwqid);
- for(i = 0; i < fc->params.rwalk.nwqid; i++)
- ret += v9fs_printqid(buf+ret, buflen-ret,
+ for (i = 0; i < fc->params.rwalk.nwqid; i++)
+ ret += p9_printqid(buf+ret, buflen-ret,
&fc->params.rwalk.wqids[i]);
break;
- case TOPEN:
+ case P9_TOPEN:
ret += scnprintf(buf+ret, buflen-ret,
"Topen tag %u fid %d mode %d", tag,
fc->params.topen.fid, fc->params.topen.mode);
break;
- case ROPEN:
+ case P9_ROPEN:
ret += scnprintf(buf+ret, buflen-ret, "Ropen tag %u", tag);
- ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
- ret += scnprintf(buf+ret, buflen-ret," iounit %d",
+ ret += p9_printqid(buf+ret, buflen-ret, &fc->params.ropen.qid);
+ ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
fc->params.ropen.iounit);
break;
- case TCREATE:
+ case P9_TCREATE:
ret += scnprintf(buf+ret, buflen-ret,
"Tcreate tag %u fid %d name '%.*s' perm ", tag,
fc->params.tcreate.fid, fc->params.tcreate.name.len,
fc->params.tcreate.name.str);
- ret += v9fs_printperm(buf+ret, buflen-ret, fc->params.tcreate.perm);
+ ret += p9_printperm(buf+ret, buflen-ret,
+ fc->params.tcreate.perm);
ret += scnprintf(buf+ret, buflen-ret, " mode %d",
fc->params.tcreate.mode);
break;
- case RCREATE:
+ case P9_RCREATE:
ret += scnprintf(buf+ret, buflen-ret, "Rcreate tag %u", tag);
- ret += v9fs_printqid(buf+ret, buflen-ret, &fc->params.rcreate.qid);
+ ret += p9_printqid(buf+ret, buflen-ret,
+ &fc->params.rcreate.qid);
ret += scnprintf(buf+ret, buflen-ret, " iounit %d",
fc->params.rcreate.iounit);
break;
- case TREAD:
+ case P9_TREAD:
ret += scnprintf(buf+ret, buflen-ret,
"Tread tag %u fid %d offset %lld count %u", tag,
fc->params.tread.fid,
@@ -273,66 +277,66 @@ v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
fc->params.tread.count);
break;
- case RREAD:
+ case P9_RREAD:
ret += scnprintf(buf+ret, buflen-ret,
"Rread tag %u count %u data ", tag,
fc->params.rread.count);
- ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.rread.data,
+ ret += p9_printdata(buf+ret, buflen-ret, fc->params.rread.data,
fc->params.rread.count);
break;
- case TWRITE:
+ case P9_TWRITE:
ret += scnprintf(buf+ret, buflen-ret,
"Twrite tag %u fid %d offset %lld count %u data ",
tag, fc->params.twrite.fid,
(long long int) fc->params.twrite.offset,
fc->params.twrite.count);
- ret += v9fs_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
+ ret += p9_printdata(buf+ret, buflen-ret, fc->params.twrite.data,
fc->params.twrite.count);
break;
- case RWRITE:
+ case P9_RWRITE:
ret += scnprintf(buf+ret, buflen-ret, "Rwrite tag %u count %u",
tag, fc->params.rwrite.count);
break;
- case TCLUNK:
+ case P9_TCLUNK:
ret += scnprintf(buf+ret, buflen-ret, "Tclunk tag %u fid %d",
tag, fc->params.tclunk.fid);
break;
- case RCLUNK:
+ case P9_RCLUNK:
ret += scnprintf(buf+ret, buflen-ret, "Rclunk tag %u", tag);
break;
- case TREMOVE:
+ case P9_TREMOVE:
ret += scnprintf(buf+ret, buflen-ret, "Tremove tag %u fid %d",
tag, fc->params.tremove.fid);
break;
- case RREMOVE:
+ case P9_RREMOVE:
ret += scnprintf(buf+ret, buflen-ret, "Rremove tag %u", tag);
break;
- case TSTAT:
+ case P9_TSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Tstat tag %u fid %d",
tag, fc->params.tstat.fid);
break;
- case RSTAT:
+ case P9_RSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Rstat tag %u ", tag);
- ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
+ ret += p9_printstat(buf+ret, buflen-ret, &fc->params.rstat.stat,
extended);
break;
- case TWSTAT:
+ case P9_TWSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Twstat tag %u fid %d ",
tag, fc->params.twstat.fid);
- ret += v9fs_printstat(buf+ret, buflen-ret, &fc->params.twstat.stat,
- extended);
+ ret += p9_printstat(buf+ret, buflen-ret,
+ &fc->params.twstat.stat, extended);
break;
- case RWSTAT:
+ case P9_RWSTAT:
ret += scnprintf(buf+ret, buflen-ret, "Rwstat tag %u", tag);
break;
@@ -343,3 +347,12 @@ v9fs_printfcall(char *buf, int buflen, struct v9fs_fcall *fc, int extended)
return ret;
}
+
+#else
+int
+p9_printfcall(char *buf, int buflen, struct p9_fcall *fc, int extended)
+{
+ return 0;
+}
+EXPORT_SYMBOL(p9_printfcall);
+#endif /* CONFIG_NET_9P_DEBUG */
diff --git a/net/9p/mod.c b/net/9p/mod.c
new file mode 100644
index 000000000000..4f9e1d2ac257
--- /dev/null
+++ b/net/9p/mod.c
@@ -0,0 +1,85 @@
+/*
+ * net/9p/9p.c
+ *
+ * 9P entry point
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ * 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:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <net/9p/9p.h>
+
+#ifdef CONFIG_NET_9P_DEBUG
+unsigned int p9_debug_level = 0; /* feature-rific global debug level */
+EXPORT_SYMBOL(p9_debug_level);
+module_param_named(debug, p9_debug_level, uint, 0);
+MODULE_PARM_DESC(debug, "9P debugging level");
+#endif
+
+extern int p9_mux_global_init(void);
+extern void p9_mux_global_exit(void);
+extern int p9_sysctl_register(void);
+extern void p9_sysctl_unregister(void);
+
+/**
+ * v9fs_init - Initialize module
+ *
+ */
+static int __init init_p9(void)
+{
+ int ret;
+
+ p9_error_init();
+ printk(KERN_INFO "Installing 9P2000 support\n");
+ ret = p9_mux_global_init();
+ if (ret) {
+ printk(KERN_WARNING "9p: starting mux failed\n");
+ return ret;
+ }
+
+ ret = p9_sysctl_register();
+ if (ret) {
+ printk(KERN_WARNING "9p: registering sysctl failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/**
+ * v9fs_init - shutdown module
+ *
+ */
+
+static void __exit exit_p9(void)
+{
+ p9_sysctl_unregister();
+ p9_mux_global_exit();
+}
+
+module_init(init_p9)
+module_exit(exit_p9)
+
+MODULE_AUTHOR("Latchesar Ionkov <lucho@ionkov.net>");
+MODULE_AUTHOR("Eric Van Hensbergen <ericvh@gmail.com>");
+MODULE_AUTHOR("Ron Minnich <rminnich@lanl.gov>");
+MODULE_LICENSE("GPL");
diff --git a/fs/9p/mux.c b/net/9p/mux.c
index c783874a9caf..acb038810f39 100644
--- a/fs/9p/mux.c
+++ b/net/9p/mux.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/9p/mux.c
+ * net/9p/mux.c
*
* Protocol Multiplexer
*
@@ -30,13 +30,9 @@
#include <linux/kthread.h>
#include <linux/idr.h>
#include <linux/mutex.h>
-
-#include "debug.h"
-#include "v9fs.h"
-#include "9p.h"
-#include "conv.h"
-#include "transport.h"
-#include "mux.h"
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+#include <net/9p/conn.h>
#define ERREQFLUSH 1
#define SCHED_TIMEOUT 10
@@ -55,33 +51,33 @@ enum {
Flushed,
};
-struct v9fs_mux_poll_task;
+struct p9_mux_poll_task;
-struct v9fs_req {
- spinlock_t lock;
+struct p9_req {
+ spinlock_t lock; /* protect request structure */
int tag;
- struct v9fs_fcall *tcall;
- struct v9fs_fcall *rcall;
+ struct p9_fcall *tcall;
+ struct p9_fcall *rcall;
int err;
- v9fs_mux_req_callback cb;
+ p9_conn_req_callback cb;
void *cba;
int flush;
struct list_head req_list;
};
-struct v9fs_mux_data {
- spinlock_t lock;
+struct p9_conn {
+ spinlock_t lock; /* protect lock structure */
struct list_head mux_list;
- struct v9fs_mux_poll_task *poll_task;
+ struct p9_mux_poll_task *poll_task;
int msize;
unsigned char *extended;
- struct v9fs_transport *trans;
- struct v9fs_idpool tagpool;
+ struct p9_transport *trans;
+ struct p9_idpool *tagpool;
int err;
wait_queue_head_t equeue;
struct list_head req_list;
struct list_head unsent_req_list;
- struct v9fs_fcall *rcall;
+ struct p9_fcall *rcall;
int rpos;
char *rbuf;
int wpos;
@@ -95,44 +91,44 @@ struct v9fs_mux_data {
unsigned long wsched;
};
-struct v9fs_mux_poll_task {
+struct p9_mux_poll_task {
struct task_struct *task;
struct list_head mux_list;
int muxnum;
};
-struct v9fs_mux_rpc {
- struct v9fs_mux_data *m;
+struct p9_mux_rpc {
+ struct p9_conn *m;
int err;
- struct v9fs_fcall *tcall;
- struct v9fs_fcall *rcall;
+ struct p9_fcall *tcall;
+ struct p9_fcall *rcall;
wait_queue_head_t wqueue;
};
-static int v9fs_poll_proc(void *);
-static void v9fs_read_work(struct work_struct *work);
-static void v9fs_write_work(struct work_struct *work);
-static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
+static int p9_poll_proc(void *);
+static void p9_read_work(struct work_struct *work);
+static void p9_write_work(struct work_struct *work);
+static void p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
poll_table * p);
-static u16 v9fs_mux_get_tag(struct v9fs_mux_data *);
-static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16);
+static u16 p9_mux_get_tag(struct p9_conn *);
+static void p9_mux_put_tag(struct p9_conn *, u16);
-static DEFINE_MUTEX(v9fs_mux_task_lock);
-static struct workqueue_struct *v9fs_mux_wq;
+static DEFINE_MUTEX(p9_mux_task_lock);
+static struct workqueue_struct *p9_mux_wq;
-static int v9fs_mux_num;
-static int v9fs_mux_poll_task_num;
-static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100];
+static int p9_mux_num;
+static int p9_mux_poll_task_num;
+static struct p9_mux_poll_task p9_mux_poll_tasks[100];
-int v9fs_mux_global_init(void)
+int p9_mux_global_init(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++)
- v9fs_mux_poll_tasks[i].task = NULL;
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++)
+ p9_mux_poll_tasks[i].task = NULL;
- v9fs_mux_wq = create_workqueue("v9fs");
- if (!v9fs_mux_wq) {
+ p9_mux_wq = create_workqueue("v9fs");
+ if (!p9_mux_wq) {
printk(KERN_WARNING "v9fs: mux: creating workqueue failed\n");
return -ENOMEM;
}
@@ -140,114 +136,117 @@ int v9fs_mux_global_init(void)
return 0;
}
-void v9fs_mux_global_exit(void)
+void p9_mux_global_exit(void)
{
- destroy_workqueue(v9fs_mux_wq);
+ destroy_workqueue(p9_mux_wq);
}
/**
- * v9fs_mux_calc_poll_procs - calculates the number of polling procs
+ * p9_mux_calc_poll_procs - calculates the number of polling procs
* based on the number of mounted v9fs filesystems.
*
* The current implementation returns sqrt of the number of mounts.
*/
-static int v9fs_mux_calc_poll_procs(int muxnum)
+static int p9_mux_calc_poll_procs(int muxnum)
{
int n;
- if (v9fs_mux_poll_task_num)
- n = muxnum / v9fs_mux_poll_task_num +
- (muxnum % v9fs_mux_poll_task_num ? 1 : 0);
+ if (p9_mux_poll_task_num)
+ n = muxnum / p9_mux_poll_task_num +
+ (muxnum % p9_mux_poll_task_num ? 1 : 0);
else
n = 1;
- if (n > ARRAY_SIZE(v9fs_mux_poll_tasks))
- n = ARRAY_SIZE(v9fs_mux_poll_tasks);
+ if (n > ARRAY_SIZE(p9_mux_poll_tasks))
+ n = ARRAY_SIZE(p9_mux_poll_tasks);
return n;
}
-static int v9fs_mux_poll_start(struct v9fs_mux_data *m)
+static int p9_mux_poll_start(struct p9_conn *m)
{
int i, n;
- struct v9fs_mux_poll_task *vpt, *vptlast;
+ struct p9_mux_poll_task *vpt, *vptlast;
struct task_struct *pproc;
- dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num,
- v9fs_mux_poll_task_num);
- mutex_lock(&v9fs_mux_task_lock);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, p9_mux_num,
+ p9_mux_poll_task_num);
+ mutex_lock(&p9_mux_task_lock);
- n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1);
- if (n > v9fs_mux_poll_task_num) {
- for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) {
- if (v9fs_mux_poll_tasks[i].task == NULL) {
- vpt = &v9fs_mux_poll_tasks[i];
- dprintk(DEBUG_MUX, "create proc %p\n", vpt);
- pproc = kthread_create(v9fs_poll_proc, vpt,
- "v9fs-poll");
+ n = p9_mux_calc_poll_procs(p9_mux_num + 1);
+ if (n > p9_mux_poll_task_num) {
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+ if (p9_mux_poll_tasks[i].task == NULL) {
+ vpt = &p9_mux_poll_tasks[i];
+ P9_DPRINTK(P9_DEBUG_MUX, "create proc %p\n",
+ vpt);
+ pproc = kthread_create(p9_poll_proc, vpt,
+ "v9fs-poll");
if (!IS_ERR(pproc)) {
vpt->task = pproc;
INIT_LIST_HEAD(&vpt->mux_list);
vpt->muxnum = 0;
- v9fs_mux_poll_task_num++;
+ p9_mux_poll_task_num++;
wake_up_process(vpt->task);
}
break;
}
}
- if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks))
- dprintk(DEBUG_ERROR, "warning: no free poll slots\n");
+ if (i >= ARRAY_SIZE(p9_mux_poll_tasks))
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "warning: no free poll slots\n");
}
- n = (v9fs_mux_num + 1) / v9fs_mux_poll_task_num +
- ((v9fs_mux_num + 1) % v9fs_mux_poll_task_num ? 1 : 0);
+ n = (p9_mux_num + 1) / p9_mux_poll_task_num +
+ ((p9_mux_num + 1) % p9_mux_poll_task_num ? 1 : 0);
vptlast = NULL;
- for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) {
- vpt = &v9fs_mux_poll_tasks[i];
+ for (i = 0; i < ARRAY_SIZE(p9_mux_poll_tasks); i++) {
+ vpt = &p9_mux_poll_tasks[i];
if (vpt->task != NULL) {
vptlast = vpt;
if (vpt->muxnum < n) {
- dprintk(DEBUG_MUX, "put in proc %d\n", i);
+ P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
list_add(&m->mux_list, &vpt->mux_list);
vpt->muxnum++;
m->poll_task = vpt;
- memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- init_poll_funcptr(&m->pt, v9fs_pollwait);
+ memset(&m->poll_waddr, 0,
+ sizeof(m->poll_waddr));
+ init_poll_funcptr(&m->pt, p9_pollwait);
break;
}
}
}
- if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) {
+ if (i >= ARRAY_SIZE(p9_mux_poll_tasks)) {
if (vptlast == NULL)
return -ENOMEM;
- dprintk(DEBUG_MUX, "put in proc %d\n", i);
+ P9_DPRINTK(P9_DEBUG_MUX, "put in proc %d\n", i);
list_add(&m->mux_list, &vptlast->mux_list);
vptlast->muxnum++;
m->poll_task = vptlast;
memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
- init_poll_funcptr(&m->pt, v9fs_pollwait);
+ init_poll_funcptr(&m->pt, p9_pollwait);
}
- v9fs_mux_num++;
- mutex_unlock(&v9fs_mux_task_lock);
+ p9_mux_num++;
+ mutex_unlock(&p9_mux_task_lock);
return 0;
}
-static void v9fs_mux_poll_stop(struct v9fs_mux_data *m)
+static void p9_mux_poll_stop(struct p9_conn *m)
{
int i;
- struct v9fs_mux_poll_task *vpt;
+ struct p9_mux_poll_task *vpt;
- mutex_lock(&v9fs_mux_task_lock);
+ mutex_lock(&p9_mux_task_lock);
vpt = m->poll_task;
list_del(&m->mux_list);
- for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
if (m->poll_waddr[i] != NULL) {
remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]);
m->poll_waddr[i] = NULL;
@@ -255,31 +254,31 @@ static void v9fs_mux_poll_stop(struct v9fs_mux_data *m)
}
vpt->muxnum--;
if (!vpt->muxnum) {
- dprintk(DEBUG_MUX, "destroy proc %p\n", vpt);
+ P9_DPRINTK(P9_DEBUG_MUX, "destroy proc %p\n", vpt);
kthread_stop(vpt->task);
vpt->task = NULL;
- v9fs_mux_poll_task_num--;
+ p9_mux_poll_task_num--;
}
- v9fs_mux_num--;
- mutex_unlock(&v9fs_mux_task_lock);
+ p9_mux_num--;
+ mutex_unlock(&p9_mux_task_lock);
}
/**
- * v9fs_mux_init - allocate and initialize the per-session mux data
+ * p9_conn_create - allocate and initialize the per-session mux data
* Creates the polling task if this is the first session.
*
* @trans - transport structure
* @msize - maximum message size
* @extended - pointer to the extended flag
*/
-struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
+struct p9_conn *p9_conn_create(struct p9_transport *trans, int msize,
unsigned char *extended)
{
int i, n;
- struct v9fs_mux_data *m, *mtmp;
+ struct p9_conn *m, *mtmp;
- dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize);
- m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL);
+ P9_DPRINTK(P9_DEBUG_MUX, "transport %p msize %d\n", trans, msize);
+ m = kmalloc(sizeof(struct p9_conn), GFP_KERNEL);
if (!m)
return ERR_PTR(-ENOMEM);
@@ -288,8 +287,12 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
m->msize = msize;
m->extended = extended;
m->trans = trans;
- idr_init(&m->tagpool.pool);
- init_MUTEX(&m->tagpool.lock);
+ m->tagpool = p9_idpool_create();
+ if (!m->tagpool) {
+ kfree(m);
+ return ERR_PTR(PTR_ERR(m->tagpool));
+ }
+
m->err = 0;
init_waitqueue_head(&m->equeue);
INIT_LIST_HEAD(&m->req_list);
@@ -299,29 +302,29 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
m->rbuf = NULL;
m->wpos = m->wsize = 0;
m->wbuf = NULL;
- INIT_WORK(&m->rq, v9fs_read_work);
- INIT_WORK(&m->wq, v9fs_write_work);
+ INIT_WORK(&m->rq, p9_read_work);
+ INIT_WORK(&m->wq, p9_write_work);
m->wsched = 0;
memset(&m->poll_waddr, 0, sizeof(m->poll_waddr));
m->poll_task = NULL;
- n = v9fs_mux_poll_start(m);
+ n = p9_mux_poll_start(m);
if (n)
return ERR_PTR(n);
n = trans->poll(trans, &m->pt);
if (n & POLLIN) {
- dprintk(DEBUG_MUX, "mux %p can read\n", m);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
set_bit(Rpending, &m->wsched);
}
if (n & POLLOUT) {
- dprintk(DEBUG_MUX, "mux %p can write\n", m);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
set_bit(Wpending, &m->wsched);
}
- for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) {
if (IS_ERR(m->poll_waddr[i])) {
- v9fs_mux_poll_stop(m);
+ p9_mux_poll_stop(m);
mtmp = (void *)m->poll_waddr; /* the error code */
kfree(m);
m = mtmp;
@@ -331,56 +334,58 @@ struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize,
return m;
}
+EXPORT_SYMBOL(p9_conn_create);
/**
- * v9fs_mux_destroy - cancels all pending requests and frees mux resources
+ * p9_mux_destroy - cancels all pending requests and frees mux resources
*/
-void v9fs_mux_destroy(struct v9fs_mux_data *m)
+void p9_conn_destroy(struct p9_conn *m)
{
- dprintk(DEBUG_MUX, "mux %p prev %p next %p\n", m,
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p prev %p next %p\n", m,
m->mux_list.prev, m->mux_list.next);
- v9fs_mux_cancel(m, -ECONNRESET);
+ p9_conn_cancel(m, -ECONNRESET);
if (!list_empty(&m->req_list)) {
/* wait until all processes waiting on this session exit */
- dprintk(DEBUG_MUX, "mux %p waiting for empty request queue\n",
- m);
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p waiting for empty request queue\n", m);
wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000);
- dprintk(DEBUG_MUX, "mux %p request queue empty: %d\n", m,
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p request queue empty: %d\n", m,
list_empty(&m->req_list));
}
- v9fs_mux_poll_stop(m);
+ p9_mux_poll_stop(m);
m->trans = NULL;
-
+ p9_idpool_destroy(m->tagpool);
kfree(m);
}
+EXPORT_SYMBOL(p9_conn_destroy);
/**
- * v9fs_pollwait - called by files poll operation to add v9fs-poll task
+ * p9_pollwait - called by files poll operation to add v9fs-poll task
* to files wait queue
*/
static void
-v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
+p9_pollwait(struct file *filp, wait_queue_head_t *wait_address,
poll_table * p)
{
int i;
- struct v9fs_mux_data *m;
+ struct p9_conn *m;
- m = container_of(p, struct v9fs_mux_data, pt);
- for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
+ m = container_of(p, struct p9_conn, pt);
+ for (i = 0; i < ARRAY_SIZE(m->poll_waddr); i++)
if (m->poll_waddr[i] == NULL)
break;
if (i >= ARRAY_SIZE(m->poll_waddr)) {
- dprintk(DEBUG_ERROR, "not enough wait_address slots\n");
+ P9_DPRINTK(P9_DEBUG_ERROR, "not enough wait_address slots\n");
return;
}
m->poll_waddr[i] = wait_address;
if (!wait_address) {
- dprintk(DEBUG_ERROR, "no wait_address\n");
+ P9_DPRINTK(P9_DEBUG_ERROR, "no wait_address\n");
m->poll_waddr[i] = ERR_PTR(-EIO);
return;
}
@@ -390,9 +395,9 @@ v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address,
}
/**
- * v9fs_poll_mux - polls a mux and schedules read or write works if necessary
+ * p9_poll_mux - polls a mux and schedules read or write works if necessary
*/
-static void v9fs_poll_mux(struct v9fs_mux_data *m)
+static void p9_poll_mux(struct p9_conn *m)
{
int n;
@@ -401,69 +406,69 @@ static void v9fs_poll_mux(struct v9fs_mux_data *m)
n = m->trans->poll(m->trans, NULL);
if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) {
- dprintk(DEBUG_MUX, "error mux %p err %d\n", m, n);
+ P9_DPRINTK(P9_DEBUG_MUX, "error mux %p err %d\n", m, n);
if (n >= 0)
n = -ECONNRESET;
- v9fs_mux_cancel(m, n);
+ p9_conn_cancel(m, n);
}
if (n & POLLIN) {
set_bit(Rpending, &m->wsched);
- dprintk(DEBUG_MUX, "mux %p can read\n", m);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can read\n", m);
if (!test_and_set_bit(Rworksched, &m->wsched)) {
- dprintk(DEBUG_MUX, "schedule read work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->rq);
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+ queue_work(p9_mux_wq, &m->rq);
}
}
if (n & POLLOUT) {
set_bit(Wpending, &m->wsched);
- dprintk(DEBUG_MUX, "mux %p can write\n", m);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p can write\n", m);
if ((m->wsize || !list_empty(&m->unsent_req_list))
&& !test_and_set_bit(Wworksched, &m->wsched)) {
- dprintk(DEBUG_MUX, "schedule write work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->wq);
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+ queue_work(p9_mux_wq, &m->wq);
}
}
}
/**
- * v9fs_poll_proc - polls all v9fs transports for new events and queues
+ * p9_poll_proc - polls all v9fs transports for new events and queues
* the appropriate work to the work queue
*/
-static int v9fs_poll_proc(void *a)
+static int p9_poll_proc(void *a)
{
- struct v9fs_mux_data *m, *mtmp;
- struct v9fs_mux_poll_task *vpt;
+ struct p9_conn *m, *mtmp;
+ struct p9_mux_poll_task *vpt;
vpt = a;
- dprintk(DEBUG_MUX, "start %p %p\n", current, vpt);
+ P9_DPRINTK(P9_DEBUG_MUX, "start %p %p\n", current, vpt);
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) {
- v9fs_poll_mux(m);
+ p9_poll_mux(m);
}
- dprintk(DEBUG_MUX, "sleeping...\n");
+ P9_DPRINTK(P9_DEBUG_MUX, "sleeping...\n");
schedule_timeout(SCHED_TIMEOUT * HZ);
}
__set_current_state(TASK_RUNNING);
- dprintk(DEBUG_MUX, "finish\n");
+ P9_DPRINTK(P9_DEBUG_MUX, "finish\n");
return 0;
}
/**
- * v9fs_write_work - called when a transport can send some data
+ * p9_write_work - called when a transport can send some data
*/
-static void v9fs_write_work(struct work_struct *work)
+static void p9_write_work(struct work_struct *work)
{
int n, err;
- struct v9fs_mux_data *m;
- struct v9fs_req *req;
+ struct p9_conn *m;
+ struct p9_req *req;
- m = container_of(work, struct v9fs_mux_data, wq);
+ m = container_of(work, struct p9_conn, wq);
if (m->err < 0) {
clear_bit(Wworksched, &m->wsched);
@@ -478,7 +483,7 @@ static void v9fs_write_work(struct work_struct *work)
spin_lock(&m->lock);
again:
- req = list_entry(m->unsent_req_list.next, struct v9fs_req,
+ req = list_entry(m->unsent_req_list.next, struct p9_req,
req_list);
list_move_tail(&req->req_list, &m->req_list);
if (req->err == ERREQFLUSH)
@@ -487,21 +492,25 @@ again:
m->wbuf = req->tcall->sdata;
m->wsize = req->tcall->size;
m->wpos = 0;
- dump_data(m->wbuf, m->wsize);
spin_unlock(&m->lock);
}
- dprintk(DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos,
+ m->wsize);
clear_bit(Wpending, &m->wsched);
err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos);
- dprintk(DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p sent %d bytes\n", m, err);
if (err == -EAGAIN) {
clear_bit(Wworksched, &m->wsched);
return;
}
- if (err <= 0)
+ if (err < 0)
+ goto error;
+ else if (err == 0) {
+ err = -EREMOTEIO;
goto error;
+ }
m->wpos += err;
if (m->wpos == m->wsize)
@@ -514,8 +523,8 @@ again:
n = m->trans->poll(m->trans, NULL);
if (n & POLLOUT) {
- dprintk(DEBUG_MUX, "schedule write work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->wq);
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule write work %p\n", m);
+ queue_work(p9_mux_wq, &m->wq);
} else
clear_bit(Wworksched, &m->wsched);
} else
@@ -523,27 +532,28 @@ again:
return;
- error:
- v9fs_mux_cancel(m, err);
+error:
+ p9_conn_cancel(m, err);
clear_bit(Wworksched, &m->wsched);
}
-static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
+static void process_request(struct p9_conn *m, struct p9_req *req)
{
int ecode;
- struct v9fs_str *ename;
+ struct p9_str *ename;
- if (!req->err && req->rcall->id == RERROR) {
+ if (!req->err && req->rcall->id == P9_RERROR) {
ecode = req->rcall->params.rerror.errno;
ename = &req->rcall->params.rerror.error;
- dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str);
+ P9_DPRINTK(P9_DEBUG_MUX, "Rerror %.*s\n", ename->len,
+ ename->str);
if (*m->extended)
req->err = -ecode;
if (!req->err) {
- req->err = v9fs_errstr2errno(ename->str, ename->len);
+ req->err = p9_errstr2errno(ename->str, ename->len);
if (!req->err) { /* string match failed */
PRINT_FCALL_ERROR("unknown error", req->rcall);
@@ -553,47 +563,48 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
req->err = -ESERVERFAULT;
}
} else if (req->tcall && req->rcall->id != req->tcall->id + 1) {
- dprintk(DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n",
- req->tcall->id + 1, req->rcall->id);
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "fcall mismatch: expected %d, got %d\n",
+ req->tcall->id + 1, req->rcall->id);
if (!req->err)
req->err = -EIO;
}
}
/**
- * v9fs_read_work - called when there is some data to be read from a transport
+ * p9_read_work - called when there is some data to be read from a transport
*/
-static void v9fs_read_work(struct work_struct *work)
+static void p9_read_work(struct work_struct *work)
{
int n, err;
- struct v9fs_mux_data *m;
- struct v9fs_req *req, *rptr, *rreq;
- struct v9fs_fcall *rcall;
+ struct p9_conn *m;
+ struct p9_req *req, *rptr, *rreq;
+ struct p9_fcall *rcall;
char *rbuf;
- m = container_of(work, struct v9fs_mux_data, rq);
+ m = container_of(work, struct p9_conn, rq);
if (m->err < 0)
return;
rcall = NULL;
- dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
+ P9_DPRINTK(P9_DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos);
if (!m->rcall) {
m->rcall =
- kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL);
+ kmalloc(sizeof(struct p9_fcall) + m->msize, GFP_KERNEL);
if (!m->rcall) {
err = -ENOMEM;
goto error;
}
- m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
+ m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
m->rpos = 0;
}
clear_bit(Rpending, &m->wsched);
err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos);
- dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p got %d bytes\n", m, err);
if (err == -EAGAIN) {
clear_bit(Rworksched, &m->wsched);
return;
@@ -606,7 +617,7 @@ static void v9fs_read_work(struct work_struct *work)
while (m->rpos > 4) {
n = le32_to_cpu(*(__le32 *) m->rbuf);
if (n >= m->msize) {
- dprintk(DEBUG_ERROR,
+ P9_DPRINTK(P9_DEBUG_ERROR,
"requested packet size too big: %d\n", n);
err = -EIO;
goto error;
@@ -615,32 +626,33 @@ static void v9fs_read_work(struct work_struct *work)
if (m->rpos < n)
break;
- dump_data(m->rbuf, n);
err =
- v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
+ p9_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended);
if (err < 0) {
goto error;
}
- if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) {
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
char buf[150];
- v9fs_printfcall(buf, sizeof(buf), m->rcall,
+ p9_printfcall(buf, sizeof(buf), m->rcall,
*m->extended);
printk(KERN_NOTICE ">>> %p %s\n", m, buf);
}
+#endif
rcall = m->rcall;
rbuf = m->rbuf;
if (m->rpos > n) {
- m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize,
+ m->rcall = kmalloc(sizeof(struct p9_fcall) + m->msize,
GFP_KERNEL);
if (!m->rcall) {
err = -ENOMEM;
goto error;
}
- m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall);
+ m->rbuf = (char *)m->rcall + sizeof(struct p9_fcall);
memmove(m->rbuf, rbuf + n, m->rpos - n);
m->rpos -= n;
} else {
@@ -649,8 +661,8 @@ static void v9fs_read_work(struct work_struct *work)
m->rpos = 0;
}
- dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id,
- rcall->tag);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p fcall id %d tag %d\n", m,
+ rcall->id, rcall->tag);
req = NULL;
spin_lock(&m->lock);
@@ -677,10 +689,10 @@ static void v9fs_read_work(struct work_struct *work)
wake_up(&m->equeue);
}
} else {
- if (err >= 0 && rcall->id != RFLUSH)
- dprintk(DEBUG_ERROR,
- "unexpected response mux %p id %d tag %d\n",
- m, rcall->id, rcall->tag);
+ if (err >= 0 && rcall->id != P9_RFLUSH)
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "unexpected response mux %p id %d tag %d\n",
+ m, rcall->id, rcall->tag);
kfree(rcall);
}
}
@@ -692,8 +704,8 @@ static void v9fs_read_work(struct work_struct *work)
n = m->trans->poll(m->trans, NULL);
if (n & POLLIN) {
- dprintk(DEBUG_MUX, "schedule read work mux %p\n", m);
- queue_work(v9fs_mux_wq, &m->rq);
+ P9_DPRINTK(P9_DEBUG_MUX, "schedule read work %p\n", m);
+ queue_work(p9_mux_wq, &m->rq);
} else
clear_bit(Rworksched, &m->wsched);
} else
@@ -701,13 +713,13 @@ static void v9fs_read_work(struct work_struct *work)
return;
- error:
- v9fs_mux_cancel(m, err);
+error:
+ p9_conn_cancel(m, err);
clear_bit(Rworksched, &m->wsched);
}
/**
- * v9fs_send_request - send 9P request
+ * p9_send_request - send 9P request
* The function can sleep until the request is scheduled for sending.
* The function can be interrupted. Return from the function is not
* a guarantee that the request is sent successfully. Can return errors
@@ -718,37 +730,40 @@ static void v9fs_read_work(struct work_struct *work)
* @cb: callback function to call when response is received
* @cba: parameter to pass to the callback function
*/
-static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m,
- struct v9fs_fcall *tc,
- v9fs_mux_req_callback cb, void *cba)
+static struct p9_req *p9_send_request(struct p9_conn *m,
+ struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *cba)
{
int n;
- struct v9fs_req *req;
+ struct p9_req *req;
- dprintk(DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current,
tc, tc->id);
if (m->err < 0)
return ERR_PTR(m->err);
- req = kmalloc(sizeof(struct v9fs_req), GFP_KERNEL);
+ req = kmalloc(sizeof(struct p9_req), GFP_KERNEL);
if (!req)
return ERR_PTR(-ENOMEM);
- if (tc->id == TVERSION)
- n = V9FS_NOTAG;
+ if (tc->id == P9_TVERSION)
+ n = P9_NOTAG;
else
- n = v9fs_mux_get_tag(m);
+ n = p9_mux_get_tag(m);
if (n < 0)
return ERR_PTR(-ENOMEM);
- v9fs_set_tag(tc, n);
- if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) {
+ p9_set_tag(tc, n);
+
+#ifdef CONFIG_NET_9P_DEBUG
+ if ((p9_debug_level&P9_DEBUG_FCALL) == P9_DEBUG_FCALL) {
char buf[150];
- v9fs_printfcall(buf, sizeof(buf), tc, *m->extended);
+ p9_printfcall(buf, sizeof(buf), tc, *m->extended);
printk(KERN_NOTICE "<<< %p %s\n", m, buf);
}
+#endif
spin_lock_init(&req->lock);
req->tag = n;
@@ -769,26 +784,26 @@ static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m,
n = m->trans->poll(m->trans, NULL);
if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched))
- queue_work(v9fs_mux_wq, &m->wq);
+ queue_work(p9_mux_wq, &m->wq);
return req;
}
-static void v9fs_mux_free_request(struct v9fs_mux_data *m, struct v9fs_req *req)
+static void p9_mux_free_request(struct p9_conn *m, struct p9_req *req)
{
- v9fs_mux_put_tag(m, req->tag);
+ p9_mux_put_tag(m, req->tag);
kfree(req);
}
-static void v9fs_mux_flush_cb(struct v9fs_req *freq, void *a)
+static void p9_mux_flush_cb(struct p9_req *freq, void *a)
{
- v9fs_mux_req_callback cb;
+ p9_conn_req_callback cb;
int tag;
- struct v9fs_mux_data *m;
- struct v9fs_req *req, *rreq, *rptr;
+ struct p9_conn *m;
+ struct p9_req *req, *rreq, *rptr;
m = a;
- dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m,
freq->tcall, freq->rcall, freq->err,
freq->tcall->params.tflush.oldtag);
@@ -820,22 +835,23 @@ static void v9fs_mux_flush_cb(struct v9fs_req *freq, void *a)
kfree(freq->tcall);
kfree(freq->rcall);
- v9fs_mux_free_request(m, freq);
+ p9_mux_free_request(m, freq);
}
static int
-v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req)
+p9_mux_flush_request(struct p9_conn *m, struct p9_req *req)
{
- struct v9fs_fcall *fc;
- struct v9fs_req *rreq, *rptr;
+ struct p9_fcall *fc;
+ struct p9_req *rreq, *rptr;
- dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag);
/* if a response was received for a request, do nothing */
spin_lock(&req->lock);
if (req->rcall || req->err) {
spin_unlock(&req->lock);
- dprintk(DEBUG_MUX, "mux %p req %p response already received\n", m, req);
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p req %p response already received\n", m, req);
return 0;
}
@@ -846,7 +862,8 @@ v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req)
/* if the request is not sent yet, just remove it from the list */
list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) {
if (rreq->tag == req->tag) {
- dprintk(DEBUG_MUX, "mux %p req %p request is not sent yet\n", m, req);
+ P9_DPRINTK(P9_DEBUG_MUX,
+ "mux %p req %p request is not sent yet\n", m, req);
list_del(&rreq->req_list);
req->flush = Flushed;
spin_unlock(&m->lock);
@@ -858,42 +875,42 @@ v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req)
spin_unlock(&m->lock);
clear_thread_flag(TIF_SIGPENDING);
- fc = v9fs_create_tflush(req->tag);
- v9fs_send_request(m, fc, v9fs_mux_flush_cb, m);
+ fc = p9_create_tflush(req->tag);
+ p9_send_request(m, fc, p9_mux_flush_cb, m);
return 1;
}
static void
-v9fs_mux_rpc_cb(struct v9fs_req *req, void *a)
+p9_conn_rpc_cb(struct p9_req *req, void *a)
{
- struct v9fs_mux_rpc *r;
+ struct p9_mux_rpc *r;
- dprintk(DEBUG_MUX, "req %p r %p\n", req, a);
+ P9_DPRINTK(P9_DEBUG_MUX, "req %p r %p\n", req, a);
r = a;
r->rcall = req->rcall;
r->err = req->err;
- if (req->flush!=None && !req->err)
+ if (req->flush != None && !req->err)
r->err = -ERESTARTSYS;
wake_up(&r->wqueue);
}
/**
- * v9fs_mux_rpc - sends 9P request and waits until a response is available.
+ * p9_mux_rpc - sends 9P request and waits until a response is available.
* The function can be interrupted.
* @m: mux data
* @tc: request to be sent
* @rc: pointer where a pointer to the response is stored
*/
int
-v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
- struct v9fs_fcall **rc)
+p9_conn_rpc(struct p9_conn *m, struct p9_fcall *tc,
+ struct p9_fcall **rc)
{
int err, sigpending;
unsigned long flags;
- struct v9fs_req *req;
- struct v9fs_mux_rpc r;
+ struct p9_req *req;
+ struct p9_mux_rpc r;
r.err = 0;
r.tcall = tc;
@@ -910,10 +927,10 @@ v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
clear_thread_flag(TIF_SIGPENDING);
}
- req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r);
+ req = p9_send_request(m, tc, p9_conn_rpc_cb, &r);
if (IS_ERR(req)) {
err = PTR_ERR(req);
- dprintk(DEBUG_MUX, "error %d\n", err);
+ P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
return err;
}
@@ -921,15 +938,16 @@ v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
if (r.err < 0)
err = r.err;
- if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) {
- if (v9fs_mux_flush_request(m, req)) {
+ if (err == -ERESTARTSYS && m->trans->status == Connected
+ && m->err == 0) {
+ if (p9_mux_flush_request(m, req)) {
/* wait until we get response of the flush message */
do {
clear_thread_flag(TIF_SIGPENDING);
err = wait_event_interruptible(r.wqueue,
r.rcall || r.err);
- } while (!r.rcall && !r.err && err==-ERESTARTSYS &&
- m->trans->status==Connected && !m->err);
+ } while (!r.rcall && !r.err && err == -ERESTARTSYS &&
+ m->trans->status == Connected && !m->err);
err = -ERESTARTSYS;
}
@@ -947,50 +965,52 @@ v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
else
kfree(r.rcall);
- v9fs_mux_free_request(m, req);
+ p9_mux_free_request(m, req);
if (err > 0)
err = -EIO;
return err;
}
+EXPORT_SYMBOL(p9_conn_rpc);
-#if 0
+#ifdef P9_NONBLOCK
/**
- * v9fs_mux_rpcnb - sends 9P request without waiting for response.
+ * p9_conn_rpcnb - sends 9P request without waiting for response.
* @m: mux data
* @tc: request to be sent
* @cb: callback function to be called when response arrives
* @cba: value to pass to the callback function
*/
-int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc,
- v9fs_mux_req_callback cb, void *a)
+int p9_conn_rpcnb(struct p9_conn *m, struct p9_fcall *tc,
+ p9_conn_req_callback cb, void *a)
{
int err;
- struct v9fs_req *req;
+ struct p9_req *req;
- req = v9fs_send_request(m, tc, cb, a);
+ req = p9_send_request(m, tc, cb, a);
if (IS_ERR(req)) {
err = PTR_ERR(req);
- dprintk(DEBUG_MUX, "error %d\n", err);
+ P9_DPRINTK(P9_DEBUG_MUX, "error %d\n", err);
return PTR_ERR(req);
}
- dprintk(DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
+ P9_DPRINTK(P9_DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag);
return 0;
}
-#endif /* 0 */
+EXPORT_SYMBOL(p9_conn_rpcnb);
+#endif /* P9_NONBLOCK */
/**
- * v9fs_mux_cancel - cancel all pending requests with error
+ * p9_conn_cancel - cancel all pending requests with error
* @m: mux data
* @err: error code
*/
-void v9fs_mux_cancel(struct v9fs_mux_data *m, int err)
+void p9_conn_cancel(struct p9_conn *m, int err)
{
- struct v9fs_req *req, *rtmp;
+ struct p9_req *req, *rtmp;
LIST_HEAD(cancel_list);
- dprintk(DEBUG_ERROR, "mux %p err %d\n", m, err);
+ P9_DPRINTK(P9_DEBUG_ERROR, "mux %p err %d\n", m, err);
m->err = err;
spin_lock(&m->lock);
list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) {
@@ -1014,20 +1034,21 @@ void v9fs_mux_cancel(struct v9fs_mux_data *m, int err)
wake_up(&m->equeue);
}
+EXPORT_SYMBOL(p9_conn_cancel);
-static u16 v9fs_mux_get_tag(struct v9fs_mux_data *m)
+static u16 p9_mux_get_tag(struct p9_conn *m)
{
int tag;
- tag = v9fs_get_idpool(&m->tagpool);
+ tag = p9_idpool_get(m->tagpool);
if (tag < 0)
- return V9FS_NOTAG;
+ return P9_NOTAG;
else
return (u16) tag;
}
-static void v9fs_mux_put_tag(struct v9fs_mux_data *m, u16 tag)
+static void p9_mux_put_tag(struct p9_conn *m, u16 tag)
{
- if (tag != V9FS_NOTAG && v9fs_check_idpool(tag, &m->tagpool))
- v9fs_put_idpool(tag, &m->tagpool);
+ if (tag != P9_NOTAG && p9_idpool_check(tag, m->tagpool))
+ p9_idpool_put(tag, m->tagpool);
}
diff --git a/net/9p/sysctl.c b/net/9p/sysctl.c
new file mode 100644
index 000000000000..8b61027a24ea
--- /dev/null
+++ b/net/9p/sysctl.c
@@ -0,0 +1,81 @@
+/*
+ * net/9p/sysctl.c
+ *
+ * 9P sysctl interface
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ *
+ * 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:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sysctl.h>
+#include <linux/init.h>
+#include <net/9p/9p.h>
+
+static struct ctl_table p9_table[] = {
+#ifdef CONFIG_NET_9P_DEBUG
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "debug",
+ .data = &p9_debug_level,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
+#endif
+ {},
+};
+
+static struct ctl_table p9_net_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "9p",
+ .maxlen = 0,
+ .mode = 0555,
+ .child = p9_table,
+ },
+ {},
+};
+
+static struct ctl_table p9_ctl_table[] = {
+ {
+ .ctl_name = CTL_NET,
+ .procname = "net",
+ .maxlen = 0,
+ .mode = 0555,
+ .child = p9_net_table,
+ },
+ {},
+};
+
+static struct ctl_table_header *p9_table_header;
+
+int __init p9_sysctl_register(void)
+{
+ p9_table_header = register_sysctl_table(p9_ctl_table);
+ if (!p9_table_header)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void __exit p9_sysctl_unregister(void)
+{
+ unregister_sysctl_table(p9_table_header);
+}
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
new file mode 100644
index 000000000000..fd636e94358f
--- /dev/null
+++ b/net/9p/trans_fd.c
@@ -0,0 +1,363 @@
+/*
+ * linux/fs/9p/trans_fd.c
+ *
+ * Fd transport layer. Includes deprecated socket layer.
+ *
+ * Copyright (C) 2006 by Russ Cox <rsc@swtch.com>
+ * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004-2005 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 1997-2002 by Ron Minnich <rminnich@sarnoff.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/in.h>
+#include <linux/module.h>
+#include <linux/net.h>
+#include <linux/ipv6.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/un.h>
+#include <linux/uaccess.h>
+#include <linux/inet.h>
+#include <linux/idr.h>
+#include <linux/file.h>
+#include <net/9p/9p.h>
+#include <net/9p/transport.h>
+
+#define P9_PORT 564
+
+struct p9_trans_fd {
+ struct file *rd;
+ struct file *wr;
+};
+
+static int p9_socket_open(struct p9_transport *trans, struct socket *csocket);
+static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd);
+static int p9_fd_read(struct p9_transport *trans, void *v, int len);
+static int p9_fd_write(struct p9_transport *trans, void *v, int len);
+static unsigned int p9_fd_poll(struct p9_transport *trans,
+ struct poll_table_struct *pt);
+static void p9_fd_close(struct p9_transport *trans);
+
+struct p9_transport *p9_trans_create_tcp(const char *addr, int port)
+{
+ int err;
+ struct p9_transport *trans;
+ struct socket *csocket;
+ struct sockaddr_in sin_server;
+
+ csocket = NULL;
+ trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
+
+ trans->write = p9_fd_write;
+ trans->read = p9_fd_read;
+ trans->close = p9_fd_close;
+ trans->poll = p9_fd_poll;
+
+ sin_server.sin_family = AF_INET;
+ sin_server.sin_addr.s_addr = in_aton(addr);
+ sin_server.sin_port = htons(port);
+ sock_create_kern(PF_INET, SOCK_STREAM, IPPROTO_TCP, &csocket);
+
+ if (!csocket) {
+ P9_EPRINTK(KERN_ERR, "p9_trans_tcp: problem creating socket\n");
+ err = -EIO;
+ goto error;
+ }
+
+ err = csocket->ops->connect(csocket,
+ (struct sockaddr *)&sin_server,
+ sizeof(struct sockaddr_in), 0);
+ if (err < 0) {
+ P9_EPRINTK(KERN_ERR,
+ "p9_trans_tcp: problem connecting socket to %s\n",
+ addr);
+ goto error;
+ }
+
+ err = p9_socket_open(trans, csocket);
+ if (err < 0)
+ goto error;
+
+ return trans;
+
+error:
+ if (csocket)
+ sock_release(csocket);
+
+ kfree(trans);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_trans_create_tcp);
+
+struct p9_transport *p9_trans_create_unix(const char *addr)
+{
+ int err;
+ struct socket *csocket;
+ struct sockaddr_un sun_server;
+ struct p9_transport *trans;
+
+ csocket = NULL;
+ trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
+
+ trans->write = p9_fd_write;
+ trans->read = p9_fd_read;
+ trans->close = p9_fd_close;
+ trans->poll = p9_fd_poll;
+
+ if (strlen(addr) > UNIX_PATH_MAX) {
+ P9_EPRINTK(KERN_ERR, "p9_trans_unix: address too long: %s\n",
+ addr);
+ err = -ENAMETOOLONG;
+ goto error;
+ }
+
+ sun_server.sun_family = PF_UNIX;
+ strcpy(sun_server.sun_path, addr);
+ sock_create_kern(PF_UNIX, SOCK_STREAM, 0, &csocket);
+ err = csocket->ops->connect(csocket, (struct sockaddr *)&sun_server,
+ sizeof(struct sockaddr_un) - 1, 0);
+ if (err < 0) {
+ P9_EPRINTK(KERN_ERR,
+ "p9_trans_unix: problem connecting socket: %s: %d\n",
+ addr, err);
+ goto error;
+ }
+
+ err = p9_socket_open(trans, csocket);
+ if (err < 0)
+ goto error;
+
+ return trans;
+
+error:
+ if (csocket)
+ sock_release(csocket);
+
+ kfree(trans);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_trans_create_unix);
+
+struct p9_transport *p9_trans_create_fd(int rfd, int wfd)
+{
+ int err;
+ struct p9_transport *trans;
+
+ if (rfd == ~0 || wfd == ~0) {
+ printk(KERN_ERR "v9fs: Insufficient options for proto=fd\n");
+ return ERR_PTR(-ENOPROTOOPT);
+ }
+
+ trans = kmalloc(sizeof(struct p9_transport), GFP_KERNEL);
+ if (!trans)
+ return ERR_PTR(-ENOMEM);
+
+ trans->write = p9_fd_write;
+ trans->read = p9_fd_read;
+ trans->close = p9_fd_close;
+ trans->poll = p9_fd_poll;
+
+ err = p9_fd_open(trans, rfd, wfd);
+ if (err < 0)
+ goto error;
+
+ return trans;
+
+error:
+ kfree(trans);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(p9_trans_create_fd);
+
+static int p9_socket_open(struct p9_transport *trans, struct socket *csocket)
+{
+ int fd, ret;
+
+ csocket->sk->sk_allocation = GFP_NOIO;
+ fd = sock_map_fd(csocket);
+ if (fd < 0) {
+ P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to map fd\n");
+ return fd;
+ }
+
+ ret = p9_fd_open(trans, fd, fd);
+ if (ret < 0) {
+ P9_EPRINTK(KERN_ERR, "p9_socket_open: failed to open fd\n");
+ sockfd_put(csocket);
+ return ret;
+ }
+
+ ((struct p9_trans_fd *)trans->priv)->rd->f_flags |= O_NONBLOCK;
+
+ return 0;
+}
+
+static int p9_fd_open(struct p9_transport *trans, int rfd, int wfd)
+{
+ struct p9_trans_fd *ts = kmalloc(sizeof(struct p9_trans_fd),
+ GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ ts->rd = fget(rfd);
+ ts->wr = fget(wfd);
+ if (!ts->rd || !ts->wr) {
+ if (ts->rd)
+ fput(ts->rd);
+ if (ts->wr)
+ fput(ts->wr);
+ kfree(ts);
+ return -EIO;
+ }
+
+ trans->priv = ts;
+ trans->status = Connected;
+
+ return 0;
+}
+
+/**
+ * p9_fd_read- read from a fd
+ * @v9ses: session information
+ * @v: buffer to receive data into
+ * @len: size of receive buffer
+ *
+ */
+static int p9_fd_read(struct p9_transport *trans, void *v, int len)
+{
+ int ret;
+ struct p9_trans_fd *ts = NULL;
+
+ if (trans && trans->status != Disconnected)
+ ts = trans->priv;
+
+ if (!ts)
+ return -EREMOTEIO;
+
+ if (!(ts->rd->f_flags & O_NONBLOCK))
+ P9_DPRINTK(P9_DEBUG_ERROR, "blocking read ...\n");
+
+ ret = kernel_read(ts->rd, ts->rd->f_pos, v, len);
+ if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
+ trans->status = Disconnected;
+ return ret;
+}
+
+/**
+ * p9_fd_write - write to a socket
+ * @v9ses: session information
+ * @v: buffer to send data from
+ * @len: size of send buffer
+ *
+ */
+static int p9_fd_write(struct p9_transport *trans, void *v, int len)
+{
+ int ret;
+ mm_segment_t oldfs;
+ struct p9_trans_fd *ts = NULL;
+
+ if (trans && trans->status != Disconnected)
+ ts = trans->priv;
+
+ if (!ts)
+ return -EREMOTEIO;
+
+ if (!(ts->wr->f_flags & O_NONBLOCK))
+ P9_DPRINTK(P9_DEBUG_ERROR, "blocking write ...\n");
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+ /* The cast to a user pointer is valid due to the set_fs() */
+ ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
+ set_fs(oldfs);
+
+ if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
+ trans->status = Disconnected;
+ return ret;
+}
+
+static unsigned int
+p9_fd_poll(struct p9_transport *trans, struct poll_table_struct *pt)
+{
+ int ret, n;
+ struct p9_trans_fd *ts = NULL;
+ mm_segment_t oldfs;
+
+ if (trans && trans->status == Connected)
+ ts = trans->priv;
+
+ if (!ts)
+ return -EREMOTEIO;
+
+ if (!ts->rd->f_op || !ts->rd->f_op->poll)
+ return -EIO;
+
+ if (!ts->wr->f_op || !ts->wr->f_op->poll)
+ return -EIO;
+
+ oldfs = get_fs();
+ set_fs(get_ds());
+
+ ret = ts->rd->f_op->poll(ts->rd, pt);
+ if (ret < 0)
+ goto end;
+
+ if (ts->rd != ts->wr) {
+ n = ts->wr->f_op->poll(ts->wr, pt);
+ if (n < 0) {
+ ret = n;
+ goto end;
+ }
+ ret = (ret & ~POLLOUT) | (n & ~POLLIN);
+ }
+
+end:
+ set_fs(oldfs);
+ return ret;
+}
+
+/**
+ * p9_sock_close - shutdown socket
+ * @trans: private socket structure
+ *
+ */
+static void p9_fd_close(struct p9_transport *trans)
+{
+ struct p9_trans_fd *ts;
+
+ if (!trans)
+ return;
+
+ ts = xchg(&trans->priv, NULL);
+
+ if (!ts)
+ return;
+
+ trans->status = Disconnected;
+ if (ts->rd)
+ fput(ts->rd);
+ if (ts->wr)
+ fput(ts->wr);
+ kfree(ts);
+}
+
diff --git a/net/9p/util.c b/net/9p/util.c
new file mode 100644
index 000000000000..22077b79395d
--- /dev/null
+++ b/net/9p/util.c
@@ -0,0 +1,125 @@
+/*
+ * net/9p/util.c
+ *
+ * This file contains some helper functions
+ *
+ * Copyright (C) 2007 by Latchesar Ionkov <lucho@ionkov.net>
+ * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
+ * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
+ *
+ * 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:
+ * Free Software Foundation
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA 02111-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/parser.h>
+#include <linux/idr.h>
+#include <net/9p/9p.h>
+
+struct p9_idpool {
+ struct semaphore lock;
+ struct idr pool;
+};
+
+struct p9_idpool *p9_idpool_create(void)
+{
+ struct p9_idpool *p;
+
+ p = kmalloc(sizeof(struct p9_idpool), GFP_KERNEL);
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+
+ init_MUTEX(&p->lock);
+ idr_init(&p->pool);
+
+ return p;
+}
+EXPORT_SYMBOL(p9_idpool_create);
+
+void p9_idpool_destroy(struct p9_idpool *p)
+{
+ idr_destroy(&p->pool);
+ kfree(p);
+}
+EXPORT_SYMBOL(p9_idpool_destroy);
+
+/**
+ * p9_idpool_get - allocate numeric id from pool
+ * @p - pool to allocate from
+ *
+ * XXX - This seems to be an awful generic function, should it be in idr.c with
+ * the lock included in struct idr?
+ */
+
+int p9_idpool_get(struct p9_idpool *p)
+{
+ int i = 0;
+ int error;
+
+retry:
+ if (idr_pre_get(&p->pool, GFP_KERNEL) == 0)
+ return 0;
+
+ if (down_interruptible(&p->lock) == -EINTR) {
+ P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
+ return -1;
+ }
+
+ /* no need to store exactly p, we just need something non-null */
+ error = idr_get_new(&p->pool, p, &i);
+ up(&p->lock);
+
+ if (error == -EAGAIN)
+ goto retry;
+ else if (error)
+ return -1;
+
+ return i;
+}
+EXPORT_SYMBOL(p9_idpool_get);
+
+/**
+ * p9_idpool_put - release numeric id from pool
+ * @p - pool to allocate from
+ *
+ * XXX - This seems to be an awful generic function, should it be in idr.c with
+ * the lock included in struct idr?
+ */
+
+void p9_idpool_put(int id, struct p9_idpool *p)
+{
+ if (down_interruptible(&p->lock) == -EINTR) {
+ P9_EPRINTK(KERN_WARNING, "Interrupted while locking\n");
+ return;
+ }
+ idr_remove(&p->pool, id);
+ up(&p->lock);
+}
+EXPORT_SYMBOL(p9_idpool_put);
+
+/**
+ * p9_idpool_check - check if the specified id is available
+ * @id - id to check
+ * @p - pool
+ */
+int p9_idpool_check(int id, struct p9_idpool *p)
+{
+ return idr_find(&p->pool, id) != NULL;
+}
+EXPORT_SYMBOL(p9_idpool_check);
diff --git a/net/Kconfig b/net/Kconfig
index f3de72978ab6..cdba08ca2efe 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -227,6 +227,7 @@ source "net/ieee80211/Kconfig"
endmenu
source "net/rfkill/Kconfig"
+source "net/9p/Kconfig"
endif # if NET
endmenu # Networking
diff --git a/net/Makefile b/net/Makefile
index 34e5b2d7f877..bbe7d2a41486 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -37,7 +37,6 @@ obj-$(CONFIG_AX25) += ax25/
obj-$(CONFIG_IRDA) += irda/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_SUNRPC) += sunrpc/
-obj-$(CONFIG_RXRPC) += rxrpc/
obj-$(CONFIG_AF_RXRPC) += rxrpc/
obj-$(CONFIG_ATM) += atm/
obj-$(CONFIG_DECNET) += decnet/
@@ -52,6 +51,7 @@ obj-$(CONFIG_TIPC) += tipc/
obj-$(CONFIG_NETLABEL) += netlabel/
obj-$(CONFIG_IUCV) += iucv/
obj-$(CONFIG_RFKILL) += rfkill/
+obj-$(CONFIG_NET_9P) += 9p/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c
index 5ef6a238bdbc..3d1655f98388 100644
--- a/net/appletalk/aarp.c
+++ b/net/appletalk/aarp.c
@@ -1024,7 +1024,7 @@ static int aarp_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations aarp_seq_ops = {
+static const struct seq_operations aarp_seq_ops = {
.start = aarp_seq_start,
.next = aarp_seq_next,
.stop = aarp_seq_stop,
diff --git a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c
index 57ff8122b5c5..87a582cc8111 100644
--- a/net/appletalk/atalk_proc.c
+++ b/net/appletalk/atalk_proc.c
@@ -204,21 +204,21 @@ out:
return 0;
}
-static struct seq_operations atalk_seq_interface_ops = {
+static const struct seq_operations atalk_seq_interface_ops = {
.start = atalk_seq_interface_start,
.next = atalk_seq_interface_next,
.stop = atalk_seq_interface_stop,
.show = atalk_seq_interface_show,
};
-static struct seq_operations atalk_seq_route_ops = {
+static const struct seq_operations atalk_seq_route_ops = {
.start = atalk_seq_route_start,
.next = atalk_seq_route_next,
.stop = atalk_seq_route_stop,
.show = atalk_seq_route_show,
};
-static struct seq_operations atalk_seq_socket_ops = {
+static const struct seq_operations atalk_seq_socket_ops = {
.start = atalk_seq_socket_start,
.next = atalk_seq_socket_next,
.stop = atalk_seq_socket_stop,
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 0e9f00c5c899..c0f6861eefe3 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -460,11 +460,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
skb_pull(skb, plen);
skb_set_mac_header(skb, -ETH_HLEN);
skb->pkt_type = PACKET_HOST;
-#ifdef CONFIG_BR2684_FAST_TRANS
- skb->protocol = ((u16 *) skb->data)[-1];
-#else /* some protocols might require this: */
skb->protocol = br_type_trans(skb, net_dev);
-#endif /* CONFIG_BR2684_FAST_TRANS */
#else
skb_pull(skb, plen - ETH_HLEN);
skb->protocol = eth_type_trans(skb, net_dev);
@@ -699,28 +695,13 @@ static struct atm_ioctl br2684_ioctl_ops = {
#ifdef CONFIG_PROC_FS
static void *br2684_seq_start(struct seq_file *seq, loff_t *pos)
{
- loff_t offs = 0;
- struct br2684_dev *brd;
-
read_lock(&devs_lock);
-
- list_for_each_entry(brd, &br2684_devs, br2684_devs) {
- if (offs == *pos)
- return brd;
- ++offs;
- }
- return NULL;
+ return seq_list_start(&br2684_devs, *pos);
}
static void *br2684_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct br2684_dev *brd = v;
-
- ++*pos;
-
- brd = list_entry(brd->br2684_devs.next,
- struct br2684_dev, br2684_devs);
- return (&brd->br2684_devs != &br2684_devs) ? brd : NULL;
+ return seq_list_next(v, &br2684_devs, pos);
}
static void br2684_seq_stop(struct seq_file *seq, void *v)
@@ -730,7 +711,8 @@ static void br2684_seq_stop(struct seq_file *seq, void *v)
static int br2684_seq_show(struct seq_file *seq, void *v)
{
- const struct br2684_dev *brdev = v;
+ const struct br2684_dev *brdev = list_entry(v, struct br2684_dev,
+ br2684_devs);
const struct net_device *net_dev = brdev->net_dev;
const struct br2684_vcc *brvcc;
@@ -772,7 +754,7 @@ static int br2684_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations br2684_seq_ops = {
+static const struct seq_operations br2684_seq_ops = {
.start = br2684_seq_start,
.next = br2684_seq_next,
.stop = br2684_seq_stop,
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 876b77f14745..ecf0f79b94ae 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -928,7 +928,7 @@ static int clip_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations arp_seq_ops = {
+static const struct seq_operations arp_seq_ops = {
.start = clip_seq_start,
.next = neigh_seq_next,
.stop = neigh_seq_stop,
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 4dc5f2b8c43c..2770fb451ae8 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -1174,7 +1174,7 @@ static int lec_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations lec_seq_ops = {
+static const struct seq_operations lec_seq_ops = {
.start = lec_seq_start,
.next = lec_seq_next,
.stop = lec_seq_stop,
diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
index 4b05cbec7a58..91f3ffc90dbd 100644
--- a/net/atm/mpoa_proc.c
+++ b/net/atm/mpoa_proc.c
@@ -177,7 +177,7 @@ static int mpc_show(struct seq_file *m, void *v)
return 0;
}
-static struct seq_operations mpc_op = {
+static const struct seq_operations mpc_op = {
.start = mpc_start,
.next = mpc_next,
.stop = mpc_stop,
diff --git a/net/atm/proc.c b/net/atm/proc.c
index 9e61e512f667..99fc1fe950ee 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -110,7 +110,7 @@ static inline void *vcc_walk(struct vcc_state *state, loff_t l)
}
static int __vcc_seq_open(struct inode *inode, struct file *file,
- int family, struct seq_operations *ops)
+ int family, const struct seq_operations *ops)
{
struct vcc_state *state;
struct seq_file *seq;
@@ -260,7 +260,7 @@ static int atm_dev_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations atm_dev_seq_ops = {
+static const struct seq_operations atm_dev_seq_ops = {
.start = atm_dev_seq_start,
.next = atm_dev_seq_next,
.stop = atm_dev_seq_stop,
@@ -295,7 +295,7 @@ static int pvc_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations pvc_seq_ops = {
+static const struct seq_operations pvc_seq_ops = {
.start = vcc_seq_start,
.next = vcc_seq_next,
.stop = vcc_seq_stop,
@@ -329,7 +329,7 @@ static int vcc_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations vcc_seq_ops = {
+static const struct seq_operations vcc_seq_ops = {
.start = vcc_seq_start,
.next = vcc_seq_next,
.stop = vcc_seq_stop,
@@ -364,7 +364,7 @@ static int svc_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations svc_seq_ops = {
+static const struct seq_operations svc_seq_ops = {
.start = vcc_seq_start,
.next = vcc_seq_next,
.stop = vcc_seq_stop,
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 429e13a6c6ad..dae2a42d3d86 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -1262,7 +1262,7 @@ static int __must_check ax25_connect(struct socket *sock,
for (;;) {
prepare_to_wait(sk->sk_sleep, &wait,
- TASK_INTERRUPTIBLE);
+ TASK_INTERRUPTIBLE);
if (sk->sk_state != TCP_SYN_SENT)
break;
if (!signal_pending(current)) {
@@ -1924,7 +1924,7 @@ static int ax25_info_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ax25_info_seqops = {
+static const struct seq_operations ax25_info_seqops = {
.start = ax25_info_start,
.next = ax25_info_next,
.stop = ax25_info_stop,
diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
index d65b8e22868d..9ecf6f1df863 100644
--- a/net/ax25/ax25_route.c
+++ b/net/ax25/ax25_route.c
@@ -320,7 +320,7 @@ static int ax25_rt_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ax25_rt_seqops = {
+static const struct seq_operations ax25_rt_seqops = {
.start = ax25_rt_seq_start,
.next = ax25_rt_seq_next,
.stop = ax25_rt_seq_stop,
diff --git a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
index 75c76647b2cb..ce0b13d44385 100644
--- a/net/ax25/ax25_uid.c
+++ b/net/ax25/ax25_uid.c
@@ -185,7 +185,7 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ax25_uid_seqops = {
+static const struct seq_operations ax25_uid_seqops = {
.start = ax25_uid_seq_start,
.next = ax25_uid_seq_next,
.stop = ax25_uid_seq_stop,
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index 1c8f4a0c5f43..1f78c3e336d8 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -36,6 +36,7 @@
#include <linux/signal.h>
#include <linux/init.h>
#include <linux/wait.h>
+#include <linux/freezer.h>
#include <linux/errno.h>
#include <linux/net.h>
#include <net/sock.h>
@@ -474,7 +475,6 @@ static int bnep_session(void *arg)
daemonize("kbnepd %s", dev->name);
set_user_nice(current, -15);
- current->flags |= PF_NOFREEZE;
init_waitqueue_entry(&wait, current);
add_wait_queue(sk->sk_sleep, &wait);
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index 66bef1ccee2a..ca60a4517fd3 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
+#include <linux/freezer.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/ioctl.h>
@@ -287,7 +288,6 @@ static int cmtp_session(void *arg)
daemonize("kcmtpd_ctr_%d", session->num);
set_user_nice(current, -15);
- current->flags |= PF_NOFREEZE;
init_waitqueue_entry(&wait, current);
add_wait_queue(sk->sk_sleep, &wait);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 63980bd6b5f2..5fdfc9a67d39 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -123,8 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
conn->state = BT_CONNECT;
conn->out = 1;
- cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
cp.handle = cpu_to_le16(handle);
+ cp.pkt_type = cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
}
@@ -220,19 +220,19 @@ int hci_conn_del(struct hci_conn *conn)
del_timer(&conn->disc_timer);
- if (conn->type == SCO_LINK) {
- struct hci_conn *acl = conn->link;
- if (acl) {
- acl->link = NULL;
- hci_conn_put(acl);
- }
- } else {
+ if (conn->type == ACL_LINK) {
struct hci_conn *sco = conn->link;
if (sco)
sco->link = NULL;
/* Unacked frames */
hdev->acl_cnt += conn->sent;
+ } else {
+ struct hci_conn *acl = conn->link;
+ if (acl) {
+ acl->link = NULL;
+ hci_conn_put(acl);
+ }
}
tasklet_disable(&hdev->tx_task);
@@ -297,9 +297,10 @@ EXPORT_SYMBOL(hci_get_route);
/* Create SCO or ACL connection.
* Device _must_ be locked */
-struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
{
struct hci_conn *acl;
+ struct hci_conn *sco;
BT_DBG("%s dst %s", hdev->name, batostr(dst));
@@ -313,28 +314,26 @@ struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
hci_acl_connect(acl);
- if (type == SCO_LINK) {
- struct hci_conn *sco;
+ if (type == ACL_LINK)
+ return acl;
- if (!(sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
- if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
- hci_conn_put(acl);
- return NULL;
- }
+ if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) {
+ if (!(sco = hci_conn_add(hdev, type, dst))) {
+ hci_conn_put(acl);
+ return NULL;
}
- acl->link = sco;
- sco->link = acl;
+ }
- hci_conn_hold(sco);
+ acl->link = sco;
+ sco->link = acl;
- if (acl->state == BT_CONNECTED &&
- (sco->state == BT_OPEN || sco->state == BT_CLOSED))
- hci_add_sco(sco, acl->handle);
+ hci_conn_hold(sco);
- return sco;
- } else {
- return acl;
- }
+ if (acl->state == BT_CONNECTED &&
+ (sco->state == BT_OPEN || sco->state == BT_CLOSED))
+ hci_add_sco(sco, acl->handle);
+
+ return sco;
}
EXPORT_SYMBOL(hci_connect);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index aa4b56a8c3ea..63caa414945d 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -826,7 +826,7 @@ EXPORT_SYMBOL(hci_free_dev);
int hci_register_dev(struct hci_dev *hdev)
{
struct list_head *head = &hci_dev_list, *p;
- int id = 0;
+ int i, id = 0;
BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner);
@@ -851,6 +851,7 @@ int hci_register_dev(struct hci_dev *hdev)
hdev->flags = 0;
hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1);
+ hdev->esco_type = (ESCO_HV1);
hdev->link_mode = (HCI_LM_ACCEPT);
hdev->idle_timeout = 0;
@@ -865,6 +866,9 @@ int hci_register_dev(struct hci_dev *hdev)
skb_queue_head_init(&hdev->cmd_q);
skb_queue_head_init(&hdev->raw_q);
+ for (i = 0; i < 3; i++)
+ hdev->reassembly[i] = NULL;
+
init_waitqueue_head(&hdev->req_wait_q);
init_MUTEX(&hdev->req_lock);
@@ -889,6 +893,8 @@ EXPORT_SYMBOL(hci_register_dev);
/* Unregister HCI device */
int hci_unregister_dev(struct hci_dev *hdev)
{
+ int i;
+
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
hci_unregister_sysfs(hdev);
@@ -899,9 +905,13 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_dev_do_close(hdev);
+ for (i = 0; i < 3; i++)
+ kfree_skb(hdev->reassembly[i]);
+
hci_notify(hdev, HCI_DEV_UNREG);
__hci_dev_put(hdev);
+
return 0;
}
EXPORT_SYMBOL(hci_unregister_dev);
@@ -922,6 +932,90 @@ int hci_resume_dev(struct hci_dev *hdev)
}
EXPORT_SYMBOL(hci_resume_dev);
+/* Receive packet type fragment */
+#define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 2])
+
+int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
+{
+ if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT)
+ return -EILSEQ;
+
+ while (count) {
+ struct sk_buff *skb = __reassembly(hdev, type);
+ struct { int expect; } *scb;
+ int len = 0;
+
+ if (!skb) {
+ /* Start of the frame */
+
+ switch (type) {
+ case HCI_EVENT_PKT:
+ if (count >= HCI_EVENT_HDR_SIZE) {
+ struct hci_event_hdr *h = data;
+ len = HCI_EVENT_HDR_SIZE + h->plen;
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ if (count >= HCI_ACL_HDR_SIZE) {
+ struct hci_acl_hdr *h = data;
+ len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
+ } else
+ return -EILSEQ;
+ break;
+
+ case HCI_SCODATA_PKT:
+ if (count >= HCI_SCO_HDR_SIZE) {
+ struct hci_sco_hdr *h = data;
+ len = HCI_SCO_HDR_SIZE + h->dlen;
+ } else
+ return -EILSEQ;
+ break;
+ }
+
+ skb = bt_skb_alloc(len, GFP_ATOMIC);
+ if (!skb) {
+ BT_ERR("%s no memory for packet", hdev->name);
+ return -ENOMEM;
+ }
+
+ skb->dev = (void *) hdev;
+ bt_cb(skb)->pkt_type = type;
+
+ __reassembly(hdev, type) = skb;
+
+ scb = (void *) skb->cb;
+ scb->expect = len;
+ } else {
+ /* Continuation */
+
+ scb = (void *) skb->cb;
+ len = scb->expect;
+ }
+
+ len = min(len, count);
+
+ memcpy(skb_put(skb, len), data, len);
+
+ scb->expect -= len;
+
+ if (scb->expect == 0) {
+ /* Complete frame */
+
+ __reassembly(hdev, type) = NULL;
+
+ bt_cb(skb)->pkt_type = type;
+ hci_recv_frame(skb);
+ }
+
+ count -= len; data += len;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hci_recv_fragment);
+
/* ---- Interface to upper protocols ---- */
/* Register/Unregister protocols.
@@ -1029,7 +1123,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) {
- BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
+ BT_ERR("%s no memory for command", hdev->name);
return -ENOMEM;
}
@@ -1161,7 +1255,7 @@ EXPORT_SYMBOL(hci_send_sco);
static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
{
struct hci_conn_hash *h = &hdev->conn_hash;
- struct hci_conn *conn = NULL;
+ struct hci_conn *conn = NULL;
int num = 0, min = ~0;
struct list_head *p;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 447ba7131220..4baea1e38652 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -350,11 +350,24 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
if (hdev->features[0] & LMP_5SLOT)
hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
- if (hdev->features[1] & LMP_HV2)
- hdev->pkt_type |= (HCI_HV2);
+ if (hdev->features[1] & LMP_HV2) {
+ hdev->pkt_type |= (HCI_HV2);
+ hdev->esco_type |= (ESCO_HV2);
+ }
+
+ if (hdev->features[1] & LMP_HV3) {
+ hdev->pkt_type |= (HCI_HV3);
+ hdev->esco_type |= (ESCO_HV3);
+ }
- if (hdev->features[1] & LMP_HV3)
- hdev->pkt_type |= (HCI_HV3);
+ if (hdev->features[3] & LMP_ESCO)
+ hdev->esco_type |= (ESCO_EV3);
+
+ if (hdev->features[4] & LMP_EV4)
+ hdev->esco_type |= (ESCO_EV4);
+
+ if (hdev->features[4] & LMP_EV5)
+ hdev->esco_type |= (ESCO_EV5);
BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
lf->features[0], lf->features[1], lf->features[2]);
@@ -881,12 +894,12 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
if (conn) {
conn->sent -= count;
- if (conn->type == SCO_LINK) {
- if ((hdev->sco_cnt += count) > hdev->sco_pkts)
- hdev->sco_cnt = hdev->sco_pkts;
- } else {
+ if (conn->type == ACL_LINK) {
if ((hdev->acl_cnt += count) > hdev->acl_pkts)
hdev->acl_cnt = hdev->acl_pkts;
+ } else {
+ if ((hdev->sco_cnt += count) > hdev->sco_pkts)
+ hdev->sco_cnt = hdev->sco_pkts;
}
}
}
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 450eb0244bbf..64d89ca28847 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -28,6 +28,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
+#include <linux/freezer.h>
#include <linux/fcntl.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
@@ -547,7 +548,6 @@ static int hidp_session(void *arg)
daemonize("khidpd_%04x%04x", vendor, product);
set_user_nice(current, -15);
- current->flags |= PF_NOFREEZE;
init_waitqueue_entry(&ctrl_wait, current);
init_waitqueue_entry(&intr_wait, current);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 52e04df323ea..bb7220770f2c 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -33,6 +33,7 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/init.h>
+#include <linux/freezer.h>
#include <linux/wait.h>
#include <linux/device.h>
#include <linux/net.h>
@@ -1940,7 +1941,6 @@ static int rfcomm_run(void *unused)
daemonize("krfcommd");
set_user_nice(current, -10);
- current->flags |= PF_NOFREEZE;
BT_DBG("");
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index b2b1cceb102a..23ba61a13bdd 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -95,6 +95,10 @@ static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
BT_DBG("dev %p dlc %p", dev, dlc);
+ write_lock_bh(&rfcomm_dev_lock);
+ list_del_init(&dev->list);
+ write_unlock_bh(&rfcomm_dev_lock);
+
rfcomm_dlc_lock(dlc);
/* Detach DLC if it's owned by this dev */
if (dlc->owner == dev)
@@ -156,8 +160,13 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
read_lock(&rfcomm_dev_lock);
dev = __rfcomm_dev_get(id);
- if (dev)
- rfcomm_dev_hold(dev);
+
+ if (dev) {
+ if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+ dev = NULL;
+ else
+ rfcomm_dev_hold(dev);
+ }
read_unlock(&rfcomm_dev_lock);
@@ -265,6 +274,12 @@ out:
dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
+ if (IS_ERR(dev->tty_dev)) {
+ list_del(&dev->list);
+ kfree(dev);
+ return PTR_ERR(dev->tty_dev);
+ }
+
return dev->id;
}
@@ -272,10 +287,7 @@ static void rfcomm_dev_del(struct rfcomm_dev *dev)
{
BT_DBG("dev %p", dev);
- write_lock_bh(&rfcomm_dev_lock);
- list_del_init(&dev->list);
- write_unlock_bh(&rfcomm_dev_lock);
-
+ set_bit(RFCOMM_TTY_RELEASED, &dev->flags);
rfcomm_dev_put(dev);
}
@@ -329,7 +341,7 @@ static int rfcomm_create_dev(struct sock *sk, void __user *arg)
if (copy_from_user(&req, arg, sizeof(req)))
return -EFAULT;
- BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
+ BT_DBG("sk %p dev_id %d flags 0x%x", sk, req.dev_id, req.flags);
if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
return -EPERM;
@@ -370,7 +382,7 @@ static int rfcomm_release_dev(void __user *arg)
if (copy_from_user(&req, arg, sizeof(req)))
return -EFAULT;
- BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
+ BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags);
if (!(dev = rfcomm_dev_get(req.dev_id)))
return -ENODEV;
@@ -383,6 +395,10 @@ static int rfcomm_release_dev(void __user *arg)
if (req.flags & (1 << RFCOMM_HANGUP_NOW))
rfcomm_dlc_close(dev->dlc, 0);
+ /* Shut down TTY synchronously before freeing rfcomm_dev */
+ if (dev->tty)
+ tty_vhangup(dev->tty);
+
rfcomm_dev_del(dev);
rfcomm_dev_put(dev);
return 0;
@@ -415,6 +431,8 @@ static int rfcomm_get_dev_list(void __user *arg)
list_for_each(p, &rfcomm_dev_list) {
struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
+ if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+ continue;
(di + n)->id = dev->id;
(di + n)->flags = dev->flags;
(di + n)->state = dev->dlc->state;
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 3fc697293819..69b70977f000 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -36,7 +36,7 @@ int __init br_fdb_init(void)
br_fdb_cache = kmem_cache_create("bridge_fdb_cache",
sizeof(struct net_bridge_fdb_entry),
0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!br_fdb_cache)
return -ENOMEM;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 849deaf14108..7b4ce9113be2 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -368,10 +368,18 @@ void br_features_recompute(struct net_bridge *br)
list_for_each_entry(p, &br->port_list, list) {
unsigned long feature = p->dev->features;
+ /* if device needs checksumming, downgrade to hw checksumming */
if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
+
+ /* if device can't do all checksum, downgrade to ipv4/ipv6 */
if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
- checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
+ checksum ^= NETIF_F_HW_CSUM
+ | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+
+ if (checksum & NETIF_F_IPV6_CSUM && !(feature & NETIF_F_IPV6_CSUM))
+ checksum &= ~NETIF_F_IPV6_CSUM;
+
if (!(feature & NETIF_F_IP_CSUM))
checksum = 0;
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index a786e7863200..1ea2f86f7683 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -125,7 +125,7 @@ static void br_stp_start(struct net_bridge *br)
char *argv[] = { BR_STP_PROG, br->dev->name, "start", NULL };
char *envp[] = { NULL };
- r = call_usermodehelper(BR_STP_PROG, argv, envp, 1);
+ r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
if (r == 0) {
br->stp_enabled = BR_USER_STP;
printk(KERN_INFO "%s: userspace STP started\n", br->dev->name);
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 33c6c4a7c689..4f42263e0a8a 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -360,8 +360,9 @@ static struct attribute_group bridge_group = {
*
* Returns the number of bytes read.
*/
-static ssize_t brforward_read(struct kobject *kobj, char *buf,
- loff_t off, size_t count)
+static ssize_t brforward_read(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
struct device *dev = to_dev(kobj);
struct net_bridge *br = to_bridge(dev);
@@ -383,8 +384,7 @@ static ssize_t brforward_read(struct kobject *kobj, char *buf,
static struct bin_attribute bridge_forward = {
.attr = { .name = SYSFS_BRIDGE_FDB,
- .mode = S_IRUGO,
- .owner = THIS_MODULE, },
+ .mode = S_IRUGO, },
.read = brforward_read,
};
diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c
index 2da22927d8dd..79db51fcb476 100644
--- a/net/bridge/br_sysfs_if.c
+++ b/net/bridge/br_sysfs_if.c
@@ -29,8 +29,7 @@ struct brport_attribute {
#define BRPORT_ATTR(_name,_mode,_show,_store) \
struct brport_attribute brport_attr_##_name = { \
.attr = {.name = __stringify(_name), \
- .mode = _mode, \
- .owner = THIS_MODULE, }, \
+ .mode = _mode }, \
.show = _show, \
.store = _store, \
};
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index ac9984f98e59..4169a2a89a39 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1525,14 +1525,14 @@ static int __init ebtables_init(void)
if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
return ret;
- printk(KERN_NOTICE "Ebtables v2.0 registered\n");
+ printk(KERN_INFO "Ebtables v2.0 registered\n");
return 0;
}
static void __exit ebtables_fini(void)
{
nf_unregister_sockopt(&ebt_sockopts);
- printk(KERN_NOTICE "Ebtables v2.0 unregistered\n");
+ printk(KERN_INFO "Ebtables v2.0 unregistered\n");
}
EXPORT_SYMBOL(ebt_register_table);
diff --git a/net/compat.c b/net/compat.c
index 9a0f5f2b90c8..d74d82155d78 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -276,7 +276,8 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
err = security_file_receive(fp[i]);
if (err)
break;
- err = get_unused_fd();
+ err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & kmsg->msg_flags
+ ? O_CLOEXEC : 0);
if (err < 0)
break;
new_fd = err;
diff --git a/net/core/dev.c b/net/core/dev.c
index ee051bb398a0..ee4035571c21 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -98,6 +98,7 @@
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/if_bridge.h>
+#include <linux/if_macvlan.h>
#include <net/dst.h>
#include <net/pkt_sched.h>
#include <net/checksum.h>
@@ -151,9 +152,22 @@ static struct list_head ptype_base[16] __read_mostly; /* 16 way hashed list */
static struct list_head ptype_all __read_mostly; /* Taps */
#ifdef CONFIG_NET_DMA
-static struct dma_client *net_dma_client;
-static unsigned int net_dma_count;
-static spinlock_t net_dma_event_lock;
+struct net_dma {
+ struct dma_client client;
+ spinlock_t lock;
+ cpumask_t channel_mask;
+ struct dma_chan *channels[NR_CPUS];
+};
+
+static enum dma_state_client
+netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
+ enum dma_state state);
+
+static struct net_dma net_dma = {
+ .client = {
+ .event_callback = netdev_dma_event,
+ },
+};
#endif
/*
@@ -942,7 +956,7 @@ int dev_open(struct net_device *dev)
/*
* Initialize multicasting status
*/
- dev_mc_upload(dev);
+ dev_set_rx_mode(dev);
/*
* Wakeup transmit queue engine
@@ -1429,7 +1443,9 @@ gso:
skb->next = nskb;
return rc;
}
- if (unlikely(netif_queue_stopped(dev) && skb->next))
+ if (unlikely((netif_queue_stopped(dev) ||
+ netif_subqueue_stopped(dev, skb->queue_mapping)) &&
+ skb->next))
return NETDEV_TX_BUSY;
} while (skb->next);
@@ -1510,8 +1526,10 @@ int dev_queue_xmit(struct sk_buff *skb)
skb_headroom(skb));
if (!(dev->features & NETIF_F_GEN_CSUM) &&
- (!(dev->features & NETIF_F_IP_CSUM) ||
- skb->protocol != htons(ETH_P_IP)))
+ !((dev->features & NETIF_F_IP_CSUM) &&
+ skb->protocol == htons(ETH_P_IP)) &&
+ !((dev->features & NETIF_F_IPV6_CSUM) &&
+ skb->protocol == htons(ETH_P_IPV6)))
if (skb_checksum_help(skb))
goto out_kfree_skb;
}
@@ -1545,6 +1563,8 @@ gso:
spin_lock(&dev->queue_lock);
q = dev->qdisc;
if (q->enqueue) {
+ /* reset queue_mapping to zero */
+ skb->queue_mapping = 0;
rc = q->enqueue(skb, q);
qdisc_run(dev);
spin_unlock(&dev->queue_lock);
@@ -1574,7 +1594,8 @@ gso:
HARD_TX_LOCK(dev, cpu);
- if (!netif_queue_stopped(dev)) {
+ if (!netif_queue_stopped(dev) &&
+ !netif_subqueue_stopped(dev, skb->queue_mapping)) {
rc = 0;
if (!dev_hard_start_xmit(skb, dev)) {
HARD_TX_UNLOCK(dev);
@@ -1793,6 +1814,28 @@ static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
#define handle_bridge(skb, pt_prev, ret, orig_dev) (skb)
#endif
+#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
+struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *skb) __read_mostly;
+EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
+
+static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
+ struct packet_type **pt_prev,
+ int *ret,
+ struct net_device *orig_dev)
+{
+ if (skb->dev->macvlan_port == NULL)
+ return skb;
+
+ if (*pt_prev) {
+ *ret = deliver_skb(skb, *pt_prev, orig_dev);
+ *pt_prev = NULL;
+ }
+ return macvlan_handle_frame_hook(skb);
+}
+#else
+#define handle_macvlan(skb, pt_prev, ret, orig_dev) (skb)
+#endif
+
#ifdef CONFIG_NET_CLS_ACT
/* TODO: Maybe we should just force sch_ingress to be compiled in
* when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
@@ -1900,6 +1943,9 @@ ncls:
skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
if (!skb)
goto out;
+ skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
+ if (!skb)
+ goto out;
type = skb->protocol;
list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
@@ -2015,12 +2061,13 @@ out:
* There may not be any more sk_buffs coming right now, so push
* any pending DMA copies to hardware
*/
- if (net_dma_client) {
- struct dma_chan *chan;
- rcu_read_lock();
- list_for_each_entry_rcu(chan, &net_dma_client->channels, client_node)
- dma_async_memcpy_issue_pending(chan);
- rcu_read_unlock();
+ if (!cpus_empty(net_dma.channel_mask)) {
+ int chan_idx;
+ for_each_cpu_mask(chan_idx, net_dma.channel_mask) {
+ struct dma_chan *chan = net_dma.channels[chan_idx];
+ if (chan)
+ dma_async_memcpy_issue_pending(chan);
+ }
}
#endif
return;
@@ -2496,26 +2543,17 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
return 0;
}
-/**
- * dev_set_promiscuity - update promiscuity count on a device
- * @dev: device
- * @inc: modifier
- *
- * Add or remove promiscuity from a device. While the count in the device
- * remains above zero the interface remains promiscuous. Once it hits zero
- * the device reverts back to normal filtering operation. A negative inc
- * value is used to drop promiscuity on the device.
- */
-void dev_set_promiscuity(struct net_device *dev, int inc)
+static void __dev_set_promiscuity(struct net_device *dev, int inc)
{
unsigned short old_flags = dev->flags;
+ ASSERT_RTNL();
+
if ((dev->promiscuity += inc) == 0)
dev->flags &= ~IFF_PROMISC;
else
dev->flags |= IFF_PROMISC;
if (dev->flags != old_flags) {
- dev_mc_upload(dev);
printk(KERN_INFO "device %s %s promiscuous mode\n",
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
"left");
@@ -2525,10 +2563,32 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
dev->name, (dev->flags & IFF_PROMISC),
(old_flags & IFF_PROMISC),
audit_get_loginuid(current->audit_context));
+
+ if (dev->change_rx_flags)
+ dev->change_rx_flags(dev, IFF_PROMISC);
}
}
/**
+ * dev_set_promiscuity - update promiscuity count on a device
+ * @dev: device
+ * @inc: modifier
+ *
+ * Add or remove promiscuity from a device. While the count in the device
+ * remains above zero the interface remains promiscuous. Once it hits zero
+ * the device reverts back to normal filtering operation. A negative inc
+ * value is used to drop promiscuity on the device.
+ */
+void dev_set_promiscuity(struct net_device *dev, int inc)
+{
+ unsigned short old_flags = dev->flags;
+
+ __dev_set_promiscuity(dev, inc);
+ if (dev->flags != old_flags)
+ dev_set_rx_mode(dev);
+}
+
+/**
* dev_set_allmulti - update allmulti count on a device
* @dev: device
* @inc: modifier
@@ -2544,11 +2604,190 @@ void dev_set_allmulti(struct net_device *dev, int inc)
{
unsigned short old_flags = dev->flags;
+ ASSERT_RTNL();
+
dev->flags |= IFF_ALLMULTI;
if ((dev->allmulti += inc) == 0)
dev->flags &= ~IFF_ALLMULTI;
- if (dev->flags ^ old_flags)
- dev_mc_upload(dev);
+ if (dev->flags ^ old_flags) {
+ if (dev->change_rx_flags)
+ dev->change_rx_flags(dev, IFF_ALLMULTI);
+ dev_set_rx_mode(dev);
+ }
+}
+
+/*
+ * Upload unicast and multicast address lists to device and
+ * configure RX filtering. When the device doesn't support unicast
+ * filtering it is put in promiscous mode while unicast addresses
+ * are present.
+ */
+void __dev_set_rx_mode(struct net_device *dev)
+{
+ /* dev_open will call this function so the list will stay sane. */
+ if (!(dev->flags&IFF_UP))
+ return;
+
+ if (!netif_device_present(dev))
+ return;
+
+ if (dev->set_rx_mode)
+ dev->set_rx_mode(dev);
+ else {
+ /* Unicast addresses changes may only happen under the rtnl,
+ * therefore calling __dev_set_promiscuity here is safe.
+ */
+ if (dev->uc_count > 0 && !dev->uc_promisc) {
+ __dev_set_promiscuity(dev, 1);
+ dev->uc_promisc = 1;
+ } else if (dev->uc_count == 0 && dev->uc_promisc) {
+ __dev_set_promiscuity(dev, -1);
+ dev->uc_promisc = 0;
+ }
+
+ if (dev->set_multicast_list)
+ dev->set_multicast_list(dev);
+ }
+}
+
+void dev_set_rx_mode(struct net_device *dev)
+{
+ netif_tx_lock_bh(dev);
+ __dev_set_rx_mode(dev);
+ netif_tx_unlock_bh(dev);
+}
+
+int __dev_addr_delete(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+{
+ struct dev_addr_list *da;
+
+ for (; (da = *list) != NULL; list = &da->next) {
+ if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
+ alen == da->da_addrlen) {
+ if (glbl) {
+ int old_glbl = da->da_gusers;
+ da->da_gusers = 0;
+ if (old_glbl == 0)
+ break;
+ }
+ if (--da->da_users)
+ return 0;
+
+ *list = da->next;
+ kfree(da);
+ (*count)--;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int __dev_addr_add(struct dev_addr_list **list, int *count,
+ void *addr, int alen, int glbl)
+{
+ struct dev_addr_list *da;
+
+ for (da = *list; da != NULL; da = da->next) {
+ if (memcmp(da->da_addr, addr, da->da_addrlen) == 0 &&
+ da->da_addrlen == alen) {
+ if (glbl) {
+ int old_glbl = da->da_gusers;
+ da->da_gusers = 1;
+ if (old_glbl)
+ return 0;
+ }
+ da->da_users++;
+ return 0;
+ }
+ }
+
+ da = kmalloc(sizeof(*da), GFP_ATOMIC);
+ if (da == NULL)
+ return -ENOMEM;
+ memcpy(da->da_addr, addr, alen);
+ da->da_addrlen = alen;
+ da->da_users = 1;
+ da->da_gusers = glbl ? 1 : 0;
+ da->next = *list;
+ *list = da;
+ (*count)++;
+ return 0;
+}
+
+/**
+ * dev_unicast_delete - Release secondary unicast address.
+ * @dev: device
+ *
+ * Release reference to a secondary unicast address and remove it
+ * from the device if the reference count drop to zero.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+int dev_unicast_delete(struct net_device *dev, void *addr, int alen)
+{
+ int err;
+
+ ASSERT_RTNL();
+
+ netif_tx_lock_bh(dev);
+ err = __dev_addr_delete(&dev->uc_list, &dev->uc_count, addr, alen, 0);
+ if (!err)
+ __dev_set_rx_mode(dev);
+ netif_tx_unlock_bh(dev);
+ return err;
+}
+EXPORT_SYMBOL(dev_unicast_delete);
+
+/**
+ * dev_unicast_add - add a secondary unicast address
+ * @dev: device
+ *
+ * Add a secondary unicast address to the device or increase
+ * the reference count if it already exists.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+int dev_unicast_add(struct net_device *dev, void *addr, int alen)
+{
+ int err;
+
+ ASSERT_RTNL();
+
+ netif_tx_lock_bh(dev);
+ err = __dev_addr_add(&dev->uc_list, &dev->uc_count, addr, alen, 0);
+ if (!err)
+ __dev_set_rx_mode(dev);
+ netif_tx_unlock_bh(dev);
+ return err;
+}
+EXPORT_SYMBOL(dev_unicast_add);
+
+static void __dev_addr_discard(struct dev_addr_list **list)
+{
+ struct dev_addr_list *tmp;
+
+ while (*list != NULL) {
+ tmp = *list;
+ *list = tmp->next;
+ if (tmp->da_users > tmp->da_gusers)
+ printk("__dev_addr_discard: address leakage! "
+ "da_users=%d\n", tmp->da_users);
+ kfree(tmp);
+ }
+}
+
+static void dev_addr_discard(struct net_device *dev)
+{
+ netif_tx_lock_bh(dev);
+
+ __dev_addr_discard(&dev->uc_list);
+ dev->uc_count = 0;
+
+ __dev_addr_discard(&dev->mc_list);
+ dev->mc_count = 0;
+
+ netif_tx_unlock_bh(dev);
}
unsigned dev_get_flags(const struct net_device *dev)
@@ -2580,6 +2819,8 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
int ret, changes;
int old_flags = dev->flags;
+ ASSERT_RTNL();
+
/*
* Set the flags on our device.
*/
@@ -2594,7 +2835,10 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
* Load in the correct multicast list now the flags have changed.
*/
- dev_mc_upload(dev);
+ if (dev->change_rx_flags && (dev->flags ^ flags) & IFF_MULTICAST)
+ dev->change_rx_flags(dev, IFF_MULTICAST);
+
+ dev_set_rx_mode(dev);
/*
* Have we downed the interface. We handle IFF_UP ourselves
@@ -2607,7 +2851,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
if (!ret)
- dev_mc_upload(dev);
+ dev_set_rx_mode(dev);
}
if (dev->flags & IFF_UP &&
@@ -3107,6 +3351,22 @@ int register_netdevice(struct net_device *dev)
}
}
+ /* Fix illegal checksum combinations */
+ if ((dev->features & NETIF_F_HW_CSUM) &&
+ (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
+ printk(KERN_NOTICE "%s: mixed HW and IP checksum settings.\n",
+ dev->name);
+ dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM);
+ }
+
+ if ((dev->features & NETIF_F_NO_CSUM) &&
+ (dev->features & (NETIF_F_HW_CSUM|NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
+ printk(KERN_NOTICE "%s: mixed no checksumming and other settings.\n",
+ dev->name);
+ dev->features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM|NETIF_F_HW_CSUM);
+ }
+
+
/* Fix illegal SG+CSUM combinations. */
if ((dev->features & NETIF_F_SG) &&
!(dev->features & NETIF_F_ALL_CSUM)) {
@@ -3343,16 +3603,18 @@ static struct net_device_stats *internal_stats(struct net_device *dev)
}
/**
- * alloc_netdev - allocate network device
+ * alloc_netdev_mq - allocate network device
* @sizeof_priv: size of private data to allocate space for
* @name: device name format string
* @setup: callback to initialize device
+ * @queue_count: the number of subqueues to allocate
*
* Allocates a struct net_device with private data area for driver use
- * and performs basic initialization.
+ * and performs basic initialization. Also allocates subquue structs
+ * for each queue on the device at the end of the netdevice.
*/
-struct net_device *alloc_netdev(int sizeof_priv, const char *name,
- void (*setup)(struct net_device *))
+struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
+ void (*setup)(struct net_device *), unsigned int queue_count)
{
void *p;
struct net_device *dev;
@@ -3361,7 +3623,9 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name,
BUG_ON(strlen(name) >= sizeof(dev->name));
/* ensure 32-byte alignment of both the device and private area */
- alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST;
+ alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST +
+ (sizeof(struct net_device_subqueue) * (queue_count - 1))) &
+ ~NETDEV_ALIGN_CONST;
alloc_size += sizeof_priv + NETDEV_ALIGN_CONST;
p = kzalloc(alloc_size, GFP_KERNEL);
@@ -3374,15 +3638,22 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name,
(((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
dev->padded = (char *)dev - (char *)p;
- if (sizeof_priv)
- dev->priv = netdev_priv(dev);
+ if (sizeof_priv) {
+ dev->priv = ((char *)dev +
+ ((sizeof(struct net_device) +
+ (sizeof(struct net_device_subqueue) *
+ (queue_count - 1)) + NETDEV_ALIGN_CONST)
+ & ~NETDEV_ALIGN_CONST));
+ }
+
+ dev->egress_subqueue_count = queue_count;
dev->get_stats = internal_stats;
setup(dev);
strcpy(dev->name, name);
return dev;
}
-EXPORT_SYMBOL(alloc_netdev);
+EXPORT_SYMBOL(alloc_netdev_mq);
/**
* free_netdev - free network device
@@ -3471,9 +3742,9 @@ void unregister_netdevice(struct net_device *dev)
raw_notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
/*
- * Flush the multicast chain
+ * Flush the unicast and multicast chains
*/
- dev_mc_discard(dev);
+ dev_addr_discard(dev);
if (dev->uninit)
dev->uninit(dev);
@@ -3563,12 +3834,13 @@ static int dev_cpu_callback(struct notifier_block *nfb,
* This is called when the number of channels allocated to the net_dma_client
* changes. The net_dma_client tries to have one DMA channel per CPU.
*/
-static void net_dma_rebalance(void)
+
+static void net_dma_rebalance(struct net_dma *net_dma)
{
- unsigned int cpu, i, n;
+ unsigned int cpu, i, n, chan_idx;
struct dma_chan *chan;
- if (net_dma_count == 0) {
+ if (cpus_empty(net_dma->channel_mask)) {
for_each_online_cpu(cpu)
rcu_assign_pointer(per_cpu(softnet_data, cpu).net_dma, NULL);
return;
@@ -3577,10 +3849,12 @@ static void net_dma_rebalance(void)
i = 0;
cpu = first_cpu(cpu_online_map);
- rcu_read_lock();
- list_for_each_entry(chan, &net_dma_client->channels, client_node) {
- n = ((num_online_cpus() / net_dma_count)
- + (i < (num_online_cpus() % net_dma_count) ? 1 : 0));
+ for_each_cpu_mask(chan_idx, net_dma->channel_mask) {
+ chan = net_dma->channels[chan_idx];
+
+ n = ((num_online_cpus() / cpus_weight(net_dma->channel_mask))
+ + (i < (num_online_cpus() %
+ cpus_weight(net_dma->channel_mask)) ? 1 : 0));
while(n) {
per_cpu(softnet_data, cpu).net_dma = chan;
@@ -3589,7 +3863,6 @@ static void net_dma_rebalance(void)
}
i++;
}
- rcu_read_unlock();
}
/**
@@ -3598,23 +3871,53 @@ static void net_dma_rebalance(void)
* @chan: DMA channel for the event
* @event: event type
*/
-static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
- enum dma_event event)
-{
- spin_lock(&net_dma_event_lock);
- switch (event) {
- case DMA_RESOURCE_ADDED:
- net_dma_count++;
- net_dma_rebalance();
+static enum dma_state_client
+netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
+ enum dma_state state)
+{
+ int i, found = 0, pos = -1;
+ struct net_dma *net_dma =
+ container_of(client, struct net_dma, client);
+ enum dma_state_client ack = DMA_DUP; /* default: take no action */
+
+ spin_lock(&net_dma->lock);
+ switch (state) {
+ case DMA_RESOURCE_AVAILABLE:
+ for (i = 0; i < NR_CPUS; i++)
+ if (net_dma->channels[i] == chan) {
+ found = 1;
+ break;
+ } else if (net_dma->channels[i] == NULL && pos < 0)
+ pos = i;
+
+ if (!found && pos >= 0) {
+ ack = DMA_ACK;
+ net_dma->channels[pos] = chan;
+ cpu_set(pos, net_dma->channel_mask);
+ net_dma_rebalance(net_dma);
+ }
break;
case DMA_RESOURCE_REMOVED:
- net_dma_count--;
- net_dma_rebalance();
+ for (i = 0; i < NR_CPUS; i++)
+ if (net_dma->channels[i] == chan) {
+ found = 1;
+ pos = i;
+ break;
+ }
+
+ if (found) {
+ ack = DMA_ACK;
+ cpu_clear(pos, net_dma->channel_mask);
+ net_dma->channels[i] = NULL;
+ net_dma_rebalance(net_dma);
+ }
break;
default:
break;
}
- spin_unlock(&net_dma_event_lock);
+ spin_unlock(&net_dma->lock);
+
+ return ack;
}
/**
@@ -3622,12 +3925,10 @@ static void netdev_dma_event(struct dma_client *client, struct dma_chan *chan,
*/
static int __init netdev_dma_register(void)
{
- spin_lock_init(&net_dma_event_lock);
- net_dma_client = dma_async_client_register(netdev_dma_event);
- if (net_dma_client == NULL)
- return -ENOMEM;
-
- dma_async_client_chan_request(net_dma_client, num_online_cpus());
+ spin_lock_init(&net_dma.lock);
+ dma_cap_set(DMA_MEMCPY, net_dma.client.cap_mask);
+ dma_async_client_register(&net_dma.client);
+ dma_async_client_chan_request(&net_dma.client);
return 0;
}
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 5a54053386c8..99aece1aeccf 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -64,85 +64,24 @@
*/
/*
- * Update the multicast list into the physical NIC controller.
- */
-
-static void __dev_mc_upload(struct net_device *dev)
-{
- /* Don't do anything till we up the interface
- * [dev_open will call this function so the list will
- * stay sane]
- */
-
- if (!(dev->flags&IFF_UP))
- return;
-
- /*
- * Devices with no set multicast or which have been
- * detached don't get set.
- */
-
- if (dev->set_multicast_list == NULL ||
- !netif_device_present(dev))
- return;
-
- dev->set_multicast_list(dev);
-}
-
-void dev_mc_upload(struct net_device *dev)
-{
- netif_tx_lock_bh(dev);
- __dev_mc_upload(dev);
- netif_tx_unlock_bh(dev);
-}
-
-/*
* Delete a device level multicast
*/
int dev_mc_delete(struct net_device *dev, void *addr, int alen, int glbl)
{
- int err = 0;
- struct dev_mc_list *dmi, **dmip;
+ int err;
netif_tx_lock_bh(dev);
-
- for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
+ err = __dev_addr_delete(&dev->mc_list, &dev->mc_count,
+ addr, alen, glbl);
+ if (!err) {
/*
- * Find the entry we want to delete. The device could
- * have variable length entries so check these too.
+ * We have altered the list, so the card
+ * loaded filter is now wrong. Fix it
*/
- if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
- alen == dmi->dmi_addrlen) {
- if (glbl) {
- int old_glbl = dmi->dmi_gusers;
- dmi->dmi_gusers = 0;
- if (old_glbl == 0)
- break;
- }
- if (--dmi->dmi_users)
- goto done;
-
- /*
- * Last user. So delete the entry.
- */
- *dmip = dmi->next;
- dev->mc_count--;
-
- kfree(dmi);
-
- /*
- * We have altered the list, so the card
- * loaded filter is now wrong. Fix it
- */
- __dev_mc_upload(dev);
-
- netif_tx_unlock_bh(dev);
- return 0;
- }
+
+ __dev_set_rx_mode(dev);
}
- err = -ENOENT;
-done:
netif_tx_unlock_bh(dev);
return err;
}
@@ -153,68 +92,90 @@ done:
int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
{
- int err = 0;
- struct dev_mc_list *dmi, *dmi1;
-
- dmi1 = kmalloc(sizeof(*dmi), GFP_ATOMIC);
+ int err;
netif_tx_lock_bh(dev);
- for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
- if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
- dmi->dmi_addrlen == alen) {
- if (glbl) {
- int old_glbl = dmi->dmi_gusers;
- dmi->dmi_gusers = 1;
- if (old_glbl)
- goto done;
- }
- dmi->dmi_users++;
- goto done;
- }
- }
-
- if ((dmi = dmi1) == NULL) {
- netif_tx_unlock_bh(dev);
- return -ENOMEM;
- }
- memcpy(dmi->dmi_addr, addr, alen);
- dmi->dmi_addrlen = alen;
- dmi->next = dev->mc_list;
- dmi->dmi_users = 1;
- dmi->dmi_gusers = glbl ? 1 : 0;
- dev->mc_list = dmi;
- dev->mc_count++;
+ err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl);
+ if (!err)
+ __dev_set_rx_mode(dev);
+ netif_tx_unlock_bh(dev);
+ return err;
+}
- __dev_mc_upload(dev);
+/**
+ * dev_mc_sync - Synchronize device's multicast list to another device
+ * @to: destination device
+ * @from: source device
+ *
+ * Add newly added addresses to the destination device and release
+ * addresses that have no users left. The source device must be
+ * locked by netif_tx_lock_bh.
+ *
+ * This function is intended to be called from the dev->set_multicast_list
+ * function of layered software devices.
+ */
+int dev_mc_sync(struct net_device *to, struct net_device *from)
+{
+ struct dev_addr_list *da;
+ int err = 0;
- netif_tx_unlock_bh(dev);
- return 0;
+ netif_tx_lock_bh(to);
+ for (da = from->mc_list; da != NULL; da = da->next) {
+ if (!da->da_synced) {
+ err = __dev_addr_add(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ if (err < 0)
+ break;
+ da->da_synced = 1;
+ da->da_users++;
+ } else if (da->da_users == 1) {
+ __dev_addr_delete(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ __dev_addr_delete(&from->mc_list, &from->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ }
+ }
+ if (!err)
+ __dev_set_rx_mode(to);
+ netif_tx_unlock_bh(to);
-done:
- netif_tx_unlock_bh(dev);
- kfree(dmi1);
return err;
}
+EXPORT_SYMBOL(dev_mc_sync);
-/*
- * Discard multicast list when a device is downed
- */
-void dev_mc_discard(struct net_device *dev)
+/**
+ * dev_mc_unsync - Remove synchronized addresses from the destination
+ * device
+ * @to: destination device
+ * @from: source device
+ *
+ * Remove all addresses that were added to the destination device by
+ * dev_mc_sync(). This function is intended to be called from the
+ * dev->stop function of layered software devices.
+ */
+void dev_mc_unsync(struct net_device *to, struct net_device *from)
{
- netif_tx_lock_bh(dev);
-
- while (dev->mc_list != NULL) {
- struct dev_mc_list *tmp = dev->mc_list;
- dev->mc_list = tmp->next;
- if (tmp->dmi_users > tmp->dmi_gusers)
- printk("dev_mc_discard: multicast leakage! dmi_users=%d\n", tmp->dmi_users);
- kfree(tmp);
+ struct dev_addr_list *da;
+
+ netif_tx_lock_bh(from);
+ netif_tx_lock_bh(to);
+
+ for (da = from->mc_list; da != NULL; da = da->next) {
+ if (!da->da_synced)
+ continue;
+ __dev_addr_delete(&to->mc_list, &to->mc_count,
+ da->da_addr, da->da_addrlen, 0);
+ da->da_synced = 0;
+ __dev_addr_delete(&from->mc_list, &from->mc_count,
+ da->da_addr, da->da_addrlen, 0);
}
- dev->mc_count = 0;
+ __dev_set_rx_mode(to);
- netif_tx_unlock_bh(dev);
+ netif_tx_unlock_bh(to);
+ netif_tx_unlock_bh(from);
}
+EXPORT_SYMBOL(dev_mc_unsync);
#ifdef CONFIG_PROC_FS
static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -244,7 +205,7 @@ static void dev_mc_seq_stop(struct seq_file *seq, void *v)
static int dev_mc_seq_show(struct seq_file *seq, void *v)
{
- struct dev_mc_list *m;
+ struct dev_addr_list *m;
struct net_device *dev = v;
netif_tx_lock_bh(dev);
@@ -292,4 +253,3 @@ void __init dev_mcast_init(void)
EXPORT_SYMBOL(dev_mc_add);
EXPORT_SYMBOL(dev_mc_delete);
-EXPORT_SYMBOL(dev_mc_upload);
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 8d5e5a09b576..0b531e98ec33 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -52,6 +52,17 @@ int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
return 0;
}
+
+int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ else
+ dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
+
+ return 0;
+}
+
u32 ethtool_op_get_sg(struct net_device *dev)
{
return (dev->features & NETIF_F_SG) != 0;
@@ -980,5 +991,6 @@ EXPORT_SYMBOL(ethtool_op_set_sg);
EXPORT_SYMBOL(ethtool_op_set_tso);
EXPORT_SYMBOL(ethtool_op_set_tx_csum);
EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
+EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
EXPORT_SYMBOL(ethtool_op_set_ufo);
EXPORT_SYMBOL(ethtool_op_get_ufo);
diff --git a/net/core/flow.c b/net/core/flow.c
index 051430545a05..0ab5234b17d8 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -350,7 +350,7 @@ static int __init flow_cache_init(void)
flow_cachep = kmem_cache_create("flow_cache",
sizeof(struct flow_cache_entry),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
flow_hash_shift = 10;
flow_lwm = 2 * flow_hash_size;
flow_hwm = 4 * flow_hash_size;
diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c
index 17daf4c9f793..590a767b029c 100644
--- a/net/core/gen_estimator.c
+++ b/net/core/gen_estimator.c
@@ -79,27 +79,27 @@
struct gen_estimator
{
- struct gen_estimator *next;
+ struct list_head list;
struct gnet_stats_basic *bstats;
struct gnet_stats_rate_est *rate_est;
spinlock_t *stats_lock;
- unsigned interval;
int ewma_log;
u64 last_bytes;
u32 last_packets;
u32 avpps;
u32 avbps;
+ struct rcu_head e_rcu;
};
struct gen_estimator_head
{
struct timer_list timer;
- struct gen_estimator *list;
+ struct list_head list;
};
static struct gen_estimator_head elist[EST_MAX_INTERVAL+1];
-/* Estimator array lock */
+/* Protects against NULL dereference */
static DEFINE_RWLOCK(est_lock);
static void est_timer(unsigned long arg)
@@ -107,13 +107,17 @@ static void est_timer(unsigned long arg)
int idx = (int)arg;
struct gen_estimator *e;
- read_lock(&est_lock);
- for (e = elist[idx].list; e; e = e->next) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(e, &elist[idx].list, list) {
u64 nbytes;
u32 npackets;
u32 rate;
spin_lock(e->stats_lock);
+ read_lock(&est_lock);
+ if (e->bstats == NULL)
+ goto skip;
+
nbytes = e->bstats->bytes;
npackets = e->bstats->packets;
rate = (nbytes - e->last_bytes)<<(7 - idx);
@@ -125,11 +129,14 @@ static void est_timer(unsigned long arg)
e->last_packets = npackets;
e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
e->rate_est->pps = (e->avpps+0x1FF)>>10;
+skip:
+ read_unlock(&est_lock);
spin_unlock(e->stats_lock);
}
- mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
- read_unlock(&est_lock);
+ if (!list_empty(&elist[idx].list))
+ mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+ rcu_read_unlock();
}
/**
@@ -146,12 +153,17 @@ static void est_timer(unsigned long arg)
* &rate_est with the statistics lock grabed during this period.
*
* Returns 0 on success or a negative error code.
+ *
+ * NOTE: Called under rtnl_mutex
*/
int gen_new_estimator(struct gnet_stats_basic *bstats,
- struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct rtattr *opt)
+ struct gnet_stats_rate_est *rate_est,
+ spinlock_t *stats_lock,
+ struct rtattr *opt)
{
struct gen_estimator *est;
struct gnet_estimator *parm = RTA_DATA(opt);
+ int idx;
if (RTA_PAYLOAD(opt) < sizeof(*parm))
return -EINVAL;
@@ -163,7 +175,7 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
if (est == NULL)
return -ENOBUFS;
- est->interval = parm->interval + 2;
+ idx = parm->interval + 2;
est->bstats = bstats;
est->rate_est = rate_est;
est->stats_lock = stats_lock;
@@ -173,20 +185,25 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
est->last_packets = bstats->packets;
est->avpps = rate_est->pps<<10;
- est->next = elist[est->interval].list;
- if (est->next == NULL) {
- init_timer(&elist[est->interval].timer);
- elist[est->interval].timer.data = est->interval;
- elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
- elist[est->interval].timer.function = est_timer;
- add_timer(&elist[est->interval].timer);
+ if (!elist[idx].timer.function) {
+ INIT_LIST_HEAD(&elist[idx].list);
+ setup_timer(&elist[idx].timer, est_timer, idx);
}
- write_lock_bh(&est_lock);
- elist[est->interval].list = est;
- write_unlock_bh(&est_lock);
+
+ if (list_empty(&elist[idx].list))
+ mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
+
+ list_add_rcu(&est->list, &elist[idx].list);
return 0;
}
+static void __gen_kill_estimator(struct rcu_head *head)
+{
+ struct gen_estimator *e = container_of(head,
+ struct gen_estimator, e_rcu);
+ kfree(e);
+}
+
/**
* gen_kill_estimator - remove a rate estimator
* @bstats: basic statistics
@@ -194,31 +211,32 @@ int gen_new_estimator(struct gnet_stats_basic *bstats,
*
* Removes the rate estimator specified by &bstats and &rate_est
* and deletes the timer.
+ *
+ * NOTE: Called under rtnl_mutex
*/
void gen_kill_estimator(struct gnet_stats_basic *bstats,
struct gnet_stats_rate_est *rate_est)
{
int idx;
- struct gen_estimator *est, **pest;
+ struct gen_estimator *e, *n;
for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
- int killed = 0;
- pest = &elist[idx].list;
- while ((est=*pest) != NULL) {
- if (est->rate_est != rate_est || est->bstats != bstats) {
- pest = &est->next;
+
+ /* Skip non initialized indexes */
+ if (!elist[idx].timer.function)
+ continue;
+
+ list_for_each_entry_safe(e, n, &elist[idx].list, list) {
+ if (e->rate_est != rate_est || e->bstats != bstats)
continue;
- }
write_lock_bh(&est_lock);
- *pest = est->next;
+ e->bstats = NULL;
write_unlock_bh(&est_lock);
- kfree(est);
- killed++;
+ list_del_rcu(&e->list);
+ call_rcu(&e->e_rcu, __gen_kill_estimator);
}
- if (killed && elist[idx].list == NULL)
- del_timer(&elist[idx].timer);
}
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 9df26a07f067..ca2a1533138a 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1347,7 +1347,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl)
tbl->kmem_cachep =
kmem_cache_create(tbl->id, tbl->entry_size, 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
tbl->stats = alloc_percpu(struct neigh_statistics);
if (!tbl->stats)
panic("cannot create neighbour cache statistics");
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index a0efdd7a6b37..de1b26aa5720 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -66,8 +66,9 @@ static void queue_process(struct work_struct *work)
local_irq_save(flags);
netif_tx_lock(dev);
- if (netif_queue_stopped(dev) ||
- dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
+ if ((netif_queue_stopped(dev) ||
+ netif_subqueue_stopped(dev, skb->queue_mapping)) ||
+ dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) {
skb_queue_head(&npinfo->txq, skb);
netif_tx_unlock(dev);
local_irq_restore(flags);
@@ -254,7 +255,8 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
tries > 0; --tries) {
if (netif_tx_trylock(dev)) {
- if (!netif_queue_stopped(dev))
+ if (!netif_queue_stopped(dev) &&
+ !netif_subqueue_stopped(dev, skb->queue_mapping))
status = dev->hard_start_xmit(skb, dev);
netif_tx_unlock(dev);
@@ -781,7 +783,6 @@ void netpoll_cleanup(struct netpoll *np)
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
}
- np->dev->npinfo = NULL;
if (atomic_dec_and_test(&npinfo->refcnt)) {
skb_queue_purge(&npinfo->arp_tx);
skb_queue_purge(&npinfo->txq);
@@ -794,6 +795,7 @@ void netpoll_cleanup(struct netpoll *np)
kfree_skb(skb);
}
kfree(npinfo);
+ np->dev->npinfo = NULL;
}
}
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 9cd3a1cb60ef..bca787fdbc51 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -152,6 +152,9 @@
#include <net/checksum.h>
#include <net/ipv6.h>
#include <net/addrconf.h>
+#ifdef CONFIG_XFRM
+#include <net/xfrm.h>
+#endif
#include <asm/byteorder.h>
#include <linux/rcupdate.h>
#include <asm/bitops.h>
@@ -181,6 +184,8 @@
#define F_MPLS_RND (1<<8) /* Random MPLS labels */
#define F_VID_RND (1<<9) /* Random VLAN ID */
#define F_SVID_RND (1<<10) /* Random SVLAN ID */
+#define F_FLOW_SEQ (1<<11) /* Sequential flows */
+#define F_IPSEC_ON (1<<12) /* ipsec on for flows */
/* Thread control flag bits */
#define T_TERMINATE (1<<0)
@@ -207,8 +212,15 @@ static struct proc_dir_entry *pg_proc_dir = NULL;
struct flow_state {
__be32 cur_daddr;
int count;
+#ifdef CONFIG_XFRM
+ struct xfrm_state *x;
+#endif
+ __u32 flags;
};
+/* flow flag bits */
+#define F_INIT (1<<0) /* flow has been initialized */
+
struct pktgen_dev {
/*
* Try to keep frequent/infrequent used vars. separated.
@@ -228,6 +240,7 @@ struct pktgen_dev {
int min_pkt_size; /* = ETH_ZLEN; */
int max_pkt_size; /* = ETH_ZLEN; */
+ int pkt_overhead; /* overhead for MPLS, VLANs, IPSEC etc */
int nfrags;
__u32 delay_us; /* Default delay */
__u32 delay_ns;
@@ -341,7 +354,11 @@ struct pktgen_dev {
unsigned cflows; /* Concurrent flows (config) */
unsigned lflow; /* Flow length (config) */
unsigned nflows; /* accumulated flows (stats) */
-
+ unsigned curfl; /* current sequenced flow (state)*/
+#ifdef CONFIG_XFRM
+ __u8 ipsmode; /* IPSEC mode (config) */
+ __u8 ipsproto; /* IPSEC type (config) */
+#endif
char result[512];
};
@@ -690,6 +707,18 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
if (pkt_dev->flags & F_MPLS_RND)
seq_printf(seq, "MPLS_RND ");
+ if (pkt_dev->cflows) {
+ if (pkt_dev->flags & F_FLOW_SEQ)
+ seq_printf(seq, "FLOW_SEQ "); /*in sequence flows*/
+ else
+ seq_printf(seq, "FLOW_RND ");
+ }
+
+#ifdef CONFIG_XFRM
+ if (pkt_dev->flags & F_IPSEC_ON)
+ seq_printf(seq, "IPSEC ");
+#endif
+
if (pkt_dev->flags & F_MACSRC_RND)
seq_printf(seq, "MACSRC_RND ");
@@ -1181,6 +1210,14 @@ static ssize_t pktgen_if_write(struct file *file,
else if (strcmp(f, "!SVID_RND") == 0)
pkt_dev->flags &= ~F_SVID_RND;
+ else if (strcmp(f, "FLOW_SEQ") == 0)
+ pkt_dev->flags |= F_FLOW_SEQ;
+
+#ifdef CONFIG_XFRM
+ else if (strcmp(f, "IPSEC") == 0)
+ pkt_dev->flags |= F_IPSEC_ON;
+#endif
+
else if (strcmp(f, "!IPV6") == 0)
pkt_dev->flags &= ~F_IPV6;
@@ -1189,7 +1226,7 @@ static ssize_t pktgen_if_write(struct file *file,
"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
f,
"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
- "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND\n");
+ "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n");
return count;
}
sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
@@ -2075,6 +2112,70 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
pkt_dev->idle_acc += now - start;
}
+static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
+{
+ pkt_dev->pkt_overhead = 0;
+ pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
+ pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
+ pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
+}
+
+static inline int f_seen(struct pktgen_dev *pkt_dev, int flow)
+{
+
+ if (pkt_dev->flows[flow].flags & F_INIT)
+ return 1;
+ else
+ return 0;
+}
+
+static inline int f_pick(struct pktgen_dev *pkt_dev)
+{
+ int flow = pkt_dev->curfl;
+
+ if (pkt_dev->flags & F_FLOW_SEQ) {
+ if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
+ /* reset time */
+ pkt_dev->flows[flow].count = 0;
+ pkt_dev->curfl += 1;
+ if (pkt_dev->curfl >= pkt_dev->cflows)
+ pkt_dev->curfl = 0; /*reset */
+ }
+ } else {
+ flow = random32() % pkt_dev->cflows;
+
+ if (pkt_dev->flows[flow].count > pkt_dev->lflow)
+ pkt_dev->flows[flow].count = 0;
+ }
+
+ return pkt_dev->curfl;
+}
+
+
+#ifdef CONFIG_XFRM
+/* If there was already an IPSEC SA, we keep it as is, else
+ * we go look for it ...
+*/
+inline
+void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
+{
+ struct xfrm_state *x = pkt_dev->flows[flow].x;
+ if (!x) {
+ /*slow path: we dont already have xfrm_state*/
+ x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr,
+ (xfrm_address_t *)&pkt_dev->cur_saddr,
+ AF_INET,
+ pkt_dev->ipsmode,
+ pkt_dev->ipsproto, 0);
+ if (x) {
+ pkt_dev->flows[flow].x = x;
+ set_pkt_overhead(pkt_dev);
+ pkt_dev->pkt_overhead+=x->props.header_len;
+ }
+
+ }
+}
+#endif
/* Increment/randomize headers according to flags and current values
* for IP src/dest, UDP src/dst port, MAC-Addr src/dst
*/
@@ -2084,12 +2185,8 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
__u32 imx;
int flow = 0;
- if (pkt_dev->cflows) {
- flow = random32() % pkt_dev->cflows;
-
- if (pkt_dev->flows[flow].count > pkt_dev->lflow)
- pkt_dev->flows[flow].count = 0;
- }
+ if (pkt_dev->cflows)
+ flow = f_pick(pkt_dev);
/* Deal with source MAC */
if (pkt_dev->src_mac_count > 1) {
@@ -2205,7 +2302,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
pkt_dev->cur_saddr = htonl(t);
}
- if (pkt_dev->cflows && pkt_dev->flows[flow].count != 0) {
+ if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
} else {
imn = ntohl(pkt_dev->daddr_min);
@@ -2235,8 +2332,13 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
}
}
if (pkt_dev->cflows) {
+ pkt_dev->flows[flow].flags |= F_INIT;
pkt_dev->flows[flow].cur_daddr =
pkt_dev->cur_daddr;
+#ifdef CONFIG_XFRM
+ if (pkt_dev->flags & F_IPSEC_ON)
+ get_ipsec_sa(pkt_dev, flow);
+#endif
pkt_dev->nflows++;
}
}
@@ -2277,6 +2379,91 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
pkt_dev->flows[flow].count++;
}
+
+#ifdef CONFIG_XFRM
+static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
+{
+ struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
+ int err = 0;
+ struct iphdr *iph;
+
+ if (!x)
+ return 0;
+ /* XXX: we dont support tunnel mode for now until
+ * we resolve the dst issue */
+ if (x->props.mode != XFRM_MODE_TRANSPORT)
+ return 0;
+
+ spin_lock(&x->lock);
+ iph = ip_hdr(skb);
+
+ err = x->mode->output(x, skb);
+ if (err)
+ goto error;
+ err = x->type->output(x, skb);
+ if (err)
+ goto error;
+
+ x->curlft.bytes +=skb->len;
+ x->curlft.packets++;
+ spin_unlock(&x->lock);
+
+error:
+ spin_unlock(&x->lock);
+ return err;
+}
+
+static inline void free_SAs(struct pktgen_dev *pkt_dev)
+{
+ if (pkt_dev->cflows) {
+ /* let go of the SAs if we have them */
+ int i = 0;
+ for (; i < pkt_dev->nflows; i++){
+ struct xfrm_state *x = pkt_dev->flows[i].x;
+ if (x) {
+ xfrm_state_put(x);
+ pkt_dev->flows[i].x = NULL;
+ }
+ }
+ }
+}
+
+static inline int process_ipsec(struct pktgen_dev *pkt_dev,
+ struct sk_buff *skb, __be16 protocol)
+{
+ if (pkt_dev->flags & F_IPSEC_ON) {
+ struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
+ int nhead = 0;
+ if (x) {
+ int ret;
+ __u8 *eth;
+ nhead = x->props.header_len - skb_headroom(skb);
+ if (nhead >0) {
+ ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
+ if (ret < 0) {
+ printk("Error expanding ipsec packet %d\n",ret);
+ return 0;
+ }
+ }
+
+ /* ipsec is not expecting ll header */
+ skb_pull(skb, ETH_HLEN);
+ ret = pktgen_output_ipsec(skb, pkt_dev);
+ if (ret) {
+ printk("Error creating ipsec packet %d\n",ret);
+ kfree_skb(skb);
+ return 0;
+ }
+ /* restore ll */
+ eth = (__u8 *) skb_push(skb, ETH_HLEN);
+ memcpy(eth, pkt_dev->hh, 12);
+ *(u16 *) & eth[12] = protocol;
+ }
+ }
+ return 1;
+}
+#endif
+
static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
{
unsigned i;
@@ -2323,9 +2510,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
datalen = (odev->hard_header_len + 16) & ~0xf;
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
- pkt_dev->nr_labels*sizeof(u32) +
- VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
- GFP_ATOMIC);
+ pkt_dev->pkt_overhead, GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
@@ -2368,7 +2553,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
/* Eth + IPh + UDPh + mpls */
datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
- pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+ pkt_dev->pkt_overhead;
if (datalen < sizeof(struct pktgen_hdr))
datalen = sizeof(struct pktgen_hdr);
@@ -2391,8 +2576,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
iph->check = ip_fast_csum((void *)iph, iph->ihl);
skb->protocol = protocol;
skb->mac_header = (skb->network_header - ETH_HLEN -
- pkt_dev->nr_labels * sizeof(u32) -
- VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev));
+ pkt_dev->pkt_overhead);
skb->dev = odev;
skb->pkt_type = PACKET_HOST;
@@ -2463,6 +2647,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
pgh->tv_usec = htonl(timestamp.tv_usec);
}
+#ifdef CONFIG_XFRM
+ if (!process_ipsec(pkt_dev, skb, protocol))
+ return NULL;
+#endif
+
return skb;
}
@@ -2662,9 +2851,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
mod_cur_headers(pkt_dev);
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
- pkt_dev->nr_labels*sizeof(u32) +
- VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
- GFP_ATOMIC);
+ pkt_dev->pkt_overhead, GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
@@ -2708,7 +2895,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
/* Eth + IPh + UDPh + mpls */
datalen = pkt_dev->cur_pkt_size - 14 -
sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
- pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+ pkt_dev->pkt_overhead;
if (datalen < sizeof(struct pktgen_hdr)) {
datalen = sizeof(struct pktgen_hdr);
@@ -2738,8 +2925,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
skb->mac_header = (skb->network_header - ETH_HLEN -
- pkt_dev->nr_labels * sizeof(u32) -
- VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev));
+ pkt_dev->pkt_overhead);
skb->protocol = protocol;
skb->dev = odev;
skb->pkt_type = PACKET_HOST;
@@ -2857,6 +3043,7 @@ static void pktgen_run(struct pktgen_thread *t)
pkt_dev->started_at = getCurUs();
pkt_dev->next_tx_us = getCurUs(); /* Transmit immediately */
pkt_dev->next_tx_ns = 0;
+ set_pkt_overhead(pkt_dev);
strcpy(pkt_dev->result, "Starting");
started++;
@@ -3139,7 +3326,9 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
}
}
- if (netif_queue_stopped(odev) || need_resched()) {
+ if ((netif_queue_stopped(odev) ||
+ netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) ||
+ need_resched()) {
idle_start = getCurUs();
if (!netif_running(odev)) {
@@ -3154,7 +3343,8 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
pkt_dev->idle_acc += getCurUs() - idle_start;
- if (netif_queue_stopped(odev)) {
+ if (netif_queue_stopped(odev) ||
+ netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
pkt_dev->next_tx_us = getCurUs(); /* TODO */
pkt_dev->next_tx_ns = 0;
goto out; /* Try the next interface */
@@ -3181,7 +3371,8 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
}
netif_tx_lock_bh(odev);
- if (!netif_queue_stopped(odev)) {
+ if (!netif_queue_stopped(odev) &&
+ !netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
atomic_inc(&(pkt_dev->skb->users));
retry_now:
@@ -3274,6 +3465,8 @@ static int pktgen_thread_worker(void *arg)
set_current_state(TASK_INTERRUPTIBLE);
+ set_freezable();
+
while (!kthread_should_stop()) {
pkt_dev = next_to_run(t);
@@ -3446,11 +3639,18 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
}
pkt_dev->entry->proc_fops = &pktgen_if_fops;
pkt_dev->entry->data = pkt_dev;
+#ifdef CONFIG_XFRM
+ pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
+ pkt_dev->ipsproto = IPPROTO_ESP;
+#endif
return add_dev_to_thread(t, pkt_dev);
out2:
dev_put(pkt_dev->odev);
out1:
+#ifdef CONFIG_XFRM
+ free_SAs(pkt_dev);
+#endif
if (pkt_dev->flows)
vfree(pkt_dev->flows);
kfree(pkt_dev);
@@ -3545,6 +3745,9 @@ static int pktgen_remove_device(struct pktgen_thread *t,
if (pkt_dev->entry)
remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
+#ifdef CONFIG_XFRM
+ free_SAs(pkt_dev);
+#endif
if (pkt_dev->flows)
vfree(pkt_dev->flows);
kfree(pkt_dev);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 02e8bf084277..06eccca8cb5d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -97,6 +97,19 @@ int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
return 0;
}
+int __rtattr_parse_nested_compat(struct rtattr *tb[], int maxattr,
+ struct rtattr *rta, int len)
+{
+ if (RTA_PAYLOAD(rta) < len)
+ return -1;
+ if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
+ rta = RTA_DATA(rta) + RTA_ALIGN(len);
+ return rtattr_parse_nested(tb, maxattr, rta);
+ }
+ memset(tb, 0, sizeof(struct rtattr *) * maxattr);
+ return 0;
+}
+
static struct rtnl_link *rtnl_msg_handlers[NPROTO];
static inline int rtm_msgindex(int msgtype)
@@ -243,6 +256,150 @@ void rtnl_unregister_all(int protocol)
EXPORT_SYMBOL_GPL(rtnl_unregister_all);
+static LIST_HEAD(link_ops);
+
+/**
+ * __rtnl_link_register - Register rtnl_link_ops with rtnetlink.
+ * @ops: struct rtnl_link_ops * to register
+ *
+ * The caller must hold the rtnl_mutex. This function should be used
+ * by drivers that create devices during module initialization. It
+ * must be called before registering the devices.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int __rtnl_link_register(struct rtnl_link_ops *ops)
+{
+ if (!ops->dellink)
+ ops->dellink = unregister_netdevice;
+
+ list_add_tail(&ops->list, &link_ops);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(__rtnl_link_register);
+
+/**
+ * rtnl_link_register - Register rtnl_link_ops with rtnetlink.
+ * @ops: struct rtnl_link_ops * to register
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int rtnl_link_register(struct rtnl_link_ops *ops)
+{
+ int err;
+
+ rtnl_lock();
+ err = __rtnl_link_register(ops);
+ rtnl_unlock();
+ return err;
+}
+
+EXPORT_SYMBOL_GPL(rtnl_link_register);
+
+/**
+ * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
+ * @ops: struct rtnl_link_ops * to unregister
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+void __rtnl_link_unregister(struct rtnl_link_ops *ops)
+{
+ struct net_device *dev, *n;
+
+ for_each_netdev_safe(dev, n) {
+ if (dev->rtnl_link_ops == ops)
+ ops->dellink(dev);
+ }
+ list_del(&ops->list);
+}
+
+EXPORT_SYMBOL_GPL(__rtnl_link_unregister);
+
+/**
+ * rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink.
+ * @ops: struct rtnl_link_ops * to unregister
+ */
+void rtnl_link_unregister(struct rtnl_link_ops *ops)
+{
+ rtnl_lock();
+ __rtnl_link_unregister(ops);
+ rtnl_unlock();
+}
+
+EXPORT_SYMBOL_GPL(rtnl_link_unregister);
+
+static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind)
+{
+ const struct rtnl_link_ops *ops;
+
+ list_for_each_entry(ops, &link_ops, list) {
+ if (!strcmp(ops->kind, kind))
+ return ops;
+ }
+ return NULL;
+}
+
+static size_t rtnl_link_get_size(const struct net_device *dev)
+{
+ const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
+ size_t size;
+
+ if (!ops)
+ return 0;
+
+ size = nlmsg_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */
+ nlmsg_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_KIND */
+
+ if (ops->get_size)
+ /* IFLA_INFO_DATA + nested data */
+ size += nlmsg_total_size(sizeof(struct nlattr)) +
+ ops->get_size(dev);
+
+ if (ops->get_xstats_size)
+ size += ops->get_xstats_size(dev); /* IFLA_INFO_XSTATS */
+
+ return size;
+}
+
+static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
+{
+ const struct rtnl_link_ops *ops = dev->rtnl_link_ops;
+ struct nlattr *linkinfo, *data;
+ int err = -EMSGSIZE;
+
+ linkinfo = nla_nest_start(skb, IFLA_LINKINFO);
+ if (linkinfo == NULL)
+ goto out;
+
+ if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0)
+ goto err_cancel_link;
+ if (ops->fill_xstats) {
+ err = ops->fill_xstats(skb, dev);
+ if (err < 0)
+ goto err_cancel_link;
+ }
+ if (ops->fill_info) {
+ data = nla_nest_start(skb, IFLA_INFO_DATA);
+ if (data == NULL)
+ goto err_cancel_link;
+ err = ops->fill_info(skb, dev);
+ if (err < 0)
+ goto err_cancel_data;
+ nla_nest_end(skb, data);
+ }
+
+ nla_nest_end(skb, linkinfo);
+ return 0;
+
+err_cancel_data:
+ nla_nest_cancel(skb, data);
+err_cancel_link:
+ nla_nest_cancel(skb, linkinfo);
+out:
+ return err;
+}
+
static const int rtm_min[RTM_NR_FAMILIES] =
{
[RTM_FAM(RTM_NEWLINK)] = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
@@ -437,7 +594,7 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->tx_compressed = b->tx_compressed;
};
-static inline size_t if_nlmsg_size(void)
+static inline size_t if_nlmsg_size(const struct net_device *dev)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
+ nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
@@ -452,7 +609,8 @@ static inline size_t if_nlmsg_size(void)
+ nla_total_size(4) /* IFLA_LINK */
+ nla_total_size(4) /* IFLA_MASTER */
+ nla_total_size(1) /* IFLA_OPERSTATE */
- + nla_total_size(1); /* IFLA_LINKMODE */
+ + nla_total_size(1) /* IFLA_LINKMODE */
+ + rtnl_link_get_size(dev); /* IFLA_LINKINFO */
}
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
@@ -522,6 +680,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
}
}
+ if (dev->rtnl_link_ops) {
+ if (rtnl_link_fill(skb, dev) < 0)
+ goto nla_put_failure;
+ }
+
return nlmsg_end(skb, nlh);
nla_put_failure:
@@ -553,6 +716,8 @@ cont:
static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 },
+ [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
+ [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
[IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) },
[IFLA_MTU] = { .type = NLA_U32 },
[IFLA_TXQLEN] = { .type = NLA_U32 },
@@ -561,44 +726,16 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_LINKMODE] = { .type = NLA_U8 },
};
-static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
-{
- struct ifinfomsg *ifm;
- struct net_device *dev;
- int err, send_addr_notify = 0, modified = 0;
- struct nlattr *tb[IFLA_MAX+1];
- char ifname[IFNAMSIZ];
-
- err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
- if (err < 0)
- goto errout;
-
- if (tb[IFLA_IFNAME])
- nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
- else
- ifname[0] = '\0';
-
- err = -EINVAL;
- ifm = nlmsg_data(nlh);
- if (ifm->ifi_index > 0)
- dev = dev_get_by_index(ifm->ifi_index);
- else if (tb[IFLA_IFNAME])
- dev = dev_get_by_name(ifname);
- else
- goto errout;
-
- if (dev == NULL) {
- err = -ENODEV;
- goto errout;
- }
-
- if (tb[IFLA_ADDRESS] &&
- nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
- goto errout_dev;
+static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = {
+ [IFLA_INFO_KIND] = { .type = NLA_STRING },
+ [IFLA_INFO_DATA] = { .type = NLA_NESTED },
+};
- if (tb[IFLA_BROADCAST] &&
- nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
- goto errout_dev;
+static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
+ struct nlattr **tb, char *ifname, int modified)
+{
+ int send_addr_notify = 0;
+ int err;
if (tb[IFLA_MAP]) {
struct rtnl_link_ifmap *u_map;
@@ -606,12 +743,12 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (!dev->set_config) {
err = -EOPNOTSUPP;
- goto errout_dev;
+ goto errout;
}
if (!netif_device_present(dev)) {
err = -ENODEV;
- goto errout_dev;
+ goto errout;
}
u_map = nla_data(tb[IFLA_MAP]);
@@ -624,7 +761,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
err = dev->set_config(dev, &k_map);
if (err < 0)
- goto errout_dev;
+ goto errout;
modified = 1;
}
@@ -635,19 +772,19 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (!dev->set_mac_address) {
err = -EOPNOTSUPP;
- goto errout_dev;
+ goto errout;
}
if (!netif_device_present(dev)) {
err = -ENODEV;
- goto errout_dev;
+ goto errout;
}
len = sizeof(sa_family_t) + dev->addr_len;
sa = kmalloc(len, GFP_KERNEL);
if (!sa) {
err = -ENOMEM;
- goto errout_dev;
+ goto errout;
}
sa->sa_family = dev->type;
memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]),
@@ -655,7 +792,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
err = dev->set_mac_address(dev, sa);
kfree(sa);
if (err)
- goto errout_dev;
+ goto errout;
send_addr_notify = 1;
modified = 1;
}
@@ -663,7 +800,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (tb[IFLA_MTU]) {
err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
if (err < 0)
- goto errout_dev;
+ goto errout;
modified = 1;
}
@@ -675,7 +812,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
if (ifm->ifi_index > 0 && ifname[0]) {
err = dev_change_name(dev, ifname);
if (err < 0)
- goto errout_dev;
+ goto errout;
modified = 1;
}
@@ -684,7 +821,6 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
send_addr_notify = 1;
}
-
if (ifm->ifi_flags || ifm->ifi_change) {
unsigned int flags = ifm->ifi_flags;
@@ -712,7 +848,7 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
err = 0;
-errout_dev:
+errout:
if (err < 0 && modified && net_ratelimit())
printk(KERN_WARNING "A link change request failed with "
"some changes comitted already. Interface %s may "
@@ -721,12 +857,239 @@ errout_dev:
if (send_addr_notify)
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
+ return err;
+}
+
+static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ struct ifinfomsg *ifm;
+ struct net_device *dev;
+ int err;
+ struct nlattr *tb[IFLA_MAX+1];
+ char ifname[IFNAMSIZ];
+
+ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
+ if (err < 0)
+ goto errout;
+
+ if (tb[IFLA_IFNAME])
+ nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
+ else
+ ifname[0] = '\0';
+
+ err = -EINVAL;
+ ifm = nlmsg_data(nlh);
+ if (ifm->ifi_index > 0)
+ dev = dev_get_by_index(ifm->ifi_index);
+ else if (tb[IFLA_IFNAME])
+ dev = dev_get_by_name(ifname);
+ else
+ goto errout;
+
+ if (dev == NULL) {
+ err = -ENODEV;
+ goto errout;
+ }
+ if (tb[IFLA_ADDRESS] &&
+ nla_len(tb[IFLA_ADDRESS]) < dev->addr_len)
+ goto errout_dev;
+
+ if (tb[IFLA_BROADCAST] &&
+ nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
+ goto errout_dev;
+
+ err = do_setlink(dev, ifm, tb, ifname, 0);
+errout_dev:
dev_put(dev);
errout:
return err;
}
+static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ const struct rtnl_link_ops *ops;
+ struct net_device *dev;
+ struct ifinfomsg *ifm;
+ char ifname[IFNAMSIZ];
+ struct nlattr *tb[IFLA_MAX+1];
+ int err;
+
+ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[IFLA_IFNAME])
+ nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
+
+ ifm = nlmsg_data(nlh);
+ if (ifm->ifi_index > 0)
+ dev = __dev_get_by_index(ifm->ifi_index);
+ else if (tb[IFLA_IFNAME])
+ dev = __dev_get_by_name(ifname);
+ else
+ return -EINVAL;
+
+ if (!dev)
+ return -ENODEV;
+
+ ops = dev->rtnl_link_ops;
+ if (!ops)
+ return -EOPNOTSUPP;
+
+ ops->dellink(dev);
+ return 0;
+}
+
+static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+{
+ const struct rtnl_link_ops *ops;
+ struct net_device *dev;
+ struct ifinfomsg *ifm;
+ char kind[MODULE_NAME_LEN];
+ char ifname[IFNAMSIZ];
+ struct nlattr *tb[IFLA_MAX+1];
+ struct nlattr *linkinfo[IFLA_INFO_MAX+1];
+ int err;
+
+replay:
+ err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[IFLA_IFNAME])
+ nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ);
+ else
+ ifname[0] = '\0';
+
+ ifm = nlmsg_data(nlh);
+ if (ifm->ifi_index > 0)
+ dev = __dev_get_by_index(ifm->ifi_index);
+ else if (ifname[0])
+ dev = __dev_get_by_name(ifname);
+ else
+ dev = NULL;
+
+ if (tb[IFLA_LINKINFO]) {
+ err = nla_parse_nested(linkinfo, IFLA_INFO_MAX,
+ tb[IFLA_LINKINFO], ifla_info_policy);
+ if (err < 0)
+ return err;
+ } else
+ memset(linkinfo, 0, sizeof(linkinfo));
+
+ if (linkinfo[IFLA_INFO_KIND]) {
+ nla_strlcpy(kind, linkinfo[IFLA_INFO_KIND], sizeof(kind));
+ ops = rtnl_link_ops_get(kind);
+ } else {
+ kind[0] = '\0';
+ ops = NULL;
+ }
+
+ if (1) {
+ struct nlattr *attr[ops ? ops->maxtype + 1 : 0], **data = NULL;
+
+ if (ops) {
+ if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) {
+ err = nla_parse_nested(attr, ops->maxtype,
+ linkinfo[IFLA_INFO_DATA],
+ ops->policy);
+ if (err < 0)
+ return err;
+ data = attr;
+ }
+ if (ops->validate) {
+ err = ops->validate(tb, data);
+ if (err < 0)
+ return err;
+ }
+ }
+
+ if (dev) {
+ int modified = 0;
+
+ if (nlh->nlmsg_flags & NLM_F_EXCL)
+ return -EEXIST;
+ if (nlh->nlmsg_flags & NLM_F_REPLACE)
+ return -EOPNOTSUPP;
+
+ if (linkinfo[IFLA_INFO_DATA]) {
+ if (!ops || ops != dev->rtnl_link_ops ||
+ !ops->changelink)
+ return -EOPNOTSUPP;
+
+ err = ops->changelink(dev, tb, data);
+ if (err < 0)
+ return err;
+ modified = 1;
+ }
+
+ return do_setlink(dev, ifm, tb, ifname, modified);
+ }
+
+ if (!(nlh->nlmsg_flags & NLM_F_CREATE))
+ return -ENODEV;
+
+ if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change)
+ return -EOPNOTSUPP;
+ if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO])
+ return -EOPNOTSUPP;
+
+ if (!ops) {
+#ifdef CONFIG_KMOD
+ if (kind[0]) {
+ __rtnl_unlock();
+ request_module("rtnl-link-%s", kind);
+ rtnl_lock();
+ ops = rtnl_link_ops_get(kind);
+ if (ops)
+ goto replay;
+ }
+#endif
+ return -EOPNOTSUPP;
+ }
+
+ if (!ifname[0])
+ snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind);
+ dev = alloc_netdev(ops->priv_size, ifname, ops->setup);
+ if (!dev)
+ return -ENOMEM;
+
+ if (strchr(dev->name, '%')) {
+ err = dev_alloc_name(dev, dev->name);
+ if (err < 0)
+ goto err_free;
+ }
+ dev->rtnl_link_ops = ops;
+
+ if (tb[IFLA_MTU])
+ dev->mtu = nla_get_u32(tb[IFLA_MTU]);
+ if (tb[IFLA_ADDRESS])
+ memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]),
+ nla_len(tb[IFLA_ADDRESS]));
+ if (tb[IFLA_BROADCAST])
+ memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]),
+ nla_len(tb[IFLA_BROADCAST]));
+ if (tb[IFLA_TXQLEN])
+ dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]);
+ if (tb[IFLA_WEIGHT])
+ dev->weight = nla_get_u32(tb[IFLA_WEIGHT]);
+ if (tb[IFLA_OPERSTATE])
+ set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE]));
+ if (tb[IFLA_LINKMODE])
+ dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]);
+
+ if (ops->newlink)
+ err = ops->newlink(dev, tb, data);
+ else
+ err = register_netdevice(dev);
+err_free:
+ if (err < 0)
+ free_netdev(dev);
+ return err;
+ }
+}
+
static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{
struct ifinfomsg *ifm;
@@ -747,7 +1110,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
} else
return -EINVAL;
- nskb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL);
+ nskb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
if (nskb == NULL) {
err = -ENOBUFS;
goto errout;
@@ -797,7 +1160,7 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
struct sk_buff *skb;
int err = -ENOBUFS;
- skb = nlmsg_new(if_nlmsg_size(), GFP_KERNEL);
+ skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL);
if (skb == NULL)
goto errout;
@@ -952,6 +1315,8 @@ void __init rtnetlink_init(void)
rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, rtnl_dump_ifinfo);
rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL);
+ rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL);
+ rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL);
rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all);
rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all);
@@ -960,6 +1325,7 @@ void __init rtnetlink_init(void)
EXPORT_SYMBOL(__rta_fill);
EXPORT_SYMBOL(rtattr_strlcpy);
EXPORT_SYMBOL(rtattr_parse);
+EXPORT_SYMBOL(__rtattr_parse_nested_compat);
EXPORT_SYMBOL(rtnetlink_put_metrics);
EXPORT_SYMBOL(rtnl_lock);
EXPORT_SYMBOL(rtnl_trylock);
diff --git a/net/core/scm.c b/net/core/scm.c
index 292ad8d5ad76..44c4ec2c8769 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -228,7 +228,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
err = security_file_receive(fp[i]);
if (err)
break;
- err = get_unused_fd();
+ err = get_unused_fd_flags(MSG_CMSG_CLOEXEC & msg->msg_flags
+ ? O_CLOEXEC : 0);
if (err < 0)
break;
new_fd = err;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 3943c3ad9145..35021eb3ed07 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -415,9 +415,11 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
C(csum);
C(local_df);
n->cloned = 1;
+ n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
n->nohdr = 0;
C(pkt_type);
C(ip_summed);
+ skb_copy_queue_mapping(n, skb);
C(priority);
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
C(ipvs_property);
@@ -426,6 +428,10 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
n->destructor = NULL;
C(mark);
__nf_copy(n, skb);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ C(nf_trace);
+#endif
#ifdef CONFIG_NET_SCHED
C(tc_index);
#ifdef CONFIG_NET_CLS_ACT
@@ -459,6 +465,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
#endif
new->sk = NULL;
new->dev = old->dev;
+ skb_copy_queue_mapping(new, old);
new->priority = old->priority;
new->protocol = old->protocol;
new->dst = dst_clone(old->dst);
@@ -482,6 +489,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->destructor = NULL;
new->mark = old->mark;
__nf_copy(new, old);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ new->nf_trace = old->nf_trace;
+#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
new->ipvs_property = old->ipvs_property;
#endif
@@ -676,6 +687,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb->network_header += off;
skb->mac_header += off;
skb->cloned = 0;
+ skb->hdr_len = 0;
skb->nohdr = 0;
atomic_set(&skb_shinfo(skb)->dataref, 1);
return 0;
@@ -1930,6 +1942,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
tail = nskb;
nskb->dev = skb->dev;
+ skb_copy_queue_mapping(nskb, skb);
nskb->priority = skb->priority;
nskb->protocol = skb->protocol;
nskb->dst = dst_clone(skb->dst);
@@ -2008,13 +2021,13 @@ void __init skb_init(void)
sizeof(struct sk_buff),
0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache",
(2*sizeof(struct sk_buff)) +
sizeof(atomic_t),
0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
}
/**
diff --git a/net/core/sock.c b/net/core/sock.c
index c14ce0198d25..cfed7d42c485 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -171,6 +171,20 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
"slock-AF_RXRPC" , "slock-AF_MAX"
};
+static const char *af_family_clock_key_strings[AF_MAX+1] = {
+ "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" ,
+ "clock-AF_AX25" , "clock-AF_IPX" , "clock-AF_APPLETALK",
+ "clock-AF_NETROM", "clock-AF_BRIDGE" , "clock-AF_ATMPVC" ,
+ "clock-AF_X25" , "clock-AF_INET6" , "clock-AF_ROSE" ,
+ "clock-AF_DECnet", "clock-AF_NETBEUI" , "clock-AF_SECURITY" ,
+ "clock-AF_KEY" , "clock-AF_NETLINK" , "clock-AF_PACKET" ,
+ "clock-AF_ASH" , "clock-AF_ECONET" , "clock-AF_ATMSVC" ,
+ "clock-21" , "clock-AF_SNA" , "clock-AF_IRDA" ,
+ "clock-AF_PPPOX" , "clock-AF_WANPIPE" , "clock-AF_LLC" ,
+ "clock-27" , "clock-28" , "clock-29" ,
+ "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
+ "clock-AF_RXRPC" , "clock-AF_MAX"
+};
#endif
/*
@@ -210,13 +224,14 @@ static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
return -EDOM;
if (tv.tv_sec < 0) {
- static int warned = 0;
+ static int warned __read_mostly;
+
*timeo_p = 0;
if (warned < 10 && net_ratelimit())
warned++;
printk(KERN_INFO "sock_set_timeout: `%s' (pid %d) "
"tries to set negative timeout\n",
- current->comm, current->pid);
+ current->comm, current->pid);
return 0;
}
*timeo_p = MAX_SCHEDULE_TIMEOUT;
@@ -940,8 +955,9 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
rwlock_init(&newsk->sk_dst_lock);
rwlock_init(&newsk->sk_callback_lock);
- lockdep_set_class(&newsk->sk_callback_lock,
- af_callback_keys + newsk->sk_family);
+ lockdep_set_class_and_name(&newsk->sk_callback_lock,
+ af_callback_keys + newsk->sk_family,
+ af_family_clock_key_strings[newsk->sk_family]);
newsk->sk_dst_cache = NULL;
newsk->sk_wmem_queued = 0;
@@ -1529,8 +1545,9 @@ void sock_init_data(struct socket *sock, struct sock *sk)
rwlock_init(&sk->sk_dst_lock);
rwlock_init(&sk->sk_callback_lock);
- lockdep_set_class(&sk->sk_callback_lock,
- af_callback_keys + sk->sk_family);
+ lockdep_set_class_and_name(&sk->sk_callback_lock,
+ af_callback_keys + sk->sk_family,
+ af_family_clock_key_strings[sk->sk_family]);
sk->sk_state_change = sock_def_wakeup;
sk->sk_data_ready = sock_def_readable;
@@ -1751,7 +1768,7 @@ int proto_register(struct proto *prot, int alloc_slab)
if (alloc_slab) {
prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (prot->slab == NULL) {
printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n",
@@ -1769,7 +1786,7 @@ int proto_register(struct proto *prot, int alloc_slab)
sprintf(request_sock_slab_name, mask, prot->name);
prot->rsk_prot->slab = kmem_cache_create(request_sock_slab_name,
prot->rsk_prot->obj_size, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (prot->rsk_prot->slab == NULL) {
printk(KERN_CRIT "%s: Can't create request sock SLAB cache!\n",
@@ -1791,7 +1808,7 @@ int proto_register(struct proto *prot, int alloc_slab)
kmem_cache_create(timewait_sock_slab_name,
prot->twsk_prot->twsk_obj_size,
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (prot->twsk_prot->twsk_slab == NULL)
goto out_free_timewait_sock_slab_name;
}
@@ -1851,46 +1868,15 @@ void proto_unregister(struct proto *prot)
EXPORT_SYMBOL(proto_unregister);
#ifdef CONFIG_PROC_FS
-static inline struct proto *__proto_head(void)
-{
- return list_entry(proto_list.next, struct proto, node);
-}
-
-static inline struct proto *proto_head(void)
-{
- return list_empty(&proto_list) ? NULL : __proto_head();
-}
-
-static inline struct proto *proto_next(struct proto *proto)
-{
- return proto->node.next == &proto_list ? NULL :
- list_entry(proto->node.next, struct proto, node);
-}
-
-static inline struct proto *proto_get_idx(loff_t pos)
-{
- struct proto *proto;
- loff_t i = 0;
-
- list_for_each_entry(proto, &proto_list, node)
- if (i++ == pos)
- goto out;
-
- proto = NULL;
-out:
- return proto;
-}
-
static void *proto_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&proto_list_lock);
- return *pos ? proto_get_idx(*pos - 1) : SEQ_START_TOKEN;
+ return seq_list_start_head(&proto_list, *pos);
}
static void *proto_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- ++*pos;
- return v == SEQ_START_TOKEN ? proto_head() : proto_next(v);
+ return seq_list_next(v, &proto_list, pos);
}
static void proto_seq_stop(struct seq_file *seq, void *v)
@@ -1938,7 +1924,7 @@ static void proto_seq_printf(struct seq_file *seq, struct proto *proto)
static int proto_seq_show(struct seq_file *seq, void *v)
{
- if (v == SEQ_START_TOKEN)
+ if (v == &proto_list)
seq_printf(seq, "%-9s %-4s %-8s %-6s %-5s %-7s %-4s %-10s %s",
"protocol",
"size",
@@ -1950,7 +1936,7 @@ static int proto_seq_show(struct seq_file *seq, void *v)
"module",
"cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n");
else
- proto_seq_printf(seq, v);
+ proto_seq_printf(seq, list_entry(v, struct proto, node));
return 0;
}
diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c
index 01030f346177..7ac775f9a64b 100644
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -481,14 +481,14 @@ int __init dccp_ackvec_init(void)
{
dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
sizeof(struct dccp_ackvec), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (dccp_ackvec_slab == NULL)
goto out_err;
dccp_ackvec_record_slab =
kmem_cache_create("dccp_ackvec_record",
sizeof(struct dccp_ackvec_record),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (dccp_ackvec_record_slab == NULL)
goto out_destroy_slab;
diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c
index d8cf92f09e68..ccbf72c793b6 100644
--- a/net/dccp/ccid.c
+++ b/net/dccp/ccid.c
@@ -69,7 +69,7 @@ static struct kmem_cache *ccid_kmem_cache_create(int obj_size, const char *fmt,.
if (slab_name == NULL)
return NULL;
slab = kmem_cache_create(slab_name, sizeof(struct ccid) + obj_size, 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (slab == NULL)
kfree(slab_name);
return slab;
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index ec7fa4d67f08..e91c2b9dc27b 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -1,8 +1,8 @@
/*
* net/dccp/ccids/ccid3.c
*
- * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
- * Copyright (c) 2005-6 Ian McDonald <ian.mcdonald@jandi.co.nz>
+ * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand.
+ * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz>
*
* An implementation of the DCCP protocol
*
@@ -49,7 +49,6 @@ static int ccid3_debug;
static struct dccp_tx_hist *ccid3_tx_hist;
static struct dccp_rx_hist *ccid3_rx_hist;
-static struct dccp_li_hist *ccid3_li_hist;
/*
* Transmitter Half-Connection Routines
@@ -194,25 +193,20 @@ static inline void ccid3_hc_tx_update_s(struct ccid3_hc_tx_sock *hctx, int len)
* The algorithm is not applicable if RTT < 4 microseconds.
*/
static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hctx,
- struct timeval *now)
+ ktime_t now)
{
- suseconds_t delta;
u32 quarter_rtts;
if (unlikely(hctx->ccid3hctx_rtt < 4)) /* avoid divide-by-zero */
return;
- delta = timeval_delta(now, &hctx->ccid3hctx_t_last_win_count);
- DCCP_BUG_ON(delta < 0);
-
- quarter_rtts = (u32)delta / (hctx->ccid3hctx_rtt / 4);
+ quarter_rtts = ktime_us_delta(now, hctx->ccid3hctx_t_last_win_count);
+ quarter_rtts /= hctx->ccid3hctx_rtt / 4;
if (quarter_rtts > 0) {
- hctx->ccid3hctx_t_last_win_count = *now;
+ hctx->ccid3hctx_t_last_win_count = now;
hctx->ccid3hctx_last_win_count += min_t(u32, quarter_rtts, 5);
hctx->ccid3hctx_last_win_count &= 0xF; /* mod 16 */
-
- ccid3_pr_debug("now at %#X\n", hctx->ccid3hctx_last_win_count);
}
}
@@ -312,8 +306,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
- struct timeval now;
- suseconds_t delay;
+ ktime_t now = ktime_get_real();
+ s64 delay;
BUG_ON(hctx == NULL);
@@ -325,8 +319,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
if (unlikely(skb->len == 0))
return -EBADMSG;
- dccp_timestamp(sk, &now);
-
switch (hctx->ccid3hctx_state) {
case TFRC_SSTATE_NO_SENT:
sk_reset_timer(sk, &hctx->ccid3hctx_no_feedback_timer,
@@ -349,7 +341,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
ccid3_pr_debug("SYN RTT = %uus\n", dp->dccps_syn_rtt);
hctx->ccid3hctx_rtt = dp->dccps_syn_rtt;
hctx->ccid3hctx_x = rfc3390_initial_rate(sk);
- hctx->ccid3hctx_t_ld = now;
+ hctx->ccid3hctx_t_ld = ktime_to_timeval(now);
} else {
/* Sender does not have RTT sample: X = MSS/second */
hctx->ccid3hctx_x = dp->dccps_mss_cache;
@@ -361,7 +353,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
break;
case TFRC_SSTATE_NO_FBACK:
case TFRC_SSTATE_FBACK:
- delay = timeval_delta(&hctx->ccid3hctx_t_nom, &now);
+ delay = ktime_us_delta(hctx->ccid3hctx_t_nom, now);
ccid3_pr_debug("delay=%ld\n", (long)delay);
/*
* Scheduling of packet transmissions [RFC 3448, 4.6]
@@ -371,10 +363,10 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
* else
* // send the packet in (t_nom - t_now) milliseconds.
*/
- if (delay - (suseconds_t)hctx->ccid3hctx_delta >= 0)
- return delay / 1000L;
+ if (delay - (s64)hctx->ccid3hctx_delta >= 1000)
+ return (u32)delay / 1000L;
- ccid3_hc_tx_update_win_count(hctx, &now);
+ ccid3_hc_tx_update_win_count(hctx, now);
break;
case TFRC_SSTATE_TERM:
DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
@@ -387,8 +379,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
hctx->ccid3hctx_idle = 0;
/* set the nominal send time for the next following packet */
- timeval_add_usecs(&hctx->ccid3hctx_t_nom, hctx->ccid3hctx_t_ipi);
-
+ hctx->ccid3hctx_t_nom = ktime_add_us(hctx->ccid3hctx_t_nom,
+ hctx->ccid3hctx_t_ipi);
return 0;
}
@@ -819,154 +811,6 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
return 0;
}
-/* calculate first loss interval
- *
- * returns estimated loss interval in usecs */
-
-static u32 ccid3_hc_rx_calc_first_li(struct sock *sk)
-{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
- struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
- u32 x_recv, p;
- suseconds_t rtt, delta;
- struct timeval tstamp = { 0, };
- int interval = 0;
- int win_count = 0;
- int step = 0;
- u64 fval;
-
- list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist,
- dccphrx_node) {
- if (dccp_rx_hist_entry_data_packet(entry)) {
- tail = entry;
-
- switch (step) {
- case 0:
- tstamp = entry->dccphrx_tstamp;
- win_count = entry->dccphrx_ccval;
- step = 1;
- break;
- case 1:
- interval = win_count - entry->dccphrx_ccval;
- if (interval < 0)
- interval += TFRC_WIN_COUNT_LIMIT;
- if (interval > 4)
- goto found;
- break;
- }
- }
- }
-
- if (unlikely(step == 0)) {
- DCCP_WARN("%s(%p), packet history has no data packets!\n",
- dccp_role(sk), sk);
- return ~0;
- }
-
- if (unlikely(interval == 0)) {
- DCCP_WARN("%s(%p), Could not find a win_count interval > 0."
- "Defaulting to 1\n", dccp_role(sk), sk);
- interval = 1;
- }
-found:
- if (!tail) {
- DCCP_CRIT("tail is null\n");
- return ~0;
- }
-
- delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp);
- DCCP_BUG_ON(delta < 0);
-
- rtt = delta * 4 / interval;
- ccid3_pr_debug("%s(%p), approximated RTT to %dus\n",
- dccp_role(sk), sk, (int)rtt);
-
- /*
- * Determine the length of the first loss interval via inverse lookup.
- * Assume that X_recv can be computed by the throughput equation
- * s
- * X_recv = --------
- * R * fval
- * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1].
- */
- if (rtt == 0) { /* would result in divide-by-zero */
- DCCP_WARN("RTT==0\n");
- return ~0;
- }
-
- dccp_timestamp(sk, &tstamp);
- delta = timeval_delta(&tstamp, &hcrx->ccid3hcrx_tstamp_last_feedback);
- DCCP_BUG_ON(delta <= 0);
-
- x_recv = scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
- if (x_recv == 0) { /* would also trigger divide-by-zero */
- DCCP_WARN("X_recv==0\n");
- if ((x_recv = hcrx->ccid3hcrx_x_recv) == 0) {
- DCCP_BUG("stored value of X_recv is zero");
- return ~0;
- }
- }
-
- fval = scaled_div(hcrx->ccid3hcrx_s, rtt);
- fval = scaled_div32(fval, x_recv);
- p = tfrc_calc_x_reverse_lookup(fval);
-
- ccid3_pr_debug("%s(%p), receive rate=%u bytes/s, implied "
- "loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
-
- if (p == 0)
- return ~0;
- else
- return 1000000 / p;
-}
-
-static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss)
-{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
- struct dccp_li_hist_entry *head;
- u64 seq_temp;
-
- if (list_empty(&hcrx->ccid3hcrx_li_hist)) {
- if (!dccp_li_hist_interval_new(ccid3_li_hist,
- &hcrx->ccid3hcrx_li_hist, seq_loss, win_loss))
- return;
-
- head = list_entry(hcrx->ccid3hcrx_li_hist.next,
- struct dccp_li_hist_entry, dccplih_node);
- head->dccplih_interval = ccid3_hc_rx_calc_first_li(sk);
- } else {
- struct dccp_li_hist_entry *entry;
- struct list_head *tail;
-
- head = list_entry(hcrx->ccid3hcrx_li_hist.next,
- struct dccp_li_hist_entry, dccplih_node);
- /* FIXME win count check removed as was wrong */
- /* should make this check with receive history */
- /* and compare there as per section 10.2 of RFC4342 */
-
- /* new loss event detected */
- /* calculate last interval length */
- seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss);
- entry = dccp_li_hist_entry_new(ccid3_li_hist, GFP_ATOMIC);
-
- if (entry == NULL) {
- DCCP_BUG("out of memory - can not allocate entry");
- return;
- }
-
- list_add(&entry->dccplih_node, &hcrx->ccid3hcrx_li_hist);
-
- tail = hcrx->ccid3hcrx_li_hist.prev;
- list_del(tail);
- kmem_cache_free(ccid3_li_hist->dccplih_slab, tail);
-
- /* Create the newest interval */
- entry->dccplih_seqno = seq_loss;
- entry->dccplih_interval = seq_temp;
- entry->dccplih_win_count = win_loss;
- }
-}
-
static int ccid3_hc_rx_detect_loss(struct sock *sk,
struct dccp_rx_hist_entry *packet)
{
@@ -992,8 +836,15 @@ static int ccid3_hc_rx_detect_loss(struct sock *sk,
while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno)
> TFRC_RECV_NUM_LATE_LOSS) {
loss = 1;
- ccid3_hc_rx_update_li(sk, hcrx->ccid3hcrx_seqno_nonloss,
- hcrx->ccid3hcrx_ccval_nonloss);
+ dccp_li_update_li(sk,
+ &hcrx->ccid3hcrx_li_hist,
+ &hcrx->ccid3hcrx_hist,
+ &hcrx->ccid3hcrx_tstamp_last_feedback,
+ hcrx->ccid3hcrx_s,
+ hcrx->ccid3hcrx_bytes_recv,
+ hcrx->ccid3hcrx_x_recv,
+ hcrx->ccid3hcrx_seqno_nonloss,
+ hcrx->ccid3hcrx_ccval_nonloss);
tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss;
dccp_inc_seqno(&tmp_seqno);
hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
@@ -1152,7 +1003,7 @@ static void ccid3_hc_rx_exit(struct sock *sk)
dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist);
/* Empty loss interval history */
- dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist);
+ dccp_li_hist_purge(&hcrx->ccid3hcrx_li_hist);
}
static void ccid3_hc_rx_get_info(struct sock *sk, struct tcp_info *info)
@@ -1236,19 +1087,12 @@ static __init int ccid3_module_init(void)
if (ccid3_tx_hist == NULL)
goto out_free_rx;
- ccid3_li_hist = dccp_li_hist_new("ccid3");
- if (ccid3_li_hist == NULL)
- goto out_free_tx;
-
rc = ccid_register(&ccid3);
if (rc != 0)
- goto out_free_loss_interval_history;
+ goto out_free_tx;
out:
return rc;
-out_free_loss_interval_history:
- dccp_li_hist_delete(ccid3_li_hist);
- ccid3_li_hist = NULL;
out_free_tx:
dccp_tx_hist_delete(ccid3_tx_hist);
ccid3_tx_hist = NULL;
@@ -1271,10 +1115,6 @@ static __exit void ccid3_module_exit(void)
dccp_rx_hist_delete(ccid3_rx_hist);
ccid3_rx_hist = NULL;
}
- if (ccid3_li_hist != NULL) {
- dccp_li_hist_delete(ccid3_li_hist);
- ccid3_li_hist = NULL;
- }
}
module_exit(ccid3_module_exit);
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index 8d31b389c19c..51d4b804e334 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -36,6 +36,7 @@
#ifndef _DCCP_CCID3_H_
#define _DCCP_CCID3_H_
+#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/time.h>
#include <linux/types.h>
@@ -108,10 +109,10 @@ struct ccid3_hc_tx_sock {
enum ccid3_hc_tx_states ccid3hctx_state:8;
u8 ccid3hctx_last_win_count;
u8 ccid3hctx_idle;
- struct timeval ccid3hctx_t_last_win_count;
+ ktime_t ccid3hctx_t_last_win_count;
struct timer_list ccid3hctx_no_feedback_timer;
struct timeval ccid3hctx_t_ld;
- struct timeval ccid3hctx_t_nom;
+ ktime_t ccid3hctx_t_nom;
u32 ccid3hctx_delta;
struct list_head ccid3hctx_hist;
struct ccid3_options_received ccid3hctx_options_received;
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
index 372d7e75cdd8..174d3f13d93f 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -1,8 +1,8 @@
/*
* net/dccp/ccids/lib/loss_interval.c
*
- * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
- * Copyright (c) 2005-6 Ian McDonald <ian.mcdonald@jandi.co.nz>
+ * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand.
+ * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz>
* Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program is free software; you can redistribute it and/or modify
@@ -15,58 +15,38 @@
#include <net/sock.h>
#include "../../dccp.h"
#include "loss_interval.h"
+#include "packet_history.h"
+#include "tfrc.h"
-struct dccp_li_hist *dccp_li_hist_new(const char *name)
-{
- struct dccp_li_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
- static const char dccp_li_hist_mask[] = "li_hist_%s";
- char *slab_name;
-
- if (hist == NULL)
- goto out;
-
- slab_name = kmalloc(strlen(name) + sizeof(dccp_li_hist_mask) - 1,
- GFP_ATOMIC);
- if (slab_name == NULL)
- goto out_free_hist;
-
- sprintf(slab_name, dccp_li_hist_mask, name);
- hist->dccplih_slab = kmem_cache_create(slab_name,
- sizeof(struct dccp_li_hist_entry),
- 0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
- if (hist->dccplih_slab == NULL)
- goto out_free_slab_name;
-out:
- return hist;
-out_free_slab_name:
- kfree(slab_name);
-out_free_hist:
- kfree(hist);
- hist = NULL;
- goto out;
-}
+#define DCCP_LI_HIST_IVAL_F_LENGTH 8
-EXPORT_SYMBOL_GPL(dccp_li_hist_new);
+struct dccp_li_hist_entry {
+ struct list_head dccplih_node;
+ u64 dccplih_seqno:48,
+ dccplih_win_count:4;
+ u32 dccplih_interval;
+};
-void dccp_li_hist_delete(struct dccp_li_hist *hist)
-{
- const char* name = kmem_cache_name(hist->dccplih_slab);
+static struct kmem_cache *dccp_li_cachep __read_mostly;
- kmem_cache_destroy(hist->dccplih_slab);
- kfree(name);
- kfree(hist);
+static inline struct dccp_li_hist_entry *dccp_li_hist_entry_new(const gfp_t prio)
+{
+ return kmem_cache_alloc(dccp_li_cachep, prio);
}
-EXPORT_SYMBOL_GPL(dccp_li_hist_delete);
+static inline void dccp_li_hist_entry_delete(struct dccp_li_hist_entry *entry)
+{
+ if (entry != NULL)
+ kmem_cache_free(dccp_li_cachep, entry);
+}
-void dccp_li_hist_purge(struct dccp_li_hist *hist, struct list_head *list)
+void dccp_li_hist_purge(struct list_head *list)
{
struct dccp_li_hist_entry *entry, *next;
list_for_each_entry_safe(entry, next, list, dccplih_node) {
list_del_init(&entry->dccplih_node);
- kmem_cache_free(hist->dccplih_slab, entry);
+ kmem_cache_free(dccp_li_cachep, entry);
}
}
@@ -118,16 +98,16 @@ u32 dccp_li_hist_calc_i_mean(struct list_head *list)
EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean);
-int dccp_li_hist_interval_new(struct dccp_li_hist *hist,
- struct list_head *list, const u64 seq_loss, const u8 win_loss)
+static int dccp_li_hist_interval_new(struct list_head *list,
+ const u64 seq_loss, const u8 win_loss)
{
struct dccp_li_hist_entry *entry;
int i;
for (i = 0; i < DCCP_LI_HIST_IVAL_F_LENGTH; i++) {
- entry = dccp_li_hist_entry_new(hist, GFP_ATOMIC);
+ entry = dccp_li_hist_entry_new(GFP_ATOMIC);
if (entry == NULL) {
- dccp_li_hist_purge(hist, list);
+ dccp_li_hist_purge(list);
DCCP_BUG("loss interval list entry is NULL");
return 0;
}
@@ -140,4 +120,176 @@ int dccp_li_hist_interval_new(struct dccp_li_hist *hist,
return 1;
}
-EXPORT_SYMBOL_GPL(dccp_li_hist_interval_new);
+/* calculate first loss interval
+ *
+ * returns estimated loss interval in usecs */
+static u32 dccp_li_calc_first_li(struct sock *sk,
+ struct list_head *hist_list,
+ struct timeval *last_feedback,
+ u16 s, u32 bytes_recv,
+ u32 previous_x_recv)
+{
+ struct dccp_rx_hist_entry *entry, *next, *tail = NULL;
+ u32 x_recv, p;
+ suseconds_t rtt, delta;
+ struct timeval tstamp = { 0, 0 };
+ int interval = 0;
+ int win_count = 0;
+ int step = 0;
+ u64 fval;
+
+ list_for_each_entry_safe(entry, next, hist_list, dccphrx_node) {
+ if (dccp_rx_hist_entry_data_packet(entry)) {
+ tail = entry;
+
+ switch (step) {
+ case 0:
+ tstamp = entry->dccphrx_tstamp;
+ win_count = entry->dccphrx_ccval;
+ step = 1;
+ break;
+ case 1:
+ interval = win_count - entry->dccphrx_ccval;
+ if (interval < 0)
+ interval += TFRC_WIN_COUNT_LIMIT;
+ if (interval > 4)
+ goto found;
+ break;
+ }
+ }
+ }
+
+ if (unlikely(step == 0)) {
+ DCCP_WARN("%s(%p), packet history has no data packets!\n",
+ dccp_role(sk), sk);
+ return ~0;
+ }
+
+ if (unlikely(interval == 0)) {
+ DCCP_WARN("%s(%p), Could not find a win_count interval > 0."
+ "Defaulting to 1\n", dccp_role(sk), sk);
+ interval = 1;
+ }
+found:
+ if (!tail) {
+ DCCP_CRIT("tail is null\n");
+ return ~0;
+ }
+
+ delta = timeval_delta(&tstamp, &tail->dccphrx_tstamp);
+ DCCP_BUG_ON(delta < 0);
+
+ rtt = delta * 4 / interval;
+ dccp_pr_debug("%s(%p), approximated RTT to %dus\n",
+ dccp_role(sk), sk, (int)rtt);
+
+ /*
+ * Determine the length of the first loss interval via inverse lookup.
+ * Assume that X_recv can be computed by the throughput equation
+ * s
+ * X_recv = --------
+ * R * fval
+ * Find some p such that f(p) = fval; return 1/p [RFC 3448, 6.3.1].
+ */
+ if (rtt == 0) { /* would result in divide-by-zero */
+ DCCP_WARN("RTT==0\n");
+ return ~0;
+ }
+
+ dccp_timestamp(sk, &tstamp);
+ delta = timeval_delta(&tstamp, last_feedback);
+ DCCP_BUG_ON(delta <= 0);
+
+ x_recv = scaled_div32(bytes_recv, delta);
+ if (x_recv == 0) { /* would also trigger divide-by-zero */
+ DCCP_WARN("X_recv==0\n");
+ if (previous_x_recv == 0) {
+ DCCP_BUG("stored value of X_recv is zero");
+ return ~0;
+ }
+ x_recv = previous_x_recv;
+ }
+
+ fval = scaled_div(s, rtt);
+ fval = scaled_div32(fval, x_recv);
+ p = tfrc_calc_x_reverse_lookup(fval);
+
+ dccp_pr_debug("%s(%p), receive rate=%u bytes/s, implied "
+ "loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
+
+ if (p == 0)
+ return ~0;
+ else
+ return 1000000 / p;
+}
+
+void dccp_li_update_li(struct sock *sk,
+ struct list_head *li_hist_list,
+ struct list_head *hist_list,
+ struct timeval *last_feedback, u16 s, u32 bytes_recv,
+ u32 previous_x_recv, u64 seq_loss, u8 win_loss)
+{
+ struct dccp_li_hist_entry *head;
+ u64 seq_temp;
+
+ if (list_empty(li_hist_list)) {
+ if (!dccp_li_hist_interval_new(li_hist_list, seq_loss,
+ win_loss))
+ return;
+
+ head = list_entry(li_hist_list->next, struct dccp_li_hist_entry,
+ dccplih_node);
+ head->dccplih_interval = dccp_li_calc_first_li(sk, hist_list,
+ last_feedback,
+ s, bytes_recv,
+ previous_x_recv);
+ } else {
+ struct dccp_li_hist_entry *entry;
+ struct list_head *tail;
+
+ head = list_entry(li_hist_list->next, struct dccp_li_hist_entry,
+ dccplih_node);
+ /* FIXME win count check removed as was wrong */
+ /* should make this check with receive history */
+ /* and compare there as per section 10.2 of RFC4342 */
+
+ /* new loss event detected */
+ /* calculate last interval length */
+ seq_temp = dccp_delta_seqno(head->dccplih_seqno, seq_loss);
+ entry = dccp_li_hist_entry_new(GFP_ATOMIC);
+
+ if (entry == NULL) {
+ DCCP_BUG("out of memory - can not allocate entry");
+ return;
+ }
+
+ list_add(&entry->dccplih_node, li_hist_list);
+
+ tail = li_hist_list->prev;
+ list_del(tail);
+ kmem_cache_free(dccp_li_cachep, tail);
+
+ /* Create the newest interval */
+ entry->dccplih_seqno = seq_loss;
+ entry->dccplih_interval = seq_temp;
+ entry->dccplih_win_count = win_loss;
+ }
+}
+
+EXPORT_SYMBOL_GPL(dccp_li_update_li);
+
+static __init int dccp_li_init(void)
+{
+ dccp_li_cachep = kmem_cache_create("dccp_li_hist",
+ sizeof(struct dccp_li_hist_entry),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ return dccp_li_cachep == NULL ? -ENOBUFS : 0;
+}
+
+static __exit void dccp_li_exit(void)
+{
+ kmem_cache_destroy(dccp_li_cachep);
+}
+
+module_init(dccp_li_init);
+module_exit(dccp_li_exit);
diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h
index eb257014dd74..906c806d6d9d 100644
--- a/net/dccp/ccids/lib/loss_interval.h
+++ b/net/dccp/ccids/lib/loss_interval.h
@@ -3,8 +3,8 @@
/*
* net/dccp/ccids/lib/loss_interval.h
*
- * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
- * Copyright (c) 2005 Ian McDonald <ian.mcdonald@jandi.co.nz>
+ * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand.
+ * Copyright (c) 2005-7 Ian McDonald <ian.mcdonald@jandi.co.nz>
* Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program is free software; you can redistribute it and/or modify it
@@ -14,44 +14,16 @@
*/
#include <linux/list.h>
-#include <linux/slab.h>
#include <linux/time.h>
-#define DCCP_LI_HIST_IVAL_F_LENGTH 8
-
-struct dccp_li_hist {
- struct kmem_cache *dccplih_slab;
-};
-
-extern struct dccp_li_hist *dccp_li_hist_new(const char *name);
-extern void dccp_li_hist_delete(struct dccp_li_hist *hist);
-
-struct dccp_li_hist_entry {
- struct list_head dccplih_node;
- u64 dccplih_seqno:48,
- dccplih_win_count:4;
- u32 dccplih_interval;
-};
-
-static inline struct dccp_li_hist_entry *
- dccp_li_hist_entry_new(struct dccp_li_hist *hist,
- const gfp_t prio)
-{
- return kmem_cache_alloc(hist->dccplih_slab, prio);
-}
-
-static inline void dccp_li_hist_entry_delete(struct dccp_li_hist *hist,
- struct dccp_li_hist_entry *entry)
-{
- if (entry != NULL)
- kmem_cache_free(hist->dccplih_slab, entry);
-}
-
-extern void dccp_li_hist_purge(struct dccp_li_hist *hist,
- struct list_head *list);
+extern void dccp_li_hist_purge(struct list_head *list);
extern u32 dccp_li_hist_calc_i_mean(struct list_head *list);
-extern int dccp_li_hist_interval_new(struct dccp_li_hist *hist,
- struct list_head *list, const u64 seq_loss, const u8 win_loss);
+extern void dccp_li_update_li(struct sock *sk,
+ struct list_head *li_hist_list,
+ struct list_head *hist_list,
+ struct timeval *last_feedback, u16 s,
+ u32 bytes_recv, u32 previous_x_recv,
+ u64 seq_loss, u8 win_loss);
#endif /* _DCCP_LI_HIST_ */
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c
index 2e8ef42721e2..34c4f6047724 100644
--- a/net/dccp/ccids/lib/packet_history.c
+++ b/net/dccp/ccids/lib/packet_history.c
@@ -59,7 +59,7 @@ struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
hist->dccptxh_slab = kmem_cache_create(slab_name,
sizeof(struct dccp_tx_hist_entry),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (hist->dccptxh_slab == NULL)
goto out_free_slab_name;
out:
@@ -148,7 +148,7 @@ struct dccp_rx_hist *dccp_rx_hist_new(const char *name)
hist->dccprxh_slab = kmem_cache_create(slab_name,
sizeof(struct dccp_rx_hist_entry),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (hist->dccprxh_slab == NULL)
goto out_free_slab_name;
out:
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index d8ad27bfe01a..e2d74cd7eeeb 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -184,7 +184,7 @@ DECLARE_SNMP_STAT(struct dccp_mib, dccp_statistics);
/*
* Checksumming routines
*/
-static inline int dccp_csum_coverage(const struct sk_buff *skb)
+static inline unsigned int dccp_csum_coverage(const struct sk_buff *skb)
{
const struct dccp_hdr* dh = dccp_hdr(skb);
@@ -195,7 +195,7 @@ static inline int dccp_csum_coverage(const struct sk_buff *skb)
static inline void dccp_csum_outgoing(struct sk_buff *skb)
{
- int cov = dccp_csum_coverage(skb);
+ unsigned int cov = dccp_csum_coverage(skb);
if (cov >= skb->len)
dccp_hdr(skb)->dccph_cscov = 0;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 31737cdf156a..b158c661867b 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -253,17 +253,6 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
if (dst == NULL) {
opt = np->opt;
- if (opt == NULL &&
- np->rxopt.bits.osrcrt == 2 &&
- ireq6->pktopts) {
- struct sk_buff *pktopts = ireq6->pktopts;
- struct inet6_skb_parm *rxopt = IP6CB(pktopts);
-
- if (rxopt->srcrt)
- opt = ipv6_invert_rthdr(sk,
- (struct ipv6_rt_hdr *)(skb_network_header(pktopts) +
- rxopt->srcrt));
- }
if (opt != NULL && opt->srcrt != NULL) {
const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
@@ -570,15 +559,6 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
if (sk_acceptq_is_full(sk))
goto out_overflow;
- if (np->rxopt.bits.osrcrt == 2 && opt == NULL && ireq6->pktopts) {
- const struct inet6_skb_parm *rxopt = IP6CB(ireq6->pktopts);
-
- if (rxopt->srcrt)
- opt = ipv6_invert_rthdr(sk,
- (struct ipv6_rt_hdr *)(skb_network_header(ireq6->pktopts) +
- rxopt->srcrt));
- }
-
if (dst == NULL) {
struct in6_addr *final_p = NULL, final;
struct flowi fl;
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 43a3adb027e7..bae10b0f2fc3 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -112,7 +112,7 @@ static struct jprobe dccp_send_probe = {
.kp = {
.symbol_name = "dccp_sendmsg",
},
- .entry = JPROBE_ENTRY(jdccp_sendmsg),
+ .entry = jdccp_sendmsg,
};
static int dccpprobe_open(struct inode *inode, struct file *file)
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 6607b7b14f34..04b59ec4f512 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -1003,7 +1003,7 @@ static int __init dccp_init(void)
dccp_hashinfo.bind_bucket_cachep =
kmem_cache_create("dccp_bind_bucket",
sizeof(struct inet_bind_bucket), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!dccp_hashinfo.bind_bucket_cachep)
goto out;
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index bfa910b6ad25..ed76d4aab4a9 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -2304,7 +2304,7 @@ static int dn_socket_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations dn_socket_seq_ops = {
+static const struct seq_operations dn_socket_seq_ops = {
.start = dn_socket_seq_start,
.next = dn_socket_seq_next,
.stop = dn_socket_seq_stop,
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index ab41c1879fd4..fa6604fcf0e7 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -461,7 +461,6 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {
dn_dn2eth(mac_addr, ifa->ifa_local);
dev_mc_add(dev, mac_addr, ETH_ALEN, 0);
- dev_mc_upload(dev);
}
}
@@ -1064,8 +1063,6 @@ static int dn_eth_up(struct net_device *dev)
else
dev_mc_add(dev, dn_rt_all_rt_mcast, ETH_ALEN, 0);
- dev_mc_upload(dev);
-
dn_db->use_long = 1;
return 0;
@@ -1419,7 +1416,7 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations dn_dev_seq_ops = {
+static const struct seq_operations dn_dev_seq_ops = {
.start = dn_dev_seq_start,
.next = dn_dev_seq_next,
.stop = dn_dev_seq_stop,
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index 4bf066c416e2..174d8a7a6dac 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -569,7 +569,7 @@ static void *dn_neigh_seq_start(struct seq_file *seq, loff_t *pos)
NEIGH_SEQ_NEIGH_ONLY);
}
-static struct seq_operations dn_neigh_seq_ops = {
+static const struct seq_operations dn_neigh_seq_ops = {
.start = dn_neigh_seq_start,
.next = neigh_seq_next,
.stop = neigh_seq_stop,
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index a8bf106b7a61..f2a61ef2af9c 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1726,7 +1726,7 @@ static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations dn_rt_cache_seq_ops = {
+static const struct seq_operations dn_rt_cache_seq_ops = {
.start = dn_rt_cache_seq_start,
.next = dn_rt_cache_seq_next,
.stop = dn_rt_cache_seq_stop,
@@ -1770,7 +1770,7 @@ void __init dn_route_init(void)
dn_dst_ops.kmem_cachep =
kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
init_timer(&dn_route_timer);
dn_route_timer.function = dn_dst_check_expire;
dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ;
diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c
index d6615c9361e9..fda0772fa215 100644
--- a/net/decnet/dn_table.c
+++ b/net/decnet/dn_table.c
@@ -881,7 +881,7 @@ void __init dn_fib_table_init(void)
dn_hash_kmem = kmem_cache_create("dn_fib_info_cache",
sizeof(struct dn_fib_info),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
}
void __exit dn_fib_table_cleanup(void)
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 0ac2524f3b68..12c765715acf 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -266,8 +266,11 @@ void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev,
static int eth_mac_addr(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
+
if (netif_running(dev))
return -EBUSY;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
return 0;
}
@@ -316,9 +319,10 @@ void ether_setup(struct net_device *dev)
EXPORT_SYMBOL(ether_setup);
/**
- * alloc_etherdev - Allocates and sets up an Ethernet device
+ * alloc_etherdev_mq - Allocates and sets up an Ethernet device
* @sizeof_priv: Size of additional driver-private structure to be allocated
* for this Ethernet device
+ * @queue_count: The number of queues this device has.
*
* Fill in the fields of the device structure with Ethernet-generic
* values. Basically does everything except registering the device.
@@ -328,8 +332,8 @@ EXPORT_SYMBOL(ether_setup);
* this private data area.
*/
-struct net_device *alloc_etherdev(int sizeof_priv)
+struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count)
{
- return alloc_netdev(sizeof_priv, "eth%d", ether_setup);
+ return alloc_netdev_mq(sizeof_priv, "eth%d", ether_setup, queue_count);
}
-EXPORT_SYMBOL(alloc_etherdev);
+EXPORT_SYMBOL(alloc_etherdev_mq);
diff --git a/net/ieee80211/ieee80211_wx.c b/net/ieee80211/ieee80211_wx.c
index 523a137d49dd..465b73d50532 100644
--- a/net/ieee80211/ieee80211_wx.c
+++ b/net/ieee80211/ieee80211_wx.c
@@ -90,14 +90,11 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
}
/* Add channel and frequency */
+ /* Note : userspace automatically computes channel using iwrange */
iwe.cmd = SIOCGIWFREQ;
- iwe.u.freq.m = network->channel;
- iwe.u.freq.e = 0;
- iwe.u.freq.i = 0;
- start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
-
iwe.u.freq.m = ieee80211_channel_to_freq(ieee, network->channel);
iwe.u.freq.e = 6;
+ iwe.u.freq.i = 0;
start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
/* Add encryption capability */
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index cc8110bdd579..afb6c6698b27 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -271,8 +271,11 @@ ieee80211softmac_assoc_work(struct work_struct *work)
*/
dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n");
ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
- if (ieee80211softmac_start_scan(mac))
+ if (ieee80211softmac_start_scan(mac)) {
dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
+ mac->associnfo.associating = 0;
+ mac->associnfo.associated = 0;
+ }
goto out;
} else {
mac->associnfo.associating = 0;
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 010fbb2d45e9..fb7909774254 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -116,48 +116,6 @@ config IP_ROUTE_MULTIPATH
equal "cost" and chooses one of them in a non-deterministic fashion
if a matching packet arrives.
-config IP_ROUTE_MULTIPATH_CACHED
- bool "IP: equal cost multipath with caching support (EXPERIMENTAL)"
- depends on IP_ROUTE_MULTIPATH
- help
- Normally, equal cost multipath routing is not supported by the
- routing cache. If you say Y here, alternative routes are cached
- and on cache lookup a route is chosen in a configurable fashion.
-
- If unsure, say N.
-
-config IP_ROUTE_MULTIPATH_RR
- tristate "MULTIPATH: round robin algorithm"
- depends on IP_ROUTE_MULTIPATH_CACHED
- help
- Multipath routes are chosen according to Round Robin
-
-config IP_ROUTE_MULTIPATH_RANDOM
- tristate "MULTIPATH: random algorithm"
- depends on IP_ROUTE_MULTIPATH_CACHED
- help
- Multipath routes are chosen in a random fashion. Actually,
- there is no weight for a route. The advantage of this policy
- is that it is implemented stateless and therefore introduces only
- a very small delay.
-
-config IP_ROUTE_MULTIPATH_WRANDOM
- tristate "MULTIPATH: weighted random algorithm"
- depends on IP_ROUTE_MULTIPATH_CACHED
- help
- Multipath routes are chosen in a weighted random fashion.
- The per route weights are the weights visible via ip route 2. As the
- corresponding state management introduces some overhead routing delay
- is increased.
-
-config IP_ROUTE_MULTIPATH_DRR
- tristate "MULTIPATH: interface round robin algorithm"
- depends on IP_ROUTE_MULTIPATH_CACHED
- help
- Connections are distributed in a round robin fashion over the
- available interfaces. This policy makes sense if the connections
- should be primarily distributed on interfaces and not on routes.
-
config IP_ROUTE_VERBOSE
bool "IP: verbose route monitoring"
depends on IP_ADVANCED_ROUTER
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 4ff6c151d7f3..fbf1674e0c2a 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -29,14 +29,9 @@ obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
obj-$(CONFIG_IP_PNP) += ipconfig.o
-obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
-obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o
-obj-$(CONFIG_IP_ROUTE_MULTIPATH_WRANDOM) += multipath_wrandom.o
-obj-$(CONFIG_IP_ROUTE_MULTIPATH_DRR) += multipath_drr.o
obj-$(CONFIG_NETFILTER) += netfilter.o netfilter/
obj-$(CONFIG_IP_VS) += ipvs/
obj-$(CONFIG_INET_DIAG) += inet_diag.o
-obj-$(CONFIG_IP_ROUTE_MULTIPATH_CACHED) += multipath.o
obj-$(CONFIG_INET_TCP_DIAG) += tcp_diag.o
obj-$(CONFIG_NET_TCPPROBE) += tcp_probe.o
obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 041fba3fa0aa..06c08e5740fb 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1170,6 +1170,9 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
int ihl;
int id;
+ if (!(features & NETIF_F_V4_CSUM))
+ features &= ~NETIF_F_SG;
+
if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_TCPV4 |
SKB_GSO_UDP |
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 6da8ff597ad3..7a23e59c374a 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -339,3 +339,4 @@ static void __exit ah4_fini(void)
module_init(ah4_init);
module_exit(ah4_fini);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_AH);
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index e00767e8ebd9..9ab9d534fbac 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -885,7 +885,7 @@ static int arp_process(struct sk_buff *skb)
if (n == NULL &&
arp->ar_op == htons(ARPOP_REPLY) &&
inet_addr_type(sip) == RTN_UNICAST)
- n = __neigh_lookup(&arp_tbl, &sip, dev, -1);
+ n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
}
if (n) {
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 47c95e8ef045..98767a4f1185 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -481,3 +481,4 @@ static void __exit esp4_fini(void)
module_init(esp4_init);
module_exit(esp4_fini);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 311d633f7f39..eff6bce453ee 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -453,7 +453,6 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {
[RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) },
[RTA_PROTOINFO] = { .type = NLA_U32 },
[RTA_FLOW] = { .type = NLA_U32 },
- [RTA_MP_ALGO] = { .type = NLA_U32 },
};
static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -515,9 +514,6 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
case RTA_FLOW:
cfg->fc_flow = nla_get_u32(attr);
break;
- case RTA_MP_ALGO:
- cfg->fc_mp_alg = nla_get_u32(attr);
- break;
case RTA_TABLE:
cfg->fc_table = nla_get_u32(attr);
break;
@@ -821,7 +817,7 @@ static void nl_fib_input(struct sock *sk, int len)
static void nl_fib_lookup_init(void)
{
netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, NULL,
- THIS_MODULE);
+ THIS_MODULE);
}
static void fib_disable_ip(struct net_device *dev, int force)
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 07e843a47dde..9ad1d9ff9ce7 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -771,13 +771,13 @@ struct fib_table * __init fib_hash_init(u32 id)
fn_hash_kmem = kmem_cache_create("ip_fib_hash",
sizeof(struct fib_node),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (fn_alias_kmem == NULL)
fn_alias_kmem = kmem_cache_create("ip_fib_alias",
sizeof(struct fib_alias),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash),
GFP_KERNEL);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index bb94550d95c3..c434119deb52 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -42,7 +42,6 @@
#include <net/tcp.h>
#include <net/sock.h>
#include <net/ip_fib.h>
-#include <net/ip_mp_alg.h>
#include <net/netlink.h>
#include <net/nexthop.h>
@@ -697,13 +696,6 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
goto err_inval;
}
#endif
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- if (cfg->fc_mp_alg) {
- if (cfg->fc_mp_alg < IP_MP_ALG_NONE ||
- cfg->fc_mp_alg > IP_MP_ALG_MAX)
- goto err_inval;
- }
-#endif
err = -ENOBUFS;
if (fib_info_cnt >= fib_hash_size) {
@@ -791,10 +783,6 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
#endif
}
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- fi->fib_mp_alg = cfg->fc_mp_alg;
-#endif
-
if (fib_props[cfg->fc_type].error) {
if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp)
goto err_inval;
@@ -940,10 +928,6 @@ out_fill_res:
res->type = fa->fa_type;
res->scope = fa->fa_scope;
res->fi = fa->fa_info;
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- res->netmask = mask;
- res->network = zone & inet_make_mask(prefixlen);
-#endif
atomic_inc(&res->fi->fib_clntref);
return 0;
}
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 30e332ade61b..9ca786a6fd3c 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1970,7 +1970,7 @@ struct fib_table * __init fib_hash_init(u32 id)
fn_alias_kmem = kmem_cache_create("ip_fib_alias",
sizeof(struct fib_alias),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
tb = kmalloc(sizeof(struct fib_table) + sizeof(struct trie),
GFP_KERNEL);
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index a73cf93cee36..2586df09b9b6 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -14,7 +14,8 @@
#include <net/ip.h>
/* Must be called with locally disabled BHs. */
-void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo)
+static void __inet_twsk_kill(struct inet_timewait_sock *tw,
+ struct inet_hashinfo *hashinfo)
{
struct inet_bind_hashbucket *bhead;
struct inet_bind_bucket *tb;
@@ -47,8 +48,6 @@ void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashi
inet_twsk_put(tw);
}
-EXPORT_SYMBOL_GPL(__inet_twsk_kill);
-
/*
* Enter the time wait state. This is called with locally disabled BH.
* Essentially we whip up a timewait bucket, copy the relevant info into it
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 2f44e6128068..771031dfbd0f 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -123,7 +123,7 @@ void __init inet_initpeers(void)
peer_cachep = kmem_cache_create("inet_peer_cache",
sizeof(struct inet_peer),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
/* All the timers, started at system startup tend
to synchronize. Perturb it a bit.
@@ -158,7 +158,7 @@ static void unlink_from_unused(struct inet_peer *p)
#define lookup(_daddr,_stack) \
({ \
struct inet_peer *u, **v; \
- if (_stack) { \
+ if (_stack != NULL) { \
stackptr = _stack; \
*stackptr++ = &peer_root; \
} \
@@ -169,7 +169,7 @@ static void unlink_from_unused(struct inet_peer *p)
v = &u->avl_left; \
else \
v = &u->avl_right; \
- if (_stack) \
+ if (_stack != NULL) \
*stackptr++ = v; \
u = *v; \
} \
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 9cb04df0054b..8c95cf09f87a 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -86,7 +86,7 @@ int ip_forward(struct sk_buff *skb)
goto sr_failed;
if (unlikely(skb->len > dst_mtu(&rt->u.dst) &&
- (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
+ (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
IP_INC_STATS(IPSTATS_MIB_FRAGFAILS);
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
htonl(dst_mtu(&rt->u.dst)));
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 63282934725e..5c14ed63e56c 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -809,7 +809,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen;
- if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+ if (skb_headroom(skb) < max_headroom || skb_shared(skb)||
+ (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 34ea4547ebbe..c9e2b5e6305e 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -399,6 +399,10 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index;
#endif
nf_copy(to, from);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ to->nf_trace = from->nf_trace;
+#endif
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
to->ipvs_property = from->ipvs_property;
#endif
@@ -837,7 +841,7 @@ int ip_append_data(struct sock *sk,
*/
if (transhdrlen &&
length + fragheaderlen <= mtu &&
- rt->u.dst.dev->features & NETIF_F_ALL_CSUM &&
+ rt->u.dst.dev->features & NETIF_F_V4_CSUM &&
!exthdrlen)
csummode = CHECKSUM_PARTIAL;
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index ab86137c71d2..e787044a8514 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -485,3 +485,4 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3173");
MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
+MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_COMP);
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index ebd2f2d532f6..396437242a1b 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -595,7 +595,8 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
*/
max_headroom = (LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr));
- if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+ if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
+ (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index d96582acdf69..7003cc1b7fe2 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1917,7 +1917,7 @@ void __init ip_mr_init(void)
mrt_cachep = kmem_cache_create("ip_mrt_cache",
sizeof(struct mfc_cache),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
init_timer(&ipmr_expire_timer);
ipmr_expire_timer.function=ipmr_expire_process;
register_netdevice_notifier(&ip_mr_notifier);
diff --git a/net/ipv4/ipvs/ip_vs_app.c b/net/ipv4/ipvs/ip_vs_app.c
index 15ad5dd2d984..8d6901d4e94f 100644
--- a/net/ipv4/ipvs/ip_vs_app.c
+++ b/net/ipv4/ipvs/ip_vs_app.c
@@ -549,7 +549,7 @@ static int ip_vs_app_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ip_vs_app_seq_ops = {
+static const struct seq_operations ip_vs_app_seq_ops = {
.start = ip_vs_app_seq_start,
.next = ip_vs_app_seq_next,
.stop = ip_vs_app_seq_stop,
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 7018f97c75dc..d612a6a5d957 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -745,7 +745,7 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ip_vs_conn_seq_ops = {
+static const struct seq_operations ip_vs_conn_seq_ops = {
.start = ip_vs_conn_seq_start,
.next = ip_vs_conn_seq_next,
.stop = ip_vs_conn_seq_stop,
@@ -901,7 +901,7 @@ int ip_vs_conn_init(void)
/* Allocate ip_vs_conn slab cache */
ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn",
sizeof(struct ip_vs_conn), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!ip_vs_conn_cachep) {
vfree(ip_vs_conn_tab);
return -ENOMEM;
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 68fe1d4d0210..e1052bcf4ed1 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -1783,7 +1783,7 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ip_vs_info_seq_ops = {
+static const struct seq_operations ip_vs_info_seq_ops = {
.start = ip_vs_info_seq_start,
.next = ip_vs_info_seq_next,
.stop = ip_vs_info_seq_stop,
diff --git a/net/ipv4/multipath.c b/net/ipv4/multipath.c
deleted file mode 100644
index 4e9ca7c76407..000000000000
--- a/net/ipv4/multipath.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/* multipath.c: IPV4 multipath algorithm support.
- *
- * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
- * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-
-#include <net/ip_mp_alg.h>
-
-static DEFINE_SPINLOCK(alg_table_lock);
-struct ip_mp_alg_ops *ip_mp_alg_table[IP_MP_ALG_MAX + 1];
-
-int multipath_alg_register(struct ip_mp_alg_ops *ops, enum ip_mp_alg n)
-{
- struct ip_mp_alg_ops **slot;
- int err;
-
- if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX ||
- !ops->mp_alg_select_route)
- return -EINVAL;
-
- spin_lock(&alg_table_lock);
- slot = &ip_mp_alg_table[n];
- if (*slot != NULL) {
- err = -EBUSY;
- } else {
- *slot = ops;
- err = 0;
- }
- spin_unlock(&alg_table_lock);
-
- return err;
-}
-EXPORT_SYMBOL(multipath_alg_register);
-
-void multipath_alg_unregister(struct ip_mp_alg_ops *ops, enum ip_mp_alg n)
-{
- struct ip_mp_alg_ops **slot;
-
- if (n < IP_MP_ALG_NONE || n > IP_MP_ALG_MAX)
- return;
-
- spin_lock(&alg_table_lock);
- slot = &ip_mp_alg_table[n];
- if (*slot == ops)
- *slot = NULL;
- spin_unlock(&alg_table_lock);
-
- synchronize_net();
-}
-EXPORT_SYMBOL(multipath_alg_unregister);
diff --git a/net/ipv4/multipath_drr.c b/net/ipv4/multipath_drr.c
deleted file mode 100644
index b03c5ca2c823..000000000000
--- a/net/ipv4/multipath_drr.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Device round robin policy for multipath.
- *
- *
- * Version: $Id: multipath_drr.c,v 1.1.2.1 2004/09/16 07:42:34 elueck Exp $
- *
- * Authors: Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.de>
- *
- * 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 <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/igmp.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/mroute.h>
-#include <linux/init.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/icmp.h>
-#include <net/udp.h>
-#include <net/raw.h>
-#include <linux/notifier.h>
-#include <linux/if_arp.h>
-#include <linux/netfilter_ipv4.h>
-#include <net/ipip.h>
-#include <net/checksum.h>
-#include <net/ip_mp_alg.h>
-
-struct multipath_device {
- int ifi; /* interface index of device */
- atomic_t usecount;
- int allocated;
-};
-
-#define MULTIPATH_MAX_DEVICECANDIDATES 10
-
-static struct multipath_device state[MULTIPATH_MAX_DEVICECANDIDATES];
-static DEFINE_SPINLOCK(state_lock);
-
-static int inline __multipath_findslot(void)
-{
- int i;
-
- for (i = 0; i < MULTIPATH_MAX_DEVICECANDIDATES; i++) {
- if (state[i].allocated == 0)
- return i;
- }
- return -1;
-}
-
-static int inline __multipath_finddev(int ifindex)
-{
- int i;
-
- for (i = 0; i < MULTIPATH_MAX_DEVICECANDIDATES; i++) {
- if (state[i].allocated != 0 &&
- state[i].ifi == ifindex)
- return i;
- }
- return -1;
-}
-
-static int drr_dev_event(struct notifier_block *this,
- unsigned long event, void *ptr)
-{
- struct net_device *dev = ptr;
- int devidx;
-
- switch (event) {
- case NETDEV_UNREGISTER:
- case NETDEV_DOWN:
- spin_lock_bh(&state_lock);
-
- devidx = __multipath_finddev(dev->ifindex);
- if (devidx != -1) {
- state[devidx].allocated = 0;
- state[devidx].ifi = 0;
- atomic_set(&state[devidx].usecount, 0);
- }
-
- spin_unlock_bh(&state_lock);
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block drr_dev_notifier = {
- .notifier_call = drr_dev_event,
-};
-
-
-static void drr_safe_inc(atomic_t *usecount)
-{
- int n;
-
- atomic_inc(usecount);
-
- n = atomic_read(usecount);
- if (n <= 0) {
- int i;
-
- spin_lock_bh(&state_lock);
-
- for (i = 0; i < MULTIPATH_MAX_DEVICECANDIDATES; i++)
- atomic_set(&state[i].usecount, 0);
-
- spin_unlock_bh(&state_lock);
- }
-}
-
-static void drr_select_route(const struct flowi *flp,
- struct rtable *first, struct rtable **rp)
-{
- struct rtable *nh, *result, *cur_min;
- int min_usecount = -1;
- int devidx = -1;
- int cur_min_devidx = -1;
-
- /* 1. make sure all alt. nexthops have the same GC related data */
- /* 2. determine the new candidate to be returned */
- result = NULL;
- cur_min = NULL;
- for (nh = rcu_dereference(first); nh;
- nh = rcu_dereference(nh->u.dst.rt_next)) {
- if ((nh->u.dst.flags & DST_BALANCED) != 0 &&
- multipath_comparekeys(&nh->fl, flp)) {
- int nh_ifidx = nh->u.dst.dev->ifindex;
-
- nh->u.dst.lastuse = jiffies;
- nh->u.dst.__use++;
- if (result != NULL)
- continue;
-
- /* search for the output interface */
-
- /* this is not SMP safe, only add/remove are
- * SMP safe as wrong usecount updates have no big
- * impact
- */
- devidx = __multipath_finddev(nh_ifidx);
- if (devidx == -1) {
- /* add the interface to the array
- * SMP safe
- */
- spin_lock_bh(&state_lock);
-
- /* due to SMP: search again */
- devidx = __multipath_finddev(nh_ifidx);
- if (devidx == -1) {
- /* add entry for device */
- devidx = __multipath_findslot();
- if (devidx == -1) {
- /* unlikely but possible */
- continue;
- }
-
- state[devidx].allocated = 1;
- state[devidx].ifi = nh_ifidx;
- atomic_set(&state[devidx].usecount, 0);
- min_usecount = 0;
- }
-
- spin_unlock_bh(&state_lock);
- }
-
- if (min_usecount == 0) {
- /* if the device has not been used it is
- * the primary target
- */
- drr_safe_inc(&state[devidx].usecount);
- result = nh;
- } else {
- int count =
- atomic_read(&state[devidx].usecount);
-
- if (min_usecount == -1 ||
- count < min_usecount) {
- cur_min = nh;
- cur_min_devidx = devidx;
- min_usecount = count;
- }
- }
- }
- }
-
- if (!result) {
- if (cur_min) {
- drr_safe_inc(&state[cur_min_devidx].usecount);
- result = cur_min;
- } else {
- result = first;
- }
- }
-
- *rp = result;
-}
-
-static struct ip_mp_alg_ops drr_ops = {
- .mp_alg_select_route = drr_select_route,
-};
-
-static int __init drr_init(void)
-{
- int err = register_netdevice_notifier(&drr_dev_notifier);
-
- if (err)
- return err;
-
- err = multipath_alg_register(&drr_ops, IP_MP_ALG_DRR);
- if (err)
- goto fail;
-
- return 0;
-
-fail:
- unregister_netdevice_notifier(&drr_dev_notifier);
- return err;
-}
-
-static void __exit drr_exit(void)
-{
- unregister_netdevice_notifier(&drr_dev_notifier);
- multipath_alg_unregister(&drr_ops, IP_MP_ALG_DRR);
-}
-
-module_init(drr_init);
-module_exit(drr_exit);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/multipath_random.c b/net/ipv4/multipath_random.c
deleted file mode 100644
index c312785d14d0..000000000000
--- a/net/ipv4/multipath_random.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Random policy for multipath.
- *
- *
- * Version: $Id: multipath_random.c,v 1.1.2.3 2004/09/21 08:42:11 elueck Exp $
- *
- * Authors: Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.de>
- *
- * 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 <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/igmp.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/mroute.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/icmp.h>
-#include <net/udp.h>
-#include <net/raw.h>
-#include <linux/notifier.h>
-#include <linux/if_arp.h>
-#include <linux/netfilter_ipv4.h>
-#include <net/ipip.h>
-#include <net/checksum.h>
-#include <net/ip_mp_alg.h>
-
-#define MULTIPATH_MAX_CANDIDATES 40
-
-static void random_select_route(const struct flowi *flp,
- struct rtable *first,
- struct rtable **rp)
-{
- struct rtable *rt;
- struct rtable *decision;
- unsigned char candidate_count = 0;
-
- /* count all candidate */
- for (rt = rcu_dereference(first); rt;
- rt = rcu_dereference(rt->u.dst.rt_next)) {
- if ((rt->u.dst.flags & DST_BALANCED) != 0 &&
- multipath_comparekeys(&rt->fl, flp))
- ++candidate_count;
- }
-
- /* choose a random candidate */
- decision = first;
- if (candidate_count > 1) {
- unsigned char i = 0;
- unsigned char candidate_no = (unsigned char)
- (random32() % candidate_count);
-
- /* find chosen candidate and adjust GC data for all candidates
- * to ensure they stay in cache
- */
- for (rt = first; rt; rt = rt->u.dst.rt_next) {
- if ((rt->u.dst.flags & DST_BALANCED) != 0 &&
- multipath_comparekeys(&rt->fl, flp)) {
- rt->u.dst.lastuse = jiffies;
-
- if (i == candidate_no)
- decision = rt;
-
- if (i >= candidate_count)
- break;
-
- i++;
- }
- }
- }
-
- decision->u.dst.__use++;
- *rp = decision;
-}
-
-static struct ip_mp_alg_ops random_ops = {
- .mp_alg_select_route = random_select_route,
-};
-
-static int __init random_init(void)
-{
- return multipath_alg_register(&random_ops, IP_MP_ALG_RANDOM);
-}
-
-static void __exit random_exit(void)
-{
- multipath_alg_unregister(&random_ops, IP_MP_ALG_RANDOM);
-}
-
-module_init(random_init);
-module_exit(random_exit);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/multipath_rr.c b/net/ipv4/multipath_rr.c
deleted file mode 100644
index 0ad22524f450..000000000000
--- a/net/ipv4/multipath_rr.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Round robin policy for multipath.
- *
- *
- * Version: $Id: multipath_rr.c,v 1.1.2.2 2004/09/16 07:42:34 elueck Exp $
- *
- * Authors: Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.de>
- *
- * 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 <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/igmp.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/mroute.h>
-#include <linux/init.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/icmp.h>
-#include <net/udp.h>
-#include <net/raw.h>
-#include <linux/notifier.h>
-#include <linux/if_arp.h>
-#include <linux/netfilter_ipv4.h>
-#include <net/ipip.h>
-#include <net/checksum.h>
-#include <net/ip_mp_alg.h>
-
-static void rr_select_route(const struct flowi *flp,
- struct rtable *first, struct rtable **rp)
-{
- struct rtable *nh, *result, *min_use_cand = NULL;
- int min_use = -1;
-
- /* 1. make sure all alt. nexthops have the same GC related data
- * 2. determine the new candidate to be returned
- */
- result = NULL;
- for (nh = rcu_dereference(first); nh;
- nh = rcu_dereference(nh->u.dst.rt_next)) {
- if ((nh->u.dst.flags & DST_BALANCED) != 0 &&
- multipath_comparekeys(&nh->fl, flp)) {
- nh->u.dst.lastuse = jiffies;
-
- if (min_use == -1 || nh->u.dst.__use < min_use) {
- min_use = nh->u.dst.__use;
- min_use_cand = nh;
- }
- }
- }
- result = min_use_cand;
- if (!result)
- result = first;
-
- result->u.dst.__use++;
- *rp = result;
-}
-
-static struct ip_mp_alg_ops rr_ops = {
- .mp_alg_select_route = rr_select_route,
-};
-
-static int __init rr_init(void)
-{
- return multipath_alg_register(&rr_ops, IP_MP_ALG_RR);
-}
-
-static void __exit rr_exit(void)
-{
- multipath_alg_unregister(&rr_ops, IP_MP_ALG_RR);
-}
-
-module_init(rr_init);
-module_exit(rr_exit);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c
deleted file mode 100644
index 57c503694539..000000000000
--- a/net/ipv4/multipath_wrandom.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Weighted random policy for multipath.
- *
- *
- * Version: $Id: multipath_wrandom.c,v 1.1.2.3 2004/09/22 07:51:40 elueck Exp $
- *
- * Authors: Einar Lueck <elueck@de.ibm.com><lkml@einar-lueck.de>
- *
- * 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 <asm/system.h>
-#include <asm/uaccess.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/igmp.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/module.h>
-#include <linux/mroute.h>
-#include <linux/init.h>
-#include <linux/random.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <linux/skbuff.h>
-#include <net/sock.h>
-#include <net/icmp.h>
-#include <net/udp.h>
-#include <net/raw.h>
-#include <linux/notifier.h>
-#include <linux/if_arp.h>
-#include <linux/netfilter_ipv4.h>
-#include <net/ipip.h>
-#include <net/checksum.h>
-#include <net/ip_fib.h>
-#include <net/ip_mp_alg.h>
-
-#define MULTIPATH_STATE_SIZE 15
-
-struct multipath_candidate {
- struct multipath_candidate *next;
- int power;
- struct rtable *rt;
-};
-
-struct multipath_dest {
- struct list_head list;
-
- const struct fib_nh *nh_info;
- __be32 netmask;
- __be32 network;
- unsigned char prefixlen;
-
- struct rcu_head rcu;
-};
-
-struct multipath_bucket {
- struct list_head head;
- spinlock_t lock;
-};
-
-struct multipath_route {
- struct list_head list;
-
- int oif;
- __be32 gw;
- struct list_head dests;
-
- struct rcu_head rcu;
-};
-
-/* state: primarily weight per route information */
-static struct multipath_bucket state[MULTIPATH_STATE_SIZE];
-
-static unsigned char __multipath_lookup_weight(const struct flowi *fl,
- const struct rtable *rt)
-{
- const int state_idx = rt->idev->dev->ifindex % MULTIPATH_STATE_SIZE;
- struct multipath_route *r;
- struct multipath_route *target_route = NULL;
- struct multipath_dest *d;
- int weight = 1;
-
- /* lookup the weight information for a certain route */
- rcu_read_lock();
-
- /* find state entry for gateway or add one if necessary */
- list_for_each_entry_rcu(r, &state[state_idx].head, list) {
- if (r->gw == rt->rt_gateway &&
- r->oif == rt->idev->dev->ifindex) {
- target_route = r;
- break;
- }
- }
-
- if (!target_route) {
- /* this should not happen... but we are prepared */
- printk( KERN_CRIT"%s: missing state for gateway: %u and " \
- "device %d\n", __FUNCTION__, rt->rt_gateway,
- rt->idev->dev->ifindex);
- goto out;
- }
-
- /* find state entry for destination */
- list_for_each_entry_rcu(d, &target_route->dests, list) {
- __be32 targetnetwork = fl->fl4_dst &
- inet_make_mask(d->prefixlen);
-
- if ((targetnetwork & d->netmask) == d->network) {
- weight = d->nh_info->nh_weight;
- goto out;
- }
- }
-
-out:
- rcu_read_unlock();
- return weight;
-}
-
-static void wrandom_init_state(void)
-{
- int i;
-
- for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) {
- INIT_LIST_HEAD(&state[i].head);
- spin_lock_init(&state[i].lock);
- }
-}
-
-static void wrandom_select_route(const struct flowi *flp,
- struct rtable *first,
- struct rtable **rp)
-{
- struct rtable *rt;
- struct rtable *decision;
- struct multipath_candidate *first_mpc = NULL;
- struct multipath_candidate *mpc, *last_mpc = NULL;
- int power = 0;
- int last_power;
- int selector;
- const size_t size_mpc = sizeof(struct multipath_candidate);
-
- /* collect all candidates and identify their weights */
- for (rt = rcu_dereference(first); rt;
- rt = rcu_dereference(rt->u.dst.rt_next)) {
- if ((rt->u.dst.flags & DST_BALANCED) != 0 &&
- multipath_comparekeys(&rt->fl, flp)) {
- struct multipath_candidate* mpc =
- (struct multipath_candidate*)
- kmalloc(size_mpc, GFP_ATOMIC);
-
- if (!mpc)
- return;
-
- power += __multipath_lookup_weight(flp, rt) * 10000;
-
- mpc->power = power;
- mpc->rt = rt;
- mpc->next = NULL;
-
- if (!first_mpc)
- first_mpc = mpc;
- else
- last_mpc->next = mpc;
-
- last_mpc = mpc;
- }
- }
-
- /* choose a weighted random candidate */
- decision = first;
- selector = random32() % power;
- last_power = 0;
-
- /* select candidate, adjust GC data and cleanup local state */
- decision = first;
- last_mpc = NULL;
- for (mpc = first_mpc; mpc; mpc = mpc->next) {
- mpc->rt->u.dst.lastuse = jiffies;
- if (last_power <= selector && selector < mpc->power)
- decision = mpc->rt;
-
- last_power = mpc->power;
- kfree(last_mpc);
- last_mpc = mpc;
- }
-
- /* concurrent __multipath_flush may lead to !last_mpc */
- kfree(last_mpc);
-
- decision->u.dst.__use++;
- *rp = decision;
-}
-
-static void wrandom_set_nhinfo(__be32 network,
- __be32 netmask,
- unsigned char prefixlen,
- const struct fib_nh *nh)
-{
- const int state_idx = nh->nh_oif % MULTIPATH_STATE_SIZE;
- struct multipath_route *r, *target_route = NULL;
- struct multipath_dest *d, *target_dest = NULL;
-
- /* store the weight information for a certain route */
- spin_lock_bh(&state[state_idx].lock);
-
- /* find state entry for gateway or add one if necessary */
- list_for_each_entry_rcu(r, &state[state_idx].head, list) {
- if (r->gw == nh->nh_gw && r->oif == nh->nh_oif) {
- target_route = r;
- break;
- }
- }
-
- if (!target_route) {
- const size_t size_rt = sizeof(struct multipath_route);
- target_route = (struct multipath_route *)
- kmalloc(size_rt, GFP_ATOMIC);
-
- target_route->gw = nh->nh_gw;
- target_route->oif = nh->nh_oif;
- memset(&target_route->rcu, 0, sizeof(struct rcu_head));
- INIT_LIST_HEAD(&target_route->dests);
-
- list_add_rcu(&target_route->list, &state[state_idx].head);
- }
-
- /* find state entry for destination or add one if necessary */
- list_for_each_entry_rcu(d, &target_route->dests, list) {
- if (d->nh_info == nh) {
- target_dest = d;
- break;
- }
- }
-
- if (!target_dest) {
- const size_t size_dst = sizeof(struct multipath_dest);
- target_dest = (struct multipath_dest*)
- kmalloc(size_dst, GFP_ATOMIC);
-
- target_dest->nh_info = nh;
- target_dest->network = network;
- target_dest->netmask = netmask;
- target_dest->prefixlen = prefixlen;
- memset(&target_dest->rcu, 0, sizeof(struct rcu_head));
-
- list_add_rcu(&target_dest->list, &target_route->dests);
- }
- /* else: we already stored this info for another destination =>
- * we are finished
- */
-
- spin_unlock_bh(&state[state_idx].lock);
-}
-
-static void __multipath_free(struct rcu_head *head)
-{
- struct multipath_route *rt = container_of(head, struct multipath_route,
- rcu);
- kfree(rt);
-}
-
-static void __multipath_free_dst(struct rcu_head *head)
-{
- struct multipath_dest *dst = container_of(head,
- struct multipath_dest,
- rcu);
- kfree(dst);
-}
-
-static void wrandom_flush(void)
-{
- int i;
-
- /* defere delete to all entries */
- for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) {
- struct multipath_route *r;
-
- spin_lock_bh(&state[i].lock);
- list_for_each_entry_rcu(r, &state[i].head, list) {
- struct multipath_dest *d;
- list_for_each_entry_rcu(d, &r->dests, list) {
- list_del_rcu(&d->list);
- call_rcu(&d->rcu,
- __multipath_free_dst);
- }
- list_del_rcu(&r->list);
- call_rcu(&r->rcu,
- __multipath_free);
- }
-
- spin_unlock_bh(&state[i].lock);
- }
-}
-
-static struct ip_mp_alg_ops wrandom_ops = {
- .mp_alg_select_route = wrandom_select_route,
- .mp_alg_flush = wrandom_flush,
- .mp_alg_set_nhinfo = wrandom_set_nhinfo,
-};
-
-static int __init wrandom_init(void)
-{
- wrandom_init_state();
-
- return multipath_alg_register(&wrandom_ops, IP_MP_ALG_WRANDOM);
-}
-
-static void __exit wrandom_exit(void)
-{
- multipath_alg_unregister(&wrandom_ops, IP_MP_ALG_WRANDOM);
-}
-
-module_init(wrandom_init);
-module_exit(wrandom_exit);
-MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 46509fae9fd8..fa97947c6ae1 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -230,7 +230,7 @@ config IP_NF_TARGET_NETMAP
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_TARGET_SAME
- tristate "SAME target support"
+ tristate "SAME target support (OBSOLETE)"
depends on NF_NAT
help
This option adds a `SAME' target, which works like the standard SNAT
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index cae41215e3c7..d1149aba9351 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -224,7 +224,7 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
static const char nulldevname[IFNAMSIZ];
unsigned int verdict = NF_DROP;
struct arphdr *arp;
- int hotdrop = 0;
+ bool hotdrop = false;
struct arpt_entry *e, *back;
const char *indev, *outdev;
void *table_base;
@@ -1140,13 +1140,13 @@ void arpt_unregister_table(struct arpt_table *table)
}
/* The built-in targets: standard (NULL) and error. */
-static struct arpt_target arpt_standard_target = {
+static struct arpt_target arpt_standard_target __read_mostly = {
.name = ARPT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = NF_ARP,
};
-static struct arpt_target arpt_error_target = {
+static struct arpt_target arpt_error_target __read_mostly = {
.name = ARPT_ERROR_TARGET,
.target = arpt_error,
.targetsize = ARPT_FUNCTION_MAXNAMELEN,
@@ -1184,7 +1184,7 @@ static int __init arp_tables_init(void)
if (ret < 0)
goto err4;
- printk("arp_tables: (C) 2002 David S. Miller\n");
+ printk(KERN_INFO "arp_tables: (C) 2002 David S. Miller\n");
return 0;
err4:
diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c
index 6298d404e7c7..c4bdab47597f 100644
--- a/net/ipv4/netfilter/arpt_mangle.c
+++ b/net/ipv4/netfilter/arpt_mangle.c
@@ -65,7 +65,7 @@ target(struct sk_buff **pskb,
return mangle->target;
}
-static int
+static bool
checkentry(const char *tablename, const void *e, const struct xt_target *target,
void *targinfo, unsigned int hook_mask)
{
@@ -73,15 +73,15 @@ checkentry(const char *tablename, const void *e, const struct xt_target *target,
if (mangle->flags & ~ARPT_MANGLE_MASK ||
!(mangle->flags & ARPT_MANGLE_MASK))
- return 0;
+ return false;
if (mangle->target != NF_DROP && mangle->target != NF_ACCEPT &&
mangle->target != ARPT_CONTINUE)
- return 0;
- return 1;
+ return false;
+ return true;
}
-static struct arpt_target arpt_mangle_reg = {
+static struct arpt_target arpt_mangle_reg __read_mostly = {
.name = "mangle",
.target = target,
.targetsize = sizeof(struct arpt_mangle),
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 9bacf1a03630..e1b402c6b855 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -152,20 +152,20 @@ ip_packet_match(const struct iphdr *ip,
return 1;
}
-static inline int
+static inline bool
ip_checkentry(const struct ipt_ip *ip)
{
if (ip->flags & ~IPT_F_MASK) {
duprintf("Unknown flag bits set: %08X\n",
ip->flags & ~IPT_F_MASK);
- return 0;
+ return false;
}
if (ip->invflags & ~IPT_INV_MASK) {
duprintf("Unknown invflag bits set: %08X\n",
ip->invflags & ~IPT_INV_MASK);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static unsigned int
@@ -183,19 +183,19 @@ ipt_error(struct sk_buff **pskb,
}
static inline
-int do_match(struct ipt_entry_match *m,
- const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int offset,
- int *hotdrop)
+bool do_match(struct ipt_entry_match *m,
+ const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int offset,
+ bool *hotdrop)
{
/* Stop iteration if it doesn't match */
if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
offset, ip_hdrlen(skb), hotdrop))
- return 1;
+ return true;
else
- return 0;
+ return false;
}
static inline struct ipt_entry *
@@ -204,6 +204,112 @@ get_entry(void *base, unsigned int offset)
return (struct ipt_entry *)(base + offset);
}
+/* All zeroes == unconditional rule. */
+static inline int
+unconditional(const struct ipt_ip *ip)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
+ if (((__u32 *)ip)[i])
+ return 0;
+
+ return 1;
+}
+
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+static const char *hooknames[] = {
+ [NF_IP_PRE_ROUTING] = "PREROUTING",
+ [NF_IP_LOCAL_IN] = "INPUT",
+ [NF_IP_FORWARD] = "FORWARD",
+ [NF_IP_LOCAL_OUT] = "OUTPUT",
+ [NF_IP_POST_ROUTING] = "POSTROUTING",
+};
+
+enum nf_ip_trace_comments {
+ NF_IP_TRACE_COMMENT_RULE,
+ NF_IP_TRACE_COMMENT_RETURN,
+ NF_IP_TRACE_COMMENT_POLICY,
+};
+
+static const char *comments[] = {
+ [NF_IP_TRACE_COMMENT_RULE] = "rule",
+ [NF_IP_TRACE_COMMENT_RETURN] = "return",
+ [NF_IP_TRACE_COMMENT_POLICY] = "policy",
+};
+
+static struct nf_loginfo trace_loginfo = {
+ .type = NF_LOG_TYPE_LOG,
+ .u = {
+ .log = {
+ .level = 4,
+ .logflags = NF_LOG_MASK,
+ },
+ },
+};
+
+static inline int
+get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
+ char *hookname, char **chainname,
+ char **comment, unsigned int *rulenum)
+{
+ struct ipt_standard_target *t = (void *)ipt_get_target(s);
+
+ if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
+ /* Head of user chain: ERROR target with chainname */
+ *chainname = t->target.data;
+ (*rulenum) = 0;
+ } else if (s == e) {
+ (*rulenum)++;
+
+ if (s->target_offset == sizeof(struct ipt_entry)
+ && strcmp(t->target.u.kernel.target->name,
+ IPT_STANDARD_TARGET) == 0
+ && t->verdict < 0
+ && unconditional(&s->ip)) {
+ /* Tail of chains: STANDARD target (return/policy) */
+ *comment = *chainname == hookname
+ ? (char *)comments[NF_IP_TRACE_COMMENT_POLICY]
+ : (char *)comments[NF_IP_TRACE_COMMENT_RETURN];
+ }
+ return 1;
+ } else
+ (*rulenum)++;
+
+ return 0;
+}
+
+static void trace_packet(struct sk_buff *skb,
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+ char *tablename,
+ struct xt_table_info *private,
+ struct ipt_entry *e)
+{
+ void *table_base;
+ struct ipt_entry *root;
+ char *hookname, *chainname, *comment;
+ unsigned int rulenum = 0;
+
+ table_base = (void *)private->entries[smp_processor_id()];
+ root = get_entry(table_base, private->hook_entry[hook]);
+
+ hookname = chainname = (char *)hooknames[hook];
+ comment = (char *)comments[NF_IP_TRACE_COMMENT_RULE];
+
+ IPT_ENTRY_ITERATE(root,
+ private->size - private->hook_entry[hook],
+ get_chainname_rulenum,
+ e, hookname, &chainname, &comment, &rulenum);
+
+ nf_log_packet(AF_INET, hook, skb, in, out, &trace_loginfo,
+ "TRACE: %s:%s:%s:%u ",
+ tablename, chainname, comment, rulenum);
+}
+#endif
+
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int
ipt_do_table(struct sk_buff **pskb,
@@ -216,7 +322,7 @@ ipt_do_table(struct sk_buff **pskb,
u_int16_t offset;
struct iphdr *ip;
u_int16_t datalen;
- int hotdrop = 0;
+ bool hotdrop = false;
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
const char *indev, *outdev;
@@ -261,6 +367,14 @@ ipt_do_table(struct sk_buff **pskb,
t = ipt_get_target(e);
IP_NF_ASSERT(t->u.kernel.target);
+
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ /* The packet is traced: log it */
+ if (unlikely((*pskb)->nf_trace))
+ trace_packet(*pskb, hook, in, out,
+ table->name, private, e);
+#endif
/* Standard target? */
if (!t->u.kernel.target->target) {
int v;
@@ -341,19 +455,6 @@ ipt_do_table(struct sk_buff **pskb,
#endif
}
-/* All zeroes == unconditional rule. */
-static inline int
-unconditional(const struct ipt_ip *ip)
-{
- unsigned int i;
-
- for (i = 0; i < sizeof(*ip)/sizeof(__u32); i++)
- if (((__u32 *)ip)[i])
- return 0;
-
- return 1;
-}
-
/* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */
static int
@@ -2105,16 +2206,16 @@ void ipt_unregister_table(struct xt_table *table)
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
-static inline int
+static inline bool
icmp_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
u_int8_t type, u_int8_t code,
- int invert)
+ bool invert)
{
return ((test_type == 0xFF) || (type == test_type && code >= min_code && code <= max_code))
^ invert;
}
-static int
+static bool
icmp_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -2122,14 +2223,14 @@ icmp_match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
struct icmphdr _icmph, *ic;
const struct ipt_icmp *icmpinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
- return 0;
+ return false;
ic = skb_header_pointer(skb, protoff, sizeof(_icmph), &_icmph);
if (ic == NULL) {
@@ -2137,8 +2238,8 @@ icmp_match(const struct sk_buff *skb,
* can't. Hence, no choice but to drop.
*/
duprintf("Dropping evil ICMP tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
return icmp_type_code_match(icmpinfo->type,
@@ -2149,7 +2250,7 @@ icmp_match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
icmp_checkentry(const char *tablename,
const void *info,
const struct xt_match *match,
@@ -2163,7 +2264,7 @@ icmp_checkentry(const char *tablename,
}
/* The built-in targets: standard (NULL) and error. */
-static struct xt_target ipt_standard_target = {
+static struct xt_target ipt_standard_target __read_mostly = {
.name = IPT_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = AF_INET,
@@ -2174,7 +2275,7 @@ static struct xt_target ipt_standard_target = {
#endif
};
-static struct xt_target ipt_error_target = {
+static struct xt_target ipt_error_target __read_mostly = {
.name = IPT_ERROR_TARGET,
.target = ipt_error,
.targetsize = IPT_FUNCTION_MAXNAMELEN,
@@ -2197,7 +2298,7 @@ static struct nf_sockopt_ops ipt_sockopts = {
#endif
};
-static struct xt_match icmp_matchstruct = {
+static struct xt_match icmp_matchstruct __read_mostly = {
.name = "icmp",
.match = icmp_match,
.matchsize = sizeof(struct ipt_icmp),
@@ -2230,7 +2331,7 @@ static int __init ip_tables_init(void)
if (ret < 0)
goto err5;
- printk("ip_tables: (C) 2000-2006 Netfilter Core Team\n");
+ printk(KERN_INFO "ip_tables: (C) 2000-2006 Netfilter Core Team\n");
return 0;
err5:
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 40e273421398..dcc12b183474 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -30,14 +30,6 @@
#define CLUSTERIP_VERSION "0.8"
-#define DEBUG_CLUSTERIP
-
-#ifdef DEBUG_CLUSTERIP
-#define DEBUGP printk
-#else
-#define DEBUGP
-#endif
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("iptables target for CLUSTERIP");
@@ -122,9 +114,8 @@ __clusterip_config_find(__be32 clusterip)
list_for_each(pos, &clusterip_configs) {
struct clusterip_config *c = list_entry(pos,
struct clusterip_config, list);
- if (c->clusterip == clusterip) {
+ if (c->clusterip == clusterip)
return c;
- }
}
return NULL;
@@ -155,9 +146,8 @@ clusterip_config_init_nodelist(struct clusterip_config *c,
{
int n;
- for (n = 0; n < i->num_local_nodes; n++) {
+ for (n = 0; n < i->num_local_nodes; n++)
set_bit(i->local_nodes[n] - 1, &c->local_nodes);
- }
}
static struct clusterip_config *
@@ -220,27 +210,28 @@ clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum)
return 0;
}
-static int
+static bool
clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum)
{
if (nodenum == 0 ||
nodenum > c->num_total_nodes)
- return 1;
+ return true;
if (test_and_clear_bit(nodenum - 1, &c->local_nodes))
- return 0;
+ return false;
- return 1;
+ return true;
}
#endif
static inline u_int32_t
-clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
+clusterip_hashfn(const struct sk_buff *skb,
+ const struct clusterip_config *config)
{
- struct iphdr *iph = ip_hdr(skb);
+ const struct iphdr *iph = ip_hdr(skb);
unsigned long hashval;
u_int16_t sport, dport;
- u_int16_t *ports;
+ const u_int16_t *ports;
switch (iph->protocol) {
case IPPROTO_TCP:
@@ -249,15 +240,14 @@ clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
case IPPROTO_SCTP:
case IPPROTO_DCCP:
case IPPROTO_ICMP:
- ports = (void *)iph+iph->ihl*4;
+ ports = (const void *)iph+iph->ihl*4;
sport = ports[0];
dport = ports[1];
break;
default:
- if (net_ratelimit()) {
+ if (net_ratelimit())
printk(KERN_NOTICE "CLUSTERIP: unknown protocol `%u'\n",
iph->protocol);
- }
sport = dport = 0;
}
@@ -285,11 +275,11 @@ clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config)
}
/* node numbers are 1..n, not 0..n */
- return ((hashval % config->num_total_nodes)+1);
+ return (hashval % config->num_total_nodes) + 1;
}
static inline int
-clusterip_responsible(struct clusterip_config *config, u_int32_t hash)
+clusterip_responsible(const struct clusterip_config *config, u_int32_t hash)
{
return test_bit(hash - 1, &config->local_nodes);
}
@@ -353,15 +343,15 @@ target(struct sk_buff **pskb,
break;
}
-#ifdef DEBUG_CLUSTERP
+#ifdef DEBUG
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
#endif
- DEBUGP("hash=%u ct_hash=%u ", hash, ct->mark);
+ pr_debug("hash=%u ct_hash=%u ", hash, ct->mark);
if (!clusterip_responsible(cipinfo->config, hash)) {
- DEBUGP("not responsible\n");
+ pr_debug("not responsible\n");
return NF_DROP;
}
- DEBUGP("responsible\n");
+ pr_debug("responsible\n");
/* despite being received via linklayer multicast, this is
* actually a unicast IP packet. TCP doesn't like PACKET_MULTICAST */
@@ -370,7 +360,7 @@ target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int
+static bool
checkentry(const char *tablename,
const void *e_void,
const struct xt_target *target,
@@ -387,50 +377,34 @@ checkentry(const char *tablename,
cipinfo->hash_mode != CLUSTERIP_HASHMODE_SIP_SPT_DPT) {
printk(KERN_WARNING "CLUSTERIP: unknown mode `%u'\n",
cipinfo->hash_mode);
- return 0;
+ return false;
}
if (e->ip.dmsk.s_addr != htonl(0xffffffff)
|| e->ip.dst.s_addr == 0) {
printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n");
- return 0;
+ return false;
}
/* FIXME: further sanity checks */
config = clusterip_config_find_get(e->ip.dst.s_addr, 1);
- if (config) {
- if (cipinfo->config != NULL) {
- /* Case A: This is an entry that gets reloaded, since
- * it still has a cipinfo->config pointer. Simply
- * increase the entry refcount and return */
- if (cipinfo->config != config) {
- printk(KERN_ERR "CLUSTERIP: Reloaded entry "
- "has invalid config pointer!\n");
- return 0;
- }
- } else {
- /* Case B: This is a new rule referring to an existing
- * clusterip config. */
- cipinfo->config = config;
- }
- } else {
- /* Case C: This is a completely new clusterip config */
+ if (!config) {
if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) {
printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr));
- return 0;
+ return false;
} else {
struct net_device *dev;
if (e->ip.iniface[0] == '\0') {
printk(KERN_WARNING "CLUSTERIP: Please specify an interface name\n");
- return 0;
+ return false;
}
dev = dev_get_by_name(e->ip.iniface);
if (!dev) {
printk(KERN_WARNING "CLUSTERIP: no such interface %s\n", e->ip.iniface);
- return 0;
+ return false;
}
config = clusterip_config_init(cipinfo,
@@ -438,20 +412,20 @@ checkentry(const char *tablename,
if (!config) {
printk(KERN_WARNING "CLUSTERIP: cannot allocate config\n");
dev_put(dev);
- return 0;
+ return false;
}
dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0);
}
- cipinfo->config = config;
}
+ cipinfo->config = config;
if (nf_ct_l3proto_try_module_get(target->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", target->family);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* drop reference count of cluster config when rule is deleted */
@@ -468,13 +442,30 @@ static void destroy(const struct xt_target *target, void *targinfo)
nf_ct_l3proto_module_put(target->family);
}
-static struct xt_target clusterip_tgt = {
+#ifdef CONFIG_COMPAT
+struct compat_ipt_clusterip_tgt_info
+{
+ u_int32_t flags;
+ u_int8_t clustermac[6];
+ u_int16_t num_total_nodes;
+ u_int16_t num_local_nodes;
+ u_int16_t local_nodes[CLUSTERIP_MAX_NODES];
+ u_int32_t hash_mode;
+ u_int32_t hash_initval;
+ compat_uptr_t config;
+};
+#endif /* CONFIG_COMPAT */
+
+static struct xt_target clusterip_tgt __read_mostly = {
.name = "CLUSTERIP",
.family = AF_INET,
.target = target,
- .targetsize = sizeof(struct ipt_clusterip_tgt_info),
.checkentry = checkentry,
.destroy = destroy,
+ .targetsize = sizeof(struct ipt_clusterip_tgt_info),
+#ifdef CONFIG_COMPAT
+ .compatsize = sizeof(struct compat_ipt_clusterip_tgt_info),
+#endif /* CONFIG_COMPAT */
.me = THIS_MODULE
};
@@ -491,7 +482,7 @@ struct arp_payload {
__be32 dst_ip;
} __attribute__ ((packed));
-#ifdef CLUSTERIP_DEBUG
+#ifdef DEBUG
static void arp_print(struct arp_payload *payload)
{
#define HBUFFERLEN 30
@@ -547,8 +538,9 @@ arp_mangle(unsigned int hook,
* this wouldn't work, since we didn't subscribe the mcast group on
* other interfaces */
if (c->dev != out) {
- DEBUGP("CLUSTERIP: not mangling arp reply on different "
- "interface: cip'%s'-skb'%s'\n", c->dev->name, out->name);
+ pr_debug("CLUSTERIP: not mangling arp reply on different "
+ "interface: cip'%s'-skb'%s'\n",
+ c->dev->name, out->name);
clusterip_config_put(c);
return NF_ACCEPT;
}
@@ -556,8 +548,8 @@ arp_mangle(unsigned int hook,
/* mangle reply hardware address */
memcpy(payload->src_hw, c->clustermac, arp->ar_hln);
-#ifdef CLUSTERIP_DEBUG
- DEBUGP(KERN_DEBUG "CLUSTERIP mangled arp reply: ");
+#ifdef DEBUG
+ pr_debug(KERN_DEBUG "CLUSTERIP mangled arp reply: ");
arp_print(payload);
#endif
@@ -647,7 +639,7 @@ static int clusterip_seq_show(struct seq_file *s, void *v)
return 0;
}
-static struct seq_operations clusterip_seq_ops = {
+static const struct seq_operations clusterip_seq_ops = {
.start = clusterip_seq_start,
.next = clusterip_seq_next,
.stop = clusterip_seq_stop,
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 918ca92e534a..f1253bd3837f 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -24,8 +24,8 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("iptables ECN modification module");
/* set ECT codepoint from IP header.
- * return 0 if there was an error. */
-static inline int
+ * return false if there was an error. */
+static inline bool
set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
{
struct iphdr *iph = ip_hdr(*pskb);
@@ -33,18 +33,18 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
__u8 oldtos;
if (!skb_make_writable(pskb, sizeof(struct iphdr)))
- return 0;
+ return false;
iph = ip_hdr(*pskb);
oldtos = iph->tos;
iph->tos &= ~IPT_ECN_IP_MASK;
iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
nf_csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
}
- return 1;
+ return true;
}
-/* Return 0 if there was an error. */
-static inline int
+/* Return false if there was an error. */
+static inline bool
set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
{
struct tcphdr _tcph, *tcph;
@@ -54,16 +54,16 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
tcph = skb_header_pointer(*pskb, ip_hdrlen(*pskb),
sizeof(_tcph), &_tcph);
if (!tcph)
- return 0;
+ return false;
if ((!(einfo->operation & IPT_ECN_OP_SET_ECE) ||
tcph->ece == einfo->proto.tcp.ece) &&
- ((!(einfo->operation & IPT_ECN_OP_SET_CWR) ||
- tcph->cwr == einfo->proto.tcp.cwr)))
- return 1;
+ (!(einfo->operation & IPT_ECN_OP_SET_CWR) ||
+ tcph->cwr == einfo->proto.tcp.cwr))
+ return true;
if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
- return 0;
+ return false;
tcph = (void *)ip_hdr(*pskb) + ip_hdrlen(*pskb);
oldval = ((__be16 *)tcph)[6];
@@ -74,7 +74,7 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
nf_proto_csum_replace2(&tcph->check, *pskb,
oldval, ((__be16 *)tcph)[6], 0);
- return 1;
+ return true;
}
static unsigned int
@@ -99,7 +99,7 @@ target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int
+static bool
checkentry(const char *tablename,
const void *e_void,
const struct xt_target *target,
@@ -112,23 +112,23 @@ checkentry(const char *tablename,
if (einfo->operation & IPT_ECN_OP_MASK) {
printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
einfo->operation);
- return 0;
+ return false;
}
if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
einfo->ip_ect);
- return 0;
+ return false;
}
if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
&& (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
printk(KERN_WARNING "ECN: cannot use TCP operations on a "
"non-tcp rule\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_target ipt_ecn_reg = {
+static struct xt_target ipt_ecn_reg __read_mostly = {
.name = "ECN",
.family = AF_INET,
.target = target,
diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c
index a42c5cd968b1..5937ad150b9f 100644
--- a/net/ipv4/netfilter/ipt_LOG.c
+++ b/net/ipv4/netfilter/ipt_LOG.c
@@ -27,12 +27,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables syslog logging module");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Use lock to serialize, so printks don't overlap */
static DEFINE_SPINLOCK(log_lock);
@@ -41,7 +35,8 @@ static void dump_packet(const struct nf_loginfo *info,
const struct sk_buff *skb,
unsigned int iphoff)
{
- struct iphdr _iph, *ih;
+ struct iphdr _iph;
+ const struct iphdr *ih;
unsigned int logflags;
if (info->type == NF_LOG_TYPE_LOG)
@@ -100,7 +95,8 @@ static void dump_packet(const struct nf_loginfo *info,
switch (ih->protocol) {
case IPPROTO_TCP: {
- struct tcphdr _tcph, *th;
+ struct tcphdr _tcph;
+ const struct tcphdr *th;
/* Max length: 10 "PROTO=TCP " */
printk("PROTO=TCP ");
@@ -151,7 +147,7 @@ static void dump_packet(const struct nf_loginfo *info,
if ((logflags & IPT_LOG_TCPOPT)
&& th->doff * 4 > sizeof(struct tcphdr)) {
unsigned char _opt[4 * 15 - sizeof(struct tcphdr)];
- unsigned char *op;
+ const unsigned char *op;
unsigned int i, optsize;
optsize = th->doff * 4 - sizeof(struct tcphdr);
@@ -173,7 +169,8 @@ static void dump_packet(const struct nf_loginfo *info,
}
case IPPROTO_UDP:
case IPPROTO_UDPLITE: {
- struct udphdr _udph, *uh;
+ struct udphdr _udph;
+ const struct udphdr *uh;
if (ih->protocol == IPPROTO_UDP)
/* Max length: 10 "PROTO=UDP " */
@@ -200,7 +197,8 @@ static void dump_packet(const struct nf_loginfo *info,
break;
}
case IPPROTO_ICMP: {
- struct icmphdr _icmph, *ich;
+ struct icmphdr _icmph;
+ const struct icmphdr *ich;
static const size_t required_len[NR_ICMP_TYPES+1]
= { [ICMP_ECHOREPLY] = 4,
[ICMP_DEST_UNREACH]
@@ -285,7 +283,8 @@ static void dump_packet(const struct nf_loginfo *info,
}
/* Max Length */
case IPPROTO_AH: {
- struct ip_auth_hdr _ahdr, *ah;
+ struct ip_auth_hdr _ahdr;
+ const struct ip_auth_hdr *ah;
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
@@ -307,7 +306,8 @@ static void dump_packet(const struct nf_loginfo *info,
break;
}
case IPPROTO_ESP: {
- struct ip_esp_hdr _esph, *eh;
+ struct ip_esp_hdr _esph;
+ const struct ip_esp_hdr *eh;
/* Max length: 10 "PROTO=ESP " */
printk("PROTO=ESP ");
@@ -385,11 +385,13 @@ ipt_log_packet(unsigned int pf,
out ? out->name : "");
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge) {
- struct net_device *physindev = skb->nf_bridge->physindev;
- struct net_device *physoutdev = skb->nf_bridge->physoutdev;
+ const struct net_device *physindev;
+ const struct net_device *physoutdev;
+ physindev = skb->nf_bridge->physindev;
if (physindev && in != physindev)
printk("PHYSIN=%s ", physindev->name);
+ physoutdev = skb->nf_bridge->physoutdev;
if (physoutdev && out != physoutdev)
printk("PHYSOUT=%s ", physoutdev->name);
}
@@ -435,27 +437,27 @@ ipt_log_target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int ipt_log_checkentry(const char *tablename,
- const void *e,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
+static bool ipt_log_checkentry(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
{
const struct ipt_log_info *loginfo = targinfo;
if (loginfo->level >= 8) {
- DEBUGP("LOG: level %u >= 8\n", loginfo->level);
- return 0;
+ pr_debug("LOG: level %u >= 8\n", loginfo->level);
+ return false;
}
if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
- DEBUGP("LOG: prefix term %i\n",
- loginfo->prefix[sizeof(loginfo->prefix)-1]);
- return 0;
+ pr_debug("LOG: prefix term %i\n",
+ loginfo->prefix[sizeof(loginfo->prefix)-1]);
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_target ipt_log_reg = {
+static struct xt_target ipt_log_reg __read_mostly = {
.name = "LOG",
.family = AF_INET,
.target = ipt_log_target,
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index d4f2d7775330..7c4e4be7c8b3 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -27,17 +27,11 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables MASQUERADE target module");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Lock protects masq region inside conntrack */
static DEFINE_RWLOCK(masq_lock);
/* FIXME: Multiple targets. --RR */
-static int
+static bool
masquerade_check(const char *tablename,
const void *e,
const struct xt_target *target,
@@ -47,14 +41,14 @@ masquerade_check(const char *tablename,
const struct nf_nat_multi_range_compat *mr = targinfo;
if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
- DEBUGP("masquerade_check: bad MAP_IPS.\n");
- return 0;
+ pr_debug("masquerade_check: bad MAP_IPS.\n");
+ return false;
}
if (mr->rangesize != 1) {
- DEBUGP("masquerade_check: bad rangesize %u.\n", mr->rangesize);
- return 0;
+ pr_debug("masquerade_check: bad rangesize %u\n", mr->rangesize);
+ return false;
}
- return 1;
+ return true;
}
static unsigned int
@@ -70,7 +64,7 @@ masquerade_target(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo;
struct nf_nat_range newrange;
const struct nf_nat_multi_range_compat *mr;
- struct rtable *rt;
+ const struct rtable *rt;
__be32 newsrc;
NF_CT_ASSERT(hooknum == NF_IP_POST_ROUTING);
@@ -109,10 +103,10 @@ masquerade_target(struct sk_buff **pskb,
return nf_nat_setup_info(ct, &newrange, hooknum);
}
-static inline int
+static int
device_cmp(struct nf_conn *i, void *ifindex)
{
- struct nf_conn_nat *nat = nfct_nat(i);
+ const struct nf_conn_nat *nat = nfct_nat(i);
int ret;
if (!nat)
@@ -129,7 +123,7 @@ static int masq_device_event(struct notifier_block *this,
unsigned long event,
void *ptr)
{
- struct net_device *dev = ptr;
+ const struct net_device *dev = ptr;
if (event == NETDEV_DOWN) {
/* Device was downed. Search entire table for
@@ -147,7 +141,7 @@ static int masq_inet_event(struct notifier_block *this,
unsigned long event,
void *ptr)
{
- struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
+ const struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
if (event == NETDEV_DOWN) {
/* IP address was deleted. Search entire table for
@@ -169,7 +163,7 @@ static struct notifier_block masq_inet_notifier = {
.notifier_call = masq_inet_event,
};
-static struct xt_target masquerade = {
+static struct xt_target masquerade __read_mostly = {
.name = "MASQUERADE",
.family = AF_INET,
.target = masquerade_target,
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index 068c69bce30e..41a011d5a065 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -18,18 +18,11 @@
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat_rule.h>
-#define MODULENAME "NETMAP"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>");
MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static int
+static bool
check(const char *tablename,
const void *e,
const struct xt_target *target,
@@ -39,14 +32,14 @@ check(const char *tablename,
const struct nf_nat_multi_range_compat *mr = targinfo;
if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) {
- DEBUGP(MODULENAME":check: bad MAP_IPS.\n");
- return 0;
+ pr_debug("NETMAP:check: bad MAP_IPS.\n");
+ return false;
}
if (mr->rangesize != 1) {
- DEBUGP(MODULENAME":check: bad rangesize %u.\n", mr->rangesize);
- return 0;
+ pr_debug("NETMAP:check: bad rangesize %u.\n", mr->rangesize);
+ return false;
}
- return 1;
+ return true;
}
static unsigned int
@@ -85,8 +78,8 @@ target(struct sk_buff **pskb,
return nf_nat_setup_info(ct, &newrange, hooknum);
}
-static struct xt_target target_module = {
- .name = MODULENAME,
+static struct xt_target target_module __read_mostly = {
+ .name = "NETMAP",
.family = AF_INET,
.target = target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index 68cc76a198eb..6ac7a2373316 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -25,14 +25,8 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables REDIRECT target module");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* FIXME: Take multiple ranges --RR */
-static int
+static bool
redirect_check(const char *tablename,
const void *e,
const struct xt_target *target,
@@ -42,14 +36,14 @@ redirect_check(const char *tablename,
const struct nf_nat_multi_range_compat *mr = targinfo;
if (mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) {
- DEBUGP("redirect_check: bad MAP_IPS.\n");
- return 0;
+ pr_debug("redirect_check: bad MAP_IPS.\n");
+ return false;
}
if (mr->rangesize != 1) {
- DEBUGP("redirect_check: bad rangesize %u.\n", mr->rangesize);
- return 0;
+ pr_debug("redirect_check: bad rangesize %u.\n", mr->rangesize);
+ return false;
}
- return 1;
+ return true;
}
static unsigned int
@@ -101,7 +95,7 @@ redirect_target(struct sk_buff **pskb,
return nf_nat_setup_info(ct, &newrange, hooknum);
}
-static struct xt_target redirect_reg = {
+static struct xt_target redirect_reg __read_mostly = {
.name = "REDIRECT",
.family = AF_INET,
.target = redirect_target,
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 9041e0741f6f..cb038c8fbc9d 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -31,12 +31,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("iptables REJECT target module");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int hook)
{
@@ -122,7 +116,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
tcph->check = 0;
tcph->check = tcp_v4_check(sizeof(struct tcphdr),
niph->saddr, niph->daddr,
- csum_partial((char *)tcph,
+ csum_partial(tcph,
sizeof(struct tcphdr), 0));
/* Set DF, id = 0 */
@@ -217,30 +211,30 @@ static unsigned int reject(struct sk_buff **pskb,
return NF_DROP;
}
-static int check(const char *tablename,
- const void *e_void,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
+static bool check(const char *tablename,
+ const void *e_void,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
{
const struct ipt_reject_info *rejinfo = targinfo;
const struct ipt_entry *e = e_void;
if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
- printk("REJECT: ECHOREPLY no longer supported.\n");
- return 0;
+ printk("ipt_REJECT: ECHOREPLY no longer supported.\n");
+ return false;
} else if (rejinfo->with == IPT_TCP_RESET) {
/* Must specify that it's a TCP packet */
if (e->ip.proto != IPPROTO_TCP
|| (e->ip.invflags & XT_INV_PROTO)) {
- DEBUGP("REJECT: TCP_RESET invalid for non-tcp\n");
- return 0;
+ printk("ipt_REJECT: TCP_RESET invalid for non-tcp\n");
+ return false;
}
}
- return 1;
+ return true;
}
-static struct xt_target ipt_reject_reg = {
+static struct xt_target ipt_reject_reg __read_mostly = {
.name = "REJECT",
.family = AF_INET,
.target = reject,
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index 511e5ff84938..97641f1a97f6 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -27,13 +27,7 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Martin Josefsson <gandalf@wlug.westbo.se>");
MODULE_DESCRIPTION("iptables special SNAT module for consistent sourceip");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static int
+static bool
same_check(const char *tablename,
const void *e,
const struct xt_target *target,
@@ -46,58 +40,56 @@ same_check(const char *tablename,
mr->ipnum = 0;
if (mr->rangesize < 1) {
- DEBUGP("same_check: need at least one dest range.\n");
- return 0;
+ pr_debug("same_check: need at least one dest range.\n");
+ return false;
}
if (mr->rangesize > IPT_SAME_MAX_RANGE) {
- DEBUGP("same_check: too many ranges specified, maximum "
- "is %u ranges\n",
- IPT_SAME_MAX_RANGE);
- return 0;
+ pr_debug("same_check: too many ranges specified, maximum "
+ "is %u ranges\n", IPT_SAME_MAX_RANGE);
+ return false;
}
for (count = 0; count < mr->rangesize; count++) {
if (ntohl(mr->range[count].min_ip) >
ntohl(mr->range[count].max_ip)) {
- DEBUGP("same_check: min_ip is larger than max_ip in "
- "range `%u.%u.%u.%u-%u.%u.%u.%u'.\n",
- NIPQUAD(mr->range[count].min_ip),
- NIPQUAD(mr->range[count].max_ip));
- return 0;
+ pr_debug("same_check: min_ip is larger than max_ip in "
+ "range `%u.%u.%u.%u-%u.%u.%u.%u'.\n",
+ NIPQUAD(mr->range[count].min_ip),
+ NIPQUAD(mr->range[count].max_ip));
+ return false;
}
if (!(mr->range[count].flags & IP_NAT_RANGE_MAP_IPS)) {
- DEBUGP("same_check: bad MAP_IPS.\n");
- return 0;
+ pr_debug("same_check: bad MAP_IPS.\n");
+ return false;
}
rangeip = (ntohl(mr->range[count].max_ip) -
ntohl(mr->range[count].min_ip) + 1);
mr->ipnum += rangeip;
- DEBUGP("same_check: range %u, ipnum = %u\n", count, rangeip);
+ pr_debug("same_check: range %u, ipnum = %u\n", count, rangeip);
}
- DEBUGP("same_check: total ipaddresses = %u\n", mr->ipnum);
+ pr_debug("same_check: total ipaddresses = %u\n", mr->ipnum);
mr->iparray = kmalloc((sizeof(u_int32_t) * mr->ipnum), GFP_KERNEL);
if (!mr->iparray) {
- DEBUGP("same_check: Couldn't allocate %u bytes "
- "for %u ipaddresses!\n",
- (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
- return 0;
+ pr_debug("same_check: Couldn't allocate %Zu bytes "
+ "for %u ipaddresses!\n",
+ (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
+ return false;
}
- DEBUGP("same_check: Allocated %u bytes for %u ipaddresses.\n",
- (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
+ pr_debug("same_check: Allocated %Zu bytes for %u ipaddresses.\n",
+ (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
for (count = 0; count < mr->rangesize; count++) {
for (countess = ntohl(mr->range[count].min_ip);
countess <= ntohl(mr->range[count].max_ip);
countess++) {
mr->iparray[index] = countess;
- DEBUGP("same_check: Added ipaddress `%u.%u.%u.%u' "
- "in index %u.\n",
- HIPQUAD(countess), index);
+ pr_debug("same_check: Added ipaddress `%u.%u.%u.%u' "
+ "in index %u.\n", HIPQUAD(countess), index);
index++;
}
}
- return 1;
+ return true;
}
static void
@@ -107,8 +99,8 @@ same_destroy(const struct xt_target *target, void *targinfo)
kfree(mr->iparray);
- DEBUGP("same_destroy: Deallocated %u bytes for %u ipaddresses.\n",
- (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
+ pr_debug("same_destroy: Deallocated %Zu bytes for %u ipaddresses.\n",
+ (sizeof(u_int32_t) * mr->ipnum), mr->ipnum);
}
static unsigned int
@@ -146,10 +138,9 @@ same_target(struct sk_buff **pskb,
new_ip = htonl(same->iparray[aindex]);
- DEBUGP("ipt_SAME: src=%u.%u.%u.%u dst=%u.%u.%u.%u, "
- "new src=%u.%u.%u.%u\n",
- NIPQUAD(t->src.ip), NIPQUAD(t->dst.ip),
- NIPQUAD(new_ip));
+ pr_debug("ipt_SAME: src=%u.%u.%u.%u dst=%u.%u.%u.%u, "
+ "new src=%u.%u.%u.%u\n",
+ NIPQUAD(t->src.u3.ip), NIPQUAD(t->dst.u3.ip), NIPQUAD(new_ip));
/* Transfer from original range. */
newrange = ((struct nf_nat_range)
@@ -161,7 +152,7 @@ same_target(struct sk_buff **pskb,
return nf_nat_setup_info(ct, &newrange, hooknum);
}
-static struct xt_target same_reg = {
+static struct xt_target same_reg __read_mostly = {
.name = "SAME",
.family = AF_INET,
.target = same_target,
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 0ad02f249837..25f5d0b39065 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -43,7 +43,7 @@ target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int
+static bool
checkentry(const char *tablename,
const void *e_void,
const struct xt_target *target,
@@ -58,12 +58,12 @@ checkentry(const char *tablename,
&& tos != IPTOS_MINCOST
&& tos != IPTOS_NORMALSVC) {
printk(KERN_WARNING "TOS: bad tos value %#x\n", tos);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_target ipt_tos_reg = {
+static struct xt_target ipt_tos_reg __read_mostly = {
.name = "TOS",
.family = AF_INET,
.target = target,
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index a991ec7bd4e7..2b54e7b0cfe8 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -62,25 +62,25 @@ ipt_ttl_target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int ipt_ttl_checkentry(const char *tablename,
+static bool ipt_ttl_checkentry(const char *tablename,
const void *e,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
- struct ipt_TTL_info *info = targinfo;
+ const struct ipt_TTL_info *info = targinfo;
if (info->mode > IPT_TTL_MAXMODE) {
printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
info->mode);
- return 0;
+ return false;
}
- if ((info->mode != IPT_TTL_SET) && (info->ttl == 0))
- return 0;
- return 1;
+ if (info->mode != IPT_TTL_SET && info->ttl == 0)
+ return false;
+ return true;
}
-static struct xt_target ipt_TTL = {
+static struct xt_target ipt_TTL __read_mostly = {
.name = "TTL",
.family = AF_INET,
.target = ipt_ttl_target,
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 23b607b33b32..6ca43e4ca7e3 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -55,13 +55,6 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
#define ULOG_NL_EVENT 111 /* Harald's favorite number */
#define ULOG_MAXNLGROUPS 32 /* numer of nlgroups */
-#if 0
-#define DEBUGP(format, args...) printk("%s:%s:" format, \
- __FILE__, __FUNCTION__ , ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0)
static unsigned int nlbufsiz = NLMSG_GOODSIZE;
@@ -96,12 +89,12 @@ static void ulog_send(unsigned int nlgroupnum)
ulog_buff_t *ub = &ulog_buffers[nlgroupnum];
if (timer_pending(&ub->timer)) {
- DEBUGP("ipt_ULOG: ulog_send: timer was pending, deleting\n");
+ pr_debug("ipt_ULOG: ulog_send: timer was pending, deleting\n");
del_timer(&ub->timer);
}
if (!ub->skb) {
- DEBUGP("ipt_ULOG: ulog_send: nothing to send\n");
+ pr_debug("ipt_ULOG: ulog_send: nothing to send\n");
return;
}
@@ -110,8 +103,8 @@ static void ulog_send(unsigned int nlgroupnum)
ub->lastnlh->nlmsg_type = NLMSG_DONE;
NETLINK_CB(ub->skb).dst_group = nlgroupnum + 1;
- DEBUGP("ipt_ULOG: throwing %d packets to netlink group %u\n",
- ub->qlen, nlgroupnum + 1);
+ pr_debug("ipt_ULOG: throwing %d packets to netlink group %u\n",
+ ub->qlen, nlgroupnum + 1);
netlink_broadcast(nflognl, ub->skb, 0, nlgroupnum + 1, GFP_ATOMIC);
ub->qlen = 0;
@@ -123,7 +116,7 @@ static void ulog_send(unsigned int nlgroupnum)
/* timer function to flush queue in flushtimeout time */
static void ulog_timer(unsigned long data)
{
- DEBUGP("ipt_ULOG: timer function called, calling ulog_send\n");
+ pr_debug("ipt_ULOG: timer function called, calling ulog_send\n");
/* lock to protect against somebody modifying our structure
* from ipt_ulog_target at the same time */
@@ -179,12 +172,10 @@ static void ipt_ulog_packet(unsigned int hooknum,
unsigned int groupnum = ffs(loginfo->nl_group) - 1;
/* calculate the size of the skb needed */
- if ((loginfo->copy_range == 0) ||
- (loginfo->copy_range > skb->len)) {
+ if (loginfo->copy_range == 0 || loginfo->copy_range > skb->len)
copy_len = skb->len;
- } else {
+ else
copy_len = loginfo->copy_range;
- }
size = NLMSG_SPACE(sizeof(*pm) + copy_len);
@@ -206,8 +197,8 @@ static void ipt_ulog_packet(unsigned int hooknum,
goto alloc_failure;
}
- DEBUGP("ipt_ULOG: qlen %d, qthreshold %d\n", ub->qlen,
- loginfo->qthreshold);
+ pr_debug("ipt_ULOG: qlen %d, qthreshold %Zu\n", ub->qlen,
+ loginfo->qthreshold);
/* NLMSG_PUT contains a hidden goto nlmsg_failure !!! */
nlh = NLMSG_PUT(ub->skb, 0, ub->qlen, ULOG_NL_EVENT,
@@ -257,9 +248,8 @@ static void ipt_ulog_packet(unsigned int hooknum,
BUG();
/* check if we are building multi-part messages */
- if (ub->qlen > 1) {
+ if (ub->qlen > 1)
ub->lastnlh->nlmsg_flags |= NLM_F_MULTI;
- }
ub->lastnlh = nlh;
@@ -328,25 +318,25 @@ static void ipt_logfn(unsigned int pf,
ipt_ulog_packet(hooknum, skb, in, out, &loginfo, prefix);
}
-static int ipt_ulog_checkentry(const char *tablename,
- const void *e,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hookmask)
+static bool ipt_ulog_checkentry(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hookmask)
{
- struct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) targinfo;
+ const struct ipt_ulog_info *loginfo = targinfo;
if (loginfo->prefix[sizeof(loginfo->prefix) - 1] != '\0') {
- DEBUGP("ipt_ULOG: prefix term %i\n",
- loginfo->prefix[sizeof(loginfo->prefix) - 1]);
- return 0;
+ pr_debug("ipt_ULOG: prefix term %i\n",
+ loginfo->prefix[sizeof(loginfo->prefix) - 1]);
+ return false;
}
if (loginfo->qthreshold > ULOG_MAX_QLEN) {
- DEBUGP("ipt_ULOG: queue threshold %i > MAX_QLEN\n",
- loginfo->qthreshold);
- return 0;
+ pr_debug("ipt_ULOG: queue threshold %Zu > MAX_QLEN\n",
+ loginfo->qthreshold);
+ return false;
}
- return 1;
+ return true;
}
#ifdef CONFIG_COMPAT
@@ -359,7 +349,7 @@ struct compat_ipt_ulog_info {
static void compat_from_user(void *dst, void *src)
{
- struct compat_ipt_ulog_info *cl = src;
+ const struct compat_ipt_ulog_info *cl = src;
struct ipt_ulog_info l = {
.nl_group = cl->nl_group,
.copy_range = cl->copy_range,
@@ -372,7 +362,7 @@ static void compat_from_user(void *dst, void *src)
static int compat_to_user(void __user *dst, void *src)
{
- struct ipt_ulog_info *l = src;
+ const struct ipt_ulog_info *l = src;
struct compat_ipt_ulog_info cl = {
.nl_group = l->nl_group,
.copy_range = l->copy_range,
@@ -384,7 +374,7 @@ static int compat_to_user(void __user *dst, void *src)
}
#endif /* CONFIG_COMPAT */
-static struct xt_target ipt_ulog_reg = {
+static struct xt_target ipt_ulog_reg __read_mostly = {
.name = "ULOG",
.family = AF_INET,
.target = ipt_ulog_target,
@@ -408,7 +398,7 @@ static int __init ipt_ulog_init(void)
{
int ret, i;
- DEBUGP("ipt_ULOG: init module\n");
+ pr_debug("ipt_ULOG: init module\n");
if (nlbufsiz > 128*1024) {
printk("Netlink buffer has to be <= 128kB\n");
@@ -440,7 +430,7 @@ static void __exit ipt_ulog_fini(void)
ulog_buff_t *ub;
int i;
- DEBUGP("ipt_ULOG: cleanup_module\n");
+ pr_debug("ipt_ULOG: cleanup_module\n");
if (nflog)
nf_log_unregister(&ipt_ulog_logger);
@@ -451,7 +441,7 @@ static void __exit ipt_ulog_fini(void)
for (i = 0; i < ULOG_MAXNLGROUPS; i++) {
ub = &ulog_buffers[i];
if (timer_pending(&ub->timer)) {
- DEBUGP("timer was pending, deleting\n");
+ pr_debug("timer was pending, deleting\n");
del_timer(&ub->timer);
}
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index a652a1451552..59f01f7ba6b4 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -22,19 +22,19 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("iptables addrtype match");
-static inline int match_type(__be32 addr, u_int16_t mask)
+static inline bool match_type(__be32 addr, u_int16_t mask)
{
return !!(mask & (1 << inet_addr_type(addr)));
}
-static int match(const struct sk_buff *skb,
- const struct net_device *in, const struct net_device *out,
- const struct xt_match *match, const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+static bool match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
{
const struct ipt_addrtype_info *info = matchinfo;
const struct iphdr *iph = ip_hdr(skb);
- int ret = 1;
+ bool ret = true;
if (info->source)
ret &= match_type(iph->saddr, info->source)^info->invert_source;
@@ -44,7 +44,7 @@ static int match(const struct sk_buff *skb,
return ret;
}
-static struct xt_match addrtype_match = {
+static struct xt_match addrtype_match __read_mostly = {
.name = "addrtype",
.family = AF_INET,
.match = match,
diff --git a/net/ipv4/netfilter/ipt_ah.c b/net/ipv4/netfilter/ipt_ah.c
index 18a16782cf40..61b017fd743c 100644
--- a/net/ipv4/netfilter/ipt_ah.c
+++ b/net/ipv4/netfilter/ipt_ah.c
@@ -25,10 +25,10 @@ MODULE_DESCRIPTION("iptables AH SPI match module");
#endif
/* Returns 1 if the spi is matched by the range, 0 otherwise */
-static inline int
-spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+static inline bool
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
{
- int r=0;
+ bool r;
duprintf("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
min,spi,max);
r=(spi >= min && spi <= max) ^ invert;
@@ -36,7 +36,7 @@ spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
return r;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -44,14 +44,15 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct ip_auth_hdr _ahdr, *ah;
+ struct ip_auth_hdr _ahdr;
+ const struct ip_auth_hdr *ah;
const struct ipt_ah *ahinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
- return 0;
+ return false;
ah = skb_header_pointer(skb, protoff,
sizeof(_ahdr), &_ahdr);
@@ -60,7 +61,7 @@ match(const struct sk_buff *skb,
* can't. Hence, no choice but to drop.
*/
duprintf("Dropping evil AH tinygram.\n");
- *hotdrop = 1;
+ *hotdrop = true;
return 0;
}
@@ -70,7 +71,7 @@ match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
checkentry(const char *tablename,
const void *ip_void,
const struct xt_match *match,
@@ -82,12 +83,12 @@ checkentry(const char *tablename,
/* Must specify no unknown invflags */
if (ahinfo->invflags & ~IPT_AH_INV_MASK) {
duprintf("ipt_ah: unknown flags %X\n", ahinfo->invflags);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match ah_match = {
+static struct xt_match ah_match __read_mostly = {
.name = "ah",
.family = AF_INET,
.match = match,
diff --git a/net/ipv4/netfilter/ipt_ecn.c b/net/ipv4/netfilter/ipt_ecn.c
index 26218122f865..d6925c674069 100644
--- a/net/ipv4/netfilter/ipt_ecn.c
+++ b/net/ipv4/netfilter/ipt_ecn.c
@@ -22,95 +22,96 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("iptables ECN matching module");
MODULE_LICENSE("GPL");
-static inline int match_ip(const struct sk_buff *skb,
- const struct ipt_ecn_info *einfo)
+static inline bool match_ip(const struct sk_buff *skb,
+ const struct ipt_ecn_info *einfo)
{
return (ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect;
}
-static inline int match_tcp(const struct sk_buff *skb,
- const struct ipt_ecn_info *einfo,
- int *hotdrop)
+static inline bool match_tcp(const struct sk_buff *skb,
+ const struct ipt_ecn_info *einfo,
+ bool *hotdrop)
{
- struct tcphdr _tcph, *th;
+ struct tcphdr _tcph;
+ const struct tcphdr *th;
/* In practice, TCP match does this, so can't fail. But let's
* be good citizens.
*/
th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
if (th == NULL) {
- *hotdrop = 0;
- return 0;
+ *hotdrop = false;
+ return false;
}
if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
if (th->ece == 1)
- return 0;
+ return false;
} else {
if (th->ece == 0)
- return 0;
+ return false;
}
}
if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
if (th->cwr == 1)
- return 0;
+ return false;
} else {
if (th->cwr == 0)
- return 0;
+ return false;
}
}
- return 1;
+ return true;
}
-static int match(const struct sk_buff *skb,
- const struct net_device *in, const struct net_device *out,
- const struct xt_match *match, const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+static bool match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
{
const struct ipt_ecn_info *info = matchinfo;
if (info->operation & IPT_ECN_OP_MATCH_IP)
if (!match_ip(skb, info))
- return 0;
+ return false;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
if (ip_hdr(skb)->protocol != IPPROTO_TCP)
- return 0;
+ return false;
if (!match_tcp(skb, info, hotdrop))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static int checkentry(const char *tablename, const void *ip_void,
- const struct xt_match *match,
- void *matchinfo, unsigned int hook_mask)
+static bool checkentry(const char *tablename, const void *ip_void,
+ const struct xt_match *match,
+ void *matchinfo, unsigned int hook_mask)
{
const struct ipt_ecn_info *info = matchinfo;
const struct ipt_ip *ip = ip_void;
if (info->operation & IPT_ECN_OP_MATCH_MASK)
- return 0;
+ return false;
if (info->invert & IPT_ECN_OP_MATCH_MASK)
- return 0;
+ return false;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
&& ip->proto != IPPROTO_TCP) {
printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
" non-tcp packets\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match ecn_match = {
+static struct xt_match ecn_match __read_mostly = {
.name = "ecn",
.family = AF_INET,
.match = match,
diff --git a/net/ipv4/netfilter/ipt_iprange.c b/net/ipv4/netfilter/ipt_iprange.c
index 33af9e940887..0106dc955a69 100644
--- a/net/ipv4/netfilter/ipt_iprange.c
+++ b/net/ipv4/netfilter/ipt_iprange.c
@@ -17,53 +17,47 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("iptables arbitrary IP range match module");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const struct xt_match *match,
const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+ int offset, unsigned int protoff, bool *hotdrop)
{
const struct ipt_iprange_info *info = matchinfo;
const struct iphdr *iph = ip_hdr(skb);
if (info->flags & IPRANGE_SRC) {
- if (((ntohl(iph->saddr) < ntohl(info->src.min_ip))
- || (ntohl(iph->saddr) > ntohl(info->src.max_ip)))
+ if ((ntohl(iph->saddr) < ntohl(info->src.min_ip)
+ || ntohl(iph->saddr) > ntohl(info->src.max_ip))
^ !!(info->flags & IPRANGE_SRC_INV)) {
- DEBUGP("src IP %u.%u.%u.%u NOT in range %s"
- "%u.%u.%u.%u-%u.%u.%u.%u\n",
- NIPQUAD(iph->saddr),
- info->flags & IPRANGE_SRC_INV ? "(INV) " : "",
- NIPQUAD(info->src.min_ip),
- NIPQUAD(info->src.max_ip));
- return 0;
+ pr_debug("src IP %u.%u.%u.%u NOT in range %s"
+ "%u.%u.%u.%u-%u.%u.%u.%u\n",
+ NIPQUAD(iph->saddr),
+ info->flags & IPRANGE_SRC_INV ? "(INV) " : "",
+ NIPQUAD(info->src.min_ip),
+ NIPQUAD(info->src.max_ip));
+ return false;
}
}
if (info->flags & IPRANGE_DST) {
- if (((ntohl(iph->daddr) < ntohl(info->dst.min_ip))
- || (ntohl(iph->daddr) > ntohl(info->dst.max_ip)))
+ if ((ntohl(iph->daddr) < ntohl(info->dst.min_ip)
+ || ntohl(iph->daddr) > ntohl(info->dst.max_ip))
^ !!(info->flags & IPRANGE_DST_INV)) {
- DEBUGP("dst IP %u.%u.%u.%u NOT in range %s"
- "%u.%u.%u.%u-%u.%u.%u.%u\n",
- NIPQUAD(iph->daddr),
- info->flags & IPRANGE_DST_INV ? "(INV) " : "",
- NIPQUAD(info->dst.min_ip),
- NIPQUAD(info->dst.max_ip));
- return 0;
+ pr_debug("dst IP %u.%u.%u.%u NOT in range %s"
+ "%u.%u.%u.%u-%u.%u.%u.%u\n",
+ NIPQUAD(iph->daddr),
+ info->flags & IPRANGE_DST_INV ? "(INV) " : "",
+ NIPQUAD(info->dst.min_ip),
+ NIPQUAD(info->dst.max_ip));
+ return false;
}
}
- return 1;
+ return true;
}
-static struct xt_match iprange_match = {
+static struct xt_match iprange_match __read_mostly = {
.name = "iprange",
.family = AF_INET,
.match = match,
diff --git a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c
index 7fae9aa8944c..b14e77da7a33 100644
--- a/net/ipv4/netfilter/ipt_owner.c
+++ b/net/ipv4/netfilter/ipt_owner.c
@@ -21,7 +21,7 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("iptables owner match");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -29,29 +29,29 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct ipt_owner_info *info = matchinfo;
if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
- return 0;
+ return false;
if(info->match & IPT_OWNER_UID) {
if ((skb->sk->sk_socket->file->f_uid != info->uid) ^
!!(info->invert & IPT_OWNER_UID))
- return 0;
+ return false;
}
if(info->match & IPT_OWNER_GID) {
if ((skb->sk->sk_socket->file->f_gid != info->gid) ^
!!(info->invert & IPT_OWNER_GID))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static int
+static bool
checkentry(const char *tablename,
const void *ip,
const struct xt_match *match,
@@ -63,12 +63,12 @@ checkentry(const char *tablename,
if (info->match & (IPT_OWNER_PID|IPT_OWNER_SID|IPT_OWNER_COMM)) {
printk("ipt_owner: pid, sid and command matching "
"not supported anymore\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match owner_match = {
+static struct xt_match owner_match __read_mostly = {
.name = "owner",
.family = AF_INET,
.match = match,
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 15a9e8bbb7cc..321804315659 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -163,24 +163,23 @@ static void recent_table_flush(struct recent_table *t)
struct recent_entry *e, *next;
unsigned int i;
- for (i = 0; i < ip_list_hash_size; i++) {
+ for (i = 0; i < ip_list_hash_size; i++)
list_for_each_entry_safe(e, next, &t->iphash[i], list)
recent_entry_remove(t, e);
- }
}
-static int
+static bool
ipt_recent_match(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
const struct xt_match *match, const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+ int offset, unsigned int protoff, bool *hotdrop)
{
const struct ipt_recent_info *info = matchinfo;
struct recent_table *t;
struct recent_entry *e;
__be32 addr;
u_int8_t ttl;
- int ret = info->invert;
+ bool ret = info->invert;
if (info->side == IPT_RECENT_DEST)
addr = ip_hdr(skb)->daddr;
@@ -201,16 +200,16 @@ ipt_recent_match(const struct sk_buff *skb,
goto out;
e = recent_entry_init(t, addr, ttl);
if (e == NULL)
- *hotdrop = 1;
- ret ^= 1;
+ *hotdrop = true;
+ ret = !ret;
goto out;
}
if (info->check_set & IPT_RECENT_SET)
- ret ^= 1;
+ ret = !ret;
else if (info->check_set & IPT_RECENT_REMOVE) {
recent_entry_remove(t, e);
- ret ^= 1;
+ ret = !ret;
} else if (info->check_set & (IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) {
unsigned long t = jiffies - info->seconds * HZ;
unsigned int i, hits = 0;
@@ -219,7 +218,7 @@ ipt_recent_match(const struct sk_buff *skb,
if (info->seconds && time_after(t, e->stamps[i]))
continue;
if (++hits >= info->hit_count) {
- ret ^= 1;
+ ret = !ret;
break;
}
}
@@ -235,7 +234,7 @@ out:
return ret;
}
-static int
+static bool
ipt_recent_checkentry(const char *tablename, const void *ip,
const struct xt_match *match, void *matchinfo,
unsigned int hook_mask)
@@ -243,24 +242,24 @@ ipt_recent_checkentry(const char *tablename, const void *ip,
const struct ipt_recent_info *info = matchinfo;
struct recent_table *t;
unsigned i;
- int ret = 0;
+ bool ret = false;
if (hweight8(info->check_set &
(IPT_RECENT_SET | IPT_RECENT_REMOVE |
IPT_RECENT_CHECK | IPT_RECENT_UPDATE)) != 1)
- return 0;
+ return false;
if ((info->check_set & (IPT_RECENT_SET | IPT_RECENT_REMOVE)) &&
(info->seconds || info->hit_count))
- return 0;
+ return false;
if (info->name[0] == '\0' ||
strnlen(info->name, IPT_RECENT_NAME_LEN) == IPT_RECENT_NAME_LEN)
- return 0;
+ return false;
mutex_lock(&recent_mutex);
t = recent_table_lookup(info->name);
if (t != NULL) {
t->refcnt++;
- ret = 1;
+ ret = true;
goto out;
}
@@ -287,7 +286,7 @@ ipt_recent_checkentry(const char *tablename, const void *ip,
spin_lock_bh(&recent_lock);
list_add_tail(&t->list, &tables);
spin_unlock_bh(&recent_lock);
- ret = 1;
+ ret = true;
out:
mutex_unlock(&recent_mutex);
return ret;
@@ -323,18 +322,16 @@ struct recent_iter_state {
static void *recent_seq_start(struct seq_file *seq, loff_t *pos)
{
struct recent_iter_state *st = seq->private;
- struct recent_table *t = st->table;
+ const struct recent_table *t = st->table;
struct recent_entry *e;
loff_t p = *pos;
spin_lock_bh(&recent_lock);
- for (st->bucket = 0; st->bucket < ip_list_hash_size; st->bucket++) {
- list_for_each_entry(e, &t->iphash[st->bucket], list) {
+ for (st->bucket = 0; st->bucket < ip_list_hash_size; st->bucket++)
+ list_for_each_entry(e, &t->iphash[st->bucket], list)
if (p-- == 0)
return e;
- }
- }
return NULL;
}
@@ -373,7 +370,7 @@ static int recent_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations recent_seq_ops = {
+static const struct seq_operations recent_seq_ops = {
.start = recent_seq_start,
.next = recent_seq_next,
.stop = recent_seq_stop,
@@ -463,7 +460,7 @@ static const struct file_operations recent_fops = {
};
#endif /* CONFIG_PROC_FS */
-static struct xt_match recent_match = {
+static struct xt_match recent_match __read_mostly = {
.name = "recent",
.family = AF_INET,
.match = ipt_recent_match,
diff --git a/net/ipv4/netfilter/ipt_tos.c b/net/ipv4/netfilter/ipt_tos.c
index d314844af12b..e740441c973d 100644
--- a/net/ipv4/netfilter/ipt_tos.c
+++ b/net/ipv4/netfilter/ipt_tos.c
@@ -18,7 +18,7 @@
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("iptables TOS match module");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -26,14 +26,14 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct ipt_tos_info *info = matchinfo;
return (ip_hdr(skb)->tos == info->tos) ^ info->invert;
}
-static struct xt_match tos_match = {
+static struct xt_match tos_match __read_mostly = {
.name = "tos",
.family = AF_INET,
.match = match,
diff --git a/net/ipv4/netfilter/ipt_ttl.c b/net/ipv4/netfilter/ipt_ttl.c
index ab02d9e3139c..a439900a4ba5 100644
--- a/net/ipv4/netfilter/ipt_ttl.c
+++ b/net/ipv4/netfilter/ipt_ttl.c
@@ -18,37 +18,33 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("IP tables TTL matching module");
MODULE_LICENSE("GPL");
-static int match(const struct sk_buff *skb,
- const struct net_device *in, const struct net_device *out,
- const struct xt_match *match, const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+static bool match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
{
const struct ipt_ttl_info *info = matchinfo;
const u8 ttl = ip_hdr(skb)->ttl;
switch (info->mode) {
case IPT_TTL_EQ:
- return (ttl == info->ttl);
- break;
+ return ttl == info->ttl;
case IPT_TTL_NE:
- return (!(ttl == info->ttl));
- break;
+ return ttl != info->ttl;
case IPT_TTL_LT:
- return (ttl < info->ttl);
- break;
+ return ttl < info->ttl;
case IPT_TTL_GT:
- return (ttl > info->ttl);
- break;
+ return ttl > info->ttl;
default:
printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
info->mode);
- return 0;
+ return false;
}
- return 0;
+ return false;
}
-static struct xt_match ttl_match = {
+static struct xt_match ttl_match __read_mostly = {
.name = "ttl",
.family = AF_INET,
.match = match,
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index 6dc72a815f77..64552afd01cb 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -24,12 +24,6 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
{
@@ -84,36 +78,30 @@ nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
return skb;
}
-static int
-ipv4_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
- u_int8_t *protonum)
+static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum)
{
+ struct iphdr _iph, *iph;
+
+ iph = skb_header_pointer(skb, nhoff, sizeof(_iph), &_iph);
+ if (iph == NULL)
+ return -NF_DROP;
+
/* Never happen */
- if (ip_hdr(*pskb)->frag_off & htons(IP_OFFSET)) {
+ if (iph->frag_off & htons(IP_OFFSET)) {
if (net_ratelimit()) {
- printk(KERN_ERR "ipv4_prepare: Frag of proto %u (hook=%u)\n",
- ip_hdr(*pskb)->protocol, hooknum);
+ printk(KERN_ERR "ipv4_get_l4proto: Frag of proto %u\n",
+ iph->protocol);
}
return -NF_DROP;
}
- *dataoff = skb_network_offset(*pskb) + ip_hdrlen(*pskb);
- *protonum = ip_hdr(*pskb)->protocol;
+ *dataoff = nhoff + (iph->ihl << 2);
+ *protonum = iph->protocol;
return NF_ACCEPT;
}
-int nf_nat_module_is_loaded = 0;
-EXPORT_SYMBOL_GPL(nf_nat_module_is_loaded);
-
-static u_int32_t ipv4_get_features(const struct nf_conntrack_tuple *tuple)
-{
- if (nf_nat_module_is_loaded)
- return NF_CT_F_NAT;
-
- return NF_CT_F_BASIC;
-}
-
static unsigned int ipv4_confirm(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
@@ -335,17 +323,17 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
/* We only do TCP at the moment: is there a better way? */
if (strcmp(sk->sk_prot->name, "TCP")) {
- DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n");
+ pr_debug("SO_ORIGINAL_DST: Not a TCP socket\n");
return -ENOPROTOOPT;
}
if ((unsigned int) *len < sizeof(struct sockaddr_in)) {
- DEBUGP("SO_ORIGINAL_DST: len %u not %u\n",
- *len, sizeof(struct sockaddr_in));
+ pr_debug("SO_ORIGINAL_DST: len %d not %Zu\n",
+ *len, sizeof(struct sockaddr_in));
return -EINVAL;
}
- h = nf_conntrack_find_get(&tuple, NULL);
+ h = nf_conntrack_find_get(&tuple);
if (h) {
struct sockaddr_in sin;
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
@@ -357,17 +345,17 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
.tuple.dst.u3.ip;
memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
- DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
- NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
+ pr_debug("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n",
+ NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port));
nf_ct_put(ct);
if (copy_to_user(user, &sin, sizeof(sin)) != 0)
return -EFAULT;
else
return 0;
}
- DEBUGP("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
- NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port),
- NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port));
+ pr_debug("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n",
+ NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port),
+ NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port));
return -ENOENT;
}
@@ -417,15 +405,14 @@ static struct nf_sockopt_ops so_getorigdst = {
.get = &getorigdst,
};
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
.l3proto = PF_INET,
.name = "ipv4",
.pkt_to_tuple = ipv4_pkt_to_tuple,
.invert_tuple = ipv4_invert_tuple,
.print_tuple = ipv4_print_tuple,
.print_conntrack = ipv4_print_conntrack,
- .prepare = ipv4_prepare,
- .get_features = ipv4_get_features,
+ .get_l4proto = ipv4_get_l4proto,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv4_tuple_to_nfattr,
.nfattr_to_tuple = ipv4_nfattr_to_tuple,
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
index 89f933e81035..27c7918e442a 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
@@ -18,12 +18,6 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_expect.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
#ifdef CONFIG_NF_CT_ACCT
static unsigned int
seq_print_counters(struct seq_file *s,
@@ -41,35 +35,36 @@ struct ct_iter_state {
unsigned int bucket;
};
-static struct list_head *ct_get_first(struct seq_file *seq)
+static struct hlist_node *ct_get_first(struct seq_file *seq)
{
struct ct_iter_state *st = seq->private;
for (st->bucket = 0;
st->bucket < nf_conntrack_htable_size;
st->bucket++) {
- if (!list_empty(&nf_conntrack_hash[st->bucket]))
- return nf_conntrack_hash[st->bucket].next;
+ if (!hlist_empty(&nf_conntrack_hash[st->bucket]))
+ return nf_conntrack_hash[st->bucket].first;
}
return NULL;
}
-static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head)
+static struct hlist_node *ct_get_next(struct seq_file *seq,
+ struct hlist_node *head)
{
struct ct_iter_state *st = seq->private;
head = head->next;
- while (head == &nf_conntrack_hash[st->bucket]) {
+ while (head == NULL) {
if (++st->bucket >= nf_conntrack_htable_size)
return NULL;
- head = nf_conntrack_hash[st->bucket].next;
+ head = nf_conntrack_hash[st->bucket].first;
}
return head;
}
-static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos)
+static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos)
{
- struct list_head *head = ct_get_first(seq);
+ struct hlist_node *head = ct_get_first(seq);
if (head)
while (pos && (head = ct_get_next(seq, head)))
@@ -169,7 +164,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
return 0;
}
-static struct seq_operations ct_seq_ops = {
+static const struct seq_operations ct_seq_ops = {
.start = ct_seq_start,
.next = ct_seq_next,
.stop = ct_seq_stop,
@@ -182,7 +177,7 @@ static int ct_open(struct inode *inode, struct file *file)
struct ct_iter_state *st;
int ret;
- st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
+ st = kzalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
if (st == NULL)
return -ENOMEM;
ret = seq_open(file, &ct_seq_ops);
@@ -190,7 +185,6 @@ static int ct_open(struct inode *inode, struct file *file)
goto out_free;
seq = file->private_data;
seq->private = st;
- memset(st, 0, sizeof(struct ct_iter_state));
return ret;
out_free:
kfree(st);
@@ -206,47 +200,68 @@ static const struct file_operations ct_file_ops = {
};
/* expects */
-static void *exp_seq_start(struct seq_file *s, loff_t *pos)
+struct ct_expect_iter_state {
+ unsigned int bucket;
+};
+
+static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
{
- struct list_head *e = &nf_conntrack_expect_list;
- loff_t i;
+ struct ct_expect_iter_state *st = seq->private;
- /* strange seq_file api calls stop even if we fail,
- * thus we need to grab lock since stop unlocks */
- read_lock_bh(&nf_conntrack_lock);
+ for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
+ if (!hlist_empty(&nf_ct_expect_hash[st->bucket]))
+ return nf_ct_expect_hash[st->bucket].first;
+ }
+ return NULL;
+}
- if (list_empty(e))
- return NULL;
+static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
+ struct hlist_node *head)
+{
+ struct ct_expect_iter_state *st = seq->private;
- for (i = 0; i <= *pos; i++) {
- e = e->next;
- if (e == &nf_conntrack_expect_list)
+ head = head->next;
+ while (head == NULL) {
+ if (++st->bucket >= nf_ct_expect_hsize)
return NULL;
+ head = nf_ct_expect_hash[st->bucket].first;
}
- return e;
+ return head;
}
-static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
+static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
{
- struct list_head *e = v;
+ struct hlist_node *head = ct_expect_get_first(seq);
- ++*pos;
- e = e->next;
+ if (head)
+ while (pos && (head = ct_expect_get_next(seq, head)))
+ pos--;
+ return pos ? NULL : head;
+}
- if (e == &nf_conntrack_expect_list)
- return NULL;
+static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ read_lock_bh(&nf_conntrack_lock);
+ return ct_expect_get_idx(seq, *pos);
+}
- return e;
+static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return ct_expect_get_next(seq, v);
}
-static void exp_seq_stop(struct seq_file *s, void *v)
+static void exp_seq_stop(struct seq_file *seq, void *v)
{
read_unlock_bh(&nf_conntrack_lock);
}
static int exp_seq_show(struct seq_file *s, void *v)
{
- struct nf_conntrack_expect *exp = v;
+ struct nf_conntrack_expect *exp;
+ struct hlist_node *n = v;
+
+ exp = hlist_entry(n, struct nf_conntrack_expect, hnode);
if (exp->tuple.src.l3num != AF_INET)
return 0;
@@ -266,7 +281,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
return seq_putc(s, '\n');
}
-static struct seq_operations exp_seq_ops = {
+static const struct seq_operations exp_seq_ops = {
.start = exp_seq_start,
.next = exp_seq_next,
.stop = exp_seq_stop,
@@ -275,7 +290,23 @@ static struct seq_operations exp_seq_ops = {
static int exp_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &exp_seq_ops);
+ struct seq_file *seq;
+ struct ct_expect_iter_state *st;
+ int ret;
+
+ st = kmalloc(sizeof(struct ct_expect_iter_state), GFP_KERNEL);
+ if (st == NULL)
+ return -ENOMEM;
+ ret = seq_open(file, &exp_seq_ops);
+ if (ret)
+ goto out_free;
+ seq = file->private_data;
+ seq->private = st;
+ memset(st, 0, sizeof(struct ct_expect_iter_state));
+ return ret;
+out_free:
+ kfree(st);
+ return ret;
}
static const struct file_operations ip_exp_file_ops = {
@@ -283,7 +314,7 @@ static const struct file_operations ip_exp_file_ops = {
.open = exp_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release
+ .release = seq_release_private,
};
static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
@@ -354,7 +385,7 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ct_cpu_seq_ops = {
+static const struct seq_operations ct_cpu_seq_ops = {
.start = ct_cpu_seq_start,
.next = ct_cpu_seq_next,
.stop = ct_cpu_seq_stop,
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index f4fc657c1983..6593fd2c5b10 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -21,12 +21,6 @@
static unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ;
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
static int icmp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
@@ -125,8 +119,8 @@ static int icmp_new(struct nf_conn *conntrack,
if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
|| !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
/* Can't create a new ICMP `conn' with this. */
- DEBUGP("icmp: can't create new conn with type %u\n",
- conntrack->tuplehash[0].tuple.dst.u.icmp.type);
+ pr_debug("icmp: can't create new conn with type %u\n",
+ conntrack->tuplehash[0].tuple.dst.u.icmp.type);
NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
return 0;
}
@@ -142,72 +136,42 @@ icmp_error_message(struct sk_buff *skb,
unsigned int hooknum)
{
struct nf_conntrack_tuple innertuple, origtuple;
- struct {
- struct icmphdr icmp;
- struct iphdr ip;
- } _in, *inside;
struct nf_conntrack_l4proto *innerproto;
struct nf_conntrack_tuple_hash *h;
- int dataoff;
NF_CT_ASSERT(skb->nfct == NULL);
- /* Not enough header? */
- inside = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_in), &_in);
- if (inside == NULL)
- return -NF_ACCEPT;
-
- /* Ignore ICMP's containing fragments (shouldn't happen) */
- if (inside->ip.frag_off & htons(IP_OFFSET)) {
- DEBUGP("icmp_error_message: fragment of proto %u\n",
- inside->ip.protocol);
+ /* Are they talking about one of our connections? */
+ if (!nf_ct_get_tuplepr(skb,
+ skb_network_offset(skb) + ip_hdrlen(skb)
+ + sizeof(struct icmphdr),
+ PF_INET, &origtuple)) {
+ pr_debug("icmp_error_message: failed to get tuple\n");
return -NF_ACCEPT;
}
/* rcu_read_lock()ed by nf_hook_slow */
- innerproto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
-
- dataoff = ip_hdrlen(skb) + sizeof(inside->icmp);
- /* Are they talking about one of our connections? */
- if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
- inside->ip.protocol, &origtuple,
- &nf_conntrack_l3proto_ipv4, innerproto)) {
- DEBUGP("icmp_error_message: ! get_tuple p=%u",
- inside->ip.protocol);
- return -NF_ACCEPT;
- }
+ innerproto = __nf_ct_l4proto_find(PF_INET, origtuple.dst.protonum);
/* Ordinarily, we'd expect the inverted tupleproto, but it's
been preserved inside the ICMP. */
if (!nf_ct_invert_tuple(&innertuple, &origtuple,
&nf_conntrack_l3proto_ipv4, innerproto)) {
- DEBUGP("icmp_error_message: no match\n");
+ pr_debug("icmp_error_message: no match\n");
return -NF_ACCEPT;
}
*ctinfo = IP_CT_RELATED;
- h = nf_conntrack_find_get(&innertuple, NULL);
+ h = nf_conntrack_find_get(&innertuple);
if (!h) {
- /* Locally generated ICMPs will match inverted if they
- haven't been SNAT'ed yet */
- /* FIXME: NAT code has to handle half-done double NAT --RR */
- if (hooknum == NF_IP_LOCAL_OUT)
- h = nf_conntrack_find_get(&origtuple, NULL);
-
- if (!h) {
- DEBUGP("icmp_error_message: no match\n");
- return -NF_ACCEPT;
- }
-
- /* Reverse direction from that found */
- if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
- *ctinfo += IP_CT_IS_REPLY;
- } else {
- if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
- *ctinfo += IP_CT_IS_REPLY;
+ pr_debug("icmp_error_message: no match\n");
+ return -NF_ACCEPT;
}
+ if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
+ *ctinfo += IP_CT_IS_REPLY;
+
/* Update skb to refer to this connection */
skb->nfct = &nf_ct_tuplehash_to_ctrack(h)->ct_general;
skb->nfctinfo = *ctinfo;
@@ -348,7 +312,7 @@ static struct ctl_table icmp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
{
.l3proto = PF_INET,
.l4proto = IPPROTO_ICMP,
@@ -374,4 +338,3 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp =
#endif
#endif
};
-EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_icmp);
diff --git a/net/ipv4/netfilter/nf_nat_amanda.c b/net/ipv4/netfilter/nf_nat_amanda.c
index 0f17098917bc..bd93a1d71052 100644
--- a/net/ipv4/netfilter/nf_nat_amanda.c
+++ b/net/ipv4/netfilter/nf_nat_amanda.c
@@ -45,7 +45,7 @@ static unsigned int help(struct sk_buff **pskb,
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
exp->tuple.dst.u.tcp.port = htons(port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -57,7 +57,7 @@ static unsigned int help(struct sk_buff **pskb,
matchoff, matchlen,
buffer, strlen(buffer));
if (ret != NF_ACCEPT)
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return ret;
}
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index ea02f00d2dac..e848d8d6292f 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -12,7 +12,6 @@
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/skbuff.h>
-#include <linux/vmalloc.h>
#include <net/checksum.h>
#include <net/icmp.h>
#include <net/ip.h>
@@ -32,20 +31,15 @@
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
static DEFINE_RWLOCK(nf_nat_lock);
static struct nf_conntrack_l3proto *l3proto = NULL;
/* Calculated at init based on memory size */
static unsigned int nf_nat_htable_size;
+static int nf_nat_vmalloced;
-static struct list_head *bysource;
+static struct hlist_head *bysource;
#define MAX_IP_NAT_PROTO 256
static struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO];
@@ -87,19 +81,6 @@ hash_by_src(const struct nf_conntrack_tuple *tuple)
tuple->dst.protonum, 0) % nf_nat_htable_size;
}
-/* Noone using conntrack by the time this called. */
-static void nf_nat_cleanup_conntrack(struct nf_conn *conn)
-{
- struct nf_conn_nat *nat;
- if (!(conn->status & IPS_NAT_DONE_MASK))
- return;
-
- nat = nfct_nat(conn);
- write_lock_bh(&nf_nat_lock);
- list_del(&nat->info.bysource);
- write_unlock_bh(&nf_nat_lock);
-}
-
/* Is this tuple already taken? (not by us) */
int
nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
@@ -166,10 +147,11 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple,
unsigned int h = hash_by_src(tuple);
struct nf_conn_nat *nat;
struct nf_conn *ct;
+ struct hlist_node *n;
read_lock_bh(&nf_nat_lock);
- list_for_each_entry(nat, &bysource[h], info.bysource) {
- ct = (struct nf_conn *)((char *)nat - offsetof(struct nf_conn, data));
+ hlist_for_each_entry(nat, n, &bysource[h], bysource) {
+ ct = nat->ct;
if (same_src(ct, tuple)) {
/* Copy source part from reply tuple. */
nf_ct_invert_tuplepr(result,
@@ -254,7 +236,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
manips not an issue. */
if (maniptype == IP_NAT_MANIP_SRC) {
if (find_appropriate_src(orig_tuple, tuple, range)) {
- DEBUGP("get_unique_tuple: Found current src map\n");
+ pr_debug("get_unique_tuple: Found current src map\n");
if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM))
if (!nf_nat_used_tuple(tuple, ct))
return;
@@ -296,11 +278,20 @@ nf_nat_setup_info(struct nf_conn *ct,
unsigned int hooknum)
{
struct nf_conntrack_tuple curr_tuple, new_tuple;
- struct nf_conn_nat *nat = nfct_nat(ct);
- struct nf_nat_info *info = &nat->info;
+ struct nf_conn_nat *nat;
int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK);
enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
+ /* nat helper or nfctnetlink also setup binding */
+ nat = nfct_nat(ct);
+ if (!nat) {
+ nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
+ if (nat == NULL) {
+ pr_debug("failed to add NAT extension\n");
+ return NF_ACCEPT;
+ }
+ }
+
NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING ||
hooknum == NF_IP_POST_ROUTING ||
hooknum == NF_IP_LOCAL_IN ||
@@ -337,7 +328,10 @@ nf_nat_setup_info(struct nf_conn *ct,
srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
write_lock_bh(&nf_nat_lock);
- list_add(&info->bysource, &bysource[srchash]);
+ /* nf_conntrack_alter_reply might re-allocate exntension aera */
+ nat = nfct_nat(ct);
+ nat->ct = ct;
+ hlist_add_head(&nat->bysource, &bysource[srchash]);
write_unlock_bh(&nf_nat_lock);
}
@@ -462,8 +456,9 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
return 0;
}
- DEBUGP("icmp_reply_translation: translating error %p manp %u dir %s\n",
- *pskb, manip, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
+ pr_debug("icmp_reply_translation: translating error %p manip %u "
+ "dir %s\n", *pskb, manip,
+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
/* rcu_read_lock()ed by nf_hook_slow */
l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
@@ -590,17 +585,69 @@ nf_nat_port_nfattr_to_range(struct nfattr *tb[], struct nf_nat_range *range)
EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr);
#endif
+/* Noone using conntrack by the time this called. */
+static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
+{
+ struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
+
+ if (nat == NULL || nat->ct == NULL)
+ return;
+
+ NF_CT_ASSERT(nat->ct->status & IPS_NAT_DONE_MASK);
+
+ write_lock_bh(&nf_nat_lock);
+ hlist_del(&nat->bysource);
+ nat->ct = NULL;
+ write_unlock_bh(&nf_nat_lock);
+}
+
+static void nf_nat_move_storage(struct nf_conn *conntrack, void *old)
+{
+ struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT);
+ struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old;
+ struct nf_conn *ct = old_nat->ct;
+ unsigned int srchash;
+
+ if (!(ct->status & IPS_NAT_DONE_MASK))
+ return;
+
+ srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+
+ write_lock_bh(&nf_nat_lock);
+ hlist_replace_rcu(&old_nat->bysource, &new_nat->bysource);
+ new_nat->ct = ct;
+ write_unlock_bh(&nf_nat_lock);
+}
+
+static struct nf_ct_ext_type nat_extend __read_mostly = {
+ .len = sizeof(struct nf_conn_nat),
+ .align = __alignof__(struct nf_conn_nat),
+ .destroy = nf_nat_cleanup_conntrack,
+ .move = nf_nat_move_storage,
+ .id = NF_CT_EXT_NAT,
+ .flags = NF_CT_EXT_F_PREALLOC,
+};
+
static int __init nf_nat_init(void)
{
size_t i;
+ int ret;
+
+ ret = nf_ct_extend_register(&nat_extend);
+ if (ret < 0) {
+ printk(KERN_ERR "nf_nat_core: Unable to register extension\n");
+ return ret;
+ }
/* Leave them the same for the moment. */
nf_nat_htable_size = nf_conntrack_htable_size;
- /* One vmalloc for both hash tables */
- bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size);
- if (!bysource)
- return -ENOMEM;
+ bysource = nf_ct_alloc_hashtable(&nf_nat_htable_size,
+ &nf_nat_vmalloced);
+ if (!bysource) {
+ ret = -ENOMEM;
+ goto cleanup_extend;
+ }
/* Sew in builtin protocols. */
write_lock_bh(&nf_nat_lock);
@@ -612,18 +659,18 @@ static int __init nf_nat_init(void)
write_unlock_bh(&nf_nat_lock);
for (i = 0; i < nf_nat_htable_size; i++) {
- INIT_LIST_HEAD(&bysource[i]);
+ INIT_HLIST_HEAD(&bysource[i]);
}
- /* FIXME: Man, this is a hack. <SIGH> */
- NF_CT_ASSERT(rcu_dereference(nf_conntrack_destroyed) == NULL);
- rcu_assign_pointer(nf_conntrack_destroyed, nf_nat_cleanup_conntrack);
-
/* Initialize fake conntrack so that NAT will skip it */
nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK;
l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET);
return 0;
+
+ cleanup_extend:
+ nf_ct_extend_unregister(&nat_extend);
+ return ret;
}
/* Clear NAT section of all conntracks, in case we're loaded again. */
@@ -641,10 +688,10 @@ static int clean_nat(struct nf_conn *i, void *data)
static void __exit nf_nat_cleanup(void)
{
nf_ct_iterate_cleanup(&clean_nat, NULL);
- rcu_assign_pointer(nf_conntrack_destroyed, NULL);
synchronize_rcu();
- vfree(bysource);
+ nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size);
nf_ct_l3proto_put(l3proto);
+ nf_ct_extend_unregister(&nat_extend);
}
MODULE_LICENSE("GPL");
diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c
index e6bc8e5a72f1..3663bd879c39 100644
--- a/net/ipv4/netfilter/nf_nat_ftp.c
+++ b/net/ipv4/netfilter/nf_nat_ftp.c
@@ -25,12 +25,6 @@ MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
MODULE_DESCRIPTION("ftp NAT helper");
MODULE_ALIAS("ip_nat_ftp");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* FIXME: Time out? --RR */
static int
@@ -47,7 +41,7 @@ mangle_rfc959_packet(struct sk_buff **pskb,
sprintf(buffer, "%u,%u,%u,%u,%u,%u",
NIPQUAD(newip), port>>8, port&0xFF);
- DEBUGP("calling nf_nat_mangle_tcp_packet\n");
+ pr_debug("calling nf_nat_mangle_tcp_packet\n");
return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
@@ -67,7 +61,7 @@ mangle_eprt_packet(struct sk_buff **pskb,
sprintf(buffer, "|1|%u.%u.%u.%u|%u|", NIPQUAD(newip), port);
- DEBUGP("calling nf_nat_mangle_tcp_packet\n");
+ pr_debug("calling nf_nat_mangle_tcp_packet\n");
return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
@@ -87,7 +81,7 @@ mangle_epsv_packet(struct sk_buff **pskb,
sprintf(buffer, "|||%u|", port);
- DEBUGP("calling nf_nat_mangle_tcp_packet\n");
+ pr_debug("calling nf_nat_mangle_tcp_packet\n");
return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff,
matchlen, buffer, strlen(buffer));
@@ -117,7 +111,7 @@ static unsigned int nf_nat_ftp(struct sk_buff **pskb,
int dir = CTINFO2DIR(ctinfo);
struct nf_conn *ct = exp->master;
- DEBUGP("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
+ pr_debug("FTP_NAT: type %i, off %u len %u\n", type, matchoff, matchlen);
/* Connection will come from wherever this packet goes, hence !dir */
newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
@@ -131,7 +125,7 @@ static unsigned int nf_nat_ftp(struct sk_buff **pskb,
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
exp->tuple.dst.u.tcp.port = htons(port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -139,7 +133,7 @@ static unsigned int nf_nat_ftp(struct sk_buff **pskb,
return NF_DROP;
if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo)) {
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return NF_DROP;
}
return NF_ACCEPT;
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index c5d2a2d690b8..c1b059a73708 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -21,12 +21,6 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_h323.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/****************************************************************************/
static int set_addr(struct sk_buff **pskb,
unsigned char **data, int dataoff,
@@ -126,12 +120,11 @@ static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
(ntohl(addr.ip) & 0xff000000) == 0x7f000000)
i = 0;
- DEBUGP
- ("nf_nat_ras: set signal address "
- "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(ip), port,
- NIPQUAD(ct->tuplehash[!dir].tuple.dst.
- ip), info->sig_port[!dir]);
+ pr_debug("nf_nat_ras: set signal address "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(addr.ip), port,
+ NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
+ info->sig_port[!dir]);
return set_h225_addr(pskb, data, 0, &taddr[i],
&ct->tuplehash[!dir].
tuple.dst.u3,
@@ -139,12 +132,11 @@ static int set_sig_addr(struct sk_buff **pskb, struct nf_conn *ct,
} else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
port == info->sig_port[dir]) {
/* GK->GW */
- DEBUGP
- ("nf_nat_ras: set signal address "
- "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(ip), port,
- NIPQUAD(ct->tuplehash[!dir].tuple.src.
- ip), info->sig_port[!dir]);
+ pr_debug("nf_nat_ras: set signal address "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(addr.ip), port,
+ NIPQUAD(ct->tuplehash[!dir].tuple.src.u3.ip),
+ info->sig_port[!dir]);
return set_h225_addr(pskb, data, 0, &taddr[i],
&ct->tuplehash[!dir].
tuple.src.u3,
@@ -171,12 +163,11 @@ static int set_ras_addr(struct sk_buff **pskb, struct nf_conn *ct,
if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
port == ct->tuplehash[dir].tuple.src.u.udp.port) {
- DEBUGP("nf_nat_ras: set rasAddress "
- "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(ip), ntohs(port),
- NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
- ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.
- port));
+ pr_debug("nf_nat_ras: set rasAddress "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(addr.ip), ntohs(port),
+ NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip),
+ ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port));
return set_h225_addr(pskb, data, 0, &taddr[i],
&ct->tuplehash[!dir].tuple.dst.u3,
ct->tuplehash[!dir].tuple.
@@ -237,12 +228,12 @@ static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
nated_port != 0; nated_port += 2) {
rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
- if (nf_conntrack_expect_related(rtp_exp) == 0) {
+ if (nf_ct_expect_related(rtp_exp) == 0) {
rtcp_exp->tuple.dst.u.udp.port =
htons(nated_port + 1);
- if (nf_conntrack_expect_related(rtcp_exp) == 0)
+ if (nf_ct_expect_related(rtcp_exp) == 0)
break;
- nf_conntrack_unexpect_related(rtp_exp);
+ nf_ct_unexpect_related(rtp_exp);
}
}
@@ -261,22 +252,22 @@ static int nat_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
info->rtp_port[i][dir] = rtp_port;
info->rtp_port[i][!dir] = htons(nated_port);
} else {
- nf_conntrack_unexpect_related(rtp_exp);
- nf_conntrack_unexpect_related(rtcp_exp);
+ nf_ct_unexpect_related(rtp_exp);
+ nf_ct_unexpect_related(rtcp_exp);
return -1;
}
/* Success */
- DEBUGP("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(rtp_exp->tuple.src.ip),
- ntohs(rtp_exp->tuple.src.u.udp.port),
- NIPQUAD(rtp_exp->tuple.dst.ip),
- ntohs(rtp_exp->tuple.dst.u.udp.port));
- DEBUGP("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(rtcp_exp->tuple.src.ip),
- ntohs(rtcp_exp->tuple.src.u.udp.port),
- NIPQUAD(rtcp_exp->tuple.dst.ip),
- ntohs(rtcp_exp->tuple.dst.u.udp.port));
+ pr_debug("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(rtp_exp->tuple.src.u3.ip),
+ ntohs(rtp_exp->tuple.src.u.udp.port),
+ NIPQUAD(rtp_exp->tuple.dst.u3.ip),
+ ntohs(rtp_exp->tuple.dst.u.udp.port));
+ pr_debug("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(rtcp_exp->tuple.src.u3.ip),
+ ntohs(rtcp_exp->tuple.src.u.udp.port),
+ NIPQUAD(rtcp_exp->tuple.dst.u3.ip),
+ ntohs(rtcp_exp->tuple.dst.u.udp.port));
return 0;
}
@@ -299,7 +290,7 @@ static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (; nated_port != 0; nated_port++) {
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -313,13 +304,15 @@ static int nat_t120(struct sk_buff **pskb, struct nf_conn *ct,
if (set_h245_addr(pskb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) < 0) {
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return -1;
}
- DEBUGP("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
- NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+ pr_debug("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(exp->tuple.src.u3.ip),
+ ntohs(exp->tuple.src.u.tcp.port),
+ NIPQUAD(exp->tuple.dst.u3.ip),
+ ntohs(exp->tuple.dst.u.tcp.port));
return 0;
}
@@ -347,7 +340,7 @@ static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (; nated_port != 0; nated_port++) {
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -365,13 +358,15 @@ static int nat_h245(struct sk_buff **pskb, struct nf_conn *ct,
info->sig_port[dir] = port;
info->sig_port[!dir] = htons(nated_port);
} else {
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return -1;
}
- DEBUGP("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
- NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+ pr_debug("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(exp->tuple.src.u3.ip),
+ ntohs(exp->tuple.src.u.tcp.port),
+ NIPQUAD(exp->tuple.dst.u3.ip),
+ ntohs(exp->tuple.dst.u.tcp.port));
return 0;
}
@@ -433,7 +428,7 @@ static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (; nated_port != 0; nated_port++) {
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -460,14 +455,16 @@ static int nat_q931(struct sk_buff **pskb, struct nf_conn *ct,
info->sig_port[!dir]);
}
} else {
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return -1;
}
/* Success */
- DEBUGP("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
- NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+ pr_debug("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(exp->tuple.src.u3.ip),
+ ntohs(exp->tuple.src.u.tcp.port),
+ NIPQUAD(exp->tuple.dst.u3.ip),
+ ntohs(exp->tuple.dst.u.tcp.port));
return 0;
}
@@ -517,7 +514,7 @@ static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct,
/* Try to get same port: if not, try to change it. */
for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
exp->tuple.dst.u.tcp.port = htons(nated_port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -531,15 +528,17 @@ static int nat_callforwarding(struct sk_buff **pskb, struct nf_conn *ct,
if (!set_h225_addr(pskb, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons(nated_port)) == 0) {
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return -1;
}
/* Success */
- DEBUGP("nf_nat_q931: expect Call Forwarding "
- "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port),
- NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port));
+ pr_debug("nf_nat_q931: expect Call Forwarding "
+ "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
+ NIPQUAD(exp->tuple.src.u3.ip),
+ ntohs(exp->tuple.src.u.tcp.port),
+ NIPQUAD(exp->tuple.dst.u3.ip),
+ ntohs(exp->tuple.dst.u.tcp.port));
return 0;
}
@@ -566,8 +565,6 @@ static int __init init(void)
rcu_assign_pointer(nat_h245_hook, nat_h245);
rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding);
rcu_assign_pointer(nat_q931_hook, nat_q931);
-
- DEBUGP("nf_nat_h323: init success\n");
return 0;
}
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 15b6e5ce3a04..93d8a0a8f035 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -26,13 +26,9 @@
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_helper.h>
-#if 0
-#define DEBUGP printk
-#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
-#else
-#define DEBUGP(format, args...)
-#define DUMP_OFFSET(x)
-#endif
+#define DUMP_OFFSET(x) \
+ pr_debug("offset_before=%d, offset_after=%d, correction_pos=%u\n", \
+ x->offset_before, x->offset_after, x->correction_pos);
static DEFINE_SPINLOCK(nf_nat_seqofs_lock);
@@ -47,15 +43,15 @@ adjust_tcp_sequence(u32 seq,
struct nf_nat_seq *this_way, *other_way;
struct nf_conn_nat *nat = nfct_nat(ct);
- DEBUGP("nf_nat_resize_packet: old_size = %u, new_size = %u\n",
- (*skb)->len, new_size);
+ pr_debug("adjust_tcp_sequence: seq = %u, sizediff = %d\n",
+ ntohl(seq), seq);
dir = CTINFO2DIR(ctinfo);
- this_way = &nat->info.seq[dir];
- other_way = &nat->info.seq[!dir];
+ this_way = &nat->seq[dir];
+ other_way = &nat->seq[!dir];
- DEBUGP("nf_nat_resize_packet: Seq_offset before: ");
+ pr_debug("nf_nat_resize_packet: Seq_offset before: ");
DUMP_OFFSET(this_way);
spin_lock_bh(&nf_nat_seqofs_lock);
@@ -72,7 +68,7 @@ adjust_tcp_sequence(u32 seq,
}
spin_unlock_bh(&nf_nat_seqofs_lock);
- DEBUGP("nf_nat_resize_packet: Seq_offset after: ");
+ pr_debug("nf_nat_resize_packet: Seq_offset after: ");
DUMP_OFFSET(this_way);
}
@@ -100,14 +96,12 @@ static void mangle_contents(struct sk_buff *skb,
/* update skb info */
if (rep_len > match_len) {
- DEBUGP("nf_nat_mangle_packet: Extending packet by "
- "%u from %u bytes\n", rep_len - match_len,
- skb->len);
+ pr_debug("nf_nat_mangle_packet: Extending packet by "
+ "%u from %u bytes\n", rep_len - match_len, skb->len);
skb_put(skb, rep_len - match_len);
} else {
- DEBUGP("nf_nat_mangle_packet: Shrinking packet from "
- "%u from %u bytes\n", match_len - rep_len,
- skb->len);
+ pr_debug("nf_nat_mangle_packet: Shrinking packet from "
+ "%u from %u bytes\n", match_len - rep_len, skb->len);
__skb_trim(skb, skb->len + rep_len - match_len);
}
@@ -178,7 +172,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
datalen = (*pskb)->len - iph->ihl*4;
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
if (!(rt->rt_flags & RTCF_LOCAL) &&
- (*pskb)->dev->features & NETIF_F_ALL_CSUM) {
+ (*pskb)->dev->features & NETIF_F_V4_CSUM) {
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
(*pskb)->csum_start = skb_headroom(*pskb) +
skb_network_offset(*pskb) +
@@ -190,7 +184,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff **pskb,
tcph->check = 0;
tcph->check = tcp_v4_check(datalen,
iph->saddr, iph->daddr,
- csum_partial((char *)tcph,
+ csum_partial(tcph,
datalen, 0));
}
} else
@@ -265,7 +259,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
if ((*pskb)->ip_summed != CHECKSUM_PARTIAL) {
if (!(rt->rt_flags & RTCF_LOCAL) &&
- (*pskb)->dev->features & NETIF_F_ALL_CSUM) {
+ (*pskb)->dev->features & NETIF_F_V4_CSUM) {
(*pskb)->ip_summed = CHECKSUM_PARTIAL;
(*pskb)->csum_start = skb_headroom(*pskb) +
skb_network_offset(*pskb) +
@@ -278,7 +272,7 @@ nf_nat_mangle_udp_packet(struct sk_buff **pskb,
udph->check = 0;
udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, IPPROTO_UDP,
- csum_partial((char *)udph,
+ csum_partial(udph,
datalen, 0));
if (!udph->check)
udph->check = CSUM_MANGLED_0;
@@ -320,9 +314,9 @@ sack_adjust(struct sk_buff *skb,
new_end_seq = htonl(ntohl(sack->end_seq)
- natseq->offset_before);
- DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
- ntohl(sack->start_seq), new_start_seq,
- ntohl(sack->end_seq), new_end_seq);
+ pr_debug("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
+ ntohl(sack->start_seq), new_start_seq,
+ ntohl(sack->end_seq), new_end_seq);
nf_proto_csum_replace4(&tcph->check, skb,
sack->start_seq, new_start_seq, 0);
@@ -372,8 +366,7 @@ nf_nat_sack_adjust(struct sk_buff **pskb,
op[1] >= 2+TCPOLEN_SACK_PERBLOCK &&
((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
sack_adjust(*pskb, tcph, optoff+2,
- optoff+op[1],
- &nat->info.seq[!dir]);
+ optoff+op[1], &nat->seq[!dir]);
optoff += op[1];
}
}
@@ -394,8 +387,8 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
dir = CTINFO2DIR(ctinfo);
- this_way = &nat->info.seq[dir];
- other_way = &nat->info.seq[!dir];
+ this_way = &nat->seq[dir];
+ other_way = &nat->seq[!dir];
if (!skb_make_writable(pskb, ip_hdrlen(*pskb) + sizeof(*tcph)))
return 0;
@@ -415,9 +408,9 @@ nf_nat_seq_adjust(struct sk_buff **pskb,
nf_proto_csum_replace4(&tcph->check, *pskb, tcph->seq, newseq, 0);
nf_proto_csum_replace4(&tcph->check, *pskb, tcph->ack_seq, newack, 0);
- DEBUGP("Adjusting sequence number from %u->%u, ack from %u->%u\n",
- ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
- ntohl(newack));
+ pr_debug("Adjusting sequence number from %u->%u, ack from %u->%u\n",
+ ntohl(tcph->seq), ntohl(newseq), ntohl(tcph->ack_seq),
+ ntohl(newack));
tcph->seq = newseq;
tcph->ack_seq = newack;
diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c
index 9b8c0daea744..bcf274bba602 100644
--- a/net/ipv4/netfilter/nf_nat_irc.c
+++ b/net/ipv4/netfilter/nf_nat_irc.c
@@ -22,12 +22,6 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <linux/netfilter/nf_conntrack_irc.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("IRC (DCC) NAT helper");
MODULE_LICENSE("GPL");
@@ -44,9 +38,6 @@ static unsigned int help(struct sk_buff **pskb,
u_int16_t port;
unsigned int ret;
- DEBUGP("IRC_NAT: info (seq %u + %u) in %u\n",
- expect->seq, exp_irc_info->len, ntohl(tcph->seq));
-
/* Reply comes from server. */
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
exp->dir = IP_CT_DIR_REPLY;
@@ -55,7 +46,7 @@ static unsigned int help(struct sk_buff **pskb,
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
exp->tuple.dst.u.tcp.port = htons(port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -64,14 +55,14 @@ static unsigned int help(struct sk_buff **pskb,
ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip);
sprintf(buffer, "%u %u", ip, port);
- DEBUGP("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n",
- buffer, NIPQUAD(ip), port);
+ pr_debug("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n",
+ buffer, NIPQUAD(ip), port);
ret = nf_nat_mangle_tcp_packet(pskb, exp->master, ctinfo,
matchoff, matchlen, buffer,
strlen(buffer));
if (ret != NF_ACCEPT)
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return ret;
}
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index a66888749ceb..984ec8308b2e 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -37,14 +37,6 @@ MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP");
MODULE_ALIAS("ip_nat_pptp");
-#if 0
-extern const char *pptp_msg_name[];
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \
- __FUNCTION__, ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
static void pptp_nat_expected(struct nf_conn *ct,
struct nf_conntrack_expect *exp)
{
@@ -60,7 +52,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
/* And here goes the grand finale of corrosion... */
if (exp->dir == IP_CT_DIR_ORIGINAL) {
- DEBUGP("we are PNS->PAC\n");
+ pr_debug("we are PNS->PAC\n");
/* therefore, build tuple for PAC->PNS */
t.src.l3num = AF_INET;
t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip;
@@ -69,7 +61,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
t.dst.u.gre.key = ct_pptp_info->pns_call_id;
t.dst.protonum = IPPROTO_GRE;
} else {
- DEBUGP("we are PAC->PNS\n");
+ pr_debug("we are PAC->PNS\n");
/* build tuple for PNS->PAC */
t.src.l3num = AF_INET;
t.src.u3.ip = master->tuplehash[!exp->dir].tuple.src.u3.ip;
@@ -79,15 +71,15 @@ static void pptp_nat_expected(struct nf_conn *ct,
t.dst.protonum = IPPROTO_GRE;
}
- DEBUGP("trying to unexpect other dir: ");
+ pr_debug("trying to unexpect other dir: ");
NF_CT_DUMP_TUPLE(&t);
- other_exp = nf_conntrack_expect_find_get(&t);
+ other_exp = nf_ct_expect_find_get(&t);
if (other_exp) {
- nf_conntrack_unexpect_related(other_exp);
- nf_conntrack_expect_put(other_exp);
- DEBUGP("success\n");
+ nf_ct_unexpect_related(other_exp);
+ nf_ct_expect_put(other_exp);
+ pr_debug("success\n");
} else {
- DEBUGP("not found!\n");
+ pr_debug("not found!\n");
}
/* This must be a fresh one. */
@@ -161,9 +153,9 @@ pptp_outbound_pkt(struct sk_buff **pskb,
cid_off = offsetof(union pptp_ctrl_union, clrreq.callID);
break;
default:
- DEBUGP("unknown outbound packet 0x%04x:%s\n", msg,
- (msg <= PPTP_MSG_MAX)?
- pptp_msg_name[msg]:pptp_msg_name[0]);
+ pr_debug("unknown outbound packet 0x%04x:%s\n", msg,
+ msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] :
+ pptp_msg_name[0]);
/* fall through */
case PPTP_SET_LINK_INFO:
/* only need to NAT in case PAC is behind NAT box */
@@ -179,8 +171,8 @@ pptp_outbound_pkt(struct sk_buff **pskb,
/* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass
* down to here */
- DEBUGP("altering call id from 0x%04x to 0x%04x\n",
- ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
+ pr_debug("altering call id from 0x%04x to 0x%04x\n",
+ ntohs(REQ_CID(pptpReq, cid_off)), ntohs(new_callid));
/* mangle packet */
if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
@@ -255,8 +247,9 @@ pptp_inbound_pkt(struct sk_buff **pskb,
pcid_off = offsetof(union pptp_ctrl_union, setlink.peersCallID);
break;
default:
- DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)?
- pptp_msg_name[msg]:pptp_msg_name[0]);
+ pr_debug("unknown inbound packet %s\n",
+ msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] :
+ pptp_msg_name[0]);
/* fall through */
case PPTP_START_SESSION_REQUEST:
case PPTP_START_SESSION_REPLY:
@@ -272,8 +265,8 @@ pptp_inbound_pkt(struct sk_buff **pskb,
* WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */
/* mangle packet */
- DEBUGP("altering peer call id from 0x%04x to 0x%04x\n",
- ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
+ pr_debug("altering peer call id from 0x%04x to 0x%04x\n",
+ ntohs(REQ_CID(pptpReq, pcid_off)), ntohs(new_pcid));
if (nf_nat_mangle_tcp_packet(pskb, ct, ctinfo,
pcid_off + sizeof(struct pptp_pkt_hdr) +
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index c3908bc5a709..2e40cc83526a 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -36,13 +36,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE");
-#if 0
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \
- __FUNCTION__, ## args)
-#else
-#define DEBUGP(x, args...)
-#endif
-
/* is key in given range between min and max */
static int
gre_in_range(const struct nf_conntrack_tuple *tuple,
@@ -83,7 +76,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
keyptr = &tuple->dst.u.gre.key;
if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) {
- DEBUGP("%p: NATing GRE PPTP\n", conntrack);
+ pr_debug("%p: NATing GRE PPTP\n", conntrack);
min = 1;
range_size = 0xffff;
} else {
@@ -91,7 +84,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
range_size = ntohs(range->max.gre.key) - min + 1;
}
- DEBUGP("min = %u, range_size = %u\n", min, range_size);
+ pr_debug("min = %u, range_size = %u\n", min, range_size);
for (i = 0; i < range_size; i++, key++) {
*keyptr = htons(min + key % range_size);
@@ -99,7 +92,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple,
return 1;
}
- DEBUGP("%p: no NAT mapping\n", conntrack);
+ pr_debug("%p: no NAT mapping\n", conntrack);
return 0;
}
@@ -132,11 +125,11 @@ gre_manip_pkt(struct sk_buff **pskb, unsigned int iphdroff,
* Try to behave like "nf_nat_proto_unknown" */
break;
case GRE_VERSION_PPTP:
- DEBUGP("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
+ pr_debug("call_id -> 0x%04x\n", ntohs(tuple->dst.u.gre.key));
pgreh->call_id = tuple->dst.u.gre.key;
break;
default:
- DEBUGP("can't nat unknown GRE version\n");
+ pr_debug("can't nat unknown GRE version\n");
return 0;
}
return 1;
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 6740736c5e79..0f45427e5fdc 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -24,12 +24,6 @@
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_rule.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
#define NAT_VALID_HOOKS ((1<<NF_IP_PRE_ROUTING) | (1<<NF_IP_POST_ROUTING) | (1<<NF_IP_LOCAL_OUT))
static struct
@@ -140,39 +134,39 @@ static unsigned int ipt_dnat_target(struct sk_buff **pskb,
return nf_nat_setup_info(ct, &mr->range[0], hooknum);
}
-static int ipt_snat_checkentry(const char *tablename,
- const void *entry,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
+static bool ipt_snat_checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
{
struct nf_nat_multi_range_compat *mr = targinfo;
/* Must be a valid range */
if (mr->rangesize != 1) {
printk("SNAT: multiple ranges no longer supported\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static int ipt_dnat_checkentry(const char *tablename,
- const void *entry,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
+static bool ipt_dnat_checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
{
struct nf_nat_multi_range_compat *mr = targinfo;
/* Must be a valid range */
if (mr->rangesize != 1) {
printk("DNAT: multiple ranges no longer supported\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-inline unsigned int
+unsigned int
alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
{
/* Force range to this IP; let proto decide mapping for
@@ -186,8 +180,8 @@ alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
struct nf_nat_range range
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } };
- DEBUGP("Allocating NULL binding for %p (%u.%u.%u.%u)\n",
- ct, NIPQUAD(ip));
+ pr_debug("Allocating NULL binding for %p (%u.%u.%u.%u)\n",
+ ct, NIPQUAD(ip));
return nf_nat_setup_info(ct, &range, hooknum);
}
@@ -205,8 +199,8 @@ alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
struct nf_nat_range range
= { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } };
- DEBUGP("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
- ct, NIPQUAD(ip));
+ pr_debug("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n",
+ ct, NIPQUAD(ip));
return nf_nat_setup_info(ct, &range, hooknum);
}
@@ -228,7 +222,7 @@ int nf_nat_rule_find(struct sk_buff **pskb,
return ret;
}
-static struct xt_target ipt_snat_reg = {
+static struct xt_target ipt_snat_reg __read_mostly = {
.name = "SNAT",
.target = ipt_snat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
@@ -238,7 +232,7 @@ static struct xt_target ipt_snat_reg = {
.family = AF_INET,
};
-static struct xt_target ipt_dnat_reg = {
+static struct xt_target ipt_dnat_reg __read_mostly = {
.name = "DNAT",
.target = ipt_dnat_target,
.targetsize = sizeof(struct nf_nat_multi_range_compat),
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index fac97cf51ae5..a889ec3ec83a 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -26,12 +26,6 @@ MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
MODULE_DESCRIPTION("SIP NAT helper");
MODULE_ALIAS("ip_nat_sip");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
struct addr_map {
struct {
char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
@@ -257,10 +251,12 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
__be32 newip;
u_int16_t port;
- DEBUGP("ip_nat_sdp():\n");
-
/* Connection will come from reply */
- newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+ if (ct->tuplehash[dir].tuple.src.u3.ip ==
+ ct->tuplehash[!dir].tuple.dst.u3.ip)
+ newip = exp->tuple.dst.u3.ip;
+ else
+ newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
exp->saved_ip = exp->tuple.dst.u3.ip;
exp->tuple.dst.u3.ip = newip;
@@ -274,7 +270,7 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
/* Try to get same port: if not, try to change it. */
for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
exp->tuple.dst.u.udp.port = htons(port);
- if (nf_conntrack_expect_related(exp) == 0)
+ if (nf_ct_expect_related(exp) == 0)
break;
}
@@ -282,7 +278,7 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
return NF_DROP;
if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
return NF_DROP;
}
return NF_ACCEPT;
diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c
index 6e88505d6162..6bfcd3a90f08 100644
--- a/net/ipv4/netfilter/nf_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c
@@ -1276,9 +1276,6 @@ static struct nf_conntrack_helper snmp_helper __read_mostly = {
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(SNMP_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
};
static struct nf_conntrack_helper snmp_trap_helper __read_mostly = {
@@ -1290,9 +1287,6 @@ static struct nf_conntrack_helper snmp_trap_helper __read_mostly = {
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(SNMP_TRAP_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
};
/*****************************************************************************
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 55dac36dbc85..332814dac503 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -19,6 +19,7 @@
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_nat_protocol.h>
@@ -26,12 +27,6 @@
#include <net/netfilter/nf_nat_helper.h>
#include <linux/netfilter_ipv4/ip_tables.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
#ifdef CONFIG_XFRM
static void nat_decode_session(struct sk_buff *skb, struct flowi *fl)
{
@@ -113,8 +108,13 @@ nf_nat_fn(unsigned int hooknum,
return NF_ACCEPT;
nat = nfct_nat(ct);
- if (!nat)
- return NF_ACCEPT;
+ if (!nat) {
+ nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
+ if (nat == NULL) {
+ pr_debug("failed to add NAT extension\n");
+ return NF_ACCEPT;
+ }
+ }
switch (ctinfo) {
case IP_CT_RELATED:
@@ -148,9 +148,9 @@ nf_nat_fn(unsigned int hooknum,
return ret;
}
} else
- DEBUGP("Already setup manip %s for ct %p\n",
- maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
- ct);
+ pr_debug("Already setup manip %s for ct %p\n",
+ maniptype == IP_NAT_MANIP_SRC ? "SRC" : "DST",
+ ct);
break;
default:
@@ -264,7 +264,7 @@ nf_nat_adjust(unsigned int hooknum,
ct = nf_ct_get(*pskb, &ctinfo);
if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) {
- DEBUGP("nf_nat_standalone: adjusting sequence number\n");
+ pr_debug("nf_nat_standalone: adjusting sequence number\n");
if (!nf_nat_seq_adjust(pskb, ct, ctinfo))
return NF_DROP;
}
@@ -326,26 +326,10 @@ static struct nf_hook_ops nf_nat_ops[] = {
static int __init nf_nat_standalone_init(void)
{
- int size, ret = 0;
+ int ret = 0;
need_conntrack();
- size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) +
- sizeof(struct nf_conn_nat);
- ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size);
- if (ret < 0) {
- printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n");
- return ret;
- }
-
- size = ALIGN(size, __alignof__(struct nf_conn_help)) +
- sizeof(struct nf_conn_help);
- ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP,
- "nf_nat:help", size);
- if (ret < 0) {
- printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n");
- goto cleanup_register_cache;
- }
#ifdef CONFIG_XFRM
BUG_ON(ip_nat_decode_session != NULL);
ip_nat_decode_session = nat_decode_session;
@@ -360,7 +344,6 @@ static int __init nf_nat_standalone_init(void)
printk("nf_nat_init: can't register hooks.\n");
goto cleanup_rule_init;
}
- nf_nat_module_is_loaded = 1;
return ret;
cleanup_rule_init:
@@ -370,9 +353,6 @@ static int __init nf_nat_standalone_init(void)
ip_nat_decode_session = NULL;
synchronize_net();
#endif
- nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP);
- cleanup_register_cache:
- nf_conntrack_unregister_cache(NF_CT_F_NAT);
return ret;
}
@@ -380,7 +360,6 @@ static void __exit nf_nat_standalone_fini(void)
{
nf_unregister_hooks(nf_nat_ops, ARRAY_SIZE(nf_nat_ops));
nf_nat_rule_cleanup();
- nf_nat_module_is_loaded = 0;
#ifdef CONFIG_XFRM
ip_nat_decode_session = NULL;
synchronize_net();
diff --git a/net/ipv4/netfilter/nf_nat_tftp.c b/net/ipv4/netfilter/nf_nat_tftp.c
index 2566b79de224..04dfeaefec02 100644
--- a/net/ipv4/netfilter/nf_nat_tftp.c
+++ b/net/ipv4/netfilter/nf_nat_tftp.c
@@ -30,7 +30,7 @@ static unsigned int help(struct sk_buff **pskb,
= ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port;
exp->dir = IP_CT_DIR_REPLY;
exp->expectfn = nf_nat_follow_master;
- if (nf_conntrack_expect_related(exp) != 0)
+ if (nf_ct_expect_related(exp) != 0)
return NF_DROP;
return NF_ACCEPT;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 29ca63e81ced..df42b7fb3268 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -101,7 +101,6 @@
#include <net/tcp.h>
#include <net/icmp.h>
#include <net/xfrm.h>
-#include <net/ip_mp_alg.h>
#include <net/netevent.h>
#include <net/rtnetlink.h>
#ifdef CONFIG_SYSCTL
@@ -168,7 +167,7 @@ static struct dst_ops ipv4_dst_ops = {
#define ECN_OR_COST(class) TC_PRIO_##class
-__u8 ip_tos2prio[16] = {
+const __u8 ip_tos2prio[16] = {
TC_PRIO_BESTEFFORT,
ECN_OR_COST(FILLER),
TC_PRIO_BESTEFFORT,
@@ -495,13 +494,11 @@ static const struct file_operations rt_cpu_seq_fops = {
static __inline__ void rt_free(struct rtable *rt)
{
- multipath_remove(rt);
call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
}
static __inline__ void rt_drop(struct rtable *rt)
{
- multipath_remove(rt);
ip_rt_put(rt);
call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
}
@@ -574,52 +571,6 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
(fl1->iif ^ fl2->iif)) == 0;
}
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
-static struct rtable **rt_remove_balanced_route(struct rtable **chain_head,
- struct rtable *expentry,
- int *removed_count)
-{
- int passedexpired = 0;
- struct rtable **nextstep = NULL;
- struct rtable **rthp = chain_head;
- struct rtable *rth;
-
- if (removed_count)
- *removed_count = 0;
-
- while ((rth = *rthp) != NULL) {
- if (rth == expentry)
- passedexpired = 1;
-
- if (((*rthp)->u.dst.flags & DST_BALANCED) != 0 &&
- compare_keys(&(*rthp)->fl, &expentry->fl)) {
- if (*rthp == expentry) {
- *rthp = rth->u.dst.rt_next;
- continue;
- } else {
- *rthp = rth->u.dst.rt_next;
- rt_free(rth);
- if (removed_count)
- ++(*removed_count);
- }
- } else {
- if (!((*rthp)->u.dst.flags & DST_BALANCED) &&
- passedexpired && !nextstep)
- nextstep = &rth->u.dst.rt_next;
-
- rthp = &rth->u.dst.rt_next;
- }
- }
-
- rt_free(expentry);
- if (removed_count)
- ++(*removed_count);
-
- return nextstep;
-}
-#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
-
-
/* This runs via a timer and thus is always in BH context. */
static void rt_check_expire(unsigned long dummy)
{
@@ -658,22 +609,8 @@ static void rt_check_expire(unsigned long dummy)
}
/* Cleanup aged off entries. */
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- /* remove all related balanced entries if necessary */
- if (rth->u.dst.flags & DST_BALANCED) {
- rthp = rt_remove_balanced_route(
- &rt_hash_table[i].chain,
- rth, NULL);
- if (!rthp)
- break;
- } else {
- *rthp = rth->u.dst.rt_next;
- rt_free(rth);
- }
-#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
*rthp = rth->u.dst.rt_next;
rt_free(rth);
-#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
}
spin_unlock(rt_hash_lock_addr(i));
@@ -721,9 +658,6 @@ void rt_cache_flush(int delay)
if (delay < 0)
delay = ip_rt_min_delay;
- /* flush existing multipath state*/
- multipath_flush();
-
spin_lock_bh(&rt_flush_lock);
if (del_timer(&rt_flush_timer) && delay > 0 && rt_deadline) {
@@ -842,30 +776,9 @@ static int rt_garbage_collect(void)
rthp = &rth->u.dst.rt_next;
continue;
}
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- /* remove all related balanced entries
- * if necessary
- */
- if (rth->u.dst.flags & DST_BALANCED) {
- int r;
-
- rthp = rt_remove_balanced_route(
- &rt_hash_table[k].chain,
- rth,
- &r);
- goal -= r;
- if (!rthp)
- break;
- } else {
- *rthp = rth->u.dst.rt_next;
- rt_free(rth);
- goal--;
- }
-#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
*rthp = rth->u.dst.rt_next;
rt_free(rth);
goal--;
-#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
}
spin_unlock_bh(rt_hash_lock_addr(k));
if (goal <= 0)
@@ -939,12 +852,7 @@ restart:
spin_lock_bh(rt_hash_lock_addr(hash));
while ((rth = *rthp) != NULL) {
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- if (!(rth->u.dst.flags & DST_BALANCED) &&
- compare_keys(&rth->fl, &rt->fl)) {
-#else
if (compare_keys(&rth->fl, &rt->fl)) {
-#endif
/* Put it first */
*rthp = rth->u.dst.rt_next;
/*
@@ -1774,10 +1682,6 @@ static inline int __mkroute_input(struct sk_buff *skb,
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- if (res->fi->fib_nhs > 1)
- rth->u.dst.flags |= DST_BALANCED;
-#endif
if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
rth->u.dst.flags |= DST_NOPOLICY;
if (IN_DEV_CONF_GET(out_dev, NOXFRM))
@@ -1812,11 +1716,11 @@ static inline int __mkroute_input(struct sk_buff *skb,
return err;
}
-static inline int ip_mkroute_input_def(struct sk_buff *skb,
- struct fib_result* res,
- const struct flowi *fl,
- struct in_device *in_dev,
- __be32 daddr, __be32 saddr, u32 tos)
+static inline int ip_mkroute_input(struct sk_buff *skb,
+ struct fib_result* res,
+ const struct flowi *fl,
+ struct in_device *in_dev,
+ __be32 daddr, __be32 saddr, u32 tos)
{
struct rtable* rth = NULL;
int err;
@@ -1837,63 +1741,6 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
}
-static inline int ip_mkroute_input(struct sk_buff *skb,
- struct fib_result* res,
- const struct flowi *fl,
- struct in_device *in_dev,
- __be32 daddr, __be32 saddr, u32 tos)
-{
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- struct rtable* rth = NULL, *rtres;
- unsigned char hop, hopcount;
- int err = -EINVAL;
- unsigned int hash;
-
- if (res->fi)
- hopcount = res->fi->fib_nhs;
- else
- hopcount = 1;
-
- /* distinguish between multipath and singlepath */
- if (hopcount < 2)
- return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
- saddr, tos);
-
- /* add all alternatives to the routing cache */
- for (hop = 0; hop < hopcount; hop++) {
- res->nh_sel = hop;
-
- /* put reference to previous result */
- if (hop)
- ip_rt_put(rtres);
-
- /* create a routing cache entry */
- err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
- &rth);
- if (err)
- return err;
-
- /* put it into the cache */
- hash = rt_hash(daddr, saddr, fl->iif);
- err = rt_intern_hash(hash, rth, &rtres);
- if (err)
- return err;
-
- /* forward hop information to multipath impl. */
- multipath_set_nhinfo(rth,
- FIB_RES_NETWORK(*res),
- FIB_RES_NETMASK(*res),
- res->prefixlen,
- &FIB_RES_NH(*res));
- }
- skb->dst = &rtres->u.dst;
- return err;
-#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
- return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
-#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
-}
-
-
/*
* NOTE. We drop all the packets that has local source
* addresses, because every properly looped back packet
@@ -2211,13 +2058,6 @@ static inline int __mkroute_output(struct rtable **result,
atomic_set(&rth->u.dst.__refcnt, 1);
rth->u.dst.flags= DST_HOST;
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- if (res->fi) {
- rth->rt_multipath_alg = res->fi->fib_mp_alg;
- if (res->fi->fib_nhs > 1)
- rth->u.dst.flags |= DST_BALANCED;
- }
-#endif
if (IN_DEV_CONF_GET(in_dev, NOXFRM))
rth->u.dst.flags |= DST_NOXFRM;
if (IN_DEV_CONF_GET(in_dev, NOPOLICY))
@@ -2277,12 +2117,12 @@ static inline int __mkroute_output(struct rtable **result,
return err;
}
-static inline int ip_mkroute_output_def(struct rtable **rp,
- struct fib_result* res,
- const struct flowi *fl,
- const struct flowi *oldflp,
- struct net_device *dev_out,
- unsigned flags)
+static inline int ip_mkroute_output(struct rtable **rp,
+ struct fib_result* res,
+ const struct flowi *fl,
+ const struct flowi *oldflp,
+ struct net_device *dev_out,
+ unsigned flags)
{
struct rtable *rth = NULL;
int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags);
@@ -2295,68 +2135,6 @@ static inline int ip_mkroute_output_def(struct rtable **rp,
return err;
}
-static inline int ip_mkroute_output(struct rtable** rp,
- struct fib_result* res,
- const struct flowi *fl,
- const struct flowi *oldflp,
- struct net_device *dev_out,
- unsigned flags)
-{
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- unsigned char hop;
- unsigned hash;
- int err = -EINVAL;
- struct rtable *rth = NULL;
-
- if (res->fi && res->fi->fib_nhs > 1) {
- unsigned char hopcount = res->fi->fib_nhs;
-
- for (hop = 0; hop < hopcount; hop++) {
- struct net_device *dev2nexthop;
-
- res->nh_sel = hop;
-
- /* hold a work reference to the output device */
- dev2nexthop = FIB_RES_DEV(*res);
- dev_hold(dev2nexthop);
-
- /* put reference to previous result */
- if (hop)
- ip_rt_put(*rp);
-
- err = __mkroute_output(&rth, res, fl, oldflp,
- dev2nexthop, flags);
-
- if (err != 0)
- goto cleanup;
-
- hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src,
- oldflp->oif);
- err = rt_intern_hash(hash, rth, rp);
-
- /* forward hop information to multipath impl. */
- multipath_set_nhinfo(rth,
- FIB_RES_NETWORK(*res),
- FIB_RES_NETMASK(*res),
- res->prefixlen,
- &FIB_RES_NH(*res));
- cleanup:
- /* release work reference to output device */
- dev_put(dev2nexthop);
-
- if (err != 0)
- return err;
- }
- return err;
- } else {
- return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out,
- flags);
- }
-#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
- return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out, flags);
-#endif
-}
-
/*
* Major route resolver routine.
*/
@@ -2570,17 +2348,6 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
rth->fl.mark == flp->mark &&
!((rth->fl.fl4_tos ^ flp->fl4_tos) &
(IPTOS_RT_MASK | RTO_ONLINK))) {
-
- /* check for multipath routes and choose one if
- * necessary
- */
- if (multipath_select_route(flp, rth, rp)) {
- dst_hold(&(*rp)->u.dst);
- RT_CACHE_STAT_INC(out_hit);
- rcu_read_unlock_bh();
- return 0;
- }
-
rth->u.dst.lastuse = jiffies;
dst_hold(&rth->u.dst);
rth->u.dst.__use++;
@@ -2729,10 +2496,6 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
if (rt->u.dst.tclassid)
NLA_PUT_U32(skb, RTA_FLOW, rt->u.dst.tclassid);
#endif
-#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- if (rt->rt_multipath_alg != IP_MP_ALG_NONE)
- NLA_PUT_U32(skb, RTA_MP_ALGO, rt->rt_multipath_alg);
-#endif
if (rt->fl.iif)
NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst);
else if (rt->rt_src != rt->fl.fl4_src)
@@ -3204,7 +2967,7 @@ int __init ip_rt_init(void)
ipv4_dst_ops.kmem_cachep =
kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 450f44bb2c8e..da4c0b6ab79a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1116,6 +1116,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
long timeo;
struct task_struct *user_recv = NULL;
int copied_early = 0;
+ struct sk_buff *skb;
lock_sock(sk);
@@ -1142,16 +1143,26 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
#ifdef CONFIG_NET_DMA
tp->ucopy.dma_chan = NULL;
preempt_disable();
- if ((len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) &&
- !sysctl_tcp_low_latency && __get_cpu_var(softnet_data).net_dma) {
- preempt_enable_no_resched();
- tp->ucopy.pinned_list = dma_pin_iovec_pages(msg->msg_iov, len);
- } else
- preempt_enable_no_resched();
+ skb = skb_peek_tail(&sk->sk_receive_queue);
+ {
+ int available = 0;
+
+ if (skb)
+ available = TCP_SKB_CB(skb)->seq + skb->len - (*seq);
+ if ((available < target) &&
+ (len > sysctl_tcp_dma_copybreak) && !(flags & MSG_PEEK) &&
+ !sysctl_tcp_low_latency &&
+ __get_cpu_var(softnet_data).net_dma) {
+ preempt_enable_no_resched();
+ tp->ucopy.pinned_list =
+ dma_pin_iovec_pages(msg->msg_iov, len);
+ } else {
+ preempt_enable_no_resched();
+ }
+ }
#endif
do {
- struct sk_buff *skb;
u32 offset;
/* Are we at urgent data? Stop if we have read anything or have SIGURG pending. */
@@ -1439,7 +1450,6 @@ skip_copy:
#ifdef CONFIG_NET_DMA
if (tp->ucopy.dma_chan) {
- struct sk_buff *skb;
dma_cookie_t done, used;
dma_async_memcpy_issue_pending(tp->ucopy.dma_chan);
@@ -2420,7 +2430,7 @@ void __init tcp_init(void)
tcp_hashinfo.bind_bucket_cachep =
kmem_cache_create("tcp_bind_bucket",
sizeof(struct inet_bind_bucket), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
/* Size and allocate the main established and bind bucket
* hash tables.
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
index dd9ef65ad3ff..519de091a94d 100644
--- a/net/ipv4/tcp_bic.c
+++ b/net/ipv4/tcp_bic.c
@@ -137,7 +137,7 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
}
static void bictcp_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int data_acked)
+ u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
struct bictcp *ca = inet_csk_ca(sk);
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 1260e52ad772..55fca1820c34 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -324,8 +324,7 @@ EXPORT_SYMBOL_GPL(tcp_slow_start);
/* This is Jacobson's slow start and congestion avoidance.
* SIGCOMM '88, p. 328.
*/
-void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
- int flag)
+void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index ebfaac2f9f46..d17da30d82d6 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -270,7 +270,7 @@ static inline void measure_delay(struct sock *sk)
}
static void bictcp_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int data_acked)
+ u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
struct bictcp *ca = inet_csk_ca(sk);
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
index 43d624e5043c..14a073d8b60f 100644
--- a/net/ipv4/tcp_highspeed.c
+++ b/net/ipv4/tcp_highspeed.c
@@ -109,7 +109,7 @@ static void hstcp_init(struct sock *sk)
tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
}
-static void hstcp_cong_avoid(struct sock *sk, u32 adk, u32 rtt,
+static void hstcp_cong_avoid(struct sock *sk, u32 adk,
u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
index 4ba4a7ae0a85..08a02e6045c9 100644
--- a/net/ipv4/tcp_htcp.c
+++ b/net/ipv4/tcp_htcp.c
@@ -225,7 +225,7 @@ static u32 htcp_recalc_ssthresh(struct sock *sk)
return max((tp->snd_cwnd * ca->beta) >> 7, 2U);
}
-static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void htcp_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int data_acked)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
index e5be35117223..b3e55cf56171 100644
--- a/net/ipv4/tcp_hybla.c
+++ b/net/ipv4/tcp_hybla.c
@@ -85,7 +85,7 @@ static inline u32 hybla_fraction(u32 odds)
* o Give cwnd a new value based on the model proposed
* o remember increments <1
*/
-static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void hybla_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
@@ -103,7 +103,7 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
return;
if (!ca->hybla_en)
- return tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+ return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
if (ca->rho == 0)
hybla_recalc_param(sk);
diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c
index b2b2256d3b84..cc5de6f69d46 100644
--- a/net/ipv4/tcp_illinois.c
+++ b/net/ipv4/tcp_illinois.c
@@ -258,7 +258,7 @@ static void tcp_illinois_state(struct sock *sk, u8 new_state)
/*
* Increase window in response to successful acknowledgment.
*/
-static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 69f9f1ef3ef6..fec8a7a4dbaf 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -1398,7 +1398,9 @@ static void tcp_enter_frto_loss(struct sock *sk, int allowed_segments, int flag)
* waiting for the first ACK and did not get it)...
*/
if ((tp->frto_counter == 1) && !(flag&FLAG_DATA_ACKED)) {
- tp->retrans_out += tcp_skb_pcount(skb);
+ /* For some reason this R-bit might get cleared? */
+ if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)
+ tp->retrans_out += tcp_skb_pcount(skb);
/* ...enter this if branch just for the first segment */
flag |= FLAG_DATA_ACKED;
} else {
@@ -2321,11 +2323,11 @@ static inline void tcp_ack_update_rtt(struct sock *sk, const int flag,
tcp_ack_no_tstamp(sk, seq_rtt, flag);
}
-static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int good)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
- icsk->icsk_ca_ops->cong_avoid(sk, ack, rtt, in_flight, good);
+ icsk->icsk_ca_ops->cong_avoid(sk, ack, in_flight, good);
tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp;
}
@@ -2824,11 +2826,11 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
/* Advance CWND, if state allows this. */
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd &&
tcp_may_raise_cwnd(sk, flag))
- tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 0);
+ tcp_cong_avoid(sk, ack, prior_in_flight, 0);
tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
} else {
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
- tcp_cong_avoid(sk, ack, seq_rtt, prior_in_flight, 1);
+ tcp_cong_avoid(sk, ack, prior_in_flight, 1);
}
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 354721d67f69..3f5f7423b95c 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2045,10 +2045,7 @@ static void *established_get_first(struct seq_file *seq)
struct hlist_node *node;
struct inet_timewait_sock *tw;
- /* We can reschedule _before_ having picked the target: */
- cond_resched_softirq();
-
- read_lock(&tcp_hashinfo.ehash[st->bucket].lock);
+ read_lock_bh(&tcp_hashinfo.ehash[st->bucket].lock);
sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) {
if (sk->sk_family != st->family) {
continue;
@@ -2065,7 +2062,7 @@ static void *established_get_first(struct seq_file *seq)
rc = tw;
goto out;
}
- read_unlock(&tcp_hashinfo.ehash[st->bucket].lock);
+ read_unlock_bh(&tcp_hashinfo.ehash[st->bucket].lock);
st->state = TCP_SEQ_STATE_ESTABLISHED;
}
out:
@@ -2092,14 +2089,11 @@ get_tw:
cur = tw;
goto out;
}
- read_unlock(&tcp_hashinfo.ehash[st->bucket].lock);
+ read_unlock_bh(&tcp_hashinfo.ehash[st->bucket].lock);
st->state = TCP_SEQ_STATE_ESTABLISHED;
- /* We can reschedule between buckets: */
- cond_resched_softirq();
-
if (++st->bucket < tcp_hashinfo.ehash_size) {
- read_lock(&tcp_hashinfo.ehash[st->bucket].lock);
+ read_lock_bh(&tcp_hashinfo.ehash[st->bucket].lock);
sk = sk_head(&tcp_hashinfo.ehash[st->bucket].chain);
} else {
cur = NULL;
@@ -2144,7 +2138,6 @@ static void *tcp_get_idx(struct seq_file *seq, loff_t pos)
if (!rc) {
inet_listen_unlock(&tcp_hashinfo);
- local_bh_disable();
st->state = TCP_SEQ_STATE_ESTABLISHED;
rc = established_get_idx(seq, pos);
}
@@ -2177,7 +2170,6 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
rc = listening_get_next(seq, v);
if (!rc) {
inet_listen_unlock(&tcp_hashinfo);
- local_bh_disable();
st->state = TCP_SEQ_STATE_ESTABLISHED;
rc = established_get_first(seq);
}
@@ -2209,8 +2201,7 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)
case TCP_SEQ_STATE_TIME_WAIT:
case TCP_SEQ_STATE_ESTABLISHED:
if (v)
- read_unlock(&tcp_hashinfo.ehash[st->bucket].lock);
- local_bh_enable();
+ read_unlock_bh(&tcp_hashinfo.ehash[st->bucket].lock);
break;
}
}
diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
index e49836ce012e..80e140e3ec2d 100644
--- a/net/ipv4/tcp_lp.c
+++ b/net/ipv4/tcp_lp.c
@@ -115,13 +115,12 @@ static void tcp_lp_init(struct sock *sk)
* Will only call newReno CA when away from inference.
* From TCP-LP's paper, this will be handled in additive increasement.
*/
-static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 rtt, u32 in_flight,
- int flag)
+static void tcp_lp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight, int flag)
{
struct lp *lp = inet_csk_ca(sk);
if (!(lp->flag & LP_WITHIN_INF))
- tcp_reno_cong_avoid(sk, ack, rtt, in_flight, flag);
+ tcp_reno_cong_avoid(sk, ack, in_flight, flag);
}
/**
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 53232dd6fb48..666d8a58d14a 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -699,6 +699,14 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss
tp->fackets_out -= diff;
if ((int)tp->fackets_out < 0)
tp->fackets_out = 0;
+ /* SACK fastpath might overwrite it unless dealt with */
+ if (tp->fastpath_skb_hint != NULL &&
+ after(TCP_SKB_CB(tp->fastpath_skb_hint)->seq,
+ TCP_SKB_CB(skb)->seq)) {
+ tp->fastpath_cnt_hint -= diff;
+ if ((int)tp->fastpath_cnt_hint < 0)
+ tp->fastpath_cnt_hint = 0;
+ }
}
}
@@ -1607,7 +1615,7 @@ u32 __tcp_select_window(struct sock *sk)
if (window <= free_space - mss || window > free_space)
window = (free_space/mss)*mss;
else if (mss == full_space &&
- free_space > window + full_space/2)
+ free_space > window + full_space/2)
window = free_space;
}
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index d9323dfff826..b76398d1b454 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -6,8 +6,7 @@
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -25,23 +24,22 @@
#include <linux/tcp.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
-#include <linux/kfifo.h>
#include <linux/ktime.h>
#include <linux/time.h>
-#include <linux/vmalloc.h>
#include <net/tcp.h>
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_DESCRIPTION("TCP cwnd snooper");
MODULE_LICENSE("GPL");
+MODULE_VERSION("1.1");
static int port __read_mostly = 0;
MODULE_PARM_DESC(port, "Port to match (0=all)");
module_param(port, int, 0);
-static int bufsize __read_mostly = 64*1024;
-MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
+static int bufsize __read_mostly = 4096;
+MODULE_PARM_DESC(bufsize, "Log buffer size in packets (4096)");
module_param(bufsize, int, 0);
static int full __read_mostly;
@@ -50,39 +48,38 @@ module_param(full, int, 0);
static const char procname[] = "tcpprobe";
-struct {
- struct kfifo *fifo;
+struct tcp_log {
+ ktime_t tstamp;
+ __be32 saddr, daddr;
+ __be16 sport, dport;
+ u16 length;
+ u32 snd_nxt;
+ u32 snd_una;
+ u32 snd_wnd;
+ u32 snd_cwnd;
+ u32 ssthresh;
+ u32 srtt;
+};
+
+static struct {
spinlock_t lock;
wait_queue_head_t wait;
ktime_t start;
u32 lastcwnd;
-} tcpw;
-/*
- * Print to log with timestamps.
- * FIXME: causes an extra copy
- */
-static void printl(const char *fmt, ...)
- __attribute__ ((format (printf, 1, 2)));
+ unsigned long head, tail;
+ struct tcp_log *log;
+} tcp_probe;
+
-static void printl(const char *fmt, ...)
+static inline int tcp_probe_used(void)
{
- va_list args;
- int len;
- struct timespec tv;
- char tbuf[256];
-
- va_start(args, fmt);
- /* want monotonic time since start of tcp_probe */
- tv = ktime_to_timespec(ktime_sub(ktime_get(), tcpw.start));
-
- len = sprintf(tbuf, "%lu.%09lu ",
- (unsigned long) tv.tv_sec, (unsigned long) tv.tv_nsec);
- len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
- va_end(args);
-
- kfifo_put(tcpw.fifo, tbuf, len);
- wake_up(&tcpw.wait);
+ return (tcp_probe.head - tcp_probe.tail) % bufsize;
+}
+
+static inline int tcp_probe_avail(void)
+{
+ return bufsize - tcp_probe_used();
}
/*
@@ -97,63 +94,118 @@ static int jtcp_rcv_established(struct sock *sk, struct sk_buff *skb,
/* Only update if port matches */
if ((port == 0 || ntohs(inet->dport) == port || ntohs(inet->sport) == port)
- && (full || tp->snd_cwnd != tcpw.lastcwnd)) {
- printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %#x %#x %u %u %u %u\n",
- NIPQUAD(inet->saddr), ntohs(inet->sport),
- NIPQUAD(inet->daddr), ntohs(inet->dport),
- skb->len, tp->snd_nxt, tp->snd_una,
- tp->snd_cwnd, tcp_current_ssthresh(sk),
- tp->snd_wnd, tp->srtt >> 3);
- tcpw.lastcwnd = tp->snd_cwnd;
+ && (full || tp->snd_cwnd != tcp_probe.lastcwnd)) {
+
+ spin_lock(&tcp_probe.lock);
+ /* If log fills, just silently drop */
+ if (tcp_probe_avail() > 1) {
+ struct tcp_log *p = tcp_probe.log + tcp_probe.head;
+
+ p->tstamp = ktime_get();
+ p->saddr = inet->saddr;
+ p->sport = inet->sport;
+ p->daddr = inet->daddr;
+ p->dport = inet->dport;
+ p->length = skb->len;
+ p->snd_nxt = tp->snd_nxt;
+ p->snd_una = tp->snd_una;
+ p->snd_cwnd = tp->snd_cwnd;
+ p->snd_wnd = tp->snd_wnd;
+ p->ssthresh = tcp_current_ssthresh(sk);
+ p->srtt = tp->srtt >> 3;
+
+ tcp_probe.head = (tcp_probe.head + 1) % bufsize;
+ }
+ tcp_probe.lastcwnd = tp->snd_cwnd;
+ spin_unlock(&tcp_probe.lock);
+
+ wake_up(&tcp_probe.wait);
}
jprobe_return();
return 0;
}
-static struct jprobe tcp_probe = {
+static struct jprobe tcp_jprobe = {
.kp = {
.symbol_name = "tcp_rcv_established",
},
- .entry = JPROBE_ENTRY(jtcp_rcv_established),
+ .entry = jtcp_rcv_established,
};
-
static int tcpprobe_open(struct inode * inode, struct file * file)
{
- kfifo_reset(tcpw.fifo);
- tcpw.start = ktime_get();
+ /* Reset (empty) log */
+ spin_lock_bh(&tcp_probe.lock);
+ tcp_probe.head = tcp_probe.tail = 0;
+ tcp_probe.start = ktime_get();
+ spin_unlock_bh(&tcp_probe.lock);
+
return 0;
}
+static int tcpprobe_sprint(char *tbuf, int n)
+{
+ const struct tcp_log *p
+ = tcp_probe.log + tcp_probe.tail % bufsize;
+ struct timespec tv
+ = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start));
+
+ return snprintf(tbuf, n,
+ "%lu.%09lu %d.%d.%d.%d:%u %d.%d.%d.%d:%u"
+ " %d %#x %#x %u %u %u %u\n",
+ (unsigned long) tv.tv_sec,
+ (unsigned long) tv.tv_nsec,
+ NIPQUAD(p->saddr), ntohs(p->sport),
+ NIPQUAD(p->daddr), ntohs(p->dport),
+ p->length, p->snd_nxt, p->snd_una,
+ p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt);
+}
+
static ssize_t tcpprobe_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
int error = 0, cnt = 0;
- unsigned char *tbuf;
if (!buf || len < 0)
return -EINVAL;
- if (len == 0)
- return 0;
+ while (cnt < len) {
+ char tbuf[128];
+ int width;
+
+ /* Wait for data in buffer */
+ error = wait_event_interruptible(tcp_probe.wait,
+ tcp_probe_used() > 0);
+ if (error)
+ break;
- tbuf = vmalloc(len);
- if (!tbuf)
- return -ENOMEM;
+ spin_lock_bh(&tcp_probe.lock);
+ if (tcp_probe.head == tcp_probe.tail) {
+ /* multiple readers race? */
+ spin_unlock_bh(&tcp_probe.lock);
+ continue;
+ }
- error = wait_event_interruptible(tcpw.wait,
- __kfifo_len(tcpw.fifo) != 0);
- if (error)
- goto out_free;
+ width = tcpprobe_sprint(tbuf, sizeof(tbuf));
- cnt = kfifo_get(tcpw.fifo, tbuf, len);
- error = copy_to_user(buf, tbuf, cnt);
+ if (width < len)
+ tcp_probe.tail = (tcp_probe.tail + 1) % bufsize;
-out_free:
- vfree(tbuf);
+ spin_unlock_bh(&tcp_probe.lock);
+
+ /* if record greater than space available
+ return partial buffer (so far) */
+ if (width >= len)
+ break;
+
+ error = copy_to_user(buf + cnt, tbuf, width);
+ if (error)
+ break;
+ cnt += width;
+ }
- return error ? error : cnt;
+ return cnt == 0 ? error : cnt;
}
static const struct file_operations tcpprobe_fops = {
@@ -166,34 +218,37 @@ static __init int tcpprobe_init(void)
{
int ret = -ENOMEM;
- init_waitqueue_head(&tcpw.wait);
- spin_lock_init(&tcpw.lock);
- tcpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &tcpw.lock);
- if (IS_ERR(tcpw.fifo))
- return PTR_ERR(tcpw.fifo);
+ init_waitqueue_head(&tcp_probe.wait);
+ spin_lock_init(&tcp_probe.lock);
+
+ if (bufsize < 0)
+ return -EINVAL;
+
+ tcp_probe.log = kcalloc(sizeof(struct tcp_log), bufsize, GFP_KERNEL);
+ if (!tcp_probe.log)
+ goto err0;
if (!proc_net_fops_create(procname, S_IRUSR, &tcpprobe_fops))
goto err0;
- ret = register_jprobe(&tcp_probe);
+ ret = register_jprobe(&tcp_jprobe);
if (ret)
goto err1;
- pr_info("TCP watch registered (port=%d)\n", port);
+ pr_info("TCP probe registered (port=%d)\n", port);
return 0;
err1:
proc_net_remove(procname);
err0:
- kfifo_free(tcpw.fifo);
+ kfree(tcp_probe.log);
return ret;
}
module_init(tcpprobe_init);
static __exit void tcpprobe_exit(void)
{
- kfifo_free(tcpw.fifo);
proc_net_remove(procname);
- unregister_jprobe(&tcp_probe);
-
+ unregister_jprobe(&tcp_jprobe);
+ kfree(tcp_probe.log);
}
module_exit(tcpprobe_exit);
diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c
index 4624501e9680..be27a33a1c68 100644
--- a/net/ipv4/tcp_scalable.c
+++ b/net/ipv4/tcp_scalable.c
@@ -15,7 +15,7 @@
#define TCP_SCALABLE_AI_CNT 50U
#define TCP_SCALABLE_MD_SCALE 3
-static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 rtt,
+static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack,
u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
index e218a51ceced..914e0307f7af 100644
--- a/net/ipv4/tcp_vegas.c
+++ b/net/ipv4/tcp_vegas.c
@@ -163,13 +163,13 @@ void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event)
EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event);
static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int flag)
+ u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
struct vegas *vegas = inet_csk_ca(sk);
if (!vegas->doing_vegas_now)
- return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
/* The key players are v_beg_snd_una and v_beg_snd_nxt.
*
@@ -228,7 +228,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack,
/* We don't have enough RTT samples to do the Vegas
* calculation, so we'll behave like Reno.
*/
- tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ tcp_reno_cong_avoid(sk, ack, in_flight, flag);
} else {
u32 rtt, target_cwnd, diff;
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
index ec854cc5fad5..7a55ddf86032 100644
--- a/net/ipv4/tcp_veno.c
+++ b/net/ipv4/tcp_veno.c
@@ -115,13 +115,13 @@ static void tcp_veno_cwnd_event(struct sock *sk, enum tcp_ca_event event)
}
static void tcp_veno_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int flag)
+ u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
struct veno *veno = inet_csk_ca(sk);
if (!veno->doing_veno_now)
- return tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ return tcp_reno_cong_avoid(sk, ack, in_flight, flag);
/* limited by applications */
if (!tcp_is_cwnd_limited(sk, in_flight))
@@ -132,7 +132,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack,
/* We don't have enough rtt samples to do the Veno
* calculation, so we'll behave like Reno.
*/
- tcp_reno_cong_avoid(sk, ack, seq_rtt, in_flight, flag);
+ tcp_reno_cong_avoid(sk, ack, in_flight, flag);
} else {
u32 rtt, target_cwnd;
diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c
index 545ed237ab53..c04b7c6ec702 100644
--- a/net/ipv4/tcp_yeah.c
+++ b/net/ipv4/tcp_yeah.c
@@ -70,7 +70,7 @@ static void tcp_yeah_pkts_acked(struct sock *sk, u32 pkts_acked, ktime_t last)
}
static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack,
- u32 seq_rtt, u32 in_flight, int flag)
+ u32 in_flight, int flag)
{
struct tcp_sock *tp = tcp_sk(sk);
struct yeah *yeah = inet_csk_ca(sk);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index facb7e29304e..28355350fb62 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -70,6 +70,7 @@
* Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind
* a single port at the same time.
* Derek Atkins <derek@ihtfp.com>: Add Encapulation Support
+ * James Chapman : Add L2TP encapsulation type.
*
*
* This program is free software; you can redistribute it and/or
@@ -919,104 +920,6 @@ int udp_disconnect(struct sock *sk, int flags)
return 0;
}
-/* return:
- * 1 if the UDP system should process it
- * 0 if we should drop this packet
- * -1 if it should get processed by xfrm4_rcv_encap
- */
-static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
-{
-#ifndef CONFIG_XFRM
- return 1;
-#else
- struct udp_sock *up = udp_sk(sk);
- struct udphdr *uh;
- struct iphdr *iph;
- int iphlen, len;
-
- __u8 *udpdata;
- __be32 *udpdata32;
- __u16 encap_type = up->encap_type;
-
- /* if we're overly short, let UDP handle it */
- len = skb->len - sizeof(struct udphdr);
- if (len <= 0)
- return 1;
-
- /* if this is not encapsulated socket, then just return now */
- if (!encap_type)
- return 1;
-
- /* If this is a paged skb, make sure we pull up
- * whatever data we need to look at. */
- if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
- return 1;
-
- /* Now we can get the pointers */
- uh = udp_hdr(skb);
- udpdata = (__u8 *)uh + sizeof(struct udphdr);
- udpdata32 = (__be32 *)udpdata;
-
- switch (encap_type) {
- default:
- case UDP_ENCAP_ESPINUDP:
- /* Check if this is a keepalive packet. If so, eat it. */
- if (len == 1 && udpdata[0] == 0xff) {
- return 0;
- } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
- /* ESP Packet without Non-ESP header */
- len = sizeof(struct udphdr);
- } else
- /* Must be an IKE packet.. pass it through */
- return 1;
- break;
- case UDP_ENCAP_ESPINUDP_NON_IKE:
- /* Check if this is a keepalive packet. If so, eat it. */
- if (len == 1 && udpdata[0] == 0xff) {
- return 0;
- } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
- udpdata32[0] == 0 && udpdata32[1] == 0) {
-
- /* ESP Packet with Non-IKE marker */
- len = sizeof(struct udphdr) + 2 * sizeof(u32);
- } else
- /* Must be an IKE packet.. pass it through */
- return 1;
- break;
- }
-
- /* At this point we are sure that this is an ESPinUDP packet,
- * so we need to remove 'len' bytes from the packet (the UDP
- * header and optional ESP marker bytes) and then modify the
- * protocol to ESP, and then call into the transform receiver.
- */
- if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
- return 0;
-
- /* Now we can update and verify the packet length... */
- iph = ip_hdr(skb);
- iphlen = iph->ihl << 2;
- iph->tot_len = htons(ntohs(iph->tot_len) - len);
- if (skb->len < iphlen + len) {
- /* packet is too small!?! */
- return 0;
- }
-
- /* pull the data buffer up to the ESP header and set the
- * transport header to point to ESP. Keep UDP on the stack
- * for later.
- */
- __skb_pull(skb, len);
- skb_reset_transport_header(skb);
-
- /* modify the protocol (it's ESP!) */
- iph->protocol = IPPROTO_ESP;
-
- /* and let the caller know to send this into the ESP processor... */
- return -1;
-#endif
-}
-
/* returns:
* -1: error
* 0: success
@@ -1039,28 +942,28 @@ int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
if (up->encap_type) {
/*
- * This is an encapsulation socket, so let's see if this is
- * an encapsulated packet.
- * If it's a keepalive packet, then just eat it.
- * If it's an encapsulateed packet, then pass it to the
- * IPsec xfrm input and return the response
- * appropriately. Otherwise, just fall through and
- * pass this up the UDP socket.
+ * This is an encapsulation socket so pass the skb to
+ * the socket's udp_encap_rcv() hook. Otherwise, just
+ * fall through and pass this up the UDP socket.
+ * up->encap_rcv() returns the following value:
+ * =0 if skb was successfully passed to the encap
+ * handler or was discarded by it.
+ * >0 if skb should be passed on to UDP.
+ * <0 if skb should be resubmitted as proto -N
*/
- int ret;
- ret = udp_encap_rcv(sk, skb);
- if (ret == 0) {
- /* Eat the packet .. */
- kfree_skb(skb);
- return 0;
- }
- if (ret < 0) {
- /* process the ESP packet */
- ret = xfrm4_rcv_encap(skb, up->encap_type);
- UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
- return -ret;
+ /* if we're overly short, let UDP handle it */
+ if (skb->len > sizeof(struct udphdr) &&
+ up->encap_rcv != NULL) {
+ int ret;
+
+ ret = (*up->encap_rcv)(sk, skb);
+ if (ret <= 0) {
+ UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag);
+ return -ret;
+ }
}
+
/* FALLTHROUGH -- it's a UDP Packet */
}
@@ -1349,6 +1252,9 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname,
case 0:
case UDP_ENCAP_ESPINUDP:
case UDP_ENCAP_ESPINUDP_NON_IKE:
+ up->encap_rcv = xfrm4_udp_encap_rcv;
+ /* FALLTHROUGH */
+ case UDP_ENCAP_L2TPINUDP:
up->encap_type = val;
break;
default:
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index fa1902dc81b8..2fa108245413 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -16,13 +16,6 @@
#include <net/ip.h>
#include <net/xfrm.h>
-int xfrm4_rcv(struct sk_buff *skb)
-{
- return xfrm4_rcv_encap(skb, 0);
-}
-
-EXPORT_SYMBOL(xfrm4_rcv);
-
static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
{
switch (nexthdr) {
@@ -53,7 +46,7 @@ drop:
}
#endif
-int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
+static int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
{
__be32 spi, seq;
struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
@@ -167,3 +160,108 @@ drop:
kfree_skb(skb);
return 0;
}
+
+/* If it's a keepalive packet, then just eat it.
+ * If it's an encapsulated packet, then pass it to the
+ * IPsec xfrm input.
+ * Returns 0 if skb passed to xfrm or was dropped.
+ * Returns >0 if skb should be passed to UDP.
+ * Returns <0 if skb should be resubmitted (-ret is protocol)
+ */
+int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
+{
+ struct udp_sock *up = udp_sk(sk);
+ struct udphdr *uh;
+ struct iphdr *iph;
+ int iphlen, len;
+ int ret;
+
+ __u8 *udpdata;
+ __be32 *udpdata32;
+ __u16 encap_type = up->encap_type;
+
+ /* if this is not encapsulated socket, then just return now */
+ if (!encap_type)
+ return 1;
+
+ /* If this is a paged skb, make sure we pull up
+ * whatever data we need to look at. */
+ len = skb->len - sizeof(struct udphdr);
+ if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8)))
+ return 1;
+
+ /* Now we can get the pointers */
+ uh = udp_hdr(skb);
+ udpdata = (__u8 *)uh + sizeof(struct udphdr);
+ udpdata32 = (__be32 *)udpdata;
+
+ switch (encap_type) {
+ default:
+ case UDP_ENCAP_ESPINUDP:
+ /* Check if this is a keepalive packet. If so, eat it. */
+ if (len == 1 && udpdata[0] == 0xff) {
+ goto drop;
+ } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) {
+ /* ESP Packet without Non-ESP header */
+ len = sizeof(struct udphdr);
+ } else
+ /* Must be an IKE packet.. pass it through */
+ return 1;
+ break;
+ case UDP_ENCAP_ESPINUDP_NON_IKE:
+ /* Check if this is a keepalive packet. If so, eat it. */
+ if (len == 1 && udpdata[0] == 0xff) {
+ goto drop;
+ } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) &&
+ udpdata32[0] == 0 && udpdata32[1] == 0) {
+
+ /* ESP Packet with Non-IKE marker */
+ len = sizeof(struct udphdr) + 2 * sizeof(u32);
+ } else
+ /* Must be an IKE packet.. pass it through */
+ return 1;
+ break;
+ }
+
+ /* At this point we are sure that this is an ESPinUDP packet,
+ * so we need to remove 'len' bytes from the packet (the UDP
+ * header and optional ESP marker bytes) and then modify the
+ * protocol to ESP, and then call into the transform receiver.
+ */
+ if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+ goto drop;
+
+ /* Now we can update and verify the packet length... */
+ iph = ip_hdr(skb);
+ iphlen = iph->ihl << 2;
+ iph->tot_len = htons(ntohs(iph->tot_len) - len);
+ if (skb->len < iphlen + len) {
+ /* packet is too small!?! */
+ goto drop;
+ }
+
+ /* pull the data buffer up to the ESP header and set the
+ * transport header to point to ESP. Keep UDP on the stack
+ * for later.
+ */
+ __skb_pull(skb, len);
+ skb_reset_transport_header(skb);
+
+ /* modify the protocol (it's ESP!) */
+ iph->protocol = IPPROTO_ESP;
+
+ /* process ESP */
+ ret = xfrm4_rcv_encap(skb, encap_type);
+ return ret;
+
+drop:
+ kfree_skb(skb);
+ return 0;
+}
+
+int xfrm4_rcv(struct sk_buff *skb)
+{
+ return xfrm4_rcv_encap(skb, 0);
+}
+
+EXPORT_SYMBOL(xfrm4_rcv);
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index 568510304553..9275c79119b6 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -109,3 +109,4 @@ static void __exit ipip_fini(void)
module_init(ipip_init);
module_exit(ipip_fini);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP);
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index 8e5d54f23b49..eb0b8085949b 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -109,7 +109,7 @@ config INET6_IPCOMP
If unsure, say Y.
config IPV6_MIP6
- bool "IPv6: Mobility (EXPERIMENTAL)"
+ tristate "IPv6: Mobility (EXPERIMENTAL)"
depends on IPV6 && EXPERIMENTAL
select XFRM
---help---
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index bb33309044c9..87c23a73d284 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -14,7 +14,6 @@ ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
xfrm6_output.o
ipv6-$(CONFIG_NETFILTER) += netfilter.o
ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
-ipv6-$(CONFIG_IPV6_MIP6) += mip6.o
ipv6-$(CONFIG_PROC_FS) += proc.o
ipv6-objs += $(ipv6-y)
@@ -28,6 +27,7 @@ obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o
obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
+obj-$(CONFIG_IPV6_MIP6) += mip6.o
obj-$(CONFIG_NETFILTER) += netfilter/
obj-$(CONFIG_IPV6_SIT) += sit.o
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 79b79f3de24c..06012920912a 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1034,7 +1034,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
}
/* Rule 4: Prefer home address */
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
if (hiscore.rule < 4) {
if (ifa_result->flags & IFA_F_HOMEADDRESS)
hiscore.attrs |= IPV6_SADDR_SCORE_HOA;
@@ -2475,6 +2475,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
write_unlock_bh(&idev->lock);
__ipv6_ifa_notify(RTM_DELADDR, ifa);
+ atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
@@ -2785,7 +2786,7 @@ static int if6_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations if6_seq_ops = {
+static const struct seq_operations if6_seq_ops = {
.start = if6_seq_start,
.next = if6_seq_next,
.show = if6_seq_show,
@@ -2835,7 +2836,7 @@ void if6_proc_exit(void)
}
#endif /* CONFIG_PROC_FS */
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
/* Check if address is a home address configured on any interface. */
int ipv6_chk_home_addr(struct in6_addr *addr)
{
@@ -4243,7 +4244,6 @@ errout:
void __exit addrconf_cleanup(void)
{
struct net_device *dev;
- struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
int i;
@@ -4261,7 +4261,7 @@ void __exit addrconf_cleanup(void)
*/
for_each_netdev(dev) {
- if ((idev = __in6_dev_get(dev)) == NULL)
+ if (__in6_dev_get(dev) == NULL)
continue;
addrconf_ifdown(dev, 1);
}
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 6dd377253cf7..eed09373a45d 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -58,9 +58,6 @@
#ifdef CONFIG_IPV6_TUNNEL
#include <net/ip6_tunnel.h>
#endif
-#ifdef CONFIG_IPV6_MIP6
-#include <net/mip6.h>
-#endif
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -853,9 +850,6 @@ static int __init inet6_init(void)
ipv6_frag_init();
ipv6_nodata_init();
ipv6_destopt_init();
-#ifdef CONFIG_IPV6_MIP6
- mip6_init();
-#endif
/* Init v6 transport protocols. */
udpv6_init();
@@ -921,9 +915,7 @@ static void __exit inet6_exit(void)
/* Cleanup code parts. */
ipv6_packet_cleanup();
-#ifdef CONFIG_IPV6_MIP6
- mip6_fini();
-#endif
+
addrconf_cleanup();
ip6_flowlabel_cleanup();
ip6_route_cleanup();
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 128f94c79c64..53f46ab6af70 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -74,7 +74,7 @@ bad:
return 0;
}
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
/**
* ipv6_rearrange_destopt - rearrange IPv6 destination options header
* @iph: IPv6 header
@@ -132,6 +132,8 @@ static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *des
bad:
return;
}
+#else
+static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt) {}
#endif
/**
@@ -189,10 +191,8 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
while (exthdr.raw < end) {
switch (nexthdr) {
case NEXTHDR_DEST:
-#ifdef CONFIG_IPV6_MIP6
if (dir == XFRM_POLICY_OUT)
ipv6_rearrange_destopt(iph, exthdr.opth);
-#endif
case NEXTHDR_HOP:
if (!zero_out_mutable_opts(exthdr.opth)) {
LIMIT_NETDEBUG(
@@ -228,7 +228,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
u8 nexthdr;
char tmp_base[8];
struct {
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
struct in6_addr saddr;
#endif
struct in6_addr daddr;
@@ -255,7 +255,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
err = -ENOMEM;
goto error;
}
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
memcpy(tmp_ext, &top_iph->saddr, extlen);
#else
memcpy(tmp_ext, &top_iph->daddr, extlen);
@@ -294,7 +294,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
memcpy(top_iph, tmp_base, sizeof(tmp_base));
if (tmp_ext) {
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
memcpy(&top_iph->saddr, tmp_ext, extlen);
#else
memcpy(&top_iph->daddr, tmp_ext, extlen);
@@ -554,3 +554,4 @@ module_init(ah6_init);
module_exit(ah6_fini);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_AH);
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 9b81264eb78f..b8c533fbdb63 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -539,7 +539,7 @@ static int ac6_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ac6_seq_ops = {
+static const struct seq_operations ac6_seq_ops = {
.start = ac6_seq_start,
.next = ac6_seq_next,
.stop = ac6_seq_stop,
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index b1fe7ac5dc90..fe0f49024a0a 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -657,11 +657,10 @@ int datagram_send_ctl(struct msghdr *msg, struct flowi *fl,
rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg);
switch (rthdr->type) {
- case IPV6_SRCRT_TYPE_0:
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPV6_SRCRT_TYPE_2:
-#endif
break;
+#endif
default:
err = -EINVAL;
goto exit_f;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 7107bb7e2e62..2db31ce3c7e6 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -421,3 +421,4 @@ module_init(esp6_init);
module_exit(esp6_fini);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ESP);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 14be0b9b77a5..c82d4d49f71f 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -42,7 +42,7 @@
#include <net/ndisc.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
#include <net/xfrm.h>
#endif
@@ -90,6 +90,7 @@ int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
bad:
return -1;
}
+EXPORT_SYMBOL_GPL(ipv6_find_tlv);
/*
* Parsing tlv encoded headers.
@@ -196,7 +197,7 @@ bad:
Destination options header.
*****************************/
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
{
struct sk_buff *skb = *skbp;
@@ -270,7 +271,7 @@ static int ipv6_dest_hao(struct sk_buff **skbp, int optoff)
#endif
static struct tlvtype_proc tlvprocdestopt_lst[] = {
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
{
.type = IPV6_TLV_HAO,
.func = ipv6_dest_hao,
@@ -283,7 +284,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
{
struct sk_buff *skb = *skbp;
struct inet6_skb_parm *opt = IP6CB(skb);
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
__u16 dstbuf;
#endif
struct dst_entry *dst;
@@ -298,7 +299,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
}
opt->lastopt = opt->dst1 = skb_network_header_len(skb);
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
dstbuf = opt->dst1;
#endif
@@ -308,7 +309,7 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
skb = *skbp;
skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3;
opt = IP6CB(skb);
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
opt->nhoff = dstbuf;
#else
opt->nhoff = opt->dst1;
@@ -371,22 +372,13 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
struct rt0_hdr *rthdr;
int accept_source_route = ipv6_devconf.accept_source_route;
- if (accept_source_route < 0 ||
- ((idev = in6_dev_get(skb->dev)) == NULL)) {
- kfree_skb(skb);
- return -1;
- }
- if (idev->cnf.accept_source_route < 0) {
+ idev = in6_dev_get(skb->dev);
+ if (idev) {
+ if (accept_source_route > idev->cnf.accept_source_route)
+ accept_source_route = idev->cnf.accept_source_route;
in6_dev_put(idev);
- kfree_skb(skb);
- return -1;
}
- if (accept_source_route > idev->cnf.accept_source_route)
- accept_source_route = idev->cnf.accept_source_route;
-
- in6_dev_put(idev);
-
if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) ||
!pskb_may_pull(skb, (skb_transport_offset(skb) +
((skb_transport_header(skb)[1] + 1) << 3)))) {
@@ -398,24 +390,6 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb);
- switch (hdr->type) {
-#ifdef CONFIG_IPV6_MIP6
- case IPV6_SRCRT_TYPE_2:
- break;
-#endif
- case IPV6_SRCRT_TYPE_0:
- if (accept_source_route > 0)
- break;
- kfree_skb(skb);
- return -1;
- default:
- IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
- IPSTATS_MIB_INHDRERRORS);
- icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
- (&hdr->type) - skb_network_header(skb));
- return -1;
- }
-
if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) ||
skb->pkt_type != PACKET_HOST) {
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -427,7 +401,7 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
looped_back:
if (hdr->segments_left == 0) {
switch (hdr->type) {
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPV6_SRCRT_TYPE_2:
/* Silently discard type 2 header unless it was
* processed by own
@@ -453,18 +427,10 @@ looped_back:
}
switch (hdr->type) {
- case IPV6_SRCRT_TYPE_0:
- if (hdr->hdrlen & 0x01) {
- IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
- IPSTATS_MIB_INHDRERRORS);
- icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
- ((&hdr->hdrlen) -
- skb_network_header(skb)));
- return -1;
- }
- break;
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPV6_SRCRT_TYPE_2:
+ if (accept_source_route < 0)
+ goto unknown_rh;
/* Silently discard invalid RTH type 2 */
if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
@@ -474,6 +440,8 @@ looped_back:
}
break;
#endif
+ default:
+ goto unknown_rh;
}
/*
@@ -520,7 +488,7 @@ looped_back:
addr += i - 1;
switch (hdr->type) {
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPV6_SRCRT_TYPE_2:
if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
(xfrm_address_t *)&ipv6_hdr(skb)->saddr,
@@ -577,6 +545,12 @@ looped_back:
skb_push(skb, skb->data - skb_network_header(skb));
dst_input(skb);
return -1;
+
+unknown_rh:
+ IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+ icmpv6_param_prob(skb, ICMPV6_HDR_FIELD,
+ (&hdr->type) - skb_network_header(skb));
+ return -1;
}
static struct inet6_protocol rthdr_protocol = {
@@ -590,72 +564,6 @@ void __init ipv6_rthdr_init(void)
printk(KERN_ERR "ipv6_rthdr_init: Could not register protocol\n");
};
-/*
- This function inverts received rthdr.
- NOTE: specs allow to make it automatically only if
- packet authenticated.
-
- I will not discuss it here (though, I am really pissed off at
- this stupid requirement making rthdr idea useless)
-
- Actually, it creates severe problems for us.
- Embryonic requests has no associated sockets,
- so that user have no control over it and
- cannot not only to set reply options, but
- even to know, that someone wants to connect
- without success. :-(
-
- For now we need to test the engine, so that I created
- temporary (or permanent) backdoor.
- If listening socket set IPV6_RTHDR to 2, then we invert header.
- --ANK (980729)
- */
-
-struct ipv6_txoptions *
-ipv6_invert_rthdr(struct sock *sk, struct ipv6_rt_hdr *hdr)
-{
- /* Received rthdr:
-
- [ H1 -> H2 -> ... H_prev ] daddr=ME
-
- Inverted result:
- [ H_prev -> ... -> H1 ] daddr =sender
-
- Note, that IP output engine will rewrite this rthdr
- by rotating it left by one addr.
- */
-
- int n, i;
- struct rt0_hdr *rthdr = (struct rt0_hdr*)hdr;
- struct rt0_hdr *irthdr;
- struct ipv6_txoptions *opt;
- int hdrlen = ipv6_optlen(hdr);
-
- if (hdr->segments_left ||
- hdr->type != IPV6_SRCRT_TYPE_0 ||
- hdr->hdrlen & 0x01)
- return NULL;
-
- n = hdr->hdrlen >> 1;
- opt = sock_kmalloc(sk, sizeof(*opt) + hdrlen, GFP_ATOMIC);
- if (opt == NULL)
- return NULL;
- memset(opt, 0, sizeof(*opt));
- opt->tot_len = sizeof(*opt) + hdrlen;
- opt->srcrt = (void*)(opt+1);
- opt->opt_nflen = hdrlen;
-
- memcpy(opt->srcrt, hdr, sizeof(*hdr));
- irthdr = (struct rt0_hdr*)opt->srcrt;
- irthdr->reserved = 0;
- opt->srcrt->segments_left = n;
- for (i=0; i<n; i++)
- memcpy(irthdr->addr+i, rthdr->addr+(n-1-i), 16);
- return opt;
-}
-
-EXPORT_SYMBOL_GPL(ipv6_invert_rthdr);
-
/**********************************
Hop-by-hop options.
**********************************/
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index e9bcce9e7bdf..6a6714d154ed 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -272,7 +272,7 @@ static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, st
return 0;
}
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
static void mip6_addr_swap(struct sk_buff *skb)
{
struct ipv6hdr *iph = ipv6_hdr(skb);
@@ -604,7 +604,7 @@ static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info)
read_lock(&raw_v6_lock);
if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) {
- while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr,
+ while ((sk = __raw_v6_lookup(sk, nexthdr, saddr, daddr,
IP6CB(skb)->iif))) {
rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
sk = sk_next(sk);
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 662a7d9681fd..6a612a701eaa 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -1474,7 +1474,7 @@ void __init fib6_init(void)
fib6_node_kmem = kmem_cache_create("fib6_nodes",
sizeof(struct fib6_node),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
fib6_tables_init();
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index c206a152ed9d..413a4ebb195c 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -648,7 +648,7 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ip6fl_seq_ops = {
+static const struct seq_operations ip6fl_seq_ops = {
.start = ip6fl_seq_start,
.next = ip6fl_seq_next,
.stop = ip6fl_seq_stop,
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4704b5fc3085..50d86e94d9ed 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -521,6 +521,10 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->tc_index = from->tc_index;
#endif
nf_copy(to, from);
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ to->nf_trace = from->nf_trace;
+#endif
skb_copy_secmark(to, from);
}
@@ -543,7 +547,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr)
found_rhdr = 1;
break;
case NEXTHDR_DEST:
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0)
break;
#endif
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index a0902fbdb4e1..df30976f6dfd 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -883,8 +883,8 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
*/
max_headroom += LL_RESERVED_SPACE(tdev);
- if (skb_headroom(skb) < max_headroom ||
- skb_cloned(skb) || skb_shared(skb)) {
+ if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
+ (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
struct sk_buff *new_skb;
if (!(new_skb = skb_realloc_headroom(skb, max_headroom)))
@@ -962,8 +962,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
dsfield = ipv4_get_dsfield(iph);
if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
- fl.fl6_flowlabel |= ntohl(((__u32)iph->tos << IPV6_TCLASS_SHIFT)
- & IPV6_TCLASS_MASK);
+ fl.fl6_flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
+ & IPV6_TCLASS_MASK;
err = ip6_tnl_xmit2(skb, dev, dsfield, &fl, encap_limit, &mtu);
if (err != 0) {
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index 1ee50b5782e1..473f165310ea 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -500,4 +500,4 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) for IPv6 - RFC3173");
MODULE_AUTHOR("Mitsuru KANDA <mk@linux-ipv6.org>");
-
+MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_COMP);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index aa3d07c52a8f..d6846393182d 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -123,7 +123,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
struct ipv6hdr *ipv6h;
struct inet6_protocol *ops;
- if (!(features & NETIF_F_HW_CSUM))
+ if (!(features & NETIF_F_V6_CSUM))
features &= ~NETIF_F_SG;
if (unlikely(skb_shinfo(skb)->gso_type &
@@ -336,16 +336,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
break;
case IPV6_RECVRTHDR:
- if (val < 0 || val > 2)
- goto e_inval;
- np->rxopt.bits.srcrt = val;
+ np->rxopt.bits.srcrt = valbool;
retv = 0;
break;
case IPV6_2292RTHDR:
- if (val < 0 || val > 2)
- goto e_inval;
- np->rxopt.bits.osrcrt = val;
+ np->rxopt.bits.osrcrt = valbool;
retv = 0;
break;
@@ -416,11 +412,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
if (optname == IPV6_RTHDR && opt && opt->srcrt) {
struct ipv6_rt_hdr *rthdr = opt->srcrt;
switch (rthdr->type) {
- case IPV6_SRCRT_TYPE_0:
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPV6_SRCRT_TYPE_2:
-#endif
break;
+#endif
default:
goto sticky_done;
}
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 3e308fb41b49..ae9881832a7e 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2423,7 +2423,7 @@ static int igmp6_mc_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations igmp6_mc_seq_ops = {
+static const struct seq_operations igmp6_mc_seq_ops = {
.start = igmp6_mc_seq_start,
.next = igmp6_mc_seq_next,
.stop = igmp6_mc_seq_stop,
@@ -2597,7 +2597,7 @@ static int igmp6_mcf_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations igmp6_mcf_seq_ops = {
+static const struct seq_operations igmp6_mcf_seq_ops = {
.start = igmp6_mcf_seq_start,
.next = igmp6_mcf_seq_next,
.stop = igmp6_mcf_seq_stop,
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 13b7160fb892..8a1399ce38ce 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -30,6 +30,7 @@
#include <net/sock.h>
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
+#include <net/rawv6.h>
#include <net/xfrm.h>
#include <net/mip6.h>
@@ -86,7 +87,7 @@ static int mip6_mh_len(int type)
return len;
}
-int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
+static int mip6_mh_filter(struct sock *sk, struct sk_buff *skb)
{
struct ip6_mh *mh;
@@ -471,7 +472,7 @@ static struct xfrm_type mip6_rthdr_type =
.remote_addr = mip6_xfrm_addr,
};
-int __init mip6_init(void)
+static int __init mip6_init(void)
{
printk(KERN_INFO "Mobile IPv6\n");
@@ -483,18 +484,35 @@ int __init mip6_init(void)
printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__);
goto mip6_rthdr_xfrm_fail;
}
+ if (rawv6_mh_filter_register(mip6_mh_filter) < 0) {
+ printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __FUNCTION__);
+ goto mip6_rawv6_mh_fail;
+ }
+
+
return 0;
+ mip6_rawv6_mh_fail:
+ xfrm_unregister_type(&mip6_rthdr_type, AF_INET6);
mip6_rthdr_xfrm_fail:
xfrm_unregister_type(&mip6_destopt_type, AF_INET6);
mip6_destopt_xfrm_fail:
return -EAGAIN;
}
-void __exit mip6_fini(void)
+static void __exit mip6_fini(void)
{
+ if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0)
+ printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __FUNCTION__);
if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0)
printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__);
if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0)
printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__);
}
+
+module_init(mip6_init);
+module_exit(mip6_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_DSTOPTS);
+MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ROUTING);
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 9aa624026688..aeda617246b7 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -96,13 +96,13 @@ ip6t_ext_hdr(u8 nexthdr)
}
/* Returns whether matches rule or not. */
-static inline int
+static inline bool
ip6_packet_match(const struct sk_buff *skb,
const char *indev,
const char *outdev,
const struct ip6t_ip6 *ip6info,
unsigned int *protoff,
- int *fragoff, int *hotdrop)
+ int *fragoff, bool *hotdrop)
{
size_t i;
unsigned long ret;
@@ -122,7 +122,7 @@ ip6_packet_match(const struct sk_buff *skb,
dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
- return 0;
+ return false;
}
/* Look for ifname matches; this should unroll nicely. */
@@ -136,7 +136,7 @@ ip6_packet_match(const struct sk_buff *skb,
dprintf("VIA in mismatch (%s vs %s).%s\n",
indev, ip6info->iniface,
ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
- return 0;
+ return false;
}
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
@@ -149,7 +149,7 @@ ip6_packet_match(const struct sk_buff *skb,
dprintf("VIA out mismatch (%s vs %s).%s\n",
outdev, ip6info->outiface,
ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
- return 0;
+ return false;
}
/* ... might want to do something with class and flowlabel here ... */
@@ -162,8 +162,8 @@ ip6_packet_match(const struct sk_buff *skb,
protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off);
if (protohdr < 0) {
if (_frag_off == 0)
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
*fragoff = _frag_off;
@@ -174,34 +174,34 @@ ip6_packet_match(const struct sk_buff *skb,
if (ip6info->proto == protohdr) {
if(ip6info->invflags & IP6T_INV_PROTO) {
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* We need match for the '-p all', too! */
if ((ip6info->proto != 0) &&
!(ip6info->invflags & IP6T_INV_PROTO))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* should be ip6 safe */
-static inline int
+static inline bool
ip6_checkentry(const struct ip6t_ip6 *ipv6)
{
if (ipv6->flags & ~IP6T_F_MASK) {
duprintf("Unknown flag bits set: %08X\n",
ipv6->flags & ~IP6T_F_MASK);
- return 0;
+ return false;
}
if (ipv6->invflags & ~IP6T_INV_MASK) {
duprintf("Unknown invflag bits set: %08X\n",
ipv6->invflags & ~IP6T_INV_MASK);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static unsigned int
@@ -219,20 +219,20 @@ ip6t_error(struct sk_buff **pskb,
}
static inline
-int do_match(struct ip6t_entry_match *m,
- const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int offset,
- unsigned int protoff,
- int *hotdrop)
+bool do_match(struct ip6t_entry_match *m,
+ const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop)
{
/* Stop iteration if it doesn't match */
if (!m->u.kernel.match->match(skb, in, out, m->u.kernel.match, m->data,
offset, protoff, hotdrop))
- return 1;
+ return true;
else
- return 0;
+ return false;
}
static inline struct ip6t_entry *
@@ -241,6 +241,113 @@ get_entry(void *base, unsigned int offset)
return (struct ip6t_entry *)(base + offset);
}
+/* All zeroes == unconditional rule. */
+static inline int
+unconditional(const struct ip6t_ip6 *ipv6)
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(*ipv6); i++)
+ if (((char *)ipv6)[i])
+ break;
+
+ return (i == sizeof(*ipv6));
+}
+
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+/* This cries for unification! */
+static const char *hooknames[] = {
+ [NF_IP6_PRE_ROUTING] = "PREROUTING",
+ [NF_IP6_LOCAL_IN] = "INPUT",
+ [NF_IP6_FORWARD] = "FORWARD",
+ [NF_IP6_LOCAL_OUT] = "OUTPUT",
+ [NF_IP6_POST_ROUTING] = "POSTROUTING",
+};
+
+enum nf_ip_trace_comments {
+ NF_IP6_TRACE_COMMENT_RULE,
+ NF_IP6_TRACE_COMMENT_RETURN,
+ NF_IP6_TRACE_COMMENT_POLICY,
+};
+
+static const char *comments[] = {
+ [NF_IP6_TRACE_COMMENT_RULE] = "rule",
+ [NF_IP6_TRACE_COMMENT_RETURN] = "return",
+ [NF_IP6_TRACE_COMMENT_POLICY] = "policy",
+};
+
+static struct nf_loginfo trace_loginfo = {
+ .type = NF_LOG_TYPE_LOG,
+ .u = {
+ .log = {
+ .level = 4,
+ .logflags = NF_LOG_MASK,
+ },
+ },
+};
+
+static inline int
+get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
+ char *hookname, char **chainname,
+ char **comment, unsigned int *rulenum)
+{
+ struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
+
+ if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
+ /* Head of user chain: ERROR target with chainname */
+ *chainname = t->target.data;
+ (*rulenum) = 0;
+ } else if (s == e) {
+ (*rulenum)++;
+
+ if (s->target_offset == sizeof(struct ip6t_entry)
+ && strcmp(t->target.u.kernel.target->name,
+ IP6T_STANDARD_TARGET) == 0
+ && t->verdict < 0
+ && unconditional(&s->ipv6)) {
+ /* Tail of chains: STANDARD target (return/policy) */
+ *comment = *chainname == hookname
+ ? (char *)comments[NF_IP6_TRACE_COMMENT_POLICY]
+ : (char *)comments[NF_IP6_TRACE_COMMENT_RETURN];
+ }
+ return 1;
+ } else
+ (*rulenum)++;
+
+ return 0;
+}
+
+static void trace_packet(struct sk_buff *skb,
+ unsigned int hook,
+ const struct net_device *in,
+ const struct net_device *out,
+ char *tablename,
+ struct xt_table_info *private,
+ struct ip6t_entry *e)
+{
+ void *table_base;
+ struct ip6t_entry *root;
+ char *hookname, *chainname, *comment;
+ unsigned int rulenum = 0;
+
+ table_base = (void *)private->entries[smp_processor_id()];
+ root = get_entry(table_base, private->hook_entry[hook]);
+
+ hookname = chainname = (char *)hooknames[hook];
+ comment = (char *)comments[NF_IP6_TRACE_COMMENT_RULE];
+
+ IP6T_ENTRY_ITERATE(root,
+ private->size - private->hook_entry[hook],
+ get_chainname_rulenum,
+ e, hookname, &chainname, &comment, &rulenum);
+
+ nf_log_packet(AF_INET6, hook, skb, in, out, &trace_loginfo,
+ "TRACE: %s:%s:%s:%u ",
+ tablename, chainname, comment, rulenum);
+}
+#endif
+
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
unsigned int
ip6t_do_table(struct sk_buff **pskb,
@@ -252,7 +359,7 @@ ip6t_do_table(struct sk_buff **pskb,
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
int offset = 0;
unsigned int protoff = 0;
- int hotdrop = 0;
+ bool hotdrop = false;
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
const char *indev, *outdev;
@@ -298,6 +405,14 @@ ip6t_do_table(struct sk_buff **pskb,
t = ip6t_get_target(e);
IP_NF_ASSERT(t->u.kernel.target);
+
+#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
+ /* The packet is traced: log it */
+ if (unlikely((*pskb)->nf_trace))
+ trace_packet(*pskb, hook, in, out,
+ table->name, private, e);
+#endif
/* Standard target? */
if (!t->u.kernel.target->target) {
int v;
@@ -377,19 +492,6 @@ ip6t_do_table(struct sk_buff **pskb,
#endif
}
-/* All zeroes == unconditional rule. */
-static inline int
-unconditional(const struct ip6t_ip6 *ipv6)
-{
- unsigned int i;
-
- for (i = 0; i < sizeof(*ipv6); i++)
- if (((char *)ipv6)[i])
- break;
-
- return (i == sizeof(*ipv6));
-}
-
/* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */
static int
@@ -1282,16 +1384,16 @@ void ip6t_unregister_table(struct xt_table *table)
}
/* Returns 1 if the type and code is matched by the range, 0 otherwise */
-static inline int
+static inline bool
icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
u_int8_t type, u_int8_t code,
- int invert)
+ bool invert)
{
return (type == test_type && code >= min_code && code <= max_code)
^ invert;
}
-static int
+static bool
icmp6_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -1299,22 +1401,22 @@ icmp6_match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
struct icmp6hdr _icmp, *ic;
const struct ip6t_icmp *icmpinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
- return 0;
+ return false;
ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
if (ic == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil ICMP tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
return icmp6_type_code_match(icmpinfo->type,
@@ -1325,7 +1427,7 @@ icmp6_match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
icmp6_checkentry(const char *tablename,
const void *entry,
const struct xt_match *match,
@@ -1339,13 +1441,13 @@ icmp6_checkentry(const char *tablename,
}
/* The built-in targets: standard (NULL) and error. */
-static struct xt_target ip6t_standard_target = {
+static struct xt_target ip6t_standard_target __read_mostly = {
.name = IP6T_STANDARD_TARGET,
.targetsize = sizeof(int),
.family = AF_INET6,
};
-static struct xt_target ip6t_error_target = {
+static struct xt_target ip6t_error_target __read_mostly = {
.name = IP6T_ERROR_TARGET,
.target = ip6t_error,
.targetsize = IP6T_FUNCTION_MAXNAMELEN,
@@ -1362,7 +1464,7 @@ static struct nf_sockopt_ops ip6t_sockopts = {
.get = do_ip6t_get_ctl,
};
-static struct xt_match icmp6_matchstruct = {
+static struct xt_match icmp6_matchstruct __read_mostly = {
.name = "icmp6",
.match = &icmp6_match,
.matchsize = sizeof(struct ip6t_icmp),
@@ -1395,7 +1497,7 @@ static int __init ip6_tables_init(void)
if (ret < 0)
goto err5;
- printk("ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
+ printk(KERN_INFO "ip6_tables: (C) 2000-2006 Netfilter Core Team\n");
return 0;
err5:
diff --git a/net/ipv6/netfilter/ip6t_HL.c b/net/ipv6/netfilter/ip6t_HL.c
index 4115a576ba25..ad4d94310b87 100644
--- a/net/ipv6/netfilter/ip6t_HL.c
+++ b/net/ipv6/netfilter/ip6t_HL.c
@@ -58,28 +58,28 @@ static unsigned int ip6t_hl_target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int ip6t_hl_checkentry(const char *tablename,
+static bool ip6t_hl_checkentry(const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
- struct ip6t_HL_info *info = targinfo;
+ const struct ip6t_HL_info *info = targinfo;
if (info->mode > IP6T_HL_MAXMODE) {
printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
info->mode);
- return 0;
+ return false;
}
- if ((info->mode != IP6T_HL_SET) && (info->hop_limit == 0)) {
+ if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
"make sense with value 0\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_target ip6t_HL = {
+static struct xt_target ip6t_HL __read_mostly = {
.name = "HL",
.family = AF_INET6,
.target = ip6t_hl_target,
diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
index 5bb9cd349350..b05327ebd332 100644
--- a/net/ipv6/netfilter/ip6t_LOG.c
+++ b/net/ipv6/netfilter/ip6t_LOG.c
@@ -32,12 +32,6 @@ struct in_device;
#include <net/route.h>
#include <linux/netfilter_ipv6/ip6t_LOG.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Use lock to serialize, so printks don't overlap */
static DEFINE_SPINLOCK(log_lock);
@@ -48,7 +42,8 @@ static void dump_packet(const struct nf_loginfo *info,
{
u_int8_t currenthdr;
int fragment;
- struct ipv6hdr _ip6h, *ih;
+ struct ipv6hdr _ip6h;
+ const struct ipv6hdr *ih;
unsigned int ptr;
unsigned int hdrlen = 0;
unsigned int logflags;
@@ -78,7 +73,8 @@ static void dump_packet(const struct nf_loginfo *info,
ptr = ip6hoff + sizeof(struct ipv6hdr);
currenthdr = ih->nexthdr;
while (currenthdr != NEXTHDR_NONE && ip6t_ext_hdr(currenthdr)) {
- struct ipv6_opt_hdr _hdr, *hp;
+ struct ipv6_opt_hdr _hdr;
+ const struct ipv6_opt_hdr *hp;
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
if (hp == NULL) {
@@ -92,7 +88,8 @@ static void dump_packet(const struct nf_loginfo *info,
switch (currenthdr) {
case IPPROTO_FRAGMENT: {
- struct frag_hdr _fhdr, *fh;
+ struct frag_hdr _fhdr;
+ const struct frag_hdr *fh;
printk("FRAG:");
fh = skb_header_pointer(skb, ptr, sizeof(_fhdr),
@@ -131,7 +128,8 @@ static void dump_packet(const struct nf_loginfo *info,
/* Max Length */
case IPPROTO_AH:
if (logflags & IP6T_LOG_IPOPT) {
- struct ip_auth_hdr _ahdr, *ah;
+ struct ip_auth_hdr _ahdr;
+ const struct ip_auth_hdr *ah;
/* Max length: 3 "AH " */
printk("AH ");
@@ -162,7 +160,8 @@ static void dump_packet(const struct nf_loginfo *info,
break;
case IPPROTO_ESP:
if (logflags & IP6T_LOG_IPOPT) {
- struct ip_esp_hdr _esph, *eh;
+ struct ip_esp_hdr _esph;
+ const struct ip_esp_hdr *eh;
/* Max length: 4 "ESP " */
printk("ESP ");
@@ -202,7 +201,8 @@ static void dump_packet(const struct nf_loginfo *info,
switch (currenthdr) {
case IPPROTO_TCP: {
- struct tcphdr _tcph, *th;
+ struct tcphdr _tcph;
+ const struct tcphdr *th;
/* Max length: 10 "PROTO=TCP " */
printk("PROTO=TCP ");
@@ -250,7 +250,8 @@ static void dump_packet(const struct nf_loginfo *info,
if ((logflags & IP6T_LOG_TCPOPT)
&& th->doff * 4 > sizeof(struct tcphdr)) {
- u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
+ u_int8_t _opt[60 - sizeof(struct tcphdr)];
+ const u_int8_t *op;
unsigned int i;
unsigned int optsize = th->doff * 4
- sizeof(struct tcphdr);
@@ -273,7 +274,8 @@ static void dump_packet(const struct nf_loginfo *info,
}
case IPPROTO_UDP:
case IPPROTO_UDPLITE: {
- struct udphdr _udph, *uh;
+ struct udphdr _udph;
+ const struct udphdr *uh;
if (currenthdr == IPPROTO_UDP)
/* Max length: 10 "PROTO=UDP " */
@@ -298,7 +300,8 @@ static void dump_packet(const struct nf_loginfo *info,
break;
}
case IPPROTO_ICMPV6: {
- struct icmp6hdr _icmp6h, *ic;
+ struct icmp6hdr _icmp6h;
+ const struct icmp6hdr *ic;
/* Max length: 13 "PROTO=ICMPv6 " */
printk("PROTO=ICMPv6 ");
@@ -448,27 +451,27 @@ ip6t_log_target(struct sk_buff **pskb,
}
-static int ip6t_log_checkentry(const char *tablename,
- const void *entry,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
+static bool ip6t_log_checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
{
const struct ip6t_log_info *loginfo = targinfo;
if (loginfo->level >= 8) {
- DEBUGP("LOG: level %u >= 8\n", loginfo->level);
- return 0;
+ pr_debug("LOG: level %u >= 8\n", loginfo->level);
+ return false;
}
if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
- DEBUGP("LOG: prefix term %i\n",
- loginfo->prefix[sizeof(loginfo->prefix)-1]);
- return 0;
+ pr_debug("LOG: prefix term %i\n",
+ loginfo->prefix[sizeof(loginfo->prefix)-1]);
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_target ip6t_log_reg = {
+static struct xt_target ip6t_log_reg __read_mostly = {
.name = "LOG",
.family = AF_INET6,
.target = ip6t_log_target,
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index cb3d2415a064..2f487cda3b6b 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -34,12 +34,6 @@ MODULE_AUTHOR("Yasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>");
MODULE_DESCRIPTION("IP6 tables REJECT target module");
MODULE_LICENSE("GPL");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Send RST reply */
static void send_reset(struct sk_buff *oldskb)
{
@@ -54,7 +48,7 @@ static void send_reset(struct sk_buff *oldskb)
if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
(!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
- DEBUGP("ip6t_REJECT: addr is not unicast.\n");
+ pr_debug("ip6t_REJECT: addr is not unicast.\n");
return;
}
@@ -62,16 +56,17 @@ static void send_reset(struct sk_buff *oldskb)
tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto);
if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
- DEBUGP("ip6t_REJECT: Can't get TCP header.\n");
+ pr_debug("ip6t_REJECT: Can't get TCP header.\n");
return;
}
otcplen = oldskb->len - tcphoff;
/* IP header checks: fragment, too short. */
- if ((proto != IPPROTO_TCP) || (otcplen < sizeof(struct tcphdr))) {
- DEBUGP("ip6t_REJECT: proto(%d) != IPPROTO_TCP, or too short. otcplen = %d\n",
- proto, otcplen);
+ if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
+ pr_debug("ip6t_REJECT: proto(%d) != IPPROTO_TCP, "
+ "or too short. otcplen = %d\n",
+ proto, otcplen);
return;
}
@@ -80,14 +75,14 @@ static void send_reset(struct sk_buff *oldskb)
/* No RST for RST. */
if (otcph.rst) {
- DEBUGP("ip6t_REJECT: RST is set\n");
+ pr_debug("ip6t_REJECT: RST is set\n");
return;
}
/* Check checksum. */
if (csum_ipv6_magic(&oip6h->saddr, &oip6h->daddr, otcplen, IPPROTO_TCP,
skb_checksum(oldskb, tcphoff, otcplen, 0))) {
- DEBUGP("ip6t_REJECT: TCP checksum is invalid\n");
+ pr_debug("ip6t_REJECT: TCP checksum is invalid\n");
return;
}
@@ -159,7 +154,7 @@ static void send_reset(struct sk_buff *oldskb)
tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
&ipv6_hdr(nskb)->daddr,
sizeof(struct tcphdr), IPPROTO_TCP,
- csum_partial((char *)tcph,
+ csum_partial(tcph,
sizeof(struct tcphdr), 0));
nf_ct_attach(nskb, oldskb);
@@ -186,7 +181,7 @@ static unsigned int reject6_target(struct sk_buff **pskb,
{
const struct ip6t_reject_info *reject = targinfo;
- DEBUGP(KERN_DEBUG "%s: medium point\n", __FUNCTION__);
+ pr_debug("%s: medium point\n", __FUNCTION__);
/* WARNING: This code causes reentry within ip6tables.
This means that the ip6tables jump stack is now crap. We
must return an absolute verdict. --RR */
@@ -221,30 +216,30 @@ static unsigned int reject6_target(struct sk_buff **pskb,
return NF_DROP;
}
-static int check(const char *tablename,
- const void *entry,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
+static bool check(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
{
const struct ip6t_reject_info *rejinfo = targinfo;
const struct ip6t_entry *e = entry;
if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
printk("ip6t_REJECT: ECHOREPLY is not supported.\n");
- return 0;
+ return false;
} else if (rejinfo->with == IP6T_TCP_RESET) {
/* Must specify that it's a TCP packet */
if (e->ipv6.proto != IPPROTO_TCP
|| (e->ipv6.invflags & XT_INV_PROTO)) {
- DEBUGP("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
- return 0;
+ printk("ip6t_REJECT: TCP_RESET illegal for non-tcp\n");
+ return false;
}
}
- return 1;
+ return true;
}
-static struct xt_target ip6t_reject_reg = {
+static struct xt_target ip6t_reject_reg __read_mostly = {
.name = "REJECT",
.family = AF_INET6,
.target = reject6_target,
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
index d3c154371b41..2a25fe25e0e0 100644
--- a/net/ipv6/netfilter/ip6t_ah.c
+++ b/net/ipv6/netfilter/ip6t_ah.c
@@ -23,25 +23,20 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 AH match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Returns 1 if the spi is matched by the range, 0 otherwise */
-static inline int
-spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+static inline bool
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
{
- int r=0;
- DEBUGP("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
- min,spi,max);
+ bool r;
+
+ pr_debug("ah spi_match:%c 0x%x <= 0x%x <= 0x%x",
+ invert ? '!' : ' ', min, spi, max);
r = (spi >= min && spi <= max) ^ invert;
- DEBUGP(" result %s\n",r? "PASS\n" : "FAILED\n");
+ pr_debug(" result %s\n", r ? "PASS" : "FAILED");
return r;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -49,9 +44,10 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct ip_auth_hdr *ah, _ah;
+ struct ip_auth_hdr _ah;
+ const struct ip_auth_hdr *ah;
const struct ip6t_ah *ahinfo = matchinfo;
unsigned int ptr;
unsigned int hdrlen = 0;
@@ -60,40 +56,40 @@ match(const struct sk_buff *skb,
err = ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL);
if (err < 0) {
if (err != -ENOENT)
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah);
if (ah == NULL) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
hdrlen = (ah->hdrlen + 2) << 2;
- DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
- DEBUGP("RES %04X ", ah->reserved);
- DEBUGP("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
-
- DEBUGP("IPv6 AH spi %02X ",
- (spi_match(ahinfo->spis[0], ahinfo->spis[1],
- ntohl(ah->spi),
- !!(ahinfo->invflags & IP6T_AH_INV_SPI))));
- DEBUGP("len %02X %04X %02X ",
- ahinfo->hdrlen, hdrlen,
- (!ahinfo->hdrlen ||
- (ahinfo->hdrlen == hdrlen) ^
- !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
- DEBUGP("res %02X %04X %02X\n",
- ahinfo->hdrres, ah->reserved,
- !(ahinfo->hdrres && ah->reserved));
+ pr_debug("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
+ pr_debug("RES %04X ", ah->reserved);
+ pr_debug("SPI %u %08X\n", ntohl(ah->spi), ntohl(ah->spi));
+
+ pr_debug("IPv6 AH spi %02X ",
+ spi_match(ahinfo->spis[0], ahinfo->spis[1],
+ ntohl(ah->spi),
+ !!(ahinfo->invflags & IP6T_AH_INV_SPI)));
+ pr_debug("len %02X %04X %02X ",
+ ahinfo->hdrlen, hdrlen,
+ (!ahinfo->hdrlen ||
+ (ahinfo->hdrlen == hdrlen) ^
+ !!(ahinfo->invflags & IP6T_AH_INV_LEN)));
+ pr_debug("res %02X %04X %02X\n",
+ ahinfo->hdrres, ah->reserved,
+ !(ahinfo->hdrres && ah->reserved));
return (ah != NULL)
&&
- (spi_match(ahinfo->spis[0], ahinfo->spis[1],
- ntohl(ah->spi),
- !!(ahinfo->invflags & IP6T_AH_INV_SPI)))
+ spi_match(ahinfo->spis[0], ahinfo->spis[1],
+ ntohl(ah->spi),
+ !!(ahinfo->invflags & IP6T_AH_INV_SPI))
&&
(!ahinfo->hdrlen ||
(ahinfo->hdrlen == hdrlen) ^
@@ -103,7 +99,7 @@ match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
checkentry(const char *tablename,
const void *entry,
const struct xt_match *match,
@@ -113,13 +109,13 @@ checkentry(const char *tablename,
const struct ip6t_ah *ahinfo = matchinfo;
if (ahinfo->invflags & ~IP6T_AH_INV_MASK) {
- DEBUGP("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
- return 0;
+ pr_debug("ip6t_ah: unknown flags %X\n", ahinfo->invflags);
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match ah_match = {
+static struct xt_match ah_match __read_mostly = {
.name = "ah",
.family = AF_INET6,
.match = match,
diff --git a/net/ipv6/netfilter/ip6t_eui64.c b/net/ipv6/netfilter/ip6t_eui64.c
index 0f3dd932f0a6..34ba150bfe5d 100644
--- a/net/ipv6/netfilter/ip6t_eui64.c
+++ b/net/ipv6/netfilter/ip6t_eui64.c
@@ -19,7 +19,7 @@ MODULE_DESCRIPTION("IPv6 EUI64 address checking match");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -27,16 +27,16 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
unsigned char eui64[8];
int i = 0;
if (!(skb_mac_header(skb) >= skb->head &&
- (skb_mac_header(skb) + ETH_HLEN) <= skb->data) &&
+ skb_mac_header(skb) + ETH_HLEN <= skb->data) &&
offset != 0) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
memset(eui64, 0, sizeof(eui64));
@@ -50,19 +50,19 @@ match(const struct sk_buff *skb,
eui64[0] |= 0x02;
i = 0;
- while ((ipv6_hdr(skb)->saddr.s6_addr[8 + i] == eui64[i])
- && (i < 8))
+ while (ipv6_hdr(skb)->saddr.s6_addr[8 + i] == eui64[i]
+ && i < 8)
i++;
if (i == 8)
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
-static struct xt_match eui64_match = {
+static struct xt_match eui64_match __read_mostly = {
.name = "eui64",
.family = AF_INET6,
.match = match,
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
index 5a5da71321b6..968aeba02073 100644
--- a/net/ipv6/netfilter/ip6t_frag.c
+++ b/net/ipv6/netfilter/ip6t_frag.c
@@ -22,25 +22,19 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 FRAG match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Returns 1 if the id is matched by the range, 0 otherwise */
-static inline int
-id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
+static inline bool
+id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
{
- int r = 0;
- DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
- min, id, max);
+ bool r;
+ pr_debug("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
+ min, id, max);
r = (id >= min && id <= max) ^ invert;
- DEBUGP(" result %s\n", r ? "PASS" : "FAILED");
+ pr_debug(" result %s\n", r ? "PASS" : "FAILED");
return r;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -48,9 +42,10 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct frag_hdr _frag, *fh;
+ struct frag_hdr _frag;
+ const struct frag_hdr *fh;
const struct ip6t_frag *fraginfo = matchinfo;
unsigned int ptr;
int err;
@@ -58,53 +53,53 @@ match(const struct sk_buff *skb,
err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL);
if (err < 0) {
if (err != -ENOENT)
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
if (fh == NULL) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
- DEBUGP("INFO %04X ", fh->frag_off);
- DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
- DEBUGP("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6);
- DEBUGP("MF %04X ", fh->frag_off & htons(IP6_MF));
- DEBUGP("ID %u %08X\n", ntohl(fh->identification),
- ntohl(fh->identification));
-
- DEBUGP("IPv6 FRAG id %02X ",
- (id_match(fraginfo->ids[0], fraginfo->ids[1],
- ntohl(fh->identification),
- !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
- DEBUGP("res %02X %02X%04X %02X ",
- (fraginfo->flags & IP6T_FRAG_RES), fh->reserved,
- ntohs(fh->frag_off) & 0x6,
- !((fraginfo->flags & IP6T_FRAG_RES)
- && (fh->reserved || (ntohs(fh->frag_off) & 0x06))));
- DEBUGP("first %02X %02X %02X ",
- (fraginfo->flags & IP6T_FRAG_FST),
- ntohs(fh->frag_off) & ~0x7,
- !((fraginfo->flags & IP6T_FRAG_FST)
- && (ntohs(fh->frag_off) & ~0x7)));
- DEBUGP("mf %02X %02X %02X ",
- (fraginfo->flags & IP6T_FRAG_MF),
- ntohs(fh->frag_off) & IP6_MF,
- !((fraginfo->flags & IP6T_FRAG_MF)
- && !((ntohs(fh->frag_off) & IP6_MF))));
- DEBUGP("last %02X %02X %02X\n",
- (fraginfo->flags & IP6T_FRAG_NMF),
- ntohs(fh->frag_off) & IP6_MF,
- !((fraginfo->flags & IP6T_FRAG_NMF)
- && (ntohs(fh->frag_off) & IP6_MF)));
+ pr_debug("INFO %04X ", fh->frag_off);
+ pr_debug("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7);
+ pr_debug("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6);
+ pr_debug("MF %04X ", fh->frag_off & htons(IP6_MF));
+ pr_debug("ID %u %08X\n", ntohl(fh->identification),
+ ntohl(fh->identification));
+
+ pr_debug("IPv6 FRAG id %02X ",
+ id_match(fraginfo->ids[0], fraginfo->ids[1],
+ ntohl(fh->identification),
+ !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)));
+ pr_debug("res %02X %02X%04X %02X ",
+ fraginfo->flags & IP6T_FRAG_RES, fh->reserved,
+ ntohs(fh->frag_off) & 0x6,
+ !((fraginfo->flags & IP6T_FRAG_RES)
+ && (fh->reserved || (ntohs(fh->frag_off) & 0x06))));
+ pr_debug("first %02X %02X %02X ",
+ fraginfo->flags & IP6T_FRAG_FST,
+ ntohs(fh->frag_off) & ~0x7,
+ !((fraginfo->flags & IP6T_FRAG_FST)
+ && (ntohs(fh->frag_off) & ~0x7)));
+ pr_debug("mf %02X %02X %02X ",
+ fraginfo->flags & IP6T_FRAG_MF,
+ ntohs(fh->frag_off) & IP6_MF,
+ !((fraginfo->flags & IP6T_FRAG_MF)
+ && !((ntohs(fh->frag_off) & IP6_MF))));
+ pr_debug("last %02X %02X %02X\n",
+ fraginfo->flags & IP6T_FRAG_NMF,
+ ntohs(fh->frag_off) & IP6_MF,
+ !((fraginfo->flags & IP6T_FRAG_NMF)
+ && (ntohs(fh->frag_off) & IP6_MF)));
return (fh != NULL)
&&
- (id_match(fraginfo->ids[0], fraginfo->ids[1],
- ntohl(fh->identification),
- !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
+ id_match(fraginfo->ids[0], fraginfo->ids[1],
+ ntohl(fh->identification),
+ !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))
&&
!((fraginfo->flags & IP6T_FRAG_RES)
&& (fh->reserved || (ntohs(fh->frag_off) & 0x6)))
@@ -120,7 +115,7 @@ match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
checkentry(const char *tablename,
const void *ip,
const struct xt_match *match,
@@ -130,13 +125,13 @@ checkentry(const char *tablename,
const struct ip6t_frag *fraginfo = matchinfo;
if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
- DEBUGP("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
- return 0;
+ pr_debug("ip6t_frag: unknown flags %X\n", fraginfo->invflags);
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match frag_match = {
+static struct xt_match frag_match __read_mostly = {
.name = "frag",
.family = AF_INET6,
.match = match,
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c
index d2373c7cd354..e6ca6018b1ea 100644
--- a/net/ipv6/netfilter/ip6t_hbh.c
+++ b/net/ipv6/netfilter/ip6t_hbh.c
@@ -25,12 +25,6 @@ MODULE_DESCRIPTION("IPv6 opts match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
MODULE_ALIAS("ip6t_dst");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/*
* (Type & 0xC0) >> 6
* 0 -> ignorable
@@ -47,7 +41,7 @@ MODULE_ALIAS("ip6t_dst");
* 5 -> RTALERT 2 x x
*/
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -55,45 +49,48 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct ipv6_opt_hdr _optsh, *oh;
+ struct ipv6_opt_hdr _optsh;
+ const struct ipv6_opt_hdr *oh;
const struct ip6t_opts *optinfo = matchinfo;
unsigned int temp;
unsigned int ptr;
unsigned int hdrlen = 0;
- unsigned int ret = 0;
- u8 _opttype, *tp = NULL;
- u8 _optlen, *lp = NULL;
+ bool ret = false;
+ u8 _opttype;
+ u8 _optlen;
+ const u_int8_t *tp = NULL;
+ const u_int8_t *lp = NULL;
unsigned int optlen;
int err;
err = ipv6_find_hdr(skb, &ptr, match->data, NULL);
if (err < 0) {
if (err != -ENOENT)
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh);
if (oh == NULL) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
hdrlen = ipv6_optlen(oh);
if (skb->len - ptr < hdrlen) {
/* Packet smaller than it's length field */
- return 0;
+ return false;
}
- DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
+ pr_debug("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen);
- DEBUGP("len %02X %04X %02X ",
- optinfo->hdrlen, hdrlen,
- (!(optinfo->flags & IP6T_OPTS_LEN) ||
- ((optinfo->hdrlen == hdrlen) ^
- !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
+ pr_debug("len %02X %04X %02X ",
+ optinfo->hdrlen, hdrlen,
+ (!(optinfo->flags & IP6T_OPTS_LEN) ||
+ ((optinfo->hdrlen == hdrlen) ^
+ !!(optinfo->invflags & IP6T_OPTS_INV_LEN))));
ret = (oh != NULL) &&
(!(optinfo->flags & IP6T_OPTS_LEN) ||
@@ -105,10 +102,10 @@ match(const struct sk_buff *skb,
if (!(optinfo->flags & IP6T_OPTS_OPTS)) {
return ret;
} else if (optinfo->flags & IP6T_OPTS_NSTRICT) {
- DEBUGP("Not strict - not implemented");
+ pr_debug("Not strict - not implemented");
} else {
- DEBUGP("Strict ");
- DEBUGP("#%d ", optinfo->optsnr);
+ pr_debug("Strict ");
+ pr_debug("#%d ", optinfo->optsnr);
for (temp = 0; temp < optinfo->optsnr; temp++) {
/* type field exists ? */
if (hdrlen < 1)
@@ -120,12 +117,11 @@ match(const struct sk_buff *skb,
/* Type check */
if (*tp != (optinfo->opts[temp] & 0xFF00) >> 8) {
- DEBUGP("Tbad %02X %02X\n",
- *tp,
- (optinfo->opts[temp] & 0xFF00) >> 8);
- return 0;
+ pr_debug("Tbad %02X %02X\n", *tp,
+ (optinfo->opts[temp] & 0xFF00) >> 8);
+ return false;
} else {
- DEBUGP("Tok ");
+ pr_debug("Tok ");
}
/* Length check */
if (*tp) {
@@ -142,23 +138,23 @@ match(const struct sk_buff *skb,
spec_len = optinfo->opts[temp] & 0x00FF;
if (spec_len != 0x00FF && spec_len != *lp) {
- DEBUGP("Lbad %02X %04X\n", *lp,
- spec_len);
- return 0;
+ pr_debug("Lbad %02X %04X\n", *lp,
+ spec_len);
+ return false;
}
- DEBUGP("Lok ");
+ pr_debug("Lok ");
optlen = *lp + 2;
} else {
- DEBUGP("Pad1\n");
+ pr_debug("Pad1\n");
optlen = 1;
}
/* Step to the next */
- DEBUGP("len%04X \n", optlen);
+ pr_debug("len%04X \n", optlen);
if ((ptr > skb->len - optlen || hdrlen < optlen) &&
- (temp < optinfo->optsnr - 1)) {
- DEBUGP("new pointer is too large! \n");
+ temp < optinfo->optsnr - 1) {
+ pr_debug("new pointer is too large! \n");
break;
}
ptr += optlen;
@@ -167,14 +163,14 @@ match(const struct sk_buff *skb,
if (temp == optinfo->optsnr)
return ret;
else
- return 0;
+ return false;
}
- return 0;
+ return false;
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
checkentry(const char *tablename,
const void *entry,
const struct xt_match *match,
@@ -184,13 +180,13 @@ checkentry(const char *tablename,
const struct ip6t_opts *optsinfo = matchinfo;
if (optsinfo->invflags & ~IP6T_OPTS_INV_MASK) {
- DEBUGP("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
- return 0;
+ pr_debug("ip6t_opts: unknown flags %X\n", optsinfo->invflags);
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match opts_match[] = {
+static struct xt_match opts_match[] __read_mostly = {
{
.name = "hbh",
.family = AF_INET6,
diff --git a/net/ipv6/netfilter/ip6t_hl.c b/net/ipv6/netfilter/ip6t_hl.c
index d606c0e6d6fd..ca29ec00dc18 100644
--- a/net/ipv6/netfilter/ip6t_hl.c
+++ b/net/ipv6/netfilter/ip6t_hl.c
@@ -19,37 +19,37 @@ MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("IP tables Hop Limit matching module");
MODULE_LICENSE("GPL");
-static int match(const struct sk_buff *skb,
- const struct net_device *in, const struct net_device *out,
- const struct xt_match *match, const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+static bool match(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
{
const struct ip6t_hl_info *info = matchinfo;
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
switch (info->mode) {
case IP6T_HL_EQ:
- return (ip6h->hop_limit == info->hop_limit);
+ return ip6h->hop_limit == info->hop_limit;
break;
case IP6T_HL_NE:
- return (!(ip6h->hop_limit == info->hop_limit));
+ return ip6h->hop_limit != info->hop_limit;
break;
case IP6T_HL_LT:
- return (ip6h->hop_limit < info->hop_limit);
+ return ip6h->hop_limit < info->hop_limit;
break;
case IP6T_HL_GT:
- return (ip6h->hop_limit > info->hop_limit);
+ return ip6h->hop_limit > info->hop_limit;
break;
default:
printk(KERN_WARNING "ip6t_hl: unknown mode %d\n",
info->mode);
- return 0;
+ return false;
}
- return 0;
+ return false;
}
-static struct xt_match hl_match = {
+static struct xt_match hl_match __read_mostly = {
.name = "hl",
.family = AF_INET6,
.match = match,
diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
index fd6a0869099b..2c65c2f9a4ab 100644
--- a/net/ipv6/netfilter/ip6t_ipv6header.c
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c
@@ -26,7 +26,7 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 headers match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
-static int
+static bool
ipv6header_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -34,7 +34,7 @@ ipv6header_match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct ip6t_ipv6header_info *info = matchinfo;
unsigned int temp;
@@ -58,7 +58,7 @@ ipv6header_match(const struct sk_buff *skb,
/* Is there enough space for the next ext header? */
if (len < (int)sizeof(struct ipv6_opt_hdr))
- return 0;
+ return false;
/* No more exthdr -> evaluate */
if (nexthdr == NEXTHDR_NONE) {
temp |= MASK_NONE;
@@ -74,9 +74,9 @@ ipv6header_match(const struct sk_buff *skb,
BUG_ON(hp == NULL);
/* Calculate the header length */
- if (nexthdr == NEXTHDR_FRAGMENT) {
+ if (nexthdr == NEXTHDR_FRAGMENT)
hdrlen = 8;
- } else if (nexthdr == NEXTHDR_AUTH)
+ else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hp->hdrlen + 2) << 2;
else
hdrlen = ipv6_optlen(hp);
@@ -99,7 +99,7 @@ ipv6header_match(const struct sk_buff *skb,
temp |= MASK_DSTOPTS;
break;
default:
- return 0;
+ return false;
break;
}
@@ -110,7 +110,7 @@ ipv6header_match(const struct sk_buff *skb,
break;
}
- if ((nexthdr != NEXTHDR_NONE) && (nexthdr != NEXTHDR_ESP))
+ if (nexthdr != NEXTHDR_NONE && nexthdr != NEXTHDR_ESP)
temp |= MASK_PROTO;
if (info->modeflag)
@@ -124,7 +124,7 @@ ipv6header_match(const struct sk_buff *skb,
}
}
-static int
+static bool
ipv6header_checkentry(const char *tablename,
const void *ip,
const struct xt_match *match,
@@ -136,12 +136,12 @@ ipv6header_checkentry(const char *tablename,
/* invflags is 0 or 0xff in hard mode */
if ((!info->modeflag) && info->invflags != 0x00 &&
info->invflags != 0xFF)
- return 0;
+ return false;
- return 1;
+ return true;
}
-static struct xt_match ip6t_ipv6header_match = {
+static struct xt_match ip6t_ipv6header_match __read_mostly = {
.name = "ipv6header",
.family = AF_INET6,
.match = &ipv6header_match,
diff --git a/net/ipv6/netfilter/ip6t_mh.c b/net/ipv6/netfilter/ip6t_mh.c
index c2a909893a64..0fa714092dc9 100644
--- a/net/ipv6/netfilter/ip6t_mh.c
+++ b/net/ipv6/netfilter/ip6t_mh.c
@@ -31,16 +31,13 @@ MODULE_LICENSE("GPL");
#endif
/* Returns 1 if the type is matched by the range, 0 otherwise */
-static inline int
-type_match(u_int8_t min, u_int8_t max, u_int8_t type, int invert)
+static inline bool
+type_match(u_int8_t min, u_int8_t max, u_int8_t type, bool invert)
{
- int ret;
-
- ret = (type >= min && type <= max) ^ invert;
- return ret;
+ return (type >= min && type <= max) ^ invert;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -48,29 +45,30 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct ip6_mh _mh, *mh;
+ struct ip6_mh _mh;
+ const struct ip6_mh *mh;
const struct ip6t_mh *mhinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
- return 0;
+ return false;
mh = skb_header_pointer(skb, protoff, sizeof(_mh), &_mh);
if (mh == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil MH tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
if (mh->ip6mh_proto != IPPROTO_NONE) {
duprintf("Dropping invalid MH Payload Proto: %u\n",
mh->ip6mh_proto);
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
return type_match(mhinfo->types[0], mhinfo->types[1], mh->ip6mh_type,
@@ -78,7 +76,7 @@ match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
mh_checkentry(const char *tablename,
const void *entry,
const struct xt_match *match,
@@ -91,7 +89,7 @@ mh_checkentry(const char *tablename,
return !(mhinfo->invflags & ~IP6T_MH_INV_MASK);
}
-static struct xt_match mh_match = {
+static struct xt_match mh_match __read_mostly = {
.name = "mh",
.family = AF_INET6,
.checkentry = mh_checkentry,
diff --git a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c
index 43738bba00b5..6036613aef36 100644
--- a/net/ipv6/netfilter/ip6t_owner.c
+++ b/net/ipv6/netfilter/ip6t_owner.c
@@ -23,7 +23,7 @@ MODULE_DESCRIPTION("IP6 tables owner matching module");
MODULE_LICENSE("GPL");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -31,29 +31,27 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct ip6t_owner_info *info = matchinfo;
if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file)
- return 0;
+ return false;
- if (info->match & IP6T_OWNER_UID) {
+ if (info->match & IP6T_OWNER_UID)
if ((skb->sk->sk_socket->file->f_uid != info->uid) ^
!!(info->invert & IP6T_OWNER_UID))
- return 0;
- }
+ return false;
- if (info->match & IP6T_OWNER_GID) {
+ if (info->match & IP6T_OWNER_GID)
if ((skb->sk->sk_socket->file->f_gid != info->gid) ^
!!(info->invert & IP6T_OWNER_GID))
- return 0;
- }
+ return false;
- return 1;
+ return true;
}
-static int
+static bool
checkentry(const char *tablename,
const void *ip,
const struct xt_match *match,
@@ -65,12 +63,12 @@ checkentry(const char *tablename,
if (info->match & (IP6T_OWNER_PID | IP6T_OWNER_SID)) {
printk("ipt_owner: pid and sid matching "
"not supported anymore\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match owner_match = {
+static struct xt_match owner_match __read_mostly = {
.name = "owner",
.family = AF_INET6,
.match = match,
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 81ab00d8c182..357cea703bd9 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -24,25 +24,19 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IPv6 RT match");
MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Returns 1 if the id is matched by the range, 0 otherwise */
-static inline int
-segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
+static inline bool
+segsleft_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
{
- int r = 0;
- DEBUGP("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",
- invert ? '!' : ' ', min, id, max);
+ bool r;
+ pr_debug("rt segsleft_match:%c 0x%x <= 0x%x <= 0x%x",
+ invert ? '!' : ' ', min, id, max);
r = (id >= min && id <= max) ^ invert;
- DEBUGP(" result %s\n", r ? "PASS" : "FAILED");
+ pr_debug(" result %s\n", r ? "PASS" : "FAILED");
return r;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -50,59 +44,61 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct ipv6_rt_hdr _route, *rh;
+ struct ipv6_rt_hdr _route;
+ const struct ipv6_rt_hdr *rh;
const struct ip6t_rt *rtinfo = matchinfo;
unsigned int temp;
unsigned int ptr;
unsigned int hdrlen = 0;
- unsigned int ret = 0;
- struct in6_addr *ap, _addr;
+ bool ret = false;
+ struct in6_addr _addr;
+ const struct in6_addr *ap;
int err;
err = ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL);
if (err < 0) {
if (err != -ENOENT)
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route);
if (rh == NULL) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
hdrlen = ipv6_optlen(rh);
if (skb->len - ptr < hdrlen) {
/* Pcket smaller than its length field */
- return 0;
+ return false;
}
- DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
- DEBUGP("TYPE %04X ", rh->type);
- DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);
-
- DEBUGP("IPv6 RT segsleft %02X ",
- (segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
- rh->segments_left,
- !!(rtinfo->invflags & IP6T_RT_INV_SGS))));
- DEBUGP("type %02X %02X %02X ",
- rtinfo->rt_type, rh->type,
- (!(rtinfo->flags & IP6T_RT_TYP) ||
- ((rtinfo->rt_type == rh->type) ^
- !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
- DEBUGP("len %02X %04X %02X ",
- rtinfo->hdrlen, hdrlen,
- (!(rtinfo->flags & IP6T_RT_LEN) ||
- ((rtinfo->hdrlen == hdrlen) ^
- !!(rtinfo->invflags & IP6T_RT_INV_LEN))));
- DEBUGP("res %02X %02X %02X ",
- (rtinfo->flags & IP6T_RT_RES),
- ((struct rt0_hdr *)rh)->reserved,
- !((rtinfo->flags & IP6T_RT_RES) &&
- (((struct rt0_hdr *)rh)->reserved)));
+ pr_debug("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen);
+ pr_debug("TYPE %04X ", rh->type);
+ pr_debug("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left);
+
+ pr_debug("IPv6 RT segsleft %02X ",
+ segsleft_match(rtinfo->segsleft[0], rtinfo->segsleft[1],
+ rh->segments_left,
+ !!(rtinfo->invflags & IP6T_RT_INV_SGS)));
+ pr_debug("type %02X %02X %02X ",
+ rtinfo->rt_type, rh->type,
+ (!(rtinfo->flags & IP6T_RT_TYP) ||
+ ((rtinfo->rt_type == rh->type) ^
+ !!(rtinfo->invflags & IP6T_RT_INV_TYP))));
+ pr_debug("len %02X %04X %02X ",
+ rtinfo->hdrlen, hdrlen,
+ !(rtinfo->flags & IP6T_RT_LEN) ||
+ ((rtinfo->hdrlen == hdrlen) ^
+ !!(rtinfo->invflags & IP6T_RT_INV_LEN)));
+ pr_debug("res %02X %02X %02X ",
+ rtinfo->flags & IP6T_RT_RES,
+ ((const struct rt0_hdr *)rh)->reserved,
+ !((rtinfo->flags & IP6T_RT_RES) &&
+ (((const struct rt0_hdr *)rh)->reserved)));
ret = (rh != NULL)
&&
@@ -129,18 +125,18 @@ match(const struct sk_buff *skb,
ret = (*rp == 0);
}
- DEBUGP("#%d ", rtinfo->addrnr);
+ pr_debug("#%d ", rtinfo->addrnr);
if (!(rtinfo->flags & IP6T_RT_FST)) {
return ret;
} else if (rtinfo->flags & IP6T_RT_FST_NSTRICT) {
- DEBUGP("Not strict ");
+ pr_debug("Not strict ");
if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) {
- DEBUGP("There isn't enough space\n");
- return 0;
+ pr_debug("There isn't enough space\n");
+ return false;
} else {
unsigned int i = 0;
- DEBUGP("#%d ", rtinfo->addrnr);
+ pr_debug("#%d ", rtinfo->addrnr);
for (temp = 0;
temp < (unsigned int)((hdrlen - 8) / 16);
temp++) {
@@ -154,25 +150,25 @@ match(const struct sk_buff *skb,
BUG_ON(ap == NULL);
if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) {
- DEBUGP("i=%d temp=%d;\n", i, temp);
+ pr_debug("i=%d temp=%d;\n", i, temp);
i++;
}
if (i == rtinfo->addrnr)
break;
}
- DEBUGP("i=%d #%d\n", i, rtinfo->addrnr);
+ pr_debug("i=%d #%d\n", i, rtinfo->addrnr);
if (i == rtinfo->addrnr)
return ret;
else
- return 0;
+ return false;
}
} else {
- DEBUGP("Strict ");
+ pr_debug("Strict ");
if (rtinfo->addrnr > (unsigned int)((hdrlen - 8) / 16)) {
- DEBUGP("There isn't enough space\n");
- return 0;
+ pr_debug("There isn't enough space\n");
+ return false;
} else {
- DEBUGP("#%d ", rtinfo->addrnr);
+ pr_debug("#%d ", rtinfo->addrnr);
for (temp = 0; temp < rtinfo->addrnr; temp++) {
ap = skb_header_pointer(skb,
ptr
@@ -185,20 +181,20 @@ match(const struct sk_buff *skb,
if (!ipv6_addr_equal(ap, &rtinfo->addrs[temp]))
break;
}
- DEBUGP("temp=%d #%d\n", temp, rtinfo->addrnr);
- if ((temp == rtinfo->addrnr) &&
- (temp == (unsigned int)((hdrlen - 8) / 16)))
+ pr_debug("temp=%d #%d\n", temp, rtinfo->addrnr);
+ if (temp == rtinfo->addrnr &&
+ temp == (unsigned int)((hdrlen - 8) / 16))
return ret;
else
- return 0;
+ return false;
}
}
- return 0;
+ return false;
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
checkentry(const char *tablename,
const void *entry,
const struct xt_match *match,
@@ -208,21 +204,21 @@ checkentry(const char *tablename,
const struct ip6t_rt *rtinfo = matchinfo;
if (rtinfo->invflags & ~IP6T_RT_INV_MASK) {
- DEBUGP("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
- return 0;
+ pr_debug("ip6t_rt: unknown flags %X\n", rtinfo->invflags);
+ return false;
}
if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) &&
(!(rtinfo->flags & IP6T_RT_TYP) ||
(rtinfo->rt_type != 0) ||
(rtinfo->invflags & IP6T_RT_INV_TYP))) {
- DEBUGP("`--rt-type 0' required before `--rt-0-*'");
- return 0;
+ pr_debug("`--rt-type 0' required before `--rt-0-*'");
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match rt_match = {
+static struct xt_match rt_match __read_mostly = {
.name = "rt",
.family = AF_INET6,
.match = match,
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index f2d26495f413..f0a9efa67fb5 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -21,12 +21,6 @@ MODULE_DESCRIPTION("ip6tables mangle table");
(1 << NF_IP6_LOCAL_OUT) | \
(1 << NF_IP6_POST_ROUTING))
-#if 0
-#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
-#else
-#define DEBUGP(x, args...)
-#endif
-
static struct
{
struct ip6t_replace repl;
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index 0acda45d455d..ec290e4ebdd8 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -8,12 +8,6 @@
#define RAW_VALID_HOOKS ((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_OUT))
-#if 0
-#define DEBUGP(x, args...) printk(KERN_DEBUG x, ## args)
-#else
-#define DEBUGP(x, args...)
-#endif
-
static struct
{
struct ip6t_replace repl;
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 1b1797f1f33d..36df2218b669 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -26,12 +26,6 @@
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_core.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
{
@@ -92,7 +86,7 @@ static int ipv6_print_conntrack(struct seq_file *s,
* - Note also special handling of AUTH header. Thanks to IPsec wizards.
*/
-int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
+int nf_ct_ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
int len)
{
u8 nexthdr = *nexthdrp;
@@ -123,22 +117,25 @@ int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp,
return start;
}
-static int
-ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
- u_int8_t *protonum)
+static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum)
{
- unsigned int extoff = (u8 *)(ipv6_hdr(*pskb) + 1) - (*pskb)->data;
- unsigned char pnum = ipv6_hdr(*pskb)->nexthdr;
- int protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
- (*pskb)->len - extoff);
+ unsigned int extoff = nhoff + sizeof(struct ipv6hdr);
+ unsigned char pnum;
+ int protoff;
+
+ if (skb_copy_bits(skb, nhoff + offsetof(struct ipv6hdr, nexthdr),
+ &pnum, sizeof(pnum)) != 0) {
+ pr_debug("ip6_conntrack_core: can't get nexthdr\n");
+ return -NF_ACCEPT;
+ }
+ protoff = nf_ct_ipv6_skip_exthdr(skb, extoff, &pnum, skb->len - extoff);
/*
- * (protoff == (*pskb)->len) mean that the packet doesn't have no data
+ * (protoff == skb->len) mean that the packet doesn't have no data
* except of IPv6 & ext headers. but it's tracked anyway. - YK
*/
- if ((protoff < 0) || (protoff > (*pskb)->len)) {
- DEBUGP("ip6_conntrack_core: can't find proto in pkt\n");
- NF_CT_STAT_INC_ATOMIC(error);
- NF_CT_STAT_INC_ATOMIC(invalid);
+ if ((protoff < 0) || (protoff > skb->len)) {
+ pr_debug("ip6_conntrack_core: can't find proto in pkt\n");
return -NF_ACCEPT;
}
@@ -147,11 +144,6 @@ ipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff,
return NF_ACCEPT;
}
-static u_int32_t ipv6_get_features(const struct nf_conntrack_tuple *tuple)
-{
- return NF_CT_F_BASIC;
-}
-
static unsigned int ipv6_confirm(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
@@ -183,7 +175,7 @@ static unsigned int ipv6_confirm(unsigned int hooknum,
protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum,
(*pskb)->len - extoff);
if (protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) {
- DEBUGP("proto header not found\n");
+ pr_debug("proto header not found\n");
return NF_ACCEPT;
}
@@ -381,14 +373,14 @@ static int ipv6_nfattr_to_tuple(struct nfattr *tb[],
}
#endif
-struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
+struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 __read_mostly = {
.l3proto = PF_INET6,
.name = "ipv6",
.pkt_to_tuple = ipv6_pkt_to_tuple,
.invert_tuple = ipv6_invert_tuple,
.print_tuple = ipv6_print_tuple,
.print_conntrack = ipv6_print_conntrack,
- .prepare = ipv6_prepare,
+ .get_l4proto = ipv6_get_l4proto,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv6_tuple_to_nfattr,
.nfattr_to_tuple = ipv6_nfattr_to_tuple,
@@ -397,7 +389,6 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
.ctl_table_path = nf_net_netfilter_sysctl_path,
.ctl_table = nf_ct_ipv6_sysctl_table,
#endif
- .get_features = ipv6_get_features,
.me = THIS_MODULE,
};
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index 8814b95b2326..ab154fb90018 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -27,12 +27,6 @@
static unsigned long nf_ct_icmpv6_timeout __read_mostly = 30*HZ;
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct nf_conntrack_tuple *tuple)
@@ -125,8 +119,8 @@ static int icmpv6_new(struct nf_conn *conntrack,
if (type < 0 || type >= sizeof(valid_new) || !valid_new[type]) {
/* Can't create a new ICMPv6 `conn' with this. */
- DEBUGP("icmpv6: can't create new conn with type %u\n",
- type + 128);
+ pr_debug("icmpv6: can't create new conn with type %u\n",
+ type + 128);
NF_CT_DUMP_TUPLE(&conntrack->tuplehash[0].tuple);
return 0;
}
@@ -142,60 +136,36 @@ icmpv6_error_message(struct sk_buff *skb,
{
struct nf_conntrack_tuple intuple, origtuple;
struct nf_conntrack_tuple_hash *h;
- struct icmp6hdr _hdr, *hp;
- unsigned int inip6off;
struct nf_conntrack_l4proto *inproto;
- u_int8_t inprotonum;
- unsigned int inprotoff;
NF_CT_ASSERT(skb->nfct == NULL);
- hp = skb_header_pointer(skb, icmp6off, sizeof(_hdr), &_hdr);
- if (hp == NULL) {
- DEBUGP("icmpv6_error: Can't get ICMPv6 hdr.\n");
- return -NF_ACCEPT;
- }
-
- inip6off = icmp6off + sizeof(_hdr);
- if (skb_copy_bits(skb, inip6off+offsetof(struct ipv6hdr, nexthdr),
- &inprotonum, sizeof(inprotonum)) != 0) {
- DEBUGP("icmpv6_error: Can't get nexthdr in inner IPv6 header.\n");
- return -NF_ACCEPT;
- }
- inprotoff = nf_ct_ipv6_skip_exthdr(skb,
- inip6off + sizeof(struct ipv6hdr),
- &inprotonum,
- skb->len - inip6off
- - sizeof(struct ipv6hdr));
-
- if ((inprotoff > skb->len) || (inprotonum == NEXTHDR_FRAGMENT)) {
- DEBUGP("icmpv6_error: Can't get protocol header in ICMPv6 payload.\n");
+ /* Are they talking about one of our connections? */
+ if (!nf_ct_get_tuplepr(skb,
+ skb_network_offset(skb)
+ + sizeof(struct ipv6hdr)
+ + sizeof(struct icmp6hdr),
+ PF_INET6, &origtuple)) {
+ pr_debug("icmpv6_error: Can't get tuple\n");
return -NF_ACCEPT;
}
/* rcu_read_lock()ed by nf_hook_slow */
- inproto = __nf_ct_l4proto_find(PF_INET6, inprotonum);
-
- /* Are they talking about one of our connections? */
- if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
- &origtuple, &nf_conntrack_l3proto_ipv6, inproto)) {
- DEBUGP("icmpv6_error: Can't get tuple\n");
- return -NF_ACCEPT;
- }
+ inproto = __nf_ct_l4proto_find(PF_INET6, origtuple.dst.protonum);
/* Ordinarily, we'd expect the inverted tupleproto, but it's
been preserved inside the ICMP. */
if (!nf_ct_invert_tuple(&intuple, &origtuple,
&nf_conntrack_l3proto_ipv6, inproto)) {
- DEBUGP("icmpv6_error: Can't invert tuple\n");
+ pr_debug("icmpv6_error: Can't invert tuple\n");
return -NF_ACCEPT;
}
*ctinfo = IP_CT_RELATED;
- h = nf_conntrack_find_get(&intuple, NULL);
+ h = nf_conntrack_find_get(&intuple);
if (!h) {
- DEBUGP("icmpv6_error: no match\n");
+ pr_debug("icmpv6_error: no match\n");
return -NF_ACCEPT;
} else {
if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY)
@@ -306,7 +276,7 @@ static struct ctl_table icmpv6_sysctl_table[] = {
};
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
{
.l3proto = PF_INET6,
.l4proto = IPPROTO_ICMPV6,
@@ -327,5 +297,3 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 =
.ctl_table = icmpv6_sysctl_table,
#endif
};
-
-EXPORT_SYMBOL(nf_conntrack_l4proto_icmpv6);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 347ab7608231..25442a8c1ba8 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -44,12 +44,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
#define NF_CT_FRAG6_HIGH_THRESH 262144 /* == 256*1024 */
#define NF_CT_FRAG6_LOW_THRESH 196608 /* == 192*1024 */
#define NF_CT_FRAG6_TIMEOUT IPV6_FRAG_TIMEOUT
@@ -343,7 +337,7 @@ nf_ct_frag6_create(unsigned int hash, __be32 id, struct in6_addr *src, str
struct nf_ct_frag6_queue *fq;
if ((fq = frag_alloc_queue()) == NULL) {
- DEBUGP("Can't alloc new queue\n");
+ pr_debug("Can't alloc new queue\n");
goto oom;
}
@@ -393,7 +387,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
int offset, end;
if (fq->last_in & COMPLETE) {
- DEBUGP("Allready completed\n");
+ pr_debug("Allready completed\n");
goto err;
}
@@ -402,7 +396,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1)));
if ((unsigned int)end > IPV6_MAXPLEN) {
- DEBUGP("offset is too large.\n");
+ pr_debug("offset is too large.\n");
return -1;
}
@@ -420,7 +414,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
*/
if (end < fq->len ||
((fq->last_in & LAST_IN) && end != fq->len)) {
- DEBUGP("already received last fragment\n");
+ pr_debug("already received last fragment\n");
goto err;
}
fq->last_in |= LAST_IN;
@@ -433,13 +427,13 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
/* RFC2460 says always send parameter problem in
* this case. -DaveM
*/
- DEBUGP("the end of this fragment is not rounded to 8 bytes.\n");
+ pr_debug("end of fragment not rounded to 8 bytes.\n");
return -1;
}
if (end > fq->len) {
/* Some bits beyond end -> corruption. */
if (fq->last_in & LAST_IN) {
- DEBUGP("last packet already reached.\n");
+ pr_debug("last packet already reached.\n");
goto err;
}
fq->len = end;
@@ -451,11 +445,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
/* Point into the IP datagram 'data' part. */
if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) {
- DEBUGP("queue: message is too short.\n");
+ pr_debug("queue: message is too short.\n");
goto err;
}
if (pskb_trim_rcsum(skb, end - offset)) {
- DEBUGP("Can't trim\n");
+ pr_debug("Can't trim\n");
goto err;
}
@@ -480,11 +474,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
if (i > 0) {
offset += i;
if (end <= offset) {
- DEBUGP("overlap\n");
+ pr_debug("overlap\n");
goto err;
}
if (!pskb_pull(skb, i)) {
- DEBUGP("Can't pull\n");
+ pr_debug("Can't pull\n");
goto err;
}
if (skb->ip_summed != CHECKSUM_UNNECESSARY)
@@ -503,7 +497,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb,
/* Eat head of the next overlapped fragment
* and leave the loop. The next ones cannot overlap.
*/
- DEBUGP("Eat head of the overlapped parts.: %d", i);
+ pr_debug("Eat head of the overlapped parts.: %d", i);
if (!pskb_pull(next, i))
goto err;
@@ -586,13 +580,13 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
sizeof(struct ipv6hdr) + fq->len -
sizeof(struct frag_hdr));
if (payload_len > IPV6_MAXPLEN) {
- DEBUGP("payload len is too large.\n");
+ pr_debug("payload len is too large.\n");
goto out_oversize;
}
/* Head of list must not be cloned. */
if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) {
- DEBUGP("skb is cloned but can't expand head");
+ pr_debug("skb is cloned but can't expand head");
goto out_oom;
}
@@ -604,7 +598,7 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev)
int i, plen = 0;
if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) {
- DEBUGP("Can't alloc skb\n");
+ pr_debug("Can't alloc skb\n");
goto out_oom;
}
clone->next = head->next;
@@ -719,11 +713,11 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
return -1;
}
if (len < (int)sizeof(struct ipv6_opt_hdr)) {
- DEBUGP("too short\n");
+ pr_debug("too short\n");
return -1;
}
if (nexthdr == NEXTHDR_NONE) {
- DEBUGP("next header is none\n");
+ pr_debug("next header is none\n");
return -1;
}
if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
@@ -764,7 +758,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
/* Jumbo payload inhibits frag. header */
if (ipv6_hdr(skb)->payload_len == 0) {
- DEBUGP("payload len = 0\n");
+ pr_debug("payload len = 0\n");
return skb;
}
@@ -773,14 +767,14 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
clone = skb_clone(skb, GFP_ATOMIC);
if (clone == NULL) {
- DEBUGP("Can't clone skb\n");
+ pr_debug("Can't clone skb\n");
return skb;
}
NFCT_FRAG6_CB(clone)->orig = skb;
if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) {
- DEBUGP("message is too short.\n");
+ pr_debug("message is too short.\n");
goto ret_orig;
}
@@ -789,7 +783,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
fhdr = (struct frag_hdr *)skb_transport_header(clone);
if (!(fhdr->frag_off & htons(0xFFF9))) {
- DEBUGP("Invalid fragment offset\n");
+ pr_debug("Invalid fragment offset\n");
/* It is not a fragmented frame */
goto ret_orig;
}
@@ -799,7 +793,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);
if (fq == NULL) {
- DEBUGP("Can't find and can't create new queue\n");
+ pr_debug("Can't find and can't create new queue\n");
goto ret_orig;
}
@@ -807,7 +801,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {
spin_unlock(&fq->lock);
- DEBUGP("Can't insert skb to queue\n");
+ pr_debug("Can't insert skb to queue\n");
fq_put(fq, NULL);
goto ret_orig;
}
@@ -815,7 +809,7 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb)
if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) {
ret_skb = nf_ct_frag6_reasm(fq, dev);
if (ret_skb == NULL)
- DEBUGP("Can't reassemble fragmented packets\n");
+ pr_debug("Can't reassemble fragmented packets\n");
}
spin_unlock(&fq->lock);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index a58459a76684..e27383d855de 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -49,7 +49,7 @@
#include <net/udp.h>
#include <net/inet_common.h>
#include <net/tcp_states.h>
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
#include <net/mip6.h>
#endif
@@ -137,6 +137,28 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
return 0;
}
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+static int (*mh_filter)(struct sock *sock, struct sk_buff *skb);
+
+int rawv6_mh_filter_register(int (*filter)(struct sock *sock,
+ struct sk_buff *skb))
+{
+ rcu_assign_pointer(mh_filter, filter);
+ return 0;
+}
+EXPORT_SYMBOL(rawv6_mh_filter_register);
+
+int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock,
+ struct sk_buff *skb))
+{
+ rcu_assign_pointer(mh_filter, NULL);
+ synchronize_rcu();
+ return 0;
+}
+EXPORT_SYMBOL(rawv6_mh_filter_unregister);
+
+#endif
+
/*
* demultiplex raw sockets.
* (should consider queueing the skb in the sock receive_queue
@@ -178,16 +200,22 @@ int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
case IPPROTO_ICMPV6:
filtered = icmpv6_filter(sk, skb);
break;
-#ifdef CONFIG_IPV6_MIP6
+
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPPROTO_MH:
+ {
/* XXX: To validate MH only once for each packet,
* this is placed here. It should be after checking
* xfrm policy, however it doesn't. The checking xfrm
* policy is placed in rawv6_rcv() because it is
* required for each socket.
*/
- filtered = mip6_mh_filter(sk, skb);
+ int (*filter)(struct sock *sock, struct sk_buff *skb);
+
+ filter = rcu_dereference(mh_filter);
+ filtered = filter ? filter(sk, skb) : 0;
break;
+ }
#endif
default:
filtered = 0;
@@ -611,9 +639,7 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
struct iovec *iov;
u8 __user *type = NULL;
u8 __user *code = NULL;
-#ifdef CONFIG_IPV6_MIP6
u8 len = 0;
-#endif
int probed = 0;
int i;
@@ -646,7 +672,6 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
probed = 1;
}
break;
-#ifdef CONFIG_IPV6_MIP6
case IPPROTO_MH:
if (iov->iov_base && iov->iov_len < 1)
break;
@@ -660,7 +685,6 @@ static int rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg)
len += iov->iov_len;
break;
-#endif
default:
probed = 1;
break;
@@ -1256,7 +1280,7 @@ static int raw6_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations raw6_seq_ops = {
+static const struct seq_operations raw6_seq_ops = {
.start = raw6_seq_start,
.next = raw6_seq_next,
.stop = raw6_seq_stop,
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index fe8d9837f9f8..919de682b331 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2555,7 +2555,7 @@ void __init ip6_route_init(void)
#endif
ip6_dst_ops.kmem_cachep =
kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
- SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep;
fib6_init();
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 1efa95a99f45..eb20bb690abd 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -532,7 +532,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
*/
max_headroom = LL_RESERVED_SPACE(tdev)+sizeof(struct iphdr);
- if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+ if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
+ (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
ip_rt_put(rt);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 193d9d60bb7a..d67fb1ef751e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -484,17 +484,6 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
if (dst == NULL) {
opt = np->opt;
- if (opt == NULL &&
- np->rxopt.bits.osrcrt == 2 &&
- treq->pktopts) {
- struct sk_buff *pktopts = treq->pktopts;
- struct inet6_skb_parm *rxopt = IP6CB(pktopts);
- if (rxopt->srcrt)
- opt = ipv6_invert_rthdr(sk,
- (struct ipv6_rt_hdr *)(skb_network_header(pktopts) +
- rxopt->srcrt));
- }
-
if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
@@ -1391,15 +1380,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
if (sk_acceptq_is_full(sk))
goto out_overflow;
- if (np->rxopt.bits.osrcrt == 2 &&
- opt == NULL && treq->pktopts) {
- struct inet6_skb_parm *rxopt = IP6CB(treq->pktopts);
- if (rxopt->srcrt)
- opt = ipv6_invert_rthdr(sk,
- (struct ipv6_rt_hdr *)(skb_network_header(treq->pktopts) +
- rxopt->srcrt));
- }
-
if (dst == NULL) {
struct in6_addr *final_p = NULL, final;
struct flowi fl;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 1faa2ea80afc..3ec0c4770ee3 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -18,7 +18,7 @@
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
#include <net/mip6.h>
#endif
@@ -318,7 +318,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl)
fl->proto = nexthdr;
return;
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
case IPPROTO_MH:
if (pskb_may_pull(skb, nh + offset + 3 - skb->data)) {
struct ip6_mh *mh;
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index baa461b9f74e..cdadb4847469 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -65,7 +65,7 @@ __xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n)
goto end;
/* Rule 2: select MIPv6 RO or inbound trigger */
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
for (i = 0; i < n; i++) {
if (src[i] &&
(src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION ||
@@ -130,7 +130,7 @@ __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
goto end;
/* Rule 2: select MIPv6 RO or inbound trigger */
-#ifdef CONFIG_IPV6_MIP6
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
for (i = 0; i < n; i++) {
if (src[i] &&
(src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION ||
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 5502cc948dfb..30f3236c402a 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -84,7 +84,7 @@ static int xfrm6_tunnel_spi_init(void)
xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
sizeof(struct xfrm6_tunnel_spi),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!xfrm6_tunnel_spi_kmem)
return -ENOMEM;
@@ -379,3 +379,4 @@ static void __exit xfrm6_tunnel_fini(void)
module_init(xfrm6_tunnel_init);
module_exit(xfrm6_tunnel_fini);
MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_IPV6);
diff --git a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c
index db32ac8e79bd..4226e71ae1e3 100644
--- a/net/ipx/ipx_proc.c
+++ b/net/ipx/ipx_proc.c
@@ -286,21 +286,21 @@ out:
return 0;
}
-static struct seq_operations ipx_seq_interface_ops = {
+static const struct seq_operations ipx_seq_interface_ops = {
.start = ipx_seq_interface_start,
.next = ipx_seq_interface_next,
.stop = ipx_seq_interface_stop,
.show = ipx_seq_interface_show,
};
-static struct seq_operations ipx_seq_route_ops = {
+static const struct seq_operations ipx_seq_route_ops = {
.start = ipx_seq_route_start,
.next = ipx_seq_route_next,
.stop = ipx_seq_route_stop,
.show = ipx_seq_route_show,
};
-static struct seq_operations ipx_seq_socket_ops = {
+static const struct seq_operations ipx_seq_socket_ops = {
.start = ipx_seq_socket_start,
.next = ipx_seq_socket_next,
.stop = ipx_seq_interface_stop,
diff --git a/net/irda/Makefile b/net/irda/Makefile
index d1366c2a39cb..187f6c563a4b 100644
--- a/net/irda/Makefile
+++ b/net/irda/Makefile
@@ -10,6 +10,6 @@ obj-$(CONFIG_IRCOMM) += ircomm/
irda-y := iriap.o iriap_event.o irlmp.o irlmp_event.o irlmp_frame.o \
irlap.o irlap_event.o irlap_frame.o timer.o qos.o irqueue.o \
irttp.o irda_device.o irias_object.o wrapper.o af_irda.o \
- discovery.o parameters.o irmod.o
+ discovery.o parameters.o irnetlink.o irmod.o
irda-$(CONFIG_PROC_FS) += irproc.o
irda-$(CONFIG_SYSCTL) += irsysctl.o
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index dcd7e325b283..4c670cf6aefa 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -2567,7 +2567,7 @@ int __init irsock_init(void)
* Remove IrDA protocol
*
*/
-void __exit irsock_cleanup(void)
+void irsock_cleanup(void)
{
sock_unregister(PF_IRDA);
proto_unregister(&irda_proto);
diff --git a/net/irda/discovery.c b/net/irda/discovery.c
index f09734128674..af0cea721d2a 100644
--- a/net/irda/discovery.c
+++ b/net/irda/discovery.c
@@ -395,7 +395,7 @@ static int discovery_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations discovery_seq_ops = {
+static const struct seq_operations discovery_seq_ops = {
.start = discovery_seq_start,
.next = discovery_seq_next,
.stop = discovery_seq_stop,
diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
index 4749f8f55391..2d63fa8e1556 100644
--- a/net/irda/ircomm/ircomm_core.c
+++ b/net/irda/ircomm/ircomm_core.c
@@ -562,7 +562,7 @@ static int ircomm_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ircomm_seq_ops = {
+static const struct seq_operations ircomm_seq_ops = {
.start = ircomm_seq_start,
.next = ircomm_seq_next,
.stop = ircomm_seq_stop,
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index 7b5def1ea633..435b563d29a6 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -95,14 +95,14 @@ int __init irda_device_init( void)
return 0;
}
-static void __exit leftover_dongle(void *arg)
+static void leftover_dongle(void *arg)
{
struct dongle_reg *reg = arg;
IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
reg->type);
}
-void __exit irda_device_cleanup(void)
+void irda_device_cleanup(void)
{
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index 915d9384f36a..ee3889fa49ab 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -153,7 +153,7 @@ int __init iriap_init(void)
* Initializes the IrIAP layer, called by the module cleanup code in
* irmod.c
*/
-void __exit iriap_cleanup(void)
+void iriap_cleanup(void)
{
irlmp_unregister_service(service_handle);
@@ -1066,7 +1066,7 @@ static int irias_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations irias_seq_ops = {
+static const struct seq_operations irias_seq_ops = {
.start = irias_seq_start,
.next = irias_seq_next,
.stop = irias_seq_stop,
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index 4adaae242b9e..cf302457097b 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -36,39 +36,6 @@ hashbin_t *irias_objects;
*/
struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}};
-/*
- * Function strndup (str, max)
- *
- * My own kernel version of strndup!
- *
- * Faster, check boundary... Jean II
- */
-static char *strndup(char *str, size_t max)
-{
- char *new_str;
- int len;
-
- /* Check string */
- if (str == NULL)
- return NULL;
- /* Check length, truncate */
- len = strlen(str);
- if(len > max)
- len = max;
-
- /* Allocate new string */
- new_str = kmalloc(len + 1, GFP_ATOMIC);
- if (new_str == NULL) {
- IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
- return NULL;
- }
-
- /* Copy and truncate */
- memcpy(new_str, str, len);
- new_str[len] = '\0';
-
- return new_str;
-}
/*
* Function ias_new_object (name, id)
@@ -90,7 +57,7 @@ struct ias_object *irias_new_object( char *name, int id)
}
obj->magic = IAS_OBJECT_MAGIC;
- obj->name = strndup(name, IAS_MAX_CLASSNAME);
+ obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC);
if (!obj->name) {
IRDA_WARNING("%s(), Unable to allocate name!\n",
__FUNCTION__);
@@ -360,7 +327,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value,
}
attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
/* Insert value */
attrib->value = irias_new_integer_value(value);
@@ -404,7 +371,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets,
}
attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
attrib->value = irias_new_octseq_value( octets, len);
if (!attrib->name || !attrib->value) {
@@ -446,7 +413,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value,
}
attrib->magic = IAS_ATTRIB_MAGIC;
- attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
+ attrib->name = kstrndup(name, IAS_MAX_ATTRIBNAME, GFP_ATOMIC);
attrib->value = irias_new_string_value(value);
if (!attrib->name || !attrib->value) {
@@ -506,7 +473,7 @@ struct ias_value *irias_new_string_value(char *string)
value->type = IAS_STRING;
value->charset = CS_ASCII;
- value->t.string = strndup(string, IAS_MAX_STRING);
+ value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC);
if (!value->t.string) {
IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__);
kfree(value);
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index ed69773b0f8e..f5778ef3ccc7 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -1217,7 +1217,7 @@ static int irlan_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations irlan_seq_ops = {
+static const struct seq_operations irlan_seq_ops = {
.start = irlan_seq_start,
.next = irlan_seq_next,
.stop = irlan_seq_stop,
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index d93ebd11431e..3d76aafdb2e5 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -95,7 +95,7 @@ int __init irlap_init(void)
return 0;
}
-void __exit irlap_cleanup(void)
+void irlap_cleanup(void)
{
IRDA_ASSERT(irlap != NULL, return;);
@@ -1210,7 +1210,7 @@ static int irlap_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations irlap_seq_ops = {
+static const struct seq_operations irlap_seq_ops = {
.start = irlap_seq_start,
.next = irlap_seq_next,
.stop = irlap_seq_stop,
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 3013c49ab975..25a3444a9234 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -101,6 +101,13 @@ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
irlap_insert_info(self, skb);
+ if (unlikely(self->mode & IRDA_MODE_MONITOR)) {
+ IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __FUNCTION__,
+ self->netdev->name);
+ dev_kfree_skb(skb);
+ return;
+ }
+
dev_queue_xmit(skb);
}
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index 9df0461b6d18..7efa930ed684 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -116,7 +116,7 @@ int __init irlmp_init(void)
* Remove IrLMP layer
*
*/
-void __exit irlmp_cleanup(void)
+void irlmp_cleanup(void)
{
/* Check for main structure */
IRDA_ASSERT(irlmp != NULL, return;);
@@ -1994,7 +1994,7 @@ static int irlmp_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations irlmp_seq_ops = {
+static const struct seq_operations irlmp_seq_ops = {
.start = irlmp_seq_start,
.next = irlmp_seq_next,
.stop = irlmp_seq_stop,
diff --git a/net/irda/irmod.c b/net/irda/irmod.c
index c7fad2c5b9f3..1900937b3328 100644
--- a/net/irda/irmod.c
+++ b/net/irda/irmod.c
@@ -88,16 +88,23 @@ EXPORT_SYMBOL(irda_notify_init);
*/
static int __init irda_init(void)
{
+ int ret = 0;
+
IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
/* Lower layer of the stack */
irlmp_init();
irlap_init();
+ /* Driver/dongle support */
+ irda_device_init();
+
/* Higher layers of the stack */
iriap_init();
irttp_init();
- irsock_init();
+ ret = irsock_init();
+ if (ret < 0)
+ goto out_err_1;
/* Add IrDA packet type (Start receiving packets) */
dev_add_pack(&irda_packet_type);
@@ -107,13 +114,44 @@ static int __init irda_init(void)
irda_proc_register();
#endif
#ifdef CONFIG_SYSCTL
- irda_sysctl_register();
+ ret = irda_sysctl_register();
+ if (ret < 0)
+ goto out_err_2;
#endif
- /* Driver/dongle support */
- irda_device_init();
+ ret = irda_nl_register();
+ if (ret < 0)
+ goto out_err_3;
return 0;
+
+ out_err_3:
+#ifdef CONFIG_SYSCTL
+ irda_sysctl_unregister();
+#endif
+ out_err_2:
+#ifdef CONFIG_PROC_FS
+ irda_proc_unregister();
+#endif
+
+ /* Remove IrDA packet type (stop receiving packets) */
+ dev_remove_pack(&irda_packet_type);
+
+ /* Remove higher layers */
+ irsock_cleanup();
+ out_err_1:
+ irttp_cleanup();
+ iriap_cleanup();
+
+ /* Remove lower layers */
+ irda_device_cleanup();
+ irlap_cleanup(); /* Must be done before irlmp_cleanup()! DB */
+
+ /* Remove middle layer */
+ irlmp_cleanup();
+
+
+ return ret;
}
/*
@@ -125,6 +163,8 @@ static int __init irda_init(void)
static void __exit irda_cleanup(void)
{
/* Remove External APIs */
+ irda_nl_unregister();
+
#ifdef CONFIG_SYSCTL
irda_sysctl_unregister();
#endif
diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c
new file mode 100644
index 000000000000..694ea4d92fa8
--- /dev/null
+++ b/net/irda/irnetlink.c
@@ -0,0 +1,170 @@
+/*
+ * IrDA netlink layer, for stack configuration.
+ *
+ * Copyright (c) 2007 Samuel Ortiz <samuel@sortiz.org>
+ *
+ * Partly based on the 802.11 nelink implementation
+ * (see net/wireless/nl80211.c) which is:
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ *
+ * 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/socket.h>
+#include <linux/irda.h>
+#include <net/sock.h>
+#include <net/irda/irda.h>
+#include <net/irda/irlap.h>
+#include <net/genetlink.h>
+
+
+
+static struct genl_family irda_nl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = IRDA_NL_NAME,
+ .hdrsize = 0,
+ .version = IRDA_NL_VERSION,
+ .maxattr = IRDA_NL_CMD_MAX,
+};
+
+static struct net_device * ifname_to_netdev(struct genl_info *info)
+{
+ char * ifname;
+
+ if (!info->attrs[IRDA_NL_ATTR_IFNAME])
+ return NULL;
+
+ ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]);
+
+ IRDA_DEBUG(5, "%s(): Looking for %s\n", __FUNCTION__, ifname);
+
+ return dev_get_by_name(ifname);
+}
+
+static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info)
+{
+ struct net_device * dev;
+ struct irlap_cb * irlap;
+ u32 mode;
+
+ if (!info->attrs[IRDA_NL_ATTR_MODE])
+ return -EINVAL;
+
+ mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]);
+
+ IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __FUNCTION__, mode);
+
+ dev = ifname_to_netdev(info);
+ if (!dev)
+ return -ENODEV;
+
+ irlap = (struct irlap_cb *)dev->atalk_ptr;
+ if (!irlap) {
+ dev_put(dev);
+ return -ENODEV;
+ }
+
+ irlap->mode = mode;
+
+ dev_put(dev);
+
+ return 0;
+}
+
+static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info)
+{
+ struct net_device * dev;
+ struct irlap_cb * irlap;
+ struct sk_buff *msg;
+ void *hdr;
+ int ret = -ENOBUFS;
+
+ dev = ifname_to_netdev(info);
+ if (!dev)
+ return -ENODEV;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg) {
+ dev_put(dev);
+ return -ENOMEM;
+ }
+
+ irlap = (struct irlap_cb *)dev->atalk_ptr;
+ if (!irlap) {
+ ret = -ENODEV;
+ goto err_out;
+ }
+
+ hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
+ &irda_nl_family, 0, IRDA_NL_CMD_GET_MODE);
+ if (IS_ERR(hdr)) {
+ ret = PTR_ERR(hdr);
+ goto err_out;
+ }
+
+ if(nla_put_string(msg, IRDA_NL_ATTR_IFNAME,
+ dev->name));
+ goto err_out;
+
+ if(nla_put_u32(msg, IRDA_NL_ATTR_MODE, irlap->mode))
+ goto err_out;
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_unicast(msg, info->snd_pid);
+
+ err_out:
+ nlmsg_free(msg);
+ dev_put(dev);
+
+ return ret;
+}
+
+static struct nla_policy irda_nl_policy[IRDA_NL_ATTR_MAX + 1] = {
+ [IRDA_NL_ATTR_IFNAME] = { .type = NLA_NUL_STRING,
+ .len = IFNAMSIZ-1 },
+ [IRDA_NL_ATTR_MODE] = { .type = NLA_U32 },
+};
+
+static struct genl_ops irda_nl_ops[] = {
+ {
+ .cmd = IRDA_NL_CMD_SET_MODE,
+ .doit = irda_nl_set_mode,
+ .policy = irda_nl_policy,
+ .flags = GENL_ADMIN_PERM,
+ },
+ {
+ .cmd = IRDA_NL_CMD_GET_MODE,
+ .doit = irda_nl_get_mode,
+ .policy = irda_nl_policy,
+ /* can be retrieved by unprivileged users */
+ },
+
+};
+
+int irda_nl_register(void)
+{
+ int err, i;
+
+ err = genl_register_family(&irda_nl_family);
+ if (err)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(irda_nl_ops); i++) {
+ err = genl_register_ops(&irda_nl_family, &irda_nl_ops[i]);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+ err_out:
+ genl_unregister_family(&irda_nl_family);
+ return err;
+}
+
+void irda_nl_unregister(void)
+{
+ genl_unregister_family(&irda_nl_family);
+}
diff --git a/net/irda/irproc.c b/net/irda/irproc.c
index d6f9aba5b9dc..181cb51b48a8 100644
--- a/net/irda/irproc.c
+++ b/net/irda/irproc.c
@@ -84,7 +84,7 @@ void __init irda_proc_register(void)
* Unregister irda entry in /proc file system
*
*/
-void __exit irda_proc_unregister(void)
+void irda_proc_unregister(void)
{
int i;
diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c
index 2e968e7d8fea..957e04feb0f7 100644
--- a/net/irda/irsysctl.c
+++ b/net/irda/irsysctl.c
@@ -287,7 +287,7 @@ int __init irda_sysctl_register(void)
* Unregister our sysctl interface
*
*/
-void __exit irda_sysctl_unregister(void)
+void irda_sysctl_unregister(void)
{
unregister_sysctl_table(irda_table_header);
}
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 7069e4a58257..3d7ab03fb131 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -109,7 +109,7 @@ int __init irttp_init(void)
* Called by module destruction/cleanup code
*
*/
-void __exit irttp_cleanup(void)
+void irttp_cleanup(void)
{
/* Check for main structure */
IRDA_ASSERT(irttp->magic == TTP_MAGIC, return;);
@@ -369,6 +369,20 @@ static int irttp_param_max_sdu_size(void *instance, irda_param_t *param,
/* Everything is happily mixed up. Waiting for next clean up - Jean II */
/*
+ * Initialization, that has to be done on new tsap
+ * instance allocation and on duplication
+ */
+static void irttp_init_tsap(struct tsap_cb *tsap)
+{
+ spin_lock_init(&tsap->lock);
+ init_timer(&tsap->todo_timer);
+
+ skb_queue_head_init(&tsap->rx_queue);
+ skb_queue_head_init(&tsap->tx_queue);
+ skb_queue_head_init(&tsap->rx_fragments);
+}
+
+/*
* Function irttp_open_tsap (stsap, notify)
*
* Create TSAP connection endpoint,
@@ -395,10 +409,11 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __FUNCTION__);
return NULL;
}
- spin_lock_init(&self->lock);
+
+ /* Initialize internal objects */
+ irttp_init_tsap(self);
/* Initialise todo timer */
- init_timer(&self->todo_timer);
self->todo_timer.data = (unsigned long) self;
self->todo_timer.function = &irttp_todo_expired;
@@ -418,9 +433,6 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify)
self->magic = TTP_TSAP_MAGIC;
self->connected = FALSE;
- skb_queue_head_init(&self->rx_queue);
- skb_queue_head_init(&self->tx_queue);
- skb_queue_head_init(&self->rx_fragments);
/*
* Create LSAP at IrLMP layer
*/
@@ -1455,12 +1467,9 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
/* Not everything should be copied */
new->notify.instance = instance;
- spin_lock_init(&new->lock);
- init_timer(&new->todo_timer);
- skb_queue_head_init(&new->rx_queue);
- skb_queue_head_init(&new->tx_queue);
- skb_queue_head_init(&new->rx_fragments);
+ /* Initialize internal objects */
+ irttp_init_tsap(new);
/* This is locked */
hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (long) new, NULL);
@@ -1866,7 +1875,7 @@ static int irttp_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations irttp_seq_ops = {
+static const struct seq_operations irttp_seq_ops = {
.start = irttp_seq_start,
.next = irttp_seq_next,
.stop = irttp_seq_stop,
diff --git a/net/iucv/Kconfig b/net/iucv/Kconfig
index f8fcc3d10327..16ce9cd4f39e 100644
--- a/net/iucv/Kconfig
+++ b/net/iucv/Kconfig
@@ -1,13 +1,13 @@
config IUCV
- tristate "IUCV support (VM only)"
+ tristate "IUCV support (S390 - z/VM only)"
depends on S390
help
- Select this option if you want to use inter-user communication under
- VM or VIF sockets. If you run on z/VM, say "Y" to enable a fast
+ Select this option if you want to use inter-user communication
+ under VM or VIF. If you run on z/VM, say "Y" to enable a fast
communication link between VM guests.
config AFIUCV
- tristate "AF_IUCV support (VM only)"
+ tristate "AF_IUCV support (S390 - z/VM only)"
depends on IUCV
help
Select this option if you want to use inter-user communication under
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index d9e9ddb8eac5..53ae14c35f70 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -219,6 +219,7 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio)
sock_init_data(sock, sk);
INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
+ spin_lock_init(&iucv_sk(sk)->accept_q_lock);
skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q);
iucv_sk(sk)->send_tag = 0;
@@ -274,15 +275,25 @@ void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *sk)
void iucv_accept_enqueue(struct sock *parent, struct sock *sk)
{
+ unsigned long flags;
+ struct iucv_sock *par = iucv_sk(parent);
+
sock_hold(sk);
- list_add_tail(&iucv_sk(sk)->accept_q, &iucv_sk(parent)->accept_q);
+ spin_lock_irqsave(&par->accept_q_lock, flags);
+ list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q);
+ spin_unlock_irqrestore(&par->accept_q_lock, flags);
iucv_sk(sk)->parent = parent;
parent->sk_ack_backlog++;
}
void iucv_accept_unlink(struct sock *sk)
{
+ unsigned long flags;
+ struct iucv_sock *par = iucv_sk(iucv_sk(sk)->parent);
+
+ spin_lock_irqsave(&par->accept_q_lock, flags);
list_del_init(&iucv_sk(sk)->accept_q);
+ spin_unlock_irqrestore(&par->accept_q_lock, flags);
iucv_sk(sk)->parent->sk_ack_backlog--;
iucv_sk(sk)->parent = NULL;
sock_put(sk);
@@ -298,8 +309,8 @@ struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock)
lock_sock(sk);
if (sk->sk_state == IUCV_CLOSED) {
- release_sock(sk);
iucv_accept_unlink(sk);
+ release_sock(sk);
continue;
}
@@ -879,6 +890,7 @@ static int iucv_callback_connreq(struct iucv_path *path,
/* Find out if this path belongs to af_iucv. */
read_lock(&iucv_sk_list.lock);
iucv = NULL;
+ sk = NULL;
sk_for_each(sk, node, &iucv_sk_list.head)
if (sk->sk_state == IUCV_LISTEN &&
!memcmp(&iucv_sk(sk)->src_name, src_name, 8)) {
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index b7333061016d..ad5150b8dfa9 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1494,7 +1494,10 @@ static void iucv_tasklet_fn(unsigned long ignored)
struct iucv_irq_list *p, *n;
/* Serialize tasklet, iucv_path_sever and iucv_path_connect. */
- spin_lock(&iucv_table_lock);
+ if (!spin_trylock(&iucv_table_lock)) {
+ tasklet_schedule(&iucv_tasklet);
+ return;
+ }
iucv_active_cpu = smp_processor_id();
spin_lock_irq(&iucv_queue_lock);
diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c
index 3ab9d9f8b17f..49be6c902c83 100644
--- a/net/llc/llc_proc.c
+++ b/net/llc/llc_proc.c
@@ -184,14 +184,14 @@ out:
return 0;
}
-static struct seq_operations llc_seq_socket_ops = {
+static const struct seq_operations llc_seq_socket_ops = {
.start = llc_seq_start,
.next = llc_seq_next,
.stop = llc_seq_stop,
.show = llc_seq_socket_show,
};
-static struct seq_operations llc_seq_core_ops = {
+static const struct seq_operations llc_seq_core_ops = {
.start = llc_seq_start,
.next = llc_seq_next,
.stop = llc_seq_stop,
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index e9738dad2d7c..a9c2d0787d4a 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -13,6 +13,7 @@ mac80211-objs := \
ieee80211_iface.o \
ieee80211_rate.o \
michael.o \
+ regdomain.o \
tkip.o \
aes_ccm.o \
wme.o \
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 9e3964638bad..799a9208c4b4 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -118,7 +118,7 @@ static ssize_t ieee80211_if_fmt_flags(
sdata->u.sta.authenticated ? "AUTH\n" : "",
sdata->u.sta.associated ? "ASSOC\n" : "",
sdata->u.sta.probereq_poll ? "PROBEREQ POLL\n" : "",
- sdata->u.sta.use_protection ? "CTS prot\n" : "");
+ sdata->use_protection ? "CTS prot\n" : "");
}
__IEEE80211_IF_FILE(flags);
@@ -397,6 +397,8 @@ static int netdev_notify(struct notifier_block * nb,
void *ndev)
{
struct net_device *dev = ndev;
+ struct dentry *dir;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
char buf[10+IFNAMSIZ];
if (state != NETDEV_CHANGENAME)
@@ -408,10 +410,11 @@ static int netdev_notify(struct notifier_block * nb,
if (dev->ieee80211_ptr->wiphy->privid != mac80211_wiphy_privid)
return 0;
- /* TODO
sprintf(buf, "netdev:%s", dev->name);
- debugfs_rename(IEEE80211_DEV_TO_SUB_IF(dev)->debugfsdir, buf);
- */
+ dir = sdata->debugfsdir;
+ if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf))
+ printk(KERN_ERR "mac80211: debugfs: failed to rename debugfs "
+ "dir to %s\n", buf);
return 0;
}
diff --git a/net/mac80211/hostapd_ioctl.h b/net/mac80211/hostapd_ioctl.h
index 34fa128e9872..52da513f060a 100644
--- a/net/mac80211/hostapd_ioctl.h
+++ b/net/mac80211/hostapd_ioctl.h
@@ -26,24 +26,16 @@
* mess shall be deleted completely. */
enum {
PRISM2_PARAM_IEEE_802_1X = 23,
- PRISM2_PARAM_ANTSEL_TX = 24,
- PRISM2_PARAM_ANTSEL_RX = 25,
/* Instant802 additions */
PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES = 1001,
- PRISM2_PARAM_DROP_UNENCRYPTED = 1002,
PRISM2_PARAM_PREAMBLE = 1003,
PRISM2_PARAM_SHORT_SLOT_TIME = 1006,
PRISM2_PARAM_NEXT_MODE = 1008,
- PRISM2_PARAM_CLEAR_KEYS = 1009,
PRISM2_PARAM_RADIO_ENABLED = 1010,
PRISM2_PARAM_ANTENNA_MODE = 1013,
PRISM2_PARAM_STAT_TIME = 1016,
PRISM2_PARAM_STA_ANTENNA_SEL = 1017,
- PRISM2_PARAM_FORCE_UNICAST_RATE = 1018,
- PRISM2_PARAM_RATE_CTRL_NUM_UP = 1019,
- PRISM2_PARAM_RATE_CTRL_NUM_DOWN = 1020,
- PRISM2_PARAM_MAX_RATECTRL_RATE = 1021,
PRISM2_PARAM_TX_POWER_REDUCTION = 1022,
PRISM2_PARAM_KEY_TX_RX_THRESHOLD = 1024,
PRISM2_PARAM_DEFAULT_WEP_ONLY = 1026,
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 4e84f24fd439..c944b17d0fc0 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -24,6 +24,7 @@
#include <linux/compiler.h>
#include <linux/bitmap.h>
#include <net/cfg80211.h>
+#include <asm/unaligned.h>
#include "ieee80211_common.h"
#include "ieee80211_i.h"
@@ -56,6 +57,17 @@ static const unsigned char eapol_header[] =
{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x88, 0x8e };
+/*
+ * For seeing transmitted packets on monitor interfaces
+ * we have a radiotap header too.
+ */
+struct ieee80211_tx_status_rtap_hdr {
+ struct ieee80211_radiotap_header hdr;
+ __le16 tx_flags;
+ u8 data_retries;
+} __attribute__ ((packed));
+
+
static inline void ieee80211_include_sequence(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr)
{
@@ -430,7 +442,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx)
if (!tx->u.tx.rate)
return TXRX_DROP;
if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
- tx->local->cts_protect_erp_frames && tx->fragmented &&
+ tx->sdata->use_protection && tx->fragmented &&
extra.nonerp) {
tx->u.tx.last_frag_rate = tx->u.tx.rate;
tx->u.tx.probe_last_frag = extra.probe ? 1 : 0;
@@ -528,7 +540,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
/* reserve enough extra head and tail room for possible
* encryption */
frag = frags[i] =
- dev_alloc_skb(tx->local->hw.extra_tx_headroom +
+ dev_alloc_skb(tx->local->tx_headroom +
frag_threshold +
IEEE80211_ENCRYPT_HEADROOM +
IEEE80211_ENCRYPT_TAILROOM);
@@ -537,8 +549,8 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx)
/* Make sure that all fragments use the same priority so
* that they end up using the same TX queue */
frag->priority = first->priority;
- skb_reserve(frag, tx->local->hw.extra_tx_headroom +
- IEEE80211_ENCRYPT_HEADROOM);
+ skb_reserve(frag, tx->local->tx_headroom +
+ IEEE80211_ENCRYPT_HEADROOM);
fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen);
memcpy(fhdr, first->data, hdrlen);
if (i == num_fragm - 2)
@@ -856,8 +868,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx)
* for the frame. */
if (mode->mode == MODE_IEEE80211G &&
(tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
- tx->u.tx.unicast &&
- tx->local->cts_protect_erp_frames &&
+ tx->u.tx.unicast && tx->sdata->use_protection &&
!(control->flags & IEEE80211_TXCTL_USE_RTS_CTS))
control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT;
@@ -1118,7 +1129,138 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
}
-static void inline
+/*
+ * deal with packet injection down monitor interface
+ * with Radiotap Header -- only called for monitor mode interface
+ */
+
+static ieee80211_txrx_result
+__ieee80211_parse_tx_radiotap(
+ struct ieee80211_txrx_data *tx,
+ struct sk_buff *skb, struct ieee80211_tx_control *control)
+{
+ /*
+ * this is the moment to interpret and discard the radiotap header that
+ * must be at the start of the packet injected in Monitor mode
+ *
+ * Need to take some care with endian-ness since radiotap
+ * args are little-endian
+ */
+
+ struct ieee80211_radiotap_iterator iterator;
+ struct ieee80211_radiotap_header *rthdr =
+ (struct ieee80211_radiotap_header *) skb->data;
+ struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode;
+ int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len);
+
+ /*
+ * default control situation for all injected packets
+ * FIXME: this does not suit all usage cases, expand to allow control
+ */
+
+ control->retry_limit = 1; /* no retry */
+ control->key_idx = -1; /* no encryption key */
+ control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS |
+ IEEE80211_TXCTL_USE_CTS_PROTECT);
+ control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT |
+ IEEE80211_TXCTL_NO_ACK;
+ control->antenna_sel_tx = 0; /* default to default antenna */
+
+ /*
+ * for every radiotap entry that is present
+ * (ieee80211_radiotap_iterator_next returns -ENOENT when no more
+ * entries present, or -EINVAL on error)
+ */
+
+ while (!ret) {
+ int i, target_rate;
+
+ ret = ieee80211_radiotap_iterator_next(&iterator);
+
+ if (ret)
+ continue;
+
+ /* see if this argument is something we can use */
+ switch (iterator.this_arg_index) {
+ /*
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+ case IEEE80211_RADIOTAP_RATE:
+ /*
+ * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps
+ * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps
+ */
+ target_rate = (*iterator.this_arg) * 5;
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *r = &mode->rates[i];
+
+ if (r->rate > target_rate)
+ continue;
+
+ control->rate = r;
+
+ if (r->flags & IEEE80211_RATE_PREAMBLE2)
+ control->tx_rate = r->val2;
+ else
+ control->tx_rate = r->val;
+
+ /* end on exact match */
+ if (r->rate == target_rate)
+ i = mode->num_rates;
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ /*
+ * radiotap uses 0 for 1st ant, mac80211 is 1 for
+ * 1st ant
+ */
+ control->antenna_sel_tx = (*iterator.this_arg) + 1;
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_TX_POWER:
+ control->power_level = *iterator.this_arg;
+ break;
+
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) {
+ /*
+ * this indicates that the skb we have been
+ * handed has the 32-bit FCS CRC at the end...
+ * we should react to that by snipping it off
+ * because it will be recomputed and added
+ * on transmission
+ */
+ if (skb->len < (iterator.max_length + FCS_LEN))
+ return TXRX_DROP;
+
+ skb_trim(skb, skb->len - FCS_LEN);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
+ return TXRX_DROP;
+
+ /*
+ * remove the radiotap header
+ * iterator->max_length was sanity-checked against
+ * skb->len by iterator init
+ */
+ skb_pull(skb, iterator.max_length);
+
+ return TXRX_CONTINUE;
+}
+
+
+static ieee80211_txrx_result inline
__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
struct sk_buff *skb,
struct net_device *dev,
@@ -1126,6 +1268,9 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_sub_if_data *sdata;
+ ieee80211_txrx_result res = TXRX_CONTINUE;
+
int hdrlen;
memset(tx, 0, sizeof(*tx));
@@ -1135,7 +1280,32 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev);
tx->sta = sta_info_get(local, hdr->addr1);
tx->fc = le16_to_cpu(hdr->frame_control);
+
+ /*
+ * set defaults for things that can be set by
+ * injected radiotap headers
+ */
control->power_level = local->hw.conf.power_level;
+ control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
+ if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
+ control->antenna_sel_tx = tx->sta->antenna_sel_tx;
+
+ /* process and remove the injection radiotap header */
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (unlikely(sdata->type == IEEE80211_IF_TYPE_MNTR)) {
+ if (__ieee80211_parse_tx_radiotap(tx, skb, control) ==
+ TXRX_DROP) {
+ return TXRX_DROP;
+ }
+ /*
+ * we removed the radiotap header after this point,
+ * we filled control with what we could use
+ * set to the actual ieee header now
+ */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ res = TXRX_QUEUED; /* indication it was monitor packet */
+ }
+
tx->u.tx.control = control;
tx->u.tx.unicast = !is_multicast_ether_addr(hdr->addr1);
if (is_multicast_ether_addr(hdr->addr1))
@@ -1152,9 +1322,6 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK;
tx->sta->clear_dst_mask = 0;
}
- control->antenna_sel_tx = local->hw.conf.antenna_sel_tx;
- if (local->sta_antenna_sel != STA_ANTENNA_SEL_AUTO && tx->sta)
- control->antenna_sel_tx = tx->sta->antenna_sel_tx;
hdrlen = ieee80211_get_hdrlen(tx->fc);
if (skb->len > hdrlen + sizeof(rfc1042_header) + 2) {
u8 *pos = &skb->data[hdrlen + sizeof(rfc1042_header)];
@@ -1162,6 +1329,7 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx,
}
control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT;
+ return res;
}
static int inline is_ieee80211_device(struct net_device *dev,
@@ -1274,7 +1442,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
struct sta_info *sta;
ieee80211_tx_handler *handler;
struct ieee80211_txrx_data tx;
- ieee80211_txrx_result res = TXRX_DROP;
+ ieee80211_txrx_result res = TXRX_DROP, res_prepare;
int ret, i;
WARN_ON(__ieee80211_queue_pending(local, control->queue));
@@ -1284,15 +1452,26 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
return 0;
}
- __ieee80211_tx_prepare(&tx, skb, dev, control);
+ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control);
+
+ if (res_prepare == TXRX_DROP) {
+ dev_kfree_skb(skb);
+ return 0;
+ }
+
sta = tx.sta;
tx.u.tx.mgmt_interface = mgmt;
tx.u.tx.mode = local->hw.conf.mode;
- for (handler = local->tx_handlers; *handler != NULL; handler++) {
- res = (*handler)(&tx);
- if (res != TXRX_CONTINUE)
- break;
+ if (res_prepare == TXRX_QUEUED) { /* if it was an injected packet */
+ res = TXRX_CONTINUE;
+ } else {
+ for (handler = local->tx_handlers; *handler != NULL;
+ handler++) {
+ res = (*handler)(&tx);
+ if (res != TXRX_CONTINUE)
+ break;
+ }
}
skb = tx.skb; /* handlers are allowed to change skb */
@@ -1467,8 +1646,7 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb,
}
osdata = IEEE80211_DEV_TO_SUB_IF(odev);
- headroom = osdata->local->hw.extra_tx_headroom +
- IEEE80211_ENCRYPT_HEADROOM;
+ headroom = osdata->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM;
if (skb_headroom(skb) < headroom) {
if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) {
dev_kfree_skb(skb);
@@ -1494,6 +1672,56 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb,
}
+int ieee80211_monitor_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_tx_packet_data *pkt_data;
+ struct ieee80211_radiotap_header *prthdr =
+ (struct ieee80211_radiotap_header *)skb->data;
+ u16 len;
+
+ /*
+ * there must be a radiotap header at the
+ * start in this case
+ */
+ if (unlikely(prthdr->it_version)) {
+ /* only version 0 is supported */
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ skb->dev = local->mdev;
+
+ pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
+ memset(pkt_data, 0, sizeof(*pkt_data));
+ pkt_data->ifindex = dev->ifindex;
+ pkt_data->mgmt_iface = 0;
+ pkt_data->do_not_encrypt = 1;
+
+ /* above needed because we set skb device to master */
+
+ /*
+ * fix up the pointers accounting for the radiotap
+ * header still being in there. We are being given
+ * a precooked IEEE80211 header so no need for
+ * normal processing
+ */
+ len = le16_to_cpu(get_unaligned(&prthdr->it_len));
+ skb_set_mac_header(skb, len);
+ skb_set_network_header(skb, len + sizeof(struct ieee80211_hdr));
+ skb_set_transport_header(skb, len + sizeof(struct ieee80211_hdr));
+
+ /*
+ * pass the radiotap header up to
+ * the next stage intact
+ */
+ dev_queue_xmit(skb);
+
+ return NETDEV_TX_OK;
+}
+
+
/**
* ieee80211_subif_start_xmit - netif start_xmit function for Ethernet-type
* subinterfaces (wlan#, WDS, and VLAN interfaces)
@@ -1509,8 +1737,8 @@ static int ieee80211_master_start_xmit(struct sk_buff *skb,
* encapsulated packet will then be passed to master interface, wlan#.11, for
* transmission (through low-level driver).
*/
-static int ieee80211_subif_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
+int ieee80211_subif_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_tx_packet_data *pkt_data;
@@ -1619,7 +1847,7 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb,
* build in headroom in __dev_alloc_skb() (linux/skbuff.h) and
* alloc_skb() (net/core/skbuff.c)
*/
- head_need = hdrlen + encaps_len + local->hw.extra_tx_headroom;
+ head_need = hdrlen + encaps_len + local->tx_headroom;
head_need -= skb_headroom(skb);
/* We are going to modify skb data, so make a copy of it if happens to
@@ -1658,7 +1886,7 @@ static int ieee80211_subif_start_xmit(struct sk_buff *skb,
pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data));
- pkt_data->ifindex = sdata->dev->ifindex;
+ pkt_data->ifindex = dev->ifindex;
pkt_data->mgmt_iface = (sdata->type == IEEE80211_IF_TYPE_MGMT);
pkt_data->do_not_encrypt = no_encrypt;
@@ -1706,9 +1934,9 @@ ieee80211_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
- if (skb_headroom(skb) < sdata->local->hw.extra_tx_headroom) {
- if (pskb_expand_head(skb,
- sdata->local->hw.extra_tx_headroom, 0, GFP_ATOMIC)) {
+ if (skb_headroom(skb) < sdata->local->tx_headroom) {
+ if (pskb_expand_head(skb, sdata->local->tx_headroom,
+ 0, GFP_ATOMIC)) {
dev_kfree_skb(skb);
return 0;
}
@@ -1847,12 +2075,12 @@ struct sk_buff * ieee80211_beacon_get(struct ieee80211_hw *hw, int if_id,
bh_len = ap->beacon_head_len;
bt_len = ap->beacon_tail_len;
- skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+ skb = dev_alloc_skb(local->tx_headroom +
bh_len + bt_len + 256 /* maximum TIM len */);
if (!skb)
return NULL;
- skb_reserve(skb, local->hw.extra_tx_headroom);
+ skb_reserve(skb, local->tx_headroom);
memcpy(skb_put(skb, bh_len), b_head, bh_len);
ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data);
@@ -2376,8 +2604,7 @@ static void ieee80211_start_hard_monitor(struct ieee80211_local *local)
struct ieee80211_if_init_conf conf;
if (local->open_count && local->open_count == local->monitors &&
- !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER) &&
- local->ops->add_interface) {
+ !(local->hw.flags & IEEE80211_HW_MONITOR_DURING_OPER)) {
conf.if_id = -1;
conf.type = IEEE80211_IF_TYPE_MNTR;
conf.mac_addr = NULL;
@@ -2420,21 +2647,14 @@ static int ieee80211_open(struct net_device *dev)
}
ieee80211_start_soft_monitor(local);
- if (local->ops->add_interface) {
- conf.if_id = dev->ifindex;
- conf.type = sdata->type;
- conf.mac_addr = dev->dev_addr;
- res = local->ops->add_interface(local_to_hw(local), &conf);
- if (res) {
- if (sdata->type == IEEE80211_IF_TYPE_MNTR)
- ieee80211_start_hard_monitor(local);
- return res;
- }
- } else {
- if (sdata->type != IEEE80211_IF_TYPE_STA)
- return -EOPNOTSUPP;
- if (local->open_count > 0)
- return -ENOBUFS;
+ conf.if_id = dev->ifindex;
+ conf.type = sdata->type;
+ conf.mac_addr = dev->dev_addr;
+ res = local->ops->add_interface(local_to_hw(local), &conf);
+ if (res) {
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR)
+ ieee80211_start_hard_monitor(local);
+ return res;
}
if (local->open_count == 0) {
@@ -2941,34 +3161,6 @@ int ieee80211_radar_status(struct ieee80211_hw *hw, int channel,
}
EXPORT_SYMBOL(ieee80211_radar_status);
-int ieee80211_set_aid_for_sta(struct ieee80211_hw *hw, u8 *peer_address,
- u16 aid)
-{
- struct sk_buff *skb;
- struct ieee80211_msg_set_aid_for_sta *msg;
- struct ieee80211_local *local = hw_to_local(hw);
-
- /* unlikely because if this event only happens for APs,
- * which require an open ap device. */
- if (unlikely(!local->apdev))
- return 0;
-
- skb = dev_alloc_skb(sizeof(struct ieee80211_frame_info) +
- sizeof(struct ieee80211_msg_set_aid_for_sta));
-
- if (!skb)
- return -ENOMEM;
- skb_reserve(skb, sizeof(struct ieee80211_frame_info));
-
- msg = (struct ieee80211_msg_set_aid_for_sta *)
- skb_put(skb, sizeof(struct ieee80211_msg_set_aid_for_sta));
- memcpy(msg->sta_address, peer_address, ETH_ALEN);
- msg->aid = aid;
-
- ieee80211_rx_mgmt(local, skb, NULL, ieee80211_msg_set_aid_for_sta);
- return 0;
-}
-EXPORT_SYMBOL(ieee80211_set_aid_for_sta);
static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta)
{
@@ -4284,6 +4476,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_local *local = hw_to_local(hw);
u16 frag, type;
u32 msg_type;
+ struct ieee80211_tx_status_rtap_hdr *rthdr;
+ struct ieee80211_sub_if_data *sdata;
+ int monitors;
if (!status) {
printk(KERN_ERR
@@ -4395,27 +4590,100 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
local->dot11FailedCount++;
}
- if (!(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS)
- || unlikely(!local->apdev)) {
+ msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
+ ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
+
+ /* this was a transmitted frame, but now we want to reuse it */
+ skb_orphan(skb);
+
+ if ((status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS) &&
+ local->apdev) {
+ if (local->monitors) {
+ skb2 = skb_clone(skb, GFP_ATOMIC);
+ } else {
+ skb2 = skb;
+ skb = NULL;
+ }
+
+ if (skb2)
+ /* Send frame to hostapd */
+ ieee80211_rx_mgmt(local, skb2, NULL, msg_type);
+
+ if (!skb)
+ return;
+ }
+
+ if (!local->monitors) {
dev_kfree_skb(skb);
return;
}
- msg_type = (status->flags & IEEE80211_TX_STATUS_ACK) ?
- ieee80211_msg_tx_callback_ack : ieee80211_msg_tx_callback_fail;
+ /* send frame to monitor interfaces now */
- /* skb was the original skb used for TX. Clone it and give the clone
- * to netif_rx(). Free original skb. */
- skb2 = skb_copy(skb, GFP_ATOMIC);
- if (!skb2) {
+ if (skb_headroom(skb) < sizeof(*rthdr)) {
+ printk(KERN_ERR "ieee80211_tx_status: headroom too small\n");
dev_kfree_skb(skb);
return;
}
- dev_kfree_skb(skb);
- skb = skb2;
- /* Send frame to hostapd */
- ieee80211_rx_mgmt(local, skb, NULL, msg_type);
+ rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+ skb_push(skb, sizeof(*rthdr));
+
+ memset(rthdr, 0, sizeof(*rthdr));
+ rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr));
+ rthdr->hdr.it_present =
+ cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_DATA_RETRIES));
+
+ if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+ !is_multicast_ether_addr(hdr->addr1))
+ rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
+
+ if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
+ (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+ rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
+ else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
+
+ rthdr->data_retries = status->retry_count;
+
+ read_lock(&local->sub_if_lock);
+ monitors = local->monitors;
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ /*
+ * Using the monitors counter is possibly racy, but
+ * if the value is wrong we simply either clone the skb
+ * once too much or forget sending it to one monitor iface
+ * The latter case isn't nice but fixing the race is much
+ * more complicated.
+ */
+ if (!monitors || !skb)
+ goto out;
+
+ if (sdata->type == IEEE80211_IF_TYPE_MNTR) {
+ if (!netif_running(sdata->dev))
+ continue;
+ monitors--;
+ if (monitors)
+ skb2 = skb_clone(skb, GFP_KERNEL);
+ else
+ skb2 = NULL;
+ skb->dev = sdata->dev;
+ /* XXX: is this sufficient for BPF? */
+ skb_set_mac_header(skb, 0);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ memset(skb->cb, 0, sizeof(skb->cb));
+ netif_rx(skb);
+ skb = skb2;
+ break;
+ }
+ }
+ out:
+ read_unlock(&local->sub_if_lock);
+ if (skb)
+ dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status);
@@ -4619,6 +4887,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
((sizeof(struct ieee80211_local) +
NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+ BUG_ON(!ops->tx);
+ BUG_ON(!ops->config);
+ BUG_ON(!ops->add_interface);
local->ops = ops;
/* for now, mdev needs sub_if_data :/ */
@@ -4647,8 +4918,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->short_retry_limit = 7;
local->long_retry_limit = 4;
local->hw.conf.radio_enabled = 1;
- local->rate_ctrl_num_up = RATE_CONTROL_NUM_UP;
- local->rate_ctrl_num_down = RATE_CONTROL_NUM_DOWN;
local->enabled_modes = (unsigned int) -1;
@@ -4712,6 +4981,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_workqueue;
}
+ /*
+ * The hardware needs headroom for sending the frame,
+ * and we need some headroom for passing the frame to monitor
+ * interfaces, but never both at the same time.
+ */
+ local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
+ sizeof(struct ieee80211_tx_status_rtap_hdr));
+
debugfs_hw_add(local);
local->hw.conf.beacon_int = 1000;
@@ -4818,7 +5095,7 @@ int ieee80211_register_hwmode(struct ieee80211_hw *hw,
}
if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED))
- ieee80211_init_client(local->mdev);
+ ieee80211_set_default_regdomain(mode);
return 0;
}
@@ -4969,6 +5246,7 @@ static int __init ieee80211_init(void)
}
ieee80211_debugfs_netdev_init();
+ ieee80211_regdomain_init();
return 0;
}
diff --git a/net/mac80211/ieee80211_common.h b/net/mac80211/ieee80211_common.h
index b9a73e7f5f75..77c6afb7f6a8 100644
--- a/net/mac80211/ieee80211_common.h
+++ b/net/mac80211/ieee80211_common.h
@@ -47,21 +47,16 @@ enum ieee80211_msg_type {
ieee80211_msg_normal = 0,
ieee80211_msg_tx_callback_ack = 1,
ieee80211_msg_tx_callback_fail = 2,
- ieee80211_msg_passive_scan = 3,
+ /* hole at 3, was ieee80211_msg_passive_scan but unused */
ieee80211_msg_wep_frame_unknown_key = 4,
ieee80211_msg_michael_mic_failure = 5,
/* hole at 6, was monitor but never sent to userspace */
ieee80211_msg_sta_not_assoc = 7,
- ieee80211_msg_set_aid_for_sta = 8 /* used by Intersil MVC driver */,
+ /* 8 was ieee80211_msg_set_aid_for_sta */
ieee80211_msg_key_threshold_notification = 9,
ieee80211_msg_radar = 11,
};
-struct ieee80211_msg_set_aid_for_sta {
- char sta_address[ETH_ALEN];
- u16 aid;
-};
-
struct ieee80211_msg_key_notification {
int tx_rx_count;
char ifname[IFNAMSIZ];
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index af4d14d0b969..6f7bae7ef9c0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -99,6 +99,12 @@ struct ieee80211_sta_bss {
int probe_resp;
unsigned long last_update;
+ /* during assocation, we save an ERP value from a probe response so
+ * that we can feed ERP info to the driver when handling the
+ * association completes. these fields probably won't be up-to-date
+ * otherwise, you probably don't want to use them. */
+ int has_erp_value;
+ u8 erp_value;
};
@@ -235,7 +241,6 @@ struct ieee80211_if_sta {
unsigned int authenticated:1;
unsigned int associated:1;
unsigned int probereq_poll:1;
- unsigned int use_protection:1;
unsigned int create_ibss:1;
unsigned int mixed_cell:1;
unsigned int wmm_enabled:1;
@@ -278,6 +283,7 @@ struct ieee80211_sub_if_data {
int mc_count;
unsigned int allmulti:1;
unsigned int promisc:1;
+ unsigned int use_protection:1; /* CTS protect ERP frames */
struct net_device_stats stats;
int drop_unencrypted;
@@ -392,6 +398,7 @@ struct ieee80211_local {
int monitors;
struct iw_statistics wstats;
u8 wstats_flags;
+ int tx_headroom; /* required headroom for hardware/radiotap */
enum {
IEEE80211_DEV_UNINITIALIZED = 0,
@@ -437,7 +444,6 @@ struct ieee80211_local {
int *basic_rates[NUM_IEEE80211_MODES];
int rts_threshold;
- int cts_protect_erp_frames;
int fragmentation_threshold;
int short_retry_limit; /* dot11ShortRetryLimit */
int long_retry_limit; /* dot11LongRetryLimit */
@@ -513,8 +519,6 @@ struct ieee80211_local {
STA_ANTENNA_SEL_SW_CTRL_DEBUG = 2
} sta_antenna_sel;
- int rate_ctrl_num_up, rate_ctrl_num_down;
-
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
/* TX/RX handler statistics */
unsigned int tx_handlers_drop;
@@ -719,6 +723,8 @@ void ieee80211_prepare_rates(struct ieee80211_local *local,
struct ieee80211_hw_mode *mode);
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
+int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
+int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
void ieee80211_if_setup(struct net_device *dev);
void ieee80211_if_mgmt_setup(struct net_device *dev);
int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local,
@@ -753,7 +759,6 @@ void ieee80211_update_default_wep_only(struct ieee80211_local *local);
/* ieee80211_ioctl.c */
int ieee80211_set_compression(struct ieee80211_local *local,
struct net_device *dev, struct sta_info *sta);
-int ieee80211_init_client(struct net_device *dev);
int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq);
/* ieee80211_sta.c */
void ieee80211_sta_timer(unsigned long data);
@@ -792,6 +797,10 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata);
int ieee80211_if_add_mgmt(struct ieee80211_local *local);
void ieee80211_if_del_mgmt(struct ieee80211_local *local);
+/* regdomain.c */
+void ieee80211_regdomain_init(void);
+void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode);
+
/* for wiphy privid */
extern void *mac80211_wiphy_privid;
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index cf0f32e8c2a2..8532a5ccdd1e 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -157,6 +157,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int oldtype = sdata->type;
+ dev->hard_start_xmit = ieee80211_subif_start_xmit;
+
sdata->type = type;
switch (type) {
case IEEE80211_IF_TYPE_WDS:
@@ -196,6 +198,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
}
case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_IEEE80211_RADIOTAP;
+ dev->hard_start_xmit = ieee80211_monitor_start_xmit;
break;
default:
printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x",
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 352f03bd8a3a..d0e1ab5589db 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -27,20 +27,6 @@
#include "aes_ccm.h"
#include "debugfs_key.h"
-static int ieee80211_regdom = 0x10; /* FCC */
-module_param(ieee80211_regdom, int, 0444);
-MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
-
-/*
- * If firmware is upgraded by the vendor, additional channels can be used based
- * on the new Japanese regulatory rules. This is indicated by setting
- * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
- * module.
- */
-static int ieee80211_japan_5ghz /* = 0 */;
-module_param(ieee80211_japan_5ghz, int, 0444);
-MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
-
static void ieee80211_set_hw_encryption(struct net_device *dev,
struct sta_info *sta, u8 addr[ETH_ALEN],
struct ieee80211_key *key)
@@ -345,6 +331,8 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct iw_range *range = (struct iw_range *) extra;
+ struct ieee80211_hw_mode *mode = NULL;
+ int c = 0;
data->length = sizeof(struct iw_range);
memset(range, 0, sizeof(struct iw_range));
@@ -378,130 +366,34 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev,
range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
- IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
- IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-
- return 0;
-}
-
-
-struct ieee80211_channel_range {
- short start_freq;
- short end_freq;
- unsigned char power_level;
- unsigned char antenna_max;
-};
-
-static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
- { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
- { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
- { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
- { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
- { 0 }
-};
-
-static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
- { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
- { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
- { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
- { 0 }
-};
-
-
-static const struct ieee80211_channel_range *channel_range =
- ieee80211_fcc_channels;
-
-
-static void ieee80211_unmask_channel(struct net_device *dev, int mode,
- struct ieee80211_channel *chan)
-{
- int i;
-
- chan->flag = 0;
-
- if (ieee80211_regdom == 64 &&
- (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
- /* Do not allow Turbo modes in Japan. */
- return;
- }
-
- for (i = 0; channel_range[i].start_freq; i++) {
- const struct ieee80211_channel_range *r = &channel_range[i];
- if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
- if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
- chan->freq >= 5260 && chan->freq <= 5320) {
- /*
- * Skip new channels in Japan since the
- * firmware was not marked having been upgraded
- * by the vendor.
- */
- continue;
- }
+ list_for_each_entry(mode, &local->modes_list, list) {
+ int i = 0;
- if (ieee80211_regdom == 0x10 &&
- (chan->freq == 5190 || chan->freq == 5210 ||
- chan->freq == 5230)) {
- /* Skip MKK channels when in FCC domain. */
- continue;
- }
+ if (!(local->enabled_modes & (1 << mode->mode)) ||
+ (local->hw_modes & local->enabled_modes &
+ (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
+ continue;
- chan->flag |= IEEE80211_CHAN_W_SCAN |
- IEEE80211_CHAN_W_ACTIVE_SCAN |
- IEEE80211_CHAN_W_IBSS;
- chan->power_level = r->power_level;
- chan->antenna_max = r->antenna_max;
-
- if (ieee80211_regdom == 64 &&
- (chan->freq == 5170 || chan->freq == 5190 ||
- chan->freq == 5210 || chan->freq == 5230)) {
- /*
- * New regulatory rules in Japan have backwards
- * compatibility with old channels in 5.15-5.25
- * GHz band, but the station is not allowed to
- * use active scan on these old channels.
- */
- chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
- }
+ while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
+ struct ieee80211_channel *chan = &mode->channels[i];
- if (ieee80211_regdom == 64 &&
- (chan->freq == 5260 || chan->freq == 5280 ||
- chan->freq == 5300 || chan->freq == 5320)) {
- /*
- * IBSS is not allowed on 5.25-5.35 GHz band
- * due to radar detection requirements.
- */
- chan->flag &= ~IEEE80211_CHAN_W_IBSS;
+ if (chan->flag & IEEE80211_CHAN_W_SCAN) {
+ range->freq[c].i = chan->chan;
+ range->freq[c].m = chan->freq * 100000;
+ range->freq[c].e = 1;
+ c++;
}
-
- break;
+ i++;
}
}
-}
-
-
-static int ieee80211_unmask_channels(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
- int c;
-
- list_for_each_entry(mode, &local->modes_list, list) {
- for (c = 0; c < mode->num_channels; c++) {
- ieee80211_unmask_channel(dev, mode->mode,
- &mode->channels[c]);
- }
- }
- return 0;
-}
+ range->num_channels = c;
+ range->num_frequency = c;
+ IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+ IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-int ieee80211_init_client(struct net_device *dev)
-{
- if (ieee80211_regdom == 0x40)
- channel_range = ieee80211_mkk_channels;
- ieee80211_unmask_channels(dev);
return 0;
}
@@ -838,6 +730,67 @@ static int ieee80211_ioctl_giwscan(struct net_device *dev,
}
+static int ieee80211_ioctl_siwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
+ int i;
+ u32 target_rate = rate->value / 100000;
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (!sdata->bss)
+ return -ENODEV;
+ mode = local->oper_hw_mode;
+ /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
+ * target_rate = X, rate->fixed = 1 means only rate X
+ * target_rate = X, rate->fixed = 0 means all rates <= X */
+ sdata->bss->max_ratectrl_rateidx = -1;
+ sdata->bss->force_unicast_rateidx = -1;
+ if (rate->value < 0)
+ return 0;
+ for (i=0; i< mode->num_rates; i++) {
+ struct ieee80211_rate *rates = &mode->rates[i];
+ int this_rate = rates->rate;
+
+ if (mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG)
+ this_rate *= 2;
+ if (target_rate == this_rate) {
+ sdata->bss->max_ratectrl_rateidx = i;
+ if (rate->fixed)
+ sdata->bss->force_unicast_rateidx = i;
+ break;
+ }
+ }
+ return 0;
+}
+
+static int ieee80211_ioctl_giwrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rate, char *extra)
+{
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
+ struct ieee80211_sub_if_data *sdata;
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA)
+ sta = sta_info_get(local, sdata->u.sta.bssid);
+ else
+ return -EOPNOTSUPP;
+ if (!sta)
+ return -ENODEV;
+ if (sta->txrate < local->oper_hw_mode->num_rates)
+ rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
+ else
+ rate->value = 0;
+ sta_info_put(sta);
+ return 0;
+}
+
static int ieee80211_ioctl_siwrts(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *rts, char *extra)
@@ -970,118 +923,6 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev,
return 0;
}
-static int ieee80211_ioctl_clear_keys(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_key_conf key;
- int i;
- u8 addr[ETH_ALEN];
- struct ieee80211_key_conf *keyconf;
- struct ieee80211_sub_if_data *sdata;
- struct sta_info *sta;
-
- memset(addr, 0xff, ETH_ALEN);
- read_lock(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list) {
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- keyconf = NULL;
- if (sdata->keys[i] &&
- !sdata->keys[i]->force_sw_encrypt &&
- local->ops->set_key &&
- (keyconf = ieee80211_key_data2conf(local,
- sdata->keys[i])))
- local->ops->set_key(local_to_hw(local),
- DISABLE_KEY, addr,
- keyconf, 0);
- kfree(keyconf);
- ieee80211_key_free(sdata->keys[i]);
- sdata->keys[i] = NULL;
- }
- sdata->default_key = NULL;
- }
- read_unlock(&local->sub_if_lock);
-
- spin_lock_bh(&local->sta_lock);
- list_for_each_entry(sta, &local->sta_list, list) {
- keyconf = NULL;
- if (sta->key && !sta->key->force_sw_encrypt &&
- local->ops->set_key &&
- (keyconf = ieee80211_key_data2conf(local, sta->key)))
- local->ops->set_key(local_to_hw(local), DISABLE_KEY,
- sta->addr, keyconf, sta->aid);
- kfree(keyconf);
- ieee80211_key_free(sta->key);
- sta->key = NULL;
- }
- spin_unlock_bh(&local->sta_lock);
-
- memset(&key, 0, sizeof(key));
- if (local->ops->set_key &&
- local->ops->set_key(local_to_hw(local), REMOVE_ALL_KEYS,
- NULL, &key, 0))
- printk(KERN_DEBUG "%s: failed to remove hwaccel keys\n",
- dev->name);
-
- return 0;
-}
-
-
-static int
-ieee80211_ioctl_force_unicast_rate(struct net_device *dev,
- struct ieee80211_sub_if_data *sdata,
- int rate)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
- int i;
-
- if (sdata->type != IEEE80211_IF_TYPE_AP)
- return -ENOENT;
-
- if (rate == 0) {
- sdata->u.ap.force_unicast_rateidx = -1;
- return 0;
- }
-
- mode = local->oper_hw_mode;
- for (i = 0; i < mode->num_rates; i++) {
- if (mode->rates[i].rate == rate) {
- sdata->u.ap.force_unicast_rateidx = i;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-
-static int
-ieee80211_ioctl_max_ratectrl_rate(struct net_device *dev,
- struct ieee80211_sub_if_data *sdata,
- int rate)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_hw_mode *mode;
- int i;
-
- if (sdata->type != IEEE80211_IF_TYPE_AP)
- return -ENOENT;
-
- if (rate == 0) {
- sdata->u.ap.max_ratectrl_rateidx = -1;
- return 0;
- }
-
- mode = local->oper_hw_mode;
- for (i = 0; i < mode->num_rates; i++) {
- if (mode->rates[i].rate == rate) {
- sdata->u.ap.max_ratectrl_rateidx = i;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-
static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
struct ieee80211_key *key)
{
@@ -1205,24 +1046,11 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev,
sdata->ieee802_1x = value;
break;
- case PRISM2_PARAM_ANTSEL_TX:
- local->hw.conf.antenna_sel_tx = value;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- local->hw.conf.antenna_sel_rx = value;
- if (ieee80211_hw_config(local))
- ret = -EINVAL;
- break;
-
case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- local->cts_protect_erp_frames = value;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- sdata->drop_unencrypted = value;
+ if (sdata->type != IEEE80211_IF_TYPE_AP)
+ ret = -ENOENT;
+ else
+ sdata->use_protection = value;
break;
case PRISM2_PARAM_PREAMBLE:
@@ -1251,10 +1079,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev,
local->next_mode = value;
break;
- case PRISM2_PARAM_CLEAR_KEYS:
- ret = ieee80211_ioctl_clear_keys(dev);
- break;
-
case PRISM2_PARAM_RADIO_ENABLED:
ret = ieee80211_ioctl_set_radio_enabled(dev, value);
break;
@@ -1269,22 +1093,6 @@ static int ieee80211_ioctl_prism2_param(struct net_device *dev,
local->sta_antenna_sel = value;
break;
- case PRISM2_PARAM_FORCE_UNICAST_RATE:
- ret = ieee80211_ioctl_force_unicast_rate(dev, sdata, value);
- break;
-
- case PRISM2_PARAM_MAX_RATECTRL_RATE:
- ret = ieee80211_ioctl_max_ratectrl_rate(dev, sdata, value);
- break;
-
- case PRISM2_PARAM_RATE_CTRL_NUM_UP:
- local->rate_ctrl_num_up = value;
- break;
-
- case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
- local->rate_ctrl_num_down = value;
- break;
-
case PRISM2_PARAM_TX_POWER_REDUCTION:
if (value < 0)
ret = -EINVAL;
@@ -1364,20 +1172,8 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
*param = sdata->ieee802_1x;
break;
- case PRISM2_PARAM_ANTSEL_TX:
- *param = local->hw.conf.antenna_sel_tx;
- break;
-
- case PRISM2_PARAM_ANTSEL_RX:
- *param = local->hw.conf.antenna_sel_rx;
- break;
-
case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
- *param = local->cts_protect_erp_frames;
- break;
-
- case PRISM2_PARAM_DROP_UNENCRYPTED:
- *param = sdata->drop_unencrypted;
+ *param = sdata->use_protection;
break;
case PRISM2_PARAM_PREAMBLE:
@@ -1403,14 +1199,6 @@ static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
*param = local->sta_antenna_sel;
break;
- case PRISM2_PARAM_RATE_CTRL_NUM_UP:
- *param = local->rate_ctrl_num_up;
- break;
-
- case PRISM2_PARAM_RATE_CTRL_NUM_DOWN:
- *param = local->rate_ctrl_num_down;
- break;
-
case PRISM2_PARAM_TX_POWER_REDUCTION:
*param = local->hw.conf.tx_power_reduction;
break;
@@ -1778,8 +1566,8 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) NULL, /* SIOCGIWNICKN */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
- (iw_handler) NULL, /* SIOCSIWRATE */
- (iw_handler) NULL, /* SIOCGIWRATE */
+ (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
+ (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
(iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
(iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
(iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c
index 16e850864b8a..2118de04fc35 100644
--- a/net/mac80211/ieee80211_rate.c
+++ b/net/mac80211/ieee80211_rate.c
@@ -24,11 +24,10 @@ int ieee80211_rate_control_register(struct rate_control_ops *ops)
{
struct rate_control_alg *alg;
- alg = kmalloc(sizeof(*alg), GFP_KERNEL);
+ alg = kzalloc(sizeof(*alg), GFP_KERNEL);
if (alg == NULL) {
return -ENOMEM;
}
- memset(alg, 0, sizeof(*alg));
alg->ops = ops;
mutex_lock(&rate_ctrl_mutex);
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 91b545c144c1..7ba352e3ffe0 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -25,7 +25,6 @@
#include <linux/wireless.h>
#include <linux/random.h>
#include <linux/etherdevice.h>
-#include <linux/rtnetlink.h>
#include <net/iw_handler.h>
#include <asm/types.h>
@@ -76,33 +75,36 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
/* Parsed Information Elements */
struct ieee802_11_elems {
+ /* pointers to IEs */
u8 *ssid;
- u8 ssid_len;
u8 *supp_rates;
- u8 supp_rates_len;
u8 *fh_params;
- u8 fh_params_len;
u8 *ds_params;
- u8 ds_params_len;
u8 *cf_params;
- u8 cf_params_len;
u8 *tim;
- u8 tim_len;
u8 *ibss_params;
- u8 ibss_params_len;
u8 *challenge;
- u8 challenge_len;
u8 *wpa;
- u8 wpa_len;
u8 *rsn;
- u8 rsn_len;
u8 *erp_info;
- u8 erp_info_len;
u8 *ext_supp_rates;
- u8 ext_supp_rates_len;
u8 *wmm_info;
- u8 wmm_info_len;
u8 *wmm_param;
+
+ /* length of them, respectively */
+ u8 ssid_len;
+ u8 supp_rates_len;
+ u8 fh_params_len;
+ u8 ds_params_len;
+ u8 cf_params_len;
+ u8 tim_len;
+ u8 ibss_params_len;
+ u8 challenge_len;
+ u8 wpa_len;
+ u8 rsn_len;
+ u8 erp_info_len;
+ u8 ext_supp_rates_len;
+ u8 wmm_info_len;
u8 wmm_param_len;
};
@@ -311,6 +313,25 @@ static void ieee80211_sta_wmm_params(struct net_device *dev,
}
+static void ieee80211_handle_erp_ie(struct net_device *dev, u8 erp_value)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ int use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+
+ if (use_protection != sdata->use_protection) {
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
+ MAC_FMT ")\n",
+ dev->name,
+ use_protection ? "enabled" : "disabled",
+ MAC_ARG(ifsta->bssid));
+ }
+ sdata->use_protection = use_protection;
+ }
+}
+
+
static void ieee80211_sta_send_associnfo(struct net_device *dev,
struct ieee80211_if_sta *ifsta)
{
@@ -366,6 +387,7 @@ static void ieee80211_set_associated(struct net_device *dev,
struct ieee80211_if_sta *ifsta, int assoc)
{
union iwreq_data wrqu;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (ifsta->associated == assoc)
return;
@@ -374,9 +396,18 @@ static void ieee80211_set_associated(struct net_device *dev,
if (assoc) {
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sta_bss *bss;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type != IEEE80211_IF_TYPE_STA)
return;
+
+ bss = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ if (bss->has_erp_value)
+ ieee80211_handle_erp_ie(dev, bss->erp_value);
+ ieee80211_rx_bss_put(dev, bss);
+ }
+
netif_carrier_on(dev);
ifsta->prev_bssid_set = 1;
memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
@@ -384,6 +415,7 @@ static void ieee80211_set_associated(struct net_device *dev,
ieee80211_sta_send_associnfo(dev, ifsta);
} else {
netif_carrier_off(dev);
+ sdata->use_protection = 0;
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
}
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -1174,6 +1206,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct net_device *dev,
return;
}
+ /* it probably doesn't, but if the frame includes an ERP value then
+ * update our stored copy */
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ struct ieee80211_sta_bss *bss
+ = ieee80211_rx_bss_get(dev, ifsta->bssid);
+ if (bss) {
+ bss->erp_value = elems.erp_info[0];
+ bss->has_erp_value = 1;
+ ieee80211_rx_bss_put(dev, bss);
+ }
+ }
+
printk(KERN_DEBUG "%s: associated\n", dev->name);
ifsta->aid = aid;
ifsta->ap_capab = capab_info;
@@ -1282,10 +1326,9 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid)
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
- bss = kmalloc(sizeof(*bss), GFP_ATOMIC);
+ bss = kzalloc(sizeof(*bss), GFP_ATOMIC);
if (!bss)
return NULL;
- memset(bss, 0, sizeof(*bss));
atomic_inc(&bss->users);
atomic_inc(&bss->users);
memcpy(bss->bssid, bssid, ETH_ALEN);
@@ -1496,6 +1539,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev,
return;
}
+ /* save the ERP value so that it is available at association time */
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ bss->erp_value = elems.erp_info[0];
+ bss->has_erp_value = 1;
+ }
+
bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int);
bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info);
if (elems.ssid && elems.ssid_len <= IEEE80211_MAX_SSID_LEN) {
@@ -1611,10 +1660,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
size_t len,
struct ieee80211_rx_status *rx_status)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_sta *ifsta;
- int use_protection;
size_t baselen;
struct ieee802_11_elems elems;
@@ -1638,23 +1685,8 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev,
&elems) == ParseFailed)
return;
- use_protection = 0;
- if (elems.erp_info && elems.erp_info_len >= 1) {
- use_protection =
- (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
- }
-
- if (use_protection != !!ifsta->use_protection) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: CTS protection %s (BSSID="
- MAC_FMT ")\n",
- dev->name,
- use_protection ? "enabled" : "disabled",
- MAC_ARG(ifsta->bssid));
- }
- ifsta->use_protection = use_protection ? 1 : 0;
- local->cts_protect_erp_frames = use_protection;
- }
+ if (elems.erp_info && elems.erp_info_len >= 1)
+ ieee80211_handle_erp_ie(dev, elems.erp_info[0]);
if (elems.wmm_param && ifsta->wmm_enabled) {
ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param,
@@ -2073,12 +2105,9 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
struct ieee80211_sta_bss *bss, *selected = NULL;
int top_rssi = 0, freq;
- rtnl_lock();
-
if (!ifsta->auto_channel_sel && !ifsta->auto_bssid_sel &&
!ifsta->auto_ssid_sel) {
ifsta->state = IEEE80211_AUTHENTICATE;
- rtnl_unlock();
ieee80211_sta_reset_auth(dev, ifsta);
return 0;
}
@@ -2121,7 +2150,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
ieee80211_sta_set_bssid(dev, selected->bssid);
ieee80211_rx_bss_put(dev, selected);
ifsta->state = IEEE80211_AUTHENTICATE;
- rtnl_unlock();
ieee80211_sta_reset_auth(dev, ifsta);
return 0;
} else {
@@ -2132,7 +2160,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev,
} else
ifsta->state = IEEE80211_DISABLED;
}
- rtnl_unlock();
return -1;
}
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
index 2048cfd1ca70..f6780d63b342 100644
--- a/net/mac80211/rc80211_simple.c
+++ b/net/mac80211/rc80211_simple.c
@@ -187,9 +187,13 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev,
}
#endif
- if (per_failed > local->rate_ctrl_num_down) {
+ /*
+ * XXX: Make these configurable once we have an
+ * interface to the rate control algorithms
+ */
+ if (per_failed > RATE_CONTROL_NUM_DOWN) {
rate_control_rate_dec(local, sta);
- } else if (per_failed < local->rate_ctrl_num_up) {
+ } else if (per_failed < RATE_CONTROL_NUM_UP) {
rate_control_rate_inc(local, sta);
}
srctrl->tx_avg_rate_sum += status->control.rate->rate;
@@ -283,14 +287,16 @@ static void rate_control_simple_rate_init(void *priv, void *priv_sta,
int i;
sta->txrate = 0;
mode = local->oper_hw_mode;
- /* TODO: what is a good starting rate for STA? About middle? Maybe not
- * the lowest or the highest rate.. Could consider using RSSI from
- * previous packets? Need to have IEEE 802.1X auth succeed immediately
- * after assoc.. */
+ /* TODO: This routine should consider using RSSI from previous packets
+ * as we need to have IEEE 802.1X auth succeed immediately after assoc..
+ * Until that method is implemented, we will use the lowest supported rate
+ * as a workaround, */
for (i = 0; i < mode->num_rates; i++) {
if ((sta->supp_rates & BIT(i)) &&
- (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
+ (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) {
sta->txrate = i;
+ break;
+ }
}
}
diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c
new file mode 100644
index 000000000000..b697a2afbb4b
--- /dev/null
+++ b/net/mac80211/regdomain.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2002-2005, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 regulatory domain control implementation is known to be incomplete
+ * and confusing. mac80211 regulatory domain control will be significantly
+ * reworked in the not-too-distant future.
+ *
+ * For now, drivers wishing to control which channels are and aren't available
+ * are advised as follows:
+ * - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag
+ * - continue to include *ALL* possible channels in the modes registered
+ * through ieee80211_register_hwmode()
+ * - for each allowable ieee80211_channel structure registered in the above
+ * call, set the flag member to some meaningful value such as
+ * IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN |
+ * IEEE80211_CHAN_W_IBSS.
+ * - leave flag as 0 for non-allowable channels
+ *
+ * The usual implementation is for a driver to read a device EEPROM to
+ * determine which regulatory domain it should be operating under, then
+ * looking up the allowable channels in a driver-local table, then performing
+ * the above.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+
+static int ieee80211_regdom = 0x10; /* FCC */
+module_param(ieee80211_regdom, int, 0444);
+MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK");
+
+/*
+ * If firmware is upgraded by the vendor, additional channels can be used based
+ * on the new Japanese regulatory rules. This is indicated by setting
+ * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel
+ * module.
+ */
+static int ieee80211_japan_5ghz /* = 0 */;
+module_param(ieee80211_japan_5ghz, int, 0444);
+MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz");
+
+
+struct ieee80211_channel_range {
+ short start_freq;
+ short end_freq;
+ unsigned char power_level;
+ unsigned char antenna_max;
+};
+
+static const struct ieee80211_channel_range ieee80211_fcc_channels[] = {
+ { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */,
+ { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */,
+ { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */,
+ { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */,
+ { 0 }
+};
+
+static const struct ieee80211_channel_range ieee80211_mkk_channels[] = {
+ { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */,
+ { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */,
+ { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */,
+ { 0 }
+};
+
+
+static const struct ieee80211_channel_range *channel_range =
+ ieee80211_fcc_channels;
+
+
+static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan)
+{
+ int i;
+
+ chan->flag = 0;
+
+ if (ieee80211_regdom == 64 &&
+ (mode == MODE_ATHEROS_TURBO || mode == MODE_ATHEROS_TURBOG)) {
+ /* Do not allow Turbo modes in Japan. */
+ return;
+ }
+
+ for (i = 0; channel_range[i].start_freq; i++) {
+ const struct ieee80211_channel_range *r = &channel_range[i];
+ if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) {
+ if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz &&
+ chan->freq >= 5260 && chan->freq <= 5320) {
+ /*
+ * Skip new channels in Japan since the
+ * firmware was not marked having been upgraded
+ * by the vendor.
+ */
+ continue;
+ }
+
+ if (ieee80211_regdom == 0x10 &&
+ (chan->freq == 5190 || chan->freq == 5210 ||
+ chan->freq == 5230)) {
+ /* Skip MKK channels when in FCC domain. */
+ continue;
+ }
+
+ chan->flag |= IEEE80211_CHAN_W_SCAN |
+ IEEE80211_CHAN_W_ACTIVE_SCAN |
+ IEEE80211_CHAN_W_IBSS;
+ chan->power_level = r->power_level;
+ chan->antenna_max = r->antenna_max;
+
+ if (ieee80211_regdom == 64 &&
+ (chan->freq == 5170 || chan->freq == 5190 ||
+ chan->freq == 5210 || chan->freq == 5230)) {
+ /*
+ * New regulatory rules in Japan have backwards
+ * compatibility with old channels in 5.15-5.25
+ * GHz band, but the station is not allowed to
+ * use active scan on these old channels.
+ */
+ chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN;
+ }
+
+ if (ieee80211_regdom == 64 &&
+ (chan->freq == 5260 || chan->freq == 5280 ||
+ chan->freq == 5300 || chan->freq == 5320)) {
+ /*
+ * IBSS is not allowed on 5.25-5.35 GHz band
+ * due to radar detection requirements.
+ */
+ chan->flag &= ~IEEE80211_CHAN_W_IBSS;
+ }
+
+ break;
+ }
+ }
+}
+
+
+void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode)
+{
+ int c;
+ for (c = 0; c < mode->num_channels; c++)
+ ieee80211_unmask_channel(mode->mode, &mode->channels[c]);
+}
+
+
+void ieee80211_regdomain_init(void)
+{
+ if (ieee80211_regdom == 0x40)
+ channel_range = ieee80211_mkk_channels;
+}
+
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index a567dae8e5fd..3599770a2473 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -102,6 +102,16 @@ config NF_CT_PROTO_SCTP
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+config NF_CT_PROTO_UDPLITE
+ tristate 'UDP-Lite protocol connection tracking support (EXPERIMENTAL)'
+ depends on EXPERIMENTAL && NF_CONNTRACK
+ help
+ With this option enabled, the layer 3 independent connection
+ tracking code will be able to do state tracking on UDP-Lite
+ connections.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NF_CONNTRACK_AMANDA
tristate "Amanda backup protocol support"
depends on NF_CONNTRACK
@@ -343,6 +353,18 @@ config NETFILTER_XT_TARGET_NOTRACK
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_TARGET_TRACE
+ tristate '"TRACE" target support'
+ depends on NETFILTER_XTABLES
+ depends on IP_NF_RAW || IP6_NF_RAW
+ help
+ The TRACE target allows you to mark packets so that the kernel
+ will log every rule which match the packets as those traverse
+ the tables, chains, rules.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `N'.
+
config NETFILTER_XT_TARGET_SECMARK
tristate '"SECMARK" target support'
depends on NETFILTER_XTABLES && NETWORK_SECMARK
@@ -411,6 +433,14 @@ config NETFILTER_XT_MATCH_CONNBYTES
If you want to compile it as a module, say M here and read
<file:Documentation/kbuild/modules.txt>. If unsure, say `N'.
+config NETFILTER_XT_MATCH_CONNLIMIT
+ tristate '"connlimit" match support"'
+ depends on NETFILTER_XTABLES
+ depends on NF_CONNTRACK
+ ---help---
+ This match allows you to match against the number of parallel
+ connections to a server per client IP address (or address block).
+
config NETFILTER_XT_MATCH_CONNMARK
tristate '"connmark" connection mark match support'
depends on NETFILTER_XTABLES
@@ -635,6 +665,19 @@ config NETFILTER_XT_MATCH_TCPMSS
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_U32
+ tristate '"u32" match support'
+ depends on NETFILTER_XTABLES
+ ---help---
+ u32 allows you to extract quantities of up to 4 bytes from a packet,
+ AND them with specified masks, shift them by specified amounts and
+ test whether the results are in any of a set of specified ranges.
+ The specification of what to extract is general enough to skip over
+ headers with lengths stored in the packet, as in IP or TCP header
+ lengths.
+
+ Details and examples are in the kernel module source.
+
config NETFILTER_XT_MATCH_HASHLIMIT
tristate '"hashlimit" match support'
depends on NETFILTER_XTABLES && (IP6_NF_IPTABLES || IP6_NF_IPTABLES=n)
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index b2b5c7566b26..0c054bf27973 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -1,6 +1,6 @@
netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
-nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o
+nf_conntrack-y := nf_conntrack_core.o nf_conntrack_standalone.o nf_conntrack_expect.o nf_conntrack_helper.o nf_conntrack_proto.o nf_conntrack_l3proto_generic.o nf_conntrack_proto_generic.o nf_conntrack_proto_tcp.o nf_conntrack_proto_udp.o nf_conntrack_extend.o
nf_conntrack-$(CONFIG_NF_CONNTRACK_EVENTS) += nf_conntrack_ecache.o
obj-$(CONFIG_NETFILTER) = netfilter.o
@@ -16,6 +16,7 @@ obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
# SCTP protocol connection tracking
obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
+obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o
# netlink interface for nf_conntrack
obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
@@ -44,6 +45,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
@@ -51,6 +53,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o
obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o
obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o
@@ -72,4 +75,5 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STATISTIC) += xt_statistic.o
obj-$(CONFIG_NETFILTER_XT_MATCH_STRING) += xt_string.o
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_PHYSDEV) += xt_physdev.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o
obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index a84478ee2ded..381a77cf0c9e 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -203,7 +203,9 @@ int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len)
return 0;
/* Not exclusive use of packet? Must copy. */
- if (skb_shared(*pskb) || skb_cloned(*pskb))
+ if (skb_cloned(*pskb) && !skb_clone_writable(*pskb, writable_len))
+ goto copy_skb;
+ if (skb_shared(*pskb))
goto copy_skb;
return pskb_may_pull(*pskb, writable_len);
@@ -229,13 +231,13 @@ void nf_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
{
__be32 diff[] = { ~from, to };
if (skb->ip_summed != CHECKSUM_PARTIAL) {
- *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
+ *sum = csum_fold(csum_partial(diff, sizeof(diff),
~csum_unfold(*sum)));
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
- skb->csum = ~csum_partial((char *)diff, sizeof(diff),
+ skb->csum = ~csum_partial(diff, sizeof(diff),
~skb->csum);
} else if (pseudohdr)
- *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff),
+ *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
csum_unfold(*sum)));
}
EXPORT_SYMBOL(nf_proto_csum_replace4);
diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c
index 0568f2e86b59..e42ab230ad88 100644
--- a/net/netfilter/nf_conntrack_amanda.c
+++ b/net/netfilter/nf_conntrack_amanda.c
@@ -142,23 +142,22 @@ static int amanda_help(struct sk_buff **pskb,
if (port == 0 || len > 5)
break;
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (exp == NULL) {
ret = NF_DROP;
goto out;
}
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
- nf_conntrack_expect_init(exp, family,
- &tuple->src.u3, &tuple->dst.u3,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+ IPPROTO_TCP, NULL, &port);
nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
ret = nf_nat_amanda(pskb, ctinfo, off - dataoff,
len, exp);
- else if (nf_conntrack_expect_related(exp) != 0)
+ else if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
}
out:
@@ -175,9 +174,6 @@ static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(10080),
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
},
{
.name = "amanda",
@@ -188,9 +184,6 @@ static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
.tuple.src.l3num = AF_INET6,
.tuple.src.u.udp.port = __constant_htons(10080),
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
},
};
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 7a15e30356f2..aa086c83af80 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -36,15 +36,10 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_extend.h>
#define NF_CONNTRACK_VERSION "0.5.0"
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
DEFINE_RWLOCK(nf_conntrack_lock);
EXPORT_SYMBOL_GPL(nf_conntrack_lock);
@@ -52,57 +47,27 @@ EXPORT_SYMBOL_GPL(nf_conntrack_lock);
atomic_t nf_conntrack_count = ATOMIC_INIT(0);
EXPORT_SYMBOL_GPL(nf_conntrack_count);
-void (*nf_conntrack_destroyed)(struct nf_conn *conntrack);
-EXPORT_SYMBOL_GPL(nf_conntrack_destroyed);
-
unsigned int nf_conntrack_htable_size __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
int nf_conntrack_max __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_max);
-struct list_head *nf_conntrack_hash __read_mostly;
+struct hlist_head *nf_conntrack_hash __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_hash);
struct nf_conn nf_conntrack_untracked __read_mostly;
EXPORT_SYMBOL_GPL(nf_conntrack_untracked);
unsigned int nf_ct_log_invalid __read_mostly;
-LIST_HEAD(unconfirmed);
+HLIST_HEAD(unconfirmed);
static int nf_conntrack_vmalloc __read_mostly;
-
+static struct kmem_cache *nf_conntrack_cachep __read_mostly;
static unsigned int nf_conntrack_next_id;
DEFINE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat);
-/*
- * This scheme offers various size of "struct nf_conn" dependent on
- * features(helper, nat, ...)
- */
-
-#define NF_CT_FEATURES_NAMELEN 256
-static struct {
- /* name of slab cache. printed in /proc/slabinfo */
- char *name;
-
- /* size of slab cache */
- size_t size;
-
- /* slab cache pointer */
- struct kmem_cache *cachep;
-
- /* allocated slab cache + modules which uses this slab cache */
- int use;
-
-} nf_ct_cache[NF_CT_F_NUM];
-
-/* protect members of nf_ct_cache except of "use" */
-DEFINE_RWLOCK(nf_ct_cache_lock);
-
-/* This avoids calling kmem_cache_create() with same name simultaneously */
-static DEFINE_MUTEX(nf_ct_cache_mutex);
-
static int nf_conntrack_hash_rnd_initted;
static unsigned int nf_conntrack_hash_rnd;
@@ -125,122 +90,6 @@ static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple)
nf_conntrack_hash_rnd);
}
-int nf_conntrack_register_cache(u_int32_t features, const char *name,
- size_t size)
-{
- int ret = 0;
- char *cache_name;
- struct kmem_cache *cachep;
-
- DEBUGP("nf_conntrack_register_cache: features=0x%x, name=%s, size=%d\n",
- features, name, size);
-
- if (features < NF_CT_F_BASIC || features >= NF_CT_F_NUM) {
- DEBUGP("nf_conntrack_register_cache: invalid features.: 0x%x\n",
- features);
- return -EINVAL;
- }
-
- mutex_lock(&nf_ct_cache_mutex);
-
- write_lock_bh(&nf_ct_cache_lock);
- /* e.g: multiple helpers are loaded */
- if (nf_ct_cache[features].use > 0) {
- DEBUGP("nf_conntrack_register_cache: already resisterd.\n");
- if ((!strncmp(nf_ct_cache[features].name, name,
- NF_CT_FEATURES_NAMELEN))
- && nf_ct_cache[features].size == size) {
- DEBUGP("nf_conntrack_register_cache: reusing.\n");
- nf_ct_cache[features].use++;
- ret = 0;
- } else
- ret = -EBUSY;
-
- write_unlock_bh(&nf_ct_cache_lock);
- mutex_unlock(&nf_ct_cache_mutex);
- return ret;
- }
- write_unlock_bh(&nf_ct_cache_lock);
-
- /*
- * The memory space for name of slab cache must be alive until
- * cache is destroyed.
- */
- cache_name = kmalloc(sizeof(char)*NF_CT_FEATURES_NAMELEN, GFP_ATOMIC);
- if (cache_name == NULL) {
- DEBUGP("nf_conntrack_register_cache: can't alloc cache_name\n");
- ret = -ENOMEM;
- goto out_up_mutex;
- }
-
- if (strlcpy(cache_name, name, NF_CT_FEATURES_NAMELEN)
- >= NF_CT_FEATURES_NAMELEN) {
- printk("nf_conntrack_register_cache: name too long\n");
- ret = -EINVAL;
- goto out_free_name;
- }
-
- cachep = kmem_cache_create(cache_name, size, 0, 0,
- NULL, NULL);
- if (!cachep) {
- printk("nf_conntrack_register_cache: Can't create slab cache "
- "for the features = 0x%x\n", features);
- ret = -ENOMEM;
- goto out_free_name;
- }
-
- write_lock_bh(&nf_ct_cache_lock);
- nf_ct_cache[features].use = 1;
- nf_ct_cache[features].size = size;
- nf_ct_cache[features].cachep = cachep;
- nf_ct_cache[features].name = cache_name;
- write_unlock_bh(&nf_ct_cache_lock);
-
- goto out_up_mutex;
-
-out_free_name:
- kfree(cache_name);
-out_up_mutex:
- mutex_unlock(&nf_ct_cache_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(nf_conntrack_register_cache);
-
-/* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */
-void nf_conntrack_unregister_cache(u_int32_t features)
-{
- struct kmem_cache *cachep;
- char *name;
-
- /*
- * This assures that kmem_cache_create() isn't called before destroying
- * slab cache.
- */
- DEBUGP("nf_conntrack_unregister_cache: 0x%04x\n", features);
- mutex_lock(&nf_ct_cache_mutex);
-
- write_lock_bh(&nf_ct_cache_lock);
- if (--nf_ct_cache[features].use > 0) {
- write_unlock_bh(&nf_ct_cache_lock);
- mutex_unlock(&nf_ct_cache_mutex);
- return;
- }
- cachep = nf_ct_cache[features].cachep;
- name = nf_ct_cache[features].name;
- nf_ct_cache[features].cachep = NULL;
- nf_ct_cache[features].name = NULL;
- nf_ct_cache[features].size = 0;
- write_unlock_bh(&nf_ct_cache_lock);
-
- synchronize_net();
-
- kmem_cache_destroy(cachep);
- kfree(name);
-
- mutex_unlock(&nf_ct_cache_mutex);
-}
-EXPORT_SYMBOL_GPL(nf_conntrack_unregister_cache);
-
int
nf_ct_get_tuple(const struct sk_buff *skb,
unsigned int nhoff,
@@ -264,6 +113,36 @@ nf_ct_get_tuple(const struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(nf_ct_get_tuple);
+int nf_ct_get_tuplepr(const struct sk_buff *skb,
+ unsigned int nhoff,
+ u_int16_t l3num,
+ struct nf_conntrack_tuple *tuple)
+{
+ struct nf_conntrack_l3proto *l3proto;
+ struct nf_conntrack_l4proto *l4proto;
+ unsigned int protoff;
+ u_int8_t protonum;
+ int ret;
+
+ rcu_read_lock();
+
+ l3proto = __nf_ct_l3proto_find(l3num);
+ ret = l3proto->get_l4proto(skb, nhoff, &protoff, &protonum);
+ if (ret != NF_ACCEPT) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ l4proto = __nf_ct_l4proto_find(l3num, protonum);
+
+ ret = nf_ct_get_tuple(skb, nhoff, protoff, l3num, protonum, tuple,
+ l3proto, l4proto);
+
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nf_ct_get_tuplepr);
+
int
nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig,
@@ -286,9 +165,9 @@ EXPORT_SYMBOL_GPL(nf_ct_invert_tuple);
static void
clean_from_lists(struct nf_conn *ct)
{
- DEBUGP("clean_from_lists(%p)\n", ct);
- list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
- list_del(&ct->tuplehash[IP_CT_DIR_REPLY].list);
+ pr_debug("clean_from_lists(%p)\n", ct);
+ hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
+ hlist_del(&ct->tuplehash[IP_CT_DIR_REPLY].hnode);
/* Destroy all pending expectations */
nf_ct_remove_expectations(ct);
@@ -299,9 +178,8 @@ destroy_conntrack(struct nf_conntrack *nfct)
{
struct nf_conn *ct = (struct nf_conn *)nfct;
struct nf_conntrack_l4proto *l4proto;
- typeof(nf_conntrack_destroyed) destroyed;
- DEBUGP("destroy_conntrack(%p)\n", ct);
+ pr_debug("destroy_conntrack(%p)\n", ct);
NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
NF_CT_ASSERT(!timer_pending(&ct->timeout));
@@ -317,9 +195,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
if (l4proto && l4proto->destroy)
l4proto->destroy(ct);
- destroyed = rcu_dereference(nf_conntrack_destroyed);
- if (destroyed)
- destroyed(ct);
+ nf_ct_ext_destroy(ct);
rcu_read_unlock();
@@ -332,8 +208,8 @@ destroy_conntrack(struct nf_conntrack *nfct)
/* We overload first tuple to link into unconfirmed list. */
if (!nf_ct_is_confirmed(ct)) {
- BUG_ON(list_empty(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list));
- list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+ BUG_ON(hlist_unhashed(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode));
+ hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
}
NF_CT_STAT_INC(delete);
@@ -342,7 +218,7 @@ destroy_conntrack(struct nf_conntrack *nfct)
if (ct->master)
nf_ct_put(ct->master);
- DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct);
+ pr_debug("destroy_conntrack: returning ct=%p to slab\n", ct);
nf_conntrack_free(ct);
}
@@ -374,9 +250,10 @@ __nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *ignored_conntrack)
{
struct nf_conntrack_tuple_hash *h;
+ struct hlist_node *n;
unsigned int hash = hash_conntrack(tuple);
- list_for_each_entry(h, &nf_conntrack_hash[hash], list) {
+ hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) {
if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
nf_ct_tuple_equal(tuple, &h->tuple)) {
NF_CT_STAT_INC(found);
@@ -391,13 +268,12 @@ EXPORT_SYMBOL_GPL(__nf_conntrack_find);
/* Find a connection corresponding to a tuple. */
struct nf_conntrack_tuple_hash *
-nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple,
- const struct nf_conn *ignored_conntrack)
+nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_tuple_hash *h;
read_lock_bh(&nf_conntrack_lock);
- h = __nf_conntrack_find(tuple, ignored_conntrack);
+ h = __nf_conntrack_find(tuple, NULL);
if (h)
atomic_inc(&nf_ct_tuplehash_to_ctrack(h)->ct_general.use);
read_unlock_bh(&nf_conntrack_lock);
@@ -411,10 +287,10 @@ static void __nf_conntrack_hash_insert(struct nf_conn *ct,
unsigned int repl_hash)
{
ct->id = ++nf_conntrack_next_id;
- list_add(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list,
- &nf_conntrack_hash[hash]);
- list_add(&ct->tuplehash[IP_CT_DIR_REPLY].list,
- &nf_conntrack_hash[repl_hash]);
+ hlist_add_head(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
+ &nf_conntrack_hash[hash]);
+ hlist_add_head(&ct->tuplehash[IP_CT_DIR_REPLY].hnode,
+ &nf_conntrack_hash[repl_hash]);
}
void nf_conntrack_hash_insert(struct nf_conn *ct)
@@ -438,6 +314,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct;
struct nf_conn_help *help;
+ struct hlist_node *n;
enum ip_conntrack_info ctinfo;
ct = nf_ct_get(*pskb, &ctinfo);
@@ -460,24 +337,24 @@ __nf_conntrack_confirm(struct sk_buff **pskb)
/* No external references means noone else could have
confirmed us. */
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
- DEBUGP("Confirming conntrack %p\n", ct);
+ pr_debug("Confirming conntrack %p\n", ct);
write_lock_bh(&nf_conntrack_lock);
/* See if there's one in the list already, including reverse:
NAT could have grabbed it without realizing, since we're
not in the hash. If there is, we lost race. */
- list_for_each_entry(h, &nf_conntrack_hash[hash], list)
+ hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode)
if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
&h->tuple))
goto out;
- list_for_each_entry(h, &nf_conntrack_hash[repl_hash], list)
+ hlist_for_each_entry(h, n, &nf_conntrack_hash[repl_hash], hnode)
if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
&h->tuple))
goto out;
/* Remove from unconfirmed list */
- list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list);
+ hlist_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].hnode);
__nf_conntrack_hash_insert(ct, hash, repl_hash);
/* Timer relative to confirmation time, not original
@@ -524,24 +401,33 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
}
EXPORT_SYMBOL_GPL(nf_conntrack_tuple_taken);
+#define NF_CT_EVICTION_RANGE 8
+
/* There's a small race here where we may free a just-assured
connection. Too bad: we're in trouble anyway. */
-static int early_drop(struct list_head *chain)
+static int early_drop(unsigned int hash)
{
- /* Traverse backwards: gives us oldest, which is roughly LRU */
+ /* Use oldest entry, which is roughly LRU */
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct = NULL, *tmp;
+ struct hlist_node *n;
+ unsigned int i, cnt = 0;
int dropped = 0;
read_lock_bh(&nf_conntrack_lock);
- list_for_each_entry_reverse(h, chain, list) {
- tmp = nf_ct_tuplehash_to_ctrack(h);
- if (!test_bit(IPS_ASSURED_BIT, &tmp->status)) {
- ct = tmp;
- atomic_inc(&ct->ct_general.use);
- break;
+ for (i = 0; i < nf_conntrack_htable_size; i++) {
+ hlist_for_each_entry(h, n, &nf_conntrack_hash[hash], hnode) {
+ tmp = nf_ct_tuplehash_to_ctrack(h);
+ if (!test_bit(IPS_ASSURED_BIT, &tmp->status))
+ ct = tmp;
+ cnt++;
}
+ if (ct || cnt >= NF_CT_EVICTION_RANGE)
+ break;
+ hash = (hash + 1) % nf_conntrack_htable_size;
}
+ if (ct)
+ atomic_inc(&ct->ct_general.use);
read_unlock_bh(&nf_conntrack_lock);
if (!ct)
@@ -556,14 +442,10 @@ static int early_drop(struct list_head *chain)
return dropped;
}
-static struct nf_conn *
-__nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
- const struct nf_conntrack_tuple *repl,
- const struct nf_conntrack_l3proto *l3proto,
- u_int32_t features)
+struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
+ const struct nf_conntrack_tuple *repl)
{
struct nf_conn *conntrack = NULL;
- struct nf_conntrack_helper *helper;
if (unlikely(!nf_conntrack_hash_rnd_initted)) {
get_random_bytes(&nf_conntrack_hash_rnd, 4);
@@ -576,8 +458,7 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
if (nf_conntrack_max
&& atomic_read(&nf_conntrack_count) > nf_conntrack_max) {
unsigned int hash = hash_conntrack(orig);
- /* Try dropping from this hash chain. */
- if (!early_drop(&nf_conntrack_hash[hash])) {
+ if (!early_drop(hash)) {
atomic_dec(&nf_conntrack_count);
if (net_ratelimit())
printk(KERN_WARNING
@@ -587,72 +468,28 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
}
}
- /* find features needed by this conntrack. */
- features |= l3proto->get_features(orig);
-
- /* FIXME: protect helper list per RCU */
- read_lock_bh(&nf_conntrack_lock);
- helper = __nf_ct_helper_find(repl);
- /* NAT might want to assign a helper later */
- if (helper || features & NF_CT_F_NAT)
- features |= NF_CT_F_HELP;
- read_unlock_bh(&nf_conntrack_lock);
-
- DEBUGP("nf_conntrack_alloc: features=0x%x\n", features);
-
- read_lock_bh(&nf_ct_cache_lock);
-
- if (unlikely(!nf_ct_cache[features].use)) {
- DEBUGP("nf_conntrack_alloc: not supported features = 0x%x\n",
- features);
- goto out;
- }
-
- conntrack = kmem_cache_alloc(nf_ct_cache[features].cachep, GFP_ATOMIC);
+ conntrack = kmem_cache_zalloc(nf_conntrack_cachep, GFP_ATOMIC);
if (conntrack == NULL) {
- DEBUGP("nf_conntrack_alloc: Can't alloc conntrack from cache\n");
- goto out;
+ pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n");
+ atomic_dec(&nf_conntrack_count);
+ return ERR_PTR(-ENOMEM);
}
- memset(conntrack, 0, nf_ct_cache[features].size);
- conntrack->features = features;
atomic_set(&conntrack->ct_general.use, 1);
conntrack->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig;
conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *repl;
/* Don't set timer yet: wait for confirmation */
setup_timer(&conntrack->timeout, death_by_timeout,
(unsigned long)conntrack);
- read_unlock_bh(&nf_ct_cache_lock);
return conntrack;
-out:
- read_unlock_bh(&nf_ct_cache_lock);
- atomic_dec(&nf_conntrack_count);
- return conntrack;
-}
-
-struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
- const struct nf_conntrack_tuple *repl)
-{
- struct nf_conntrack_l3proto *l3proto;
- struct nf_conn *ct;
-
- rcu_read_lock();
- l3proto = __nf_ct_l3proto_find(orig->src.l3num);
- ct = __nf_conntrack_alloc(orig, repl, l3proto, 0);
- rcu_read_unlock();
-
- return ct;
}
EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
void nf_conntrack_free(struct nf_conn *conntrack)
{
- u_int32_t features = conntrack->features;
- NF_CT_ASSERT(features >= NF_CT_F_BASIC && features < NF_CT_F_NUM);
- DEBUGP("nf_conntrack_free: features = 0x%x, conntrack=%p\n", features,
- conntrack);
- kmem_cache_free(nf_ct_cache[features].cachep, conntrack);
+ nf_ct_ext_free(conntrack);
+ kmem_cache_free(nf_conntrack_cachep, conntrack);
atomic_dec(&nf_conntrack_count);
}
EXPORT_SYMBOL_GPL(nf_conntrack_free);
@@ -670,43 +507,38 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
struct nf_conn_help *help;
struct nf_conntrack_tuple repl_tuple;
struct nf_conntrack_expect *exp;
- u_int32_t features = 0;
if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
- DEBUGP("Can't invert tuple.\n");
+ pr_debug("Can't invert tuple.\n");
return NULL;
}
- read_lock_bh(&nf_conntrack_lock);
- exp = __nf_conntrack_expect_find(tuple);
- if (exp && exp->helper)
- features = NF_CT_F_HELP;
- read_unlock_bh(&nf_conntrack_lock);
-
- conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto, features);
+ conntrack = nf_conntrack_alloc(tuple, &repl_tuple);
if (conntrack == NULL || IS_ERR(conntrack)) {
- DEBUGP("Can't allocate conntrack.\n");
+ pr_debug("Can't allocate conntrack.\n");
return (struct nf_conntrack_tuple_hash *)conntrack;
}
if (!l4proto->new(conntrack, skb, dataoff)) {
nf_conntrack_free(conntrack);
- DEBUGP("init conntrack: can't track with proto module\n");
+ pr_debug("init conntrack: can't track with proto module\n");
return NULL;
}
write_lock_bh(&nf_conntrack_lock);
- exp = find_expectation(tuple);
-
- help = nfct_help(conntrack);
+ exp = nf_ct_find_expectation(tuple);
if (exp) {
- DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n",
- conntrack, exp);
+ pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
+ conntrack, exp);
/* Welcome, Mr. Bond. We've been expecting you... */
__set_bit(IPS_EXPECTED_BIT, &conntrack->status);
conntrack->master = exp->master;
- if (exp->helper)
- rcu_assign_pointer(help->helper, exp->helper);
+ if (exp->helper) {
+ help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
+ if (help)
+ rcu_assign_pointer(help->helper, exp->helper);
+ }
+
#ifdef CONFIG_NF_CONNTRACK_MARK
conntrack->mark = exp->master->mark;
#endif
@@ -716,23 +548,27 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
nf_conntrack_get(&conntrack->master->ct_general);
NF_CT_STAT_INC(expect_new);
} else {
- if (help) {
- /* not in hash table yet, so not strictly necessary */
- rcu_assign_pointer(help->helper,
- __nf_ct_helper_find(&repl_tuple));
+ struct nf_conntrack_helper *helper;
+
+ helper = __nf_ct_helper_find(&repl_tuple);
+ if (helper) {
+ help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
+ if (help)
+ rcu_assign_pointer(help->helper, helper);
}
NF_CT_STAT_INC(new);
}
/* Overload tuple linked list to put us in unconfirmed list. */
- list_add(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].list, &unconfirmed);
+ hlist_add_head(&conntrack->tuplehash[IP_CT_DIR_ORIGINAL].hnode,
+ &unconfirmed);
write_unlock_bh(&nf_conntrack_lock);
if (exp) {
if (exp->expectfn)
exp->expectfn(conntrack, exp);
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
}
return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL];
@@ -756,12 +592,12 @@ resolve_normal_ct(struct sk_buff *skb,
if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
dataoff, l3num, protonum, &tuple, l3proto,
l4proto)) {
- DEBUGP("resolve_normal_ct: Can't get tuple\n");
+ pr_debug("resolve_normal_ct: Can't get tuple\n");
return NULL;
}
/* look for tuple match */
- h = nf_conntrack_find_get(&tuple, NULL);
+ h = nf_conntrack_find_get(&tuple);
if (!h) {
h = init_conntrack(&tuple, l3proto, l4proto, skb, dataoff);
if (!h)
@@ -779,13 +615,14 @@ resolve_normal_ct(struct sk_buff *skb,
} else {
/* Once we've had two way comms, always ESTABLISHED. */
if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
- DEBUGP("nf_conntrack_in: normal packet for %p\n", ct);
+ pr_debug("nf_conntrack_in: normal packet for %p\n", ct);
*ctinfo = IP_CT_ESTABLISHED;
} else if (test_bit(IPS_EXPECTED_BIT, &ct->status)) {
- DEBUGP("nf_conntrack_in: related packet for %p\n", ct);
+ pr_debug("nf_conntrack_in: related packet for %p\n",
+ ct);
*ctinfo = IP_CT_RELATED;
} else {
- DEBUGP("nf_conntrack_in: new packet for %p\n", ct);
+ pr_debug("nf_conntrack_in: new packet for %p\n", ct);
*ctinfo = IP_CT_NEW;
}
*set_reply = 0;
@@ -815,9 +652,12 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
/* rcu_read_lock()ed by nf_hook_slow */
l3proto = __nf_ct_l3proto_find((u_int16_t)pf);
-
- if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) {
- DEBUGP("not prepared to track yet or error occured\n");
+ ret = l3proto->get_l4proto(*pskb, skb_network_offset(*pskb),
+ &dataoff, &protonum);
+ if (ret <= 0) {
+ pr_debug("not prepared to track yet or error occured\n");
+ NF_CT_STAT_INC_ATOMIC(error);
+ NF_CT_STAT_INC_ATOMIC(invalid);
return -ret;
}
@@ -853,7 +693,7 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb)
if (ret < 0) {
/* Invalid: inverse of the return code tells
* the netfilter core what to do */
- DEBUGP("nf_conntrack_in: Can't track with proto module\n");
+ pr_debug("nf_conntrack_in: Can't track with proto module\n");
nf_conntrack_put((*pskb)->nfct);
(*pskb)->nfct = NULL;
NF_CT_STAT_INC_ATOMIC(invalid);
@@ -888,23 +728,36 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
const struct nf_conntrack_tuple *newreply)
{
struct nf_conn_help *help = nfct_help(ct);
+ struct nf_conntrack_helper *helper;
write_lock_bh(&nf_conntrack_lock);
/* Should be unconfirmed, so not in hash table yet */
NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
- DEBUGP("Altering reply tuple of %p to ", ct);
+ pr_debug("Altering reply tuple of %p to ", ct);
NF_CT_DUMP_TUPLE(newreply);
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
- if (!ct->master && help && help->expecting == 0) {
- struct nf_conntrack_helper *helper;
- helper = __nf_ct_helper_find(newreply);
- if (helper)
- memset(&help->help, 0, sizeof(help->help));
- /* not in hash table yet, so not strictly necessary */
- rcu_assign_pointer(help->helper, helper);
+ if (ct->master || (help && help->expecting != 0))
+ goto out;
+
+ helper = __nf_ct_helper_find(newreply);
+ if (helper == NULL) {
+ if (help)
+ rcu_assign_pointer(help->helper, NULL);
+ goto out;
}
+
+ if (help == NULL) {
+ help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
+ if (help == NULL)
+ goto out;
+ } else {
+ memset(&help->help, 0, sizeof(help->help));
+ }
+
+ rcu_assign_pointer(help->helper, helper);
+out:
write_unlock_bh(&nf_conntrack_lock);
}
EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
@@ -1048,16 +901,17 @@ get_next_corpse(int (*iter)(struct nf_conn *i, void *data),
{
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct;
+ struct hlist_node *n;
write_lock_bh(&nf_conntrack_lock);
for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
- list_for_each_entry(h, &nf_conntrack_hash[*bucket], list) {
+ hlist_for_each_entry(h, n, &nf_conntrack_hash[*bucket], hnode) {
ct = nf_ct_tuplehash_to_ctrack(h);
if (iter(ct, data))
goto found;
}
}
- list_for_each_entry(h, &unconfirmed, list) {
+ hlist_for_each_entry(h, n, &unconfirmed, hnode) {
ct = nf_ct_tuplehash_to_ctrack(h);
if (iter(ct, data))
set_bit(IPS_DYING_BIT, &ct->status);
@@ -1092,14 +946,15 @@ static int kill_all(struct nf_conn *i, void *data)
return 1;
}
-static void free_conntrack_hash(struct list_head *hash, int vmalloced, int size)
+void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, int size)
{
if (vmalloced)
vfree(hash);
else
free_pages((unsigned long)hash,
- get_order(sizeof(struct list_head) * size));
+ get_order(sizeof(struct hlist_head) * size));
}
+EXPORT_SYMBOL_GPL(nf_ct_free_hashtable);
void nf_conntrack_flush(void)
{
@@ -1111,8 +966,6 @@ EXPORT_SYMBOL_GPL(nf_conntrack_flush);
supposed to kill the mall. */
void nf_conntrack_cleanup(void)
{
- int i;
-
rcu_assign_pointer(ip_ct_attach, NULL);
/* This makes sure all current packets have passed through
@@ -1133,49 +986,46 @@ void nf_conntrack_cleanup(void)
rcu_assign_pointer(nf_ct_destroy, NULL);
- for (i = 0; i < NF_CT_F_NUM; i++) {
- if (nf_ct_cache[i].use == 0)
- continue;
-
- NF_CT_ASSERT(nf_ct_cache[i].use == 1);
- nf_ct_cache[i].use = 1;
- nf_conntrack_unregister_cache(i);
- }
- kmem_cache_destroy(nf_conntrack_expect_cachep);
- free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
- nf_conntrack_htable_size);
+ kmem_cache_destroy(nf_conntrack_cachep);
+ nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_vmalloc,
+ nf_conntrack_htable_size);
nf_conntrack_proto_fini();
+ nf_conntrack_helper_fini();
+ nf_conntrack_expect_fini();
}
-static struct list_head *alloc_hashtable(int size, int *vmalloced)
+struct hlist_head *nf_ct_alloc_hashtable(int *sizep, int *vmalloced)
{
- struct list_head *hash;
- unsigned int i;
+ struct hlist_head *hash;
+ unsigned int size, i;
*vmalloced = 0;
+
+ size = *sizep = roundup(*sizep, PAGE_SIZE / sizeof(struct hlist_head));
hash = (void*)__get_free_pages(GFP_KERNEL,
- get_order(sizeof(struct list_head)
+ get_order(sizeof(struct hlist_head)
* size));
if (!hash) {
*vmalloced = 1;
printk(KERN_WARNING "nf_conntrack: falling back to vmalloc.\n");
- hash = vmalloc(sizeof(struct list_head) * size);
+ hash = vmalloc(sizeof(struct hlist_head) * size);
}
if (hash)
for (i = 0; i < size; i++)
- INIT_LIST_HEAD(&hash[i]);
+ INIT_HLIST_HEAD(&hash[i]);
return hash;
}
+EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable);
int set_hashsize(const char *val, struct kernel_param *kp)
{
int i, bucket, hashsize, vmalloced;
int old_vmalloced, old_size;
int rnd;
- struct list_head *hash, *old_hash;
+ struct hlist_head *hash, *old_hash;
struct nf_conntrack_tuple_hash *h;
/* On boot, we can set this without any fancy locking. */
@@ -1186,7 +1036,7 @@ int set_hashsize(const char *val, struct kernel_param *kp)
if (!hashsize)
return -EINVAL;
- hash = alloc_hashtable(hashsize, &vmalloced);
+ hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced);
if (!hash)
return -ENOMEM;
@@ -1196,12 +1046,12 @@ int set_hashsize(const char *val, struct kernel_param *kp)
write_lock_bh(&nf_conntrack_lock);
for (i = 0; i < nf_conntrack_htable_size; i++) {
- while (!list_empty(&nf_conntrack_hash[i])) {
- h = list_entry(nf_conntrack_hash[i].next,
- struct nf_conntrack_tuple_hash, list);
- list_del(&h->list);
+ while (!hlist_empty(&nf_conntrack_hash[i])) {
+ h = hlist_entry(nf_conntrack_hash[i].first,
+ struct nf_conntrack_tuple_hash, hnode);
+ hlist_del(&h->hnode);
bucket = __hash_conntrack(&h->tuple, hashsize, rnd);
- list_add_tail(&h->list, &hash[bucket]);
+ hlist_add_head(&h->hnode, &hash[bucket]);
}
}
old_size = nf_conntrack_htable_size;
@@ -1214,7 +1064,7 @@ int set_hashsize(const char *val, struct kernel_param *kp)
nf_conntrack_hash_rnd = rnd;
write_unlock_bh(&nf_conntrack_lock);
- free_conntrack_hash(old_hash, old_vmalloced, old_size);
+ nf_ct_free_hashtable(old_hash, old_vmalloced, old_size);
return 0;
}
@@ -1223,50 +1073,58 @@ module_param_call(hashsize, set_hashsize, param_get_uint,
int __init nf_conntrack_init(void)
{
+ int max_factor = 8;
int ret;
/* Idea from tcp.c: use 1/16384 of memory. On i386: 32MB
- * machine has 256 buckets. >= 1GB machines have 8192 buckets. */
+ * machine has 512 buckets. >= 1GB machines have 16384 buckets. */
if (!nf_conntrack_htable_size) {
nf_conntrack_htable_size
= (((num_physpages << PAGE_SHIFT) / 16384)
- / sizeof(struct list_head));
+ / sizeof(struct hlist_head));
if (num_physpages > (1024 * 1024 * 1024 / PAGE_SIZE))
- nf_conntrack_htable_size = 8192;
- if (nf_conntrack_htable_size < 16)
- nf_conntrack_htable_size = 16;
+ nf_conntrack_htable_size = 16384;
+ if (nf_conntrack_htable_size < 32)
+ nf_conntrack_htable_size = 32;
+
+ /* Use a max. factor of four by default to get the same max as
+ * with the old struct list_heads. When a table size is given
+ * we use the old value of 8 to avoid reducing the max.
+ * entries. */
+ max_factor = 4;
}
- nf_conntrack_max = 8 * nf_conntrack_htable_size;
-
- printk("nf_conntrack version %s (%u buckets, %d max)\n",
- NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
- nf_conntrack_max);
-
- nf_conntrack_hash = alloc_hashtable(nf_conntrack_htable_size,
- &nf_conntrack_vmalloc);
+ nf_conntrack_hash = nf_ct_alloc_hashtable(&nf_conntrack_htable_size,
+ &nf_conntrack_vmalloc);
if (!nf_conntrack_hash) {
printk(KERN_ERR "Unable to create nf_conntrack_hash\n");
goto err_out;
}
- ret = nf_conntrack_register_cache(NF_CT_F_BASIC, "nf_conntrack:basic",
- sizeof(struct nf_conn));
- if (ret < 0) {
+ nf_conntrack_max = max_factor * nf_conntrack_htable_size;
+
+ printk("nf_conntrack version %s (%u buckets, %d max)\n",
+ NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
+ nf_conntrack_max);
+
+ nf_conntrack_cachep = kmem_cache_create("nf_conntrack",
+ sizeof(struct nf_conn),
+ 0, 0, NULL);
+ if (!nf_conntrack_cachep) {
printk(KERN_ERR "Unable to create nf_conn slab cache\n");
goto err_free_hash;
}
- nf_conntrack_expect_cachep = kmem_cache_create("nf_conntrack_expect",
- sizeof(struct nf_conntrack_expect),
- 0, 0, NULL, NULL);
- if (!nf_conntrack_expect_cachep) {
- printk(KERN_ERR "Unable to create nf_expect slab cache\n");
+ ret = nf_conntrack_proto_init();
+ if (ret < 0)
goto err_free_conntrack_slab;
- }
- ret = nf_conntrack_proto_init();
+ ret = nf_conntrack_expect_init();
+ if (ret < 0)
+ goto out_fini_proto;
+
+ ret = nf_conntrack_helper_init();
if (ret < 0)
- goto out_free_expect_slab;
+ goto out_fini_expect;
/* For use by REJECT target */
rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach);
@@ -1280,13 +1138,15 @@ int __init nf_conntrack_init(void)
return ret;
-out_free_expect_slab:
- kmem_cache_destroy(nf_conntrack_expect_cachep);
+out_fini_expect:
+ nf_conntrack_expect_fini();
+out_fini_proto:
+ nf_conntrack_proto_fini();
err_free_conntrack_slab:
- nf_conntrack_unregister_cache(NF_CT_F_BASIC);
+ kmem_cache_destroy(nf_conntrack_cachep);
err_free_hash:
- free_conntrack_hash(nf_conntrack_hash, nf_conntrack_vmalloc,
- nf_conntrack_htable_size);
+ nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_vmalloc,
+ nf_conntrack_htable_size);
err_out:
return -ENOMEM;
}
diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c
index 6bd421df2dbc..83c41ac3505b 100644
--- a/net/netfilter/nf_conntrack_ecache.c
+++ b/net/netfilter/nf_conntrack_ecache.c
@@ -26,8 +26,8 @@
ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain);
EXPORT_SYMBOL_GPL(nf_conntrack_chain);
-ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain);
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_chain);
+ATOMIC_NOTIFIER_HEAD(nf_ct_expect_chain);
+EXPORT_SYMBOL_GPL(nf_ct_expect_chain);
DEFINE_PER_CPU(struct nf_conntrack_ecache, nf_conntrack_ecache);
EXPORT_PER_CPU_SYMBOL_GPL(nf_conntrack_ecache);
@@ -103,14 +103,14 @@ int nf_conntrack_unregister_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
-int nf_conntrack_expect_register_notifier(struct notifier_block *nb)
+int nf_ct_expect_register_notifier(struct notifier_block *nb)
{
- return atomic_notifier_chain_register(&nf_conntrack_expect_chain, nb);
+ return atomic_notifier_chain_register(&nf_ct_expect_chain, nb);
}
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_register_notifier);
+EXPORT_SYMBOL_GPL(nf_ct_expect_register_notifier);
-int nf_conntrack_expect_unregister_notifier(struct notifier_block *nb)
+int nf_ct_expect_unregister_notifier(struct notifier_block *nb)
{
- return atomic_notifier_chain_unregister(&nf_conntrack_expect_chain, nb);
+ return atomic_notifier_chain_unregister(&nf_ct_expect_chain, nb);
}
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_unregister_notifier);
+EXPORT_SYMBOL_GPL(nf_ct_expect_unregister_notifier);
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 504fb6c083f9..1aa6229ca99f 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -19,6 +19,7 @@
#include <linux/err.h>
#include <linux/percpu.h>
#include <linux/kernel.h>
+#include <linux/jhash.h>
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
@@ -26,11 +27,20 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_tuple.h>
-LIST_HEAD(nf_conntrack_expect_list);
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_list);
+struct hlist_head *nf_ct_expect_hash __read_mostly;
+EXPORT_SYMBOL_GPL(nf_ct_expect_hash);
-struct kmem_cache *nf_conntrack_expect_cachep __read_mostly;
-static unsigned int nf_conntrack_expect_next_id;
+unsigned int nf_ct_expect_hsize __read_mostly;
+EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
+
+static unsigned int nf_ct_expect_hash_rnd __read_mostly;
+static unsigned int nf_ct_expect_count;
+unsigned int nf_ct_expect_max __read_mostly;
+static int nf_ct_expect_hash_rnd_initted __read_mostly;
+static int nf_ct_expect_vmalloc;
+
+static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
+static unsigned int nf_ct_expect_next_id;
/* nf_conntrack_expect helper functions */
void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
@@ -40,60 +50,83 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
NF_CT_ASSERT(master_help);
NF_CT_ASSERT(!timer_pending(&exp->timeout));
- list_del(&exp->list);
- NF_CT_STAT_INC(expect_delete);
+ hlist_del(&exp->hnode);
+ nf_ct_expect_count--;
+
+ hlist_del(&exp->lnode);
master_help->expecting--;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
+
+ NF_CT_STAT_INC(expect_delete);
}
EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
-static void expectation_timed_out(unsigned long ul_expect)
+static void nf_ct_expectation_timed_out(unsigned long ul_expect)
{
struct nf_conntrack_expect *exp = (void *)ul_expect;
write_lock_bh(&nf_conntrack_lock);
nf_ct_unlink_expect(exp);
write_unlock_bh(&nf_conntrack_lock);
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
+}
+
+static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple)
+{
+ if (unlikely(!nf_ct_expect_hash_rnd_initted)) {
+ get_random_bytes(&nf_ct_expect_hash_rnd, 4);
+ nf_ct_expect_hash_rnd_initted = 1;
+ }
+
+ return jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
+ (((tuple->dst.protonum ^ tuple->src.l3num) << 16) |
+ tuple->dst.u.all) ^ nf_ct_expect_hash_rnd) %
+ nf_ct_expect_hsize;
}
struct nf_conntrack_expect *
-__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple)
+__nf_ct_expect_find(const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_expect *i;
+ struct hlist_node *n;
+ unsigned int h;
+
+ if (!nf_ct_expect_count)
+ return NULL;
- list_for_each_entry(i, &nf_conntrack_expect_list, list) {
+ h = nf_ct_expect_dst_hash(tuple);
+ hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
return i;
}
return NULL;
}
-EXPORT_SYMBOL_GPL(__nf_conntrack_expect_find);
+EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
/* Just find a expectation corresponding to a tuple. */
struct nf_conntrack_expect *
-nf_conntrack_expect_find_get(const struct nf_conntrack_tuple *tuple)
+nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_expect *i;
read_lock_bh(&nf_conntrack_lock);
- i = __nf_conntrack_expect_find(tuple);
+ i = __nf_ct_expect_find(tuple);
if (i)
atomic_inc(&i->use);
read_unlock_bh(&nf_conntrack_lock);
return i;
}
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_find_get);
+EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
/* If an expectation for this connection is found, it gets delete from
* global list then returned. */
struct nf_conntrack_expect *
-find_expectation(const struct nf_conntrack_tuple *tuple)
+nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_expect *exp;
- exp = __nf_conntrack_expect_find(tuple);
+ exp = __nf_ct_expect_find(tuple);
if (!exp)
return NULL;
@@ -119,17 +152,18 @@ find_expectation(const struct nf_conntrack_tuple *tuple)
/* delete all expectations for this conntrack */
void nf_ct_remove_expectations(struct nf_conn *ct)
{
- struct nf_conntrack_expect *i, *tmp;
struct nf_conn_help *help = nfct_help(ct);
+ struct nf_conntrack_expect *exp;
+ struct hlist_node *n, *next;
/* Optimization: most connection never expect any others. */
if (!help || help->expecting == 0)
return;
- list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) {
- if (i->master == ct && del_timer(&i->timeout)) {
- nf_ct_unlink_expect(i);
- nf_conntrack_expect_put(i);
+ hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
+ if (del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
}
}
}
@@ -141,25 +175,16 @@ static inline int expect_clash(const struct nf_conntrack_expect *a,
{
/* Part covered by intersection of masks must be unequal,
otherwise they clash */
- struct nf_conntrack_tuple intersect_mask;
+ struct nf_conntrack_tuple_mask intersect_mask;
int count;
- intersect_mask.src.l3num = a->mask.src.l3num & b->mask.src.l3num;
intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
- intersect_mask.dst.u.all = a->mask.dst.u.all & b->mask.dst.u.all;
- intersect_mask.dst.protonum = a->mask.dst.protonum
- & b->mask.dst.protonum;
for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
intersect_mask.src.u3.all[count] =
a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
}
- for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
- intersect_mask.dst.u3.all[count] =
- a->mask.dst.u3.all[count] & b->mask.dst.u3.all[count];
- }
-
return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
}
@@ -168,36 +193,29 @@ static inline int expect_matches(const struct nf_conntrack_expect *a,
{
return a->master == b->master
&& nf_ct_tuple_equal(&a->tuple, &b->tuple)
- && nf_ct_tuple_equal(&a->mask, &b->mask);
+ && nf_ct_tuple_mask_equal(&a->mask, &b->mask);
}
/* Generally a bad idea to call this: could have matched already. */
-void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp)
+void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
{
- struct nf_conntrack_expect *i;
-
write_lock_bh(&nf_conntrack_lock);
- /* choose the oldest expectation to evict */
- list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
- if (expect_matches(i, exp) && del_timer(&i->timeout)) {
- nf_ct_unlink_expect(i);
- write_unlock_bh(&nf_conntrack_lock);
- nf_conntrack_expect_put(i);
- return;
- }
+ if (del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
}
write_unlock_bh(&nf_conntrack_lock);
}
-EXPORT_SYMBOL_GPL(nf_conntrack_unexpect_related);
+EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
/* We don't increase the master conntrack refcount for non-fulfilled
* conntracks. During the conntrack destruction, the expectations are
* always killed before the conntrack itself */
-struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me)
+struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
{
struct nf_conntrack_expect *new;
- new = kmem_cache_alloc(nf_conntrack_expect_cachep, GFP_ATOMIC);
+ new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
if (!new)
return NULL;
@@ -205,12 +223,12 @@ struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me)
atomic_set(&new->use, 1);
return new;
}
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_alloc);
+EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
-void nf_conntrack_expect_init(struct nf_conntrack_expect *exp, int family,
- union nf_conntrack_address *saddr,
- union nf_conntrack_address *daddr,
- u_int8_t proto, __be16 *src, __be16 *dst)
+void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
+ union nf_conntrack_address *saddr,
+ union nf_conntrack_address *daddr,
+ u_int8_t proto, __be16 *src, __be16 *dst)
{
int len;
@@ -224,8 +242,6 @@ void nf_conntrack_expect_init(struct nf_conntrack_expect *exp, int family,
exp->helper = NULL;
exp->tuple.src.l3num = family;
exp->tuple.dst.protonum = proto;
- exp->mask.src.l3num = 0xFFFF;
- exp->mask.dst.protonum = 0xFF;
if (saddr) {
memcpy(&exp->tuple.src.u3, saddr, len);
@@ -242,21 +258,6 @@ void nf_conntrack_expect_init(struct nf_conntrack_expect *exp, int family,
memset(&exp->mask.src.u3, 0x00, sizeof(exp->mask.src.u3));
}
- if (daddr) {
- memcpy(&exp->tuple.dst.u3, daddr, len);
- if (sizeof(exp->tuple.dst.u3) > len)
- /* address needs to be cleared for nf_ct_tuple_equal */
- memset((void *)&exp->tuple.dst.u3 + len, 0x00,
- sizeof(exp->tuple.dst.u3) - len);
- memset(&exp->mask.dst.u3, 0xFF, len);
- if (sizeof(exp->mask.dst.u3) > len)
- memset((void *)&exp->mask.dst.u3 + len, 0x00,
- sizeof(exp->mask.dst.u3) - len);
- } else {
- memset(&exp->tuple.dst.u3, 0x00, sizeof(exp->tuple.dst.u3));
- memset(&exp->mask.dst.u3, 0x00, sizeof(exp->mask.dst.u3));
- }
-
if (src) {
exp->tuple.src.u.all = (__force u16)*src;
exp->mask.src.u.all = 0xFFFF;
@@ -265,36 +266,42 @@ void nf_conntrack_expect_init(struct nf_conntrack_expect *exp, int family,
exp->mask.src.u.all = 0;
}
- if (dst) {
- exp->tuple.dst.u.all = (__force u16)*dst;
- exp->mask.dst.u.all = 0xFFFF;
- } else {
- exp->tuple.dst.u.all = 0;
- exp->mask.dst.u.all = 0;
- }
+ memcpy(&exp->tuple.dst.u3, daddr, len);
+ if (sizeof(exp->tuple.dst.u3) > len)
+ /* address needs to be cleared for nf_ct_tuple_equal */
+ memset((void *)&exp->tuple.dst.u3 + len, 0x00,
+ sizeof(exp->tuple.dst.u3) - len);
+
+ exp->tuple.dst.u.all = (__force u16)*dst;
}
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_init);
+EXPORT_SYMBOL_GPL(nf_ct_expect_init);
-void nf_conntrack_expect_put(struct nf_conntrack_expect *exp)
+void nf_ct_expect_put(struct nf_conntrack_expect *exp)
{
if (atomic_dec_and_test(&exp->use))
- kmem_cache_free(nf_conntrack_expect_cachep, exp);
+ kmem_cache_free(nf_ct_expect_cachep, exp);
}
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_put);
+EXPORT_SYMBOL_GPL(nf_ct_expect_put);
-static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
+static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
{
struct nf_conn_help *master_help = nfct_help(exp->master);
+ unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
atomic_inc(&exp->use);
+
+ hlist_add_head(&exp->lnode, &master_help->expectations);
master_help->expecting++;
- list_add(&exp->list, &nf_conntrack_expect_list);
- setup_timer(&exp->timeout, expectation_timed_out, (unsigned long)exp);
+ hlist_add_head(&exp->hnode, &nf_ct_expect_hash[h]);
+ nf_ct_expect_count++;
+
+ setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
+ (unsigned long)exp);
exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
add_timer(&exp->timeout);
- exp->id = ++nf_conntrack_expect_next_id;
+ exp->id = ++nf_ct_expect_next_id;
atomic_inc(&exp->use);
NF_CT_STAT_INC(expect_create);
}
@@ -302,16 +309,16 @@ static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp)
/* Race with expectations being used means we could have none to find; OK. */
static void evict_oldest_expect(struct nf_conn *master)
{
- struct nf_conntrack_expect *i;
+ struct nf_conn_help *master_help = nfct_help(master);
+ struct nf_conntrack_expect *exp = NULL;
+ struct hlist_node *n;
- list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) {
- if (i->master == master) {
- if (del_timer(&i->timeout)) {
- nf_ct_unlink_expect(i);
- nf_conntrack_expect_put(i);
- }
- break;
- }
+ hlist_for_each_entry(exp, n, &master_help->expectations, lnode)
+ ; /* nothing */
+
+ if (exp && del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
}
}
@@ -327,11 +334,13 @@ static inline int refresh_timer(struct nf_conntrack_expect *i)
return 1;
}
-int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
+int nf_ct_expect_related(struct nf_conntrack_expect *expect)
{
struct nf_conntrack_expect *i;
struct nf_conn *master = expect->master;
struct nf_conn_help *master_help = nfct_help(master);
+ struct hlist_node *n;
+ unsigned int h;
int ret;
NF_CT_ASSERT(master_help);
@@ -341,7 +350,8 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
ret = -ESHUTDOWN;
goto out;
}
- list_for_each_entry(i, &nf_conntrack_expect_list, list) {
+ h = nf_ct_expect_dst_hash(&expect->tuple);
+ hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) {
if (expect_matches(i, expect)) {
/* Refresh timer: if it's dying, ignore.. */
if (refresh_timer(i)) {
@@ -358,57 +368,86 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect)
master_help->expecting >= master_help->helper->max_expected)
evict_oldest_expect(master);
- nf_conntrack_expect_insert(expect);
- nf_conntrack_expect_event(IPEXP_NEW, expect);
+ if (nf_ct_expect_count >= nf_ct_expect_max) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "nf_conntrack: expectation table full");
+ ret = -EMFILE;
+ goto out;
+ }
+
+ nf_ct_expect_insert(expect);
+ nf_ct_expect_event(IPEXP_NEW, expect);
ret = 0;
out:
write_unlock_bh(&nf_conntrack_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(nf_conntrack_expect_related);
+EXPORT_SYMBOL_GPL(nf_ct_expect_related);
#ifdef CONFIG_PROC_FS
-static void *exp_seq_start(struct seq_file *s, loff_t *pos)
+struct ct_expect_iter_state {
+ unsigned int bucket;
+};
+
+static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
{
- struct list_head *e = &nf_conntrack_expect_list;
- loff_t i;
+ struct ct_expect_iter_state *st = seq->private;
- /* strange seq_file api calls stop even if we fail,
- * thus we need to grab lock since stop unlocks */
- read_lock_bh(&nf_conntrack_lock);
+ for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
+ if (!hlist_empty(&nf_ct_expect_hash[st->bucket]))
+ return nf_ct_expect_hash[st->bucket].first;
+ }
+ return NULL;
+}
- if (list_empty(e))
- return NULL;
+static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
+ struct hlist_node *head)
+{
+ struct ct_expect_iter_state *st = seq->private;
- for (i = 0; i <= *pos; i++) {
- e = e->next;
- if (e == &nf_conntrack_expect_list)
+ head = head->next;
+ while (head == NULL) {
+ if (++st->bucket >= nf_ct_expect_hsize)
return NULL;
+ head = nf_ct_expect_hash[st->bucket].first;
}
- return e;
+ return head;
}
-static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
+static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
{
- struct list_head *e = v;
+ struct hlist_node *head = ct_expect_get_first(seq);
- ++*pos;
- e = e->next;
+ if (head)
+ while (pos && (head = ct_expect_get_next(seq, head)))
+ pos--;
+ return pos ? NULL : head;
+}
- if (e == &nf_conntrack_expect_list)
- return NULL;
+static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ read_lock_bh(&nf_conntrack_lock);
+ return ct_expect_get_idx(seq, *pos);
+}
- return e;
+static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return ct_expect_get_next(seq, v);
}
-static void exp_seq_stop(struct seq_file *s, void *v)
+static void exp_seq_stop(struct seq_file *seq, void *v)
{
read_unlock_bh(&nf_conntrack_lock);
}
static int exp_seq_show(struct seq_file *s, void *v)
{
- struct nf_conntrack_expect *expect = v;
+ struct nf_conntrack_expect *expect;
+ struct hlist_node *n = v;
+
+ expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
if (expect->timeout.function)
seq_printf(s, "%ld ", timer_pending(&expect->timeout)
@@ -425,7 +464,7 @@ static int exp_seq_show(struct seq_file *s, void *v)
return seq_putc(s, '\n');
}
-static struct seq_operations exp_seq_ops = {
+static const struct seq_operations exp_seq_ops = {
.start = exp_seq_start,
.next = exp_seq_next,
.stop = exp_seq_stop,
@@ -434,14 +473,96 @@ static struct seq_operations exp_seq_ops = {
static int exp_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &exp_seq_ops);
+ struct seq_file *seq;
+ struct ct_expect_iter_state *st;
+ int ret;
+
+ st = kmalloc(sizeof(struct ct_expect_iter_state), GFP_KERNEL);
+ if (st == NULL)
+ return -ENOMEM;
+ ret = seq_open(file, &exp_seq_ops);
+ if (ret)
+ goto out_free;
+ seq = file->private_data;
+ seq->private = st;
+ memset(st, 0, sizeof(struct ct_expect_iter_state));
+ return ret;
+out_free:
+ kfree(st);
+ return ret;
}
-const struct file_operations exp_file_ops = {
+static const struct file_operations exp_file_ops = {
.owner = THIS_MODULE,
.open = exp_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release
+ .release = seq_release_private,
};
#endif /* CONFIG_PROC_FS */
+
+static int __init exp_proc_init(void)
+{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc;
+
+ proc = proc_net_fops_create("nf_conntrack_expect", 0440, &exp_file_ops);
+ if (!proc)
+ return -ENOMEM;
+#endif /* CONFIG_PROC_FS */
+ return 0;
+}
+
+static void exp_proc_remove(void)
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_remove("nf_conntrack_expect");
+#endif /* CONFIG_PROC_FS */
+}
+
+module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0600);
+
+int __init nf_conntrack_expect_init(void)
+{
+ int err = -ENOMEM;
+
+ if (!nf_ct_expect_hsize) {
+ nf_ct_expect_hsize = nf_conntrack_htable_size / 256;
+ if (!nf_ct_expect_hsize)
+ nf_ct_expect_hsize = 1;
+ }
+ nf_ct_expect_max = nf_ct_expect_hsize * 4;
+
+ nf_ct_expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize,
+ &nf_ct_expect_vmalloc);
+ if (nf_ct_expect_hash == NULL)
+ goto err1;
+
+ nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
+ sizeof(struct nf_conntrack_expect),
+ 0, 0, NULL);
+ if (!nf_ct_expect_cachep)
+ goto err2;
+
+ err = exp_proc_init();
+ if (err < 0)
+ goto err3;
+
+ return 0;
+
+err3:
+ nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_vmalloc,
+ nf_ct_expect_hsize);
+err2:
+ kmem_cache_destroy(nf_ct_expect_cachep);
+err1:
+ return err;
+}
+
+void nf_conntrack_expect_fini(void)
+{
+ exp_proc_remove();
+ kmem_cache_destroy(nf_ct_expect_cachep);
+ nf_ct_free_hashtable(nf_ct_expect_hash, nf_ct_expect_vmalloc,
+ nf_ct_expect_hsize);
+}
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
new file mode 100644
index 000000000000..a1a65a1313b3
--- /dev/null
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -0,0 +1,195 @@
+/* Structure dynamic extension infrastructure
+ * Copyright (C) 2004 Rusty Russell IBM Corporation
+ * Copyright (C) 2007 Netfilter Core Team <coreteam@netfilter.org>
+ * Copyright (C) 2007 USAGI/WIDE Project <http://www.linux-ipv6.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/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rcupdate.h>
+#include <linux/slab.h>
+#include <linux/skbuff.h>
+#include <net/netfilter/nf_conntrack_extend.h>
+
+static struct nf_ct_ext_type *nf_ct_ext_types[NF_CT_EXT_NUM];
+static DEFINE_MUTEX(nf_ct_ext_type_mutex);
+
+/* Horrible trick to figure out smallest amount worth kmallocing. */
+#define CACHE(x) (x) + 0 *
+enum {
+ NF_CT_EXT_MIN_SIZE =
+#include <linux/kmalloc_sizes.h>
+ 1 };
+#undef CACHE
+
+void __nf_ct_ext_destroy(struct nf_conn *ct)
+{
+ unsigned int i;
+ struct nf_ct_ext_type *t;
+
+ for (i = 0; i < NF_CT_EXT_NUM; i++) {
+ if (!nf_ct_ext_exist(ct, i))
+ continue;
+
+ rcu_read_lock();
+ t = rcu_dereference(nf_ct_ext_types[i]);
+
+ /* Here the nf_ct_ext_type might have been unregisterd.
+ * I.e., it has responsible to cleanup private
+ * area in all conntracks when it is unregisterd.
+ */
+ if (t && t->destroy)
+ t->destroy(ct);
+ rcu_read_unlock();
+ }
+}
+EXPORT_SYMBOL(__nf_ct_ext_destroy);
+
+static void *
+nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
+{
+ unsigned int off, len, real_len;
+ struct nf_ct_ext_type *t;
+
+ rcu_read_lock();
+ t = rcu_dereference(nf_ct_ext_types[id]);
+ BUG_ON(t == NULL);
+ off = ALIGN(sizeof(struct nf_ct_ext), t->align);
+ len = off + t->len;
+ real_len = t->alloc_size;
+ rcu_read_unlock();
+
+ *ext = kzalloc(real_len, gfp);
+ if (!*ext)
+ return NULL;
+
+ (*ext)->offset[id] = off;
+ (*ext)->len = len;
+ (*ext)->real_len = real_len;
+
+ return (void *)(*ext) + off;
+}
+
+void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
+{
+ struct nf_ct_ext *new;
+ int i, newlen, newoff;
+ struct nf_ct_ext_type *t;
+
+ if (!ct->ext)
+ return nf_ct_ext_create(&ct->ext, id, gfp);
+
+ if (nf_ct_ext_exist(ct, id))
+ return NULL;
+
+ rcu_read_lock();
+ t = rcu_dereference(nf_ct_ext_types[id]);
+ BUG_ON(t == NULL);
+
+ newoff = ALIGN(ct->ext->len, t->align);
+ newlen = newoff + t->len;
+ rcu_read_unlock();
+
+ if (newlen >= ct->ext->real_len) {
+ new = kmalloc(newlen, gfp);
+ if (!new)
+ return NULL;
+
+ memcpy(new, ct->ext, ct->ext->len);
+
+ for (i = 0; i < NF_CT_EXT_NUM; i++) {
+ if (!nf_ct_ext_exist(ct, i))
+ continue;
+
+ rcu_read_lock();
+ t = rcu_dereference(nf_ct_ext_types[i]);
+ if (t && t->move)
+ t->move(ct, ct->ext + ct->ext->offset[id]);
+ rcu_read_unlock();
+ }
+ kfree(ct->ext);
+ new->real_len = newlen;
+ ct->ext = new;
+ }
+
+ ct->ext->offset[id] = newoff;
+ ct->ext->len = newlen;
+ memset((void *)ct->ext + newoff, 0, newlen - newoff);
+ return (void *)ct->ext + newoff;
+}
+EXPORT_SYMBOL(__nf_ct_ext_add);
+
+static void update_alloc_size(struct nf_ct_ext_type *type)
+{
+ int i, j;
+ struct nf_ct_ext_type *t1, *t2;
+ enum nf_ct_ext_id min = 0, max = NF_CT_EXT_NUM - 1;
+
+ /* unnecessary to update all types */
+ if ((type->flags & NF_CT_EXT_F_PREALLOC) == 0) {
+ min = type->id;
+ max = type->id;
+ }
+
+ /* This assumes that extended areas in conntrack for the types
+ whose NF_CT_EXT_F_PREALLOC bit set are allocated in order */
+ for (i = min; i <= max; i++) {
+ t1 = nf_ct_ext_types[i];
+ if (!t1)
+ continue;
+
+ t1->alloc_size = sizeof(struct nf_ct_ext)
+ + ALIGN(sizeof(struct nf_ct_ext), t1->align)
+ + t1->len;
+ for (j = 0; j < NF_CT_EXT_NUM; j++) {
+ t2 = nf_ct_ext_types[j];
+ if (t2 == NULL || t2 == t1 ||
+ (t2->flags & NF_CT_EXT_F_PREALLOC) == 0)
+ continue;
+
+ t1->alloc_size = ALIGN(t1->alloc_size, t2->align)
+ + t2->len;
+ }
+ if (t1->alloc_size < NF_CT_EXT_MIN_SIZE)
+ t1->alloc_size = NF_CT_EXT_MIN_SIZE;
+ }
+}
+
+/* This MUST be called in process context. */
+int nf_ct_extend_register(struct nf_ct_ext_type *type)
+{
+ int ret = 0;
+
+ mutex_lock(&nf_ct_ext_type_mutex);
+ if (nf_ct_ext_types[type->id]) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* This ensures that nf_ct_ext_create() can allocate enough area
+ before updating alloc_size */
+ type->alloc_size = ALIGN(sizeof(struct nf_ct_ext), type->align)
+ + type->len;
+ rcu_assign_pointer(nf_ct_ext_types[type->id], type);
+ update_alloc_size(type);
+out:
+ mutex_unlock(&nf_ct_ext_type_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(nf_ct_extend_register);
+
+/* This MUST be called in process context. */
+void nf_ct_extend_unregister(struct nf_ct_ext_type *type)
+{
+ mutex_lock(&nf_ct_ext_type_mutex);
+ rcu_assign_pointer(nf_ct_ext_types[type->id], NULL);
+ update_alloc_size(type);
+ mutex_unlock(&nf_ct_ext_type_mutex);
+ synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index 82db2aa53bfc..c763ee74ea02 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -51,12 +51,6 @@ unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb,
struct nf_conntrack_expect *exp);
EXPORT_SYMBOL_GPL(nf_nat_ftp_hook);
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
static int try_rfc959(const char *, size_t, struct nf_conntrack_man *, char);
static int try_eprt(const char *, size_t, struct nf_conntrack_man *, char);
static int try_epsv_response(const char *, size_t, struct nf_conntrack_man *,
@@ -138,13 +132,13 @@ static int try_number(const char *data, size_t dlen, u_int32_t array[],
if (*data == term && i == array_size - 1)
return len;
- DEBUGP("Char %u (got %u nums) `%u' unexpected\n",
- len, i, *data);
+ pr_debug("Char %u (got %u nums) `%u' unexpected\n",
+ len, i, *data);
return 0;
}
}
- DEBUGP("Failed to fill %u numbers separated by %c\n", array_size, sep);
-
+ pr_debug("Failed to fill %u numbers separated by %c\n",
+ array_size, sep);
return 0;
}
@@ -178,13 +172,13 @@ static int get_port(const char *data, int start, size_t dlen, char delim,
if (tmp_port == 0)
break;
*port = htons(tmp_port);
- DEBUGP("get_port: return %d\n", tmp_port);
+ pr_debug("get_port: return %d\n", tmp_port);
return i + 1;
}
else if (data[i] >= '0' && data[i] <= '9')
tmp_port = tmp_port*10 + data[i] - '0';
else { /* Some other crap */
- DEBUGP("get_port: invalid char.\n");
+ pr_debug("get_port: invalid char.\n");
break;
}
}
@@ -201,22 +195,22 @@ static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd,
/* First character is delimiter, then "1" for IPv4 or "2" for IPv6,
then delimiter again. */
if (dlen <= 3) {
- DEBUGP("EPRT: too short\n");
+ pr_debug("EPRT: too short\n");
return 0;
}
delim = data[0];
if (isdigit(delim) || delim < 33 || delim > 126 || data[2] != delim) {
- DEBUGP("try_eprt: invalid delimitter.\n");
+ pr_debug("try_eprt: invalid delimitter.\n");
return 0;
}
if ((cmd->l3num == PF_INET && data[1] != '1') ||
(cmd->l3num == PF_INET6 && data[1] != '2')) {
- DEBUGP("EPRT: invalid protocol number.\n");
+ pr_debug("EPRT: invalid protocol number.\n");
return 0;
}
- DEBUGP("EPRT: Got %c%c%c\n", delim, data[1], delim);
+ pr_debug("EPRT: Got %c%c%c\n", delim, data[1], delim);
if (data[1] == '1') {
u_int32_t array[4];
@@ -234,7 +228,7 @@ static int try_eprt(const char *data, size_t dlen, struct nf_conntrack_man *cmd,
if (length == 0)
return 0;
- DEBUGP("EPRT: Got IP address!\n");
+ pr_debug("EPRT: Got IP address!\n");
/* Start offset includes initial "|1|", and trailing delimiter */
return get_port(data, 3 + length + 1, dlen, delim, &cmd->u.tcp.port);
}
@@ -267,7 +261,7 @@ static int find_pattern(const char *data, size_t dlen,
{
size_t i;
- DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
+ pr_debug("find_pattern `%s': dlen = %Zu\n", pattern, dlen);
if (dlen == 0)
return 0;
@@ -282,17 +276,17 @@ static int find_pattern(const char *data, size_t dlen,
#if 0
size_t i;
- DEBUGP("ftp: string mismatch\n");
+ pr_debug("ftp: string mismatch\n");
for (i = 0; i < plen; i++) {
- DEBUGP("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
- i, data[i], data[i],
- pattern[i], pattern[i]);
+ pr_debug("ftp:char %u `%c'(%u) vs `%c'(%u)\n",
+ i, data[i], data[i],
+ pattern[i], pattern[i]);
}
#endif
return 0;
}
- DEBUGP("Pattern matches!\n");
+ pr_debug("Pattern matches!\n");
/* Now we've found the constant string, try to skip
to the 'skip' character */
for (i = plen; data[i] != skip; i++)
@@ -301,14 +295,14 @@ static int find_pattern(const char *data, size_t dlen,
/* Skip over the last character */
i++;
- DEBUGP("Skipped up to `%c'!\n", skip);
+ pr_debug("Skipped up to `%c'!\n", skip);
*numoff = i;
*numlen = getnum(data + i, dlen - i, cmd, term);
if (!*numlen)
return -1;
- DEBUGP("Match succeeded!\n");
+ pr_debug("Match succeeded!\n");
return 1;
}
@@ -364,6 +358,7 @@ static int help(struct sk_buff **pskb,
unsigned int matchlen, matchoff;
struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info;
struct nf_conntrack_expect *exp;
+ union nf_conntrack_address *daddr;
struct nf_conntrack_man cmd = {};
unsigned int i;
int found = 0, ends_in_nl;
@@ -372,7 +367,7 @@ static int help(struct sk_buff **pskb,
/* Until there's been traffic both ways, don't look in packets. */
if (ctinfo != IP_CT_ESTABLISHED
&& ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) {
- DEBUGP("ftp: Conntrackinfo = %u\n", ctinfo);
+ pr_debug("ftp: Conntrackinfo = %u\n", ctinfo);
return NF_ACCEPT;
}
@@ -383,8 +378,8 @@ static int help(struct sk_buff **pskb,
dataoff = protoff + th->doff * 4;
/* No data? */
if (dataoff >= (*pskb)->len) {
- DEBUGP("ftp: dataoff(%u) >= skblen(%u)\n", dataoff,
- (*pskb)->len);
+ pr_debug("ftp: dataoff(%u) >= skblen(%u)\n", dataoff,
+ (*pskb)->len);
return NF_ACCEPT;
}
datalen = (*pskb)->len - dataoff;
@@ -399,11 +394,11 @@ static int help(struct sk_buff **pskb,
/* Look up to see if we're just after a \n. */
if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) {
/* Now if this ends in \n, update ftp info. */
- DEBUGP("nf_conntrack_ftp_help: wrong seq pos %s(%u) or %s(%u)\n",
- ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)",
- ct_ftp_info->seq_aft_nl[dir][0],
- ct_ftp_info->seq_aft_nl_num[dir] > 1 ? "" : "(UNSET)",
- ct_ftp_info->seq_aft_nl[dir][1]);
+ pr_debug("nf_conntrack_ftp: wrong seq pos %s(%u) or %s(%u)\n",
+ ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)",
+ ct_ftp_info->seq_aft_nl[dir][0],
+ ct_ftp_info->seq_aft_nl_num[dir] > 1 ? "" : "(UNSET)",
+ ct_ftp_info->seq_aft_nl[dir][1]);
ret = NF_ACCEPT;
goto out_update_nl;
}
@@ -441,11 +436,11 @@ static int help(struct sk_buff **pskb,
goto out_update_nl;
}
- DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
- (int)matchlen, fb_ptr + matchoff,
- matchlen, ntohl(th->seq) + matchoff);
+ pr_debug("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
+ matchlen, fb_ptr + matchoff,
+ matchlen, ntohl(th->seq) + matchoff);
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (exp == NULL) {
ret = NF_DROP;
goto out;
@@ -454,7 +449,7 @@ static int help(struct sk_buff **pskb,
/* We refer to the reverse direction ("!dir") tuples here,
* because we're expecting something in the other direction.
* Doesn't matter unless NAT is happening. */
- exp->tuple.dst.u3 = ct->tuplehash[!dir].tuple.dst.u3;
+ daddr = &ct->tuplehash[!dir].tuple.dst.u3;
/* Update the ftp info */
if ((cmd.l3num == ct->tuplehash[dir].tuple.src.l3num) &&
@@ -465,14 +460,16 @@ static int help(struct sk_buff **pskb,
different IP address. Simply don't record it for
NAT. */
if (cmd.l3num == PF_INET) {
- DEBUGP("conntrack_ftp: NOT RECORDING: " NIPQUAD_FMT " != " NIPQUAD_FMT "\n",
- NIPQUAD(cmd.u3.ip),
- NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip));
+ pr_debug("conntrack_ftp: NOT RECORDING: " NIPQUAD_FMT
+ " != " NIPQUAD_FMT "\n",
+ NIPQUAD(cmd.u3.ip),
+ NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip));
} else {
- DEBUGP("conntrack_ftp: NOT RECORDING: " NIP6_FMT " != " NIP6_FMT "\n",
- NIP6(*((struct in6_addr *)cmd.u3.ip6)),
- NIP6(*((struct in6_addr *)ct->tuplehash[dir]
- .tuple.src.u3.ip6)));
+ pr_debug("conntrack_ftp: NOT RECORDING: " NIP6_FMT
+ " != " NIP6_FMT "\n",
+ NIP6(*((struct in6_addr *)cmd.u3.ip6)),
+ NIP6(*((struct in6_addr *)
+ ct->tuplehash[dir].tuple.src.u3.ip6)));
}
/* Thanks to Cristiano Lincoln Mattos
@@ -483,37 +480,12 @@ static int help(struct sk_buff **pskb,
ret = NF_ACCEPT;
goto out_put_expect;
}
- memcpy(&exp->tuple.dst.u3, &cmd.u3.all,
- sizeof(exp->tuple.dst.u3));
- }
-
- exp->tuple.src.u3 = ct->tuplehash[!dir].tuple.src.u3;
- exp->tuple.src.l3num = cmd.l3num;
- exp->tuple.src.u.tcp.port = 0;
- exp->tuple.dst.u.tcp.port = cmd.u.tcp.port;
- exp->tuple.dst.protonum = IPPROTO_TCP;
-
- exp->mask = (struct nf_conntrack_tuple)
- { .src = { .l3num = 0xFFFF,
- .u = { .tcp = { 0 }},
- },
- .dst = { .protonum = 0xFF,
- .u = { .tcp = { __constant_htons(0xFFFF) }},
- },
- };
- if (cmd.l3num == PF_INET) {
- exp->mask.src.u3.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u3.ip = htonl(0xFFFFFFFF);
- } else {
- memset(exp->mask.src.u3.ip6, 0xFF,
- sizeof(exp->mask.src.u3.ip6));
- memset(exp->mask.dst.u3.ip6, 0xFF,
- sizeof(exp->mask.src.u3.ip6));
+ daddr = &cmd.u3;
}
- exp->expectfn = NULL;
- exp->helper = NULL;
- exp->flags = 0;
+ nf_ct_expect_init(exp, cmd.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3, daddr,
+ IPPROTO_TCP, NULL, &cmd.u.tcp.port);
/* Now, NAT might want to mangle the packet, and register the
* (possibly changed) expectation itself. */
@@ -523,14 +495,14 @@ static int help(struct sk_buff **pskb,
matchoff, matchlen, exp);
else {
/* Can't expect this? Best to drop packet now. */
- if (nf_conntrack_expect_related(exp) != 0)
+ if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
else
ret = NF_ACCEPT;
}
out_put_expect:
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
out_update_nl:
/* Now if this ends in \n, update ftp info. Seq may have been
@@ -542,8 +514,8 @@ out_update_nl:
return ret;
}
-static struct nf_conntrack_helper ftp[MAX_PORTS][2];
-static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")];
+static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly;
+static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")] __read_mostly;
/* don't make this __exit, since it's called from __init ! */
static void nf_conntrack_ftp_fini(void)
@@ -554,9 +526,9 @@ static void nf_conntrack_ftp_fini(void)
if (ftp[i][j].me == NULL)
continue;
- DEBUGP("nf_ct_ftp: unregistering helper for pf: %d "
- "port: %d\n",
- ftp[i][j].tuple.src.l3num, ports[i]);
+ pr_debug("nf_ct_ftp: unregistering helper for pf: %d "
+ "port: %d\n",
+ ftp[i][j].tuple.src.l3num, ports[i]);
nf_conntrack_helper_unregister(&ftp[i][j]);
}
}
@@ -584,9 +556,6 @@ static int __init nf_conntrack_ftp_init(void)
for (j = 0; j < 2; j++) {
ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]);
ftp[i][j].tuple.dst.protonum = IPPROTO_TCP;
- ftp[i][j].mask.src.l3num = 0xFFFF;
- ftp[i][j].mask.src.u.tcp.port = htons(0xFFFF);
- ftp[i][j].mask.dst.protonum = 0xFF;
ftp[i][j].max_expected = 1;
ftp[i][j].timeout = 5 * 60; /* 5 Minutes */
ftp[i][j].me = THIS_MODULE;
@@ -598,9 +567,9 @@ static int __init nf_conntrack_ftp_init(void)
sprintf(tmpname, "ftp-%d", ports[i]);
ftp[i][j].name = tmpname;
- DEBUGP("nf_ct_ftp: registering helper for pf: %d "
- "port: %d\n",
- ftp[i][j].tuple.src.l3num, ports[i]);
+ pr_debug("nf_ct_ftp: registering helper for pf: %d "
+ "port: %d\n",
+ ftp[i][j].tuple.src.l3num, ports[i]);
ret = nf_conntrack_helper_register(&ftp[i][j]);
if (ret) {
printk("nf_ct_ftp: failed to register helper "
diff --git a/net/netfilter/nf_conntrack_h323_asn1.c b/net/netfilter/nf_conntrack_h323_asn1.c
index 6b7eaa019d4c..a869403b2294 100644
--- a/net/netfilter/nf_conntrack_h323_asn1.c
+++ b/net/netfilter/nf_conntrack_h323_asn1.c
@@ -555,15 +555,6 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
/* Decode the extension components */
for (opt = 0; opt < bmp2_len; opt++, i++, son++) {
- if (i < f->ub && son->attr & STOP) {
- PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
- son->name);
- return H323_ERROR_STOP;
- }
-
- if (!((0x80000000 >> opt) & bmp2)) /* Not present */
- continue;
-
/* Check Range */
if (i >= f->ub) { /* Newer Version? */
CHECK_BOUND(bs, 2);
@@ -573,6 +564,15 @@ int decode_seq(bitstr_t * bs, field_t * f, char *base, int level)
continue;
}
+ if (son->attr & STOP) {
+ PRINT("%*.s%s\n", (level + 1) * TAB_SIZE, " ",
+ son->name);
+ return H323_ERROR_STOP;
+ }
+
+ if (!((0x80000000 >> opt) & bmp2)) /* Not present */
+ continue;
+
CHECK_BOUND(bs, 2);
len = get_len(bs);
CHECK_BOUND(bs, len);
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index a1b95acad297..a8a9dfbe7a67 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -31,12 +31,6 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <linux/netfilter/nf_conntrack_h323.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Parameters */
static unsigned int default_rrq_ttl __read_mostly = 300;
module_param(default_rrq_ttl, uint, 0600);
@@ -150,9 +144,9 @@ static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff,
if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) {
/* Netmeeting sends TPKT header and data separately */
if (info->tpkt_len[dir] > 0) {
- DEBUGP("nf_ct_h323: previous packet "
- "indicated separate TPKT data of %hu "
- "bytes\n", info->tpkt_len[dir]);
+ pr_debug("nf_ct_h323: previous packet "
+ "indicated separate TPKT data of %hu "
+ "bytes\n", info->tpkt_len[dir]);
if (info->tpkt_len[dir] <= tcpdatalen) {
/* Yes, there was a TPKT header
* received */
@@ -163,9 +157,7 @@ static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff,
}
/* Fragmented TPKT */
- if (net_ratelimit())
- printk("nf_ct_h323: "
- "fragmented TPKT\n");
+ pr_debug("nf_ct_h323: fragmented TPKT\n");
goto clear_out;
}
@@ -192,9 +184,9 @@ static int get_tpkt_data(struct sk_buff **pskb, unsigned int protoff,
if (tpktlen > tcpdatalen) {
if (tcpdatalen == 4) { /* Separate TPKT header */
/* Netmeeting sends TPKT header and data separately */
- DEBUGP("nf_ct_h323: separate TPKT header indicates "
- "there will be TPKT data of %hu bytes\n",
- tpktlen - 4);
+ pr_debug("nf_ct_h323: separate TPKT header indicates "
+ "there will be TPKT data of %hu bytes\n",
+ tpktlen - 4);
info->tpkt_len[dir] = tpktlen - 4;
return 0;
}
@@ -282,22 +274,22 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
rtcp_port = htons(ntohs(port) + 1);
/* Create expect for RTP */
- if ((rtp_exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3,
- &ct->tuplehash[!dir].tuple.dst.u3,
- IPPROTO_UDP, NULL, &rtp_port);
+ nf_ct_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_UDP, NULL, &rtp_port);
/* Create expect for RTCP */
- if ((rtcp_exp = nf_conntrack_expect_alloc(ct)) == NULL) {
- nf_conntrack_expect_put(rtp_exp);
+ if ((rtcp_exp = nf_ct_expect_alloc(ct)) == NULL) {
+ nf_ct_expect_put(rtp_exp);
return -1;
}
- nf_conntrack_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3,
- &ct->tuplehash[!dir].tuple.dst.u3,
- IPPROTO_UDP, NULL, &rtcp_port);
+ nf_ct_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_UDP, NULL, &rtcp_port);
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
&ct->tuplehash[!dir].tuple.dst.u3,
@@ -308,22 +300,22 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct nf_conn *ct,
ret = nat_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
taddr, port, rtp_port, rtp_exp, rtcp_exp);
} else { /* Conntrack only */
- if (nf_conntrack_expect_related(rtp_exp) == 0) {
- if (nf_conntrack_expect_related(rtcp_exp) == 0) {
- DEBUGP("nf_ct_h323: expect RTP ");
+ if (nf_ct_expect_related(rtp_exp) == 0) {
+ if (nf_ct_expect_related(rtcp_exp) == 0) {
+ pr_debug("nf_ct_h323: expect RTP ");
NF_CT_DUMP_TUPLE(&rtp_exp->tuple);
- DEBUGP("nf_ct_h323: expect RTCP ");
+ pr_debug("nf_ct_h323: expect RTCP ");
NF_CT_DUMP_TUPLE(&rtcp_exp->tuple);
} else {
- nf_conntrack_unexpect_related(rtp_exp);
+ nf_ct_unexpect_related(rtp_exp);
ret = -1;
}
} else
ret = -1;
}
- nf_conntrack_expect_put(rtp_exp);
- nf_conntrack_expect_put(rtcp_exp);
+ nf_ct_expect_put(rtp_exp);
+ nf_ct_expect_put(rtcp_exp);
return ret;
}
@@ -349,12 +341,12 @@ static int expect_t120(struct sk_buff **pskb,
return 0;
/* Create expect for T.120 connections */
- if ((exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3,
- &ct->tuplehash[!dir].tuple.dst.u3,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple channels */
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
@@ -366,14 +358,14 @@ static int expect_t120(struct sk_buff **pskb,
ret = nat_t120(pskb, ct, ctinfo, data, dataoff, taddr,
port, exp);
} else { /* Conntrack only */
- if (nf_conntrack_expect_related(exp) == 0) {
- DEBUGP("nf_ct_h323: expect T.120 ");
+ if (nf_ct_expect_related(exp) == 0) {
+ pr_debug("nf_ct_h323: expect T.120 ");
NF_CT_DUMP_TUPLE(&exp->tuple);
} else
ret = -1;
}
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return ret;
}
@@ -415,7 +407,7 @@ static int process_olc(struct sk_buff **pskb, struct nf_conn *ct,
{
int ret;
- DEBUGP("nf_ct_h323: OpenLogicalChannel\n");
+ pr_debug("nf_ct_h323: OpenLogicalChannel\n");
if (olc->forwardLogicalChannelParameters.multiplexParameters.choice ==
eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)
@@ -475,7 +467,7 @@ static int process_olca(struct sk_buff **pskb, struct nf_conn *ct,
H2250LogicalChannelAckParameters *ack;
int ret;
- DEBUGP("nf_ct_h323: OpenLogicalChannelAck\n");
+ pr_debug("nf_ct_h323: OpenLogicalChannelAck\n");
if ((olca->options &
eOpenLogicalChannelAck_reverseLogicalChannelParameters) &&
@@ -546,8 +538,8 @@ static int process_h245(struct sk_buff **pskb, struct nf_conn *ct,
return process_olc(pskb, ct, ctinfo, data, dataoff,
&mscm->request.openLogicalChannel);
}
- DEBUGP("nf_ct_h323: H.245 Request %d\n",
- mscm->request.choice);
+ pr_debug("nf_ct_h323: H.245 Request %d\n",
+ mscm->request.choice);
break;
case eMultimediaSystemControlMessage_response:
if (mscm->response.choice ==
@@ -556,11 +548,11 @@ static int process_h245(struct sk_buff **pskb, struct nf_conn *ct,
&mscm->response.
openLogicalChannelAck);
}
- DEBUGP("nf_ct_h323: H.245 Response %d\n",
- mscm->response.choice);
+ pr_debug("nf_ct_h323: H.245 Response %d\n",
+ mscm->response.choice);
break;
default:
- DEBUGP("nf_ct_h323: H.245 signal %d\n", mscm->choice);
+ pr_debug("nf_ct_h323: H.245 signal %d\n", mscm->choice);
break;
}
@@ -582,24 +574,23 @@ static int h245_help(struct sk_buff **pskb, unsigned int protoff,
ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
return NF_ACCEPT;
}
- DEBUGP("nf_ct_h245: skblen = %u\n", (*pskb)->len);
+ pr_debug("nf_ct_h245: skblen = %u\n", (*pskb)->len);
spin_lock_bh(&nf_h323_lock);
/* Process each TPKT */
while (get_tpkt_data(pskb, protoff, ct, ctinfo,
&data, &datalen, &dataoff)) {
- DEBUGP("nf_ct_h245: TPKT len=%d ", datalen);
+ pr_debug("nf_ct_h245: TPKT len=%d ", datalen);
NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
/* Decode H.245 signal */
ret = DecodeMultimediaSystemControlMessage(data, datalen,
&mscm);
if (ret < 0) {
- if (net_ratelimit())
- printk("nf_ct_h245: decoding error: %s\n",
- ret == H323_ERROR_BOUND ?
- "out of bound" : "out of range");
+ pr_debug("nf_ct_h245: decoding error: %s\n",
+ ret == H323_ERROR_BOUND ?
+ "out of bound" : "out of range");
/* We don't drop when decoding error */
break;
}
@@ -626,8 +617,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
.max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */,
.timeout = 240,
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
.help = h245_help
};
@@ -684,12 +673,12 @@ static int expect_h245(struct sk_buff **pskb, struct nf_conn *ct,
return 0;
/* Create expect for h245 connection */
- if ((exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3,
- &ct->tuplehash[!dir].tuple.dst.u3,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
exp->helper = &nf_conntrack_helper_h245;
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
@@ -701,14 +690,14 @@ static int expect_h245(struct sk_buff **pskb, struct nf_conn *ct,
ret = nat_h245(pskb, ct, ctinfo, data, dataoff, taddr,
port, exp);
} else { /* Conntrack only */
- if (nf_conntrack_expect_related(exp) == 0) {
- DEBUGP("nf_ct_q931: expect H.245 ");
+ if (nf_ct_expect_related(exp) == 0) {
+ pr_debug("nf_ct_q931: expect H.245 ");
NF_CT_DUMP_TUPLE(&exp->tuple);
} else
ret = -1;
}
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return ret;
}
@@ -791,16 +780,16 @@ static int expect_callforwarding(struct sk_buff **pskb,
if (callforward_filter &&
callforward_do_filter(&addr, &ct->tuplehash[!dir].tuple.src.u3,
ct->tuplehash[!dir].tuple.src.l3num)) {
- DEBUGP("nf_ct_q931: Call Forwarding not tracked\n");
+ pr_debug("nf_ct_q931: Call Forwarding not tracked\n");
return 0;
}
/* Create expect for the second call leg */
- if ((exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3, &addr,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
exp->helper = nf_conntrack_helper_q931;
if (memcmp(&ct->tuplehash[dir].tuple.src.u3,
@@ -812,14 +801,14 @@ static int expect_callforwarding(struct sk_buff **pskb,
ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff,
taddr, port, exp);
} else { /* Conntrack only */
- if (nf_conntrack_expect_related(exp) == 0) {
- DEBUGP("nf_ct_q931: expect Call Forwarding ");
+ if (nf_ct_expect_related(exp) == 0) {
+ pr_debug("nf_ct_q931: expect Call Forwarding ");
NF_CT_DUMP_TUPLE(&exp->tuple);
} else
ret = -1;
}
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return ret;
}
@@ -837,7 +826,7 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
union nf_conntrack_address addr;
typeof(set_h225_addr_hook) set_h225_addr;
- DEBUGP("nf_ct_q931: Setup\n");
+ pr_debug("nf_ct_q931: Setup\n");
if (setup->options & eSetup_UUIE_h245Address) {
ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
@@ -852,11 +841,11 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
get_h225_addr(ct, *data, &setup->destCallSignalAddress,
&addr, &port) &&
memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) {
- DEBUGP("nf_ct_q931: set destCallSignalAddress "
- NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n",
- NIP6(*(struct in6_addr *)&addr), ntohs(port),
- NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.src.u3),
- ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
+ pr_debug("nf_ct_q931: set destCallSignalAddress "
+ NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n",
+ NIP6(*(struct in6_addr *)&addr), ntohs(port),
+ NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.src.u3),
+ ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
ret = set_h225_addr(pskb, data, dataoff,
&setup->destCallSignalAddress,
&ct->tuplehash[!dir].tuple.src.u3,
@@ -870,11 +859,11 @@ static int process_setup(struct sk_buff **pskb, struct nf_conn *ct,
get_h225_addr(ct, *data, &setup->sourceCallSignalAddress,
&addr, &port) &&
memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) {
- DEBUGP("nf_ct_q931: set sourceCallSignalAddress "
- NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n",
- NIP6(*(struct in6_addr *)&addr), ntohs(port),
- NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.dst.u3),
- ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
+ pr_debug("nf_ct_q931: set sourceCallSignalAddress "
+ NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n",
+ NIP6(*(struct in6_addr *)&addr), ntohs(port),
+ NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.dst.u3),
+ ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
ret = set_h225_addr(pskb, data, dataoff,
&setup->sourceCallSignalAddress,
&ct->tuplehash[!dir].tuple.dst.u3,
@@ -905,7 +894,7 @@ static int process_callproceeding(struct sk_buff **pskb,
int ret;
int i;
- DEBUGP("nf_ct_q931: CallProceeding\n");
+ pr_debug("nf_ct_q931: CallProceeding\n");
if (callproc->options & eCallProceeding_UUIE_h245Address) {
ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
@@ -935,7 +924,7 @@ static int process_connect(struct sk_buff **pskb, struct nf_conn *ct,
int ret;
int i;
- DEBUGP("nf_ct_q931: Connect\n");
+ pr_debug("nf_ct_q931: Connect\n");
if (connect->options & eConnect_UUIE_h245Address) {
ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
@@ -965,7 +954,7 @@ static int process_alerting(struct sk_buff **pskb, struct nf_conn *ct,
int ret;
int i;
- DEBUGP("nf_ct_q931: Alerting\n");
+ pr_debug("nf_ct_q931: Alerting\n");
if (alert->options & eAlerting_UUIE_h245Address) {
ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
@@ -995,7 +984,7 @@ static int process_facility(struct sk_buff **pskb, struct nf_conn *ct,
int ret;
int i;
- DEBUGP("nf_ct_q931: Facility\n");
+ pr_debug("nf_ct_q931: Facility\n");
if (facility->reason.choice == eFacilityReason_callForwarded) {
if (facility->options & eFacility_UUIE_alternativeAddress)
@@ -1034,7 +1023,7 @@ static int process_progress(struct sk_buff **pskb, struct nf_conn *ct,
int ret;
int i;
- DEBUGP("nf_ct_q931: Progress\n");
+ pr_debug("nf_ct_q931: Progress\n");
if (progress->options & eProgress_UUIE_h245Address) {
ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
@@ -1091,8 +1080,8 @@ static int process_q931(struct sk_buff **pskb, struct nf_conn *ct,
&pdu->h323_message_body.progress);
break;
default:
- DEBUGP("nf_ct_q931: Q.931 signal %d\n",
- pdu->h323_message_body.choice);
+ pr_debug("nf_ct_q931: Q.931 signal %d\n",
+ pdu->h323_message_body.choice);
break;
}
@@ -1126,23 +1115,22 @@ static int q931_help(struct sk_buff **pskb, unsigned int protoff,
ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
return NF_ACCEPT;
}
- DEBUGP("nf_ct_q931: skblen = %u\n", (*pskb)->len);
+ pr_debug("nf_ct_q931: skblen = %u\n", (*pskb)->len);
spin_lock_bh(&nf_h323_lock);
/* Process each TPKT */
while (get_tpkt_data(pskb, protoff, ct, ctinfo,
&data, &datalen, &dataoff)) {
- DEBUGP("nf_ct_q931: TPKT len=%d ", datalen);
+ pr_debug("nf_ct_q931: TPKT len=%d ", datalen);
NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
/* Decode Q.931 signal */
ret = DecodeQ931(data, datalen, &q931);
if (ret < 0) {
- if (net_ratelimit())
- printk("nf_ct_q931: decoding error: %s\n",
- ret == H323_ERROR_BOUND ?
- "out of bound" : "out of range");
+ pr_debug("nf_ct_q931: decoding error: %s\n",
+ ret == H323_ERROR_BOUND ?
+ "out of bound" : "out of range");
/* We don't drop when decoding error */
break;
}
@@ -1173,9 +1161,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
.tuple.src.l3num = AF_INET,
.tuple.src.u.tcp.port = __constant_htons(Q931_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.tcp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
.help = q931_help
},
{
@@ -1187,9 +1172,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
.tuple.src.l3num = AF_INET6,
.tuple.src.u.tcp.port = __constant_htons(Q931_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.tcp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
.help = q931_help
},
};
@@ -1225,7 +1207,7 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
tuple.dst.u.tcp.port = port;
tuple.dst.protonum = IPPROTO_TCP;
- exp = __nf_conntrack_expect_find(&tuple);
+ exp = __nf_ct_expect_find(&tuple);
if (exp && exp->master == ct)
return exp;
return NULL;
@@ -1271,14 +1253,13 @@ static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct,
return 0;
/* Create expect for Q.931 */
- if ((exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
- gkrouted_only ? /* only accept calls from GK? */
- &ct->tuplehash[!dir].tuple.src.u3 :
- NULL,
- &ct->tuplehash[!dir].tuple.dst.u3,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ gkrouted_only ? /* only accept calls from GK? */
+ &ct->tuplehash[!dir].tuple.src.u3 : NULL,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ IPPROTO_TCP, NULL, &port);
exp->helper = nf_conntrack_helper_q931;
exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */
@@ -1286,8 +1267,8 @@ static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct,
if (nat_q931 && ct->status & IPS_NAT_MASK) { /* Need NAT */
ret = nat_q931(pskb, ct, ctinfo, data, taddr, i, port, exp);
} else { /* Conntrack only */
- if (nf_conntrack_expect_related(exp) == 0) {
- DEBUGP("nf_ct_ras: expect Q.931 ");
+ if (nf_ct_expect_related(exp) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
NF_CT_DUMP_TUPLE(&exp->tuple);
/* Save port for looking up expect in processing RCF */
@@ -1296,7 +1277,7 @@ static int expect_q931(struct sk_buff **pskb, struct nf_conn *ct,
ret = -1;
}
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return ret;
}
@@ -1308,7 +1289,7 @@ static int process_grq(struct sk_buff **pskb, struct nf_conn *ct,
{
typeof(set_ras_addr_hook) set_ras_addr;
- DEBUGP("nf_ct_ras: GRQ\n");
+ pr_debug("nf_ct_ras: GRQ\n");
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr && ct->status & IPS_NAT_MASK) /* NATed */
@@ -1328,7 +1309,7 @@ static int process_gcf(struct sk_buff **pskb, struct nf_conn *ct,
union nf_conntrack_address addr;
struct nf_conntrack_expect *exp;
- DEBUGP("nf_ct_ras: GCF\n");
+ pr_debug("nf_ct_ras: GCF\n");
if (!get_h225_addr(ct, *data, &gcf->rasAddress, &addr, &port))
return 0;
@@ -1343,20 +1324,20 @@ static int process_gcf(struct sk_buff **pskb, struct nf_conn *ct,
return 0;
/* Need new expect */
- if ((exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3, &addr,
- IPPROTO_UDP, NULL, &port);
+ nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_UDP, NULL, &port);
exp->helper = nf_conntrack_helper_ras;
- if (nf_conntrack_expect_related(exp) == 0) {
- DEBUGP("nf_ct_ras: expect RAS ");
+ if (nf_ct_expect_related(exp) == 0) {
+ pr_debug("nf_ct_ras: expect RAS ");
NF_CT_DUMP_TUPLE(&exp->tuple);
} else
ret = -1;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return ret;
}
@@ -1370,7 +1351,7 @@ static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct,
int ret;
typeof(set_ras_addr_hook) set_ras_addr;
- DEBUGP("nf_ct_ras: RRQ\n");
+ pr_debug("nf_ct_ras: RRQ\n");
ret = expect_q931(pskb, ct, ctinfo, data,
rrq->callSignalAddress.item,
@@ -1388,7 +1369,7 @@ static int process_rrq(struct sk_buff **pskb, struct nf_conn *ct,
}
if (rrq->options & eRegistrationRequest_timeToLive) {
- DEBUGP("nf_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive);
+ pr_debug("nf_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive);
info->timeout = rrq->timeToLive;
} else
info->timeout = default_rrq_ttl;
@@ -1407,7 +1388,7 @@ static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct,
struct nf_conntrack_expect *exp;
typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("nf_ct_ras: RCF\n");
+ pr_debug("nf_ct_ras: RCF\n");
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr && ct->status & IPS_NAT_MASK) {
@@ -1419,14 +1400,13 @@ static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct,
}
if (rcf->options & eRegistrationConfirm_timeToLive) {
- DEBUGP("nf_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive);
+ pr_debug("nf_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive);
info->timeout = rcf->timeToLive;
}
if (info->timeout > 0) {
- DEBUGP
- ("nf_ct_ras: set RAS connection timeout to %u seconds\n",
- info->timeout);
+ pr_debug("nf_ct_ras: set RAS connection timeout to "
+ "%u seconds\n", info->timeout);
nf_ct_refresh(ct, *pskb, info->timeout * HZ);
/* Set expect timeout */
@@ -1434,9 +1414,9 @@ static int process_rcf(struct sk_buff **pskb, struct nf_conn *ct,
exp = find_expect(ct, &ct->tuplehash[dir].tuple.dst.u3,
info->sig_port[!dir]);
if (exp) {
- DEBUGP("nf_ct_ras: set Q.931 expect "
- "timeout to %u seconds for",
- info->timeout);
+ pr_debug("nf_ct_ras: set Q.931 expect "
+ "timeout to %u seconds for",
+ info->timeout);
NF_CT_DUMP_TUPLE(&exp->tuple);
set_expect_timeout(exp, info->timeout);
}
@@ -1456,7 +1436,7 @@ static int process_urq(struct sk_buff **pskb, struct nf_conn *ct,
int ret;
typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("nf_ct_ras: URQ\n");
+ pr_debug("nf_ct_ras: URQ\n");
set_sig_addr = rcu_dereference(set_sig_addr_hook);
if (set_sig_addr && ct->status & IPS_NAT_MASK) {
@@ -1489,7 +1469,7 @@ static int process_arq(struct sk_buff **pskb, struct nf_conn *ct,
union nf_conntrack_address addr;
typeof(set_h225_addr_hook) set_h225_addr;
- DEBUGP("nf_ct_ras: ARQ\n");
+ pr_debug("nf_ct_ras: ARQ\n");
set_h225_addr = rcu_dereference(set_h225_addr_hook);
if ((arq->options & eAdmissionRequest_destCallSignalAddress) &&
@@ -1532,7 +1512,7 @@ static int process_acf(struct sk_buff **pskb, struct nf_conn *ct,
struct nf_conntrack_expect *exp;
typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("nf_ct_ras: ACF\n");
+ pr_debug("nf_ct_ras: ACF\n");
if (!get_h225_addr(ct, *data, &acf->destCallSignalAddress,
&addr, &port))
@@ -1548,21 +1528,21 @@ static int process_acf(struct sk_buff **pskb, struct nf_conn *ct,
}
/* Need new expect */
- if ((exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3, &addr,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
exp->flags = NF_CT_EXPECT_PERMANENT;
exp->helper = nf_conntrack_helper_q931;
- if (nf_conntrack_expect_related(exp) == 0) {
- DEBUGP("nf_ct_ras: expect Q.931 ");
+ if (nf_ct_expect_related(exp) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
NF_CT_DUMP_TUPLE(&exp->tuple);
} else
ret = -1;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return ret;
}
@@ -1574,7 +1554,7 @@ static int process_lrq(struct sk_buff **pskb, struct nf_conn *ct,
{
typeof(set_ras_addr_hook) set_ras_addr;
- DEBUGP("nf_ct_ras: LRQ\n");
+ pr_debug("nf_ct_ras: LRQ\n");
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr && ct->status & IPS_NAT_MASK)
@@ -1594,28 +1574,28 @@ static int process_lcf(struct sk_buff **pskb, struct nf_conn *ct,
union nf_conntrack_address addr;
struct nf_conntrack_expect *exp;
- DEBUGP("nf_ct_ras: LCF\n");
+ pr_debug("nf_ct_ras: LCF\n");
if (!get_h225_addr(ct, *data, &lcf->callSignalAddress,
&addr, &port))
return 0;
/* Need new expect for call signal */
- if ((exp = nf_conntrack_expect_alloc(ct)) == NULL)
+ if ((exp = nf_ct_expect_alloc(ct)) == NULL)
return -1;
- nf_conntrack_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
- &ct->tuplehash[!dir].tuple.src.u3, &addr,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,
+ &ct->tuplehash[!dir].tuple.src.u3, &addr,
+ IPPROTO_TCP, NULL, &port);
exp->flags = NF_CT_EXPECT_PERMANENT;
exp->helper = nf_conntrack_helper_q931;
- if (nf_conntrack_expect_related(exp) == 0) {
- DEBUGP("nf_ct_ras: expect Q.931 ");
+ if (nf_ct_expect_related(exp) == 0) {
+ pr_debug("nf_ct_ras: expect Q.931 ");
NF_CT_DUMP_TUPLE(&exp->tuple);
} else
ret = -1;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
/* Ignore rasAddress */
@@ -1631,7 +1611,7 @@ static int process_irr(struct sk_buff **pskb, struct nf_conn *ct,
typeof(set_ras_addr_hook) set_ras_addr;
typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("nf_ct_ras: IRR\n");
+ pr_debug("nf_ct_ras: IRR\n");
set_ras_addr = rcu_dereference(set_ras_addr_hook);
if (set_ras_addr && ct->status & IPS_NAT_MASK) {
@@ -1690,7 +1670,7 @@ static int process_ras(struct sk_buff **pskb, struct nf_conn *ct,
return process_irr(pskb, ct, ctinfo, data,
&ras->infoRequestResponse);
default:
- DEBUGP("nf_ct_ras: RAS message %d\n", ras->choice);
+ pr_debug("nf_ct_ras: RAS message %d\n", ras->choice);
break;
}
@@ -1706,7 +1686,7 @@ static int ras_help(struct sk_buff **pskb, unsigned int protoff,
int datalen = 0;
int ret;
- DEBUGP("nf_ct_ras: skblen = %u\n", (*pskb)->len);
+ pr_debug("nf_ct_ras: skblen = %u\n", (*pskb)->len);
spin_lock_bh(&nf_h323_lock);
@@ -1714,16 +1694,15 @@ static int ras_help(struct sk_buff **pskb, unsigned int protoff,
data = get_udp_data(pskb, protoff, &datalen);
if (data == NULL)
goto accept;
- DEBUGP("nf_ct_ras: RAS message len=%d ", datalen);
+ pr_debug("nf_ct_ras: RAS message len=%d ", datalen);
NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
/* Decode RAS message */
ret = DecodeRasMessage(data, datalen, &ras);
if (ret < 0) {
- if (net_ratelimit())
- printk("nf_ct_ras: decoding error: %s\n",
- ret == H323_ERROR_BOUND ?
- "out of bound" : "out of range");
+ pr_debug("nf_ct_ras: decoding error: %s\n",
+ ret == H323_ERROR_BOUND ?
+ "out of bound" : "out of range");
goto accept;
}
@@ -1752,9 +1731,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(RAS_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
.help = ras_help,
},
{
@@ -1765,9 +1741,6 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = {
.tuple.src.l3num = AF_INET6,
.tuple.src.u.udp.port = __constant_htons(RAS_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
.help = ras_help,
},
};
@@ -1780,7 +1753,7 @@ static void __exit nf_conntrack_h323_fini(void)
nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]);
nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]);
kfree(h323_buffer);
- DEBUGP("nf_ct_h323: fini\n");
+ pr_debug("nf_ct_h323: fini\n");
}
/****************************************************************************/
@@ -1803,7 +1776,7 @@ static int __init nf_conntrack_h323_init(void)
ret = nf_conntrack_helper_register(&nf_conntrack_helper_ras[1]);
if (ret < 0)
goto err4;
- DEBUGP("nf_ct_h323: init success\n");
+ pr_debug("nf_ct_h323: init success\n");
return 0;
err4:
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index f868b7fbd9b4..ca10df40784f 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -26,23 +26,43 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_extend.h>
-static __read_mostly LIST_HEAD(helpers);
+static struct hlist_head *nf_ct_helper_hash __read_mostly;
+static unsigned int nf_ct_helper_hsize __read_mostly;
+static unsigned int nf_ct_helper_count __read_mostly;
+static int nf_ct_helper_vmalloc;
+
+
+/* Stupid hash, but collision free for the default registrations of the
+ * helpers currently in the kernel. */
+static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple)
+{
+ return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^
+ tuple->src.u.all) % nf_ct_helper_hsize;
+}
struct nf_conntrack_helper *
__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple)
{
- struct nf_conntrack_helper *h;
+ struct nf_conntrack_helper *helper;
+ struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
+ struct hlist_node *n;
+ unsigned int h;
+
+ if (!nf_ct_helper_count)
+ return NULL;
- list_for_each_entry(h, &helpers, list) {
- if (nf_ct_tuple_mask_cmp(tuple, &h->tuple, &h->mask))
- return h;
+ h = helper_hash(tuple);
+ hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) {
+ if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask))
+ return helper;
}
return NULL;
}
struct nf_conntrack_helper *
-nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple)
+nf_ct_helper_find_get(const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_helper *helper;
@@ -75,16 +95,32 @@ struct nf_conntrack_helper *
__nf_conntrack_helper_find_byname(const char *name)
{
struct nf_conntrack_helper *h;
+ struct hlist_node *n;
+ unsigned int i;
- list_for_each_entry(h, &helpers, list) {
- if (!strcmp(h->name, name))
- return h;
+ for (i = 0; i < nf_ct_helper_hsize; i++) {
+ hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) {
+ if (!strcmp(h->name, name))
+ return h;
+ }
}
-
return NULL;
}
EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname);
+struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
+{
+ struct nf_conn_help *help;
+
+ help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
+ if (help)
+ INIT_HLIST_HEAD(&help->expectations);
+ else
+ pr_debug("failed to add helper extension area");
+ return help;
+}
+EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
+
static inline int unhelp(struct nf_conntrack_tuple_hash *i,
const struct nf_conntrack_helper *me)
{
@@ -100,20 +136,13 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i,
int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
{
- int size, ret;
+ unsigned int h = helper_hash(&me->tuple);
BUG_ON(me->timeout == 0);
- size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_help)) +
- sizeof(struct nf_conn_help);
- ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help",
- size);
- if (ret < 0) {
- printk(KERN_ERR "nf_conntrack_helper_register: Unable to create slab cache for conntracks\n");
- return ret;
- }
write_lock_bh(&nf_conntrack_lock);
- list_add(&me->list, &helpers);
+ hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]);
+ nf_ct_helper_count++;
write_unlock_bh(&nf_conntrack_lock);
return 0;
@@ -122,29 +151,34 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
{
- unsigned int i;
struct nf_conntrack_tuple_hash *h;
- struct nf_conntrack_expect *exp, *tmp;
+ struct nf_conntrack_expect *exp;
+ struct hlist_node *n, *next;
+ unsigned int i;
/* Need write lock here, to delete helper. */
write_lock_bh(&nf_conntrack_lock);
- list_del(&me->list);
+ hlist_del(&me->hnode);
+ nf_ct_helper_count--;
/* Get rid of expectations */
- list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, list) {
- struct nf_conn_help *help = nfct_help(exp->master);
- if ((help->helper == me || exp->helper == me) &&
- del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
- nf_conntrack_expect_put(exp);
+ for (i = 0; i < nf_ct_expect_hsize; i++) {
+ hlist_for_each_entry_safe(exp, n, next,
+ &nf_ct_expect_hash[i], hnode) {
+ struct nf_conn_help *help = nfct_help(exp->master);
+ if ((help->helper == me || exp->helper == me) &&
+ del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
+ }
}
}
/* Get rid of expecteds, set helpers to NULL. */
- list_for_each_entry(h, &unconfirmed, list)
+ hlist_for_each_entry(h, n, &unconfirmed, hnode)
unhelp(h, me);
for (i = 0; i < nf_conntrack_htable_size; i++) {
- list_for_each_entry(h, &nf_conntrack_hash[i], list)
+ hlist_for_each_entry(h, n, &nf_conntrack_hash[i], hnode)
unhelp(h, me);
}
write_unlock_bh(&nf_conntrack_lock);
@@ -153,3 +187,38 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
synchronize_net();
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
+
+static struct nf_ct_ext_type helper_extend __read_mostly = {
+ .len = sizeof(struct nf_conn_help),
+ .align = __alignof__(struct nf_conn_help),
+ .id = NF_CT_EXT_HELPER,
+};
+
+int nf_conntrack_helper_init(void)
+{
+ int err;
+
+ nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
+ nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize,
+ &nf_ct_helper_vmalloc);
+ if (!nf_ct_helper_hash)
+ return -ENOMEM;
+
+ err = nf_ct_extend_register(&helper_extend);
+ if (err < 0)
+ goto err1;
+
+ return 0;
+
+err1:
+ nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc,
+ nf_ct_helper_hsize);
+ return err;
+}
+
+void nf_conntrack_helper_fini(void)
+{
+ nf_ct_extend_unregister(&helper_extend);
+ nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc,
+ nf_ct_helper_hsize);
+}
diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c
index 43ccd0e2e8ae..1562ca97a349 100644
--- a/net/netfilter/nf_conntrack_irc.c
+++ b/net/netfilter/nf_conntrack_irc.c
@@ -12,6 +12,7 @@
#include <linux/moduleparam.h>
#include <linux/skbuff.h>
#include <linux/in.h>
+#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter.h>
@@ -55,13 +56,6 @@ static const char *dccprotos[] = {
#define MINMATCHLEN 5
-#if 0
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s:" format, \
- __FILE__, __FUNCTION__ , ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* tries to get the ip_addr and port out of a dcc command
* return value: -1 on failure, 0 on success
* data pointer to first byte of DCC command data
@@ -99,6 +93,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
struct nf_conn *ct, enum ip_conntrack_info ctinfo)
{
unsigned int dataoff;
+ struct iphdr *iph;
struct tcphdr _tcph, *th;
char *data, *data_limit, *ib_ptr;
int dir = CTINFO2DIR(ctinfo);
@@ -148,9 +143,10 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
data += 5;
/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
- DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
- NIPQUAD(iph->saddr), ntohs(th->source),
- NIPQUAD(iph->daddr), ntohs(th->dest));
+ iph = ip_hdr(*pskb);
+ pr_debug("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u\n",
+ NIPQUAD(iph->saddr), ntohs(th->source),
+ NIPQUAD(iph->daddr), ntohs(th->dest));
for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
@@ -158,18 +154,18 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
continue;
}
data += strlen(dccprotos[i]);
- DEBUGP("DCC %s detected\n", dccprotos[i]);
+ pr_debug("DCC %s detected\n", dccprotos[i]);
/* we have at least
* (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
* data left (== 14/13 bytes) */
if (parse_dcc((char *)data, data_limit, &dcc_ip,
&dcc_port, &addr_beg_p, &addr_end_p)) {
- DEBUGP("unable to parse dcc command\n");
+ pr_debug("unable to parse dcc command\n");
continue;
}
- DEBUGP("DCC bound ip/port: %u.%u.%u.%u:%u\n",
- HIPQUAD(dcc_ip), dcc_port);
+ pr_debug("DCC bound ip/port: %u.%u.%u.%u:%u\n",
+ HIPQUAD(dcc_ip), dcc_port);
/* dcc_ip can be the internal OR external (NAT'ed) IP */
tuple = &ct->tuplehash[dir].tuple;
@@ -184,16 +180,16 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
continue;
}
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (exp == NULL) {
ret = NF_DROP;
goto out;
}
tuple = &ct->tuplehash[!dir].tuple;
port = htons(dcc_port);
- nf_conntrack_expect_init(exp, tuple->src.l3num,
- NULL, &tuple->dst.u3,
- IPPROTO_TCP, NULL, &port);
+ nf_ct_expect_init(exp, tuple->src.l3num,
+ NULL, &tuple->dst.u3,
+ IPPROTO_TCP, NULL, &port);
nf_nat_irc = rcu_dereference(nf_nat_irc_hook);
if (nf_nat_irc && ct->status & IPS_NAT_MASK)
@@ -201,9 +197,9 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
addr_beg_p - ib_ptr,
addr_end_p - addr_beg_p,
exp);
- else if (nf_conntrack_expect_related(exp) != 0)
+ else if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
goto out;
}
}
@@ -239,9 +235,6 @@ static int __init nf_conntrack_irc_init(void)
irc[i].tuple.src.l3num = AF_INET;
irc[i].tuple.src.u.tcp.port = htons(ports[i]);
irc[i].tuple.dst.protonum = IPPROTO_TCP;
- irc[i].mask.src.l3num = 0xFFFF;
- irc[i].mask.src.u.tcp.port = htons(0xFFFF);
- irc[i].mask.dst.protonum = 0xFF;
irc[i].max_expected = max_dcc_channels;
irc[i].timeout = dcc_timeout;
irc[i].me = THIS_MODULE;
diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c
index cbd96f3c1b89..991c52c9a28b 100644
--- a/net/netfilter/nf_conntrack_l3proto_generic.c
+++ b/net/netfilter/nf_conntrack_l3proto_generic.c
@@ -31,12 +31,6 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
static int generic_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
{
@@ -67,29 +61,21 @@ static int generic_print_conntrack(struct seq_file *s,
return 0;
}
-static int
-generic_prepare(struct sk_buff **pskb, unsigned int hooknum,
- unsigned int *dataoff, u_int8_t *protonum)
+static int generic_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
+ unsigned int *dataoff, u_int8_t *protonum)
{
/* Never track !!! */
return -NF_ACCEPT;
}
-static u_int32_t generic_get_features(const struct nf_conntrack_tuple *tuple)
-
-{
- return NF_CT_F_BASIC;
-}
-
-struct nf_conntrack_l3proto nf_conntrack_l3proto_generic = {
+struct nf_conntrack_l3proto nf_conntrack_l3proto_generic __read_mostly = {
.l3proto = PF_UNSPEC,
.name = "unknown",
.pkt_to_tuple = generic_pkt_to_tuple,
.invert_tuple = generic_invert_tuple,
.print_tuple = generic_print_tuple,
.print_conntrack = generic_print_conntrack,
- .prepare = generic_prepare,
- .get_features = generic_get_features,
+ .get_l4proto = generic_get_l4proto,
};
EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_generic);
diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c
index 1093478cc007..1d59fabeb5f7 100644
--- a/net/netfilter/nf_conntrack_netbios_ns.c
+++ b/net/netfilter/nf_conntrack_netbios_ns.c
@@ -74,7 +74,7 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
if (mask == 0)
goto out;
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (exp == NULL)
goto out;
@@ -83,16 +83,13 @@ static int help(struct sk_buff **pskb, unsigned int protoff,
exp->mask.src.u3.ip = mask;
exp->mask.src.u.udp.port = htons(0xFFFF);
- exp->mask.dst.u3.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.udp.port = htons(0xFFFF);
- exp->mask.dst.protonum = 0xFF;
exp->expectfn = NULL;
exp->flags = NF_CT_EXPECT_PERMANENT;
exp->helper = NULL;
- nf_conntrack_expect_related(exp);
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_related(exp);
+ nf_ct_expect_put(exp);
nf_ct_refresh(ct, *pskb, timeout * HZ);
out:
@@ -104,9 +101,6 @@ static struct nf_conntrack_helper helper __read_mostly = {
.tuple.src.l3num = AF_INET,
.tuple.src.u.udp.port = __constant_htons(NMBD_PORT),
.tuple.dst.protonum = IPPROTO_UDP,
- .mask.src.l3num = 0xFFFF,
- .mask.src.u.udp.port = __constant_htons(0xFFFF),
- .mask.dst.protonum = 0xFF,
.max_expected = 1,
.me = THIS_MODULE,
.help = help,
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index d0fe3d769828..6f89b105a205 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -428,7 +428,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
struct nf_conn *ct, *last;
struct nf_conntrack_tuple_hash *h;
- struct list_head *i;
+ struct hlist_node *n;
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
@@ -436,8 +436,8 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
last = (struct nf_conn *)cb->args[1];
for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
restart:
- list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) {
- h = (struct nf_conntrack_tuple_hash *) i;
+ hlist_for_each_entry(h, n, &nf_conntrack_hash[cb->args[0]],
+ hnode) {
if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
continue;
ct = nf_ct_tuplehash_to_ctrack(h);
@@ -689,7 +689,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- h = nf_conntrack_find_get(&tuple, NULL);
+ h = nf_conntrack_find_get(&tuple);
if (!h)
return -ENOENT;
@@ -744,7 +744,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- h = nf_conntrack_find_get(&tuple, NULL);
+ h = nf_conntrack_find_get(&tuple);
if (!h)
return -ENOENT;
@@ -856,23 +856,23 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
return 0;
}
- if (!help) {
- /* FIXME: we need to reallocate and rehash */
- return -EBUSY;
- }
-
helper = __nf_conntrack_helper_find_byname(helpname);
if (helper == NULL)
return -EINVAL;
- if (help->helper == helper)
- return 0;
-
- if (help->helper)
- return -EBUSY;
+ if (help) {
+ if (help->helper == helper)
+ return 0;
+ if (help->helper)
+ return -EBUSY;
+ /* need to zero data of old helper */
+ memset(&help->help, 0, sizeof(help->help));
+ } else {
+ help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
+ if (help == NULL)
+ return -ENOMEM;
+ }
- /* need to zero data of old helper */
- memset(&help->help, 0, sizeof(help->help));
rcu_assign_pointer(help->helper, helper);
return 0;
@@ -957,7 +957,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
struct nf_conn *ct;
int err = -EINVAL;
struct nf_conn_help *help;
- struct nf_conntrack_helper *helper = NULL;
+ struct nf_conntrack_helper *helper;
ct = nf_conntrack_alloc(otuple, rtuple);
if (ct == NULL || IS_ERR(ct))
@@ -987,9 +987,14 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
#endif
- help = nfct_help(ct);
- if (help) {
- helper = nf_ct_helper_find_get(rtuple);
+ helper = nf_ct_helper_find_get(rtuple);
+ if (helper) {
+ help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
+ if (help == NULL) {
+ nf_ct_helper_put(helper);
+ err = -ENOMEM;
+ goto err;
+ }
/* not in hash table yet so not strictly necessary */
rcu_assign_pointer(help->helper, helper);
}
@@ -1089,22 +1094,29 @@ nfattr_failure:
static inline int
ctnetlink_exp_dump_mask(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple,
- const struct nf_conntrack_tuple *mask)
+ const struct nf_conntrack_tuple_mask *mask)
{
int ret;
struct nf_conntrack_l3proto *l3proto;
struct nf_conntrack_l4proto *l4proto;
- struct nfattr *nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK);
+ struct nf_conntrack_tuple m;
+ struct nfattr *nest_parms;
+
+ memset(&m, 0xFF, sizeof(m));
+ m.src.u.all = mask->src.u.all;
+ memcpy(&m.src.u3, &mask->src.u3, sizeof(m.src.u3));
+
+ nest_parms = NFA_NEST(skb, CTA_EXPECT_MASK);
l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
- ret = ctnetlink_dump_tuples_ip(skb, mask, l3proto);
+ ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto);
nf_ct_l3proto_put(l3proto);
if (unlikely(ret < 0))
goto nfattr_failure;
l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum);
- ret = ctnetlink_dump_tuples_proto(skb, mask, l4proto);
+ ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto);
nf_ct_l4proto_put(l4proto);
if (unlikely(ret < 0))
goto nfattr_failure;
@@ -1223,32 +1235,52 @@ nfattr_failure:
return NOTIFY_DONE;
}
#endif
+static int ctnetlink_exp_done(struct netlink_callback *cb)
+{
+ if (cb->args[1])
+ nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[1]);
+ return 0;
+}
static int
ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct nf_conntrack_expect *exp = NULL;
- struct list_head *i;
- u_int32_t *id = (u_int32_t *) &cb->args[0];
+ struct nf_conntrack_expect *exp, *last;
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
+ struct hlist_node *n;
u_int8_t l3proto = nfmsg->nfgen_family;
read_lock_bh(&nf_conntrack_lock);
- list_for_each_prev(i, &nf_conntrack_expect_list) {
- exp = (struct nf_conntrack_expect *) i;
- if (l3proto && exp->tuple.src.l3num != l3proto)
- continue;
- if (exp->id <= *id)
- continue;
- if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq,
- IPCTNL_MSG_EXP_NEW,
- 1, exp) < 0)
- goto out;
- *id = exp->id;
+ last = (struct nf_conntrack_expect *)cb->args[1];
+ for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
+restart:
+ hlist_for_each_entry(exp, n, &nf_ct_expect_hash[cb->args[0]],
+ hnode) {
+ if (l3proto && exp->tuple.src.l3num != l3proto)
+ continue;
+ if (cb->args[1]) {
+ if (exp != last)
+ continue;
+ cb->args[1] = 0;
+ }
+ if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq,
+ IPCTNL_MSG_EXP_NEW,
+ 1, exp) < 0) {
+ atomic_inc(&exp->use);
+ cb->args[1] = (unsigned long)exp;
+ goto out;
+ }
+ }
+ if (cb->args[1]) {
+ cb->args[1] = 0;
+ goto restart;
+ }
}
out:
read_unlock_bh(&nf_conntrack_lock);
+ if (last)
+ nf_ct_expect_put(last);
return skb->len;
}
@@ -1275,7 +1307,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (nlh->nlmsg_flags & NLM_F_DUMP) {
return netlink_dump_start(ctnl, skb, nlh,
ctnetlink_exp_dump_table,
- ctnetlink_done);
+ ctnetlink_exp_done);
}
if (cda[CTA_EXPECT_MASTER-1])
@@ -1286,14 +1318,14 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- exp = nf_conntrack_expect_find_get(&tuple);
+ exp = nf_ct_expect_find_get(&tuple);
if (!exp)
return -ENOENT;
if (cda[CTA_EXPECT_ID-1]) {
__be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
if (exp->id != ntohl(id)) {
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return -ENOENT;
}
}
@@ -1309,14 +1341,14 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (err <= 0)
goto free;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
free:
kfree_skb(skb2);
out:
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return err;
}
@@ -1324,11 +1356,13 @@ static int
ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *cda[])
{
- struct nf_conntrack_expect *exp, *tmp;
+ struct nf_conntrack_expect *exp;
struct nf_conntrack_tuple tuple;
struct nf_conntrack_helper *h;
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+ struct hlist_node *n, *next;
u_int8_t u3 = nfmsg->nfgen_family;
+ unsigned int i;
int err;
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
@@ -1341,25 +1375,26 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
return err;
/* bump usage count to 2 */
- exp = nf_conntrack_expect_find_get(&tuple);
+ exp = nf_ct_expect_find_get(&tuple);
if (!exp)
return -ENOENT;
if (cda[CTA_EXPECT_ID-1]) {
__be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
if (exp->id != ntohl(id)) {
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return -ENOENT;
}
}
/* after list removal, usage count == 1 */
- nf_conntrack_unexpect_related(exp);
+ nf_ct_unexpect_related(exp);
/* have to put what we 'get' above.
* after this line usage count == 0 */
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
} else if (cda[CTA_EXPECT_HELP_NAME-1]) {
char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]);
+ struct nf_conn_help *m_help;
/* delete all expectations for this helper */
write_lock_bh(&nf_conntrack_lock);
@@ -1368,24 +1403,30 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
write_unlock_bh(&nf_conntrack_lock);
return -EINVAL;
}
- list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list,
- list) {
- struct nf_conn_help *m_help = nfct_help(exp->master);
- if (m_help->helper == h
- && del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
- nf_conntrack_expect_put(exp);
+ for (i = 0; i < nf_ct_expect_hsize; i++) {
+ hlist_for_each_entry_safe(exp, n, next,
+ &nf_ct_expect_hash[i],
+ hnode) {
+ m_help = nfct_help(exp->master);
+ if (m_help->helper == h
+ && del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
+ }
}
}
write_unlock_bh(&nf_conntrack_lock);
} else {
/* This basically means we have to flush everything*/
write_lock_bh(&nf_conntrack_lock);
- list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list,
- list) {
- if (del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
- nf_conntrack_expect_put(exp);
+ for (i = 0; i < nf_ct_expect_hsize; i++) {
+ hlist_for_each_entry_safe(exp, n, next,
+ &nf_ct_expect_hash[i],
+ hnode) {
+ if (del_timer(&exp->timeout)) {
+ nf_ct_unlink_expect(exp);
+ nf_ct_expect_put(exp);
+ }
}
}
write_unlock_bh(&nf_conntrack_lock);
@@ -1421,7 +1462,7 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
return err;
/* Look for master conntrack of this expectation */
- h = nf_conntrack_find_get(&master_tuple, NULL);
+ h = nf_conntrack_find_get(&master_tuple);
if (!h)
return -ENOENT;
ct = nf_ct_tuplehash_to_ctrack(h);
@@ -1433,7 +1474,7 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
goto out;
}
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (!exp) {
err = -ENOMEM;
goto out;
@@ -1444,10 +1485,11 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
exp->master = ct;
exp->helper = NULL;
memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple));
- memcpy(&exp->mask, &mask, sizeof(struct nf_conntrack_tuple));
+ memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3));
+ exp->mask.src.u.all = mask.src.u.all;
- err = nf_conntrack_expect_related(exp);
- nf_conntrack_expect_put(exp);
+ err = nf_ct_expect_related(exp);
+ nf_ct_expect_put(exp);
out:
nf_ct_put(nf_ct_tuplehash_to_ctrack(h));
@@ -1477,7 +1519,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
return err;
write_lock_bh(&nf_conntrack_lock);
- exp = __nf_conntrack_expect_find(&tuple);
+ exp = __nf_ct_expect_find(&tuple);
if (!exp) {
write_unlock_bh(&nf_conntrack_lock);
@@ -1567,7 +1609,7 @@ static int __init ctnetlink_init(void)
goto err_unreg_exp_subsys;
}
- ret = nf_conntrack_expect_register_notifier(&ctnl_notifier_exp);
+ ret = nf_ct_expect_register_notifier(&ctnl_notifier_exp);
if (ret < 0) {
printk("ctnetlink_init: cannot expect register notifier.\n");
goto err_unreg_notifier;
@@ -1593,7 +1635,7 @@ static void __exit ctnetlink_exit(void)
printk("ctnetlink: unregistering from nfnetlink.\n");
#ifdef CONFIG_NF_CONNTRACK_EVENTS
- nf_conntrack_expect_unregister_notifier(&ctnl_notifier_exp);
+ nf_ct_expect_unregister_notifier(&ctnl_notifier_exp);
nf_conntrack_unregister_notifier(&ctnl_notifier);
#endif
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 115bcb5d5a7c..b0804199ab59 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -65,7 +65,7 @@ void
struct nf_conntrack_expect *exp) __read_mostly;
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
-#if 0
+#ifdef DEBUG
/* PptpControlMessageType names */
const char *pptp_msg_name[] = {
"UNKNOWN_MESSAGE",
@@ -86,9 +86,6 @@ const char *pptp_msg_name[] = {
"SET_LINK_INFO"
};
EXPORT_SYMBOL(pptp_msg_name);
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
-#else
-#define DEBUGP(format, args...)
#endif
#define SECS *HZ
@@ -102,7 +99,7 @@ static void pptp_expectfn(struct nf_conn *ct,
struct nf_conntrack_expect *exp)
{
typeof(nf_nat_pptp_hook_expectfn) nf_nat_pptp_expectfn;
- DEBUGP("increasing timeouts\n");
+ pr_debug("increasing timeouts\n");
/* increase timeout of GRE data channel conntrack entry */
ct->proto.gre.timeout = PPTP_GRE_TIMEOUT;
@@ -121,17 +118,17 @@ static void pptp_expectfn(struct nf_conn *ct,
/* obviously this tuple inversion only works until you do NAT */
nf_ct_invert_tuplepr(&inv_t, &exp->tuple);
- DEBUGP("trying to unexpect other dir: ");
+ pr_debug("trying to unexpect other dir: ");
NF_CT_DUMP_TUPLE(&inv_t);
- exp_other = nf_conntrack_expect_find_get(&inv_t);
+ exp_other = nf_ct_expect_find_get(&inv_t);
if (exp_other) {
/* delete other expectation. */
- DEBUGP("found\n");
- nf_conntrack_unexpect_related(exp_other);
- nf_conntrack_expect_put(exp_other);
+ pr_debug("found\n");
+ nf_ct_unexpect_related(exp_other);
+ nf_ct_expect_put(exp_other);
} else {
- DEBUGP("not found\n");
+ pr_debug("not found\n");
}
}
rcu_read_unlock();
@@ -143,13 +140,13 @@ static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t)
struct nf_conntrack_expect *exp;
struct nf_conn *sibling;
- DEBUGP("trying to timeout ct or exp for tuple ");
+ pr_debug("trying to timeout ct or exp for tuple ");
NF_CT_DUMP_TUPLE(t);
- h = nf_conntrack_find_get(t, NULL);
+ h = nf_conntrack_find_get(t);
if (h) {
sibling = nf_ct_tuplehash_to_ctrack(h);
- DEBUGP("setting timeout of conntrack %p to 0\n", sibling);
+ pr_debug("setting timeout of conntrack %p to 0\n", sibling);
sibling->proto.gre.timeout = 0;
sibling->proto.gre.stream_timeout = 0;
if (del_timer(&sibling->timeout))
@@ -157,11 +154,11 @@ static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t)
nf_ct_put(sibling);
return 1;
} else {
- exp = nf_conntrack_expect_find_get(t);
+ exp = nf_ct_expect_find_get(t);
if (exp) {
- DEBUGP("unexpect_related of expect %p\n", exp);
- nf_conntrack_unexpect_related(exp);
- nf_conntrack_expect_put(exp);
+ pr_debug("unexpect_related of expect %p\n", exp);
+ nf_ct_unexpect_related(exp);
+ nf_ct_expect_put(exp);
return 1;
}
}
@@ -182,7 +179,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id;
t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id;
if (!destroy_sibling_or_exp(&t))
- DEBUGP("failed to timeout original pns->pac ct/exp\n");
+ pr_debug("failed to timeout original pns->pac ct/exp\n");
/* try reply (pac->pns) tuple */
memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t));
@@ -190,7 +187,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id;
t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id;
if (!destroy_sibling_or_exp(&t))
- DEBUGP("failed to timeout reply pac->pns ct/exp\n");
+ pr_debug("failed to timeout reply pac->pns ct/exp\n");
}
/* expect GRE connections (PNS->PAC and PAC->PNS direction) */
@@ -201,36 +198,36 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
int ret = 1;
typeof(nf_nat_pptp_hook_exp_gre) nf_nat_pptp_exp_gre;
- exp_orig = nf_conntrack_expect_alloc(ct);
+ exp_orig = nf_ct_expect_alloc(ct);
if (exp_orig == NULL)
goto out;
- exp_reply = nf_conntrack_expect_alloc(ct);
+ exp_reply = nf_ct_expect_alloc(ct);
if (exp_reply == NULL)
goto out_put_orig;
/* original direction, PNS->PAC */
dir = IP_CT_DIR_ORIGINAL;
- nf_conntrack_expect_init(exp_orig, ct->tuplehash[dir].tuple.src.l3num,
- &ct->tuplehash[dir].tuple.src.u3,
- &ct->tuplehash[dir].tuple.dst.u3,
- IPPROTO_GRE, &peer_callid, &callid);
+ nf_ct_expect_init(exp_orig, ct->tuplehash[dir].tuple.src.l3num,
+ &ct->tuplehash[dir].tuple.src.u3,
+ &ct->tuplehash[dir].tuple.dst.u3,
+ IPPROTO_GRE, &peer_callid, &callid);
exp_orig->expectfn = pptp_expectfn;
/* reply direction, PAC->PNS */
dir = IP_CT_DIR_REPLY;
- nf_conntrack_expect_init(exp_reply, ct->tuplehash[dir].tuple.src.l3num,
- &ct->tuplehash[dir].tuple.src.u3,
- &ct->tuplehash[dir].tuple.dst.u3,
- IPPROTO_GRE, &callid, &peer_callid);
+ nf_ct_expect_init(exp_reply, ct->tuplehash[dir].tuple.src.l3num,
+ &ct->tuplehash[dir].tuple.src.u3,
+ &ct->tuplehash[dir].tuple.dst.u3,
+ IPPROTO_GRE, &callid, &peer_callid);
exp_reply->expectfn = pptp_expectfn;
nf_nat_pptp_exp_gre = rcu_dereference(nf_nat_pptp_hook_exp_gre);
if (nf_nat_pptp_exp_gre && ct->status & IPS_NAT_MASK)
nf_nat_pptp_exp_gre(exp_orig, exp_reply);
- if (nf_conntrack_expect_related(exp_orig) != 0)
+ if (nf_ct_expect_related(exp_orig) != 0)
goto out_put_both;
- if (nf_conntrack_expect_related(exp_reply) != 0)
+ if (nf_ct_expect_related(exp_reply) != 0)
goto out_unexpect_orig;
/* Add GRE keymap entries */
@@ -243,16 +240,16 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
ret = 0;
out_put_both:
- nf_conntrack_expect_put(exp_reply);
+ nf_ct_expect_put(exp_reply);
out_put_orig:
- nf_conntrack_expect_put(exp_orig);
+ nf_ct_expect_put(exp_orig);
out:
return ret;
out_unexpect_both:
- nf_conntrack_unexpect_related(exp_reply);
+ nf_ct_unexpect_related(exp_reply);
out_unexpect_orig:
- nf_conntrack_unexpect_related(exp_orig);
+ nf_ct_unexpect_related(exp_orig);
goto out_put_both;
}
@@ -270,7 +267,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
typeof(nf_nat_pptp_hook_inbound) nf_nat_pptp_inbound;
msg = ntohs(ctlh->messageType);
- DEBUGP("inbound control message %s\n", pptp_msg_name[msg]);
+ pr_debug("inbound control message %s\n", pptp_msg_name[msg]);
switch (msg) {
case PPTP_START_SESSION_REPLY:
@@ -305,8 +302,8 @@ pptp_inbound_pkt(struct sk_buff **pskb,
pcid = pptpReq->ocack.peersCallID;
if (info->pns_call_id != pcid)
goto invalid;
- DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg],
- ntohs(cid), ntohs(pcid));
+ pr_debug("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg],
+ ntohs(cid), ntohs(pcid));
if (pptpReq->ocack.resultCode == PPTP_OUTCALL_CONNECT) {
info->cstate = PPTP_CALL_OUT_CONF;
@@ -322,7 +319,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
goto invalid;
cid = pptpReq->icreq.callID;
- DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
+ pr_debug("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
info->cstate = PPTP_CALL_IN_REQ;
info->pac_call_id = cid;
break;
@@ -341,7 +338,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
if (info->pns_call_id != pcid)
goto invalid;
- DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid));
+ pr_debug("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(pcid));
info->cstate = PPTP_CALL_IN_CONF;
/* we expect a GRE connection from PAC to PNS */
@@ -351,7 +348,7 @@ pptp_inbound_pkt(struct sk_buff **pskb,
case PPTP_CALL_DISCONNECT_NOTIFY:
/* server confirms disconnect */
cid = pptpReq->disc.callID;
- DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
+ pr_debug("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
info->cstate = PPTP_CALL_NONE;
/* untrack this call id, unexpect GRE packets */
@@ -374,11 +371,11 @@ pptp_inbound_pkt(struct sk_buff **pskb,
return NF_ACCEPT;
invalid:
- DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
- "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
- msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
- msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
- ntohs(info->pns_call_id), ntohs(info->pac_call_id));
+ pr_debug("invalid %s: type=%d cid=%u pcid=%u "
+ "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
+ msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
+ msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
+ ntohs(info->pns_call_id), ntohs(info->pac_call_id));
return NF_ACCEPT;
}
@@ -396,7 +393,7 @@ pptp_outbound_pkt(struct sk_buff **pskb,
typeof(nf_nat_pptp_hook_outbound) nf_nat_pptp_outbound;
msg = ntohs(ctlh->messageType);
- DEBUGP("outbound control message %s\n", pptp_msg_name[msg]);
+ pr_debug("outbound control message %s\n", pptp_msg_name[msg]);
switch (msg) {
case PPTP_START_SESSION_REQUEST:
@@ -418,7 +415,7 @@ pptp_outbound_pkt(struct sk_buff **pskb,
info->cstate = PPTP_CALL_OUT_REQ;
/* track PNS call id */
cid = pptpReq->ocreq.callID;
- DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
+ pr_debug("%s, CID=%X\n", pptp_msg_name[msg], ntohs(cid));
info->pns_call_id = cid;
break;
@@ -432,8 +429,8 @@ pptp_outbound_pkt(struct sk_buff **pskb,
pcid = pptpReq->icack.peersCallID;
if (info->pac_call_id != pcid)
goto invalid;
- DEBUGP("%s, CID=%X PCID=%X\n", pptp_msg_name[msg],
- ntohs(cid), ntohs(pcid));
+ pr_debug("%s, CID=%X PCID=%X\n", pptp_msg_name[msg],
+ ntohs(cid), ntohs(pcid));
if (pptpReq->icack.resultCode == PPTP_INCALL_ACCEPT) {
/* part two of the three-way handshake */
@@ -469,11 +466,11 @@ pptp_outbound_pkt(struct sk_buff **pskb,
return NF_ACCEPT;
invalid:
- DEBUGP("invalid %s: type=%d cid=%u pcid=%u "
- "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
- msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
- msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
- ntohs(info->pns_call_id), ntohs(info->pac_call_id));
+ pr_debug("invalid %s: type=%d cid=%u pcid=%u "
+ "cstate=%d sstate=%d pns_cid=%u pac_cid=%u\n",
+ msg <= PPTP_MSG_MAX ? pptp_msg_name[msg] : pptp_msg_name[0],
+ msg, ntohs(cid), ntohs(pcid), info->cstate, info->sstate,
+ ntohs(info->pns_call_id), ntohs(info->pac_call_id));
return NF_ACCEPT;
}
@@ -524,7 +521,7 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph);
if (!pptph) {
- DEBUGP("no full PPTP header, can't track\n");
+ pr_debug("no full PPTP header, can't track\n");
return NF_ACCEPT;
}
nexthdr_off += sizeof(_pptph);
@@ -533,7 +530,7 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
/* if it's not a control message we can't do anything with it */
if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL ||
ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) {
- DEBUGP("not a control packet\n");
+ pr_debug("not a control packet\n");
return NF_ACCEPT;
}
@@ -569,8 +566,8 @@ conntrack_pptp_help(struct sk_buff **pskb, unsigned int protoff,
/* server -> client (PAC -> PNS) */
ret = pptp_inbound_pkt(pskb, ctlh, pptpReq, reqlen, ct,
ctinfo);
- DEBUGP("sstate: %d->%d, cstate: %d->%d\n",
- oldsstate, info->sstate, oldcstate, info->cstate);
+ pr_debug("sstate: %d->%d, cstate: %d->%d\n",
+ oldsstate, info->sstate, oldcstate, info->cstate);
spin_unlock_bh(&nf_pptp_lock);
return ret;
@@ -585,9 +582,6 @@ static struct nf_conntrack_helper pptp __read_mostly = {
.tuple.src.l3num = AF_INET,
.tuple.src.u.tcp.port = __constant_htons(PPTP_CONTROL_PORT),
.tuple.dst.protonum = IPPROTO_TCP,
- .mask.src.l3num = 0xffff,
- .mask.src.u.tcp.port = __constant_htons(0xffff),
- .mask.dst.protonum = 0xff,
.help = conntrack_pptp_help,
.destroy = pptp_destroy_siblings,
};
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index 6faf1bed7224..d8b501878d9f 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -98,7 +98,7 @@ static struct ctl_table generic_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_generic =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
{
.l3proto = PF_UNSPEC,
.l4proto = 0,
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index 339c397d1b5f..bdbead8a7a83 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -40,12 +40,6 @@
#define GRE_TIMEOUT (30 * HZ)
#define GRE_STREAM_TIMEOUT (180 * HZ)
-#if 0
-#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args)
-#else
-#define DEBUGP(x, args...)
-#endif
-
static DEFINE_RWLOCK(nf_ct_gre_lock);
static LIST_HEAD(gre_keymap_list);
@@ -87,7 +81,7 @@ static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t)
}
read_unlock_bh(&nf_ct_gre_lock);
- DEBUGP("lookup src key 0x%x for ", key);
+ pr_debug("lookup src key 0x%x for ", key);
NF_CT_DUMP_TUPLE(t);
return key;
@@ -107,8 +101,8 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
if (gre_key_cmpfn(km, t) && km == *kmp)
return 0;
}
- DEBUGP("trying to override keymap_%s for ct %p\n",
- dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
+ pr_debug("trying to override keymap_%s for ct %p\n",
+ dir == IP_CT_DIR_REPLY ? "reply" : "orig", ct);
return -EEXIST;
}
@@ -118,7 +112,7 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
memcpy(&km->tuple, t, sizeof(*t));
*kmp = km;
- DEBUGP("adding new entry %p: ", km);
+ pr_debug("adding new entry %p: ", km);
NF_CT_DUMP_TUPLE(&km->tuple);
write_lock_bh(&nf_ct_gre_lock);
@@ -135,13 +129,13 @@ void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
struct nf_conn_help *help = nfct_help(ct);
enum ip_conntrack_dir dir;
- DEBUGP("entering for ct %p\n", ct);
+ pr_debug("entering for ct %p\n", ct);
write_lock_bh(&nf_ct_gre_lock);
for (dir = IP_CT_DIR_ORIGINAL; dir < IP_CT_DIR_MAX; dir++) {
if (help->help.ct_pptp_info.keymap[dir]) {
- DEBUGP("removing %p from list\n",
- help->help.ct_pptp_info.keymap[dir]);
+ pr_debug("removing %p from list\n",
+ help->help.ct_pptp_info.keymap[dir]);
list_del(&help->help.ct_pptp_info.keymap[dir]->list);
kfree(help->help.ct_pptp_info.keymap[dir]);
help->help.ct_pptp_info.keymap[dir] = NULL;
@@ -186,7 +180,7 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb,
return 1;
if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) {
- DEBUGP("GRE_VERSION_PPTP but unknown proto\n");
+ pr_debug("GRE_VERSION_PPTP but unknown proto\n");
return 0;
}
@@ -242,7 +236,7 @@ static int gre_packet(struct nf_conn *ct,
static int gre_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
{
- DEBUGP(": ");
+ pr_debug(": ");
NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
/* initialize to sane value. Ideally a conntrack helper
@@ -258,16 +252,16 @@ static int gre_new(struct nf_conn *ct, const struct sk_buff *skb,
static void gre_destroy(struct nf_conn *ct)
{
struct nf_conn *master = ct->master;
- DEBUGP(" entering\n");
+ pr_debug(" entering\n");
if (!master)
- DEBUGP("no master !?!\n");
+ pr_debug("no master !?!\n");
else
nf_ct_gre_keymap_destroy(master);
}
/* protocol helper struct */
-static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 = {
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
.l3proto = AF_INET,
.l4proto = IPPROTO_GRE,
.name = "gre",
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 0d3254b974c5..04192acc7c40 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -25,12 +25,6 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_ecache.h>
-#if 0
-#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Protects conntrack->proto.sctp */
static DEFINE_RWLOCK(sctp_lock);
@@ -151,9 +145,6 @@ static int sctp_pkt_to_tuple(const struct sk_buff *skb,
{
sctp_sctphdr_t _hdr, *hp;
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
/* Actually only need first 8 bytes. */
hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
if (hp == NULL)
@@ -167,9 +158,6 @@ static int sctp_pkt_to_tuple(const struct sk_buff *skb,
static int sctp_invert_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig)
{
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
tuple->src.u.sctp.port = orig->dst.u.sctp.port;
tuple->dst.u.sctp.port = orig->src.u.sctp.port;
return 1;
@@ -179,9 +167,6 @@ static int sctp_invert_tuple(struct nf_conntrack_tuple *tuple,
static int sctp_print_tuple(struct seq_file *s,
const struct nf_conntrack_tuple *tuple)
{
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
return seq_printf(s, "sport=%hu dport=%hu ",
ntohs(tuple->src.u.sctp.port),
ntohs(tuple->dst.u.sctp.port));
@@ -193,9 +178,6 @@ static int sctp_print_conntrack(struct seq_file *s,
{
enum sctp_conntrack state;
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
read_lock_bh(&sctp_lock);
state = conntrack->proto.sctp.state;
read_unlock_bh(&sctp_lock);
@@ -219,13 +201,10 @@ static int do_basic_checks(struct nf_conn *conntrack,
sctp_chunkhdr_t _sch, *sch;
int flag;
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
flag = 0;
for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) {
- DEBUGP("Chunk Num: %d Type: %d\n", count, sch->type);
+ pr_debug("Chunk Num: %d Type: %d\n", count, sch->type);
if (sch->type == SCTP_CID_INIT
|| sch->type == SCTP_CID_INIT_ACK
@@ -242,7 +221,7 @@ static int do_basic_checks(struct nf_conn *conntrack,
|| sch->type == SCTP_CID_COOKIE_ECHO
|| flag)
&& count !=0) || !sch->length) {
- DEBUGP("Basic checks failed\n");
+ pr_debug("Basic checks failed\n");
return 1;
}
@@ -251,7 +230,7 @@ static int do_basic_checks(struct nf_conn *conntrack,
}
}
- DEBUGP("Basic checks passed\n");
+ pr_debug("Basic checks passed\n");
return count == 0;
}
@@ -261,50 +240,47 @@ static int new_state(enum ip_conntrack_dir dir,
{
int i;
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
- DEBUGP("Chunk type: %d\n", chunk_type);
+ pr_debug("Chunk type: %d\n", chunk_type);
switch (chunk_type) {
case SCTP_CID_INIT:
- DEBUGP("SCTP_CID_INIT\n");
+ pr_debug("SCTP_CID_INIT\n");
i = 0; break;
case SCTP_CID_INIT_ACK:
- DEBUGP("SCTP_CID_INIT_ACK\n");
+ pr_debug("SCTP_CID_INIT_ACK\n");
i = 1; break;
case SCTP_CID_ABORT:
- DEBUGP("SCTP_CID_ABORT\n");
+ pr_debug("SCTP_CID_ABORT\n");
i = 2; break;
case SCTP_CID_SHUTDOWN:
- DEBUGP("SCTP_CID_SHUTDOWN\n");
+ pr_debug("SCTP_CID_SHUTDOWN\n");
i = 3; break;
case SCTP_CID_SHUTDOWN_ACK:
- DEBUGP("SCTP_CID_SHUTDOWN_ACK\n");
+ pr_debug("SCTP_CID_SHUTDOWN_ACK\n");
i = 4; break;
case SCTP_CID_ERROR:
- DEBUGP("SCTP_CID_ERROR\n");
+ pr_debug("SCTP_CID_ERROR\n");
i = 5; break;
case SCTP_CID_COOKIE_ECHO:
- DEBUGP("SCTP_CID_COOKIE_ECHO\n");
+ pr_debug("SCTP_CID_COOKIE_ECHO\n");
i = 6; break;
case SCTP_CID_COOKIE_ACK:
- DEBUGP("SCTP_CID_COOKIE_ACK\n");
+ pr_debug("SCTP_CID_COOKIE_ACK\n");
i = 7; break;
case SCTP_CID_SHUTDOWN_COMPLETE:
- DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n");
+ pr_debug("SCTP_CID_SHUTDOWN_COMPLETE\n");
i = 8; break;
default:
/* Other chunks like DATA, SACK, HEARTBEAT and
its ACK do not cause a change in state */
- DEBUGP("Unknown chunk type, Will stay in %s\n",
- sctp_conntrack_names[cur_state]);
+ pr_debug("Unknown chunk type, Will stay in %s\n",
+ sctp_conntrack_names[cur_state]);
return cur_state;
}
- DEBUGP("dir: %d cur_state: %s chunk_type: %d new_state: %s\n",
- dir, sctp_conntrack_names[cur_state], chunk_type,
- sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]);
+ pr_debug("dir: %d cur_state: %s chunk_type: %d new_state: %s\n",
+ dir, sctp_conntrack_names[cur_state], chunk_type,
+ sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]);
return sctp_conntracks[dir][i][cur_state];
}
@@ -323,9 +299,6 @@ static int sctp_packet(struct nf_conn *conntrack,
u_int32_t offset, count;
char map[256 / sizeof (char)] = {0};
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph);
if (sh == NULL)
return -1;
@@ -340,7 +313,7 @@ static int sctp_packet(struct nf_conn *conntrack,
&& !test_bit(SCTP_CID_ABORT, (void *)map)
&& !test_bit(SCTP_CID_SHUTDOWN_ACK, (void *)map)
&& (sh->vtag != conntrack->proto.sctp.vtag[CTINFO2DIR(ctinfo)])) {
- DEBUGP("Verification tag check failed\n");
+ pr_debug("Verification tag check failed\n");
return -1;
}
@@ -385,8 +358,9 @@ static int sctp_packet(struct nf_conn *conntrack,
/* Invalid */
if (newconntrack == SCTP_CONNTRACK_MAX) {
- DEBUGP("nf_conntrack_sctp: Invalid dir=%i ctype=%u conntrack=%u\n",
- CTINFO2DIR(ctinfo), sch->type, oldsctpstate);
+ pr_debug("nf_conntrack_sctp: Invalid dir=%i ctype=%u "
+ "conntrack=%u\n",
+ CTINFO2DIR(ctinfo), sch->type, oldsctpstate);
write_unlock_bh(&sctp_lock);
return -1;
}
@@ -402,8 +376,8 @@ static int sctp_packet(struct nf_conn *conntrack,
write_unlock_bh(&sctp_lock);
return -1;
}
- DEBUGP("Setting vtag %x for dir %d\n",
- ih->init_tag, !CTINFO2DIR(ctinfo));
+ pr_debug("Setting vtag %x for dir %d\n",
+ ih->init_tag, !CTINFO2DIR(ctinfo));
conntrack->proto.sctp.vtag[!CTINFO2DIR(ctinfo)] = ih->init_tag;
}
@@ -418,7 +392,7 @@ static int sctp_packet(struct nf_conn *conntrack,
if (oldsctpstate == SCTP_CONNTRACK_COOKIE_ECHOED
&& CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY
&& newconntrack == SCTP_CONNTRACK_ESTABLISHED) {
- DEBUGP("Setting assured bit\n");
+ pr_debug("Setting assured bit\n");
set_bit(IPS_ASSURED_BIT, &conntrack->status);
nf_conntrack_event_cache(IPCT_STATUS, skb);
}
@@ -436,9 +410,6 @@ static int sctp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
u_int32_t offset, count;
char map[256 / sizeof (char)] = {0};
- DEBUGP(__FUNCTION__);
- DEBUGP("\n");
-
sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph);
if (sh == NULL)
return 0;
@@ -460,8 +431,9 @@ static int sctp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
SCTP_CONNTRACK_NONE, sch->type);
/* Invalid: delete conntrack */
- if (newconntrack == SCTP_CONNTRACK_MAX) {
- DEBUGP("nf_conntrack_sctp: invalid new deleting.\n");
+ if (newconntrack == SCTP_CONNTRACK_NONE ||
+ newconntrack == SCTP_CONNTRACK_MAX) {
+ pr_debug("nf_conntrack_sctp: invalid new deleting.\n");
return 0;
}
@@ -475,8 +447,8 @@ static int sctp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
if (ih == NULL)
return 0;
- DEBUGP("Setting vtag %x for new conn\n",
- ih->init_tag);
+ pr_debug("Setting vtag %x for new conn\n",
+ ih->init_tag);
conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] =
ih->init_tag;
@@ -488,8 +460,8 @@ static int sctp_new(struct nf_conn *conntrack, const struct sk_buff *skb,
/* If it is a shutdown ack OOTB packet, we expect a return
shutdown complete, otherwise an ABORT Sec 8.4 (5) and (8) */
else {
- DEBUGP("Setting vtag %x for new conn OOTB\n",
- sh->vtag);
+ pr_debug("Setting vtag %x for new conn OOTB\n",
+ sh->vtag);
conntrack->proto.sctp.vtag[IP_CT_DIR_REPLY] = sh->vtag;
}
@@ -629,7 +601,7 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif
-struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = {
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.l3proto = PF_INET,
.l4proto = IPPROTO_SCTP,
.name = "sctp",
@@ -650,7 +622,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 = {
#endif
};
-struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 = {
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
.l3proto = PF_INET6,
.l4proto = IPPROTO_SCTP,
.name = "sctp",
@@ -688,8 +660,6 @@ int __init nf_conntrack_proto_sctp_init(void)
cleanup_sctp4:
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
out:
- DEBUGP("SCTP conntrack module loading %s\n",
- ret ? "failed": "succeeded");
return ret;
}
@@ -697,7 +667,6 @@ void __exit nf_conntrack_proto_sctp_fini(void)
{
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
- DEBUGP("SCTP conntrack module unloaded\n");
}
module_init(nf_conntrack_proto_sctp_init);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ccdd5d231e0d..87ad3ccf8aff 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -26,13 +26,6 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_ecache.h>
-#if 0
-#define DEBUGP printk
-#define DEBUGP_VARS
-#else
-#define DEBUGP(format, args...)
-#endif
-
/* Protects conntrack->proto.tcp */
static DEFINE_RWLOCK(tcp_lock);
@@ -496,7 +489,8 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
}
}
-static int tcp_in_window(struct ip_ct_tcp *state,
+static int tcp_in_window(struct nf_conn *ct,
+ struct ip_ct_tcp *state,
enum ip_conntrack_dir dir,
unsigned int index,
const struct sk_buff *skb,
@@ -506,6 +500,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
{
struct ip_ct_tcp_state *sender = &state->seen[dir];
struct ip_ct_tcp_state *receiver = &state->seen[!dir];
+ struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
__u32 seq, ack, sack, end, win, swin;
int res;
@@ -520,18 +515,17 @@ static int tcp_in_window(struct ip_ct_tcp *state,
if (receiver->flags & IP_CT_TCP_FLAG_SACK_PERM)
tcp_sack(skb, dataoff, tcph, &sack);
- DEBUGP("tcp_in_window: START\n");
- DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
- "seq=%u ack=%u sack=%u win=%u end=%u\n",
- NIPQUAD(iph->saddr), ntohs(tcph->source),
- NIPQUAD(iph->daddr), ntohs(tcph->dest),
- seq, ack, sack, win, end);
- DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
- "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
- sender->td_end, sender->td_maxend, sender->td_maxwin,
- sender->td_scale,
- receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
- receiver->td_scale);
+ pr_debug("tcp_in_window: START\n");
+ pr_debug("tcp_in_window: ");
+ NF_CT_DUMP_TUPLE(tuple);
+ pr_debug("seq=%u ack=%u sack=%u win=%u end=%u\n",
+ seq, ack, sack, win, end);
+ pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
if (sender->td_end == 0) {
/*
@@ -609,23 +603,22 @@ static int tcp_in_window(struct ip_ct_tcp *state,
*/
seq = end = sender->td_end;
- DEBUGP("tcp_in_window: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
- "seq=%u ack=%u sack =%u win=%u end=%u\n",
- NIPQUAD(iph->saddr), ntohs(tcph->source),
- NIPQUAD(iph->daddr), ntohs(tcph->dest),
- seq, ack, sack, win, end);
- DEBUGP("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
- "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
- sender->td_end, sender->td_maxend, sender->td_maxwin,
- sender->td_scale,
- receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
- receiver->td_scale);
-
- DEBUGP("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
- before(seq, sender->td_maxend + 1),
- after(end, sender->td_end - receiver->td_maxwin - 1),
- before(sack, receiver->td_end + 1),
- after(ack, receiver->td_end - MAXACKWINDOW(sender)));
+ pr_debug("tcp_in_window: ");
+ NF_CT_DUMP_TUPLE(tuple);
+ pr_debug("seq=%u ack=%u sack =%u win=%u end=%u\n",
+ seq, ack, sack, win, end);
+ pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
+
+ pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
+ before(seq, sender->td_maxend + 1),
+ after(end, sender->td_end - receiver->td_maxwin - 1),
+ before(sack, receiver->td_end + 1),
+ after(ack, receiver->td_end - MAXACKWINDOW(sender)));
if (before(seq, sender->td_maxend + 1) &&
after(end, sender->td_end - receiver->td_maxwin - 1) &&
@@ -694,10 +687,10 @@ static int tcp_in_window(struct ip_ct_tcp *state,
: "SEQ is over the upper bound (over the window of the receiver)");
}
- DEBUGP("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
- "receiver end=%u maxend=%u maxwin=%u\n",
- res, sender->td_end, sender->td_maxend, sender->td_maxwin,
- receiver->td_end, receiver->td_maxend, receiver->td_maxwin);
+ pr_debug("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u "
+ "receiver end=%u maxend=%u maxwin=%u\n",
+ res, sender->td_end, sender->td_maxend, sender->td_maxwin,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin);
return res;
}
@@ -711,11 +704,9 @@ void nf_conntrack_tcp_update(struct sk_buff *skb,
int dir)
{
struct tcphdr *tcph = (void *)skb->data + dataoff;
- __u32 end;
-#ifdef DEBUGP_VARS
struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[dir];
struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[!dir];
-#endif
+ __u32 end;
end = segment_seq_plus_len(ntohl(tcph->seq), skb->len, dataoff, tcph);
@@ -727,12 +718,12 @@ void nf_conntrack_tcp_update(struct sk_buff *skb,
conntrack->proto.tcp.seen[dir].td_end = end;
conntrack->proto.tcp.last_end = end;
write_unlock_bh(&tcp_lock);
- DEBUGP("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
- "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
- sender->td_end, sender->td_maxend, sender->td_maxwin,
- sender->td_scale,
- receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
- receiver->td_scale);
+ pr_debug("tcp_update: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
}
EXPORT_SYMBOL_GPL(nf_conntrack_tcp_update);
#endif
@@ -823,6 +814,7 @@ static int tcp_packet(struct nf_conn *conntrack,
int pf,
unsigned int hooknum)
{
+ struct nf_conntrack_tuple *tuple;
enum tcp_conntrack new_state, old_state;
enum ip_conntrack_dir dir;
struct tcphdr *th, _tcph;
@@ -837,6 +829,7 @@ static int tcp_packet(struct nf_conn *conntrack,
dir = CTINFO2DIR(ctinfo);
index = get_conntrack_index(th);
new_state = tcp_conntracks[dir][index][old_state];
+ tuple = &conntrack->tuplehash[dir].tuple;
switch (new_state) {
case TCP_CONNTRACK_IGNORE:
@@ -880,9 +873,8 @@ static int tcp_packet(struct nf_conn *conntrack,
return NF_ACCEPT;
case TCP_CONNTRACK_MAX:
/* Invalid packet */
- DEBUGP("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",
- dir, get_conntrack_index(th),
- old_state);
+ pr_debug("nf_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",
+ dir, get_conntrack_index(th), old_state);
write_unlock_bh(&tcp_lock);
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
@@ -933,7 +925,7 @@ static int tcp_packet(struct nf_conn *conntrack,
break;
}
- if (!tcp_in_window(&conntrack->proto.tcp, dir, index,
+ if (!tcp_in_window(conntrack, &conntrack->proto.tcp, dir, index,
skb, dataoff, th, pf)) {
write_unlock_bh(&tcp_lock);
return -NF_ACCEPT;
@@ -942,13 +934,12 @@ static int tcp_packet(struct nf_conn *conntrack,
/* From now on we have got in-window packets */
conntrack->proto.tcp.last_index = index;
- DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
- "syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",
- NIPQUAD(iph->saddr), ntohs(th->source),
- NIPQUAD(iph->daddr), ntohs(th->dest),
- (th->syn ? 1 : 0), (th->ack ? 1 : 0),
- (th->fin ? 1 : 0), (th->rst ? 1 : 0),
- old_state, new_state);
+ pr_debug("tcp_conntracks: ");
+ NF_CT_DUMP_TUPLE(tuple);
+ pr_debug("syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",
+ (th->syn ? 1 : 0), (th->ack ? 1 : 0),
+ (th->fin ? 1 : 0), (th->rst ? 1 : 0),
+ old_state, new_state);
conntrack->proto.tcp.state = new_state;
if (old_state != new_state
@@ -997,10 +988,8 @@ static int tcp_new(struct nf_conn *conntrack,
{
enum tcp_conntrack new_state;
struct tcphdr *th, _tcph;
-#ifdef DEBUGP_VARS
struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
-#endif
th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
BUG_ON(th == NULL);
@@ -1012,7 +1001,7 @@ static int tcp_new(struct nf_conn *conntrack,
/* Invalid: delete conntrack */
if (new_state >= TCP_CONNTRACK_MAX) {
- DEBUGP("nf_ct_tcp: invalid new deleting.\n");
+ pr_debug("nf_ct_tcp: invalid new deleting.\n");
return 0;
}
@@ -1065,12 +1054,12 @@ static int tcp_new(struct nf_conn *conntrack,
conntrack->proto.tcp.state = TCP_CONNTRACK_NONE;
conntrack->proto.tcp.last_index = TCP_NONE_SET;
- DEBUGP("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
- "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
- sender->td_end, sender->td_maxend, sender->td_maxwin,
- sender->td_scale,
- receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
- receiver->td_scale);
+ pr_debug("tcp_new: sender end=%u maxend=%u maxwin=%u scale=%i "
+ "receiver end=%u maxend=%u maxwin=%u scale=%i\n",
+ sender->td_end, sender->td_maxend, sender->td_maxwin,
+ sender->td_scale,
+ receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
+ receiver->td_scale);
return 1;
}
@@ -1383,7 +1372,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
{
.l3proto = PF_INET,
.l4proto = IPPROTO_TCP,
@@ -1412,7 +1401,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 =
};
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
-struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
{
.l3proto = PF_INET6,
.l4proto = IPPROTO_TCP,
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 3620ecc095fd..13d94a025723 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -191,7 +191,7 @@ static struct ctl_table udp_compat_sysctl_table[] = {
#endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
#endif /* CONFIG_SYSCTL */
-struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
{
.l3proto = PF_INET,
.l4proto = IPPROTO_UDP,
@@ -218,7 +218,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 =
};
EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
-struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 =
+struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
{
.l3proto = PF_INET6,
.l4proto = IPPROTO_UDP,
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
new file mode 100644
index 000000000000..93e747b5396e
--- /dev/null
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -0,0 +1,266 @@
+/* (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ * (C) 2007 Patrick McHardy <kaber@trash.net>
+ *
+ * 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/types.h>
+#include <linux/timer.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/udp.h>
+#include <linux/seq_file.h>
+#include <linux/skbuff.h>
+#include <linux/ipv6.h>
+#include <net/ip6_checksum.h>
+#include <net/checksum.h>
+
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
+#include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_ecache.h>
+
+static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ;
+static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ;
+
+static int udplite_pkt_to_tuple(const struct sk_buff *skb,
+ unsigned int dataoff,
+ struct nf_conntrack_tuple *tuple)
+{
+ struct udphdr _hdr, *hp;
+
+ hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hp == NULL)
+ return 0;
+
+ tuple->src.u.udp.port = hp->source;
+ tuple->dst.u.udp.port = hp->dest;
+ return 1;
+}
+
+static int udplite_invert_tuple(struct nf_conntrack_tuple *tuple,
+ const struct nf_conntrack_tuple *orig)
+{
+ tuple->src.u.udp.port = orig->dst.u.udp.port;
+ tuple->dst.u.udp.port = orig->src.u.udp.port;
+ return 1;
+}
+
+/* Print out the per-protocol part of the tuple. */
+static int udplite_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
+{
+ return seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.udp.port),
+ ntohs(tuple->dst.u.udp.port));
+}
+
+/* Print out the private part of the conntrack. */
+static int udplite_print_conntrack(struct seq_file *s,
+ const struct nf_conn *conntrack)
+{
+ return 0;
+}
+
+/* Returns verdict for packet, and may modify conntracktype */
+static int udplite_packet(struct nf_conn *conntrack,
+ const struct sk_buff *skb,
+ unsigned int dataoff,
+ enum ip_conntrack_info ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ /* If we've seen traffic both ways, this is some kind of UDP
+ stream. Extend timeout. */
+ if (test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)) {
+ nf_ct_refresh_acct(conntrack, ctinfo, skb,
+ nf_ct_udplite_timeout_stream);
+ /* Also, more likely to be important, and not a probe */
+ if (!test_and_set_bit(IPS_ASSURED_BIT, &conntrack->status))
+ nf_conntrack_event_cache(IPCT_STATUS, skb);
+ } else
+ nf_ct_refresh_acct(conntrack, ctinfo, skb,
+ nf_ct_udplite_timeout);
+
+ return NF_ACCEPT;
+}
+
+/* Called when a new connection for this protocol found. */
+static int udplite_new(struct nf_conn *conntrack, const struct sk_buff *skb,
+ unsigned int dataoff)
+{
+ return 1;
+}
+
+static int udplite_error(struct sk_buff *skb, unsigned int dataoff,
+ enum ip_conntrack_info *ctinfo,
+ int pf,
+ unsigned int hooknum)
+{
+ unsigned int udplen = skb->len - dataoff;
+ struct udphdr _hdr, *hdr;
+ unsigned int cscov;
+
+ /* Header is too small? */
+ hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
+ if (hdr == NULL) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: short packet ");
+ return -NF_ACCEPT;
+ }
+
+ cscov = ntohs(hdr->len);
+ if (cscov == 0)
+ cscov = udplen;
+ else if (cscov < sizeof(*hdr) || cscov > udplen) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: invalid checksum coverage ");
+ return -NF_ACCEPT;
+ }
+
+ /* UDPLITE mandates checksums */
+ if (!hdr->check) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: checksum missing ");
+ return -NF_ACCEPT;
+ }
+
+ /* Checksum invalid? Ignore. */
+ if (nf_conntrack_checksum && !skb_csum_unnecessary(skb) &&
+ ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
+ (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING))) {
+ if (pf == PF_INET) {
+ struct iphdr *iph = ip_hdr(skb);
+
+ skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr,
+ udplen, IPPROTO_UDPLITE, 0);
+ } else {
+ struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+ __wsum hsum = skb_checksum(skb, 0, dataoff, 0);
+
+ skb->csum = ~csum_unfold(
+ csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
+ udplen, IPPROTO_UDPLITE,
+ csum_sub(0, hsum)));
+ }
+
+ skb->ip_summed = CHECKSUM_NONE;
+ if (__skb_checksum_complete_head(skb, dataoff + cscov)) {
+ if (LOG_INVALID(IPPROTO_UDPLITE))
+ nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
+ "nf_ct_udplite: bad UDPLite "
+ "checksum ");
+ return -NF_ACCEPT;
+ }
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
+
+ return NF_ACCEPT;
+}
+
+#ifdef CONFIG_SYSCTL
+static unsigned int udplite_sysctl_table_users;
+static struct ctl_table_header *udplite_sysctl_header;
+static struct ctl_table udplite_sysctl_table[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nf_conntrack_udplite_timeout",
+ .data = &nf_ct_udplite_timeout,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nf_conntrack_udplite_timeout_stream",
+ .data = &nf_ct_udplite_timeout_stream,
+ .maxlen = sizeof(unsigned int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_jiffies,
+ },
+ {
+ .ctl_name = 0
+ }
+};
+#endif /* CONFIG_SYSCTL */
+
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
+{
+ .l3proto = PF_INET,
+ .l4proto = IPPROTO_UDPLITE,
+ .name = "udplite",
+ .pkt_to_tuple = udplite_pkt_to_tuple,
+ .invert_tuple = udplite_invert_tuple,
+ .print_tuple = udplite_print_tuple,
+ .print_conntrack = udplite_print_conntrack,
+ .packet = udplite_packet,
+ .new = udplite_new,
+ .error = udplite_error,
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
+ .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
+#endif
+#ifdef CONFIG_SYSCTL
+ .ctl_table_users = &udplite_sysctl_table_users,
+ .ctl_table_header = &udplite_sysctl_header,
+ .ctl_table = udplite_sysctl_table,
+#endif
+};
+
+static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
+{
+ .l3proto = PF_INET6,
+ .l4proto = IPPROTO_UDPLITE,
+ .name = "udplite",
+ .pkt_to_tuple = udplite_pkt_to_tuple,
+ .invert_tuple = udplite_invert_tuple,
+ .print_tuple = udplite_print_tuple,
+ .print_conntrack = udplite_print_conntrack,
+ .packet = udplite_packet,
+ .new = udplite_new,
+ .error = udplite_error,
+#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
+ .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
+ .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
+#endif
+#ifdef CONFIG_SYSCTL
+ .ctl_table_users = &udplite_sysctl_table_users,
+ .ctl_table_header = &udplite_sysctl_header,
+ .ctl_table = udplite_sysctl_table,
+#endif
+};
+
+static int __init nf_conntrack_proto_udplite_init(void)
+{
+ int err;
+
+ err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite4);
+ if (err < 0)
+ goto err1;
+ err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite6);
+ if (err < 0)
+ goto err2;
+ return 0;
+err2:
+ nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
+err1:
+ return err;
+}
+
+static void __exit nf_conntrack_proto_udplite_exit(void)
+{
+ nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
+ nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
+}
+
+module_init(nf_conntrack_proto_udplite_init);
+module_exit(nf_conntrack_proto_udplite_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c
index eb2d1dc46d45..355d371bac93 100644
--- a/net/netfilter/nf_conntrack_sane.c
+++ b/net/netfilter/nf_conntrack_sane.c
@@ -40,12 +40,6 @@ static u_int16_t ports[MAX_PORTS];
static unsigned int ports_c;
module_param_array(ports, ushort, &ports_c, 0400);
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
struct sane_request {
__be32 RPC_code;
#define SANE_NET_START 7 /* RPC code */
@@ -125,15 +119,15 @@ static int help(struct sk_buff **pskb,
ct_sane_info->state = SANE_STATE_NORMAL;
if (datalen < sizeof(struct sane_reply_net_start)) {
- DEBUGP("nf_ct_sane: NET_START reply too short\n");
+ pr_debug("nf_ct_sane: NET_START reply too short\n");
goto out;
}
reply = (struct sane_reply_net_start *)sb_ptr;
if (reply->status != htonl(SANE_STATUS_SUCCESS)) {
/* saned refused the command */
- DEBUGP("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
- ntohl(reply->status));
+ pr_debug("nf_ct_sane: unsuccessful SANE_STATUS = %u\n",
+ ntohl(reply->status));
goto out;
}
@@ -141,35 +135,32 @@ static int help(struct sk_buff **pskb,
if (reply->zero != 0)
goto out;
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (exp == NULL) {
ret = NF_DROP;
goto out;
}
tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
- nf_conntrack_expect_init(exp, family,
- &tuple->src.u3, &tuple->dst.u3,
- IPPROTO_TCP,
- NULL, &reply->port);
+ nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+ IPPROTO_TCP, NULL, &reply->port);
- DEBUGP("nf_ct_sane: expect: ");
+ pr_debug("nf_ct_sane: expect: ");
NF_CT_DUMP_TUPLE(&exp->tuple);
- NF_CT_DUMP_TUPLE(&exp->mask);
/* Can't expect this? Best to drop packet now. */
- if (nf_conntrack_expect_related(exp) != 0)
+ if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
out:
spin_unlock_bh(&nf_sane_lock);
return ret;
}
-static struct nf_conntrack_helper sane[MAX_PORTS][2];
-static char sane_names[MAX_PORTS][2][sizeof("sane-65535")];
+static struct nf_conntrack_helper sane[MAX_PORTS][2] __read_mostly;
+static char sane_names[MAX_PORTS][2][sizeof("sane-65535")] __read_mostly;
/* don't make this __exit, since it's called from __init ! */
static void nf_conntrack_sane_fini(void)
@@ -178,9 +169,9 @@ static void nf_conntrack_sane_fini(void)
for (i = 0; i < ports_c; i++) {
for (j = 0; j < 2; j++) {
- DEBUGP("nf_ct_sane: unregistering helper for pf: %d "
- "port: %d\n",
- sane[i][j].tuple.src.l3num, ports[i]);
+ pr_debug("nf_ct_sane: unregistering helper for pf: %d "
+ "port: %d\n",
+ sane[i][j].tuple.src.l3num, ports[i]);
nf_conntrack_helper_unregister(&sane[i][j]);
}
}
@@ -208,8 +199,6 @@ static int __init nf_conntrack_sane_init(void)
for (j = 0; j < 2; j++) {
sane[i][j].tuple.src.u.tcp.port = htons(ports[i]);
sane[i][j].tuple.dst.protonum = IPPROTO_TCP;
- sane[i][j].mask.src.u.tcp.port = 0xFFFF;
- sane[i][j].mask.dst.protonum = 0xFF;
sane[i][j].max_expected = 1;
sane[i][j].timeout = 5 * 60; /* 5 Minutes */
sane[i][j].me = THIS_MODULE;
@@ -221,9 +210,9 @@ static int __init nf_conntrack_sane_init(void)
sprintf(tmpname, "sane-%d", ports[i]);
sane[i][j].name = tmpname;
- DEBUGP("nf_ct_sane: registering helper for pf: %d "
- "port: %d\n",
- sane[i][j].tuple.src.l3num, ports[i]);
+ pr_debug("nf_ct_sane: registering helper for pf: %d "
+ "port: %d\n",
+ sane[i][j].tuple.src.l3num, ports[i]);
ret = nf_conntrack_helper_register(&sane[i][j]);
if (ret) {
printk(KERN_ERR "nf_ct_sane: failed to "
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 1b5c6c1055f7..1276a442f10c 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -21,12 +21,6 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <linux/netfilter/nf_conntrack_sip.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
MODULE_DESCRIPTION("SIP connection tracking helper");
@@ -285,7 +279,7 @@ static int epaddr_len(struct nf_conn *ct, const char *dptr,
const char *aux = dptr;
if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
- DEBUGP("ip: %s parse failed.!\n", dptr);
+ pr_debug("ip: %s parse failed.!\n", dptr);
return 0;
}
@@ -344,8 +338,8 @@ int ct_sip_get_info(struct nf_conn *ct,
ct_sip_lnlen(dptr, limit),
hnfo->case_sensitive);
if (!aux) {
- DEBUGP("'%s' not found in '%s'.\n", hnfo->ln_str,
- hnfo->lname);
+ pr_debug("'%s' not found in '%s'.\n", hnfo->ln_str,
+ hnfo->lname);
return -1;
}
aux += hnfo->ln_strlen;
@@ -356,11 +350,11 @@ int ct_sip_get_info(struct nf_conn *ct,
*matchoff = (aux - k) + shift;
- DEBUGP("%s match succeeded! - len: %u\n", hnfo->lname,
- *matchlen);
+ pr_debug("%s match succeeded! - len: %u\n", hnfo->lname,
+ *matchlen);
return 1;
}
- DEBUGP("%s header not found.\n", hnfo->lname);
+ pr_debug("%s header not found.\n", hnfo->lname);
return 0;
}
EXPORT_SYMBOL_GPL(ct_sip_get_info);
@@ -378,23 +372,23 @@ static int set_expected_rtp(struct sk_buff **pskb,
int ret;
typeof(nf_nat_sdp_hook) nf_nat_sdp;
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (exp == NULL)
return NF_DROP;
- nf_conntrack_expect_init(exp, family,
- &ct->tuplehash[!dir].tuple.src.u3, addr,
- IPPROTO_UDP, NULL, &port);
+ nf_ct_expect_init(exp, family,
+ &ct->tuplehash[!dir].tuple.src.u3, addr,
+ IPPROTO_UDP, NULL, &port);
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
if (nf_nat_sdp && ct->status & IPS_NAT_MASK)
ret = nf_nat_sdp(pskb, ctinfo, exp, dptr);
else {
- if (nf_conntrack_expect_related(exp) != 0)
+ if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
else
ret = NF_ACCEPT;
}
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
return ret;
}
@@ -424,7 +418,7 @@ static int sip_help(struct sk_buff **pskb,
if (!skb_is_nonlinear(*pskb))
dptr = (*pskb)->data + dataoff;
else {
- DEBUGP("Copy of skbuff not supported yet.\n");
+ pr_debug("Copy of skbuff not supported yet.\n");
goto out;
}
@@ -506,9 +500,6 @@ static int __init nf_conntrack_sip_init(void)
for (j = 0; j < 2; j++) {
sip[i][j].tuple.dst.protonum = IPPROTO_UDP;
sip[i][j].tuple.src.u.udp.port = htons(ports[i]);
- sip[i][j].mask.src.l3num = 0xFFFF;
- sip[i][j].mask.src.u.udp.port = htons(0xFFFF);
- sip[i][j].mask.dst.protonum = 0xFF;
sip[i][j].max_expected = 2;
sip[i][j].timeout = 3 * 60; /* 3 minutes */
sip[i][j].me = THIS_MODULE;
@@ -521,7 +512,7 @@ static int __init nf_conntrack_sip_init(void)
sprintf(tmpname, "sip-%u", i);
sip[i][j].name = tmpname;
- DEBUGP("port #%u: %u\n", i, ports[i]);
+ pr_debug("port #%u: %u\n", i, ports[i]);
ret = nf_conntrack_helper_register(&sip[i][j]);
if (ret) {
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index 45baeb0e30f9..a4ce5e887997 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -25,12 +25,6 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_helper.h>
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
MODULE_LICENSE("GPL");
#ifdef CONFIG_PROC_FS
@@ -60,35 +54,36 @@ struct ct_iter_state {
unsigned int bucket;
};
-static struct list_head *ct_get_first(struct seq_file *seq)
+static struct hlist_node *ct_get_first(struct seq_file *seq)
{
struct ct_iter_state *st = seq->private;
for (st->bucket = 0;
st->bucket < nf_conntrack_htable_size;
st->bucket++) {
- if (!list_empty(&nf_conntrack_hash[st->bucket]))
- return nf_conntrack_hash[st->bucket].next;
+ if (!hlist_empty(&nf_conntrack_hash[st->bucket]))
+ return nf_conntrack_hash[st->bucket].first;
}
return NULL;
}
-static struct list_head *ct_get_next(struct seq_file *seq, struct list_head *head)
+static struct hlist_node *ct_get_next(struct seq_file *seq,
+ struct hlist_node *head)
{
struct ct_iter_state *st = seq->private;
head = head->next;
- while (head == &nf_conntrack_hash[st->bucket]) {
+ while (head == NULL) {
if (++st->bucket >= nf_conntrack_htable_size)
return NULL;
- head = nf_conntrack_hash[st->bucket].next;
+ head = nf_conntrack_hash[st->bucket].first;
}
return head;
}
-static struct list_head *ct_get_idx(struct seq_file *seq, loff_t pos)
+static struct hlist_node *ct_get_idx(struct seq_file *seq, loff_t pos)
{
- struct list_head *head = ct_get_first(seq);
+ struct hlist_node *head = ct_get_first(seq);
if (head)
while (pos && (head = ct_get_next(seq, head)))
@@ -186,11 +181,11 @@ static int ct_seq_show(struct seq_file *s, void *v)
if (seq_printf(s, "use=%u\n", atomic_read(&conntrack->ct_general.use)))
return -ENOSPC;
-
+
return 0;
}
-static struct seq_operations ct_seq_ops = {
+static const struct seq_operations ct_seq_ops = {
.start = ct_seq_start,
.next = ct_seq_next,
.stop = ct_seq_stop,
@@ -203,7 +198,7 @@ static int ct_open(struct inode *inode, struct file *file)
struct ct_iter_state *st;
int ret;
- st = kmalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
+ st = kzalloc(sizeof(struct ct_iter_state), GFP_KERNEL);
if (st == NULL)
return -ENOMEM;
ret = seq_open(file, &ct_seq_ops);
@@ -211,7 +206,6 @@ static int ct_open(struct inode *inode, struct file *file)
goto out_free;
seq = file->private_data;
seq->private = st;
- memset(st, 0, sizeof(struct ct_iter_state));
return ret;
out_free:
kfree(st);
@@ -294,7 +288,7 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations ct_cpu_seq_ops = {
+static const struct seq_operations ct_cpu_seq_ops = {
.start = ct_cpu_seq_start,
.next = ct_cpu_seq_next,
.stop = ct_cpu_seq_stop,
@@ -371,7 +365,14 @@ static ctl_table nf_ct_sysctl_table[] = {
.extra1 = &log_invalid_proto_min,
.extra2 = &log_invalid_proto_max,
},
-
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nf_conntrack_expect_max",
+ .data = &nf_ct_expect_max,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
{ .ctl_name = 0 }
};
@@ -410,7 +411,7 @@ EXPORT_SYMBOL_GPL(nf_ct_log_invalid);
static int __init nf_conntrack_standalone_init(void)
{
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *proc, *proc_exp, *proc_stat;
+ struct proc_dir_entry *proc, *proc_stat;
#endif
int ret = 0;
@@ -422,13 +423,9 @@ static int __init nf_conntrack_standalone_init(void)
proc = proc_net_fops_create("nf_conntrack", 0440, &ct_file_ops);
if (!proc) goto cleanup_init;
- proc_exp = proc_net_fops_create("nf_conntrack_expect", 0440,
- &exp_file_ops);
- if (!proc_exp) goto cleanup_proc;
-
proc_stat = create_proc_entry("nf_conntrack", S_IRUGO, proc_net_stat);
if (!proc_stat)
- goto cleanup_proc_exp;
+ goto cleanup_proc;
proc_stat->proc_fops = &ct_cpu_seq_fops;
proc_stat->owner = THIS_MODULE;
@@ -448,8 +445,6 @@ static int __init nf_conntrack_standalone_init(void)
#endif
#ifdef CONFIG_PROC_FS
remove_proc_entry("nf_conntrack", proc_net_stat);
- cleanup_proc_exp:
- proc_net_remove("nf_conntrack_expect");
cleanup_proc:
proc_net_remove("nf_conntrack");
cleanup_init:
@@ -465,7 +460,6 @@ static void __exit nf_conntrack_standalone_fini(void)
#endif
#ifdef CONFIG_PROC_FS
remove_proc_entry("nf_conntrack", proc_net_stat);
- proc_net_remove("nf_conntrack_expect");
proc_net_remove("nf_conntrack");
#endif /* CNFIG_PROC_FS */
nf_conntrack_cleanup();
diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c
index 37c4542e3112..cc19506cf2f8 100644
--- a/net/netfilter/nf_conntrack_tftp.c
+++ b/net/netfilter/nf_conntrack_tftp.c
@@ -29,13 +29,6 @@ static int ports_c;
module_param_array(ports, ushort, &ports_c, 0400);
MODULE_PARM_DESC(ports, "Port numbers of TFTP servers");
-#if 0
-#define DEBUGP(format, args...) printk("%s:%s:" format, \
- __FILE__, __FUNCTION__ , ## args)
-#else
-#define DEBUGP(format, args...)
-#endif
-
unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
struct nf_conntrack_expect *exp) __read_mostly;
@@ -62,39 +55,35 @@ static int tftp_help(struct sk_buff **pskb,
case TFTP_OPCODE_READ:
case TFTP_OPCODE_WRITE:
/* RRQ and WRQ works the same way */
- DEBUGP("");
NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
- exp = nf_conntrack_expect_alloc(ct);
+ exp = nf_ct_expect_alloc(ct);
if (exp == NULL)
return NF_DROP;
tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
- nf_conntrack_expect_init(exp, family,
- &tuple->src.u3, &tuple->dst.u3,
- IPPROTO_UDP,
- NULL, &tuple->dst.u.udp.port);
+ nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3,
+ IPPROTO_UDP, NULL, &tuple->dst.u.udp.port);
- DEBUGP("expect: ");
+ pr_debug("expect: ");
NF_CT_DUMP_TUPLE(&exp->tuple);
- NF_CT_DUMP_TUPLE(&exp->mask);
nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
ret = nf_nat_tftp(pskb, ctinfo, exp);
- else if (nf_conntrack_expect_related(exp) != 0)
+ else if (nf_ct_expect_related(exp) != 0)
ret = NF_DROP;
- nf_conntrack_expect_put(exp);
+ nf_ct_expect_put(exp);
break;
case TFTP_OPCODE_DATA:
case TFTP_OPCODE_ACK:
- DEBUGP("Data/ACK opcode\n");
+ pr_debug("Data/ACK opcode\n");
break;
case TFTP_OPCODE_ERROR:
- DEBUGP("Error opcode\n");
+ pr_debug("Error opcode\n");
break;
default:
- DEBUGP("Unknown opcode\n");
+ pr_debug("Unknown opcode\n");
}
return ret;
}
@@ -128,9 +117,6 @@ static int __init nf_conntrack_tftp_init(void)
for (j = 0; j < 2; j++) {
tftp[i][j].tuple.dst.protonum = IPPROTO_UDP;
tftp[i][j].tuple.src.u.udp.port = htons(ports[i]);
- tftp[i][j].mask.src.l3num = 0xFFFF;
- tftp[i][j].mask.dst.protonum = 0xFF;
- tftp[i][j].mask.src.u.udp.port = htons(0xFFFF);
tftp[i][j].max_expected = 1;
tftp[i][j].timeout = 5 * 60; /* 5 minutes */
tftp[i][j].me = THIS_MODULE;
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 91b220cf5a1f..d67c4fbf6031 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -9,7 +9,7 @@
#include "nf_internals.h"
-/* Internal logging interface, which relies on the real
+/* Internal logging interface, which relies on the real
LOG target modules */
#define NF_LOG_PREFIXLEN 128
@@ -140,7 +140,7 @@ static int seq_show(struct seq_file *s, void *v)
return seq_printf(s, "%2lld %s\n", *pos, logger->name);
}
-static struct seq_operations nflog_seq_ops = {
+static const struct seq_operations nflog_seq_ops = {
.start = seq_start,
.next = seq_next,
.stop = seq_stop,
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index b1f2ace96f6d..a481a349f7bf 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -17,7 +17,7 @@
*/
static struct nf_queue_handler *queue_handler[NPROTO];
-static DEFINE_RWLOCK(queue_handler_lock);
+static DEFINE_MUTEX(queue_handler_mutex);
/* return EBUSY when somebody else is registered, return EEXIST if the
* same handler is registered, return 0 in case of success. */
@@ -28,30 +28,37 @@ int nf_register_queue_handler(int pf, struct nf_queue_handler *qh)
if (pf >= NPROTO)
return -EINVAL;
- write_lock_bh(&queue_handler_lock);
+ mutex_lock(&queue_handler_mutex);
if (queue_handler[pf] == qh)
ret = -EEXIST;
else if (queue_handler[pf])
ret = -EBUSY;
else {
- queue_handler[pf] = qh;
+ rcu_assign_pointer(queue_handler[pf], qh);
ret = 0;
}
- write_unlock_bh(&queue_handler_lock);
+ mutex_unlock(&queue_handler_mutex);
return ret;
}
EXPORT_SYMBOL(nf_register_queue_handler);
/* The caller must flush their queue before this */
-int nf_unregister_queue_handler(int pf)
+int nf_unregister_queue_handler(int pf, struct nf_queue_handler *qh)
{
if (pf >= NPROTO)
return -EINVAL;
- write_lock_bh(&queue_handler_lock);
- queue_handler[pf] = NULL;
- write_unlock_bh(&queue_handler_lock);
+ mutex_lock(&queue_handler_mutex);
+ if (queue_handler[pf] != qh) {
+ mutex_unlock(&queue_handler_mutex);
+ return -EINVAL;
+ }
+
+ rcu_assign_pointer(queue_handler[pf], NULL);
+ mutex_unlock(&queue_handler_mutex);
+
+ synchronize_rcu();
return 0;
}
@@ -61,12 +68,14 @@ void nf_unregister_queue_handlers(struct nf_queue_handler *qh)
{
int pf;
- write_lock_bh(&queue_handler_lock);
+ mutex_lock(&queue_handler_mutex);
for (pf = 0; pf < NPROTO; pf++) {
if (queue_handler[pf] == qh)
- queue_handler[pf] = NULL;
+ rcu_assign_pointer(queue_handler[pf], NULL);
}
- write_unlock_bh(&queue_handler_lock);
+ mutex_unlock(&queue_handler_mutex);
+
+ synchronize_rcu();
}
EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
@@ -89,18 +98,21 @@ static int __nf_queue(struct sk_buff *skb,
struct net_device *physoutdev = NULL;
#endif
struct nf_afinfo *afinfo;
+ struct nf_queue_handler *qh;
/* QUEUE == DROP if noone is waiting, to be safe. */
- read_lock(&queue_handler_lock);
- if (!queue_handler[pf]) {
- read_unlock(&queue_handler_lock);
+ rcu_read_lock();
+
+ qh = rcu_dereference(queue_handler[pf]);
+ if (!qh) {
+ rcu_read_unlock();
kfree_skb(skb);
return 1;
}
afinfo = nf_get_afinfo(pf);
if (!afinfo) {
- read_unlock(&queue_handler_lock);
+ rcu_read_unlock();
kfree_skb(skb);
return 1;
}
@@ -110,7 +122,7 @@ static int __nf_queue(struct sk_buff *skb,
if (net_ratelimit())
printk(KERN_ERR "OOM queueing packet %p\n",
skb);
- read_unlock(&queue_handler_lock);
+ rcu_read_unlock();
kfree_skb(skb);
return 1;
}
@@ -120,7 +132,7 @@ static int __nf_queue(struct sk_buff *skb,
/* If it's going away, ignore hook. */
if (!try_module_get(info->elem->owner)) {
- read_unlock(&queue_handler_lock);
+ rcu_read_unlock();
kfree(info);
return 0;
}
@@ -138,10 +150,9 @@ static int __nf_queue(struct sk_buff *skb,
}
#endif
afinfo->saveroute(skb, info);
- status = queue_handler[pf]->outfn(skb, info, queuenum,
- queue_handler[pf]->data);
+ status = qh->outfn(skb, info, queuenum, qh->data);
- read_unlock(&queue_handler_lock);
+ rcu_read_unlock();
if (status < 0) {
/* James M doesn't say fuck enough. */
@@ -308,18 +319,18 @@ static int seq_show(struct seq_file *s, void *v)
loff_t *pos = v;
struct nf_queue_handler *qh;
- read_lock_bh(&queue_handler_lock);
- qh = queue_handler[*pos];
+ rcu_read_lock();
+ qh = rcu_dereference(queue_handler[*pos]);
if (!qh)
ret = seq_printf(s, "%2lld NONE\n", *pos);
else
ret = seq_printf(s, "%2lld %s\n", *pos, qh->name);
- read_unlock_bh(&queue_handler_lock);
+ rcu_read_unlock();
return ret;
}
-static struct seq_operations nfqueue_seq_ops = {
+static const struct seq_operations nfqueue_seq_ops = {
.start = seq_start,
.next = seq_next,
.stop = seq_stop,
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index e32e30e7a17c..e185a5b55913 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -962,7 +962,7 @@ static int seq_show(struct seq_file *s, void *v)
inst->flushtimeout, atomic_read(&inst->use));
}
-static struct seq_operations nful_seq_ops = {
+static const struct seq_operations nful_seq_ops = {
.start = seq_start,
.next = seq_next,
.stop = seq_stop,
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 7a97bec67729..bb65a38c816c 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -913,9 +913,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
case NFQNL_CFG_CMD_PF_UNBIND:
QDEBUG("unregistering queue handler for pf=%u\n",
ntohs(cmd->pf));
- /* This is a bug and a feature. We can unregister
- * other handlers(!) */
- ret = nf_unregister_queue_handler(ntohs(cmd->pf));
+ ret = nf_unregister_queue_handler(ntohs(cmd->pf), &nfqh);
break;
default:
ret = -EINVAL;
@@ -1050,7 +1048,7 @@ static int seq_show(struct seq_file *s, void *v)
atomic_read(&inst->use));
}
-static struct seq_operations nfqnl_seq_ops = {
+static const struct seq_operations nfqnl_seq_ops = {
.start = seq_start,
.next = seq_next,
.stop = seq_stop,
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 0eb2504b89b5..cc2baa6d5a7a 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -320,8 +320,8 @@ int xt_check_match(const struct xt_match *match, unsigned short family,
return -EINVAL;
}
if (match->hooks && (hook_mask & ~match->hooks) != 0) {
- printk("%s_tables: %s match: bad hook_mask %u\n",
- xt_prefix[family], match->name, hook_mask);
+ printk("%s_tables: %s match: bad hook_mask %u/%u\n",
+ xt_prefix[family], match->name, hook_mask, match->hooks);
return -EINVAL;
}
if (match->proto && (match->proto != proto || inv_proto)) {
@@ -410,8 +410,9 @@ int xt_check_target(const struct xt_target *target, unsigned short family,
return -EINVAL;
}
if (target->hooks && (hook_mask & ~target->hooks) != 0) {
- printk("%s_tables: %s target: bad hook_mask %u\n",
- xt_prefix[family], target->name, hook_mask);
+ printk("%s_tables: %s target: bad hook_mask %u/%u\n",
+ xt_prefix[family], target->name, hook_mask,
+ target->hooks);
return -EINVAL;
}
if (target->proto && (target->proto != proto || inv_proto)) {
@@ -744,7 +745,7 @@ static int xt_name_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations xt_tgt_seq_ops = {
+static const struct seq_operations xt_tgt_seq_ops = {
.start = xt_tgt_seq_start,
.next = xt_tgt_seq_next,
.stop = xt_tgt_seq_stop,
diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c
index 30884833e665..519428566829 100644
--- a/net/netfilter/xt_CLASSIFY.c
+++ b/net/netfilter/xt_CLASSIFY.c
@@ -39,7 +39,7 @@ target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static struct xt_target xt_classify_target[] = {
+static struct xt_target xt_classify_target[] __read_mostly = {
{
.family = AF_INET,
.name = "CLASSIFY",
diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c
index b03ce009d0bf..5a00c5444334 100644
--- a/net/netfilter/xt_CONNMARK.c
+++ b/net/netfilter/xt_CONNMARK.c
@@ -76,33 +76,33 @@ target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int
+static bool
checkentry(const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
- struct xt_connmark_target_info *matchinfo = targinfo;
+ const struct xt_connmark_target_info *matchinfo = targinfo;
if (nf_ct_l3proto_try_module_get(target->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", target->family);
- return 0;
+ return false;
}
if (matchinfo->mode == XT_CONNMARK_RESTORE) {
if (strcmp(tablename, "mangle") != 0) {
printk(KERN_WARNING "CONNMARK: restore can only be "
"called from \"mangle\" table, not \"%s\"\n",
tablename);
- return 0;
+ return false;
}
}
if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) {
printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static void
@@ -121,7 +121,7 @@ struct compat_xt_connmark_target_info {
static void compat_from_user(void *dst, void *src)
{
- struct compat_xt_connmark_target_info *cm = src;
+ const struct compat_xt_connmark_target_info *cm = src;
struct xt_connmark_target_info m = {
.mark = cm->mark,
.mask = cm->mask,
@@ -132,7 +132,7 @@ static void compat_from_user(void *dst, void *src)
static int compat_to_user(void __user *dst, void *src)
{
- struct xt_connmark_target_info *m = src;
+ const struct xt_connmark_target_info *m = src;
struct compat_xt_connmark_target_info cm = {
.mark = m->mark,
.mask = m->mask,
@@ -142,7 +142,7 @@ static int compat_to_user(void __user *dst, void *src)
}
#endif /* CONFIG_COMPAT */
-static struct xt_target xt_connmark_target[] = {
+static struct xt_target xt_connmark_target[] __read_mostly = {
{
.name = "CONNMARK",
.family = AF_INET,
diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c
index 81c0c58bab47..63d73138c1b9 100644
--- a/net/netfilter/xt_CONNSECMARK.c
+++ b/net/netfilter/xt_CONNSECMARK.c
@@ -33,7 +33,7 @@ MODULE_ALIAS("ip6t_CONNSECMARK");
* If the packet has a security mark and the connection does not, copy
* the security mark from the packet to the connection.
*/
-static void secmark_save(struct sk_buff *skb)
+static void secmark_save(const struct sk_buff *skb)
{
if (skb->secmark) {
struct nf_conn *ct;
@@ -85,16 +85,16 @@ static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
return XT_CONTINUE;
}
-static int checkentry(const char *tablename, const void *entry,
- const struct xt_target *target, void *targinfo,
- unsigned int hook_mask)
+static bool checkentry(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+ unsigned int hook_mask)
{
- struct xt_connsecmark_target_info *info = targinfo;
+ const struct xt_connsecmark_target_info *info = targinfo;
if (nf_ct_l3proto_try_module_get(target->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", target->family);
- return 0;
+ return false;
}
switch (info->mode) {
case CONNSECMARK_SAVE:
@@ -103,10 +103,10 @@ static int checkentry(const char *tablename, const void *entry,
default:
printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static void
@@ -115,7 +115,7 @@ destroy(const struct xt_target *target, void *targinfo)
nf_ct_l3proto_module_put(target->family);
}
-static struct xt_target xt_connsecmark_target[] = {
+static struct xt_target xt_connsecmark_target[] __read_mostly = {
{
.name = "CONNSECMARK",
.family = AF_INET,
diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c
index 9f2f2201f6ae..798ab731009d 100644
--- a/net/netfilter/xt_DSCP.c
+++ b/net/netfilter/xt_DSCP.c
@@ -66,22 +66,22 @@ static unsigned int target6(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int checkentry(const char *tablename,
- const void *e_void,
- const struct xt_target *target,
- void *targinfo,
- unsigned int hook_mask)
+static bool checkentry(const char *tablename,
+ const void *e_void,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
{
const u_int8_t dscp = ((struct xt_DSCP_info *)targinfo)->dscp;
- if ((dscp > XT_DSCP_MAX)) {
+ if (dscp > XT_DSCP_MAX) {
printk(KERN_WARNING "DSCP: dscp %x out of range\n", dscp);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_target xt_dscp_target[] = {
+static struct xt_target xt_dscp_target[] __read_mostly = {
{
.name = "DSCP",
.family = AF_INET,
diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c
index 43817808d865..f30fe0baf7de 100644
--- a/net/netfilter/xt_MARK.c
+++ b/net/netfilter/xt_MARK.c
@@ -65,43 +65,43 @@ target_v1(struct sk_buff **pskb,
}
-static int
+static bool
checkentry_v0(const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
- struct xt_mark_target_info *markinfo = targinfo;
+ const struct xt_mark_target_info *markinfo = targinfo;
if (markinfo->mark > 0xffffffff) {
printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static int
+static bool
checkentry_v1(const char *tablename,
const void *entry,
const struct xt_target *target,
void *targinfo,
unsigned int hook_mask)
{
- struct xt_mark_target_info_v1 *markinfo = targinfo;
+ const struct xt_mark_target_info_v1 *markinfo = targinfo;
if (markinfo->mode != XT_MARK_SET
&& markinfo->mode != XT_MARK_AND
&& markinfo->mode != XT_MARK_OR) {
printk(KERN_WARNING "MARK: unknown mode %u\n",
markinfo->mode);
- return 0;
+ return false;
}
if (markinfo->mark > 0xffffffff) {
printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
#ifdef CONFIG_COMPAT
@@ -114,7 +114,7 @@ struct compat_xt_mark_target_info_v1 {
static void compat_from_user_v1(void *dst, void *src)
{
- struct compat_xt_mark_target_info_v1 *cm = src;
+ const struct compat_xt_mark_target_info_v1 *cm = src;
struct xt_mark_target_info_v1 m = {
.mark = cm->mark,
.mode = cm->mode,
@@ -124,7 +124,7 @@ static void compat_from_user_v1(void *dst, void *src)
static int compat_to_user_v1(void __user *dst, void *src)
{
- struct xt_mark_target_info_v1 *m = src;
+ const struct xt_mark_target_info_v1 *m = src;
struct compat_xt_mark_target_info_v1 cm = {
.mark = m->mark,
.mode = m->mode,
@@ -133,7 +133,7 @@ static int compat_to_user_v1(void __user *dst, void *src)
}
#endif /* CONFIG_COMPAT */
-static struct xt_target xt_mark_target[] = {
+static struct xt_target xt_mark_target[] __read_mostly = {
{
.name = "MARK",
.family = AF_INET,
diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c
index 901ed7abaa1b..d3594c7ccb26 100644
--- a/net/netfilter/xt_NFLOG.c
+++ b/net/netfilter/xt_NFLOG.c
@@ -38,21 +38,21 @@ nflog_target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static int
+static bool
nflog_checkentry(const char *tablename, const void *entry,
const struct xt_target *target, void *targetinfo,
unsigned int hookmask)
{
- struct xt_nflog_info *info = targetinfo;
+ const struct xt_nflog_info *info = targetinfo;
if (info->flags & ~XT_NFLOG_MASK)
- return 0;
+ return false;
if (info->prefix[sizeof(info->prefix) - 1] != '\0')
- return 0;
- return 1;
+ return false;
+ return true;
}
-static struct xt_target xt_nflog_target[] = {
+static struct xt_target xt_nflog_target[] __read_mostly = {
{
.name = "NFLOG",
.family = AF_INET,
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index 201155b316e0..13f59f3e8c38 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -36,7 +36,7 @@ target(struct sk_buff **pskb,
return NF_QUEUE_NR(tinfo->queuenum);
}
-static struct xt_target xt_nfqueue_target[] = {
+static struct xt_target xt_nfqueue_target[] __read_mostly = {
{
.name = "NFQUEUE",
.family = AF_INET,
diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c
index 5085fb3d1e2d..b7d6312fccc7 100644
--- a/net/netfilter/xt_NOTRACK.c
+++ b/net/netfilter/xt_NOTRACK.c
@@ -33,7 +33,7 @@ target(struct sk_buff **pskb,
return XT_CONTINUE;
}
-static struct xt_target xt_notrack_target[] = {
+static struct xt_target xt_notrack_target[] __read_mostly = {
{
.name = "NOTRACK",
.family = AF_INET,
diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c
index 705f0e830a79..c83779a941a1 100644
--- a/net/netfilter/xt_SECMARK.c
+++ b/net/netfilter/xt_SECMARK.c
@@ -51,7 +51,7 @@ static unsigned int target(struct sk_buff **pskb, const struct net_device *in,
return XT_CONTINUE;
}
-static int checkentry_selinux(struct xt_secmark_target_info *info)
+static bool checkentry_selinux(struct xt_secmark_target_info *info)
{
int err;
struct xt_secmark_target_selinux_info *sel = &info->u.sel;
@@ -63,53 +63,53 @@ static int checkentry_selinux(struct xt_secmark_target_info *info)
if (err == -EINVAL)
printk(KERN_INFO PFX "invalid SELinux context \'%s\'\n",
sel->selctx);
- return 0;
+ return false;
}
if (!sel->selsid) {
printk(KERN_INFO PFX "unable to map SELinux context \'%s\'\n",
sel->selctx);
- return 0;
+ return false;
}
err = selinux_relabel_packet_permission(sel->selsid);
if (err) {
printk(KERN_INFO PFX "unable to obtain relabeling permission\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static int checkentry(const char *tablename, const void *entry,
- const struct xt_target *target, void *targinfo,
- unsigned int hook_mask)
+static bool checkentry(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+ unsigned int hook_mask)
{
struct xt_secmark_target_info *info = targinfo;
if (mode && mode != info->mode) {
printk(KERN_INFO PFX "mode already set to %hu cannot mix with "
"rules for mode %hu\n", mode, info->mode);
- return 0;
+ return false;
}
switch (info->mode) {
case SECMARK_MODE_SEL:
if (!checkentry_selinux(info))
- return 0;
+ return false;
break;
default:
printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode);
- return 0;
+ return false;
}
if (!mode)
mode = info->mode;
- return 1;
+ return true;
}
-static struct xt_target xt_secmark_target[] = {
+static struct xt_target xt_secmark_target[] __read_mostly = {
{
.name = "SECMARK",
.family = AF_INET,
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index 15fe8f649510..d40f7e4b1289 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -93,7 +93,7 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
return 0;
opt[i+2] = (newmss & 0xff00) >> 8;
- opt[i+3] = (newmss & 0x00ff);
+ opt[i+3] = newmss & 0x00ff;
nf_proto_csum_replace2(&tcph->check, *pskb,
htons(oldmss), htons(newmss), 0);
@@ -126,7 +126,7 @@ tcpmss_mangle_packet(struct sk_buff **pskb,
opt[0] = TCPOPT_MSS;
opt[1] = TCPOLEN_MSS;
opt[2] = (newmss & 0xff00) >> 8;
- opt[3] = (newmss & 0x00ff);
+ opt[3] = newmss & 0x00ff;
nf_proto_csum_replace4(&tcph->check, *pskb, 0, *((__be32 *)opt), 0);
@@ -197,19 +197,19 @@ xt_tcpmss_target6(struct sk_buff **pskb,
#define TH_SYN 0x02
/* Must specify -p tcp --syn */
-static inline int find_syn_match(const struct xt_entry_match *m)
+static inline bool find_syn_match(const struct xt_entry_match *m)
{
const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
tcpinfo->flg_cmp & TH_SYN &&
!(tcpinfo->invflags & XT_TCP_INV_FLAGS))
- return 1;
+ return true;
- return 0;
+ return false;
}
-static int
+static bool
xt_tcpmss_checkentry4(const char *tablename,
const void *entry,
const struct xt_target *target,
@@ -225,16 +225,16 @@ xt_tcpmss_checkentry4(const char *tablename,
(1 << NF_IP_POST_ROUTING))) != 0) {
printk("xt_TCPMSS: path-MTU clamping only supported in "
"FORWARD, OUTPUT and POSTROUTING hooks\n");
- return 0;
+ return false;
}
if (IPT_MATCH_ITERATE(e, find_syn_match))
- return 1;
+ return true;
printk("xt_TCPMSS: Only works on TCP SYN packets\n");
- return 0;
+ return false;
}
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
-static int
+static bool
xt_tcpmss_checkentry6(const char *tablename,
const void *entry,
const struct xt_target *target,
@@ -250,16 +250,16 @@ xt_tcpmss_checkentry6(const char *tablename,
(1 << NF_IP6_POST_ROUTING))) != 0) {
printk("xt_TCPMSS: path-MTU clamping only supported in "
"FORWARD, OUTPUT and POSTROUTING hooks\n");
- return 0;
+ return false;
}
if (IP6T_MATCH_ITERATE(e, find_syn_match))
- return 1;
+ return true;
printk("xt_TCPMSS: Only works on TCP SYN packets\n");
- return 0;
+ return false;
}
#endif
-static struct xt_target xt_tcpmss_reg[] = {
+static struct xt_target xt_tcpmss_reg[] __read_mostly = {
{
.family = AF_INET,
.name = "TCPMSS",
diff --git a/net/netfilter/xt_TRACE.c b/net/netfilter/xt_TRACE.c
new file mode 100644
index 000000000000..4df2dedcc0b5
--- /dev/null
+++ b/net/netfilter/xt_TRACE.c
@@ -0,0 +1,53 @@
+/* This is a module which is used to mark packets for tracing.
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_TRACE");
+MODULE_ALIAS("ip6t_TRACE");
+
+static unsigned int
+target(struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo)
+{
+ (*pskb)->nf_trace = 1;
+ return XT_CONTINUE;
+}
+
+static struct xt_target xt_trace_target[] __read_mostly = {
+ {
+ .name = "TRACE",
+ .family = AF_INET,
+ .target = target,
+ .table = "raw",
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "TRACE",
+ .family = AF_INET6,
+ .target = target,
+ .table = "raw",
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_trace_init(void)
+{
+ return xt_register_targets(xt_trace_target,
+ ARRAY_SIZE(xt_trace_target));
+}
+
+static void __exit xt_trace_fini(void)
+{
+ xt_unregister_targets(xt_trace_target, ARRAY_SIZE(xt_trace_target));
+}
+
+module_init(xt_trace_init);
+module_exit(xt_trace_fini);
diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c
index 7db492d65220..64bcdb0fe1e6 100644
--- a/net/netfilter/xt_comment.c
+++ b/net/netfilter/xt_comment.c
@@ -15,7 +15,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_comment");
MODULE_ALIAS("ip6t_comment");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -23,13 +23,13 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protooff,
- int *hotdrop)
+ bool *hotdrop)
{
/* We always match */
- return 1;
+ return true;
}
-static struct xt_match xt_comment_match[] = {
+static struct xt_match xt_comment_match[] __read_mostly = {
{
.name = "comment",
.family = AF_INET,
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 804afe55e141..dd4d79b8fc9d 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -15,7 +15,7 @@ MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("iptables match for matching number of pkts/bytes per connection");
MODULE_ALIAS("ipt_connbytes");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -23,10 +23,10 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_connbytes_info *sinfo = matchinfo;
- struct nf_conn *ct;
+ const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
u_int64_t what = 0; /* initialize to make gcc happy */
u_int64_t bytes = 0;
@@ -35,7 +35,7 @@ match(const struct sk_buff *skb,
ct = nf_ct_get(skb, &ctinfo);
if (!ct)
- return 0;
+ return false;
counters = ct->counters;
switch (sinfo->what) {
@@ -90,36 +90,36 @@ match(const struct sk_buff *skb,
}
if (sinfo->count.to)
- return (what <= sinfo->count.to && what >= sinfo->count.from);
+ return what <= sinfo->count.to && what >= sinfo->count.from;
else
- return (what >= sinfo->count.from);
+ return what >= sinfo->count.from;
}
-static int check(const char *tablename,
- const void *ip,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int hook_mask)
+static bool check(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
{
const struct xt_connbytes_info *sinfo = matchinfo;
if (sinfo->what != XT_CONNBYTES_PKTS &&
sinfo->what != XT_CONNBYTES_BYTES &&
sinfo->what != XT_CONNBYTES_AVGPKT)
- return 0;
+ return false;
if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL &&
sinfo->direction != XT_CONNBYTES_DIR_REPLY &&
sinfo->direction != XT_CONNBYTES_DIR_BOTH)
- return 0;
+ return false;
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static void
@@ -128,7 +128,7 @@ destroy(const struct xt_match *match, void *matchinfo)
nf_ct_l3proto_module_put(match->family);
}
-static struct xt_match xt_connbytes_match[] = {
+static struct xt_match xt_connbytes_match[] __read_mostly = {
{
.name = "connbytes",
.family = AF_INET,
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
new file mode 100644
index 000000000000..3335dd5be962
--- /dev/null
+++ b/net/netfilter/xt_connlimit.c
@@ -0,0 +1,313 @@
+/*
+ * netfilter module to limit the number of parallel tcp
+ * connections per IP address.
+ * (c) 2000 Gerd Knorr <kraxel@bytesex.org>
+ * Nov 2002: Martin Bene <martin.bene@icomedias.com>:
+ * only ignore TIME_WAIT or gone connections
+ * Copyright © Jan Engelhardt <jengelh@gmx.de>, 2007
+ *
+ * based on ...
+ *
+ * Kernel module to match connection tracking information.
+ * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au).
+ */
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/jhash.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_connlimit.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_tuple.h>
+
+/* we will save the tuples of all connections we care about */
+struct xt_connlimit_conn {
+ struct list_head list;
+ struct nf_conntrack_tuple tuple;
+};
+
+struct xt_connlimit_data {
+ struct list_head iphash[256];
+ spinlock_t lock;
+};
+
+static u_int32_t connlimit_rnd;
+static bool connlimit_rnd_inited;
+
+static inline unsigned int connlimit_iphash(u_int32_t addr)
+{
+ if (unlikely(!connlimit_rnd_inited)) {
+ get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd));
+ connlimit_rnd_inited = true;
+ }
+ return jhash_1word(addr, connlimit_rnd) & 0xFF;
+}
+
+static inline unsigned int
+connlimit_iphash6(const union nf_conntrack_address *addr,
+ const union nf_conntrack_address *mask)
+{
+ union nf_conntrack_address res;
+ unsigned int i;
+
+ if (unlikely(!connlimit_rnd_inited)) {
+ get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd));
+ connlimit_rnd_inited = true;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i)
+ res.ip6[i] = addr->ip6[i] & mask->ip6[i];
+
+ return jhash2(res.ip6, ARRAY_SIZE(res.ip6), connlimit_rnd) & 0xFF;
+}
+
+static inline bool already_closed(const struct nf_conn *conn)
+{
+ u_int16_t proto = conn->tuplehash[0].tuple.dst.protonum;
+
+ if (proto == IPPROTO_TCP)
+ return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT;
+ else
+ return 0;
+}
+
+static inline unsigned int
+same_source_net(const union nf_conntrack_address *addr,
+ const union nf_conntrack_address *mask,
+ const union nf_conntrack_address *u3, unsigned int family)
+{
+ if (family == AF_INET) {
+ return (addr->ip & mask->ip) == (u3->ip & mask->ip);
+ } else {
+ union nf_conntrack_address lh, rh;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(addr->ip6); ++i) {
+ lh.ip6[i] = addr->ip6[i] & mask->ip6[i];
+ rh.ip6[i] = u3->ip6[i] & mask->ip6[i];
+ }
+
+ return memcmp(&lh.ip6, &rh.ip6, sizeof(lh.ip6)) == 0;
+ }
+}
+
+static int count_them(struct xt_connlimit_data *data,
+ const struct nf_conntrack_tuple *tuple,
+ const union nf_conntrack_address *addr,
+ const union nf_conntrack_address *mask,
+ const struct xt_match *match)
+{
+ struct nf_conntrack_tuple_hash *found;
+ struct xt_connlimit_conn *conn;
+ struct xt_connlimit_conn *tmp;
+ struct nf_conn *found_ct;
+ struct list_head *hash;
+ bool addit = true;
+ int matches = 0;
+
+
+ if (match->family == AF_INET6)
+ hash = &data->iphash[connlimit_iphash6(addr, mask)];
+ else
+ hash = &data->iphash[connlimit_iphash(addr->ip & mask->ip)];
+
+ read_lock_bh(&nf_conntrack_lock);
+
+ /* check the saved connections */
+ list_for_each_entry_safe(conn, tmp, hash, list) {
+ found = __nf_conntrack_find(&conn->tuple, NULL);
+ found_ct = NULL;
+
+ if (found != NULL)
+ found_ct = nf_ct_tuplehash_to_ctrack(found);
+
+ if (found_ct != NULL &&
+ nf_ct_tuple_equal(&conn->tuple, tuple) &&
+ !already_closed(found_ct))
+ /*
+ * Just to be sure we have it only once in the list.
+ * We should not see tuples twice unless someone hooks
+ * this into a table without "-p tcp --syn".
+ */
+ addit = false;
+
+ if (found == NULL) {
+ /* this one is gone */
+ list_del(&conn->list);
+ kfree(conn);
+ continue;
+ }
+
+ if (already_closed(found_ct)) {
+ /*
+ * we do not care about connections which are
+ * closed already -> ditch it
+ */
+ list_del(&conn->list);
+ kfree(conn);
+ continue;
+ }
+
+ if (same_source_net(addr, mask, &conn->tuple.src.u3,
+ match->family))
+ /* same source network -> be counted! */
+ ++matches;
+ }
+
+ read_unlock_bh(&nf_conntrack_lock);
+
+ if (addit) {
+ /* save the new connection in our list */
+ conn = kzalloc(sizeof(*conn), GFP_ATOMIC);
+ if (conn == NULL)
+ return -ENOMEM;
+ conn->tuple = *tuple;
+ list_add(&conn->list, hash);
+ ++matches;
+ }
+
+ return matches;
+}
+
+static bool connlimit_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo, int offset,
+ unsigned int protoff, bool *hotdrop)
+{
+ const struct xt_connlimit_info *info = matchinfo;
+ union nf_conntrack_address addr, mask;
+ struct nf_conntrack_tuple tuple;
+ const struct nf_conntrack_tuple *tuple_ptr = &tuple;
+ enum ip_conntrack_info ctinfo;
+ const struct nf_conn *ct;
+ int connections;
+
+ ct = nf_ct_get(skb, &ctinfo);
+ if (ct != NULL)
+ tuple_ptr = &ct->tuplehash[0].tuple;
+ else if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
+ match->family, &tuple))
+ goto hotdrop;
+
+ if (match->family == AF_INET6) {
+ const struct ipv6hdr *iph = ipv6_hdr(skb);
+ memcpy(&addr.ip6, &iph->saddr, sizeof(iph->saddr));
+ memcpy(&mask.ip6, info->v6_mask, sizeof(info->v6_mask));
+ } else {
+ const struct iphdr *iph = ip_hdr(skb);
+ addr.ip = iph->saddr;
+ mask.ip = info->v4_mask;
+ }
+
+ spin_lock_bh(&info->data->lock);
+ connections = count_them(info->data, tuple_ptr, &addr, &mask, match);
+ spin_unlock_bh(&info->data->lock);
+
+ if (connections < 0) {
+ /* kmalloc failed, drop it entirely */
+ *hotdrop = true;
+ return false;
+ }
+
+ return (connections > info->limit) ^ info->inverse;
+
+ hotdrop:
+ *hotdrop = true;
+ return false;
+}
+
+static bool connlimit_check(const char *tablename, const void *ip,
+ const struct xt_match *match, void *matchinfo,
+ unsigned int hook_mask)
+{
+ struct xt_connlimit_info *info = matchinfo;
+ unsigned int i;
+
+ if (nf_ct_l3proto_try_module_get(match->family) < 0) {
+ printk(KERN_WARNING "cannot load conntrack support for "
+ "address family %u\n", match->family);
+ return false;
+ }
+
+ /* init private data */
+ info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL);
+ if (info->data == NULL) {
+ nf_ct_l3proto_module_put(match->family);
+ return false;
+ }
+
+ spin_lock_init(&info->data->lock);
+ for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i)
+ INIT_LIST_HEAD(&info->data->iphash[i]);
+
+ return true;
+}
+
+static void connlimit_destroy(const struct xt_match *match, void *matchinfo)
+{
+ struct xt_connlimit_info *info = matchinfo;
+ struct xt_connlimit_conn *conn;
+ struct xt_connlimit_conn *tmp;
+ struct list_head *hash = info->data->iphash;
+ unsigned int i;
+
+ nf_ct_l3proto_module_put(match->family);
+
+ for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) {
+ list_for_each_entry_safe(conn, tmp, &hash[i], list) {
+ list_del(&conn->list);
+ kfree(conn);
+ }
+ }
+
+ kfree(info->data);
+}
+
+static struct xt_match connlimit_reg[] __read_mostly = {
+ {
+ .name = "connlimit",
+ .family = AF_INET,
+ .checkentry = connlimit_check,
+ .match = connlimit_match,
+ .matchsize = sizeof(struct xt_connlimit_info),
+ .destroy = connlimit_destroy,
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "connlimit",
+ .family = AF_INET6,
+ .checkentry = connlimit_check,
+ .match = connlimit_match,
+ .matchsize = sizeof(struct xt_connlimit_info),
+ .destroy = connlimit_destroy,
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_connlimit_init(void)
+{
+ return xt_register_matches(connlimit_reg, ARRAY_SIZE(connlimit_reg));
+}
+
+static void __exit xt_connlimit_exit(void)
+{
+ xt_unregister_matches(connlimit_reg, ARRAY_SIZE(connlimit_reg));
+}
+
+module_init(xt_connlimit_init);
+module_exit(xt_connlimit_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
+MODULE_DESCRIPTION("netfilter xt_connlimit match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_connlimit");
+MODULE_ALIAS("ip6t_connlimit");
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index e1803256c792..e73fa9b46cf7 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -30,7 +30,7 @@ MODULE_DESCRIPTION("IP tables connmark match module");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_connmark");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -38,38 +38,38 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_connmark_info *info = matchinfo;
- struct nf_conn *ct;
+ const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
ct = nf_ct_get(skb, &ctinfo);
if (!ct)
- return 0;
+ return false;
- return (((ct->mark) & info->mask) == info->mark) ^ info->invert;
+ return ((ct->mark & info->mask) == info->mark) ^ info->invert;
}
-static int
+static bool
checkentry(const char *tablename,
const void *ip,
const struct xt_match *match,
void *matchinfo,
unsigned int hook_mask)
{
- struct xt_connmark_info *cm = matchinfo;
+ const struct xt_connmark_info *cm = matchinfo;
if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) {
printk(KERN_WARNING "connmark: only support 32bit mark\n");
- return 0;
+ return false;
}
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static void
@@ -88,7 +88,7 @@ struct compat_xt_connmark_info {
static void compat_from_user(void *dst, void *src)
{
- struct compat_xt_connmark_info *cm = src;
+ const struct compat_xt_connmark_info *cm = src;
struct xt_connmark_info m = {
.mark = cm->mark,
.mask = cm->mask,
@@ -99,7 +99,7 @@ static void compat_from_user(void *dst, void *src)
static int compat_to_user(void __user *dst, void *src)
{
- struct xt_connmark_info *m = src;
+ const struct xt_connmark_info *m = src;
struct compat_xt_connmark_info cm = {
.mark = m->mark,
.mask = m->mask,
@@ -109,7 +109,7 @@ static int compat_to_user(void __user *dst, void *src)
}
#endif /* CONFIG_COMPAT */
-static struct xt_match xt_connmark_match[] = {
+static struct xt_match xt_connmark_match[] __read_mostly = {
{
.name = "connmark",
.family = AF_INET,
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index 189ded5f378b..ca4b69f020a8 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -19,7 +19,7 @@ MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("iptables connection tracking match module");
MODULE_ALIAS("ipt_conntrack");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -27,14 +27,14 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_conntrack_info *sinfo = matchinfo;
- struct nf_conn *ct;
+ const struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
unsigned int statebit;
- ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
+ ct = nf_ct_get(skb, &ctinfo);
#define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
@@ -54,53 +54,53 @@ match(const struct sk_buff *skb,
}
if (FWINV((statebit & sinfo->statemask) == 0,
XT_CONNTRACK_STATE))
- return 0;
+ return false;
}
if (ct == NULL) {
if (sinfo->flags & ~XT_CONNTRACK_STATE)
- return 0;
- return 1;
+ return false;
+ return true;
}
if (sinfo->flags & XT_CONNTRACK_PROTO &&
FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum !=
sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
XT_CONNTRACK_PROTO))
- return 0;
+ return false;
if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip &
sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
XT_CONNTRACK_ORIGSRC))
- return 0;
+ return false;
if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip &
sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
XT_CONNTRACK_ORIGDST))
- return 0;
+ return false;
if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip &
sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
XT_CONNTRACK_REPLSRC))
- return 0;
+ return false;
if (sinfo->flags & XT_CONNTRACK_REPLDST &&
FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip &
sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
XT_CONNTRACK_REPLDST))
- return 0;
+ return false;
if (sinfo->flags & XT_CONNTRACK_STATUS &&
FWINV((ct->status & sinfo->statusmask) == 0,
XT_CONNTRACK_STATUS))
- return 0;
+ return false;
if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
unsigned long expires = timer_pending(&ct->timeout) ?
@@ -109,12 +109,12 @@ match(const struct sk_buff *skb,
if (FWINV(!(expires >= sinfo->expires_min &&
expires <= sinfo->expires_max),
XT_CONNTRACK_EXPIRES))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static int
+static bool
checkentry(const char *tablename,
const void *ip,
const struct xt_match *match,
@@ -124,9 +124,9 @@ checkentry(const char *tablename,
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static void destroy(const struct xt_match *match, void *matchinfo)
@@ -150,7 +150,7 @@ struct compat_xt_conntrack_info
static void compat_from_user(void *dst, void *src)
{
- struct compat_xt_conntrack_info *cm = src;
+ const struct compat_xt_conntrack_info *cm = src;
struct xt_conntrack_info m = {
.statemask = cm->statemask,
.statusmask = cm->statusmask,
@@ -167,7 +167,7 @@ static void compat_from_user(void *dst, void *src)
static int compat_to_user(void __user *dst, void *src)
{
- struct xt_conntrack_info *m = src;
+ const struct xt_conntrack_info *m = src;
struct compat_xt_conntrack_info cm = {
.statemask = m->statemask,
.statusmask = m->statusmask,
@@ -183,7 +183,7 @@ static int compat_to_user(void __user *dst, void *src)
}
#endif
-static struct xt_match conntrack_match = {
+static struct xt_match conntrack_match __read_mostly = {
.name = "conntrack",
.match = match,
.checkentry = checkentry,
diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c
index 2c9c0dee8aaf..83224ec89cc0 100644
--- a/net/netfilter/xt_dccp.c
+++ b/net/netfilter/xt_dccp.c
@@ -31,40 +31,40 @@ MODULE_ALIAS("ipt_dccp");
static unsigned char *dccp_optbuf;
static DEFINE_SPINLOCK(dccp_buflock);
-static inline int
+static inline bool
dccp_find_option(u_int8_t option,
const struct sk_buff *skb,
unsigned int protoff,
const struct dccp_hdr *dh,
- int *hotdrop)
+ bool *hotdrop)
{
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
- unsigned char *op;
+ const unsigned char *op;
unsigned int optoff = __dccp_hdr_len(dh);
unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh);
unsigned int i;
if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
if (!optlen)
- return 0;
+ return false;
spin_lock_bh(&dccp_buflock);
op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf);
if (op == NULL) {
/* If we don't have the whole header, drop packet. */
spin_unlock_bh(&dccp_buflock);
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
for (i = 0; i < optlen; ) {
if (op[i] == option) {
spin_unlock_bh(&dccp_buflock);
- return 1;
+ return true;
}
if (op[i] < 2)
@@ -74,24 +74,24 @@ dccp_find_option(u_int8_t option,
}
spin_unlock_bh(&dccp_buflock);
- return 0;
+ return false;
}
-static inline int
+static inline bool
match_types(const struct dccp_hdr *dh, u_int16_t typemask)
{
- return (typemask & (1 << dh->dccph_type));
+ return typemask & (1 << dh->dccph_type);
}
-static inline int
+static inline bool
match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff,
- const struct dccp_hdr *dh, int *hotdrop)
+ const struct dccp_hdr *dh, bool *hotdrop)
{
return dccp_find_option(option, skb, protoff, dh, hotdrop);
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -99,25 +99,25 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_dccp_info *info = matchinfo;
struct dccp_hdr _dh, *dh;
if (offset)
- return 0;
+ return false;
dh = skb_header_pointer(skb, protoff, sizeof(_dh), &_dh);
if (dh == NULL) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
- return DCCHECK(((ntohs(dh->dccph_sport) >= info->spts[0])
- && (ntohs(dh->dccph_sport) <= info->spts[1])),
+ return DCCHECK(ntohs(dh->dccph_sport) >= info->spts[0]
+ && ntohs(dh->dccph_sport) <= info->spts[1],
XT_DCCP_SRC_PORTS, info->flags, info->invflags)
- && DCCHECK(((ntohs(dh->dccph_dport) >= info->dpts[0])
- && (ntohs(dh->dccph_dport) <= info->dpts[1])),
+ && DCCHECK(ntohs(dh->dccph_dport) >= info->dpts[0]
+ && ntohs(dh->dccph_dport) <= info->dpts[1],
XT_DCCP_DEST_PORTS, info->flags, info->invflags)
&& DCCHECK(match_types(dh, info->typemask),
XT_DCCP_TYPE, info->flags, info->invflags)
@@ -126,7 +126,7 @@ match(const struct sk_buff *skb,
XT_DCCP_OPTION, info->flags, info->invflags);
}
-static int
+static bool
checkentry(const char *tablename,
const void *inf,
const struct xt_match *match,
@@ -140,7 +140,7 @@ checkentry(const char *tablename,
&& !(info->invflags & ~info->flags);
}
-static struct xt_match xt_dccp_match[] = {
+static struct xt_match xt_dccp_match[] __read_mostly = {
{
.name = "dccp",
.family = AF_INET,
diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c
index 56b247ecc283..dde6d66e0d33 100644
--- a/net/netfilter/xt_dscp.c
+++ b/net/netfilter/xt_dscp.c
@@ -22,14 +22,14 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_dscp");
MODULE_ALIAS("ip6t_dscp");
-static int match(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct xt_match *match,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop)
+static bool match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop)
{
const struct xt_dscp_info *info = matchinfo;
u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
@@ -37,14 +37,14 @@ static int match(const struct sk_buff *skb,
return (dscp == info->dscp) ^ !!info->invert;
}
-static int match6(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct xt_match *match,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop)
+static bool match6(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop)
{
const struct xt_dscp_info *info = matchinfo;
u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
@@ -52,23 +52,23 @@ static int match6(const struct sk_buff *skb,
return (dscp == info->dscp) ^ !!info->invert;
}
-static int checkentry(const char *tablename,
- const void *info,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int hook_mask)
+static bool checkentry(const char *tablename,
+ const void *info,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
{
const u_int8_t dscp = ((struct xt_dscp_info *)matchinfo)->dscp;
if (dscp > XT_DSCP_MAX) {
printk(KERN_ERR "xt_dscp: dscp %x out of range\n", dscp);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match xt_dscp_match[] = {
+static struct xt_match xt_dscp_match[] __read_mostly = {
{
.name = "dscp",
.family = AF_INET,
diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c
index 7c95f149d942..b11378e001b6 100644
--- a/net/netfilter/xt_esp.c
+++ b/net/netfilter/xt_esp.c
@@ -31,10 +31,10 @@ MODULE_ALIAS("ip6t_esp");
#endif
/* Returns 1 if the spi is matched by the range, 0 otherwise */
-static inline int
-spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
+static inline bool
+spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert)
{
- int r = 0;
+ bool r;
duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ',
min, spi, max);
r = (spi >= min && spi <= max) ^ invert;
@@ -42,7 +42,7 @@ spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
return r;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -50,14 +50,14 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
struct ip_esp_hdr _esp, *eh;
const struct xt_esp *espinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
- return 0;
+ return false;
eh = skb_header_pointer(skb, protoff, sizeof(_esp), &_esp);
if (eh == NULL) {
@@ -65,8 +65,8 @@ match(const struct sk_buff *skb,
* can't. Hence, no choice but to drop.
*/
duprintf("Dropping evil ESP tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
return spi_match(espinfo->spis[0], espinfo->spis[1], ntohl(eh->spi),
@@ -74,7 +74,7 @@ match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
checkentry(const char *tablename,
const void *ip_void,
const struct xt_match *match,
@@ -85,13 +85,13 @@ checkentry(const char *tablename,
if (espinfo->invflags & ~XT_ESP_INV_MASK) {
duprintf("xt_esp: unknown flags %X\n", espinfo->invflags);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match xt_esp_match[] = {
+static struct xt_match xt_esp_match[] __read_mostly = {
{
.name = "esp",
.family = AF_INET,
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index d3043fa32ebc..bd45f9d3f7d0 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -94,7 +94,8 @@ static DEFINE_MUTEX(hlimit_mutex); /* additional checkentry protection */
static HLIST_HEAD(hashlimit_htables);
static struct kmem_cache *hashlimit_cachep __read_mostly;
-static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
+static inline bool dst_cmp(const struct dsthash_ent *ent,
+ const struct dsthash_dst *b)
{
return !memcmp(&ent->dst, b, sizeof(ent->dst));
}
@@ -106,7 +107,8 @@ hash_dst(const struct xt_hashlimit_htable *ht, const struct dsthash_dst *dst)
}
static struct dsthash_ent *
-dsthash_find(const struct xt_hashlimit_htable *ht, struct dsthash_dst *dst)
+dsthash_find(const struct xt_hashlimit_htable *ht,
+ const struct dsthash_dst *dst)
{
struct dsthash_ent *ent;
struct hlist_node *pos;
@@ -122,7 +124,8 @@ dsthash_find(const struct xt_hashlimit_htable *ht, struct dsthash_dst *dst)
/* allocate dsthash_ent, initialize dst, put in htable and lock it */
static struct dsthash_ent *
-dsthash_alloc_init(struct xt_hashlimit_htable *ht, struct dsthash_dst *dst)
+dsthash_alloc_init(struct xt_hashlimit_htable *ht,
+ const struct dsthash_dst *dst)
{
struct dsthash_ent *ent;
@@ -227,19 +230,21 @@ static int htable_create(struct xt_hashlimit_info *minfo, int family)
return 0;
}
-static int select_all(struct xt_hashlimit_htable *ht, struct dsthash_ent *he)
+static bool select_all(const struct xt_hashlimit_htable *ht,
+ const struct dsthash_ent *he)
{
return 1;
}
-static int select_gc(struct xt_hashlimit_htable *ht, struct dsthash_ent *he)
+static bool select_gc(const struct xt_hashlimit_htable *ht,
+ const struct dsthash_ent *he)
{
- return (jiffies >= he->expires);
+ return jiffies >= he->expires;
}
static void htable_selective_cleanup(struct xt_hashlimit_htable *ht,
- int (*select)(struct xt_hashlimit_htable *ht,
- struct dsthash_ent *he))
+ bool (*select)(const struct xt_hashlimit_htable *ht,
+ const struct dsthash_ent *he))
{
unsigned int i;
@@ -282,7 +287,8 @@ static void htable_destroy(struct xt_hashlimit_htable *hinfo)
vfree(hinfo);
}
-static struct xt_hashlimit_htable *htable_find_get(char *name, int family)
+static struct xt_hashlimit_htable *htable_find_get(const char *name,
+ int family)
{
struct xt_hashlimit_htable *hinfo;
struct hlist_node *pos;
@@ -367,7 +373,8 @@ static inline void rateinfo_recalc(struct dsthash_ent *dh, unsigned long now)
}
static int
-hashlimit_init_dst(struct xt_hashlimit_htable *hinfo, struct dsthash_dst *dst,
+hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
+ struct dsthash_dst *dst,
const struct sk_buff *skb, unsigned int protoff)
{
__be16 _ports[2], *ports;
@@ -432,7 +439,7 @@ hashlimit_init_dst(struct xt_hashlimit_htable *hinfo, struct dsthash_dst *dst,
return 0;
}
-static int
+static bool
hashlimit_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -440,10 +447,10 @@ hashlimit_match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct xt_hashlimit_info *r =
- ((struct xt_hashlimit_info *)matchinfo)->u.master;
+ const struct xt_hashlimit_info *r =
+ ((const struct xt_hashlimit_info *)matchinfo)->u.master;
struct xt_hashlimit_htable *hinfo = r->hinfo;
unsigned long now = jiffies;
struct dsthash_ent *dh;
@@ -478,20 +485,20 @@ hashlimit_match(const struct sk_buff *skb,
/* We're underlimit. */
dh->rateinfo.credit -= dh->rateinfo.cost;
spin_unlock_bh(&hinfo->lock);
- return 1;
+ return true;
}
spin_unlock_bh(&hinfo->lock);
/* default case: we're overlimit, thus don't match */
- return 0;
+ return false;
hotdrop:
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
-static int
+static bool
hashlimit_checkentry(const char *tablename,
const void *inf,
const struct xt_match *match,
@@ -505,20 +512,20 @@ hashlimit_checkentry(const char *tablename,
user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) {
printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n",
r->cfg.avg, r->cfg.burst);
- return 0;
+ return false;
}
if (r->cfg.mode == 0 ||
r->cfg.mode > (XT_HASHLIMIT_HASH_DPT |
XT_HASHLIMIT_HASH_DIP |
XT_HASHLIMIT_HASH_SIP |
XT_HASHLIMIT_HASH_SPT))
- return 0;
+ return false;
if (!r->cfg.gc_interval)
- return 0;
+ return false;
if (!r->cfg.expire)
- return 0;
+ return false;
if (r->name[sizeof(r->name) - 1] != '\0')
- return 0;
+ return false;
/* This is the best we've got: We cannot release and re-grab lock,
* since checkentry() is called before x_tables.c grabs xt_mutex.
@@ -530,19 +537,19 @@ hashlimit_checkentry(const char *tablename,
r->hinfo = htable_find_get(r->name, match->family);
if (!r->hinfo && htable_create(r, match->family) != 0) {
mutex_unlock(&hlimit_mutex);
- return 0;
+ return false;
}
mutex_unlock(&hlimit_mutex);
/* Ugly hack: For SMP, we only want to use one set */
r->u.master = r;
- return 1;
+ return true;
}
static void
hashlimit_destroy(const struct xt_match *match, void *matchinfo)
{
- struct xt_hashlimit_info *r = matchinfo;
+ const struct xt_hashlimit_info *r = matchinfo;
htable_put(r->hinfo);
}
@@ -571,7 +578,7 @@ static int compat_to_user(void __user *dst, void *src)
}
#endif
-static struct xt_match xt_hashlimit[] = {
+static struct xt_match xt_hashlimit[] __read_mostly = {
{
.name = "hashlimit",
.family = AF_INET,
@@ -694,7 +701,7 @@ static int dl_seq_show(struct seq_file *s, void *v)
return 0;
}
-static struct seq_operations dl_seq_ops = {
+static const struct seq_operations dl_seq_ops = {
.start = dl_seq_start,
.next = dl_seq_next,
.stop = dl_seq_stop,
@@ -731,7 +738,7 @@ static int __init xt_hashlimit_init(void)
err = -ENOMEM;
hashlimit_cachep = kmem_cache_create("xt_hashlimit",
sizeof(struct dsthash_ent), 0, 0,
- NULL, NULL);
+ NULL);
if (!hashlimit_cachep) {
printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n");
goto err2;
diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c
index c139b2f43a10..0a1f4c6bcdef 100644
--- a/net/netfilter/xt_helper.c
+++ b/net/netfilter/xt_helper.c
@@ -22,13 +22,8 @@ MODULE_DESCRIPTION("iptables helper match module");
MODULE_ALIAS("ipt_helper");
MODULE_ALIAS("ip6t_helper");
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -36,61 +31,51 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_helper_info *info = matchinfo;
- struct nf_conn *ct;
- struct nf_conn_help *master_help;
+ const struct nf_conn *ct;
+ const struct nf_conn_help *master_help;
+ const struct nf_conntrack_helper *helper;
enum ip_conntrack_info ctinfo;
- int ret = info->invert;
+ bool ret = info->invert;
- ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
- if (!ct) {
- DEBUGP("xt_helper: Eek! invalid conntrack?\n");
+ ct = nf_ct_get(skb, &ctinfo);
+ if (!ct || !ct->master)
return ret;
- }
-
- if (!ct->master) {
- DEBUGP("xt_helper: conntrack %p has no master\n", ct);
- return ret;
- }
- read_lock_bh(&nf_conntrack_lock);
master_help = nfct_help(ct->master);
- if (!master_help || !master_help->helper) {
- DEBUGP("xt_helper: master ct %p has no helper\n",
- exp->expectant);
- goto out_unlock;
- }
+ if (!master_help)
+ return ret;
- DEBUGP("master's name = %s , info->name = %s\n",
- ct->master->helper->name, info->name);
+ /* rcu_read_lock()ed by nf_hook_slow */
+ helper = rcu_dereference(master_help->helper);
+ if (!helper)
+ return ret;
if (info->name[0] == '\0')
- ret ^= 1;
+ ret = !ret;
else
ret ^= !strncmp(master_help->helper->name, info->name,
strlen(master_help->helper->name));
-out_unlock:
- read_unlock_bh(&nf_conntrack_lock);
return ret;
}
-static int check(const char *tablename,
- const void *inf,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int hook_mask)
+static bool check(const char *tablename,
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
{
struct xt_helper_info *info = matchinfo;
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
- return 0;
+ return false;
}
info->name[29] = '\0';
- return 1;
+ return true;
}
static void
@@ -99,7 +84,7 @@ destroy(const struct xt_match *match, void *matchinfo)
nf_ct_l3proto_module_put(match->family);
}
-static struct xt_match xt_helper_match[] = {
+static struct xt_match xt_helper_match[] __read_mostly = {
{
.name = "helper",
.family = AF_INET,
diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c
index 77288c5ada78..3dad173d9735 100644
--- a/net/netfilter/xt_length.c
+++ b/net/netfilter/xt_length.c
@@ -20,7 +20,7 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_length");
MODULE_ALIAS("ip6t_length");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -28,7 +28,7 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_length_info *info = matchinfo;
u_int16_t pktlen = ntohs(ip_hdr(skb)->tot_len);
@@ -36,7 +36,7 @@ match(const struct sk_buff *skb,
return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
}
-static int
+static bool
match6(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -44,16 +44,16 @@ match6(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_length_info *info = matchinfo;
- const u_int16_t pktlen = (ntohs(ipv6_hdr(skb)->payload_len) +
- sizeof(struct ipv6hdr));
+ const u_int16_t pktlen = ntohs(ipv6_hdr(skb)->payload_len) +
+ sizeof(struct ipv6hdr);
return (pktlen >= info->min && pktlen <= info->max) ^ info->invert;
}
-static struct xt_match xt_length_match[] = {
+static struct xt_match xt_length_match[] __read_mostly = {
{
.name = "length",
.family = AF_INET,
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index 571a72ab89ad..4fcca797150f 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -57,7 +57,7 @@ static DEFINE_SPINLOCK(limit_lock);
#define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ)
-static int
+static bool
ipt_limit_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -65,9 +65,10 @@ ipt_limit_match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
- struct xt_rateinfo *r = ((struct xt_rateinfo *)matchinfo)->master;
+ struct xt_rateinfo *r =
+ ((const struct xt_rateinfo *)matchinfo)->master;
unsigned long now = jiffies;
spin_lock_bh(&limit_lock);
@@ -79,11 +80,11 @@ ipt_limit_match(const struct sk_buff *skb,
/* We're not limited. */
r->credit -= r->cost;
spin_unlock_bh(&limit_lock);
- return 1;
+ return true;
}
spin_unlock_bh(&limit_lock);
- return 0;
+ return false;
}
/* Precision saver. */
@@ -98,7 +99,7 @@ user2credits(u_int32_t user)
return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE;
}
-static int
+static bool
ipt_limit_checkentry(const char *tablename,
const void *inf,
const struct xt_match *match,
@@ -112,7 +113,7 @@ ipt_limit_checkentry(const char *tablename,
|| user2credits(r->avg * r->burst) < user2credits(r->avg)) {
printk("Overflow in xt_limit, try lower: %u/%u\n",
r->avg, r->burst);
- return 0;
+ return false;
}
/* For SMP, we only want to use one set of counters. */
@@ -125,7 +126,7 @@ ipt_limit_checkentry(const char *tablename,
r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
r->cost = user2credits(r->avg);
}
- return 1;
+ return true;
}
#ifdef CONFIG_COMPAT
@@ -144,7 +145,7 @@ struct compat_xt_rateinfo {
* master pointer, which does not need to be preserved. */
static void compat_from_user(void *dst, void *src)
{
- struct compat_xt_rateinfo *cm = src;
+ const struct compat_xt_rateinfo *cm = src;
struct xt_rateinfo m = {
.avg = cm->avg,
.burst = cm->burst,
@@ -158,7 +159,7 @@ static void compat_from_user(void *dst, void *src)
static int compat_to_user(void __user *dst, void *src)
{
- struct xt_rateinfo *m = src;
+ const struct xt_rateinfo *m = src;
struct compat_xt_rateinfo cm = {
.avg = m->avg,
.burst = m->burst,
@@ -172,7 +173,7 @@ static int compat_to_user(void __user *dst, void *src)
}
#endif /* CONFIG_COMPAT */
-static struct xt_match xt_limit_match[] = {
+static struct xt_match xt_limit_match[] __read_mostly = {
{
.name = "limit",
.family = AF_INET,
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
index 1d3a1d98b885..00490d777a0f 100644
--- a/net/netfilter/xt_mac.c
+++ b/net/netfilter/xt_mac.c
@@ -24,7 +24,7 @@ MODULE_DESCRIPTION("iptables mac matching module");
MODULE_ALIAS("ipt_mac");
MODULE_ALIAS("ip6t_mac");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -32,19 +32,19 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_mac_info *info = matchinfo;
/* Is mac pointer valid? */
- return (skb_mac_header(skb) >= skb->head &&
- (skb_mac_header(skb) + ETH_HLEN) <= skb->data
- /* If so, compare... */
- && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
- ^ info->invert));
+ return skb_mac_header(skb) >= skb->head &&
+ skb_mac_header(skb) + ETH_HLEN <= skb->data
+ /* If so, compare... */
+ && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr))
+ ^ info->invert);
}
-static struct xt_match xt_mac_match[] = {
+static struct xt_match xt_mac_match[] __read_mostly = {
{
.name = "mac",
.family = AF_INET,
diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c
index 39911dddb011..c02a7f8f3925 100644
--- a/net/netfilter/xt_mark.c
+++ b/net/netfilter/xt_mark.c
@@ -19,7 +19,7 @@ MODULE_DESCRIPTION("iptables mark matching module");
MODULE_ALIAS("ipt_mark");
MODULE_ALIAS("ip6t_mark");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -27,14 +27,14 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_mark_info *info = matchinfo;
return ((skb->mark & info->mask) == info->mark) ^ info->invert;
}
-static int
+static bool
checkentry(const char *tablename,
const void *entry,
const struct xt_match *match,
@@ -45,9 +45,9 @@ checkentry(const char *tablename,
if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) {
printk(KERN_WARNING "mark: only supports 32bit mark\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
#ifdef CONFIG_COMPAT
@@ -60,7 +60,7 @@ struct compat_xt_mark_info {
static void compat_from_user(void *dst, void *src)
{
- struct compat_xt_mark_info *cm = src;
+ const struct compat_xt_mark_info *cm = src;
struct xt_mark_info m = {
.mark = cm->mark,
.mask = cm->mask,
@@ -71,7 +71,7 @@ static void compat_from_user(void *dst, void *src)
static int compat_to_user(void __user *dst, void *src)
{
- struct xt_mark_info *m = src;
+ const struct xt_mark_info *m = src;
struct compat_xt_mark_info cm = {
.mark = m->mark,
.mask = m->mask,
@@ -81,7 +81,7 @@ static int compat_to_user(void __user *dst, void *src)
}
#endif /* CONFIG_COMPAT */
-static struct xt_match xt_mark_match[] = {
+static struct xt_match xt_mark_match[] __read_mostly = {
{
.name = "mark",
.family = AF_INET,
diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c
index 4dce2a81702a..e8ae10284acd 100644
--- a/net/netfilter/xt_multiport.c
+++ b/net/netfilter/xt_multiport.c
@@ -33,24 +33,24 @@ MODULE_ALIAS("ip6t_multiport");
#endif
/* Returns 1 if the port is matched by the test, 0 otherwise. */
-static inline int
+static inline bool
ports_match(const u_int16_t *portlist, enum xt_multiport_flags flags,
u_int8_t count, u_int16_t src, u_int16_t dst)
{
unsigned int i;
for (i = 0; i < count; i++) {
if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src)
- return 1;
+ return true;
if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst)
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* Returns 1 if the port is matched by the test, 0 otherwise. */
-static inline int
+static inline bool
ports_match_v1(const struct xt_multiport_v1 *minfo,
u_int16_t src, u_int16_t dst)
{
@@ -67,34 +67,34 @@ ports_match_v1(const struct xt_multiport_v1 *minfo,
if (minfo->flags == XT_MULTIPORT_SOURCE
&& src >= s && src <= e)
- return 1 ^ minfo->invert;
+ return true ^ minfo->invert;
if (minfo->flags == XT_MULTIPORT_DESTINATION
&& dst >= s && dst <= e)
- return 1 ^ minfo->invert;
+ return true ^ minfo->invert;
if (minfo->flags == XT_MULTIPORT_EITHER
&& ((dst >= s && dst <= e)
|| (src >= s && src <= e)))
- return 1 ^ minfo->invert;
+ return true ^ minfo->invert;
} else {
/* exact port matching */
duprintf("src or dst matches with %d?\n", s);
if (minfo->flags == XT_MULTIPORT_SOURCE
&& src == s)
- return 1 ^ minfo->invert;
+ return true ^ minfo->invert;
if (minfo->flags == XT_MULTIPORT_DESTINATION
&& dst == s)
- return 1 ^ minfo->invert;
+ return true ^ minfo->invert;
if (minfo->flags == XT_MULTIPORT_EITHER
&& (src == s || dst == s))
- return 1 ^ minfo->invert;
+ return true ^ minfo->invert;
}
}
return minfo->invert;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -102,13 +102,13 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
__be16 _ports[2], *pptr;
const struct xt_multiport *multiinfo = matchinfo;
if (offset)
- return 0;
+ return false;
pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
if (pptr == NULL) {
@@ -116,8 +116,8 @@ match(const struct sk_buff *skb,
* can't. Hence, no choice but to drop.
*/
duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
return ports_match(multiinfo->ports,
@@ -125,7 +125,7 @@ match(const struct sk_buff *skb,
ntohs(pptr[0]), ntohs(pptr[1]));
}
-static int
+static bool
match_v1(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -133,13 +133,13 @@ match_v1(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
__be16 _ports[2], *pptr;
const struct xt_multiport_v1 *multiinfo = matchinfo;
if (offset)
- return 0;
+ return false;
pptr = skb_header_pointer(skb, protoff, sizeof(_ports), _ports);
if (pptr == NULL) {
@@ -147,14 +147,14 @@ match_v1(const struct sk_buff *skb,
* can't. Hence, no choice but to drop.
*/
duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
return ports_match_v1(multiinfo, ntohs(pptr[0]), ntohs(pptr[1]));
}
-static inline int
+static inline bool
check(u_int16_t proto,
u_int8_t ip_invflags,
u_int8_t match_flags,
@@ -172,7 +172,7 @@ check(u_int16_t proto,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
checkentry(const char *tablename,
const void *info,
const struct xt_match *match,
@@ -186,7 +186,7 @@ checkentry(const char *tablename,
multiinfo->count);
}
-static int
+static bool
checkentry_v1(const char *tablename,
const void *info,
const struct xt_match *match,
@@ -200,7 +200,7 @@ checkentry_v1(const char *tablename,
multiinfo->count);
}
-static int
+static bool
checkentry6(const char *tablename,
const void *info,
const struct xt_match *match,
@@ -214,7 +214,7 @@ checkentry6(const char *tablename,
multiinfo->count);
}
-static int
+static bool
checkentry6_v1(const char *tablename,
const void *info,
const struct xt_match *match,
@@ -228,7 +228,7 @@ checkentry6_v1(const char *tablename,
multiinfo->count);
}
-static struct xt_match xt_multiport_match[] = {
+static struct xt_match xt_multiport_match[] __read_mostly = {
{
.name = "multiport",
.family = AF_INET,
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index 35a0fe200c39..f47cab7a696d 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -14,8 +14,6 @@
#include <linux/netfilter/xt_physdev.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_bridge.h>
-#define MATCH 1
-#define NOMATCH 0
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>");
@@ -23,7 +21,7 @@ MODULE_DESCRIPTION("iptables bridge physical device match module");
MODULE_ALIAS("ipt_physdev");
MODULE_ALIAS("ip6t_physdev");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -31,14 +29,14 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
int i;
static const char nulldevname[IFNAMSIZ];
const struct xt_physdev_info *info = matchinfo;
- unsigned int ret;
+ bool ret;
const char *indev, *outdev;
- struct nf_bridge_info *nf_bridge;
+ const struct nf_bridge_info *nf_bridge;
/* Not a bridged IP packet or no info available yet:
* LOCAL_OUT/mangle and LOCAL_OUT/nat don't know if
@@ -47,61 +45,61 @@ match(const struct sk_buff *skb,
/* Return MATCH if the invert flags of the used options are on */
if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
!(info->invert & XT_PHYSDEV_OP_BRIDGED))
- return NOMATCH;
+ return false;
if ((info->bitmask & XT_PHYSDEV_OP_ISIN) &&
!(info->invert & XT_PHYSDEV_OP_ISIN))
- return NOMATCH;
+ return false;
if ((info->bitmask & XT_PHYSDEV_OP_ISOUT) &&
!(info->invert & XT_PHYSDEV_OP_ISOUT))
- return NOMATCH;
+ return false;
if ((info->bitmask & XT_PHYSDEV_OP_IN) &&
!(info->invert & XT_PHYSDEV_OP_IN))
- return NOMATCH;
+ return false;
if ((info->bitmask & XT_PHYSDEV_OP_OUT) &&
!(info->invert & XT_PHYSDEV_OP_OUT))
- return NOMATCH;
- return MATCH;
+ return false;
+ return true;
}
/* This only makes sense in the FORWARD and POSTROUTING chains */
if ((info->bitmask & XT_PHYSDEV_OP_BRIDGED) &&
(!!(nf_bridge->mask & BRNF_BRIDGED) ^
!(info->invert & XT_PHYSDEV_OP_BRIDGED)))
- return NOMATCH;
+ return false;
if ((info->bitmask & XT_PHYSDEV_OP_ISIN &&
(!nf_bridge->physindev ^ !!(info->invert & XT_PHYSDEV_OP_ISIN))) ||
(info->bitmask & XT_PHYSDEV_OP_ISOUT &&
(!nf_bridge->physoutdev ^ !!(info->invert & XT_PHYSDEV_OP_ISOUT))))
- return NOMATCH;
+ return false;
if (!(info->bitmask & XT_PHYSDEV_OP_IN))
goto match_outdev;
indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
- for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+ for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
ret |= (((const unsigned int *)indev)[i]
^ ((const unsigned int *)info->physindev)[i])
& ((const unsigned int *)info->in_mask)[i];
}
- if ((ret == 0) ^ !(info->invert & XT_PHYSDEV_OP_IN))
- return NOMATCH;
+ if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
+ return false;
match_outdev:
if (!(info->bitmask & XT_PHYSDEV_OP_OUT))
- return MATCH;
+ return true;
outdev = nf_bridge->physoutdev ?
nf_bridge->physoutdev->name : nulldevname;
- for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned int); i++) {
+ for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) {
ret |= (((const unsigned int *)outdev)[i]
^ ((const unsigned int *)info->physoutdev)[i])
& ((const unsigned int *)info->out_mask)[i];
}
- return (ret != 0) ^ !(info->invert & XT_PHYSDEV_OP_OUT);
+ return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT);
}
-static int
+static bool
checkentry(const char *tablename,
const void *ip,
const struct xt_match *match,
@@ -112,7 +110,7 @@ checkentry(const char *tablename,
if (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||
info->bitmask & ~XT_PHYSDEV_OP_MASK)
- return 0;
+ return false;
if (info->bitmask & XT_PHYSDEV_OP_OUT &&
(!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||
info->invert & XT_PHYSDEV_OP_BRIDGED) &&
@@ -122,12 +120,12 @@ checkentry(const char *tablename,
"OUTPUT, FORWARD and POSTROUTING chains for non-bridged "
"traffic is not supported anymore.\n");
if (hook_mask & (1 << NF_IP_LOCAL_OUT))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match xt_physdev_match[] = {
+static struct xt_match xt_physdev_match[] __read_mostly = {
{
.name = "physdev",
.family = AF_INET,
diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c
index e1409fc5c288..a52925f12f35 100644
--- a/net/netfilter/xt_pkttype.c
+++ b/net/netfilter/xt_pkttype.c
@@ -21,29 +21,29 @@ MODULE_DESCRIPTION("IP tables match to match on linklayer packet type");
MODULE_ALIAS("ipt_pkttype");
MODULE_ALIAS("ip6t_pkttype");
-static int match(const struct sk_buff *skb,
+static bool match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const struct xt_match *match,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
u_int8_t type;
const struct xt_pkttype_info *info = matchinfo;
if (skb->pkt_type == PACKET_LOOPBACK)
- type = (MULTICAST(ip_hdr(skb)->daddr)
+ type = MULTICAST(ip_hdr(skb)->daddr)
? PACKET_MULTICAST
- : PACKET_BROADCAST);
+ : PACKET_BROADCAST;
else
type = skb->pkt_type;
return (type == info->pkttype) ^ info->invert;
}
-static struct xt_match xt_pkttype_match[] = {
+static struct xt_match xt_pkttype_match[] __read_mostly = {
{
.name = "pkttype",
.family = AF_INET,
diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c
index 15b45a95ec13..6d6d3b7fcbb5 100644
--- a/net/netfilter/xt_policy.c
+++ b/net/netfilter/xt_policy.c
@@ -20,7 +20,7 @@ MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("Xtables IPsec policy matching module");
MODULE_LICENSE("GPL");
-static inline int
+static inline bool
xt_addr_cmp(const union xt_policy_addr *a1, const union xt_policy_addr *m,
const union xt_policy_addr *a2, unsigned short family)
{
@@ -30,11 +30,11 @@ xt_addr_cmp(const union xt_policy_addr *a1, const union xt_policy_addr *m,
case AF_INET6:
return !ipv6_masked_addr_cmp(&a1->a6, &m->a6, &a2->a6);
}
- return 0;
+ return false;
}
-static inline int
-match_xfrm_state(struct xfrm_state *x, const struct xt_policy_elem *e,
+static inline bool
+match_xfrm_state(const struct xfrm_state *x, const struct xt_policy_elem *e,
unsigned short family)
{
#define MATCH_ADDR(x,y,z) (!e->match.x || \
@@ -55,7 +55,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,
unsigned short family)
{
const struct xt_policy_elem *e;
- struct sec_path *sp = skb->sp;
+ const struct sec_path *sp = skb->sp;
int strict = info->flags & XT_POLICY_MATCH_STRICT;
int i, pos;
@@ -85,7 +85,7 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
unsigned short family)
{
const struct xt_policy_elem *e;
- struct dst_entry *dst = skb->dst;
+ const struct dst_entry *dst = skb->dst;
int strict = info->flags & XT_POLICY_MATCH_STRICT;
int i, pos;
@@ -108,14 +108,14 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info,
return strict ? i == info->len : 0;
}
-static int match(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct xt_match *match,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop)
+static bool match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop)
{
const struct xt_policy_info *info = matchinfo;
int ret;
@@ -126,45 +126,45 @@ static int match(const struct sk_buff *skb,
ret = match_policy_out(skb, info, match->family);
if (ret < 0)
- ret = info->flags & XT_POLICY_MATCH_NONE ? 1 : 0;
+ ret = info->flags & XT_POLICY_MATCH_NONE ? true : false;
else if (info->flags & XT_POLICY_MATCH_NONE)
- ret = 0;
+ ret = false;
return ret;
}
-static int checkentry(const char *tablename, const void *ip_void,
- const struct xt_match *match,
- void *matchinfo, unsigned int hook_mask)
+static bool checkentry(const char *tablename, const void *ip_void,
+ const struct xt_match *match,
+ void *matchinfo, unsigned int hook_mask)
{
struct xt_policy_info *info = matchinfo;
if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) {
printk(KERN_ERR "xt_policy: neither incoming nor "
"outgoing policy selected\n");
- return 0;
+ return false;
}
/* hook values are equal for IPv4 and IPv6 */
if (hook_mask & (1 << NF_IP_PRE_ROUTING | 1 << NF_IP_LOCAL_IN)
&& info->flags & XT_POLICY_MATCH_OUT) {
printk(KERN_ERR "xt_policy: output policy not valid in "
"PRE_ROUTING and INPUT\n");
- return 0;
+ return false;
}
if (hook_mask & (1 << NF_IP_POST_ROUTING | 1 << NF_IP_LOCAL_OUT)
&& info->flags & XT_POLICY_MATCH_IN) {
printk(KERN_ERR "xt_policy: input policy not valid in "
"POST_ROUTING and OUTPUT\n");
- return 0;
+ return false;
}
if (info->len > XT_POLICY_MAX_ELEM) {
printk(KERN_ERR "xt_policy: too many policy elements\n");
- return 0;
+ return false;
}
- return 1;
+ return true;
}
-static struct xt_match xt_policy_match[] = {
+static struct xt_match xt_policy_match[] __read_mostly = {
{
.name = "policy",
.family = AF_INET,
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index bfdde06ca0b7..dae97445b87b 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -16,19 +16,20 @@ MODULE_ALIAS("ip6t_quota");
static DEFINE_SPINLOCK(quota_lock);
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
const struct xt_match *match, const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+ int offset, unsigned int protoff, bool *hotdrop)
{
- struct xt_quota_info *q = ((struct xt_quota_info *)matchinfo)->master;
- int ret = q->flags & XT_QUOTA_INVERT ? 1 : 0;
+ struct xt_quota_info *q =
+ ((const struct xt_quota_info *)matchinfo)->master;
+ bool ret = q->flags & XT_QUOTA_INVERT;
spin_lock_bh(&quota_lock);
if (q->quota >= skb->len) {
q->quota -= skb->len;
- ret ^= 1;
+ ret = !ret;
} else {
/* we do not allow even small packets from now on */
q->quota = 0;
@@ -38,21 +39,21 @@ match(const struct sk_buff *skb,
return ret;
}
-static int
+static bool
checkentry(const char *tablename, const void *entry,
const struct xt_match *match, void *matchinfo,
unsigned int hook_mask)
{
- struct xt_quota_info *q = (struct xt_quota_info *)matchinfo;
+ struct xt_quota_info *q = matchinfo;
if (q->flags & ~XT_QUOTA_MASK)
- return 0;
+ return false;
/* For SMP, we only want to use one set of counters. */
q->master = q;
- return 1;
+ return true;
}
-static struct xt_match xt_quota_match[] = {
+static struct xt_match xt_quota_match[] __read_mostly = {
{
.name = "quota",
.family = AF_INET,
diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c
index c2017f8af9c4..cc3e76d77a99 100644
--- a/net/netfilter/xt_realm.c
+++ b/net/netfilter/xt_realm.c
@@ -21,7 +21,7 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("X_tables realm match");
MODULE_ALIAS("ipt_realm");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -29,15 +29,15 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_realm_info *info = matchinfo;
- struct dst_entry *dst = skb->dst;
+ const struct dst_entry *dst = skb->dst;
return (info->id == (dst->tclassid & info->mask)) ^ info->invert;
}
-static struct xt_match realm_match = {
+static struct xt_match realm_match __read_mostly = {
.name = "realm",
.match = match,
.matchsize = sizeof(struct xt_realm_info),
diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c
index f86d8d769d47..c002153b80ab 100644
--- a/net/netfilter/xt_sctp.c
+++ b/net/netfilter/xt_sctp.c
@@ -23,7 +23,7 @@ MODULE_ALIAS("ipt_sctp");
#define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \
|| (!!((invflag) & (option)) ^ (cond)))
-static int
+static bool
match_flags(const struct xt_sctp_flag_info *flag_info,
const int flag_count,
u_int8_t chunktype,
@@ -31,23 +31,21 @@ match_flags(const struct xt_sctp_flag_info *flag_info,
{
int i;
- for (i = 0; i < flag_count; i++) {
- if (flag_info[i].chunktype == chunktype) {
+ for (i = 0; i < flag_count; i++)
+ if (flag_info[i].chunktype == chunktype)
return (chunkflags & flag_info[i].flag_mask) == flag_info[i].flag;
- }
- }
- return 1;
+ return true;
}
-static inline int
+static inline bool
match_packet(const struct sk_buff *skb,
unsigned int offset,
const u_int32_t *chunkmap,
int chunk_match_type,
const struct xt_sctp_flag_info *flag_info,
const int flag_count,
- int *hotdrop)
+ bool *hotdrop)
{
u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)];
sctp_chunkhdr_t _sch, *sch;
@@ -56,16 +54,15 @@ match_packet(const struct sk_buff *skb,
int i = 0;
#endif
- if (chunk_match_type == SCTP_CHUNK_MATCH_ALL) {
+ if (chunk_match_type == SCTP_CHUNK_MATCH_ALL)
SCTP_CHUNKMAP_COPY(chunkmapcopy, chunkmap);
- }
do {
sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch);
if (sch == NULL || sch->length == 0) {
duprintf("Dropping invalid SCTP packet.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n",
@@ -80,28 +77,26 @@ match_packet(const struct sk_buff *skb,
case SCTP_CHUNK_MATCH_ANY:
if (match_flags(flag_info, flag_count,
sch->type, sch->flags)) {
- return 1;
+ return true;
}
break;
case SCTP_CHUNK_MATCH_ALL:
if (match_flags(flag_info, flag_count,
- sch->type, sch->flags)) {
+ sch->type, sch->flags))
SCTP_CHUNKMAP_CLEAR(chunkmapcopy, sch->type);
- }
break;
case SCTP_CHUNK_MATCH_ONLY:
if (!match_flags(flag_info, flag_count,
- sch->type, sch->flags)) {
- return 0;
- }
+ sch->type, sch->flags))
+ return false;
break;
}
} else {
switch (chunk_match_type) {
case SCTP_CHUNK_MATCH_ONLY:
- return 0;
+ return false;
}
}
} while (offset < skb->len);
@@ -110,16 +105,16 @@ match_packet(const struct sk_buff *skb,
case SCTP_CHUNK_MATCH_ALL:
return SCTP_CHUNKMAP_IS_CLEAR(chunkmap);
case SCTP_CHUNK_MATCH_ANY:
- return 0;
+ return false;
case SCTP_CHUNK_MATCH_ONLY:
- return 1;
+ return true;
}
/* This will never be reached, but required to stop compiler whine */
- return 0;
+ return false;
}
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -127,29 +122,29 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_sctp_info *info = matchinfo;
sctp_sctphdr_t _sh, *sh;
if (offset) {
duprintf("Dropping non-first fragment.. FIXME\n");
- return 0;
+ return false;
}
sh = skb_header_pointer(skb, protoff, sizeof(_sh), &_sh);
if (sh == NULL) {
duprintf("Dropping evil TCP offset=0 tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest));
- return SCCHECK(((ntohs(sh->source) >= info->spts[0])
- && (ntohs(sh->source) <= info->spts[1])),
+ return SCCHECK(ntohs(sh->source) >= info->spts[0]
+ && ntohs(sh->source) <= info->spts[1],
XT_SCTP_SRC_PORTS, info->flags, info->invflags)
- && SCCHECK(((ntohs(sh->dest) >= info->dpts[0])
- && (ntohs(sh->dest) <= info->dpts[1])),
+ && SCCHECK(ntohs(sh->dest) >= info->dpts[0]
+ && ntohs(sh->dest) <= info->dpts[1],
XT_SCTP_DEST_PORTS, info->flags, info->invflags)
&& SCCHECK(match_packet(skb, protoff + sizeof (sctp_sctphdr_t),
info->chunkmap, info->chunk_match_type,
@@ -158,7 +153,7 @@ match(const struct sk_buff *skb,
XT_SCTP_CHUNK_TYPES, info->flags, info->invflags);
}
-static int
+static bool
checkentry(const char *tablename,
const void *inf,
const struct xt_match *match,
@@ -177,7 +172,7 @@ checkentry(const char *tablename,
| SCTP_CHUNK_MATCH_ONLY)));
}
-static struct xt_match xt_sctp_match[] = {
+static struct xt_match xt_sctp_match[] __read_mostly = {
{
.name = "sctp",
.family = AF_INET,
diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c
index 149294f7df71..e0a528df19a7 100644
--- a/net/netfilter/xt_state.c
+++ b/net/netfilter/xt_state.c
@@ -20,7 +20,7 @@ MODULE_DESCRIPTION("ip[6]_tables connection tracking state match module");
MODULE_ALIAS("ipt_state");
MODULE_ALIAS("ip6t_state");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -28,7 +28,7 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_state_info *sinfo = matchinfo;
enum ip_conntrack_info ctinfo;
@@ -44,18 +44,18 @@ match(const struct sk_buff *skb,
return (sinfo->statemask & statebit);
}
-static int check(const char *tablename,
- const void *inf,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int hook_mask)
+static bool check(const char *tablename,
+ const void *inf,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
{
if (nf_ct_l3proto_try_module_get(match->family) < 0) {
printk(KERN_WARNING "can't load conntrack support for "
"proto=%d\n", match->family);
- return 0;
+ return false;
}
- return 1;
+ return true;
}
static void
@@ -64,7 +64,7 @@ destroy(const struct xt_match *match, void *matchinfo)
nf_ct_l3proto_module_put(match->family);
}
-static struct xt_match xt_state_match[] = {
+static struct xt_match xt_state_match[] __read_mostly = {
{
.name = "state",
.family = AF_INET,
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
index 091a9f89f5d5..4089dae4e286 100644
--- a/net/netfilter/xt_statistic.c
+++ b/net/netfilter/xt_statistic.c
@@ -24,26 +24,26 @@ MODULE_ALIAS("ip6t_statistic");
static DEFINE_SPINLOCK(nth_lock);
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
const struct xt_match *match, const void *matchinfo,
- int offset, unsigned int protoff, int *hotdrop)
+ int offset, unsigned int protoff, bool *hotdrop)
{
struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
- int ret = info->flags & XT_STATISTIC_INVERT ? 1 : 0;
+ bool ret = info->flags & XT_STATISTIC_INVERT;
switch (info->mode) {
case XT_STATISTIC_MODE_RANDOM:
if ((net_random() & 0x7FFFFFFF) < info->u.random.probability)
- ret ^= 1;
+ ret = !ret;
break;
case XT_STATISTIC_MODE_NTH:
info = info->master;
spin_lock_bh(&nth_lock);
if (info->u.nth.count++ == info->u.nth.every) {
info->u.nth.count = 0;
- ret ^= 1;
+ ret = !ret;
}
spin_unlock_bh(&nth_lock);
break;
@@ -52,21 +52,21 @@ match(const struct sk_buff *skb,
return ret;
}
-static int
+static bool
checkentry(const char *tablename, const void *entry,
const struct xt_match *match, void *matchinfo,
unsigned int hook_mask)
{
- struct xt_statistic_info *info = (struct xt_statistic_info *)matchinfo;
+ struct xt_statistic_info *info = matchinfo;
if (info->mode > XT_STATISTIC_MODE_MAX ||
info->flags & ~XT_STATISTIC_MASK)
- return 0;
+ return false;
info->master = info;
- return 1;
+ return true;
}
-static struct xt_match xt_statistic_match[] = {
+static struct xt_match xt_statistic_match[] __read_mostly = {
{
.name = "statistic",
.family = AF_INET,
diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c
index 999a005dbd0c..864133442cda 100644
--- a/net/netfilter/xt_string.c
+++ b/net/netfilter/xt_string.c
@@ -21,14 +21,14 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_string");
MODULE_ALIAS("ip6t_string");
-static int match(const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- const struct xt_match *match,
- const void *matchinfo,
- int offset,
- unsigned int protoff,
- int *hotdrop)
+static bool match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop)
{
const struct xt_string_info *conf = matchinfo;
struct ts_state state;
@@ -42,30 +42,30 @@ static int match(const struct sk_buff *skb,
#define STRING_TEXT_PRIV(m) ((struct xt_string_info *) m)
-static int checkentry(const char *tablename,
- const void *ip,
- const struct xt_match *match,
- void *matchinfo,
- unsigned int hook_mask)
+static bool checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
{
struct xt_string_info *conf = matchinfo;
struct ts_config *ts_conf;
/* Damn, can't handle this case properly with iptables... */
if (conf->from_offset > conf->to_offset)
- return 0;
+ return false;
if (conf->algo[XT_STRING_MAX_ALGO_NAME_SIZE - 1] != '\0')
- return 0;
+ return false;
if (conf->patlen > XT_STRING_MAX_PATTERN_SIZE)
- return 0;
+ return false;
ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,
GFP_KERNEL, TS_AUTOLOAD);
if (IS_ERR(ts_conf))
- return 0;
+ return false;
conf->config = ts_conf;
- return 1;
+ return true;
}
static void destroy(const struct xt_match *match, void *matchinfo)
@@ -73,7 +73,7 @@ static void destroy(const struct xt_match *match, void *matchinfo)
textsearch_destroy(STRING_TEXT_PRIV(matchinfo)->config);
}
-static struct xt_match xt_string_match[] = {
+static struct xt_match xt_string_match[] __read_mostly = {
{
.name = "string",
.family = AF_INET,
diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c
index 80571d0749f7..cd5f6d758c68 100644
--- a/net/netfilter/xt_tcpmss.c
+++ b/net/netfilter/xt_tcpmss.c
@@ -23,7 +23,7 @@ MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("iptables TCP MSS match module");
MODULE_ALIAS("ipt_tcpmss");
-static int
+static bool
match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -31,7 +31,7 @@ match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
const struct xt_tcpmss_match_info *info = matchinfo;
struct tcphdr _tcph, *th;
@@ -77,11 +77,11 @@ out:
return info->invert;
dropit:
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
-static struct xt_match xt_tcpmss_match[] = {
+static struct xt_match xt_tcpmss_match[] __read_mostly = {
{
.name = "tcpmss",
.family = AF_INET,
diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c
index 46414b562a19..ab7d845224fc 100644
--- a/net/netfilter/xt_tcpudp.c
+++ b/net/netfilter/xt_tcpudp.c
@@ -27,22 +27,19 @@ MODULE_ALIAS("ip6t_tcp");
/* Returns 1 if the port is matched by the range, 0 otherwise */
-static inline int
-port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
+static inline bool
+port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert)
{
- int ret;
-
- ret = (port >= min && port <= max) ^ invert;
- return ret;
+ return (port >= min && port <= max) ^ invert;
}
-static int
+static bool
tcp_find_option(u_int8_t option,
const struct sk_buff *skb,
unsigned int protoff,
unsigned int optlen,
- int invert,
- int *hotdrop)
+ bool invert,
+ bool *hotdrop)
{
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
@@ -57,8 +54,8 @@ tcp_find_option(u_int8_t option,
op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr),
optlen, _opt);
if (op == NULL) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
for (i = 0; i < optlen; ) {
@@ -70,7 +67,7 @@ tcp_find_option(u_int8_t option,
return invert;
}
-static int
+static bool
tcp_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -78,7 +75,7 @@ tcp_match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
struct tcphdr _tcph, *th;
const struct xt_tcp *tcpinfo = matchinfo;
@@ -92,51 +89,51 @@ tcp_match(const struct sk_buff *skb,
*/
if (offset == 1) {
duprintf("Dropping evil TCP offset=1 frag.\n");
- *hotdrop = 1;
+ *hotdrop = true;
}
/* Must not be a fragment. */
- return 0;
+ return false;
}
-#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
+#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg)))
th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
if (th == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil TCP offset=0 tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
ntohs(th->source),
!!(tcpinfo->invflags & XT_TCP_INV_SRCPT)))
- return 0;
+ return false;
if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
ntohs(th->dest),
!!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
- return 0;
+ return false;
if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
== tcpinfo->flg_cmp,
XT_TCP_INV_FLAGS))
- return 0;
+ return false;
if (tcpinfo->option) {
if (th->doff * 4 < sizeof(_tcph)) {
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
if (!tcp_find_option(tcpinfo->option, skb, protoff,
th->doff*4 - sizeof(_tcph),
tcpinfo->invflags & XT_TCP_INV_OPTION,
hotdrop))
- return 0;
+ return false;
}
- return 1;
+ return true;
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
tcp_checkentry(const char *tablename,
const void *info,
const struct xt_match *match,
@@ -149,7 +146,7 @@ tcp_checkentry(const char *tablename,
return !(tcpinfo->invflags & ~XT_TCP_INV_MASK);
}
-static int
+static bool
udp_match(const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
@@ -157,22 +154,22 @@ udp_match(const struct sk_buff *skb,
const void *matchinfo,
int offset,
unsigned int protoff,
- int *hotdrop)
+ bool *hotdrop)
{
struct udphdr _udph, *uh;
const struct xt_udp *udpinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
- return 0;
+ return false;
uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
if (uh == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil UDP tinygram.\n");
- *hotdrop = 1;
- return 0;
+ *hotdrop = true;
+ return false;
}
return port_match(udpinfo->spts[0], udpinfo->spts[1],
@@ -184,7 +181,7 @@ udp_match(const struct sk_buff *skb,
}
/* Called when user tries to insert an entry of this type. */
-static int
+static bool
udp_checkentry(const char *tablename,
const void *info,
const struct xt_match *match,
@@ -197,7 +194,7 @@ udp_checkentry(const char *tablename,
return !(udpinfo->invflags & ~XT_UDP_INV_MASK);
}
-static struct xt_match xt_tcpudp_match[] = {
+static struct xt_match xt_tcpudp_match[] __read_mostly = {
{
.name = "tcp",
.family = AF_INET,
diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c
new file mode 100644
index 000000000000..04b677ae8dae
--- /dev/null
+++ b/net/netfilter/xt_u32.c
@@ -0,0 +1,135 @@
+/*
+ * xt_u32 - kernel module to match u32 packet content
+ *
+ * Original author: Don Cohen <don@isis.cs3-inc.com>
+ * © Jan Engelhardt <jengelh@gmx.de>, 2007
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_u32.h>
+
+static bool u32_match_it(const struct xt_u32 *data,
+ const struct sk_buff *skb)
+{
+ const struct xt_u32_test *ct;
+ unsigned int testind;
+ unsigned int nnums;
+ unsigned int nvals;
+ unsigned int i;
+ u_int32_t pos;
+ u_int32_t val;
+ u_int32_t at;
+ int ret;
+
+ /*
+ * Small example: "0 >> 28 == 4 && 8 & 0xFF0000 >> 16 = 6, 17"
+ * (=IPv4 and (TCP or UDP)). Outer loop runs over the "&&" operands.
+ */
+ for (testind = 0; testind < data->ntests; ++testind) {
+ ct = &data->tests[testind];
+ at = 0;
+ pos = ct->location[0].number;
+
+ if (skb->len < 4 || pos > skb->len - 4);
+ return false;
+
+ ret = skb_copy_bits(skb, pos, &val, sizeof(val));
+ BUG_ON(ret < 0);
+ val = ntohl(val);
+ nnums = ct->nnums;
+
+ /* Inner loop runs over "&", "<<", ">>" and "@" operands */
+ for (i = 1; i < nnums; ++i) {
+ u_int32_t number = ct->location[i].number;
+ switch (ct->location[i].nextop) {
+ case XT_U32_AND:
+ val &= number;
+ break;
+ case XT_U32_LEFTSH:
+ val <<= number;
+ break;
+ case XT_U32_RIGHTSH:
+ val >>= number;
+ break;
+ case XT_U32_AT:
+ if (at + val < at)
+ return false;
+ at += val;
+ pos = number;
+ if (at + 4 < at || skb->len < at + 4 ||
+ pos > skb->len - at - 4)
+ return false;
+
+ ret = skb_copy_bits(skb, at + pos, &val,
+ sizeof(val));
+ BUG_ON(ret < 0);
+ val = ntohl(val);
+ break;
+ }
+ }
+
+ /* Run over the "," and ":" operands */
+ nvals = ct->nvalues;
+ for (i = 0; i < nvals; ++i)
+ if (ct->value[i].min <= val && val <= ct->value[i].max)
+ break;
+
+ if (i >= ct->nvalues)
+ return false;
+ }
+
+ return true;
+}
+
+static bool u32_match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo,
+ int offset, unsigned int protoff, bool *hotdrop)
+{
+ const struct xt_u32 *data = matchinfo;
+ bool ret;
+
+ ret = u32_match_it(data, skb);
+ return ret ^ data->invert;
+}
+
+static struct xt_match u32_reg[] __read_mostly = {
+ {
+ .name = "u32",
+ .family = AF_INET,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+ {
+ .name = "u32",
+ .family = AF_INET6,
+ .match = u32_match,
+ .matchsize = sizeof(struct xt_u32),
+ .me = THIS_MODULE,
+ },
+};
+
+static int __init xt_u32_init(void)
+{
+ return xt_register_matches(u32_reg, ARRAY_SIZE(u32_reg));
+}
+
+static void __exit xt_u32_exit(void)
+{
+ xt_unregister_matches(u32_reg, ARRAY_SIZE(u32_reg));
+}
+
+module_init(xt_u32_init);
+module_exit(xt_u32_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
+MODULE_DESCRIPTION("netfilter u32 match module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_u32");
+MODULE_ALIAS("ip6t_u32");
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 24b660f16ce3..c060e3f991f1 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -41,6 +41,7 @@
#include "netlabel_user.h"
#include "netlabel_cipso_v4.h"
+#include "netlabel_mgmt.h"
/* Argument struct for cipso_v4_doi_walk() */
struct netlbl_cipsov4_doiwalk_arg {
@@ -419,6 +420,8 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
ret_val = netlbl_cipsov4_add_pass(info);
break;
}
+ if (ret_val == 0)
+ netlbl_mgmt_protocount_inc();
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
&audit_info);
@@ -694,6 +697,8 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
ret_val = cipso_v4_doi_remove(doi,
&audit_info,
netlbl_cipsov4_doi_free);
+ if (ret_val == 0)
+ netlbl_mgmt_protocount_dec();
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
&audit_info);
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index b165712aaa70..4f50949722a9 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -38,6 +38,7 @@
#include "netlabel_domainhash.h"
#include "netlabel_unlabeled.h"
#include "netlabel_user.h"
+#include "netlabel_mgmt.h"
/*
* Security Attribute Functions
@@ -245,6 +246,26 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
*/
/**
+ * netlbl_enabled - Determine if the NetLabel subsystem is enabled
+ *
+ * Description:
+ * The LSM can use this function to determine if it should use NetLabel
+ * security attributes in it's enforcement mechanism. Currently, NetLabel is
+ * considered to be enabled when it's configuration contains a valid setup for
+ * at least one labeled protocol (i.e. NetLabel can understand incoming
+ * labeled packets of at least one type); otherwise NetLabel is considered to
+ * be disabled.
+ *
+ */
+int netlbl_enabled(void)
+{
+ /* At some point we probably want to expose this mechanism to the user
+ * as well so that admins can toggle NetLabel regardless of the
+ * configuration */
+ return (netlbl_mgmt_protocount_value() > 0 ? 1 : 0);
+}
+
+/**
* netlbl_socket_setattr - Label a socket using the correct protocol
* @sk: the socket to label
* @secattr: the security attributes
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index e00fc219c72b..5315dacc5222 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -42,6 +42,10 @@
#include "netlabel_user.h"
#include "netlabel_mgmt.h"
+/* NetLabel configured protocol count */
+static DEFINE_SPINLOCK(netlabel_mgmt_protocount_lock);
+static u32 netlabel_mgmt_protocount = 0;
+
/* Argument struct for netlbl_domhsh_walk() */
struct netlbl_domhsh_walk_arg {
struct netlink_callback *nl_cb;
@@ -67,6 +71,67 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
};
/*
+ * NetLabel Misc Managment Functions
+ */
+
+/**
+ * netlbl_mgmt_protocount_inc - Increment the configured labeled protocol count
+ *
+ * Description:
+ * Increment the number of labeled protocol configurations in the current
+ * NetLabel configuration. Keep track of this for use in determining if
+ * NetLabel label enforcement should be active/enabled or not in the LSM.
+ *
+ */
+void netlbl_mgmt_protocount_inc(void)
+{
+ rcu_read_lock();
+ spin_lock(&netlabel_mgmt_protocount_lock);
+ netlabel_mgmt_protocount++;
+ spin_unlock(&netlabel_mgmt_protocount_lock);
+ rcu_read_unlock();
+}
+
+/**
+ * netlbl_mgmt_protocount_dec - Decrement the configured labeled protocol count
+ *
+ * Description:
+ * Decrement the number of labeled protocol configurations in the current
+ * NetLabel configuration. Keep track of this for use in determining if
+ * NetLabel label enforcement should be active/enabled or not in the LSM.
+ *
+ */
+void netlbl_mgmt_protocount_dec(void)
+{
+ rcu_read_lock();
+ spin_lock(&netlabel_mgmt_protocount_lock);
+ if (netlabel_mgmt_protocount > 0)
+ netlabel_mgmt_protocount--;
+ spin_unlock(&netlabel_mgmt_protocount_lock);
+ rcu_read_unlock();
+}
+
+/**
+ * netlbl_mgmt_protocount_value - Return the number of configured protocols
+ *
+ * Description:
+ * Return the number of labeled protocols in the current NetLabel
+ * configuration. This value is useful in determining if NetLabel label
+ * enforcement should be active/enabled or not in the LSM.
+ *
+ */
+u32 netlbl_mgmt_protocount_value(void)
+{
+ u32 val;
+
+ rcu_read_lock();
+ val = netlabel_mgmt_protocount;
+ rcu_read_unlock();
+
+ return val;
+}
+
+/*
* NetLabel Command Handlers
*/
diff --git a/net/netlabel/netlabel_mgmt.h b/net/netlabel/netlabel_mgmt.h
index 3642d3bfc8eb..ccb2b3923591 100644
--- a/net/netlabel/netlabel_mgmt.h
+++ b/net/netlabel/netlabel_mgmt.h
@@ -168,4 +168,9 @@ enum {
/* NetLabel protocol functions */
int netlbl_mgmt_genl_init(void);
+/* NetLabel misc management functions */
+void netlbl_mgmt_protocount_inc(void);
+void netlbl_mgmt_protocount_dec(void);
+u32 netlbl_mgmt_protocount_value(void);
+
#endif
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index 42f12bd65964..89dcc485653b 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -46,10 +46,6 @@
#include "netlabel_cipso_v4.h"
#include "netlabel_user.h"
-/* do not do any auditing if audit_enabled == 0, see kernel/audit.c for
- * details */
-extern int audit_enabled;
-
/*
* NetLabel NETLINK Setup Functions
*/
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 1f15821c8da4..5681ce3aebca 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -62,6 +62,7 @@
#include <net/netlink.h>
#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8)
+#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long))
struct netlink_sock {
/* struct sock has to be the first member of netlink_sock */
@@ -314,10 +315,12 @@ netlink_update_listeners(struct sock *sk)
unsigned long mask;
unsigned int i;
- for (i = 0; i < NLGRPSZ(tbl->groups)/sizeof(unsigned long); i++) {
+ for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
mask = 0;
- sk_for_each_bound(sk, node, &tbl->mc_list)
- mask |= nlk_sk(sk)->groups[i];
+ sk_for_each_bound(sk, node, &tbl->mc_list) {
+ if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
+ mask |= nlk_sk(sk)->groups[i];
+ }
tbl->listeners[i] = mask;
}
/* this function is only called with the netlink table "grabbed", which
@@ -555,26 +558,37 @@ netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
nlk->subscriptions = subscriptions;
}
-static int netlink_alloc_groups(struct sock *sk)
+static int netlink_realloc_groups(struct sock *sk)
{
struct netlink_sock *nlk = nlk_sk(sk);
unsigned int groups;
+ unsigned long *new_groups;
int err = 0;
- netlink_lock_table();
+ netlink_table_grab();
+
groups = nl_table[sk->sk_protocol].groups;
- if (!nl_table[sk->sk_protocol].registered)
+ if (!nl_table[sk->sk_protocol].registered) {
err = -ENOENT;
- netlink_unlock_table();
+ goto out_unlock;
+ }
- if (err)
- return err;
+ if (nlk->ngroups >= groups)
+ goto out_unlock;
- nlk->groups = kzalloc(NLGRPSZ(groups), GFP_KERNEL);
- if (nlk->groups == NULL)
- return -ENOMEM;
+ new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC);
+ if (new_groups == NULL) {
+ err = -ENOMEM;
+ goto out_unlock;
+ }
+ memset((char*)new_groups + NLGRPSZ(nlk->ngroups), 0,
+ NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups));
+
+ nlk->groups = new_groups;
nlk->ngroups = groups;
- return 0;
+ out_unlock:
+ netlink_table_ungrab();
+ return err;
}
static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
@@ -591,11 +605,9 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len
if (nladdr->nl_groups) {
if (!netlink_capable(sock, NL_NONROOT_RECV))
return -EPERM;
- if (nlk->groups == NULL) {
- err = netlink_alloc_groups(sk);
- if (err)
- return err;
- }
+ err = netlink_realloc_groups(sk);
+ if (err)
+ return err;
}
if (nlk->pid) {
@@ -839,10 +851,18 @@ retry:
int netlink_has_listeners(struct sock *sk, unsigned int group)
{
int res = 0;
+ unsigned long *listeners;
BUG_ON(!(nlk_sk(sk)->flags & NETLINK_KERNEL_SOCKET));
+
+ rcu_read_lock();
+ listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
+
if (group - 1 < nl_table[sk->sk_protocol].groups)
- res = test_bit(group - 1, nl_table[sk->sk_protocol].listeners);
+ res = test_bit(group - 1, listeners);
+
+ rcu_read_unlock();
+
return res;
}
EXPORT_SYMBOL_GPL(netlink_has_listeners);
@@ -1007,18 +1027,36 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
read_unlock(&nl_table_lock);
}
+/* must be called with netlink table grabbed */
+static void netlink_update_socket_mc(struct netlink_sock *nlk,
+ unsigned int group,
+ int is_new)
+{
+ int old, new = !!is_new, subscriptions;
+
+ old = test_bit(group - 1, nlk->groups);
+ subscriptions = nlk->subscriptions - old + new;
+ if (new)
+ __set_bit(group - 1, nlk->groups);
+ else
+ __clear_bit(group - 1, nlk->groups);
+ netlink_update_subscriptions(&nlk->sk, subscriptions);
+ netlink_update_listeners(&nlk->sk);
+}
+
static int netlink_setsockopt(struct socket *sock, int level, int optname,
char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
struct netlink_sock *nlk = nlk_sk(sk);
- int val = 0, err;
+ unsigned int val = 0;
+ int err;
if (level != SOL_NETLINK)
return -ENOPROTOOPT;
if (optlen >= sizeof(int) &&
- get_user(val, (int __user *)optval))
+ get_user(val, (unsigned int __user *)optval))
return -EFAULT;
switch (optname) {
@@ -1031,27 +1069,16 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
break;
case NETLINK_ADD_MEMBERSHIP:
case NETLINK_DROP_MEMBERSHIP: {
- unsigned int subscriptions;
- int old, new = optname == NETLINK_ADD_MEMBERSHIP ? 1 : 0;
-
if (!netlink_capable(sock, NL_NONROOT_RECV))
return -EPERM;
- if (nlk->groups == NULL) {
- err = netlink_alloc_groups(sk);
- if (err)
- return err;
- }
+ err = netlink_realloc_groups(sk);
+ if (err)
+ return err;
if (!val || val - 1 >= nlk->ngroups)
return -EINVAL;
netlink_table_grab();
- old = test_bit(val - 1, nlk->groups);
- subscriptions = nlk->subscriptions - old + new;
- if (new)
- __set_bit(val - 1, nlk->groups);
- else
- __clear_bit(val - 1, nlk->groups);
- netlink_update_subscriptions(sk, subscriptions);
- netlink_update_listeners(sk);
+ netlink_update_socket_mc(nlk, val,
+ optname == NETLINK_ADD_MEMBERSHIP);
netlink_table_ungrab();
err = 0;
break;
@@ -1327,6 +1354,71 @@ out_sock_release:
return NULL;
}
+/**
+ * netlink_change_ngroups - change number of multicast groups
+ *
+ * This changes the number of multicast groups that are available
+ * on a certain netlink family. Note that it is not possible to
+ * change the number of groups to below 32. Also note that it does
+ * not implicitly call netlink_clear_multicast_users() when the
+ * number of groups is reduced.
+ *
+ * @sk: The kernel netlink socket, as returned by netlink_kernel_create().
+ * @groups: The new number of groups.
+ */
+int netlink_change_ngroups(struct sock *sk, unsigned int groups)
+{
+ unsigned long *listeners, *old = NULL;
+ struct netlink_table *tbl = &nl_table[sk->sk_protocol];
+ int err = 0;
+
+ if (groups < 32)
+ groups = 32;
+
+ netlink_table_grab();
+ if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) {
+ listeners = kzalloc(NLGRPSZ(groups), GFP_ATOMIC);
+ if (!listeners) {
+ err = -ENOMEM;
+ goto out_ungrab;
+ }
+ old = tbl->listeners;
+ memcpy(listeners, old, NLGRPSZ(tbl->groups));
+ rcu_assign_pointer(tbl->listeners, listeners);
+ }
+ tbl->groups = groups;
+
+ out_ungrab:
+ netlink_table_ungrab();
+ synchronize_rcu();
+ kfree(old);
+ return err;
+}
+EXPORT_SYMBOL(netlink_change_ngroups);
+
+/**
+ * netlink_clear_multicast_users - kick off multicast listeners
+ *
+ * This function removes all listeners from the given group.
+ * @ksk: The kernel netlink socket, as returned by
+ * netlink_kernel_create().
+ * @group: The multicast group to clear.
+ */
+void netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
+{
+ struct sock *sk;
+ struct hlist_node *node;
+ struct netlink_table *tbl = &nl_table[ksk->sk_protocol];
+
+ netlink_table_grab();
+
+ sk_for_each_bound(sk, node, &tbl->mc_list)
+ netlink_update_socket_mc(nlk_sk(sk), group, 0);
+
+ netlink_table_ungrab();
+}
+EXPORT_SYMBOL(netlink_clear_multicast_users);
+
void netlink_set_nonroot(int protocol, unsigned int flags)
{
if ((unsigned int)protocol < MAX_LINKS)
@@ -1713,7 +1805,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations netlink_seq_ops = {
+static const struct seq_operations netlink_seq_ops = {
.start = netlink_seq_start,
.next = netlink_seq_next,
.stop = netlink_seq_stop,
diff --git a/net/netlink/attr.c b/net/netlink/attr.c
index c591212793ee..e4d7bed99c2e 100644
--- a/net/netlink/attr.c
+++ b/net/netlink/attr.c
@@ -72,6 +72,17 @@ static int validate_nla(struct nlattr *nla, int maxtype,
return -ERANGE;
break;
+ case NLA_NESTED_COMPAT:
+ if (attrlen < pt->len)
+ return -ERANGE;
+ if (attrlen < NLA_ALIGN(pt->len))
+ break;
+ if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN)
+ return -ERANGE;
+ nla = nla_data(nla) + NLA_ALIGN(pt->len);
+ if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla))
+ return -ERANGE;
+ break;
default:
if (pt->len)
minlen = pt->len;
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index b9ab62f938d0..e146531faf1d 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -3,6 +3,7 @@
*
* Authors: Jamal Hadi Salim
* Thomas Graf <tgraf@suug.ch>
+ * Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/module.h>
@@ -13,6 +14,7 @@
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/mutex.h>
+#include <linux/bitmap.h>
#include <net/sock.h>
#include <net/genetlink.h>
@@ -42,6 +44,16 @@ static void genl_unlock(void)
#define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1)
static struct list_head family_ht[GENL_FAM_TAB_SIZE];
+/*
+ * Bitmap of multicast groups that are currently in use.
+ *
+ * To avoid an allocation at boot of just one unsigned long,
+ * declare it global instead.
+ * Bit 0 is marked as already used since group 0 is invalid.
+ */
+static unsigned long mc_group_start = 0x1;
+static unsigned long *mc_groups = &mc_group_start;
+static unsigned long mc_groups_longs = 1;
static int genl_ctrl_event(int event, void *data);
@@ -116,6 +128,114 @@ static inline u16 genl_generate_id(void)
return id_gen_idx;
}
+static struct genl_multicast_group notify_grp;
+
+/**
+ * genl_register_mc_group - register a multicast group
+ *
+ * Registers the specified multicast group and notifies userspace
+ * about the new group.
+ *
+ * Returns 0 on success or a negative error code.
+ *
+ * @family: The generic netlink family the group shall be registered for.
+ * @grp: The group to register, must have a name.
+ */
+int genl_register_mc_group(struct genl_family *family,
+ struct genl_multicast_group *grp)
+{
+ int id;
+ unsigned long *new_groups;
+ int err;
+
+ BUG_ON(grp->name[0] == '\0');
+
+ genl_lock();
+
+ /* special-case our own group */
+ if (grp == &notify_grp)
+ id = GENL_ID_CTRL;
+ else
+ id = find_first_zero_bit(mc_groups,
+ mc_groups_longs * BITS_PER_LONG);
+
+
+ if (id >= mc_groups_longs * BITS_PER_LONG) {
+ size_t nlen = (mc_groups_longs + 1) * sizeof(unsigned long);
+
+ if (mc_groups == &mc_group_start) {
+ new_groups = kzalloc(nlen, GFP_KERNEL);
+ if (!new_groups) {
+ err = -ENOMEM;
+ goto out;
+ }
+ mc_groups = new_groups;
+ *mc_groups = mc_group_start;
+ } else {
+ new_groups = krealloc(mc_groups, nlen, GFP_KERNEL);
+ if (!new_groups) {
+ err = -ENOMEM;
+ goto out;
+ }
+ mc_groups = new_groups;
+ mc_groups[mc_groups_longs] = 0;
+ }
+ mc_groups_longs++;
+ }
+
+ err = netlink_change_ngroups(genl_sock,
+ sizeof(unsigned long) * NETLINK_GENERIC);
+ if (err)
+ goto out;
+
+ grp->id = id;
+ set_bit(id, mc_groups);
+ list_add_tail(&grp->list, &family->mcast_groups);
+ grp->family = family;
+
+ genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, grp);
+ out:
+ genl_unlock();
+ return 0;
+}
+EXPORT_SYMBOL(genl_register_mc_group);
+
+/**
+ * genl_unregister_mc_group - unregister a multicast group
+ *
+ * Unregisters the specified multicast group and notifies userspace
+ * about it. All current listeners on the group are removed.
+ *
+ * Note: It is not necessary to unregister all multicast groups before
+ * unregistering the family, unregistering the family will cause
+ * all assigned multicast groups to be unregistered automatically.
+ *
+ * @family: Generic netlink family the group belongs to.
+ * @grp: The group to unregister, must have been registered successfully
+ * previously.
+ */
+void genl_unregister_mc_group(struct genl_family *family,
+ struct genl_multicast_group *grp)
+{
+ BUG_ON(grp->family != family);
+ genl_lock();
+ netlink_clear_multicast_users(genl_sock, grp->id);
+ clear_bit(grp->id, mc_groups);
+ list_del(&grp->list);
+ genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, grp);
+ grp->id = 0;
+ grp->family = NULL;
+ genl_unlock();
+}
+
+static void genl_unregister_mc_groups(struct genl_family *family)
+{
+ struct genl_multicast_group *grp, *tmp;
+
+ list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list)
+ genl_unregister_mc_group(family, grp);
+}
+
/**
* genl_register_ops - register generic netlink operations
* @family: generic netlink family
@@ -216,6 +336,7 @@ int genl_register_family(struct genl_family *family)
goto errout;
INIT_LIST_HEAD(&family->ops_list);
+ INIT_LIST_HEAD(&family->mcast_groups);
genl_lock();
@@ -275,6 +396,8 @@ int genl_unregister_family(struct genl_family *family)
{
struct genl_family *rc;
+ genl_unregister_mc_groups(family);
+
genl_lock();
list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
@@ -410,6 +533,67 @@ static int ctrl_fill_info(struct genl_family *family, u32 pid, u32 seq,
nla_nest_end(skb, nla_ops);
}
+ if (!list_empty(&family->mcast_groups)) {
+ struct genl_multicast_group *grp;
+ struct nlattr *nla_grps;
+ int idx = 1;
+
+ nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
+ if (nla_grps == NULL)
+ goto nla_put_failure;
+
+ list_for_each_entry(grp, &family->mcast_groups, list) {
+ struct nlattr *nest;
+
+ nest = nla_nest_start(skb, idx++);
+ if (nest == NULL)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
+ NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
+ grp->name);
+
+ nla_nest_end(skb, nest);
+ }
+ nla_nest_end(skb, nla_grps);
+ }
+
+ return genlmsg_end(skb, hdr);
+
+nla_put_failure:
+ return genlmsg_cancel(skb, hdr);
+}
+
+static int ctrl_fill_mcgrp_info(struct genl_multicast_group *grp, u32 pid,
+ u32 seq, u32 flags, struct sk_buff *skb,
+ u8 cmd)
+{
+ void *hdr;
+ struct nlattr *nla_grps;
+ struct nlattr *nest;
+
+ hdr = genlmsg_put(skb, pid, seq, &genl_ctrl, flags, cmd);
+ if (hdr == NULL)
+ return -1;
+
+ NLA_PUT_STRING(skb, CTRL_ATTR_FAMILY_NAME, grp->family->name);
+ NLA_PUT_U16(skb, CTRL_ATTR_FAMILY_ID, grp->family->id);
+
+ nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS);
+ if (nla_grps == NULL)
+ goto nla_put_failure;
+
+ nest = nla_nest_start(skb, 1);
+ if (nest == NULL)
+ goto nla_put_failure;
+
+ NLA_PUT_U32(skb, CTRL_ATTR_MCAST_GRP_ID, grp->id);
+ NLA_PUT_STRING(skb, CTRL_ATTR_MCAST_GRP_NAME,
+ grp->name);
+
+ nla_nest_end(skb, nest);
+ nla_nest_end(skb, nla_grps);
+
return genlmsg_end(skb, hdr);
nla_put_failure:
@@ -453,8 +637,8 @@ errout:
return skb->len;
}
-static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
- int seq, u8 cmd)
+static struct sk_buff *ctrl_build_family_msg(struct genl_family *family,
+ u32 pid, int seq, u8 cmd)
{
struct sk_buff *skb;
int err;
@@ -472,6 +656,25 @@ static struct sk_buff *ctrl_build_msg(struct genl_family *family, u32 pid,
return skb;
}
+static struct sk_buff *ctrl_build_mcgrp_msg(struct genl_multicast_group *grp,
+ u32 pid, int seq, u8 cmd)
+{
+ struct sk_buff *skb;
+ int err;
+
+ skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (skb == NULL)
+ return ERR_PTR(-ENOBUFS);
+
+ err = ctrl_fill_mcgrp_info(grp, pid, seq, 0, skb, cmd);
+ if (err < 0) {
+ nlmsg_free(skb);
+ return ERR_PTR(err);
+ }
+
+ return skb;
+}
+
static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
[CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
[CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING,
@@ -501,8 +704,8 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
goto errout;
}
- msg = ctrl_build_msg(res, info->snd_pid, info->snd_seq,
- CTRL_CMD_NEWFAMILY);
+ msg = ctrl_build_family_msg(res, info->snd_pid, info->snd_seq,
+ CTRL_CMD_NEWFAMILY);
if (IS_ERR(msg)) {
err = PTR_ERR(msg);
goto errout;
@@ -523,7 +726,15 @@ static int genl_ctrl_event(int event, void *data)
switch (event) {
case CTRL_CMD_NEWFAMILY:
case CTRL_CMD_DELFAMILY:
- msg = ctrl_build_msg(data, 0, 0, event);
+ msg = ctrl_build_family_msg(data, 0, 0, event);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
+ break;
+ case CTRL_CMD_NEWMCAST_GRP:
+ case CTRL_CMD_DELMCAST_GRP:
+ msg = ctrl_build_mcgrp_msg(data, 0, 0, event);
if (IS_ERR(msg))
return PTR_ERR(msg);
@@ -541,6 +752,10 @@ static struct genl_ops genl_ctrl_ops = {
.policy = ctrl_policy,
};
+static struct genl_multicast_group notify_grp = {
+ .name = "notify",
+};
+
static int __init genl_init(void)
{
int i, err;
@@ -557,11 +772,17 @@ static int __init genl_init(void)
goto errout_register;
netlink_set_nonroot(NETLINK_GENERIC, NL_NONROOT_RECV);
- genl_sock = netlink_kernel_create(NETLINK_GENERIC, GENL_MAX_ID,
- genl_rcv, NULL, THIS_MODULE);
+
+ /* we'll bump the group number right afterwards */
+ genl_sock = netlink_kernel_create(NETLINK_GENERIC, 0, genl_rcv,
+ NULL, THIS_MODULE);
if (genl_sock == NULL)
panic("GENL: Cannot initialize generic netlink\n");
+ err = genl_register_mc_group(&genl_ctrl, &notify_grp);
+ if (err < 0)
+ goto errout_register;
+
return 0;
errout_register:
diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
index 5d4a26c2aa0c..dc9273295a38 100644
--- a/net/netrom/af_netrom.c
+++ b/net/netrom/af_netrom.c
@@ -720,7 +720,7 @@ static int nr_connect(struct socket *sock, struct sockaddr *uaddr,
for (;;) {
prepare_to_wait(sk->sk_sleep, &wait,
- TASK_INTERRUPTIBLE);
+ TASK_INTERRUPTIBLE);
if (sk->sk_state != TCP_SYN_SENT)
break;
if (!signal_pending(current)) {
@@ -1328,7 +1328,7 @@ static int nr_info_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations nr_info_seqops = {
+static const struct seq_operations nr_info_seqops = {
.start = nr_info_start,
.next = nr_info_next,
.stop = nr_info_stop,
diff --git a/net/netrom/nr_route.c b/net/netrom/nr_route.c
index 2f76e062609d..24fe4a66d297 100644
--- a/net/netrom/nr_route.c
+++ b/net/netrom/nr_route.c
@@ -922,7 +922,7 @@ static int nr_node_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations nr_node_seqops = {
+static const struct seq_operations nr_node_seqops = {
.start = nr_node_start,
.next = nr_node_next,
.stop = nr_node_stop,
@@ -1006,7 +1006,7 @@ static int nr_neigh_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations nr_neigh_seqops = {
+static const struct seq_operations nr_neigh_seqops = {
.start = nr_neigh_start,
.next = nr_neigh_next,
.stop = nr_neigh_stop,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index f8b83014ccca..1322d62b5d97 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -108,7 +108,7 @@ Outgoing, dev->hard_header!=NULL
Incoming, dev->hard_header==NULL
mac_header -> UNKNOWN position. It is very likely, that it points to ll
header. PPP makes it, that is wrong, because introduce
- assymetry between rx and tx paths.
+ assymetry between rx and tx paths.
data -> data
Outgoing, dev->hard_header==NULL
@@ -1928,7 +1928,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations packet_seq_ops = {
+static const struct seq_operations packet_seq_ops = {
.start = packet_seq_start,
.next = packet_seq_next,
.stop = packet_seq_stop,
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index e5c840c30284..9f746be58854 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -55,7 +55,7 @@ static void rfkill_task_handler(struct work_struct *work)
static void rfkill_schedule_toggle(struct rfkill_task *task)
{
- unsigned int flags;
+ unsigned long flags;
spin_lock_irqsave(&task->lock, flags);
@@ -83,7 +83,7 @@ static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
static void rfkill_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int down)
+ unsigned int code, int down)
{
if (type == EV_KEY && down == 1) {
switch (code) {
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index f3986d498b40..db3395bfbcfa 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -187,7 +187,7 @@ static ssize_t rfkill_claim_store(struct device *dev,
static struct device_attribute rfkill_dev_attrs[] = {
__ATTR(name, S_IRUGO, rfkill_name_show, NULL),
__ATTR(type, S_IRUGO, rfkill_type_show, NULL),
- __ATTR(state, S_IRUGO, rfkill_state_show, rfkill_state_store),
+ __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
__ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
__ATTR_NULL
};
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index d476c43d5216..976c3cc86a29 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -816,7 +816,7 @@ rose_try_next_neigh:
for (;;) {
prepare_to_wait(sk->sk_sleep, &wait,
- TASK_INTERRUPTIBLE);
+ TASK_INTERRUPTIBLE);
if (sk->sk_state != TCP_SYN_SENT)
break;
if (!signal_pending(current)) {
@@ -1454,7 +1454,7 @@ static int rose_info_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations rose_info_seqops = {
+static const struct seq_operations rose_info_seqops = {
.start = rose_info_start,
.next = rose_info_next,
.stop = rose_info_stop,
diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c
index 929a784a86d7..bbcbad1da0d0 100644
--- a/net/rose/rose_route.c
+++ b/net/rose/rose_route.c
@@ -1118,7 +1118,7 @@ static int rose_node_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations rose_node_seqops = {
+static const struct seq_operations rose_node_seqops = {
.start = rose_node_start,
.next = rose_node_next,
.stop = rose_node_stop,
@@ -1200,7 +1200,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v)
}
-static struct seq_operations rose_neigh_seqops = {
+static const struct seq_operations rose_neigh_seqops = {
.start = rose_neigh_start,
.next = rose_neigh_next,
.stop = rose_neigh_stop,
@@ -1284,7 +1284,7 @@ static int rose_route_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations rose_route_seqops = {
+static const struct seq_operations rose_route_seqops = {
.start = rose_route_start,
.next = rose_route_next,
.stop = rose_route_stop,
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 2c57df9c131b..16a68df4e36b 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -792,7 +792,7 @@ static int __init af_rxrpc_init(void)
ret = -ENOMEM;
rxrpc_call_jar = kmem_cache_create(
"rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
+ SLAB_HWCACHE_ALIGN, NULL);
if (!rxrpc_call_jar) {
printk(KERN_NOTICE "RxRPC: Failed to allocate call jar\n");
goto error_call_jar;
@@ -805,26 +805,26 @@ static int __init af_rxrpc_init(void)
}
ret = proto_register(&rxrpc_proto, 1);
- if (ret < 0) {
- printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
+ if (ret < 0) {
+ printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
goto error_proto;
}
ret = sock_register(&rxrpc_family_ops);
if (ret < 0) {
- printk(KERN_CRIT "RxRPC: Cannot register socket family\n");
+ printk(KERN_CRIT "RxRPC: Cannot register socket family\n");
goto error_sock;
}
ret = register_key_type(&key_type_rxrpc);
if (ret < 0) {
- printk(KERN_CRIT "RxRPC: Cannot register client key type\n");
+ printk(KERN_CRIT "RxRPC: Cannot register client key type\n");
goto error_key_type;
}
ret = register_key_type(&key_type_rxrpc_s);
if (ret < 0) {
- printk(KERN_CRIT "RxRPC: Cannot register server key type\n");
+ printk(KERN_CRIT "RxRPC: Cannot register server key type\n");
goto error_key_type_s;
}
diff --git a/net/rxrpc/ar-proc.c b/net/rxrpc/ar-proc.c
index 1c0be0e77b16..2e83ce325d15 100644
--- a/net/rxrpc/ar-proc.c
+++ b/net/rxrpc/ar-proc.c
@@ -30,31 +30,13 @@ static const char *rxrpc_conn_states[] = {
*/
static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
read_lock(&rxrpc_call_lock);
- if (!pos)
- return SEQ_START_TOKEN;
- pos--;
-
- list_for_each(_p, &rxrpc_calls)
- if (!pos--)
- break;
-
- return _p != &rxrpc_calls ? _p : NULL;
+ return seq_list_start_head(&rxrpc_calls, *_pos);
}
static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = (v == SEQ_START_TOKEN) ? rxrpc_calls.next : _p->next;
-
- return _p != &rxrpc_calls ? _p : NULL;
+ return seq_list_next(v, &rxrpc_calls, pos);
}
static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
@@ -68,7 +50,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
struct rxrpc_call *call;
char lbuff[4 + 4 + 4 + 4 + 5 + 1], rbuff[4 + 4 + 4 + 4 + 5 + 1];
- if (v == SEQ_START_TOKEN) {
+ if (v == &rxrpc_calls) {
seq_puts(seq,
"Proto Local Remote "
" SvID ConnID CallID End Use State Abort "
@@ -104,7 +86,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations rxrpc_call_seq_ops = {
+static const struct seq_operations rxrpc_call_seq_ops = {
.start = rxrpc_call_seq_start,
.next = rxrpc_call_seq_next,
.stop = rxrpc_call_seq_stop,
@@ -129,32 +111,14 @@ struct file_operations rxrpc_call_seq_fops = {
*/
static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
{
- struct list_head *_p;
- loff_t pos = *_pos;
-
read_lock(&rxrpc_connection_lock);
- if (!pos)
- return SEQ_START_TOKEN;
- pos--;
-
- list_for_each(_p, &rxrpc_connections)
- if (!pos--)
- break;
-
- return _p != &rxrpc_connections ? _p : NULL;
+ return seq_list_start_head(&rxrpc_connections, *_pos);
}
static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
loff_t *pos)
{
- struct list_head *_p;
-
- (*pos)++;
-
- _p = v;
- _p = (v == SEQ_START_TOKEN) ? rxrpc_connections.next : _p->next;
-
- return _p != &rxrpc_connections ? _p : NULL;
+ return seq_list_next(v, &rxrpc_connections, pos);
}
static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
@@ -168,7 +132,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
struct rxrpc_transport *trans;
char lbuff[4 + 4 + 4 + 4 + 5 + 1], rbuff[4 + 4 + 4 + 4 + 5 + 1];
- if (v == SEQ_START_TOKEN) {
+ if (v == &rxrpc_connections) {
seq_puts(seq,
"Proto Local Remote "
" SvID ConnID Calls End Use State Key "
@@ -206,7 +170,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations rxrpc_connection_seq_ops = {
+static const struct seq_operations rxrpc_connection_seq_ops = {
.start = rxrpc_connection_seq_start,
.next = rxrpc_connection_seq_next,
.stop = rxrpc_connection_seq_stop,
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 475df8449be9..8a74cac0be8c 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -97,7 +97,7 @@ config NET_SCH_ATM
select classes of this queuing discipline. Each class maps
the flow(s) it is handling to a given virtual circuit.
- See the top of <file:net/sched/sch_atm.c>) for more details.
+ See the top of <file:net/sched/sch_atm.c> for more details.
To compile this code as a module, choose M here: the
module will be called sch_atm.
@@ -111,6 +111,17 @@ config NET_SCH_PRIO
To compile this code as a module, choose M here: the
module will be called sch_prio.
+config NET_SCH_RR
+ tristate "Multi Band Round Robin Queuing (RR)"
+ select NET_SCH_PRIO
+ ---help---
+ Say Y here if you want to use an n-band round robin packet
+ scheduler.
+
+ The module uses sch_prio for its framework and is aliased as
+ sch_rr, so it will load sch_prio, although it is referred
+ to using sch_rr.
+
config NET_SCH_RED
tristate "Random Early Detection (RED)"
---help---
@@ -126,7 +137,7 @@ config NET_SCH_SFQ
tristate "Stochastic Fairness Queueing (SFQ)"
---help---
Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
- packet scheduling algorithm .
+ packet scheduling algorithm.
See the top of <file:net/sched/sch_sfq.c> for more details.
@@ -275,7 +286,6 @@ config CLS_U32_MARK
config NET_CLS_RSVP
tristate "IPv4 Resource Reservation Protocol (RSVP)"
select NET_CLS
- select NET_ESTIMATOR
---help---
The Resource Reservation Protocol (RSVP) permits end systems to
request a minimum and maximum data flow rate for a connection; this
@@ -290,14 +300,13 @@ config NET_CLS_RSVP
config NET_CLS_RSVP6
tristate "IPv6 Resource Reservation Protocol (RSVP6)"
select NET_CLS
- select NET_ESTIMATOR
---help---
The Resource Reservation Protocol (RSVP) permits end systems to
request a minimum and maximum data flow rate for a connection; this
is important for real time data such as streaming sound or video.
Say Y here if you want to be able to classify outgoing packets based
- on their RSVP requests and you are using the IPv6.
+ on their RSVP requests and you are using the IPv6 protocol.
To compile this code as a module, choose M here: the
module will be called cls_rsvp6.
@@ -382,7 +391,6 @@ config NET_EMATCH_TEXT
config NET_CLS_ACT
bool "Actions"
- select NET_ESTIMATOR
---help---
Say Y here if you want to use traffic control actions. Actions
get attached to classifiers and are invoked after a successful
@@ -464,13 +472,12 @@ config NET_ACT_SIMP
config NET_CLS_POLICE
bool "Traffic Policing (obsolete)"
- depends on NET_CLS_ACT!=y
- select NET_ESTIMATOR
+ select NET_CLS_ACT
+ select NET_ACT_POLICE
---help---
Say Y here if you want to do traffic policing, i.e. strict
- bandwidth limiting. This option is obsoleted by the traffic
- policer implemented as action, it stays here for compatibility
- reasons.
+ bandwidth limiting. This option is obsolete and just selects
+ the option replacing it. It will be removed in the future.
config NET_CLS_IND
bool "Incoming device classification"
@@ -480,14 +487,6 @@ config NET_CLS_IND
classification based on the incoming device. This option is
likely to disappear in favour of the metadata ematch.
-config NET_ESTIMATOR
- bool "Rate estimator"
- ---help---
- Say Y here to allow using rate estimators to estimate the current
- rate-of-flow for network devices, queues, etc. This module is
- automatically selected if needed but can be selected manually for
- statistical purposes.
-
endif # NET_SCHED
endmenu
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 020767a204d4..b67c36f65cf2 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -8,7 +8,6 @@ obj-$(CONFIG_NET_SCHED) += sch_api.o sch_blackhole.o
obj-$(CONFIG_NET_CLS) += cls_api.o
obj-$(CONFIG_NET_CLS_ACT) += act_api.o
obj-$(CONFIG_NET_ACT_POLICE) += act_police.o
-obj-$(CONFIG_NET_CLS_POLICE) += act_police.o
obj-$(CONFIG_NET_ACT_GACT) += act_gact.o
obj-$(CONFIG_NET_ACT_MIRRED) += act_mirred.o
obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 711dd26c95c3..feef366cad5d 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -11,23 +11,13 @@
*
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
-#include <net/sock.h>
#include <net/sch_generic.h>
#include <net/act_api.h>
#include <net/netlink.h>
@@ -42,10 +32,8 @@ void tcf_hash_destroy(struct tcf_common *p, struct tcf_hashinfo *hinfo)
write_lock_bh(hinfo->lock);
*p1p = p->tcfc_next;
write_unlock_bh(hinfo->lock);
-#ifdef CONFIG_NET_ESTIMATOR
gen_kill_estimator(&p->tcfc_bstats,
&p->tcfc_rate_est);
-#endif
kfree(p);
return;
}
@@ -232,15 +220,12 @@ struct tcf_common *tcf_hash_create(u32 index, struct rtattr *est, struct tc_acti
p->tcfc_bindcnt = 1;
spin_lock_init(&p->tcfc_lock);
- p->tcfc_stats_lock = &p->tcfc_lock;
p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo);
p->tcfc_tm.install = jiffies;
p->tcfc_tm.lastuse = jiffies;
-#ifdef CONFIG_NET_ESTIMATOR
if (est)
gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est,
- p->tcfc_stats_lock, est);
-#endif
+ &p->tcfc_lock, est);
a->priv = (void *) p;
return p;
}
@@ -599,12 +584,12 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
if (compat_mode) {
if (a->type == TCA_OLD_COMPAT)
err = gnet_stats_start_copy_compat(skb, 0,
- TCA_STATS, TCA_XSTATS, h->tcf_stats_lock, &d);
+ TCA_STATS, TCA_XSTATS, &h->tcf_lock, &d);
else
return 0;
} else
err = gnet_stats_start_copy(skb, TCA_ACT_STATS,
- h->tcf_stats_lock, &d);
+ &h->tcf_lock, &d);
if (err < 0)
goto errout;
@@ -614,9 +599,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
goto errout;
if (gnet_stats_copy_basic(&d, &h->tcf_bstats) < 0 ||
-#ifdef CONFIG_NET_ESTIMATOR
gnet_stats_copy_rate_est(&d, &h->tcf_rate_est) < 0 ||
-#endif
gnet_stats_copy_queue(&d, &h->tcf_qstats) < 0)
goto errout;
diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c
index 7517f3791541..a9631e426d91 100644
--- a/net/sched/act_gact.c
+++ b/net/sched/act_gact.c
@@ -10,26 +10,15 @@
*
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/proc_fs.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
#include <linux/tc_act/tc_gact.h>
#include <net/tc_act/tc_gact.h>
diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c
index 00b05f422d45..6b407ece953c 100644
--- a/net/sched/act_ipt.c
+++ b/net/sched/act_ipt.c
@@ -11,27 +11,15 @@
* Copyright: Jamal Hadi Salim (2002-4)
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/proc_fs.h>
-#include <linux/kmod.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
#include <linux/tc_act/tc_ipt.h>
#include <net/tc_act/tc_ipt.h>
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index de21c92faaa2..579578944ae7 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -12,31 +12,19 @@
*
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/proc_fs.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
#include <linux/tc_act/tc_mirred.h>
#include <net/tc_act/tc_mirred.h>
-#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#define MIRRED_TAB_MASK 7
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 6f8684b5617e..b46fab5fb323 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -9,26 +9,15 @@
* Authors: Jamal Hadi Salim (2002-4)
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/proc_fs.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
#include <linux/tc_act/tc_pedit.h>
#include <net/tc_act/tc_pedit.h>
diff --git a/net/sched/act_police.c b/net/sched/act_police.c
index 616f465f407e..bf90e60f8411 100644
--- a/net/sched/act_police.c
+++ b/net/sched/act_police.c
@@ -10,25 +10,15 @@
* J Hadi Salim (action changes)
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <linux/init.h>
-#include <net/sock.h>
#include <net/act_api.h>
#include <net/netlink.h>
@@ -60,7 +50,6 @@ struct tc_police_compat
/* Each policer is serialized by its individual spinlock */
-#ifdef CONFIG_NET_CLS_ACT
static int tcf_act_police_walker(struct sk_buff *skb, struct netlink_callback *cb,
int type, struct tc_action *a)
{
@@ -106,9 +95,8 @@ rtattr_failure:
nlmsg_trim(skb, r);
goto done;
}
-#endif
-void tcf_police_destroy(struct tcf_police *p)
+static void tcf_police_destroy(struct tcf_police *p)
{
unsigned int h = tcf_hash(p->tcf_index, POL_TAB_MASK);
struct tcf_common **p1p;
@@ -118,10 +106,8 @@ void tcf_police_destroy(struct tcf_police *p)
write_lock_bh(&police_lock);
*p1p = p->tcf_next;
write_unlock_bh(&police_lock);
-#ifdef CONFIG_NET_ESTIMATOR
gen_kill_estimator(&p->tcf_bstats,
&p->tcf_rate_est);
-#endif
if (p->tcfp_R_tab)
qdisc_put_rtab(p->tcfp_R_tab);
if (p->tcfp_P_tab)
@@ -133,7 +119,6 @@ void tcf_police_destroy(struct tcf_police *p)
BUG_TRAP(0);
}
-#ifdef CONFIG_NET_CLS_ACT
static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,
struct tc_action *a, int ovr, int bind)
{
@@ -185,7 +170,6 @@ static int tcf_act_police_locate(struct rtattr *rta, struct rtattr *est,
ret = ACT_P_CREATED;
police->tcf_refcnt = 1;
spin_lock_init(&police->tcf_lock);
- police->tcf_stats_lock = &police->tcf_lock;
if (bind)
police->tcf_bindcnt = 1;
override:
@@ -227,15 +211,13 @@ override:
police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
police->tcf_action = parm->action;
-#ifdef CONFIG_NET_ESTIMATOR
if (tb[TCA_POLICE_AVRATE-1])
police->tcfp_ewma_rate =
*(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
if (est)
gen_replace_estimator(&police->tcf_bstats,
&police->tcf_rate_est,
- police->tcf_stats_lock, est);
-#endif
+ &police->tcf_lock, est);
spin_unlock_bh(&police->tcf_lock);
if (ret != ACT_P_CREATED)
@@ -262,10 +244,19 @@ failure:
static int tcf_act_police_cleanup(struct tc_action *a, int bind)
{
struct tcf_police *p = a->priv;
+ int ret = 0;
- if (p != NULL)
- return tcf_police_release(p, bind);
- return 0;
+ if (p != NULL) {
+ if (bind)
+ p->tcf_bindcnt--;
+
+ p->tcf_refcnt--;
+ if (p->tcf_refcnt <= 0 && !p->tcf_bindcnt) {
+ tcf_police_destroy(p);
+ ret = 1;
+ }
+ }
+ return ret;
}
static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
@@ -281,14 +272,12 @@ static int tcf_act_police(struct sk_buff *skb, struct tc_action *a,
police->tcf_bstats.bytes += skb->len;
police->tcf_bstats.packets++;
-#ifdef CONFIG_NET_ESTIMATOR
if (police->tcfp_ewma_rate &&
police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
police->tcf_qstats.overlimits++;
spin_unlock(&police->tcf_lock);
return police->tcf_action;
}
-#endif
if (skb->len <= police->tcfp_mtu) {
if (police->tcfp_R_tab == NULL) {
@@ -348,10 +337,8 @@ tcf_act_police_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
if (police->tcfp_result)
RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int),
&police->tcfp_result);
-#ifdef CONFIG_NET_ESTIMATOR
if (police->tcfp_ewma_rate)
RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate);
-#endif
return skb->len;
rtattr_failure:
@@ -391,240 +378,3 @@ police_cleanup_module(void)
module_init(police_init_module);
module_exit(police_cleanup_module);
-
-#else /* CONFIG_NET_CLS_ACT */
-
-static struct tcf_common *tcf_police_lookup(u32 index)
-{
- struct tcf_hashinfo *hinfo = &police_hash_info;
- struct tcf_common *p;
-
- read_lock(hinfo->lock);
- for (p = hinfo->htab[tcf_hash(index, hinfo->hmask)]; p;
- p = p->tcfc_next) {
- if (p->tcfc_index == index)
- break;
- }
- read_unlock(hinfo->lock);
-
- return p;
-}
-
-static u32 tcf_police_new_index(void)
-{
- u32 *idx_gen = &police_idx_gen;
- u32 val = *idx_gen;
-
- do {
- if (++val == 0)
- val = 1;
- } while (tcf_police_lookup(val));
-
- return (*idx_gen = val);
-}
-
-struct tcf_police *tcf_police_locate(struct rtattr *rta, struct rtattr *est)
-{
- unsigned int h;
- struct tcf_police *police;
- struct rtattr *tb[TCA_POLICE_MAX];
- struct tc_police *parm;
- int size;
-
- if (rtattr_parse_nested(tb, TCA_POLICE_MAX, rta) < 0)
- return NULL;
-
- if (tb[TCA_POLICE_TBF-1] == NULL)
- return NULL;
- size = RTA_PAYLOAD(tb[TCA_POLICE_TBF-1]);
- if (size != sizeof(*parm) && size != sizeof(struct tc_police_compat))
- return NULL;
-
- parm = RTA_DATA(tb[TCA_POLICE_TBF-1]);
-
- if (parm->index) {
- struct tcf_common *pc;
-
- pc = tcf_police_lookup(parm->index);
- if (pc) {
- police = to_police(pc);
- police->tcf_refcnt++;
- return police;
- }
- }
- police = kzalloc(sizeof(*police), GFP_KERNEL);
- if (unlikely(!police))
- return NULL;
-
- police->tcf_refcnt = 1;
- spin_lock_init(&police->tcf_lock);
- police->tcf_stats_lock = &police->tcf_lock;
- if (parm->rate.rate) {
- police->tcfp_R_tab =
- qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1]);
- if (police->tcfp_R_tab == NULL)
- goto failure;
- if (parm->peakrate.rate) {
- police->tcfp_P_tab =
- qdisc_get_rtab(&parm->peakrate,
- tb[TCA_POLICE_PEAKRATE-1]);
- if (police->tcfp_P_tab == NULL)
- goto failure;
- }
- }
- if (tb[TCA_POLICE_RESULT-1]) {
- if (RTA_PAYLOAD(tb[TCA_POLICE_RESULT-1]) != sizeof(u32))
- goto failure;
- police->tcfp_result = *(u32*)RTA_DATA(tb[TCA_POLICE_RESULT-1]);
- }
-#ifdef CONFIG_NET_ESTIMATOR
- if (tb[TCA_POLICE_AVRATE-1]) {
- if (RTA_PAYLOAD(tb[TCA_POLICE_AVRATE-1]) != sizeof(u32))
- goto failure;
- police->tcfp_ewma_rate =
- *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]);
- }
-#endif
- police->tcfp_toks = police->tcfp_burst = parm->burst;
- police->tcfp_mtu = parm->mtu;
- if (police->tcfp_mtu == 0) {
- police->tcfp_mtu = ~0;
- if (police->tcfp_R_tab)
- police->tcfp_mtu = 255<<police->tcfp_R_tab->rate.cell_log;
- }
- if (police->tcfp_P_tab)
- police->tcfp_ptoks = L2T_P(police, police->tcfp_mtu);
- police->tcfp_t_c = psched_get_time();
- police->tcf_index = parm->index ? parm->index :
- tcf_police_new_index();
- police->tcf_action = parm->action;
-#ifdef CONFIG_NET_ESTIMATOR
- if (est)
- gen_new_estimator(&police->tcf_bstats, &police->tcf_rate_est,
- police->tcf_stats_lock, est);
-#endif
- h = tcf_hash(police->tcf_index, POL_TAB_MASK);
- write_lock_bh(&police_lock);
- police->tcf_next = tcf_police_ht[h];
- tcf_police_ht[h] = &police->common;
- write_unlock_bh(&police_lock);
- return police;
-
-failure:
- if (police->tcfp_R_tab)
- qdisc_put_rtab(police->tcfp_R_tab);
- kfree(police);
- return NULL;
-}
-
-int tcf_police(struct sk_buff *skb, struct tcf_police *police)
-{
- psched_time_t now;
- long toks;
- long ptoks = 0;
-
- spin_lock(&police->tcf_lock);
-
- police->tcf_bstats.bytes += skb->len;
- police->tcf_bstats.packets++;
-
-#ifdef CONFIG_NET_ESTIMATOR
- if (police->tcfp_ewma_rate &&
- police->tcf_rate_est.bps >= police->tcfp_ewma_rate) {
- police->tcf_qstats.overlimits++;
- spin_unlock(&police->tcf_lock);
- return police->tcf_action;
- }
-#endif
- if (skb->len <= police->tcfp_mtu) {
- if (police->tcfp_R_tab == NULL) {
- spin_unlock(&police->tcf_lock);
- return police->tcfp_result;
- }
-
- now = psched_get_time();
- toks = psched_tdiff_bounded(now, police->tcfp_t_c,
- police->tcfp_burst);
- if (police->tcfp_P_tab) {
- ptoks = toks + police->tcfp_ptoks;
- if (ptoks > (long)L2T_P(police, police->tcfp_mtu))
- ptoks = (long)L2T_P(police, police->tcfp_mtu);
- ptoks -= L2T_P(police, skb->len);
- }
- toks += police->tcfp_toks;
- if (toks > (long)police->tcfp_burst)
- toks = police->tcfp_burst;
- toks -= L2T(police, skb->len);
- if ((toks|ptoks) >= 0) {
- police->tcfp_t_c = now;
- police->tcfp_toks = toks;
- police->tcfp_ptoks = ptoks;
- spin_unlock(&police->tcf_lock);
- return police->tcfp_result;
- }
- }
-
- police->tcf_qstats.overlimits++;
- spin_unlock(&police->tcf_lock);
- return police->tcf_action;
-}
-EXPORT_SYMBOL(tcf_police);
-
-int tcf_police_dump(struct sk_buff *skb, struct tcf_police *police)
-{
- unsigned char *b = skb_tail_pointer(skb);
- struct tc_police opt;
-
- opt.index = police->tcf_index;
- opt.action = police->tcf_action;
- opt.mtu = police->tcfp_mtu;
- opt.burst = police->tcfp_burst;
- if (police->tcfp_R_tab)
- opt.rate = police->tcfp_R_tab->rate;
- else
- memset(&opt.rate, 0, sizeof(opt.rate));
- if (police->tcfp_P_tab)
- opt.peakrate = police->tcfp_P_tab->rate;
- else
- memset(&opt.peakrate, 0, sizeof(opt.peakrate));
- RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt);
- if (police->tcfp_result)
- RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int),
- &police->tcfp_result);
-#ifdef CONFIG_NET_ESTIMATOR
- if (police->tcfp_ewma_rate)
- RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &police->tcfp_ewma_rate);
-#endif
- return skb->len;
-
-rtattr_failure:
- nlmsg_trim(skb, b);
- return -1;
-}
-
-int tcf_police_dump_stats(struct sk_buff *skb, struct tcf_police *police)
-{
- struct gnet_dump d;
-
- if (gnet_stats_start_copy_compat(skb, TCA_STATS2, TCA_STATS,
- TCA_XSTATS, police->tcf_stats_lock,
- &d) < 0)
- goto errout;
-
- if (gnet_stats_copy_basic(&d, &police->tcf_bstats) < 0 ||
-#ifdef CONFIG_NET_ESTIMATOR
- gnet_stats_copy_rate_est(&d, &police->tcf_rate_est) < 0 ||
-#endif
- gnet_stats_copy_queue(&d, &police->tcf_qstats) < 0)
- goto errout;
-
- if (gnet_stats_finish_copy(&d) < 0)
- goto errout;
-
- return 0;
-
-errout:
- return -1;
-}
-
-#endif /* CONFIG_NET_CLS_ACT */
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 36e1edad5990..fb84ef33d14f 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <net/netlink.h>
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index ebf94edf0478..5f0fbca7393f 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -14,26 +14,16 @@
*
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/netlink.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
@@ -468,11 +458,6 @@ tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
tcf_action_destroy(exts->action, TCA_ACT_UNBIND);
exts->action = NULL;
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (exts->police) {
- tcf_police_release(exts->police, TCA_ACT_UNBIND);
- exts->police = NULL;
- }
#endif
}
@@ -506,17 +491,6 @@ tcf_exts_validate(struct tcf_proto *tp, struct rtattr **tb,
exts->action = act;
}
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (map->police && tb[map->police-1]) {
- struct tcf_police *p;
-
- p = tcf_police_locate(tb[map->police-1], rate_tlv);
- if (p == NULL)
- return -EINVAL;
-
- exts->police = p;
- } else if (map->action && tb[map->action-1])
- return -EOPNOTSUPP;
#else
if ((map->action && tb[map->action-1]) ||
(map->police && tb[map->police-1]))
@@ -539,15 +513,6 @@ tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
if (act)
tcf_action_destroy(act, TCA_ACT_UNBIND);
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (src->police) {
- struct tcf_police *p;
- tcf_tree_lock(tp);
- p = xchg(&dst->police, src->police);
- tcf_tree_unlock(tp);
- if (p)
- tcf_police_release(p, TCA_ACT_UNBIND);
- }
#endif
}
@@ -576,17 +541,6 @@ tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta;
}
}
-#elif defined CONFIG_NET_CLS_POLICE
- if (map->police && exts->police) {
- struct rtattr *p_rta = (struct rtattr *)skb_tail_pointer(skb);
-
- RTA_PUT(skb, map->police, 0, NULL);
-
- if (tcf_police_dump(skb, exts->police) < 0)
- goto rtattr_failure;
-
- p_rta->rta_len = skb_tail_pointer(skb) - (u8 *)p_rta;
- }
#endif
return 0;
rtattr_failure: __attribute__ ((unused))
@@ -601,10 +555,6 @@ tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
if (exts->action)
if (tcf_action_copy_stats(skb, exts->action, 1) < 0)
goto rtattr_failure;
-#elif defined CONFIG_NET_CLS_POLICE
- if (exts->police)
- if (tcf_police_dump_stats(skb, exts->police) < 0)
- goto rtattr_failure;
#endif
return 0;
rtattr_failure: __attribute__ ((unused))
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index c885412d79d5..8dbcf2771a46 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -13,7 +13,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c
index bbec4a0d4dcb..8adbd6a37d14 100644
--- a/net/sched/cls_fw.c
+++ b/net/sched/cls_fw.c
@@ -19,29 +19,12 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <linux/netfilter.h>
-#include <net/ip.h>
-#include <net/netlink.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
+#include <net/netlink.h>
#include <net/act_api.h>
#include <net/pkt_cls.h>
diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c
index cc941d0ee3a5..0a8409c1d28a 100644
--- a/net/sched/cls_route.c
+++ b/net/sched/cls_route.c
@@ -10,28 +10,14 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
-#include <net/netlink.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
+#include <net/dst.h>
+#include <net/route.h>
+#include <net/netlink.h>
#include <net/act_api.h>
#include <net/pkt_cls.h>
diff --git a/net/sched/cls_rsvp.c b/net/sched/cls_rsvp.c
index 0a683c07c648..cbb5e0d600f3 100644
--- a/net/sched/cls_rsvp.c
+++ b/net/sched/cls_rsvp.c
@@ -10,27 +10,12 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
+#include <net/ip.h>
#include <net/netlink.h>
#include <net/act_api.h>
#include <net/pkt_cls.h>
diff --git a/net/sched/cls_rsvp6.c b/net/sched/cls_rsvp6.c
index 93b6abed57db..dd08aea2aee5 100644
--- a/net/sched/cls_rsvp6.c
+++ b/net/sched/cls_rsvp6.c
@@ -10,28 +10,12 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
#include <linux/ipv6.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
#include <net/act_api.h>
#include <net/pkt_cls.h>
#include <net/netlink.h>
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index 47ac0c556429..2314820a080a 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -9,12 +9,9 @@
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <net/ip.h>
#include <net/act_api.h>
#include <net/netlink.h>
#include <net/pkt_cls.h>
-#include <net/route.h>
/*
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index c7a347bd6d70..8dbe36912ecb 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -30,30 +30,14 @@
* nfmark match added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro>
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
#include <linux/rtnetlink.h>
-#include <net/ip.h>
-#include <net/netlink.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
+#include <net/netlink.h>
#include <net/act_api.h>
#include <net/pkt_cls.h>
@@ -798,9 +782,6 @@ static int __init init_u32(void)
#ifdef CONFIG_CLS_U32_PERF
printk(" Performance counters on\n");
#endif
-#ifdef CONFIG_NET_CLS_POLICE
- printk(" OLD policer on \n");
-#endif
#ifdef CONFIG_NET_CLS_IND
printk(" input device check on \n");
#endif
diff --git a/net/sched/em_cmp.c b/net/sched/em_cmp.c
index 8d6dacd81900..cc49c932641d 100644
--- a/net/sched/em_cmp.c
+++ b/net/sched/em_cmp.c
@@ -98,3 +98,4 @@ MODULE_LICENSE("GPL");
module_init(init_em_cmp);
module_exit(exit_em_cmp);
+MODULE_ALIAS_TCF_EMATCH(TCF_EM_CMP);
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index 60acf8cdb27b..650f09c8bd6a 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -848,3 +848,5 @@ MODULE_LICENSE("GPL");
module_init(init_em_meta);
module_exit(exit_em_meta);
+
+MODULE_ALIAS_TCF_EMATCH(TCF_EM_META);
diff --git a/net/sched/em_nbyte.c b/net/sched/em_nbyte.c
index b4b36efce292..370a1b2ea317 100644
--- a/net/sched/em_nbyte.c
+++ b/net/sched/em_nbyte.c
@@ -76,3 +76,5 @@ MODULE_LICENSE("GPL");
module_init(init_em_nbyte);
module_exit(exit_em_nbyte);
+
+MODULE_ALIAS_TCF_EMATCH(TCF_EM_NBYTE);
diff --git a/net/sched/em_text.c b/net/sched/em_text.c
index e8f46169449d..d5cd86efb7d0 100644
--- a/net/sched/em_text.c
+++ b/net/sched/em_text.c
@@ -150,3 +150,5 @@ MODULE_LICENSE("GPL");
module_init(init_em_text);
module_exit(exit_em_text);
+
+MODULE_ALIAS_TCF_EMATCH(TCF_EM_TEXT);
diff --git a/net/sched/em_u32.c b/net/sched/em_u32.c
index 0a2a7fe08de3..112796e4a7c4 100644
--- a/net/sched/em_u32.c
+++ b/net/sched/em_u32.c
@@ -60,3 +60,5 @@ MODULE_LICENSE("GPL");
module_init(init_em_u32);
module_exit(exit_em_u32);
+
+MODULE_ALIAS_TCF_EMATCH(TCF_EM_U32);
diff --git a/net/sched/ematch.c b/net/sched/ematch.c
index 63146d339d81..f3a104e323bd 100644
--- a/net/sched/ematch.c
+++ b/net/sched/ematch.c
@@ -84,9 +84,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
#include <linux/rtnetlink.h>
#include <linux/skbuff.h>
#include <net/pkt_cls.h>
@@ -224,6 +222,19 @@ static int tcf_em_validate(struct tcf_proto *tp,
if (em->ops == NULL) {
err = -ENOENT;
+#ifdef CONFIG_KMOD
+ __rtnl_unlock();
+ request_module("ematch-kind-%u", em_hdr->kind);
+ rtnl_lock();
+ em->ops = tcf_em_lookup(em_hdr->kind);
+ if (em->ops) {
+ /* We dropped the RTNL mutex in order to
+ * perform the module load. Tell the caller
+ * to replay the request. */
+ module_put(em->ops->owner);
+ err = -EAGAIN;
+ }
+#endif
goto errout;
}
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index bec600af03ca..13c09bc32aa3 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -19,30 +19,18 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/kmod.h>
#include <linux/list.h>
-#include <linux/bitops.h>
#include <linux/hrtimer.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-
static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n, u32 clid,
struct Qdisc *old, struct Qdisc *new);
static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n,
@@ -290,11 +278,7 @@ static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
wd->qdisc->flags &= ~TCQ_F_THROTTLED;
smp_wmb();
- if (spin_trylock(&dev->queue_lock)) {
- qdisc_run(dev);
- spin_unlock(&dev->queue_lock);
- } else
- netif_schedule(dev);
+ netif_schedule(dev);
return HRTIMER_NORESTART;
}
@@ -515,7 +499,6 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
sch->handle = handle;
if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) {
-#ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1]) {
err = gen_new_estimator(&sch->bstats, &sch->rate_est,
sch->stats_lock,
@@ -531,7 +514,6 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
goto err_out3;
}
}
-#endif
qdisc_lock_tree(dev);
list_add_tail(&sch->list, &dev->qdisc_list);
qdisc_unlock_tree(dev);
@@ -559,11 +541,9 @@ static int qdisc_change(struct Qdisc *sch, struct rtattr **tca)
if (err)
return err;
}
-#ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1])
gen_replace_estimator(&sch->bstats, &sch->rate_est,
sch->stats_lock, tca[TCA_RATE-1]);
-#endif
return 0;
}
@@ -839,9 +819,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
goto rtattr_failure;
if (gnet_stats_copy_basic(&d, &q->bstats) < 0 ||
-#ifdef CONFIG_NET_ESTIMATOR
gnet_stats_copy_rate_est(&d, &q->rate_est) < 0 ||
-#endif
gnet_stats_copy_queue(&d, &q->qstats) < 0)
goto rtattr_failure;
@@ -1167,47 +1145,57 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
to this qdisc, (optionally) tests for protocol and asks
specific classifiers.
*/
+int tc_classify_compat(struct sk_buff *skb, struct tcf_proto *tp,
+ struct tcf_result *res)
+{
+ __be16 protocol = skb->protocol;
+ int err = 0;
+
+ for (; tp; tp = tp->next) {
+ if ((tp->protocol == protocol ||
+ tp->protocol == htons(ETH_P_ALL)) &&
+ (err = tp->classify(skb, tp, res)) >= 0) {
+#ifdef CONFIG_NET_CLS_ACT
+ if (err != TC_ACT_RECLASSIFY && skb->tc_verd)
+ skb->tc_verd = SET_TC_VERD(skb->tc_verd, 0);
+#endif
+ return err;
+ }
+ }
+ return -1;
+}
+EXPORT_SYMBOL(tc_classify_compat);
+
int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
- struct tcf_result *res)
+ struct tcf_result *res)
{
int err = 0;
- __be16 protocol = skb->protocol;
+ __be16 protocol;
#ifdef CONFIG_NET_CLS_ACT
struct tcf_proto *otp = tp;
reclassify:
#endif
protocol = skb->protocol;
- for ( ; tp; tp = tp->next) {
- if ((tp->protocol == protocol ||
- tp->protocol == htons(ETH_P_ALL)) &&
- (err = tp->classify(skb, tp, res)) >= 0) {
+ err = tc_classify_compat(skb, tp, res);
#ifdef CONFIG_NET_CLS_ACT
- if ( TC_ACT_RECLASSIFY == err) {
- __u32 verd = (__u32) G_TC_VERD(skb->tc_verd);
- tp = otp;
-
- if (MAX_REC_LOOP < verd++) {
- printk("rule prio %d protocol %02x reclassify is buggy packet dropped\n",
- tp->prio&0xffff, ntohs(tp->protocol));
- return TC_ACT_SHOT;
- }
- skb->tc_verd = SET_TC_VERD(skb->tc_verd,verd);
- goto reclassify;
- } else {
- if (skb->tc_verd)
- skb->tc_verd = SET_TC_VERD(skb->tc_verd,0);
- return err;
- }
-#else
-
- return err;
-#endif
+ if (err == TC_ACT_RECLASSIFY) {
+ u32 verd = G_TC_VERD(skb->tc_verd);
+ tp = otp;
+
+ if (verd++ >= MAX_REC_LOOP) {
+ printk("rule prio %u protocol %02x reclassify loop, "
+ "packet dropped\n",
+ tp->prio&0xffff, ntohs(tp->protocol));
+ return TC_ACT_SHOT;
}
-
+ skb->tc_verd = SET_TC_VERD(skb->tc_verd, verd);
+ goto reclassify;
}
- return -1;
+#endif
+ return err;
}
+EXPORT_SYMBOL(tc_classify);
void tcf_destroy(struct tcf_proto *tp)
{
@@ -1274,4 +1262,3 @@ EXPORT_SYMBOL(qdisc_get_rtab);
EXPORT_SYMBOL(qdisc_put_rtab);
EXPORT_SYMBOL(register_qdisc);
EXPORT_SYMBOL(unregister_qdisc);
-EXPORT_SYMBOL(tc_classify);
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index d1c383fca82c..ddc4f2c54379 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -2,24 +2,19 @@
/* Written 1998-2000 by Werner Almesberger, EPFL ICA */
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
-#include <linux/interrupt.h>
#include <linux/atmdev.h>
#include <linux/atmclip.h>
-#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
-#include <linux/file.h> /* for fput */
+#include <linux/file.h> /* for fput */
#include <net/netlink.h>
#include <net/pkt_sched.h>
-#include <net/sock.h>
-
-extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */
+extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */
#if 0 /* control */
#define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
@@ -33,7 +28,6 @@ extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */
#define D2PRINTK(format,args...)
#endif
-
/*
* The ATM queuing discipline provides a framework for invoking classifiers
* (aka "filters"), which in turn select classes of this queuing discipline.
@@ -55,23 +49,21 @@ extern struct socket *sockfd_lookup(int fd, int *err); /* @@@ fix this */
* - should lock the flow while there is data in the queue (?)
*/
-
#define PRIV(sch) qdisc_priv(sch)
#define VCC2FLOW(vcc) ((struct atm_flow_data *) ((vcc)->user_back))
-
struct atm_flow_data {
- struct Qdisc *q; /* FIFO, TBF, etc. */
+ struct Qdisc *q; /* FIFO, TBF, etc. */
struct tcf_proto *filter_list;
- struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
- void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* chaining */
+ struct atm_vcc *vcc; /* VCC; NULL if VCC is closed */
+ void (*old_pop)(struct atm_vcc *vcc,
+ struct sk_buff * skb); /* chaining */
struct atm_qdisc_data *parent; /* parent qdisc */
struct socket *sock; /* for closing */
u32 classid; /* x:y type ID */
int ref; /* reference count */
struct gnet_stats_basic bstats;
struct gnet_stats_queue qstats;
- spinlock_t *stats_lock;
struct atm_flow_data *next;
struct atm_flow_data *excess; /* flow for excess traffic;
NULL to set CLP instead */
@@ -86,76 +78,74 @@ struct atm_qdisc_data {
struct tasklet_struct task; /* requeue tasklet */
};
-
/* ------------------------- Class/flow operations ------------------------- */
-
-static int find_flow(struct atm_qdisc_data *qdisc,struct atm_flow_data *flow)
+static int find_flow(struct atm_qdisc_data *qdisc, struct atm_flow_data *flow)
{
struct atm_flow_data *walk;
- DPRINTK("find_flow(qdisc %p,flow %p)\n",qdisc,flow);
+ DPRINTK("find_flow(qdisc %p,flow %p)\n", qdisc, flow);
for (walk = qdisc->flows; walk; walk = walk->next)
- if (walk == flow) return 1;
+ if (walk == flow)
+ return 1;
DPRINTK("find_flow: not found\n");
return 0;
}
-
-static __inline__ struct atm_flow_data *lookup_flow(struct Qdisc *sch,
- u32 classid)
+static inline struct atm_flow_data *lookup_flow(struct Qdisc *sch, u32 classid)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
for (flow = p->flows; flow; flow = flow->next)
- if (flow->classid == classid) break;
+ if (flow->classid == classid)
+ break;
return flow;
}
-
-static int atm_tc_graft(struct Qdisc *sch,unsigned long arg,
- struct Qdisc *new,struct Qdisc **old)
+static int atm_tc_graft(struct Qdisc *sch, unsigned long arg,
+ struct Qdisc *new, struct Qdisc **old)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) arg;
-
- DPRINTK("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",sch,
- p,flow,new,old);
- if (!find_flow(p,flow)) return -EINVAL;
- if (!new) new = &noop_qdisc;
- *old = xchg(&flow->q,new);
- if (*old) qdisc_reset(*old);
+ struct atm_flow_data *flow = (struct atm_flow_data *)arg;
+
+ DPRINTK("atm_tc_graft(sch %p,[qdisc %p],flow %p,new %p,old %p)\n",
+ sch, p, flow, new, old);
+ if (!find_flow(p, flow))
+ return -EINVAL;
+ if (!new)
+ new = &noop_qdisc;
+ *old = xchg(&flow->q, new);
+ if (*old)
+ qdisc_reset(*old);
return 0;
}
-
-static struct Qdisc *atm_tc_leaf(struct Qdisc *sch,unsigned long cl)
+static struct Qdisc *atm_tc_leaf(struct Qdisc *sch, unsigned long cl)
{
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
- DPRINTK("atm_tc_leaf(sch %p,flow %p)\n",sch,flow);
+ DPRINTK("atm_tc_leaf(sch %p,flow %p)\n", sch, flow);
return flow ? flow->q : NULL;
}
-
-static unsigned long atm_tc_get(struct Qdisc *sch,u32 classid)
+static unsigned long atm_tc_get(struct Qdisc *sch, u32 classid)
{
- struct atm_qdisc_data *p __attribute__((unused)) = PRIV(sch);
+ struct atm_qdisc_data *p __maybe_unused = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n",sch,p,classid);
- flow = lookup_flow(sch,classid);
- if (flow) flow->ref++;
- DPRINTK("atm_tc_get: flow %p\n",flow);
- return (unsigned long) flow;
+ DPRINTK("atm_tc_get(sch %p,[qdisc %p],classid %x)\n", sch, p, classid);
+ flow = lookup_flow(sch, classid);
+ if (flow)
+ flow->ref++;
+ DPRINTK("atm_tc_get: flow %p\n", flow);
+ return (unsigned long)flow;
}
-
static unsigned long atm_tc_bind_filter(struct Qdisc *sch,
- unsigned long parent, u32 classid)
+ unsigned long parent, u32 classid)
{
- return atm_tc_get(sch,classid);
+ return atm_tc_get(sch, classid);
}
/*
@@ -163,72 +153,75 @@ static unsigned long atm_tc_bind_filter(struct Qdisc *sch,
* requested (atm_tc_destroy, etc.). The assumption here is that we never drop
* anything that still seems to be in use.
*/
-
static void atm_tc_put(struct Qdisc *sch, unsigned long cl)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
struct atm_flow_data **prev;
- DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
- if (--flow->ref) return;
+ DPRINTK("atm_tc_put(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
+ if (--flow->ref)
+ return;
DPRINTK("atm_tc_put: destroying\n");
for (prev = &p->flows; *prev; prev = &(*prev)->next)
- if (*prev == flow) break;
+ if (*prev == flow)
+ break;
if (!*prev) {
- printk(KERN_CRIT "atm_tc_put: class %p not found\n",flow);
+ printk(KERN_CRIT "atm_tc_put: class %p not found\n", flow);
return;
}
*prev = flow->next;
- DPRINTK("atm_tc_put: qdisc %p\n",flow->q);
+ DPRINTK("atm_tc_put: qdisc %p\n", flow->q);
qdisc_destroy(flow->q);
tcf_destroy_chain(flow->filter_list);
if (flow->sock) {
DPRINTK("atm_tc_put: f_count %d\n",
- file_count(flow->sock->file));
+ file_count(flow->sock->file));
flow->vcc->pop = flow->old_pop;
sockfd_put(flow->sock);
}
- if (flow->excess) atm_tc_put(sch,(unsigned long) flow->excess);
- if (flow != &p->link) kfree(flow);
+ if (flow->excess)
+ atm_tc_put(sch, (unsigned long)flow->excess);
+ if (flow != &p->link)
+ kfree(flow);
/*
* If flow == &p->link, the qdisc no longer works at this point and
* needs to be removed. (By the caller of atm_tc_put.)
*/
}
-
-static void sch_atm_pop(struct atm_vcc *vcc,struct sk_buff *skb)
+static void sch_atm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct atm_qdisc_data *p = VCC2FLOW(vcc)->parent;
- D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n",vcc,skb,p);
- VCC2FLOW(vcc)->old_pop(vcc,skb);
+ D2PRINTK("sch_atm_pop(vcc %p,skb %p,[qdisc %p])\n", vcc, skb, p);
+ VCC2FLOW(vcc)->old_pop(vcc, skb);
tasklet_schedule(&p->task);
}
static const u8 llc_oui_ip[] = {
- 0xaa, /* DSAP: non-ISO */
- 0xaa, /* SSAP: non-ISO */
- 0x03, /* Ctrl: Unnumbered Information Command PDU */
- 0x00, /* OUI: EtherType */
+ 0xaa, /* DSAP: non-ISO */
+ 0xaa, /* SSAP: non-ISO */
+ 0x03, /* Ctrl: Unnumbered Information Command PDU */
+ 0x00, /* OUI: EtherType */
0x00, 0x00,
- 0x08, 0x00 }; /* Ethertype IP (0800) */
+ 0x08, 0x00
+}; /* Ethertype IP (0800) */
static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
- struct rtattr **tca, unsigned long *arg)
+ struct rtattr **tca, unsigned long *arg)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) *arg;
+ struct atm_flow_data *flow = (struct atm_flow_data *)*arg;
struct atm_flow_data *excess = NULL;
- struct rtattr *opt = tca[TCA_OPTIONS-1];
+ struct rtattr *opt = tca[TCA_OPTIONS - 1];
struct rtattr *tb[TCA_ATM_MAX];
struct socket *sock;
- int fd,error,hdr_len;
+ int fd, error, hdr_len;
void *hdr;
DPRINTK("atm_tc_change(sch %p,[qdisc %p],classid %x,parent %x,"
- "flow %p,opt %p)\n",sch,p,classid,parent,flow,opt);
+ "flow %p,opt %p)\n", sch, p, classid, parent, flow, opt);
/*
* The concept of parents doesn't apply for this qdisc.
*/
@@ -241,33 +234,36 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
* class needs to be removed and a new one added. (This may be changed
* later.)
*/
- if (flow) return -EBUSY;
+ if (flow)
+ return -EBUSY;
if (opt == NULL || rtattr_parse_nested(tb, TCA_ATM_MAX, opt))
return -EINVAL;
- if (!tb[TCA_ATM_FD-1] || RTA_PAYLOAD(tb[TCA_ATM_FD-1]) < sizeof(fd))
+ if (!tb[TCA_ATM_FD - 1] || RTA_PAYLOAD(tb[TCA_ATM_FD - 1]) < sizeof(fd))
return -EINVAL;
- fd = *(int *) RTA_DATA(tb[TCA_ATM_FD-1]);
- DPRINTK("atm_tc_change: fd %d\n",fd);
- if (tb[TCA_ATM_HDR-1]) {
- hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR-1]);
- hdr = RTA_DATA(tb[TCA_ATM_HDR-1]);
- }
- else {
+ fd = *(int *)RTA_DATA(tb[TCA_ATM_FD - 1]);
+ DPRINTK("atm_tc_change: fd %d\n", fd);
+ if (tb[TCA_ATM_HDR - 1]) {
+ hdr_len = RTA_PAYLOAD(tb[TCA_ATM_HDR - 1]);
+ hdr = RTA_DATA(tb[TCA_ATM_HDR - 1]);
+ } else {
hdr_len = RFC1483LLC_LEN;
- hdr = NULL; /* default LLC/SNAP for IP */
+ hdr = NULL; /* default LLC/SNAP for IP */
}
- if (!tb[TCA_ATM_EXCESS-1]) excess = NULL;
+ if (!tb[TCA_ATM_EXCESS - 1])
+ excess = NULL;
else {
- if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS-1]) != sizeof(u32))
+ if (RTA_PAYLOAD(tb[TCA_ATM_EXCESS - 1]) != sizeof(u32))
return -EINVAL;
- excess = (struct atm_flow_data *) atm_tc_get(sch,
- *(u32 *) RTA_DATA(tb[TCA_ATM_EXCESS-1]));
- if (!excess) return -ENOENT;
+ excess = (struct atm_flow_data *)
+ atm_tc_get(sch, *(u32 *)RTA_DATA(tb[TCA_ATM_EXCESS - 1]));
+ if (!excess)
+ return -ENOENT;
}
DPRINTK("atm_tc_change: type %d, payload %d, hdr_len %d\n",
- opt->rta_type,RTA_PAYLOAD(opt),hdr_len);
- if (!(sock = sockfd_lookup(fd,&error))) return error; /* f_count++ */
- DPRINTK("atm_tc_change: f_count %d\n",file_count(sock->file));
+ opt->rta_type, RTA_PAYLOAD(opt), hdr_len);
+ if (!(sock = sockfd_lookup(fd, &error)))
+ return error; /* f_count++ */
+ DPRINTK("atm_tc_change: f_count %d\n", file_count(sock->file));
if (sock->ops->family != PF_ATMSVC && sock->ops->family != PF_ATMPVC) {
error = -EPROTOTYPE;
goto err_out;
@@ -280,37 +276,36 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
error = -EINVAL;
goto err_out;
}
- if (find_flow(p,flow)) {
+ if (find_flow(p, flow)) {
error = -EEXIST;
goto err_out;
}
- }
- else {
+ } else {
int i;
unsigned long cl;
for (i = 1; i < 0x8000; i++) {
- classid = TC_H_MAKE(sch->handle,0x8000 | i);
- if (!(cl = atm_tc_get(sch,classid))) break;
- atm_tc_put(sch,cl);
+ classid = TC_H_MAKE(sch->handle, 0x8000 | i);
+ if (!(cl = atm_tc_get(sch, classid)))
+ break;
+ atm_tc_put(sch, cl);
}
}
- DPRINTK("atm_tc_change: new id %x\n",classid);
- flow = kmalloc(sizeof(struct atm_flow_data)+hdr_len,GFP_KERNEL);
- DPRINTK("atm_tc_change: flow %p\n",flow);
+ DPRINTK("atm_tc_change: new id %x\n", classid);
+ flow = kzalloc(sizeof(struct atm_flow_data) + hdr_len, GFP_KERNEL);
+ DPRINTK("atm_tc_change: flow %p\n", flow);
if (!flow) {
error = -ENOBUFS;
goto err_out;
}
- memset(flow,0,sizeof(*flow));
flow->filter_list = NULL;
- if (!(flow->q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops,classid)))
+ if (!(flow->q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid)))
flow->q = &noop_qdisc;
- DPRINTK("atm_tc_change: qdisc %p\n",flow->q);
+ DPRINTK("atm_tc_change: qdisc %p\n", flow->q);
flow->sock = sock;
- flow->vcc = ATM_SD(sock); /* speedup */
+ flow->vcc = ATM_SD(sock); /* speedup */
flow->vcc->user_back = flow;
- DPRINTK("atm_tc_change: vcc %p\n",flow->vcc);
+ DPRINTK("atm_tc_change: vcc %p\n", flow->vcc);
flow->old_pop = flow->vcc->pop;
flow->parent = p;
flow->vcc->pop = sch_atm_pop;
@@ -321,50 +316,53 @@ static int atm_tc_change(struct Qdisc *sch, u32 classid, u32 parent,
p->link.next = flow;
flow->hdr_len = hdr_len;
if (hdr)
- memcpy(flow->hdr,hdr,hdr_len);
+ memcpy(flow->hdr, hdr, hdr_len);
else
- memcpy(flow->hdr,llc_oui_ip,sizeof(llc_oui_ip));
- *arg = (unsigned long) flow;
+ memcpy(flow->hdr, llc_oui_ip, sizeof(llc_oui_ip));
+ *arg = (unsigned long)flow;
return 0;
err_out:
- if (excess) atm_tc_put(sch,(unsigned long) excess);
+ if (excess)
+ atm_tc_put(sch, (unsigned long)excess);
sockfd_put(sock);
return error;
}
-
-static int atm_tc_delete(struct Qdisc *sch,unsigned long arg)
+static int atm_tc_delete(struct Qdisc *sch, unsigned long arg)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) arg;
+ struct atm_flow_data *flow = (struct atm_flow_data *)arg;
- DPRINTK("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
- if (!find_flow(PRIV(sch),flow)) return -EINVAL;
- if (flow->filter_list || flow == &p->link) return -EBUSY;
+ DPRINTK("atm_tc_delete(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
+ if (!find_flow(PRIV(sch), flow))
+ return -EINVAL;
+ if (flow->filter_list || flow == &p->link)
+ return -EBUSY;
/*
* Reference count must be 2: one for "keepalive" (set at class
* creation), and one for the reference held when calling delete.
*/
if (flow->ref < 2) {
- printk(KERN_ERR "atm_tc_delete: flow->ref == %d\n",flow->ref);
+ printk(KERN_ERR "atm_tc_delete: flow->ref == %d\n", flow->ref);
return -EINVAL;
}
- if (flow->ref > 2) return -EBUSY; /* catch references via excess, etc.*/
- atm_tc_put(sch,arg);
+ if (flow->ref > 2)
+ return -EBUSY; /* catch references via excess, etc. */
+ atm_tc_put(sch, arg);
return 0;
}
-
-static void atm_tc_walk(struct Qdisc *sch,struct qdisc_walker *walker)
+static void atm_tc_walk(struct Qdisc *sch, struct qdisc_walker *walker)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n",sch,p,walker);
- if (walker->stop) return;
+ DPRINTK("atm_tc_walk(sch %p,[qdisc %p],walker %p)\n", sch, p, walker);
+ if (walker->stop)
+ return;
for (flow = p->flows; flow; flow = flow->next) {
if (walker->count >= walker->skip)
- if (walker->fn(sch,(unsigned long) flow,walker) < 0) {
+ if (walker->fn(sch, (unsigned long)flow, walker) < 0) {
walker->stop = 1;
break;
}
@@ -372,73 +370,71 @@ static void atm_tc_walk(struct Qdisc *sch,struct qdisc_walker *walker)
}
}
-
-static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch,unsigned long cl)
+static struct tcf_proto **atm_tc_find_tcf(struct Qdisc *sch, unsigned long cl)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
- DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n",sch,p,flow);
+ DPRINTK("atm_tc_find_tcf(sch %p,[qdisc %p],flow %p)\n", sch, p, flow);
return flow ? &flow->filter_list : &p->link.filter_list;
}
-
/* --------------------------- Qdisc operations ---------------------------- */
-
-static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch)
+static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = NULL ; /* @@@ */
+ struct atm_flow_data *flow = NULL; /* @@@ */
struct tcf_result res;
int result;
int ret = NET_XMIT_POLICED;
- D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
- result = TC_POLICE_OK; /* be nice to gcc */
+ D2PRINTK("atm_tc_enqueue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+ result = TC_POLICE_OK; /* be nice to gcc */
if (TC_H_MAJ(skb->priority) != sch->handle ||
- !(flow = (struct atm_flow_data *) atm_tc_get(sch,skb->priority)))
+ !(flow = (struct atm_flow_data *)atm_tc_get(sch, skb->priority)))
for (flow = p->flows; flow; flow = flow->next)
if (flow->filter_list) {
- result = tc_classify(skb,flow->filter_list,
- &res);
- if (result < 0) continue;
- flow = (struct atm_flow_data *) res.class;
- if (!flow) flow = lookup_flow(sch,res.classid);
+ result = tc_classify_compat(skb,
+ flow->filter_list,
+ &res);
+ if (result < 0)
+ continue;
+ flow = (struct atm_flow_data *)res.class;
+ if (!flow)
+ flow = lookup_flow(sch, res.classid);
break;
}
- if (!flow) flow = &p->link;
+ if (!flow)
+ flow = &p->link;
else {
if (flow->vcc)
ATM_SKB(skb)->atm_options = flow->vcc->atm_options;
- /*@@@ looks good ... but it's not supposed to work :-)*/
-#ifdef CONFIG_NET_CLS_POLICE
+ /*@@@ looks good ... but it's not supposed to work :-) */
+#ifdef CONFIG_NET_CLS_ACT
switch (result) {
- case TC_POLICE_SHOT:
- kfree_skb(skb);
- break;
- case TC_POLICE_RECLASSIFY:
- if (flow->excess) flow = flow->excess;
- else {
- ATM_SKB(skb)->atm_options |=
- ATM_ATMOPT_CLP;
- break;
- }
- /* fall through */
- case TC_POLICE_OK:
- /* fall through */
- default:
- break;
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ kfree_skb(skb);
+ return NET_XMIT_SUCCESS;
+ case TC_ACT_SHOT:
+ kfree_skb(skb);
+ goto drop;
+ case TC_POLICE_RECLASSIFY:
+ if (flow->excess)
+ flow = flow->excess;
+ else
+ ATM_SKB(skb)->atm_options |= ATM_ATMOPT_CLP;
+ break;
}
#endif
}
- if (
-#ifdef CONFIG_NET_CLS_POLICE
- result == TC_POLICE_SHOT ||
-#endif
- (ret = flow->q->enqueue(skb,flow->q)) != 0) {
+
+ if ((ret = flow->q->enqueue(skb, flow->q)) != 0) {
+drop: __maybe_unused
sch->qstats.drops++;
- if (flow) flow->qstats.drops++;
+ if (flow)
+ flow->qstats.drops++;
return ret;
}
sch->bstats.bytes += skb->len;
@@ -462,7 +458,6 @@ static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch)
return NET_XMIT_BYPASS;
}
-
/*
* Dequeue packets and send them over ATM. Note that we quite deliberately
* avoid checking net_device's flow control here, simply because sch_atm
@@ -470,167 +465,163 @@ static int atm_tc_enqueue(struct sk_buff *skb,struct Qdisc *sch)
* non-ATM interfaces.
*/
-
static void sch_atm_dequeue(unsigned long data)
{
- struct Qdisc *sch = (struct Qdisc *) data;
+ struct Qdisc *sch = (struct Qdisc *)data;
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
struct sk_buff *skb;
- D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n",sch,p);
+ D2PRINTK("sch_atm_dequeue(sch %p,[qdisc %p])\n", sch, p);
for (flow = p->link.next; flow; flow = flow->next)
/*
* If traffic is properly shaped, this won't generate nasty
* little bursts. Otherwise, it may ... (but that's okay)
*/
while ((skb = flow->q->dequeue(flow->q))) {
- if (!atm_may_send(flow->vcc,skb->truesize)) {
- (void) flow->q->ops->requeue(skb,flow->q);
+ if (!atm_may_send(flow->vcc, skb->truesize)) {
+ (void)flow->q->ops->requeue(skb, flow->q);
break;
}
- D2PRINTK("atm_tc_dequeue: sending on class %p\n",flow);
+ D2PRINTK("atm_tc_dequeue: sending on class %p\n", flow);
/* remove any LL header somebody else has attached */
skb_pull(skb, skb_network_offset(skb));
if (skb_headroom(skb) < flow->hdr_len) {
struct sk_buff *new;
- new = skb_realloc_headroom(skb,flow->hdr_len);
+ new = skb_realloc_headroom(skb, flow->hdr_len);
dev_kfree_skb(skb);
- if (!new) continue;
+ if (!new)
+ continue;
skb = new;
}
D2PRINTK("sch_atm_dequeue: ip %p, data %p\n",
skb_network_header(skb), skb->data);
ATM_SKB(skb)->vcc = flow->vcc;
- memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
- flow->hdr_len);
+ memcpy(skb_push(skb, flow->hdr_len), flow->hdr,
+ flow->hdr_len);
atomic_add(skb->truesize,
&sk_atm(flow->vcc)->sk_wmem_alloc);
/* atm.atm_options are already set by atm_tc_enqueue */
- (void) flow->vcc->send(flow->vcc,skb);
+ flow->vcc->send(flow->vcc, skb);
}
}
-
static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct sk_buff *skb;
- D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n",sch,p);
+ D2PRINTK("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p);
tasklet_schedule(&p->task);
skb = p->link.q->dequeue(p->link.q);
- if (skb) sch->q.qlen--;
+ if (skb)
+ sch->q.qlen--;
return skb;
}
-
-static int atm_tc_requeue(struct sk_buff *skb,struct Qdisc *sch)
+static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
int ret;
- D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
- ret = p->link.q->ops->requeue(skb,p->link.q);
+ D2PRINTK("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p);
+ ret = p->link.q->ops->requeue(skb, p->link.q);
if (!ret) {
- sch->q.qlen++;
- sch->qstats.requeues++;
- } else {
+ sch->q.qlen++;
+ sch->qstats.requeues++;
+ } else {
sch->qstats.drops++;
p->link.qstats.drops++;
}
return ret;
}
-
static unsigned int atm_tc_drop(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
unsigned int len;
- DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n",sch,p);
+ DPRINTK("atm_tc_drop(sch %p,[qdisc %p])\n", sch, p);
for (flow = p->flows; flow; flow = flow->next)
if (flow->q->ops->drop && (len = flow->q->ops->drop(flow->q)))
return len;
return 0;
}
-
-static int atm_tc_init(struct Qdisc *sch,struct rtattr *opt)
+static int atm_tc_init(struct Qdisc *sch, struct rtattr *opt)
{
struct atm_qdisc_data *p = PRIV(sch);
- DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n",sch,p,opt);
+ DPRINTK("atm_tc_init(sch %p,[qdisc %p],opt %p)\n", sch, p, opt);
p->flows = &p->link;
- if(!(p->link.q = qdisc_create_dflt(sch->dev,&pfifo_qdisc_ops,
- sch->handle)))
+ if (!(p->link.q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
+ sch->handle)))
p->link.q = &noop_qdisc;
- DPRINTK("atm_tc_init: link (%p) qdisc %p\n",&p->link,p->link.q);
+ DPRINTK("atm_tc_init: link (%p) qdisc %p\n", &p->link, p->link.q);
p->link.filter_list = NULL;
p->link.vcc = NULL;
p->link.sock = NULL;
p->link.classid = sch->handle;
p->link.ref = 1;
p->link.next = NULL;
- tasklet_init(&p->task,sch_atm_dequeue,(unsigned long) sch);
+ tasklet_init(&p->task, sch_atm_dequeue, (unsigned long)sch);
return 0;
}
-
static void atm_tc_reset(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n",sch,p);
- for (flow = p->flows; flow; flow = flow->next) qdisc_reset(flow->q);
+ DPRINTK("atm_tc_reset(sch %p,[qdisc %p])\n", sch, p);
+ for (flow = p->flows; flow; flow = flow->next)
+ qdisc_reset(flow->q);
sch->q.qlen = 0;
}
-
static void atm_tc_destroy(struct Qdisc *sch)
{
struct atm_qdisc_data *p = PRIV(sch);
struct atm_flow_data *flow;
- DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n",sch,p);
+ DPRINTK("atm_tc_destroy(sch %p,[qdisc %p])\n", sch, p);
/* races ? */
while ((flow = p->flows)) {
tcf_destroy_chain(flow->filter_list);
flow->filter_list = NULL;
if (flow->ref > 1)
- printk(KERN_ERR "atm_destroy: %p->ref = %d\n",flow,
- flow->ref);
- atm_tc_put(sch,(unsigned long) flow);
+ printk(KERN_ERR "atm_destroy: %p->ref = %d\n", flow,
+ flow->ref);
+ atm_tc_put(sch, (unsigned long)flow);
if (p->flows == flow) {
printk(KERN_ERR "atm_destroy: putting flow %p didn't "
- "kill it\n",flow);
- p->flows = flow->next; /* brute force */
+ "kill it\n", flow);
+ p->flows = flow->next; /* brute force */
break;
}
}
tasklet_kill(&p->task);
}
-
static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
- struct sk_buff *skb, struct tcmsg *tcm)
+ struct sk_buff *skb, struct tcmsg *tcm)
{
struct atm_qdisc_data *p = PRIV(sch);
- struct atm_flow_data *flow = (struct atm_flow_data *) cl;
+ struct atm_flow_data *flow = (struct atm_flow_data *)cl;
unsigned char *b = skb_tail_pointer(skb);
struct rtattr *rta;
DPRINTK("atm_tc_dump_class(sch %p,[qdisc %p],flow %p,skb %p,tcm %p)\n",
- sch,p,flow,skb,tcm);
- if (!find_flow(p,flow)) return -EINVAL;
+ sch, p, flow, skb, tcm);
+ if (!find_flow(p, flow))
+ return -EINVAL;
tcm->tcm_handle = flow->classid;
tcm->tcm_info = flow->q->handle;
- rta = (struct rtattr *) b;
- RTA_PUT(skb,TCA_OPTIONS,0,NULL);
- RTA_PUT(skb,TCA_ATM_HDR,flow->hdr_len,flow->hdr);
+ rta = (struct rtattr *)b;
+ RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
+ RTA_PUT(skb, TCA_ATM_HDR, flow->hdr_len, flow->hdr);
if (flow->vcc) {
struct sockaddr_atmpvc pvc;
int state;
@@ -639,16 +630,16 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;
pvc.sap_addr.vpi = flow->vcc->vpi;
pvc.sap_addr.vci = flow->vcc->vci;
- RTA_PUT(skb,TCA_ATM_ADDR,sizeof(pvc),&pvc);
+ RTA_PUT(skb, TCA_ATM_ADDR, sizeof(pvc), &pvc);
state = ATM_VF2VS(flow->vcc->flags);
- RTA_PUT(skb,TCA_ATM_STATE,sizeof(state),&state);
+ RTA_PUT(skb, TCA_ATM_STATE, sizeof(state), &state);
}
if (flow->excess)
- RTA_PUT(skb,TCA_ATM_EXCESS,sizeof(u32),&flow->classid);
+ RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(u32), &flow->classid);
else {
static u32 zero;
- RTA_PUT(skb,TCA_ATM_EXCESS,sizeof(zero),&zero);
+ RTA_PUT(skb, TCA_ATM_EXCESS, sizeof(zero), &zero);
}
rta->rta_len = skb_tail_pointer(skb) - b;
return skb->len;
@@ -659,9 +650,9 @@ rtattr_failure:
}
static int
atm_tc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
- struct gnet_dump *d)
+ struct gnet_dump *d)
{
- struct atm_flow_data *flow = (struct atm_flow_data *) arg;
+ struct atm_flow_data *flow = (struct atm_flow_data *)arg;
flow->qstats.qlen = flow->q->q.qlen;
@@ -678,38 +669,35 @@ static int atm_tc_dump(struct Qdisc *sch, struct sk_buff *skb)
}
static struct Qdisc_class_ops atm_class_ops = {
- .graft = atm_tc_graft,
- .leaf = atm_tc_leaf,
- .get = atm_tc_get,
- .put = atm_tc_put,
- .change = atm_tc_change,
- .delete = atm_tc_delete,
- .walk = atm_tc_walk,
- .tcf_chain = atm_tc_find_tcf,
- .bind_tcf = atm_tc_bind_filter,
- .unbind_tcf = atm_tc_put,
- .dump = atm_tc_dump_class,
- .dump_stats = atm_tc_dump_class_stats,
+ .graft = atm_tc_graft,
+ .leaf = atm_tc_leaf,
+ .get = atm_tc_get,
+ .put = atm_tc_put,
+ .change = atm_tc_change,
+ .delete = atm_tc_delete,
+ .walk = atm_tc_walk,
+ .tcf_chain = atm_tc_find_tcf,
+ .bind_tcf = atm_tc_bind_filter,
+ .unbind_tcf = atm_tc_put,
+ .dump = atm_tc_dump_class,
+ .dump_stats = atm_tc_dump_class_stats,
};
static struct Qdisc_ops atm_qdisc_ops = {
- .next = NULL,
- .cl_ops = &atm_class_ops,
- .id = "atm",
- .priv_size = sizeof(struct atm_qdisc_data),
- .enqueue = atm_tc_enqueue,
- .dequeue = atm_tc_dequeue,
- .requeue = atm_tc_requeue,
- .drop = atm_tc_drop,
- .init = atm_tc_init,
- .reset = atm_tc_reset,
- .destroy = atm_tc_destroy,
- .change = NULL,
- .dump = atm_tc_dump,
- .owner = THIS_MODULE,
+ .cl_ops = &atm_class_ops,
+ .id = "atm",
+ .priv_size = sizeof(struct atm_qdisc_data),
+ .enqueue = atm_tc_enqueue,
+ .dequeue = atm_tc_dequeue,
+ .requeue = atm_tc_requeue,
+ .drop = atm_tc_drop,
+ .init = atm_tc_init,
+ .reset = atm_tc_reset,
+ .destroy = atm_tc_destroy,
+ .dump = atm_tc_dump,
+ .owner = THIS_MODULE,
};
-
static int __init atm_init(void)
{
return register_qdisc(&atm_qdisc_ops);
diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c
index cb0c456aa349..f914fc43a124 100644
--- a/net/sched/sch_blackhole.c
+++ b/net/sched/sch_blackhole.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/pkt_sched.h>
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index ee2d5967d109..e38c2839b25c 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -11,28 +11,12 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
-#include <net/netlink.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
+#include <net/netlink.h>
#include <net/pkt_sched.h>
@@ -98,7 +82,7 @@ struct cbq_class
unsigned char priority2; /* priority to be used after overlimit */
unsigned char ewma_log; /* time constant for idle time calculation */
unsigned char ovl_strategy;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
unsigned char police;
#endif
@@ -148,7 +132,6 @@ struct cbq_class
struct gnet_stats_basic bstats;
struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est;
- spinlock_t *stats_lock;
struct tc_cbq_xstats xstats;
struct tcf_proto *filter_list;
@@ -171,7 +154,7 @@ struct cbq_sched_data
struct cbq_class *active[TC_CBQ_MAXPRIO+1]; /* List of all classes
with backlog */
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
struct cbq_class *rx_class;
#endif
struct cbq_class *tx_class;
@@ -213,7 +196,7 @@ cbq_class_lookup(struct cbq_sched_data *q, u32 classid)
return NULL;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
static struct cbq_class *
cbq_reclassify(struct sk_buff *skb, struct cbq_class *this)
@@ -264,7 +247,8 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
/*
* Step 2+n. Apply classifier.
*/
- if (!head->filter_list || (result = tc_classify(skb, head->filter_list, &res)) < 0)
+ if (!head->filter_list ||
+ (result = tc_classify_compat(skb, head->filter_list, &res)) < 0)
goto fallback;
if ((cl = (void*)res.class) == NULL) {
@@ -284,15 +268,8 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
*qerr = NET_XMIT_SUCCESS;
case TC_ACT_SHOT:
return NULL;
- }
-#elif defined(CONFIG_NET_CLS_POLICE)
- switch (result) {
- case TC_POLICE_RECLASSIFY:
+ case TC_ACT_RECLASSIFY:
return cbq_reclassify(skb, cl);
- case TC_POLICE_SHOT:
- return NULL;
- default:
- break;
}
#endif
if (cl->level == 0)
@@ -406,7 +383,7 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
int ret;
struct cbq_class *cl = cbq_classify(skb, sch, &ret);
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
q->rx_class = cl;
#endif
if (cl == NULL) {
@@ -416,7 +393,7 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
return ret;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
cl->q->__parent = sch;
#endif
if ((ret = cl->q->enqueue(skb, cl->q)) == NET_XMIT_SUCCESS) {
@@ -451,7 +428,7 @@ cbq_requeue(struct sk_buff *skb, struct Qdisc *sch)
cbq_mark_toplevel(q, cl);
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
q->rx_class = cl;
cl->q->__parent = sch;
#endif
@@ -686,9 +663,7 @@ static enum hrtimer_restart cbq_undelay(struct hrtimer *timer)
return HRTIMER_NORESTART;
}
-
-#ifdef CONFIG_NET_CLS_POLICE
-
+#ifdef CONFIG_NET_CLS_ACT
static int cbq_reshape_fail(struct sk_buff *skb, struct Qdisc *child)
{
int len = skb->len;
@@ -1381,7 +1356,7 @@ static int cbq_set_overlimit(struct cbq_class *cl, struct tc_cbq_ovl *ovl)
return 0;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
static int cbq_set_police(struct cbq_class *cl, struct tc_cbq_police *p)
{
cl->police = p->police;
@@ -1442,7 +1417,6 @@ static int cbq_init(struct Qdisc *sch, struct rtattr *opt)
q->link.ewma_log = TC_CBQ_DEF_EWMA;
q->link.avpkt = q->link.allot/2;
q->link.minidle = -0x7FFFFFFF;
- q->link.stats_lock = &sch->dev->queue_lock;
qdisc_watchdog_init(&q->watchdog, sch);
hrtimer_init(&q->delay_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
@@ -1550,7 +1524,7 @@ rtattr_failure:
return -1;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
{
unsigned char *b = skb_tail_pointer(skb);
@@ -1576,7 +1550,7 @@ static int cbq_dump_attr(struct sk_buff *skb, struct cbq_class *cl)
cbq_dump_rate(skb, cl) < 0 ||
cbq_dump_wrr(skb, cl) < 0 ||
cbq_dump_ovl(skb, cl) < 0 ||
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
cbq_dump_police(skb, cl) < 0 ||
#endif
cbq_dump_fopt(skb, cl) < 0)
@@ -1653,9 +1627,7 @@ cbq_dump_class_stats(struct Qdisc *sch, unsigned long arg,
cl->xstats.undertime = cl->undertime - q->now;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
-#ifdef CONFIG_NET_ESTIMATOR
gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
-#endif
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
@@ -1673,7 +1645,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
cl->classid)) == NULL)
return -ENOBUFS;
} else {
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (cl->police == TC_POLICE_RECLASSIFY)
new->reshape_fail = cbq_reshape_fail;
#endif
@@ -1726,9 +1698,7 @@ static void cbq_destroy_class(struct Qdisc *sch, struct cbq_class *cl)
tcf_destroy_chain(cl->filter_list);
qdisc_destroy(cl->q);
qdisc_put_rtab(cl->R_tab);
-#ifdef CONFIG_NET_ESTIMATOR
gen_kill_estimator(&cl->bstats, &cl->rate_est);
-#endif
if (cl != &q->link)
kfree(cl);
}
@@ -1740,7 +1710,7 @@ cbq_destroy(struct Qdisc* sch)
struct cbq_class *cl;
unsigned h;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
q->rx_class = NULL;
#endif
/*
@@ -1769,7 +1739,7 @@ static void cbq_put(struct Qdisc *sch, unsigned long arg)
struct cbq_class *cl = (struct cbq_class*)arg;
if (--cl->refcnt == 0) {
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
struct cbq_sched_data *q = qdisc_priv(sch);
spin_lock_bh(&sch->dev->queue_lock);
@@ -1817,7 +1787,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
RTA_PAYLOAD(tb[TCA_CBQ_WRROPT-1]) < sizeof(struct tc_cbq_wrropt))
return -EINVAL;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (tb[TCA_CBQ_POLICE-1] &&
RTA_PAYLOAD(tb[TCA_CBQ_POLICE-1]) < sizeof(struct tc_cbq_police))
return -EINVAL;
@@ -1860,7 +1830,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
if (tb[TCA_CBQ_OVL_STRATEGY-1])
cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1]));
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (tb[TCA_CBQ_POLICE-1])
cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1]));
#endif
@@ -1873,11 +1843,10 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
sch_tree_unlock(sch);
-#ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
- cl->stats_lock, tca[TCA_RATE-1]);
-#endif
+ &sch->dev->queue_lock,
+ tca[TCA_RATE-1]);
return 0;
}
@@ -1935,7 +1904,6 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
cl->allot = parent->allot;
cl->quantum = cl->allot;
cl->weight = cl->R_tab->rate.rate;
- cl->stats_lock = &sch->dev->queue_lock;
sch_tree_lock(sch);
cbq_link_class(cl);
@@ -1955,7 +1923,7 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
cl->overlimit = cbq_ovl_classic;
if (tb[TCA_CBQ_OVL_STRATEGY-1])
cbq_set_overlimit(cl, RTA_DATA(tb[TCA_CBQ_OVL_STRATEGY-1]));
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (tb[TCA_CBQ_POLICE-1])
cbq_set_police(cl, RTA_DATA(tb[TCA_CBQ_POLICE-1]));
#endif
@@ -1963,11 +1931,9 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct rtattr **t
cbq_set_fopt(cl, RTA_DATA(tb[TCA_CBQ_FOPT-1]));
sch_tree_unlock(sch);
-#ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1])
gen_new_estimator(&cl->bstats, &cl->rate_est,
- cl->stats_lock, tca[TCA_RATE-1]);
-#endif
+ &sch->dev->queue_lock, tca[TCA_RATE-1]);
*arg = (unsigned long)cl;
return 0;
@@ -2001,7 +1967,7 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
q->tx_class = NULL;
q->tx_borrowed = NULL;
}
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (q->rx_class == cl)
q->rx_class = NULL;
#endif
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 3c6fd181263f..60f89199e3da 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/skbuff.h>
-#include <linux/netdevice.h> /* for pkt_sched */
#include <linux/rtnetlink.h>
#include <net/pkt_sched.h>
#include <net/dsfield.h>
@@ -238,25 +237,23 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
D2PRINTK("result %d class 0x%04x\n", result, res.classid);
switch (result) {
-#ifdef CONFIG_NET_CLS_POLICE
- case TC_POLICE_SHOT:
- kfree_skb(skb);
- sch->qstats.drops++;
- return NET_XMIT_POLICED;
-#if 0
- case TC_POLICE_RECLASSIFY:
- /* FIXME: what to do here ??? */
+#ifdef CONFIG_NET_CLS_ACT
+ case TC_ACT_QUEUED:
+ case TC_ACT_STOLEN:
+ kfree_skb(skb);
+ return NET_XMIT_SUCCESS;
+ case TC_ACT_SHOT:
+ kfree_skb(skb);
+ sch->qstats.drops++;
+ return NET_XMIT_BYPASS;
#endif
-#endif
- case TC_POLICE_OK:
- skb->tc_index = TC_H_MIN(res.classid);
- break;
- case TC_POLICE_UNSPEC:
- /* fall through */
- default:
- if (p->default_index != NO_DEFAULT_INDEX)
- skb->tc_index = p->default_index;
- break;
+ case TC_ACT_OK:
+ skb->tc_index = TC_H_MIN(res.classid);
+ break;
+ default:
+ if (p->default_index != NO_DEFAULT_INDEX)
+ skb->tc_index = p->default_index;
+ break;
}
}
diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c
index c2689f4ba8de..c264308f17c1 100644
--- a/net/sched/sch_fifo.c
+++ b/net/sched/sch_fifo.c
@@ -13,7 +13,6 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/pkt_sched.h>
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index f4d34480a093..c81649cf0b9e 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -11,27 +11,19 @@
* - Ingress support
*/
-#include <asm/uaccess.h>
-#include <asm/system.h>
#include <linux/bitops.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/init.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
/* Main transmission queue. */
@@ -59,122 +51,143 @@ void qdisc_unlock_tree(struct net_device *dev)
spin_unlock_bh(&dev->queue_lock);
}
-/*
- dev->queue_lock serializes queue accesses for this device
- AND dev->qdisc pointer itself.
+static inline int qdisc_qlen(struct Qdisc *q)
+{
+ return q->q.qlen;
+}
- netif_tx_lock serializes accesses to device driver.
+static inline int dev_requeue_skb(struct sk_buff *skb, struct net_device *dev,
+ struct Qdisc *q)
+{
+ if (unlikely(skb->next))
+ dev->gso_skb = skb;
+ else
+ q->ops->requeue(skb, q);
- dev->queue_lock and netif_tx_lock are mutually exclusive,
- if one is grabbed, another must be free.
- */
+ netif_schedule(dev);
+ return 0;
+}
+static inline struct sk_buff *dev_dequeue_skb(struct net_device *dev,
+ struct Qdisc *q)
+{
+ struct sk_buff *skb;
-/* Kick device.
+ if ((skb = dev->gso_skb))
+ dev->gso_skb = NULL;
+ else
+ skb = q->dequeue(q);
- Returns: 0 - queue is empty or throttled.
- >0 - queue is not empty.
+ return skb;
+}
- NOTE: Called under dev->queue_lock with locally disabled BH.
-*/
+static inline int handle_dev_cpu_collision(struct sk_buff *skb,
+ struct net_device *dev,
+ struct Qdisc *q)
+{
+ int ret;
+ if (unlikely(dev->xmit_lock_owner == smp_processor_id())) {
+ /*
+ * Same CPU holding the lock. It may be a transient
+ * configuration error, when hard_start_xmit() recurses. We
+ * detect it by checking xmit owner and drop the packet when
+ * deadloop is detected. Return OK to try the next skb.
+ */
+ kfree_skb(skb);
+ if (net_ratelimit())
+ printk(KERN_WARNING "Dead loop on netdevice %s, "
+ "fix it urgently!\n", dev->name);
+ ret = qdisc_qlen(q);
+ } else {
+ /*
+ * Another cpu is holding lock, requeue & delay xmits for
+ * some time.
+ */
+ __get_cpu_var(netdev_rx_stat).cpu_collision++;
+ ret = dev_requeue_skb(skb, dev, q);
+ }
+
+ return ret;
+}
+
+/*
+ * NOTE: Called under dev->queue_lock with locally disabled BH.
+ *
+ * __LINK_STATE_QDISC_RUNNING guarantees only one CPU can process this
+ * device at a time. dev->queue_lock serializes queue accesses for
+ * this device AND dev->qdisc pointer itself.
+ *
+ * netif_tx_lock serializes accesses to device driver.
+ *
+ * dev->queue_lock and netif_tx_lock are mutually exclusive,
+ * if one is grabbed, another must be free.
+ *
+ * Note, that this procedure can be called by a watchdog timer
+ *
+ * Returns to the caller:
+ * 0 - queue is empty or throttled.
+ * >0 - queue is not empty.
+ *
+ */
static inline int qdisc_restart(struct net_device *dev)
{
struct Qdisc *q = dev->qdisc;
struct sk_buff *skb;
+ unsigned lockless;
+ int ret;
/* Dequeue packet */
- if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) {
- unsigned nolock = (dev->features & NETIF_F_LLTX);
+ if (unlikely((skb = dev_dequeue_skb(dev, q)) == NULL))
+ return 0;
+
+ /*
+ * When the driver has LLTX set, it does its own locking in
+ * start_xmit. These checks are worth it because even uncongested
+ * locks can be quite expensive. The driver can do a trylock, as
+ * is being done here; in case of lock contention it should return
+ * NETDEV_TX_LOCKED and the packet will be requeued.
+ */
+ lockless = (dev->features & NETIF_F_LLTX);
- dev->gso_skb = NULL;
+ if (!lockless && !netif_tx_trylock(dev)) {
+ /* Another CPU grabbed the driver tx lock */
+ return handle_dev_cpu_collision(skb, dev, q);
+ }
- /*
- * When the driver has LLTX set it does its own locking
- * in start_xmit. No need to add additional overhead by
- * locking again. These checks are worth it because
- * even uncongested locks can be quite expensive.
- * The driver can do trylock like here too, in case
- * of lock congestion it should return -1 and the packet
- * will be requeued.
- */
- if (!nolock) {
- if (!netif_tx_trylock(dev)) {
- collision:
- /* So, someone grabbed the driver. */
-
- /* It may be transient configuration error,
- when hard_start_xmit() recurses. We detect
- it by checking xmit owner and drop the
- packet when deadloop is detected.
- */
- if (dev->xmit_lock_owner == smp_processor_id()) {
- kfree_skb(skb);
- if (net_ratelimit())
- printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
- goto out;
- }
- __get_cpu_var(netdev_rx_stat).cpu_collision++;
- goto requeue;
- }
- }
+ /* And release queue */
+ spin_unlock(&dev->queue_lock);
- {
- /* And release queue */
- spin_unlock(&dev->queue_lock);
-
- if (!netif_queue_stopped(dev)) {
- int ret;
-
- ret = dev_hard_start_xmit(skb, dev);
- if (ret == NETDEV_TX_OK) {
- if (!nolock) {
- netif_tx_unlock(dev);
- }
- spin_lock(&dev->queue_lock);
- q = dev->qdisc;
- goto out;
- }
- if (ret == NETDEV_TX_LOCKED && nolock) {
- spin_lock(&dev->queue_lock);
- q = dev->qdisc;
- goto collision;
- }
- }
+ ret = dev_hard_start_xmit(skb, dev);
- /* NETDEV_TX_BUSY - we need to requeue */
- /* Release the driver */
- if (!nolock) {
- netif_tx_unlock(dev);
- }
- spin_lock(&dev->queue_lock);
- q = dev->qdisc;
- }
+ if (!lockless)
+ netif_tx_unlock(dev);
- /* Device kicked us out :(
- This is possible in three cases:
+ spin_lock(&dev->queue_lock);
+ q = dev->qdisc;
- 0. driver is locked
- 1. fastroute is enabled
- 2. device cannot determine busy state
- before start of transmission (f.e. dialout)
- 3. device is buggy (ppp)
- */
+ switch (ret) {
+ case NETDEV_TX_OK:
+ /* Driver sent out skb successfully */
+ ret = qdisc_qlen(q);
+ break;
-requeue:
- if (unlikely(q == &noop_qdisc))
- kfree_skb(skb);
- else if (skb->next)
- dev->gso_skb = skb;
- else
- q->ops->requeue(skb, q);
- netif_schedule(dev);
+ case NETDEV_TX_LOCKED:
+ /* Driver try lock failed */
+ ret = handle_dev_cpu_collision(skb, dev, q);
+ break;
+
+ default:
+ /* Driver returned NETDEV_TX_BUSY - requeue skb */
+ if (unlikely (ret != NETDEV_TX_BUSY && net_ratelimit()))
+ printk(KERN_WARNING "BUG %s code %d qlen %d\n",
+ dev->name, ret, q->q.qlen);
+
+ ret = dev_requeue_skb(skb, dev, q);
+ break;
}
- return 0;
-out:
- BUG_ON((int) q->q.qlen < 0);
- return q->q.qlen;
+ return ret;
}
void __qdisc_run(struct net_device *dev)
@@ -493,9 +506,7 @@ void qdisc_destroy(struct Qdisc *qdisc)
return;
list_del(&qdisc->list);
-#ifdef CONFIG_NET_ESTIMATOR
gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
-#endif
if (ops->reset)
ops->reset(qdisc);
if (ops->destroy)
diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c
index fa1b4fe7a5fd..3cc6dda02e2e 100644
--- a/net/sched/sch_gred.c
+++ b/net/sched/sch_gred.c
@@ -21,7 +21,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/pkt_sched.h>
#include <net/red.h>
diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c
index 9d124c4ee3a7..55e7e4530f43 100644
--- a/net/sched/sch_hfsc.c
+++ b/net/sched/sch_hfsc.c
@@ -53,7 +53,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/jiffies.h>
#include <linux/compiler.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
@@ -62,13 +61,11 @@
#include <linux/list.h>
#include <linux/rbtree.h>
#include <linux/init.h>
-#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/pkt_sched.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
#include <net/pkt_cls.h>
-#include <asm/system.h>
#include <asm/div64.h>
/*
@@ -122,7 +119,6 @@ struct hfsc_class
struct gnet_stats_basic bstats;
struct gnet_stats_queue qstats;
struct gnet_stats_rate_est rate_est;
- spinlock_t *stats_lock;
unsigned int level; /* class level in hierarchy */
struct tcf_proto *filter_list; /* filter list */
unsigned int filter_cnt; /* filter count */
@@ -1054,11 +1050,10 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
}
sch_tree_unlock(sch);
-#ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1])
gen_replace_estimator(&cl->bstats, &cl->rate_est,
- cl->stats_lock, tca[TCA_RATE-1]);
-#endif
+ &sch->dev->queue_lock,
+ tca[TCA_RATE-1]);
return 0;
}
@@ -1098,7 +1093,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->qdisc = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, classid);
if (cl->qdisc == NULL)
cl->qdisc = &noop_qdisc;
- cl->stats_lock = &sch->dev->queue_lock;
INIT_LIST_HEAD(&cl->children);
cl->vt_tree = RB_ROOT;
cl->cf_tree = RB_ROOT;
@@ -1112,11 +1106,9 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
cl->cl_pcvtoff = parent->cl_cvtoff;
sch_tree_unlock(sch);
-#ifdef CONFIG_NET_ESTIMATOR
if (tca[TCA_RATE-1])
gen_new_estimator(&cl->bstats, &cl->rate_est,
- cl->stats_lock, tca[TCA_RATE-1]);
-#endif
+ &sch->dev->queue_lock, tca[TCA_RATE-1]);
*arg = (unsigned long)cl;
return 0;
}
@@ -1128,9 +1120,7 @@ hfsc_destroy_class(struct Qdisc *sch, struct hfsc_class *cl)
tcf_destroy_chain(cl->filter_list);
qdisc_destroy(cl->qdisc);
-#ifdef CONFIG_NET_ESTIMATOR
gen_kill_estimator(&cl->bstats, &cl->rate_est);
-#endif
if (cl != &q->root)
kfree(cl);
}
@@ -1184,9 +1174,6 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
case TC_ACT_SHOT:
return NULL;
}
-#elif defined(CONFIG_NET_CLS_POLICE)
- if (result == TC_POLICE_SHOT)
- return NULL;
#endif
if ((cl = (struct hfsc_class *)res.class) == NULL) {
if ((cl = hfsc_find_class(res.classid, sch)) == NULL)
@@ -1384,9 +1371,7 @@ hfsc_dump_class_stats(struct Qdisc *sch, unsigned long arg,
xstats.rtwork = cl->cl_cumul;
if (gnet_stats_copy_basic(d, &cl->bstats) < 0 ||
-#ifdef CONFIG_NET_ESTIMATOR
gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 ||
-#endif
gnet_stats_copy_queue(d, &cl->qstats) < 0)
return -1;
@@ -1448,8 +1433,6 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt)
return -EINVAL;
qopt = RTA_DATA(opt);
- sch->stats_lock = &sch->dev->queue_lock;
-
q->defcls = qopt->defcls;
for (i = 0; i < HFSC_HSIZE; i++)
INIT_LIST_HEAD(&q->clhash[i]);
@@ -1464,7 +1447,6 @@ hfsc_init_qdisc(struct Qdisc *sch, struct rtattr *opt)
sch->handle);
if (q->root.qdisc == NULL)
q->root.qdisc = &noop_qdisc;
- q->root.stats_lock = &sch->dev->queue_lock;
INIT_LIST_HEAD(&q->root.children);
q->root.vt_tree = RB_ROOT;
q->root.cf_tree = RB_ROOT;
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 035788c5b7f8..246a2f9765f1 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -28,32 +28,16 @@
* $Id: sch_htb.c,v 1.25 2003/12/07 11:08:25 devik Exp devik $
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
-#include <net/route.h>
#include <linux/skbuff.h>
#include <linux/list.h>
#include <linux/compiler.h>
+#include <linux/rbtree.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
-#include <linux/rbtree.h>
/* HTB algorithm.
Author: devik@cdi.cz
@@ -69,8 +53,6 @@
*/
#define HTB_HSIZE 16 /* classid hash size */
-#define HTB_EWMAC 2 /* rate average over HTB_EWMAC*HTB_HSIZE sec */
-#define HTB_RATECM 1 /* whether to use rate computer */
#define HTB_HYSTERESIS 1 /* whether to use mode hysteresis for speedup */
#define HTB_VER 0x30011 /* major must be matched with number suplied by TC as version */
@@ -95,12 +77,6 @@ struct htb_class {
struct tc_htb_xstats xstats; /* our special stats */
int refcnt; /* usage count of this class */
-#ifdef HTB_RATECM
- /* rate measurement counters */
- unsigned long rate_bytes, sum_bytes;
- unsigned long rate_packets, sum_packets;
-#endif
-
/* topology */
int level; /* our level (see above) */
struct htb_class *parent; /* parent class */
@@ -153,15 +129,12 @@ struct htb_class {
/* of un.leaf originals should be done. */
};
-/* TODO: maybe compute rate when size is too large .. or drop ? */
static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate,
int size)
{
int slot = size >> rate->rate.cell_log;
- if (slot > 255) {
- cl->xstats.giants++;
- slot = 255;
- }
+ if (slot > 255)
+ return (rate->data[255]*(slot >> 8) + rate->data[slot & 0xFF]);
return rate->data[slot];
}
@@ -194,10 +167,6 @@ struct htb_sched {
int rate2quantum; /* quant = rate / rate2quantum */
psched_time_t now; /* cached dequeue time */
struct qdisc_watchdog watchdog;
-#ifdef HTB_RATECM
- struct timer_list rttim; /* rate computer timer */
- int recmp_bucket; /* which hash bucket to recompute next */
-#endif
/* non shaped skbs; let them go directly thru */
struct sk_buff_head direct_queue;
@@ -280,9 +249,6 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
case TC_ACT_SHOT:
return NULL;
}
-#elif defined(CONFIG_NET_CLS_POLICE)
- if (result == TC_POLICE_SHOT)
- return HTB_DIRECT;
#endif
if ((cl = (void *)res.class) == NULL) {
if (res.classid == sch->handle)
@@ -634,13 +600,14 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)
cl->qstats.drops++;
return NET_XMIT_DROP;
} else {
- cl->bstats.packets++;
+ cl->bstats.packets +=
+ skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
cl->bstats.bytes += skb->len;
htb_activate(q, cl);
}
sch->q.qlen++;
- sch->bstats.packets++;
+ sch->bstats.packets += skb_is_gso(skb)?skb_shinfo(skb)->gso_segs:1;
sch->bstats.bytes += skb->len;
return NET_XMIT_SUCCESS;
}
@@ -677,34 +644,6 @@ static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch)
return NET_XMIT_SUCCESS;
}
-#ifdef HTB_RATECM
-#define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0
-static void htb_rate_timer(unsigned long arg)
-{
- struct Qdisc *sch = (struct Qdisc *)arg;
- struct htb_sched *q = qdisc_priv(sch);
- struct hlist_node *p;
- struct htb_class *cl;
-
-
- /* lock queue so that we can muck with it */
- spin_lock_bh(&sch->dev->queue_lock);
-
- q->rttim.expires = jiffies + HZ;
- add_timer(&q->rttim);
-
- /* scan and recompute one bucket at time */
- if (++q->recmp_bucket >= HTB_HSIZE)
- q->recmp_bucket = 0;
-
- hlist_for_each_entry(cl,p, q->hash + q->recmp_bucket, hlist) {
- RT_GEN(cl->sum_bytes, cl->rate_bytes);
- RT_GEN(cl->sum_packets, cl->rate_packets);
- }
- spin_unlock_bh(&sch->dev->queue_lock);
-}
-#endif
-
/**
* htb_charge_class - charges amount "bytes" to leaf and ancestors
*
@@ -717,8 +656,9 @@ static void htb_rate_timer(unsigned long arg)
* In such case we remove class from event queue first.
*/
static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
- int level, int bytes)
+ int level, struct sk_buff *skb)
{
+ int bytes = skb->len;
long toks, diff;
enum htb_cmode old_mode;
@@ -750,16 +690,12 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl,
if (cl->cmode != HTB_CAN_SEND)
htb_add_to_wait_tree(q, cl, diff);
}
-#ifdef HTB_RATECM
- /* update rate counters */
- cl->sum_bytes += bytes;
- cl->sum_packets++;
-#endif
/* update byte stats except for leaves which are already updated */
if (cl->level) {
cl->bstats.bytes += bytes;
- cl->bstats.packets++;
+ cl->bstats.packets += skb_is_gso(skb)?
+ skb_shinfo(skb)->gso_segs:1;
}
cl = cl->parent;
}
@@ -943,7 +879,7 @@ next:
gives us slightly better performance */
if (!cl->un.leaf.q->q.qlen)
htb_deactivate(q, cl);
- htb_charge_class(q, cl, level, skb->len);
+ htb_charge_class(q, cl, level, skb);
}
return skb;
}
@@ -1095,13 +1031,6 @@ static int htb_init(struct Qdisc *sch, struct rtattr *opt)
if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
q->direct_qlen = 2;
-#ifdef HTB_RATECM
- init_timer(&q->rttim);
- q->rttim.function = htb_rate_timer;
- q->rttim.data = (unsigned long)sch;
- q->rttim.expires = jiffies + HZ;
- add_timer(&q->rttim);
-#endif
if ((q->rate2quantum = gopt->rate2quantum) < 1)
q->rate2quantum = 1;
q->defcls = gopt->defcls;
@@ -1175,11 +1104,6 @@ htb_dump_class_stats(struct Qdisc *sch, unsigned long arg, struct gnet_dump *d)
{
struct htb_class *cl = (struct htb_class *)arg;
-#ifdef HTB_RATECM
- cl->rate_est.bps = cl->rate_bytes / (HTB_EWMAC * HTB_HSIZE);
- cl->rate_est.pps = cl->rate_packets / (HTB_EWMAC * HTB_HSIZE);
-#endif
-
if (!cl->level && cl->un.leaf.q)
cl->qstats.qlen = cl->un.leaf.q->q.qlen;
cl->xstats.tokens = cl->tokens;
@@ -1277,6 +1201,7 @@ static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
BUG_TRAP(cl->un.leaf.q);
qdisc_destroy(cl->un.leaf.q);
}
+ gen_kill_estimator(&cl->bstats, &cl->rate_est);
qdisc_put_rtab(cl->rate);
qdisc_put_rtab(cl->ceil);
@@ -1305,9 +1230,6 @@ static void htb_destroy(struct Qdisc *sch)
struct htb_sched *q = qdisc_priv(sch);
qdisc_watchdog_cancel(&q->watchdog);
-#ifdef HTB_RATECM
- del_timer_sync(&q->rttim);
-#endif
/* This line used to be after htb_destroy_class call below
and surprisingly it worked in 2.4. But it must precede it
because filter need its target class alive to be able to call
@@ -1403,6 +1325,20 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if (!cl) { /* new class */
struct Qdisc *new_q;
int prio;
+ struct {
+ struct rtattr rta;
+ struct gnet_estimator opt;
+ } est = {
+ .rta = {
+ .rta_len = RTA_LENGTH(sizeof(est.opt)),
+ .rta_type = TCA_RATE,
+ },
+ .opt = {
+ /* 4s interval, 16s averaging constant */
+ .interval = 2,
+ .ewma_log = 2,
+ },
+ };
/* check for valid classid */
if (!classid || TC_H_MAJ(classid ^ sch->handle)
@@ -1418,6 +1354,9 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL)
goto failure;
+ gen_new_estimator(&cl->bstats, &cl->rate_est,
+ &sch->dev->queue_lock,
+ tca[TCA_RATE-1] ? : &est.rta);
cl->refcnt = 1;
INIT_LIST_HEAD(&cl->sibling);
INIT_HLIST_NODE(&cl->hlist);
@@ -1469,8 +1408,13 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
hlist_add_head(&cl->hlist, q->hash + htb_hash(classid));
list_add_tail(&cl->sibling,
parent ? &parent->children : &q->root);
- } else
+ } else {
+ if (tca[TCA_RATE-1])
+ gen_replace_estimator(&cl->bstats, &cl->rate_est,
+ &sch->dev->queue_lock,
+ tca[TCA_RATE-1]);
sch_tree_lock(sch);
+ }
/* it used to be a nasty bug here, we have to check that node
is really leaf before changing cl->un.leaf ! */
diff --git a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
index f8b9f1cdf738..51f16b0af198 100644
--- a/net/sched/sch_ingress.c
+++ b/net/sched/sch_ingress.c
@@ -9,21 +9,14 @@
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/list.h>
#include <linux/skbuff.h>
-#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter.h>
-#include <linux/smp.h>
#include <net/netlink.h>
#include <net/pkt_sched.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-#include <linux/kmod.h>
-#include <linux/stat.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
#undef DEBUG_INGRESS
@@ -171,31 +164,12 @@ static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch)
result = TC_ACT_OK;
break;
}
-/* backward compat */
-#else
-#ifdef CONFIG_NET_CLS_POLICE
- switch (result) {
- case TC_POLICE_SHOT:
- result = NF_DROP;
- sch->qstats.drops++;
- break;
- case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */
- case TC_POLICE_OK:
- case TC_POLICE_UNSPEC:
- default:
- sch->bstats.packets++;
- sch->bstats.bytes += skb->len;
- result = NF_ACCEPT;
- break;
- }
-
#else
D2PRINTK("Overriding result to ACCEPT\n");
result = NF_ACCEPT;
sch->bstats.packets++;
sch->bstats.bytes += skb->len;
#endif
-#endif
return result;
}
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 5d9d8bc9cc3a..9e5e87e81f00 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -14,11 +14,9 @@
*/
#include <linux/module.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c
index 6d7542c26e47..2d8c08493d6e 100644
--- a/net/sched/sch_prio.c
+++ b/net/sched/sch_prio.c
@@ -12,37 +12,23 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
-#include <net/route.h>
#include <linux/skbuff.h>
#include <net/netlink.h>
-#include <net/sock.h>
#include <net/pkt_sched.h>
struct prio_sched_data
{
int bands;
+ int curband; /* for round-robin */
struct tcf_proto *filter_list;
u8 prio2band[TC_PRIO_MAX+1];
struct Qdisc *queues[TCQ_PRIO_BANDS];
+ int mq;
};
@@ -70,14 +56,17 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr)
#endif
if (TC_H_MAJ(band))
band = 0;
- return q->queues[q->prio2band[band&TC_PRIO_MAX]];
+ band = q->prio2band[band&TC_PRIO_MAX];
+ goto out;
}
band = res.classid;
}
band = TC_H_MIN(band) - 1;
if (band >= q->bands)
- return q->queues[q->prio2band[0]];
-
+ band = q->prio2band[0];
+out:
+ if (q->mq)
+ skb_set_queue_mapping(skb, band);
return q->queues[band];
}
@@ -144,17 +133,58 @@ prio_dequeue(struct Qdisc* sch)
struct Qdisc *qdisc;
for (prio = 0; prio < q->bands; prio++) {
- qdisc = q->queues[prio];
- skb = qdisc->dequeue(qdisc);
- if (skb) {
- sch->q.qlen--;
- return skb;
+ /* Check if the target subqueue is available before
+ * pulling an skb. This way we avoid excessive requeues
+ * for slower queues.
+ */
+ if (!netif_subqueue_stopped(sch->dev, (q->mq ? prio : 0))) {
+ qdisc = q->queues[prio];
+ skb = qdisc->dequeue(qdisc);
+ if (skb) {
+ sch->q.qlen--;
+ return skb;
+ }
}
}
return NULL;
}
+static struct sk_buff *rr_dequeue(struct Qdisc* sch)
+{
+ struct sk_buff *skb;
+ struct prio_sched_data *q = qdisc_priv(sch);
+ struct Qdisc *qdisc;
+ int bandcount;
+
+ /* Only take one pass through the queues. If nothing is available,
+ * return nothing.
+ */
+ for (bandcount = 0; bandcount < q->bands; bandcount++) {
+ /* Check if the target subqueue is available before
+ * pulling an skb. This way we avoid excessive requeues
+ * for slower queues. If the queue is stopped, try the
+ * next queue.
+ */
+ if (!netif_subqueue_stopped(sch->dev,
+ (q->mq ? q->curband : 0))) {
+ qdisc = q->queues[q->curband];
+ skb = qdisc->dequeue(qdisc);
+ if (skb) {
+ sch->q.qlen--;
+ q->curband++;
+ if (q->curband >= q->bands)
+ q->curband = 0;
+ return skb;
+ }
+ }
+ q->curband++;
+ if (q->curband >= q->bands)
+ q->curband = 0;
+ }
+ return NULL;
+}
+
static unsigned int prio_drop(struct Qdisc* sch)
{
struct prio_sched_data *q = qdisc_priv(sch);
@@ -198,21 +228,41 @@ prio_destroy(struct Qdisc* sch)
static int prio_tune(struct Qdisc *sch, struct rtattr *opt)
{
struct prio_sched_data *q = qdisc_priv(sch);
- struct tc_prio_qopt *qopt = RTA_DATA(opt);
+ struct tc_prio_qopt *qopt;
+ struct rtattr *tb[TCA_PRIO_MAX];
int i;
- if (opt->rta_len < RTA_LENGTH(sizeof(*qopt)))
+ if (rtattr_parse_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
+ sizeof(*qopt)))
return -EINVAL;
- if (qopt->bands > TCQ_PRIO_BANDS || qopt->bands < 2)
+ q->bands = qopt->bands;
+ /* If we're multiqueue, make sure the number of incoming bands
+ * matches the number of queues on the device we're associating with.
+ * If the number of bands requested is zero, then set q->bands to
+ * dev->egress_subqueue_count.
+ */
+ q->mq = RTA_GET_FLAG(tb[TCA_PRIO_MQ - 1]);
+ if (q->mq) {
+ if (sch->handle != TC_H_ROOT)
+ return -EINVAL;
+ if (netif_is_multiqueue(sch->dev)) {
+ if (q->bands == 0)
+ q->bands = sch->dev->egress_subqueue_count;
+ else if (q->bands != sch->dev->egress_subqueue_count)
+ return -EINVAL;
+ } else
+ return -EOPNOTSUPP;
+ }
+
+ if (q->bands > TCQ_PRIO_BANDS || q->bands < 2)
return -EINVAL;
for (i=0; i<=TC_PRIO_MAX; i++) {
- if (qopt->priomap[i] >= qopt->bands)
+ if (qopt->priomap[i] >= q->bands)
return -EINVAL;
}
sch_tree_lock(sch);
- q->bands = qopt->bands;
memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1);
for (i=q->bands; i<TCQ_PRIO_BANDS; i++) {
@@ -268,11 +318,17 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb)
{
struct prio_sched_data *q = qdisc_priv(sch);
unsigned char *b = skb_tail_pointer(skb);
+ struct rtattr *nest;
struct tc_prio_qopt opt;
opt.bands = q->bands;
memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1);
- RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+
+ nest = RTA_NEST_COMPAT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+ if (q->mq)
+ RTA_PUT_FLAG(skb, TCA_PRIO_MQ);
+ RTA_NEST_COMPAT_END(skb, nest);
+
return skb->len;
rtattr_failure:
@@ -443,17 +499,44 @@ static struct Qdisc_ops prio_qdisc_ops = {
.owner = THIS_MODULE,
};
+static struct Qdisc_ops rr_qdisc_ops = {
+ .next = NULL,
+ .cl_ops = &prio_class_ops,
+ .id = "rr",
+ .priv_size = sizeof(struct prio_sched_data),
+ .enqueue = prio_enqueue,
+ .dequeue = rr_dequeue,
+ .requeue = prio_requeue,
+ .drop = prio_drop,
+ .init = prio_init,
+ .reset = prio_reset,
+ .destroy = prio_destroy,
+ .change = prio_tune,
+ .dump = prio_dump,
+ .owner = THIS_MODULE,
+};
+
static int __init prio_module_init(void)
{
- return register_qdisc(&prio_qdisc_ops);
+ int err;
+
+ err = register_qdisc(&prio_qdisc_ops);
+ if (err < 0)
+ return err;
+ err = register_qdisc(&rr_qdisc_ops);
+ if (err < 0)
+ unregister_qdisc(&prio_qdisc_ops);
+ return err;
}
static void __exit prio_module_exit(void)
{
unregister_qdisc(&prio_qdisc_ops);
+ unregister_qdisc(&rr_qdisc_ops);
}
module_init(prio_module_init)
module_exit(prio_module_exit)
MODULE_LICENSE("GPL");
+MODULE_ALIAS("sch_rr");
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 00db53eb8159..9b95fefb70f4 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/pkt_sched.h>
#include <net/inet_ecn.h>
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 96dfdf78d32c..957957309859 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -10,31 +10,17 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
#include <linux/init.h>
-#include <net/ip.h>
-#include <net/netlink.h>
#include <linux/ipv6.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
+#include <net/ip.h>
+#include <net/netlink.h>
#include <net/pkt_sched.h>
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 53862953baaf..8c2639af4c6a 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -13,29 +13,12 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/jiffies.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
-#include <net/ip.h>
-#include <net/netlink.h>
-#include <net/route.h>
#include <linux/skbuff.h>
-#include <net/sock.h>
+#include <net/netlink.h>
#include <net/pkt_sched.h>
@@ -142,7 +125,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch)
if (skb->len > q->max_size) {
sch->qstats.drops++;
-#ifdef CONFIG_NET_CLS_POLICE
+#ifdef CONFIG_NET_CLS_ACT
if (sch->reshape_fail == NULL || sch->reshape_fail(skb, sch))
#endif
kfree_skb(skb);
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index f05ad9a30b4c..0968184ea6be 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -9,30 +9,17 @@
*/
#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
#include <linux/errno.h>
-#include <linux/interrupt.h>
#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/inet.h>
#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/notifier.h>
#include <linux/init.h>
-#include <net/ip.h>
-#include <net/route.h>
#include <linux/skbuff.h>
#include <linux/moduleparam.h>
-#include <net/sock.h>
+#include <net/dst.h>
+#include <net/neighbour.h>
#include <net/pkt_sched.h>
/*
@@ -225,7 +212,6 @@ static int teql_qdisc_init(struct Qdisc *sch, struct rtattr *opt)
return 0;
}
-/* "teql*" netdevice routines */
static int
__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev)
@@ -277,6 +263,7 @@ static int teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
int busy;
int nores;
int len = skb->len;
+ int subq = skb->queue_mapping;
struct sk_buff *skb_res = NULL;
start = master->slaves;
@@ -293,7 +280,9 @@ restart:
if (slave->qdisc_sleeping != q)
continue;
- if (netif_queue_stopped(slave) || ! netif_running(slave)) {
+ if (netif_queue_stopped(slave) ||
+ netif_subqueue_stopped(slave, subq) ||
+ !netif_running(slave)) {
busy = 1;
continue;
}
@@ -302,6 +291,7 @@ restart:
case 0:
if (netif_tx_trylock(slave)) {
if (!netif_queue_stopped(slave) &&
+ !netif_subqueue_stopped(slave, subq) &&
slave->hard_start_xmit(skb, slave) == 0) {
netif_tx_unlock(slave);
master->slaves = NEXT_SLAVE(q);
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 2f12bf2d8d3c..e4cd841a22e4 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -250,7 +250,7 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations sctp_eps_ops = {
+static const struct seq_operations sctp_eps_ops = {
.start = sctp_eps_seq_start,
.next = sctp_eps_seq_next,
.stop = sctp_eps_seq_stop,
@@ -361,7 +361,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations sctp_assoc_ops = {
+static const struct seq_operations sctp_assoc_ops = {
.start = sctp_assocs_seq_start,
.next = sctp_assocs_seq_next,
.stop = sctp_assocs_seq_stop,
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 34bab36637ac..e98579b788b8 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -980,14 +980,14 @@ SCTP_STATIC __init int sctp_init(void)
sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
sizeof(struct sctp_bind_bucket),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!sctp_bucket_cachep)
goto out;
sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
sizeof(struct sctp_chunk),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!sctp_chunk_cachep)
goto err_chunk_cachep;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index f02ce3dddb7b..fd2dfdd7d7fd 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -1779,7 +1779,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
SCTP_COMM_UP, 0,
asoc->c.sinit_num_ostreams,
asoc->c.sinit_max_instreams,
- NULL, GFP_ATOMIC);
+ NULL, GFP_ATOMIC);
if (!ev)
goto nomem;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index b1917f68723c..ee88f2ea5101 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4803,7 +4803,7 @@ static int sctp_getsockopt_partial_delivery_point(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
- u32 val;
+ u32 val;
if (len < sizeof(u32))
return -EINVAL;
@@ -4827,7 +4827,7 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
char __user *optval,
int __user *optlen)
{
- int val;
+ int val;
if (len < sizeof(int))
return -EINVAL;
diff --git a/net/socket.c b/net/socket.c
index f4530196a70a..ec077037f534 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -272,8 +272,7 @@ static int init_inodecache(void)
(SLAB_HWCACHE_ALIGN |
SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD),
- init_once,
- NULL);
+ init_once);
if (sock_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -1939,9 +1938,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg,
total_len = err;
cmsg_ptr = (unsigned long)msg_sys.msg_control;
- msg_sys.msg_flags = 0;
- if (MSG_CMSG_COMPAT & flags)
- msg_sys.msg_flags = MSG_CMSG_COMPAT;
+ msg_sys.msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 9527f2bb1744..1ea27559b1de 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -18,12 +18,16 @@
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
-static struct rpc_authops * auth_flavors[RPC_AUTH_MAXFLAVOR] = {
+static DEFINE_SPINLOCK(rpc_authflavor_lock);
+static const struct rpc_authops *auth_flavors[RPC_AUTH_MAXFLAVOR] = {
&authnull_ops, /* AUTH_NULL */
&authunix_ops, /* AUTH_UNIX */
NULL, /* others can be loadable modules */
};
+static LIST_HEAD(cred_unused);
+static unsigned long number_cred_unused;
+
static u32
pseudoflavor_to_flavor(u32 flavor) {
if (flavor >= RPC_AUTH_MAXFLAVOR)
@@ -32,55 +36,67 @@ pseudoflavor_to_flavor(u32 flavor) {
}
int
-rpcauth_register(struct rpc_authops *ops)
+rpcauth_register(const struct rpc_authops *ops)
{
rpc_authflavor_t flavor;
+ int ret = -EPERM;
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
return -EINVAL;
- if (auth_flavors[flavor] != NULL)
- return -EPERM; /* what else? */
- auth_flavors[flavor] = ops;
- return 0;
+ spin_lock(&rpc_authflavor_lock);
+ if (auth_flavors[flavor] == NULL) {
+ auth_flavors[flavor] = ops;
+ ret = 0;
+ }
+ spin_unlock(&rpc_authflavor_lock);
+ return ret;
}
int
-rpcauth_unregister(struct rpc_authops *ops)
+rpcauth_unregister(const struct rpc_authops *ops)
{
rpc_authflavor_t flavor;
+ int ret = -EPERM;
if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
return -EINVAL;
- if (auth_flavors[flavor] != ops)
- return -EPERM; /* what else? */
- auth_flavors[flavor] = NULL;
- return 0;
+ spin_lock(&rpc_authflavor_lock);
+ if (auth_flavors[flavor] == ops) {
+ auth_flavors[flavor] = NULL;
+ ret = 0;
+ }
+ spin_unlock(&rpc_authflavor_lock);
+ return ret;
}
struct rpc_auth *
rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
{
struct rpc_auth *auth;
- struct rpc_authops *ops;
+ const struct rpc_authops *ops;
u32 flavor = pseudoflavor_to_flavor(pseudoflavor);
auth = ERR_PTR(-EINVAL);
if (flavor >= RPC_AUTH_MAXFLAVOR)
goto out;
- /* FIXME - auth_flavors[] really needs an rw lock,
- * and module refcounting. */
#ifdef CONFIG_KMOD
if ((ops = auth_flavors[flavor]) == NULL)
request_module("rpc-auth-%u", flavor);
#endif
- if ((ops = auth_flavors[flavor]) == NULL)
+ spin_lock(&rpc_authflavor_lock);
+ ops = auth_flavors[flavor];
+ if (ops == NULL || !try_module_get(ops->owner)) {
+ spin_unlock(&rpc_authflavor_lock);
goto out;
+ }
+ spin_unlock(&rpc_authflavor_lock);
auth = ops->create(clnt, pseudoflavor);
+ module_put(ops->owner);
if (IS_ERR(auth))
return auth;
if (clnt->cl_auth)
- rpcauth_destroy(clnt->cl_auth);
+ rpcauth_release(clnt->cl_auth);
clnt->cl_auth = auth;
out:
@@ -88,7 +104,7 @@ out:
}
void
-rpcauth_destroy(struct rpc_auth *auth)
+rpcauth_release(struct rpc_auth *auth)
{
if (!atomic_dec_and_test(&auth->au_count))
return;
@@ -97,11 +113,31 @@ rpcauth_destroy(struct rpc_auth *auth)
static DEFINE_SPINLOCK(rpc_credcache_lock);
+static void
+rpcauth_unhash_cred_locked(struct rpc_cred *cred)
+{
+ hlist_del_rcu(&cred->cr_hash);
+ smp_mb__before_clear_bit();
+ clear_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
+}
+
+static void
+rpcauth_unhash_cred(struct rpc_cred *cred)
+{
+ spinlock_t *cache_lock;
+
+ cache_lock = &cred->cr_auth->au_credcache->lock;
+ spin_lock(cache_lock);
+ if (atomic_read(&cred->cr_count) == 0)
+ rpcauth_unhash_cred_locked(cred);
+ spin_unlock(cache_lock);
+}
+
/*
* Initialize RPC credential cache
*/
int
-rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire)
+rpcauth_init_credcache(struct rpc_auth *auth)
{
struct rpc_cred_cache *new;
int i;
@@ -111,8 +147,7 @@ rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire)
return -ENOMEM;
for (i = 0; i < RPC_CREDCACHE_NR; i++)
INIT_HLIST_HEAD(&new->hashtable[i]);
- new->expire = expire;
- new->nextgc = jiffies + (expire >> 1);
+ spin_lock_init(&new->lock);
auth->au_credcache = new;
return 0;
}
@@ -121,13 +156,13 @@ rpcauth_init_credcache(struct rpc_auth *auth, unsigned long expire)
* Destroy a list of credentials
*/
static inline
-void rpcauth_destroy_credlist(struct hlist_head *head)
+void rpcauth_destroy_credlist(struct list_head *head)
{
struct rpc_cred *cred;
- while (!hlist_empty(head)) {
- cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
- hlist_del_init(&cred->cr_hash);
+ while (!list_empty(head)) {
+ cred = list_entry(head->next, struct rpc_cred, cr_lru);
+ list_del_init(&cred->cr_lru);
put_rpccred(cred);
}
}
@@ -137,58 +172,95 @@ void rpcauth_destroy_credlist(struct hlist_head *head)
* that are not referenced.
*/
void
-rpcauth_free_credcache(struct rpc_auth *auth)
+rpcauth_clear_credcache(struct rpc_cred_cache *cache)
{
- struct rpc_cred_cache *cache = auth->au_credcache;
- HLIST_HEAD(free);
- struct hlist_node *pos, *next;
+ LIST_HEAD(free);
+ struct hlist_head *head;
struct rpc_cred *cred;
int i;
spin_lock(&rpc_credcache_lock);
+ spin_lock(&cache->lock);
for (i = 0; i < RPC_CREDCACHE_NR; i++) {
- hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
- cred = hlist_entry(pos, struct rpc_cred, cr_hash);
- __hlist_del(&cred->cr_hash);
- hlist_add_head(&cred->cr_hash, &free);
+ head = &cache->hashtable[i];
+ while (!hlist_empty(head)) {
+ cred = hlist_entry(head->first, struct rpc_cred, cr_hash);
+ get_rpccred(cred);
+ if (!list_empty(&cred->cr_lru)) {
+ list_del(&cred->cr_lru);
+ number_cred_unused--;
+ }
+ list_add_tail(&cred->cr_lru, &free);
+ rpcauth_unhash_cred_locked(cred);
}
}
+ spin_unlock(&cache->lock);
spin_unlock(&rpc_credcache_lock);
rpcauth_destroy_credlist(&free);
}
-static void
-rpcauth_prune_expired(struct rpc_auth *auth, struct rpc_cred *cred, struct hlist_head *free)
+/*
+ * Destroy the RPC credential cache
+ */
+void
+rpcauth_destroy_credcache(struct rpc_auth *auth)
{
- if (atomic_read(&cred->cr_count) != 1)
- return;
- if (time_after(jiffies, cred->cr_expire + auth->au_credcache->expire))
- cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
- if (!(cred->cr_flags & RPCAUTH_CRED_UPTODATE)) {
- __hlist_del(&cred->cr_hash);
- hlist_add_head(&cred->cr_hash, free);
+ struct rpc_cred_cache *cache = auth->au_credcache;
+
+ if (cache) {
+ auth->au_credcache = NULL;
+ rpcauth_clear_credcache(cache);
+ kfree(cache);
}
}
/*
* Remove stale credentials. Avoid sleeping inside the loop.
*/
-static void
-rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free)
+static int
+rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
{
- struct rpc_cred_cache *cache = auth->au_credcache;
- struct hlist_node *pos, *next;
- struct rpc_cred *cred;
- int i;
+ spinlock_t *cache_lock;
+ struct rpc_cred *cred;
- dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
- for (i = 0; i < RPC_CREDCACHE_NR; i++) {
- hlist_for_each_safe(pos, next, &cache->hashtable[i]) {
- cred = hlist_entry(pos, struct rpc_cred, cr_hash);
- rpcauth_prune_expired(auth, cred, free);
+ while (!list_empty(&cred_unused)) {
+ cred = list_entry(cred_unused.next, struct rpc_cred, cr_lru);
+ list_del_init(&cred->cr_lru);
+ number_cred_unused--;
+ if (atomic_read(&cred->cr_count) != 0)
+ continue;
+ cache_lock = &cred->cr_auth->au_credcache->lock;
+ spin_lock(cache_lock);
+ if (atomic_read(&cred->cr_count) == 0) {
+ get_rpccred(cred);
+ list_add_tail(&cred->cr_lru, free);
+ rpcauth_unhash_cred_locked(cred);
+ nr_to_scan--;
}
+ spin_unlock(cache_lock);
+ if (nr_to_scan == 0)
+ break;
}
- cache->nextgc = jiffies + cache->expire;
+ return nr_to_scan;
+}
+
+/*
+ * Run memory cache shrinker.
+ */
+static int
+rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
+{
+ LIST_HEAD(free);
+ int res;
+
+ if (list_empty(&cred_unused))
+ return 0;
+ spin_lock(&rpc_credcache_lock);
+ nr_to_scan = rpcauth_prune_expired(&free, nr_to_scan);
+ res = (number_cred_unused / 100) * sysctl_vfs_cache_pressure;
+ spin_unlock(&rpc_credcache_lock);
+ rpcauth_destroy_credlist(&free);
+ return res;
}
/*
@@ -198,53 +270,56 @@ struct rpc_cred *
rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
int flags)
{
+ LIST_HEAD(free);
struct rpc_cred_cache *cache = auth->au_credcache;
- HLIST_HEAD(free);
- struct hlist_node *pos, *next;
- struct rpc_cred *new = NULL,
- *cred = NULL;
+ struct hlist_node *pos;
+ struct rpc_cred *cred = NULL,
+ *entry, *new;
int nr = 0;
if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS))
nr = acred->uid & RPC_CREDCACHE_MASK;
-retry:
- spin_lock(&rpc_credcache_lock);
- if (time_before(cache->nextgc, jiffies))
- rpcauth_gc_credcache(auth, &free);
- hlist_for_each_safe(pos, next, &cache->hashtable[nr]) {
- struct rpc_cred *entry;
- entry = hlist_entry(pos, struct rpc_cred, cr_hash);
- if (entry->cr_ops->crmatch(acred, entry, flags)) {
- hlist_del(&entry->cr_hash);
- cred = entry;
- break;
+
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(entry, pos, &cache->hashtable[nr], cr_hash) {
+ if (!entry->cr_ops->crmatch(acred, entry, flags))
+ continue;
+ spin_lock(&cache->lock);
+ if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) {
+ spin_unlock(&cache->lock);
+ continue;
}
- rpcauth_prune_expired(auth, entry, &free);
- }
- if (new) {
- if (cred)
- hlist_add_head(&new->cr_hash, &free);
- else
- cred = new;
+ cred = get_rpccred(entry);
+ spin_unlock(&cache->lock);
+ break;
}
- if (cred) {
- hlist_add_head(&cred->cr_hash, &cache->hashtable[nr]);
- get_rpccred(cred);
- }
- spin_unlock(&rpc_credcache_lock);
+ rcu_read_unlock();
- rpcauth_destroy_credlist(&free);
+ if (cred != NULL)
+ goto found;
- if (!cred) {
- new = auth->au_ops->crcreate(auth, acred, flags);
- if (!IS_ERR(new)) {
-#ifdef RPC_DEBUG
- new->cr_magic = RPCAUTH_CRED_MAGIC;
-#endif
- goto retry;
- } else
- cred = new;
- } else if ((cred->cr_flags & RPCAUTH_CRED_NEW)
+ new = auth->au_ops->crcreate(auth, acred, flags);
+ if (IS_ERR(new)) {
+ cred = new;
+ goto out;
+ }
+
+ spin_lock(&cache->lock);
+ hlist_for_each_entry(entry, pos, &cache->hashtable[nr], cr_hash) {
+ if (!entry->cr_ops->crmatch(acred, entry, flags))
+ continue;
+ cred = get_rpccred(entry);
+ break;
+ }
+ if (cred == NULL) {
+ cred = new;
+ set_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags);
+ hlist_add_head_rcu(&cred->cr_hash, &cache->hashtable[nr]);
+ } else
+ list_add_tail(&new->cr_lru, &free);
+ spin_unlock(&cache->lock);
+found:
+ if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags)
&& cred->cr_ops->cr_init != NULL
&& !(flags & RPCAUTH_LOOKUP_NEW)) {
int res = cred->cr_ops->cr_init(auth, cred);
@@ -253,8 +328,9 @@ retry:
cred = ERR_PTR(res);
}
}
-
- return (struct rpc_cred *) cred;
+ rpcauth_destroy_credlist(&free);
+out:
+ return cred;
}
struct rpc_cred *
@@ -275,10 +351,27 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags)
return ret;
}
+void
+rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
+ struct rpc_auth *auth, const struct rpc_credops *ops)
+{
+ INIT_HLIST_NODE(&cred->cr_hash);
+ INIT_LIST_HEAD(&cred->cr_lru);
+ atomic_set(&cred->cr_count, 1);
+ cred->cr_auth = auth;
+ cred->cr_ops = ops;
+ cred->cr_expire = jiffies;
+#ifdef RPC_DEBUG
+ cred->cr_magic = RPCAUTH_CRED_MAGIC;
+#endif
+ cred->cr_uid = acred->uid;
+}
+EXPORT_SYMBOL(rpcauth_init_cred);
+
struct rpc_cred *
rpcauth_bindcred(struct rpc_task *task)
{
- struct rpc_auth *auth = task->tk_auth;
+ struct rpc_auth *auth = task->tk_client->cl_auth;
struct auth_cred acred = {
.uid = current->fsuid,
.gid = current->fsgid,
@@ -288,7 +381,7 @@ rpcauth_bindcred(struct rpc_task *task)
int flags = 0;
dprintk("RPC: %5u looking up %s cred\n",
- task->tk_pid, task->tk_auth->au_ops->au_name);
+ task->tk_pid, task->tk_client->cl_auth->au_ops->au_name);
get_group_info(acred.group_info);
if (task->tk_flags & RPC_TASK_ROOTCREDS)
flags |= RPCAUTH_LOOKUP_ROOTCREDS;
@@ -304,19 +397,42 @@ rpcauth_bindcred(struct rpc_task *task)
void
rpcauth_holdcred(struct rpc_task *task)
{
- dprintk("RPC: %5u holding %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name,
- task->tk_msg.rpc_cred);
- if (task->tk_msg.rpc_cred)
- get_rpccred(task->tk_msg.rpc_cred);
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+ if (cred != NULL) {
+ get_rpccred(cred);
+ dprintk("RPC: %5u holding %s cred %p\n", task->tk_pid,
+ cred->cr_auth->au_ops->au_name, cred);
+ }
}
void
put_rpccred(struct rpc_cred *cred)
{
- cred->cr_expire = jiffies;
+ /* Fast path for unhashed credentials */
+ if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
+ goto need_lock;
+
if (!atomic_dec_and_test(&cred->cr_count))
return;
+ goto out_destroy;
+need_lock:
+ if (!atomic_dec_and_lock(&cred->cr_count, &rpc_credcache_lock))
+ return;
+ if (!list_empty(&cred->cr_lru)) {
+ number_cred_unused--;
+ list_del_init(&cred->cr_lru);
+ }
+ if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0)
+ rpcauth_unhash_cred(cred);
+ else if (test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0) {
+ cred->cr_expire = jiffies;
+ list_add_tail(&cred->cr_lru, &cred_unused);
+ number_cred_unused++;
+ spin_unlock(&rpc_credcache_lock);
+ return;
+ }
+ spin_unlock(&rpc_credcache_lock);
+out_destroy:
cred->cr_ops->crdestroy(cred);
}
@@ -326,7 +442,7 @@ rpcauth_unbindcred(struct rpc_task *task)
struct rpc_cred *cred = task->tk_msg.rpc_cred;
dprintk("RPC: %5u releasing %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name, cred);
+ task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
put_rpccred(cred);
task->tk_msg.rpc_cred = NULL;
@@ -338,7 +454,7 @@ rpcauth_marshcred(struct rpc_task *task, __be32 *p)
struct rpc_cred *cred = task->tk_msg.rpc_cred;
dprintk("RPC: %5u marshaling %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name, cred);
+ task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
return cred->cr_ops->crmarshal(task, p);
}
@@ -349,7 +465,7 @@ rpcauth_checkverf(struct rpc_task *task, __be32 *p)
struct rpc_cred *cred = task->tk_msg.rpc_cred;
dprintk("RPC: %5u validating %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name, cred);
+ task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
return cred->cr_ops->crvalidate(task, p);
}
@@ -365,7 +481,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
if (cred->cr_ops->crwrap_req)
return cred->cr_ops->crwrap_req(task, encode, rqstp, data, obj);
/* By default, we encode the arguments normally. */
- return encode(rqstp, data, obj);
+ return rpc_call_xdrproc(encode, rqstp, data, obj);
}
int
@@ -380,7 +496,7 @@ rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
return cred->cr_ops->crunwrap_resp(task, decode, rqstp,
data, obj);
/* By default, we decode the arguments normally. */
- return decode(rqstp, data, obj);
+ return rpc_call_xdrproc(decode, rqstp, data, obj);
}
int
@@ -390,7 +506,7 @@ rpcauth_refreshcred(struct rpc_task *task)
int err;
dprintk("RPC: %5u refreshing %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name, cred);
+ task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
err = cred->cr_ops->crrefresh(task);
if (err < 0)
@@ -401,17 +517,35 @@ rpcauth_refreshcred(struct rpc_task *task)
void
rpcauth_invalcred(struct rpc_task *task)
{
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+
dprintk("RPC: %5u invalidating %s cred %p\n",
- task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
- spin_lock(&rpc_credcache_lock);
- if (task->tk_msg.rpc_cred)
- task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
- spin_unlock(&rpc_credcache_lock);
+ task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
+ if (cred)
+ clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
}
int
rpcauth_uptodatecred(struct rpc_task *task)
{
- return !(task->tk_msg.rpc_cred) ||
- (task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
+ struct rpc_cred *cred = task->tk_msg.rpc_cred;
+
+ return cred == NULL ||
+ test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) != 0;
+}
+
+static struct shrinker rpc_cred_shrinker = {
+ .shrink = rpcauth_cache_shrinker,
+ .seeks = DEFAULT_SEEKS,
+};
+
+void __init rpcauth_init_module(void)
+{
+ rpc_init_authunix();
+ register_shrinker(&rpc_cred_shrinker);
+}
+
+void __exit rpcauth_remove_module(void)
+{
+ unregister_shrinker(&rpc_cred_shrinker);
}
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 4e4ccc5b6fea..4bbc59cc237c 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -54,9 +54,10 @@
#include <linux/sunrpc/gss_api.h>
#include <asm/uaccess.h>
-static struct rpc_authops authgss_ops;
+static const struct rpc_authops authgss_ops;
-static struct rpc_credops gss_credops;
+static const struct rpc_credops gss_credops;
+static const struct rpc_credops gss_nullops;
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
@@ -64,7 +65,6 @@ static struct rpc_credops gss_credops;
#define NFS_NGROUPS 16
-#define GSS_CRED_EXPIRE (60 * HZ) /* XXX: reasonable? */
#define GSS_CRED_SLACK 1024 /* XXX: unused */
/* length of a krb5 verifier (48), plus data added before arguments when
* using integrity (two 4-byte integers): */
@@ -79,19 +79,16 @@ static struct rpc_credops gss_credops;
/* dump the buffer in `emacs-hexl' style */
#define isprint(c) ((c > 0x1f) && (c < 0x7f))
-static DEFINE_RWLOCK(gss_ctx_lock);
-
struct gss_auth {
+ struct kref kref;
struct rpc_auth rpc_auth;
struct gss_api_mech *mech;
enum rpc_gss_svc service;
- struct list_head upcalls;
struct rpc_clnt *client;
struct dentry *dentry;
- spinlock_t lock;
};
-static void gss_destroy_ctx(struct gss_cl_ctx *);
+static void gss_free_ctx(struct gss_cl_ctx *);
static struct rpc_pipe_ops gss_upcall_ops;
static inline struct gss_cl_ctx *
@@ -105,20 +102,24 @@ static inline void
gss_put_ctx(struct gss_cl_ctx *ctx)
{
if (atomic_dec_and_test(&ctx->count))
- gss_destroy_ctx(ctx);
+ gss_free_ctx(ctx);
}
+/* gss_cred_set_ctx:
+ * called by gss_upcall_callback and gss_create_upcall in order
+ * to set the gss context. The actual exchange of an old context
+ * and a new one is protected by the inode->i_lock.
+ */
static void
gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
{
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *old;
- write_lock(&gss_ctx_lock);
+
old = gss_cred->gc_ctx;
- gss_cred->gc_ctx = ctx;
- cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
- cred->cr_flags &= ~RPCAUTH_CRED_NEW;
- write_unlock(&gss_ctx_lock);
+ rcu_assign_pointer(gss_cred->gc_ctx, ctx);
+ set_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+ clear_bit(RPCAUTH_CRED_NEW, &cred->cr_flags);
if (old)
gss_put_ctx(old);
}
@@ -129,10 +130,10 @@ gss_cred_is_uptodate_ctx(struct rpc_cred *cred)
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
int res = 0;
- read_lock(&gss_ctx_lock);
- if ((cred->cr_flags & RPCAUTH_CRED_UPTODATE) && gss_cred->gc_ctx)
+ rcu_read_lock();
+ if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) && gss_cred->gc_ctx)
res = 1;
- read_unlock(&gss_ctx_lock);
+ rcu_read_unlock();
return res;
}
@@ -171,10 +172,10 @@ gss_cred_get_ctx(struct rpc_cred *cred)
struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
struct gss_cl_ctx *ctx = NULL;
- read_lock(&gss_ctx_lock);
+ rcu_read_lock();
if (gss_cred->gc_ctx)
ctx = gss_get_ctx(gss_cred->gc_ctx);
- read_unlock(&gss_ctx_lock);
+ rcu_read_unlock();
return ctx;
}
@@ -269,10 +270,10 @@ gss_release_msg(struct gss_upcall_msg *gss_msg)
}
static struct gss_upcall_msg *
-__gss_find_upcall(struct gss_auth *gss_auth, uid_t uid)
+__gss_find_upcall(struct rpc_inode *rpci, uid_t uid)
{
struct gss_upcall_msg *pos;
- list_for_each_entry(pos, &gss_auth->upcalls, list) {
+ list_for_each_entry(pos, &rpci->in_downcall, list) {
if (pos->uid != uid)
continue;
atomic_inc(&pos->count);
@@ -290,24 +291,24 @@ __gss_find_upcall(struct gss_auth *gss_auth, uid_t uid)
static inline struct gss_upcall_msg *
gss_add_msg(struct gss_auth *gss_auth, struct gss_upcall_msg *gss_msg)
{
+ struct inode *inode = gss_auth->dentry->d_inode;
+ struct rpc_inode *rpci = RPC_I(inode);
struct gss_upcall_msg *old;
- spin_lock(&gss_auth->lock);
- old = __gss_find_upcall(gss_auth, gss_msg->uid);
+ spin_lock(&inode->i_lock);
+ old = __gss_find_upcall(rpci, gss_msg->uid);
if (old == NULL) {
atomic_inc(&gss_msg->count);
- list_add(&gss_msg->list, &gss_auth->upcalls);
+ list_add(&gss_msg->list, &rpci->in_downcall);
} else
gss_msg = old;
- spin_unlock(&gss_auth->lock);
+ spin_unlock(&inode->i_lock);
return gss_msg;
}
static void
__gss_unhash_msg(struct gss_upcall_msg *gss_msg)
{
- if (list_empty(&gss_msg->list))
- return;
list_del_init(&gss_msg->list);
rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
wake_up_all(&gss_msg->waitqueue);
@@ -318,10 +319,14 @@ static void
gss_unhash_msg(struct gss_upcall_msg *gss_msg)
{
struct gss_auth *gss_auth = gss_msg->auth;
+ struct inode *inode = gss_auth->dentry->d_inode;
- spin_lock(&gss_auth->lock);
- __gss_unhash_msg(gss_msg);
- spin_unlock(&gss_auth->lock);
+ if (list_empty(&gss_msg->list))
+ return;
+ spin_lock(&inode->i_lock);
+ if (!list_empty(&gss_msg->list))
+ __gss_unhash_msg(gss_msg);
+ spin_unlock(&inode->i_lock);
}
static void
@@ -330,16 +335,16 @@ gss_upcall_callback(struct rpc_task *task)
struct gss_cred *gss_cred = container_of(task->tk_msg.rpc_cred,
struct gss_cred, gc_base);
struct gss_upcall_msg *gss_msg = gss_cred->gc_upcall;
+ struct inode *inode = gss_msg->auth->dentry->d_inode;
- BUG_ON(gss_msg == NULL);
+ spin_lock(&inode->i_lock);
if (gss_msg->ctx)
gss_cred_set_ctx(task->tk_msg.rpc_cred, gss_get_ctx(gss_msg->ctx));
else
task->tk_status = gss_msg->msg.errno;
- spin_lock(&gss_msg->auth->lock);
gss_cred->gc_upcall = NULL;
rpc_wake_up_status(&gss_msg->rpc_waitqueue, gss_msg->msg.errno);
- spin_unlock(&gss_msg->auth->lock);
+ spin_unlock(&inode->i_lock);
gss_release_msg(gss_msg);
}
@@ -386,11 +391,12 @@ static inline int
gss_refresh_upcall(struct rpc_task *task)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
- struct gss_auth *gss_auth = container_of(task->tk_client->cl_auth,
+ struct gss_auth *gss_auth = container_of(cred->cr_auth,
struct gss_auth, rpc_auth);
struct gss_cred *gss_cred = container_of(cred,
struct gss_cred, gc_base);
struct gss_upcall_msg *gss_msg;
+ struct inode *inode = gss_auth->dentry->d_inode;
int err = 0;
dprintk("RPC: %5u gss_refresh_upcall for uid %u\n", task->tk_pid,
@@ -400,7 +406,7 @@ gss_refresh_upcall(struct rpc_task *task)
err = PTR_ERR(gss_msg);
goto out;
}
- spin_lock(&gss_auth->lock);
+ spin_lock(&inode->i_lock);
if (gss_cred->gc_upcall != NULL)
rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL);
else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) {
@@ -411,7 +417,7 @@ gss_refresh_upcall(struct rpc_task *task)
rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL);
} else
err = gss_msg->msg.errno;
- spin_unlock(&gss_auth->lock);
+ spin_unlock(&inode->i_lock);
gss_release_msg(gss_msg);
out:
dprintk("RPC: %5u gss_refresh_upcall for uid %u result %d\n",
@@ -422,6 +428,7 @@ out:
static inline int
gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
{
+ struct inode *inode = gss_auth->dentry->d_inode;
struct rpc_cred *cred = &gss_cred->gc_base;
struct gss_upcall_msg *gss_msg;
DEFINE_WAIT(wait);
@@ -435,12 +442,11 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
}
for (;;) {
prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE);
- spin_lock(&gss_auth->lock);
+ spin_lock(&inode->i_lock);
if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) {
- spin_unlock(&gss_auth->lock);
break;
}
- spin_unlock(&gss_auth->lock);
+ spin_unlock(&inode->i_lock);
if (signalled()) {
err = -ERESTARTSYS;
goto out_intr;
@@ -451,6 +457,7 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx));
else
err = gss_msg->msg.errno;
+ spin_unlock(&inode->i_lock);
out_intr:
finish_wait(&gss_msg->waitqueue, &wait);
gss_release_msg(gss_msg);
@@ -489,12 +496,11 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
const void *p, *end;
void *buf;
struct rpc_clnt *clnt;
- struct gss_auth *gss_auth;
- struct rpc_cred *cred;
struct gss_upcall_msg *gss_msg;
+ struct inode *inode = filp->f_path.dentry->d_inode;
struct gss_cl_ctx *ctx;
uid_t uid;
- int err = -EFBIG;
+ ssize_t err = -EFBIG;
if (mlen > MSG_BUF_MAXSIZE)
goto out;
@@ -503,7 +509,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
if (!buf)
goto out;
- clnt = RPC_I(filp->f_path.dentry->d_inode)->private;
+ clnt = RPC_I(inode)->private;
err = -EFAULT;
if (copy_from_user(buf, src, mlen))
goto err;
@@ -519,43 +525,38 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
ctx = gss_alloc_context();
if (ctx == NULL)
goto err;
- err = 0;
- gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth);
- p = gss_fill_context(p, end, ctx, gss_auth->mech);
+
+ err = -ENOENT;
+ /* Find a matching upcall */
+ spin_lock(&inode->i_lock);
+ gss_msg = __gss_find_upcall(RPC_I(inode), uid);
+ if (gss_msg == NULL) {
+ spin_unlock(&inode->i_lock);
+ goto err_put_ctx;
+ }
+ list_del_init(&gss_msg->list);
+ spin_unlock(&inode->i_lock);
+
+ p = gss_fill_context(p, end, ctx, gss_msg->auth->mech);
if (IS_ERR(p)) {
err = PTR_ERR(p);
- if (err != -EACCES)
- goto err_put_ctx;
- }
- spin_lock(&gss_auth->lock);
- gss_msg = __gss_find_upcall(gss_auth, uid);
- if (gss_msg) {
- if (err == 0 && gss_msg->ctx == NULL)
- gss_msg->ctx = gss_get_ctx(ctx);
- gss_msg->msg.errno = err;
- __gss_unhash_msg(gss_msg);
- spin_unlock(&gss_auth->lock);
- gss_release_msg(gss_msg);
- } else {
- struct auth_cred acred = { .uid = uid };
- spin_unlock(&gss_auth->lock);
- cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW);
- if (IS_ERR(cred)) {
- err = PTR_ERR(cred);
- goto err_put_ctx;
- }
- gss_cred_set_ctx(cred, gss_get_ctx(ctx));
+ gss_msg->msg.errno = (err == -EACCES) ? -EACCES : -EAGAIN;
+ goto err_release_msg;
}
- gss_put_ctx(ctx);
- kfree(buf);
- dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen);
- return mlen;
+ gss_msg->ctx = gss_get_ctx(ctx);
+ err = mlen;
+
+err_release_msg:
+ spin_lock(&inode->i_lock);
+ __gss_unhash_msg(gss_msg);
+ spin_unlock(&inode->i_lock);
+ gss_release_msg(gss_msg);
err_put_ctx:
gss_put_ctx(ctx);
err:
kfree(buf);
out:
- dprintk("RPC: gss_pipe_downcall returning %d\n", err);
+ dprintk("RPC: gss_pipe_downcall returning %Zd\n", err);
return err;
}
@@ -563,27 +564,21 @@ static void
gss_pipe_release(struct inode *inode)
{
struct rpc_inode *rpci = RPC_I(inode);
- struct rpc_clnt *clnt;
- struct rpc_auth *auth;
- struct gss_auth *gss_auth;
+ struct gss_upcall_msg *gss_msg;
- clnt = rpci->private;
- auth = clnt->cl_auth;
- gss_auth = container_of(auth, struct gss_auth, rpc_auth);
- spin_lock(&gss_auth->lock);
- while (!list_empty(&gss_auth->upcalls)) {
- struct gss_upcall_msg *gss_msg;
+ spin_lock(&inode->i_lock);
+ while (!list_empty(&rpci->in_downcall)) {
- gss_msg = list_entry(gss_auth->upcalls.next,
+ gss_msg = list_entry(rpci->in_downcall.next,
struct gss_upcall_msg, list);
gss_msg->msg.errno = -EPIPE;
atomic_inc(&gss_msg->count);
__gss_unhash_msg(gss_msg);
- spin_unlock(&gss_auth->lock);
+ spin_unlock(&inode->i_lock);
gss_release_msg(gss_msg);
- spin_lock(&gss_auth->lock);
+ spin_lock(&inode->i_lock);
}
- spin_unlock(&gss_auth->lock);
+ spin_unlock(&inode->i_lock);
}
static void
@@ -637,18 +632,13 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
if (gss_auth->service == 0)
goto err_put_mech;
- INIT_LIST_HEAD(&gss_auth->upcalls);
- spin_lock_init(&gss_auth->lock);
auth = &gss_auth->rpc_auth;
auth->au_cslack = GSS_CRED_SLACK >> 2;
auth->au_rslack = GSS_VERF_SLACK >> 2;
auth->au_ops = &authgss_ops;
auth->au_flavor = flavor;
atomic_set(&auth->au_count, 1);
-
- err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE);
- if (err)
- goto err_put_mech;
+ kref_init(&gss_auth->kref);
gss_auth->dentry = rpc_mkpipe(clnt->cl_dentry, gss_auth->mech->gm_name,
clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
@@ -657,7 +647,13 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
goto err_put_mech;
}
+ err = rpcauth_init_credcache(auth);
+ if (err)
+ goto err_unlink_pipe;
+
return auth;
+err_unlink_pipe:
+ rpc_unlink(gss_auth->dentry);
err_put_mech:
gss_mech_put(gss_auth->mech);
err_free:
@@ -668,6 +664,25 @@ out_dec:
}
static void
+gss_free(struct gss_auth *gss_auth)
+{
+ rpc_unlink(gss_auth->dentry);
+ gss_auth->dentry = NULL;
+ gss_mech_put(gss_auth->mech);
+
+ kfree(gss_auth);
+ module_put(THIS_MODULE);
+}
+
+static void
+gss_free_callback(struct kref *kref)
+{
+ struct gss_auth *gss_auth = container_of(kref, struct gss_auth, kref);
+
+ gss_free(gss_auth);
+}
+
+static void
gss_destroy(struct rpc_auth *auth)
{
struct gss_auth *gss_auth;
@@ -675,23 +690,51 @@ gss_destroy(struct rpc_auth *auth)
dprintk("RPC: destroying GSS authenticator %p flavor %d\n",
auth, auth->au_flavor);
+ rpcauth_destroy_credcache(auth);
+
gss_auth = container_of(auth, struct gss_auth, rpc_auth);
- rpc_unlink(gss_auth->dentry);
- gss_auth->dentry = NULL;
- gss_mech_put(gss_auth->mech);
+ kref_put(&gss_auth->kref, gss_free_callback);
+}
- rpcauth_free_credcache(auth);
- kfree(gss_auth);
- module_put(THIS_MODULE);
+/*
+ * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call
+ * to the server with the GSS control procedure field set to
+ * RPC_GSS_PROC_DESTROY. This should normally cause the server to release
+ * all RPCSEC_GSS state associated with that context.
+ */
+static int
+gss_destroying_context(struct rpc_cred *cred)
+{
+ struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
+ struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
+ struct rpc_task *task;
+
+ if (gss_cred->gc_ctx == NULL ||
+ gss_cred->gc_ctx->gc_proc == RPC_GSS_PROC_DESTROY)
+ return 0;
+
+ gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY;
+ cred->cr_ops = &gss_nullops;
+
+ /* Take a reference to ensure the cred will be destroyed either
+ * by the RPC call or by the put_rpccred() below */
+ get_rpccred(cred);
+
+ task = rpc_call_null(gss_auth->client, cred, RPC_TASK_ASYNC);
+ if (!IS_ERR(task))
+ rpc_put_task(task);
+
+ put_rpccred(cred);
+ return 1;
}
-/* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure
+/* gss_destroy_cred (and gss_free_ctx) are used to clean up after failure
* to create a new cred or context, so they check that things have been
* allocated before freeing them. */
static void
-gss_destroy_ctx(struct gss_cl_ctx *ctx)
+gss_do_free_ctx(struct gss_cl_ctx *ctx)
{
- dprintk("RPC: gss_destroy_ctx\n");
+ dprintk("RPC: gss_free_ctx\n");
if (ctx->gc_gss_ctx)
gss_delete_sec_context(&ctx->gc_gss_ctx);
@@ -701,15 +744,46 @@ gss_destroy_ctx(struct gss_cl_ctx *ctx)
}
static void
-gss_destroy_cred(struct rpc_cred *rc)
+gss_free_ctx_callback(struct rcu_head *head)
{
- struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base);
+ struct gss_cl_ctx *ctx = container_of(head, struct gss_cl_ctx, gc_rcu);
+ gss_do_free_ctx(ctx);
+}
- dprintk("RPC: gss_destroy_cred \n");
+static void
+gss_free_ctx(struct gss_cl_ctx *ctx)
+{
+ call_rcu(&ctx->gc_rcu, gss_free_ctx_callback);
+}
- if (cred->gc_ctx)
- gss_put_ctx(cred->gc_ctx);
- kfree(cred);
+static void
+gss_free_cred(struct gss_cred *gss_cred)
+{
+ dprintk("RPC: gss_free_cred %p\n", gss_cred);
+ kfree(gss_cred);
+}
+
+static void
+gss_free_cred_callback(struct rcu_head *head)
+{
+ struct gss_cred *gss_cred = container_of(head, struct gss_cred, gc_base.cr_rcu);
+ gss_free_cred(gss_cred);
+}
+
+static void
+gss_destroy_cred(struct rpc_cred *cred)
+{
+ struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base);
+ struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth);
+ struct gss_cl_ctx *ctx = gss_cred->gc_ctx;
+
+ if (gss_destroying_context(cred))
+ return;
+ rcu_assign_pointer(gss_cred->gc_ctx, NULL);
+ call_rcu(&cred->cr_rcu, gss_free_cred_callback);
+ if (ctx)
+ gss_put_ctx(ctx);
+ kref_put(&gss_auth->kref, gss_free_callback);
}
/*
@@ -734,16 +808,14 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
if (!(cred = kzalloc(sizeof(*cred), GFP_KERNEL)))
goto out_err;
- atomic_set(&cred->gc_count, 1);
- cred->gc_uid = acred->uid;
+ rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops);
/*
* Note: in order to force a call to call_refresh(), we deliberately
* fail to flag the credential as RPCAUTH_CRED_UPTODATE.
*/
- cred->gc_flags = 0;
- cred->gc_base.cr_ops = &gss_credops;
- cred->gc_base.cr_flags = RPCAUTH_CRED_NEW;
+ cred->gc_base.cr_flags = 1UL << RPCAUTH_CRED_NEW;
cred->gc_service = gss_auth->service;
+ kref_get(&gss_auth->kref);
return &cred->gc_base;
out_err:
@@ -774,7 +846,7 @@ gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
* we don't really care if the credential has expired or not,
* since the caller should be prepared to reinitialise it.
*/
- if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW))
+ if ((flags & RPCAUTH_LOOKUP_NEW) && test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
goto out;
/* Don't match with creds that have expired. */
if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
@@ -830,7 +902,7 @@ gss_marshal(struct rpc_task *task, __be32 *p)
mic.data = (u8 *)(p + 1);
maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
- cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+ clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
} else if (maj_stat != 0) {
printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat);
goto out_put_ctx;
@@ -855,6 +927,13 @@ gss_refresh(struct rpc_task *task)
return 0;
}
+/* Dummy refresh routine: used only when destroying the context */
+static int
+gss_refresh_null(struct rpc_task *task)
+{
+ return -EACCES;
+}
+
static __be32 *
gss_validate(struct rpc_task *task, __be32 *p)
{
@@ -883,12 +962,15 @@ gss_validate(struct rpc_task *task, __be32 *p)
maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
- cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
- if (maj_stat)
+ clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
+ if (maj_stat) {
+ dprintk("RPC: %5u gss_validate: gss_verify_mic returned"
+ "error 0x%08x\n", task->tk_pid, maj_stat);
goto out_bad;
+ }
/* We leave it to unwrap to calculate au_rslack. For now we just
* calculate the length of the verifier: */
- task->tk_auth->au_verfsize = XDR_QUADLEN(len) + 2;
+ cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2;
gss_put_ctx(ctx);
dprintk("RPC: %5u gss_validate: gss_verify_mic succeeded.\n",
task->tk_pid);
@@ -917,7 +999,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
*p++ = htonl(rqstp->rq_seqno);
- status = encode(rqstp, p, obj);
+ status = rpc_call_xdrproc(encode, rqstp, p, obj);
if (status)
return status;
@@ -937,7 +1019,7 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
maj_stat = gss_get_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
status = -EIO; /* XXX? */
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
- cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+ clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
else if (maj_stat)
return status;
q = xdr_encode_opaque(p, NULL, mic.len);
@@ -1011,7 +1093,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
*p++ = htonl(rqstp->rq_seqno);
- status = encode(rqstp, p, obj);
+ status = rpc_call_xdrproc(encode, rqstp, p, obj);
if (status)
return status;
@@ -1036,7 +1118,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
/* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was
* done anyway, so it's safe to put the request on the wire: */
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
- cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+ clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
else if (maj_stat)
return status;
@@ -1070,12 +1152,12 @@ gss_wrap_req(struct rpc_task *task,
/* The spec seems a little ambiguous here, but I think that not
* wrapping context destruction requests makes the most sense.
*/
- status = encode(rqstp, p, obj);
+ status = rpc_call_xdrproc(encode, rqstp, p, obj);
goto out;
}
switch (gss_cred->gc_service) {
case RPC_GSS_SVC_NONE:
- status = encode(rqstp, p, obj);
+ status = rpc_call_xdrproc(encode, rqstp, p, obj);
break;
case RPC_GSS_SVC_INTEGRITY:
status = gss_wrap_req_integ(cred, ctx, encode,
@@ -1123,7 +1205,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic);
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
- cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+ clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
if (maj_stat != GSS_S_COMPLETE)
return status;
return 0;
@@ -1148,7 +1230,7 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf);
if (maj_stat == GSS_S_CONTEXT_EXPIRED)
- cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+ clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
if (maj_stat != GSS_S_COMPLETE)
return status;
if (ntohl(*(*p)++) != rqstp->rq_seqno)
@@ -1188,10 +1270,10 @@ gss_unwrap_resp(struct rpc_task *task,
break;
}
/* take into account extra slack for integrity and privacy cases: */
- task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp)
+ cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp)
+ (savedlen - head->iov_len);
out_decode:
- status = decode(rqstp, p, obj);
+ status = rpc_call_xdrproc(decode, rqstp, p, obj);
out:
gss_put_ctx(ctx);
dprintk("RPC: %5u gss_unwrap_resp returning %d\n", task->tk_pid,
@@ -1199,7 +1281,7 @@ out:
return status;
}
-static struct rpc_authops authgss_ops = {
+static const struct rpc_authops authgss_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_GSS,
#ifdef RPC_DEBUG
@@ -1211,7 +1293,7 @@ static struct rpc_authops authgss_ops = {
.crcreate = gss_create_cred
};
-static struct rpc_credops gss_credops = {
+static const struct rpc_credops gss_credops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
.cr_init = gss_cred_init,
@@ -1223,6 +1305,17 @@ static struct rpc_credops gss_credops = {
.crunwrap_resp = gss_unwrap_resp,
};
+static const struct rpc_credops gss_nullops = {
+ .cr_name = "AUTH_GSS",
+ .crdestroy = gss_destroy_cred,
+ .crmatch = gss_match,
+ .crmarshal = gss_marshal,
+ .crrefresh = gss_refresh_null,
+ .crvalidate = gss_validate,
+ .crwrap_req = gss_wrap_req,
+ .crunwrap_resp = gss_unwrap_resp,
+};
+
static struct rpc_pipe_ops gss_upcall_ops = {
.upcall = gss_pipe_upcall,
.downcall = gss_pipe_downcall,
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index f441aa0b26dc..bfb6a29633dd 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -67,7 +67,7 @@ krb5_encrypt(
if (crypto_blkcipher_ivsize(tfm) > 16) {
dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
- crypto_blkcipher_ivsize(tfm));
+ crypto_blkcipher_ivsize(tfm));
goto out;
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 7b1943217053..9843eacef11d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -201,7 +201,7 @@ gss_delete_sec_context_kerberos(void *internal_ctx) {
kfree(kctx);
}
-static struct gss_api_ops gss_kerberos_ops = {
+static const struct gss_api_ops gss_kerberos_ops = {
.gss_import_sec_context = gss_import_sec_context_kerberos,
.gss_get_mic = gss_get_mic_kerberos,
.gss_verify_mic = gss_verify_mic_kerberos,
@@ -231,6 +231,7 @@ static struct pf_desc gss_kerberos_pfs[] = {
static struct gss_api_mech gss_kerberos_mech = {
.gm_name = "krb5",
.gm_owner = THIS_MODULE,
+ .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"},
.gm_ops = &gss_kerberos_ops,
.gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
.gm_pfs = gss_kerberos_pfs,
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index 26872517ccf3..61801a069ff0 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -194,6 +194,20 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor);
u32
+gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
+{
+ int i;
+
+ for (i = 0; i < gm->gm_pf_num; i++) {
+ if (gm->gm_pfs[i].service == service) {
+ return gm->gm_pfs[i].pseudoflavor;
+ }
+ }
+ return RPC_AUTH_MAXFLAVOR; /* illegal value */
+}
+EXPORT_SYMBOL(gss_svc_to_pseudoflavor);
+
+u32
gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
{
int i;
diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
index 7e15aa68ae64..5deb4b6e4514 100644
--- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
+++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
@@ -202,7 +202,7 @@ gss_get_mic_spkm3(struct gss_ctx *ctx,
return err;
}
-static struct gss_api_ops gss_spkm3_ops = {
+static const struct gss_api_ops gss_spkm3_ops = {
.gss_import_sec_context = gss_import_sec_context_spkm3,
.gss_get_mic = gss_get_mic_spkm3,
.gss_verify_mic = gss_verify_mic_spkm3,
@@ -217,6 +217,7 @@ static struct pf_desc gss_spkm3_pfs[] = {
static struct gss_api_mech gss_spkm3_mech = {
.gm_name = "spkm3",
.gm_owner = THIS_MODULE,
+ .gm_oid = {7, "\053\006\001\005\005\001\003"},
.gm_ops = &gss_spkm3_ops,
.gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs),
.gm_pfs = gss_spkm3_pfs,
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index c094583386fd..490697542fc2 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -743,6 +743,15 @@ find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
static struct auth_ops svcauthops_gss;
+u32 svcauth_gss_flavor(struct auth_domain *dom)
+{
+ struct gss_domain *gd = container_of(dom, struct gss_domain, h);
+
+ return gd->pseudoflavor;
+}
+
+EXPORT_SYMBOL(svcauth_gss_flavor);
+
int
svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
{
@@ -913,10 +922,23 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
struct gss_svc_data *svcdata = rqstp->rq_auth_data;
struct rsc *rsci = svcdata->rsci;
struct rpc_gss_wire_cred *gc = &svcdata->clcred;
+ int stat;
- rqstp->rq_client = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
- if (rqstp->rq_client == NULL)
+ /*
+ * A gss export can be specified either by:
+ * export *(sec=krb5,rw)
+ * or by
+ * export gss/krb5(rw)
+ * The latter is deprecated; but for backwards compatibility reasons
+ * the nfsd code will still fall back on trying it if the former
+ * doesn't work; so we try to make both available to nfsd, below.
+ */
+ rqstp->rq_gssclient = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
+ if (rqstp->rq_gssclient == NULL)
return SVC_DENIED;
+ stat = svcauth_unix_set_client(rqstp);
+ if (stat == SVC_DROP)
+ return stat;
return SVC_OK;
}
@@ -1088,7 +1110,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
svc_putnl(resv, GSS_SEQ_WIN);
if (svc_safe_putnetobj(resv, &rsip->out_token))
goto drop;
- rqstp->rq_client = NULL;
}
goto complete;
case RPC_GSS_PROC_DESTROY:
@@ -1131,6 +1152,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
}
svcdata->rsci = rsci;
cache_get(&rsci->h);
+ rqstp->rq_flavor = gss_svc_to_pseudoflavor(
+ rsci->mechctx->mech_type, gc->gc_svc);
ret = SVC_OK;
goto out;
}
@@ -1317,6 +1340,9 @@ out_err:
if (rqstp->rq_client)
auth_domain_put(rqstp->rq_client);
rqstp->rq_client = NULL;
+ if (rqstp->rq_gssclient)
+ auth_domain_put(rqstp->rq_gssclient);
+ rqstp->rq_gssclient = NULL;
if (rqstp->rq_cred.cr_group_info)
put_group_info(rqstp->rq_cred.cr_group_info);
rqstp->rq_cred.cr_group_info = NULL;
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index 3df9fccab2f8..537d0e8589dd 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -76,7 +76,7 @@ nul_marshal(struct rpc_task *task, __be32 *p)
static int
nul_refresh(struct rpc_task *task)
{
- task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+ set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
return 0;
}
@@ -101,7 +101,7 @@ nul_validate(struct rpc_task *task, __be32 *p)
return p;
}
-struct rpc_authops authnull_ops = {
+const struct rpc_authops authnull_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_NULL,
#ifdef RPC_DEBUG
@@ -122,7 +122,7 @@ struct rpc_auth null_auth = {
};
static
-struct rpc_credops null_credops = {
+const struct rpc_credops null_credops = {
.cr_name = "AUTH_NULL",
.crdestroy = nul_destroy_cred,
.crmatch = nul_match,
@@ -133,9 +133,11 @@ struct rpc_credops null_credops = {
static
struct rpc_cred null_cred = {
+ .cr_lru = LIST_HEAD_INIT(null_cred.cr_lru),
+ .cr_auth = &null_auth,
.cr_ops = &null_credops,
.cr_count = ATOMIC_INIT(1),
- .cr_flags = RPCAUTH_CRED_UPTODATE,
+ .cr_flags = 1UL << RPCAUTH_CRED_UPTODATE,
#ifdef RPC_DEBUG
.cr_magic = RPCAUTH_CRED_MAGIC,
#endif
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 4e7733aee36e..5ed91e5bcee4 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -20,11 +20,6 @@ struct unx_cred {
gid_t uc_gids[NFS_NGROUPS];
};
#define uc_uid uc_base.cr_uid
-#define uc_count uc_base.cr_count
-#define uc_flags uc_base.cr_flags
-#define uc_expire uc_base.cr_expire
-
-#define UNX_CRED_EXPIRE (60 * HZ)
#define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2))
@@ -34,15 +29,14 @@ struct unx_cred {
static struct rpc_auth unix_auth;
static struct rpc_cred_cache unix_cred_cache;
-static struct rpc_credops unix_credops;
+static const struct rpc_credops unix_credops;
static struct rpc_auth *
unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
{
dprintk("RPC: creating UNIX authenticator for client %p\n",
clnt);
- if (atomic_inc_return(&unix_auth.au_count) == 0)
- unix_cred_cache.nextgc = jiffies + (unix_cred_cache.expire >> 1);
+ atomic_inc(&unix_auth.au_count);
return &unix_auth;
}
@@ -50,7 +44,7 @@ static void
unx_destroy(struct rpc_auth *auth)
{
dprintk("RPC: destroying UNIX authenticator %p\n", auth);
- rpcauth_free_credcache(auth);
+ rpcauth_clear_credcache(auth->au_credcache);
}
/*
@@ -74,8 +68,8 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
return ERR_PTR(-ENOMEM);
- atomic_set(&cred->uc_count, 1);
- cred->uc_flags = RPCAUTH_CRED_UPTODATE;
+ rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
+ cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
if (flags & RPCAUTH_LOOKUP_ROOTCREDS) {
cred->uc_uid = 0;
cred->uc_gid = 0;
@@ -85,22 +79,34 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
if (groups > NFS_NGROUPS)
groups = NFS_NGROUPS;
- cred->uc_uid = acred->uid;
cred->uc_gid = acred->gid;
for (i = 0; i < groups; i++)
cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
if (i < NFS_NGROUPS)
cred->uc_gids[i] = NOGROUP;
}
- cred->uc_base.cr_ops = &unix_credops;
- return (struct rpc_cred *) cred;
+ return &cred->uc_base;
+}
+
+static void
+unx_free_cred(struct unx_cred *unx_cred)
+{
+ dprintk("RPC: unx_free_cred %p\n", unx_cred);
+ kfree(unx_cred);
+}
+
+static void
+unx_free_cred_callback(struct rcu_head *head)
+{
+ struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu);
+ unx_free_cred(unx_cred);
}
static void
unx_destroy_cred(struct rpc_cred *cred)
{
- kfree(cred);
+ call_rcu(&cred->cr_rcu, unx_free_cred_callback);
}
/*
@@ -111,7 +117,7 @@ unx_destroy_cred(struct rpc_cred *cred)
static int
unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
{
- struct unx_cred *cred = (struct unx_cred *) rcred;
+ struct unx_cred *cred = container_of(rcred, struct unx_cred, uc_base);
int i;
if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) {
@@ -142,7 +148,7 @@ static __be32 *
unx_marshal(struct rpc_task *task, __be32 *p)
{
struct rpc_clnt *clnt = task->tk_client;
- struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred;
+ struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base);
__be32 *base, *hold;
int i;
@@ -175,7 +181,7 @@ unx_marshal(struct rpc_task *task, __be32 *p)
static int
unx_refresh(struct rpc_task *task)
{
- task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+ set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
return 0;
}
@@ -198,13 +204,18 @@ unx_validate(struct rpc_task *task, __be32 *p)
printk("RPC: giant verf size: %u\n", size);
return NULL;
}
- task->tk_auth->au_rslack = (size >> 2) + 2;
+ task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2;
p += (size >> 2);
return p;
}
-struct rpc_authops authunix_ops = {
+void __init rpc_init_authunix(void)
+{
+ spin_lock_init(&unix_cred_cache.lock);
+}
+
+const struct rpc_authops authunix_ops = {
.owner = THIS_MODULE,
.au_flavor = RPC_AUTH_UNIX,
#ifdef RPC_DEBUG
@@ -218,7 +229,6 @@ struct rpc_authops authunix_ops = {
static
struct rpc_cred_cache unix_cred_cache = {
- .expire = UNX_CRED_EXPIRE,
};
static
@@ -232,7 +242,7 @@ struct rpc_auth unix_auth = {
};
static
-struct rpc_credops unix_credops = {
+const struct rpc_credops unix_credops = {
.cr_name = "AUTH_UNIX",
.crdestroy = unx_destroy_cred,
.crmatch = unx_match,
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 543b085ae2c1..01c3c4105204 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -1210,7 +1210,7 @@ static int c_show(struct seq_file *m, void *p)
return cd->cache_show(m, cd, cp);
}
-static struct seq_operations cache_content_op = {
+static const struct seq_operations cache_content_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index d8fbee40a19c..52429b1ffcc1 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -44,6 +44,12 @@
dprintk("RPC: %5u %s (status %d)\n", t->tk_pid, \
__FUNCTION__, t->tk_status)
+/*
+ * All RPC clients are linked into this list
+ */
+static LIST_HEAD(all_clients);
+static DEFINE_SPINLOCK(rpc_client_lock);
+
static DECLARE_WAIT_QUEUE_HEAD(destroy_wait);
@@ -66,6 +72,21 @@ static void call_connect_status(struct rpc_task *task);
static __be32 * call_header(struct rpc_task *task);
static __be32 * call_verify(struct rpc_task *task);
+static int rpc_ping(struct rpc_clnt *clnt, int flags);
+
+static void rpc_register_client(struct rpc_clnt *clnt)
+{
+ spin_lock(&rpc_client_lock);
+ list_add(&clnt->cl_clients, &all_clients);
+ spin_unlock(&rpc_client_lock);
+}
+
+static void rpc_unregister_client(struct rpc_clnt *clnt)
+{
+ spin_lock(&rpc_client_lock);
+ list_del(&clnt->cl_clients);
+ spin_unlock(&rpc_client_lock);
+}
static int
rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
@@ -111,6 +132,9 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
dprintk("RPC: creating %s client for %s (xprt %p)\n",
program->name, servname, xprt);
+ err = rpciod_up();
+ if (err)
+ goto out_no_rpciod;
err = -EINVAL;
if (!xprt)
goto out_no_xprt;
@@ -121,8 +145,6 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
if (!clnt)
goto out_err;
- atomic_set(&clnt->cl_users, 0);
- atomic_set(&clnt->cl_count, 1);
clnt->cl_parent = clnt;
clnt->cl_server = clnt->cl_inline_name;
@@ -148,6 +170,8 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
if (clnt->cl_metrics == NULL)
goto out_no_stats;
clnt->cl_program = program;
+ INIT_LIST_HEAD(&clnt->cl_tasks);
+ spin_lock_init(&clnt->cl_lock);
if (!xprt_bound(clnt->cl_xprt))
clnt->cl_autobind = 1;
@@ -155,6 +179,8 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
clnt->cl_rtt = &clnt->cl_rtt_default;
rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval);
+ kref_init(&clnt->cl_kref);
+
err = rpc_setup_pipedir(clnt, program->pipe_dir_name);
if (err < 0)
goto out_no_path;
@@ -172,6 +198,7 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
if (clnt->cl_nodelen > UNX_MAXNODENAME)
clnt->cl_nodelen = UNX_MAXNODENAME;
memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen);
+ rpc_register_client(clnt);
return clnt;
out_no_auth:
@@ -188,6 +215,8 @@ out_no_stats:
out_err:
xprt_put(xprt);
out_no_xprt:
+ rpciod_down();
+out_no_rpciod:
return ERR_PTR(err);
}
@@ -205,13 +234,32 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
{
struct rpc_xprt *xprt;
struct rpc_clnt *clnt;
+ struct rpc_xprtsock_create xprtargs = {
+ .proto = args->protocol,
+ .srcaddr = args->saddress,
+ .dstaddr = args->address,
+ .addrlen = args->addrsize,
+ .timeout = args->timeout
+ };
+ char servername[20];
- xprt = xprt_create_transport(args->protocol, args->address,
- args->addrsize, args->timeout);
+ xprt = xprt_create_transport(&xprtargs);
if (IS_ERR(xprt))
return (struct rpc_clnt *)xprt;
/*
+ * If the caller chooses not to specify a hostname, whip
+ * up a string representation of the passed-in address.
+ */
+ if (args->servername == NULL) {
+ struct sockaddr_in *addr =
+ (struct sockaddr_in *) &args->address;
+ snprintf(servername, sizeof(servername), NIPQUAD_FMT,
+ NIPQUAD(addr->sin_addr.s_addr));
+ args->servername = servername;
+ }
+
+ /*
* By default, kernel RPC client connects from a reserved port.
* CAP_NET_BIND_SERVICE will not be set for unprivileged requesters,
* but it is always enabled for rpciod, which handles the connect
@@ -245,8 +293,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
clnt->cl_intr = 1;
if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
clnt->cl_autobind = 1;
- if (args->flags & RPC_CLNT_CREATE_ONESHOT)
- clnt->cl_oneshot = 1;
if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
clnt->cl_discrtry = 1;
@@ -268,24 +314,25 @@ rpc_clone_client(struct rpc_clnt *clnt)
new = kmemdup(clnt, sizeof(*new), GFP_KERNEL);
if (!new)
goto out_no_clnt;
- atomic_set(&new->cl_count, 1);
- atomic_set(&new->cl_users, 0);
+ new->cl_parent = clnt;
+ /* Turn off autobind on clones */
+ new->cl_autobind = 0;
+ INIT_LIST_HEAD(&new->cl_tasks);
+ spin_lock_init(&new->cl_lock);
+ rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
new->cl_metrics = rpc_alloc_iostats(clnt);
if (new->cl_metrics == NULL)
goto out_no_stats;
+ kref_init(&new->cl_kref);
err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
if (err != 0)
goto out_no_path;
- new->cl_parent = clnt;
- atomic_inc(&clnt->cl_count);
- new->cl_xprt = xprt_get(clnt->cl_xprt);
- /* Turn off autobind on clones */
- new->cl_autobind = 0;
- new->cl_oneshot = 0;
- new->cl_dead = 0;
- rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count);
+ xprt_get(clnt->cl_xprt);
+ kref_get(&clnt->cl_kref);
+ rpc_register_client(new);
+ rpciod_up();
return new;
out_no_path:
rpc_free_iostats(new->cl_metrics);
@@ -298,86 +345,86 @@ out_no_clnt:
/*
* Properly shut down an RPC client, terminating all outstanding
- * requests. Note that we must be certain that cl_oneshot and
- * cl_dead are cleared, or else the client would be destroyed
- * when the last task releases it.
+ * requests.
*/
-int
-rpc_shutdown_client(struct rpc_clnt *clnt)
+void rpc_shutdown_client(struct rpc_clnt *clnt)
{
- dprintk("RPC: shutting down %s client for %s, tasks=%d\n",
- clnt->cl_protname, clnt->cl_server,
- atomic_read(&clnt->cl_users));
-
- while (atomic_read(&clnt->cl_users) > 0) {
- /* Don't let rpc_release_client destroy us */
- clnt->cl_oneshot = 0;
- clnt->cl_dead = 0;
+ dprintk("RPC: shutting down %s client for %s\n",
+ clnt->cl_protname, clnt->cl_server);
+
+ while (!list_empty(&clnt->cl_tasks)) {
rpc_killall_tasks(clnt);
wait_event_timeout(destroy_wait,
- !atomic_read(&clnt->cl_users), 1*HZ);
- }
-
- if (atomic_read(&clnt->cl_users) < 0) {
- printk(KERN_ERR "RPC: rpc_shutdown_client clnt %p tasks=%d\n",
- clnt, atomic_read(&clnt->cl_users));
-#ifdef RPC_DEBUG
- rpc_show_tasks();
-#endif
- BUG();
+ list_empty(&clnt->cl_tasks), 1*HZ);
}
- return rpc_destroy_client(clnt);
+ rpc_release_client(clnt);
}
/*
- * Delete an RPC client
+ * Free an RPC client
*/
-int
-rpc_destroy_client(struct rpc_clnt *clnt)
+static void
+rpc_free_client(struct kref *kref)
{
- if (!atomic_dec_and_test(&clnt->cl_count))
- return 1;
- BUG_ON(atomic_read(&clnt->cl_users) != 0);
+ struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
dprintk("RPC: destroying %s client for %s\n",
clnt->cl_protname, clnt->cl_server);
- if (clnt->cl_auth) {
- rpcauth_destroy(clnt->cl_auth);
- clnt->cl_auth = NULL;
- }
if (!IS_ERR(clnt->cl_dentry)) {
rpc_rmdir(clnt->cl_dentry);
rpc_put_mount();
}
if (clnt->cl_parent != clnt) {
- rpc_destroy_client(clnt->cl_parent);
+ rpc_release_client(clnt->cl_parent);
goto out_free;
}
if (clnt->cl_server != clnt->cl_inline_name)
kfree(clnt->cl_server);
out_free:
+ rpc_unregister_client(clnt);
rpc_free_iostats(clnt->cl_metrics);
clnt->cl_metrics = NULL;
xprt_put(clnt->cl_xprt);
+ rpciod_down();
kfree(clnt);
- return 0;
}
/*
- * Release an RPC client
+ * Free an RPC client
+ */
+static void
+rpc_free_auth(struct kref *kref)
+{
+ struct rpc_clnt *clnt = container_of(kref, struct rpc_clnt, cl_kref);
+
+ if (clnt->cl_auth == NULL) {
+ rpc_free_client(kref);
+ return;
+ }
+
+ /*
+ * Note: RPCSEC_GSS may need to send NULL RPC calls in order to
+ * release remaining GSS contexts. This mechanism ensures
+ * that it can do so safely.
+ */
+ kref_init(kref);
+ rpcauth_release(clnt->cl_auth);
+ clnt->cl_auth = NULL;
+ kref_put(kref, rpc_free_client);
+}
+
+/*
+ * Release reference to the RPC client
*/
void
rpc_release_client(struct rpc_clnt *clnt)
{
- dprintk("RPC: rpc_release_client(%p, %d)\n",
- clnt, atomic_read(&clnt->cl_users));
+ dprintk("RPC: rpc_release_client(%p)\n", clnt);
- if (!atomic_dec_and_test(&clnt->cl_users))
- return;
- wake_up(&destroy_wait);
- if (clnt->cl_oneshot || clnt->cl_dead)
- rpc_destroy_client(clnt);
+ if (list_empty(&clnt->cl_tasks))
+ wake_up(&destroy_wait);
+ kref_put(&clnt->cl_kref, rpc_free_auth);
}
/**
@@ -468,82 +515,96 @@ void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
rpc_restore_sigmask(oldset);
}
-/*
- * New rpc_call implementation
+static
+struct rpc_task *rpc_do_run_task(struct rpc_clnt *clnt,
+ struct rpc_message *msg,
+ int flags,
+ const struct rpc_call_ops *ops,
+ void *data)
+{
+ struct rpc_task *task, *ret;
+ sigset_t oldset;
+
+ task = rpc_new_task(clnt, flags, ops, data);
+ if (task == NULL) {
+ rpc_release_calldata(ops, data);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Mask signals on synchronous RPC calls and RPCSEC_GSS upcalls */
+ rpc_task_sigmask(task, &oldset);
+ if (msg != NULL) {
+ rpc_call_setup(task, msg, 0);
+ if (task->tk_status != 0) {
+ ret = ERR_PTR(task->tk_status);
+ rpc_put_task(task);
+ goto out;
+ }
+ }
+ atomic_inc(&task->tk_count);
+ rpc_execute(task);
+ ret = task;
+out:
+ rpc_restore_sigmask(&oldset);
+ return ret;
+}
+
+/**
+ * rpc_call_sync - Perform a synchronous RPC call
+ * @clnt: pointer to RPC client
+ * @msg: RPC call parameters
+ * @flags: RPC call flags
*/
int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
{
struct rpc_task *task;
- sigset_t oldset;
- int status;
-
- /* If this client is slain all further I/O fails */
- if (clnt->cl_dead)
- return -EIO;
+ int status;
BUG_ON(flags & RPC_TASK_ASYNC);
- task = rpc_new_task(clnt, flags, &rpc_default_ops, NULL);
- if (task == NULL)
- return -ENOMEM;
-
- /* Mask signals on RPC calls _and_ GSS_AUTH upcalls */
- rpc_task_sigmask(task, &oldset);
-
- /* Set up the call info struct and execute the task */
- rpc_call_setup(task, msg, 0);
- if (task->tk_status == 0) {
- atomic_inc(&task->tk_count);
- rpc_execute(task);
- }
+ task = rpc_do_run_task(clnt, msg, flags, &rpc_default_ops, NULL);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
status = task->tk_status;
rpc_put_task(task);
- rpc_restore_sigmask(&oldset);
return status;
}
-/*
- * New rpc_call implementation
+/**
+ * rpc_call_async - Perform an asynchronous RPC call
+ * @clnt: pointer to RPC client
+ * @msg: RPC call parameters
+ * @flags: RPC call flags
+ * @ops: RPC call ops
+ * @data: user call data
*/
int
rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
const struct rpc_call_ops *tk_ops, void *data)
{
struct rpc_task *task;
- sigset_t oldset;
- int status;
-
- /* If this client is slain all further I/O fails */
- status = -EIO;
- if (clnt->cl_dead)
- goto out_release;
-
- flags |= RPC_TASK_ASYNC;
-
- /* Create/initialize a new RPC task */
- status = -ENOMEM;
- if (!(task = rpc_new_task(clnt, flags, tk_ops, data)))
- goto out_release;
-
- /* Mask signals on GSS_AUTH upcalls */
- rpc_task_sigmask(task, &oldset);
- rpc_call_setup(task, msg, 0);
-
- /* Set up the call info struct and execute the task */
- status = task->tk_status;
- if (status == 0)
- rpc_execute(task);
- else
- rpc_put_task(task);
-
- rpc_restore_sigmask(&oldset);
- return status;
-out_release:
- rpc_release_calldata(tk_ops, data);
- return status;
+ task = rpc_do_run_task(clnt, msg, flags|RPC_TASK_ASYNC, tk_ops, data);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ rpc_put_task(task);
+ return 0;
}
+/**
+ * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
+ * @clnt: pointer to RPC client
+ * @flags: RPC flags
+ * @ops: RPC call ops
+ * @data: user call data
+ */
+struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
+ const struct rpc_call_ops *tk_ops,
+ void *data)
+{
+ return rpc_do_run_task(clnt, NULL, flags, tk_ops, data);
+}
+EXPORT_SYMBOL(rpc_run_task);
void
rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
@@ -745,7 +806,7 @@ call_reserveresult(struct rpc_task *task)
static void
call_allocate(struct rpc_task *task)
{
- unsigned int slack = task->tk_auth->au_cslack;
+ unsigned int slack = task->tk_msg.rpc_cred->cr_auth->au_cslack;
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = task->tk_xprt;
struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
@@ -843,10 +904,8 @@ call_encode(struct rpc_task *task)
if (encode == NULL)
return;
- lock_kernel();
task->tk_status = rpcauth_wrap_req(task, encode, req, p,
task->tk_msg.rpc_argp);
- unlock_kernel();
if (task->tk_status == -ENOMEM) {
/* XXX: Is this sane? */
rpc_delay(task, 3*HZ);
@@ -1177,10 +1236,8 @@ call_decode(struct rpc_task *task)
task->tk_action = rpc_exit_task;
if (decode) {
- lock_kernel();
task->tk_status = rpcauth_unwrap_resp(task, decode, req, p,
task->tk_msg.rpc_resp);
- unlock_kernel();
}
dprintk("RPC: %5u call_decode result %d\n", task->tk_pid,
task->tk_status);
@@ -1273,9 +1330,9 @@ call_verify(struct rpc_task *task)
* - if it isn't pointer subtraction in the NFS client may give
* undefined results
*/
- printk(KERN_WARNING
- "call_verify: XDR representation not a multiple of"
- " 4 bytes: 0x%x\n", task->tk_rqstp->rq_rcv_buf.len);
+ dprintk("RPC: %5u %s: XDR representation not a multiple of"
+ " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__,
+ task->tk_rqstp->rq_rcv_buf.len);
goto out_eio;
}
if ((len -= 3) < 0)
@@ -1283,7 +1340,8 @@ call_verify(struct rpc_task *task)
p += 1; /* skip XID */
if ((n = ntohl(*p++)) != RPC_REPLY) {
- printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n);
+ dprintk("RPC: %5u %s: not an RPC reply: %x\n",
+ task->tk_pid, __FUNCTION__, n);
goto out_garbage;
}
if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
@@ -1334,7 +1392,8 @@ call_verify(struct rpc_task *task)
"authentication.\n", task->tk_client->cl_server);
break;
default:
- printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n);
+ dprintk("RPC: %5u %s: unknown auth error: %x\n",
+ task->tk_pid, __FUNCTION__, n);
error = -EIO;
}
dprintk("RPC: %5u %s: call rejected %d\n",
@@ -1342,7 +1401,8 @@ call_verify(struct rpc_task *task)
goto out_err;
}
if (!(p = rpcauth_checkverf(task, p))) {
- printk(KERN_WARNING "call_verify: auth check failed\n");
+ dprintk("RPC: %5u %s: auth check failed\n",
+ task->tk_pid, __FUNCTION__);
goto out_garbage; /* bad verifier, retry */
}
len = p - (__be32 *)iov->iov_base - 1;
@@ -1381,7 +1441,8 @@ call_verify(struct rpc_task *task)
task->tk_pid, __FUNCTION__);
break; /* retry */
default:
- printk(KERN_WARNING "call_verify: server accept status: %x\n", n);
+ dprintk("RPC: %5u %s: server accept status: %x\n",
+ task->tk_pid, __FUNCTION__, n);
/* Also retry */
}
@@ -1395,14 +1456,16 @@ out_garbage:
out_retry:
return ERR_PTR(-EAGAIN);
}
- printk(KERN_WARNING "RPC %s: retry failed, exit EIO\n", __FUNCTION__);
out_eio:
error = -EIO;
out_err:
rpc_exit(task, error);
+ dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
+ __FUNCTION__, error);
return ERR_PTR(error);
out_overflow:
- printk(KERN_WARNING "RPC %s: server reply was truncated.\n", __FUNCTION__);
+ dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid,
+ __FUNCTION__);
goto out_garbage;
}
@@ -1421,7 +1484,7 @@ static struct rpc_procinfo rpcproc_null = {
.p_decode = rpcproc_decode_null,
};
-int rpc_ping(struct rpc_clnt *clnt, int flags)
+static int rpc_ping(struct rpc_clnt *clnt, int flags)
{
struct rpc_message msg = {
.rpc_proc = &rpcproc_null,
@@ -1432,3 +1495,51 @@ int rpc_ping(struct rpc_clnt *clnt, int flags)
put_rpccred(msg.rpc_cred);
return err;
}
+
+struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int flags)
+{
+ struct rpc_message msg = {
+ .rpc_proc = &rpcproc_null,
+ .rpc_cred = cred,
+ };
+ return rpc_do_run_task(clnt, &msg, flags, &rpc_default_ops, NULL);
+}
+EXPORT_SYMBOL(rpc_call_null);
+
+#ifdef RPC_DEBUG
+void rpc_show_tasks(void)
+{
+ struct rpc_clnt *clnt;
+ struct rpc_task *t;
+
+ spin_lock(&rpc_client_lock);
+ if (list_empty(&all_clients))
+ goto out;
+ printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
+ "-rpcwait -action- ---ops--\n");
+ list_for_each_entry(clnt, &all_clients, cl_clients) {
+ if (list_empty(&clnt->cl_tasks))
+ continue;
+ spin_lock(&clnt->cl_lock);
+ list_for_each_entry(t, &clnt->cl_tasks, tk_task) {
+ const char *rpc_waitq = "none";
+
+ if (RPC_IS_QUEUED(t))
+ rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
+
+ printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
+ t->tk_pid,
+ (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
+ t->tk_flags, t->tk_status,
+ t->tk_client,
+ (t->tk_client ? t->tk_client->cl_prog : 0),
+ t->tk_rqstp, t->tk_timeout,
+ rpc_waitq,
+ t->tk_action, t->tk_ops);
+ }
+ spin_unlock(&clnt->cl_lock);
+ }
+out:
+ spin_unlock(&rpc_client_lock);
+}
+#endif
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 5887457dc936..650af064ff8d 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -344,7 +344,7 @@ rpc_info_open(struct inode *inode, struct file *file)
mutex_lock(&inode->i_mutex);
clnt = RPC_I(inode)->private;
if (clnt) {
- atomic_inc(&clnt->cl_users);
+ kref_get(&clnt->cl_kref);
m->private = clnt;
} else {
single_release(inode, file);
@@ -448,24 +448,31 @@ void rpc_put_mount(void)
simple_release_fs(&rpc_mount, &rpc_mount_count);
}
+static int rpc_delete_dentry(struct dentry *dentry)
+{
+ return 1;
+}
+
+static struct dentry_operations rpc_dentry_operations = {
+ .d_delete = rpc_delete_dentry,
+};
+
static int
rpc_lookup_parent(char *path, struct nameidata *nd)
{
+ struct vfsmount *mnt;
+
if (path[0] == '\0')
return -ENOENT;
- nd->mnt = rpc_get_mount();
- if (IS_ERR(nd->mnt)) {
+
+ mnt = rpc_get_mount();
+ if (IS_ERR(mnt)) {
printk(KERN_WARNING "%s: %s failed to mount "
"pseudofilesystem \n", __FILE__, __FUNCTION__);
- return PTR_ERR(nd->mnt);
+ return PTR_ERR(mnt);
}
- mntget(nd->mnt);
- nd->dentry = dget(rpc_mount->mnt_root);
- nd->last_type = LAST_ROOT;
- nd->flags = LOOKUP_PARENT;
- nd->depth = 0;
- if (path_walk(path, nd)) {
+ if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) {
printk(KERN_WARNING "%s: %s failed to find path %s\n",
__FILE__, __FUNCTION__, path);
rpc_put_mount();
@@ -506,7 +513,7 @@ rpc_get_inode(struct super_block *sb, int mode)
* FIXME: This probably has races.
*/
static void
-rpc_depopulate(struct dentry *parent)
+rpc_depopulate(struct dentry *parent, int start, int eof)
{
struct inode *dir = parent->d_inode;
struct list_head *pos, *next;
@@ -518,6 +525,10 @@ repeat:
spin_lock(&dcache_lock);
list_for_each_safe(pos, next, &parent->d_subdirs) {
dentry = list_entry(pos, struct dentry, d_u.d_child);
+ if (!dentry->d_inode ||
+ dentry->d_inode->i_ino < start ||
+ dentry->d_inode->i_ino >= eof)
+ continue;
spin_lock(&dentry->d_lock);
if (!d_unhashed(dentry)) {
dget_locked(dentry);
@@ -533,11 +544,11 @@ repeat:
if (n) {
do {
dentry = dvec[--n];
- if (dentry->d_inode) {
- rpc_close_pipes(dentry->d_inode);
+ if (S_ISREG(dentry->d_inode->i_mode))
simple_unlink(dir, dentry);
- }
- inode_dir_notify(dir, DN_DELETE);
+ else if (S_ISDIR(dentry->d_inode->i_mode))
+ simple_rmdir(dir, dentry);
+ d_delete(dentry);
dput(dentry);
} while (n);
goto repeat;
@@ -560,6 +571,7 @@ rpc_populate(struct dentry *parent,
dentry = d_alloc_name(parent, files[i].name);
if (!dentry)
goto out_bad;
+ dentry->d_op = &rpc_dentry_operations;
mode = files[i].mode;
inode = rpc_get_inode(dir->i_sb, mode);
if (!inode) {
@@ -607,21 +619,14 @@ static int
__rpc_rmdir(struct inode *dir, struct dentry *dentry)
{
int error;
-
- shrink_dcache_parent(dentry);
- if (d_unhashed(dentry))
- return 0;
- if ((error = simple_rmdir(dir, dentry)) != 0)
- return error;
- if (!error) {
- inode_dir_notify(dir, DN_DELETE);
- d_drop(dentry);
- }
- return 0;
+ error = simple_rmdir(dir, dentry);
+ if (!error)
+ d_delete(dentry);
+ return error;
}
static struct dentry *
-rpc_lookup_create(struct dentry *parent, const char *name, int len)
+rpc_lookup_create(struct dentry *parent, const char *name, int len, int exclusive)
{
struct inode *dir = parent->d_inode;
struct dentry *dentry;
@@ -630,7 +635,9 @@ rpc_lookup_create(struct dentry *parent, const char *name, int len)
dentry = lookup_one_len(name, parent, len);
if (IS_ERR(dentry))
goto out_err;
- if (dentry->d_inode) {
+ if (!dentry->d_inode)
+ dentry->d_op = &rpc_dentry_operations;
+ else if (exclusive) {
dput(dentry);
dentry = ERR_PTR(-EEXIST);
goto out_err;
@@ -649,7 +656,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
if ((error = rpc_lookup_parent(path, nd)) != 0)
return ERR_PTR(error);
- dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len);
+ dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len, 1);
if (IS_ERR(dentry))
rpc_release_path(nd);
return dentry;
@@ -681,7 +688,7 @@ out:
rpc_release_path(&nd);
return dentry;
err_depopulate:
- rpc_depopulate(dentry);
+ rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF);
__rpc_rmdir(dir, dentry);
err_dput:
dput(dentry);
@@ -701,7 +708,7 @@ rpc_rmdir(struct dentry *dentry)
parent = dget_parent(dentry);
dir = parent->d_inode;
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
- rpc_depopulate(dentry);
+ rpc_depopulate(dentry, RPCAUTH_info, RPCAUTH_EOF);
error = __rpc_rmdir(dir, dentry);
dput(dentry);
mutex_unlock(&dir->i_mutex);
@@ -716,10 +723,21 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi
struct inode *dir, *inode;
struct rpc_inode *rpci;
- dentry = rpc_lookup_create(parent, name, strlen(name));
+ dentry = rpc_lookup_create(parent, name, strlen(name), 0);
if (IS_ERR(dentry))
return dentry;
dir = parent->d_inode;
+ if (dentry->d_inode) {
+ rpci = RPC_I(dentry->d_inode);
+ if (rpci->private != private ||
+ rpci->ops != ops ||
+ rpci->flags != flags) {
+ dput (dentry);
+ dentry = ERR_PTR(-EBUSY);
+ }
+ rpci->nkern_readwriters++;
+ goto out;
+ }
inode = rpc_get_inode(dir->i_sb, S_IFIFO | S_IRUSR | S_IWUSR);
if (!inode)
goto err_dput;
@@ -730,6 +748,7 @@ rpc_mkpipe(struct dentry *parent, const char *name, void *private, struct rpc_pi
rpci->private = private;
rpci->flags = flags;
rpci->ops = ops;
+ rpci->nkern_readwriters = 1;
inode_dir_notify(dir, DN_CREATE);
dget(dentry);
out:
@@ -754,13 +773,11 @@ rpc_unlink(struct dentry *dentry)
parent = dget_parent(dentry);
dir = parent->d_inode;
mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
- if (!d_unhashed(dentry)) {
- d_drop(dentry);
- if (dentry->d_inode) {
- rpc_close_pipes(dentry->d_inode);
- error = simple_unlink(dir, dentry);
- }
- inode_dir_notify(dir, DN_DELETE);
+ if (--RPC_I(dentry->d_inode)->nkern_readwriters == 0) {
+ rpc_close_pipes(dentry->d_inode);
+ error = simple_unlink(dir, dentry);
+ if (!error)
+ d_delete(dentry);
}
dput(dentry);
mutex_unlock(&dir->i_mutex);
@@ -833,6 +850,7 @@ init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
rpci->nreaders = 0;
rpci->nwriters = 0;
INIT_LIST_HEAD(&rpci->in_upcall);
+ INIT_LIST_HEAD(&rpci->in_downcall);
INIT_LIST_HEAD(&rpci->pipe);
rpci->pipelen = 0;
init_waitqueue_head(&rpci->waitq);
@@ -849,7 +867,7 @@ int register_rpc_pipefs(void)
sizeof(struct rpc_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD),
- init_once, NULL);
+ init_once);
if (!rpc_inode_cachep)
return -ENOMEM;
err = register_filesystem(&rpc_pipe_fs_type);
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 6c7aa8a1f0c6..d1740dbab991 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -12,6 +12,8 @@
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
+#include <linux/module.h>
+
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/kernel.h>
@@ -184,8 +186,8 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
.program = &rpcb_program,
.version = version,
.authflavor = RPC_AUTH_UNIX,
- .flags = (RPC_CLNT_CREATE_ONESHOT |
- RPC_CLNT_CREATE_NOPING),
+ .flags = (RPC_CLNT_CREATE_NOPING |
+ RPC_CLNT_CREATE_INTR),
};
((struct sockaddr_in *)srvaddr)->sin_port = htons(RPCBIND_PORT);
@@ -238,6 +240,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
error = rpc_call_sync(rpcb_clnt, &msg, 0);
+ rpc_shutdown_client(rpcb_clnt);
if (error < 0)
printk(KERN_WARNING "RPC: failed to contact local rpcbind "
"server (errno %d).\n", -error);
@@ -246,21 +249,20 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
return error;
}
-#ifdef CONFIG_ROOT_NFS
/**
- * rpcb_getport_external - obtain the port for an RPC service on a given host
+ * rpcb_getport_sync - obtain the port for an RPC service on a given host
* @sin: address of remote peer
* @prog: RPC program number to bind
* @vers: RPC version number to bind
* @prot: transport protocol to use to make this request
*
* Called from outside the RPC client in a synchronous task context.
+ * Uses default timeout parameters specified by underlying transport.
*
- * For now, this supports only version 2 queries, but is used only by
- * mount_clnt for NFS_ROOT.
+ * XXX: Needs to support IPv6, and rpcbind versions 3 and 4
*/
-int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog,
- __u32 vers, int prot)
+int rpcb_getport_sync(struct sockaddr_in *sin, __u32 prog,
+ __u32 vers, int prot)
{
struct rpcbind_args map = {
.r_prog = prog,
@@ -277,15 +279,16 @@ int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog,
char hostname[40];
int status;
- dprintk("RPC: rpcb_getport_external(%u.%u.%u.%u, %u, %u, %d)\n",
- NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
+ dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
+ __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);
- sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr));
+ sprintf(hostname, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
rpcb_clnt = rpcb_create(hostname, (struct sockaddr *)sin, prot, 2, 0);
if (IS_ERR(rpcb_clnt))
return PTR_ERR(rpcb_clnt);
status = rpc_call_sync(rpcb_clnt, &msg, 0);
+ rpc_shutdown_client(rpcb_clnt);
if (status >= 0) {
if (map.r_port != 0)
@@ -294,16 +297,16 @@ int rpcb_getport_external(struct sockaddr_in *sin, __u32 prog,
}
return status;
}
-#endif
+EXPORT_SYMBOL_GPL(rpcb_getport_sync);
/**
- * rpcb_getport - obtain the port for a given RPC service on a given host
+ * rpcb_getport_async - obtain the port for a given RPC service on a given host
* @task: task that is waiting for portmapper request
*
* This one can be called for an ongoing RPC request, and can be used in
* an async (rpciod) context.
*/
-void rpcb_getport(struct rpc_task *task)
+void rpcb_getport_async(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
int bind_version;
@@ -314,17 +317,17 @@ void rpcb_getport(struct rpc_task *task)
struct sockaddr addr;
int status;
- dprintk("RPC: %5u rpcb_getport(%s, %u, %u, %d)\n",
- task->tk_pid, clnt->cl_server,
- clnt->cl_prog, clnt->cl_vers, xprt->prot);
+ dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
+ task->tk_pid, __FUNCTION__,
+ clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);
/* Autobind on cloned rpc clients is discouraged */
BUG_ON(clnt->cl_parent != clnt);
if (xprt_test_and_set_binding(xprt)) {
status = -EACCES; /* tell caller to check again */
- dprintk("RPC: %5u rpcb_getport waiting for another binder\n",
- task->tk_pid);
+ dprintk("RPC: %5u %s: waiting for another binder\n",
+ task->tk_pid, __FUNCTION__);
goto bailout_nowake;
}
@@ -335,27 +338,28 @@ void rpcb_getport(struct rpc_task *task)
/* Someone else may have bound if we slept */
if (xprt_bound(xprt)) {
status = 0;
- dprintk("RPC: %5u rpcb_getport already bound\n", task->tk_pid);
+ dprintk("RPC: %5u %s: already bound\n",
+ task->tk_pid, __FUNCTION__);
goto bailout_nofree;
}
if (rpcb_next_version[xprt->bind_index].rpc_proc == NULL) {
xprt->bind_index = 0;
status = -EACCES; /* tell caller to try again later */
- dprintk("RPC: %5u rpcb_getport no more getport versions "
- "available\n", task->tk_pid);
+ dprintk("RPC: %5u %s: no more getport versions available\n",
+ task->tk_pid, __FUNCTION__);
goto bailout_nofree;
}
bind_version = rpcb_next_version[xprt->bind_index].rpc_vers;
- dprintk("RPC: %5u rpcb_getport trying rpcbind version %u\n",
- task->tk_pid, bind_version);
+ dprintk("RPC: %5u %s: trying rpcbind version %u\n",
+ task->tk_pid, __FUNCTION__, bind_version);
map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
if (!map) {
status = -ENOMEM;
- dprintk("RPC: %5u rpcb_getport no memory available\n",
- task->tk_pid);
+ dprintk("RPC: %5u %s: no memory available\n",
+ task->tk_pid, __FUNCTION__);
goto bailout_nofree;
}
map->r_prog = clnt->cl_prog;
@@ -373,16 +377,17 @@ void rpcb_getport(struct rpc_task *task)
rpcb_clnt = rpcb_create(clnt->cl_server, &addr, xprt->prot, bind_version, 0);
if (IS_ERR(rpcb_clnt)) {
status = PTR_ERR(rpcb_clnt);
- dprintk("RPC: %5u rpcb_getport rpcb_create failed, error %ld\n",
- task->tk_pid, PTR_ERR(rpcb_clnt));
+ dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
+ task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
goto bailout;
}
child = rpc_run_task(rpcb_clnt, RPC_TASK_ASYNC, &rpcb_getport_ops, map);
+ rpc_release_client(rpcb_clnt);
if (IS_ERR(child)) {
status = -EIO;
- dprintk("RPC: %5u rpcb_getport rpc_run_task failed\n",
- task->tk_pid);
+ dprintk("RPC: %5u %s: rpc_run_task failed\n",
+ task->tk_pid, __FUNCTION__);
goto bailout_nofree;
}
rpc_put_task(child);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 944d75396fb3..b5723c262a3e 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -25,7 +25,6 @@
#ifdef RPC_DEBUG
#define RPCDBG_FACILITY RPCDBG_SCHED
#define RPC_TASK_MAGIC_ID 0xf00baa
-static int rpc_task_id;
#endif
/*
@@ -40,7 +39,6 @@ static mempool_t *rpc_task_mempool __read_mostly;
static mempool_t *rpc_buffer_mempool __read_mostly;
static void __rpc_default_timer(struct rpc_task *task);
-static void rpciod_killall(void);
static void rpc_async_schedule(struct work_struct *);
static void rpc_release_task(struct rpc_task *task);
@@ -50,23 +48,13 @@ static void rpc_release_task(struct rpc_task *task);
static RPC_WAITQ(delay_queue, "delayq");
/*
- * All RPC tasks are linked into this list
- */
-static LIST_HEAD(all_tasks);
-
-/*
* rpciod-related stuff
*/
static DEFINE_MUTEX(rpciod_mutex);
-static unsigned int rpciod_users;
+static atomic_t rpciod_users = ATOMIC_INIT(0);
struct workqueue_struct *rpciod_workqueue;
/*
- * Spinlock for other critical sections of code.
- */
-static DEFINE_SPINLOCK(rpc_sched_lock);
-
-/*
* Disable the timer for a given RPC task. Should be called with
* queue->lock and bh_disabled in order to avoid races within
* rpc_run_timer().
@@ -267,18 +255,33 @@ static int rpc_wait_bit_interruptible(void *word)
return 0;
}
+#ifdef RPC_DEBUG
+static void rpc_task_set_debuginfo(struct rpc_task *task)
+{
+ static atomic_t rpc_pid;
+
+ task->tk_magic = RPC_TASK_MAGIC_ID;
+ task->tk_pid = atomic_inc_return(&rpc_pid);
+}
+#else
+static inline void rpc_task_set_debuginfo(struct rpc_task *task)
+{
+}
+#endif
+
static void rpc_set_active(struct rpc_task *task)
{
+ struct rpc_clnt *clnt;
if (test_and_set_bit(RPC_TASK_ACTIVE, &task->tk_runstate) != 0)
return;
- spin_lock(&rpc_sched_lock);
-#ifdef RPC_DEBUG
- task->tk_magic = RPC_TASK_MAGIC_ID;
- task->tk_pid = rpc_task_id++;
-#endif
+ rpc_task_set_debuginfo(task);
/* Add to global list of all tasks */
- list_add_tail(&task->tk_task, &all_tasks);
- spin_unlock(&rpc_sched_lock);
+ clnt = task->tk_client;
+ if (clnt != NULL) {
+ spin_lock(&clnt->cl_lock);
+ list_add_tail(&task->tk_task, &clnt->cl_tasks);
+ spin_unlock(&clnt->cl_lock);
+ }
}
/*
@@ -818,6 +821,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons
if (tk_ops->rpc_call_prepare != NULL)
task->tk_action = rpc_prepare_task;
task->tk_calldata = calldata;
+ INIT_LIST_HEAD(&task->tk_task);
/* Initialize retry counters */
task->tk_garb_retry = 2;
@@ -830,7 +834,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons
task->tk_workqueue = rpciod_workqueue;
if (clnt) {
- atomic_inc(&clnt->cl_users);
+ kref_get(&clnt->cl_kref);
if (clnt->cl_softrtry)
task->tk_flags |= RPC_TASK_SOFT;
if (!clnt->cl_intr)
@@ -860,9 +864,7 @@ static void rpc_free_task(struct rcu_head *rcu)
}
/*
- * Create a new task for the specified client. We have to
- * clean up after an allocation failure, as the client may
- * have specified "oneshot".
+ * Create a new task for the specified client.
*/
struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc_call_ops *tk_ops, void *calldata)
{
@@ -870,7 +872,7 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc
task = rpc_alloc_task();
if (!task)
- goto cleanup;
+ goto out;
rpc_init_task(task, clnt, flags, tk_ops, calldata);
@@ -878,16 +880,6 @@ struct rpc_task *rpc_new_task(struct rpc_clnt *clnt, int flags, const struct rpc
task->tk_flags |= RPC_TASK_DYNAMIC;
out:
return task;
-
-cleanup:
- /* Check whether to release the client */
- if (clnt) {
- printk("rpc_new_task: failed, users=%d, oneshot=%d\n",
- atomic_read(&clnt->cl_users), clnt->cl_oneshot);
- atomic_inc(&clnt->cl_users); /* pretend we were used ... */
- rpc_release_client(clnt);
- }
- goto out;
}
@@ -920,11 +912,13 @@ static void rpc_release_task(struct rpc_task *task)
#endif
dprintk("RPC: %5u release task\n", task->tk_pid);
- /* Remove from global task list */
- spin_lock(&rpc_sched_lock);
- list_del(&task->tk_task);
- spin_unlock(&rpc_sched_lock);
-
+ if (!list_empty(&task->tk_task)) {
+ struct rpc_clnt *clnt = task->tk_client;
+ /* Remove from client task list */
+ spin_lock(&clnt->cl_lock);
+ list_del(&task->tk_task);
+ spin_unlock(&clnt->cl_lock);
+ }
BUG_ON (RPC_IS_QUEUED(task));
/* Synchronously delete any running timer */
@@ -939,29 +933,6 @@ static void rpc_release_task(struct rpc_task *task)
rpc_put_task(task);
}
-/**
- * rpc_run_task - Allocate a new RPC task, then run rpc_execute against it
- * @clnt: pointer to RPC client
- * @flags: RPC flags
- * @ops: RPC call ops
- * @data: user call data
- */
-struct rpc_task *rpc_run_task(struct rpc_clnt *clnt, int flags,
- const struct rpc_call_ops *ops,
- void *data)
-{
- struct rpc_task *task;
- task = rpc_new_task(clnt, flags, ops, data);
- if (task == NULL) {
- rpc_release_calldata(ops, data);
- return ERR_PTR(-ENOMEM);
- }
- atomic_inc(&task->tk_count);
- rpc_execute(task);
- return task;
-}
-EXPORT_SYMBOL(rpc_run_task);
-
/*
* Kill all tasks for the given client.
* XXX: kill their descendants as well?
@@ -969,44 +940,25 @@ EXPORT_SYMBOL(rpc_run_task);
void rpc_killall_tasks(struct rpc_clnt *clnt)
{
struct rpc_task *rovr;
- struct list_head *le;
- dprintk("RPC: killing all tasks for client %p\n", clnt);
+ if (list_empty(&clnt->cl_tasks))
+ return;
+ dprintk("RPC: killing all tasks for client %p\n", clnt);
/*
* Spin lock all_tasks to prevent changes...
*/
- spin_lock(&rpc_sched_lock);
- alltask_for_each(rovr, le, &all_tasks) {
+ spin_lock(&clnt->cl_lock);
+ list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) {
if (! RPC_IS_ACTIVATED(rovr))
continue;
- if (!clnt || rovr->tk_client == clnt) {
+ if (!(rovr->tk_flags & RPC_TASK_KILLED)) {
rovr->tk_flags |= RPC_TASK_KILLED;
rpc_exit(rovr, -EIO);
rpc_wake_up_task(rovr);
}
}
- spin_unlock(&rpc_sched_lock);
-}
-
-static void rpciod_killall(void)
-{
- unsigned long flags;
-
- while (!list_empty(&all_tasks)) {
- clear_thread_flag(TIF_SIGPENDING);
- rpc_killall_tasks(NULL);
- flush_workqueue(rpciod_workqueue);
- if (!list_empty(&all_tasks)) {
- dprintk("RPC: rpciod_killall: waiting for tasks "
- "to exit\n");
- yield();
- }
- }
-
- spin_lock_irqsave(&current->sighand->siglock, flags);
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ spin_unlock(&clnt->cl_lock);
}
/*
@@ -1018,28 +970,27 @@ rpciod_up(void)
struct workqueue_struct *wq;
int error = 0;
+ if (atomic_inc_not_zero(&rpciod_users))
+ return 0;
+
mutex_lock(&rpciod_mutex);
- dprintk("RPC: rpciod_up: users %u\n", rpciod_users);
- rpciod_users++;
- if (rpciod_workqueue)
- goto out;
- /*
- * If there's no pid, we should be the first user.
- */
- if (rpciod_users > 1)
- printk(KERN_WARNING "rpciod_up: no workqueue, %u users??\n", rpciod_users);
+
+ /* Guard against races with rpciod_down() */
+ if (rpciod_workqueue != NULL)
+ goto out_ok;
/*
* Create the rpciod thread and wait for it to start.
*/
+ dprintk("RPC: creating workqueue rpciod\n");
error = -ENOMEM;
wq = create_workqueue("rpciod");
- if (wq == NULL) {
- printk(KERN_WARNING "rpciod_up: create workqueue failed, error=%d\n", error);
- rpciod_users--;
+ if (wq == NULL)
goto out;
- }
+
rpciod_workqueue = wq;
error = 0;
+out_ok:
+ atomic_inc(&rpciod_users);
out:
mutex_unlock(&rpciod_mutex);
return error;
@@ -1048,59 +999,19 @@ out:
void
rpciod_down(void)
{
+ if (!atomic_dec_and_test(&rpciod_users))
+ return;
+
mutex_lock(&rpciod_mutex);
- dprintk("RPC: rpciod_down sema %u\n", rpciod_users);
- if (rpciod_users) {
- if (--rpciod_users)
- goto out;
- } else
- printk(KERN_WARNING "rpciod_down: no users??\n");
+ dprintk("RPC: destroying workqueue rpciod\n");
- if (!rpciod_workqueue) {
- dprintk("RPC: rpciod_down: Nothing to do!\n");
- goto out;
+ if (atomic_read(&rpciod_users) == 0 && rpciod_workqueue != NULL) {
+ destroy_workqueue(rpciod_workqueue);
+ rpciod_workqueue = NULL;
}
- rpciod_killall();
-
- destroy_workqueue(rpciod_workqueue);
- rpciod_workqueue = NULL;
- out:
mutex_unlock(&rpciod_mutex);
}
-#ifdef RPC_DEBUG
-void rpc_show_tasks(void)
-{
- struct list_head *le;
- struct rpc_task *t;
-
- spin_lock(&rpc_sched_lock);
- if (list_empty(&all_tasks)) {
- spin_unlock(&rpc_sched_lock);
- return;
- }
- printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
- "-rpcwait -action- ---ops--\n");
- alltask_for_each(t, le, &all_tasks) {
- const char *rpc_waitq = "none";
-
- if (RPC_IS_QUEUED(t))
- rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
-
- printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n",
- t->tk_pid,
- (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
- t->tk_flags, t->tk_status,
- t->tk_client,
- (t->tk_client ? t->tk_client->cl_prog : 0),
- t->tk_rqstp, t->tk_timeout,
- rpc_waitq,
- t->tk_action, t->tk_ops);
- }
- spin_unlock(&rpc_sched_lock);
-}
-#endif
-
void
rpc_destroy_mempool(void)
{
@@ -1120,13 +1031,13 @@ rpc_init_mempool(void)
rpc_task_slabp = kmem_cache_create("rpc_tasks",
sizeof(struct rpc_task),
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!rpc_task_slabp)
goto err_nomem;
rpc_buffer_slabp = kmem_cache_create("rpc_buffers",
RPC_BUFFER_MAXSIZE,
0, SLAB_HWCACHE_ALIGN,
- NULL, NULL);
+ NULL);
if (!rpc_buffer_slabp)
goto err_nomem;
rpc_task_mempool = mempool_create_slab_pool(RPC_TASK_POOLSIZE,
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 73075dec83c0..384c4ad5ab86 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -28,15 +28,11 @@ EXPORT_SYMBOL(rpc_init_task);
EXPORT_SYMBOL(rpc_sleep_on);
EXPORT_SYMBOL(rpc_wake_up_next);
EXPORT_SYMBOL(rpc_wake_up_task);
-EXPORT_SYMBOL(rpciod_down);
-EXPORT_SYMBOL(rpciod_up);
-EXPORT_SYMBOL(rpc_new_task);
EXPORT_SYMBOL(rpc_wake_up_status);
/* RPC client functions */
EXPORT_SYMBOL(rpc_clone_client);
EXPORT_SYMBOL(rpc_bind_new_program);
-EXPORT_SYMBOL(rpc_destroy_client);
EXPORT_SYMBOL(rpc_shutdown_client);
EXPORT_SYMBOL(rpc_killall_tasks);
EXPORT_SYMBOL(rpc_call_sync);
@@ -61,7 +57,7 @@ EXPORT_SYMBOL(rpcauth_unregister);
EXPORT_SYMBOL(rpcauth_create);
EXPORT_SYMBOL(rpcauth_lookupcred);
EXPORT_SYMBOL(rpcauth_lookup_credcache);
-EXPORT_SYMBOL(rpcauth_free_credcache);
+EXPORT_SYMBOL(rpcauth_destroy_credcache);
EXPORT_SYMBOL(rpcauth_init_credcache);
EXPORT_SYMBOL(put_rpccred);
@@ -156,6 +152,7 @@ init_sunrpc(void)
cache_register(&ip_map_cache);
cache_register(&unix_gid_cache);
init_socket_xprt();
+ rpcauth_init_module();
out:
return err;
}
@@ -163,6 +160,7 @@ out:
static void __exit
cleanup_sunrpc(void)
{
+ rpcauth_remove_module();
cleanup_socket_xprt();
unregister_rpc_pipefs();
rpc_destroy_mempool();
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 07dcd20cbee4..411479411b21 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -5,6 +5,7 @@
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/svcauth.h>
+#include <linux/sunrpc/gss_api.h>
#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/hash.h>
@@ -637,7 +638,7 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
}
}
-static int
+int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
struct sockaddr_in *sin = svc_addr_in(rqstp);
@@ -672,6 +673,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
return SVC_OK;
}
+EXPORT_SYMBOL(svcauth_unix_set_client);
+
static int
svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
{
@@ -707,6 +710,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
svc_putnl(resv, RPC_AUTH_NULL);
svc_putnl(resv, 0);
+ rqstp->rq_flavor = RPC_AUTH_NULL;
return SVC_OK;
}
@@ -784,6 +788,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
svc_putnl(resv, RPC_AUTH_NULL);
svc_putnl(resv, 0);
+ rqstp->rq_flavor = RPC_AUTH_UNIX;
return SVC_OK;
badcred:
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 5baf48de2558..64b9b8c743c4 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -644,6 +644,7 @@ svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen)
struct msghdr msg = {
.msg_flags = MSG_DONTWAIT,
};
+ struct sockaddr *sin;
int len;
len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
@@ -654,6 +655,19 @@ svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr, int buflen)
memcpy(&rqstp->rq_addr, &svsk->sk_remote, svsk->sk_remotelen);
rqstp->rq_addrlen = svsk->sk_remotelen;
+ /* Destination address in request is needed for binding the
+ * source address in RPC callbacks later.
+ */
+ sin = (struct sockaddr *)&svsk->sk_local;
+ switch (sin->sa_family) {
+ case AF_INET:
+ rqstp->rq_daddr.addr = ((struct sockaddr_in *)sin)->sin_addr;
+ break;
+ case AF_INET6:
+ rqstp->rq_daddr.addr6 = ((struct sockaddr_in6 *)sin)->sin6_addr;
+ break;
+ }
+
dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",
svsk, iov[0].iov_base, iov[0].iov_len, len);
@@ -1064,6 +1078,12 @@ svc_tcp_accept(struct svc_sock *svsk)
goto failed;
memcpy(&newsvsk->sk_remote, sin, slen);
newsvsk->sk_remotelen = slen;
+ err = kernel_getsockname(newsock, sin, &slen);
+ if (unlikely(err < 0)) {
+ dprintk("svc_tcp_accept: kernel_getsockname error %d\n", -err);
+ slen = offsetof(struct sockaddr, sa_data);
+ }
+ memcpy(&newsvsk->sk_local, sin, slen);
svc_sock_received(newsvsk);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 5b05b73e4c1d..c8c2edccad7e 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -127,7 +127,7 @@ static void xprt_clear_locked(struct rpc_xprt *xprt)
clear_bit(XPRT_LOCKED, &xprt->state);
smp_mb__after_clear_bit();
} else
- schedule_work(&xprt->task_cleanup);
+ queue_work(rpciod_workqueue, &xprt->task_cleanup);
}
/*
@@ -515,7 +515,7 @@ xprt_init_autodisconnect(unsigned long data)
if (xprt_connecting(xprt))
xprt_release_write(xprt, NULL);
else
- schedule_work(&xprt->task_cleanup);
+ queue_work(rpciod_workqueue, &xprt->task_cleanup);
return;
out_abort:
spin_unlock(&xprt->transport_lock);
@@ -886,27 +886,24 @@ void xprt_set_timeout(struct rpc_timeout *to, unsigned int retr, unsigned long i
/**
* xprt_create_transport - create an RPC transport
- * @proto: requested transport protocol
- * @ap: remote peer address
- * @size: length of address
- * @to: timeout parameters
+ * @args: rpc transport creation arguments
*
*/
-struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t size, struct rpc_timeout *to)
+struct rpc_xprt *xprt_create_transport(struct rpc_xprtsock_create *args)
{
struct rpc_xprt *xprt;
struct rpc_rqst *req;
- switch (proto) {
+ switch (args->proto) {
case IPPROTO_UDP:
- xprt = xs_setup_udp(ap, size, to);
+ xprt = xs_setup_udp(args);
break;
case IPPROTO_TCP:
- xprt = xs_setup_tcp(ap, size, to);
+ xprt = xs_setup_tcp(args);
break;
default:
printk(KERN_ERR "RPC: unrecognized transport protocol: %d\n",
- proto);
+ args->proto);
return ERR_PTR(-EIO);
}
if (IS_ERR(xprt)) {
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index cc33c5880abb..4ae7eed7f617 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -235,6 +235,7 @@ struct sock_xprt {
* Connection of transports
*/
struct delayed_work connect_worker;
+ struct sockaddr_storage addr;
unsigned short port;
/*
@@ -653,8 +654,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
dprintk("RPC: xs_destroy xprt %p\n", xprt);
- cancel_delayed_work(&transport->connect_worker);
- flush_scheduled_work();
+ cancel_rearming_delayed_work(&transport->connect_worker);
xprt_disconnect(xprt);
xs_close(xprt);
@@ -1001,7 +1001,7 @@ static void xs_tcp_state_change(struct sock *sk)
/* Try to schedule an autoclose RPC calls */
set_bit(XPRT_CLOSE_WAIT, &xprt->state);
if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
- schedule_work(&xprt->task_cleanup);
+ queue_work(rpciod_workqueue, &xprt->task_cleanup);
default:
xprt_disconnect(xprt);
}
@@ -1146,31 +1146,36 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port)
sap->sin_port = htons(port);
}
-static int xs_bindresvport(struct sock_xprt *transport, struct socket *sock)
+static int xs_bind(struct sock_xprt *transport, struct socket *sock)
{
struct sockaddr_in myaddr = {
.sin_family = AF_INET,
};
+ struct sockaddr_in *sa;
int err;
unsigned short port = transport->port;
+ if (!transport->xprt.resvport)
+ port = 0;
+ sa = (struct sockaddr_in *)&transport->addr;
+ myaddr.sin_addr = sa->sin_addr;
do {
myaddr.sin_port = htons(port);
err = kernel_bind(sock, (struct sockaddr *) &myaddr,
sizeof(myaddr));
+ if (!transport->xprt.resvport)
+ break;
if (err == 0) {
transport->port = port;
- dprintk("RPC: xs_bindresvport bound to port %u\n",
- port);
- return 0;
+ break;
}
if (port <= xprt_min_resvport)
port = xprt_max_resvport;
else
port--;
} while (err == -EADDRINUSE && port != transport->port);
-
- dprintk("RPC: can't bind to reserved port (%d).\n", -err);
+ dprintk("RPC: xs_bind "NIPQUAD_FMT":%u: %s (%d)\n",
+ NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err);
return err;
}
@@ -1229,7 +1234,7 @@ static void xs_udp_connect_worker(struct work_struct *work)
}
xs_reclassify_socket(sock);
- if (xprt->resvport && xs_bindresvport(transport, sock) < 0) {
+ if (xs_bind(transport, sock)) {
sock_release(sock);
goto out;
}
@@ -1316,7 +1321,7 @@ static void xs_tcp_connect_worker(struct work_struct *work)
}
xs_reclassify_socket(sock);
- if (xprt->resvport && xs_bindresvport(transport, sock) < 0) {
+ if (xs_bind(transport, sock)) {
sock_release(sock);
goto out;
}
@@ -1410,18 +1415,16 @@ static void xs_connect(struct rpc_task *task)
dprintk("RPC: xs_connect delayed xprt %p for %lu "
"seconds\n",
xprt, xprt->reestablish_timeout / HZ);
- schedule_delayed_work(&transport->connect_worker,
- xprt->reestablish_timeout);
+ queue_delayed_work(rpciod_workqueue,
+ &transport->connect_worker,
+ xprt->reestablish_timeout);
xprt->reestablish_timeout <<= 1;
if (xprt->reestablish_timeout > XS_TCP_MAX_REEST_TO)
xprt->reestablish_timeout = XS_TCP_MAX_REEST_TO;
} else {
dprintk("RPC: xs_connect scheduled xprt %p\n", xprt);
- schedule_delayed_work(&transport->connect_worker, 0);
-
- /* flush_scheduled_work can sleep... */
- if (!RPC_IS_ASYNC(task))
- flush_scheduled_work();
+ queue_delayed_work(rpciod_workqueue,
+ &transport->connect_worker, 0);
}
}
@@ -1476,7 +1479,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
.set_buffer_size = xs_udp_set_buffer_size,
.reserve_xprt = xprt_reserve_xprt_cong,
.release_xprt = xprt_release_xprt_cong,
- .rpcbind = rpcb_getport,
+ .rpcbind = rpcb_getport_async,
.set_port = xs_set_port,
.connect = xs_connect,
.buf_alloc = rpc_malloc,
@@ -1493,7 +1496,7 @@ static struct rpc_xprt_ops xs_udp_ops = {
static struct rpc_xprt_ops xs_tcp_ops = {
.reserve_xprt = xprt_reserve_xprt,
.release_xprt = xs_tcp_release_xprt,
- .rpcbind = rpcb_getport,
+ .rpcbind = rpcb_getport_async,
.set_port = xs_set_port,
.connect = xs_connect,
.buf_alloc = rpc_malloc,
@@ -1505,12 +1508,12 @@ static struct rpc_xprt_ops xs_tcp_ops = {
.print_stats = xs_tcp_print_stats,
};
-static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, unsigned int slot_table_size)
+static struct rpc_xprt *xs_setup_xprt(struct rpc_xprtsock_create *args, unsigned int slot_table_size)
{
struct rpc_xprt *xprt;
struct sock_xprt *new;
- if (addrlen > sizeof(xprt->addr)) {
+ if (args->addrlen > sizeof(xprt->addr)) {
dprintk("RPC: xs_setup_xprt: address too large\n");
return ERR_PTR(-EBADF);
}
@@ -1532,8 +1535,10 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns
return ERR_PTR(-ENOMEM);
}
- memcpy(&xprt->addr, addr, addrlen);
- xprt->addrlen = addrlen;
+ memcpy(&xprt->addr, args->dstaddr, args->addrlen);
+ xprt->addrlen = args->addrlen;
+ if (args->srcaddr)
+ memcpy(&new->addr, args->srcaddr, args->addrlen);
new->port = xs_get_random_port();
return xprt;
@@ -1541,22 +1546,20 @@ static struct rpc_xprt *xs_setup_xprt(struct sockaddr *addr, size_t addrlen, uns
/**
* xs_setup_udp - Set up transport to use a UDP socket
- * @addr: address of remote server
- * @addrlen: length of address in bytes
- * @to: timeout parameters
+ * @args: rpc transport creation arguments
*
*/
-struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to)
+struct rpc_xprt *xs_setup_udp(struct rpc_xprtsock_create *args)
{
struct rpc_xprt *xprt;
struct sock_xprt *transport;
- xprt = xs_setup_xprt(addr, addrlen, xprt_udp_slot_table_entries);
+ xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries);
if (IS_ERR(xprt))
return xprt;
transport = container_of(xprt, struct sock_xprt, xprt);
- if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0)
+ if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
xprt_set_bound(xprt);
xprt->prot = IPPROTO_UDP;
@@ -1572,8 +1575,8 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_
xprt->ops = &xs_udp_ops;
- if (to)
- xprt->timeout = *to;
+ if (args->timeout)
+ xprt->timeout = *args->timeout;
else
xprt_set_timeout(&xprt->timeout, 5, 5 * HZ);
@@ -1586,22 +1589,20 @@ struct rpc_xprt *xs_setup_udp(struct sockaddr *addr, size_t addrlen, struct rpc_
/**
* xs_setup_tcp - Set up transport to use a TCP socket
- * @addr: address of remote server
- * @addrlen: length of address in bytes
- * @to: timeout parameters
+ * @args: rpc transport creation arguments
*
*/
-struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_timeout *to)
+struct rpc_xprt *xs_setup_tcp(struct rpc_xprtsock_create *args)
{
struct rpc_xprt *xprt;
struct sock_xprt *transport;
- xprt = xs_setup_xprt(addr, addrlen, xprt_tcp_slot_table_entries);
+ xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
if (IS_ERR(xprt))
return xprt;
transport = container_of(xprt, struct sock_xprt, xprt);
- if (ntohs(((struct sockaddr_in *)addr)->sin_port) != 0)
+ if (ntohs(((struct sockaddr_in *)args->dstaddr)->sin_port) != 0)
xprt_set_bound(xprt);
xprt->prot = IPPROTO_TCP;
@@ -1616,8 +1617,8 @@ struct rpc_xprt *xs_setup_tcp(struct sockaddr *addr, size_t addrlen, struct rpc_
xprt->ops = &xs_tcp_ops;
- if (to)
- xprt->timeout = *to;
+ if (args->timeout)
+ xprt->timeout = *args->timeout;
else
xprt_set_timeout(&xprt->timeout, 2, 60 * HZ);
diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c
index 77d2d9ce8962..711ca4b1f051 100644
--- a/net/tipc/eth_media.c
+++ b/net/tipc/eth_media.c
@@ -1,8 +1,8 @@
/*
* net/tipc/eth_media.c: Ethernet bearer support for TIPC
*
- * Copyright (c) 2001-2006, Ericsson AB
- * Copyright (c) 2005-2006, Wind River Systems
+ * Copyright (c) 2001-2007, Ericsson AB
+ * Copyright (c) 2005-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,6 +87,9 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
/**
* recv_msg - handle incoming TIPC message from an Ethernet interface
*
+ * Accept only packets explicitly sent to this node, or broadcast packets;
+ * ignores packets sent using Ethernet multicast, and traffic sent to other
+ * nodes (which can happen if interface is running in promiscuous mode).
* Routine truncates any Ethernet padding/CRC appended to the message,
* and ensures message size matches actual length
*/
@@ -98,9 +101,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev,
u32 size;
if (likely(eb_ptr->bearer)) {
- if (likely(!dev->promiscuity) ||
- !memcmp(skb_mac_header(buf), dev->dev_addr, ETH_ALEN) ||
- !memcmp(skb_mac_header(buf), dev->broadcast, ETH_ALEN)) {
+ if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
size = msg_size((struct tipc_msg *)buf->data);
skb_trim(buf, size);
if (likely(buf->len == size)) {
diff --git a/net/tipc/handler.c b/net/tipc/handler.c
index e1dcf663f8a6..0c70010a7dfe 100644
--- a/net/tipc/handler.c
+++ b/net/tipc/handler.c
@@ -97,7 +97,7 @@ int tipc_handler_start(void)
{
tipc_queue_item_cache =
kmem_cache_create("tipc_queue_items", sizeof(struct queue_item),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (!tipc_queue_item_cache)
return -ENOMEM;
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 2124f32ef29f..5adfdfd49d61 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1,8 +1,8 @@
/*
* net/tipc/link.c: TIPC link code
*
- * Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2004-2006, Wind River Systems
+ * Copyright (c) 1996-2007, Ericsson AB
+ * Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1260,7 +1260,7 @@ again:
* (Must not hold any locks while building message.)
*/
- res = msg_build(hdr, msg_sect, num_sect, sender->max_pkt,
+ res = msg_build(hdr, msg_sect, num_sect, sender->publ.max_pkt,
!sender->user_port, &buf);
read_lock_bh(&tipc_net_lock);
@@ -1271,7 +1271,7 @@ again:
if (likely(l_ptr)) {
if (likely(buf)) {
res = link_send_buf_fast(l_ptr, buf,
- &sender->max_pkt);
+ &sender->publ.max_pkt);
if (unlikely(res < 0))
buf_discard(buf);
exit:
@@ -1299,12 +1299,12 @@ exit:
* then re-try fast path or fragment the message
*/
- sender->max_pkt = link_max_pkt(l_ptr);
+ sender->publ.max_pkt = link_max_pkt(l_ptr);
tipc_node_unlock(node);
read_unlock_bh(&tipc_net_lock);
- if ((msg_hdr_sz(hdr) + res) <= sender->max_pkt)
+ if ((msg_hdr_sz(hdr) + res) <= sender->publ.max_pkt)
goto again;
return link_send_sections_long(sender, msg_sect,
@@ -1357,7 +1357,7 @@ static int link_send_sections_long(struct port *sender,
again:
fragm_no = 1;
- max_pkt = sender->max_pkt - INT_H_SIZE;
+ max_pkt = sender->publ.max_pkt - INT_H_SIZE;
/* leave room for tunnel header in case of link changeover */
fragm_sz = max_pkt - INT_H_SIZE;
/* leave room for fragmentation header in each fragment */
@@ -1463,7 +1463,7 @@ error:
goto reject;
}
if (link_max_pkt(l_ptr) < max_pkt) {
- sender->max_pkt = link_max_pkt(l_ptr);
+ sender->publ.max_pkt = link_max_pkt(l_ptr);
tipc_node_unlock(node);
for (; buf_chain; buf_chain = buf) {
buf = buf_chain->next;
diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c
index 9dfc9127acdd..d8473eefcd23 100644
--- a/net/tipc/name_table.c
+++ b/net/tipc/name_table.c
@@ -1052,12 +1052,11 @@ int tipc_nametbl_init(void)
{
int array_size = sizeof(struct hlist_head) * tipc_nametbl_size;
- table.types = kmalloc(array_size, GFP_ATOMIC);
+ table.types = kzalloc(array_size, GFP_ATOMIC);
if (!table.types)
return -ENOMEM;
write_lock_bh(&tipc_nametbl_lock);
- memset(table.types, 0, array_size);
table.local_publ_count = 0;
write_unlock_bh(&tipc_nametbl_lock);
return 0;
diff --git a/net/tipc/port.c b/net/tipc/port.c
index bcd5da00737b..5d2b9ce84d0a 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -1,8 +1,8 @@
/*
* net/tipc/port.c: TIPC port code
*
- * Copyright (c) 1992-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 1992-2007, Ericsson AB
+ * Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -239,6 +239,8 @@ u32 tipc_createport_raw(void *usr_handle,
}
tipc_port_lock(ref);
+ p_ptr->publ.usr_handle = usr_handle;
+ p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
p_ptr->publ.ref = ref;
msg = &p_ptr->publ.phdr;
msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0);
@@ -248,11 +250,9 @@ u32 tipc_createport_raw(void *usr_handle,
msg_set_importance(msg,importance);
p_ptr->last_in_seqno = 41;
p_ptr->sent = 1;
- p_ptr->publ.usr_handle = usr_handle;
INIT_LIST_HEAD(&p_ptr->wait_list);
INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list);
p_ptr->congested_link = NULL;
- p_ptr->max_pkt = MAX_PKT_DEFAULT;
p_ptr->dispatcher = dispatcher;
p_ptr->wakeup = wakeup;
p_ptr->user_port = NULL;
@@ -1243,7 +1243,7 @@ int tipc_connect2port(u32 ref, struct tipc_portid const *peer)
res = TIPC_OK;
exit:
tipc_port_unlock(p_ptr);
- p_ptr->max_pkt = tipc_link_get_max_pkt(peer->node, ref);
+ p_ptr->publ.max_pkt = tipc_link_get_max_pkt(peer->node, ref);
return res;
}
diff --git a/net/tipc/port.h b/net/tipc/port.h
index 7ef4d64b32f7..e5f8c16429bd 100644
--- a/net/tipc/port.h
+++ b/net/tipc/port.h
@@ -1,8 +1,8 @@
/*
* net/tipc/port.h: Include file for TIPC port code
*
- * Copyright (c) 1994-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 1994-2007, Ericsson AB
+ * Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -81,7 +81,6 @@ struct user_port {
* @acked:
* @publications: list of publications for port
* @pub_count: total # of publications port has made during its lifetime
- * @max_pkt: maximum packet size "hint" used when building messages sent by port
* @probing_state:
* @probing_interval:
* @last_in_seqno:
@@ -102,7 +101,6 @@ struct port {
u32 acked;
struct list_head publications;
u32 pub_count;
- u32 max_pkt;
u32 probing_state;
u32 probing_interval;
u32 last_in_seqno;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 45832fb75ea4..84110172031e 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -1,8 +1,8 @@
/*
* net/tipc/socket.c: TIPC socket API
*
- * Copyright (c) 2001-2006, Ericsson AB
- * Copyright (c) 2004-2006, Wind River Systems
+ * Copyright (c) 2001-2007, Ericsson AB
+ * Copyright (c) 2004-2007, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -607,23 +607,24 @@ exit:
static int send_stream(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t total_len)
{
+ struct tipc_port *tport;
struct msghdr my_msg;
struct iovec my_iov;
struct iovec *curr_iov;
int curr_iovlen;
char __user *curr_start;
+ u32 hdr_size;
int curr_left;
int bytes_to_send;
int bytes_sent;
int res;
- if (likely(total_len <= TIPC_MAX_USER_MSG_SIZE))
- return send_packet(iocb, sock, m, total_len);
-
- /* Can only send large data streams if already connected */
+ /* Handle special cases where there is no connection */
if (unlikely(sock->state != SS_CONNECTED)) {
- if (sock->state == SS_DISCONNECTING)
+ if (sock->state == SS_UNCONNECTED)
+ return send_packet(iocb, sock, m, total_len);
+ else if (sock->state == SS_DISCONNECTING)
return -EPIPE;
else
return -ENOTCONN;
@@ -648,17 +649,25 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
my_msg.msg_name = NULL;
bytes_sent = 0;
+ tport = tipc_sk(sock->sk)->p;
+ hdr_size = msg_hdr_sz(&tport->phdr);
+
while (curr_iovlen--) {
curr_start = curr_iov->iov_base;
curr_left = curr_iov->iov_len;
while (curr_left) {
- bytes_to_send = (curr_left < TIPC_MAX_USER_MSG_SIZE)
- ? curr_left : TIPC_MAX_USER_MSG_SIZE;
+ bytes_to_send = tport->max_pkt - hdr_size;
+ if (bytes_to_send > TIPC_MAX_USER_MSG_SIZE)
+ bytes_to_send = TIPC_MAX_USER_MSG_SIZE;
+ if (curr_left < bytes_to_send)
+ bytes_to_send = curr_left;
my_iov.iov_base = curr_start;
my_iov.iov_len = bytes_to_send;
if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) {
- return bytes_sent ? bytes_sent : res;
+ if (bytes_sent != 0)
+ res = bytes_sent;
+ return res;
}
curr_left -= bytes_to_send;
curr_start += bytes_to_send;
@@ -1600,33 +1609,6 @@ static int getsockopt(struct socket *sock,
}
/**
- * Placeholders for non-implemented functionality
- *
- * Returns error code (POSIX-compliant where defined)
- */
-
-static int ioctl(struct socket *s, u32 cmd, unsigned long arg)
-{
- return -EINVAL;
-}
-
-static int no_mmap(struct file *file, struct socket *sock,
- struct vm_area_struct *vma)
-{
- return -EINVAL;
-}
-static ssize_t no_sendpage(struct socket *sock, struct page *page,
- int offset, size_t size, int flags)
-{
- return -EINVAL;
-}
-
-static int no_skpair(struct socket *s1, struct socket *s2)
-{
- return -EOPNOTSUPP;
-}
-
-/**
* Protocol switches for the various types of TIPC sockets
*/
@@ -1636,19 +1618,19 @@ static struct proto_ops msg_ops = {
.release = release,
.bind = bind,
.connect = connect,
- .socketpair = no_skpair,
+ .socketpair = sock_no_socketpair,
.accept = accept,
.getname = get_name,
.poll = poll,
- .ioctl = ioctl,
+ .ioctl = sock_no_ioctl,
.listen = listen,
.shutdown = shutdown,
.setsockopt = setsockopt,
.getsockopt = getsockopt,
.sendmsg = send_msg,
.recvmsg = recv_msg,
- .mmap = no_mmap,
- .sendpage = no_sendpage
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage
};
static struct proto_ops packet_ops = {
@@ -1657,19 +1639,19 @@ static struct proto_ops packet_ops = {
.release = release,
.bind = bind,
.connect = connect,
- .socketpair = no_skpair,
+ .socketpair = sock_no_socketpair,
.accept = accept,
.getname = get_name,
.poll = poll,
- .ioctl = ioctl,
+ .ioctl = sock_no_ioctl,
.listen = listen,
.shutdown = shutdown,
.setsockopt = setsockopt,
.getsockopt = getsockopt,
.sendmsg = send_packet,
.recvmsg = recv_msg,
- .mmap = no_mmap,
- .sendpage = no_sendpage
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage
};
static struct proto_ops stream_ops = {
@@ -1678,19 +1660,19 @@ static struct proto_ops stream_ops = {
.release = release,
.bind = bind,
.connect = connect,
- .socketpair = no_skpair,
+ .socketpair = sock_no_socketpair,
.accept = accept,
.getname = get_name,
.poll = poll,
- .ioctl = ioctl,
+ .ioctl = sock_no_ioctl,
.listen = listen,
.shutdown = shutdown,
.setsockopt = setsockopt,
.getsockopt = getsockopt,
.sendmsg = send_stream,
.recvmsg = recv_stream,
- .mmap = no_mmap,
- .sendpage = no_sendpage
+ .mmap = sock_no_mmap,
+ .sendpage = sock_no_sendpage
};
static struct net_proto_family tipc_family_ops = {
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index d70fa30d4294..65ebccc0a698 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -592,7 +592,8 @@ static struct sock * unix_create1(struct socket *sock)
u->dentry = NULL;
u->mnt = NULL;
spin_lock_init(&u->lock);
- atomic_set(&u->inflight, sock ? 0 : -1);
+ atomic_set(&u->inflight, 0);
+ INIT_LIST_HEAD(&u->link);
mutex_init(&u->readlock); /* single task reading lock */
init_waitqueue_head(&u->peer_wait);
unix_insert_socket(unix_sockets_unbound, sk);
@@ -1134,9 +1135,6 @@ restart:
/* take ten and and send info to listening sock */
spin_lock(&other->sk_receive_queue.lock);
__skb_queue_tail(&other->sk_receive_queue, skb);
- /* Undo artificially decreased inflight after embrion
- * is installed to listening socket. */
- atomic_inc(&newu->inflight);
spin_unlock(&other->sk_receive_queue.lock);
unix_state_unlock(other);
other->sk_data_ready(other, 0);
@@ -2048,7 +2046,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations unix_seq_ops = {
+static const struct seq_operations unix_seq_ops = {
.start = unix_seq_start,
.next = unix_seq_next,
.stop = unix_seq_stop,
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index f20b7ea7c555..406b6433e467 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -62,6 +62,10 @@
* AV 1 Mar 1999
* Damn. Added missing check for ->dead in listen queues scanning.
*
+ * Miklos Szeredi 25 Jun 2007
+ * Reimplement with a cycle collecting algorithm. This should
+ * solve several problems with the previous code, like being racy
+ * wrt receive and holding up unrelated socket operations.
*/
#include <linux/kernel.h>
@@ -84,10 +88,9 @@
/* Internal data structures and random procedures: */
-#define GC_HEAD ((struct sock *)(-1))
-#define GC_ORPHAN ((struct sock *)(-3))
-
-static struct sock *gc_current = GC_HEAD; /* stack of objects to mark */
+static LIST_HEAD(gc_inflight_list);
+static LIST_HEAD(gc_candidates);
+static DEFINE_SPINLOCK(unix_gc_lock);
atomic_t unix_tot_inflight = ATOMIC_INIT(0);
@@ -122,8 +125,16 @@ void unix_inflight(struct file *fp)
{
struct sock *s = unix_get_socket(fp);
if(s) {
- atomic_inc(&unix_sk(s)->inflight);
+ struct unix_sock *u = unix_sk(s);
+ spin_lock(&unix_gc_lock);
+ if (atomic_inc_return(&u->inflight) == 1) {
+ BUG_ON(!list_empty(&u->link));
+ list_add_tail(&u->link, &gc_inflight_list);
+ } else {
+ BUG_ON(list_empty(&u->link));
+ }
atomic_inc(&unix_tot_inflight);
+ spin_unlock(&unix_gc_lock);
}
}
@@ -131,182 +142,218 @@ void unix_notinflight(struct file *fp)
{
struct sock *s = unix_get_socket(fp);
if(s) {
- atomic_dec(&unix_sk(s)->inflight);
+ struct unix_sock *u = unix_sk(s);
+ spin_lock(&unix_gc_lock);
+ BUG_ON(list_empty(&u->link));
+ if (atomic_dec_and_test(&u->inflight))
+ list_del_init(&u->link);
atomic_dec(&unix_tot_inflight);
+ spin_unlock(&unix_gc_lock);
}
}
+static inline struct sk_buff *sock_queue_head(struct sock *sk)
+{
+ return (struct sk_buff *) &sk->sk_receive_queue;
+}
-/*
- * Garbage Collector Support Functions
- */
+#define receive_queue_for_each_skb(sk, next, skb) \
+ for (skb = sock_queue_head(sk)->next, next = skb->next; \
+ skb != sock_queue_head(sk); skb = next, next = skb->next)
-static inline struct sock *pop_stack(void)
+static void scan_inflight(struct sock *x, void (*func)(struct sock *),
+ struct sk_buff_head *hitlist)
{
- struct sock *p = gc_current;
- gc_current = unix_sk(p)->gc_tree;
- return p;
+ struct sk_buff *skb;
+ struct sk_buff *next;
+
+ spin_lock(&x->sk_receive_queue.lock);
+ receive_queue_for_each_skb(x, next, skb) {
+ /*
+ * Do we have file descriptors ?
+ */
+ if (UNIXCB(skb).fp) {
+ bool hit = false;
+ /*
+ * Process the descriptors of this socket
+ */
+ int nfd = UNIXCB(skb).fp->count;
+ struct file **fp = UNIXCB(skb).fp->fp;
+ while (nfd--) {
+ /*
+ * Get the socket the fd matches
+ * if it indeed does so
+ */
+ struct sock *sk = unix_get_socket(*fp++);
+ if(sk) {
+ hit = true;
+ func(sk);
+ }
+ }
+ if (hit && hitlist != NULL) {
+ __skb_unlink(skb, &x->sk_receive_queue);
+ __skb_queue_tail(hitlist, skb);
+ }
+ }
+ }
+ spin_unlock(&x->sk_receive_queue.lock);
}
-static inline int empty_stack(void)
+static void scan_children(struct sock *x, void (*func)(struct sock *),
+ struct sk_buff_head *hitlist)
{
- return gc_current == GC_HEAD;
+ if (x->sk_state != TCP_LISTEN)
+ scan_inflight(x, func, hitlist);
+ else {
+ struct sk_buff *skb;
+ struct sk_buff *next;
+ struct unix_sock *u;
+ LIST_HEAD(embryos);
+
+ /*
+ * For a listening socket collect the queued embryos
+ * and perform a scan on them as well.
+ */
+ spin_lock(&x->sk_receive_queue.lock);
+ receive_queue_for_each_skb(x, next, skb) {
+ u = unix_sk(skb->sk);
+
+ /*
+ * An embryo cannot be in-flight, so it's safe
+ * to use the list link.
+ */
+ BUG_ON(!list_empty(&u->link));
+ list_add_tail(&u->link, &embryos);
+ }
+ spin_unlock(&x->sk_receive_queue.lock);
+
+ while (!list_empty(&embryos)) {
+ u = list_entry(embryos.next, struct unix_sock, link);
+ scan_inflight(&u->sk, func, hitlist);
+ list_del_init(&u->link);
+ }
+ }
}
-static void maybe_unmark_and_push(struct sock *x)
+static void dec_inflight(struct sock *sk)
{
- struct unix_sock *u = unix_sk(x);
+ atomic_dec(&unix_sk(sk)->inflight);
+}
- if (u->gc_tree != GC_ORPHAN)
- return;
- sock_hold(x);
- u->gc_tree = gc_current;
- gc_current = x;
+static void inc_inflight(struct sock *sk)
+{
+ atomic_inc(&unix_sk(sk)->inflight);
}
+static void inc_inflight_move_tail(struct sock *sk)
+{
+ struct unix_sock *u = unix_sk(sk);
+
+ atomic_inc(&u->inflight);
+ /*
+ * If this is still a candidate, move it to the end of the
+ * list, so that it's checked even if it was already passed
+ * over
+ */
+ if (u->gc_candidate)
+ list_move_tail(&u->link, &gc_candidates);
+}
/* The external entry point: unix_gc() */
void unix_gc(void)
{
- static DEFINE_MUTEX(unix_gc_sem);
- int i;
- struct sock *s;
- struct sk_buff_head hitlist;
- struct sk_buff *skb;
+ static bool gc_in_progress = false;
- /*
- * Avoid a recursive GC.
- */
+ struct unix_sock *u;
+ struct unix_sock *next;
+ struct sk_buff_head hitlist;
+ struct list_head cursor;
- if (!mutex_trylock(&unix_gc_sem))
- return;
+ spin_lock(&unix_gc_lock);
- spin_lock(&unix_table_lock);
+ /* Avoid a recursive GC. */
+ if (gc_in_progress)
+ goto out;
- forall_unix_sockets(i, s)
- {
- unix_sk(s)->gc_tree = GC_ORPHAN;
- }
+ gc_in_progress = true;
/*
- * Everything is now marked
- */
-
- /* Invariant to be maintained:
- - everything unmarked is either:
- -- (a) on the stack, or
- -- (b) has all of its children unmarked
- - everything on the stack is always unmarked
- - nothing is ever pushed onto the stack twice, because:
- -- nothing previously unmarked is ever pushed on the stack
+ * First, select candidates for garbage collection. Only
+ * in-flight sockets are considered, and from those only ones
+ * which don't have any external reference.
+ *
+ * Holding unix_gc_lock will protect these candidates from
+ * being detached, and hence from gaining an external
+ * reference. This also means, that since there are no
+ * possible receivers, the receive queues of these sockets are
+ * static during the GC, even though the dequeue is done
+ * before the detach without atomicity guarantees.
*/
+ list_for_each_entry_safe(u, next, &gc_inflight_list, link) {
+ int total_refs;
+ int inflight_refs;
+
+ total_refs = file_count(u->sk.sk_socket->file);
+ inflight_refs = atomic_read(&u->inflight);
+
+ BUG_ON(inflight_refs < 1);
+ BUG_ON(total_refs < inflight_refs);
+ if (total_refs == inflight_refs) {
+ list_move_tail(&u->link, &gc_candidates);
+ u->gc_candidate = 1;
+ }
+ }
/*
- * Push root set
+ * Now remove all internal in-flight reference to children of
+ * the candidates.
*/
-
- forall_unix_sockets(i, s)
- {
- int open_count = 0;
-
- /*
- * If all instances of the descriptor are not
- * in flight we are in use.
- *
- * Special case: when socket s is embrion, it may be
- * hashed but still not in queue of listening socket.
- * In this case (see unix_create1()) we set artificial
- * negative inflight counter to close race window.
- * It is trick of course and dirty one.
- */
- if (s->sk_socket && s->sk_socket->file)
- open_count = file_count(s->sk_socket->file);
- if (open_count > atomic_read(&unix_sk(s)->inflight))
- maybe_unmark_and_push(s);
- }
+ list_for_each_entry(u, &gc_candidates, link)
+ scan_children(&u->sk, dec_inflight, NULL);
/*
- * Mark phase
+ * Restore the references for children of all candidates,
+ * which have remaining references. Do this recursively, so
+ * only those remain, which form cyclic references.
+ *
+ * Use a "cursor" link, to make the list traversal safe, even
+ * though elements might be moved about.
*/
+ list_add(&cursor, &gc_candidates);
+ while (cursor.next != &gc_candidates) {
+ u = list_entry(cursor.next, struct unix_sock, link);
- while (!empty_stack())
- {
- struct sock *x = pop_stack();
- struct sock *sk;
-
- spin_lock(&x->sk_receive_queue.lock);
- skb = skb_peek(&x->sk_receive_queue);
-
- /*
- * Loop through all but first born
- */
+ /* Move cursor to after the current position. */
+ list_move(&cursor, &u->link);
- while (skb && skb != (struct sk_buff *)&x->sk_receive_queue) {
- /*
- * Do we have file descriptors ?
- */
- if(UNIXCB(skb).fp)
- {
- /*
- * Process the descriptors of this socket
- */
- int nfd=UNIXCB(skb).fp->count;
- struct file **fp = UNIXCB(skb).fp->fp;
- while(nfd--)
- {
- /*
- * Get the socket the fd matches if
- * it indeed does so
- */
- if((sk=unix_get_socket(*fp++))!=NULL)
- {
- maybe_unmark_and_push(sk);
- }
- }
- }
- /* We have to scan not-yet-accepted ones too */
- if (x->sk_state == TCP_LISTEN)
- maybe_unmark_and_push(skb->sk);
- skb=skb->next;
+ if (atomic_read(&u->inflight) > 0) {
+ list_move_tail(&u->link, &gc_inflight_list);
+ u->gc_candidate = 0;
+ scan_children(&u->sk, inc_inflight_move_tail, NULL);
}
- spin_unlock(&x->sk_receive_queue.lock);
- sock_put(x);
}
+ list_del(&cursor);
+ /*
+ * Now gc_candidates contains only garbage. Restore original
+ * inflight counters for these as well, and remove the skbuffs
+ * which are creating the cycle(s).
+ */
skb_queue_head_init(&hitlist);
+ list_for_each_entry(u, &gc_candidates, link)
+ scan_children(&u->sk, inc_inflight, &hitlist);
- forall_unix_sockets(i, s)
- {
- struct unix_sock *u = unix_sk(s);
+ spin_unlock(&unix_gc_lock);
- if (u->gc_tree == GC_ORPHAN) {
- struct sk_buff *nextsk;
+ /* Here we are. Hitlist is filled. Die. */
+ __skb_queue_purge(&hitlist);
- spin_lock(&s->sk_receive_queue.lock);
- skb = skb_peek(&s->sk_receive_queue);
- while (skb &&
- skb != (struct sk_buff *)&s->sk_receive_queue) {
- nextsk = skb->next;
- /*
- * Do we have file descriptors ?
- */
- if (UNIXCB(skb).fp) {
- __skb_unlink(skb,
- &s->sk_receive_queue);
- __skb_queue_tail(&hitlist, skb);
- }
- skb = nextsk;
- }
- spin_unlock(&s->sk_receive_queue.lock);
- }
- u->gc_tree = GC_ORPHAN;
- }
- spin_unlock(&unix_table_lock);
+ spin_lock(&unix_gc_lock);
- /*
- * Here we are. Hitlist is filled. Die.
- */
+ /* All candidates should have been detached by now. */
+ BUG_ON(!list_empty(&gc_candidates));
+ gc_in_progress = false;
- __skb_queue_purge(&hitlist);
- mutex_unlock(&unix_gc_sem);
+ out:
+ spin_unlock(&unix_gc_lock);
}
diff --git a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
index 205106521ecb..236e7eaf1b7f 100644
--- a/net/wanrouter/wanproc.c
+++ b/net/wanrouter/wanproc.c
@@ -164,14 +164,14 @@ static int status_show(struct seq_file *m, void *v)
return 0;
}
-static struct seq_operations config_op = {
+static const struct seq_operations config_op = {
.start = r_start,
.next = r_next,
.stop = r_stop,
.show = config_show,
};
-static struct seq_operations status_op = {
+static const struct seq_operations status_op = {
.start = r_start,
.next = r_next,
.stop = r_stop,
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 3a96ae60271c..092116e390b6 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -1,4 +1,4 @@
obj-$(CONFIG_WIRELESS_EXT) += wext.o
obj-$(CONFIG_CFG80211) += cfg80211.o
-cfg80211-y += core.o sysfs.o
+cfg80211-y += core.o sysfs.o radiotap.o
diff --git a/net/wireless/radiotap.c b/net/wireless/radiotap.c
new file mode 100644
index 000000000000..68c11d099917
--- /dev/null
+++ b/net/wireless/radiotap.c
@@ -0,0 +1,257 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ */
+
+#include <net/cfg80211.h>
+#include <net/ieee80211_radiotap.h>
+#include <asm/unaligned.h>
+
+/* function prototypes and related defs are in include/net/cfg80211.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header. It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code. Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member. This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length)
+{
+ /* Linux only supports version 0 radiotap format */
+ if (radiotap_header->it_version)
+ return -EINVAL;
+
+ /* sanity check for allowed length and radiotap length field */
+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(get_unaligned(
+ &radiotap_header->it_len));
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+ &radiotap_header->it_present));
+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+ iterator->this_arg = NULL;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+ (1<<IEEE80211_RADIOTAP_EXT)) {
+ iterator->arg += sizeof(u32);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+
+ if (((ulong)iterator->arg -
+ (ulong)iterator->rtheader) > iterator->max_length)
+ return -EINVAL;
+ }
+
+ iterator->arg += sizeof(u32);
+
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, because ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+
+ /* we are all initialized happily */
+
+ return 0;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_init);
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field. It takes care of alignment handling and extended
+ * present fields. @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x u16
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const u8 rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < sizeof(rt_sizes)) {
+ int hit = 0;
+ int pad;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ *
+ * the above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area
+ */
+
+ pad = (((ulong)iterator->arg) -
+ ((ulong)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+ if (pad)
+ iterator->arg +=
+ (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+ iterator->max_length)
+ return -EINVAL;
+
+ next_entry:
+ iterator->arg_index++;
+ if (unlikely((iterator->arg_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (iterator->bitmap_shifter & 1) {
+ /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ iterator->bitmap_shifter = le32_to_cpu(
+ get_unaligned(iterator->next_bitmap));
+ iterator->next_bitmap++;
+ } else
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof(rt_sizes);
+ } else /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+
+ /* if we found a valid arg earlier, return it now */
+ if (hit)
+ return 0;
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -ENOENT;
+}
+EXPORT_SYMBOL(ieee80211_radiotap_iterator_next);
diff --git a/net/x25/x25_proc.c b/net/x25/x25_proc.c
index 96001f0c64fc..7405b9c5b7f2 100644
--- a/net/x25/x25_proc.c
+++ b/net/x25/x25_proc.c
@@ -234,21 +234,21 @@ out:
return 0;
}
-static struct seq_operations x25_seq_route_ops = {
+static const struct seq_operations x25_seq_route_ops = {
.start = x25_seq_route_start,
.next = x25_seq_route_next,
.stop = x25_seq_route_stop,
.show = x25_seq_route_show,
};
-static struct seq_operations x25_seq_socket_ops = {
+static const struct seq_operations x25_seq_socket_ops = {
.start = x25_seq_socket_start,
.next = x25_seq_socket_next,
.stop = x25_seq_socket_stop,
.show = x25_seq_socket_show,
};
-static struct seq_operations x25_seq_forward_ops = {
+static const struct seq_operations x25_seq_forward_ops = {
.start = x25_seq_forward_start,
.next = x25_seq_forward_next,
.stop = x25_seq_forward_stop,
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 5c4695840c58..113f44429982 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -83,5 +83,5 @@ void __init xfrm_input_init(void)
secpath_cachep = kmem_cache_create("secpath_cache",
sizeof(struct sec_path),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
}
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 157bfbd250ba..c3a4b0a18687 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -857,7 +857,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
pol, NULL);
return err;
}
- }
+ }
for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
hlist_for_each_entry(pol, entry,
xfrm_policy_bydst[dir].table + i,
@@ -2141,7 +2141,7 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
if (last == first)
break;
- last = last->u.next;
+ last = (struct xfrm_dst *)last->u.dst.next;
last->child_mtu_cached = mtu;
}
@@ -2378,7 +2378,7 @@ static void __init xfrm_policy_init(void)
xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
sizeof(struct xfrm_dst),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
- NULL, NULL);
+ NULL);
hmask = 8 - 1;
sz = (hmask+1) * sizeof(struct hlist_head);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index dfacb9c2a6e3..38f90ca75b1e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -407,7 +407,7 @@ xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info)
xfrm_audit_log(audit_info->loginuid,
audit_info->secid,
AUDIT_MAC_IPSEC_DELSA,
- 0, NULL, x);
+ 0, NULL, x);
return err;
}
@@ -686,6 +686,37 @@ out:
return x;
}
+struct xfrm_state *
+xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
+ unsigned short family, u8 mode, u8 proto, u32 reqid)
+{
+ unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family);
+ struct xfrm_state *rx = NULL, *x = NULL;
+ struct hlist_node *entry;
+
+ spin_lock(&xfrm_state_lock);
+ hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
+ if (x->props.family == family &&
+ x->props.reqid == reqid &&
+ !(x->props.flags & XFRM_STATE_WILDRECV) &&
+ xfrm_state_addr_check(x, daddr, saddr, family) &&
+ mode == x->props.mode &&
+ proto == x->id.proto &&
+ x->km.state == XFRM_STATE_VALID) {
+ rx = x;
+ break;
+ }
+ }
+
+ if (rx)
+ xfrm_state_hold(rx);
+ spin_unlock(&xfrm_state_lock);
+
+
+ return rx;
+}
+EXPORT_SYMBOL(xfrm_stateonly_find);
+
static void __xfrm_state_insert(struct xfrm_state *x)
{
unsigned int h;
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 06c1a377c4c5..677bc6c175cb 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -100,9 +100,14 @@ cc-option-align = $(subst -functions=0,,\
$(call cc-option,-falign-functions=0,-malign-functions=0))
# cc-version
-# Usage gcc-ver := $(call cc-version,$(CC))
+# Usage gcc-ver := $(call cc-version)
cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
+# cc-fullversion
+# Usage gcc-ver := $(call cc-fullversion)
+cc-fullversion = $(shell $(CONFIG_SHELL) \
+ $(srctree)/scripts/gcc-version.sh -p $(CC))
+
# cc-ifversion
# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
diff --git a/scripts/Lindent b/scripts/Lindent
index 7d8d8896e309..9468ec7971db 100755
--- a/scripts/Lindent
+++ b/scripts/Lindent
@@ -1,2 +1,2 @@
#!/bin/sh
-indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs "$@"
+indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 "$@"
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index a525112847fd..3f7b451f3955 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -7,6 +7,22 @@ src := $(obj)
PHONY := __build
__build:
+# Init all relevant variables used in kbuild files so
+# 1) they have correct type
+# 2) they do not inherit any value from the environment
+obj-y :=
+obj-m :=
+lib-y :=
+lib-m :=
+always :=
+targets :=
+subdir-y :=
+subdir-m :=
+EXTRA_AFLAGS :=
+EXTRA_CFLAGS :=
+EXTRA_CPPFLAGS :=
+EXTRA_LDFLAGS :=
+
# Read .config if it exist, otherwise ignore
-include include/config/auto.conf
diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
index f98d772aac80..53dae3eb3d1f 100644
--- a/scripts/Makefile.headersinst
+++ b/scripts/Makefile.headersinst
@@ -11,13 +11,13 @@ UNIFDEF := scripts/unifdef -U__KERNEL__
# Eliminate the contents of (and inclusions of) compiler.h
HDRSED := sed -e "s/ inline / __inline__ /g" \
- -e "s/[[:space:]]__user[[:space:]]\+/ /g" \
- -e "s/(__user[[:space:]]\+/ (/g" \
- -e "s/[[:space:]]__force[[:space:]]\+/ /g" \
- -e "s/(__force[[:space:]]\+/ (/g" \
- -e "s/[[:space:]]__iomem[[:space:]]\+/ /g" \
- -e "s/(__iomem[[:space:]]\+/ (/g" \
- -e "s/[[:space:]]__attribute_const__[[:space:]]\+/\ /g" \
+ -e "s/[[:space:]]__user[[:space:]]\{1,\}/ /g" \
+ -e "s/(__user[[:space:]]\{1,\}/ (/g" \
+ -e "s/[[:space:]]__force[[:space:]]\{1,\}/ /g" \
+ -e "s/(__force[[:space:]]\{1,\}/ (/g" \
+ -e "s/[[:space:]]__iomem[[:space:]]\{1,\}/ /g" \
+ -e "s/(__iomem[[:space:]]\{1,\}/ (/g" \
+ -e "s/[[:space:]]__attribute_const__[[:space:]]\{1,\}/\ /g" \
-e "s/[[:space:]]__attribute_const__$$//" \
-e "/^\#include <linux\/compiler.h>/d"
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index d5bbbcce31ef..c6fcc597b3be 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -70,10 +70,10 @@ __modpost: $(modules:.ko=.o) FORCE
$(call cmd,modpost) $(wildcard vmlinux) $(filter-out FORCE,$^)
quiet_cmd_kernel-mod = MODPOST $@
- cmd_kernel-mod = $(cmd_modpost) $(KBUILD_VMLINUX_OBJS)
+ cmd_kernel-mod = $(cmd_modpost) $@
PHONY += vmlinux
-vmlinux: FORCE
+vmlinux.o: FORCE
$(call cmd,kernel-mod)
# Declare generated files as targets for modpost
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 277c32647f36..73751ab6ec0c 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -9,7 +9,7 @@ use strict;
my $P = $0;
$P =~ s@.*/@@g;
-my $V = '0.06';
+my $V = '0.08';
use Getopt::Long qw(:config no_auto_abbrev);
@@ -47,16 +47,14 @@ my $removal = 'Documentation/feature-removal-schedule.txt';
if ($tree && -f $removal) {
open(REMOVE, "<$removal") || die "$P: $removal: open failed - $!\n";
while (<REMOVE>) {
- if (/^Files:\s+(.*\S)/) {
- for my $file (split(/[, ]+/, $1)) {
- if ($file =~ m@include/(.*)@) {
+ if (/^Check:\s+(.*\S)/) {
+ for my $entry (split(/[, ]+/, $1)) {
+ if ($entry =~ m@include/(.*)@) {
push(@dep_includes, $1);
- }
- }
- } elsif (/^Funcs:\s+(.*\S)/) {
- for my $func (split(/[, ]+/, $1)) {
- push(@dep_functions, $func);
+ } elsif ($entry !~ m@/@) {
+ push(@dep_functions, $entry);
+ }
}
}
}
@@ -153,7 +151,7 @@ sub sanitise_line {
}
sub ctx_block_get {
- my ($linenr, $remain, $outer, $open, $close) = @_;
+ my ($linenr, $remain, $outer, $open, $close, $off) = @_;
my $line;
my $start = $linenr - 1;
my $blk = '';
@@ -161,38 +159,58 @@ sub ctx_block_get {
my @c;
my @res = ();
+ my $level = 0;
for ($line = $start; $remain > 0; $line++) {
next if ($rawlines[$line] =~ /^-/);
$remain--;
$blk .= $rawlines[$line];
+ foreach my $c (split(//, $rawlines[$line])) {
+ ##print "C<$c>L<$level><$open$close>O<$off>\n";
+ if ($off > 0) {
+ $off--;
+ next;
+ }
- @o = ($blk =~ /$open/g);
- @c = ($blk =~ /$close/g);
+ if ($c eq $close && $level > 0) {
+ $level--;
+ last if ($level == 0);
+ } elsif ($c eq $open) {
+ $level++;
+ }
+ }
- if (!$outer || (scalar(@o) - scalar(@c)) == 1) {
+ if (!$outer || $level <= 1) {
push(@res, $rawlines[$line]);
}
- last if (scalar(@o) == scalar(@c));
+ last if ($level == 0);
}
- return @res;
+ return ($level, @res);
}
sub ctx_block_outer {
my ($linenr, $remain) = @_;
- return ctx_block_get($linenr, $remain, 1, '\{', '\}');
+ my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+ return @r;
}
sub ctx_block {
my ($linenr, $remain) = @_;
- return ctx_block_get($linenr, $remain, 0, '\{', '\}');
+ my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+ return @r;
}
sub ctx_statement {
+ my ($linenr, $remain, $off) = @_;
+
+ my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+ return @r;
+}
+sub ctx_block_level {
my ($linenr, $remain) = @_;
- return ctx_block_get($linenr, $remain, 0, '\(', '\)');
+ return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
}
sub ctx_locate_comment {
@@ -246,6 +264,26 @@ sub cat_vet {
return $vet;
}
+my @report = ();
+sub report {
+ push(@report, $_[0]);
+}
+sub report_dump {
+ @report;
+}
+sub ERROR {
+ report("ERROR: $_[0]\n");
+ our $clean = 0;
+}
+sub WARN {
+ report("WARNING: $_[0]\n");
+ our $clean = 0;
+}
+sub CHK {
+ report("CHECK: $_[0]\n");
+ our $clean = 0;
+}
+
sub process {
my $filename = shift;
my @lines = @_;
@@ -259,7 +297,7 @@ sub process {
my $previndent=0;
my $stashindent=0;
- my $clean = 1;
+ our $clean = 1;
my $signoff = 0;
my $is_patch = 0;
@@ -290,8 +328,11 @@ sub process {
long\s+int|
long\s+long|
long\s+long\s+int|
+ u8|u16|u32|u64|
+ s8|s16|s32|s64|
struct\s+$Ident|
union\s+$Ident|
+ enum\s+$Ident|
${Ident}_t
)
(?:\s+$Sparse)*
@@ -302,7 +343,27 @@ sub process {
(?:\s*\*+\s*const|\s*\*+)?
}x;
my $Declare = qr{(?:$Storage\s+)?$Type};
- my $Attribute = qr{__read_mostly|__init|__initdata};
+ my $Attribute = qr{const|__read_mostly|__init|__initdata|__meminit};
+
+ my $Member = qr{->$Ident|\.$Ident|\[[^]]*\]};
+ my $Lval = qr{$Ident(?:$Member)*};
+
+ # Pre-scan the patch looking for any __setup documentation.
+ my @setup_docs = ();
+ my $setup_docs = 0;
+ foreach my $line (@lines) {
+ if ($line=~/^\+\+\+\s+(\S+)/) {
+ $setup_docs = 0;
+ if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
+ $setup_docs = 1;
+ }
+ next;
+ }
+
+ if ($setup_docs && $line =~ /^\+/) {
+ push(@setup_docs, $line);
+ }
+ }
foreach my $line (@lines) {
$linenr++;
@@ -369,30 +430,42 @@ sub process {
$here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
my $hereline = "$here\n$line\n";
- my $herecurr = "$here\n$line\n\n";
- my $hereprev = "$here\n$prevline\n$line\n\n";
+ my $herecurr = "$here\n$line\n";
+ my $hereprev = "$here\n$prevline\n$line\n";
#check the patch for a signoff:
if ($line =~ /^\s*signed-off-by:/i) {
# This is a signoff, if ugly, so do not double report.
$signoff++;
if (!($line =~ /^\s*Signed-off-by:/)) {
- print "Signed-off-by: is the preferred form\n";
- print "$herecurr";
- $clean = 0;
+ WARN("Signed-off-by: is the preferred form\n" .
+ $herecurr);
}
if ($line =~ /^\s*signed-off-by:\S/i) {
- print "need space after Signed-off-by:\n";
- print "$herecurr";
- $clean = 0;
+ WARN("need space after Signed-off-by:\n" .
+ $herecurr);
}
}
# Check for wrappage within a valid hunk of the file
if ($realcnt != 0 && $line !~ m{^(?:\+|-| |$)}) {
- print "patch seems to be corrupt (line wrapped?) [$realcnt]\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("patch seems to be corrupt (line wrapped?)\n" .
+ $herecurr);
+ }
+
+# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+ if (($realfile =~ /^$/ || $line =~ /^\+/) &&
+ !($line =~ m/^(
+ [\x09\x0A\x0D\x20-\x7E] # ASCII
+ | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
+ | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
+ | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
+ | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
+ | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
+ | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
+ | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
+ )*$/x )) {
+ ERROR("Invalid UTF-8\n" . $herecurr);
}
#ignore lines being removed
@@ -403,16 +476,12 @@ sub process {
#trailing whitespace
if ($line =~ /^\+.*\S\s+$/ || $line =~ /^\+\s+$/) {
- my $herevet = "$here\n" . cat_vet($line) . "\n\n";
- print "trailing whitespace\n";
- print "$herevet";
- $clean = 0;
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("trailing whitespace\n" . $herevet);
}
#80 column limit
if ($line =~ /^\+/ && !($prevline=~/\/\*\*/) && $length > 80) {
- print "line over 80 characters\n";
- print "$herecurr";
- $clean = 0;
+ WARN("line over 80 characters\n" . $herecurr);
}
# check we are in a valid source file *.[hc] if not then ignore this hunk
@@ -421,10 +490,8 @@ sub process {
# at the beginning of a line any tabs must come first and anything
# more than 8 must use tabs.
if ($line=~/^\+\s* \t\s*\S/ or $line=~/^\+\s* \s*/) {
- my $herevet = "$here\n" . cat_vet($line) . "\n\n";
- print "use tabs not spaces\n";
- print "$herevet";
- $clean = 0;
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("use tabs not spaces\n" . $herevet);
}
#
@@ -463,9 +530,27 @@ sub process {
}
}
if ($err ne '') {
- print "switch and case should be at the same indent\n";
- print "$here\n$line\n$err\n";
- $clean = 0;
+ ERROR("switch and case should be at the same indent\n$hereline\n$err\n");
+ }
+ }
+
+# if/while/etc brace do not go on next line, unless defining a do while loop,
+# or if that brace on the next line is for something else
+ if ($line =~ /\b(?:(if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.#/) {
+ my @ctx = ctx_statement($linenr, $realcnt, 0);
+ my $ctx_ln = $linenr + $#ctx + 1;
+ my $ctx_cnt = $realcnt - $#ctx - 1;
+ my $ctx = join("\n", @ctx);
+
+ while ($ctx_cnt > 0 && $lines[$ctx_ln - 1] =~ /^-/) {
+ $ctx_ln++;
+ $ctx_cnt--;
+ }
+ ##warn "line<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>";
+
+ if ($ctx !~ /{\s*/ && $ctx_cnt > 0 && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+ ERROR("That open brace { should be on the previous line\n" .
+ "$here\n$ctx\n$lines[$ctx_ln - 1]");
}
}
@@ -474,12 +559,16 @@ sub process {
# TEST: allow direct testing of the type matcher.
if ($tst_type && $line =~ /^.$Declare$/) {
- print "TEST: is type $Declare\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("TEST: is type $Declare\n" . $herecurr);
next;
}
+# check for initialisation to aggregates open brace on the next line
+ if ($prevline =~ /$Declare\s*$Ident\s*=\s*$/ &&
+ $line =~ /^.\s*{/) {
+ ERROR("That open brace { should be on the previous line\n" . $hereprev);
+ }
+
#
# Checks which are anchored on the added line.
#
@@ -488,9 +577,8 @@ sub process {
if ($rawline =~ m{^.#\s*include\s+[<"](.*)[">]}) {
my $path = $1;
if ($path =~ m{//}) {
- print "malformed #include filename\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("malformed #include filename\n" .
+ $herecurr);
}
# Sanitise this special form of string.
$path = 'X' x length($path);
@@ -499,9 +587,7 @@ sub process {
# no C99 // comments
if ($line =~ m{//}) {
- print "do not use C99 // comments\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("do not use C99 // comments\n" . $herecurr);
}
# Remove C99 comments.
$line =~ s@//.*@@;
@@ -514,49 +600,45 @@ sub process {
($prevline !~ /^\+}/) &&
($prevline !~ /^ }/) &&
($prevline !~ /\s$name(?:\s+$Attribute)?\s*(?:;|=)/)) {
- print "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n";
- print "$herecurr";
- $clean = 0;
+ WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
}
}
+# check for external initialisers.
+ if ($line =~ /^.$Type\s*$Ident\s*=\s*(0|NULL);/) {
+ ERROR("do not initialise externals to 0 or NULL\n" .
+ $herecurr);
+ }
# check for static initialisers.
- if ($line=~/\s*static\s.*=\s+(0|NULL);/) {
- print "do not initialise statics to 0 or NULL\n";
- print "$herecurr";
- $clean = 0;
+ if ($line =~ /\s*static\s.*=\s*(0|NULL);/) {
+ ERROR("do not initialise statics to 0 or NULL\n" .
+ $herecurr);
}
# check for new typedefs, only function parameters and sparse annotations
# make sense.
if ($line =~ /\btypedef\s/ &&
- $line !~ /\btypedef\s+$Type\s+\(\s*$Ident\s*\)\s*\(/ &&
+ $line !~ /\btypedef\s+$Type\s+\(\s*\*$Ident\s*\)\s*\(/ &&
$line !~ /\b__bitwise(?:__|)\b/) {
- print "do not add new typedefs\n";
- print "$herecurr";
- $clean = 0;
+ WARN("do not add new typedefs\n" . $herecurr);
}
# * goes on variable not on type
if ($line =~ m{\($NonptrType(\*+)(?:\s+const)?\)}) {
- print "\"(foo$1)\" should be \"(foo $1)\"\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("\"(foo$1)\" should be \"(foo $1)\"\n" .
+ $herecurr);
} elsif ($line =~ m{\($NonptrType\s+(\*+)(?!\s+const)\s+\)}) {
- print "\"(foo $1 )\" should be \"(foo $1)\"\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("\"(foo $1 )\" should be \"(foo $1)\"\n" .
+ $herecurr);
- } elsif ($line =~ m{$NonptrType(\*+)(?:\s+const)?\s+[A-Za-z\d_]+}) {
- print "\"foo$1 bar\" should be \"foo $1bar\"\n";
- print "$herecurr";
- $clean = 0;
+ } elsif ($line =~ m{$NonptrType(\*+)(?:\s+$Attribute)?\s+[A-Za-z\d_]+}) {
+ ERROR("\"foo$1 bar\" should be \"foo $1bar\"\n" .
+ $herecurr);
- } elsif ($line =~ m{$NonptrType\s+(\*+)(?!\s+const)\s+[A-Za-z\d_]+}) {
- print "\"foo $1 bar\" should be \"foo $1bar\"\n";
- print "$herecurr";
- $clean = 0;
+ } elsif ($line =~ m{$NonptrType\s+(\*+)(?!\s+$Attribute)\s+[A-Za-z\d_]+}) {
+ ERROR("\"foo $1 bar\" should be \"foo $1bar\"\n" .
+ $herecurr);
}
# # no BUG() or BUG_ON()
@@ -571,7 +653,7 @@ sub process {
# to try and find and validate the current printk. In summary the current
# printk includes all preceeding printk's which have no newline on the end.
# we assume the first bad printk is the one to report.
- if ($line =~ /\bprintk\((?!KERN_)/) {
+ if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
my $ok = 0;
for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
#print "CHECK<$lines[$ln - 1]\n";
@@ -585,9 +667,7 @@ sub process {
}
}
if ($ok == 0) {
- print "printk() should include KERN_ facility level\n";
- print "$herecurr";
- $clean = 0;
+ WARN("printk() should include KERN_ facility level\n" . $herecurr);
}
}
@@ -595,11 +675,15 @@ sub process {
# or if closed on same line
if (($line=~/$Type\s*[A-Za-z\d_]+\(.*\).* {/) and
!($line=~/\#define.*do\s{/) and !($line=~/}/)) {
- print "braces following function declarations go on the next line\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("open brace '{' following function declarations go on the next line\n" . $herecurr);
}
+# check for spaces between functions and their parentheses.
+ if ($line =~ /($Ident)\s+\(/ &&
+ $1 !~ /^(?:if|for|while|switch|return|volatile)$/ &&
+ $line !~ /$Type\s+\(/ && $line !~ /^.\#\s*define\b/) {
+ ERROR("no space between function name and open parenthesis '('\n" . $herecurr);
+ }
# Check operator spacing.
# Note we expand the line with the leading + as the real
# line will be displayed with the leading + and the tabs
@@ -608,7 +692,7 @@ sub process {
$opline = expand_tabs($opline);
$opline =~ s/^./ /;
if (!($line=~/\#\s*include/)) {
- my @elements = split(/(<<=|>>=|<=|>=|==|!=|\+=|-=|\*=|\/=|%=|\^=|\|=|&=|->|<<|>>|<|>|=|!|~|&&|\|\||,|\^|\+\+|--|;|&|\||\+|-|\*|\/\/|\/)/, $opline);
+ my @elements = split(/(<<=|>>=|<=|>=|==|!=|\+=|-=|\*=|\/=|%=|\^=|\|=|&=|=>|->|<<|>>|<|>|=|!|~|&&|\|\||,|\^|\+\+|--|;|&|\||\+|-|\*|\/\/|\/)/, $opline);
my $off = 0;
for (my $n = 0; $n < $#elements; $n += 2) {
$off += length($elements[$n]);
@@ -633,27 +717,27 @@ sub process {
}
# Pick up the preceeding and succeeding characters.
- my $ca = substr($opline, $off - 1, 1);
+ my $ca = substr($opline, 0, $off);
my $cc = '';
if (length($opline) >= ($off + length($elements[$n + 1]))) {
$cc = substr($opline, $off + length($elements[$n + 1]));
}
+ my $cb = "$ca$;$cc";
my $ctx = "${a}x${c}";
my $at = "(ctx:$ctx)";
my $ptr = (" " x $off) . "^";
- my $hereptr = "$hereline$ptr\n\n";
+ my $hereptr = "$hereline$ptr\n";
##print "<$s1:$op:$s2> <$elements[$n]:$elements[$n + 1]:$elements[$n + 2]>\n";
# ; should have either the end of line or a space or \ after it
if ($op eq ';') {
- if ($ctx !~ /.x[WE]/ && $cc !~ /^\\/) {
- print "need space after that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ if ($ctx !~ /.x[WEB]/ && $cc !~ /^\\/ &&
+ $cc !~ /^;/) {
+ ERROR("need space after that '$op' $at\n" . $hereptr);
}
# // is a comment
@@ -662,43 +746,31 @@ sub process {
# -> should have no spaces
} elsif ($op eq '->') {
if ($ctx =~ /Wx.|.xW/) {
- print "no spaces around that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("no spaces around that '$op' $at\n" . $hereptr);
}
# , must have a space on the right.
} elsif ($op eq ',') {
if ($ctx !~ /.xW|.xE/ && $cc !~ /^}/) {
- print "need space after that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("need space after that '$op' $at\n" . $hereptr);
}
# unary ! and unary ~ are allowed no space on the right
} elsif ($op eq '!' or $op eq '~') {
if ($ctx !~ /[WOEB]x./) {
- print "need space before that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("need space before that '$op' $at\n" . $hereptr);
}
if ($ctx =~ /.xW/) {
- print "no space after that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("no space after that '$op' $at\n" . $hereptr);
}
# unary ++ and unary -- are allowed no space on one side.
} elsif ($op eq '++' or $op eq '--') {
if ($ctx !~ /[WOB]x[^W]/ && $ctx !~ /[^W]x[WOBE]/) {
- print "need space one side of that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("need space one side of that '$op' $at\n" . $hereptr);
}
if ($ctx =~ /Wx./ && $cc =~ /^;/) {
- print "no space before that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("no space before that '$op' $at\n" . $hereptr);
}
# & is both unary and binary
@@ -715,9 +787,7 @@ sub process {
#
} elsif ($op eq '&' or $op eq '-') {
if ($ctx !~ /VxV|[EW]x[WE]|[EWB]x[VO]/) {
- print "need space before that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("need space before that '$op' $at\n" . $hereptr);
}
# * is the same as & only adding:
@@ -726,16 +796,9 @@ sub process {
# (foo **)
#
} elsif ($op eq '*') {
- if ($ca eq '*') {
- if ($cc =~ /^\s(?!\s*const)/) {
- print "no space after that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
- }
- } elsif ($ctx !~ /VxV|[EW]x[WE]|[EWB]x[VO]|OxV|WxB|BxB/) {
- print "need space before that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ if ($ca !~ /$Type$/ && $cb !~ /(\*$;|$;\*)/ &&
+ $ctx !~ /VxV|[EW]x[WE]|[EWB]x[VO]|OxV|WxB|BxB/) {
+ ERROR("need space before that '$op' $at\n" . $hereptr);
}
# << and >> may either have or not have spaces both sides
@@ -743,58 +806,63 @@ sub process {
$op eq '^' or $op eq '|')
{
if ($ctx !~ /VxV|WxW|VxE|WxE/) {
- print "need consistent spacing around '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("need consistent spacing around '$op' $at\n" .
+ $hereptr);
}
# All the others need spaces both sides.
} elsif ($ctx !~ /[EW]x[WE]/) {
- print "need spaces around that '$op' $at\n";
- print "$hereptr";
- $clean = 0;
+ ERROR("need spaces around that '$op' $at\n" . $hereptr);
}
$off += length($elements[$n + 1]);
}
}
+# check for multiple assignments
+ if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+ WARN("multiple assignments should be avoided\n" . $herecurr);
+ }
+
+# check for multiple declarations, allowing for a function declaration
+# continuation.
+ if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+ $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+ WARN("declaring multiple variables together should be avoided\n" . $herecurr);
+ }
+
#need space before brace following if, while, etc
- if ($line=~/\(.*\){/) {
- print "need a space before the brace\n";
- print "$herecurr";
- $clean = 0;
+ if ($line =~ /\(.*\){/ || $line =~ /do{/) {
+ ERROR("need a space before the open brace '{'\n" . $herecurr);
+ }
+
+# closing brace should have a space following it when it has anything
+# on the line
+ if ($line =~ /}(?!(?:,|;|\)))\S/) {
+ ERROR("need a space after that close brace '}'\n" . $herecurr);
}
#goto labels aren't indented, allow a single space however
if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
!($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
- print "labels should not be indented\n";
- print "$herecurr";
- $clean = 0;
+ WARN("labels should not be indented\n" . $herecurr);
}
# Need a space before open parenthesis after if, while etc
if ($line=~/\b(if|while|for|switch)\(/) {
- print "need a space before the open parenthesis\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("need a space before the open parenthesis '('\n" . $herecurr);
}
# Check for illegal assignment in if conditional.
if ($line=~/\bif\s*\(.*[^<>!=]=[^=].*\)/) {
#next if ($line=~/\".*\Q$op\E.*\"/ or $line=~/\'\Q$op\E\'/);
- print "do not use assignment in if condition\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("do not use assignment in if condition\n" . $herecurr);
}
# Check for }<nl>else {, these must be at the same
# indent level to be relevant to each other.
if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
$previndent == $indent) {
- print "else should follow close brace\n";
- print "$hereprev";
- $clean = 0;
+ ERROR("else should follow close brace '}'\n" . $hereprev);
}
#studly caps, commented out until figure out how to distinguish between use of existing and adding new
@@ -806,57 +874,22 @@ sub process {
#no spaces allowed after \ in define
if ($line=~/\#define.*\\\s$/) {
- print("Whitepspace after \\ makes next lines useless\n");
- print "$herecurr";
- $clean = 0;
+ WARN("Whitepspace after \\ makes next lines useless\n" . $herecurr);
}
#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
if ($tree && $rawline =~ m{^.\#\s*include\s*\<asm\/(.*)\.h\>}) {
my $checkfile = "include/linux/$1.h";
if (-f $checkfile) {
- print "Use #include <linux/$1.h> instead of <asm/$1.h>\n";
- print $herecurr;
- $clean = 0;
- }
- }
-
-# if/while/etc brace do not go on next line, unless defining a do while loop,
-# or if that brace on the next line is for something else
- if ($prevline=~/\b(?:(if|while|for|switch)\s*\(|do\b|else\b)/) {
- my @opened = $prevline=~/\(/g;
- my @closed = $prevline=~/\)/g;
- my $nr_line = $linenr;
- my $remaining = $realcnt - 1;
- my $next_line = $line;
- my $extra_lines = 0;
- my $display_segment = $prevline;
-
- while ($remaining > 0 && scalar @opened > scalar @closed) {
- $prevline .= $next_line;
- $display_segment .= "\n" . $next_line;
- $next_line = $lines[$nr_line];
- $nr_line++;
- $remaining--;
-
- @opened = $prevline=~/\(/g;
- @closed = $prevline=~/\)/g;
- }
-
- if (($prevline=~/\b(?:(if|while|for|switch)\s*\(.*\)|do|else)\s*$/) and ($next_line=~/{/) and
- !($next_line=~/\b(?:if|while|for|switch|do|else)\b/) and !($next_line=~/\#define.*do.*while/)) {
- print "That { should be on the previous line\n";
- print "$here\n$display_segment\n$next_line\n\n";
- $clean = 0;
+ CHK("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
+ $herecurr);
}
}
# if and else should not have general statements after it
if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/ &&
- $1 !~ /^\s*(?:\sif|{|$)/) {
- print "trailing statements should be on next line\n";
- print "$herecurr";
- $clean = 0;
+ $1 !~ /^\s*(?:\sif|{|\\|$)/) {
+ ERROR("trailing statements should be on next line\n" . $herecurr);
}
# multi-statement macros should be enclosed in a do while loop, grab the
@@ -871,55 +904,106 @@ sub process {
# or the one below.
my $ln = $linenr;
my $cnt = $realcnt;
+ my $off = 0;
- # If the macro starts on the define line start there.
- if ($prevline !~ m{^.#\s*define\s*$Ident(?:\([^\)]*\))?\s*\\\s*$}) {
+ # If the macro starts on the define line start
+ # grabbing the statement after the identifier
+ $prevline =~ m{^(.#\s*define\s*$Ident(?:\([^\)]*\))?\s*)(.*)\\\s*$};
+ ##print "1<$1> 2<$2>\n";
+ if ($2 ne '') {
+ $off = length($1);
$ln--;
$cnt++;
}
- my $ctx = join('', ctx_statement($ln, $cnt));
+ my @ctx = ctx_statement($ln, $cnt, $off);
+ my $ctx_ln = $ln + $#ctx + 1;
+ my $ctx = join("\n", @ctx);
+
+ # Pull in any empty extension lines.
+ while ($ctx =~ /\\$/ &&
+ $lines[$ctx_ln - 1] =~ /^.\s*(?:\\)?$/) {
+ $ctx .= $lines[$ctx_ln - 1];
+ $ctx_ln++;
+ }
if ($ctx =~ /\\$/) {
if ($ctx =~ /;/) {
- print "Macros with multiple statements should be enclosed in a do - while loop\n";
+ ERROR("Macros with multiple statements should be enclosed in a do - while loop\n" . "$here\n$ctx\n");
} else {
- print "Macros with complex values should be enclosed in parenthesis\n";
+ ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
+ }
+ }
+ }
+
+# check for redundant bracing round if etc
+ if ($line =~ /\b(if|while|for|else)\b/) {
+ # Locate the end of the opening statement.
+ my @control = ctx_statement($linenr, $realcnt, 0);
+ my $nr = $linenr + (scalar(@control) - 1);
+ my $cnt = $realcnt - (scalar(@control) - 1);
+
+ my $off = $realcnt - $cnt;
+ #print "$off: line<$line>end<" . $lines[$nr - 1] . ">\n";
+
+ # If this is is a braced statement group check it
+ if ($lines[$nr - 1] =~ /{\s*$/) {
+ my ($lvl, @block) = ctx_block_level($nr, $cnt);
+
+ my $stmt = join(' ', @block);
+ $stmt =~ s/^[^{]*{//;
+ $stmt =~ s/}[^}]*$//;
+
+ #print "block<" . join(' ', @block) . "><" . scalar(@block) . ">\n";
+ #print "stmt<$stmt>\n\n";
+
+ # Count the ;'s if there is fewer than two
+ # then there can only be one statement,
+ # if there is a brace inside we cannot
+ # trivially detect if its one statement.
+ # Also nested if's often require braces to
+ # disambiguate the else binding so shhh there.
+ my @semi = ($stmt =~ /;/g);
+ ##print "semi<" . scalar(@semi) . ">\n";
+ if ($lvl == 0 && scalar(@semi) < 2 &&
+ $stmt !~ /{/ && $stmt !~ /\bif\b/) {
+ my $herectx = "$here\n" . join("\n", @control, @block[1 .. $#block]) . "\n";
+ shift(@block);
+ ERROR("braces {} are not necessary for single statement blocks\n" . $herectx);
}
- print "$hereprev";
- $clean = 0;
}
}
# don't include deprecated include files (uses RAW line)
for my $inc (@dep_includes) {
if ($rawline =~ m@\#\s*include\s*\<$inc>@) {
- print "Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("Don't use <$inc>: see Documentation/feature-removal-schedule.txt\n" . $herecurr);
}
}
# don't use deprecated functions
for my $func (@dep_functions) {
if ($line =~ /\b$func\b/) {
- print "Don't use $func(): see Documentation/feature-removal-schedule.txt\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("Don't use $func(): see Documentation/feature-removal-schedule.txt\n" . $herecurr);
}
}
# no volatiles please
if ($line =~ /\bvolatile\b/ && $line !~ /\basm\s+volatile\b/) {
- print "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n";
- print "$herecurr";
- $clean = 0;
+ WARN("Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
}
# warn about #if 0
if ($line =~ /^.#\s*if\s+0\b/) {
- print "#if 0 -- if this code redundant remove it\n";
- print "$herecurr";
- $clean = 0;
+ CHK("if this code is redundant consider removing it\n" .
+ $herecurr);
+ }
+
+# check for needless kfree() checks
+ if ($prevline =~ /\bif\s*\(([^\)]*)\)/) {
+ my $expr = $1;
+ if ($line =~ /\bkfree\(\Q$expr\E\);/) {
+ WARN("kfree(NULL) is safe this check is probabally not required\n" . $hereprev);
+ }
}
# warn about #ifdefs in C files
@@ -933,43 +1017,52 @@ sub process {
if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/) {
my $which = $1;
if (!ctx_has_comment($first_line, $linenr)) {
- print "$1 definition without comment\n";
- print "$herecurr";
- $clean = 0;
+ CHK("$1 definition without comment\n" . $herecurr);
}
}
# check for memory barriers without a comment.
if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
if (!ctx_has_comment($first_line, $linenr)) {
- print "memory barrier without comment\n";
- print "$herecurr";
- $clean = 0;
+ CHK("memory barrier without comment\n" . $herecurr);
}
}
# check of hardware specific defines
if ($line =~ m@^.#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@) {
- print "architecture specific defines should be avoided\n";
- print "$herecurr";
- $clean = 0;
+ CHK("architecture specific defines should be avoided\n" . $herecurr);
}
+# check the location of the inline attribute, that it is between
+# storage class and type.
if ($line =~ /$Type\s+(?:inline|__always_inline)\b/ ||
$line =~ /\b(?:inline|always_inline)\s+$Storage/) {
- print "inline keyword should sit between storage class and type\n";
- print "$herecurr";
- $clean = 0;
+ ERROR("inline keyword should sit between storage class and type\n" . $herecurr);
+ }
+
+# check for new externs in .c files.
+ if ($line =~ /^.\s*extern\s/ && ($realfile =~ /\.c$/)) {
+ WARN("externs should be avoided in .c files\n" . $herecurr);
+ }
+
+# checks for new __setup's
+ if ($rawline =~ /\b__setup\("([^"]*)"/) {
+ my $name = $1;
+
+ if (!grep(/$name/, @setup_docs)) {
+ CHK("__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
+ }
}
}
if ($chk_patch && !$is_patch) {
- $clean = 0;
- print "Does not appear to be a unified-diff format patch\n";
+ ERROR("Does not appear to be a unified-diff format patch\n");
}
if ($is_patch && $chk_signoff && $signoff == 0) {
- $clean = 0;
- print "Missing Signed-off-by: line(s)\n";
+ ERROR("Missing Signed-off-by: line(s)\n");
}
+ if ($clean == 0 && ($chk_patch || $is_patch)) {
+ print report_dump();
+ }
if ($clean == 1 && $quiet == 0) {
print "Your patch has no obvious style problems and is ready for submission.\n"
}
diff --git a/scripts/cleanfile b/scripts/cleanfile
index f1ba8aa58a40..cefd29e52298 100755
--- a/scripts/cleanfile
+++ b/scripts/cleanfile
@@ -7,7 +7,9 @@
use bytes;
use File::Basename;
-#
+# Default options
+$max_width = 79;
+
# Clean up space-tab sequences, either by removing spaces or
# replacing them with tabs.
sub clean_space_tabs($)
@@ -48,9 +50,49 @@ sub clean_space_tabs($)
return $lo;
}
+# Compute the visual width of a string
+sub strwidth($) {
+ no bytes; # Tab alignment depends on characters
+
+ my($li) = @_;
+ my($c, $i);
+ my $pos = 0;
+ my $mlen = 0;
+
+ for ($i = 0; $i < length($li); $i++) {
+ $c = substr($li,$i,1);
+ if ($c eq "\t") {
+ $pos = ($pos+8) & ~7;
+ } elsif ($c eq "\n") {
+ $mlen = $pos if ($pos > $mlen);
+ $pos = 0;
+ } else {
+ $pos++;
+ }
+ }
+
+ $mlen = $pos if ($pos > $mlen);
+ return $mlen;
+}
+
$name = basename($0);
-foreach $f ( @ARGV ) {
+@files = ();
+
+while (defined($a = shift(@ARGV))) {
+ if ($a =~ /^-/) {
+ if ($a eq '-width' || $a eq '-w') {
+ $max_width = shift(@ARGV)+0;
+ } else {
+ print STDERR "Usage: $name [-width #] files...\n";
+ exit 1;
+ }
+ } else {
+ push(@files, $a);
+ }
+}
+
+foreach $f ( @files ) {
print STDERR "$name: $f\n";
if (! -f $f) {
@@ -90,8 +132,10 @@ foreach $f ( @ARGV ) {
@blanks = ();
@lines = ();
+ $lineno = 0;
while ( defined($line = <FILE>) ) {
+ $lineno++;
$in_bytes += length($line);
$line =~ s/[ \t\r]*$//; # Remove trailing spaces
$line = clean_space_tabs($line);
@@ -107,6 +151,12 @@ foreach $f ( @ARGV ) {
@blanks = ();
$blank_bytes = 0;
}
+
+ $l_width = strwidth($line);
+ if ($max_width && $l_width > $max_width) {
+ print STDERR
+ "$f:$lineno: line exceeds $max_width characters ($l_width)\n";
+ }
}
# Any blanks at the end of the file are discarded
diff --git a/scripts/cleanpatch b/scripts/cleanpatch
index a53f987708f5..9680d03ad2b8 100755
--- a/scripts/cleanpatch
+++ b/scripts/cleanpatch
@@ -7,7 +7,9 @@
use bytes;
use File::Basename;
-#
+# Default options
+$max_width = 79;
+
# Clean up space-tab sequences, either by removing spaces or
# replacing them with tabs.
sub clean_space_tabs($)
@@ -48,9 +50,49 @@ sub clean_space_tabs($)
return $lo;
}
+# Compute the visual width of a string
+sub strwidth($) {
+ no bytes; # Tab alignment depends on characters
+
+ my($li) = @_;
+ my($c, $i);
+ my $pos = 0;
+ my $mlen = 0;
+
+ for ($i = 0; $i < length($li); $i++) {
+ $c = substr($li,$i,1);
+ if ($c eq "\t") {
+ $pos = ($pos+8) & ~7;
+ } elsif ($c eq "\n") {
+ $mlen = $pos if ($pos > $mlen);
+ $pos = 0;
+ } else {
+ $pos++;
+ }
+ }
+
+ $mlen = $pos if ($pos > $mlen);
+ return $mlen;
+}
+
$name = basename($0);
-foreach $f ( @ARGV ) {
+@files = ();
+
+while (defined($a = shift(@ARGV))) {
+ if ($a =~ /^-/) {
+ if ($a eq '-width' || $a eq '-w') {
+ $max_width = shift(@ARGV)+0;
+ } else {
+ print STDERR "Usage: $name [-width #] files...\n";
+ exit 1;
+ }
+ } else {
+ push(@files, $a);
+ }
+}
+
+foreach $f ( @files ) {
print STDERR "$name: $f\n";
if (! -f $f) {
@@ -86,6 +128,7 @@ foreach $f ( @ARGV ) {
$in_bytes = 0;
$out_bytes = 0;
+ $lineno = 0;
@lines = ();
@@ -93,10 +136,12 @@ foreach $f ( @ARGV ) {
$err = 0;
while ( defined($line = <FILE>) ) {
+ $lineno++;
$in_bytes += length($line);
if (!$in_hunk) {
- if ($line =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
+ if ($line =~
+ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
$minus_lines = $2;
$plus_lines = $4;
if ($minus_lines || $plus_lines) {
@@ -117,6 +162,13 @@ foreach $f ( @ARGV ) {
$text =~ s/[ \t\r]*$//; # Remove trailing spaces
$text = clean_space_tabs($text);
+ $l_width = strwidth($text);
+ if ($max_width && $l_width > $max_width) {
+ print STDERR
+ "$f:$lineno: adds line exceeds $max_width ",
+ "characters ($l_width)\n";
+ }
+
push(@hunk_lines, '+'.$text);
} elsif ($line =~ /^\-/) {
$minus_lines--;
diff --git a/scripts/decodecode b/scripts/decodecode
new file mode 100644
index 000000000000..1e1a8f620c47
--- /dev/null
+++ b/scripts/decodecode
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Disassemble the Code: line in Linux oopses
+# usage: decodecode < oops.file
+#
+# options: set env. variable AFLAGS=options to pass options to "as";
+# e.g., to decode an i386 oops on an x86_64 system, use:
+# AFLAGS=--32 decodecode < 386.oops
+
+T=`mktemp`
+code=
+
+while read i ; do
+
+case "$i" in
+*Code:*)
+ code=$i
+ ;;
+esac
+
+done
+
+if [ -z "$code" ]; then
+ exit
+fi
+
+echo $code
+code=`echo $code | sed -e 's/.*Code: //'`
+
+marker=`expr index "$code" "\<"`
+if [ $marker -eq 0 ]; then
+ marker=`expr index "$code" "\("`
+fi
+
+if [ $marker -ne 0 ]; then
+ beforemark=`echo "$code" | cut -c-$((${marker} - 1))`
+ echo -n " .byte 0x" > $T.s
+ echo $beforemark | sed -e 's/ /,0x/g' >> $T.s
+ as $AFLAGS -o $T.o $T.s
+ objdump -S $T.o
+ rm $T.o $T.s
+
+# and fix code at-and-after marker
+ code=`echo "$code" | cut -c$((${marker} + 1))-`
+fi
+
+code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g'`
+echo -n " .byte 0x" > $T.s
+echo $code >> $T.s
+as $AFLAGS -o $T.o $T.s
+objdump -S $T.o
+rm $T.o $T.s
diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh
index bb4fbeab8320..8a1d1879c7ad 100644
--- a/scripts/gcc-version.sh
+++ b/scripts/gcc-version.sh
@@ -1,14 +1,23 @@
#!/bin/sh
#
-# gcc-version gcc-command
+# gcc-version [-p] gcc-command
#
# Prints the gcc version of `gcc-command' in a canonical 4-digit form
# such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc.
#
+# With the -p option, prints the patchlevel as well, for example `029503' for
+# gcc-2.95.3, `030301' for gcc-3.3.1, etc.
+#
+
+if [ $1 = "-p" ] ; then with_patchlevel=1; shift; fi
compiler="$*"
MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1)
MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1)
-printf "%02d%02d\\n" $MAJOR $MINOR
-
+if [ "x$with_patchlevel" != "x" ] ; then
+ PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1)
+ printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
+else
+ printf "%02d%02d\\n" $MAJOR $MINOR
+fi
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index 683eb12babbb..684fb9cdc055 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -19,11 +19,11 @@ $0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
-o <file> Create gzipped initramfs file named <file> using
gen_init_cpio and gzip
-u <uid> User ID to map to user ID 0 (root).
- <uid> is only meaningful if <cpio_source>
- is a directory.
+ <uid> is only meaningful if <cpio_source> is a
+ directory. "squash" forces all files to uid 0.
-g <gid> Group ID to map to group ID 0 (root).
- <gid> is only meaningful if <cpio_source>
- is a directory.
+ <gid> is only meaningful if <cpio_source> is a
+ directory. "squash" forces all files to gid 0.
<cpio_source> File list or directory for cpio archive.
If <cpio_source> is a .cpio file it will be used
as direct input to initramfs.
@@ -113,8 +113,8 @@ parse() {
local gid="$4"
local ftype=$(filetype "${location}")
# remap uid/gid to 0 if necessary
- [ "$uid" -eq "$root_uid" ] && uid=0
- [ "$gid" -eq "$root_gid" ] && gid=0
+ [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
+ [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
local str="${mode} ${uid} ${gid}"
[ "${ftype}" == "invalid" ] && return 0
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 8b809b264d18..1f11d848532a 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -24,14 +24,12 @@
*
*/
-#define _GNU_SOURCE
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
-#define KSYM_NAME_LEN 127
+#define KSYM_NAME_LEN 128
struct sym_entry {
@@ -254,7 +252,7 @@ static void write_src(void)
unsigned int i, k, off;
unsigned int best_idx[256];
unsigned int *markers;
- char buf[KSYM_NAME_LEN+1];
+ char buf[KSYM_NAME_LEN];
printf("#include <asm/types.h>\n");
printf("#if BITS_PER_LONG == 64\n");
@@ -378,6 +376,17 @@ static void build_initial_tok_table(void)
table_cnt = pos;
}
+static void *find_token(unsigned char *str, int len, unsigned char *token)
+{
+ int i;
+
+ for (i = 0; i < len - 1; i++) {
+ if (str[i] == token[0] && str[i+1] == token[1])
+ return &str[i];
+ }
+ return NULL;
+}
+
/* replace a given token in all the valid symbols. Use the sampled symbols
* to update the counts */
static void compress_symbols(unsigned char *str, int idx)
@@ -391,7 +400,7 @@ static void compress_symbols(unsigned char *str, int idx)
p1 = table[i].sym;
/* find the token on the symbol */
- p2 = memmem(p1, len, str, 2);
+ p2 = find_token(p1, len, str);
if (!p2) continue;
/* decrease the counts for this symbol's tokens */
@@ -410,7 +419,7 @@ static void compress_symbols(unsigned char *str, int idx)
if (size < 2) break;
/* find the token on the symbol */
- p2 = memmem(p1, size, str, 2);
+ p2 = find_token(p1, size, str);
} while (p2);
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index fb2bb3099dd9..8986a48c8c49 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -22,24 +22,25 @@ oldconfig: $(obj)/conf
silentoldconfig: $(obj)/conf
$< -s arch/$(ARCH)/Kconfig
+# Create new linux.po file
+# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
+# The symlink is used to repair a deficiency in arch/um
update-po-config: $(obj)/kxgettext
- xgettext --default-domain=linux \
- --add-comments --keyword=_ --keyword=N_ \
- --files-from=scripts/kconfig/POTFILES.in \
- --output scripts/kconfig/config.pot
- $(Q)ln -fs Kconfig_i386 arch/um/Kconfig_arch
- $(Q)for i in `ls arch/`; \
- do \
- scripts/kconfig/kxgettext arch/$$i/Kconfig \
- | msguniq -o scripts/kconfig/linux_$${i}.pot; \
- done
- $(Q)msgcat scripts/kconfig/config.pot \
- `find scripts/kconfig/ -type f -name linux_*.pot` \
- --output scripts/kconfig/linux_raw.pot
- $(Q)msguniq --sort-by-file scripts/kconfig/linux_raw.pot \
- --output scripts/kconfig/linux.pot
- $(Q)rm -f arch/um/Kconfig_arch
- $(Q)rm -f scripts/kconfig/linux_*.pot scripts/kconfig/config.pot
+ xgettext --default-domain=linux \
+ --add-comments --keyword=_ --keyword=N_ \
+ --from-code=UTF-8 \
+ --files-from=scripts/kconfig/POTFILES.in \
+ --output $(obj)/config.pot
+ $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot
+ $(Q)ln -fs Kconfig.i386 arch/um/Kconfig.arch
+ (for i in `ls arch/`; \
+ do \
+ $(obj)/kxgettext arch/$$i/Kconfig; \
+ done ) >> $(obj)/config.pot
+ msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \
+ --output $(obj)/linux.pot
+ $(Q)rm -f arch/um/Kconfig.arch
+ $(Q)rm -f $(obj)/config.pot
PHONY += randconfig allyesconfig allnoconfig allmodconfig defconfig
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 664fe29dacef..b2913e9da495 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -341,27 +341,42 @@ int conf_read(const char *name)
conf_unsaved++;
/* maybe print value in verbose mode... */
sym_ok:
+ if (!sym_is_choice(sym))
+ continue;
+ /* The choice symbol only has a set value (and thus is not new)
+ * if all its visible childs have values.
+ */
+ prop = sym_get_choice_prop(sym);
+ flags = sym->flags;
+ for (e = prop->expr; e; e = e->left.expr)
+ if (e->right.sym->visible != no)
+ flags &= e->right.sym->flags;
+ sym->flags &= flags | ~SYMBOL_DEF_USER;
+ }
+
+ for_all_symbols(i, sym) {
if (sym_has_value(sym) && !sym_is_choice_value(sym)) {
- if (sym->visible == no)
+ /* Reset values of generates values, so they'll appear
+ * as new, if they should become visible, but that
+ * doesn't quite work if the Kconfig and the saved
+ * configuration disagree.
+ */
+ if (sym->visible == no && !conf_unsaved)
sym->flags &= ~SYMBOL_DEF_USER;
switch (sym->type) {
case S_STRING:
case S_INT:
case S_HEX:
- if (!sym_string_within_range(sym, sym->def[S_DEF_USER].val))
- sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ /* Reset a string value if it's out of range */
+ if (sym_string_within_range(sym, sym->def[S_DEF_USER].val))
+ break;
+ sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER);
+ conf_unsaved++;
+ break;
default:
break;
}
}
- if (!sym_is_choice(sym))
- continue;
- prop = sym_get_choice_prop(sym);
- flags = sym->flags;
- for (e = prop->expr; e; e = e->left.expr)
- if (e->right.sym->visible != no)
- flags &= e->right.sym->flags;
- sym->flags &= flags | ~SYMBOL_DEF_USER;
}
sym_add_change_count(conf_warnings || conf_unsaved);
diff --git a/scripts/kconfig/kxgettext.c b/scripts/kconfig/kxgettext.c
index abee55ca6174..11f7dab94715 100644
--- a/scripts/kconfig/kxgettext.c
+++ b/scripts/kconfig/kxgettext.c
@@ -212,7 +212,9 @@ void menu__xgettext(void)
struct message *m = message__list;
while (m != NULL) {
- message__print_gettext_msgid_msgstr(m);
+ /* skip empty lines ("") */
+ if (strlen(m->msg) > sizeof("\"\""))
+ message__print_gettext_msgid_msgstr(m);
m = m->next;
}
}
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
index cdca7388e0f1..9681476b96e7 100644
--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
+++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
@@ -51,7 +51,7 @@ usage() {
printf "Usage: $0 [-check compiler options|-header|-library]\n"
}
-if [ $# == 0 ]; then
+if [ $# -eq 0 ]; then
usage
exit 1
fi
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index d0e4fa594fc7..d2c2a429887b 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -419,11 +419,13 @@ static void search_conf(void)
{
struct symbol **sym_arr;
struct gstr res;
+ char *dialog_input;
int dres;
again:
dialog_clear();
dres = dialog_inputbox(_("Search Configuration Parameter"),
- _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
+ _("Enter CONFIG_ (sub)string to search for "
+ "(with or without \"CONFIG\")"),
10, 75, "");
switch (dres) {
case 0:
@@ -435,7 +437,12 @@ again:
return;
}
- sym_arr = sym_re_search(dialog_input_result);
+ /* strip CONFIG_ if necessary */
+ dialog_input = dialog_input_result;
+ if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
+ dialog_input += 7;
+
+ sym_arr = sym_re_search(dialog_input);
res = get_relations_str(sym_arr);
free(sym_arr);
show_textbox(_("Search Results"), str_get(&res), 0, 0);
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index e5bf649e516a..1f5835115cad 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -154,6 +154,7 @@ use strict;
my $errors = 0;
my $warnings = 0;
+my $anon_struct_union = 0;
# match expressions used to find embedded type information
my $type_constant = '\%([-_\w]+)';
@@ -403,7 +404,11 @@ sub output_highlight {
print $lineprefix, $blankline;
} else {
$line =~ s/\\\\\\/\&/g;
- print $lineprefix, $line;
+ if ($output_mode eq "man" && substr($line, 0, 1) eq ".") {
+ print "\\&$line";
+ } else {
+ print $lineprefix, $line;
+ }
}
print "\n";
}
@@ -718,6 +723,7 @@ sub output_struct_xml(%) {
# pointer-to-function
print " $1 $parameter) ($2);\n";
} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
print " $1 $parameter$2;\n";
} else {
print " ".$type." ".$parameter.";\n";
@@ -1260,6 +1266,7 @@ sub output_struct_text(%) {
# pointer-to-function
print "\t$1 $parameter) ($2);\n";
} elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
print "\t$1 $parameter$2;\n";
} else {
print "\t".$type." ".$parameter.";\n";
@@ -1510,8 +1517,13 @@ sub push_parameter($$$) {
my $param = shift;
my $type = shift;
my $file = shift;
- my $anon = 0;
+ if (($anon_struct_union == 1) && ($type eq "") &&
+ ($param eq "}")) {
+ return; # ignore the ending }; from anon. struct/union
+ }
+
+ $anon_struct_union = 0;
my $param_name = $param;
$param_name =~ s/\[.*//;
@@ -1530,16 +1542,16 @@ sub push_parameter($$$) {
# handle unnamed (anonymous) union or struct:
{
$type = $param;
- $param = "{unnamed_" . $param. "}";
+ $param = "{unnamed_" . $param . "}";
$parameterdescs{$param} = "anonymous\n";
- $anon = 1;
+ $anon_struct_union = 1;
}
# warn if parameter has no description
# (but ignore ones starting with # as these are not parameters
# but inline preprocessor statements);
# also ignore unnamed structs/unions;
- if (!$anon) {
+ if (!$anon_struct_union) {
if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) {
$parameterdescs{$param_name} = $undescribed;
@@ -1691,6 +1703,8 @@ sub process_state3_function($$) {
my $x = shift;
my $file = shift;
+ $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#define/)) {
# do nothing
}
@@ -1713,6 +1727,8 @@ sub process_state3_type($$) {
$x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
$x =~ s@^\s+@@gos; # strip leading spaces
$x =~ s@\s+$@@gos; # strip trailing spaces
+ $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
if ($x =~ /^#/) {
# To distinguish preprocessor directive from regular declaration later.
$x .= ";";
@@ -1796,7 +1812,7 @@ sub process_file($) {
$state = 2;
if (/-(.*)/) {
- # strip leading/trailing/multiple spaces #RDD:T:
+ # strip leading/trailing/multiple spaces
$descr= $1;
$descr =~ s/^\s*//;
$descr =~ s/\s*$//;
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 3645e980da71..5ab7914d30ef 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -75,7 +75,8 @@ static int is_vmlinux(const char *modname)
else
myname = modname;
- return strcmp(myname, "vmlinux") == 0;
+ return (strcmp(myname, "vmlinux") == 0) ||
+ (strcmp(myname, "vmlinux.o") == 0);
}
void *do_nofail(void *ptr, const char *expr)
@@ -374,6 +375,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx);
hdr->e_shnum = TO_NATIVE(hdr->e_shnum);
hdr->e_machine = TO_NATIVE(hdr->e_machine);
+ hdr->e_type = TO_NATIVE(hdr->e_type);
sechdrs = (void *)hdr + hdr->e_shoff;
info->sechdrs = sechdrs;
@@ -384,6 +386,8 @@ static int parse_elf(struct elf_info *info, const char *filename)
sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size);
sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link);
sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name);
+ sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info);
+ sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr);
}
/* Find symbol table. */
for (i = 1; i < hdr->e_shnum; i++) {
@@ -605,18 +609,14 @@ static int strrcmp(const char *s, const char *sub)
* warn here.
* the pattern is identified by:
* tosec = .init.text | .exit.text | .init.data
- * fromsec = .data
- * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console
+ * fromsec = .data | .data.rel | .data.rel.*
+ * atsym = *driver, *_template, *_sht, *_ops, *_probe, *probe_one, *_console, *_timer
*
* Pattern 3:
- * Whitelist all references from .pci_fixup* section to .init.text
- * This is part of the PCI init when built-in
- *
- * Pattern 4:
* Whitelist all refereces from .text.head to .init.data
* Whitelist all refereces from .text.head to .init.text
*
- * Pattern 5:
+ * Pattern 4:
* Some symbols belong to init section but still it is ok to reference
* these from non-init sections as these symbols don't have any memory
* allocated for them and symbol address and value are same. So even
@@ -625,26 +625,6 @@ static int strrcmp(const char *s, const char *sub)
* This pattern is identified by
* refsymname = __init_begin, _sinittext, _einittext
*
- * Pattern 7:
- * Logos used in drivers/video/logo reside in __initdata but the
- * funtion that references them are EXPORT_SYMBOL() so cannot be
- * marker __init. So we whitelist them here.
- * The pattern is:
- * tosec = .init.data
- * fromsec = .text*
- * refsymname = logo_
- *
- * Pattern 8:
- * Symbols contained in .paravirtprobe may safely reference .init.text.
- * The pattern is:
- * tosec = .init.text
- * fromsec = .paravirtprobe
- *
- * Pattern 10:
- * ia64 has machvec table for each platform and
- * powerpc has a machine desc table for each platform.
- * It is mixture of function pointers of .init.text and .text.
- * fromsec = .machvec | .machine.desc
**/
static int secref_whitelist(const char *modname, const char *tosec,
const char *fromsec, const char *atsym,
@@ -655,12 +635,12 @@ static int secref_whitelist(const char *modname, const char *tosec,
const char *pat2sym[] = {
"driver",
"_template", /* scsi uses *_template a lot */
+ "_timer", /* arm uses ops structures named _timer a lot */
"_sht", /* scsi also used *_sht to some extent */
"_ops",
"_probe",
"_probe_one",
"_console",
- "apic_es7000",
NULL
};
@@ -692,7 +672,9 @@ static int secref_whitelist(const char *modname, const char *tosec,
(strcmp(tosec, ".exit.text") != 0) &&
(strcmp(tosec, ".init.data") != 0))
f2 = 0;
- if (strcmp(fromsec, ".data") != 0)
+ if ((strcmp(fromsec, ".data") != 0) &&
+ (strcmp(fromsec, ".data.rel") != 0) &&
+ (strncmp(fromsec, ".data.rel.", strlen(".data.rel.")) != 0))
f2 = 0;
for (s = pat2sym; *s; s++)
@@ -702,37 +684,16 @@ static int secref_whitelist(const char *modname, const char *tosec,
return 1;
/* Check for pattern 3 */
- if ((strncmp(fromsec, ".pci_fixup", strlen(".pci_fixup")) == 0) &&
- (strcmp(tosec, ".init.text") == 0))
- return 1;
-
- /* Check for pattern 4 */
if ((strcmp(fromsec, ".text.head") == 0) &&
((strcmp(tosec, ".init.data") == 0) ||
(strcmp(tosec, ".init.text") == 0)))
return 1;
- /* Check for pattern 5 */
+ /* Check for pattern 4 */
for (s = pat3refsym; *s; s++)
if (strcmp(refsymname, *s) == 0)
return 1;
- /* Check for pattern 7 */
- if ((strcmp(tosec, ".init.data") == 0) &&
- (strncmp(fromsec, ".text", strlen(".text")) == 0) &&
- (strncmp(refsymname, "logo_", strlen("logo_")) == 0))
- return 1;
-
- /* Check for pattern 8 */
- if ((strcmp(tosec, ".init.text") == 0) &&
- (strcmp(fromsec, ".paravirtprobe") == 0))
- return 1;
-
- /* Check for pattern 10 */
- if ((strcmp(fromsec, ".machvec") == 0) ||
- (strcmp(fromsec, ".machine.desc") == 0))
- return 1;
-
return 0;
}
@@ -753,6 +714,8 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf_Addr addr,
for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) {
if (sym->st_shndx != relsym->st_shndx)
continue;
+ if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
+ continue;
if (sym->st_value == addr)
return sym;
}
@@ -864,11 +827,6 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
elf->strtab + before->st_name, refsymname))
return;
- /* fromsec whitelist - without a valid 'before'
- * powerpc has a GOT table in .got2 section */
- if (strcmp(fromsec, ".got2") == 0)
- return;
-
if (before && after) {
warn("%s(%s+0x%llx): Section mismatch: reference to %s:%s "
"(between '%s' and '%s')\n",
@@ -895,6 +853,78 @@ static void warn_sec_mismatch(const char *modname, const char *fromsec,
}
}
+static unsigned int *reloc_location(struct elf_info *elf,
+ int rsection, Elf_Rela *r)
+{
+ Elf_Shdr *sechdrs = elf->sechdrs;
+ int section = sechdrs[rsection].sh_info;
+
+ return (void *)elf->hdr + sechdrs[section].sh_offset +
+ (r->r_offset - sechdrs[section].sh_addr);
+}
+
+static int addend_386_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, rsection, r);
+
+ switch (r_typ) {
+ case R_386_32:
+ r->r_addend = TO_NATIVE(*location);
+ break;
+ case R_386_PC32:
+ r->r_addend = TO_NATIVE(*location) + 4;
+ /* For CONFIG_RELOCATABLE=y */
+ if (elf->hdr->e_type == ET_EXEC)
+ r->r_addend += r->r_offset;
+ break;
+ }
+ return 0;
+}
+
+static int addend_arm_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+
+ switch (r_typ) {
+ case R_ARM_ABS32:
+ /* From ARM ABI: (S + A) | T */
+ r->r_addend = (int)(long)(elf->symtab_start + ELF_R_SYM(r->r_info));
+ break;
+ case R_ARM_PC24:
+ /* From ARM ABI: ((S + A) | T) - P */
+ r->r_addend = (int)(long)(elf->hdr + elf->sechdrs[rsection].sh_offset +
+ (r->r_offset - elf->sechdrs[rsection].sh_addr));
+ break;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int addend_mips_rel(struct elf_info *elf, int rsection, Elf_Rela *r)
+{
+ unsigned int r_typ = ELF_R_TYPE(r->r_info);
+ unsigned int *location = reloc_location(elf, rsection, r);
+ unsigned int inst;
+
+ if (r_typ == R_MIPS_HI16)
+ return 1; /* skip this */
+ inst = TO_NATIVE(*location);
+ switch (r_typ) {
+ case R_MIPS_LO16:
+ r->r_addend = inst & 0xffff;
+ break;
+ case R_MIPS_26:
+ r->r_addend = (inst & 0x03ffffff) << 2;
+ break;
+ case R_MIPS_32:
+ r->r_addend = inst;
+ break;
+ }
+ return 0;
+}
+
/**
* A module includes a number of sections that are discarded
* either when loaded or when used as built-in.
@@ -938,8 +968,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
r.r_offset = TO_NATIVE(rela->r_offset);
#if KERNEL_ELFCLASS == ELFCLASS64
if (hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
r_sym = ELF64_MIPS_R_SYM(rela->r_info);
r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rela->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
} else {
r.r_info = TO_NATIVE(rela->r_info);
r_sym = ELF_R_SYM(r.r_info);
@@ -972,8 +1005,11 @@ static void check_sec_ref(struct module *mod, const char *modname,
r.r_offset = TO_NATIVE(rel->r_offset);
#if KERNEL_ELFCLASS == ELFCLASS64
if (hdr->e_machine == EM_MIPS) {
+ unsigned int r_typ;
r_sym = ELF64_MIPS_R_SYM(rel->r_info);
r_sym = TO_NATIVE(r_sym);
+ r_typ = ELF64_MIPS_R_TYPE(rel->r_info);
+ r.r_info = ELF64_R_INFO(r_sym, r_typ);
} else {
r.r_info = TO_NATIVE(rel->r_info);
r_sym = ELF_R_SYM(r.r_info);
@@ -983,6 +1019,20 @@ static void check_sec_ref(struct module *mod, const char *modname,
r_sym = ELF_R_SYM(r.r_info);
#endif
r.r_addend = 0;
+ switch (hdr->e_machine) {
+ case EM_386:
+ if (addend_386_rel(elf, i, &r))
+ continue;
+ break;
+ case EM_ARM:
+ if(addend_arm_rel(elf, i, &r))
+ continue;
+ break;
+ case EM_MIPS:
+ if (addend_mips_rel(elf, i, &r))
+ continue;
+ break;
+ }
sym = elf->symtab_start + r_sym;
/* Skip special sections */
if (sym->st_shndx >= SHN_LORESERVE)
@@ -998,6 +1048,64 @@ static void check_sec_ref(struct module *mod, const char *modname,
}
}
+/*
+ * Identify sections from which references to either a
+ * .init or a .exit section is OK.
+ *
+ * [OPD] Keith Ownes <kaos@sgi.com> commented:
+ * For our future {in}sanity, add a comment that this is the ppc .opd
+ * section, not the ia64 .opd section.
+ * ia64 .opd should not point to discarded sections.
+ * [.rodata] like for .init.text we ignore .rodata references -same reason
+ */
+static int initexit_section_ref_ok(const char *name)
+{
+ const char **s;
+ /* Absolute section names */
+ const char *namelist1[] = {
+ "__bug_table", /* used by powerpc for BUG() */
+ "__ex_table",
+ ".altinstructions",
+ ".cranges", /* used by sh64 */
+ ".fixup",
+ ".machvec", /* ia64 + powerpc uses these */
+ ".machine.desc",
+ ".opd", /* See comment [OPD] */
+ ".parainstructions",
+ ".pdr",
+ ".plt", /* seen on ARCH=um build on x86_64. Harmless */
+ ".smp_locks",
+ ".stab",
+ ".m68k_fixup",
+ NULL
+ };
+ /* Start of section names */
+ const char *namelist2[] = {
+ ".debug",
+ ".eh_frame",
+ ".note", /* ignore ELF notes - may contain anything */
+ ".got", /* powerpc - global offset table */
+ ".toc", /* powerpc - table of contents */
+ NULL
+ };
+ /* part of section name */
+ const char *namelist3 [] = {
+ ".unwind", /* Sample: IA_64.unwind.exit.text */
+ NULL
+ };
+
+ for (s = namelist1; *s; s++)
+ if (strcmp(*s, name) == 0)
+ return 1;
+ for (s = namelist2; *s; s++)
+ if (strncmp(*s, name, strlen(*s)) == 0)
+ return 1;
+ for (s = namelist3; *s; s++)
+ if (strstr(name, *s) != NULL)
+ return 1;
+ return 0;
+}
+
/**
* Functions used only during module init is marked __init and is stored in
* a .init.text section. Likewise data is marked __initdata and stored in
@@ -1014,7 +1122,7 @@ static int init_section(const char *name)
return 0;
}
-/**
+/*
* Identify sections from which references to a .init section is OK.
*
* Unfortunately references to read only data that referenced .init
@@ -1028,48 +1136,31 @@ static int init_section(const char *name)
*
* where vgacon_startup is __init. If you want to wade through the false
* positives, take out the check for rodata.
- **/
+ */
static int init_section_ref_ok(const char *name)
{
const char **s;
/* Absolute section names */
const char *namelist1[] = {
- ".init",
- ".opd", /* see comment [OPD] at exit_section_ref_ok() */
- ".toc1", /* used by ppc64 */
- ".stab",
- ".data.rel.ro", /* used by parisc64 */
- ".parainstructions",
- ".text.lock",
- "__bug_table", /* used by powerpc for BUG() */
- ".pci_fixup_header",
- ".pci_fixup_final",
- ".pdr",
- "__param",
- "__ex_table",
- ".fixup",
- ".smp_locks",
- ".plt", /* seen on ARCH=um build on x86_64. Harmless */
+ "__dbe_table", /* MIPS generate these */
"__ftr_fixup", /* powerpc cpu feature fixup */
"__fw_ftr_fixup", /* powerpc firmware feature fixup */
- ".cranges", /* used by sh64 */
+ "__param",
+ ".data.rel.ro", /* used by parisc64 */
+ ".init",
+ ".text.lock",
NULL
};
/* Start of section names */
const char *namelist2[] = {
".init.",
- ".altinstructions",
- ".eh_frame",
- ".debug",
- ".parainstructions",
+ ".pci_fixup",
".rodata",
NULL
};
- /* part of section name */
- const char *namelist3 [] = {
- ".unwind", /* sample: IA_64.unwind.init.text */
- NULL
- };
+
+ if (initexit_section_ref_ok(name))
+ return 1;
for (s = namelist1; *s; s++)
if (strcmp(*s, name) == 0)
@@ -1077,9 +1168,10 @@ static int init_section_ref_ok(const char *name)
for (s = namelist2; *s; s++)
if (strncmp(*s, name, strlen(*s)) == 0)
return 1;
- for (s = namelist3; *s; s++)
- if (strstr(name, *s) != NULL)
- return 1;
+
+ /* If section name ends with ".init" we allow references
+ * as is the case with .initcallN.init, .early_param.init, .taglist.init etc
+ */
if (strrcmp(name, ".init") == 0)
return 1;
return 0;
@@ -1104,58 +1196,25 @@ static int exit_section(const char *name)
/*
* Identify sections from which references to a .exit section is OK.
- *
- * [OPD] Keith Ownes <kaos@sgi.com> commented:
- * For our future {in}sanity, add a comment that this is the ppc .opd
- * section, not the ia64 .opd section.
- * ia64 .opd should not point to discarded sections.
- * [.rodata] like for .init.text we ignore .rodata references -same reason
- **/
+ */
static int exit_section_ref_ok(const char *name)
{
const char **s;
/* Absolute section names */
const char *namelist1[] = {
- ".exit.text",
".exit.data",
- ".init.text",
- ".rodata",
- ".opd", /* See comment [OPD] */
- ".toc1", /* used by ppc64 */
- ".altinstructions",
- ".pdr",
- "__bug_table", /* used by powerpc for BUG() */
+ ".exit.text",
".exitcall.exit",
- ".eh_frame",
- ".parainstructions",
- ".stab",
- "__ex_table",
- ".fixup",
- ".smp_locks",
- ".plt", /* seen on ARCH=um build on x86_64. Harmless */
- ".cranges", /* used by sh64 */
- NULL
- };
- /* Start of section names */
- const char *namelist2[] = {
- ".debug",
- NULL
- };
- /* part of section name */
- const char *namelist3 [] = {
- ".unwind", /* Sample: IA_64.unwind.exit.text */
+ ".rodata",
NULL
};
+ if (initexit_section_ref_ok(name))
+ return 1;
+
for (s = namelist1; *s; s++)
if (strcmp(*s, name) == 0)
return 1;
- for (s = namelist2; *s; s++)
- if (strncmp(*s, name, strlen(*s)) == 0)
- return 1;
- for (s = namelist3; *s; s++)
- if (strstr(name, *s) != NULL)
- return 1;
return 0;
}
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 0858caa9c03f..4156dd34c5de 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -60,6 +60,9 @@ typedef union
#define ELF64_MIPS_R_SYM(i) \
((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym)
+#define ELF64_MIPS_R_TYPE(i) \
+ ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1)
+
#if KERNEL_ELFDATA != HOST_ELFDATA
static inline void __endian(const void *src, void *dest, unsigned int size)
diff --git a/security/commoncap.c b/security/commoncap.c
index 384379ede4fd..338606eb7238 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -148,7 +148,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
!cap_issubset (new_permitted, current->cap_permitted)) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
if (!capable(CAP_SETUID)) {
diff --git a/security/dummy.c b/security/dummy.c
index 8ffd76405b5b..19d813d5e083 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -130,7 +130,7 @@ static void dummy_bprm_free_security (struct linux_binprm *bprm)
static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
- current->mm->dumpable = suid_dumpable;
+ set_dumpable(current->mm, suid_dumpable);
if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) {
bprm->e_uid = current->uid;
@@ -420,8 +420,12 @@ static int dummy_file_ioctl (struct file *file, unsigned int command,
static int dummy_file_mmap (struct file *file, unsigned long reqprot,
unsigned long prot,
- unsigned long flags)
+ unsigned long flags,
+ unsigned long addr,
+ unsigned long addr_only)
{
+ if (addr < mmap_min_addr)
+ return -EACCES;
return 0;
}
diff --git a/security/keys/key.c b/security/keys/key.c
index 700400d801dc..01bbc6d9d19b 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -1001,7 +1001,7 @@ void __init key_init(void)
{
/* allocate a slab in which we can store keys */
key_jar = kmem_cache_create("key_jar", sizeof(struct key),
- 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
/* add the special key types */
list_add_tail(&key_type_keyring.link, &key_types_list);
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index f573ac189a0a..557500110a13 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -108,7 +108,8 @@ static int call_sbin_request_key(struct key *key,
argv[i] = NULL;
/* do it */
- ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1);
+ ret = call_usermodehelper_keys(argv[0], argv, envp, keyring,
+ UMH_WAIT_PROC);
error_link:
key_put(keyring);
diff --git a/security/security.c b/security/security.c
index fc8601b2b7ac..27e5863d30f1 100644
--- a/security/security.c
+++ b/security/security.c
@@ -24,6 +24,7 @@ extern struct security_operations dummy_security_ops;
extern void security_fixup_ops(struct security_operations *ops);
struct security_operations *security_ops; /* Initialized to NULL */
+unsigned long mmap_min_addr; /* 0 means no protection */
static inline int verify(struct security_operations *ops)
{
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index e4396a89edc6..0e69adf63bdb 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -239,7 +239,7 @@ void __init avc_init(void)
atomic_set(&avc_cache.lru_hint, 0);
avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n");
}
@@ -570,10 +570,12 @@ void avc_audit(u32 ssid, u32 tsid,
case AVC_AUDIT_DATA_FS:
if (a->u.fs.dentry) {
struct dentry *dentry = a->u.fs.dentry;
- if (a->u.fs.mnt)
- audit_avc_path(dentry, a->u.fs.mnt);
- audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab, dentry->d_name.name);
+ if (a->u.fs.mnt) {
+ audit_log_d_path(ab, "path=", dentry, a->u.fs.mnt);
+ } else {
+ audit_log_format(ab, " name=");
+ audit_log_untrustedstring(ab, dentry->d_name.name);
+ }
inode = dentry->d_inode;
} else if (a->u.fs.inode) {
struct dentry *dentry;
@@ -586,7 +588,7 @@ void avc_audit(u32 ssid, u32 tsid,
}
}
if (inode)
- audit_log_format(ab, " dev=%s ino=%ld",
+ audit_log_format(ab, " dev=%s ino=%lu",
inode->i_sb->s_id,
inode->i_ino);
break;
@@ -624,9 +626,8 @@ void avc_audit(u32 ssid, u32 tsid,
case AF_UNIX:
u = unix_sk(sk);
if (u->dentry) {
- audit_avc_path(u->dentry, u->mnt);
- audit_log_format(ab, " name=");
- audit_log_untrustedstring(ab, u->dentry->d_name.name);
+ audit_log_d_path(ab, "path=",
+ u->dentry, u->mnt);
break;
}
if (!u->addr)
@@ -832,6 +833,7 @@ int avc_ss_reset(u32 seqno)
* @tsid: target security identifier
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
+ * @flags: AVC_STRICT or 0
* @avd: access vector decisions
*
* Check the AVC to determine whether the @requested permissions are granted
@@ -846,8 +848,9 @@ int avc_ss_reset(u32 seqno)
* should be released for the auditing.
*/
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
- u16 tclass, u32 requested,
- struct av_decision *avd)
+ u16 tclass, u32 requested,
+ unsigned flags,
+ struct av_decision *avd)
{
struct avc_node *node;
struct avc_entry entry, *p_ae;
@@ -874,7 +877,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
denied = requested & ~(p_ae->avd.allowed);
if (!requested || denied) {
- if (selinux_enforcing)
+ if (selinux_enforcing || (flags & AVC_STRICT))
rc = -EACCES;
else
if (node)
@@ -909,7 +912,7 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
struct av_decision avd;
int rc;
- rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, &avd);
+ rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
return rc;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ad8dd4e8657e..0fac6829c63a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1592,9 +1592,10 @@ static int selinux_vm_enough_memory(long pages)
rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
if (rc == 0)
rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
- SECCLASS_CAPABILITY,
- CAP_TO_MASK(CAP_SYS_ADMIN),
- NULL);
+ SECCLASS_CAPABILITY,
+ CAP_TO_MASK(CAP_SYS_ADMIN),
+ 0,
+ NULL);
if (rc == 0)
cap_sys_admin = 1;
@@ -2317,7 +2318,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value
if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
return -EOPNOTSUPP;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ if (!is_owner_or_cap(inode))
return -EPERM;
AVC_AUDIT_DATA_INIT(&ad,FS);
@@ -2568,12 +2569,16 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
}
static int selinux_file_mmap(struct file *file, unsigned long reqprot,
- unsigned long prot, unsigned long flags)
+ unsigned long prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only)
{
- int rc;
+ int rc = 0;
+ u32 sid = ((struct task_security_struct*)(current->security))->sid;
- rc = secondary_ops->file_mmap(file, reqprot, prot, flags);
- if (rc)
+ if (addr < mmap_min_addr)
+ rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
+ MEMPROTECT__MMAP_ZERO, NULL);
+ if (rc || addr_only)
return rc;
if (selinux_checkreqprot)
@@ -3124,17 +3129,19 @@ static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad,
/**
* selinux_skb_extlbl_sid - Determine the external label of a packet
* @skb: the packet
- * @base_sid: the SELinux SID to use as a context for MLS only external labels
* @sid: the packet's SID
*
* Description:
* Check the various different forms of external packet labeling and determine
- * the external SID for the packet.
+ * the external SID for the packet. If only one form of external labeling is
+ * present then it is used, if both labeled IPsec and NetLabel labels are
+ * present then the SELinux type information is taken from the labeled IPsec
+ * SA and the MLS sensitivity label information is taken from the NetLabel
+ * security attributes. This bit of "magic" is done in the call to
+ * selinux_netlbl_skbuff_getsid().
*
*/
-static void selinux_skb_extlbl_sid(struct sk_buff *skb,
- u32 base_sid,
- u32 *sid)
+static void selinux_skb_extlbl_sid(struct sk_buff *skb, u32 *sid)
{
u32 xfrm_sid;
u32 nlbl_sid;
@@ -3142,10 +3149,9 @@ static void selinux_skb_extlbl_sid(struct sk_buff *skb,
selinux_skb_xfrm_sid(skb, &xfrm_sid);
if (selinux_netlbl_skbuff_getsid(skb,
(xfrm_sid == SECSID_NULL ?
- base_sid : xfrm_sid),
+ SECINITSID_NETMSG : xfrm_sid),
&nlbl_sid) != 0)
nlbl_sid = SECSID_NULL;
-
*sid = (nlbl_sid == SECSID_NULL ? xfrm_sid : nlbl_sid);
}
@@ -3690,7 +3696,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
if (sock && sock->sk->sk_family == PF_UNIX)
selinux_get_inode_sid(SOCK_INODE(sock), &peer_secid);
else if (skb)
- selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peer_secid);
+ selinux_skb_extlbl_sid(skb, &peer_secid);
if (peer_secid == SECSID_NULL)
err = -EINVAL;
@@ -3751,7 +3757,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
u32 newsid;
u32 peersid;
- selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &peersid);
+ selinux_skb_extlbl_sid(skb, &peersid);
if (peersid == SECSID_NULL) {
req->secid = sksec->sid;
req->peer_secid = SECSID_NULL;
@@ -3789,7 +3795,7 @@ static void selinux_inet_conn_established(struct sock *sk,
{
struct sk_security_struct *sksec = sk->sk_security;
- selinux_skb_extlbl_sid(skb, SECINITSID_UNLABELED, &sksec->peer_sid);
+ selinux_skb_extlbl_sid(skb, &sksec->peer_sid);
}
static void selinux_req_classify_flow(const struct request_sock *req,
@@ -4626,7 +4632,7 @@ static int selinux_setprocattr(struct task_struct *p,
if (p->ptrace & PT_PTRACED) {
error = avc_has_perm_noaudit(tsec->ptrace_sid, sid,
SECCLASS_PROCESS,
- PROCESS__PTRACE, &avd);
+ PROCESS__PTRACE, 0, &avd);
if (!error)
tsec->sid = sid;
task_unlock(p);
@@ -4907,7 +4913,7 @@ static __init int selinux_init(void)
sel_inode_cache = kmem_cache_create("selinux_inode_security",
sizeof(struct inode_security_struct),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
avc_init();
original_ops = secondary_ops = security_ops;
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index b83e74012a97..049bf69429b6 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -158,3 +158,4 @@
S_(SECCLASS_KEY, KEY__CREATE, "create")
S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NODE_BIND, "node_bind")
S_(SECCLASS_DCCP_SOCKET, DCCP_SOCKET__NAME_CONNECT, "name_connect")
+ S_(SECCLASS_MEMPROTECT, MEMPROTECT__MMAP_ZERO, "mmap_zero")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index 5fee1735bffe..eda89a2ec635 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -823,3 +823,4 @@
#define DCCP_SOCKET__NAME_BIND 0x00200000UL
#define DCCP_SOCKET__NODE_BIND 0x00400000UL
#define DCCP_SOCKET__NAME_CONNECT 0x00800000UL
+#define MEMPROTECT__MMAP_ZERO 0x00000001UL
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 6ed10c3d3339..e145f6e13b0b 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -102,9 +102,11 @@ void avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd, int result, struct avc_audit_data *auditdata);
+#define AVC_STRICT 1 /* Ignore permissive mode. */
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
- u16 tclass, u32 requested,
- struct av_decision *avd);
+ u16 tclass, u32 requested,
+ unsigned flags,
+ struct av_decision *avd);
int avc_has_perm(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
diff --git a/security/selinux/include/class_to_string.h b/security/selinux/include/class_to_string.h
index 378799068441..e77de0e62ea0 100644
--- a/security/selinux/include/class_to_string.h
+++ b/security/selinux/include/class_to_string.h
@@ -63,3 +63,4 @@
S_("key")
S_(NULL)
S_("dccp_socket")
+ S_("memprotect")
diff --git a/security/selinux/include/flask.h b/security/selinux/include/flask.h
index 35f309f47873..a9c2b20f14b5 100644
--- a/security/selinux/include/flask.h
+++ b/security/selinux/include/flask.h
@@ -49,6 +49,7 @@
#define SECCLASS_PACKET 57
#define SECCLASS_KEY 58
#define SECCLASS_DCCP_SOCKET 60
+#define SECCLASS_MEMPROTECT 61
/*
* Security identifier indices for initial entities
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index b94378afea25..83bdd4d2a29e 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -41,6 +41,7 @@ extern int selinux_mls_enabled;
int security_load_policy(void * data, size_t len);
+#define SEL_VEC_MAX 32
struct av_decision {
u32 allowed;
u32 decided;
@@ -87,6 +88,9 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
+int security_get_classes(char ***classes, int *nclasses);
+int security_get_permissions(char *class, char ***perms, int *nperms);
+
#define SECURITY_FS_USE_XATTR 1 /* use xattr */
#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
#define SECURITY_FS_USE_TASK 3 /* use task SIDs, e.g. pipefs/sockfs */
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index e64eca246f1a..051b14c88e2d 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -155,12 +155,15 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, u32 base_sid, u32 *sid)
int rc;
struct netlbl_lsm_secattr secattr;
+ if (!netlbl_enabled()) {
+ *sid = SECSID_NULL;
+ return 0;
+ }
+
netlbl_secattr_init(&secattr);
rc = netlbl_skbuff_getattr(skb, &secattr);
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
- rc = security_netlbl_secattr_to_sid(&secattr,
- base_sid,
- sid);
+ rc = security_netlbl_secattr_to_sid(&secattr, base_sid, sid);
else
*sid = SECSID_NULL;
netlbl_secattr_destroy(&secattr);
@@ -198,7 +201,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
if (netlbl_sock_getattr(sk, &secattr) == 0 &&
secattr.flags != NETLBL_SECATTR_NONE &&
security_netlbl_secattr_to_sid(&secattr,
- SECINITSID_UNLABELED,
+ SECINITSID_NETMSG,
&nlbl_peer_sid) == 0)
sksec->peer_sid = nlbl_peer_sid;
netlbl_secattr_destroy(&secattr);
@@ -295,38 +298,42 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
struct avc_audit_data *ad)
{
int rc;
- u32 netlbl_sid;
- u32 recv_perm;
+ u32 nlbl_sid;
+ u32 perm;
+ struct netlbl_lsm_secattr secattr;
+
+ if (!netlbl_enabled())
+ return 0;
- rc = selinux_netlbl_skbuff_getsid(skb,
- SECINITSID_UNLABELED,
- &netlbl_sid);
+ netlbl_secattr_init(&secattr);
+ rc = netlbl_skbuff_getattr(skb, &secattr);
+ if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
+ rc = security_netlbl_secattr_to_sid(&secattr,
+ SECINITSID_NETMSG,
+ &nlbl_sid);
+ else
+ nlbl_sid = SECINITSID_UNLABELED;
+ netlbl_secattr_destroy(&secattr);
if (rc != 0)
return rc;
- if (netlbl_sid == SECSID_NULL)
- return 0;
-
switch (sksec->sclass) {
case SECCLASS_UDP_SOCKET:
- recv_perm = UDP_SOCKET__RECVFROM;
+ perm = UDP_SOCKET__RECVFROM;
break;
case SECCLASS_TCP_SOCKET:
- recv_perm = TCP_SOCKET__RECVFROM;
+ perm = TCP_SOCKET__RECVFROM;
break;
default:
- recv_perm = RAWIP_SOCKET__RECVFROM;
+ perm = RAWIP_SOCKET__RECVFROM;
}
- rc = avc_has_perm(sksec->sid,
- netlbl_sid,
- sksec->sclass,
- recv_perm,
- ad);
+ rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
if (rc == 0)
return 0;
- netlbl_skbuff_err(skb, rc);
+ if (nlbl_sid != SECINITSID_UNLABELED)
+ netlbl_skbuff_err(skb, rc);
return rc;
}
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index ccfe8755735e..eddc7b420109 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -110,6 +110,8 @@ static struct nlmsg_perm nlmsg_audit_perms[] =
{ AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
{ AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
{ AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_TTY_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_TTY_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
};
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index aca099aa2ed3..c9e92daedee2 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -67,6 +67,10 @@ static struct dentry *bool_dir = NULL;
static int bool_num = 0;
static int *bool_pending_values = NULL;
+/* global data for classes */
+static struct dentry *class_dir = NULL;
+static unsigned long last_class_ino;
+
extern void selnl_notify_setenforce(int val);
/* Check whether a task is allowed to use a security operation. */
@@ -106,6 +110,7 @@ static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
#define SEL_INITCON_INO_OFFSET 0x01000000
#define SEL_BOOL_INO_OFFSET 0x02000000
+#define SEL_CLASS_INO_OFFSET 0x04000000
#define SEL_INO_MASK 0x00ffffff
#define TMPBUFLEN 12
@@ -237,6 +242,11 @@ static const struct file_operations sel_policyvers_ops = {
/* declaration for sel_write_load */
static int sel_make_bools(void);
+static int sel_make_classes(void);
+
+/* declaration for sel_make_class_dirs */
+static int sel_make_dir(struct inode *dir, struct dentry *dentry,
+ unsigned long *ino);
static ssize_t sel_read_mls(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
@@ -287,10 +297,18 @@ static ssize_t sel_write_load(struct file * file, const char __user * buf,
goto out;
ret = sel_make_bools();
+ if (ret) {
+ length = ret;
+ goto out1;
+ }
+
+ ret = sel_make_classes();
if (ret)
length = ret;
else
length = count;
+
+out1:
audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
"policy loaded auid=%u",
audit_get_loginuid(current->audit_context));
@@ -940,9 +958,8 @@ static const struct file_operations sel_commit_bools_ops = {
.write = sel_commit_bools_write,
};
-/* delete booleans - partial revoke() from
- * fs/proc/generic.c proc_kill_inodes */
-static void sel_remove_bools(struct dentry *de)
+/* partial revoke() from fs/proc/generic.c proc_kill_inodes */
+static void sel_remove_entries(struct dentry *de)
{
struct list_head *p, *node;
struct super_block *sb = de->d_sb;
@@ -998,7 +1015,7 @@ static int sel_make_bools(void)
kfree(bool_pending_values);
bool_pending_values = NULL;
- sel_remove_bools(dir);
+ sel_remove_entries(dir);
if (!(page = (char*)get_zeroed_page(GFP_KERNEL)))
return -ENOMEM;
@@ -1048,7 +1065,7 @@ out:
return ret;
err:
kfree(values);
- sel_remove_bools(dir);
+ sel_remove_entries(dir);
ret = -ENOMEM;
goto out;
}
@@ -1294,7 +1311,227 @@ out:
return ret;
}
-static int sel_make_dir(struct inode *dir, struct dentry *dentry)
+static inline unsigned int sel_div(unsigned long a, unsigned long b)
+{
+ return a / b - (a % b < 0);
+}
+
+static inline unsigned long sel_class_to_ino(u16 class)
+{
+ return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
+}
+
+static inline u16 sel_ino_to_class(unsigned long ino)
+{
+ return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1);
+}
+
+static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
+{
+ return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;
+}
+
+static inline u32 sel_ino_to_perm(unsigned long ino)
+{
+ return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);
+}
+
+static ssize_t sel_read_class(struct file * file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t rc, len;
+ char *page;
+ unsigned long ino = file->f_path.dentry->d_inode->i_ino;
+
+ page = (char *)__get_free_page(GFP_KERNEL);
+ if (!page) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ len = snprintf(page, PAGE_SIZE, "%d", sel_ino_to_class(ino));
+ rc = simple_read_from_buffer(buf, count, ppos, page, len);
+ free_page((unsigned long)page);
+out:
+ return rc;
+}
+
+static const struct file_operations sel_class_ops = {
+ .read = sel_read_class,
+};
+
+static ssize_t sel_read_perm(struct file * file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ssize_t rc, len;
+ char *page;
+ unsigned long ino = file->f_path.dentry->d_inode->i_ino;
+
+ page = (char *)__get_free_page(GFP_KERNEL);
+ if (!page) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ len = snprintf(page, PAGE_SIZE,"%d", sel_ino_to_perm(ino));
+ rc = simple_read_from_buffer(buf, count, ppos, page, len);
+ free_page((unsigned long)page);
+out:
+ return rc;
+}
+
+static const struct file_operations sel_perm_ops = {
+ .read = sel_read_perm,
+};
+
+static int sel_make_perm_files(char *objclass, int classvalue,
+ struct dentry *dir)
+{
+ int i, rc = 0, nperms;
+ char **perms;
+
+ rc = security_get_permissions(objclass, &perms, &nperms);
+ if (rc)
+ goto out;
+
+ for (i = 0; i < nperms; i++) {
+ struct inode *inode;
+ struct dentry *dentry;
+
+ dentry = d_alloc_name(dir, perms[i]);
+ if (!dentry) {
+ rc = -ENOMEM;
+ goto out1;
+ }
+
+ inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
+ if (!inode) {
+ rc = -ENOMEM;
+ goto out1;
+ }
+ inode->i_fop = &sel_perm_ops;
+ /* i+1 since perm values are 1-indexed */
+ inode->i_ino = sel_perm_to_ino(classvalue, i+1);
+ d_add(dentry, inode);
+ }
+
+out1:
+ for (i = 0; i < nperms; i++)
+ kfree(perms[i]);
+ kfree(perms);
+out:
+ return rc;
+}
+
+static int sel_make_class_dir_entries(char *classname, int index,
+ struct dentry *dir)
+{
+ struct dentry *dentry = NULL;
+ struct inode *inode = NULL;
+ int rc;
+
+ dentry = d_alloc_name(dir, "index");
+ if (!dentry) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
+ if (!inode) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ inode->i_fop = &sel_class_ops;
+ inode->i_ino = sel_class_to_ino(index);
+ d_add(dentry, inode);
+
+ dentry = d_alloc_name(dir, "perms");
+ if (!dentry) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = sel_make_dir(dir->d_inode, dentry, &last_class_ino);
+ if (rc)
+ goto out;
+
+ rc = sel_make_perm_files(classname, index, dentry);
+
+out:
+ return rc;
+}
+
+static void sel_remove_classes(void)
+{
+ struct list_head *class_node;
+
+ list_for_each(class_node, &class_dir->d_subdirs) {
+ struct dentry *class_subdir = list_entry(class_node,
+ struct dentry, d_u.d_child);
+ struct list_head *class_subdir_node;
+
+ list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
+ struct dentry *d = list_entry(class_subdir_node,
+ struct dentry, d_u.d_child);
+
+ if (d->d_inode)
+ if (d->d_inode->i_mode & S_IFDIR)
+ sel_remove_entries(d);
+ }
+
+ sel_remove_entries(class_subdir);
+ }
+
+ sel_remove_entries(class_dir);
+}
+
+static int sel_make_classes(void)
+{
+ int rc = 0, nclasses, i;
+ char **classes;
+
+ /* delete any existing entries */
+ sel_remove_classes();
+
+ rc = security_get_classes(&classes, &nclasses);
+ if (rc < 0)
+ goto out;
+
+ /* +2 since classes are 1-indexed */
+ last_class_ino = sel_class_to_ino(nclasses+2);
+
+ for (i = 0; i < nclasses; i++) {
+ struct dentry *class_name_dir;
+
+ class_name_dir = d_alloc_name(class_dir, classes[i]);
+ if (!class_name_dir) {
+ rc = -ENOMEM;
+ goto out1;
+ }
+
+ rc = sel_make_dir(class_dir->d_inode, class_name_dir,
+ &last_class_ino);
+ if (rc)
+ goto out1;
+
+ /* i+1 since class values are 1-indexed */
+ rc = sel_make_class_dir_entries(classes[i], i+1,
+ class_name_dir);
+ if (rc)
+ goto out1;
+ }
+
+out1:
+ for (i = 0; i < nclasses; i++)
+ kfree(classes[i]);
+ kfree(classes);
+out:
+ return rc;
+}
+
+static int sel_make_dir(struct inode *dir, struct dentry *dentry,
+ unsigned long *ino)
{
int ret = 0;
struct inode *inode;
@@ -1306,7 +1543,7 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry)
}
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
- inode->i_ino = ++sel_last_ino;
+ inode->i_ino = ++(*ino);
/* directory inodes start off with i_nlink == 2 (for "." entry) */
inc_nlink(inode);
d_add(dentry, inode);
@@ -1352,7 +1589,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
goto err;
}
- ret = sel_make_dir(root_inode, dentry);
+ ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
if (ret)
goto err;
@@ -1385,7 +1622,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
goto err;
}
- ret = sel_make_dir(root_inode, dentry);
+ ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
if (ret)
goto err;
@@ -1399,7 +1636,7 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
goto err;
}
- ret = sel_make_dir(root_inode, dentry);
+ ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
if (ret)
goto err;
@@ -1407,6 +1644,18 @@ static int sel_fill_super(struct super_block * sb, void * data, int silent)
if (ret)
goto err;
+ dentry = d_alloc_name(sb->s_root, "class");
+ if (!dentry) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = sel_make_dir(root_inode, dentry, &sel_last_ino);
+ if (ret)
+ goto err;
+
+ class_dir = dentry;
+
out:
return ret;
err:
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 3122908afdc1..85705eb289e0 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -445,7 +445,7 @@ void avtab_cache_init(void)
{
avtab_node_cachep = kmem_cache_create("avtab_node",
sizeof(struct avtab_node),
- 0, SLAB_PANIC, NULL, NULL);
+ 0, SLAB_PANIC, NULL);
}
void avtab_cache_destroy(void)
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 0ac1021734c0..f05f97a2bc3a 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -21,6 +21,7 @@
*/
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
@@ -598,6 +599,7 @@ void policydb_destroy(struct policydb *p)
struct range_trans *rt, *lrt = NULL;
for (i = 0; i < SYM_NUM; i++) {
+ cond_resched();
hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
hashtab_destroy(p->symtab[i].table);
}
@@ -612,6 +614,7 @@ void policydb_destroy(struct policydb *p)
avtab_destroy(&p->te_avtab);
for (i = 0; i < OCON_NUM; i++) {
+ cond_resched();
c = p->ocontexts[i];
while (c) {
ctmp = c;
@@ -623,6 +626,7 @@ void policydb_destroy(struct policydb *p)
g = p->genfs;
while (g) {
+ cond_resched();
kfree(g->fstype);
c = g->head;
while (c) {
@@ -639,18 +643,21 @@ void policydb_destroy(struct policydb *p)
cond_policydb_destroy(p);
for (tr = p->role_tr; tr; tr = tr->next) {
+ cond_resched();
kfree(ltr);
ltr = tr;
}
kfree(ltr);
for (ra = p->role_allow; ra; ra = ra -> next) {
+ cond_resched();
kfree(lra);
lra = ra;
}
kfree(lra);
for (rt = p->range_tr; rt; rt = rt -> next) {
+ cond_resched();
if (lrt) {
ebitmap_destroy(&lrt->target_range.level[0].cat);
ebitmap_destroy(&lrt->target_range.level[1].cat);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 40660ffd49b6..b5f017f07a75 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1587,19 +1587,18 @@ int security_get_user_sids(u32 fromsid,
u32 *nel)
{
struct context *fromcon, usercon;
- u32 *mysids, *mysids2, sid;
+ u32 *mysids = NULL, *mysids2, sid;
u32 mynel = 0, maxnel = SIDS_NEL;
struct user_datum *user;
struct role_datum *role;
- struct av_decision avd;
struct ebitmap_node *rnode, *tnode;
int rc = 0, i, j;
- if (!ss_initialized) {
- *sids = NULL;
- *nel = 0;
+ *sids = NULL;
+ *nel = 0;
+
+ if (!ss_initialized)
goto out;
- }
POLICY_RDLOCK;
@@ -1635,17 +1634,9 @@ int security_get_user_sids(u32 fromsid,
if (mls_setup_user_range(fromcon, user, &usercon))
continue;
- rc = context_struct_compute_av(fromcon, &usercon,
- SECCLASS_PROCESS,
- PROCESS__TRANSITION,
- &avd);
- if (rc || !(avd.allowed & PROCESS__TRANSITION))
- continue;
rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
- if (rc) {
- kfree(mysids);
+ if (rc)
goto out_unlock;
- }
if (mynel < maxnel) {
mysids[mynel++] = sid;
} else {
@@ -1653,7 +1644,6 @@ int security_get_user_sids(u32 fromsid,
mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
if (!mysids2) {
rc = -ENOMEM;
- kfree(mysids);
goto out_unlock;
}
memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
@@ -1664,11 +1654,32 @@ int security_get_user_sids(u32 fromsid,
}
}
- *sids = mysids;
- *nel = mynel;
-
out_unlock:
POLICY_RDUNLOCK;
+ if (rc || !mynel) {
+ kfree(mysids);
+ goto out;
+ }
+
+ mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
+ if (!mysids2) {
+ rc = -ENOMEM;
+ kfree(mysids);
+ goto out;
+ }
+ for (i = 0, j = 0; i < mynel; i++) {
+ rc = avc_has_perm_noaudit(fromsid, mysids[i],
+ SECCLASS_PROCESS,
+ PROCESS__TRANSITION, AVC_STRICT,
+ NULL);
+ if (!rc)
+ mysids2[j++] = mysids[i];
+ cond_resched();
+ }
+ rc = 0;
+ kfree(mysids);
+ *sids = mysids2;
+ *nel = j;
out:
return rc;
}
@@ -1996,6 +2007,101 @@ out:
return rc;
}
+static int get_classes_callback(void *k, void *d, void *args)
+{
+ struct class_datum *datum = d;
+ char *name = k, **classes = args;
+ int value = datum->value - 1;
+
+ classes[value] = kstrdup(name, GFP_ATOMIC);
+ if (!classes[value])
+ return -ENOMEM;
+
+ return 0;
+}
+
+int security_get_classes(char ***classes, int *nclasses)
+{
+ int rc = -ENOMEM;
+
+ POLICY_RDLOCK;
+
+ *nclasses = policydb.p_classes.nprim;
+ *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC);
+ if (!*classes)
+ goto out;
+
+ rc = hashtab_map(policydb.p_classes.table, get_classes_callback,
+ *classes);
+ if (rc < 0) {
+ int i;
+ for (i = 0; i < *nclasses; i++)
+ kfree((*classes)[i]);
+ kfree(*classes);
+ }
+
+out:
+ POLICY_RDUNLOCK;
+ return rc;
+}
+
+static int get_permissions_callback(void *k, void *d, void *args)
+{
+ struct perm_datum *datum = d;
+ char *name = k, **perms = args;
+ int value = datum->value - 1;
+
+ perms[value] = kstrdup(name, GFP_ATOMIC);
+ if (!perms[value])
+ return -ENOMEM;
+
+ return 0;
+}
+
+int security_get_permissions(char *class, char ***perms, int *nperms)
+{
+ int rc = -ENOMEM, i;
+ struct class_datum *match;
+
+ POLICY_RDLOCK;
+
+ match = hashtab_search(policydb.p_classes.table, class);
+ if (!match) {
+ printk(KERN_ERR "%s: unrecognized class %s\n",
+ __FUNCTION__, class);
+ rc = -EINVAL;
+ goto out;
+ }
+
+ *nperms = match->permissions.nprim;
+ *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC);
+ if (!*perms)
+ goto out;
+
+ if (match->comdatum) {
+ rc = hashtab_map(match->comdatum->permissions.table,
+ get_permissions_callback, *perms);
+ if (rc < 0)
+ goto err;
+ }
+
+ rc = hashtab_map(match->permissions.table, get_permissions_callback,
+ *perms);
+ if (rc < 0)
+ goto err;
+
+out:
+ POLICY_RDUNLOCK;
+ return rc;
+
+err:
+ POLICY_RDUNLOCK;
+ for (i = 0; i < *nperms; i++)
+ kfree((*perms)[i]);
+ kfree(*perms);
+ return rc;
+}
+
struct selinux_audit_rule {
u32 au_seqno;
struct context au_ctxt;
diff --git a/sound/Kconfig b/sound/Kconfig
index 9ea473823418..e48b9b37d228 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -65,6 +65,8 @@ source "sound/arm/Kconfig"
source "sound/mips/Kconfig"
+source "sound/sh/Kconfig"
+
# the following will depend on the order of config.
# here assuming USB is defined before ALSA
source "sound/usb/Kconfig"
diff --git a/sound/Makefile b/sound/Makefile
index b7c7fb7c24c8..3ead922bd9c6 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
-obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
+obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/ soc/
obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
diff --git a/sound/aoa/codecs/snd-aoa-codec-onyx.c b/sound/aoa/codecs/snd-aoa-codec-onyx.c
index ded516717940..028852374f21 100644
--- a/sound/aoa/codecs/snd-aoa-codec-onyx.c
+++ b/sound/aoa/codecs/snd-aoa-codec-onyx.c
@@ -661,7 +661,7 @@ static struct transfer_info onyx_transfers[] = {
.tag = 2,
},
#ifdef SNDRV_PCM_FMTBIT_COMPRESSED_16BE
-Once alsa gets supports for this kind of thing we can add it...
+ /* Once alsa gets supports for this kind of thing we can add it... */
{
/* digital compressed output */
.formats = SNDRV_PCM_FMTBIT_COMPRESSED_16BE,
@@ -713,7 +713,7 @@ static int onyx_prepare(struct codec_info_item *cii,
if (substream->runtime->format == SNDRV_PCM_FMTBIT_COMPRESSED_16BE) {
/* mute and lock analog output */
onyx_read_register(onyx, ONYX_REG_DAC_CONTROL, &v);
- if (onyx_write_register(onyx
+ if (onyx_write_register(onyx,
ONYX_REG_DAC_CONTROL,
v | ONYX_MUTE_RIGHT | ONYX_MUTE_LEFT))
goto out_unlock;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index a96733a5beb8..59b29cd482ae 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1487,7 +1487,7 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream)
snd_pcm_stream_lock_irq(substream);
/* resume pause */
- if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_PAUSED)
snd_pcm_pause(substream, 0);
/* pre-start/stop - all running streams are changed to DRAINING state */
diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c
index f30d171b6d96..5efe6523a589 100644
--- a/sound/core/seq/seq_instr.c
+++ b/sound/core/seq/seq_instr.c
@@ -109,7 +109,7 @@ void snd_seq_instr_list_free(struct snd_seq_kinstr_list **list_ptr)
spin_lock_irqsave(&list->lock, flags);
while (instr->use) {
spin_unlock_irqrestore(&list->lock, flags);
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
spin_lock_irqsave(&list->lock, flags);
}
spin_unlock_irqrestore(&list->lock, flags);
@@ -199,7 +199,7 @@ int snd_seq_instr_list_free_cond(struct snd_seq_kinstr_list *list,
instr = flist;
flist = instr->next;
while (instr->use)
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
if (snd_seq_instr_free(instr, atomic)<0)
snd_printk(KERN_WARNING "instrument free problem\n");
instr = next;
@@ -555,7 +555,7 @@ static int instr_free(struct snd_seq_kinstr_ops *ops,
SNDRV_SEQ_INSTR_NOTIFY_REMOVE);
while (instr->use) {
spin_unlock_irqrestore(&list->lock, flags);
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
spin_lock_irqsave(&list->lock, flags);
}
spin_unlock_irqrestore(&list->lock, flags);
diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c
index 061a7c61402a..e11790f6debe 100644
--- a/sound/core/seq/seq_virmidi.c
+++ b/sound/core/seq/seq_virmidi.c
@@ -363,7 +363,7 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
if (rdev->client >= 0)
return 0;
- pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL);
+ pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
if (!pinfo) {
err = -ENOMEM;
goto __error;
@@ -380,7 +380,6 @@ static int snd_virmidi_dev_attach_seq(struct snd_virmidi_dev *rdev)
rdev->client = client;
/* create a port */
- memset(pinfo, 0, sizeof(*pinfo));
pinfo->addr.client = client;
sprintf(pinfo->name, "VirMIDI %d-%d", rdev->card->number, rdev->device);
/* set all capabilities */
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 70600df94d62..8dc7a3b32b98 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -446,8 +446,7 @@ static void __exit alsa_sound_exit(void)
{
snd_info_minor_unregister();
snd_info_done();
- if (unregister_chrdev(major, "alsa") != 0)
- snd_printk(KERN_ERR "unable to unregister major device number %d\n", major);
+ unregister_chrdev(major, "alsa");
}
module_init(alsa_sound_init)
diff --git a/sound/core/timer.c b/sound/core/timer.c
index 67520b3c0042..f2bbacedd567 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1549,9 +1549,11 @@ static int snd_timer_user_info(struct file *file,
int err = 0;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
t = tu->timeri->timer;
- snd_assert(t != NULL, return -ENXIO);
+ if (!t)
+ return -EBADFD;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (! info)
@@ -1579,9 +1581,11 @@ static int snd_timer_user_params(struct file *file,
int err;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
t = tu->timeri->timer;
- snd_assert(t != NULL, return -ENXIO);
+ if (!t)
+ return -EBADFD;
if (copy_from_user(&params, _params, sizeof(params)))
return -EFAULT;
if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
@@ -1675,7 +1679,8 @@ static int snd_timer_user_status(struct file *file,
struct snd_timer_status status;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp;
status.resolution = snd_timer_resolution(tu->timeri);
@@ -1695,7 +1700,8 @@ static int snd_timer_user_start(struct file *file)
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
snd_timer_stop(tu->timeri);
tu->timeri->lost = 0;
tu->last_resolution = 0;
@@ -1708,7 +1714,8 @@ static int snd_timer_user_stop(struct file *file)
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
}
@@ -1718,7 +1725,8 @@ static int snd_timer_user_continue(struct file *file)
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
tu->timeri->lost = 0;
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
}
@@ -1729,7 +1737,8 @@ static int snd_timer_user_pause(struct file *file)
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
}
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c
index a0f28f51fc7e..4360ae9de19c 100644
--- a/sound/drivers/dummy.c
+++ b/sound/drivers/dummy.c
@@ -659,7 +659,7 @@ static struct platform_driver snd_dummy_driver = {
},
};
-static void __init_or_module snd_dummy_unregister_all(void)
+static void snd_dummy_unregister_all(void)
{
int i;
diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c
index 1d563e515c17..67c6e9745418 100644
--- a/sound/drivers/mpu401/mpu401.c
+++ b/sound/drivers/mpu401/mpu401.c
@@ -228,7 +228,7 @@ static struct pnp_driver snd_mpu401_pnp_driver = {
static struct pnp_driver snd_mpu401_pnp_driver;
#endif
-static void __init_or_module snd_mpu401_unregister_all(void)
+static void snd_mpu401_unregister_all(void)
{
int i;
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c
index 497cafb57d9b..0eb9b5cebfcd 100644
--- a/sound/drivers/portman2x4.c
+++ b/sound/drivers/portman2x4.c
@@ -833,7 +833,7 @@ static struct platform_driver snd_portman_driver = {
/*********************************************************************
* module init stuff
*********************************************************************/
-static void __init_or_module snd_portman_unregister_all(void)
+static void snd_portman_unregister_all(void)
{
int i;
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 838a4277929d..d3e6a20edd38 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -998,7 +998,7 @@ static struct platform_driver snd_serial_driver = {
},
};
-static void __init_or_module snd_serial_unregister_all(void)
+static void snd_serial_unregister_all(void)
{
int i;
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index 46f3d3486067..915c86773c21 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -145,7 +145,7 @@ static struct platform_driver snd_virmidi_driver = {
},
};
-static void __init_or_module snd_virmidi_unregister_all(void)
+static void snd_virmidi_unregister_all(void)
{
int i;
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index 8805110017a7..fd335159f849 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -481,8 +481,8 @@ static int ak4xxx_switch_get(struct snd_kcontrol *kcontrol,
int addr = AK_GET_ADDR(kcontrol->private_value);
int shift = AK_GET_SHIFT(kcontrol->private_value);
int invert = AK_GET_INVERT(kcontrol->private_value);
- unsigned char val = snd_akm4xxx_get(ak, chip, addr);
-
+ /* we observe the (1<<shift) bit only */
+ unsigned char val = snd_akm4xxx_get(ak, chip, addr) & (1<<shift);
if (invert)
val = ! val;
ucontrol->value.integer.value[0] = (val & (1<<shift)) != 0;
@@ -585,6 +585,26 @@ static int build_dac_controls(struct snd_akm4xxx *ak)
mixer_ch = 0;
for (idx = 0; idx < ak->num_dacs; ) {
+ /* mute control for Revolution 7.1 - AK4381 */
+ if (ak->type == SND_AK4381
+ && ak->dac_info[mixer_ch].switch_name) {
+ memset(&knew, 0, sizeof(knew));
+ knew.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ knew.count = 1;
+ knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ knew.name = ak->dac_info[mixer_ch].switch_name;
+ knew.info = ak4xxx_switch_info;
+ knew.get = ak4xxx_switch_get;
+ knew.put = ak4xxx_switch_put;
+ knew.access = 0;
+ /* register 1, bit 0 (SMUTE): 0 = normal operation,
+ 1 = mute */
+ knew.private_value =
+ AK_COMPOSE(idx/2, 1, 0, 0) | AK_INVERT;
+ err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak));
+ if (err < 0)
+ return err;
+ }
memset(&knew, 0, sizeof(knew));
if (! ak->dac_info || ! ak->dac_info[mixer_ch].name) {
knew.name = "DAC Volume";
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index cf3803cd579c..ea5084abe60f 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -1,8 +1,5 @@
# ALSA ISA drivers
-menu "ISA devices"
- depends on SND!=n && ISA && ISA_DMA_API
-
config SND_AD1848_LIB
tristate
select SND_PCM
@@ -11,6 +8,22 @@ config SND_CS4231_LIB
tristate
select SND_PCM
+config SND_SB_COMMON
+ tristate
+
+config SND_SB8_DSP
+ tristate
+ select SND_PCM
+ select SND_SB_COMMON
+
+config SND_SB16_DSP
+ tristate
+ select SND_PCM
+ select SND_SB_COMMON
+
+menu "ISA devices"
+ depends on SND!=n && ISA && ISA_DMA_API
+
config SND_ADLIB
tristate "AdLib FM card"
depends on SND
@@ -55,7 +68,7 @@ config SND_ALS100
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB16_DSP
help
Say Y here to include support for soundcards based on Avance
Logic ALS100, ALS110, ALS120 and ALS200 chips.
@@ -81,6 +94,7 @@ config SND_CMI8330
tristate "C-Media CMI8330"
depends on SND
select SND_AD1848_LIB
+ select SND_SB16_DSP
help
Say Y here to include support for soundcards based on the
C-Media CMI8330 chip.
@@ -132,7 +146,7 @@ config SND_DT019X
select ISAPNP
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB16_DSP
help
Say Y here to include support for soundcards based on the
Diamond Technologies DT-019X or Avance Logic ALS-007 chips.
@@ -145,7 +159,7 @@ config SND_ES968
depends on SND && PNP && ISA
select ISAPNP
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB8_DSP
help
Say Y here to include support for ESS AudioDrive ES968 chips.
@@ -321,7 +335,7 @@ config SND_SB8
depends on SND
select SND_OPL3_LIB
select SND_RAWMIDI
- select SND_PCM
+ select SND_SB8_DSP
help
Say Y here to include support for Creative Sound Blaster 1.0/
2.0/Pro (8-bit) or 100% compatible soundcards.
@@ -334,7 +348,7 @@ config SND_SB16
depends on SND
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB16_DSP
help
Say Y here to include support for Sound Blaster 16 soundcards
(including the Plug and Play version).
@@ -347,7 +361,7 @@ config SND_SBAWE
depends on SND
select SND_OPL3_LIB
select SND_MPU401_UART
- select SND_PCM
+ select SND_SB16_DSP
help
Say Y here to include support for Sound Blaster AWE soundcards
(including the Plug and Play version).
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 8094282c2ae1..1bc2e3fd5721 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -245,7 +245,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
snd_printk(KERN_ERR "mce_down - auto calibration time out (2)\n");
return;
}
- time = schedule_timeout_interruptible(time);
+ time = schedule_timeout(time);
spin_lock_irqsave(&chip->reg_lock, flags);
}
#if 0
@@ -258,7 +258,7 @@ static void snd_ad1848_mce_down(struct snd_ad1848 *chip)
snd_printk(KERN_ERR "mce_down - auto calibration time out (3)\n");
return;
}
- time = schedule_timeout_interruptible(time);
+ time = schedule_timeout(time);
spin_lock_irqsave(&chip->reg_lock, flags);
}
spin_unlock_irqrestore(&chip->reg_lock, flags);
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index 4f6800b43b0e..e70db32991d9 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -164,6 +164,8 @@ static struct pnp_card_device_id snd_opl3sa2_pnpids[] = {
{ .id = "YMH0801", .devs = { { "YMH0021" } } },
/* NeoMagic MagicWave 3DX */
{ .id = "NMX2200", .devs = { { "YMH2210" } } },
+ /* NeoMagic MagicWave 3D */
+ { .id = "NMX2200", .devs = { { "NMX2210" } } },
/* --- */
{ .id = "" } /* end */
};
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 60c120ffb9de..049d479ce2b3 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -1927,10 +1927,12 @@ static struct snd_card *snd_opti9xx_card_new(void)
static int __devinit snd_opti9xx_isa_match(struct device *devptr,
unsigned int dev)
{
+#ifdef CONFIG_PNP
if (snd_opti9xx_pnp_is_probed)
return 0;
if (isapnp)
return 0;
+#endif
return 1;
}
@@ -2096,6 +2098,7 @@ static int __init alsa_card_opti9xx_init(void)
pnp_register_card_driver(&opti9xx_pnpc_driver);
if (snd_opti9xx_pnp_is_probed)
return 0;
+ pnp_unregister_card_driver(&opti9xx_pnpc_driver);
#endif
return isa_register_driver(&snd_opti9xx_driver, 1);
}
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile
index fd9d9c5726fc..556e66928029 100644
--- a/sound/isa/sb/Makefile
+++ b/sound/isa/sb/Makefile
@@ -22,14 +22,13 @@ snd-es968-objs := es968.o
sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1)))
# Toplevel Module Dependency
-obj-$(CONFIG_SND_ALS100) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_CMI8330) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_DT019X) += snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB8) += snd-sb8.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SB16) += snd-sb16.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o snd-sb16-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ES968) += snd-es968.o snd-sb8-dsp.o snd-sb-common.o
-obj-$(CONFIG_SND_ALS4000) += snd-sb-common.o
+obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o
+obj-$(CONFIG_SND_SB16_DSP) += snd-sb16-dsp.o
+obj-$(CONFIG_SND_SB8_DSP) += snd-sb8-dsp.o
+obj-$(CONFIG_SND_SB8) += snd-sb8.o
+obj-$(CONFIG_SND_SB16) += snd-sb16.o
+obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o
+obj-$(CONFIG_SND_ES968) += snd-es968.o
ifeq ($(CONFIG_SND_SB16_CSP),y)
obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o
obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 383911b9e74d..5d4d3aafe2d5 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -563,6 +563,11 @@ static int snd_sb16_playback_open(struct snd_pcm_substream *substream)
__open_ok:
if (chip->hardware == SB_HW_ALS100)
runtime->hw.rate_max = 48000;
+ if (chip->hardware == SB_HW_CS5530) {
+ runtime->hw.buffer_bytes_max = 32 * 1024;
+ runtime->hw.periods_min = 2;
+ runtime->hw.rate_min = 44100;
+ }
if (chip->mode & SB_RATE_LOCK)
runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
chip->playback_substream = substream;
@@ -633,6 +638,11 @@ static int snd_sb16_capture_open(struct snd_pcm_substream *substream)
__open_ok:
if (chip->hardware == SB_HW_ALS100)
runtime->hw.rate_max = 48000;
+ if (chip->hardware == SB_HW_CS5530) {
+ runtime->hw.buffer_bytes_max = 32 * 1024;
+ runtime->hw.periods_min = 2;
+ runtime->hw.rate_min = 44100;
+ }
if (chip->mode & SB_RATE_LOCK)
runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate;
chip->capture_substream = substream;
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index 3094f3852167..efa9d5c2558a 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -128,7 +128,7 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
minor = version & 0xff;
snd_printdd("SB [0x%lx]: DSP chip found, version = %i.%i\n",
chip->port, major, minor);
-
+
switch (chip->hardware) {
case SB_HW_AUTO:
switch (major) {
@@ -168,6 +168,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
case SB_HW_DT019X:
str = "(DT019X/ALS007)";
break;
+ case SB_HW_CS5530:
+ str = "16 (CS5530)";
+ break;
default:
return -ENODEV;
}
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 490b1ca5cf58..3d4befcff28e 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -821,6 +821,7 @@ int snd_sbmixer_new(struct snd_sb *chip)
break;
case SB_HW_16:
case SB_HW_ALS100:
+ case SB_HW_CS5530:
if ((err = snd_sbmixer_init(chip,
snd_sb16_controls,
ARRAY_SIZE(snd_sb16_controls),
@@ -950,6 +951,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip)
break;
case SB_HW_16:
case SB_HW_ALS100:
+ case SB_HW_CS5530:
save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
break;
case SB_HW_ALS4000:
@@ -975,6 +977,7 @@ void snd_sbmixer_resume(struct snd_sb *chip)
break;
case SB_HW_16:
case SB_HW_ALS100:
+ case SB_HW_CS5530:
restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
break;
case SB_HW_ALS4000:
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c
index 9ea417bcf3e5..cbad2a51cbaa 100644
--- a/sound/isa/sscape.c
+++ b/sound/isa/sscape.c
@@ -382,7 +382,7 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout)
unsigned long flags;
unsigned char x;
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
spin_lock_irqsave(&s->lock, flags);
x = inb(HOST_DATA_IO(s->io_base));
@@ -409,7 +409,7 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout)
unsigned long flags;
unsigned char x;
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
spin_lock_irqsave(&s->lock, flags);
x = inb(HOST_DATA_IO(s->io_base));
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c
index 78020d832e04..bacc51c86587 100644
--- a/sound/isa/wavefront/wavefront_synth.c
+++ b/sound/isa/wavefront/wavefront_synth.c
@@ -1780,7 +1780,7 @@ wavefront_should_cause_interrupt (snd_wavefront_t *dev,
outb (val,port);
spin_unlock_irq(&dev->irq_lock);
while (1) {
- if ((timeout = schedule_timeout_interruptible(timeout)) == 0)
+ if ((timeout = schedule_timeout(timeout)) == 0)
return;
if (dev->irq_ok)
return;
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 4b30ae6d8ba5..866d4de8d4ab 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -5,35 +5,6 @@
#
# Prompt user for primary drivers.
-config OSS_OBSOLETE
- bool "Obsolete OSS drivers"
- depends on SOUND_PRIME
- help
- This option enables support for obsolete OSS drivers that
- are scheduled for removal in the near future.
-
- Please contact Adrian Bunk <bunk@stusta.de> if you had to
- say Y here because your hardware is not properly supported
- by ALSA.
-
- If unsure, say N.
-
-config SOUND_BT878
- tristate "BT878 audio dma"
- depends on SOUND_PRIME && PCI && OSS_OBSOLETE
- ---help---
- Audio DMA support for bt878 based grabber boards. As you might have
- already noticed, bt878 is listed with two functions in /proc/pci.
- Function 0 does the video stuff (bt848 compatible), function 1 does
- the same for audio data. This is a driver for the audio part of
- the chip. If you say 'Y' here you get a oss-compatible dsp device
- where you can record from. If you want just watch TV you probably
- don't need this driver as most TV cards handle sound with a short
- cable from the TV card to your sound card's line-in.
-
- To compile this driver as a module, choose M here: the module will
- be called btaudio.
-
config SOUND_BCM_CS4297A
tristate "Crystal Sound CS4297a (for Swarm)"
depends on SOUND_PRIME && SIBYTE_SWARM
@@ -44,13 +15,6 @@ config SOUND_BCM_CS4297A
note that CONFIG_KGDB should not be enabled at the same
time, since it also attempts to use this UART port.
-config SOUND_ICH
- tristate "Intel ICH (i8xx) audio support"
- depends on SOUND_PRIME && PCI && OSS_OBSOLETE
- help
- Support for integral audio in Intel's I/O Controller Hub (ICH)
- chipset, as used on the 810/820/840 motherboards.
-
config SOUND_VWSND
tristate "SGI Visual Workstation Sound"
depends on SOUND_PRIME && X86_VISWS
@@ -346,29 +310,9 @@ config MSND_FIFOSIZE
and Pinnacle). Larger values reduce the chance of data overruns at
the expense of overall latency. If unsure, use the default.
-config SOUND_VIA82CXXX
- tristate "VIA 82C686 Audio Codec"
- depends on SOUND_PRIME && PCI && OSS_OBSOLETE
- help
- Say Y here to include support for the audio codec found on VIA
- 82Cxxx-based chips. Typically these are built into a motherboard.
-
- DO NOT select Sound Blaster or Adlib with this driver, unless
- you have a Sound Blaster or Adlib card in addition to your VIA
- audio chip.
-
-config MIDI_VIA82CXXX
- bool "VIA 82C686 MIDI"
- depends on SOUND_VIA82CXXX && ISA_DMA_API
- help
- Answer Y to use the MIDI interface of the Via686. You may need to
- enable this in the BIOS before it will work. This is for connection
- to external MIDI hardware, and is not required for software playback
- of MIDI files.
-
config SOUND_OSS
tristate "OSS sound modules"
- depends on SOUND_PRIME && ISA_DMA_API
+ depends on SOUND_PRIME && ISA_DMA_API && VIRT_TO_BUS
help
OSS is the Open Sound System suite of sound card drivers. They make
sound programming easier since they provide a common API. Say Y or
@@ -400,23 +344,10 @@ config SOUND_DMAP
Say Y unless you have 16MB or more RAM or a PCI sound card.
-config SOUND_CS4232
- tristate "Crystal CS4232 based (PnP) cards"
- depends on SOUND_OSS && OSS_OBSOLETE
- help
- Say Y here if you have a card based on the Crystal CS4232 chip set,
- which uses its own Plug and Play protocol.
-
- If you compile the driver into the kernel, you have to add
- "cs4232=<io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>" to the kernel
- command line.
-
- See <file:Documentation/sound/oss/CS4232> for more information on
- configuring this card.
-
config SOUND_SSCAPE
tristate "Ensoniq SoundScape support"
depends on SOUND_OSS
+ depends on VIRT_TO_BUS
help
Answer Y if you have a sound card based on the Ensoniq SoundScape
chipset. Such cards are being manufactured at least by Ensoniq, Spea
@@ -719,13 +650,6 @@ config SOUND_WAVEARTIST
Say Y here to include support for the Rockwell WaveArtist sound
system. This driver is mainly for the NetWinder.
-config SOUND_TVMIXER
- tristate "TV card (bt848) mixer support"
- depends on SOUND_PRIME && I2C && VIDEO_V4L1 && OSS_OBSOLETE
- help
- Support for audio mixer facilities on the BT848 TV frame-grabber
- card.
-
config SOUND_KAHLUA
tristate "XpressAudio Sound Blaster emulation"
depends on SOUND_SB
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 2489bd6bb085..7a2f9ae7b7c5 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -18,20 +18,15 @@ obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
-obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
obj-$(CONFIG_SOUND_UART6850) += uart6850.o
-obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o
obj-$(CONFIG_SOUND_YM3812) += opl3.o
obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
-obj-$(CONFIG_SOUND_AD1816) += ad1816.o
-obj-$(CONFIG_SOUND_AD1889) += ad1889.o ac97_codec.o
-obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
@@ -40,24 +35,16 @@ endif
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
-obj-$(CONFIG_SOUND_NM256) += nm256_audio.o ac97.o
obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o
obj-$(CONFIG_SOUND_VRC5477) += nec_vrc5477.o ac97_codec.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
-obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
-obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
obj-$(CONFIG_SOUND_BT878) += btaudio.o
obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
-ifeq ($(CONFIG_MIDI_EMU10K1),y)
- obj-$(CONFIG_SOUND_EMU10K1) += sound.o
-endif
-
-obj-$(CONFIG_SOUND_EMU10K1) += emu10k1/
obj-$(CONFIG_DMASOUND) += dmasound/
# Declare multi-part drivers.
diff --git a/sound/oss/ac97.c b/sound/oss/ac97.c
deleted file mode 100644
index 72cf4ed77937..000000000000
--- a/sound/oss/ac97.c
+++ /dev/null
@@ -1,432 +0,0 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include "ac97.h"
-
-/* Flag for mono controls. */
-#define MO 0
-/* And for stereo. */
-#define ST 1
-
-/* Whether or not the bits in the channel are inverted. */
-#define INV 1
-#define NINV 0
-
-static struct ac97_chn_desc {
- int ac97_regnum;
- int oss_channel;
- int maxval;
- int is_stereo;
- int oss_mask;
- int recordNum;
- u16 regmask;
- int is_inverted;
-} mixerRegs[] = {
- { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME, 0x3f, ST, SOUND_MASK_VOLUME, 5, 0x0000, INV },
- { AC97_MASTER_VOL_MONO, SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000, INV },
- { AC97_MASTER_TONE, SOUND_MIXER_TREBLE, 0x0f, MO, SOUND_MASK_TREBLE, -1, 0x00ff, INV },
- { AC97_MASTER_TONE, SOUND_MIXER_BASS, 0x0f, MO, SOUND_MASK_BASS, -1, 0xff00, INV },
- { AC97_PCBEEP_VOL, SOUND_MIXER_SPEAKER, 0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e, INV },
- { AC97_PHONE_VOL, SOUND_MIXER_PHONEIN, 0x1f, MO, SOUND_MASK_PHONEIN, 7, 0x0000, INV },
- { AC97_MIC_VOL, SOUND_MIXER_MIC, 0x1f, MO, SOUND_MASK_MIC, 0, 0x0000, INV },
- { AC97_LINEIN_VOL, SOUND_MIXER_LINE, 0x1f, ST, SOUND_MASK_LINE, 4, 0x0000, INV },
- { AC97_CD_VOL, SOUND_MIXER_CD, 0x1f, ST, SOUND_MASK_CD, 1, 0x0000, INV },
- { AC97_VIDEO_VOL, SOUND_MIXER_VIDEO, 0x1f, ST, SOUND_MASK_VIDEO, 2, 0x0000, INV },
- { AC97_AUX_VOL, SOUND_MIXER_LINE1, 0x1f, ST, SOUND_MASK_LINE1, 3, 0x0000, INV },
- { AC97_PCMOUT_VOL, SOUND_MIXER_PCM, 0x1f, ST, SOUND_MASK_PCM, -1, 0x0000, INV },
- { AC97_RECORD_GAIN, SOUND_MIXER_IGAIN, 0x0f, ST, SOUND_MASK_IGAIN, -1, 0x0000, NINV },
- { -1, -1, 0xff, 0, 0, -1, 0x0000, 0 },
-};
-
-static struct ac97_chn_desc *
-ac97_find_chndesc (struct ac97_hwint *dev, int oss_channel)
-{
- int x;
-
- for (x = 0; mixerRegs[x].oss_channel != -1; x++) {
- if (mixerRegs[x].oss_channel == oss_channel)
- return mixerRegs + x;
- }
-
- return NULL;
-}
-
-static inline int
-ac97_is_valid_channel (struct ac97_hwint *dev, struct ac97_chn_desc *chn)
-{
- return (dev->last_written_mixer_values[chn->ac97_regnum / 2]
- != AC97_REG_UNSUPPORTED);
-}
-
-int
-ac97_init (struct ac97_hwint *dev)
-{
- int x;
- int reg0;
-
- /* Clear out the arrays of cached values. */
- for (x = 0; x < AC97_REG_CNT; x++)
- dev->last_written_mixer_values[x] = AC97_REGVAL_UNKNOWN;
-
- for (x = 0; x < SOUND_MIXER_NRDEVICES; x++)
- dev->last_written_OSS_values[x] = AC97_REGVAL_UNKNOWN;
-
- /* Clear the device masks. */
- dev->mixer_devmask = 0;
- dev->mixer_stereomask = 0;
- dev->mixer_recmask = 0;
-
- /* ??? Do a "standard reset" via register 0? */
-
- /* Hardware-dependent reset. */
- if (dev->reset_device (dev))
- return -1;
-
- /* Check the mixer device capabilities. */
- reg0 = dev->read_reg (dev, AC97_RESET);
-
- if (reg0 < 0)
- return -1;
-
- /* Check for support for treble/bass controls. */
- if (! (reg0 & 4)) {
- dev->last_written_mixer_values[AC97_MASTER_TONE / 2]
- = AC97_REG_UNSUPPORTED;
- }
-
- /* ??? There may be other tests here? */
-
- /* Fill in the device masks. */
- for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
- if (ac97_is_valid_channel (dev, mixerRegs + x)) {
- dev->mixer_devmask |= mixerRegs[x].oss_mask;
-
- if (mixerRegs[x].is_stereo)
- dev->mixer_stereomask |= mixerRegs[x].oss_mask;
-
- if (mixerRegs[x].recordNum != -1)
- dev->mixer_recmask |= mixerRegs[x].oss_mask;
- }
- }
-
- return 0;
-}
-
-/* Return the contents of register REG; use the cache if the value in it
- is valid. Returns a negative error code on failure. */
-static int
-ac97_get_register (struct ac97_hwint *dev, u8 reg)
-{
- if (reg > 127 || (reg & 1))
- return -EINVAL;
-
- /* See if it's in the cache, or if it's just plain invalid. */
- switch (dev->last_written_mixer_values[reg / 2]) {
- case AC97_REG_UNSUPPORTED:
- return -EINVAL;
- break;
- case AC97_REGVAL_UNKNOWN:
- dev->last_written_mixer_values[reg / 2] = dev->read_reg (dev, reg);
- break;
- default:
- break;
- }
- return dev->last_written_mixer_values[reg / 2];
-}
-
-/* Write VALUE to AC97 register REG, and cache its value in the last-written
- cache. Returns a negative error code on failure, or 0 on success. */
-int
-ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value)
-{
- if (reg > 127 || (reg & 1))
- return -EINVAL;
-
- if (dev->last_written_mixer_values[reg / 2] == AC97_REG_UNSUPPORTED)
- return -EINVAL;
- else {
- int res = dev->write_reg (dev, reg, value);
- if (res >= 0) {
- dev->last_written_mixer_values[reg / 2] = value;
- return 0;
- }
- else
- return res;
- }
-}
-
-/* Scale VALUE (a value fro 0 to MAXVAL) to a value from 0-100. If
- IS_STEREO is set, VALUE is a stereo value; the left channel value
- is in the lower 8 bits, and the right channel value is in the upper
- 8 bits.
-
- A negative error code is returned on failure, or the unsigned
- scaled value on success. */
-
-static int
-ac97_scale_to_oss_val (int value, int maxval, int is_stereo, int inv)
-{
- /* Muted? */
- if (value & AC97_MUTE)
- return 0;
-
- if (is_stereo)
- return (ac97_scale_to_oss_val (value & 255, maxval, 0, inv) << 8)
- | (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
- else {
- int i;
-
- /* Inverted. */
- if (inv)
- value = maxval - value;
-
- i = (value * 100 + (maxval / 2)) / maxval;
- if (i > 100)
- i = 100;
- if (i < 0)
- i = 0;
- return i;
- }
-}
-
-static int
-ac97_scale_from_oss_val (int value, int maxval, int is_stereo, int inv)
-{
- if (is_stereo)
- return (ac97_scale_from_oss_val (value & 255, maxval, 0, inv) << 8)
- | (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
- else {
- int i = ((value & 255) * maxval + 50) / 100;
- if (inv)
- i = maxval - i;
- if (i < 0)
- i = 0;
- if (i > maxval)
- i = maxval;
- return i;
- }
-}
-
-static int
-ac97_set_mixer (struct ac97_hwint *dev, int oss_channel, u16 oss_value)
-{
- int scaled_value;
- struct ac97_chn_desc *channel = ac97_find_chndesc (dev, oss_channel);
- int result;
-
- if (channel == NULL)
- return -ENODEV;
- if (! ac97_is_valid_channel (dev, channel))
- return -ENODEV;
- scaled_value = ac97_scale_from_oss_val (oss_value, channel->maxval,
- channel->is_stereo,
- channel->is_inverted);
- if (scaled_value < 0)
- return scaled_value;
-
- if (channel->regmask != 0) {
- int mv;
-
- int oldval = ac97_get_register (dev, channel->ac97_regnum);
- if (oldval < 0)
- return oldval;
-
- for (mv = channel->regmask; ! (mv & 1); mv >>= 1)
- scaled_value <<= 1;
-
- scaled_value &= channel->regmask;
- scaled_value |= (oldval & ~channel->regmask);
- }
- result = ac97_put_register (dev, channel->ac97_regnum, scaled_value);
- if (result == 0)
- dev->last_written_OSS_values[oss_channel] = oss_value;
- return result;
-}
-
-static int
-ac97_get_mixer_scaled (struct ac97_hwint *dev, int oss_channel)
-{
- struct ac97_chn_desc *channel = ac97_find_chndesc (dev, oss_channel);
- int regval;
-
- if (channel == NULL)
- return -ENODEV;
-
- if (! ac97_is_valid_channel (dev, channel))
- return -ENODEV;
-
- regval = ac97_get_register (dev, channel->ac97_regnum);
-
- if (regval < 0)
- return regval;
-
- if (channel->regmask != 0) {
- int mv;
-
- regval &= channel->regmask;
-
- for (mv = channel->regmask; ! (mv & 1); mv >>= 1)
- regval >>= 1;
- }
- return ac97_scale_to_oss_val (regval, channel->maxval,
- channel->is_stereo,
- channel->is_inverted);
-}
-
-static int
-ac97_get_recmask (struct ac97_hwint *dev)
-{
- int recReg = ac97_get_register (dev, AC97_RECORD_SELECT);
-
- if (recReg < 0)
- return recReg;
- else {
- int x;
- for (x = 0; mixerRegs[x].ac97_regnum >= 0; x++) {
- if (mixerRegs[x].recordNum == (recReg & 7))
- return mixerRegs[x].oss_mask;
- }
- return -ENODEV;
- }
-}
-
-static int
-ac97_set_recmask (struct ac97_hwint *dev, int oss_recmask)
-{
- int x;
-
- if (oss_recmask == 0)
- oss_recmask = SOUND_MIXER_MIC;
-
- for (x = 0; mixerRegs[x].ac97_regnum >= 0; x++) {
- if ((mixerRegs[x].recordNum >= 0)
- && (oss_recmask & mixerRegs[x].oss_mask))
- break;
- }
- if (mixerRegs[x].ac97_regnum < 0)
- return -ENODEV;
- else {
- int regval = (mixerRegs[x].recordNum << 8) | mixerRegs[x].recordNum;
- int res = ac97_put_register (dev, AC97_RECORD_SELECT, regval);
- if (res == 0)
- return ac97_get_recmask (dev);
- else
- return res;
- }
-}
-
-/* Set the mixer DEV to the list of values in VALUE_LIST. Return 0 on
- success, or a negative error code. */
-int
-ac97_set_values (struct ac97_hwint *dev,
- struct ac97_mixer_value_list *value_list)
-{
- int x;
-
- for (x = 0; value_list[x].oss_channel != -1; x++) {
- int chnum = value_list[x].oss_channel;
- struct ac97_chn_desc *chent = ac97_find_chndesc (dev, chnum);
- if (chent != NULL) {
- u16 val;
- int res;
-
- if (chent->is_stereo)
- val = (value_list[x].value.stereo.right << 8)
- | value_list[x].value.stereo.left;
- else {
- /* We do this so the returned value looks OK in the
- mixer app. It's not necessary otherwise. */
- val = (value_list[x].value.mono << 8)
- | value_list[x].value.mono;
- }
- res = ac97_set_mixer (dev, chnum, val);
- if (res < 0)
- return res;
- }
- else
- return -ENODEV;
- }
- return 0;
-}
-
-int
-ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd, void __user *arg)
-{
- int ret;
-
- switch (cmd) {
- case SOUND_MIXER_READ_RECSRC:
- ret = ac97_get_recmask (dev);
- break;
-
- case SOUND_MIXER_WRITE_RECSRC:
- {
- if (get_user (ret, (int __user *) arg))
- ret = -EFAULT;
- else
- ret = ac97_set_recmask (dev, ret);
- }
- break;
-
- case SOUND_MIXER_READ_CAPS:
- ret = SOUND_CAP_EXCL_INPUT;
- break;
-
- case SOUND_MIXER_READ_DEVMASK:
- ret = dev->mixer_devmask;
- break;
-
- case SOUND_MIXER_READ_RECMASK:
- ret = dev->mixer_recmask;
- break;
-
- case SOUND_MIXER_READ_STEREODEVS:
- ret = dev->mixer_stereomask;
- break;
-
- default:
- /* Read or write request. */
- ret = -EINVAL;
- if (_IOC_TYPE (cmd) == 'M') {
- int dir = _SIOC_DIR (cmd);
- int channel = _IOC_NR (cmd);
-
- if (channel >= 0 && channel < SOUND_MIXER_NRDEVICES) {
- ret = 0;
- if (dir & _SIOC_WRITE) {
- int val;
- if (get_user (val, (int __user *) arg) == 0)
- ret = ac97_set_mixer (dev, channel, val);
- else
- ret = -EFAULT;
- }
- if (ret >= 0 && (dir & _SIOC_READ)) {
- if (dev->last_written_OSS_values[channel]
- == AC97_REGVAL_UNKNOWN)
- dev->last_written_OSS_values[channel]
- = ac97_get_mixer_scaled (dev, channel);
- ret = dev->last_written_OSS_values[channel];
- }
- }
- }
- break;
- }
-
- if (ret < 0)
- return ret;
- else
- return put_user(ret, (int __user *) arg);
-}
-
-EXPORT_SYMBOL(ac97_init);
-EXPORT_SYMBOL(ac97_set_values);
-EXPORT_SYMBOL(ac97_put_register);
-EXPORT_SYMBOL(ac97_mixer_ioctl);
-MODULE_LICENSE("GPL");
-
-
-/*
- * Local variables:
- * c-basic-offset: 4
- * End:
- */
diff --git a/sound/oss/ac97.h b/sound/oss/ac97.h
deleted file mode 100644
index 01837a9d7d6e..000000000000
--- a/sound/oss/ac97.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * ac97.h
- *
- * definitions for the AC97, Intel's Audio Codec 97 Spec
- * also includes support for a generic AC97 interface
- */
-
-#ifndef _AC97_H_
-#define _AC97_H_
-#include "sound_config.h"
-#include "sound_calls.h"
-
-#define AC97_RESET 0x0000 //
-#define AC97_MASTER_VOL_STEREO 0x0002 // Line Out
-#define AC97_HEADPHONE_VOL 0x0004 //
-#define AC97_MASTER_VOL_MONO 0x0006 // TAD Output
-#define AC97_MASTER_TONE 0x0008 //
-#define AC97_PCBEEP_VOL 0x000a // none
-#define AC97_PHONE_VOL 0x000c // TAD Input (mono)
-#define AC97_MIC_VOL 0x000e // MIC Input (mono)
-#define AC97_LINEIN_VOL 0x0010 // Line Input (stereo)
-#define AC97_CD_VOL 0x0012 // CD Input (stereo)
-#define AC97_VIDEO_VOL 0x0014 // none
-#define AC97_AUX_VOL 0x0016 // Aux Input (stereo)
-#define AC97_PCMOUT_VOL 0x0018 // Wave Output (stereo)
-#define AC97_RECORD_SELECT 0x001a //
-#define AC97_RECORD_GAIN 0x001c
-#define AC97_RECORD_GAIN_MIC 0x001e
-#define AC97_GENERAL_PURPOSE 0x0020
-#define AC97_3D_CONTROL 0x0022
-#define AC97_MODEM_RATE 0x0024
-#define AC97_POWER_CONTROL 0x0026
-
-/* registers 0x0028 - 0x0058 are reserved */
-
-/* AC'97 2.0 */
-#define AC97_EXTENDED_ID 0x0028 /* Extended Audio ID */
-#define AC97_EXTENDED_STATUS 0x002A /* Extended Audio Status */
-#define AC97_PCM_FRONT_DAC_RATE 0x002C /* PCM Front DAC Rate */
-#define AC97_PCM_SURR_DAC_RATE 0x002E /* PCM Surround DAC Rate */
-#define AC97_PCM_LFE_DAC_RATE 0x0030 /* PCM LFE DAC Rate */
-#define AC97_PCM_LR_ADC_RATE 0x0032 /* PCM LR DAC Rate */
-#define AC97_PCM_MIC_ADC_RATE 0x0034 /* PCM MIC ADC Rate */
-#define AC97_CENTER_LFE_MASTER 0x0036 /* Center + LFE Master Volume */
-#define AC97_SURROUND_MASTER 0x0038 /* Surround (Rear) Master Volume */
-#define AC97_RESERVED_3A 0x003A /* Reserved */
-/* range 0x3c-0x58 - MODEM */
-
-/* registers 0x005a - 0x007a are vendor reserved */
-
-#define AC97_VENDOR_ID1 0x007c
-#define AC97_VENDOR_ID2 0x007e
-
-/* volume control bit defines */
-
-#define AC97_MUTE 0x8000
-#define AC97_MICBOOST 0x0040
-#define AC97_LEFTVOL 0x3f00
-#define AC97_RIGHTVOL 0x003f
-
-/* record mux defines */
-
-#define AC97_RECMUX_MIC 0x0000
-#define AC97_RECMUX_CD 0x0101
-#define AC97_RECMUX_VIDEO 0x0202 /* not used */
-#define AC97_RECMUX_AUX 0x0303
-#define AC97_RECMUX_LINE 0x0404
-#define AC97_RECMUX_STEREO_MIX 0x0505
-#define AC97_RECMUX_MONO_MIX 0x0606
-#define AC97_RECMUX_PHONE 0x0707
-
-
-/* general purpose register bit defines */
-
-#define AC97_GP_LPBK 0x0080 /* Loopback mode */
-#define AC97_GP_MS 0x0100 /* Mic Select 0=Mic1, 1=Mic2 */
-#define AC97_GP_MIX 0x0200 /* Mono output select 0=Mix, 1=Mic */
-#define AC97_GP_RLBK 0x0400 /* Remote Loopback - Modem line codec */
-#define AC97_GP_LLBK 0x0800 /* Local Loopback - Modem Line codec */
-#define AC97_GP_LD 0x1000 /* Loudness 1=on */
-#define AC97_GP_3D 0x2000 /* 3D Enhancement 1=on */
-#define AC97_GP_ST 0x4000 /* Stereo Enhancement 1=on */
-#define AC97_GP_POP 0x8000 /* Pcm Out Path, 0=pre 3D, 1=post 3D */
-
-
-/* powerdown control and status bit defines */
-
-/* status */
-#define AC97_PWR_MDM 0x0010 /* Modem section ready */
-#define AC97_PWR_REF 0x0008 /* Vref nominal */
-#define AC97_PWR_ANL 0x0004 /* Analog section ready */
-#define AC97_PWR_DAC 0x0002 /* DAC section ready */
-#define AC97_PWR_ADC 0x0001 /* ADC section ready */
-
-/* control */
-#define AC97_PWR_PR0 0x0100 /* ADC and Mux powerdown */
-#define AC97_PWR_PR1 0x0200 /* DAC powerdown */
-#define AC97_PWR_PR2 0x0400 /* Output mixer powerdown (Vref on) */
-#define AC97_PWR_PR3 0x0800 /* Output mixer powerdown (Vref off) */
-#define AC97_PWR_PR4 0x1000 /* AC-link powerdown */
-#define AC97_PWR_PR5 0x2000 /* Internal Clk disable */
-#define AC97_PWR_PR6 0x4000 /* HP amp powerdown */
-#define AC97_PWR_PR7 0x8000 /* Modem off - if supported */
-
-/* useful power states */
-#define AC97_PWR_D0 0x0000 /* everything on */
-#define AC97_PWR_D1 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR4
-#define AC97_PWR_D2 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
-#define AC97_PWR_D3 AC97_PWR_PR0|AC97_PWR_PR1|AC97_PWR_PR2|AC97_PWR_PR3|AC97_PWR_PR4
-#define AC97_PWR_ANLOFF AC97_PWR_PR2|AC97_PWR_PR3 /* analog section off */
-
-/* Total number of defined registers. */
-#define AC97_REG_CNT 64
-
-/* Generic AC97 mixer interface. */
-
-/* Structure describing access to the hardware. */
-struct ac97_hwint
-{
- /* Perform any hardware-specific reset and initialization. Returns
- 0 on success, or a negative error code. */
- int (*reset_device) (struct ac97_hwint *dev);
-
- /* Returns the contents of the specified register REG. The caller
- should check to see if the desired contents are available in
- the cache first, if applicable. Returns a positive unsigned value
- representing the contents of the register, or a negative error
- code. */
- int (*read_reg) (struct ac97_hwint *dev, u8 reg);
-
- /* Writes VALUE to register REG. Returns 0 on success, or a
- negative error code. */
- int (*write_reg) (struct ac97_hwint *dev, u8 reg, u16 value);
-
- /* Hardware-specific information. */
- void *driver_private;
-
- /* Three OSS masks. */
- int mixer_devmask;
- int mixer_stereomask;
- int mixer_recmask;
-
- /* The mixer cache. The indices correspond to the AC97 hardware register
- number / 2, since the register numbers are always an even number.
-
- Unknown values are set to -1; unsupported registers contain a
- -2. */
- int last_written_mixer_values[AC97_REG_CNT];
-
- /* A cache of values written via OSS; we need these so we can return
- the values originally written by the user.
-
- Why the original user values? Because the real-world hardware
- has less precision, and some existing applications assume that
- they will get back the exact value that they wrote (aumix).
-
- A -1 value indicates that no value has been written to this mixer
- channel via OSS. */
- int last_written_OSS_values[SOUND_MIXER_NRDEVICES];
-};
-
-/* Values stored in the register cache. */
-#define AC97_REGVAL_UNKNOWN -1
-#define AC97_REG_UNSUPPORTED -2
-
-struct ac97_mixer_value_list
-{
- /* Mixer channel to set. List is terminated by a value of -1. */
- int oss_channel;
- /* The scaled value to set it to; values generally range from 0-100. */
- union {
- struct {
- u8 left, right;
- } stereo;
- u8 mono;
- } value;
-};
-
-/* Initialize the ac97 mixer by resetting it. */
-extern int ac97_init (struct ac97_hwint *dev);
-
-/* Sets the mixer DEV to the values in VALUE_LIST. Returns 0 on success,
- or a negative error code. */
-extern int ac97_set_values (struct ac97_hwint *dev,
- struct ac97_mixer_value_list *value_list);
-
-/* Writes the specified VALUE to the AC97 register REG in the mixer.
- Takes care of setting the last-written cache as well. */
-extern int ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value);
-
-/* Default ioctl. */
-extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
- void __user * arg);
-
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 4
- * End:
- */
diff --git a/sound/oss/aci.c b/sound/oss/aci.c
deleted file mode 100644
index 3bfac375dbdb..000000000000
--- a/sound/oss/aci.c
+++ /dev/null
@@ -1,712 +0,0 @@
-/*
- * Audio Command Interface (ACI) driver (sound/aci.c)
- *
- * ACI is a protocol used to communicate with the microcontroller on
- * some sound cards produced by miro, e.g. the miroSOUND PCM12 and
- * PCM20. The ACI has been developed for miro by Norberto Pellicci
- * <pellicci@home.com>. Special thanks to both him and miro for
- * providing the ACI specification.
- *
- * The main function of the ACI is to control the mixer and to get a
- * product identification. On the PCM20, ACI also controls the radio
- * tuner on this card, this is supported in the Video for Linux
- * miropcm20 driver.
- * -
- * This is a fullfeatured implementation. Unsupported features
- * are bugs... (:
- *
- * It is not longer necessary to load the mad16 module first. The
- * user is currently responsible to set the mad16 mixer correctly.
- *
- * To toggle the solo mode for full duplex operation just use the OSS
- * record switch for the pcm ('wave') controller. Robert
- * -
- *
- * Revision history:
- *
- * 1995-11-10 Markus Kuhn <mskuhn@cip.informatik.uni-erlangen.de>
- * First version written.
- * 1995-12-31 Markus Kuhn
- * Second revision, general code cleanup.
- * 1996-05-16 Hannu Savolainen
- * Integrated with other parts of the driver.
- * 1996-05-28 Markus Kuhn
- * Initialize CS4231A mixer, make ACI first mixer,
- * use new private mixer API for solo mode.
- * 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
- * Small modification to export ACI functions and
- * complete modularisation.
- * 2000-06-20 Robert Siemer <Robert.Siemer@gmx.de>
- * Don't initialize the CS4231A mixer anymore, so the code is
- * working again, and other small changes to fit in todays
- * kernels.
- * 2000-08-26 Robert Siemer
- * Clean up and rewrite for 2.4.x. Maybe it's SMP safe now... (:
- * ioctl bugfix, and integration of solo-mode into OSS-API,
- * added (OSS-limited) equalizer support, return value bugfix,
- * changed param aci_reset to reset, new params: ide, wss.
- * 2001-04-20 Robert Siemer
- * even more cleanups...
- * 2001-10-08 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- * Get rid of check_region, .bss optimizations, use set_current_state
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include "sound_config.h"
-
-int aci_port; /* as determined by bit 4 in the OPTi 929 MC4 register */
-static int aci_idcode[2]; /* manufacturer and product ID */
-int aci_version; /* ACI firmware version */
-
-EXPORT_SYMBOL(aci_port);
-EXPORT_SYMBOL(aci_version);
-
-#include "aci.h"
-
-
-static int aci_solo; /* status bit of the card that can't be *
- * checked with ACI versions prior to 0xb0 */
-static int aci_amp; /* status bit for power-amp/line-out level
- but I have no docs about what is what... */
-static int aci_micpreamp=3; /* microphone preamp-level that can't be *
- * checked with ACI versions prior to 0xb0 */
-
-static int mixer_device;
-static struct mutex aci_mutex;
-
-#ifdef MODULE
-static int reset;
-module_param(reset, bool, 0);
-MODULE_PARM_DESC(reset,"When set to 1, reset aci mixer.");
-#else
-static int reset = 1;
-#endif
-
-static int ide=-1;
-module_param(ide, int, 0);
-MODULE_PARM_DESC(ide,"1 enable, 0 disable ide-port - untested"
- " default: do nothing");
-static int wss=-1;
-module_param(wss, int, 0);
-MODULE_PARM_DESC(wss,"change between ACI/WSS-mixer; use 0 and 1 - untested"
- " default: do nothing; for PCM1-pro only");
-
-#ifdef DEBUG
-static void print_bits(unsigned char c)
-{
- int j;
- printk(KERN_DEBUG "aci: ");
-
- for (j=7; j>=0; j--) {
- printk("%d", (c >> j) & 0x1);
- }
-
- printk("\n");
-}
-#endif
-
-/*
- * This busy wait code normally requires less than 15 loops and
- * practically always less than 100 loops on my i486/DX2 66 MHz.
- *
- * Warning: Waiting on the general status flag after reseting the MUTE
- * function can take a VERY long time, because the PCM12 does some kind
- * of fade-in effect. For this reason, access to the MUTE function has
- * not been implemented at all.
- *
- * - The OSS interface has no mute option. It takes about 3 seconds to
- * fade-in on my PCM20. busy_wait() handles it great now... Robert
- */
-
-static int busy_wait(void)
-{
- #define MINTIME 500
- long timeout;
- unsigned char byte;
-
- for (timeout = 1; timeout <= MINTIME+30; timeout++) {
- if (((byte=inb(BUSY_REGISTER)) & 1) == 0) {
- if (timeout >= MINTIME)
- printk(KERN_DEBUG "aci: Got READYFLAG in round %ld.\n", timeout-MINTIME);
- return byte;
- }
- if (timeout >= MINTIME) {
- long out=10*HZ;
- switch (timeout-MINTIME) {
- case 0 ... 9:
- out /= 10;
- case 10 ... 19:
- out /= 10;
- case 20 ... 30:
- out /= 10;
- default:
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(out);
- break;
- }
- }
- }
- printk(KERN_WARNING "aci: busy_wait() time out.\n");
- return -EBUSY;
-}
-
-/* The four ACI command types are fucked up. [-:
- * implied is: 1w - special case for INIT
- * write is: 2w1r
- * read is: x(1w1r) where x is 1 or 2 (1 CHECK_SIG, 1 CHECK_STER,
- * 1 VERSION, 2 IDCODE)
- * the command is only in the first write, rest is protocol overhead
- *
- * indexed is technically a write and used for STATUS
- * and the special case for TUNE is: 3w1r
- *
- * Here the new general sheme: TUNE --> aci_rw_cmd(x, y, z)
- * indexed and write --> aci_rw_cmd(x, y, -1)
- * implied and read (x=1) --> aci_rw_cmd(x, -1, -1)
- *
- * Read (x>=2) is not implemented (only used during initialization).
- * Use aci_idcode[2] and aci_version... Robert
- */
-
-/* Some notes for error detection: theoretically it is possible.
- * But it doubles the I/O-traffic from ww(r) to wwwrw(r) in the normal
- * case and doesn't seem to be designed for that... Robert
- */
-
-static inline int aci_rawwrite(unsigned char byte)
-{
- if (busy_wait() >= 0) {
-#ifdef DEBUG
- printk(KERN_DEBUG "aci_rawwrite(%d)\n", byte);
-#endif
- outb(byte, COMMAND_REGISTER);
- return 0;
- } else
- return -EBUSY;
-}
-
-static inline int aci_rawread(void)
-{
- unsigned char byte;
-
- if (busy_wait() >= 0) {
- byte=inb(STATUS_REGISTER);
-#ifdef DEBUG
- printk(KERN_DEBUG "%d = aci_rawread()\n", byte);
-#endif
- return byte;
- } else
- return -EBUSY;
-}
-
-
-int aci_rw_cmd(int write1, int write2, int write3)
-{
- int write[] = {write1, write2, write3};
- int read = -EINTR, i;
-
- if (mutex_lock_interruptible(&aci_mutex))
- goto out;
-
- for (i=0; i<3; i++) {
- if (write[i]< 0 || write[i] > 255)
- break;
- else {
- read = aci_rawwrite(write[i]);
- if (read < 0)
- goto out_up;
- }
-
- }
-
- read = aci_rawread();
-out_up: mutex_unlock(&aci_mutex);
-out: return read;
-}
-
-EXPORT_SYMBOL(aci_rw_cmd);
-
-static int setvolume(int __user *arg,
- unsigned char left_index, unsigned char right_index)
-{
- int vol, ret, uservol, buf;
-
- __get_user(uservol, arg);
-
- /* left channel */
- vol = uservol & 0xff;
- if (vol > 100)
- vol = 100;
- vol = SCALE(100, 0x20, vol);
- if ((buf=aci_write_cmd(left_index, 0x20 - vol))<0)
- return buf;
- ret = SCALE(0x20, 100, vol);
-
-
- /* right channel */
- vol = (uservol >> 8) & 0xff;
- if (vol > 100)
- vol = 100;
- vol = SCALE(100, 0x20, vol);
- if ((buf=aci_write_cmd(right_index, 0x20 - vol))<0)
- return buf;
- ret |= SCALE(0x20, 100, vol) << 8;
-
- __put_user(ret, arg);
-
- return 0;
-}
-
-static int getvolume(int __user *arg,
- unsigned char left_index, unsigned char right_index)
-{
- int vol;
- int buf;
-
- /* left channel */
- if ((buf=aci_indexed_cmd(ACI_STATUS, left_index))<0)
- return buf;
- vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0);
-
- /* right channel */
- if ((buf=aci_indexed_cmd(ACI_STATUS, right_index))<0)
- return buf;
- vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8;
-
- __put_user(vol, arg);
-
- return 0;
-}
-
-
-/* The equalizer is somewhat strange on the ACI. From -12dB to +12dB
- * write: 0xff..down.to..0x80==0x00..up.to..0x7f
- */
-
-static inline unsigned int eq_oss2aci(unsigned int vol)
-{
- int boost=0;
- unsigned int ret;
-
- if (vol > 100)
- vol = 100;
- if (vol > 50) {
- vol -= 51;
- boost=1;
- }
- if (boost)
- ret=SCALE(49, 0x7e, vol)+1;
- else
- ret=0xff - SCALE(50, 0x7f, vol);
- return ret;
-}
-
-static inline unsigned int eq_aci2oss(unsigned int vol)
-{
- if (vol < 0x80)
- return SCALE(0x7f, 50, vol) + 50;
- else
- return SCALE(0x7f, 50, 0xff-vol);
-}
-
-
-static int setequalizer(int __user *arg,
- unsigned char left_index, unsigned char right_index)
-{
- int buf;
- unsigned int vol;
-
- __get_user(vol, arg);
-
- /* left channel */
- if ((buf=aci_write_cmd(left_index, eq_oss2aci(vol & 0xff)))<0)
- return buf;
-
- /* right channel */
- if ((buf=aci_write_cmd(right_index, eq_oss2aci((vol>>8) & 0xff)))<0)
- return buf;
-
- /* the ACI equalizer is more precise */
- return 0;
-}
-
-static int getequalizer(int __user *arg,
- unsigned char left_index, unsigned char right_index)
-{
- int buf;
- unsigned int vol;
-
- /* left channel */
- if ((buf=aci_indexed_cmd(ACI_STATUS, left_index))<0)
- return buf;
- vol = eq_aci2oss(buf);
-
- /* right channel */
- if ((buf=aci_indexed_cmd(ACI_STATUS, right_index))<0)
- return buf;
- vol |= eq_aci2oss(buf) << 8;
-
- __put_user(vol, arg);
-
- return 0;
-}
-
-static int aci_mixer_ioctl (int dev, unsigned int cmd, void __user * arg)
-{
- int vol, buf;
- int __user *p = arg;
-
- switch (cmd) {
- case SOUND_MIXER_WRITE_VOLUME:
- return setvolume(p, 0x01, 0x00);
- case SOUND_MIXER_WRITE_CD:
- return setvolume(p, 0x3c, 0x34);
- case SOUND_MIXER_WRITE_MIC:
- return setvolume(p, 0x38, 0x30);
- case SOUND_MIXER_WRITE_LINE:
- return setvolume(p, 0x39, 0x31);
- case SOUND_MIXER_WRITE_SYNTH:
- return setvolume(p, 0x3b, 0x33);
- case SOUND_MIXER_WRITE_PCM:
- return setvolume(p, 0x3a, 0x32);
- case MIXER_WRITE(SOUND_MIXER_RADIO): /* fall through */
- case SOUND_MIXER_WRITE_LINE1: /* AUX1 or radio */
- return setvolume(p, 0x3d, 0x35);
- case SOUND_MIXER_WRITE_LINE2: /* AUX2 */
- return setvolume(p, 0x3e, 0x36);
- case SOUND_MIXER_WRITE_BASS: /* set band one and two */
- if (aci_idcode[1]=='C') {
- if ((buf=setequalizer(p, 0x48, 0x40)) ||
- (buf=setequalizer(p, 0x49, 0x41)));
- return buf;
- }
- break;
- case SOUND_MIXER_WRITE_TREBLE: /* set band six and seven */
- if (aci_idcode[1]=='C') {
- if ((buf=setequalizer(p, 0x4d, 0x45)) ||
- (buf=setequalizer(p, 0x4e, 0x46)));
- return buf;
- }
- break;
- case SOUND_MIXER_WRITE_IGAIN: /* MIC pre-amp */
- if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
- __get_user(vol, p);
- vol = vol & 0xff;
- if (vol > 100)
- vol = 100;
- vol = SCALE(100, 3, vol);
- if ((buf=aci_write_cmd(ACI_WRITE_IGAIN, vol))<0)
- return buf;
- aci_micpreamp = vol;
- vol = SCALE(3, 100, vol);
- vol |= (vol << 8);
- __put_user(vol, p);
- return 0;
- }
- break;
- case SOUND_MIXER_WRITE_OGAIN: /* Power-amp/line-out level */
- if (aci_idcode[1]=='A' || aci_idcode[1]=='B') {
- __get_user(buf, p);
- buf = buf & 0xff;
- if (buf > 50)
- vol = 1;
- else
- vol = 0;
- if ((buf=aci_write_cmd(ACI_SET_POWERAMP, vol))<0)
- return buf;
- aci_amp = vol;
- if (aci_amp)
- buf = (100 || 100<<8);
- else
- buf = 0;
- __put_user(buf, p);
- return 0;
- }
- break;
- case SOUND_MIXER_WRITE_RECSRC:
- /* handle solo mode control */
- __get_user(buf, p);
- /* unset solo when RECSRC for PCM is requested */
- if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
- vol = !(buf & SOUND_MASK_PCM);
- if ((buf=aci_write_cmd(ACI_SET_SOLOMODE, vol))<0)
- return buf;
- aci_solo = vol;
- }
- buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
- SOUND_MASK_SYNTH| SOUND_MASK_LINE2);
- if (aci_idcode[1] == 'C') /* PCM20 radio */
- buf |= SOUND_MASK_RADIO;
- else
- buf |= SOUND_MASK_LINE1;
- if (!aci_solo)
- buf |= SOUND_MASK_PCM;
- __put_user(buf, p);
- return 0;
- case SOUND_MIXER_READ_DEVMASK:
- buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_MIC | SOUND_MASK_LINE |
- SOUND_MASK_SYNTH | SOUND_MASK_PCM |
- SOUND_MASK_LINE2);
- switch (aci_idcode[1]) {
- case 'C': /* PCM20 radio */
- buf |= (SOUND_MASK_RADIO | SOUND_MASK_IGAIN |
- SOUND_MASK_BASS | SOUND_MASK_TREBLE);
- break;
- case 'B': /* PCM12 */
- buf |= (SOUND_MASK_LINE1 | SOUND_MASK_IGAIN |
- SOUND_MASK_OGAIN);
- break;
- case 'A': /* PCM1-pro */
- buf |= (SOUND_MASK_LINE1 | SOUND_MASK_OGAIN);
- break;
- default:
- buf |= SOUND_MASK_LINE1;
- }
- __put_user(buf, p);
- return 0;
- case SOUND_MIXER_READ_STEREODEVS:
- buf = (SOUND_MASK_VOLUME | SOUND_MASK_CD |
- SOUND_MASK_MIC | SOUND_MASK_LINE |
- SOUND_MASK_SYNTH | SOUND_MASK_PCM |
- SOUND_MASK_LINE2);
- switch (aci_idcode[1]) {
- case 'C': /* PCM20 radio */
- buf |= (SOUND_MASK_RADIO |
- SOUND_MASK_BASS | SOUND_MASK_TREBLE);
- break;
- default:
- buf |= SOUND_MASK_LINE1;
- }
- __put_user(buf, p);
- return 0;
- case SOUND_MIXER_READ_RECMASK:
- buf = (SOUND_MASK_CD| SOUND_MASK_MIC| SOUND_MASK_LINE|
- SOUND_MASK_SYNTH| SOUND_MASK_LINE2| SOUND_MASK_PCM);
- if (aci_idcode[1] == 'C') /* PCM20 radio */
- buf |= SOUND_MASK_RADIO;
- else
- buf |= SOUND_MASK_LINE1;
-
- __put_user(buf, p);
- return 0;
- case SOUND_MIXER_READ_RECSRC:
- buf = (SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE |
- SOUND_MASK_SYNTH | SOUND_MASK_LINE2);
- /* do we need aci_solo or can I get it from the ACI? */
- switch (aci_idcode[1]) {
- case 'B': /* PCM12 */
- case 'C': /* PCM20 radio */
- if (aci_version >= 0xb0) {
- if ((vol=aci_rw_cmd(ACI_STATUS,
- ACI_S_GENERAL, -1))<0)
- return vol;
- if (vol & 0x20)
- buf |= SOUND_MASK_PCM;
- }
- else
- if (!aci_solo)
- buf |= SOUND_MASK_PCM;
- break;
- default:
- buf |= SOUND_MASK_PCM;
- }
- if (aci_idcode[1] == 'C') /* PCM20 radio */
- buf |= SOUND_MASK_RADIO;
- else
- buf |= SOUND_MASK_LINE1;
-
- __put_user(buf, p);
- return 0;
- case SOUND_MIXER_READ_CAPS:
- __put_user(0, p);
- return 0;
- case SOUND_MIXER_READ_VOLUME:
- return getvolume(p, 0x04, 0x03);
- case SOUND_MIXER_READ_CD:
- return getvolume(p, 0x0a, 0x09);
- case SOUND_MIXER_READ_MIC:
- return getvolume(p, 0x06, 0x05);
- case SOUND_MIXER_READ_LINE:
- return getvolume(p, 0x08, 0x07);
- case SOUND_MIXER_READ_SYNTH:
- return getvolume(p, 0x0c, 0x0b);
- case SOUND_MIXER_READ_PCM:
- return getvolume(p, 0x0e, 0x0d);
- case MIXER_READ(SOUND_MIXER_RADIO): /* fall through */
- case SOUND_MIXER_READ_LINE1: /* AUX1 */
- return getvolume(p, 0x11, 0x10);
- case SOUND_MIXER_READ_LINE2: /* AUX2 */
- return getvolume(p, 0x13, 0x12);
- case SOUND_MIXER_READ_BASS: /* get band one */
- if (aci_idcode[1]=='C') {
- return getequalizer(p, 0x23, 0x22);
- }
- break;
- case SOUND_MIXER_READ_TREBLE: /* get band seven */
- if (aci_idcode[1]=='C') {
- return getequalizer(p, 0x2f, 0x2e);
- }
- break;
- case SOUND_MIXER_READ_IGAIN: /* MIC pre-amp */
- if (aci_idcode[1]=='B' || aci_idcode[1]=='C') {
- /* aci_micpreamp or ACI? */
- if (aci_version >= 0xb0) {
- if ((buf=aci_indexed_cmd(ACI_STATUS,
- ACI_S_READ_IGAIN))<0)
- return buf;
- }
- else
- buf=aci_micpreamp;
- vol = SCALE(3, 100, buf <= 3 ? buf : 3);
- vol |= vol << 8;
- __put_user(vol, p);
- return 0;
- }
- break;
- case SOUND_MIXER_READ_OGAIN:
- if (aci_amp)
- buf = (100 || 100<<8);
- else
- buf = 0;
- __put_user(buf, p);
- return 0;
- }
- return -EINVAL;
-}
-
-static struct mixer_operations aci_mixer_operations =
-{
- .owner = THIS_MODULE,
- .id = "ACI",
- .ioctl = aci_mixer_ioctl
-};
-
-/*
- * There is also an internal mixer in the codec (CS4231A or AD1845),
- * that deserves no purpose in an ACI based system which uses an
- * external ACI controlled stereo mixer. Make sure that this codec
- * mixer has the AUX1 input selected as the recording source, that the
- * input gain is set near maximum and that the other channels going
- * from the inputs to the codec output are muted.
- */
-
-static int __init attach_aci(void)
-{
- char *boardname;
- int i, rc = -EBUSY;
-
- mutex_init(&aci_mutex);
-
- outb(0xE3, 0xf8f); /* Write MAD16 password */
- aci_port = (inb(0xf90) & 0x10) ?
- 0x344: 0x354; /* Get aci_port from MC4_PORT */
-
- if (!request_region(aci_port, 3, "sound mixer (ACI)")) {
- printk(KERN_NOTICE
- "aci: I/O area 0x%03x-0x%03x already used.\n",
- aci_port, aci_port+2);
- goto out;
- }
-
- /* force ACI into a known state */
- rc = -EFAULT;
- for (i=0; i<3; i++)
- if (aci_rw_cmd(ACI_ERROR_OP, -1, -1)<0)
- goto out_release_region;
-
- /* official this is one aci read call: */
- rc = -EFAULT;
- if ((aci_idcode[0]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0 ||
- (aci_idcode[1]=aci_rw_cmd(ACI_READ_IDCODE, -1, -1))<0) {
- printk(KERN_ERR "aci: Failed to read idcode on 0x%03x.\n",
- aci_port);
- goto out_release_region;
- }
-
- if ((aci_version=aci_rw_cmd(ACI_READ_VERSION, -1, -1))<0) {
- printk(KERN_ERR "aci: Failed to read version on 0x%03x.\n",
- aci_port);
- goto out_release_region;
- }
-
- if (aci_idcode[0] == 'm') {
- /* It looks like a miro sound card. */
- switch (aci_idcode[1]) {
- case 'A':
- boardname = "PCM1 pro / early PCM12";
- break;
- case 'B':
- boardname = "PCM12";
- break;
- case 'C':
- boardname = "PCM20 radio";
- break;
- default:
- boardname = "unknown miro";
- }
- } else {
- printk(KERN_WARNING "aci: Warning: unsupported card! - "
- "no hardware, no specs...\n");
- boardname = "unknown Cardinal Technologies";
- }
-
- printk(KERN_INFO "<ACI 0x%02x, id %02x/%02x \"%c/%c\", (%s)> at 0x%03x\n",
- aci_version,
- aci_idcode[0], aci_idcode[1],
- aci_idcode[0], aci_idcode[1],
- boardname, aci_port);
-
- rc = -EBUSY;
- if (reset) {
- /* first write()s after reset fail with my PCM20 */
- if (aci_rw_cmd(ACI_INIT, -1, -1)<0 ||
- aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0 ||
- aci_rw_cmd(ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP)<0)
- goto out_release_region;
- }
-
- /* the PCM20 is muted after reset (and reboot) */
- if (aci_rw_cmd(ACI_SET_MUTE, 0x00, -1)<0)
- goto out_release_region;
-
- if (ide>=0)
- if (aci_rw_cmd(ACI_SET_IDE, !ide, -1)<0)
- goto out_release_region;
-
- if (wss>=0 && aci_idcode[1]=='A')
- if (aci_rw_cmd(ACI_SET_WSS, !!wss, -1)<0)
- goto out_release_region;
-
- mixer_device = sound_install_mixer(MIXER_DRIVER_VERSION, boardname,
- &aci_mixer_operations,
- sizeof(aci_mixer_operations), NULL);
- rc = 0;
- if (mixer_device < 0) {
- printk(KERN_ERR "aci: Failed to install mixer.\n");
- rc = mixer_device;
- goto out_release_region;
- } /* else Maybe initialize the CS4231A mixer here... */
-out: return rc;
-out_release_region:
- release_region(aci_port, 3);
- goto out;
-}
-
-static void __exit unload_aci(void)
-{
- sound_unload_mixerdev(mixer_device);
- release_region(aci_port, 3);
-}
-
-module_init(attach_aci);
-module_exit(unload_aci);
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/aci.h b/sound/oss/aci.h
deleted file mode 100644
index 20102ee088eb..000000000000
--- a/sound/oss/aci.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef _ACI_H_
-#define _ACI_H_
-
-extern int aci_port;
-extern int aci_version; /* ACI firmware version */
-extern int aci_rw_cmd(int write1, int write2, int write3);
-
-#define aci_indexed_cmd(a, b) aci_rw_cmd(a, b, -1)
-#define aci_write_cmd(a, b) aci_rw_cmd(a, b, -1)
-#define aci_read_cmd(a) aci_rw_cmd(a,-1, -1)
-
-#define COMMAND_REGISTER (aci_port) /* write register */
-#define STATUS_REGISTER (aci_port + 1) /* read register */
-#define BUSY_REGISTER (aci_port + 2) /* also used for rds */
-
-#define RDS_REGISTER BUSY_REGISTER
-
-#define ACI_SET_MUTE 0x0d
-#define ACI_SET_POWERAMP 0x0f
-#define ACI_SET_TUNERMUTE 0xa3
-#define ACI_SET_TUNERMONO 0xa4
-#define ACI_SET_IDE 0xd0
-#define ACI_SET_WSS 0xd1
-#define ACI_SET_SOLOMODE 0xd2
-#define ACI_WRITE_IGAIN 0x03
-#define ACI_WRITE_TUNE 0xa7
-#define ACI_READ_TUNERSTEREO 0xa8
-#define ACI_READ_TUNERSTATION 0xa9
-#define ACI_READ_VERSION 0xf1
-#define ACI_READ_IDCODE 0xf2
-#define ACI_INIT 0xff
-#define ACI_STATUS 0xf0
-#define ACI_S_GENERAL 0x00
-#define ACI_S_READ_IGAIN 0x21
-#define ACI_ERROR_OP 0xdf
-
-/*
- * The following macro SCALE can be used to scale one integer volume
- * value into another one using only integer arithmetic. If the input
- * value x is in the range 0 <= x <= xmax, then the result will be in
- * the range 0 <= SCALE(xmax,ymax,x) <= ymax.
- *
- * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the
- * following nice properties:
- *
- * - SCALE(xmax,ymax,xmax) = ymax
- * - SCALE(xmax,ymax,0) = 0
- * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x)
- *
- * In addition, the rounding error is minimal and nicely distributed.
- * The proofs are left as an exercise to the reader.
- */
-
-#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax))
-
-
-#endif /* _ACI_H_ */
diff --git a/sound/oss/ad1816.c b/sound/oss/ad1816.c
deleted file mode 100644
index caabf31193f7..000000000000
--- a/sound/oss/ad1816.c
+++ /dev/null
@@ -1,1368 +0,0 @@
-/*
- *
- * AD1816 lowlevel sound driver for Linux 2.6.0 and above
- *
- * Copyright (C) 1998-2003 by Thorsten Knabe <linux@thorsten-knabe.de>
- *
- * Based on the CS4232/AD1848 driver Copyright (C) by Hannu Savolainen 1993-1996
- *
- *
- * version: 1.5
- * status: beta
- * date: 2003/07/15
- *
- * Changes:
- * Oleg Drokin: Some cleanup of load/unload functions. 1998/11/24
- *
- * Thorsten Knabe: attach and unload rewritten,
- * some argument checks added 1998/11/30
- *
- * Thorsten Knabe: Buggy isa bridge workaround added 1999/01/16
- *
- * David Moews/Thorsten Knabe: Introduced options
- * parameter. Added slightly modified patch from
- * David Moews to disable dsp audio sources by setting
- * bit 0 of options parameter. This seems to be
- * required by some Aztech/Newcom SC-16 cards. 1999/04/18
- *
- * Christoph Hellwig: Adapted to module_init/module_exit. 2000/03/03
- *
- * Christoph Hellwig: Added isapnp support 2000/03/15
- *
- * Arnaldo Carvalho de Melo: get rid of check_region 2001/10/07
- *
- * Thorsten Knabe: Compiling with CONFIG_PNP enabled
- * works again. It is now possible to use more than one
- * AD1816 sound card. Sample rate now may be changed during
- * playback/capture. printk() uses log levels everywhere.
- * SMP fixes. DMA handling fixes.
- * Other minor code cleanup. 2003/07/15
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/isapnp.h>
-#include <linux/stddef.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#define DEBUGNOISE(x)
-
-#define CHECK_FOR_POWER { int timeout=100; \
- while (timeout > 0 && (inb(devc->base)&0x80)!= 0x80) {\
- timeout--; \
- } \
- if (timeout==0) {\
- printk(KERN_WARNING "ad1816: Check for power failed in %s line: %d\n",__FILE__,__LINE__); \
- } \
-}
-
-/* structure to hold device specific information */
-typedef struct
-{
- int base; /* set in attach */
- int irq;
- int dma_playback;
- int dma_capture;
-
- int opened; /* open */
- int speed;
- int channels;
- int audio_format;
- int audio_mode;
-
- int recmask; /* setup */
- unsigned char format_bits;
- int supported_devices;
- int supported_rec_devices;
- unsigned short levels[SOUND_MIXER_NRDEVICES];
- /* misc */
- struct pnp_dev *pnpdev; /* configured via pnp */
- int dev_no; /* this is the # in audio_devs and NOT
- in ad1816_info */
- spinlock_t lock;
-} ad1816_info;
-
-static int nr_ad1816_devs;
-static int ad1816_clockfreq = 33000;
-static int options;
-
-/* supported audio formats */
-static int ad_format_mask =
-AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW;
-
-/* array of device info structures */
-static ad1816_info dev_info[MAX_AUDIO_DEV];
-
-
-/* ------------------------------------------------------------------- */
-
-/* functions for easier access to inderect registers */
-
-static int ad_read (ad1816_info * devc, int reg)
-{
- int result;
-
- CHECK_FOR_POWER;
- outb ((unsigned char) (reg & 0x3f), devc->base+0);
- result = inb(devc->base+2);
- result+= inb(devc->base+3)<<8;
- return (result);
-}
-
-
-static void ad_write (ad1816_info * devc, int reg, int data)
-{
- CHECK_FOR_POWER;
- outb ((unsigned char) (reg & 0xff), devc->base+0);
- outb ((unsigned char) (data & 0xff),devc->base+2);
- outb ((unsigned char) ((data>>8)&0xff),devc->base+3);
-}
-
-/* ------------------------------------------------------------------- */
-
-/* function interface required by struct audio_driver */
-
-static void ad1816_halt_input (int dev)
-{
- unsigned long flags;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
- unsigned char buffer;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: halt_input called\n"));
-
- spin_lock_irqsave(&devc->lock,flags);
-
- if(!isa_dma_bridge_buggy) {
- disable_dma(audio_devs[dev]->dmap_in->dma);
- }
-
- buffer=inb(devc->base+9);
- if (buffer & 0x01) {
- /* disable capture */
- outb(buffer & ~0x01,devc->base+9);
- }
-
- if(!isa_dma_bridge_buggy) {
- enable_dma(audio_devs[dev]->dmap_in->dma);
- }
-
- /* Clear interrupt status */
- outb (~0x40, devc->base+1);
-
- devc->audio_mode &= ~PCM_ENABLE_INPUT;
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-static void ad1816_halt_output (int dev)
-{
- unsigned long flags;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- unsigned char buffer;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: halt_output called!\n"));
-
- spin_lock_irqsave(&devc->lock,flags);
- /* Mute pcm output */
- ad_write(devc, 4, ad_read(devc,4)|0x8080);
-
- if(!isa_dma_bridge_buggy) {
- disable_dma(audio_devs[dev]->dmap_out->dma);
- }
-
- buffer=inb(devc->base+8);
- if (buffer & 0x01) {
- /* disable capture */
- outb(buffer & ~0x01,devc->base+8);
- }
-
- if(!isa_dma_bridge_buggy) {
- enable_dma(audio_devs[dev]->dmap_out->dma);
- }
-
- /* Clear interrupt status */
- outb ((unsigned char)~0x80, devc->base+1);
-
- devc->audio_mode &= ~PCM_ENABLE_OUTPUT;
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-static void ad1816_output_block (int dev, unsigned long buf,
- int count, int intrflag)
-{
- unsigned long flags;
- unsigned long cnt;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: output_block called buf=%ld count=%d flags=%d\n",buf,count,intrflag));
-
- cnt = count/4 - 1;
-
- spin_lock_irqsave(&devc->lock,flags);
-
- /* set transfer count */
- ad_write (devc, 8, cnt & 0xffff);
-
- devc->audio_mode |= PCM_ENABLE_OUTPUT;
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-
-static void ad1816_start_input (int dev, unsigned long buf, int count,
- int intrflag)
-{
- unsigned long flags;
- unsigned long cnt;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: start_input called buf=%ld count=%d flags=%d\n",buf,count,intrflag));
-
- cnt = count/4 - 1;
-
- spin_lock_irqsave(&devc->lock,flags);
-
- /* set transfer count */
- ad_write (devc, 10, cnt & 0xffff);
- devc->audio_mode |= PCM_ENABLE_INPUT;
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-static int ad1816_prepare_for_input (int dev, int bsize, int bcount)
-{
- unsigned long flags;
- unsigned int freq;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
- unsigned char fmt_bits;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: prepare_for_input called: bsize=%d bcount=%d\n",bsize,bcount));
-
- spin_lock_irqsave(&devc->lock,flags);
- fmt_bits= (devc->format_bits&0x7)<<3;
-
- /* set mono/stereo mode */
- if (devc->channels > 1) {
- fmt_bits |=0x4;
- }
- /* set Mono/Stereo in playback/capture register */
- outb( (inb(devc->base+8) & ~0x3C)|fmt_bits, devc->base+8);
- outb( (inb(devc->base+9) & ~0x3C)|fmt_bits, devc->base+9);
-
- freq=((unsigned int)devc->speed*33000)/ad1816_clockfreq;
-
- /* write playback/capture speeds */
- ad_write (devc, 2, freq & 0xffff);
- ad_write (devc, 3, freq & 0xffff);
-
- spin_unlock_irqrestore(&devc->lock,flags);
-
- ad1816_halt_input(dev);
- return 0;
-}
-
-static int ad1816_prepare_for_output (int dev, int bsize, int bcount)
-{
- unsigned long flags;
- unsigned int freq;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
- unsigned char fmt_bits;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: prepare_for_output called: bsize=%d bcount=%d\n",bsize,bcount));
-
- spin_lock_irqsave(&devc->lock,flags);
-
- fmt_bits= (devc->format_bits&0x7)<<3;
- /* set mono/stereo mode */
- if (devc->channels > 1) {
- fmt_bits |=0x4;
- }
-
- /* write format bits to playback/capture registers */
- outb( (inb(devc->base+8) & ~0x3C)|fmt_bits, devc->base+8);
- outb( (inb(devc->base+9) & ~0x3C)|fmt_bits, devc->base+9);
-
- freq=((unsigned int)devc->speed*33000)/ad1816_clockfreq;
-
- /* write playback/capture speeds */
- ad_write (devc, 2, freq & 0xffff);
- ad_write (devc, 3, freq & 0xffff);
-
- spin_unlock_irqrestore(&devc->lock,flags);
-
- ad1816_halt_output(dev);
- return 0;
-
-}
-
-static void ad1816_trigger (int dev, int state)
-{
- unsigned long flags;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: trigger called! (devc=%d,devc->base=%d\n", devc, devc->base));
-
- /* mode may have changed */
-
- spin_lock_irqsave(&devc->lock,flags);
-
- /* mask out modes not specified on open call */
- state &= devc->audio_mode;
-
- /* setup soundchip to new io-mode */
- if (state & PCM_ENABLE_INPUT) {
- /* enable capture */
- outb(inb(devc->base+9)|0x01, devc->base+9);
- } else {
- /* disable capture */
- outb(inb(devc->base+9)&~0x01, devc->base+9);
- }
-
- if (state & PCM_ENABLE_OUTPUT) {
- /* enable playback */
- outb(inb(devc->base+8)|0x01, devc->base+8);
- /* unmute pcm output */
- ad_write(devc, 4, ad_read(devc,4)&~0x8080);
- } else {
- /* mute pcm output */
- ad_write(devc, 4, ad_read(devc,4)|0x8080);
- /* disable capture */
- outb(inb(devc->base+8)&~0x01, devc->base+8);
- }
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-
-/* halt input & output */
-static void ad1816_halt (int dev)
-{
- ad1816_halt_input(dev);
- ad1816_halt_output(dev);
-}
-
-static void ad1816_reset (int dev)
-{
- ad1816_halt (dev);
-}
-
-/* set playback speed */
-static int ad1816_set_speed (int dev, int arg)
-{
- unsigned long flags;
- unsigned int freq;
- int ret;
-
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- spin_lock_irqsave(&devc->lock, flags);
- if (arg == 0) {
- ret = devc->speed;
- spin_unlock_irqrestore(&devc->lock, flags);
- return ret;
- }
- /* range checking */
- if (arg < 4000) {
- arg = 4000;
- }
- if (arg > 55000) {
- arg = 55000;
- }
- devc->speed = arg;
-
- /* change speed during playback */
- freq=((unsigned int)devc->speed*33000)/ad1816_clockfreq;
- /* write playback/capture speeds */
- ad_write (devc, 2, freq & 0xffff);
- ad_write (devc, 3, freq & 0xffff);
-
- ret = devc->speed;
- spin_unlock_irqrestore(&devc->lock, flags);
- return ret;
-
-}
-
-static unsigned int ad1816_set_bits (int dev, unsigned int arg)
-{
- unsigned long flags;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- static struct format_tbl {
- int format;
- unsigned char bits;
- } format2bits[] = {
- { 0, 0 },
- { AFMT_MU_LAW, 1 },
- { AFMT_A_LAW, 3 },
- { AFMT_IMA_ADPCM, 0 },
- { AFMT_U8, 0 },
- { AFMT_S16_LE, 2 },
- { AFMT_S16_BE, 6 },
- { AFMT_S8, 0 },
- { AFMT_U16_LE, 0 },
- { AFMT_U16_BE, 0 }
- };
-
- int i, n = sizeof (format2bits) / sizeof (struct format_tbl);
-
- spin_lock_irqsave(&devc->lock, flags);
- /* return current format */
- if (arg == 0) {
- arg = devc->audio_format;
- spin_unlock_irqrestore(&devc->lock, flags);
- return arg;
- }
- devc->audio_format = arg;
-
- /* search matching format bits */
- for (i = 0; i < n; i++)
- if (format2bits[i].format == arg) {
- devc->format_bits = format2bits[i].bits;
- devc->audio_format = arg;
- spin_unlock_irqrestore(&devc->lock, flags);
- return arg;
- }
-
- /* Still hanging here. Something must be terribly wrong */
- devc->format_bits = 0;
- devc->audio_format = AFMT_U8;
- spin_unlock_irqrestore(&devc->lock, flags);
- return(AFMT_U8);
-}
-
-static short ad1816_set_channels (int dev, short arg)
-{
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- if (arg != 1 && arg != 2)
- return devc->channels;
-
- devc->channels = arg;
- return arg;
-}
-
-/* open device */
-static int ad1816_open (int dev, int mode)
-{
- ad1816_info *devc = NULL;
- unsigned long flags;
-
- /* is device number valid ? */
- if (dev < 0 || dev >= num_audiodevs)
- return -(ENXIO);
-
- /* get device info of this dev */
- devc = (ad1816_info *) audio_devs[dev]->devc;
-
- /* make check if device already open atomic */
- spin_lock_irqsave(&devc->lock,flags);
-
- if (devc->opened) {
- spin_unlock_irqrestore(&devc->lock,flags);
- return -(EBUSY);
- }
-
- /* mark device as open */
- devc->opened = 1;
-
- devc->audio_mode = 0;
- devc->speed = 8000;
- devc->audio_format=AFMT_U8;
- devc->channels=1;
- spin_unlock_irqrestore(&devc->lock,flags);
- ad1816_reset(devc->dev_no); /* halt all pending output */
- return 0;
-}
-
-static void ad1816_close (int dev) /* close device */
-{
- unsigned long flags;
- ad1816_info *devc = (ad1816_info *) audio_devs[dev]->devc;
-
- /* halt all pending output */
- ad1816_reset(devc->dev_no);
-
- spin_lock_irqsave(&devc->lock,flags);
- devc->opened = 0;
- devc->audio_mode = 0;
- devc->speed = 8000;
- devc->audio_format=AFMT_U8;
- devc->format_bits = 0;
- spin_unlock_irqrestore(&devc->lock,flags);
-}
-
-
-/* ------------------------------------------------------------------- */
-
-/* Audio driver structure */
-
-static struct audio_driver ad1816_audio_driver =
-{
- .owner = THIS_MODULE,
- .open = ad1816_open,
- .close = ad1816_close,
- .output_block = ad1816_output_block,
- .start_input = ad1816_start_input,
- .prepare_for_input = ad1816_prepare_for_input,
- .prepare_for_output = ad1816_prepare_for_output,
- .halt_io = ad1816_halt,
- .halt_input = ad1816_halt_input,
- .halt_output = ad1816_halt_output,
- .trigger = ad1816_trigger,
- .set_speed = ad1816_set_speed,
- .set_bits = ad1816_set_bits,
- .set_channels = ad1816_set_channels,
-};
-
-
-/* ------------------------------------------------------------------- */
-
-/* Interrupt handler */
-
-
-static irqreturn_t ad1816_interrupt (int irq, void *dev_id)
-{
- unsigned char status;
- ad1816_info *devc = (ad1816_info *)dev_id;
-
- if (irq < 0 || irq > 15) {
- printk(KERN_WARNING "ad1816: Got bogus interrupt %d\n", irq);
- return IRQ_NONE;
- }
-
- spin_lock(&devc->lock);
-
- /* read interrupt register */
- status = inb (devc->base+1);
- /* Clear all interrupt */
- outb (~status, devc->base+1);
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: Got interrupt subclass %d\n",status));
-
- if (status == 0) {
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: interrupt: Got interrupt, but no source.\n"));
- spin_unlock(&devc->lock);
- return IRQ_NONE;
- }
-
- if (devc->opened && (devc->audio_mode & PCM_ENABLE_INPUT) && (status&64))
- DMAbuf_inputintr (devc->dev_no);
-
- if (devc->opened && (devc->audio_mode & PCM_ENABLE_OUTPUT) && (status & 128))
- DMAbuf_outputintr (devc->dev_no, 1);
-
- spin_unlock(&devc->lock);
- return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------- */
-
-/* Mixer stuff */
-
-struct mixer_def {
- unsigned int regno: 7;
- unsigned int polarity:1; /* 0=normal, 1=reversed */
- unsigned int bitpos:4;
- unsigned int nbits:4;
-};
-
-static char mix_cvt[101] = {
- 0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
- 43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,
- 65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,
- 80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,
- 91,91,92,92,93,93,94,94,95,95,96,96,96,97,97,98,98,98,99,99,
- 100
-};
-
-typedef struct mixer_def mixer_ent;
-
-/*
- * Most of the mixer entries work in backwards. Setting the polarity field
- * makes them to work correctly.
- *
- * The channel numbering used by individual soundcards is not fixed. Some
- * cards have assigned different meanings for the AUX1, AUX2 and LINE inputs.
- * The current version doesn't try to compensate this.
- */
-
-#define MIX_ENT(name, reg_l, pola_l, pos_l, len_l, reg_r, pola_r, pos_r, len_r) \
- {{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}
-
-
-static mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = {
-MIX_ENT(SOUND_MIXER_VOLUME, 14, 1, 8, 5, 14, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),
-MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),
-MIX_ENT(SOUND_MIXER_SYNTH, 5, 1, 8, 6, 5, 1, 0, 6),
-MIX_ENT(SOUND_MIXER_PCM, 4, 1, 8, 6, 4, 1, 0, 6),
-MIX_ENT(SOUND_MIXER_SPEAKER, 0, 0, 0, 0, 0, 0, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE, 18, 1, 8, 5, 18, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_MIC, 19, 1, 8, 5, 19, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_CD, 15, 1, 8, 5, 15, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_IMIX, 0, 0, 0, 0, 0, 0, 0, 0),
-MIX_ENT(SOUND_MIXER_ALTPCM, 0, 0, 0, 0, 0, 0, 0, 0),
-MIX_ENT(SOUND_MIXER_RECLEV, 20, 0, 8, 4, 20, 0, 0, 4),
-MIX_ENT(SOUND_MIXER_IGAIN, 0, 0, 0, 0, 0, 0, 0, 0),
-MIX_ENT(SOUND_MIXER_OGAIN, 0, 0, 0, 0, 0, 0, 0, 0),
-MIX_ENT(SOUND_MIXER_LINE1, 17, 1, 8, 5, 17, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_LINE2, 16, 1, 8, 5, 16, 1, 0, 5),
-MIX_ENT(SOUND_MIXER_LINE3, 39, 0, 9, 4, 39, 1, 0, 5)
-};
-
-
-static unsigned short default_mixer_levels[SOUND_MIXER_NRDEVICES] =
-{
- 0x4343, /* Master Volume */
- 0x3232, /* Bass */
- 0x3232, /* Treble */
- 0x0000, /* FM */
- 0x4343, /* PCM */
- 0x0000, /* PC Speaker */
- 0x0000, /* Ext Line */
- 0x0000, /* Mic */
- 0x0000, /* CD */
- 0x0000, /* Recording monitor */
- 0x0000, /* SB PCM */
- 0x0000, /* Recording level */
- 0x0000, /* Input gain */
- 0x0000, /* Output gain */
- 0x0000, /* Line1 */
- 0x0000, /* Line2 */
- 0x0000 /* Line3 (usually line in)*/
-};
-
-#define LEFT_CHN 0
-#define RIGHT_CHN 1
-
-
-
-static int
-ad1816_set_recmask (ad1816_info * devc, int mask)
-{
- unsigned long flags;
- unsigned char recdev;
- int i, n;
-
- spin_lock_irqsave(&devc->lock, flags);
- mask &= devc->supported_rec_devices;
-
- n = 0;
- /* Count selected device bits */
- for (i = 0; i < 32; i++)
- if (mask & (1 << i))
- n++;
-
- if (n == 0)
- mask = SOUND_MASK_MIC;
- else if (n != 1) { /* Too many devices selected */
- /* Filter out active settings */
- mask &= ~devc->recmask;
-
- n = 0;
- /* Count selected device bits */
- for (i = 0; i < 32; i++)
- if (mask & (1 << i))
- n++;
-
- if (n != 1)
- mask = SOUND_MASK_MIC;
- }
-
- switch (mask) {
- case SOUND_MASK_MIC:
- recdev = 5;
- break;
-
- case SOUND_MASK_LINE:
- recdev = 0;
- break;
-
- case SOUND_MASK_CD:
- recdev = 2;
- break;
-
- case SOUND_MASK_LINE1:
- recdev = 4;
- break;
-
- case SOUND_MASK_LINE2:
- recdev = 3;
- break;
-
- case SOUND_MASK_VOLUME:
- recdev = 1;
- break;
-
- default:
- mask = SOUND_MASK_MIC;
- recdev = 5;
- }
-
- recdev <<= 4;
- ad_write (devc, 20,
- (ad_read (devc, 20) & 0x8f8f) | recdev | (recdev<<8));
-
- devc->recmask = mask;
- spin_unlock_irqrestore(&devc->lock, flags);
- return mask;
-}
-
-static void
-change_bits (int *regval, int dev, int chn, int newval)
-{
- unsigned char mask;
- int shift;
-
- /* Reverse polarity*/
-
- if (mix_devices[dev][chn].polarity == 1)
- newval = 100 - newval;
-
- mask = (1 << mix_devices[dev][chn].nbits) - 1;
- shift = mix_devices[dev][chn].bitpos;
- /* Scale it */
- newval = (int) ((newval * mask) + 50) / 100;
- /* Clear bits */
- *regval &= ~(mask << shift);
- /* Set new value */
- *regval |= (newval & mask) << shift;
-}
-
-static int
-ad1816_mixer_get (ad1816_info * devc, int dev)
-{
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: mixer_get called!\n"));
-
- /* range check + supported mixer check */
- if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES )
- return (-(EINVAL));
- if (!((1 << dev) & devc->supported_devices))
- return -(EINVAL);
-
- return devc->levels[dev];
-}
-
-static int
-ad1816_mixer_set (ad1816_info * devc, int dev, int value)
-{
- int left = value & 0x000000ff;
- int right = (value & 0x0000ff00) >> 8;
- int retvol;
-
- int regoffs;
- int val;
- int valmute;
- unsigned long flags;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: mixer_set called!\n"));
-
- if (dev < 0 || dev >= SOUND_MIXER_NRDEVICES )
- return -(EINVAL);
-
- if (left > 100)
- left = 100;
- if (left < 0)
- left = 0;
- if (right > 100)
- right = 100;
- if (right < 0)
- right = 0;
-
- /* Mono control */
- if (mix_devices[dev][RIGHT_CHN].nbits == 0)
- right = left;
- retvol = left | (right << 8);
-
- /* Scale it */
-
- left = mix_cvt[left];
- right = mix_cvt[right];
-
- /* reject all mixers that are not supported */
- if (!(devc->supported_devices & (1 << dev)))
- return -(EINVAL);
-
- /* sanity check */
- if (mix_devices[dev][LEFT_CHN].nbits == 0)
- return -(EINVAL);
- spin_lock_irqsave(&devc->lock, flags);
-
- /* keep precise volume internal */
- devc->levels[dev] = retvol;
-
- /* Set the left channel */
- regoffs = mix_devices[dev][LEFT_CHN].regno;
- val = ad_read (devc, regoffs);
- change_bits (&val, dev, LEFT_CHN, left);
-
- valmute=val;
-
- /* Mute bit masking on some registers */
- if ( regoffs==5 || regoffs==14 || regoffs==15 ||
- regoffs==16 || regoffs==17 || regoffs==18 ||
- regoffs==19 || regoffs==39) {
- if (left==0)
- valmute |= 0x8000;
- else
- valmute &= ~0x8000;
- }
- ad_write (devc, regoffs, valmute); /* mute */
-
- /*
- * Set the right channel
- */
-
- /* Was just a mono channel */
- if (mix_devices[dev][RIGHT_CHN].nbits == 0) {
- spin_unlock_irqrestore(&devc->lock, flags);
- return retvol;
- }
-
- regoffs = mix_devices[dev][RIGHT_CHN].regno;
- val = ad_read (devc, regoffs);
- change_bits (&val, dev, RIGHT_CHN, right);
-
- valmute=val;
- if ( regoffs==5 || regoffs==14 || regoffs==15 ||
- regoffs==16 || regoffs==17 || regoffs==18 ||
- regoffs==19 || regoffs==39) {
- if (right==0)
- valmute |= 0x80;
- else
- valmute &= ~0x80;
- }
- ad_write (devc, regoffs, valmute); /* mute */
- spin_unlock_irqrestore(&devc->lock, flags);
- return retvol;
-}
-
-#define MIXER_DEVICES ( SOUND_MASK_VOLUME | \
- SOUND_MASK_SYNTH | \
- SOUND_MASK_PCM | \
- SOUND_MASK_LINE | \
- SOUND_MASK_LINE1 | \
- SOUND_MASK_LINE2 | \
- SOUND_MASK_LINE3 | \
- SOUND_MASK_MIC | \
- SOUND_MASK_CD | \
- SOUND_MASK_RECLEV \
- )
-#define REC_DEVICES ( SOUND_MASK_LINE2 |\
- SOUND_MASK_LINE |\
- SOUND_MASK_LINE1 |\
- SOUND_MASK_MIC |\
- SOUND_MASK_CD |\
- SOUND_MASK_VOLUME \
- )
-
-static void
-ad1816_mixer_reset (ad1816_info * devc)
-{
- int i;
-
- devc->supported_devices = MIXER_DEVICES;
-
- devc->supported_rec_devices = REC_DEVICES;
-
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (devc->supported_devices & (1 << i))
- ad1816_mixer_set (devc, i, default_mixer_levels[i]);
- ad1816_set_recmask (devc, SOUND_MASK_MIC);
-}
-
-static int
-ad1816_mixer_ioctl (int dev, unsigned int cmd, void __user * arg)
-{
- ad1816_info *devc = mixer_devs[dev]->devc;
- int val;
- int __user *p = arg;
-
- DEBUGNOISE(printk(KERN_DEBUG "ad1816: mixer_ioctl called!\n"));
-
- /* Mixer ioctl */
- if (((cmd >> 8) & 0xff) == 'M') {
-
- /* set ioctl */
- if (_SIOC_DIR (cmd) & _SIOC_WRITE) {
- switch (cmd & 0xff){
- case SOUND_MIXER_RECSRC:
-
- if (get_user(val, p))
- return -EFAULT;
- val=ad1816_set_recmask (devc, val);
- return put_user(val, p);
- break;
-
- default:
- if (get_user(val, p))
- return -EFAULT;
- if ((val=ad1816_mixer_set (devc, cmd & 0xff, val))<0)
- return val;
- else
- return put_user(val, p);
- }
- } else {
- /* read ioctl */
- switch (cmd & 0xff) {
-
- case SOUND_MIXER_RECSRC:
- val=devc->recmask;
- return put_user(val, p);
- break;
-
- case SOUND_MIXER_DEVMASK:
- val=devc->supported_devices;
- return put_user(val, p);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- val=devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
- return put_user(val, p);
- break;
-
- case SOUND_MIXER_RECMASK:
- val=devc->supported_rec_devices;
- return put_user(val, p);
- break;
-
- case SOUND_MIXER_CAPS:
- val=SOUND_CAP_EXCL_INPUT;
- return put_user(val, p);
- break;
-
- default:
- if ((val=ad1816_mixer_get (devc, cmd & 0xff))<0)
- return val;
- else
- return put_user(val, p);
- }
- }
- } else
- /* not for mixer */
- return -(EINVAL);
-}
-
-/* ------------------------------------------------------------------- */
-
-/* Mixer structure */
-
-static struct mixer_operations ad1816_mixer_operations = {
- .owner = THIS_MODULE,
- .id = "AD1816",
- .name = "AD1816 Mixer",
- .ioctl = ad1816_mixer_ioctl
-};
-
-
-/* ------------------------------------------------------------------- */
-
-/* stuff for card recognition, init and unloading PNP ...*/
-
-
-/* check if AD1816 present at specified hw_config and register device with OS
- * return 1 if initialization was successful, 0 otherwise
- */
-static int __init ad1816_init_card (struct address_info *hw_config,
- struct pnp_dev *pnp)
-{
- ad1816_info *devc = NULL;
- int tmp;
- int oss_devno = -1;
-
- printk(KERN_INFO "ad1816: initializing card: io=0x%x, irq=%d, dma=%d, "
- "dma2=%d, clockfreq=%d, options=%d isadmabug=%d "
- "%s\n",
- hw_config->io_base,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma2,
- ad1816_clockfreq,
- options,
- isa_dma_bridge_buggy,
- pnp?"(PNP)":"");
-
- /* ad1816_info structure remaining ? */
- if (nr_ad1816_devs >= MAX_AUDIO_DEV) {
- printk(KERN_WARNING "ad1816: no more ad1816_info structures "
- "left\n");
- goto out;
- }
-
- devc = &dev_info[nr_ad1816_devs];
- devc->base = hw_config->io_base;
- devc->irq = hw_config->irq;
- devc->dma_playback=hw_config->dma;
- devc->dma_capture=hw_config->dma2;
- devc->opened = 0;
- devc->pnpdev = pnp;
- spin_lock_init(&devc->lock);
-
- if (!request_region(devc->base, 16, "AD1816 Sound")) {
- printk(KERN_WARNING "ad1816: I/O port 0x%03x not free\n",
- devc->base);
- goto out;
- }
-
- printk(KERN_INFO "ad1816: Examining AD1816 at address 0x%03x.\n",
- devc->base);
-
-
- /* tests for ad1816 */
- /* base+0: bit 1 must be set but not 255 */
- tmp=inb(devc->base);
- if ( (tmp&0x80)==0 || tmp==255 ) {
- printk (KERN_INFO "ad1816: Chip is not an AD1816 or chip "
- "is not active (Test 0)\n");
- goto out_release_region;
- }
-
- /* writes to ireg 8 are copied to ireg 9 */
- ad_write(devc,8,12345);
- if (ad_read(devc,9)!=12345) {
- printk(KERN_INFO "ad1816: Chip is not an AD1816 (Test 1)\n");
- goto out_release_region;
- }
-
- /* writes to ireg 8 are copied to ireg 9 */
- ad_write(devc,8,54321);
- if (ad_read(devc,9)!=54321) {
- printk(KERN_INFO "ad1816: Chip is not an AD1816 (Test 2)\n");
- goto out_release_region;
- }
-
- /* writes to ireg 10 are copied to ireg 11 */
- ad_write(devc,10,54321);
- if (ad_read(devc,11)!=54321) {
- printk (KERN_INFO "ad1816: Chip is not an AD1816 (Test 3)\n");
- goto out_release_region;
- }
-
- /* writes to ireg 10 are copied to ireg 11 */
- ad_write(devc,10,12345);
- if (ad_read(devc,11)!=12345) {
- printk (KERN_INFO "ad1816: Chip is not an AD1816 (Test 4)\n");
- goto out_release_region;
- }
-
- /* bit in base +1 cannot be set to 1 */
- tmp=inb(devc->base+1);
- outb(0xff,devc->base+1);
- if (inb(devc->base+1)!=tmp) {
- printk(KERN_INFO "ad1816: Chip is not an AD1816 (Test 5)\n");
- goto out_release_region;
- }
-
- printk(KERN_INFO "ad1816: AD1816 (version %d) successfully detected!\n",
- ad_read(devc,45));
-
- /* disable all interrupts */
- ad_write(devc,1,0);
-
- /* Clear pending interrupts */
- outb (0, devc->base+1);
-
- /* allocate irq */
- if (devc->irq < 0 || devc->irq > 15)
- goto out_release_region;
- if (request_irq(devc->irq, ad1816_interrupt,0,
- "SoundPort", devc) < 0) {
- printk(KERN_WARNING "ad1816: IRQ in use\n");
- goto out_release_region;
- }
-
- /* DMA stuff */
- if (sound_alloc_dma (devc->dma_playback, "Sound System")) {
- printk(KERN_WARNING "ad1816: Can't allocate DMA%d\n",
- devc->dma_playback);
- goto out_free_irq;
- }
-
- if ( devc->dma_capture >= 0 &&
- devc->dma_capture != devc->dma_playback) {
- if (sound_alloc_dma(devc->dma_capture,
- "Sound System (capture)")) {
- printk(KERN_WARNING "ad1816: Can't allocate DMA%d\n",
- devc->dma_capture);
- goto out_free_dma;
- }
- devc->audio_mode=DMA_AUTOMODE|DMA_DUPLEX;
- } else {
- printk(KERN_WARNING "ad1816: Only one DMA channel "
- "available/configured. No duplex operation possible\n");
- devc->audio_mode=DMA_AUTOMODE;
- }
-
- conf_printf2 ("AD1816 audio driver",
- devc->base, devc->irq, devc->dma_playback,
- devc->dma_capture);
-
- /* register device */
- if ((oss_devno = sound_install_audiodrv (AUDIO_DRIVER_VERSION,
- "AD1816 audio driver",
- &ad1816_audio_driver,
- sizeof (struct audio_driver),
- devc->audio_mode,
- ad_format_mask,
- devc,
- devc->dma_playback,
- devc->dma_capture)) < 0) {
- printk(KERN_WARNING "ad1816: Can't install sound driver\n");
- goto out_free_dma_2;
- }
-
-
- ad_write(devc,32,0x80f0); /* sound system mode */
- if (options&1) {
- ad_write(devc,33,0); /* disable all audiosources for dsp */
- } else {
- ad_write(devc,33,0x03f8); /* enable all audiosources for dsp */
- }
- ad_write(devc,4,0x8080); /* default values for volumes (muted)*/
- ad_write(devc,5,0x8080);
- ad_write(devc,6,0x8080);
- ad_write(devc,7,0x8080);
- ad_write(devc,15,0x8888);
- ad_write(devc,16,0x8888);
- ad_write(devc,17,0x8888);
- ad_write(devc,18,0x8888);
- ad_write(devc,19,0xc888); /* +20db mic active */
- ad_write(devc,14,0x0000); /* Master volume unmuted */
- ad_write(devc,39,0x009f); /* 3D effect on 0% phone out muted */
- ad_write(devc,44,0x0080); /* everything on power, 3d enabled for d/a */
- outb(0x10,devc->base+8); /* set dma mode */
- outb(0x10,devc->base+9);
-
- /* enable capture + playback interrupt */
- ad_write(devc,1,0xc000);
-
- /* set mixer defaults */
- ad1816_mixer_reset (devc);
-
- /* register mixer */
- if ((audio_devs[oss_devno]->mixer_dev=sound_install_mixer(
- MIXER_DRIVER_VERSION,
- "AD1816 audio driver",
- &ad1816_mixer_operations,
- sizeof (struct mixer_operations),
- devc)) < 0) {
- printk(KERN_WARNING "Can't install mixer\n");
- }
- /* make ad1816_info active */
- nr_ad1816_devs++;
- printk(KERN_INFO "ad1816: card successfully installed!\n");
- return 1;
- /* error handling */
-out_free_dma_2:
- if (devc->dma_capture >= 0 && devc->dma_capture != devc->dma_playback)
- sound_free_dma(devc->dma_capture);
-out_free_dma:
- sound_free_dma(devc->dma_playback);
-out_free_irq:
- free_irq(devc->irq, devc);
-out_release_region:
- release_region(devc->base, 16);
-out:
- return 0;
-}
-
-static void __exit unload_card(ad1816_info *devc)
-{
- int mixer, dev = 0;
-
- if (devc != NULL) {
- printk("ad1816: Unloading card at address 0x%03x\n",devc->base);
-
- dev = devc->dev_no;
- mixer = audio_devs[dev]->mixer_dev;
-
- /* unreg mixer*/
- if(mixer>=0) {
- sound_unload_mixerdev(mixer);
- }
- /* unreg audiodev */
- sound_unload_audiodev(dev);
-
- /* free dma channels */
- if (devc->dma_capture>=0 &&
- devc->dma_capture != devc->dma_playback) {
- sound_free_dma(devc->dma_capture);
- }
- sound_free_dma (devc->dma_playback);
- /* free irq */
- free_irq(devc->irq, devc);
- /* free io */
- release_region (devc->base, 16);
-#ifdef __ISAPNP__
- if (devc->pnpdev) {
- pnp_disable_dev(devc->pnpdev);
- pnp_device_detach(devc->pnpdev);
- }
-#endif
-
- } else
- printk(KERN_WARNING "ad1816: no device/card specified\n");
-}
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma2 = -1;
-
-#ifdef __ISAPNP__
-/* use isapnp for configuration */
-static int isapnp = 1;
-static int isapnpjump;
-module_param(isapnp, bool, 0);
-module_param(isapnpjump, int, 0);
-#endif
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma2, int, 0);
-module_param(ad1816_clockfreq, int, 0);
-module_param(options, int, 0);
-
-#ifdef __ISAPNP__
-static struct {
- unsigned short card_vendor, card_device;
- unsigned short vendor;
- unsigned short function;
- struct ad1816_data *data;
-} isapnp_ad1816_list[] __initdata = {
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
- ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7150),
- NULL },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID,
- ISAPNP_VENDOR('A','D','S'), ISAPNP_FUNCTION(0x7180),
- NULL },
- {0}
-};
-
-MODULE_DEVICE_TABLE(isapnp, isapnp_ad1816_list);
-
-
-static void __init ad1816_config_pnp_card(struct pnp_card *card,
- unsigned short vendor,
- unsigned short function)
-{
- struct address_info cfg;
- struct pnp_dev *card_dev = pnp_find_dev(card, vendor, function, NULL);
- if (!card_dev) return;
- if (pnp_device_attach(card_dev) < 0) {
- printk(KERN_WARNING "ad1816: Failed to attach PnP device\n");
- return;
- }
- if (pnp_activate_dev(card_dev) < 0) {
- printk(KERN_WARNING "ad1816: Failed to activate PnP device\n");
- pnp_device_detach(card_dev);
- return;
- }
- cfg.io_base = pnp_port_start(card_dev, 2);
- cfg.irq = pnp_irq(card_dev, 0);
- cfg.dma = pnp_irq(card_dev, 0);
- cfg.dma2 = pnp_irq(card_dev, 1);
- if (!ad1816_init_card(&cfg, card_dev)) {
- pnp_disable_dev(card_dev);
- pnp_device_detach(card_dev);
- }
-}
-
-static void __init ad1816_config_pnp_cards(void)
-{
- int nr_pnp_cfg;
- int i;
-
- /* Count entries in isapnp_ad1816_list */
- for (nr_pnp_cfg = 0; isapnp_ad1816_list[nr_pnp_cfg].card_vendor != 0;
- nr_pnp_cfg++);
- /* Check and adjust isapnpjump */
- if( isapnpjump < 0 || isapnpjump >= nr_pnp_cfg) {
- printk(KERN_WARNING
- "ad1816: Valid range for isapnpjump is 0-%d. "
- "Adjusted to 0.\n", nr_pnp_cfg-1);
- isapnpjump = 0;
- }
- for (i = isapnpjump; isapnp_ad1816_list[i].card_vendor != 0; i++) {
- struct pnp_card *card = NULL;
- /* iterate over all pnp cards */
- while ((card = pnp_find_card(isapnp_ad1816_list[i].card_vendor,
- isapnp_ad1816_list[i].card_device, card)))
- ad1816_config_pnp_card(card,
- isapnp_ad1816_list[i].vendor,
- isapnp_ad1816_list[i].function);
- }
-}
-#endif
-
-/* module initialization */
-static int __init init_ad1816(void)
-{
- printk(KERN_INFO "ad1816: AD1816 sounddriver "
- "Copyright (C) 1998-2003 by Thorsten Knabe and "
- "others\n");
-#ifdef AD1816_CLOCK
- /* set ad1816_clockfreq if set during compilation */
- ad1816_clockfreq=AD1816_CLOCK;
-#endif
- if (ad1816_clockfreq<5000 || ad1816_clockfreq>100000) {
- ad1816_clockfreq=33000;
- }
-
-#ifdef __ISAPNP__
- /* configure PnP cards */
- if(isapnp) ad1816_config_pnp_cards();
-#endif
- /* configure card by module params */
- if (io != -1 && irq != -1 && dma != -1) {
- struct address_info cfg;
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma2;
- ad1816_init_card(&cfg, NULL);
- }
- if (nr_ad1816_devs <= 0)
- return -ENODEV;
- return 0;
-}
-
-/* module cleanup */
-static void __exit cleanup_ad1816 (void)
-{
- int i;
- ad1816_info *devc = NULL;
-
- /* remove any soundcard */
- for (i = 0; i < nr_ad1816_devs; i++) {
- devc = &dev_info[i];
- unload_card(devc);
- }
- nr_ad1816_devs=0;
- printk(KERN_INFO "ad1816: driver unloaded!\n");
-}
-
-module_init(init_ad1816);
-module_exit(cleanup_ad1816);
-
-#ifndef MODULE
-/* kernel command line parameter evaluation */
-static int __init setup_ad1816(char *str)
-{
- /* io, irq, dma, dma2 */
- int ints[5];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- return 1;
-}
-
-__setup("ad1816=", setup_ad1816);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c
deleted file mode 100644
index c0730a3563a2..000000000000
--- a/sound/oss/ad1889.c
+++ /dev/null
@@ -1,1101 +0,0 @@
-/*
- * Copyright 2001-2004 Randolph Chung <tausq@debian.org>
- *
- * Analog Devices 1889 PCI audio driver (AD1819 AC97-compatible codec)
- *
- * 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.
- *
- * Notes:
- * 1. Only flat DMA is supported; s-g is not supported right now
- *
- *
-<jsm> tausq: Anyway, to set up sample rates for D to A, you just use the sample rate on the codec. For A to D, you need to set the codec always to 48K (using the split sample rate feature on the codec) and then set the resampler on the AD1889 to the sample rate you want.
-<jsm> Also, when changing the sample rate on the codec you need to power it down and re power it up for the change to take effect!
- *
- * $Id: ad1889.c,v 1.3 2002/10/19 21:31:44 grundler Exp $
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/sound.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/delay.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "ad1889.h"
-
-#define DBG(fmt, arg...) printk(fmt, ##arg)
-#define DEVNAME "ad1889"
-
-#define NR_HW_CH 4
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
-
-#define UNDERRUN(dev) (0)
-
-#define AD1889_READW(dev,reg) readw(dev->regbase + reg)
-#define AD1889_WRITEW(dev,reg,val) writew((val), dev->regbase + reg)
-#define AD1889_READL(dev,reg) readl(dev->regbase + reg)
-#define AD1889_WRITEL(dev,reg,val) writel((val), dev->regbase + reg)
-
-//now 100ms
-/* #define WAIT_10MS() schedule_timeout(HZ/10) */
-#define WAIT_10MS() do { int __i; for (__i = 0; __i < 100; __i++) udelay(1000); } while(0)
-
-/* currently only support a single device */
-static ad1889_dev_t *ad1889_dev = NULL;
-
-/************************* helper routines ***************************** */
-static inline void ad1889_set_wav_rate(ad1889_dev_t *dev, int rate)
-{
- struct ac97_codec *ac97_codec = dev->ac97_codec;
-
- DBG("Setting WAV rate to %d\n", rate);
- dev->state[AD_WAV_STATE].dmabuf.rate = rate;
- AD1889_WRITEW(dev, AD_DS_WAS, rate);
-
- /* Cycle the DAC to enable the new rate */
- ac97_codec->codec_write(dev->ac97_codec, AC97_POWER_CONTROL, 0x0200);
- WAIT_10MS();
- ac97_codec->codec_write(dev->ac97_codec, AC97_POWER_CONTROL, 0);
-}
-
-static inline void ad1889_set_wav_fmt(ad1889_dev_t *dev, int fmt)
-{
- u16 tmp;
-
- DBG("Setting WAV format to 0x%x\n", fmt);
-
- tmp = AD1889_READW(ad1889_dev, AD_DS_WSMC);
- if (fmt & AFMT_S16_LE) {
- //tmp |= 0x0100; /* set WA16 */
- tmp |= 0x0300; /* set WA16 stereo */
- } else if (fmt & AFMT_U8) {
- tmp &= ~0x0100; /* clear WA16 */
- }
- AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, tmp);
-}
-
-static inline void ad1889_set_adc_fmt(ad1889_dev_t *dev, int fmt)
-{
- u16 tmp;
-
- DBG("Setting ADC format to 0x%x\n", fmt);
-
- tmp = AD1889_READW(ad1889_dev, AD_DS_RAMC);
- if (fmt & AFMT_S16_LE) {
- tmp |= 0x0100; /* set WA16 */
- } else if (fmt & AFMT_U8) {
- tmp &= ~0x0100; /* clear WA16 */
- }
- AD1889_WRITEW(ad1889_dev, AD_DS_RAMC, tmp);
-}
-
-static void ad1889_start_wav(ad1889_state_t *state)
-{
- unsigned long flags;
- struct dmabuf *dmabuf = &state->dmabuf;
- int cnt;
- u16 tmp;
-
- spin_lock_irqsave(&state->card->lock, flags);
-
- if (dmabuf->dma_len) /* DMA already in flight */
- goto skip_dma;
-
- /* setup dma */
- cnt = dmabuf->wr_ptr - dmabuf->rd_ptr;
- if (cnt == 0) /* done - don't need to do anything */
- goto skip_dma;
-
- /* If the wr_ptr has wrapped, only map to the end */
- if (cnt < 0)
- cnt = DMA_SIZE - dmabuf->rd_ptr;
-
- dmabuf->dma_handle = pci_map_single(ad1889_dev->pci,
- dmabuf->rawbuf + dmabuf->rd_ptr,
- cnt, PCI_DMA_TODEVICE);
- dmabuf->dma_len = cnt;
- dmabuf->ready = 1;
-
- DBG("Starting playback at 0x%p for %ld bytes\n", dmabuf->rawbuf +
- dmabuf->rd_ptr, dmabuf->dma_len);
-
- /* load up the current register set */
- AD1889_WRITEL(ad1889_dev, AD_DMA_WAVCC, cnt);
- AD1889_WRITEL(ad1889_dev, AD_DMA_WAVICC, cnt);
- AD1889_WRITEL(ad1889_dev, AD_DMA_WAVCA, dmabuf->dma_handle);
-
- /* TODO: for now we load the base registers with the same thing */
- AD1889_WRITEL(ad1889_dev, AD_DMA_WAVBC, cnt);
- AD1889_WRITEL(ad1889_dev, AD_DMA_WAVIBC, cnt);
- AD1889_WRITEL(ad1889_dev, AD_DMA_WAVBA, dmabuf->dma_handle);
-
- /* and we're off to the races... */
- AD1889_WRITEL(ad1889_dev, AD_DMA_CHSS, 0x8);
- tmp = AD1889_READW(ad1889_dev, AD_DS_WSMC);
- tmp |= 0x0400; /* set WAEN */
- AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, tmp);
- (void) AD1889_READW(ad1889_dev, AD_DS_WSMC); /* flush posted PCI write */
-
- dmabuf->enable |= DAC_RUNNING;
-
-skip_dma:
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-
-static void ad1889_stop_wav(ad1889_state_t *state)
-{
- unsigned long flags;
- struct dmabuf *dmabuf = &state->dmabuf;
-
- spin_lock_irqsave(&state->card->lock, flags);
-
- if (dmabuf->enable & DAC_RUNNING) {
- u16 tmp;
- unsigned long cnt = dmabuf->dma_len;
-
- tmp = AD1889_READW(ad1889_dev, AD_DS_WSMC);
- tmp &= ~0x0400; /* clear WAEN */
- AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, tmp);
- (void) AD1889_READW(ad1889_dev, AD_DS_WSMC); /* flush posted PCI write */
- pci_unmap_single(ad1889_dev->pci, dmabuf->dma_handle,
- cnt, PCI_DMA_TODEVICE);
-
- dmabuf->enable &= ~DAC_RUNNING;
-
- /* update dma pointers */
- dmabuf->rd_ptr += cnt;
- dmabuf->rd_ptr &= (DMA_SIZE - 1);
-
- dmabuf->dma_handle = 0;
- dmabuf->dma_len = 0;
- dmabuf->ready = 0;
-
- wake_up(&dmabuf->wait);
- }
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-
-#if 0
-static void ad1889_startstop_adc(ad1889_state_t *state, int start)
-{
- u16 tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&state->card->lock, flags);
-
- tmp = AD1889_READW(ad1889_dev, AD_DS_RAMC);
- if (start) {
- state->dmabuf.enable |= ADC_RUNNING;
- tmp |= 0x0004; /* set ADEN */
- } else {
- state->dmabuf.enable &= ~ADC_RUNNING;
- tmp &= ~0x0004; /* clear ADEN */
- }
- AD1889_WRITEW(ad1889_dev, AD_DS_RAMC, tmp);
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-#endif
-
-static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci)
-{
- ad1889_dev_t *dev;
- struct dmabuf *dmabuf;
- int i;
-
- if ((dev = kzalloc(sizeof(ad1889_dev_t), GFP_KERNEL)) == NULL)
- return NULL;
- spin_lock_init(&dev->lock);
- dev->pci = pci;
-
- for (i = 0; i < AD_MAX_STATES; i++) {
- dev->state[i].card = dev;
- mutex_init(&dev->state[i].mutex);
- init_waitqueue_head(&dev->state[i].dmabuf.wait);
- }
-
- /* allocate dma buffer */
-
- for (i = 0; i < AD_MAX_STATES; i++) {
- dmabuf = &dev->state[i].dmabuf;
- dmabuf->rawbuf = kmalloc(DMA_SIZE, GFP_KERNEL|GFP_DMA);
- if (!dmabuf->rawbuf)
- goto err_free_dmabuf;
- dmabuf->rawbuf_size = DMA_SIZE;
- dmabuf->dma_handle = 0;
- dmabuf->rd_ptr = dmabuf->wr_ptr = dmabuf->dma_len = 0UL;
- dmabuf->ready = 0;
- dmabuf->rate = 48000;
- }
- return dev;
-
-err_free_dmabuf:
- while (--i >= 0)
- kfree(dev->state[i].dmabuf.rawbuf);
- kfree(dev);
- return NULL;
-}
-
-static void ad1889_free_dev(ad1889_dev_t *dev)
-{
- int j;
- struct dmabuf *dmabuf;
-
- if (dev == NULL)
- return;
-
- if (dev->ac97_codec)
- ac97_release_codec(dev->ac97_codec);
-
- for (j = 0; j < AD_MAX_STATES; j++) {
- dmabuf = &dev->state[j].dmabuf;
- kfree(dmabuf->rawbuf);
- }
-
- kfree(dev);
-}
-
-static inline void ad1889_trigger_playback(ad1889_dev_t *dev)
-{
-#if 0
- u32 val;
- struct dmabuf *dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
-#endif
-
- ad1889_start_wav(&dev->state[AD_WAV_STATE]);
-}
-
-static int ad1889_read_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- char *out = page;
- int len, i;
- ad1889_dev_t *dev = data;
- ad1889_reg_t regs[] = {
- { "WSMC", AD_DS_WSMC, 16 },
- { "RAMC", AD_DS_RAMC, 16 },
- { "WADA", AD_DS_WADA, 16 },
- { "SYDA", AD_DS_SYDA, 16 },
- { "WAS", AD_DS_WAS, 16 },
- { "RES", AD_DS_RES, 16 },
- { "CCS", AD_DS_CCS, 16 },
- { "ADCBA", AD_DMA_ADCBA, 32 },
- { "ADCCA", AD_DMA_ADCCA, 32 },
- { "ADCBC", AD_DMA_ADCBC, 32 },
- { "ADCCC", AD_DMA_ADCCC, 32 },
- { "ADCIBC", AD_DMA_ADCIBC, 32 },
- { "ADCICC", AD_DMA_ADCICC, 32 },
- { "ADCCTRL", AD_DMA_ADCCTRL, 16 },
- { "WAVBA", AD_DMA_WAVBA, 32 },
- { "WAVCA", AD_DMA_WAVCA, 32 },
- { "WAVBC", AD_DMA_WAVBC, 32 },
- { "WAVCC", AD_DMA_WAVCC, 32 },
- { "WAVIBC", AD_DMA_WAVIBC, 32 },
- { "WAVICC", AD_DMA_WAVICC, 32 },
- { "WAVCTRL", AD_DMA_WAVCTRL, 16 },
- { "DISR", AD_DMA_DISR, 32 },
- { "CHSS", AD_DMA_CHSS, 32 },
- { "IPC", AD_GPIO_IPC, 16 },
- { "OP", AD_GPIO_OP, 16 },
- { "IP", AD_GPIO_IP, 16 },
- { "ACIC", AD_AC97_ACIC, 16 },
- { "AC97_RESET", AD_AC97_BASE + AC97_RESET, 16 },
- { "AC97_MASTER_VOL_STEREO", AD_AC97_BASE + AC97_MASTER_VOL_STEREO, 16 },
- { "AC97_HEADPHONE_VOL", AD_AC97_BASE + AC97_HEADPHONE_VOL, 16 },
- { "AC97_MASTER_VOL_MONO", AD_AC97_BASE + AC97_MASTER_VOL_MONO, 16 },
- { "AC97_MASTER_TONE", AD_AC97_BASE + AC97_MASTER_TONE, 16 },
- { "AC97_PCBEEP_VOL", AD_AC97_BASE + AC97_PCBEEP_VOL, 16 },
- { "AC97_PHONE_VOL", AD_AC97_BASE + AC97_PHONE_VOL, 16 },
- { "AC97_MIC_VOL", AD_AC97_BASE + AC97_MIC_VOL, 16 },
- { "AC97_LINEIN_VOL", AD_AC97_BASE + AC97_LINEIN_VOL, 16 },
- { "AC97_CD_VOL", AD_AC97_BASE + AC97_CD_VOL, 16 },
- { "AC97_VIDEO_VOL", AD_AC97_BASE + AC97_VIDEO_VOL, 16 },
- { "AC97_AUX_VOL", AD_AC97_BASE + AC97_AUX_VOL, 16 },
- { "AC97_PCMOUT_VOL", AD_AC97_BASE + AC97_PCMOUT_VOL, 16 },
- { "AC97_RECORD_SELECT", AD_AC97_BASE + AC97_RECORD_SELECT, 16 },
- { "AC97_RECORD_GAIN", AD_AC97_BASE + AC97_RECORD_GAIN, 16 },
- { "AC97_RECORD_GAIN_MIC", AD_AC97_BASE + AC97_RECORD_GAIN_MIC, 16 },
- { "AC97_GENERAL_PURPOSE", AD_AC97_BASE + AC97_GENERAL_PURPOSE, 16 },
- { "AC97_3D_CONTROL", AD_AC97_BASE + AC97_3D_CONTROL, 16 },
- { "AC97_MODEM_RATE", AD_AC97_BASE + AC97_MODEM_RATE, 16 },
- { "AC97_POWER_CONTROL", AD_AC97_BASE + AC97_POWER_CONTROL, 16 },
- { NULL }
- };
-
- if (dev == NULL)
- return -ENODEV;
-
- for (i = 0; regs[i].name != 0; i++)
- out += sprintf(out, "%s: 0x%0*x\n", regs[i].name,
- regs[i].width >> 2,
- (regs[i].width == 16
- ? AD1889_READW(dev, regs[i].offset)
- : AD1889_READL(dev, regs[i].offset)));
-
- for (i = 0; i < AD_MAX_STATES; i++) {
- out += sprintf(out, "DMA status for %s:\n",
- (i == AD_WAV_STATE ? "WAV" : "ADC"));
- out += sprintf(out, "\t\t0x%p (IOVA: 0x%llu)\n",
- dev->state[i].dmabuf.rawbuf,
- (unsigned long long)dev->state[i].dmabuf.dma_handle);
-
- out += sprintf(out, "\tread ptr: offset %u\n",
- (unsigned int)dev->state[i].dmabuf.rd_ptr);
- out += sprintf(out, "\twrite ptr: offset %u\n",
- (unsigned int)dev->state[i].dmabuf.wr_ptr);
- out += sprintf(out, "\tdma len: offset %u\n",
- (unsigned int)dev->state[i].dmabuf.dma_len);
- }
-
- len = out - page - off;
- if (len < count) {
- *eof = 1;
- if (len <= 0) return 0;
- } else {
- len = count;
- }
- *start = page + off;
- return len;
-}
-
-/***************************** DMA interfaces ************************** */
-#if 0
-static inline unsigned long ad1889_get_dma_addr(ad1889_state_t *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 offset;
-
- if (!(dmabuf->enable & (DAC_RUNNING | ADC_RUNNING))) {
- printk(KERN_ERR DEVNAME ": get_dma_addr called without dma enabled\n");
- return 0;
- }
-
- if (dmabuf->enable & DAC_RUNNING)
- offset = le32_to_cpu(AD1889_READL(state->card, AD_DMA_WAVBA));
- else
- offset = le32_to_cpu(AD1889_READL(state->card, AD_DMA_ADCBA));
-
- return (unsigned long)bus_to_virt((unsigned long)offset) - (unsigned long)dmabuf->rawbuf;
-}
-
-static void ad1889_update_ptr(ad1889_dev_t *dev, int wake)
-{
- ad1889_state_t *state;
- struct dmabuf *dmabuf;
- unsigned long hwptr;
- int diff;
-
- /* check ADC first */
- state = &dev->adc_state;
- dmabuf = &state->dmabuf;
- if (dmabuf->enable & ADC_RUNNING) {
- hwptr = ad1889_get_dma_addr(state);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count += diff;
- if (dmabuf->count > dmabuf->dmasize)
- dmabuf->count = dmabuf->dmasize;
-
- if (dmabuf->mapped) {
- if (wake & dmabuf->count >= dmabuf->fragsize)
- wake_up(&dmabuf->wait);
- } else {
- if (wake & dmabuf->count > 0)
- wake_up(&dmabuf->wait);
- }
- }
-
- /* check DAC */
- state = &dev->wav_state;
- dmabuf = &state->dmabuf;
- if (dmabuf->enable & DAC_RUNNING) {
-XXX
-
-}
-#endif
-
-/************************* /dev/dsp interfaces ************************* */
-
-static ssize_t ad1889_read(struct file *file, char __user *buffer, size_t count,
- loff_t *ppos)
-{
- return 0;
-}
-
-static ssize_t ad1889_write(struct file *file, const char __user *buffer, size_t count,
- loff_t *ppos)
-{
- ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
- ad1889_state_t *state = &dev->state[AD_WAV_STATE];
- volatile struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- mutex_lock(&state->mutex);
-#if 0
- if (dmabuf->mapped) {
- ret = -ENXIO;
- goto err1;
- }
-#endif
- if (!access_ok(VERIFY_READ, buffer, count)) {
- ret = -EFAULT;
- goto err1;
- }
-
- add_wait_queue(&state->dmabuf.wait, &wait);
-
- /* start filling dma buffer.... */
- while (count > 0) {
- long rem;
- long cnt = count;
- unsigned long flags;
-
- for (;;) {
- long used_bytes;
- long timeout; /* max time for DMA in jiffies */
-
- /* buffer is full if wr catches up to rd */
- spin_lock_irqsave(&state->card->lock, flags);
- used_bytes = dmabuf->wr_ptr - dmabuf->rd_ptr;
- timeout = (dmabuf->dma_len * HZ) / dmabuf->rate;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* adjust for buffer wrap around */
- used_bytes = (used_bytes + DMA_SIZE) & (DMA_SIZE - 1);
-
- /* If at least one page unused */
- if (used_bytes < (DMA_SIZE - 0x1000))
- break;
-
- /* dma buffer full */
-
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- goto err2;
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(timeout + 1);
- if (signal_pending(current)) {
- ret = -ERESTARTSYS;
- goto err2;
- }
- }
-
- /* watch out for wrapping around static buffer */
- spin_lock_irqsave(&state->card->lock, flags);
- rem = DMA_SIZE - dmabuf->wr_ptr;
- if (cnt > rem)
- cnt = rem;
-
- rem = dmabuf->wr_ptr;
-
- /* update dma pointers */
- dmabuf->wr_ptr += cnt;
- dmabuf->wr_ptr &= DMA_SIZE - 1; /* wrap ptr if necessary */
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* transfer unwrapped chunk */
- if (copy_from_user(dmabuf->rawbuf + rem, buffer, cnt)) {
- ret = -EFAULT;
- goto err2;
- }
-
- DBG("Writing 0x%lx bytes to +0x%lx\n", cnt, rem);
-
- /* update counters */
- count -= cnt;
- buffer += cnt;
- ret += cnt;
-
- /* we have something to play - go play it! */
- ad1889_trigger_playback(dev);
- }
-
-err2:
- remove_wait_queue(&state->dmabuf.wait, &wait);
-err1:
- mutex_unlock(&state->mutex);
- return ret;
-}
-
-static unsigned int ad1889_poll(struct file *file, struct poll_table_struct *wait)
-{
- unsigned int mask = 0;
-#if 0
- ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
- ad1889_state_t *state = NULL;
- struct dmabuf *dmabuf;
- unsigned long flags;
-
- if (!(file->f_mode & (FMODE_READ | FMODE_WRITE)))
- return -EINVAL;
-
- if (file->f_mode & FMODE_WRITE) {
- state = &dev->state[AD_WAV_STATE];
- if (!state) return 0;
- dmabuf = &state->dmabuf;
- poll_wait(file, &dmabuf->wait, wait);
- }
-
- if (file->f_mode & FMODE_READ) {
- state = &dev->state[AD_ADC_STATE];
- if (!state) return 0;
- dmabuf = &state->dmabuf;
- poll_wait(file, &dmabuf->wait, wait);
- }
-
- spin_lock_irqsave(&dev->lock, flags);
- ad1889_update_ptr(dev, 0);
-
- if (file->f_mode & FMODE_WRITE) {
- state = &dev->state[WAV_STATE];
- dmabuf = &state->dmabuf;
- if (dmabuf->mapped) {
- if (dmabuf->count >= (int)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((int)dmabuf->dmasize >= dmabuf->count +
- (int)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
-
- if (file ->f_mode & FMODE_READ) {
- state = &dev->state[AD_ADC_STATE];
- dmabuf = &state->dmabuf;
- if (dmabuf->count >= (int)dmabuf->fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-
-#endif
- return mask;
-}
-
-static int ad1889_mmap(struct file *file, struct vm_area_struct *vma)
-{
- return 0;
-}
-
-static int ad1889_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int val = 0;
- ad1889_dev_t *dev = (ad1889_dev_t *)file->private_data;
- struct dmabuf *dmabuf;
- audio_buf_info abinfo;
- int __user *p = (int __user *)arg;
-
- DBG("ad1889_ioctl cmd 0x%x arg %lu\n", cmd, arg);
-
- switch (cmd)
- {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_RESET:
- break;
-
- case SNDCTL_DSP_SYNC:
- break;
-
- case SNDCTL_DSP_SPEED:
- /* set sampling rate */
- if (get_user(val, p))
- return -EFAULT;
- if (val > 5400 && val < 48000)
- {
- if (file->f_mode & FMODE_WRITE)
- AD1889_WRITEW(ad1889_dev, AD_DS_WAS, val);
- if (file->f_mode & FMODE_READ)
- AD1889_WRITEW(ad1889_dev, AD_DS_RES, val);
- }
- return 0;
-
- case SNDCTL_DSP_STEREO: /* undocumented? */
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- val = AD1889_READW(ad1889_dev, AD_DS_WSMC);
- if (val) {
- val |= 0x0200; /* set WAST */
- } else {
- val &= ~0x0200; /* clear WAST */
- }
- AD1889_WRITEW(ad1889_dev, AD_DS_WSMC, val);
- }
- if (file->f_mode & FMODE_WRITE) {
- val = AD1889_READW(ad1889_dev, AD_DS_RAMC);
- if (val) {
- val |= 0x0002; /* set ADST */
- } else {
- val &= ~0x0002; /* clear ADST */
- }
- AD1889_WRITEW(ad1889_dev, AD_DS_RAMC, val);
- }
-
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(DMA_SIZE, p);
-
- case SNDCTL_DSP_GETFMTS:
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(val, p))
- return -EFAULT;
-
- if (val == 0) {
- if (file->f_mode & FMODE_READ)
- ad1889_set_adc_fmt(dev, val);
-
- if (file->f_mode & FMODE_WRITE)
- ad1889_set_wav_fmt(dev, val);
- } else {
- val = AFMT_S16_LE | AFMT_U8;
- }
-
- return put_user(val, p);
-
- case SNDCTL_DSP_CHANNELS:
- break;
-
- case SNDCTL_DSP_POST:
- /* send all data to device */
- break;
-
- case SNDCTL_DSP_SUBDIVIDE:
- break;
-
- case SNDCTL_DSP_SETFRAGMENT:
- /* not supported; uses fixed fragment sizes */
- return put_user(DMA_SIZE, p);
-
- case SNDCTL_DSP_GETOSPACE:
- case SNDCTL_DSP_GETISPACE:
- /* space left in dma buffers */
- if (cmd == SNDCTL_DSP_GETOSPACE)
- dmabuf = &dev->state[AD_WAV_STATE].dmabuf;
- else
- dmabuf = &dev->state[AD_ADC_STATE].dmabuf;
- abinfo.fragments = 1;
- abinfo.fragstotal = 1;
- abinfo.fragsize = DMA_SIZE;
- abinfo.bytes = DMA_SIZE;
- return copy_to_user(p, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(0, p);
-
- case SNDCTL_DSP_GETTRIGGER:
- case SNDCTL_DSP_SETTRIGGER:
- break;
-
- case SNDCTL_DSP_GETIPTR:
- case SNDCTL_DSP_GETOPTR:
- break;
-
- case SNDCTL_DSP_SETDUPLEX:
- break;
-
- case SNDCTL_DSP_GETODELAY:
- break;
-
- case SOUND_PCM_READ_RATE:
- return put_user(AD1889_READW(ad1889_dev, AD_DS_WAS), p);
-
- case SOUND_PCM_READ_CHANNELS:
- case SOUND_PCM_READ_BITS:
- break;
-
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- break;
-
- default:
- break;
- }
-
- return -ENOTTY;
-}
-
-static int ad1889_open(struct inode *inode, struct file *file)
-{
- /* check minor; only support /dev/dsp atm */
- if (iminor(inode) != 3)
- return -ENXIO;
-
- file->private_data = ad1889_dev;
-
- ad1889_set_wav_rate(ad1889_dev, 48000);
- ad1889_set_wav_fmt(ad1889_dev, AFMT_S16_LE);
- AD1889_WRITEW(ad1889_dev, AD_DS_WADA, 0x0404); /* attenuation */
- return nonseekable_open(inode, file);
-}
-
-static int ad1889_release(struct inode *inode, struct file *file)
-{
- /* if we have state free it here */
- return 0;
-}
-
-static const struct file_operations ad1889_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ad1889_read,
- .write = ad1889_write,
- .poll = ad1889_poll,
- .ioctl = ad1889_ioctl,
- .mmap = ad1889_mmap,
- .open = ad1889_open,
- .release = ad1889_release,
-};
-
-/************************* /dev/mixer interfaces ************************ */
-static int ad1889_mixer_open(struct inode *inode, struct file *file)
-{
- if (ad1889_dev->ac97_codec->dev_mixer != iminor(inode))
- return -ENODEV;
-
- file->private_data = ad1889_dev->ac97_codec;
- return 0;
-}
-
-static int ad1889_mixer_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int ad1889_mixer_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static const struct file_operations ad1889_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = ad1889_mixer_ioctl,
- .open = ad1889_mixer_open,
- .release = ad1889_mixer_release,
-};
-
-/************************* AC97 interfaces ****************************** */
-static void ad1889_codec_write(struct ac97_codec *ac97, u8 reg, u16 val)
-{
- ad1889_dev_t *dev = ac97->private_data;
-
- //DBG("Writing 0x%x to 0x%lx\n", val, dev->regbase + AD_AC97_BASE + reg);
- AD1889_WRITEW(dev, AD_AC97_BASE + reg, val);
-}
-
-static u16 ad1889_codec_read(struct ac97_codec *ac97, u8 reg)
-{
- ad1889_dev_t *dev = ac97->private_data;
- //DBG("Reading from 0x%lx\n", dev->regbase + AD_AC97_BASE + reg);
- return AD1889_READW(dev, AD_AC97_BASE + reg);
-}
-
-static int ad1889_ac97_init(ad1889_dev_t *dev, int id)
-{
- struct ac97_codec *ac97;
- u16 eid;
-
- if ((ac97 = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- ac97->private_data = dev;
- ac97->id = id;
-
- ac97->codec_read = ad1889_codec_read;
- ac97->codec_write = ad1889_codec_write;
-
- if (ac97_probe_codec(ac97) == 0) {
- printk(DEVNAME ": ac97_probe_codec failed\n");
- goto out_free;
- }
-
- eid = ad1889_codec_read(ac97, AC97_EXTENDED_ID);
- if (eid == 0xffff) {
- printk(KERN_WARNING DEVNAME ": no codec attached?\n");
- goto out_free;
- }
-
- dev->ac97_features = eid;
-
- if ((ac97->dev_mixer = register_sound_mixer(&ad1889_mixer_fops, -1)) < 0) {
- printk(KERN_ERR DEVNAME ": cannot register mixer\n");
- goto out_free;
- }
-
- dev->ac97_codec = ac97;
- return 0;
-
-out_free:
- ac97_release_codec(ac97);
- return -ENODEV;
-}
-
-static int ad1889_aclink_reset(struct pci_dev * pcidev)
-{
- u16 stat;
- int retry = 200;
- ad1889_dev_t *dev = pci_get_drvdata(pcidev);
-
- AD1889_WRITEW(dev, AD_DS_CCS, 0x8000); /* turn on clock */
- AD1889_READW(dev, AD_DS_CCS);
-
- WAIT_10MS();
-
- stat = AD1889_READW(dev, AD_AC97_ACIC);
- stat |= 0x0002; /* Reset Disable */
- AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
- (void) AD1889_READW(dev, AD_AC97_ACIC); /* flush posted write */
-
- udelay(10);
-
- stat = AD1889_READW(dev, AD_AC97_ACIC);
- stat |= 0x0001; /* Interface Enable */
- AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
-
- do {
- if (AD1889_READW(dev, AD_AC97_ACIC) & 0x8000) /* Ready */
- break;
- WAIT_10MS();
- retry--;
- } while (retry > 0);
-
- if (!retry) {
- printk(KERN_ERR "ad1889_aclink_reset: codec is not ready [0x%x]\n",
- AD1889_READW(dev, AD_AC97_ACIC));
- return -EBUSY;
- }
-
- /* TODO reset AC97 codec */
- /* TODO set wave/adc pci ctrl status */
-
- stat = AD1889_READW(dev, AD_AC97_ACIC);
- stat |= 0x0004; /* Audio Stream Output Enable */
- AD1889_WRITEW(dev, AD_AC97_ACIC, stat);
- return 0;
-}
-
-/************************* PCI interfaces ****************************** */
-/* PCI device table */
-static struct pci_device_id ad1889_id_tbl[] = {
- { PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS, PCI_ANY_ID,
- PCI_ANY_ID, 0, 0, (unsigned long)DEVNAME },
- { },
-};
-MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
-
-static irqreturn_t ad1889_interrupt(int irq, void *dev_id)
-{
- u32 stat;
- ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
-
- stat = AD1889_READL(dev, AD_DMA_DISR);
-
- /* clear ISR */
- AD1889_WRITEL(dev, AD_DMA_DISR, stat);
-
- if (stat & 0x8) { /* WAVI */
- DBG("WAV interrupt\n");
- dev->stats.wav_intrs++;
- if (dev->state[AD_WAV_STATE].dmabuf.ready) {
- ad1889_stop_wav(&dev->state[AD_WAV_STATE]); /* clean up */
- ad1889_start_wav(&dev->state[AD_WAV_STATE]); /* start new */
- }
- }
-
- if ((stat & 0x2) && dev->state[AD_ADC_STATE].dmabuf.ready) { /* ADCI */
- DBG("ADC interrupt\n");
- dev->stats.adc_intrs++;
- }
- if(stat)
- return IRQ_HANDLED;
- return IRQ_NONE;
-}
-
-static void ad1889_initcfg(ad1889_dev_t *dev)
-{
- u16 tmp16;
- u32 tmp32;
-
- /* make sure the interrupt bits are setup the way we want */
- tmp32 = AD1889_READL(dev, AD_DMA_WAVCTRL);
- tmp32 &= ~0xff; /* flat dma, no sg, mask out the intr bits */
- tmp32 |= 0x6; /* intr on count, loop */
- AD1889_WRITEL(dev, AD_DMA_WAVCTRL, tmp32);
-
- /* unmute... */
- tmp16 = AD1889_READW(dev, AD_DS_WADA);
- tmp16 &= ~0x8080;
- AD1889_WRITEW(dev, AD_DS_WADA, tmp16);
-}
-
-static int __devinit ad1889_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
-{
- int err;
- ad1889_dev_t *dev;
- unsigned long bar;
- struct proc_dir_entry *proc_root = NULL;
-
- if ((err = pci_enable_device(pcidev)) != 0) {
- printk(KERN_ERR DEVNAME ": pci_enable_device failed\n");
- return err;
- }
-
- pci_set_master(pcidev);
- if ((dev = ad1889_alloc_dev(pcidev)) == NULL) {
- printk(KERN_ERR DEVNAME ": cannot allocate memory for device\n");
- return -ENOMEM;
- }
- pci_set_drvdata(pcidev, dev);
- bar = pci_resource_start(pcidev, 0);
-
- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR DEVNAME ": memory region not assigned\n");
- goto out1;
- }
-
- if (pci_request_region(pcidev, 0, DEVNAME)) {
- printk(KERN_ERR DEVNAME ": unable to request memory region\n");
- goto out1;
- }
-
- dev->regbase = ioremap_nocache(bar, AD_DS_IOMEMSIZE);
- if (!dev->regbase) {
- printk(KERN_ERR DEVNAME ": unable to remap iomem\n");
- goto out2;
- }
-
- if (request_irq(pcidev->irq, ad1889_interrupt, IRQF_SHARED, DEVNAME, dev) != 0) {
- printk(KERN_ERR DEVNAME ": unable to request interrupt\n");
- goto out3;
- }
-
- printk(KERN_INFO DEVNAME ": %s at %p IRQ %d\n",
- (char *)ent->driver_data, dev->regbase, pcidev->irq);
-
- if (ad1889_aclink_reset(pcidev) != 0)
- goto out4;
-
- /* register /dev/dsp */
- if ((dev->dev_audio = register_sound_dsp(&ad1889_fops, -1)) < 0) {
- printk(KERN_ERR DEVNAME ": cannot register /dev/dsp\n");
- goto out4;
- }
-
- if ((err = ad1889_ac97_init(dev, 0)) != 0)
- goto out5;
-
- /* XXX: cleanups */
- if (((proc_root = proc_mkdir("driver/ad1889", NULL)) == NULL) ||
- create_proc_read_entry("ac97", S_IFREG|S_IRUGO, proc_root, ac97_read_proc, dev->ac97_codec) == NULL ||
- create_proc_read_entry("info", S_IFREG|S_IRUGO, proc_root, ad1889_read_proc, dev) == NULL)
- goto out5;
-
- ad1889_initcfg(dev);
-
- //DBG(DEVNAME ": Driver initialization done!\n");
-
- ad1889_dev = dev;
-
- return 0;
-
-out5:
- unregister_sound_dsp(dev->dev_audio);
-out4:
- free_irq(pcidev->irq, dev);
-out3:
- iounmap(dev->regbase);
-out2:
- pci_release_region(pcidev, 0);
-out1:
- ad1889_free_dev(dev);
- pci_set_drvdata(pcidev, NULL);
-
- return -ENODEV;
-}
-
-static void __devexit ad1889_remove(struct pci_dev *pcidev)
-{
- ad1889_dev_t *dev = pci_get_drvdata(pcidev);
-
- if (dev == NULL) return;
-
- unregister_sound_mixer(dev->ac97_codec->dev_mixer);
- unregister_sound_dsp(dev->dev_audio);
- free_irq(pcidev->irq, dev);
- iounmap(dev->regbase);
- pci_release_region(pcidev, 0);
-
- /* any hw programming needed? */
- ad1889_free_dev(dev);
- pci_set_drvdata(pcidev, NULL);
-}
-
-MODULE_AUTHOR("Randolph Chung");
-MODULE_DESCRIPTION("Analog Devices AD1889 PCI Audio");
-MODULE_LICENSE("GPL");
-
-static struct pci_driver ad1889_driver = {
- .name = DEVNAME,
- .id_table = ad1889_id_tbl,
- .probe = ad1889_probe,
- .remove = __devexit_p(ad1889_remove),
-};
-
-static int __init ad1889_init_module(void)
-{
- return pci_register_driver(&ad1889_driver);
-}
-
-static void ad1889_exit_module(void)
-{
- pci_unregister_driver(&ad1889_driver);
- return;
-}
-
-module_init(ad1889_init_module);
-module_exit(ad1889_exit_module);
diff --git a/sound/oss/ad1889.h b/sound/oss/ad1889.h
deleted file mode 100644
index 09913765967a..000000000000
--- a/sound/oss/ad1889.h
+++ /dev/null
@@ -1,135 +0,0 @@
-#ifndef _AD1889_H_
-#define _AD1889_H_
-
-#define AD_DS_WSMC 0x00 /* DMA input wave/syn mixer control */
-#define AD_DS_RAMC 0x02 /* DMA output resamp/ADC mixer control */
-#define AD_DS_WADA 0x04 /* DMA input wave attenuation */
-#define AD_DS_SYDA 0x06 /* DMA input syn attentuation */
-#define AD_DS_WAS 0x08 /* wave input sample rate */
-#define AD_DS_RES 0x0a /* resampler output sample rate */
-#define AD_DS_CCS 0x0c /* chip control/status */
-
-#define AD_DMA_RESBA 0x40 /* RES base addr */
-#define AD_DMA_RESCA 0x44 /* RES current addr */
-#define AD_DMA_RESBC 0x48 /* RES base cnt */
-#define AD_DMA_RESCC 0x4c /* RES current count */
-#define AD_DMA_ADCBA 0x50 /* ADC */
-#define AD_DMA_ADCCA 0x54
-#define AD_DMA_ADCBC 0x58
-#define AD_DMA_ADCCC 0x5c
-#define AD_DMA_SYNBA 0x60 /* SYN */
-#define AD_DMA_SYNCA 0x64
-#define AD_DMA_SYNBC 0x68
-#define AD_DMA_SYNCC 0x6c
-#define AD_DMA_WAVBA 0x70 /* WAV */
-#define AD_DMA_WAVCA 0x74
-#define AD_DMA_WAVBC 0x78
-#define AD_DMA_WAVCC 0x7c
-#define AD_DMA_RESICC 0x80 /* RES interrupt current count */
-#define AD_DMA_RESIBC 0x84 /* RES interrupt base count */
-#define AD_DMA_ADCICC 0x88 /* ADC interrupt current count */
-#define AD_DMA_ADCIBC 0x8c /* ADC interrupt base count */
-#define AD_DMA_SYNICC 0x90 /* SYN interrupt current count */
-#define AD_DMA_SYNIBC 0x94 /* SYN interrupt base count */
-#define AD_DMA_WAVICC 0x98 /* WAV interrupt current count */
-#define AD_DMA_WAVIBC 0x9c /* WAV interrupt base count */
-#define AD_DMA_RESCTRL 0xa0 /* RES PCI control/status */
-#define AD_DMA_ADCCTRL 0xa8 /* ADC PCI control/status */
-#define AD_DMA_SYNCTRL 0xb0 /* SYN PCI control/status */
-#define AD_DMA_WAVCTRL 0xb8 /* WAV PCI control/status */
-#define AD_DMA_DISR 0xc0 /* PCI DMA intr status */
-#define AD_DMA_CHSS 0xc4 /* PCI DMA channel stop status */
-
-#define AD_GPIO_IPC 0xc8 /* IO port ctrl */
-#define AD_GPIO_OP 0xca /* IO output status */
-#define AD_GPIO_IP 0xcc /* IO input status */
-
-/* AC97 registers, 0x100 - 0x17f; see ac97.h */
-#define AD_AC97_BASE 0x100 /* ac97 base register */
-#define AD_AC97_ACIC 0x180 /* AC Link interface ctrl */
-
-/* OPL3; BAR1 */
-#define AD_OPL_M0AS 0x00 /* Music0 address/status */
-#define AD_OPL_M0DATA 0x01 /* Music0 data */
-#define AD_OPL_M1A 0x02 /* Music1 address */
-#define AD_OPL_M1DATA 0x03 /* Music1 data */
-/* 0x04-0x0f reserved */
-
-/* MIDI; BAR2 */
-#define AD_MIDA 0x00 /* MIDI data */
-#define AD_MISC 0x01 /* MIDI status/cmd */
-/* 0x02-0xff reserved */
-
-#define AD_DS_IOMEMSIZE 512
-#define AD_OPL_MEMSIZE 16
-#define AD_MIDI_MEMSIZE 16
-
-#define AD_WAV_STATE 0
-#define AD_ADC_STATE 1
-#define AD_MAX_STATES 2
-
-#define DMA_SIZE (128*1024)
-
-#define DMA_FLAG_MAPPED 1
-
-struct ad1889_dev;
-
-typedef struct ad1889_state {
- struct ad1889_dev *card;
-
- mode_t open_mode;
- struct dmabuf {
- unsigned int rate;
- unsigned char fmt, enable;
-
- /* buf management */
- size_t rawbuf_size;
- void *rawbuf;
- dma_addr_t dma_handle; /* mapped address */
- unsigned long dma_len; /* number of bytes mapped */
-
- /* indexes into rawbuf for setting up DMA engine */
- volatile unsigned long rd_ptr, wr_ptr;
-
- wait_queue_head_t wait; /* to wait for buf servicing */
-
- /* OSS bits */
- unsigned int mapped:1;
- unsigned int ready:1;
- unsigned int ossfragshift;
- int ossmaxfrags;
- unsigned int subdivision;
- } dmabuf;
-
- struct mutex mutex;
-} ad1889_state_t;
-
-typedef struct ad1889_dev {
- void __iomem *regbase;
- struct pci_dev *pci;
-
- spinlock_t lock;
-
- int dev_audio;
-
- /* states; one per channel; right now only WAV and ADC */
- struct ad1889_state state[AD_MAX_STATES];
-
- /* AC97 codec */
- struct ac97_codec *ac97_codec;
- u16 ac97_features;
-
- /* debugging stuff */
- struct stats {
- unsigned int wav_intrs, adc_intrs;
- unsigned int blocks, underrun, error;
- } stats;
-} ad1889_dev_t;
-
-typedef struct ad1889_reg {
- const char *name;
- int offset;
- int width;
-} ad1889_reg_t;
-
-#endif
diff --git a/sound/oss/adlib_card.c b/sound/oss/adlib_card.c
deleted file mode 100644
index c9a7c9b470de..000000000000
--- a/sound/oss/adlib_card.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * sound/oss/adlib_card.c
- *
- * Detection routine for the AdLib card.
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "sound_config.h"
-
-#include "opl3.h"
-
-static void __init attach_adlib_card(struct address_info *hw_config)
-{
- hw_config->slots[0] = opl3_init(hw_config->io_base, hw_config->osp, THIS_MODULE);
-}
-
-static int __init probe_adlib(struct address_info *hw_config)
-{
- return opl3_detect(hw_config->io_base, hw_config->osp);
-}
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-
-module_param(io, int, 0);
-
-static int __init init_adlib(void)
-{
- cfg.io_base = io;
-
- if (cfg.io_base == -1) {
- printk(KERN_ERR "adlib: must specify I/O address.\n");
- return -EINVAL;
- }
- if (probe_adlib(&cfg) == 0)
- return -ENODEV;
- attach_adlib_card(&cfg);
-
- return 0;
-}
-
-static void __exit cleanup_adlib(void)
-{
- sound_unload_synthdev(cfg.slots[0]);
-
-}
-
-module_init(init_adlib);
-module_exit(cleanup_adlib);
-
-#ifndef MODULE
-static int __init setup_adlib(char *str)
-{
- /* io */
- int ints[2];
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
-
- return 1;
-}
-__setup("adlib=", setup_adlib);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/cs461x.h b/sound/oss/cs461x.h
deleted file mode 100644
index 0ce41338e6dd..000000000000
--- a/sound/oss/cs461x.h
+++ /dev/null
@@ -1,1691 +0,0 @@
-#ifndef __CS461X_H
-#define __CS461X_H
-
-/*
- * Copyright (c) by Cirrus Logic Corporation <pcaudio@crystal.cirrus.com>
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- * Definitions for Cirrus Logic CS461x chips
- *
- *
- * 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 PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
-#endif
-
-/*
- * Direct registers
- */
-
-/*
- * The following define the offsets of the registers accessed via base address
- * register zero on the CS461x part.
- */
-#define BA0_HISR 0x00000000
-#define BA0_HSR0 0x00000004
-#define BA0_HICR 0x00000008
-#define BA0_DMSR 0x00000100
-#define BA0_HSAR 0x00000110
-#define BA0_HDAR 0x00000114
-#define BA0_HDMR 0x00000118
-#define BA0_HDCR 0x0000011C
-#define BA0_PFMC 0x00000200
-#define BA0_PFCV1 0x00000204
-#define BA0_PFCV2 0x00000208
-#define BA0_PCICFG00 0x00000300
-#define BA0_PCICFG04 0x00000304
-#define BA0_PCICFG08 0x00000308
-#define BA0_PCICFG0C 0x0000030C
-#define BA0_PCICFG10 0x00000310
-#define BA0_PCICFG14 0x00000314
-#define BA0_PCICFG18 0x00000318
-#define BA0_PCICFG1C 0x0000031C
-#define BA0_PCICFG20 0x00000320
-#define BA0_PCICFG24 0x00000324
-#define BA0_PCICFG28 0x00000328
-#define BA0_PCICFG2C 0x0000032C
-#define BA0_PCICFG30 0x00000330
-#define BA0_PCICFG34 0x00000334
-#define BA0_PCICFG38 0x00000338
-#define BA0_PCICFG3C 0x0000033C
-#define BA0_CLKCR1 0x00000400
-#define BA0_CLKCR2 0x00000404
-#define BA0_PLLM 0x00000408
-#define BA0_PLLCC 0x0000040C
-#define BA0_FRR 0x00000410
-#define BA0_CFL1 0x00000414
-#define BA0_CFL2 0x00000418
-#define BA0_SERMC1 0x00000420
-#define BA0_SERMC2 0x00000424
-#define BA0_SERC1 0x00000428
-#define BA0_SERC2 0x0000042C
-#define BA0_SERC3 0x00000430
-#define BA0_SERC4 0x00000434
-#define BA0_SERC5 0x00000438
-#define BA0_SERBSP 0x0000043C
-#define BA0_SERBST 0x00000440
-#define BA0_SERBCM 0x00000444
-#define BA0_SERBAD 0x00000448
-#define BA0_SERBCF 0x0000044C
-#define BA0_SERBWP 0x00000450
-#define BA0_SERBRP 0x00000454
-#ifndef NO_CS4612
-#define BA0_ASER_FADDR 0x00000458
-#endif
-#define BA0_ACCTL 0x00000460
-#define BA0_ACSTS 0x00000464
-#define BA0_ACOSV 0x00000468
-#define BA0_ACCAD 0x0000046C
-#define BA0_ACCDA 0x00000470
-#define BA0_ACISV 0x00000474
-#define BA0_ACSAD 0x00000478
-#define BA0_ACSDA 0x0000047C
-#define BA0_JSPT 0x00000480
-#define BA0_JSCTL 0x00000484
-#define BA0_JSC1 0x00000488
-#define BA0_JSC2 0x0000048C
-#define BA0_MIDCR 0x00000490
-#define BA0_MIDSR 0x00000494
-#define BA0_MIDWP 0x00000498
-#define BA0_MIDRP 0x0000049C
-#define BA0_JSIO 0x000004A0
-#ifndef NO_CS4612
-#define BA0_ASER_MASTER 0x000004A4
-#endif
-#define BA0_CFGI 0x000004B0
-#define BA0_SSVID 0x000004B4
-#define BA0_GPIOR 0x000004B8
-#ifndef NO_CS4612
-#define BA0_EGPIODR 0x000004BC
-#define BA0_EGPIOPTR 0x000004C0
-#define BA0_EGPIOTR 0x000004C4
-#define BA0_EGPIOWR 0x000004C8
-#define BA0_EGPIOSR 0x000004CC
-#define BA0_SERC6 0x000004D0
-#define BA0_SERC7 0x000004D4
-#define BA0_SERACC 0x000004D8
-#define BA0_ACCTL2 0x000004E0
-#define BA0_ACSTS2 0x000004E4
-#define BA0_ACOSV2 0x000004E8
-#define BA0_ACCAD2 0x000004EC
-#define BA0_ACCDA2 0x000004F0
-#define BA0_ACISV2 0x000004F4
-#define BA0_ACSAD2 0x000004F8
-#define BA0_ACSDA2 0x000004FC
-#define BA0_IOTAC0 0x00000500
-#define BA0_IOTAC1 0x00000504
-#define BA0_IOTAC2 0x00000508
-#define BA0_IOTAC3 0x0000050C
-#define BA0_IOTAC4 0x00000510
-#define BA0_IOTAC5 0x00000514
-#define BA0_IOTAC6 0x00000518
-#define BA0_IOTAC7 0x0000051C
-#define BA0_IOTAC8 0x00000520
-#define BA0_IOTAC9 0x00000524
-#define BA0_IOTAC10 0x00000528
-#define BA0_IOTAC11 0x0000052C
-#define BA0_IOTFR0 0x00000540
-#define BA0_IOTFR1 0x00000544
-#define BA0_IOTFR2 0x00000548
-#define BA0_IOTFR3 0x0000054C
-#define BA0_IOTFR4 0x00000550
-#define BA0_IOTFR5 0x00000554
-#define BA0_IOTFR6 0x00000558
-#define BA0_IOTFR7 0x0000055C
-#define BA0_IOTFIFO 0x00000580
-#define BA0_IOTRRD 0x00000584
-#define BA0_IOTFP 0x00000588
-#define BA0_IOTCR 0x0000058C
-#define BA0_DPCID 0x00000590
-#define BA0_DPCIA 0x00000594
-#define BA0_DPCIC 0x00000598
-#define BA0_PCPCIR 0x00000600
-#define BA0_PCPCIG 0x00000604
-#define BA0_PCPCIEN 0x00000608
-#define BA0_EPCIPMC 0x00000610
-#endif
-
-/*
- * The following define the offsets of the registers and memories accessed via
- * base address register one on the CS461x part.
- */
-#define BA1_SP_DMEM0 0x00000000
-#define BA1_SP_DMEM1 0x00010000
-#define BA1_SP_PMEM 0x00020000
-#define BA1_SP_REG 0x00030000
-#define BA1_SPCR 0x00030000
-#define BA1_DREG 0x00030004
-#define BA1_DSRWP 0x00030008
-#define BA1_TWPR 0x0003000C
-#define BA1_SPWR 0x00030010
-#define BA1_SPIR 0x00030014
-#define BA1_FGR1 0x00030020
-#define BA1_SPCS 0x00030028
-#define BA1_SDSR 0x0003002C
-#define BA1_FRMT 0x00030030
-#define BA1_FRCC 0x00030034
-#define BA1_FRSC 0x00030038
-#define BA1_OMNI_MEM 0x000E0000
-
-/*
- * The following defines are for the flags in the host interrupt status
- * register.
- */
-#define HISR_VC_MASK 0x0000FFFF
-#define HISR_VC0 0x00000001
-#define HISR_VC1 0x00000002
-#define HISR_VC2 0x00000004
-#define HISR_VC3 0x00000008
-#define HISR_VC4 0x00000010
-#define HISR_VC5 0x00000020
-#define HISR_VC6 0x00000040
-#define HISR_VC7 0x00000080
-#define HISR_VC8 0x00000100
-#define HISR_VC9 0x00000200
-#define HISR_VC10 0x00000400
-#define HISR_VC11 0x00000800
-#define HISR_VC12 0x00001000
-#define HISR_VC13 0x00002000
-#define HISR_VC14 0x00004000
-#define HISR_VC15 0x00008000
-#define HISR_INT0 0x00010000
-#define HISR_INT1 0x00020000
-#define HISR_DMAI 0x00040000
-#define HISR_FROVR 0x00080000
-#define HISR_MIDI 0x00100000
-#ifdef NO_CS4612
-#define HISR_RESERVED 0x0FE00000
-#else
-#define HISR_SBINT 0x00200000
-#define HISR_RESERVED 0x0FC00000
-#endif
-#define HISR_H0P 0x40000000
-#define HISR_INTENA 0x80000000
-
-/*
- * The following defines are for the flags in the host signal register 0.
- */
-#define HSR0_VC_MASK 0xFFFFFFFF
-#define HSR0_VC16 0x00000001
-#define HSR0_VC17 0x00000002
-#define HSR0_VC18 0x00000004
-#define HSR0_VC19 0x00000008
-#define HSR0_VC20 0x00000010
-#define HSR0_VC21 0x00000020
-#define HSR0_VC22 0x00000040
-#define HSR0_VC23 0x00000080
-#define HSR0_VC24 0x00000100
-#define HSR0_VC25 0x00000200
-#define HSR0_VC26 0x00000400
-#define HSR0_VC27 0x00000800
-#define HSR0_VC28 0x00001000
-#define HSR0_VC29 0x00002000
-#define HSR0_VC30 0x00004000
-#define HSR0_VC31 0x00008000
-#define HSR0_VC32 0x00010000
-#define HSR0_VC33 0x00020000
-#define HSR0_VC34 0x00040000
-#define HSR0_VC35 0x00080000
-#define HSR0_VC36 0x00100000
-#define HSR0_VC37 0x00200000
-#define HSR0_VC38 0x00400000
-#define HSR0_VC39 0x00800000
-#define HSR0_VC40 0x01000000
-#define HSR0_VC41 0x02000000
-#define HSR0_VC42 0x04000000
-#define HSR0_VC43 0x08000000
-#define HSR0_VC44 0x10000000
-#define HSR0_VC45 0x20000000
-#define HSR0_VC46 0x40000000
-#define HSR0_VC47 0x80000000
-
-/*
- * The following defines are for the flags in the host interrupt control
- * register.
- */
-#define HICR_IEV 0x00000001
-#define HICR_CHGM 0x00000002
-
-/*
- * The following defines are for the flags in the DMA status register.
- */
-#define DMSR_HP 0x00000001
-#define DMSR_HR 0x00000002
-#define DMSR_SP 0x00000004
-#define DMSR_SR 0x00000008
-
-/*
- * The following defines are for the flags in the host DMA source address
- * register.
- */
-#define HSAR_HOST_ADDR_MASK 0xFFFFFFFF
-#define HSAR_DSP_ADDR_MASK 0x0000FFFF
-#define HSAR_MEMID_MASK 0x000F0000
-#define HSAR_MEMID_SP_DMEM0 0x00000000
-#define HSAR_MEMID_SP_DMEM1 0x00010000
-#define HSAR_MEMID_SP_PMEM 0x00020000
-#define HSAR_MEMID_SP_DEBUG 0x00030000
-#define HSAR_MEMID_OMNI_MEM 0x000E0000
-#define HSAR_END 0x40000000
-#define HSAR_ERR 0x80000000
-
-/*
- * The following defines are for the flags in the host DMA destination address
- * register.
- */
-#define HDAR_HOST_ADDR_MASK 0xFFFFFFFF
-#define HDAR_DSP_ADDR_MASK 0x0000FFFF
-#define HDAR_MEMID_MASK 0x000F0000
-#define HDAR_MEMID_SP_DMEM0 0x00000000
-#define HDAR_MEMID_SP_DMEM1 0x00010000
-#define HDAR_MEMID_SP_PMEM 0x00020000
-#define HDAR_MEMID_SP_DEBUG 0x00030000
-#define HDAR_MEMID_OMNI_MEM 0x000E0000
-#define HDAR_END 0x40000000
-#define HDAR_ERR 0x80000000
-
-/*
- * The following defines are for the flags in the host DMA control register.
- */
-#define HDMR_AC_MASK 0x0000F000
-#define HDMR_AC_8_16 0x00001000
-#define HDMR_AC_M_S 0x00002000
-#define HDMR_AC_B_L 0x00004000
-#define HDMR_AC_S_U 0x00008000
-
-/*
- * The following defines are for the flags in the host DMA control register.
- */
-#define HDCR_COUNT_MASK 0x000003FF
-#define HDCR_DONE 0x00004000
-#define HDCR_OPT 0x00008000
-#define HDCR_WBD 0x00400000
-#define HDCR_WBS 0x00800000
-#define HDCR_DMS_MASK 0x07000000
-#define HDCR_DMS_LINEAR 0x00000000
-#define HDCR_DMS_16_DWORDS 0x01000000
-#define HDCR_DMS_32_DWORDS 0x02000000
-#define HDCR_DMS_64_DWORDS 0x03000000
-#define HDCR_DMS_128_DWORDS 0x04000000
-#define HDCR_DMS_256_DWORDS 0x05000000
-#define HDCR_DMS_512_DWORDS 0x06000000
-#define HDCR_DMS_1024_DWORDS 0x07000000
-#define HDCR_DH 0x08000000
-#define HDCR_SMS_MASK 0x70000000
-#define HDCR_SMS_LINEAR 0x00000000
-#define HDCR_SMS_16_DWORDS 0x10000000
-#define HDCR_SMS_32_DWORDS 0x20000000
-#define HDCR_SMS_64_DWORDS 0x30000000
-#define HDCR_SMS_128_DWORDS 0x40000000
-#define HDCR_SMS_256_DWORDS 0x50000000
-#define HDCR_SMS_512_DWORDS 0x60000000
-#define HDCR_SMS_1024_DWORDS 0x70000000
-#define HDCR_SH 0x80000000
-#define HDCR_COUNT_SHIFT 0
-
-/*
- * The following defines are for the flags in the performance monitor control
- * register.
- */
-#define PFMC_C1SS_MASK 0x0000001F
-#define PFMC_C1EV 0x00000020
-#define PFMC_C1RS 0x00008000
-#define PFMC_C2SS_MASK 0x001F0000
-#define PFMC_C2EV 0x00200000
-#define PFMC_C2RS 0x80000000
-#define PFMC_C1SS_SHIFT 0
-#define PFMC_C2SS_SHIFT 16
-#define PFMC_BUS_GRANT 0
-#define PFMC_GRANT_AFTER_REQ 1
-#define PFMC_TRANSACTION 2
-#define PFMC_DWORD_TRANSFER 3
-#define PFMC_SLAVE_READ 4
-#define PFMC_SLAVE_WRITE 5
-#define PFMC_PREEMPTION 6
-#define PFMC_DISCONNECT_RETRY 7
-#define PFMC_INTERRUPT 8
-#define PFMC_BUS_OWNERSHIP 9
-#define PFMC_TRANSACTION_LAG 10
-#define PFMC_PCI_CLOCK 11
-#define PFMC_SERIAL_CLOCK 12
-#define PFMC_SP_CLOCK 13
-
-/*
- * The following defines are for the flags in the performance counter value 1
- * register.
- */
-#define PFCV1_PC1V_MASK 0xFFFFFFFF
-#define PFCV1_PC1V_SHIFT 0
-
-/*
- * The following defines are for the flags in the performance counter value 2
- * register.
- */
-#define PFCV2_PC2V_MASK 0xFFFFFFFF
-#define PFCV2_PC2V_SHIFT 0
-
-/*
- * The following defines are for the flags in the clock control register 1.
- */
-#define CLKCR1_OSCS 0x00000001
-#define CLKCR1_OSCP 0x00000002
-#define CLKCR1_PLLSS_MASK 0x0000000C
-#define CLKCR1_PLLSS_SERIAL 0x00000000
-#define CLKCR1_PLLSS_CRYSTAL 0x00000004
-#define CLKCR1_PLLSS_PCI 0x00000008
-#define CLKCR1_PLLSS_RESERVED 0x0000000C
-#define CLKCR1_PLLP 0x00000010
-#define CLKCR1_SWCE 0x00000020
-#define CLKCR1_PLLOS 0x00000040
-
-/*
- * The following defines are for the flags in the clock control register 2.
- */
-#define CLKCR2_PDIVS_MASK 0x0000000F
-#define CLKCR2_PDIVS_1 0x00000001
-#define CLKCR2_PDIVS_2 0x00000002
-#define CLKCR2_PDIVS_4 0x00000004
-#define CLKCR2_PDIVS_7 0x00000007
-#define CLKCR2_PDIVS_8 0x00000008
-#define CLKCR2_PDIVS_16 0x00000000
-
-/*
- * The following defines are for the flags in the PLL multiplier register.
- */
-#define PLLM_MASK 0x000000FF
-#define PLLM_SHIFT 0
-
-/*
- * The following defines are for the flags in the PLL capacitor coefficient
- * register.
- */
-#define PLLCC_CDR_MASK 0x00000007
-#ifndef NO_CS4610
-#define PLLCC_CDR_240_350_MHZ 0x00000000
-#define PLLCC_CDR_184_265_MHZ 0x00000001
-#define PLLCC_CDR_144_205_MHZ 0x00000002
-#define PLLCC_CDR_111_160_MHZ 0x00000003
-#define PLLCC_CDR_87_123_MHZ 0x00000004
-#define PLLCC_CDR_67_96_MHZ 0x00000005
-#define PLLCC_CDR_52_74_MHZ 0x00000006
-#define PLLCC_CDR_45_58_MHZ 0x00000007
-#endif
-#ifndef NO_CS4612
-#define PLLCC_CDR_271_398_MHZ 0x00000000
-#define PLLCC_CDR_227_330_MHZ 0x00000001
-#define PLLCC_CDR_167_239_MHZ 0x00000002
-#define PLLCC_CDR_150_215_MHZ 0x00000003
-#define PLLCC_CDR_107_154_MHZ 0x00000004
-#define PLLCC_CDR_98_140_MHZ 0x00000005
-#define PLLCC_CDR_73_104_MHZ 0x00000006
-#define PLLCC_CDR_63_90_MHZ 0x00000007
-#endif
-#define PLLCC_LPF_MASK 0x000000F8
-#ifndef NO_CS4610
-#define PLLCC_LPF_23850_60000_KHZ 0x00000000
-#define PLLCC_LPF_7960_26290_KHZ 0x00000008
-#define PLLCC_LPF_4160_10980_KHZ 0x00000018
-#define PLLCC_LPF_1740_4580_KHZ 0x00000038
-#define PLLCC_LPF_724_1910_KHZ 0x00000078
-#define PLLCC_LPF_317_798_KHZ 0x000000F8
-#endif
-#ifndef NO_CS4612
-#define PLLCC_LPF_25580_64530_KHZ 0x00000000
-#define PLLCC_LPF_14360_37270_KHZ 0x00000008
-#define PLLCC_LPF_6100_16020_KHZ 0x00000018
-#define PLLCC_LPF_2540_6690_KHZ 0x00000038
-#define PLLCC_LPF_1050_2780_KHZ 0x00000078
-#define PLLCC_LPF_450_1160_KHZ 0x000000F8
-#endif
-
-/*
- * The following defines are for the flags in the feature reporting register.
- */
-#define FRR_FAB_MASK 0x00000003
-#define FRR_MASK_MASK 0x0000001C
-#ifdef NO_CS4612
-#define FRR_CFOP_MASK 0x000000E0
-#else
-#define FRR_CFOP_MASK 0x00000FE0
-#endif
-#define FRR_CFOP_NOT_DVD 0x00000020
-#define FRR_CFOP_A3D 0x00000040
-#define FRR_CFOP_128_PIN 0x00000080
-#ifndef NO_CS4612
-#define FRR_CFOP_CS4280 0x00000800
-#endif
-#define FRR_FAB_SHIFT 0
-#define FRR_MASK_SHIFT 2
-#define FRR_CFOP_SHIFT 5
-
-/*
- * The following defines are for the flags in the configuration load 1
- * register.
- */
-#define CFL1_CLOCK_SOURCE_MASK 0x00000003
-#define CFL1_CLOCK_SOURCE_CS423X 0x00000000
-#define CFL1_CLOCK_SOURCE_AC97 0x00000001
-#define CFL1_CLOCK_SOURCE_CRYSTAL 0x00000002
-#define CFL1_CLOCK_SOURCE_DUAL_AC97 0x00000003
-#define CFL1_VALID_DATA_MASK 0x000000FF
-
-/*
- * The following defines are for the flags in the configuration load 2
- * register.
- */
-#define CFL2_VALID_DATA_MASK 0x000000FF
-
-/*
- * The following defines are for the flags in the serial port master control
- * register 1.
- */
-#define SERMC1_MSPE 0x00000001
-#define SERMC1_PTC_MASK 0x0000000E
-#define SERMC1_PTC_CS423X 0x00000000
-#define SERMC1_PTC_AC97 0x00000002
-#define SERMC1_PTC_DAC 0x00000004
-#define SERMC1_PLB 0x00000010
-#define SERMC1_XLB 0x00000020
-
-/*
- * The following defines are for the flags in the serial port master control
- * register 2.
- */
-#define SERMC2_LROE 0x00000001
-#define SERMC2_MCOE 0x00000002
-#define SERMC2_MCDIV 0x00000004
-
-/*
- * The following defines are for the flags in the serial port 1 configuration
- * register.
- */
-#define SERC1_SO1EN 0x00000001
-#define SERC1_SO1F_MASK 0x0000000E
-#define SERC1_SO1F_CS423X 0x00000000
-#define SERC1_SO1F_AC97 0x00000002
-#define SERC1_SO1F_DAC 0x00000004
-#define SERC1_SO1F_SPDIF 0x00000006
-
-/*
- * The following defines are for the flags in the serial port 2 configuration
- * register.
- */
-#define SERC2_SI1EN 0x00000001
-#define SERC2_SI1F_MASK 0x0000000E
-#define SERC2_SI1F_CS423X 0x00000000
-#define SERC2_SI1F_AC97 0x00000002
-#define SERC2_SI1F_ADC 0x00000004
-#define SERC2_SI1F_SPDIF 0x00000006
-
-/*
- * The following defines are for the flags in the serial port 3 configuration
- * register.
- */
-#define SERC3_SO2EN 0x00000001
-#define SERC3_SO2F_MASK 0x00000006
-#define SERC3_SO2F_DAC 0x00000000
-#define SERC3_SO2F_SPDIF 0x00000002
-
-/*
- * The following defines are for the flags in the serial port 4 configuration
- * register.
- */
-#define SERC4_SO3EN 0x00000001
-#define SERC4_SO3F_MASK 0x00000006
-#define SERC4_SO3F_DAC 0x00000000
-#define SERC4_SO3F_SPDIF 0x00000002
-
-/*
- * The following defines are for the flags in the serial port 5 configuration
- * register.
- */
-#define SERC5_SI2EN 0x00000001
-#define SERC5_SI2F_MASK 0x00000006
-#define SERC5_SI2F_ADC 0x00000000
-#define SERC5_SI2F_SPDIF 0x00000002
-
-/*
- * The following defines are for the flags in the serial port backdoor sample
- * pointer register.
- */
-#define SERBSP_FSP_MASK 0x0000000F
-#define SERBSP_FSP_SHIFT 0
-
-/*
- * The following defines are for the flags in the serial port backdoor status
- * register.
- */
-#define SERBST_RRDY 0x00000001
-#define SERBST_WBSY 0x00000002
-
-/*
- * The following defines are for the flags in the serial port backdoor command
- * register.
- */
-#define SERBCM_RDC 0x00000001
-#define SERBCM_WRC 0x00000002
-
-/*
- * The following defines are for the flags in the serial port backdoor address
- * register.
- */
-#ifdef NO_CS4612
-#define SERBAD_FAD_MASK 0x000000FF
-#else
-#define SERBAD_FAD_MASK 0x000001FF
-#endif
-#define SERBAD_FAD_SHIFT 0
-
-/*
- * The following defines are for the flags in the serial port backdoor
- * configuration register.
- */
-#define SERBCF_HBP 0x00000001
-
-/*
- * The following defines are for the flags in the serial port backdoor write
- * port register.
- */
-#define SERBWP_FWD_MASK 0x000FFFFF
-#define SERBWP_FWD_SHIFT 0
-
-/*
- * The following defines are for the flags in the serial port backdoor read
- * port register.
- */
-#define SERBRP_FRD_MASK 0x000FFFFF
-#define SERBRP_FRD_SHIFT 0
-
-/*
- * The following defines are for the flags in the async FIFO address register.
- */
-#ifndef NO_CS4612
-#define ASER_FADDR_A1_MASK 0x000001FF
-#define ASER_FADDR_EN1 0x00008000
-#define ASER_FADDR_A2_MASK 0x01FF0000
-#define ASER_FADDR_EN2 0x80000000
-#define ASER_FADDR_A1_SHIFT 0
-#define ASER_FADDR_A2_SHIFT 16
-#endif
-
-/*
- * The following defines are for the flags in the AC97 control register.
- */
-#define ACCTL_RSTN 0x00000001
-#define ACCTL_ESYN 0x00000002
-#define ACCTL_VFRM 0x00000004
-#define ACCTL_DCV 0x00000008
-#define ACCTL_CRW 0x00000010
-#define ACCTL_ASYN 0x00000020
-#ifndef NO_CS4612
-#define ACCTL_TC 0x00000040
-#endif
-
-/*
- * The following defines are for the flags in the AC97 status register.
- */
-#define ACSTS_CRDY 0x00000001
-#define ACSTS_VSTS 0x00000002
-#ifndef NO_CS4612
-#define ACSTS_WKUP 0x00000004
-#endif
-
-/*
- * The following defines are for the flags in the AC97 output slot valid
- * register.
- */
-#define ACOSV_SLV3 0x00000001
-#define ACOSV_SLV4 0x00000002
-#define ACOSV_SLV5 0x00000004
-#define ACOSV_SLV6 0x00000008
-#define ACOSV_SLV7 0x00000010
-#define ACOSV_SLV8 0x00000020
-#define ACOSV_SLV9 0x00000040
-#define ACOSV_SLV10 0x00000080
-#define ACOSV_SLV11 0x00000100
-#define ACOSV_SLV12 0x00000200
-
-/*
- * The following defines are for the flags in the AC97 command address
- * register.
- */
-#define ACCAD_CI_MASK 0x0000007F
-#define ACCAD_CI_SHIFT 0
-
-/*
- * The following defines are for the flags in the AC97 command data register.
- */
-#define ACCDA_CD_MASK 0x0000FFFF
-#define ACCDA_CD_SHIFT 0
-
-/*
- * The following defines are for the flags in the AC97 input slot valid
- * register.
- */
-#define ACISV_ISV3 0x00000001
-#define ACISV_ISV4 0x00000002
-#define ACISV_ISV5 0x00000004
-#define ACISV_ISV6 0x00000008
-#define ACISV_ISV7 0x00000010
-#define ACISV_ISV8 0x00000020
-#define ACISV_ISV9 0x00000040
-#define ACISV_ISV10 0x00000080
-#define ACISV_ISV11 0x00000100
-#define ACISV_ISV12 0x00000200
-
-/*
- * The following defines are for the flags in the AC97 status address
- * register.
- */
-#define ACSAD_SI_MASK 0x0000007F
-#define ACSAD_SI_SHIFT 0
-
-/*
- * The following defines are for the flags in the AC97 status data register.
- */
-#define ACSDA_SD_MASK 0x0000FFFF
-#define ACSDA_SD_SHIFT 0
-
-/*
- * The following defines are for the flags in the joystick poll/trigger
- * register.
- */
-#define JSPT_CAX 0x00000001
-#define JSPT_CAY 0x00000002
-#define JSPT_CBX 0x00000004
-#define JSPT_CBY 0x00000008
-#define JSPT_BA1 0x00000010
-#define JSPT_BA2 0x00000020
-#define JSPT_BB1 0x00000040
-#define JSPT_BB2 0x00000080
-
-/*
- * The following defines are for the flags in the joystick control register.
- */
-#define JSCTL_SP_MASK 0x00000003
-#define JSCTL_SP_SLOW 0x00000000
-#define JSCTL_SP_MEDIUM_SLOW 0x00000001
-#define JSCTL_SP_MEDIUM_FAST 0x00000002
-#define JSCTL_SP_FAST 0x00000003
-#define JSCTL_ARE 0x00000004
-
-/*
- * The following defines are for the flags in the joystick coordinate pair 1
- * readback register.
- */
-#define JSC1_Y1V_MASK 0x0000FFFF
-#define JSC1_X1V_MASK 0xFFFF0000
-#define JSC1_Y1V_SHIFT 0
-#define JSC1_X1V_SHIFT 16
-
-/*
- * The following defines are for the flags in the joystick coordinate pair 2
- * readback register.
- */
-#define JSC2_Y2V_MASK 0x0000FFFF
-#define JSC2_X2V_MASK 0xFFFF0000
-#define JSC2_Y2V_SHIFT 0
-#define JSC2_X2V_SHIFT 16
-
-/*
- * The following defines are for the flags in the MIDI control register.
- */
-#define MIDCR_TXE 0x00000001 /* Enable transmitting. */
-#define MIDCR_RXE 0x00000002 /* Enable receiving. */
-#define MIDCR_RIE 0x00000004 /* Interrupt upon tx ready. */
-#define MIDCR_TIE 0x00000008 /* Interrupt upon rx ready. */
-#define MIDCR_MLB 0x00000010 /* Enable midi loopback. */
-#define MIDCR_MRST 0x00000020 /* Reset interface. */
-
-/*
- * The following defines are for the flags in the MIDI status register.
- */
-#define MIDSR_TBF 0x00000001 /* Tx FIFO is full. */
-#define MIDSR_RBE 0x00000002 /* Rx FIFO is empty. */
-
-/*
- * The following defines are for the flags in the MIDI write port register.
- */
-#define MIDWP_MWD_MASK 0x000000FF
-#define MIDWP_MWD_SHIFT 0
-
-/*
- * The following defines are for the flags in the MIDI read port register.
- */
-#define MIDRP_MRD_MASK 0x000000FF
-#define MIDRP_MRD_SHIFT 0
-
-/*
- * The following defines are for the flags in the joystick GPIO register.
- */
-#define JSIO_DAX 0x00000001
-#define JSIO_DAY 0x00000002
-#define JSIO_DBX 0x00000004
-#define JSIO_DBY 0x00000008
-#define JSIO_AXOE 0x00000010
-#define JSIO_AYOE 0x00000020
-#define JSIO_BXOE 0x00000040
-#define JSIO_BYOE 0x00000080
-
-/*
- * The following defines are for the flags in the master async/sync serial
- * port enable register.
- */
-#ifndef NO_CS4612
-#define ASER_MASTER_ME 0x00000001
-#endif
-
-/*
- * The following defines are for the flags in the configuration interface
- * register.
- */
-#define CFGI_CLK 0x00000001
-#define CFGI_DOUT 0x00000002
-#define CFGI_DIN_EEN 0x00000004
-#define CFGI_EELD 0x00000008
-
-/*
- * The following defines are for the flags in the subsystem ID and vendor ID
- * register.
- */
-#define SSVID_VID_MASK 0x0000FFFF
-#define SSVID_SID_MASK 0xFFFF0000
-#define SSVID_VID_SHIFT 0
-#define SSVID_SID_SHIFT 16
-
-/*
- * The following defines are for the flags in the GPIO pin interface register.
- */
-#define GPIOR_VOLDN 0x00000001
-#define GPIOR_VOLUP 0x00000002
-#define GPIOR_SI2D 0x00000004
-#define GPIOR_SI2OE 0x00000008
-
-/*
- * The following defines are for the flags in the extended GPIO pin direction
- * register.
- */
-#ifndef NO_CS4612
-#define EGPIODR_GPOE0 0x00000001
-#define EGPIODR_GPOE1 0x00000002
-#define EGPIODR_GPOE2 0x00000004
-#define EGPIODR_GPOE3 0x00000008
-#define EGPIODR_GPOE4 0x00000010
-#define EGPIODR_GPOE5 0x00000020
-#define EGPIODR_GPOE6 0x00000040
-#define EGPIODR_GPOE7 0x00000080
-#define EGPIODR_GPOE8 0x00000100
-#endif
-
-/*
- * The following defines are for the flags in the extended GPIO pin polarity/
- * type register.
- */
-#ifndef NO_CS4612
-#define EGPIOPTR_GPPT0 0x00000001
-#define EGPIOPTR_GPPT1 0x00000002
-#define EGPIOPTR_GPPT2 0x00000004
-#define EGPIOPTR_GPPT3 0x00000008
-#define EGPIOPTR_GPPT4 0x00000010
-#define EGPIOPTR_GPPT5 0x00000020
-#define EGPIOPTR_GPPT6 0x00000040
-#define EGPIOPTR_GPPT7 0x00000080
-#define EGPIOPTR_GPPT8 0x00000100
-#endif
-
-/*
- * The following defines are for the flags in the extended GPIO pin sticky
- * register.
- */
-#ifndef NO_CS4612
-#define EGPIOTR_GPS0 0x00000001
-#define EGPIOTR_GPS1 0x00000002
-#define EGPIOTR_GPS2 0x00000004
-#define EGPIOTR_GPS3 0x00000008
-#define EGPIOTR_GPS4 0x00000010
-#define EGPIOTR_GPS5 0x00000020
-#define EGPIOTR_GPS6 0x00000040
-#define EGPIOTR_GPS7 0x00000080
-#define EGPIOTR_GPS8 0x00000100
-#endif
-
-/*
- * The following defines are for the flags in the extended GPIO ping wakeup
- * register.
- */
-#ifndef NO_CS4612
-#define EGPIOWR_GPW0 0x00000001
-#define EGPIOWR_GPW1 0x00000002
-#define EGPIOWR_GPW2 0x00000004
-#define EGPIOWR_GPW3 0x00000008
-#define EGPIOWR_GPW4 0x00000010
-#define EGPIOWR_GPW5 0x00000020
-#define EGPIOWR_GPW6 0x00000040
-#define EGPIOWR_GPW7 0x00000080
-#define EGPIOWR_GPW8 0x00000100
-#endif
-
-/*
- * The following defines are for the flags in the extended GPIO pin status
- * register.
- */
-#ifndef NO_CS4612
-#define EGPIOSR_GPS0 0x00000001
-#define EGPIOSR_GPS1 0x00000002
-#define EGPIOSR_GPS2 0x00000004
-#define EGPIOSR_GPS3 0x00000008
-#define EGPIOSR_GPS4 0x00000010
-#define EGPIOSR_GPS5 0x00000020
-#define EGPIOSR_GPS6 0x00000040
-#define EGPIOSR_GPS7 0x00000080
-#define EGPIOSR_GPS8 0x00000100
-#endif
-
-/*
- * The following defines are for the flags in the serial port 6 configuration
- * register.
- */
-#ifndef NO_CS4612
-#define SERC6_ASDO2EN 0x00000001
-#endif
-
-/*
- * The following defines are for the flags in the serial port 7 configuration
- * register.
- */
-#ifndef NO_CS4612
-#define SERC7_ASDI2EN 0x00000001
-#define SERC7_POSILB 0x00000002
-#define SERC7_SIPOLB 0x00000004
-#define SERC7_SOSILB 0x00000008
-#define SERC7_SISOLB 0x00000010
-#endif
-
-/*
- * The following defines are for the flags in the serial port AC link
- * configuration register.
- */
-#ifndef NO_CS4612
-#define SERACC_CODEC_TYPE_MASK 0x00000001
-#define SERACC_CODEC_TYPE_1_03 0x00000000
-#define SERACC_CODEC_TYPE_2_0 0x00000001
-#define SERACC_TWO_CODECS 0x00000002
-#define SERACC_MDM 0x00000004
-#define SERACC_HSP 0x00000008
-#endif
-
-/*
- * The following defines are for the flags in the AC97 control register 2.
- */
-#ifndef NO_CS4612
-#define ACCTL2_RSTN 0x00000001
-#define ACCTL2_ESYN 0x00000002
-#define ACCTL2_VFRM 0x00000004
-#define ACCTL2_DCV 0x00000008
-#define ACCTL2_CRW 0x00000010
-#define ACCTL2_ASYN 0x00000020
-#endif
-
-/*
- * The following defines are for the flags in the AC97 status register 2.
- */
-#ifndef NO_CS4612
-#define ACSTS2_CRDY 0x00000001
-#define ACSTS2_VSTS 0x00000002
-#endif
-
-/*
- * The following defines are for the flags in the AC97 output slot valid
- * register 2.
- */
-#ifndef NO_CS4612
-#define ACOSV2_SLV3 0x00000001
-#define ACOSV2_SLV4 0x00000002
-#define ACOSV2_SLV5 0x00000004
-#define ACOSV2_SLV6 0x00000008
-#define ACOSV2_SLV7 0x00000010
-#define ACOSV2_SLV8 0x00000020
-#define ACOSV2_SLV9 0x00000040
-#define ACOSV2_SLV10 0x00000080
-#define ACOSV2_SLV11 0x00000100
-#define ACOSV2_SLV12 0x00000200
-#endif
-
-/*
- * The following defines are for the flags in the AC97 command address
- * register 2.
- */
-#ifndef NO_CS4612
-#define ACCAD2_CI_MASK 0x0000007F
-#define ACCAD2_CI_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the AC97 command data register
- * 2.
- */
-#ifndef NO_CS4612
-#define ACCDA2_CD_MASK 0x0000FFFF
-#define ACCDA2_CD_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the AC97 input slot valid
- * register 2.
- */
-#ifndef NO_CS4612
-#define ACISV2_ISV3 0x00000001
-#define ACISV2_ISV4 0x00000002
-#define ACISV2_ISV5 0x00000004
-#define ACISV2_ISV6 0x00000008
-#define ACISV2_ISV7 0x00000010
-#define ACISV2_ISV8 0x00000020
-#define ACISV2_ISV9 0x00000040
-#define ACISV2_ISV10 0x00000080
-#define ACISV2_ISV11 0x00000100
-#define ACISV2_ISV12 0x00000200
-#endif
-
-/*
- * The following defines are for the flags in the AC97 status address
- * register 2.
- */
-#ifndef NO_CS4612
-#define ACSAD2_SI_MASK 0x0000007F
-#define ACSAD2_SI_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the AC97 status data register 2.
- */
-#ifndef NO_CS4612
-#define ACSDA2_SD_MASK 0x0000FFFF
-#define ACSDA2_SD_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the I/O trap address and control
- * registers (all 12).
- */
-#ifndef NO_CS4612
-#define IOTAC_SA_MASK 0x0000FFFF
-#define IOTAC_MSK_MASK 0x000F0000
-#define IOTAC_IODC_MASK 0x06000000
-#define IOTAC_IODC_16_BIT 0x00000000
-#define IOTAC_IODC_10_BIT 0x02000000
-#define IOTAC_IODC_12_BIT 0x04000000
-#define IOTAC_WSPI 0x08000000
-#define IOTAC_RSPI 0x10000000
-#define IOTAC_WSE 0x20000000
-#define IOTAC_WE 0x40000000
-#define IOTAC_RE 0x80000000
-#define IOTAC_SA_SHIFT 0
-#define IOTAC_MSK_SHIFT 16
-#endif
-
-/*
- * The following defines are for the flags in the I/O trap fast read registers
- * (all 8).
- */
-#ifndef NO_CS4612
-#define IOTFR_D_MASK 0x0000FFFF
-#define IOTFR_A_MASK 0x000F0000
-#define IOTFR_R_MASK 0x0F000000
-#define IOTFR_ALL 0x40000000
-#define IOTFR_VL 0x80000000
-#define IOTFR_D_SHIFT 0
-#define IOTFR_A_SHIFT 16
-#define IOTFR_R_SHIFT 24
-#endif
-
-/*
- * The following defines are for the flags in the I/O trap FIFO register.
- */
-#ifndef NO_CS4612
-#define IOTFIFO_BA_MASK 0x00003FFF
-#define IOTFIFO_S_MASK 0x00FF0000
-#define IOTFIFO_OF 0x40000000
-#define IOTFIFO_SPIOF 0x80000000
-#define IOTFIFO_BA_SHIFT 0
-#define IOTFIFO_S_SHIFT 16
-#endif
-
-/*
- * The following defines are for the flags in the I/O trap retry read data
- * register.
- */
-#ifndef NO_CS4612
-#define IOTRRD_D_MASK 0x0000FFFF
-#define IOTRRD_RDV 0x80000000
-#define IOTRRD_D_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the I/O trap FIFO pointer
- * register.
- */
-#ifndef NO_CS4612
-#define IOTFP_CA_MASK 0x00003FFF
-#define IOTFP_PA_MASK 0x3FFF0000
-#define IOTFP_CA_SHIFT 0
-#define IOTFP_PA_SHIFT 16
-#endif
-
-/*
- * The following defines are for the flags in the I/O trap control register.
- */
-#ifndef NO_CS4612
-#define IOTCR_ITD 0x00000001
-#define IOTCR_HRV 0x00000002
-#define IOTCR_SRV 0x00000004
-#define IOTCR_DTI 0x00000008
-#define IOTCR_DFI 0x00000010
-#define IOTCR_DDP 0x00000020
-#define IOTCR_JTE 0x00000040
-#define IOTCR_PPE 0x00000080
-#endif
-
-/*
- * The following defines are for the flags in the direct PCI data register.
- */
-#ifndef NO_CS4612
-#define DPCID_D_MASK 0xFFFFFFFF
-#define DPCID_D_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the direct PCI address register.
- */
-#ifndef NO_CS4612
-#define DPCIA_A_MASK 0xFFFFFFFF
-#define DPCIA_A_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the direct PCI command register.
- */
-#ifndef NO_CS4612
-#define DPCIC_C_MASK 0x0000000F
-#define DPCIC_C_IOREAD 0x00000002
-#define DPCIC_C_IOWRITE 0x00000003
-#define DPCIC_BE_MASK 0x000000F0
-#endif
-
-/*
- * The following defines are for the flags in the PC/PCI request register.
- */
-#ifndef NO_CS4612
-#define PCPCIR_RDC_MASK 0x00000007
-#define PCPCIR_C_MASK 0x00007000
-#define PCPCIR_REQ 0x00008000
-#define PCPCIR_RDC_SHIFT 0
-#define PCPCIR_C_SHIFT 12
-#endif
-
-/*
- * The following defines are for the flags in the PC/PCI grant register.
- */
-#ifndef NO_CS4612
-#define PCPCIG_GDC_MASK 0x00000007
-#define PCPCIG_VL 0x00008000
-#define PCPCIG_GDC_SHIFT 0
-#endif
-
-/*
- * The following defines are for the flags in the PC/PCI master enable
- * register.
- */
-#ifndef NO_CS4612
-#define PCPCIEN_EN 0x00000001
-#endif
-
-/*
- * The following defines are for the flags in the extended PCI power
- * management control register.
- */
-#ifndef NO_CS4612
-#define EPCIPMC_GWU 0x00000001
-#define EPCIPMC_FSPC 0x00000002
-#endif
-
-/*
- * The following defines are for the flags in the SP control register.
- */
-#define SPCR_RUN 0x00000001
-#define SPCR_STPFR 0x00000002
-#define SPCR_RUNFR 0x00000004
-#define SPCR_TICK 0x00000008
-#define SPCR_DRQEN 0x00000020
-#define SPCR_RSTSP 0x00000040
-#define SPCR_OREN 0x00000080
-#ifndef NO_CS4612
-#define SPCR_PCIINT 0x00000100
-#define SPCR_OINTD 0x00000200
-#define SPCR_CRE 0x00008000
-#endif
-
-/*
- * The following defines are for the flags in the debug index register.
- */
-#define DREG_REGID_MASK 0x0000007F
-#define DREG_DEBUG 0x00000080
-#define DREG_RGBK_MASK 0x00000700
-#define DREG_TRAP 0x00000800
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_TRAPX 0x00001000
-#endif
-#endif
-#define DREG_REGID_SHIFT 0
-#define DREG_RGBK_SHIFT 8
-#define DREG_RGBK_REGID_MASK 0x0000077F
-#define DREG_REGID_R0 0x00000010
-#define DREG_REGID_R1 0x00000011
-#define DREG_REGID_R2 0x00000012
-#define DREG_REGID_R3 0x00000013
-#define DREG_REGID_R4 0x00000014
-#define DREG_REGID_R5 0x00000015
-#define DREG_REGID_R6 0x00000016
-#define DREG_REGID_R7 0x00000017
-#define DREG_REGID_R8 0x00000018
-#define DREG_REGID_R9 0x00000019
-#define DREG_REGID_RA 0x0000001A
-#define DREG_REGID_RB 0x0000001B
-#define DREG_REGID_RC 0x0000001C
-#define DREG_REGID_RD 0x0000001D
-#define DREG_REGID_RE 0x0000001E
-#define DREG_REGID_RF 0x0000001F
-#define DREG_REGID_RA_BUS_LOW 0x00000020
-#define DREG_REGID_RA_BUS_HIGH 0x00000038
-#define DREG_REGID_YBUS_LOW 0x00000050
-#define DREG_REGID_YBUS_HIGH 0x00000058
-#define DREG_REGID_TRAP_0 0x00000100
-#define DREG_REGID_TRAP_1 0x00000101
-#define DREG_REGID_TRAP_2 0x00000102
-#define DREG_REGID_TRAP_3 0x00000103
-#define DREG_REGID_TRAP_4 0x00000104
-#define DREG_REGID_TRAP_5 0x00000105
-#define DREG_REGID_TRAP_6 0x00000106
-#define DREG_REGID_TRAP_7 0x00000107
-#define DREG_REGID_INDIRECT_ADDRESS 0x0000010E
-#define DREG_REGID_TOP_OF_STACK 0x0000010F
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_8 0x00000110
-#define DREG_REGID_TRAP_9 0x00000111
-#define DREG_REGID_TRAP_10 0x00000112
-#define DREG_REGID_TRAP_11 0x00000113
-#define DREG_REGID_TRAP_12 0x00000114
-#define DREG_REGID_TRAP_13 0x00000115
-#define DREG_REGID_TRAP_14 0x00000116
-#define DREG_REGID_TRAP_15 0x00000117
-#define DREG_REGID_TRAP_16 0x00000118
-#define DREG_REGID_TRAP_17 0x00000119
-#define DREG_REGID_TRAP_18 0x0000011A
-#define DREG_REGID_TRAP_19 0x0000011B
-#define DREG_REGID_TRAP_20 0x0000011C
-#define DREG_REGID_TRAP_21 0x0000011D
-#define DREG_REGID_TRAP_22 0x0000011E
-#define DREG_REGID_TRAP_23 0x0000011F
-#endif
-#endif
-#define DREG_REGID_RSA0_LOW 0x00000200
-#define DREG_REGID_RSA0_HIGH 0x00000201
-#define DREG_REGID_RSA1_LOW 0x00000202
-#define DREG_REGID_RSA1_HIGH 0x00000203
-#define DREG_REGID_RSA2 0x00000204
-#define DREG_REGID_RSA3 0x00000205
-#define DREG_REGID_RSI0_LOW 0x00000206
-#define DREG_REGID_RSI0_HIGH 0x00000207
-#define DREG_REGID_RSI1 0x00000208
-#define DREG_REGID_RSI2 0x00000209
-#define DREG_REGID_SAGUSTATUS 0x0000020A
-#define DREG_REGID_RSCONFIG01_LOW 0x0000020B
-#define DREG_REGID_RSCONFIG01_HIGH 0x0000020C
-#define DREG_REGID_RSCONFIG23_LOW 0x0000020D
-#define DREG_REGID_RSCONFIG23_HIGH 0x0000020E
-#define DREG_REGID_RSDMA01E 0x0000020F
-#define DREG_REGID_RSDMA23E 0x00000210
-#define DREG_REGID_RSD0_LOW 0x00000211
-#define DREG_REGID_RSD0_HIGH 0x00000212
-#define DREG_REGID_RSD1_LOW 0x00000213
-#define DREG_REGID_RSD1_HIGH 0x00000214
-#define DREG_REGID_RSD2_LOW 0x00000215
-#define DREG_REGID_RSD2_HIGH 0x00000216
-#define DREG_REGID_RSD3_LOW 0x00000217
-#define DREG_REGID_RSD3_HIGH 0x00000218
-#define DREG_REGID_SRAR_HIGH 0x0000021A
-#define DREG_REGID_SRAR_LOW 0x0000021B
-#define DREG_REGID_DMA_STATE 0x0000021C
-#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021D
-#define DREG_REGID_NEXT_DMA_STREAM 0x0000021E
-#define DREG_REGID_CPU_STATUS 0x00000300
-#define DREG_REGID_MAC_MODE 0x00000301
-#define DREG_REGID_STACK_AND_REPEAT 0x00000302
-#define DREG_REGID_INDEX0 0x00000304
-#define DREG_REGID_INDEX1 0x00000305
-#define DREG_REGID_DMA_STATE_0_3 0x00000400
-#define DREG_REGID_DMA_STATE_4_7 0x00000404
-#define DREG_REGID_DMA_STATE_8_11 0x00000408
-#define DREG_REGID_DMA_STATE_12_15 0x0000040C
-#define DREG_REGID_DMA_STATE_16_19 0x00000410
-#define DREG_REGID_DMA_STATE_20_23 0x00000414
-#define DREG_REGID_DMA_STATE_24_27 0x00000418
-#define DREG_REGID_DMA_STATE_28_31 0x0000041C
-#define DREG_REGID_DMA_STATE_32_35 0x00000420
-#define DREG_REGID_DMA_STATE_36_39 0x00000424
-#define DREG_REGID_DMA_STATE_40_43 0x00000428
-#define DREG_REGID_DMA_STATE_44_47 0x0000042C
-#define DREG_REGID_DMA_STATE_48_51 0x00000430
-#define DREG_REGID_DMA_STATE_52_55 0x00000434
-#define DREG_REGID_DMA_STATE_56_59 0x00000438
-#define DREG_REGID_DMA_STATE_60_63 0x0000043C
-#define DREG_REGID_DMA_STATE_64_67 0x00000440
-#define DREG_REGID_DMA_STATE_68_71 0x00000444
-#define DREG_REGID_DMA_STATE_72_75 0x00000448
-#define DREG_REGID_DMA_STATE_76_79 0x0000044C
-#define DREG_REGID_DMA_STATE_80_83 0x00000450
-#define DREG_REGID_DMA_STATE_84_87 0x00000454
-#define DREG_REGID_DMA_STATE_88_91 0x00000458
-#define DREG_REGID_DMA_STATE_92_95 0x0000045C
-#define DREG_REGID_TRAP_SELECT 0x00000500
-#define DREG_REGID_TRAP_WRITE_0 0x00000500
-#define DREG_REGID_TRAP_WRITE_1 0x00000501
-#define DREG_REGID_TRAP_WRITE_2 0x00000502
-#define DREG_REGID_TRAP_WRITE_3 0x00000503
-#define DREG_REGID_TRAP_WRITE_4 0x00000504
-#define DREG_REGID_TRAP_WRITE_5 0x00000505
-#define DREG_REGID_TRAP_WRITE_6 0x00000506
-#define DREG_REGID_TRAP_WRITE_7 0x00000507
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_WRITE_8 0x00000510
-#define DREG_REGID_TRAP_WRITE_9 0x00000511
-#define DREG_REGID_TRAP_WRITE_10 0x00000512
-#define DREG_REGID_TRAP_WRITE_11 0x00000513
-#define DREG_REGID_TRAP_WRITE_12 0x00000514
-#define DREG_REGID_TRAP_WRITE_13 0x00000515
-#define DREG_REGID_TRAP_WRITE_14 0x00000516
-#define DREG_REGID_TRAP_WRITE_15 0x00000517
-#define DREG_REGID_TRAP_WRITE_16 0x00000518
-#define DREG_REGID_TRAP_WRITE_17 0x00000519
-#define DREG_REGID_TRAP_WRITE_18 0x0000051A
-#define DREG_REGID_TRAP_WRITE_19 0x0000051B
-#define DREG_REGID_TRAP_WRITE_20 0x0000051C
-#define DREG_REGID_TRAP_WRITE_21 0x0000051D
-#define DREG_REGID_TRAP_WRITE_22 0x0000051E
-#define DREG_REGID_TRAP_WRITE_23 0x0000051F
-#endif
-#endif
-#define DREG_REGID_MAC0_ACC0_LOW 0x00000600
-#define DREG_REGID_MAC0_ACC1_LOW 0x00000601
-#define DREG_REGID_MAC0_ACC2_LOW 0x00000602
-#define DREG_REGID_MAC0_ACC3_LOW 0x00000603
-#define DREG_REGID_MAC1_ACC0_LOW 0x00000604
-#define DREG_REGID_MAC1_ACC1_LOW 0x00000605
-#define DREG_REGID_MAC1_ACC2_LOW 0x00000606
-#define DREG_REGID_MAC1_ACC3_LOW 0x00000607
-#define DREG_REGID_MAC0_ACC0_MID 0x00000608
-#define DREG_REGID_MAC0_ACC1_MID 0x00000609
-#define DREG_REGID_MAC0_ACC2_MID 0x0000060A
-#define DREG_REGID_MAC0_ACC3_MID 0x0000060B
-#define DREG_REGID_MAC1_ACC0_MID 0x0000060C
-#define DREG_REGID_MAC1_ACC1_MID 0x0000060D
-#define DREG_REGID_MAC1_ACC2_MID 0x0000060E
-#define DREG_REGID_MAC1_ACC3_MID 0x0000060F
-#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610
-#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611
-#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612
-#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613
-#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614
-#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615
-#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616
-#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617
-#define DREG_REGID_RSHOUT_LOW 0x00000620
-#define DREG_REGID_RSHOUT_MID 0x00000628
-#define DREG_REGID_RSHOUT_HIGH 0x00000630
-
-/*
- * The following defines are for the flags in the DMA stream requestor write
- */
-#define DSRWP_DSR_MASK 0x0000000F
-#define DSRWP_DSR_BG_RQ 0x00000001
-#define DSRWP_DSR_PRIORITY_MASK 0x00000006
-#define DSRWP_DSR_PRIORITY_0 0x00000000
-#define DSRWP_DSR_PRIORITY_1 0x00000002
-#define DSRWP_DSR_PRIORITY_2 0x00000004
-#define DSRWP_DSR_PRIORITY_3 0x00000006
-#define DSRWP_DSR_RQ_PENDING 0x00000008
-
-/*
- * The following defines are for the flags in the trap write port register.
- */
-#define TWPR_TW_MASK 0x0000FFFF
-#define TWPR_TW_SHIFT 0
-
-/*
- * The following defines are for the flags in the stack pointer write
- * register.
- */
-#define SPWR_STKP_MASK 0x0000000F
-#define SPWR_STKP_SHIFT 0
-
-/*
- * The following defines are for the flags in the SP interrupt register.
- */
-#define SPIR_FRI 0x00000001
-#define SPIR_DOI 0x00000002
-#define SPIR_GPI2 0x00000004
-#define SPIR_GPI3 0x00000008
-#define SPIR_IP0 0x00000010
-#define SPIR_IP1 0x00000020
-#define SPIR_IP2 0x00000040
-#define SPIR_IP3 0x00000080
-
-/*
- * The following defines are for the flags in the functional group 1 register.
- */
-#define FGR1_F1S_MASK 0x0000FFFF
-#define FGR1_F1S_SHIFT 0
-
-/*
- * The following defines are for the flags in the SP clock status register.
- */
-#define SPCS_FRI 0x00000001
-#define SPCS_DOI 0x00000002
-#define SPCS_GPI2 0x00000004
-#define SPCS_GPI3 0x00000008
-#define SPCS_IP0 0x00000010
-#define SPCS_IP1 0x00000020
-#define SPCS_IP2 0x00000040
-#define SPCS_IP3 0x00000080
-#define SPCS_SPRUN 0x00000100
-#define SPCS_SLEEP 0x00000200
-#define SPCS_FG 0x00000400
-#define SPCS_ORUN 0x00000800
-#define SPCS_IRQ 0x00001000
-#define SPCS_FGN_MASK 0x0000E000
-#define SPCS_FGN_SHIFT 13
-
-/*
- * The following defines are for the flags in the SP DMA requestor status
- * register.
- */
-#define SDSR_DCS_MASK 0x000000FF
-#define SDSR_DCS_SHIFT 0
-#define SDSR_DCS_NONE 0x00000007
-
-/*
- * The following defines are for the flags in the frame timer register.
- */
-#define FRMT_FTV_MASK 0x0000FFFF
-#define FRMT_FTV_SHIFT 0
-
-/*
- * The following defines are for the flags in the frame timer current count
- * register.
- */
-#define FRCC_FCC_MASK 0x0000FFFF
-#define FRCC_FCC_SHIFT 0
-
-/*
- * The following defines are for the flags in the frame timer save count
- * register.
- */
-#define FRSC_FCS_MASK 0x0000FFFF
-#define FRSC_FCS_SHIFT 0
-
-/*
- * The following define the various flags stored in the scatter/gather
- * descriptors.
- */
-#define DMA_SG_NEXT_ENTRY_MASK 0x00000FF8
-#define DMA_SG_SAMPLE_END_MASK 0x0FFF0000
-#define DMA_SG_SAMPLE_END_FLAG 0x10000000
-#define DMA_SG_LOOP_END_FLAG 0x20000000
-#define DMA_SG_SIGNAL_END_FLAG 0x40000000
-#define DMA_SG_SIGNAL_PAGE_FLAG 0x80000000
-#define DMA_SG_NEXT_ENTRY_SHIFT 3
-#define DMA_SG_SAMPLE_END_SHIFT 16
-
-/*
- * The following define the offsets of the fields within the on-chip generic
- * DMA requestor.
- */
-#define DMA_RQ_CONTROL1 0x00000000
-#define DMA_RQ_CONTROL2 0x00000004
-#define DMA_RQ_SOURCE_ADDR 0x00000008
-#define DMA_RQ_DESTINATION_ADDR 0x0000000C
-#define DMA_RQ_NEXT_PAGE_ADDR 0x00000010
-#define DMA_RQ_NEXT_PAGE_SGDESC 0x00000014
-#define DMA_RQ_LOOP_START_ADDR 0x00000018
-#define DMA_RQ_POST_LOOP_ADDR 0x0000001C
-#define DMA_RQ_PAGE_MAP_ADDR 0x00000020
-
-/*
- * The following defines are for the flags in the first control word of the
- * on-chip generic DMA requestor.
- */
-#define DMA_RQ_C1_COUNT_MASK 0x000003FF
-#define DMA_RQ_C1_DESTINATION_SCATTER 0x00001000
-#define DMA_RQ_C1_SOURCE_GATHER 0x00002000
-#define DMA_RQ_C1_DONE_FLAG 0x00004000
-#define DMA_RQ_C1_OPTIMIZE_STATE 0x00008000
-#define DMA_RQ_C1_SAMPLE_END_STATE_MASK 0x00030000
-#define DMA_RQ_C1_FULL_PAGE 0x00000000
-#define DMA_RQ_C1_BEFORE_SAMPLE_END 0x00010000
-#define DMA_RQ_C1_PAGE_MAP_ERROR 0x00020000
-#define DMA_RQ_C1_AT_SAMPLE_END 0x00030000
-#define DMA_RQ_C1_LOOP_END_STATE_MASK 0x000C0000
-#define DMA_RQ_C1_NOT_LOOP_END 0x00000000
-#define DMA_RQ_C1_BEFORE_LOOP_END 0x00040000
-#define DMA_RQ_C1_2PAGE_LOOP_BEGIN 0x00080000
-#define DMA_RQ_C1_LOOP_BEGIN 0x000C0000
-#define DMA_RQ_C1_PAGE_MAP_MASK 0x00300000
-#define DMA_RQ_C1_PM_NONE_PENDING 0x00000000
-#define DMA_RQ_C1_PM_NEXT_PENDING 0x00100000
-#define DMA_RQ_C1_PM_RESERVED 0x00200000
-#define DMA_RQ_C1_PM_LOOP_NEXT_PENDING 0x00300000
-#define DMA_RQ_C1_WRITEBACK_DEST_FLAG 0x00400000
-#define DMA_RQ_C1_WRITEBACK_SRC_FLAG 0x00800000
-#define DMA_RQ_C1_DEST_SIZE_MASK 0x07000000
-#define DMA_RQ_C1_DEST_LINEAR 0x00000000
-#define DMA_RQ_C1_DEST_MOD16 0x01000000
-#define DMA_RQ_C1_DEST_MOD32 0x02000000
-#define DMA_RQ_C1_DEST_MOD64 0x03000000
-#define DMA_RQ_C1_DEST_MOD128 0x04000000
-#define DMA_RQ_C1_DEST_MOD256 0x05000000
-#define DMA_RQ_C1_DEST_MOD512 0x06000000
-#define DMA_RQ_C1_DEST_MOD1024 0x07000000
-#define DMA_RQ_C1_DEST_ON_HOST 0x08000000
-#define DMA_RQ_C1_SOURCE_SIZE_MASK 0x70000000
-#define DMA_RQ_C1_SOURCE_LINEAR 0x00000000
-#define DMA_RQ_C1_SOURCE_MOD16 0x10000000
-#define DMA_RQ_C1_SOURCE_MOD32 0x20000000
-#define DMA_RQ_C1_SOURCE_MOD64 0x30000000
-#define DMA_RQ_C1_SOURCE_MOD128 0x40000000
-#define DMA_RQ_C1_SOURCE_MOD256 0x50000000
-#define DMA_RQ_C1_SOURCE_MOD512 0x60000000
-#define DMA_RQ_C1_SOURCE_MOD1024 0x70000000
-#define DMA_RQ_C1_SOURCE_ON_HOST 0x80000000
-#define DMA_RQ_C1_COUNT_SHIFT 0
-
-/*
- * The following defines are for the flags in the second control word of the
- * on-chip generic DMA requestor.
- */
-#define DMA_RQ_C2_VIRTUAL_CHANNEL_MASK 0x0000003F
-#define DMA_RQ_C2_VIRTUAL_SIGNAL_MASK 0x00000300
-#define DMA_RQ_C2_NO_VIRTUAL_SIGNAL 0x00000000
-#define DMA_RQ_C2_SIGNAL_EVERY_DMA 0x00000100
-#define DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG 0x00000200
-#define DMA_RQ_C2_SIGNAL_DEST_PINGPONG 0x00000300
-#define DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000
-#define DMA_RQ_C2_AC_NONE 0x00000000
-#define DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000
-#define DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000
-#define DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000
-#define DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000
-#define DMA_RQ_C2_LOOP_END_MASK 0x0FFF0000
-#define DMA_RQ_C2_LOOP_MASK 0x30000000
-#define DMA_RQ_C2_NO_LOOP 0x00000000
-#define DMA_RQ_C2_ONE_PAGE_LOOP 0x10000000
-#define DMA_RQ_C2_TWO_PAGE_LOOP 0x20000000
-#define DMA_RQ_C2_MULTI_PAGE_LOOP 0x30000000
-#define DMA_RQ_C2_SIGNAL_LOOP_BACK 0x40000000
-#define DMA_RQ_C2_SIGNAL_POST_BEGIN_PAGE 0x80000000
-#define DMA_RQ_C2_VIRTUAL_CHANNEL_SHIFT 0
-#define DMA_RQ_C2_LOOP_END_SHIFT 16
-
-/*
- * The following defines are for the flags in the source and destination words
- * of the on-chip generic DMA requestor.
- */
-#define DMA_RQ_SD_ADDRESS_MASK 0x0000FFFF
-#define DMA_RQ_SD_MEMORY_ID_MASK 0x000F0000
-#define DMA_RQ_SD_SP_PARAM_ADDR 0x00000000
-#define DMA_RQ_SD_SP_SAMPLE_ADDR 0x00010000
-#define DMA_RQ_SD_SP_PROGRAM_ADDR 0x00020000
-#define DMA_RQ_SD_SP_DEBUG_ADDR 0x00030000
-#define DMA_RQ_SD_OMNIMEM_ADDR 0x000E0000
-#define DMA_RQ_SD_END_FLAG 0x40000000
-#define DMA_RQ_SD_ERROR_FLAG 0x80000000
-#define DMA_RQ_SD_ADDRESS_SHIFT 0
-
-/*
- * The following defines are for the flags in the page map address word of the
- * on-chip generic DMA requestor.
- */
-#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_MASK 0x00000FF8
-#define DMA_RQ_PMA_PAGE_TABLE_MASK 0xFFFFF000
-#define DMA_RQ_PMA_LOOP_THIRD_PAGE_ENTRY_SHIFT 3
-#define DMA_RQ_PMA_PAGE_TABLE_SHIFT 12
-
-#define BA1_VARIDEC_BUF_1 0x000
-
-#define BA1_PDTC 0x0c0 /* BA1_PLAY_DMA_TRANSACTION_COUNT_REG */
-#define BA1_PFIE 0x0c4 /* BA1_PLAY_FORMAT_&_INTERRUPT_ENABLE_REG */
-#define BA1_PBA 0x0c8 /* BA1_PLAY_BUFFER_ADDRESS */
-#define BA1_PVOL 0x0f8 /* BA1_PLAY_VOLUME_REG */
-#define BA1_PSRC 0x288 /* BA1_PLAY_SAMPLE_RATE_CORRECTION_REG */
-#define BA1_PCTL 0x2a4 /* BA1_PLAY_CONTROL_REG */
-#define BA1_PPI 0x2b4 /* BA1_PLAY_PHASE_INCREMENT_REG */
-
-#define BA1_CCTL 0x064 /* BA1_CAPTURE_CONTROL_REG */
-#define BA1_CIE 0x104 /* BA1_CAPTURE_INTERRUPT_ENABLE_REG */
-#define BA1_CBA 0x10c /* BA1_CAPTURE_BUFFER_ADDRESS */
-#define BA1_CSRC 0x2c8 /* BA1_CAPTURE_SAMPLE_RATE_CORRECTION_REG */
-#define BA1_CCI 0x2d8 /* BA1_CAPTURE_COEFFICIENT_INCREMENT_REG */
-#define BA1_CD 0x2e0 /* BA1_CAPTURE_DELAY_REG */
-#define BA1_CPI 0x2f4 /* BA1_CAPTURE_PHASE_INCREMENT_REG */
-#define BA1_CVOL 0x2f8 /* BA1_CAPTURE_VOLUME_REG */
-
-#define BA1_CFG1 0x134 /* BA1_CAPTURE_FRAME_GROUP_1_REG */
-#define BA1_CFG2 0x138 /* BA1_CAPTURE_FRAME_GROUP_2_REG */
-#define BA1_CCST 0x13c /* BA1_CAPTURE_CONSTANT_REG */
-#define BA1_CSPB 0x340 /* BA1_CAPTURE_SPB_ADDRESS */
-
-/*
- *
- */
-
-#define CS461X_MODE_OUTPUT (1<<0) /* MIDI UART - output */
-#define CS461X_MODE_INPUT (1<<1) /* MIDI UART - input */
-
-//****************************************************************************
-//
-// The following define the offsets of the AC97 shadow registers, which appear
-// as a virtual extension to the base address register zero memory range.
-//
-//****************************************************************************
-#define AC97_REG_OFFSET_MASK 0x0000007EL
-#define AC97_CODEC_NUMBER_MASK 0x00003000L
-
-#define BA0_AC97_RESET 0x00001000L
-#define BA0_AC97_MASTER_VOLUME 0x00001002L
-#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L
-#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L
-#define BA0_AC97_MASTER_TONE 0x00001008L
-#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL
-#define BA0_AC97_PHONE_VOLUME 0x0000100CL
-#define BA0_AC97_MIC_VOLUME 0x0000100EL
-#define BA0_AC97_LINE_IN_VOLUME 0x00001010L
-#define BA0_AC97_CD_VOLUME 0x00001012L
-#define BA0_AC97_VIDEO_VOLUME 0x00001014L
-#define BA0_AC97_AUX_VOLUME 0x00001016L
-#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L
-#define BA0_AC97_RECORD_SELECT 0x0000101AL
-#define BA0_AC97_RECORD_GAIN 0x0000101CL
-#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL
-#define BA0_AC97_GENERAL_PURPOSE 0x00001020L
-#define BA0_AC97_3D_CONTROL 0x00001022L
-#define BA0_AC97_MODEM_RATE 0x00001024L
-#define BA0_AC97_POWERDOWN 0x00001026L
-#define BA0_AC97_EXT_AUDIO_ID 0x00001028L
-#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL
-#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL
-#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL
-#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L
-#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L
-#define BA0_AC97_MIC_ADC_RATE 0x00001034L
-#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L
-#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L
-#define BA0_AC97_RESERVED_3A 0x0000103AL
-#define BA0_AC97_EXT_MODEM_ID 0x0000103CL
-#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL
-#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L
-#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L
-#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L
-#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L
-#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L
-#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL
-#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL
-#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL
-#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L
-#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L
-#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L
-#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L
-#define BA0_AC97_RESERVED_58 0x00001058L
-#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL
-#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL
-#define BA0_AC97_AC_MODE 0x0000105EL
-#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L
-#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L
-#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L
-#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L
-#define BA0_AC97_SPDIF_CONTROL 0x00001068L
-#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL
-#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL
-#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL
-#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L
-#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L
-#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L
-#define BA0_AC97_CAL_ADDRESS 0x00001076L
-#define BA0_AC97_CAL_DATA 0x00001078L
-#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL
-#define BA0_AC97_VENDOR_ID1 0x0000107CL
-#define BA0_AC97_VENDOR_ID2 0x0000107EL
-#endif /* __CS461X_H */
diff --git a/sound/oss/cs461x_image.h b/sound/oss/cs461x_image.h
deleted file mode 100644
index b5c5a46d3423..000000000000
--- a/sound/oss/cs461x_image.h
+++ /dev/null
@@ -1,322 +0,0 @@
-/****************************************************************************
- * "CWCIMAGE.H"-- For CS46XX. Ver 1.04
- * Copyright 1998-2001 (c) Cirrus Logic Corp.
- * Version 1.04
- ****************************************************************************
- */
-#ifndef __CS_IMAGE_H
-#define __CS_IMAGE_H
-
-#define CLEAR__COUNT 3
-#define FILL__COUNT 4
-#define BA1__DWORD_SIZE 13*1024+512
-
-static struct
-{
- unsigned BA1__DestByteOffset;
- unsigned BA1__SourceSize;
-} ClrStat[CLEAR__COUNT] ={ {0x00000000, 0x00003000 },
- {0x00010000, 0x00003800 },
- {0x00020000, 0x00007000 } };
-
-static u32 FillArray1[]={
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000163,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00200040,0x00008010,0x00000000,
-0x00000000,0x80000001,0x00000001,0x00060000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00900080,0x00000173,0x00000000,
-0x00000000,0x00000010,0x00800000,0x00900000,
-0xf2c0000f,0x00000200,0x00000000,0x00010600,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000163,0x330300c2,
-0x06000000,0x00000000,0x80008000,0x80008000,
-0x3fc0000f,0x00000301,0x00010400,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00b00000,0x00d0806d,0x330480c3,
-0x04800000,0x00000001,0x00800001,0x0000ffff,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x066a0600,0x06350070,0x0000929d,0x929d929d,
-0x00000000,0x0000735a,0x00000600,0x00000000,
-0x929d735a,0x00000000,0x00010000,0x735a735a,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000804f,0x000000c3,
-0x05000000,0x00a00010,0x00000000,0x80008000,
-0x00000000,0x00000000,0x00000700,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000080,0x00a00000,0x0000809a,0x000000c2,
-0x07400000,0x00000000,0x80008000,0xffffffff,
-0x00c80028,0x00005555,0x00000000,0x000107a0,
-0x00c80028,0x000000c2,0x06800000,0x00000000,
-0x06e00080,0x00300000,0x000080bb,0x000000c9,
-0x07a00000,0x04000000,0x80008000,0xffffffff,
-0x00c80028,0x00005555,0x00000000,0x00000780,
-0x00c80028,0x000000c5,0xff800000,0x00000000,
-0x00640080,0x00c00000,0x00008197,0x000000c9,
-0x07800000,0x04000000,0x80008000,0xffffffff,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000805e,0x000000c1,
-0x00000000,0x00800000,0x80008000,0x80008000,
-0x00020000,0x0000ffff,0x00000000,0x00000000};
-
-static u32 FillArray2[]={
-0x929d0600,0x929d929d,0x929d929d,0x929d0000,
-0x929d929d,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0x00100635,0x060b013f,0x00000004,
-0x00000001,0x007a0002,0x00000000,0x066e0610,
-0x0105929d,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0xa431ac75,0x0001735a,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0x735a0051,
-0x00000000,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0x929d929d,0x929d929d,0x929d929d,
-0x929d929d,0x929d929d,0x00000000,0x06400136,
-0x0000270f,0x00010000,0x007a0000,0x00000000,
-0x068e0645,0x0105929d,0x929d929d,0x929d929d,
-0x929d929d,0x929d929d,0xa431ac75,0x0001735a,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75,
-0x735a0100,0x00000000,0x00000000,0x00000000};
-
-static u32 FillArray3[]={
-0x00000000,0x00000000,0x00000000,0x00010004};
-
-static u32 FillArray4[]={
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00001705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00009705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00011705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00019705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00021705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00029705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00031705,0x00001400,0x000a411e,0x00001003,
-0x00040730,0x00001002,0x000f619e,0x00001003,
-0x00039705,0x00001400,0x000a411e,0x00001003,
-0x000fe19e,0x00001003,0x0009c730,0x00001003,
-0x0008e19c,0x00001003,0x000083c1,0x00093040,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00009705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00011705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00019705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00021705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00029705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00031705,0x00001400,0x000a211e,0x00001003,
-0x00098730,0x00001002,0x000ee19e,0x00001003,
-0x00039705,0x00001400,0x000a211e,0x00001003,
-0x0000a730,0x00001008,0x000e2730,0x00001002,
-0x0000a731,0x00001002,0x0000a731,0x00001002,
-0x0000a731,0x00001002,0x0000a731,0x00001002,
-0x0000a731,0x00001002,0x0000a731,0x00001002,
-0x00000000,0x00000000,0x000f619c,0x00001003,
-0x0007f801,0x000c0000,0x00000037,0x00001000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x000c0000,0x00000000,0x00000000,
-0x0000373c,0x00001000,0x00000000,0x00000000,
-0x000ee19c,0x00001003,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000273c,0x00001000,
-0x00000033,0x00001000,0x000e679e,0x00001003,
-0x00007705,0x00001400,0x000ac71e,0x00001003,
-0x00087fc1,0x000c3be0,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0000a730,0x00001003,
-0x00000033,0x00001000,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x000c0000,
-0x00000032,0x00001000,0x0000273d,0x00001000,
-0x0004a730,0x00001003,0x00000f41,0x00097140,
-0x0000a841,0x0009b240,0x0000a0c1,0x0009f040,
-0x0001c641,0x00093540,0x0001cec1,0x0009b5c0,
-0x00000000,0x00000000,0x0001bf05,0x0003fc40,
-0x00002725,0x000aa400,0x00013705,0x00093a00,
-0x0000002e,0x0009d6c0,0x00038630,0x00001004,
-0x0004ef0a,0x000eb785,0x0003fc8a,0x00000000,
-0x00000000,0x000c70e0,0x0007d182,0x0002c640,
-0x00000630,0x00001004,0x000799b8,0x0002c6c0,
-0x00031705,0x00092240,0x00039f05,0x000932c0,
-0x0003520a,0x00000000,0x00040731,0x0000100b,
-0x00010705,0x000b20c0,0x00000000,0x000eba44,
-0x00032108,0x000c60c4,0x00065208,0x000c2917,
-0x000406b0,0x00001007,0x00012f05,0x00036880,
-0x0002818e,0x000c0000,0x0004410a,0x00000000,
-0x00040630,0x00001007,0x00029705,0x000c0000,
-0x00000000,0x00000000,0x00003fc1,0x0003fc40,
-0x000037c1,0x00091b40,0x00003fc1,0x000911c0,
-0x000037c1,0x000957c0,0x00003fc1,0x000951c0,
-0x000037c1,0x00000000,0x00003fc1,0x000991c0,
-0x000037c1,0x00000000,0x00003fc1,0x0009d1c0,
-0x000037c1,0x00000000,0x0001ccc1,0x000915c0,
-0x0001c441,0x0009d800,0x0009cdc1,0x00091240,
-0x0001c541,0x00091d00,0x0009cfc1,0x00095240,
-0x0001c741,0x00095c80,0x000e8ca9,0x00099240,
-0x000e85ad,0x00095640,0x00069ca9,0x00099d80,
-0x000e952d,0x00099640,0x000eaca9,0x0009d6c0,
-0x000ea5ad,0x00091a40,0x0006bca9,0x0009de80,
-0x000eb52d,0x00095a40,0x000ecca9,0x00099ac0,
-0x000ec5ad,0x0009da40,0x000edca9,0x0009d300,
-0x000a6e0a,0x00001000,0x000ed52d,0x00091e40,
-0x000eeca9,0x00095ec0,0x000ee5ad,0x00099e40,
-0x0006fca9,0x00002500,0x000fb208,0x000c59a0,
-0x000ef52d,0x0009de40,0x00068ca9,0x000912c1,
-0x000683ad,0x00095241,0x00020f05,0x000991c1,
-0x00000000,0x00000000,0x00086f88,0x00001000,
-0x0009cf81,0x000b5340,0x0009c701,0x000b92c0,
-0x0009de81,0x000bd300,0x0009d601,0x000b1700,
-0x0001fd81,0x000b9d80,0x0009f501,0x000b57c0,
-0x000a0f81,0x000bd740,0x00020701,0x000b5c80,
-0x000a1681,0x000b97c0,0x00021601,0x00002500,
-0x000a0701,0x000b9b40,0x000a0f81,0x000b1bc0,
-0x00021681,0x00002d00,0x00020f81,0x000bd800,
-0x000a0701,0x000b5bc0,0x00021601,0x00003500,
-0x000a0f81,0x000b5f40,0x000a0701,0x000bdbc0,
-0x00021681,0x00003d00,0x00020f81,0x000b1d00,
-0x000a0701,0x000b1fc0,0x00021601,0x00020500,
-0x00020f81,0x000b1341,0x000a0701,0x000b9fc0,
-0x00021681,0x00020d00,0x00020f81,0x000bde80,
-0x000a0701,0x000bdfc0,0x00021601,0x00021500,
-0x00020f81,0x000b9341,0x00020701,0x000b53c1,
-0x00021681,0x00021d00,0x000a0f81,0x000d0380,
-0x0000b601,0x000b15c0,0x00007b01,0x00000000,
-0x00007b81,0x000bd1c0,0x00007b01,0x00000000,
-0x00007b81,0x000b91c0,0x00007b01,0x000b57c0,
-0x00007b81,0x000b51c0,0x00007b01,0x000b1b40,
-0x00007b81,0x000b11c0,0x00087b01,0x000c3dc0,
-0x0007e488,0x000d7e45,0x00000000,0x000d7a44,
-0x0007e48a,0x00000000,0x00011f05,0x00084080,
-0x00000000,0x00000000,0x00001705,0x000b3540,
-0x00008a01,0x000bf040,0x00007081,0x000bb5c0,
-0x00055488,0x00000000,0x0000d482,0x0003fc40,
-0x0003fc88,0x00000000,0x0001e401,0x000b3a00,
-0x0001ec81,0x000bd6c0,0x0004ef08,0x000eb784,
-0x000c86b0,0x00001007,0x00008281,0x000bb240,
-0x0000b801,0x000b7140,0x00007888,0x00000000,
-0x0000073c,0x00001000,0x0007f188,0x000c0000,
-0x00000000,0x00000000,0x00055288,0x000c555c,
-0x0005528a,0x000c0000,0x0009fa88,0x000c5d00,
-0x0000fa88,0x00000000,0x00000032,0x00001000,
-0x0000073d,0x00001000,0x0007f188,0x000c0000,
-0x00000000,0x00000000,0x0008c01c,0x00001003,
-0x00002705,0x00001008,0x0008b201,0x000c1392,
-0x0000ba01,0x00000000,0x00008731,0x00001400,
-0x0004c108,0x000fe0c4,0x00057488,0x00000000,
-0x000a6388,0x00001001,0x0008b334,0x000bc141,
-0x0003020e,0x00000000,0x000886b0,0x00001008,
-0x00003625,0x000c5dfa,0x000a638a,0x00001001,
-0x0008020e,0x00001002,0x0008a6b0,0x00001008,
-0x0007f301,0x00000000,0x00000000,0x00000000,
-0x00002725,0x000a8c40,0x000000ae,0x00000000,
-0x000d8630,0x00001008,0x00000000,0x000c74e0,
-0x0007d182,0x0002d640,0x000a8630,0x00001008,
-0x000799b8,0x0002d6c0,0x0000748a,0x000c3ec5,
-0x0007420a,0x000c0000,0x00062208,0x000c4117,
-0x00070630,0x00001009,0x00000000,0x000c0000,
-0x0001022e,0x00000000,0x0003a630,0x00001009,
-0x00000000,0x000c0000,0x00000036,0x00001000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x0002a730,0x00001008,0x0007f801,0x000c0000,
-0x00000037,0x00001000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x00000000,0x00000000,
-0x00000000,0x00000000,0x0002a730,0x00001008,
-0x00000033,0x00001000,0x0002a705,0x00001008,
-0x00007a01,0x000c0000,0x000e6288,0x000d550a,
-0x0006428a,0x00000000,0x00060730,0x0000100a,
-0x00000000,0x000c0000,0x00000000,0x00000000,
-0x0007aab0,0x00034880,0x00078fb0,0x0000100b,
-0x00057488,0x00000000,0x00033b94,0x00081140,
-0x000183ae,0x00000000,0x000786b0,0x0000100b,
-0x00022f05,0x000c3545,0x0000eb8a,0x00000000,
-0x00042731,0x00001003,0x0007aab0,0x00034880,
-0x00048fb0,0x0000100a,0x00057488,0x00000000,
-0x00033b94,0x00081140,0x000183ae,0x00000000,
-0x000806b0,0x0000100b,0x00022f05,0x00000000,
-0x00007401,0x00091140,0x00048f05,0x000951c0,
-0x00042731,0x00001003,0x0000473d,0x00001000,
-0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
-0x000fe19e,0x00001003,0x00000000,0x00000000,
-0x0008e19c,0x00001003,0x000083c1,0x00093040,
-0x00000f41,0x00097140,0x0000a841,0x0009b240,
-0x0000a0c1,0x0009f040,0x0001c641,0x00093540,
-0x0001cec1,0x0009b5c0,0x00000000,0x000fdc44,
-0x00055208,0x00000000,0x00010705,0x000a2880,
-0x0000a23a,0x00093a00,0x0003fc8a,0x000df6c5,
-0x0004ef0a,0x000c0000,0x00012f05,0x00036880,
-0x00065308,0x000c2997,0x000d86b0,0x0000100a,
-0x0004410a,0x000d40c7,0x00000000,0x00000000,
-0x00080730,0x00001004,0x00056f0a,0x000ea105,
-0x00000000,0x00000000,0x0000473d,0x00001000,
-0x000f19b0,0x000bbc47,0x00080000,0x000bffc7,
-0x0000273d,0x00001000,0x00000000,0x000eba44,
-0x00048f05,0x0000f440,0x00007401,0x0000f7c0,
-0x00000734,0x00001000,0x00010705,0x000a6880,
-0x00006a88,0x000c75c4,0x00000000,0x000e5084,
-0x00000000,0x000eba44,0x00087401,0x000e4782,
-0x00000734,0x00001000,0x00010705,0x000a6880,
-0x00006a88,0x000c75c4,0x0007c108,0x000c0000,
-0x0007e721,0x000bed40,0x00005f25,0x000badc0,
-0x0003ba97,0x000beb80,0x00065590,0x000b2e00,
-0x00033217,0x00003ec0,0x00065590,0x000b8e40,
-0x0003ed80,0x000491c0,0x00073fb0,0x00074c80,
-0x000283a0,0x0000100c,0x000ee388,0x00042970,
-0x00008301,0x00021ef2,0x000b8f14,0x0000000f,
-0x000c4d8d,0x0000001b,0x000d6dc2,0x000e06c6,
-0x000032ac,0x000c3916,0x0004edc2,0x00074c80,
-0x00078898,0x00001000,0x00038894,0x00000032,
-0x000c4d8d,0x00092e1b,0x000d6dc2,0x000e06c6,
-0x0004edc2,0x000c1956,0x0000722c,0x00034a00,
-0x00041705,0x0009ed40,0x00058730,0x00001400,
-0x000d7488,0x000c3a00,0x00048f05,0x00000000};
-
-static struct
-{ u32 Offset;
- u32 Size;
- u32 *pFill;
-} FillStat[FILL__COUNT] = {
- {0x00000000, sizeof(FillArray1), FillArray1},
- {0x00001800, sizeof(FillArray2), FillArray2},
- {0x000137f0, sizeof(FillArray3), FillArray3},
- {0x00020000, sizeof(FillArray4), FillArray4}
- };
-
-
-#endif
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
deleted file mode 100644
index 2a1f0d9ac968..000000000000
--- a/sound/oss/cs46xx.c
+++ /dev/null
@@ -1,5444 +0,0 @@
-/*
- * Crystal SoundFusion CS46xx driver
- *
- * Copyright 1998-2001 Cirrus Logic Corporation <pcaudio@crystal.cirrus.com>
- * <twoller@crystal.cirrus.com>
- * Copyright 1999-2000 Jaroslav Kysela <perex@suse.cz>
- * Copyright 2000 Alan Cox <alan@redhat.com>
- *
- * The core of this code is taken from the ALSA project driver by
- * Jaroslav. Please send Jaroslav the credit for the driver and
- * report bugs in this port to <alan@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- * Current maintainers:
- * Cirrus Logic Corporation, Thomas Woller (tw)
- * <twoller@crystal.cirrus.com>
- * Nils Faerber (nf)
- * <nils@kernelconcepts.de>
- * Thanks to David Pollard for testing.
- *
- * Changes:
- * 20000909-nf Changed cs_read, cs_write and drain_dac
- * 20001025-tw Separate Playback/Capture structs and buffers.
- * Added Scatter/Gather support for Playback.
- * Added Capture.
- * 20001027-nf Port to kernel 2.4.0-test9, some clean-ups
- * Start of powermanagement support (CS46XX_PM).
- * 20001128-tw Add module parm for default buffer order.
- * added DMA_GFP flag to kmalloc dma buffer allocs.
- * backfill silence to eliminate stuttering on
- * underruns.
- * 20001201-tw add resyncing of swptr on underruns.
- * 20001205-tw-nf fixed GETOSPACE ioctl() after open()
- * 20010113-tw patch from Hans Grobler general cleanup.
- * 20010117-tw 2.4.0 pci cleanup, wrapper code for 2.2.16-2.4.0
- * 20010118-tw basic PM support for 2.2.16+ and 2.4.0/2.4.2.
- * 20010228-dh patch from David Huggins - cs_update_ptr recursion.
- * 20010409-tw add hercules game theatre XP amp code.
- * 20010420-tw cleanup powerdown/up code.
- * 20010521-tw eliminate pops, and fixes for powerdown.
- * 20010525-tw added fixes for thinkpads with powerdown logic.
- * 20010723-sh patch from Horms (Simon Horman) -
- * SOUND_PCM_READ_BITS returns bits as set in driver
- * rather than a logical or of the possible values.
- * Various ioctls handle the case where the device
- * is open for reading or writing but not both better.
- *
- * Status:
- * Playback/Capture supported from 8k-48k.
- * 16Bit Signed LE & 8Bit Unsigned, with Mono or Stereo supported.
- *
- * APM/PM - 2.2.x APM is enabled and functioning fine. APM can also
- * be enabled for 2.4.x by modifying the CS46XX_ACPI_SUPPORT macro
- * definition.
- *
- * Hercules Game Theatre XP - the EGPIO2 pin controls the external Amp,
- * so, use the drain/polarity to enable.
- * hercules_egpio_disable set to 1, will force a 0 to EGPIODR.
- *
- * VTB Santa Cruz - the GPIO7/GPIO8 on the Secondary Codec control
- * the external amplifier for the "back" speakers, since we do not
- * support the secondary codec then this external amp is also not
- * turned on.
- */
-
-#include <linux/interrupt.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/ac97_codec.h>
-#include <linux/mutex.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "cs46xxpm.h"
-#include "cs46xx_wrapper-24.h"
-#include "cs461x.h"
-
-/* MIDI buffer sizes */
-#define CS_MIDIINBUF 500
-#define CS_MIDIOUTBUF 500
-
-#define ADC_RUNNING 1
-#define DAC_RUNNING 2
-
-#define CS_FMT_16BIT 1 /* These are fixed in fact */
-#define CS_FMT_STEREO 2
-#define CS_FMT_MASK 3
-
-#define CS_TYPE_ADC 1
-#define CS_TYPE_DAC 2
-
-#define CS_TRUE 1
-#define CS_FALSE 0
-
-#define CS_INC_USE_COUNT(m) (atomic_inc(m))
-#define CS_DEC_USE_COUNT(m) (atomic_dec(m))
-#define CS_DEC_AND_TEST(m) (atomic_dec_and_test(m))
-#define CS_IN_USE(m) (atomic_read(m) != 0)
-
-#define CS_DBGBREAKPOINT {__asm__("INT $3");}
-/*
- * CS461x definitions
- */
-
-#define CS461X_BA0_SIZE 0x2000
-#define CS461X_BA1_DATA0_SIZE 0x3000
-#define CS461X_BA1_DATA1_SIZE 0x3800
-#define CS461X_BA1_PRG_SIZE 0x7000
-#define CS461X_BA1_REG_SIZE 0x0100
-
-#define GOF_PER_SEC 200
-
-#define CSDEBUG_INTERFACE 1
-#define CSDEBUG 1
-/*
- * Turn on/off debugging compilation by using 1/0 respectively for CSDEBUG
- *
- *
- * CSDEBUG is usual mode is set to 1, then use the
- * cs_debuglevel and cs_debugmask to turn on or off debugging.
- * Debug level of 1 has been defined to be kernel errors and info
- * that should be printed on any released driver.
- */
-#if CSDEBUG
-#define CS_DBGOUT(mask,level,x) if ((cs_debuglevel >= (level)) && ((mask) & cs_debugmask)) {x;}
-#else
-#define CS_DBGOUT(mask,level,x)
-#endif
-/*
- * cs_debugmask areas
- */
-#define CS_INIT 0x00000001 /* initialization and probe functions */
-#define CS_ERROR 0x00000002 /* tmp debugging bit placeholder */
-#define CS_INTERRUPT 0x00000004 /* interrupt handler (separate from all other) */
-#define CS_FUNCTION 0x00000008 /* enter/leave functions */
-#define CS_WAVE_WRITE 0x00000010 /* write information for wave */
-#define CS_WAVE_READ 0x00000020 /* read information for wave */
-#define CS_MIDI_WRITE 0x00000040 /* write information for midi */
-#define CS_MIDI_READ 0x00000080 /* read information for midi */
-#define CS_MPU401_WRITE 0x00000100 /* write information for mpu401 */
-#define CS_MPU401_READ 0x00000200 /* read information for mpu401 */
-#define CS_OPEN 0x00000400 /* all open functions in the driver */
-#define CS_RELEASE 0x00000800 /* all release functions in the driver */
-#define CS_PARMS 0x00001000 /* functional and operational parameters */
-#define CS_IOCTL 0x00002000 /* ioctl (non-mixer) */
-#define CS_PM 0x00004000 /* PM */
-#define CS_TMP 0x10000000 /* tmp debug mask bit */
-
-#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend
-#define CS_IOCTL_CMD_RESUME 0x2 // resume
-
-#if CSDEBUG
-static unsigned long cs_debuglevel = 1; /* levels range from 1-9 */
-module_param(cs_debuglevel, ulong, 0644);
-static unsigned long cs_debugmask = CS_INIT | CS_ERROR; /* use CS_DBGOUT with various mask values */
-module_param(cs_debugmask, ulong, 0644);
-#endif
-static unsigned long hercules_egpio_disable; /* if non-zero set all EGPIO to 0 */
-module_param(hercules_egpio_disable, ulong, 0);
-static unsigned long initdelay = 700; /* PM delay in millisecs */
-module_param(initdelay, ulong, 0);
-static unsigned long powerdown = -1; /* turn on/off powerdown processing in driver */
-module_param(powerdown, ulong, 0);
-#define DMABUF_DEFAULTORDER 3
-static unsigned long defaultorder = DMABUF_DEFAULTORDER;
-module_param(defaultorder, ulong, 0);
-
-static int external_amp;
-module_param(external_amp, bool, 0);
-static int thinkpad;
-module_param(thinkpad, bool, 0);
-
-/*
-* set the powerdown module parm to 0 to disable all
-* powerdown. also set thinkpad to 1 to disable powerdown,
-* but also to enable the clkrun functionality.
-*/
-static unsigned cs_powerdown = 1;
-static unsigned cs_laptop_wait = 1;
-
-/* An instance of the 4610 channel */
-struct cs_channel
-{
- int used;
- int num;
- void *state;
-};
-
-#define CS46XX_MAJOR_VERSION "1"
-#define CS46XX_MINOR_VERSION "28"
-
-#ifdef __ia64__
-#define CS46XX_ARCH "64" //architecture key
-#else
-#define CS46XX_ARCH "32" //architecture key
-#endif
-
-static struct list_head cs46xx_devs = { &cs46xx_devs, &cs46xx_devs };
-
-/* magic numbers to protect our data structures */
-#define CS_CARD_MAGIC 0x43525553 /* "CRUS" */
-#define CS_STATE_MAGIC 0x4c4f4749 /* "LOGI" */
-#define NR_HW_CH 3
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 2
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct cs_state {
- unsigned int magic;
- struct cs_card *card; /* Card info */
-
- /* single open lock mechanism, only used for recording */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
-
- /* file mode */
- mode_t open_mode;
-
- /* virtual channel number */
- int virt;
-
- struct dmabuf {
- /* wave sample stuff */
- unsigned int rate;
- unsigned char fmt, enable;
-
- /* hardware channel */
- struct cs_channel *channel;
- int pringbuf; /* Software ring slot */
- void *pbuf; /* 4K hardware DMA buffer */
-
- /* OSS buffer management stuff */
- void *rawbuf;
- dma_addr_t dma_handle;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- unsigned divisor;
- unsigned type;
- void *tmpbuff; /* tmp buffer for sample conversions */
- dma_addr_t dmaaddr;
- dma_addr_t dmaaddr_tmpbuff;
- unsigned buforder_tmpbuff; /* Log base 2 of size in bytes.. */
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started, updated by update_ptr */
- unsigned swptr; /* where driver last clear/filled, updated by read/write */
- int count; /* bytes to be comsumed or been generated by dma machine */
- unsigned total_bytes; /* total bytes dmaed by hardware */
- unsigned blocks; /* total blocks */
-
- unsigned error; /* number of over/underruns */
- unsigned underrun; /* underrun pending before next write has occurred */
- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned SGok:1;
- unsigned update_flag;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dmabuf;
- /* Guard against mmap/write/read races */
- struct mutex sem;
-};
-
-struct cs_card {
- struct cs_channel channel[2];
- unsigned int magic;
-
- /* We keep cs461x cards in a linked list */
- struct cs_card *next;
-
- /* The cs461x has a certain amount of cross channel interaction
- so we use a single per card lock */
- spinlock_t lock;
-
- /* Keep AC97 sane */
- spinlock_t ac97_lock;
-
- /* mixer use count */
- atomic_t mixer_use_cnt;
-
- /* PCI device stuff */
- struct pci_dev *pci_dev;
- struct list_head list;
-
- unsigned int pctl, cctl; /* Hardware DMA flag sets */
-
- /* soundcore stuff */
- int dev_audio;
- int dev_midi;
-
- /* structures for abstraction of hardware facilities, codecs, banks and channels*/
- struct ac97_codec *ac97_codec[NR_AC97];
- struct cs_state *states[2];
-
- u16 ac97_features;
-
- int amplifier; /* Amplifier control */
- void (*amplifier_ctrl)(struct cs_card *, int);
- void (*amp_init)(struct cs_card *);
-
- int active; /* Active clocking */
- void (*active_ctrl)(struct cs_card *, int);
-
- /* hardware resources */
- unsigned long ba0_addr;
- unsigned long ba1_addr;
- u32 irq;
-
- /* mappings */
- void __iomem *ba0;
- union
- {
- struct
- {
- u8 __iomem *data0;
- u8 __iomem *data1;
- u8 __iomem *pmem;
- u8 __iomem *reg;
- } name;
- u8 __iomem *idx[4];
- } ba1;
-
- /* Function support */
- struct cs_channel *(*alloc_pcm_channel)(struct cs_card *);
- struct cs_channel *(*alloc_rec_pcm_channel)(struct cs_card *);
- void (*free_pcm_channel)(struct cs_card *, int chan);
-
- /* /dev/midi stuff */
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t open_wait;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- spinlock_t lock;
- unsigned char ibuf[CS_MIDIINBUF];
- unsigned char obuf[CS_MIDIOUTBUF];
- mode_t open_mode;
- struct mutex open_mutex;
- } midi;
- struct cs46xx_pm pm;
-};
-
-static int cs_open_mixdev(struct inode *inode, struct file *file);
-static int cs_release_mixdev(struct inode *inode, struct file *file);
-static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg);
-static int cs_hardware_init(struct cs_card *card);
-static int cs46xx_powerup(struct cs_card *card, unsigned int type);
-static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
-static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
-#ifdef CONFIG_PM
-static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
-static int cs46xx_resume_tbl(struct pci_dev *pcidev);
-#endif
-
-#if CSDEBUG
-
-/* DEBUG ROUTINES */
-
-#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
-#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
-#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
-#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
-#define SOUND_MIXER_CS_APM _SIOWR('M',124, int)
-
-static void printioctl(unsigned int x)
-{
- unsigned int i;
- unsigned char vidx;
- /* these values are incorrect for the ac97 driver, fix.
- * Index of mixtable1[] member is Device ID
- * and must be <= SOUND_MIXER_NRDEVICES.
- * Value of array member is index into s->mix.vol[]
- */
- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, /* voice */
- [SOUND_MIXER_LINE1] = 2, /* AUX */
- [SOUND_MIXER_CD] = 3, /* CD */
- [SOUND_MIXER_LINE] = 4, /* Line */
- [SOUND_MIXER_SYNTH] = 5, /* FM */
- [SOUND_MIXER_MIC] = 6, /* Mic */
- [SOUND_MIXER_SPEAKER] = 7, /* Speaker */
- [SOUND_MIXER_RECLEV] = 8, /* Recording level */
- [SOUND_MIXER_VOLUME] = 9 /* Master Volume */
- };
-
- switch (x) {
- case SOUND_MIXER_CS_GETDBGMASK:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGMASK: ") );
- break;
- case SOUND_MIXER_CS_GETDBGLEVEL:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGLEVEL: ") );
- break;
- case SOUND_MIXER_CS_SETDBGMASK:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGMASK: ") );
- break;
- case SOUND_MIXER_CS_SETDBGLEVEL:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGLEVEL: ") );
- break;
- case OSS_GETVERSION:
- CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION: ") );
- break;
- case SNDCTL_DSP_SYNC:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC: ") );
- break;
- case SNDCTL_DSP_SETDUPLEX:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX: ") );
- break;
- case SNDCTL_DSP_GETCAPS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS: ") );
- break;
- case SNDCTL_DSP_RESET:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET: ") );
- break;
- case SNDCTL_DSP_SPEED:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED: ") );
- break;
- case SNDCTL_DSP_STEREO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO: ") );
- break;
- case SNDCTL_DSP_CHANNELS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS: ") );
- break;
- case SNDCTL_DSP_GETFMTS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS: ") );
- break;
- case SNDCTL_DSP_SETFMT:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT: ") );
- break;
- case SNDCTL_DSP_POST:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST: ") );
- break;
- case SNDCTL_DSP_GETTRIGGER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER: ") );
- break;
- case SNDCTL_DSP_SETTRIGGER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER: ") );
- break;
- case SNDCTL_DSP_GETOSPACE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE: ") );
- break;
- case SNDCTL_DSP_GETISPACE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE: ") );
- break;
- case SNDCTL_DSP_NONBLOCK:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK: ") );
- break;
- case SNDCTL_DSP_GETODELAY:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY: ") );
- break;
- case SNDCTL_DSP_GETIPTR:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR: ") );
- break;
- case SNDCTL_DSP_GETOPTR:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR: ") );
- break;
- case SNDCTL_DSP_GETBLKSIZE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE: ") );
- break;
- case SNDCTL_DSP_SETFRAGMENT:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFRAGMENT: ") );
- break;
- case SNDCTL_DSP_SUBDIVIDE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE: ") );
- break;
- case SOUND_PCM_READ_RATE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE: ") );
- break;
- case SOUND_PCM_READ_CHANNELS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_CHANNELS: ") );
- break;
- case SOUND_PCM_READ_BITS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS: ") );
- break;
- case SOUND_PCM_WRITE_FILTER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_WRITE_FILTER: ") );
- break;
- case SNDCTL_DSP_SETSYNCRO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO: ") );
- break;
- case SOUND_PCM_READ_FILTER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") );
- break;
- case SOUND_MIXER_PRIVATE1:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") );
- break;
- case SOUND_MIXER_PRIVATE2:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2: ") );
- break;
- case SOUND_MIXER_PRIVATE3:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3: ") );
- break;
- case SOUND_MIXER_PRIVATE4:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4: ") );
- break;
- case SOUND_MIXER_PRIVATE5:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5: ") );
- break;
- case SOUND_MIXER_INFO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO: ") );
- break;
- case SOUND_OLD_MIXER_INFO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO: ") );
- break;
- default:
- switch (_IOC_NR(x)) {
- case SOUND_MIXER_VOLUME:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_VOLUME: ") );
- break;
- case SOUND_MIXER_SPEAKER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SPEAKER: ") );
- break;
- case SOUND_MIXER_RECLEV:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECLEV: ") );
- break;
- case SOUND_MIXER_MIC:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_MIC: ") );
- break;
- case SOUND_MIXER_SYNTH:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SYNTH: ") );
- break;
- case SOUND_MIXER_RECSRC:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECSRC: ") );
- break;
- case SOUND_MIXER_DEVMASK:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_DEVMASK: ") );
- break;
- case SOUND_MIXER_RECMASK:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECMASK: ") );
- break;
- case SOUND_MIXER_STEREODEVS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_STEREODEVS: ") );
- break;
- case SOUND_MIXER_CAPS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:") );
- break;
- default:
- i = _IOC_NR(x);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) {
- CS_DBGOUT(CS_IOCTL, 4, printk("UNKNOWN IOCTL: 0x%.8x NR=%d ",x,i) );
- } else {
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d ",
- x,i));
- }
- break;
- }
- }
- CS_DBGOUT(CS_IOCTL, 4, printk("command = 0x%x IOC_NR=%d\n",x, _IOC_NR(x)) );
-}
-#endif
-
-/*
- * common I/O routines
- */
-
-static void cs461x_poke(struct cs_card *codec, unsigned long reg, unsigned int val)
-{
- writel(val, codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
-}
-
-static unsigned int cs461x_peek(struct cs_card *codec, unsigned long reg)
-{
- return readl(codec->ba1.idx[(reg >> 16) & 3] + (reg & 0xffff));
-}
-
-static void cs461x_pokeBA0(struct cs_card *codec, unsigned long reg, unsigned int val)
-{
- writel(val, codec->ba0 + reg);
-}
-
-static unsigned int cs461x_peekBA0(struct cs_card *codec, unsigned long reg)
-{
- return readl(codec->ba0 + reg);
-}
-
-
-static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg);
-static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct cs_channel *cs_alloc_pcm_channel(struct cs_card *card)
-{
- if (card->channel[1].used == 1)
- return NULL;
- card->channel[1].used = 1;
- card->channel[1].num = 1;
- return &card->channel[1];
-}
-
-static struct cs_channel *cs_alloc_rec_pcm_channel(struct cs_card *card)
-{
- if (card->channel[0].used == 1)
- return NULL;
- card->channel[0].used = 1;
- card->channel[0].num = 0;
- return &card->channel[0];
-}
-
-static void cs_free_pcm_channel(struct cs_card *card, int channel)
-{
- card->channel[channel].state = NULL;
- card->channel[channel].used = 0;
-}
-
-/*
- * setup a divisor value to help with conversion from
- * 16bit Stereo, down to 8bit stereo/mono or 16bit mono.
- * assign a divisor of 1 if using 16bit Stereo as that is
- * the only format that the static image will capture.
- */
-static void cs_set_divisor(struct dmabuf *dmabuf)
-{
- if (dmabuf->type == CS_TYPE_DAC)
- dmabuf->divisor = 1;
- else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
- (dmabuf->fmt & CS_FMT_16BIT))
- dmabuf->divisor = 2;
- else if ((dmabuf->fmt & CS_FMT_STEREO) &&
- !(dmabuf->fmt & CS_FMT_16BIT))
- dmabuf->divisor = 2;
- else if (!(dmabuf->fmt & CS_FMT_STEREO) &&
- !(dmabuf->fmt & CS_FMT_16BIT))
- dmabuf->divisor = 4;
- else
- dmabuf->divisor = 1;
-
- CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8, printk(
- "cs46xx: cs_set_divisor()- %s %d\n",
- (dmabuf->type == CS_TYPE_ADC) ? "ADC" : "DAC",
- dmabuf->divisor) );
-}
-
-/*
-* mute some of the more prevalent registers to avoid popping.
-*/
-static void cs_mute(struct cs_card *card, int state)
-{
- struct ac97_codec *dev = card->ac97_codec[0];
-
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()+ %s\n",
- (state == CS_TRUE) ? "Muting" : "UnMuting"));
-
- if (state == CS_TRUE) {
- /*
- * fix pops when powering up on thinkpads
- */
- card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
- (u8)BA0_AC97_MASTER_VOLUME);
- card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
- (u8)BA0_AC97_HEADPHONE_VOLUME);
- card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
- (u8)BA0_AC97_MASTER_VOLUME_MONO);
- card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
- (u8)BA0_AC97_PCM_OUT_VOLUME);
-
- cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
- cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
- cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
- cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
- } else {
- cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, card->pm.u32AC97_master_volume);
- cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, card->pm.u32AC97_headphone_volume);
- cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, card->pm.u32AC97_master_volume_mono);
- cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, card->pm.u32AC97_pcm_out_volume);
- }
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: cs_mute()-\n"));
-}
-
-/* set playback sample rate */
-static unsigned int cs_set_dac_rate(struct cs_state * state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int tmp1, tmp2;
- unsigned int phiIncr;
- unsigned int correctionPerGOF, correctionPerSec;
- unsigned long flags;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()+ %d\n",rate) );
-
- /*
- * Compute the values used to drive the actual sample rate conversion.
- * The following formulas are being computed, using inline assembly
- * since we need to use 64 bit arithmetic to compute the values:
- *
- * phiIncr = floor((Fs,in * 2^26) / Fs,out)
- * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
- * GOF_PER_SEC)
- * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
- * GOF_PER_SEC * correctionPerGOF
- *
- * i.e.
- *
- * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
- * correctionPerGOF:correctionPerSec =
- * dividend:remainder(ulOther / GOF_PER_SEC)
- */
- tmp1 = rate << 16;
- phiIncr = tmp1 / 48000;
- tmp1 -= phiIncr * 48000;
- tmp1 <<= 10;
- phiIncr <<= 10;
- tmp2 = tmp1 / 48000;
- phiIncr += tmp2;
- tmp1 -= tmp2 * 48000;
- correctionPerGOF = tmp1 / GOF_PER_SEC;
- tmp1 -= correctionPerGOF * GOF_PER_SEC;
- correctionPerSec = tmp1;
-
- /*
- * Fill in the SampleRateConverter control block.
- */
- spin_lock_irqsave(&state->card->lock, flags);
- cs461x_poke(state->card, BA1_PSRC,
- ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
- cs461x_poke(state->card, BA1_PPI, phiIncr);
- spin_unlock_irqrestore(&state->card->lock, flags);
- dmabuf->rate = rate;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_dac_rate()- %d\n",rate) );
- return rate;
-}
-
-/* set recording sample rate */
-static unsigned int cs_set_adc_rate(struct cs_state *state, unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct cs_card *card = state->card;
- unsigned int phiIncr, coeffIncr, tmp1, tmp2;
- unsigned int correctionPerGOF, correctionPerSec, initialDelay;
- unsigned int frameGroupLength, cnt;
- unsigned long flags;
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()+ %d\n",rate) );
-
- /*
- * We can only decimate by up to a factor of 1/9th the hardware rate.
- * Correct the value if an attempt is made to stray outside that limit.
- */
- if ((rate * 9) < 48000)
- rate = 48000 / 9;
-
- /*
- * We cannot capture at at rate greater than the Input Rate (48000).
- * Return an error if an attempt is made to stray outside that limit.
- */
- if (rate > 48000)
- rate = 48000;
-
- /*
- * Compute the values used to drive the actual sample rate conversion.
- * The following formulas are being computed, using inline assembly
- * since we need to use 64 bit arithmetic to compute the values:
- *
- * coeffIncr = -floor((Fs,out * 2^23) / Fs,in)
- * phiIncr = floor((Fs,in * 2^26) / Fs,out)
- * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
- * GOF_PER_SEC)
- * correctionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -
- * GOF_PER_SEC * correctionPerGOF
- * initialDelay = ceil((24 * Fs,in) / Fs,out)
- *
- * i.e.
- *
- * coeffIncr = neg(dividend((Fs,out * 2^23) / Fs,in))
- * phiIncr:ulOther = dividend:remainder((Fs,in * 2^26) / Fs,out)
- * correctionPerGOF:correctionPerSec =
- * dividend:remainder(ulOther / GOF_PER_SEC)
- * initialDelay = dividend(((24 * Fs,in) + Fs,out - 1) / Fs,out)
- */
- tmp1 = rate << 16;
- coeffIncr = tmp1 / 48000;
- tmp1 -= coeffIncr * 48000;
- tmp1 <<= 7;
- coeffIncr <<= 7;
- coeffIncr += tmp1 / 48000;
- coeffIncr ^= 0xFFFFFFFF;
- coeffIncr++;
- tmp1 = 48000 << 16;
- phiIncr = tmp1 / rate;
- tmp1 -= phiIncr * rate;
- tmp1 <<= 10;
- phiIncr <<= 10;
- tmp2 = tmp1 / rate;
- phiIncr += tmp2;
- tmp1 -= tmp2 * rate;
- correctionPerGOF = tmp1 / GOF_PER_SEC;
- tmp1 -= correctionPerGOF * GOF_PER_SEC;
- correctionPerSec = tmp1;
- initialDelay = ((48000 * 24) + rate - 1) / rate;
-
- /*
- * Fill in the VariDecimate control block.
- */
- spin_lock_irqsave(&card->lock, flags);
- cs461x_poke(card, BA1_CSRC,
- ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
- cs461x_poke(card, BA1_CCI, coeffIncr);
- cs461x_poke(card, BA1_CD,
- (((BA1_VARIDEC_BUF_1 + (initialDelay << 2)) << 16) & 0xFFFF0000) | 0x80);
- cs461x_poke(card, BA1_CPI, phiIncr);
- spin_unlock_irqrestore(&card->lock, flags);
-
- /*
- * Figure out the frame group length for the write back task. Basically,
- * this is just the factors of 24000 (2^6*3*5^3) that are not present in
- * the output sample rate.
- */
- frameGroupLength = 1;
- for (cnt = 2; cnt <= 64; cnt *= 2) {
- if (((rate / cnt) * cnt) != rate)
- frameGroupLength *= 2;
- }
- if (((rate / 3) * 3) != rate) {
- frameGroupLength *= 3;
- }
- for (cnt = 5; cnt <= 125; cnt *= 5) {
- if (((rate / cnt) * cnt) != rate)
- frameGroupLength *= 5;
- }
-
- /*
- * Fill in the WriteBack control block.
- */
- spin_lock_irqsave(&card->lock, flags);
- cs461x_poke(card, BA1_CFG1, frameGroupLength);
- cs461x_poke(card, BA1_CFG2, (0x00800000 | frameGroupLength));
- cs461x_poke(card, BA1_CCST, 0x0000FFFF);
- cs461x_poke(card, BA1_CSPB, ((65536 * rate) / 24000));
- cs461x_poke(card, (BA1_CSPB + 4), 0x0000FFFF);
- spin_unlock_irqrestore(&card->lock, flags);
- dmabuf->rate = rate;
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_set_adc_rate()- %d\n",rate) );
- return rate;
-}
-
-/* prepare channel attributes for playback */
-static void cs_play_setup(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct cs_card *card = state->card;
- unsigned int tmp, Count, playFormat;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()+\n") );
- cs461x_poke(card, BA1_PVOL, 0x80008000);
- if (!dmabuf->SGok)
- cs461x_poke(card, BA1_PBA, virt_to_bus(dmabuf->pbuf));
-
- Count = 4;
- playFormat=cs461x_peek(card, BA1_PFIE);
- if ((dmabuf->fmt & CS_FMT_STEREO)) {
- playFormat &= ~DMA_RQ_C2_AC_MONO_TO_STEREO;
- Count *= 2;
- } else
- playFormat |= DMA_RQ_C2_AC_MONO_TO_STEREO;
-
- if ((dmabuf->fmt & CS_FMT_16BIT)) {
- playFormat &= ~(DMA_RQ_C2_AC_8_TO_16_BIT
- | DMA_RQ_C2_AC_SIGNED_CONVERT);
- Count *= 2;
- } else
- playFormat |= (DMA_RQ_C2_AC_8_TO_16_BIT
- | DMA_RQ_C2_AC_SIGNED_CONVERT);
-
- cs461x_poke(card, BA1_PFIE, playFormat);
-
- tmp = cs461x_peek(card, BA1_PDTC);
- tmp &= 0xfffffe00;
- cs461x_poke(card, BA1_PDTC, tmp | --Count);
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_play_setup()-\n") );
-}
-
-static struct InitStruct
-{
- u32 off;
- u32 val;
-} InitArray[] = { {0x00000040, 0x3fc0000f},
- {0x0000004c, 0x04800000},
-
- {0x000000b3, 0x00000780},
- {0x000000b7, 0x00000000},
- {0x000000bc, 0x07800000},
-
- {0x000000cd, 0x00800000},
- };
-
-/*
- * "SetCaptureSPValues()" -- Initialize record task values before each
- * capture startup.
- */
-static void SetCaptureSPValues(struct cs_card *card)
-{
- unsigned i, offset;
- CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()+\n") );
- for (i = 0; i < sizeof(InitArray) / sizeof(struct InitStruct); i++) {
- offset = InitArray[i].off*4; /* 8bit to 32bit offset value */
- cs461x_poke(card, offset, InitArray[i].val );
- }
- CS_DBGOUT(CS_FUNCTION, 8, printk("cs46xx: SetCaptureSPValues()-\n") );
-}
-
-/* prepare channel attributes for recording */
-static void cs_rec_setup(struct cs_state *state)
-{
- struct cs_card *card = state->card;
- struct dmabuf *dmabuf = &state->dmabuf;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()+\n"));
- SetCaptureSPValues(card);
-
- /*
- * set the attenuation to 0dB
- */
- cs461x_poke(card, BA1_CVOL, 0x80008000);
-
- /*
- * set the physical address of the capture buffer into the SP
- */
- cs461x_poke(card, BA1_CBA, virt_to_bus(dmabuf->rawbuf));
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_rec_setup()-\n") );
-}
-
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
- called with spinlock held! */
-
-static inline unsigned cs_get_dma_addr(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 offset;
-
- if ( (!(dmabuf->enable & DAC_RUNNING)) &&
- (!(dmabuf->enable & ADC_RUNNING) ) )
- {
- CS_DBGOUT(CS_ERROR, 2, printk(
- "cs46xx: ERROR cs_get_dma_addr(): not enabled \n") );
- return 0;
- }
-
- /*
- * granularity is byte boundary, good part.
- */
- if (dmabuf->enable & DAC_RUNNING)
- offset = cs461x_peek(state->card, BA1_PBA);
- else /* ADC_RUNNING must be set */
- offset = cs461x_peek(state->card, BA1_CBA);
-
- CS_DBGOUT(CS_PARMS | CS_FUNCTION, 9,
- printk("cs46xx: cs_get_dma_addr() %d\n",offset) );
- offset = (u32)bus_to_virt((unsigned long)offset) - (u32)dmabuf->rawbuf;
- CS_DBGOUT(CS_PARMS | CS_FUNCTION, 8,
- printk("cs46xx: cs_get_dma_addr()- %d\n",offset) );
- return offset;
-}
-
-static void resync_dma_ptrs(struct cs_state *state)
-{
- struct dmabuf *dmabuf;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()+ \n") );
- if (state) {
- dmabuf = &state->dmabuf;
- dmabuf->hwptr=dmabuf->swptr = 0;
- dmabuf->pringbuf = 0;
- }
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: resync_dma_ptrs()- \n") );
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct cs_card *card = state->card;
- unsigned int tmp;
-
- dmabuf->enable &= ~ADC_RUNNING;
-
- tmp = cs461x_peek(card, BA1_CCTL);
- tmp &= 0xFFFF0000;
- cs461x_poke(card, BA1_CCTL, tmp );
-}
-
-static void stop_adc(struct cs_state *state)
-{
- unsigned long flags;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()+ \n") );
- spin_lock_irqsave(&state->card->lock, flags);
- __stop_adc(state);
- spin_unlock_irqrestore(&state->card->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_adc()- \n") );
-}
-
-static void start_adc(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct cs_card *card = state->card;
- unsigned long flags;
- unsigned int tmp;
-
- spin_lock_irqsave(&card->lock, flags);
- if (!(dmabuf->enable & ADC_RUNNING) &&
- ((dmabuf->mapped || dmabuf->count < (signed)dmabuf->dmasize)
- && dmabuf->ready) &&
- ((card->pm.flags & CS46XX_PM_IDLE) ||
- (card->pm.flags & CS46XX_PM_RESUMED)) )
- {
- dmabuf->enable |= ADC_RUNNING;
- cs_set_divisor(dmabuf);
- tmp = cs461x_peek(card, BA1_CCTL);
- tmp &= 0xFFFF0000;
- tmp |= card->cctl;
- CS_DBGOUT(CS_FUNCTION, 2, printk(
- "cs46xx: start_adc() poke 0x%x \n",tmp) );
- cs461x_poke(card, BA1_CCTL, tmp);
- }
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct cs_card *card = state->card;
- unsigned int tmp;
-
- dmabuf->enable &= ~DAC_RUNNING;
-
- tmp=cs461x_peek(card, BA1_PCTL);
- tmp&=0xFFFF;
- cs461x_poke(card, BA1_PCTL, tmp);
-}
-
-static void stop_dac(struct cs_state *state)
-{
- unsigned long flags;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()+ \n") );
- spin_lock_irqsave(&state->card->lock, flags);
- __stop_dac(state);
- spin_unlock_irqrestore(&state->card->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: stop_dac()- \n") );
-}
-
-static void start_dac(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct cs_card *card = state->card;
- unsigned long flags;
- int tmp;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()+ \n") );
- spin_lock_irqsave(&card->lock, flags);
- if (!(dmabuf->enable & DAC_RUNNING) &&
- ((dmabuf->mapped || dmabuf->count > 0) && dmabuf->ready) &&
- ((card->pm.flags & CS46XX_PM_IDLE) ||
- (card->pm.flags & CS46XX_PM_RESUMED)) )
- {
- dmabuf->enable |= DAC_RUNNING;
- tmp = cs461x_peek(card, BA1_PCTL);
- tmp &= 0xFFFF;
- tmp |= card->pctl;
- CS_DBGOUT(CS_PARMS, 6, printk(
- "cs46xx: start_dac() poke card=%p tmp=0x%.08x addr=%p \n",
- card, (unsigned)tmp,
- card->ba1.idx[(BA1_PCTL >> 16) & 3]+(BA1_PCTL&0xffff) ) );
- cs461x_poke(card, BA1_PCTL, tmp);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: start_dac()- \n") );
-}
-
-#define DMABUF_MINORDER 1
-
-/*
- * allocate DMA buffer, playback and recording buffers are separate.
- */
-static int alloc_dmabuf(struct cs_state *state)
-{
-
- struct cs_card *card=state->card;
- struct dmabuf *dmabuf = &state->dmabuf;
- void *rawbuf = NULL;
- void *tmpbuff = NULL;
- int order;
- struct page *map, *mapend;
- unsigned long df;
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->SGok = 0;
-/*
-* check for order within limits, but do not overwrite value.
-*/
- if ((defaultorder > 1) && (defaultorder < 12))
- df = defaultorder;
- else
- df = 2;
-
- for (order = df; order >= DMABUF_MINORDER; order--)
- if ((rawbuf = (void *)pci_alloc_consistent(
- card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr)))
- break;
- if (!rawbuf) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs46xx: alloc_dmabuf(): unable to allocate rawbuf\n"));
- return -ENOMEM;
- }
- dmabuf->buforder = order;
- dmabuf->rawbuf = rawbuf;
- // Now mark the pages as reserved; otherwise the
- // remap_pfn_range() in cs46xx_mmap doesn't work.
- // 1. get index to last page in mem_map array for rawbuf.
- mapend = virt_to_page(dmabuf->rawbuf +
- (PAGE_SIZE << dmabuf->buforder) - 1);
-
- // 2. mark each physical page in range as 'reserved'.
- for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
- cs4x_mem_map_reserve(map);
-
- CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: alloc_dmabuf(): allocated %ld (order = %d) bytes at %p\n",
- PAGE_SIZE << order, order, rawbuf) );
-
-/*
-* only allocate the conversion buffer for the ADC
-*/
- if (dmabuf->type == CS_TYPE_DAC) {
- dmabuf->tmpbuff = NULL;
- dmabuf->buforder_tmpbuff = 0;
- return 0;
- }
-/*
- * now the temp buffer for 16/8 conversions
- */
-
- tmpbuff = (void *) pci_alloc_consistent(
- card->pci_dev, PAGE_SIZE << order, &dmabuf->dmaaddr_tmpbuff);
-
- if (!tmpbuff)
- return -ENOMEM;
- CS_DBGOUT(CS_PARMS, 9, printk("cs46xx: allocated %ld (order = %d) bytes at %p\n",
- PAGE_SIZE << order, order, tmpbuff) );
-
- dmabuf->tmpbuff = tmpbuff;
- dmabuf->buforder_tmpbuff = order;
-
- // Now mark the pages as reserved; otherwise the
- // remap_pfn_range() in cs46xx_mmap doesn't work.
- // 1. get index to last page in mem_map array for rawbuf.
- mapend = virt_to_page(dmabuf->tmpbuff +
- (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
-
- // 2. mark each physical page in range as 'reserved'.
- for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
- cs4x_mem_map_reserve(map);
- return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct page *map, *mapend;
-
- if (dmabuf->rawbuf) {
- // Undo prog_dmabuf()'s marking the pages as reserved
- mapend = virt_to_page(dmabuf->rawbuf +
- (PAGE_SIZE << dmabuf->buforder) - 1);
- for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
- cs4x_mem_map_unreserve(map);
- free_dmabuf(state->card, dmabuf);
- }
-
- if (dmabuf->tmpbuff) {
- // Undo prog_dmabuf()'s marking the pages as reserved
- mapend = virt_to_page(dmabuf->tmpbuff +
- (PAGE_SIZE << dmabuf->buforder_tmpbuff) - 1);
- for (map = virt_to_page(dmabuf->tmpbuff); map <= mapend; map++)
- cs4x_mem_map_unreserve(map);
- free_dmabuf2(state->card, dmabuf);
- }
-
- dmabuf->rawbuf = NULL;
- dmabuf->tmpbuff = NULL;
- dmabuf->mapped = dmabuf->ready = 0;
- dmabuf->SGok = 0;
-}
-
-static int __prog_dmabuf(struct cs_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned long allocated_pages, allocated_bytes;
- unsigned long tmp1, tmp2, fmt=0;
- unsigned long *ptmp = (unsigned long *) dmabuf->pbuf;
- unsigned long SGarray[9], nSGpages=0;
- int ret;
-
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()+ \n"));
-/*
- * check for CAPTURE and use only non-sg for initial release
- */
- if (dmabuf->type == CS_TYPE_ADC) {
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() ADC\n"));
- /*
- * add in non-sg support for capture.
- */
- spin_lock_irqsave(&state->card->lock, flags);
- /* add code to reset the rawbuf memory. TRW */
- resync_dma_ptrs(state);
- dmabuf->total_bytes = dmabuf->blocks = 0;
- dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
-
- dmabuf->SGok = 0;
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* allocate DMA buffer if not allocated yet */
- if (!dmabuf->rawbuf || !dmabuf->tmpbuff)
- if ((ret = alloc_dmabuf(state)))
- return ret;
- /*
- * static image only supports 16Bit signed, stereo - hard code fmt
- */
- fmt = CS_FMT_16BIT | CS_FMT_STEREO;
-
- dmabuf->numfrag = 2;
- dmabuf->fragsize = 2048;
- dmabuf->fragsamples = 2048 >> sample_shift[fmt];
- dmabuf->dmasize = 4096;
- dmabuf->fragshift = 11;
-
- memset(dmabuf->rawbuf, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
- dmabuf->dmasize);
- memset(dmabuf->tmpbuff, (fmt & CS_FMT_16BIT) ? 0 : 0x80,
- PAGE_SIZE<<dmabuf->buforder_tmpbuff);
-
- /*
- * Now set up the ring
- */
-
- spin_lock_irqsave(&state->card->lock, flags);
- cs_rec_setup(state);
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
-
- CS_DBGOUT(CS_PARMS, 4, printk(
- "cs46xx: prog_dmabuf(): CAPTURE rate=%d fmt=0x%x numfrag=%d "
- "fragsize=%d dmasize=%d\n",
- dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
- dmabuf->fragsize, dmabuf->dmasize) );
-
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- 0 \n"));
- return 0;
- } else if (dmabuf->type == CS_TYPE_DAC) {
- /*
- * Must be DAC
- */
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf() DAC\n"));
- spin_lock_irqsave(&state->card->lock, flags);
- resync_dma_ptrs(state);
- dmabuf->total_bytes = dmabuf->blocks = 0;
- dmabuf->count = dmabuf->error = dmabuf->underrun = 0;
-
- dmabuf->SGok = 0;
-
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* allocate DMA buffer if not allocated yet */
- if (!dmabuf->rawbuf)
- if ((ret = alloc_dmabuf(state)))
- return ret;
-
- allocated_pages = 1 << dmabuf->buforder;
- allocated_bytes = allocated_pages*PAGE_SIZE;
-
- if (allocated_pages < 2) {
- CS_DBGOUT(CS_FUNCTION, 4, printk(
- "cs46xx: prog_dmabuf() Error: allocated_pages too small (%d)\n",
- (unsigned)allocated_pages));
- return -ENOMEM;
- }
-
- /* Use all the pages allocated, fragsize 4k. */
- /* Use 'pbuf' for S/G page map table. */
- dmabuf->SGok = 1; /* Use S/G. */
-
- nSGpages = allocated_bytes/4096; /* S/G pages always 4k. */
-
- /* Set up S/G variables. */
- *ptmp = virt_to_bus(dmabuf->rawbuf);
- *(ptmp + 1) = 0x00000008;
- for (tmp1 = 1; tmp1 < nSGpages; tmp1++) {
- *(ptmp + 2 * tmp1) = virt_to_bus((dmabuf->rawbuf) + 4096 * tmp1);
- if (tmp1 == nSGpages - 1)
- tmp2 = 0xbfff0000;
- else
- tmp2 = 0x80000000 + 8 * (tmp1 + 1);
- *(ptmp + 2 * tmp1 + 1) = tmp2;
- }
- SGarray[0] = 0x82c0200d;
- SGarray[1] = 0xffff0000;
- SGarray[2] = *ptmp;
- SGarray[3] = 0x00010600;
- SGarray[4] = *(ptmp+2);
- SGarray[5] = 0x80000010;
- SGarray[6] = *ptmp;
- SGarray[7] = *(ptmp+2);
- SGarray[8] = (virt_to_bus(dmabuf->pbuf) & 0xffff000) | 0x10;
-
- if (dmabuf->SGok) {
- dmabuf->numfrag = nSGpages;
- dmabuf->fragsize = 4096;
- dmabuf->fragsamples = 4096 >> sample_shift[dmabuf->fmt];
- dmabuf->fragshift = 12;
- dmabuf->dmasize = dmabuf->numfrag * 4096;
- } else {
- SGarray[0] = 0xf2c0000f;
- SGarray[1] = 0x00000200;
- SGarray[2] = 0;
- SGarray[3] = 0x00010600;
- SGarray[4]=SGarray[5]=SGarray[6]=SGarray[7]=SGarray[8] = 0;
- dmabuf->numfrag = 2;
- dmabuf->fragsize = 2048;
- dmabuf->fragsamples = 2048 >> sample_shift[dmabuf->fmt];
- dmabuf->dmasize = 4096;
- dmabuf->fragshift = 11;
- }
- for (tmp1 = 0; tmp1 < sizeof(SGarray) / 4; tmp1++)
- cs461x_poke(state->card, BA1_PDTC+tmp1 * 4, SGarray[tmp1]);
-
- memset(dmabuf->rawbuf, (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
- dmabuf->dmasize);
-
- /*
- * Now set up the ring
- */
-
- spin_lock_irqsave(&state->card->lock, flags);
- cs_play_setup(state);
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
-
- CS_DBGOUT(CS_PARMS, 4, printk(
- "cs46xx: prog_dmabuf(): PLAYBACK rate=%d fmt=0x%x numfrag=%d "
- "fragsize=%d dmasize=%d\n",
- dmabuf->rate, dmabuf->fmt, dmabuf->numfrag,
- dmabuf->fragsize, dmabuf->dmasize) );
-
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- \n"));
- return 0;
- } else {
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: prog_dmabuf()- Invalid Type %d\n",
- dmabuf->type));
- }
- return 1;
-}
-
-static int prog_dmabuf(struct cs_state *state)
-{
- int ret;
-
- mutex_lock(&state->sem);
- ret = __prog_dmabuf(state);
- mutex_unlock(&state->sem);
-
- return ret;
-}
-
-static void cs_clear_tail(struct cs_state *state)
-{
-}
-
-static int drain_dac(struct cs_state *state, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf = &state->dmabuf;
- struct cs_card *card=state->card;
- unsigned long flags;
- unsigned long tmo;
- int count;
-
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()+ \n"));
- if (dmabuf->mapped || !dmabuf->ready)
- {
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0, not ready\n"));
- return 0;
- }
-
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
- /* It seems that we have to set the current state to TASK_INTERRUPTIBLE
- every time to make the process really go to sleep */
- current->state = TASK_INTERRUPTIBLE;
-
- spin_lock_irqsave(&state->card->lock, flags);
- count = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (count <= 0)
- break;
-
- if (signal_pending(current))
- break;
-
- if (nonblock) {
- remove_wait_queue(&dmabuf->wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
-
- tmo = (dmabuf->dmasize * HZ) / dmabuf->rate;
- tmo >>= sample_shift[dmabuf->fmt];
- tmo += (2048*HZ)/dmabuf->rate;
-
- if (!schedule_timeout(tmo ? tmo : 1) && tmo){
- printk(KERN_ERR "cs46xx: drain_dac, dma timeout? %d\n", count);
- break;
- }
- }
- remove_wait_queue(&dmabuf->wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current)) {
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- -ERESTARTSYS\n"));
- /*
- * set to silence and let that clear the fifos.
- */
- cs461x_clear_serial_FIFOs(card, CS_TYPE_DAC);
- return -ERESTARTSYS;
- }
-
- CS_DBGOUT(CS_FUNCTION, 4, printk("cs46xx: drain_dac()- 0\n"));
- return 0;
-}
-
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void cs_update_ptr(struct cs_card *card, int wake)
-{
- struct cs_state *state;
- struct dmabuf *dmabuf;
- unsigned hwptr;
- int diff;
-
- /* error handling and process wake up for ADC */
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- if (dmabuf->enable & ADC_RUNNING) {
- /* update hardware pointer */
- hwptr = cs_get_dma_addr(state);
-
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- CS_DBGOUT(CS_PARMS, 9, printk(
- "cs46xx: cs_update_ptr()+ ADC hwptr=%d diff=%d\n",
- hwptr,diff) );
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count += diff;
- if (dmabuf->count > dmabuf->dmasize)
- dmabuf->count = dmabuf->dmasize;
-
- if (dmabuf->mapped) {
- if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
- wake_up(&dmabuf->wait);
- } else {
- if (wake && dmabuf->count > 0)
- wake_up(&dmabuf->wait);
- }
- }
- }
-
-/*
- * Now the DAC
- */
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- /* error handling and process wake up for DAC */
- if (dmabuf->enable & DAC_RUNNING) {
- /* update hardware pointer */
- hwptr = cs_get_dma_addr(state);
-
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- CS_DBGOUT(CS_PARMS, 9, printk(
- "cs46xx: cs_update_ptr()+ DAC hwptr=%d diff=%d\n",
- hwptr,diff) );
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- if (dmabuf->mapped) {
- dmabuf->count += diff;
- if (wake && dmabuf->count >= (signed)dmabuf->fragsize)
- wake_up(&dmabuf->wait);
- /*
- * other drivers use fragsize, but don't see any sense
- * in that, since dmasize is the buffer asked for
- * via mmap.
- */
- if (dmabuf->count > dmabuf->dmasize)
- dmabuf->count &= dmabuf->dmasize-1;
- } else {
- dmabuf->count -= diff;
- /*
- * backfill with silence and clear out the last
- * "diff" number of bytes.
- */
- if (hwptr >= diff) {
- memset(dmabuf->rawbuf + hwptr - diff,
- (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80, diff);
- } else {
- memset(dmabuf->rawbuf,
- (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
- (unsigned)hwptr);
- memset((char *)dmabuf->rawbuf +
- dmabuf->dmasize + hwptr - diff,
- (dmabuf->fmt & CS_FMT_16BIT) ? 0 : 0x80,
- diff - hwptr);
- }
-
- if (dmabuf->count < 0 || dmabuf->count > dmabuf->dmasize) {
- CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
- "cs46xx: ERROR DAC count<0 or count > dmasize (%d)\n",
- dmabuf->count));
- /*
- * buffer underrun or buffer overrun, reset the
- * count of bytes written back to 0.
- */
- if (dmabuf->count < 0)
- dmabuf->underrun = 1;
- dmabuf->count = 0;
- dmabuf->error++;
- }
- if (wake && dmabuf->count < (signed)dmabuf->dmasize / 2)
- wake_up(&dmabuf->wait);
- }
- }
- }
-}
-
-
-/* hold spinlock for the following! */
-static void cs_handle_midi(struct cs_card *card)
-{
- unsigned char ch;
- int wake;
- unsigned temp1;
-
- wake = 0;
- while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_RBE)) {
- ch = cs461x_peekBA0(card, BA0_MIDRP);
- if (card->midi.icnt < CS_MIDIINBUF) {
- card->midi.ibuf[card->midi.iwr] = ch;
- card->midi.iwr = (card->midi.iwr + 1) % CS_MIDIINBUF;
- card->midi.icnt++;
- }
- wake = 1;
- }
- if (wake)
- wake_up(&card->midi.iwait);
- wake = 0;
- while (!(cs461x_peekBA0(card, BA0_MIDSR) & MIDSR_TBF) && card->midi.ocnt > 0) {
- temp1 = ( card->midi.obuf[card->midi.ord] ) & 0x000000ff;
- cs461x_pokeBA0(card, BA0_MIDWP,temp1);
- card->midi.ord = (card->midi.ord + 1) % CS_MIDIOUTBUF;
- card->midi.ocnt--;
- if (card->midi.ocnt < CS_MIDIOUTBUF-16)
- wake = 1;
- }
- if (wake)
- wake_up(&card->midi.owait);
-}
-
-static irqreturn_t cs_interrupt(int irq, void *dev_id)
-{
- struct cs_card *card = (struct cs_card *)dev_id;
- /* Single channel card */
- struct cs_state *recstate = card->channel[0].state;
- struct cs_state *playstate = card->channel[1].state;
- u32 status;
-
- CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()+ \n"));
-
- spin_lock(&card->lock);
-
- status = cs461x_peekBA0(card, BA0_HISR);
-
- if ((status & 0x7fffffff) == 0) {
- cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
- spin_unlock(&card->lock);
- return IRQ_HANDLED; /* Might be IRQ_NONE.. */
- }
-
- /*
- * check for playback or capture interrupt only
- */
- if (((status & HISR_VC0) && playstate && playstate->dmabuf.ready) ||
- (((status & HISR_VC1) && recstate && recstate->dmabuf.ready))) {
- CS_DBGOUT(CS_INTERRUPT, 8, printk(
- "cs46xx: cs_interrupt() interrupt bit(s) set (0x%x)\n",status));
- cs_update_ptr(card, CS_TRUE);
- }
-
- if (status & HISR_MIDI)
- cs_handle_midi(card);
-
- /* clear 'em */
- cs461x_pokeBA0(card, BA0_HICR, HICR_CHGM|HICR_IEV);
- spin_unlock(&card->lock);
- CS_DBGOUT(CS_INTERRUPT, 9, printk("cs46xx: cs_interrupt()- \n"));
- return IRQ_HANDLED;
-}
-
-
-/**********************************************************************/
-
-static ssize_t cs_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cs_card *card = file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count > 0) {
- spin_lock_irqsave(&card->lock, flags);
- ptr = card->midi.ird;
- cnt = CS_MIDIINBUF - ptr;
- if (card->midi.icnt < cnt)
- cnt = card->midi.icnt;
- spin_unlock_irqrestore(&card->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&card->midi.iwait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_to_user(buffer, card->midi.ibuf + ptr, cnt))
- return ret ? ret : -EFAULT;
- ptr = (ptr + cnt) % CS_MIDIINBUF;
- spin_lock_irqsave(&card->lock, flags);
- card->midi.ird = ptr;
- card->midi.icnt -= cnt;
- spin_unlock_irqrestore(&card->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
- return ret;
-}
-
-
-static ssize_t cs_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cs_card *card = file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count > 0) {
- spin_lock_irqsave(&card->lock, flags);
- ptr = card->midi.owr;
- cnt = CS_MIDIOUTBUF - ptr;
- if (card->midi.ocnt + cnt > CS_MIDIOUTBUF)
- cnt = CS_MIDIOUTBUF - card->midi.ocnt;
- if (cnt <= 0)
- cs_handle_midi(card);
- spin_unlock_irqrestore(&card->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&card->midi.owait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_from_user(card->midi.obuf + ptr, buffer, cnt))
- return ret ? ret : -EFAULT;
- ptr = (ptr + cnt) % CS_MIDIOUTBUF;
- spin_lock_irqsave(&card->lock, flags);
- card->midi.owr = ptr;
- card->midi.ocnt += cnt;
- spin_unlock_irqrestore(&card->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_lock_irqsave(&card->lock, flags);
- cs_handle_midi(card);
- spin_unlock_irqrestore(&card->lock, flags);
- }
- return ret;
-}
-
-
-static unsigned int cs_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct cs_card *card = file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- if (file->f_flags & FMODE_WRITE)
- poll_wait(file, &card->midi.owait, wait);
- if (file->f_flags & FMODE_READ)
- poll_wait(file, &card->midi.iwait, wait);
- spin_lock_irqsave(&card->lock, flags);
- if (file->f_flags & FMODE_READ) {
- if (card->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_flags & FMODE_WRITE) {
- if (card->midi.ocnt < CS_MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return mask;
-}
-
-
-static int cs_midi_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct cs_card *card = NULL;
- unsigned long flags;
- struct list_head *entry;
-
- list_for_each(entry, &cs46xx_devs) {
- card = list_entry(entry, struct cs_card, list);
- if (card->dev_midi == minor)
- break;
- }
-
- if (entry == &cs46xx_devs)
- return -ENODEV;
- if (!card) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs46xx: cs46xx_midi_open(): Error - unable to find card struct\n"));
- return -ENODEV;
- }
-
- file->private_data = card;
- /* wait for device to become free */
- mutex_lock(&card->midi.open_mutex);
- while (card->midi.open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&card->midi.open_mutex);
- return -EBUSY;
- }
- mutex_unlock(&card->midi.open_mutex);
- interruptible_sleep_on(&card->midi.open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&card->midi.open_mutex);
- }
- spin_lock_irqsave(&card->midi.lock, flags);
- if (!(card->midi.open_mode & (FMODE_READ | FMODE_WRITE))) {
- card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
- card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
- card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
- cs461x_pokeBA0(card, BA0_MIDCR, 0x0000000f); /* Enable xmit, rcv. */
- cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM); /* Enable interrupts */
- }
- if (file->f_mode & FMODE_READ)
- card->midi.ird = card->midi.iwr = card->midi.icnt = 0;
- if (file->f_mode & FMODE_WRITE)
- card->midi.ord = card->midi.owr = card->midi.ocnt = 0;
- spin_unlock_irqrestore(&card->midi.lock, flags);
- card->midi.open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
- mutex_unlock(&card->midi.open_mutex);
- return 0;
-}
-
-
-static int cs_midi_release(struct inode *inode, struct file *file)
-{
- struct cs_card *card = file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- unsigned count, tmo;
-
- if (file->f_mode & FMODE_WRITE) {
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue(&card->midi.owait, &wait);
- for (;;) {
- spin_lock_irqsave(&card->midi.lock, flags);
- count = card->midi.ocnt;
- spin_unlock_irqrestore(&card->midi.lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (file->f_flags & O_NONBLOCK)
- break;
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "cs46xx: midi timed out??\n");
- }
- remove_wait_queue(&card->midi.owait, &wait);
- current->state = TASK_RUNNING;
- }
- mutex_lock(&card->midi.open_mutex);
- card->midi.open_mode &= (~(file->f_mode & (FMODE_READ | FMODE_WRITE)));
- mutex_unlock(&card->midi.open_mutex);
- wake_up(&card->midi.open_wait);
- return 0;
-}
-
-/*
- * Midi file operations struct.
- */
-static /*const*/ struct file_operations cs_midi_fops = {
- CS_OWNER CS_THIS_MODULE
- .llseek = no_llseek,
- .read = cs_midi_read,
- .write = cs_midi_write,
- .poll = cs_midi_poll,
- .open = cs_midi_open,
- .release = cs_midi_release,
-};
-
-/*
- *
- * CopySamples copies 16-bit stereo signed samples from the source to the
- * destination, possibly converting down to unsigned 8-bit and/or mono.
- * count specifies the number of output bytes to write.
- *
- * Arguments:
- *
- * dst - Pointer to a destination buffer.
- * src - Pointer to a source buffer
- * count - The number of bytes to copy into the destination buffer.
- * fmt - CS_FMT_16BIT and/or CS_FMT_STEREO bits
- * dmabuf - pointer to the dma buffer structure
- *
- * NOTES: only call this routine if the output desired is not 16 Signed Stereo
- *
- *
- */
-static void CopySamples(char *dst, char *src, int count, unsigned fmt,
- struct dmabuf *dmabuf)
-{
- s32 s32AudioSample;
- s16 *psSrc = (s16 *)src;
- s16 *psDst = (s16 *)dst;
- u8 *pucDst = (u8 *)dst;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "cs46xx: CopySamples()+ ") );
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- " dst=%p src=%p count=%d fmt=0x%x\n",
- dst,src,count,fmt) );
-
- /*
- * See if the data should be output as 8-bit unsigned stereo.
- */
- if ((fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
- /*
- * Convert each 16-bit signed stereo sample to 8-bit unsigned
- * stereo using rounding.
- */
- psSrc = (s16 *)src;
- count = count / 2;
- while (count--)
- *(pucDst++) = (u8)(((s16)(*psSrc++) + (s16)0x8000) >> 8);
- }
- /*
- * See if the data should be output at 8-bit unsigned mono.
- */
- else if (!(fmt & CS_FMT_STEREO) && !(fmt & CS_FMT_16BIT)) {
- /*
- * Convert each 16-bit signed stereo sample to 8-bit unsigned
- * mono using averaging and rounding.
- */
- psSrc = (s16 *)src;
- count = count / 2;
- while (count--) {
- s32AudioSample = ((*psSrc) + (*(psSrc + 1))) / 2 + (s32)0x80;
- if (s32AudioSample > 0x7fff)
- s32AudioSample = 0x7fff;
- *(pucDst++) = (u8)(((s16)s32AudioSample + (s16)0x8000) >> 8);
- psSrc += 2;
- }
- }
- /*
- * See if the data should be output at 16-bit signed mono.
- */
- else if (!(fmt & CS_FMT_STEREO) && (fmt & CS_FMT_16BIT)) {
- /*
- * Convert each 16-bit signed stereo sample to 16-bit signed
- * mono using averaging.
- */
- psSrc = (s16 *)src;
- count = count / 2;
- while (count--) {
- *(psDst++) = (s16)((*psSrc) + (*(psSrc + 1))) / 2;
- psSrc += 2;
- }
- }
-}
-
-/*
- * cs_copy_to_user()
- * replacement for the standard copy_to_user, to allow for a conversion from
- * 16 bit to 8 bit and from stereo to mono, if the record conversion is active.
- * The current CS46xx/CS4280 static image only records in 16bit unsigned Stereo,
- * so we convert from any of the other format combinations.
- */
-static unsigned cs_copy_to_user(
- struct cs_state *s,
- void __user *dest,
- void *hwsrc,
- unsigned cnt,
- unsigned *copied)
-{
- struct dmabuf *dmabuf = &s->dmabuf;
- void *src = hwsrc; /* default to the standard destination buffer addr */
-
- CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
- "cs_copy_to_user()+ fmt=0x%x cnt=%d dest=%p\n",
- dmabuf->fmt,(unsigned)cnt,dest) );
-
- if (cnt > dmabuf->dmasize)
- cnt = dmabuf->dmasize;
- if (!cnt) {
- *copied = 0;
- return 0;
- }
- if (dmabuf->divisor != 1) {
- if (!dmabuf->tmpbuff) {
- *copied = cnt / dmabuf->divisor;
- return 0;
- }
-
- CopySamples((char *)dmabuf->tmpbuff, (char *)hwsrc, cnt,
- dmabuf->fmt, dmabuf);
- src = dmabuf->tmpbuff;
- cnt = cnt/dmabuf->divisor;
- }
- if (copy_to_user(dest, src, cnt)) {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
- "cs46xx: cs_copy_to_user()- fault dest=%p src=%p cnt=%d\n",
- dest,src,cnt));
- *copied = 0;
- return -EFAULT;
- }
- *copied = cnt;
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
- "cs46xx: cs_copy_to_user()- copied bytes is %d \n",cnt));
- return 0;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be copied to
- the user's buffer. it is filled by the dma machine and drained by this loop. */
-static ssize_t cs_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cs_card *card = file->private_data;
- struct cs_state *state;
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf;
- ssize_t ret = 0;
- unsigned long flags;
- unsigned swptr;
- int cnt;
- unsigned copied = 0;
-
- CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
- printk("cs46xx: cs_read()+ %zd\n",count) );
- state = card->states[0];
- if (!state)
- return -ENODEV;
- dmabuf = &state->dmabuf;
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
-
- mutex_lock(&state->sem);
- if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
- goto out2;
-
- add_wait_queue(&state->dmabuf.wait, &wait);
- while (count > 0) {
- while (!(card->pm.flags & CS46XX_PM_IDLE)) {
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- }
- spin_lock_irqsave(&state->card->lock, flags);
- swptr = dmabuf->swptr;
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count < cnt)
- cnt = dmabuf->count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (cnt > (count * dmabuf->divisor))
- cnt = count * dmabuf->divisor;
- if (cnt <= 0) {
- /* buffer is empty, start the dma machine and wait for data to be
- recorded */
- start_adc(state);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&state->sem);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- mutex_lock(&state->sem);
- if (dmabuf->mapped) {
- if (!ret)
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
-
- CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
- "_read() copy_to cnt=%d count=%zd ", cnt,count) );
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- " .dmasize=%d .count=%d buffer=%p ret=%zd\n",
- dmabuf->dmasize,dmabuf->count,buffer,ret));
-
- if (cs_copy_to_user(state, buffer,
- (char *)dmabuf->rawbuf + swptr, cnt, &copied)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % dmabuf->dmasize;
- spin_lock_irqsave(&card->lock, flags);
- dmabuf->swptr = swptr;
- dmabuf->count -= cnt;
- spin_unlock_irqrestore(&card->lock, flags);
- count -= copied;
- buffer += copied;
- ret += copied;
- start_adc(state);
- }
-out:
- remove_wait_queue(&state->dmabuf.wait, &wait);
-out2:
- mutex_unlock(&state->sem);
- set_current_state(TASK_RUNNING);
- CS_DBGOUT(CS_WAVE_READ | CS_FUNCTION, 4,
- printk("cs46xx: cs_read()- %zd\n",ret) );
- return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
- the soundcard. it is drained by the dma machine and filled by this loop. */
-static ssize_t cs_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cs_card *card = file->private_data;
- struct cs_state *state;
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 4,
- printk("cs46xx: cs_write called, count = %zd\n", count) );
- state = card->states[1];
- if (!state)
- return -ENODEV;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- dmabuf = &state->dmabuf;
-
- mutex_lock(&state->sem);
- if (dmabuf->mapped) {
- ret = -ENXIO;
- goto out;
- }
-
- if (!dmabuf->ready && (ret = __prog_dmabuf(state)))
- goto out;
- add_wait_queue(&state->dmabuf.wait, &wait);
- ret = 0;
-/*
-* Start the loop to read from the user's buffer and write to the dma buffer.
-* check for PM events and underrun/overrun in the loop.
-*/
- while (count > 0) {
- while (!(card->pm.flags & CS46XX_PM_IDLE)) {
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- }
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->count < 0) {
- /* buffer underrun, we are recovering from sleep_on_timeout,
- resync hwptr and swptr */
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- }
- if (dmabuf->underrun) {
- dmabuf->underrun = 0;
- dmabuf->hwptr = cs_get_dma_addr(state);
- dmabuf->swptr = dmabuf->hwptr;
- }
-
- swptr = dmabuf->swptr;
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count + cnt > dmabuf->dmasize)
- cnt = dmabuf->dmasize - dmabuf->count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- /* buffer is full, start the dma machine and wait for data to be
- played */
- start_dac(state);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&state->sem);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- mutex_lock(&state->sem);
- if (dmabuf->mapped) {
- if (!ret)
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
- if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- swptr = (swptr + cnt) % dmabuf->dmasize;
- dmabuf->swptr = swptr;
- dmabuf->count += cnt;
- if (dmabuf->count > dmabuf->dmasize) {
- CS_DBGOUT(CS_WAVE_WRITE | CS_ERROR, 2, printk(
- "cs46xx: cs_write() d->count > dmasize - resetting\n"));
- dmabuf->count = dmabuf->dmasize;
- }
- dmabuf->endcleared = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(state);
- }
-out:
- mutex_unlock(&state->sem);
- remove_wait_queue(&state->dmabuf.wait, &wait);
- set_current_state(TASK_RUNNING);
-
- CS_DBGOUT(CS_WAVE_WRITE | CS_FUNCTION, 2,
- printk("cs46xx: cs_write()- ret=%zd\n", ret));
- return ret;
-}
-
-static unsigned int cs_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct cs_card *card = file->private_data;
- struct dmabuf *dmabuf;
- struct cs_state *state;
- unsigned long flags;
- unsigned int mask = 0;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()+ \n"));
- if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
- return -EINVAL;
- }
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- poll_wait(file, &dmabuf->wait, wait);
- }
- }
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- poll_wait(file, &dmabuf->wait, wait);
- }
- }
-
- spin_lock_irqsave(&card->lock, flags);
- cs_update_ptr(card, CS_FALSE);
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- if (dmabuf->count >= (signed)dmabuf->fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- if (dmabuf->mapped) {
- if (dmabuf->count >= (signed)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)dmabuf->dmasize >= dmabuf->count
- + (signed)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- }
- spin_unlock_irqrestore(&card->lock, flags);
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_poll()- (0x%x) \n",
- mask));
- return mask;
-}
-
-/*
- * We let users mmap the ring buffer. Its not the real DMA buffer but
- * that side of the code is hidden in the IRQ handling. We do a software
- * emulation of DMA from a 64K or so buffer into a 2K FIFO.
- * (the hardware probably deserves a moan here but Crystal send me nice
- * toys ;)).
- */
-
-static int cs_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cs_card *card = file->private_data;
- struct cs_state *state;
- struct dmabuf *dmabuf;
- int ret = 0;
- unsigned long size;
-
- CS_DBGOUT(CS_FUNCTION | CS_PARMS, 2, printk("cs46xx: cs_mmap()+ file=%p %s %s\n",
- file, vma->vm_flags & VM_WRITE ? "VM_WRITE" : "",
- vma->vm_flags & VM_READ ? "VM_READ" : "") );
-
- if (vma->vm_flags & VM_WRITE) {
- state = card->states[1];
- if (state) {
- CS_DBGOUT(CS_OPEN, 2, printk(
- "cs46xx: cs_mmap() VM_WRITE - state TRUE prog_dmabuf DAC\n") );
- if ((ret = prog_dmabuf(state)) != 0)
- return ret;
- }
- } else if (vma->vm_flags & VM_READ) {
- state = card->states[0];
- if (state) {
- CS_DBGOUT(CS_OPEN, 2, printk(
- "cs46xx: cs_mmap() VM_READ - state TRUE prog_dmabuf ADC\n") );
- if ((ret = prog_dmabuf(state)) != 0)
- return ret;
- }
- } else {
- CS_DBGOUT(CS_ERROR, 2, printk(
- "cs46xx: cs_mmap() return -EINVAL\n") );
- return -EINVAL;
- }
-
-/*
- * For now ONLY support playback, but seems like the only way to use
- * mmap() is to open an FD with RDWR, just read or just write access
- * does not function, get an error back from the kernel.
- * Also, QuakeIII opens with RDWR! So, there must be something
- * to needing read/write access mapping. So, allow read/write but
- * use the DAC only.
- */
- state = card->states[1];
- if (!state) {
- ret = -EINVAL;
- goto out;
- }
-
- mutex_lock(&state->sem);
- dmabuf = &state->dmabuf;
- if (cs4x_pgoff(vma) != 0) {
- ret = -EINVAL;
- goto out;
- }
- size = vma->vm_end - vma->vm_start;
-
- CS_DBGOUT(CS_PARMS, 2, printk("cs46xx: cs_mmap(): size=%d\n",(unsigned)size) );
-
- if (size > (PAGE_SIZE << dmabuf->buforder)) {
- ret = -EINVAL;
- goto out;
- }
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
- ret = -EAGAIN;
- goto out;
- }
- dmabuf->mapped = 1;
-
- CS_DBGOUT(CS_FUNCTION, 2, printk("cs46xx: cs_mmap()-\n") );
-out:
- mutex_unlock(&state->sem);
- return ret;
-}
-
-static int cs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct cs_card *card = file->private_data;
- struct cs_state *state;
- struct dmabuf *dmabuf = NULL;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, valsave, ret;
- int mapped = 0;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- mapped = (file->f_mode & FMODE_READ) && dmabuf->mapped;
- }
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- mapped |= (file->f_mode & FMODE_WRITE) && dmabuf->mapped;
- }
-
-#if CSDEBUG
- printioctl(cmd);
-#endif
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
- case SNDCTL_DSP_RESET:
- /* FIXME: spin_lock ? */
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_dac(state);
- synchronize_irq(card->irq);
- dmabuf->ready = 0;
- resync_dma_ptrs(state);
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- dmabuf->blocks = 0;
- dmabuf->SGok = 0;
- }
- }
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_adc(state);
- synchronize_irq(card->irq);
- resync_dma_ptrs(state);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- dmabuf->blocks = 0;
- dmabuf->SGok = 0;
- }
- }
- CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_RESET()-\n") );
- return 0;
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(state, file->f_flags & O_NONBLOCK);
- return 0;
- case SNDCTL_DSP_SPEED: /* set sample rate */
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_adc(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- cs_set_adc_rate(state, val);
- cs_set_divisor(dmabuf);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_dac(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- cs_set_dac_rate(state, val);
- cs_set_divisor(dmabuf);
- }
- }
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
- "cs46xx: cs_ioctl() DSP_SPEED %s %s %d\n",
- file->f_mode & FMODE_WRITE ? "DAC" : "",
- file->f_mode & FMODE_READ ? "ADC" : "",
- dmabuf->rate ) );
- return put_user(dmabuf->rate, p);
- }
- return put_user(0, p);
- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_dac(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- if (val)
- dmabuf->fmt |= CS_FMT_STEREO;
- else
- dmabuf->fmt &= ~CS_FMT_STEREO;
- cs_set_divisor(dmabuf);
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
- "cs46xx: DSP_STEREO() DAC %s\n",
- (dmabuf->fmt & CS_FMT_STEREO) ?
- "STEREO":"MONO") );
- }
- }
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_adc(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- if (val)
- dmabuf->fmt |= CS_FMT_STEREO;
- else
- dmabuf->fmt &= ~CS_FMT_STEREO;
- cs_set_divisor(dmabuf);
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
- "cs46xx: DSP_STEREO() ADC %s\n",
- (dmabuf->fmt & CS_FMT_STEREO) ?
- "STEREO":"MONO") );
- }
- }
- return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- if ((val = prog_dmabuf(state)))
- return val;
- return put_user(dmabuf->fragsize, p);
- }
- }
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- if ((val = prog_dmabuf(state)))
- return val;
- return put_user(dmabuf->fragsize/dmabuf->divisor,
- p);
- }
- }
- return put_user(0, p);
- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
- return put_user(AFMT_S16_LE | AFMT_U8, p);
- case SNDCTL_DSP_SETFMT: /* Select sample format */
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(
- "cs46xx: cs_ioctl() DSP_SETFMT %s %s %s %s\n",
- file->f_mode & FMODE_WRITE ? "DAC" : "",
- file->f_mode & FMODE_READ ? "ADC" : "",
- val == AFMT_S16_LE ? "16Bit Signed" : "",
- val == AFMT_U8 ? "8Bit Unsigned" : "") );
- valsave = val;
- if (val != AFMT_QUERY) {
- if (val==AFMT_S16_LE || val==AFMT_U8) {
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_dac(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- if (val == AFMT_S16_LE)
- dmabuf->fmt |= CS_FMT_16BIT;
- else
- dmabuf->fmt &= ~CS_FMT_16BIT;
- cs_set_divisor(dmabuf);
- if ((ret = prog_dmabuf(state)))
- return ret;
- }
- }
- if (file->f_mode & FMODE_READ) {
- val = valsave;
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_adc(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- if (val == AFMT_S16_LE)
- dmabuf->fmt |= CS_FMT_16BIT;
- else
- dmabuf->fmt &= ~CS_FMT_16BIT;
- cs_set_divisor(dmabuf);
- if ((ret = prog_dmabuf(state)))
- return ret;
- }
- }
- } else {
- CS_DBGOUT(CS_IOCTL | CS_ERROR, 2, printk(
- "cs46xx: DSP_SETFMT() Unsupported format (0x%x)\n",
- valsave) );
- }
- } else {
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state)
- dmabuf = &state->dmabuf;
- } else if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state)
- dmabuf = &state->dmabuf;
- }
- }
- if (dmabuf) {
- if (dmabuf->fmt & CS_FMT_16BIT)
- return put_user(AFMT_S16_LE, p);
- else
- return put_user(AFMT_U8, p);
- }
- return put_user(0, p);
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_dac(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- if (val > 1)
- dmabuf->fmt |= CS_FMT_STEREO;
- else
- dmabuf->fmt &= ~CS_FMT_STEREO;
- cs_set_divisor(dmabuf);
- if (prog_dmabuf(state))
- return 0;
- }
- }
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- stop_adc(state);
- dmabuf->ready = 0;
- dmabuf->SGok = 0;
- if (val > 1)
- dmabuf->fmt |= CS_FMT_STEREO;
- else
- dmabuf->fmt &= ~CS_FMT_STEREO;
- cs_set_divisor(dmabuf);
- if (prog_dmabuf(state))
- return 0;
- }
- }
- }
- return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
- p);
- case SNDCTL_DSP_POST:
- /*
- * There will be a longer than normal pause in the data.
- * so... do nothing, because there is nothing that we can do.
- */
- return 0;
- case SNDCTL_DSP_SUBDIVIDE:
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- if (dmabuf->subdivision)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2)
- return -EINVAL;
- dmabuf->subdivision = val;
- }
- }
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- if (dmabuf->subdivision)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2)
- return -EINVAL;
- dmabuf->subdivision = val;
- }
- }
- return 0;
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- dmabuf->ossfragshift = val & 0xffff;
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- }
- }
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- dmabuf->ossfragshift = val & 0xffff;
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- }
- }
- return 0;
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- spin_lock_irqsave(&state->card->lock, flags);
- cs_update_ptr(card, CS_TRUE);
- abinfo.fragsize = dmabuf->fragsize;
- abinfo.fragstotal = dmabuf->numfrag;
- /*
- * for mmap we always have total space available
- */
- if (dmabuf->mapped)
- abinfo.bytes = dmabuf->dmasize;
- else
- abinfo.bytes = dmabuf->dmasize - dmabuf->count;
-
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->card->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
- }
- return -ENODEV;
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- spin_lock_irqsave(&state->card->lock, flags);
- cs_update_ptr(card, CS_TRUE);
- abinfo.fragsize = dmabuf->fragsize/dmabuf->divisor;
- abinfo.bytes = dmabuf->count/dmabuf->divisor;
- abinfo.fragstotal = dmabuf->numfrag;
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->card->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
- }
- return -ENODEV;
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
- p);
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()+\n") );
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- if (dmabuf->enable & DAC_RUNNING)
- val |= PCM_ENABLE_INPUT;
- }
- }
- if (file->f_mode & FMODE_READ) {
- if (state) {
- state = card->states[0];
- dmabuf = &state->dmabuf;
- if (dmabuf->enable & ADC_RUNNING)
- val |= PCM_ENABLE_OUTPUT;
- }
- }
- CS_DBGOUT(CS_IOCTL, 2, printk("cs46xx: DSP_GETTRIGGER()- val=0x%x\n",val) );
- return put_user(val, p);
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- if (val & PCM_ENABLE_INPUT) {
- if (!dmabuf->ready && (ret = prog_dmabuf(state)))
- return ret;
- start_adc(state);
- } else
- stop_adc(state);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- if (val & PCM_ENABLE_OUTPUT) {
- if (!dmabuf->ready && (ret = prog_dmabuf(state)))
- return ret;
- start_dac(state);
- } else
- stop_dac(state);
- }
- }
- return 0;
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- state = card->states[0];
- if (state) {
- dmabuf = &state->dmabuf;
- spin_lock_irqsave(&state->card->lock, flags);
- cs_update_ptr(card, CS_TRUE);
- cinfo.bytes = dmabuf->total_bytes/dmabuf->divisor;
- cinfo.blocks = dmabuf->count/dmabuf->divisor >> dmabuf->fragshift;
- cinfo.ptr = dmabuf->hwptr/dmabuf->divisor;
- spin_unlock_irqrestore(&state->card->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
- }
- return -ENODEV;
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- spin_lock_irqsave(&state->card->lock, flags);
- cs_update_ptr(card, CS_TRUE);
- cinfo.bytes = dmabuf->total_bytes;
- if (dmabuf->mapped) {
- cinfo.blocks = (cinfo.bytes >> dmabuf->fragshift)
- - dmabuf->blocks;
- CS_DBGOUT(CS_PARMS, 8,
- printk("total_bytes=%d blocks=%d dmabuf->blocks=%d\n",
- cinfo.bytes,cinfo.blocks,dmabuf->blocks) );
- dmabuf->blocks = cinfo.bytes >> dmabuf->fragshift;
- } else {
- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
- }
- cinfo.ptr = dmabuf->hwptr;
-
- CS_DBGOUT(CS_PARMS, 4, printk(
- "cs46xx: GETOPTR bytes=%d blocks=%d ptr=%d\n",
- cinfo.bytes,cinfo.blocks,cinfo.ptr) );
- spin_unlock_irqrestore(&state->card->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
- }
- return -ENODEV;
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- spin_lock_irqsave(&state->card->lock, flags);
- cs_update_ptr(card, CS_TRUE);
- val = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
- } else
- val = 0;
- return put_user(val, p);
- case SOUND_PCM_READ_RATE:
- if (file->f_mode & FMODE_READ)
- state = card->states[0];
- else
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- return put_user(dmabuf->rate, p);
- }
- return put_user(0, p);
- case SOUND_PCM_READ_CHANNELS:
- if (file->f_mode & FMODE_READ)
- state = card->states[0];
- else
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- return put_user((dmabuf->fmt & CS_FMT_STEREO) ? 2 : 1,
- p);
- }
- return put_user(0, p);
- case SOUND_PCM_READ_BITS:
- if (file->f_mode & FMODE_READ)
- state = card->states[0];
- else
- state = card->states[1];
- if (state) {
- dmabuf = &state->dmabuf;
- return put_user((dmabuf->fmt & CS_FMT_16BIT) ?
- AFMT_S16_LE : AFMT_U8, p);
-
- }
- return put_user(0, p);
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-
-/*
- * AMP control - null AMP
- */
-
-static void amp_none(struct cs_card *card, int change)
-{
-}
-
-/*
- * Crystal EAPD mode
- */
-
-static void amp_voyetra(struct cs_card *card, int change)
-{
- /* Manage the EAPD bit on the Crystal 4297
- and the Analog AD1885 */
-
- int old = card->amplifier;
-
- card->amplifier+=change;
- if (card->amplifier && !old) {
- /* Turn the EAPD amp on */
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
- cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) |
- 0x8000);
- } else if(old && !card->amplifier) {
- /* Turn the EAPD amp off */
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL,
- cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- ~0x8000);
- }
-}
-
-
-/*
- * Game Theatre XP card - EGPIO[2] is used to enable the external amp.
- */
-
-static void amp_hercules(struct cs_card *card, int change)
-{
- int old = card->amplifier;
- if (!card) {
- CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
- "cs46xx: amp_hercules() called before initialized.\n"));
- return;
- }
- card->amplifier+=change;
- if ((card->amplifier && !old) && !(hercules_egpio_disable)) {
- CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
- "cs46xx: amp_hercules() external amp enabled\n"));
- cs461x_pokeBA0(card, BA0_EGPIODR,
- EGPIODR_GPOE2); /* enable EGPIO2 output */
- cs461x_pokeBA0(card, BA0_EGPIOPTR,
- EGPIOPTR_GPPT2); /* open-drain on output */
- } else if (old && !card->amplifier) {
- CS_DBGOUT(CS_PARMS, 4, printk(KERN_INFO
- "cs46xx: amp_hercules() external amp disabled\n"));
- cs461x_pokeBA0(card, BA0_EGPIODR, 0); /* disable */
- cs461x_pokeBA0(card, BA0_EGPIOPTR, 0); /* disable */
- }
-}
-
-/*
- * Handle the CLKRUN on a thinkpad. We must disable CLKRUN support
- * whenever we need to beat on the chip.
- *
- * The original idea and code for this hack comes from David Kaiser at
- * Linuxcare. Perhaps one day Crystal will document their chips well
- * enough to make them useful.
- */
-
-static void clkrun_hack(struct cs_card *card, int change)
-{
- struct pci_dev *acpi_dev;
- u16 control;
- u8 pp;
- unsigned long port;
- int old = card->active;
-
- card->active+=change;
-
- acpi_dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
- if (acpi_dev == NULL)
- return; /* Not a thinkpad thats for sure */
-
- /* Find the control port */
- pci_read_config_byte(acpi_dev, 0x41, &pp);
- port = pp << 8;
-
- /* Read ACPI port */
- control = inw(port + 0x10);
-
- /* Flip CLKRUN off while running */
- if (!card->active && old) {
- CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
- "cs46xx: clkrun() enable clkrun - change=%d active=%d\n",
- change,card->active));
- outw(control|0x2000, port+0x10);
- } else {
- /*
- * sometimes on a resume the bit is set, so always reset the bit.
- */
- CS_DBGOUT(CS_PARMS , 9, printk( KERN_INFO
- "cs46xx: clkrun() disable clkrun - change=%d active=%d\n",
- change,card->active));
- outw(control&~0x2000, port+0x10);
- }
- pci_dev_put(acpi_dev);
-}
-
-
-static int cs_open(struct inode *inode, struct file *file)
-{
- struct cs_card *card = file->private_data;
- struct cs_state *state = NULL;
- struct dmabuf *dmabuf = NULL;
- struct list_head *entry;
- unsigned int minor = iminor(inode);
- int ret = 0;
- unsigned int tmp;
-
- CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()+ file=%p %s %s\n",
- file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
- file->f_mode & FMODE_READ ? "FMODE_READ" : "") );
-
- list_for_each(entry, &cs46xx_devs) {
- card = list_entry(entry, struct cs_card, list);
-
- if (!((card->dev_audio ^ minor) & ~0xf))
- break;
- }
- if (entry == &cs46xx_devs)
- return -ENODEV;
- if (!card) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs46xx: cs_open(): Error - unable to find audio card struct\n"));
- return -ENODEV;
- }
-
- /*
- * hardcode state[0] for capture, [1] for playback
- */
- if (file->f_mode & FMODE_READ) {
- CS_DBGOUT(CS_WAVE_READ, 2, printk("cs46xx: cs_open() FMODE_READ\n") );
- if (card->states[0] == NULL) {
- state = card->states[0] =
- kzalloc(sizeof(struct cs_state), GFP_KERNEL);
- if (state == NULL)
- return -ENOMEM;
- mutex_init(&state->sem);
- dmabuf = &state->dmabuf;
- dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (dmabuf->pbuf == NULL) {
- kfree(state);
- card->states[0] = NULL;
- return -ENOMEM;
- }
- } else {
- state = card->states[0];
- if (state->open_mode & FMODE_READ)
- return -EBUSY;
- }
- dmabuf->channel = card->alloc_rec_pcm_channel(card);
-
- if (dmabuf->channel == NULL) {
- kfree(card->states[0]);
- card->states[0] = NULL;
- return -ENODEV;
- }
-
- /* Now turn on external AMP if needed */
- state->card = card;
- state->card->active_ctrl(state->card, 1);
- state->card->amplifier_ctrl(state->card, 1);
-
- if ((tmp = cs46xx_powerup(card, CS_POWER_ADC))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs46xx_powerup of ADC failed (0x%x)\n", tmp));
- return -EIO;
- }
-
- dmabuf->channel->state = state;
- /* initialize the virtual channel */
- state->virt = 0;
- state->magic = CS_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- file->private_data = card;
-
- mutex_lock(&state->open_mutex);
-
- /* set default sample format. According to OSS Programmer's Guide /dev/dsp
- should be default to unsigned 8-bits, mono, with sample rate 8kHz and
- /dev/dspW will accept 16-bits sample */
-
- /* Default input is 8bit mono */
- dmabuf->fmt &= ~CS_FMT_MASK;
- dmabuf->type = CS_TYPE_ADC;
- dmabuf->ossfragshift = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
- cs_set_adc_rate(state, 8000);
- cs_set_divisor(dmabuf);
-
- state->open_mode |= FMODE_READ;
- mutex_unlock(&state->open_mutex);
- }
- if (file->f_mode & FMODE_WRITE) {
- CS_DBGOUT(CS_OPEN, 2, printk("cs46xx: cs_open() FMODE_WRITE\n") );
- if (card->states[1] == NULL) {
- state = card->states[1] =
- kzalloc(sizeof(struct cs_state), GFP_KERNEL);
- if (state == NULL)
- return -ENOMEM;
- mutex_init(&state->sem);
- dmabuf = &state->dmabuf;
- dmabuf->pbuf = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (dmabuf->pbuf == NULL) {
- kfree(state);
- card->states[1] = NULL;
- return -ENOMEM;
- }
- } else {
- state = card->states[1];
- if (state->open_mode & FMODE_WRITE)
- return -EBUSY;
- }
- dmabuf->channel = card->alloc_pcm_channel(card);
-
- if (dmabuf->channel == NULL) {
- kfree(card->states[1]);
- card->states[1] = NULL;
- return -ENODEV;
- }
-
- /* Now turn on external AMP if needed */
- state->card = card;
- state->card->active_ctrl(state->card, 1);
- state->card->amplifier_ctrl(state->card, 1);
-
- if ((tmp = cs46xx_powerup(card, CS_POWER_DAC))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs46xx_powerup of DAC failed (0x%x)\n", tmp));
- return -EIO;
- }
-
- dmabuf->channel->state = state;
- /* initialize the virtual channel */
- state->virt = 1;
- state->magic = CS_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- file->private_data = card;
-
- mutex_lock(&state->open_mutex);
-
- /* set default sample format. According to OSS Programmer's Guide /dev/dsp
- should be default to unsigned 8-bits, mono, with sample rate 8kHz and
- /dev/dspW will accept 16-bits sample */
-
- /* Default output is 8bit mono. */
- dmabuf->fmt &= ~CS_FMT_MASK;
- dmabuf->type = CS_TYPE_DAC;
- dmabuf->ossfragshift = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
- cs_set_dac_rate(state, 8000);
- cs_set_divisor(dmabuf);
-
- state->open_mode |= FMODE_WRITE;
- mutex_unlock(&state->open_mutex);
- if ((ret = prog_dmabuf(state)))
- return ret;
- }
- CS_DBGOUT(CS_OPEN | CS_FUNCTION, 2, printk("cs46xx: cs_open()- 0\n"));
- return nonseekable_open(inode, file);
-}
-
-static int cs_release(struct inode *inode, struct file *file)
-{
- struct cs_card *card = file->private_data;
- struct dmabuf *dmabuf;
- struct cs_state *state;
- unsigned int tmp;
- CS_DBGOUT(CS_RELEASE | CS_FUNCTION, 2, printk("cs46xx: cs_release()+ file=%p %s %s\n",
- file, file->f_mode & FMODE_WRITE ? "FMODE_WRITE" : "",
- file->f_mode & FMODE_READ ? "FMODE_READ" : ""));
-
- if (!(file->f_mode & (FMODE_WRITE | FMODE_READ)))
- return -EINVAL;
- state = card->states[1];
- if (state) {
- if ((state->open_mode & FMODE_WRITE) & (file->f_mode & FMODE_WRITE)) {
- CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_WRITE\n"));
- dmabuf = &state->dmabuf;
- cs_clear_tail(state);
- drain_dac(state, file->f_flags & O_NONBLOCK);
- /* stop DMA state machine and free DMA buffers/channels */
- mutex_lock(&state->open_mutex);
- stop_dac(state);
- dealloc_dmabuf(state);
- state->card->free_pcm_channel(state->card, dmabuf->channel->num);
- free_page((unsigned long)state->dmabuf.pbuf);
-
- /* we're covered by the open_mutex */
- mutex_unlock(&state->open_mutex);
- state->card->states[state->virt] = NULL;
- state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
- if ((tmp = cs461x_powerdown(card, CS_POWER_DAC, CS_FALSE))) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs46xx: cs_release_mixdev() powerdown DAC failure (0x%x)\n",tmp) );
- }
-
- /* Now turn off external AMP if needed */
- state->card->amplifier_ctrl(state->card, -1);
- state->card->active_ctrl(state->card, -1);
- kfree(state);
- }
- }
-
- state = card->states[0];
- if (state) {
- if ((state->open_mode & FMODE_READ) & (file->f_mode & FMODE_READ)) {
- CS_DBGOUT(CS_RELEASE, 2, printk("cs46xx: cs_release() FMODE_READ\n"));
- dmabuf = &state->dmabuf;
- mutex_lock(&state->open_mutex);
- stop_adc(state);
- dealloc_dmabuf(state);
- state->card->free_pcm_channel(state->card, dmabuf->channel->num);
- free_page((unsigned long)state->dmabuf.pbuf);
-
- /* we're covered by the open_mutex */
- mutex_unlock(&state->open_mutex);
- state->card->states[state->virt] = NULL;
- state->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
- if ((tmp = cs461x_powerdown(card, CS_POWER_ADC, CS_FALSE))) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs46xx: cs_release_mixdev() powerdown ADC failure (0x%x)\n",tmp) );
- }
-
- /* Now turn off external AMP if needed */
- state->card->amplifier_ctrl(state->card, -1);
- state->card->active_ctrl(state->card, -1);
- kfree(state);
- }
- }
-
- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk("cs46xx: cs_release()- 0\n"));
- return 0;
-}
-
-static void printpm(struct cs_card *s)
-{
- CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
- CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
- (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
- CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
- s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
- s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
- s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
- s->pm.u32SSCR,s->pm.u32SRCSA));
- CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
- s->pm.u32DacASR,s->pm.u32AdcASR));
- CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
- s->pm.u32DacSR,s->pm.u32AdcSR));
- CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
- s->pm.u32MIDCR_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32AC97_powerdown: 0x%x _general_purpose 0x%x\n",
- s->pm.u32AC97_powerdown,s->pm.u32AC97_general_purpose));
- CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume: 0x%x\n",
- s->pm.u32AC97_master_volume));
- CS_DBGOUT(CS_PM, 9, printk("u32AC97_headphone_volume: 0x%x\n",
- s->pm.u32AC97_headphone_volume));
- CS_DBGOUT(CS_PM, 9, printk("u32AC97_master_volume_mono: 0x%x\n",
- s->pm.u32AC97_master_volume_mono));
- CS_DBGOUT(CS_PM, 9, printk("u32AC97_pcm_out_volume: 0x%x\n",
- s->pm.u32AC97_pcm_out_volume));
- CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_play: 0x%x dmabuf_count_play: %d\n",
- s->pm.dmabuf_swptr_play,s->pm.dmabuf_count_play));
- CS_DBGOUT(CS_PM, 9, printk("dmabuf_swptr_capture: 0x%x dmabuf_count_capture: %d\n",
- s->pm.dmabuf_swptr_capture,s->pm.dmabuf_count_capture));
-
-}
-
-/****************************************************************************
-*
-* Suspend - save the ac97 regs, mute the outputs and power down the part.
-*
-****************************************************************************/
-static void cs46xx_ac97_suspend(struct cs_card *card)
-{
- int Count,i;
- struct ac97_codec *dev=card->ac97_codec[0];
- unsigned int tmp;
-
- CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()+\n"));
-
- if (card->states[1]) {
- stop_dac(card->states[1]);
- resync_dma_ptrs(card->states[1]);
- }
- if (card->states[0]) {
- stop_adc(card->states[0]);
- resync_dma_ptrs(card->states[0]);
- }
-
- for (Count = 0x2, i = 0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE)
- && (i < CS46XX_AC97_NUMBER_RESTORE_REGS);
- Count += 2, i++) {
- card->pm.ac97[i] = cs_ac97_get(dev, BA0_AC97_RESET + Count);
- }
-/*
-* Save the ac97 volume registers as well as the current powerdown state.
-* Now, mute the all the outputs (master, headphone, and mono), as well
-* as the PCM volume, in preparation for powering down the entire part.
- card->pm.u32AC97_master_volume = (u32)cs_ac97_get( dev,
- (u8)BA0_AC97_MASTER_VOLUME);
- card->pm.u32AC97_headphone_volume = (u32)cs_ac97_get(dev,
- (u8)BA0_AC97_HEADPHONE_VOLUME);
- card->pm.u32AC97_master_volume_mono = (u32)cs_ac97_get(dev,
- (u8)BA0_AC97_MASTER_VOLUME_MONO);
- card->pm.u32AC97_pcm_out_volume = (u32)cs_ac97_get(dev,
- (u8)BA0_AC97_PCM_OUT_VOLUME);
-*/
-/*
-* mute the outputs
-*/
- cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME, 0x8000);
- cs_ac97_set(dev, (u8)BA0_AC97_HEADPHONE_VOLUME, 0x8000);
- cs_ac97_set(dev, (u8)BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
- cs_ac97_set(dev, (u8)BA0_AC97_PCM_OUT_VOLUME, 0x8000);
-
-/*
-* save the registers that cause pops
-*/
- card->pm.u32AC97_powerdown = (u32)cs_ac97_get(dev, (u8)AC97_POWER_CONTROL);
- card->pm.u32AC97_general_purpose = (u32)cs_ac97_get(dev, (u8)BA0_AC97_GENERAL_PURPOSE);
-/*
-* And power down everything on the AC97 codec.
-* well, for now, only power down the DAC/ADC and MIXER VREFON components.
-* trouble with removing VREF.
-*/
- if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON, CS_TRUE))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs46xx_ac97_suspend() failure (0x%x)\n",tmp));
- }
-
- CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_suspend()-\n"));
-}
-
-/****************************************************************************
-*
-* Resume - power up the part and restore its registers..
-*
-****************************************************************************/
-static void cs46xx_ac97_resume(struct cs_card *card)
-{
- int Count,i;
- struct ac97_codec *dev=card->ac97_codec[0];
-
- CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()+\n"));
-
-/*
-* First, we restore the state of the general purpose register. This
-* contains the mic select (mic1 or mic2) and if we restore this after
-* we restore the mic volume/boost state and mic2 was selected at
-* suspend time, we will end up with a brief period of time where mic1
-* is selected with the volume/boost settings for mic2, causing
-* acoustic feedback. So we restore the general purpose register
-* first, thereby getting the correct mic selected before we restore
-* the mic volume/boost.
-*/
- cs_ac97_set(dev, (u8)BA0_AC97_GENERAL_PURPOSE,
- (u16)card->pm.u32AC97_general_purpose);
-/*
-* Now, while the outputs are still muted, restore the state of power
-* on the AC97 part.
-*/
- cs_ac97_set(dev, (u8)BA0_AC97_POWERDOWN, (u16)card->pm.u32AC97_powerdown);
- mdelay(5 * cs_laptop_wait);
-/*
-* Restore just the first set of registers, from register number
-* 0x02 to the register number that ulHighestRegToRestore specifies.
-*/
- for (Count = 0x2, i=0; (Count <= CS46XX_AC97_HIGHESTREGTORESTORE) &&
- (i < CS46XX_AC97_NUMBER_RESTORE_REGS); Count += 2, i++) {
- cs_ac97_set(dev, (u8)(BA0_AC97_RESET + Count), (u16)card->pm.ac97[i]);
- }
-
- /* Check if we have to init the amplifier */
- if (card->amp_init)
- card->amp_init(card);
-
- CS_DBGOUT(CS_PM, 9, printk("cs46xx: cs46xx_ac97_resume()-\n"));
-}
-
-
-static int cs46xx_restart_part(struct cs_card *card)
-{
- struct dmabuf *dmabuf;
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
- printk( "cs46xx: cs46xx_restart_part()+\n"));
- if (card->states[1]) {
- dmabuf = &card->states[1]->dmabuf;
- dmabuf->ready = 0;
- resync_dma_ptrs(card->states[1]);
- cs_set_divisor(dmabuf);
- if (__prog_dmabuf(card->states[1])) {
- CS_DBGOUT(CS_PM | CS_ERROR, 1,
- printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() dac error\n"));
- return -1;
- }
- cs_set_dac_rate(card->states[1], dmabuf->rate);
- }
- if (card->states[0]) {
- dmabuf = &card->states[0]->dmabuf;
- dmabuf->ready = 0;
- resync_dma_ptrs(card->states[0]);
- cs_set_divisor(dmabuf);
- if (__prog_dmabuf(card->states[0])) {
- CS_DBGOUT(CS_PM | CS_ERROR, 1,
- printk("cs46xx: cs46xx_restart_part()- (-1) prog_dmabuf() adc error\n"));
- return -1;
- }
- cs_set_adc_rate(card->states[0], dmabuf->rate);
- }
- card->pm.flags |= CS46XX_PM_RESUMED;
- if (card->states[0])
- start_adc(card->states[0]);
- if (card->states[1])
- start_dac(card->states[1]);
-
- card->pm.flags |= CS46XX_PM_IDLE;
- card->pm.flags &= ~(CS46XX_PM_SUSPENDING | CS46XX_PM_SUSPENDED
- | CS46XX_PM_RESUMING | CS46XX_PM_RESUMED);
- if (card->states[0])
- wake_up(&card->states[0]->dmabuf.wait);
- if (card->states[1])
- wake_up(&card->states[1]->dmabuf.wait);
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
- printk( "cs46xx: cs46xx_restart_part()-\n"));
- return 0;
-}
-
-static void cs461x_reset(struct cs_card *card);
-static void cs461x_proc_stop(struct cs_card *card);
-static int cs46xx_suspend(struct cs_card *card, pm_message_t state)
-{
- unsigned int tmp;
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
- printk("cs46xx: cs46xx_suspend()+ flags=0x%x s=%p\n",
- (unsigned)card->pm.flags,card));
-/*
-* check the current state, only suspend if IDLE
-*/
- if (!(card->pm.flags & CS46XX_PM_IDLE)) {
- CS_DBGOUT(CS_PM | CS_ERROR, 2,
- printk("cs46xx: cs46xx_suspend() unable to suspend, not IDLE\n"));
- return 1;
- }
- card->pm.flags &= ~CS46XX_PM_IDLE;
- card->pm.flags |= CS46XX_PM_SUSPENDING;
-
- card->active_ctrl(card,1);
-
- tmp = cs461x_peek(card, BA1_PFIE);
- tmp &= ~0x0000f03f;
- tmp |= 0x00000010;
- cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
-
- tmp = cs461x_peek(card, BA1_CIE);
- tmp &= ~0x0000003f;
- tmp |= 0x00000011;
- cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
-
- /*
- * Stop playback DMA.
- */
- tmp = cs461x_peek(card, BA1_PCTL);
- cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
-
- /*
- * Stop capture DMA.
- */
- tmp = cs461x_peek(card, BA1_CCTL);
- cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
-
- if (card->states[1]) {
- card->pm.dmabuf_swptr_play = card->states[1]->dmabuf.swptr;
- card->pm.dmabuf_count_play = card->states[1]->dmabuf.count;
- }
- if (card->states[0]) {
- card->pm.dmabuf_swptr_capture = card->states[0]->dmabuf.swptr;
- card->pm.dmabuf_count_capture = card->states[0]->dmabuf.count;
- }
-
- cs46xx_ac97_suspend(card);
-
- /*
- * Reset the processor.
- */
- cs461x_reset(card);
-
- cs461x_proc_stop(card);
-
- /*
- * Power down the DAC and ADC. For now leave the other areas on.
- */
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, 0x0300);
-
- /*
- * Power down the PLL.
- */
- cs461x_pokeBA0(card, BA0_CLKCR1, 0);
-
- /*
- * Turn off the Processor by turning off the software clock enable flag in
- * the clock control register.
- */
- tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
- cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
-
- card->active_ctrl(card,-1);
-
- card->pm.flags &= ~CS46XX_PM_SUSPENDING;
- card->pm.flags |= CS46XX_PM_SUSPENDED;
-
- printpm(card);
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
- printk("cs46xx: cs46xx_suspend()- flags=0x%x\n",
- (unsigned)card->pm.flags));
- return 0;
-}
-
-static int cs46xx_resume(struct cs_card *card)
-{
- int i;
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
- printk( "cs46xx: cs46xx_resume()+ flags=0x%x\n",
- (unsigned)card->pm.flags));
- if (!(card->pm.flags & CS46XX_PM_SUSPENDED)) {
- CS_DBGOUT(CS_PM | CS_ERROR, 2,
- printk("cs46xx: cs46xx_resume() unable to resume, not SUSPENDED\n"));
- return 1;
- }
- card->pm.flags |= CS46XX_PM_RESUMING;
- card->pm.flags &= ~CS46XX_PM_SUSPENDED;
- printpm(card);
- card->active_ctrl(card, 1);
-
- for (i = 0; i < 5; i++) {
- if (cs_hardware_init(card) != 0) {
- CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
- "cs46xx: cs46xx_resume()- ERROR in cs_hardware_init()\n"));
- mdelay(10 * cs_laptop_wait);
- cs461x_reset(card);
- continue;
- }
- break;
- }
- if (i >= 4) {
- CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
- "cs46xx: cs46xx_resume()- cs_hardware_init() failed, retried %d times.\n",i));
- return 0;
- }
-
- if (cs46xx_restart_part(card)) {
- CS_DBGOUT(CS_PM | CS_ERROR, 4, printk(
- "cs46xx: cs46xx_resume(): cs46xx_restart_part() returned error\n"));
- }
-
- card->active_ctrl(card, -1);
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4, printk("cs46xx: cs46xx_resume()- flags=0x%x\n",
- (unsigned)card->pm.flags));
- return 0;
-}
-
-static /*const*/ struct file_operations cs461x_fops = {
- CS_OWNER CS_THIS_MODULE
- .llseek = no_llseek,
- .read = cs_read,
- .write = cs_write,
- .poll = cs_poll,
- .ioctl = cs_ioctl,
- .mmap = cs_mmap,
- .open = cs_open,
- .release = cs_release,
-};
-
-/* Write AC97 codec registers */
-
-
-static u16 _cs_ac97_get(struct ac97_codec *dev, u8 reg)
-{
- struct cs_card *card = dev->private_data;
- int count,loopcnt;
- unsigned int tmp;
- u16 ret;
-
- /*
- * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
- * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
- * 3. Write ACCTL = Control Register = 460h for initiating the write
- * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
- * 5. if DCV not cleared, break and return error
- * 6. Read ACSTS = Status Register = 464h, check VSTS bit
- */
-
- cs461x_peekBA0(card, BA0_ACSDA);
-
- /*
- * Setup the AC97 control registers on the CS461x to send the
- * appropriate command to the AC97 to perform the read.
- * ACCAD = Command Address Register = 46Ch
- * ACCDA = Command Data Register = 470h
- * ACCTL = Control Register = 460h
- * set DCV - will clear when process completed
- * set CRW - Read command
- * set VFRM - valid frame enabled
- * set ESYN - ASYNC generation enabled
- * set RSTN - ARST# inactive, AC97 codec not reset
- */
-
- cs461x_pokeBA0(card, BA0_ACCAD, reg);
- cs461x_pokeBA0(card, BA0_ACCDA, 0);
- cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_CRW |
- ACCTL_VFRM | ACCTL_ESYN |
- ACCTL_RSTN);
-
-
- /*
- * Wait for the read to occur.
- */
- if (!(card->pm.flags & CS46XX_PM_IDLE))
- loopcnt = 2000;
- else
- loopcnt = 500 * cs_laptop_wait;
- loopcnt *= cs_laptop_wait;
- for (count = 0; count < loopcnt; count++) {
- /*
- * First, we want to wait for a short time.
- */
- udelay(10 * cs_laptop_wait);
- /*
- * Now, check to see if the read has completed.
- * ACCTL = 460h, DCV should be reset by now and 460h = 17h
- */
- if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
- break;
- }
-
- /*
- * Make sure the read completed.
- */
- if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: AC'97 read problem (ACCTL_DCV), reg = 0x%x returning 0xffff\n", reg));
- return 0xffff;
- }
-
- /*
- * Wait for the valid status bit to go active.
- */
-
- if (!(card->pm.flags & CS46XX_PM_IDLE))
- loopcnt = 2000;
- else
- loopcnt = 1000;
- loopcnt *= cs_laptop_wait;
- for (count = 0; count < loopcnt; count++) {
- /*
- * Read the AC97 status register.
- * ACSTS = Status Register = 464h
- * VSTS - Valid Status
- */
- if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_VSTS)
- break;
- udelay(10 * cs_laptop_wait);
- }
-
- /*
- * Make sure we got valid status.
- */
- if (!((tmp = cs461x_peekBA0(card, BA0_ACSTS)) & ACSTS_VSTS)) {
- CS_DBGOUT(CS_ERROR, 2, printk(KERN_WARNING
- "cs46xx: AC'97 read problem (ACSTS_VSTS), reg = 0x%x val=0x%x 0xffff \n",
- reg, tmp));
- return 0xffff;
- }
-
- /*
- * Read the data returned from the AC97 register.
- * ACSDA = Status Data Register = 474h
- */
- CS_DBGOUT(CS_FUNCTION, 9, printk(KERN_INFO
- "cs46xx: cs_ac97_get() reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n",
- reg, cs461x_peekBA0(card, BA0_ACSDA),
- cs461x_peekBA0(card, BA0_ACCAD)));
- ret = cs461x_peekBA0(card, BA0_ACSDA);
- return ret;
-}
-
-static u16 cs_ac97_get(struct ac97_codec *dev, u8 reg)
-{
- u16 ret;
- struct cs_card *card = dev->private_data;
-
- spin_lock(&card->ac97_lock);
- ret = _cs_ac97_get(dev, reg);
- spin_unlock(&card->ac97_lock);
- return ret;
-}
-
-static void cs_ac97_set(struct ac97_codec *dev, u8 reg, u16 val)
-{
- struct cs_card *card = dev->private_data;
- int count;
- int val2 = 0;
-
- spin_lock(&card->ac97_lock);
-
- if (reg == AC97_CD_VOL)
- val2 = _cs_ac97_get(dev, AC97_CD_VOL);
-
- /*
- * 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
- * 2. Write ACCDA = Command Data Register = 470h for data to write to AC97
- * 3. Write ACCTL = Control Register = 460h for initiating the write
- * 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
- * 5. if DCV not cleared, break and return error
- */
-
- /*
- * Setup the AC97 control registers on the CS461x to send the
- * appropriate command to the AC97 to perform the read.
- * ACCAD = Command Address Register = 46Ch
- * ACCDA = Command Data Register = 470h
- * ACCTL = Control Register = 460h
- * set DCV - will clear when process completed
- * reset CRW - Write command
- * set VFRM - valid frame enabled
- * set ESYN - ASYNC generation enabled
- * set RSTN - ARST# inactive, AC97 codec not reset
- */
- cs461x_pokeBA0(card, BA0_ACCAD, reg);
- cs461x_pokeBA0(card, BA0_ACCDA, val);
- cs461x_peekBA0(card, BA0_ACCTL);
- cs461x_pokeBA0(card, BA0_ACCTL, 0 | ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
- cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_DCV | ACCTL_VFRM |
- ACCTL_ESYN | ACCTL_RSTN);
- for (count = 0; count < 1000; count++) {
- /*
- * First, we want to wait for a short time.
- */
- udelay(10 * cs_laptop_wait);
- /*
- * Now, check to see if the write has completed.
- * ACCTL = 460h, DCV should be reset by now and 460h = 07h
- */
- if (!(cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV))
- break;
- }
- /*
- * Make sure the write completed.
- */
- if (cs461x_peekBA0(card, BA0_ACCTL) & ACCTL_DCV) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val));
- }
-
- spin_unlock(&card->ac97_lock);
-
- /*
- * Adjust power if the mixer is selected/deselected according
- * to the CD.
- *
- * IF the CD is a valid input source (mixer or direct) AND
- * the CD is not muted THEN power is needed
- *
- * We do two things. When record select changes the input to
- * add/remove the CD we adjust the power count if the CD is
- * unmuted.
- *
- * When the CD mute changes we adjust the power level if the
- * CD was a valid input.
- *
- * We also check for CD volume != 0, as the CD mute isn't
- * normally tweaked from userspace.
- */
-
- /* CD mute change ? */
-
- if (reg == AC97_CD_VOL) {
- /* Mute bit change ? */
- if ((val2^val) & 0x8000 ||
- ((val2 == 0x1f1f || val == 0x1f1f) && val2 != val)) {
- /* This is a hack but its cleaner than the alternatives.
- Right now card->ac97_codec[0] might be NULL as we are
- still doing codec setup. This does an early assignment
- to avoid the problem if it occurs */
-
- if (card->ac97_codec[0] == NULL)
- card->ac97_codec[0] = dev;
-
- /* Mute on */
- if (val & 0x8000 || val == 0x1f1f)
- card->amplifier_ctrl(card, -1);
- else { /* Mute off power on */
- if (card->amp_init)
- card->amp_init(card);
- card->amplifier_ctrl(card, 1);
- }
- }
- }
-}
-
-/* OSS /dev/mixer file operation methods */
-
-static int cs_open_mixdev(struct inode *inode, struct file *file)
-{
- int i = 0;
- unsigned int minor = iminor(inode);
- struct cs_card *card = NULL;
- struct list_head *entry;
- unsigned int tmp;
-
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
- printk(KERN_INFO "cs46xx: cs_open_mixdev()+\n"));
-
- list_for_each(entry, &cs46xx_devs) {
- card = list_entry(entry, struct cs_card, list);
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL &&
- card->ac97_codec[i]->dev_mixer == minor)
- goto match;
- }
- if (!card) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
- printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
- return -ENODEV;
- }
- match:
- if (!card->ac97_codec[i])
- return -ENODEV;
- file->private_data = card->ac97_codec[i];
-
- card->active_ctrl(card,1);
- if (!CS_IN_USE(&card->mixer_use_cnt)) {
- if ((tmp = cs46xx_powerup(card, CS_POWER_MIXVON))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs_open_mixdev() powerup failure (0x%x)\n", tmp));
- return -EIO;
- }
- }
- card->amplifier_ctrl(card, 1);
- CS_INC_USE_COUNT(&card->mixer_use_cnt);
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
- printk(KERN_INFO "cs46xx: cs_open_mixdev()- 0\n"));
- return nonseekable_open(inode, file);
-}
-
-static int cs_release_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct cs_card *card = NULL;
- struct list_head *entry;
- int i;
- unsigned int tmp;
-
- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
- printk(KERN_INFO "cs46xx: cs_release_mixdev()+\n"));
- list_for_each(entry, &cs46xx_devs)
- {
- card = list_entry(entry, struct cs_card, list);
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL &&
- card->ac97_codec[i]->dev_mixer == minor)
- goto match;
- }
- if (!card) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
- printk(KERN_INFO "cs46xx: cs46xx_open_mixdev()- -ENODEV\n"));
- return -ENODEV;
- }
-match:
- if (!CS_DEC_AND_TEST(&card->mixer_use_cnt)) {
- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
- printk(KERN_INFO "cs46xx: cs_release_mixdev()- no powerdown, usecnt>0\n"));
- card->active_ctrl(card, -1);
- card->amplifier_ctrl(card, -1);
- return 0;
- }
-/*
-* ok, no outstanding mixer opens, so powerdown.
-*/
- if ((tmp = cs461x_powerdown(card, CS_POWER_MIXVON, CS_FALSE))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs_release_mixdev() powerdown MIXVON failure (0x%x)\n", tmp));
- card->active_ctrl(card, -1);
- card->amplifier_ctrl(card, -1);
- return -EIO;
- }
- card->active_ctrl(card, -1);
- card->amplifier_ctrl(card, -1);
- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4,
- printk(KERN_INFO "cs46xx: cs_release_mixdev()- 0\n"));
- return 0;
-}
-
-static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct ac97_codec *codec = file->private_data;
- struct cs_card *card = NULL;
- struct list_head *entry;
- unsigned long __user *p = (long __user *)arg;
-#if CSDEBUG_INTERFACE
- int val;
-
- if ( (cmd == SOUND_MIXER_CS_GETDBGMASK) ||
- (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
- (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
- (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
- (cmd == SOUND_MIXER_CS_APM)) {
- switch (cmd) {
- case SOUND_MIXER_CS_GETDBGMASK:
- return put_user(cs_debugmask, p);
- case SOUND_MIXER_CS_GETDBGLEVEL:
- return put_user(cs_debuglevel, p);
- case SOUND_MIXER_CS_SETDBGMASK:
- if (get_user(val, p))
- return -EFAULT;
- cs_debugmask = val;
- return 0;
- case SOUND_MIXER_CS_SETDBGLEVEL:
- if (get_user(val, p))
- return -EFAULT;
- cs_debuglevel = val;
- return 0;
- case SOUND_MIXER_CS_APM:
- if (get_user(val, p))
- return -EFAULT;
- if (val == CS_IOCTL_CMD_SUSPEND) {
- list_for_each(entry, &cs46xx_devs) {
- card = list_entry(entry, struct cs_card, list);
- cs46xx_suspend(card, PMSG_ON);
- }
-
- } else if (val == CS_IOCTL_CMD_RESUME) {
- list_for_each(entry, &cs46xx_devs) {
- card = list_entry(entry, struct cs_card, list);
- cs46xx_resume(card);
- }
- } else {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs46xx: mixer_ioctl(): invalid APM cmd (%d)\n",
- val));
- }
- return 0;
- default:
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs46xx: mixer_ioctl(): ERROR unknown debug cmd\n"));
- return 0;
- }
- }
-#endif
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const*/ struct file_operations cs_mixer_fops = {
- CS_OWNER CS_THIS_MODULE
- .llseek = no_llseek,
- .ioctl = cs_ioctl_mixdev,
- .open = cs_open_mixdev,
- .release = cs_release_mixdev,
-};
-
-/* AC97 codec initialisation. */
-static int __init cs_ac97_init(struct cs_card *card)
-{
- int num_ac97 = 0;
- int ready_2nd = 0;
- struct ac97_codec *codec;
- u16 eid;
-
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_ac97_init()+\n") );
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- /* initialize some basic codec information, other fields will be filled
- in ac97_probe_codec */
- codec->private_data = card;
- codec->id = num_ac97;
-
- codec->codec_read = cs_ac97_get;
- codec->codec_write = cs_ac97_set;
-
- if (ac97_probe_codec(codec) == 0) {
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_ac97_init()- codec number %d not found\n",
- num_ac97) );
- card->ac97_codec[num_ac97] = NULL;
- break;
- }
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_ac97_init() found codec %d\n",num_ac97));
-
- eid = cs_ac97_get(codec, AC97_EXTENDED_ID);
-
- if (eid == 0xFFFF) {
- printk(KERN_WARNING "cs46xx: codec %d not present\n",num_ac97);
- ac97_release_codec(codec);
- break;
- }
-
- card->ac97_features = eid;
-
- if ((codec->dev_mixer = register_sound_mixer(&cs_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "cs46xx: couldn't register mixer!\n");
- ac97_release_codec(codec);
- break;
- }
- card->ac97_codec[num_ac97] = codec;
-
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_ac97_init() ac97_codec[%d] set to %p\n",
- (unsigned int)num_ac97,
- codec));
- /* if there is no secondary codec at all, don't probe any more */
- if (!ready_2nd)
- {
- num_ac97 += 1;
- break;
- }
- }
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_ac97_init()- %d\n", (unsigned int)num_ac97));
- return num_ac97;
-}
-
-/*
- * load the static image into the DSP
- */
-#include "cs461x_image.h"
-static void cs461x_download_image(struct cs_card *card)
-{
- unsigned i, j, temp1, temp2, offset, count;
- unsigned char __iomem *pBA1 = ioremap(card->ba1_addr, 0x40000);
- for (i = 0; i < CLEAR__COUNT; i++) {
- offset = ClrStat[i].BA1__DestByteOffset;
- count = ClrStat[i].BA1__SourceSize;
- for (temp1 = offset; temp1 < (offset + count); temp1 += 4)
- writel(0, pBA1+temp1);
- }
-
- for (i = 0; i < FILL__COUNT; i++) {
- temp2 = FillStat[i].Offset;
- for (j = 0; j < (FillStat[i].Size) / 4; j++) {
- temp1 = (FillStat[i]).pFill[j];
- writel(temp1, pBA1+temp2 + j * 4);
- }
- }
- iounmap(pBA1);
-}
-
-/*
- * Chip reset
- */
-
-static void cs461x_reset(struct cs_card *card)
-{
- int idx;
-
- /*
- * Write the reset bit of the SP control register.
- */
- cs461x_poke(card, BA1_SPCR, SPCR_RSTSP);
-
- /*
- * Write the control register.
- */
- cs461x_poke(card, BA1_SPCR, SPCR_DRQEN);
-
- /*
- * Clear the trap registers.
- */
- for (idx = 0; idx < 8; idx++) {
- cs461x_poke(card, BA1_DREG, DREG_REGID_TRAP_SELECT + idx);
- cs461x_poke(card, BA1_TWPR, 0xFFFF);
- }
- cs461x_poke(card, BA1_DREG, 0);
-
- /*
- * Set the frame timer to reflect the number of cycles per frame.
- */
- cs461x_poke(card, BA1_FRMT, 0xadf);
-}
-
-static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type)
-{
- int idx, loop, startfifo=0, endfifo=0, powerdown1 = 0;
- unsigned int tmp;
-
- /*
- * See if the devices are powered down. If so, we must power them up first
- * or they will not respond.
- */
- if (!((tmp = cs461x_peekBA0(card, BA0_CLKCR1)) & CLKCR1_SWCE)) {
- cs461x_pokeBA0(card, BA0_CLKCR1, tmp | CLKCR1_SWCE);
- powerdown1 = 1;
- }
-
- /*
- * We want to clear out the serial port FIFOs so we don't end up playing
- * whatever random garbage happens to be in them. We fill the sample FIFOS
- * with zero (silence).
- */
- cs461x_pokeBA0(card, BA0_SERBWP, 0);
-
- /*
- * Check for which FIFO locations to clear, if we are currently
- * playing or capturing then we don't want to put in 128 bytes of
- * "noise".
- */
- if (type & CS_TYPE_DAC) {
- startfifo = 128;
- endfifo = 256;
- }
- if (type & CS_TYPE_ADC) {
- startfifo = 0;
- if (!endfifo)
- endfifo = 128;
- }
- /*
- * Fill sample FIFO locations (256 locations total).
- */
- for (idx = startfifo; idx < endfifo; idx++) {
- /*
- * Make sure the previous FIFO write operation has completed.
- */
- for (loop = 0; loop < 5; loop++) {
- udelay(50);
- if (!(cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY))
- break;
- }
- if (cs461x_peekBA0(card, BA0_SERBST) & SERBST_WBSY) {
- if (powerdown1)
- cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
- }
- /*
- * Write the serial port FIFO index.
- */
- cs461x_pokeBA0(card, BA0_SERBAD, idx);
- /*
- * Tell the serial port to load the new value into the FIFO location.
- */
- cs461x_pokeBA0(card, BA0_SERBCM, SERBCM_WRC);
- }
- /*
- * Now, if we powered up the devices, then power them back down again.
- * This is kinda ugly, but should never happen.
- */
- if (powerdown1)
- cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
-}
-
-
-static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag)
-{
- int count;
- unsigned int tmp=0,muted=0;
-
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
- "cs46xx: cs461x_powerdown()+ type=0x%x\n",type));
- if (!cs_powerdown && !suspendflag) {
- CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
- "cs46xx: cs461x_powerdown() DISABLED exiting\n"));
- return 0;
- }
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
- "cs46xx: cs461x_powerdown() powerdown reg=0x%x\n",tmp));
-/*
-* if powering down only the VREF, and not powering down the DAC/ADC,
-* then do not power down the VREF, UNLESS both the DAC and ADC are not
-* currently powered down. If powering down DAC and ADC, then
-* it is possible to power down the VREF (ON).
-*/
- if (((type & CS_POWER_MIXVON) &&
- (!(type & CS_POWER_ADC) || (!(type & CS_POWER_DAC))))
- &&
- ((tmp & CS_AC97_POWER_CONTROL_ADC_ON) ||
- (tmp & CS_AC97_POWER_CONTROL_DAC_ON))) {
- CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
- "cs46xx: cs461x_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp));
- return 0;
- }
-/*
-* for now, always keep power to the mixer block.
-* not sure why it's a problem but it seems to be if we power off.
-*/
- type &= ~CS_POWER_MIXVON;
- type &= ~CS_POWER_MIXVOFF;
-
- /*
- * Power down indicated areas.
- */
- if (type & CS_POWER_MIXVOFF) {
-
- CS_DBGOUT(CS_FUNCTION, 4,
- printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVOFF\n"));
- /*
- * Power down the MIXER (VREF ON) on the AC97 card.
- */
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp |= CS_AC97_POWER_CONTROL_MIXVOFF;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVOFF_ON))
- break;
- }
-
- /*
- * Check the status..
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVOFF_ON) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerdown MIXVOFF failed\n"));
- return 1;
- }
- }
- }
- if (type & CS_POWER_MIXVON) {
-
- CS_DBGOUT(CS_FUNCTION, 4,
- printk(KERN_INFO "cs46xx: cs461x_powerdown()+ MIXVON\n"));
- /*
- * Power down the MIXER (VREF ON) on the AC97 card.
- */
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_MIXVON_ON) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp |= CS_AC97_POWER_CONTROL_MIXVON;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVON_ON))
- break;
- }
-
- /*
- * Check the status..
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVON_ON) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerdown MIXVON failed\n"));
- return 1;
- }
- }
- }
- if (type & CS_POWER_ADC) {
- /*
- * Power down the ADC on the AC97 card.
- */
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs461x_powerdown()+ ADC\n"));
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_ADC_ON) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp |= CS_AC97_POWER_CONTROL_ADC;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
-
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_ADC_ON))
- break;
- }
-
- /*
- * Check the status..
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_ADC_ON) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerdown ADC failed\n"));
- return 1;
- }
- }
- }
- if (type & CS_POWER_DAC) {
- /*
- * Power down the DAC on the AC97 card.
- */
-
- CS_DBGOUT(CS_FUNCTION, 4,
- printk(KERN_INFO "cs46xx: cs461x_powerdown()+ DAC\n"));
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (tmp & CS_AC97_POWER_CONTROL_DAC_ON) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp |= CS_AC97_POWER_CONTROL_DAC;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp);
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_DAC_ON))
- break;
- }
-
- /*
- * Check the status..
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_DAC_ON) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerdown DAC failed\n"));
- return 1;
- }
- }
- }
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (muted)
- cs_mute(card, CS_FALSE);
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
- "cs46xx: cs461x_powerdown()- 0 tmp=0x%x\n",tmp));
- return 0;
-}
-
-static int cs46xx_powerup(struct cs_card *card, unsigned int type)
-{
- int count;
- unsigned int tmp = 0, muted = 0;
-
- CS_DBGOUT(CS_FUNCTION, 8, printk(KERN_INFO
- "cs46xx: cs46xx_powerup()+ type=0x%x\n",type));
- /*
- * check for VREF and powerup if need to.
- */
- if (type & CS_POWER_MIXVON)
- type |= CS_POWER_MIXVOFF;
- if (type & (CS_POWER_DAC | CS_POWER_ADC))
- type |= CS_POWER_MIXVON | CS_POWER_MIXVOFF;
-
- /*
- * Power up indicated areas.
- */
- if (type & CS_POWER_MIXVOFF) {
-
- CS_DBGOUT(CS_FUNCTION, 4,
- printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVOFF\n"));
- /*
- * Power up the MIXER (VREF ON) on the AC97 card.
- */
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp &= ~CS_AC97_POWER_CONTROL_MIXVOFF;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVOFF_ON)
- break;
- }
-
- /*
- * Check the status..
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVOFF_ON)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerup MIXVOFF failed\n"));
- return 1;
- }
- }
- }
- if(type & CS_POWER_MIXVON) {
-
- CS_DBGOUT(CS_FUNCTION, 4,
- printk(KERN_INFO "cs46xx: cs46xx_powerup()+ MIXVON\n"));
- /*
- * Power up the MIXER (VREF ON) on the AC97 card.
- */
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_MIXVON_ON)) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp &= ~CS_AC97_POWER_CONTROL_MIXVON;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVON_ON)
- break;
- }
-
- /*
- * Check the status..
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_MIXVON_ON)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerup MIXVON failed\n"));
- return 1;
- }
- }
- }
- if (type & CS_POWER_ADC) {
- /*
- * Power up the ADC on the AC97 card.
- */
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO "cs46xx: cs46xx_powerup()+ ADC\n"));
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_ADC_ON)) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp &= ~CS_AC97_POWER_CONTROL_ADC;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
-
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_ADC_ON)
- break;
- }
-
- /*
- * Check the status..
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_ADC_ON)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerup ADC failed\n"));
- return 1;
- }
- }
- }
- if (type & CS_POWER_DAC) {
- /*
- * Power up the DAC on the AC97 card.
- */
-
- CS_DBGOUT(CS_FUNCTION, 4,
- printk(KERN_INFO "cs46xx: cs46xx_powerup()+ DAC\n"));
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (!(tmp & CS_AC97_POWER_CONTROL_DAC_ON)) {
- if (!muted) {
- cs_mute(card, CS_TRUE);
- muted = 1;
- }
- tmp &= ~CS_AC97_POWER_CONTROL_DAC;
- cs_ac97_set(card->ac97_codec[0], AC97_POWER_CONTROL, tmp );
- /*
- * Now, we wait until we sample a ready state.
- */
- for (count = 0; count < 32; count++) {
- /*
- * First, lets wait a short while to let things settle out a
- * bit, and to prevent retrying the read too quickly.
- */
- udelay(500);
-
- /*
- * Read the current state of the power control register.
- */
- if (cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_DAC_ON)
- break;
- }
-
- /*
- * Check the status..
- */
- if (!(cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL) &
- CS_AC97_POWER_CONTROL_DAC_ON)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING
- "cs46xx: powerup DAC failed\n"));
- return 1;
- }
- }
- }
- tmp = cs_ac97_get(card->ac97_codec[0], AC97_POWER_CONTROL);
- if (muted)
- cs_mute(card, CS_FALSE);
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
- "cs46xx: cs46xx_powerup()- 0 tmp=0x%x\n",tmp));
- return 0;
-}
-
-static void cs461x_proc_start(struct cs_card *card)
-{
- int cnt;
-
- /*
- * Set the frame timer to reflect the number of cycles per frame.
- */
- cs461x_poke(card, BA1_FRMT, 0xadf);
- /*
- * Turn on the run, run at frame, and DMA enable bits in the local copy of
- * the SP control register.
- */
- cs461x_poke(card, BA1_SPCR, SPCR_RUN | SPCR_RUNFR | SPCR_DRQEN);
- /*
- * Wait until the run at frame bit resets itself in the SP control
- * register.
- */
- for (cnt = 0; cnt < 25; cnt++) {
- udelay(50);
- if (!(cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR))
- break;
- }
-
- if (cs461x_peek(card, BA1_SPCR) & SPCR_RUNFR)
- printk(KERN_WARNING "cs46xx: SPCR_RUNFR never reset\n");
-}
-
-static void cs461x_proc_stop(struct cs_card *card)
-{
- /*
- * Turn off the run, run at frame, and DMA enable bits in the local copy of
- * the SP control register.
- */
- cs461x_poke(card, BA1_SPCR, 0);
-}
-
-static int cs_hardware_init(struct cs_card *card)
-{
- unsigned long end_time;
- unsigned int tmp,count;
-
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_hardware_init()+\n") );
- /*
- * First, blast the clock control register to zero so that the PLL starts
- * out in a known state, and blast the master serial port control register
- * to zero so that the serial ports also start out in a known state.
- */
- cs461x_pokeBA0(card, BA0_CLKCR1, 0);
- cs461x_pokeBA0(card, BA0_SERMC1, 0);
-
- /*
- * If we are in AC97 mode, then we must set the part to a host controlled
- * AC-link. Otherwise, we won't be able to bring up the link.
- */
- cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_1_03); /* 1.03 card */
- /* cs461x_pokeBA0(card, BA0_SERACC, SERACC_HSP | SERACC_CODEC_TYPE_2_0); */ /* 2.00 card */
-
- /*
- * Drive the ARST# pin low for a minimum of 1uS (as defined in the AC97
- * spec) and then drive it high. This is done for non AC97 modes since
- * there might be logic external to the CS461x that uses the ARST# line
- * for a reset.
- */
- cs461x_pokeBA0(card, BA0_ACCTL, 1);
- udelay(50);
- cs461x_pokeBA0(card, BA0_ACCTL, 0);
- udelay(50);
- cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_RSTN);
-
- /*
- * The first thing we do here is to enable sync generation. As soon
- * as we start receiving bit clock, we'll start producing the SYNC
- * signal.
- */
- cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
-
- /*
- * Now wait for a short while to allow the AC97 part to start
- * generating bit clock (so we don't try to start the PLL without an
- * input clock).
- */
- mdelay(5 * cs_laptop_wait); /* 1 should be enough ?? (and pigs might fly) */
-
- /*
- * Set the serial port timing configuration, so that
- * the clock control circuit gets its clock from the correct place.
- */
- cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97);
-
- /*
- * The part seems to not be ready for a while after a resume.
- * so, if we are resuming, then wait for 700 mils. Note that 600 mils
- * is not enough for some platforms! tested on an IBM Thinkpads and
- * reference cards.
- */
- if (!(card->pm.flags & CS46XX_PM_IDLE))
- mdelay(initdelay);
- /*
- * Write the selected clock control setup to the hardware. Do not turn on
- * SWCE yet (if requested), so that the devices clocked by the output of
- * PLL are not clocked until the PLL is stable.
- */
- cs461x_pokeBA0(card, BA0_PLLCC, PLLCC_LPF_1050_2780_KHZ | PLLCC_CDR_73_104_MHZ);
- cs461x_pokeBA0(card, BA0_PLLM, 0x3a);
- cs461x_pokeBA0(card, BA0_CLKCR2, CLKCR2_PDIVS_8);
-
- /*
- * Power up the PLL.
- */
- cs461x_pokeBA0(card, BA0_CLKCR1, CLKCR1_PLLP);
-
- /*
- * Wait until the PLL has stabilized.
- */
- mdelay(5 * cs_laptop_wait); /* Again 1 should be enough ?? */
-
- /*
- * Turn on clocking of the core so that we can setup the serial ports.
- */
- tmp = cs461x_peekBA0(card, BA0_CLKCR1) | CLKCR1_SWCE;
- cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
-
- /*
- * Fill the serial port FIFOs with silence.
- */
- cs461x_clear_serial_FIFOs(card,CS_TYPE_DAC | CS_TYPE_ADC);
-
- /*
- * Set the serial port FIFO pointer to the first sample in the FIFO.
- */
- /* cs461x_pokeBA0(card, BA0_SERBSP, 0); */
-
- /*
- * Write the serial port configuration to the part. The master
- * enable bit is not set until all other values have been written.
- */
- cs461x_pokeBA0(card, BA0_SERC1, SERC1_SO1F_AC97 | SERC1_SO1EN);
- cs461x_pokeBA0(card, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
- cs461x_pokeBA0(card, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
-
-
- mdelay(5 * cs_laptop_wait); /* Shouldnt be needed ?? */
-
-/*
-* If we are resuming under 2.2.x then we cannot schedule a timeout,
-* so just spin the CPU.
-*/
- if (card->pm.flags & CS46XX_PM_IDLE) {
- /*
- * Wait for the card ready signal from the AC97 card.
- */
- end_time = jiffies + 3 * (HZ >> 2);
- do {
- /*
- * Read the AC97 status register to see if we've seen a CODEC READY
- * signal from the AC97 card.
- */
- if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
- break;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(1);
- } while (time_before(jiffies, end_time));
- } else {
- for (count = 0; count < 100; count++) {
- // First, we want to wait for a short time.
- udelay(25 * cs_laptop_wait);
-
- if (cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)
- break;
- }
- }
-
- /*
- * Make sure CODEC is READY.
- */
- if (!(cs461x_peekBA0(card, BA0_ACSTS) & ACSTS_CRDY)) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
- "cs46xx: create - never read card ready from AC'97\n"));
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
- "cs46xx: probably not a bug, try using the CS4232 driver,\n"));
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_WARNING
- "cs46xx: or turn off any automatic Power Management support in the BIOS.\n"));
- return -EIO;
- }
-
- /*
- * Assert the vaid frame signal so that we can start sending commands
- * to the AC97 card.
- */
- cs461x_pokeBA0(card, BA0_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
-
- if (card->pm.flags & CS46XX_PM_IDLE) {
- /*
- * Wait until we've sampled input slots 3 and 4 as valid, meaning that
- * the card is pumping ADC data across the AC-link.
- */
- end_time = jiffies + 3 * (HZ >> 2);
- do {
- /*
- * Read the input slot valid register and see if input slots 3 and
- * 4 are valid yet.
- */
- if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
- break;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(1);
- } while (time_before(jiffies, end_time));
- } else {
- for (count = 0; count < 100; count++) {
- // First, we want to wait for a short time.
- udelay(25 * cs_laptop_wait);
-
- if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) == (ACISV_ISV3 | ACISV_ISV4))
- break;
- }
- }
- /*
- * Make sure input slots 3 and 4 are valid. If not, then return
- * an error.
- */
- if ((cs461x_peekBA0(card, BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) != (ACISV_ISV3 | ACISV_ISV4)) {
- printk(KERN_WARNING "cs46xx: create - never read ISV3 & ISV4 from AC'97\n");
- return -EIO;
- }
-
- /*
- * Now, assert valid frame and the slot 3 and 4 valid bits. This will
- * commense the transfer of digital audio data to the AC97 card.
- */
- cs461x_pokeBA0(card, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
-
- /*
- * Turn off the Processor by turning off the software clock enable flag in
- * the clock control register.
- */
- /* tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE; */
- /* cs461x_pokeBA0(card, BA0_CLKCR1, tmp); */
-
- /*
- * Reset the processor.
- */
- cs461x_reset(card);
-
- /*
- * Download the image to the processor.
- */
-
- cs461x_download_image(card);
-
- /*
- * Stop playback DMA.
- */
- tmp = cs461x_peek(card, BA1_PCTL);
- card->pctl = tmp & 0xffff0000;
- cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
-
- /*
- * Stop capture DMA.
- */
- tmp = cs461x_peek(card, BA1_CCTL);
- card->cctl = tmp & 0x0000ffff;
- cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
-
- /* initialize AC97 codec and register /dev/mixer */
- if (card->pm.flags & CS46XX_PM_IDLE) {
- if (cs_ac97_init(card) <= 0) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs_ac97_init() failure\n"));
- return -EIO;
- }
- } else {
- cs46xx_ac97_resume(card);
- }
-
- cs461x_proc_start(card);
-
- /*
- * Enable interrupts on the part.
- */
- cs461x_pokeBA0(card, BA0_HICR, HICR_IEV | HICR_CHGM);
-
- tmp = cs461x_peek(card, BA1_PFIE);
- tmp &= ~0x0000f03f;
- cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt enable */
-
- tmp = cs461x_peek(card, BA1_CIE);
- tmp &= ~0x0000003f;
- tmp |= 0x00000001;
- cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt enable */
-
- /*
- * If IDLE then Power down the part. We will power components up
- * when we need them.
- */
- if (card->pm.flags & CS46XX_PM_IDLE) {
- if (!cs_powerdown) {
- if ((tmp = cs46xx_powerup(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs461x_powerup() failure (0x%x)\n",tmp) );
- return -EIO;
- }
- } else {
- if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON, CS_FALSE))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
- return -EIO;
- }
- }
- }
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO
- "cs46xx: cs_hardware_init()- 0\n"));
- return 0;
-}
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
- until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
-
-/*
- * Card subid table
- */
-
-struct cs_card_type
-{
- u16 vendor;
- u16 id;
- char *name;
- void (*amp)(struct cs_card *, int);
- void (*amp_init)(struct cs_card *);
- void (*active)(struct cs_card *, int);
-};
-
-static struct cs_card_type cards[] = {
- {
- .vendor = 0x1489,
- .id = 0x7001,
- .name = "Genius Soundmaker 128 value",
- .amp = amp_none,
- },
- {
- .vendor = 0x5053,
- .id = 0x3357,
- .name = "Voyetra",
- .amp = amp_voyetra,
- },
- {
- .vendor = 0x1071,
- .id = 0x6003,
- .name = "Mitac MI6020/21",
- .amp = amp_voyetra,
- },
- {
- .vendor = 0x14AF,
- .id = 0x0050,
- .name = "Hercules Game Theatre XP",
- .amp = amp_hercules,
- },
- {
- .vendor = 0x1681,
- .id = 0x0050,
- .name = "Hercules Game Theatre XP",
- .amp = amp_hercules,
- },
- {
- .vendor = 0x1681,
- .id = 0x0051,
- .name = "Hercules Game Theatre XP",
- .amp = amp_hercules,
- },
- {
- .vendor = 0x1681,
- .id = 0x0052,
- .name = "Hercules Game Theatre XP",
- .amp = amp_hercules,
- },
- {
- .vendor = 0x1681,
- .id = 0x0053,
- .name = "Hercules Game Theatre XP",
- .amp = amp_hercules,
- },
- {
- .vendor = 0x1681,
- .id = 0x0054,
- .name = "Hercules Game Theatre XP",
- .amp = amp_hercules,
- },
- {
- .vendor = 0x1681,
- .id = 0xa010,
- .name = "Hercules Fortissimo II",
- .amp = amp_none,
- },
- /* Not sure if the 570 needs the clkrun hack */
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .id = 0x0132,
- .name = "Thinkpad 570",
- .amp = amp_none,
- .active = clkrun_hack,
- },
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .id = 0x0153,
- .name = "Thinkpad 600X/A20/T20",
- .amp = amp_none,
- .active = clkrun_hack,
- },
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .id = 0x1010,
- .name = "Thinkpad 600E (unsupported)",
- },
- {
- .name = "Card without SSID set",
- },
- { 0, },
-};
-
-MODULE_AUTHOR("Alan Cox <alan@redhat.com>, Jaroslav Kysela, <pcaudio@crystal.cirrus.com>");
-MODULE_DESCRIPTION("Crystal SoundFusion Audio Support");
-MODULE_LICENSE("GPL");
-
-static const char cs46xx_banner[] = KERN_INFO "Crystal 4280/46xx + AC97 Audio, version " CS46XX_MAJOR_VERSION "." CS46XX_MINOR_VERSION "." CS46XX_ARCH ", " __TIME__ " " __DATE__ "\n";
-static const char fndmsg[] = KERN_INFO "cs46xx: Found %d audio device(s).\n";
-
-static int __devinit cs46xx_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pciid)
-{
- int i, j;
- u16 ss_card, ss_vendor;
- struct cs_card *card;
- dma_addr_t dma_mask;
- struct cs_card_type *cp = &cards[0];
-
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
- printk(KERN_INFO "cs46xx: probe()+\n"));
-
- dma_mask = 0xffffffff; /* this enables playback and recording */
- if (pci_enable_device(pci_dev)) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs46xx: pci_enable_device() failed\n"));
- return -1;
- }
- if (!RSRCISMEMORYREGION(pci_dev, 0) ||
- !RSRCISMEMORYREGION(pci_dev, 1)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs46xx: probe()- Memory region not assigned\n"));
- return -1;
- }
- if (pci_dev->irq == 0) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs46xx: probe() IRQ not assigned\n"));
- return -1;
- }
- if (!pci_dma_supported(pci_dev, 0xffffffff)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs46xx: probe() architecture does not support 32bit PCI busmaster DMA\n"));
- return -1;
- }
- pci_read_config_word(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor);
- pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &ss_card);
-
- if ((card = kzalloc(sizeof(struct cs_card), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "cs46xx: out of memory\n");
- return -ENOMEM;
- }
- card->ba0_addr = RSRCADDRESS(pci_dev, 0);
- card->ba1_addr = RSRCADDRESS(pci_dev, 1);
- card->pci_dev = pci_dev;
- card->irq = pci_dev->irq;
- card->magic = CS_CARD_MAGIC;
- spin_lock_init(&card->lock);
- spin_lock_init(&card->ac97_lock);
-
- pci_set_master(pci_dev);
-
- printk(cs46xx_banner);
- printk(KERN_INFO "cs46xx: Card found at 0x%08lx and 0x%08lx, IRQ %d\n",
- card->ba0_addr, card->ba1_addr, card->irq);
-
- card->alloc_pcm_channel = cs_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = cs_alloc_rec_pcm_channel;
- card->free_pcm_channel = cs_free_pcm_channel;
- card->amplifier_ctrl = amp_none;
- card->active_ctrl = amp_none;
-
- while (cp->name)
- {
- if (cp->vendor == ss_vendor && cp->id == ss_card) {
- card->amplifier_ctrl = cp->amp;
- if (cp->active)
- card->active_ctrl = cp->active;
- if (cp->amp_init)
- card->amp_init = cp->amp_init;
- break;
- }
- cp++;
- }
- if (cp->name == NULL) {
- printk(KERN_INFO "cs46xx: Unknown card (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
- ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
- } else {
- printk(KERN_INFO "cs46xx: %s (%04X:%04X) at 0x%08lx/0x%08lx, IRQ %d\n",
- cp->name, ss_vendor, ss_card, card->ba0_addr, card->ba1_addr, card->irq);
- }
-
- if (card->amplifier_ctrl == NULL) {
- card->amplifier_ctrl = amp_none;
- card->active_ctrl = clkrun_hack;
- }
-
- if (external_amp == 1) {
- printk(KERN_INFO "cs46xx: Crystal EAPD support forced on.\n");
- card->amplifier_ctrl = amp_voyetra;
- }
-
- if (thinkpad == 1) {
- printk(KERN_INFO "cs46xx: Activating CLKRUN hack for Thinkpad.\n");
- card->active_ctrl = clkrun_hack;
- }
-/*
-* The thinkpads don't work well without runtime updating on their kernel
-* delay values (or any laptop with variable CPU speeds really).
-* so, just to be safe set the init delay to 2100. Eliminates
-* failures on T21 Thinkpads. remove this code when the udelay
-* and mdelay kernel code is replaced by a pm timer, or the delays
-* work well for battery and/or AC power both.
-*/
- if (card->active_ctrl == clkrun_hack) {
- initdelay = 2100;
- cs_laptop_wait = 5;
- }
- if ((card->active_ctrl == clkrun_hack) && !(powerdown == 1)) {
-/*
-* for some currently unknown reason, powering down the DAC and ADC component
-* blocks on thinkpads causes some funky behavior... distoorrrtion and ac97
-* codec access problems. probably the serial clock becomes unsynced.
-* added code to sync the chips back up, but only helped about 70% the time.
-*/
- cs_powerdown = 0;
- }
- if (powerdown == 0)
- cs_powerdown = 0;
- card->active_ctrl(card, 1);
-
- /* claim our iospace and irq */
-
- card->ba0 = ioremap_nocache(card->ba0_addr, CS461X_BA0_SIZE);
- card->ba1.name.data0 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
- card->ba1.name.data1 = ioremap_nocache(card->ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
- card->ba1.name.pmem = ioremap_nocache(card->ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
- card->ba1.name.reg = ioremap_nocache(card->ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
- CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
- "cs46xx: card=%p card->ba0=%p\n",card,card->ba0) );
- CS_DBGOUT(CS_INIT, 4, printk(KERN_INFO
- "cs46xx: card->ba1=%p %p %p %p\n",
- card->ba1.name.data0,
- card->ba1.name.data1,
- card->ba1.name.pmem,
- card->ba1.name.reg) );
-
- if (card->ba0 == 0 || card->ba1.name.data0 == 0 ||
- card->ba1.name.data1 == 0 || card->ba1.name.pmem == 0 ||
- card->ba1.name.reg == 0)
- goto fail2;
-
- if (request_irq(card->irq, &cs_interrupt, IRQF_SHARED, "cs46xx", card)) {
- printk(KERN_ERR "cs46xx: unable to allocate irq %d\n", card->irq);
- goto fail2;
- }
- /* register /dev/dsp */
- if ((card->dev_audio = register_sound_dsp(&cs461x_fops, -1)) < 0) {
- printk(KERN_ERR "cs46xx: unable to register dsp\n");
- goto fail;
- }
-
- /* register /dev/midi */
- if ((card->dev_midi = register_sound_midi(&cs_midi_fops, -1)) < 0)
- printk(KERN_ERR "cs46xx: unable to register midi\n");
-
- card->pm.flags |= CS46XX_PM_IDLE;
- for (i = 0; i < 5; i++) {
- if (cs_hardware_init(card) != 0) {
- CS_DBGOUT(CS_ERROR, 4, printk(
- "cs46xx: ERROR in cs_hardware_init()... retrying\n"));
- for (j = 0; j < NR_AC97; j++)
- if (card->ac97_codec[j] != NULL) {
- unregister_sound_mixer(card->ac97_codec[j]->dev_mixer);
- ac97_release_codec(card->ac97_codec[j]);
- }
- mdelay(10 * cs_laptop_wait);
- continue;
- }
- break;
- }
- if(i >= 4) {
- CS_DBGOUT(CS_PM | CS_ERROR, 1, printk(
- "cs46xx: cs46xx_probe()- cs_hardware_init() failed, retried %d times.\n",i));
- unregister_sound_dsp(card->dev_audio);
- if (card->dev_midi)
- unregister_sound_midi(card->dev_midi);
- goto fail;
- }
-
- init_waitqueue_head(&card->midi.open_wait);
- mutex_init(&card->midi.open_mutex);
- init_waitqueue_head(&card->midi.iwait);
- init_waitqueue_head(&card->midi.owait);
- cs461x_pokeBA0(card, BA0_MIDCR, MIDCR_MRST);
- cs461x_pokeBA0(card, BA0_MIDCR, 0);
-
- /*
- * Check if we have to init the amplifier, but probably already done
- * since the CD logic in the ac97 init code will turn on the ext amp.
- */
- if (cp->amp_init)
- cp->amp_init(card);
- card->active_ctrl(card, -1);
-
- PCI_SET_DRIVER_DATA(pci_dev, card);
- PCI_SET_DMA_MASK(pci_dev, dma_mask);
- list_add(&card->list, &cs46xx_devs);
-
- CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "cs46xx: pm.flags=0x%x card=%p\n",
- (unsigned)card->pm.flags,card));
-
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs46xx: probe()- device allocated successfully\n"));
- return 0;
-
-fail:
- free_irq(card->irq, card);
-fail2:
- if (card->ba0)
- iounmap(card->ba0);
- if (card->ba1.name.data0)
- iounmap(card->ba1.name.data0);
- if (card->ba1.name.data1)
- iounmap(card->ba1.name.data1);
- if (card->ba1.name.pmem)
- iounmap(card->ba1.name.pmem);
- if (card->ba1.name.reg)
- iounmap(card->ba1.name.reg);
- kfree(card);
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
- "cs46xx: probe()- no device allocated\n"));
- return -ENODEV;
-} // probe_cs46xx
-
-// ---------------------------------------------------------------------
-
-static void __devexit cs46xx_remove(struct pci_dev *pci_dev)
-{
- struct cs_card *card = PCI_GET_DRIVER_DATA(pci_dev);
- int i;
- unsigned int tmp;
-
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs46xx: cs46xx_remove()+\n"));
-
- card->active_ctrl(card,1);
-
- tmp = cs461x_peek(card, BA1_PFIE);
- tmp &= ~0x0000f03f;
- tmp |= 0x00000010;
- cs461x_poke(card, BA1_PFIE, tmp); /* playback interrupt disable */
-
- tmp = cs461x_peek(card, BA1_CIE);
- tmp &= ~0x0000003f;
- tmp |= 0x00000011;
- cs461x_poke(card, BA1_CIE, tmp); /* capture interrupt disable */
-
- /*
- * Stop playback DMA.
- */
- tmp = cs461x_peek(card, BA1_PCTL);
- cs461x_poke(card, BA1_PCTL, tmp & 0x0000ffff);
-
- /*
- * Stop capture DMA.
- */
- tmp = cs461x_peek(card, BA1_CCTL);
- cs461x_poke(card, BA1_CCTL, tmp & 0xffff0000);
-
- /*
- * Reset the processor.
- */
- cs461x_reset(card);
-
- cs461x_proc_stop(card);
-
- /*
- * Power down the DAC and ADC. We will power them up (if) when we need
- * them.
- */
- if ((tmp = cs461x_powerdown(card, CS_POWER_DAC | CS_POWER_ADC |
- CS_POWER_MIXVON, CS_TRUE))) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO
- "cs46xx: cs461x_powerdown() failure (0x%x)\n",tmp) );
- }
-
- /*
- * Power down the PLL.
- */
- cs461x_pokeBA0(card, BA0_CLKCR1, 0);
-
- /*
- * Turn off the Processor by turning off the software clock enable flag in
- * the clock control register.
- */
- tmp = cs461x_peekBA0(card, BA0_CLKCR1) & ~CLKCR1_SWCE;
- cs461x_pokeBA0(card, BA0_CLKCR1, tmp);
-
- card->active_ctrl(card,-1);
-
- /* free hardware resources */
- free_irq(card->irq, card);
- iounmap(card->ba0);
- iounmap(card->ba1.name.data0);
- iounmap(card->ba1.name.data1);
- iounmap(card->ba1.name.pmem);
- iounmap(card->ba1.name.reg);
-
- /* unregister audio devices */
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- ac97_release_codec(card->ac97_codec[i]);
- }
- unregister_sound_dsp(card->dev_audio);
- if (card->dev_midi)
- unregister_sound_midi(card->dev_midi);
- list_del(&card->list);
- kfree(card);
- PCI_SET_DRIVER_DATA(pci_dev,NULL);
-
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs46xx: cs46xx_remove()-: remove successful\n"));
-}
-
-enum {
- CS46XX_4610 = 0,
- CS46XX_4612, /* same as 4630 */
- CS46XX_4615, /* same as 4624 */
-};
-
-static struct pci_device_id cs46xx_pci_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_CIRRUS,
- .device = PCI_DEVICE_ID_CIRRUS_4610,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = CS46XX_4610,
- },
- {
- .vendor = PCI_VENDOR_ID_CIRRUS,
- .device = PCI_DEVICE_ID_CIRRUS_4612,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = CS46XX_4612,
- },
- {
- .vendor = PCI_VENDOR_ID_CIRRUS,
- .device = PCI_DEVICE_ID_CIRRUS_4615,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = CS46XX_4615,
- },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, cs46xx_pci_tbl);
-
-static struct pci_driver cs46xx_pci_driver = {
- .name = "cs46xx",
- .id_table = cs46xx_pci_tbl,
- .probe = cs46xx_probe,
- .remove = __devexit_p(cs46xx_remove),
-#ifdef CONFIG_PM
- .suspend = cs46xx_suspend_tbl,
- .resume = cs46xx_resume_tbl,
-#endif
-};
-
-static int __init cs46xx_init_module(void)
-{
- int rtn = 0;
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs46xx: cs46xx_init_module()+ \n"));
- rtn = pci_register_driver(&cs46xx_pci_driver);
-
- if (rtn == -ENODEV) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(
- "cs46xx: Unable to detect valid cs46xx device\n"));
- }
-
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs46xx: cs46xx_init_module()- (%d)\n",rtn));
- return rtn;
-}
-
-static void __exit cs46xx_cleanup_module(void)
-{
- pci_unregister_driver(&cs46xx_pci_driver);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs46xx: cleanup_cs46xx() finished\n"));
-}
-
-module_init(cs46xx_init_module);
-module_exit(cs46xx_cleanup_module);
-
-#ifdef CONFIG_PM
-static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
-{
- struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
- CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
- printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
- cs46xx_suspend(s, state);
- return 0;
-}
-
-static int cs46xx_resume_tbl(struct pci_dev *pcidev)
-{
- struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
- CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
- printk(KERN_INFO "cs46xx: cs46xx_resume_tbl request\n"));
- cs46xx_resume(s);
- return 0;
-}
-#endif
diff --git a/sound/oss/cs46xx_wrapper-24.h b/sound/oss/cs46xx_wrapper-24.h
deleted file mode 100644
index f68e01181a7c..000000000000
--- a/sound/oss/cs46xx_wrapper-24.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*******************************************************************************
-*
-* "cs46xx_wrapper.c" -- Cirrus Logic-Crystal CS46XX linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (pcaudio@crystal.cirrus.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.
-*
-* 01/11/2001 trw - new file from cs4281 wrapper code.
-*
-*******************************************************************************/
-#ifndef __CS46XX_WRAPPER24_H
-#define __CS46XX_WRAPPER24_H
-
-#include <linux/spinlock.h>
-
-#define CS_OWNER .owner =
-#define CS_THIS_MODULE THIS_MODULE,
-static inline void cs46xx_null(struct pci_dev *pcidev) { return; }
-#define cs4x_mem_map_reserve(page) SetPageReserved(page)
-#define cs4x_mem_map_unreserve(page) ClearPageReserved(page)
-
-#define free_dmabuf(card, dmabuf) \
- pci_free_consistent((card)->pci_dev, \
- PAGE_SIZE << (dmabuf)->buforder, \
- (dmabuf)->rawbuf, (dmabuf)->dmaaddr);
-#define free_dmabuf2(card, dmabuf) \
- pci_free_consistent((card)->pci_dev, \
- PAGE_SIZE << (dmabuf)->buforder_tmpbuff, \
- (dmabuf)->tmpbuff, (dmabuf)->dmaaddr_tmpbuff);
-#define cs4x_pgoff(vma) ((vma)->vm_pgoff)
-
-#define RSRCISIOREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
- ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
-#define RSRCISMEMORYREGION(dev,num) ((dev)->resource[(num)].start != 0 && \
- ((dev)->resource[(num)].flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY)
-#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
-#define PCI_GET_DRIVER_DATA pci_get_drvdata
-#define PCI_SET_DRIVER_DATA pci_set_drvdata
-#define PCI_SET_DMA_MASK(pcidev,mask) pcidev->dma_mask = mask
-
-#endif
diff --git a/sound/oss/cs46xxpm.h b/sound/oss/cs46xxpm.h
deleted file mode 100644
index 2932b6e0e0bb..000000000000
--- a/sound/oss/cs46xxpm.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*******************************************************************************
-*
-* "cs46xxpm.h" -- Cirrus Logic-Crystal CS46XX linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (pcaudio@crystal.cirrus.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.
-*
-* 12/22/00 trw - new file.
-*
-*******************************************************************************/
-#ifndef __CS46XXPM_H
-#define __CS46XXPM_H
-
-#define CS46XX_AC97_HIGHESTREGTORESTORE 0x26
-#define CS46XX_AC97_NUMBER_RESTORE_REGS (CS46XX_AC97_HIGHESTREGTORESTORE/2-1)
-
-/* PM state defintions */
-#define CS46XX_PM_NOT_REGISTERED 0x1000
-#define CS46XX_PM_IDLE 0x0001
-#define CS46XX_PM_SUSPENDING 0x0002
-#define CS46XX_PM_SUSPENDED 0x0004
-#define CS46XX_PM_RESUMING 0x0008
-#define CS46XX_PM_RESUMED 0x0010
-
-#define CS_POWER_DAC 0x0001
-#define CS_POWER_ADC 0x0002
-#define CS_POWER_MIXVON 0x0004
-#define CS_POWER_MIXVOFF 0x0008
-#define CS_AC97_POWER_CONTROL_ON 0xf000 /* always on bits (inverted) */
-#define CS_AC97_POWER_CONTROL_ADC 0x0100
-#define CS_AC97_POWER_CONTROL_DAC 0x0200
-#define CS_AC97_POWER_CONTROL_MIXVON 0x0400
-#define CS_AC97_POWER_CONTROL_MIXVOFF 0x0800
-#define CS_AC97_POWER_CONTROL_ADC_ON 0x0001
-#define CS_AC97_POWER_CONTROL_DAC_ON 0x0002
-#define CS_AC97_POWER_CONTROL_MIXVON_ON 0x0004
-#define CS_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008
-
-struct cs46xx_pm {
- unsigned long flags;
- u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue;
- u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR;
- u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save;
- u32 u32SSPM_BITS;
- u32 ac97[CS46XX_AC97_NUMBER_RESTORE_REGS];
- u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono;
- u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose;
- u32 u32hwptr_playback,u32hwptr_capture;
- unsigned dmabuf_swptr_play;
- int dmabuf_count_play;
- unsigned dmabuf_swptr_capture;
- int dmabuf_count_capture;
-};
-
-#endif
diff --git a/sound/oss/emu10k1/8010.h b/sound/oss/emu10k1/8010.h
deleted file mode 100644
index 61c6c42bbc36..000000000000
--- a/sound/oss/emu10k1/8010.h
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
- **********************************************************************
- * 8010.h
- * Copyright 1999-2001 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS
- * line endings
- * December 8, 1999 Jon Taylor Added lots of new register info
- * May 16, 2001 Daniel Bertrand Added unofficial DBG register info
- * Oct-Nov 2001 D.B. Added unofficial Audigy registers
- *
- **********************************************************************
- *
- * 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 _8010_H
-#define _8010_H
-
-#include <linux/types.h>
-
-// Driver version:
-#define MAJOR_VER 0
-#define MINOR_VER 20
-#define DRIVER_VERSION "0.20a"
-
-
-// Audigy specify registers are prefixed with 'A_'
-
-/************************************************************************************************/
-/* PCI function 0 registers, address = <val> + PCIBASE0 */
-/************************************************************************************************/
-
-#define PTR 0x00 /* Indexed register set pointer register */
- /* NOTE: The CHANNELNUM and ADDRESS words can */
- /* be modified independently of each other. */
-#define PTR_CHANNELNUM_MASK 0x0000003f /* For each per-channel register, indicates the */
- /* channel number of the register to be */
- /* accessed. For non per-channel registers the */
- /* value should be set to zero. */
-#define PTR_ADDRESS_MASK 0x07ff0000 /* Register index */
-
-#define DATA 0x04 /* Indexed register set data register */
-
-#define IPR 0x08 /* Global interrupt pending register */
- /* Clear pending interrupts by writing a 1 to */
- /* the relevant bits and zero to the other bits */
-
-/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */
-#define A_IPR_MIDITRANSBUFEMPTY2 0x10000000 /* MIDI UART transmit buffer empty */
-#define A_IPR_MIDIRECVBUFEMPTY2 0x08000000 /* MIDI UART receive buffer empty */
-
-#define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */
-#define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */
-#define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */
-#define IPR_PCIERROR 0x00200000 /* PCI bus error */
-#define IPR_VOLINCR 0x00100000 /* Volume increment button pressed */
-#define IPR_VOLDECR 0x00080000 /* Volume decrement button pressed */
-#define IPR_MUTE 0x00040000 /* Mute button pressed */
-#define IPR_MICBUFFULL 0x00020000 /* Microphone buffer full */
-#define IPR_MICBUFHALFFULL 0x00010000 /* Microphone buffer half full */
-#define IPR_ADCBUFFULL 0x00008000 /* ADC buffer full */
-#define IPR_ADCBUFHALFFULL 0x00004000 /* ADC buffer half full */
-#define IPR_EFXBUFFULL 0x00002000 /* Effects buffer full */
-#define IPR_EFXBUFHALFFULL 0x00001000 /* Effects buffer half full */
-#define IPR_GPSPDIFSTATUSCHANGE 0x00000800 /* GPSPDIF channel status change */
-#define IPR_CDROMSTATUSCHANGE 0x00000400 /* CD-ROM channel status change */
-#define IPR_INTERVALTIMER 0x00000200 /* Interval timer terminal count */
-#define IPR_MIDITRANSBUFEMPTY 0x00000100 /* MIDI UART transmit buffer empty */
-#define IPR_MIDIRECVBUFEMPTY 0x00000080 /* MIDI UART receive buffer empty */
-#define IPR_CHANNELLOOP 0x00000040 /* One or more channel loop interrupts pending */
-#define IPR_CHANNELNUMBERMASK 0x0000003f /* When IPR_CHANNELLOOP is set, indicates the */
- /* Highest set channel in CLIPL or CLIPH. When */
- /* IP is written with CL set, the bit in CLIPL */
- /* or CLIPH corresponding to the CIN value */
- /* written will be cleared. */
-#define A_IPR_MIDITRANSBUFEMPTY1 IPR_MIDITRANSBUFEMPTY /* MIDI UART transmit buffer empty */
-#define A_IPR_MIDIRECVBUFEMPTY1 IPR_MIDIRECVBUFEMPTY /* MIDI UART receive buffer empty */
-
-
-
-#define INTE 0x0c /* Interrupt enable register */
-#define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */
-#define INTE_VIRTUALSB_220 0x00000000 /* Capture at I/O base address 0x220-0x22f */
-#define INTE_VIRTUALSB_240 0x40000000 /* Capture at I/O base address 0x240 */
-#define INTE_VIRTUALSB_260 0x80000000 /* Capture at I/O base address 0x260 */
-#define INTE_VIRTUALSB_280 0xc0000000 /* Capture at I/O base address 0x280 */
-#define INTE_VIRTUALMPU_MASK 0x30000000 /* Virtual MPU I/O port capture */
-#define INTE_VIRTUALMPU_300 0x00000000 /* Capture at I/O base address 0x300-0x301 */
-#define INTE_VIRTUALMPU_310 0x10000000 /* Capture at I/O base address 0x310 */
-#define INTE_VIRTUALMPU_320 0x20000000 /* Capture at I/O base address 0x320 */
-#define INTE_VIRTUALMPU_330 0x30000000 /* Capture at I/O base address 0x330 */
-#define INTE_MASTERDMAENABLE 0x08000000 /* Master DMA emulation at 0x000-0x00f */
-#define INTE_SLAVEDMAENABLE 0x04000000 /* Slave DMA emulation at 0x0c0-0x0df */
-#define INTE_MASTERPICENABLE 0x02000000 /* Master PIC emulation at 0x020-0x021 */
-#define INTE_SLAVEPICENABLE 0x01000000 /* Slave PIC emulation at 0x0a0-0x0a1 */
-#define INTE_VSBENABLE 0x00800000 /* Enable virtual Soundblaster */
-#define INTE_ADLIBENABLE 0x00400000 /* Enable AdLib emulation at 0x388-0x38b */
-#define INTE_MPUENABLE 0x00200000 /* Enable virtual MPU */
-#define INTE_FORCEINT 0x00100000 /* Continuously assert INTAN */
-
-#define INTE_MRHANDENABLE 0x00080000 /* Enable the "Mr. Hand" logic */
- /* NOTE: There is no reason to use this under */
- /* Linux, and it will cause odd hardware */
- /* behavior and possibly random segfaults and */
- /* lockups if enabled. */
-
-/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */
-#define A_INTE_MIDITXENABLE2 0x00020000 /* Enable MIDI transmit-buffer-empty interrupts */
-#define A_INTE_MIDIRXENABLE2 0x00010000 /* Enable MIDI receive-buffer-empty interrupts */
-
-
-#define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */
- /* NOTE: This bit must always be enabled */
-#define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */
-#define INTE_PCIERRORENABLE 0x00000800 /* Enable PCI bus error interrupts */
-#define INTE_VOLINCRENABLE 0x00000400 /* Enable volume increment button interrupts */
-#define INTE_VOLDECRENABLE 0x00000200 /* Enable volume decrement button interrupts */
-#define INTE_MUTEENABLE 0x00000100 /* Enable mute button interrupts */
-#define INTE_MICBUFENABLE 0x00000080 /* Enable microphone buffer interrupts */
-#define INTE_ADCBUFENABLE 0x00000040 /* Enable ADC buffer interrupts */
-#define INTE_EFXBUFENABLE 0x00000020 /* Enable Effects buffer interrupts */
-#define INTE_GPSPDIFENABLE 0x00000010 /* Enable GPSPDIF status interrupts */
-#define INTE_CDSPDIFENABLE 0x00000008 /* Enable CDSPDIF status interrupts */
-#define INTE_INTERVALTIMERENB 0x00000004 /* Enable interval timer interrupts */
-#define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */
-#define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */
-
-/* The next two interrupts are for the midi port on the Audigy (A_MPU2) */
-#define A_INTE_MIDITXENABLE1 INTE_MIDITXENABLE
-#define A_INTE_MIDIRXENABLE1 INTE_MIDIRXENABLE
-
-#define WC 0x10 /* Wall Clock register */
-#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */
-#define WC_SAMPLECOUNTER 0x14060010
-#define WC_CURRENTCHANNEL 0x0000003F /* Channel [0..63] currently being serviced */
- /* NOTE: Each channel takes 1/64th of a sample */
- /* period to be serviced. */
-
-#define HCFG 0x14 /* Hardware config register */
- /* NOTE: There is no reason to use the legacy */
- /* SoundBlaster emulation stuff described below */
- /* under Linux, and all kinds of weird hardware */
- /* behavior can result if you try. Don't. */
-#define HCFG_LEGACYFUNC_MASK 0xe0000000 /* Legacy function number */
-#define HCFG_LEGACYFUNC_MPU 0x00000000 /* Legacy MPU */
-#define HCFG_LEGACYFUNC_SB 0x40000000 /* Legacy SB */
-#define HCFG_LEGACYFUNC_AD 0x60000000 /* Legacy AD */
-#define HCFG_LEGACYFUNC_MPIC 0x80000000 /* Legacy MPIC */
-#define HCFG_LEGACYFUNC_MDMA 0xa0000000 /* Legacy MDMA */
-#define HCFG_LEGACYFUNC_SPCI 0xc0000000 /* Legacy SPCI */
-#define HCFG_LEGACYFUNC_SDMA 0xe0000000 /* Legacy SDMA */
-#define HCFG_IOCAPTUREADDR 0x1f000000 /* The 4 LSBs of the captured I/O address. */
-#define HCFG_LEGACYWRITE 0x00800000 /* 1 = write, 0 = read */
-#define HCFG_LEGACYWORD 0x00400000 /* 1 = word, 0 = byte */
-#define HCFG_LEGACYINT 0x00200000 /* 1 = legacy event captured. Write 1 to clear. */
- /* NOTE: The rest of the bits in this register */
- /* _are_ relevant under Linux. */
-#define HCFG_CODECFORMAT_MASK 0x00070000 /* CODEC format */
-#define HCFG_CODECFORMAT_AC97 0x00000000 /* AC97 CODEC format -- Primary Output */
-#define HCFG_CODECFORMAT_I2S 0x00010000 /* I2S CODEC format -- Secondary (Rear) Output */
-#define HCFG_GPINPUT0 0x00004000 /* External pin112 */
-#define HCFG_GPINPUT1 0x00002000 /* External pin110 */
-
-#define HCFG_GPOUTPUT_MASK 0x00001c00 /* External pins which may be controlled */
-#define HCFG_GPOUT0 0x00001000 /* set to enable digital out on 5.1 cards */
-
-#define HCFG_JOYENABLE 0x00000200 /* Internal joystick enable */
-#define HCFG_PHASETRACKENABLE 0x00000100 /* Phase tracking enable */
- /* 1 = Force all 3 async digital inputs to use */
- /* the same async sample rate tracker (ZVIDEO) */
-#define HCFG_AC3ENABLE_MASK 0x0x0000e0 /* AC3 async input control - Not implemented */
-#define HCFG_AC3ENABLE_ZVIDEO 0x00000080 /* Channels 0 and 1 replace ZVIDEO */
-#define HCFG_AC3ENABLE_CDSPDIF 0x00000040 /* Channels 0 and 1 replace CDSPDIF */
-#define HCFG_AC3ENABLE_GPSPDIF 0x00000020 /* Channels 0 and 1 replace GPSPDIF */
-#define HCFG_AUTOMUTE 0x00000010 /* When set, the async sample rate convertors */
- /* will automatically mute their output when */
- /* they are not rate-locked to the external */
- /* async audio source */
-#define HCFG_LOCKSOUNDCACHE 0x00000008 /* 1 = Cancel bustmaster accesses to soundcache */
- /* NOTE: This should generally never be used. */
-#define HCFG_LOCKTANKCACHE_MASK 0x00000004 /* 1 = Cancel bustmaster accesses to tankcache */
- /* NOTE: This should generally never be used. */
-#define HCFG_LOCKTANKCACHE 0x01020014
-#define HCFG_MUTEBUTTONENABLE 0x00000002 /* 1 = Master mute button sets AUDIOENABLE = 0. */
- /* NOTE: This is a 'cheap' way to implement a */
- /* master mute function on the mute button, and */
- /* in general should not be used unless a more */
- /* sophisticated master mute function has not */
- /* been written. */
-#define HCFG_AUDIOENABLE 0x00000001 /* 0 = CODECs transmit zero-valued samples */
- /* Should be set to 1 when the EMU10K1 is */
- /* completely initialized. */
-
-//For Audigy, MPU port move to 0x70-0x74 ptr register
-
-#define MUDATA 0x18 /* MPU401 data register (8 bits) */
-
-#define MUCMD 0x19 /* MPU401 command register (8 bits) */
-#define MUCMD_RESET 0xff /* RESET command */
-#define MUCMD_ENTERUARTMODE 0x3f /* Enter_UART_mode command */
- /* NOTE: All other commands are ignored */
-
-#define MUSTAT MUCMD /* MPU401 status register (8 bits) */
-#define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */
-#define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */
-
-#define A_IOCFG 0x18 /* GPIO on Audigy card (16bits) */
-#define A_GPINPUT_MASK 0xff00
-#define A_GPOUTPUT_MASK 0x00ff
-
-#define TIMER 0x1a /* Timer terminal count register (16-bit) */
- /* NOTE: After the rate is changed, a maximum */
- /* of 1024 sample periods should be allowed */
- /* before the new rate is guaranteed accurate. */
-#define TIMER_RATE_MASK 0x03ff /* Timer interrupt rate in sample periods */
- /* 0 == 1024 periods, [1..4] are not useful */
-
-#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */
-
-#define AC97ADDRESS 0x1e /* AC97 register set address register (8 bit) */
-#define AC97ADDRESS_READY 0x80 /* Read-only bit, reflects CODEC READY signal */
-#define AC97ADDRESS_ADDRESS 0x7f /* Address of indexed AC97 register */
-
-/********************************************************************************************************/
-/* Emu10k1 pointer-offset register set, accessed through the PTR and DATA registers */
-/********************************************************************************************************/
-
-#define CPF 0x00 /* Current pitch and fraction register */
-#define CPF_CURRENTPITCH_MASK 0xffff0000 /* Current pitch (linear, 0x4000 == unity pitch shift) */
-#define CPF_CURRENTPITCH 0x10100000
-#define CPF_STEREO_MASK 0x00008000 /* 1 = Even channel interleave, odd channel locked */
-#define CPF_STOP_MASK 0x00004000 /* 1 = Current pitch forced to 0 */
-#define CPF_FRACADDRESS_MASK 0x00003fff /* Linear fractional address of the current channel */
-
-#define PTRX 0x01 /* Pitch target and send A/B amounts register */
-#define PTRX_PITCHTARGET_MASK 0xffff0000 /* Pitch target of specified channel */
-#define PTRX_PITCHTARGET 0x10100001
-#define PTRX_FXSENDAMOUNT_A_MASK 0x0000ff00 /* Linear level of channel output sent to FX send bus A */
-#define PTRX_FXSENDAMOUNT_A 0x08080001
-#define PTRX_FXSENDAMOUNT_B_MASK 0x000000ff /* Linear level of channel output sent to FX send bus B */
-#define PTRX_FXSENDAMOUNT_B 0x08000001
-
-#define CVCF 0x02 /* Current volume and filter cutoff register */
-#define CVCF_CURRENTVOL_MASK 0xffff0000 /* Current linear volume of specified channel */
-#define CVCF_CURRENTVOL 0x10100002
-#define CVCF_CURRENTFILTER_MASK 0x0000ffff /* Current filter cutoff frequency of specified channel */
-#define CVCF_CURRENTFILTER 0x10000002
-
-#define VTFT 0x03 /* Volume target and filter cutoff target register */
-#define VTFT_VOLUMETARGET_MASK 0xffff0000 /* Volume target of specified channel */
-#define VTFT_FILTERTARGET_MASK 0x0000ffff /* Filter cutoff target of specified channel */
-
-#define Z1 0x05 /* Filter delay memory 1 register */
-
-#define Z2 0x04 /* Filter delay memory 2 register */
-
-#define PSST 0x06 /* Send C amount and loop start address register */
-#define PSST_FXSENDAMOUNT_C_MASK 0xff000000 /* Linear level of channel output sent to FX send bus C */
-
-#define PSST_FXSENDAMOUNT_C 0x08180006
-
-#define PSST_LOOPSTARTADDR_MASK 0x00ffffff /* Loop start address of the specified channel */
-#define PSST_LOOPSTARTADDR 0x18000006
-
-#define DSL 0x07 /* Send D amount and loop start address register */
-#define DSL_FXSENDAMOUNT_D_MASK 0xff000000 /* Linear level of channel output sent to FX send bus D */
-
-#define DSL_FXSENDAMOUNT_D 0x08180007
-
-#define DSL_LOOPENDADDR_MASK 0x00ffffff /* Loop end address of the specified channel */
-#define DSL_LOOPENDADDR 0x18000007
-
-#define CCCA 0x08 /* Filter Q, interp. ROM, byte size, cur. addr register */
-#define CCCA_RESONANCE 0xf0000000 /* Lowpass filter resonance (Q) height */
-#define CCCA_INTERPROMMASK 0x0e000000 /* Selects passband of interpolation ROM */
- /* 1 == full band, 7 == lowpass */
- /* ROM 0 is used when pitch shifting downward or less */
- /* then 3 semitones upward. Increasingly higher ROM */
- /* numbers are used, typically in steps of 3 semitones, */
- /* as upward pitch shifting is performed. */
-#define CCCA_INTERPROM_0 0x00000000 /* Select interpolation ROM 0 */
-#define CCCA_INTERPROM_1 0x02000000 /* Select interpolation ROM 1 */
-#define CCCA_INTERPROM_2 0x04000000 /* Select interpolation ROM 2 */
-#define CCCA_INTERPROM_3 0x06000000 /* Select interpolation ROM 3 */
-#define CCCA_INTERPROM_4 0x08000000 /* Select interpolation ROM 4 */
-#define CCCA_INTERPROM_5 0x0a000000 /* Select interpolation ROM 5 */
-#define CCCA_INTERPROM_6 0x0c000000 /* Select interpolation ROM 6 */
-#define CCCA_INTERPROM_7 0x0e000000 /* Select interpolation ROM 7 */
-#define CCCA_8BITSELECT 0x01000000 /* 1 = Sound memory for this channel uses 8-bit samples */
-#define CCCA_CURRADDR_MASK 0x00ffffff /* Current address of the selected channel */
-#define CCCA_CURRADDR 0x18000008
-
-#define CCR 0x09 /* Cache control register */
-#define CCR_CACHEINVALIDSIZE 0x07190009
-#define CCR_CACHEINVALIDSIZE_MASK 0xfe000000 /* Number of invalid samples cache for this channel */
-#define CCR_CACHELOOPFLAG 0x01000000 /* 1 = Cache has a loop service pending */
-#define CCR_INTERLEAVEDSAMPLES 0x00800000 /* 1 = A cache service will fetch interleaved samples */
-#define CCR_WORDSIZEDSAMPLES 0x00400000 /* 1 = A cache service will fetch word sized samples */
-#define CCR_READADDRESS 0x06100009
-#define CCR_READADDRESS_MASK 0x003f0000 /* Location of cache just beyond current cache service */
-#define CCR_LOOPINVALSIZE 0x0000fe00 /* Number of invalid samples in cache prior to loop */
- /* NOTE: This is valid only if CACHELOOPFLAG is set */
-#define CCR_LOOPFLAG 0x00000100 /* Set for a single sample period when a loop occurs */
-#define CCR_CACHELOOPADDRHI 0x000000ff /* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set */
-
-#define CLP 0x0a /* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */
- /* NOTE: This register is normally not used */
-#define CLP_CACHELOOPADDR 0x0000ffff /* Cache loop address (DSL_LOOPSTARTADDR [0..15]) */
-
-#define FXRT 0x0b /* Effects send routing register */
- /* NOTE: It is illegal to assign the same routing to */
- /* two effects sends. */
-#define FXRT_CHANNELA 0x000f0000 /* Effects send bus number for channel's effects send A */
-#define FXRT_CHANNELB 0x00f00000 /* Effects send bus number for channel's effects send B */
-#define FXRT_CHANNELC 0x0f000000 /* Effects send bus number for channel's effects send C */
-#define FXRT_CHANNELD 0xf0000000 /* Effects send bus number for channel's effects send D */
-
-#define MAPA 0x0c /* Cache map A */
-
-#define MAPB 0x0d /* Cache map B */
-
-#define MAP_PTE_MASK 0xffffe000 /* The 19 MSBs of the PTE indexed by the PTI */
-#define MAP_PTI_MASK 0x00001fff /* The 13 bit index to one of the 8192 PTE dwords */
-
-#define ENVVOL 0x10 /* Volume envelope register */
-#define ENVVOL_MASK 0x0000ffff /* Current value of volume envelope state variable */
- /* 0x8000-n == 666*n usec delay */
-
-#define ATKHLDV 0x11 /* Volume envelope hold and attack register */
-#define ATKHLDV_PHASE0 0x00008000 /* 0 = Begin attack phase */
-#define ATKHLDV_HOLDTIME_MASK 0x00007f00 /* Envelope hold time (127-n == n*88.2msec) */
-#define ATKHLDV_ATTACKTIME_MASK 0x0000007f /* Envelope attack time, log encoded */
- /* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec */
-
-#define DCYSUSV 0x12 /* Volume envelope sustain and decay register */
-#define DCYSUSV_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */
-#define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */
-#define DCYSUSV_CHANNELENABLE_MASK 0x00000080 /* 1 = Inhibit envelope engine from writing values in */
- /* this channel and from writing to pitch, filter and */
- /* volume targets. */
-#define DCYSUSV_DECAYTIME_MASK 0x0000007f /* Volume envelope decay time, log encoded */
- /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */
-
-#define LFOVAL1 0x13 /* Modulation LFO value */
-#define LFOVAL_MASK 0x0000ffff /* Current value of modulation LFO state variable */
- /* 0x8000-n == 666*n usec delay */
-
-#define ENVVAL 0x14 /* Modulation envelope register */
-#define ENVVAL_MASK 0x0000ffff /* Current value of modulation envelope state variable */
- /* 0x8000-n == 666*n usec delay */
-
-#define ATKHLDM 0x15 /* Modulation envelope hold and attack register */
-#define ATKHLDM_PHASE0 0x00008000 /* 0 = Begin attack phase */
-#define ATKHLDM_HOLDTIME 0x00007f00 /* Envelope hold time (127-n == n*42msec) */
-#define ATKHLDM_ATTACKTIME 0x0000007f /* Envelope attack time, log encoded */
- /* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec */
-
-#define DCYSUSM 0x16 /* Modulation envelope decay and sustain register */
-#define DCYSUSM_PHASE1_MASK 0x00008000 /* 0 = Begin attack phase, 1 = begin release phase */
-#define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00 /* 127 = full, 0 = off, 0.75dB increments */
-#define DCYSUSM_DECAYTIME_MASK 0x0000007f /* Envelope decay time, log encoded */
- /* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec */
-
-#define LFOVAL2 0x17 /* Vibrato LFO register */
-#define LFOVAL2_MASK 0x0000ffff /* Current value of vibrato LFO state variable */
- /* 0x8000-n == 666*n usec delay */
-
-#define IP 0x18 /* Initial pitch register */
-#define IP_MASK 0x0000ffff /* Exponential initial pitch shift */
- /* 4 bits of octave, 12 bits of fractional octave */
-#define IP_UNITY 0x0000e000 /* Unity pitch shift */
-
-#define IFATN 0x19 /* Initial filter cutoff and attenuation register */
-#define IFATN_FILTERCUTOFF_MASK 0x0000ff00 /* Initial filter cutoff frequency in exponential units */
- /* 6 most significant bits are semitones */
- /* 2 least significant bits are fractions */
-#define IFATN_FILTERCUTOFF 0x08080019
-#define IFATN_ATTENUATION_MASK 0x000000ff /* Initial attenuation in 0.375dB steps */
-#define IFATN_ATTENUATION 0x08000019
-
-
-#define PEFE 0x1a /* Pitch envelope and filter envelope amount register */
-#define PEFE_PITCHAMOUNT_MASK 0x0000ff00 /* Pitch envlope amount */
- /* Signed 2's complement, +/- one octave peak extremes */
-#define PEFE_PITCHAMOUNT 0x0808001a
-#define PEFE_FILTERAMOUNT_MASK 0x000000ff /* Filter envlope amount */
- /* Signed 2's complement, +/- six octaves peak extremes */
-#define PEFE_FILTERAMOUNT 0x0800001a
-#define FMMOD 0x1b /* Vibrato/filter modulation from LFO register */
-#define FMMOD_MODVIBRATO 0x0000ff00 /* Vibrato LFO modulation depth */
- /* Signed 2's complement, +/- one octave extremes */
-#define FMMOD_MOFILTER 0x000000ff /* Filter LFO modulation depth */
- /* Signed 2's complement, +/- three octave extremes */
-
-
-#define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */
-#define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */
- /* Signed 2's complement, with +/- 12dB extremes */
-#define TREMFRQ_FREQUENCY 0x000000ff /* Tremolo LFO frequency */
- /* ??Hz steps, maximum of ?? Hz. */
-
-#define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */
-#define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */
- /* Signed 2's complement, +/- one octave extremes */
-#define FM2FRQ2_FREQUENCY 0x000000ff /* Vibrato LFO frequency */
- /* 0.039Hz steps, maximum of 9.85 Hz. */
-
-#define TEMPENV 0x1e /* Tempory envelope register */
-#define TEMPENV_MASK 0x0000ffff /* 16-bit value */
- /* NOTE: All channels contain internal variables; do */
- /* not write to these locations. */
-
-#define CD0 0x20 /* Cache data 0 register */
-#define CD1 0x21 /* Cache data 1 register */
-#define CD2 0x22 /* Cache data 2 register */
-#define CD3 0x23 /* Cache data 3 register */
-#define CD4 0x24 /* Cache data 4 register */
-#define CD5 0x25 /* Cache data 5 register */
-#define CD6 0x26 /* Cache data 6 register */
-#define CD7 0x27 /* Cache data 7 register */
-#define CD8 0x28 /* Cache data 8 register */
-#define CD9 0x29 /* Cache data 9 register */
-#define CDA 0x2a /* Cache data A register */
-#define CDB 0x2b /* Cache data B register */
-#define CDC 0x2c /* Cache data C register */
-#define CDD 0x2d /* Cache data D register */
-#define CDE 0x2e /* Cache data E register */
-#define CDF 0x2f /* Cache data F register */
-
-#define PTB 0x40 /* Page table base register */
-#define PTB_MASK 0xfffff000 /* Physical address of the page table in host memory */
-
-#define TCB 0x41 /* Tank cache base register */
-#define TCB_MASK 0xfffff000 /* Physical address of the bottom of host based TRAM */
-
-#define ADCCR 0x42 /* ADC sample rate/stereo control register */
-#define ADCCR_RCHANENABLE 0x00000010 /* Enables right channel for writing to the host */
-#define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */
- /* NOTE: To guarantee phase coherency, both channels */
- /* must be disabled prior to enabling both channels. */
-#define A_ADCCR_RCHANENABLE 0x00000020
-#define A_ADCCR_LCHANENABLE 0x00000010
-
-#define A_ADCCR_SAMPLERATE_MASK 0x0000000F /* Audigy sample rate convertor output rate */
-#define ADCCR_SAMPLERATE_MASK 0x00000007 /* Sample rate convertor output rate */
-
-#define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */
-#define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */
-#define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */
-#define ADCCR_SAMPLERATE_24 0x00000003 /* 24kHz sample rate */
-#define ADCCR_SAMPLERATE_22 0x00000004 /* 22.05kHz sample rate */
-#define ADCCR_SAMPLERATE_16 0x00000005 /* 16kHz sample rate */
-#define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */
-#define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz sample rate */
-
-#define A_ADCCR_SAMPLERATE_12 0x00000006 /* 12kHz sample rate */
-#define A_ADCCR_SAMPLERATE_11 0x00000007 /* 11.025kHz sample rate */
-#define A_ADCCR_SAMPLERATE_8 0x00000008 /* 8kHz sample rate */
-
-#define FXWC 0x43 /* FX output write channels register */
- /* When set, each bit enables the writing of the */
- /* corresponding FX output channel (internal registers */
- /* 0x20-0x3f) into host memory. This mode of recording */
- /* is 16bit, 48KHz only. All 32 channels can be enabled */
- /* simultaneously. */
-#define TCBS 0x44 /* Tank cache buffer size register */
-#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */
-#define TCBS_BUFFSIZE_16K 0x00000000
-#define TCBS_BUFFSIZE_32K 0x00000001
-#define TCBS_BUFFSIZE_64K 0x00000002
-#define TCBS_BUFFSIZE_128K 0x00000003
-#define TCBS_BUFFSIZE_256K 0x00000004
-#define TCBS_BUFFSIZE_512K 0x00000005
-#define TCBS_BUFFSIZE_1024K 0x00000006
-#define TCBS_BUFFSIZE_2048K 0x00000007
-
-#define MICBA 0x45 /* AC97 microphone buffer address register */
-#define MICBA_MASK 0xfffff000 /* 20 bit base address */
-
-#define ADCBA 0x46 /* ADC buffer address register */
-#define ADCBA_MASK 0xfffff000 /* 20 bit base address */
-
-#define FXBA 0x47 /* FX Buffer Address */
-#define FXBA_MASK 0xfffff000 /* 20 bit base address */
-
-#define MICBS 0x49 /* Microphone buffer size register */
-
-#define ADCBS 0x4a /* ADC buffer size register */
-
-#define FXBS 0x4b /* FX buffer size register */
-
-/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */
-#define ADCBS_BUFSIZE_NONE 0x00000000
-#define ADCBS_BUFSIZE_384 0x00000001
-#define ADCBS_BUFSIZE_448 0x00000002
-#define ADCBS_BUFSIZE_512 0x00000003
-#define ADCBS_BUFSIZE_640 0x00000004
-#define ADCBS_BUFSIZE_768 0x00000005
-#define ADCBS_BUFSIZE_896 0x00000006
-#define ADCBS_BUFSIZE_1024 0x00000007
-#define ADCBS_BUFSIZE_1280 0x00000008
-#define ADCBS_BUFSIZE_1536 0x00000009
-#define ADCBS_BUFSIZE_1792 0x0000000a
-#define ADCBS_BUFSIZE_2048 0x0000000b
-#define ADCBS_BUFSIZE_2560 0x0000000c
-#define ADCBS_BUFSIZE_3072 0x0000000d
-#define ADCBS_BUFSIZE_3584 0x0000000e
-#define ADCBS_BUFSIZE_4096 0x0000000f
-#define ADCBS_BUFSIZE_5120 0x00000010
-#define ADCBS_BUFSIZE_6144 0x00000011
-#define ADCBS_BUFSIZE_7168 0x00000012
-#define ADCBS_BUFSIZE_8192 0x00000013
-#define ADCBS_BUFSIZE_10240 0x00000014
-#define ADCBS_BUFSIZE_12288 0x00000015
-#define ADCBS_BUFSIZE_14366 0x00000016
-#define ADCBS_BUFSIZE_16384 0x00000017
-#define ADCBS_BUFSIZE_20480 0x00000018
-#define ADCBS_BUFSIZE_24576 0x00000019
-#define ADCBS_BUFSIZE_28672 0x0000001a
-#define ADCBS_BUFSIZE_32768 0x0000001b
-#define ADCBS_BUFSIZE_40960 0x0000001c
-#define ADCBS_BUFSIZE_49152 0x0000001d
-#define ADCBS_BUFSIZE_57344 0x0000001e
-#define ADCBS_BUFSIZE_65536 0x0000001f
-
-
-#define CDCS 0x50 /* CD-ROM digital channel status register */
-
-#define GPSCS 0x51 /* General Purpose SPDIF channel status register*/
-
-#define DBG 0x52 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
-
-/* definitions for debug register - taken from the alsa drivers */
-#define DBG_ZC 0x80000000 /* zero tram counter */
-#define DBG_SATURATION_OCCURED 0x02000000 /* saturation control */
-#define DBG_SATURATION_ADDR 0x01ff0000 /* saturation address */
-#define DBG_SINGLE_STEP 0x00008000 /* single step mode */
-#define DBG_STEP 0x00004000 /* start single step */
-#define DBG_CONDITION_CODE 0x00003e00 /* condition code */
-#define DBG_SINGLE_STEP_ADDR 0x000001ff /* single step address */
-
-
-#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
-
-#define A_DBG 0x53
-#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */
-#define A_DBG_ZC 0x40000000 /* zero tram counter */
-#define A_DBG_STEP_ADDR 0x000003ff
-#define A_DBG_SATURATION_OCCURED 0x20000000
-#define A_DBG_SATURATION_ADDR 0x0ffc0000
-
-#define SPCS0 0x54 /* SPDIF output Channel Status 0 register */
-
-#define SPCS1 0x55 /* SPDIF output Channel Status 1 register */
-
-#define SPCS2 0x56 /* SPDIF output Channel Status 2 register */
-
-#define SPCS_CLKACCYMASK 0x30000000 /* Clock accuracy */
-#define SPCS_CLKACCY_1000PPM 0x00000000 /* 1000 parts per million */
-#define SPCS_CLKACCY_50PPM 0x10000000 /* 50 parts per million */
-#define SPCS_CLKACCY_VARIABLE 0x20000000 /* Variable accuracy */
-#define SPCS_SAMPLERATEMASK 0x0f000000 /* Sample rate */
-#define SPCS_SAMPLERATE_44 0x00000000 /* 44.1kHz sample rate */
-#define SPCS_SAMPLERATE_48 0x02000000 /* 48kHz sample rate */
-#define SPCS_SAMPLERATE_32 0x03000000 /* 32kHz sample rate */
-#define SPCS_CHANNELNUMMASK 0x00f00000 /* Channel number */
-#define SPCS_CHANNELNUM_UNSPEC 0x00000000 /* Unspecified channel number */
-#define SPCS_CHANNELNUM_LEFT 0x00100000 /* Left channel */
-#define SPCS_CHANNELNUM_RIGHT 0x00200000 /* Right channel */
-#define SPCS_SOURCENUMMASK 0x000f0000 /* Source number */
-#define SPCS_SOURCENUM_UNSPEC 0x00000000 /* Unspecified source number */
-#define SPCS_GENERATIONSTATUS 0x00008000 /* Originality flag (see IEC-958 spec) */
-#define SPCS_CATEGORYCODEMASK 0x00007f00 /* Category code (see IEC-958 spec) */
-#define SPCS_MODEMASK 0x000000c0 /* Mode (see IEC-958 spec) */
-#define SPCS_EMPHASISMASK 0x00000038 /* Emphasis */
-#define SPCS_EMPHASIS_NONE 0x00000000 /* No emphasis */
-#define SPCS_EMPHASIS_50_15 0x00000008 /* 50/15 usec 2 channel */
-#define SPCS_COPYRIGHT 0x00000004 /* Copyright asserted flag -- do not modify */
-#define SPCS_NOTAUDIODATA 0x00000002 /* 0 = Digital audio, 1 = not audio */
-#define SPCS_PROFESSIONAL 0x00000001 /* 0 = Consumer (IEC-958), 1 = pro (AES3-1992) */
-
-/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status */
-#define CLIEL 0x58 /* Channel loop interrupt enable low register */
-
-#define CLIEH 0x59 /* Channel loop interrupt enable high register */
-
-#define CLIPL 0x5a /* Channel loop interrupt pending low register */
-
-#define CLIPH 0x5b /* Channel loop interrupt pending high register */
-
-#define SOLEL 0x5c /* Stop on loop enable low register */
-
-#define SOLEH 0x5d /* Stop on loop enable high register */
-
-#define SPBYPASS 0x5e /* SPDIF BYPASS mode register */
-#define SPBYPASS_ENABLE 0x00000001 /* Enable SPDIF bypass mode */
-
-#define AC97SLOT 0x5f /* additional AC97 slots enable bits */
-#define AC97SLOT_CNTR 0x10 /* Center enable */
-#define AC97SLOT_LFE 0x20 /* LFE enable */
-
-#define CDSRCS 0x60 /* CD-ROM Sample Rate Converter status register */
-
-#define GPSRCS 0x61 /* General Purpose SPDIF sample rate cvt status */
-
-#define ZVSRCS 0x62 /* ZVideo sample rate converter status */
- /* NOTE: This one has no SPDIFLOCKED field */
- /* Assumes sample lock */
-
-/* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS. */
-#define SRCS_SPDIFLOCKED 0x02000000 /* SPDIF stream locked */
-#define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */
-#define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */
-
-
-/* Note that these values can vary +/- by a small amount */
-#define SRCS_SPDIFRATE_44 0x0003acd9
-#define SRCS_SPDIFRATE_48 0x00040000
-#define SRCS_SPDIFRATE_96 0x00080000
-
-#define MICIDX 0x63 /* Microphone recording buffer index register */
-#define MICIDX_MASK 0x0000ffff /* 16-bit value */
-#define MICIDX_IDX 0x10000063
-
-#define A_ADCIDX 0x63
-#define A_ADCIDX_IDX 0x10000063
-
-#define ADCIDX 0x64 /* ADC recording buffer index register */
-#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */
-#define ADCIDX_IDX 0x10000064
-
-#define FXIDX 0x65 /* FX recording buffer index register */
-#define FXIDX_MASK 0x0000ffff /* 16-bit value */
-#define FXIDX_IDX 0x10000065
-
-/* This is the MPU port on the card (via the game port) */
-#define A_MUDATA1 0x70
-#define A_MUCMD1 0x71
-#define A_MUSTAT1 A_MUCMD1
-
-/* This is the MPU port on the Audigy Drive */
-#define A_MUDATA2 0x72
-#define A_MUCMD2 0x73
-#define A_MUSTAT2 A_MUCMD2
-
-/* The next two are the Audigy equivalent of FXWC */
-/* the Audigy can record any output (16bit, 48kHz, up to 64 channel simultaneously) */
-/* Each bit selects a channel for recording */
-#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */
-#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
-
-#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
-#define A_SPDIF_48000 0x00000080
-#define A_SPDIF_44100 0x00000000
-#define A_SPDIF_96000 0x00000040
-
-#define A_FXRT2 0x7c
-#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */
-#define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */
-#define A_FXRT_CHANNELG 0x003f0000 /* Effects send bus number for channel's effects send G */
-#define A_FXRT_CHANNELH 0x3f000000 /* Effects send bus number for channel's effects send H */
-
-#define A_SENDAMOUNTS 0x7d
-#define A_FXSENDAMOUNT_E_MASK 0xff000000
-#define A_FXSENDAMOUNT_F_MASK 0x00ff0000
-#define A_FXSENDAMOUNT_G_MASK 0x0000ff00
-#define A_FXSENDAMOUNT_H_MASK 0x000000ff
-
-/* The send amounts for this one are the same as used with the emu10k1 */
-#define A_FXRT1 0x7e
-#define A_FXRT_CHANNELA 0x0000003f
-#define A_FXRT_CHANNELB 0x00003f00
-#define A_FXRT_CHANNELC 0x003f0000
-#define A_FXRT_CHANNELD 0x3f000000
-
-
-/* Each FX general purpose register is 32 bits in length, all bits are used */
-#define FXGPREGBASE 0x100 /* FX general purpose registers base */
-#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */
-/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */
-/* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */
-/* locations are for external TRAM. */
-#define TANKMEMDATAREGBASE 0x200 /* Tank memory data registers base */
-#define TANKMEMDATAREG_MASK 0x000fffff /* 20 bit tank audio data field */
-
-/* Combined address field and memory opcode or flag field. 160 locations, last 32 are external */
-#define TANKMEMADDRREGBASE 0x300 /* Tank memory address registers base */
-#define TANKMEMADDRREG_ADDR_MASK 0x000fffff /* 20 bit tank address field */
-#define TANKMEMADDRREG_CLEAR 0x00800000 /* Clear tank memory */
-#define TANKMEMADDRREG_ALIGN 0x00400000 /* Align read or write relative to tank access */
-#define TANKMEMADDRREG_WRITE 0x00200000 /* Write to tank memory */
-#define TANKMEMADDRREG_READ 0x00100000 /* Read from tank memory */
-
-#define MICROCODEBASE 0x400 /* Microcode data base address */
-
-/* Each DSP microcode instruction is mapped into 2 doublewords */
-/* NOTE: When writing, always write the LO doubleword first. Reads can be in either order. */
-#define LOWORD_OPX_MASK 0x000ffc00 /* Instruction operand X */
-#define LOWORD_OPY_MASK 0x000003ff /* Instruction operand Y */
-#define HIWORD_OPCODE_MASK 0x00f00000 /* Instruction opcode */
-#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */
-#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */
-
-
-/* Audigy Soundcard have a different instruction format */
-#define AUDIGY_CODEBASE 0x600
-#define A_LOWORD_OPY_MASK 0x000007ff
-#define A_LOWORD_OPX_MASK 0x007ff000
-#define A_HIWORD_OPCODE_MASK 0x0f000000
-#define A_HIWORD_RESULT_MASK 0x007ff000
-#define A_HIWORD_OPA_MASK 0x000007ff
-
-
-#endif /* _8010_H */
diff --git a/sound/oss/emu10k1/Makefile b/sound/oss/emu10k1/Makefile
deleted file mode 100644
index b3af9ccb0579..000000000000
--- a/sound/oss/emu10k1/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-# Makefile for Creative Labs EMU10K1
-#
-# 12 Apr 2000 Rui Sousa
-
-obj-$(CONFIG_SOUND_EMU10K1) += emu10k1.o
-
-emu10k1-objs := audio.o cardmi.o cardmo.o cardwi.o cardwo.o ecard.o \
- efxmgr.o emuadxmg.o hwaccess.o irqmgr.o main.o midi.o \
- mixer.o passthrough.o recmgr.o timer.o voicemgr.o
-
-ifdef DEBUG
- EXTRA_CFLAGS += -DEMU10K1_DEBUG
-endif
-
-ifdef CONFIG_MIDI_EMU10K1
- EXTRA_CFLAGS += -DEMU10K1_SEQUENCER
-endif
diff --git a/sound/oss/emu10k1/audio.c b/sound/oss/emu10k1/audio.c
deleted file mode 100644
index e75ea21eb811..000000000000
--- a/sound/oss/emu10k1/audio.c
+++ /dev/null
@@ -1,1595 +0,0 @@
-/*
- **********************************************************************
- * audio.c -- /dev/dsp interface for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up types/leaks
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-
-#include "hwaccess.h"
-#include "cardwo.h"
-#include "cardwi.h"
-#include "recmgr.h"
-#include "irqmgr.h"
-#include "audio.h"
-#include "8010.h"
-
-static void calculate_ofrag(struct woinst *);
-static void calculate_ifrag(struct wiinst *);
-
-static void emu10k1_waveout_bh(unsigned long refdata);
-static void emu10k1_wavein_bh(unsigned long refdata);
-
-/* Audio file operations */
-static ssize_t emu10k1_audio_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- struct wiinst *wiinst = wave_dev->wiinst;
- ssize_t ret = 0;
- unsigned long flags;
-
- DPD(3, "emu10k1_audio_read(), buffer=%p, count=%d\n", buffer, (u32) count);
-
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (wiinst->mmapped) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
- return -ENXIO;
- }
-
- if (wiinst->state == WAVE_STATE_CLOSED) {
- calculate_ifrag(wiinst);
-
- while (emu10k1_wavein_open(wave_dev) < 0) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- interruptible_sleep_on(&wave_dev->card->open_wait);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&wiinst->lock, flags);
- }
- }
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- while (count > 0) {
- u32 bytestocopy;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (!(wiinst->state & WAVE_STATE_STARTED)
- && (wave_dev->enablebits & PCM_ENABLE_INPUT))
- emu10k1_wavein_start(wave_dev);
-
- emu10k1_wavein_update(wave_dev->card, wiinst);
- emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- DPD(3, "bytestocopy --> %d\n", bytestocopy);
-
- if ((bytestocopy >= wiinst->buffer.fragment_size)
- || (bytestocopy >= count)) {
- int rc;
-
- bytestocopy = min_t(u32, bytestocopy, count);
-
- rc = emu10k1_wavein_xferdata(wiinst,
- (u8 __user *)buffer,
- &bytestocopy);
- if (rc)
- return rc;
-
- count -= bytestocopy;
- buffer += bytestocopy;
- ret += bytestocopy;
- }
-
- if (count > 0) {
- if ((file->f_flags & O_NONBLOCK)
- || (!(wave_dev->enablebits & PCM_ENABLE_INPUT)))
- return (ret ? ret : -EAGAIN);
-
- interruptible_sleep_on(&wiinst->wait_queue);
-
- if (signal_pending(current))
- return (ret ? ret : -ERESTARTSYS);
-
- }
- }
-
- DPD(3, "bytes copied -> %d\n", (u32) ret);
-
- return ret;
-}
-
-static ssize_t emu10k1_audio_write(struct file *file, const char __user *buffer, size_t count, loff_t * ppos)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- struct woinst *woinst = wave_dev->woinst;
- ssize_t ret;
- unsigned long flags;
-
- DPD(3, "emu10k1_audio_write(), buffer=%p, count=%d\n", buffer, (u32) count);
-
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (woinst->mmapped) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return -ENXIO;
- }
- // This is for emu10k1 revs less than 7, we need to go through tram
- if (woinst->format.passthrough == 1) {
- int r;
-
- woinst->buffer.ossfragshift = PT_BLOCKSIZE_LOG2;
- woinst->buffer.numfrags = PT_BLOCKCOUNT;
- calculate_ofrag(woinst);
-
- r = emu10k1_pt_write(file, buffer, count);
- spin_unlock_irqrestore(&woinst->lock, flags);
- return r;
- }
-
- if (woinst->state == WAVE_STATE_CLOSED) {
- calculate_ofrag(woinst);
-
- while (emu10k1_waveout_open(wave_dev) < 0) {
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- interruptible_sleep_on(&wave_dev->card->open_wait);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
-
- spin_lock_irqsave(&woinst->lock, flags);
- }
- }
-
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- ret = 0;
- if (count % woinst->format.bytespersample)
- return -EINVAL;
-
- count /= woinst->num_voices;
-
- while (count > 0) {
- u32 bytestocopy;
-
- spin_lock_irqsave(&woinst->lock, flags);
- emu10k1_waveout_update(woinst);
- emu10k1_waveout_getxfersize(woinst, &bytestocopy);
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- DPD(3, "bytestocopy --> %d\n", bytestocopy);
-
- if ((bytestocopy >= woinst->buffer.fragment_size)
- || (bytestocopy >= count)) {
-
- bytestocopy = min_t(u32, bytestocopy, count);
-
- emu10k1_waveout_xferdata(woinst, (u8 __user *) buffer, &bytestocopy);
-
- count -= bytestocopy;
- buffer += bytestocopy * woinst->num_voices;
- ret += bytestocopy * woinst->num_voices;
-
- spin_lock_irqsave(&woinst->lock, flags);
- woinst->total_copied += bytestocopy;
-
- if (!(woinst->state & WAVE_STATE_STARTED)
- && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)
- && (woinst->total_copied >= woinst->buffer.fragment_size))
- emu10k1_waveout_start(wave_dev);
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- if (count > 0) {
- if ((file->f_flags & O_NONBLOCK)
- || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT)))
- return (ret ? ret : -EAGAIN);
-
- interruptible_sleep_on(&woinst->wait_queue);
-
- if (signal_pending(current))
- return (ret ? ret : -ERESTARTSYS);
- }
- }
-
- DPD(3, "bytes copied -> %d\n", (u32) ret);
-
- return ret;
-}
-
-static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- struct woinst *woinst = NULL;
- struct wiinst *wiinst = NULL;
- int val = 0;
- u32 bytestocopy;
- unsigned long flags;
- int __user *p = (int __user *)arg;
-
- DPF(4, "emu10k1_audio_ioctl()\n");
-
- if (file->f_mode & FMODE_WRITE)
- woinst = wave_dev->woinst;
-
- if (file->f_mode & FMODE_READ)
- wiinst = wave_dev->wiinst;
-
- switch (cmd) {
- case OSS_GETVERSION:
- DPF(2, "OSS_GETVERSION:\n");
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_RESET:
- DPF(2, "SNDCTL_DSP_RESET:\n");
- wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;
-
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (woinst->state & WAVE_STATE_OPEN) {
- emu10k1_waveout_close(wave_dev);
- }
-
- woinst->mmapped = 0;
- woinst->total_copied = 0;
- woinst->total_played = 0;
- woinst->blocks = 0;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (wiinst->state & WAVE_STATE_OPEN) {
- emu10k1_wavein_close(wave_dev);
- }
-
- wiinst->mmapped = 0;
- wiinst->total_recorded = 0;
- wiinst->blocks = 0;
- spin_unlock_irqrestore(&wiinst->lock, flags);
- }
-
- break;
-
- case SNDCTL_DSP_SYNC:
- DPF(2, "SNDCTL_DSP_SYNC:\n");
-
- if (file->f_mode & FMODE_WRITE) {
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (woinst->state & WAVE_STATE_OPEN) {
-
- if (woinst->state & WAVE_STATE_STARTED)
- while ((woinst->total_played < woinst->total_copied)
- && !signal_pending(current)) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- interruptible_sleep_on(&woinst->wait_queue);
- spin_lock_irqsave(&woinst->lock, flags);
- }
- emu10k1_waveout_close(wave_dev);
- }
-
- woinst->mmapped = 0;
- woinst->total_copied = 0;
- woinst->total_played = 0;
- woinst->blocks = 0;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (wiinst->state & WAVE_STATE_OPEN) {
- emu10k1_wavein_close(wave_dev);
- }
-
- wiinst->mmapped = 0;
- wiinst->total_recorded = 0;
- wiinst->blocks = 0;
- spin_unlock_irqrestore(&wiinst->lock, flags);
- }
-
- break;
-
- case SNDCTL_DSP_SETDUPLEX:
- DPF(2, "SNDCTL_DSP_SETDUPLEX:\n");
- break;
-
- case SNDCTL_DSP_GETCAPS:
- DPF(2, "SNDCTL_DSP_GETCAPS:\n");
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
- DSP_CAP_TRIGGER | DSP_CAP_MMAP |
- DSP_CAP_COPROC| DSP_CAP_MULTI, p);
- case SNDCTL_DSP_SPEED:
- DPF(2, "SNDCTL_DSP_SPEED:\n");
-
- if (get_user(val, p))
- return -EFAULT;
-
- DPD(2, "val is %d\n", val);
-
- if (val > 0) {
- if (file->f_mode & FMODE_READ) {
- struct wave_format format;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- format = wiinst->format;
- format.samplingrate = val;
-
- if (emu10k1_wavein_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
- return -EINVAL;
- }
-
- val = wiinst->format.samplingrate;
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- DPD(2, "set recording sampling rate -> %d\n", val);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- struct wave_format format;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- format = woinst->format;
- format.samplingrate = val;
-
- if (emu10k1_waveout_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return -EINVAL;
- }
-
- val = woinst->format.samplingrate;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- DPD(2, "set playback sampling rate -> %d\n", val);
- }
-
- return put_user(val, p);
- } else {
- if (file->f_mode & FMODE_READ)
- val = wiinst->format.samplingrate;
- else if (file->f_mode & FMODE_WRITE)
- val = woinst->format.samplingrate;
-
- return put_user(val, p);
- }
- break;
-
- case SNDCTL_DSP_STEREO:
- DPF(2, "SNDCTL_DSP_STEREO:\n");
-
- if (get_user(val, p))
- return -EFAULT;
-
- DPD(2, " val is %d\n", val);
-
- if (file->f_mode & FMODE_READ) {
- struct wave_format format;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- format = wiinst->format;
- format.channels = val ? 2 : 1;
-
- if (emu10k1_wavein_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
- return -EINVAL;
- }
-
- val = wiinst->format.channels - 1;
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(2, "set recording stereo -> %d\n", val);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- struct wave_format format;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- format = woinst->format;
- format.channels = val ? 2 : 1;
-
- if (emu10k1_waveout_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return -EINVAL;
- }
-
- val = woinst->format.channels - 1;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- DPD(2, "set playback stereo -> %d\n", val);
- }
-
- return put_user(val, p);
-
- break;
-
- case SNDCTL_DSP_CHANNELS:
- DPF(2, "SNDCTL_DSP_CHANNELS:\n");
-
- if (get_user(val, p))
- return -EFAULT;
-
- DPD(2, " val is %d\n", val);
-
- if (val > 0) {
- if (file->f_mode & FMODE_READ) {
- struct wave_format format;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- format = wiinst->format;
- format.channels = val;
-
- if (emu10k1_wavein_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
- return -EINVAL;
- }
- val = wiinst->format.channels;
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(2, "set recording number of channels -> %d\n", val);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- struct wave_format format;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- format = woinst->format;
- format.channels = val;
-
- if (emu10k1_waveout_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return -EINVAL;
- }
-
- val = woinst->format.channels;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- DPD(2, "set playback number of channels -> %d\n", val);
- }
-
- return put_user(val, p);
- } else {
- if (file->f_mode & FMODE_READ)
- val = wiinst->format.channels;
- else if (file->f_mode & FMODE_WRITE)
- val = woinst->format.channels;
-
- return put_user(val, p);
- }
- break;
-
- case SNDCTL_DSP_GETFMTS:
- DPF(2, "SNDCTL_DSP_GETFMTS:\n");
-
- if (file->f_mode & FMODE_READ)
- val = AFMT_S16_LE;
- else if (file->f_mode & FMODE_WRITE) {
- val = AFMT_S16_LE | AFMT_U8;
- if (emu10k1_find_control_gpr(&wave_dev->card->mgr,
- wave_dev->card->pt.patch_name,
- wave_dev->card->pt.enable_gpr_name) >= 0)
- val |= AFMT_AC3;
- }
- return put_user(val, p);
-
- case SNDCTL_DSP_SETFMT: /* Same as SNDCTL_DSP_SAMPLESIZE */
- DPF(2, "SNDCTL_DSP_SETFMT:\n");
-
- if (get_user(val, p))
- return -EFAULT;
-
- DPD(2, " val is %d\n", val);
-
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- struct wave_format format;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- format = wiinst->format;
- format.id = val;
-
- if (emu10k1_wavein_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
- return -EINVAL;
- }
-
- val = wiinst->format.id;
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- DPD(2, "set recording format -> %d\n", val);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- struct wave_format format;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- format = woinst->format;
- format.id = val;
-
- if (emu10k1_waveout_setformat(wave_dev, &format) < 0) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return -EINVAL;
- }
-
- val = woinst->format.id;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- DPD(2, "set playback format -> %d\n", val);
- }
-
- return put_user(val, p);
- } else {
- if (file->f_mode & FMODE_READ)
- val = wiinst->format.id;
- else if (file->f_mode & FMODE_WRITE)
- val = woinst->format.id;
-
- return put_user(val, p);
- }
- break;
-
- case SOUND_PCM_READ_BITS:
-
- if (file->f_mode & FMODE_READ)
- val = wiinst->format.bitsperchannel;
- else if (file->f_mode & FMODE_WRITE)
- val = woinst->format.bitsperchannel;
-
- return put_user(val, p);
-
- case SOUND_PCM_READ_RATE:
-
- if (file->f_mode & FMODE_READ)
- val = wiinst->format.samplingrate;
- else if (file->f_mode & FMODE_WRITE)
- val = woinst->format.samplingrate;
-
- return put_user(val, p);
-
- case SOUND_PCM_READ_CHANNELS:
-
- if (file->f_mode & FMODE_READ)
- val = wiinst->format.channels;
- else if (file->f_mode & FMODE_WRITE)
- val = woinst->format.channels;
-
- return put_user(val, p);
-
- case SOUND_PCM_WRITE_FILTER:
- DPF(2, "SOUND_PCM_WRITE_FILTER: not implemented\n");
- break;
-
- case SOUND_PCM_READ_FILTER:
- DPF(2, "SOUND_PCM_READ_FILTER: not implemented\n");
- break;
-
- case SNDCTL_DSP_SETSYNCRO:
- DPF(2, "SNDCTL_DSP_SETSYNCRO: not implemented\n");
- break;
-
- case SNDCTL_DSP_GETTRIGGER:
- DPF(2, "SNDCTL_DSP_GETTRIGGER:\n");
-
- if (file->f_mode & FMODE_WRITE && (wave_dev->enablebits & PCM_ENABLE_OUTPUT))
- val |= PCM_ENABLE_OUTPUT;
-
- if (file->f_mode & FMODE_READ && (wave_dev->enablebits & PCM_ENABLE_INPUT))
- val |= PCM_ENABLE_INPUT;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- DPF(2, "SNDCTL_DSP_SETTRIGGER:\n");
-
- if (get_user(val, p))
- return -EFAULT;
-
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (val & PCM_ENABLE_OUTPUT) {
- wave_dev->enablebits |= PCM_ENABLE_OUTPUT;
- if (woinst->state & WAVE_STATE_OPEN)
- emu10k1_waveout_start(wave_dev);
- } else {
- wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT;
- if (woinst->state & WAVE_STATE_STARTED)
- emu10k1_waveout_stop(wave_dev);
- }
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (val & PCM_ENABLE_INPUT) {
- wave_dev->enablebits |= PCM_ENABLE_INPUT;
- if (wiinst->state & WAVE_STATE_OPEN)
- emu10k1_wavein_start(wave_dev);
- } else {
- wave_dev->enablebits &= ~PCM_ENABLE_INPUT;
- if (wiinst->state & WAVE_STATE_STARTED)
- emu10k1_wavein_stop(wave_dev);
- }
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- }
- break;
-
- case SNDCTL_DSP_GETOSPACE:
- {
- audio_buf_info info;
-
- DPF(4, "SNDCTL_DSP_GETOSPACE:\n");
-
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (woinst->state & WAVE_STATE_OPEN) {
- emu10k1_waveout_update(woinst);
- emu10k1_waveout_getxfersize(woinst, &bytestocopy);
- info.bytes = bytestocopy;
- } else {
- calculate_ofrag(woinst);
- info.bytes = woinst->buffer.size;
- }
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- info.bytes *= woinst->num_voices;
- info.fragsize = woinst->buffer.fragment_size * woinst->num_voices;
- info.fragstotal = woinst->buffer.numfrags * woinst->num_voices;
- info.fragments = info.bytes / info.fragsize;
-
- if (copy_to_user(p, &info, sizeof(info)))
- return -EFAULT;
- }
- break;
-
- case SNDCTL_DSP_GETISPACE:
- {
- audio_buf_info info;
-
- DPF(4, "SNDCTL_DSP_GETISPACE:\n");
-
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
-
- spin_lock_irqsave(&wiinst->lock, flags);
- if (wiinst->state & WAVE_STATE_OPEN) {
- emu10k1_wavein_update(wave_dev->card, wiinst);
- emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
- info.bytes = bytestocopy;
- } else {
- calculate_ifrag(wiinst);
- info.bytes = 0;
- }
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- info.fragstotal = wiinst->buffer.numfrags;
- info.fragments = info.bytes / wiinst->buffer.fragment_size;
- info.fragsize = wiinst->buffer.fragment_size;
-
- if (copy_to_user(p, &info, sizeof(info)))
- return -EFAULT;
- }
- break;
-
- case SNDCTL_DSP_NONBLOCK:
- DPF(2, "SNDCTL_DSP_NONBLOCK:\n");
-
- file->f_flags |= O_NONBLOCK;
- break;
-
- case SNDCTL_DSP_GETODELAY:
- DPF(4, "SNDCTL_DSP_GETODELAY:\n");
-
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- spin_lock_irqsave(&woinst->lock, flags);
- if (woinst->state & WAVE_STATE_OPEN) {
- emu10k1_waveout_update(woinst);
- emu10k1_waveout_getxfersize(woinst, &bytestocopy);
- val = woinst->buffer.size - bytestocopy;
- } else
- val = 0;
-
- val *= woinst->num_voices;
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- {
- count_info cinfo;
-
- DPF(4, "SNDCTL_DSP_GETIPTR: \n");
-
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (wiinst->state & WAVE_STATE_OPEN) {
- emu10k1_wavein_update(wave_dev->card, wiinst);
- cinfo.ptr = wiinst->buffer.hw_pos;
- cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % wiinst->buffer.size;
- cinfo.blocks = cinfo.bytes / wiinst->buffer.fragment_size - wiinst->blocks;
- wiinst->blocks = cinfo.bytes / wiinst->buffer.fragment_size;
- } else {
- cinfo.ptr = 0;
- cinfo.bytes = 0;
- cinfo.blocks = 0;
- }
-
- if (wiinst->mmapped)
- wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size;
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- if (copy_to_user(p, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- }
- break;
-
- case SNDCTL_DSP_GETOPTR:
- {
- count_info cinfo;
-
- DPF(4, "SNDCTL_DSP_GETOPTR:\n");
-
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (woinst->state & WAVE_STATE_OPEN ||
- ((woinst->format.passthrough == 1) && wave_dev->card->pt.state)) {
- int num_fragments;
-
- if (woinst->format.passthrough == 1) {
- emu10k1_pt_waveout_update(wave_dev);
- cinfo.bytes = woinst->total_played;
- } else {
- emu10k1_waveout_update(woinst);
- cinfo.bytes = woinst->total_played;
- }
-
- cinfo.ptr = woinst->buffer.hw_pos;
- num_fragments = cinfo.bytes / woinst->buffer.fragment_size;
- cinfo.blocks = num_fragments - woinst->blocks;
- woinst->blocks = num_fragments;
-
- cinfo.bytes *= woinst->num_voices;
- cinfo.ptr *= woinst->num_voices;
- } else {
- cinfo.ptr = 0;
- cinfo.bytes = 0;
- cinfo.blocks = 0;
- }
-
- if (woinst->mmapped)
- woinst->buffer.free_bytes %= woinst->buffer.fragment_size;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- if (copy_to_user(p, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- }
- break;
-
- case SNDCTL_DSP_GETBLKSIZE:
- DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n");
-
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
-
- calculate_ofrag(woinst);
- val = woinst->buffer.fragment_size * woinst->num_voices;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
-
- calculate_ifrag(wiinst);
- val = wiinst->buffer.fragment_size;
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- }
-
- return put_user(val, p);
-
- break;
-
- case SNDCTL_DSP_POST:
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (!(woinst->state & WAVE_STATE_STARTED)
- && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)
- && (woinst->total_copied > 0))
- emu10k1_waveout_start(wave_dev);
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- break;
-
- case SNDCTL_DSP_SUBDIVIDE:
- DPF(2, "SNDCTL_DSP_SUBDIVIDE: not implemented\n");
- break;
-
- case SNDCTL_DSP_SETFRAGMENT:
- DPF(2, "SNDCTL_DSP_SETFRAGMENT:\n");
-
- if (get_user(val, p))
- return -EFAULT;
-
- DPD(2, "val is %#x\n", val);
-
- if (val == 0)
- return -EIO;
-
- if (file->f_mode & FMODE_WRITE) {
- /* digital pass-through fragment count and size are fixed values */
- if (woinst->state & WAVE_STATE_OPEN || (woinst->format.passthrough == 1))
- return -EINVAL; /* too late to change */
-
- woinst->buffer.ossfragshift = val & 0xffff;
- woinst->buffer.numfrags = (val >> 16) & 0xffff;
- }
-
- if (file->f_mode & FMODE_READ) {
- if (wiinst->state & WAVE_STATE_OPEN)
- return -EINVAL; /* too late to change */
-
- wiinst->buffer.ossfragshift = val & 0xffff;
- wiinst->buffer.numfrags = (val >> 16) & 0xffff;
- }
-
- break;
-
- case SNDCTL_COPR_LOAD:
- {
- copr_buffer *buf;
- u32 i;
-
- DPF(4, "SNDCTL_COPR_LOAD:\n");
-
- buf = kmalloc(sizeof(copr_buffer), GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, p, sizeof(copr_buffer))) {
- kfree (buf);
- return -EFAULT;
- }
-
- if ((buf->command != CMD_READ) && (buf->command != CMD_WRITE)) {
- kfree (buf);
- return -EINVAL;
- }
-
- if (buf->command == CMD_WRITE) {
-
-#ifdef DBGEMU
- if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) {
-#else
- if (((buf->offs < 0x100) || (buf->offs + buf->len > (wave_dev->card->is_audigy ? 0xe00 : 0x800)) || (buf->len > 1000)
- ) && !(
- //any register allowed raw access to users goes here:
- (buf->offs == DBG ||
- buf->offs == A_DBG)
- && (buf->len == 1))) {
-#endif
- kfree(buf);
- return -EINVAL;
- }
- } else {
- if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) {
- kfree(buf);
- return -EINVAL;
- }
- }
-
- if (((unsigned)buf->flags) > 0x3f)
- buf->flags = 0;
-
- if (buf->command == CMD_READ) {
- for (i = 0; i < buf->len; i++)
- ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, buf->flags);
-
- if (copy_to_user(p, buf, sizeof(copr_buffer))) {
- kfree(buf);
- return -EFAULT;
- }
- } else {
- for (i = 0; i < buf->len; i++)
- sblive_writeptr(wave_dev->card, buf->offs + i, buf->flags, ((u32 *) buf->data)[i]);
- }
-
- kfree (buf);
- break;
- }
-
- default: /* Default is unrecognized command */
- DPD(2, "default: %#x\n", cmd);
- return -EINVAL;
- }
- return 0;
-}
-
-static struct page *emu10k1_mm_nopage (struct vm_area_struct * vma, unsigned long address, int *type)
-{
- struct emu10k1_wavedevice *wave_dev = vma->vm_private_data;
- struct woinst *woinst = wave_dev->woinst;
- struct wiinst *wiinst = wave_dev->wiinst;
- struct page *dmapage;
- unsigned long pgoff;
- int rd, wr;
-
- DPF(3, "emu10k1_mm_nopage()\n");
- DPD(3, "addr: %#lx\n", address);
-
- if (address > vma->vm_end) {
- DPF(1, "EXIT, returning NOPAGE_SIGBUS\n");
- return NOPAGE_SIGBUS; /* Disallow mremap */
- }
-
- pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT);
- if (woinst != NULL)
- wr = woinst->mmapped;
- else
- wr = 0;
-
- if (wiinst != NULL)
- rd = wiinst->mmapped;
- else
- rd = 0;
-
- /* if full-duplex (read+write) and we have two sets of bufs,
- * then the playback buffers come first, sez soundcard.c */
- if (wr) {
- if (pgoff >= woinst->buffer.pages) {
- pgoff -= woinst->buffer.pages;
- dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE);
- } else
- dmapage = virt_to_page (woinst->voice[0].mem.addr[pgoff]);
- } else {
- dmapage = virt_to_page ((u8 *) wiinst->buffer.addr + pgoff * PAGE_SIZE);
- }
-
- get_page (dmapage);
-
- DPD(3, "page: %#lx\n", (unsigned long) dmapage);
- if (type)
- *type = VM_FAULT_MINOR;
- return dmapage;
-}
-
-static struct vm_operations_struct emu10k1_mm_ops = {
- .nopage = emu10k1_mm_nopage,
-};
-
-static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- unsigned long max_pages, n_pages, pgoffset;
- struct woinst *woinst = NULL;
- struct wiinst *wiinst = NULL;
- unsigned long flags;
-
- DPF(2, "emu10k1_audio_mmap()\n");
-
- max_pages = 0;
- if (vma->vm_flags & VM_WRITE) {
- woinst = wave_dev->woinst;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- /* No m'mapping possible for multichannel */
- if (woinst->num_voices > 1) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return -EINVAL;
- }
-
- if (woinst->state == WAVE_STATE_CLOSED) {
- calculate_ofrag(woinst);
-
- if (emu10k1_waveout_open(wave_dev) < 0) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- ERROR();
- return -EINVAL;
- }
- }
-
- woinst->mmapped = 1;
- max_pages += woinst->buffer.pages;
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- if (vma->vm_flags & VM_READ) {
- wiinst = wave_dev->wiinst;
-
- spin_lock_irqsave(&wiinst->lock, flags);
- if (wiinst->state == WAVE_STATE_CLOSED) {
- calculate_ifrag(wiinst);
-
- if (emu10k1_wavein_open(wave_dev) < 0) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
- ERROR();
- return -EINVAL;
- }
- }
-
- wiinst->mmapped = 1;
- max_pages += wiinst->buffer.pages;
- spin_unlock_irqrestore(&wiinst->lock, flags);
- }
-
- n_pages = ((vma->vm_end - vma->vm_start) + PAGE_SIZE - 1) >> PAGE_SHIFT;
- pgoffset = vma->vm_pgoff;
-
- DPD(2, "vma_start: %#lx, vma_end: %#lx, vma_offset: %ld\n", vma->vm_start, vma->vm_end, pgoffset);
- DPD(2, "n_pages: %ld, max_pages: %ld\n", n_pages, max_pages);
-
- if (pgoffset + n_pages > max_pages)
- return -EINVAL;
-
- vma->vm_flags |= VM_RESERVED;
- vma->vm_ops = &emu10k1_mm_ops;
- vma->vm_private_data = wave_dev;
- return 0;
-}
-
-static int emu10k1_audio_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct emu10k1_card *card = NULL;
- struct list_head *entry;
- struct emu10k1_wavedevice *wave_dev;
-
- DPF(2, "emu10k1_audio_open()\n");
-
- /* Check for correct device to open */
-
- list_for_each(entry, &emu10k1_devs) {
- card = list_entry(entry, struct emu10k1_card, list);
-
- if (!((card->audio_dev ^ minor) & ~0xf) || !((card->audio_dev1 ^ minor) & ~0xf))
- goto match;
- }
-
- return -ENODEV;
-
-match:
-
- wave_dev = kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL);
-
- if (wave_dev == NULL) {
- ERROR();
- return -ENOMEM;
- }
-
- wave_dev->card = card;
- wave_dev->wiinst = NULL;
- wave_dev->woinst = NULL;
- wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT; /* Default */
-
- if (file->f_mode & FMODE_READ) {
- /* Recording */
- struct wiinst *wiinst;
-
- if ((wiinst = kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
- ERROR();
- kfree(wave_dev);
- return -ENOMEM;
- }
-
- wiinst->recsrc = card->wavein.recsrc;
- wiinst->fxwc = card->wavein.fxwc;
-
- switch (wiinst->recsrc) {
- case WAVERECORD_AC97:
- wiinst->format.id = AFMT_S16_LE;
- wiinst->format.samplingrate = 8000;
- wiinst->format.bitsperchannel = 16;
- wiinst->format.channels = 1;
- break;
- case WAVERECORD_MIC:
- wiinst->format.id = AFMT_S16_LE;
- wiinst->format.samplingrate = 8000;
- wiinst->format.bitsperchannel = 16;
- wiinst->format.channels = 1;
- break;
- case WAVERECORD_FX:
- wiinst->format.id = AFMT_S16_LE;
- wiinst->format.samplingrate = 48000;
- wiinst->format.bitsperchannel = 16;
- wiinst->format.channels = hweight32(wiinst->fxwc);
- break;
- default:
- kfree(wave_dev);
- kfree(wiinst);
- BUG();
- break;
- }
-
- wiinst->state = WAVE_STATE_CLOSED;
-
- wiinst->buffer.ossfragshift = 0;
- wiinst->buffer.fragment_size = 0;
- wiinst->buffer.numfrags = 0;
-
- init_waitqueue_head(&wiinst->wait_queue);
-
- wiinst->mmapped = 0;
- wiinst->total_recorded = 0;
- wiinst->blocks = 0;
- spin_lock_init(&wiinst->lock);
- tasklet_init(&wiinst->timer.tasklet, emu10k1_wavein_bh, (unsigned long) wave_dev);
- wave_dev->wiinst = wiinst;
- emu10k1_wavein_setformat(wave_dev, &wiinst->format);
- }
-
- if (file->f_mode & FMODE_WRITE) {
- struct woinst *woinst;
- int i;
-
- if ((woinst = kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) {
- ERROR();
- kfree(wave_dev);
- return -ENOMEM;
- }
-
- if (wave_dev->wiinst != NULL) {
- woinst->format = wave_dev->wiinst->format;
- } else {
- woinst->format.id = AFMT_U8;
- woinst->format.samplingrate = 8000;
- woinst->format.bitsperchannel = 8;
- woinst->format.channels = 1;
- }
-
- woinst->state = WAVE_STATE_CLOSED;
-
- woinst->buffer.fragment_size = 0;
- woinst->buffer.ossfragshift = 0;
- woinst->buffer.numfrags = 0;
- woinst->device = (card->audio_dev1 == minor);
- woinst->timer.state = TIMER_STATE_UNINSTALLED;
- woinst->num_voices = 1;
- for (i = 0; i < WAVEOUT_MAXVOICES; i++) {
- woinst->voice[i].usage = VOICE_USAGE_FREE;
- woinst->voice[i].mem.emupageindex = -1;
- }
-
- init_waitqueue_head(&woinst->wait_queue);
-
- woinst->mmapped = 0;
- woinst->total_copied = 0;
- woinst->total_played = 0;
- woinst->blocks = 0;
- spin_lock_init(&woinst->lock);
- tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev);
- wave_dev->woinst = woinst;
- emu10k1_waveout_setformat(wave_dev, &woinst->format);
- }
-
- file->private_data = (void *) wave_dev;
-
- return nonseekable_open(inode, file);
-}
-
-static int emu10k1_audio_release(struct inode *inode, struct file *file)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- struct emu10k1_card *card;
- unsigned long flags;
-
- card = wave_dev->card;
-
- DPF(2, "emu10k1_audio_release()\n");
-
- if (file->f_mode & FMODE_WRITE) {
- struct woinst *woinst = wave_dev->woinst;
-
- spin_lock_irqsave(&woinst->lock, flags);
- if(woinst->format.passthrough==2)
- card->pt.state=PT_STATE_PLAYING;
- if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE){
- spin_lock(&card->pt.lock);
- emu10k1_pt_stop(card);
- spin_unlock(&card->pt.lock);
- }
- if (woinst->state & WAVE_STATE_OPEN) {
- if (woinst->state & WAVE_STATE_STARTED) {
- if (!(file->f_flags & O_NONBLOCK)) {
- while (!signal_pending(current)
- && (woinst->total_played < woinst->total_copied)) {
- DPF(4, "Buffer hasn't been totally played, sleep....\n");
- spin_unlock_irqrestore(&woinst->lock, flags);
- interruptible_sleep_on(&woinst->wait_queue);
- spin_lock_irqsave(&woinst->lock, flags);
- }
- }
- }
- emu10k1_waveout_close(wave_dev);
- }
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- /* remove the tasklet */
- tasklet_kill(&woinst->timer.tasklet);
- kfree(wave_dev->woinst);
- }
-
- if (file->f_mode & FMODE_READ) {
- struct wiinst *wiinst = wave_dev->wiinst;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (wiinst->state & WAVE_STATE_OPEN) {
- emu10k1_wavein_close(wave_dev);
- }
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- tasklet_kill(&wiinst->timer.tasklet);
- kfree(wave_dev->wiinst);
- }
-
- kfree(wave_dev);
-
- if (waitqueue_active(&card->open_wait))
- wake_up_interruptible(&card->open_wait);
-
- return 0;
-}
-
-/* FIXME sort out poll() + mmap() */
-static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- struct woinst *woinst = wave_dev->woinst;
- struct wiinst *wiinst = wave_dev->wiinst;
- unsigned int mask = 0;
- u32 bytestocopy;
- unsigned long flags;
-
- DPF(4, "emu10k1_audio_poll()\n");
-
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &woinst->wait_queue, wait);
-
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &wiinst->wait_queue, wait);
-
- if (file->f_mode & FMODE_WRITE) {
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (woinst->state & WAVE_STATE_OPEN) {
- emu10k1_waveout_update(woinst);
- emu10k1_waveout_getxfersize(woinst, &bytestocopy);
-
- if (bytestocopy >= woinst->buffer.fragment_size)
- mask |= POLLOUT | POLLWRNORM;
- } else
- mask |= POLLOUT | POLLWRNORM;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
- }
-
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (wiinst->state & WAVE_STATE_OPEN) {
- emu10k1_wavein_update(wave_dev->card, wiinst);
- emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
-
- if (bytestocopy >= wiinst->buffer.fragment_size)
- mask |= POLLIN | POLLRDNORM;
- }
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
- }
-
- return mask;
-}
-
-static void calculate_ofrag(struct woinst *woinst)
-{
- struct waveout_buffer *buffer = &woinst->buffer;
- u32 fragsize;
-
- if (buffer->fragment_size)
- return;
-
- if (!buffer->ossfragshift) {
- fragsize = (woinst->format.bytespervoicesample * woinst->format.samplingrate * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1;
-
- while (fragsize) {
- fragsize >>= 1;
- buffer->ossfragshift++;
- }
- }
-
- if (buffer->ossfragshift < WAVEOUT_MINFRAGSHIFT)
- buffer->ossfragshift = WAVEOUT_MINFRAGSHIFT;
-
- buffer->fragment_size = 1 << buffer->ossfragshift;
-
- while (buffer->fragment_size * WAVEOUT_MINFRAGS > WAVEOUT_MAXBUFSIZE)
- buffer->fragment_size >>= 1;
-
- /* now we are sure that:
- (2^WAVEOUT_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEOUT_MAXBUFSIZE / WAVEOUT_MINFRAGS)
- */
-
- if (!buffer->numfrags) {
- u32 numfrags;
-
- numfrags = (woinst->format.bytespervoicesample * woinst->format.samplingrate * WAVEOUT_DEFAULTBUFLEN) /
- (buffer->fragment_size * 1000) - 1;
-
- buffer->numfrags = 1;
-
- while (numfrags) {
- numfrags >>= 1;
- buffer->numfrags <<= 1;
- }
- }
-
- if (buffer->numfrags < WAVEOUT_MINFRAGS)
- buffer->numfrags = WAVEOUT_MINFRAGS;
-
- if (buffer->numfrags * buffer->fragment_size > WAVEOUT_MAXBUFSIZE)
- buffer->numfrags = WAVEOUT_MAXBUFSIZE / buffer->fragment_size;
-
- if (buffer->numfrags < WAVEOUT_MINFRAGS)
- BUG();
-
- buffer->size = buffer->fragment_size * buffer->numfrags;
- buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);
-
- DPD(2, " calculated playback fragment_size -> %d\n", buffer->fragment_size);
- DPD(2, " calculated playback numfrags -> %d\n", buffer->numfrags);
-
- return;
-}
-
-static void calculate_ifrag(struct wiinst *wiinst)
-{
- struct wavein_buffer *buffer = &wiinst->buffer;
- u32 fragsize, bufsize, size[4];
- int i, j;
-
- if (buffer->fragment_size)
- return;
-
- if (!buffer->ossfragshift) {
- fragsize = (wiinst->format.bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1;
-
- while (fragsize) {
- fragsize >>= 1;
- buffer->ossfragshift++;
- }
- }
-
- if (buffer->ossfragshift < WAVEIN_MINFRAGSHIFT)
- buffer->ossfragshift = WAVEIN_MINFRAGSHIFT;
-
- buffer->fragment_size = 1 << buffer->ossfragshift;
-
- while (buffer->fragment_size * WAVEIN_MINFRAGS > WAVEIN_MAXBUFSIZE)
- buffer->fragment_size >>= 1;
-
- /* now we are sure that:
- (2^WAVEIN_MINFRAGSHIFT) <= (fragment_size = 2^n) <= (WAVEIN_MAXBUFSIZE / WAVEIN_MINFRAGS)
- */
-
-
- if (!buffer->numfrags)
- buffer->numfrags = (wiinst->format.bytespersec * WAVEIN_DEFAULTBUFLEN) / (buffer->fragment_size * 1000) - 1;
-
- if (buffer->numfrags < WAVEIN_MINFRAGS)
- buffer->numfrags = WAVEIN_MINFRAGS;
-
- if (buffer->numfrags * buffer->fragment_size > WAVEIN_MAXBUFSIZE)
- buffer->numfrags = WAVEIN_MAXBUFSIZE / buffer->fragment_size;
-
- if (buffer->numfrags < WAVEIN_MINFRAGS)
- BUG();
-
- bufsize = buffer->fragment_size * buffer->numfrags;
-
- /* the buffer size for recording is restricted to certain values, adjust it now */
- if (bufsize >= 0x10000) {
- buffer->size = 0x10000;
- buffer->sizeregval = 0x1f;
- } else {
- buffer->size = 0;
- size[0] = 384;
- size[1] = 448;
- size[2] = 512;
- size[3] = 640;
-
- for (i = 0; i < 8; i++)
- for (j = 0; j < 4; j++)
- if (bufsize >= size[j]) {
- buffer->size = size[j];
- size[j] *= 2;
- buffer->sizeregval = i * 4 + j + 1;
- } else
- goto exitloop;
- exitloop:
- if (buffer->size == 0) {
- buffer->size = 384;
- buffer->sizeregval = 0x01;
- }
- }
-
- /* adjust the fragment size so that buffer size is an integer multiple */
- while (buffer->size % buffer->fragment_size)
- buffer->fragment_size >>= 1;
-
- buffer->numfrags = buffer->size / buffer->fragment_size;
- buffer->pages = buffer->size / PAGE_SIZE + ((buffer->size % PAGE_SIZE) ? 1 : 0);
-
- DPD(2, " calculated recording fragment_size -> %d\n", buffer->fragment_size);
- DPD(2, " calculated recording numfrags -> %d\n", buffer->numfrags);
- DPD(2, " buffer size register -> %#04x\n", buffer->sizeregval);
-
- return;
-}
-
-static void emu10k1_wavein_bh(unsigned long refdata)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
- struct wiinst *wiinst = wave_dev->wiinst;
- u32 bytestocopy;
- unsigned long flags;
-
- if (!wiinst)
- return;
-
- spin_lock_irqsave(&wiinst->lock, flags);
-
- if (!(wiinst->state & WAVE_STATE_STARTED)) {
- spin_unlock_irqrestore(&wiinst->lock, flags);
- return;
- }
-
- emu10k1_wavein_update(wave_dev->card, wiinst);
- emu10k1_wavein_getxfersize(wiinst, &bytestocopy);
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- if (bytestocopy >= wiinst->buffer.fragment_size) {
- if (waitqueue_active(&wiinst->wait_queue))
- wake_up_interruptible(&wiinst->wait_queue);
- } else
- DPD(3, "Not enough transfer size, %d\n", bytestocopy);
-
- return;
-}
-
-static void emu10k1_waveout_bh(unsigned long refdata)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
- struct woinst *woinst = wave_dev->woinst;
- u32 bytestocopy;
- unsigned long flags;
-
- if (!woinst)
- return;
-
- spin_lock_irqsave(&woinst->lock, flags);
-
- if (!(woinst->state & WAVE_STATE_STARTED)) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- return;
- }
-
- emu10k1_waveout_update(woinst);
- emu10k1_waveout_getxfersize(woinst, &bytestocopy);
-
- if (woinst->buffer.fill_silence) {
- spin_unlock_irqrestore(&woinst->lock, flags);
- emu10k1_waveout_fillsilence(woinst);
- } else
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- if (bytestocopy >= woinst->buffer.fragment_size) {
- if (waitqueue_active(&woinst->wait_queue))
- wake_up_interruptible(&woinst->wait_queue);
- } else
- DPD(3, "Not enough transfer size -> %d\n", bytestocopy);
-
- return;
-}
-
-const struct file_operations emu10k1_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = emu10k1_audio_read,
- .write = emu10k1_audio_write,
- .poll = emu10k1_audio_poll,
- .ioctl = emu10k1_audio_ioctl,
- .mmap = emu10k1_audio_mmap,
- .open = emu10k1_audio_open,
- .release = emu10k1_audio_release,
-};
diff --git a/sound/oss/emu10k1/audio.h b/sound/oss/emu10k1/audio.h
deleted file mode 100644
index 26ee81bbd6c6..000000000000
--- a/sound/oss/emu10k1/audio.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- **********************************************************************
- * audio.c -- /dev/dsp interface for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up types/leaks
- *
- **********************************************************************
- *
- * 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 _AUDIO_H
-#define _AUDIO_H
-
-struct emu10k1_wavedevice
-{
- struct emu10k1_card *card;
- struct wiinst *wiinst;
- struct woinst *woinst;
- u16 enablebits;
-};
-
-#endif /* _AUDIO_H */
diff --git a/sound/oss/emu10k1/cardmi.c b/sound/oss/emu10k1/cardmi.c
deleted file mode 100644
index 57674f8c8a2e..000000000000
--- a/sound/oss/emu10k1/cardmi.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- **********************************************************************
- * sblive_mi.c - MIDI UART input HAL for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox clean up
- *
- **********************************************************************
- *
- * 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/slab.h>
-#include <linux/jiffies.h>
-
-#include "hwaccess.h"
-#include "8010.h"
-#include "cardmi.h"
-#include "irqmgr.h"
-
-
-static int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid);
-
-static int sblive_miStateInit(struct emu10k1_mpuin *);
-static int sblive_miStateEntry(struct emu10k1_mpuin *, u8);
-static int sblive_miStateParse(struct emu10k1_mpuin *, u8);
-static int sblive_miState3Byte(struct emu10k1_mpuin *, u8);
-static int sblive_miState3ByteKey(struct emu10k1_mpuin *, u8);
-static int sblive_miState3ByteVel(struct emu10k1_mpuin *, u8);
-static int sblive_miState2Byte(struct emu10k1_mpuin *, u8);
-static int sblive_miState2ByteKey(struct emu10k1_mpuin *, u8);
-static int sblive_miStateSysCommon2(struct emu10k1_mpuin *, u8);
-static int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *, u8);
-static int sblive_miStateSysCommon3(struct emu10k1_mpuin *, u8);
-static int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *, u8);
-static int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *, u8);
-static int sblive_miStateSysExNorm(struct emu10k1_mpuin *, u8);
-static int sblive_miStateSysReal(struct emu10k1_mpuin *, u8);
-
-
-static struct {
- int (*Fn) (struct emu10k1_mpuin *, u8);
-} midistatefn[] = {
-
- {
- sblive_miStateParse}, {
- sblive_miState3Byte}, /* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */
- {
- sblive_miState3ByteKey}, /* Byte 1 */
- {
- sblive_miState3ByteVel}, /* Byte 2 */
- {
- sblive_miState2Byte}, /* 0xCn, 0xDn */
- {
- sblive_miState2ByteKey}, /* Byte 1 */
- {
- sblive_miStateSysCommon2}, /* 0xF1 , 0xF3 */
- {
- sblive_miStateSysCommon2Key}, /* 0xF1 , 0xF3, Byte 1 */
- {
- sblive_miStateSysCommon3}, /* 0xF2 */
- {
- sblive_miStateSysCommon3Key}, /* 0xF2 , Byte 1 */
- {
- sblive_miStateSysCommon3Vel}, /* 0xF2 , Byte 2 */
- {
- sblive_miStateSysExNorm}, /* 0xF0, 0xF7, Normal mode */
- {
- sblive_miStateSysReal} /* 0xF4 - 0xF6 ,0xF8 - 0xFF */
-};
-
-
-/* Installs the IRQ handler for the MPU in port */
-
-/* and initialize parameters */
-
-int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
-{
- struct emu10k1_mpuin *card_mpuin = card->mpuin;
-
- DPF(2, "emu10k1_mpuin_open\n");
-
- if (!(card_mpuin->status & FLAGS_AVAILABLE))
- return -1;
-
- /* Copy open info and mark channel as in use */
- card_mpuin->openinfo = *openinfo;
- card_mpuin->status &= ~FLAGS_AVAILABLE; /* clear */
- card_mpuin->status |= FLAGS_READY; /* set */
- card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
- card_mpuin->firstmidiq = NULL;
- card_mpuin->lastmidiq = NULL;
- card_mpuin->qhead = 0;
- card_mpuin->qtail = 0;
-
- sblive_miStateInit(card_mpuin);
-
- emu10k1_mpu_reset(card);
- emu10k1_mpu_acquire(card);
-
- return 0;
-}
-
-int emu10k1_mpuin_close(struct emu10k1_card *card)
-{
- struct emu10k1_mpuin *card_mpuin = card->mpuin;
-
- DPF(2, "emu10k1_mpuin_close()\n");
-
- /* Check if there are pending input SysEx buffers */
- if (card_mpuin->firstmidiq != NULL) {
- ERROR();
- return -1;
- }
-
- /* Disable RX interrupt */
- emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
-
- emu10k1_mpu_release(card);
-
- card_mpuin->status |= FLAGS_AVAILABLE; /* set */
- card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
-
- return 0;
-}
-
-/* Adds MIDI buffer to local queue list */
-
-int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr *midihdr)
-{
- struct midi_queue *midiq;
- unsigned long flags;
-
- DPF(2, "emu10k1_mpuin_add_buffer()\n");
-
- /* Update MIDI buffer flags */
- midihdr->flags |= MIDIBUF_INQUEUE; /* set */
- midihdr->flags &= ~MIDIBUF_DONE; /* clear */
-
- if ((midiq = kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
- /* Message lost */
- return -1;
- }
-
- midiq->next = NULL;
- midiq->qtype = 1;
- midiq->length = midihdr->bufferlength;
- midiq->sizeLeft = midihdr->bufferlength;
- midiq->midibyte = midihdr->data;
- midiq->refdata = (unsigned long) midihdr;
-
- spin_lock_irqsave(&card_mpuin->lock, flags);
-
- if (card_mpuin->firstmidiq == NULL) {
- card_mpuin->firstmidiq = midiq;
- card_mpuin->lastmidiq = midiq;
- } else {
- (card_mpuin->lastmidiq)->next = midiq;
- card_mpuin->lastmidiq = midiq;
- }
-
- spin_unlock_irqrestore(&card_mpuin->lock, flags);
-
- return 0;
-}
-
-/* First set the Time Stamp if MIDI IN has not started. */
-
-/* Then enable RX Irq. */
-
-int emu10k1_mpuin_start(struct emu10k1_card *card)
-{
- struct emu10k1_mpuin *card_mpuin = card->mpuin;
- u8 dummy;
-
- DPF(2, "emu10k1_mpuin_start()\n");
-
- /* Set timestamp if not set */
- if (card_mpuin->status & FLAGS_MIDM_STARTED) {
- DPF(2, "Time Stamp not changed\n");
- } else {
- while (!emu10k1_mpu_read_data(card, &dummy));
-
- card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */
-
- /* Set new time stamp */
- card_mpuin->timestart = (jiffies * 1000) / HZ;
- DPD(2, "New Time Stamp = %d\n", card_mpuin->timestart);
-
- card_mpuin->qhead = 0;
- card_mpuin->qtail = 0;
-
- emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
- }
-
- return 0;
-}
-
-/* Disable the RX Irq. If a partial recorded buffer */
-
-/* exist, send it up to IMIDI level. */
-
-int emu10k1_mpuin_stop(struct emu10k1_card *card)
-{
- struct emu10k1_mpuin *card_mpuin = card->mpuin;
- struct midi_queue *midiq;
- unsigned long flags;
-
- DPF(2, "emu10k1_mpuin_stop()\n");
-
- emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
-
- card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
-
- if (card_mpuin->firstmidiq) {
- spin_lock_irqsave(&card_mpuin->lock, flags);
-
- midiq = card_mpuin->firstmidiq;
- if (midiq != NULL) {
- if (midiq->sizeLeft == midiq->length)
- midiq = NULL;
- else {
- card_mpuin->firstmidiq = midiq->next;
- if (card_mpuin->firstmidiq == NULL)
- card_mpuin->lastmidiq = NULL;
- }
- }
-
- spin_unlock_irqrestore(&card_mpuin->lock, flags);
-
- if (midiq) {
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
- kfree(midiq);
- }
- }
-
- return 0;
-}
-
-/* Disable the RX Irq. If any buffer */
-
-/* exist, send it up to IMIDI level. */
-int emu10k1_mpuin_reset(struct emu10k1_card *card)
-{
- struct emu10k1_mpuin *card_mpuin = card->mpuin;
- struct midi_queue *midiq;
-
- DPF(2, "emu10k1_mpuin_reset()\n");
-
- emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
-
- while (card_mpuin->firstmidiq) {
- midiq = card_mpuin->firstmidiq;
- card_mpuin->firstmidiq = midiq->next;
-
- if (midiq->sizeLeft == midiq->length)
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
- else
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
-
- kfree(midiq);
- }
-
- card_mpuin->lastmidiq = NULL;
- card_mpuin->status &= ~FLAGS_MIDM_STARTED;
-
- return 0;
-}
-
-/* Passes the message with the data back to the client */
-
-/* via IRQ & DPC callbacks to Ring 3 */
-static int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid)
-{
- unsigned long timein;
- struct midi_queue *midiq;
- unsigned long callback_msg[3];
- struct midi_hdr *midihdr;
-
- /* Called during ISR. The data & code touched are:
- * 1. card_mpuin
- * 2. The function to be called
- */
-
- timein = card_mpuin->timein;
- if (card_mpuin->timestart <= timein)
- callback_msg[0] = timein - card_mpuin->timestart;
- else
- callback_msg[0] = (~0x0L - card_mpuin->timestart) + timein;
-
- if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR) {
- callback_msg[1] = data;
- callback_msg[2] = bytesvalid;
- DPD(2, "emu10k1_mpuin_callback: midimsg = %#lx\n", data);
- } else {
- midiq = (struct midi_queue *) data;
- midihdr = (struct midi_hdr *) midiq->refdata;
-
- callback_msg[1] = midiq->length - midiq->sizeLeft;
- callback_msg[2] = midiq->refdata;
- midihdr->flags &= ~MIDIBUF_INQUEUE;
- midihdr->flags |= MIDIBUF_DONE;
-
- midihdr->bytesrecorded = midiq->length - midiq->sizeLeft;
- }
-
- /* Notify client that Sysex buffer has been sent */
- emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg);
-
- return 0;
-}
-
-void emu10k1_mpuin_bh(unsigned long refdata)
-{
- u8 data;
- unsigned idx;
- struct emu10k1_mpuin *card_mpuin = (struct emu10k1_mpuin *) refdata;
- unsigned long flags;
-
- while (card_mpuin->qhead != card_mpuin->qtail) {
- spin_lock_irqsave(&card_mpuin->lock, flags);
- idx = card_mpuin->qhead;
- data = card_mpuin->midiq[idx].data;
- card_mpuin->timein = card_mpuin->midiq[idx].timein;
- idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
- card_mpuin->qhead = idx;
- spin_unlock_irqrestore(&card_mpuin->lock, flags);
-
- sblive_miStateEntry(card_mpuin, data);
- }
-
- return;
-}
-
-/* IRQ callback handler routine for the MPU in port */
-
-int emu10k1_mpuin_irqhandler(struct emu10k1_card *card)
-{
- unsigned idx;
- unsigned count;
- u8 MPUIvalue;
- struct emu10k1_mpuin *card_mpuin = card->mpuin;
-
- /* IRQ service routine. The data and code touched are:
- * 1. card_mpuin
- */
-
- count = 0;
- idx = card_mpuin->qtail;
-
- while (1) {
- if (emu10k1_mpu_read_data(card, &MPUIvalue) < 0) {
- break;
- } else {
- ++count;
- card_mpuin->midiq[idx].data = MPUIvalue;
- card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ;
- idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
- }
- }
-
- if (count) {
- card_mpuin->qtail = idx;
-
- tasklet_hi_schedule(&card_mpuin->tasklet);
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-/* Supporting functions for Midi-In Interpretation State Machine */
-
-/*****************************************************************************/
-
-/* FIXME: This should be a macro */
-static int sblive_miStateInit(struct emu10k1_mpuin *card_mpuin)
-{
- card_mpuin->status = 0; /* For MIDI running status */
- card_mpuin->fstatus = 0; /* For 0xFn status only */
- card_mpuin->curstate = STIN_PARSE;
- card_mpuin->laststate = STIN_PARSE;
- card_mpuin->data = 0;
- card_mpuin->timestart = 0;
- card_mpuin->timein = 0;
-
- return 0;
-}
-
-/* FIXME: This should be a macro */
-static int sblive_miStateEntry(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
-}
-
-static int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- switch (data & 0xf0) {
- case 0x80:
- case 0x90:
- case 0xA0:
- case 0xB0:
- case 0xE0:
- card_mpuin->curstate = STIN_3BYTE;
- break;
-
- case 0xC0:
- case 0xD0:
- card_mpuin->curstate = STIN_2BYTE;
- break;
-
- case 0xF0:
- /* System messages do not affect the previous running status! */
- switch (data & 0x0f) {
- case 0x0:
- card_mpuin->laststate = card_mpuin->curstate;
- card_mpuin->curstate = STIN_SYS_EX_NORM;
-
- if (card_mpuin->firstmidiq) {
- struct midi_queue *midiq;
-
- midiq = card_mpuin->firstmidiq;
- *midiq->midibyte = data;
- --midiq->sizeLeft;
- ++midiq->midibyte;
- }
-
- return CTSTATUS_NEXT_BYTE;
-
- case 0x7:
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0);
- return -1;
-
- case 0x2:
- card_mpuin->laststate = card_mpuin->curstate;
- card_mpuin->curstate = STIN_SYS_COMMON_3;
- break;
-
- case 0x1:
- case 0x3:
- card_mpuin->laststate = card_mpuin->curstate;
- card_mpuin->curstate = STIN_SYS_COMMON_2;
- break;
-
- default:
- /* includes 0xF4 - 0xF6, 0xF8 - 0xFF */
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
- }
-
- break;
-
- default:
- DPF(2, "BUG: default case hit\n");
- return -1;
- }
-
- return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
-}
-
-static int sblive_miState3Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- u8 temp = data & 0xf0;
-
- if (temp < 0x80) {
- return midistatefn[STIN_3BYTE_KEY].Fn(card_mpuin, data);
- } else if (temp <= 0xe0 && temp != 0xc0 && temp != 0xd0) {
- card_mpuin->status = data;
- card_mpuin->curstate = STIN_3BYTE_KEY;
-
- return CTSTATUS_NEXT_BYTE;
- }
-
- return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
-}
-
-static int sblive_miState3ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
-/* byte 1 */
-{
- unsigned long tmp;
-
- if (data > 0x7f) {
- /* Real-time messages check */
- if (data > 0xf7)
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
-
- /* Invalid data! */
- DPF(2, "Invalid data!\n");
-
- card_mpuin->curstate = STIN_PARSE;
- tmp = ((unsigned long) data) << 8;
- tmp |= (unsigned long) card_mpuin->status;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
-
- return -1;
- }
-
- card_mpuin->data = data;
- card_mpuin->curstate = STIN_3BYTE_VEL;
-
- return CTSTATUS_NEXT_BYTE;
-}
-
-static int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data)
-/* byte 2 */
-{
- unsigned long tmp;
-
- if (data > 0x7f) {
- /* Real-time messages check */
- if (data > 0xf7)
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
-
- /* Invalid data! */
- DPF(2, "Invalid data!\n");
-
- card_mpuin->curstate = STIN_PARSE;
- tmp = ((unsigned long) data) << 8;
- tmp |= card_mpuin->data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->status;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
-
- return -1;
- }
-
- card_mpuin->curstate = STIN_3BYTE;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->status;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
-
- return 0;
-}
-
-static int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- u8 temp = data & 0xf0;
-
- if ((temp == 0xc0) || (temp == 0xd0)) {
- card_mpuin->status = data;
- card_mpuin->curstate = STIN_2BYTE_KEY;
-
- return CTSTATUS_NEXT_BYTE;
- }
-
- if (temp < 0x80)
- return midistatefn[STIN_2BYTE_KEY].Fn(card_mpuin, data);
-
- return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
-}
-
-static int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
-/* byte 1 */
-{
- unsigned long tmp;
-
- if (data > 0x7f) {
- /* Real-time messages check */
- if (data > 0xf7)
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
-
- /* Invalid data! */
- DPF(2, "Invalid data!\n");
-
- card_mpuin->curstate = STIN_PARSE;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->status;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
-
- return -1;
- }
-
- card_mpuin->curstate = STIN_2BYTE;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->status;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
-
- return 0;
-}
-
-static int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- card_mpuin->fstatus = data;
- card_mpuin->curstate = STIN_SYS_COMMON_2_KEY;
-
- return CTSTATUS_NEXT_BYTE;
-}
-
-static int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data)
-/* byte 1 */
-{
- unsigned long tmp;
-
- if (data > 0x7f) {
- /* Real-time messages check */
- if (data > 0xf7)
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
-
- /* Invalid data! */
- DPF(2, "Invalid data!\n");
-
- card_mpuin->curstate = card_mpuin->laststate;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->fstatus;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
-
- return -1;
- }
-
- card_mpuin->curstate = card_mpuin->laststate;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->fstatus;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
-
- return 0;
-}
-
-static int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- card_mpuin->fstatus = data;
- card_mpuin->curstate = STIN_SYS_COMMON_3_KEY;
-
- return CTSTATUS_NEXT_BYTE;
-}
-
-static int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *card_mpuin, u8 data)
-/* byte 1 */
-{
- unsigned long tmp;
-
- if (data > 0x7f) {
- /* Real-time messages check */
- if (data > 0xf7)
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
-
- /* Invalid data! */
- DPF(2, "Invalid data!\n");
-
- card_mpuin->curstate = card_mpuin->laststate;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->fstatus;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
-
- return -1;
- }
-
- card_mpuin->data = data;
- card_mpuin->curstate = STIN_SYS_COMMON_3_VEL;
-
- return CTSTATUS_NEXT_BYTE;
-}
-
-static int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data)
-/* byte 2 */
-{
- unsigned long tmp;
-
- if (data > 0x7f) {
- /* Real-time messages check */
- if (data > 0xf7)
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
-
- /* Invalid data! */
- DPF(2, "Invalid data!\n");
-
- card_mpuin->curstate = card_mpuin->laststate;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->fstatus;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
-
- return -1;
- }
-
- card_mpuin->curstate = card_mpuin->laststate;
- tmp = (unsigned long) data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->data;
- tmp = tmp << 8;
- tmp |= (unsigned long) card_mpuin->fstatus;
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
-
- return 0;
-}
-
-static int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- unsigned long flags;
-
- if ((data > 0x7f) && (data != 0xf7)) {
- /* Real-time messages check */
- if (data > 0xf7)
- return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
-
- /* Invalid Data! */
- DPF(2, "Invalid data!\n");
-
- card_mpuin->curstate = card_mpuin->laststate;
-
- if (card_mpuin->firstmidiq) {
- struct midi_queue *midiq;
-
- midiq = card_mpuin->firstmidiq;
- *midiq->midibyte = data;
- --midiq->sizeLeft;
- ++midiq->midibyte;
-
- spin_lock_irqsave(&card_mpuin->lock, flags);
-
- card_mpuin->firstmidiq = midiq->next;
- if (card_mpuin->firstmidiq == NULL)
- card_mpuin->lastmidiq = NULL;
-
- spin_unlock_irqrestore(&card_mpuin->lock, flags);
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
-
- kfree(midiq);
- }
-
- return -1;
- }
-
- if (card_mpuin->firstmidiq) {
- struct midi_queue *midiq;
-
- midiq = card_mpuin->firstmidiq;
- *midiq->midibyte = data;
- --midiq->sizeLeft;
- ++midiq->midibyte;
- }
-
- if (data == 0xf7) {
- /* End of Sysex buffer */
- /* Send down the buffer */
-
- card_mpuin->curstate = card_mpuin->laststate;
-
- if (card_mpuin->firstmidiq) {
- struct midi_queue *midiq;
-
- midiq = card_mpuin->firstmidiq;
-
- spin_lock_irqsave(&card_mpuin->lock, flags);
-
- card_mpuin->firstmidiq = midiq->next;
- if (card_mpuin->firstmidiq == NULL)
- card_mpuin->lastmidiq = NULL;
-
- spin_unlock_irqrestore(&card_mpuin->lock, flags);
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
-
- kfree(midiq);
- }
-
- return 0;
- }
-
- if (card_mpuin->firstmidiq) {
- struct midi_queue *midiq;
-
- midiq = card_mpuin->firstmidiq;
-
- if (midiq->sizeLeft == 0) {
- /* Special case */
-
- spin_lock_irqsave(&card_mpuin->lock, flags);
-
- card_mpuin->firstmidiq = midiq->next;
- if (card_mpuin->firstmidiq == NULL)
- card_mpuin->lastmidiq = NULL;
-
- spin_unlock_irqrestore(&card_mpuin->lock, flags);
-
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
-
- kfree(midiq);
-
- return CTSTATUS_NEXT_BYTE;
- }
- }
-
- return CTSTATUS_NEXT_BYTE;
-}
-
-static int sblive_miStateSysReal(struct emu10k1_mpuin *card_mpuin, u8 data)
-{
- emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, data, 1);
-
- return CTSTATUS_NEXT_BYTE;
-}
diff --git a/sound/oss/emu10k1/cardmi.h b/sound/oss/emu10k1/cardmi.h
deleted file mode 100644
index d12c24116307..000000000000
--- a/sound/oss/emu10k1/cardmi.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- **********************************************************************
- * sblive_mi.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up
- *
- **********************************************************************
- *
- * 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 _CARDMI_H
-#define _CARDMI_H
-
-#include "icardmid.h"
-#include <linux/interrupt.h>
-
-typedef enum
-{
- STIN_PARSE = 0,
- STIN_3BYTE, /* 0x80, 0x90, 0xA0, 0xB0, 0xE0 */
- STIN_3BYTE_KEY, /* Byte 1 */
- STIN_3BYTE_VEL, /* Byte 1 */
- STIN_2BYTE, /* 0xC0, 0xD0 */
- STIN_2BYTE_KEY, /* Byte 1 */
- STIN_SYS_COMMON_2, /* 0xF1, 0xF3 */
- STIN_SYS_COMMON_2_KEY,
- STIN_SYS_COMMON_3, /* 0xF2 */
- STIN_SYS_COMMON_3_KEY,
- STIN_SYS_COMMON_3_VEL,
- STIN_SYS_EX_NORM, /* 0xF0, Normal mode */
- STIN_SYS_REAL
-} midi_in_state;
-
-
-/* flags for card MIDI in object */
-#define FLAGS_MIDM_STARTED 0x00001000 // Data has started to come in after Midm Start
-#define MIDIIN_MAX_BUFFER_SIZE 200 // Definition for struct emu10k1_mpuin
-
-struct midi_data
-{
- u8 data;
- u32 timein;
-};
-
-struct emu10k1_mpuin
-{
- spinlock_t lock;
- struct midi_queue *firstmidiq;
- struct midi_queue *lastmidiq;
- unsigned qhead, qtail;
- struct midi_data midiq[MIDIIN_MAX_BUFFER_SIZE];
- struct tasklet_struct tasklet;
- struct midi_openinfo openinfo;
-
- /* For MIDI state machine */
- u8 status; /* For MIDI running status */
- u8 fstatus; /* For 0xFn status only */
- midi_in_state curstate;
- midi_in_state laststate;
- u32 timestart;
- u32 timein;
- u8 data;
-};
-
-int emu10k1_mpuin_open(struct emu10k1_card *, struct midi_openinfo *);
-int emu10k1_mpuin_close(struct emu10k1_card *);
-int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *, struct midi_hdr *);
-int emu10k1_mpuin_start(struct emu10k1_card *);
-int emu10k1_mpuin_stop(struct emu10k1_card *);
-int emu10k1_mpuin_reset(struct emu10k1_card *);
-
-int emu10k1_mpuin_irqhandler(struct emu10k1_card *);
-void emu10k1_mpuin_bh(unsigned long);
-
-#endif /* _CARDMI_H */
diff --git a/sound/oss/emu10k1/cardmo.c b/sound/oss/emu10k1/cardmo.c
deleted file mode 100644
index a8cc75db3e45..000000000000
--- a/sound/oss/emu10k1/cardmo.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- **********************************************************************
- * cardmo.c - MIDI UART output HAL for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up
- *
- **********************************************************************
- *
- * 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/slab.h>
-
-#include "hwaccess.h"
-#include "8010.h"
-#include "cardmo.h"
-#include "irqmgr.h"
-
-/* Installs the IRQ handler for the MPU out port *
- * and initialize parameters */
-
-int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
-{
- struct emu10k1_mpuout *card_mpuout = card->mpuout;
-
- DPF(2, "emu10k1_mpuout_open()\n");
-
- if (!(card_mpuout->status & FLAGS_AVAILABLE))
- return -1;
-
- /* Copy open info and mark channel as in use */
- card_mpuout->intr = 0;
- card_mpuout->openinfo = *openinfo;
- card_mpuout->status &= ~FLAGS_AVAILABLE;
- card_mpuout->laststatus = 0x80;
- card_mpuout->firstmidiq = NULL;
- card_mpuout->lastmidiq = NULL;
-
- emu10k1_mpu_reset(card);
- emu10k1_mpu_acquire(card);
-
- return 0;
-}
-
-int emu10k1_mpuout_close(struct emu10k1_card *card)
-{
- struct emu10k1_mpuout *card_mpuout = card->mpuout;
- struct midi_queue *midiq;
- struct midi_hdr *midihdr;
- unsigned long flags;
-
- DPF(2, "emu10k1_mpuout_close()\n");
-
- emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
-
- spin_lock_irqsave(&card_mpuout->lock, flags);
-
- while (card_mpuout->firstmidiq != NULL) {
- midiq = card_mpuout->firstmidiq;
- midihdr = (struct midi_hdr *) midiq->refdata;
-
- card_mpuout->firstmidiq = midiq->next;
-
- kfree(midihdr->data);
- kfree(midihdr);
- kfree(midiq);
- }
-
- card_mpuout->lastmidiq = NULL;
-
- emu10k1_mpu_release(card);
-
- card_mpuout->status |= FLAGS_AVAILABLE;
-
- spin_unlock_irqrestore(&card_mpuout->lock, flags);
-
- return 0;
-}
-
-/* If there isn't enough buffer space, reject Midi Buffer. *
-* Otherwise, disable TX, create object to hold Midi *
-* uffer, update buffer flags and other parameters *
-* before enabling TX again. */
-
-int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr)
-{
- struct emu10k1_mpuout *card_mpuout = card->mpuout;
- struct midi_queue *midiq;
- unsigned long flags;
-
- DPF(2, "emu10k1_mpuout_add_buffer()\n");
-
- if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
- return 0;
-
- midihdr->flags |= MIDIBUF_INQUEUE;
- midihdr->flags &= ~MIDIBUF_DONE;
-
- if ((midiq = kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
- /* Message lost */
- return -1;
- }
-
- midiq->next = NULL;
- midiq->qtype = 1;
- midiq->length = midihdr->bufferlength;
- midiq->sizeLeft = midihdr->bufferlength;
- midiq->midibyte = midihdr->data;
-
- midiq->refdata = (unsigned long) midihdr;
-
- spin_lock_irqsave(&card_mpuout->lock, flags);
-
- if (card_mpuout->firstmidiq == NULL) {
- card_mpuout->firstmidiq = midiq;
- card_mpuout->lastmidiq = midiq;
- } else {
- (card_mpuout->lastmidiq)->next = midiq;
- card_mpuout->lastmidiq = midiq;
- }
-
- card_mpuout->intr = 0;
-
- emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
-
- spin_unlock_irqrestore(&card_mpuout->lock, flags);
-
- return 0;
-}
-
-void emu10k1_mpuout_bh(unsigned long refdata)
-{
- struct emu10k1_card *card = (struct emu10k1_card *) refdata;
- struct emu10k1_mpuout *card_mpuout = card->mpuout;
- int cByteSent = 0;
- struct midi_queue *midiq;
- struct midi_queue *doneq = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&card_mpuout->lock, flags);
-
- while (card_mpuout->firstmidiq != NULL) {
- midiq = card_mpuout->firstmidiq;
-
- while (cByteSent < 4 && midiq->sizeLeft) {
- if (emu10k1_mpu_write_data(card, *midiq->midibyte) < 0) {
- DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
- } else {
- ++cByteSent;
- --midiq->sizeLeft;
- ++midiq->midibyte;
- }
- }
-
- if (midiq->sizeLeft == 0) {
- if (doneq == NULL)
- doneq = midiq;
- card_mpuout->firstmidiq = midiq->next;
- } else
- break;
- }
-
- if (card_mpuout->firstmidiq == NULL)
- card_mpuout->lastmidiq = NULL;
-
- if (doneq != NULL) {
- while (doneq != card_mpuout->firstmidiq) {
- unsigned long callback_msg[3];
-
- midiq = doneq;
- doneq = midiq->next;
-
- if (midiq->qtype) {
- callback_msg[0] = 0;
- callback_msg[1] = midiq->length;
- callback_msg[2] = midiq->refdata;
-
- emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg);
- } else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F)
- card_mpuout->laststatus = (u8) midiq->refdata;
-
- kfree(midiq);
- }
- }
-
- if ((card_mpuout->firstmidiq != NULL) || cByteSent) {
- card_mpuout->intr = 0;
- emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
- }
-
- spin_unlock_irqrestore(&card_mpuout->lock, flags);
-
- return;
-}
-
-int emu10k1_mpuout_irqhandler(struct emu10k1_card *card)
-{
- struct emu10k1_mpuout *card_mpuout = card->mpuout;
-
- DPF(4, "emu10k1_mpuout_irqhandler\n");
-
- card_mpuout->intr = 1;
- emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
-
- tasklet_hi_schedule(&card_mpuout->tasklet);
-
- return 0;
-}
diff --git a/sound/oss/emu10k1/cardmo.h b/sound/oss/emu10k1/cardmo.h
deleted file mode 100644
index 7026eb3a85af..000000000000
--- a/sound/oss/emu10k1/cardmo.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- **********************************************************************
- * cardmo.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up
- *
- **********************************************************************
- *
- * 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 _CARDMO_H
-#define _CARDMO_H
-
-#include "icardmid.h"
-#include <linux/interrupt.h>
-
-#define CARDMIDIOUT_STATE_DEFAULT 0x00000000
-#define CARDMIDIOUT_STATE_SUSPEND 0x00000001
-
-struct emu10k1_mpuout
-{
- u32 status;
- u32 state;
- volatile int intr;
- struct midi_queue *firstmidiq;
- struct midi_queue *lastmidiq;
- u8 laststatus;
- struct tasklet_struct tasklet;
- spinlock_t lock;
- struct midi_openinfo openinfo;
-};
-
-int emu10k1_mpuout_open(struct emu10k1_card *, struct midi_openinfo *);
-int emu10k1_mpuout_close(struct emu10k1_card *);
-int emu10k1_mpuout_add_buffer(struct emu10k1_card *, struct midi_hdr *);
-
-int emu10k1_mpuout_irqhandler(struct emu10k1_card *);
-void emu10k1_mpuout_bh(unsigned long);
-
-#endif /* _CARDMO_H */
diff --git a/sound/oss/emu10k1/cardwi.c b/sound/oss/emu10k1/cardwi.c
deleted file mode 100644
index 060d1be94d33..000000000000
--- a/sound/oss/emu10k1/cardwi.c
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- **********************************************************************
- * cardwi.c - PCM input HAL for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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/poll.h>
-#include "hwaccess.h"
-#include "timer.h"
-#include "recmgr.h"
-#include "audio.h"
-#include "cardwi.h"
-
-/**
- * query_format - returns a valid sound format
- *
- * This function will return a valid sound format as close
- * to the requested one as possible.
- */
-static void query_format(int recsrc, struct wave_format *wave_fmt)
-{
-
- switch (recsrc) {
- case WAVERECORD_AC97:
-
- if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
- wave_fmt->channels = 2;
-
- if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2)
- wave_fmt->samplingrate = 0xBB80;
- else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2)
- wave_fmt->samplingrate = 0xAC44;
- else if (wave_fmt->samplingrate >= (0x7D00 + 0x5DC0) / 2)
- wave_fmt->samplingrate = 0x7D00;
- else if (wave_fmt->samplingrate >= (0x5DC0 + 0x5622) / 2)
- wave_fmt->samplingrate = 0x5DC0;
- else if (wave_fmt->samplingrate >= (0x5622 + 0x3E80) / 2)
- wave_fmt->samplingrate = 0x5622;
- else if (wave_fmt->samplingrate >= (0x3E80 + 0x2B11) / 2)
- wave_fmt->samplingrate = 0x3E80;
- else if (wave_fmt->samplingrate >= (0x2B11 + 0x1F40) / 2)
- wave_fmt->samplingrate = 0x2B11;
- else
- wave_fmt->samplingrate = 0x1F40;
-
- switch (wave_fmt->id) {
- case AFMT_S16_LE:
- wave_fmt->bitsperchannel = 16;
- break;
- case AFMT_U8:
- wave_fmt->bitsperchannel = 8;
- break;
- default:
- wave_fmt->id = AFMT_S16_LE;
- wave_fmt->bitsperchannel = 16;
- break;
- }
-
- break;
-
- /* these can't be changed from the original values */
- case WAVERECORD_MIC:
- case WAVERECORD_FX:
- break;
-
- default:
- BUG();
- break;
- }
-
- wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
- wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
- wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
- wave_fmt->bytespervoicesample = wave_fmt->bytespersample;
-}
-
-static int alloc_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
-{
- buffer->addr = pci_alloc_consistent(card->pci_dev, buffer->size * buffer->cov,
- &buffer->dma_handle);
- if (buffer->addr == NULL)
- return -1;
-
- return 0;
-}
-
-static void free_buffer(struct emu10k1_card *card, struct wavein_buffer *buffer)
-{
- if (buffer->addr != NULL)
- pci_free_consistent(card->pci_dev, buffer->size * buffer->cov,
- buffer->addr, buffer->dma_handle);
-}
-
-int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct wiinst *wiinst = wave_dev->wiinst;
- struct wiinst **wiinst_tmp = NULL;
- u16 delay;
- unsigned long flags;
-
- DPF(2, "emu10k1_wavein_open()\n");
-
- switch (wiinst->recsrc) {
- case WAVERECORD_AC97:
- wiinst_tmp = &card->wavein.ac97;
- break;
- case WAVERECORD_MIC:
- wiinst_tmp = &card->wavein.mic;
- break;
- case WAVERECORD_FX:
- wiinst_tmp = &card->wavein.fx;
- break;
- default:
- BUG();
- break;
- }
-
- spin_lock_irqsave(&card->lock, flags);
- if (*wiinst_tmp != NULL) {
- spin_unlock_irqrestore(&card->lock, flags);
- return -1;
- }
-
- *wiinst_tmp = wiinst;
- spin_unlock_irqrestore(&card->lock, flags);
-
- /* handle 8 bit recording */
- if (wiinst->format.bytesperchannel == 1) {
- if (wiinst->buffer.size > 0x8000) {
- wiinst->buffer.size = 0x8000;
- wiinst->buffer.sizeregval = 0x1f;
- } else
- wiinst->buffer.sizeregval += 4;
-
- wiinst->buffer.cov = 2;
- } else
- wiinst->buffer.cov = 1;
-
- if (alloc_buffer(card, &wiinst->buffer) < 0) {
- ERROR();
- return -1;
- }
-
- emu10k1_set_record_src(card, wiinst);
-
- emu10k1_reset_record(card, &wiinst->buffer);
-
- wiinst->buffer.hw_pos = 0;
- wiinst->buffer.pos = 0;
- wiinst->buffer.bytestocopy = 0;
-
- delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
-
- emu10k1_timer_install(card, &wiinst->timer, delay / 2);
-
- wiinst->state = WAVE_STATE_OPEN;
-
- return 0;
-}
-
-void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct wiinst *wiinst = wave_dev->wiinst;
- unsigned long flags;
-
- DPF(2, "emu10k1_wavein_close()\n");
-
- emu10k1_wavein_stop(wave_dev);
-
- emu10k1_timer_uninstall(card, &wiinst->timer);
-
- free_buffer(card, &wiinst->buffer);
-
- spin_lock_irqsave(&card->lock, flags);
- switch (wave_dev->wiinst->recsrc) {
- case WAVERECORD_AC97:
- card->wavein.ac97 = NULL;
- break;
- case WAVERECORD_MIC:
- card->wavein.mic = NULL;
- break;
- case WAVERECORD_FX:
- card->wavein.fx = NULL;
- break;
- default:
- BUG();
- break;
- }
- spin_unlock_irqrestore(&card->lock, flags);
-
- wiinst->state = WAVE_STATE_CLOSED;
-}
-
-void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct wiinst *wiinst = wave_dev->wiinst;
-
- DPF(2, "emu10k1_wavein_start()\n");
-
- emu10k1_start_record(card, &wiinst->buffer);
- emu10k1_timer_enable(wave_dev->card, &wiinst->timer);
-
- wiinst->state |= WAVE_STATE_STARTED;
-}
-
-void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct wiinst *wiinst = wave_dev->wiinst;
-
- DPF(2, "emu10k1_wavein_stop()\n");
-
- if (!(wiinst->state & WAVE_STATE_STARTED))
- return;
-
- emu10k1_timer_disable(card, &wiinst->timer);
- emu10k1_stop_record(card, &wiinst->buffer);
-
- wiinst->state &= ~WAVE_STATE_STARTED;
-}
-
-int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct wiinst *wiinst = wave_dev->wiinst;
- u16 delay;
-
- DPF(2, "emu10k1_wavein_setformat()\n");
-
- if (wiinst->state & WAVE_STATE_STARTED)
- return -1;
-
- query_format(wiinst->recsrc, format);
-
- if ((wiinst->format.samplingrate != format->samplingrate)
- || (wiinst->format.bitsperchannel != format->bitsperchannel)
- || (wiinst->format.channels != format->channels)) {
-
- wiinst->format = *format;
-
- if (wiinst->state == WAVE_STATE_CLOSED)
- return 0;
-
- wiinst->buffer.size *= wiinst->buffer.cov;
-
- if (wiinst->format.bytesperchannel == 1) {
- wiinst->buffer.cov = 2;
- wiinst->buffer.size /= wiinst->buffer.cov;
- } else
- wiinst->buffer.cov = 1;
-
- emu10k1_timer_uninstall(card, &wiinst->timer);
-
- delay = (48000 * wiinst->buffer.fragment_size) / wiinst->format.bytespersec;
-
- emu10k1_timer_install(card, &wiinst->timer, delay / 2);
- }
-
- return 0;
-}
-
-void emu10k1_wavein_getxfersize(struct wiinst *wiinst, u32 * size)
-{
- struct wavein_buffer *buffer = &wiinst->buffer;
-
- *size = buffer->bytestocopy;
-
- if (wiinst->mmapped)
- return;
-
- if (*size > buffer->size) {
- *size = buffer->size;
- buffer->pos = buffer->hw_pos;
- buffer->bytestocopy = buffer->size;
- DPF(1, "buffer overrun\n");
- }
-}
-
-static int copy_block(u8 __user *dst, u8 * src, u32 str, u32 len, u8 cov)
-{
- if (cov == 1) {
- if (__copy_to_user(dst, src + str, len))
- return -EFAULT;
- } else {
- u8 byte;
- u32 i;
-
- src += 1 + 2 * str;
-
- for (i = 0; i < len; i++) {
- byte = src[2 * i] ^ 0x80;
- if (__copy_to_user(dst + i, &byte, 1))
- return -EFAULT;
- }
- }
-
- return 0;
-}
-
-int emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 __user *data, u32 * size)
-{
- struct wavein_buffer *buffer = &wiinst->buffer;
- u32 sizetocopy, sizetocopy_now, start;
- unsigned long flags;
- int ret;
-
- sizetocopy = min_t(u32, buffer->size, *size);
- *size = sizetocopy;
-
- if (!sizetocopy)
- return 0;
-
- spin_lock_irqsave(&wiinst->lock, flags);
- start = buffer->pos;
- buffer->pos += sizetocopy;
- buffer->pos %= buffer->size;
- buffer->bytestocopy -= sizetocopy;
- sizetocopy_now = buffer->size - start;
-
- spin_unlock_irqrestore(&wiinst->lock, flags);
-
- if (sizetocopy > sizetocopy_now) {
- sizetocopy -= sizetocopy_now;
-
- ret = copy_block(data, buffer->addr, start, sizetocopy_now,
- buffer->cov);
- if (ret == 0)
- ret = copy_block(data + sizetocopy_now, buffer->addr, 0,
- sizetocopy, buffer->cov);
- } else {
- ret = copy_block(data, buffer->addr, start, sizetocopy,
- buffer->cov);
- }
-
- return ret;
-}
-
-void emu10k1_wavein_update(struct emu10k1_card *card, struct wiinst *wiinst)
-{
- u32 hw_pos;
- u32 diff;
-
- /* There is no actual start yet */
- if (!(wiinst->state & WAVE_STATE_STARTED)) {
- hw_pos = wiinst->buffer.hw_pos;
- } else {
- /* hw_pos in byte units */
- hw_pos = sblive_readptr(card, wiinst->buffer.idxreg, 0) / wiinst->buffer.cov;
- }
-
- diff = (wiinst->buffer.size + hw_pos - wiinst->buffer.hw_pos) % wiinst->buffer.size;
- wiinst->total_recorded += diff;
- wiinst->buffer.bytestocopy += diff;
-
- wiinst->buffer.hw_pos = hw_pos;
-}
diff --git a/sound/oss/emu10k1/cardwi.h b/sound/oss/emu10k1/cardwi.h
deleted file mode 100644
index e82029b46ad1..000000000000
--- a/sound/oss/emu10k1/cardwi.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- **********************************************************************
- * cardwi.h -- header file for card wave input functions
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _CARDWI_H
-#define _CARDWI_H
-
-#include "icardwav.h"
-#include "audio.h"
-#include "timer.h"
-
-struct wavein_buffer {
- u16 ossfragshift;
- u32 fragment_size;
- u32 numfrags;
- u32 hw_pos; /* hardware cursor position */
- u32 pos; /* software cursor position */
- u32 bytestocopy; /* bytes of recorded data available */
- u32 size;
- u32 pages;
- u32 sizereg;
- u32 sizeregval;
- u32 addrreg;
- u32 idxreg;
- u32 adcctl;
- void *addr;
- u8 cov;
- dma_addr_t dma_handle;
-};
-
-struct wiinst
-{
- u8 state;
- struct emu_timer timer;
- struct wave_format format;
- struct wavein_buffer buffer;
- wait_queue_head_t wait_queue;
- u8 mmapped;
- u32 total_recorded; /* total bytes read() from device */
- u32 blocks;
- spinlock_t lock;
- u8 recsrc;
- u16 fxwc;
-};
-
-#define WAVEIN_MAXBUFSIZE 65536
-#define WAVEIN_MINBUFSIZE 368
-
-#define WAVEIN_DEFAULTFRAGLEN 100
-#define WAVEIN_DEFAULTBUFLEN 1000
-
-#define WAVEIN_MINFRAGSHIFT 8
-#define WAVEIN_MINFRAGS 2
-
-int emu10k1_wavein_open(struct emu10k1_wavedevice *);
-void emu10k1_wavein_close(struct emu10k1_wavedevice *);
-void emu10k1_wavein_start(struct emu10k1_wavedevice *);
-void emu10k1_wavein_stop(struct emu10k1_wavedevice *);
-void emu10k1_wavein_getxfersize(struct wiinst *, u32 *);
-int emu10k1_wavein_xferdata(struct wiinst *, u8 __user *, u32 *);
-int emu10k1_wavein_setformat(struct emu10k1_wavedevice *, struct wave_format *);
-void emu10k1_wavein_update(struct emu10k1_card *, struct wiinst *);
-
-
-#endif /* _CARDWI_H */
diff --git a/sound/oss/emu10k1/cardwo.c b/sound/oss/emu10k1/cardwo.c
deleted file mode 100644
index 54daca4f57b4..000000000000
--- a/sound/oss/emu10k1/cardwo.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- **********************************************************************
- * cardwo.c - PCM output HAL for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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/poll.h>
-#include "hwaccess.h"
-#include "8010.h"
-#include "voicemgr.h"
-#include "cardwo.h"
-#include "audio.h"
-
-static u32 samplerate_to_linearpitch(u32 samplingrate)
-{
- samplingrate = (samplingrate << 8) / 375;
- return (samplingrate >> 1) + (samplingrate & 1);
-}
-
-static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format *wave_fmt)
-{
- int i, j, do_passthrough = 0, is_ac3 = 0;
- struct emu10k1_card *card = wave_dev->card;
- struct woinst *woinst = wave_dev->woinst;
-
- if ((wave_fmt->channels > 2) && (wave_fmt->id != AFMT_S16_LE) && (wave_fmt->id != AFMT_U8))
- wave_fmt->channels = 2;
-
- if ((wave_fmt->channels < 1) || (wave_fmt->channels > WAVEOUT_MAXVOICES))
- wave_fmt->channels = 2;
-
- if (wave_fmt->channels == 2)
- woinst->num_voices = 1;
- else
- woinst->num_voices = wave_fmt->channels;
-
- if (wave_fmt->samplingrate >= 0x2ee00)
- wave_fmt->samplingrate = 0x2ee00;
-
- wave_fmt->passthrough = 0;
- do_passthrough = is_ac3 = 0;
-
- if (card->pt.selected)
- do_passthrough = 1;
-
- switch (wave_fmt->id) {
- case AFMT_S16_LE:
- wave_fmt->bitsperchannel = 16;
- break;
- case AFMT_U8:
- wave_fmt->bitsperchannel = 8;
- break;
- case AFMT_AC3:
- do_passthrough = 1;
- is_ac3 = 1;
- break;
- default:
- wave_fmt->id = AFMT_S16_LE;
- wave_fmt->bitsperchannel = 16;
- break;
- }
- if (do_passthrough) {
- /* currently only one waveout instance may use pass-through */
- if (woinst->state != WAVE_STATE_CLOSED ||
- card->pt.state != PT_STATE_INACTIVE ||
- (wave_fmt->samplingrate != 48000 && !is_ac3)) {
- DPF(2, "unable to set pass-through mode\n");
- } else if (USE_PT_METHOD1) {
- i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name);
- j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name);
- if (i < 0 || j < 0)
- DPF(2, "unable to set pass-through mode\n");
- else {
- wave_fmt->samplingrate = 48000;
- wave_fmt->channels = 2;
- card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
- card->pt.pos_gpr_name);
- wave_fmt->passthrough = 1;
- card->pt.intr_gpr = i;
- card->pt.enable_gpr = j;
- card->pt.state = PT_STATE_INACTIVE;
-
- DPD(2, "is_ac3 is %d\n", is_ac3);
- card->pt.ac3data = is_ac3;
- wave_fmt->bitsperchannel = 16;
- }
- }else{
- DPF(2, "Using Passthrough Method 2\n");
- card->pt.enable_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
- card->pt.enable_gpr_name);
- wave_fmt->passthrough = 2;
- wave_fmt->bitsperchannel = 16;
- }
- }
-
- wave_fmt->bytesperchannel = wave_fmt->bitsperchannel >> 3;
- wave_fmt->bytespersample = wave_fmt->channels * wave_fmt->bytesperchannel;
- wave_fmt->bytespersec = wave_fmt->bytespersample * wave_fmt->samplingrate;
-
- if (wave_fmt->channels == 2)
- wave_fmt->bytespervoicesample = wave_fmt->channels * wave_fmt->bytesperchannel;
- else
- wave_fmt->bytespervoicesample = wave_fmt->bytesperchannel;
-}
-
-static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned int voicenum)
-{
- struct emu_voice *voice = &woinst->voice[voicenum];
-
- /* Allocate voices here, if no voices available, return error. */
-
- voice->usage = VOICE_USAGE_PLAYBACK;
-
- voice->flags = 0;
-
- if (woinst->format.channels == 2)
- voice->flags |= VOICE_FLAGS_STEREO;
-
- if (woinst->format.bitsperchannel == 16)
- voice->flags |= VOICE_FLAGS_16BIT;
-
- if (emu10k1_voice_alloc(card, voice) < 0) {
- voice->usage = VOICE_USAGE_FREE;
- return -1;
- }
-
- /* Calculate pitch */
- voice->initial_pitch = (u16) (srToPitch(woinst->format.samplingrate) >> 8);
- voice->pitch_target = samplerate_to_linearpitch(woinst->format.samplingrate);
-
- DPD(2, "Initial pitch --> %#x\n", voice->initial_pitch);
-
- voice->startloop = (voice->mem.emupageindex << 12) /
- woinst->format.bytespervoicesample;
- voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample;
- voice->start = voice->startloop;
-
-
- voice->params[0].volume_target = 0xffff;
- voice->params[0].initial_fc = 0xff;
- voice->params[0].initial_attn = 0x00;
- voice->params[0].byampl_env_sustain = 0x7f;
- voice->params[0].byampl_env_decay = 0x7f;
-
-
- if (voice->flags & VOICE_FLAGS_STEREO) {
- if (woinst->format.passthrough == 2) {
- voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PT];
- voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PT];
- voice->params[0].send_dcba = 0xff;
- voice->params[1].send_dcba = 0xff00;
- voice->params[0].send_hgfe = voice->params[1].send_hgfe=0;
- } else {
- voice->params[0].send_dcba = card->waveout.send_dcba[SEND_LEFT];
- voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_LEFT];
- voice->params[1].send_dcba = card->waveout.send_dcba[SEND_RIGHT];
- voice->params[1].send_hgfe = card->waveout.send_hgfe[SEND_RIGHT];
-
- if (woinst->device) {
- // /dev/dps1
- voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM1];
- voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
- } else {
- voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM];
- voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
- }
- }
-
- voice->params[1].volume_target = 0xffff;
- voice->params[1].initial_fc = 0xff;
- voice->params[1].initial_attn = 0x00;
- voice->params[1].byampl_env_sustain = 0x7f;
- voice->params[1].byampl_env_decay = 0x7f;
- } else {
- if (woinst->num_voices > 1) {
- // Multichannel pcm
- voice->params[0].send_dcba=0xff;
- voice->params[0].send_hgfe=0;
- if (card->is_audigy) {
- voice->params[0].send_routing = 0x3f3f3f00 + card->mchannel_fx + voicenum;
- voice->params[0].send_routing2 = 0x3f3f3f3f;
- } else {
- voice->params[0].send_routing = 0xfff0 + card->mchannel_fx + voicenum;
- }
-
- } else {
- voice->params[0].send_dcba = card->waveout.send_dcba[SEND_MONO];
- voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_MONO];
-
- if (woinst->device) {
- voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM1];
- voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
- } else {
- voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM];
- voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
- }
- }
- }
-
- DPD(2, "voice: startloop=%#x, endloop=%#x\n", voice->startloop, voice->endloop);
-
- emu10k1_voice_playback_setup(voice);
-
- return 0;
-}
-
-int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct woinst *woinst = wave_dev->woinst;
- struct waveout_buffer *buffer = &woinst->buffer;
- unsigned int voicenum;
- u16 delay;
-
- DPF(2, "emu10k1_waveout_open()\n");
-
- for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
- if (emu10k1_voice_alloc_buffer(card, &woinst->voice[voicenum].mem, woinst->buffer.pages) < 0) {
- ERROR();
- emu10k1_waveout_close(wave_dev);
- return -1;
- }
-
- if (get_voice(card, woinst, voicenum) < 0) {
- ERROR();
- emu10k1_waveout_close(wave_dev);
- return -1;
- }
- }
-
- buffer->fill_silence = 0;
- buffer->silence_bytes = 0;
- buffer->silence_pos = 0;
- buffer->hw_pos = 0;
- buffer->free_bytes = woinst->buffer.size;
-
- delay = (48000 * woinst->buffer.fragment_size) /
- (woinst->format.samplingrate * woinst->format.bytespervoicesample);
-
- emu10k1_timer_install(card, &woinst->timer, delay);
-
- woinst->state = WAVE_STATE_OPEN;
-
- return 0;
-}
-
-void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct woinst *woinst = wave_dev->woinst;
- unsigned int voicenum;
-
- DPF(2, "emu10k1_waveout_close()\n");
-
- emu10k1_waveout_stop(wave_dev);
-
- emu10k1_timer_uninstall(card, &woinst->timer);
-
- for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
- emu10k1_voice_free(&woinst->voice[voicenum]);
- emu10k1_voice_free_buffer(card, &woinst->voice[voicenum].mem);
- }
-
- woinst->state = WAVE_STATE_CLOSED;
-}
-
-void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct woinst *woinst = wave_dev->woinst;
- struct pt_data *pt = &card->pt;
-
- DPF(2, "emu10k1_waveout_start()\n");
-
- if (woinst->format.passthrough == 2) {
- emu10k1_pt_setup(wave_dev);
- sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 1);
- pt->state = PT_STATE_PLAYING;
- }
-
- /* Actual start */
- emu10k1_voices_start(woinst->voice, woinst->num_voices, woinst->total_played);
-
- emu10k1_timer_enable(card, &woinst->timer);
-
- woinst->state |= WAVE_STATE_STARTED;
-}
-
-int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev, struct wave_format *format)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct woinst *woinst = wave_dev->woinst;
- unsigned int voicenum;
- u16 delay;
-
- DPF(2, "emu10k1_waveout_setformat()\n");
-
- if (woinst->state & WAVE_STATE_STARTED)
- return -1;
-
- query_format(wave_dev, format);
-
- if (woinst->format.samplingrate != format->samplingrate ||
- woinst->format.channels != format->channels ||
- woinst->format.bitsperchannel != format->bitsperchannel) {
-
- woinst->format = *format;
-
- if (woinst->state == WAVE_STATE_CLOSED)
- return 0;
-
- emu10k1_timer_uninstall(card, &woinst->timer);
-
- for (voicenum = 0; voicenum < woinst->num_voices; voicenum++) {
- emu10k1_voice_free(&woinst->voice[voicenum]);
-
- if (get_voice(card, woinst, voicenum) < 0) {
- ERROR();
- emu10k1_waveout_close(wave_dev);
- return -1;
- }
- }
-
- delay = (48000 * woinst->buffer.fragment_size) /
- (woinst->format.samplingrate * woinst->format.bytespervoicesample);
-
- emu10k1_timer_install(card, &woinst->timer, delay);
- }
-
- return 0;
-}
-
-void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev)
-{
- struct emu10k1_card *card = wave_dev->card;
- struct woinst *woinst = wave_dev->woinst;
-
- DPF(2, "emu10k1_waveout_stop()\n");
-
- if (!(woinst->state & WAVE_STATE_STARTED))
- return;
-
- emu10k1_timer_disable(card, &woinst->timer);
-
- /* Stop actual voices */
- emu10k1_voices_stop(woinst->voice, woinst->num_voices);
-
- emu10k1_waveout_update(woinst);
-
- woinst->state &= ~WAVE_STATE_STARTED;
-}
-
-/**
- * emu10k1_waveout_getxfersize -
- *
- * gives the total free bytes on the voice buffer, including silence bytes
- * (basically: total_free_bytes = free_bytes + silence_bytes).
- *
- */
-void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 *total_free_bytes)
-{
- struct waveout_buffer *buffer = &woinst->buffer;
- int pending_bytes;
-
- if (woinst->mmapped) {
- *total_free_bytes = buffer->free_bytes;
- return;
- }
-
- pending_bytes = buffer->size - buffer->free_bytes;
-
- buffer->fill_silence = (pending_bytes < (signed) buffer->fragment_size * 2) ? 1 : 0;
-
- if (pending_bytes > (signed) buffer->silence_bytes) {
- *total_free_bytes = (buffer->free_bytes + buffer->silence_bytes);
- } else {
- *total_free_bytes = buffer->size;
- buffer->silence_bytes = pending_bytes;
- if (pending_bytes < 0) {
- buffer->silence_pos = buffer->hw_pos;
- buffer->silence_bytes = 0;
- buffer->free_bytes = buffer->size;
- DPF(1, "buffer underrun\n");
- }
- }
-}
-
-/**
- * copy_block -
- *
- * copies a block of pcm data to a voice buffer.
- * Notice that the voice buffer is actually a set of disjointed memory pages.
- *
- */
-static void copy_block(void **dst, u32 str, u8 __user *src, u32 len)
-{
- unsigned int pg;
- unsigned int pgoff;
- unsigned int k;
-
- pg = str / PAGE_SIZE;
- pgoff = str % PAGE_SIZE;
-
- if (len > PAGE_SIZE - pgoff) {
- k = PAGE_SIZE - pgoff;
- if (__copy_from_user((u8 *)dst[pg] + pgoff, src, k))
- return;
- len -= k;
- while (len > PAGE_SIZE) {
- if (__copy_from_user(dst[++pg], src + k, PAGE_SIZE))
- return;
- k += PAGE_SIZE;
- len -= PAGE_SIZE;
- }
- if (__copy_from_user(dst[++pg], src + k, len))
- return;
-
- } else
- __copy_from_user((u8 *)dst[pg] + pgoff, src, len);
-}
-
-/**
- * copy_ilv_block -
- *
- * copies a block of pcm data containing n interleaved channels to n mono voice buffers.
- * Notice that the voice buffer is actually a set of disjointed memory pages.
- *
- */
-static void copy_ilv_block(struct woinst *woinst, u32 str, u8 __user *src, u32 len)
-{
- unsigned int pg;
- unsigned int pgoff;
- unsigned int voice_num;
- struct emu_voice *voice = woinst->voice;
-
- pg = str / PAGE_SIZE;
- pgoff = str % PAGE_SIZE;
-
- while (len) {
- for (voice_num = 0; voice_num < woinst->num_voices; voice_num++) {
- if (__copy_from_user((u8 *)(voice[voice_num].mem.addr[pg]) + pgoff, src, woinst->format.bytespervoicesample))
- return;
- src += woinst->format.bytespervoicesample;
- }
-
- len -= woinst->format.bytespervoicesample;
-
- pgoff += woinst->format.bytespervoicesample;
- if (pgoff >= PAGE_SIZE) {
- pgoff = 0;
- pg++;
- }
- }
-}
-
-/**
- * fill_block -
- *
- * fills a set voice buffers with a block of a given sample.
- *
- */
-static void fill_block(struct woinst *woinst, u32 str, u8 data, u32 len)
-{
- unsigned int pg;
- unsigned int pgoff;
- unsigned int voice_num;
- struct emu_voice *voice = woinst->voice;
- unsigned int k;
-
- pg = str / PAGE_SIZE;
- pgoff = str % PAGE_SIZE;
-
- if (len > PAGE_SIZE - pgoff) {
- k = PAGE_SIZE - pgoff;
- for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
- memset((u8 *)voice[voice_num].mem.addr[pg] + pgoff, data, k);
- len -= k;
- while (len > PAGE_SIZE) {
- pg++;
- for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
- memset(voice[voice_num].mem.addr[pg], data, PAGE_SIZE);
-
- len -= PAGE_SIZE;
- }
- pg++;
- for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
- memset(voice[voice_num].mem.addr[pg], data, len);
-
- } else {
- for (voice_num = 0; voice_num < woinst->num_voices; voice_num++)
- memset((u8 *)voice[voice_num].mem.addr[pg] + pgoff, data, len);
- }
-}
-
-/**
- * emu10k1_waveout_xferdata -
- *
- * copies pcm data to the voice buffer. Silence samples
- * previously added to the buffer are overwritten.
- *
- */
-void emu10k1_waveout_xferdata(struct woinst *woinst, u8 __user *data, u32 *size)
-{
- struct waveout_buffer *buffer = &woinst->buffer;
- struct voice_mem *mem = &woinst->voice[0].mem;
- u32 sizetocopy, sizetocopy_now, start;
- unsigned long flags;
-
- sizetocopy = min_t(u32, buffer->size, *size);
- *size = sizetocopy;
-
- if (!sizetocopy)
- return;
-
- spin_lock_irqsave(&woinst->lock, flags);
- start = (buffer->size + buffer->silence_pos - buffer->silence_bytes) % buffer->size;
-
- if (sizetocopy > buffer->silence_bytes) {
- buffer->silence_pos += sizetocopy - buffer->silence_bytes;
- buffer->free_bytes -= sizetocopy - buffer->silence_bytes;
- buffer->silence_bytes = 0;
- } else
- buffer->silence_bytes -= sizetocopy;
-
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- sizetocopy_now = buffer->size - start;
- if (sizetocopy > sizetocopy_now) {
- sizetocopy -= sizetocopy_now;
- if (woinst->num_voices > 1) {
- copy_ilv_block(woinst, start, data, sizetocopy_now);
- copy_ilv_block(woinst, 0, data + sizetocopy_now * woinst->num_voices, sizetocopy);
- } else {
- copy_block(mem->addr, start, data, sizetocopy_now);
- copy_block(mem->addr, 0, data + sizetocopy_now, sizetocopy);
- }
- } else {
- if (woinst->num_voices > 1)
- copy_ilv_block(woinst, start, data, sizetocopy);
- else
- copy_block(mem->addr, start, data, sizetocopy);
- }
-}
-
-/**
- * emu10k1_waveout_fillsilence -
- *
- * adds samples of silence to the voice buffer so that we
- * don't loop over stale pcm data.
- *
- */
-void emu10k1_waveout_fillsilence(struct woinst *woinst)
-{
- struct waveout_buffer *buffer = &woinst->buffer;
- u32 sizetocopy, sizetocopy_now, start;
- u8 filldata;
- unsigned long flags;
-
- sizetocopy = buffer->fragment_size;
-
- if (woinst->format.bitsperchannel == 16)
- filldata = 0x00;
- else
- filldata = 0x80;
-
- spin_lock_irqsave(&woinst->lock, flags);
- buffer->silence_bytes += sizetocopy;
- buffer->free_bytes -= sizetocopy;
- buffer->silence_pos %= buffer->size;
- start = buffer->silence_pos;
- buffer->silence_pos += sizetocopy;
- spin_unlock_irqrestore(&woinst->lock, flags);
-
- sizetocopy_now = buffer->size - start;
-
- if (sizetocopy > sizetocopy_now) {
- sizetocopy -= sizetocopy_now;
- fill_block(woinst, start, filldata, sizetocopy_now);
- fill_block(woinst, 0, filldata, sizetocopy);
- } else {
- fill_block(woinst, start, filldata, sizetocopy);
- }
-}
-
-/**
- * emu10k1_waveout_update -
- *
- * updates the position of the voice buffer hardware pointer (hw_pos)
- * and the number of free bytes on the buffer (free_bytes).
- * The free bytes _don't_ include silence bytes that may have been
- * added to the buffer.
- *
- */
-void emu10k1_waveout_update(struct woinst *woinst)
-{
- u32 hw_pos;
- u32 diff;
-
- /* There is no actual start yet */
- if (!(woinst->state & WAVE_STATE_STARTED)) {
- hw_pos = woinst->buffer.hw_pos;
- } else {
- /* hw_pos in sample units */
- hw_pos = sblive_readptr(woinst->voice[0].card, CCCA_CURRADDR, woinst->voice[0].num);
-
- if(hw_pos < woinst->voice[0].start)
- hw_pos += woinst->buffer.size / woinst->format.bytespervoicesample - woinst->voice[0].start;
- else
- hw_pos -= woinst->voice[0].start;
-
- hw_pos *= woinst->format.bytespervoicesample;
- }
-
- diff = (woinst->buffer.size + hw_pos - woinst->buffer.hw_pos) % woinst->buffer.size;
- woinst->total_played += diff;
- woinst->buffer.free_bytes += diff;
- woinst->buffer.hw_pos = hw_pos;
-}
diff --git a/sound/oss/emu10k1/cardwo.h b/sound/oss/emu10k1/cardwo.h
deleted file mode 100644
index 1dece8853e5c..000000000000
--- a/sound/oss/emu10k1/cardwo.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- **********************************************************************
- * cardwo.h -- header file for card wave out functions
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _CARDWO_H
-#define _CARDWO_H
-
-#include "icardwav.h"
-#include "audio.h"
-#include "voicemgr.h"
-#include "timer.h"
-
-/* setting this to other than a power of two may break some applications */
-#define WAVEOUT_MAXBUFSIZE MAXBUFSIZE
-
-#define WAVEOUT_DEFAULTFRAGLEN 20 /* Time to play a fragment in ms (latency) */
-#define WAVEOUT_DEFAULTBUFLEN 500 /* Time to play the entire buffer in ms */
-
-#define WAVEOUT_MINFRAGSHIFT 6 /* Minimum fragment size in bytes is 2^6 */
-#define WAVEOUT_MINFRAGS 3 /* _don't_ go bellow 3, it would break silence filling */
-#define WAVEOUT_MAXVOICES 6
-
-struct waveout_buffer {
- u16 ossfragshift;
- u32 numfrags;
- u32 fragment_size; /* in bytes units */
- u32 size; /* in bytes units */
- u32 pages; /* buffer size in page units*/
- u32 silence_pos; /* software cursor position (including silence bytes) */
- u32 hw_pos; /* hardware cursor position */
- u32 free_bytes; /* free bytes available on the buffer (not including silence bytes) */
- u8 fill_silence;
- u32 silence_bytes; /* silence bytes on the buffer */
-};
-
-struct woinst
-{
- u8 state;
- u8 num_voices;
- struct emu_voice voice[WAVEOUT_MAXVOICES];
- struct emu_timer timer;
- struct wave_format format;
- struct waveout_buffer buffer;
- wait_queue_head_t wait_queue;
- u8 mmapped;
- u32 total_copied; /* total number of bytes written() to the buffer (excluding silence) */
- u32 total_played; /* total number of bytes played including silence */
- u32 blocks;
- u8 device;
- spinlock_t lock;
-};
-
-int emu10k1_waveout_open(struct emu10k1_wavedevice *);
-void emu10k1_waveout_close(struct emu10k1_wavedevice *);
-void emu10k1_waveout_start(struct emu10k1_wavedevice *);
-void emu10k1_waveout_stop(struct emu10k1_wavedevice *);
-void emu10k1_waveout_getxfersize(struct woinst*, u32 *);
-void emu10k1_waveout_xferdata(struct woinst*, u8 __user *, u32 *);
-void emu10k1_waveout_fillsilence(struct woinst*);
-int emu10k1_waveout_setformat(struct emu10k1_wavedevice*, struct wave_format*);
-void emu10k1_waveout_update(struct woinst*);
-
-#endif /* _CARDWO_H */
diff --git a/sound/oss/emu10k1/ecard.c b/sound/oss/emu10k1/ecard.c
deleted file mode 100644
index 4ae635fe1402..000000000000
--- a/sound/oss/emu10k1/ecard.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- **********************************************************************
- * ecard.c - E-card initialization code
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 "ecard.h"
-#include "hwaccess.h"
-
-/* Private routines */
-static void ecard_setadcgain(struct emu10k1_card *, struct ecard_state *, u16);
-static void ecard_write(struct emu10k1_card *, u32);
-
-/**************************************************************************
- * @func Set the gain of the ECARD's CS3310 Trim/gain controller. The
- * trim value consists of a 16bit value which is composed of two
- * 8 bit gain/trim values, one for the left channel and one for the
- * right channel. The following table maps from the Gain/Attenuation
- * value in decibels into the corresponding bit pattern for a single
- * channel.
- */
-
-static void ecard_setadcgain(struct emu10k1_card *card, struct ecard_state *ecard, u16 gain)
-{
- u32 currbit;
- ecard->adc_gain = gain;
-
- /* Enable writing to the TRIM registers */
- ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
-
- /* Do it again to insure that we meet hold time requirements */
- ecard_write(card, ecard->control_bits & ~EC_TRIM_CSN);
-
- for (currbit = (1L << 15); currbit; currbit >>= 1) {
-
- u32 value = ecard->control_bits & ~(EC_TRIM_CSN|EC_TRIM_SDATA);
-
- if (gain & currbit)
- value |= EC_TRIM_SDATA;
-
- /* Clock the bit */
- ecard_write(card, value);
- ecard_write(card, value | EC_TRIM_SCLK);
- ecard_write(card, value);
- }
-
- ecard_write(card, ecard->control_bits);
-}
-
-/**************************************************************************
- * @func Clock bits into the Ecard's control latch. The Ecard uses a
- * control latch will is loaded bit-serially by toggling the Modem control
- * lines from function 2 on the E8010. This function hides these details
- * and presents the illusion that we are actually writing to a distinct
- * register.
- */
-static void ecard_write(struct emu10k1_card *card, u32 value)
-{
- u16 count;
- u32 data, hcvalue;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- hcvalue = inl(card->iobase + HCFG) & ~(HOOKN_BIT|HANDN_BIT|PULSEN_BIT);
-
- outl(card->iobase + HCFG, hcvalue);
-
- for (count = 0 ; count < EC_NUM_CONTROL_BITS; count++) {
-
- /* Set up the value */
- data = ((value & 0x1) ? PULSEN_BIT : 0);
- value >>= 1;
-
- outl(card->iobase + HCFG, hcvalue | data);
-
- /* Clock the shift register */
- outl(card->iobase + HCFG, hcvalue | data | HANDN_BIT);
- outl(card->iobase + HCFG, hcvalue | data);
- }
-
- /* Latch the bits */
- outl(card->iobase + HCFG, hcvalue | HOOKN_BIT);
- outl(card->iobase + HCFG, hcvalue);
-
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-void __devinit emu10k1_ecard_init(struct emu10k1_card *card)
-{
- u32 hcvalue;
- struct ecard_state ecard;
-
- /* Set up the initial settings */
- ecard.mux0_setting = EC_DEFAULT_SPDIF0_SEL;
- ecard.mux1_setting = EC_DEFAULT_SPDIF1_SEL;
- ecard.mux2_setting = 0;
- ecard.adc_gain = EC_DEFAULT_ADC_GAIN;
- ecard.control_bits = EC_RAW_RUN_MODE |
- EC_SPDIF0_SELECT(ecard.mux0_setting) |
- EC_SPDIF1_SELECT(ecard.mux1_setting);
-
-
- /* Step 0: Set the codec type in the hardware control register
- * and enable audio output */
- hcvalue = emu10k1_readfn0(card, HCFG);
- emu10k1_writefn0(card, HCFG, hcvalue | HCFG_AUDIOENABLE | HCFG_CODECFORMAT_I2S);
-
- /* Step 1: Turn off the led and deassert TRIM_CS */
- ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
-
- /* Step 2: Calibrate the ADC and DAC */
- ecard_write(card, EC_DACCAL | EC_LEDN | EC_TRIM_CSN);
-
- /* Step 3: Wait for awhile; FIXME: Is this correct? */
-
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ);
-
- /* Step 4: Switch off the DAC and ADC calibration. Note
- * That ADC_CAL is actually an inverted signal, so we assert
- * it here to stop calibration. */
- ecard_write(card, EC_ADCCAL | EC_LEDN | EC_TRIM_CSN);
-
- /* Step 4: Switch into run mode */
- ecard_write(card, ecard.control_bits);
-
- /* Step 5: Set the analog input gain */
- ecard_setadcgain(card, &ecard, ecard.adc_gain);
-}
-
-
diff --git a/sound/oss/emu10k1/ecard.h b/sound/oss/emu10k1/ecard.h
deleted file mode 100644
index 67aead16e8ec..000000000000
--- a/sound/oss/emu10k1/ecard.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- **********************************************************************
- * ecard.h
- * Copyright 1999, 2000 Creative Labs, 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., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-#ifndef _ECARD_H
-#define _ECARD_H
-
-#include "8010.h"
-#include "hwaccess.h"
-#include <linux/init.h>
-
-/* In A1 Silicon, these bits are in the HC register */
-#define HOOKN_BIT (1L << 12)
-#define HANDN_BIT (1L << 11)
-#define PULSEN_BIT (1L << 10)
-
-#define EC_GDI1 (1 << 13)
-#define EC_GDI0 (1 << 14)
-
-#define EC_NUM_CONTROL_BITS 20
-
-#define EC_AC3_DATA_SELN 0x0001L
-#define EC_EE_DATA_SEL 0x0002L
-#define EC_EE_CNTRL_SELN 0x0004L
-#define EC_EECLK 0x0008L
-#define EC_EECS 0x0010L
-#define EC_EESDO 0x0020L
-#define EC_TRIM_CSN 0x0040L
-#define EC_TRIM_SCLK 0x0080L
-#define EC_TRIM_SDATA 0x0100L
-#define EC_TRIM_MUTEN 0x0200L
-#define EC_ADCCAL 0x0400L
-#define EC_ADCRSTN 0x0800L
-#define EC_DACCAL 0x1000L
-#define EC_DACMUTEN 0x2000L
-#define EC_LEDN 0x4000L
-
-#define EC_SPDIF0_SEL_SHIFT 15
-#define EC_SPDIF1_SEL_SHIFT 17
-#define EC_SPDIF0_SEL_MASK (0x3L << EC_SPDIF0_SEL_SHIFT)
-#define EC_SPDIF1_SEL_MASK (0x7L << EC_SPDIF1_SEL_SHIFT)
-#define EC_SPDIF0_SELECT(_x) (((_x) << EC_SPDIF0_SEL_SHIFT) & EC_SPDIF0_SEL_MASK)
-#define EC_SPDIF1_SELECT(_x) (((_x) << EC_SPDIF1_SEL_SHIFT) & EC_SPDIF1_SEL_MASK)
-#define EC_CURRENT_PROM_VERSION 0x01 /* Self-explanatory. This should
- * be incremented any time the EEPROM's
- * format is changed. */
-
-#define EC_EEPROM_SIZE 0x40 /* ECARD EEPROM has 64 16-bit words */
-
-/* Addresses for special values stored in to EEPROM */
-#define EC_PROM_VERSION_ADDR 0x20 /* Address of the current prom version */
-#define EC_BOARDREV0_ADDR 0x21 /* LSW of board rev */
-#define EC_BOARDREV1_ADDR 0x22 /* MSW of board rev */
-
-#define EC_LAST_PROMFILE_ADDR 0x2f
-
-#define EC_SERIALNUM_ADD 0x30 /* First word of serial number. The number
- * can be up to 30 characters in length
- * and is stored as a NULL-terminated
- * ASCII string. Any unused bytes must be
- * filled with zeros */
-#define EC_CHECKSUM_ADDR 0x3f /* Location at which checksum is stored */
-
-
-
-/* Most of this stuff is pretty self-evident. According to the hardware
- * dudes, we need to leave the ADCCAL bit low in order to avoid a DC
- * offset problem. Weird.
- */
-#define EC_RAW_RUN_MODE (EC_DACMUTEN | EC_ADCRSTN | EC_TRIM_MUTEN | EC_TRIM_CSN)
-
-
-#define EC_DEFAULT_ADC_GAIN 0xC4C4
-#define EC_DEFAULT_SPDIF0_SEL 0x0
-#define EC_DEFAULT_SPDIF1_SEL 0x4
-
-#define HC_EA 0x01L
-
-/* ECARD state structure. This structure maintains the state
- * for various portions of the ECARD's onboard hardware.
- */
-struct ecard_state {
- u32 control_bits;
- u16 adc_gain;
- u16 mux0_setting;
- u16 mux1_setting;
- u16 mux2_setting;
-};
-
-void emu10k1_ecard_init(struct emu10k1_card *) __devinit;
-
-#endif /* _ECARD_H */
diff --git a/sound/oss/emu10k1/efxmgr.c b/sound/oss/emu10k1/efxmgr.c
deleted file mode 100644
index 7d5865de4c2e..000000000000
--- a/sound/oss/emu10k1/efxmgr.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- **********************************************************************
- * efxmgr.c
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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/bitops.h>
-#include "hwaccess.h"
-#include "efxmgr.h"
-
-int emu10k1_find_control_gpr(struct patch_manager *mgr, const char *patch_name, const char *gpr_name)
-{
- struct dsp_patch *patch;
- struct dsp_rpatch *rpatch;
- char s[PATCH_NAME_SIZE + 4];
- unsigned long *gpr_used;
- int i;
-
- DPD(2, "emu10k1_find_control_gpr(): %s %s\n", patch_name, gpr_name);
-
- rpatch = &mgr->rpatch;
- if (!strcmp(rpatch->name, patch_name)) {
- gpr_used = rpatch->gpr_used;
- goto match;
- }
-
- for (i = 0; i < mgr->current_pages * PATCHES_PER_PAGE; i++) {
- patch = PATCH(mgr, i);
- sprintf(s,"%s", patch->name);
-
- if (!strcmp(s, patch_name)) {
- gpr_used = patch->gpr_used;
- goto match;
- }
- }
-
- return -1;
-
- match:
- for (i = 0; i < NUM_GPRS; i++)
- if (mgr->gpr[i].type == GPR_TYPE_CONTROL &&
- test_bit(i, gpr_used) &&
- !strcmp(mgr->gpr[i].name, gpr_name))
- return i;
-
- return -1;
-}
-
-void emu10k1_set_control_gpr(struct emu10k1_card *card, int addr, s32 val, int flag)
-{
- struct patch_manager *mgr = &card->mgr;
-
- DPD(2, "emu10k1_set_control_gpr(): %d %x\n", addr, val);
-
- if (addr < 0 || addr >= NUM_GPRS)
- return;
-
- //fixme: once patch manager is up, remember to fix this for the audigy
- if (card->is_audigy) {
- sblive_writeptr(card, A_GPR_BASE + addr, 0, val);
- } else {
- if (flag)
- val += sblive_readptr(card, GPR_BASE + addr, 0);
- if (val > mgr->gpr[addr].max)
- val = mgr->gpr[addr].max;
- else if (val < mgr->gpr[addr].min)
- val = mgr->gpr[addr].min;
- sblive_writeptr(card, GPR_BASE + addr, 0, val);
- }
-
-
-}
-
-//TODO: make this configurable:
-#define VOLCTRL_CHANNEL SOUND_MIXER_VOLUME
-#define VOLCTRL_STEP_SIZE 5
-
-//An internal function for setting OSS mixer controls.
-static void emu10k1_set_oss_vol(struct emu10k1_card *card, int oss_mixer,
- unsigned int left, unsigned int right)
-{
- extern char volume_params[SOUND_MIXER_NRDEVICES];
-
- card->ac97->mixer_state[oss_mixer] = (right << 8) | left;
-
- if (!card->is_aps)
- card->ac97->write_mixer(card->ac97, oss_mixer, left, right);
-
- emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left,
- volume_params[oss_mixer]);
-
- emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][1], right,
- volume_params[oss_mixer]);
-}
-
-//FIXME: mute should unmute when pressed a second time
-void emu10k1_mute_irqhandler(struct emu10k1_card *card)
-{
- int oss_channel = VOLCTRL_CHANNEL;
- int left, right;
- static int val;
-
- if (val) {
- left = val & 0xff;
- right = (val >> 8) & 0xff;
- val = 0;
- } else {
- val = card->ac97->mixer_state[oss_channel];
- left = 0;
- right = 0;
- }
-
- emu10k1_set_oss_vol(card, oss_channel, left, right);
-}
-
-void emu10k1_volincr_irqhandler(struct emu10k1_card *card)
-{
- int oss_channel = VOLCTRL_CHANNEL;
- int left, right;
-
- left = card->ac97->mixer_state[oss_channel] & 0xff;
- right = (card->ac97->mixer_state[oss_channel] >> 8) & 0xff;
-
- if ((left += VOLCTRL_STEP_SIZE) > 100)
- left = 100;
-
- if ((right += VOLCTRL_STEP_SIZE) > 100)
- right = 100;
-
- emu10k1_set_oss_vol(card, oss_channel, left, right);
-}
-
-void emu10k1_voldecr_irqhandler(struct emu10k1_card *card)
-{
- int oss_channel = VOLCTRL_CHANNEL;
- int left, right;
-
- left = card->ac97->mixer_state[oss_channel] & 0xff;
- right = (card->ac97->mixer_state[oss_channel] >> 8) & 0xff;
-
- if ((left -= VOLCTRL_STEP_SIZE) < 0)
- left = 0;
-
- if ((right -= VOLCTRL_STEP_SIZE) < 0)
- right = 0;
-
- emu10k1_set_oss_vol(card, oss_channel, left, right);
-}
-
-void emu10k1_set_volume_gpr(struct emu10k1_card *card, int addr, s32 vol, int scale)
-{
- struct patch_manager *mgr = &card->mgr;
- unsigned long flags;
-
- static const s32 log2lin[4] ={ // attenuation (dB)
- 0x7fffffff, // 0.0
- 0x7fffffff * 0.840896415253715 , // 1.5
- 0x7fffffff * 0.707106781186548, // 3.0
- 0x7fffffff * 0.594603557501361 , // 4.5
- };
-
- if (addr < 0)
- return;
-
- vol = (100 - vol ) * scale / 100;
-
- // Thanks to the comp.dsp newsgroup for this neat trick:
- vol = (vol >= scale) ? 0 : (log2lin[vol & 3] >> (vol >> 2));
-
- spin_lock_irqsave(&mgr->lock, flags);
- emu10k1_set_control_gpr(card, addr, vol, 0);
- spin_unlock_irqrestore(&mgr->lock, flags);
-}
-
-void emu10k1_dsp_irqhandler(struct emu10k1_card *card)
-{
- unsigned long flags;
-
- if (card->pt.state != PT_STATE_INACTIVE) {
- u32 bc;
- bc = sblive_readptr(card, GPR_BASE + card->pt.intr_gpr, 0);
- if (bc != 0) {
- DPD(3, "pt interrupt, bc = %d\n", bc);
- spin_lock_irqsave(&card->pt.lock, flags);
- card->pt.blocks_played = bc;
- if (card->pt.blocks_played >= card->pt.blocks_copied) {
- DPF(1, "buffer underrun in passthrough playback\n");
- emu10k1_pt_stop(card);
- }
- wake_up_interruptible(&card->pt.wait);
- spin_unlock_irqrestore(&card->pt.lock, flags);
- }
- }
-}
-
diff --git a/sound/oss/emu10k1/efxmgr.h b/sound/oss/emu10k1/efxmgr.h
deleted file mode 100644
index ef48e5c70d1f..000000000000
--- a/sound/oss/emu10k1/efxmgr.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- **********************************************************************
- * sblive_fx.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _EFXMGR_H
-#define _EFXMGR_H
-
-struct emu_efx_info_t{
- int opcode_shift;
- int high_operand_shift;
- int instruction_start;
- int gpr_base;
- int output_base;
-};
-
-
-#define WRITE_EFX(a, b, c) sblive_writeptr((a), emu_efx_info[card->is_audigy].instruction_start + (b), 0, (c))
-
-#define OP(op, z, w, x, y) \
- do { WRITE_EFX(card, (pc) * 2, ((x) << emu_efx_info[card->is_audigy].high_operand_shift) | (y)); \
- WRITE_EFX(card, (pc) * 2 + 1, ((op) << emu_efx_info[card->is_audigy].opcode_shift ) | ((z) << emu_efx_info[card->is_audigy].high_operand_shift) | (w)); \
- ++pc; } while (0)
-
-#define NUM_INPUTS 0x20
-#define NUM_OUTPUTS 0x20
-#define NUM_GPRS 0x100
-
-#define A_NUM_INPUTS 0x60
-#define A_NUM_OUTPUTS 0x60 //fixme: this may or may not be true
-#define A_NUM_GPRS 0x200
-
-#define GPR_NAME_SIZE 32
-#define PATCH_NAME_SIZE 32
-
-struct dsp_rpatch {
- char name[PATCH_NAME_SIZE];
- u16 code_start;
- u16 code_size;
-
- unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
- unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
- unsigned long route[NUM_OUTPUTS];
- unsigned long route_v[NUM_OUTPUTS];
-};
-
-struct dsp_patch {
- char name[PATCH_NAME_SIZE];
- u8 id;
- unsigned long input; /* bitmap of the lines used as inputs */
- unsigned long output; /* bitmap of the lines used as outputs */
- u16 code_start;
- u16 code_size;
-
- unsigned long gpr_used[NUM_GPRS / (sizeof(unsigned long) * 8) + 1]; /* bitmap of used gprs */
- unsigned long gpr_input[NUM_GPRS / (sizeof(unsigned long) * 8) + 1];
- u8 traml_istart; /* starting address of the internal tram lines used */
- u8 traml_isize; /* number of internal tram lines used */
-
- u8 traml_estart;
- u8 traml_esize;
-
- u16 tramb_istart; /* starting address of the internal tram memory used */
- u16 tramb_isize; /* amount of internal memory used */
- u32 tramb_estart;
- u32 tramb_esize;
-};
-
-struct dsp_gpr {
- u8 type; /* gpr type, STATIC, DYNAMIC, INPUT, OUTPUT, CONTROL */
- char name[GPR_NAME_SIZE]; /* gpr value, only valid for control gprs */
- s32 min, max; /* value range for this gpr, only valid for control gprs */
- u8 line; /* which input/output line is the gpr attached, only valid for input/output gprs */
- u8 usage;
-};
-
-enum {
- GPR_TYPE_NULL = 0,
- GPR_TYPE_IO,
- GPR_TYPE_STATIC,
- GPR_TYPE_DYNAMIC,
- GPR_TYPE_CONTROL,
- GPR_TYPE_CONSTANT
-};
-
-#define GPR_BASE 0x100
-#define OUTPUT_BASE 0x20
-
-#define A_GPR_BASE 0x400
-#define A_OUTPUT_BASE 0x60
-
-#define MAX_PATCHES_PAGES 32
-
-struct patch_manager {
- void *patch[MAX_PATCHES_PAGES];
- int current_pages;
- struct dsp_rpatch rpatch;
- struct dsp_gpr gpr[NUM_GPRS]; /* gpr usage table */
- spinlock_t lock;
- s16 ctrl_gpr[SOUND_MIXER_NRDEVICES][2];
-};
-
-#define PATCHES_PER_PAGE (PAGE_SIZE / sizeof(struct dsp_patch))
-
-#define PATCH(mgr, i) ((struct dsp_patch *) (mgr)->patch[(i) / PATCHES_PER_PAGE] + (i) % PATCHES_PER_PAGE)
-
-/* PCM volume control */
-#define TMP_PCM_L 0x100 //temp PCM L (after the vol control)
-#define TMP_PCM_R 0x101
-#define VOL_PCM_L 0x102 //vol PCM
-#define VOL_PCM_R 0x103
-
-/* Routing patch */
-#define TMP_AC_L 0x104 //tmp ac97 out
-#define TMP_AC_R 0x105
-#define TMP_REAR_L 0x106 //output - Temp Rear
-#define TMP_REAR_R 0x107
-#define TMP_DIGI_L 0x108 //output - Temp digital
-#define TMP_DIGI_R 0x109
-#define DSP_VOL_L 0x10a // main dsp volume
-#define DSP_VOL_R 0x10b
-
-/* hw inputs */
-#define PCM_IN_L 0x00
-#define PCM_IN_R 0x01
-
-#define PCM1_IN_L 0x04
-#define PCM1_IN_R 0x05
-//mutilchannel playback stream appear here:
-
-#define MULTI_FRONT_L 0x08
-#define MULTI_FRONT_R 0x09
-#define MULTI_REAR_L 0x0a
-#define MULTI_REAR_R 0x0b
-#define MULTI_CENTER 0x0c
-#define MULTI_LFE 0x0d
-
-#define AC97_IN_L 0x10
-#define AC97_IN_R 0x11
-#define SPDIF_CD_L 0x12
-#define SPDIF_CD_R 0x13
-
-/* hw outputs */
-#define AC97_FRONT_L 0x20
-#define AC97_FRONT_R 0x21
-#define DIGITAL_OUT_L 0x22
-#define DIGITAL_OUT_R 0x23
-#define DIGITAL_CENTER 0x24
-#define DIGITAL_LFE 0x25
-
-#define ANALOG_REAR_L 0x28
-#define ANALOG_REAR_R 0x29
-#define ADC_REC_L 0x2a
-#define ADC_REC_R 0x2b
-
-#define ANALOG_CENTER 0x31
-#define ANALOG_LFE 0x32
-
-
-#define INPUT_PATCH_START(patch, nm, ln, i) \
-do { \
- patch = PATCH(mgr, patch_n); \
- strcpy(patch->name, nm); \
- patch->code_start = pc * 2; \
- patch->input = (1<<(0x1f&ln)); \
- patch->output= (1<<(0x1f&ln)); \
- patch->id = i; \
-} while(0)
-
-#define INPUT_PATCH_END(patch) \
-do { \
- patch->code_size = pc * 2 - patch->code_start; \
- patch_n++; \
-} while(0)
-
-
-#define ROUTING_PATCH_START(patch, nm) \
-do { \
- patch = &mgr->rpatch; \
- strcpy(patch->name, nm); \
- patch->code_start = pc * 2; \
-} while(0)
-
-#define ROUTING_PATCH_END(patch) \
-do { \
- patch->code_size = pc * 2 - patch->code_start; \
-} while(0)
-
-#define CONNECT(input, output) set_bit(input, &rpatch->route[(output) - OUTPUT_BASE]);
-
-#define CONNECT_V(input, output) set_bit(input, &rpatch->route_v[(output) - OUTPUT_BASE]);
-
-#define OUTPUT_PATCH_START(patch, nm, ln, i) \
-do { \
- patch = PATCH(mgr, patch_n); \
- strcpy(patch->name, nm); \
- patch->code_start = pc * 2; \
- patch->input = (1<<(0x1f&ln)); \
- patch->output= (1<<(0x1f&ln)); \
- patch->id = i; \
-} while(0)
-
-#define OUTPUT_PATCH_END(patch) \
-do { \
- patch->code_size = pc * 2 - patch->code_start; \
- patch_n++; \
-} while(0)
-
-#define GET_OUTPUT_GPR(patch, g, ln) \
-do { \
- mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_IO; \
- mgr->gpr[(g) - GPR_BASE].usage++; \
- mgr->gpr[(g) - GPR_BASE].line = ln; \
- set_bit((g) - GPR_BASE, patch->gpr_used); \
-} while(0)
-
-#define GET_INPUT_GPR(patch, g, ln) \
-do { \
- mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_IO; \
- mgr->gpr[(g) - GPR_BASE].usage++; \
- mgr->gpr[(g) - GPR_BASE].line = ln; \
- set_bit((g) - GPR_BASE, patch->gpr_used); \
- set_bit((g) - GPR_BASE, patch->gpr_input); \
-} while(0)
-
-#define GET_DYNAMIC_GPR(patch, g) \
-do { \
- mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_DYNAMIC; \
- mgr->gpr[(g) - GPR_BASE].usage++; \
- set_bit((g) - GPR_BASE, patch->gpr_used); \
-} while(0)
-
-#define GET_CONTROL_GPR(patch, g, nm, a, b) \
-do { \
- strcpy(mgr->gpr[(g) - GPR_BASE].name, nm); \
- mgr->gpr[(g) - GPR_BASE].type = GPR_TYPE_CONTROL; \
- mgr->gpr[(g) - GPR_BASE].usage++; \
- mgr->gpr[(g) - GPR_BASE].min = a; \
- mgr->gpr[(g) - GPR_BASE].max = b; \
- sblive_writeptr(card, g, 0, b); \
- set_bit((g) - GPR_BASE, patch->gpr_used); \
-} while(0)
-
-#endif /* _EFXMGR_H */
diff --git a/sound/oss/emu10k1/emuadxmg.c b/sound/oss/emu10k1/emuadxmg.c
deleted file mode 100644
index d7d2d4caf7ba..000000000000
--- a/sound/oss/emu10k1/emuadxmg.c
+++ /dev/null
@@ -1,104 +0,0 @@
-
-/*
- **********************************************************************
- * emuadxmg.c - Address space manager for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 "hwaccess.h"
-
-/* Allocates emu address space */
-
-int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card)
-{
- u16 *pagetable = card->emupagetable;
- u16 index = 0;
- u16 numpages;
- unsigned long flags;
-
- /* Convert bytes to pages */
- numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0);
-
- spin_lock_irqsave(&card->lock, flags);
-
- while (index < (MAXPAGES - 1)) {
- if (pagetable[index] & 0x8000) {
- /* This block of pages is in use, jump to the start of the next block. */
- index += (pagetable[index] & 0x7fff);
- } else {
- /* Found free block */
- if (pagetable[index] >= numpages) {
-
- /* Block is large enough */
-
- /* If free block is larger than the block requested
- * then adjust the size of the block remaining */
- if (pagetable[index] > numpages)
- pagetable[index + numpages] = pagetable[index] - numpages;
-
- pagetable[index] = (numpages | 0x8000); /* Mark block as used */
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return index;
- } else {
- /* Block too small, jump to the start of the next block */
- index += pagetable[index];
- }
- }
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return -1;
-}
-
-/* Frees a previously allocated emu address space. */
-
-void emu10k1_addxmgr_free(struct emu10k1_card *card, int index)
-{
- u16 *pagetable = card->emupagetable;
- u16 origsize = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (pagetable[index] & 0x8000) {
- /* Block is allocated - mark block as free */
- origsize = pagetable[index] & 0x7fff;
- pagetable[index] = origsize;
-
- /* If next block is free, we concat both blocks */
- if (!(pagetable[index + origsize] & 0x8000))
- pagetable[index] += pagetable[index + origsize] & 0x7fff;
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return;
-}
diff --git a/sound/oss/emu10k1/hwaccess.c b/sound/oss/emu10k1/hwaccess.c
deleted file mode 100644
index 2dc16a841fa1..000000000000
--- a/sound/oss/emu10k1/hwaccess.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- **********************************************************************
- * hwaccess.c -- Hardware access layer
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * December 9, 1999 Jon Taylor rewrote the I/O subsystem
- *
- **********************************************************************
- *
- * 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 <asm/io.h>
-
-#include "hwaccess.h"
-#include "8010.h"
-#include "icardmid.h"
-
-/*************************************************************************
-* Function : srToPitch *
-* Input : sampleRate - sampling rate *
-* Return : pitch value *
-* About : convert sampling rate to pitch *
-* Note : for 8010, sampling rate is at 48kHz, this function should *
-* be changed. *
-*************************************************************************/
-u32 srToPitch(u32 sampleRate)
-{
- int i;
-
- /* FIXME: These tables should be defined in a headerfile */
- static u32 logMagTable[128] = {
- 0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
- 0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
- 0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
- 0x3f782, 0x41e42, 0x444c1, 0x46b01, 0x49101, 0x4b6c4, 0x4dc49, 0x50191,
- 0x5269e, 0x54b6f, 0x57006, 0x59463, 0x5b888, 0x5dc74, 0x60029, 0x623a7,
- 0x646ee, 0x66a00, 0x68cdd, 0x6af86, 0x6d1fa, 0x6f43c, 0x7164b, 0x73829,
- 0x759d4, 0x77b4f, 0x79c9a, 0x7bdb5, 0x7dea1, 0x7ff5e, 0x81fed, 0x8404e,
- 0x86082, 0x88089, 0x8a064, 0x8c014, 0x8df98, 0x8fef1, 0x91e20, 0x93d26,
- 0x95c01, 0x97ab4, 0x9993e, 0x9b79f, 0x9d5d9, 0x9f3ec, 0xa11d8, 0xa2f9d,
- 0xa4d3c, 0xa6ab5, 0xa8808, 0xaa537, 0xac241, 0xadf26, 0xafbe7, 0xb1885,
- 0xb3500, 0xb5157, 0xb6d8c, 0xb899f, 0xba58f, 0xbc15e, 0xbdd0c, 0xbf899,
- 0xc1404, 0xc2f50, 0xc4a7b, 0xc6587, 0xc8073, 0xc9b3f, 0xcb5ed, 0xcd07c,
- 0xceaec, 0xd053f, 0xd1f73, 0xd398a, 0xd5384, 0xd6d60, 0xd8720, 0xda0c3,
- 0xdba4a, 0xdd3b4, 0xded03, 0xe0636, 0xe1f4e, 0xe384a, 0xe512c, 0xe69f3,
- 0xe829f, 0xe9b31, 0xeb3a9, 0xecc08, 0xee44c, 0xefc78, 0xf148a, 0xf2c83,
- 0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
- };
-
- static char logSlopeTable[128] = {
- 0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
- 0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
- 0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
- 0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
- 0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
- 0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
- 0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
- 0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
- 0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
- 0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
- 0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
- 0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
- 0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
- 0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
- 0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
- };
-
- if (sampleRate == 0)
- return 0; /* Bail out if no leading "1" */
-
- sampleRate *= 11185; /* Scale 48000 to 0x20002380 */
-
- for (i = 31; i > 0; i--) {
- if (sampleRate & 0x80000000) { /* Detect leading "1" */
- return (u32) (((s32) (i - 15) << 20) +
- logMagTable[0x7f & (sampleRate >> 24)] +
- (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]);
- }
- sampleRate = sampleRate << 1;
- }
-
- DPF(2, "srToPitch: BUG!\n");
- return 0; /* Should never reach this point */
-}
-
-/*******************************************
-* write/read PCI function 0 registers *
-********************************************/
-void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data)
-{
- unsigned long flags;
-
- if (reg & 0xff000000) {
- u32 mask;
- u8 size, offset;
-
- size = (reg >> 24) & 0x3f;
- offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
- data = (data << offset) & mask;
- reg &= 0x7f;
-
- spin_lock_irqsave(&card->lock, flags);
- data |= inl(card->iobase + reg) & ~mask;
- outl(data, card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
- } else {
- spin_lock_irqsave(&card->lock, flags);
- outl(data, card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
- }
-
- return;
-}
-
-#ifdef DBGEMU
-void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (size == 32)
- outl(data, card->iobase + (reg & 0x1F));
- else if (size == 16)
- outw(data, card->iobase + (reg & 0x1F));
- else
- outb(data, card->iobase + (reg & 0x1F));
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return;
-}
-#endif /* DBGEMU */
-
-u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
-{
- u32 val;
- unsigned long flags;
-
- if (reg & 0xff000000) {
- u32 mask;
- u8 size, offset;
-
- size = (reg >> 24) & 0x3f;
- offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
- reg &= 0x7f;
-
- spin_lock_irqsave(&card->lock, flags);
- val = inl(card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return (val & mask) >> offset;
- } else {
- spin_lock_irqsave(&card->lock, flags);
- val = inl(card->iobase + reg);
- spin_unlock_irqrestore(&card->lock, flags);
- return val;
- }
-}
-
-void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- outw(data & TIMER_RATE_MASK, card->iobase + TIMER);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/************************************************************************
-* write/read Emu10k1 pointer-offset register set, accessed through *
-* the PTR and DATA registers *
-*************************************************************************/
-#define A_PTR_ADDRESS_MASK 0x0fff0000
-void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
-{
- u32 regptr;
- unsigned long flags;
-
- regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
-
- if (reg & 0xff000000) {
- u32 mask;
- u8 size, offset;
-
- size = (reg >> 24) & 0x3f;
- offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
- data = (data << offset) & mask;
-
- spin_lock_irqsave(&card->lock, flags);
- outl(regptr, card->iobase + PTR);
- data |= inl(card->iobase + DATA) & ~mask;
- outl(data, card->iobase + DATA);
- spin_unlock_irqrestore(&card->lock, flags);
- } else {
- spin_lock_irqsave(&card->lock, flags);
- outl(regptr, card->iobase + PTR);
- outl(data, card->iobase + DATA);
- spin_unlock_irqrestore(&card->lock, flags);
- }
-}
-
-/* ... : data, reg, ... , TAGLIST_END */
-void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
-{
- va_list args;
-
- unsigned long flags;
- u32 reg;
-
- va_start(args, channel);
-
- spin_lock_irqsave(&card->lock, flags);
- while ((reg = va_arg(args, u32)) != TAGLIST_END) {
- u32 data = va_arg(args, u32);
- u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK)
- | (channel & PTR_CHANNELNUM_MASK));
- outl(regptr, card->iobase + PTR);
- if (reg & 0xff000000) {
- int size = (reg >> 24) & 0x3f;
- int offset = (reg >> 16) & 0x1f;
- u32 mask = ((1 << size) - 1) << offset;
- data = (data << offset) & mask;
-
- data |= inl(card->iobase + DATA) & ~mask;
- }
- outl(data, card->iobase + DATA);
- }
- spin_unlock_irqrestore(&card->lock, flags);
-
- va_end(args);
-
- return;
-}
-
-u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
-{
- u32 regptr, val;
- unsigned long flags;
-
- regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
-
- if (reg & 0xff000000) {
- u32 mask;
- u8 size, offset;
-
- size = (reg >> 24) & 0x3f;
- offset = (reg >> 16) & 0x1f;
- mask = ((1 << size) - 1) << offset;
-
- spin_lock_irqsave(&card->lock, flags);
- outl(regptr, card->iobase + PTR);
- val = inl(card->iobase + DATA);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return (val & mask) >> offset;
- } else {
- spin_lock_irqsave(&card->lock, flags);
- outl(regptr, card->iobase + PTR);
- val = inl(card->iobase + DATA);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return val;
- }
-}
-
-void emu10k1_irq_enable(struct emu10k1_card *card, u32 irq_mask)
-{
- u32 val;
- unsigned long flags;
-
- DPF(2,"emu10k1_irq_enable()\n");
-
- spin_lock_irqsave(&card->lock, flags);
- val = inl(card->iobase + INTE) | irq_mask;
- outl(val, card->iobase + INTE);
- spin_unlock_irqrestore(&card->lock, flags);
- return;
-}
-
-void emu10k1_irq_disable(struct emu10k1_card *card, u32 irq_mask)
-{
- u32 val;
- unsigned long flags;
-
- DPF(2,"emu10k1_irq_disable()\n");
-
- spin_lock_irqsave(&card->lock, flags);
- val = inl(card->iobase + INTE) & ~irq_mask;
- outl(val, card->iobase + INTE);
- spin_unlock_irqrestore(&card->lock, flags);
- return;
-}
-
-void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
-{
- /* Voice interrupt */
- if (voicenum >= 32)
- sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
- else
- sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
-
- return;
-}
-
-static void sblive_wcwait(struct emu10k1_card *card, u32 wait)
-{
- volatile unsigned uCount;
- u32 newtime = 0, curtime;
-
- curtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
- while (wait--) {
- uCount = 0;
- while (uCount++ < TIMEOUT) {
- newtime = emu10k1_readfn0(card, WC_SAMPLECOUNTER);
- if (newtime != curtime)
- break;
- }
-
- if (uCount >= TIMEOUT)
- break;
-
- curtime = newtime;
- }
-}
-
-u16 emu10k1_ac97_read(struct ac97_codec *codec, u8 reg)
-{
- struct emu10k1_card *card = codec->private_data;
- u16 data;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- outb(reg, card->iobase + AC97ADDRESS);
- data = inw(card->iobase + AC97DATA);
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return data;
-}
-
-void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value)
-{
- struct emu10k1_card *card = codec->private_data;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- outb(reg, card->iobase + AC97ADDRESS);
- outw(value, card->iobase + AC97DATA);
- outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/*********************************************************
-* MPU access functions *
-**********************************************************/
-
-int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
-{
- unsigned long flags;
- int ret;
-
- if (card->is_audigy) {
- if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) {
- sblive_writeptr(card, A_MUDATA, 0, data);
- ret = 0;
- } else
- ret = -1;
- } else {
- spin_lock_irqsave(&card->lock, flags);
-
- if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
- outb(data, card->iobase + MUDATA);
- ret = 0;
- } else
- ret = -1;
-
- spin_unlock_irqrestore(&card->lock, flags);
- }
-
- return ret;
-}
-
-int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
-{
- unsigned long flags;
- int ret;
-
- if (card->is_audigy) {
- if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) {
- *data = sblive_readptr(card, A_MUDATA,0);
- ret = 0;
- } else
- ret = -1;
- } else {
- spin_lock_irqsave(&card->lock, flags);
-
- if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
- *data = inb(card->iobase + MUDATA);
- ret = 0;
- } else
- ret = -1;
-
- spin_unlock_irqrestore(&card->lock, flags);
- }
-
- return ret;
-}
-
-int emu10k1_mpu_reset(struct emu10k1_card *card)
-{
- u8 status;
- unsigned long flags;
-
- DPF(2, "emu10k1_mpu_reset()\n");
- if (card->is_audigy) {
- if (card->mpuacqcount == 0) {
- sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
- sblive_wcwait(card, 8);
- sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
- sblive_wcwait(card, 8);
- sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE);
- sblive_wcwait(card, 8);
- status = sblive_readptr(card, A_MUDATA, 0);
- if (status == 0xfe)
- return 0;
- else
- return -1;
- }
-
- return 0;
- } else {
- if (card->mpuacqcount == 0) {
- spin_lock_irqsave(&card->lock, flags);
- outb(MUCMD_RESET, card->iobase + MUCMD);
- spin_unlock_irqrestore(&card->lock, flags);
-
- sblive_wcwait(card, 8);
-
- spin_lock_irqsave(&card->lock, flags);
- outb(MUCMD_RESET, card->iobase + MUCMD);
- spin_unlock_irqrestore(&card->lock, flags);
-
- sblive_wcwait(card, 8);
-
- spin_lock_irqsave(&card->lock, flags);
- outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
- spin_unlock_irqrestore(&card->lock, flags);
-
- sblive_wcwait(card, 8);
-
- spin_lock_irqsave(&card->lock, flags);
- status = inb(card->iobase + MUDATA);
- spin_unlock_irqrestore(&card->lock, flags);
-
- if (status == 0xfe)
- return 0;
- else
- return -1;
- }
-
- return 0;
- }
-}
-
-int emu10k1_mpu_acquire(struct emu10k1_card *card)
-{
- /* FIXME: This should be a macro */
- ++card->mpuacqcount;
-
- return 0;
-}
-
-int emu10k1_mpu_release(struct emu10k1_card *card)
-{
- /* FIXME: this should be a macro */
- --card->mpuacqcount;
-
- return 0;
-}
diff --git a/sound/oss/emu10k1/hwaccess.h b/sound/oss/emu10k1/hwaccess.h
deleted file mode 100644
index 85e27bda694b..000000000000
--- a/sound/oss/emu10k1/hwaccess.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- **********************************************************************
- * hwaccess.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _HWACCESS_H
-#define _HWACCESS_H
-
-#include <linux/fs.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <asm/io.h>
-
-#include "efxmgr.h"
-#include "passthrough.h"
-#include "midi.h"
-
-#define EMUPAGESIZE 4096 /* don't change */
-#define NUM_G 64 /* use all channels */
-#define NUM_FXSENDS 4 /* don't change */
-/* setting this to other than a power of two may break some applications */
-#define MAXBUFSIZE 65536
-#define MAXPAGES 8192
-#define BUFMAXPAGES (MAXBUFSIZE / PAGE_SIZE)
-
-#define FLAGS_AVAILABLE 0x0001
-#define FLAGS_READY 0x0002
-
-struct memhandle
-{
- dma_addr_t dma_handle;
- void *addr;
- u32 size;
-};
-
-#define DEBUG_LEVEL 2
-
-#ifdef EMU10K1_DEBUG
-# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0)
-# define DPF(level,x) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0)
-#else
-# define DPD(level,x,y...) do { } while (0) /* not debugging: nothing */
-# define DPF(level,x) do { } while (0)
-#endif /* EMU10K1_DEBUG */
-
-#define ERROR() DPF(1,"error\n")
-
-/* DATA STRUCTURES */
-
-struct emu10k1_waveout
-{
- u32 send_routing[3];
- // audigy only:
- u32 send_routing2[3];
-
- u32 send_dcba[3];
- // audigy only:
- u32 send_hgfe[3];
-};
-#define ROUTE_PCM 0
-#define ROUTE_PT 1
-#define ROUTE_PCM1 2
-
-#define SEND_MONO 0
-#define SEND_LEFT 1
-#define SEND_RIGHT 2
-
-struct emu10k1_wavein
-{
- struct wiinst *ac97;
- struct wiinst *mic;
- struct wiinst *fx;
-
- u8 recsrc;
- u32 fxwc;
-};
-
-#define CMD_READ 1
-#define CMD_WRITE 2
-
-struct mixer_private_ioctl {
- u32 cmd;
- u32 val[90];
-};
-
-/* bogus ioctls numbers to escape from OSS mixer limitations */
-#define CMD_WRITEFN0 _IOW('D', 0, struct mixer_private_ioctl)
-#define CMD_READFN0 _IOR('D', 1, struct mixer_private_ioctl)
-#define CMD_WRITEPTR _IOW('D', 2, struct mixer_private_ioctl)
-#define CMD_READPTR _IOR('D', 3, struct mixer_private_ioctl)
-#define CMD_SETRECSRC _IOW('D', 4, struct mixer_private_ioctl)
-#define CMD_GETRECSRC _IOR('D', 5, struct mixer_private_ioctl)
-#define CMD_GETVOICEPARAM _IOR('D', 6, struct mixer_private_ioctl)
-#define CMD_SETVOICEPARAM _IOW('D', 7, struct mixer_private_ioctl)
-#define CMD_GETPATCH _IOR('D', 8, struct mixer_private_ioctl)
-#define CMD_GETGPR _IOR('D', 9, struct mixer_private_ioctl)
-#define CMD_GETCTLGPR _IOR('D', 10, struct mixer_private_ioctl)
-#define CMD_SETPATCH _IOW('D', 11, struct mixer_private_ioctl)
-#define CMD_SETGPR _IOW('D', 12, struct mixer_private_ioctl)
-#define CMD_SETCTLGPR _IOW('D', 13, struct mixer_private_ioctl)
-#define CMD_SETGPOUT _IOW('D', 14, struct mixer_private_ioctl)
-#define CMD_GETGPR2OSS _IOR('D', 15, struct mixer_private_ioctl)
-#define CMD_SETGPR2OSS _IOW('D', 16, struct mixer_private_ioctl)
-#define CMD_SETMCH_FX _IOW('D', 17, struct mixer_private_ioctl)
-#define CMD_SETPASSTHROUGH _IOW('D', 18, struct mixer_private_ioctl)
-#define CMD_PRIVATE3_VERSION _IOW('D', 19, struct mixer_private_ioctl)
-#define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl)
-
-//up this number when breaking compatibility
-#define PRIVATE3_VERSION 2
-
-struct emu10k1_card
-{
- struct list_head list;
-
- struct memhandle virtualpagetable;
- struct memhandle tankmem;
- struct memhandle silentpage;
-
- spinlock_t lock;
-
- u8 voicetable[NUM_G];
- u16 emupagetable[MAXPAGES];
-
- struct list_head timers;
- u16 timer_delay;
- spinlock_t timer_lock;
-
- struct pci_dev *pci_dev;
- unsigned long iobase;
- unsigned long length;
- unsigned short model;
- unsigned int irq;
-
- int audio_dev;
- int audio_dev1;
- int midi_dev;
-#ifdef EMU10K1_SEQUENCER
- int seq_dev;
- struct emu10k1_mididevice *seq_mididev;
-#endif
-
- struct ac97_codec *ac97;
- int ac97_supported_mixers;
- int ac97_stereo_mixers;
-
- /* Number of first fx voice for multichannel output */
- u8 mchannel_fx;
- struct emu10k1_waveout waveout;
- struct emu10k1_wavein wavein;
- struct emu10k1_mpuout *mpuout;
- struct emu10k1_mpuin *mpuin;
-
- struct mutex open_sem;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- u32 mpuacqcount; // Mpu acquire count
- u32 has_toslink; // TOSLink detection
-
- u8 chiprev; /* Chip revision */
- u8 is_audigy;
- u8 is_aps;
-
- struct patch_manager mgr;
- struct pt_data pt;
-};
-
-int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
-void emu10k1_addxmgr_free(struct emu10k1_card *, int);
-
-int emu10k1_find_control_gpr(struct patch_manager *, const char *, const char *);
-void emu10k1_set_control_gpr(struct emu10k1_card *, int , s32, int );
-
-void emu10k1_set_volume_gpr(struct emu10k1_card *, int, s32, int);
-
-
-#define VOL_6BIT 0x40
-#define VOL_5BIT 0x20
-#define VOL_4BIT 0x10
-
-#define TIMEOUT 16384
-
-u32 srToPitch(u32);
-
-extern struct list_head emu10k1_devs;
-
-/* Hardware Abstraction Layer access functions */
-
-void emu10k1_writefn0(struct emu10k1_card *, u32, u32);
-void emu10k1_writefn0_2(struct emu10k1_card *, u32, u32, int);
-u32 emu10k1_readfn0(struct emu10k1_card *, u32);
-
-void emu10k1_timer_set(struct emu10k1_card *, u16);
-
-void sblive_writeptr(struct emu10k1_card *, u32, u32, u32);
-void sblive_writeptr_tag(struct emu10k1_card *, u32, ...);
-#define TAGLIST_END 0
-
-u32 sblive_readptr(struct emu10k1_card *, u32 , u32 );
-
-void emu10k1_irq_enable(struct emu10k1_card *, u32);
-void emu10k1_irq_disable(struct emu10k1_card *, u32);
-void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32);
-
-/* AC97 Codec register access function */
-u16 emu10k1_ac97_read(struct ac97_codec *, u8);
-void emu10k1_ac97_write(struct ac97_codec *, u8, u16);
-
-/* MPU access function*/
-int emu10k1_mpu_write_data(struct emu10k1_card *, u8);
-int emu10k1_mpu_read_data(struct emu10k1_card *, u8 *);
-int emu10k1_mpu_reset(struct emu10k1_card *);
-int emu10k1_mpu_acquire(struct emu10k1_card *);
-int emu10k1_mpu_release(struct emu10k1_card *);
-
-#endif /* _HWACCESS_H */
diff --git a/sound/oss/emu10k1/icardmid.h b/sound/oss/emu10k1/icardmid.h
deleted file mode 100644
index 6a6ef419401f..000000000000
--- a/sound/oss/emu10k1/icardmid.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- **********************************************************************
- * isblive_mid.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _ICARDMIDI_H
-#define _ICARDMIDI_H
-
-/* MIDI defines */
-#define MIDI_DATA_FIRST 0x00
-#define MIDI_DATA_LAST 0x7F
-#define MIDI_STATUS_FIRST 0x80
-#define MIDI_STATUS_LAST 0xFF
-
-/* Channel status bytes */
-#define MIDI_STATUS_CHANNEL_FIRST 0x80
-#define MIDI_STATUS_CHANNEL_LAST 0xE0
-#define MIDI_STATUS_CHANNEL_MASK 0xF0
-
-/* Channel voice messages */
-#define MIDI_VOICE_NOTE_OFF 0x80
-#define MIDI_VOICE_NOTE_ON 0x90
-#define MIDI_VOICE_POLY_PRESSURE 0xA0
-#define MIDI_VOICE_CONTROL_CHANGE 0xB0
-#define MIDI_VOICE_PROGRAM_CHANGE 0xC0
-#define MIDI_VOICE_CHANNEL_PRESSURE 0xD0
-#define MIDI_VOICE_PITCH_BEND 0xE0
-
-/* Channel mode messages */
-#define MIDI_MODE_CHANNEL MIDI_VOICE_CONTROL_CHANGE
-
-/* System status bytes */
-#define MIDI_STATUS_SYSTEM_FIRST 0xF0
-#define MIDI_STATUS_SYSTEM_LAST 0xFF
-
-/* System exclusive messages */
-#define MIDI_SYSEX_BEGIN 0xF0
-#define MIDI_SYSEX_EOX 0xF7
-
-/* System common messages */
-#define MIDI_COMMON_TCQF 0xF1 /* Time code quarter frame */
-#define MIDI_COMMON_SONG_POSITION 0xF2
-#define MIDI_COMMON_SONG_SELECT 0xF3
-#define MIDI_COMMON_UNDEFINED_F4 0xF4
-#define MIDI_COMMON_UNDEFINED_F5 0xF5
-#define MIDI_COMMON_TUNE_REQUEST 0xF6
-
-/* System real-time messages */
-#define MIDI_RTIME_TIMING_CLOCK 0xF8
-#define MIDI_RTIME_UNDEFINED_F9 0xF9
-#define MIDI_RTIME_START 0xFA
-#define MIDI_RTIME_CONTINUE 0xFB
-#define MIDI_RTIME_STOP 0xFC
-#define MIDI_RTIME_UNDEFINED_FD 0xFD
-#define MIDI_RTIME_ACTIVE_SENSING 0xFE
-#define MIDI_RTIME_SYSTEM_RESET 0xFF
-
-/* Flags for flags parm of midiOutCachePatches(), midiOutCacheDrumPatches() */
-#define MIDI_CACHE_ALL 1
-#define MIDI_CACHE_BESTFIT 2
-#define MIDI_CACHE_QUERY 3
-#define MIDI_UNCACHE 4
-
-/* Event declarations for MPU IRQ Callbacks */
-#define ICARDMIDI_INLONGDATA 0x00000001 /* MIM_LONGDATA */
-#define ICARDMIDI_INLONGERROR 0x00000002 /* MIM_LONGERROR */
-#define ICARDMIDI_OUTLONGDATA 0x00000004 /* MOM_DONE for MPU OUT buffer */
-#define ICARDMIDI_INDATA 0x00000010 /* MIM_DATA */
-#define ICARDMIDI_INDATAERROR 0x00000020 /* MIM_ERROR */
-
-/* Declaration for flags in CARDMIDIBUFFERHDR */
-/* Make it the same as MHDR_DONE, MHDR_INQUEUE in mmsystem.h */
-#define MIDIBUF_DONE 0x00000001
-#define MIDIBUF_INQUEUE 0x00000004
-
-/* Declaration for msg parameter in midiCallbackFn */
-#define ICARDMIDI_OUTBUFFEROK 0x00000001
-#define ICARDMIDI_INMIDIOK 0x00000002
-
-/* Declaration for technology in struct midi_caps */
-#define MT_MIDIPORT 0x00000001 /* In original MIDIOUTCAPS structure */
-#define MT_FMSYNTH 0x00000004 /* In original MIDIOUTCAPS structure */
-#define MT_AWESYNTH 0x00001000
-#define MT_PCISYNTH 0x00002000
-#define MT_PCISYNTH64 0x00004000
-#define CARDMIDI_AWEMASK 0x0000F000
-
-enum LocalErrorCode
-{
- CTSTATUS_NOTENABLED = 0x7000,
- CTSTATUS_READY,
- CTSTATUS_BUSY,
- CTSTATUS_DATAAVAIL,
- CTSTATUS_NODATA,
- CTSTATUS_NEXT_BYTE
-};
-
-/* MIDI data block header */
-struct midi_hdr
-{
- u8 *reserved; /* Pointer to original locked data block */
- u32 bufferlength; /* Length of data in data block */
- u32 bytesrecorded; /* Used for input only */
- u32 user; /* For client's use */
- u32 flags; /* Assorted flags (see defines) */
- struct list_head list; /* Reserved for driver */
- u8 *data; /* Second copy of first pointer */
-};
-
-/* Enumeration for SetControl */
-enum
-{
- MIDIOBJVOLUME = 0x1,
- MIDIQUERYACTIVEINST
-};
-
-struct midi_queue
-{
- struct midi_queue *next;
- u32 qtype; /* 0 = short message, 1 = long data */
- u32 length;
- u32 sizeLeft;
- u8 *midibyte;
- unsigned long refdata;
-};
-
-struct midi_openinfo
-{
- u32 cbsize;
- u32 flags;
- unsigned long refdata;
- u32 streamid;
-};
-
-int emu10k1_midi_callback(unsigned long , unsigned long, unsigned long *);
-
-#endif /* _ICARDMIDI_H */
diff --git a/sound/oss/emu10k1/icardwav.h b/sound/oss/emu10k1/icardwav.h
deleted file mode 100644
index 25be40928b4d..000000000000
--- a/sound/oss/emu10k1/icardwav.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- **********************************************************************
- * icardwav.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _ICARDWAV_H
-#define _ICARDWAV_H
-
-struct wave_format
-{
- int id;
- int samplingrate;
- u8 bitsperchannel;
- u8 channels; /* 1 = Mono, 2 = Stereo, 3, ... = Multichannel */
- u8 bytesperchannel;
- u8 bytespervoicesample;
- u8 bytespersample;
- int bytespersec;
- u8 passthrough;
-};
-
-/* emu10k1_wave states */
-#define WAVE_STATE_OPEN 0x01
-#define WAVE_STATE_STARTED 0x02
-#define WAVE_STATE_CLOSED 0x04
-
-#endif /* _ICARDWAV_H */
diff --git a/sound/oss/emu10k1/irqmgr.c b/sound/oss/emu10k1/irqmgr.c
deleted file mode 100644
index fb2ce638f01c..000000000000
--- a/sound/oss/emu10k1/irqmgr.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- **********************************************************************
- * irqmgr.c - IRQ manager for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 "hwaccess.h"
-#include "8010.h"
-#include "cardmi.h"
-#include "cardmo.h"
-#include "irqmgr.h"
-
-/* Interrupt handler */
-
-irqreturn_t emu10k1_interrupt(int irq, void *dev_id)
-{
- struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
- u32 irqstatus, irqstatus_tmp;
- int handled = 0;
-
- DPD(4, "emu10k1_interrupt called, irq = %u\n", irq);
-
- /*
- ** NOTE :
- ** We do a 'while loop' here cos on certain machines, with both
- ** playback and recording going on at the same time, IRQs will
- ** stop coming in after a while. Checking IPND indeed shows that
- ** there are interrupts pending but the PIC says no IRQs pending.
- ** I suspect that some boards need edge-triggered IRQs but are not
- ** getting that condition if we don't completely clear the IPND
- ** (make sure no more interrupts are pending).
- ** - Eric
- */
-
- while ((irqstatus = inl(card->iobase + IPR))) {
- DPD(4, "irq status %#x\n", irqstatus);
-
- irqstatus_tmp = irqstatus;
-
- if (irqstatus & IRQTYPE_TIMER) {
- emu10k1_timer_irqhandler(card);
- irqstatus &= ~IRQTYPE_TIMER;
- }
-
- if (irqstatus & IRQTYPE_DSP) {
- emu10k1_dsp_irqhandler(card);
- irqstatus &= ~IRQTYPE_DSP;
- }
-
- if (irqstatus & IRQTYPE_MPUIN) {
- emu10k1_mpuin_irqhandler(card);
- irqstatus &= ~IRQTYPE_MPUIN;
- }
-
- if (irqstatus & IRQTYPE_MPUOUT) {
- emu10k1_mpuout_irqhandler(card);
- irqstatus &= ~IRQTYPE_MPUOUT;
- }
-
- if (irqstatus & IPR_MUTE) {
- emu10k1_mute_irqhandler(card);
- irqstatus &=~IPR_MUTE;
- }
-
- if (irqstatus & IPR_VOLINCR) {
- emu10k1_volincr_irqhandler(card);
- irqstatus &=~IPR_VOLINCR;
- }
-
- if (irqstatus & IPR_VOLDECR) {
- emu10k1_voldecr_irqhandler(card);
- irqstatus &=~IPR_VOLDECR;
- }
-
- if (irqstatus){
- printk(KERN_ERR "emu10k1: Warning, unhandled interrupt: %#08x\n", irqstatus);
- //make sure any interrupts we don't handle are disabled:
- emu10k1_irq_disable(card, ~(INTE_MIDIRXENABLE | INTE_MIDITXENABLE | INTE_INTERVALTIMERENB |
- INTE_VOLDECRENABLE | INTE_VOLINCRENABLE | INTE_MUTEENABLE |
- INTE_FXDSPENABLE));
- }
-
- /* acknowledge interrupt */
- outl(irqstatus_tmp, card->iobase + IPR);
- handled = 1;
- }
- return IRQ_RETVAL(handled);
-}
diff --git a/sound/oss/emu10k1/irqmgr.h b/sound/oss/emu10k1/irqmgr.h
deleted file mode 100644
index 7e7c9ca1098c..000000000000
--- a/sound/oss/emu10k1/irqmgr.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- **********************************************************************
- * irq.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _IRQ_H
-#define _IRQ_H
-
-/* EMU Irq Types */
-#define IRQTYPE_PCIBUSERROR IPR_PCIERROR
-#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
-#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
-#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
-#define IRQTYPE_MPUOUT (IPR_MIDITRANSBUFEMPTY | A_IPR_MIDITRANSBUFEMPTY2)
-#define IRQTYPE_MPUIN (IPR_MIDIRECVBUFEMPTY | A_IPR_MIDIRECVBUFEMPTY2)
-#define IRQTYPE_TIMER IPR_INTERVALTIMER
-#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
-#define IRQTYPE_DSP IPR_FXDSP
-
-void emu10k1_timer_irqhandler(struct emu10k1_card *);
-void emu10k1_dsp_irqhandler(struct emu10k1_card *);
-void emu10k1_mute_irqhandler(struct emu10k1_card *);
-void emu10k1_volincr_irqhandler(struct emu10k1_card *);
-void emu10k1_voldecr_irqhandler(struct emu10k1_card *);
-
-#endif /* _IRQ_H */
diff --git a/sound/oss/emu10k1/main.c b/sound/oss/emu10k1/main.c
deleted file mode 100644
index 16ac02540a3f..000000000000
--- a/sound/oss/emu10k1/main.c
+++ /dev/null
@@ -1,1471 +0,0 @@
- /*
- **********************************************************************
- * main.c - Creative EMU10K1 audio driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up stuff
- *
- **********************************************************************
- *
- * 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.
- *
- **********************************************************************
- *
- * Supported devices:
- * /dev/dsp: Standard /dev/dsp device, OSS-compatible
- * /dev/dsp1: Routes to rear speakers only
- * /dev/mixer: Standard /dev/mixer device, OSS-compatible
- * /dev/midi: Raw MIDI UART device, mostly OSS-compatible
- * /dev/sequencer: Sequencer Interface (requires sound.o)
- *
- * Revision history:
- * 0.1 beta Initial release
- * 0.2 Lowered initial mixer vol. Improved on stuttering wave playback. Added MIDI UART support.
- * 0.3 Fixed mixer routing bug, added APS, joystick support.
- * 0.4 Added rear-channel, SPDIF support.
- * 0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes,
- * moved bh's to tasklets, moved to the new PCI driver initialization style.
- * 0.6 Make use of pci_alloc_consistent, improve compatibility layer for 2.2 kernels,
- * code reorganization and cleanup.
- * 0.7 Support for the Emu-APS. Bug fixes for voice cache setup, mmaped sound + poll().
- * Support for setting external TRAM size.
- * 0.8 Make use of the kernel ac97 interface. Support for a dsp patch manager.
- * 0.9 Re-enables rear speakers volume controls
- * 0.10 Initializes rear speaker volume.
- * Dynamic patch storage allocation.
- * New private ioctls to change control gpr values.
- * Enable volume control interrupts.
- * By default enable dsp routes to digital out.
- * 0.11 Fixed fx / 4 problem.
- * 0.12 Implemented mmaped for recording.
- * Fixed bug: not unreserving mmaped buffer pages.
- * IRQ handler cleanup.
- * 0.13 Fixed problem with dsp1
- * Simplified dsp patch writing (inside the driver)
- * Fixed several bugs found by the Stanford tools
- * 0.14 New control gpr to oss mixer mapping feature (Chris Purnell)
- * Added AC3 Passthrough Support (Juha Yrjola)
- * Added Support for 5.1 cards (digital out and the third analog out)
- * 0.15 Added Sequencer Support (Daniel Mack)
- * Support for multichannel pcm playback (Eduard Hasenleithner)
- * 0.16 Mixer improvements, added old treble/bass support (Daniel Bertrand)
- * Small code format cleanup.
- * Deadlock bug fix for emu10k1_volxxx_irqhandler().
- * 0.17 Fix for mixer SOUND_MIXER_INFO ioctl.
- * Fix for HIGHMEM machines (emu10k1 can only do 31 bit bus master)
- * midi poll initial implementation.
- * Small mixer fixes/cleanups.
- * Improved support for 5.1 cards.
- * 0.18 Fix for possible leak in pci_alloc_consistent()
- * Cleaned up poll() functions (audio and midi). Don't start input.
- * Restrict DMA pages used to 512Mib range.
- * New AC97_BOOST mixer ioctl.
- * 0.19a Added Support for Audigy Cards
- * Real fix for kernel with highmem support (cast dma_handle to u32).
- * Fix recording buffering parameters calculation.
- * Use unsigned long for variables in bit ops.
- * 0.20a Fixed recording startup
- * Fixed timer rate setting (it's a 16-bit register)
- * 0.21 Converted code to use pci_name() instead of accessing slot_name
- * directly (Eugene Teo)
- *********************************************************************/
-
-/* These are only included once per module */
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/dma-mapping.h>
-
-#include "hwaccess.h"
-#include "8010.h"
-#include "efxmgr.h"
-#include "cardwo.h"
-#include "cardwi.h"
-#include "cardmo.h"
-#include "cardmi.h"
-#include "recmgr.h"
-#include "ecard.h"
-
-
-#ifdef EMU10K1_SEQUENCER
-#define MIDI_SYNTH_NAME "EMU10K1 MIDI"
-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-
-#include "../sound_config.h"
-#include "../midi_synth.h"
-
-/* this should be in dev_table.h */
-#define SNDCARD_EMU10K1 46
-#endif
-
-
-/* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */
-#define EMU10K1_DMA_MASK DMA_29BIT_MASK /* DMA buffer mask for pci_alloc_consist */
-
-#ifndef PCI_VENDOR_ID_CREATIVE
-#define PCI_VENDOR_ID_CREATIVE 0x1102
-#endif
-
-#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1
-#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
-#endif
-#ifndef PCI_DEVICE_ID_CREATIVE_AUDIGY
-#define PCI_DEVICE_ID_CREATIVE_AUDIGY 0x0004
-#endif
-
-#define EMU_APS_SUBID 0x40011102
-
-enum {
- EMU10K1 = 0,
- AUDIGY,
-};
-
-static char *card_names[] __devinitdata = {
- "EMU10K1",
- "Audigy",
-};
-
-static struct pci_device_id emu10k1_pci_tbl[] = {
- {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1},
- {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_AUDIGY,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, AUDIGY},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, emu10k1_pci_tbl);
-
-/* Global var instantiation */
-
-LIST_HEAD(emu10k1_devs);
-
-extern struct file_operations emu10k1_audio_fops;
-extern struct file_operations emu10k1_mixer_fops;
-extern struct file_operations emu10k1_midi_fops;
-
-#ifdef EMU10K1_SEQUENCER
-static struct midi_operations emu10k1_midi_operations;
-#endif
-
-extern irqreturn_t emu10k1_interrupt(int, void *);
-
-static int __devinit emu10k1_audio_init(struct emu10k1_card *card)
-{
- /* Assign default playback voice parameters */
- if (card->is_audigy)
- card->mchannel_fx = 0;
- else
- card->mchannel_fx = 8;
-
-
- if (card->is_audigy) {
- /* mono voice */
- card->waveout.send_dcba[SEND_MONO] = 0xffffffff;
- card->waveout.send_hgfe[SEND_MONO] = 0x0000ffff;
-
- /* stereo voice */
- /* left */
- card->waveout.send_dcba[SEND_LEFT] = 0x00ff00ff;
- card->waveout.send_hgfe[SEND_LEFT] = 0x00007f7f;
- /* right */
- card->waveout.send_dcba[SEND_RIGHT] = 0xff00ff00;
- card->waveout.send_hgfe[SEND_RIGHT] = 0x00007f7f;
-
- card->waveout.send_routing[ROUTE_PCM] = 0x03020100; // Regular pcm
- card->waveout.send_routing2[ROUTE_PCM] = 0x07060504;
-
- card->waveout.send_routing[ROUTE_PT] = 0x3f3f3d3c; // Passthrough
- card->waveout.send_routing2[ROUTE_PT] = 0x3f3f3f3f;
-
- card->waveout.send_routing[ROUTE_PCM1] = 0x03020100; // Spare
- card->waveout.send_routing2[ROUTE_PCM1] = 0x07060404;
-
- } else {
- /* mono voice */
- card->waveout.send_dcba[SEND_MONO] = 0x0000ffff;
-
- /* stereo voice */
- /* left */
- card->waveout.send_dcba[SEND_LEFT] = 0x000000ff;
- /* right */
- card->waveout.send_dcba[SEND_RIGHT] = 0x0000ff00;
-
- card->waveout.send_routing[ROUTE_PCM] = 0x3210; // pcm
- card->waveout.send_routing[ROUTE_PT] = 0x3210; // passthrough
- card->waveout.send_routing[ROUTE_PCM1] = 0x7654; // /dev/dsp1
- }
-
- /* Assign default recording parameters */
- /* FIXME */
- if (card->is_aps)
- card->wavein.recsrc = WAVERECORD_FX;
- else
- card->wavein.recsrc = WAVERECORD_AC97;
-
- card->wavein.fxwc = 0x0003;
- return 0;
-}
-
-static void emu10k1_audio_cleanup(struct emu10k1_card *card)
-{
-}
-
-static int __devinit emu10k1_register_devices(struct emu10k1_card *card)
-{
- card->audio_dev = register_sound_dsp(&emu10k1_audio_fops, -1);
- if (card->audio_dev < 0) {
- printk(KERN_ERR "emu10k1: cannot register first audio device!\n");
- goto err_dev;
- }
-
- card->audio_dev1 = register_sound_dsp(&emu10k1_audio_fops, -1);
- if (card->audio_dev1 < 0) {
- printk(KERN_ERR "emu10k1: cannot register second audio device!\n");
- goto err_dev1;
- }
-
- card->ac97->dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1);
- if (card->ac97->dev_mixer < 0) {
- printk(KERN_ERR "emu10k1: cannot register mixer device\n");
- goto err_mixer;
- }
-
- card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1);
- if (card->midi_dev < 0) {
- printk(KERN_ERR "emu10k1: cannot register midi device!\n");
- goto err_midi;
- }
-
-#ifdef EMU10K1_SEQUENCER
- card->seq_dev = sound_alloc_mididev();
- if (card->seq_dev == -1)
- printk(KERN_WARNING "emu10k1: unable to register sequencer device!");
- else {
- std_midi_synth.midi_dev = card->seq_dev;
- midi_devs[card->seq_dev] =
- (struct midi_operations *)
- kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
-
- if (midi_devs[card->seq_dev] == NULL) {
- printk(KERN_ERR "emu10k1: unable to allocate memory!");
- sound_unload_mididev(card->seq_dev);
- card->seq_dev = -1;
- /* return without error */
- } else {
- memcpy((char *)midi_devs[card->seq_dev],
- (char *)&emu10k1_midi_operations,
- sizeof(struct midi_operations));
- midi_devs[card->seq_dev]->devc = card;
- sequencer_init();
- card->seq_mididev = NULL;
- }
- }
-#endif
- return 0;
-
-err_midi:
- unregister_sound_mixer(card->ac97->dev_mixer);
-err_mixer:
- unregister_sound_dsp(card->audio_dev);
-err_dev1:
- unregister_sound_dsp(card->audio_dev);
-err_dev:
- return -ENODEV;
-}
-
-static void emu10k1_unregister_devices(struct emu10k1_card *card)
-{
-#ifdef EMU10K1_SEQUENCER
- if (card->seq_dev > -1) {
- kfree(midi_devs[card->seq_dev]);
- midi_devs[card->seq_dev] = NULL;
- sound_unload_mididev(card->seq_dev);
- card->seq_dev = -1;
- }
-#endif
-
- unregister_sound_midi(card->midi_dev);
- unregister_sound_mixer(card->ac97->dev_mixer);
- unregister_sound_dsp(card->audio_dev1);
- unregister_sound_dsp(card->audio_dev);
-}
-
-static int emu10k1_info_proc (char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- struct emu10k1_card *card = data;
- int len = 0;
-
- if (card == NULL)
- return -ENODEV;
-
- len += sprintf (page + len, "Driver Version : %s\n", DRIVER_VERSION);
- len += sprintf (page + len, "Card type : %s\n", card->is_aps ? "Aps" : (card->is_audigy ? "Audigy" : "Emu10k1"));
- len += sprintf (page + len, "Revision : %d\n", card->chiprev);
- len += sprintf (page + len, "Model : %#06x\n", card->model);
- len += sprintf (page + len, "IO : %#06lx-%#06lx\n", card->iobase, card->iobase + card->length - 1);
- len += sprintf (page + len, "IRQ : %d\n\n", card->irq);
-
- len += sprintf (page + len, "Registered /dev Entries:\n");
- len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev / 16);
- len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev1 / 16);
- len += sprintf (page + len, "/dev/mixer%d\n", card->ac97->dev_mixer / 16);
- len += sprintf (page + len, "/dev/midi%d\n", card->midi_dev / 16);
-
-#ifdef EMU10K1_SEQUENCER
- len += sprintf (page + len, "/dev/sequencer\n");
-#endif
-
- return len;
-}
-
-static int __devinit emu10k1_proc_init(struct emu10k1_card *card)
-{
- char s[48];
-
- if (!proc_mkdir ("driver/emu10k1", NULL)) {
- printk(KERN_ERR "emu10k1: unable to create proc directory driver/emu10k1\n");
- goto err_out;
- }
-
- sprintf(s, "driver/emu10k1/%s", pci_name(card->pci_dev));
- if (!proc_mkdir (s, NULL)) {
- printk(KERN_ERR "emu10k1: unable to create proc directory %s\n", s);
- goto err_emu10k1_proc;
- }
-
- sprintf(s, "driver/emu10k1/%s/info", pci_name(card->pci_dev));
- if (!create_proc_read_entry (s, 0, NULL, emu10k1_info_proc, card)) {
- printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s);
- goto err_dev_proc;
- }
-
- if (!card->is_aps) {
- sprintf(s, "driver/emu10k1/%s/ac97", pci_name(card->pci_dev));
- if (!create_proc_read_entry (s, 0, NULL, ac97_read_proc, card->ac97)) {
- printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s);
- goto err_proc_ac97;
- }
- }
-
- return 0;
-
-err_proc_ac97:
- sprintf(s, "driver/emu10k1/%s/info", pci_name(card->pci_dev));
- remove_proc_entry(s, NULL);
-
-err_dev_proc:
- sprintf(s, "driver/emu10k1/%s", pci_name(card->pci_dev));
- remove_proc_entry(s, NULL);
-
-err_emu10k1_proc:
- remove_proc_entry("driver/emu10k1", NULL);
-
-err_out:
- return -EIO;
-}
-
-static void emu10k1_proc_cleanup(struct emu10k1_card *card)
-{
- char s[48];
-
- if (!card->is_aps) {
- sprintf(s, "driver/emu10k1/%s/ac97", pci_name(card->pci_dev));
- remove_proc_entry(s, NULL);
- }
-
- sprintf(s, "driver/emu10k1/%s/info", pci_name(card->pci_dev));
- remove_proc_entry(s, NULL);
-
- sprintf(s, "driver/emu10k1/%s", pci_name(card->pci_dev));
- remove_proc_entry(s, NULL);
-
- remove_proc_entry("driver/emu10k1", NULL);
-}
-
-static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
-{
- struct ac97_codec *codec = ac97_alloc_codec();
-
- if(codec == NULL)
- {
- printk(KERN_ERR "emu10k1: cannot allocate mixer\n");
- return -EIO;
- }
- card->ac97 = codec;
- card->ac97->private_data = card;
-
- if (!card->is_aps) {
- card->ac97->id = 0;
- card->ac97->codec_read = emu10k1_ac97_read;
- card->ac97->codec_write = emu10k1_ac97_write;
-
- if (ac97_probe_codec (card->ac97) == 0) {
- printk(KERN_ERR "emu10k1: unable to probe AC97 codec\n");
- goto err_out;
- }
- /* 5.1: Enable the additional AC97 Slots and unmute extra channels on AC97 codec */
- if (codec->codec_read(codec, AC97_EXTENDED_ID) & 0x0080){
- printk(KERN_INFO "emu10k1: SBLive! 5.1 card detected\n");
- sblive_writeptr(card, AC97SLOT, 0, AC97SLOT_CNTR | AC97SLOT_LFE);
- codec->codec_write(codec, AC97_SURROUND_MASTER, 0x0);
- }
-
- // Force 5bit:
- //card->ac97->bit_resolution=5;
-
- /* these will store the original values and never be modified */
- card->ac97_supported_mixers = card->ac97->supported_mixers;
- card->ac97_stereo_mixers = card->ac97->stereo_mixers;
- }
-
- return 0;
-
- err_out:
- ac97_release_codec(card->ac97);
- return -EIO;
-}
-
-static void emu10k1_mixer_cleanup(struct emu10k1_card *card)
-{
- ac97_release_codec(card->ac97);
-}
-
-static int __devinit emu10k1_midi_init(struct emu10k1_card *card)
-{
- int ret;
-
- card->mpuout = kzalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL);
- if (card->mpuout == NULL) {
- printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n");
- ret = -ENOMEM;
- goto err_out1;
- }
-
- card->mpuout->intr = 1;
- card->mpuout->status = FLAGS_AVAILABLE;
- card->mpuout->state = CARDMIDIOUT_STATE_DEFAULT;
-
- tasklet_init(&card->mpuout->tasklet, emu10k1_mpuout_bh, (unsigned long) card);
-
- spin_lock_init(&card->mpuout->lock);
-
- card->mpuin = kzalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL);
- if (card->mpuin == NULL) {
- printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n");
- ret = -ENOMEM;
- goto err_out2;
- }
-
- card->mpuin->status = FLAGS_AVAILABLE;
-
- tasklet_init(&card->mpuin->tasklet, emu10k1_mpuin_bh, (unsigned long) card->mpuin);
-
- spin_lock_init(&card->mpuin->lock);
-
- /* Reset the MPU port */
- if (emu10k1_mpu_reset(card) < 0) {
- ERROR();
- ret = -EIO;
- goto err_out3;
- }
-
- return 0;
-
-err_out3:
- kfree(card->mpuin);
-err_out2:
- kfree(card->mpuout);
-err_out1:
- return ret;
-}
-
-static void emu10k1_midi_cleanup(struct emu10k1_card *card)
-{
- tasklet_kill(&card->mpuout->tasklet);
- kfree(card->mpuout);
-
- tasklet_kill(&card->mpuin->tasklet);
- kfree(card->mpuin);
-}
-
-static void __devinit voice_init(struct emu10k1_card *card)
-{
- int i;
-
- for (i = 0; i < NUM_G; i++)
- card->voicetable[i] = VOICE_USAGE_FREE;
-}
-
-static void __devinit timer_init(struct emu10k1_card *card)
-{
- INIT_LIST_HEAD(&card->timers);
- card->timer_delay = TIMER_STOPPED;
- spin_lock_init(&card->timer_lock);
-}
-
-static void __devinit addxmgr_init(struct emu10k1_card *card)
-{
- u32 count;
-
- for (count = 0; count < MAXPAGES; count++)
- card->emupagetable[count] = 0;
-
- /* Mark first page as used */
- /* This page is reserved by the driver */
- card->emupagetable[0] = 0x8001;
- card->emupagetable[1] = MAXPAGES - 1;
-}
-
-static void fx_cleanup(struct patch_manager *mgr)
-{
- int i;
- for(i = 0; i < mgr->current_pages; i++)
- free_page((unsigned long) mgr->patch[i]);
-}
-
-static int __devinit fx_init(struct emu10k1_card *card)
-{
- struct patch_manager *mgr = &card->mgr;
- struct dsp_patch *patch;
- struct dsp_rpatch *rpatch;
- s32 left, right;
- int i;
- u32 pc = 0;
- u32 patch_n=0;
- struct emu_efx_info_t emu_efx_info[2]=
- {{ 20, 10, 0x400, 0x100, 0x20 },
- { 24, 12, 0x600, 0x400, 0x60 },
- };
-
-
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- mgr->ctrl_gpr[i][0] = -1;
- mgr->ctrl_gpr[i][1] = -1;
- }
-
-
- if (card->is_audigy)
- mgr->current_pages = (2 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE;
- else
- /* !! The number below must equal the number of patches, currently 11 !! */
- mgr->current_pages = (11 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE;
-
- for (i = 0; i < mgr->current_pages; i++) {
- mgr->patch[i] = (void *)__get_free_page(GFP_KERNEL);
- if (mgr->patch[i] == NULL) {
- mgr->current_pages = i;
- fx_cleanup(mgr);
- return -ENOMEM;
- }
- memset(mgr->patch[i], 0, PAGE_SIZE);
- }
-
- if (card->is_audigy) {
- for (i = 0; i < 1024; i++)
- OP(0xf, 0x0c0, 0x0c0, 0x0cf, 0x0c0);
-
- for (i = 0; i < 512 ; i++)
- sblive_writeptr(card, A_GPR_BASE+i,0,0);
-
- pc=0;
-
- //Pcm input volume
- OP(0, 0x402, 0x0c0, 0x406, 0x000);
- OP(0, 0x403, 0x0c0, 0x407, 0x001);
-
- //CD-Digital input Volume
- OP(0, 0x404, 0x0c0, 0x40d, 0x42);
- OP(0, 0x405, 0x0c0, 0x40f, 0x43);
-
- // CD + PCM
- OP(6, 0x400, 0x0c0, 0x402, 0x404);
- OP(6, 0x401, 0x0c0, 0x403, 0x405);
-
- // Front Output + Master Volume
- OP(0, 0x68, 0x0c0, 0x408, 0x400);
- OP(0, 0x69, 0x0c0, 0x409, 0x401);
-
- // Add-in analog inputs for other speakers
- OP(6, 0x400, 0x40, 0x400, 0xc0);
- OP(6, 0x401, 0x41, 0x401, 0xc0);
-
- // Digital Front + Master Volume
- OP(0, 0x60, 0x0c0, 0x408, 0x400);
- OP(0, 0x61, 0x0c0, 0x409, 0x401);
-
- // Rear Output + Rear Volume
- OP(0, 0x06e, 0x0c0, 0x419, 0x400);
- OP(0, 0x06f, 0x0c0, 0x41a, 0x401);
-
- // Digital Rear Output + Rear Volume
- OP(0, 0x066, 0x0c0, 0x419, 0x400);
- OP(0, 0x067, 0x0c0, 0x41a, 0x401);
-
- // Audigy Drive, Headphone out
- OP(6, 0x64, 0x0c0, 0x0c0, 0x400);
- OP(6, 0x65, 0x0c0, 0x0c0, 0x401);
-
- // ac97 Recording
- OP(6, 0x76, 0x0c0, 0x0c0, 0x40);
- OP(6, 0x77, 0x0c0, 0x0c0, 0x41);
-
- // Center = sub = Left/2 + Right/2
- OP(0xe, 0x400, 0x401, 0xcd, 0x400);
-
- // center/sub Volume (master)
- OP(0, 0x06a, 0x0c0, 0x408, 0x400);
- OP(0, 0x06b, 0x0c0, 0x409, 0x400);
-
- // Digital center/sub Volume (master)
- OP(0, 0x062, 0x0c0, 0x408, 0x400);
- OP(0, 0x063, 0x0c0, 0x409, 0x400);
-
- ROUTING_PATCH_START(rpatch, "Routing");
- ROUTING_PATCH_END(rpatch);
-
- /* delimiter patch */
- patch = PATCH(mgr, patch_n);
- patch->code_size = 0;
-
-
- sblive_writeptr(card, 0x53, 0, 0);
- } else {
- for (i = 0; i < 512 ; i++)
- OP(6, 0x40, 0x40, 0x40, 0x40);
-
- for (i = 0; i < 256; i++)
- sblive_writeptr_tag(card, 0,
- FXGPREGBASE + i, 0,
- TANKMEMADDRREGBASE + i, 0,
- TAGLIST_END);
-
-
- pc = 0;
-
- //first free GPR = 0x11b
-
-
- /* FX volume correction and Volume control*/
- INPUT_PATCH_START(patch, "Pcm L vol", 0x0, 0);
- GET_OUTPUT_GPR(patch, 0x100, 0x0);
- GET_CONTROL_GPR(patch, 0x106, "Vol", 0, 0x7fffffff);
- GET_DYNAMIC_GPR(patch, 0x112);
-
- OP(4, 0x112, 0x40, PCM_IN_L, 0x44); //*4
- OP(0, 0x100, 0x040, 0x112, 0x106); //*vol
- INPUT_PATCH_END(patch);
-
-
- INPUT_PATCH_START(patch, "Pcm R vol", 0x1, 0);
- GET_OUTPUT_GPR(patch, 0x101, 0x1);
- GET_CONTROL_GPR(patch, 0x107, "Vol", 0, 0x7fffffff);
- GET_DYNAMIC_GPR(patch, 0x112);
-
- OP(4, 0x112, 0x40, PCM_IN_R, 0x44);
- OP(0, 0x101, 0x040, 0x112, 0x107);
-
- INPUT_PATCH_END(patch);
-
-
- // CD-Digital In Volume control
- INPUT_PATCH_START(patch, "CD-Digital Vol L", 0x12, 0);
- GET_OUTPUT_GPR(patch, 0x10c, 0x12);
- GET_CONTROL_GPR(patch, 0x10d, "Vol", 0, 0x7fffffff);
-
- OP(0, 0x10c, 0x040, SPDIF_CD_L, 0x10d);
- INPUT_PATCH_END(patch);
-
- INPUT_PATCH_START(patch, "CD-Digital Vol R", 0x13, 0);
- GET_OUTPUT_GPR(patch, 0x10e, 0x13);
- GET_CONTROL_GPR(patch, 0x10f, "Vol", 0, 0x7fffffff);
-
- OP(0, 0x10e, 0x040, SPDIF_CD_R, 0x10f);
- INPUT_PATCH_END(patch);
-
- //Volume Correction for Multi-channel Inputs
- INPUT_PATCH_START(patch, "Multi-Channel Gain", 0x08, 0);
- patch->input=patch->output=0x3F00;
-
- GET_OUTPUT_GPR(patch, 0x113, MULTI_FRONT_L);
- GET_OUTPUT_GPR(patch, 0x114, MULTI_FRONT_R);
- GET_OUTPUT_GPR(patch, 0x115, MULTI_REAR_L);
- GET_OUTPUT_GPR(patch, 0x116, MULTI_REAR_R);
- GET_OUTPUT_GPR(patch, 0x117, MULTI_CENTER);
- GET_OUTPUT_GPR(patch, 0x118, MULTI_LFE);
-
- OP(4, 0x113, 0x40, MULTI_FRONT_L, 0x44);
- OP(4, 0x114, 0x40, MULTI_FRONT_R, 0x44);
- OP(4, 0x115, 0x40, MULTI_REAR_L, 0x44);
- OP(4, 0x116, 0x40, MULTI_REAR_R, 0x44);
- OP(4, 0x117, 0x40, MULTI_CENTER, 0x44);
- OP(4, 0x118, 0x40, MULTI_LFE, 0x44);
-
- INPUT_PATCH_END(patch);
-
-
- //Routing patch start
- ROUTING_PATCH_START(rpatch, "Routing");
- GET_INPUT_GPR(rpatch, 0x100, 0x0);
- GET_INPUT_GPR(rpatch, 0x101, 0x1);
- GET_INPUT_GPR(rpatch, 0x10c, 0x12);
- GET_INPUT_GPR(rpatch, 0x10e, 0x13);
- GET_INPUT_GPR(rpatch, 0x113, MULTI_FRONT_L);
- GET_INPUT_GPR(rpatch, 0x114, MULTI_FRONT_R);
- GET_INPUT_GPR(rpatch, 0x115, MULTI_REAR_L);
- GET_INPUT_GPR(rpatch, 0x116, MULTI_REAR_R);
- GET_INPUT_GPR(rpatch, 0x117, MULTI_CENTER);
- GET_INPUT_GPR(rpatch, 0x118, MULTI_LFE);
-
- GET_DYNAMIC_GPR(rpatch, 0x102);
- GET_DYNAMIC_GPR(rpatch, 0x103);
-
- GET_OUTPUT_GPR(rpatch, 0x104, 0x8);
- GET_OUTPUT_GPR(rpatch, 0x105, 0x9);
- GET_OUTPUT_GPR(rpatch, 0x10a, 0x2);
- GET_OUTPUT_GPR(rpatch, 0x10b, 0x3);
-
-
- /* input buffer */
- OP(6, 0x102, AC97_IN_L, 0x40, 0x40);
- OP(6, 0x103, AC97_IN_R, 0x40, 0x40);
-
-
- /* Digital In + PCM + MULTI_FRONT-> AC97 out (front speakers)*/
- OP(6, AC97_FRONT_L, 0x100, 0x10c, 0x113);
-
- CONNECT(MULTI_FRONT_L, AC97_FRONT_L);
- CONNECT(PCM_IN_L, AC97_FRONT_L);
- CONNECT(SPDIF_CD_L, AC97_FRONT_L);
-
- OP(6, AC97_FRONT_R, 0x101, 0x10e, 0x114);
-
- CONNECT(MULTI_FRONT_R, AC97_FRONT_R);
- CONNECT(PCM_IN_R, AC97_FRONT_R);
- CONNECT(SPDIF_CD_R, AC97_FRONT_R);
-
- /* Digital In + PCM + AC97 In + PCM1 + MULTI_REAR --> Rear Channel */
- OP(6, 0x104, PCM1_IN_L, 0x100, 0x115);
- OP(6, 0x104, 0x104, 0x10c, 0x102);
-
- CONNECT(MULTI_REAR_L, ANALOG_REAR_L);
- CONNECT(AC97_IN_L, ANALOG_REAR_L);
- CONNECT(PCM_IN_L, ANALOG_REAR_L);
- CONNECT(SPDIF_CD_L, ANALOG_REAR_L);
- CONNECT(PCM1_IN_L, ANALOG_REAR_L);
-
- OP(6, 0x105, PCM1_IN_R, 0x101, 0x116);
- OP(6, 0x105, 0x105, 0x10e, 0x103);
-
- CONNECT(MULTI_REAR_R, ANALOG_REAR_R);
- CONNECT(AC97_IN_R, ANALOG_REAR_R);
- CONNECT(PCM_IN_R, ANALOG_REAR_R);
- CONNECT(SPDIF_CD_R, ANALOG_REAR_R);
- CONNECT(PCM1_IN_R, ANALOG_REAR_R);
-
- /* Digital In + PCM + AC97 In + MULTI_FRONT --> Digital out */
- OP(6, 0x10b, 0x100, 0x102, 0x10c);
- OP(6, 0x10b, 0x10b, 0x113, 0x40);
-
- CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L);
- CONNECT(PCM_IN_L, DIGITAL_OUT_L);
- CONNECT(AC97_IN_L, DIGITAL_OUT_L);
- CONNECT(SPDIF_CD_L, DIGITAL_OUT_L);
-
- OP(6, 0x10a, 0x101, 0x103, 0x10e);
- OP(6, 0x10b, 0x10b, 0x114, 0x40);
-
- CONNECT(MULTI_FRONT_R, DIGITAL_OUT_R);
- CONNECT(PCM_IN_R, DIGITAL_OUT_R);
- CONNECT(AC97_IN_R, DIGITAL_OUT_R);
- CONNECT(SPDIF_CD_R, DIGITAL_OUT_R);
-
- /* AC97 In --> ADC Recording Buffer */
- OP(6, ADC_REC_L, 0x102, 0x40, 0x40);
-
- CONNECT(AC97_IN_L, ADC_REC_L);
-
- OP(6, ADC_REC_R, 0x103, 0x40, 0x40);
-
- CONNECT(AC97_IN_R, ADC_REC_R);
-
-
- /* fx12:Analog-Center */
- OP(6, ANALOG_CENTER, 0x117, 0x40, 0x40);
- CONNECT(MULTI_CENTER, ANALOG_CENTER);
-
- /* fx11:Analog-LFE */
- OP(6, ANALOG_LFE, 0x118, 0x40, 0x40);
- CONNECT(MULTI_LFE, ANALOG_LFE);
-
- /* fx12:Digital-Center */
- OP(6, DIGITAL_CENTER, 0x117, 0x40, 0x40);
- CONNECT(MULTI_CENTER, DIGITAL_CENTER);
-
- /* fx11:Analog-LFE */
- OP(6, DIGITAL_LFE, 0x118, 0x40, 0x40);
- CONNECT(MULTI_LFE, DIGITAL_LFE);
-
- ROUTING_PATCH_END(rpatch);
-
-
- // Rear volume control
- OUTPUT_PATCH_START(patch, "Vol Rear L", 0x8, 0);
- GET_INPUT_GPR(patch, 0x104, 0x8);
- GET_CONTROL_GPR(patch, 0x119, "Vol", 0, 0x7fffffff);
-
- OP(0, ANALOG_REAR_L, 0x040, 0x104, 0x119);
- OUTPUT_PATCH_END(patch);
-
- OUTPUT_PATCH_START(patch, "Vol Rear R", 0x9, 0);
- GET_INPUT_GPR(patch, 0x105, 0x9);
- GET_CONTROL_GPR(patch, 0x11a, "Vol", 0, 0x7fffffff);
-
- OP(0, ANALOG_REAR_R, 0x040, 0x105, 0x11a);
- OUTPUT_PATCH_END(patch);
-
-
- //Master volume control on front-digital
- OUTPUT_PATCH_START(patch, "Vol Master L", 0x2, 1);
- GET_INPUT_GPR(patch, 0x10a, 0x2);
- GET_CONTROL_GPR(patch, 0x108, "Vol", 0, 0x7fffffff);
-
- OP(0, DIGITAL_OUT_L, 0x040, 0x10a, 0x108);
- OUTPUT_PATCH_END(patch);
-
-
- OUTPUT_PATCH_START(patch, "Vol Master R", 0x3, 1);
- GET_INPUT_GPR(patch, 0x10b, 0x3);
- GET_CONTROL_GPR(patch, 0x109, "Vol", 0, 0x7fffffff);
-
- OP(0, DIGITAL_OUT_R, 0x040, 0x10b, 0x109);
- OUTPUT_PATCH_END(patch);
-
-
- /* delimiter patch */
- patch = PATCH(mgr, patch_n);
- patch->code_size = 0;
-
-
- sblive_writeptr(card, DBG, 0, 0);
- }
-
- spin_lock_init(&mgr->lock);
-
- // Set up Volume controls, try to keep this the same for both Audigy and Live
-
- //Master volume
- mgr->ctrl_gpr[SOUND_MIXER_VOLUME][0] = 8;
- mgr->ctrl_gpr[SOUND_MIXER_VOLUME][1] = 9;
-
- left = card->ac97->mixer_state[SOUND_MIXER_VOLUME] & 0xff;
- right = (card->ac97->mixer_state[SOUND_MIXER_VOLUME] >> 8) & 0xff;
-
- emu10k1_set_volume_gpr(card, 8, left, 1 << card->ac97->bit_resolution);
- emu10k1_set_volume_gpr(card, 9, right, 1 << card->ac97->bit_resolution);
-
- //Rear volume
- mgr->ctrl_gpr[ SOUND_MIXER_OGAIN ][0] = 0x19;
- mgr->ctrl_gpr[ SOUND_MIXER_OGAIN ][1] = 0x1a;
-
- left = right = 67;
- card->ac97->mixer_state[SOUND_MIXER_OGAIN] = (right << 8) | left;
-
- card->ac97->supported_mixers |= SOUND_MASK_OGAIN;
- card->ac97->stereo_mixers |= SOUND_MASK_OGAIN;
-
- emu10k1_set_volume_gpr(card, 0x19, left, VOL_5BIT);
- emu10k1_set_volume_gpr(card, 0x1a, right, VOL_5BIT);
-
- //PCM Volume
- mgr->ctrl_gpr[SOUND_MIXER_PCM][0] = 6;
- mgr->ctrl_gpr[SOUND_MIXER_PCM][1] = 7;
-
- left = card->ac97->mixer_state[SOUND_MIXER_PCM] & 0xff;
- right = (card->ac97->mixer_state[SOUND_MIXER_PCM] >> 8) & 0xff;
-
- emu10k1_set_volume_gpr(card, 6, left, VOL_5BIT);
- emu10k1_set_volume_gpr(card, 7, right, VOL_5BIT);
-
- //CD-Digital Volume
- mgr->ctrl_gpr[SOUND_MIXER_DIGITAL1][0] = 0xd;
- mgr->ctrl_gpr[SOUND_MIXER_DIGITAL1][1] = 0xf;
-
- left = right = 67;
- card->ac97->mixer_state[SOUND_MIXER_DIGITAL1] = (right << 8) | left;
-
- card->ac97->supported_mixers |= SOUND_MASK_DIGITAL1;
- card->ac97->stereo_mixers |= SOUND_MASK_DIGITAL1;
-
- emu10k1_set_volume_gpr(card, 0xd, left, VOL_5BIT);
- emu10k1_set_volume_gpr(card, 0xf, right, VOL_5BIT);
-
-
- //hard wire the ac97's pcm, pcm volume is done above using dsp code.
- if (card->is_audigy)
- //for Audigy, we mute it and use the philips 6 channel DAC instead
- emu10k1_ac97_write(card->ac97, 0x18, 0x8000);
- else
- //For the Live we hardwire it to full volume
- emu10k1_ac97_write(card->ac97, 0x18, 0x0);
-
- //remove it from the ac97_codec's control
- card->ac97_supported_mixers &= ~SOUND_MASK_PCM;
- card->ac97_stereo_mixers &= ~SOUND_MASK_PCM;
-
- //set Igain to 0dB by default, maybe consider hardwiring it here.
- emu10k1_ac97_write(card->ac97, AC97_RECORD_GAIN, 0x0000);
- card->ac97->mixer_state[SOUND_MIXER_IGAIN] = 0x101;
-
- return 0;
-}
-
-static int __devinit hw_init(struct emu10k1_card *card)
-{
- int nCh;
- u32 pagecount; /* tmp */
- int ret;
-
- /* Disable audio and lock cache */
- emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE);
-
- /* Reset recording buffers */
- sblive_writeptr_tag(card, 0,
- MICBS, ADCBS_BUFSIZE_NONE,
- MICBA, 0,
- FXBS, ADCBS_BUFSIZE_NONE,
- FXBA, 0,
- ADCBS, ADCBS_BUFSIZE_NONE,
- ADCBA, 0,
- TAGLIST_END);
-
- /* Disable channel interrupt */
- emu10k1_writefn0(card, INTE, 0);
- sblive_writeptr_tag(card, 0,
- CLIEL, 0,
- CLIEH, 0,
- SOLEL, 0,
- SOLEH, 0,
- TAGLIST_END);
-
- if (card->is_audigy) {
- sblive_writeptr_tag(card,0,
- 0x5e,0xf00,
- 0x5f,0x3,
- TAGLIST_END);
- }
-
- /* Init envelope engine */
- for (nCh = 0; nCh < NUM_G; nCh++) {
- sblive_writeptr_tag(card, nCh,
- DCYSUSV, 0,
- IP, 0,
- VTFT, 0xffff,
- CVCF, 0xffff,
- PTRX, 0,
- //CPF, 0,
- CCR, 0,
-
- PSST, 0,
- DSL, 0x10,
- CCCA, 0,
- Z1, 0,
- Z2, 0,
- FXRT, 0xd01c0000,
-
- ATKHLDM, 0,
- DCYSUSM, 0,
- IFATN, 0xffff,
- PEFE, 0,
- FMMOD, 0,
- TREMFRQ, 24, /* 1 Hz */
- FM2FRQ2, 24, /* 1 Hz */
- TEMPENV, 0,
-
- /*** These are last so OFF prevents writing ***/
- LFOVAL2, 0,
- LFOVAL1, 0,
- ATKHLDV, 0,
- ENVVOL, 0,
- ENVVAL, 0,
- TAGLIST_END);
- sblive_writeptr(card, CPF, nCh, 0);
- /*
- Audigy FXRT initialization
- reversed eng'd, may not be accurate.
- */
- if (card->is_audigy) {
- sblive_writeptr_tag(card,nCh,
- 0x4c,0x0,
- 0x4d,0x0,
- 0x4e,0x0,
- 0x4f,0x0,
- A_FXRT1, 0x3f3f3f3f,
- A_FXRT2, 0x3f3f3f3f,
- A_SENDAMOUNTS, 0,
- TAGLIST_END);
- }
- }
-
-
- /*
- ** Init to 0x02109204 :
- ** Clock accuracy = 0 (1000ppm)
- ** Sample Rate = 2 (48kHz)
- ** Audio Channel = 1 (Left of 2)
- ** Source Number = 0 (Unspecified)
- ** Generation Status = 1 (Original for Cat Code 12)
- ** Cat Code = 12 (Digital Signal Mixer)
- ** Mode = 0 (Mode 0)
- ** Emphasis = 0 (None)
- ** CP = 1 (Copyright unasserted)
- ** AN = 0 (Digital audio)
- ** P = 0 (Consumer)
- */
-
- sblive_writeptr_tag(card, 0,
-
- /* SPDIF0 */
- SPCS0, (SPCS_CLKACCY_1000PPM | 0x002000000 |
- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT),
-
- /* SPDIF1 */
- SPCS1, (SPCS_CLKACCY_1000PPM | 0x002000000 |
- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT),
-
- /* SPDIF2 & SPDIF3 */
- SPCS2, (SPCS_CLKACCY_1000PPM | 0x002000000 |
- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT),
-
- TAGLIST_END);
-
- if (card->is_audigy && (card->chiprev == 4)) {
- /* Hacks for Alice3 to work independent of haP16V driver */
- u32 tmp;
-
- //Setup SRCMulti_I2S SamplingRate
- tmp = sblive_readptr(card, A_SPDIF_SAMPLERATE, 0);
- tmp &= 0xfffff1ff;
- tmp |= (0x2<<9);
- sblive_writeptr(card, A_SPDIF_SAMPLERATE, 0, tmp);
-
- /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
- emu10k1_writefn0(card, 0x20, 0x600000);
- emu10k1_writefn0(card, 0x24, 0x14);
-
- /* Setup SRCMulti Input Audio Enable */
- emu10k1_writefn0(card, 0x20, 0x6E0000);
- emu10k1_writefn0(card, 0x24, 0xFF00FF00);
- }
-
- ret = fx_init(card); /* initialize effects engine */
- if (ret < 0)
- return ret;
-
- card->tankmem.size = 0;
-
- card->virtualpagetable.size = MAXPAGES * sizeof(u32);
-
- card->virtualpagetable.addr = pci_alloc_consistent(card->pci_dev, card->virtualpagetable.size, &card->virtualpagetable.dma_handle);
- if (card->virtualpagetable.addr == NULL) {
- ERROR();
- ret = -ENOMEM;
- goto err0;
- }
-
- card->silentpage.size = EMUPAGESIZE;
-
- card->silentpage.addr = pci_alloc_consistent(card->pci_dev, card->silentpage.size, &card->silentpage.dma_handle);
- if (card->silentpage.addr == NULL) {
- ERROR();
- ret = -ENOMEM;
- goto err1;
- }
-
- for (pagecount = 0; pagecount < MAXPAGES; pagecount++)
- ((u32 *) card->virtualpagetable.addr)[pagecount] = cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pagecount);
-
- /* Init page table & tank memory base register */
- sblive_writeptr_tag(card, 0,
- PTB, (u32) card->virtualpagetable.dma_handle,
- TCB, 0,
- TCBS, 0,
- TAGLIST_END);
-
- for (nCh = 0; nCh < NUM_G; nCh++) {
- sblive_writeptr_tag(card, nCh,
- MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
- MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
- TAGLIST_END);
- }
-
- /* Hokay, now enable the AUD bit */
- /* Enable Audio = 1 */
- /* Mute Disable Audio = 0 */
- /* Lock Tank Memory = 1 */
- /* Lock Sound Memory = 0 */
- /* Auto Mute = 1 */
- if (card->is_audigy) {
- if (card->chiprev == 4)
- emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | HCFG_AC3ENABLE_GPSPDIF | HCFG_AUTOMUTE | HCFG_JOYENABLE);
- else
- emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
- } else {
- if (card->model == 0x20 || card->model == 0xc400 ||
- (card->model == 0x21 && card->chiprev < 6))
- emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE);
- else
- emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE);
- }
- /* Enable Vol_Ctrl irqs */
- emu10k1_irq_enable(card, INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_FXDSPENABLE);
-
- if (card->is_audigy && (card->chiprev == 4)) {
- /* Unmute Analog now. Set GPO6 to 1 for Apollo.
- * This has to be done after init ALice3 I2SOut beyond 48KHz.
- * So, sequence is important. */
- u32 tmp = emu10k1_readfn0(card, A_IOCFG);
- tmp |= 0x0040;
- emu10k1_writefn0(card, A_IOCFG, tmp);
- }
-
- /* FIXME: TOSLink detection */
- card->has_toslink = 0;
-
- /* Initialize digital passthrough variables */
- card->pt.pos_gpr = card->pt.intr_gpr = card->pt.enable_gpr = -1;
- card->pt.selected = 0;
- card->pt.state = PT_STATE_INACTIVE;
- card->pt.spcs_to_use = 0x01;
- card->pt.patch_name = "AC3pass";
- card->pt.intr_gpr_name = "count";
- card->pt.enable_gpr_name = "enable";
- card->pt.pos_gpr_name = "ptr";
- spin_lock_init(&card->pt.lock);
- init_waitqueue_head(&card->pt.wait);
-
-/* tmp = sblive_readfn0(card, HCFG);
- if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
- sblive_writefn0(card, HCFG, tmp | 0x800);
-
- udelay(512);
-
- if (tmp != (sblive_readfn0(card, HCFG) & ~0x800)) {
- card->has_toslink = 1;
- sblive_writefn0(card, HCFG, tmp);
- }
- }
-*/
- return 0;
-
- err1:
- pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle);
- err0:
- fx_cleanup(&card->mgr);
-
- return ret;
-}
-
-static int __devinit emu10k1_init(struct emu10k1_card *card)
-{
- /* Init Card */
- if (hw_init(card) < 0)
- return -1;
-
- voice_init(card);
- timer_init(card);
- addxmgr_init(card);
-
- DPD(2, " hw control register -> %#x\n", emu10k1_readfn0(card, HCFG));
-
- return 0;
-}
-
-static void emu10k1_cleanup(struct emu10k1_card *card)
-{
- int ch;
-
- emu10k1_writefn0(card, INTE, 0);
-
- /** Shutdown the chip **/
- for (ch = 0; ch < NUM_G; ch++)
- sblive_writeptr(card, DCYSUSV, ch, 0);
-
- for (ch = 0; ch < NUM_G; ch++) {
- sblive_writeptr_tag(card, ch,
- VTFT, 0,
- CVCF, 0,
- PTRX, 0,
- //CPF, 0,
- TAGLIST_END);
- sblive_writeptr(card, CPF, ch, 0);
- }
-
- /* Disable audio and lock cache */
- emu10k1_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE);
-
- sblive_writeptr_tag(card, 0,
- PTB, 0,
-
- /* Reset recording buffers */
- MICBS, ADCBS_BUFSIZE_NONE,
- MICBA, 0,
- FXBS, ADCBS_BUFSIZE_NONE,
- FXBA, 0,
- FXWC, 0,
- ADCBS, ADCBS_BUFSIZE_NONE,
- ADCBA, 0,
- TCBS, 0,
- TCB, 0,
- DBG, 0x8000,
-
- /* Disable channel interrupt */
- CLIEL, 0,
- CLIEH, 0,
- SOLEL, 0,
- SOLEH, 0,
- TAGLIST_END);
-
- if (card->is_audigy)
- sblive_writeptr(card, 0, A_DBG, A_DBG_SINGLE_STEP);
-
- pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle);
- pci_free_consistent(card->pci_dev, card->silentpage.size, card->silentpage.addr, card->silentpage.dma_handle);
-
- if(card->tankmem.size != 0)
- pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle);
-
- /* release patch storage memory */
- fx_cleanup(&card->mgr);
-}
-
-/* Driver initialization routine */
-static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- struct emu10k1_card *card;
- u32 subsysvid;
- int ret;
-
- if (pci_set_dma_mask(pci_dev, EMU10K1_DMA_MASK)) {
- printk(KERN_ERR "emu10k1: architecture does not support 29bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- if (pci_enable_device(pci_dev))
- return -EIO;
-
- pci_set_master(pci_dev);
-
- if ((card = kzalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "emu10k1: out of memory\n");
- return -ENOMEM;
- }
-
- card->iobase = pci_resource_start(pci_dev, 0);
- card->length = pci_resource_len(pci_dev, 0);
-
- if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
- printk(KERN_ERR "emu10k1: IO space in use\n");
- ret = -EBUSY;
- goto err_region;
- }
-
- pci_set_drvdata(pci_dev, card);
-
- card->irq = pci_dev->irq;
- card->pci_dev = pci_dev;
-
- /* Reserve IRQ Line */
- if (request_irq(card->irq, emu10k1_interrupt, IRQF_SHARED, card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "emu10k1: IRQ in use\n");
- ret = -EBUSY;
- goto err_irq;
- }
-
- pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev);
- pci_read_config_word(pci_dev, PCI_SUBSYSTEM_ID, &card->model);
-
- printk(KERN_INFO "emu10k1: %s rev %d model %#04x found, IO at %#04lx-%#04lx, IRQ %d\n",
- card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase,
- card->iobase + card->length - 1, card->irq);
-
- if (pci_id->device == PCI_DEVICE_ID_CREATIVE_AUDIGY)
- card->is_audigy = 1;
-
- pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
- card->is_aps = (subsysvid == EMU_APS_SUBID);
-
- spin_lock_init(&card->lock);
- mutex_init(&card->open_sem);
- card->open_mode = 0;
- init_waitqueue_head(&card->open_wait);
-
- ret = emu10k1_audio_init(card);
- if (ret < 0) {
- printk(KERN_ERR "emu10k1: cannot initialize audio devices\n");
- goto err_audio;
- }
-
- ret = emu10k1_mixer_init(card);
- if (ret < 0) {
- printk(KERN_ERR "emu10k1: cannot initialize AC97 codec\n");
- goto err_mixer;
- }
-
- ret = emu10k1_midi_init(card);
- if (ret < 0) {
- printk(KERN_ERR "emu10k1: cannot register midi device\n");
- goto err_midi;
- }
-
- ret = emu10k1_init(card);
- if (ret < 0) {
- printk(KERN_ERR "emu10k1: cannot initialize device\n");
- goto err_emu10k1_init;
- }
-
- if (card->is_aps)
- emu10k1_ecard_init(card);
-
- ret = emu10k1_register_devices(card);
- if (ret < 0)
- goto err_register;
-
- /* proc entries must be created after registering devices, as
- * emu10k1_info_proc prints card->audio_dev &co. */
- ret = emu10k1_proc_init(card);
- if (ret < 0) {
- printk(KERN_ERR "emu10k1: cannot initialize proc directory\n");
- goto err_proc;
- }
-
- list_add(&card->list, &emu10k1_devs);
-
- return 0;
-
-err_proc:
- emu10k1_unregister_devices(card);
-
-err_register:
- emu10k1_cleanup(card);
-
-err_emu10k1_init:
- emu10k1_midi_cleanup(card);
-
-err_midi:
- emu10k1_mixer_cleanup(card);
-
-err_mixer:
- emu10k1_audio_cleanup(card);
-
-err_audio:
- free_irq(card->irq, card);
-
-err_irq:
- release_region(card->iobase, card->length);
- pci_set_drvdata(pci_dev, NULL);
-
-err_region:
- kfree(card);
-
- return ret;
-}
-
-static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
-{
- struct emu10k1_card *card = pci_get_drvdata(pci_dev);
-
- list_del(&card->list);
-
- emu10k1_unregister_devices(card);
- emu10k1_cleanup(card);
- emu10k1_midi_cleanup(card);
- emu10k1_mixer_cleanup(card);
- emu10k1_proc_cleanup(card);
- emu10k1_audio_cleanup(card);
- free_irq(card->irq, card);
- release_region(card->iobase, card->length);
- kfree(card);
- pci_set_drvdata(pci_dev, NULL);
-}
-
-MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@lists.sourceforge.net)");
-MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd.");
-MODULE_LICENSE("GPL");
-
-static struct pci_driver emu10k1_pci_driver = {
- .name = "emu10k1",
- .id_table = emu10k1_pci_tbl,
- .probe = emu10k1_probe,
- .remove = __devexit_p(emu10k1_remove),
-};
-
-static int __init emu10k1_init_module(void)
-{
- printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
- return pci_register_driver(&emu10k1_pci_driver);
-}
-
-static void __exit emu10k1_cleanup_module(void)
-{
- pci_unregister_driver(&emu10k1_pci_driver);
-
- return;
-}
-
-module_init(emu10k1_init_module);
-module_exit(emu10k1_cleanup_module);
-
-#ifdef EMU10K1_SEQUENCER
-
-/* in midi.c */
-extern int emu10k1_seq_midi_open(int dev, int mode,
- void (*input)(int dev, unsigned char midi_byte),
- void (*output)(int dev));
-extern void emu10k1_seq_midi_close(int dev);
-extern int emu10k1_seq_midi_out(int dev, unsigned char midi_byte);
-extern int emu10k1_seq_midi_start_read(int dev);
-extern int emu10k1_seq_midi_end_read(int dev);
-extern void emu10k1_seq_midi_kick(int dev);
-extern int emu10k1_seq_midi_buffer_status(int dev);
-
-static struct midi_operations emu10k1_midi_operations =
-{
- THIS_MODULE,
- {"EMU10K1 MIDI", 0, 0, SNDCARD_EMU10K1},
- &std_midi_synth,
- {0},
- emu10k1_seq_midi_open,
- emu10k1_seq_midi_close,
- NULL,
- emu10k1_seq_midi_out,
- emu10k1_seq_midi_start_read,
- emu10k1_seq_midi_end_read,
- emu10k1_seq_midi_kick,
- NULL,
- emu10k1_seq_midi_buffer_status,
- NULL
-};
-
-#endif
diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c
deleted file mode 100644
index df1e990449a0..000000000000
--- a/sound/oss/emu10k1/midi.c
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- **********************************************************************
- * midi.c - /dev/midi interface for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <asm/uaccess.h>
-
-#include "hwaccess.h"
-#include "cardmo.h"
-#include "cardmi.h"
-#include "midi.h"
-
-#ifdef EMU10K1_SEQUENCER
-#include "../sound_config.h"
-#endif
-
-static DEFINE_SPINLOCK(midi_spinlock);
-
-static void init_midi_hdr(struct midi_hdr *midihdr)
-{
- midihdr->bufferlength = MIDIIN_BUFLEN;
- midihdr->bytesrecorded = 0;
- midihdr->flags = 0;
-}
-
-static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr)
-{
- struct midi_hdr *midihdr;
-
- if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL) {
- ERROR();
- return -EINVAL;
- }
-
- init_midi_hdr(midihdr);
-
- midihdr->data = kmalloc(MIDIIN_BUFLEN, GFP_KERNEL);
- if (!midihdr->data) {
- ERROR();
- kfree(midihdr);
- return -1;
- }
-
- if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) < 0) {
- ERROR();
- kfree(midihdr->data);
- kfree(midihdr);
- return -1;
- }
-
- *midihdrptr = midihdr;
- list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
-
- return 0;
-}
-
-static int emu10k1_midi_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct emu10k1_card *card = NULL;
- struct emu10k1_mididevice *midi_dev;
- struct list_head *entry;
-
- DPF(2, "emu10k1_midi_open()\n");
-
- /* Check for correct device to open */
- list_for_each(entry, &emu10k1_devs) {
- card = list_entry(entry, struct emu10k1_card, list);
-
- if (card->midi_dev == minor)
- goto match;
- }
-
- return -ENODEV;
-
-match:
-#ifdef EMU10K1_SEQUENCER
- if (card->seq_mididev) /* card is opened by sequencer */
- return -EBUSY;
-#endif
-
- /* Wait for device to become free */
- mutex_lock(&card->open_sem);
- while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&card->open_sem);
- return -EBUSY;
- }
-
- mutex_unlock(&card->open_sem);
- interruptible_sleep_on(&card->open_wait);
-
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
-
- mutex_lock(&card->open_sem);
- }
-
- if ((midi_dev = kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
- return -EINVAL;
-
- midi_dev->card = card;
- midi_dev->mistate = MIDIIN_STATE_STOPPED;
- init_waitqueue_head(&midi_dev->oWait);
- init_waitqueue_head(&midi_dev->iWait);
- midi_dev->ird = 0;
- midi_dev->iwr = 0;
- midi_dev->icnt = 0;
- INIT_LIST_HEAD(&midi_dev->mid_hdrs);
-
- if (file->f_mode & FMODE_READ) {
- struct midi_openinfo dsCardMidiOpenInfo;
- struct midi_hdr *midihdr1;
- struct midi_hdr *midihdr2;
-
- dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
-
- if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo) < 0) {
- ERROR();
- kfree(midi_dev);
- return -ENODEV;
- }
-
- /* Add two buffers to receive sysex buffer */
- if (midiin_add_buffer(midi_dev, &midihdr1) < 0) {
- kfree(midi_dev);
- return -ENODEV;
- }
-
- if (midiin_add_buffer(midi_dev, &midihdr2) < 0) {
- list_del(&midihdr1->list);
- kfree(midihdr1->data);
- kfree(midihdr1);
- kfree(midi_dev);
- return -ENODEV;
- }
- }
-
- if (file->f_mode & FMODE_WRITE) {
- struct midi_openinfo dsCardMidiOpenInfo;
-
- dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
-
- if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
- ERROR();
- kfree(midi_dev);
- return -ENODEV;
- }
- }
-
- file->private_data = (void *) midi_dev;
-
- card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-
- mutex_unlock(&card->open_sem);
-
- return nonseekable_open(inode, file);
-}
-
-static int emu10k1_midi_release(struct inode *inode, struct file *file)
-{
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- struct emu10k1_card *card;
-
- lock_kernel();
-
- card = midi_dev->card;
- DPF(2, "emu10k1_midi_release()\n");
-
- if (file->f_mode & FMODE_WRITE) {
- if (!(file->f_flags & O_NONBLOCK)) {
-
- while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) {
- DPF(4, "Cannot close - buffers not empty\n");
-
- interruptible_sleep_on(&midi_dev->oWait);
-
- }
- }
-
- emu10k1_mpuout_close(card);
- }
-
- if (file->f_mode & FMODE_READ) {
- struct midi_hdr *midihdr;
-
- if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
- emu10k1_mpuin_stop(card);
- midi_dev->mistate = MIDIIN_STATE_STOPPED;
- }
-
- emu10k1_mpuin_reset(card);
- emu10k1_mpuin_close(card);
-
- while (!list_empty(&midi_dev->mid_hdrs)) {
- midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list);
-
- list_del(midi_dev->mid_hdrs.next);
- kfree(midihdr->data);
- kfree(midihdr);
- }
- }
-
- kfree(midi_dev);
-
- mutex_lock(&card->open_sem);
- card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
- mutex_unlock(&card->open_sem);
- wake_up_interruptible(&card->open_wait);
-
- unlock_kernel();
-
- return 0;
-}
-
-static ssize_t emu10k1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t * pos)
-{
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- ssize_t ret = 0;
- u16 cnt;
- unsigned long flags;
-
- DPD(4, "emu10k1_midi_read(), count %#x\n", (u32) count);
-
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
-
- if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
- if (emu10k1_mpuin_start(midi_dev->card) < 0) {
- ERROR();
- return -EINVAL;
- }
-
- midi_dev->mistate = MIDIIN_STATE_STARTED;
- }
-
- while (count > 0) {
- cnt = MIDIIN_BUFLEN - midi_dev->ird;
-
- spin_lock_irqsave(&midi_spinlock, flags);
-
- if (midi_dev->icnt < cnt)
- cnt = midi_dev->icnt;
-
- spin_unlock_irqrestore(&midi_spinlock, flags);
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- DPF(2, " Go to sleep...\n");
-
- interruptible_sleep_on(&midi_dev->iWait);
-
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
-
- continue;
- }
-
- if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) {
- ERROR();
- return ret ? ret : -EFAULT;
- }
-
- midi_dev->ird += cnt;
- midi_dev->ird %= MIDIIN_BUFLEN;
-
- spin_lock_irqsave(&midi_spinlock, flags);
-
- midi_dev->icnt -= cnt;
-
- spin_unlock_irqrestore(&midi_spinlock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
-
- if (midi_dev->icnt == 0)
- break;
- }
-
- return ret;
-}
-
-static ssize_t emu10k1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t * pos)
-{
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- struct midi_hdr *midihdr;
- unsigned long flags;
-
- DPD(4, "emu10k1_midi_write(), count=%#x\n", (u32) count);
-
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-
- if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
- return -EINVAL;
-
- midihdr->bufferlength = count;
- midihdr->bytesrecorded = 0;
- midihdr->flags = 0;
-
- midihdr->data = kmalloc(count, GFP_KERNEL);
- if (!midihdr->data) {
- ERROR();
- kfree(midihdr);
- return -EINVAL;
- }
-
- if (copy_from_user(midihdr->data, buffer, count)) {
- kfree(midihdr->data);
- kfree(midihdr);
- return -EFAULT;
- }
-
- spin_lock_irqsave(&midi_spinlock, flags);
-
- if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) < 0) {
- ERROR();
- kfree(midihdr->data);
- kfree(midihdr);
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return -EINVAL;
- }
-
- spin_unlock_irqrestore(&midi_spinlock, flags);
-
- return count;
-}
-
-static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- DPF(4, "emu10k1_midi_poll() called\n");
-
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &midi_dev->oWait, wait);
-
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &midi_dev->iWait, wait);
-
- spin_lock_irqsave(&midi_spinlock, flags);
-
- if (file->f_mode & FMODE_WRITE)
- mask |= POLLOUT | POLLWRNORM;
-
- if (file->f_mode & FMODE_READ) {
- if (midi_dev->mistate == MIDIIN_STATE_STARTED)
- if (midi_dev->icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
-
- spin_unlock_irqrestore(&midi_spinlock, flags);
-
- return mask;
-}
-
-int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
-{
- struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata;
- struct midi_hdr *midihdr = NULL;
- unsigned long flags;
- int i;
-
- DPF(4, "emu10k1_midi_callback()\n");
-
- spin_lock_irqsave(&midi_spinlock, flags);
-
- switch (msg) {
- case ICARDMIDI_OUTLONGDATA:
- midihdr = (struct midi_hdr *) pmsg[2];
-
- kfree(midihdr->data);
- kfree(midihdr);
- wake_up_interruptible(&midi_dev->oWait);
-
- break;
-
- case ICARDMIDI_INLONGDATA:
- midihdr = (struct midi_hdr *) pmsg[2];
-
- for (i = 0; i < midihdr->bytesrecorded; i++) {
- midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i];
- midi_dev->iwr %= MIDIIN_BUFLEN;
- }
-
- midi_dev->icnt += midihdr->bytesrecorded;
-
- if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
- init_midi_hdr(midihdr);
- emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr);
- wake_up_interruptible(&midi_dev->iWait);
- }
- break;
-
- case ICARDMIDI_INDATA:
- {
- u8 *pBuf = (u8 *) & pmsg[1];
- u16 bytesvalid = pmsg[2];
-
- for (i = 0; i < bytesvalid; i++) {
- midi_dev->iBuf[midi_dev->iwr++] = pBuf[i];
- midi_dev->iwr %= MIDIIN_BUFLEN;
- }
-
- midi_dev->icnt += bytesvalid;
- }
-
- wake_up_interruptible(&midi_dev->iWait);
- break;
-
- default: /* Unknown message */
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return -1;
- }
-
- spin_unlock_irqrestore(&midi_spinlock, flags);
-
- return 0;
-}
-
-/* MIDI file operations */
-const struct file_operations emu10k1_midi_fops = {
- .owner = THIS_MODULE,
- .read = emu10k1_midi_read,
- .write = emu10k1_midi_write,
- .poll = emu10k1_midi_poll,
- .open = emu10k1_midi_open,
- .release = emu10k1_midi_release,
-};
-
-
-#ifdef EMU10K1_SEQUENCER
-
-/* functions used for sequencer access */
-
-int emu10k1_seq_midi_open(int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev))
-{
- struct emu10k1_card *card;
- struct midi_openinfo dsCardMidiOpenInfo;
- struct emu10k1_mididevice *midi_dev;
-
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return -EINVAL;
-
- card = midi_devs[dev]->devc;
-
- if (card->open_mode) /* card is opened native */
- return -EBUSY;
-
- DPF(2, "emu10k1_seq_midi_open()\n");
-
- if ((midi_dev = kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL)
- return -EINVAL;
-
- midi_dev->card = card;
- midi_dev->mistate = MIDIIN_STATE_STOPPED;
- init_waitqueue_head(&midi_dev->oWait);
- init_waitqueue_head(&midi_dev->iWait);
- midi_dev->ird = 0;
- midi_dev->iwr = 0;
- midi_dev->icnt = 0;
- INIT_LIST_HEAD(&midi_dev->mid_hdrs);
-
- dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
-
- if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo) < 0) {
- ERROR();
- return -ENODEV;
- }
-
- card->seq_mididev = midi_dev;
-
- return 0;
-}
-
-void emu10k1_seq_midi_close(int dev)
-{
- struct emu10k1_card *card;
-
- DPF(2, "emu10k1_seq_midi_close()\n");
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return;
-
- card = midi_devs[dev]->devc;
- emu10k1_mpuout_close(card);
-
- kfree(card->seq_mididev);
- card->seq_mididev = NULL;
-}
-
-int emu10k1_seq_midi_out(int dev, unsigned char midi_byte)
-{
- struct emu10k1_card *card;
- struct midi_hdr *midihdr;
- unsigned long flags;
-
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return -EINVAL;
-
- card = midi_devs[dev]->devc;
-
- if ((midihdr = kmalloc(sizeof(struct midi_hdr), GFP_KERNEL)) == NULL)
- return -EINVAL;
-
- midihdr->bufferlength = 1;
- midihdr->bytesrecorded = 0;
- midihdr->flags = 0;
-
- midihdr->data = kmalloc(1, GFP_KERNEL);
- if (!midihdr->data) {
- ERROR();
- kfree(midihdr);
- return -EINVAL;
- }
-
- *(midihdr->data) = midi_byte;
-
- spin_lock_irqsave(&midi_spinlock, flags);
-
- if (emu10k1_mpuout_add_buffer(card, midihdr) < 0) {
- ERROR();
- kfree(midihdr->data);
- kfree(midihdr);
- spin_unlock_irqrestore(&midi_spinlock, flags);
- return -EINVAL;
- }
-
- spin_unlock_irqrestore(&midi_spinlock, flags);
-
- return 1;
-}
-
-int emu10k1_seq_midi_start_read(int dev)
-{
- return 0;
-}
-
-int emu10k1_seq_midi_end_read(int dev)
-{
- return 0;
-}
-
-void emu10k1_seq_midi_kick(int dev)
-{
-}
-
-int emu10k1_seq_midi_buffer_status(int dev)
-{
- int count;
- struct midi_queue *queue;
- struct emu10k1_card *card;
-
- if (midi_devs[dev] == NULL || midi_devs[dev]->devc == NULL)
- return -EINVAL;
-
- count = 0;
-
- card = midi_devs[dev]->devc;
- queue = card->mpuout->firstmidiq;
-
- while (queue != NULL) {
- count++;
- if (queue == card->mpuout->lastmidiq)
- break;
-
- queue = queue->next;
- }
-
- return count;
-}
-
-#endif
-
diff --git a/sound/oss/emu10k1/midi.h b/sound/oss/emu10k1/midi.h
deleted file mode 100644
index 2459ec929e8d..000000000000
--- a/sound/oss/emu10k1/midi.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- **********************************************************************
- * midi.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _MIDI_H
-#define _MIDI_H
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define MIDIIN_STATE_STARTED 0x00000001
-#define MIDIIN_STATE_STOPPED 0x00000002
-
-#define MIDIIN_BUFLEN 1024
-
-struct emu10k1_mididevice
-{
- struct emu10k1_card *card;
- u32 mistate;
- wait_queue_head_t oWait;
- wait_queue_head_t iWait;
- s8 iBuf[MIDIIN_BUFLEN];
- u16 ird, iwr, icnt;
- struct list_head mid_hdrs;
-};
-
-/* uncomment next line to use midi port on Audigy drive */
-//#define USE_AUDIGY_DRIVE_MIDI
-
-#ifdef USE_AUDIGY_DRIVE_MIDI
-#define A_MUDATA A_MUDATA2
-#define A_MUCMD A_MUCMD2
-#define A_MUSTAT A_MUCMD2
-#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY2
-#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY2
-#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE2
-#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE2
-#else
-#define A_MUDATA A_MUDATA1
-#define A_MUCMD A_MUCMD1
-#define A_MUSTAT A_MUCMD1
-#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY1
-#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY1
-#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE1
-#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE1
-#endif
-
-
-#endif /* _MIDI_H */
-
diff --git a/sound/oss/emu10k1/mixer.c b/sound/oss/emu10k1/mixer.c
deleted file mode 100644
index bc3805fb0701..000000000000
--- a/sound/oss/emu10k1/mixer.c
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- **********************************************************************
- * mixer.c - /dev/mixer interface for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- * November 2, 1999 Alan Cox cleaned up stuff
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-#include <linux/module.h>
-#include <asm/uaccess.h>
-#include <linux/fs.h>
-
-#include "hwaccess.h"
-#include "8010.h"
-#include "recmgr.h"
-
-
-static const u32 bass_table[41][5] = {
- { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
- { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
- { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
- { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
- { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
- { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
- { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
- { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
- { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
- { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
- { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
- { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
- { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
- { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
- { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
- { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
- { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
- { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
- { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
- { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
- { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
- { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
- { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
- { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
- { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
- { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
- { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
- { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
- { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
- { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
- { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
- { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
- { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
- { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
- { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
- { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
- { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
- { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
- { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
- { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
- { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
-};
-
-static const u32 treble_table[41][5] = {
- { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
- { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
- { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
- { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
- { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
- { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
- { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
- { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
- { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
- { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
- { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
- { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
- { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
- { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
- { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
- { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
- { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
- { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
- { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
- { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
- { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
- { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
- { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
- { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
- { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
- { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
- { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
- { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
- { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
- { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
- { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
- { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
- { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
- { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
- { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
- { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
- { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
- { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
- { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
- { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
- { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
-};
-
-
-static void set_bass(struct emu10k1_card *card, int l, int r)
-{
- int i;
-
- l = (l * 40 + 50) / 100;
- r = (r * 40 + 50) / 100;
-
- for (i = 0; i < 5; i++)
- sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]);
-}
-
-static void set_treble(struct emu10k1_card *card, int l, int r)
-{
- int i;
-
- l = (l * 40 + 50) / 100;
- r = (r * 40 + 50) / 100;
-
- for (i = 0; i < 5; i++)
- sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]);
-}
-
-const char volume_params[SOUND_MIXER_NRDEVICES]= {
-/* Used by the ac97 driver */
- [SOUND_MIXER_VOLUME] = VOL_6BIT,
- [SOUND_MIXER_BASS] = VOL_4BIT,
- [SOUND_MIXER_TREBLE] = VOL_4BIT,
- [SOUND_MIXER_PCM] = VOL_5BIT,
- [SOUND_MIXER_SPEAKER] = VOL_4BIT,
- [SOUND_MIXER_LINE] = VOL_5BIT,
- [SOUND_MIXER_MIC] = VOL_5BIT,
- [SOUND_MIXER_CD] = VOL_5BIT,
- [SOUND_MIXER_ALTPCM] = VOL_6BIT,
- [SOUND_MIXER_IGAIN] = VOL_4BIT,
- [SOUND_MIXER_LINE1] = VOL_5BIT,
- [SOUND_MIXER_PHONEIN] = VOL_5BIT,
- [SOUND_MIXER_PHONEOUT] = VOL_6BIT,
- [SOUND_MIXER_VIDEO] = VOL_5BIT,
-/* Not used by the ac97 driver */
- [SOUND_MIXER_SYNTH] = VOL_5BIT,
- [SOUND_MIXER_IMIX] = VOL_5BIT,
- [SOUND_MIXER_RECLEV] = VOL_5BIT,
- [SOUND_MIXER_OGAIN] = VOL_5BIT,
- [SOUND_MIXER_LINE2] = VOL_5BIT,
- [SOUND_MIXER_LINE3] = VOL_5BIT,
- [SOUND_MIXER_DIGITAL1] = VOL_5BIT,
- [SOUND_MIXER_DIGITAL2] = VOL_5BIT,
- [SOUND_MIXER_DIGITAL3] = VOL_5BIT,
- [SOUND_MIXER_RADIO] = VOL_5BIT,
- [SOUND_MIXER_MONITOR] = VOL_5BIT
-};
-
-/* Mixer file operations */
-static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, unsigned long arg)
-{
- struct mixer_private_ioctl *ctl;
- struct dsp_patch *patch;
- u32 size, page;
- int addr, size_reg, i, ret;
- unsigned int id, ch;
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
-
- case SOUND_MIXER_PRIVATE3:
-
- ctl = kmalloc(sizeof(struct mixer_private_ioctl), GFP_KERNEL);
- if (ctl == NULL)
- return -ENOMEM;
-
- if (copy_from_user(ctl, argp, sizeof(struct mixer_private_ioctl))) {
- kfree(ctl);
- return -EFAULT;
- }
-
- ret = 0;
- switch (ctl->cmd) {
-#ifdef DBGEMU
- case CMD_WRITEFN0:
- emu10k1_writefn0_2(card, ctl->val[0], ctl->val[1], ctl->val[2]);
- break;
-#endif
- case CMD_WRITEPTR:
-#ifdef DBGEMU
- if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000) {
-#else
- if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000 || ((ctl->val[0] < 0x100 ) &&
- //Any register allowed raw access goes here:
- (ctl->val[0] != A_SPDIF_SAMPLERATE) && (ctl->val[0] != A_DBG)
- )
- ) {
-#endif
- ret = -EINVAL;
- break;
- }
- sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]);
- break;
-
- case CMD_READFN0:
- ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]);
-
- if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
- ret = -EFAULT;
-
- break;
-
- case CMD_READPTR:
- if (ctl->val[1] >= 0x40 || (ctl->val[0] & 0x7ff) > 0xff) {
- ret = -EINVAL;
- break;
- }
-
- if ((ctl->val[0] & 0x7ff) > 0x3f)
- ctl->val[1] = 0x00;
-
- ctl->val[2] = sblive_readptr(card, ctl->val[0], ctl->val[1]);
-
- if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
- ret = -EFAULT;
-
- break;
-
- case CMD_SETRECSRC:
- switch (ctl->val[0]) {
- case WAVERECORD_AC97:
- if (card->is_aps) {
- ret = -EINVAL;
- break;
- }
-
- card->wavein.recsrc = WAVERECORD_AC97;
- break;
-
- case WAVERECORD_MIC:
- card->wavein.recsrc = WAVERECORD_MIC;
- break;
-
- case WAVERECORD_FX:
- card->wavein.recsrc = WAVERECORD_FX;
- card->wavein.fxwc = ctl->val[1] & 0xffff;
-
- if (!card->wavein.fxwc)
- ret = -EINVAL;
-
- break;
-
- default:
- ret = -EINVAL;
- break;
- }
- break;
-
- case CMD_GETRECSRC:
- ctl->val[0] = card->wavein.recsrc;
- ctl->val[1] = card->wavein.fxwc;
- if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
- ret = -EFAULT;
-
- break;
-
- case CMD_GETVOICEPARAM:
- ctl->val[0] = card->waveout.send_routing[0];
- ctl->val[1] = card->waveout.send_dcba[0];
-
- ctl->val[2] = card->waveout.send_routing[1];
- ctl->val[3] = card->waveout.send_dcba[1];
-
- ctl->val[4] = card->waveout.send_routing[2];
- ctl->val[5] = card->waveout.send_dcba[2];
-
- if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
- ret = -EFAULT;
-
- break;
-
- case CMD_SETVOICEPARAM:
- card->waveout.send_routing[0] = ctl->val[0];
- card->waveout.send_dcba[0] = ctl->val[1];
-
- card->waveout.send_routing[1] = ctl->val[2];
- card->waveout.send_dcba[1] = ctl->val[3];
-
- card->waveout.send_routing[2] = ctl->val[4];
- card->waveout.send_dcba[2] = ctl->val[5];
-
- break;
-
- case CMD_SETMCH_FX:
- card->mchannel_fx = ctl->val[0] & 0x000f;
- break;
-
- case CMD_GETPATCH:
- if (ctl->val[0] == 0) {
- if (copy_to_user(argp, &card->mgr.rpatch, sizeof(struct dsp_rpatch)))
- ret = -EFAULT;
- } else {
- if ((ctl->val[0] - 1) / PATCHES_PER_PAGE >= card->mgr.current_pages) {
- ret = -EINVAL;
- break;
- }
-
- if (copy_to_user(argp, PATCH(&card->mgr, ctl->val[0] - 1), sizeof(struct dsp_patch)))
- ret = -EFAULT;
- }
-
- break;
-
- case CMD_GETGPR:
- id = ctl->val[0];
-
- if (id > NUM_GPRS) {
- ret = -EINVAL;
- break;
- }
-
- if (copy_to_user(argp, &card->mgr.gpr[id], sizeof(struct dsp_gpr)))
- ret = -EFAULT;
-
- break;
-
- case CMD_GETCTLGPR:
- addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, &((char *) ctl->val)[PATCH_NAME_SIZE]);
- ctl->val[0] = sblive_readptr(card, addr, 0);
-
- if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
- ret = -EFAULT;
-
- break;
-
- case CMD_SETPATCH:
- if (ctl->val[0] == 0)
- memcpy(&card->mgr.rpatch, &ctl->val[1], sizeof(struct dsp_rpatch));
- else {
- page = (ctl->val[0] - 1) / PATCHES_PER_PAGE;
- if (page > MAX_PATCHES_PAGES) {
- ret = -EINVAL;
- break;
- }
-
- if (page >= card->mgr.current_pages) {
- for (i = card->mgr.current_pages; i < page + 1; i++) {
- card->mgr.patch[i] = (void *)__get_free_page(GFP_KERNEL);
- if(card->mgr.patch[i] == NULL) {
- card->mgr.current_pages = i;
- ret = -ENOMEM;
- break;
- }
- memset(card->mgr.patch[i], 0, PAGE_SIZE);
- }
- card->mgr.current_pages = page + 1;
- }
-
- patch = PATCH(&card->mgr, ctl->val[0] - 1);
-
- memcpy(patch, &ctl->val[1], sizeof(struct dsp_patch));
-
- if (patch->code_size == 0) {
- for(i = page + 1; i < card->mgr.current_pages; i++)
- free_page((unsigned long) card->mgr.patch[i]);
-
- card->mgr.current_pages = page + 1;
- }
- }
- break;
-
- case CMD_SETGPR:
- if (ctl->val[0] > NUM_GPRS) {
- ret = -EINVAL;
- break;
- }
-
- memcpy(&card->mgr.gpr[ctl->val[0]], &ctl->val[1], sizeof(struct dsp_gpr));
- break;
-
- case CMD_SETCTLGPR:
- addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, (char *) ctl->val + PATCH_NAME_SIZE);
- emu10k1_set_control_gpr(card, addr, *((s32 *)((char *) ctl->val + 2 * PATCH_NAME_SIZE)), 0);
- break;
-
- case CMD_SETGPOUT:
- if ( ((ctl->val[0] > 2) && (!card->is_audigy))
- || (ctl->val[0] > 15) || ctl->val[1] > 1) {
- ret= -EINVAL;
- break;
- }
-
- if (card->is_audigy)
- emu10k1_writefn0(card, (1 << 24) | ((ctl->val[0]) << 16) | A_IOCFG, ctl->val[1]);
- else
- emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]);
- break;
-
- case CMD_GETGPR2OSS:
- id = ctl->val[0];
- ch = ctl->val[1];
-
- if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) {
- ret = -EINVAL;
- break;
- }
-
- ctl->val[2] = card->mgr.ctrl_gpr[id][ch];
-
- if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
- ret = -EFAULT;
-
- break;
-
- case CMD_SETGPR2OSS:
- id = ctl->val[0];
- /* 0 == left, 1 == right */
- ch = ctl->val[1];
- addr = ctl->val[2];
-
- if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) {
- ret = -EINVAL;
- break;
- }
-
- card->mgr.ctrl_gpr[id][ch] = addr;
-
- if (card->is_aps)
- break;
-
- if (addr >= 0) {
- unsigned int state = card->ac97->mixer_state[id];
-
- if (ch == 1) {
- state >>= 8;
- card->ac97->stereo_mixers |= (1 << id);
- }
-
- card->ac97->supported_mixers |= (1 << id);
-
- if (id == SOUND_MIXER_TREBLE) {
- set_treble(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff);
- } else if (id == SOUND_MIXER_BASS) {
- set_bass(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff);
- } else
- emu10k1_set_volume_gpr(card, addr, state & 0xff,
- volume_params[id]);
- } else {
- card->ac97->stereo_mixers &= ~(1 << id);
- card->ac97->stereo_mixers |= card->ac97_stereo_mixers;
-
- if (ch == 0) {
- card->ac97->supported_mixers &= ~(1 << id);
- card->ac97->supported_mixers |= card->ac97_supported_mixers;
- }
- }
- break;
-
- case CMD_SETPASSTHROUGH:
- card->pt.selected = ctl->val[0] ? 1 : 0;
- if (card->pt.state != PT_STATE_INACTIVE)
- break;
-
- card->pt.spcs_to_use = ctl->val[0] & 0x07;
- break;
-
- case CMD_PRIVATE3_VERSION:
- ctl->val[0] = PRIVATE3_VERSION; //private3 version
- ctl->val[1] = MAJOR_VER; //major driver version
- ctl->val[2] = MINOR_VER; //minor driver version
- ctl->val[3] = card->is_audigy; //1=card is audigy
-
- if (card->is_audigy)
- ctl->val[4]=emu10k1_readfn0(card, 0x18);
-
- if (copy_to_user(argp, ctl, sizeof(struct mixer_private_ioctl)))
- ret = -EFAULT;
- break;
-
- case CMD_AC97_BOOST:
- if (ctl->val[0])
- emu10k1_ac97_write(card->ac97, 0x18, 0x0);
- else
- emu10k1_ac97_write(card->ac97, 0x18, 0x0808);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- kfree(ctl);
- return ret;
- break;
-
- case SOUND_MIXER_PRIVATE4:
-
- if (copy_from_user(&size, argp, sizeof(size)))
- return -EFAULT;
-
- DPD(2, "External tram size %#x\n", size);
-
- if (size > 0x1fffff)
- return -EINVAL;
-
- size_reg = 0;
-
- if (size != 0) {
- size = (size - 1) >> 14;
-
- while (size) {
- size >>= 1;
- size_reg++;
- }
-
- size = 0x4000 << size_reg;
- }
-
- DPD(2, "External tram size %#x %#x\n", size, size_reg);
-
- if (size != card->tankmem.size) {
- if (card->tankmem.size > 0) {
- emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1);
-
- sblive_writeptr_tag(card, 0, TCB, 0, TCBS, 0, TAGLIST_END);
-
- pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle);
-
- card->tankmem.size = 0;
- }
-
- if (size != 0) {
- card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size, &card->tankmem.dma_handle);
- if (card->tankmem.addr == NULL)
- return -ENOMEM;
-
- card->tankmem.size = size;
-
- sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS,(u32) size_reg, TAGLIST_END);
-
- emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
- }
- }
- return 0;
- break;
-
- default:
- break;
- }
-
- return -EINVAL;
-}
-
-static int emu10k1_dsp_mixer(struct emu10k1_card *card, unsigned int oss_mixer, unsigned long arg)
-{
- unsigned int left, right;
- int val;
- int scale;
-
- card->ac97->modcnt++;
-
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
-
- /* cleanse input a little */
- right = ((val >> 8) & 0xff);
- left = (val & 0xff);
-
- if (right > 100) right = 100;
- if (left > 100) left = 100;
-
- card->ac97->mixer_state[oss_mixer] = (right << 8) | left;
- if (oss_mixer == SOUND_MIXER_TREBLE) {
- set_treble(card, left, right);
- return 0;
- } if (oss_mixer == SOUND_MIXER_BASS) {
- set_bass(card, left, right);
- return 0;
- }
-
- if (oss_mixer == SOUND_MIXER_VOLUME)
- scale = 1 << card->ac97->bit_resolution;
- else
- scale = volume_params[oss_mixer];
-
- emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left, scale);
- emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][1], right, scale);
-
- if (card->ac97_supported_mixers & (1 << oss_mixer))
- card->ac97->write_mixer(card->ac97, oss_mixer, left, right);
-
- return 0;
-}
-
-static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- int ret;
- struct emu10k1_card *card = file->private_data;
- unsigned int oss_mixer = _IOC_NR(cmd);
-
- ret = -EINVAL;
- if (!card->is_aps) {
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
-
- strlcpy(info.id, card->ac97->name, sizeof(info.id));
-
- if (card->is_audigy)
- strlcpy(info.name, "Audigy - Emu10k1", sizeof(info.name));
- else
- strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
-
- info.modify_counter = card->ac97->modcnt;
-
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
-
- return 0;
- }
-
- if ((_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) && oss_mixer <= SOUND_MIXER_NRDEVICES)
- ret = emu10k1_dsp_mixer(card, oss_mixer, arg);
- else
- ret = card->ac97->mixer_ioctl(card->ac97, cmd, arg);
- }
-
- if (ret < 0)
- ret = emu10k1_private_mixer(card, cmd, arg);
-
- return ret;
-}
-
-static int emu10k1_mixer_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct emu10k1_card *card = NULL;
- struct list_head *entry;
-
- DPF(4, "emu10k1_mixer_open()\n");
-
- list_for_each(entry, &emu10k1_devs) {
- card = list_entry(entry, struct emu10k1_card, list);
-
- if (card->ac97->dev_mixer == minor)
- goto match;
- }
-
- return -ENODEV;
-
- match:
- file->private_data = card;
- return 0;
-}
-
-static int emu10k1_mixer_release(struct inode *inode, struct file *file)
-{
- DPF(4, "emu10k1_mixer_release()\n");
- return 0;
-}
-
-const struct file_operations emu10k1_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = emu10k1_mixer_ioctl,
- .open = emu10k1_mixer_open,
- .release = emu10k1_mixer_release,
-};
diff --git a/sound/oss/emu10k1/passthrough.c b/sound/oss/emu10k1/passthrough.c
deleted file mode 100644
index 6d21d4368dec..000000000000
--- a/sound/oss/emu10k1/passthrough.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- **********************************************************************
- * passthrough.c -- Emu10k1 digital passthrough
- * Copyright (C) 2001 Juha Yrjölä <jyrjola@cc.hut.fi>
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * May 15, 2001 Juha Yrjölä base code release
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-#include <asm/io.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-
-#include "hwaccess.h"
-#include "cardwo.h"
-#include "cardwi.h"
-#include "recmgr.h"
-#include "irqmgr.h"
-#include "audio.h"
-#include "8010.h"
-
-static void pt_putsamples(struct pt_data *pt, u16 *ptr, u16 left, u16 right)
-{
- unsigned int idx;
-
- ptr[pt->copyptr] = left;
- idx = pt->copyptr + PT_SAMPLES/2;
- idx %= PT_SAMPLES;
- ptr[idx] = right;
-}
-
-static inline int pt_can_write(struct pt_data *pt)
-{
- return pt->blocks_copied < pt->blocks_played + 8;
-}
-
-static int pt_wait_for_write(struct emu10k1_wavedevice *wavedev, int nonblock)
-{
- struct emu10k1_card *card = wavedev->card;
- struct pt_data *pt = &card->pt;
-
- if (nonblock && !pt_can_write(pt))
- return -EAGAIN;
- while (!pt_can_write(pt) && pt->state != PT_STATE_INACTIVE) {
- interruptible_sleep_on(&pt->wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
- if (pt->state == PT_STATE_INACTIVE)
- return -EAGAIN;
-
- return 0;
-}
-
-static int pt_putblock(struct emu10k1_wavedevice *wave_dev, u16 *block, int nonblock)
-{
- struct woinst *woinst = wave_dev->woinst;
- struct emu10k1_card *card = wave_dev->card;
- struct pt_data *pt = &card->pt;
- u16 *ptr = (u16 *) card->tankmem.addr;
- int i = 0, r;
- unsigned long flags;
-
- r = pt_wait_for_write(wave_dev, nonblock);
- if (r < 0)
- return r;
- spin_lock_irqsave(&card->pt.lock, flags);
- while (i < PT_BLOCKSAMPLES) {
- pt_putsamples(pt, ptr, block[2*i], block[2*i+1]);
- if (pt->copyptr == 0)
- pt->copyptr = PT_SAMPLES;
- pt->copyptr--;
- i++;
- }
- woinst->total_copied += PT_BLOCKSIZE;
- pt->blocks_copied++;
- if (pt->blocks_copied >= 4 && pt->state != PT_STATE_PLAYING) {
- DPF(2, "activating digital pass-through playback\n");
- sblive_writeptr(card, GPR_BASE + pt->enable_gpr, 0, 1);
- pt->state = PT_STATE_PLAYING;
- }
- spin_unlock_irqrestore(&card->pt.lock, flags);
- return 0;
-}
-
-int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev)
-{
- u32 bits;
- struct emu10k1_card *card = wave_dev->card;
- struct pt_data *pt = &card->pt;
- int i;
-
- for (i = 0; i < 3; i++) {
- pt->old_spcs[i] = sblive_readptr(card, SPCS0 + i, 0);
- if (pt->spcs_to_use & (1 << i)) {
- DPD(2, "using S/PDIF port %d\n", i);
- bits = SPCS_CLKACCY_1000PPM | SPCS_SAMPLERATE_48 |
- SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS |
- 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT;
- if (pt->ac3data)
- bits |= SPCS_NOTAUDIODATA;
- sblive_writeptr(card, SPCS0 + i, 0, bits);
- }
- }
- return 0;
-}
-
-ssize_t emu10k1_pt_write(struct file *file, const char __user *buffer, size_t count)
-{
- struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
- struct emu10k1_card *card = wave_dev->card;
- struct pt_data *pt = &card->pt;
- int nonblock, i, r, blocks, blocks_copied, bytes_copied = 0;
-
- DPD(3, "emu10k1_pt_write(): %d bytes\n", count);
-
- nonblock = file->f_flags & O_NONBLOCK;
-
- if (card->tankmem.size < PT_SAMPLES*2)
- return -EFAULT;
- if (pt->state == PT_STATE_INACTIVE) {
- DPF(2, "bufptr init\n");
- pt->playptr = PT_SAMPLES-1;
- pt->copyptr = PT_INITPTR;
- pt->blocks_played = pt->blocks_copied = 0;
- memset(card->tankmem.addr, 0, card->tankmem.size);
- pt->state = PT_STATE_ACTIVATED;
- pt->buf = kmalloc(PT_BLOCKSIZE, GFP_KERNEL);
- pt->prepend_size = 0;
- if (pt->buf == NULL)
- return -ENOMEM;
- emu10k1_pt_setup(wave_dev);
- }
- if (pt->prepend_size) {
- int needed = PT_BLOCKSIZE - pt->prepend_size;
-
- DPD(3, "prepend size %d, prepending %d bytes\n", pt->prepend_size, needed);
- if (count < needed) {
- if (copy_from_user(pt->buf + pt->prepend_size,
- buffer, count))
- return -EFAULT;
- pt->prepend_size += count;
- DPD(3, "prepend size now %d\n", pt->prepend_size);
- return count;
- }
- if (copy_from_user(pt->buf + pt->prepend_size, buffer, needed))
- return -EFAULT;
- r = pt_putblock(wave_dev, (u16 *) pt->buf, nonblock);
- if (r)
- return r;
- bytes_copied += needed;
- pt->prepend_size = 0;
- }
- blocks = (count-bytes_copied)/PT_BLOCKSIZE;
- blocks_copied = 0;
- while (blocks > 0) {
- u16 __user *bufptr = (u16 __user *) buffer + (bytes_copied/2);
- if (copy_from_user(pt->buf, bufptr, PT_BLOCKSIZE))
- return -EFAULT;
- r = pt_putblock(wave_dev, (u16 *)pt->buf, nonblock);
- if (r) {
- if (bytes_copied)
- return bytes_copied;
- else
- return r;
- }
- bytes_copied += PT_BLOCKSIZE;
- blocks--;
- blocks_copied++;
- }
- i = count - bytes_copied;
- if (i) {
- pt->prepend_size = i;
- if (copy_from_user(pt->buf, buffer + bytes_copied, i))
- return -EFAULT;
- bytes_copied += i;
- DPD(3, "filling prepend buffer with %d bytes", i);
- }
- return bytes_copied;
-}
-
-void emu10k1_pt_stop(struct emu10k1_card *card)
-{
- struct pt_data *pt = &card->pt;
- int i;
-
- if (pt->state != PT_STATE_INACTIVE) {
- DPF(2, "digital pass-through stopped\n");
- sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 0);
- for (i = 0; i < 3; i++) {
- if (pt->spcs_to_use & (1 << i))
- sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
- }
- pt->state = PT_STATE_INACTIVE;
- kfree(pt->buf);
- }
-}
-
-void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev)
-{
- struct woinst *woinst = wave_dev->woinst;
- struct pt_data *pt = &wave_dev->card->pt;
- u32 pos;
-
- if (pt->state == PT_STATE_PLAYING && pt->pos_gpr >= 0) {
- pos = sblive_readptr(wave_dev->card, GPR_BASE + pt->pos_gpr, 0);
- if (pos > PT_BLOCKSAMPLES)
- pos = PT_BLOCKSAMPLES;
- pos = 4 * (PT_BLOCKSAMPLES - pos);
- } else
- pos = 0;
- woinst->total_played = pt->blocks_played * woinst->buffer.fragment_size + pos;
- woinst->buffer.hw_pos = pos;
-}
diff --git a/sound/oss/emu10k1/passthrough.h b/sound/oss/emu10k1/passthrough.h
deleted file mode 100644
index 420cc9784251..000000000000
--- a/sound/oss/emu10k1/passthrough.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- **********************************************************************
- * passthrough.h -- Emu10k1 digital passthrough header file
- * Copyright (C) 2001 Juha Yrjölä <jyrjola@cc.hut.fi>
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * May 15, 2001 Juha Yrjölä base code release
- *
- **********************************************************************
- *
- * 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 _PASSTHROUGH_H
-#define _PASSTHROUGH_H
-
-#include "audio.h"
-
-/* number of 16-bit stereo samples in XTRAM buffer */
-#define PT_SAMPLES 0x8000
-#define PT_BLOCKSAMPLES 0x400
-#define PT_BLOCKSIZE (PT_BLOCKSAMPLES*4)
-#define PT_BLOCKSIZE_LOG2 12
-#define PT_BLOCKCOUNT (PT_SAMPLES/PT_BLOCKSAMPLES)
-#define PT_INITPTR (PT_SAMPLES/2-1)
-
-#define PT_STATE_INACTIVE 0
-#define PT_STATE_ACTIVATED 1
-#define PT_STATE_PLAYING 2
-
-/* passthrough struct */
-struct pt_data
-{
- u8 selected, state, spcs_to_use;
- int intr_gpr, enable_gpr, pos_gpr;
- u32 blocks_played, blocks_copied, old_spcs[3];
- u32 playptr, copyptr;
- u32 prepend_size;
- u8 *buf;
- u8 ac3data;
-
- char *patch_name, *intr_gpr_name, *enable_gpr_name, *pos_gpr_name;
-
- wait_queue_head_t wait;
- spinlock_t lock;
-};
-
-/*
- Passthrough can be done in two methods:
-
- Method 1 : tram
- In original emu10k1, we couldn't bypass the sample rate converters. Even at 48kHz
- (the internal sample rate of the emu10k1) the samples would get messed up.
- To over come this, samples are copied into the tram and a special dsp patch copies
- the samples out and generates interrupts when a block has finnished playing.
-
- Method 2 : Interpolator bypass
-
- Creative fixed the sample rate convert problem in emu10k1 rev 7 and higher
- (including the emu10k2 (audigy)). This allows us to use the regular, and much simpler
- playback method.
-
-
- In both methods, dsp code is used to mux audio and passthrough. This ensures that the spdif
- doesn't receive audio and pasthrough data at the same time. The spdif flag SPCS_NOTAUDIODATA
- is set to tell
-
- */
-
-// emu10k1 revs greater than or equal to 7 can use method2
-
-#define USE_PT_METHOD2 (card->is_audigy)
-#define USE_PT_METHOD1 !USE_PT_METHOD2
-
-ssize_t emu10k1_pt_write(struct file *file, const char __user *buf, size_t count);
-
-int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev);
-void emu10k1_pt_stop(struct emu10k1_card *card);
-void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev);
-
-#endif /* _PASSTHROUGH_H */
diff --git a/sound/oss/emu10k1/recmgr.c b/sound/oss/emu10k1/recmgr.c
deleted file mode 100644
index 2ce56180e7d4..000000000000
--- a/sound/oss/emu10k1/recmgr.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- **********************************************************************
- * recmgr.c -- Recording manager for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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/delay.h>
-#include "8010.h"
-#include "recmgr.h"
-
-void emu10k1_reset_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
-{
- DPF(2, "emu10k1_reset_record()\n");
-
- sblive_writeptr(card, buffer->sizereg, 0, ADCBS_BUFSIZE_NONE);
-
- sblive_writeptr(card, buffer->sizereg, 0, buffer->sizeregval);
-
- while (sblive_readptr(card, buffer->idxreg, 0))
- udelay(5);
-}
-
-void emu10k1_start_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
-{
- DPF(2, "emu10k1_start_record()\n");
-
- if (buffer->adcctl)
- sblive_writeptr(card, ADCCR, 0, buffer->adcctl);
-}
-
-void emu10k1_stop_record(struct emu10k1_card *card, struct wavein_buffer *buffer)
-{
- DPF(2, "emu10k1_stop_record()\n");
-
- /* Disable record transfer */
- if (buffer->adcctl)
- sblive_writeptr(card, ADCCR, 0, 0);
-}
-
-void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
-{
- struct wavein_buffer *buffer = &wiinst->buffer;
-
- DPF(2, "emu10k1_set_record_src()\n");
-
- switch (wiinst->recsrc) {
-
- case WAVERECORD_AC97:
- DPF(2, "recording source: AC97\n");
- buffer->sizereg = ADCBS;
- buffer->addrreg = ADCBA;
- buffer->idxreg = card->is_audigy ? A_ADCIDX_IDX : ADCIDX_IDX;
-
- switch (wiinst->format.samplingrate) {
- case 0xBB80:
- buffer->adcctl = ADCCR_SAMPLERATE_48;
- break;
- case 0xAC44:
- buffer->adcctl = ADCCR_SAMPLERATE_44;
- break;
- case 0x7D00:
- buffer->adcctl = ADCCR_SAMPLERATE_32;
- break;
- case 0x5DC0:
- buffer->adcctl = ADCCR_SAMPLERATE_24;
- break;
- case 0x5622:
- buffer->adcctl = ADCCR_SAMPLERATE_22;
- break;
- case 0x3E80:
- buffer->adcctl = ADCCR_SAMPLERATE_16;
- break;
- // FIXME: audigy supports 12kHz recording
- /*
- case ????:
- buffer->adcctl = A_ADCCR_SAMPLERATE_12;
- break;
- */
- case 0x2B11:
- buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_11 : ADCCR_SAMPLERATE_11;
- break;
- case 0x1F40:
- buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_8 : ADCCR_SAMPLERATE_8;
- break;
- default:
- BUG();
- break;
- }
-
- buffer->adcctl |= card->is_audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
-
- if (wiinst->format.channels == 2)
- buffer->adcctl |= card->is_audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
-
- break;
-
- case WAVERECORD_MIC:
- DPF(2, "recording source: MIC\n");
- buffer->sizereg = MICBS;
- buffer->addrreg = MICBA;
- buffer->idxreg = MICIDX_IDX;
- buffer->adcctl = 0;
- break;
-
- case WAVERECORD_FX:
- DPF(2, "recording source: FX\n");
- buffer->sizereg = FXBS;
- buffer->addrreg = FXBA;
- buffer->idxreg = FXIDX_IDX;
- buffer->adcctl = 0;
-
- sblive_writeptr(card, FXWC, 0, wiinst->fxwc);
- break;
- default:
- BUG();
- break;
- }
-
- DPD(2, "bus addx: %#lx\n", (unsigned long) buffer->dma_handle);
-
- sblive_writeptr(card, buffer->addrreg, 0, (u32)buffer->dma_handle);
-}
diff --git a/sound/oss/emu10k1/recmgr.h b/sound/oss/emu10k1/recmgr.h
deleted file mode 100644
index a68766ac4fd5..000000000000
--- a/sound/oss/emu10k1/recmgr.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- **********************************************************************
- * recmgr.h
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _RECORDMGR_H
-#define _RECORDMGR_H
-
-#include "hwaccess.h"
-#include "cardwi.h"
-
-/* Recording resources */
-#define WAVERECORD_AC97 0x01
-#define WAVERECORD_MIC 0x02
-#define WAVERECORD_FX 0x03
-
-void emu10k1_reset_record(struct emu10k1_card *card, struct wavein_buffer *buffer);
-void emu10k1_start_record(struct emu10k1_card *, struct wavein_buffer *);
-void emu10k1_stop_record(struct emu10k1_card *, struct wavein_buffer *);
-void emu10k1_set_record_src(struct emu10k1_card *, struct wiinst *wiinst);
-
-#endif /* _RECORDMGR_H */
diff --git a/sound/oss/emu10k1/timer.c b/sound/oss/emu10k1/timer.c
deleted file mode 100644
index d10d30739f41..000000000000
--- a/sound/oss/emu10k1/timer.c
+++ /dev/null
@@ -1,176 +0,0 @@
-
-/*
- **********************************************************************
- * timer.c
- * Copyright (C) 1999, 2000 Creative Labs, 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., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-/* 3/6/2000 Improved support for different timer delays Rui Sousa */
-
-/* 4/3/2000 Implemented timer list using list.h Rui Sousa */
-
-#include "hwaccess.h"
-#include "8010.h"
-#include "irqmgr.h"
-#include "timer.h"
-
-/* Try to schedule only once per fragment */
-
-void emu10k1_timer_irqhandler(struct emu10k1_card *card)
-{
- struct emu_timer *t;
- struct list_head *entry;
-
- spin_lock(&card->timer_lock);
-
- list_for_each(entry, &card->timers) {
- t = list_entry(entry, struct emu_timer, list);
-
- if (t->state & TIMER_STATE_ACTIVE) {
- t->count++;
- if (t->count == t->count_max) {
- t->count = 0;
- tasklet_hi_schedule(&t->tasklet);
- }
- }
- }
-
- spin_unlock(&card->timer_lock);
-
- return;
-}
-
-void emu10k1_timer_install(struct emu10k1_card *card, struct emu_timer *timer, u16 delay)
-{
- struct emu_timer *t;
- struct list_head *entry;
- unsigned long flags;
-
- if (delay < 5)
- delay = 5;
-
- timer->delay = delay;
- timer->state = TIMER_STATE_INSTALLED;
-
- spin_lock_irqsave(&card->timer_lock, flags);
-
- timer->count_max = timer->delay / (card->timer_delay < 1024 ? card->timer_delay : 1024);
- timer->count = timer->count_max - 1;
-
- list_add(&timer->list, &card->timers);
-
- if (card->timer_delay > delay) {
- if (card->timer_delay == TIMER_STOPPED)
- emu10k1_irq_enable(card, INTE_INTERVALTIMERENB);
-
- card->timer_delay = delay;
- delay = (delay < 1024 ? delay : 1024);
-
- emu10k1_timer_set(card, delay);
-
- list_for_each(entry, &card->timers) {
- t = list_entry(entry, struct emu_timer, list);
-
- t->count_max = t->delay / delay;
- /* don't want to think much, just force scheduling
- on the next interrupt */
- t->count = t->count_max - 1;
- }
-
- DPD(2, "timer rate --> %u\n", delay);
- }
-
- spin_unlock_irqrestore(&card->timer_lock, flags);
-
- return;
-}
-
-void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer)
-{
- struct emu_timer *t;
- struct list_head *entry;
- u16 delay = TIMER_STOPPED;
- unsigned long flags;
-
- if (timer->state == TIMER_STATE_UNINSTALLED)
- return;
-
- spin_lock_irqsave(&card->timer_lock, flags);
-
- list_del(&timer->list);
-
- list_for_each(entry, &card->timers) {
- t = list_entry(entry, struct emu_timer, list);
-
- if (t->delay < delay)
- delay = t->delay;
- }
-
- if (card->timer_delay != delay) {
- card->timer_delay = delay;
-
- if (delay == TIMER_STOPPED)
- emu10k1_irq_disable(card, INTE_INTERVALTIMERENB);
- else {
- delay = (delay < 1024 ? delay : 1024);
-
- emu10k1_timer_set(card, delay);
-
- list_for_each(entry, &card->timers) {
- t = list_entry(entry, struct emu_timer, list);
-
- t->count_max = t->delay / delay;
- t->count = t->count_max - 1;
- }
- }
-
- DPD(2, "timer rate --> %u\n", delay);
- }
-
- spin_unlock_irqrestore(&card->timer_lock, flags);
-
- timer->state = TIMER_STATE_UNINSTALLED;
-
- return;
-}
-
-void emu10k1_timer_enable(struct emu10k1_card *card, struct emu_timer *timer)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->timer_lock, flags);
- timer->state |= TIMER_STATE_ACTIVE;
- spin_unlock_irqrestore(&card->timer_lock, flags);
-
- return;
-}
-
-void emu10k1_timer_disable(struct emu10k1_card *card, struct emu_timer *timer)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->timer_lock, flags);
- timer->state &= ~TIMER_STATE_ACTIVE;
- spin_unlock_irqrestore(&card->timer_lock, flags);
-
- return;
-}
diff --git a/sound/oss/emu10k1/timer.h b/sound/oss/emu10k1/timer.h
deleted file mode 100644
index b2543b4d53a8..000000000000
--- a/sound/oss/emu10k1/timer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- **********************************************************************
- * timer.h
- * Copyright (C) 1999, 2000 Creative Labs, 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., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- **********************************************************************
- */
-
-
-#ifndef _TIMER_H
-#define _TIMER_H
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include "hwaccess.h"
-
-struct emu_timer
-{
- struct list_head list;
- struct tasklet_struct tasklet;
- u8 state;
- u16 count; /* current number of interrupts */
- u16 count_max; /* number of interrupts needed to schedule the bh */
- u16 delay; /* timer delay */
-};
-
-void emu10k1_timer_install(struct emu10k1_card *, struct emu_timer *, u16);
-void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *);
-void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *);
-void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *);
-
-#define TIMER_STOPPED 0xffff
-#define TIMER_STATE_INSTALLED 0x01
-#define TIMER_STATE_ACTIVE 0x02
-#define TIMER_STATE_UNINSTALLED 0x04
-
-#endif /* _TIMER_H */
diff --git a/sound/oss/emu10k1/voicemgr.c b/sound/oss/emu10k1/voicemgr.c
deleted file mode 100644
index d88b602c07c2..000000000000
--- a/sound/oss/emu10k1/voicemgr.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
- **********************************************************************
- * voicemgr.c - Voice manager for emu10k1 driver
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 "voicemgr.h"
-#include "8010.h"
-
-#define PITCH_48000 0x00004000
-#define PITCH_96000 0x00008000
-#define PITCH_85000 0x00007155
-#define PITCH_80726 0x00006ba2
-#define PITCH_67882 0x00005a82
-#define PITCH_57081 0x00004c1c
-
-static u32 emu10k1_select_interprom(struct emu10k1_card *card,
- struct emu_voice *voice)
-{
- if(voice->pitch_target==PITCH_48000)
- return CCCA_INTERPROM_0;
- else if(voice->pitch_target<PITCH_48000)
- return CCCA_INTERPROM_1;
- else if(voice->pitch_target>=PITCH_96000)
- return CCCA_INTERPROM_0;
- else if(voice->pitch_target>=PITCH_85000)
- return CCCA_INTERPROM_6;
- else if(voice->pitch_target>=PITCH_80726)
- return CCCA_INTERPROM_5;
- else if(voice->pitch_target>=PITCH_67882)
- return CCCA_INTERPROM_4;
- else if(voice->pitch_target>=PITCH_57081)
- return CCCA_INTERPROM_3;
- else
- return CCCA_INTERPROM_2;
-}
-
-
-/**
- * emu10k1_voice_alloc_buffer -
- *
- * allocates the memory buffer for a voice. Two page tables are kept for each buffer.
- * One (dma_handle) keeps track of the host memory pages used and the other (virtualpagetable)
- * is passed to the device so that it can do DMA to host memory.
- *
- */
-int emu10k1_voice_alloc_buffer(struct emu10k1_card *card, struct voice_mem *mem, u32 pages)
-{
- u32 pageindex, pagecount;
- u32 busaddx;
- int i;
-
- DPD(2, "requested pages is: %d\n", pages);
-
- if ((mem->emupageindex = emu10k1_addxmgr_alloc(pages * PAGE_SIZE, card)) < 0)
- {
- DPF(1, "couldn't allocate emu10k1 address space\n");
- return -1;
- }
-
- /* Fill in virtual memory table */
- for (pagecount = 0; pagecount < pages; pagecount++) {
- if ((mem->addr[pagecount] = pci_alloc_consistent(card->pci_dev, PAGE_SIZE, &mem->dma_handle[pagecount]))
- == NULL) {
- mem->pages = pagecount;
- DPF(1, "couldn't allocate dma memory\n");
- return -1;
- }
-
- DPD(2, "Virtual Addx: %p\n", mem->addr[pagecount]);
-
- for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
- busaddx = (u32) mem->dma_handle[pagecount] + i * EMUPAGESIZE;
-
- DPD(3, "Bus Addx: %#x\n", busaddx);
-
- pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
-
- ((u32 *) card->virtualpagetable.addr)[pageindex] = cpu_to_le32((busaddx * 2) | pageindex);
- }
- }
-
- mem->pages = pagecount;
-
- return 0;
-}
-
-/**
- * emu10k1_voice_free_buffer -
- *
- * frees the memory buffer for a voice.
- */
-void emu10k1_voice_free_buffer(struct emu10k1_card *card, struct voice_mem *mem)
-{
- u32 pagecount, pageindex;
- int i;
-
- if (mem->emupageindex < 0)
- return;
-
- for (pagecount = 0; pagecount < mem->pages; pagecount++) {
- pci_free_consistent(card->pci_dev, PAGE_SIZE,
- mem->addr[pagecount],
- mem->dma_handle[pagecount]);
-
- for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
- pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
- ((u32 *) card->virtualpagetable.addr)[pageindex] =
- cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pageindex);
- }
- }
-
- emu10k1_addxmgr_free(card, mem->emupageindex);
- mem->emupageindex = -1;
-}
-
-int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice)
-{
- u8 *voicetable = card->voicetable;
- int i;
- unsigned long flags;
-
- DPF(2, "emu10k1_voice_alloc()\n");
-
- spin_lock_irqsave(&card->lock, flags);
-
- if (voice->flags & VOICE_FLAGS_STEREO) {
- for (i = 0; i < NUM_G; i += 2)
- if ((voicetable[i] == VOICE_USAGE_FREE) && (voicetable[i + 1] == VOICE_USAGE_FREE)) {
- voicetable[i] = voice->usage;
- voicetable[i + 1] = voice->usage;
- break;
- }
- } else {
- for (i = 0; i < NUM_G; i++)
- if (voicetable[i] == VOICE_USAGE_FREE) {
- voicetable[i] = voice->usage;
- break;
- }
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- if (i >= NUM_G)
- return -1;
-
- voice->card = card;
- voice->num = i;
-
- for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
- DPD(2, " voice allocated -> %d\n", voice->num + i);
-
- sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff,
- DCYSUSV, 0,
- VTFT, 0x0000ffff,
- PTRX, 0,
- TAGLIST_END);
- }
-
- return 0;
-}
-
-void emu10k1_voice_free(struct emu_voice *voice)
-{
- struct emu10k1_card *card = voice->card;
- int i;
- unsigned long flags;
-
- DPF(2, "emu10k1_voice_free()\n");
-
- if (voice->usage == VOICE_USAGE_FREE)
- return;
-
- for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
- DPD(2, " voice released -> %d\n", voice->num + i);
-
- sblive_writeptr_tag(card, voice->num + i, DCYSUSV, 0,
- VTFT, 0x0000ffff,
- PTRX_PITCHTARGET, 0,
- CVCF, 0x0000ffff,
- //CPF, 0,
- TAGLIST_END);
-
- sblive_writeptr(card, CPF, voice->num + i, 0);
- }
-
- voice->usage = VOICE_USAGE_FREE;
-
- spin_lock_irqsave(&card->lock, flags);
-
- card->voicetable[voice->num] = VOICE_USAGE_FREE;
-
- if (voice->flags & VOICE_FLAGS_STEREO)
- card->voicetable[voice->num + 1] = VOICE_USAGE_FREE;
-
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-void emu10k1_voice_playback_setup(struct emu_voice *voice)
-{
- struct emu10k1_card *card = voice->card;
- u32 start;
- int i;
-
- DPF(2, "emu10k1_voice_playback_setup()\n");
-
- if (voice->flags & VOICE_FLAGS_STEREO) {
- /* Set stereo bit */
- start = 28;
- sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
- sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
- } else {
- start = 30;
- sblive_writeptr(card, CPF, voice->num, 0);
- }
-
- if(!(voice->flags & VOICE_FLAGS_16BIT))
- start *= 2;
-
- voice->start += start;
-
- for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
- if (card->is_audigy) {
- sblive_writeptr(card, A_FXRT1, voice->num + i, voice->params[i].send_routing);
- sblive_writeptr(card, A_FXRT2, voice->num + i, voice->params[i].send_routing2);
- sblive_writeptr(card, A_SENDAMOUNTS, voice->num + i, voice->params[i].send_hgfe);
- } else {
- sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
- }
-
- /* Stop CA */
- /* Assumption that PT is already 0 so no harm overwriting */
- sblive_writeptr(card, PTRX, voice->num + i, ((voice->params[i].send_dcba & 0xff) << 8)
- | ((voice->params[i].send_dcba & 0xff00) >> 8));
-
- sblive_writeptr_tag(card, voice->num + i,
- /* CSL, ST, CA */
- DSL, voice->endloop | (voice->params[i].send_dcba & 0xff000000),
- PSST, voice->startloop | ((voice->params[i].send_dcba & 0x00ff0000) << 8),
- CCCA, (voice->start) | emu10k1_select_interprom(card,voice) |
- ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
- /* Clear filter delay memory */
- Z1, 0,
- Z2, 0,
- /* Invalidate maps */
- MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
- MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
- /* modulation envelope */
- CVCF, 0x0000ffff,
- VTFT, 0x0000ffff,
- ATKHLDM, 0,
- DCYSUSM, 0x007f,
- LFOVAL1, 0x8000,
- LFOVAL2, 0x8000,
- FMMOD, 0,
- TREMFRQ, 0,
- FM2FRQ2, 0,
- ENVVAL, 0x8000,
- /* volume envelope */
- ATKHLDV, 0x7f7f,
- ENVVOL, 0x8000,
- /* filter envelope */
- PEFE_FILTERAMOUNT, 0x7f,
- /* pitch envelope */
- PEFE_PITCHAMOUNT, 0, TAGLIST_END);
-
- voice->params[i].fc_target = 0xffff;
- }
-}
-
-void emu10k1_voices_start(struct emu_voice *first_voice, unsigned int num_voices, int set)
-{
- struct emu10k1_card *card = first_voice->card;
- struct emu_voice *voice;
- unsigned int voicenum;
- int j;
-
- DPF(2, "emu10k1_voices_start()\n");
-
- for (voicenum = 0; voicenum < num_voices; voicenum++)
- {
- voice = first_voice + voicenum;
-
- if (!set) {
- u32 cra, ccis, cs, sample;
- if (voice->flags & VOICE_FLAGS_STEREO) {
- cra = 64;
- ccis = 28;
- cs = 4;
- } else {
- cra = 64;
- ccis = 30;
- cs = 2;
- }
-
- if(voice->flags & VOICE_FLAGS_16BIT) {
- sample = 0x00000000;
- } else {
- sample = 0x80808080;
- ccis *= 2;
- }
-
- for(j = 0; j < cs; j++)
- sblive_writeptr(card, CD0 + j, voice->num, sample);
-
- /* Reset cache */
- sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, 0);
- if (voice->flags & VOICE_FLAGS_STEREO)
- sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num + 1, 0);
-
- sblive_writeptr(card, CCR_READADDRESS, voice->num, cra);
-
- if (voice->flags & VOICE_FLAGS_STEREO)
- sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra);
-
- /* Fill cache */
- sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis);
- }
-
- for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
- sblive_writeptr_tag(card, voice->num + j,
- IFATN, (voice->params[j].initial_fc << 8) | voice->params[j].initial_attn,
- VTFT, (voice->params[j].volume_target << 16) | voice->params[j].fc_target,
- CVCF, (voice->params[j].volume_target << 16) | voice->params[j].fc_target,
- DCYSUSV, (voice->params[j].byampl_env_sustain << 8) | voice->params[j].byampl_env_decay,
- TAGLIST_END);
-
- emu10k1_clear_stop_on_loop(card, voice->num + j);
- }
- }
-
-
- for (voicenum = 0; voicenum < num_voices; voicenum++)
- {
- voice = first_voice + voicenum;
-
- for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
- sblive_writeptr(card, PTRX_PITCHTARGET, voice->num + j, voice->pitch_target);
-
- if (j == 0)
- sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->pitch_target);
-
- sblive_writeptr(card, IP, voice->num + j, voice->initial_pitch);
- }
- }
-}
-
-void emu10k1_voices_stop(struct emu_voice *first_voice, int num_voices)
-{
- struct emu10k1_card *card = first_voice->card;
- struct emu_voice *voice;
- unsigned int voice_num;
- int j;
-
- DPF(2, "emu10k1_voice_stop()\n");
-
- for (voice_num = 0; voice_num < num_voices; voice_num++)
- {
- voice = first_voice + voice_num;
-
- for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
- sblive_writeptr_tag(card, voice->num + j,
- PTRX_PITCHTARGET, 0,
- CPF_CURRENTPITCH, 0,
- IFATN, 0xffff,
- VTFT, 0x0000ffff,
- CVCF, 0x0000ffff,
- IP, 0,
- TAGLIST_END);
- }
- }
-}
-
diff --git a/sound/oss/emu10k1/voicemgr.h b/sound/oss/emu10k1/voicemgr.h
deleted file mode 100644
index 099a8cb7f2c5..000000000000
--- a/sound/oss/emu10k1/voicemgr.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- **********************************************************************
- * sblive_voice.h -- EMU Voice Resource Manager header file
- * Copyright 1999, 2000 Creative Labs, Inc.
- *
- **********************************************************************
- *
- * Date Author Summary of changes
- * ---- ------ ------------------
- * October 20, 1999 Bertrand Lee base code release
- *
- **********************************************************************
- *
- * 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 _VOICEMGR_H
-#define _VOICEMGR_H
-
-#include "hwaccess.h"
-
-/* struct emu_voice.usage flags */
-#define VOICE_USAGE_FREE 0x01
-#define VOICE_USAGE_MIDI 0x02
-#define VOICE_USAGE_PLAYBACK 0x04
-
-/* struct emu_voice.flags flags */
-#define VOICE_FLAGS_STEREO 0x02
-#define VOICE_FLAGS_16BIT 0x04
-
-struct voice_param
-{
- /* FX bus amount send */
-
- u32 send_routing;
- // audigy only:
- u32 send_routing2;
-
- u32 send_dcba;
- // audigy only:
- u32 send_hgfe;
-
-
- u32 initial_fc;
- u32 fc_target;
-
- u32 initial_attn;
- u32 volume_target;
-
- u32 byampl_env_sustain;
- u32 byampl_env_decay;
-};
-
-struct voice_mem {
- int emupageindex;
- void *addr[BUFMAXPAGES];
- dma_addr_t dma_handle[BUFMAXPAGES];
- u32 pages;
-};
-
-struct emu_voice
-{
- struct emu10k1_card *card;
- u8 usage; /* Free, MIDI, playback */
- u8 num; /* Voice ID */
- u8 flags; /* Stereo/mono, 8/16 bit */
-
- u32 startloop;
- u32 endloop;
- u32 start;
-
- u32 initial_pitch;
- u32 pitch_target;
-
- struct voice_param params[2];
-
- struct voice_mem mem;
-};
-
-int emu10k1_voice_alloc_buffer(struct emu10k1_card *, struct voice_mem *, u32);
-void emu10k1_voice_free_buffer(struct emu10k1_card *, struct voice_mem *);
-int emu10k1_voice_alloc(struct emu10k1_card *, struct emu_voice *);
-void emu10k1_voice_free(struct emu_voice *);
-void emu10k1_voice_playback_setup(struct emu_voice *);
-void emu10k1_voices_start(struct emu_voice *, unsigned int, int);
-void emu10k1_voices_stop(struct emu_voice *, int);
-
-#endif /* _VOICEMGR_H */
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
index 593a3aac12ce..52648573f601 100644
--- a/sound/oss/es1371.c
+++ b/sound/oss/es1371.c
@@ -2894,7 +2894,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
s->irq = pcidev->irq;
s->vendor = pcidev->vendor;
s->device = pcidev->device;
- pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
+ s->rev = pcidev->revision;
s->codec->private_data = s;
s->codec->id = 0;
s->codec->codec_read = rdcodec;
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index 2796c0ef985f..a690ca57adb5 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -1003,7 +1003,8 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner)
}
if (!devc->shared_irq)
{
- if (request_irq(devc->irq, mpuintr, 0, "mpu401", (void *)m) < 0)
+ if (request_irq(devc->irq, mpuintr, 0, "mpu401",
+ hw_config) < 0)
{
printk(KERN_WARNING "mpu401: Failed to allocate IRQ%d\n", devc->irq);
ret = -ENOMEM;
@@ -1112,7 +1113,7 @@ int attach_mpu401(struct address_info *hw_config, struct module *owner)
return 0;
out_irq:
- free_irq(devc->irq, (void *)m);
+ free_irq(devc->irq, hw_config);
out_mididev:
sound_unload_mididev(m);
out_err:
@@ -1227,7 +1228,7 @@ void unload_mpu401(struct address_info *hw_config)
if (n != -1) {
release_region(hw_config->io_base, 2);
if (hw_config->always_detect == 0 && hw_config->irq > 0)
- free_irq(hw_config->irq, (void *)n);
+ free_irq(hw_config->irq, hw_config);
p=mpu401_synth_operations[n];
sound_unload_mididev(n);
sound_unload_timerdev(hw_config->slots[2]);
diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h
deleted file mode 100644
index 1dade9033995..000000000000
--- a/sound/oss/nm256.h
+++ /dev/null
@@ -1,292 +0,0 @@
-#ifndef _NM256_H_
-#define _NM256_H_
-
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-
-#include "ac97.h"
-
-/* The revisions that we currently handle. */
-enum nm256rev {
- REV_NM256AV, REV_NM256ZX
-};
-
-/* Per-card structure. */
-struct nm256_info
-{
- /* Magic number used to verify that this struct is valid. */
-#define NM_MAGIC_SIG 0x55aa00ff
- int magsig;
-
- /* Revision number */
- enum nm256rev rev;
-
- struct ac97_hwint mdev;
-
- /* Our audio device numbers. */
- int dev[2];
-
- /* The # of times each device has been opened. (Should only be
- 0 or 1). */
- int opencnt[2];
-
- /* We use two devices, because we can do simultaneous play and record.
- This keeps track of which device is being used for what purpose;
- these are the actual device numbers. */
- int dev_for_play;
- int dev_for_record;
-
- spinlock_t lock;
-
- /* The mixer device. */
- int mixer_oss_dev;
-
- /*
- * Can only be opened once for each operation. These aren't set
- * until an actual I/O operation is performed; this allows one
- * device to be open for read/write without inhibiting I/O to
- * the other device.
- */
- int is_open_play;
- int is_open_record;
-
- /* Non-zero if we're currently playing a sample. */
- int playing;
- /* Ditto for recording a sample. */
- int recording;
-
- /* The two memory ports. */
- struct nm256_ports {
- /* Physical address of the port. */
- u32 physaddr;
- /* Our mapped-in pointer. */
- char __iomem *ptr;
- /* PTR's offset within the physical port. */
- u32 start_offset;
- /* And the offset of the end of the buffer. */
- u32 end_offset;
- } port[2];
-
- /* The following are offsets within memory port 1. */
- u32 coeffBuf;
- u32 allCoeffBuf;
-
- /* Record and playback buffers. */
- u32 abuf1, abuf2;
-
- /* Offset of the AC97 mixer in memory port 2. */
- u32 mixer;
-
- /* Offset of the mixer status register in memory port 2. */
- u32 mixer_status_offset;
-
- /* Non-zero if we have written initial values to the mixer. */
- u8 mixer_values_init;
-
- /*
- * Status mask bit; (*mixer_status_loc & mixer_status_mask) == 0 means
- * it's ready.
- */
- u16 mixer_status_mask;
-
- /* The sizes of the playback and record ring buffers. */
- u32 playbackBufferSize;
- u32 recordBufferSize;
-
- /* Are the coefficient values in the memory cache current? */
- u8 coeffsCurrent;
-
- /* For writes, the amount we last wrote. */
- u32 requested_amt;
- /* The start of the block currently playing. */
- u32 curPlayPos;
-
- /* The amount of data we were requested to record. */
- u32 requestedRecAmt;
- /* The offset of the currently-recording block. */
- u32 curRecPos;
- /* The destination buffer. */
- char *recBuf;
-
- /* Our IRQ number. */
- int irq;
-
- /* A flag indicating how many times we've grabbed the IRQ. */
- int has_irq;
-
- /* The card interrupt service routine. */
- irq_handler_t introutine;
-
- /* Current audio config, cached. */
- struct sinfo {
- u32 samplerate;
- u8 bits;
- u8 stereo;
- } sinfo[2]; /* goes with each device */
-
- /* The cards are stored in a chain; this is the next card. */
- struct nm256_info *next_card;
-};
-
-/* The BIOS signature. */
-#define NM_SIGNATURE 0x4e4d0000
-/* Signature mask. */
-#define NM_SIG_MASK 0xffff0000
-
-/* Size of the second memory area. */
-#define NM_PORT2_SIZE 4096
-
-/* The base offset of the mixer in the second memory area. */
-#define NM_MIXER_OFFSET 0x600
-
-/* The maximum size of a coefficient entry. */
-#define NM_MAX_COEFFICIENT 0x5000
-
-/* The interrupt register. */
-#define NM_INT_REG 0xa04
-/* And its bits. */
-#define NM_PLAYBACK_INT 0x40
-#define NM_RECORD_INT 0x100
-#define NM_MISC_INT_1 0x4000
-#define NM_MISC_INT_2 0x1
-#define NM_ACK_INT(CARD, X) nm256_writePort16((CARD), 2, NM_INT_REG, (X) << 1)
-
-/* The AV's "mixer ready" status bit and location. */
-#define NM_MIXER_STATUS_OFFSET 0xa04
-#define NM_MIXER_READY_MASK 0x0800
-#define NM_MIXER_PRESENCE 0xa06
-#define NM_PRESENCE_MASK 0x0050
-#define NM_PRESENCE_VALUE 0x0040
-
-/*
- * For the ZX. It uses the same interrupt register, but it holds 32
- * bits instead of 16.
- */
-#define NM2_PLAYBACK_INT 0x10000
-#define NM2_RECORD_INT 0x80000
-#define NM2_MISC_INT_1 0x8
-#define NM2_MISC_INT_2 0x2
-#define NM2_ACK_INT(CARD, X) nm256_writePort32((CARD), 2, NM_INT_REG, (X))
-
-/* The ZX's "mixer ready" status bit and location. */
-#define NM2_MIXER_STATUS_OFFSET 0xa06
-#define NM2_MIXER_READY_MASK 0x0800
-
-/* The playback registers start from here. */
-#define NM_PLAYBACK_REG_OFFSET 0x0
-/* The record registers start from here. */
-#define NM_RECORD_REG_OFFSET 0x200
-
-/* The rate register is located 2 bytes from the start of the register area. */
-#define NM_RATE_REG_OFFSET 2
-
-/* Mono/stereo flag, number of bits on playback, and rate mask. */
-#define NM_RATE_STEREO 1
-#define NM_RATE_BITS_16 2
-#define NM_RATE_MASK 0xf0
-
-/* Playback enable register. */
-#define NM_PLAYBACK_ENABLE_REG (NM_PLAYBACK_REG_OFFSET + 0x1)
-#define NM_PLAYBACK_ENABLE_FLAG 1
-#define NM_PLAYBACK_ONESHOT 2
-#define NM_PLAYBACK_FREERUN 4
-
-/* Mutes the audio output. */
-#define NM_AUDIO_MUTE_REG (NM_PLAYBACK_REG_OFFSET + 0x18)
-#define NM_AUDIO_MUTE_LEFT 0x8000
-#define NM_AUDIO_MUTE_RIGHT 0x0080
-
-/* Recording enable register. */
-#define NM_RECORD_ENABLE_REG (NM_RECORD_REG_OFFSET + 0)
-#define NM_RECORD_ENABLE_FLAG 1
-#define NM_RECORD_FREERUN 2
-
-#define NM_RBUFFER_START (NM_RECORD_REG_OFFSET + 0x4)
-#define NM_RBUFFER_END (NM_RECORD_REG_OFFSET + 0x10)
-#define NM_RBUFFER_WMARK (NM_RECORD_REG_OFFSET + 0xc)
-#define NM_RBUFFER_CURRP (NM_RECORD_REG_OFFSET + 0x8)
-
-#define NM_PBUFFER_START (NM_PLAYBACK_REG_OFFSET + 0x4)
-#define NM_PBUFFER_END (NM_PLAYBACK_REG_OFFSET + 0x14)
-#define NM_PBUFFER_WMARK (NM_PLAYBACK_REG_OFFSET + 0xc)
-#define NM_PBUFFER_CURRP (NM_PLAYBACK_REG_OFFSET + 0x8)
-
-/* A few trivial routines to make it easier to work with the registers
- on the chip. */
-
-/* This is a common code portion used to fix up the port offsets. */
-#define NM_FIX_PORT \
- if (port < 1 || port > 2 || card == NULL) \
- return -1; \
-\
- if (offset < card->port[port - 1].start_offset \
- || offset >= card->port[port - 1].end_offset) { \
- printk (KERN_ERR "Bad access: port %d, offset 0x%x\n", port, offset); \
- return -1; \
- } \
- offset -= card->port[port - 1].start_offset;
-
-#define DEFwritePortX(X, func) \
-static inline int nm256_writePort##X (struct nm256_info *card,\
- int port, int offset, int value)\
-{\
- u##X __iomem *addr;\
-\
- if (nm256_debug > 1)\
- printk (KERN_DEBUG "Writing 0x%x to %d:0x%x\n", value, port, offset);\
-\
- NM_FIX_PORT;\
-\
- addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
- func (value, addr);\
- return 0;\
-}
-
-DEFwritePortX (8, writeb)
-DEFwritePortX (16, writew)
-DEFwritePortX (32, writel)
-
-#define DEFreadPortX(X, func) \
-static inline u##X nm256_readPort##X (struct nm256_info *card,\
- int port, int offset)\
-{\
- u##X __iomem *addr;\
-\
- NM_FIX_PORT\
-\
- addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
- return func(addr);\
-}
-
-DEFreadPortX (8, readb)
-DEFreadPortX (16, readw)
-DEFreadPortX (32, readl)
-
-static inline int
-nm256_writeBuffer8 (struct nm256_info *card, u8 *src, int port, int offset,
- int amt)
-{
- NM_FIX_PORT;
- memcpy_toio (card->port[port - 1].ptr + offset, src, amt);
- return 0;
-}
-
-static inline int
-nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset,
- int amt)
-{
- NM_FIX_PORT;
- memcpy_fromio (dst, card->port[port - 1].ptr + offset, amt);
- return 0;
-}
-
-/* Returns a non-zero value if we should use the coefficient cache. */
-static int nm256_cachedCoefficients (struct nm256_info *card);
-
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 4
- * End:
- */
diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
deleted file mode 100644
index 44cd15505001..000000000000
--- a/sound/oss/nm256_audio.c
+++ /dev/null
@@ -1,1662 +0,0 @@
-/*
- * Audio driver for the NeoMagic 256AV and 256ZX chipsets in native
- * mode, with AC97 mixer support.
- *
- * Overall design and parts of this code stolen from vidc_*.c and
- * skeleton.c.
- *
- * Yeah, there are a lot of magic constants in here. You tell ME what
- * they are. I just get this stuff psychically, remember?
- *
- * This driver was written by someone who wishes to remain anonymous.
- * It is in the public domain, so share and enjoy. Try to make a profit
- * off of it; go on, I dare you.
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added some __init
- * 19-04-2001 Marcus Meissner <mm@caldera.de>
- * Ported to 2.4 PCI API.
- */
-
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-static int nm256_debug;
-static int force_load;
-
-#include "nm256.h"
-#include "nm256_coeff.h"
-
-/*
- * The size of the playback reserve. When the playback buffer has less
- * than NM256_PLAY_WMARK_SIZE bytes to output, we request a new
- * buffer.
- */
-#define NM256_PLAY_WMARK_SIZE 512
-
-static struct audio_driver nm256_audio_driver;
-
-static int nm256_grabInterrupt (struct nm256_info *card);
-static int nm256_releaseInterrupt (struct nm256_info *card);
-static irqreturn_t nm256_interrupt (int irq, void *dev_id);
-static irqreturn_t nm256_interrupt_zx (int irq, void *dev_id);
-
-/* These belong in linux/pci.h. */
-#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
-#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
-#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016
-
-/* List of cards. */
-static struct nm256_info *nmcard_list;
-
-/* Release the mapped-in memory for CARD. */
-static void
-nm256_release_ports (struct nm256_info *card)
-{
- int x;
-
- for (x = 0; x < 2; x++) {
- if (card->port[x].ptr != NULL) {
- iounmap (card->port[x].ptr);
- card->port[x].ptr = NULL;
- }
- }
-}
-
-/*
- * Map in the memory ports for CARD, if they aren't already mapped in
- * and have been configured. If successful, a zero value is returned;
- * otherwise any previously mapped-in areas are released and a non-zero
- * value is returned.
- *
- * This is invoked twice, once for each port. Ideally it would only be
- * called once, but we now need to map in the second port in order to
- * check how much memory the card has on the 256ZX.
- */
-static int
-nm256_remap_ports (struct nm256_info *card)
-{
- int x;
-
- for (x = 0; x < 2; x++) {
- if (card->port[x].ptr == NULL && card->port[x].end_offset > 0) {
- u32 physaddr
- = card->port[x].physaddr + card->port[x].start_offset;
- u32 size
- = card->port[x].end_offset - card->port[x].start_offset;
-
- card->port[x].ptr = ioremap_nocache (physaddr, size);
-
- if (card->port[x].ptr == NULL) {
- printk (KERN_ERR "NM256: Unable to remap port %d\n", x + 1);
- nm256_release_ports (card);
- return -1;
- }
- }
- }
- return 0;
-}
-
-/* Locate the card in our list. */
-static struct nm256_info *
-nm256_find_card (int dev)
-{
- struct nm256_info *card;
-
- for (card = nmcard_list; card != NULL; card = card->next_card)
- if (card->dev[0] == dev || card->dev[1] == dev)
- return card;
-
- return NULL;
-}
-
-/*
- * Ditto, but find the card struct corresponding to the mixer device DEV
- * instead.
- */
-static struct nm256_info *
-nm256_find_card_for_mixer (int dev)
-{
- struct nm256_info *card;
-
- for (card = nmcard_list; card != NULL; card = card->next_card)
- if (card->mixer_oss_dev == dev)
- return card;
-
- return NULL;
-}
-
-static int usecache;
-static int buffertop;
-
-/* Check to see if we're using the bank of cached coefficients. */
-static int
-nm256_cachedCoefficients (struct nm256_info *card)
-{
- return usecache;
-}
-
-/* The actual rates supported by the card. */
-static int samplerates[9] = {
- 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999
-};
-
-/*
- * Set the card samplerate, word size and stereo mode to correspond to
- * the settings in the CARD struct for the specified device in DEV.
- * We keep two separate sets of information, one for each device; the
- * hardware is not actually configured until a read or write is
- * attempted.
- */
-
-static int
-nm256_setInfo (int dev, struct nm256_info *card)
-{
- int x;
- int w;
- int targetrate;
-
- if (card->dev[0] == dev)
- w = 0;
- else if (card->dev[1] == dev)
- w = 1;
- else
- return -ENODEV;
-
- targetrate = card->sinfo[w].samplerate;
-
- if ((card->sinfo[w].bits != 8 && card->sinfo[w].bits != 16)
- || targetrate < samplerates[0]
- || targetrate > samplerates[7])
- return -EINVAL;
-
- for (x = 0; x < 8; x++)
- if (targetrate < ((samplerates[x] + samplerates[x + 1]) / 2))
- break;
-
- if (x < 8) {
- u8 ratebits = ((x << 4) & NM_RATE_MASK);
- if (card->sinfo[w].bits == 16)
- ratebits |= NM_RATE_BITS_16;
- if (card->sinfo[w].stereo)
- ratebits |= NM_RATE_STEREO;
-
- card->sinfo[w].samplerate = samplerates[x];
-
-
- if (card->dev_for_play == dev && card->playing) {
- if (nm256_debug)
- printk (KERN_DEBUG "Setting play ratebits to 0x%x\n",
- ratebits);
- nm256_loadCoefficient (card, 0, x);
- nm256_writePort8 (card, 2,
- NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET,
- ratebits);
- }
-
- if (card->dev_for_record == dev && card->recording) {
- if (nm256_debug)
- printk (KERN_DEBUG "Setting record ratebits to 0x%x\n",
- ratebits);
- nm256_loadCoefficient (card, 1, x);
- nm256_writePort8 (card, 2,
- NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET,
- ratebits);
- }
- return 0;
- }
- else
- return -EINVAL;
-}
-
-/* Start the play process going. */
-static void
-startPlay (struct nm256_info *card)
-{
- if (! card->playing) {
- card->playing = 1;
- if (nm256_grabInterrupt (card) == 0) {
- nm256_setInfo (card->dev_for_play, card);
-
- /* Enable playback engine and interrupts. */
- nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG,
- NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN);
-
- /* Enable both channels. */
- nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG, 0x0);
- }
- }
-}
-
-/*
- * Request one chunk of AMT bytes from the recording device. When the
- * operation is complete, the data will be copied into BUFFER and the
- * function DMAbuf_inputintr will be invoked.
- */
-
-static void
-nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt)
-{
- u32 endpos;
- int enableEngine = 0;
- u32 ringsize = card->recordBufferSize;
- unsigned long flags;
-
- if (amt > (ringsize / 2)) {
- /*
- * Of course this won't actually work right, because the
- * caller is going to assume we will give what we got asked
- * for.
- */
- printk (KERN_ERR "NM256: Read request too large: %d\n", amt);
- amt = ringsize / 2;
- }
-
- if (amt < 8) {
- printk (KERN_ERR "NM256: Read request too small; %d\n", amt);
- return;
- }
-
- spin_lock_irqsave(&card->lock,flags);
- /*
- * If we're not currently recording, set up the start and end registers
- * for the recording engine.
- */
- if (! card->recording) {
- card->recording = 1;
- if (nm256_grabInterrupt (card) == 0) {
- card->curRecPos = 0;
- nm256_setInfo (card->dev_for_record, card);
- nm256_writePort32 (card, 2, NM_RBUFFER_START, card->abuf2);
- nm256_writePort32 (card, 2, NM_RBUFFER_END,
- card->abuf2 + ringsize);
-
- nm256_writePort32 (card, 2, NM_RBUFFER_CURRP,
- card->abuf2 + card->curRecPos);
- enableEngine = 1;
- }
- else {
- /* Not sure what else to do here. */
- spin_unlock_irqrestore(&card->lock,flags);
- return;
- }
- }
-
- /*
- * If we happen to go past the end of the buffer a bit (due to a
- * delayed interrupt) it's OK. So might as well set the watermark
- * right at the end of the data we want.
- */
- endpos = card->abuf2 + ((card->curRecPos + amt) % ringsize);
-
- card->recBuf = buffer;
- card->requestedRecAmt = amt;
- nm256_writePort32 (card, 2, NM_RBUFFER_WMARK, endpos);
- /* Enable recording engine and interrupts. */
- if (enableEngine)
- nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG,
- NM_RECORD_ENABLE_FLAG | NM_RECORD_FREERUN);
-
- spin_unlock_irqrestore(&card->lock,flags);
-}
-
-/* Stop the play engine. */
-static void
-stopPlay (struct nm256_info *card)
-{
- /* Shut off sound from both channels. */
- nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG,
- NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT);
- /* Disable play engine. */
- nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG, 0);
- if (card->playing) {
- nm256_releaseInterrupt (card);
-
- /* Reset the relevant state bits. */
- card->playing = 0;
- card->curPlayPos = 0;
- }
-}
-
-/* Stop recording. */
-static void
-stopRecord (struct nm256_info *card)
-{
- /* Disable recording engine. */
- nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG, 0);
-
- if (card->recording) {
- nm256_releaseInterrupt (card);
-
- card->recording = 0;
- card->curRecPos = 0;
- }
-}
-
-/*
- * Ring buffers, man. That's where the hip-hop, wild-n-wooly action's at.
- * 1972? (Well, I suppose it was cheep-n-easy to implement.)
- *
- * Write AMT bytes of BUFFER to the playback ring buffer, and start the
- * playback engine running. It will only accept up to 1/2 of the total
- * size of the ring buffer. No check is made that we're about to overwrite
- * the currently-playing sample.
- */
-
-static void
-nm256_write_block (struct nm256_info *card, char *buffer, u32 amt)
-{
- u32 ringsize = card->playbackBufferSize;
- u32 endstop;
- unsigned long flags;
-
- if (amt > (ringsize / 2)) {
- printk (KERN_ERR "NM256: Write request too large: %d\n", amt);
- amt = (ringsize / 2);
- }
-
- if (amt < NM256_PLAY_WMARK_SIZE) {
- printk (KERN_ERR "NM256: Write request too small: %d\n", amt);
- return;
- }
-
- card->curPlayPos %= ringsize;
-
- card->requested_amt = amt;
-
- spin_lock_irqsave(&card->lock,flags);
-
- if ((card->curPlayPos + amt) >= ringsize) {
- u32 rem = ringsize - card->curPlayPos;
-
- nm256_writeBuffer8 (card, buffer, 1,
- card->abuf1 + card->curPlayPos,
- rem);
- if (amt > rem)
- nm256_writeBuffer8 (card, buffer + rem, 1, card->abuf1,
- amt - rem);
- }
- else
- nm256_writeBuffer8 (card, buffer, 1,
- card->abuf1 + card->curPlayPos,
- amt);
-
- /*
- * Setup the start-n-stop-n-limit registers, and start that engine
- * goin'.
- *
- * Normally we just let it wrap around to avoid the click-click
- * action scene.
- */
- if (! card->playing) {
- /* The PBUFFER_END register in this case points to one sample
- before the end of the buffer. */
- int w = (card->dev_for_play == card->dev[0] ? 0 : 1);
- int sampsize = (card->sinfo[w].bits == 16 ? 2 : 1);
-
- if (card->sinfo[w].stereo)
- sampsize *= 2;
-
- /* Need to set the not-normally-changing-registers up. */
- nm256_writePort32 (card, 2, NM_PBUFFER_START,
- card->abuf1 + card->curPlayPos);
- nm256_writePort32 (card, 2, NM_PBUFFER_END,
- card->abuf1 + ringsize - sampsize);
- nm256_writePort32 (card, 2, NM_PBUFFER_CURRP,
- card->abuf1 + card->curPlayPos);
- }
- endstop = (card->curPlayPos + amt - NM256_PLAY_WMARK_SIZE) % ringsize;
- nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop);
-
- if (! card->playing)
- startPlay (card);
-
- spin_unlock_irqrestore(&card->lock,flags);
-}
-
-/* We just got a card playback interrupt; process it. */
-static void
-nm256_get_new_block (struct nm256_info *card)
-{
- /* Check to see how much got played so far. */
- u32 amt = nm256_readPort32 (card, 2, NM_PBUFFER_CURRP) - card->abuf1;
-
- if (amt >= card->playbackBufferSize) {
- printk (KERN_ERR "NM256: Sound playback pointer invalid!\n");
- amt = 0;
- }
-
- if (amt < card->curPlayPos)
- amt = (card->playbackBufferSize - card->curPlayPos) + amt;
- else
- amt -= card->curPlayPos;
-
- if (card->requested_amt > (amt + NM256_PLAY_WMARK_SIZE)) {
- u32 endstop =
- card->curPlayPos + card->requested_amt - NM256_PLAY_WMARK_SIZE;
- nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop);
- }
- else {
- card->curPlayPos += card->requested_amt;
- /* Get a new block to write. This will eventually invoke
- nm256_write_block () or stopPlay (). */
- DMAbuf_outputintr (card->dev_for_play, 1);
- }
-}
-
-/*
- * Read the last-recorded block from the ring buffer, copy it into the
- * saved buffer pointer, and invoke DMAuf_inputintr() with the recording
- * device.
- */
-
-static void
-nm256_read_block (struct nm256_info *card)
-{
- /* Grab the current position of the recording pointer. */
- u32 currptr = nm256_readPort32 (card, 2, NM_RBUFFER_CURRP) - card->abuf2;
- u32 amtToRead = card->requestedRecAmt;
- u32 ringsize = card->recordBufferSize;
-
- if (currptr >= card->recordBufferSize) {
- printk (KERN_ERR "NM256: Sound buffer record pointer invalid!\n");
- currptr = 0;
- }
-
- /*
- * This test is probably redundant; we shouldn't be here unless
- * it's true.
- */
- if (card->recording) {
- /* If we wrapped around, copy everything from the start of our
- recording buffer to the end of the buffer. */
- if (currptr < card->curRecPos) {
- u32 amt = min (ringsize - card->curRecPos, amtToRead);
-
- nm256_readBuffer8 (card, card->recBuf, 1,
- card->abuf2 + card->curRecPos,
- amt);
- amtToRead -= amt;
- card->curRecPos += amt;
- card->recBuf += amt;
- if (card->curRecPos == ringsize)
- card->curRecPos = 0;
- }
-
- if ((card->curRecPos < currptr) && (amtToRead > 0)) {
- u32 amt = min (currptr - card->curRecPos, amtToRead);
- nm256_readBuffer8 (card, card->recBuf, 1,
- card->abuf2 + card->curRecPos, amt);
- card->curRecPos = ((card->curRecPos + amt) % ringsize);
- }
- card->recBuf = NULL;
- card->requestedRecAmt = 0;
- DMAbuf_inputintr (card->dev_for_record);
- }
-}
-
-/*
- * Initialize the hardware.
- */
-static void
-nm256_initHw (struct nm256_info *card)
-{
- /* Reset everything. */
- nm256_writePort8 (card, 2, 0x0, 0x11);
- nm256_writePort16 (card, 2, 0x214, 0);
-
- stopRecord (card);
- stopPlay (card);
-}
-
-/*
- * Handle a potential interrupt for the device referred to by DEV_ID.
- *
- * I don't like the cut-n-paste job here either between the two routines,
- * but there are sufficient differences between the two interrupt handlers
- * that parameterizing it isn't all that great either. (Could use a macro,
- * I suppose...yucky bleah.)
- */
-
-static irqreturn_t
-nm256_interrupt (int irq, void *dev_id)
-{
- struct nm256_info *card = (struct nm256_info *)dev_id;
- u16 status;
- static int badintrcount;
- int handled = 0;
-
- if ((card == NULL) || (card->magsig != NM_MAGIC_SIG)) {
- printk (KERN_ERR "NM256: Bad card pointer\n");
- return IRQ_NONE;
- }
-
- status = nm256_readPort16 (card, 2, NM_INT_REG);
-
- /* Not ours. */
- if (status == 0) {
- if (badintrcount++ > 1000) {
- /*
- * I'm not sure if the best thing is to stop the card from
- * playing or just release the interrupt (after all, we're in
- * a bad situation, so doing fancy stuff may not be such a good
- * idea).
- *
- * I worry about the card engine continuing to play noise
- * over and over, however--that could become a very
- * obnoxious problem. And we know that when this usually
- * happens things are fairly safe, it just means the user's
- * inserted a PCMCIA card and someone's spamming us with IRQ 9s.
- */
-
- handled = 1;
- if (card->playing)
- stopPlay (card);
- if (card->recording)
- stopRecord (card);
- badintrcount = 0;
- }
- return IRQ_RETVAL(handled);
- }
-
- badintrcount = 0;
-
- /* Rather boring; check for individual interrupts and process them. */
-
- if (status & NM_PLAYBACK_INT) {
- handled = 1;
- status &= ~NM_PLAYBACK_INT;
- NM_ACK_INT (card, NM_PLAYBACK_INT);
-
- if (card->playing)
- nm256_get_new_block (card);
- }
-
- if (status & NM_RECORD_INT) {
- handled = 1;
- status &= ~NM_RECORD_INT;
- NM_ACK_INT (card, NM_RECORD_INT);
-
- if (card->recording)
- nm256_read_block (card);
- }
-
- if (status & NM_MISC_INT_1) {
- u8 cbyte;
-
- handled = 1;
- status &= ~NM_MISC_INT_1;
- printk (KERN_ERR "NM256: Got misc interrupt #1\n");
- NM_ACK_INT (card, NM_MISC_INT_1);
- nm256_writePort16 (card, 2, NM_INT_REG, 0x8000);
- cbyte = nm256_readPort8 (card, 2, 0x400);
- nm256_writePort8 (card, 2, 0x400, cbyte | 2);
- }
-
- if (status & NM_MISC_INT_2) {
- u8 cbyte;
-
- handled = 1;
- status &= ~NM_MISC_INT_2;
- printk (KERN_ERR "NM256: Got misc interrupt #2\n");
- NM_ACK_INT (card, NM_MISC_INT_2);
- cbyte = nm256_readPort8 (card, 2, 0x400);
- nm256_writePort8 (card, 2, 0x400, cbyte & ~2);
- }
-
- /* Unknown interrupt. */
- if (status) {
- handled = 1;
- printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n",
- status);
- /* Pray. */
- NM_ACK_INT (card, status);
- }
- return IRQ_RETVAL(handled);
-}
-
-/*
- * Handle a potential interrupt for the device referred to by DEV_ID.
- * This handler is for the 256ZX, and is very similar to the non-ZX
- * routine.
- */
-
-static irqreturn_t
-nm256_interrupt_zx (int irq, void *dev_id)
-{
- struct nm256_info *card = (struct nm256_info *)dev_id;
- u32 status;
- static int badintrcount;
- int handled = 0;
-
- if ((card == NULL) || (card->magsig != NM_MAGIC_SIG)) {
- printk (KERN_ERR "NM256: Bad card pointer\n");
- return IRQ_NONE;
- }
-
- status = nm256_readPort32 (card, 2, NM_INT_REG);
-
- /* Not ours. */
- if (status == 0) {
- if (badintrcount++ > 1000) {
- printk (KERN_ERR "NM256: Releasing interrupt, over 1000 invalid interrupts\n");
- /*
- * I'm not sure if the best thing is to stop the card from
- * playing or just release the interrupt (after all, we're in
- * a bad situation, so doing fancy stuff may not be such a good
- * idea).
- *
- * I worry about the card engine continuing to play noise
- * over and over, however--that could become a very
- * obnoxious problem. And we know that when this usually
- * happens things are fairly safe, it just means the user's
- * inserted a PCMCIA card and someone's spamming us with
- * IRQ 9s.
- */
-
- handled = 1;
- if (card->playing)
- stopPlay (card);
- if (card->recording)
- stopRecord (card);
- badintrcount = 0;
- }
- return IRQ_RETVAL(handled);
- }
-
- badintrcount = 0;
-
- /* Rather boring; check for individual interrupts and process them. */
-
- if (status & NM2_PLAYBACK_INT) {
- handled = 1;
- status &= ~NM2_PLAYBACK_INT;
- NM2_ACK_INT (card, NM2_PLAYBACK_INT);
-
- if (card->playing)
- nm256_get_new_block (card);
- }
-
- if (status & NM2_RECORD_INT) {
- handled = 1;
- status &= ~NM2_RECORD_INT;
- NM2_ACK_INT (card, NM2_RECORD_INT);
-
- if (card->recording)
- nm256_read_block (card);
- }
-
- if (status & NM2_MISC_INT_1) {
- u8 cbyte;
-
- handled = 1;
- status &= ~NM2_MISC_INT_1;
- printk (KERN_ERR "NM256: Got misc interrupt #1\n");
- NM2_ACK_INT (card, NM2_MISC_INT_1);
- cbyte = nm256_readPort8 (card, 2, 0x400);
- nm256_writePort8 (card, 2, 0x400, cbyte | 2);
- }
-
- if (status & NM2_MISC_INT_2) {
- u8 cbyte;
-
- handled = 1;
- status &= ~NM2_MISC_INT_2;
- printk (KERN_ERR "NM256: Got misc interrupt #2\n");
- NM2_ACK_INT (card, NM2_MISC_INT_2);
- cbyte = nm256_readPort8 (card, 2, 0x400);
- nm256_writePort8 (card, 2, 0x400, cbyte & ~2);
- }
-
- /* Unknown interrupt. */
- if (status) {
- handled = 1;
- printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n",
- status);
- /* Pray. */
- NM2_ACK_INT (card, status);
- }
- return IRQ_RETVAL(handled);
-}
-
-/*
- * Request our interrupt.
- */
-static int
-nm256_grabInterrupt (struct nm256_info *card)
-{
- if (card->has_irq++ == 0) {
- if (request_irq (card->irq, card->introutine, IRQF_SHARED,
- "NM256_audio", card) < 0) {
- printk (KERN_ERR "NM256: can't obtain IRQ %d\n", card->irq);
- return -1;
- }
- }
- return 0;
-}
-
-/*
- * Release our interrupt.
- */
-static int
-nm256_releaseInterrupt (struct nm256_info *card)
-{
- if (card->has_irq <= 0) {
- printk (KERN_ERR "nm256: too many calls to releaseInterrupt\n");
- return -1;
- }
- card->has_irq--;
- if (card->has_irq == 0) {
- free_irq (card->irq, card);
- }
- return 0;
-}
-
-/*
- * Waits for the mixer to become ready to be written; returns a zero value
- * if it timed out.
- */
-
-static int
-nm256_isReady (struct ac97_hwint *dev)
-{
- struct nm256_info *card = (struct nm256_info *)dev->driver_private;
- int t2 = 10;
- u32 testaddr;
- u16 testb;
- int done = 0;
-
- if (card->magsig != NM_MAGIC_SIG) {
- printk (KERN_ERR "NM256: Bad magic signature in isReady!\n");
- return 0;
- }
-
- testaddr = card->mixer_status_offset;
- testb = card->mixer_status_mask;
-
- /*
- * Loop around waiting for the mixer to become ready.
- */
- while (! done && t2-- > 0) {
- if ((nm256_readPort16 (card, 2, testaddr) & testb) == 0)
- done = 1;
- else
- udelay (100);
- }
- return done;
-}
-
-/*
- * Return the contents of the AC97 mixer register REG. Returns a positive
- * value if successful, or a negative error code.
- */
-static int
-nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg)
-{
- struct nm256_info *card = (struct nm256_info *)dev->driver_private;
-
- if (card->magsig != NM_MAGIC_SIG) {
- printk (KERN_ERR "NM256: Bad magic signature in readAC97Reg!\n");
- return -EINVAL;
- }
-
- if (reg < 128) {
- int res;
-
- nm256_isReady (dev);
- res = nm256_readPort16 (card, 2, card->mixer + reg);
- /* Magic delay. Bleah yucky. */
- udelay (1000);
- return res;
- }
- else
- return -EINVAL;
-}
-
-/*
- * Writes VALUE to AC97 mixer register REG. Returns 0 if successful, or
- * a negative error code.
- */
-static int
-nm256_writeAC97Reg (struct ac97_hwint *dev, u8 reg, u16 value)
-{
- unsigned long flags;
- int tries = 2;
- int done = 0;
- u32 base;
-
- struct nm256_info *card = (struct nm256_info *)dev->driver_private;
-
- if (card->magsig != NM_MAGIC_SIG) {
- printk (KERN_ERR "NM256: Bad magic signature in writeAC97Reg!\n");
- return -EINVAL;
- }
-
- base = card->mixer;
-
- spin_lock_irqsave(&card->lock,flags);
-
- nm256_isReady (dev);
-
- /* Wait for the write to take, too. */
- while ((tries-- > 0) && !done) {
- nm256_writePort16 (card, 2, base + reg, value);
- if (nm256_isReady (dev)) {
- done = 1;
- break;
- }
-
- }
-
- spin_unlock_irqrestore(&card->lock,flags);
- udelay (1000);
-
- return ! done;
-}
-
-/*
- * Initial register values to be written to the AC97 mixer.
- * While most of these are identical to the reset values, we do this
- * so that we have most of the register contents cached--this avoids
- * reading from the mixer directly (which seems to be problematic,
- * probably due to ignorance).
- */
-struct initialValues
-{
- unsigned short port;
- unsigned short value;
-};
-
-static struct initialValues nm256_ac97_initial_values[] =
-{
- { AC97_MASTER_VOL_STEREO, 0x8000 },
- { AC97_HEADPHONE_VOL, 0x8000 },
- { AC97_MASTER_VOL_MONO, 0x0000 },
- { AC97_PCBEEP_VOL, 0x0000 },
- { AC97_PHONE_VOL, 0x0008 },
- { AC97_MIC_VOL, 0x8000 },
- { AC97_LINEIN_VOL, 0x8808 },
- { AC97_CD_VOL, 0x8808 },
- { AC97_VIDEO_VOL, 0x8808 },
- { AC97_AUX_VOL, 0x8808 },
- { AC97_PCMOUT_VOL, 0x0808 },
- { AC97_RECORD_SELECT, 0x0000 },
- { AC97_RECORD_GAIN, 0x0B0B },
- { AC97_GENERAL_PURPOSE, 0x0000 },
- { 0xffff, 0xffff }
-};
-
-/* Initialize the AC97 into a known state. */
-static int
-nm256_resetAC97 (struct ac97_hwint *dev)
-{
- struct nm256_info *card = (struct nm256_info *)dev->driver_private;
- int x;
-
- if (card->magsig != NM_MAGIC_SIG) {
- printk (KERN_ERR "NM256: Bad magic signature in resetAC97!\n");
- return -EINVAL;
- }
-
- /* Reset the mixer. 'Tis magic! */
- nm256_writePort8 (card, 2, 0x6c0, 1);
-// nm256_writePort8 (card, 2, 0x6cc, 0x87); /* This crashes Dell latitudes */
- nm256_writePort8 (card, 2, 0x6cc, 0x80);
- nm256_writePort8 (card, 2, 0x6cc, 0x0);
-
- if (! card->mixer_values_init) {
- for (x = 0; nm256_ac97_initial_values[x].port != 0xffff; x++) {
- ac97_put_register (dev,
- nm256_ac97_initial_values[x].port,
- nm256_ac97_initial_values[x].value);
- card->mixer_values_init = 1;
- }
- }
-
- return 0;
-}
-
-/*
- * We don't do anything particularly special here; it just passes the
- * mixer ioctl to the AC97 driver.
- */
-static int
-nm256_default_mixer_ioctl (int dev, unsigned int cmd, void __user *arg)
-{
- struct nm256_info *card = nm256_find_card_for_mixer (dev);
- if (card != NULL)
- return ac97_mixer_ioctl (&(card->mdev), cmd, arg);
- else
- return -ENODEV;
-}
-
-static struct mixer_operations nm256_mixer_operations = {
- .owner = THIS_MODULE,
- .id = "NeoMagic",
- .name = "NM256AC97Mixer",
- .ioctl = nm256_default_mixer_ioctl
-};
-
-/*
- * Default settings for the OSS mixer. These are set last, after the
- * mixer is initialized.
- *
- * I "love" C sometimes. Got braces?
- */
-static struct ac97_mixer_value_list mixer_defaults[] = {
- { SOUND_MIXER_VOLUME, { { 85, 85 } } },
- { SOUND_MIXER_SPEAKER, { { 100 } } },
- { SOUND_MIXER_PCM, { { 65, 65 } } },
- { SOUND_MIXER_CD, { { 65, 65 } } },
- { -1, { { 0, 0 } } }
-};
-
-
-/* Installs the AC97 mixer into CARD. */
-static int __devinit
-nm256_install_mixer (struct nm256_info *card)
-{
- int mixer;
-
- card->mdev.reset_device = nm256_resetAC97;
- card->mdev.read_reg = nm256_readAC97Reg;
- card->mdev.write_reg = nm256_writeAC97Reg;
- card->mdev.driver_private = (void *)card;
-
- if (ac97_init (&(card->mdev)))
- return -1;
-
- mixer = sound_alloc_mixerdev();
- if (num_mixers >= MAX_MIXER_DEV) {
- printk ("NM256 mixer: Unable to alloc mixerdev\n");
- return -1;
- }
-
- mixer_devs[mixer] = &nm256_mixer_operations;
- card->mixer_oss_dev = mixer;
-
- /* Some reasonable default values. */
- ac97_set_values (&(card->mdev), mixer_defaults);
-
- printk(KERN_INFO "Initialized AC97 mixer\n");
- return 0;
-}
-
-/*
- * See if the signature left by the NM256 BIOS is intact; if so, we use
- * the associated address as the end of our audio buffer in the video
- * RAM.
- */
-
-static void __devinit
-nm256_peek_for_sig (struct nm256_info *card)
-{
- u32 port1offset
- = card->port[0].physaddr + card->port[0].end_offset - 0x0400;
- /* The signature is located 1K below the end of video RAM. */
- char __iomem *temp = ioremap_nocache (port1offset, 16);
- /* Default buffer end is 5120 bytes below the top of RAM. */
- u32 default_value = card->port[0].end_offset - 0x1400;
- u32 sig;
-
- /* Install the default value first, so we don't have to repeatedly
- do it if there is a problem. */
- card->port[0].end_offset = default_value;
-
- if (temp == NULL) {
- printk (KERN_ERR "NM256: Unable to scan for card signature in video RAM\n");
- return;
- }
- sig = readl (temp);
- if ((sig & NM_SIG_MASK) == NM_SIGNATURE) {
- u32 pointer = readl (temp + 4);
-
- /*
- * If it's obviously invalid, don't use it (the port already has a
- * suitable default value set).
- */
- if (pointer != 0xffffffff)
- card->port[0].end_offset = pointer;
-
- printk (KERN_INFO "NM256: Found card signature in video RAM: 0x%x\n",
- pointer);
- }
-
- iounmap (temp);
-}
-
-/*
- * Install a driver for the PCI device referenced by PCIDEV.
- * VERSTR is a human-readable version string.
- */
-
-static int __devinit
-nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
-{
- struct nm256_info *card;
- int x;
-
- if (pci_enable_device(pcidev))
- return 0;
-
- card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL);
- if (card == NULL) {
- printk (KERN_ERR "NM256: out of memory!\n");
- return 0;
- }
-
- card->magsig = NM_MAGIC_SIG;
- card->playing = 0;
- card->recording = 0;
- card->rev = rev;
- spin_lock_init(&card->lock);
-
- /* Init the memory port info. */
- for (x = 0; x < 2; x++) {
- card->port[x].physaddr = pci_resource_start (pcidev, x);
- card->port[x].ptr = NULL;
- card->port[x].start_offset = 0;
- card->port[x].end_offset = 0;
- }
-
- /* Port 2 is easy. */
- card->port[1].start_offset = 0;
- card->port[1].end_offset = NM_PORT2_SIZE;
-
- /* Yuck. But we have to map in port 2 so we can check how much RAM the
- card has. */
- if (nm256_remap_ports (card)) {
- kfree (card);
- return 0;
- }
-
- /*
- * The NM256 has two memory ports. The first port is nothing
- * more than a chunk of video RAM, which is used as the I/O ring
- * buffer. The second port has the actual juicy stuff (like the
- * mixer and the playback engine control registers).
- */
-
- if (card->rev == REV_NM256AV) {
- /* Ok, try to see if this is a non-AC97 version of the hardware. */
- int pval = nm256_readPort16 (card, 2, NM_MIXER_PRESENCE);
- if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
- if (! force_load) {
- printk (KERN_ERR "NM256: This doesn't look to me like the AC97-compatible version.\n");
- printk (KERN_ERR " You can force the driver to load by passing in the module\n");
- printk (KERN_ERR " parameter:\n");
- printk (KERN_ERR " force_load = 1\n");
- printk (KERN_ERR "\n");
- printk (KERN_ERR " More likely, you should be using the appropriate SB-16 or\n");
- printk (KERN_ERR " CS4232 driver instead. (If your BIOS has settings for\n");
- printk (KERN_ERR " IRQ and/or DMA for the sound card, this is *not* the correct\n");
- printk (KERN_ERR " driver to use.)\n");
- nm256_release_ports (card);
- kfree (card);
- return 0;
- }
- else {
- printk (KERN_INFO "NM256: Forcing driver load as per user request.\n");
- }
- }
- else {
- /* printk (KERN_INFO "NM256: Congratulations. You're not running Eunice.\n")*/;
- }
- card->port[0].end_offset = 2560 * 1024;
- card->introutine = nm256_interrupt;
- card->mixer_status_offset = NM_MIXER_STATUS_OFFSET;
- card->mixer_status_mask = NM_MIXER_READY_MASK;
- }
- else {
- /* Not sure if there is any relevant detect for the ZX or not. */
- if (nm256_readPort8 (card, 2, 0xa0b) != 0)
- card->port[0].end_offset = 6144 * 1024;
- else
- card->port[0].end_offset = 4096 * 1024;
-
- card->introutine = nm256_interrupt_zx;
- card->mixer_status_offset = NM2_MIXER_STATUS_OFFSET;
- card->mixer_status_mask = NM2_MIXER_READY_MASK;
- }
-
- if (buffertop >= 98304 && buffertop < card->port[0].end_offset)
- card->port[0].end_offset = buffertop;
- else
- nm256_peek_for_sig (card);
-
- card->port[0].start_offset = card->port[0].end_offset - 98304;
-
- printk (KERN_INFO "NM256: Mapping port 1 from 0x%x - 0x%x\n",
- card->port[0].start_offset, card->port[0].end_offset);
-
- if (nm256_remap_ports (card)) {
- kfree (card);
- return 0;
- }
-
- /* See if we can get the interrupt. */
-
- card->irq = pcidev->irq;
- card->has_irq = 0;
-
- if (nm256_grabInterrupt (card) != 0) {
- nm256_release_ports (card);
- kfree (card);
- return 0;
- }
-
- nm256_releaseInterrupt (card);
-
- /*
- * Init the board.
- */
-
- card->playbackBufferSize = 16384;
- card->recordBufferSize = 16384;
-
- card->coeffBuf = card->port[0].end_offset - NM_MAX_COEFFICIENT;
- card->abuf2 = card->coeffBuf - card->recordBufferSize;
- card->abuf1 = card->abuf2 - card->playbackBufferSize;
- card->allCoeffBuf = card->abuf2 - (NM_TOTAL_COEFF_COUNT * 4);
-
- /* Fixed setting. */
- card->mixer = NM_MIXER_OFFSET;
- card->mixer_values_init = 0;
-
- card->is_open_play = 0;
- card->is_open_record = 0;
-
- card->coeffsCurrent = 0;
-
- card->opencnt[0] = 0; card->opencnt[1] = 0;
-
- /* Reasonable default settings, but largely unnecessary. */
- for (x = 0; x < 2; x++) {
- card->sinfo[x].bits = 8;
- card->sinfo[x].stereo = 0;
- card->sinfo[x].samplerate = 8000;
- }
-
- nm256_initHw (card);
-
- for (x = 0; x < 2; x++) {
- if ((card->dev[x] =
- sound_install_audiodrv(AUDIO_DRIVER_VERSION,
- "NM256", &nm256_audio_driver,
- sizeof(struct audio_driver),
- DMA_NODMA, AFMT_U8 | AFMT_S16_LE,
- NULL, -1, -1)) >= 0) {
- /* 1K minimum buffer size. */
- audio_devs[card->dev[x]]->min_fragment = 10;
- /* Maximum of 8K buffer size. */
- audio_devs[card->dev[x]]->max_fragment = 13;
- }
- else {
- printk(KERN_ERR "NM256: Too many PCM devices available\n");
- nm256_release_ports (card);
- kfree (card);
- return 0;
- }
- }
-
- pci_set_drvdata(pcidev,card);
-
- /* Insert the card in the list. */
- card->next_card = nmcard_list;
- nmcard_list = card;
-
- printk(KERN_INFO "Initialized NeoMagic %s audio in PCI native mode\n",
- verstr);
-
- /*
- * And our mixer. (We should allow support for other mixers, maybe.)
- */
-
- nm256_install_mixer (card);
-
- return 1;
-}
-
-
-static int __devinit
-nm256_probe(struct pci_dev *pcidev,const struct pci_device_id *pciid)
-{
- if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO)
- return nm256_install(pcidev, REV_NM256AV, "256AV");
- if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO)
- return nm256_install(pcidev, REV_NM256ZX, "256ZX");
- if (pcidev->device == PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO)
- return nm256_install(pcidev, REV_NM256ZX, "256XL+");
- return -1; /* should not come here ... */
-}
-
-static void __devinit
-nm256_remove(struct pci_dev *pcidev) {
- struct nm256_info *xcard = pci_get_drvdata(pcidev);
- struct nm256_info *card,*next_card = NULL;
-
- for (card = nmcard_list; card != NULL; card = next_card) {
- next_card = card->next_card;
- if (card == xcard) {
- stopPlay (card);
- stopRecord (card);
- if (card->has_irq)
- free_irq (card->irq, card);
- nm256_release_ports (card);
- sound_unload_mixerdev (card->mixer_oss_dev);
- sound_unload_audiodev (card->dev[0]);
- sound_unload_audiodev (card->dev[1]);
- kfree (card);
- break;
- }
- }
- if (nmcard_list == card)
- nmcard_list = next_card;
-}
-
-/*
- * Open the device
- *
- * DEV - device
- * MODE - mode to open device (logical OR of OPEN_READ and OPEN_WRITE)
- *
- * Called when opening the DMAbuf (dmabuf.c:259)
- */
-static int
-nm256_audio_open(int dev, int mode)
-{
- struct nm256_info *card = nm256_find_card (dev);
- int w;
-
- if (card == NULL)
- return -ENODEV;
-
- if (card->dev[0] == dev)
- w = 0;
- else if (card->dev[1] == dev)
- w = 1;
- else
- return -ENODEV;
-
- if (card->opencnt[w] > 0)
- return -EBUSY;
-
- /* No bits set? Huh? */
- if (! ((mode & OPEN_READ) || (mode & OPEN_WRITE)))
- return -EIO;
-
- /*
- * If it's open for both read and write, and the card's currently
- * being read or written to, then do the opposite of what has
- * already been done. Otherwise, don't specify any mode until the
- * user actually tries to do I/O. (Some programs open the device
- * for both read and write, but only actually do reading or writing.)
- */
-
- if ((mode & OPEN_WRITE) && (mode & OPEN_READ)) {
- if (card->is_open_play)
- mode = OPEN_WRITE;
- else if (card->is_open_record)
- mode = OPEN_READ;
- else mode = 0;
- }
-
- if (mode & OPEN_WRITE) {
- if (card->is_open_play == 0) {
- card->dev_for_play = dev;
- card->is_open_play = 1;
- }
- else
- return -EBUSY;
- }
-
- if (mode & OPEN_READ) {
- if (card->is_open_record == 0) {
- card->dev_for_record = dev;
- card->is_open_record = 1;
- }
- else
- return -EBUSY;
- }
-
- card->opencnt[w]++;
- return 0;
-}
-
-/*
- * Close the device
- *
- * DEV - device
- *
- * Called when closing the DMAbuf (dmabuf.c:477)
- * after halt_xfer
- */
-static void
-nm256_audio_close(int dev)
-{
- struct nm256_info *card = nm256_find_card (dev);
-
- if (card != NULL) {
- int w;
-
- if (card->dev[0] == dev)
- w = 0;
- else if (card->dev[1] == dev)
- w = 1;
- else
- return;
-
- card->opencnt[w]--;
- if (card->opencnt[w] <= 0) {
- card->opencnt[w] = 0;
-
- if (card->dev_for_play == dev) {
- stopPlay (card);
- card->is_open_play = 0;
- card->dev_for_play = -1;
- }
-
- if (card->dev_for_record == dev) {
- stopRecord (card);
- card->is_open_record = 0;
- card->dev_for_record = -1;
- }
- }
- }
-}
-
-/* Standard ioctl handler. */
-static int
-nm256_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int ret;
- u32 oldinfo;
- int w;
-
- struct nm256_info *card = nm256_find_card (dev);
-
- if (card == NULL)
- return -ENODEV;
-
- if (dev == card->dev[0])
- w = 0;
- else
- w = 1;
-
- /*
- * The code here is messy. There are probably better ways to do
- * it. (It should be possible to handle it the same way the AC97 mixer
- * is done.)
- */
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (get_user(ret, (int __user *) arg))
- return -EFAULT;
-
- if (ret != 0) {
- oldinfo = card->sinfo[w].samplerate;
- card->sinfo[w].samplerate = ret;
- ret = nm256_setInfo(dev, card);
- if (ret != 0)
- card->sinfo[w].samplerate = oldinfo;
- }
- if (ret == 0)
- ret = card->sinfo[w].samplerate;
- break;
-
- case SOUND_PCM_READ_RATE:
- ret = card->sinfo[w].samplerate;
- break;
-
- case SNDCTL_DSP_STEREO:
- if (get_user(ret, (int __user *) arg))
- return -EFAULT;
-
- card->sinfo[w].stereo = ret ? 1 : 0;
- ret = nm256_setInfo (dev, card);
- if (ret == 0)
- ret = card->sinfo[w].stereo;
-
- break;
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (get_user(ret, (int __user *) arg))
- return -EFAULT;
-
- if (ret < 1 || ret > 3)
- ret = card->sinfo[w].stereo + 1;
- else {
- card->sinfo[w].stereo = ret - 1;
- ret = nm256_setInfo (dev, card);
- if (ret == 0)
- ret = card->sinfo[w].stereo + 1;
- }
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- ret = card->sinfo[w].stereo + 1;
- break;
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(ret, (int __user *) arg))
- return -EFAULT;
-
- if (ret != 0) {
- oldinfo = card->sinfo[w].bits;
- card->sinfo[w].bits = ret;
- ret = nm256_setInfo (dev, card);
- if (ret != 0)
- card->sinfo[w].bits = oldinfo;
- }
- if (ret == 0)
- ret = card->sinfo[w].bits;
- break;
-
- case SOUND_PCM_READ_BITS:
- ret = card->sinfo[w].bits;
- break;
-
- default:
- return -EINVAL;
- }
- return put_user(ret, (int __user *) arg);
-}
-
-/*
- * Given the sound device DEV and an associated physical buffer PHYSBUF,
- * return a pointer to the actual buffer in kernel space.
- *
- * This routine should exist as part of the soundcore routines.
- */
-
-static char *
-nm256_getDMAbuffer (int dev, unsigned long physbuf)
-{
- struct audio_operations *adev = audio_devs[dev];
- struct dma_buffparms *dmap = adev->dmap_out;
- char *dma_start =
- (char *)(physbuf - (unsigned long)dmap->raw_buf_phys
- + (unsigned long)dmap->raw_buf);
-
- return dma_start;
-}
-
-
-/*
- * Output a block to sound device
- *
- * dev - device number
- * buf - physical address of buffer
- * total_count - total byte count in buffer
- * intrflag - set if this has been called from an interrupt
- * (via DMAbuf_outputintr)
- * restart_dma - set if engine needs to be re-initialised
- *
- * Called when:
- * 1. Starting output (dmabuf.c:1327)
- * 2. (dmabuf.c:1504)
- * 3. A new buffer needs to be sent to the device (dmabuf.c:1579)
- */
-static void
-nm256_audio_output_block(int dev, unsigned long physbuf,
- int total_count, int intrflag)
-{
- struct nm256_info *card = nm256_find_card (dev);
-
- if (card != NULL) {
- char *dma_buf = nm256_getDMAbuffer (dev, physbuf);
- card->is_open_play = 1;
- card->dev_for_play = dev;
- nm256_write_block (card, dma_buf, total_count);
- }
-}
-
-/* Ditto, but do recording instead. */
-static void
-nm256_audio_start_input(int dev, unsigned long physbuf, int count,
- int intrflag)
-{
- struct nm256_info *card = nm256_find_card (dev);
-
- if (card != NULL) {
- char *dma_buf = nm256_getDMAbuffer (dev, physbuf);
- card->is_open_record = 1;
- card->dev_for_record = dev;
- nm256_startRecording (card, dma_buf, count);
- }
-}
-
-/*
- * Prepare for inputting samples to DEV.
- * Each requested buffer will be BSIZE byes long, with a total of
- * BCOUNT buffers.
- */
-
-static int
-nm256_audio_prepare_for_input(int dev, int bsize, int bcount)
-{
- struct nm256_info *card = nm256_find_card (dev);
-
- if (card == NULL)
- return -ENODEV;
-
- if (card->is_open_record && card->dev_for_record != dev)
- return -EBUSY;
-
- audio_devs[dev]->dmap_in->flags |= DMA_NODMA;
- return 0;
-}
-
-/*
- * Prepare for outputting samples to `dev'
- *
- * Each buffer that will be passed will be `bsize' bytes long,
- * with a total of `bcount' buffers.
- *
- * Called when:
- * 1. A trigger enables audio output (dmabuf.c:978)
- * 2. We get a write buffer without dma_mode setup (dmabuf.c:1152)
- * 3. We restart a transfer (dmabuf.c:1324)
- */
-
-static int
-nm256_audio_prepare_for_output(int dev, int bsize, int bcount)
-{
- struct nm256_info *card = nm256_find_card (dev);
-
- if (card == NULL)
- return -ENODEV;
-
- if (card->is_open_play && card->dev_for_play != dev)
- return -EBUSY;
-
- audio_devs[dev]->dmap_out->flags |= DMA_NODMA;
- return 0;
-}
-
-/* Stop the current operations associated with DEV. */
-static void
-nm256_audio_reset(int dev)
-{
- struct nm256_info *card = nm256_find_card (dev);
-
- if (card != NULL) {
- if (card->dev_for_play == dev)
- stopPlay (card);
- if (card->dev_for_record == dev)
- stopRecord (card);
- }
-}
-
-static int
-nm256_audio_local_qlen(int dev)
-{
- return 0;
-}
-
-static struct audio_driver nm256_audio_driver =
-{
- .owner = THIS_MODULE,
- .open = nm256_audio_open,
- .close = nm256_audio_close,
- .output_block = nm256_audio_output_block,
- .start_input = nm256_audio_start_input,
- .ioctl = nm256_audio_ioctl,
- .prepare_for_input = nm256_audio_prepare_for_input,
- .prepare_for_output = nm256_audio_prepare_for_output,
- .halt_io = nm256_audio_reset,
- .local_qlen = nm256_audio_local_qlen,
-};
-
-static struct pci_device_id nm256_pci_tbl[] = {
- {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0},
- {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0},
- {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0},
- {0,}
-};
-MODULE_DEVICE_TABLE(pci, nm256_pci_tbl);
-MODULE_LICENSE("GPL");
-
-
-static struct pci_driver nm256_pci_driver = {
- .name = "nm256_audio",
- .id_table = nm256_pci_tbl,
- .probe = nm256_probe,
- .remove = nm256_remove,
-};
-
-module_param(usecache, bool, 0);
-module_param(buffertop, int, 0);
-module_param(nm256_debug, bool, 0644);
-module_param(force_load, bool, 0);
-
-static int __init do_init_nm256(void)
-{
- printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1p\n");
- return pci_register_driver(&nm256_pci_driver);
-}
-
-static void __exit cleanup_nm256 (void)
-{
- pci_unregister_driver(&nm256_pci_driver);
-}
-
-module_init(do_init_nm256);
-module_exit(cleanup_nm256);
-
-/*
- * Local variables:
- * c-basic-offset: 4
- * End:
- */
diff --git a/sound/oss/nm256_coeff.h b/sound/oss/nm256_coeff.h
deleted file mode 100644
index 6fc07f3cb33b..000000000000
--- a/sound/oss/nm256_coeff.h
+++ /dev/null
@@ -1,4697 +0,0 @@
-#ifndef NM256_COEFF_H
-#define NM256_COEFF_H
-
-#define NM_TOTAL_COEFF_COUNT 0x3158
-
-static char coefficients[NM_TOTAL_COEFF_COUNT * 4] = {
- 0xFF, 0xFF, 0x2F, 0x00, 0x4B, 0xFF, 0xA5, 0x01, 0xEF, 0xFC, 0x21,
- 0x05, 0x87, 0xF7, 0x62, 0x11, 0xE9, 0x45, 0x5E, 0xF9, 0xB5, 0x01,
- 0xDE, 0xFF, 0xA4, 0xFF, 0x60, 0x00, 0xCA, 0xFF, 0x0D, 0x00, 0xFD,
- 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3D, 0xFC, 0xD6, 0x06,
- 0x4C, 0xF3, 0xED, 0x20, 0x3D, 0x3D, 0x4A, 0xF3, 0x4E, 0x05, 0xB1,
- 0xFD, 0xE1, 0x00, 0xC3, 0xFF, 0x05, 0x00, 0x02, 0x00, 0xFD, 0xFF,
- 0x2A, 0x00, 0x5C, 0xFF, 0xAA, 0x01, 0x71, 0xFC, 0x07, 0x07, 0x7E,
- 0xF1, 0x44, 0x30, 0x44, 0x30, 0x7E, 0xF1, 0x07, 0x07, 0x71, 0xFC,
- 0xAA, 0x01, 0x5C, 0xFF, 0x2A, 0x00, 0xFD, 0xFF, 0x02, 0x00, 0x05,
- 0x00, 0xC3, 0xFF, 0xE1, 0x00, 0xB1, 0xFD, 0x4E, 0x05, 0x4A, 0xF3,
- 0x3D, 0x3D, 0xED, 0x20, 0x4C, 0xF3, 0xD6, 0x06, 0x3D, 0xFC, 0xE6,
- 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x0D, 0x00, 0xCA, 0xFF,
- 0x60, 0x00, 0xA4, 0xFF, 0xDE, 0xFF, 0xB5, 0x01, 0x5E, 0xF9, 0xE9,
- 0x45, 0x62, 0x11, 0x87, 0xF7, 0x21, 0x05, 0xEF, 0xFC, 0xA5, 0x01,
- 0x4B, 0xFF, 0x2F, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x1E, 0x00, 0x84,
- 0xFF, 0x11, 0x01, 0x34, 0xFE, 0x8F, 0x02, 0xC7, 0xFC, 0xAE, 0x03,
- 0xF7, 0x48, 0xAE, 0x03, 0xC7, 0xFC, 0x8F, 0x02, 0x34, 0xFE, 0x11,
- 0x01, 0x84, 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3D, 0xFF,
- 0xCA, 0x01, 0x95, 0xFC, 0xEA, 0x05, 0xBB, 0xF5, 0x25, 0x17, 0x3C,
- 0x43, 0x8D, 0xF6, 0x43, 0x03, 0xF5, 0xFE, 0x26, 0x00, 0x20, 0x00,
- 0xE2, 0xFF, 0x08, 0x00, 0xFD, 0xFF, 0x30, 0x00, 0x4D, 0xFF, 0xC5,
- 0x01, 0x4C, 0xFC, 0x26, 0x07, 0xA3, 0xF1, 0xAB, 0x2C, 0xBB, 0x33,
- 0x8F, 0xF1, 0xCA, 0x06, 0xA6, 0xFC, 0x85, 0x01, 0x6F, 0xFF, 0x24,
- 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFE, 0xFF, 0xD5, 0xFF, 0xBC, 0x00,
- 0xF0, 0xFD, 0xEC, 0x04, 0xD9, 0xF3, 0xB1, 0x3E, 0xCD, 0x1E, 0xC1,
- 0xF3, 0xAF, 0x06, 0x49, 0xFC, 0xE4, 0x01, 0x36, 0xFF, 0x36, 0x00,
- 0xFE, 0xFF, 0x16, 0x00, 0xA6, 0xFF, 0xBB, 0x00, 0xE9, 0xFE, 0x38,
- 0x01, 0x4B, 0xFF, 0x28, 0xFE, 0x3A, 0x48, 0x04, 0x0A, 0x2E, 0xFA,
- 0xDF, 0x03, 0x8A, 0xFD, 0x60, 0x01, 0x65, 0xFF, 0x27, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x2E, 0x00, 0x50, 0xFF, 0x98, 0x01, 0x0D, 0xFD,
- 0xE0, 0x04, 0x14, 0xF8, 0xC3, 0x0F, 0x89, 0x46, 0x4C, 0xFA, 0x38,
- 0x01, 0x25, 0x00, 0x7D, 0xFF, 0x73, 0x00, 0xC2, 0xFF, 0x0F, 0x00,
- 0xFD, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xE3, 0x01, 0x31, 0xFC, 0x0F,
- 0x07, 0x84, 0xF2, 0x29, 0x25, 0x1A, 0x3A, 0x67, 0xF2, 0xF6, 0x05,
- 0x41, 0xFD, 0x24, 0x01, 0xA1, 0xFF, 0x12, 0x00, 0x00, 0x00, 0xFF,
- 0xFF, 0x15, 0x00, 0x97, 0xFF, 0x37, 0x01, 0x22, 0xFD, 0x23, 0x06,
- 0x2F, 0xF2, 0x11, 0x39, 0x7B, 0x26, 0x50, 0xF2, 0x1B, 0x07, 0x32,
- 0xFC, 0xE1, 0x01, 0x3C, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x0E, 0x00,
- 0xC8, 0xFF, 0x64, 0x00, 0x9B, 0xFF, 0xEE, 0xFF, 0x98, 0x01, 0x93,
- 0xF9, 0x10, 0x46, 0x03, 0x11, 0xA7, 0xF7, 0x12, 0x05, 0xF6, 0xFC,
- 0xA2, 0x01, 0x4C, 0xFF, 0x2F, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x26,
- 0x00, 0x6A, 0xFF, 0x53, 0x01, 0xA6, 0xFD, 0xA6, 0x03, 0xA1, 0xFA,
- 0xDE, 0x08, 0x76, 0x48, 0x0C, 0xFF, 0xDE, 0xFE, 0x73, 0x01, 0xC9,
- 0xFE, 0xCA, 0x00, 0xA0, 0xFF, 0x17, 0x00, 0xFE, 0xFF, 0x36, 0x00,
- 0x36, 0xFF, 0xE1, 0x01, 0x52, 0xFC, 0x93, 0x06, 0x10, 0xF4, 0x78,
- 0x1D, 0x90, 0x3F, 0x3E, 0xF4, 0xAA, 0x04, 0x19, 0xFE, 0xA4, 0x00,
- 0xE2, 0xFF, 0xFA, 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0x26, 0x00, 0x68,
- 0xFF, 0x93, 0x01, 0x92, 0xFC, 0xE2, 0x06, 0x83, 0xF1, 0x8C, 0x32,
- 0xED, 0x2D, 0x90, 0xF1, 0x1E, 0x07, 0x57, 0xFC, 0xBD, 0x01, 0x51,
- 0xFF, 0x2E, 0x00, 0xFD, 0xFF, 0x07, 0x00, 0xE8, 0xFF, 0x12, 0x00,
- 0x42, 0x00, 0xC4, 0xFE, 0x94, 0x03, 0x02, 0xF6, 0x89, 0x42, 0x76,
- 0x18, 0x5C, 0xF5, 0x12, 0x06, 0x84, 0xFC, 0xD1, 0x01, 0x3B, 0xFF,
- 0x34, 0x00, 0xFE, 0xFF, 0x1D, 0x00, 0x8A, 0xFF, 0x03, 0x01, 0x53,
- 0xFE, 0x53, 0x02, 0x39, 0xFD, 0xA9, 0x02, 0xF2, 0x48, 0xB9, 0x04,
- 0x54, 0xFC, 0xCA, 0x02, 0x16, 0xFE, 0x20, 0x01, 0x7F, 0xFF, 0x20,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x40, 0xFF, 0xC3, 0x01,
- 0xA7, 0xFC, 0xC0, 0x05, 0x1E, 0xF6, 0xD8, 0x15, 0xE7, 0x43, 0x20,
- 0xF7, 0xEF, 0x02, 0x27, 0xFF, 0x0A, 0x00, 0x2E, 0x00, 0xDD, 0xFF,
- 0x09, 0x00, 0xFD, 0xFF, 0x31, 0x00, 0x48, 0xFF, 0xCD, 0x01, 0x43,
- 0xFC, 0x2A, 0x07, 0xBC, 0xF1, 0x64, 0x2B, 0xE3, 0x34, 0xA3, 0xF1,
- 0xAE, 0x06, 0xBD, 0xFC, 0x77, 0x01, 0x77, 0xFF, 0x21, 0x00, 0xFE,
- 0xFF, 0x02, 0x00, 0x03, 0x00, 0xCA, 0xFF, 0xD4, 0x00, 0xC8, 0xFD,
- 0x2A, 0x05, 0x7D, 0xF3, 0xCA, 0x3D, 0x22, 0x20, 0x76, 0xF3, 0xC8,
- 0x06, 0x41, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0x14, 0x00, 0xAC, 0xFF, 0xAC, 0x00, 0x08, 0xFF, 0xFD, 0x00, 0xB5,
- 0xFF, 0x4B, 0xFD, 0xF4, 0x47, 0x30, 0x0B, 0xBC, 0xF9, 0x17, 0x04,
- 0x6E, 0xFD, 0x6D, 0x01, 0x60, 0xFF, 0x29, 0x00, 0x00, 0x00, 0xFF,
- 0xFF, 0x2C, 0x00, 0x54, 0xFF, 0x8D, 0x01, 0x26, 0xFD, 0xAD, 0x04,
- 0x82, 0xF8, 0x87, 0x0E, 0xF9, 0x46, 0x0C, 0xFB, 0xD4, 0x00, 0x5D,
- 0x00, 0x5E, 0xFF, 0x82, 0x00, 0xBD, 0xFF, 0x10, 0x00, 0xFD, 0xFF,
- 0x36, 0x00, 0x38, 0xFF, 0xE5, 0x01, 0x33, 0xFC, 0x01, 0x07, 0xBE,
- 0xF2, 0xD6, 0x23, 0x1F, 0x3B, 0xA5, 0xF2, 0xC5, 0x05, 0x62, 0xFD,
- 0x10, 0x01, 0xAB, 0xFF, 0x0E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x19,
- 0x00, 0x8E, 0xFF, 0x49, 0x01, 0x04, 0xFD, 0x4D, 0x06, 0x00, 0xF2,
- 0xFE, 0x37, 0xCB, 0x27, 0x21, 0xF2, 0x23, 0x07, 0x34, 0xFC, 0xDD,
- 0x01, 0x3F, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x0C, 0x00, 0xCE, 0xFF,
- 0x56, 0x00, 0xB9, 0xFF, 0xB8, 0xFF, 0xF7, 0x01, 0xE2, 0xF8, 0x8D,
- 0x45, 0x46, 0x12, 0x3C, 0xF7, 0x43, 0x05, 0xDF, 0xFC, 0xAC, 0x01,
- 0x48, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x24, 0x00, 0x70,
- 0xFF, 0x46, 0x01, 0xC3, 0xFD, 0x6D, 0x03, 0x14, 0xFB, 0xBE, 0x07,
- 0xA6, 0x48, 0xF8, 0xFF, 0x70, 0xFE, 0xAE, 0x01, 0xAA, 0xFE, 0xD9,
- 0x00, 0x9A, 0xFF, 0x19, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF,
- 0xDE, 0x01, 0x5D, 0xFC, 0x74, 0x06, 0x63, 0xF4, 0x23, 0x1C, 0x66,
- 0x40, 0xAA, 0xF4, 0x65, 0x04, 0x44, 0xFE, 0x8B, 0x00, 0xEE, 0xFF,
- 0xF5, 0xFF, 0x04, 0x00, 0xFD, 0xFF, 0x29, 0x00, 0x61, 0xFF, 0x9F,
- 0x01, 0x80, 0xFC, 0xF7, 0x06, 0x7D, 0xF1, 0x5A, 0x31, 0x2C, 0x2F,
- 0x83, 0xF1, 0x13, 0x07, 0x64, 0xFC, 0xB3, 0x01, 0x57, 0xFF, 0x2C,
- 0x00, 0xFD, 0xFF, 0x06, 0x00, 0xED, 0xFF, 0x05, 0x00, 0x5D, 0x00,
- 0x95, 0xFE, 0xE2, 0x03, 0x7F, 0xF5, 0xCC, 0x41, 0xC7, 0x19, 0xFF,
- 0xF4, 0x37, 0x06, 0x75, 0xFC, 0xD6, 0x01, 0x39, 0xFF, 0x35, 0x00,
- 0xFE, 0xFF, 0x1B, 0x00, 0x90, 0xFF, 0xF4, 0x00, 0x72, 0xFE, 0x18,
- 0x02, 0xAA, 0xFD, 0xAB, 0x01, 0xDF, 0x48, 0xCA, 0x05, 0xE1, 0xFB,
- 0x05, 0x03, 0xF7, 0xFD, 0x2E, 0x01, 0x79, 0xFF, 0x21, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x32, 0x00, 0x43, 0xFF, 0xBB, 0x01, 0xBA, 0xFC,
- 0x95, 0x05, 0x83, 0xF6, 0x8C, 0x14, 0x87, 0x44, 0xBB, 0xF7, 0x98,
- 0x02, 0x5A, 0xFF, 0xEE, 0xFF, 0x3C, 0x00, 0xD8, 0xFF, 0x0A, 0x00,
- 0xFD, 0xFF, 0x32, 0x00, 0x44, 0xFF, 0xD3, 0x01, 0x3C, 0xFC, 0x2A,
- 0x07, 0xDC, 0xF1, 0x1A, 0x2A, 0x06, 0x36, 0xBE, 0xF1, 0x8E, 0x06,
- 0xD5, 0xFC, 0x67, 0x01, 0x7F, 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0x01,
- 0x00, 0x07, 0x00, 0xBE, 0xFF, 0xEA, 0x00, 0xA2, 0xFD, 0x65, 0x05,
- 0x28, 0xF3, 0xDB, 0x3C, 0x78, 0x21, 0x30, 0xF3, 0xDF, 0x06, 0x3A,
- 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x13, 0x00,
- 0xB2, 0xFF, 0x9D, 0x00, 0x27, 0xFF, 0xC3, 0x00, 0x1F, 0x00, 0x76,
- 0xFC, 0xA3, 0x47, 0x60, 0x0C, 0x4A, 0xF9, 0x4E, 0x04, 0x53, 0xFD,
- 0x79, 0x01, 0x5C, 0xFF, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B,
- 0x00, 0x58, 0xFF, 0x82, 0x01, 0x3F, 0xFD, 0x78, 0x04, 0xF2, 0xF8,
- 0x50, 0x0D, 0x5E, 0x47, 0xD5, 0xFB, 0x6F, 0x00, 0x96, 0x00, 0x40,
- 0xFF, 0x91, 0x00, 0xB7, 0xFF, 0x12, 0x00, 0xFD, 0xFF, 0x36, 0x00,
- 0x37, 0xFF, 0xE6, 0x01, 0x36, 0xFC, 0xEF, 0x06, 0xFC, 0xF2, 0x81,
- 0x22, 0x1C, 0x3C, 0xEC, 0xF2, 0x90, 0x05, 0x85, 0xFD, 0xFB, 0x00,
- 0xB6, 0xFF, 0x0A, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x1C, 0x00, 0x85,
- 0xFF, 0x5B, 0x01, 0xE9, 0xFC, 0x73, 0x06, 0xD8, 0xF1, 0xE5, 0x36,
- 0x19, 0x29, 0xF8, 0xF1, 0x29, 0x07, 0x37, 0xFC, 0xD8, 0x01, 0x42,
- 0xFF, 0x33, 0x00, 0xFD, 0xFF, 0x0B, 0x00, 0xD3, 0xFF, 0x47, 0x00,
- 0xD7, 0xFF, 0x82, 0xFF, 0x53, 0x02, 0x39, 0xF8, 0xFD, 0x44, 0x8D,
- 0x13, 0xD3, 0xF6, 0x72, 0x05, 0xCA, 0xFC, 0xB5, 0x01, 0x45, 0xFF,
- 0x31, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x23, 0x00, 0x75, 0xFF, 0x39,
- 0x01, 0xE0, 0xFD, 0x33, 0x03, 0x87, 0xFB, 0xA2, 0x06, 0xCB, 0x48,
- 0xEA, 0x00, 0x01, 0xFE, 0xE9, 0x01, 0x8A, 0xFE, 0xE8, 0x00, 0x95,
- 0xFF, 0x1A, 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x38, 0xFF, 0xDA, 0x01,
- 0x6A, 0xFC, 0x53, 0x06, 0xBA, 0xF4, 0xCE, 0x1A, 0x32, 0x41, 0x1F,
- 0xF5, 0x1D, 0x04, 0x71, 0xFE, 0x71, 0x00, 0xFB, 0xFF, 0xF0, 0xFF,
- 0x05, 0x00, 0xFD, 0xFF, 0x2B, 0x00, 0x5B, 0xFF, 0xAB, 0x01, 0x6F,
- 0xFC, 0x08, 0x07, 0x7E, 0xF1, 0x21, 0x30, 0x67, 0x30, 0x7D, 0xF1,
- 0x05, 0x07, 0x73, 0xFC, 0xA8, 0x01, 0x5C, 0xFF, 0x2A, 0x00, 0xFD,
- 0xFF, 0x05, 0x00, 0xF2, 0xFF, 0xF8, 0xFF, 0x77, 0x00, 0x67, 0xFE,
- 0x2D, 0x04, 0x04, 0xF5, 0x07, 0x41, 0x1B, 0x1B, 0xA6, 0xF4, 0x5A,
- 0x06, 0x67, 0xFC, 0xDB, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFE, 0xFF,
- 0x1A, 0x00, 0x96, 0xFF, 0xE5, 0x00, 0x91, 0xFE, 0xDC, 0x01, 0x1A,
- 0xFE, 0xB3, 0x00, 0xC3, 0x48, 0xE1, 0x06, 0x6E, 0xFB, 0x40, 0x03,
- 0xDA, 0xFD, 0x3C, 0x01, 0x74, 0xFF, 0x23, 0x00, 0x00, 0x00, 0xFF,
- 0xFF, 0x31, 0x00, 0x46, 0xFF, 0xB3, 0x01, 0xCF, 0xFC, 0x67, 0x05,
- 0xEA, 0xF6, 0x44, 0x13, 0x1E, 0x45, 0x5E, 0xF8, 0x3F, 0x02, 0x8E,
- 0xFF, 0xD0, 0xFF, 0x4A, 0x00, 0xD2, 0xFF, 0x0B, 0x00, 0xFD, 0xFF,
- 0x33, 0x00, 0x41, 0xFF, 0xD9, 0x01, 0x36, 0xFC, 0x28, 0x07, 0x01,
- 0xF2, 0xCE, 0x28, 0x23, 0x37, 0xE0, 0xF1, 0x6B, 0x06, 0xEF, 0xFC,
- 0x57, 0x01, 0x87, 0xFF, 0x1B, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x0B,
- 0x00, 0xB4, 0xFF, 0x00, 0x01, 0x7E, 0xFD, 0x9C, 0x05, 0xDC, 0xF2,
- 0xE4, 0x3B, 0xCD, 0x22, 0xEE, 0xF2, 0xF3, 0x06, 0x35, 0xFC, 0xE6,
- 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x11, 0x00, 0xB8, 0xFF,
- 0x8E, 0x00, 0x46, 0xFF, 0x8A, 0x00, 0x86, 0x00, 0xA7, 0xFB, 0x48,
- 0x47, 0x95, 0x0D, 0xD9, 0xF8, 0x84, 0x04, 0x39, 0xFD, 0x85, 0x01,
- 0x57, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x5D,
- 0xFF, 0x76, 0x01, 0x59, 0xFD, 0x42, 0x04, 0x63, 0xF9, 0x1C, 0x0C,
- 0xB6, 0x47, 0xA4, 0xFC, 0x07, 0x00, 0xD0, 0x00, 0x20, 0xFF, 0xA0,
- 0x00, 0xB1, 0xFF, 0x13, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF,
- 0xE6, 0x01, 0x3B, 0xFC, 0xDA, 0x06, 0x3F, 0xF3, 0x2C, 0x21, 0x11,
- 0x3D, 0x3A, 0xF3, 0x58, 0x05, 0xAA, 0xFD, 0xE5, 0x00, 0xC1, 0xFF,
- 0x06, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x1F, 0x00, 0x7D, 0xFF, 0x6B,
- 0x01, 0xCF, 0xFC, 0x96, 0x06, 0xB7, 0xF1, 0xC6, 0x35, 0x64, 0x2A,
- 0xD4, 0xF1, 0x2B, 0x07, 0x3D, 0xFC, 0xD2, 0x01, 0x45, 0xFF, 0x32,
- 0x00, 0xFD, 0xFF, 0x0A, 0x00, 0xD9, 0xFF, 0x39, 0x00, 0xF4, 0xFF,
- 0x4E, 0xFF, 0xAC, 0x02, 0x98, 0xF7, 0x65, 0x44, 0xD6, 0x14, 0x6C,
- 0xF6, 0x9F, 0x05, 0xB6, 0xFC, 0xBD, 0x01, 0x42, 0xFF, 0x32, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0x21, 0x00, 0x7A, 0xFF, 0x2B, 0x01, 0xFE,
- 0xFD, 0xF8, 0x02, 0xFB, 0xFB, 0x8D, 0x05, 0xE5, 0x48, 0xE3, 0x01,
- 0x91, 0xFD, 0x25, 0x02, 0x6B, 0xFE, 0xF7, 0x00, 0x8F, 0xFF, 0x1C,
- 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xD5, 0x01, 0x78, 0xFC,
- 0x2F, 0x06, 0x13, 0xF5, 0x7C, 0x19, 0xF7, 0x41, 0x9B, 0xF5, 0xD1,
- 0x03, 0x9F, 0xFE, 0x57, 0x00, 0x08, 0x00, 0xEC, 0xFF, 0x06, 0x00,
- 0xFD, 0xFF, 0x2D, 0x00, 0x55, 0xFF, 0xB5, 0x01, 0x61, 0xFC, 0x16,
- 0x07, 0x85, 0xF1, 0xE6, 0x2E, 0x9E, 0x31, 0x7D, 0xF1, 0xF3, 0x06,
- 0x84, 0xFC, 0x9D, 0x01, 0x63, 0xFF, 0x28, 0x00, 0xFD, 0xFF, 0x04,
- 0x00, 0xF6, 0xFF, 0xEB, 0xFF, 0x91, 0x00, 0x3B, 0xFE, 0x75, 0x04,
- 0x92, 0xF4, 0x36, 0x40, 0x6E, 0x1C, 0x50, 0xF4, 0x7B, 0x06, 0x5B,
- 0xFC, 0xDF, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x18, 0x00,
- 0x9C, 0xFF, 0xD6, 0x00, 0xB1, 0xFE, 0xA1, 0x01, 0x89, 0xFE, 0xC3,
- 0xFF, 0x9C, 0x48, 0xFD, 0x07, 0xFA, 0xFA, 0x7A, 0x03, 0xBC, 0xFD,
- 0x49, 0x01, 0x6E, 0xFF, 0x24, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30,
- 0x00, 0x49, 0xFF, 0xAA, 0x01, 0xE4, 0xFC, 0x38, 0x05, 0x54, 0xF7,
- 0xFE, 0x11, 0xAA, 0x45, 0x09, 0xF9, 0xE2, 0x01, 0xC4, 0xFF, 0xB3,
- 0xFF, 0x59, 0x00, 0xCD, 0xFF, 0x0D, 0x00, 0xFD, 0xFF, 0x34, 0x00,
- 0x3E, 0xFF, 0xDE, 0x01, 0x33, 0xFC, 0x22, 0x07, 0x2B, 0xF2, 0x80,
- 0x27, 0x3B, 0x38, 0x0A, 0xF2, 0x44, 0x06, 0x0B, 0xFD, 0x45, 0x01,
- 0x90, 0xFF, 0x18, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0xA9,
- 0xFF, 0x15, 0x01, 0x5B, 0xFD, 0xD0, 0x05, 0x97, 0xF2, 0xE6, 0x3A,
- 0x21, 0x24, 0xB1, 0xF2, 0x04, 0x07, 0x33, 0xFC, 0xE5, 0x01, 0x39,
- 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x10, 0x00, 0xBE, 0xFF, 0x7F, 0x00,
- 0x65, 0xFF, 0x51, 0x00, 0xEB, 0x00, 0xE1, 0xFA, 0xE1, 0x46, 0xCD,
- 0x0E, 0x6A, 0xF8, 0xB8, 0x04, 0x20, 0xFD, 0x90, 0x01, 0x53, 0xFF,
- 0x2D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x28, 0x00, 0x62, 0xFF, 0x6A,
- 0x01, 0x74, 0xFD, 0x0A, 0x04, 0xD5, 0xF9, 0xED, 0x0A, 0x03, 0x48,
- 0x7C, 0xFD, 0x9E, 0xFF, 0x0A, 0x01, 0x01, 0xFF, 0xAF, 0x00, 0xAB,
- 0xFF, 0x14, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE5, 0x01,
- 0x42, 0xFC, 0xC3, 0x06, 0x87, 0xF3, 0xD7, 0x1F, 0xFE, 0x3D, 0x91,
- 0xF3, 0x1D, 0x05, 0xD1, 0xFD, 0xCE, 0x00, 0xCC, 0xFF, 0x02, 0x00,
- 0x02, 0x00, 0xFE, 0xFF, 0x22, 0x00, 0x75, 0xFF, 0x7A, 0x01, 0xB8,
- 0xFC, 0xB4, 0x06, 0x9E, 0xF1, 0xA2, 0x34, 0xAD, 0x2B, 0xB6, 0xF1,
- 0x29, 0x07, 0x45, 0xFC, 0xCB, 0x01, 0x49, 0xFF, 0x31, 0x00, 0xFD,
- 0xFF, 0x09, 0x00, 0xDE, 0xFF, 0x2B, 0x00, 0x11, 0x00, 0x1B, 0xFF,
- 0x02, 0x03, 0xFE, 0xF6, 0xC3, 0x43, 0x22, 0x16, 0x07, 0xF6, 0xCA,
- 0x05, 0xA3, 0xFC, 0xC5, 0x01, 0x3F, 0xFF, 0x33, 0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x20, 0x00, 0x80, 0xFF, 0x1C, 0x01, 0x1C, 0xFE, 0xBD,
- 0x02, 0x6E, 0xFC, 0x7D, 0x04, 0xF3, 0x48, 0xE2, 0x02, 0x1F, 0xFD,
- 0x60, 0x02, 0x4C, 0xFE, 0x06, 0x01, 0x89, 0xFF, 0x1D, 0x00, 0xFE,
- 0xFF, 0x34, 0x00, 0x3C, 0xFF, 0xCF, 0x01, 0x88, 0xFC, 0x09, 0x06,
- 0x71, 0xF5, 0x2B, 0x18, 0xB2, 0x42, 0x20, 0xF6, 0x83, 0x03, 0xCF,
- 0xFE, 0x3C, 0x00, 0x15, 0x00, 0xE6, 0xFF, 0x07, 0x00, 0xFD, 0xFF,
- 0x2E, 0x00, 0x50, 0xFF, 0xBF, 0x01, 0x54, 0xFC, 0x20, 0x07, 0x94,
- 0xF1, 0xA6, 0x2D, 0xD0, 0x32, 0x85, 0xF1, 0xDD, 0x06, 0x96, 0xFC,
- 0x90, 0x01, 0x69, 0xFF, 0x26, 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFB,
- 0xFF, 0xDF, 0xFF, 0xA9, 0x00, 0x10, 0xFE, 0xB9, 0x04, 0x27, 0xF4,
- 0x5E, 0x3F, 0xC3, 0x1D, 0xFE, 0xF3, 0x99, 0x06, 0x50, 0xFC, 0xE2,
- 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x17, 0x00, 0xA2, 0xFF,
- 0xC7, 0x00, 0xD0, 0xFE, 0x65, 0x01, 0xF6, 0xFE, 0xD9, 0xFE, 0x6A,
- 0x48, 0x1F, 0x09, 0x87, 0xFA, 0xB3, 0x03, 0xA0, 0xFD, 0x56, 0x01,
- 0x69, 0xFF, 0x26, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2F, 0x00, 0x4D,
- 0xFF, 0xA0, 0x01, 0xFB, 0xFC, 0x07, 0x05, 0xBF, 0xF7, 0xBB, 0x10,
- 0x2B, 0x46, 0xBB, 0xF9, 0x83, 0x01, 0xFA, 0xFF, 0x95, 0xFF, 0x68,
- 0x00, 0xC7, 0xFF, 0x0E, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3C, 0xFF,
- 0xE1, 0x01, 0x31, 0xFC, 0x19, 0x07, 0x5B, 0xF2, 0x30, 0x26, 0x4B,
- 0x39, 0x3B, 0xF2, 0x1A, 0x06, 0x29, 0xFD, 0x33, 0x01, 0x99, 0xFF,
- 0x15, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x13, 0x00, 0x9F, 0xFF, 0x28,
- 0x01, 0x3A, 0xFD, 0x00, 0x06, 0x5A, 0xF2, 0xDF, 0x39, 0x73, 0x25,
- 0x79, 0xF2, 0x12, 0x07, 0x31, 0xFC, 0xE3, 0x01, 0x3B, 0xFF, 0x35,
- 0x00, 0xFD, 0xFF, 0x0F, 0x00, 0xC4, 0xFF, 0x70, 0x00, 0x84, 0xFF,
- 0x19, 0x00, 0x4D, 0x01, 0x22, 0xFA, 0x70, 0x46, 0x0A, 0x10, 0xFC,
- 0xF7, 0xEB, 0x04, 0x08, 0xFD, 0x9A, 0x01, 0x4F, 0xFF, 0x2E, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0x27, 0x00, 0x66, 0xFF, 0x5E, 0x01, 0x90,
- 0xFD, 0xD2, 0x03, 0x47, 0xFA, 0xC3, 0x09, 0x48, 0x48, 0x5A, 0xFE,
- 0x33, 0xFF, 0x45, 0x01, 0xE2, 0xFE, 0xBE, 0x00, 0xA5, 0xFF, 0x16,
- 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE3, 0x01, 0x4B, 0xFC,
- 0xA9, 0x06, 0xD2, 0xF3, 0x81, 0x1E, 0xE4, 0x3E, 0xEF, 0xF3, 0xDE,
- 0x04, 0xF9, 0xFD, 0xB7, 0x00, 0xD8, 0xFF, 0xFD, 0xFF, 0x03, 0x00,
- 0xFD, 0xFF, 0x24, 0x00, 0x6D, 0xFF, 0x88, 0x01, 0xA2, 0xFC, 0xD0,
- 0x06, 0x8C, 0xF1, 0x78, 0x33, 0xF2, 0x2C, 0x9E, 0xF1, 0x24, 0x07,
- 0x4E, 0xFC, 0xC3, 0x01, 0x4E, 0xFF, 0x2F, 0x00, 0xFD, 0xFF, 0x08,
- 0x00, 0xE4, 0xFF, 0x1D, 0x00, 0x2D, 0x00, 0xEA, 0xFE, 0x56, 0x03,
- 0x6D, 0xF6, 0x17, 0x43, 0x70, 0x17, 0xA6, 0xF5, 0xF3, 0x05, 0x91,
- 0xFC, 0xCC, 0x01, 0x3D, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0x1E, 0x00,
- 0x86, 0xFF, 0x0E, 0x01, 0x3B, 0xFE, 0x82, 0x02, 0xE0, 0xFC, 0x73,
- 0x03, 0xF6, 0x48, 0xE9, 0x03, 0xAD, 0xFC, 0x9C, 0x02, 0x2D, 0xFE,
- 0x14, 0x01, 0x83, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x33,
- 0x00, 0x3E, 0xFF, 0xC9, 0x01, 0x99, 0xFC, 0xE1, 0x05, 0xD1, 0xF5,
- 0xDC, 0x16, 0x65, 0x43, 0xAD, 0xF6, 0x31, 0x03, 0x00, 0xFF, 0x20,
- 0x00, 0x23, 0x00, 0xE1, 0xFF, 0x08, 0x00, 0xFD, 0xFF, 0x30, 0x00,
- 0x4C, 0xFF, 0xC7, 0x01, 0x4A, 0xFC, 0x27, 0x07, 0xA8, 0xF1, 0x62,
- 0x2C, 0xFD, 0x33, 0x93, 0xF1, 0xC4, 0x06, 0xAB, 0xFC, 0x82, 0x01,
- 0x71, 0xFF, 0x23, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0xFF, 0xFF, 0xD3,
- 0xFF, 0xC1, 0x00, 0xE7, 0xFD, 0xFA, 0x04, 0xC4, 0xF3, 0x7E, 0x3E,
- 0x19, 0x1F, 0xB0, 0xF3, 0xB5, 0x06, 0x47, 0xFC, 0xE4, 0x01, 0x36,
- 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x15, 0x00, 0xA8, 0xFF, 0xB8, 0x00,
- 0xF0, 0xFE, 0x2B, 0x01, 0x63, 0xFF, 0xF6, 0xFD, 0x2C, 0x48, 0x47,
- 0x0A, 0x14, 0xFA, 0xEB, 0x03, 0x84, 0xFD, 0x63, 0x01, 0x64, 0xFF,
- 0x27, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2D, 0x00, 0x51, 0xFF, 0x96,
- 0x01, 0x13, 0xFD, 0xD5, 0x04, 0x2C, 0xF8, 0x7D, 0x0F, 0xA3, 0x46,
- 0x76, 0xFA, 0x22, 0x01, 0x32, 0x00, 0x76, 0xFF, 0x76, 0x00, 0xC1,
- 0xFF, 0x0F, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x3A, 0xFF, 0xE4, 0x01,
- 0x32, 0xFC, 0x0C, 0x07, 0x91, 0xF2, 0xDD, 0x24, 0x54, 0x3A, 0x74,
- 0xF2, 0xEB, 0x05, 0x49, 0xFD, 0x20, 0x01, 0xA3, 0xFF, 0x11, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x16, 0x00, 0x95, 0xFF, 0x3B, 0x01, 0x1B,
- 0xFD, 0x2D, 0x06, 0x24, 0xF2, 0xD3, 0x38, 0xC6, 0x26, 0x45, 0xF2,
- 0x1D, 0x07, 0x32, 0xFC, 0xE0, 0x01, 0x3D, 0xFF, 0x35, 0x00, 0xFD,
- 0xFF, 0x0D, 0x00, 0xC9, 0xFF, 0x61, 0x00, 0xA2, 0xFF, 0xE2, 0xFF,
- 0xAE, 0x01, 0x6B, 0xF9, 0xF2, 0x45, 0x4A, 0x11, 0x8F, 0xF7, 0x1D,
- 0x05, 0xF1, 0xFC, 0xA4, 0x01, 0x4B, 0xFF, 0x2F, 0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x25, 0x00, 0x6C, 0xFF, 0x51, 0x01, 0xAC, 0xFD, 0x9A,
- 0x03, 0xBA, 0xFA, 0x9E, 0x08, 0x81, 0x48, 0x40, 0xFF, 0xC6, 0xFE,
- 0x80, 0x01, 0xC2, 0xFE, 0xCE, 0x00, 0x9F, 0xFF, 0x17, 0x00, 0xFE,
- 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE1, 0x01, 0x55, 0xFC, 0x8C, 0x06,
- 0x22, 0xF4, 0x2C, 0x1D, 0xC0, 0x3F, 0x55, 0xF4, 0x9B, 0x04, 0x23,
- 0xFE, 0x9F, 0x00, 0xE4, 0xFF, 0xF9, 0xFF, 0x04, 0x00, 0xFD, 0xFF,
- 0x27, 0x00, 0x66, 0xFF, 0x96, 0x01, 0x8E, 0xFC, 0xE7, 0x06, 0x81,
- 0xF1, 0x48, 0x32, 0x34, 0x2E, 0x8D, 0xF1, 0x1C, 0x07, 0x5A, 0xFC,
- 0xBB, 0x01, 0x53, 0xFF, 0x2E, 0x00, 0xFD, 0xFF, 0x07, 0x00, 0xE9,
- 0xFF, 0x0F, 0x00, 0x48, 0x00, 0xB9, 0xFE, 0xA6, 0x03, 0xE4, 0xF5,
- 0x60, 0x42, 0xC1, 0x18, 0x47, 0xF5, 0x1A, 0x06, 0x81, 0xFC, 0xD2,
- 0x01, 0x3B, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1C, 0x00, 0x8B, 0xFF,
- 0xFF, 0x00, 0x5A, 0xFE, 0x46, 0x02, 0x52, 0xFD, 0x70, 0x02, 0xED,
- 0x48, 0xF5, 0x04, 0x3B, 0xFC, 0xD7, 0x02, 0x0F, 0xFE, 0x23, 0x01,
- 0x7E, 0xFF, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x40,
- 0xFF, 0xC1, 0x01, 0xAB, 0xFC, 0xB7, 0x05, 0x34, 0xF6, 0x8E, 0x15,
- 0x0B, 0x44, 0x42, 0xF7, 0xDC, 0x02, 0x32, 0xFF, 0x04, 0x00, 0x31,
- 0x00, 0xDC, 0xFF, 0x09, 0x00, 0xFD, 0xFF, 0x31, 0x00, 0x47, 0xFF,
- 0xCE, 0x01, 0x41, 0xFC, 0x2A, 0x07, 0xC2, 0xF1, 0x1B, 0x2B, 0x25,
- 0x35, 0xA8, 0xF1, 0xA7, 0x06, 0xC2, 0xFC, 0x74, 0x01, 0x78, 0xFF,
- 0x20, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x04, 0x00, 0xC7, 0xFF, 0xD9,
- 0x00, 0xBF, 0xFD, 0x38, 0x05, 0x69, 0xF3, 0x96, 0x3D, 0x6F, 0x20,
- 0x66, 0xF3, 0xCE, 0x06, 0x3F, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0x14, 0x00, 0xAE, 0xFF, 0xA9, 0x00, 0x0F, 0xFF,
- 0xF0, 0x00, 0xCD, 0xFF, 0x1B, 0xFD, 0xE4, 0x47, 0x73, 0x0B, 0xA2,
- 0xF9, 0x23, 0x04, 0x68, 0xFD, 0x70, 0x01, 0x5F, 0xFF, 0x29, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x2C, 0x00, 0x55, 0xFF, 0x8B, 0x01, 0x2B,
- 0xFD, 0xA1, 0x04, 0x9B, 0xF8, 0x42, 0x0E, 0x0F, 0x47, 0x38, 0xFB,
- 0xBE, 0x00, 0x6A, 0x00, 0x58, 0xFF, 0x85, 0x00, 0xBB, 0xFF, 0x10,
- 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xE6, 0x01, 0x34, 0xFC,
- 0xFD, 0x06, 0xCB, 0xF2, 0x8A, 0x23, 0x58, 0x3B, 0xB4, 0xF2, 0xBA,
- 0x05, 0x6A, 0xFD, 0x0B, 0x01, 0xAE, 0xFF, 0x0D, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x19, 0x00, 0x8C, 0xFF, 0x4D, 0x01, 0xFE, 0xFC, 0x56,
- 0x06, 0xF7, 0xF1, 0xBF, 0x37, 0x15, 0x28, 0x18, 0xF2, 0x25, 0x07,
- 0x34, 0xFC, 0xDC, 0x01, 0x3F, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x0C,
- 0x00, 0xCF, 0xFF, 0x52, 0x00, 0xC0, 0xFF, 0xAC, 0xFF, 0x0C, 0x02,
- 0xBC, 0xF8, 0x6D, 0x45, 0x8E, 0x12, 0x24, 0xF7, 0x4D, 0x05, 0xDB,
- 0xFC, 0xAE, 0x01, 0x48, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x24, 0x00, 0x71, 0xFF, 0x43, 0x01, 0xC9, 0xFD, 0x60, 0x03, 0x2E,
- 0xFB, 0x7E, 0x07, 0xAF, 0x48, 0x2D, 0x00, 0x58, 0xFE, 0xBB, 0x01,
- 0xA3, 0xFE, 0xDD, 0x00, 0x99, 0xFF, 0x19, 0x00, 0xFE, 0xFF, 0x36,
- 0x00, 0x37, 0xFF, 0xDD, 0x01, 0x60, 0xFC, 0x6D, 0x06, 0x76, 0xF4,
- 0xD8, 0x1B, 0x95, 0x40, 0xC3, 0xF4, 0x56, 0x04, 0x4E, 0xFE, 0x85,
- 0x00, 0xF1, 0xFF, 0xF4, 0xFF, 0x04, 0x00, 0xFD, 0xFF, 0x29, 0x00,
- 0x60, 0xFF, 0xA2, 0x01, 0x7C, 0xFC, 0xFB, 0x06, 0x7C, 0xF1, 0x15,
- 0x31, 0x73, 0x2F, 0x81, 0xF1, 0x10, 0x07, 0x67, 0xFC, 0xB1, 0x01,
- 0x58, 0xFF, 0x2C, 0x00, 0xFD, 0xFF, 0x06, 0x00, 0xEE, 0xFF, 0x02,
- 0x00, 0x63, 0x00, 0x8A, 0xFE, 0xF3, 0x03, 0x63, 0xF5, 0xA1, 0x41,
- 0x12, 0x1A, 0xEB, 0xF4, 0x3F, 0x06, 0x72, 0xFC, 0xD7, 0x01, 0x39,
- 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1B, 0x00, 0x91, 0xFF, 0xF1, 0x00,
- 0x79, 0xFE, 0x0A, 0x02, 0xC3, 0xFD, 0x73, 0x01, 0xDB, 0x48, 0x07,
- 0x06, 0xC7, 0xFB, 0x12, 0x03, 0xF1, 0xFD, 0x31, 0x01, 0x78, 0xFF,
- 0x22, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x32, 0x00, 0x43, 0xFF, 0xBA,
- 0x01, 0xBF, 0xFC, 0x8B, 0x05, 0x99, 0xF6, 0x43, 0x14, 0xA9, 0x44,
- 0xDE, 0xF7, 0x85, 0x02, 0x65, 0xFF, 0xE7, 0xFF, 0x3F, 0x00, 0xD6,
- 0xFF, 0x0A, 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x44, 0xFF, 0xD5, 0x01,
- 0x3A, 0xFC, 0x2A, 0x07, 0xE3, 0xF1, 0xD1, 0x29, 0x46, 0x36, 0xC5,
- 0xF1, 0x87, 0x06, 0xDA, 0xFC, 0x64, 0x01, 0x80, 0xFF, 0x1E, 0x00,
- 0xFE, 0xFF, 0x01, 0x00, 0x08, 0x00, 0xBC, 0xFF, 0xEF, 0x00, 0x9A,
- 0xFD, 0x72, 0x05, 0x16, 0xF3, 0xA5, 0x3C, 0xC4, 0x21, 0x21, 0xF3,
- 0xE4, 0x06, 0x39, 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0x12, 0x00, 0xB3, 0xFF, 0x99, 0x00, 0x2E, 0xFF, 0xB6, 0x00,
- 0x36, 0x00, 0x47, 0xFC, 0x90, 0x47, 0xA4, 0x0C, 0x31, 0xF9, 0x5A,
- 0x04, 0x4E, 0xFD, 0x7C, 0x01, 0x5B, 0xFF, 0x2A, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x2B, 0x00, 0x59, 0xFF, 0x80, 0x01, 0x45, 0xFD, 0x6C,
- 0x04, 0x0B, 0xF9, 0x0B, 0x0D, 0x73, 0x47, 0x02, 0xFC, 0x58, 0x00,
- 0xA3, 0x00, 0x39, 0xFF, 0x94, 0x00, 0xB5, 0xFF, 0x12, 0x00, 0xFD,
- 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x37, 0xFC, 0xEB, 0x06,
- 0x0B, 0xF3, 0x35, 0x22, 0x52, 0x3C, 0xFD, 0xF2, 0x84, 0x05, 0x8D,
- 0xFD, 0xF6, 0x00, 0xB8, 0xFF, 0x09, 0x00, 0x01, 0x00, 0xFE, 0xFF,
- 0x1D, 0x00, 0x83, 0xFF, 0x5E, 0x01, 0xE3, 0xFC, 0x7B, 0x06, 0xD0,
- 0xF1, 0xA5, 0x36, 0x62, 0x29, 0xEF, 0xF1, 0x29, 0x07, 0x39, 0xFC,
- 0xD7, 0x01, 0x42, 0xFF, 0x33, 0x00, 0xFD, 0xFF, 0x0B, 0x00, 0xD5,
- 0xFF, 0x44, 0x00, 0xDD, 0xFF, 0x77, 0xFF, 0x67, 0x02, 0x14, 0xF8,
- 0xDC, 0x44, 0xD5, 0x13, 0xBC, 0xF6, 0x7C, 0x05, 0xC5, 0xFC, 0xB7,
- 0x01, 0x44, 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x22, 0x00,
- 0x76, 0xFF, 0x35, 0x01, 0xE7, 0xFD, 0x26, 0x03, 0xA1, 0xFB, 0x64,
- 0x06, 0xD2, 0x48, 0x21, 0x01, 0xE8, 0xFD, 0xF7, 0x01, 0x83, 0xFE,
- 0xEC, 0x00, 0x93, 0xFF, 0x1A, 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x39,
- 0xFF, 0xD9, 0x01, 0x6D, 0xFC, 0x4B, 0x06, 0xCD, 0xF4, 0x83, 0x1A,
- 0x5F, 0x41, 0x3A, 0xF5, 0x0C, 0x04, 0x7B, 0xFE, 0x6C, 0x00, 0xFE,
- 0xFF, 0xEF, 0xFF, 0x05, 0x00, 0xFD, 0xFF, 0x2B, 0x00, 0x5A, 0xFF,
- 0xAD, 0x01, 0x6C, 0xFC, 0x0C, 0x07, 0x7F, 0xF1, 0xDC, 0x2F, 0xAD,
- 0x30, 0x7D, 0xF1, 0x01, 0x07, 0x76, 0xFC, 0xA6, 0x01, 0x5E, 0xFF,
- 0x2A, 0x00, 0xFD, 0xFF, 0x05, 0x00, 0xF3, 0xFF, 0xF5, 0xFF, 0x7D,
- 0x00, 0x5D, 0xFE, 0x3E, 0x04, 0xEA, 0xF4, 0xD9, 0x40, 0x66, 0x1B,
- 0x93, 0xF4, 0x62, 0x06, 0x64, 0xFC, 0xDC, 0x01, 0x38, 0xFF, 0x36,
- 0x00, 0xFE, 0xFF, 0x19, 0x00, 0x97, 0xFF, 0xE2, 0x00, 0x98, 0xFE,
- 0xCF, 0x01, 0x33, 0xFE, 0x7D, 0x00, 0xBB, 0x48, 0x1F, 0x07, 0x54,
- 0xFB, 0x4C, 0x03, 0xD3, 0xFD, 0x3F, 0x01, 0x73, 0xFF, 0x23, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x00, 0x46, 0xFF, 0xB1, 0x01, 0xD3,
- 0xFC, 0x5D, 0x05, 0x01, 0xF7, 0xFB, 0x12, 0x3F, 0x45, 0x83, 0xF8,
- 0x2A, 0x02, 0x9A, 0xFF, 0xCA, 0xFF, 0x4E, 0x00, 0xD1, 0xFF, 0x0C,
- 0x00, 0xFD, 0xFF, 0x34, 0x00, 0x40, 0xFF, 0xDA, 0x01, 0x35, 0xFC,
- 0x27, 0x07, 0x09, 0xF2, 0x85, 0x28, 0x63, 0x37, 0xE9, 0xF1, 0x63,
- 0x06, 0xF5, 0xFC, 0x53, 0x01, 0x89, 0xFF, 0x1A, 0x00, 0xFE, 0xFF,
- 0x00, 0x00, 0x0C, 0x00, 0xB1, 0xFF, 0x04, 0x01, 0x76, 0xFD, 0xA8,
- 0x05, 0xCC, 0xF2, 0xAB, 0x3B, 0x18, 0x23, 0xE0, 0xF2, 0xF7, 0x06,
- 0x35, 0xFC, 0xE6, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x11,
- 0x00, 0xB9, 0xFF, 0x8A, 0x00, 0x4D, 0xFF, 0x7D, 0x00, 0x9C, 0x00,
- 0x7B, 0xFB, 0x31, 0x47, 0xD9, 0x0D, 0xC0, 0xF8, 0x8F, 0x04, 0x34,
- 0xFD, 0x87, 0x01, 0x56, 0xFF, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x29, 0x00, 0x5E, 0xFF, 0x74, 0x01, 0x5F, 0xFD, 0x35, 0x04, 0x7C,
- 0xF9, 0xD8, 0x0B, 0xC9, 0x47, 0xD4, 0xFC, 0xF0, 0xFF, 0xDD, 0x00,
- 0x19, 0xFF, 0xA4, 0x00, 0xAF, 0xFF, 0x13, 0x00, 0xFD, 0xFF, 0x36,
- 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3D, 0xFC, 0xD5, 0x06, 0x4F, 0xF3,
- 0xE0, 0x20, 0x45, 0x3D, 0x4D, 0xF3, 0x4B, 0x05, 0xB3, 0xFD, 0xE0,
- 0x00, 0xC3, 0xFF, 0x05, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x20, 0x00,
- 0x7B, 0xFF, 0x6E, 0x01, 0xCA, 0xFC, 0x9D, 0x06, 0xB1, 0xF1, 0x86,
- 0x35, 0xAE, 0x2A, 0xCD, 0xF1, 0x2B, 0x07, 0x3F, 0xFC, 0xD1, 0x01,
- 0x46, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x0A, 0x00, 0xDA, 0xFF, 0x36,
- 0x00, 0xFA, 0xFF, 0x43, 0xFF, 0xBF, 0x02, 0x75, 0xF7, 0x42, 0x44,
- 0x20, 0x15, 0x55, 0xF6, 0xA9, 0x05, 0xB2, 0xFC, 0xBF, 0x01, 0x41,
- 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x21, 0x00, 0x7C, 0xFF,
- 0x27, 0x01, 0x05, 0xFE, 0xEB, 0x02, 0x14, 0xFC, 0x50, 0x05, 0xEA,
- 0x48, 0x1B, 0x02, 0x78, 0xFD, 0x32, 0x02, 0x64, 0xFE, 0xFA, 0x00,
- 0x8D, 0xFF, 0x1C, 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xD4,
- 0x01, 0x7C, 0xFC, 0x27, 0x06, 0x28, 0xF5, 0x31, 0x19, 0x21, 0x42,
- 0xB8, 0xF5, 0xC0, 0x03, 0xAA, 0xFE, 0x51, 0x00, 0x0B, 0x00, 0xEA,
- 0xFF, 0x06, 0x00, 0xFD, 0xFF, 0x2D, 0x00, 0x54, 0xFF, 0xB7, 0x01,
- 0x5E, 0xFC, 0x19, 0x07, 0x88, 0xF1, 0x9F, 0x2E, 0xE3, 0x31, 0x7E,
- 0xF1, 0xEE, 0x06, 0x88, 0xFC, 0x9A, 0x01, 0x64, 0xFF, 0x28, 0x00,
- 0xFD, 0xFF, 0x04, 0x00, 0xF7, 0xFF, 0xE8, 0xFF, 0x96, 0x00, 0x31,
- 0xFE, 0x84, 0x04, 0x79, 0xF4, 0x07, 0x40, 0xBA, 0x1C, 0x3E, 0xF4,
- 0x82, 0x06, 0x58, 0xFC, 0xE0, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE,
- 0xFF, 0x18, 0x00, 0x9D, 0xFF, 0xD3, 0x00, 0xB8, 0xFE, 0x93, 0x01,
- 0xA1, 0xFE, 0x8E, 0xFF, 0x92, 0x48, 0x3D, 0x08, 0xE1, 0xFA, 0x86,
- 0x03, 0xB6, 0xFD, 0x4C, 0x01, 0x6D, 0xFF, 0x25, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x30, 0x00, 0x4A, 0xFF, 0xA8, 0x01, 0xE9, 0xFC, 0x2D,
- 0x05, 0x6B, 0xF7, 0xB6, 0x11, 0xC8, 0x45, 0x30, 0xF9, 0xCD, 0x01,
- 0xD0, 0xFF, 0xAC, 0xFF, 0x5C, 0x00, 0xCB, 0xFF, 0x0D, 0x00, 0xFD,
- 0xFF, 0x34, 0x00, 0x3E, 0xFF, 0xDF, 0x01, 0x33, 0xFC, 0x20, 0x07,
- 0x35, 0xF2, 0x36, 0x27, 0x78, 0x38, 0x14, 0xF2, 0x3B, 0x06, 0x11,
- 0xFD, 0x41, 0x01, 0x92, 0xFF, 0x17, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x10, 0x00, 0xA7, 0xFF, 0x19, 0x01, 0x53, 0xFD, 0xDB, 0x05, 0x88,
- 0xF2, 0xAD, 0x3A, 0x6D, 0x24, 0xA4, 0xF2, 0x08, 0x07, 0x32, 0xFC,
- 0xE5, 0x01, 0x39, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x10, 0x00, 0xBF,
- 0xFF, 0x7B, 0x00, 0x6C, 0xFF, 0x44, 0x00, 0x01, 0x01, 0xB6, 0xFA,
- 0xC8, 0x46, 0x13, 0x0F, 0x51, 0xF8, 0xC4, 0x04, 0x1B, 0xFD, 0x92,
- 0x01, 0x52, 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x28, 0x00,
- 0x63, 0xFF, 0x67, 0x01, 0x7A, 0xFD, 0xFE, 0x03, 0xEE, 0xF9, 0xAA,
- 0x0A, 0x16, 0x48, 0xAC, 0xFD, 0x86, 0xFF, 0x17, 0x01, 0xFA, 0xFE,
- 0xB3, 0x00, 0xAA, 0xFF, 0x15, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36,
- 0xFF, 0xE5, 0x01, 0x44, 0xFC, 0xBD, 0x06, 0x97, 0xF3, 0x8A, 0x1F,
- 0x31, 0x3E, 0xA5, 0xF3, 0x0F, 0x05, 0xDA, 0xFD, 0xC9, 0x00, 0xCF,
- 0xFF, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x22, 0x00, 0x73, 0xFF,
- 0x7D, 0x01, 0xB3, 0xFC, 0xBB, 0x06, 0x9A, 0xF1, 0x60, 0x34, 0xF5,
- 0x2B, 0xB0, 0xF1, 0x28, 0x07, 0x47, 0xFC, 0xCA, 0x01, 0x4A, 0xFF,
- 0x30, 0x00, 0xFD, 0xFF, 0x09, 0x00, 0xDF, 0xFF, 0x28, 0x00, 0x17,
- 0x00, 0x10, 0xFF, 0x15, 0x03, 0xDD, 0xF6, 0x9E, 0x43, 0x6C, 0x16,
- 0xF1, 0xF5, 0xD3, 0x05, 0x9F, 0xFC, 0xC6, 0x01, 0x3F, 0xFF, 0x33,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x81, 0xFF, 0x19, 0x01,
- 0x23, 0xFE, 0xB0, 0x02, 0x87, 0xFC, 0x41, 0x04, 0xF4, 0x48, 0x1C,
- 0x03, 0x06, 0xFD, 0x6E, 0x02, 0x45, 0xFE, 0x09, 0x01, 0x88, 0xFF,
- 0x1D, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3C, 0xFF, 0xCE, 0x01, 0x8C,
- 0xFC, 0x00, 0x06, 0x86, 0xF5, 0xE0, 0x17, 0xDB, 0x42, 0x3F, 0xF6,
- 0x71, 0x03, 0xD9, 0xFE, 0x36, 0x00, 0x18, 0x00, 0xE5, 0xFF, 0x07,
- 0x00, 0xFD, 0xFF, 0x2F, 0x00, 0x4F, 0xFF, 0xC1, 0x01, 0x52, 0xFC,
- 0x22, 0x07, 0x98, 0xF1, 0x5E, 0x2D, 0x13, 0x33, 0x87, 0xF1, 0xD8,
- 0x06, 0x9B, 0xFC, 0x8D, 0x01, 0x6B, 0xFF, 0x25, 0x00, 0xFD, 0xFF,
- 0x03, 0x00, 0xFC, 0xFF, 0xDC, 0xFF, 0xAF, 0x00, 0x07, 0xFE, 0xC8,
- 0x04, 0x10, 0xF4, 0x2D, 0x3F, 0x0F, 0x1E, 0xED, 0xF3, 0xA0, 0x06,
- 0x4E, 0xFC, 0xE3, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x16,
- 0x00, 0xA3, 0xFF, 0xC3, 0x00, 0xD7, 0xFE, 0x58, 0x01, 0x0F, 0xFF,
- 0xA6, 0xFE, 0x5D, 0x48, 0x61, 0x09, 0x6E, 0xFA, 0xC0, 0x03, 0x99,
- 0xFD, 0x59, 0x01, 0x68, 0xFF, 0x26, 0x00, 0x00, 0x00, 0xFF, 0xFF,
- 0x2E, 0x00, 0x4E, 0xFF, 0x9E, 0x01, 0x00, 0xFD, 0xFC, 0x04, 0xD7,
- 0xF7, 0x75, 0x10, 0x48, 0x46, 0xE4, 0xF9, 0x6E, 0x01, 0x06, 0x00,
- 0x8E, 0xFF, 0x6B, 0x00, 0xC6, 0xFF, 0x0E, 0x00, 0xFD, 0xFF, 0x35,
- 0x00, 0x3B, 0xFF, 0xE2, 0x01, 0x31, 0xFC, 0x16, 0x07, 0x67, 0xF2,
- 0xE5, 0x25, 0x87, 0x39, 0x47, 0xF2, 0x10, 0x06, 0x30, 0xFD, 0x2F,
- 0x01, 0x9C, 0xFF, 0x14, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x13, 0x00,
- 0x9D, 0xFF, 0x2D, 0x01, 0x33, 0xFD, 0x0B, 0x06, 0x4D, 0xF2, 0xA5,
- 0x39, 0xBF, 0x25, 0x6D, 0xF2, 0x15, 0x07, 0x31, 0xFC, 0xE2, 0x01,
- 0x3B, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x0E, 0x00, 0xC5, 0xFF, 0x6D,
- 0x00, 0x8B, 0xFF, 0x0D, 0x00, 0x63, 0x01, 0xF9, 0xF9, 0x55, 0x46,
- 0x51, 0x10, 0xE3, 0xF7, 0xF7, 0x04, 0x03, 0xFD, 0x9D, 0x01, 0x4E,
- 0xFF, 0x2E, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x26, 0x00, 0x68, 0xFF,
- 0x5B, 0x01, 0x96, 0xFD, 0xC6, 0x03, 0x61, 0xFA, 0x81, 0x09, 0x57,
- 0x48, 0x8D, 0xFE, 0x1B, 0xFF, 0x52, 0x01, 0xDB, 0xFE, 0xC2, 0x00,
- 0xA4, 0xFF, 0x16, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE3,
- 0x01, 0x4D, 0xFC, 0xA3, 0x06, 0xE4, 0xF3, 0x36, 0x1E, 0x16, 0x3F,
- 0x05, 0xF4, 0xCF, 0x04, 0x02, 0xFE, 0xB2, 0x00, 0xDB, 0xFF, 0xFC,
- 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0x25, 0x00, 0x6C, 0xFF, 0x8B, 0x01,
- 0x9D, 0xFC, 0xD5, 0x06, 0x89, 0xF1, 0x35, 0x33, 0x3A, 0x2D, 0x9A,
- 0xF1, 0x23, 0x07, 0x51, 0xFC, 0xC2, 0x01, 0x4F, 0xFF, 0x2F, 0x00,
- 0xFD, 0xFF, 0x07, 0x00, 0xE5, 0xFF, 0x1A, 0x00, 0x33, 0x00, 0xDF,
- 0xFE, 0x68, 0x03, 0x4E, 0xF6, 0xEE, 0x42, 0xBB, 0x17, 0x90, 0xF5,
- 0xFC, 0x05, 0x8E, 0xFC, 0xCD, 0x01, 0x3C, 0xFF, 0x34, 0x00, 0xFE,
- 0xFF, 0x1E, 0x00, 0x87, 0xFF, 0x0B, 0x01, 0x42, 0xFE, 0x74, 0x02,
- 0xF9, 0xFC, 0x39, 0x03, 0xF5, 0x48, 0x24, 0x04, 0x94, 0xFC, 0xA9,
- 0x02, 0x27, 0xFE, 0x18, 0x01, 0x82, 0xFF, 0x1F, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x33, 0x00, 0x3E, 0xFF, 0xC7, 0x01, 0x9D, 0xFC, 0xD8,
- 0x05, 0xE7, 0xF5, 0x91, 0x16, 0x89, 0x43, 0xCD, 0xF6, 0x1E, 0x03,
- 0x0B, 0xFF, 0x1A, 0x00, 0x26, 0x00, 0xE0, 0xFF, 0x08, 0x00, 0xFD,
- 0xFF, 0x30, 0x00, 0x4B, 0xFF, 0xC9, 0x01, 0x48, 0xFC, 0x28, 0x07,
- 0xAD, 0xF1, 0x19, 0x2C, 0x3F, 0x34, 0x97, 0xF1, 0xBE, 0x06, 0xB0,
- 0xFC, 0x7F, 0x01, 0x72, 0xFF, 0x23, 0x00, 0xFE, 0xFF, 0x02, 0x00,
- 0x00, 0x00, 0xD0, 0xFF, 0xC7, 0x00, 0xDE, 0xFD, 0x08, 0x05, 0xB0,
- 0xF3, 0x4A, 0x3E, 0x64, 0x1F, 0xA0, 0xF3, 0xBB, 0x06, 0x45, 0xFC,
- 0xE5, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x15, 0x00, 0xA9,
- 0xFF, 0xB4, 0x00, 0xF7, 0xFE, 0x1D, 0x01, 0x7A, 0xFF, 0xC5, 0xFD,
- 0x1D, 0x48, 0x89, 0x0A, 0xFB, 0xF9, 0xF8, 0x03, 0x7D, 0xFD, 0x66,
- 0x01, 0x63, 0xFF, 0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2D, 0x00,
- 0x52, 0xFF, 0x93, 0x01, 0x18, 0xFD, 0xC9, 0x04, 0x45, 0xF8, 0x36,
- 0x0F, 0xBB, 0x46, 0xA1, 0xFA, 0x0C, 0x01, 0x3E, 0x00, 0x70, 0xFF,
- 0x7A, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x39,
- 0xFF, 0xE4, 0x01, 0x32, 0xFC, 0x09, 0x07, 0x9D, 0xF2, 0x92, 0x24,
- 0x8F, 0x3A, 0x82, 0xF2, 0xE1, 0x05, 0x50, 0xFD, 0x1B, 0x01, 0xA6,
- 0xFF, 0x10, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x17, 0x00, 0x93, 0xFF,
- 0x3F, 0x01, 0x15, 0xFD, 0x36, 0x06, 0x19, 0xF2, 0x97, 0x38, 0x11,
- 0x27, 0x3B, 0xF2, 0x1F, 0x07, 0x32, 0xFC, 0xDF, 0x01, 0x3D, 0xFF,
- 0x34, 0x00, 0xFD, 0xFF, 0x0D, 0x00, 0xCB, 0xFF, 0x5E, 0x00, 0xA9,
- 0xFF, 0xD6, 0xFF, 0xC3, 0x01, 0x43, 0xF9, 0xD7, 0x45, 0x92, 0x11,
- 0x77, 0xF7, 0x28, 0x05, 0xEC, 0xFC, 0xA7, 0x01, 0x4A, 0xFF, 0x2F,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x25, 0x00, 0x6D, 0xFF, 0x4E, 0x01,
- 0xB3, 0xFD, 0x8D, 0x03, 0xD4, 0xFA, 0x5D, 0x08, 0x8D, 0x48, 0x74,
- 0xFF, 0xAE, 0xFE, 0x8D, 0x01, 0xBB, 0xFE, 0xD1, 0x00, 0x9E, 0xFF,
- 0x18, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE0, 0x01, 0x57,
- 0xFC, 0x85, 0x06, 0x34, 0xF4, 0xE0, 0x1C, 0xF0, 0x3F, 0x6D, 0xF4,
- 0x8C, 0x04, 0x2C, 0xFE, 0x99, 0x00, 0xE7, 0xFF, 0xF8, 0xFF, 0x04,
- 0x00, 0xFD, 0xFF, 0x27, 0x00, 0x65, 0xFF, 0x98, 0x01, 0x8A, 0xFC,
- 0xEC, 0x06, 0x7F, 0xF1, 0x04, 0x32, 0x7B, 0x2E, 0x8A, 0xF1, 0x1A,
- 0x07, 0x5D, 0xFC, 0xB8, 0x01, 0x54, 0xFF, 0x2D, 0x00, 0xFD, 0xFF,
- 0x06, 0x00, 0xEA, 0xFF, 0x0C, 0x00, 0x4E, 0x00, 0xAF, 0xFE, 0xB8,
- 0x03, 0xC7, 0xF5, 0x38, 0x42, 0x0C, 0x19, 0x32, 0xF5, 0x23, 0x06,
- 0x7D, 0xFC, 0xD3, 0x01, 0x3A, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1C,
- 0x00, 0x8D, 0xFF, 0xFC, 0x00, 0x61, 0xFE, 0x39, 0x02, 0x6B, 0xFD,
- 0x37, 0x02, 0xEB, 0x48, 0x31, 0x05, 0x21, 0xFC, 0xE4, 0x02, 0x08,
- 0xFE, 0x26, 0x01, 0x7C, 0xFF, 0x21, 0x00, 0x00, 0x00, 0xFF, 0xFF,
- 0x32, 0x00, 0x41, 0xFF, 0xC0, 0x01, 0xAF, 0xFC, 0xAD, 0x05, 0x4A,
- 0xF6, 0x44, 0x15, 0x2F, 0x44, 0x64, 0xF7, 0xC9, 0x02, 0x3D, 0xFF,
- 0xFE, 0xFF, 0x34, 0x00, 0xDB, 0xFF, 0x09, 0x00, 0xFD, 0xFF, 0x32,
- 0x00, 0x47, 0xFF, 0xD0, 0x01, 0x40, 0xFC, 0x2A, 0x07, 0xCA, 0xF1,
- 0xD1, 0x2A, 0x65, 0x35, 0xAE, 0xF1, 0xA0, 0x06, 0xC7, 0xFC, 0x70,
- 0x01, 0x7A, 0xFF, 0x20, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x05, 0x00,
- 0xC5, 0xFF, 0xDE, 0x00, 0xB7, 0xFD, 0x45, 0x05, 0x56, 0xF3, 0x61,
- 0x3D, 0xBA, 0x20, 0x56, 0xF3, 0xD3, 0x06, 0x3E, 0xFC, 0xE6, 0x01,
- 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x13, 0x00, 0xAF, 0xFF, 0xA5,
- 0x00, 0x16, 0xFF, 0xE3, 0x00, 0xE4, 0xFF, 0xEB, 0xFC, 0xD2, 0x47,
- 0xB6, 0x0B, 0x89, 0xF9, 0x2F, 0x04, 0x62, 0xFD, 0x72, 0x01, 0x5E,
- 0xFF, 0x29, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2C, 0x00, 0x56, 0xFF,
- 0x88, 0x01, 0x31, 0xFD, 0x95, 0x04, 0xB4, 0xF8, 0xFC, 0x0D, 0x26,
- 0x47, 0x64, 0xFB, 0xA7, 0x00, 0x77, 0x00, 0x51, 0xFF, 0x89, 0x00,
- 0xBA, 0xFF, 0x11, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xE6,
- 0x01, 0x34, 0xFC, 0xF9, 0x06, 0xD9, 0xF2, 0x3F, 0x23, 0x90, 0x3B,
- 0xC4, 0xF2, 0xAE, 0x05, 0x72, 0xFD, 0x07, 0x01, 0xB0, 0xFF, 0x0C,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1A, 0x00, 0x8A, 0xFF, 0x51, 0x01,
- 0xF8, 0xFC, 0x5E, 0x06, 0xED, 0xF1, 0x82, 0x37, 0x60, 0x28, 0x0E,
- 0xF2, 0x26, 0x07, 0x35, 0xFC, 0xDB, 0x01, 0x40, 0xFF, 0x34, 0x00,
- 0xFD, 0xFF, 0x0C, 0x00, 0xD0, 0xFF, 0x4F, 0x00, 0xC7, 0xFF, 0xA0,
- 0xFF, 0x20, 0x02, 0x96, 0xF8, 0x4E, 0x45, 0xD7, 0x12, 0x0D, 0xF7,
- 0x58, 0x05, 0xD6, 0xFC, 0xB0, 0x01, 0x47, 0xFF, 0x30, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x23, 0x00, 0x72, 0xFF, 0x40, 0x01, 0xD0, 0xFD,
- 0x53, 0x03, 0x47, 0xFB, 0x3F, 0x07, 0xB8, 0x48, 0x62, 0x00, 0x3F,
- 0xFE, 0xC8, 0x01, 0x9C, 0xFE, 0xE0, 0x00, 0x98, 0xFF, 0x19, 0x00,
- 0xFE, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xDC, 0x01, 0x63, 0xFC, 0x66,
- 0x06, 0x89, 0xF4, 0x8C, 0x1B, 0xC3, 0x40, 0xDD, 0xF4, 0x46, 0x04,
- 0x58, 0xFE, 0x80, 0x00, 0xF4, 0xFF, 0xF3, 0xFF, 0x05, 0x00, 0xFD,
- 0xFF, 0x29, 0x00, 0x5F, 0xFF, 0xA5, 0x01, 0x78, 0xFC, 0xFF, 0x06,
- 0x7D, 0xF1, 0xCF, 0x30, 0xB8, 0x2F, 0x80, 0xF1, 0x0D, 0x07, 0x6A,
- 0xFC, 0xAE, 0x01, 0x59, 0xFF, 0x2B, 0x00, 0xFD, 0xFF, 0x05, 0x00,
- 0xEF, 0xFF, 0xFF, 0xFF, 0x69, 0x00, 0x80, 0xFE, 0x04, 0x04, 0x48,
- 0xF5, 0x74, 0x41, 0x5D, 0x1A, 0xD7, 0xF4, 0x47, 0x06, 0x6F, 0xFC,
- 0xD8, 0x01, 0x39, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1B, 0x00, 0x93,
- 0xFF, 0xED, 0x00, 0x80, 0xFE, 0xFD, 0x01, 0xDC, 0xFD, 0x3C, 0x01,
- 0xD5, 0x48, 0x45, 0x06, 0xAE, 0xFB, 0x1F, 0x03, 0xEA, 0xFD, 0x34,
- 0x01, 0x77, 0xFF, 0x22, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x00,
- 0x44, 0xFF, 0xB8, 0x01, 0xC3, 0xFC, 0x81, 0x05, 0xB0, 0xF6, 0xFA,
- 0x13, 0xCC, 0x44, 0x02, 0xF8, 0x71, 0x02, 0x71, 0xFF, 0xE1, 0xFF,
- 0x42, 0x00, 0xD5, 0xFF, 0x0B, 0x00, 0xFD, 0xFF, 0x33, 0x00, 0x43,
- 0xFF, 0xD6, 0x01, 0x39, 0xFC, 0x2A, 0x07, 0xEB, 0xF1, 0x87, 0x29,
- 0x85, 0x36, 0xCC, 0xF1, 0x7F, 0x06, 0xE0, 0xFC, 0x60, 0x01, 0x82,
- 0xFF, 0x1D, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x09, 0x00, 0xBA, 0xFF,
- 0xF4, 0x00, 0x91, 0xFD, 0x7E, 0x05, 0x05, 0xF3, 0x6E, 0x3C, 0x10,
- 0x22, 0x12, 0xF3, 0xE9, 0x06, 0x38, 0xFC, 0xE6, 0x01, 0x37, 0xFF,
- 0x36, 0x00, 0xFD, 0xFF, 0x12, 0x00, 0xB5, 0xFF, 0x96, 0x00, 0x35,
- 0xFF, 0xA9, 0x00, 0x4D, 0x00, 0x19, 0xFC, 0x7C, 0x47, 0xE8, 0x0C,
- 0x18, 0xF9, 0x66, 0x04, 0x48, 0xFD, 0x7E, 0x01, 0x5A, 0xFF, 0x2B,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x5A, 0xFF, 0x7D, 0x01,
- 0x4B, 0xFD, 0x60, 0x04, 0x24, 0xF9, 0xC6, 0x0C, 0x86, 0x47, 0x30,
- 0xFC, 0x41, 0x00, 0xB0, 0x00, 0x32, 0xFF, 0x98, 0x00, 0xB4, 0xFF,
- 0x12, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x38,
- 0xFC, 0xE6, 0x06, 0x19, 0xF3, 0xEA, 0x21, 0x8A, 0x3C, 0x0E, 0xF3,
- 0x78, 0x05, 0x96, 0xFD, 0xF1, 0x00, 0xBB, 0xFF, 0x08, 0x00, 0x01,
- 0x00, 0xFE, 0xFF, 0x1D, 0x00, 0x81, 0xFF, 0x62, 0x01, 0xDD, 0xFC,
- 0x83, 0x06, 0xC9, 0xF1, 0x66, 0x36, 0xAC, 0x29, 0xE7, 0xF1, 0x2A,
- 0x07, 0x3A, 0xFC, 0xD5, 0x01, 0x43, 0xFF, 0x33, 0x00, 0xFD, 0xFF,
- 0x0B, 0x00, 0xD6, 0xFF, 0x41, 0x00, 0xE4, 0xFF, 0x6B, 0xFF, 0x7B,
- 0x02, 0xF0, 0xF7, 0xBA, 0x44, 0x1E, 0x14, 0xA5, 0xF6, 0x86, 0x05,
- 0xC1, 0xFC, 0xB9, 0x01, 0x44, 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x22, 0x00, 0x77, 0xFF, 0x32, 0x01, 0xED, 0xFD, 0x19, 0x03,
- 0xBB, 0xFB, 0x26, 0x06, 0xD7, 0x48, 0x58, 0x01, 0xCF, 0xFD, 0x04,
- 0x02, 0x7D, 0xFE, 0xEF, 0x00, 0x92, 0xFF, 0x1B, 0x00, 0xFE, 0xFF,
- 0x35, 0x00, 0x39, 0xFF, 0xD8, 0x01, 0x70, 0xFC, 0x43, 0x06, 0xE1,
- 0xF4, 0x38, 0x1A, 0x8C, 0x41, 0x55, 0xF5, 0xFC, 0x03, 0x85, 0xFE,
- 0x66, 0x00, 0x01, 0x00, 0xEE, 0xFF, 0x06, 0x00, 0xFD, 0xFF, 0x2B,
- 0x00, 0x59, 0xFF, 0xB0, 0x01, 0x69, 0xFC, 0x0F, 0x07, 0x80, 0xF1,
- 0x96, 0x2F, 0xF2, 0x30, 0x7C, 0xF1, 0xFD, 0x06, 0x7A, 0xFC, 0xA3,
- 0x01, 0x5F, 0xFF, 0x29, 0x00, 0xFD, 0xFF, 0x05, 0x00, 0xF4, 0xFF,
- 0xF2, 0xFF, 0x83, 0x00, 0x53, 0xFE, 0x4E, 0x04, 0xD0, 0xF4, 0xAB,
- 0x40, 0xB2, 0x1B, 0x7F, 0xF4, 0x69, 0x06, 0x62, 0xFC, 0xDD, 0x01,
- 0x38, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x19, 0x00, 0x98, 0xFF, 0xDE,
- 0x00, 0x9F, 0xFE, 0xC2, 0x01, 0x4B, 0xFE, 0x48, 0x00, 0xB3, 0x48,
- 0x5E, 0x07, 0x3B, 0xFB, 0x59, 0x03, 0xCD, 0xFD, 0x42, 0x01, 0x71,
- 0xFF, 0x24, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0x00, 0x47, 0xFF,
- 0xAF, 0x01, 0xD8, 0xFC, 0x52, 0x05, 0x19, 0xF7, 0xB2, 0x12, 0x5C,
- 0x45, 0xA9, 0xF8, 0x16, 0x02, 0xA6, 0xFF, 0xC3, 0xFF, 0x51, 0x00,
- 0xD0, 0xFF, 0x0C, 0x00, 0xFD, 0xFF, 0x34, 0x00, 0x40, 0xFF, 0xDB,
- 0x01, 0x35, 0xFC, 0x25, 0x07, 0x13, 0xF2, 0x3A, 0x28, 0xA0, 0x37,
- 0xF2, 0xF1, 0x5A, 0x06, 0xFB, 0xFC, 0x4F, 0x01, 0x8B, 0xFF, 0x1A,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x0D, 0x00, 0xAF, 0xFF, 0x09, 0x01,
- 0x6E, 0xFD, 0xB4, 0x05, 0xBC, 0xF2, 0x73, 0x3B, 0x64, 0x23, 0xD2,
- 0xF2, 0xFB, 0x06, 0x34, 0xFC, 0xE6, 0x01, 0x38, 0xFF, 0x36, 0x00,
- 0xFD, 0xFF, 0x11, 0x00, 0xBB, 0xFF, 0x87, 0x00, 0x54, 0xFF, 0x70,
- 0x00, 0xB3, 0x00, 0x4E, 0xFB, 0x1A, 0x47, 0x1F, 0x0E, 0xA8, 0xF8,
- 0x9B, 0x04, 0x2E, 0xFD, 0x8A, 0x01, 0x55, 0xFF, 0x2C, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x29, 0x00, 0x5F, 0xFF, 0x71, 0x01, 0x65, 0xFD,
- 0x29, 0x04, 0x96, 0xF9, 0x95, 0x0B, 0xDC, 0x47, 0x03, 0xFD, 0xD9,
- 0xFF, 0xEA, 0x00, 0x12, 0xFF, 0xA7, 0x00, 0xAE, 0xFF, 0x14, 0x00,
- 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3E, 0xFC, 0xD0,
- 0x06, 0x5E, 0xF3, 0x94, 0x20, 0x7B, 0x3D, 0x60, 0xF3, 0x3E, 0x05,
- 0xBB, 0xFD, 0xDB, 0x00, 0xC6, 0xFF, 0x04, 0x00, 0x02, 0x00, 0xFE,
- 0xFF, 0x20, 0x00, 0x79, 0xFF, 0x72, 0x01, 0xC4, 0xFC, 0xA4, 0x06,
- 0xAB, 0xF1, 0x46, 0x35, 0xF7, 0x2A, 0xC6, 0xF1, 0x2A, 0x07, 0x40,
- 0xFC, 0xCF, 0x01, 0x47, 0xFF, 0x31, 0x00, 0xFD, 0xFF, 0x09, 0x00,
- 0xDB, 0xFF, 0x33, 0x00, 0x01, 0x00, 0x38, 0xFF, 0xD3, 0x02, 0x53,
- 0xF7, 0x1F, 0x44, 0x69, 0x15, 0x3F, 0xF6, 0xB2, 0x05, 0xAD, 0xFC,
- 0xC1, 0x01, 0x41, 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x20,
- 0x00, 0x7D, 0xFF, 0x24, 0x01, 0x0C, 0xFE, 0xDE, 0x02, 0x2E, 0xFC,
- 0x13, 0x05, 0xEC, 0x48, 0x54, 0x02, 0x5E, 0xFD, 0x3F, 0x02, 0x5D,
- 0xFE, 0xFE, 0x00, 0x8C, 0xFF, 0x1C, 0x00, 0xFE, 0xFF, 0x35, 0x00,
- 0x3B, 0xFF, 0xD3, 0x01, 0x7F, 0xFC, 0x1F, 0x06, 0x3C, 0xF5, 0xE6,
- 0x18, 0x4D, 0x42, 0xD5, 0xF5, 0xAF, 0x03, 0xB4, 0xFE, 0x4B, 0x00,
- 0x0E, 0x00, 0xE9, 0xFF, 0x07, 0x00, 0xFD, 0xFF, 0x2D, 0x00, 0x53,
- 0xFF, 0xBA, 0x01, 0x5B, 0xFC, 0x1B, 0x07, 0x8B, 0xF1, 0x58, 0x2E,
- 0x26, 0x32, 0x80, 0xF1, 0xEA, 0x06, 0x8C, 0xFC, 0x97, 0x01, 0x66,
- 0xFF, 0x27, 0x00, 0xFD, 0xFF, 0x04, 0x00, 0xF8, 0xFF, 0xE6, 0xFF,
- 0x9C, 0x00, 0x27, 0xFE, 0x94, 0x04, 0x61, 0xF4, 0xD7, 0x3F, 0x06,
- 0x1D, 0x2B, 0xF4, 0x89, 0x06, 0x56, 0xFC, 0xE0, 0x01, 0x37, 0xFF,
- 0x36, 0x00, 0xFE, 0xFF, 0x17, 0x00, 0x9E, 0xFF, 0xCF, 0x00, 0xBF,
- 0xFE, 0x86, 0x01, 0xBA, 0xFE, 0x5A, 0xFF, 0x86, 0x48, 0x7D, 0x08,
- 0xC7, 0xFA, 0x93, 0x03, 0xB0, 0xFD, 0x4F, 0x01, 0x6C, 0xFF, 0x25,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2F, 0x00, 0x4B, 0xFF, 0xA6, 0x01,
- 0xEE, 0xFC, 0x23, 0x05, 0x83, 0xF7, 0x6E, 0x11, 0xE5, 0x45, 0x57,
- 0xF9, 0xB8, 0x01, 0xDC, 0xFF, 0xA5, 0xFF, 0x5F, 0x00, 0xCA, 0xFF,
- 0x0D, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3D, 0xFF, 0xDF, 0x01, 0x32,
- 0xFC, 0x1E, 0x07, 0x40, 0xF2, 0xEB, 0x26, 0xB5, 0x38, 0x1F, 0xF2,
- 0x32, 0x06, 0x18, 0xFD, 0x3D, 0x01, 0x94, 0xFF, 0x16, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x11, 0x00, 0xA4, 0xFF, 0x1D, 0x01, 0x4C, 0xFD,
- 0xE6, 0x05, 0x7B, 0xF2, 0x71, 0x3A, 0xB8, 0x24, 0x97, 0xF2, 0x0B,
- 0x07, 0x32, 0xFC, 0xE4, 0x01, 0x39, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0x0F, 0x00, 0xC0, 0xFF, 0x78, 0x00, 0x73, 0xFF, 0x38, 0x00, 0x17,
- 0x01, 0x8B, 0xFA, 0xAF, 0x46, 0x59, 0x0F, 0x39, 0xF8, 0xCF, 0x04,
- 0x15, 0xFD, 0x95, 0x01, 0x51, 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x28, 0x00, 0x64, 0xFF, 0x65, 0x01, 0x81, 0xFD, 0xF2, 0x03,
- 0x08, 0xFA, 0x68, 0x0A, 0x25, 0x48, 0xDE, 0xFD, 0x6E, 0xFF, 0x24,
- 0x01, 0xF3, 0xFE, 0xB6, 0x00, 0xA8, 0xFF, 0x15, 0x00, 0xFD, 0xFF,
- 0x36, 0x00, 0x36, 0xFF, 0xE5, 0x01, 0x46, 0xFC, 0xB8, 0x06, 0xA8,
- 0xF3, 0x3F, 0x1F, 0x64, 0x3E, 0xBA, 0xF3, 0x01, 0x05, 0xE2, 0xFD,
- 0xC4, 0x00, 0xD2, 0xFF, 0x00, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x23,
- 0x00, 0x71, 0xFF, 0x81, 0x01, 0xAE, 0xFC, 0xC1, 0x06, 0x95, 0xF1,
- 0x1E, 0x34, 0x3E, 0x2C, 0xAB, 0xF1, 0x27, 0x07, 0x49, 0xFC, 0xC8,
- 0x01, 0x4B, 0xFF, 0x30, 0x00, 0xFD, 0xFF, 0x08, 0x00, 0xE1, 0xFF,
- 0x25, 0x00, 0x1D, 0x00, 0x05, 0xFF, 0x28, 0x03, 0xBD, 0xF6, 0x77,
- 0x43, 0xB6, 0x16, 0xDC, 0xF5, 0xDD, 0x05, 0x9B, 0xFC, 0xC8, 0x01,
- 0x3E, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x83,
- 0xFF, 0x16, 0x01, 0x2A, 0xFE, 0xA3, 0x02, 0xA1, 0xFC, 0x06, 0x04,
- 0xF5, 0x48, 0x56, 0x03, 0xED, 0xFC, 0x7B, 0x02, 0x3E, 0xFE, 0x0C,
- 0x01, 0x86, 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3D, 0xFF,
- 0xCC, 0x01, 0x8F, 0xFC, 0xF8, 0x05, 0x9B, 0xF5, 0x96, 0x17, 0x02,
- 0x43, 0x5E, 0xF6, 0x5F, 0x03, 0xE4, 0xFE, 0x30, 0x00, 0x1B, 0x00,
- 0xE4, 0xFF, 0x08, 0x00, 0xFD, 0xFF, 0x2F, 0x00, 0x4E, 0xFF, 0xC3,
- 0x01, 0x4F, 0xFC, 0x24, 0x07, 0x9C, 0xF1, 0x17, 0x2D, 0x57, 0x33,
- 0x8A, 0xF1, 0xD3, 0x06, 0x9F, 0xFC, 0x8A, 0x01, 0x6D, 0xFF, 0x25,
- 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0xD9, 0xFF, 0xB4, 0x00,
- 0xFD, 0xFD, 0xD7, 0x04, 0xFA, 0xF3, 0xFC, 0x3E, 0x5B, 0x1E, 0xDB,
- 0xF3, 0xA6, 0x06, 0x4C, 0xFC, 0xE3, 0x01, 0x36, 0xFF, 0x36, 0x00,
- 0xFE, 0xFF, 0x16, 0x00, 0xA4, 0xFF, 0xC0, 0x00, 0xDE, 0xFE, 0x4B,
- 0x01, 0x27, 0xFF, 0x73, 0xFE, 0x4F, 0x48, 0xA2, 0x09, 0x54, 0xFA,
- 0xCC, 0x03, 0x93, 0xFD, 0x5C, 0x01, 0x67, 0xFF, 0x27, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x2E, 0x00, 0x4E, 0xFF, 0x9C, 0x01, 0x05, 0xFD,
- 0xF1, 0x04, 0xF0, 0xF7, 0x2D, 0x10, 0x61, 0x46, 0x0D, 0xFA, 0x58,
- 0x01, 0x13, 0x00, 0x87, 0xFF, 0x6E, 0x00, 0xC4, 0xFF, 0x0E, 0x00,
- 0xFD, 0xFF, 0x35, 0x00, 0x3B, 0xFF, 0xE3, 0x01, 0x31, 0xFC, 0x14,
- 0x07, 0x73, 0xF2, 0x99, 0x25, 0xC2, 0x39, 0x54, 0xF2, 0x05, 0x06,
- 0x37, 0xFD, 0x2B, 0x01, 0x9E, 0xFF, 0x13, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x14, 0x00, 0x9B, 0xFF, 0x31, 0x01, 0x2C, 0xFD, 0x15, 0x06,
- 0x41, 0xF2, 0x6A, 0x39, 0x0A, 0x26, 0x61, 0xF2, 0x17, 0x07, 0x31,
- 0xFC, 0xE2, 0x01, 0x3B, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x0E, 0x00,
- 0xC6, 0xFF, 0x69, 0x00, 0x91, 0xFF, 0x00, 0x00, 0x78, 0x01, 0xD0,
- 0xF9, 0x39, 0x46, 0x98, 0x10, 0xCB, 0xF7, 0x02, 0x05, 0xFE, 0xFC,
- 0x9F, 0x01, 0x4D, 0xFF, 0x2E, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x26,
- 0x00, 0x69, 0xFF, 0x58, 0x01, 0x9D, 0xFD, 0xB9, 0x03, 0x7B, 0xFA,
- 0x40, 0x09, 0x63, 0x48, 0xBF, 0xFE, 0x03, 0xFF, 0x5F, 0x01, 0xD4,
- 0xFE, 0xC5, 0x00, 0xA2, 0xFF, 0x16, 0x00, 0xFE, 0xFF, 0x36, 0x00,
- 0x36, 0xFF, 0xE2, 0x01, 0x4F, 0xFC, 0x9C, 0x06, 0xF5, 0xF3, 0xEA,
- 0x1D, 0x47, 0x3F, 0x1B, 0xF4, 0xC1, 0x04, 0x0B, 0xFE, 0xAC, 0x00,
- 0xDE, 0xFF, 0xFB, 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0x25, 0x00, 0x6A,
- 0xFF, 0x8E, 0x01, 0x99, 0xFC, 0xDB, 0x06, 0x86, 0xF1, 0xF2, 0x32,
- 0x82, 0x2D, 0x96, 0xF1, 0x21, 0x07, 0x53, 0xFC, 0xC0, 0x01, 0x50,
- 0xFF, 0x2E, 0x00, 0xFD, 0xFF, 0x07, 0x00, 0xE6, 0xFF, 0x17, 0x00,
- 0x39, 0x00, 0xD4, 0xFE, 0x7A, 0x03, 0x2F, 0xF6, 0xC7, 0x42, 0x06,
- 0x18, 0x7B, 0xF5, 0x05, 0x06, 0x8A, 0xFC, 0xCF, 0x01, 0x3C, 0xFF,
- 0x34, 0x00, 0xFE, 0xFF, 0x1D, 0x00, 0x88, 0xFF, 0x07, 0x01, 0x49,
- 0xFE, 0x67, 0x02, 0x13, 0xFD, 0xFF, 0x02, 0xF4, 0x48, 0x5F, 0x04,
- 0x7A, 0xFC, 0xB6, 0x02, 0x20, 0xFE, 0x1B, 0x01, 0x81, 0xFF, 0x1F,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x3F, 0xFF, 0xC6, 0x01,
- 0xA1, 0xFC, 0xCF, 0x05, 0xFC, 0xF5, 0x47, 0x16, 0xB0, 0x43, 0xEE,
- 0xF6, 0x0C, 0x03, 0x16, 0xFF, 0x14, 0x00, 0x29, 0x00, 0xDF, 0xFF,
- 0x09, 0x00, 0xFD, 0xFF, 0x30, 0x00, 0x4A, 0xFF, 0xCA, 0x01, 0x46,
- 0xFC, 0x29, 0x07, 0xB3, 0xF1, 0xD1, 0x2B, 0x81, 0x34, 0x9C, 0xF1,
- 0xB8, 0x06, 0xB5, 0xFC, 0x7C, 0x01, 0x74, 0xFF, 0x22, 0x00, 0xFE,
- 0xFF, 0x02, 0x00, 0x01, 0x00, 0xCE, 0xFF, 0xCC, 0x00, 0xD5, 0xFD,
- 0x16, 0x05, 0x9B, 0xF3, 0x18, 0x3E, 0xB1, 0x1F, 0x8F, 0xF3, 0xC0,
- 0x06, 0x43, 0xFC, 0xE5, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0x15, 0x00, 0xAA, 0xFF, 0xB1, 0x00, 0xFE, 0xFE, 0x10, 0x01, 0x92,
- 0xFF, 0x94, 0xFD, 0x0D, 0x48, 0xCB, 0x0A, 0xE2, 0xF9, 0x04, 0x04,
- 0x77, 0xFD, 0x69, 0x01, 0x62, 0xFF, 0x28, 0x00, 0x00, 0x00, 0xFF,
- 0xFF, 0x2D, 0x00, 0x52, 0xFF, 0x91, 0x01, 0x1E, 0xFD, 0xBE, 0x04,
- 0x5E, 0xF8, 0xF0, 0x0E, 0xD3, 0x46, 0xCB, 0xFA, 0xF6, 0x00, 0x4B,
- 0x00, 0x69, 0xFF, 0x7D, 0x00, 0xBE, 0xFF, 0x10, 0x00, 0xFD, 0xFF,
- 0x36, 0x00, 0x39, 0xFF, 0xE5, 0x01, 0x32, 0xFC, 0x06, 0x07, 0xAA,
- 0xF2, 0x46, 0x24, 0xC8, 0x3A, 0x90, 0xF2, 0xD6, 0x05, 0x57, 0xFD,
- 0x17, 0x01, 0xA8, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18,
- 0x00, 0x91, 0xFF, 0x43, 0x01, 0x0E, 0xFD, 0x40, 0x06, 0x0F, 0xF2,
- 0x5B, 0x38, 0x5C, 0x27, 0x30, 0xF2, 0x21, 0x07, 0x33, 0xFC, 0xDE,
- 0x01, 0x3E, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x0D, 0x00, 0xCC, 0xFF,
- 0x5A, 0x00, 0xAF, 0xFF, 0xCA, 0xFF, 0xD8, 0x01, 0x1C, 0xF9, 0xB8,
- 0x45, 0xDA, 0x11, 0x60, 0xF7, 0x33, 0x05, 0xE7, 0xFC, 0xA9, 0x01,
- 0x4A, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x25, 0x00, 0x6E,
- 0xFF, 0x4B, 0x01, 0xB9, 0xFD, 0x80, 0x03, 0xEE, 0xFA, 0x1D, 0x08,
- 0x98, 0x48, 0xA8, 0xFF, 0x95, 0xFE, 0x9A, 0x01, 0xB4, 0xFE, 0xD4,
- 0x00, 0x9C, 0xFF, 0x18, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF,
- 0xDF, 0x01, 0x5A, 0xFC, 0x7E, 0x06, 0x47, 0xF4, 0x94, 0x1C, 0x1F,
- 0x40, 0x85, 0xF4, 0x7D, 0x04, 0x36, 0xFE, 0x93, 0x00, 0xEA, 0xFF,
- 0xF7, 0xFF, 0x04, 0x00, 0xFD, 0xFF, 0x28, 0x00, 0x63, 0xFF, 0x9B,
- 0x01, 0x86, 0xFC, 0xF1, 0x06, 0x7E, 0xF1, 0xC0, 0x31, 0xC2, 0x2E,
- 0x87, 0xF1, 0x17, 0x07, 0x5F, 0xFC, 0xB6, 0x01, 0x55, 0xFF, 0x2D,
- 0x00, 0xFD, 0xFF, 0x06, 0x00, 0xEB, 0xFF, 0x09, 0x00, 0x54, 0x00,
- 0xA4, 0xFE, 0xC9, 0x03, 0xAA, 0xF5, 0x0C, 0x42, 0x56, 0x19, 0x1E,
- 0xF5, 0x2B, 0x06, 0x7A, 0xFC, 0xD4, 0x01, 0x3A, 0xFF, 0x35, 0x00,
- 0xFE, 0xFF, 0x1C, 0x00, 0x8E, 0xFF, 0xF9, 0x00, 0x68, 0xFE, 0x2C,
- 0x02, 0x84, 0xFD, 0xFF, 0x01, 0xE6, 0x48, 0x6E, 0x05, 0x07, 0xFC,
- 0xF1, 0x02, 0x01, 0xFE, 0x29, 0x01, 0x7B, 0xFF, 0x21, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x32, 0x00, 0x42, 0xFF, 0xBE, 0x01, 0xB4, 0xFC,
- 0xA4, 0x05, 0x61, 0xF6, 0xFB, 0x14, 0x53, 0x44, 0x86, 0xF7, 0xB6,
- 0x02, 0x49, 0xFF, 0xF7, 0xFF, 0x37, 0x00, 0xD9, 0xFF, 0x0A, 0x00,
- 0xFD, 0xFF, 0x32, 0x00, 0x46, 0xFF, 0xD1, 0x01, 0x3E, 0xFC, 0x2B,
- 0x07, 0xD0, 0xF1, 0x89, 0x2A, 0xA6, 0x35, 0xB4, 0xF1, 0x99, 0x06,
- 0xCD, 0xFC, 0x6D, 0x01, 0x7C, 0xFF, 0x1F, 0x00, 0xFE, 0xFF, 0x01,
- 0x00, 0x06, 0x00, 0xC2, 0xFF, 0xE3, 0x00, 0xAE, 0xFD, 0x52, 0x05,
- 0x44, 0xF3, 0x2A, 0x3D, 0x06, 0x21, 0x47, 0xF3, 0xD8, 0x06, 0x3C,
- 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x13, 0x00,
- 0xB0, 0xFF, 0xA2, 0x00, 0x1D, 0xFF, 0xD6, 0x00, 0xFC, 0xFF, 0xBC,
- 0xFC, 0xC0, 0x47, 0xFA, 0x0B, 0x70, 0xF9, 0x3C, 0x04, 0x5C, 0xFD,
- 0x75, 0x01, 0x5D, 0xFF, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B,
- 0x00, 0x57, 0xFF, 0x86, 0x01, 0x36, 0xFD, 0x89, 0x04, 0xCD, 0xF8,
- 0xB7, 0x0D, 0x3D, 0x47, 0x91, 0xFB, 0x91, 0x00, 0x83, 0x00, 0x4A,
- 0xFF, 0x8C, 0x00, 0xB9, 0xFF, 0x11, 0x00, 0xFD, 0xFF, 0x36, 0x00,
- 0x38, 0xFF, 0xE6, 0x01, 0x35, 0xFC, 0xF5, 0x06, 0xE7, 0xF2, 0xF2,
- 0x22, 0xC7, 0x3B, 0xD4, 0xF2, 0xA2, 0x05, 0x7A, 0xFD, 0x02, 0x01,
- 0xB2, 0xFF, 0x0B, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x1B, 0x00, 0x88,
- 0xFF, 0x55, 0x01, 0xF2, 0xFC, 0x67, 0x06, 0xE4, 0xF1, 0x44, 0x37,
- 0xAA, 0x28, 0x05, 0xF2, 0x27, 0x07, 0x36, 0xFC, 0xDA, 0x01, 0x41,
- 0xFF, 0x33, 0x00, 0xFD, 0xFF, 0x0B, 0x00, 0xD2, 0xFF, 0x4C, 0x00,
- 0xCD, 0xFF, 0x94, 0xFF, 0x34, 0x02, 0x70, 0xF8, 0x2E, 0x45, 0x20,
- 0x13, 0xF6, 0xF6, 0x62, 0x05, 0xD1, 0xFC, 0xB2, 0x01, 0x46, 0xFF,
- 0x31, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x23, 0x00, 0x73, 0xFF, 0x3D,
- 0x01, 0xD6, 0xFD, 0x46, 0x03, 0x61, 0xFB, 0x00, 0x07, 0xBF, 0x48,
- 0x98, 0x00, 0x26, 0xFE, 0xD5, 0x01, 0x95, 0xFE, 0xE3, 0x00, 0x96,
- 0xFF, 0x1A, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xDB, 0x01,
- 0x66, 0xFC, 0x5E, 0x06, 0x9C, 0xF4, 0x40, 0x1B, 0xEF, 0x40, 0xF7,
- 0xF4, 0x35, 0x04, 0x62, 0xFE, 0x7A, 0x00, 0xF7, 0xFF, 0xF2, 0xFF,
- 0x05, 0x00, 0xFD, 0xFF, 0x2A, 0x00, 0x5D, 0xFF, 0xA7, 0x01, 0x75,
- 0xFC, 0x03, 0x07, 0x7D, 0xF1, 0x8A, 0x30, 0xFF, 0x2F, 0x7E, 0xF1,
- 0x0A, 0x07, 0x6E, 0xFC, 0xAC, 0x01, 0x5A, 0xFF, 0x2B, 0x00, 0xFD,
- 0xFF, 0x05, 0x00, 0xF0, 0xFF, 0xFC, 0xFF, 0x6E, 0x00, 0x76, 0xFE,
- 0x15, 0x04, 0x2C, 0xF5, 0x49, 0x41, 0xA9, 0x1A, 0xC3, 0xF4, 0x4F,
- 0x06, 0x6C, 0xFC, 0xD9, 0x01, 0x38, 0xFF, 0x35, 0x00, 0xFE, 0xFF,
- 0x1A, 0x00, 0x94, 0xFF, 0xEA, 0x00, 0x87, 0xFE, 0xF0, 0x01, 0xF5,
- 0xFD, 0x05, 0x01, 0xCE, 0x48, 0x83, 0x06, 0x94, 0xFB, 0x2C, 0x03,
- 0xE4, 0xFD, 0x37, 0x01, 0x76, 0xFF, 0x22, 0x00, 0x00, 0x00, 0xFF,
- 0xFF, 0x31, 0x00, 0x45, 0xFF, 0xB6, 0x01, 0xC8, 0xFC, 0x77, 0x05,
- 0xC7, 0xF6, 0xB1, 0x13, 0xED, 0x44, 0x26, 0xF8, 0x5D, 0x02, 0x7D,
- 0xFF, 0xDA, 0xFF, 0x46, 0x00, 0xD4, 0xFF, 0x0B, 0x00, 0xFD, 0xFF,
- 0x33, 0x00, 0x42, 0xFF, 0xD7, 0x01, 0x38, 0xFC, 0x29, 0x07, 0xF3,
- 0xF1, 0x3E, 0x29, 0xC6, 0x36, 0xD4, 0xF1, 0x77, 0x06, 0xE6, 0xFC,
- 0x5C, 0x01, 0x84, 0xFF, 0x1C, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x0A,
- 0x00, 0xB7, 0xFF, 0xF9, 0x00, 0x89, 0xFD, 0x8A, 0x05, 0xF4, 0xF2,
- 0x37, 0x3C, 0x5B, 0x22, 0x03, 0xF3, 0xED, 0x06, 0x37, 0xFC, 0xE6,
- 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x12, 0x00, 0xB6, 0xFF,
- 0x93, 0x00, 0x3C, 0xFF, 0x9D, 0x00, 0x63, 0x00, 0xEB, 0xFB, 0x69,
- 0x47, 0x2D, 0x0D, 0xFF, 0xF8, 0x72, 0x04, 0x42, 0xFD, 0x81, 0x01,
- 0x59, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x5B,
- 0xFF, 0x7A, 0x01, 0x50, 0xFD, 0x54, 0x04, 0x3D, 0xF9, 0x82, 0x0C,
- 0x9A, 0x47, 0x5E, 0xFC, 0x2A, 0x00, 0xBD, 0x00, 0x2B, 0xFF, 0x9B,
- 0x00, 0xB3, 0xFF, 0x12, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF,
- 0xE6, 0x01, 0x3A, 0xFC, 0xE2, 0x06, 0x28, 0xF3, 0x9E, 0x21, 0xC0,
- 0x3C, 0x1F, 0xF3, 0x6C, 0x05, 0x9E, 0xFD, 0xED, 0x00, 0xBD, 0xFF,
- 0x07, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x1E, 0x00, 0x80, 0xFF, 0x66,
- 0x01, 0xD8, 0xFC, 0x8B, 0x06, 0xC1, 0xF1, 0x27, 0x36, 0xF6, 0x29,
- 0xDF, 0xF1, 0x2A, 0x07, 0x3B, 0xFC, 0xD4, 0x01, 0x44, 0xFF, 0x32,
- 0x00, 0xFD, 0xFF, 0x0A, 0x00, 0xD7, 0xFF, 0x3E, 0x00, 0xEA, 0xFF,
- 0x60, 0xFF, 0x8F, 0x02, 0xCD, 0xF7, 0x99, 0x44, 0x68, 0x14, 0x8E,
- 0xF6, 0x90, 0x05, 0xBC, 0xFC, 0xBA, 0x01, 0x43, 0xFF, 0x32, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0x22, 0x00, 0x79, 0xFF, 0x2F, 0x01, 0xF4,
- 0xFD, 0x0C, 0x03, 0xD4, 0xFB, 0xE9, 0x05, 0xDE, 0x48, 0x8F, 0x01,
- 0xB6, 0xFD, 0x11, 0x02, 0x76, 0xFE, 0xF2, 0x00, 0x91, 0xFF, 0x1B,
- 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x39, 0xFF, 0xD7, 0x01, 0x73, 0xFC,
- 0x3B, 0x06, 0xF5, 0xF4, 0xED, 0x19, 0xB7, 0x41, 0x71, 0xF5, 0xEB,
- 0x03, 0x90, 0xFE, 0x60, 0x00, 0x04, 0x00, 0xED, 0xFF, 0x06, 0x00,
- 0xFD, 0xFF, 0x2C, 0x00, 0x57, 0xFF, 0xB2, 0x01, 0x65, 0xFC, 0x12,
- 0x07, 0x82, 0xF1, 0x50, 0x2F, 0x38, 0x31, 0x7C, 0xF1, 0xF9, 0x06,
- 0x7E, 0xFC, 0xA1, 0x01, 0x61, 0xFF, 0x29, 0x00, 0xFD, 0xFF, 0x04,
- 0x00, 0xF5, 0xFF, 0xEF, 0xFF, 0x88, 0x00, 0x49, 0xFE, 0x5D, 0x04,
- 0xB7, 0xF4, 0x7D, 0x40, 0xFD, 0x1B, 0x6C, 0xF4, 0x70, 0x06, 0x5F,
- 0xFC, 0xDE, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x19, 0x00,
- 0x9A, 0xFF, 0xDB, 0x00, 0xA6, 0xFE, 0xB4, 0x01, 0x64, 0xFE, 0x12,
- 0x00, 0xAA, 0x48, 0x9E, 0x07, 0x21, 0xFB, 0x66, 0x03, 0xC6, 0xFD,
- 0x45, 0x01, 0x70, 0xFF, 0x24, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30,
- 0x00, 0x48, 0xFF, 0xAD, 0x01, 0xDD, 0xFC, 0x48, 0x05, 0x30, 0xF7,
- 0x6B, 0x12, 0x7D, 0x45, 0xCF, 0xF8, 0x01, 0x02, 0xB2, 0xFF, 0xBD,
- 0xFF, 0x54, 0x00, 0xCE, 0xFF, 0x0C, 0x00, 0xFD, 0xFF, 0x34, 0x00,
- 0x3F, 0xFF, 0xDC, 0x01, 0x34, 0xFC, 0x24, 0x07, 0x1C, 0xF2, 0xF0,
- 0x27, 0xDF, 0x37, 0xFB, 0xF1, 0x51, 0x06, 0x01, 0xFD, 0x4B, 0x01,
- 0x8D, 0xFF, 0x19, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x0E, 0x00, 0xAC,
- 0xFF, 0x0E, 0x01, 0x66, 0xFD, 0xBF, 0x05, 0xAD, 0xF2, 0x3B, 0x3B,
- 0xB0, 0x23, 0xC4, 0xF2, 0xFF, 0x06, 0x33, 0xFC, 0xE5, 0x01, 0x38,
- 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x10, 0x00, 0xBC, 0xFF, 0x84, 0x00,
- 0x5B, 0xFF, 0x64, 0x00, 0xC9, 0x00, 0x22, 0xFB, 0x02, 0x47, 0x64,
- 0x0E, 0x8F, 0xF8, 0xA7, 0x04, 0x29, 0xFD, 0x8C, 0x01, 0x54, 0xFF,
- 0x2C, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x29, 0x00, 0x60, 0xFF, 0x6E,
- 0x01, 0x6B, 0xFD, 0x1D, 0x04, 0xAF, 0xF9, 0x51, 0x0B, 0xEC, 0x47,
- 0x33, 0xFD, 0xC1, 0xFF, 0xF7, 0x00, 0x0C, 0xFF, 0xAA, 0x00, 0xAD,
- 0xFF, 0x14, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01,
- 0x40, 0xFC, 0xCB, 0x06, 0x6E, 0xF3, 0x49, 0x20, 0xB0, 0x3D, 0x73,
- 0xF3, 0x31, 0x05, 0xC4, 0xFD, 0xD6, 0x00, 0xC8, 0xFF, 0x03, 0x00,
- 0x02, 0x00, 0xFE, 0xFF, 0x21, 0x00, 0x77, 0xFF, 0x75, 0x01, 0xBF,
- 0xFC, 0xAB, 0x06, 0xA6, 0xF1, 0x05, 0x35, 0x40, 0x2B, 0xBF, 0xF1,
- 0x2A, 0x07, 0x42, 0xFC, 0xCE, 0x01, 0x48, 0xFF, 0x31, 0x00, 0xFD,
- 0xFF, 0x09, 0x00, 0xDC, 0xFF, 0x2F, 0x00, 0x07, 0x00, 0x2C, 0xFF,
- 0xE6, 0x02, 0x31, 0xF7, 0xFA, 0x43, 0xB3, 0x15, 0x29, 0xF6, 0xBC,
- 0x05, 0xA9, 0xFC, 0xC2, 0x01, 0x40, 0xFF, 0x33, 0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x20, 0x00, 0x7E, 0xFF, 0x21, 0x01, 0x12, 0xFE, 0xD1,
- 0x02, 0x47, 0xFC, 0xD7, 0x04, 0xF0, 0x48, 0x8D, 0x02, 0x45, 0xFD,
- 0x4D, 0x02, 0x56, 0xFE, 0x01, 0x01, 0x8B, 0xFF, 0x1D, 0x00, 0xFE,
- 0xFF, 0x34, 0x00, 0x3B, 0xFF, 0xD1, 0x01, 0x83, 0xFC, 0x16, 0x06,
- 0x51, 0xF5, 0x9B, 0x18, 0x75, 0x42, 0xF3, 0xF5, 0x9D, 0x03, 0xBF,
- 0xFE, 0x45, 0x00, 0x11, 0x00, 0xE8, 0xFF, 0x07, 0x00, 0xFD, 0xFF,
- 0x2E, 0x00, 0x52, 0xFF, 0xBC, 0x01, 0x58, 0xFC, 0x1D, 0x07, 0x8E,
- 0xF1, 0x11, 0x2E, 0x6B, 0x32, 0x81, 0xF1, 0xE5, 0x06, 0x90, 0xFC,
- 0x94, 0x01, 0x67, 0xFF, 0x26, 0x00, 0xFD, 0xFF, 0x04, 0x00, 0xF9,
- 0xFF, 0xE3, 0xFF, 0xA1, 0x00, 0x1E, 0xFE, 0xA3, 0x04, 0x49, 0xF4,
- 0xA8, 0x3F, 0x52, 0x1D, 0x19, 0xF4, 0x90, 0x06, 0x53, 0xFC, 0xE1,
- 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x17, 0x00, 0xA0, 0xFF,
- 0xCC, 0x00, 0xC6, 0xFE, 0x79, 0x01, 0xD2, 0xFE, 0x26, 0xFF, 0x7C,
- 0x48, 0xBE, 0x08, 0xAE, 0xFA, 0xA0, 0x03, 0xA9, 0xFD, 0x52, 0x01,
- 0x6B, 0xFF, 0x25, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2F, 0x00, 0x4C,
- 0xFF, 0xA3, 0x01, 0xF3, 0xFC, 0x18, 0x05, 0x9B, 0xF7, 0x27, 0x11,
- 0x02, 0x46, 0x7F, 0xF9, 0xA3, 0x01, 0xE8, 0xFF, 0x9F, 0xFF, 0x63,
- 0x00, 0xC9, 0xFF, 0x0D, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3C, 0xFF,
- 0xE0, 0x01, 0x32, 0xFC, 0x1C, 0x07, 0x4B, 0xF2, 0xA0, 0x26, 0xF2,
- 0x38, 0x2A, 0xF2, 0x28, 0x06, 0x1F, 0xFD, 0x39, 0x01, 0x96, 0xFF,
- 0x16, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x11, 0x00, 0xA2, 0xFF, 0x22,
- 0x01, 0x45, 0xFD, 0xF1, 0x05, 0x6D, 0xF2, 0x38, 0x3A, 0x03, 0x25,
- 0x8B, 0xF2, 0x0E, 0x07, 0x32, 0xFC, 0xE4, 0x01, 0x3A, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0x0F, 0x00, 0xC2, 0xFF, 0x75, 0x00, 0x7A, 0xFF,
- 0x2B, 0x00, 0x2D, 0x01, 0x61, 0xFA, 0x97, 0x46, 0xA0, 0x0F, 0x20,
- 0xF8, 0xDA, 0x04, 0x10, 0xFD, 0x97, 0x01, 0x50, 0xFF, 0x2E, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0x27, 0x00, 0x65, 0xFF, 0x62, 0x01, 0x87,
- 0xFD, 0xE5, 0x03, 0x21, 0xFA, 0x25, 0x0A, 0x33, 0x48, 0x0F, 0xFE,
- 0x57, 0xFF, 0x31, 0x01, 0xEC, 0xFE, 0xB9, 0x00, 0xA7, 0xFF, 0x15,
- 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE4, 0x01, 0x48, 0xFC,
- 0xB2, 0x06, 0xB9, 0xF3, 0xF3, 0x1E, 0x98, 0x3E, 0xCF, 0xF3, 0xF3,
- 0x04, 0xEB, 0xFD, 0xBF, 0x00, 0xD4, 0xFF, 0xFF, 0xFF, 0x03, 0x00,
- 0xFE, 0xFF, 0x23, 0x00, 0x70, 0xFF, 0x84, 0x01, 0xA9, 0xFC, 0xC7,
- 0x06, 0x91, 0xF1, 0xDC, 0x33, 0x87, 0x2C, 0xA5, 0xF1, 0x26, 0x07,
- 0x4B, 0xFC, 0xC6, 0x01, 0x4C, 0xFF, 0x30, 0x00, 0xFD, 0xFF, 0x08,
- 0x00, 0xE2, 0xFF, 0x21, 0x00, 0x23, 0x00, 0xFA, 0xFE, 0x3A, 0x03,
- 0x9D, 0xF6, 0x50, 0x43, 0x00, 0x17, 0xC6, 0xF5, 0xE6, 0x05, 0x97,
- 0xFC, 0xC9, 0x01, 0x3E, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0x00, 0x00,
- 0x1E, 0x00, 0x84, 0xFF, 0x13, 0x01, 0x31, 0xFE, 0x95, 0x02, 0xBA,
- 0xFC, 0xCB, 0x03, 0xF7, 0x48, 0x91, 0x03, 0xD3, 0xFC, 0x88, 0x02,
- 0x38, 0xFE, 0x10, 0x01, 0x85, 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0x34,
- 0x00, 0x3D, 0xFF, 0xCB, 0x01, 0x93, 0xFC, 0xEF, 0x05, 0xB0, 0xF5,
- 0x4B, 0x17, 0x2A, 0x43, 0x7D, 0xF6, 0x4D, 0x03, 0xEF, 0xFE, 0x2A,
- 0x00, 0x1E, 0x00, 0xE3, 0xFF, 0x08, 0x00, 0xFD, 0xFF, 0x2F, 0x00,
- 0x4D, 0xFF, 0xC4, 0x01, 0x4D, 0xFC, 0x25, 0x07, 0xA1, 0xF1, 0xCE,
- 0x2C, 0x99, 0x33, 0x8E, 0xF1, 0xCD, 0x06, 0xA4, 0xFC, 0x87, 0x01,
- 0x6E, 0xFF, 0x24, 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFE, 0xFF, 0xD7,
- 0xFF, 0xBA, 0x00, 0xF4, 0xFD, 0xE5, 0x04, 0xE4, 0xF3, 0xCA, 0x3E,
- 0xA7, 0x1E, 0xCA, 0xF3, 0xAC, 0x06, 0x4A, 0xFC, 0xE4, 0x01, 0x36,
- 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x16, 0x00, 0xA6, 0xFF, 0xBD, 0x00,
- 0xE5, 0xFE, 0x3E, 0x01, 0x3F, 0xFF, 0x41, 0xFE, 0x41, 0x48, 0xE4,
- 0x09, 0x3B, 0xFA, 0xD9, 0x03, 0x8D, 0xFD, 0x5F, 0x01, 0x66, 0xFF,
- 0x27, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2E, 0x00, 0x4F, 0xFF, 0x99,
- 0x01, 0x0B, 0xFD, 0xE6, 0x04, 0x08, 0xF8, 0xE7, 0x0F, 0x7C, 0x46,
- 0x37, 0xFA, 0x42, 0x01, 0x1F, 0x00, 0x81, 0xFF, 0x71, 0x00, 0xC3,
- 0xFF, 0x0F, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xE3, 0x01,
- 0x31, 0xFC, 0x11, 0x07, 0x7F, 0xF2, 0x4E, 0x25, 0xFD, 0x39, 0x60,
- 0xF2, 0xFB, 0x05, 0x3E, 0xFD, 0x26, 0x01, 0xA0, 0xFF, 0x12, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00, 0x98, 0xFF, 0x35, 0x01, 0x25,
- 0xFD, 0x1E, 0x06, 0x35, 0xF2, 0x2E, 0x39, 0x55, 0x26, 0x56, 0xF2,
- 0x1A, 0x07, 0x31, 0xFC, 0xE1, 0x01, 0x3C, 0xFF, 0x35, 0x00, 0xFD,
- 0xFF, 0x0E, 0x00, 0xC7, 0xFF, 0x66, 0x00, 0x98, 0xFF, 0xF4, 0xFF,
- 0x8E, 0x01, 0xA7, 0xF9, 0x1D, 0x46, 0xDF, 0x10, 0xB3, 0xF7, 0x0D,
- 0x05, 0xF8, 0xFC, 0xA1, 0x01, 0x4C, 0xFF, 0x2F, 0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x26, 0x00, 0x6A, 0xFF, 0x55, 0x01, 0xA3, 0xFD, 0xAD,
- 0x03, 0x94, 0xFA, 0xFF, 0x08, 0x70, 0x48, 0xF3, 0xFE, 0xEA, 0xFE,
- 0x6C, 0x01, 0xCD, 0xFE, 0xC9, 0x00, 0xA1, 0xFF, 0x17, 0x00, 0xFE,
- 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE2, 0x01, 0x51, 0xFC, 0x96, 0x06,
- 0x07, 0xF4, 0x9E, 0x1D, 0x77, 0x3F, 0x32, 0xF4, 0xB2, 0x04, 0x15,
- 0xFE, 0xA7, 0x00, 0xE0, 0xFF, 0xFA, 0xFF, 0x03, 0x00, 0xFD, 0xFF,
- 0x26, 0x00, 0x69, 0xFF, 0x91, 0x01, 0x94, 0xFC, 0xE0, 0x06, 0x84,
- 0xF1, 0xAF, 0x32, 0xCA, 0x2D, 0x92, 0xF1, 0x1F, 0x07, 0x56, 0xFC,
- 0xBE, 0x01, 0x51, 0xFF, 0x2E, 0x00, 0xFD, 0xFF, 0x07, 0x00, 0xE7,
- 0xFF, 0x14, 0x00, 0x3F, 0x00, 0xC9, 0xFE, 0x8C, 0x03, 0x11, 0xF6,
- 0x9E, 0x42, 0x50, 0x18, 0x66, 0xF5, 0x0D, 0x06, 0x86, 0xFC, 0xD0,
- 0x01, 0x3B, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0x1D, 0x00, 0x8A, 0xFF,
- 0x04, 0x01, 0x50, 0xFE, 0x5A, 0x02, 0x2C, 0xFD, 0xC6, 0x02, 0xF2,
- 0x48, 0x9B, 0x04, 0x61, 0xFC, 0xC3, 0x02, 0x19, 0xFE, 0x1E, 0x01,
- 0x7F, 0xFF, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x40,
- 0xFF, 0xC4, 0x01, 0xA5, 0xFC, 0xC5, 0x05, 0x13, 0xF6, 0xFD, 0x15,
- 0xD4, 0x43, 0x0F, 0xF7, 0xF9, 0x02, 0x21, 0xFF, 0x0D, 0x00, 0x2C,
- 0x00, 0xDE, 0xFF, 0x09, 0x00, 0xFD, 0xFF, 0x31, 0x00, 0x49, 0xFF,
- 0xCC, 0x01, 0x44, 0xFC, 0x29, 0x07, 0xB9, 0xF1, 0x89, 0x2B, 0xC3,
- 0x34, 0xA0, 0xF1, 0xB1, 0x06, 0xBA, 0xFC, 0x79, 0x01, 0x76, 0xFF,
- 0x21, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x02, 0x00, 0xCB, 0xFF, 0xD1,
- 0x00, 0xCC, 0xFD, 0x24, 0x05, 0x87, 0xF3, 0xE4, 0x3D, 0xFD, 0x1F,
- 0x7F, 0xF3, 0xC6, 0x06, 0x41, 0xFC, 0xE5, 0x01, 0x36, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0x14, 0x00, 0xAC, 0xFF, 0xAE, 0x00, 0x05, 0xFF,
- 0x03, 0x01, 0xAA, 0xFF, 0x63, 0xFD, 0xFD, 0x47, 0x0E, 0x0B, 0xC8,
- 0xF9, 0x11, 0x04, 0x71, 0xFD, 0x6C, 0x01, 0x61, 0xFF, 0x28, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x2D, 0x00, 0x53, 0xFF, 0x8F, 0x01, 0x23,
- 0xFD, 0xB2, 0x04, 0x76, 0xF8, 0xAA, 0x0E, 0xED, 0x46, 0xF7, 0xFA,
- 0xDF, 0x00, 0x57, 0x00, 0x62, 0xFF, 0x80, 0x00, 0xBD, 0xFF, 0x10,
- 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x39, 0xFF, 0xE5, 0x01, 0x33, 0xFC,
- 0x03, 0x07, 0xB7, 0xF2, 0xFC, 0x23, 0x03, 0x3B, 0x9E, 0xF2, 0xCB,
- 0x05, 0x5F, 0xFD, 0x12, 0x01, 0xAA, 0xFF, 0x0E, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x18, 0x00, 0x8F, 0xFF, 0x47, 0x01, 0x08, 0xFD, 0x49,
- 0x06, 0x05, 0xF2, 0x1D, 0x38, 0xA6, 0x27, 0x26, 0xF2, 0x23, 0x07,
- 0x33, 0xFC, 0xDD, 0x01, 0x3E, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x0C,
- 0x00, 0xCD, 0xFF, 0x57, 0x00, 0xB6, 0xFF, 0xBE, 0xFF, 0xED, 0x01,
- 0xF5, 0xF8, 0x9B, 0x45, 0x22, 0x12, 0x48, 0xF7, 0x3D, 0x05, 0xE2,
- 0xFC, 0xAB, 0x01, 0x49, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x24, 0x00, 0x6F, 0xFF, 0x48, 0x01, 0xC0, 0xFD, 0x73, 0x03, 0x07,
- 0xFB, 0xDD, 0x07, 0xA1, 0x48, 0xDD, 0xFF, 0x7D, 0xFE, 0xA7, 0x01,
- 0xAD, 0xFE, 0xD8, 0x00, 0x9B, 0xFF, 0x18, 0x00, 0xFE, 0xFF, 0x36,
- 0x00, 0x37, 0xFF, 0xDF, 0x01, 0x5C, 0xFC, 0x78, 0x06, 0x5A, 0xF4,
- 0x49, 0x1C, 0x4E, 0x40, 0x9E, 0xF4, 0x6D, 0x04, 0x3F, 0xFE, 0x8E,
- 0x00, 0xED, 0xFF, 0xF6, 0xFF, 0x04, 0x00, 0xFD, 0xFF, 0x28, 0x00,
- 0x62, 0xFF, 0x9E, 0x01, 0x82, 0xFC, 0xF5, 0x06, 0x7D, 0xF1, 0x7B,
- 0x31, 0x09, 0x2F, 0x84, 0xF1, 0x15, 0x07, 0x62, 0xFC, 0xB4, 0x01,
- 0x56, 0xFF, 0x2C, 0x00, 0xFD, 0xFF, 0x06, 0x00, 0xEC, 0xFF, 0x06,
- 0x00, 0x5A, 0x00, 0x9A, 0xFE, 0xDA, 0x03, 0x8D, 0xF5, 0xE1, 0x41,
- 0xA1, 0x19, 0x09, 0xF5, 0x33, 0x06, 0x77, 0xFC, 0xD6, 0x01, 0x3A,
- 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1B, 0x00, 0x8F, 0xFF, 0xF5, 0x00,
- 0x6F, 0xFE, 0x1E, 0x02, 0x9D, 0xFD, 0xC7, 0x01, 0xE1, 0x48, 0xAB,
- 0x05, 0xEE, 0xFB, 0xFE, 0x02, 0xFB, 0xFD, 0x2C, 0x01, 0x7A, 0xFF,
- 0x21, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x32, 0x00, 0x42, 0xFF, 0xBC,
- 0x01, 0xB8, 0xFC, 0x9A, 0x05, 0x77, 0xF6, 0xB1, 0x14, 0x77, 0x44,
- 0xA9, 0xF7, 0xA2, 0x02, 0x54, 0xFF, 0xF1, 0xFF, 0x3A, 0x00, 0xD8,
- 0xFF, 0x0A, 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x45, 0xFF, 0xD3, 0x01,
- 0x3C, 0xFC, 0x2A, 0x07, 0xD8, 0xF1, 0x3F, 0x2A, 0xE6, 0x35, 0xBB,
- 0xF1, 0x92, 0x06, 0xD2, 0xFC, 0x69, 0x01, 0x7E, 0xFF, 0x1F, 0x00,
- 0xFE, 0xFF, 0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xE8, 0x00, 0xA6,
- 0xFD, 0x5F, 0x05, 0x31, 0xF3, 0xF6, 0x3C, 0x52, 0x21, 0x37, 0xF3,
- 0xDD, 0x06, 0x3B, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0x13, 0x00, 0xB1, 0xFF, 0x9F, 0x00, 0x24, 0xFF, 0xC9, 0x00,
- 0x13, 0x00, 0x8D, 0xFC, 0xAE, 0x47, 0x3E, 0x0C, 0x56, 0xF9, 0x48,
- 0x04, 0x56, 0xFD, 0x78, 0x01, 0x5C, 0xFF, 0x2A, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x2B, 0x00, 0x58, 0xFF, 0x83, 0x01, 0x3C, 0xFD, 0x7E,
- 0x04, 0xE6, 0xF8, 0x72, 0x0D, 0x52, 0x47, 0xBE, 0xFB, 0x7A, 0x00,
- 0x90, 0x00, 0x43, 0xFF, 0x8F, 0x00, 0xB7, 0xFF, 0x11, 0x00, 0xFD,
- 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x36, 0xFC, 0xF1, 0x06,
- 0xF5, 0xF2, 0xA7, 0x22, 0xFF, 0x3B, 0xE4, 0xF2, 0x96, 0x05, 0x81,
- 0xFD, 0xFD, 0x00, 0xB5, 0xFF, 0x0B, 0x00, 0x01, 0x00, 0xFE, 0xFF,
- 0x1C, 0x00, 0x86, 0xFF, 0x59, 0x01, 0xEC, 0xFC, 0x6F, 0x06, 0xDC,
- 0xF1, 0x04, 0x37, 0xF3, 0x28, 0xFC, 0xF1, 0x28, 0x07, 0x37, 0xFC,
- 0xD8, 0x01, 0x41, 0xFF, 0x33, 0x00, 0xFD, 0xFF, 0x0B, 0x00, 0xD3,
- 0xFF, 0x49, 0x00, 0xD4, 0xFF, 0x88, 0xFF, 0x49, 0x02, 0x4B, 0xF8,
- 0x0D, 0x45, 0x68, 0x13, 0xDF, 0xF6, 0x6C, 0x05, 0xCC, 0xFC, 0xB4,
- 0x01, 0x45, 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x23, 0x00,
- 0x74, 0xFF, 0x3A, 0x01, 0xDD, 0xFD, 0x39, 0x03, 0x7B, 0xFB, 0xC1,
- 0x06, 0xC7, 0x48, 0xCF, 0x00, 0x0D, 0xFE, 0xE3, 0x01, 0x8E, 0xFE,
- 0xE7, 0x00, 0x95, 0xFF, 0x1A, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x38,
- 0xFF, 0xDA, 0x01, 0x69, 0xFC, 0x57, 0x06, 0xAF, 0xF4, 0xF5, 0x1A,
- 0x1D, 0x41, 0x11, 0xF5, 0x25, 0x04, 0x6C, 0xFE, 0x74, 0x00, 0xF9,
- 0xFF, 0xF1, 0xFF, 0x05, 0x00, 0xFD, 0xFF, 0x2A, 0x00, 0x5C, 0xFF,
- 0xAA, 0x01, 0x71, 0xFC, 0x07, 0x07, 0x7E, 0xF1, 0x44, 0x30, 0x44,
- 0x30, 0x7E, 0xF1, 0x07, 0x07, 0x71, 0xFC, 0xAA, 0x01, 0x5C, 0xFF,
- 0x2A, 0x00, 0xFD, 0xFF, 0x05, 0x00, 0xF1, 0xFF, 0xF9, 0xFF, 0x74,
- 0x00, 0x6C, 0xFE, 0x25, 0x04, 0x11, 0xF5, 0x1D, 0x41, 0xF5, 0x1A,
- 0xAF, 0xF4, 0x57, 0x06, 0x69, 0xFC, 0xDA, 0x01, 0x38, 0xFF, 0x36,
- 0x00, 0xFE, 0xFF, 0x1A, 0x00, 0x95, 0xFF, 0xE7, 0x00, 0x8E, 0xFE,
- 0xE3, 0x01, 0x0D, 0xFE, 0xCF, 0x00, 0xC7, 0x48, 0xC1, 0x06, 0x7B,
- 0xFB, 0x39, 0x03, 0xDD, 0xFD, 0x3A, 0x01, 0x74, 0xFF, 0x23, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x00, 0x45, 0xFF, 0xB4, 0x01, 0xCC,
- 0xFC, 0x6C, 0x05, 0xDF, 0xF6, 0x68, 0x13, 0x0D, 0x45, 0x4B, 0xF8,
- 0x49, 0x02, 0x88, 0xFF, 0xD4, 0xFF, 0x49, 0x00, 0xD3, 0xFF, 0x0B,
- 0x00, 0xFD, 0xFF, 0x33, 0x00, 0x41, 0xFF, 0xD8, 0x01, 0x37, 0xFC,
- 0x28, 0x07, 0xFC, 0xF1, 0xF3, 0x28, 0x04, 0x37, 0xDC, 0xF1, 0x6F,
- 0x06, 0xEC, 0xFC, 0x59, 0x01, 0x86, 0xFF, 0x1C, 0x00, 0xFE, 0xFF,
- 0x01, 0x00, 0x0B, 0x00, 0xB5, 0xFF, 0xFD, 0x00, 0x81, 0xFD, 0x96,
- 0x05, 0xE4, 0xF2, 0xFF, 0x3B, 0xA7, 0x22, 0xF5, 0xF2, 0xF1, 0x06,
- 0x36, 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x11,
- 0x00, 0xB7, 0xFF, 0x8F, 0x00, 0x43, 0xFF, 0x90, 0x00, 0x7A, 0x00,
- 0xBE, 0xFB, 0x52, 0x47, 0x72, 0x0D, 0xE6, 0xF8, 0x7E, 0x04, 0x3C,
- 0xFD, 0x83, 0x01, 0x58, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2A, 0x00, 0x5C, 0xFF, 0x78, 0x01, 0x56, 0xFD, 0x48, 0x04, 0x56,
- 0xF9, 0x3E, 0x0C, 0xAE, 0x47, 0x8D, 0xFC, 0x13, 0x00, 0xC9, 0x00,
- 0x24, 0xFF, 0x9F, 0x00, 0xB1, 0xFF, 0x13, 0x00, 0xFD, 0xFF, 0x36,
- 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3B, 0xFC, 0xDD, 0x06, 0x37, 0xF3,
- 0x52, 0x21, 0xF6, 0x3C, 0x31, 0xF3, 0x5F, 0x05, 0xA6, 0xFD, 0xE8,
- 0x00, 0xC0, 0xFF, 0x07, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x1F, 0x00,
- 0x7E, 0xFF, 0x69, 0x01, 0xD2, 0xFC, 0x92, 0x06, 0xBB, 0xF1, 0xE6,
- 0x35, 0x3F, 0x2A, 0xD8, 0xF1, 0x2A, 0x07, 0x3C, 0xFC, 0xD3, 0x01,
- 0x45, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x0A, 0x00, 0xD8, 0xFF, 0x3A,
- 0x00, 0xF1, 0xFF, 0x54, 0xFF, 0xA2, 0x02, 0xA9, 0xF7, 0x77, 0x44,
- 0xB1, 0x14, 0x77, 0xF6, 0x9A, 0x05, 0xB8, 0xFC, 0xBC, 0x01, 0x42,
- 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x21, 0x00, 0x7A, 0xFF,
- 0x2C, 0x01, 0xFB, 0xFD, 0xFE, 0x02, 0xEE, 0xFB, 0xAB, 0x05, 0xE1,
- 0x48, 0xC7, 0x01, 0x9D, 0xFD, 0x1E, 0x02, 0x6F, 0xFE, 0xF5, 0x00,
- 0x8F, 0xFF, 0x1B, 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xD6,
- 0x01, 0x77, 0xFC, 0x33, 0x06, 0x09, 0xF5, 0xA1, 0x19, 0xE1, 0x41,
- 0x8D, 0xF5, 0xDA, 0x03, 0x9A, 0xFE, 0x5A, 0x00, 0x06, 0x00, 0xEC,
- 0xFF, 0x06, 0x00, 0xFD, 0xFF, 0x2C, 0x00, 0x56, 0xFF, 0xB4, 0x01,
- 0x62, 0xFC, 0x15, 0x07, 0x84, 0xF1, 0x09, 0x2F, 0x7B, 0x31, 0x7D,
- 0xF1, 0xF5, 0x06, 0x82, 0xFC, 0x9E, 0x01, 0x62, 0xFF, 0x28, 0x00,
- 0xFD, 0xFF, 0x04, 0x00, 0xF6, 0xFF, 0xED, 0xFF, 0x8E, 0x00, 0x3F,
- 0xFE, 0x6D, 0x04, 0x9E, 0xF4, 0x4E, 0x40, 0x49, 0x1C, 0x5A, 0xF4,
- 0x78, 0x06, 0x5C, 0xFC, 0xDF, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE,
- 0xFF, 0x18, 0x00, 0x9B, 0xFF, 0xD8, 0x00, 0xAD, 0xFE, 0xA7, 0x01,
- 0x7D, 0xFE, 0xDD, 0xFF, 0xA1, 0x48, 0xDD, 0x07, 0x07, 0xFB, 0x73,
- 0x03, 0xC0, 0xFD, 0x48, 0x01, 0x6F, 0xFF, 0x24, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x30, 0x00, 0x49, 0xFF, 0xAB, 0x01, 0xE2, 0xFC, 0x3D,
- 0x05, 0x48, 0xF7, 0x22, 0x12, 0x9B, 0x45, 0xF5, 0xF8, 0xED, 0x01,
- 0xBE, 0xFF, 0xB6, 0xFF, 0x57, 0x00, 0xCD, 0xFF, 0x0C, 0x00, 0xFD,
- 0xFF, 0x34, 0x00, 0x3E, 0xFF, 0xDD, 0x01, 0x33, 0xFC, 0x23, 0x07,
- 0x26, 0xF2, 0xA6, 0x27, 0x1D, 0x38, 0x05, 0xF2, 0x49, 0x06, 0x08,
- 0xFD, 0x47, 0x01, 0x8F, 0xFF, 0x18, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x0E, 0x00, 0xAA, 0xFF, 0x12, 0x01, 0x5F, 0xFD, 0xCB, 0x05, 0x9E,
- 0xF2, 0x03, 0x3B, 0xFC, 0x23, 0xB7, 0xF2, 0x03, 0x07, 0x33, 0xFC,
- 0xE5, 0x01, 0x39, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x10, 0x00, 0xBD,
- 0xFF, 0x80, 0x00, 0x62, 0xFF, 0x57, 0x00, 0xDF, 0x00, 0xF7, 0xFA,
- 0xED, 0x46, 0xAA, 0x0E, 0x76, 0xF8, 0xB2, 0x04, 0x23, 0xFD, 0x8F,
- 0x01, 0x53, 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x28, 0x00,
- 0x61, 0xFF, 0x6C, 0x01, 0x71, 0xFD, 0x11, 0x04, 0xC8, 0xF9, 0x0E,
- 0x0B, 0xFD, 0x47, 0x63, 0xFD, 0xAA, 0xFF, 0x03, 0x01, 0x05, 0xFF,
- 0xAE, 0x00, 0xAC, 0xFF, 0x14, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36,
- 0xFF, 0xE5, 0x01, 0x41, 0xFC, 0xC6, 0x06, 0x7F, 0xF3, 0xFD, 0x1F,
- 0xE4, 0x3D, 0x87, 0xF3, 0x24, 0x05, 0xCC, 0xFD, 0xD1, 0x00, 0xCB,
- 0xFF, 0x02, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x21, 0x00, 0x76, 0xFF,
- 0x79, 0x01, 0xBA, 0xFC, 0xB1, 0x06, 0xA0, 0xF1, 0xC3, 0x34, 0x89,
- 0x2B, 0xB9, 0xF1, 0x29, 0x07, 0x44, 0xFC, 0xCC, 0x01, 0x49, 0xFF,
- 0x31, 0x00, 0xFD, 0xFF, 0x09, 0x00, 0xDE, 0xFF, 0x2C, 0x00, 0x0D,
- 0x00, 0x21, 0xFF, 0xF9, 0x02, 0x0F, 0xF7, 0xD4, 0x43, 0xFD, 0x15,
- 0x13, 0xF6, 0xC5, 0x05, 0xA5, 0xFC, 0xC4, 0x01, 0x40, 0xFF, 0x33,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x7F, 0xFF, 0x1E, 0x01,
- 0x19, 0xFE, 0xC3, 0x02, 0x61, 0xFC, 0x9B, 0x04, 0xF2, 0x48, 0xC6,
- 0x02, 0x2C, 0xFD, 0x5A, 0x02, 0x50, 0xFE, 0x04, 0x01, 0x8A, 0xFF,
- 0x1D, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3B, 0xFF, 0xD0, 0x01, 0x86,
- 0xFC, 0x0D, 0x06, 0x66, 0xF5, 0x50, 0x18, 0x9E, 0x42, 0x11, 0xF6,
- 0x8C, 0x03, 0xC9, 0xFE, 0x3F, 0x00, 0x14, 0x00, 0xE7, 0xFF, 0x07,
- 0x00, 0xFD, 0xFF, 0x2E, 0x00, 0x51, 0xFF, 0xBE, 0x01, 0x56, 0xFC,
- 0x1F, 0x07, 0x92, 0xF1, 0xCA, 0x2D, 0xAF, 0x32, 0x84, 0xF1, 0xE0,
- 0x06, 0x94, 0xFC, 0x91, 0x01, 0x69, 0xFF, 0x26, 0x00, 0xFD, 0xFF,
- 0x03, 0x00, 0xFA, 0xFF, 0xE0, 0xFF, 0xA7, 0x00, 0x15, 0xFE, 0xB2,
- 0x04, 0x32, 0xF4, 0x77, 0x3F, 0x9E, 0x1D, 0x07, 0xF4, 0x96, 0x06,
- 0x51, 0xFC, 0xE2, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x17,
- 0x00, 0xA1, 0xFF, 0xC9, 0x00, 0xCD, 0xFE, 0x6C, 0x01, 0xEA, 0xFE,
- 0xF3, 0xFE, 0x70, 0x48, 0xFF, 0x08, 0x94, 0xFA, 0xAD, 0x03, 0xA3,
- 0xFD, 0x55, 0x01, 0x6A, 0xFF, 0x26, 0x00, 0x00, 0x00, 0xFF, 0xFF,
- 0x2F, 0x00, 0x4C, 0xFF, 0xA1, 0x01, 0xF8, 0xFC, 0x0D, 0x05, 0xB3,
- 0xF7, 0xDF, 0x10, 0x1D, 0x46, 0xA7, 0xF9, 0x8E, 0x01, 0xF4, 0xFF,
- 0x98, 0xFF, 0x66, 0x00, 0xC7, 0xFF, 0x0E, 0x00, 0xFD, 0xFF, 0x35,
- 0x00, 0x3C, 0xFF, 0xE1, 0x01, 0x31, 0xFC, 0x1A, 0x07, 0x56, 0xF2,
- 0x55, 0x26, 0x2E, 0x39, 0x35, 0xF2, 0x1E, 0x06, 0x25, 0xFD, 0x35,
- 0x01, 0x98, 0xFF, 0x15, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x12, 0x00,
- 0xA0, 0xFF, 0x26, 0x01, 0x3E, 0xFD, 0xFB, 0x05, 0x60, 0xF2, 0xFD,
- 0x39, 0x4E, 0x25, 0x7F, 0xF2, 0x11, 0x07, 0x31, 0xFC, 0xE3, 0x01,
- 0x3A, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x0F, 0x00, 0xC3, 0xFF, 0x71,
- 0x00, 0x81, 0xFF, 0x1F, 0x00, 0x42, 0x01, 0x37, 0xFA, 0x7C, 0x46,
- 0xE7, 0x0F, 0x08, 0xF8, 0xE6, 0x04, 0x0B, 0xFD, 0x99, 0x01, 0x4F,
- 0xFF, 0x2E, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x27, 0x00, 0x66, 0xFF,
- 0x5F, 0x01, 0x8D, 0xFD, 0xD9, 0x03, 0x3B, 0xFA, 0xE4, 0x09, 0x41,
- 0x48, 0x41, 0xFE, 0x3F, 0xFF, 0x3E, 0x01, 0xE5, 0xFE, 0xBD, 0x00,
- 0xA6, 0xFF, 0x16, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE4,
- 0x01, 0x4A, 0xFC, 0xAC, 0x06, 0xCA, 0xF3, 0xA7, 0x1E, 0xCA, 0x3E,
- 0xE4, 0xF3, 0xE5, 0x04, 0xF4, 0xFD, 0xBA, 0x00, 0xD7, 0xFF, 0xFE,
- 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0x24, 0x00, 0x6E, 0xFF, 0x87, 0x01,
- 0xA4, 0xFC, 0xCD, 0x06, 0x8E, 0xF1, 0x99, 0x33, 0xCE, 0x2C, 0xA1,
- 0xF1, 0x25, 0x07, 0x4D, 0xFC, 0xC4, 0x01, 0x4D, 0xFF, 0x2F, 0x00,
- 0xFD, 0xFF, 0x08, 0x00, 0xE3, 0xFF, 0x1E, 0x00, 0x2A, 0x00, 0xEF,
- 0xFE, 0x4D, 0x03, 0x7D, 0xF6, 0x2A, 0x43, 0x4B, 0x17, 0xB0, 0xF5,
- 0xEF, 0x05, 0x93, 0xFC, 0xCB, 0x01, 0x3D, 0xFF, 0x34, 0x00, 0xFE,
- 0xFF, 0x1E, 0x00, 0x85, 0xFF, 0x10, 0x01, 0x38, 0xFE, 0x88, 0x02,
- 0xD3, 0xFC, 0x91, 0x03, 0xF7, 0x48, 0xCB, 0x03, 0xBA, 0xFC, 0x95,
- 0x02, 0x31, 0xFE, 0x13, 0x01, 0x84, 0xFF, 0x1E, 0x00, 0x00, 0x00,
- 0xFE, 0xFF, 0x34, 0x00, 0x3E, 0xFF, 0xC9, 0x01, 0x97, 0xFC, 0xE6,
- 0x05, 0xC6, 0xF5, 0x00, 0x17, 0x50, 0x43, 0x9D, 0xF6, 0x3A, 0x03,
- 0xFA, 0xFE, 0x23, 0x00, 0x21, 0x00, 0xE2, 0xFF, 0x08, 0x00, 0xFD,
- 0xFF, 0x30, 0x00, 0x4C, 0xFF, 0xC6, 0x01, 0x4B, 0xFC, 0x26, 0x07,
- 0xA5, 0xF1, 0x87, 0x2C, 0xDC, 0x33, 0x91, 0xF1, 0xC7, 0x06, 0xA9,
- 0xFC, 0x84, 0x01, 0x70, 0xFF, 0x23, 0x00, 0xFE, 0xFF, 0x03, 0x00,
- 0xFF, 0xFF, 0xD4, 0xFF, 0xBF, 0x00, 0xEB, 0xFD, 0xF3, 0x04, 0xCF,
- 0xF3, 0x98, 0x3E, 0xF3, 0x1E, 0xB9, 0xF3, 0xB2, 0x06, 0x48, 0xFC,
- 0xE4, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x15, 0x00, 0xA7,
- 0xFF, 0xB9, 0x00, 0xEC, 0xFE, 0x31, 0x01, 0x57, 0xFF, 0x0F, 0xFE,
- 0x33, 0x48, 0x25, 0x0A, 0x21, 0xFA, 0xE5, 0x03, 0x87, 0xFD, 0x62,
- 0x01, 0x65, 0xFF, 0x27, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2E, 0x00,
- 0x50, 0xFF, 0x97, 0x01, 0x10, 0xFD, 0xDA, 0x04, 0x20, 0xF8, 0xA0,
- 0x0F, 0x97, 0x46, 0x61, 0xFA, 0x2D, 0x01, 0x2B, 0x00, 0x7A, 0xFF,
- 0x75, 0x00, 0xC2, 0xFF, 0x0F, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x3A,
- 0xFF, 0xE4, 0x01, 0x32, 0xFC, 0x0E, 0x07, 0x8B, 0xF2, 0x03, 0x25,
- 0x38, 0x3A, 0x6D, 0xF2, 0xF1, 0x05, 0x45, 0xFD, 0x22, 0x01, 0xA2,
- 0xFF, 0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x16, 0x00, 0x96, 0xFF,
- 0x39, 0x01, 0x1F, 0xFD, 0x28, 0x06, 0x2A, 0xF2, 0xF2, 0x38, 0xA0,
- 0x26, 0x4B, 0xF2, 0x1C, 0x07, 0x32, 0xFC, 0xE0, 0x01, 0x3C, 0xFF,
- 0x35, 0x00, 0xFD, 0xFF, 0x0D, 0x00, 0xC9, 0xFF, 0x63, 0x00, 0x9F,
- 0xFF, 0xE8, 0xFF, 0xA3, 0x01, 0x7F, 0xF9, 0x02, 0x46, 0x27, 0x11,
- 0x9B, 0xF7, 0x18, 0x05, 0xF3, 0xFC, 0xA3, 0x01, 0x4C, 0xFF, 0x2F,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x25, 0x00, 0x6B, 0xFF, 0x52, 0x01,
- 0xA9, 0xFD, 0xA0, 0x03, 0xAE, 0xFA, 0xBE, 0x08, 0x7C, 0x48, 0x26,
- 0xFF, 0xD2, 0xFE, 0x79, 0x01, 0xC6, 0xFE, 0xCC, 0x00, 0xA0, 0xFF,
- 0x17, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE1, 0x01, 0x53,
- 0xFC, 0x90, 0x06, 0x19, 0xF4, 0x52, 0x1D, 0xA8, 0x3F, 0x49, 0xF4,
- 0xA3, 0x04, 0x1E, 0xFE, 0xA1, 0x00, 0xE3, 0xFF, 0xF9, 0xFF, 0x04,
- 0x00, 0xFD, 0xFF, 0x26, 0x00, 0x67, 0xFF, 0x94, 0x01, 0x90, 0xFC,
- 0xE5, 0x06, 0x81, 0xF1, 0x6B, 0x32, 0x11, 0x2E, 0x8E, 0xF1, 0x1D,
- 0x07, 0x58, 0xFC, 0xBC, 0x01, 0x52, 0xFF, 0x2E, 0x00, 0xFD, 0xFF,
- 0x07, 0x00, 0xE8, 0xFF, 0x11, 0x00, 0x45, 0x00, 0xBF, 0xFE, 0x9D,
- 0x03, 0xF3, 0xF5, 0x75, 0x42, 0x9B, 0x18, 0x51, 0xF5, 0x16, 0x06,
- 0x83, 0xFC, 0xD1, 0x01, 0x3B, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0x1D,
- 0x00, 0x8B, 0xFF, 0x01, 0x01, 0x56, 0xFE, 0x4D, 0x02, 0x45, 0xFD,
- 0x8D, 0x02, 0xF0, 0x48, 0xD7, 0x04, 0x47, 0xFC, 0xD1, 0x02, 0x12,
- 0xFE, 0x21, 0x01, 0x7E, 0xFF, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF,
- 0x33, 0x00, 0x40, 0xFF, 0xC2, 0x01, 0xA9, 0xFC, 0xBC, 0x05, 0x29,
- 0xF6, 0xB3, 0x15, 0xFA, 0x43, 0x31, 0xF7, 0xE6, 0x02, 0x2C, 0xFF,
- 0x07, 0x00, 0x2F, 0x00, 0xDC, 0xFF, 0x09, 0x00, 0xFD, 0xFF, 0x31,
- 0x00, 0x48, 0xFF, 0xCE, 0x01, 0x42, 0xFC, 0x2A, 0x07, 0xBF, 0xF1,
- 0x40, 0x2B, 0x05, 0x35, 0xA6, 0xF1, 0xAB, 0x06, 0xBF, 0xFC, 0x75,
- 0x01, 0x77, 0xFF, 0x21, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x03, 0x00,
- 0xC8, 0xFF, 0xD6, 0x00, 0xC4, 0xFD, 0x31, 0x05, 0x73, 0xF3, 0xB0,
- 0x3D, 0x49, 0x20, 0x6E, 0xF3, 0xCB, 0x06, 0x40, 0xFC, 0xE6, 0x01,
- 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x14, 0x00, 0xAD, 0xFF, 0xAA,
- 0x00, 0x0C, 0xFF, 0xF7, 0x00, 0xC1, 0xFF, 0x33, 0xFD, 0xEC, 0x47,
- 0x51, 0x0B, 0xAF, 0xF9, 0x1D, 0x04, 0x6B, 0xFD, 0x6E, 0x01, 0x60,
- 0xFF, 0x29, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2C, 0x00, 0x54, 0xFF,
- 0x8C, 0x01, 0x29, 0xFD, 0xA7, 0x04, 0x8F, 0xF8, 0x64, 0x0E, 0x02,
- 0x47, 0x22, 0xFB, 0xC9, 0x00, 0x64, 0x00, 0x5B, 0xFF, 0x84, 0x00,
- 0xBC, 0xFF, 0x10, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xE5,
- 0x01, 0x33, 0xFC, 0xFF, 0x06, 0xC4, 0xF2, 0xB0, 0x23, 0x3B, 0x3B,
- 0xAD, 0xF2, 0xBF, 0x05, 0x66, 0xFD, 0x0E, 0x01, 0xAC, 0xFF, 0x0E,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x19, 0x00, 0x8D, 0xFF, 0x4B, 0x01,
- 0x01, 0xFD, 0x51, 0x06, 0xFB, 0xF1, 0xDF, 0x37, 0xF0, 0x27, 0x1C,
- 0xF2, 0x24, 0x07, 0x34, 0xFC, 0xDC, 0x01, 0x3F, 0xFF, 0x34, 0x00,
- 0xFD, 0xFF, 0x0C, 0x00, 0xCE, 0xFF, 0x54, 0x00, 0xBD, 0xFF, 0xB2,
- 0xFF, 0x01, 0x02, 0xCF, 0xF8, 0x7D, 0x45, 0x6B, 0x12, 0x30, 0xF7,
- 0x48, 0x05, 0xDD, 0xFC, 0xAD, 0x01, 0x48, 0xFF, 0x30, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x24, 0x00, 0x70, 0xFF, 0x45, 0x01, 0xC6, 0xFD,
- 0x66, 0x03, 0x21, 0xFB, 0x9E, 0x07, 0xAA, 0x48, 0x12, 0x00, 0x64,
- 0xFE, 0xB4, 0x01, 0xA6, 0xFE, 0xDB, 0x00, 0x9A, 0xFF, 0x19, 0x00,
- 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xDE, 0x01, 0x5F, 0xFC, 0x70,
- 0x06, 0x6C, 0xF4, 0xFD, 0x1B, 0x7D, 0x40, 0xB7, 0xF4, 0x5D, 0x04,
- 0x49, 0xFE, 0x88, 0x00, 0xEF, 0xFF, 0xF5, 0xFF, 0x04, 0x00, 0xFD,
- 0xFF, 0x29, 0x00, 0x61, 0xFF, 0xA1, 0x01, 0x7E, 0xFC, 0xF9, 0x06,
- 0x7C, 0xF1, 0x38, 0x31, 0x50, 0x2F, 0x82, 0xF1, 0x12, 0x07, 0x65,
- 0xFC, 0xB2, 0x01, 0x57, 0xFF, 0x2C, 0x00, 0xFD, 0xFF, 0x06, 0x00,
- 0xED, 0xFF, 0x04, 0x00, 0x60, 0x00, 0x90, 0xFE, 0xEB, 0x03, 0x71,
- 0xF5, 0xB7, 0x41, 0xED, 0x19, 0xF5, 0xF4, 0x3B, 0x06, 0x73, 0xFC,
- 0xD7, 0x01, 0x39, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1B, 0x00, 0x91,
- 0xFF, 0xF2, 0x00, 0x76, 0xFE, 0x11, 0x02, 0xB6, 0xFD, 0x8F, 0x01,
- 0xDE, 0x48, 0xE9, 0x05, 0xD4, 0xFB, 0x0C, 0x03, 0xF4, 0xFD, 0x2F,
- 0x01, 0x79, 0xFF, 0x22, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x32, 0x00,
- 0x43, 0xFF, 0xBA, 0x01, 0xBC, 0xFC, 0x90, 0x05, 0x8E, 0xF6, 0x68,
- 0x14, 0x99, 0x44, 0xCD, 0xF7, 0x8F, 0x02, 0x60, 0xFF, 0xEA, 0xFF,
- 0x3E, 0x00, 0xD7, 0xFF, 0x0A, 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x44,
- 0xFF, 0xD4, 0x01, 0x3B, 0xFC, 0x2A, 0x07, 0xDF, 0xF1, 0xF6, 0x29,
- 0x27, 0x36, 0xC1, 0xF1, 0x8B, 0x06, 0xD8, 0xFC, 0x66, 0x01, 0x80,
- 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x07, 0x00, 0xBD, 0xFF,
- 0xED, 0x00, 0x9E, 0xFD, 0x6C, 0x05, 0x1F, 0xF3, 0xC0, 0x3C, 0x9E,
- 0x21, 0x28, 0xF3, 0xE2, 0x06, 0x3A, 0xFC, 0xE6, 0x01, 0x37, 0xFF,
- 0x36, 0x00, 0xFD, 0xFF, 0x12, 0x00, 0xB3, 0xFF, 0x9B, 0x00, 0x2B,
- 0xFF, 0xBD, 0x00, 0x2A, 0x00, 0x5E, 0xFC, 0x9A, 0x47, 0x82, 0x0C,
- 0x3D, 0xF9, 0x54, 0x04, 0x50, 0xFD, 0x7A, 0x01, 0x5B, 0xFF, 0x2A,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x59, 0xFF, 0x81, 0x01,
- 0x42, 0xFD, 0x72, 0x04, 0xFF, 0xF8, 0x2D, 0x0D, 0x69, 0x47, 0xEB,
- 0xFB, 0x63, 0x00, 0x9D, 0x00, 0x3C, 0xFF, 0x93, 0x00, 0xB6, 0xFF,
- 0x12, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x37,
- 0xFC, 0xED, 0x06, 0x03, 0xF3, 0x5B, 0x22, 0x37, 0x3C, 0xF4, 0xF2,
- 0x8A, 0x05, 0x89, 0xFD, 0xF9, 0x00, 0xB7, 0xFF, 0x0A, 0x00, 0x01,
- 0x00, 0xFE, 0xFF, 0x1C, 0x00, 0x84, 0xFF, 0x5C, 0x01, 0xE6, 0xFC,
- 0x77, 0x06, 0xD4, 0xF1, 0xC6, 0x36, 0x3E, 0x29, 0xF3, 0xF1, 0x29,
- 0x07, 0x38, 0xFC, 0xD7, 0x01, 0x42, 0xFF, 0x33, 0x00, 0xFD, 0xFF,
- 0x0B, 0x00, 0xD4, 0xFF, 0x46, 0x00, 0xDA, 0xFF, 0x7D, 0xFF, 0x5D,
- 0x02, 0x26, 0xF8, 0xED, 0x44, 0xB1, 0x13, 0xC7, 0xF6, 0x77, 0x05,
- 0xC8, 0xFC, 0xB6, 0x01, 0x45, 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x22, 0x00, 0x76, 0xFF, 0x37, 0x01, 0xE4, 0xFD, 0x2C, 0x03,
- 0x94, 0xFB, 0x83, 0x06, 0xCE, 0x48, 0x05, 0x01, 0xF5, 0xFD, 0xF0,
- 0x01, 0x87, 0xFE, 0xEA, 0x00, 0x94, 0xFF, 0x1A, 0x00, 0xFE, 0xFF,
- 0x35, 0x00, 0x38, 0xFF, 0xD9, 0x01, 0x6C, 0xFC, 0x4F, 0x06, 0xC3,
- 0xF4, 0xA9, 0x1A, 0x49, 0x41, 0x2C, 0xF5, 0x15, 0x04, 0x76, 0xFE,
- 0x6E, 0x00, 0xFC, 0xFF, 0xF0, 0xFF, 0x05, 0x00, 0xFD, 0xFF, 0x2B,
- 0x00, 0x5A, 0xFF, 0xAC, 0x01, 0x6E, 0xFC, 0x0A, 0x07, 0x7E, 0xF1,
- 0xFF, 0x2F, 0x8A, 0x30, 0x7D, 0xF1, 0x03, 0x07, 0x75, 0xFC, 0xA7,
- 0x01, 0x5D, 0xFF, 0x2A, 0x00, 0xFD, 0xFF, 0x05, 0x00, 0xF2, 0xFF,
- 0xF7, 0xFF, 0x7A, 0x00, 0x62, 0xFE, 0x35, 0x04, 0xF7, 0xF4, 0xEF,
- 0x40, 0x40, 0x1B, 0x9C, 0xF4, 0x5E, 0x06, 0x66, 0xFC, 0xDB, 0x01,
- 0x38, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x1A, 0x00, 0x96, 0xFF, 0xE3,
- 0x00, 0x95, 0xFE, 0xD5, 0x01, 0x26, 0xFE, 0x98, 0x00, 0xBF, 0x48,
- 0x00, 0x07, 0x61, 0xFB, 0x46, 0x03, 0xD6, 0xFD, 0x3D, 0x01, 0x73,
- 0xFF, 0x23, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x00, 0x46, 0xFF,
- 0xB2, 0x01, 0xD1, 0xFC, 0x62, 0x05, 0xF6, 0xF6, 0x20, 0x13, 0x2E,
- 0x45, 0x70, 0xF8, 0x34, 0x02, 0x94, 0xFF, 0xCD, 0xFF, 0x4C, 0x00,
- 0xD2, 0xFF, 0x0B, 0x00, 0xFD, 0xFF, 0x33, 0x00, 0x41, 0xFF, 0xDA,
- 0x01, 0x36, 0xFC, 0x27, 0x07, 0x05, 0xF2, 0xAA, 0x28, 0x44, 0x37,
- 0xE4, 0xF1, 0x67, 0x06, 0xF2, 0xFC, 0x55, 0x01, 0x88, 0xFF, 0x1B,
- 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x0B, 0x00, 0xB2, 0xFF, 0x02, 0x01,
- 0x7A, 0xFD, 0xA2, 0x05, 0xD4, 0xF2, 0xC7, 0x3B, 0xF2, 0x22, 0xE7,
- 0xF2, 0xF5, 0x06, 0x35, 0xFC, 0xE6, 0x01, 0x38, 0xFF, 0x36, 0x00,
- 0xFD, 0xFF, 0x11, 0x00, 0xB9, 0xFF, 0x8C, 0x00, 0x4A, 0xFF, 0x83,
- 0x00, 0x91, 0x00, 0x91, 0xFB, 0x3D, 0x47, 0xB7, 0x0D, 0xCD, 0xF8,
- 0x89, 0x04, 0x36, 0xFD, 0x86, 0x01, 0x57, 0xFF, 0x2B, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x2A, 0x00, 0x5D, 0xFF, 0x75, 0x01, 0x5C, 0xFD,
- 0x3C, 0x04, 0x70, 0xF9, 0xFA, 0x0B, 0xC0, 0x47, 0xBC, 0xFC, 0xFC,
- 0xFF, 0xD6, 0x00, 0x1D, 0xFF, 0xA2, 0x00, 0xB0, 0xFF, 0x13, 0x00,
- 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3C, 0xFC, 0xD8,
- 0x06, 0x47, 0xF3, 0x06, 0x21, 0x2A, 0x3D, 0x44, 0xF3, 0x52, 0x05,
- 0xAE, 0xFD, 0xE3, 0x00, 0xC2, 0xFF, 0x06, 0x00, 0x01, 0x00, 0xFE,
- 0xFF, 0x1F, 0x00, 0x7C, 0xFF, 0x6D, 0x01, 0xCD, 0xFC, 0x99, 0x06,
- 0xB4, 0xF1, 0xA6, 0x35, 0x89, 0x2A, 0xD0, 0xF1, 0x2B, 0x07, 0x3E,
- 0xFC, 0xD1, 0x01, 0x46, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x0A, 0x00,
- 0xD9, 0xFF, 0x37, 0x00, 0xF7, 0xFF, 0x49, 0xFF, 0xB6, 0x02, 0x86,
- 0xF7, 0x53, 0x44, 0xFB, 0x14, 0x61, 0xF6, 0xA4, 0x05, 0xB4, 0xFC,
- 0xBE, 0x01, 0x42, 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x21,
- 0x00, 0x7B, 0xFF, 0x29, 0x01, 0x01, 0xFE, 0xF1, 0x02, 0x07, 0xFC,
- 0x6E, 0x05, 0xE6, 0x48, 0xFF, 0x01, 0x84, 0xFD, 0x2C, 0x02, 0x68,
- 0xFE, 0xF9, 0x00, 0x8E, 0xFF, 0x1C, 0x00, 0xFE, 0xFF, 0x35, 0x00,
- 0x3A, 0xFF, 0xD4, 0x01, 0x7A, 0xFC, 0x2B, 0x06, 0x1E, 0xF5, 0x56,
- 0x19, 0x0C, 0x42, 0xAA, 0xF5, 0xC9, 0x03, 0xA4, 0xFE, 0x54, 0x00,
- 0x09, 0x00, 0xEB, 0xFF, 0x06, 0x00, 0xFD, 0xFF, 0x2D, 0x00, 0x55,
- 0xFF, 0xB6, 0x01, 0x5F, 0xFC, 0x17, 0x07, 0x87, 0xF1, 0xC2, 0x2E,
- 0xC0, 0x31, 0x7E, 0xF1, 0xF1, 0x06, 0x86, 0xFC, 0x9B, 0x01, 0x63,
- 0xFF, 0x28, 0x00, 0xFD, 0xFF, 0x04, 0x00, 0xF7, 0xFF, 0xEA, 0xFF,
- 0x93, 0x00, 0x36, 0xFE, 0x7D, 0x04, 0x85, 0xF4, 0x1F, 0x40, 0x94,
- 0x1C, 0x47, 0xF4, 0x7E, 0x06, 0x5A, 0xFC, 0xDF, 0x01, 0x37, 0xFF,
- 0x36, 0x00, 0xFE, 0xFF, 0x18, 0x00, 0x9C, 0xFF, 0xD4, 0x00, 0xB4,
- 0xFE, 0x9A, 0x01, 0x95, 0xFE, 0xA8, 0xFF, 0x98, 0x48, 0x1D, 0x08,
- 0xEE, 0xFA, 0x80, 0x03, 0xB9, 0xFD, 0x4B, 0x01, 0x6E, 0xFF, 0x25,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0x00, 0x4A, 0xFF, 0xA9, 0x01,
- 0xE7, 0xFC, 0x33, 0x05, 0x60, 0xF7, 0xDA, 0x11, 0xB8, 0x45, 0x1C,
- 0xF9, 0xD8, 0x01, 0xCA, 0xFF, 0xAF, 0xFF, 0x5A, 0x00, 0xCC, 0xFF,
- 0x0D, 0x00, 0xFD, 0xFF, 0x34, 0x00, 0x3E, 0xFF, 0xDE, 0x01, 0x33,
- 0xFC, 0x21, 0x07, 0x30, 0xF2, 0x5C, 0x27, 0x5B, 0x38, 0x0F, 0xF2,
- 0x40, 0x06, 0x0E, 0xFD, 0x43, 0x01, 0x91, 0xFF, 0x18, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x0F, 0x00, 0xA8, 0xFF, 0x17, 0x01, 0x57, 0xFD,
- 0xD6, 0x05, 0x90, 0xF2, 0xC8, 0x3A, 0x46, 0x24, 0xAA, 0xF2, 0x06,
- 0x07, 0x32, 0xFC, 0xE5, 0x01, 0x39, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0x10, 0x00, 0xBE, 0xFF, 0x7D, 0x00, 0x69, 0xFF, 0x4B, 0x00, 0xF6,
- 0x00, 0xCB, 0xFA, 0xD3, 0x46, 0xF0, 0x0E, 0x5E, 0xF8, 0xBE, 0x04,
- 0x1E, 0xFD, 0x91, 0x01, 0x52, 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x28, 0x00, 0x62, 0xFF, 0x69, 0x01, 0x77, 0xFD, 0x04, 0x04,
- 0xE2, 0xF9, 0xCB, 0x0A, 0x0D, 0x48, 0x94, 0xFD, 0x92, 0xFF, 0x10,
- 0x01, 0xFE, 0xFE, 0xB1, 0x00, 0xAA, 0xFF, 0x15, 0x00, 0xFD, 0xFF,
- 0x36, 0x00, 0x36, 0xFF, 0xE5, 0x01, 0x43, 0xFC, 0xC0, 0x06, 0x8F,
- 0xF3, 0xB1, 0x1F, 0x18, 0x3E, 0x9B, 0xF3, 0x16, 0x05, 0xD5, 0xFD,
- 0xCC, 0x00, 0xCE, 0xFF, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x22,
- 0x00, 0x74, 0xFF, 0x7C, 0x01, 0xB5, 0xFC, 0xB8, 0x06, 0x9C, 0xF1,
- 0x81, 0x34, 0xD1, 0x2B, 0xB3, 0xF1, 0x29, 0x07, 0x46, 0xFC, 0xCA,
- 0x01, 0x4A, 0xFF, 0x30, 0x00, 0xFD, 0xFF, 0x09, 0x00, 0xDF, 0xFF,
- 0x29, 0x00, 0x14, 0x00, 0x16, 0xFF, 0x0C, 0x03, 0xEE, 0xF6, 0xB0,
- 0x43, 0x47, 0x16, 0xFC, 0xF5, 0xCF, 0x05, 0xA1, 0xFC, 0xC6, 0x01,
- 0x3F, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x81,
- 0xFF, 0x1B, 0x01, 0x20, 0xFE, 0xB6, 0x02, 0x7A, 0xFC, 0x5F, 0x04,
- 0xF4, 0x48, 0xFF, 0x02, 0x13, 0xFD, 0x67, 0x02, 0x49, 0xFE, 0x07,
- 0x01, 0x88, 0xFF, 0x1D, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3C, 0xFF,
- 0xCF, 0x01, 0x8A, 0xFC, 0x05, 0x06, 0x7B, 0xF5, 0x06, 0x18, 0xC7,
- 0x42, 0x2F, 0xF6, 0x7A, 0x03, 0xD4, 0xFE, 0x39, 0x00, 0x17, 0x00,
- 0xE6, 0xFF, 0x07, 0x00, 0xFD, 0xFF, 0x2E, 0x00, 0x50, 0xFF, 0xC0,
- 0x01, 0x53, 0xFC, 0x21, 0x07, 0x96, 0xF1, 0x82, 0x2D, 0xF2, 0x32,
- 0x86, 0xF1, 0xDB, 0x06, 0x99, 0xFC, 0x8E, 0x01, 0x6A, 0xFF, 0x25,
- 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFB, 0xFF, 0xDE, 0xFF, 0xAC, 0x00,
- 0x0B, 0xFE, 0xC1, 0x04, 0x1B, 0xF4, 0x47, 0x3F, 0xEA, 0x1D, 0xF5,
- 0xF3, 0x9C, 0x06, 0x4F, 0xFC, 0xE2, 0x01, 0x36, 0xFF, 0x36, 0x00,
- 0xFE, 0xFF, 0x16, 0x00, 0xA2, 0xFF, 0xC5, 0x00, 0xD4, 0xFE, 0x5F,
- 0x01, 0x03, 0xFF, 0xBF, 0xFE, 0x63, 0x48, 0x40, 0x09, 0x7B, 0xFA,
- 0xB9, 0x03, 0x9D, 0xFD, 0x58, 0x01, 0x69, 0xFF, 0x26, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x2E, 0x00, 0x4D, 0xFF, 0x9F, 0x01, 0xFE, 0xFC,
- 0x02, 0x05, 0xCB, 0xF7, 0x98, 0x10, 0x39, 0x46, 0xD0, 0xF9, 0x78,
- 0x01, 0x00, 0x00, 0x91, 0xFF, 0x69, 0x00, 0xC6, 0xFF, 0x0E, 0x00,
- 0xFD, 0xFF, 0x35, 0x00, 0x3B, 0xFF, 0xE2, 0x01, 0x31, 0xFC, 0x17,
- 0x07, 0x61, 0xF2, 0x0A, 0x26, 0x6A, 0x39, 0x41, 0xF2, 0x15, 0x06,
- 0x2C, 0xFD, 0x31, 0x01, 0x9B, 0xFF, 0x14, 0x00, 0xFF, 0xFF, 0xFF,
- 0xFF, 0x13, 0x00, 0x9E, 0xFF, 0x2B, 0x01, 0x37, 0xFD, 0x05, 0x06,
- 0x54, 0xF2, 0xC2, 0x39, 0x99, 0x25, 0x73, 0xF2, 0x14, 0x07, 0x31,
- 0xFC, 0xE3, 0x01, 0x3B, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x0E, 0x00,
- 0xC4, 0xFF, 0x6E, 0x00, 0x87, 0xFF, 0x13, 0x00, 0x58, 0x01, 0x0D,
- 0xFA, 0x61, 0x46, 0x2D, 0x10, 0xF0, 0xF7, 0xF1, 0x04, 0x05, 0xFD,
- 0x9C, 0x01, 0x4E, 0xFF, 0x2E, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x27,
- 0x00, 0x67, 0xFF, 0x5C, 0x01, 0x93, 0xFD, 0xCC, 0x03, 0x54, 0xFA,
- 0xA2, 0x09, 0x4F, 0x48, 0x73, 0xFE, 0x27, 0xFF, 0x4B, 0x01, 0xDE,
- 0xFE, 0xC0, 0x00, 0xA4, 0xFF, 0x16, 0x00, 0xFE, 0xFF, 0x36, 0x00,
- 0x36, 0xFF, 0xE3, 0x01, 0x4C, 0xFC, 0xA6, 0x06, 0xDB, 0xF3, 0x5B,
- 0x1E, 0xFC, 0x3E, 0xFA, 0xF3, 0xD7, 0x04, 0xFD, 0xFD, 0xB4, 0x00,
- 0xD9, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0x25, 0x00, 0x6D,
- 0xFF, 0x8A, 0x01, 0x9F, 0xFC, 0xD3, 0x06, 0x8A, 0xF1, 0x57, 0x33,
- 0x17, 0x2D, 0x9C, 0xF1, 0x24, 0x07, 0x4F, 0xFC, 0xC3, 0x01, 0x4E,
- 0xFF, 0x2F, 0x00, 0xFD, 0xFF, 0x08, 0x00, 0xE4, 0xFF, 0x1B, 0x00,
- 0x30, 0x00, 0xE4, 0xFE, 0x5F, 0x03, 0x5E, 0xF6, 0x02, 0x43, 0x96,
- 0x17, 0x9B, 0xF5, 0xF8, 0x05, 0x8F, 0xFC, 0xCC, 0x01, 0x3D, 0xFF,
- 0x34, 0x00, 0xFE, 0xFF, 0x1E, 0x00, 0x86, 0xFF, 0x0C, 0x01, 0x3E,
- 0xFE, 0x7B, 0x02, 0xED, 0xFC, 0x56, 0x03, 0xF5, 0x48, 0x06, 0x04,
- 0xA1, 0xFC, 0xA3, 0x02, 0x2A, 0xFE, 0x16, 0x01, 0x83, 0xFF, 0x1F,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x3E, 0xFF, 0xC8, 0x01,
- 0x9B, 0xFC, 0xDD, 0x05, 0xDC, 0xF5, 0xB6, 0x16, 0x77, 0x43, 0xBD,
- 0xF6, 0x28, 0x03, 0x05, 0xFF, 0x1D, 0x00, 0x25, 0x00, 0xE1, 0xFF,
- 0x08, 0x00, 0xFD, 0xFF, 0x30, 0x00, 0x4B, 0xFF, 0xC8, 0x01, 0x49,
- 0xFC, 0x27, 0x07, 0xAB, 0xF1, 0x3E, 0x2C, 0x1E, 0x34, 0x95, 0xF1,
- 0xC1, 0x06, 0xAE, 0xFC, 0x81, 0x01, 0x71, 0xFF, 0x23, 0x00, 0xFE,
- 0xFF, 0x02, 0x00, 0x00, 0x00, 0xD2, 0xFF, 0xC4, 0x00, 0xE2, 0xFD,
- 0x01, 0x05, 0xBA, 0xF3, 0x64, 0x3E, 0x3F, 0x1F, 0xA8, 0xF3, 0xB8,
- 0x06, 0x46, 0xFC, 0xE5, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0x15, 0x00, 0xA8, 0xFF, 0xB6, 0x00, 0xF3, 0xFE, 0x24, 0x01, 0x6E,
- 0xFF, 0xDE, 0xFD, 0x25, 0x48, 0x68, 0x0A, 0x08, 0xFA, 0xF2, 0x03,
- 0x81, 0xFD, 0x65, 0x01, 0x64, 0xFF, 0x28, 0x00, 0x00, 0x00, 0xFF,
- 0xFF, 0x2D, 0x00, 0x51, 0xFF, 0x95, 0x01, 0x15, 0xFD, 0xCF, 0x04,
- 0x39, 0xF8, 0x59, 0x0F, 0xAF, 0x46, 0x8B, 0xFA, 0x17, 0x01, 0x38,
- 0x00, 0x73, 0xFF, 0x78, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0xFD, 0xFF,
- 0x36, 0x00, 0x39, 0xFF, 0xE4, 0x01, 0x32, 0xFC, 0x0B, 0x07, 0x97,
- 0xF2, 0xB8, 0x24, 0x71, 0x3A, 0x7B, 0xF2, 0xE6, 0x05, 0x4C, 0xFD,
- 0x1D, 0x01, 0xA4, 0xFF, 0x11, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x16,
- 0x00, 0x94, 0xFF, 0x3D, 0x01, 0x18, 0xFD, 0x32, 0x06, 0x1F, 0xF2,
- 0xB5, 0x38, 0xEB, 0x26, 0x40, 0xF2, 0x1E, 0x07, 0x32, 0xFC, 0xDF,
- 0x01, 0x3D, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x0D, 0x00, 0xCA, 0xFF,
- 0x5F, 0x00, 0xA5, 0xFF, 0xDC, 0xFF, 0xB8, 0x01, 0x57, 0xF9, 0xE5,
- 0x45, 0x6E, 0x11, 0x83, 0xF7, 0x23, 0x05, 0xEE, 0xFC, 0xA6, 0x01,
- 0x4B, 0xFF, 0x2F, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x25, 0x00, 0x6C,
- 0xFF, 0x4F, 0x01, 0xB0, 0xFD, 0x93, 0x03, 0xC7, 0xFA, 0x7D, 0x08,
- 0x86, 0x48, 0x5A, 0xFF, 0xBA, 0xFE, 0x86, 0x01, 0xBF, 0xFE, 0xCF,
- 0x00, 0x9E, 0xFF, 0x17, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF,
- 0xE0, 0x01, 0x56, 0xFC, 0x89, 0x06, 0x2B, 0xF4, 0x06, 0x1D, 0xD7,
- 0x3F, 0x61, 0xF4, 0x94, 0x04, 0x27, 0xFE, 0x9C, 0x00, 0xE6, 0xFF,
- 0xF8, 0xFF, 0x04, 0x00, 0xFD, 0xFF, 0x27, 0x00, 0x66, 0xFF, 0x97,
- 0x01, 0x8C, 0xFC, 0xEA, 0x06, 0x80, 0xF1, 0x26, 0x32, 0x58, 0x2E,
- 0x8B, 0xF1, 0x1B, 0x07, 0x5B, 0xFC, 0xBA, 0x01, 0x53, 0xFF, 0x2D,
- 0x00, 0xFD, 0xFF, 0x07, 0x00, 0xE9, 0xFF, 0x0E, 0x00, 0x4B, 0x00,
- 0xB4, 0xFE, 0xAF, 0x03, 0xD5, 0xF5, 0x4D, 0x42, 0xE6, 0x18, 0x3C,
- 0xF5, 0x1F, 0x06, 0x7F, 0xFC, 0xD3, 0x01, 0x3B, 0xFF, 0x35, 0x00,
- 0xFE, 0xFF, 0x1C, 0x00, 0x8C, 0xFF, 0xFE, 0x00, 0x5D, 0xFE, 0x3F,
- 0x02, 0x5E, 0xFD, 0x54, 0x02, 0xEC, 0x48, 0x13, 0x05, 0x2E, 0xFC,
- 0xDE, 0x02, 0x0C, 0xFE, 0x24, 0x01, 0x7D, 0xFF, 0x20, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x32, 0x00, 0x41, 0xFF, 0xC1, 0x01, 0xAD, 0xFC,
- 0xB2, 0x05, 0x3F, 0xF6, 0x69, 0x15, 0x1F, 0x44, 0x53, 0xF7, 0xD3,
- 0x02, 0x38, 0xFF, 0x01, 0x00, 0x33, 0x00, 0xDB, 0xFF, 0x09, 0x00,
- 0xFD, 0xFF, 0x31, 0x00, 0x47, 0xFF, 0xCF, 0x01, 0x40, 0xFC, 0x2A,
- 0x07, 0xC6, 0xF1, 0xF7, 0x2A, 0x46, 0x35, 0xAB, 0xF1, 0xA4, 0x06,
- 0xC4, 0xFC, 0x72, 0x01, 0x79, 0xFF, 0x20, 0x00, 0xFE, 0xFF, 0x02,
- 0x00, 0x04, 0x00, 0xC6, 0xFF, 0xDB, 0x00, 0xBB, 0xFD, 0x3E, 0x05,
- 0x60, 0xF3, 0x7B, 0x3D, 0x94, 0x20, 0x5E, 0xF3, 0xD0, 0x06, 0x3E,
- 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x14, 0x00,
- 0xAE, 0xFF, 0xA7, 0x00, 0x12, 0xFF, 0xEA, 0x00, 0xD9, 0xFF, 0x03,
- 0xFD, 0xDC, 0x47, 0x95, 0x0B, 0x96, 0xF9, 0x29, 0x04, 0x65, 0xFD,
- 0x71, 0x01, 0x5F, 0xFF, 0x29, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2C,
- 0x00, 0x55, 0xFF, 0x8A, 0x01, 0x2E, 0xFD, 0x9B, 0x04, 0xA8, 0xF8,
- 0x1F, 0x0E, 0x1A, 0x47, 0x4E, 0xFB, 0xB3, 0x00, 0x70, 0x00, 0x54,
- 0xFF, 0x87, 0x00, 0xBB, 0xFF, 0x11, 0x00, 0xFD, 0xFF, 0x36, 0x00,
- 0x38, 0xFF, 0xE6, 0x01, 0x34, 0xFC, 0xFB, 0x06, 0xD2, 0xF2, 0x64,
- 0x23, 0x73, 0x3B, 0xBC, 0xF2, 0xB4, 0x05, 0x6E, 0xFD, 0x09, 0x01,
- 0xAF, 0xFF, 0x0D, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1A, 0x00, 0x8B,
- 0xFF, 0x4F, 0x01, 0xFB, 0xFC, 0x5A, 0x06, 0xF2, 0xF1, 0xA0, 0x37,
- 0x3A, 0x28, 0x13, 0xF2, 0x25, 0x07, 0x35, 0xFC, 0xDB, 0x01, 0x40,
- 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x0C, 0x00, 0xD0, 0xFF, 0x51, 0x00,
- 0xC3, 0xFF, 0xA6, 0xFF, 0x16, 0x02, 0xA9, 0xF8, 0x5C, 0x45, 0xB2,
- 0x12, 0x19, 0xF7, 0x52, 0x05, 0xD8, 0xFC, 0xAF, 0x01, 0x47, 0xFF,
- 0x30, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x24, 0x00, 0x71, 0xFF, 0x42,
- 0x01, 0xCD, 0xFD, 0x59, 0x03, 0x3B, 0xFB, 0x5E, 0x07, 0xB3, 0x48,
- 0x48, 0x00, 0x4B, 0xFE, 0xC2, 0x01, 0x9F, 0xFE, 0xDE, 0x00, 0x98,
- 0xFF, 0x19, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xDD, 0x01,
- 0x62, 0xFC, 0x69, 0x06, 0x7F, 0xF4, 0xB2, 0x1B, 0xAB, 0x40, 0xD0,
- 0xF4, 0x4E, 0x04, 0x53, 0xFE, 0x83, 0x00, 0xF2, 0xFF, 0xF4, 0xFF,
- 0x05, 0x00, 0xFD, 0xFF, 0x29, 0x00, 0x5F, 0xFF, 0xA3, 0x01, 0x7A,
- 0xFC, 0xFD, 0x06, 0x7C, 0xF1, 0xF2, 0x30, 0x96, 0x2F, 0x80, 0xF1,
- 0x0F, 0x07, 0x69, 0xFC, 0xB0, 0x01, 0x59, 0xFF, 0x2B, 0x00, 0xFD,
- 0xFF, 0x06, 0x00, 0xEE, 0xFF, 0x01, 0x00, 0x66, 0x00, 0x85, 0xFE,
- 0xFC, 0x03, 0x55, 0xF5, 0x8C, 0x41, 0x38, 0x1A, 0xE1, 0xF4, 0x43,
- 0x06, 0x70, 0xFC, 0xD8, 0x01, 0x39, 0xFF, 0x35, 0x00, 0xFE, 0xFF,
- 0x1B, 0x00, 0x92, 0xFF, 0xEF, 0x00, 0x7D, 0xFE, 0x04, 0x02, 0xCF,
- 0xFD, 0x58, 0x01, 0xD7, 0x48, 0x26, 0x06, 0xBB, 0xFB, 0x19, 0x03,
- 0xED, 0xFD, 0x32, 0x01, 0x77, 0xFF, 0x22, 0x00, 0x00, 0x00, 0xFF,
- 0xFF, 0x32, 0x00, 0x44, 0xFF, 0xB9, 0x01, 0xC1, 0xFC, 0x86, 0x05,
- 0xA5, 0xF6, 0x1E, 0x14, 0xBA, 0x44, 0xF0, 0xF7, 0x7B, 0x02, 0x6B,
- 0xFF, 0xE4, 0xFF, 0x41, 0x00, 0xD6, 0xFF, 0x0B, 0x00, 0xFD, 0xFF,
- 0x33, 0x00, 0x43, 0xFF, 0xD5, 0x01, 0x3A, 0xFC, 0x2A, 0x07, 0xE7,
- 0xF1, 0xAC, 0x29, 0x66, 0x36, 0xC9, 0xF1, 0x83, 0x06, 0xDD, 0xFC,
- 0x62, 0x01, 0x81, 0xFF, 0x1D, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x08,
- 0x00, 0xBB, 0xFF, 0xF1, 0x00, 0x96, 0xFD, 0x78, 0x05, 0x0E, 0xF3,
- 0x8A, 0x3C, 0xEA, 0x21, 0x19, 0xF3, 0xE6, 0x06, 0x38, 0xFC, 0xE6,
- 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x12, 0x00, 0xB4, 0xFF,
- 0x98, 0x00, 0x32, 0xFF, 0xB0, 0x00, 0x41, 0x00, 0x30, 0xFC, 0x86,
- 0x47, 0xC6, 0x0C, 0x24, 0xF9, 0x60, 0x04, 0x4B, 0xFD, 0x7D, 0x01,
- 0x5A, 0xFF, 0x2A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x5A,
- 0xFF, 0x7E, 0x01, 0x48, 0xFD, 0x66, 0x04, 0x18, 0xF9, 0xE8, 0x0C,
- 0x7C, 0x47, 0x19, 0xFC, 0x4D, 0x00, 0xA9, 0x00, 0x35, 0xFF, 0x96,
- 0x00, 0xB5, 0xFF, 0x12, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF,
- 0xE6, 0x01, 0x38, 0xFC, 0xE9, 0x06, 0x12, 0xF3, 0x10, 0x22, 0x6E,
- 0x3C, 0x05, 0xF3, 0x7E, 0x05, 0x91, 0xFD, 0xF4, 0x00, 0xBA, 0xFF,
- 0x09, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x1D, 0x00, 0x82, 0xFF, 0x60,
- 0x01, 0xE0, 0xFC, 0x7F, 0x06, 0xCC, 0xF1, 0x85, 0x36, 0x87, 0x29,
- 0xEB, 0xF1, 0x2A, 0x07, 0x39, 0xFC, 0xD6, 0x01, 0x43, 0xFF, 0x33,
- 0x00, 0xFD, 0xFF, 0x0B, 0x00, 0xD5, 0xFF, 0x42, 0x00, 0xE1, 0xFF,
- 0x71, 0xFF, 0x71, 0x02, 0x02, 0xF8, 0xCC, 0x44, 0xFA, 0x13, 0xB0,
- 0xF6, 0x81, 0x05, 0xC3, 0xFC, 0xB8, 0x01, 0x44, 0xFF, 0x31, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0x22, 0x00, 0x77, 0xFF, 0x34, 0x01, 0xEA,
- 0xFD, 0x1F, 0x03, 0xAE, 0xFB, 0x45, 0x06, 0xD5, 0x48, 0x3C, 0x01,
- 0xDC, 0xFD, 0xFD, 0x01, 0x80, 0xFE, 0xED, 0x00, 0x93, 0xFF, 0x1B,
- 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x39, 0xFF, 0xD8, 0x01, 0x6F, 0xFC,
- 0x47, 0x06, 0xD7, 0xF4, 0x5D, 0x1A, 0x74, 0x41, 0x48, 0xF5, 0x04,
- 0x04, 0x80, 0xFE, 0x69, 0x00, 0xFF, 0xFF, 0xEF, 0xFF, 0x05, 0x00,
- 0xFD, 0xFF, 0x2B, 0x00, 0x59, 0xFF, 0xAE, 0x01, 0x6A, 0xFC, 0x0D,
- 0x07, 0x80, 0xF1, 0xB8, 0x2F, 0xCF, 0x30, 0x7D, 0xF1, 0xFF, 0x06,
- 0x78, 0xFC, 0xA5, 0x01, 0x5F, 0xFF, 0x29, 0x00, 0xFD, 0xFF, 0x05,
- 0x00, 0xF3, 0xFF, 0xF4, 0xFF, 0x80, 0x00, 0x58, 0xFE, 0x46, 0x04,
- 0xDD, 0xF4, 0xC3, 0x40, 0x8C, 0x1B, 0x89, 0xF4, 0x66, 0x06, 0x63,
- 0xFC, 0xDC, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x19, 0x00,
- 0x98, 0xFF, 0xE0, 0x00, 0x9C, 0xFE, 0xC8, 0x01, 0x3F, 0xFE, 0x62,
- 0x00, 0xB8, 0x48, 0x3F, 0x07, 0x47, 0xFB, 0x53, 0x03, 0xD0, 0xFD,
- 0x40, 0x01, 0x72, 0xFF, 0x23, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30,
- 0x00, 0x47, 0xFF, 0xB0, 0x01, 0xD6, 0xFC, 0x58, 0x05, 0x0D, 0xF7,
- 0xD7, 0x12, 0x4E, 0x45, 0x96, 0xF8, 0x20, 0x02, 0xA0, 0xFF, 0xC7,
- 0xFF, 0x4F, 0x00, 0xD0, 0xFF, 0x0C, 0x00, 0xFD, 0xFF, 0x34, 0x00,
- 0x40, 0xFF, 0xDB, 0x01, 0x35, 0xFC, 0x26, 0x07, 0x0E, 0xF2, 0x60,
- 0x28, 0x82, 0x37, 0xED, 0xF1, 0x5E, 0x06, 0xF8, 0xFC, 0x51, 0x01,
- 0x8A, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00, 0xB0,
- 0xFF, 0x07, 0x01, 0x72, 0xFD, 0xAE, 0x05, 0xC4, 0xF2, 0x90, 0x3B,
- 0x3F, 0x23, 0xD9, 0xF2, 0xF9, 0x06, 0x34, 0xFC, 0xE6, 0x01, 0x38,
- 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x11, 0x00, 0xBA, 0xFF, 0x89, 0x00,
- 0x51, 0xFF, 0x77, 0x00, 0xA7, 0x00, 0x64, 0xFB, 0x26, 0x47, 0xFC,
- 0x0D, 0xB4, 0xF8, 0x95, 0x04, 0x31, 0xFD, 0x88, 0x01, 0x56, 0xFF,
- 0x2C, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x29, 0x00, 0x5E, 0xFF, 0x72,
- 0x01, 0x62, 0xFD, 0x2F, 0x04, 0x89, 0xF9, 0xB6, 0x0B, 0xD2, 0x47,
- 0xEB, 0xFC, 0xE4, 0xFF, 0xE3, 0x00, 0x16, 0xFF, 0xA5, 0x00, 0xAF,
- 0xFF, 0x13, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01,
- 0x3E, 0xFC, 0xD3, 0x06, 0x56, 0xF3, 0xBA, 0x20, 0x61, 0x3D, 0x56,
- 0xF3, 0x45, 0x05, 0xB7, 0xFD, 0xDE, 0x00, 0xC5, 0xFF, 0x05, 0x00,
- 0x02, 0x00, 0xFE, 0xFF, 0x20, 0x00, 0x7A, 0xFF, 0x70, 0x01, 0xC7,
- 0xFC, 0xA0, 0x06, 0xAE, 0xF1, 0x65, 0x35, 0xD1, 0x2A, 0xCA, 0xF1,
- 0x2A, 0x07, 0x40, 0xFC, 0xD0, 0x01, 0x47, 0xFF, 0x32, 0x00, 0xFD,
- 0xFF, 0x09, 0x00, 0xDB, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0x3D, 0xFF,
- 0xC9, 0x02, 0x64, 0xF7, 0x2F, 0x44, 0x44, 0x15, 0x4A, 0xF6, 0xAD,
- 0x05, 0xAF, 0xFC, 0xC0, 0x01, 0x41, 0xFF, 0x32, 0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x21, 0x00, 0x7C, 0xFF, 0x26, 0x01, 0x08, 0xFE, 0xE4,
- 0x02, 0x21, 0xFC, 0x31, 0x05, 0xEB, 0x48, 0x37, 0x02, 0x6B, 0xFD,
- 0x39, 0x02, 0x61, 0xFE, 0xFC, 0x00, 0x8D, 0xFF, 0x1C, 0x00, 0xFE,
- 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xD3, 0x01, 0x7D, 0xFC, 0x23, 0x06,
- 0x32, 0xF5, 0x0C, 0x19, 0x38, 0x42, 0xC7, 0xF5, 0xB8, 0x03, 0xAF,
- 0xFE, 0x4E, 0x00, 0x0C, 0x00, 0xEA, 0xFF, 0x06, 0x00, 0xFD, 0xFF,
- 0x2D, 0x00, 0x54, 0xFF, 0xB8, 0x01, 0x5D, 0xFC, 0x1A, 0x07, 0x8A,
- 0xF1, 0x7B, 0x2E, 0x04, 0x32, 0x7F, 0xF1, 0xEC, 0x06, 0x8A, 0xFC,
- 0x98, 0x01, 0x65, 0xFF, 0x27, 0x00, 0xFD, 0xFF, 0x04, 0x00, 0xF8,
- 0xFF, 0xE7, 0xFF, 0x99, 0x00, 0x2C, 0xFE, 0x8C, 0x04, 0x6D, 0xF4,
- 0xF0, 0x3F, 0xE0, 0x1C, 0x34, 0xF4, 0x85, 0x06, 0x57, 0xFC, 0xE0,
- 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x18, 0x00, 0x9E, 0xFF,
- 0xD1, 0x00, 0xBB, 0xFE, 0x8D, 0x01, 0xAE, 0xFE, 0x74, 0xFF, 0x8D,
- 0x48, 0x5D, 0x08, 0xD4, 0xFA, 0x8D, 0x03, 0xB3, 0xFD, 0x4E, 0x01,
- 0x6D, 0xFF, 0x25, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2F, 0x00, 0x4A,
- 0xFF, 0xA7, 0x01, 0xEC, 0xFC, 0x28, 0x05, 0x77, 0xF7, 0x92, 0x11,
- 0xD7, 0x45, 0x43, 0xF9, 0xC3, 0x01, 0xD6, 0xFF, 0xA9, 0xFF, 0x5E,
- 0x00, 0xCB, 0xFF, 0x0D, 0x00, 0xFD, 0xFF, 0x34, 0x00, 0x3D, 0xFF,
- 0xDF, 0x01, 0x32, 0xFC, 0x1F, 0x07, 0x3B, 0xF2, 0x11, 0x27, 0x97,
- 0x38, 0x19, 0xF2, 0x36, 0x06, 0x15, 0xFD, 0x3F, 0x01, 0x93, 0xFF,
- 0x17, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x10, 0x00, 0xA6, 0xFF, 0x1B,
- 0x01, 0x50, 0xFD, 0xE1, 0x05, 0x82, 0xF2, 0x8F, 0x3A, 0x92, 0x24,
- 0x9D, 0xF2, 0x09, 0x07, 0x32, 0xFC, 0xE4, 0x01, 0x39, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0x0F, 0x00, 0xC0, 0xFF, 0x7A, 0x00, 0x70, 0xFF,
- 0x3E, 0x00, 0x0C, 0x01, 0xA1, 0xFA, 0xBB, 0x46, 0x36, 0x0F, 0x45,
- 0xF8, 0xC9, 0x04, 0x18, 0xFD, 0x93, 0x01, 0x52, 0xFF, 0x2D, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0x28, 0x00, 0x63, 0xFF, 0x66, 0x01, 0x7D,
- 0xFD, 0xF8, 0x03, 0xFB, 0xF9, 0x89, 0x0A, 0x1D, 0x48, 0xC5, 0xFD,
- 0x7A, 0xFF, 0x1D, 0x01, 0xF7, 0xFE, 0xB4, 0x00, 0xA9, 0xFF, 0x15,
- 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE5, 0x01, 0x45, 0xFC,
- 0xBB, 0x06, 0xA0, 0xF3, 0x64, 0x1F, 0x4A, 0x3E, 0xB0, 0xF3, 0x08,
- 0x05, 0xDE, 0xFD, 0xC7, 0x00, 0xD0, 0xFF, 0x00, 0x00, 0x02, 0x00,
- 0xFE, 0xFF, 0x23, 0x00, 0x72, 0xFF, 0x7F, 0x01, 0xB0, 0xFC, 0xBE,
- 0x06, 0x97, 0xF1, 0x3F, 0x34, 0x19, 0x2C, 0xAD, 0xF1, 0x28, 0x07,
- 0x48, 0xFC, 0xC9, 0x01, 0x4B, 0xFF, 0x30, 0x00, 0xFD, 0xFF, 0x08,
- 0x00, 0xE0, 0xFF, 0x26, 0x00, 0x1A, 0x00, 0x0B, 0xFF, 0x1E, 0x03,
- 0xCD, 0xF6, 0x89, 0x43, 0x91, 0x16, 0xE7, 0xF5, 0xD8, 0x05, 0x9D,
- 0xFC, 0xC7, 0x01, 0x3E, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x1F, 0x00, 0x82, 0xFF, 0x18, 0x01, 0x27, 0xFE, 0xA9, 0x02, 0x94,
- 0xFC, 0x24, 0x04, 0xF5, 0x48, 0x39, 0x03, 0xF9, 0xFC, 0x74, 0x02,
- 0x42, 0xFE, 0x0B, 0x01, 0x87, 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0x34,
- 0x00, 0x3C, 0xFF, 0xCD, 0x01, 0x8E, 0xFC, 0xFC, 0x05, 0x90, 0xF5,
- 0xBB, 0x17, 0xEE, 0x42, 0x4E, 0xF6, 0x68, 0x03, 0xDF, 0xFE, 0x33,
- 0x00, 0x1A, 0x00, 0xE5, 0xFF, 0x07, 0x00, 0xFD, 0xFF, 0x2F, 0x00,
- 0x4F, 0xFF, 0xC2, 0x01, 0x51, 0xFC, 0x23, 0x07, 0x9A, 0xF1, 0x3A,
- 0x2D, 0x35, 0x33, 0x89, 0xF1, 0xD5, 0x06, 0x9D, 0xFC, 0x8B, 0x01,
- 0x6C, 0xFF, 0x25, 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0xDB,
- 0xFF, 0xB2, 0x00, 0x02, 0xFE, 0xCF, 0x04, 0x05, 0xF4, 0x16, 0x3F,
- 0x36, 0x1E, 0xE4, 0xF3, 0xA3, 0x06, 0x4D, 0xFC, 0xE3, 0x01, 0x36,
- 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x16, 0x00, 0xA4, 0xFF, 0xC2, 0x00,
- 0xDB, 0xFE, 0x52, 0x01, 0x1B, 0xFF, 0x8D, 0xFE, 0x57, 0x48, 0x81,
- 0x09, 0x61, 0xFA, 0xC6, 0x03, 0x96, 0xFD, 0x5B, 0x01, 0x68, 0xFF,
- 0x26, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2E, 0x00, 0x4E, 0xFF, 0x9D,
- 0x01, 0x03, 0xFD, 0xF7, 0x04, 0xE3, 0xF7, 0x51, 0x10, 0x55, 0x46,
- 0xF9, 0xF9, 0x63, 0x01, 0x0D, 0x00, 0x8B, 0xFF, 0x6D, 0x00, 0xC5,
- 0xFF, 0x0E, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3B, 0xFF, 0xE2, 0x01,
- 0x31, 0xFC, 0x15, 0x07, 0x6D, 0xF2, 0xBF, 0x25, 0xA5, 0x39, 0x4D,
- 0xF2, 0x0B, 0x06, 0x33, 0xFD, 0x2D, 0x01, 0x9D, 0xFF, 0x13, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x14, 0x00, 0x9C, 0xFF, 0x2F, 0x01, 0x30,
- 0xFD, 0x10, 0x06, 0x47, 0xF2, 0x87, 0x39, 0xE5, 0x25, 0x67, 0xF2,
- 0x16, 0x07, 0x31, 0xFC, 0xE2, 0x01, 0x3B, 0xFF, 0x35, 0x00, 0xFD,
- 0xFF, 0x0E, 0x00, 0xC6, 0xFF, 0x6B, 0x00, 0x8E, 0xFF, 0x06, 0x00,
- 0x6E, 0x01, 0xE4, 0xF9, 0x48, 0x46, 0x75, 0x10, 0xD7, 0xF7, 0xFC,
- 0x04, 0x00, 0xFD, 0x9E, 0x01, 0x4E, 0xFF, 0x2E, 0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0x26, 0x00, 0x68, 0xFF, 0x59, 0x01, 0x99, 0xFD, 0xC0,
- 0x03, 0x6E, 0xFA, 0x61, 0x09, 0x5D, 0x48, 0xA6, 0xFE, 0x0F, 0xFF,
- 0x58, 0x01, 0xD7, 0xFE, 0xC3, 0x00, 0xA3, 0xFF, 0x16, 0x00, 0xFE,
- 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE3, 0x01, 0x4E, 0xFC, 0xA0, 0x06,
- 0xED, 0xF3, 0x0F, 0x1E, 0x2D, 0x3F, 0x10, 0xF4, 0xC8, 0x04, 0x07,
- 0xFE, 0xAF, 0x00, 0xDC, 0xFF, 0xFC, 0xFF, 0x03, 0x00, 0xFD, 0xFF,
- 0x25, 0x00, 0x6B, 0xFF, 0x8D, 0x01, 0x9B, 0xFC, 0xD8, 0x06, 0x87,
- 0xF1, 0x13, 0x33, 0x5E, 0x2D, 0x98, 0xF1, 0x22, 0x07, 0x52, 0xFC,
- 0xC1, 0x01, 0x4F, 0xFF, 0x2F, 0x00, 0xFD, 0xFF, 0x07, 0x00, 0xE5,
- 0xFF, 0x18, 0x00, 0x36, 0x00, 0xD9, 0xFE, 0x71, 0x03, 0x3F, 0xF6,
- 0xDB, 0x42, 0xE0, 0x17, 0x86, 0xF5, 0x00, 0x06, 0x8C, 0xFC, 0xCE,
- 0x01, 0x3C, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0x1D, 0x00, 0x88, 0xFF,
- 0x09, 0x01, 0x45, 0xFE, 0x6E, 0x02, 0x06, 0xFD, 0x1C, 0x03, 0xF4,
- 0x48, 0x41, 0x04, 0x87, 0xFC, 0xB0, 0x02, 0x23, 0xFE, 0x19, 0x01,
- 0x81, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x3F,
- 0xFF, 0xC6, 0x01, 0x9F, 0xFC, 0xD3, 0x05, 0xF1, 0xF5, 0x6C, 0x16,
- 0x9E, 0x43, 0xDD, 0xF6, 0x15, 0x03, 0x10, 0xFF, 0x17, 0x00, 0x28,
- 0x00, 0xDF, 0xFF, 0x09, 0x00, 0xFD, 0xFF, 0x30, 0x00, 0x4A, 0xFF,
- 0xCA, 0x01, 0x47, 0xFC, 0x28, 0x07, 0xB0, 0xF1, 0xF5, 0x2B, 0x60,
- 0x34, 0x9A, 0xF1, 0xBB, 0x06, 0xB3, 0xFC, 0x7D, 0x01, 0x73, 0xFF,
- 0x22, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x01, 0x00, 0xCF, 0xFF, 0xC9,
- 0x00, 0xDA, 0xFD, 0x0F, 0x05, 0xA5, 0xF3, 0x31, 0x3E, 0x8A, 0x1F,
- 0x97, 0xF3, 0xBD, 0x06, 0x44, 0xFC, 0xE5, 0x01, 0x36, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0x15, 0x00, 0xAA, 0xFF, 0xB3, 0x00, 0xFA, 0xFE,
- 0x17, 0x01, 0x86, 0xFF, 0xAC, 0xFD, 0x16, 0x48, 0xAA, 0x0A, 0xEE,
- 0xF9, 0xFE, 0x03, 0x7A, 0xFD, 0x67, 0x01, 0x63, 0xFF, 0x28, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x2D, 0x00, 0x52, 0xFF, 0x92, 0x01, 0x1B,
- 0xFD, 0xC4, 0x04, 0x51, 0xF8, 0x13, 0x0F, 0xC8, 0x46, 0xB6, 0xFA,
- 0x01, 0x01, 0x44, 0x00, 0x6C, 0xFF, 0x7B, 0x00, 0xBF, 0xFF, 0x10,
- 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x39, 0xFF, 0xE5, 0x01, 0x32, 0xFC,
- 0x08, 0x07, 0xA4, 0xF2, 0x6D, 0x24, 0xAD, 0x3A, 0x88, 0xF2, 0xDB,
- 0x05, 0x53, 0xFD, 0x19, 0x01, 0xA7, 0xFF, 0x10, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x17, 0x00, 0x92, 0xFF, 0x41, 0x01, 0x11, 0xFD, 0x3B,
- 0x06, 0x14, 0xF2, 0x78, 0x38, 0x36, 0x27, 0x35, 0xF2, 0x20, 0x07,
- 0x33, 0xFC, 0xDF, 0x01, 0x3E, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x0D,
- 0x00, 0xCB, 0xFF, 0x5C, 0x00, 0xAC, 0xFF, 0xD0, 0xFF, 0xCD, 0x01,
- 0x30, 0xF9, 0xC8, 0x45, 0xB6, 0x11, 0x6B, 0xF7, 0x2D, 0x05, 0xE9,
- 0xFC, 0xA8, 0x01, 0x4A, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x25, 0x00, 0x6D, 0xFF, 0x4C, 0x01, 0xB6, 0xFD, 0x86, 0x03, 0xE1,
- 0xFA, 0x3D, 0x08, 0x92, 0x48, 0x8E, 0xFF, 0xA1, 0xFE, 0x93, 0x01,
- 0xB8, 0xFE, 0xD3, 0x00, 0x9D, 0xFF, 0x18, 0x00, 0xFE, 0xFF, 0x36,
- 0x00, 0x37, 0xFF, 0xE0, 0x01, 0x58, 0xFC, 0x82, 0x06, 0x3E, 0xF4,
- 0xBA, 0x1C, 0x07, 0x40, 0x79, 0xF4, 0x84, 0x04, 0x31, 0xFE, 0x96,
- 0x00, 0xE8, 0xFF, 0xF7, 0xFF, 0x04, 0x00, 0xFD, 0xFF, 0x28, 0x00,
- 0x64, 0xFF, 0x9A, 0x01, 0x88, 0xFC, 0xEE, 0x06, 0x7E, 0xF1, 0xE3,
- 0x31, 0x9F, 0x2E, 0x88, 0xF1, 0x19, 0x07, 0x5E, 0xFC, 0xB7, 0x01,
- 0x54, 0xFF, 0x2D, 0x00, 0xFD, 0xFF, 0x06, 0x00, 0xEA, 0xFF, 0x0B,
- 0x00, 0x51, 0x00, 0xAA, 0xFE, 0xC0, 0x03, 0xB8, 0xF5, 0x21, 0x42,
- 0x31, 0x19, 0x28, 0xF5, 0x27, 0x06, 0x7C, 0xFC, 0xD4, 0x01, 0x3A,
- 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1C, 0x00, 0x8D, 0xFF, 0xFA, 0x00,
- 0x64, 0xFE, 0x32, 0x02, 0x78, 0xFD, 0x1B, 0x02, 0xEA, 0x48, 0x50,
- 0x05, 0x14, 0xFC, 0xEB, 0x02, 0x05, 0xFE, 0x27, 0x01, 0x7C, 0xFF,
- 0x21, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x32, 0x00, 0x41, 0xFF, 0xBF,
- 0x01, 0xB2, 0xFC, 0xA9, 0x05, 0x55, 0xF6, 0x20, 0x15, 0x42, 0x44,
- 0x75, 0xF7, 0xBF, 0x02, 0x43, 0xFF, 0xFA, 0xFF, 0x36, 0x00, 0xDA,
- 0xFF, 0x0A, 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x46, 0xFF, 0xD1, 0x01,
- 0x3F, 0xFC, 0x2B, 0x07, 0xCD, 0xF1, 0xAE, 0x2A, 0x86, 0x35, 0xB1,
- 0xF1, 0x9D, 0x06, 0xCA, 0xFC, 0x6E, 0x01, 0x7B, 0xFF, 0x20, 0x00,
- 0xFE, 0xFF, 0x02, 0x00, 0x05, 0x00, 0xC3, 0xFF, 0xE0, 0x00, 0xB3,
- 0xFD, 0x4B, 0x05, 0x4D, 0xF3, 0x45, 0x3D, 0xE0, 0x20, 0x4F, 0xF3,
- 0xD5, 0x06, 0x3D, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0x13, 0x00, 0xAF, 0xFF, 0xA4, 0x00, 0x19, 0xFF, 0xDD, 0x00,
- 0xF0, 0xFF, 0xD4, 0xFC, 0xC9, 0x47, 0xD8, 0x0B, 0x7C, 0xF9, 0x35,
- 0x04, 0x5F, 0xFD, 0x74, 0x01, 0x5E, 0xFF, 0x29, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x2C, 0x00, 0x56, 0xFF, 0x87, 0x01, 0x34, 0xFD, 0x8F,
- 0x04, 0xC0, 0xF8, 0xD9, 0x0D, 0x31, 0x47, 0x7B, 0xFB, 0x9C, 0x00,
- 0x7D, 0x00, 0x4D, 0xFF, 0x8A, 0x00, 0xB9, 0xFF, 0x11, 0x00, 0xFD,
- 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xE6, 0x01, 0x35, 0xFC, 0xF7, 0x06,
- 0xE0, 0xF2, 0x18, 0x23, 0xAB, 0x3B, 0xCC, 0xF2, 0xA8, 0x05, 0x76,
- 0xFD, 0x04, 0x01, 0xB1, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0xFE, 0xFF,
- 0x1A, 0x00, 0x89, 0xFF, 0x53, 0x01, 0xF5, 0xFC, 0x63, 0x06, 0xE9,
- 0xF1, 0x63, 0x37, 0x85, 0x28, 0x09, 0xF2, 0x27, 0x07, 0x35, 0xFC,
- 0xDA, 0x01, 0x40, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x0C, 0x00, 0xD1,
- 0xFF, 0x4E, 0x00, 0xCA, 0xFF, 0x9A, 0xFF, 0x2A, 0x02, 0x83, 0xF8,
- 0x3F, 0x45, 0xFB, 0x12, 0x01, 0xF7, 0x5D, 0x05, 0xD3, 0xFC, 0xB1,
- 0x01, 0x46, 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x23, 0x00,
- 0x73, 0xFF, 0x3F, 0x01, 0xD3, 0xFD, 0x4C, 0x03, 0x54, 0xFB, 0x1F,
- 0x07, 0xBB, 0x48, 0x7D, 0x00, 0x33, 0xFE, 0xCF, 0x01, 0x98, 0xFE,
- 0xE2, 0x00, 0x97, 0xFF, 0x19, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x38,
- 0xFF, 0xDC, 0x01, 0x64, 0xFC, 0x62, 0x06, 0x93, 0xF4, 0x66, 0x1B,
- 0xD9, 0x40, 0xEA, 0xF4, 0x3E, 0x04, 0x5D, 0xFE, 0x7D, 0x00, 0xF5,
- 0xFF, 0xF3, 0xFF, 0x05, 0x00, 0xFD, 0xFF, 0x2A, 0x00, 0x5E, 0xFF,
- 0xA6, 0x01, 0x76, 0xFC, 0x01, 0x07, 0x7D, 0xF1, 0xAD, 0x30, 0xDC,
- 0x2F, 0x7F, 0xF1, 0x0C, 0x07, 0x6C, 0xFC, 0xAD, 0x01, 0x5A, 0xFF,
- 0x2B, 0x00, 0xFD, 0xFF, 0x05, 0x00, 0xEF, 0xFF, 0xFE, 0xFF, 0x6C,
- 0x00, 0x7B, 0xFE, 0x0C, 0x04, 0x3A, 0xF5, 0x5F, 0x41, 0x83, 0x1A,
- 0xCD, 0xF4, 0x4B, 0x06, 0x6D, 0xFC, 0xD9, 0x01, 0x39, 0xFF, 0x35,
- 0x00, 0xFE, 0xFF, 0x1A, 0x00, 0x93, 0xFF, 0xEC, 0x00, 0x83, 0xFE,
- 0xF7, 0x01, 0xE8, 0xFD, 0x21, 0x01, 0xD2, 0x48, 0x64, 0x06, 0xA1,
- 0xFB, 0x26, 0x03, 0xE7, 0xFD, 0x35, 0x01, 0x76, 0xFF, 0x22, 0x00,
- 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x00, 0x44, 0xFF, 0xB7, 0x01, 0xC5,
- 0xFC, 0x7C, 0x05, 0xBC, 0xF6, 0xD5, 0x13, 0xDC, 0x44, 0x14, 0xF8,
- 0x67, 0x02, 0x77, 0xFF, 0xDD, 0xFF, 0x44, 0x00, 0xD5, 0xFF, 0x0B,
- 0x00, 0xFD, 0xFF, 0x33, 0x00, 0x42, 0xFF, 0xD7, 0x01, 0x39, 0xFC,
- 0x29, 0x07, 0xEF, 0xF1, 0x62, 0x29, 0xA5, 0x36, 0xD0, 0xF1, 0x7B,
- 0x06, 0xE3, 0xFC, 0x5E, 0x01, 0x83, 0xFF, 0x1D, 0x00, 0xFE, 0xFF,
- 0x01, 0x00, 0x09, 0x00, 0xB8, 0xFF, 0xF6, 0x00, 0x8D, 0xFD, 0x84,
- 0x05, 0xFD, 0xF2, 0x52, 0x3C, 0x35, 0x22, 0x0B, 0xF3, 0xEB, 0x06,
- 0x37, 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x12,
- 0x00, 0xB5, 0xFF, 0x94, 0x00, 0x39, 0xFF, 0xA3, 0x00, 0x58, 0x00,
- 0x02, 0xFC, 0x73, 0x47, 0x0B, 0x0D, 0x0B, 0xF9, 0x6C, 0x04, 0x45,
- 0xFD, 0x80, 0x01, 0x59, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x2A, 0x00, 0x5B, 0xFF, 0x7C, 0x01, 0x4E, 0xFD, 0x5A, 0x04, 0x31,
- 0xF9, 0xA4, 0x0C, 0x90, 0x47, 0x47, 0xFC, 0x36, 0x00, 0xB6, 0x00,
- 0x2E, 0xFF, 0x99, 0x00, 0xB3, 0xFF, 0x12, 0x00, 0xFD, 0xFF, 0x36,
- 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x39, 0xFC, 0xE4, 0x06, 0x21, 0xF3,
- 0xC4, 0x21, 0xA5, 0x3C, 0x16, 0xF3, 0x72, 0x05, 0x9A, 0xFD, 0xEF,
- 0x00, 0xBC, 0xFF, 0x08, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x1E, 0x00,
- 0x80, 0xFF, 0x64, 0x01, 0xDA, 0xFC, 0x87, 0x06, 0xC5, 0xF1, 0x46,
- 0x36, 0xD1, 0x29, 0xE3, 0xF1, 0x2A, 0x07, 0x3A, 0xFC, 0xD5, 0x01,
- 0x44, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x0A, 0x00, 0xD6, 0xFF, 0x3F,
- 0x00, 0xE7, 0xFF, 0x65, 0xFF, 0x85, 0x02, 0xDE, 0xF7, 0xA9, 0x44,
- 0x43, 0x14, 0x99, 0xF6, 0x8B, 0x05, 0xBF, 0xFC, 0xBA, 0x01, 0x43,
- 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x22, 0x00, 0x78, 0xFF,
- 0x31, 0x01, 0xF1, 0xFD, 0x12, 0x03, 0xC7, 0xFB, 0x07, 0x06, 0xDB,
- 0x48, 0x73, 0x01, 0xC3, 0xFD, 0x0A, 0x02, 0x79, 0xFE, 0xF1, 0x00,
- 0x91, 0xFF, 0x1B, 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x39, 0xFF, 0xD7,
- 0x01, 0x72, 0xFC, 0x3F, 0x06, 0xEB, 0xF4, 0x12, 0x1A, 0xA1, 0x41,
- 0x63, 0xF5, 0xF3, 0x03, 0x8A, 0xFE, 0x63, 0x00, 0x02, 0x00, 0xEE,
- 0xFF, 0x06, 0x00, 0xFD, 0xFF, 0x2C, 0x00, 0x58, 0xFF, 0xB1, 0x01,
- 0x67, 0xFC, 0x10, 0x07, 0x81, 0xF1, 0x73, 0x2F, 0x15, 0x31, 0x7C,
- 0xF1, 0xFB, 0x06, 0x7C, 0xFC, 0xA2, 0x01, 0x60, 0xFF, 0x29, 0x00,
- 0xFD, 0xFF, 0x04, 0x00, 0xF4, 0xFF, 0xF1, 0xFF, 0x85, 0x00, 0x4E,
- 0xFE, 0x56, 0x04, 0xC3, 0xF4, 0x95, 0x40, 0xD8, 0x1B, 0x76, 0xF4,
- 0x6D, 0x06, 0x60, 0xFC, 0xDD, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE,
- 0xFF, 0x19, 0x00, 0x99, 0xFF, 0xDD, 0x00, 0xA3, 0xFE, 0xBB, 0x01,
- 0x58, 0xFE, 0x2D, 0x00, 0xAF, 0x48, 0x7E, 0x07, 0x2E, 0xFB, 0x60,
- 0x03, 0xC9, 0xFD, 0x43, 0x01, 0x71, 0xFF, 0x24, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x30, 0x00, 0x48, 0xFF, 0xAE, 0x01, 0xDB, 0xFC, 0x4D,
- 0x05, 0x24, 0xF7, 0x8E, 0x12, 0x6D, 0x45, 0xBC, 0xF8, 0x0C, 0x02,
- 0xAC, 0xFF, 0xC0, 0xFF, 0x52, 0x00, 0xCF, 0xFF, 0x0C, 0x00, 0xFD,
- 0xFF, 0x34, 0x00, 0x3F, 0xFF, 0xDC, 0x01, 0x34, 0xFC, 0x25, 0x07,
- 0x18, 0xF2, 0x15, 0x28, 0xBF, 0x37, 0xF7, 0xF1, 0x56, 0x06, 0xFE,
- 0xFC, 0x4D, 0x01, 0x8C, 0xFF, 0x19, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0x0D, 0x00, 0xAE, 0xFF, 0x0B, 0x01, 0x6A, 0xFD, 0xBA, 0x05, 0xB4,
- 0xF2, 0x58, 0x3B, 0x8A, 0x23, 0xCB, 0xF2, 0xFD, 0x06, 0x34, 0xFC,
- 0xE6, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x10, 0x00, 0xBB,
- 0xFF, 0x85, 0x00, 0x58, 0xFF, 0x6A, 0x00, 0xBE, 0x00, 0x38, 0xFB,
- 0x0F, 0x47, 0x42, 0x0E, 0x9B, 0xF8, 0xA1, 0x04, 0x2B, 0xFD, 0x8B,
- 0x01, 0x55, 0xFF, 0x2C, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x29, 0x00,
- 0x5F, 0xFF, 0x70, 0x01, 0x68, 0xFD, 0x23, 0x04, 0xA2, 0xF9, 0x73,
- 0x0B, 0xE4, 0x47, 0x1B, 0xFD, 0xCD, 0xFF, 0xF0, 0x00, 0x0F, 0xFF,
- 0xA9, 0x00, 0xAE, 0xFF, 0x14, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36,
- 0xFF, 0xE6, 0x01, 0x3F, 0xFC, 0xCE, 0x06, 0x66, 0xF3, 0x6F, 0x20,
- 0x96, 0x3D, 0x69, 0xF3, 0x38, 0x05, 0xBF, 0xFD, 0xD9, 0x00, 0xC7,
- 0xFF, 0x04, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x20, 0x00, 0x78, 0xFF,
- 0x74, 0x01, 0xC2, 0xFC, 0xA7, 0x06, 0xA8, 0xF1, 0x25, 0x35, 0x1B,
- 0x2B, 0xC2, 0xF1, 0x2A, 0x07, 0x41, 0xFC, 0xCE, 0x01, 0x47, 0xFF,
- 0x31, 0x00, 0xFD, 0xFF, 0x09, 0x00, 0xDC, 0xFF, 0x31, 0x00, 0x04,
- 0x00, 0x32, 0xFF, 0xDC, 0x02, 0x42, 0xF7, 0x0B, 0x44, 0x8E, 0x15,
- 0x34, 0xF6, 0xB7, 0x05, 0xAB, 0xFC, 0xC1, 0x01, 0x40, 0xFF, 0x33,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x7E, 0xFF, 0x23, 0x01,
- 0x0F, 0xFE, 0xD7, 0x02, 0x3B, 0xFC, 0xF5, 0x04, 0xED, 0x48, 0x70,
- 0x02, 0x52, 0xFD, 0x46, 0x02, 0x5A, 0xFE, 0xFF, 0x00, 0x8B, 0xFF,
- 0x1C, 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x3B, 0xFF, 0xD2, 0x01, 0x81,
- 0xFC, 0x1A, 0x06, 0x47, 0xF5, 0xC1, 0x18, 0x60, 0x42, 0xE4, 0xF5,
- 0xA6, 0x03, 0xB9, 0xFE, 0x48, 0x00, 0x0F, 0x00, 0xE9, 0xFF, 0x07,
- 0x00, 0xFD, 0xFF, 0x2E, 0x00, 0x53, 0xFF, 0xBB, 0x01, 0x5A, 0xFC,
- 0x1C, 0x07, 0x8D, 0xF1, 0x34, 0x2E, 0x48, 0x32, 0x81, 0xF1, 0xE7,
- 0x06, 0x8E, 0xFC, 0x96, 0x01, 0x66, 0xFF, 0x27, 0x00, 0xFD, 0xFF,
- 0x04, 0x00, 0xF9, 0xFF, 0xE4, 0xFF, 0x9F, 0x00, 0x23, 0xFE, 0x9B,
- 0x04, 0x55, 0xF4, 0xC0, 0x3F, 0x2C, 0x1D, 0x22, 0xF4, 0x8C, 0x06,
- 0x55, 0xFC, 0xE1, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x17,
- 0x00, 0x9F, 0xFF, 0xCE, 0x00, 0xC2, 0xFE, 0x80, 0x01, 0xC6, 0xFE,
- 0x40, 0xFF, 0x81, 0x48, 0x9E, 0x08, 0xBA, 0xFA, 0x9A, 0x03, 0xAC,
- 0xFD, 0x51, 0x01, 0x6C, 0xFF, 0x25, 0x00, 0x00, 0x00, 0xFF, 0xFF,
- 0x2F, 0x00, 0x4B, 0xFF, 0xA4, 0x01, 0xF1, 0xFC, 0x1D, 0x05, 0x8F,
- 0xF7, 0x4A, 0x11, 0xF2, 0x45, 0x6B, 0xF9, 0xAE, 0x01, 0xE2, 0xFF,
- 0xA2, 0xFF, 0x61, 0x00, 0xC9, 0xFF, 0x0D, 0x00, 0xFD, 0xFF, 0x35,
- 0x00, 0x3D, 0xFF, 0xE0, 0x01, 0x32, 0xFC, 0x1D, 0x07, 0x45, 0xF2,
- 0xC6, 0x26, 0xD3, 0x38, 0x24, 0xF2, 0x2D, 0x06, 0x1B, 0xFD, 0x3B,
- 0x01, 0x95, 0xFF, 0x16, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x11, 0x00,
- 0xA3, 0xFF, 0x20, 0x01, 0x49, 0xFD, 0xEB, 0x05, 0x74, 0xF2, 0x54,
- 0x3A, 0xDD, 0x24, 0x91, 0xF2, 0x0C, 0x07, 0x32, 0xFC, 0xE4, 0x01,
- 0x3A, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x0F, 0x00, 0xC1, 0xFF, 0x76,
- 0x00, 0x76, 0xFF, 0x32, 0x00, 0x22, 0x01, 0x76, 0xFA, 0xA3, 0x46,
- 0x7D, 0x0F, 0x2C, 0xF8, 0xD5, 0x04, 0x13, 0xFD, 0x96, 0x01, 0x51,
- 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x27, 0x00, 0x64, 0xFF,
- 0x63, 0x01, 0x84, 0xFD, 0xEB, 0x03, 0x14, 0xFA, 0x47, 0x0A, 0x2C,
- 0x48, 0xF6, 0xFD, 0x63, 0xFF, 0x2B, 0x01, 0xF0, 0xFE, 0xB8, 0x00,
- 0xA8, 0xFF, 0x15, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE4,
- 0x01, 0x47, 0xFC, 0xB5, 0x06, 0xB0, 0xF3, 0x19, 0x1F, 0x7E, 0x3E,
- 0xC4, 0xF3, 0xFA, 0x04, 0xE7, 0xFD, 0xC1, 0x00, 0xD3, 0xFF, 0xFF,
- 0xFF, 0x02, 0x00, 0xFE, 0xFF, 0x23, 0x00, 0x71, 0xFF, 0x82, 0x01,
- 0xAB, 0xFC, 0xC4, 0x06, 0x93, 0xF1, 0xFD, 0x33, 0x62, 0x2C, 0xA8,
- 0xF1, 0x27, 0x07, 0x4A, 0xFC, 0xC7, 0x01, 0x4C, 0xFF, 0x30, 0x00,
- 0xFD, 0xFF, 0x08, 0x00, 0xE1, 0xFF, 0x23, 0x00, 0x20, 0x00, 0x00,
- 0xFF, 0x31, 0x03, 0xAD, 0xF6, 0x65, 0x43, 0xDC, 0x16, 0xD1, 0xF5,
- 0xE1, 0x05, 0x99, 0xFC, 0xC9, 0x01, 0x3E, 0xFF, 0x33, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x83, 0xFF, 0x14, 0x01, 0x2D, 0xFE,
- 0x9C, 0x02, 0xAD, 0xFC, 0xE9, 0x03, 0xF6, 0x48, 0x73, 0x03, 0xE0,
- 0xFC, 0x82, 0x02, 0x3B, 0xFE, 0x0E, 0x01, 0x86, 0xFF, 0x1E, 0x00,
- 0xFE, 0xFF, 0x34, 0x00, 0x3D, 0xFF, 0xCC, 0x01, 0x91, 0xFC, 0xF3,
- 0x05, 0xA6, 0xF5, 0x70, 0x17, 0x17, 0x43, 0x6D, 0xF6, 0x56, 0x03,
- 0xEA, 0xFE, 0x2D, 0x00, 0x1D, 0x00, 0xE4, 0xFF, 0x08, 0x00, 0xFD,
- 0xFF, 0x2F, 0x00, 0x4E, 0xFF, 0xC3, 0x01, 0x4E, 0xFC, 0x24, 0x07,
- 0x9E, 0xF1, 0xF2, 0x2C, 0x78, 0x33, 0x8C, 0xF1, 0xD0, 0x06, 0xA2,
- 0xFC, 0x88, 0x01, 0x6D, 0xFF, 0x24, 0x00, 0xFD, 0xFF, 0x03, 0x00,
- 0xFD, 0xFF, 0xD8, 0xFF, 0xB7, 0x00, 0xF9, 0xFD, 0xDE, 0x04, 0xEF,
- 0xF3, 0xE4, 0x3E, 0x81, 0x1E, 0xD2, 0xF3, 0xA9, 0x06, 0x4B, 0xFC,
- 0xE3, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x16, 0x00, 0xA5,
- 0xFF, 0xBE, 0x00, 0xE2, 0xFE, 0x45, 0x01, 0x33, 0xFF, 0x5A, 0xFE,
- 0x48, 0x48, 0xC3, 0x09, 0x47, 0xFA, 0xD2, 0x03, 0x90, 0xFD, 0x5E,
- 0x01, 0x66, 0xFF, 0x27, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2E, 0x00,
- 0x4F, 0xFF, 0x9A, 0x01, 0x08, 0xFD, 0xEB, 0x04, 0xFC, 0xF7, 0x0A,
- 0x10, 0x70, 0x46, 0x22, 0xFA, 0x4D, 0x01, 0x19, 0x00, 0x84, 0xFF,
- 0x70, 0x00, 0xC4, 0xFF, 0x0F, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3B,
- 0xFF, 0xE3, 0x01, 0x31, 0xFC, 0x12, 0x07, 0x79, 0xF2, 0x73, 0x25,
- 0xDF, 0x39, 0x5A, 0xF2, 0x00, 0x06, 0x3A, 0xFD, 0x28, 0x01, 0x9F,
- 0xFF, 0x13, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00, 0x99, 0xFF,
- 0x33, 0x01, 0x29, 0xFD, 0x1A, 0x06, 0x3B, 0xF2, 0x4B, 0x39, 0x30,
- 0x26, 0x5B, 0xF2, 0x19, 0x07, 0x31, 0xFC, 0xE1, 0x01, 0x3C, 0xFF,
- 0x35, 0x00, 0xFD, 0xFF, 0x0E, 0x00, 0xC7, 0xFF, 0x68, 0x00, 0x95,
- 0xFF, 0xFA, 0xFF, 0x83, 0x01, 0xBB, 0xF9, 0x2B, 0x46, 0xBB, 0x10,
- 0xBF, 0xF7, 0x07, 0x05, 0xFB, 0xFC, 0xA0, 0x01, 0x4D, 0xFF, 0x2F,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x26, 0x00, 0x69, 0xFF, 0x56, 0x01,
- 0xA0, 0xFD, 0xB3, 0x03, 0x87, 0xFA, 0x1F, 0x09, 0x6A, 0x48, 0xD9,
- 0xFE, 0xF6, 0xFE, 0x65, 0x01, 0xD0, 0xFE, 0xC7, 0x00, 0xA2, 0xFF,
- 0x17, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE2, 0x01, 0x50,
- 0xFC, 0x99, 0x06, 0xFE, 0xF3, 0xC3, 0x1D, 0x5E, 0x3F, 0x27, 0xF4,
- 0xB9, 0x04, 0x10, 0xFE, 0xA9, 0x00, 0xDF, 0xFF, 0xFB, 0xFF, 0x03,
- 0x00, 0xFD, 0xFF, 0x26, 0x00, 0x69, 0xFF, 0x90, 0x01, 0x96, 0xFC,
- 0xDD, 0x06, 0x85, 0xF1, 0xD0, 0x32, 0xA6, 0x2D, 0x94, 0xF1, 0x20,
- 0x07, 0x54, 0xFC, 0xBF, 0x01, 0x50, 0xFF, 0x2E, 0x00, 0xFD, 0xFF,
- 0x07, 0x00, 0xE6, 0xFF, 0x15, 0x00, 0x3C, 0x00, 0xCF, 0xFE, 0x83,
- 0x03, 0x20, 0xF6, 0xB2, 0x42, 0x2B, 0x18, 0x71, 0xF5, 0x09, 0x06,
- 0x88, 0xFC, 0xCF, 0x01, 0x3C, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0x1D,
- 0x00, 0x89, 0xFF, 0x06, 0x01, 0x4C, 0xFE, 0x60, 0x02, 0x1F, 0xFD,
- 0xE2, 0x02, 0xF3, 0x48, 0x7D, 0x04, 0x6E, 0xFC, 0xBD, 0x02, 0x1C,
- 0xFE, 0x1C, 0x01, 0x80, 0xFF, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF,
- 0x33, 0x00, 0x3F, 0xFF, 0xC5, 0x01, 0xA3, 0xFC, 0xCA, 0x05, 0x07,
- 0xF6, 0x22, 0x16, 0xC3, 0x43, 0xFE, 0xF6, 0x02, 0x03, 0x1B, 0xFF,
- 0x11, 0x00, 0x2B, 0x00, 0xDE, 0xFF, 0x09, 0x00, 0xFD, 0xFF, 0x31,
- 0x00, 0x49, 0xFF, 0xCB, 0x01, 0x45, 0xFC, 0x29, 0x07, 0xB6, 0xF1,
- 0xAD, 0x2B, 0xA2, 0x34, 0x9E, 0xF1, 0xB4, 0x06, 0xB8, 0xFC, 0x7A,
- 0x01, 0x75, 0xFF, 0x22, 0x00, 0xFE, 0xFF, 0x02, 0x00, 0x02, 0x00,
- 0xCC, 0xFF, 0xCE, 0x00, 0xD1, 0xFD, 0x1D, 0x05, 0x91, 0xF3, 0xFE,
- 0x3D, 0xD7, 0x1F, 0x87, 0xF3, 0xC3, 0x06, 0x42, 0xFC, 0xE5, 0x01,
- 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x14, 0x00, 0xAB, 0xFF, 0xAF,
- 0x00, 0x01, 0xFF, 0x0A, 0x01, 0x9E, 0xFF, 0x7C, 0xFD, 0x03, 0x48,
- 0xED, 0x0A, 0xD5, 0xF9, 0x0A, 0x04, 0x74, 0xFD, 0x6A, 0x01, 0x62,
- 0xFF, 0x28, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x2D, 0x00, 0x53, 0xFF,
- 0x90, 0x01, 0x20, 0xFD, 0xB8, 0x04, 0x6A, 0xF8, 0xCD, 0x0E, 0xE1,
- 0x46, 0xE1, 0xFA, 0xEB, 0x00, 0x51, 0x00, 0x65, 0xFF, 0x7F, 0x00,
- 0xBE, 0xFF, 0x10, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x39, 0xFF, 0xE5,
- 0x01, 0x33, 0xFC, 0x04, 0x07, 0xB1, 0xF2, 0x21, 0x24, 0xE6, 0x3A,
- 0x97, 0xF2, 0xD0, 0x05, 0x5B, 0xFD, 0x15, 0x01, 0xA9, 0xFF, 0x0F,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x00, 0x90, 0xFF, 0x45, 0x01,
- 0x0B, 0xFD, 0x44, 0x06, 0x0A, 0xF2, 0x3B, 0x38, 0x80, 0x27, 0x2B,
- 0xF2, 0x22, 0x07, 0x33, 0xFC, 0xDE, 0x01, 0x3E, 0xFF, 0x34, 0x00,
- 0xFD, 0xFF, 0x0D, 0x00, 0xCD, 0xFF, 0x59, 0x00, 0xB3, 0xFF, 0xC4,
- 0xFF, 0xE2, 0x01, 0x09, 0xF9, 0xAA, 0x45, 0xFE, 0x11, 0x54, 0xF7,
- 0x38, 0x05, 0xE4, 0xFC, 0xAA, 0x01, 0x49, 0xFF, 0x30, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x24, 0x00, 0x6E, 0xFF, 0x49, 0x01, 0xBC, 0xFD,
- 0x7A, 0x03, 0xFA, 0xFA, 0xFD, 0x07, 0x9C, 0x48, 0xC3, 0xFF, 0x89,
- 0xFE, 0xA1, 0x01, 0xB1, 0xFE, 0xD6, 0x00, 0x9C, 0xFF, 0x18, 0x00,
- 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xDF, 0x01, 0x5B, 0xFC, 0x7B,
- 0x06, 0x50, 0xF4, 0x6E, 0x1C, 0x36, 0x40, 0x92, 0xF4, 0x75, 0x04,
- 0x3B, 0xFE, 0x91, 0x00, 0xEB, 0xFF, 0xF6, 0xFF, 0x04, 0x00, 0xFD,
- 0xFF, 0x28, 0x00, 0x63, 0xFF, 0x9D, 0x01, 0x84, 0xFC, 0xF3, 0x06,
- 0x7D, 0xF1, 0x9E, 0x31, 0xE6, 0x2E, 0x85, 0xF1, 0x16, 0x07, 0x61,
- 0xFC, 0xB5, 0x01, 0x55, 0xFF, 0x2D, 0x00, 0xFD, 0xFF, 0x06, 0x00,
- 0xEC, 0xFF, 0x08, 0x00, 0x57, 0x00, 0x9F, 0xFE, 0xD1, 0x03, 0x9B,
- 0xF5, 0xF7, 0x41, 0x7C, 0x19, 0x13, 0xF5, 0x2F, 0x06, 0x78, 0xFC,
- 0xD5, 0x01, 0x3A, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1C, 0x00, 0x8F,
- 0xFF, 0xF7, 0x00, 0x6B, 0xFE, 0x25, 0x02, 0x91, 0xFD, 0xE3, 0x01,
- 0xE5, 0x48, 0x8D, 0x05, 0xFB, 0xFB, 0xF8, 0x02, 0xFE, 0xFD, 0x2B,
- 0x01, 0x7A, 0xFF, 0x21, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x32, 0x00,
- 0x42, 0xFF, 0xBD, 0x01, 0xB6, 0xFC, 0x9F, 0x05, 0x6C, 0xF6, 0xD6,
- 0x14, 0x65, 0x44, 0x98, 0xF7, 0xAC, 0x02, 0x4E, 0xFF, 0xF4, 0xFF,
- 0x39, 0x00, 0xD9, 0xFF, 0x0A, 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x45,
- 0xFF, 0xD2, 0x01, 0x3D, 0xFC, 0x2B, 0x07, 0xD4, 0xF1, 0x64, 0x2A,
- 0xC6, 0x35, 0xB7, 0xF1, 0x96, 0x06, 0xCF, 0xFC, 0x6B, 0x01, 0x7D,
- 0xFF, 0x1F, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x06, 0x00, 0xC1, 0xFF,
- 0xE5, 0x00, 0xAA, 0xFD, 0x58, 0x05, 0x3A, 0xF3, 0x11, 0x3D, 0x2C,
- 0x21, 0x3F, 0xF3, 0xDA, 0x06, 0x3B, 0xFC, 0xE6, 0x01, 0x36, 0xFF,
- 0x36, 0x00, 0xFD, 0xFF, 0x13, 0x00, 0xB1, 0xFF, 0xA0, 0x00, 0x20,
- 0xFF, 0xD0, 0x00, 0x07, 0x00, 0xA4, 0xFC, 0xB6, 0x47, 0x1C, 0x0C,
- 0x63, 0xF9, 0x42, 0x04, 0x59, 0xFD, 0x76, 0x01, 0x5D, 0xFF, 0x2A,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x57, 0xFF, 0x85, 0x01,
- 0x39, 0xFD, 0x84, 0x04, 0xD9, 0xF8, 0x95, 0x0D, 0x48, 0x47, 0xA7,
- 0xFB, 0x86, 0x00, 0x8A, 0x00, 0x46, 0xFF, 0x8E, 0x00, 0xB8, 0xFF,
- 0x11, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x35,
- 0xFC, 0xF3, 0x06, 0xEE, 0xF2, 0xCD, 0x22, 0xE4, 0x3B, 0xDC, 0xF2,
- 0x9C, 0x05, 0x7E, 0xFD, 0x00, 0x01, 0xB4, 0xFF, 0x0B, 0x00, 0x01,
- 0x00, 0xFE, 0xFF, 0x1B, 0x00, 0x87, 0xFF, 0x57, 0x01, 0xEF, 0xFC,
- 0x6B, 0x06, 0xE0, 0xF1, 0x23, 0x37, 0xCE, 0x28, 0x01, 0xF2, 0x28,
- 0x07, 0x36, 0xFC, 0xD9, 0x01, 0x41, 0xFF, 0x33, 0x00, 0xFD, 0xFF,
- 0x0B, 0x00, 0xD2, 0xFF, 0x4A, 0x00, 0xD0, 0xFF, 0x8E, 0xFF, 0x3F,
- 0x02, 0x5E, 0xF8, 0x1E, 0x45, 0x44, 0x13, 0xEA, 0xF6, 0x67, 0x05,
- 0xCF, 0xFC, 0xB3, 0x01, 0x46, 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x23, 0x00, 0x74, 0xFF, 0x3C, 0x01, 0xDA, 0xFD, 0x40, 0x03,
- 0x6E, 0xFB, 0xE1, 0x06, 0xC3, 0x48, 0xB3, 0x00, 0x1A, 0xFE, 0xDC,
- 0x01, 0x91, 0xFE, 0xE5, 0x00, 0x96, 0xFF, 0x1A, 0x00, 0xFE, 0xFF,
- 0x36, 0x00, 0x38, 0xFF, 0xDB, 0x01, 0x67, 0xFC, 0x5A, 0x06, 0xA6,
- 0xF4, 0x1B, 0x1B, 0x07, 0x41, 0x04, 0xF5, 0x2D, 0x04, 0x67, 0xFE,
- 0x77, 0x00, 0xF8, 0xFF, 0xF2, 0xFF, 0x05, 0x00, 0xFD, 0xFF, 0x2A,
- 0x00, 0x5C, 0xFF, 0xA8, 0x01, 0x73, 0xFC, 0x05, 0x07, 0x7D, 0xF1,
- 0x67, 0x30, 0x21, 0x30, 0x7E, 0xF1, 0x08, 0x07, 0x6F, 0xFC, 0xAB,
- 0x01, 0x5B, 0xFF, 0x2B, 0x00, 0xFD, 0xFF, 0x05, 0x00, 0xF0, 0xFF,
- 0xFB, 0xFF, 0x71, 0x00, 0x71, 0xFE, 0x1D, 0x04, 0x1F, 0xF5, 0x32,
- 0x41, 0xCE, 0x1A, 0xBA, 0xF4, 0x53, 0x06, 0x6A, 0xFC, 0xDA, 0x01,
- 0x38, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x1A, 0x00, 0x95, 0xFF, 0xE8,
- 0x00, 0x8A, 0xFE, 0xE9, 0x01, 0x01, 0xFE, 0xEA, 0x00, 0xCB, 0x48,
- 0xA2, 0x06, 0x87, 0xFB, 0x33, 0x03, 0xE0, 0xFD, 0x39, 0x01, 0x75,
- 0xFF, 0x23, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x00, 0x45, 0xFF,
- 0xB5, 0x01, 0xCA, 0xFC, 0x72, 0x05, 0xD3, 0xF6, 0x8D, 0x13, 0xFD,
- 0x44, 0x39, 0xF8, 0x53, 0x02, 0x82, 0xFF, 0xD7, 0xFF, 0x47, 0x00,
- 0xD3, 0xFF, 0x0B, 0x00, 0xFD, 0xFF, 0x33, 0x00, 0x42, 0xFF, 0xD8,
- 0x01, 0x37, 0xFC, 0x29, 0x07, 0xF8, 0xF1, 0x19, 0x29, 0xE5, 0x36,
- 0xD8, 0xF1, 0x73, 0x06, 0xE9, 0xFC, 0x5B, 0x01, 0x85, 0xFF, 0x1C,
- 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x0A, 0x00, 0xB6, 0xFF, 0xFB, 0x00,
- 0x85, 0xFD, 0x90, 0x05, 0xEC, 0xF2, 0x1C, 0x3C, 0x81, 0x22, 0xFC,
- 0xF2, 0xEF, 0x06, 0x36, 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00,
- 0xFD, 0xFF, 0x12, 0x00, 0xB7, 0xFF, 0x91, 0x00, 0x40, 0xFF, 0x96,
- 0x00, 0x6F, 0x00, 0xD5, 0xFB, 0x5E, 0x47, 0x50, 0x0D, 0xF2, 0xF8,
- 0x78, 0x04, 0x3F, 0xFD, 0x82, 0x01, 0x58, 0xFF, 0x2B, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x2A, 0x00, 0x5C, 0xFF, 0x79, 0x01, 0x53, 0xFD,
- 0x4E, 0x04, 0x4A, 0xF9, 0x60, 0x0C, 0xA3, 0x47, 0x76, 0xFC, 0x1F,
- 0x00, 0xC3, 0x00, 0x27, 0xFF, 0x9D, 0x00, 0xB2, 0xFF, 0x13, 0x00,
- 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x3A, 0xFC, 0xDF,
- 0x06, 0x30, 0xF3, 0x78, 0x21, 0xDB, 0x3C, 0x28, 0xF3, 0x65, 0x05,
- 0xA2, 0xFD, 0xEA, 0x00, 0xBE, 0xFF, 0x07, 0x00, 0x01, 0x00, 0xFE,
- 0xFF, 0x1E, 0x00, 0x7F, 0xFF, 0x67, 0x01, 0xD5, 0xFC, 0x8E, 0x06,
- 0xBE, 0xF1, 0x06, 0x36, 0x1A, 0x2A, 0xDC, 0xF1, 0x2A, 0x07, 0x3C,
- 0xFC, 0xD3, 0x01, 0x44, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x0A, 0x00,
- 0xD8, 0xFF, 0x3C, 0x00, 0xEE, 0xFF, 0x5A, 0xFF, 0x98, 0x02, 0xBB,
- 0xF7, 0x87, 0x44, 0x8C, 0x14, 0x83, 0xF6, 0x95, 0x05, 0xBA, 0xFC,
- 0xBB, 0x01, 0x43, 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x21,
- 0x00, 0x79, 0xFF, 0x2E, 0x01, 0xF7, 0xFD, 0x05, 0x03, 0xE1, 0xFB,
- 0xCA, 0x05, 0xDF, 0x48, 0xAB, 0x01, 0xAA, 0xFD, 0x18, 0x02, 0x72,
- 0xFE, 0xF4, 0x00, 0x90, 0xFF, 0x1B, 0x00, 0xFE, 0xFF, 0x35, 0x00,
- 0x39, 0xFF, 0xD6, 0x01, 0x75, 0xFC, 0x37, 0x06, 0xFF, 0xF4, 0xC7,
- 0x19, 0xCC, 0x41, 0x7F, 0xF5, 0xE2, 0x03, 0x95, 0xFE, 0x5D, 0x00,
- 0x05, 0x00, 0xED, 0xFF, 0x06, 0x00, 0xFD, 0xFF, 0x2C, 0x00, 0x57,
- 0xFF, 0xB3, 0x01, 0x64, 0xFC, 0x13, 0x07, 0x83, 0xF1, 0x2C, 0x2F,
- 0x5A, 0x31, 0x7D, 0xF1, 0xF7, 0x06, 0x80, 0xFC, 0x9F, 0x01, 0x61,
- 0xFF, 0x29, 0x00, 0xFD, 0xFF, 0x04, 0x00, 0xF5, 0xFF, 0xEE, 0xFF,
- 0x8B, 0x00, 0x44, 0xFE, 0x65, 0x04, 0xAA, 0xF4, 0x66, 0x40, 0x23,
- 0x1C, 0x63, 0xF4, 0x74, 0x06, 0x5D, 0xFC, 0xDE, 0x01, 0x37, 0xFF,
- 0x36, 0x00, 0xFE, 0xFF, 0x19, 0x00, 0x9A, 0xFF, 0xD9, 0x00, 0xAA,
- 0xFE, 0xAE, 0x01, 0x70, 0xFE, 0xF8, 0xFF, 0xA6, 0x48, 0xBE, 0x07,
- 0x14, 0xFB, 0x6D, 0x03, 0xC3, 0xFD, 0x46, 0x01, 0x70, 0xFF, 0x24,
- 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0x00, 0x48, 0xFF, 0xAC, 0x01,
- 0xDF, 0xFC, 0x43, 0x05, 0x3C, 0xF7, 0x46, 0x12, 0x8D, 0x45, 0xE2,
- 0xF8, 0xF7, 0x01, 0xB8, 0xFF, 0xB9, 0xFF, 0x56, 0x00, 0xCE, 0xFF,
- 0x0C, 0x00, 0xFD, 0xFF, 0x34, 0x00, 0x3F, 0xFF, 0xDD, 0x01, 0x34,
- 0xFC, 0x23, 0x07, 0x21, 0xF2, 0xCB, 0x27, 0xFE, 0x37, 0x00, 0xF2,
- 0x4D, 0x06, 0x04, 0xFD, 0x49, 0x01, 0x8E, 0xFF, 0x19, 0x00, 0xFF,
- 0xFF, 0x00, 0x00, 0x0E, 0x00, 0xAB, 0xFF, 0x10, 0x01, 0x62, 0xFD,
- 0xC5, 0x05, 0xA5, 0xF2, 0x1F, 0x3B, 0xD6, 0x23, 0xBE, 0xF2, 0x01,
- 0x07, 0x33, 0xFC, 0xE5, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0x10, 0x00, 0xBD, 0xFF, 0x82, 0x00, 0x5E, 0xFF, 0x5D, 0x00, 0xD4,
- 0x00, 0x0C, 0xFB, 0xF9, 0x46, 0x87, 0x0E, 0x82, 0xF8, 0xAD, 0x04,
- 0x26, 0xFD, 0x8D, 0x01, 0x54, 0xFF, 0x2C, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x29, 0x00, 0x60, 0xFF, 0x6D, 0x01, 0x6E, 0xFD, 0x17, 0x04,
- 0xBC, 0xF9, 0x30, 0x0B, 0xF4, 0x47, 0x4B, 0xFD, 0xB5, 0xFF, 0xFD,
- 0x00, 0x08, 0xFF, 0xAC, 0x00, 0xAC, 0xFF, 0x14, 0x00, 0xFD, 0xFF,
- 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x41, 0xFC, 0xC8, 0x06, 0x76,
- 0xF3, 0x22, 0x20, 0xCA, 0x3D, 0x7D, 0xF3, 0x2A, 0x05, 0xC8, 0xFD,
- 0xD4, 0x00, 0xCA, 0xFF, 0x03, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x21,
- 0x00, 0x77, 0xFF, 0x77, 0x01, 0xBD, 0xFC, 0xAE, 0x06, 0xA3, 0xF1,
- 0xE3, 0x34, 0x64, 0x2B, 0xBC, 0xF1, 0x2A, 0x07, 0x43, 0xFC, 0xCD,
- 0x01, 0x48, 0xFF, 0x31, 0x00, 0xFD, 0xFF, 0x09, 0x00, 0xDD, 0xFF,
- 0x2E, 0x00, 0x0A, 0x00, 0x27, 0xFF, 0xEF, 0x02, 0x20, 0xF7, 0xE7,
- 0x43, 0xD8, 0x15, 0x1E, 0xF6, 0xC0, 0x05, 0xA7, 0xFC, 0xC3, 0x01,
- 0x40, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x7F,
- 0xFF, 0x20, 0x01, 0x16, 0xFE, 0xCA, 0x02, 0x54, 0xFC, 0xB9, 0x04,
- 0xF2, 0x48, 0xA9, 0x02, 0x39, 0xFD, 0x53, 0x02, 0x53, 0xFE, 0x03,
- 0x01, 0x8A, 0xFF, 0x1D, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3B, 0xFF,
- 0xD1, 0x01, 0x84, 0xFC, 0x12, 0x06, 0x5C, 0xF5, 0x76, 0x18, 0x89,
- 0x42, 0x02, 0xF6, 0x94, 0x03, 0xC4, 0xFE, 0x42, 0x00, 0x12, 0x00,
- 0xE8, 0xFF, 0x07, 0x00, 0xFD, 0xFF, 0x2E, 0x00, 0x51, 0xFF, 0xBD,
- 0x01, 0x57, 0xFC, 0x1E, 0x07, 0x90, 0xF1, 0xED, 0x2D, 0x8C, 0x32,
- 0x83, 0xF1, 0xE2, 0x06, 0x92, 0xFC, 0x93, 0x01, 0x68, 0xFF, 0x26,
- 0x00, 0xFD, 0xFF, 0x03, 0x00, 0xFA, 0xFF, 0xE2, 0xFF, 0xA4, 0x00,
- 0x19, 0xFE, 0xAA, 0x04, 0x3E, 0xF4, 0x90, 0x3F, 0x78, 0x1D, 0x10,
- 0xF4, 0x93, 0x06, 0x52, 0xFC, 0xE1, 0x01, 0x36, 0xFF, 0x36, 0x00,
- 0xFE, 0xFF, 0x17, 0x00, 0xA0, 0xFF, 0xCA, 0x00, 0xC9, 0xFE, 0x73,
- 0x01, 0xDE, 0xFE, 0x0C, 0xFF, 0x76, 0x48, 0xDE, 0x08, 0xA1, 0xFA,
- 0xA6, 0x03, 0xA6, 0xFD, 0x53, 0x01, 0x6A, 0xFF, 0x26, 0x00, 0x00,
- 0x00, 0xFF, 0xFF, 0x2F, 0x00, 0x4C, 0xFF, 0xA2, 0x01, 0xF6, 0xFC,
- 0x12, 0x05, 0xA7, 0xF7, 0x03, 0x11, 0x10, 0x46, 0x93, 0xF9, 0x98,
- 0x01, 0xEE, 0xFF, 0x9B, 0xFF, 0x64, 0x00, 0xC8, 0xFF, 0x0E, 0x00,
- 0xFD, 0xFF, 0x35, 0x00, 0x3C, 0xFF, 0xE1, 0x01, 0x32, 0xFC, 0x1B,
- 0x07, 0x50, 0xF2, 0x7B, 0x26, 0x11, 0x39, 0x2F, 0xF2, 0x23, 0x06,
- 0x22, 0xFD, 0x37, 0x01, 0x97, 0xFF, 0x15, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0x12, 0x00, 0xA1, 0xFF, 0x24, 0x01, 0x41, 0xFD, 0xF6, 0x05,
- 0x67, 0xF2, 0x1A, 0x3A, 0x29, 0x25, 0x84, 0xF2, 0x0F, 0x07, 0x31,
- 0xFC, 0xE3, 0x01, 0x3A, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x0F, 0x00,
- 0xC2, 0xFF, 0x73, 0x00, 0x7D, 0xFF, 0x25, 0x00, 0x38, 0x01, 0x4C,
- 0xFA, 0x89, 0x46, 0xC3, 0x0F, 0x14, 0xF8, 0xE0, 0x04, 0x0D, 0xFD,
- 0x98, 0x01, 0x50, 0xFF, 0x2E, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x27,
- 0x00, 0x65, 0xFF, 0x60, 0x01, 0x8A, 0xFD, 0xDF, 0x03, 0x2E, 0xFA,
- 0x04, 0x0A, 0x3A, 0x48, 0x28, 0xFE, 0x4B, 0xFF, 0x38, 0x01, 0xE9,
- 0xFE, 0xBB, 0x00, 0xA6, 0xFF, 0x16, 0x00, 0xFE, 0xFF, 0x36, 0x00,
- 0x36, 0xFF, 0xE4, 0x01, 0x49, 0xFC, 0xAF, 0x06, 0xC1, 0xF3, 0xCD,
- 0x1E, 0xB1, 0x3E, 0xD9, 0xF3, 0xEC, 0x04, 0xF0, 0xFD, 0xBC, 0x00,
- 0xD5, 0xFF, 0xFE, 0xFF, 0x03, 0x00, 0xFD, 0xFF, 0x24, 0x00, 0x6F,
- 0xFF, 0x85, 0x01, 0xA6, 0xFC, 0xCA, 0x06, 0x8F, 0xF1, 0xBB, 0x33,
- 0xAB, 0x2C, 0xA3, 0xF1, 0x26, 0x07, 0x4C, 0xFC, 0xC5, 0x01, 0x4D,
- 0xFF, 0x30, 0x00, 0xFD, 0xFF, 0x08, 0x00, 0xE2, 0xFF, 0x20, 0x00,
- 0x26, 0x00, 0xF5, 0xFE, 0x43, 0x03, 0x8D, 0xF6, 0x3C, 0x43, 0x25,
- 0x17, 0xBB, 0xF5, 0xEA, 0x05, 0x95, 0xFC, 0xCA, 0x01, 0x3D, 0xFF,
- 0x34, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x1E, 0x00, 0x84, 0xFF, 0x11,
- 0x01, 0x34, 0xFE, 0x8F, 0x02, 0xC7, 0xFC, 0xAE, 0x03, 0xF7, 0x48,
- 0xAE, 0x03, 0xC7, 0xFC, 0x8F, 0x02, 0x34, 0xFE, 0x11, 0x01, 0x84,
- 0xFF, 0x1E, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01,
- 0x3D, 0xFC, 0xD6, 0x06, 0x4C, 0xF3, 0xED, 0x20, 0x3D, 0x3D, 0x4A,
- 0xF3, 0x4E, 0x05, 0xB1, 0xFD, 0xE1, 0x00, 0xC3, 0xFF, 0x05, 0x00,
- 0x02, 0x00, 0x02, 0x00, 0x05, 0x00, 0xC3, 0xFF, 0xE1, 0x00, 0xB1,
- 0xFD, 0x4E, 0x05, 0x4A, 0xF3, 0x3D, 0x3D, 0xED, 0x20, 0x4C, 0xF3,
- 0xD6, 0x06, 0x3D, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0x00, 0x00, 0x1E, 0x00, 0x84, 0xFF, 0x11, 0x01, 0x34, 0xFE,
- 0x8F, 0x02, 0xC7, 0xFC, 0xAE, 0x03, 0xF7, 0x48, 0xAE, 0x03, 0xC7,
- 0xFC, 0x8F, 0x02, 0x34, 0xFE, 0x11, 0x01, 0x84, 0xFF, 0x1E, 0x00,
- 0xFD, 0xFF, 0x30, 0x00, 0x4D, 0xFF, 0xC5, 0x01, 0x4C, 0xFC, 0x26,
- 0x07, 0xA3, 0xF1, 0xAB, 0x2C, 0xBB, 0x33, 0x8F, 0xF1, 0xCA, 0x06,
- 0xA6, 0xFC, 0x85, 0x01, 0x6F, 0xFF, 0x24, 0x00, 0xFD, 0xFF, 0x16,
- 0x00, 0xA6, 0xFF, 0xBB, 0x00, 0xE9, 0xFE, 0x38, 0x01, 0x4B, 0xFF,
- 0x28, 0xFE, 0x3A, 0x48, 0x04, 0x0A, 0x2E, 0xFA, 0xDF, 0x03, 0x8A,
- 0xFD, 0x60, 0x01, 0x65, 0xFF, 0x27, 0x00, 0x00, 0x00, 0xFD, 0xFF,
- 0x35, 0x00, 0x3A, 0xFF, 0xE3, 0x01, 0x31, 0xFC, 0x0F, 0x07, 0x84,
- 0xF2, 0x29, 0x25, 0x1A, 0x3A, 0x67, 0xF2, 0xF6, 0x05, 0x41, 0xFD,
- 0x24, 0x01, 0xA1, 0xFF, 0x12, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xC8,
- 0xFF, 0x64, 0x00, 0x9B, 0xFF, 0xEE, 0xFF, 0x98, 0x01, 0x93, 0xF9,
- 0x10, 0x46, 0x03, 0x11, 0xA7, 0xF7, 0x12, 0x05, 0xF6, 0xFC, 0xA2,
- 0x01, 0x4C, 0xFF, 0x2F, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00,
- 0x36, 0xFF, 0xE1, 0x01, 0x52, 0xFC, 0x93, 0x06, 0x10, 0xF4, 0x78,
- 0x1D, 0x90, 0x3F, 0x3E, 0xF4, 0xAA, 0x04, 0x19, 0xFE, 0xA4, 0x00,
- 0xE2, 0xFF, 0xFA, 0xFF, 0x03, 0x00, 0x07, 0x00, 0xE8, 0xFF, 0x12,
- 0x00, 0x42, 0x00, 0xC4, 0xFE, 0x94, 0x03, 0x02, 0xF6, 0x89, 0x42,
- 0x76, 0x18, 0x5C, 0xF5, 0x12, 0x06, 0x84, 0xFC, 0xD1, 0x01, 0x3B,
- 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x33, 0x00, 0x40, 0xFF,
- 0xC3, 0x01, 0xA7, 0xFC, 0xC0, 0x05, 0x1E, 0xF6, 0xD8, 0x15, 0xE7,
- 0x43, 0x20, 0xF7, 0xEF, 0x02, 0x27, 0xFF, 0x0A, 0x00, 0x2E, 0x00,
- 0xDD, 0xFF, 0x09, 0x00, 0x02, 0x00, 0x03, 0x00, 0xCA, 0xFF, 0xD4,
- 0x00, 0xC8, 0xFD, 0x2A, 0x05, 0x7D, 0xF3, 0xCA, 0x3D, 0x22, 0x20,
- 0x76, 0xF3, 0xC8, 0x06, 0x41, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x2C, 0x00, 0x54, 0xFF, 0x8D, 0x01,
- 0x26, 0xFD, 0xAD, 0x04, 0x82, 0xF8, 0x87, 0x0E, 0xF9, 0x46, 0x0C,
- 0xFB, 0xD4, 0x00, 0x5D, 0x00, 0x5E, 0xFF, 0x82, 0x00, 0xBD, 0xFF,
- 0x10, 0x00, 0xFF, 0xFF, 0x19, 0x00, 0x8E, 0xFF, 0x49, 0x01, 0x04,
- 0xFD, 0x4D, 0x06, 0x00, 0xF2, 0xFE, 0x37, 0xCB, 0x27, 0x21, 0xF2,
- 0x23, 0x07, 0x34, 0xFC, 0xDD, 0x01, 0x3F, 0xFF, 0x34, 0x00, 0xFD,
- 0xFF, 0x00, 0x00, 0x24, 0x00, 0x70, 0xFF, 0x46, 0x01, 0xC3, 0xFD,
- 0x6D, 0x03, 0x14, 0xFB, 0xBE, 0x07, 0xA6, 0x48, 0xF8, 0xFF, 0x70,
- 0xFE, 0xAE, 0x01, 0xAA, 0xFE, 0xD9, 0x00, 0x9A, 0xFF, 0x19, 0x00,
- 0xFD, 0xFF, 0x29, 0x00, 0x61, 0xFF, 0x9F, 0x01, 0x80, 0xFC, 0xF7,
- 0x06, 0x7D, 0xF1, 0x5A, 0x31, 0x2C, 0x2F, 0x83, 0xF1, 0x13, 0x07,
- 0x64, 0xFC, 0xB3, 0x01, 0x57, 0xFF, 0x2C, 0x00, 0xFD, 0xFF, 0x1B,
- 0x00, 0x90, 0xFF, 0xF4, 0x00, 0x72, 0xFE, 0x18, 0x02, 0xAA, 0xFD,
- 0xAB, 0x01, 0xDF, 0x48, 0xCA, 0x05, 0xE1, 0xFB, 0x05, 0x03, 0xF7,
- 0xFD, 0x2E, 0x01, 0x79, 0xFF, 0x21, 0x00, 0x00, 0x00, 0xFD, 0xFF,
- 0x32, 0x00, 0x44, 0xFF, 0xD3, 0x01, 0x3C, 0xFC, 0x2A, 0x07, 0xDC,
- 0xF1, 0x1A, 0x2A, 0x06, 0x36, 0xBE, 0xF1, 0x8E, 0x06, 0xD5, 0xFC,
- 0x67, 0x01, 0x7F, 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0x13, 0x00, 0xB2,
- 0xFF, 0x9D, 0x00, 0x27, 0xFF, 0xC3, 0x00, 0x1F, 0x00, 0x76, 0xFC,
- 0xA3, 0x47, 0x60, 0x0C, 0x4A, 0xF9, 0x4E, 0x04, 0x53, 0xFD, 0x79,
- 0x01, 0x5C, 0xFF, 0x2A, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00,
- 0x37, 0xFF, 0xE6, 0x01, 0x36, 0xFC, 0xEF, 0x06, 0xFC, 0xF2, 0x81,
- 0x22, 0x1C, 0x3C, 0xEC, 0xF2, 0x90, 0x05, 0x85, 0xFD, 0xFB, 0x00,
- 0xB6, 0xFF, 0x0A, 0x00, 0x01, 0x00, 0x0B, 0x00, 0xD3, 0xFF, 0x47,
- 0x00, 0xD7, 0xFF, 0x82, 0xFF, 0x53, 0x02, 0x39, 0xF8, 0xFD, 0x44,
- 0x8D, 0x13, 0xD3, 0xF6, 0x72, 0x05, 0xCA, 0xFC, 0xB5, 0x01, 0x45,
- 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x35, 0x00, 0x38, 0xFF,
- 0xDA, 0x01, 0x6A, 0xFC, 0x53, 0x06, 0xBA, 0xF4, 0xCE, 0x1A, 0x32,
- 0x41, 0x1F, 0xF5, 0x1D, 0x04, 0x71, 0xFE, 0x71, 0x00, 0xFB, 0xFF,
- 0xF0, 0xFF, 0x05, 0x00, 0x05, 0x00, 0xF2, 0xFF, 0xF8, 0xFF, 0x77,
- 0x00, 0x67, 0xFE, 0x2D, 0x04, 0x04, 0xF5, 0x07, 0x41, 0x1B, 0x1B,
- 0xA6, 0xF4, 0x5A, 0x06, 0x67, 0xFC, 0xDB, 0x01, 0x38, 0xFF, 0x36,
- 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x31, 0x00, 0x46, 0xFF, 0xB3, 0x01,
- 0xCF, 0xFC, 0x67, 0x05, 0xEA, 0xF6, 0x44, 0x13, 0x1E, 0x45, 0x5E,
- 0xF8, 0x3F, 0x02, 0x8E, 0xFF, 0xD0, 0xFF, 0x4A, 0x00, 0xD2, 0xFF,
- 0x0B, 0x00, 0x01, 0x00, 0x0B, 0x00, 0xB4, 0xFF, 0x00, 0x01, 0x7E,
- 0xFD, 0x9C, 0x05, 0xDC, 0xF2, 0xE4, 0x3B, 0xCD, 0x22, 0xEE, 0xF2,
- 0xF3, 0x06, 0x35, 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0x00, 0x00, 0x2A, 0x00, 0x5D, 0xFF, 0x76, 0x01, 0x59, 0xFD,
- 0x42, 0x04, 0x63, 0xF9, 0x1C, 0x0C, 0xB6, 0x47, 0xA4, 0xFC, 0x07,
- 0x00, 0xD0, 0x00, 0x20, 0xFF, 0xA0, 0x00, 0xB1, 0xFF, 0x13, 0x00,
- 0xFE, 0xFF, 0x1F, 0x00, 0x7D, 0xFF, 0x6B, 0x01, 0xCF, 0xFC, 0x96,
- 0x06, 0xB7, 0xF1, 0xC6, 0x35, 0x64, 0x2A, 0xD4, 0xF1, 0x2B, 0x07,
- 0x3D, 0xFC, 0xD2, 0x01, 0x45, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x00,
- 0x00, 0x21, 0x00, 0x7A, 0xFF, 0x2B, 0x01, 0xFE, 0xFD, 0xF8, 0x02,
- 0xFB, 0xFB, 0x8D, 0x05, 0xE5, 0x48, 0xE3, 0x01, 0x91, 0xFD, 0x25,
- 0x02, 0x6B, 0xFE, 0xF7, 0x00, 0x8F, 0xFF, 0x1C, 0x00, 0xFD, 0xFF,
- 0x2D, 0x00, 0x55, 0xFF, 0xB5, 0x01, 0x61, 0xFC, 0x16, 0x07, 0x85,
- 0xF1, 0xE6, 0x2E, 0x9E, 0x31, 0x7D, 0xF1, 0xF3, 0x06, 0x84, 0xFC,
- 0x9D, 0x01, 0x63, 0xFF, 0x28, 0x00, 0xFD, 0xFF, 0x18, 0x00, 0x9C,
- 0xFF, 0xD6, 0x00, 0xB1, 0xFE, 0xA1, 0x01, 0x89, 0xFE, 0xC3, 0xFF,
- 0x9C, 0x48, 0xFD, 0x07, 0xFA, 0xFA, 0x7A, 0x03, 0xBC, 0xFD, 0x49,
- 0x01, 0x6E, 0xFF, 0x24, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x34, 0x00,
- 0x3E, 0xFF, 0xDE, 0x01, 0x33, 0xFC, 0x22, 0x07, 0x2B, 0xF2, 0x80,
- 0x27, 0x3B, 0x38, 0x0A, 0xF2, 0x44, 0x06, 0x0B, 0xFD, 0x45, 0x01,
- 0x90, 0xFF, 0x18, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0xBE, 0xFF, 0x7F,
- 0x00, 0x65, 0xFF, 0x51, 0x00, 0xEB, 0x00, 0xE1, 0xFA, 0xE1, 0x46,
- 0xCD, 0x0E, 0x6A, 0xF8, 0xB8, 0x04, 0x20, 0xFD, 0x90, 0x01, 0x53,
- 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF,
- 0xE5, 0x01, 0x42, 0xFC, 0xC3, 0x06, 0x87, 0xF3, 0xD7, 0x1F, 0xFE,
- 0x3D, 0x91, 0xF3, 0x1D, 0x05, 0xD1, 0xFD, 0xCE, 0x00, 0xCC, 0xFF,
- 0x02, 0x00, 0x02, 0x00, 0x09, 0x00, 0xDE, 0xFF, 0x2B, 0x00, 0x11,
- 0x00, 0x1B, 0xFF, 0x02, 0x03, 0xFE, 0xF6, 0xC3, 0x43, 0x22, 0x16,
- 0x07, 0xF6, 0xCA, 0x05, 0xA3, 0xFC, 0xC5, 0x01, 0x3F, 0xFF, 0x33,
- 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x34, 0x00, 0x3C, 0xFF, 0xCF, 0x01,
- 0x88, 0xFC, 0x09, 0x06, 0x71, 0xF5, 0x2B, 0x18, 0xB2, 0x42, 0x20,
- 0xF6, 0x83, 0x03, 0xCF, 0xFE, 0x3C, 0x00, 0x15, 0x00, 0xE6, 0xFF,
- 0x07, 0x00, 0x03, 0x00, 0xFB, 0xFF, 0xDF, 0xFF, 0xA9, 0x00, 0x10,
- 0xFE, 0xB9, 0x04, 0x27, 0xF4, 0x5E, 0x3F, 0xC3, 0x1D, 0xFE, 0xF3,
- 0x99, 0x06, 0x50, 0xFC, 0xE2, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE,
- 0xFF, 0xFF, 0xFF, 0x2F, 0x00, 0x4D, 0xFF, 0xA0, 0x01, 0xFB, 0xFC,
- 0x07, 0x05, 0xBF, 0xF7, 0xBB, 0x10, 0x2B, 0x46, 0xBB, 0xF9, 0x83,
- 0x01, 0xFA, 0xFF, 0x95, 0xFF, 0x68, 0x00, 0xC7, 0xFF, 0x0E, 0x00,
- 0x00, 0x00, 0x13, 0x00, 0x9F, 0xFF, 0x28, 0x01, 0x3A, 0xFD, 0x00,
- 0x06, 0x5A, 0xF2, 0xDF, 0x39, 0x73, 0x25, 0x79, 0xF2, 0x12, 0x07,
- 0x31, 0xFC, 0xE3, 0x01, 0x3B, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x00,
- 0x00, 0x27, 0x00, 0x66, 0xFF, 0x5E, 0x01, 0x90, 0xFD, 0xD2, 0x03,
- 0x47, 0xFA, 0xC3, 0x09, 0x48, 0x48, 0x5A, 0xFE, 0x33, 0xFF, 0x45,
- 0x01, 0xE2, 0xFE, 0xBE, 0x00, 0xA5, 0xFF, 0x16, 0x00, 0xFD, 0xFF,
- 0x24, 0x00, 0x6D, 0xFF, 0x88, 0x01, 0xA2, 0xFC, 0xD0, 0x06, 0x8C,
- 0xF1, 0x78, 0x33, 0xF2, 0x2C, 0x9E, 0xF1, 0x24, 0x07, 0x4E, 0xFC,
- 0xC3, 0x01, 0x4E, 0xFF, 0x2F, 0x00, 0xFD, 0xFF, 0x1E, 0x00, 0x86,
- 0xFF, 0x0E, 0x01, 0x3B, 0xFE, 0x82, 0x02, 0xE0, 0xFC, 0x73, 0x03,
- 0xF6, 0x48, 0xE9, 0x03, 0xAD, 0xFC, 0x9C, 0x02, 0x2D, 0xFE, 0x14,
- 0x01, 0x83, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x30, 0x00,
- 0x4C, 0xFF, 0xC7, 0x01, 0x4A, 0xFC, 0x27, 0x07, 0xA8, 0xF1, 0x62,
- 0x2C, 0xFD, 0x33, 0x93, 0xF1, 0xC4, 0x06, 0xAB, 0xFC, 0x82, 0x01,
- 0x71, 0xFF, 0x23, 0x00, 0xFE, 0xFF, 0x15, 0x00, 0xA8, 0xFF, 0xB8,
- 0x00, 0xF0, 0xFE, 0x2B, 0x01, 0x63, 0xFF, 0xF6, 0xFD, 0x2C, 0x48,
- 0x47, 0x0A, 0x14, 0xFA, 0xEB, 0x03, 0x84, 0xFD, 0x63, 0x01, 0x64,
- 0xFF, 0x27, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x3A, 0xFF,
- 0xE4, 0x01, 0x32, 0xFC, 0x0C, 0x07, 0x91, 0xF2, 0xDD, 0x24, 0x54,
- 0x3A, 0x74, 0xF2, 0xEB, 0x05, 0x49, 0xFD, 0x20, 0x01, 0xA3, 0xFF,
- 0x11, 0x00, 0x00, 0x00, 0x0D, 0x00, 0xC9, 0xFF, 0x61, 0x00, 0xA2,
- 0xFF, 0xE2, 0xFF, 0xAE, 0x01, 0x6B, 0xF9, 0xF2, 0x45, 0x4A, 0x11,
- 0x8F, 0xF7, 0x1D, 0x05, 0xF1, 0xFC, 0xA4, 0x01, 0x4B, 0xFF, 0x2F,
- 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE1, 0x01,
- 0x55, 0xFC, 0x8C, 0x06, 0x22, 0xF4, 0x2C, 0x1D, 0xC0, 0x3F, 0x55,
- 0xF4, 0x9B, 0x04, 0x23, 0xFE, 0x9F, 0x00, 0xE4, 0xFF, 0xF9, 0xFF,
- 0x04, 0x00, 0x07, 0x00, 0xE9, 0xFF, 0x0F, 0x00, 0x48, 0x00, 0xB9,
- 0xFE, 0xA6, 0x03, 0xE4, 0xF5, 0x60, 0x42, 0xC1, 0x18, 0x47, 0xF5,
- 0x1A, 0x06, 0x81, 0xFC, 0xD2, 0x01, 0x3B, 0xFF, 0x35, 0x00, 0xFE,
- 0xFF, 0xFF, 0xFF, 0x33, 0x00, 0x40, 0xFF, 0xC1, 0x01, 0xAB, 0xFC,
- 0xB7, 0x05, 0x34, 0xF6, 0x8E, 0x15, 0x0B, 0x44, 0x42, 0xF7, 0xDC,
- 0x02, 0x32, 0xFF, 0x04, 0x00, 0x31, 0x00, 0xDC, 0xFF, 0x09, 0x00,
- 0x02, 0x00, 0x04, 0x00, 0xC7, 0xFF, 0xD9, 0x00, 0xBF, 0xFD, 0x38,
- 0x05, 0x69, 0xF3, 0x96, 0x3D, 0x6F, 0x20, 0x66, 0xF3, 0xCE, 0x06,
- 0x3F, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFF,
- 0xFF, 0x2C, 0x00, 0x55, 0xFF, 0x8B, 0x01, 0x2B, 0xFD, 0xA1, 0x04,
- 0x9B, 0xF8, 0x42, 0x0E, 0x0F, 0x47, 0x38, 0xFB, 0xBE, 0x00, 0x6A,
- 0x00, 0x58, 0xFF, 0x85, 0x00, 0xBB, 0xFF, 0x10, 0x00, 0xFF, 0xFF,
- 0x19, 0x00, 0x8C, 0xFF, 0x4D, 0x01, 0xFE, 0xFC, 0x56, 0x06, 0xF7,
- 0xF1, 0xBF, 0x37, 0x15, 0x28, 0x18, 0xF2, 0x25, 0x07, 0x34, 0xFC,
- 0xDC, 0x01, 0x3F, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x24,
- 0x00, 0x71, 0xFF, 0x43, 0x01, 0xC9, 0xFD, 0x60, 0x03, 0x2E, 0xFB,
- 0x7E, 0x07, 0xAF, 0x48, 0x2D, 0x00, 0x58, 0xFE, 0xBB, 0x01, 0xA3,
- 0xFE, 0xDD, 0x00, 0x99, 0xFF, 0x19, 0x00, 0xFD, 0xFF, 0x29, 0x00,
- 0x60, 0xFF, 0xA2, 0x01, 0x7C, 0xFC, 0xFB, 0x06, 0x7C, 0xF1, 0x15,
- 0x31, 0x73, 0x2F, 0x81, 0xF1, 0x10, 0x07, 0x67, 0xFC, 0xB1, 0x01,
- 0x58, 0xFF, 0x2C, 0x00, 0xFD, 0xFF, 0x1B, 0x00, 0x91, 0xFF, 0xF1,
- 0x00, 0x79, 0xFE, 0x0A, 0x02, 0xC3, 0xFD, 0x73, 0x01, 0xDB, 0x48,
- 0x07, 0x06, 0xC7, 0xFB, 0x12, 0x03, 0xF1, 0xFD, 0x31, 0x01, 0x78,
- 0xFF, 0x22, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x44, 0xFF,
- 0xD5, 0x01, 0x3A, 0xFC, 0x2A, 0x07, 0xE3, 0xF1, 0xD1, 0x29, 0x46,
- 0x36, 0xC5, 0xF1, 0x87, 0x06, 0xDA, 0xFC, 0x64, 0x01, 0x80, 0xFF,
- 0x1E, 0x00, 0xFE, 0xFF, 0x12, 0x00, 0xB3, 0xFF, 0x99, 0x00, 0x2E,
- 0xFF, 0xB6, 0x00, 0x36, 0x00, 0x47, 0xFC, 0x90, 0x47, 0xA4, 0x0C,
- 0x31, 0xF9, 0x5A, 0x04, 0x4E, 0xFD, 0x7C, 0x01, 0x5B, 0xFF, 0x2A,
- 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01,
- 0x37, 0xFC, 0xEB, 0x06, 0x0B, 0xF3, 0x35, 0x22, 0x52, 0x3C, 0xFD,
- 0xF2, 0x84, 0x05, 0x8D, 0xFD, 0xF6, 0x00, 0xB8, 0xFF, 0x09, 0x00,
- 0x01, 0x00, 0x0B, 0x00, 0xD5, 0xFF, 0x44, 0x00, 0xDD, 0xFF, 0x77,
- 0xFF, 0x67, 0x02, 0x14, 0xF8, 0xDC, 0x44, 0xD5, 0x13, 0xBC, 0xF6,
- 0x7C, 0x05, 0xC5, 0xFC, 0xB7, 0x01, 0x44, 0xFF, 0x31, 0x00, 0xFF,
- 0xFF, 0xFE, 0xFF, 0x35, 0x00, 0x39, 0xFF, 0xD9, 0x01, 0x6D, 0xFC,
- 0x4B, 0x06, 0xCD, 0xF4, 0x83, 0x1A, 0x5F, 0x41, 0x3A, 0xF5, 0x0C,
- 0x04, 0x7B, 0xFE, 0x6C, 0x00, 0xFE, 0xFF, 0xEF, 0xFF, 0x05, 0x00,
- 0x05, 0x00, 0xF3, 0xFF, 0xF5, 0xFF, 0x7D, 0x00, 0x5D, 0xFE, 0x3E,
- 0x04, 0xEA, 0xF4, 0xD9, 0x40, 0x66, 0x1B, 0x93, 0xF4, 0x62, 0x06,
- 0x64, 0xFC, 0xDC, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF,
- 0xFF, 0x31, 0x00, 0x46, 0xFF, 0xB1, 0x01, 0xD3, 0xFC, 0x5D, 0x05,
- 0x01, 0xF7, 0xFB, 0x12, 0x3F, 0x45, 0x83, 0xF8, 0x2A, 0x02, 0x9A,
- 0xFF, 0xCA, 0xFF, 0x4E, 0x00, 0xD1, 0xFF, 0x0C, 0x00, 0x00, 0x00,
- 0x0C, 0x00, 0xB1, 0xFF, 0x04, 0x01, 0x76, 0xFD, 0xA8, 0x05, 0xCC,
- 0xF2, 0xAB, 0x3B, 0x18, 0x23, 0xE0, 0xF2, 0xF7, 0x06, 0x35, 0xFC,
- 0xE6, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x29,
- 0x00, 0x5E, 0xFF, 0x74, 0x01, 0x5F, 0xFD, 0x35, 0x04, 0x7C, 0xF9,
- 0xD8, 0x0B, 0xC9, 0x47, 0xD4, 0xFC, 0xF0, 0xFF, 0xDD, 0x00, 0x19,
- 0xFF, 0xA4, 0x00, 0xAF, 0xFF, 0x13, 0x00, 0xFE, 0xFF, 0x20, 0x00,
- 0x7B, 0xFF, 0x6E, 0x01, 0xCA, 0xFC, 0x9D, 0x06, 0xB1, 0xF1, 0x86,
- 0x35, 0xAE, 0x2A, 0xCD, 0xF1, 0x2B, 0x07, 0x3F, 0xFC, 0xD1, 0x01,
- 0x46, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x21, 0x00, 0x7C,
- 0xFF, 0x27, 0x01, 0x05, 0xFE, 0xEB, 0x02, 0x14, 0xFC, 0x50, 0x05,
- 0xEA, 0x48, 0x1B, 0x02, 0x78, 0xFD, 0x32, 0x02, 0x64, 0xFE, 0xFA,
- 0x00, 0x8D, 0xFF, 0x1C, 0x00, 0xFD, 0xFF, 0x2D, 0x00, 0x54, 0xFF,
- 0xB7, 0x01, 0x5E, 0xFC, 0x19, 0x07, 0x88, 0xF1, 0x9F, 0x2E, 0xE3,
- 0x31, 0x7E, 0xF1, 0xEE, 0x06, 0x88, 0xFC, 0x9A, 0x01, 0x64, 0xFF,
- 0x28, 0x00, 0xFD, 0xFF, 0x18, 0x00, 0x9D, 0xFF, 0xD3, 0x00, 0xB8,
- 0xFE, 0x93, 0x01, 0xA1, 0xFE, 0x8E, 0xFF, 0x92, 0x48, 0x3D, 0x08,
- 0xE1, 0xFA, 0x86, 0x03, 0xB6, 0xFD, 0x4C, 0x01, 0x6D, 0xFF, 0x25,
- 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x34, 0x00, 0x3E, 0xFF, 0xDF, 0x01,
- 0x33, 0xFC, 0x20, 0x07, 0x35, 0xF2, 0x36, 0x27, 0x78, 0x38, 0x14,
- 0xF2, 0x3B, 0x06, 0x11, 0xFD, 0x41, 0x01, 0x92, 0xFF, 0x17, 0x00,
- 0xFF, 0xFF, 0x10, 0x00, 0xBF, 0xFF, 0x7B, 0x00, 0x6C, 0xFF, 0x44,
- 0x00, 0x01, 0x01, 0xB6, 0xFA, 0xC8, 0x46, 0x13, 0x0F, 0x51, 0xF8,
- 0xC4, 0x04, 0x1B, 0xFD, 0x92, 0x01, 0x52, 0xFF, 0x2D, 0x00, 0xFF,
- 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE5, 0x01, 0x44, 0xFC,
- 0xBD, 0x06, 0x97, 0xF3, 0x8A, 0x1F, 0x31, 0x3E, 0xA5, 0xF3, 0x0F,
- 0x05, 0xDA, 0xFD, 0xC9, 0x00, 0xCF, 0xFF, 0x01, 0x00, 0x02, 0x00,
- 0x09, 0x00, 0xDF, 0xFF, 0x28, 0x00, 0x17, 0x00, 0x10, 0xFF, 0x15,
- 0x03, 0xDD, 0xF6, 0x9E, 0x43, 0x6C, 0x16, 0xF1, 0xF5, 0xD3, 0x05,
- 0x9F, 0xFC, 0xC6, 0x01, 0x3F, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0xFE,
- 0xFF, 0x34, 0x00, 0x3C, 0xFF, 0xCE, 0x01, 0x8C, 0xFC, 0x00, 0x06,
- 0x86, 0xF5, 0xE0, 0x17, 0xDB, 0x42, 0x3F, 0xF6, 0x71, 0x03, 0xD9,
- 0xFE, 0x36, 0x00, 0x18, 0x00, 0xE5, 0xFF, 0x07, 0x00, 0x03, 0x00,
- 0xFC, 0xFF, 0xDC, 0xFF, 0xAF, 0x00, 0x07, 0xFE, 0xC8, 0x04, 0x10,
- 0xF4, 0x2D, 0x3F, 0x0F, 0x1E, 0xED, 0xF3, 0xA0, 0x06, 0x4E, 0xFC,
- 0xE3, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x2E,
- 0x00, 0x4E, 0xFF, 0x9E, 0x01, 0x00, 0xFD, 0xFC, 0x04, 0xD7, 0xF7,
- 0x75, 0x10, 0x48, 0x46, 0xE4, 0xF9, 0x6E, 0x01, 0x06, 0x00, 0x8E,
- 0xFF, 0x6B, 0x00, 0xC6, 0xFF, 0x0E, 0x00, 0xFF, 0xFF, 0x13, 0x00,
- 0x9D, 0xFF, 0x2D, 0x01, 0x33, 0xFD, 0x0B, 0x06, 0x4D, 0xF2, 0xA5,
- 0x39, 0xBF, 0x25, 0x6D, 0xF2, 0x15, 0x07, 0x31, 0xFC, 0xE2, 0x01,
- 0x3B, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x26, 0x00, 0x68,
- 0xFF, 0x5B, 0x01, 0x96, 0xFD, 0xC6, 0x03, 0x61, 0xFA, 0x81, 0x09,
- 0x57, 0x48, 0x8D, 0xFE, 0x1B, 0xFF, 0x52, 0x01, 0xDB, 0xFE, 0xC2,
- 0x00, 0xA4, 0xFF, 0x16, 0x00, 0xFD, 0xFF, 0x25, 0x00, 0x6C, 0xFF,
- 0x8B, 0x01, 0x9D, 0xFC, 0xD5, 0x06, 0x89, 0xF1, 0x35, 0x33, 0x3A,
- 0x2D, 0x9A, 0xF1, 0x23, 0x07, 0x51, 0xFC, 0xC2, 0x01, 0x4F, 0xFF,
- 0x2F, 0x00, 0xFD, 0xFF, 0x1E, 0x00, 0x87, 0xFF, 0x0B, 0x01, 0x42,
- 0xFE, 0x74, 0x02, 0xF9, 0xFC, 0x39, 0x03, 0xF5, 0x48, 0x24, 0x04,
- 0x94, 0xFC, 0xA9, 0x02, 0x27, 0xFE, 0x18, 0x01, 0x82, 0xFF, 0x1F,
- 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x30, 0x00, 0x4B, 0xFF, 0xC9, 0x01,
- 0x48, 0xFC, 0x28, 0x07, 0xAD, 0xF1, 0x19, 0x2C, 0x3F, 0x34, 0x97,
- 0xF1, 0xBE, 0x06, 0xB0, 0xFC, 0x7F, 0x01, 0x72, 0xFF, 0x23, 0x00,
- 0xFE, 0xFF, 0x15, 0x00, 0xA9, 0xFF, 0xB4, 0x00, 0xF7, 0xFE, 0x1D,
- 0x01, 0x7A, 0xFF, 0xC5, 0xFD, 0x1D, 0x48, 0x89, 0x0A, 0xFB, 0xF9,
- 0xF8, 0x03, 0x7D, 0xFD, 0x66, 0x01, 0x63, 0xFF, 0x28, 0x00, 0x00,
- 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x39, 0xFF, 0xE4, 0x01, 0x32, 0xFC,
- 0x09, 0x07, 0x9D, 0xF2, 0x92, 0x24, 0x8F, 0x3A, 0x82, 0xF2, 0xE1,
- 0x05, 0x50, 0xFD, 0x1B, 0x01, 0xA6, 0xFF, 0x10, 0x00, 0x00, 0x00,
- 0x0D, 0x00, 0xCB, 0xFF, 0x5E, 0x00, 0xA9, 0xFF, 0xD6, 0xFF, 0xC3,
- 0x01, 0x43, 0xF9, 0xD7, 0x45, 0x92, 0x11, 0x77, 0xF7, 0x28, 0x05,
- 0xEC, 0xFC, 0xA7, 0x01, 0x4A, 0xFF, 0x2F, 0x00, 0xFF, 0xFF, 0xFE,
- 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE0, 0x01, 0x57, 0xFC, 0x85, 0x06,
- 0x34, 0xF4, 0xE0, 0x1C, 0xF0, 0x3F, 0x6D, 0xF4, 0x8C, 0x04, 0x2C,
- 0xFE, 0x99, 0x00, 0xE7, 0xFF, 0xF8, 0xFF, 0x04, 0x00, 0x06, 0x00,
- 0xEA, 0xFF, 0x0C, 0x00, 0x4E, 0x00, 0xAF, 0xFE, 0xB8, 0x03, 0xC7,
- 0xF5, 0x38, 0x42, 0x0C, 0x19, 0x32, 0xF5, 0x23, 0x06, 0x7D, 0xFC,
- 0xD3, 0x01, 0x3A, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x32,
- 0x00, 0x41, 0xFF, 0xC0, 0x01, 0xAF, 0xFC, 0xAD, 0x05, 0x4A, 0xF6,
- 0x44, 0x15, 0x2F, 0x44, 0x64, 0xF7, 0xC9, 0x02, 0x3D, 0xFF, 0xFE,
- 0xFF, 0x34, 0x00, 0xDB, 0xFF, 0x09, 0x00, 0x02, 0x00, 0x05, 0x00,
- 0xC5, 0xFF, 0xDE, 0x00, 0xB7, 0xFD, 0x45, 0x05, 0x56, 0xF3, 0x61,
- 0x3D, 0xBA, 0x20, 0x56, 0xF3, 0xD3, 0x06, 0x3E, 0xFC, 0xE6, 0x01,
- 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x2C, 0x00, 0x56,
- 0xFF, 0x88, 0x01, 0x31, 0xFD, 0x95, 0x04, 0xB4, 0xF8, 0xFC, 0x0D,
- 0x26, 0x47, 0x64, 0xFB, 0xA7, 0x00, 0x77, 0x00, 0x51, 0xFF, 0x89,
- 0x00, 0xBA, 0xFF, 0x11, 0x00, 0xFF, 0xFF, 0x1A, 0x00, 0x8A, 0xFF,
- 0x51, 0x01, 0xF8, 0xFC, 0x5E, 0x06, 0xED, 0xF1, 0x82, 0x37, 0x60,
- 0x28, 0x0E, 0xF2, 0x26, 0x07, 0x35, 0xFC, 0xDB, 0x01, 0x40, 0xFF,
- 0x34, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x23, 0x00, 0x72, 0xFF, 0x40,
- 0x01, 0xD0, 0xFD, 0x53, 0x03, 0x47, 0xFB, 0x3F, 0x07, 0xB8, 0x48,
- 0x62, 0x00, 0x3F, 0xFE, 0xC8, 0x01, 0x9C, 0xFE, 0xE0, 0x00, 0x98,
- 0xFF, 0x19, 0x00, 0xFD, 0xFF, 0x29, 0x00, 0x5F, 0xFF, 0xA5, 0x01,
- 0x78, 0xFC, 0xFF, 0x06, 0x7D, 0xF1, 0xCF, 0x30, 0xB8, 0x2F, 0x80,
- 0xF1, 0x0D, 0x07, 0x6A, 0xFC, 0xAE, 0x01, 0x59, 0xFF, 0x2B, 0x00,
- 0xFD, 0xFF, 0x1B, 0x00, 0x93, 0xFF, 0xED, 0x00, 0x80, 0xFE, 0xFD,
- 0x01, 0xDC, 0xFD, 0x3C, 0x01, 0xD5, 0x48, 0x45, 0x06, 0xAE, 0xFB,
- 0x1F, 0x03, 0xEA, 0xFD, 0x34, 0x01, 0x77, 0xFF, 0x22, 0x00, 0x00,
- 0x00, 0xFD, 0xFF, 0x33, 0x00, 0x43, 0xFF, 0xD6, 0x01, 0x39, 0xFC,
- 0x2A, 0x07, 0xEB, 0xF1, 0x87, 0x29, 0x85, 0x36, 0xCC, 0xF1, 0x7F,
- 0x06, 0xE0, 0xFC, 0x60, 0x01, 0x82, 0xFF, 0x1D, 0x00, 0xFE, 0xFF,
- 0x12, 0x00, 0xB5, 0xFF, 0x96, 0x00, 0x35, 0xFF, 0xA9, 0x00, 0x4D,
- 0x00, 0x19, 0xFC, 0x7C, 0x47, 0xE8, 0x0C, 0x18, 0xF9, 0x66, 0x04,
- 0x48, 0xFD, 0x7E, 0x01, 0x5A, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0xFD,
- 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x38, 0xFC, 0xE6, 0x06,
- 0x19, 0xF3, 0xEA, 0x21, 0x8A, 0x3C, 0x0E, 0xF3, 0x78, 0x05, 0x96,
- 0xFD, 0xF1, 0x00, 0xBB, 0xFF, 0x08, 0x00, 0x01, 0x00, 0x0B, 0x00,
- 0xD6, 0xFF, 0x41, 0x00, 0xE4, 0xFF, 0x6B, 0xFF, 0x7B, 0x02, 0xF0,
- 0xF7, 0xBA, 0x44, 0x1E, 0x14, 0xA5, 0xF6, 0x86, 0x05, 0xC1, 0xFC,
- 0xB9, 0x01, 0x44, 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x35,
- 0x00, 0x39, 0xFF, 0xD8, 0x01, 0x70, 0xFC, 0x43, 0x06, 0xE1, 0xF4,
- 0x38, 0x1A, 0x8C, 0x41, 0x55, 0xF5, 0xFC, 0x03, 0x85, 0xFE, 0x66,
- 0x00, 0x01, 0x00, 0xEE, 0xFF, 0x06, 0x00, 0x05, 0x00, 0xF4, 0xFF,
- 0xF2, 0xFF, 0x83, 0x00, 0x53, 0xFE, 0x4E, 0x04, 0xD0, 0xF4, 0xAB,
- 0x40, 0xB2, 0x1B, 0x7F, 0xF4, 0x69, 0x06, 0x62, 0xFC, 0xDD, 0x01,
- 0x38, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x30, 0x00, 0x47,
- 0xFF, 0xAF, 0x01, 0xD8, 0xFC, 0x52, 0x05, 0x19, 0xF7, 0xB2, 0x12,
- 0x5C, 0x45, 0xA9, 0xF8, 0x16, 0x02, 0xA6, 0xFF, 0xC3, 0xFF, 0x51,
- 0x00, 0xD0, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x0D, 0x00, 0xAF, 0xFF,
- 0x09, 0x01, 0x6E, 0xFD, 0xB4, 0x05, 0xBC, 0xF2, 0x73, 0x3B, 0x64,
- 0x23, 0xD2, 0xF2, 0xFB, 0x06, 0x34, 0xFC, 0xE6, 0x01, 0x38, 0xFF,
- 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x29, 0x00, 0x5F, 0xFF, 0x71,
- 0x01, 0x65, 0xFD, 0x29, 0x04, 0x96, 0xF9, 0x95, 0x0B, 0xDC, 0x47,
- 0x03, 0xFD, 0xD9, 0xFF, 0xEA, 0x00, 0x12, 0xFF, 0xA7, 0x00, 0xAE,
- 0xFF, 0x14, 0x00, 0xFE, 0xFF, 0x20, 0x00, 0x79, 0xFF, 0x72, 0x01,
- 0xC4, 0xFC, 0xA4, 0x06, 0xAB, 0xF1, 0x46, 0x35, 0xF7, 0x2A, 0xC6,
- 0xF1, 0x2A, 0x07, 0x40, 0xFC, 0xCF, 0x01, 0x47, 0xFF, 0x31, 0x00,
- 0xFD, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x7D, 0xFF, 0x24, 0x01, 0x0C,
- 0xFE, 0xDE, 0x02, 0x2E, 0xFC, 0x13, 0x05, 0xEC, 0x48, 0x54, 0x02,
- 0x5E, 0xFD, 0x3F, 0x02, 0x5D, 0xFE, 0xFE, 0x00, 0x8C, 0xFF, 0x1C,
- 0x00, 0xFD, 0xFF, 0x2D, 0x00, 0x53, 0xFF, 0xBA, 0x01, 0x5B, 0xFC,
- 0x1B, 0x07, 0x8B, 0xF1, 0x58, 0x2E, 0x26, 0x32, 0x80, 0xF1, 0xEA,
- 0x06, 0x8C, 0xFC, 0x97, 0x01, 0x66, 0xFF, 0x27, 0x00, 0xFD, 0xFF,
- 0x17, 0x00, 0x9E, 0xFF, 0xCF, 0x00, 0xBF, 0xFE, 0x86, 0x01, 0xBA,
- 0xFE, 0x5A, 0xFF, 0x86, 0x48, 0x7D, 0x08, 0xC7, 0xFA, 0x93, 0x03,
- 0xB0, 0xFD, 0x4F, 0x01, 0x6C, 0xFF, 0x25, 0x00, 0x00, 0x00, 0xFD,
- 0xFF, 0x35, 0x00, 0x3D, 0xFF, 0xDF, 0x01, 0x32, 0xFC, 0x1E, 0x07,
- 0x40, 0xF2, 0xEB, 0x26, 0xB5, 0x38, 0x1F, 0xF2, 0x32, 0x06, 0x18,
- 0xFD, 0x3D, 0x01, 0x94, 0xFF, 0x16, 0x00, 0xFF, 0xFF, 0x0F, 0x00,
- 0xC0, 0xFF, 0x78, 0x00, 0x73, 0xFF, 0x38, 0x00, 0x17, 0x01, 0x8B,
- 0xFA, 0xAF, 0x46, 0x59, 0x0F, 0x39, 0xF8, 0xCF, 0x04, 0x15, 0xFD,
- 0x95, 0x01, 0x51, 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x36,
- 0x00, 0x36, 0xFF, 0xE5, 0x01, 0x46, 0xFC, 0xB8, 0x06, 0xA8, 0xF3,
- 0x3F, 0x1F, 0x64, 0x3E, 0xBA, 0xF3, 0x01, 0x05, 0xE2, 0xFD, 0xC4,
- 0x00, 0xD2, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0xE1, 0xFF,
- 0x25, 0x00, 0x1D, 0x00, 0x05, 0xFF, 0x28, 0x03, 0xBD, 0xF6, 0x77,
- 0x43, 0xB6, 0x16, 0xDC, 0xF5, 0xDD, 0x05, 0x9B, 0xFC, 0xC8, 0x01,
- 0x3E, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x34, 0x00, 0x3D,
- 0xFF, 0xCC, 0x01, 0x8F, 0xFC, 0xF8, 0x05, 0x9B, 0xF5, 0x96, 0x17,
- 0x02, 0x43, 0x5E, 0xF6, 0x5F, 0x03, 0xE4, 0xFE, 0x30, 0x00, 0x1B,
- 0x00, 0xE4, 0xFF, 0x08, 0x00, 0x03, 0x00, 0xFD, 0xFF, 0xD9, 0xFF,
- 0xB4, 0x00, 0xFD, 0xFD, 0xD7, 0x04, 0xFA, 0xF3, 0xFC, 0x3E, 0x5B,
- 0x1E, 0xDB, 0xF3, 0xA6, 0x06, 0x4C, 0xFC, 0xE3, 0x01, 0x36, 0xFF,
- 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x2E, 0x00, 0x4E, 0xFF, 0x9C,
- 0x01, 0x05, 0xFD, 0xF1, 0x04, 0xF0, 0xF7, 0x2D, 0x10, 0x61, 0x46,
- 0x0D, 0xFA, 0x58, 0x01, 0x13, 0x00, 0x87, 0xFF, 0x6E, 0x00, 0xC4,
- 0xFF, 0x0E, 0x00, 0xFF, 0xFF, 0x14, 0x00, 0x9B, 0xFF, 0x31, 0x01,
- 0x2C, 0xFD, 0x15, 0x06, 0x41, 0xF2, 0x6A, 0x39, 0x0A, 0x26, 0x61,
- 0xF2, 0x17, 0x07, 0x31, 0xFC, 0xE2, 0x01, 0x3B, 0xFF, 0x35, 0x00,
- 0xFD, 0xFF, 0x00, 0x00, 0x26, 0x00, 0x69, 0xFF, 0x58, 0x01, 0x9D,
- 0xFD, 0xB9, 0x03, 0x7B, 0xFA, 0x40, 0x09, 0x63, 0x48, 0xBF, 0xFE,
- 0x03, 0xFF, 0x5F, 0x01, 0xD4, 0xFE, 0xC5, 0x00, 0xA2, 0xFF, 0x16,
- 0x00, 0xFD, 0xFF, 0x25, 0x00, 0x6A, 0xFF, 0x8E, 0x01, 0x99, 0xFC,
- 0xDB, 0x06, 0x86, 0xF1, 0xF2, 0x32, 0x82, 0x2D, 0x96, 0xF1, 0x21,
- 0x07, 0x53, 0xFC, 0xC0, 0x01, 0x50, 0xFF, 0x2E, 0x00, 0xFD, 0xFF,
- 0x1D, 0x00, 0x88, 0xFF, 0x07, 0x01, 0x49, 0xFE, 0x67, 0x02, 0x13,
- 0xFD, 0xFF, 0x02, 0xF4, 0x48, 0x5F, 0x04, 0x7A, 0xFC, 0xB6, 0x02,
- 0x20, 0xFE, 0x1B, 0x01, 0x81, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFD,
- 0xFF, 0x30, 0x00, 0x4A, 0xFF, 0xCA, 0x01, 0x46, 0xFC, 0x29, 0x07,
- 0xB3, 0xF1, 0xD1, 0x2B, 0x81, 0x34, 0x9C, 0xF1, 0xB8, 0x06, 0xB5,
- 0xFC, 0x7C, 0x01, 0x74, 0xFF, 0x22, 0x00, 0xFE, 0xFF, 0x15, 0x00,
- 0xAA, 0xFF, 0xB1, 0x00, 0xFE, 0xFE, 0x10, 0x01, 0x92, 0xFF, 0x94,
- 0xFD, 0x0D, 0x48, 0xCB, 0x0A, 0xE2, 0xF9, 0x04, 0x04, 0x77, 0xFD,
- 0x69, 0x01, 0x62, 0xFF, 0x28, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36,
- 0x00, 0x39, 0xFF, 0xE5, 0x01, 0x32, 0xFC, 0x06, 0x07, 0xAA, 0xF2,
- 0x46, 0x24, 0xC8, 0x3A, 0x90, 0xF2, 0xD6, 0x05, 0x57, 0xFD, 0x17,
- 0x01, 0xA8, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x0D, 0x00, 0xCC, 0xFF,
- 0x5A, 0x00, 0xAF, 0xFF, 0xCA, 0xFF, 0xD8, 0x01, 0x1C, 0xF9, 0xB8,
- 0x45, 0xDA, 0x11, 0x60, 0xF7, 0x33, 0x05, 0xE7, 0xFC, 0xA9, 0x01,
- 0x4A, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x37,
- 0xFF, 0xDF, 0x01, 0x5A, 0xFC, 0x7E, 0x06, 0x47, 0xF4, 0x94, 0x1C,
- 0x1F, 0x40, 0x85, 0xF4, 0x7D, 0x04, 0x36, 0xFE, 0x93, 0x00, 0xEA,
- 0xFF, 0xF7, 0xFF, 0x04, 0x00, 0x06, 0x00, 0xEB, 0xFF, 0x09, 0x00,
- 0x54, 0x00, 0xA4, 0xFE, 0xC9, 0x03, 0xAA, 0xF5, 0x0C, 0x42, 0x56,
- 0x19, 0x1E, 0xF5, 0x2B, 0x06, 0x7A, 0xFC, 0xD4, 0x01, 0x3A, 0xFF,
- 0x35, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x32, 0x00, 0x42, 0xFF, 0xBE,
- 0x01, 0xB4, 0xFC, 0xA4, 0x05, 0x61, 0xF6, 0xFB, 0x14, 0x53, 0x44,
- 0x86, 0xF7, 0xB6, 0x02, 0x49, 0xFF, 0xF7, 0xFF, 0x37, 0x00, 0xD9,
- 0xFF, 0x0A, 0x00, 0x01, 0x00, 0x06, 0x00, 0xC2, 0xFF, 0xE3, 0x00,
- 0xAE, 0xFD, 0x52, 0x05, 0x44, 0xF3, 0x2A, 0x3D, 0x06, 0x21, 0x47,
- 0xF3, 0xD8, 0x06, 0x3C, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00,
- 0xFD, 0xFF, 0x00, 0x00, 0x2B, 0x00, 0x57, 0xFF, 0x86, 0x01, 0x36,
- 0xFD, 0x89, 0x04, 0xCD, 0xF8, 0xB7, 0x0D, 0x3D, 0x47, 0x91, 0xFB,
- 0x91, 0x00, 0x83, 0x00, 0x4A, 0xFF, 0x8C, 0x00, 0xB9, 0xFF, 0x11,
- 0x00, 0xFE, 0xFF, 0x1B, 0x00, 0x88, 0xFF, 0x55, 0x01, 0xF2, 0xFC,
- 0x67, 0x06, 0xE4, 0xF1, 0x44, 0x37, 0xAA, 0x28, 0x05, 0xF2, 0x27,
- 0x07, 0x36, 0xFC, 0xDA, 0x01, 0x41, 0xFF, 0x33, 0x00, 0xFD, 0xFF,
- 0x00, 0x00, 0x23, 0x00, 0x73, 0xFF, 0x3D, 0x01, 0xD6, 0xFD, 0x46,
- 0x03, 0x61, 0xFB, 0x00, 0x07, 0xBF, 0x48, 0x98, 0x00, 0x26, 0xFE,
- 0xD5, 0x01, 0x95, 0xFE, 0xE3, 0x00, 0x96, 0xFF, 0x1A, 0x00, 0xFD,
- 0xFF, 0x2A, 0x00, 0x5D, 0xFF, 0xA7, 0x01, 0x75, 0xFC, 0x03, 0x07,
- 0x7D, 0xF1, 0x8A, 0x30, 0xFF, 0x2F, 0x7E, 0xF1, 0x0A, 0x07, 0x6E,
- 0xFC, 0xAC, 0x01, 0x5A, 0xFF, 0x2B, 0x00, 0xFD, 0xFF, 0x1A, 0x00,
- 0x94, 0xFF, 0xEA, 0x00, 0x87, 0xFE, 0xF0, 0x01, 0xF5, 0xFD, 0x05,
- 0x01, 0xCE, 0x48, 0x83, 0x06, 0x94, 0xFB, 0x2C, 0x03, 0xE4, 0xFD,
- 0x37, 0x01, 0x76, 0xFF, 0x22, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x33,
- 0x00, 0x42, 0xFF, 0xD7, 0x01, 0x38, 0xFC, 0x29, 0x07, 0xF3, 0xF1,
- 0x3E, 0x29, 0xC6, 0x36, 0xD4, 0xF1, 0x77, 0x06, 0xE6, 0xFC, 0x5C,
- 0x01, 0x84, 0xFF, 0x1C, 0x00, 0xFE, 0xFF, 0x12, 0x00, 0xB6, 0xFF,
- 0x93, 0x00, 0x3C, 0xFF, 0x9D, 0x00, 0x63, 0x00, 0xEB, 0xFB, 0x69,
- 0x47, 0x2D, 0x0D, 0xFF, 0xF8, 0x72, 0x04, 0x42, 0xFD, 0x81, 0x01,
- 0x59, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x37,
- 0xFF, 0xE6, 0x01, 0x3A, 0xFC, 0xE2, 0x06, 0x28, 0xF3, 0x9E, 0x21,
- 0xC0, 0x3C, 0x1F, 0xF3, 0x6C, 0x05, 0x9E, 0xFD, 0xED, 0x00, 0xBD,
- 0xFF, 0x07, 0x00, 0x01, 0x00, 0x0A, 0x00, 0xD7, 0xFF, 0x3E, 0x00,
- 0xEA, 0xFF, 0x60, 0xFF, 0x8F, 0x02, 0xCD, 0xF7, 0x99, 0x44, 0x68,
- 0x14, 0x8E, 0xF6, 0x90, 0x05, 0xBC, 0xFC, 0xBA, 0x01, 0x43, 0xFF,
- 0x32, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x35, 0x00, 0x39, 0xFF, 0xD7,
- 0x01, 0x73, 0xFC, 0x3B, 0x06, 0xF5, 0xF4, 0xED, 0x19, 0xB7, 0x41,
- 0x71, 0xF5, 0xEB, 0x03, 0x90, 0xFE, 0x60, 0x00, 0x04, 0x00, 0xED,
- 0xFF, 0x06, 0x00, 0x04, 0x00, 0xF5, 0xFF, 0xEF, 0xFF, 0x88, 0x00,
- 0x49, 0xFE, 0x5D, 0x04, 0xB7, 0xF4, 0x7D, 0x40, 0xFD, 0x1B, 0x6C,
- 0xF4, 0x70, 0x06, 0x5F, 0xFC, 0xDE, 0x01, 0x37, 0xFF, 0x36, 0x00,
- 0xFE, 0xFF, 0xFF, 0xFF, 0x30, 0x00, 0x48, 0xFF, 0xAD, 0x01, 0xDD,
- 0xFC, 0x48, 0x05, 0x30, 0xF7, 0x6B, 0x12, 0x7D, 0x45, 0xCF, 0xF8,
- 0x01, 0x02, 0xB2, 0xFF, 0xBD, 0xFF, 0x54, 0x00, 0xCE, 0xFF, 0x0C,
- 0x00, 0x00, 0x00, 0x0E, 0x00, 0xAC, 0xFF, 0x0E, 0x01, 0x66, 0xFD,
- 0xBF, 0x05, 0xAD, 0xF2, 0x3B, 0x3B, 0xB0, 0x23, 0xC4, 0xF2, 0xFF,
- 0x06, 0x33, 0xFC, 0xE5, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0x00, 0x00, 0x29, 0x00, 0x60, 0xFF, 0x6E, 0x01, 0x6B, 0xFD, 0x1D,
- 0x04, 0xAF, 0xF9, 0x51, 0x0B, 0xEC, 0x47, 0x33, 0xFD, 0xC1, 0xFF,
- 0xF7, 0x00, 0x0C, 0xFF, 0xAA, 0x00, 0xAD, 0xFF, 0x14, 0x00, 0xFE,
- 0xFF, 0x21, 0x00, 0x77, 0xFF, 0x75, 0x01, 0xBF, 0xFC, 0xAB, 0x06,
- 0xA6, 0xF1, 0x05, 0x35, 0x40, 0x2B, 0xBF, 0xF1, 0x2A, 0x07, 0x42,
- 0xFC, 0xCE, 0x01, 0x48, 0xFF, 0x31, 0x00, 0xFD, 0xFF, 0x00, 0x00,
- 0x20, 0x00, 0x7E, 0xFF, 0x21, 0x01, 0x12, 0xFE, 0xD1, 0x02, 0x47,
- 0xFC, 0xD7, 0x04, 0xF0, 0x48, 0x8D, 0x02, 0x45, 0xFD, 0x4D, 0x02,
- 0x56, 0xFE, 0x01, 0x01, 0x8B, 0xFF, 0x1D, 0x00, 0xFD, 0xFF, 0x2E,
- 0x00, 0x52, 0xFF, 0xBC, 0x01, 0x58, 0xFC, 0x1D, 0x07, 0x8E, 0xF1,
- 0x11, 0x2E, 0x6B, 0x32, 0x81, 0xF1, 0xE5, 0x06, 0x90, 0xFC, 0x94,
- 0x01, 0x67, 0xFF, 0x26, 0x00, 0xFD, 0xFF, 0x17, 0x00, 0xA0, 0xFF,
- 0xCC, 0x00, 0xC6, 0xFE, 0x79, 0x01, 0xD2, 0xFE, 0x26, 0xFF, 0x7C,
- 0x48, 0xBE, 0x08, 0xAE, 0xFA, 0xA0, 0x03, 0xA9, 0xFD, 0x52, 0x01,
- 0x6B, 0xFF, 0x25, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3C,
- 0xFF, 0xE0, 0x01, 0x32, 0xFC, 0x1C, 0x07, 0x4B, 0xF2, 0xA0, 0x26,
- 0xF2, 0x38, 0x2A, 0xF2, 0x28, 0x06, 0x1F, 0xFD, 0x39, 0x01, 0x96,
- 0xFF, 0x16, 0x00, 0xFF, 0xFF, 0x0F, 0x00, 0xC2, 0xFF, 0x75, 0x00,
- 0x7A, 0xFF, 0x2B, 0x00, 0x2D, 0x01, 0x61, 0xFA, 0x97, 0x46, 0xA0,
- 0x0F, 0x20, 0xF8, 0xDA, 0x04, 0x10, 0xFD, 0x97, 0x01, 0x50, 0xFF,
- 0x2E, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE4,
- 0x01, 0x48, 0xFC, 0xB2, 0x06, 0xB9, 0xF3, 0xF3, 0x1E, 0x98, 0x3E,
- 0xCF, 0xF3, 0xF3, 0x04, 0xEB, 0xFD, 0xBF, 0x00, 0xD4, 0xFF, 0xFF,
- 0xFF, 0x03, 0x00, 0x08, 0x00, 0xE2, 0xFF, 0x21, 0x00, 0x23, 0x00,
- 0xFA, 0xFE, 0x3A, 0x03, 0x9D, 0xF6, 0x50, 0x43, 0x00, 0x17, 0xC6,
- 0xF5, 0xE6, 0x05, 0x97, 0xFC, 0xC9, 0x01, 0x3E, 0xFF, 0x34, 0x00,
- 0xFE, 0xFF, 0xFE, 0xFF, 0x34, 0x00, 0x3D, 0xFF, 0xCB, 0x01, 0x93,
- 0xFC, 0xEF, 0x05, 0xB0, 0xF5, 0x4B, 0x17, 0x2A, 0x43, 0x7D, 0xF6,
- 0x4D, 0x03, 0xEF, 0xFE, 0x2A, 0x00, 0x1E, 0x00, 0xE3, 0xFF, 0x08,
- 0x00, 0x03, 0x00, 0xFE, 0xFF, 0xD7, 0xFF, 0xBA, 0x00, 0xF4, 0xFD,
- 0xE5, 0x04, 0xE4, 0xF3, 0xCA, 0x3E, 0xA7, 0x1E, 0xCA, 0xF3, 0xAC,
- 0x06, 0x4A, 0xFC, 0xE4, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF,
- 0xFF, 0xFF, 0x2E, 0x00, 0x4F, 0xFF, 0x99, 0x01, 0x0B, 0xFD, 0xE6,
- 0x04, 0x08, 0xF8, 0xE7, 0x0F, 0x7C, 0x46, 0x37, 0xFA, 0x42, 0x01,
- 0x1F, 0x00, 0x81, 0xFF, 0x71, 0x00, 0xC3, 0xFF, 0x0F, 0x00, 0xFF,
- 0xFF, 0x15, 0x00, 0x98, 0xFF, 0x35, 0x01, 0x25, 0xFD, 0x1E, 0x06,
- 0x35, 0xF2, 0x2E, 0x39, 0x55, 0x26, 0x56, 0xF2, 0x1A, 0x07, 0x31,
- 0xFC, 0xE1, 0x01, 0x3C, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x00, 0x00,
- 0x26, 0x00, 0x6A, 0xFF, 0x55, 0x01, 0xA3, 0xFD, 0xAD, 0x03, 0x94,
- 0xFA, 0xFF, 0x08, 0x70, 0x48, 0xF3, 0xFE, 0xEA, 0xFE, 0x6C, 0x01,
- 0xCD, 0xFE, 0xC9, 0x00, 0xA1, 0xFF, 0x17, 0x00, 0xFD, 0xFF, 0x26,
- 0x00, 0x69, 0xFF, 0x91, 0x01, 0x94, 0xFC, 0xE0, 0x06, 0x84, 0xF1,
- 0xAF, 0x32, 0xCA, 0x2D, 0x92, 0xF1, 0x1F, 0x07, 0x56, 0xFC, 0xBE,
- 0x01, 0x51, 0xFF, 0x2E, 0x00, 0xFD, 0xFF, 0x1D, 0x00, 0x8A, 0xFF,
- 0x04, 0x01, 0x50, 0xFE, 0x5A, 0x02, 0x2C, 0xFD, 0xC6, 0x02, 0xF2,
- 0x48, 0x9B, 0x04, 0x61, 0xFC, 0xC3, 0x02, 0x19, 0xFE, 0x1E, 0x01,
- 0x7F, 0xFF, 0x20, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x31, 0x00, 0x49,
- 0xFF, 0xCC, 0x01, 0x44, 0xFC, 0x29, 0x07, 0xB9, 0xF1, 0x89, 0x2B,
- 0xC3, 0x34, 0xA0, 0xF1, 0xB1, 0x06, 0xBA, 0xFC, 0x79, 0x01, 0x76,
- 0xFF, 0x21, 0x00, 0xFE, 0xFF, 0x14, 0x00, 0xAC, 0xFF, 0xAE, 0x00,
- 0x05, 0xFF, 0x03, 0x01, 0xAA, 0xFF, 0x63, 0xFD, 0xFD, 0x47, 0x0E,
- 0x0B, 0xC8, 0xF9, 0x11, 0x04, 0x71, 0xFD, 0x6C, 0x01, 0x61, 0xFF,
- 0x28, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x39, 0xFF, 0xE5,
- 0x01, 0x33, 0xFC, 0x03, 0x07, 0xB7, 0xF2, 0xFC, 0x23, 0x03, 0x3B,
- 0x9E, 0xF2, 0xCB, 0x05, 0x5F, 0xFD, 0x12, 0x01, 0xAA, 0xFF, 0x0E,
- 0x00, 0x00, 0x00, 0x0C, 0x00, 0xCD, 0xFF, 0x57, 0x00, 0xB6, 0xFF,
- 0xBE, 0xFF, 0xED, 0x01, 0xF5, 0xF8, 0x9B, 0x45, 0x22, 0x12, 0x48,
- 0xF7, 0x3D, 0x05, 0xE2, 0xFC, 0xAB, 0x01, 0x49, 0xFF, 0x30, 0x00,
- 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xDF, 0x01, 0x5C,
- 0xFC, 0x78, 0x06, 0x5A, 0xF4, 0x49, 0x1C, 0x4E, 0x40, 0x9E, 0xF4,
- 0x6D, 0x04, 0x3F, 0xFE, 0x8E, 0x00, 0xED, 0xFF, 0xF6, 0xFF, 0x04,
- 0x00, 0x06, 0x00, 0xEC, 0xFF, 0x06, 0x00, 0x5A, 0x00, 0x9A, 0xFE,
- 0xDA, 0x03, 0x8D, 0xF5, 0xE1, 0x41, 0xA1, 0x19, 0x09, 0xF5, 0x33,
- 0x06, 0x77, 0xFC, 0xD6, 0x01, 0x3A, 0xFF, 0x35, 0x00, 0xFE, 0xFF,
- 0xFF, 0xFF, 0x32, 0x00, 0x42, 0xFF, 0xBC, 0x01, 0xB8, 0xFC, 0x9A,
- 0x05, 0x77, 0xF6, 0xB1, 0x14, 0x77, 0x44, 0xA9, 0xF7, 0xA2, 0x02,
- 0x54, 0xFF, 0xF1, 0xFF, 0x3A, 0x00, 0xD8, 0xFF, 0x0A, 0x00, 0x01,
- 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xE8, 0x00, 0xA6, 0xFD, 0x5F, 0x05,
- 0x31, 0xF3, 0xF6, 0x3C, 0x52, 0x21, 0x37, 0xF3, 0xDD, 0x06, 0x3B,
- 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00,
- 0x2B, 0x00, 0x58, 0xFF, 0x83, 0x01, 0x3C, 0xFD, 0x7E, 0x04, 0xE6,
- 0xF8, 0x72, 0x0D, 0x52, 0x47, 0xBE, 0xFB, 0x7A, 0x00, 0x90, 0x00,
- 0x43, 0xFF, 0x8F, 0x00, 0xB7, 0xFF, 0x11, 0x00, 0xFE, 0xFF, 0x1C,
- 0x00, 0x86, 0xFF, 0x59, 0x01, 0xEC, 0xFC, 0x6F, 0x06, 0xDC, 0xF1,
- 0x04, 0x37, 0xF3, 0x28, 0xFC, 0xF1, 0x28, 0x07, 0x37, 0xFC, 0xD8,
- 0x01, 0x41, 0xFF, 0x33, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x23, 0x00,
- 0x74, 0xFF, 0x3A, 0x01, 0xDD, 0xFD, 0x39, 0x03, 0x7B, 0xFB, 0xC1,
- 0x06, 0xC7, 0x48, 0xCF, 0x00, 0x0D, 0xFE, 0xE3, 0x01, 0x8E, 0xFE,
- 0xE7, 0x00, 0x95, 0xFF, 0x1A, 0x00, 0xFD, 0xFF, 0x2A, 0x00, 0x5C,
- 0xFF, 0xAA, 0x01, 0x71, 0xFC, 0x07, 0x07, 0x7E, 0xF1, 0x44, 0x30,
- 0x44, 0x30, 0x7E, 0xF1, 0x07, 0x07, 0x71, 0xFC, 0xAA, 0x01, 0x5C,
- 0xFF, 0x2A, 0x00, 0xFD, 0xFF, 0x1A, 0x00, 0x95, 0xFF, 0xE7, 0x00,
- 0x8E, 0xFE, 0xE3, 0x01, 0x0D, 0xFE, 0xCF, 0x00, 0xC7, 0x48, 0xC1,
- 0x06, 0x7B, 0xFB, 0x39, 0x03, 0xDD, 0xFD, 0x3A, 0x01, 0x74, 0xFF,
- 0x23, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x33, 0x00, 0x41, 0xFF, 0xD8,
- 0x01, 0x37, 0xFC, 0x28, 0x07, 0xFC, 0xF1, 0xF3, 0x28, 0x04, 0x37,
- 0xDC, 0xF1, 0x6F, 0x06, 0xEC, 0xFC, 0x59, 0x01, 0x86, 0xFF, 0x1C,
- 0x00, 0xFE, 0xFF, 0x11, 0x00, 0xB7, 0xFF, 0x8F, 0x00, 0x43, 0xFF,
- 0x90, 0x00, 0x7A, 0x00, 0xBE, 0xFB, 0x52, 0x47, 0x72, 0x0D, 0xE6,
- 0xF8, 0x7E, 0x04, 0x3C, 0xFD, 0x83, 0x01, 0x58, 0xFF, 0x2B, 0x00,
- 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3B,
- 0xFC, 0xDD, 0x06, 0x37, 0xF3, 0x52, 0x21, 0xF6, 0x3C, 0x31, 0xF3,
- 0x5F, 0x05, 0xA6, 0xFD, 0xE8, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0x01,
- 0x00, 0x0A, 0x00, 0xD8, 0xFF, 0x3A, 0x00, 0xF1, 0xFF, 0x54, 0xFF,
- 0xA2, 0x02, 0xA9, 0xF7, 0x77, 0x44, 0xB1, 0x14, 0x77, 0xF6, 0x9A,
- 0x05, 0xB8, 0xFC, 0xBC, 0x01, 0x42, 0xFF, 0x32, 0x00, 0xFF, 0xFF,
- 0xFE, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xD6, 0x01, 0x77, 0xFC, 0x33,
- 0x06, 0x09, 0xF5, 0xA1, 0x19, 0xE1, 0x41, 0x8D, 0xF5, 0xDA, 0x03,
- 0x9A, 0xFE, 0x5A, 0x00, 0x06, 0x00, 0xEC, 0xFF, 0x06, 0x00, 0x04,
- 0x00, 0xF6, 0xFF, 0xED, 0xFF, 0x8E, 0x00, 0x3F, 0xFE, 0x6D, 0x04,
- 0x9E, 0xF4, 0x4E, 0x40, 0x49, 0x1C, 0x5A, 0xF4, 0x78, 0x06, 0x5C,
- 0xFC, 0xDF, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF,
- 0x30, 0x00, 0x49, 0xFF, 0xAB, 0x01, 0xE2, 0xFC, 0x3D, 0x05, 0x48,
- 0xF7, 0x22, 0x12, 0x9B, 0x45, 0xF5, 0xF8, 0xED, 0x01, 0xBE, 0xFF,
- 0xB6, 0xFF, 0x57, 0x00, 0xCD, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x0E,
- 0x00, 0xAA, 0xFF, 0x12, 0x01, 0x5F, 0xFD, 0xCB, 0x05, 0x9E, 0xF2,
- 0x03, 0x3B, 0xFC, 0x23, 0xB7, 0xF2, 0x03, 0x07, 0x33, 0xFC, 0xE5,
- 0x01, 0x39, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x28, 0x00,
- 0x61, 0xFF, 0x6C, 0x01, 0x71, 0xFD, 0x11, 0x04, 0xC8, 0xF9, 0x0E,
- 0x0B, 0xFD, 0x47, 0x63, 0xFD, 0xAA, 0xFF, 0x03, 0x01, 0x05, 0xFF,
- 0xAE, 0x00, 0xAC, 0xFF, 0x14, 0x00, 0xFE, 0xFF, 0x21, 0x00, 0x76,
- 0xFF, 0x79, 0x01, 0xBA, 0xFC, 0xB1, 0x06, 0xA0, 0xF1, 0xC3, 0x34,
- 0x89, 0x2B, 0xB9, 0xF1, 0x29, 0x07, 0x44, 0xFC, 0xCC, 0x01, 0x49,
- 0xFF, 0x31, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x7F, 0xFF,
- 0x1E, 0x01, 0x19, 0xFE, 0xC3, 0x02, 0x61, 0xFC, 0x9B, 0x04, 0xF2,
- 0x48, 0xC6, 0x02, 0x2C, 0xFD, 0x5A, 0x02, 0x50, 0xFE, 0x04, 0x01,
- 0x8A, 0xFF, 0x1D, 0x00, 0xFD, 0xFF, 0x2E, 0x00, 0x51, 0xFF, 0xBE,
- 0x01, 0x56, 0xFC, 0x1F, 0x07, 0x92, 0xF1, 0xCA, 0x2D, 0xAF, 0x32,
- 0x84, 0xF1, 0xE0, 0x06, 0x94, 0xFC, 0x91, 0x01, 0x69, 0xFF, 0x26,
- 0x00, 0xFD, 0xFF, 0x17, 0x00, 0xA1, 0xFF, 0xC9, 0x00, 0xCD, 0xFE,
- 0x6C, 0x01, 0xEA, 0xFE, 0xF3, 0xFE, 0x70, 0x48, 0xFF, 0x08, 0x94,
- 0xFA, 0xAD, 0x03, 0xA3, 0xFD, 0x55, 0x01, 0x6A, 0xFF, 0x26, 0x00,
- 0x00, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3C, 0xFF, 0xE1, 0x01, 0x31,
- 0xFC, 0x1A, 0x07, 0x56, 0xF2, 0x55, 0x26, 0x2E, 0x39, 0x35, 0xF2,
- 0x1E, 0x06, 0x25, 0xFD, 0x35, 0x01, 0x98, 0xFF, 0x15, 0x00, 0xFF,
- 0xFF, 0x0F, 0x00, 0xC3, 0xFF, 0x71, 0x00, 0x81, 0xFF, 0x1F, 0x00,
- 0x42, 0x01, 0x37, 0xFA, 0x7C, 0x46, 0xE7, 0x0F, 0x08, 0xF8, 0xE6,
- 0x04, 0x0B, 0xFD, 0x99, 0x01, 0x4F, 0xFF, 0x2E, 0x00, 0xFF, 0xFF,
- 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE4, 0x01, 0x4A, 0xFC, 0xAC,
- 0x06, 0xCA, 0xF3, 0xA7, 0x1E, 0xCA, 0x3E, 0xE4, 0xF3, 0xE5, 0x04,
- 0xF4, 0xFD, 0xBA, 0x00, 0xD7, 0xFF, 0xFE, 0xFF, 0x03, 0x00, 0x08,
- 0x00, 0xE3, 0xFF, 0x1E, 0x00, 0x2A, 0x00, 0xEF, 0xFE, 0x4D, 0x03,
- 0x7D, 0xF6, 0x2A, 0x43, 0x4B, 0x17, 0xB0, 0xF5, 0xEF, 0x05, 0x93,
- 0xFC, 0xCB, 0x01, 0x3D, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0xFE, 0xFF,
- 0x34, 0x00, 0x3E, 0xFF, 0xC9, 0x01, 0x97, 0xFC, 0xE6, 0x05, 0xC6,
- 0xF5, 0x00, 0x17, 0x50, 0x43, 0x9D, 0xF6, 0x3A, 0x03, 0xFA, 0xFE,
- 0x23, 0x00, 0x21, 0x00, 0xE2, 0xFF, 0x08, 0x00, 0x03, 0x00, 0xFF,
- 0xFF, 0xD4, 0xFF, 0xBF, 0x00, 0xEB, 0xFD, 0xF3, 0x04, 0xCF, 0xF3,
- 0x98, 0x3E, 0xF3, 0x1E, 0xB9, 0xF3, 0xB2, 0x06, 0x48, 0xFC, 0xE4,
- 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x2E, 0x00,
- 0x50, 0xFF, 0x97, 0x01, 0x10, 0xFD, 0xDA, 0x04, 0x20, 0xF8, 0xA0,
- 0x0F, 0x97, 0x46, 0x61, 0xFA, 0x2D, 0x01, 0x2B, 0x00, 0x7A, 0xFF,
- 0x75, 0x00, 0xC2, 0xFF, 0x0F, 0x00, 0xFF, 0xFF, 0x16, 0x00, 0x96,
- 0xFF, 0x39, 0x01, 0x1F, 0xFD, 0x28, 0x06, 0x2A, 0xF2, 0xF2, 0x38,
- 0xA0, 0x26, 0x4B, 0xF2, 0x1C, 0x07, 0x32, 0xFC, 0xE0, 0x01, 0x3C,
- 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x25, 0x00, 0x6B, 0xFF,
- 0x52, 0x01, 0xA9, 0xFD, 0xA0, 0x03, 0xAE, 0xFA, 0xBE, 0x08, 0x7C,
- 0x48, 0x26, 0xFF, 0xD2, 0xFE, 0x79, 0x01, 0xC6, 0xFE, 0xCC, 0x00,
- 0xA0, 0xFF, 0x17, 0x00, 0xFD, 0xFF, 0x26, 0x00, 0x67, 0xFF, 0x94,
- 0x01, 0x90, 0xFC, 0xE5, 0x06, 0x81, 0xF1, 0x6B, 0x32, 0x11, 0x2E,
- 0x8E, 0xF1, 0x1D, 0x07, 0x58, 0xFC, 0xBC, 0x01, 0x52, 0xFF, 0x2E,
- 0x00, 0xFD, 0xFF, 0x1D, 0x00, 0x8B, 0xFF, 0x01, 0x01, 0x56, 0xFE,
- 0x4D, 0x02, 0x45, 0xFD, 0x8D, 0x02, 0xF0, 0x48, 0xD7, 0x04, 0x47,
- 0xFC, 0xD1, 0x02, 0x12, 0xFE, 0x21, 0x01, 0x7E, 0xFF, 0x20, 0x00,
- 0x00, 0x00, 0xFD, 0xFF, 0x31, 0x00, 0x48, 0xFF, 0xCE, 0x01, 0x42,
- 0xFC, 0x2A, 0x07, 0xBF, 0xF1, 0x40, 0x2B, 0x05, 0x35, 0xA6, 0xF1,
- 0xAB, 0x06, 0xBF, 0xFC, 0x75, 0x01, 0x77, 0xFF, 0x21, 0x00, 0xFE,
- 0xFF, 0x14, 0x00, 0xAD, 0xFF, 0xAA, 0x00, 0x0C, 0xFF, 0xF7, 0x00,
- 0xC1, 0xFF, 0x33, 0xFD, 0xEC, 0x47, 0x51, 0x0B, 0xAF, 0xF9, 0x1D,
- 0x04, 0x6B, 0xFD, 0x6E, 0x01, 0x60, 0xFF, 0x29, 0x00, 0x00, 0x00,
- 0xFD, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xE5, 0x01, 0x33, 0xFC, 0xFF,
- 0x06, 0xC4, 0xF2, 0xB0, 0x23, 0x3B, 0x3B, 0xAD, 0xF2, 0xBF, 0x05,
- 0x66, 0xFD, 0x0E, 0x01, 0xAC, 0xFF, 0x0E, 0x00, 0x00, 0x00, 0x0C,
- 0x00, 0xCE, 0xFF, 0x54, 0x00, 0xBD, 0xFF, 0xB2, 0xFF, 0x01, 0x02,
- 0xCF, 0xF8, 0x7D, 0x45, 0x6B, 0x12, 0x30, 0xF7, 0x48, 0x05, 0xDD,
- 0xFC, 0xAD, 0x01, 0x48, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0xFE, 0xFF,
- 0x36, 0x00, 0x37, 0xFF, 0xDE, 0x01, 0x5F, 0xFC, 0x70, 0x06, 0x6C,
- 0xF4, 0xFD, 0x1B, 0x7D, 0x40, 0xB7, 0xF4, 0x5D, 0x04, 0x49, 0xFE,
- 0x88, 0x00, 0xEF, 0xFF, 0xF5, 0xFF, 0x04, 0x00, 0x06, 0x00, 0xED,
- 0xFF, 0x04, 0x00, 0x60, 0x00, 0x90, 0xFE, 0xEB, 0x03, 0x71, 0xF5,
- 0xB7, 0x41, 0xED, 0x19, 0xF5, 0xF4, 0x3B, 0x06, 0x73, 0xFC, 0xD7,
- 0x01, 0x39, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x32, 0x00,
- 0x43, 0xFF, 0xBA, 0x01, 0xBC, 0xFC, 0x90, 0x05, 0x8E, 0xF6, 0x68,
- 0x14, 0x99, 0x44, 0xCD, 0xF7, 0x8F, 0x02, 0x60, 0xFF, 0xEA, 0xFF,
- 0x3E, 0x00, 0xD7, 0xFF, 0x0A, 0x00, 0x01, 0x00, 0x07, 0x00, 0xBD,
- 0xFF, 0xED, 0x00, 0x9E, 0xFD, 0x6C, 0x05, 0x1F, 0xF3, 0xC0, 0x3C,
- 0x9E, 0x21, 0x28, 0xF3, 0xE2, 0x06, 0x3A, 0xFC, 0xE6, 0x01, 0x37,
- 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x2B, 0x00, 0x59, 0xFF,
- 0x81, 0x01, 0x42, 0xFD, 0x72, 0x04, 0xFF, 0xF8, 0x2D, 0x0D, 0x69,
- 0x47, 0xEB, 0xFB, 0x63, 0x00, 0x9D, 0x00, 0x3C, 0xFF, 0x93, 0x00,
- 0xB6, 0xFF, 0x12, 0x00, 0xFE, 0xFF, 0x1C, 0x00, 0x84, 0xFF, 0x5C,
- 0x01, 0xE6, 0xFC, 0x77, 0x06, 0xD4, 0xF1, 0xC6, 0x36, 0x3E, 0x29,
- 0xF3, 0xF1, 0x29, 0x07, 0x38, 0xFC, 0xD7, 0x01, 0x42, 0xFF, 0x33,
- 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x22, 0x00, 0x76, 0xFF, 0x37, 0x01,
- 0xE4, 0xFD, 0x2C, 0x03, 0x94, 0xFB, 0x83, 0x06, 0xCE, 0x48, 0x05,
- 0x01, 0xF5, 0xFD, 0xF0, 0x01, 0x87, 0xFE, 0xEA, 0x00, 0x94, 0xFF,
- 0x1A, 0x00, 0xFD, 0xFF, 0x2B, 0x00, 0x5A, 0xFF, 0xAC, 0x01, 0x6E,
- 0xFC, 0x0A, 0x07, 0x7E, 0xF1, 0xFF, 0x2F, 0x8A, 0x30, 0x7D, 0xF1,
- 0x03, 0x07, 0x75, 0xFC, 0xA7, 0x01, 0x5D, 0xFF, 0x2A, 0x00, 0xFD,
- 0xFF, 0x1A, 0x00, 0x96, 0xFF, 0xE3, 0x00, 0x95, 0xFE, 0xD5, 0x01,
- 0x26, 0xFE, 0x98, 0x00, 0xBF, 0x48, 0x00, 0x07, 0x61, 0xFB, 0x46,
- 0x03, 0xD6, 0xFD, 0x3D, 0x01, 0x73, 0xFF, 0x23, 0x00, 0x00, 0x00,
- 0xFD, 0xFF, 0x33, 0x00, 0x41, 0xFF, 0xDA, 0x01, 0x36, 0xFC, 0x27,
- 0x07, 0x05, 0xF2, 0xAA, 0x28, 0x44, 0x37, 0xE4, 0xF1, 0x67, 0x06,
- 0xF2, 0xFC, 0x55, 0x01, 0x88, 0xFF, 0x1B, 0x00, 0xFE, 0xFF, 0x11,
- 0x00, 0xB9, 0xFF, 0x8C, 0x00, 0x4A, 0xFF, 0x83, 0x00, 0x91, 0x00,
- 0x91, 0xFB, 0x3D, 0x47, 0xB7, 0x0D, 0xCD, 0xF8, 0x89, 0x04, 0x36,
- 0xFD, 0x86, 0x01, 0x57, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0xFD, 0xFF,
- 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3C, 0xFC, 0xD8, 0x06, 0x47,
- 0xF3, 0x06, 0x21, 0x2A, 0x3D, 0x44, 0xF3, 0x52, 0x05, 0xAE, 0xFD,
- 0xE3, 0x00, 0xC2, 0xFF, 0x06, 0x00, 0x01, 0x00, 0x0A, 0x00, 0xD9,
- 0xFF, 0x37, 0x00, 0xF7, 0xFF, 0x49, 0xFF, 0xB6, 0x02, 0x86, 0xF7,
- 0x53, 0x44, 0xFB, 0x14, 0x61, 0xF6, 0xA4, 0x05, 0xB4, 0xFC, 0xBE,
- 0x01, 0x42, 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x35, 0x00,
- 0x3A, 0xFF, 0xD4, 0x01, 0x7A, 0xFC, 0x2B, 0x06, 0x1E, 0xF5, 0x56,
- 0x19, 0x0C, 0x42, 0xAA, 0xF5, 0xC9, 0x03, 0xA4, 0xFE, 0x54, 0x00,
- 0x09, 0x00, 0xEB, 0xFF, 0x06, 0x00, 0x04, 0x00, 0xF7, 0xFF, 0xEA,
- 0xFF, 0x93, 0x00, 0x36, 0xFE, 0x7D, 0x04, 0x85, 0xF4, 0x1F, 0x40,
- 0x94, 0x1C, 0x47, 0xF4, 0x7E, 0x06, 0x5A, 0xFC, 0xDF, 0x01, 0x37,
- 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x30, 0x00, 0x4A, 0xFF,
- 0xA9, 0x01, 0xE7, 0xFC, 0x33, 0x05, 0x60, 0xF7, 0xDA, 0x11, 0xB8,
- 0x45, 0x1C, 0xF9, 0xD8, 0x01, 0xCA, 0xFF, 0xAF, 0xFF, 0x5A, 0x00,
- 0xCC, 0xFF, 0x0D, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xA8, 0xFF, 0x17,
- 0x01, 0x57, 0xFD, 0xD6, 0x05, 0x90, 0xF2, 0xC8, 0x3A, 0x46, 0x24,
- 0xAA, 0xF2, 0x06, 0x07, 0x32, 0xFC, 0xE5, 0x01, 0x39, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x28, 0x00, 0x62, 0xFF, 0x69, 0x01,
- 0x77, 0xFD, 0x04, 0x04, 0xE2, 0xF9, 0xCB, 0x0A, 0x0D, 0x48, 0x94,
- 0xFD, 0x92, 0xFF, 0x10, 0x01, 0xFE, 0xFE, 0xB1, 0x00, 0xAA, 0xFF,
- 0x15, 0x00, 0xFE, 0xFF, 0x22, 0x00, 0x74, 0xFF, 0x7C, 0x01, 0xB5,
- 0xFC, 0xB8, 0x06, 0x9C, 0xF1, 0x81, 0x34, 0xD1, 0x2B, 0xB3, 0xF1,
- 0x29, 0x07, 0x46, 0xFC, 0xCA, 0x01, 0x4A, 0xFF, 0x30, 0x00, 0xFD,
- 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x81, 0xFF, 0x1B, 0x01, 0x20, 0xFE,
- 0xB6, 0x02, 0x7A, 0xFC, 0x5F, 0x04, 0xF4, 0x48, 0xFF, 0x02, 0x13,
- 0xFD, 0x67, 0x02, 0x49, 0xFE, 0x07, 0x01, 0x88, 0xFF, 0x1D, 0x00,
- 0xFD, 0xFF, 0x2E, 0x00, 0x50, 0xFF, 0xC0, 0x01, 0x53, 0xFC, 0x21,
- 0x07, 0x96, 0xF1, 0x82, 0x2D, 0xF2, 0x32, 0x86, 0xF1, 0xDB, 0x06,
- 0x99, 0xFC, 0x8E, 0x01, 0x6A, 0xFF, 0x25, 0x00, 0xFD, 0xFF, 0x16,
- 0x00, 0xA2, 0xFF, 0xC5, 0x00, 0xD4, 0xFE, 0x5F, 0x01, 0x03, 0xFF,
- 0xBF, 0xFE, 0x63, 0x48, 0x40, 0x09, 0x7B, 0xFA, 0xB9, 0x03, 0x9D,
- 0xFD, 0x58, 0x01, 0x69, 0xFF, 0x26, 0x00, 0x00, 0x00, 0xFD, 0xFF,
- 0x35, 0x00, 0x3B, 0xFF, 0xE2, 0x01, 0x31, 0xFC, 0x17, 0x07, 0x61,
- 0xF2, 0x0A, 0x26, 0x6A, 0x39, 0x41, 0xF2, 0x15, 0x06, 0x2C, 0xFD,
- 0x31, 0x01, 0x9B, 0xFF, 0x14, 0x00, 0xFF, 0xFF, 0x0E, 0x00, 0xC4,
- 0xFF, 0x6E, 0x00, 0x87, 0xFF, 0x13, 0x00, 0x58, 0x01, 0x0D, 0xFA,
- 0x61, 0x46, 0x2D, 0x10, 0xF0, 0xF7, 0xF1, 0x04, 0x05, 0xFD, 0x9C,
- 0x01, 0x4E, 0xFF, 0x2E, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00,
- 0x36, 0xFF, 0xE3, 0x01, 0x4C, 0xFC, 0xA6, 0x06, 0xDB, 0xF3, 0x5B,
- 0x1E, 0xFC, 0x3E, 0xFA, 0xF3, 0xD7, 0x04, 0xFD, 0xFD, 0xB4, 0x00,
- 0xD9, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0x08, 0x00, 0xE4, 0xFF, 0x1B,
- 0x00, 0x30, 0x00, 0xE4, 0xFE, 0x5F, 0x03, 0x5E, 0xF6, 0x02, 0x43,
- 0x96, 0x17, 0x9B, 0xF5, 0xF8, 0x05, 0x8F, 0xFC, 0xCC, 0x01, 0x3D,
- 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x33, 0x00, 0x3E, 0xFF,
- 0xC8, 0x01, 0x9B, 0xFC, 0xDD, 0x05, 0xDC, 0xF5, 0xB6, 0x16, 0x77,
- 0x43, 0xBD, 0xF6, 0x28, 0x03, 0x05, 0xFF, 0x1D, 0x00, 0x25, 0x00,
- 0xE1, 0xFF, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0xD2, 0xFF, 0xC4,
- 0x00, 0xE2, 0xFD, 0x01, 0x05, 0xBA, 0xF3, 0x64, 0x3E, 0x3F, 0x1F,
- 0xA8, 0xF3, 0xB8, 0x06, 0x46, 0xFC, 0xE5, 0x01, 0x36, 0xFF, 0x36,
- 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x2D, 0x00, 0x51, 0xFF, 0x95, 0x01,
- 0x15, 0xFD, 0xCF, 0x04, 0x39, 0xF8, 0x59, 0x0F, 0xAF, 0x46, 0x8B,
- 0xFA, 0x17, 0x01, 0x38, 0x00, 0x73, 0xFF, 0x78, 0x00, 0xC0, 0xFF,
- 0x0F, 0x00, 0xFF, 0xFF, 0x16, 0x00, 0x94, 0xFF, 0x3D, 0x01, 0x18,
- 0xFD, 0x32, 0x06, 0x1F, 0xF2, 0xB5, 0x38, 0xEB, 0x26, 0x40, 0xF2,
- 0x1E, 0x07, 0x32, 0xFC, 0xDF, 0x01, 0x3D, 0xFF, 0x35, 0x00, 0xFD,
- 0xFF, 0x00, 0x00, 0x25, 0x00, 0x6C, 0xFF, 0x4F, 0x01, 0xB0, 0xFD,
- 0x93, 0x03, 0xC7, 0xFA, 0x7D, 0x08, 0x86, 0x48, 0x5A, 0xFF, 0xBA,
- 0xFE, 0x86, 0x01, 0xBF, 0xFE, 0xCF, 0x00, 0x9E, 0xFF, 0x17, 0x00,
- 0xFD, 0xFF, 0x27, 0x00, 0x66, 0xFF, 0x97, 0x01, 0x8C, 0xFC, 0xEA,
- 0x06, 0x80, 0xF1, 0x26, 0x32, 0x58, 0x2E, 0x8B, 0xF1, 0x1B, 0x07,
- 0x5B, 0xFC, 0xBA, 0x01, 0x53, 0xFF, 0x2D, 0x00, 0xFD, 0xFF, 0x1C,
- 0x00, 0x8C, 0xFF, 0xFE, 0x00, 0x5D, 0xFE, 0x3F, 0x02, 0x5E, 0xFD,
- 0x54, 0x02, 0xEC, 0x48, 0x13, 0x05, 0x2E, 0xFC, 0xDE, 0x02, 0x0C,
- 0xFE, 0x24, 0x01, 0x7D, 0xFF, 0x20, 0x00, 0x00, 0x00, 0xFD, 0xFF,
- 0x31, 0x00, 0x47, 0xFF, 0xCF, 0x01, 0x40, 0xFC, 0x2A, 0x07, 0xC6,
- 0xF1, 0xF7, 0x2A, 0x46, 0x35, 0xAB, 0xF1, 0xA4, 0x06, 0xC4, 0xFC,
- 0x72, 0x01, 0x79, 0xFF, 0x20, 0x00, 0xFE, 0xFF, 0x14, 0x00, 0xAE,
- 0xFF, 0xA7, 0x00, 0x12, 0xFF, 0xEA, 0x00, 0xD9, 0xFF, 0x03, 0xFD,
- 0xDC, 0x47, 0x95, 0x0B, 0x96, 0xF9, 0x29, 0x04, 0x65, 0xFD, 0x71,
- 0x01, 0x5F, 0xFF, 0x29, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00,
- 0x38, 0xFF, 0xE6, 0x01, 0x34, 0xFC, 0xFB, 0x06, 0xD2, 0xF2, 0x64,
- 0x23, 0x73, 0x3B, 0xBC, 0xF2, 0xB4, 0x05, 0x6E, 0xFD, 0x09, 0x01,
- 0xAF, 0xFF, 0x0D, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xD0, 0xFF, 0x51,
- 0x00, 0xC3, 0xFF, 0xA6, 0xFF, 0x16, 0x02, 0xA9, 0xF8, 0x5C, 0x45,
- 0xB2, 0x12, 0x19, 0xF7, 0x52, 0x05, 0xD8, 0xFC, 0xAF, 0x01, 0x47,
- 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x38, 0xFF,
- 0xDD, 0x01, 0x62, 0xFC, 0x69, 0x06, 0x7F, 0xF4, 0xB2, 0x1B, 0xAB,
- 0x40, 0xD0, 0xF4, 0x4E, 0x04, 0x53, 0xFE, 0x83, 0x00, 0xF2, 0xFF,
- 0xF4, 0xFF, 0x05, 0x00, 0x06, 0x00, 0xEE, 0xFF, 0x01, 0x00, 0x66,
- 0x00, 0x85, 0xFE, 0xFC, 0x03, 0x55, 0xF5, 0x8C, 0x41, 0x38, 0x1A,
- 0xE1, 0xF4, 0x43, 0x06, 0x70, 0xFC, 0xD8, 0x01, 0x39, 0xFF, 0x35,
- 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x32, 0x00, 0x44, 0xFF, 0xB9, 0x01,
- 0xC1, 0xFC, 0x86, 0x05, 0xA5, 0xF6, 0x1E, 0x14, 0xBA, 0x44, 0xF0,
- 0xF7, 0x7B, 0x02, 0x6B, 0xFF, 0xE4, 0xFF, 0x41, 0x00, 0xD6, 0xFF,
- 0x0B, 0x00, 0x01, 0x00, 0x08, 0x00, 0xBB, 0xFF, 0xF1, 0x00, 0x96,
- 0xFD, 0x78, 0x05, 0x0E, 0xF3, 0x8A, 0x3C, 0xEA, 0x21, 0x19, 0xF3,
- 0xE6, 0x06, 0x38, 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0x00, 0x00, 0x2B, 0x00, 0x5A, 0xFF, 0x7E, 0x01, 0x48, 0xFD,
- 0x66, 0x04, 0x18, 0xF9, 0xE8, 0x0C, 0x7C, 0x47, 0x19, 0xFC, 0x4D,
- 0x00, 0xA9, 0x00, 0x35, 0xFF, 0x96, 0x00, 0xB5, 0xFF, 0x12, 0x00,
- 0xFE, 0xFF, 0x1D, 0x00, 0x82, 0xFF, 0x60, 0x01, 0xE0, 0xFC, 0x7F,
- 0x06, 0xCC, 0xF1, 0x85, 0x36, 0x87, 0x29, 0xEB, 0xF1, 0x2A, 0x07,
- 0x39, 0xFC, 0xD6, 0x01, 0x43, 0xFF, 0x33, 0x00, 0xFD, 0xFF, 0x00,
- 0x00, 0x22, 0x00, 0x77, 0xFF, 0x34, 0x01, 0xEA, 0xFD, 0x1F, 0x03,
- 0xAE, 0xFB, 0x45, 0x06, 0xD5, 0x48, 0x3C, 0x01, 0xDC, 0xFD, 0xFD,
- 0x01, 0x80, 0xFE, 0xED, 0x00, 0x93, 0xFF, 0x1B, 0x00, 0xFD, 0xFF,
- 0x2B, 0x00, 0x59, 0xFF, 0xAE, 0x01, 0x6A, 0xFC, 0x0D, 0x07, 0x80,
- 0xF1, 0xB8, 0x2F, 0xCF, 0x30, 0x7D, 0xF1, 0xFF, 0x06, 0x78, 0xFC,
- 0xA5, 0x01, 0x5F, 0xFF, 0x29, 0x00, 0xFD, 0xFF, 0x19, 0x00, 0x98,
- 0xFF, 0xE0, 0x00, 0x9C, 0xFE, 0xC8, 0x01, 0x3F, 0xFE, 0x62, 0x00,
- 0xB8, 0x48, 0x3F, 0x07, 0x47, 0xFB, 0x53, 0x03, 0xD0, 0xFD, 0x40,
- 0x01, 0x72, 0xFF, 0x23, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x34, 0x00,
- 0x40, 0xFF, 0xDB, 0x01, 0x35, 0xFC, 0x26, 0x07, 0x0E, 0xF2, 0x60,
- 0x28, 0x82, 0x37, 0xED, 0xF1, 0x5E, 0x06, 0xF8, 0xFC, 0x51, 0x01,
- 0x8A, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0x11, 0x00, 0xBA, 0xFF, 0x89,
- 0x00, 0x51, 0xFF, 0x77, 0x00, 0xA7, 0x00, 0x64, 0xFB, 0x26, 0x47,
- 0xFC, 0x0D, 0xB4, 0xF8, 0x95, 0x04, 0x31, 0xFD, 0x88, 0x01, 0x56,
- 0xFF, 0x2C, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF,
- 0xE6, 0x01, 0x3E, 0xFC, 0xD3, 0x06, 0x56, 0xF3, 0xBA, 0x20, 0x61,
- 0x3D, 0x56, 0xF3, 0x45, 0x05, 0xB7, 0xFD, 0xDE, 0x00, 0xC5, 0xFF,
- 0x05, 0x00, 0x02, 0x00, 0x09, 0x00, 0xDB, 0xFF, 0x34, 0x00, 0xFE,
- 0xFF, 0x3D, 0xFF, 0xC9, 0x02, 0x64, 0xF7, 0x2F, 0x44, 0x44, 0x15,
- 0x4A, 0xF6, 0xAD, 0x05, 0xAF, 0xFC, 0xC0, 0x01, 0x41, 0xFF, 0x32,
- 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xD3, 0x01,
- 0x7D, 0xFC, 0x23, 0x06, 0x32, 0xF5, 0x0C, 0x19, 0x38, 0x42, 0xC7,
- 0xF5, 0xB8, 0x03, 0xAF, 0xFE, 0x4E, 0x00, 0x0C, 0x00, 0xEA, 0xFF,
- 0x06, 0x00, 0x04, 0x00, 0xF8, 0xFF, 0xE7, 0xFF, 0x99, 0x00, 0x2C,
- 0xFE, 0x8C, 0x04, 0x6D, 0xF4, 0xF0, 0x3F, 0xE0, 0x1C, 0x34, 0xF4,
- 0x85, 0x06, 0x57, 0xFC, 0xE0, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE,
- 0xFF, 0xFF, 0xFF, 0x2F, 0x00, 0x4A, 0xFF, 0xA7, 0x01, 0xEC, 0xFC,
- 0x28, 0x05, 0x77, 0xF7, 0x92, 0x11, 0xD7, 0x45, 0x43, 0xF9, 0xC3,
- 0x01, 0xD6, 0xFF, 0xA9, 0xFF, 0x5E, 0x00, 0xCB, 0xFF, 0x0D, 0x00,
- 0x00, 0x00, 0x10, 0x00, 0xA6, 0xFF, 0x1B, 0x01, 0x50, 0xFD, 0xE1,
- 0x05, 0x82, 0xF2, 0x8F, 0x3A, 0x92, 0x24, 0x9D, 0xF2, 0x09, 0x07,
- 0x32, 0xFC, 0xE4, 0x01, 0x39, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x00,
- 0x00, 0x28, 0x00, 0x63, 0xFF, 0x66, 0x01, 0x7D, 0xFD, 0xF8, 0x03,
- 0xFB, 0xF9, 0x89, 0x0A, 0x1D, 0x48, 0xC5, 0xFD, 0x7A, 0xFF, 0x1D,
- 0x01, 0xF7, 0xFE, 0xB4, 0x00, 0xA9, 0xFF, 0x15, 0x00, 0xFE, 0xFF,
- 0x23, 0x00, 0x72, 0xFF, 0x7F, 0x01, 0xB0, 0xFC, 0xBE, 0x06, 0x97,
- 0xF1, 0x3F, 0x34, 0x19, 0x2C, 0xAD, 0xF1, 0x28, 0x07, 0x48, 0xFC,
- 0xC9, 0x01, 0x4B, 0xFF, 0x30, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x1F,
- 0x00, 0x82, 0xFF, 0x18, 0x01, 0x27, 0xFE, 0xA9, 0x02, 0x94, 0xFC,
- 0x24, 0x04, 0xF5, 0x48, 0x39, 0x03, 0xF9, 0xFC, 0x74, 0x02, 0x42,
- 0xFE, 0x0B, 0x01, 0x87, 0xFF, 0x1E, 0x00, 0xFD, 0xFF, 0x2F, 0x00,
- 0x4F, 0xFF, 0xC2, 0x01, 0x51, 0xFC, 0x23, 0x07, 0x9A, 0xF1, 0x3A,
- 0x2D, 0x35, 0x33, 0x89, 0xF1, 0xD5, 0x06, 0x9D, 0xFC, 0x8B, 0x01,
- 0x6C, 0xFF, 0x25, 0x00, 0xFD, 0xFF, 0x16, 0x00, 0xA4, 0xFF, 0xC2,
- 0x00, 0xDB, 0xFE, 0x52, 0x01, 0x1B, 0xFF, 0x8D, 0xFE, 0x57, 0x48,
- 0x81, 0x09, 0x61, 0xFA, 0xC6, 0x03, 0x96, 0xFD, 0x5B, 0x01, 0x68,
- 0xFF, 0x26, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3B, 0xFF,
- 0xE2, 0x01, 0x31, 0xFC, 0x15, 0x07, 0x6D, 0xF2, 0xBF, 0x25, 0xA5,
- 0x39, 0x4D, 0xF2, 0x0B, 0x06, 0x33, 0xFD, 0x2D, 0x01, 0x9D, 0xFF,
- 0x13, 0x00, 0xFF, 0xFF, 0x0E, 0x00, 0xC6, 0xFF, 0x6B, 0x00, 0x8E,
- 0xFF, 0x06, 0x00, 0x6E, 0x01, 0xE4, 0xF9, 0x48, 0x46, 0x75, 0x10,
- 0xD7, 0xF7, 0xFC, 0x04, 0x00, 0xFD, 0x9E, 0x01, 0x4E, 0xFF, 0x2E,
- 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE3, 0x01,
- 0x4E, 0xFC, 0xA0, 0x06, 0xED, 0xF3, 0x0F, 0x1E, 0x2D, 0x3F, 0x10,
- 0xF4, 0xC8, 0x04, 0x07, 0xFE, 0xAF, 0x00, 0xDC, 0xFF, 0xFC, 0xFF,
- 0x03, 0x00, 0x07, 0x00, 0xE5, 0xFF, 0x18, 0x00, 0x36, 0x00, 0xD9,
- 0xFE, 0x71, 0x03, 0x3F, 0xF6, 0xDB, 0x42, 0xE0, 0x17, 0x86, 0xF5,
- 0x00, 0x06, 0x8C, 0xFC, 0xCE, 0x01, 0x3C, 0xFF, 0x34, 0x00, 0xFE,
- 0xFF, 0xFF, 0xFF, 0x33, 0x00, 0x3F, 0xFF, 0xC6, 0x01, 0x9F, 0xFC,
- 0xD3, 0x05, 0xF1, 0xF5, 0x6C, 0x16, 0x9E, 0x43, 0xDD, 0xF6, 0x15,
- 0x03, 0x10, 0xFF, 0x17, 0x00, 0x28, 0x00, 0xDF, 0xFF, 0x09, 0x00,
- 0x02, 0x00, 0x01, 0x00, 0xCF, 0xFF, 0xC9, 0x00, 0xDA, 0xFD, 0x0F,
- 0x05, 0xA5, 0xF3, 0x31, 0x3E, 0x8A, 0x1F, 0x97, 0xF3, 0xBD, 0x06,
- 0x44, 0xFC, 0xE5, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFF,
- 0xFF, 0x2D, 0x00, 0x52, 0xFF, 0x92, 0x01, 0x1B, 0xFD, 0xC4, 0x04,
- 0x51, 0xF8, 0x13, 0x0F, 0xC8, 0x46, 0xB6, 0xFA, 0x01, 0x01, 0x44,
- 0x00, 0x6C, 0xFF, 0x7B, 0x00, 0xBF, 0xFF, 0x10, 0x00, 0xFF, 0xFF,
- 0x17, 0x00, 0x92, 0xFF, 0x41, 0x01, 0x11, 0xFD, 0x3B, 0x06, 0x14,
- 0xF2, 0x78, 0x38, 0x36, 0x27, 0x35, 0xF2, 0x20, 0x07, 0x33, 0xFC,
- 0xDF, 0x01, 0x3E, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x25,
- 0x00, 0x6D, 0xFF, 0x4C, 0x01, 0xB6, 0xFD, 0x86, 0x03, 0xE1, 0xFA,
- 0x3D, 0x08, 0x92, 0x48, 0x8E, 0xFF, 0xA1, 0xFE, 0x93, 0x01, 0xB8,
- 0xFE, 0xD3, 0x00, 0x9D, 0xFF, 0x18, 0x00, 0xFD, 0xFF, 0x28, 0x00,
- 0x64, 0xFF, 0x9A, 0x01, 0x88, 0xFC, 0xEE, 0x06, 0x7E, 0xF1, 0xE3,
- 0x31, 0x9F, 0x2E, 0x88, 0xF1, 0x19, 0x07, 0x5E, 0xFC, 0xB7, 0x01,
- 0x54, 0xFF, 0x2D, 0x00, 0xFD, 0xFF, 0x1C, 0x00, 0x8D, 0xFF, 0xFA,
- 0x00, 0x64, 0xFE, 0x32, 0x02, 0x78, 0xFD, 0x1B, 0x02, 0xEA, 0x48,
- 0x50, 0x05, 0x14, 0xFC, 0xEB, 0x02, 0x05, 0xFE, 0x27, 0x01, 0x7C,
- 0xFF, 0x21, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x46, 0xFF,
- 0xD1, 0x01, 0x3F, 0xFC, 0x2B, 0x07, 0xCD, 0xF1, 0xAE, 0x2A, 0x86,
- 0x35, 0xB1, 0xF1, 0x9D, 0x06, 0xCA, 0xFC, 0x6E, 0x01, 0x7B, 0xFF,
- 0x20, 0x00, 0xFE, 0xFF, 0x13, 0x00, 0xAF, 0xFF, 0xA4, 0x00, 0x19,
- 0xFF, 0xDD, 0x00, 0xF0, 0xFF, 0xD4, 0xFC, 0xC9, 0x47, 0xD8, 0x0B,
- 0x7C, 0xF9, 0x35, 0x04, 0x5F, 0xFD, 0x74, 0x01, 0x5E, 0xFF, 0x29,
- 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xE6, 0x01,
- 0x35, 0xFC, 0xF7, 0x06, 0xE0, 0xF2, 0x18, 0x23, 0xAB, 0x3B, 0xCC,
- 0xF2, 0xA8, 0x05, 0x76, 0xFD, 0x04, 0x01, 0xB1, 0xFF, 0x0C, 0x00,
- 0x00, 0x00, 0x0C, 0x00, 0xD1, 0xFF, 0x4E, 0x00, 0xCA, 0xFF, 0x9A,
- 0xFF, 0x2A, 0x02, 0x83, 0xF8, 0x3F, 0x45, 0xFB, 0x12, 0x01, 0xF7,
- 0x5D, 0x05, 0xD3, 0xFC, 0xB1, 0x01, 0x46, 0xFF, 0x31, 0x00, 0xFF,
- 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xDC, 0x01, 0x64, 0xFC,
- 0x62, 0x06, 0x93, 0xF4, 0x66, 0x1B, 0xD9, 0x40, 0xEA, 0xF4, 0x3E,
- 0x04, 0x5D, 0xFE, 0x7D, 0x00, 0xF5, 0xFF, 0xF3, 0xFF, 0x05, 0x00,
- 0x05, 0x00, 0xEF, 0xFF, 0xFE, 0xFF, 0x6C, 0x00, 0x7B, 0xFE, 0x0C,
- 0x04, 0x3A, 0xF5, 0x5F, 0x41, 0x83, 0x1A, 0xCD, 0xF4, 0x4B, 0x06,
- 0x6D, 0xFC, 0xD9, 0x01, 0x39, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0xFF,
- 0xFF, 0x31, 0x00, 0x44, 0xFF, 0xB7, 0x01, 0xC5, 0xFC, 0x7C, 0x05,
- 0xBC, 0xF6, 0xD5, 0x13, 0xDC, 0x44, 0x14, 0xF8, 0x67, 0x02, 0x77,
- 0xFF, 0xDD, 0xFF, 0x44, 0x00, 0xD5, 0xFF, 0x0B, 0x00, 0x01, 0x00,
- 0x09, 0x00, 0xB8, 0xFF, 0xF6, 0x00, 0x8D, 0xFD, 0x84, 0x05, 0xFD,
- 0xF2, 0x52, 0x3C, 0x35, 0x22, 0x0B, 0xF3, 0xEB, 0x06, 0x37, 0xFC,
- 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x2A,
- 0x00, 0x5B, 0xFF, 0x7C, 0x01, 0x4E, 0xFD, 0x5A, 0x04, 0x31, 0xF9,
- 0xA4, 0x0C, 0x90, 0x47, 0x47, 0xFC, 0x36, 0x00, 0xB6, 0x00, 0x2E,
- 0xFF, 0x99, 0x00, 0xB3, 0xFF, 0x12, 0x00, 0xFE, 0xFF, 0x1E, 0x00,
- 0x80, 0xFF, 0x64, 0x01, 0xDA, 0xFC, 0x87, 0x06, 0xC5, 0xF1, 0x46,
- 0x36, 0xD1, 0x29, 0xE3, 0xF1, 0x2A, 0x07, 0x3A, 0xFC, 0xD5, 0x01,
- 0x44, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x22, 0x00, 0x78,
- 0xFF, 0x31, 0x01, 0xF1, 0xFD, 0x12, 0x03, 0xC7, 0xFB, 0x07, 0x06,
- 0xDB, 0x48, 0x73, 0x01, 0xC3, 0xFD, 0x0A, 0x02, 0x79, 0xFE, 0xF1,
- 0x00, 0x91, 0xFF, 0x1B, 0x00, 0xFD, 0xFF, 0x2C, 0x00, 0x58, 0xFF,
- 0xB1, 0x01, 0x67, 0xFC, 0x10, 0x07, 0x81, 0xF1, 0x73, 0x2F, 0x15,
- 0x31, 0x7C, 0xF1, 0xFB, 0x06, 0x7C, 0xFC, 0xA2, 0x01, 0x60, 0xFF,
- 0x29, 0x00, 0xFD, 0xFF, 0x19, 0x00, 0x99, 0xFF, 0xDD, 0x00, 0xA3,
- 0xFE, 0xBB, 0x01, 0x58, 0xFE, 0x2D, 0x00, 0xAF, 0x48, 0x7E, 0x07,
- 0x2E, 0xFB, 0x60, 0x03, 0xC9, 0xFD, 0x43, 0x01, 0x71, 0xFF, 0x24,
- 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x34, 0x00, 0x3F, 0xFF, 0xDC, 0x01,
- 0x34, 0xFC, 0x25, 0x07, 0x18, 0xF2, 0x15, 0x28, 0xBF, 0x37, 0xF7,
- 0xF1, 0x56, 0x06, 0xFE, 0xFC, 0x4D, 0x01, 0x8C, 0xFF, 0x19, 0x00,
- 0xFF, 0xFF, 0x10, 0x00, 0xBB, 0xFF, 0x85, 0x00, 0x58, 0xFF, 0x6A,
- 0x00, 0xBE, 0x00, 0x38, 0xFB, 0x0F, 0x47, 0x42, 0x0E, 0x9B, 0xF8,
- 0xA1, 0x04, 0x2B, 0xFD, 0x8B, 0x01, 0x55, 0xFF, 0x2C, 0x00, 0xFF,
- 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3F, 0xFC,
- 0xCE, 0x06, 0x66, 0xF3, 0x6F, 0x20, 0x96, 0x3D, 0x69, 0xF3, 0x38,
- 0x05, 0xBF, 0xFD, 0xD9, 0x00, 0xC7, 0xFF, 0x04, 0x00, 0x02, 0x00,
- 0x09, 0x00, 0xDC, 0xFF, 0x31, 0x00, 0x04, 0x00, 0x32, 0xFF, 0xDC,
- 0x02, 0x42, 0xF7, 0x0B, 0x44, 0x8E, 0x15, 0x34, 0xF6, 0xB7, 0x05,
- 0xAB, 0xFC, 0xC1, 0x01, 0x40, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0xFE,
- 0xFF, 0x35, 0x00, 0x3B, 0xFF, 0xD2, 0x01, 0x81, 0xFC, 0x1A, 0x06,
- 0x47, 0xF5, 0xC1, 0x18, 0x60, 0x42, 0xE4, 0xF5, 0xA6, 0x03, 0xB9,
- 0xFE, 0x48, 0x00, 0x0F, 0x00, 0xE9, 0xFF, 0x07, 0x00, 0x04, 0x00,
- 0xF9, 0xFF, 0xE4, 0xFF, 0x9F, 0x00, 0x23, 0xFE, 0x9B, 0x04, 0x55,
- 0xF4, 0xC0, 0x3F, 0x2C, 0x1D, 0x22, 0xF4, 0x8C, 0x06, 0x55, 0xFC,
- 0xE1, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x2F,
- 0x00, 0x4B, 0xFF, 0xA4, 0x01, 0xF1, 0xFC, 0x1D, 0x05, 0x8F, 0xF7,
- 0x4A, 0x11, 0xF2, 0x45, 0x6B, 0xF9, 0xAE, 0x01, 0xE2, 0xFF, 0xA2,
- 0xFF, 0x61, 0x00, 0xC9, 0xFF, 0x0D, 0x00, 0x00, 0x00, 0x11, 0x00,
- 0xA3, 0xFF, 0x20, 0x01, 0x49, 0xFD, 0xEB, 0x05, 0x74, 0xF2, 0x54,
- 0x3A, 0xDD, 0x24, 0x91, 0xF2, 0x0C, 0x07, 0x32, 0xFC, 0xE4, 0x01,
- 0x3A, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x27, 0x00, 0x64,
- 0xFF, 0x63, 0x01, 0x84, 0xFD, 0xEB, 0x03, 0x14, 0xFA, 0x47, 0x0A,
- 0x2C, 0x48, 0xF6, 0xFD, 0x63, 0xFF, 0x2B, 0x01, 0xF0, 0xFE, 0xB8,
- 0x00, 0xA8, 0xFF, 0x15, 0x00, 0xFE, 0xFF, 0x23, 0x00, 0x71, 0xFF,
- 0x82, 0x01, 0xAB, 0xFC, 0xC4, 0x06, 0x93, 0xF1, 0xFD, 0x33, 0x62,
- 0x2C, 0xA8, 0xF1, 0x27, 0x07, 0x4A, 0xFC, 0xC7, 0x01, 0x4C, 0xFF,
- 0x30, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x1F, 0x00, 0x83, 0xFF, 0x14,
- 0x01, 0x2D, 0xFE, 0x9C, 0x02, 0xAD, 0xFC, 0xE9, 0x03, 0xF6, 0x48,
- 0x73, 0x03, 0xE0, 0xFC, 0x82, 0x02, 0x3B, 0xFE, 0x0E, 0x01, 0x86,
- 0xFF, 0x1E, 0x00, 0xFD, 0xFF, 0x2F, 0x00, 0x4E, 0xFF, 0xC3, 0x01,
- 0x4E, 0xFC, 0x24, 0x07, 0x9E, 0xF1, 0xF2, 0x2C, 0x78, 0x33, 0x8C,
- 0xF1, 0xD0, 0x06, 0xA2, 0xFC, 0x88, 0x01, 0x6D, 0xFF, 0x24, 0x00,
- 0xFD, 0xFF, 0x16, 0x00, 0xA5, 0xFF, 0xBE, 0x00, 0xE2, 0xFE, 0x45,
- 0x01, 0x33, 0xFF, 0x5A, 0xFE, 0x48, 0x48, 0xC3, 0x09, 0x47, 0xFA,
- 0xD2, 0x03, 0x90, 0xFD, 0x5E, 0x01, 0x66, 0xFF, 0x27, 0x00, 0x00,
- 0x00, 0xFD, 0xFF, 0x35, 0x00, 0x3B, 0xFF, 0xE3, 0x01, 0x31, 0xFC,
- 0x12, 0x07, 0x79, 0xF2, 0x73, 0x25, 0xDF, 0x39, 0x5A, 0xF2, 0x00,
- 0x06, 0x3A, 0xFD, 0x28, 0x01, 0x9F, 0xFF, 0x13, 0x00, 0x00, 0x00,
- 0x0E, 0x00, 0xC7, 0xFF, 0x68, 0x00, 0x95, 0xFF, 0xFA, 0xFF, 0x83,
- 0x01, 0xBB, 0xF9, 0x2B, 0x46, 0xBB, 0x10, 0xBF, 0xF7, 0x07, 0x05,
- 0xFB, 0xFC, 0xA0, 0x01, 0x4D, 0xFF, 0x2F, 0x00, 0xFF, 0xFF, 0xFE,
- 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE2, 0x01, 0x50, 0xFC, 0x99, 0x06,
- 0xFE, 0xF3, 0xC3, 0x1D, 0x5E, 0x3F, 0x27, 0xF4, 0xB9, 0x04, 0x10,
- 0xFE, 0xA9, 0x00, 0xDF, 0xFF, 0xFB, 0xFF, 0x03, 0x00, 0x07, 0x00,
- 0xE6, 0xFF, 0x15, 0x00, 0x3C, 0x00, 0xCF, 0xFE, 0x83, 0x03, 0x20,
- 0xF6, 0xB2, 0x42, 0x2B, 0x18, 0x71, 0xF5, 0x09, 0x06, 0x88, 0xFC,
- 0xCF, 0x01, 0x3C, 0xFF, 0x34, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x33,
- 0x00, 0x3F, 0xFF, 0xC5, 0x01, 0xA3, 0xFC, 0xCA, 0x05, 0x07, 0xF6,
- 0x22, 0x16, 0xC3, 0x43, 0xFE, 0xF6, 0x02, 0x03, 0x1B, 0xFF, 0x11,
- 0x00, 0x2B, 0x00, 0xDE, 0xFF, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00,
- 0xCC, 0xFF, 0xCE, 0x00, 0xD1, 0xFD, 0x1D, 0x05, 0x91, 0xF3, 0xFE,
- 0x3D, 0xD7, 0x1F, 0x87, 0xF3, 0xC3, 0x06, 0x42, 0xFC, 0xE5, 0x01,
- 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x2D, 0x00, 0x53,
- 0xFF, 0x90, 0x01, 0x20, 0xFD, 0xB8, 0x04, 0x6A, 0xF8, 0xCD, 0x0E,
- 0xE1, 0x46, 0xE1, 0xFA, 0xEB, 0x00, 0x51, 0x00, 0x65, 0xFF, 0x7F,
- 0x00, 0xBE, 0xFF, 0x10, 0x00, 0xFF, 0xFF, 0x18, 0x00, 0x90, 0xFF,
- 0x45, 0x01, 0x0B, 0xFD, 0x44, 0x06, 0x0A, 0xF2, 0x3B, 0x38, 0x80,
- 0x27, 0x2B, 0xF2, 0x22, 0x07, 0x33, 0xFC, 0xDE, 0x01, 0x3E, 0xFF,
- 0x34, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x24, 0x00, 0x6E, 0xFF, 0x49,
- 0x01, 0xBC, 0xFD, 0x7A, 0x03, 0xFA, 0xFA, 0xFD, 0x07, 0x9C, 0x48,
- 0xC3, 0xFF, 0x89, 0xFE, 0xA1, 0x01, 0xB1, 0xFE, 0xD6, 0x00, 0x9C,
- 0xFF, 0x18, 0x00, 0xFD, 0xFF, 0x28, 0x00, 0x63, 0xFF, 0x9D, 0x01,
- 0x84, 0xFC, 0xF3, 0x06, 0x7D, 0xF1, 0x9E, 0x31, 0xE6, 0x2E, 0x85,
- 0xF1, 0x16, 0x07, 0x61, 0xFC, 0xB5, 0x01, 0x55, 0xFF, 0x2D, 0x00,
- 0xFD, 0xFF, 0x1C, 0x00, 0x8F, 0xFF, 0xF7, 0x00, 0x6B, 0xFE, 0x25,
- 0x02, 0x91, 0xFD, 0xE3, 0x01, 0xE5, 0x48, 0x8D, 0x05, 0xFB, 0xFB,
- 0xF8, 0x02, 0xFE, 0xFD, 0x2B, 0x01, 0x7A, 0xFF, 0x21, 0x00, 0x00,
- 0x00, 0xFD, 0xFF, 0x32, 0x00, 0x45, 0xFF, 0xD2, 0x01, 0x3D, 0xFC,
- 0x2B, 0x07, 0xD4, 0xF1, 0x64, 0x2A, 0xC6, 0x35, 0xB7, 0xF1, 0x96,
- 0x06, 0xCF, 0xFC, 0x6B, 0x01, 0x7D, 0xFF, 0x1F, 0x00, 0xFE, 0xFF,
- 0x13, 0x00, 0xB1, 0xFF, 0xA0, 0x00, 0x20, 0xFF, 0xD0, 0x00, 0x07,
- 0x00, 0xA4, 0xFC, 0xB6, 0x47, 0x1C, 0x0C, 0x63, 0xF9, 0x42, 0x04,
- 0x59, 0xFD, 0x76, 0x01, 0x5D, 0xFF, 0x2A, 0x00, 0x00, 0x00, 0xFD,
- 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x35, 0xFC, 0xF3, 0x06,
- 0xEE, 0xF2, 0xCD, 0x22, 0xE4, 0x3B, 0xDC, 0xF2, 0x9C, 0x05, 0x7E,
- 0xFD, 0x00, 0x01, 0xB4, 0xFF, 0x0B, 0x00, 0x01, 0x00, 0x0B, 0x00,
- 0xD2, 0xFF, 0x4A, 0x00, 0xD0, 0xFF, 0x8E, 0xFF, 0x3F, 0x02, 0x5E,
- 0xF8, 0x1E, 0x45, 0x44, 0x13, 0xEA, 0xF6, 0x67, 0x05, 0xCF, 0xFC,
- 0xB3, 0x01, 0x46, 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x36,
- 0x00, 0x38, 0xFF, 0xDB, 0x01, 0x67, 0xFC, 0x5A, 0x06, 0xA6, 0xF4,
- 0x1B, 0x1B, 0x07, 0x41, 0x04, 0xF5, 0x2D, 0x04, 0x67, 0xFE, 0x77,
- 0x00, 0xF8, 0xFF, 0xF2, 0xFF, 0x05, 0x00, 0x05, 0x00, 0xF0, 0xFF,
- 0xFB, 0xFF, 0x71, 0x00, 0x71, 0xFE, 0x1D, 0x04, 0x1F, 0xF5, 0x32,
- 0x41, 0xCE, 0x1A, 0xBA, 0xF4, 0x53, 0x06, 0x6A, 0xFC, 0xDA, 0x01,
- 0x38, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x31, 0x00, 0x45,
- 0xFF, 0xB5, 0x01, 0xCA, 0xFC, 0x72, 0x05, 0xD3, 0xF6, 0x8D, 0x13,
- 0xFD, 0x44, 0x39, 0xF8, 0x53, 0x02, 0x82, 0xFF, 0xD7, 0xFF, 0x47,
- 0x00, 0xD3, 0xFF, 0x0B, 0x00, 0x01, 0x00, 0x0A, 0x00, 0xB6, 0xFF,
- 0xFB, 0x00, 0x85, 0xFD, 0x90, 0x05, 0xEC, 0xF2, 0x1C, 0x3C, 0x81,
- 0x22, 0xFC, 0xF2, 0xEF, 0x06, 0x36, 0xFC, 0xE6, 0x01, 0x37, 0xFF,
- 0x36, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x2A, 0x00, 0x5C, 0xFF, 0x79,
- 0x01, 0x53, 0xFD, 0x4E, 0x04, 0x4A, 0xF9, 0x60, 0x0C, 0xA3, 0x47,
- 0x76, 0xFC, 0x1F, 0x00, 0xC3, 0x00, 0x27, 0xFF, 0x9D, 0x00, 0xB2,
- 0xFF, 0x13, 0x00, 0xFE, 0xFF, 0x1E, 0x00, 0x7F, 0xFF, 0x67, 0x01,
- 0xD5, 0xFC, 0x8E, 0x06, 0xBE, 0xF1, 0x06, 0x36, 0x1A, 0x2A, 0xDC,
- 0xF1, 0x2A, 0x07, 0x3C, 0xFC, 0xD3, 0x01, 0x44, 0xFF, 0x32, 0x00,
- 0xFD, 0xFF, 0x00, 0x00, 0x21, 0x00, 0x79, 0xFF, 0x2E, 0x01, 0xF7,
- 0xFD, 0x05, 0x03, 0xE1, 0xFB, 0xCA, 0x05, 0xDF, 0x48, 0xAB, 0x01,
- 0xAA, 0xFD, 0x18, 0x02, 0x72, 0xFE, 0xF4, 0x00, 0x90, 0xFF, 0x1B,
- 0x00, 0xFD, 0xFF, 0x2C, 0x00, 0x57, 0xFF, 0xB3, 0x01, 0x64, 0xFC,
- 0x13, 0x07, 0x83, 0xF1, 0x2C, 0x2F, 0x5A, 0x31, 0x7D, 0xF1, 0xF7,
- 0x06, 0x80, 0xFC, 0x9F, 0x01, 0x61, 0xFF, 0x29, 0x00, 0xFD, 0xFF,
- 0x19, 0x00, 0x9A, 0xFF, 0xD9, 0x00, 0xAA, 0xFE, 0xAE, 0x01, 0x70,
- 0xFE, 0xF8, 0xFF, 0xA6, 0x48, 0xBE, 0x07, 0x14, 0xFB, 0x6D, 0x03,
- 0xC3, 0xFD, 0x46, 0x01, 0x70, 0xFF, 0x24, 0x00, 0x00, 0x00, 0xFD,
- 0xFF, 0x34, 0x00, 0x3F, 0xFF, 0xDD, 0x01, 0x34, 0xFC, 0x23, 0x07,
- 0x21, 0xF2, 0xCB, 0x27, 0xFE, 0x37, 0x00, 0xF2, 0x4D, 0x06, 0x04,
- 0xFD, 0x49, 0x01, 0x8E, 0xFF, 0x19, 0x00, 0xFF, 0xFF, 0x10, 0x00,
- 0xBD, 0xFF, 0x82, 0x00, 0x5E, 0xFF, 0x5D, 0x00, 0xD4, 0x00, 0x0C,
- 0xFB, 0xF9, 0x46, 0x87, 0x0E, 0x82, 0xF8, 0xAD, 0x04, 0x26, 0xFD,
- 0x8D, 0x01, 0x54, 0xFF, 0x2C, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x36,
- 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x41, 0xFC, 0xC8, 0x06, 0x76, 0xF3,
- 0x22, 0x20, 0xCA, 0x3D, 0x7D, 0xF3, 0x2A, 0x05, 0xC8, 0xFD, 0xD4,
- 0x00, 0xCA, 0xFF, 0x03, 0x00, 0x02, 0x00, 0x09, 0x00, 0xDD, 0xFF,
- 0x2E, 0x00, 0x0A, 0x00, 0x27, 0xFF, 0xEF, 0x02, 0x20, 0xF7, 0xE7,
- 0x43, 0xD8, 0x15, 0x1E, 0xF6, 0xC0, 0x05, 0xA7, 0xFC, 0xC3, 0x01,
- 0x40, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0xFE, 0xFF, 0x34, 0x00, 0x3B,
- 0xFF, 0xD1, 0x01, 0x84, 0xFC, 0x12, 0x06, 0x5C, 0xF5, 0x76, 0x18,
- 0x89, 0x42, 0x02, 0xF6, 0x94, 0x03, 0xC4, 0xFE, 0x42, 0x00, 0x12,
- 0x00, 0xE8, 0xFF, 0x07, 0x00, 0x03, 0x00, 0xFA, 0xFF, 0xE2, 0xFF,
- 0xA4, 0x00, 0x19, 0xFE, 0xAA, 0x04, 0x3E, 0xF4, 0x90, 0x3F, 0x78,
- 0x1D, 0x10, 0xF4, 0x93, 0x06, 0x52, 0xFC, 0xE1, 0x01, 0x36, 0xFF,
- 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x2F, 0x00, 0x4C, 0xFF, 0xA2,
- 0x01, 0xF6, 0xFC, 0x12, 0x05, 0xA7, 0xF7, 0x03, 0x11, 0x10, 0x46,
- 0x93, 0xF9, 0x98, 0x01, 0xEE, 0xFF, 0x9B, 0xFF, 0x64, 0x00, 0xC8,
- 0xFF, 0x0E, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA1, 0xFF, 0x24, 0x01,
- 0x41, 0xFD, 0xF6, 0x05, 0x67, 0xF2, 0x1A, 0x3A, 0x29, 0x25, 0x84,
- 0xF2, 0x0F, 0x07, 0x31, 0xFC, 0xE3, 0x01, 0x3A, 0xFF, 0x35, 0x00,
- 0xFD, 0xFF, 0x00, 0x00, 0x27, 0x00, 0x65, 0xFF, 0x60, 0x01, 0x8A,
- 0xFD, 0xDF, 0x03, 0x2E, 0xFA, 0x04, 0x0A, 0x3A, 0x48, 0x28, 0xFE,
- 0x4B, 0xFF, 0x38, 0x01, 0xE9, 0xFE, 0xBB, 0x00, 0xA6, 0xFF, 0x16,
- 0x00, 0xFD, 0xFF, 0x24, 0x00, 0x6F, 0xFF, 0x85, 0x01, 0xA6, 0xFC,
- 0xCA, 0x06, 0x8F, 0xF1, 0xBB, 0x33, 0xAB, 0x2C, 0xA3, 0xF1, 0x26,
- 0x07, 0x4C, 0xFC, 0xC5, 0x01, 0x4D, 0xFF, 0x30, 0x00, 0xFD, 0xFF,
- 0x00, 0x00, 0x1E, 0x00, 0x84, 0xFF, 0x11, 0x01, 0x34, 0xFE, 0x8F,
- 0x02, 0xC7, 0xFC, 0xAE, 0x03, 0xF7, 0x48, 0xAE, 0x03, 0xC7, 0xFC,
- 0x8F, 0x02, 0x34, 0xFE, 0x11, 0x01, 0x84, 0xFF, 0x1E, 0x00, 0xFD,
- 0xFF, 0x2A, 0x00, 0x5C, 0xFF, 0xAA, 0x01, 0x71, 0xFC, 0x07, 0x07,
- 0x7E, 0xF1, 0x44, 0x30, 0x44, 0x30, 0x7E, 0xF1, 0x07, 0x07, 0x71,
- 0xFC, 0xAA, 0x01, 0x5C, 0xFF, 0x2A, 0x00, 0xFD, 0xFF, 0x00, 0x00,
- 0x1E, 0x00, 0x84, 0xFF, 0x11, 0x01, 0x34, 0xFE, 0x8F, 0x02, 0xC7,
- 0xFC, 0xAE, 0x03, 0xF7, 0x48, 0xAE, 0x03, 0xC7, 0xFC, 0x8F, 0x02,
- 0x34, 0xFE, 0x11, 0x01, 0x84, 0xFF, 0x1E, 0x00, 0x02, 0x00, 0x05,
- 0x00, 0xC3, 0xFF, 0xE1, 0x00, 0xB1, 0xFD, 0x4E, 0x05, 0x4A, 0xF3,
- 0x3D, 0x3D, 0xED, 0x20, 0x4C, 0xF3, 0xD6, 0x06, 0x3D, 0xFC, 0xE6,
- 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x36, 0x00,
- 0x36, 0xFF, 0xE6, 0x01, 0x3D, 0xFC, 0xD6, 0x06, 0x4C, 0xF3, 0xED,
- 0x20, 0x3D, 0x3D, 0x4A, 0xF3, 0x4E, 0x05, 0xB1, 0xFD, 0xE1, 0x00,
- 0xC3, 0xFF, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x84,
- 0xFF, 0x11, 0x01, 0x34, 0xFE, 0x8F, 0x02, 0xC7, 0xFC, 0xAE, 0x03,
- 0xF7, 0x48, 0xAE, 0x03, 0xC7, 0xFC, 0x8F, 0x02, 0x34, 0xFE, 0x11,
- 0x01, 0x84, 0xFF, 0x1E, 0x00, 0x16, 0x00, 0xA6, 0xFF, 0xBB, 0x00,
- 0xE9, 0xFE, 0x38, 0x01, 0x4B, 0xFF, 0x28, 0xFE, 0x3A, 0x48, 0x04,
- 0x0A, 0x2E, 0xFA, 0xDF, 0x03, 0x8A, 0xFD, 0x60, 0x01, 0x65, 0xFF,
- 0x27, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xC8, 0xFF, 0x64, 0x00, 0x9B,
- 0xFF, 0xEE, 0xFF, 0x98, 0x01, 0x93, 0xF9, 0x10, 0x46, 0x03, 0x11,
- 0xA7, 0xF7, 0x12, 0x05, 0xF6, 0xFC, 0xA2, 0x01, 0x4C, 0xFF, 0x2F,
- 0x00, 0xFF, 0xFF, 0x07, 0x00, 0xE8, 0xFF, 0x12, 0x00, 0x42, 0x00,
- 0xC4, 0xFE, 0x94, 0x03, 0x02, 0xF6, 0x89, 0x42, 0x76, 0x18, 0x5C,
- 0xF5, 0x12, 0x06, 0x84, 0xFC, 0xD1, 0x01, 0x3B, 0xFF, 0x34, 0x00,
- 0xFE, 0xFF, 0x02, 0x00, 0x03, 0x00, 0xCA, 0xFF, 0xD4, 0x00, 0xC8,
- 0xFD, 0x2A, 0x05, 0x7D, 0xF3, 0xCA, 0x3D, 0x22, 0x20, 0x76, 0xF3,
- 0xC8, 0x06, 0x41, 0xFC, 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0xFF, 0xFF, 0x19, 0x00, 0x8E, 0xFF, 0x49, 0x01, 0x04, 0xFD,
- 0x4D, 0x06, 0x00, 0xF2, 0xFE, 0x37, 0xCB, 0x27, 0x21, 0xF2, 0x23,
- 0x07, 0x34, 0xFC, 0xDD, 0x01, 0x3F, 0xFF, 0x34, 0x00, 0xFD, 0xFF,
- 0xFD, 0xFF, 0x29, 0x00, 0x61, 0xFF, 0x9F, 0x01, 0x80, 0xFC, 0xF7,
- 0x06, 0x7D, 0xF1, 0x5A, 0x31, 0x2C, 0x2F, 0x83, 0xF1, 0x13, 0x07,
- 0x64, 0xFC, 0xB3, 0x01, 0x57, 0xFF, 0x2C, 0x00, 0xFD, 0xFF, 0xFD,
- 0xFF, 0x32, 0x00, 0x44, 0xFF, 0xD3, 0x01, 0x3C, 0xFC, 0x2A, 0x07,
- 0xDC, 0xF1, 0x1A, 0x2A, 0x06, 0x36, 0xBE, 0xF1, 0x8E, 0x06, 0xD5,
- 0xFC, 0x67, 0x01, 0x7F, 0xFF, 0x1E, 0x00, 0xFE, 0xFF, 0xFD, 0xFF,
- 0x36, 0x00, 0x37, 0xFF, 0xE6, 0x01, 0x36, 0xFC, 0xEF, 0x06, 0xFC,
- 0xF2, 0x81, 0x22, 0x1C, 0x3C, 0xEC, 0xF2, 0x90, 0x05, 0x85, 0xFD,
- 0xFB, 0x00, 0xB6, 0xFF, 0x0A, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x35,
- 0x00, 0x38, 0xFF, 0xDA, 0x01, 0x6A, 0xFC, 0x53, 0x06, 0xBA, 0xF4,
- 0xCE, 0x1A, 0x32, 0x41, 0x1F, 0xF5, 0x1D, 0x04, 0x71, 0xFE, 0x71,
- 0x00, 0xFB, 0xFF, 0xF0, 0xFF, 0x05, 0x00, 0xFF, 0xFF, 0x31, 0x00,
- 0x46, 0xFF, 0xB3, 0x01, 0xCF, 0xFC, 0x67, 0x05, 0xEA, 0xF6, 0x44,
- 0x13, 0x1E, 0x45, 0x5E, 0xF8, 0x3F, 0x02, 0x8E, 0xFF, 0xD0, 0xFF,
- 0x4A, 0x00, 0xD2, 0xFF, 0x0B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x5D,
- 0xFF, 0x76, 0x01, 0x59, 0xFD, 0x42, 0x04, 0x63, 0xF9, 0x1C, 0x0C,
- 0xB6, 0x47, 0xA4, 0xFC, 0x07, 0x00, 0xD0, 0x00, 0x20, 0xFF, 0xA0,
- 0x00, 0xB1, 0xFF, 0x13, 0x00, 0x00, 0x00, 0x21, 0x00, 0x7A, 0xFF,
- 0x2B, 0x01, 0xFE, 0xFD, 0xF8, 0x02, 0xFB, 0xFB, 0x8D, 0x05, 0xE5,
- 0x48, 0xE3, 0x01, 0x91, 0xFD, 0x25, 0x02, 0x6B, 0xFE, 0xF7, 0x00,
- 0x8F, 0xFF, 0x1C, 0x00, 0x18, 0x00, 0x9C, 0xFF, 0xD6, 0x00, 0xB1,
- 0xFE, 0xA1, 0x01, 0x89, 0xFE, 0xC3, 0xFF, 0x9C, 0x48, 0xFD, 0x07,
- 0xFA, 0xFA, 0x7A, 0x03, 0xBC, 0xFD, 0x49, 0x01, 0x6E, 0xFF, 0x24,
- 0x00, 0x00, 0x00, 0x10, 0x00, 0xBE, 0xFF, 0x7F, 0x00, 0x65, 0xFF,
- 0x51, 0x00, 0xEB, 0x00, 0xE1, 0xFA, 0xE1, 0x46, 0xCD, 0x0E, 0x6A,
- 0xF8, 0xB8, 0x04, 0x20, 0xFD, 0x90, 0x01, 0x53, 0xFF, 0x2D, 0x00,
- 0xFF, 0xFF, 0x09, 0x00, 0xDE, 0xFF, 0x2B, 0x00, 0x11, 0x00, 0x1B,
- 0xFF, 0x02, 0x03, 0xFE, 0xF6, 0xC3, 0x43, 0x22, 0x16, 0x07, 0xF6,
- 0xCA, 0x05, 0xA3, 0xFC, 0xC5, 0x01, 0x3F, 0xFF, 0x33, 0x00, 0xFF,
- 0xFF, 0x03, 0x00, 0xFB, 0xFF, 0xDF, 0xFF, 0xA9, 0x00, 0x10, 0xFE,
- 0xB9, 0x04, 0x27, 0xF4, 0x5E, 0x3F, 0xC3, 0x1D, 0xFE, 0xF3, 0x99,
- 0x06, 0x50, 0xFC, 0xE2, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF,
- 0x00, 0x00, 0x13, 0x00, 0x9F, 0xFF, 0x28, 0x01, 0x3A, 0xFD, 0x00,
- 0x06, 0x5A, 0xF2, 0xDF, 0x39, 0x73, 0x25, 0x79, 0xF2, 0x12, 0x07,
- 0x31, 0xFC, 0xE3, 0x01, 0x3B, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0xFD,
- 0xFF, 0x24, 0x00, 0x6D, 0xFF, 0x88, 0x01, 0xA2, 0xFC, 0xD0, 0x06,
- 0x8C, 0xF1, 0x78, 0x33, 0xF2, 0x2C, 0x9E, 0xF1, 0x24, 0x07, 0x4E,
- 0xFC, 0xC3, 0x01, 0x4E, 0xFF, 0x2F, 0x00, 0xFD, 0xFF, 0xFD, 0xFF,
- 0x30, 0x00, 0x4C, 0xFF, 0xC7, 0x01, 0x4A, 0xFC, 0x27, 0x07, 0xA8,
- 0xF1, 0x62, 0x2C, 0xFD, 0x33, 0x93, 0xF1, 0xC4, 0x06, 0xAB, 0xFC,
- 0x82, 0x01, 0x71, 0xFF, 0x23, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0x36,
- 0x00, 0x3A, 0xFF, 0xE4, 0x01, 0x32, 0xFC, 0x0C, 0x07, 0x91, 0xF2,
- 0xDD, 0x24, 0x54, 0x3A, 0x74, 0xF2, 0xEB, 0x05, 0x49, 0xFD, 0x20,
- 0x01, 0xA3, 0xFF, 0x11, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x36, 0x00,
- 0x37, 0xFF, 0xE1, 0x01, 0x55, 0xFC, 0x8C, 0x06, 0x22, 0xF4, 0x2C,
- 0x1D, 0xC0, 0x3F, 0x55, 0xF4, 0x9B, 0x04, 0x23, 0xFE, 0x9F, 0x00,
- 0xE4, 0xFF, 0xF9, 0xFF, 0x04, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x40,
- 0xFF, 0xC1, 0x01, 0xAB, 0xFC, 0xB7, 0x05, 0x34, 0xF6, 0x8E, 0x15,
- 0x0B, 0x44, 0x42, 0xF7, 0xDC, 0x02, 0x32, 0xFF, 0x04, 0x00, 0x31,
- 0x00, 0xDC, 0xFF, 0x09, 0x00, 0xFF, 0xFF, 0x2C, 0x00, 0x55, 0xFF,
- 0x8B, 0x01, 0x2B, 0xFD, 0xA1, 0x04, 0x9B, 0xF8, 0x42, 0x0E, 0x0F,
- 0x47, 0x38, 0xFB, 0xBE, 0x00, 0x6A, 0x00, 0x58, 0xFF, 0x85, 0x00,
- 0xBB, 0xFF, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x71, 0xFF, 0x43,
- 0x01, 0xC9, 0xFD, 0x60, 0x03, 0x2E, 0xFB, 0x7E, 0x07, 0xAF, 0x48,
- 0x2D, 0x00, 0x58, 0xFE, 0xBB, 0x01, 0xA3, 0xFE, 0xDD, 0x00, 0x99,
- 0xFF, 0x19, 0x00, 0x1B, 0x00, 0x91, 0xFF, 0xF1, 0x00, 0x79, 0xFE,
- 0x0A, 0x02, 0xC3, 0xFD, 0x73, 0x01, 0xDB, 0x48, 0x07, 0x06, 0xC7,
- 0xFB, 0x12, 0x03, 0xF1, 0xFD, 0x31, 0x01, 0x78, 0xFF, 0x22, 0x00,
- 0x00, 0x00, 0x12, 0x00, 0xB3, 0xFF, 0x99, 0x00, 0x2E, 0xFF, 0xB6,
- 0x00, 0x36, 0x00, 0x47, 0xFC, 0x90, 0x47, 0xA4, 0x0C, 0x31, 0xF9,
- 0x5A, 0x04, 0x4E, 0xFD, 0x7C, 0x01, 0x5B, 0xFF, 0x2A, 0x00, 0x00,
- 0x00, 0x0B, 0x00, 0xD5, 0xFF, 0x44, 0x00, 0xDD, 0xFF, 0x77, 0xFF,
- 0x67, 0x02, 0x14, 0xF8, 0xDC, 0x44, 0xD5, 0x13, 0xBC, 0xF6, 0x7C,
- 0x05, 0xC5, 0xFC, 0xB7, 0x01, 0x44, 0xFF, 0x31, 0x00, 0xFF, 0xFF,
- 0x05, 0x00, 0xF3, 0xFF, 0xF5, 0xFF, 0x7D, 0x00, 0x5D, 0xFE, 0x3E,
- 0x04, 0xEA, 0xF4, 0xD9, 0x40, 0x66, 0x1B, 0x93, 0xF4, 0x62, 0x06,
- 0x64, 0xFC, 0xDC, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x00,
- 0x00, 0x0C, 0x00, 0xB1, 0xFF, 0x04, 0x01, 0x76, 0xFD, 0xA8, 0x05,
- 0xCC, 0xF2, 0xAB, 0x3B, 0x18, 0x23, 0xE0, 0xF2, 0xF7, 0x06, 0x35,
- 0xFC, 0xE6, 0x01, 0x38, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFE, 0xFF,
- 0x20, 0x00, 0x7B, 0xFF, 0x6E, 0x01, 0xCA, 0xFC, 0x9D, 0x06, 0xB1,
- 0xF1, 0x86, 0x35, 0xAE, 0x2A, 0xCD, 0xF1, 0x2B, 0x07, 0x3F, 0xFC,
- 0xD1, 0x01, 0x46, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x2D,
- 0x00, 0x54, 0xFF, 0xB7, 0x01, 0x5E, 0xFC, 0x19, 0x07, 0x88, 0xF1,
- 0x9F, 0x2E, 0xE3, 0x31, 0x7E, 0xF1, 0xEE, 0x06, 0x88, 0xFC, 0x9A,
- 0x01, 0x64, 0xFF, 0x28, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x34, 0x00,
- 0x3E, 0xFF, 0xDF, 0x01, 0x33, 0xFC, 0x20, 0x07, 0x35, 0xF2, 0x36,
- 0x27, 0x78, 0x38, 0x14, 0xF2, 0x3B, 0x06, 0x11, 0xFD, 0x41, 0x01,
- 0x92, 0xFF, 0x17, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x36,
- 0xFF, 0xE5, 0x01, 0x44, 0xFC, 0xBD, 0x06, 0x97, 0xF3, 0x8A, 0x1F,
- 0x31, 0x3E, 0xA5, 0xF3, 0x0F, 0x05, 0xDA, 0xFD, 0xC9, 0x00, 0xCF,
- 0xFF, 0x01, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3C, 0xFF,
- 0xCE, 0x01, 0x8C, 0xFC, 0x00, 0x06, 0x86, 0xF5, 0xE0, 0x17, 0xDB,
- 0x42, 0x3F, 0xF6, 0x71, 0x03, 0xD9, 0xFE, 0x36, 0x00, 0x18, 0x00,
- 0xE5, 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0x2E, 0x00, 0x4E, 0xFF, 0x9E,
- 0x01, 0x00, 0xFD, 0xFC, 0x04, 0xD7, 0xF7, 0x75, 0x10, 0x48, 0x46,
- 0xE4, 0xF9, 0x6E, 0x01, 0x06, 0x00, 0x8E, 0xFF, 0x6B, 0x00, 0xC6,
- 0xFF, 0x0E, 0x00, 0x00, 0x00, 0x26, 0x00, 0x68, 0xFF, 0x5B, 0x01,
- 0x96, 0xFD, 0xC6, 0x03, 0x61, 0xFA, 0x81, 0x09, 0x57, 0x48, 0x8D,
- 0xFE, 0x1B, 0xFF, 0x52, 0x01, 0xDB, 0xFE, 0xC2, 0x00, 0xA4, 0xFF,
- 0x16, 0x00, 0x1E, 0x00, 0x87, 0xFF, 0x0B, 0x01, 0x42, 0xFE, 0x74,
- 0x02, 0xF9, 0xFC, 0x39, 0x03, 0xF5, 0x48, 0x24, 0x04, 0x94, 0xFC,
- 0xA9, 0x02, 0x27, 0xFE, 0x18, 0x01, 0x82, 0xFF, 0x1F, 0x00, 0x00,
- 0x00, 0x15, 0x00, 0xA9, 0xFF, 0xB4, 0x00, 0xF7, 0xFE, 0x1D, 0x01,
- 0x7A, 0xFF, 0xC5, 0xFD, 0x1D, 0x48, 0x89, 0x0A, 0xFB, 0xF9, 0xF8,
- 0x03, 0x7D, 0xFD, 0x66, 0x01, 0x63, 0xFF, 0x28, 0x00, 0x00, 0x00,
- 0x0D, 0x00, 0xCB, 0xFF, 0x5E, 0x00, 0xA9, 0xFF, 0xD6, 0xFF, 0xC3,
- 0x01, 0x43, 0xF9, 0xD7, 0x45, 0x92, 0x11, 0x77, 0xF7, 0x28, 0x05,
- 0xEC, 0xFC, 0xA7, 0x01, 0x4A, 0xFF, 0x2F, 0x00, 0xFF, 0xFF, 0x06,
- 0x00, 0xEA, 0xFF, 0x0C, 0x00, 0x4E, 0x00, 0xAF, 0xFE, 0xB8, 0x03,
- 0xC7, 0xF5, 0x38, 0x42, 0x0C, 0x19, 0x32, 0xF5, 0x23, 0x06, 0x7D,
- 0xFC, 0xD3, 0x01, 0x3A, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x02, 0x00,
- 0x05, 0x00, 0xC5, 0xFF, 0xDE, 0x00, 0xB7, 0xFD, 0x45, 0x05, 0x56,
- 0xF3, 0x61, 0x3D, 0xBA, 0x20, 0x56, 0xF3, 0xD3, 0x06, 0x3E, 0xFC,
- 0xE6, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFF, 0xFF, 0x1A,
- 0x00, 0x8A, 0xFF, 0x51, 0x01, 0xF8, 0xFC, 0x5E, 0x06, 0xED, 0xF1,
- 0x82, 0x37, 0x60, 0x28, 0x0E, 0xF2, 0x26, 0x07, 0x35, 0xFC, 0xDB,
- 0x01, 0x40, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x29, 0x00,
- 0x5F, 0xFF, 0xA5, 0x01, 0x78, 0xFC, 0xFF, 0x06, 0x7D, 0xF1, 0xCF,
- 0x30, 0xB8, 0x2F, 0x80, 0xF1, 0x0D, 0x07, 0x6A, 0xFC, 0xAE, 0x01,
- 0x59, 0xFF, 0x2B, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x33, 0x00, 0x43,
- 0xFF, 0xD6, 0x01, 0x39, 0xFC, 0x2A, 0x07, 0xEB, 0xF1, 0x87, 0x29,
- 0x85, 0x36, 0xCC, 0xF1, 0x7F, 0x06, 0xE0, 0xFC, 0x60, 0x01, 0x82,
- 0xFF, 0x1D, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x37, 0xFF,
- 0xE6, 0x01, 0x38, 0xFC, 0xE6, 0x06, 0x19, 0xF3, 0xEA, 0x21, 0x8A,
- 0x3C, 0x0E, 0xF3, 0x78, 0x05, 0x96, 0xFD, 0xF1, 0x00, 0xBB, 0xFF,
- 0x08, 0x00, 0x01, 0x00, 0xFE, 0xFF, 0x35, 0x00, 0x39, 0xFF, 0xD8,
- 0x01, 0x70, 0xFC, 0x43, 0x06, 0xE1, 0xF4, 0x38, 0x1A, 0x8C, 0x41,
- 0x55, 0xF5, 0xFC, 0x03, 0x85, 0xFE, 0x66, 0x00, 0x01, 0x00, 0xEE,
- 0xFF, 0x06, 0x00, 0xFF, 0xFF, 0x30, 0x00, 0x47, 0xFF, 0xAF, 0x01,
- 0xD8, 0xFC, 0x52, 0x05, 0x19, 0xF7, 0xB2, 0x12, 0x5C, 0x45, 0xA9,
- 0xF8, 0x16, 0x02, 0xA6, 0xFF, 0xC3, 0xFF, 0x51, 0x00, 0xD0, 0xFF,
- 0x0C, 0x00, 0x00, 0x00, 0x29, 0x00, 0x5F, 0xFF, 0x71, 0x01, 0x65,
- 0xFD, 0x29, 0x04, 0x96, 0xF9, 0x95, 0x0B, 0xDC, 0x47, 0x03, 0xFD,
- 0xD9, 0xFF, 0xEA, 0x00, 0x12, 0xFF, 0xA7, 0x00, 0xAE, 0xFF, 0x14,
- 0x00, 0x00, 0x00, 0x20, 0x00, 0x7D, 0xFF, 0x24, 0x01, 0x0C, 0xFE,
- 0xDE, 0x02, 0x2E, 0xFC, 0x13, 0x05, 0xEC, 0x48, 0x54, 0x02, 0x5E,
- 0xFD, 0x3F, 0x02, 0x5D, 0xFE, 0xFE, 0x00, 0x8C, 0xFF, 0x1C, 0x00,
- 0x17, 0x00, 0x9E, 0xFF, 0xCF, 0x00, 0xBF, 0xFE, 0x86, 0x01, 0xBA,
- 0xFE, 0x5A, 0xFF, 0x86, 0x48, 0x7D, 0x08, 0xC7, 0xFA, 0x93, 0x03,
- 0xB0, 0xFD, 0x4F, 0x01, 0x6C, 0xFF, 0x25, 0x00, 0x00, 0x00, 0x0F,
- 0x00, 0xC0, 0xFF, 0x78, 0x00, 0x73, 0xFF, 0x38, 0x00, 0x17, 0x01,
- 0x8B, 0xFA, 0xAF, 0x46, 0x59, 0x0F, 0x39, 0xF8, 0xCF, 0x04, 0x15,
- 0xFD, 0x95, 0x01, 0x51, 0xFF, 0x2D, 0x00, 0xFF, 0xFF, 0x08, 0x00,
- 0xE1, 0xFF, 0x25, 0x00, 0x1D, 0x00, 0x05, 0xFF, 0x28, 0x03, 0xBD,
- 0xF6, 0x77, 0x43, 0xB6, 0x16, 0xDC, 0xF5, 0xDD, 0x05, 0x9B, 0xFC,
- 0xC8, 0x01, 0x3E, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xFD,
- 0xFF, 0xD9, 0xFF, 0xB4, 0x00, 0xFD, 0xFD, 0xD7, 0x04, 0xFA, 0xF3,
- 0xFC, 0x3E, 0x5B, 0x1E, 0xDB, 0xF3, 0xA6, 0x06, 0x4C, 0xFC, 0xE3,
- 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x14, 0x00,
- 0x9B, 0xFF, 0x31, 0x01, 0x2C, 0xFD, 0x15, 0x06, 0x41, 0xF2, 0x6A,
- 0x39, 0x0A, 0x26, 0x61, 0xF2, 0x17, 0x07, 0x31, 0xFC, 0xE2, 0x01,
- 0x3B, 0xFF, 0x35, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x25, 0x00, 0x6A,
- 0xFF, 0x8E, 0x01, 0x99, 0xFC, 0xDB, 0x06, 0x86, 0xF1, 0xF2, 0x32,
- 0x82, 0x2D, 0x96, 0xF1, 0x21, 0x07, 0x53, 0xFC, 0xC0, 0x01, 0x50,
- 0xFF, 0x2E, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x30, 0x00, 0x4A, 0xFF,
- 0xCA, 0x01, 0x46, 0xFC, 0x29, 0x07, 0xB3, 0xF1, 0xD1, 0x2B, 0x81,
- 0x34, 0x9C, 0xF1, 0xB8, 0x06, 0xB5, 0xFC, 0x7C, 0x01, 0x74, 0xFF,
- 0x22, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x39, 0xFF, 0xE5,
- 0x01, 0x32, 0xFC, 0x06, 0x07, 0xAA, 0xF2, 0x46, 0x24, 0xC8, 0x3A,
- 0x90, 0xF2, 0xD6, 0x05, 0x57, 0xFD, 0x17, 0x01, 0xA8, 0xFF, 0x0F,
- 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xDF, 0x01,
- 0x5A, 0xFC, 0x7E, 0x06, 0x47, 0xF4, 0x94, 0x1C, 0x1F, 0x40, 0x85,
- 0xF4, 0x7D, 0x04, 0x36, 0xFE, 0x93, 0x00, 0xEA, 0xFF, 0xF7, 0xFF,
- 0x04, 0x00, 0xFF, 0xFF, 0x32, 0x00, 0x42, 0xFF, 0xBE, 0x01, 0xB4,
- 0xFC, 0xA4, 0x05, 0x61, 0xF6, 0xFB, 0x14, 0x53, 0x44, 0x86, 0xF7,
- 0xB6, 0x02, 0x49, 0xFF, 0xF7, 0xFF, 0x37, 0x00, 0xD9, 0xFF, 0x0A,
- 0x00, 0x00, 0x00, 0x2B, 0x00, 0x57, 0xFF, 0x86, 0x01, 0x36, 0xFD,
- 0x89, 0x04, 0xCD, 0xF8, 0xB7, 0x0D, 0x3D, 0x47, 0x91, 0xFB, 0x91,
- 0x00, 0x83, 0x00, 0x4A, 0xFF, 0x8C, 0x00, 0xB9, 0xFF, 0x11, 0x00,
- 0x00, 0x00, 0x23, 0x00, 0x73, 0xFF, 0x3D, 0x01, 0xD6, 0xFD, 0x46,
- 0x03, 0x61, 0xFB, 0x00, 0x07, 0xBF, 0x48, 0x98, 0x00, 0x26, 0xFE,
- 0xD5, 0x01, 0x95, 0xFE, 0xE3, 0x00, 0x96, 0xFF, 0x1A, 0x00, 0x1A,
- 0x00, 0x94, 0xFF, 0xEA, 0x00, 0x87, 0xFE, 0xF0, 0x01, 0xF5, 0xFD,
- 0x05, 0x01, 0xCE, 0x48, 0x83, 0x06, 0x94, 0xFB, 0x2C, 0x03, 0xE4,
- 0xFD, 0x37, 0x01, 0x76, 0xFF, 0x22, 0x00, 0x00, 0x00, 0x12, 0x00,
- 0xB6, 0xFF, 0x93, 0x00, 0x3C, 0xFF, 0x9D, 0x00, 0x63, 0x00, 0xEB,
- 0xFB, 0x69, 0x47, 0x2D, 0x0D, 0xFF, 0xF8, 0x72, 0x04, 0x42, 0xFD,
- 0x81, 0x01, 0x59, 0xFF, 0x2B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xD7,
- 0xFF, 0x3E, 0x00, 0xEA, 0xFF, 0x60, 0xFF, 0x8F, 0x02, 0xCD, 0xF7,
- 0x99, 0x44, 0x68, 0x14, 0x8E, 0xF6, 0x90, 0x05, 0xBC, 0xFC, 0xBA,
- 0x01, 0x43, 0xFF, 0x32, 0x00, 0xFF, 0xFF, 0x04, 0x00, 0xF5, 0xFF,
- 0xEF, 0xFF, 0x88, 0x00, 0x49, 0xFE, 0x5D, 0x04, 0xB7, 0xF4, 0x7D,
- 0x40, 0xFD, 0x1B, 0x6C, 0xF4, 0x70, 0x06, 0x5F, 0xFC, 0xDE, 0x01,
- 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x0E, 0x00, 0xAC,
- 0xFF, 0x0E, 0x01, 0x66, 0xFD, 0xBF, 0x05, 0xAD, 0xF2, 0x3B, 0x3B,
- 0xB0, 0x23, 0xC4, 0xF2, 0xFF, 0x06, 0x33, 0xFC, 0xE5, 0x01, 0x38,
- 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0x21, 0x00, 0x77, 0xFF,
- 0x75, 0x01, 0xBF, 0xFC, 0xAB, 0x06, 0xA6, 0xF1, 0x05, 0x35, 0x40,
- 0x2B, 0xBF, 0xF1, 0x2A, 0x07, 0x42, 0xFC, 0xCE, 0x01, 0x48, 0xFF,
- 0x31, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x2E, 0x00, 0x52, 0xFF, 0xBC,
- 0x01, 0x58, 0xFC, 0x1D, 0x07, 0x8E, 0xF1, 0x11, 0x2E, 0x6B, 0x32,
- 0x81, 0xF1, 0xE5, 0x06, 0x90, 0xFC, 0x94, 0x01, 0x67, 0xFF, 0x26,
- 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x35, 0x00, 0x3C, 0xFF, 0xE0, 0x01,
- 0x32, 0xFC, 0x1C, 0x07, 0x4B, 0xF2, 0xA0, 0x26, 0xF2, 0x38, 0x2A,
- 0xF2, 0x28, 0x06, 0x1F, 0xFD, 0x39, 0x01, 0x96, 0xFF, 0x16, 0x00,
- 0xFF, 0xFF, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE4, 0x01, 0x48,
- 0xFC, 0xB2, 0x06, 0xB9, 0xF3, 0xF3, 0x1E, 0x98, 0x3E, 0xCF, 0xF3,
- 0xF3, 0x04, 0xEB, 0xFD, 0xBF, 0x00, 0xD4, 0xFF, 0xFF, 0xFF, 0x03,
- 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3D, 0xFF, 0xCB, 0x01, 0x93, 0xFC,
- 0xEF, 0x05, 0xB0, 0xF5, 0x4B, 0x17, 0x2A, 0x43, 0x7D, 0xF6, 0x4D,
- 0x03, 0xEF, 0xFE, 0x2A, 0x00, 0x1E, 0x00, 0xE3, 0xFF, 0x08, 0x00,
- 0xFF, 0xFF, 0x2E, 0x00, 0x4F, 0xFF, 0x99, 0x01, 0x0B, 0xFD, 0xE6,
- 0x04, 0x08, 0xF8, 0xE7, 0x0F, 0x7C, 0x46, 0x37, 0xFA, 0x42, 0x01,
- 0x1F, 0x00, 0x81, 0xFF, 0x71, 0x00, 0xC3, 0xFF, 0x0F, 0x00, 0x00,
- 0x00, 0x26, 0x00, 0x6A, 0xFF, 0x55, 0x01, 0xA3, 0xFD, 0xAD, 0x03,
- 0x94, 0xFA, 0xFF, 0x08, 0x70, 0x48, 0xF3, 0xFE, 0xEA, 0xFE, 0x6C,
- 0x01, 0xCD, 0xFE, 0xC9, 0x00, 0xA1, 0xFF, 0x17, 0x00, 0x1D, 0x00,
- 0x8A, 0xFF, 0x04, 0x01, 0x50, 0xFE, 0x5A, 0x02, 0x2C, 0xFD, 0xC6,
- 0x02, 0xF2, 0x48, 0x9B, 0x04, 0x61, 0xFC, 0xC3, 0x02, 0x19, 0xFE,
- 0x1E, 0x01, 0x7F, 0xFF, 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0xAC,
- 0xFF, 0xAE, 0x00, 0x05, 0xFF, 0x03, 0x01, 0xAA, 0xFF, 0x63, 0xFD,
- 0xFD, 0x47, 0x0E, 0x0B, 0xC8, 0xF9, 0x11, 0x04, 0x71, 0xFD, 0x6C,
- 0x01, 0x61, 0xFF, 0x28, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xCD, 0xFF,
- 0x57, 0x00, 0xB6, 0xFF, 0xBE, 0xFF, 0xED, 0x01, 0xF5, 0xF8, 0x9B,
- 0x45, 0x22, 0x12, 0x48, 0xF7, 0x3D, 0x05, 0xE2, 0xFC, 0xAB, 0x01,
- 0x49, 0xFF, 0x30, 0x00, 0xFF, 0xFF, 0x06, 0x00, 0xEC, 0xFF, 0x06,
- 0x00, 0x5A, 0x00, 0x9A, 0xFE, 0xDA, 0x03, 0x8D, 0xF5, 0xE1, 0x41,
- 0xA1, 0x19, 0x09, 0xF5, 0x33, 0x06, 0x77, 0xFC, 0xD6, 0x01, 0x3A,
- 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF,
- 0xE8, 0x00, 0xA6, 0xFD, 0x5F, 0x05, 0x31, 0xF3, 0xF6, 0x3C, 0x52,
- 0x21, 0x37, 0xF3, 0xDD, 0x06, 0x3B, 0xFC, 0xE6, 0x01, 0x36, 0xFF,
- 0x36, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0x1C, 0x00, 0x86, 0xFF, 0x59,
- 0x01, 0xEC, 0xFC, 0x6F, 0x06, 0xDC, 0xF1, 0x04, 0x37, 0xF3, 0x28,
- 0xFC, 0xF1, 0x28, 0x07, 0x37, 0xFC, 0xD8, 0x01, 0x41, 0xFF, 0x33,
- 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x2A, 0x00, 0x5C, 0xFF, 0xAA, 0x01,
- 0x71, 0xFC, 0x07, 0x07, 0x7E, 0xF1, 0x44, 0x30, 0x44, 0x30, 0x7E,
- 0xF1, 0x07, 0x07, 0x71, 0xFC, 0xAA, 0x01, 0x5C, 0xFF, 0x2A, 0x00,
- 0xFD, 0xFF, 0xFD, 0xFF, 0x33, 0x00, 0x41, 0xFF, 0xD8, 0x01, 0x37,
- 0xFC, 0x28, 0x07, 0xFC, 0xF1, 0xF3, 0x28, 0x04, 0x37, 0xDC, 0xF1,
- 0x6F, 0x06, 0xEC, 0xFC, 0x59, 0x01, 0x86, 0xFF, 0x1C, 0x00, 0xFE,
- 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3B, 0xFC,
- 0xDD, 0x06, 0x37, 0xF3, 0x52, 0x21, 0xF6, 0x3C, 0x31, 0xF3, 0x5F,
- 0x05, 0xA6, 0xFD, 0xE8, 0x00, 0xC0, 0xFF, 0x07, 0x00, 0x01, 0x00,
- 0xFE, 0xFF, 0x35, 0x00, 0x3A, 0xFF, 0xD6, 0x01, 0x77, 0xFC, 0x33,
- 0x06, 0x09, 0xF5, 0xA1, 0x19, 0xE1, 0x41, 0x8D, 0xF5, 0xDA, 0x03,
- 0x9A, 0xFE, 0x5A, 0x00, 0x06, 0x00, 0xEC, 0xFF, 0x06, 0x00, 0xFF,
- 0xFF, 0x30, 0x00, 0x49, 0xFF, 0xAB, 0x01, 0xE2, 0xFC, 0x3D, 0x05,
- 0x48, 0xF7, 0x22, 0x12, 0x9B, 0x45, 0xF5, 0xF8, 0xED, 0x01, 0xBE,
- 0xFF, 0xB6, 0xFF, 0x57, 0x00, 0xCD, 0xFF, 0x0C, 0x00, 0x00, 0x00,
- 0x28, 0x00, 0x61, 0xFF, 0x6C, 0x01, 0x71, 0xFD, 0x11, 0x04, 0xC8,
- 0xF9, 0x0E, 0x0B, 0xFD, 0x47, 0x63, 0xFD, 0xAA, 0xFF, 0x03, 0x01,
- 0x05, 0xFF, 0xAE, 0x00, 0xAC, 0xFF, 0x14, 0x00, 0x00, 0x00, 0x20,
- 0x00, 0x7F, 0xFF, 0x1E, 0x01, 0x19, 0xFE, 0xC3, 0x02, 0x61, 0xFC,
- 0x9B, 0x04, 0xF2, 0x48, 0xC6, 0x02, 0x2C, 0xFD, 0x5A, 0x02, 0x50,
- 0xFE, 0x04, 0x01, 0x8A, 0xFF, 0x1D, 0x00, 0x17, 0x00, 0xA1, 0xFF,
- 0xC9, 0x00, 0xCD, 0xFE, 0x6C, 0x01, 0xEA, 0xFE, 0xF3, 0xFE, 0x70,
- 0x48, 0xFF, 0x08, 0x94, 0xFA, 0xAD, 0x03, 0xA3, 0xFD, 0x55, 0x01,
- 0x6A, 0xFF, 0x26, 0x00, 0x00, 0x00, 0x0F, 0x00, 0xC3, 0xFF, 0x71,
- 0x00, 0x81, 0xFF, 0x1F, 0x00, 0x42, 0x01, 0x37, 0xFA, 0x7C, 0x46,
- 0xE7, 0x0F, 0x08, 0xF8, 0xE6, 0x04, 0x0B, 0xFD, 0x99, 0x01, 0x4F,
- 0xFF, 0x2E, 0x00, 0xFF, 0xFF, 0x08, 0x00, 0xE3, 0xFF, 0x1E, 0x00,
- 0x2A, 0x00, 0xEF, 0xFE, 0x4D, 0x03, 0x7D, 0xF6, 0x2A, 0x43, 0x4B,
- 0x17, 0xB0, 0xF5, 0xEF, 0x05, 0x93, 0xFC, 0xCB, 0x01, 0x3D, 0xFF,
- 0x34, 0x00, 0xFE, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0xD4, 0xFF, 0xBF,
- 0x00, 0xEB, 0xFD, 0xF3, 0x04, 0xCF, 0xF3, 0x98, 0x3E, 0xF3, 0x1E,
- 0xB9, 0xF3, 0xB2, 0x06, 0x48, 0xFC, 0xE4, 0x01, 0x36, 0xFF, 0x36,
- 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x16, 0x00, 0x96, 0xFF, 0x39, 0x01,
- 0x1F, 0xFD, 0x28, 0x06, 0x2A, 0xF2, 0xF2, 0x38, 0xA0, 0x26, 0x4B,
- 0xF2, 0x1C, 0x07, 0x32, 0xFC, 0xE0, 0x01, 0x3C, 0xFF, 0x35, 0x00,
- 0xFD, 0xFF, 0xFD, 0xFF, 0x26, 0x00, 0x67, 0xFF, 0x94, 0x01, 0x90,
- 0xFC, 0xE5, 0x06, 0x81, 0xF1, 0x6B, 0x32, 0x11, 0x2E, 0x8E, 0xF1,
- 0x1D, 0x07, 0x58, 0xFC, 0xBC, 0x01, 0x52, 0xFF, 0x2E, 0x00, 0xFD,
- 0xFF, 0xFD, 0xFF, 0x31, 0x00, 0x48, 0xFF, 0xCE, 0x01, 0x42, 0xFC,
- 0x2A, 0x07, 0xBF, 0xF1, 0x40, 0x2B, 0x05, 0x35, 0xA6, 0xF1, 0xAB,
- 0x06, 0xBF, 0xFC, 0x75, 0x01, 0x77, 0xFF, 0x21, 0x00, 0xFE, 0xFF,
- 0xFD, 0xFF, 0x36, 0x00, 0x38, 0xFF, 0xE5, 0x01, 0x33, 0xFC, 0xFF,
- 0x06, 0xC4, 0xF2, 0xB0, 0x23, 0x3B, 0x3B, 0xAD, 0xF2, 0xBF, 0x05,
- 0x66, 0xFD, 0x0E, 0x01, 0xAC, 0xFF, 0x0E, 0x00, 0x00, 0x00, 0xFE,
- 0xFF, 0x36, 0x00, 0x37, 0xFF, 0xDE, 0x01, 0x5F, 0xFC, 0x70, 0x06,
- 0x6C, 0xF4, 0xFD, 0x1B, 0x7D, 0x40, 0xB7, 0xF4, 0x5D, 0x04, 0x49,
- 0xFE, 0x88, 0x00, 0xEF, 0xFF, 0xF5, 0xFF, 0x04, 0x00, 0xFF, 0xFF,
- 0x32, 0x00, 0x43, 0xFF, 0xBA, 0x01, 0xBC, 0xFC, 0x90, 0x05, 0x8E,
- 0xF6, 0x68, 0x14, 0x99, 0x44, 0xCD, 0xF7, 0x8F, 0x02, 0x60, 0xFF,
- 0xEA, 0xFF, 0x3E, 0x00, 0xD7, 0xFF, 0x0A, 0x00, 0x00, 0x00, 0x2B,
- 0x00, 0x59, 0xFF, 0x81, 0x01, 0x42, 0xFD, 0x72, 0x04, 0xFF, 0xF8,
- 0x2D, 0x0D, 0x69, 0x47, 0xEB, 0xFB, 0x63, 0x00, 0x9D, 0x00, 0x3C,
- 0xFF, 0x93, 0x00, 0xB6, 0xFF, 0x12, 0x00, 0x00, 0x00, 0x22, 0x00,
- 0x76, 0xFF, 0x37, 0x01, 0xE4, 0xFD, 0x2C, 0x03, 0x94, 0xFB, 0x83,
- 0x06, 0xCE, 0x48, 0x05, 0x01, 0xF5, 0xFD, 0xF0, 0x01, 0x87, 0xFE,
- 0xEA, 0x00, 0x94, 0xFF, 0x1A, 0x00, 0x1A, 0x00, 0x96, 0xFF, 0xE3,
- 0x00, 0x95, 0xFE, 0xD5, 0x01, 0x26, 0xFE, 0x98, 0x00, 0xBF, 0x48,
- 0x00, 0x07, 0x61, 0xFB, 0x46, 0x03, 0xD6, 0xFD, 0x3D, 0x01, 0x73,
- 0xFF, 0x23, 0x00, 0x00, 0x00, 0x11, 0x00, 0xB9, 0xFF, 0x8C, 0x00,
- 0x4A, 0xFF, 0x83, 0x00, 0x91, 0x00, 0x91, 0xFB, 0x3D, 0x47, 0xB7,
- 0x0D, 0xCD, 0xF8, 0x89, 0x04, 0x36, 0xFD, 0x86, 0x01, 0x57, 0xFF,
- 0x2B, 0x00, 0x00, 0x00, 0x0A, 0x00, 0xD9, 0xFF, 0x37, 0x00, 0xF7,
- 0xFF, 0x49, 0xFF, 0xB6, 0x02, 0x86, 0xF7, 0x53, 0x44, 0xFB, 0x14,
- 0x61, 0xF6, 0xA4, 0x05, 0xB4, 0xFC, 0xBE, 0x01, 0x42, 0xFF, 0x32,
- 0x00, 0xFF, 0xFF, 0x04, 0x00, 0xF7, 0xFF, 0xEA, 0xFF, 0x93, 0x00,
- 0x36, 0xFE, 0x7D, 0x04, 0x85, 0xF4, 0x1F, 0x40, 0x94, 0x1C, 0x47,
- 0xF4, 0x7E, 0x06, 0x5A, 0xFC, 0xDF, 0x01, 0x37, 0xFF, 0x36, 0x00,
- 0xFE, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0xA8, 0xFF, 0x17, 0x01, 0x57,
- 0xFD, 0xD6, 0x05, 0x90, 0xF2, 0xC8, 0x3A, 0x46, 0x24, 0xAA, 0xF2,
- 0x06, 0x07, 0x32, 0xFC, 0xE5, 0x01, 0x39, 0xFF, 0x36, 0x00, 0xFD,
- 0xFF, 0xFE, 0xFF, 0x22, 0x00, 0x74, 0xFF, 0x7C, 0x01, 0xB5, 0xFC,
- 0xB8, 0x06, 0x9C, 0xF1, 0x81, 0x34, 0xD1, 0x2B, 0xB3, 0xF1, 0x29,
- 0x07, 0x46, 0xFC, 0xCA, 0x01, 0x4A, 0xFF, 0x30, 0x00, 0xFD, 0xFF,
- 0xFD, 0xFF, 0x2E, 0x00, 0x50, 0xFF, 0xC0, 0x01, 0x53, 0xFC, 0x21,
- 0x07, 0x96, 0xF1, 0x82, 0x2D, 0xF2, 0x32, 0x86, 0xF1, 0xDB, 0x06,
- 0x99, 0xFC, 0x8E, 0x01, 0x6A, 0xFF, 0x25, 0x00, 0xFD, 0xFF, 0xFD,
- 0xFF, 0x35, 0x00, 0x3B, 0xFF, 0xE2, 0x01, 0x31, 0xFC, 0x17, 0x07,
- 0x61, 0xF2, 0x0A, 0x26, 0x6A, 0x39, 0x41, 0xF2, 0x15, 0x06, 0x2C,
- 0xFD, 0x31, 0x01, 0x9B, 0xFF, 0x14, 0x00, 0xFF, 0xFF, 0xFE, 0xFF,
- 0x36, 0x00, 0x36, 0xFF, 0xE3, 0x01, 0x4C, 0xFC, 0xA6, 0x06, 0xDB,
- 0xF3, 0x5B, 0x1E, 0xFC, 0x3E, 0xFA, 0xF3, 0xD7, 0x04, 0xFD, 0xFD,
- 0xB4, 0x00, 0xD9, 0xFF, 0xFD, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x33,
- 0x00, 0x3E, 0xFF, 0xC8, 0x01, 0x9B, 0xFC, 0xDD, 0x05, 0xDC, 0xF5,
- 0xB6, 0x16, 0x77, 0x43, 0xBD, 0xF6, 0x28, 0x03, 0x05, 0xFF, 0x1D,
- 0x00, 0x25, 0x00, 0xE1, 0xFF, 0x08, 0x00, 0xFF, 0xFF, 0x2D, 0x00,
- 0x51, 0xFF, 0x95, 0x01, 0x15, 0xFD, 0xCF, 0x04, 0x39, 0xF8, 0x59,
- 0x0F, 0xAF, 0x46, 0x8B, 0xFA, 0x17, 0x01, 0x38, 0x00, 0x73, 0xFF,
- 0x78, 0x00, 0xC0, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x25, 0x00, 0x6C,
- 0xFF, 0x4F, 0x01, 0xB0, 0xFD, 0x93, 0x03, 0xC7, 0xFA, 0x7D, 0x08,
- 0x86, 0x48, 0x5A, 0xFF, 0xBA, 0xFE, 0x86, 0x01, 0xBF, 0xFE, 0xCF,
- 0x00, 0x9E, 0xFF, 0x17, 0x00, 0x1C, 0x00, 0x8C, 0xFF, 0xFE, 0x00,
- 0x5D, 0xFE, 0x3F, 0x02, 0x5E, 0xFD, 0x54, 0x02, 0xEC, 0x48, 0x13,
- 0x05, 0x2E, 0xFC, 0xDE, 0x02, 0x0C, 0xFE, 0x24, 0x01, 0x7D, 0xFF,
- 0x20, 0x00, 0x00, 0x00, 0x14, 0x00, 0xAE, 0xFF, 0xA7, 0x00, 0x12,
- 0xFF, 0xEA, 0x00, 0xD9, 0xFF, 0x03, 0xFD, 0xDC, 0x47, 0x95, 0x0B,
- 0x96, 0xF9, 0x29, 0x04, 0x65, 0xFD, 0x71, 0x01, 0x5F, 0xFF, 0x29,
- 0x00, 0x00, 0x00, 0x0C, 0x00, 0xD0, 0xFF, 0x51, 0x00, 0xC3, 0xFF,
- 0xA6, 0xFF, 0x16, 0x02, 0xA9, 0xF8, 0x5C, 0x45, 0xB2, 0x12, 0x19,
- 0xF7, 0x52, 0x05, 0xD8, 0xFC, 0xAF, 0x01, 0x47, 0xFF, 0x30, 0x00,
- 0xFF, 0xFF, 0x06, 0x00, 0xEE, 0xFF, 0x01, 0x00, 0x66, 0x00, 0x85,
- 0xFE, 0xFC, 0x03, 0x55, 0xF5, 0x8C, 0x41, 0x38, 0x1A, 0xE1, 0xF4,
- 0x43, 0x06, 0x70, 0xFC, 0xD8, 0x01, 0x39, 0xFF, 0x35, 0x00, 0xFE,
- 0xFF, 0x01, 0x00, 0x08, 0x00, 0xBB, 0xFF, 0xF1, 0x00, 0x96, 0xFD,
- 0x78, 0x05, 0x0E, 0xF3, 0x8A, 0x3C, 0xEA, 0x21, 0x19, 0xF3, 0xE6,
- 0x06, 0x38, 0xFC, 0xE6, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF,
- 0xFE, 0xFF, 0x1D, 0x00, 0x82, 0xFF, 0x60, 0x01, 0xE0, 0xFC, 0x7F,
- 0x06, 0xCC, 0xF1, 0x85, 0x36, 0x87, 0x29, 0xEB, 0xF1, 0x2A, 0x07,
- 0x39, 0xFC, 0xD6, 0x01, 0x43, 0xFF, 0x33, 0x00, 0xFD, 0xFF, 0xFD,
- 0xFF, 0x2B, 0x00, 0x59, 0xFF, 0xAE, 0x01, 0x6A, 0xFC, 0x0D, 0x07,
- 0x80, 0xF1, 0xB8, 0x2F, 0xCF, 0x30, 0x7D, 0xF1, 0xFF, 0x06, 0x78,
- 0xFC, 0xA5, 0x01, 0x5F, 0xFF, 0x29, 0x00, 0xFD, 0xFF, 0xFD, 0xFF,
- 0x34, 0x00, 0x40, 0xFF, 0xDB, 0x01, 0x35, 0xFC, 0x26, 0x07, 0x0E,
- 0xF2, 0x60, 0x28, 0x82, 0x37, 0xED, 0xF1, 0x5E, 0x06, 0xF8, 0xFC,
- 0x51, 0x01, 0x8A, 0xFF, 0x1A, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x36,
- 0x00, 0x36, 0xFF, 0xE6, 0x01, 0x3E, 0xFC, 0xD3, 0x06, 0x56, 0xF3,
- 0xBA, 0x20, 0x61, 0x3D, 0x56, 0xF3, 0x45, 0x05, 0xB7, 0xFD, 0xDE,
- 0x00, 0xC5, 0xFF, 0x05, 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x35, 0x00,
- 0x3A, 0xFF, 0xD3, 0x01, 0x7D, 0xFC, 0x23, 0x06, 0x32, 0xF5, 0x0C,
- 0x19, 0x38, 0x42, 0xC7, 0xF5, 0xB8, 0x03, 0xAF, 0xFE, 0x4E, 0x00,
- 0x0C, 0x00, 0xEA, 0xFF, 0x06, 0x00, 0xFF, 0xFF, 0x2F, 0x00, 0x4A,
- 0xFF, 0xA7, 0x01, 0xEC, 0xFC, 0x28, 0x05, 0x77, 0xF7, 0x92, 0x11,
- 0xD7, 0x45, 0x43, 0xF9, 0xC3, 0x01, 0xD6, 0xFF, 0xA9, 0xFF, 0x5E,
- 0x00, 0xCB, 0xFF, 0x0D, 0x00, 0x00, 0x00, 0x28, 0x00, 0x63, 0xFF,
- 0x66, 0x01, 0x7D, 0xFD, 0xF8, 0x03, 0xFB, 0xF9, 0x89, 0x0A, 0x1D,
- 0x48, 0xC5, 0xFD, 0x7A, 0xFF, 0x1D, 0x01, 0xF7, 0xFE, 0xB4, 0x00,
- 0xA9, 0xFF, 0x15, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x82, 0xFF, 0x18,
- 0x01, 0x27, 0xFE, 0xA9, 0x02, 0x94, 0xFC, 0x24, 0x04, 0xF5, 0x48,
- 0x39, 0x03, 0xF9, 0xFC, 0x74, 0x02, 0x42, 0xFE, 0x0B, 0x01, 0x87,
- 0xFF, 0x1E, 0x00, 0x16, 0x00, 0xA4, 0xFF, 0xC2, 0x00, 0xDB, 0xFE,
- 0x52, 0x01, 0x1B, 0xFF, 0x8D, 0xFE, 0x57, 0x48, 0x81, 0x09, 0x61,
- 0xFA, 0xC6, 0x03, 0x96, 0xFD, 0x5B, 0x01, 0x68, 0xFF, 0x26, 0x00,
- 0x00, 0x00, 0x0E, 0x00, 0xC6, 0xFF, 0x6B, 0x00, 0x8E, 0xFF, 0x06,
- 0x00, 0x6E, 0x01, 0xE4, 0xF9, 0x48, 0x46, 0x75, 0x10, 0xD7, 0xF7,
- 0xFC, 0x04, 0x00, 0xFD, 0x9E, 0x01, 0x4E, 0xFF, 0x2E, 0x00, 0xFF,
- 0xFF, 0x07, 0x00, 0xE5, 0xFF, 0x18, 0x00, 0x36, 0x00, 0xD9, 0xFE,
- 0x71, 0x03, 0x3F, 0xF6, 0xDB, 0x42, 0xE0, 0x17, 0x86, 0xF5, 0x00,
- 0x06, 0x8C, 0xFC, 0xCE, 0x01, 0x3C, 0xFF, 0x34, 0x00, 0xFE, 0xFF,
- 0x02, 0x00, 0x01, 0x00, 0xCF, 0xFF, 0xC9, 0x00, 0xDA, 0xFD, 0x0F,
- 0x05, 0xA5, 0xF3, 0x31, 0x3E, 0x8A, 0x1F, 0x97, 0xF3, 0xBD, 0x06,
- 0x44, 0xFC, 0xE5, 0x01, 0x36, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFF,
- 0xFF, 0x17, 0x00, 0x92, 0xFF, 0x41, 0x01, 0x11, 0xFD, 0x3B, 0x06,
- 0x14, 0xF2, 0x78, 0x38, 0x36, 0x27, 0x35, 0xF2, 0x20, 0x07, 0x33,
- 0xFC, 0xDF, 0x01, 0x3E, 0xFF, 0x34, 0x00, 0xFD, 0xFF, 0xFD, 0xFF,
- 0x28, 0x00, 0x64, 0xFF, 0x9A, 0x01, 0x88, 0xFC, 0xEE, 0x06, 0x7E,
- 0xF1, 0xE3, 0x31, 0x9F, 0x2E, 0x88, 0xF1, 0x19, 0x07, 0x5E, 0xFC,
- 0xB7, 0x01, 0x54, 0xFF, 0x2D, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x32,
- 0x00, 0x46, 0xFF, 0xD1, 0x01, 0x3F, 0xFC, 0x2B, 0x07, 0xCD, 0xF1,
- 0xAE, 0x2A, 0x86, 0x35, 0xB1, 0xF1, 0x9D, 0x06, 0xCA, 0xFC, 0x6E,
- 0x01, 0x7B, 0xFF, 0x20, 0x00, 0xFE, 0xFF, 0xFD, 0xFF, 0x36, 0x00,
- 0x38, 0xFF, 0xE6, 0x01, 0x35, 0xFC, 0xF7, 0x06, 0xE0, 0xF2, 0x18,
- 0x23, 0xAB, 0x3B, 0xCC, 0xF2, 0xA8, 0x05, 0x76, 0xFD, 0x04, 0x01,
- 0xB1, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x38,
- 0xFF, 0xDC, 0x01, 0x64, 0xFC, 0x62, 0x06, 0x93, 0xF4, 0x66, 0x1B,
- 0xD9, 0x40, 0xEA, 0xF4, 0x3E, 0x04, 0x5D, 0xFE, 0x7D, 0x00, 0xF5,
- 0xFF, 0xF3, 0xFF, 0x05, 0x00, 0xFF, 0xFF, 0x31, 0x00, 0x44, 0xFF,
- 0xB7, 0x01, 0xC5, 0xFC, 0x7C, 0x05, 0xBC, 0xF6, 0xD5, 0x13, 0xDC,
- 0x44, 0x14, 0xF8, 0x67, 0x02, 0x77, 0xFF, 0xDD, 0xFF, 0x44, 0x00,
- 0xD5, 0xFF, 0x0B, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x5B, 0xFF, 0x7C,
- 0x01, 0x4E, 0xFD, 0x5A, 0x04, 0x31, 0xF9, 0xA4, 0x0C, 0x90, 0x47,
- 0x47, 0xFC, 0x36, 0x00, 0xB6, 0x00, 0x2E, 0xFF, 0x99, 0x00, 0xB3,
- 0xFF, 0x12, 0x00, 0x00, 0x00, 0x22, 0x00, 0x78, 0xFF, 0x31, 0x01,
- 0xF1, 0xFD, 0x12, 0x03, 0xC7, 0xFB, 0x07, 0x06, 0xDB, 0x48, 0x73,
- 0x01, 0xC3, 0xFD, 0x0A, 0x02, 0x79, 0xFE, 0xF1, 0x00, 0x91, 0xFF,
- 0x1B, 0x00, 0x19, 0x00, 0x99, 0xFF, 0xDD, 0x00, 0xA3, 0xFE, 0xBB,
- 0x01, 0x58, 0xFE, 0x2D, 0x00, 0xAF, 0x48, 0x7E, 0x07, 0x2E, 0xFB,
- 0x60, 0x03, 0xC9, 0xFD, 0x43, 0x01, 0x71, 0xFF, 0x24, 0x00, 0x00,
- 0x00, 0x10, 0x00, 0xBB, 0xFF, 0x85, 0x00, 0x58, 0xFF, 0x6A, 0x00,
- 0xBE, 0x00, 0x38, 0xFB, 0x0F, 0x47, 0x42, 0x0E, 0x9B, 0xF8, 0xA1,
- 0x04, 0x2B, 0xFD, 0x8B, 0x01, 0x55, 0xFF, 0x2C, 0x00, 0xFF, 0xFF,
- 0x09, 0x00, 0xDC, 0xFF, 0x31, 0x00, 0x04, 0x00, 0x32, 0xFF, 0xDC,
- 0x02, 0x42, 0xF7, 0x0B, 0x44, 0x8E, 0x15, 0x34, 0xF6, 0xB7, 0x05,
- 0xAB, 0xFC, 0xC1, 0x01, 0x40, 0xFF, 0x33, 0x00, 0xFF, 0xFF, 0x04,
- 0x00, 0xF9, 0xFF, 0xE4, 0xFF, 0x9F, 0x00, 0x23, 0xFE, 0x9B, 0x04,
- 0x55, 0xF4, 0xC0, 0x3F, 0x2C, 0x1D, 0x22, 0xF4, 0x8C, 0x06, 0x55,
- 0xFC, 0xE1, 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFE, 0xFF, 0x00, 0x00,
- 0x11, 0x00, 0xA3, 0xFF, 0x20, 0x01, 0x49, 0xFD, 0xEB, 0x05, 0x74,
- 0xF2, 0x54, 0x3A, 0xDD, 0x24, 0x91, 0xF2, 0x0C, 0x07, 0x32, 0xFC,
- 0xE4, 0x01, 0x3A, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0x23,
- 0x00, 0x71, 0xFF, 0x82, 0x01, 0xAB, 0xFC, 0xC4, 0x06, 0x93, 0xF1,
- 0xFD, 0x33, 0x62, 0x2C, 0xA8, 0xF1, 0x27, 0x07, 0x4A, 0xFC, 0xC7,
- 0x01, 0x4C, 0xFF, 0x30, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x2F, 0x00,
- 0x4E, 0xFF, 0xC3, 0x01, 0x4E, 0xFC, 0x24, 0x07, 0x9E, 0xF1, 0xF2,
- 0x2C, 0x78, 0x33, 0x8C, 0xF1, 0xD0, 0x06, 0xA2, 0xFC, 0x88, 0x01,
- 0x6D, 0xFF, 0x24, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x35, 0x00, 0x3B,
- 0xFF, 0xE3, 0x01, 0x31, 0xFC, 0x12, 0x07, 0x79, 0xF2, 0x73, 0x25,
- 0xDF, 0x39, 0x5A, 0xF2, 0x00, 0x06, 0x3A, 0xFD, 0x28, 0x01, 0x9F,
- 0xFF, 0x13, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x36, 0x00, 0x36, 0xFF,
- 0xE2, 0x01, 0x50, 0xFC, 0x99, 0x06, 0xFE, 0xF3, 0xC3, 0x1D, 0x5E,
- 0x3F, 0x27, 0xF4, 0xB9, 0x04, 0x10, 0xFE, 0xA9, 0x00, 0xDF, 0xFF,
- 0xFB, 0xFF, 0x03, 0x00, 0xFF, 0xFF, 0x33, 0x00, 0x3F, 0xFF, 0xC5,
- 0x01, 0xA3, 0xFC, 0xCA, 0x05, 0x07, 0xF6, 0x22, 0x16, 0xC3, 0x43,
- 0xFE, 0xF6, 0x02, 0x03, 0x1B, 0xFF, 0x11, 0x00, 0x2B, 0x00, 0xDE,
- 0xFF, 0x09, 0x00, 0xFF, 0xFF, 0x2D, 0x00, 0x53, 0xFF, 0x90, 0x01,
- 0x20, 0xFD, 0xB8, 0x04, 0x6A, 0xF8, 0xCD, 0x0E, 0xE1, 0x46, 0xE1,
- 0xFA, 0xEB, 0x00, 0x51, 0x00, 0x65, 0xFF, 0x7F, 0x00, 0xBE, 0xFF,
- 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, 0x6E, 0xFF, 0x49, 0x01, 0xBC,
- 0xFD, 0x7A, 0x03, 0xFA, 0xFA, 0xFD, 0x07, 0x9C, 0x48, 0xC3, 0xFF,
- 0x89, 0xFE, 0xA1, 0x01, 0xB1, 0xFE, 0xD6, 0x00, 0x9C, 0xFF, 0x18,
- 0x00, 0x1C, 0x00, 0x8F, 0xFF, 0xF7, 0x00, 0x6B, 0xFE, 0x25, 0x02,
- 0x91, 0xFD, 0xE3, 0x01, 0xE5, 0x48, 0x8D, 0x05, 0xFB, 0xFB, 0xF8,
- 0x02, 0xFE, 0xFD, 0x2B, 0x01, 0x7A, 0xFF, 0x21, 0x00, 0x00, 0x00,
- 0x13, 0x00, 0xB1, 0xFF, 0xA0, 0x00, 0x20, 0xFF, 0xD0, 0x00, 0x07,
- 0x00, 0xA4, 0xFC, 0xB6, 0x47, 0x1C, 0x0C, 0x63, 0xF9, 0x42, 0x04,
- 0x59, 0xFD, 0x76, 0x01, 0x5D, 0xFF, 0x2A, 0x00, 0x00, 0x00, 0x0B,
- 0x00, 0xD2, 0xFF, 0x4A, 0x00, 0xD0, 0xFF, 0x8E, 0xFF, 0x3F, 0x02,
- 0x5E, 0xF8, 0x1E, 0x45, 0x44, 0x13, 0xEA, 0xF6, 0x67, 0x05, 0xCF,
- 0xFC, 0xB3, 0x01, 0x46, 0xFF, 0x31, 0x00, 0xFF, 0xFF, 0x05, 0x00,
- 0xF0, 0xFF, 0xFB, 0xFF, 0x71, 0x00, 0x71, 0xFE, 0x1D, 0x04, 0x1F,
- 0xF5, 0x32, 0x41, 0xCE, 0x1A, 0xBA, 0xF4, 0x53, 0x06, 0x6A, 0xFC,
- 0xDA, 0x01, 0x38, 0xFF, 0x35, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x0A,
- 0x00, 0xB6, 0xFF, 0xFB, 0x00, 0x85, 0xFD, 0x90, 0x05, 0xEC, 0xF2,
- 0x1C, 0x3C, 0x81, 0x22, 0xFC, 0xF2, 0xEF, 0x06, 0x36, 0xFC, 0xE6,
- 0x01, 0x37, 0xFF, 0x36, 0x00, 0xFD, 0xFF, 0xFE, 0xFF, 0x1E, 0x00,
- 0x7F, 0xFF, 0x67, 0x01, 0xD5, 0xFC, 0x8E, 0x06, 0xBE, 0xF1, 0x06,
- 0x36, 0x1A, 0x2A, 0xDC, 0xF1, 0x2A, 0x07, 0x3C, 0xFC, 0xD3, 0x01,
- 0x44, 0xFF, 0x32, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x2C, 0x00, 0x57,
- 0xFF, 0xB3, 0x01, 0x64, 0xFC, 0x13, 0x07, 0x83, 0xF1, 0x2C, 0x2F,
- 0x5A, 0x31, 0x7D, 0xF1, 0xF7, 0x06, 0x80, 0xFC, 0x9F, 0x01, 0x61,
- 0xFF, 0x29, 0x00, 0xFD, 0xFF, 0xFD, 0xFF, 0x34, 0x00, 0x3F, 0xFF,
- 0xDD, 0x01, 0x34, 0xFC, 0x23, 0x07, 0x21, 0xF2, 0xCB, 0x27, 0xFE,
- 0x37, 0x00, 0xF2, 0x4D, 0x06, 0x04, 0xFD, 0x49, 0x01, 0x8E, 0xFF,
- 0x19, 0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0x36, 0x00, 0x36, 0xFF, 0xE6,
- 0x01, 0x41, 0xFC, 0xC8, 0x06, 0x76, 0xF3, 0x22, 0x20, 0xCA, 0x3D,
- 0x7D, 0xF3, 0x2A, 0x05, 0xC8, 0xFD, 0xD4, 0x00, 0xCA, 0xFF, 0x03,
- 0x00, 0x02, 0x00, 0xFE, 0xFF, 0x34, 0x00, 0x3B, 0xFF, 0xD1, 0x01,
- 0x84, 0xFC, 0x12, 0x06, 0x5C, 0xF5, 0x76, 0x18, 0x89, 0x42, 0x02,
- 0xF6, 0x94, 0x03, 0xC4, 0xFE, 0x42, 0x00, 0x12, 0x00, 0xE8, 0xFF,
- 0x07, 0x00, 0xFF, 0xFF, 0x2F, 0x00, 0x4C, 0xFF, 0xA2, 0x01, 0xF6,
- 0xFC, 0x12, 0x05, 0xA7, 0xF7, 0x03, 0x11, 0x10, 0x46, 0x93, 0xF9,
- 0x98, 0x01, 0xEE, 0xFF, 0x9B, 0xFF, 0x64, 0x00, 0xC8, 0xFF, 0x0E,
- 0x00, 0x00, 0x00, 0x27, 0x00, 0x65, 0xFF, 0x60, 0x01, 0x8A, 0xFD,
- 0xDF, 0x03, 0x2E, 0xFA, 0x04, 0x0A, 0x3A, 0x48, 0x28, 0xFE, 0x4B,
- 0xFF, 0x38, 0x01, 0xE9, 0xFE, 0xBB, 0x00, 0xA6, 0xFF, 0x16, 0x00,
- 0x00, 0x00, 0x1E, 0x00, 0x84, 0xFF, 0x11, 0x01, 0x34, 0xFE, 0x8F,
- 0x02, 0xC7, 0xFC, 0xAE, 0x03, 0xF7, 0x48, 0xAE, 0x03, 0xC7, 0xFC,
- 0x8F, 0x02, 0x34, 0xFE, 0x11, 0x01, 0x84, 0xFF, 0x1E, 0x00, 0x00,
- 0x00, 0xF4, 0xFF, 0x1A, 0x00, 0xFF, 0x00, 0x07, 0x03, 0x16, 0x06,
- 0x7C, 0x09, 0x2A, 0x0C, 0x2E, 0x0D, 0x2A, 0x0C, 0x7C, 0x09, 0x16,
- 0x06, 0x07, 0x03, 0xFF, 0x00, 0x1A, 0x00, 0xF4, 0xFF, 0xF2, 0xFF,
- 0xA0, 0xFF, 0x71, 0xFF, 0x71, 0x00, 0x86, 0x03, 0x73, 0x08, 0x88,
- 0x0D, 0x78, 0x10, 0xC9, 0x0F, 0xD5, 0x0B, 0x8B, 0x06, 0x28, 0x02,
- 0xDF, 0xFF, 0x6F, 0xFF, 0xC3, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0xDC,
- 0xFF, 0x80, 0xFF, 0x9A, 0xFF, 0x46, 0x01, 0x1E, 0x05, 0x5A, 0x0A,
- 0xED, 0x0E, 0xAA, 0x10, 0xAF, 0x0E, 0xFD, 0x09, 0xCB, 0x04, 0x18,
- 0x01, 0x8E, 0xFF, 0x85, 0xFF, 0xE1, 0xFF, 0xFC, 0xFF, 0xBD, 0xFF,
- 0x6D, 0xFF, 0xF6, 0xFF, 0x65, 0x02, 0xE5, 0x06, 0x2B, 0x0C, 0xF3,
- 0x0F, 0x60, 0x10, 0x3B, 0x0D, 0x16, 0x08, 0x3F, 0x03, 0x50, 0x00,
- 0x6E, 0xFF, 0xA7, 0xFF, 0xF5, 0xFF, 0xEF, 0xFF, 0x9A, 0xFF, 0x75,
- 0xFF, 0x91, 0x00, 0xC9, 0x03, 0xC8, 0x08, 0xCC, 0x0D, 0x89, 0x10,
- 0x9F, 0x0F, 0x85, 0x0B, 0x3B, 0x06, 0xF4, 0x01, 0xCD, 0xFF, 0x72,
- 0xFF, 0xC9, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xD7, 0xFF, 0x7B, 0xFF,
- 0xA5, 0xFF, 0x73, 0x01, 0x6A, 0x05, 0xAD, 0x0A, 0x21, 0x0F, 0xA6,
- 0x10, 0x74, 0x0E, 0xA9, 0x09, 0x83, 0x04, 0xF0, 0x00, 0x85, 0xFF,
- 0x8B, 0xFF, 0xE5, 0xFF, 0xFA, 0xFF, 0xB7, 0xFF, 0x6C, 0xFF, 0x0C,
- 0x00, 0x9D, 0x02, 0x37, 0x07, 0x78, 0x0C, 0x15, 0x10, 0x47, 0x10,
- 0xF3, 0x0C, 0xC2, 0x07, 0x01, 0x03, 0x35, 0x00, 0x6D, 0xFF, 0xAD,
- 0xFF, 0xF7, 0xFF, 0xEB, 0xFF, 0x94, 0xFF, 0x7A, 0xFF, 0xB3, 0x00,
- 0x0D, 0x04, 0x1C, 0x09, 0x0D, 0x0E, 0x97, 0x10, 0x73, 0x0F, 0x35,
- 0x0B, 0xEB, 0x05, 0xC1, 0x01, 0xBD, 0xFF, 0x75, 0xFF, 0xCE, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0xFF, 0x77, 0xFF, 0xB3, 0xFF, 0xA1,
- 0x01, 0xB7, 0x05, 0xFF, 0x0A, 0x53, 0x0F, 0x9E, 0x10, 0x37, 0x0E,
- 0x55, 0x09, 0x3B, 0x04, 0xCB, 0x00, 0x7E, 0xFF, 0x90, 0xFF, 0xE9,
- 0xFF, 0xF8, 0xFF, 0xB1, 0xFF, 0x6C, 0xFF, 0x24, 0x00, 0xD8, 0x02,
- 0x8A, 0x07, 0xC2, 0x0C, 0x34, 0x10, 0x2A, 0x10, 0xAA, 0x0C, 0x6F,
- 0x07, 0xC4, 0x02, 0x1C, 0x00, 0x6C, 0xFF, 0xB3, 0xFF, 0xF9, 0xFF,
- 0xE8, 0xFF, 0x8E, 0xFF, 0x80, 0xFF, 0xD7, 0x00, 0x53, 0x04, 0x71,
- 0x09, 0x4C, 0x0E, 0xA1, 0x10, 0x43, 0x0F, 0xE3, 0x0A, 0x9D, 0x05,
- 0x91, 0x01, 0xAE, 0xFF, 0x79, 0xFF, 0xD4, 0xFF, 0x00, 0x00, 0xFF,
- 0xFF, 0xCD, 0xFF, 0x74, 0xFF, 0xC2, 0xFF, 0xD2, 0x01, 0x06, 0x06,
- 0x50, 0x0B, 0x82, 0x0F, 0x93, 0x10, 0xF8, 0x0D, 0x00, 0x09, 0xF6,
- 0x03, 0xA7, 0x00, 0x78, 0xFF, 0x96, 0xFF, 0xEC, 0xFF, 0xF6, 0xFF,
- 0xAB, 0xFF, 0x6D, 0xFF, 0x3E, 0x00, 0x15, 0x03, 0xDE, 0x07, 0x0B,
- 0x0D, 0x50, 0x10, 0x0A, 0x10, 0x5E, 0x0C, 0x1C, 0x07, 0x8A, 0x02,
- 0x04, 0x00, 0x6C, 0xFF, 0xB9, 0xFF, 0xFB, 0xFF, 0xE4, 0xFF, 0x89,
- 0xFF, 0x88, 0xFF, 0xFD, 0x00, 0x9B, 0x04, 0xC5, 0x09, 0x88, 0x0E,
- 0xA8, 0x10, 0x10, 0x0F, 0x91, 0x0A, 0x50, 0x05, 0x64, 0x01, 0xA1,
- 0xFF, 0x7D, 0xFF, 0xD9, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0xFF,
- 0x71, 0xFF, 0xD3, 0xFF, 0x05, 0x02, 0x55, 0x06, 0xA0, 0x0B, 0xAD,
- 0x0F, 0x84, 0x10, 0xB6, 0x0D, 0xAC, 0x08, 0xB3, 0x03, 0x86, 0x00,
- 0x74, 0xFF, 0x9C, 0xFF, 0xF0, 0xFF, 0xF4, 0xFF, 0xA5, 0xFF, 0x6F,
- 0xFF, 0x5A, 0x00, 0x54, 0x03, 0x32, 0x08, 0x52, 0x0D, 0x68, 0x10,
- 0xE6, 0x0F, 0x11, 0x0C, 0xCA, 0x06, 0x52, 0x02, 0xEF, 0xFF, 0x6E,
- 0xFF, 0xBF, 0xFF, 0xFC, 0xFF, 0xDF, 0xFF, 0x84, 0xFF, 0x91, 0xFF,
- 0x25, 0x01, 0xE4, 0x04, 0x19, 0x0A, 0xC2, 0x0E, 0xAA, 0x10, 0xDA,
- 0x0E, 0x3E, 0x0A, 0x05, 0x05, 0x38, 0x01, 0x96, 0xFF, 0x81, 0xFF,
- 0xDD, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xC1, 0xFF, 0x6E, 0xFF, 0xE6,
- 0xFF, 0x3A, 0x02, 0xA6, 0x06, 0xEF, 0x0B, 0xD6, 0x0F, 0x71, 0x10,
- 0x71, 0x0D, 0x57, 0x08, 0x71, 0x03, 0x67, 0x00, 0x70, 0xFF, 0xA2,
- 0xFF, 0xF3, 0xFF, 0xF1, 0xFF, 0x9F, 0xFF, 0x72, 0xFF, 0x78, 0x00,
- 0x95, 0x03, 0x86, 0x08, 0x98, 0x0D, 0x7C, 0x10, 0xC0, 0x0F, 0xC3,
- 0x0B, 0x79, 0x06, 0x1C, 0x02, 0xDB, 0xFF, 0x70, 0xFF, 0xC5, 0xFF,
- 0xFE, 0xFF, 0x00, 0x00, 0xDB, 0xFF, 0x7F, 0xFF, 0x9C, 0xFF, 0x50,
- 0x01, 0x2F, 0x05, 0x6C, 0x0A, 0xF9, 0x0E, 0xA9, 0x10, 0xA2, 0x0E,
- 0xEA, 0x09, 0xBB, 0x04, 0x0F, 0x01, 0x8C, 0xFF, 0x87, 0xFF, 0xE2,
- 0xFF, 0xFC, 0xFF, 0xBC, 0xFF, 0x6D, 0xFF, 0xFA, 0xFF, 0x71, 0x02,
- 0xF7, 0x06, 0x3C, 0x0C, 0xFB, 0x0F, 0x5B, 0x10, 0x2B, 0x0D, 0x03,
- 0x08, 0x31, 0x03, 0x4A, 0x00, 0x6E, 0xFF, 0xA8, 0xFF, 0xF5, 0xFF,
- 0xEE, 0xFF, 0x99, 0xFF, 0x76, 0xFF, 0x98, 0x00, 0xD8, 0x03, 0xDB,
- 0x08, 0xDB, 0x0D, 0x8D, 0x10, 0x96, 0x0F, 0x73, 0x0B, 0x29, 0x06,
- 0xE8, 0x01, 0xC9, 0xFF, 0x72, 0xFF, 0xCA, 0xFF, 0xFE, 0xFF, 0x00,
- 0x00, 0xD6, 0xFF, 0x7A, 0xFF, 0xA8, 0xFF, 0x7D, 0x01, 0x7B, 0x05,
- 0xBF, 0x0A, 0x2D, 0x0F, 0xA5, 0x10, 0x67, 0x0E, 0x96, 0x09, 0x73,
- 0x04, 0xE7, 0x00, 0x84, 0xFF, 0x8C, 0xFF, 0xE6, 0xFF, 0xFA, 0xFF,
- 0xB6, 0xFF, 0x6C, 0xFF, 0x11, 0x00, 0xAA, 0x02, 0x4A, 0x07, 0x88,
- 0x0C, 0x1C, 0x10, 0x41, 0x10, 0xE3, 0x0C, 0xAF, 0x07, 0xF3, 0x02,
- 0x2F, 0x00, 0x6C, 0xFF, 0xAE, 0xFF, 0xF7, 0xFF, 0xEA, 0xFF, 0x93,
- 0xFF, 0x7B, 0xFF, 0xBB, 0x00, 0x1C, 0x04, 0x2F, 0x09, 0x1B, 0x0E,
- 0x9A, 0x10, 0x68, 0x0F, 0x23, 0x0B, 0xDA, 0x05, 0xB7, 0x01, 0xB9,
- 0xFF, 0x76, 0xFF, 0xD0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD1, 0xFF,
- 0x76, 0xFF, 0xB6, 0xFF, 0xAC, 0x01, 0xC8, 0x05, 0x11, 0x0B, 0x5E,
- 0x0F, 0x9C, 0x10, 0x29, 0x0E, 0x42, 0x09, 0x2C, 0x04, 0xC2, 0x00,
- 0x7D, 0xFF, 0x92, 0xFF, 0xEA, 0xFF, 0xF8, 0xFF, 0xB0, 0xFF, 0x6C,
- 0xFF, 0x29, 0x00, 0xE6, 0x02, 0x9D, 0x07, 0xD3, 0x0C, 0x3B, 0x10,
- 0x23, 0x10, 0x99, 0x0C, 0x5C, 0x07, 0xB7, 0x02, 0x16, 0x00, 0x6C,
- 0xFF, 0xB4, 0xFF, 0xF9, 0xFF, 0xE7, 0xFF, 0x8D, 0xFF, 0x82, 0xFF,
- 0xDF, 0x00, 0x63, 0x04, 0x84, 0x09, 0x59, 0x0E, 0xA3, 0x10, 0x38,
- 0x0F, 0xD1, 0x0A, 0x8C, 0x05, 0x87, 0x01, 0xAB, 0xFF, 0x79, 0xFF,
- 0xD5, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xCB, 0xFF, 0x73, 0xFF, 0xC6,
- 0xFF, 0xDD, 0x01, 0x17, 0x06, 0x62, 0x0B, 0x8C, 0x0F, 0x90, 0x10,
- 0xE9, 0x0D, 0xED, 0x08, 0xE7, 0x03, 0xA0, 0x00, 0x77, 0xFF, 0x97,
- 0xFF, 0xED, 0xFF, 0xF6, 0xFF, 0xA9, 0xFF, 0x6D, 0xFF, 0x44, 0x00,
- 0x23, 0x03, 0xF1, 0x07, 0x1B, 0x0D, 0x55, 0x10, 0x02, 0x10, 0x4D,
- 0x0C, 0x0A, 0x07, 0x7E, 0x02, 0xFF, 0xFF, 0x6D, 0xFF, 0xBA, 0xFF,
- 0xFB, 0xFF, 0xE3, 0xFF, 0x88, 0xFF, 0x8A, 0xFF, 0x06, 0x01, 0xAB,
- 0x04, 0xD8, 0x09, 0x95, 0x0E, 0xA9, 0x10, 0x05, 0x0F, 0x7F, 0x0A,
- 0x40, 0x05, 0x5A, 0x01, 0x9F, 0xFF, 0x7E, 0xFF, 0xDA, 0xFF, 0x00,
- 0x00, 0xFE, 0xFF, 0xC6, 0xFF, 0x70, 0xFF, 0xD7, 0xFF, 0x10, 0x02,
- 0x67, 0x06, 0xB1, 0x0B, 0xB7, 0x0F, 0x80, 0x10, 0xA7, 0x0D, 0x99,
- 0x08, 0xA4, 0x03, 0x7F, 0x00, 0x73, 0xFF, 0x9D, 0xFF, 0xF0, 0xFF,
- 0xF3, 0xFF, 0xA3, 0xFF, 0x70, 0xFF, 0x60, 0x00, 0x62, 0x03, 0x45,
- 0x08, 0x62, 0x0D, 0x6C, 0x10, 0xDE, 0x0F, 0x00, 0x0C, 0xB8, 0x06,
- 0x46, 0x02, 0xEA, 0xFF, 0x6E, 0xFF, 0xC0, 0xFF, 0xFD, 0xFF, 0x00,
- 0x00, 0xDE, 0xFF, 0x83, 0xFF, 0x94, 0xFF, 0x2F, 0x01, 0xF4, 0x04,
- 0x2B, 0x0A, 0xCE, 0x0E, 0xAA, 0x10, 0xCE, 0x0E, 0x2B, 0x0A, 0xF4,
- 0x04, 0x2F, 0x01, 0x94, 0xFF, 0x83, 0xFF, 0xDE, 0xFF, 0xFD, 0xFF,
- 0xC0, 0xFF, 0x6E, 0xFF, 0xEA, 0xFF, 0x46, 0x02, 0xB8, 0x06, 0x00,
- 0x0C, 0xDE, 0x0F, 0x6C, 0x10, 0x62, 0x0D, 0x45, 0x08, 0x62, 0x03,
- 0x60, 0x00, 0x70, 0xFF, 0xA3, 0xFF, 0xF3, 0xFF, 0xF0, 0xFF, 0x9D,
- 0xFF, 0x73, 0xFF, 0x7F, 0x00, 0xA4, 0x03, 0x99, 0x08, 0xA7, 0x0D,
- 0x80, 0x10, 0xB7, 0x0F, 0xB1, 0x0B, 0x67, 0x06, 0x10, 0x02, 0xD7,
- 0xFF, 0x70, 0xFF, 0xC6, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xDA, 0xFF,
- 0x7E, 0xFF, 0x9F, 0xFF, 0x5A, 0x01, 0x40, 0x05, 0x7F, 0x0A, 0x05,
- 0x0F, 0xA9, 0x10, 0x95, 0x0E, 0xD8, 0x09, 0xAB, 0x04, 0x06, 0x01,
- 0x8A, 0xFF, 0x88, 0xFF, 0xE3, 0xFF, 0xFB, 0xFF, 0xBA, 0xFF, 0x6D,
- 0xFF, 0xFF, 0xFF, 0x7E, 0x02, 0x0A, 0x07, 0x4D, 0x0C, 0x02, 0x10,
- 0x55, 0x10, 0x1B, 0x0D, 0xF1, 0x07, 0x23, 0x03, 0x44, 0x00, 0x6D,
- 0xFF, 0xA9, 0xFF, 0xF6, 0xFF, 0xED, 0xFF, 0x97, 0xFF, 0x77, 0xFF,
- 0xA0, 0x00, 0xE7, 0x03, 0xED, 0x08, 0xE9, 0x0D, 0x90, 0x10, 0x8C,
- 0x0F, 0x62, 0x0B, 0x17, 0x06, 0xDD, 0x01, 0xC6, 0xFF, 0x73, 0xFF,
- 0xCB, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xD5, 0xFF, 0x79, 0xFF, 0xAB,
- 0xFF, 0x87, 0x01, 0x8C, 0x05, 0xD1, 0x0A, 0x38, 0x0F, 0xA3, 0x10,
- 0x59, 0x0E, 0x84, 0x09, 0x63, 0x04, 0xDF, 0x00, 0x82, 0xFF, 0x8D,
- 0xFF, 0xE7, 0xFF, 0xF9, 0xFF, 0xB4, 0xFF, 0x6C, 0xFF, 0x16, 0x00,
- 0xB7, 0x02, 0x5C, 0x07, 0x99, 0x0C, 0x23, 0x10, 0x3B, 0x10, 0xD3,
- 0x0C, 0x9D, 0x07, 0xE6, 0x02, 0x29, 0x00, 0x6C, 0xFF, 0xB0, 0xFF,
- 0xF8, 0xFF, 0xEA, 0xFF, 0x92, 0xFF, 0x7D, 0xFF, 0xC2, 0x00, 0x2C,
- 0x04, 0x42, 0x09, 0x29, 0x0E, 0x9C, 0x10, 0x5E, 0x0F, 0x11, 0x0B,
- 0xC8, 0x05, 0xAC, 0x01, 0xB6, 0xFF, 0x76, 0xFF, 0xD1, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xD0, 0xFF, 0x76, 0xFF, 0xB9, 0xFF, 0xB7, 0x01,
- 0xDA, 0x05, 0x23, 0x0B, 0x68, 0x0F, 0x9A, 0x10, 0x1B, 0x0E, 0x2F,
- 0x09, 0x1C, 0x04, 0xBB, 0x00, 0x7B, 0xFF, 0x93, 0xFF, 0xEA, 0xFF,
- 0xF7, 0xFF, 0xAE, 0xFF, 0x6C, 0xFF, 0x2F, 0x00, 0xF3, 0x02, 0xAF,
- 0x07, 0xE3, 0x0C, 0x41, 0x10, 0x1C, 0x10, 0x88, 0x0C, 0x4A, 0x07,
- 0xAA, 0x02, 0x11, 0x00, 0x6C, 0xFF, 0xB6, 0xFF, 0xFA, 0xFF, 0xE6,
- 0xFF, 0x8C, 0xFF, 0x84, 0xFF, 0xE7, 0x00, 0x73, 0x04, 0x96, 0x09,
- 0x67, 0x0E, 0xA5, 0x10, 0x2D, 0x0F, 0xBF, 0x0A, 0x7B, 0x05, 0x7D,
- 0x01, 0xA8, 0xFF, 0x7A, 0xFF, 0xD6, 0xFF, 0x00, 0x00, 0xFE, 0xFF,
- 0xCA, 0xFF, 0x72, 0xFF, 0xC9, 0xFF, 0xE8, 0x01, 0x29, 0x06, 0x73,
- 0x0B, 0x96, 0x0F, 0x8D, 0x10, 0xDB, 0x0D, 0xDB, 0x08, 0xD8, 0x03,
- 0x98, 0x00, 0x76, 0xFF, 0x99, 0xFF, 0xEE, 0xFF, 0xF5, 0xFF, 0xA8,
- 0xFF, 0x6E, 0xFF, 0x4A, 0x00, 0x31, 0x03, 0x03, 0x08, 0x2B, 0x0D,
- 0x5B, 0x10, 0xFB, 0x0F, 0x3C, 0x0C, 0xF7, 0x06, 0x71, 0x02, 0xFA,
- 0xFF, 0x6D, 0xFF, 0xBC, 0xFF, 0xFC, 0xFF, 0xE2, 0xFF, 0x87, 0xFF,
- 0x8C, 0xFF, 0x0F, 0x01, 0xBB, 0x04, 0xEA, 0x09, 0xA2, 0x0E, 0xA9,
- 0x10, 0xF9, 0x0E, 0x6C, 0x0A, 0x2F, 0x05, 0x50, 0x01, 0x9C, 0xFF,
- 0x7F, 0xFF, 0xDB, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xC5, 0xFF, 0x70,
- 0xFF, 0xDB, 0xFF, 0x1C, 0x02, 0x79, 0x06, 0xC3, 0x0B, 0xC0, 0x0F,
- 0x7C, 0x10, 0x98, 0x0D, 0x86, 0x08, 0x95, 0x03, 0x78, 0x00, 0x72,
- 0xFF, 0x9F, 0xFF, 0xF1, 0xFF, 0xF3, 0xFF, 0xA2, 0xFF, 0x70, 0xFF,
- 0x67, 0x00, 0x71, 0x03, 0x57, 0x08, 0x71, 0x0D, 0x71, 0x10, 0xD6,
- 0x0F, 0xEF, 0x0B, 0xA6, 0x06, 0x3A, 0x02, 0xE6, 0xFF, 0x6E, 0xFF,
- 0xC1, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0xDD, 0xFF, 0x81, 0xFF, 0x96,
- 0xFF, 0x38, 0x01, 0x05, 0x05, 0x3E, 0x0A, 0xDA, 0x0E, 0xAA, 0x10,
- 0xC2, 0x0E, 0x19, 0x0A, 0xE4, 0x04, 0x25, 0x01, 0x91, 0xFF, 0x84,
- 0xFF, 0xDF, 0xFF, 0xFC, 0xFF, 0xBF, 0xFF, 0x6E, 0xFF, 0xEF, 0xFF,
- 0x52, 0x02, 0xCA, 0x06, 0x11, 0x0C, 0xE6, 0x0F, 0x68, 0x10, 0x52,
- 0x0D, 0x32, 0x08, 0x54, 0x03, 0x5A, 0x00, 0x6F, 0xFF, 0xA5, 0xFF,
- 0xF4, 0xFF, 0xF0, 0xFF, 0x9C, 0xFF, 0x74, 0xFF, 0x86, 0x00, 0xB3,
- 0x03, 0xAC, 0x08, 0xB6, 0x0D, 0x84, 0x10, 0xAD, 0x0F, 0xA0, 0x0B,
- 0x55, 0x06, 0x05, 0x02, 0xD3, 0xFF, 0x71, 0xFF, 0xC7, 0xFF, 0xFE,
- 0xFF, 0x00, 0x00, 0xD9, 0xFF, 0x7D, 0xFF, 0xA1, 0xFF, 0x64, 0x01,
- 0x50, 0x05, 0x91, 0x0A, 0x10, 0x0F, 0xA8, 0x10, 0x88, 0x0E, 0xC5,
- 0x09, 0x9B, 0x04, 0xFD, 0x00, 0x88, 0xFF, 0x89, 0xFF, 0xE4, 0xFF,
- 0xFB, 0xFF, 0xB9, 0xFF, 0x6C, 0xFF, 0x04, 0x00, 0x8A, 0x02, 0x1C,
- 0x07, 0x5E, 0x0C, 0x0A, 0x10, 0x50, 0x10, 0x0B, 0x0D, 0xDE, 0x07,
- 0x15, 0x03, 0x3E, 0x00, 0x6D, 0xFF, 0xAB, 0xFF, 0xF6, 0xFF, 0xEC,
- 0xFF, 0x96, 0xFF, 0x78, 0xFF, 0xA7, 0x00, 0xF6, 0x03, 0x00, 0x09,
- 0xF8, 0x0D, 0x93, 0x10, 0x82, 0x0F, 0x50, 0x0B, 0x06, 0x06, 0xD2,
- 0x01, 0xC2, 0xFF, 0x74, 0xFF, 0xCD, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
- 0xD4, 0xFF, 0x79, 0xFF, 0xAE, 0xFF, 0x91, 0x01, 0x9D, 0x05, 0xE3,
- 0x0A, 0x43, 0x0F, 0xA1, 0x10, 0x4C, 0x0E, 0x71, 0x09, 0x53, 0x04,
- 0xD7, 0x00, 0x80, 0xFF, 0x8E, 0xFF, 0xE8, 0xFF, 0xF9, 0xFF, 0xB3,
- 0xFF, 0x6C, 0xFF, 0x1C, 0x00, 0xC4, 0x02, 0x6F, 0x07, 0xAA, 0x0C,
- 0x2A, 0x10, 0x34, 0x10, 0xC2, 0x0C, 0x8A, 0x07, 0xD8, 0x02, 0x24,
- 0x00, 0x6C, 0xFF, 0xB1, 0xFF, 0xF8, 0xFF, 0xE9, 0xFF, 0x90, 0xFF,
- 0x7E, 0xFF, 0xCB, 0x00, 0x3B, 0x04, 0x55, 0x09, 0x37, 0x0E, 0x9E,
- 0x10, 0x53, 0x0F, 0xFF, 0x0A, 0xB7, 0x05, 0xA1, 0x01, 0xB3, 0xFF,
- 0x77, 0xFF, 0xD2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCE, 0xFF, 0x75,
- 0xFF, 0xBD, 0xFF, 0xC1, 0x01, 0xEB, 0x05, 0x35, 0x0B, 0x73, 0x0F,
- 0x97, 0x10, 0x0D, 0x0E, 0x1C, 0x09, 0x0D, 0x04, 0xB3, 0x00, 0x7A,
- 0xFF, 0x94, 0xFF, 0xEB, 0xFF, 0xF7, 0xFF, 0xAD, 0xFF, 0x6D, 0xFF,
- 0x35, 0x00, 0x01, 0x03, 0xC2, 0x07, 0xF3, 0x0C, 0x47, 0x10, 0x15,
- 0x10, 0x78, 0x0C, 0x37, 0x07, 0x9D, 0x02, 0x0C, 0x00, 0x6C, 0xFF,
- 0xB7, 0xFF, 0xFA, 0xFF, 0xE5, 0xFF, 0x8B, 0xFF, 0x85, 0xFF, 0xF0,
- 0x00, 0x83, 0x04, 0xA9, 0x09, 0x74, 0x0E, 0xA6, 0x10, 0x21, 0x0F,
- 0xAD, 0x0A, 0x6A, 0x05, 0x73, 0x01, 0xA5, 0xFF, 0x7B, 0xFF, 0xD7,
- 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xC9, 0xFF, 0x72, 0xFF, 0xCD, 0xFF,
- 0xF4, 0x01, 0x3B, 0x06, 0x85, 0x0B, 0x9F, 0x0F, 0x89, 0x10, 0xCC,
- 0x0D, 0xC8, 0x08, 0xC9, 0x03, 0x91, 0x00, 0x75, 0xFF, 0x9A, 0xFF,
- 0xEF, 0xFF, 0xF5, 0xFF, 0xA7, 0xFF, 0x6E, 0xFF, 0x50, 0x00, 0x3F,
- 0x03, 0x16, 0x08, 0x3B, 0x0D, 0x60, 0x10, 0xF3, 0x0F, 0x2B, 0x0C,
- 0xE5, 0x06, 0x65, 0x02, 0xF6, 0xFF, 0x6D, 0xFF, 0xBD, 0xFF, 0xFC,
- 0xFF, 0xE1, 0xFF, 0x85, 0xFF, 0x8E, 0xFF, 0x18, 0x01, 0xCB, 0x04,
- 0xFD, 0x09, 0xAF, 0x0E, 0xAA, 0x10, 0xED, 0x0E, 0x5A, 0x0A, 0x1E,
- 0x05, 0x46, 0x01, 0x9A, 0xFF, 0x80, 0xFF, 0xDC, 0xFF, 0x00, 0x00,
- 0xFD, 0xFF, 0xC3, 0xFF, 0x6F, 0xFF, 0xDF, 0xFF, 0x28, 0x02, 0x8B,
- 0x06, 0xD5, 0x0B, 0xC9, 0x0F, 0x78, 0x10, 0x88, 0x0D, 0x73, 0x08,
- 0x86, 0x03, 0x71, 0x00, 0x71, 0xFF, 0xA0, 0xFF, 0xF2, 0xFF, 0xF2,
- 0xFF, 0xA1, 0xFF, 0x71, 0xFF, 0x6E, 0x00, 0x7F, 0x03, 0x6A, 0x08,
- 0x81, 0x0D, 0x76, 0x10, 0xCD, 0x0F, 0xDD, 0x0B, 0x94, 0x06, 0x2E,
- 0x02, 0xE1, 0xFF, 0x6F, 0xFF, 0xC3, 0xFF, 0xFD, 0xFF, 0x00, 0x00,
- 0xDC, 0xFF, 0x80, 0xFF, 0x98, 0xFF, 0x42, 0x01, 0x16, 0x05, 0x50,
- 0x0A, 0xE7, 0x0E, 0xAA, 0x10, 0xB5, 0x0E, 0x06, 0x0A, 0xD3, 0x04,
- 0x1C, 0x01, 0x8F, 0xFF, 0x85, 0xFF, 0xE0, 0xFF, 0xFC, 0xFF, 0xBE,
- 0xFF, 0x6D, 0xFF, 0xF3, 0xFF, 0x5E, 0x02, 0xDC, 0x06, 0x23, 0x0C,
- 0xEF, 0x0F, 0x63, 0x10, 0x43, 0x0D, 0x1F, 0x08, 0x46, 0x03, 0x53,
- 0x00, 0x6E, 0xFF, 0xA6, 0xFF, 0xF4, 0xFF, 0xEF, 0xFF, 0x9B, 0xFF,
- 0x75, 0xFF, 0x8D, 0x00, 0xC1, 0x03, 0xBE, 0x08, 0xC4, 0x0D, 0x88,
- 0x10, 0xA4, 0x0F, 0x8E, 0x0B, 0x43, 0x06, 0xF9, 0x01, 0xCF, 0xFF,
- 0x71, 0xFF, 0xC8, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xD8, 0xFF, 0x7C,
- 0xFF, 0xA4, 0xFF, 0x6E, 0x01, 0x61, 0x05, 0xA3, 0x0A, 0x1C, 0x0F,
- 0xA7, 0x10, 0x7B, 0x0E, 0xB2, 0x09, 0x8B, 0x04, 0xF4, 0x00, 0x86,
- 0xFF, 0x8A, 0xFF, 0xE4, 0xFF, 0xFA, 0xFF, 0xB8, 0xFF, 0x6C, 0xFF,
- 0x09, 0x00, 0x97, 0x02, 0x2E, 0x07, 0x6F, 0x0C, 0x11, 0x10, 0x4A,
- 0x10, 0xFB, 0x0C, 0xCB, 0x07, 0x07, 0x03, 0x38, 0x00, 0x6D, 0xFF,
- 0xAC, 0xFF, 0xF7, 0xFF, 0xEC, 0xFF, 0x95, 0xFF, 0x79, 0xFF, 0xAF,
- 0x00, 0x05, 0x04, 0x13, 0x09, 0x06, 0x0E, 0x96, 0x10, 0x78, 0x0F,
- 0x3E, 0x0B, 0xF4, 0x05, 0xC7, 0x01, 0xBF, 0xFF, 0x74, 0xFF, 0xCE,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD2, 0xFF, 0x78, 0xFF, 0xB1, 0xFF,
- 0x9C, 0x01, 0xAE, 0x05, 0xF6, 0x0A, 0x4E, 0x0F, 0x9F, 0x10, 0x3E,
- 0x0E, 0x5E, 0x09, 0x43, 0x04, 0xCF, 0x00, 0x7F, 0xFF, 0x90, 0xFF,
- 0xE8, 0xFF, 0xF9, 0xFF, 0xB2, 0xFF, 0x6C, 0xFF, 0x21, 0x00, 0xD2,
- 0x02, 0x81, 0x07, 0xBA, 0x0C, 0x31, 0x10, 0x2E, 0x10, 0xB2, 0x0C,
- 0x78, 0x07, 0xCB, 0x02, 0x1E, 0x00, 0x6C, 0xFF, 0xB2, 0xFF, 0xF9,
- 0xFF, 0xE8, 0xFF, 0x8F, 0xFF, 0x80, 0xFF, 0xD3, 0x00, 0x4B, 0x04,
- 0x67, 0x09, 0x45, 0x0E, 0xA0, 0x10, 0x48, 0x0F, 0xEC, 0x0A, 0xA6,
- 0x05, 0x97, 0x01, 0xB0, 0xFF, 0x78, 0xFF, 0xD3, 0xFF, 0x00, 0x00,
- 0xFF, 0xFF, 0xCD, 0xFF, 0x74, 0xFF, 0xC0, 0xFF, 0xCC, 0x01, 0xFD,
- 0x05, 0x47, 0x0B, 0x7D, 0x0F, 0x94, 0x10, 0xFF, 0x0D, 0x0A, 0x09,
- 0xFE, 0x03, 0xAB, 0x00, 0x79, 0xFF, 0x95, 0xFF, 0xEC, 0xFF, 0xF7,
- 0xFF, 0xAC, 0xFF, 0x6D, 0xFF, 0x3B, 0x00, 0x0E, 0x03, 0xD5, 0x07,
- 0x03, 0x0D, 0x4D, 0x10, 0x0E, 0x10, 0x67, 0x0C, 0x25, 0x07, 0x91,
- 0x02, 0x07, 0x00, 0x6C, 0xFF, 0xB8, 0xFF, 0xFB, 0xFF, 0xE4, 0xFF,
- 0x89, 0xFF, 0x87, 0xFF, 0xF9, 0x00, 0x93, 0x04, 0xBC, 0x09, 0x82,
- 0x0E, 0xA7, 0x10, 0x16, 0x0F, 0x9A, 0x0A, 0x59, 0x05, 0x69, 0x01,
- 0xA3, 0xFF, 0x7C, 0xFF, 0xD8, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xC8,
- 0xFF, 0x71, 0xFF, 0xD1, 0xFF, 0xFF, 0x01, 0x4C, 0x06, 0x97, 0x0B,
- 0xA9, 0x0F, 0x86, 0x10, 0xBD, 0x0D, 0xB5, 0x08, 0xBA, 0x03, 0x8A,
- 0x00, 0x74, 0xFF, 0x9B, 0xFF, 0xEF, 0xFF, 0xF4, 0xFF, 0xA5, 0xFF,
- 0x6F, 0xFF, 0x57, 0x00, 0x4D, 0x03, 0x29, 0x08, 0x4B, 0x0D, 0x65,
- 0x10, 0xEB, 0x0F, 0x1A, 0x0C, 0xD3, 0x06, 0x58, 0x02, 0xF1, 0xFF,
- 0x6D, 0xFF, 0xBE, 0xFF, 0xFC, 0xFF, 0xE0, 0xFF, 0x84, 0xFF, 0x90,
- 0xFF, 0x21, 0x01, 0xDC, 0x04, 0x10, 0x0A, 0xBB, 0x0E, 0xAA, 0x10,
- 0xE1, 0x0E, 0x47, 0x0A, 0x0D, 0x05, 0x3D, 0x01, 0x97, 0xFF, 0x81,
- 0xFF, 0xDD, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xC2, 0xFF, 0x6F, 0xFF,
- 0xE4, 0xFF, 0x34, 0x02, 0x9D, 0x06, 0xE6, 0x0B, 0xD1, 0x0F, 0x73,
- 0x10, 0x79, 0x0D, 0x61, 0x08, 0x78, 0x03, 0x6A, 0x00, 0x70, 0xFF,
- 0xA1, 0xFF, 0xF2, 0xFF, 0xF1, 0xFF, 0x9F, 0xFF, 0x72, 0xFF, 0x74,
- 0x00, 0x8E, 0x03, 0x7D, 0x08, 0x90, 0x0D, 0x7A, 0x10, 0xC4, 0x0F,
- 0xCC, 0x0B, 0x82, 0x06, 0x22, 0x02, 0xDD, 0xFF, 0x6F, 0xFF, 0xC4,
- 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0xDB, 0xFF, 0x7F, 0xFF, 0x9B, 0xFF,
- 0x4B, 0x01, 0x26, 0x05, 0x63, 0x0A, 0xF3, 0x0E, 0xAA, 0x10, 0xA8,
- 0x0E, 0xF4, 0x09, 0xC3, 0x04, 0x13, 0x01, 0x8D, 0xFF, 0x86, 0xFF,
- 0xE1, 0xFF, 0xFC, 0xFF, 0xBC, 0xFF, 0x6D, 0xFF, 0xF8, 0xFF, 0x6B,
- 0x02, 0xEE, 0x06, 0x34, 0x0C, 0xF7, 0x0F, 0x5D, 0x10, 0x33, 0x0D,
- 0x0D, 0x08, 0x38, 0x03, 0x4D, 0x00, 0x6E, 0xFF, 0xA7, 0xFF, 0xF5,
- 0xFF, 0xEE, 0xFF, 0x99, 0xFF, 0x76, 0xFF, 0x94, 0x00, 0xD0, 0x03,
- 0xD1, 0x08, 0xD3, 0x0D, 0x8B, 0x10, 0x9A, 0x0F, 0x7C, 0x0B, 0x32,
- 0x06, 0xEE, 0x01, 0xCB, 0xFF, 0x72, 0xFF, 0xCA, 0xFF, 0xFE, 0xFF,
- 0x00, 0x00, 0xD6, 0xFF, 0x7B, 0xFF, 0xA7, 0xFF, 0x78, 0x01, 0x72,
- 0x05, 0xB6, 0x0A, 0x27, 0x0F, 0xA5, 0x10, 0x6E, 0x0E, 0xA0, 0x09,
- 0x7B, 0x04, 0xEC, 0x00, 0x85, 0xFF, 0x8B, 0xFF, 0xE5, 0xFF, 0xFA,
- 0xFF, 0xB6, 0xFF, 0x6C, 0xFF, 0x0E, 0x00, 0xA4, 0x02, 0x41, 0x07,
- 0x80, 0x0C, 0x19, 0x10, 0x44, 0x10, 0xEB, 0x0C, 0xB9, 0x07, 0xFA,
- 0x02, 0x32, 0x00, 0x6D, 0xFF, 0xAE, 0xFF, 0xF7, 0xFF, 0xEB, 0xFF,
- 0x93, 0xFF, 0x7B, 0xFF, 0xB7, 0x00, 0x15, 0x04, 0x26, 0x09, 0x14,
- 0x0E, 0x98, 0x10, 0x6D, 0x0F, 0x2C, 0x0B, 0xE3, 0x05, 0xBC, 0x01,
- 0xBB, 0xFF, 0x75, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD1,
- 0xFF, 0x77, 0xFF, 0xB5, 0xFF, 0xA6, 0x01, 0xC0, 0x05, 0x08, 0x0B,
- 0x58, 0x0F, 0x9D, 0x10, 0x30, 0x0E, 0x4B, 0x09, 0x34, 0x04, 0xC6,
- 0x00, 0x7D, 0xFF, 0x91, 0xFF, 0xE9, 0xFF, 0xF8, 0xFF, 0xB0, 0xFF,
- 0x6C, 0xFF, 0x27, 0x00, 0xDF, 0x02, 0x94, 0x07, 0xCA, 0x0C, 0x37,
- 0x10, 0x27, 0x10, 0xA1, 0x0C, 0x65, 0x07, 0xBE, 0x02, 0x19, 0x00,
- 0x6C, 0xFF, 0xB4, 0xFF, 0xF9, 0xFF, 0xE7, 0xFF, 0x8E, 0xFF, 0x81,
- 0xFF, 0xDB, 0x00, 0x5B, 0x04, 0x7A, 0x09, 0x53, 0x0E, 0xA2, 0x10,
- 0x3D, 0x0F, 0xDA, 0x0A, 0x95, 0x05, 0x8C, 0x01, 0xAD, 0xFF, 0x79,
- 0xFF, 0xD4, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xCC, 0xFF, 0x73, 0xFF,
- 0xC4, 0xFF, 0xD7, 0x01, 0x0E, 0x06, 0x59, 0x0B, 0x87, 0x0F, 0x91,
- 0x10, 0xF0, 0x0D, 0xF7, 0x08, 0xEF, 0x03, 0xA3, 0x00, 0x78, 0xFF,
- 0x97, 0xFF, 0xED, 0xFF, 0xF6, 0xFF, 0xAA, 0xFF, 0x6D, 0xFF, 0x41,
- 0x00, 0x1C, 0x03, 0xE7, 0x07, 0x13, 0x0D, 0x52, 0x10, 0x06, 0x10,
- 0x56, 0x0C, 0x13, 0x07, 0x84, 0x02, 0x02, 0x00, 0x6D, 0xFF, 0xBA,
- 0xFF, 0xFB, 0xFF, 0xE3, 0xFF, 0x88, 0xFF, 0x89, 0xFF, 0x01, 0x01,
- 0xA3, 0x04, 0xCE, 0x09, 0x8F, 0x0E, 0xA8, 0x10, 0x0A, 0x0F, 0x88,
- 0x0A, 0x48, 0x05, 0x5F, 0x01, 0xA0, 0xFF, 0x7D, 0xFF, 0xD9, 0xFF,
- 0x00, 0x00, 0xFE, 0xFF, 0xC7, 0xFF, 0x70, 0xFF, 0xD5, 0xFF, 0x0B,
- 0x02, 0x5E, 0x06, 0xA9, 0x0B, 0xB2, 0x0F, 0x82, 0x10, 0xAE, 0x0D,
- 0xA2, 0x08, 0xAB, 0x03, 0x82, 0x00, 0x73, 0xFF, 0x9D, 0xFF, 0xF0,
- 0xFF, 0xF3, 0xFF, 0xA4, 0xFF, 0x6F, 0xFF, 0x5D, 0x00, 0x5B, 0x03,
- 0x3B, 0x08, 0x5A, 0x0D, 0x6A, 0x10, 0xE2, 0x0F, 0x09, 0x0C, 0xC1,
- 0x06, 0x4C, 0x02, 0xEC, 0xFF, 0x6E, 0xFF, 0xC0, 0xFF, 0xFC, 0xFF,
- 0xDF, 0xFF, 0x83, 0xFF, 0x93, 0xFF, 0x2A, 0x01, 0xEC, 0x04, 0x22,
- 0x0A, 0xC8, 0x0E, 0xAB, 0x10, 0xD4, 0x0E, 0x35, 0x0A, 0xFD, 0x04,
- 0x33, 0x01, 0x95, 0xFF, 0x82, 0xFF, 0xDE, 0xFF, 0x00, 0x00, 0xFD,
- 0xFF, 0xC1, 0xFF, 0x6E, 0xFF, 0xE8, 0xFF, 0x40, 0x02, 0xAF, 0x06,
- 0xF7, 0x0B, 0xDA, 0x0F, 0x6F, 0x10, 0x6A, 0x0D, 0x4E, 0x08, 0x6A,
- 0x03, 0x64, 0x00, 0x70, 0xFF, 0xA3, 0xFF, 0xF3, 0xFF, 0xF1, 0xFF,
- 0x9E, 0xFF, 0x72, 0xFF, 0x7B, 0x00, 0x9C, 0x03, 0x90, 0x08, 0x9F,
- 0x0D, 0x7E, 0x10, 0xBB, 0x0F, 0xBA, 0x0B, 0x70, 0x06, 0x16, 0x02,
- 0xD9, 0xFF, 0x70, 0xFF, 0xC5, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xDA,
- 0xFF, 0x7E, 0xFF, 0x9D, 0xFF, 0x55, 0x01, 0x37, 0x05, 0x75, 0x0A,
- 0xFF, 0x0E, 0xA9, 0x10, 0x9C, 0x0E, 0xE1, 0x09, 0xB3, 0x04, 0x0A,
- 0x01, 0x8B, 0xFF, 0x87, 0xFF, 0xE2, 0xFF, 0xFB, 0xFF, 0xBB, 0xFF,
- 0x6D, 0xFF, 0xFD, 0xFF, 0x77, 0x02, 0x01, 0x07, 0x45, 0x0C, 0xFF,
- 0x0F, 0x58, 0x10, 0x23, 0x0D, 0xFA, 0x07, 0x2A, 0x03, 0x47, 0x00,
- 0x6E, 0xFF, 0xA9, 0xFF, 0xF5, 0xFF, 0xED, 0xFF, 0x98, 0xFF, 0x77,
- 0xFF, 0x9C, 0x00, 0xDF, 0x03, 0xE4, 0x08, 0xE2, 0x0D, 0x8E, 0x10,
- 0x91, 0x0F, 0x6B, 0x0B, 0x20, 0x06, 0xE3, 0x01, 0xC8, 0xFF, 0x73,
- 0xFF, 0xCB, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xD5, 0xFF, 0x7A, 0xFF,
- 0xAA, 0xFF, 0x82, 0x01, 0x83, 0x05, 0xC8, 0x0A, 0x32, 0x0F, 0xA4,
- 0x10, 0x60, 0x0E, 0x8D, 0x09, 0x6B, 0x04, 0xE3, 0x00, 0x83, 0xFF,
- 0x8D, 0xFF, 0xE6, 0xFF, 0xFA, 0xFF, 0xB5, 0xFF, 0x6C, 0xFF, 0x14,
- 0x00, 0xB1, 0x02, 0x53, 0x07, 0x91, 0x0C, 0x20, 0x10, 0x3E, 0x10,
- 0xDB, 0x0C, 0xA6, 0x07, 0xEC, 0x02, 0x2C, 0x00, 0x6C, 0xFF, 0xAF,
- 0xFF, 0xF8, 0xFF, 0xEA, 0xFF, 0x92, 0xFF, 0x7C, 0xFF, 0xBE, 0x00,
- 0x24, 0x04, 0x38, 0x09, 0x22, 0x0E, 0x9B, 0x10, 0x63, 0x0F, 0x1A,
- 0x0B, 0xD1, 0x05, 0xB1, 0x01, 0xB8, 0xFF, 0x76, 0xFF, 0xD0, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xFF, 0x76, 0xFF, 0xB8, 0xFF, 0xB1,
- 0x01, 0xD1, 0x05, 0x1A, 0x0B, 0x63, 0x0F, 0x9B, 0x10, 0x22, 0x0E,
- 0x38, 0x09, 0x24, 0x04, 0xBE, 0x00, 0x7C, 0xFF, 0x92, 0xFF, 0xEA,
- 0xFF, 0xF8, 0xFF, 0xAF, 0xFF, 0x6C, 0xFF, 0x2C, 0x00, 0xEC, 0x02,
- 0xA6, 0x07, 0xDB, 0x0C, 0x3E, 0x10, 0x20, 0x10, 0x91, 0x0C, 0x53,
- 0x07, 0xB1, 0x02, 0x14, 0x00, 0x6C, 0xFF, 0xB5, 0xFF, 0xFA, 0xFF,
- 0xE6, 0xFF, 0x8D, 0xFF, 0x83, 0xFF, 0xE3, 0x00, 0x6B, 0x04, 0x8D,
- 0x09, 0x60, 0x0E, 0xA4, 0x10, 0x32, 0x0F, 0xC8, 0x0A, 0x83, 0x05,
- 0x82, 0x01, 0xAA, 0xFF, 0x7A, 0xFF, 0xD5, 0xFF, 0x00, 0x00, 0xFF,
- 0xFF, 0xCB, 0xFF, 0x73, 0xFF, 0xC8, 0xFF, 0xE3, 0x01, 0x20, 0x06,
- 0x6B, 0x0B, 0x91, 0x0F, 0x8E, 0x10, 0xE2, 0x0D, 0xE4, 0x08, 0xDF,
- 0x03, 0x9C, 0x00, 0x77, 0xFF, 0x98, 0xFF, 0xED, 0xFF, 0xF5, 0xFF,
- 0xA9, 0xFF, 0x6E, 0xFF, 0x47, 0x00, 0x2A, 0x03, 0xFA, 0x07, 0x23,
- 0x0D, 0x58, 0x10, 0xFF, 0x0F, 0x45, 0x0C, 0x01, 0x07, 0x77, 0x02,
- 0xFD, 0xFF, 0x6D, 0xFF, 0xBB, 0xFF, 0xFB, 0xFF, 0xE2, 0xFF, 0x87,
- 0xFF, 0x8B, 0xFF, 0x0A, 0x01, 0xB3, 0x04, 0xE1, 0x09, 0x9C, 0x0E,
- 0xA9, 0x10, 0xFF, 0x0E, 0x75, 0x0A, 0x37, 0x05, 0x55, 0x01, 0x9D,
- 0xFF, 0x7E, 0xFF, 0xDA, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xC5, 0xFF,
- 0x70, 0xFF, 0xD9, 0xFF, 0x16, 0x02, 0x70, 0x06, 0xBA, 0x0B, 0xBB,
- 0x0F, 0x7E, 0x10, 0x9F, 0x0D, 0x90, 0x08, 0x9C, 0x03, 0x7B, 0x00,
- 0x72, 0xFF, 0x9E, 0xFF, 0xF1, 0xFF, 0xF3, 0xFF, 0xA3, 0xFF, 0x70,
- 0xFF, 0x64, 0x00, 0x6A, 0x03, 0x4E, 0x08, 0x6A, 0x0D, 0x6F, 0x10,
- 0xDA, 0x0F, 0xF7, 0x0B, 0xAF, 0x06, 0x40, 0x02, 0xE8, 0xFF, 0x6E,
- 0xFF, 0xC1, 0xFF, 0xFD, 0xFF, 0x00, 0x00, 0xDE, 0xFF, 0x82, 0xFF,
- 0x95, 0xFF, 0x33, 0x01, 0xFD, 0x04, 0x35, 0x0A, 0xD4, 0x0E, 0xAB,
- 0x10, 0xC8, 0x0E, 0x22, 0x0A, 0xEC, 0x04, 0x2A, 0x01, 0x93, 0xFF,
- 0x83, 0xFF, 0xDF, 0xFF, 0xFC, 0xFF, 0xC0, 0xFF, 0x6E, 0xFF, 0xEC,
- 0xFF, 0x4C, 0x02, 0xC1, 0x06, 0x09, 0x0C, 0xE2, 0x0F, 0x6A, 0x10,
- 0x5A, 0x0D, 0x3B, 0x08, 0x5B, 0x03, 0x5D, 0x00, 0x6F, 0xFF, 0xA4,
- 0xFF, 0xF3, 0xFF, 0xF0, 0xFF, 0x9D, 0xFF, 0x73, 0xFF, 0x82, 0x00,
- 0xAB, 0x03, 0xA2, 0x08, 0xAE, 0x0D, 0x82, 0x10, 0xB2, 0x0F, 0xA9,
- 0x0B, 0x5E, 0x06, 0x0B, 0x02, 0xD5, 0xFF, 0x70, 0xFF, 0xC7, 0xFF,
- 0xFE, 0xFF, 0x00, 0x00, 0xD9, 0xFF, 0x7D, 0xFF, 0xA0, 0xFF, 0x5F,
- 0x01, 0x48, 0x05, 0x88, 0x0A, 0x0A, 0x0F, 0xA8, 0x10, 0x8F, 0x0E,
- 0xCE, 0x09, 0xA3, 0x04, 0x01, 0x01, 0x89, 0xFF, 0x88, 0xFF, 0xE3,
- 0xFF, 0xFB, 0xFF, 0xBA, 0xFF, 0x6D, 0xFF, 0x02, 0x00, 0x84, 0x02,
- 0x13, 0x07, 0x56, 0x0C, 0x06, 0x10, 0x52, 0x10, 0x13, 0x0D, 0xE7,
- 0x07, 0x1C, 0x03, 0x41, 0x00, 0x6D, 0xFF, 0xAA, 0xFF, 0xF6, 0xFF,
- 0xED, 0xFF, 0x97, 0xFF, 0x78, 0xFF, 0xA3, 0x00, 0xEF, 0x03, 0xF7,
- 0x08, 0xF0, 0x0D, 0x91, 0x10, 0x87, 0x0F, 0x59, 0x0B, 0x0E, 0x06,
- 0xD7, 0x01, 0xC4, 0xFF, 0x73, 0xFF, 0xCC, 0xFF, 0xFF, 0xFF, 0x00,
- 0x00, 0xD4, 0xFF, 0x79, 0xFF, 0xAD, 0xFF, 0x8C, 0x01, 0x95, 0x05,
- 0xDA, 0x0A, 0x3D, 0x0F, 0xA2, 0x10, 0x53, 0x0E, 0x7A, 0x09, 0x5B,
- 0x04, 0xDB, 0x00, 0x81, 0xFF, 0x8E, 0xFF, 0xE7, 0xFF, 0xF9, 0xFF,
- 0xB4, 0xFF, 0x6C, 0xFF, 0x19, 0x00, 0xBE, 0x02, 0x65, 0x07, 0xA1,
- 0x0C, 0x27, 0x10, 0x37, 0x10, 0xCA, 0x0C, 0x94, 0x07, 0xDF, 0x02,
- 0x27, 0x00, 0x6C, 0xFF, 0xB0, 0xFF, 0xF8, 0xFF, 0xE9, 0xFF, 0x91,
- 0xFF, 0x7D, 0xFF, 0xC6, 0x00, 0x34, 0x04, 0x4B, 0x09, 0x30, 0x0E,
- 0x9D, 0x10, 0x58, 0x0F, 0x08, 0x0B, 0xC0, 0x05, 0xA6, 0x01, 0xB5,
- 0xFF, 0x77, 0xFF, 0xD1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF,
- 0x75, 0xFF, 0xBB, 0xFF, 0xBC, 0x01, 0xE3, 0x05, 0x2C, 0x0B, 0x6D,
- 0x0F, 0x98, 0x10, 0x14, 0x0E, 0x26, 0x09, 0x15, 0x04, 0xB7, 0x00,
- 0x7B, 0xFF, 0x93, 0xFF, 0xEB, 0xFF, 0xF7, 0xFF, 0xAE, 0xFF, 0x6D,
- 0xFF, 0x32, 0x00, 0xFA, 0x02, 0xB9, 0x07, 0xEB, 0x0C, 0x44, 0x10,
- 0x19, 0x10, 0x80, 0x0C, 0x41, 0x07, 0xA4, 0x02, 0x0E, 0x00, 0x6C,
- 0xFF, 0xB6, 0xFF, 0xFA, 0xFF, 0xE5, 0xFF, 0x8B, 0xFF, 0x85, 0xFF,
- 0xEC, 0x00, 0x7B, 0x04, 0xA0, 0x09, 0x6E, 0x0E, 0xA5, 0x10, 0x27,
- 0x0F, 0xB6, 0x0A, 0x72, 0x05, 0x78, 0x01, 0xA7, 0xFF, 0x7B, 0xFF,
- 0xD6, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0xCA, 0xFF, 0x72, 0xFF, 0xCB,
- 0xFF, 0xEE, 0x01, 0x32, 0x06, 0x7C, 0x0B, 0x9A, 0x0F, 0x8B, 0x10,
- 0xD3, 0x0D, 0xD1, 0x08, 0xD0, 0x03, 0x94, 0x00, 0x76, 0xFF, 0x99,
- 0xFF, 0xEE, 0xFF, 0xF5, 0xFF, 0xA7, 0xFF, 0x6E, 0xFF, 0x4D, 0x00,
- 0x38, 0x03, 0x0D, 0x08, 0x33, 0x0D, 0x5D, 0x10, 0xF7, 0x0F, 0x34,
- 0x0C, 0xEE, 0x06, 0x6B, 0x02, 0xF8, 0xFF, 0x6D, 0xFF, 0xBC, 0xFF,
- 0xFC, 0xFF, 0xE1, 0xFF, 0x86, 0xFF, 0x8D, 0xFF, 0x13, 0x01, 0xC3,
- 0x04, 0xF4, 0x09, 0xA8, 0x0E, 0xAA, 0x10, 0xF3, 0x0E, 0x63, 0x0A,
- 0x26, 0x05, 0x4B, 0x01, 0x9B, 0xFF, 0x7F, 0xFF, 0xDB, 0xFF, 0x00,
- 0x00, 0xFD, 0xFF, 0xC4, 0xFF, 0x6F, 0xFF, 0xDD, 0xFF, 0x22, 0x02,
- 0x82, 0x06, 0xCC, 0x0B, 0xC4, 0x0F, 0x7A, 0x10, 0x90, 0x0D, 0x7D,
- 0x08, 0x8E, 0x03, 0x74, 0x00, 0x72, 0xFF, 0x9F, 0xFF, 0xF1, 0xFF,
- 0xF2, 0xFF, 0xA1, 0xFF, 0x70, 0xFF, 0x6A, 0x00, 0x78, 0x03, 0x61,
- 0x08, 0x79, 0x0D, 0x73, 0x10, 0xD1, 0x0F, 0xE6, 0x0B, 0x9D, 0x06,
- 0x34, 0x02, 0xE4, 0xFF, 0x6F, 0xFF, 0xC2, 0xFF, 0xFD, 0xFF, 0x00,
- 0x00, 0xDD, 0xFF, 0x81, 0xFF, 0x97, 0xFF, 0x3D, 0x01, 0x0D, 0x05,
- 0x47, 0x0A, 0xE1, 0x0E, 0xAA, 0x10, 0xBB, 0x0E, 0x10, 0x0A, 0xDC,
- 0x04, 0x21, 0x01, 0x90, 0xFF, 0x84, 0xFF, 0xE0, 0xFF, 0xFC, 0xFF,
- 0xBE, 0xFF, 0x6D, 0xFF, 0xF1, 0xFF, 0x58, 0x02, 0xD3, 0x06, 0x1A,
- 0x0C, 0xEB, 0x0F, 0x65, 0x10, 0x4B, 0x0D, 0x29, 0x08, 0x4D, 0x03,
- 0x57, 0x00, 0x6F, 0xFF, 0xA5, 0xFF, 0xF4, 0xFF, 0xEF, 0xFF, 0x9B,
- 0xFF, 0x74, 0xFF, 0x8A, 0x00, 0xBA, 0x03, 0xB5, 0x08, 0xBD, 0x0D,
- 0x86, 0x10, 0xA9, 0x0F, 0x97, 0x0B, 0x4C, 0x06, 0xFF, 0x01, 0xD1,
- 0xFF, 0x71, 0xFF, 0xC8, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0xD8, 0xFF,
- 0x7C, 0xFF, 0xA3, 0xFF, 0x69, 0x01, 0x59, 0x05, 0x9A, 0x0A, 0x16,
- 0x0F, 0xA7, 0x10, 0x82, 0x0E, 0xBC, 0x09, 0x93, 0x04, 0xF9, 0x00,
- 0x87, 0xFF, 0x89, 0xFF, 0xE4, 0xFF, 0xFB, 0xFF, 0xB8, 0xFF, 0x6C,
- 0xFF, 0x07, 0x00, 0x91, 0x02, 0x25, 0x07, 0x67, 0x0C, 0x0E, 0x10,
- 0x4D, 0x10, 0x03, 0x0D, 0xD5, 0x07, 0x0E, 0x03, 0x3B, 0x00, 0x6D,
- 0xFF, 0xAC, 0xFF, 0xF7, 0xFF, 0xEC, 0xFF, 0x95, 0xFF, 0x79, 0xFF,
- 0xAB, 0x00, 0xFE, 0x03, 0x0A, 0x09, 0xFF, 0x0D, 0x94, 0x10, 0x7D,
- 0x0F, 0x47, 0x0B, 0xFD, 0x05, 0xCC, 0x01, 0xC0, 0xFF, 0x74, 0xFF,
- 0xCD, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xD3, 0xFF, 0x78, 0xFF, 0xB0,
- 0xFF, 0x97, 0x01, 0xA6, 0x05, 0xEC, 0x0A, 0x48, 0x0F, 0xA0, 0x10,
- 0x45, 0x0E, 0x67, 0x09, 0x4B, 0x04, 0xD3, 0x00, 0x80, 0xFF, 0x8F,
- 0xFF, 0xE8, 0xFF, 0xF9, 0xFF, 0xB2, 0xFF, 0x6C, 0xFF, 0x1E, 0x00,
- 0xCB, 0x02, 0x78, 0x07, 0xB2, 0x0C, 0x2E, 0x10, 0x31, 0x10, 0xBA,
- 0x0C, 0x81, 0x07, 0xD2, 0x02, 0x21, 0x00, 0x6C, 0xFF, 0xB2, 0xFF,
- 0xF9, 0xFF, 0xE8, 0xFF, 0x90, 0xFF, 0x7F, 0xFF, 0xCF, 0x00, 0x43,
- 0x04, 0x5E, 0x09, 0x3E, 0x0E, 0x9F, 0x10, 0x4E, 0x0F, 0xF6, 0x0A,
- 0xAE, 0x05, 0x9C, 0x01, 0xB1, 0xFF, 0x78, 0xFF, 0xD2, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xCE, 0xFF, 0x74, 0xFF, 0xBF, 0xFF, 0xC7, 0x01,
- 0xF4, 0x05, 0x3E, 0x0B, 0x78, 0x0F, 0x96, 0x10, 0x06, 0x0E, 0x13,
- 0x09, 0x05, 0x04, 0xAF, 0x00, 0x79, 0xFF, 0x95, 0xFF, 0xEC, 0xFF,
- 0xF7, 0xFF, 0xAC, 0xFF, 0x6D, 0xFF, 0x38, 0x00, 0x07, 0x03, 0xCB,
- 0x07, 0xFB, 0x0C, 0x4A, 0x10, 0x11, 0x10, 0x6F, 0x0C, 0x2E, 0x07,
- 0x97, 0x02, 0x09, 0x00, 0x6C, 0xFF, 0xB8, 0xFF, 0xFA, 0xFF, 0xE4,
- 0xFF, 0x8A, 0xFF, 0x86, 0xFF, 0xF4, 0x00, 0x8B, 0x04, 0xB2, 0x09,
- 0x7B, 0x0E, 0xA7, 0x10, 0x1C, 0x0F, 0xA3, 0x0A, 0x61, 0x05, 0x6E,
- 0x01, 0xA4, 0xFF, 0x7C, 0xFF, 0xD8, 0xFF, 0x00, 0x00, 0xFE, 0xFF,
- 0xC8, 0xFF, 0x71, 0xFF, 0xCF, 0xFF, 0xF9, 0x01, 0x43, 0x06, 0x8E,
- 0x0B, 0xA4, 0x0F, 0x88, 0x10, 0xC4, 0x0D, 0xBE, 0x08, 0xC1, 0x03,
- 0x8D, 0x00, 0x75, 0xFF, 0x9B, 0xFF, 0xEF, 0xFF, 0xF4, 0xFF, 0xA6,
- 0xFF, 0x6E, 0xFF, 0x53, 0x00, 0x46, 0x03, 0x1F, 0x08, 0x43, 0x0D,
- 0x63, 0x10, 0xEF, 0x0F, 0x23, 0x0C, 0xDC, 0x06, 0x5E, 0x02, 0xF3,
- 0xFF, 0x6D, 0xFF, 0xBE, 0xFF, 0xFC, 0xFF, 0xE0, 0xFF, 0x85, 0xFF,
- 0x8F, 0xFF, 0x1C, 0x01, 0xD3, 0x04, 0x06, 0x0A, 0xB5, 0x0E, 0xAA,
- 0x10, 0xE7, 0x0E, 0x50, 0x0A, 0x16, 0x05, 0x42, 0x01, 0x98, 0xFF,
- 0x80, 0xFF, 0xDC, 0xFF, 0x00, 0x00, 0xFD, 0xFF, 0xC3, 0xFF, 0x6F,
- 0xFF, 0xE1, 0xFF, 0x2E, 0x02, 0x94, 0x06, 0xDD, 0x0B, 0xCD, 0x0F,
- 0x76, 0x10, 0x81, 0x0D, 0x6A, 0x08, 0x7F, 0x03, 0x6E, 0x00, 0x71,
- 0xFF, 0xA1, 0xFF, 0xF2, 0xFF, 0x00, 0x00, 0x15, 0x00, 0xD1, 0xFF,
- 0x8B, 0xFE, 0xBC, 0xFD, 0xE1, 0x00, 0x84, 0x09, 0xB0, 0x13, 0x47,
- 0x18, 0xB0, 0x13, 0x84, 0x09, 0xE1, 0x00, 0xBC, 0xFD, 0x8B, 0xFE,
- 0xD1, 0xFF, 0x15, 0x00, 0xFD, 0xFF, 0x13, 0x00, 0xDA, 0x00, 0x30,
- 0x00, 0x5D, 0xFC, 0xB3, 0xFC, 0x35, 0x0A, 0xC2, 0x1C, 0x24, 0x20,
- 0x48, 0x10, 0x5D, 0xFF, 0x74, 0xFB, 0x3A, 0xFF, 0xFB, 0x00, 0x42,
- 0x00, 0xF8, 0xFF, 0xFA, 0xFF, 0x2C, 0x00, 0xF3, 0x00, 0xAD, 0xFF,
- 0xC5, 0xFB, 0x11, 0xFE, 0xAF, 0x0D, 0xEF, 0x1E, 0x68, 0x1E, 0xBC,
- 0x0C, 0xA7, 0xFD, 0xEA, 0xFB, 0xD3, 0xFF, 0xEE, 0x00, 0x24, 0x00,
- 0xFA, 0xFF, 0xF7, 0xFF, 0x4C, 0x00, 0xFB, 0x00, 0x0C, 0xFF, 0x5F,
- 0xFB, 0xE8, 0xFF, 0x3D, 0x11, 0x7E, 0x20, 0x13, 0x1C, 0x4C, 0x09,
- 0x6A, 0xFC, 0x8C, 0xFC, 0x4E, 0x00, 0xD1, 0x00, 0x0E, 0x00, 0xFD,
- 0xFF, 0xF7, 0xFF, 0x72, 0x00, 0xEC, 0x00, 0x55, 0xFE, 0x3D, 0xFB,
- 0x37, 0x02, 0xBE, 0x14, 0x5D, 0x21, 0x40, 0x19, 0x18, 0x06, 0xA2,
- 0xFB, 0x47, 0xFD, 0xA7, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0xFC, 0xFF, 0x9B, 0x00, 0xC0, 0x00, 0x92, 0xFD, 0x73,
- 0xFB, 0xF2, 0x04, 0x0E, 0x18, 0x81, 0x21, 0x0C, 0x16, 0x37, 0x03,
- 0x47, 0xFB, 0x0B, 0xFE, 0xDF, 0x00, 0x82, 0x00, 0xF9, 0xFF, 0xFE,
- 0xFF, 0x08, 0x00, 0xC3, 0x00, 0x74, 0x00, 0xD2, 0xFC, 0x10, 0xFC,
- 0x08, 0x08, 0x0A, 0x1B, 0xE9, 0x20, 0x9A, 0x12, 0xBE, 0x00, 0x49,
- 0xFB, 0xC8, 0xFE, 0xF9, 0x00, 0x5A, 0x00, 0xF7, 0xFF, 0xFC, 0xFF,
- 0x1B, 0x00, 0xE4, 0x00, 0x06, 0x00, 0x24, 0xFC, 0x1E, 0xFD, 0x65,
- 0x0B, 0x94, 0x1D, 0x9D, 0x1F, 0x0D, 0x0F, 0xB8, 0xFE, 0x96, 0xFB,
- 0x72, 0xFF, 0xF9, 0x00, 0x37, 0x00, 0xF8, 0xFF, 0xF9, 0xFF, 0x36,
- 0x00, 0xF8, 0x00, 0x78, 0xFF, 0x9B, 0xFB, 0xA6, 0xFE, 0xE9, 0x0E,
- 0x8D, 0x1F, 0xAA, 0x1D, 0x87, 0x0B, 0x2B, 0xFD, 0x1E, 0xFC, 0x02,
- 0x00, 0xE5, 0x00, 0x1C, 0x00, 0xFB, 0xFF, 0xF7, 0xFF, 0x58, 0x00,
- 0xF9, 0x00, 0xCF, 0xFE, 0x4A, 0xFB, 0xA7, 0x00, 0x77, 0x12, 0xE0,
- 0x20, 0x26, 0x1B, 0x28, 0x08, 0x18, 0xFC, 0xCB, 0xFC, 0x71, 0x00,
- 0xC5, 0x00, 0x08, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0x80, 0x00, 0xE1,
- 0x00, 0x13, 0xFE, 0x45, 0xFB, 0x1D, 0x03, 0xEB, 0x15, 0x7F, 0x21,
- 0x2D, 0x18, 0x0E, 0x05, 0x77, 0xFB, 0x8B, 0xFD, 0xBE, 0x00, 0x9D,
- 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xA9, 0x00,
- 0xAA, 0x00, 0x4F, 0xFD, 0x9D, 0xFB, 0xFA, 0x05, 0x22, 0x19, 0x62,
- 0x21, 0xE0, 0x14, 0x50, 0x02, 0x3E, 0xFB, 0x4E, 0xFE, 0xEB, 0x00,
- 0x73, 0x00, 0xF7, 0xFF, 0xFE, 0xFF, 0x0D, 0x00, 0xD0, 0x00, 0x52,
- 0x00, 0x93, 0xFC, 0x60, 0xFC, 0x2C, 0x09, 0xFA, 0x1B, 0x8A, 0x20,
- 0x60, 0x11, 0xFD, 0xFF, 0x5C, 0xFB, 0x06, 0xFF, 0xFB, 0x00, 0x4D,
- 0x00, 0xF7, 0xFF, 0xFA, 0xFF, 0x23, 0x00, 0xED, 0x00, 0xD9, 0xFF,
- 0xEF, 0xFB, 0x98, 0xFD, 0x99, 0x0C, 0x54, 0x1E, 0x02, 0x1F, 0xD2,
- 0x0D, 0x20, 0xFE, 0xC0, 0xFB, 0xA7, 0xFF, 0xF4, 0x00, 0x2D, 0x00,
- 0xF9, 0xFF, 0xF8, 0xFF, 0x41, 0x00, 0xFB, 0x00, 0x41, 0xFF, 0x78,
- 0xFB, 0x4A, 0xFF, 0x25, 0x10, 0x16, 0x20, 0xDA, 0x1C, 0x56, 0x0A,
- 0xBE, 0xFC, 0x56, 0xFC, 0x2C, 0x00, 0xDB, 0x00, 0x14, 0x00, 0xFD,
- 0xFF, 0xF7, 0xFF, 0x66, 0x00, 0xF4, 0x00, 0x8F, 0xFE, 0x3F, 0xFB,
- 0x75, 0x01, 0xAE, 0x13, 0x2C, 0x21, 0x2A, 0x1A, 0x0D, 0x07, 0xD4,
- 0xFB, 0x0C, 0xFD, 0x8F, 0x00, 0xB7, 0x00, 0x03, 0x00, 0xFF, 0xFF,
- 0x00, 0x00, 0xFA, 0xFF, 0x8E, 0x00, 0xD1, 0x00, 0xCF, 0xFD, 0x58,
- 0xFB, 0x10, 0x04, 0x10, 0x17, 0x8A, 0x21, 0x10, 0x17, 0x10, 0x04,
- 0x58, 0xFB, 0xCF, 0xFD, 0xD1, 0x00, 0x8E, 0x00, 0xFA, 0xFF, 0xFF,
- 0xFF, 0x03, 0x00, 0xB7, 0x00, 0x8F, 0x00, 0x0C, 0xFD, 0xD4, 0xFB,
- 0x0D, 0x07, 0x2A, 0x1A, 0x2C, 0x21, 0xAE, 0x13, 0x75, 0x01, 0x3F,
- 0xFB, 0x8F, 0xFE, 0xF4, 0x00, 0x66, 0x00, 0xF7, 0xFF, 0xFD, 0xFF,
- 0x14, 0x00, 0xDB, 0x00, 0x2C, 0x00, 0x56, 0xFC, 0xBE, 0xFC, 0x56,
- 0x0A, 0xDA, 0x1C, 0x16, 0x20, 0x25, 0x10, 0x4A, 0xFF, 0x78, 0xFB,
- 0x41, 0xFF, 0xFB, 0x00, 0x41, 0x00, 0xF8, 0xFF, 0xF9, 0xFF, 0x2D,
- 0x00, 0xF4, 0x00, 0xA7, 0xFF, 0xC0, 0xFB, 0x20, 0xFE, 0xD2, 0x0D,
- 0x02, 0x1F, 0x54, 0x1E, 0x99, 0x0C, 0x98, 0xFD, 0xEF, 0xFB, 0xD9,
- 0xFF, 0xED, 0x00, 0x23, 0x00, 0xFA, 0xFF, 0xF7, 0xFF, 0x4D, 0x00,
- 0xFB, 0x00, 0x06, 0xFF, 0x5C, 0xFB, 0xFD, 0xFF, 0x60, 0x11, 0x8A,
- 0x20, 0xFA, 0x1B, 0x2C, 0x09, 0x60, 0xFC, 0x93, 0xFC, 0x52, 0x00,
- 0xD0, 0x00, 0x0D, 0x00, 0xFE, 0xFF, 0xF7, 0xFF, 0x73, 0x00, 0xEB,
- 0x00, 0x4E, 0xFE, 0x3E, 0xFB, 0x50, 0x02, 0xE0, 0x14, 0x62, 0x21,
- 0x22, 0x19, 0xFA, 0x05, 0x9D, 0xFB, 0x4F, 0xFD, 0xAA, 0x00, 0xA9,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0x9D, 0x00,
- 0xBE, 0x00, 0x8B, 0xFD, 0x77, 0xFB, 0x0E, 0x05, 0x2D, 0x18, 0x7F,
- 0x21, 0xEB, 0x15, 0x1D, 0x03, 0x45, 0xFB, 0x13, 0xFE, 0xE1, 0x00,
- 0x80, 0x00, 0xF8, 0xFF, 0xFE, 0xFF, 0x08, 0x00, 0xC5, 0x00, 0x71,
- 0x00, 0xCB, 0xFC, 0x18, 0xFC, 0x28, 0x08, 0x26, 0x1B, 0xE0, 0x20,
- 0x77, 0x12, 0xA7, 0x00, 0x4A, 0xFB, 0xCF, 0xFE, 0xF9, 0x00, 0x58,
- 0x00, 0xF7, 0xFF, 0xFB, 0xFF, 0x1C, 0x00, 0xE5, 0x00, 0x02, 0x00,
- 0x1E, 0xFC, 0x2B, 0xFD, 0x87, 0x0B, 0xAA, 0x1D, 0x8D, 0x1F, 0xE9,
- 0x0E, 0xA6, 0xFE, 0x9B, 0xFB, 0x78, 0xFF, 0xF8, 0x00, 0x36, 0x00,
- 0xF9, 0xFF, 0xF8, 0xFF, 0x37, 0x00, 0xF9, 0x00, 0x72, 0xFF, 0x96,
- 0xFB, 0xB8, 0xFE, 0x0D, 0x0F, 0x9D, 0x1F, 0x94, 0x1D, 0x65, 0x0B,
- 0x1E, 0xFD, 0x24, 0xFC, 0x06, 0x00, 0xE4, 0x00, 0x1B, 0x00, 0xFC,
- 0xFF, 0xF7, 0xFF, 0x5A, 0x00, 0xF9, 0x00, 0xC8, 0xFE, 0x49, 0xFB,
- 0xBE, 0x00, 0x9A, 0x12, 0xE9, 0x20, 0x0A, 0x1B, 0x08, 0x08, 0x10,
- 0xFC, 0xD2, 0xFC, 0x74, 0x00, 0xC3, 0x00, 0x08, 0x00, 0xFE, 0xFF,
- 0xF9, 0xFF, 0x82, 0x00, 0xDF, 0x00, 0x0B, 0xFE, 0x47, 0xFB, 0x37,
- 0x03, 0x0C, 0x16, 0x81, 0x21, 0x0E, 0x18, 0xF2, 0x04, 0x73, 0xFB,
- 0x92, 0xFD, 0xC0, 0x00, 0x9B, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xAB, 0x00, 0xA7, 0x00, 0x47, 0xFD, 0xA2, 0xFB,
- 0x18, 0x06, 0x40, 0x19, 0x5D, 0x21, 0xBE, 0x14, 0x37, 0x02, 0x3D,
- 0xFB, 0x55, 0xFE, 0xEC, 0x00, 0x72, 0x00, 0xF7, 0xFF, 0xFD, 0xFF,
- 0x0E, 0x00, 0xD1, 0x00, 0x4E, 0x00, 0x8C, 0xFC, 0x6A, 0xFC, 0x4C,
- 0x09, 0x13, 0x1C, 0x7E, 0x20, 0x3D, 0x11, 0xE8, 0xFF, 0x5F, 0xFB,
- 0x0C, 0xFF, 0xFB, 0x00, 0x4C, 0x00, 0xF7, 0xFF, 0xFA, 0xFF, 0x24,
- 0x00, 0xEE, 0x00, 0xD3, 0xFF, 0xEA, 0xFB, 0xA7, 0xFD, 0xBC, 0x0C,
- 0x68, 0x1E, 0xEF, 0x1E, 0xAF, 0x0D, 0x11, 0xFE, 0xC5, 0xFB, 0xAD,
- 0xFF, 0xF3, 0x00, 0x2C, 0x00, 0xFA, 0xFF, 0xF8, 0xFF, 0x42, 0x00,
- 0xFB, 0x00, 0x3A, 0xFF, 0x74, 0xFB, 0x5D, 0xFF, 0x48, 0x10, 0x24,
- 0x20, 0xC2, 0x1C, 0x35, 0x0A, 0xB3, 0xFC, 0x5D, 0xFC, 0x30, 0x00,
- 0xDA, 0x00, 0x13, 0x00, 0xFD, 0xFF, 0xF7, 0xFF, 0x67, 0x00, 0xF3,
- 0x00, 0x88, 0xFE, 0x3E, 0xFB, 0x8C, 0x01, 0xD0, 0x13, 0x33, 0x21,
- 0x0D, 0x1A, 0xEE, 0x06, 0xCD, 0xFB, 0x13, 0xFD, 0x92, 0x00, 0xB6,
- 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFA, 0xFF, 0x90, 0x00,
- 0xCF, 0x00, 0xC7, 0xFD, 0x5B, 0xFB, 0x2B, 0x04, 0x31, 0x17, 0x8A,
- 0x21, 0xF0, 0x16, 0xF4, 0x03, 0x56, 0xFB, 0xD6, 0xFD, 0xD3, 0x00,
- 0x8D, 0x00, 0xFA, 0xFF, 0xFF, 0xFF, 0x04, 0x00, 0xB9, 0x00, 0x8C,
- 0x00, 0x05, 0xFD, 0xDB, 0xFB, 0x2C, 0x07, 0x47, 0x1A, 0x25, 0x21,
- 0x8B, 0x13, 0x5D, 0x01, 0x40, 0xFB, 0x97, 0xFE, 0xF5, 0x00, 0x64,
- 0x00, 0xF7, 0xFF, 0xFC, 0xFF, 0x15, 0x00, 0xDC, 0x00, 0x27, 0x00,
- 0x50, 0xFC, 0xCA, 0xFC, 0x78, 0x0A, 0xF2, 0x1C, 0x07, 0x20, 0x02,
- 0x10, 0x37, 0xFF, 0x7B, 0xFB, 0x47, 0xFF, 0xFB, 0x00, 0x40, 0x00,
- 0xF8, 0xFF, 0xF9, 0xFF, 0x2E, 0x00, 0xF5, 0x00, 0xA2, 0xFF, 0xBB,
- 0xFB, 0x31, 0xFE, 0xF5, 0x0D, 0x14, 0x1F, 0x3F, 0x1E, 0x77, 0x0C,
- 0x8A, 0xFD, 0xF5, 0xFB, 0xDE, 0xFF, 0xEC, 0x00, 0x22, 0x00, 0xFB,
- 0xFF, 0xF7, 0xFF, 0x4E, 0x00, 0xFB, 0x00, 0xFF, 0xFE, 0x59, 0xFB,
- 0x11, 0x00, 0x83, 0x11, 0x96, 0x20, 0xE0, 0x1B, 0x0B, 0x09, 0x56,
- 0xFC, 0x99, 0xFC, 0x56, 0x00, 0xCE, 0x00, 0x0D, 0x00, 0xFE, 0xFF,
- 0xF8, 0xFF, 0x75, 0x00, 0xEA, 0x00, 0x47, 0xFE, 0x3E, 0xFB, 0x69,
- 0x02, 0x02, 0x15, 0x66, 0x21, 0x04, 0x19, 0xDC, 0x05, 0x98, 0xFB,
- 0x56, 0xFD, 0xAD, 0x00, 0xA8, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
- 0x00, 0xFD, 0xFF, 0x9E, 0x00, 0xBC, 0x00, 0x83, 0xFD, 0x7B, 0xFB,
- 0x2B, 0x05, 0x4C, 0x18, 0x7C, 0x21, 0xCA, 0x15, 0x03, 0x03, 0x44,
- 0xFB, 0x1A, 0xFE, 0xE2, 0x00, 0x7E, 0x00, 0xF8, 0xFF, 0xFE, 0xFF,
- 0x09, 0x00, 0xC6, 0x00, 0x6D, 0x00, 0xC3, 0xFC, 0x20, 0xFC, 0x49,
- 0x08, 0x41, 0x1B, 0xD6, 0x20, 0x54, 0x12, 0x92, 0x00, 0x4C, 0xFB,
- 0xD6, 0xFE, 0xFA, 0x00, 0x57, 0x00, 0xF7, 0xFF, 0xFB, 0xFF, 0x1D,
- 0x00, 0xE6, 0x00, 0xFD, 0xFF, 0x18, 0xFC, 0x38, 0xFD, 0xA9, 0x0B,
- 0xC0, 0x1D, 0x7C, 0x1F, 0xC6, 0x0E, 0x95, 0xFE, 0x9F, 0xFB, 0x7E,
- 0xFF, 0xF8, 0x00, 0x35, 0x00, 0xF9, 0xFF, 0xF8, 0xFF, 0x38, 0x00,
- 0xF9, 0x00, 0x6C, 0xFF, 0x92, 0xFB, 0xC9, 0xFE, 0x2F, 0x0F, 0xAD,
- 0x1F, 0x7D, 0x1D, 0x42, 0x0B, 0x12, 0xFD, 0x2A, 0xFC, 0x0B, 0x00,
- 0xE3, 0x00, 0x1A, 0x00, 0xFC, 0xFF, 0xF7, 0xFF, 0x5B, 0x00, 0xF8,
- 0x00, 0xC1, 0xFE, 0x47, 0xFB, 0xD4, 0x00, 0xBC, 0x12, 0xF3, 0x20,
- 0xEF, 0x1A, 0xE9, 0x07, 0x08, 0xFC, 0xD9, 0xFC, 0x78, 0x00, 0xC2,
- 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xF9, 0xFF, 0x83, 0x00, 0xDD, 0x00,
- 0x04, 0xFE, 0x49, 0xFB, 0x52, 0x03, 0x2D, 0x16, 0x83, 0x21, 0xEF,
- 0x17, 0xD5, 0x04, 0x6F, 0xFB, 0x9A, 0xFD, 0xC3, 0x00, 0x9A, 0x00,
- 0xFC, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xAD, 0x00, 0xA4,
- 0x00, 0x40, 0xFD, 0xA8, 0xFB, 0x36, 0x06, 0x5E, 0x19, 0x58, 0x21,
- 0x9C, 0x14, 0x1E, 0x02, 0x3D, 0xFB, 0x5D, 0xFE, 0xED, 0x00, 0x70,
- 0x00, 0xF7, 0xFF, 0xFD, 0xFF, 0x0F, 0x00, 0xD2, 0x00, 0x4A, 0x00,
- 0x85, 0xFC, 0x74, 0xFC, 0x6D, 0x09, 0x2D, 0x1C, 0x72, 0x20, 0x1A,
- 0x11, 0xD4, 0xFF, 0x61, 0xFB, 0x13, 0xFF, 0xFC, 0x00, 0x4A, 0x00,
- 0xF7, 0xFF, 0xFA, 0xFF, 0x25, 0x00, 0xEF, 0x00, 0xCE, 0xFF, 0xE4,
- 0xFB, 0xB5, 0xFD, 0xDE, 0x0C, 0x7C, 0x1E, 0xDD, 0x1E, 0x8C, 0x0D,
- 0x01, 0xFE, 0xCA, 0xFB, 0xB3, 0xFF, 0xF3, 0x00, 0x2B, 0x00, 0xFA,
- 0xFF, 0xF8, 0xFF, 0x44, 0x00, 0xFB, 0x00, 0x34, 0xFF, 0x71, 0xFB,
- 0x71, 0xFF, 0x6B, 0x10, 0x32, 0x20, 0xA9, 0x1C, 0x13, 0x0A, 0xA8,
- 0xFC, 0x63, 0xFC, 0x35, 0x00, 0xD9, 0x00, 0x12, 0x00, 0xFD, 0xFF,
- 0xF7, 0xFF, 0x69, 0x00, 0xF2, 0x00, 0x81, 0xFE, 0x3E, 0xFB, 0xA4,
- 0x01, 0xF2, 0x13, 0x3A, 0x21, 0xF0, 0x19, 0xCF, 0x06, 0xC7, 0xFB,
- 0x1B, 0xFD, 0x96, 0x00, 0xB4, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00,
- 0x00, 0xFB, 0xFF, 0x92, 0x00, 0xCD, 0x00, 0xC0, 0xFD, 0x5E, 0xFB,
- 0x47, 0x04, 0x51, 0x17, 0x8A, 0x21, 0xD0, 0x16, 0xD9, 0x03, 0x53,
- 0xFB, 0xDE, 0xFD, 0xD5, 0x00, 0x8B, 0x00, 0xFA, 0xFF, 0xFF, 0xFF,
- 0x04, 0x00, 0xBA, 0x00, 0x89, 0x00, 0xFD, 0xFC, 0xE2, 0xFB, 0x4B,
- 0x07, 0x63, 0x1A, 0x1D, 0x21, 0x69, 0x13, 0x46, 0x01, 0x41, 0xFB,
- 0x9E, 0xFE, 0xF5, 0x00, 0x63, 0x00, 0xF7, 0xFF, 0xFC, 0xFF, 0x16,
- 0x00, 0xDD, 0x00, 0x23, 0x00, 0x49, 0xFC, 0xD5, 0xFC, 0x99, 0x0A,
- 0x09, 0x1D, 0xF9, 0x1F, 0xDF, 0x0F, 0x24, 0xFF, 0x7F, 0xFB, 0x4D,
- 0xFF, 0xFB, 0x00, 0x3F, 0x00, 0xF8, 0xFF, 0xF9, 0xFF, 0x2F, 0x00,
- 0xF5, 0x00, 0x9C, 0xFF, 0xB6, 0xFB, 0x41, 0xFE, 0x17, 0x0E, 0x26,
- 0x1F, 0x2B, 0x1E, 0x54, 0x0C, 0x7C, 0xFD, 0xFA, 0xFB, 0xE3, 0xFF,
- 0xEB, 0x00, 0x21, 0x00, 0xFB, 0xFF, 0xF7, 0xFF, 0x50, 0x00, 0xFB,
- 0x00, 0xF8, 0xFE, 0x57, 0xFB, 0x26, 0x00, 0xA6, 0x11, 0xA1, 0x20,
- 0xC6, 0x1B, 0xEA, 0x08, 0x4D, 0xFC, 0xA0, 0xFC, 0x5A, 0x00, 0xCD,
- 0x00, 0x0C, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0x77, 0x00, 0xE9, 0x00,
- 0x3F, 0xFE, 0x3F, 0xFB, 0x82, 0x02, 0x23, 0x15, 0x6B, 0x21, 0xE5,
- 0x18, 0xBE, 0x05, 0x93, 0xFB, 0x5E, 0xFD, 0xAF, 0x00, 0xA6, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFF, 0xA0, 0x00, 0xB9,
- 0x00, 0x7C, 0xFD, 0x80, 0xFB, 0x48, 0x05, 0x6B, 0x18, 0x79, 0x21,
- 0xA9, 0x15, 0xE9, 0x02, 0x43, 0xFB, 0x21, 0xFE, 0xE3, 0x00, 0x7D,
- 0x00, 0xF8, 0xFF, 0xFE, 0xFF, 0x09, 0x00, 0xC7, 0x00, 0x69, 0x00,
- 0xBC, 0xFC, 0x29, 0xFC, 0x69, 0x08, 0x5C, 0x1B, 0xCC, 0x20, 0x32,
- 0x12, 0x7C, 0x00, 0x4E, 0xFB, 0xDD, 0xFE, 0xFA, 0x00, 0x56, 0x00,
- 0xF7, 0xFF, 0xFB, 0xFF, 0x1D, 0x00, 0xE7, 0x00, 0xF8, 0xFF, 0x12,
- 0xFC, 0x45, 0xFD, 0xCB, 0x0B, 0xD6, 0x1D, 0x6C, 0x1F, 0xA3, 0x0E,
- 0x84, 0xFE, 0xA4, 0xFB, 0x84, 0xFF, 0xF7, 0x00, 0x34, 0x00, 0xF9,
- 0xFF, 0xF8, 0xFF, 0x3A, 0x00, 0xFA, 0x00, 0x66, 0xFF, 0x8E, 0xFB,
- 0xDB, 0xFE, 0x53, 0x0F, 0xBD, 0x1F, 0x66, 0x1D, 0x21, 0x0B, 0x05,
- 0xFD, 0x30, 0xFC, 0x10, 0x00, 0xE2, 0x00, 0x19, 0x00, 0xFC, 0xFF,
- 0xF7, 0xFF, 0x5D, 0x00, 0xF8, 0x00, 0xBA, 0xFE, 0x46, 0xFB, 0xEA,
- 0x00, 0xDF, 0x12, 0xFC, 0x20, 0xD3, 0x1A, 0xC9, 0x07, 0x00, 0xFC,
- 0xE0, 0xFC, 0x7B, 0x00, 0xC0, 0x00, 0x07, 0x00, 0xFF, 0xFF, 0xF9,
- 0xFF, 0x85, 0x00, 0xDC, 0x00, 0xFC, 0xFD, 0x4A, 0xFB, 0x6C, 0x03,
- 0x4E, 0x16, 0x85, 0x21, 0xCF, 0x17, 0xB8, 0x04, 0x6C, 0xFB, 0xA2,
- 0xFD, 0xC5, 0x00, 0x98, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0xFF, 0xFF,
- 0x01, 0x00, 0xAE, 0x00, 0xA1, 0x00, 0x38, 0xFD, 0xAE, 0xFB, 0x54,
- 0x06, 0x7C, 0x19, 0x53, 0x21, 0x7B, 0x14, 0x05, 0x02, 0x3D, 0xFB,
- 0x64, 0xFE, 0xEE, 0x00, 0x6F, 0x00, 0xF7, 0xFF, 0xFD, 0xFF, 0x0F,
- 0x00, 0xD4, 0x00, 0x46, 0x00, 0x7E, 0xFC, 0x7E, 0xFC, 0x8E, 0x09,
- 0x46, 0x1C, 0x66, 0x20, 0xF7, 0x10, 0xC0, 0xFF, 0x64, 0xFB, 0x1A,
- 0xFF, 0xFC, 0x00, 0x49, 0x00, 0xF7, 0xFF, 0xFA, 0xFF, 0x26, 0x00,
- 0xF0, 0x00, 0xC9, 0xFF, 0xDF, 0xFB, 0xC4, 0xFD, 0x01, 0x0D, 0x90,
- 0x1E, 0xCA, 0x1E, 0x69, 0x0D, 0xF1, 0xFD, 0xCF, 0xFB, 0xB8, 0xFF,
- 0xF2, 0x00, 0x29, 0x00, 0xFA, 0xFF, 0xF7, 0xFF, 0x45, 0x00, 0xFC,
- 0x00, 0x2D, 0xFF, 0x6D, 0xFB, 0x84, 0xFF, 0x8E, 0x10, 0x3F, 0x20,
- 0x91, 0x1C, 0xF2, 0x09, 0x9D, 0xFC, 0x6A, 0xFC, 0x39, 0x00, 0xD7,
- 0x00, 0x12, 0x00, 0xFD, 0xFF, 0xF7, 0xFF, 0x6A, 0x00, 0xF1, 0x00,
- 0x7A, 0xFE, 0x3D, 0xFB, 0xBC, 0x01, 0x14, 0x14, 0x41, 0x21, 0xD4,
- 0x19, 0xB0, 0x06, 0xC0, 0xFB, 0x22, 0xFD, 0x99, 0x00, 0xB3, 0x00,
- 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFB, 0xFF, 0x93, 0x00, 0xCB,
- 0x00, 0xB8, 0xFD, 0x61, 0xFB, 0x63, 0x04, 0x71, 0x17, 0x89, 0x21,
- 0xB0, 0x16, 0xBD, 0x03, 0x51, 0xFB, 0xE6, 0xFD, 0xD7, 0x00, 0x8A,
- 0x00, 0xFA, 0xFF, 0xFF, 0xFF, 0x05, 0x00, 0xBC, 0x00, 0x86, 0x00,
- 0xF6, 0xFC, 0xE9, 0xFB, 0x6A, 0x07, 0x80, 0x1A, 0x15, 0x21, 0x47,
- 0x13, 0x2F, 0x01, 0x42, 0xFB, 0xA5, 0xFE, 0xF6, 0x00, 0x61, 0x00,
- 0xF7, 0xFF, 0xFC, 0xFF, 0x16, 0x00, 0xDF, 0x00, 0x1E, 0x00, 0x43,
- 0xFC, 0xE1, 0xFC, 0xBB, 0x0A, 0x21, 0x1D, 0xEA, 0x1F, 0xBC, 0x0F,
- 0x12, 0xFF, 0x82, 0xFB, 0x54, 0xFF, 0xFA, 0x00, 0x3D, 0x00, 0xF8,
- 0xFF, 0xF9, 0xFF, 0x30, 0x00, 0xF6, 0x00, 0x96, 0xFF, 0xB1, 0xFB,
- 0x51, 0xFE, 0x3A, 0x0E, 0x38, 0x1F, 0x16, 0x1E, 0x32, 0x0C, 0x6E,
- 0xFD, 0x00, 0xFC, 0xE8, 0xFF, 0xEA, 0x00, 0x20, 0x00, 0xFB, 0xFF,
- 0xF7, 0xFF, 0x51, 0x00, 0xFB, 0x00, 0xF1, 0xFE, 0x54, 0xFB, 0x3B,
- 0x00, 0xC9, 0x11, 0xAD, 0x20, 0xAC, 0x1B, 0xCA, 0x08, 0x44, 0xFC,
- 0xA7, 0xFC, 0x5E, 0x00, 0xCC, 0x00, 0x0B, 0x00, 0xFE, 0xFF, 0xF8,
- 0xFF, 0x78, 0x00, 0xE7, 0x00, 0x38, 0xFE, 0x40, 0xFB, 0x9B, 0x02,
- 0x45, 0x15, 0x6F, 0x21, 0xC7, 0x18, 0xA1, 0x05, 0x8E, 0xFB, 0x65,
- 0xFD, 0xB2, 0x00, 0xA5, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFE, 0xFF, 0xA2, 0x00, 0xB7, 0x00, 0x74, 0xFD, 0x84, 0xFB, 0x66,
- 0x05, 0x8A, 0x18, 0x76, 0x21, 0x87, 0x15, 0xCF, 0x02, 0x41, 0xFB,
- 0x29, 0xFE, 0xE5, 0x00, 0x7B, 0x00, 0xF8, 0xFF, 0xFE, 0xFF, 0x0A,
- 0x00, 0xC9, 0x00, 0x66, 0x00, 0xB5, 0xFC, 0x32, 0xFC, 0x89, 0x08,
- 0x77, 0x1B, 0xC2, 0x20, 0x0F, 0x12, 0x66, 0x00, 0x50, 0xFB, 0xE4,
- 0xFE, 0xFA, 0x00, 0x54, 0x00, 0xF7, 0xFF, 0xFB, 0xFF, 0x1E, 0x00,
- 0xE8, 0x00, 0xF3, 0xFF, 0x0C, 0xFC, 0x53, 0xFD, 0xED, 0x0B, 0xEB,
- 0x1D, 0x5A, 0x1F, 0x80, 0x0E, 0x73, 0xFE, 0xA8, 0xFB, 0x8A, 0xFF,
- 0xF7, 0x00, 0x32, 0x00, 0xF9, 0xFF, 0xF8, 0xFF, 0x3B, 0x00, 0xFA,
- 0x00, 0x60, 0xFF, 0x8A, 0xFB, 0xED, 0xFE, 0x76, 0x0F, 0xCC, 0x1F,
- 0x4F, 0x1D, 0xFF, 0x0A, 0xF9, 0xFC, 0x36, 0xFC, 0x15, 0x00, 0xE1,
- 0x00, 0x18, 0x00, 0xFC, 0xFF, 0xF7, 0xFF, 0x5E, 0x00, 0xF7, 0x00,
- 0xB3, 0xFE, 0x44, 0xFB, 0x01, 0x01, 0x02, 0x13, 0x04, 0x21, 0xB8,
- 0x1A, 0xA9, 0x07, 0xF8, 0xFB, 0xE7, 0xFC, 0x7F, 0x00, 0xBF, 0x00,
- 0x06, 0x00, 0xFF, 0xFF, 0xF9, 0xFF, 0x86, 0x00, 0xDA, 0x00, 0xF5,
- 0xFD, 0x4C, 0xFB, 0x87, 0x03, 0x6E, 0x16, 0x86, 0x21, 0xB0, 0x17,
- 0x9C, 0x04, 0x68, 0xFB, 0xA9, 0xFD, 0xC7, 0x00, 0x96, 0x00, 0xFB,
- 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x01, 0x00, 0xB0, 0x00, 0x9F, 0x00,
- 0x31, 0xFD, 0xB4, 0xFB, 0x73, 0x06, 0x99, 0x19, 0x4D, 0x21, 0x59,
- 0x14, 0xED, 0x01, 0x3D, 0xFB, 0x6B, 0xFE, 0xEF, 0x00, 0x6D, 0x00,
- 0xF7, 0xFF, 0xFD, 0xFF, 0x10, 0x00, 0xD5, 0x00, 0x42, 0x00, 0x77,
- 0xFC, 0x88, 0xFC, 0xAF, 0x09, 0x5F, 0x1C, 0x59, 0x20, 0xD4, 0x10,
- 0xAC, 0xFF, 0x67, 0xFB, 0x20, 0xFF, 0xFC, 0x00, 0x48, 0x00, 0xF7,
- 0xFF, 0xFA, 0xFF, 0x27, 0x00, 0xF0, 0x00, 0xC3, 0xFF, 0xD9, 0xFB,
- 0xD3, 0xFD, 0x24, 0x0D, 0xA3, 0x1E, 0xB7, 0x1E, 0x46, 0x0D, 0xE2,
- 0xFD, 0xD4, 0xFB, 0xBE, 0xFF, 0xF1, 0x00, 0x28, 0x00, 0xFA, 0xFF,
- 0xF7, 0xFF, 0x46, 0x00, 0xFC, 0x00, 0x27, 0xFF, 0x6A, 0xFB, 0x98,
- 0xFF, 0xB1, 0x10, 0x4C, 0x20, 0x78, 0x1C, 0xD1, 0x09, 0x93, 0xFC,
- 0x71, 0xFC, 0x3D, 0x00, 0xD6, 0x00, 0x11, 0x00, 0xFD, 0xFF, 0xF7,
- 0xFF, 0x6C, 0x00, 0xF0, 0x00, 0x72, 0xFE, 0x3D, 0xFB, 0xD4, 0x01,
- 0x36, 0x14, 0x47, 0x21, 0xB6, 0x19, 0x91, 0x06, 0xBA, 0xFB, 0x29,
- 0xFD, 0x9C, 0x00, 0xB1, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0x00, 0x00,
- 0xFB, 0xFF, 0x95, 0x00, 0xC9, 0x00, 0xB1, 0xFD, 0x65, 0xFB, 0x80,
- 0x04, 0x90, 0x17, 0x88, 0x21, 0x8F, 0x16, 0xA2, 0x03, 0x4E, 0xFB,
- 0xED, 0xFD, 0xD9, 0x00, 0x88, 0x00, 0xF9, 0xFF, 0xFF, 0xFF, 0x05,
- 0x00, 0xBD, 0x00, 0x82, 0x00, 0xEF, 0xFC, 0xF0, 0xFB, 0x8A, 0x07,
- 0x9C, 0x1A, 0x0D, 0x21, 0x24, 0x13, 0x18, 0x01, 0x43, 0xFB, 0xAC,
- 0xFE, 0xF7, 0x00, 0x60, 0x00, 0xF7, 0xFF, 0xFC, 0xFF, 0x17, 0x00,
- 0xE0, 0x00, 0x1A, 0x00, 0x3D, 0xFC, 0xED, 0xFC, 0xDD, 0x0A, 0x38,
- 0x1D, 0xDB, 0x1F, 0x99, 0x0F, 0xFF, 0xFE, 0x86, 0xFB, 0x5A, 0xFF,
- 0xFA, 0x00, 0x3C, 0x00, 0xF8, 0xFF, 0xF9, 0xFF, 0x31, 0x00, 0xF6,
- 0x00, 0x90, 0xFF, 0xAD, 0xFB, 0x62, 0xFE, 0x5D, 0x0E, 0x49, 0x1F,
- 0x01, 0x1E, 0x10, 0x0C, 0x60, 0xFD, 0x06, 0xFC, 0xEE, 0xFF, 0xE9,
- 0x00, 0x1F, 0x00, 0xFB, 0xFF, 0xF7, 0xFF, 0x53, 0x00, 0xFB, 0x00,
- 0xEB, 0xFE, 0x52, 0xFB, 0x51, 0x00, 0xEC, 0x11, 0xB7, 0x20, 0x91,
- 0x1B, 0xA9, 0x08, 0x3B, 0xFC, 0xAE, 0xFC, 0x62, 0x00, 0xCA, 0x00,
- 0x0B, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0x7A, 0x00, 0xE6, 0x00, 0x30,
- 0xFE, 0x40, 0xFB, 0xB5, 0x02, 0x66, 0x15, 0x73, 0x21, 0xA9, 0x18,
- 0x83, 0x05, 0x89, 0xFB, 0x6D, 0xFD, 0xB4, 0x00, 0xA3, 0x00, 0xFE,
- 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xA3, 0x00, 0xB4, 0x00,
- 0x6D, 0xFD, 0x89, 0xFB, 0x83, 0x05, 0xA9, 0x18, 0x73, 0x21, 0x66,
- 0x15, 0xB5, 0x02, 0x40, 0xFB, 0x30, 0xFE, 0xE6, 0x00, 0x7A, 0x00,
- 0xF8, 0xFF, 0xFE, 0xFF, 0x0B, 0x00, 0xCA, 0x00, 0x62, 0x00, 0xAE,
- 0xFC, 0x3B, 0xFC, 0xA9, 0x08, 0x91, 0x1B, 0xB7, 0x20, 0xEC, 0x11,
- 0x51, 0x00, 0x52, 0xFB, 0xEB, 0xFE, 0xFB, 0x00, 0x53, 0x00, 0xF7,
- 0xFF, 0xFB, 0xFF, 0x1F, 0x00, 0xE9, 0x00, 0xEE, 0xFF, 0x06, 0xFC,
- 0x60, 0xFD, 0x10, 0x0C, 0x01, 0x1E, 0x49, 0x1F, 0x5D, 0x0E, 0x62,
- 0xFE, 0xAD, 0xFB, 0x90, 0xFF, 0xF6, 0x00, 0x31, 0x00, 0xF9, 0xFF,
- 0xF8, 0xFF, 0x3C, 0x00, 0xFA, 0x00, 0x5A, 0xFF, 0x86, 0xFB, 0xFF,
- 0xFE, 0x99, 0x0F, 0xDB, 0x1F, 0x38, 0x1D, 0xDD, 0x0A, 0xED, 0xFC,
- 0x3D, 0xFC, 0x1A, 0x00, 0xE0, 0x00, 0x17, 0x00, 0xFC, 0xFF, 0xF7,
- 0xFF, 0x60, 0x00, 0xF7, 0x00, 0xAC, 0xFE, 0x43, 0xFB, 0x18, 0x01,
- 0x24, 0x13, 0x0D, 0x21, 0x9C, 0x1A, 0x8A, 0x07, 0xF0, 0xFB, 0xEF,
- 0xFC, 0x82, 0x00, 0xBD, 0x00, 0x05, 0x00, 0xFF, 0xFF, 0xF9, 0xFF,
- 0x88, 0x00, 0xD9, 0x00, 0xED, 0xFD, 0x4E, 0xFB, 0xA2, 0x03, 0x8F,
- 0x16, 0x88, 0x21, 0x90, 0x17, 0x80, 0x04, 0x65, 0xFB, 0xB1, 0xFD,
- 0xC9, 0x00, 0x95, 0x00, 0xFB, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02,
- 0x00, 0xB1, 0x00, 0x9C, 0x00, 0x29, 0xFD, 0xBA, 0xFB, 0x91, 0x06,
- 0xB6, 0x19, 0x47, 0x21, 0x36, 0x14, 0xD4, 0x01, 0x3D, 0xFB, 0x72,
- 0xFE, 0xF0, 0x00, 0x6C, 0x00, 0xF7, 0xFF, 0xFD, 0xFF, 0x11, 0x00,
- 0xD6, 0x00, 0x3D, 0x00, 0x71, 0xFC, 0x93, 0xFC, 0xD1, 0x09, 0x78,
- 0x1C, 0x4C, 0x20, 0xB1, 0x10, 0x98, 0xFF, 0x6A, 0xFB, 0x27, 0xFF,
- 0xFC, 0x00, 0x46, 0x00, 0xF7, 0xFF, 0xFA, 0xFF, 0x28, 0x00, 0xF1,
- 0x00, 0xBE, 0xFF, 0xD4, 0xFB, 0xE2, 0xFD, 0x46, 0x0D, 0xB7, 0x1E,
- 0xA3, 0x1E, 0x24, 0x0D, 0xD3, 0xFD, 0xD9, 0xFB, 0xC3, 0xFF, 0xF0,
- 0x00, 0x27, 0x00, 0xFA, 0xFF, 0xF7, 0xFF, 0x48, 0x00, 0xFC, 0x00,
- 0x20, 0xFF, 0x67, 0xFB, 0xAC, 0xFF, 0xD4, 0x10, 0x59, 0x20, 0x5F,
- 0x1C, 0xAF, 0x09, 0x88, 0xFC, 0x77, 0xFC, 0x42, 0x00, 0xD5, 0x00,
- 0x10, 0x00, 0xFD, 0xFF, 0xF7, 0xFF, 0x6D, 0x00, 0xEF, 0x00, 0x6B,
- 0xFE, 0x3D, 0xFB, 0xED, 0x01, 0x59, 0x14, 0x4D, 0x21, 0x99, 0x19,
- 0x73, 0x06, 0xB4, 0xFB, 0x31, 0xFD, 0x9F, 0x00, 0xB0, 0x00, 0x01,
- 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFB, 0xFF, 0x96, 0x00, 0xC7, 0x00,
- 0xA9, 0xFD, 0x68, 0xFB, 0x9C, 0x04, 0xB0, 0x17, 0x86, 0x21, 0x6E,
- 0x16, 0x87, 0x03, 0x4C, 0xFB, 0xF5, 0xFD, 0xDA, 0x00, 0x86, 0x00,
- 0xF9, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0xBF, 0x00, 0x7F, 0x00, 0xE7,
- 0xFC, 0xF8, 0xFB, 0xA9, 0x07, 0xB8, 0x1A, 0x04, 0x21, 0x02, 0x13,
- 0x01, 0x01, 0x44, 0xFB, 0xB3, 0xFE, 0xF7, 0x00, 0x5E, 0x00, 0xF7,
- 0xFF, 0xFC, 0xFF, 0x18, 0x00, 0xE1, 0x00, 0x15, 0x00, 0x36, 0xFC,
- 0xF9, 0xFC, 0xFF, 0x0A, 0x4F, 0x1D, 0xCC, 0x1F, 0x76, 0x0F, 0xED,
- 0xFE, 0x8A, 0xFB, 0x60, 0xFF, 0xFA, 0x00, 0x3B, 0x00, 0xF8, 0xFF,
- 0xF9, 0xFF, 0x32, 0x00, 0xF7, 0x00, 0x8A, 0xFF, 0xA8, 0xFB, 0x73,
- 0xFE, 0x80, 0x0E, 0x5A, 0x1F, 0xEB, 0x1D, 0xED, 0x0B, 0x53, 0xFD,
- 0x0C, 0xFC, 0xF3, 0xFF, 0xE8, 0x00, 0x1E, 0x00, 0xFB, 0xFF, 0xF7,
- 0xFF, 0x54, 0x00, 0xFA, 0x00, 0xE4, 0xFE, 0x50, 0xFB, 0x66, 0x00,
- 0x0F, 0x12, 0xC2, 0x20, 0x77, 0x1B, 0x89, 0x08, 0x32, 0xFC, 0xB5,
- 0xFC, 0x66, 0x00, 0xC9, 0x00, 0x0A, 0x00, 0xFE, 0xFF, 0xF8, 0xFF,
- 0x7B, 0x00, 0xE5, 0x00, 0x29, 0xFE, 0x41, 0xFB, 0xCF, 0x02, 0x87,
- 0x15, 0x76, 0x21, 0x8A, 0x18, 0x66, 0x05, 0x84, 0xFB, 0x74, 0xFD,
- 0xB7, 0x00, 0xA2, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFE,
- 0xFF, 0xA5, 0x00, 0xB2, 0x00, 0x65, 0xFD, 0x8E, 0xFB, 0xA1, 0x05,
- 0xC7, 0x18, 0x6F, 0x21, 0x45, 0x15, 0x9B, 0x02, 0x40, 0xFB, 0x38,
- 0xFE, 0xE7, 0x00, 0x78, 0x00, 0xF8, 0xFF, 0xFE, 0xFF, 0x0B, 0x00,
- 0xCC, 0x00, 0x5E, 0x00, 0xA7, 0xFC, 0x44, 0xFC, 0xCA, 0x08, 0xAC,
- 0x1B, 0xAD, 0x20, 0xC9, 0x11, 0x3B, 0x00, 0x54, 0xFB, 0xF1, 0xFE,
- 0xFB, 0x00, 0x51, 0x00, 0xF7, 0xFF, 0xFB, 0xFF, 0x20, 0x00, 0xEA,
- 0x00, 0xE8, 0xFF, 0x00, 0xFC, 0x6E, 0xFD, 0x32, 0x0C, 0x16, 0x1E,
- 0x38, 0x1F, 0x3A, 0x0E, 0x51, 0xFE, 0xB1, 0xFB, 0x96, 0xFF, 0xF6,
- 0x00, 0x30, 0x00, 0xF9, 0xFF, 0xF8, 0xFF, 0x3D, 0x00, 0xFA, 0x00,
- 0x54, 0xFF, 0x82, 0xFB, 0x12, 0xFF, 0xBC, 0x0F, 0xEA, 0x1F, 0x21,
- 0x1D, 0xBB, 0x0A, 0xE1, 0xFC, 0x43, 0xFC, 0x1E, 0x00, 0xDF, 0x00,
- 0x16, 0x00, 0xFC, 0xFF, 0xF7, 0xFF, 0x61, 0x00, 0xF6, 0x00, 0xA5,
- 0xFE, 0x42, 0xFB, 0x2F, 0x01, 0x47, 0x13, 0x15, 0x21, 0x80, 0x1A,
- 0x6A, 0x07, 0xE9, 0xFB, 0xF6, 0xFC, 0x86, 0x00, 0xBC, 0x00, 0x05,
- 0x00, 0xFF, 0xFF, 0xFA, 0xFF, 0x8A, 0x00, 0xD7, 0x00, 0xE6, 0xFD,
- 0x51, 0xFB, 0xBD, 0x03, 0xB0, 0x16, 0x89, 0x21, 0x71, 0x17, 0x63,
- 0x04, 0x61, 0xFB, 0xB8, 0xFD, 0xCB, 0x00, 0x93, 0x00, 0xFB, 0xFF,
- 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00, 0xB3, 0x00, 0x99, 0x00, 0x22,
- 0xFD, 0xC0, 0xFB, 0xB0, 0x06, 0xD4, 0x19, 0x41, 0x21, 0x14, 0x14,
- 0xBC, 0x01, 0x3D, 0xFB, 0x7A, 0xFE, 0xF1, 0x00, 0x6A, 0x00, 0xF7,
- 0xFF, 0xFD, 0xFF, 0x12, 0x00, 0xD7, 0x00, 0x39, 0x00, 0x6A, 0xFC,
- 0x9D, 0xFC, 0xF2, 0x09, 0x91, 0x1C, 0x3F, 0x20, 0x8E, 0x10, 0x84,
- 0xFF, 0x6D, 0xFB, 0x2D, 0xFF, 0xFC, 0x00, 0x45, 0x00, 0xF7, 0xFF,
- 0xFA, 0xFF, 0x29, 0x00, 0xF2, 0x00, 0xB8, 0xFF, 0xCF, 0xFB, 0xF1,
- 0xFD, 0x69, 0x0D, 0xCA, 0x1E, 0x90, 0x1E, 0x01, 0x0D, 0xC4, 0xFD,
- 0xDF, 0xFB, 0xC9, 0xFF, 0xF0, 0x00, 0x26, 0x00, 0xFA, 0xFF, 0xF7,
- 0xFF, 0x49, 0x00, 0xFC, 0x00, 0x1A, 0xFF, 0x64, 0xFB, 0xC0, 0xFF,
- 0xF7, 0x10, 0x66, 0x20, 0x46, 0x1C, 0x8E, 0x09, 0x7E, 0xFC, 0x7E,
- 0xFC, 0x46, 0x00, 0xD4, 0x00, 0x0F, 0x00, 0xFD, 0xFF, 0xF7, 0xFF,
- 0x6F, 0x00, 0xEE, 0x00, 0x64, 0xFE, 0x3D, 0xFB, 0x05, 0x02, 0x7B,
- 0x14, 0x53, 0x21, 0x7C, 0x19, 0x54, 0x06, 0xAE, 0xFB, 0x38, 0xFD,
- 0xA1, 0x00, 0xAE, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFC,
- 0xFF, 0x98, 0x00, 0xC5, 0x00, 0xA2, 0xFD, 0x6C, 0xFB, 0xB8, 0x04,
- 0xCF, 0x17, 0x85, 0x21, 0x4E, 0x16, 0x6C, 0x03, 0x4A, 0xFB, 0xFC,
- 0xFD, 0xDC, 0x00, 0x85, 0x00, 0xF9, 0xFF, 0xFF, 0xFF, 0x07, 0x00,
- 0xC0, 0x00, 0x7B, 0x00, 0xE0, 0xFC, 0x00, 0xFC, 0xC9, 0x07, 0xD3,
- 0x1A, 0xFC, 0x20, 0xDF, 0x12, 0xEA, 0x00, 0x46, 0xFB, 0xBA, 0xFE,
- 0xF8, 0x00, 0x5D, 0x00, 0xF7, 0xFF, 0xFC, 0xFF, 0x19, 0x00, 0xE2,
- 0x00, 0x10, 0x00, 0x30, 0xFC, 0x05, 0xFD, 0x21, 0x0B, 0x66, 0x1D,
- 0xBD, 0x1F, 0x53, 0x0F, 0xDB, 0xFE, 0x8E, 0xFB, 0x66, 0xFF, 0xFA,
- 0x00, 0x3A, 0x00, 0xF8, 0xFF, 0xF9, 0xFF, 0x34, 0x00, 0xF7, 0x00,
- 0x84, 0xFF, 0xA4, 0xFB, 0x84, 0xFE, 0xA3, 0x0E, 0x6C, 0x1F, 0xD6,
- 0x1D, 0xCB, 0x0B, 0x45, 0xFD, 0x12, 0xFC, 0xF8, 0xFF, 0xE7, 0x00,
- 0x1D, 0x00, 0xFB, 0xFF, 0xF7, 0xFF, 0x56, 0x00, 0xFA, 0x00, 0xDD,
- 0xFE, 0x4E, 0xFB, 0x7C, 0x00, 0x32, 0x12, 0xCC, 0x20, 0x5C, 0x1B,
- 0x69, 0x08, 0x29, 0xFC, 0xBC, 0xFC, 0x69, 0x00, 0xC7, 0x00, 0x09,
- 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0x7D, 0x00, 0xE3, 0x00, 0x21, 0xFE,
- 0x43, 0xFB, 0xE9, 0x02, 0xA9, 0x15, 0x79, 0x21, 0x6B, 0x18, 0x48,
- 0x05, 0x80, 0xFB, 0x7C, 0xFD, 0xB9, 0x00, 0xA0, 0x00, 0xFD, 0xFF,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xA6, 0x00, 0xAF, 0x00, 0x5E,
- 0xFD, 0x93, 0xFB, 0xBE, 0x05, 0xE5, 0x18, 0x6B, 0x21, 0x23, 0x15,
- 0x82, 0x02, 0x3F, 0xFB, 0x3F, 0xFE, 0xE9, 0x00, 0x77, 0x00, 0xF8,
- 0xFF, 0xFE, 0xFF, 0x0C, 0x00, 0xCD, 0x00, 0x5A, 0x00, 0xA0, 0xFC,
- 0x4D, 0xFC, 0xEA, 0x08, 0xC6, 0x1B, 0xA1, 0x20, 0xA6, 0x11, 0x26,
- 0x00, 0x57, 0xFB, 0xF8, 0xFE, 0xFB, 0x00, 0x50, 0x00, 0xF7, 0xFF,
- 0xFB, 0xFF, 0x21, 0x00, 0xEB, 0x00, 0xE3, 0xFF, 0xFA, 0xFB, 0x7C,
- 0xFD, 0x54, 0x0C, 0x2B, 0x1E, 0x26, 0x1F, 0x17, 0x0E, 0x41, 0xFE,
- 0xB6, 0xFB, 0x9C, 0xFF, 0xF5, 0x00, 0x2F, 0x00, 0xF9, 0xFF, 0xF8,
- 0xFF, 0x3F, 0x00, 0xFB, 0x00, 0x4D, 0xFF, 0x7F, 0xFB, 0x24, 0xFF,
- 0xDF, 0x0F, 0xF9, 0x1F, 0x09, 0x1D, 0x99, 0x0A, 0xD5, 0xFC, 0x49,
- 0xFC, 0x23, 0x00, 0xDD, 0x00, 0x16, 0x00, 0xFC, 0xFF, 0xF7, 0xFF,
- 0x63, 0x00, 0xF5, 0x00, 0x9E, 0xFE, 0x41, 0xFB, 0x46, 0x01, 0x69,
- 0x13, 0x1D, 0x21, 0x63, 0x1A, 0x4B, 0x07, 0xE2, 0xFB, 0xFD, 0xFC,
- 0x89, 0x00, 0xBA, 0x00, 0x04, 0x00, 0xFF, 0xFF, 0xFA, 0xFF, 0x8B,
- 0x00, 0xD5, 0x00, 0xDE, 0xFD, 0x53, 0xFB, 0xD9, 0x03, 0xD0, 0x16,
- 0x8A, 0x21, 0x51, 0x17, 0x47, 0x04, 0x5E, 0xFB, 0xC0, 0xFD, 0xCD,
- 0x00, 0x92, 0x00, 0xFB, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x02, 0x00,
- 0xB4, 0x00, 0x96, 0x00, 0x1B, 0xFD, 0xC7, 0xFB, 0xCF, 0x06, 0xF0,
- 0x19, 0x3A, 0x21, 0xF2, 0x13, 0xA4, 0x01, 0x3E, 0xFB, 0x81, 0xFE,
- 0xF2, 0x00, 0x69, 0x00, 0xF7, 0xFF, 0xFD, 0xFF, 0x12, 0x00, 0xD9,
- 0x00, 0x35, 0x00, 0x63, 0xFC, 0xA8, 0xFC, 0x13, 0x0A, 0xA9, 0x1C,
- 0x32, 0x20, 0x6B, 0x10, 0x71, 0xFF, 0x71, 0xFB, 0x34, 0xFF, 0xFB,
- 0x00, 0x44, 0x00, 0xF8, 0xFF, 0xFA, 0xFF, 0x2B, 0x00, 0xF3, 0x00,
- 0xB3, 0xFF, 0xCA, 0xFB, 0x01, 0xFE, 0x8C, 0x0D, 0xDD, 0x1E, 0x7C,
- 0x1E, 0xDE, 0x0C, 0xB5, 0xFD, 0xE4, 0xFB, 0xCE, 0xFF, 0xEF, 0x00,
- 0x25, 0x00, 0xFA, 0xFF, 0xF7, 0xFF, 0x4A, 0x00, 0xFC, 0x00, 0x13,
- 0xFF, 0x61, 0xFB, 0xD4, 0xFF, 0x1A, 0x11, 0x72, 0x20, 0x2D, 0x1C,
- 0x6D, 0x09, 0x74, 0xFC, 0x85, 0xFC, 0x4A, 0x00, 0xD2, 0x00, 0x0F,
- 0x00, 0xFD, 0xFF, 0xF7, 0xFF, 0x70, 0x00, 0xED, 0x00, 0x5D, 0xFE,
- 0x3D, 0xFB, 0x1E, 0x02, 0x9C, 0x14, 0x58, 0x21, 0x5E, 0x19, 0x36,
- 0x06, 0xA8, 0xFB, 0x40, 0xFD, 0xA4, 0x00, 0xAD, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0x9A, 0x00, 0xC3, 0x00, 0x9A,
- 0xFD, 0x6F, 0xFB, 0xD5, 0x04, 0xEF, 0x17, 0x83, 0x21, 0x2D, 0x16,
- 0x52, 0x03, 0x49, 0xFB, 0x04, 0xFE, 0xDD, 0x00, 0x83, 0x00, 0xF9,
- 0xFF, 0xFF, 0xFF, 0x07, 0x00, 0xC2, 0x00, 0x78, 0x00, 0xD9, 0xFC,
- 0x08, 0xFC, 0xE9, 0x07, 0xEF, 0x1A, 0xF3, 0x20, 0xBC, 0x12, 0xD4,
- 0x00, 0x47, 0xFB, 0xC1, 0xFE, 0xF8, 0x00, 0x5B, 0x00, 0xF7, 0xFF,
- 0xFC, 0xFF, 0x1A, 0x00, 0xE3, 0x00, 0x0B, 0x00, 0x2A, 0xFC, 0x12,
- 0xFD, 0x42, 0x0B, 0x7D, 0x1D, 0xAD, 0x1F, 0x2F, 0x0F, 0xC9, 0xFE,
- 0x92, 0xFB, 0x6C, 0xFF, 0xF9, 0x00, 0x38, 0x00, 0xF8, 0xFF, 0xF9,
- 0xFF, 0x35, 0x00, 0xF8, 0x00, 0x7E, 0xFF, 0x9F, 0xFB, 0x95, 0xFE,
- 0xC6, 0x0E, 0x7C, 0x1F, 0xC0, 0x1D, 0xA9, 0x0B, 0x38, 0xFD, 0x18,
- 0xFC, 0xFD, 0xFF, 0xE6, 0x00, 0x1D, 0x00, 0xFB, 0xFF, 0xF7, 0xFF,
- 0x57, 0x00, 0xFA, 0x00, 0xD6, 0xFE, 0x4C, 0xFB, 0x92, 0x00, 0x54,
- 0x12, 0xD6, 0x20, 0x41, 0x1B, 0x49, 0x08, 0x20, 0xFC, 0xC3, 0xFC,
- 0x6D, 0x00, 0xC6, 0x00, 0x09, 0x00, 0xFE, 0xFF, 0xF8, 0xFF, 0x7E,
- 0x00, 0xE2, 0x00, 0x1A, 0xFE, 0x44, 0xFB, 0x03, 0x03, 0xCA, 0x15,
- 0x7C, 0x21, 0x4C, 0x18, 0x2B, 0x05, 0x7B, 0xFB, 0x83, 0xFD, 0xBC,
- 0x00, 0x9E, 0x00, 0xFD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
- 0xA8, 0x00, 0xAD, 0x00, 0x56, 0xFD, 0x98, 0xFB, 0xDC, 0x05, 0x04,
- 0x19, 0x66, 0x21, 0x02, 0x15, 0x69, 0x02, 0x3E, 0xFB, 0x47, 0xFE,
- 0xEA, 0x00, 0x75, 0x00, 0xF8, 0xFF, 0xFE, 0xFF, 0x0D, 0x00, 0xCE,
- 0x00, 0x56, 0x00, 0x99, 0xFC, 0x56, 0xFC, 0x0B, 0x09, 0xE0, 0x1B,
- 0x96, 0x20, 0x83, 0x11, 0x11, 0x00, 0x59, 0xFB, 0xFF, 0xFE, 0xFB,
- 0x00, 0x4E, 0x00, 0xF7, 0xFF, 0xFB, 0xFF, 0x22, 0x00, 0xEC, 0x00,
- 0xDE, 0xFF, 0xF5, 0xFB, 0x8A, 0xFD, 0x77, 0x0C, 0x3F, 0x1E, 0x14,
- 0x1F, 0xF5, 0x0D, 0x31, 0xFE, 0xBB, 0xFB, 0xA2, 0xFF, 0xF5, 0x00,
- 0x2E, 0x00, 0xF9, 0xFF, 0xF8, 0xFF, 0x40, 0x00, 0xFB, 0x00, 0x47,
- 0xFF, 0x7B, 0xFB, 0x37, 0xFF, 0x02, 0x10, 0x07, 0x20, 0xF2, 0x1C,
- 0x78, 0x0A, 0xCA, 0xFC, 0x50, 0xFC, 0x27, 0x00, 0xDC, 0x00, 0x15,
- 0x00, 0xFC, 0xFF, 0xF7, 0xFF, 0x64, 0x00, 0xF5, 0x00, 0x97, 0xFE,
- 0x40, 0xFB, 0x5D, 0x01, 0x8B, 0x13, 0x25, 0x21, 0x47, 0x1A, 0x2C,
- 0x07, 0xDB, 0xFB, 0x05, 0xFD, 0x8C, 0x00, 0xB9, 0x00, 0x04, 0x00,
- 0xFF, 0xFF, 0xFA, 0xFF, 0x8D, 0x00, 0xD3, 0x00, 0xD6, 0xFD, 0x56,
- 0xFB, 0xF4, 0x03, 0xF0, 0x16, 0x8A, 0x21, 0x31, 0x17, 0x2B, 0x04,
- 0x5B, 0xFB, 0xC7, 0xFD, 0xCF, 0x00, 0x90, 0x00, 0xFA, 0xFF, 0x00,
- 0x00, 0xFF, 0xFF, 0x03, 0x00, 0xB6, 0x00, 0x92, 0x00, 0x13, 0xFD,
- 0xCD, 0xFB, 0xEE, 0x06, 0x0D, 0x1A, 0x33, 0x21, 0xD0, 0x13, 0x8C,
- 0x01, 0x3E, 0xFB, 0x88, 0xFE, 0xF3, 0x00, 0x67, 0x00, 0xF7, 0xFF,
- 0x06, 0x00, 0x1D, 0x00, 0x03, 0xFF, 0xFE, 0x00, 0xA1, 0x02, 0xA6,
- 0xF8, 0x56, 0x02, 0xA5, 0x28, 0xA5, 0x28, 0x56, 0x02, 0xA6, 0xF8,
- 0xA1, 0x02, 0xFE, 0x00, 0x03, 0xFF, 0x1D, 0x00, 0x06, 0x00, 0x00,
- 0x00, 0x21, 0x00, 0xA6, 0xFF, 0x3F, 0xFF, 0x0B, 0x03, 0x42, 0xFE,
- 0x3E, 0xF8, 0x7F, 0x15, 0xAC, 0x30, 0x7F, 0x15, 0x3E, 0xF8, 0x42,
- 0xFE, 0x0B, 0x03, 0x3F, 0xFF, 0xA6, 0xFF, 0x21, 0x00, 0x00, 0x00,
- 0xFA, 0xFF, 0xCE, 0xFF, 0x14, 0x01, 0x00, 0xFD, 0x35, 0x06, 0xD5,
- 0xF4, 0xDA, 0x15, 0x92, 0x40, 0xAE, 0xFE, 0xF3, 0xFC, 0x68, 0x03,
- 0x86, 0xFD, 0x51, 0x01, 0x8B, 0xFF, 0x11, 0x00, 0x01, 0x00, 0xEC,
- 0xFF, 0xF9, 0xFF, 0xC6, 0x00, 0x55, 0xFD, 0x35, 0x06, 0x90, 0xF3,
- 0xE5, 0x1C, 0x6B, 0x3D, 0x71, 0xFA, 0x34, 0xFF, 0x46, 0x02, 0xFF,
- 0xFD, 0x2D, 0x01, 0x90, 0xFF, 0x10, 0x00, 0x03, 0x00, 0xDB, 0xFF,
- 0x2D, 0x00, 0x60, 0x00, 0xE1, 0xFD, 0xCE, 0x05, 0xED, 0xF2, 0xF3,
- 0x23, 0x20, 0x39, 0x22, 0xF7, 0x44, 0x01, 0x1F, 0x01, 0x89, 0xFE,
- 0xFB, 0x00, 0x9C, 0xFF, 0x0D, 0x00, 0x06, 0x00, 0xC9, 0xFF, 0x68,
- 0x00, 0xE5, 0xFF, 0xA0, 0xFE, 0xFB, 0x04, 0x0C, 0xF3, 0xC5, 0x2A,
- 0xD8, 0x33, 0xC9, 0xF4, 0x0B, 0x03, 0x05, 0x00, 0x1A, 0xFF, 0xC1,
- 0x00, 0xAD, 0xFF, 0x0A, 0x00, 0x09, 0x00, 0xB5, 0xFF, 0xA5, 0x00,
- 0x5C, 0xFF, 0x8C, 0xFF, 0xBF, 0x03, 0x06, 0xF4, 0x22, 0x31, 0xC8,
- 0x2D, 0x63, 0xF3, 0x76, 0x04, 0x08, 0xFF, 0xA7, 0xFF, 0x84, 0x00,
- 0xC0, 0xFF, 0x07, 0x00, 0x0C, 0x00, 0xA4, 0xFF, 0xE1, 0x00, 0xCB,
- 0xFE, 0x9B, 0x00, 0x21, 0x02, 0xEE, 0xF5, 0xCD, 0x36, 0x24, 0x27,
- 0xE1, 0xF2, 0x7A, 0x05, 0x33, 0xFE, 0x2A, 0x00, 0x47, 0x00, 0xD3,
- 0xFF, 0x04, 0x00, 0x0F, 0x00, 0x95, 0xFF, 0x17, 0x01, 0x3D, 0xFE,
- 0xBD, 0x01, 0x30, 0x00, 0xCC, 0xF8, 0x92, 0x3B, 0x2A, 0x20, 0x2E,
- 0xF3, 0x12, 0x06, 0x8F, 0xFD, 0x9A, 0x00, 0x10, 0x00, 0xE5, 0xFF,
- 0x02, 0x00, 0x10, 0x00, 0x8C, 0xFF, 0x42, 0x01, 0xBB, 0xFD, 0xE4,
- 0x02, 0x01, 0xFE, 0x9C, 0xFC, 0x45, 0x3F, 0x16, 0x19, 0x2D, 0xF4,
- 0x41, 0x06, 0x21, 0xFD, 0xF3, 0x00, 0xE0, 0xFF, 0xF4, 0xFF, 0x01,
- 0x00, 0x10, 0x00, 0x8B, 0xFF, 0x5D, 0x01, 0x4F, 0xFD, 0xFB, 0x03,
- 0xB2, 0xFB, 0x53, 0x01, 0xC2, 0x41, 0x24, 0x12, 0xBA, 0xF5, 0x0F,
- 0x06, 0xE9, 0xFC, 0x33, 0x01, 0xBB, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0x0D, 0x00, 0x93, 0xFF, 0x63, 0x01, 0x04, 0xFD, 0xEF, 0x04, 0x62,
- 0xF9, 0xD7, 0x06, 0xF2, 0x42, 0x8D, 0x0B, 0xB0, 0xF7, 0x87, 0x05,
- 0xE6, 0xFC, 0x58, 0x01, 0xA0, 0xFF, 0x09, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x07, 0x00, 0xA5, 0xFF, 0x52, 0x01, 0xE2, 0xFC, 0xAD, 0x05,
- 0x35, 0xF7, 0x08, 0x0D, 0xCB, 0x42, 0x81, 0x05, 0xE8, 0xF9, 0xBB,
- 0x04, 0x12, 0xFD, 0x64, 0x01, 0x90, 0xFF, 0x0E, 0x00, 0x00, 0x00,
- 0xFE, 0xFF, 0xC2, 0xFF, 0x27, 0x01, 0xF1, 0xFC, 0x22, 0x06, 0x54,
- 0xF5, 0xB8, 0x13, 0x4A, 0x41, 0x29, 0x00, 0x3C, 0xFC, 0xBD, 0x03,
- 0x66, 0xFD, 0x58, 0x01, 0x8A, 0xFF, 0x11, 0x00, 0x01, 0x00, 0xF1,
- 0xFF, 0xEB, 0xFF, 0xE1, 0x00, 0x35, 0xFD, 0x40, 0x06, 0xE4, 0xF3,
- 0xB7, 0x1A, 0x85, 0x3E, 0xA6, 0xFB, 0x86, 0xFE, 0xA0, 0x02, 0xD7,
- 0xFD, 0x39, 0x01, 0x8E, 0xFF, 0x10, 0x00, 0x03, 0x00, 0xE1, 0xFF,
- 0x1C, 0x00, 0x82, 0x00, 0xB0, 0xFD, 0xF9, 0x05, 0x0C, 0xF3, 0xCB,
- 0x21, 0x8F, 0x3A, 0x0D, 0xF8, 0xA9, 0x00, 0x79, 0x01, 0x5D, 0xFE,
- 0x0B, 0x01, 0x98, 0xFF, 0x0E, 0x00, 0x05, 0x00, 0xCE, 0xFF, 0x55,
- 0x00, 0x0D, 0x00, 0x60, 0xFE, 0x48, 0x05, 0xEC, 0xF2, 0xB6, 0x28,
- 0x91, 0x35, 0x68, 0xF5, 0x88, 0x02, 0x5A, 0x00, 0xED, 0xFE, 0xD4,
- 0x00, 0xA8, 0xFF, 0x0B, 0x00, 0x08, 0x00, 0xBB, 0xFF, 0x92, 0x00,
- 0x87, 0xFF, 0x3F, 0xFF, 0x2B, 0x04, 0xA1, 0xF3, 0x3D, 0x2F, 0xB8,
- 0x2F, 0xB8, 0xF3, 0x11, 0x04, 0x52, 0xFF, 0x7C, 0xFF, 0x97, 0x00,
- 0xBA, 0xFF, 0x08, 0x00, 0x0B, 0x00, 0xA9, 0xFF, 0xCF, 0x00, 0xF8,
- 0xFE, 0x44, 0x00, 0xAA, 0x02, 0x3E, 0xF5, 0x24, 0x35, 0x3B, 0x29,
- 0xF2, 0xF2, 0x35, 0x05, 0x70, 0xFE, 0x03, 0x00, 0x5A, 0x00, 0xCD,
- 0xFF, 0x05, 0x00, 0x0E, 0x00, 0x99, 0xFF, 0x07, 0x01, 0x68, 0xFE,
- 0x63, 0x01, 0xD0, 0x00, 0xD0, 0xF7, 0x35, 0x3A, 0x55, 0x22, 0x02,
- 0xF3, 0xEF, 0x05, 0xBC, 0xFD, 0x7A, 0x00, 0x20, 0x00, 0xDF, 0xFF,
- 0x03, 0x00, 0x10, 0x00, 0x8E, 0xFF, 0x36, 0x01, 0xE1, 0xFD, 0x8A,
- 0x02, 0xB2, 0xFE, 0x56, 0xFB, 0x40, 0x3E, 0x42, 0x1B, 0xCE, 0xF3,
- 0x3E, 0x06, 0x3D, 0xFD, 0xDB, 0x00, 0xEE, 0xFF, 0xF0, 0xFF, 0x01,
- 0x00, 0x11, 0x00, 0x8A, 0xFF, 0x57, 0x01, 0x6D, 0xFD, 0xA8, 0x03,
- 0x69, 0xFC, 0xC8, 0xFF, 0x20, 0x41, 0x40, 0x14, 0x33, 0xF5, 0x28,
- 0x06, 0xF5, 0xFC, 0x22, 0x01, 0xC5, 0xFF, 0xFD, 0xFF, 0x00, 0x00,
- 0x0F, 0x00, 0x8F, 0xFF, 0x64, 0x01, 0x17, 0xFD, 0xA9, 0x04, 0x16,
- 0xFA, 0x10, 0x05, 0xB8, 0x42, 0x87, 0x0D, 0x0D, 0xF7, 0xB9, 0x05,
- 0xE2, 0xFC, 0x50, 0x01, 0xA7, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0A, 0x00, 0x9E, 0xFF, 0x5A, 0x01, 0xE8, 0xFC, 0x7A, 0x05,
- 0xDA, 0xF7, 0x10, 0x0B, 0xFB, 0x42, 0x4B, 0x07, 0x35, 0xF9, 0x00,
- 0x05, 0x00, 0xFD, 0x63, 0x01, 0x94, 0xFF, 0x0D, 0x00, 0x00, 0x00,
- 0x01, 0x00, 0xB8, 0xFF, 0x37, 0x01, 0xE7, 0xFC, 0x07, 0x06, 0xDE,
- 0xF5, 0x9F, 0x11, 0xE4, 0x41, 0xB8, 0x01, 0x84, 0xFB, 0x0F, 0x04,
- 0x48, 0xFD, 0x5E, 0x01, 0x8B, 0xFF, 0x10, 0x00, 0x01, 0x00, 0xF5,
- 0xFF, 0xDD, 0xFF, 0xF9, 0x00, 0x1B, 0xFD, 0x41, 0x06, 0x47, 0xF4,
- 0x8B, 0x18, 0x81, 0x3F, 0xF1, 0xFC, 0xD5, 0xFD, 0xFA, 0x02, 0xB2,
- 0xFD, 0x45, 0x01, 0x8C, 0xFF, 0x11, 0x00, 0x02, 0x00, 0xE6, 0xFF,
- 0x0C, 0x00, 0xA2, 0x00, 0x85, 0xFD, 0x1A, 0x06, 0x3C, 0xF3, 0x9F,
- 0x1F, 0xE6, 0x3B, 0x0E, 0xF9, 0x07, 0x00, 0xD4, 0x01, 0x33, 0xFE,
- 0x1B, 0x01, 0x94, 0xFF, 0x0F, 0x00, 0x04, 0x00, 0xD4, 0xFF, 0x43,
- 0x00, 0x33, 0x00, 0x25, 0xFE, 0x89, 0x05, 0xE0, 0xF2, 0x9C, 0x26,
- 0x33, 0x37, 0x1E, 0xF6, 0xFD, 0x01, 0xB0, 0x00, 0xC0, 0xFE, 0xE6,
- 0x00, 0xA2, 0xFF, 0x0C, 0x00, 0x07, 0x00, 0xC1, 0xFF, 0x7F, 0x00,
- 0xB2, 0xFF, 0xF6, 0xFE, 0x8E, 0x04, 0x51, 0xF3, 0x49, 0x2D, 0x98,
- 0x31, 0x23, 0xF4, 0xA2, 0x03, 0xA0, 0xFF, 0x51, 0xFF, 0xAA, 0x00,
- 0xB4, 0xFF, 0x09, 0x00, 0x0A, 0x00, 0xAE, 0xFF, 0xBD, 0x00, 0x25,
- 0xFF, 0xF1, 0xFF, 0x2B, 0x03, 0xA5, 0xF4, 0x68, 0x33, 0x48, 0x2B,
- 0x17, 0xF3, 0xE7, 0x04, 0xB1, 0xFE, 0xDB, 0xFF, 0x6C, 0x00, 0xC7,
- 0xFF, 0x06, 0x00, 0x0D, 0x00, 0x9E, 0xFF, 0xF7, 0x00, 0x94, 0xFE,
- 0x09, 0x01, 0x6A, 0x01, 0xEB, 0xF6, 0xC1, 0x38, 0x7D, 0x24, 0xE8,
- 0xF2, 0xC1, 0x05, 0xEE, 0xFD, 0x57, 0x00, 0x31, 0x00, 0xDA, 0xFF,
- 0x03, 0x00, 0x10, 0x00, 0x91, 0xFF, 0x29, 0x01, 0x09, 0xFE, 0x2F,
- 0x02, 0x5F, 0xFF, 0x27, 0xFA, 0x20, 0x3D, 0x70, 0x1D, 0x7D, 0xF3,
- 0x31, 0x06, 0x5E, 0xFD, 0xBF, 0x00, 0xFD, 0xFF, 0xEB, 0xFF, 0x02,
- 0x00, 0x11, 0x00, 0x8B, 0xFF, 0x4E, 0x01, 0x8E, 0xFD, 0x52, 0x03,
- 0x20, 0xFD, 0x52, 0xFE, 0x60, 0x40, 0x63, 0x16, 0xB7, 0xF4, 0x39,
- 0x06, 0x05, 0xFD, 0x0F, 0x01, 0xD1, 0xFF, 0xF9, 0xFF, 0x00, 0x00,
- 0x10, 0x00, 0x8D, 0xFF, 0x62, 0x01, 0x2E, 0xFD, 0x5E, 0x04, 0xCC,
- 0xFA, 0x5B, 0x03, 0x5E, 0x42, 0x8E, 0x0F, 0x71, 0xF6, 0xE4, 0x05,
- 0xE2, 0xFC, 0x45, 0x01, 0xAF, 0xFF, 0x04, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x0B, 0x00, 0x99, 0xFF, 0x60, 0x01, 0xF2, 0xFC, 0x40, 0x05,
- 0x85, 0xF8, 0x26, 0x09, 0x0C, 0x43, 0x26, 0x09, 0x85, 0xF8, 0x40,
- 0x05, 0xF2, 0xFC, 0x60, 0x01, 0x99, 0xFF, 0x0B, 0x00, 0x00, 0x00,
- 0x04, 0x00, 0xAF, 0xFF, 0x45, 0x01, 0xE2, 0xFC, 0xE4, 0x05, 0x71,
- 0xF6, 0x8E, 0x0F, 0x5E, 0x42, 0x5B, 0x03, 0xCC, 0xFA, 0x5E, 0x04,
- 0x2E, 0xFD, 0x62, 0x01, 0x8D, 0xFF, 0x10, 0x00, 0x00, 0x00, 0xF9,
- 0xFF, 0xD1, 0xFF, 0x0F, 0x01, 0x05, 0xFD, 0x39, 0x06, 0xB7, 0xF4,
- 0x63, 0x16, 0x60, 0x40, 0x52, 0xFE, 0x20, 0xFD, 0x52, 0x03, 0x8E,
- 0xFD, 0x4E, 0x01, 0x8B, 0xFF, 0x11, 0x00, 0x02, 0x00, 0xEB, 0xFF,
- 0xFD, 0xFF, 0xBF, 0x00, 0x5E, 0xFD, 0x31, 0x06, 0x7D, 0xF3, 0x70,
- 0x1D, 0x20, 0x3D, 0x27, 0xFA, 0x5F, 0xFF, 0x2F, 0x02, 0x09, 0xFE,
- 0x29, 0x01, 0x91, 0xFF, 0x10, 0x00, 0x03, 0x00, 0xDA, 0xFF, 0x31,
- 0x00, 0x57, 0x00, 0xEE, 0xFD, 0xC1, 0x05, 0xE8, 0xF2, 0x7D, 0x24,
- 0xC1, 0x38, 0xEB, 0xF6, 0x6A, 0x01, 0x09, 0x01, 0x94, 0xFE, 0xF7,
- 0x00, 0x9E, 0xFF, 0x0D, 0x00, 0x06, 0x00, 0xC7, 0xFF, 0x6C, 0x00,
- 0xDB, 0xFF, 0xB1, 0xFE, 0xE7, 0x04, 0x17, 0xF3, 0x48, 0x2B, 0x68,
- 0x33, 0xA5, 0xF4, 0x2B, 0x03, 0xF1, 0xFF, 0x25, 0xFF, 0xBD, 0x00,
- 0xAE, 0xFF, 0x0A, 0x00, 0x09, 0x00, 0xB4, 0xFF, 0xAA, 0x00, 0x51,
- 0xFF, 0xA0, 0xFF, 0xA2, 0x03, 0x23, 0xF4, 0x98, 0x31, 0x49, 0x2D,
- 0x51, 0xF3, 0x8E, 0x04, 0xF6, 0xFE, 0xB2, 0xFF, 0x7F, 0x00, 0xC1,
- 0xFF, 0x07, 0x00, 0x0C, 0x00, 0xA2, 0xFF, 0xE6, 0x00, 0xC0, 0xFE,
- 0xB0, 0x00, 0xFD, 0x01, 0x1E, 0xF6, 0x33, 0x37, 0x9C, 0x26, 0xE0,
- 0xF2, 0x89, 0x05, 0x25, 0xFE, 0x33, 0x00, 0x43, 0x00, 0xD4, 0xFF,
- 0x04, 0x00, 0x0F, 0x00, 0x94, 0xFF, 0x1B, 0x01, 0x33, 0xFE, 0xD4,
- 0x01, 0x07, 0x00, 0x0E, 0xF9, 0xE6, 0x3B, 0x9F, 0x1F, 0x3C, 0xF3,
- 0x1A, 0x06, 0x85, 0xFD, 0xA2, 0x00, 0x0C, 0x00, 0xE6, 0xFF, 0x02,
- 0x00, 0x11, 0x00, 0x8C, 0xFF, 0x45, 0x01, 0xB2, 0xFD, 0xFA, 0x02,
- 0xD5, 0xFD, 0xF1, 0xFC, 0x81, 0x3F, 0x8B, 0x18, 0x47, 0xF4, 0x41,
- 0x06, 0x1B, 0xFD, 0xF9, 0x00, 0xDD, 0xFF, 0xF5, 0xFF, 0x01, 0x00,
- 0x10, 0x00, 0x8B, 0xFF, 0x5E, 0x01, 0x48, 0xFD, 0x0F, 0x04, 0x84,
- 0xFB, 0xB8, 0x01, 0xE4, 0x41, 0x9F, 0x11, 0xDE, 0xF5, 0x07, 0x06,
- 0xE7, 0xFC, 0x37, 0x01, 0xB8, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x0D,
- 0x00, 0x94, 0xFF, 0x63, 0x01, 0x00, 0xFD, 0x00, 0x05, 0x35, 0xF9,
- 0x4B, 0x07, 0xFB, 0x42, 0x10, 0x0B, 0xDA, 0xF7, 0x7A, 0x05, 0xE8,
- 0xFC, 0x5A, 0x01, 0x9E, 0xFF, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x07, 0x00, 0xA7, 0xFF, 0x50, 0x01, 0xE2, 0xFC, 0xB9, 0x05, 0x0D,
- 0xF7, 0x87, 0x0D, 0xB8, 0x42, 0x10, 0x05, 0x16, 0xFA, 0xA9, 0x04,
- 0x17, 0xFD, 0x64, 0x01, 0x8F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0xFD,
- 0xFF, 0xC5, 0xFF, 0x22, 0x01, 0xF5, 0xFC, 0x28, 0x06, 0x33, 0xF5,
- 0x40, 0x14, 0x20, 0x41, 0xC8, 0xFF, 0x69, 0xFC, 0xA8, 0x03, 0x6D,
- 0xFD, 0x57, 0x01, 0x8A, 0xFF, 0x11, 0x00, 0x01, 0x00, 0xF0, 0xFF,
- 0xEE, 0xFF, 0xDB, 0x00, 0x3D, 0xFD, 0x3E, 0x06, 0xCE, 0xF3, 0x42,
- 0x1B, 0x40, 0x3E, 0x56, 0xFB, 0xB2, 0xFE, 0x8A, 0x02, 0xE1, 0xFD,
- 0x36, 0x01, 0x8E, 0xFF, 0x10, 0x00, 0x03, 0x00, 0xDF, 0xFF, 0x20,
- 0x00, 0x7A, 0x00, 0xBC, 0xFD, 0xEF, 0x05, 0x02, 0xF3, 0x55, 0x22,
- 0x35, 0x3A, 0xD0, 0xF7, 0xD0, 0x00, 0x63, 0x01, 0x68, 0xFE, 0x07,
- 0x01, 0x99, 0xFF, 0x0E, 0x00, 0x05, 0x00, 0xCD, 0xFF, 0x5A, 0x00,
- 0x03, 0x00, 0x70, 0xFE, 0x35, 0x05, 0xF2, 0xF2, 0x3B, 0x29, 0x24,
- 0x35, 0x3E, 0xF5, 0xAA, 0x02, 0x44, 0x00, 0xF8, 0xFE, 0xCF, 0x00,
- 0xA9, 0xFF, 0x0B, 0x00, 0x08, 0x00, 0xBA, 0xFF, 0x97, 0x00, 0x7C,
- 0xFF, 0x52, 0xFF, 0x11, 0x04, 0xB8, 0xF3, 0xB8, 0x2F, 0x3D, 0x2F,
- 0xA1, 0xF3, 0x2B, 0x04, 0x3F, 0xFF, 0x87, 0xFF, 0x92, 0x00, 0xBB,
- 0xFF, 0x08, 0x00, 0x0B, 0x00, 0xA8, 0xFF, 0xD4, 0x00, 0xED, 0xFE,
- 0x5A, 0x00, 0x88, 0x02, 0x68, 0xF5, 0x91, 0x35, 0xB6, 0x28, 0xEC,
- 0xF2, 0x48, 0x05, 0x60, 0xFE, 0x0D, 0x00, 0x55, 0x00, 0xCE, 0xFF,
- 0x05, 0x00, 0x0E, 0x00, 0x98, 0xFF, 0x0B, 0x01, 0x5D, 0xFE, 0x79,
- 0x01, 0xA9, 0x00, 0x0D, 0xF8, 0x8F, 0x3A, 0xCB, 0x21, 0x0C, 0xF3,
- 0xF9, 0x05, 0xB0, 0xFD, 0x82, 0x00, 0x1C, 0x00, 0xE1, 0xFF, 0x03,
- 0x00, 0x10, 0x00, 0x8E, 0xFF, 0x39, 0x01, 0xD7, 0xFD, 0xA0, 0x02,
- 0x86, 0xFE, 0xA6, 0xFB, 0x85, 0x3E, 0xB7, 0x1A, 0xE4, 0xF3, 0x40,
- 0x06, 0x35, 0xFD, 0xE1, 0x00, 0xEB, 0xFF, 0xF1, 0xFF, 0x01, 0x00,
- 0x11, 0x00, 0x8A, 0xFF, 0x58, 0x01, 0x66, 0xFD, 0xBD, 0x03, 0x3C,
- 0xFC, 0x29, 0x00, 0x4A, 0x41, 0xB8, 0x13, 0x54, 0xF5, 0x22, 0x06,
- 0xF1, 0xFC, 0x27, 0x01, 0xC2, 0xFF, 0xFE, 0xFF, 0x00, 0x00, 0x0E,
- 0x00, 0x90, 0xFF, 0x64, 0x01, 0x12, 0xFD, 0xBB, 0x04, 0xE8, 0xF9,
- 0x81, 0x05, 0xCB, 0x42, 0x08, 0x0D, 0x35, 0xF7, 0xAD, 0x05, 0xE2,
- 0xFC, 0x52, 0x01, 0xA5, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x09, 0x00, 0xA0, 0xFF, 0x58, 0x01, 0xE6, 0xFC, 0x87, 0x05, 0xB0,
- 0xF7, 0x8D, 0x0B, 0xF2, 0x42, 0xD7, 0x06, 0x62, 0xF9, 0xEF, 0x04,
- 0x04, 0xFD, 0x63, 0x01, 0x93, 0xFF, 0x0D, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xBB, 0xFF, 0x33, 0x01, 0xE9, 0xFC, 0x0F, 0x06, 0xBA, 0xF5,
- 0x24, 0x12, 0xC2, 0x41, 0x53, 0x01, 0xB2, 0xFB, 0xFB, 0x03, 0x4F,
- 0xFD, 0x5D, 0x01, 0x8B, 0xFF, 0x10, 0x00, 0x01, 0x00, 0xF4, 0xFF,
- 0xE0, 0xFF, 0xF3, 0x00, 0x21, 0xFD, 0x41, 0x06, 0x2D, 0xF4, 0x16,
- 0x19, 0x45, 0x3F, 0x9C, 0xFC, 0x01, 0xFE, 0xE4, 0x02, 0xBB, 0xFD,
- 0x42, 0x01, 0x8C, 0xFF, 0x10, 0x00, 0x02, 0x00, 0xE5, 0xFF, 0x10,
- 0x00, 0x9A, 0x00, 0x8F, 0xFD, 0x12, 0x06, 0x2E, 0xF3, 0x2A, 0x20,
- 0x92, 0x3B, 0xCC, 0xF8, 0x30, 0x00, 0xBD, 0x01, 0x3D, 0xFE, 0x17,
- 0x01, 0x95, 0xFF, 0x0F, 0x00, 0x04, 0x00, 0xD3, 0xFF, 0x47, 0x00,
- 0x2A, 0x00, 0x33, 0xFE, 0x7A, 0x05, 0xE1, 0xF2, 0x24, 0x27, 0xCD,
- 0x36, 0xEE, 0xF5, 0x21, 0x02, 0x9B, 0x00, 0xCB, 0xFE, 0xE1, 0x00,
- 0xA4, 0xFF, 0x0C, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0x84, 0x00, 0xA7,
- 0xFF, 0x08, 0xFF, 0x76, 0x04, 0x63, 0xF3, 0xC8, 0x2D, 0x22, 0x31,
- 0x06, 0xF4, 0xBF, 0x03, 0x8C, 0xFF, 0x5C, 0xFF, 0xA5, 0x00, 0xB5,
- 0xFF, 0x09, 0x00, 0x0A, 0x00, 0xAD, 0xFF, 0xC1, 0x00, 0x1A, 0xFF,
- 0x05, 0x00, 0x0B, 0x03, 0xC9, 0xF4, 0xD8, 0x33, 0xC5, 0x2A, 0x0C,
- 0xF3, 0xFB, 0x04, 0xA0, 0xFE, 0xE5, 0xFF, 0x68, 0x00, 0xC9, 0xFF,
- 0x06, 0x00, 0x0D, 0x00, 0x9C, 0xFF, 0xFB, 0x00, 0x89, 0xFE, 0x1F,
- 0x01, 0x44, 0x01, 0x22, 0xF7, 0x20, 0x39, 0xF3, 0x23, 0xED, 0xF2,
- 0xCE, 0x05, 0xE1, 0xFD, 0x60, 0x00, 0x2D, 0x00, 0xDB, 0xFF, 0x03,
- 0x00, 0x10, 0x00, 0x90, 0xFF, 0x2D, 0x01, 0xFF, 0xFD, 0x46, 0x02,
- 0x34, 0xFF, 0x71, 0xFA, 0x6B, 0x3D, 0xE5, 0x1C, 0x90, 0xF3, 0x35,
- 0x06, 0x55, 0xFD, 0xC6, 0x00, 0xF9, 0xFF, 0xEC, 0xFF, 0x01, 0x00,
- 0x11, 0x00, 0x8B, 0xFF, 0x51, 0x01, 0x86, 0xFD, 0x68, 0x03, 0xF3,
- 0xFC, 0xAE, 0xFE, 0x92, 0x40, 0xDA, 0x15, 0xD5, 0xF4, 0x35, 0x06,
- 0x00, 0xFD, 0x14, 0x01, 0xCE, 0xFF, 0xFA, 0xFF, 0x00, 0x00, 0x0F,
- 0x00, 0x8D, 0xFF, 0x63, 0x01, 0x28, 0xFD, 0x71, 0x04, 0x9E, 0xFA,
- 0xC7, 0x03, 0x79, 0x42, 0x0B, 0x0F, 0x97, 0xF6, 0xDA, 0x05, 0xE2,
- 0xFC, 0x48, 0x01, 0xAD, 0xFF, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0B, 0x00, 0x9A, 0xFF, 0x5F, 0x01, 0xEF, 0xFC, 0x4F, 0x05, 0x5A,
- 0xF8, 0x9F, 0x09, 0x0A, 0x43, 0xAE, 0x08, 0xB1, 0xF8, 0x30, 0x05,
- 0xF5, 0xFC, 0x61, 0x01, 0x97, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x03,
- 0x00, 0xB1, 0xFF, 0x41, 0x01, 0xE3, 0xFC, 0xED, 0x05, 0x4C, 0xF6,
- 0x11, 0x10, 0x42, 0x42, 0xF1, 0x02, 0xFA, 0xFA, 0x4B, 0x04, 0x34,
- 0xFD, 0x61, 0x01, 0x8C, 0xFF, 0x10, 0x00, 0x01, 0x00, 0xF8, 0xFF,
- 0xD4, 0xFF, 0x0A, 0x01, 0x0A, 0xFD, 0x3C, 0x06, 0x9A, 0xF4, 0xED,
- 0x16, 0x2A, 0x40, 0xF8, 0xFD, 0x4D, 0xFD, 0x3C, 0x03, 0x97, 0xFD,
- 0x4C, 0x01, 0x8B, 0xFF, 0x11, 0x00, 0x02, 0x00, 0xEA, 0xFF, 0x00,
- 0x00, 0xB8, 0x00, 0x67, 0xFD, 0x2C, 0x06, 0x6B, 0xF3, 0xFC, 0x1D,
- 0xD3, 0x3C, 0xDF, 0xF9, 0x89, 0xFF, 0x18, 0x02, 0x13, 0xFE, 0x26,
- 0x01, 0x92, 0xFF, 0x0F, 0x00, 0x04, 0x00, 0xD9, 0xFF, 0x36, 0x00,
- 0x4E, 0x00, 0xFB, 0xFD, 0xB4, 0x05, 0xE4, 0xF2, 0x04, 0x25, 0x5F,
- 0x38, 0xB6, 0xF6, 0x90, 0x01, 0xF3, 0x00, 0x9F, 0xFE, 0xF3, 0x00,
- 0x9F, 0xFF, 0x0D, 0x00, 0x06, 0x00, 0xC6, 0xFF, 0x71, 0x00, 0xD1,
- 0xFF, 0xC2, 0xFE, 0xD1, 0x04, 0x23, 0xF3, 0xC9, 0x2B, 0xF5, 0x32,
- 0x83, 0xF4, 0x49, 0x03, 0xDC, 0xFF, 0x30, 0xFF, 0xB8, 0x00, 0xB0,
- 0xFF, 0x0A, 0x00, 0x09, 0x00, 0xB3, 0xFF, 0xAE, 0x00, 0x46, 0xFF,
- 0xB4, 0xFF, 0x85, 0x03, 0x42, 0xF4, 0x0E, 0x32, 0xCA, 0x2C, 0x41,
- 0xF3, 0xA5, 0x04, 0xE4, 0xFE, 0xBC, 0xFF, 0x7A, 0x00, 0xC3, 0xFF,
- 0x07, 0x00, 0x0D, 0x00, 0xA1, 0xFF, 0xEA, 0x00, 0xB5, 0xFE, 0xC6,
- 0x00, 0xD9, 0x01, 0x4F, 0xF6, 0x99, 0x37, 0x16, 0x26, 0xE0, 0xF2,
- 0x98, 0x05, 0x16, 0xFE, 0x3C, 0x00, 0x3F, 0x00, 0xD6, 0xFF, 0x04,
- 0x00, 0x0F, 0x00, 0x93, 0xFF, 0x1F, 0x01, 0x28, 0xFE, 0xEB, 0x01,
- 0xDD, 0xFF, 0x52, 0xF9, 0x36, 0x3C, 0x13, 0x1F, 0x4B, 0xF3, 0x20,
- 0x06, 0x7B, 0xFD, 0xA9, 0x00, 0x08, 0x00, 0xE7, 0xFF, 0x02, 0x00,
- 0x11, 0x00, 0x8C, 0xFF, 0x47, 0x01, 0xA9, 0xFD, 0x10, 0x03, 0xA8,
- 0xFD, 0x47, 0xFD, 0xBB, 0x3F, 0x01, 0x18, 0x62, 0xF4, 0x40, 0x06,
- 0x15, 0xFD, 0xFF, 0x00, 0xDA, 0xFF, 0xF6, 0xFF, 0x01, 0x00, 0x10,
- 0x00, 0x8B, 0xFF, 0x5F, 0x01, 0x41, 0xFD, 0x23, 0x04, 0x56, 0xFB,
- 0x1F, 0x02, 0x06, 0x42, 0x19, 0x11, 0x02, 0xF6, 0xFF, 0x05, 0xE5,
- 0xFC, 0x3B, 0x01, 0xB6, 0xFF, 0x02, 0x00, 0x00, 0x00, 0x0D, 0x00,
- 0x95, 0xFF, 0x62, 0x01, 0xFC, 0xFC, 0x10, 0x05, 0x09, 0xF9, 0xC1,
- 0x07, 0x03, 0x43, 0x94, 0x0A, 0x05, 0xF8, 0x6C, 0x05, 0xEA, 0xFC,
- 0x5C, 0x01, 0x9D, 0xFF, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
- 0x00, 0xA9, 0xFF, 0x4D, 0x01, 0xE1, 0xFC, 0xC4, 0x05, 0xE6, 0xF6,
- 0x08, 0x0E, 0xA5, 0x42, 0xA1, 0x04, 0x43, 0xFA, 0x97, 0x04, 0x1D,
- 0xFD, 0x64, 0x01, 0x8F, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0xFC, 0xFF,
- 0xC8, 0xFF, 0x1E, 0x01, 0xF8, 0xFC, 0x2D, 0x06, 0x13, 0xF5, 0xC8,
- 0x14, 0xF2, 0x40, 0x69, 0xFF, 0x97, 0xFC, 0x92, 0x03, 0x75, 0xFD,
- 0x55, 0x01, 0x8A, 0xFF, 0x11, 0x00, 0x01, 0x00, 0xEF, 0xFF, 0xF2,
- 0xFF, 0xD4, 0x00, 0x45, 0xFD, 0x3B, 0x06, 0xB8, 0xF3, 0xCE, 0x1B,
- 0xFB, 0x3D, 0x08, 0xFB, 0xDE, 0xFE, 0x73, 0x02, 0xEB, 0xFD, 0x33,
- 0x01, 0x8F, 0xFF, 0x10, 0x00, 0x03, 0x00, 0xDE, 0xFF, 0x25, 0x00,
- 0x71, 0x00, 0xC8, 0xFD, 0xE5, 0x05, 0xFA, 0xF2, 0xDF, 0x22, 0xDB,
- 0x39, 0x94, 0xF7, 0xF7, 0x00, 0x4C, 0x01, 0x73, 0xFE, 0x03, 0x01,
- 0x9A, 0xFF, 0x0E, 0x00, 0x05, 0x00, 0xCC, 0xFF, 0x5E, 0x00, 0xF9,
- 0xFF, 0x80, 0xFE, 0x23, 0x05, 0xF9, 0xF2, 0xC0, 0x29, 0xB8, 0x34,
- 0x16, 0xF5, 0xCB, 0x02, 0x2F, 0x00, 0x03, 0xFF, 0xCA, 0x00, 0xAA,
- 0xFF, 0x0B, 0x00, 0x08, 0x00, 0xB8, 0xFF, 0x9B, 0x00, 0x72, 0xFF,
- 0x65, 0xFF, 0xF6, 0x03, 0xD1, 0xF3, 0x31, 0x30, 0xC1, 0x2E, 0x8B,
- 0xF3, 0x45, 0x04, 0x2D, 0xFF, 0x92, 0xFF, 0x8D, 0x00, 0xBD, 0xFF,
- 0x08, 0x00, 0x0C, 0x00, 0xA6, 0xFF, 0xD8, 0x00, 0xE2, 0xFE, 0x6F,
- 0x00, 0x66, 0x02, 0x93, 0xF5, 0xFB, 0x35, 0x31, 0x28, 0xE7, 0xF2,
- 0x59, 0x05, 0x51, 0xFE, 0x17, 0x00, 0x50, 0x00, 0xD0, 0xFF, 0x05,
- 0x00, 0x0E, 0x00, 0x97, 0xFF, 0x0F, 0x01, 0x53, 0xFE, 0x90, 0x01,
- 0x81, 0x00, 0x4B, 0xF8, 0xE6, 0x3A, 0x3F, 0x21, 0x16, 0xF3, 0x02,
- 0x06, 0xA5, 0xFD, 0x8A, 0x00, 0x18, 0x00, 0xE2, 0xFF, 0x02, 0x00,
- 0x10, 0x00, 0x8D, 0xFF, 0x3C, 0x01, 0xCE, 0xFD, 0xB7, 0x02, 0x5A,
- 0xFE, 0xF7, 0xFB, 0xC6, 0x3E, 0x2C, 0x1A, 0xFC, 0xF3, 0x41, 0x06,
- 0x2E, 0xFD, 0xE7, 0x00, 0xE7, 0xFF, 0xF2, 0xFF, 0x01, 0x00, 0x10,
- 0x00, 0x8B, 0xFF, 0x5A, 0x01, 0x5E, 0xFD, 0xD2, 0x03, 0x0E, 0xFC,
- 0x8B, 0x00, 0x75, 0x41, 0x32, 0x13, 0x75, 0xF5, 0x1C, 0x06, 0xEE,
- 0xFC, 0x2B, 0x01, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0E, 0x00,
- 0x91, 0xFF, 0x64, 0x01, 0x0D, 0xFD, 0xCD, 0x04, 0xBB, 0xF9, 0xF2,
- 0x05, 0xD9, 0x42, 0x88, 0x0C, 0x5E, 0xF7, 0xA1, 0x05, 0xE3, 0xFC,
- 0x54, 0x01, 0xA3, 0xFF, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
- 0x00, 0xA2, 0xFF, 0x56, 0x01, 0xE5, 0xFC, 0x94, 0x05, 0x87, 0xF7,
- 0x0A, 0x0C, 0xE6, 0x42, 0x64, 0x06, 0x8E, 0xF9, 0xDE, 0x04, 0x09,
- 0xFD, 0x64, 0x01, 0x92, 0xFF, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xBD, 0xFF, 0x2F, 0x01, 0xEC, 0xFC, 0x16, 0x06, 0x98, 0xF5, 0xAB,
- 0x12, 0x9C, 0x41, 0xEE, 0x00, 0xE0, 0xFB, 0xE6, 0x03, 0x57, 0xFD,
- 0x5B, 0x01, 0x8B, 0xFF, 0x10, 0x00, 0x01, 0x00, 0xF3, 0xFF, 0xE4,
- 0xFF, 0xED, 0x00, 0x27, 0xFD, 0x41, 0x06, 0x14, 0xF4, 0xA1, 0x19,
- 0x06, 0x3F, 0x49, 0xFC, 0x2E, 0xFE, 0xCD, 0x02, 0xC4, 0xFD, 0x3F,
- 0x01, 0x8D, 0xFF, 0x10, 0x00, 0x02, 0x00, 0xE3, 0xFF, 0x14, 0x00,
- 0x92, 0x00, 0x9A, 0xFD, 0x0A, 0x06, 0x22, 0xF3, 0xB4, 0x20, 0x3C,
- 0x3B, 0x8B, 0xF8, 0x58, 0x00, 0xA7, 0x01, 0x48, 0xFE, 0x13, 0x01,
- 0x96, 0xFF, 0x0F, 0x00, 0x04, 0x00, 0xD1, 0xFF, 0x4C, 0x00, 0x20,
- 0x00, 0x42, 0xFE, 0x6A, 0x05, 0xE3, 0xF2, 0xAB, 0x27, 0x66, 0x36,
- 0xC0, 0xF5, 0x44, 0x02, 0x85, 0x00, 0xD7, 0xFE, 0xDD, 0x00, 0xA5,
- 0xFF, 0x0C, 0x00, 0x07, 0x00, 0xBE, 0xFF, 0x89, 0x00, 0x9D, 0xFF,
- 0x1A, 0xFF, 0x5E, 0x04, 0x76, 0xF3, 0x45, 0x2E, 0xAA, 0x30, 0xEB,
- 0xF3, 0xDB, 0x03, 0x79, 0xFF, 0x67, 0xFF, 0xA0, 0x00, 0xB7, 0xFF,
- 0x09, 0x00, 0x0B, 0x00, 0xAC, 0xFF, 0xC6, 0x00, 0x0E, 0xFF, 0x1A,
- 0x00, 0xEB, 0x02, 0xEF, 0xF4, 0x49, 0x34, 0x43, 0x2A, 0x02, 0xF3,
- 0x0F, 0x05, 0x90, 0xFE, 0xEF, 0xFF, 0x63, 0x00, 0xCA, 0xFF, 0x06,
- 0x00, 0x0E, 0x00, 0x9B, 0xFF, 0xFF, 0x00, 0x7E, 0xFE, 0x36, 0x01,
- 0x1E, 0x01, 0x5B, 0xF7, 0x7E, 0x39, 0x69, 0x23, 0xF3, 0xF2, 0xD9,
- 0x05, 0xD4, 0xFD, 0x69, 0x00, 0x29, 0x00, 0xDD, 0xFF, 0x03, 0x00,
- 0x10, 0x00, 0x90, 0xFF, 0x30, 0x01, 0xF5, 0xFD, 0x5C, 0x02, 0x09,
- 0xFF, 0xBC, 0xFA, 0xB5, 0x3D, 0x5A, 0x1C, 0xA3, 0xF3, 0x38, 0x06,
- 0x4D, 0xFD, 0xCD, 0x00, 0xF5, 0xFF, 0xED, 0xFF, 0x01, 0x00, 0x11,
- 0x00, 0x8B, 0xFF, 0x53, 0x01, 0x7E, 0xFD, 0x7D, 0x03, 0xC5, 0xFC,
- 0x0B, 0xFF, 0xC3, 0x40, 0x51, 0x15, 0xF4, 0xF4, 0x31, 0x06, 0xFC,
- 0xFC, 0x19, 0x01, 0xCB, 0xFF, 0xFB, 0xFF, 0x00, 0x00, 0x0F, 0x00,
- 0x8E, 0xFF, 0x63, 0x01, 0x22, 0xFD, 0x84, 0x04, 0x71, 0xFA, 0x34,
- 0x04, 0x90, 0x42, 0x89, 0x0E, 0xBE, 0xF6, 0xCF, 0x05, 0xE1, 0xFC,
- 0x4A, 0x01, 0xAB, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0B,
- 0x00, 0x9B, 0xFF, 0x5D, 0x01, 0xEC, 0xFC, 0x5D, 0x05, 0x2F, 0xF8,
- 0x19, 0x0A, 0x07, 0x43, 0x37, 0x08, 0xDD, 0xF8, 0x21, 0x05, 0xF8,
- 0xFC, 0x62, 0x01, 0x96, 0xFF, 0x0C, 0x00, 0x00, 0x00, 0x03, 0x00,
- 0xB4, 0xFF, 0x3E, 0x01, 0xE4, 0xFC, 0xF6, 0x05, 0x26, 0xF6, 0x95,
- 0x10, 0x26, 0x42, 0x87, 0x02, 0x28, 0xFB, 0x37, 0x04, 0x3B, 0xFD,
- 0x60, 0x01, 0x8C, 0xFF, 0x10, 0x00, 0x01, 0x00, 0xF7, 0xFF, 0xD7,
- 0xFF, 0x04, 0x01, 0x0F, 0xFD, 0x3E, 0x06, 0x7D, 0xF4, 0x76, 0x17,
- 0xF4, 0x3F, 0x9F, 0xFD, 0x7B, 0xFD, 0x26, 0x03, 0xA0, 0xFD, 0x4A,
- 0x01, 0x8B, 0xFF, 0x11, 0x00, 0x02, 0x00, 0xE9, 0xFF, 0x04, 0x00,
- 0xB1, 0x00, 0x71, 0xFD, 0x26, 0x06, 0x5A, 0xF3, 0x88, 0x1E, 0x87,
- 0x3C, 0x98, 0xF9, 0xB3, 0xFF, 0x02, 0x02, 0x1E, 0xFE, 0x22, 0x01,
- 0x93, 0xFF, 0x0F, 0x00, 0x04, 0x00, 0xD7, 0xFF, 0x3A, 0x00, 0x45,
- 0x00, 0x09, 0xFE, 0xA7, 0x05, 0xE1, 0xF2, 0x8D, 0x25, 0xFD, 0x37,
- 0x82, 0xF6, 0xB5, 0x01, 0xDC, 0x00, 0xAA, 0xFE, 0xEE, 0x00, 0xA0,
- 0xFF, 0x0D, 0x00, 0x06, 0x00, 0xC4, 0xFF, 0x76, 0x00, 0xC7, 0xFF,
- 0xD3, 0xFE, 0xBC, 0x04, 0x31, 0xF3, 0x4A, 0x2C, 0x83, 0x32, 0x61,
- 0xF4, 0x68, 0x03, 0xC8, 0xFF, 0x3B, 0xFF, 0xB3, 0x00, 0xB1, 0xFF,
- 0x0A, 0x00, 0x0A, 0x00, 0xB1, 0xFF, 0xB3, 0x00, 0x3B, 0xFF, 0xC8,
- 0xFF, 0x68, 0x03, 0x61, 0xF4, 0x83, 0x32, 0x4A, 0x2C, 0x31, 0xF3,
- 0xBC, 0x04, 0xD3, 0xFE, 0xC7, 0xFF, 0x76, 0x00, 0xC4, 0xFF, 0x06,
- 0x00, 0x0D, 0x00, 0xA0, 0xFF, 0xEE, 0x00, 0xAA, 0xFE, 0xDC, 0x00,
- 0xB5, 0x01, 0x82, 0xF6, 0xFD, 0x37, 0x8D, 0x25, 0xE1, 0xF2, 0xA7,
- 0x05, 0x09, 0xFE, 0x45, 0x00, 0x3A, 0x00, 0xD7, 0xFF, 0x04, 0x00,
- 0x0F, 0x00, 0x93, 0xFF, 0x22, 0x01, 0x1E, 0xFE, 0x02, 0x02, 0xB3,
- 0xFF, 0x98, 0xF9, 0x87, 0x3C, 0x88, 0x1E, 0x5A, 0xF3, 0x26, 0x06,
- 0x71, 0xFD, 0xB1, 0x00, 0x04, 0x00, 0xE9, 0xFF, 0x02, 0x00, 0x11,
- 0x00, 0x8B, 0xFF, 0x4A, 0x01, 0xA0, 0xFD, 0x26, 0x03, 0x7B, 0xFD,
- 0x9F, 0xFD, 0xF4, 0x3F, 0x76, 0x17, 0x7D, 0xF4, 0x3E, 0x06, 0x0F,
- 0xFD, 0x04, 0x01, 0xD7, 0xFF, 0xF7, 0xFF, 0x01, 0x00, 0x10, 0x00,
- 0x8C, 0xFF, 0x60, 0x01, 0x3B, 0xFD, 0x37, 0x04, 0x28, 0xFB, 0x87,
- 0x02, 0x26, 0x42, 0x95, 0x10, 0x26, 0xF6, 0xF6, 0x05, 0xE4, 0xFC,
- 0x3E, 0x01, 0xB4, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x96,
- 0xFF, 0x62, 0x01, 0xF8, 0xFC, 0x21, 0x05, 0xDD, 0xF8, 0x37, 0x08,
- 0x07, 0x43, 0x19, 0x0A, 0x2F, 0xF8, 0x5D, 0x05, 0xEC, 0xFC, 0x5D,
- 0x01, 0x9B, 0xFF, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00,
- 0xAB, 0xFF, 0x4A, 0x01, 0xE1, 0xFC, 0xCF, 0x05, 0xBE, 0xF6, 0x89,
- 0x0E, 0x90, 0x42, 0x34, 0x04, 0x71, 0xFA, 0x84, 0x04, 0x22, 0xFD,
- 0x63, 0x01, 0x8E, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0xFB, 0xFF, 0xCB,
- 0xFF, 0x19, 0x01, 0xFC, 0xFC, 0x31, 0x06, 0xF4, 0xF4, 0x51, 0x15,
- 0xC3, 0x40, 0x0B, 0xFF, 0xC5, 0xFC, 0x7D, 0x03, 0x7E, 0xFD, 0x53,
- 0x01, 0x8B, 0xFF, 0x11, 0x00, 0x01, 0x00, 0xED, 0xFF, 0xF5, 0xFF,
- 0xCD, 0x00, 0x4D, 0xFD, 0x38, 0x06, 0xA3, 0xF3, 0x5A, 0x1C, 0xB5,
- 0x3D, 0xBC, 0xFA, 0x09, 0xFF, 0x5C, 0x02, 0xF5, 0xFD, 0x30, 0x01,
- 0x90, 0xFF, 0x10, 0x00, 0x03, 0x00, 0xDD, 0xFF, 0x29, 0x00, 0x69,
- 0x00, 0xD4, 0xFD, 0xD9, 0x05, 0xF3, 0xF2, 0x69, 0x23, 0x7E, 0x39,
- 0x5B, 0xF7, 0x1E, 0x01, 0x36, 0x01, 0x7E, 0xFE, 0xFF, 0x00, 0x9B,
- 0xFF, 0x0E, 0x00, 0x06, 0x00, 0xCA, 0xFF, 0x63, 0x00, 0xEF, 0xFF,
- 0x90, 0xFE, 0x0F, 0x05, 0x02, 0xF3, 0x43, 0x2A, 0x49, 0x34, 0xEF,
- 0xF4, 0xEB, 0x02, 0x1A, 0x00, 0x0E, 0xFF, 0xC6, 0x00, 0xAC, 0xFF,
- 0x0B, 0x00, 0x09, 0x00, 0xB7, 0xFF, 0xA0, 0x00, 0x67, 0xFF, 0x79,
- 0xFF, 0xDB, 0x03, 0xEB, 0xF3, 0xAA, 0x30, 0x45, 0x2E, 0x76, 0xF3,
- 0x5E, 0x04, 0x1A, 0xFF, 0x9D, 0xFF, 0x89, 0x00, 0xBE, 0xFF, 0x07,
- 0x00, 0x0C, 0x00, 0xA5, 0xFF, 0xDD, 0x00, 0xD7, 0xFE, 0x85, 0x00,
- 0x44, 0x02, 0xC0, 0xF5, 0x66, 0x36, 0xAB, 0x27, 0xE3, 0xF2, 0x6A,
- 0x05, 0x42, 0xFE, 0x20, 0x00, 0x4C, 0x00, 0xD1, 0xFF, 0x04, 0x00,
- 0x0F, 0x00, 0x96, 0xFF, 0x13, 0x01, 0x48, 0xFE, 0xA7, 0x01, 0x58,
- 0x00, 0x8B, 0xF8, 0x3C, 0x3B, 0xB4, 0x20, 0x22, 0xF3, 0x0A, 0x06,
- 0x9A, 0xFD, 0x92, 0x00, 0x14, 0x00, 0xE3, 0xFF, 0x02, 0x00, 0x10,
- 0x00, 0x8D, 0xFF, 0x3F, 0x01, 0xC4, 0xFD, 0xCD, 0x02, 0x2E, 0xFE,
- 0x49, 0xFC, 0x06, 0x3F, 0xA1, 0x19, 0x14, 0xF4, 0x41, 0x06, 0x27,
- 0xFD, 0xED, 0x00, 0xE4, 0xFF, 0xF3, 0xFF, 0x01, 0x00, 0x10, 0x00,
- 0x8B, 0xFF, 0x5B, 0x01, 0x57, 0xFD, 0xE6, 0x03, 0xE0, 0xFB, 0xEE,
- 0x00, 0x9C, 0x41, 0xAB, 0x12, 0x98, 0xF5, 0x16, 0x06, 0xEC, 0xFC,
- 0x2F, 0x01, 0xBD, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x92,
- 0xFF, 0x64, 0x01, 0x09, 0xFD, 0xDE, 0x04, 0x8E, 0xF9, 0x64, 0x06,
- 0xE6, 0x42, 0x0A, 0x0C, 0x87, 0xF7, 0x94, 0x05, 0xE5, 0xFC, 0x56,
- 0x01, 0xA2, 0xFF, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
- 0xA3, 0xFF, 0x54, 0x01, 0xE3, 0xFC, 0xA1, 0x05, 0x5E, 0xF7, 0x88,
- 0x0C, 0xD9, 0x42, 0xF2, 0x05, 0xBB, 0xF9, 0xCD, 0x04, 0x0D, 0xFD,
- 0x64, 0x01, 0x91, 0xFF, 0x0E, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0,
- 0xFF, 0x2B, 0x01, 0xEE, 0xFC, 0x1C, 0x06, 0x75, 0xF5, 0x32, 0x13,
- 0x75, 0x41, 0x8B, 0x00, 0x0E, 0xFC, 0xD2, 0x03, 0x5E, 0xFD, 0x5A,
- 0x01, 0x8B, 0xFF, 0x10, 0x00, 0x01, 0x00, 0xF2, 0xFF, 0xE7, 0xFF,
- 0xE7, 0x00, 0x2E, 0xFD, 0x41, 0x06, 0xFC, 0xF3, 0x2C, 0x1A, 0xC6,
- 0x3E, 0xF7, 0xFB, 0x5A, 0xFE, 0xB7, 0x02, 0xCE, 0xFD, 0x3C, 0x01,
- 0x8D, 0xFF, 0x10, 0x00, 0x02, 0x00, 0xE2, 0xFF, 0x18, 0x00, 0x8A,
- 0x00, 0xA5, 0xFD, 0x02, 0x06, 0x16, 0xF3, 0x3F, 0x21, 0xE6, 0x3A,
- 0x4B, 0xF8, 0x81, 0x00, 0x90, 0x01, 0x53, 0xFE, 0x0F, 0x01, 0x97,
- 0xFF, 0x0E, 0x00, 0x05, 0x00, 0xD0, 0xFF, 0x50, 0x00, 0x17, 0x00,
- 0x51, 0xFE, 0x59, 0x05, 0xE7, 0xF2, 0x31, 0x28, 0xFB, 0x35, 0x93,
- 0xF5, 0x66, 0x02, 0x6F, 0x00, 0xE2, 0xFE, 0xD8, 0x00, 0xA6, 0xFF,
- 0x0C, 0x00, 0x08, 0x00, 0xBD, 0xFF, 0x8D, 0x00, 0x92, 0xFF, 0x2D,
- 0xFF, 0x45, 0x04, 0x8B, 0xF3, 0xC1, 0x2E, 0x31, 0x30, 0xD1, 0xF3,
- 0xF6, 0x03, 0x65, 0xFF, 0x72, 0xFF, 0x9B, 0x00, 0xB8, 0xFF, 0x08,
- 0x00, 0x0B, 0x00, 0xAA, 0xFF, 0xCA, 0x00, 0x03, 0xFF, 0x2F, 0x00,
- 0xCB, 0x02, 0x16, 0xF5, 0xB8, 0x34, 0xC0, 0x29, 0xF9, 0xF2, 0x23,
- 0x05, 0x80, 0xFE, 0xF9, 0xFF, 0x5E, 0x00, 0xCC, 0xFF, 0x05, 0x00,
- 0x0E, 0x00, 0x9A, 0xFF, 0x03, 0x01, 0x73, 0xFE, 0x4C, 0x01, 0xF7,
- 0x00, 0x94, 0xF7, 0xDB, 0x39, 0xDF, 0x22, 0xFA, 0xF2, 0xE5, 0x05,
- 0xC8, 0xFD, 0x71, 0x00, 0x25, 0x00, 0xDE, 0xFF, 0x03, 0x00, 0x10,
- 0x00, 0x8F, 0xFF, 0x33, 0x01, 0xEB, 0xFD, 0x73, 0x02, 0xDE, 0xFE,
- 0x08, 0xFB, 0xFB, 0x3D, 0xCE, 0x1B, 0xB8, 0xF3, 0x3B, 0x06, 0x45,
- 0xFD, 0xD4, 0x00, 0xF2, 0xFF, 0xEF, 0xFF, 0x01, 0x00, 0x11, 0x00,
- 0x8A, 0xFF, 0x55, 0x01, 0x75, 0xFD, 0x92, 0x03, 0x97, 0xFC, 0x69,
- 0xFF, 0xF2, 0x40, 0xC8, 0x14, 0x13, 0xF5, 0x2D, 0x06, 0xF8, 0xFC,
- 0x1E, 0x01, 0xC8, 0xFF, 0xFC, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0x8F,
- 0xFF, 0x64, 0x01, 0x1D, 0xFD, 0x97, 0x04, 0x43, 0xFA, 0xA1, 0x04,
- 0xA5, 0x42, 0x08, 0x0E, 0xE6, 0xF6, 0xC4, 0x05, 0xE1, 0xFC, 0x4D,
- 0x01, 0xA9, 0xFF, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00,
- 0x9D, 0xFF, 0x5C, 0x01, 0xEA, 0xFC, 0x6C, 0x05, 0x05, 0xF8, 0x94,
- 0x0A, 0x03, 0x43, 0xC1, 0x07, 0x09, 0xF9, 0x10, 0x05, 0xFC, 0xFC,
- 0x62, 0x01, 0x95, 0xFF, 0x0D, 0x00, 0x00, 0x00, 0x02, 0x00, 0xB6,
- 0xFF, 0x3B, 0x01, 0xE5, 0xFC, 0xFF, 0x05, 0x02, 0xF6, 0x19, 0x11,
- 0x06, 0x42, 0x1F, 0x02, 0x56, 0xFB, 0x23, 0x04, 0x41, 0xFD, 0x5F,
- 0x01, 0x8B, 0xFF, 0x10, 0x00, 0x01, 0x00, 0xF6, 0xFF, 0xDA, 0xFF,
- 0xFF, 0x00, 0x15, 0xFD, 0x40, 0x06, 0x62, 0xF4, 0x01, 0x18, 0xBB,
- 0x3F, 0x47, 0xFD, 0xA8, 0xFD, 0x10, 0x03, 0xA9, 0xFD, 0x47, 0x01,
- 0x8C, 0xFF, 0x11, 0x00, 0x02, 0x00, 0xE7, 0xFF, 0x08, 0x00, 0xA9,
- 0x00, 0x7B, 0xFD, 0x20, 0x06, 0x4B, 0xF3, 0x13, 0x1F, 0x36, 0x3C,
- 0x52, 0xF9, 0xDD, 0xFF, 0xEB, 0x01, 0x28, 0xFE, 0x1F, 0x01, 0x93,
- 0xFF, 0x0F, 0x00, 0x04, 0x00, 0xD6, 0xFF, 0x3F, 0x00, 0x3C, 0x00,
- 0x16, 0xFE, 0x98, 0x05, 0xE0, 0xF2, 0x16, 0x26, 0x99, 0x37, 0x4F,
- 0xF6, 0xD9, 0x01, 0xC6, 0x00, 0xB5, 0xFE, 0xEA, 0x00, 0xA1, 0xFF,
- 0x0D, 0x00, 0x07, 0x00, 0xC3, 0xFF, 0x7A, 0x00, 0xBC, 0xFF, 0xE4,
- 0xFE, 0xA5, 0x04, 0x41, 0xF3, 0xCA, 0x2C, 0x0E, 0x32, 0x42, 0xF4,
- 0x85, 0x03, 0xB4, 0xFF, 0x46, 0xFF, 0xAE, 0x00, 0xB3, 0xFF, 0x09,
- 0x00, 0x0A, 0x00, 0xB0, 0xFF, 0xB8, 0x00, 0x30, 0xFF, 0xDC, 0xFF,
- 0x49, 0x03, 0x83, 0xF4, 0xF5, 0x32, 0xC9, 0x2B, 0x23, 0xF3, 0xD1,
- 0x04, 0xC2, 0xFE, 0xD1, 0xFF, 0x71, 0x00, 0xC6, 0xFF, 0x06, 0x00,
- 0x0D, 0x00, 0x9F, 0xFF, 0xF3, 0x00, 0x9F, 0xFE, 0xF3, 0x00, 0x90,
- 0x01, 0xB6, 0xF6, 0x5F, 0x38, 0x04, 0x25, 0xE4, 0xF2, 0xB4, 0x05,
- 0xFB, 0xFD, 0x4E, 0x00, 0x36, 0x00, 0xD9, 0xFF, 0x04, 0x00, 0x0F,
- 0x00, 0x92, 0xFF, 0x26, 0x01, 0x13, 0xFE, 0x18, 0x02, 0x89, 0xFF,
- 0xDF, 0xF9, 0xD3, 0x3C, 0xFC, 0x1D, 0x6B, 0xF3, 0x2C, 0x06, 0x67,
- 0xFD, 0xB8, 0x00, 0x00, 0x00, 0xEA, 0xFF, 0x02, 0x00, 0x11, 0x00,
- 0x8B, 0xFF, 0x4C, 0x01, 0x97, 0xFD, 0x3C, 0x03, 0x4D, 0xFD, 0xF8,
- 0xFD, 0x2A, 0x40, 0xED, 0x16, 0x9A, 0xF4, 0x3C, 0x06, 0x0A, 0xFD,
- 0x0A, 0x01, 0xD4, 0xFF, 0xF8, 0xFF, 0x01, 0x00, 0x10, 0x00, 0x8C,
- 0xFF, 0x61, 0x01, 0x34, 0xFD, 0x4B, 0x04, 0xFA, 0xFA, 0xF1, 0x02,
- 0x42, 0x42, 0x11, 0x10, 0x4C, 0xF6, 0xED, 0x05, 0xE3, 0xFC, 0x41,
- 0x01, 0xB1, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x97, 0xFF,
- 0x61, 0x01, 0xF5, 0xFC, 0x30, 0x05, 0xB1, 0xF8, 0xAE, 0x08, 0x0A,
- 0x43, 0x9F, 0x09, 0x5A, 0xF8, 0x4F, 0x05, 0xEF, 0xFC, 0x5F, 0x01,
- 0x9A, 0xFF, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0xAD,
- 0xFF, 0x48, 0x01, 0xE2, 0xFC, 0xDA, 0x05, 0x97, 0xF6, 0x0B, 0x0F,
- 0x79, 0x42, 0xC7, 0x03, 0x9E, 0xFA, 0x71, 0x04, 0x28, 0xFD, 0x63,
- 0x01, 0x8D, 0xFF, 0x0F, 0x00
-};
-
-static u16
-CoefficientSizes[] = {
- /* Playback */
- 0x00C0, 0x5000, 0x0060, 0x2800, 0x0040, 0x0060, 0x1400, 0x0000,
- /* Record */
- 0x0020, 0x1260, 0x0020, 0x1260, 0x0000, 0x0040, 0x1260, 0x0000,
-};
-
-#ifndef JUST_DATA
-
-static u16
-nm256_getStartOffset (u8 which)
-{
- u16 offset = 0;
-
- while (which-- > 0)
- offset += CoefficientSizes[which];
-
- return offset;
-}
-
-static void
-nm256_loadOneCoefficient (struct nm256_info *card, int devnum, u32 port,
- u16 which)
-{
- u32 coeffBuf = (which < 8) ? card->coeffBuf : card->allCoeffBuf;
- u16 offset = nm256_getStartOffset (which);
- u16 size = CoefficientSizes[which];
-
- card->coeffsCurrent = 0;
-
- if (nm256_debug)
- printk (KERN_INFO "NM256: Loading coefficient buffer 0x%x-0x%x with coefficient %d, size %d, port 0x%x\n",
- coeffBuf, coeffBuf + size - 1, which, size, port);
- nm256_writeBuffer8 (card, coefficients + offset, 1, coeffBuf, size);
- nm256_writePort32 (card, 2, port + 0, coeffBuf);
- /* ??? Record seems to behave differently than playback. */
- if (devnum == 0)
- size--;
- nm256_writePort32 (card, 2, port + 4, coeffBuf + size);
-}
-
-static void
-nm256_loadAllCoefficients (struct nm256_info *card)
-{
- nm256_writeBuffer8 (card, coefficients, 1, card->allCoeffBuf,
- NM_TOTAL_COEFF_COUNT * 4);
- card->coeffsCurrent = 1;
-}
-
-static void
-nm256_loadCoefficient (struct nm256_info *card, int which, int number)
-{
- static u16 addrs[3] = { 0x1c, 0x21c, 0x408 };
- /* The enable register for the specified engine. */
- u32 poffset = (which == 1 ? 0x200 : 1);
-
- if (nm256_readPort8 (card, 2, poffset) & 1) {
- printk (KERN_ERR "NM256: Engine was enabled while loading coefficients!\n");
- return;
- }
-
- /* The recording engine uses coefficient values 8-15. */
- if (which == 1)
- number += 8;
-
- if (! nm256_cachedCoefficients (card))
- nm256_loadOneCoefficient (card, which, addrs[which], number);
- else {
- u32 base = card->allCoeffBuf;
- u32 offset = nm256_getStartOffset (number);
- u32 endOffset = offset + CoefficientSizes[number];
-
- if (nm256_debug)
- printk (KERN_DEBUG "loading coefficient %d at port 0x%x, offset %d (0x%x-0x%x)\n",
- number, addrs[which], offset, base + offset,
- base + endOffset - 1);
-
- if (! card->coeffsCurrent)
- nm256_loadAllCoefficients (card);
-
- nm256_writePort32 (card, 2, addrs[which], base + offset);
- nm256_writePort32 (card, 2, addrs[which] + 4, base + endOffset - 1);
- }
-}
-
-#endif /* JUST_DATA */
-
-#endif
-
-/*
- * Local variables:
- * c-basic-offset: 4
- * End:
- */
diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c
index fc273e550944..7781c13c1476 100644
--- a/sound/oss/opl3.c
+++ b/sound/oss/opl3.c
@@ -34,7 +34,6 @@
#include "sound_config.h"
-#include "opl3.h"
#include "opl3_hw.h"
#define MAX_VOICE 18
@@ -73,7 +72,6 @@ typedef struct opl_devinfo
unsigned char cmask;
int is_opl4;
- int *osp;
} opl_devinfo;
static struct opl_devinfo *devc = NULL;
@@ -144,7 +142,7 @@ static int opl3_ioctl(int dev, unsigned int cmd, void __user * arg)
}
}
-int opl3_detect(int ioaddr, int *osp)
+static int opl3_detect(int ioaddr)
{
/*
* This function returns 1 if the FM chip is present at the given I/O port
@@ -182,7 +180,6 @@ int opl3_detect(int ioaddr, int *osp)
goto cleanup_devc;
}
- devc->osp = osp;
devc->base = ioaddr;
/* Reset timers 1 and 2 */
@@ -1105,7 +1102,7 @@ static struct synth_operations opl3_operations =
.setup_voice = opl3_setup_voice
};
-int opl3_init(int ioaddr, int *osp, struct module *owner)
+static int opl3_init(int ioaddr, struct module *owner)
{
int i;
int me;
@@ -1194,9 +1191,6 @@ int opl3_init(int ioaddr, int *osp, struct module *owner)
return me;
}
-EXPORT_SYMBOL(opl3_init);
-EXPORT_SYMBOL(opl3_detect);
-
static int me;
static int io = -1;
@@ -1209,12 +1203,12 @@ static int __init init_opl3 (void)
if (io != -1) /* User loading pure OPL3 module */
{
- if (!opl3_detect(io, NULL))
+ if (!opl3_detect(io))
{
return -ENODEV;
}
- me = opl3_init(io, NULL, THIS_MODULE);
+ me = opl3_init(io, THIS_MODULE);
}
return 0;
diff --git a/sound/oss/opl3.h b/sound/oss/opl3.h
deleted file mode 100644
index 0bc9a4bcda13..000000000000
--- a/sound/oss/opl3.h
+++ /dev/null
@@ -1,5 +0,0 @@
-
-int opl3_detect (int ioaddr, int *osp);
-int opl3_init(int ioaddr, int *osp, struct module *owner);
-
-void enable_opl3_mode(int left, int right, int both);
diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
deleted file mode 100644
index e20051f1be4d..000000000000
--- a/sound/oss/opl3sa2.c
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * sound/oss/opl3sa2.c
- *
- * A low level driver for Yamaha OPL3-SA2 and SA3 cards.
- * NOTE: All traces of the name OPL3-SAx have now (December 2000) been
- * removed from the driver code, as an email exchange with Yamaha
- * provided the information that the YMF-719 is indeed just a
- * re-badged 715.
- *
- * Copyright 1998-2001 Scott Murray <scott@spiteful.org>
- *
- * Originally based on the CS4232 driver (in cs4232.c) by Hannu Savolainen
- * and others. Now incorporates code/ideas from pss.c, also by Hannu
- * Savolainen. Both of those files are distributed with the following
- * license:
- *
- * "Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info."
- *
- * As such, in accordance with the above license, this file, opl3sa2.c, is
- * distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2 (June 1991).
- * See the "COPYING" file distributed with this software for more information.
- *
- * Change History
- * --------------
- * Scott Murray Original driver (Jun 14, 1998)
- * Paul J.Y. Lahaie Changed probing / attach code order
- * Scott Murray Added mixer support (Dec 03, 1998)
- * Scott Murray Changed detection code to be more forgiving,
- * added force option as last resort,
- * fixed ioctl return values. (Dec 30, 1998)
- * Scott Murray Simpler detection code should work all the time now
- * (with thanks to Ben Hutchings for the heuristic),
- * removed now unnecessary force option. (Jan 5, 1999)
- * Christoph Hellwig Adapted to module_init/module_exit (Mar 4, 2000)
- * Scott Murray Reworked SA2 versus SA3 mixer code, updated chipset
- * version detection code (again!). (Dec 5, 2000)
- * Scott Murray Adjusted master volume mixer scaling. (Dec 6, 2000)
- * Scott Murray Based on a patch by Joel Yliluoma (aka Bisqwit),
- * integrated wide mixer and adjusted mic, bass, treble
- * scaling. (Dec 6, 2000)
- * Scott Murray Based on a patch by Peter Englmaier, integrated
- * ymode and loopback options. (Dec 6, 2000)
- * Scott Murray Inspired by a patch by Peter Englmaier, and based on
- * what ALSA does, added initialization code for the
- * default DMA and IRQ settings. (Dec 6, 2000)
- * Scott Murray Added some more checks to the card detection code,
- * based on what ALSA does. (Dec 12, 2000)
- * Scott Murray Inspired by similar patches from John Fremlin,
- * Jim Radford, Mike Rolig, and Ingmar Steen, added 2.4
- * ISA PnP API support, mainly based on bits from
- * sb_card.c and awe_wave.c. (Dec 12, 2000)
- * Scott Murray Some small cleanups to the init code output.
- * (Jan 7, 2001)
- * Zwane Mwaikambo Added PM support. (Dec 4 2001)
- *
- * Adam Belay Converted driver to new PnP Layer (Oct 12, 2002)
- * Zwane Mwaikambo Code, data structure cleanups. (Feb 15 2002)
- * Zwane Mwaikambo Free resources during auxiliary device probe
- * failures (Apr 29 2002)
- *
- */
-
-#include <linux/pnp.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#define OPL3SA2_MODULE_NAME "opl3sa2"
-#define PFX OPL3SA2_MODULE_NAME ": "
-
-/* Useful control port indexes: */
-#define OPL3SA2_PM 0x01
-#define OPL3SA2_SYS_CTRL 0x02
-#define OPL3SA2_IRQ_CONFIG 0x03
-#define OPL3SA2_DMA_CONFIG 0x06
-#define OPL3SA2_MASTER_LEFT 0x07
-#define OPL3SA2_MASTER_RIGHT 0x08
-#define OPL3SA2_MIC 0x09
-#define OPL3SA2_MISC 0x0A
-
-#define OPL3SA3_WIDE 0x14
-#define OPL3SA3_BASS 0x15
-#define OPL3SA3_TREBLE 0x16
-
-/* Useful constants: */
-#define DEFAULT_VOLUME 50
-#define DEFAULT_MIC 50
-#define DEFAULT_TIMBRE 0
-
-/* Power saving modes */
-#define OPL3SA2_PM_MODE0 0x00
-#define OPL3SA2_PM_MODE1 0x04 /* PSV */
-#define OPL3SA2_PM_MODE2 0x05 /* PSV | PDX */
-#define OPL3SA2_PM_MODE3 0x27 /* ADOWN | PSV | PDN | PDX */
-
-
-/* For checking against what the card returns: */
-#define VERSION_UNKNOWN 0
-#define VERSION_YMF711 1
-#define VERSION_YMF715 2
-#define VERSION_YMF715B 3
-#define VERSION_YMF715E 4
-/* also assuming that anything > 4 but <= 7 is a 715E */
-
-/* Chipset type constants for use below */
-#define CHIPSET_UNKNOWN -1
-#define CHIPSET_OPL3SA2 0
-#define CHIPSET_OPL3SA3 1
-static const char *CHIPSET_TABLE[] = {"OPL3-SA2", "OPL3-SA3"};
-
-#ifdef CONFIG_PNP
-#define OPL3SA2_CARDS_MAX 4
-#else
-#define OPL3SA2_CARDS_MAX 1
-#endif
-
-/* This should be pretty obvious */
-static int opl3sa2_cards_num;
-
-typedef struct {
- /* device resources */
- unsigned short cfg_port;
- struct address_info cfg;
- struct address_info cfg_mss;
- struct address_info cfg_mpu;
-#ifdef CONFIG_PNP
- /* PnP Stuff */
- struct pnp_dev* pdev;
- int activated; /* Whether said devices have been activated */
-#endif
- unsigned int card;
- int chipset; /* What's my version(s)? */
- char *chipset_name;
-
- /* mixer data */
- int mixer;
- unsigned int volume_l;
- unsigned int volume_r;
- unsigned int mic;
- unsigned int bass_l;
- unsigned int bass_r;
- unsigned int treble_l;
- unsigned int treble_r;
- unsigned int wide_l;
- unsigned int wide_r;
-} opl3sa2_state_t;
-static opl3sa2_state_t opl3sa2_state[OPL3SA2_CARDS_MAX];
-
-
-
-/* Our parameters */
-static int __initdata io = -1;
-static int __initdata mss_io = -1;
-static int __initdata mpu_io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma2 = -1;
-static int __initdata ymode = -1;
-static int __initdata loopback = -1;
-
-#ifdef CONFIG_PNP
-/* PnP specific parameters */
-static int __initdata isapnp = 1;
-static int __initdata multiple = 1;
-
-/* Whether said devices have been activated */
-static int opl3sa2_activated[OPL3SA2_CARDS_MAX];
-#else
-static int __initdata isapnp; /* = 0 */
-static int __initdata multiple; /* = 0 */
-#endif
-
-MODULE_DESCRIPTION("Module for OPL3-SA2 and SA3 sound cards (uses AD1848 MSS driver).");
-MODULE_AUTHOR("Scott Murray <scott@spiteful.org>");
-MODULE_LICENSE("GPL");
-
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "Set I/O base of OPL3-SA2 or SA3 card (usually 0x370. Address must be even and must be from 0x100 to 0xFFE)");
-
-module_param(mss_io, int, 0);
-MODULE_PARM_DESC(mss_io, "Set MSS (audio) I/O base (0x530, 0xE80, or other. Address must end in 0 or 4 and must be from 0x530 to 0xF48)");
-
-module_param(mpu_io, int, 0);
-MODULE_PARM_DESC(mpu_io, "Set MIDI I/O base (0x330 or other. Address must be even and must be from 0x300 to 0x334)");
-
-module_param(irq, int, 0);
-MODULE_PARM_DESC(irq, "Set MSS (audio) IRQ (5, 7, 9, 10, 11, 12)");
-
-module_param(dma, int, 0);
-MODULE_PARM_DESC(dma, "Set MSS (audio) first DMA channel (0, 1, 3)");
-
-module_param(dma2, int, 0);
-MODULE_PARM_DESC(dma2, "Set MSS (audio) second DMA channel (0, 1, 3)");
-
-module_param(ymode, int, 0);
-MODULE_PARM_DESC(ymode, "Set Yamaha 3D enhancement mode (0 = Desktop/Normal, 1 = Notebook PC (1), 2 = Notebook PC (2), 3 = Hi-Fi)");
-
-module_param(loopback, int, 0);
-MODULE_PARM_DESC(loopback, "Set A/D input source. Useful for echo cancellation (0 = Mic Rch (default), 1 = Mono output loopback)");
-
-#ifdef CONFIG_PNP
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp, "When set to 0, ISA PnP support will be disabled");
-
-module_param(multiple, bool, 0);
-MODULE_PARM_DESC(multiple, "When set to 0, will not search for multiple cards");
-#endif
-
-
-/*
- * Standard read and write functions
-*/
-
-static inline void opl3sa2_write(unsigned short port,
- unsigned char index,
- unsigned char data)
-{
- outb_p(index, port);
- outb(data, port + 1);
-}
-
-
-static inline void opl3sa2_read(unsigned short port,
- unsigned char index,
- unsigned char* data)
-{
- outb_p(index, port);
- *data = inb(port + 1);
-}
-
-
-/*
- * All of the mixer functions...
- */
-
-static void opl3sa2_set_volume(opl3sa2_state_t* devc, int left, int right)
-{
- static unsigned char scale[101] = {
- 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e,
- 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09,
- 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08,
- 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
- 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00
- };
- unsigned char vol;
-
- vol = scale[left];
-
- /* If level is zero, turn on mute */
- if(!left)
- vol |= 0x80;
-
- opl3sa2_write(devc->cfg_port, OPL3SA2_MASTER_LEFT, vol);
-
- vol = scale[right];
-
- /* If level is zero, turn on mute */
- if(!right)
- vol |= 0x80;
-
- opl3sa2_write(devc->cfg_port, OPL3SA2_MASTER_RIGHT, vol);
-}
-
-
-static void opl3sa2_set_mic(opl3sa2_state_t* devc, int level)
-{
- unsigned char vol = 0x1F;
-
- if((level >= 0) && (level <= 100))
- vol = 0x1F - (unsigned char) (32 * level / 101);
-
- /* If level is zero, turn on mute */
- if(!level)
- vol |= 0x80;
-
- opl3sa2_write(devc->cfg_port, OPL3SA2_MIC, vol);
-}
-
-
-static void opl3sa3_set_bass(opl3sa2_state_t* devc, int left, int right)
-{
- unsigned char bass;
-
- bass = left ? ((unsigned char) (8 * left / 101)) : 0;
- bass |= (right ? ((unsigned char) (8 * right / 101)) : 0) << 4;
-
- opl3sa2_write(devc->cfg_port, OPL3SA3_BASS, bass);
-}
-
-
-static void opl3sa3_set_treble(opl3sa2_state_t* devc, int left, int right)
-{
- unsigned char treble;
-
- treble = left ? ((unsigned char) (8 * left / 101)) : 0;
- treble |= (right ? ((unsigned char) (8 * right / 101)) : 0) << 4;
-
- opl3sa2_write(devc->cfg_port, OPL3SA3_TREBLE, treble);
-}
-
-
-
-
-static void opl3sa2_mixer_reset(opl3sa2_state_t* devc)
-{
- if (devc) {
- opl3sa2_set_volume(devc, DEFAULT_VOLUME, DEFAULT_VOLUME);
- devc->volume_l = devc->volume_r = DEFAULT_VOLUME;
-
- opl3sa2_set_mic(devc, DEFAULT_MIC);
- devc->mic = DEFAULT_MIC;
-
- if (devc->chipset == CHIPSET_OPL3SA3) {
- opl3sa3_set_bass(devc, DEFAULT_TIMBRE, DEFAULT_TIMBRE);
- devc->bass_l = devc->bass_r = DEFAULT_TIMBRE;
- opl3sa3_set_treble(devc, DEFAULT_TIMBRE, DEFAULT_TIMBRE);
- devc->treble_l = devc->treble_r = DEFAULT_TIMBRE;
- }
- }
-}
-
-static inline void arg_to_vol_mono(unsigned int vol, int* value)
-{
- int left;
-
- left = vol & 0x00ff;
- if (left > 100)
- left = 100;
- *value = left;
-}
-
-
-static inline void arg_to_vol_stereo(unsigned int vol, int* aleft, int* aright)
-{
- arg_to_vol_mono(vol, aleft);
- arg_to_vol_mono(vol >> 8, aright);
-}
-
-
-static inline int ret_vol_mono(int vol)
-{
- return ((vol << 8) | vol);
-}
-
-
-static inline int ret_vol_stereo(int left, int right)
-{
- return ((right << 8) | left);
-}
-
-
-static int opl3sa2_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int retval, value, cmdf = cmd & 0xff;
- int __user *p = (int __user *)arg;
-
- opl3sa2_state_t* devc = &opl3sa2_state[dev];
-
- switch (cmdf) {
- case SOUND_MIXER_VOLUME:
- case SOUND_MIXER_MIC:
- case SOUND_MIXER_DEVMASK:
- case SOUND_MIXER_STEREODEVS:
- case SOUND_MIXER_RECMASK:
- case SOUND_MIXER_RECSRC:
- case SOUND_MIXER_CAPS:
- break;
-
- default:
- return -EINVAL;
- }
-
- if (((cmd >> 8) & 0xff) != 'M')
- return -EINVAL;
-
- retval = 0;
- if (_SIOC_DIR (cmd) & _SIOC_WRITE) {
- switch (cmdf) {
- case SOUND_MIXER_VOLUME:
- retval = get_user(value, (unsigned __user *) arg);
- if (retval)
- break;
- arg_to_vol_stereo(value, &devc->volume_l, &devc->volume_r);
- opl3sa2_set_volume(devc, devc->volume_l, devc->volume_r);
- value = ret_vol_stereo(devc->volume_l, devc->volume_r);
- retval = put_user(value, p);
- break;
-
- case SOUND_MIXER_MIC:
- retval = get_user(value, (unsigned __user *) arg);
- if (retval)
- break;
- arg_to_vol_mono(value, &devc->mic);
- opl3sa2_set_mic(devc, devc->mic);
- value = ret_vol_mono(devc->mic);
- retval = put_user(value, p);
- break;
-
- default:
- retval = -EINVAL;
- }
- }
- else {
- /*
- * Return parameters
- */
- switch (cmdf) {
- case SOUND_MIXER_DEVMASK:
- retval = put_user(SOUND_MASK_VOLUME | SOUND_MASK_MIC, p);
- break;
-
- case SOUND_MIXER_STEREODEVS:
- retval = put_user(SOUND_MASK_VOLUME, p);
- break;
-
- case SOUND_MIXER_RECMASK:
- /* No recording devices */
- retval = put_user(0, p);
- break;
-
- case SOUND_MIXER_CAPS:
- retval = put_user(SOUND_CAP_EXCL_INPUT, p);
- break;
-
- case SOUND_MIXER_RECSRC:
- /* No recording source */
- retval = put_user(0, p);
- break;
-
- case SOUND_MIXER_VOLUME:
- value = ret_vol_stereo(devc->volume_l, devc->volume_r);
- retval = put_user(value, p);
- break;
-
- case SOUND_MIXER_MIC:
- value = ret_vol_mono(devc->mic);
- put_user(value, p);
- break;
-
- default:
- retval = -EINVAL;
- }
- }
- return retval;
-}
-/* opl3sa2_mixer_ioctl end */
-
-
-static int opl3sa3_mixer_ioctl(int dev, unsigned int cmd, void __user * arg)
-{
- int value, retval, cmdf = cmd & 0xff;
-
- opl3sa2_state_t* devc = &opl3sa2_state[dev];
-
- switch (cmdf) {
- case SOUND_MIXER_BASS:
- value = ret_vol_stereo(devc->bass_l, devc->bass_r);
- retval = put_user(value, (int __user *) arg);
- break;
-
- case SOUND_MIXER_TREBLE:
- value = ret_vol_stereo(devc->treble_l, devc->treble_r);
- retval = put_user(value, (int __user *) arg);
- break;
-
- case SOUND_MIXER_DIGITAL1:
- value = ret_vol_stereo(devc->wide_l, devc->wide_r);
- retval = put_user(value, (int __user *) arg);
- break;
-
- default:
- retval = -EINVAL;
- }
- return retval;
-}
-/* opl3sa3_mixer_ioctl end */
-
-
-static struct mixer_operations opl3sa2_mixer_operations =
-{
- .owner = THIS_MODULE,
- .id = "OPL3-SA2",
- .name = "Yamaha OPL3-SA2",
- .ioctl = opl3sa2_mixer_ioctl
-};
-
-static struct mixer_operations opl3sa3_mixer_operations =
-{
- .owner = THIS_MODULE,
- .id = "OPL3-SA3",
- .name = "Yamaha OPL3-SA3",
- .ioctl = opl3sa3_mixer_ioctl
-};
-
-/* End of mixer-related stuff */
-
-
-/*
- * Component probe, attach, unload functions
- */
-
-static inline void __exit unload_opl3sa2_mpu(struct address_info *hw_config)
-{
- unload_mpu401(hw_config);
-}
-
-
-static void __init attach_opl3sa2_mss(struct address_info* hw_config, struct resource *ports)
-{
- int initial_mixers;
-
- initial_mixers = num_mixers;
- attach_ms_sound(hw_config, ports, THIS_MODULE); /* Slot 0 */
- if (hw_config->slots[0] != -1) {
- /* Did the MSS driver install? */
- if(num_mixers == (initial_mixers + 1)) {
- /* The MSS mixer is installed, reroute mixers appropriately */
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
- }
- else {
- printk(KERN_ERR PFX "MSS mixer not installed?\n");
- }
- }
-}
-
-
-static inline void __exit unload_opl3sa2_mss(struct address_info* hw_config)
-{
- unload_ms_sound(hw_config);
-}
-
-
-static int __init probe_opl3sa2(struct address_info* hw_config, int card)
-{
- unsigned char misc;
- unsigned char tmp;
- unsigned char version;
-
- /*
- * Try and allocate our I/O port range.
- */
- if (!request_region(hw_config->io_base, 2, OPL3SA2_MODULE_NAME)) {
- printk(KERN_ERR PFX "Control I/O port %#x not free\n",
- hw_config->io_base);
- goto out_nodev;
- }
-
- /*
- * Check if writing to the read-only version bits of the miscellaneous
- * register succeeds or not (it should not).
- */
- opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &misc);
- opl3sa2_write(hw_config->io_base, OPL3SA2_MISC, misc ^ 0x07);
- opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &tmp);
- if(tmp != misc) {
- printk(KERN_ERR PFX "Control I/O port %#x is not a YMF7xx chipset!\n",
- hw_config->io_base);
- goto out_region;
- }
-
- /*
- * Check if the MIC register is accessible.
- */
- opl3sa2_read(hw_config->io_base, OPL3SA2_MIC, &tmp);
- opl3sa2_write(hw_config->io_base, OPL3SA2_MIC, 0x8a);
- opl3sa2_read(hw_config->io_base, OPL3SA2_MIC, &tmp);
- if((tmp & 0x9f) != 0x8a) {
- printk(KERN_ERR
- PFX "Control I/O port %#x is not a YMF7xx chipset!\n",
- hw_config->io_base);
- goto out_region;
- }
- opl3sa2_write(hw_config->io_base, OPL3SA2_MIC, tmp);
-
- /*
- * Determine chipset type (SA2 or SA3)
- *
- * This is done by looking at the chipset version in the lower 3 bits
- * of the miscellaneous register.
- */
- version = misc & 0x07;
- printk(KERN_DEBUG PFX "Chipset version = %#x\n", version);
- switch (version) {
- case 0:
- opl3sa2_state[card].chipset = CHIPSET_UNKNOWN;
- printk(KERN_ERR
- PFX "Unknown Yamaha audio controller version\n");
- break;
-
- case VERSION_YMF711:
- opl3sa2_state[card].chipset = CHIPSET_OPL3SA2;
- printk(KERN_INFO PFX "Found OPL3-SA2 (YMF711)\n");
- break;
-
- case VERSION_YMF715:
- opl3sa2_state[card].chipset = CHIPSET_OPL3SA3;
- printk(KERN_INFO
- PFX "Found OPL3-SA3 (YMF715 or YMF719)\n");
- break;
-
- case VERSION_YMF715B:
- opl3sa2_state[card].chipset = CHIPSET_OPL3SA3;
- printk(KERN_INFO
- PFX "Found OPL3-SA3 (YMF715B or YMF719B)\n");
- break;
-
- case VERSION_YMF715E:
- default:
- opl3sa2_state[card].chipset = CHIPSET_OPL3SA3;
- printk(KERN_INFO
- PFX "Found OPL3-SA3 (YMF715E or YMF719E)\n");
- break;
- }
-
- if (opl3sa2_state[card].chipset != CHIPSET_UNKNOWN) {
- /* Generate a pretty name */
- opl3sa2_state[card].chipset_name = (char *)CHIPSET_TABLE[opl3sa2_state[card].chipset];
- return 0;
- }
-
-out_region:
- release_region(hw_config->io_base, 2);
-out_nodev:
- return -ENODEV;
-}
-
-
-static void __init attach_opl3sa2(struct address_info* hw_config, int card)
-{
- /* Initialize IRQ configuration to IRQ-B: -, IRQ-A: WSS+MPU+OPL3 */
- opl3sa2_write(hw_config->io_base, OPL3SA2_IRQ_CONFIG, 0x0d);
-
- /* Initialize DMA configuration */
- if(hw_config->dma2 == hw_config->dma) {
- /* Want DMA configuration DMA-B: -, DMA-A: WSS-P+WSS-R */
- opl3sa2_write(hw_config->io_base, OPL3SA2_DMA_CONFIG, 0x03);
- }
- else {
- /* Want DMA configuration DMA-B: WSS-R, DMA-A: WSS-P */
- opl3sa2_write(hw_config->io_base, OPL3SA2_DMA_CONFIG, 0x21);
- }
-}
-
-
-static void __init attach_opl3sa2_mixer(struct address_info *hw_config, int card)
-{
- struct mixer_operations* mixer_operations;
- opl3sa2_state_t* devc = &opl3sa2_state[card];
-
- /* Install master mixer */
- if (devc->chipset == CHIPSET_OPL3SA3) {
- mixer_operations = &opl3sa3_mixer_operations;
- }
- else {
- mixer_operations = &opl3sa2_mixer_operations;
- }
-
- devc->cfg_port = hw_config->io_base;
- devc->mixer = sound_install_mixer(MIXER_DRIVER_VERSION,
- mixer_operations->name,
- mixer_operations,
- sizeof(struct mixer_operations),
- devc);
- if(devc->mixer < 0) {
- printk(KERN_ERR PFX "Could not install %s master mixer\n",
- mixer_operations->name);
- }
- else {
- opl3sa2_mixer_reset(devc);
-
- }
-}
-
-
-static void opl3sa2_clear_slots(struct address_info* hw_config)
-{
- int i;
-
- for(i = 0; i < 6; i++) {
- hw_config->slots[i] = -1;
- }
-}
-
-
-static void __init opl3sa2_set_ymode(struct address_info* hw_config, int ymode)
-{
- /*
- * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and
- * it's supported.
- *
- * 0: Desktop (aka normal) 5-12 cm speakers
- * 1: Notebook PC mode 1 3 cm speakers
- * 2: Notebook PC mode 2 1.5 cm speakers
- * 3: Hi-fi 16-38 cm speakers
- */
- if(ymode >= 0 && ymode <= 3) {
- unsigned char sys_ctrl;
-
- opl3sa2_read(hw_config->io_base, OPL3SA2_SYS_CTRL, &sys_ctrl);
- sys_ctrl = (sys_ctrl & 0xcf) | ((ymode & 3) << 4);
- opl3sa2_write(hw_config->io_base, OPL3SA2_SYS_CTRL, sys_ctrl);
- }
- else {
- printk(KERN_ERR PFX "not setting ymode, it must be one of 0,1,2,3\n");
- }
-}
-
-
-static void __init opl3sa2_set_loopback(struct address_info* hw_config, int loopback)
-{
- if(loopback >= 0 && loopback <= 1) {
- unsigned char misc;
-
- opl3sa2_read(hw_config->io_base, OPL3SA2_MISC, &misc);
- misc = (misc & 0xef) | ((loopback & 1) << 4);
- opl3sa2_write(hw_config->io_base, OPL3SA2_MISC, misc);
- }
- else {
- printk(KERN_ERR PFX "not setting loopback, it must be either 0 or 1\n");
- }
-}
-
-
-static void __exit unload_opl3sa2(struct address_info* hw_config, int card)
-{
- /* Release control ports */
- release_region(hw_config->io_base, 2);
-
- /* Unload mixer */
- if(opl3sa2_state[card].mixer >= 0)
- sound_unload_mixerdev(opl3sa2_state[card].mixer);
-
-}
-
-#ifdef CONFIG_PNP
-static struct pnp_device_id pnp_opl3sa2_list[] = {
- {.id = "YMH0021", .driver_data = 0},
- {.id = ""}
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_opl3sa2_list);
-
-static int opl3sa2_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
- int card = opl3sa2_cards_num;
-
- /* we don't actually want to return an error as the user may have specified
- * no multiple card search
- */
-
- if (opl3sa2_cards_num == OPL3SA2_CARDS_MAX)
- return 0;
- opl3sa2_activated[card] = 1;
-
- /* Our own config: */
- opl3sa2_state[card].cfg.io_base = pnp_port_start(dev, 4);
- opl3sa2_state[card].cfg.irq = pnp_irq(dev, 0);
- opl3sa2_state[card].cfg.dma = pnp_dma(dev, 0);
- opl3sa2_state[card].cfg.dma2 = pnp_dma(dev, 1);
-
- /* The MSS config: */
- opl3sa2_state[card].cfg_mss.io_base = pnp_port_start(dev, 1);
- opl3sa2_state[card].cfg_mss.irq = pnp_irq(dev, 0);
- opl3sa2_state[card].cfg_mss.dma = pnp_dma(dev, 0);
- opl3sa2_state[card].cfg_mss.dma2 = pnp_dma(dev, 1);
- opl3sa2_state[card].cfg_mss.card_subtype = 1; /* No IRQ or DMA setup */
-
- opl3sa2_state[card].cfg_mpu.io_base = pnp_port_start(dev, 3);
- opl3sa2_state[card].cfg_mpu.irq = pnp_irq(dev, 0);
- opl3sa2_state[card].cfg_mpu.dma = -1;
- opl3sa2_state[card].cfg_mpu.dma2 = -1;
- opl3sa2_state[card].cfg_mpu.always_detect = 1; /* It's there, so use shared IRQs */
-
- /* Call me paranoid: */
- opl3sa2_clear_slots(&opl3sa2_state[card].cfg);
- opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mss);
- opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mpu);
-
- opl3sa2_state[card].pdev = dev;
- opl3sa2_cards_num++;
-
- return 0;
-}
-
-static struct pnp_driver opl3sa2_driver = {
- .name = "opl3sa2",
- .id_table = pnp_opl3sa2_list,
- .probe = opl3sa2_pnp_probe,
-};
-
-#endif /* CONFIG_PNP */
-
-/* End of component functions */
-
-/*
- * Install OPL3-SA2 based card(s).
- *
- * Need to have ad1848 and mpu401 loaded ready.
- */
-static int __init init_opl3sa2(void)
-{
- int card, max;
-
- /* Sanitize isapnp and multiple settings */
- isapnp = isapnp != 0 ? 1 : 0;
- multiple = multiple != 0 ? 1 : 0;
-
- max = (multiple && isapnp) ? OPL3SA2_CARDS_MAX : 1;
-
-#ifdef CONFIG_PNP
- if (isapnp){
- pnp_register_driver(&opl3sa2_driver);
- if(!opl3sa2_cards_num){
- printk(KERN_INFO PFX "No PnP cards found\n");
- isapnp = 0;
- }
- max = opl3sa2_cards_num;
- }
-#endif
-
- for (card = 0; card < max; card++) {
- /* If a user wants an I/O then assume they meant it */
- struct resource *ports;
- int base;
-
- if (!isapnp) {
- if (io == -1 || irq == -1 || dma == -1 ||
- dma2 == -1 || mss_io == -1) {
- printk(KERN_ERR
- PFX "io, mss_io, irq, dma, and dma2 must be set\n");
- return -EINVAL;
- }
- opl3sa2_cards_num++;
-
- /*
- * Our own config:
- * (NOTE: IRQ and DMA aren't used, so they're set to
- * give pretty output from conf_printf. :)
- */
- opl3sa2_state[card].cfg.io_base = io;
- opl3sa2_state[card].cfg.irq = irq;
- opl3sa2_state[card].cfg.dma = dma;
- opl3sa2_state[card].cfg.dma2 = dma2;
-
- /* The MSS config: */
- opl3sa2_state[card].cfg_mss.io_base = mss_io;
- opl3sa2_state[card].cfg_mss.irq = irq;
- opl3sa2_state[card].cfg_mss.dma = dma;
- opl3sa2_state[card].cfg_mss.dma2 = dma2;
- opl3sa2_state[card].cfg_mss.card_subtype = 1; /* No IRQ or DMA setup */
-
- opl3sa2_state[card].cfg_mpu.io_base = mpu_io;
- opl3sa2_state[card].cfg_mpu.irq = irq;
- opl3sa2_state[card].cfg_mpu.dma = -1;
- opl3sa2_state[card].cfg_mpu.always_detect = 1; /* Use shared IRQs */
-
- /* Call me paranoid: */
- opl3sa2_clear_slots(&opl3sa2_state[card].cfg);
- opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mss);
- opl3sa2_clear_slots(&opl3sa2_state[card].cfg_mpu);
- }
-
- /* FIXME: leak */
- if (probe_opl3sa2(&opl3sa2_state[card].cfg, card))
- return -ENODEV;
-
- base = opl3sa2_state[card].cfg_mss.io_base;
-
- if (!request_region(base, 4, "WSS config"))
- goto failed;
-
- ports = request_region(base + 4, 4, "ad1848");
- if (!ports)
- goto failed2;
-
- if (!probe_ms_sound(&opl3sa2_state[card].cfg_mss, ports)) {
- /*
- * If one or more cards are already registered, don't
- * return an error but print a warning. Note, this
- * should never really happen unless the hardware or
- * ISA PnP screwed up.
- */
- release_region(base + 4, 4);
- failed2:
- release_region(base, 4);
- failed:
- release_region(opl3sa2_state[card].cfg.io_base, 2);
-
- if (opl3sa2_cards_num) {
- printk(KERN_WARNING
- PFX "There was a problem probing one "
- " of the ISA PNP cards, continuing\n");
- opl3sa2_cards_num--;
- continue;
- } else
- return -ENODEV;
- }
-
- attach_opl3sa2(&opl3sa2_state[card].cfg, card);
- conf_printf(opl3sa2_state[card].chipset_name, &opl3sa2_state[card].cfg);
- attach_opl3sa2_mixer(&opl3sa2_state[card].cfg, card);
- attach_opl3sa2_mss(&opl3sa2_state[card].cfg_mss, ports);
-
- /* ewww =) */
- opl3sa2_state[card].card = card;
-
- /*
- * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and
- * it's supported.
- */
- if (ymode != -1) {
- if (opl3sa2_state[card].chipset == CHIPSET_OPL3SA2) {
- printk(KERN_ERR
- PFX "ymode not supported on OPL3-SA2\n");
- }
- else {
- opl3sa2_set_ymode(&opl3sa2_state[card].cfg, ymode);
- }
- }
-
-
- /* Set A/D input to Mono loopback if asked to. */
- if (loopback != -1) {
- opl3sa2_set_loopback(&opl3sa2_state[card].cfg, loopback);
- }
-
- /* Attach MPU if we've been asked to do so, failure isn't fatal */
- if (opl3sa2_state[card].cfg_mpu.io_base != -1) {
- int base = opl3sa2_state[card].cfg_mpu.io_base;
- struct resource *ports;
- ports = request_region(base, 2, "mpu401");
- if (!ports)
- goto out;
- if (!probe_mpu401(&opl3sa2_state[card].cfg_mpu, ports)) {
- release_region(base, 2);
- goto out;
- }
- if (attach_mpu401(&opl3sa2_state[card].cfg_mpu, THIS_MODULE)) {
- printk(KERN_ERR PFX "failed to attach MPU401\n");
- opl3sa2_state[card].cfg_mpu.slots[1] = -1;
- }
- }
- }
-
-out:
- if (isapnp) {
- printk(KERN_NOTICE PFX "%d PnP card(s) found.\n", opl3sa2_cards_num);
- }
-
- return 0;
-}
-
-
-/*
- * Uninstall OPL3-SA2 based card(s).
- */
-static void __exit cleanup_opl3sa2(void)
-{
- int card;
-
- for(card = 0; card < opl3sa2_cards_num; card++) {
- if (opl3sa2_state[card].cfg_mpu.slots[1] != -1) {
- unload_opl3sa2_mpu(&opl3sa2_state[card].cfg_mpu);
- }
- unload_opl3sa2_mss(&opl3sa2_state[card].cfg_mss);
- unload_opl3sa2(&opl3sa2_state[card].cfg, card);
-#ifdef CONFIG_PNP
- pnp_unregister_driver(&opl3sa2_driver);
-#endif
- }
-}
-
-module_init(init_opl3sa2);
-module_exit(cleanup_opl3sa2);
-
-#ifndef MODULE
-static int __init setup_opl3sa2(char *str)
-{
- /* io, irq, dma, dma2,... */
-#ifdef CONFIG_PNP
- int ints[11];
-#else
- int ints[9];
-#endif
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- mss_io = ints[5];
- mpu_io = ints[6];
- ymode = ints[7];
- loopback = ints[8];
-#ifdef CONFIG_PNP
- isapnp = ints[9];
- multiple = ints[10];
-#endif
- return 1;
-}
-
-__setup("opl3sa2=", setup_opl3sa2);
-#endif
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index 3bc1f6e9e4a3..96adc47917aa 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -11,12 +11,12 @@
* Built from:
* Low level code: <audio@tridentmicro.com> from ALSA
* Framework: Thomas Sailer <sailer@ife.ee.ethz.ch>
- * Extended by: Zach Brown <zab@redhat.com>
+ * Extended by: Zach Brown <zab@redhat.com>
*
* Hacked up by:
* Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
* Ollie Lho <ollie@sis.com.tw> SiS 7018 Audio Core Support
- * Ching-Ling Lee <cling-li@ali.com.tw> ALi 5451 Audio Core Support
+ * Ching-Ling Lee <cling-li@ali.com.tw> ALi 5451 Audio Core Support
* Matt Wu <mattwu@acersoftech.com.cn> ALi 5451 Audio Core Support
* Peter Wächtler <pwaechtler@loewe-komp.de> CyberPro5050 support
* Muli Ben-Yehuda <mulix@mulix.org>
@@ -54,33 +54,33 @@
* adapt to new pci joystick attachment interface
* v0.14.10f
* July 24 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * patch from Eric Lemar (via Ian Soboroff): in suspend and resume,
- * fix wrong cast from pci_dev* to struct trident_card*.
+ * patch from Eric Lemar (via Ian Soboroff): in suspend and resume,
+ * fix wrong cast from pci_dev* to struct trident_card*.
* v0.14.10e
* July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * rewrite the DMA buffer allocation/deallcoation functions, to make it
- * modular and fix a bug where we would call free_pages on memory
- * obtained with pci_alloc_consistent. Also remove unnecessary #ifdef
+ * rewrite the DMA buffer allocation/deallcoation functions, to make it
+ * modular and fix a bug where we would call free_pages on memory
+ * obtained with pci_alloc_consistent. Also remove unnecessary #ifdef
* CONFIG_PROC_FS and various other cleanups.
* v0.14.10d
* July 19 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* made several printk(KERN_NOTICE...) into TRDBG(...), to avoid spamming
- * my syslog with hundreds of messages.
+ * my syslog with hundreds of messages.
* v0.14.10c
* July 16 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
* Cleaned up Lei Hu's 0.4.10 driver to conform to Documentation/CodingStyle
- * and the coding style used in the rest of the file.
+ * and the coding style used in the rest of the file.
* v0.14.10b
* June 23 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * add a missing unlock_set_fmt, remove a superflous lock/unlock pair
- * with nothing in between.
+ * add a missing unlock_set_fmt, remove a superflous lock/unlock pair
+ * with nothing in between.
* v0.14.10a
- * June 21 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
- * use a debug macro instead of #ifdef CONFIG_DEBUG, trim to 80 columns
- * per line, use 'do {} while (0)' in statement macros.
+ * June 21 2002 Muli Ben-Yehuda <mulix@actcom.co.il>
+ * use a debug macro instead of #ifdef CONFIG_DEBUG, trim to 80 columns
+ * per line, use 'do {} while (0)' in statement macros.
* v0.14.10
* June 6 2002 Lei Hu <Lei_hu@ali.com.tw>
- * rewrite the part to read/write registers of audio codec for Ali5451
+ * rewrite the part to read/write registers of audio codec for Ali5451
* v0.14.9e
* January 2 2002 Vojtech Pavlik <vojtech@ucw.cz> added gameport
* support to avoid resource conflict with pcigame.c
@@ -111,7 +111,7 @@
* Set EBUF1 and EBUF2 to still mode
* Add dc97/ac97 reset function
* Fix power management: ali_restore_regs
- * unreleased
+ * unreleased
* Mar 09 2001 Matt Wu
* Add cache for ac97 access
* v0.14.7
@@ -120,7 +120,7 @@
* Fix bug: an extra tail will be played when playing
* Jan 05 2001 Matt Wu
* Implement multi-channels and S/PDIF in support for ALi 1535+
- * v0.14.6
+ * v0.14.6
* Nov 1 2000 Ching-Ling Lee
* Fix the bug of memory leak when switching 5.1-channels to 2 channels.
* Add lock protection into dynamic changing format of data.
@@ -138,7 +138,7 @@
* v0.14.3 May 10 2000 Ollie Lho
* fixed a small bug in trident_update_ptr, xmms 1.0.1 no longer uses 100% CPU
* v0.14.2 Mar 29 2000 Ching-Ling Lee
- * Add clear to silence advance in trident_update_ptr
+ * Add clear to silence advance in trident_update_ptr
* fix invalid data of the end of the sound
* v0.14.1 Mar 24 2000 Ching-Ling Lee
* ALi 5451 support added, playback and recording O.K.
@@ -178,7 +178,7 @@
* SiS 7018 support added, playback O.K.
* v0.01 Alan Cox et. al.
* Initial Release in kernel 2.3.30, does not work
- *
+ *
* ToDo
* Clean up of low level channel register access code. (done)
* Fix the bug on dma buffer management in update_ptr, read/write, drain_dac (done)
@@ -326,7 +326,7 @@ struct trident_state {
unsigned error; /* number of over/underruns */
/* put process on wait queue when no more space in buffer */
- wait_queue_head_t wait;
+ wait_queue_head_t wait;
/* redundant, but makes calculations easier */
unsigned fragsize;
@@ -358,7 +358,7 @@ struct trident_state {
struct trident_channel {
int num; /* channel number */
u32 lba; /* Loop Begine Address, where dma buffer starts */
- u32 eso; /* End Sample Offset, wehre dma buffer ends */
+ u32 eso; /* End Sample Offset, wehre dma buffer ends */
/* (in the unit of samples) */
u32 delta; /* delta value, sample rate / 48k for playback, */
/* 48k/sample rate for recording */
@@ -417,7 +417,7 @@ struct trident_card {
/* soundcore stuff */
int dev_audio;
- /* structures for abstraction of hardware facilities, codecs, */
+ /* structures for abstraction of hardware facilities, codecs, */
/* banks and channels */
struct ac97_codec *ac97_codec[NR_AC97];
struct trident_pcm_bank banks[NR_BANKS];
@@ -479,7 +479,7 @@ static void trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val);
static u16 trident_ac97_get(struct ac97_codec *codec, u8 reg);
static int trident_open_mixdev(struct inode *inode, struct file *file);
-static int trident_ioctl_mixdev(struct inode *inode, struct file *file,
+static int trident_ioctl_mixdev(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
static void ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val);
@@ -496,10 +496,10 @@ static void ali_disable_spdif_in(struct trident_card *card);
static void ali_disable_special_channel(struct trident_card *card, int ch);
static void ali_setup_spdif_out(struct trident_card *card, int flag);
static int ali_write_5_1(struct trident_state *state,
- const char __user *buffer,
- int cnt_for_multi_channel, unsigned int *copy_count,
+ const char __user *buffer,
+ int cnt_for_multi_channel, unsigned int *copy_count,
unsigned int *state_cnt);
-static int ali_allocate_other_states_resources(struct trident_state *state,
+static int ali_allocate_other_states_resources(struct trident_state *state,
int chan_nums);
static void ali_free_other_states_resources(struct trident_state *state);
@@ -722,7 +722,7 @@ trident_free_pcm_channel(struct trident_card *card, unsigned int channel)
if (channel < 31 || channel > 63)
return;
- if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX ||
+ if (card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_DX ||
card->pci_id == PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) {
b = inb(TRID_REG(card, T4D_REC_CH));
if ((b & ~0x80) == channel)
@@ -742,7 +742,7 @@ cyber_alloc_pcm_channel(struct trident_card *card)
int idx;
/* The cyberpro 5050 has only 32 voices and one bank */
- /* .. at least they are not documented (if you want to call that
+ /* .. at least they are not documented (if you want to call that
* crap documentation), perhaps broken ? */
bank = &card->banks[BANK_A];
@@ -802,7 +802,7 @@ cyber_init_ritual(struct trident_card *card)
/* enable, if it was disabled */
if ((portDat & CYBER_BMSK_AUENZ) != CYBER_BMSK_AUENZ_ENABLE) {
printk(KERN_INFO "cyberpro5050: enabling audio controller\n");
- cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE,
+ cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE,
portDat | CYBER_BMSK_AUENZ_ENABLE);
/* check again if hardware is enabled now */
portDat = cyber_inidx(CYBER_PORT_AUDIO, CYBER_IDX_AUDIO_ENABLE);
@@ -811,7 +811,7 @@ cyber_init_ritual(struct trident_card *card)
printk(KERN_ERR "cyberpro5050: initAudioAccess: no success\n");
ret = -1;
} else {
- cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_IRQ_ENABLE,
+ cyber_outidx(CYBER_PORT_AUDIO, CYBER_IDX_IRQ_ENABLE,
CYBER_BMSK_AUDIO_INT_ENABLE);
cyber_outidx(CYBER_PORT_AUDIO, 0xbf, 0x01);
cyber_outidx(CYBER_PORT_AUDIO, 0xba, 0x20);
@@ -827,7 +827,7 @@ cyber_init_ritual(struct trident_card *card)
/* called with spin lock held */
static int
-trident_load_channel_registers(struct trident_card *card, u32 * data,
+trident_load_channel_registers(struct trident_card *card, u32 * data,
unsigned int channel)
{
int i;
@@ -845,7 +845,7 @@ trident_load_channel_registers(struct trident_card *card, u32 * data,
continue;
outl(data[i], TRID_REG(card, CHANNEL_START + 4 * i));
}
- if (card->pci_id == PCI_DEVICE_ID_ALI_5451 ||
+ if (card->pci_id == PCI_DEVICE_ID_ALI_5451 ||
card->pci_id == PCI_DEVICE_ID_INTERG_5050) {
outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF1));
outl(ALI_EMOD_Still, TRID_REG(card, ALI_EBUF2));
@@ -884,7 +884,7 @@ trident_write_voice_regs(struct trident_state *state)
break;
case PCI_DEVICE_ID_TRIDENT_4DWAVE_NX:
data[0] = (channel->delta << 24);
- data[2] = ((channel->delta << 16) & 0xff000000) |
+ data[2] = ((channel->delta << 16) & 0xff000000) |
(channel->eso & 0x00ffffff);
data[3] = channel->fm_vol & 0xffff;
break;
@@ -989,13 +989,13 @@ trident_play_setup(struct trident_state *state)
if (state->card->pci_id != PCI_DEVICE_ID_SI_7018) {
channel->attribute = 0;
if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451) {
- if ((channel->num == ALI_SPDIF_IN_CHANNEL) ||
+ if ((channel->num == ALI_SPDIF_IN_CHANNEL) ||
(channel->num == ALI_PCM_IN_CHANNEL))
ali_disable_special_channel(state->card, channel->num);
- else if ((inl(TRID_REG(state->card, ALI_GLOBAL_CONTROL))
+ else if ((inl(TRID_REG(state->card, ALI_GLOBAL_CONTROL))
& ALI_SPDIF_OUT_CH_ENABLE)
&& (channel->num == ALI_SPDIF_OUT_CHANNEL)) {
- ali_set_spdif_out_rate(state->card,
+ ali_set_spdif_out_rate(state->card,
state->dmabuf.rate);
state->dmabuf.channel->delta = 0x1000;
}
@@ -1063,7 +1063,7 @@ trident_rec_setup(struct trident_state *state)
channel->lba = dmabuf->dma_handle;
channel->delta = compute_rate_rec(dmabuf->rate);
- if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) &&
+ if ((card->pci_id == PCI_DEVICE_ID_ALI_5451) &&
(channel->num == ALI_SPDIF_IN_CHANNEL)) {
rate = ali_get_spdif_in_rate(card);
if (rate == 0) {
@@ -1180,8 +1180,8 @@ start_adc(struct trident_state *state)
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
- if ((dmabuf->mapped ||
- dmabuf->count < (signed) dmabuf->dmasize) &&
+ if ((dmabuf->mapped ||
+ dmabuf->count < (signed) dmabuf->dmasize) &&
dmabuf->ready) {
dmabuf->enable |= ADC_RUNNING;
trident_enable_voice_irq(card, chan_num);
@@ -1261,7 +1261,7 @@ alloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev, int order)
void *rawbuf = NULL;
struct page *page, *pend;
- if (!(rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
+ if (!(rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
&dmabuf->dma_handle)))
return -ENOMEM;
@@ -1272,7 +1272,7 @@ alloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev, int order)
dmabuf->rawbuf = rawbuf;
dmabuf->buforder = order;
- /* now mark the pages as reserved; otherwise */
+ /* now mark the pages as reserved; otherwise */
/* remap_pfn_range doesn't do what we want */
pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
for (page = virt_to_page(rawbuf); page <= pend; page++)
@@ -1310,7 +1310,7 @@ dealloc_dmabuf(struct dmabuf *dmabuf, struct pci_dev *pci_dev)
pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
ClearPageReserved(page);
- pci_free_consistent(pci_dev, PAGE_SIZE << dmabuf->buforder,
+ pci_free_consistent(pci_dev, PAGE_SIZE << dmabuf->buforder,
dmabuf->rawbuf, dmabuf->dma_handle);
dmabuf->rawbuf = NULL;
}
@@ -1368,7 +1368,7 @@ prog_dmabuf(struct trident_state *state, enum dmabuf_mode rec)
dealloc_dmabuf(&state->dmabuf, state->card->pci_dev);
/* release the auxiliary DMA buffers */
for (i -= 2; i >= 0; i--)
- dealloc_dmabuf(&state->other_states[i]->dmabuf,
+ dealloc_dmabuf(&state->other_states[i]->dmabuf,
state->card->pci_dev);
unlock_set_fmt(state);
return ret;
@@ -1398,7 +1398,7 @@ prog_dmabuf(struct trident_state *state, enum dmabuf_mode rec)
dmabuf->fragsamples = dmabuf->fragsize >> sample_shift[dmabuf->fmt];
dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
- memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80,
+ memset(dmabuf->rawbuf, (dmabuf->fmt & TRIDENT_FMT_16BIT) ? 0 : 0x80,
dmabuf->dmasize);
spin_lock_irqsave(&s->card->lock, flags);
@@ -1453,7 +1453,7 @@ trident_clear_tail(struct trident_state *state)
swptr = dmabuf->swptr;
spin_unlock_irqrestore(&state->card->lock, flags);
- if (swptr == 0 || swptr == dmabuf->dmasize / 2 ||
+ if (swptr == 0 || swptr == dmabuf->dmasize / 2 ||
swptr == dmabuf->dmasize)
return;
@@ -1511,7 +1511,7 @@ drain_dac(struct trident_state *state, int nonblock)
/* No matter how much data is left in the buffer, we have to wait until
CSO == ESO/2 or CSO == ESO when address engine interrupts */
- if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451 ||
+ if (state->card->pci_id == PCI_DEVICE_ID_ALI_5451 ||
state->card->pci_id == PCI_DEVICE_ID_INTERG_5050) {
diff = dmabuf->swptr - trident_get_dma_addr(state) + dmabuf->dmasize;
diff = diff % (dmabuf->dmasize);
@@ -1532,7 +1532,7 @@ drain_dac(struct trident_state *state, int nonblock)
return 0;
}
-/* update buffer manangement pointers, especially, */
+/* update buffer manangement pointers, especially, */
/* dmabuf->count and dmabuf->hwptr */
static void
trident_update_ptr(struct trident_state *state)
@@ -1559,11 +1559,11 @@ trident_update_ptr(struct trident_state *state)
} else {
dmabuf->count += diff;
- if (dmabuf->count < 0 ||
+ if (dmabuf->count < 0 ||
dmabuf->count > dmabuf->dmasize) {
- /* buffer underrun or buffer overrun, */
- /* we have no way to recover it here, just */
- /* stop the machine and let the process */
+ /* buffer underrun or buffer overrun, */
+ /* we have no way to recover it here, just */
+ /* stop the machine and let the process */
/* force hwptr and swptr to sync */
__stop_adc(state);
dmabuf->error++;
@@ -1582,7 +1582,7 @@ trident_update_ptr(struct trident_state *state)
} else {
dmabuf->count -= diff;
- if (dmabuf->count < 0 ||
+ if (dmabuf->count < 0 ||
dmabuf->count > dmabuf->dmasize) {
/* buffer underrun or buffer overrun, we have no way to recover
it here, just stop the machine and let the process force hwptr
@@ -1608,13 +1608,13 @@ trident_update_ptr(struct trident_state *state)
if (state->chans_num == 6) {
clear_cnt = clear_cnt / 2;
swptr = swptr / 2;
- memset(state->other_states[0]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[0]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
- memset(state->other_states[1]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[1]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
- memset(state->other_states[2]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[2]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
- memset(state->other_states[3]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[3]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
}
dmabuf->endcleared = 1;
@@ -1627,13 +1627,13 @@ trident_update_ptr(struct trident_state *state)
if (state->chans_num == 6) {
clear_cnt = clear_cnt / 2;
swptr = swptr / 2;
- memset(state->other_states[0]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[0]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
- memset(state->other_states[1]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[1]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
- memset(state->other_states[2]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[2]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
- memset(state->other_states[3]->dmabuf.rawbuf + swptr,
+ memset(state->other_states[3]->dmabuf.rawbuf + swptr,
silence, clear_cnt);
}
dmabuf->endcleared = 1;
@@ -1665,7 +1665,7 @@ trident_address_interrupt(struct trident_card *card)
if ((state = card->states[i]) != NULL) {
trident_update_ptr(state);
} else {
- printk(KERN_WARNING "trident: spurious channel "
+ printk(KERN_WARNING "trident: spurious channel "
"irq %d.\n", channel);
trident_stop_voice(card, channel);
trident_disable_voice_irq(card, channel);
@@ -1694,7 +1694,7 @@ ali_hwvol_control(struct trident_card *card, int opt)
if (opt == 1) { // MUTE
dwTemp ^= 0x8000;
- ali_ac97_write(card->ac97_codec[0],
+ ali_ac97_write(card->ac97_codec[0],
0x02, dwTemp);
} else if (opt == 2) { // Down
if (mute)
@@ -1706,7 +1706,7 @@ ali_hwvol_control(struct trident_card *card, int opt)
dwTemp &= 0xe0e0;
dwTemp |= (volume[0]) | (volume[1] << 8);
ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp);
- card->ac97_codec[0]->mixer_state[0] = ((32 - volume[0]) * 25 / 8) |
+ card->ac97_codec[0]->mixer_state[0] = ((32 - volume[0]) * 25 / 8) |
(((32 - volume[1]) * 25 / 8) << 8);
} else if (opt == 4) { // Up
if (mute)
@@ -1718,7 +1718,7 @@ ali_hwvol_control(struct trident_card *card, int opt)
dwTemp &= 0xe0e0;
dwTemp |= (volume[0]) | (volume[1] << 8);
ali_ac97_write(card->ac97_codec[0], 0x02, dwTemp);
- card->ac97_codec[0]->mixer_state[0] = ((32 - volume[0]) * 25 / 8) |
+ card->ac97_codec[0]->mixer_state[0] = ((32 - volume[0]) * 25 / 8) |
(((32 - volume[1]) * 25 / 8) << 8);
} else {
/* Nothing needs doing */
@@ -1801,7 +1801,7 @@ cyber_address_interrupt(struct trident_card *card)
if ((state = card->states[i]) != NULL) {
trident_update_ptr(state);
} else {
- printk(KERN_WARNING "cyber5050: spurious "
+ printk(KERN_WARNING "cyber5050: spurious "
"channel irq %d.\n", channel);
trident_stop_voice(card, channel);
trident_disable_voice_irq(card, channel);
@@ -1836,21 +1836,21 @@ trident_interrupt(int irq, void *dev_id)
ali_queue_task(card, gpio & 0x07);
}
event = inl(TRID_REG(card, T4D_MISCINT));
- outl(event | (ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
+ outl(event | (ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
TRID_REG(card, T4D_MISCINT));
spin_unlock(&card->lock);
return IRQ_HANDLED;
}
/* manually clear interrupt status, bad hardware design, blame T^2 */
- outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
+ outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW),
TRID_REG(card, T4D_MISCINT));
spin_unlock(&card->lock);
return IRQ_HANDLED;
}
-/* in this loop, dmabuf.count signifies the amount of data that is waiting */
-/* to be copied to the user's buffer. it is filled by the dma machine and */
+/* in this loop, dmabuf.count signifies the amount of data that is waiting */
+/* to be copied to the user's buffer. it is filled by the dma machine and */
/* drained by this loop. */
static ssize_t
trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
@@ -1878,8 +1878,8 @@ trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos
while (count > 0) {
spin_lock_irqsave(&state->card->lock, flags);
if (dmabuf->count > (signed) dmabuf->dmasize) {
- /* buffer overrun, we are recovering from */
- /* sleep_on_timeout, resync hwptr and swptr, */
+ /* buffer overrun, we are recovering from */
+ /* sleep_on_timeout, resync hwptr and swptr, */
/* make process flush the buffer */
dmabuf->count = dmabuf->dmasize;
dmabuf->swptr = dmabuf->hwptr;
@@ -1894,7 +1894,7 @@ trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos
cnt = count;
if (cnt <= 0) {
unsigned long tmo;
- /* buffer is empty, start the dma machine and */
+ /* buffer is empty, start the dma machine and */
/* wait for data to be recorded */
start_adc(state);
if (file->f_flags & O_NONBLOCK) {
@@ -1904,8 +1904,8 @@ trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos
}
mutex_unlock(&state->sem);
- /* No matter how much space left in the buffer, */
- /* we have to wait until CSO == ESO/2 or CSO == ESO */
+ /* No matter how much space left in the buffer, */
+ /* we have to wait until CSO == ESO/2 or CSO == ESO */
/* when address engine interrupts */
tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
tmo >>= sample_shift[dmabuf->fmt];
@@ -2005,7 +2005,7 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
while (count > 0) {
spin_lock_irqsave(&state->card->lock, flags);
if (dmabuf->count < 0) {
- /* buffer underrun, we are recovering from */
+ /* buffer underrun, we are recovering from */
/* sleep_on_timeout, resync hwptr and swptr */
dmabuf->count = 0;
dmabuf->swptr = dmabuf->hwptr;
@@ -2020,7 +2020,7 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
cnt = count;
if (cnt <= 0) {
unsigned long tmo;
- /* buffer is full, start the dma machine and */
+ /* buffer is full, start the dma machine and */
/* wait for data to be played */
start_dac(state);
if (file->f_flags & O_NONBLOCK) {
@@ -2028,8 +2028,8 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
ret = -EAGAIN;
goto out;
}
- /* No matter how much data left in the buffer, */
- /* we have to wait until CSO == ESO/2 or CSO == ESO */
+ /* No matter how much data left in the buffer, */
+ /* we have to wait until CSO == ESO/2 or CSO == ESO */
/* when address engine interrupts */
lock_set_fmt(state);
tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2);
@@ -2037,15 +2037,15 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
unlock_set_fmt(state);
mutex_unlock(&state->sem);
- /* There are two situations when sleep_on_timeout */
- /* returns, one is when the interrupt is serviced */
- /* correctly and the process is waked up by ISR */
- /* ON TIME. Another is when timeout is expired, which */
- /* means that either interrupt is NOT serviced */
- /* correctly (pending interrupt) or it is TOO LATE */
- /* for the process to be scheduled to run */
- /* (scheduler latency) which results in a (potential) */
- /* buffer underrun. And worse, there is NOTHING we */
+ /* There are two situations when sleep_on_timeout */
+ /* returns, one is when the interrupt is serviced */
+ /* correctly and the process is waked up by ISR */
+ /* ON TIME. Another is when timeout is expired, which */
+ /* means that either interrupt is NOT serviced */
+ /* correctly (pending interrupt) or it is TOO LATE */
+ /* for the process to be scheduled to run */
+ /* (scheduler latency) which results in a (potential) */
+ /* buffer underrun. And worse, there is NOTHING we */
/* can do to prevent it. */
if (!interruptible_sleep_on_timeout(&dmabuf->wait, tmo)) {
pr_debug(KERN_ERR "trident: playback schedule "
@@ -2054,8 +2054,8 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
dmabuf->fragsize, dmabuf->count,
dmabuf->hwptr, dmabuf->swptr);
- /* a buffer underrun, we delay the recovery */
- /* until next time the while loop begin and */
+ /* a buffer underrun, we delay the recovery */
+ /* until next time the while loop begin and */
/* we REALLY have data to play */
}
if (signal_pending(current)) {
@@ -2079,7 +2079,7 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
if (state->chans_num == 6) {
copy_count = 0;
state_cnt = 0;
- if (ali_write_5_1(state, buffer, cnt, &copy_count,
+ if (ali_write_5_1(state, buffer, cnt, &copy_count,
&state_cnt) == -EFAULT) {
if (state_cnt) {
swptr = (swptr + state_cnt) % dmabuf->dmasize;
@@ -2096,7 +2096,7 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
goto out;
}
} else {
- if (copy_from_user(dmabuf->rawbuf + swptr,
+ if (copy_from_user(dmabuf->rawbuf + swptr,
buffer, cnt)) {
if (!ret)
ret = -EFAULT;
@@ -2172,7 +2172,7 @@ trident_poll(struct file *file, struct poll_table_struct *wait)
if (dmabuf->count >= (signed) dmabuf->fragsize)
mask |= POLLOUT | POLLWRNORM;
} else {
- if ((signed) dmabuf->dmasize >= dmabuf->count +
+ if ((signed) dmabuf->dmasize >= dmabuf->count +
(signed) dmabuf->fragsize)
mask |= POLLOUT | POLLWRNORM;
}
@@ -2227,7 +2227,7 @@ out:
}
static int
-trident_ioctl(struct inode *inode, struct file *file,
+trident_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct trident_state *state = (struct trident_state *)file->private_data;
@@ -2348,7 +2348,7 @@ trident_ioctl(struct inode *inode, struct file *file,
case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */
- ret = put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
+ ret = put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
AFMT_U8, p);
break;
@@ -2379,7 +2379,7 @@ trident_ioctl(struct inode *inode, struct file *file,
}
}
unlock_set_fmt(state);
- ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
+ ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
AFMT_U8, p);
break;
@@ -2438,7 +2438,7 @@ trident_ioctl(struct inode *inode, struct file *file,
stop_adc(state);
dmabuf->ready = 0;
if (val >= 2) {
- if (!((file->f_mode & FMODE_WRITE) &&
+ if (!((file->f_mode & FMODE_WRITE) &&
(val == 6)))
val = 2;
dmabuf->fmt |= TRIDENT_FMT_STEREO;
@@ -2504,7 +2504,7 @@ trident_ioctl(struct inode *inode, struct file *file,
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
+ ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
-EFAULT : 0;
break;
@@ -2524,7 +2524,7 @@ trident_ioctl(struct inode *inode, struct file *file,
abinfo.fragstotal = dmabuf->numfrag;
abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
+ ret = copy_to_user(argp, &abinfo, sizeof (abinfo)) ?
-EFAULT : 0;
break;
@@ -2533,7 +2533,7 @@ trident_ioctl(struct inode *inode, struct file *file,
break;
case SNDCTL_DSP_GETCAPS:
- ret = put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
+ ret = put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
DSP_CAP_MMAP | DSP_CAP_BIND, p);
break;
@@ -2553,7 +2553,7 @@ trident_ioctl(struct inode *inode, struct file *file,
}
if (file->f_mode & FMODE_READ) {
if (val & PCM_ENABLE_INPUT) {
- if (!dmabuf->ready &&
+ if (!dmabuf->ready &&
(ret = prog_dmabuf_record(state)))
break;
start_adc(state);
@@ -2562,7 +2562,7 @@ trident_ioctl(struct inode *inode, struct file *file,
}
if (file->f_mode & FMODE_WRITE) {
if (val & PCM_ENABLE_OUTPUT) {
- if (!dmabuf->ready &&
+ if (!dmabuf->ready &&
(ret = prog_dmabuf_playback(state)))
break;
start_dac(state);
@@ -2589,7 +2589,7 @@ trident_ioctl(struct inode *inode, struct file *file,
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize - 1;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
+ ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
-EFAULT : 0;
break;
@@ -2612,7 +2612,7 @@ trident_ioctl(struct inode *inode, struct file *file,
if (dmabuf->mapped)
dmabuf->count &= dmabuf->fragsize - 1;
spin_unlock_irqrestore(&state->card->lock, flags);
- ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
+ ret = copy_to_user(argp, &cinfo, sizeof (cinfo)) ?
-EFAULT : 0;
break;
@@ -2641,17 +2641,17 @@ trident_ioctl(struct inode *inode, struct file *file,
break;
case SOUND_PCM_READ_CHANNELS:
- ret = put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
+ ret = put_user((dmabuf->fmt & TRIDENT_FMT_STEREO) ? 2 : 1,
p);
break;
case SOUND_PCM_READ_BITS:
- ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
+ ret = put_user((dmabuf->fmt & TRIDENT_FMT_16BIT) ? AFMT_S16_LE :
AFMT_U8, p);
break;
case SNDCTL_DSP_GETCHANNELMASK:
- ret = put_user(DSP_BIND_FRONT | DSP_BIND_SURR |
+ ret = put_user(DSP_BIND_FRONT | DSP_BIND_SURR |
DSP_BIND_CENTER_LFE, p);
break;
@@ -2671,10 +2671,10 @@ trident_ioctl(struct inode *inode, struct file *file,
} else {
dmabuf->ready = 0;
if (file->f_mode & FMODE_READ)
- dmabuf->channel->attribute = (CHANNEL_REC |
+ dmabuf->channel->attribute = (CHANNEL_REC |
SRC_ENABLE);
if (file->f_mode & FMODE_WRITE)
- dmabuf->channel->attribute = (CHANNEL_SPC_PB |
+ dmabuf->channel->attribute = (CHANNEL_SPC_PB |
SRC_ENABLE);
dmabuf->channel->attribute |= mask2attr[ffs(val)];
}
@@ -2702,6 +2702,7 @@ trident_open(struct inode *inode, struct file *file)
struct trident_card *card = devs;
struct trident_state *state = NULL;
struct dmabuf *dmabuf = NULL;
+ unsigned long flags;
/* Added by Matt Wu 01-05-2001 */
/* TODO: there's some redundacy here wrt the check below */
@@ -2765,8 +2766,8 @@ trident_open(struct inode *inode, struct file *file)
init_waitqueue_head(&dmabuf->wait);
file->private_data = state;
- /* set default sample format. According to OSS Programmer's */
- /* Guide /dev/dsp should be default to unsigned 8-bits, mono, */
+ /* set default sample format. According to OSS Programmer's */
+ /* Guide /dev/dsp should be default to unsigned 8-bits, mono, */
/* with sample rate 8kHz and /dev/dspW will accept 16-bits sample */
if (file->f_mode & FMODE_WRITE) {
dmabuf->fmt &= ~TRIDENT_FMT_MASK;
@@ -2779,11 +2780,13 @@ trident_open(struct inode *inode, struct file *file)
/* set default channel attribute to normal playback */
dmabuf->channel->attribute = CHANNEL_PB;
}
+ spin_lock_irqsave(&card->lock, flags);
trident_set_dac_rate(state, 8000);
+ spin_unlock_irqrestore(&card->lock, flags);
}
if (file->f_mode & FMODE_READ) {
- /* FIXME: Trident 4d can only record in signed 16-bits stereo, */
+ /* FIXME: Trident 4d can only record in signed 16-bits stereo, */
/* 48kHz sample, to be dealed with in trident_set_adc_rate() ?? */
dmabuf->fmt &= ~TRIDENT_FMT_MASK;
if ((minor & 0x0f) == SND_DEV_DSP16)
@@ -2794,10 +2797,12 @@ trident_open(struct inode *inode, struct file *file)
if (card->pci_id == PCI_DEVICE_ID_SI_7018) {
/* set default channel attribute to 0x8a80, record from
PCM L/R FIFO and mono = (left + right + 1)/2 */
- dmabuf->channel->attribute = (CHANNEL_REC | PCM_LR |
+ dmabuf->channel->attribute = (CHANNEL_REC | PCM_LR |
MONO_MIX);
}
+ spin_lock_irqsave(&card->lock, flags);
trident_set_adc_rate(state, 8000);
+ spin_unlock_irqrestore(&card->lock, flags);
/* Added by Matt Wu 01-05-2001 */
if (card->pci_id == PCI_DEVICE_ID_ALI_5451)
@@ -3020,7 +3025,7 @@ acquirecodecaccess(struct trident_card *card)
break;
if (wsemabits == 0) {
unlock:
- outl(((u32) (wcontrol & 0x1eff) | 0x00004000),
+ outl(((u32) (wcontrol & 0x1eff) | 0x00004000),
TRID_REG(card, ALI_AC97_WRITE));
continue;
}
@@ -3104,7 +3109,7 @@ ali_ac97_get(struct trident_card *card, int secondary, u8 reg)
ncount = 10;
while (1) {
- if ((inw(TRID_REG(card, ALI_AC97_WRITE)) & ALI_AC97_BUSY_READ)
+ if ((inw(TRID_REG(card, ALI_AC97_WRITE)) & ALI_AC97_BUSY_READ)
!= 0)
break;
if (ncount <= 0)
@@ -3112,7 +3117,7 @@ ali_ac97_get(struct trident_card *card, int secondary, u8 reg)
if (ncount-- == 1) {
pr_debug("ali_ac97_read :try clear busy flag\n");
aud_reg = inl(TRID_REG(card, ALI_AC97_WRITE));
- outl((aud_reg & 0xffff7fff),
+ outl((aud_reg & 0xffff7fff),
TRID_REG(card, ALI_AC97_WRITE));
}
udelay(10);
@@ -3159,7 +3164,7 @@ ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val)
wcontrol = inw(TRID_REG(card, ALI_AC97_WRITE));
wcontrol &= 0xff00;
- wcontrol |= (0x8100 | reg); /* bit 8=1: (ali1535 )reserved/ */
+ wcontrol |= (0x8100 | reg); /* bit 8=1: (ali1535 )reserved/ */
/* ali1535+ write */
outl((data | wcontrol), TRID_REG(card, ALI_AC97_WRITE));
@@ -3177,7 +3182,7 @@ ali_ac97_set(struct trident_card *card, int secondary, u8 reg, u16 val)
break;
if (ncount-- == 1) {
pr_debug("ali_ac97_set :try clear busy flag!!\n");
- outw(wcontrol & 0x7fff,
+ outw(wcontrol & 0x7fff,
TRID_REG(card, ALI_AC97_WRITE));
}
udelay(10);
@@ -3382,7 +3387,7 @@ ali_detect_spdif_rate(struct trident_card *card)
bval |= 0x1F;
outb(bval, TRID_REG(card, ALI_SPDIF_CTRL + 1));
- while (((R1 < 0x0B) || (R1 > 0x0E)) && (R1 != 0x12) &&
+ while (((R1 < 0x0B) || (R1 > 0x0E)) && (R1 != 0x12) &&
count <= 50000) {
count++;
@@ -3669,14 +3674,14 @@ ali_save_regs(struct trident_card *card)
spin_lock_irqsave(&card->lock, flags);
ali_registers.global_regs[0x2c] = inl(TRID_REG(card, T4D_MISCINT));
- //ali_registers.global_regs[0x20] = inl(TRID_REG(card,T4D_START_A));
+ //ali_registers.global_regs[0x20] = inl(TRID_REG(card,T4D_START_A));
ali_registers.global_regs[0x21] = inl(TRID_REG(card, T4D_STOP_A));
//disable all IRQ bits
outl(ALI_DISABLE_ALL_IRQ, TRID_REG(card, T4D_MISCINT));
for (i = 1; i < ALI_MIXER_REGS; i++)
- ali_registers.mixer_regs[i] = ali_ac97_read(card->ac97_codec[0],
+ ali_registers.mixer_regs[i] = ali_ac97_read(card->ac97_codec[0],
i * 2);
for (i = 0; i < ALI_GLOBAL_REGS; i++) {
@@ -3688,7 +3693,7 @@ ali_save_regs(struct trident_card *card)
for (i = 0; i < ALI_CHANNELS; i++) {
outb(i, TRID_REG(card, T4D_LFO_GC_CIR));
for (j = 0; j < ALI_CHANNEL_REGS; j++)
- ali_registers.channel_regs[i][j] = inl(TRID_REG(card,
+ ali_registers.channel_regs[i][j] = inl(TRID_REG(card,
j * 4 + 0xe0));
}
@@ -3707,18 +3712,18 @@ ali_restore_regs(struct trident_card *card)
spin_lock_irqsave(&card->lock, flags);
for (i = 1; i < ALI_MIXER_REGS; i++)
- ali_ac97_write(card->ac97_codec[0], i * 2,
+ ali_ac97_write(card->ac97_codec[0], i * 2,
ali_registers.mixer_regs[i]);
for (i = 0; i < ALI_CHANNELS; i++) {
outb(i, TRID_REG(card, T4D_LFO_GC_CIR));
for (j = 0; j < ALI_CHANNEL_REGS; j++)
- outl(ali_registers.channel_regs[i][j],
+ outl(ali_registers.channel_regs[i][j],
TRID_REG(card, j * 4 + 0xe0));
}
for (i = 0; i < ALI_GLOBAL_REGS; i++) {
- if ((i * 4 == T4D_MISCINT) || (i * 4 == T4D_STOP_A) ||
+ if ((i * 4 == T4D_MISCINT) || (i * 4 == T4D_STOP_A) ||
(i * 4 == T4D_START_A))
continue;
outl(ali_registers.global_regs[i], TRID_REG(card, i * 4));
@@ -3763,7 +3768,7 @@ ali_alloc_pcm_channel(struct trident_card *card)
bank = &card->banks[BANK_A];
- if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) &
+ if (inl(TRID_REG(card, ALI_GLOBAL_CONTROL)) &
(ALI_SPDIF_OUT_CH_ENABLE)) {
idx = ALI_SPDIF_OUT_CHANNEL;
if (!(bank->bitmap & (1 << idx))) {
@@ -3774,7 +3779,7 @@ ali_alloc_pcm_channel(struct trident_card *card)
}
}
- for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST;
+ for (idx = ALI_PCM_OUT_CHANNEL_FIRST; idx <= ALI_PCM_OUT_CHANNEL_LAST;
idx++) {
if (!(bank->bitmap & (1 << idx))) {
struct trident_channel *channel = &bank->channels[idx];
@@ -3785,9 +3790,9 @@ ali_alloc_pcm_channel(struct trident_card *card)
}
/* no more free channels avaliable */
-#if 0
+#if 0
printk(KERN_ERR "ali: no more channels available on Bank A.\n");
-#endif /* 0 */
+#endif /* 0 */
return NULL;
}
@@ -3812,9 +3817,9 @@ ali_alloc_rec_pcm_channel(struct trident_card *card)
}
/* no free recordable channels avaliable */
-#if 0
+#if 0
printk(KERN_ERR "ali: no recordable channels available on Bank A.\n");
-#endif /* 0 */
+#endif /* 0 */
return NULL;
}
@@ -3837,14 +3842,14 @@ ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate)
break;
}
- /* select spdif_out */
+ /* select spdif_out */
ch_st_sel = inb(TRID_REG(card, ALI_SPDIF_CTRL)) & ALI_SPDIF_OUT_CH_STATUS;
- ch_st_sel |= 0x80; /* select right */
+ ch_st_sel |= 0x80; /* select right */
outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL));
outb(status_rate | 0x20, TRID_REG(card, ALI_SPDIF_CS + 2));
- ch_st_sel &= (~0x80); /* select left */
+ ch_st_sel &= (~0x80); /* select left */
outb(ch_st_sel, TRID_REG(card, ALI_SPDIF_CTRL));
outw(status_rate | 0x10, TRID_REG(card, ALI_SPDIF_CS + 2));
}
@@ -3881,14 +3886,14 @@ ali_address_interrupt(struct trident_card *card)
}
}
-/* Updating the values of counters of other_states' DMAs without lock
+/* Updating the values of counters of other_states' DMAs without lock
protection is no harm because all DMAs of multi-channels and interrupt
depend on a master state's DMA, and changing the counters of the master
state DMA is protected by a spinlock.
*/
static int
-ali_write_5_1(struct trident_state *state, const char __user *buf,
- int cnt_for_multi_channel, unsigned int *copy_count,
+ali_write_5_1(struct trident_state *state, const char __user *buf,
+ int cnt_for_multi_channel, unsigned int *copy_count,
unsigned int *state_cnt)
{
@@ -3904,10 +3909,10 @@ ali_write_5_1(struct trident_state *state, const char __user *buf,
if ((i = state->multi_channels_adjust_count) > 0) {
if (i == 1) {
- if (copy_from_user(dmabuf->rawbuf + swptr,
+ if (copy_from_user(dmabuf->rawbuf + swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
+ seek_offset(swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
i--;
(*state_cnt) += sample_s;
@@ -3916,10 +3921,10 @@ ali_write_5_1(struct trident_state *state, const char __user *buf,
i = i - (state->chans_num - other_dma_nums);
for (; (i < other_dma_nums) && (cnt_for_multi_channel > 0); i++) {
dmabuf_temp = &state->other_states[i]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
}
if (cnt_for_multi_channel == 0)
@@ -3928,39 +3933,39 @@ ali_write_5_1(struct trident_state *state, const char __user *buf,
if (cnt_for_multi_channel > 0) {
loop = cnt_for_multi_channel / (state->chans_num * sample_s);
for (i = 0; i < loop; i++) {
- if (copy_from_user(dmabuf->rawbuf + swptr, buffer,
+ if (copy_from_user(dmabuf->rawbuf + swptr, buffer,
sample_s * 2))
return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
+ seek_offset(swptr, buffer, cnt_for_multi_channel,
sample_s * 2, *copy_count);
(*state_cnt) += (sample_s * 2);
dmabuf_temp = &state->other_states[0]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
dmabuf_temp = &state->other_states[1]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
dmabuf_temp = &state->other_states[2]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
dmabuf_temp = &state->other_states[3]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
+ if (copy_from_user(dmabuf_temp->rawbuf + dmabuf_temp->swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
+ seek_offset(dmabuf_temp->swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
}
@@ -3969,15 +3974,15 @@ ali_write_5_1(struct trident_state *state, const char __user *buf,
if (copy_from_user(dmabuf->rawbuf + swptr, buffer, sample_s))
return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
+ seek_offset(swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
(*state_cnt) += sample_s;
if (cnt_for_multi_channel > 0) {
- if (copy_from_user(dmabuf->rawbuf + swptr,
+ if (copy_from_user(dmabuf->rawbuf + swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(swptr, buffer, cnt_for_multi_channel,
+ seek_offset(swptr, buffer, cnt_for_multi_channel,
sample_s, *copy_count);
(*state_cnt) += sample_s;
@@ -3986,12 +3991,12 @@ ali_write_5_1(struct trident_state *state, const char __user *buf,
loop = state->multi_channels_adjust_count - diff;
for (i = 0; i < loop; i++) {
dmabuf_temp = &state->other_states[i]->dmabuf;
- if (copy_from_user(dmabuf_temp->rawbuf +
- dmabuf_temp->swptr,
+ if (copy_from_user(dmabuf_temp->rawbuf +
+ dmabuf_temp->swptr,
buffer, sample_s))
return -EFAULT;
- seek_offset(dmabuf_temp->swptr, buffer,
- cnt_for_multi_channel,
+ seek_offset(dmabuf_temp->swptr, buffer,
+ cnt_for_multi_channel,
sample_s, *copy_count);
}
}
@@ -4048,11 +4053,11 @@ ali_write_proc(struct file *file, const char __user *buffer, unsigned long count
ali_disable_special_channel(card, ALI_SPDIF_OUT_CHANNEL);
break;
case '1':
- ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT |
+ ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT |
ALI_SPDIF_OUT_PCM);
break;
case '2':
- ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT |
+ ali_setup_spdif_out(card, ALI_SPDIF_OUT_TO_SPDIF_OUT |
ALI_SPDIF_OUT_NON_PCM);
break;
case '3':
@@ -4077,7 +4082,7 @@ trident_open_mixdev(struct inode *inode, struct file *file)
for (card = devs; card != NULL; card = card->next)
for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL &&
+ if (card->ac97_codec[i] != NULL &&
card->ac97_codec[i]->dev_mixer == minor)
goto match;
@@ -4091,7 +4096,7 @@ trident_open_mixdev(struct inode *inode, struct file *file)
}
static int
-trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+trident_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
@@ -4185,9 +4190,9 @@ trident_ac97_init(struct trident_card *card)
/* disable AC97 GPIO interrupt */
outl(0x00, TRID_REG(card, SI_AC97_GPIO));
/* when power up the AC link is in cold reset mode so stop it */
- outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT | SECONDARY_ID,
+ outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT | SECONDARY_ID,
TRID_REG(card, SI_SERIAL_INTF_CTRL));
- /* it take a long time to recover from a cold reset */
+ /* it take a long time to recover from a cold reset */
/* (especially when you have more than one codec) */
udelay(2000);
ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL));
@@ -4207,9 +4212,9 @@ trident_ac97_init(struct trident_card *card)
/* disable AC97 GPIO interrupt */
outl(0x00, TRID_REG(card, SI_AC97_GPIO));
/* when power up, the AC link is in cold reset mode, so stop it */
- outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT,
+ outl(PCMOUT | SURROUT | CENTEROUT | LFEOUT,
TRID_REG(card, SI_SERIAL_INTF_CTRL));
- /* it take a long time to recover from a cold reset (especially */
+ /* it take a long time to recover from a cold reset (especially */
/* when you have more than one codec) */
udelay(2000);
ready_2nd = inl(TRID_REG(card, SI_SERIAL_INTF_CTRL));
@@ -4221,7 +4226,7 @@ trident_ac97_init(struct trident_card *card)
if ((codec = ac97_alloc_codec()) == NULL)
return -ENOMEM;
- /* initialize some basic codec information, other fields */
+ /* initialize some basic codec information, other fields */
/* will be filled in ac97_probe_codec */
codec->private_data = card;
codec->id = num_ac97;
@@ -4352,8 +4357,8 @@ static inline int trident_register_gameport(struct trident_card *card) { return
static inline void trident_unregister_gameport(struct trident_card *card) { }
#endif /* SUPPORT_JOYSTICK */
-/* install the driver, we do not allocate hardware channel nor DMA buffer */
-/* now, they are defered until "ACCESS" time (in prog_dmabuf called by */
+/* install the driver, we do not allocate hardware channel nor DMA buffer */
+/* now, they are defered until "ACCESS" time (in prog_dmabuf called by */
/* open/read/write/ioctl/mmap) */
static int __devinit
trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
@@ -4376,9 +4381,9 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
else
dma_mask = TRIDENT_DMA_MASK;
if (pci_set_dma_mask(pci_dev, dma_mask)) {
- printk(KERN_ERR "trident: architecture does not support"
- " %s PCI busmaster DMA\n",
- pci_dev->device == PCI_DEVICE_ID_ALI_5451 ?
+ printk(KERN_ERR "trident: architecture does not support"
+ " %s PCI busmaster DMA\n",
+ pci_dev->device == PCI_DEVICE_ID_ALI_5451 ?
"32-bit" : "30-bit");
goto out;
}
@@ -4422,7 +4427,7 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
pci_set_master(pci_dev);
- printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
+ printk(KERN_INFO "trident: %s found at IO 0x%04lx, IRQ %d\n",
card_names[pci_id->driver_data], card->iobase, card->irq);
if (card->pci_id == PCI_DEVICE_ID_ALI_5451) {
@@ -4449,9 +4454,9 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
/* Add H/W Volume Control By Matt Wu Jul. 06, 2001 */
card->hwvolctl = 0;
- pci_dev_m1533 = pci_find_device(PCI_VENDOR_ID_AL,
- PCI_DEVICE_ID_AL_M1533,
- pci_dev_m1533);
+ pci_dev_m1533 = pci_get_device(PCI_VENDOR_ID_AL,
+ PCI_DEVICE_ID_AL_M1533,
+ pci_dev_m1533);
rc = -ENODEV;
if (pci_dev_m1533 == NULL)
goto out_proc_fs;
@@ -4465,6 +4470,8 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
bits &= 0xbf; /*clear bit 6 */
pci_write_config_byte(pci_dev_m1533, 0x7b, bits);
}
+ pci_dev_put(pci_dev_m1533);
+
} else if (card->pci_id == PCI_DEVICE_ID_INTERG_5050) {
card->alloc_pcm_channel = cyber_alloc_pcm_channel;
card->alloc_rec_pcm_channel = cyber_alloc_pcm_channel;
@@ -4482,7 +4489,7 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
rc = -ENODEV;
if (request_irq(card->irq, &trident_interrupt, IRQF_SHARED,
card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "trident: unable to allocate irq %d\n",
+ printk(KERN_ERR "trident: unable to allocate irq %d\n",
card->irq);
goto out_proc_fs;
}
@@ -4533,7 +4540,7 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
printk(KERN_INFO "trident: Running on Alpha system "
"type Nautilus\n");
ac97_data = ali_ac97_get(card, 0, AC97_POWER_CONTROL);
- ali_ac97_set(card, 0, AC97_POWER_CONTROL,
+ ali_ac97_set(card, 0, AC97_POWER_CONTROL,
ac97_data | ALI_EAPD_POWER_DOWN);
}
}
@@ -4566,7 +4573,7 @@ out_proc_fs:
devs = NULL;
out_release_region:
release_region(iobase, 256);
- return rc;
+ return rc;
}
static void __devexit
@@ -4634,8 +4641,8 @@ static struct pci_driver trident_pci_driver = {
static int __init
trident_init_module(void)
{
- printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro "
- "5050 PCI Audio, version " DRIVER_VERSION ", " __TIME__ " "
+ printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451,Tvia CyberPro "
+ "5050 PCI Audio, version " DRIVER_VERSION ", " __TIME__ " "
__DATE__ "\n");
return pci_register_driver(&trident_pci_driver);
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index 61e35ecc57b8..c6b44102aa5b 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -33,6 +33,7 @@ config SND_ALS4000
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_PCM
+ select SND_SB_COMMON
help
Say Y here to include support for soundcards based on Avance Logic
ALS4000 chips.
@@ -215,6 +216,16 @@ config SND_CS46XX_NEW_DSP
This works better than the old code, so say Y.
+config SND_CS5530
+ tristate "CS5530 Audio"
+ depends on SND && ISA_DMA_API
+ select SND_SB16_DSP
+ help
+ Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips.
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd-cs5530.
+
config SND_CS5535AUDIO
tristate "CS5535/CS5536 Audio"
depends on SND && X86 && !X86_64
diff --git a/sound/pci/Makefile b/sound/pci/Makefile
index e06736da9ef1..cd76e0293d06 100644
--- a/sound/pci/Makefile
+++ b/sound/pci/Makefile
@@ -12,6 +12,7 @@ snd-azt3328-objs := azt3328.o
snd-bt87x-objs := bt87x.o
snd-cmipci-objs := cmipci.o
snd-cs4281-objs := cs4281.o
+snd-cs5530-objs := cs5530.o
snd-ens1370-objs := ens1370.o
snd-ens1371-objs := ens1371.o
snd-es1938-objs := es1938.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o
obj-$(CONFIG_SND_BT87X) += snd-bt87x.o
obj-$(CONFIG_SND_CMIPCI) += snd-cmipci.o
obj-$(CONFIG_SND_CS4281) += snd-cs4281.o
+obj-$(CONFIG_SND_CS5530) += snd-cs5530.o
obj-$(CONFIG_SND_ENS1370) += snd-ens1370.o
obj-$(CONFIG_SND_ENS1371) += snd-ens1371.o
obj-$(CONFIG_SND_ES1938) += snd-es1938.o
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index cb59f994c68f..05b4c8696941 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -239,7 +239,7 @@ struct snd_ali_image {
struct snd_ali {
- unsigned long irq;
+ int irq;
unsigned long port;
unsigned char revision;
@@ -731,8 +731,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec)
return;
}
- count = 0;
- while (count++ <= 50000) {
+ for (count = 0; count <= 50000; count++) {
snd_ali_delay(codec, 6);
bval = inb(ALI_REG(codec,ALI_SPDIF_CTRL + 1));
R2 = bval & 0x1F;
@@ -2218,7 +2217,7 @@ static int __devinit snd_ali_create(struct snd_card *card,
codec->card = card;
codec->pci = pci;
codec->irq = -1;
- pci_read_config_byte(pci, PCI_REVISION_ID, &codec->revision);
+ codec->revision = pci->revision;
codec->spdif_support = spdif_support;
if (pcm_streams < 1)
@@ -2343,7 +2342,7 @@ static int __devinit snd_ali_probe(struct pci_dev *pci,
strcpy(card->driver, "ALI5451");
strcpy(card->shortname, "ALI 5451");
- sprintf(card->longname, "%s at 0x%lx, irq %li",
+ sprintf(card->longname, "%s at 0x%lx, irq %i",
card->shortname, codec->port, codec->irq);
snd_ali_printk("register card.\n");
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 8afcb98ca7bb..48cc39b771d9 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -88,8 +88,8 @@
#define PLAYBACK_BLOCK_COUNTER 0x9A
#define RECORD_BLOCK_COUNTER 0x9B
-#define DEBUG_CALLS 1
-#define DEBUG_PLAY_REC 1
+#define DEBUG_CALLS 0
+#define DEBUG_PLAY_REC 0
#if DEBUG_CALLS
#define snd_als300_dbgcalls(format, args...) printk(format, ##args)
@@ -733,7 +733,8 @@ static int __devinit snd_als300_create(struct snd_card *card,
snd_als300_init(chip);
- if (snd_als300_ac97(chip) < 0) {
+ err = snd_als300_ac97(chip);
+ if (err < 0) {
snd_printk(KERN_WARNING "Could not create ac97\n");
snd_als300_free(chip);
return err;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 7d8053b5e8d5..89184a424140 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1639,15 +1639,12 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
{
struct snd_card *card;
struct atiixp *chip;
- unsigned char revision;
int err;
card = snd_card_new(index, id, THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
- pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
-
strcpy(card->driver, spdif_aclink ? "ATIIXP" : "ATIIXP-SPDMA");
strcpy(card->shortname, "ATI IXP");
if ((err = snd_atiixp_create(card, pci, &chip)) < 0)
@@ -1670,7 +1667,8 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
snd_atiixp_chip_start(chip);
snprintf(card->longname, sizeof(card->longname),
- "%s rev %x with %s at %#lx, irq %i", card->shortname, revision,
+ "%s rev %x with %s at %#lx, irq %i", card->shortname,
+ pci->revision,
chip->ac97[0] ? snd_ac97_get_short_name(chip->ac97[0]) : "?",
chip->addr, chip->irq);
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 904023fe4f26..ce752f84457a 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1283,15 +1283,12 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
{
struct snd_card *card;
struct atiixp_modem *chip;
- unsigned char revision;
int err;
card = snd_card_new(index, id, THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
- pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
-
strcpy(card->driver, "ATIIXP-MODEM");
strcpy(card->shortname, "ATI IXP Modem");
if ((err = snd_atiixp_create(card, pci, &chip)) < 0)
@@ -1312,7 +1309,7 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci,
snd_atiixp_chip_start(chip);
sprintf(card->longname, "%s rev %x at 0x%lx, irq %i",
- card->shortname, revision, chip->addr, chip->irq);
+ card->shortname, pci->revision, chip->addr, chip->irq);
if ((err = snd_card_register(card)) < 0)
goto __error;
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 238154bb7a25..5ec1b6fcd548 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -341,11 +341,7 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
snd_card_free(card);
return err;
}
- if ((err = pci_read_config_byte(pci, PCI_REVISION_ID,
- &(chip->rev))) < 0) {
- snd_card_free(card);
- return err;
- }
+ chip->rev = pci->revision;
#ifdef CHIP_AU8830
if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
printk(KERN_ALERT
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index aaac6e5b4767..a0420bc63f0b 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -590,7 +590,6 @@ struct snd_ca0106 {
struct resource *res_port;
int irq;
- unsigned char revision; /* chip revision */
unsigned int serial; /* serial number */
unsigned short model; /* subsystem id */
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 48f3f17c5170..fcab8fb97e38 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -168,6 +168,25 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
#include "ca0106.h"
static struct snd_ca0106_details ca0106_chip_details[] = {
+ /* Sound Blaster X-Fi Extreme Audio. This does not have an AC97. 53SB079000000 */
+ /* It is really just a normal SB Live 24bit. */
+ /*
+ * CTRL:CA0111-WTLF
+ * ADC: WM8775SEDS
+ * DAC: CS4382-KQZ
+ */
+ /* Tested:
+ * Playback on front, rear, center/lfe speakers
+ * Capture from Mic in.
+ * Not-Tested:
+ * Capture from Line in.
+ * Playback to digital out.
+ */
+ { .serial = 0x10121102,
+ .name = "X-Fi Extreme Audio [SB0790]",
+ .gpio_type = 1,
+ .i2c_adc = 1 } ,
+ /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */
/* AudigyLS[SB0310] */
{ .serial = 0x10021102,
.name = "AudigyLS [SB0310]",
@@ -1293,13 +1312,12 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card,
}
pci_set_master(pci);
- /* read revision & serial */
- pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
+ /* read serial */
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
#if 1
printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", chip->model,
- chip->revision, chip->serial);
+ pci->revision, chip->serial);
#endif
strcpy(card->driver, "CA0106");
strcpy(card->shortname, "CA0106");
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index bef1f6d1859c..71d7aab9d869 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -2897,6 +2897,10 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
}
#endif
+#ifdef CONFIG_PM
+ kfree(chip->saved_regs);
+#endif
+
pci_disable_device(chip->pci);
kfree(chip);
return 0;
@@ -3140,6 +3144,23 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip)
/*
* start and load DSP
*/
+
+static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip)
+{
+ unsigned int tmp;
+
+ snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
+
+ tmp = snd_cs46xx_peek(chip, BA1_PFIE);
+ tmp &= ~0x0000f03f;
+ snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */
+
+ tmp = snd_cs46xx_peek(chip, BA1_CIE);
+ tmp &= ~0x0000003f;
+ tmp |= 0x00000001;
+ snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */
+}
+
int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
{
unsigned int tmp;
@@ -3214,19 +3235,7 @@ int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip)
snd_cs46xx_proc_start(chip);
- /*
- * Enable interrupts on the part.
- */
- snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
-
- tmp = snd_cs46xx_peek(chip, BA1_PFIE);
- tmp &= ~0x0000f03f;
- snd_cs46xx_poke(chip, BA1_PFIE, tmp); /* playback interrupt enable */
-
- tmp = snd_cs46xx_peek(chip, BA1_CIE);
- tmp &= ~0x0000003f;
- tmp |= 0x00000001;
- snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */
+ cs46xx_enable_stream_irqs(chip);
#ifndef CONFIG_SND_CS46XX_NEW_DSP
/* set the attenuation to 0dB */
@@ -3665,11 +3674,19 @@ static struct cs_card_type __devinitdata cards[] = {
* APM support
*/
#ifdef CONFIG_PM
+static unsigned int saved_regs[] = {
+ BA0_ACOSV,
+ BA0_ASER_FADDR,
+ BA0_ASER_MASTER,
+ BA1_PVOL,
+ BA1_CVOL,
+};
+
int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
{
struct snd_card *card = pci_get_drvdata(pci);
struct snd_cs46xx *chip = card->private_data;
- int amp_saved;
+ int i, amp_saved;
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
chip->in_suspend = 1;
@@ -3680,6 +3697,10 @@ int snd_cs46xx_suspend(struct pci_dev *pci, pm_message_t state)
snd_ac97_suspend(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
snd_ac97_suspend(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
+ /* save some registers */
+ for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+ chip->saved_regs[i] = snd_cs46xx_peekBA0(chip, saved_regs[i]);
+
amp_saved = chip->amplifier;
/* turn off amp */
chip->amplifier_ctrl(chip, -chip->amplifier);
@@ -3698,7 +3719,7 @@ int snd_cs46xx_resume(struct pci_dev *pci)
{
struct snd_card *card = pci_get_drvdata(pci);
struct snd_cs46xx *chip = card->private_data;
- int amp_saved;
+ int i, amp_saved;
pci_set_power_state(pci, PCI_D0);
pci_restore_state(pci);
@@ -3716,6 +3737,16 @@ int snd_cs46xx_resume(struct pci_dev *pci)
snd_cs46xx_chip_init(chip);
+ snd_cs46xx_reset(chip);
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+ cs46xx_dsp_resume(chip);
+ /* restore some registers */
+ for (i = 0; i < ARRAY_SIZE(saved_regs); i++)
+ snd_cs46xx_pokeBA0(chip, saved_regs[i], chip->saved_regs[i]);
+#else
+ snd_cs46xx_download_image(chip);
+#endif
+
#if 0
snd_cs46xx_codec_write(chip, BA0_AC97_GENERAL_PURPOSE,
chip->ac97_general_purpose);
@@ -3730,6 +3761,13 @@ int snd_cs46xx_resume(struct pci_dev *pci)
snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]);
snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]);
+ /* reset playback/capture */
+ snd_cs46xx_set_play_sample_rate(chip, 8000);
+ snd_cs46xx_set_capture_sample_rate(chip, 8000);
+ snd_cs46xx_proc_start(chip);
+
+ cs46xx_enable_stream_irqs(chip);
+
if (amp_saved)
chip->amplifier_ctrl(chip, 1); /* turn amp on */
else
@@ -3896,6 +3934,15 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
snd_cs46xx_proc_init(card, chip);
+#ifdef CONFIG_PM
+ chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
+ ARRAY_SIZE(saved_regs), GFP_KERNEL);
+ if (!chip->saved_regs) {
+ snd_cs46xx_free(chip);
+ return -ENOMEM;
+ }
+#endif
+
chip->active_ctrl(chip, -1); /* disable CLKRUN */
snd_card_set_dev(card, &pci->dev);
diff --git a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
index f75750c2bd24..20dcd72f06c1 100644
--- a/sound/pci/cs46xx/cs46xx_lib.h
+++ b/sound/pci/cs46xx/cs46xx_lib.h
@@ -86,6 +86,9 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned
struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip);
+#endif
struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
int symbol_type);
#ifdef CONFIG_PROC_FS
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
index 336e77e2600c..590b35d91df2 100644
--- a/sound/pci/cs46xx/dsp_spos.c
+++ b/sound/pci/cs46xx/dsp_spos.c
@@ -306,13 +306,59 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
mutex_unlock(&chip->spos_mutex);
}
+static int dsp_load_parameter(struct snd_cs46xx *chip,
+ struct dsp_segment_desc *parameter)
+{
+ u32 doffset, dsize;
+
+ if (!parameter) {
+ snd_printdd("dsp_spos: module got no parameter segment\n");
+ return 0;
+ }
+
+ doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
+ dsize = parameter->size * 4;
+
+ snd_printdd("dsp_spos: "
+ "downloading parameter data to chip (%08x-%08x)\n",
+ doffset,doffset + dsize);
+ if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
+ snd_printk(KERN_ERR "dsp_spos: "
+ "failed to download parameter data to DSP\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dsp_load_sample(struct snd_cs46xx *chip,
+ struct dsp_segment_desc *sample)
+{
+ u32 doffset, dsize;
+
+ if (!sample) {
+ snd_printdd("dsp_spos: module got no sample segment\n");
+ return 0;
+ }
+
+ doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET);
+ dsize = sample->size * 4;
+
+ snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
+ doffset,doffset + dsize);
+
+ if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
+ snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module)
{
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
struct dsp_segment_desc * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
- struct dsp_segment_desc * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER);
- struct dsp_segment_desc * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE);
u32 doffset, dsize;
+ int err;
if (ins->nmodules == DSP_MAX_MODULES - 1) {
snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
@@ -326,49 +372,20 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m
snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
}
- if (parameter == NULL) {
- snd_printdd("dsp_spos: module got no parameter segment\n");
- } else {
- if (ins->nmodules > 0) {
- snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n");
- }
-
- doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
- dsize = parameter->size * 4;
-
- snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
- doffset,doffset + dsize);
-
- if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
- snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n");
- return -EINVAL;
- }
- }
+ err = dsp_load_parameter(chip, get_segment_desc(module,
+ SEGTYPE_SP_PARAMETER));
+ if (err < 0)
+ return err;
if (ins->nmodules == 0) {
snd_printdd("dsp_spos: clearing sample area\n");
snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
}
- if (sample == NULL) {
- snd_printdd("dsp_spos: module got no sample segment\n");
- } else {
- if (ins->nmodules > 0) {
- snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n");
- }
-
- doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET);
- dsize = sample->size * 4;
-
- snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
- doffset,doffset + dsize);
-
- if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
- snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
- return -EINVAL;
- }
- }
-
+ err = dsp_load_sample(chip, get_segment_desc(module,
+ SEGTYPE_SP_SAMPLE));
+ if (err < 0)
+ return err;
if (ins->nmodules == 0) {
snd_printdd("dsp_spos: clearing code area\n");
@@ -986,7 +1003,10 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
return NULL;
}
- strcpy(ins->tasks[ins->ntask].task_name,name);
+ if (name)
+ strcpy(ins->tasks[ins->ntask].task_name, name);
+ else
+ strcpy(ins->tasks[ins->ntask].task_name, "(NULL)");
ins->tasks[ins->ntask].address = dest;
ins->tasks[ins->ntask].size = size;
@@ -995,7 +1015,8 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size)
desc = (ins->tasks + ins->ntask);
ins->ntask++;
- add_symbol (chip,name,dest,SYMBOL_PARAMETER);
+ if (name)
+ add_symbol (chip,name,dest,SYMBOL_PARAMETER);
return desc;
}
@@ -1006,6 +1027,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
desc = _map_scb (chip,name,dest);
if (desc) {
+ desc->data = scb_data;
_dsp_create_scb(chip,scb_data,dest);
} else {
snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
@@ -1023,6 +1045,7 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da
desc = _map_task_tree (chip,name,dest,size);
if (desc) {
+ desc->data = task_data;
_dsp_create_task_tree(chip,task_data,dest,size);
} else {
snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
@@ -1320,8 +1343,10 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip)
0x0000ffff
};
- /* dirty hack ... */
- _dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2);
+ if (!cs46xx_dsp_create_task_tree(chip, NULL,
+ (u32 *)&mix2_ostream_spb,
+ WRITE_BACK_SPB, 2))
+ goto _fail_end;
}
/* input sample converter */
@@ -1622,7 +1647,6 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip,
return 0;
}
-
static void cs46xx_dsp_disable_spdif_hw (struct snd_cs46xx *chip)
{
struct dsp_spos_instance * ins = chip->dsp_spos_instance;
@@ -1894,3 +1918,61 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
return 0;
}
+
+#ifdef CONFIG_PM
+int cs46xx_dsp_resume(struct snd_cs46xx * chip)
+{
+ struct dsp_spos_instance * ins = chip->dsp_spos_instance;
+ int i, err;
+
+ /* clear parameter, sample and code areas */
+ snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET,
+ DSP_PARAMETER_BYTE_SIZE);
+ snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET,
+ DSP_SAMPLE_BYTE_SIZE);
+ snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
+
+ for (i = 0; i < ins->nmodules; i++) {
+ struct dsp_module_desc *module = &ins->modules[i];
+ struct dsp_segment_desc *seg;
+ u32 doffset, dsize;
+
+ seg = get_segment_desc(module, SEGTYPE_SP_PARAMETER);
+ err = dsp_load_parameter(chip, seg);
+ if (err < 0)
+ return err;
+
+ seg = get_segment_desc(module, SEGTYPE_SP_SAMPLE);
+ err = dsp_load_sample(chip, seg);
+ if (err < 0)
+ return err;
+
+ seg = get_segment_desc(module, SEGTYPE_SP_PROGRAM);
+ if (!seg)
+ continue;
+
+ doffset = seg->offset * 4 + module->load_address * 4
+ + DSP_CODE_BYTE_OFFSET;
+ dsize = seg->size * 4;
+ err = snd_cs46xx_download(chip,
+ ins->code.data + module->load_address,
+ doffset, dsize);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < ins->ntask; i++) {
+ struct dsp_task_descriptor *t = &ins->tasks[i];
+ _dsp_create_task_tree(chip, t->data, t->address, t->size);
+ }
+
+ for (i = 0; i < ins->nscb; i++) {
+ struct dsp_scb_descriptor *s = &ins->scbs[i];
+ if (s->deleted)
+ continue;
+ _dsp_create_scb(chip, s->data, s->address);
+ }
+
+ return 0;
+}
+#endif
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c
new file mode 100644
index 000000000000..240a0a462209
--- /dev/null
+++ b/sound/pci/cs5530.c
@@ -0,0 +1,306 @@
+/*
+ * cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
+ *
+ * (C) Copyright 2007 Ash Willis <ashwillis@programmer.net>
+ * (C) Copyright 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
+ * mess with it a bit. The chip seems to have to have trouble with full duplex
+ * mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
+ * simultaneously play back audio at 16bit 44100kHz, the device actually plays
+ * back in the same format in which it is capturing. By forcing the chip to
+ * always play/capture in 16/44100, we can let alsa-lib convert the samples and
+ * that way we can hack up some full duplex audio.
+ *
+ * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
+ * The older version (VSA1) provides fairly good soundblaster emulation
+ * although there are a couple of bugs: large DMA buffers break record,
+ * and the MPU event handling seems suspect. VSA2 allows the native driver
+ * to control the AC97 audio engine directly and requires a different driver.
+ *
+ * Thanks to National Semiconductor for providing the needed information
+ * on the XpressAudio(tm) internals.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * TO DO:
+ * Investigate whether we can portably support Cognac (5520) in the
+ * same manner.
+ */
+
+#include <sound/driver.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <sound/core.h>
+#include <sound/sb.h>
+#include <sound/initval.h>
+
+MODULE_AUTHOR("Ash Willis");
+MODULE_DESCRIPTION("CS5530 Audio");
+MODULE_LICENSE("GPL");
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+struct snd_cs5530 {
+ struct snd_card *card;
+ struct pci_dev *pci;
+ struct snd_sb *sb;
+ unsigned long pci_base;
+};
+
+static struct pci_device_id snd_cs5530_ids[] = {
+ {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
+ PCI_ANY_ID, 0, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
+
+static int snd_cs5530_free(struct snd_cs5530 *chip)
+{
+ pci_release_regions(chip->pci);
+ pci_disable_device(chip->pci);
+ kfree(chip);
+ return 0;
+}
+
+static int snd_cs5530_dev_free(struct snd_device *device)
+{
+ struct snd_cs5530 *chip = device->device_data;
+ return snd_cs5530_free(chip);
+}
+
+static void __devexit snd_cs5530_remove(struct pci_dev *pci)
+{
+ snd_card_free(pci_get_drvdata(pci));
+ pci_set_drvdata(pci, NULL);
+}
+
+static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg)
+{
+ outb(reg, io + 4);
+ udelay(20);
+ reg = inb(io + 5);
+ udelay(20);
+ return reg;
+}
+
+static int __devinit snd_cs5530_create(struct snd_card *card,
+ struct pci_dev *pci,
+ struct snd_cs5530 **rchip)
+{
+ struct snd_cs5530 *chip;
+ unsigned long sb_base;
+ u8 irq, dma8, dma16 = 0;
+ u16 map;
+ void __iomem *mem;
+ int err;
+
+ static struct snd_device_ops ops = {
+ .dev_free = snd_cs5530_dev_free,
+ };
+ *rchip = NULL;
+
+ err = pci_enable_device(pci);
+ if (err < 0)
+ return err;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL) {
+ pci_disable_device(pci);
+ return -ENOMEM;
+ }
+
+ chip->card = card;
+ chip->pci = pci;
+
+ err = pci_request_regions(pci, "CS5530");
+ if (err < 0) {
+ kfree(chip);
+ pci_disable_device(pci);
+ return err;
+ }
+ chip->pci_base = pci_resource_start(pci, 0);
+
+ mem = ioremap_nocache(chip->pci_base, pci_resource_len(pci, 0));
+ if (mem == NULL) {
+ kfree(chip);
+ pci_disable_device(pci);
+ return -EBUSY;
+ }
+
+ map = readw(mem + 0x18);
+ iounmap(mem);
+
+ /* Map bits
+ 0:1 * 0x20 + 0x200 = sb base
+ 2 sb enable
+ 3 adlib enable
+ 5 MPU enable 0x330
+ 6 MPU enable 0x300
+
+ The other bits may be used internally so must be masked */
+
+ sb_base = 0x220 + 0x20 * (map & 3);
+
+ if (map & (1<<2))
+ printk(KERN_INFO "CS5530: XpressAudio at 0x%lx\n", sb_base);
+ else {
+ printk(KERN_ERR "Could not find XpressAudio!\n");
+ snd_cs5530_free(chip);
+ return -ENODEV;
+ }
+
+ if (map & (1<<5))
+ printk(KERN_INFO "CS5530: MPU at 0x300\n");
+ else if (map & (1<<6))
+ printk(KERN_INFO "CS5530: MPU at 0x330\n");
+
+ irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
+ dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
+
+ if (dma8 & 0x20)
+ dma16 = 5;
+ else if (dma8 & 0x40)
+ dma16 = 6;
+ else if (dma8 & 0x80)
+ dma16 = 7;
+ else {
+ printk(KERN_ERR "CS5530: No 16bit DMA enabled\n");
+ snd_cs5530_free(chip);
+ return -ENODEV;
+ }
+
+ if (dma8 & 0x01)
+ dma8 = 0;
+ else if (dma8 & 02)
+ dma8 = 1;
+ else if (dma8 & 0x08)
+ dma8 = 3;
+ else {
+ printk(KERN_ERR "CS5530: No 8bit DMA enabled\n");
+ snd_cs5530_free(chip);
+ return -ENODEV;
+ }
+
+ if (irq & 1)
+ irq = 9;
+ else if (irq & 2)
+ irq = 5;
+ else if (irq & 4)
+ irq = 7;
+ else if (irq & 8)
+ irq = 10;
+ else {
+ printk(KERN_ERR "CS5530: SoundBlaster IRQ not set\n");
+ snd_cs5530_free(chip);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "CS5530: IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8,
+ dma16);
+
+ err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
+ dma16, SB_HW_CS5530, &chip->sb);
+ if (err < 0) {
+ printk(KERN_ERR "CS5530: Could not create SoundBlaster\n");
+ snd_cs5530_free(chip);
+ return err;
+ }
+
+ err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm);
+ if (err < 0) {
+ printk(KERN_ERR "CS5530: Could not create PCM\n");
+ snd_cs5530_free(chip);
+ return err;
+ }
+
+ err = snd_sbmixer_new(chip->sb);
+ if (err < 0) {
+ printk(KERN_ERR "CS5530: Could not create Mixer\n");
+ snd_cs5530_free(chip);
+ return err;
+ }
+
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0) {
+ snd_cs5530_free(chip);
+ return err;
+ }
+
+ snd_card_set_dev(card, &pci->dev);
+ *rchip = chip;
+ return 0;
+}
+
+static int __devinit snd_cs5530_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ static int dev;
+ struct snd_card *card;
+ struct snd_cs5530 *chip = NULL;
+ int err;
+
+ if (dev >= SNDRV_CARDS)
+ return -ENODEV;
+ if (!enable[dev]) {
+ dev++;
+ return -ENOENT;
+ }
+
+ card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
+
+ if (card == NULL)
+ return -ENOMEM;
+
+ err = snd_cs5530_create(card, pci, &chip);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+
+ strcpy(card->driver, "CS5530");
+ strcpy(card->shortname, "CS5530 Audio");
+ sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_card_free(card);
+ return err;
+ }
+ pci_set_drvdata(pci, card);
+ dev++;
+ return 0;
+}
+
+static struct pci_driver driver = {
+ .name = "CS5530_Audio",
+ .id_table = snd_cs5530_ids,
+ .probe = snd_cs5530_probe,
+ .remove = __devexit_p(snd_cs5530_remove),
+};
+
+static int __init alsa_card_cs5530_init(void)
+{
+ return pci_register_driver(&driver);
+}
+
+static void __exit alsa_card_cs5530_exit(void)
+{
+ pci_unregister_driver(&driver);
+}
+
+module_init(alsa_card_cs5530_init)
+module_exit(alsa_card_cs5530_exit)
+
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index dbc805c33fc4..404ae1be0a4b 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -51,9 +51,15 @@
#define HANA_FILENAME "emu/hana.fw"
#define DOCK_FILENAME "emu/audio_dock.fw"
+#define EMU1010B_FILENAME "emu/emu1010b.fw"
+#define MICRO_DOCK_FILENAME "emu/micro_dock.fw"
+#define EMU1010_NOTEBOOK_FILENAME "emu/emu1010_notebook.fw"
MODULE_FIRMWARE(HANA_FILENAME);
MODULE_FIRMWARE(DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010B_FILENAME);
+MODULE_FIRMWARE(MICRO_DOCK_FILENAME);
+MODULE_FIRMWARE(EMU1010_NOTEBOOK_FILENAME);
/*************************************************************************
@@ -660,10 +666,12 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
return err;
}
snd_printk(KERN_INFO "firmware size=0x%zx\n", fw_entry->size);
+#if 0
if (fw_entry->size != 0x133a4) {
snd_printk(KERN_ERR "firmware: %s wrong size.\n",filename);
return -EINVAL;
}
+#endif
/* The FPGA is a Xilinx Spartan IIE XC2S50E */
/* GPIO7 -> FPGA PGMN
@@ -694,6 +702,37 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 * emu, const char * file
return 0;
}
+/*
+ * EMU-1010 - details found out from this driver, official MS Win drivers,
+ * testing the card:
+ *
+ * Audigy2 (aka Alice2):
+ * ---------------------
+ * * communication over PCI
+ * * conversion of 32-bit data coming over EMU32 links from HANA FPGA
+ * to 2 x 16-bit, using internal DSP instructions
+ * * slave mode, clock supplied by HANA
+ * * linked to HANA using:
+ * 32 x 32-bit serial EMU32 output channels
+ * 16 x EMU32 input channels
+ * (?) x I2S I/O channels (?)
+ *
+ * FPGA (aka HANA):
+ * ---------------
+ * * provides all (?) physical inputs and outputs of the card
+ * (ADC, DAC, SPDIF I/O, ADAT I/O, etc.)
+ * * provides clock signal for the card and Alice2
+ * * two crystals - for 44.1kHz and 48kHz multiples
+ * * provides internal routing of signal sources to signal destinations
+ * * inputs/outputs to Alice2 - see above
+ *
+ * Current status of the driver:
+ * ----------------------------
+ * * only 44.1/48kHz supported (the MS Win driver supports up to 192 kHz)
+ * * PCM device nb. 2:
+ * 16 x 16-bit playback - snd_emu10k1_fx8010_playback_ops
+ * 16 x 32-bit capture - snd_emu10k1_capture_efx_ops
+ */
static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
{
unsigned int i;
@@ -727,7 +766,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
/* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
snd_printdd("reg1=0x%x\n",reg);
- if (reg == 0x55) {
+ if ((reg & 0x3f) == 0x15) {
/* FPGA netlist already present so clear it */
/* Return to programming mode */
@@ -735,19 +774,32 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
}
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
snd_printdd("reg2=0x%x\n",reg);
- if (reg == 0x55) {
+ if ((reg & 0x3f) == 0x15) {
/* FPGA failed to return to programming mode */
+ snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n");
return -ENODEV;
}
snd_printk(KERN_INFO "emu1010: EMU_HANA_ID=0x%x\n",reg);
- if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
- snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
- return err;
+ if (emu->card_capabilities->emu1010 == 1) {
+ if ((err = snd_emu1010_load_firmware(emu, HANA_FILENAME)) != 0) {
+ snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file %s failed\n", HANA_FILENAME);
+ return err;
+ }
+ } else if (emu->card_capabilities->emu1010 == 2) {
+ if ((err = snd_emu1010_load_firmware(emu, EMU1010B_FILENAME)) != 0) {
+ snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010B_FILENAME);
+ return err;
+ }
+ } else if (emu->card_capabilities->emu1010 == 3) {
+ if ((err = snd_emu1010_load_firmware(emu, EMU1010_NOTEBOOK_FILENAME)) != 0) {
+ snd_printk(KERN_INFO "emu1010: Loading Firmware file %s failed\n", EMU1010_NOTEBOOK_FILENAME);
+ return err;
+ }
}
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
- if (reg != 0x55) {
+ if ((reg & 0x3f) != 0x15) {
/* FPGA failed to be programmed */
snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg=0x%x\n", reg);
return -ENODEV;
@@ -850,6 +902,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
EMU_DST_ALICE2_EMU32_6, EMU_SRC_DOCK_ADC2_LEFT1);
snd_emu1010_fpga_link_dst_src_write(emu,
EMU_DST_ALICE2_EMU32_7, EMU_SRC_DOCK_ADC2_RIGHT1);
+ /* Pavel Hofman - setting defaults for 8 more capture channels
+ * Defaults only, users will set their own values anyways, let's
+ * just copy/paste.
+ */
+
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_8, EMU_SRC_DOCK_MIC_A1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_9, EMU_SRC_DOCK_MIC_B1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_A, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_B, EMU_SRC_HAMOA_ADC_LEFT2);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_C, EMU_SRC_DOCK_ADC1_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_D, EMU_SRC_DOCK_ADC1_RIGHT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_E, EMU_SRC_DOCK_ADC2_LEFT1);
+ snd_emu1010_fpga_link_dst_src_write(emu,
+ EMU_DST_ALICE2_EMU32_F, EMU_SRC_DOCK_ADC2_RIGHT1);
#endif
#if 0
/* Original */
@@ -943,16 +1016,27 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 * emu)
/* Return to Audio Dock programming mode */
snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n");
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK );
- if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
- return err;
+ if (emu->card_capabilities->emu1010 == 1) {
+ if ((err = snd_emu1010_load_firmware(emu, DOCK_FILENAME)) != 0) {
+ return err;
+ }
+ } else if (emu->card_capabilities->emu1010 == 2) {
+ if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+ return err;
+ }
+ } else if (emu->card_capabilities->emu1010 == 3) {
+ if ((err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME)) != 0) {
+ return err;
+ }
}
+
snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0 );
snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &reg );
snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS=0x%x\n",reg);
/* ID, should read & 0x7f = 0x55 when FPGA programmed. */
snd_emu1010_fpga_read(emu, EMU_HANA_ID, &reg );
snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID=0x%x\n",reg);
- if (reg != 0x55) {
+ if ((reg & 0x3f) != 0x15) {
/* FPGA failed to be programmed */
snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg=0x%x\n", reg);
return 0;
@@ -1227,9 +1311,15 @@ static struct snd_emu_chip_details emu_chip_details[] = {
.emu10k2_chip = 1,
.ca0108_chip = 1,
.ca_cardbus_chip = 1,
- .spi_dac = 1,
- .i2c_adc = 1,
- .spk71 = 1} ,
+ .spk71 = 1 ,
+ .emu1010 = 3} ,
+ {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x40041102,
+ .driver = "Audigy2", .name = "E-mu 1010b PCI [MAEM????]",
+ .id = "EMU1010",
+ .emu10k2_chip = 1,
+ .ca0108_chip = 1,
+ .spk71 = 1 ,
+ .emu1010 = 2} ,
{.vendor = 0x1102, .device = 0x0008,
.driver = "Audigy2", .name = "Audigy 2 Value [Unknown]",
.id = "Audigy2",
@@ -1511,7 +1601,6 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
struct snd_emu10k1 *emu;
int idx, err;
int is_audigy;
- unsigned char revision;
unsigned int silent_page;
const struct snd_emu_chip_details *c;
static struct snd_device_ops ops = {
@@ -1543,8 +1632,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
emu->synth = NULL;
emu->get_synth_voice = NULL;
/* read revision & serial */
- pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
- emu->revision = revision;
+ emu->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model);
snd_printdd("vendor=0x%x, device=0x%x, subsystem_vendor_id=0x%x, subsystem_id=0x%x\n",pci->vendor, pci->device, emu->serial, emu->model);
@@ -1665,12 +1753,13 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
emu->fx8010.extout_mask = extout_mask;
emu->enable_ir = enable_ir;
+ if (emu->card_capabilities->ca_cardbus_chip) {
+ if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
+ goto error;
+ }
if (emu->card_capabilities->ecard) {
if ((err = snd_emu10k1_ecard_init(emu)) < 0)
goto error;
- } else if (emu->card_capabilities->ca_cardbus_chip) {
- if ((err = snd_emu10k1_cardbus_init(emu)) < 0)
- goto error;
} else if (emu->card_capabilities->emu1010) {
if ((err = snd_emu10k1_emu1010_init(emu)) < 0) {
snd_emu10k1_free(emu);
@@ -1816,10 +1905,10 @@ void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu)
void snd_emu10k1_resume_init(struct snd_emu10k1 *emu)
{
+ if (emu->card_capabilities->ca_cardbus_chip)
+ snd_emu10k1_cardbus_init(emu);
if (emu->card_capabilities->ecard)
snd_emu10k1_ecard_init(emu);
- else if (emu->card_capabilities->ca_cardbus_chip)
- snd_emu10k1_cardbus_init(emu);
else if (emu->card_capabilities->emu1010)
snd_emu10k1_emu1010_init(emu);
else
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index bb0fec7f7e1b..e4af7a9b808c 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -942,7 +942,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card,
pci_set_master(pci);
/* read revision & serial */
- pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
+ chip->revision = pci->revision;
pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial);
pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model);
snd_printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model,
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index c02012cccd8e..7206c0fa06f2 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -1123,6 +1123,11 @@ snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl
ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;
}
+/*
+ * Used for emu1010 - conversion from 32-bit capture inputs from HANA
+ * to 2 x 16-bit registers in audigy - their values are read via DMA.
+ * Conversion is performed by Audigy DSP instructions of FX8010.
+ */
static int snd_emu10k1_audigy_dsp_convert_32_to_2x16(
struct snd_emu10k1_fx8010_code *icode,
u32 *ptr, int tmp, int bit_shifter16,
@@ -1193,7 +1198,11 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
#if 1
- /* PCM front Playback Volume (independent from stereo mix) */
+ /* PCM front Playback Volume (independent from stereo mix)
+ * playback = 0 + ( gpr * FXBUS_PCM_LEFT_FRONT >> 31)
+ * where gpr contains attenuation from corresponding mixer control
+ * (snd_emu10k1_init_stereo_control)
+ */
A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100);
@@ -1549,7 +1558,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
if (emu->card_capabilities->emu1010) {
snd_printk("EMU inputs on\n");
- /* Capture 8 channels of S32_LE sound */
+ /* Capture 16 (originally 8) channels of S32_LE sound */
/* printk("emufx.c: gpr=0x%x, tmp=0x%x\n",gpr, tmp); */
/* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */
@@ -1560,6 +1569,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_P16VIN(0x0), A_FXBUS2(0) );
/* Right ADC in 1 of 2 */
gpr_map[gpr++] = 0x00000000;
+ /* Delaying by one sample: instead of copying the input
+ * value A_P16VIN to output A_FXBUS2 as in the first channel,
+ * we use an auxiliary register, delaying the value by one
+ * sample
+ */
snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(2) );
A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x1), A_C_00000000, A_C_00000000);
gpr_map[gpr++] = 0x00000000;
@@ -1583,6 +1597,66 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
gpr_map[gpr++] = 0x00000000;
snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, A_GPR(gpr - 1), A_FXBUS2(0xe) );
A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x7), A_C_00000000, A_C_00000000);
+ /* Pavel Hofman - we still have voices, A_FXBUS2s, and
+ * A_P16VINs available -
+ * let's add 8 more capture channels - total of 16
+ */
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x10));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x8),
+ A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x12));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0x9),
+ A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x14));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xa),
+ A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x16));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xb),
+ A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x18));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xc),
+ A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x1a));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xd),
+ A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x1c));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xe),
+ A_C_00000000, A_C_00000000);
+ gpr_map[gpr++] = 0x00000000;
+ snd_emu10k1_audigy_dsp_convert_32_to_2x16(icode, &ptr, tmp,
+ bit_shifter16,
+ A_GPR(gpr - 1),
+ A_FXBUS2(0x1e));
+ A_OP(icode, &ptr, iACC3, A_GPR(gpr - 1), A_P16VIN(0xf),
+ A_C_00000000, A_C_00000000);
#if 0
for (z = 4; z < 8; z++) {
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index 4db6e1ca1665..7b2c1dcc5337 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -77,6 +77,10 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
return 0;
}
+/*
+ * Items labels in enum mixer controls assigning source data to
+ * each destination
+ */
static char *emu1010_src_texts[] = {
"Silence",
"Dock Mic A",
@@ -133,6 +137,9 @@ static char *emu1010_src_texts[] = {
"DSP 31",
};
+/*
+ * List of data sources available for each destination
+ */
static unsigned int emu1010_src_regs[] = {
EMU_SRC_SILENCE,/* 0 */
EMU_SRC_DOCK_MIC_A1, /* 1 */
@@ -189,6 +196,10 @@ static unsigned int emu1010_src_regs[] = {
EMU_SRC_ALICE_EMU32B+0xf, /* 52 */
};
+/*
+ * Data destinations - physical EMU outputs.
+ * Each destination has an enum mixer control to choose a data source
+ */
static unsigned int emu1010_output_dst[] = {
EMU_DST_DOCK_DAC1_LEFT1, /* 0 */
EMU_DST_DOCK_DAC1_RIGHT1, /* 1 */
@@ -216,6 +227,11 @@ static unsigned int emu1010_output_dst[] = {
EMU_DST_HANA_ADAT+7, /* 23 */
};
+/*
+ * Data destinations - HANA outputs going to Alice2 (audigy) for
+ * capture (EMU32 + I2S links)
+ * Each destination has an enum mixer control to choose a data source
+ */
static unsigned int emu1010_input_dst[] = {
EMU_DST_ALICE2_EMU32_0,
EMU_DST_ALICE2_EMU32_1,
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c
index ab4f5df5241b..eda5cb373ded 100644
--- a/sound/pci/emu10k1/emupcm.c
+++ b/sound/pci/emu10k1/emupcm.c
@@ -1233,24 +1233,26 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
runtime->hw.rate_min = runtime->hw.rate_max = 48000;
spin_lock_irq(&emu->reg_lock);
if (emu->card_capabilities->emu1010) {
- /* TODO
+ /* Nb. of channels has been increased to 16 */
+ /* TODO
* SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE
* SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
* SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
* SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000
* rate_min = 44100,
* rate_max = 192000,
- * channels_min = 8,
- * channels_max = 8,
+ * channels_min = 16,
+ * channels_max = 16,
* Need to add mixer control to fix sample rate
*
- * There are 16 mono channels of 16bits each.
+ * There are 32 mono channels of 16bits each.
* 24bit Audio uses 2x channels over 16bit
* 96kHz uses 2x channels over 48kHz
* 192kHz uses 4x channels over 48kHz
- * So, for 48kHz 24bit, one has 8 channels
- * for 96kHz 24bit, one has 4 channels
- * for 192kHz 24bit, one has 2 channels
+ * So, for 48kHz 24bit, one has 16 channels
+ * for 96kHz 24bit, one has 8 channels
+ * for 192kHz 24bit, one has 4 channels
+ *
*/
#if 1
switch (emu->emu1010.internal_clock) {
@@ -1258,13 +1260,15 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
/* For 44.1kHz */
runtime->hw.rates = SNDRV_PCM_RATE_44100;
runtime->hw.rate_min = runtime->hw.rate_max = 44100;
- runtime->hw.channels_min = runtime->hw.channels_max = 8;
+ runtime->hw.channels_min =
+ runtime->hw.channels_max = 16;
break;
case 1:
/* For 48kHz */
runtime->hw.rates = SNDRV_PCM_RATE_48000;
runtime->hw.rate_min = runtime->hw.rate_max = 48000;
- runtime->hw.channels_min = runtime->hw.channels_max = 8;
+ runtime->hw.channels_min =
+ runtime->hw.channels_max = 16;
break;
};
#endif
@@ -1282,7 +1286,7 @@ static int snd_emu10k1_capture_efx_open(struct snd_pcm_substream *substream)
#endif
runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE;
/* efx_voices_mask[0] is expected to be zero
- * efx_voices_mask[1] is expected to have 16bits set
+ * efx_voices_mask[1] is expected to have 32bits set
*/
} else {
runtime->hw.channels_min = runtime->hw.channels_max = 0;
@@ -1787,11 +1791,24 @@ int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct s
/* emu->efx_voices_mask[0] = FXWC_DEFAULTROUTE_C | FXWC_DEFAULTROUTE_A; */
if (emu->audigy) {
emu->efx_voices_mask[0] = 0;
- emu->efx_voices_mask[1] = 0xffff;
+ if (emu->card_capabilities->emu1010)
+ /* Pavel Hofman - 32 voices will be used for
+ * capture (write mode) -
+ * each bit = corresponding voice
+ */
+ emu->efx_voices_mask[1] = 0xffffffff;
+ else
+ emu->efx_voices_mask[1] = 0xffff;
} else {
emu->efx_voices_mask[0] = 0xffff0000;
emu->efx_voices_mask[1] = 0;
}
+ /* For emu1010, the control has to set 32 upper bits (voices)
+ * out of the 64 bits (voices) to true for the 16-channels capture
+ * to work correctly. Correct A_FXWC2 initial value (0xffffffff)
+ * is already defined but the snd_emu10k1_pcm_efx_voices_mask
+ * control can override this register's value.
+ */
kctl = snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu);
if (!kctl)
return -ENOMEM;
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index 6a0ddcf00884..21cb4268a59b 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -1607,8 +1607,8 @@ struct es1371_quirk {
unsigned char rev; /* revision */
};
-static int __devinit es1371_quirk_lookup(struct ensoniq *ensoniq,
- struct es1371_quirk *list)
+static int es1371_quirk_lookup(struct ensoniq *ensoniq,
+ struct es1371_quirk *list)
{
while (list->vid != (unsigned short)PCI_ANY_ID) {
if (ensoniq->pci->vendor == list->vid &&
@@ -2110,7 +2110,6 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
struct ensoniq ** rensoniq)
{
struct ensoniq *ensoniq;
- unsigned char cmdb;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_ensoniq_dev_free,
@@ -2151,8 +2150,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card,
}
#endif
pci_set_master(pci);
- pci_read_config_byte(pci, PCI_REVISION_ID, &cmdb);
- ensoniq->rev = cmdb;
+ ensoniq->rev = pci->revision;
#ifdef CHIP1370
#if 0
ensoniq->ctrl = ES_1370_CDC_EN | ES_1370_SERR_DISABLE |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 6dc578bbeec9..11015178e207 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -1369,7 +1369,6 @@ static int __devinit snd_fm801_create(struct snd_card *card,
struct fm801 ** rchip)
{
struct fm801 *chip;
- unsigned char rev;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_fm801_dev_free,
@@ -1405,8 +1404,7 @@ static int __devinit snd_fm801_create(struct snd_card *card,
pci_set_master(pci);
}
- pci_read_config_byte(pci, PCI_REVISION_ID, &rev);
- if (rev >= 0xb1) /* FM801-AU */
+ if (pci->revision >= 0xb1) /* FM801-AU */
chip->multichannel = 1;
snd_fm801_chip_init(chip, 0);
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 2fa281cbef91..92bc8b3fa2a0 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -341,6 +341,9 @@ struct azx {
unsigned int single_cmd :1;
unsigned int polling_mode :1;
unsigned int msi :1;
+
+ /* for debugging */
+ unsigned int last_cmd; /* last issued command (to sync) */
};
/* driver types */
@@ -466,18 +469,10 @@ static void azx_free_cmd_io(struct azx *chip)
}
/* send a command */
-static int azx_corb_send_cmd(struct hda_codec *codec, hda_nid_t nid, int direct,
- unsigned int verb, unsigned int para)
+static int azx_corb_send_cmd(struct hda_codec *codec, u32 val)
{
struct azx *chip = codec->bus->private_data;
unsigned int wp;
- u32 val;
-
- val = (u32)(codec->addr & 0x0f) << 28;
- val |= (u32)direct << 27;
- val |= (u32)nid << 20;
- val |= verb << 8;
- val |= para;
/* add command to corb */
wp = azx_readb(chip, CORBWP);
@@ -538,12 +533,12 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
}
if (! chip->rirb.cmds)
return chip->rirb.res; /* the last value */
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
} while (time_after_eq(timeout, jiffies));
if (chip->msi) {
snd_printk(KERN_WARNING "hda_intel: No response from codec, "
- "disabling MSI...\n");
+ "disabling MSI: last cmd=0x%08x\n", chip->last_cmd);
free_irq(chip->irq, chip);
chip->irq = -1;
pci_disable_msi(chip->pci);
@@ -555,13 +550,15 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
if (!chip->polling_mode) {
snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, "
- "switching to polling mode...\n");
+ "switching to polling mode: last cmd=0x%08x\n",
+ chip->last_cmd);
chip->polling_mode = 1;
goto again;
}
snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, "
- "switching to single_cmd mode...\n");
+ "switching to single_cmd mode: last cmd=0x%08x\n",
+ chip->last_cmd);
chip->rirb.rp = azx_readb(chip, RIRBWP);
chip->rirb.cmds = 0;
/* switch to single_cmd mode */
@@ -581,20 +578,11 @@ static unsigned int azx_rirb_get_response(struct hda_codec *codec)
*/
/* send a command */
-static int azx_single_send_cmd(struct hda_codec *codec, hda_nid_t nid,
- int direct, unsigned int verb,
- unsigned int para)
+static int azx_single_send_cmd(struct hda_codec *codec, u32 val)
{
struct azx *chip = codec->bus->private_data;
- u32 val;
int timeout = 50;
- val = (u32)(codec->addr & 0x0f) << 28;
- val |= (u32)direct << 27;
- val |= (u32)nid << 20;
- val |= verb << 8;
- val |= para;
-
while (timeout--) {
/* check ICB busy bit */
if (! (azx_readw(chip, IRS) & ICH6_IRS_BUSY)) {
@@ -639,10 +627,19 @@ static int azx_send_cmd(struct hda_codec *codec, hda_nid_t nid,
unsigned int para)
{
struct azx *chip = codec->bus->private_data;
+ u32 val;
+
+ val = (u32)(codec->addr & 0x0f) << 28;
+ val |= (u32)direct << 27;
+ val |= (u32)nid << 20;
+ val |= verb << 8;
+ val |= para;
+ chip->last_cmd = val;
+
if (chip->single_cmd)
- return azx_single_send_cmd(codec, nid, direct, verb, para);
+ return azx_single_send_cmd(codec, val);
else
- return azx_corb_send_cmd(codec, nid, direct, verb, para);
+ return azx_corb_send_cmd(codec, val);
}
/* get a response */
@@ -1788,6 +1785,12 @@ static struct pci_device_id azx_ids[] = {
{ 0x10de, 0x044b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP65 */
{ 0x10de, 0x055c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
{ 0x10de, 0x055d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP67 */
+ { 0x10de, 0x07fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+ { 0x10de, 0x07fd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP73 */
+ { 0x10de, 0x0774, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+ { 0x10de, 0x0775, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+ { 0x10de, 0x0776, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
+ { 0x10de, 0x0777, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA MCP77 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c
index e313e685f161..ac15066fd300 100644
--- a/sound/pci/hda/hda_proc.c
+++ b/sound/pci/hda/hda_proc.c
@@ -250,6 +250,12 @@ static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffe
snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id);
snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id);
snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id);
+
+ if (codec->mfg)
+ snd_iprintf(buffer, "Modem Function Group: 0x%x\n", codec->mfg);
+ else
+ snd_iprintf(buffer, "No Modem Function Group found\n");
+
if (! codec->afg)
return;
snd_iprintf(buffer, "Default PCM:\n");
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 0e1a879663fa..4d7f8d11ad75 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -1,7 +1,8 @@
/*
- * HD audio interface patch for AD1981HD, AD1983, AD1986A, AD1988
+ * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
+ * AD1986A, AD1988
*
- * Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
+ * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
*
* This driver is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -61,7 +62,7 @@ struct ad198x_spec {
int num_channel_mode;
/* PCM information */
- struct hda_pcm pcm_rec[2]; /* used in alc_build_pcms() */
+ struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
struct mutex amp_mutex; /* PCM volume/mute control mutex */
unsigned int spdif_route;
@@ -2775,11 +2776,634 @@ static int patch_ad1988(struct hda_codec *codec)
/*
+ * AD1884 / AD1984
+ *
+ * port-B - front line/mic-in
+ * port-E - aux in/out
+ * port-F - aux in/out
+ * port-C - rear line/mic-in
+ * port-D - rear line/hp-out
+ * port-A - front line/hp-out
+ *
+ * AD1984 = AD1884 + two digital mic-ins
+ *
+ * FIXME:
+ * For simplicity, we share the single DAC for both HP and line-outs
+ * right now. The inidividual playbacks could be easily implemented,
+ * but no build-up framework is given, so far.
+ */
+
+static hda_nid_t ad1884_dac_nids[1] = {
+ 0x04,
+};
+
+static hda_nid_t ad1884_adc_nids[2] = {
+ 0x08, 0x09,
+};
+
+static hda_nid_t ad1884_capsrc_nids[2] = {
+ 0x0c, 0x0d,
+};
+
+#define AD1884_SPDIF_OUT 0x02
+
+static struct hda_input_mux ad1884_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Front Mic", 0x0 },
+ { "Mic", 0x1 },
+ { "CD", 0x2 },
+ { "Mix", 0x3 },
+ },
+};
+
+static struct snd_kcontrol_new ad1884_base_mixers[] = {
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+ /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
+ /*
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
+ */
+ HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
+ },
+ /* SPDIF controls */
+ HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+ /* identical with ad1983 */
+ .info = ad1983_spdif_route_info,
+ .get = ad1983_spdif_route_get,
+ .put = ad1983_spdif_route_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
+ HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
+ HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
+ HDA_INPUT),
+ { } /* end */
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1884_init_verbs[] = {
+ /* DACs; mute as default */
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* Port-A (HP) mixer */
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ /* Port-A pin */
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* HP selector - select DAC2 */
+ {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Port-D (Line-out) mixer */
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ /* Port-D pin */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Mono-out mixer */
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ /* Mono-out pin */
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Mono selector */
+ {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Port-B (front mic) pin */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Port-C (rear mic) pin */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Analog mixer; mute as default */
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ /* Analog Mix output amp */
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+ /* SPDIF output selector */
+ {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+ { } /* end */
+};
+
+static int patch_ad1884(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ mutex_init(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
+ spec->multiout.dac_nids = ad1884_dac_nids;
+ spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
+ spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
+ spec->adc_nids = ad1884_adc_nids;
+ spec->capsrc_nids = ad1884_capsrc_nids;
+ spec->input_mux = &ad1884_capture_source;
+ spec->num_mixers = 1;
+ spec->mixers[0] = ad1884_base_mixers;
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = ad1884_init_verbs;
+ spec->spdif_route = 0;
+
+ codec->patch_ops = ad198x_patch_ops;
+
+ return 0;
+}
+
+/*
+ * Lenovo Thinkpad T61/X61
+ */
+static struct hda_input_mux ad1984_thinkpad_capture_source = {
+ .num_items = 3,
+ .items = {
+ { "Mic", 0x0 },
+ { "Internal Mic", 0x1 },
+ { "Mix", 0x3 },
+ },
+};
+
+static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
+ HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+ /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
+ HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
+ },
+ { } /* end */
+};
+
+/* additional verbs */
+static struct hda_verb ad1984_thinkpad_init_verbs[] = {
+ /* Port-E (docking station mic) pin */
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* docking mic boost */
+ {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Analog mixer - docking mic; mute as default */
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ /* enable EAPD bit */
+ {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+ { } /* end */
+};
+
+/* Digial MIC ADC NID 0x05 + 0x06 */
+static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ unsigned int stream_tag,
+ unsigned int format,
+ struct snd_pcm_substream *substream)
+{
+ snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+ stream_tag, 0, format);
+ return 0;
+}
+
+static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
+ 0, 0, 0);
+ return 0;
+}
+
+static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
+ .substreams = 2,
+ .channels_min = 2,
+ .channels_max = 2,
+ .nid = 0x05,
+ .ops = {
+ .prepare = ad1984_pcm_dmic_prepare,
+ .cleanup = ad1984_pcm_dmic_cleanup
+ },
+};
+
+static int ad1984_build_pcms(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec = codec->spec;
+ struct hda_pcm *info;
+ int err;
+
+ err = ad198x_build_pcms(codec);
+ if (err < 0)
+ return err;
+
+ info = spec->pcm_rec + codec->num_pcms;
+ codec->num_pcms++;
+ info->name = "AD1984 Digital Mic";
+ info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
+ return 0;
+}
+
+/* models */
+enum {
+ AD1984_BASIC,
+ AD1984_THINKPAD,
+ AD1984_MODELS
+};
+
+static const char *ad1984_models[AD1984_MODELS] = {
+ [AD1984_BASIC] = "basic",
+ [AD1984_THINKPAD] = "thinkpad",
+};
+
+static struct snd_pci_quirk ad1984_cfg_tbl[] = {
+ /* Lenovo Thinkpad T61/X61 */
+ SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
+ {}
+};
+
+static int patch_ad1984(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec;
+ int board_config, err;
+
+ err = patch_ad1884(codec);
+ if (err < 0)
+ return err;
+ spec = codec->spec;
+ board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
+ ad1984_models, ad1984_cfg_tbl);
+ switch (board_config) {
+ case AD1984_BASIC:
+ /* additional digital mics */
+ spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
+ codec->patch_ops.build_pcms = ad1984_build_pcms;
+ break;
+ case AD1984_THINKPAD:
+ spec->multiout.dig_out_nid = 0;
+ spec->input_mux = &ad1984_thinkpad_capture_source;
+ spec->mixers[0] = ad1984_thinkpad_mixers;
+ spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
+ break;
+ }
+ return 0;
+}
+
+
+/*
+ * AD1882
+ *
+ * port-A - front hp-out
+ * port-B - front mic-in
+ * port-C - rear line-in, shared surr-out (3stack)
+ * port-D - rear line-out
+ * port-E - rear mic-in, shared clfe-out (3stack)
+ * port-F - rear surr-out (6stack)
+ * port-G - rear clfe-out (6stack)
+ */
+
+static hda_nid_t ad1882_dac_nids[3] = {
+ 0x04, 0x03, 0x05
+};
+
+static hda_nid_t ad1882_adc_nids[2] = {
+ 0x08, 0x09,
+};
+
+static hda_nid_t ad1882_capsrc_nids[2] = {
+ 0x0c, 0x0d,
+};
+
+#define AD1882_SPDIF_OUT 0x02
+
+/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
+static struct hda_input_mux ad1882_capture_source = {
+ .num_items = 5,
+ .items = {
+ { "Front Mic", 0x1 },
+ { "Mic", 0x4 },
+ { "Line", 0x2 },
+ { "CD", 0x3 },
+ { "Mix", 0x7 },
+ },
+};
+
+static struct snd_kcontrol_new ad1882_base_mixers[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
+ HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
+ HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = ad198x_mux_enum_info,
+ .get = ad198x_mux_enum_get,
+ .put = ad198x_mux_enum_put,
+ },
+ /* SPDIF controls */
+ HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
+ /* identical with ad1983 */
+ .info = ad1983_spdif_route_info,
+ .get = ad1983_spdif_route_get,
+ .put = ad1983_spdif_route_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = ad198x_ch_mode_info,
+ .get = ad198x_ch_mode_get,
+ .put = ad198x_ch_mode_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
+ HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
+ { } /* end */
+};
+
+static struct hda_verb ad1882_ch2_init[] = {
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ { } /* end */
+};
+
+static struct hda_verb ad1882_ch4_init[] = {
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ { } /* end */
+};
+
+static struct hda_verb ad1882_ch6_init[] = {
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ { } /* end */
+};
+
+static struct hda_channel_mode ad1882_modes[3] = {
+ { 2, ad1882_ch2_init },
+ { 4, ad1882_ch4_init },
+ { 6, ad1882_ch6_init },
+};
+
+/*
+ * initialization verbs
+ */
+static struct hda_verb ad1882_init_verbs[] = {
+ /* DACs; mute as default */
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ /* Port-A (HP) mixer */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ /* Port-A pin */
+ {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* HP selector - select DAC2 */
+ {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
+ /* Port-D (Line-out) mixer */
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ /* Port-D pin */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Mono-out mixer */
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ /* Mono-out pin */
+ {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Port-B (front mic) pin */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+ /* Port-C (line-in) pin */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+ /* Port-C mixer - mute as input */
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* Port-E (mic-in) pin */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
+ /* Port-E mixer - mute as input */
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ /* Port-F (surround) */
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Port-G (CLFE) */
+ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Analog mixer; mute as default */
+ /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
+ {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
+ /* Analog Mix output amp */
+ {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
+ /* SPDIF output selector */
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+ {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
+ { } /* end */
+};
+
+/* models */
+enum {
+ AD1882_3STACK,
+ AD1882_6STACK,
+ AD1882_MODELS
+};
+
+static const char *ad1882_models[AD1986A_MODELS] = {
+ [AD1882_3STACK] = "3stack",
+ [AD1882_6STACK] = "6stack",
+};
+
+
+static int patch_ad1882(struct hda_codec *codec)
+{
+ struct ad198x_spec *spec;
+ int board_config;
+
+ spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ mutex_init(&spec->amp_mutex);
+ codec->spec = spec;
+
+ spec->multiout.max_channels = 6;
+ spec->multiout.num_dacs = 3;
+ spec->multiout.dac_nids = ad1882_dac_nids;
+ spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
+ spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
+ spec->adc_nids = ad1882_adc_nids;
+ spec->capsrc_nids = ad1882_capsrc_nids;
+ spec->input_mux = &ad1882_capture_source;
+ spec->num_mixers = 1;
+ spec->mixers[0] = ad1882_base_mixers;
+ spec->num_init_verbs = 1;
+ spec->init_verbs[0] = ad1882_init_verbs;
+ spec->spdif_route = 0;
+
+ codec->patch_ops = ad198x_patch_ops;
+
+ /* override some parameters */
+ board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
+ ad1882_models, NULL);
+ switch (board_config) {
+ default:
+ case AD1882_3STACK:
+ spec->num_mixers = 2;
+ spec->mixers[1] = ad1882_3stack_mixers;
+ spec->channel_mode = ad1882_modes;
+ spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
+ spec->need_dac_fix = 1;
+ spec->multiout.max_channels = 2;
+ spec->multiout.num_dacs = 1;
+ break;
+ case AD1882_6STACK:
+ spec->num_mixers = 2;
+ spec->mixers[1] = ad1882_6stack_mixers;
+ break;
+ }
+ return 0;
+}
+
+
+/*
* patch entries
*/
struct hda_codec_preset snd_hda_preset_analog[] = {
+ { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
+ { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
{ .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
{ .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
+ { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
{ .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
{ .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
{ .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index f8eb4c90f801..72d3ab9751ac 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -172,6 +172,7 @@ static int patch_atihdmi(struct hda_codec *codec)
*/
struct hda_codec_preset snd_hda_preset_atihdmi[] = {
{ .id = 0x1002793c, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
+ { .id = 0x10027919, .name = "ATI RS600 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002791a, .name = "ATI RS690/780 HDMI", .patch = patch_atihdmi },
{ .id = 0x1002aa01, .name = "ATI R600 HDMI", .patch = patch_atihdmi },
{} /* terminator */
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index bef214bcdddf..4d8e8af5c819 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -801,7 +801,9 @@ static struct snd_pci_quirk cxt5045_cfg_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP),
SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP),
SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP),
+ SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP),
SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU),
+ SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP),
SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP),
{}
};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4776de93928b..9a47eec5a27b 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -94,10 +94,18 @@ enum {
ALC262_HP_BPC_D7000_WF,
ALC262_BENQ_ED8,
ALC262_SONY_ASSAMD,
+ ALC262_BENQ_T31,
ALC262_AUTO,
ALC262_MODEL_LAST /* last tag */
};
+/* ALC268 models */
+enum {
+ ALC268_3ST,
+ ALC268_AUTO,
+ ALC268_MODEL_LAST /* last tag */
+};
+
/* ALC861 models */
enum {
ALC861_3ST,
@@ -115,6 +123,7 @@ enum {
/* ALC861-VD models */
enum {
ALC660VD_3ST,
+ ALC660VD_3ST_DIG,
ALC861VD_3ST,
ALC861VD_3ST_DIG,
ALC861VD_6ST_DIG,
@@ -144,6 +153,7 @@ enum {
ALC882_TARGA,
ALC882_ASUS_A7J,
ALC885_MACPRO,
+ ALC885_IMAC24,
ALC882_AUTO,
ALC882_MODEL_LAST,
};
@@ -163,6 +173,8 @@ enum {
ALC883_LENOVO_101E_2ch,
ALC883_LENOVO_NB0763,
ALC888_LENOVO_MS7195_DIG,
+ ALC888_6ST_HP,
+ ALC888_3ST_HP,
ALC883_AUTO,
ALC883_MODEL_LAST,
};
@@ -713,6 +725,38 @@ static void alc_subsystem_id(struct hda_codec *codec,
}
/*
+ * Fix-up pin default configurations
+ */
+
+struct alc_pincfg {
+ hda_nid_t nid;
+ u32 val;
+};
+
+static void alc_fix_pincfg(struct hda_codec *codec,
+ const struct snd_pci_quirk *quirk,
+ const struct alc_pincfg **pinfix)
+{
+ const struct alc_pincfg *cfg;
+
+ quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+ if (!quirk)
+ return;
+
+ cfg = pinfix[quirk->value];
+ for (; cfg->nid; cfg++) {
+ int i;
+ u32 val = cfg->val;
+ for (i = 0; i < 4; i++) {
+ snd_hda_codec_write(codec, cfg->nid, 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i,
+ val & 0xff);
+ val >>= 8;
+ }
+ }
+}
+
+/*
* ALC880 3-stack model
*
* DAC: Front = 0x02 (0x0c), Surr = 0x05 (0x0f), CLFE = 0x04 (0x0e)
@@ -1878,31 +1922,53 @@ static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res)
* Pin assignment:
* Speaker-out: 0x14
* Mic-In: 0x18
- * Built-in Mic-In: 0x19 (?)
- * HP-Out: 0x1b
+ * Built-in Mic-In: 0x19
+ * Line-In: 0x1b
+ * HP-Out: 0x1a
* SPDIF-Out: 0x1e
*/
-/* seems analog CD is not working */
static struct hda_input_mux alc880_lg_lw_capture_source = {
- .num_items = 2,
+ .num_items = 3,
.items = {
{ "Mic", 0x0 },
{ "Internal Mic", 0x1 },
+ { "Line In", 0x2 },
},
};
+#define alc880_lg_lw_modes alc880_threestack_modes
+
static struct snd_kcontrol_new alc880_lg_lw_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0f, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Channel Mode",
+ .info = alc_ch_mode_info,
+ .get = alc_ch_mode_get,
+ .put = alc_ch_mode_put,
+ },
{ } /* end */
};
static struct hda_verb alc880_lg_lw_init_verbs[] = {
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+ {0x10, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */
+ {0x12, AC_VERB_SET_CONNECT_SEL, 0x03}, /* line/surround */
+
/* set capture source to mic-in */
{0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
@@ -1912,7 +1978,6 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = {
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* HP-out */
- {0x13, AC_VERB_SET_CONNECT_SEL, 0x00},
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
{0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
/* mic-in to input */
@@ -2856,11 +2921,11 @@ static struct alc_config_preset alc880_presets[] = {
.mixers = { alc880_lg_lw_mixer },
.init_verbs = { alc880_volume_init_verbs,
alc880_lg_lw_init_verbs },
- .num_dacs = 1,
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
.dac_nids = alc880_dac_nids,
.dig_out_nid = ALC880_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
- .channel_mode = alc880_2_jack_modes,
+ .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes),
+ .channel_mode = alc880_lg_lw_modes,
.input_mux = &alc880_lg_lw_capture_source,
.unsol_event = alc880_lg_lw_unsol_event,
.init_hook = alc880_lg_lw_automute,
@@ -5054,6 +5119,60 @@ static struct hda_verb alc882_macpro_init_verbs[] = {
{ }
};
+/* iMac 24 mixer. */
+static struct snd_kcontrol_new alc885_imac24_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Master Playback Switch", 0x0c, 0x00, HDA_INPUT),
+ { } /* end */
+};
+
+/* iMac 24 init verbs. */
+static struct hda_verb alc885_imac24_init_verbs[] = {
+ /* Internal speakers: output 0 (0x0c) */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Internal speakers: output 0 (0x0c) */
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
+ /* Headphone: output 0 (0x0c) */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+ /* Front Mic: input vref at 80% */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ { }
+};
+
+/* Toggle speaker-output according to the hp-jack state */
+static void alc885_imac24_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
+ snd_hda_codec_amp_update(codec, 0x18, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x18, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+ snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
+ 0x80, present ? 0x80 : 0);
+}
+
+/* Processes unsolicited events. */
+static void alc885_imac24_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Headphone insertion or removal. */
+ if ((res >> 26) == ALC880_HP_EVENT)
+ alc885_imac24_automute(codec);
+}
+
static struct hda_verb alc882_targa_verbs[] = {
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
{0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
@@ -5274,6 +5393,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = {
[ALC882_ARIMA] = "arima",
[ALC882_W2JC] = "w2jc",
[ALC885_MACPRO] = "macpro",
+ [ALC885_IMAC24] = "imac24",
[ALC882_AUTO] = "auto",
};
@@ -5284,6 +5404,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */
SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA),
SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J),
+ SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG),
SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC),
{}
@@ -5345,6 +5466,19 @@ static struct alc_config_preset alc882_presets[] = {
.channel_mode = alc882_ch_modes,
.input_mux = &alc882_capture_source,
},
+ [ALC885_IMAC24] = {
+ .mixers = { alc885_imac24_mixer },
+ .init_verbs = { alc885_imac24_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc882_dac_nids),
+ .dac_nids = alc882_dac_nids,
+ .dig_out_nid = ALC882_DIGOUT_NID,
+ .dig_in_nid = ALC882_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc882_ch_modes),
+ .channel_mode = alc882_ch_modes,
+ .input_mux = &alc882_capture_source,
+ .unsol_event = alc885_imac24_unsol_event,
+ .init_hook = alc885_imac24_automute,
+ },
[ALC882_TARGA] = {
.mixers = { alc882_targa_mixer, alc882_chmode_mixer,
alc882_capture_mixer },
@@ -5379,6 +5513,29 @@ static struct alc_config_preset alc882_presets[] = {
/*
+ * Pin config fixes
+ */
+enum {
+ PINFIX_ABIT_AW9D_MAX
+};
+
+static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
+ { 0x15, 0x01080104 }, /* side */
+ { 0x16, 0x01011012 }, /* rear */
+ { 0x17, 0x01016011 }, /* clfe */
+ { }
+};
+
+static const struct alc_pincfg *alc882_pin_fixes[] = {
+ [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+};
+
+static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+ SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
+ {}
+};
+
+/*
* BIOS auto configuration
*/
static void alc882_auto_set_output_and_unmute(struct hda_codec *codec,
@@ -5494,6 +5651,9 @@ static int patch_alc882(struct hda_codec *codec)
case 0x106b0c00: /* Mac Pro */
board_config = ALC885_MACPRO;
break;
+ case 0x106b1000: /* iMac 24 */
+ board_config = ALC885_IMAC24;
+ break;
default:
printk(KERN_INFO "hda_codec: Unknown model for ALC882, "
"trying auto-probe from BIOS...\n");
@@ -5501,6 +5661,8 @@ static int patch_alc882(struct hda_codec *codec)
}
}
+ alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+
if (board_config == ALC882_AUTO) {
/* automatic parse from the BIOS config */
err = alc882_parse_auto_config(codec);
@@ -5518,7 +5680,7 @@ static int patch_alc882(struct hda_codec *codec)
if (board_config != ALC882_AUTO)
setup_preset(spec, &alc882_presets[board_config]);
- if (board_config == ALC885_MACPRO) {
+ if (board_config == ALC885_MACPRO || board_config == ALC885_IMAC24) {
alc882_gpio_mute(codec, 0, 0);
alc882_gpio_mute(codec, 1, 0);
}
@@ -5995,6 +6157,84 @@ static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
{ } /* end */
};
+static struct snd_kcontrol_new alc888_6st_hp_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc888_3st_hp_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Surround Playback Volume", 0x0e, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Surround Playback Switch", 0x0e, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0d, 2, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0d, 1, 2, HDA_INPUT),
+ HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
+ HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT),
+ HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x05, HDA_INPUT),
+ HDA_CODEC_VOLUME("Capture Volume", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x08, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0x0, HDA_INPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc883_mux_enum_info,
+ .get = alc883_mux_enum_get,
+ .put = alc883_mux_enum_put,
+ },
+ { } /* end */
+};
+
static struct snd_kcontrol_new alc883_chmode_mixer[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
@@ -6126,6 +6366,42 @@ static struct hda_verb alc888_lenovo_ms7195_verbs[] = {
{ } /* end */
};
+static struct hda_verb alc888_6st_hp_verbs[] = {
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Rear : output 2 (0x0e) */
+ {0x16, AC_VERB_SET_CONNECT_SEL, 0x01}, /* CLFE : output 1 (0x0d) */
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, /* Side : output 3 (0x0f) */
+ { }
+};
+
+static struct hda_verb alc888_3st_hp_verbs[] = {
+ {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Front: output 0 (0x0c) */
+ {0x18, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Rear : output 1 (0x0d) */
+ {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, /* CLFE : output 2 (0x0e) */
+ { }
+};
+
+static struct hda_verb alc888_3st_hp_2ch_init[] = {
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
+ { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+ { }
+};
+
+static struct hda_verb alc888_3st_hp_6ch_init[] = {
+ { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
+ { 0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
+ { }
+};
+
+static struct hda_channel_mode alc888_3st_hp_modes[2] = {
+ { 2, alc888_3st_hp_2ch_init },
+ { 6, alc888_3st_hp_6ch_init },
+};
+
/* toggle front-jack and RCA according to the hp-jack state */
static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec)
{
@@ -6368,11 +6644,14 @@ static const char *alc883_models[ALC883_MODEL_LAST] = {
[ALC883_LENOVO_101E_2ch] = "lenovo-101e",
[ALC883_LENOVO_NB0763] = "lenovo-nb0763",
[ALC888_LENOVO_MS7195_DIG] = "lenovo-ms7195-dig",
+ [ALC888_6ST_HP] = "6stack-hp",
+ [ALC888_3ST_HP] = "3stack-hp",
[ALC883_AUTO] = "auto",
};
static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG),
+ SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch),
SND_PCI_QUIRK(0x1558, 0, "Clevo laptop", ALC883_LAPTOP_EAPD),
SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG),
@@ -6381,6 +6660,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG),
+ SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG),
SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG),
SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG),
SND_PCI_QUIRK(0x1462, 0x3ef9, "MSI", ALC883_TARGA_DIG),
@@ -6400,6 +6681,9 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
+ SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC888_6ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP),
+ SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP),
SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
{}
};
@@ -6584,6 +6868,31 @@ static struct alc_config_preset alc883_presets[] = {
.unsol_event = alc883_lenovo_ms7195_unsol_event,
.init_hook = alc888_lenovo_ms7195_front_automute,
},
+ [ALC888_6ST_HP] = {
+ .mixers = { alc888_6st_hp_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs, alc888_6st_hp_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .dig_out_nid = ALC883_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .dig_in_nid = ALC883_DIGIN_NID,
+ .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes),
+ .channel_mode = alc883_sixstack_modes,
+ .input_mux = &alc883_capture_source,
+ },
+ [ALC888_3ST_HP] = {
+ .mixers = { alc888_3st_hp_mixer, alc883_chmode_mixer },
+ .init_verbs = { alc883_init_verbs, alc888_3st_hp_verbs },
+ .num_dacs = ARRAY_SIZE(alc883_dac_nids),
+ .dac_nids = alc883_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc883_adc_nids),
+ .adc_nids = alc883_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc888_3st_hp_modes),
+ .channel_mode = alc888_3st_hp_modes,
+ .need_dac_fix = 1,
+ .input_mux = &alc883_capture_source,
+ },
};
@@ -6857,7 +7166,16 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = {
{ } /* end */
};
-
+static struct snd_kcontrol_new alc262_benq_t31_mixer[] = {
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT),
+ HDA_CODEC_MUTE("ATAPI Mic Playback Switch", 0x0b, 0x01, HDA_INPUT),
+ { } /* end */
+};
#define alc262_capture_mixer alc882_capture_mixer
#define alc262_capture_alt_mixer alc882_capture_alt_mixer
@@ -7189,6 +7507,15 @@ static struct hda_verb alc262_EAPD_verbs[] = {
{}
};
+static struct hda_verb alc262_benq_t31_EAPD_verbs[] = {
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x3050},
+ {}
+};
+
/* add playback controls from the parsed DAC table */
static int alc262_auto_create_multi_out_ctls(struct alc_spec *spec,
const struct auto_pin_cfg *cfg)
@@ -7584,7 +7911,8 @@ static const char *alc262_models[ALC262_MODEL_LAST] = {
[ALC262_HP_BPC] = "hp-bpc",
[ALC262_HP_BPC_D7000_WL]= "hp-bpc-d7000",
[ALC262_BENQ_ED8] = "benq",
- [ALC262_BENQ_ED8] = "sony-assamd",
+ [ALC262_BENQ_T31] = "benq-t31",
+ [ALC262_SONY_ASSAMD] = "sony-assamd",
[ALC262_AUTO] = "auto",
};
@@ -7592,8 +7920,12 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
SND_PCI_QUIRK(0x1002, 0x437b, "Hippo", ALC262_HIPPO),
SND_PCI_QUIRK(0x103c, 0x12fe, "HP xw9400", ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x280c, "HP xw4400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x12ff, "HP xw4550", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x1308, "HP xw4600", ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x3014, "HP xw6400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x1307, "HP xw6600", ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x3015, "HP xw8400", ALC262_HP_BPC),
+ SND_PCI_QUIRK(0x103c, 0x1306, "HP xw8600", ALC262_HP_BPC),
SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
SND_PCI_QUIRK(0x103c, 0x2804, "HP D7000", ALC262_HP_BPC_D7000_WL),
@@ -7606,6 +7938,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FUJITSU),
SND_PCI_QUIRK(0x17ff, 0x058f, "Benq Hippo", ALC262_HIPPO_1),
SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_BENQ_ED8),
+ SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_BENQ_T31),
SND_PCI_QUIRK(0x104d, 0x9015, "Sony 0x9015", ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x104d, 0x900e, "Sony ASSAMD", ALC262_SONY_ASSAMD),
SND_PCI_QUIRK(0x104d, 0x1f00, "Sony ASSAMD", ALC262_SONY_ASSAMD),
@@ -7710,6 +8043,17 @@ static struct alc_config_preset alc262_presets[] = {
.channel_mode = alc262_modes,
.input_mux = &alc262_capture_source,
.unsol_event = alc262_hippo_unsol_event,
+ },
+ [ALC262_BENQ_T31] = {
+ .mixers = { alc262_benq_t31_mixer },
+ .init_verbs = { alc262_init_verbs, alc262_benq_t31_EAPD_verbs, alc262_hippo_unsol_verbs },
+ .num_dacs = ARRAY_SIZE(alc262_dac_nids),
+ .dac_nids = alc262_dac_nids,
+ .hp_nid = 0x03,
+ .num_channel_mode = ARRAY_SIZE(alc262_modes),
+ .channel_mode = alc262_modes,
+ .input_mux = &alc262_capture_source,
+ .unsol_event = alc262_hippo_unsol_event,
},
};
@@ -7800,6 +8144,515 @@ static int patch_alc262(struct hda_codec *codec)
}
/*
+ * ALC268 channel source setting (2 channel)
+ */
+#define ALC268_DIGOUT_NID ALC880_DIGOUT_NID
+#define alc268_modes alc260_modes
+
+static hda_nid_t alc268_dac_nids[2] = {
+ /* front, hp */
+ 0x02, 0x03
+};
+
+static hda_nid_t alc268_adc_nids[2] = {
+ /* ADC0-1 */
+ 0x08, 0x07
+};
+
+static hda_nid_t alc268_adc_nids_alt[1] = {
+ /* ADC0 */
+ 0x08
+};
+
+static struct snd_kcontrol_new alc268_base_mixer[] = {
+ /* output mixer control */
+ HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT),
+ { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_base_init_verbs[] = {
+ /* Unmute DAC0-1 and set vol = 0 */
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ /*
+ * Set up output mixers (0x0c - 0x0e)
+ */
+ /* set vol=0 to output mixers */
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_CONNECT_SEL, 0x00},
+
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0},
+ {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+
+ /* FIXME: use matrix-type input source selection */
+ /* Mixer elements: 0x18, 19, 1a, 1c, 14, 15, 0b */
+ /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */
+ /* Input mixer2 */
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x01 << 8))},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))},
+ {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))},
+ { }
+};
+
+/*
+ * generic initialization of ADC, input mixers and output mixers
+ */
+static struct hda_verb alc268_volume_init_verbs[] = {
+ /* set output DAC */
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+ {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+ {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+ {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20},
+
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
+ {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+ {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+
+ /* set PCBEEP vol = 0 */
+ {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, (0xb000 | (0x00 << 8))},
+
+ { }
+};
+
+#define alc268_mux_enum_info alc_mux_enum_info
+#define alc268_mux_enum_get alc_mux_enum_get
+
+static int alc268_mux_enum_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct alc_spec *spec = codec->spec;
+ const struct hda_input_mux *imux = spec->input_mux;
+ unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+ static hda_nid_t capture_mixers[3] = { 0x23, 0x24 };
+ hda_nid_t nid = capture_mixers[adc_idx];
+ unsigned int *cur_val = &spec->cur_mux[adc_idx];
+ unsigned int i, idx;
+
+ idx = ucontrol->value.enumerated.item[0];
+ if (idx >= imux->num_items)
+ idx = imux->num_items - 1;
+ if (*cur_val == idx && !codec->in_resume)
+ return 0;
+ for (i = 0; i < imux->num_items; i++) {
+ unsigned int v = (i == idx) ? 0x7000 : 0x7080;
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+ v | (imux->items[i].index << 8));
+ snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL,
+ idx );
+ }
+ *cur_val = idx;
+ return 1;
+}
+
+static struct snd_kcontrol_new alc268_capture_alt_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 1,
+ .info = alc268_mux_enum_info,
+ .get = alc268_mux_enum_get,
+ .put = alc268_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct snd_kcontrol_new alc268_capture_mixer[] = {
+ HDA_CODEC_VOLUME("Capture Volume", 0x23, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE("Capture Switch", 0x23, 0x0, HDA_OUTPUT),
+ HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x24, 0x0, HDA_OUTPUT),
+ HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x24, 0x0, HDA_OUTPUT),
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ /* The multiple "Capture Source" controls confuse alsamixer
+ * So call somewhat different..
+ * FIXME: the controls appear in the "playback" view!
+ */
+ /* .name = "Capture Source", */
+ .name = "Input Source",
+ .count = 2,
+ .info = alc268_mux_enum_info,
+ .get = alc268_mux_enum_get,
+ .put = alc268_mux_enum_put,
+ },
+ { } /* end */
+};
+
+static struct hda_input_mux alc268_capture_source = {
+ .num_items = 4,
+ .items = {
+ { "Mic", 0x0 },
+ { "Front Mic", 0x1 },
+ { "Line", 0x2 },
+ { "CD", 0x3 },
+ },
+};
+
+/* create input playback/capture controls for the given pin */
+static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid,
+ const char *ctlname, int idx)
+{
+ char name[32];
+ int err;
+
+ sprintf(name, "%s Playback Volume", ctlname);
+ if (nid == 0x14) {
+ err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(0x02, 3, idx,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else if (nid == 0x15) {
+ err = add_control(spec, ALC_CTL_WIDGET_VOL, name,
+ HDA_COMPOSE_AMP_VAL(0x03, 3, idx,
+ HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ } else
+ return -1;
+ sprintf(name, "%s Playback Switch", ctlname);
+ err = add_control(spec, ALC_CTL_WIDGET_MUTE, name,
+ HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ hda_nid_t nid;
+ int err;
+
+ spec->multiout.num_dacs = 2; /* only use one dac */
+ spec->multiout.dac_nids = spec->private_dac_nids;
+ spec->multiout.dac_nids[0] = 2;
+ spec->multiout.dac_nids[1] = 3;
+
+ nid = cfg->line_out_pins[0];
+ if (nid)
+ alc268_new_analog_output(spec, nid, "Front", 0);
+
+ nid = cfg->speaker_pins[0];
+ if (nid == 0x1d) {
+ err = add_control(spec, ALC_CTL_WIDGET_VOL,
+ "Speaker Playback Volume",
+ HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ }
+ nid = cfg->hp_pins[0];
+ if (nid)
+ alc268_new_analog_output(spec, nid, "Headphone", 0);
+
+ nid = cfg->line_out_pins[1] | cfg->line_out_pins[2];
+ if (nid == 0x16) {
+ err = add_control(spec, ALC_CTL_WIDGET_MUTE,
+ "Mono Playback Switch",
+ HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_INPUT));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+/* create playback/capture controls for input pins */
+static int alc268_auto_create_analog_input_ctls(struct alc_spec *spec,
+ const struct auto_pin_cfg *cfg)
+{
+ struct hda_input_mux *imux = &spec->private_imux;
+ int i, idx1;
+
+ for (i = 0; i < AUTO_PIN_LAST; i++) {
+ switch(cfg->input_pins[i]) {
+ case 0x18:
+ idx1 = 0; /* Mic 1 */
+ break;
+ case 0x19:
+ idx1 = 1; /* Mic 2 */
+ break;
+ case 0x1a:
+ idx1 = 2; /* Line In */
+ break;
+ case 0x1c:
+ idx1 = 3; /* CD */
+ break;
+ default:
+ continue;
+ }
+ imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
+ imux->items[imux->num_items].index = idx1;
+ imux->num_items++;
+ }
+ return 0;
+}
+
+static void alc268_auto_init_mono_speaker_out(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0];
+ hda_nid_t hp_nid = spec->autocfg.hp_pins[0];
+ hda_nid_t line_nid = spec->autocfg.line_out_pins[0];
+ unsigned int dac_vol1, dac_vol2;
+
+ if (speaker_nid) {
+ snd_hda_codec_write(codec, speaker_nid, 0,
+ AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+ snd_hda_codec_write(codec, 0x0f, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_UNMUTE(1));
+ snd_hda_codec_write(codec, 0x10, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_IN_UNMUTE(1));
+ } else {
+ snd_hda_codec_write(codec, 0x0f, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+ snd_hda_codec_write(codec, 0x10, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1));
+ }
+
+ dac_vol1 = dac_vol2 = 0xb000 | 0x40; /* set max volume */
+ if (line_nid == 0x14)
+ dac_vol2 = AMP_OUT_ZERO;
+ else if (line_nid == 0x15)
+ dac_vol1 = AMP_OUT_ZERO;
+ if (hp_nid == 0x14)
+ dac_vol2 = AMP_OUT_ZERO;
+ else if (hp_nid == 0x15)
+ dac_vol1 = AMP_OUT_ZERO;
+ if (line_nid != 0x16 || hp_nid != 0x16 ||
+ spec->autocfg.line_out_pins[1] != 0x16 ||
+ spec->autocfg.line_out_pins[2] != 0x16)
+ dac_vol1 = dac_vol2 = AMP_OUT_ZERO;
+
+ snd_hda_codec_write(codec, 0x02, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, dac_vol1);
+ snd_hda_codec_write(codec, 0x03, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE, dac_vol2);
+}
+
+/* pcm configuration: identiacal with ALC880 */
+#define alc268_pcm_analog_playback alc880_pcm_analog_playback
+#define alc268_pcm_analog_capture alc880_pcm_analog_capture
+#define alc268_pcm_digital_playback alc880_pcm_digital_playback
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int err;
+ static hda_nid_t alc268_ignore[] = { 0 };
+
+ err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
+ alc268_ignore);
+ if (err < 0)
+ return err;
+ if (!spec->autocfg.line_outs)
+ return 0; /* can't find valid BIOS pin config */
+
+ err = alc268_auto_create_multi_out_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+ err = alc268_auto_create_analog_input_ctls(spec, &spec->autocfg);
+ if (err < 0)
+ return err;
+
+ spec->multiout.max_channels = 2;
+
+ /* digital only support output */
+ if (spec->autocfg.dig_out_pin)
+ spec->multiout.dig_out_nid = ALC268_DIGOUT_NID;
+
+ if (spec->kctl_alloc)
+ spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
+
+ spec->init_verbs[spec->num_init_verbs++] = alc268_volume_init_verbs;
+ spec->num_mux_defs = 1;
+ spec->input_mux = &spec->private_imux;
+
+ return 1;
+}
+
+#define alc268_auto_init_multi_out alc882_auto_init_multi_out
+#define alc268_auto_init_hp_out alc882_auto_init_hp_out
+#define alc268_auto_init_analog_input alc882_auto_init_analog_input
+
+/* init callback for auto-configuration model -- overriding the default init */
+static void alc268_auto_init(struct hda_codec *codec)
+{
+ alc268_auto_init_multi_out(codec);
+ alc268_auto_init_hp_out(codec);
+ alc268_auto_init_mono_speaker_out(codec);
+ alc268_auto_init_analog_input(codec);
+}
+
+/*
+ * configuration and preset
+ */
+static const char *alc268_models[ALC268_MODEL_LAST] = {
+ [ALC268_3ST] = "3stack",
+ [ALC268_AUTO] = "auto",
+};
+
+static struct snd_pci_quirk alc268_cfg_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST),
+ {}
+};
+
+static struct alc_config_preset alc268_presets[] = {
+ [ALC268_3ST] = {
+ .mixers = { alc268_base_mixer, alc268_capture_alt_mixer },
+ .init_verbs = { alc268_base_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc268_dac_nids),
+ .dac_nids = alc268_dac_nids,
+ .num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt),
+ .adc_nids = alc268_adc_nids_alt,
+ .hp_nid = 0x03,
+ .dig_out_nid = ALC268_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc268_modes),
+ .channel_mode = alc268_modes,
+ .input_mux = &alc268_capture_source,
+ },
+};
+
+static int patch_alc268(struct hda_codec *codec)
+{
+ struct alc_spec *spec;
+ int board_config;
+ int err;
+
+ spec = kcalloc(1, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+
+ codec->spec = spec;
+
+ board_config = snd_hda_check_board_config(codec, ALC268_MODEL_LAST,
+ alc268_models,
+ alc268_cfg_tbl);
+
+ if (board_config < 0 || board_config >= ALC268_MODEL_LAST) {
+ printk(KERN_INFO "hda_codec: Unknown model for ALC268, "
+ "trying auto-probe from BIOS...\n");
+ board_config = ALC268_AUTO;
+ }
+
+ if (board_config == ALC268_AUTO) {
+ /* automatic parse from the BIOS config */
+ err = alc268_parse_auto_config(codec);
+ if (err < 0) {
+ alc_free(codec);
+ return err;
+ } else if (!err) {
+ printk(KERN_INFO
+ "hda_codec: Cannot set up configuration "
+ "from BIOS. Using base mode...\n");
+ board_config = ALC268_3ST;
+ }
+ }
+
+ if (board_config != ALC268_AUTO)
+ setup_preset(spec, &alc268_presets[board_config]);
+
+ spec->stream_name_analog = "ALC268 Analog";
+ spec->stream_analog_playback = &alc268_pcm_analog_playback;
+ spec->stream_analog_capture = &alc268_pcm_analog_capture;
+
+ spec->stream_name_digital = "ALC268 Digital";
+ spec->stream_digital_playback = &alc268_pcm_digital_playback;
+
+ if (board_config == ALC268_AUTO) {
+ if (!spec->adc_nids && spec->input_mux) {
+ /* check whether NID 0x07 is valid */
+ unsigned int wcap = get_wcaps(codec, 0x07);
+
+ /* get type */
+ wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
+ if (wcap != AC_WID_AUD_IN) {
+ spec->adc_nids = alc268_adc_nids_alt;
+ spec->num_adc_nids =
+ ARRAY_SIZE(alc268_adc_nids_alt);
+ spec->mixers[spec->num_mixers] =
+ alc268_capture_alt_mixer;
+ spec->num_mixers++;
+ } else {
+ spec->adc_nids = alc268_adc_nids;
+ spec->num_adc_nids =
+ ARRAY_SIZE(alc268_adc_nids);
+ spec->mixers[spec->num_mixers] =
+ alc268_capture_mixer;
+ spec->num_mixers++;
+ }
+ }
+ }
+ codec->patch_ops = alc_patch_ops;
+ if (board_config == ALC268_AUTO)
+ spec->init_hook = alc268_auto_init;
+
+ return 0;
+}
+
+/*
* ALC861 channel source setting (2/6 channel selection for 3-stack)
*/
@@ -8767,13 +9620,21 @@ static struct snd_pci_quirk alc861_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1335, "ASUS F2/3", ALC861_ASUS_LAPTOP),
SND_PCI_QUIRK(0x1043, 0x1338, "ASUS F2/3", ALC861_ASUS_LAPTOP),
SND_PCI_QUIRK(0x1043, 0x13d7, "ASUS A9rp", ALC861_ASUS_LAPTOP),
+ SND_PCI_QUIRK(0x1584, 0x9075, "Airis Praxis N1212", ALC861_ASUS_LAPTOP),
SND_PCI_QUIRK(0x1043, 0x1393, "ASUS", ALC861_ASUS),
+ SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS P1-AH2", ALC861_3ST_DIG),
SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba", ALC861_TOSHIBA),
- SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA),
+ /* FIXME: the entry below breaks Toshiba A100 (model=auto works!)
+ * Any other models that need this preset?
+ */
+ /* SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba", ALC861_TOSHIBA), */
SND_PCI_QUIRK(0x1584, 0x9072, "Uniwill m31", ALC861_UNIWILL_M31),
+ SND_PCI_QUIRK(0x1584, 0x9075, "Uniwill", ALC861_UNIWILL_M31),
SND_PCI_QUIRK(0x1584, 0x2b01, "Uniwill X40AIx", ALC861_UNIWILL_M31),
SND_PCI_QUIRK(0x1849, 0x0660, "Asrock 939SLI32", ALC660_3ST),
SND_PCI_QUIRK(0x8086, 0xd600, "Intel", ALC861_3ST),
+ SND_PCI_QUIRK(0x1462, 0x7254, "HP dx2200 (MSI MS-7254)", ALC861_3ST),
+ SND_PCI_QUIRK(0x1462, 0x7297, "HP dx2250 (MSI MS-7297)", ALC861_3ST),
{}
};
@@ -9464,6 +10325,7 @@ static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int re
*/
static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
[ALC660VD_3ST] = "3stack-660",
+ [ALC660VD_3ST_DIG]= "3stack-660-digout",
[ALC861VD_3ST] = "3stack",
[ALC861VD_3ST_DIG] = "3stack-digout",
[ALC861VD_6ST_DIG] = "6stack-digout",
@@ -9475,7 +10337,7 @@ static const char *alc861vd_models[ALC861VD_MODEL_LAST] = {
static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
- SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST),
+ SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
@@ -9483,6 +10345,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
SND_PCI_QUIRK(0x1179, 0xff01, "DALLAS", ALC861VD_DALLAS),
SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo 3000 C200", ALC861VD_LENOVO),
SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo", ALC861VD_LENOVO),
+ SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba A135", ALC861VD_LENOVO),
{}
};
@@ -9499,6 +10362,19 @@ static struct alc_config_preset alc861vd_presets[] = {
.channel_mode = alc861vd_3stack_2ch_modes,
.input_mux = &alc861vd_capture_source,
},
+ [ALC660VD_3ST_DIG] = {
+ .mixers = { alc861vd_3st_mixer },
+ .init_verbs = { alc861vd_volume_init_verbs,
+ alc861vd_3stack_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc660vd_dac_nids),
+ .dac_nids = alc660vd_dac_nids,
+ .dig_out_nid = ALC861VD_DIGOUT_NID,
+ .num_adc_nids = ARRAY_SIZE(alc861vd_adc_nids),
+ .adc_nids = alc861vd_adc_nids,
+ .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes),
+ .channel_mode = alc861vd_3stack_2ch_modes,
+ .input_mux = &alc861vd_capture_source,
+ },
[ALC861VD_3ST] = {
.mixers = { alc861vd_3st_mixer },
.init_verbs = { alc861vd_volume_init_verbs,
@@ -10420,7 +11296,7 @@ static int alc662_auto_create_multi_out_ctls(struct alc_spec *spec,
for (i = 0; i < cfg->line_outs; i++) {
if (!spec->multiout.dac_nids[i])
continue;
- nid = alc880_idx_to_dac(i);
+ nid = alc880_idx_to_mixer(i);
if (i == 2) {
/* Center/LFE */
err = add_control(spec, ALC_CTL_WIDGET_VOL,
@@ -10643,14 +11519,10 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
spec->num_mux_defs = 1;
spec->input_mux = &spec->private_imux;
- if (err < 0)
- return err;
- else if (err > 0)
- /* hack - override the init verbs */
- spec->init_verbs[0] = alc662_auto_init_verbs;
+ spec->init_verbs[spec->num_init_verbs++] = alc662_auto_init_verbs;
spec->mixers[spec->num_mixers] = alc662_capture_mixer;
spec->num_mixers++;
- return err;
+ return 1;
}
/* additional initialization for auto-configuration model */
@@ -10687,7 +11559,7 @@ static int patch_alc662(struct hda_codec *codec)
if (err < 0) {
alc_free(codec);
return err;
- } else if (err) {
+ } else if (!err) {
printk(KERN_INFO
"hda_codec: Cannot set up configuration "
"from BIOS. Using base mode...\n");
@@ -10724,6 +11596,7 @@ static int patch_alc662(struct hda_codec *codec)
struct hda_codec_preset snd_hda_preset_realtek[] = {
{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
+ { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
.patch = patch_alc861 },
{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 43f537ef40bf..6d2ecc38905c 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -304,8 +304,12 @@ struct hda_codec_preset snd_hda_preset_si3054[] = {
{ .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 },
{ .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
{ .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 },
+ /* VIA HDA on Clevo m540 */
+ { .id = 0x11063288, .name = "Si3054", .patch = patch_si3054 },
/* Asus A8J Modem (SM56) */
{ .id = 0x15433155, .name = "Si3054", .patch = patch_si3054 },
+ /* LG LW20 modem */
+ { .id = 0x18540018, .name = "Si3054", .patch = patch_si3054 },
{}
};
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index e3964fc4c405..3f25de72966b 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -44,6 +44,7 @@ enum {
enum {
STAC_9205_REF,
+ STAC_M43xx,
STAC_9205_MODELS
};
@@ -59,11 +60,19 @@ enum {
STAC_D945_REF,
STAC_D945GTP3,
STAC_D945GTP5,
+ STAC_922X_DELL,
+ STAC_INTEL_MAC_V1,
+ STAC_INTEL_MAC_V2,
+ STAC_INTEL_MAC_V3,
+ STAC_INTEL_MAC_V4,
+ STAC_INTEL_MAC_V5,
+ /* for backward compitability */
STAC_MACMINI,
STAC_MACBOOK,
STAC_MACBOOK_PRO_V1,
STAC_MACBOOK_PRO_V2,
STAC_IMAC_INTEL,
+ STAC_IMAC_INTEL_20,
STAC_922X_MODELS
};
@@ -210,7 +219,6 @@ static hda_nid_t stac9205_pin_nids[12] = {
0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x14, 0x16, 0x17, 0x18,
0x21, 0x22,
-
};
static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol,
@@ -326,8 +334,6 @@ static struct snd_kcontrol_new stac9200_mixer[] = {
};
static struct snd_kcontrol_new stac925x_mixer[] = {
- HDA_CODEC_VOLUME("Master Playback Volume", 0xe, 0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Master Playback Switch", 0xe, 0, HDA_OUTPUT),
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Input Source",
@@ -549,44 +555,78 @@ static unsigned int d945gtp5_pin_configs[10] = {
0x02a19320, 0x40000100,
};
-static unsigned int macbook_pro_v1_pin_configs[10] = {
- 0x0321e230, 0x03a1e020, 0x9017e110, 0x01014010,
- 0x01a19021, 0x0381e021, 0x1345e240, 0x13c5e22e,
- 0x02a19320, 0x400000fb
+static unsigned int intel_mac_v1_pin_configs[10] = {
+ 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd,
+ 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240,
+ 0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v2_pin_configs[10] = {
+ 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+ 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa,
+ 0x400000fc, 0x400000fb,
+};
+
+static unsigned int intel_mac_v3_pin_configs[10] = {
+ 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd,
+ 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240,
+ 0x400000fc, 0x400000fb,
};
-static unsigned int macbook_pro_v2_pin_configs[10] = {
- 0x0221401f, 0x90a70120, 0x01813024, 0x01014010,
- 0x400000fd, 0x01016011, 0x1345e240, 0x13c5e22e,
+static unsigned int intel_mac_v4_pin_configs[10] = {
+ 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+ 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
0x400000fc, 0x400000fb,
};
-static unsigned int imac_intel_pin_configs[10] = {
- 0x0121e230, 0x90a70120, 0x9017e110, 0x400000fe,
- 0x400000fd, 0x0181e021, 0x1145e040, 0x400000fa,
+static unsigned int intel_mac_v5_pin_configs[10] = {
+ 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f,
+ 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240,
0x400000fc, 0x400000fb,
};
+static unsigned int stac922x_dell_pin_configs[10] = {
+ 0x0221121e, 0x408103ff, 0x02a1123e, 0x90100310,
+ 0x408003f1, 0x0221122f, 0x03451340, 0x40c003f2,
+ 0x50a003f3, 0x405003f4
+};
+
static unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = {
[STAC_D945_REF] = ref922x_pin_configs,
[STAC_D945GTP3] = d945gtp3_pin_configs,
[STAC_D945GTP5] = d945gtp5_pin_configs,
- [STAC_MACMINI] = macbook_pro_v1_pin_configs,
- [STAC_MACBOOK] = macbook_pro_v1_pin_configs,
- [STAC_MACBOOK_PRO_V1] = macbook_pro_v1_pin_configs,
- [STAC_MACBOOK_PRO_V2] = macbook_pro_v2_pin_configs,
- [STAC_IMAC_INTEL] = imac_intel_pin_configs,
+ [STAC_922X_DELL] = stac922x_dell_pin_configs,
+ [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs,
+ [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs,
+ [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs,
+ [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs,
+ [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs,
+ /* for backward compitability */
+ [STAC_MACMINI] = intel_mac_v3_pin_configs,
+ [STAC_MACBOOK] = intel_mac_v5_pin_configs,
+ [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs,
+ [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs,
+ [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs,
+ [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs,
};
static const char *stac922x_models[STAC_922X_MODELS] = {
[STAC_D945_REF] = "ref",
[STAC_D945GTP5] = "5stack",
[STAC_D945GTP3] = "3stack",
+ [STAC_922X_DELL] = "dell",
+ [STAC_INTEL_MAC_V1] = "intel-mac-v1",
+ [STAC_INTEL_MAC_V2] = "intel-mac-v2",
+ [STAC_INTEL_MAC_V3] = "intel-mac-v3",
+ [STAC_INTEL_MAC_V4] = "intel-mac-v4",
+ [STAC_INTEL_MAC_V5] = "intel-mac-v5",
+ /* for backward compitability */
[STAC_MACMINI] = "macmini",
[STAC_MACBOOK] = "macbook",
[STAC_MACBOOK_PRO_V1] = "macbook-pro-v1",
[STAC_MACBOOK_PRO_V2] = "macbook-pro",
[STAC_IMAC_INTEL] = "imac-intel",
+ [STAC_IMAC_INTEL_20] = "imac-intel-20",
};
static struct snd_pci_quirk stac922x_cfg_tbl[] = {
@@ -649,7 +689,10 @@ static struct snd_pci_quirk stac922x_cfg_tbl[] = {
/* other systems */
/* Apple Mac Mini (early 2006) */
SND_PCI_QUIRK(0x8384, 0x7680,
- "Mac Mini", STAC_MACMINI),
+ "Mac Mini", STAC_INTEL_MAC_V3),
+ /* Dell */
+ SND_PCI_QUIRK(0x1028, 0x01d7, "Dell XPS M1210", STAC_922X_DELL),
+
{} /* terminator */
};
@@ -730,7 +773,8 @@ static unsigned int ref9205_pin_configs[12] = {
};
static unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = {
- ref9205_pin_configs,
+ [STAC_REF] = ref9205_pin_configs,
+ [STAC_M43xx] = NULL,
};
static const char *stac9205_models[STAC_9205_MODELS] = {
@@ -741,6 +785,10 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = {
/* SigmaTel reference board */
SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
"DFI LanParty", STAC_9205_REF),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01f8,
+ "Dell Precision", STAC_M43xx),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x01ff,
+ "Dell Precision", STAC_M43xx),
{} /* terminator */
};
@@ -770,33 +818,56 @@ static int stac92xx_save_bios_config_regs(struct hda_codec *codec)
return 0;
}
+static void stac92xx_set_config_reg(struct hda_codec *codec,
+ hda_nid_t pin_nid, unsigned int pin_config)
+{
+ int i;
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
+ pin_config & 0x000000ff);
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
+ (pin_config & 0x0000ff00) >> 8);
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
+ (pin_config & 0x00ff0000) >> 16);
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
+ pin_config >> 24);
+ i = snd_hda_codec_read(codec, pin_nid, 0,
+ AC_VERB_GET_CONFIG_DEFAULT,
+ 0x00);
+ snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n",
+ pin_nid, i);
+}
+
static void stac92xx_set_config_regs(struct hda_codec *codec)
{
int i;
struct sigmatel_spec *spec = codec->spec;
- unsigned int pin_cfg;
- if (! spec->pin_nids || ! spec->pin_configs)
- return;
+ if (!spec->pin_configs)
+ return;
- for (i = 0; i < spec->num_pins; i++) {
- snd_hda_codec_write(codec, spec->pin_nids[i], 0,
- AC_VERB_SET_CONFIG_DEFAULT_BYTES_0,
- spec->pin_configs[i] & 0x000000ff);
- snd_hda_codec_write(codec, spec->pin_nids[i], 0,
- AC_VERB_SET_CONFIG_DEFAULT_BYTES_1,
- (spec->pin_configs[i] & 0x0000ff00) >> 8);
- snd_hda_codec_write(codec, spec->pin_nids[i], 0,
- AC_VERB_SET_CONFIG_DEFAULT_BYTES_2,
- (spec->pin_configs[i] & 0x00ff0000) >> 16);
- snd_hda_codec_write(codec, spec->pin_nids[i], 0,
- AC_VERB_SET_CONFIG_DEFAULT_BYTES_3,
- spec->pin_configs[i] >> 24);
- pin_cfg = snd_hda_codec_read(codec, spec->pin_nids[i], 0,
- AC_VERB_GET_CONFIG_DEFAULT,
- 0x00);
- snd_printdd(KERN_INFO "hda_codec: pin nid %2.2x pin config %8.8x\n", spec->pin_nids[i], pin_cfg);
- }
+ for (i = 0; i < spec->num_pins; i++)
+ stac92xx_set_config_reg(codec, spec->pin_nids[i],
+ spec->pin_configs[i]);
+}
+
+static void stac92xx_enable_gpio_mask(struct hda_codec *codec,
+ int gpio_mask, int gpio_data)
+{
+ /* Configure GPIOx as output */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DIRECTION, gpio_mask);
+ /* Configure GPIOx as CMOS */
+ snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
+ /* Assert GPIOx */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_DATA, gpio_data);
+ /* Enable GPIOx */
+ snd_hda_codec_write(codec, codec->afg, 0,
+ AC_VERB_SET_GPIO_MASK, gpio_mask);
}
/*
@@ -1168,7 +1239,7 @@ static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid)
* and 9202/925x. For those, dac_nids[] must be hard-coded.
*/
static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
- const struct auto_pin_cfg *cfg)
+ struct auto_pin_cfg *cfg)
{
struct sigmatel_spec *spec = codec->spec;
int i, j, conn_len = 0;
@@ -1193,6 +1264,13 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec,
}
if (j == conn_len) {
+ if (spec->multiout.num_dacs > 0) {
+ /* we have already working output pins,
+ * so let's drop the broken ones again
+ */
+ cfg->line_outs = spec->multiout.num_dacs;
+ break;
+ }
/* error out, no available DAC found */
snd_printk(KERN_ERR
"%s: No available DAC for pin 0x%x\n",
@@ -1334,7 +1412,15 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
continue;
add_spec_dacs(spec, nid);
}
-
+ for (i = 0; i < cfg->line_outs; i++) {
+ nid = snd_hda_codec_read(codec, cfg->line_out_pins[i], 0,
+ AC_VERB_GET_CONNECT_LIST, 0) & 0xff;
+ if (check_in_dac_nids(spec, nid))
+ nid = 0;
+ if (! nid)
+ continue;
+ add_spec_dacs(spec, nid);
+ }
for (i = old_num_dacs; i < spec->multiout.num_dacs; i++) {
static const char *pfxs[] = {
"Speaker", "External Speaker", "Speaker2",
@@ -1891,7 +1977,7 @@ static int patch_stac9200(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
- spec->num_pins = 8;
+ spec->num_pins = ARRAY_SIZE(stac9200_pin_nids);
spec->pin_nids = stac9200_pin_nids;
spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS,
stac9200_models,
@@ -1941,7 +2027,7 @@ static int patch_stac925x(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
- spec->num_pins = 8;
+ spec->num_pins = ARRAY_SIZE(stac925x_pin_nids);
spec->pin_nids = stac925x_pin_nids;
spec->board_config = snd_hda_check_board_config(codec, STAC_925x_MODELS,
stac925x_models,
@@ -2013,29 +2099,41 @@ static int patch_stac922x(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
- spec->num_pins = 10;
+ spec->num_pins = ARRAY_SIZE(stac922x_pin_nids);
spec->pin_nids = stac922x_pin_nids;
spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS,
stac922x_models,
stac922x_cfg_tbl);
- if (spec->board_config == STAC_MACMINI) {
+ if (spec->board_config == STAC_INTEL_MAC_V3) {
spec->gpio_mute = 1;
/* Intel Macs have all same PCI SSID, so we need to check
* codec SSID to distinguish the exact models
*/
printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id);
switch (codec->subsystem_id) {
- case 0x106b0a00: /* MacBook First generatoin */
- spec->board_config = STAC_MACBOOK;
+
+ case 0x106b0800:
+ spec->board_config = STAC_INTEL_MAC_V1;
+ break;
+ case 0x106b0600:
+ case 0x106b0700:
+ spec->board_config = STAC_INTEL_MAC_V2;
break;
- case 0x106b0200: /* MacBook Pro first generation */
- spec->board_config = STAC_MACBOOK_PRO_V1;
+ case 0x106b0e00:
+ case 0x106b0f00:
+ case 0x106b1600:
+ case 0x106b1700:
+ case 0x106b0200:
+ case 0x106b1e00:
+ spec->board_config = STAC_INTEL_MAC_V3;
break;
- case 0x106b1e00: /* MacBook Pro second generation */
- spec->board_config = STAC_MACBOOK_PRO_V2;
+ case 0x106b1a00:
+ case 0x00000100:
+ spec->board_config = STAC_INTEL_MAC_V4;
break;
- case 0x106b0700: /* Intel-based iMac */
- spec->board_config = STAC_IMAC_INTEL;
+ case 0x106b0a00:
+ case 0x106b2200:
+ spec->board_config = STAC_INTEL_MAC_V5;
break;
}
}
@@ -2082,6 +2180,13 @@ static int patch_stac922x(struct hda_codec *codec)
codec->patch_ops = stac92xx_patch_ops;
+ /* Fix Mux capture level; max to 2 */
+ snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
+ (0 << AC_AMPCAP_OFFSET_SHIFT) |
+ (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (0 << AC_AMPCAP_MUTE_SHIFT));
+
return 0;
}
@@ -2095,7 +2200,7 @@ static int patch_stac927x(struct hda_codec *codec)
return -ENOMEM;
codec->spec = spec;
- spec->num_pins = 14;
+ spec->num_pins = ARRAY_SIZE(stac927x_pin_nids);
spec->pin_nids = stac927x_pin_nids;
spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS,
stac927x_models,
@@ -2141,7 +2246,9 @@ static int patch_stac927x(struct hda_codec *codec)
}
spec->multiout.dac_nids = spec->dac_nids;
-
+ /* GPIO0 High = Enable EAPD */
+ stac92xx_enable_gpio_mask(codec, 0x00000001, 0x00000001);
+
err = stac92xx_parse_auto_config(codec, 0x1e, 0x20);
if (!err) {
if (spec->board_config < 0) {
@@ -2159,27 +2266,20 @@ static int patch_stac927x(struct hda_codec *codec)
codec->patch_ops = stac92xx_patch_ops;
- /* Fix Mux capture level; max to 2 */
- snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
- (0 << AC_AMPCAP_OFFSET_SHIFT) |
- (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
- (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
- (0 << AC_AMPCAP_MUTE_SHIFT));
-
return 0;
}
static int patch_stac9205(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
- int err;
+ int err, gpio_mask, gpio_data;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
if (spec == NULL)
return -ENOMEM;
codec->spec = spec;
- spec->num_pins = 14;
+ spec->num_pins = ARRAY_SIZE(stac9205_pin_nids);
spec->pin_nids = stac9205_pin_nids;
spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS,
stac9205_models,
@@ -2209,19 +2309,21 @@ static int patch_stac9205(struct hda_codec *codec)
spec->mixer = stac9205_mixer;
spec->multiout.dac_nids = spec->dac_nids;
+
+ if (spec->board_config == STAC_M43xx) {
+ /* Enable SPDIF in/out */
+ stac92xx_set_config_reg(codec, 0x1f, 0x01441030);
+ stac92xx_set_config_reg(codec, 0x20, 0x1c410030);
+
+ gpio_mask = 0x00000007; /* GPIO0-2 */
+ /* GPIO0 High = EAPD, GPIO1 Low = DRM,
+ * GPIO2 High = Headphone Mute
+ */
+ gpio_data = 0x00000005;
+ } else
+ gpio_mask = gpio_data = 0x00000001; /* GPIO0 High = EAPD */
- /* Configure GPIO0 as EAPD output */
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DIRECTION, 0x00000001);
- /* Configure GPIO0 as CMOS */
- snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0x00000000);
- /* Assert GPIO0 high */
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_DATA, 0x00000001);
- /* Enable GPIO0 */
- snd_hda_codec_write(codec, codec->afg, 0,
- AC_VERB_SET_GPIO_MASK, 0x00000001);
-
+ stac92xx_enable_gpio_mask(codec, gpio_mask, gpio_data);
err = stac92xx_parse_auto_config(codec, 0x1f, 0x20);
if (!err) {
if (spec->board_config < 0) {
@@ -2256,8 +2358,8 @@ static struct hda_input_mux vaio_mux = {
.num_items = 2,
.items = {
/* { "HP", 0x0 }, */
- { "Line", 0x1 },
- { "Mic", 0x2 },
+ { "Mic Jack", 0x1 },
+ { "Internal Mic", 0x2 },
{ "PCM", 0x3 },
}
};
@@ -2268,7 +2370,7 @@ static struct hda_verb vaio_init[] = {
{0x0d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? (<- 0x2) */
{0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
{0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* capture sw/vol -> 0x8 */
@@ -2284,7 +2386,7 @@ static struct hda_verb vaio_ar_init[] = {
{0x0e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, /* CD */
/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, /* Mic? */
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x2}, /* mic-sel: 0a,0d,14,02 */
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
{0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* HP */
{0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Speaker */
/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index 690ceb340644..d18a31e188a9 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -186,7 +186,12 @@ static int revo51_i2c_init(struct snd_ice1712 *ice,
#define AK_DAC(xname,xch) { .name = xname, .num_channels = xch }
static const struct snd_akm4xxx_dac_channel revo71_front[] = {
- AK_DAC("PCM Playback Volume", 2)
+ {
+ .name = "PCM Playback Volume",
+ .num_channels = 2,
+ /* front channels DAC supports muting */
+ .switch_name = "PCM Playback Switch",
+ },
};
static const struct snd_akm4xxx_dac_channel revo71_surround[] = {
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index 1d9232d2db34..170781a72292 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/firmware.h>
+#include <linux/vmalloc.h>
#include <asm/io.h>
#include <sound/core.h>
#include "mixart.h"
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 03b3a4792f73..c7621bd770a6 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -1533,7 +1533,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci,
printk(KERN_ERR " force the driver to load by "
"passing in the module parameter\n");
printk(KERN_ERR " force_ac97=1\n");
- printk(KERN_ERR " or try sb16 or cs423x drivers instead.\n");
+ printk(KERN_ERR " or try sb16, opl3sa2, or "
+ "cs423x drivers instead.\n");
err = -ENXIO;
goto __error;
}
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index bd7dbd267ed1..2de27405a0bd 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -406,7 +406,7 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652)
} else if (!frag)
return 0;
offset -= rme9652->max_jitter;
- if (offset < 0)
+ if ((int)offset < 0)
offset += period_size * 2;
} else {
if (offset > period_size + rme9652->max_jitter) {
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index a28992269f5e..6ea09df0c73a 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -2098,7 +2098,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
break;
- schedule_timeout_uninterruptible(1);
+ schedule_timeout(1);
} while (time_before(jiffies, end_time));
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -2117,7 +2117,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
chip->ac97_secondary = 1;
goto __ac97_ok2;
}
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
} while (time_before(jiffies, end_time));
/* This is ok, the most of motherboards have only one codec */
@@ -2431,7 +2431,6 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
{
struct snd_card *card;
struct via82xx *chip;
- unsigned char revision;
int chip_type = 0, card_type;
unsigned int i;
int err;
@@ -2441,18 +2440,17 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
return -ENOMEM;
card_type = pci_id->driver_data;
- pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
switch (card_type) {
case TYPE_CARD_VIA686:
strcpy(card->driver, "VIA686A");
- sprintf(card->shortname, "VIA 82C686A/B rev%x", revision);
+ sprintf(card->shortname, "VIA 82C686A/B rev%x", pci->revision);
chip_type = TYPE_VIA686;
break;
case TYPE_CARD_VIA8233:
chip_type = TYPE_VIA8233;
- sprintf(card->shortname, "VIA 823x rev%x", revision);
+ sprintf(card->shortname, "VIA 823x rev%x", pci->revision);
for (i = 0; i < ARRAY_SIZE(via823x_cards); i++) {
- if (revision == via823x_cards[i].revision) {
+ if (pci->revision == via823x_cards[i].revision) {
chip_type = via823x_cards[i].type;
strcpy(card->shortname, via823x_cards[i].name);
break;
@@ -2460,7 +2458,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
}
if (chip_type != TYPE_VIA8233A) {
if (dxs_support == VIA_DXS_AUTO)
- dxs_support = check_dxs_list(pci, revision);
+ dxs_support = check_dxs_list(pci, pci->revision);
/* force to use VIA8233 or 8233A model according to
* dxs_support module option
*/
@@ -2471,7 +2469,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
}
if (chip_type == TYPE_VIA8233A)
strcpy(card->driver, "VIA8233A");
- else if (revision >= VIA_REV_8237)
+ else if (pci->revision >= VIA_REV_8237)
strcpy(card->driver, "VIA8237"); /* no slog assignment */
else
strcpy(card->driver, "VIA8233");
@@ -2482,7 +2480,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
goto __error;
}
- if ((err = snd_via82xx_create(card, pci, chip_type, revision,
+ if ((err = snd_via82xx_create(card, pci, chip_type, pci->revision,
ac97_clock, &chip)) < 0)
goto __error;
card->private_data = chip;
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index b338e15db0d9..72425e73abae 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -983,7 +983,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
pci_read_config_byte(chip->pci, VIA_ACLINK_STAT, &pval);
if (pval & VIA_ACLINK_C00_READY) /* primary codec ready */
break;
- schedule_timeout_uninterruptible(1);
+ schedule_timeout(1);
} while (time_before(jiffies, end_time));
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
@@ -1001,7 +1001,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
chip->ac97_secondary = 1;
goto __ac97_ok2;
}
- schedule_timeout_interruptible(1);
+ schedule_timeout(1);
} while (time_before(jiffies, end_time));
/* This is ok, the most of motherboards have only one codec */
@@ -1162,7 +1162,6 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
{
struct snd_card *card;
struct via82xx_modem *chip;
- unsigned char revision;
int chip_type = 0, card_type;
unsigned int i;
int err;
@@ -1172,7 +1171,6 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
return -ENOMEM;
card_type = pci_id->driver_data;
- pci_read_config_byte(pci, PCI_REVISION_ID, &revision);
switch (card_type) {
case TYPE_CARD_VIA82XX_MODEM:
strcpy(card->driver, "VIA82XX-MODEM");
@@ -1184,7 +1182,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci,
goto __error;
}
- if ((err = snd_via82xx_create(card, pci, chip_type, revision,
+ if ((err = snd_via82xx_create(card, pci, chip_type, pci->revision,
ac97_clock, &chip)) < 0)
goto __error;
card->private_data = chip;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index ea861bceaddf..ab7a81c35705 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -2404,7 +2404,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
chip->pci = pci;
chip->irq = -1;
chip->device_id = pci->device;
- pci_read_config_byte(pci, PCI_REVISION_ID, &chip->rev);
+ chip->rev = pci->revision;
chip->reg_area_phys = pci_resource_start(pci, 0);
chip->reg_area_virt = ioremap_nocache(chip->reg_area_phys, 0x8000);
pci_set_master(pci);
diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig
index a3fb1496e4dc..cacb0b136883 100644
--- a/sound/ppc/Kconfig
+++ b/sound/ppc/Kconfig
@@ -33,3 +33,23 @@ config SND_POWERMAC_AUTO_DRC
option.
endmenu
+
+menu "ALSA PowerPC devices"
+ depends on SND!=n && ( PPC64 || PPC32 )
+
+config SND_PS3
+ tristate "PS3 Audio support"
+ depends on SND && PS3_PS3AV
+ select SND_PCM
+ default m
+ help
+ Say Y here to include support for audio on the PS3
+
+ To compile this driver as a module, choose M here: the module
+ will be called snd_ps3.
+
+config SND_PS3_DEFAULT_START_DELAY
+ int "Startup delay time in ms"
+ depends on SND_PS3
+ default "2000"
+endmenu
diff --git a/sound/ppc/Makefile b/sound/ppc/Makefile
index 4d95c652c8ca..eacee2d0675c 100644
--- a/sound/ppc/Makefile
+++ b/sound/ppc/Makefile
@@ -6,4 +6,5 @@
snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
# Toplevel Module Dependency
-obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
+obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
+obj-$(CONFIG_SND_PS3) += snd_ps3.o
diff --git a/sound/ppc/snd_ps3.c b/sound/ppc/snd_ps3.c
new file mode 100644
index 000000000000..1aa0b467599f
--- /dev/null
+++ b/sound/ppc/snd_ps3.c
@@ -0,0 +1,1125 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the Licence.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/asound.h>
+#include <sound/memalloc.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
+#include <asm/firmware.h>
+#include <linux/io.h>
+#include <asm/dma.h>
+#include <asm/lv1call.h>
+#include <asm/ps3.h>
+#include <asm/ps3av.h>
+
+#include "snd_ps3_reg.h"
+#include "snd_ps3.h"
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PS3 sound driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
+
+/* module entries */
+static int __init snd_ps3_init(void);
+static void __exit snd_ps3_exit(void);
+
+/* ALSA snd driver ops */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream);
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd);
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(struct snd_pcm_substream
+ *substream);
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params);
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream);
+
+
+/* ps3_system_bus_driver entries */
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev);
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev);
+
+/* address setup */
+static int snd_ps3_map_mmio(void);
+static void snd_ps3_unmap_mmio(void);
+static int snd_ps3_allocate_irq(void);
+static void snd_ps3_free_irq(void);
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start);
+
+/* interrupt handler */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id);
+
+
+/* set sampling rate/format */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream);
+/* take effect parameter change */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card);
+/* initialize avsetting and take it effect */
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card);
+/* setup dma */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+ enum snd_ps3_dma_filltype filltype);
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card);
+
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *, void *vaddr, int ch);
+
+
+module_init(snd_ps3_init);
+module_exit(snd_ps3_exit);
+
+/*
+ * global
+ */
+static struct snd_ps3_card_info the_card;
+
+static int snd_ps3_start_delay = CONFIG_SND_PS3_DEFAULT_START_DELAY;
+
+module_param_named(start_delay, snd_ps3_start_delay, uint, 0644);
+MODULE_PARM_DESC(start_delay, "time to insert silent data in milisec");
+
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for PS3 soundchip.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for PS3 soundchip.");
+
+
+/*
+ * PS3 audio register access
+ */
+static inline u32 read_reg(unsigned int reg)
+{
+ return in_be32(the_card.mapped_mmio_vaddr + reg);
+}
+static inline void write_reg(unsigned int reg, u32 val)
+{
+ out_be32(the_card.mapped_mmio_vaddr + reg, val);
+}
+static inline void update_reg(unsigned int reg, u32 or_val)
+{
+ u32 newval = read_reg(reg) | or_val;
+ write_reg(reg, newval);
+}
+static inline void update_mask_reg(unsigned int reg, u32 mask, u32 or_val)
+{
+ u32 newval = (read_reg(reg) & mask) | or_val;
+ write_reg(reg, newval);
+}
+
+/*
+ * ALSA defs
+ */
+const static struct snd_pcm_hardware snd_ps3_pcm_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_NONINTERLEAVED |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = (SNDRV_PCM_FMTBIT_S16_BE |
+ SNDRV_PCM_FMTBIT_S24_BE),
+ .rates = (SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000),
+ .rate_min = 44100,
+ .rate_max = 96000,
+
+ .channels_min = 2, /* stereo only */
+ .channels_max = 2,
+
+ .buffer_bytes_max = PS3_AUDIO_FIFO_SIZE * 64,
+
+ /* interrupt by four stages */
+ .period_bytes_min = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+ .period_bytes_max = PS3_AUDIO_FIFO_STAGE_SIZE * 4,
+
+ .periods_min = 16,
+ .periods_max = 32, /* buffer_size_max/ period_bytes_max */
+
+ .fifo_size = PS3_AUDIO_FIFO_SIZE
+};
+
+static struct snd_pcm_ops snd_ps3_pcm_spdif_ops =
+{
+ .open = snd_ps3_pcm_open,
+ .close = snd_ps3_pcm_close,
+ .prepare = snd_ps3_pcm_prepare,
+ .ioctl = snd_pcm_lib_ioctl,
+ .trigger = snd_ps3_pcm_trigger,
+ .pointer = snd_ps3_pcm_pointer,
+ .hw_params = snd_ps3_pcm_hw_params,
+ .hw_free = snd_ps3_pcm_hw_free
+};
+
+static int snd_ps3_verify_dma_stop(struct snd_ps3_card_info *card,
+ int count, int force_stop)
+{
+ int dma_ch, done, retries, stop_forced = 0;
+ uint32_t status;
+
+ for (dma_ch = 0; dma_ch < 8; dma_ch ++) {
+ retries = count;
+ do {
+ status = read_reg(PS3_AUDIO_KICK(dma_ch)) &
+ PS3_AUDIO_KICK_STATUS_MASK;
+ switch (status) {
+ case PS3_AUDIO_KICK_STATUS_DONE:
+ case PS3_AUDIO_KICK_STATUS_NOTIFY:
+ case PS3_AUDIO_KICK_STATUS_CLEAR:
+ case PS3_AUDIO_KICK_STATUS_ERROR:
+ done = 1;
+ break;
+ default:
+ done = 0;
+ udelay(10);
+ }
+ } while (!done && --retries);
+ if (!retries && force_stop) {
+ pr_info("%s: DMA ch %d is not stopped.",
+ __func__, dma_ch);
+ /* last resort. force to stop dma.
+ * NOTE: this cause DMA done interrupts
+ */
+ update_reg(PS3_AUDIO_CONFIG, PS3_AUDIO_CONFIG_CLEAR);
+ stop_forced = 1;
+ }
+ }
+ return stop_forced;
+}
+
+/*
+ * wait for all dma is done.
+ * NOTE: caller should reset card->running before call.
+ * If not, the interrupt handler will re-start DMA,
+ * then DMA is never stopped.
+ */
+static void snd_ps3_wait_for_dma_stop(struct snd_ps3_card_info *card)
+{
+ int stop_forced;
+ /*
+ * wait for the last dma is done
+ */
+
+ /*
+ * expected maximum DMA done time is 5.7ms + something (DMA itself).
+ * 5.7ms is from 16bit/sample 2ch 44.1Khz; the time next
+ * DMA kick event would occur.
+ */
+ stop_forced = snd_ps3_verify_dma_stop(card, 700, 1);
+
+ /*
+ * clear outstanding interrupts.
+ */
+ update_reg(PS3_AUDIO_INTR_0, 0);
+ update_reg(PS3_AUDIO_AX_IS, 0);
+
+ /*
+ *revert CLEAR bit since it will not reset automatically after DMA stop
+ */
+ if (stop_forced)
+ update_mask_reg(PS3_AUDIO_CONFIG, ~PS3_AUDIO_CONFIG_CLEAR, 0);
+ /* ensure the hardware sees changes */
+ wmb();
+}
+
+static void snd_ps3_kick_dma(struct snd_ps3_card_info *card)
+{
+
+ update_reg(PS3_AUDIO_KICK(0), PS3_AUDIO_KICK_REQUEST);
+ /* ensure the hardware sees the change */
+ wmb();
+}
+
+/*
+ * convert virtual addr to ioif bus addr.
+ */
+static dma_addr_t v_to_bus(struct snd_ps3_card_info *card,
+ void * paddr,
+ int ch)
+{
+ return card->dma_start_bus_addr[ch] +
+ (paddr - card->dma_start_vaddr[ch]);
+};
+
+
+/*
+ * increment ring buffer pointer.
+ * NOTE: caller must hold write spinlock
+ */
+static void snd_ps3_bump_buffer(struct snd_ps3_card_info *card,
+ enum snd_ps3_ch ch, size_t byte_count,
+ int stage)
+{
+ if (!stage)
+ card->dma_last_transfer_vaddr[ch] =
+ card->dma_next_transfer_vaddr[ch];
+ card->dma_next_transfer_vaddr[ch] += byte_count;
+ if ((card->dma_start_vaddr[ch] + (card->dma_buffer_size / 2)) <=
+ card->dma_next_transfer_vaddr[ch]) {
+ card->dma_next_transfer_vaddr[ch] = card->dma_start_vaddr[ch];
+ }
+}
+/*
+ * setup dmac to send data to audio and attenuate samples on the ring buffer
+ */
+static int snd_ps3_program_dma(struct snd_ps3_card_info *card,
+ enum snd_ps3_dma_filltype filltype)
+{
+ /* this dmac does not support over 4G */
+ uint32_t dma_addr;
+ int fill_stages, dma_ch, stage;
+ enum snd_ps3_ch ch;
+ uint32_t ch0_kick_event = 0; /* initialize to mute gcc */
+ void *start_vaddr;
+ unsigned long irqsave;
+ int silent = 0;
+
+ switch (filltype) {
+ case SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL:
+ silent = 1;
+ /* intentionally fall thru */
+ case SND_PS3_DMA_FILLTYPE_FIRSTFILL:
+ ch0_kick_event = PS3_AUDIO_KICK_EVENT_ALWAYS;
+ break;
+
+ case SND_PS3_DMA_FILLTYPE_SILENT_RUNNING:
+ silent = 1;
+ /* intentionally fall thru */
+ case SND_PS3_DMA_FILLTYPE_RUNNING:
+ ch0_kick_event = PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY;
+ break;
+ }
+
+ snd_ps3_verify_dma_stop(card, 700, 0);
+ fill_stages = 4;
+ spin_lock_irqsave(&card->dma_lock, irqsave);
+ for (ch = 0; ch < 2; ch++) {
+ start_vaddr = card->dma_next_transfer_vaddr[0];
+ for (stage = 0; stage < fill_stages; stage ++) {
+ dma_ch = stage * 2 + ch;
+ if (silent)
+ dma_addr = card->null_buffer_start_dma_addr;
+ else
+ dma_addr =
+ v_to_bus(card,
+ card->dma_next_transfer_vaddr[ch],
+ ch);
+
+ write_reg(PS3_AUDIO_SOURCE(dma_ch),
+ (PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY |
+ dma_addr));
+
+ /* dst: fixed to 3wire#0 */
+ if (ch == 0)
+ write_reg(PS3_AUDIO_DEST(dma_ch),
+ (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+ PS3_AUDIO_AO_3W_LDATA(0)));
+ else
+ write_reg(PS3_AUDIO_DEST(dma_ch),
+ (PS3_AUDIO_DEST_TARGET_AUDIOFIFO |
+ PS3_AUDIO_AO_3W_RDATA(0)));
+
+ /* count always 1 DMA block (1/2 stage = 128 bytes) */
+ write_reg(PS3_AUDIO_DMASIZE(dma_ch), 0);
+ /* bump pointer if needed */
+ if (!silent)
+ snd_ps3_bump_buffer(card, ch,
+ PS3_AUDIO_DMAC_BLOCK_SIZE,
+ stage);
+
+ /* kick event */
+ if (dma_ch == 0)
+ write_reg(PS3_AUDIO_KICK(dma_ch),
+ ch0_kick_event);
+ else
+ write_reg(PS3_AUDIO_KICK(dma_ch),
+ PS3_AUDIO_KICK_EVENT_AUDIO_DMA(dma_ch
+ - 1) |
+ PS3_AUDIO_KICK_REQUEST);
+ }
+ }
+ /* ensure the hardware sees the change */
+ wmb();
+ spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+ return 0;
+}
+
+/*
+ * audio mute on/off
+ * mute_on : 0 output enabled
+ * 1 mute
+ */
+static int snd_ps3_mute(int mute_on)
+{
+ return ps3av_audio_mute(mute_on);
+}
+
+/*
+ * PCM operators
+ */
+static int snd_ps3_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+ int pcm_index;
+
+ pcm_index = substream->pcm->device;
+ /* to retrieve substream/runtime in interrupt handler */
+ card->substream = substream;
+
+ runtime->hw = snd_ps3_pcm_hw;
+
+ card->start_delay = snd_ps3_start_delay;
+
+ /* mute off */
+ snd_ps3_mute(0); /* this function sleep */
+
+ snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ PS3_AUDIO_FIFO_STAGE_SIZE * 4 * 2);
+ return 0;
+};
+
+static int snd_ps3_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ size_t size;
+
+ /* alloc transport buffer */
+ size = params_buffer_bytes(hw_params);
+ snd_pcm_lib_malloc_pages(substream, size);
+ return 0;
+};
+
+static int snd_ps3_delay_to_bytes(struct snd_pcm_substream *substream,
+ unsigned int delay_ms)
+{
+ int ret;
+ int rate ;
+
+ rate = substream->runtime->rate;
+ ret = snd_pcm_format_size(substream->runtime->format,
+ rate * delay_ms / 1000)
+ * substream->runtime->channels;
+
+ pr_debug(KERN_ERR "%s: time=%d rate=%d bytes=%ld, frames=%d, ret=%d\n",
+ __func__,
+ delay_ms,
+ rate,
+ snd_pcm_format_size(substream->runtime->format, rate),
+ rate * delay_ms / 1000,
+ ret);
+
+ return ret;
+};
+
+static int snd_ps3_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+ unsigned long irqsave;
+
+ if (!snd_ps3_set_avsetting(substream)) {
+ /* some parameter changed */
+ write_reg(PS3_AUDIO_AX_IE,
+ PS3_AUDIO_AX_IE_ASOBEIE(0) |
+ PS3_AUDIO_AX_IE_ASOBUIE(0));
+ /*
+ * let SPDIF device re-lock with SPDIF signal,
+ * start with some silence
+ */
+ card->silent = snd_ps3_delay_to_bytes(substream,
+ card->start_delay) /
+ (PS3_AUDIO_FIFO_STAGE_SIZE * 4); /* every 4 times */
+ }
+
+ /* restart ring buffer pointer */
+ spin_lock_irqsave(&card->dma_lock, irqsave);
+ {
+ card->dma_buffer_size = runtime->dma_bytes;
+
+ card->dma_last_transfer_vaddr[SND_PS3_CH_L] =
+ card->dma_next_transfer_vaddr[SND_PS3_CH_L] =
+ card->dma_start_vaddr[SND_PS3_CH_L] =
+ runtime->dma_area;
+ card->dma_start_bus_addr[SND_PS3_CH_L] = runtime->dma_addr;
+
+ card->dma_last_transfer_vaddr[SND_PS3_CH_R] =
+ card->dma_next_transfer_vaddr[SND_PS3_CH_R] =
+ card->dma_start_vaddr[SND_PS3_CH_R] =
+ runtime->dma_area + (runtime->dma_bytes / 2);
+ card->dma_start_bus_addr[SND_PS3_CH_R] =
+ runtime->dma_addr + (runtime->dma_bytes / 2);
+
+ pr_debug("%s: vaddr=%p bus=%#lx\n", __func__,
+ card->dma_start_vaddr[SND_PS3_CH_L],
+ card->dma_start_bus_addr[SND_PS3_CH_L]);
+
+ }
+ spin_unlock_irqrestore(&card->dma_lock, irqsave);
+
+ /* ensure the hardware sees the change */
+ mb();
+
+ return 0;
+};
+
+static int snd_ps3_pcm_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* clear outstanding interrupts */
+ update_reg(PS3_AUDIO_AX_IS, 0);
+
+ spin_lock(&card->dma_lock);
+ {
+ card->running = 1;
+ }
+ spin_unlock(&card->dma_lock);
+
+ snd_ps3_program_dma(card,
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+ snd_ps3_kick_dma(card);
+ while (read_reg(PS3_AUDIO_KICK(7)) &
+ PS3_AUDIO_KICK_STATUS_MASK) {
+ udelay(1);
+ }
+ snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+ snd_ps3_kick_dma(card);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ spin_lock(&card->dma_lock);
+ {
+ card->running = 0;
+ }
+ spin_unlock(&card->dma_lock);
+ snd_ps3_wait_for_dma_stop(card);
+ break;
+ default:
+ break;
+
+ }
+
+ return ret;
+};
+
+/*
+ * report current pointer
+ */
+static snd_pcm_uframes_t snd_ps3_pcm_pointer(
+ struct snd_pcm_substream *substream)
+{
+ struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+ size_t bytes;
+ snd_pcm_uframes_t ret;
+
+ spin_lock(&card->dma_lock);
+ {
+ bytes = (size_t)(card->dma_last_transfer_vaddr[SND_PS3_CH_L] -
+ card->dma_start_vaddr[SND_PS3_CH_L]);
+ }
+ spin_unlock(&card->dma_lock);
+
+ ret = bytes_to_frames(substream->runtime, bytes * 2);
+
+ return ret;
+};
+
+static int snd_ps3_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ int ret;
+ ret = snd_pcm_lib_free_pages(substream);
+ return ret;
+};
+
+static int snd_ps3_pcm_close(struct snd_pcm_substream *substream)
+{
+ /* mute on */
+ snd_ps3_mute(1);
+ return 0;
+};
+
+static void snd_ps3_audio_fixup(struct snd_ps3_card_info *card)
+{
+ /*
+ * avsetting driver seems to never change the followings
+ * so, init them here once
+ */
+
+ /* no dma interrupt needed */
+ write_reg(PS3_AUDIO_INTR_EN_0, 0);
+
+ /* use every 4 buffer empty interrupt */
+ update_mask_reg(PS3_AUDIO_AX_IC,
+ PS3_AUDIO_AX_IC_AASOIMD_MASK,
+ PS3_AUDIO_AX_IC_AASOIMD_EVERY4);
+
+ /* enable 3wire clocks */
+ update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+ ~(PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED |
+ PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED),
+ 0);
+ update_reg(PS3_AUDIO_AO_3WMCTRL,
+ PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT);
+}
+
+/*
+ * av setting
+ * NOTE: calling this function may generate audio interrupt.
+ */
+static int snd_ps3_change_avsetting(struct snd_ps3_card_info *card)
+{
+ int ret, retries, i;
+ pr_debug("%s: start\n", __func__);
+
+ ret = ps3av_set_audio_mode(card->avs.avs_audio_ch,
+ card->avs.avs_audio_rate,
+ card->avs.avs_audio_width,
+ card->avs.avs_audio_format,
+ card->avs.avs_audio_source);
+ /*
+ * Reset the following unwanted settings:
+ */
+
+ /* disable all 3wire buffers */
+ update_mask_reg(PS3_AUDIO_AO_3WMCTRL,
+ ~(PS3_AUDIO_AO_3WMCTRL_ASOEN(0) |
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(1) |
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(2) |
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(3)),
+ 0);
+ wmb(); /* ensure the hardware sees the change */
+ /* wait for actually stopped */
+ retries = 1000;
+ while ((read_reg(PS3_AUDIO_AO_3WMCTRL) &
+ (PS3_AUDIO_AO_3WMCTRL_ASORUN(0) |
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(1) |
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(2) |
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(3))) &&
+ --retries) {
+ udelay(1);
+ }
+
+ /* reset buffer pointer */
+ for (i = 0; i < 4; i++) {
+ update_reg(PS3_AUDIO_AO_3WCTRL(i),
+ PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET);
+ udelay(10);
+ }
+ wmb(); /* ensure the hardware actually start resetting */
+
+ /* enable 3wire#0 buffer */
+ update_reg(PS3_AUDIO_AO_3WMCTRL, PS3_AUDIO_AO_3WMCTRL_ASOEN(0));
+
+
+ /* In 24bit mode,ALSA inserts a zero byte at first byte of per sample */
+ update_mask_reg(PS3_AUDIO_AO_3WCTRL(0),
+ ~PS3_AUDIO_AO_3WCTRL_ASODF,
+ PS3_AUDIO_AO_3WCTRL_ASODF_LSB);
+ update_mask_reg(PS3_AUDIO_AO_SPDCTRL(0),
+ ~PS3_AUDIO_AO_SPDCTRL_SPODF,
+ PS3_AUDIO_AO_SPDCTRL_SPODF_LSB);
+ /* ensure all the setting above is written back to register */
+ wmb();
+ /* avsetting driver altered AX_IE, caller must reset it if you want */
+ pr_debug("%s: end\n", __func__);
+ return ret;
+}
+
+static int snd_ps3_init_avsetting(struct snd_ps3_card_info *card)
+{
+ int ret;
+ pr_debug("%s: start\n", __func__);
+ card->avs.avs_audio_ch = PS3AV_CMD_AUDIO_NUM_OF_CH_2;
+ card->avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+ card->avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+ card->avs.avs_audio_format = PS3AV_CMD_AUDIO_FORMAT_PCM;
+ card->avs.avs_audio_source = PS3AV_CMD_AUDIO_SOURCE_SERIAL;
+
+ ret = snd_ps3_change_avsetting(card);
+
+ snd_ps3_audio_fixup(card);
+
+ /* to start to generate SPDIF signal, fill data */
+ snd_ps3_program_dma(card, SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+ snd_ps3_kick_dma(card);
+ pr_debug("%s: end\n", __func__);
+ return ret;
+}
+
+/*
+ * set sampling rate according to the substream
+ */
+static int snd_ps3_set_avsetting(struct snd_pcm_substream *substream)
+{
+ struct snd_ps3_card_info *card = snd_pcm_substream_chip(substream);
+ struct snd_ps3_avsetting_info avs;
+
+ avs = card->avs;
+
+ pr_debug("%s: called freq=%d width=%d\n", __func__,
+ substream->runtime->rate,
+ snd_pcm_format_width(substream->runtime->format));
+
+ pr_debug("%s: before freq=%d width=%d\n", __func__,
+ card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+ /* sample rate */
+ switch (substream->runtime->rate) {
+ case 44100:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_44K;
+ break;
+ case 48000:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_48K;
+ break;
+ case 88200:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_88K;
+ break;
+ case 96000:
+ avs.avs_audio_rate = PS3AV_CMD_AUDIO_FS_96K;
+ break;
+ default:
+ pr_info("%s: invalid rate %d\n", __func__,
+ substream->runtime->rate);
+ return 1;
+ }
+
+ /* width */
+ switch (snd_pcm_format_width(substream->runtime->format)) {
+ case 16:
+ avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_16;
+ break;
+ case 24:
+ avs.avs_audio_width = PS3AV_CMD_AUDIO_WORD_BITS_24;
+ break;
+ default:
+ pr_info("%s: invalid width %d\n", __func__,
+ snd_pcm_format_width(substream->runtime->format));
+ return 1;
+ }
+
+ if ((card->avs.avs_audio_width != avs.avs_audio_width) ||
+ (card->avs.avs_audio_rate != avs.avs_audio_rate)) {
+ card->avs = avs;
+ snd_ps3_change_avsetting(card);
+
+ pr_debug("%s: after freq=%d width=%d\n", __func__,
+ card->avs.avs_audio_rate, card->avs.avs_audio_width);
+
+ return 0;
+ } else
+ return 1;
+}
+
+
+
+static int snd_ps3_map_mmio(void)
+{
+ the_card.mapped_mmio_vaddr =
+ ioremap(the_card.ps3_dev->m_region->bus_addr,
+ the_card.ps3_dev->m_region->len);
+
+ if (!the_card.mapped_mmio_vaddr) {
+ pr_info("%s: ioremap 0 failed p=%#lx l=%#lx \n",
+ __func__, the_card.ps3_dev->m_region->lpar_addr,
+ the_card.ps3_dev->m_region->len);
+ return -ENXIO;
+ }
+
+ return 0;
+};
+
+static void snd_ps3_unmap_mmio(void)
+{
+ iounmap(the_card.mapped_mmio_vaddr);
+ the_card.mapped_mmio_vaddr = NULL;
+}
+
+static int snd_ps3_allocate_irq(void)
+{
+ int ret;
+ u64 lpar_addr, lpar_size;
+ u64 __iomem *mapped;
+
+ /* FIXME: move this to device_init (H/W probe) */
+
+ /* get irq outlet */
+ ret = lv1_gpu_device_map(1, &lpar_addr, &lpar_size);
+ if (ret) {
+ pr_info("%s: device map 1 failed %d\n", __func__,
+ ret);
+ return -ENXIO;
+ }
+
+ mapped = ioremap(lpar_addr, lpar_size);
+ if (!mapped) {
+ pr_info("%s: ioremap 1 failed \n", __func__);
+ return -ENXIO;
+ }
+
+ the_card.audio_irq_outlet = in_be64(mapped);
+
+ iounmap(mapped);
+ ret = lv1_gpu_device_unmap(1);
+ if (ret)
+ pr_info("%s: unmap 1 failed\n", __func__);
+
+ /* irq */
+ ret = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY,
+ the_card.audio_irq_outlet,
+ &the_card.irq_no);
+ if (ret) {
+ pr_info("%s:ps3_alloc_irq failed (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED,
+ SND_PS3_DRIVER_NAME, &the_card);
+ if (ret) {
+ pr_info("%s: request_irq failed (%d)\n", __func__, ret);
+ goto cleanup_irq;
+ }
+
+ return 0;
+
+ cleanup_irq:
+ ps3_irq_plug_destroy(the_card.irq_no);
+ return ret;
+};
+
+static void snd_ps3_free_irq(void)
+{
+ free_irq(the_card.irq_no, &the_card);
+ ps3_irq_plug_destroy(the_card.irq_no);
+}
+
+static void snd_ps3_audio_set_base_addr(uint64_t ioaddr_start)
+{
+ uint64_t val;
+ int ret;
+
+ val = (ioaddr_start & (0x0fUL << 32)) >> (32 - 20) |
+ (0x03UL << 24) |
+ (0x0fUL << 12) |
+ (PS3_AUDIO_IOID);
+
+ ret = lv1_gpu_attribute(0x100, 0x007, val, 0, 0);
+ if (ret)
+ pr_info("%s: gpu_attribute failed %d\n", __func__,
+ ret);
+}
+
+static int __init snd_ps3_driver_probe(struct ps3_system_bus_device *dev)
+{
+ int ret;
+ u64 lpar_addr, lpar_size;
+
+ BUG_ON(!firmware_has_feature(FW_FEATURE_PS3_LV1));
+ BUG_ON(dev->match_id != PS3_MATCH_ID_SOUND);
+
+ the_card.ps3_dev = dev;
+
+ ret = ps3_open_hv_device(dev);
+
+ if (ret)
+ return -ENXIO;
+
+ /* setup MMIO */
+ ret = lv1_gpu_device_map(2, &lpar_addr, &lpar_size);
+ if (ret) {
+ pr_info("%s: device map 2 failed %d\n", __func__, ret);
+ goto clean_open;
+ }
+ ps3_mmio_region_init(dev, dev->m_region, lpar_addr, lpar_size,
+ PAGE_SHIFT);
+
+ ret = snd_ps3_map_mmio();
+ if (ret)
+ goto clean_dev_map;
+
+ /* setup DMA area */
+ ps3_dma_region_init(dev, dev->d_region,
+ PAGE_SHIFT, /* use system page size */
+ 0, /* dma type; not used */
+ NULL,
+ _ALIGN_UP(SND_PS3_DMA_REGION_SIZE, PAGE_SIZE));
+ dev->d_region->ioid = PS3_AUDIO_IOID;
+
+ ret = ps3_dma_region_create(dev->d_region);
+ if (ret) {
+ pr_info("%s: region_create\n", __func__);
+ goto clean_mmio;
+ }
+
+ snd_ps3_audio_set_base_addr(dev->d_region->bus_addr);
+
+ /* CONFIG_SND_PS3_DEFAULT_START_DELAY */
+ the_card.start_delay = snd_ps3_start_delay;
+
+ /* irq */
+ if (snd_ps3_allocate_irq()) {
+ ret = -ENXIO;
+ goto clean_dma_region;
+ }
+
+ /* create card instance */
+ the_card.card = snd_card_new(index, id, THIS_MODULE, 0);
+ if (!the_card.card) {
+ ret = -ENXIO;
+ goto clean_irq;
+ }
+
+ strcpy(the_card.card->driver, "PS3");
+ strcpy(the_card.card->shortname, "PS3");
+ strcpy(the_card.card->longname, "PS3 sound");
+ /* create PCM devices instance */
+ /* NOTE:this driver works assuming pcm:substream = 1:1 */
+ ret = snd_pcm_new(the_card.card,
+ "SPDIF",
+ 0, /* instance index, will be stored pcm.device*/
+ 1, /* output substream */
+ 0, /* input substream */
+ &(the_card.pcm));
+ if (ret)
+ goto clean_card;
+
+ the_card.pcm->private_data = &the_card;
+ strcpy(the_card.pcm->name, "SPDIF");
+
+ /* set pcm ops */
+ snd_pcm_set_ops(the_card.pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_ps3_pcm_spdif_ops);
+
+ the_card.pcm->info_flags = SNDRV_PCM_INFO_NONINTERLEAVED;
+ /* pre-alloc PCM DMA buffer*/
+ ret = snd_pcm_lib_preallocate_pages_for_all(the_card.pcm,
+ SNDRV_DMA_TYPE_DEV,
+ &dev->core,
+ SND_PS3_PCM_PREALLOC_SIZE,
+ SND_PS3_PCM_PREALLOC_SIZE);
+ if (ret < 0) {
+ pr_info("%s: prealloc failed\n", __func__);
+ goto clean_card;
+ }
+
+ /*
+ * allocate null buffer
+ * its size should be lager than PS3_AUDIO_FIFO_STAGE_SIZE * 2
+ * PAGE_SIZE is enogh
+ */
+ if (!(the_card.null_buffer_start_vaddr =
+ dma_alloc_coherent(&the_card.ps3_dev->core,
+ PAGE_SIZE,
+ &the_card.null_buffer_start_dma_addr,
+ GFP_KERNEL))) {
+ pr_info("%s: nullbuffer alloc failed\n", __func__);
+ goto clean_preallocate;
+ }
+ pr_debug("%s: null vaddr=%p dma=%#lx\n", __func__,
+ the_card.null_buffer_start_vaddr,
+ the_card.null_buffer_start_dma_addr);
+ /* set default sample rate/word width */
+ snd_ps3_init_avsetting(&the_card);
+
+ /* register the card */
+ ret = snd_card_register(the_card.card);
+ if (ret < 0)
+ goto clean_dma_map;
+
+ pr_info("%s started. start_delay=%dms\n",
+ the_card.card->longname, the_card.start_delay);
+ return 0;
+
+clean_dma_map:
+ dma_free_coherent(&the_card.ps3_dev->core,
+ PAGE_SIZE,
+ the_card.null_buffer_start_vaddr,
+ the_card.null_buffer_start_dma_addr);
+clean_preallocate:
+ snd_pcm_lib_preallocate_free_for_all(the_card.pcm);
+clean_card:
+ snd_card_free(the_card.card);
+clean_irq:
+ snd_ps3_free_irq();
+clean_dma_region:
+ ps3_dma_region_free(dev->d_region);
+clean_mmio:
+ snd_ps3_unmap_mmio();
+clean_dev_map:
+ lv1_gpu_device_unmap(2);
+clean_open:
+ ps3_close_hv_device(dev);
+ /*
+ * there is no destructor function to pcm.
+ * midlayer automatically releases if the card removed
+ */
+ return ret;
+}; /* snd_ps3_probe */
+
+/* called when module removal */
+static int snd_ps3_driver_remove(struct ps3_system_bus_device *dev)
+{
+ int ret;
+ pr_info("%s:start id=%d\n", __func__, dev->match_id);
+ if (dev->match_id != PS3_MATCH_ID_SOUND)
+ return -ENXIO;
+
+ /*
+ * ctl and preallocate buffer will be freed in
+ * snd_card_free
+ */
+ ret = snd_card_free(the_card.card);
+ if (ret)
+ pr_info("%s: ctl freecard=%d\n", __func__, ret);
+
+ dma_free_coherent(&dev->core,
+ PAGE_SIZE,
+ the_card.null_buffer_start_vaddr,
+ the_card.null_buffer_start_dma_addr);
+
+ ps3_dma_region_free(dev->d_region);
+
+ snd_ps3_free_irq();
+ snd_ps3_unmap_mmio();
+
+ lv1_gpu_device_unmap(2);
+ ps3_close_hv_device(dev);
+ pr_info("%s:end id=%d\n", __func__, dev->match_id);
+ return 0;
+} /* snd_ps3_remove */
+
+static struct ps3_system_bus_driver snd_ps3_bus_driver_info = {
+ .match_id = PS3_MATCH_ID_SOUND,
+ .probe = snd_ps3_driver_probe,
+ .remove = snd_ps3_driver_remove,
+ .shutdown = snd_ps3_driver_remove,
+ .core = {
+ .name = SND_PS3_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t snd_ps3_interrupt(int irq, void *dev_id)
+{
+
+ uint32_t port_intr;
+ int underflow_occured = 0;
+ struct snd_ps3_card_info *card = dev_id;
+
+ if (!card->running) {
+ update_reg(PS3_AUDIO_AX_IS, 0);
+ update_reg(PS3_AUDIO_INTR_0, 0);
+ return IRQ_HANDLED;
+ }
+
+ port_intr = read_reg(PS3_AUDIO_AX_IS);
+ /*
+ *serial buffer empty detected (every 4 times),
+ *program next dma and kick it
+ */
+ if (port_intr & PS3_AUDIO_AX_IE_ASOBEIE(0)) {
+ write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBEIE(0));
+ if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+ write_reg(PS3_AUDIO_AX_IS, port_intr);
+ underflow_occured = 1;
+ }
+ if (card->silent) {
+ /* we are still in silent time */
+ snd_ps3_program_dma(card,
+ (underflow_occured) ?
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL :
+ SND_PS3_DMA_FILLTYPE_SILENT_RUNNING);
+ snd_ps3_kick_dma(card);
+ card->silent --;
+ } else {
+ snd_ps3_program_dma(card,
+ (underflow_occured) ?
+ SND_PS3_DMA_FILLTYPE_FIRSTFILL :
+ SND_PS3_DMA_FILLTYPE_RUNNING);
+ snd_ps3_kick_dma(card);
+ snd_pcm_period_elapsed(card->substream);
+ }
+ } else if (port_intr & PS3_AUDIO_AX_IE_ASOBUIE(0)) {
+ write_reg(PS3_AUDIO_AX_IS, PS3_AUDIO_AX_IE_ASOBUIE(0));
+ /*
+ * serial out underflow, but buffer empty not detected.
+ * in this case, fill fifo with 0 to recover. After
+ * filling dummy data, serial automatically start to
+ * consume them and then will generate normal buffer
+ * empty interrupts.
+ * If both buffer underflow and buffer empty are occured,
+ * it is better to do nomal data transfer than empty one
+ */
+ snd_ps3_program_dma(card,
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+ snd_ps3_kick_dma(card);
+ snd_ps3_program_dma(card,
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL);
+ snd_ps3_kick_dma(card);
+ }
+ /* clear interrupt cause */
+ return IRQ_HANDLED;
+};
+
+/*
+ * module/subsystem initialize/terminate
+ */
+static int __init snd_ps3_init(void)
+{
+ int ret;
+
+ if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+ return -ENXIO;
+
+ memset(&the_card, 0, sizeof(the_card));
+ spin_lock_init(&the_card.dma_lock);
+
+ /* register systembus DRIVER, this calls our probe() func */
+ ret = ps3_system_bus_driver_register(&snd_ps3_bus_driver_info);
+
+ return ret;
+}
+
+static void __exit snd_ps3_exit(void)
+{
+ ps3_system_bus_driver_unregister(&snd_ps3_bus_driver_info);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_SOUND);
diff --git a/sound/ppc/snd_ps3.h b/sound/ppc/snd_ps3.h
new file mode 100644
index 000000000000..4b7e6fbbe500
--- /dev/null
+++ b/sound/ppc/snd_ps3.h
@@ -0,0 +1,135 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * All rights reserved.
+ * Copyright 2006, 2007 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the Licence.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined(_SND_PS3_H_)
+#define _SND_PS3_H_
+
+#include <linux/irqreturn.h>
+
+#define SND_PS3_DRIVER_NAME "snd_ps3"
+
+enum snd_ps3_out_channel {
+ SND_PS3_OUT_SPDIF_0,
+ SND_PS3_OUT_SPDIF_1,
+ SND_PS3_OUT_SERIAL_0,
+ SND_PS3_OUT_DEVS
+};
+
+enum snd_ps3_dma_filltype {
+ SND_PS3_DMA_FILLTYPE_FIRSTFILL,
+ SND_PS3_DMA_FILLTYPE_RUNNING,
+ SND_PS3_DMA_FILLTYPE_SILENT_FIRSTFILL,
+ SND_PS3_DMA_FILLTYPE_SILENT_RUNNING
+};
+
+enum snd_ps3_ch {
+ SND_PS3_CH_L = 0,
+ SND_PS3_CH_R = 1,
+ SND_PS3_CH_MAX = 2
+};
+
+struct snd_ps3_avsetting_info {
+ uint32_t avs_audio_ch; /* fixed */
+ uint32_t avs_audio_rate;
+ uint32_t avs_audio_width;
+ uint32_t avs_audio_format; /* fixed */
+ uint32_t avs_audio_source; /* fixed */
+};
+/*
+ * PS3 audio 'card' instance
+ * there should be only ONE hardware.
+ */
+struct snd_ps3_card_info {
+ struct ps3_system_bus_device *ps3_dev;
+ struct snd_card *card;
+
+ struct snd_pcm *pcm;
+ struct snd_pcm_substream *substream;
+
+ /* hvc info */
+ u64 audio_lpar_addr;
+ u64 audio_lpar_size;
+
+ /* registers */
+ void __iomem *mapped_mmio_vaddr;
+
+ /* irq */
+ u64 audio_irq_outlet;
+ unsigned int irq_no;
+
+ /* remember avsetting */
+ struct snd_ps3_avsetting_info avs;
+
+ /* dma buffer management */
+ spinlock_t dma_lock;
+ /* dma_lock start */
+ void * dma_start_vaddr[2]; /* 0 for L, 1 for R */
+ dma_addr_t dma_start_bus_addr[2];
+ size_t dma_buffer_size;
+ void * dma_last_transfer_vaddr[2];
+ void * dma_next_transfer_vaddr[2];
+ int silent;
+ /* dma_lock end */
+
+ int running;
+
+ /* null buffer */
+ void *null_buffer_start_vaddr;
+ dma_addr_t null_buffer_start_dma_addr;
+
+ /* start delay */
+ unsigned int start_delay;
+
+};
+
+
+/* PS3 audio DMAC block size in bytes */
+#define PS3_AUDIO_DMAC_BLOCK_SIZE (128)
+/* one stage (stereo) of audio FIFO in bytes */
+#define PS3_AUDIO_FIFO_STAGE_SIZE (256)
+/* how many stages the fifo have */
+#define PS3_AUDIO_FIFO_STAGE_COUNT (8)
+/* fifo size 128 bytes * 8 stages * stereo (2ch) */
+#define PS3_AUDIO_FIFO_SIZE \
+ (PS3_AUDIO_FIFO_STAGE_SIZE * PS3_AUDIO_FIFO_STAGE_COUNT)
+
+/* PS3 audio DMAC max block count in one dma shot = 128 (0x80) blocks*/
+#define PS3_AUDIO_DMAC_MAX_BLOCKS (PS3_AUDIO_DMASIZE_BLOCKS_MASK + 1)
+
+#define PS3_AUDIO_NORMAL_DMA_START_CH (0)
+#define PS3_AUDIO_NORMAL_DMA_COUNT (8)
+#define PS3_AUDIO_NULL_DMA_START_CH \
+ (PS3_AUDIO_NORMAL_DMA_START_CH + PS3_AUDIO_NORMAL_DMA_COUNT)
+#define PS3_AUDIO_NULL_DMA_COUNT (2)
+
+#define SND_PS3_MAX_VOL (0x0F)
+#define SND_PS3_MIN_VOL (0x00)
+#define SND_PS3_MIN_ATT SND_PS3_MIN_VOL
+#define SND_PS3_MAX_ATT SND_PS3_MAX_VOL
+
+#define SND_PS3_PCM_PREALLOC_SIZE \
+ (PS3_AUDIO_DMAC_BLOCK_SIZE * PS3_AUDIO_DMAC_MAX_BLOCKS * 4)
+
+#define SND_PS3_DMA_REGION_SIZE \
+ (SND_PS3_PCM_PREALLOC_SIZE + PAGE_SIZE)
+
+#define PS3_AUDIO_IOID (1UL)
+
+#endif /* _SND_PS3_H_ */
diff --git a/sound/ppc/snd_ps3_reg.h b/sound/ppc/snd_ps3_reg.h
new file mode 100644
index 000000000000..03fdee4aaaf2
--- /dev/null
+++ b/sound/ppc/snd_ps3_reg.h
@@ -0,0 +1,891 @@
+/*
+ * Audio support for PS3
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2006, 2007 Sony Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * interrupt / configure registers
+ */
+
+#define PS3_AUDIO_INTR_0 (0x00000100)
+#define PS3_AUDIO_INTR_EN_0 (0x00000140)
+#define PS3_AUDIO_CONFIG (0x00000200)
+
+/*
+ * DMAC registers
+ * n:0..9
+ */
+#define PS3_AUDIO_DMAC_REGBASE(x) (0x0000210 + 0x20 * (x))
+
+#define PS3_AUDIO_KICK(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x00)
+#define PS3_AUDIO_SOURCE(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x04)
+#define PS3_AUDIO_DEST(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x08)
+#define PS3_AUDIO_DMASIZE(n) (PS3_AUDIO_DMAC_REGBASE(n) + 0x0C)
+
+/*
+ * mute control
+ */
+#define PS3_AUDIO_AX_MCTRL (0x00004000)
+#define PS3_AUDIO_AX_ISBP (0x00004004)
+#define PS3_AUDIO_AX_AOBP (0x00004008)
+#define PS3_AUDIO_AX_IC (0x00004010)
+#define PS3_AUDIO_AX_IE (0x00004014)
+#define PS3_AUDIO_AX_IS (0x00004018)
+
+/*
+ * three wire serial
+ * n:0..3
+ */
+#define PS3_AUDIO_AO_MCTRL (0x00006000)
+#define PS3_AUDIO_AO_3WMCTRL (0x00006004)
+
+#define PS3_AUDIO_AO_3WCTRL(n) (0x00006200 + 0x200 * (n))
+
+/*
+ * S/PDIF
+ * n:0..1
+ * x:0..11
+ * y:0..5
+ */
+#define PS3_AUDIO_AO_SPD_REGBASE(n) (0x00007200 + 0x200 * (n))
+
+#define PS3_AUDIO_AO_SPDCTRL(n) \
+ (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x00)
+#define PS3_AUDIO_AO_SPDUB(n, x) \
+ (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x04 + 0x04 * (x))
+#define PS3_AUDIO_AO_SPDCS(n, y) \
+ (PS3_AUDIO_AO_SPD_REGBASE(n) + 0x34 + 0x04 * (y))
+
+
+/*
+ PS3_AUDIO_INTR_0 register tells an interrupt handler which audio
+ DMA channel triggered the interrupt. The interrupt status for a channel
+ can be cleared by writing a '1' to the corresponding bit. A new interrupt
+ cannot be generated until the previous interrupt has been cleared.
+
+ Note that the status reported by PS3_AUDIO_INTR_0 is independent of the
+ value of PS3_AUDIO_INTR_EN_0.
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+#define PS3_AUDIO_INTR_0_CHAN(n) (1 << ((n) * 2))
+#define PS3_AUDIO_INTR_0_CHAN9 PS3_AUDIO_INTR_0_CHAN(9)
+#define PS3_AUDIO_INTR_0_CHAN8 PS3_AUDIO_INTR_0_CHAN(8)
+#define PS3_AUDIO_INTR_0_CHAN7 PS3_AUDIO_INTR_0_CHAN(7)
+#define PS3_AUDIO_INTR_0_CHAN6 PS3_AUDIO_INTR_0_CHAN(6)
+#define PS3_AUDIO_INTR_0_CHAN5 PS3_AUDIO_INTR_0_CHAN(5)
+#define PS3_AUDIO_INTR_0_CHAN4 PS3_AUDIO_INTR_0_CHAN(4)
+#define PS3_AUDIO_INTR_0_CHAN3 PS3_AUDIO_INTR_0_CHAN(3)
+#define PS3_AUDIO_INTR_0_CHAN2 PS3_AUDIO_INTR_0_CHAN(2)
+#define PS3_AUDIO_INTR_0_CHAN1 PS3_AUDIO_INTR_0_CHAN(1)
+#define PS3_AUDIO_INTR_0_CHAN0 PS3_AUDIO_INTR_0_CHAN(0)
+
+/*
+ The PS3_AUDIO_INTR_EN_0 register specifies which DMA channels can generate
+ an interrupt to the PU. Each bit of PS3_AUDIO_INTR_EN_0 is ANDed with the
+ corresponding bit in PS3_AUDIO_INTR_0. The resulting bits are OR'd together
+ to generate the Audio interrupt.
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C|0|C| INTR_EN_0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+ Bit assignments are same as PS3_AUDIO_INTR_0
+*/
+
+/*
+ PS3_AUDIO_CONFIG
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 0|0 0 0 0 0 0 0 C|0 0 0 0 0 0 0 0| CONFIG
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/* The CLEAR field cancels all pending transfers, and stops any running DMA
+ transfers. Any interrupts associated with the canceled transfers
+ will occur as if the transfer had finished.
+ Since this bit is designed to recover from DMA related issues
+ which are caused by unpredictable situations, it is prefered to wait
+ for normal DMA transfer end without using this bit.
+*/
+#define PS3_AUDIO_CONFIG_CLEAR (1 << 8) /* RWIVF */
+
+/*
+ PS3_AUDIO_AX_MCTRL: Audio Port Mute Control Register
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|A|A|0 0 0 0 0 0 0|S|S|A|A|A|A| AX_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/* 3 Wire Audio Serial Output Channel Mutes (0..3) */
+#define PS3_AUDIO_AX_MCTRL_ASOMT(n) (1 << (3 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO3MT (1 << 0) /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO2MT (1 << 1) /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO1MT (1 << 2) /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_ASO0MT (1 << 3) /* RWIVF */
+
+/* S/PDIF mutes (0,1)*/
+#define PS3_AUDIO_AX_MCTRL_SPOMT(n) (1 << (5 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO1MT (1 << 4) /* RWIVF */
+#define PS3_AUDIO_AX_MCTRL_SPO0MT (1 << 5) /* RWIVF */
+
+/* All 3 Wire Serial Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AASOMT (1 << 13) /* RWIVF */
+
+/* All S/PDIF Mute */
+#define PS3_AUDIO_AX_MCTRL_ASPOMT (1 << 14) /* RWIVF */
+
+/* All Audio Outputs Mute */
+#define PS3_AUDIO_AX_MCTRL_AAOMT (1 << 15) /* RWIVF */
+
+/*
+ S/PDIF Outputs Buffer Read/Write Pointer Register
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B|0 0 0 0 0 0 0 0|0|SPO0B|0|SPO1B| AX_ISBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+ S/PDIF Output Channel Read Buffer Numbers
+ Buffer number is value of field.
+ Indicates current read access buffer ID from Audio Data
+ Transfer controller of S/PDIF Output
+*/
+
+#define PS3_AUDIO_AX_ISBP_SPOBRN_MASK(n) (0x7 << 4 * (1 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BRN_MASK (0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BRN_MASK (0x7 << 4) /* R-IUF */
+
+/*
+S/PDIF Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_ISBP_SPOBWN_MASK(n) (0x7 << 4 * (5 - (n))) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO1BWN_MASK (0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_ISBP_SPO0BWN_MASK (0x7 << 20) /* R-IUF */
+
+/*
+ 3 Wire Audio Serial Outputs Buffer Read/Write
+ Pointer Register
+ Buffer number is value of field
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B|0|ASO0B|0|ASO1B|0|ASO2B|0|ASO3B| AX_AOBP
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Read Numbers
+Indicates current read access buffer Id from Audio Data Transfer
+Controller of 3 Wire Audio Serial Output Channels
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBRN_MASK(n) (0x7 << 4 * (3 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BRN_MASK (0x7 << 0) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BRN_MASK (0x7 << 4) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BRN_MASK (0x7 << 8) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BRN_MASK (0x7 << 12) /* R-IUF */
+
+/*
+3 Wire Audio Serial Output Channel Buffer Write Numbers
+Indicates current write access buffer ID from bus master.
+*/
+#define PS3_AUDIO_AX_AOBP_ASOBWN_MASK(n) (0x7 << 4 * (7 - (n))) /* R-IUF */
+
+#define PS3_AUDIO_AX_AOBP_ASO3BWN_MASK (0x7 << 16) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO2BWN_MASK (0x7 << 20) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO1BWN_MASK (0x7 << 24) /* R-IUF */
+#define PS3_AUDIO_AX_AOBP_ASO0BWN_MASK (0x7 << 28) /* R-IUF */
+
+
+
+/*
+Audio Port Interrupt Condition Register
+For the fields in this register, the following values apply:
+0 = Interrupt is generated every interrupt event.
+1 = Interrupt is generated every 2 interrupt events.
+2 = Interrupt is generated every 4 interrupt events.
+3 = Reserved
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|0 0|SPO|0 0|SPO|0 0|AAS|0 0 0 0 0 0 0 0 0 0 0 0| AX_IC
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+All 3-Wire Audio Serial Outputs Interrupt Mode
+Configures the Interrupt and Signal Notification
+condition of all 3-wire Audio Serial Outputs.
+*/
+#define PS3_AUDIO_AX_IC_AASOIMD_MASK (0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY1 (0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY2 (0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AX_IC_AASOIMD_EVERY4 (0x2 << 12) /* RW--V */
+
+/*
+S/PDIF Output Channel Interrupt Modes
+Configures the Interrupt and signal Notification
+conditions of S/PDIF output channels.
+*/
+#define PS3_AUDIO_AX_IC_SPO1IMD_MASK (0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY1 (0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY2 (0x1 << 16) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO1IMD_EVERY4 (0x2 << 16) /* RW--V */
+
+#define PS3_AUDIO_AX_IC_SPO0IMD_MASK (0x3 << 20) /* RWIVF */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY1 (0x0 << 20) /* RWI-V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY2 (0x1 << 20) /* RW--V */
+#define PS3_AUDIO_AX_IC_SPO0IMD_EVERY4 (0x2 << 20) /* RW--V */
+
+/*
+Audio Port interrupt Enable Register
+Configures whether to enable or disable each Interrupt Generation.
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+
+/*
+3 Wire Audio Serial Output Channel Buffer Underflow
+Interrupt Enables
+Select enable/disable of Buffer Underflow Interrupts for
+3-Wire Audio Serial Output Channels
+DISABLED=Interrupt generation disabled.
+*/
+#define PS3_AUDIO_AX_IE_ASOBUIE(n) (1 << (3 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BUIE (1 << 0) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BUIE (1 << 1) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BUIE (1 << 2) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BUIE (1 << 3) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Underflow Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBUIE(n) (1 << (7 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BUIE (1 << 6) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BUIE (1 << 7) /* RWIVF */
+
+/* S/PDIF Output Channel One Block Transfer Completion Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBTCIE(n) (1 << (11 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BTCIE (1 << 10) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BTCIE (1 << 11) /* RWIVF */
+
+/* 3-Wire Audio Serial Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_ASOBEIE(n) (1 << (19 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO3BEIE (1 << 16) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO2BEIE (1 << 17) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO1BEIE (1 << 18) /* RWIVF */
+#define PS3_AUDIO_AX_IE_ASO0BEIE (1 << 19) /* RWIVF */
+
+/* S/PDIF Output Channel Buffer Empty Interrupt Enables */
+
+#define PS3_AUDIO_AX_IE_SPOBEIE(n) (1 << (23 - (n))) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO1BEIE (1 << 22) /* RWIVF */
+#define PS3_AUDIO_AX_IE_SPO0BEIE (1 << 23) /* RWIVF */
+
+/*
+Audio Port Interrupt Status Register
+Indicates Interrupt status, which interrupt has occured, and can clear
+each interrupt in this register.
+Writing 1b to a field containing 1b clears field and de-asserts interrupt.
+Writing 0b to a field has no effect.
+Field vaules are the following:
+0 - Interrupt hasn't occured.
+1 - Interrupt has occured.
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0|S|S|0 0|A|A|A|A|0 0 0 0|S|S|0 0|S|S|0 0|A|A|A|A| AX_IS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+ Bit assignment are same as AX_IE
+*/
+
+/*
+Audio Output Master Control Register
+Configures Master Clock and other master Audio Output Settings
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0|SCKSE|0|SCKSE| MR0 | MR1 |MCL|MCL|0 0 0 0|0 0 0 0 0 0 0 0| AO_MCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+MCLK Output Control
+Controls mclko[1] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with scksel1 by mr1
+2 - Reserved
+3 - Reserved
+*/
+
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_MASK (0x3 << 12) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_DISABLED (0x0 << 12) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_ENABLED (0x1 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD2 (0x2 << 12) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC1_RESVD3 (0x3 << 12) /* RW--V */
+
+/*
+MCLK Output Control
+Controls mclko[0] output.
+0 - Disable output (fixed at High)
+1 - Output clock produced by clock selected
+with SCKSEL0 by MR0
+2 - Reserved
+3 - Reserved
+*/
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_MASK (0x3 << 14) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_DISABLED (0x0 << 14) /* RWI-V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_ENABLED (0x1 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD2 (0x2 << 14) /* RW--V */
+#define PS3_AUDIO_AO_MCTRL_MCLKC0_RESVD3 (0x3 << 14) /* RW--V */
+/*
+Master Clock Rate 1
+Sets the divide ration of Master Clock1 (clock output from
+mclko[1] for the input clock selected by scksel1.
+*/
+#define PS3_AUDIO_AO_MCTRL_MR1_MASK (0xf << 16)
+#define PS3_AUDIO_AO_MCTRL_MR1_DEFAULT (0x0 << 16) /* RWI-V */
+/*
+Master Clock Rate 0
+Sets the divide ratio of Master Clock0 (clock output from
+mclko[0] for the input clock selected by scksel0).
+*/
+#define PS3_AUDIO_AO_MCTRL_MR0_MASK (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_MR0_DEFAULT (0x0 << 20) /* RWI-V */
+/*
+System Clock Select 0/1
+Selects the system clock to be used as Master Clock 0/1
+Input the system clock that is appropriate for the sampling
+rate.
+*/
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_MASK (0x7 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL1_DEFAULT (0x2 << 24) /* RWI-V */
+
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_MASK (0x7 << 28) /* RWIVF */
+#define PS3_AUDIO_AO_MCTRL_SCKSEL0_DEFAULT (0x2 << 28) /* RWI-V */
+
+
+/*
+3-Wire Audio Output Master Control Register
+Configures clock, 3-Wire Audio Serial Output Enable, and
+other 3-Wire Audio Serial Output Master Settings
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |A|A|A|A|0 0 0|A| ASOSR |0 0 0 0|A|A|A|A|A|A|0|1|0 0 0 0 0 0 0 0| AO_3WMCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+/*
+LRCKO Polarity
+0 - Reserved
+1 - default
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK (1 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOPLRCK_DEFAULT (1 << 8) /* RW--V */
+
+/* LRCK Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD (1 << 10) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_ENABLED (0 << 10) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOLRCKD_DISABLED (1 << 10) /* RWI-V */
+
+/* Bit Clock Output Disable */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_ENABLED (0 << 11) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOBCLKD_DISABLED (1 << 11) /* RWI-V */
+
+/*
+3-Wire Audio Serial Output Channel 0-3 Operational
+Status. Each bit becomes 1 after each 3-Wire Audio
+Serial Output Channel N is in action by setting 1 to
+asoen.
+Each bit becomes 0 after each 3-Wire Audio Serial Output
+Channel N is out of action by setting 0 to asoen.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN(n) (1 << (15 - (n))) /* R-IVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(n) (0 << (15 - (n))) /* R-I-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(n) (1 << (15 - (n))) /* R---V */
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0 \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_STOPPED \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN0_RUNNING \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(0)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1 \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_STOPPED \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN1_RUNNING \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(1)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2 \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_STOPPED \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN2_RUNNING \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(2)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3 \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_STOPPED \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_STOPPED(3)
+#define PS3_AUDIO_AO_3WMCTRL_ASORUN3_RUNNING \
+ PS3_AUDIO_AO_3WMCTRL_ASORUN_RUNNING(3)
+
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the 3-wire Audio Output Clock, whcih
+is applied to the master clock selected by mcksel.
+Data output is synchronized with this clock.
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_MASK (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV2 (0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV4 (0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV8 (0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOSR_DIV12 (0x6 << 20) /* RW--V */
+
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL (1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK0 (0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOMCKSEL_CLK1 (1 << 24) /* RW--V */
+
+/*
+Enables and disables 4ch 3-Wire Audio Serial Output
+operation. Each Bit from 0 to 3 corresponds to an
+output channel, which means that each output channel
+can be enabled or disabled individually. When
+multiple channels are enabled at the same time, output
+operations are performed in synchronization.
+Bit 0 - Output Channel 0 (SDOUT[0])
+Bit 1 - Output Channel 1 (SDOUT[1])
+Bit 2 - Output Channel 2 (SDOUT[2])
+Bit 3 - Output Channel 3 (SDOUT[3])
+*/
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN(n) (1 << (31 - (n))) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(n) (0 << (31 - (n))) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(n) (1 << (31 - (n))) /* RW--V */
+
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0 \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(0) /* RWIVF */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_DISABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(0) /* RWI-V */
+#define PS3_AUDIO_AO_3WMCTRL_ASOEN0_ENABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(0) /* RW--V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0 \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(1) /* RWIVF */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_DISABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(1) /* RWI-V */
+#define PS3_AUDIO_A1_3WMCTRL_ASOEN0_ENABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(1) /* RW--V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0 \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(2) /* RWIVF */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_DISABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(2) /* RWI-V */
+#define PS3_AUDIO_A2_3WMCTRL_ASOEN0_ENABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(2) /* RW--V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0 \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN(3) /* RWIVF */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_DISABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_DISABLED(3) /* RWI-V */
+#define PS3_AUDIO_A3_3WMCTRL_ASOEN0_ENABLED \
+ PS3_AUDIO_AO_3WMCTRL_ASOEN_ENABLED(3) /* RW--V */
+
+/*
+3-Wire Audio Serial output Channel 0-3 Control Register
+Configures settings for 3-Wire Serial Audio Output Channel 0-3
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|A|0 0 0 0|A|0|ASO|0 0 0|0|0|0|0|0| AO_3WCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+*/
+/*
+Data Bit Mode
+Specifies the number of data bits
+0 - 16 bits
+1 - reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODB_MASK (0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_16BIT (0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_RESVD (0x1 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_20BIT (0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_3WCTRL_ASODB_24BIT (0x3 << 8) /* RW--V */
+/*
+Data Format Mode
+Specifies the data format where (LSB side or MSB) the data(in 20 bit
+or 24 bit resolution mode) is put in a 32 bit field.
+0 - Data put on LSB side
+1 - Data put on MSB side
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASODF (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_LSB (0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASODF_MSB (1 << 11) /* RW--V */
+/*
+Buffer Reset
+Performs buffer reset. Writing 1 to this bit initializes the
+corresponding 3-Wire Audio Output buffers(both L and R).
+*/
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST (1 << 16) /* CWIVF */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_IDLE (0 << 16) /* -WI-V */
+#define PS3_AUDIO_AO_3WCTRL_ASOBRST_RESET (1 << 16) /* -W--T */
+
+/*
+S/PDIF Audio Output Channel 0/1 Control Register
+Configures settings for S/PDIF Audio Output Channel 0/1.
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |S|0 0 0|S|0 0|S| SPOSR |0 0|SPO|0 0 0 0|S|0|SPO|0 0 0 0 0 0 0|S| AO_SPDCTRL
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+Buffer reset. Writing 1 to this bit initializes the
+corresponding S/PDIF output buffer pointer.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST (1 << 0) /* CWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_IDLE (0 << 0) /* -WI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOBRST_RESET (1 << 0) /* -W--T */
+
+/*
+Data Bit Mode
+Specifies number of data bits
+0 - 16 bits
+1 - Reserved
+2 - 20 bits
+3 - 24 bits
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_MASK (0x3 << 8) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_16BIT (0x0 << 8) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_RESVD (0x1 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_20BIT (0x2 << 8) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODB_24BIT (0x3 << 8) /* RW--V */
+/*
+Data format Mode
+Specifies the data format, where (LSB side or MSB)
+the data(in 20 or 24 bit resolution) is put in the
+32 bit field.
+0 - LSB Side
+1 - MSB Side
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPODF (1 << 11) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_LSB (0 << 11) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPODF_MSB (1 << 11) /* RW--V */
+/*
+Source Select
+Specifies the source of the S/PDIF output. When 0, output
+operation is controlled by 3wen[0] of AO_3WMCTRL register.
+The SR must have the same setting as the a0_3wmctrl reg.
+0 - 3-Wire Audio OUT Ch0 Buffer
+1 - S/PDIF buffer
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_MASK (0x3 << 16) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_3WEN (0x0 << 16) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSS_SPDIF (0x1 << 16) /* RW--V */
+/*
+Sampling Rate
+Specifies the divide ratio of the bit clock (clock output
+from bclko) used by the S/PDIF Output Clock, which
+is applied to the master clock selected by mcksel.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR (0xf << 20) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV2 (0x1 << 20) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV4 (0x2 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV8 (0x4 << 20) /* RW--V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOSR_DIV12 (0x6 << 20) /* RW--V */
+/*
+Master Clock Select
+0 - Master Clock 0
+1 - Master Clock 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL (1 << 24) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK0 (0 << 24) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOMCKSEL_CLK1 (1 << 24) /* RW--V */
+
+/*
+S/PDIF Output Channel Operational Status
+This bit becomes 1 after S/PDIF Output Channel is in
+action by setting 1 to spoen. This bit becomes 0
+after S/PDIF Output Channel is out of action by setting
+0 to spoen.
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN (1 << 27) /* R-IVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_STOPPED (0 << 27) /* R-I-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPORUN_RUNNING (1 << 27) /* R---V */
+
+/*
+S/PDIF Audio Output Channel Output Enable
+Enables and disables output operation. This bit is used
+only when sposs = 1
+*/
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN (1 << 31) /* RWIVF */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_DISABLED (0 << 31) /* RWI-V */
+#define PS3_AUDIO_AO_SPDCTRL_SPOEN_ENABLED (1 << 31) /* RW--V */
+
+/*
+S/PDIF Audio Output Channel Channel Status
+Setting Registers.
+Configures channel status bit settings for each block
+(192 bits).
+Output is performed from the MSB(AO_SPDCS0 register bit 31).
+The same value is added for subframes within the same frame.
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ | SPOCS | AO_SPDCS
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+
+S/PDIF Audio Output Channel User Bit Setting
+Configures user bit settings for each block (384 bits).
+Output is performed from the MSB(ao_spdub0 register bit 31).
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ | SPOUB | AO_SPDUB
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*****************************************************************************
+ *
+ * DMAC register
+ *
+ *****************************************************************************/
+/*
+The PS3_AUDIO_KICK register is used to initiate a DMA transfer and monitor
+its status
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0|STATU|0 0 0| EVENT |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0|R| KICK
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+/*
+The REQUEST field is written to ACTIVE to initiate a DMA request when EVENT
+occurs.
+It will return to the DONE state when the request is completed.
+The registers for a DMA channel should only be written if REQUEST is IDLE.
+*/
+
+#define PS3_AUDIO_KICK_REQUEST (1 << 0) /* RWIVF */
+#define PS3_AUDIO_KICK_REQUEST_IDLE (0 << 0) /* RWI-V */
+#define PS3_AUDIO_KICK_REQUEST_ACTIVE (1 << 0) /* -W--T */
+
+/*
+ *The EVENT field is used to set the event in which
+ *the DMA request becomes active.
+ */
+#define PS3_AUDIO_KICK_EVENT_MASK (0x1f << 16) /* RWIVF */
+#define PS3_AUDIO_KICK_EVENT_ALWAYS (0x00 << 16) /* RWI-V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_EMPTY (0x01 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT0_UNDERFLOW (0x02 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_EMPTY (0x03 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT1_UNDERFLOW (0x04 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_EMPTY (0x05 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT2_UNDERFLOW (0x06 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_EMPTY (0x07 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SERIALOUT3_UNDERFLOW (0x08 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_BLOCKTRANSFERCOMPLETE \
+ (0x09 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_UNDERFLOW (0x0A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF0_EMPTY (0x0B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_BLOCKTRANSFERCOMPLETE \
+ (0x0C << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_UNDERFLOW (0x0D << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_SPDIF1_EMPTY (0x0E << 16) /* RW--V */
+
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA(n) \
+ ((0x13 + (n)) << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA0 (0x13 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA1 (0x14 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA2 (0x15 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA3 (0x16 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA4 (0x17 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA5 (0x18 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA6 (0x19 << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA7 (0x1A << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA8 (0x1B << 16) /* RW--V */
+#define PS3_AUDIO_KICK_EVENT_AUDIO_DMA9 (0x1C << 16) /* RW--V */
+
+/*
+The STATUS field can be used to monitor the progress of a DMA request.
+DONE indicates the previous request has completed.
+EVENT indicates that the DMA engine is waiting for the EVENT to occur.
+PENDING indicates that the DMA engine has not started processing this
+request, but the EVENT has occured.
+DMA indicates that the data transfer is in progress.
+NOTIFY indicates that the notifier signalling end of transfer is being written.
+CLEAR indicated that the previous transfer was cleared.
+ERROR indicates the previous transfer requested an unsupported
+source/destination combination.
+*/
+
+#define PS3_AUDIO_KICK_STATUS_MASK (0x7 << 24) /* R-IVF */
+#define PS3_AUDIO_KICK_STATUS_DONE (0x0 << 24) /* R-I-V */
+#define PS3_AUDIO_KICK_STATUS_EVENT (0x1 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_PENDING (0x2 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_DMA (0x3 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_NOTIFY (0x4 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_CLEAR (0x5 << 24) /* R---V */
+#define PS3_AUDIO_KICK_STATUS_ERROR (0x6 << 24) /* R---V */
+
+/*
+The PS3_AUDIO_SOURCE register specifies the source address for transfers.
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ | START |0 0 0 0 0|TAR| SOURCE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary. The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_SOURCE_START_MASK (0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the source address.
+*/
+
+#define PS3_AUDIO_SOURCE_TARGET_MASK (3 << 0) /* RWIVF */
+#define PS3_AUDIO_SOURCE_TARGET_SYSTEM_MEMORY (2 << 0) /* RW--V */
+
+/*
+The PS3_AUDIO_DEST register specifies the destination address for transfers.
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ | START |0 0 0 0 0|TAR| DEST
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+/*
+The Audio DMA engine uses 128-byte transfers, thus the address must be aligned
+to a 128 byte boundary. The low seven bits are assumed to be 0.
+*/
+
+#define PS3_AUDIO_DEST_START_MASK (0x01FFFFFF << 7) /* RWIUF */
+
+/*
+The TARGET field specifies the memory space containing the destination address
+AUDIOFIFO = Audio WriteData FIFO,
+*/
+
+#define PS3_AUDIO_DEST_TARGET_MASK (3 << 0) /* RWIVF */
+#define PS3_AUDIO_DEST_TARGET_AUDIOFIFO (1 << 0) /* RW--V */
+
+/*
+PS3_AUDIO_DMASIZE specifies the number of 128-byte blocks + 1 to transfer.
+So a value of 0 means 128-bytes will get transfered.
+
+
+ 31 24 23 16 15 8 7 0
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+ |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0| BLOCKS | DMASIZE
+ +-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-|-+-+-+-+-+-+-+-+
+*/
+
+
+#define PS3_AUDIO_DMASIZE_BLOCKS_MASK (0x7f << 0) /* RWIUF */
+
+/*
+ * source/destination address for internal fifos
+ */
+#define PS3_AUDIO_AO_3W_LDATA(n) (0x1000 + (0x100 * (n)))
+#define PS3_AUDIO_AO_3W_RDATA(n) (0x1080 + (0x100 * (n)))
+
+#define PS3_AUDIO_AO_SPD_DATA(n) (0x2000 + (0x400 * (n)))
+
+
+/*
+ * field attiribute
+ *
+ * Read
+ * ' ' = Other Information
+ * '-' = Field is part of a write-only register
+ * 'C' = Value read is always the same, constant value line follows (C)
+ * 'R' = Value is read
+ *
+ * Write
+ * ' ' = Other Information
+ * '-' = Must not be written (D), value ignored when written (R,A,F)
+ * 'W' = Can be written
+ *
+ * Internal State
+ * ' ' = Other Information
+ * '-' = No internal state
+ * 'X' = Internal state, initial value is unknown
+ * 'I' = Internal state, initial value is known and follows (I)
+ *
+ * Declaration/Size
+ * ' ' = Other Information
+ * '-' = Does Not Apply
+ * 'V' = Type is void
+ * 'U' = Type is unsigned integer
+ * 'S' = Type is signed integer
+ * 'F' = Type is IEEE floating point
+ * '1' = Byte size (008)
+ * '2' = Short size (016)
+ * '3' = Three byte size (024)
+ * '4' = Word size (032)
+ * '8' = Double size (064)
+ *
+ * Define Indicator
+ * ' ' = Other Information
+ * 'D' = Device
+ * 'M' = Memory
+ * 'R' = Register
+ * 'A' = Array of Registers
+ * 'F' = Field
+ * 'V' = Value
+ * 'T' = Task
+ */
+
diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig
new file mode 100644
index 000000000000..b7e08ef22a94
--- /dev/null
+++ b/sound/sh/Kconfig
@@ -0,0 +1,14 @@
+# ALSA SH drivers
+
+menu "SUPERH devices"
+ depends on SND!=n && SUPERH
+
+config SND_AICA
+ tristate "Dreamcast Yamaha AICA sound"
+ depends on SH_DREAMCAST && SND
+ select SND_PCM
+ help
+ ALSA Sound driver for the SEGA Dreamcast console.
+
+endmenu
+
diff --git a/sound/sh/Makefile b/sound/sh/Makefile
new file mode 100644
index 000000000000..8fdcb6e26f00
--- /dev/null
+++ b/sound/sh/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for ALSA
+#
+
+snd-aica-objs := aica.o
+
+# Toplevel Module Dependency
+obj-$(CONFIG_SND_AICA) += snd-aica.o
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
new file mode 100644
index 000000000000..739786529ca5
--- /dev/null
+++ b/sound/sh/aica.c
@@ -0,0 +1,665 @@
+/*
+* This code is licenced under
+* the General Public Licence
+* version 2
+*
+* Copyright Adrian McMenamin 2005, 2006, 2007
+* <adrian@mcmen.demon.co.uk>
+* Requires firmware (BSD licenced) available from:
+* http://linuxdc.cvs.sourceforge.net/linuxdc/linux-sh-dc/sound/oss/aica/firmware/
+* or the maintainer
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of version 2 of the GNU General Public License as published by
+* the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*
+*/
+
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/info.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/dreamcast/sysasic.h>
+#include "aica.h"
+
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}");
+
+/* module parameters */
+#define CARD_NAME "AICA"
+static int index = -1;
+static char *id;
+static int enable = 1;
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
+module_param(enable, bool, 0644);
+MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
+
+/* Use workqueue */
+static struct workqueue_struct *aica_queue;
+
+/* Simple platform device */
+static struct platform_device *pd;
+static struct resource aica_memory_space[2] = {
+ {
+ .name = "AICA ARM CONTROL",
+ .start = ARM_RESET_REGISTER,
+ .flags = IORESOURCE_MEM,
+ .end = ARM_RESET_REGISTER + 3,
+ },
+ {
+ .name = "AICA Sound RAM",
+ .start = SPU_MEMORY_BASE,
+ .flags = IORESOURCE_MEM,
+ .end = SPU_MEMORY_BASE + 0x200000 - 1,
+ },
+};
+
+/* SPU specific functions */
+/* spu_write_wait - wait for G2-SH FIFO to clear */
+static void spu_write_wait(void)
+{
+ int time_count;
+ time_count = 0;
+ while (1) {
+ if (!(readl(G2_FIFO) & 0x11))
+ break;
+ /* To ensure hardware failure doesn't wedge kernel */
+ time_count++;
+ if (time_count > 0x10000) {
+ snd_printk
+ ("WARNING: G2 FIFO appears to be blocked.\n");
+ break;
+ }
+ }
+}
+
+/* spu_memset - write to memory in SPU address space */
+static void spu_memset(u32 toi, u32 what, int length)
+{
+ int i;
+ snd_assert(length % 4 == 0, return);
+ for (i = 0; i < length; i++) {
+ if (!(i % 8))
+ spu_write_wait();
+ writel(what, toi + SPU_MEMORY_BASE);
+ toi++;
+ }
+}
+
+/* spu_memload - write to SPU address space */
+static void spu_memload(u32 toi, void *from, int length)
+{
+ u32 *froml = from;
+ u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
+ int i;
+ u32 val;
+ length = DIV_ROUND_UP(length, 4);
+ spu_write_wait();
+ for (i = 0; i < length; i++) {
+ if (!(i % 8))
+ spu_write_wait();
+ val = *froml;
+ writel(val, to);
+ froml++;
+ to++;
+ }
+}
+
+/* spu_disable - set spu registers to stop sound output */
+static void spu_disable(void)
+{
+ int i;
+ u32 regval;
+ spu_write_wait();
+ regval = readl(ARM_RESET_REGISTER);
+ regval |= 1;
+ spu_write_wait();
+ writel(regval, ARM_RESET_REGISTER);
+ for (i = 0; i < 64; i++) {
+ spu_write_wait();
+ regval = readl(SPU_REGISTER_BASE + (i * 0x80));
+ regval = (regval & ~0x4000) | 0x8000;
+ spu_write_wait();
+ writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+ }
+}
+
+/* spu_enable - set spu registers to enable sound output */
+static void spu_enable(void)
+{
+ u32 regval = readl(ARM_RESET_REGISTER);
+ regval &= ~1;
+ spu_write_wait();
+ writel(regval, ARM_RESET_REGISTER);
+}
+
+/*
+ * Halt the sound processor, clear the memory,
+ * load some default ARM7 code, and then restart ARM7
+*/
+static void spu_reset(void)
+{
+ spu_disable();
+ spu_memset(0, 0, 0x200000 / 4);
+ /* Put ARM7 in endless loop */
+ ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+ spu_enable();
+}
+
+/* aica_chn_start - write to spu to start playback */
+static void aica_chn_start(void)
+{
+ spu_write_wait();
+ writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* aica_chn_halt - write to spu to halt playback */
+static void aica_chn_halt(void)
+{
+ spu_write_wait();
+ writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
+}
+
+/* ALSA code below */
+static struct snd_pcm_hardware snd_pcm_aica_playback_hw = {
+ .info = (SNDRV_PCM_INFO_NONINTERLEAVED),
+ .formats =
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_IMA_ADPCM),
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = AICA_BUFFER_SIZE,
+ .period_bytes_min = AICA_PERIOD_SIZE,
+ .period_bytes_max = AICA_PERIOD_SIZE,
+ .periods_min = AICA_PERIOD_NUMBER,
+ .periods_max = AICA_PERIOD_NUMBER,
+};
+
+static int aica_dma_transfer(int channels, int buffer_size,
+ struct snd_pcm_substream *substream)
+{
+ int q, err, period_offset;
+ struct snd_card_aica *dreamcastcard;
+ struct snd_pcm_runtime *runtime;
+ err = 0;
+ dreamcastcard = substream->pcm->private_data;
+ period_offset = dreamcastcard->clicks;
+ period_offset %= (AICA_PERIOD_NUMBER / channels);
+ runtime = substream->runtime;
+ for (q = 0; q < channels; q++) {
+ err = dma_xfer(AICA_DMA_CHANNEL,
+ (unsigned long) (runtime->dma_area +
+ (AICA_BUFFER_SIZE * q) /
+ channels +
+ AICA_PERIOD_SIZE *
+ period_offset),
+ AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
+ AICA_PERIOD_SIZE * period_offset,
+ buffer_size / channels, AICA_DMA_MODE);
+ if (unlikely(err < 0))
+ break;
+ dma_wait_for_completion(AICA_DMA_CHANNEL);
+ }
+ return err;
+}
+
+static void startup_aica(struct snd_card_aica *dreamcastcard)
+{
+ spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+ dreamcastcard->channel, sizeof(struct aica_channel));
+ aica_chn_start();
+}
+
+static void run_spu_dma(struct work_struct *work)
+{
+ int buffer_size;
+ struct snd_pcm_runtime *runtime;
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard =
+ container_of(work, struct snd_card_aica, spu_dma_work);
+ runtime = dreamcastcard->substream->runtime;
+ if (unlikely(dreamcastcard->dma_check == 0)) {
+ buffer_size =
+ frames_to_bytes(runtime, runtime->buffer_size);
+ if (runtime->channels > 1)
+ dreamcastcard->channel->flags |= 0x01;
+ aica_dma_transfer(runtime->channels, buffer_size,
+ dreamcastcard->substream);
+ startup_aica(dreamcastcard);
+ dreamcastcard->clicks =
+ buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
+ return;
+ } else {
+ aica_dma_transfer(runtime->channels,
+ AICA_PERIOD_SIZE * runtime->channels,
+ dreamcastcard->substream);
+ snd_pcm_period_elapsed(dreamcastcard->substream);
+ dreamcastcard->clicks++;
+ if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
+ dreamcastcard->clicks %= AICA_PERIOD_NUMBER;
+ mod_timer(&dreamcastcard->timer, jiffies + 1);
+ }
+}
+
+static void aica_period_elapsed(unsigned long timer_var)
+{
+ /*timer function - so cannot sleep */
+ int play_period;
+ struct snd_pcm_runtime *runtime;
+ struct snd_pcm_substream *substream;
+ struct snd_card_aica *dreamcastcard;
+ substream = (struct snd_pcm_substream *) timer_var;
+ runtime = substream->runtime;
+ dreamcastcard = substream->pcm->private_data;
+ /* Have we played out an additional period? */
+ play_period =
+ frames_to_bytes(runtime,
+ readl
+ (AICA_CONTROL_CHANNEL_SAMPLE_NUMBER)) /
+ AICA_PERIOD_SIZE;
+ if (play_period == dreamcastcard->current_period) {
+ /* reschedule the timer */
+ mod_timer(&(dreamcastcard->timer), jiffies + 1);
+ return;
+ }
+ if (runtime->channels > 1)
+ dreamcastcard->current_period = play_period;
+ if (unlikely(dreamcastcard->dma_check == 0))
+ dreamcastcard->dma_check = 1;
+ queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+}
+
+static void spu_begin_dma(struct snd_pcm_substream *substream)
+{
+ struct snd_card_aica *dreamcastcard;
+ struct snd_pcm_runtime *runtime;
+ runtime = substream->runtime;
+ dreamcastcard = substream->pcm->private_data;
+ /*get the queue to do the work */
+ queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+ /* Timer may already be running */
+ if (unlikely(dreamcastcard->timer.data)) {
+ mod_timer(&dreamcastcard->timer, jiffies + 4);
+ return;
+ }
+ init_timer(&(dreamcastcard->timer));
+ dreamcastcard->timer.data = (unsigned long) substream;
+ dreamcastcard->timer.function = aica_period_elapsed;
+ dreamcastcard->timer.expires = jiffies + 4;
+ add_timer(&(dreamcastcard->timer));
+}
+
+static int snd_aicapcm_pcm_open(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ struct aica_channel *channel;
+ struct snd_card_aica *dreamcastcard;
+ if (!enable)
+ return -ENOENT;
+ dreamcastcard = substream->pcm->private_data;
+ channel = kmalloc(sizeof(struct aica_channel), GFP_KERNEL);
+ if (!channel)
+ return -ENOMEM;
+ /* set defaults for channel */
+ channel->sfmt = SM_8BIT;
+ channel->cmd = AICA_CMD_START;
+ channel->vol = dreamcastcard->master_volume;
+ channel->pan = 0x80;
+ channel->pos = 0;
+ channel->flags = 0; /* default to mono */
+ dreamcastcard->channel = channel;
+ runtime = substream->runtime;
+ runtime->hw = snd_pcm_aica_playback_hw;
+ spu_enable();
+ dreamcastcard->clicks = 0;
+ dreamcastcard->current_period = 0;
+ dreamcastcard->dma_check = 0;
+ return 0;
+}
+
+static int snd_aicapcm_pcm_close(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+ flush_workqueue(aica_queue);
+ if (dreamcastcard->timer.data)
+ del_timer(&dreamcastcard->timer);
+ kfree(dreamcastcard->channel);
+ spu_disable();
+ return 0;
+}
+
+static int snd_aicapcm_pcm_hw_free(struct snd_pcm_substream
+ *substream)
+{
+ /* Free the DMA buffer */
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int snd_aicapcm_pcm_hw_params(struct snd_pcm_substream
+ *substream, struct snd_pcm_hw_params
+ *hw_params)
+{
+ /* Allocate a DMA buffer using ALSA built-ins */
+ return
+ snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int snd_aicapcm_pcm_prepare(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+ if ((substream->runtime)->format == SNDRV_PCM_FORMAT_S16_LE)
+ dreamcastcard->channel->sfmt = SM_16BIT;
+ dreamcastcard->channel->freq = substream->runtime->rate;
+ dreamcastcard->substream = substream;
+ return 0;
+}
+
+static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
+ *substream, int cmd)
+{
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ spu_begin_dma(substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ aica_chn_halt();
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static unsigned long snd_aicapcm_pcm_pointer(struct snd_pcm_substream
+ *substream)
+{
+ return readl(AICA_CONTROL_CHANNEL_SAMPLE_NUMBER);
+}
+
+static struct snd_pcm_ops snd_aicapcm_playback_ops = {
+ .open = snd_aicapcm_pcm_open,
+ .close = snd_aicapcm_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_aicapcm_pcm_hw_params,
+ .hw_free = snd_aicapcm_pcm_hw_free,
+ .prepare = snd_aicapcm_pcm_prepare,
+ .trigger = snd_aicapcm_pcm_trigger,
+ .pointer = snd_aicapcm_pcm_pointer,
+};
+
+/* TO DO: set up to handle more than one pcm instance */
+static int __init snd_aicapcmchip(struct snd_card_aica
+ *dreamcastcard, int pcm_index)
+{
+ struct snd_pcm *pcm;
+ int err;
+ /* AICA has no capture ability */
+ err =
+ snd_pcm_new(dreamcastcard->card, "AICA PCM", pcm_index, 1, 0,
+ &pcm);
+ if (unlikely(err < 0))
+ return err;
+ pcm->private_data = dreamcastcard;
+ strcpy(pcm->name, "AICA PCM");
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_aicapcm_playback_ops);
+ /* Allocate the DMA buffers */
+ err =
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data
+ (GFP_KERNEL),
+ AICA_BUFFER_SIZE,
+ AICA_BUFFER_SIZE);
+ return err;
+}
+
+/* Mixer controls */
+static int aica_pcmswitch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 1; /* TO DO: Fix me */
+ return 0;
+}
+
+static int aica_pcmswitch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ if (ucontrol->value.integer.value[0] == 1)
+ return 0; /* TO DO: Fix me */
+ else
+ aica_chn_halt();
+ return 0;
+}
+
+static int aica_pcmvolume_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0xFF;
+ return 0;
+}
+
+static int aica_pcmvolume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = kcontrol->private_data;
+ if (unlikely(!dreamcastcard->channel))
+ return -ETXTBSY; /* we've not yet been set up */
+ ucontrol->value.integer.value[0] = dreamcastcard->channel->vol;
+ return 0;
+}
+
+static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = kcontrol->private_data;
+ if (unlikely(!dreamcastcard->channel))
+ return -ETXTBSY;
+ if (unlikely(dreamcastcard->channel->vol ==
+ ucontrol->value.integer.value[0]))
+ return 0;
+ dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
+ dreamcastcard->master_volume = ucontrol->value.integer.value[0];
+ spu_memload(AICA_CHANNEL0_CONTROL_OFFSET,
+ dreamcastcard->channel, sizeof(struct aica_channel));
+ return 1;
+}
+
+static struct snd_kcontrol_new snd_aica_pcmswitch_control __devinitdata = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .index = 0,
+ .info = aica_pcmswitch_info,
+ .get = aica_pcmswitch_get,
+ .put = aica_pcmswitch_put
+};
+
+static struct snd_kcontrol_new snd_aica_pcmvolume_control __devinitdata = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .index = 0,
+ .info = aica_pcmvolume_info,
+ .get = aica_pcmvolume_get,
+ .put = aica_pcmvolume_put
+};
+
+static int load_aica_firmware(void)
+{
+ int err;
+ const struct firmware *fw_entry;
+ spu_reset();
+ err = request_firmware(&fw_entry, "aica_firmware.bin", &pd->dev);
+ if (unlikely(err))
+ return err;
+ /* write firware into memory */
+ spu_disable();
+ spu_memload(0, fw_entry->data, fw_entry->size);
+ spu_enable();
+ release_firmware(fw_entry);
+ return err;
+}
+
+static int __devinit add_aicamixer_controls(struct snd_card_aica
+ *dreamcastcard)
+{
+ int err;
+ err = snd_ctl_add
+ (dreamcastcard->card,
+ snd_ctl_new1(&snd_aica_pcmvolume_control, dreamcastcard));
+ if (unlikely(err < 0))
+ return err;
+ err = snd_ctl_add
+ (dreamcastcard->card,
+ snd_ctl_new1(&snd_aica_pcmswitch_control, dreamcastcard));
+ if (unlikely(err < 0))
+ return err;
+ return 0;
+}
+
+static int snd_aica_remove(struct platform_device *devptr)
+{
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = platform_get_drvdata(devptr);
+ if (unlikely(!dreamcastcard))
+ return -ENODEV;
+ snd_card_free(dreamcastcard->card);
+ kfree(dreamcastcard);
+ platform_set_drvdata(devptr, NULL);
+ return 0;
+}
+
+static int __init snd_aica_probe(struct platform_device *devptr)
+{
+ int err;
+ struct snd_card_aica *dreamcastcard;
+ dreamcastcard = kmalloc(sizeof(struct snd_card_aica), GFP_KERNEL);
+ if (unlikely(!dreamcastcard))
+ return -ENOMEM;
+ dreamcastcard->card =
+ snd_card_new(index, SND_AICA_DRIVER, THIS_MODULE, 0);
+ if (unlikely(!dreamcastcard->card)) {
+ kfree(dreamcastcard);
+ return -ENODEV;
+ }
+ strcpy(dreamcastcard->card->driver, "snd_aica");
+ strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
+ strcpy(dreamcastcard->card->longname,
+ "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
+ /* Prepare to use the queue */
+ INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
+ /* Load the PCM 'chip' */
+ err = snd_aicapcmchip(dreamcastcard, 0);
+ if (unlikely(err < 0))
+ goto freedreamcast;
+ snd_card_set_dev(dreamcastcard->card, &devptr->dev);
+ dreamcastcard->timer.data = 0;
+ dreamcastcard->channel = NULL;
+ /* Add basic controls */
+ err = add_aicamixer_controls(dreamcastcard);
+ if (unlikely(err < 0))
+ goto freedreamcast;
+ /* Register the card with ALSA subsystem */
+ err = snd_card_register(dreamcastcard->card);
+ if (unlikely(err < 0))
+ goto freedreamcast;
+ platform_set_drvdata(devptr, dreamcastcard);
+ aica_queue = create_workqueue(CARD_NAME);
+ if (unlikely(!aica_queue))
+ goto freedreamcast;
+ snd_printk
+ ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n");
+ return 0;
+ freedreamcast:
+ snd_card_free(dreamcastcard->card);
+ kfree(dreamcastcard);
+ return err;
+}
+
+static struct platform_driver snd_aica_driver = {
+ .probe = snd_aica_probe,
+ .remove = snd_aica_remove,
+ .driver = {
+ .name = SND_AICA_DRIVER},
+};
+
+static int __init aica_init(void)
+{
+ int err;
+ err = platform_driver_register(&snd_aica_driver);
+ if (unlikely(err < 0))
+ return err;
+ pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
+ aica_memory_space, 2);
+ if (unlikely(IS_ERR(pd))) {
+ platform_driver_unregister(&snd_aica_driver);
+ return PTR_ERR(pd);
+ }
+ /* Load the firmware */
+ return load_aica_firmware();
+}
+
+static void __exit aica_exit(void)
+{
+ /* Destroy the aica kernel thread *
+ * being extra cautious to check if it exists*/
+ if (likely(aica_queue))
+ destroy_workqueue(aica_queue);
+ platform_device_unregister(pd);
+ platform_driver_unregister(&snd_aica_driver);
+ /* Kill any sound still playing and reset ARM7 to safe state */
+ spu_reset();
+}
+
+module_init(aica_init);
+module_exit(aica_exit);
diff --git a/sound/sh/aica.h b/sound/sh/aica.h
new file mode 100644
index 000000000000..8c11e3d10a50
--- /dev/null
+++ b/sound/sh/aica.h
@@ -0,0 +1,81 @@
+/* aica.h
+ * Header file for ALSA driver for
+ * Sega Dreamcast Yamaha AICA sound
+ * Copyright Adrian McMenamin
+ * <adrian@mcmen.demon.co.uk>
+ * 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* SPU memory and register constants etc */
+#define G2_FIFO 0xa05f688c
+#define SPU_MEMORY_BASE 0xA0800000
+#define ARM_RESET_REGISTER 0xA0702C00
+#define SPU_REGISTER_BASE 0xA0700000
+
+/* AICA channels stuff */
+#define AICA_CONTROL_POINT 0xA0810000
+#define AICA_CONTROL_CHANNEL_SAMPLE_NUMBER 0xA0810008
+#define AICA_CHANNEL0_CONTROL_OFFSET 0x10004
+
+/* Command values */
+#define AICA_CMD_KICK 0x80000000
+#define AICA_CMD_NONE 0
+#define AICA_CMD_START 1
+#define AICA_CMD_STOP 2
+#define AICA_CMD_VOL 3
+
+/* Sound modes */
+#define SM_8BIT 1
+#define SM_16BIT 0
+#define SM_ADPCM 2
+
+/* Buffer and period size */
+#define AICA_BUFFER_SIZE 0x8000
+#define AICA_PERIOD_SIZE 0x800
+#define AICA_PERIOD_NUMBER 16
+
+#define AICA_CHANNEL0_OFFSET 0x11000
+#define AICA_CHANNEL1_OFFSET 0x21000
+#define CHANNEL_OFFSET 0x10000
+
+#define AICA_DMA_CHANNEL 0
+#define AICA_DMA_MODE 5
+
+#define SND_AICA_DRIVER "AICA"
+
+struct aica_channel {
+ uint32_t cmd; /* Command ID */
+ uint32_t pos; /* Sample position */
+ uint32_t length; /* Sample length */
+ uint32_t freq; /* Frequency */
+ uint32_t vol; /* Volume 0-255 */
+ uint32_t pan; /* Pan 0-255 */
+ uint32_t sfmt; /* Sound format */
+ uint32_t flags; /* Bit flags */
+};
+
+struct snd_card_aica {
+ struct work_struct spu_dma_work;
+ struct snd_card *card;
+ struct aica_channel *channel;
+ struct snd_pcm_substream *substream;
+ int clicks;
+ int current_period;
+ struct timer_list timer;
+ int master_volume;
+ int dma_check;
+};
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 10cffc087181..97b255233175 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -27,6 +27,7 @@ config SND_SOC
source "sound/soc/at91/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/s3c24xx/Kconfig"
+source "sound/soc/sh/Kconfig"
# Supported codecs
source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 0ae2e49036f9..304140377632 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
snd-soc-core-objs := soc-core.o soc-dapm.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
-obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/
+obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 044a3712077a..e97c68306a9a 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,6 +1,7 @@
config SND_S3C24XX_SOC
tristate "SoC Audio for the Samsung S3C24XX chips"
depends on ARCH_S3C2410 && SND_SOC
+ select SND_PCM
help
Say Y or M if you want to add support for codecs attached to
the S3C24XX AC97, I2S or SSP interface. You will also need
@@ -8,3 +9,29 @@ config SND_S3C24XX_SOC
config SND_S3C24XX_SOC_I2S
tristate
+
+config SND_S3C2443_SOC_AC97
+ tristate
+ select AC97_BUS
+ select SND_AC97_CODEC
+ select SND_SOC_AC97_BUS
+
+config SND_S3C24XX_SOC_NEO1973_WM8753
+ tristate "SoC I2S Audio support for NEO1973 - WM8753"
+ depends on SND_S3C24XX_SOC && MACH_GTA01
+ select SND_S3C24XX_SOC_I2S
+ select SND_SOC_WM8753
+ help
+ Say Y if you want to add support for SoC audio on smdk2440
+ with the WM8753.
+
+config SND_S3C24XX_SOC_SMDK2443_WM9710
+ tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
+ depends on SND_S3C24XX_SOC && MACH_SMDK2443
+ select SND_S3C2443_SOC_AC97
+ select SND_SOC_AC97_CODEC
+ help
+ Say Y if you want to add support for SoC audio on smdk2443
+ with the WM9710.
+
+
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 6f0fffcb30f5..13c92f0fa1e4 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -1,6 +1,15 @@
# S3c24XX Platform Support
snd-soc-s3c24xx-objs := s3c24xx-pcm.o
snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
+snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
+obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
+
+# S3C24XX Machine Support
+snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o
+snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o
+
+obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
+obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o
diff --git a/sound/soc/s3c24xx/lm4857.h b/sound/soc/s3c24xx/lm4857.h
new file mode 100644
index 000000000000..0cf5b7011d6f
--- /dev/null
+++ b/sound/soc/s3c24xx/lm4857.h
@@ -0,0 +1,32 @@
+/*
+ * lm4857.h -- ALSA Soc Audio Layer
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Revision history
+ * 18th Jun 2007 Initial version.
+ */
+
+#ifndef LM4857_H_
+#define LM4857_H_
+
+/* The register offsets in the cache array */
+#define LM4857_MVOL 0
+#define LM4857_LVOL 1
+#define LM4857_RVOL 2
+#define LM4857_CTRL 3
+
+/* the shifts required to set these bits */
+#define LM4857_3D 5
+#define LM4857_WAKEUP 5
+#define LM4857_EPGAIN 4
+
+#endif /*LM4857_H_*/
+
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
new file mode 100644
index 000000000000..d5a8fc2cf8d6
--- /dev/null
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -0,0 +1,670 @@
+/*
+ * neo1973_wm8753.c -- SoC audio for Neo1973
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Revision history
+ * 20th Jan 2007 Initial version.
+ * 05th Feb 2007 Rename all to Neo1973
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/scoop.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/hardware.h>
+#include <asm/arch/audio.h>
+#include <asm/io.h>
+#include <asm/arch/spi-gpio.h>
+#include "../codecs/wm8753.h"
+#include "lm4857.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-i2s.h"
+
+/* define the scenarios */
+#define NEO_AUDIO_OFF 0
+#define NEO_GSM_CALL_AUDIO_HANDSET 1
+#define NEO_GSM_CALL_AUDIO_HEADSET 2
+#define NEO_GSM_CALL_AUDIO_BLUETOOTH 3
+#define NEO_STEREO_TO_SPEAKERS 4
+#define NEO_STEREO_TO_HEADPHONES 5
+#define NEO_CAPTURE_HANDSET 6
+#define NEO_CAPTURE_HEADSET 7
+#define NEO_CAPTURE_BLUETOOTH 8
+
+static struct snd_soc_machine neo1973;
+static struct i2c_client *i2c;
+
+static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ unsigned int pll_out = 0, bclk = 0;
+ int ret = 0;
+ unsigned long iis_clkrate;
+
+ iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ pll_out = 12288000;
+ break;
+ case 48000:
+ bclk = WM8753_BCLK_DIV_4;
+ pll_out = 12288000;
+ break;
+ case 96000:
+ bclk = WM8753_BCLK_DIV_2;
+ pll_out = 12288000;
+ break;
+ case 11025:
+ bclk = WM8753_BCLK_DIV_16;
+ pll_out = 11289600;
+ break;
+ case 22050:
+ bclk = WM8753_BCLK_DIV_8;
+ pll_out = 11289600;
+ break;
+ case 44100:
+ bclk = WM8753_BCLK_DIV_4;
+ pll_out = 11289600;
+ break;
+ case 88200:
+ bclk = WM8753_BCLK_DIV_2;
+ pll_out = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = codec_dai->dai_ops.set_fmt(codec_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = cpu_dai->dai_ops.set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_MCLK, pll_out,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set MCLK division for sample rate */
+ ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
+ S3C2410_IISMOD_32FS );
+ if (ret < 0)
+ return ret;
+
+ /* set codec BCLK division for sample rate */
+ ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_BCLKDIV, bclk);
+ if (ret < 0)
+ return ret;
+
+ /* set prescaler division for sample rate */
+ ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
+ S3C24XX_PRESCALE(4,4));
+ if (ret < 0)
+ return ret;
+
+ /* codec PLL input is PCLK/4 */
+ ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1,
+ iis_clkrate / 4, pll_out);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+ /* disable the PLL */
+ return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL1, 0, 0);
+}
+
+/*
+ * Neo1973 WM8753 HiFi DAI opserations.
+ */
+static struct snd_soc_ops neo1973_hifi_ops = {
+ .hw_params = neo1973_hifi_hw_params,
+ .hw_free = neo1973_hifi_hw_free,
+};
+
+static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ unsigned int pcmdiv = 0;
+ int ret = 0;
+ unsigned long iis_clkrate;
+
+ iis_clkrate = s3c24xx_i2s_get_clockrate();
+
+ if (params_rate(params) != 8000)
+ return -EINVAL;
+ if (params_channels(params) != 1)
+ return -EINVAL;
+
+ pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
+
+ /* todo: gg check mode (DSP_B) against CSR datasheet */
+ /* set codec DAI configuration */
+ ret = codec_dai->dai_ops.set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = codec_dai->dai_ops.set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set codec PCM division for sample rate */
+ ret = codec_dai->dai_ops.set_clkdiv(codec_dai, WM8753_PCMDIV, pcmdiv);
+ if (ret < 0)
+ return ret;
+
+ /* configue and enable PLL for 12.288MHz output */
+ ret = codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2,
+ iis_clkrate / 4, 12288000);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int neo1973_voice_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+
+ /* disable the PLL */
+ return codec_dai->dai_ops.set_pll(codec_dai, WM8753_PLL2, 0, 0);
+}
+
+static struct snd_soc_ops neo1973_voice_ops = {
+ .hw_params = neo1973_voice_hw_params,
+ .hw_free = neo1973_voice_hw_free,
+};
+
+static int neo1973_scenario = 0;
+
+static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = neo1973_scenario;
+ return 0;
+}
+
+static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
+{
+ switch(neo1973_scenario) {
+ case NEO_AUDIO_OFF:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ break;
+ case NEO_GSM_CALL_AUDIO_HANDSET:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 1);
+ break;
+ case NEO_GSM_CALL_AUDIO_HEADSET:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ break;
+ case NEO_GSM_CALL_AUDIO_BLUETOOTH:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 1);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 1);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ break;
+ case NEO_STEREO_TO_SPEAKERS:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ break;
+ case NEO_STEREO_TO_HEADPHONES:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 1);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ break;
+ case NEO_CAPTURE_HANDSET:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 1);
+ break;
+ case NEO_CAPTURE_HEADSET:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 1);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ break;
+ case NEO_CAPTURE_BLUETOOTH:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ break;
+ default:
+ snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
+ snd_soc_dapm_set_endpoint(codec, "GSM Line In", 0);
+ snd_soc_dapm_set_endpoint(codec, "Headset Mic", 0);
+ snd_soc_dapm_set_endpoint(codec, "Call Mic", 0);
+ }
+
+ snd_soc_dapm_sync_endpoints(codec);
+
+ return 0;
+}
+
+static int neo1973_set_scenario(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (neo1973_scenario == ucontrol->value.integer.value[0])
+ return 0;
+
+ neo1973_scenario = ucontrol->value.integer.value[0];
+ set_scenario_endpoints(codec, neo1973_scenario);
+ return 1;
+}
+
+static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0};
+
+static void lm4857_write_regs(void)
+{
+ if (i2c_master_send(i2c, lm4857_regs, 4) != 4)
+ printk(KERN_ERR "lm4857: i2c write failed\n");
+}
+
+static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int reg=kcontrol->private_value & 0xFF;
+ int shift = (kcontrol->private_value >> 8) & 0x0F;
+ int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+ ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask;
+ return 0;
+}
+
+static int lm4857_set_reg(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int reg = kcontrol->private_value & 0xFF;
+ int shift = (kcontrol->private_value >> 8) & 0x0F;
+ int mask = (kcontrol->private_value >> 16) & 0xFF;
+
+ if (((lm4857_regs[reg] >> shift ) & mask) ==
+ ucontrol->value.integer.value[0])
+ return 0;
+
+ lm4857_regs[reg] &= ~ (mask << shift);
+ lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
+ lm4857_write_regs();
+ return 1;
+}
+
+static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = lm4857_regs[LM4857_CTRL] & 0x0F;
+
+ if (value)
+ value -= 5;
+
+ ucontrol->value.integer.value[0] = value;
+ return 0;
+}
+
+static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 value = ucontrol->value.integer.value[0];
+
+ if (value)
+ value += 5;
+
+ if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value)
+ return 0;
+
+ lm4857_regs[LM4857_CTRL] &= 0xF0;
+ lm4857_regs[LM4857_CTRL] |= value;
+ lm4857_write_regs();
+ return 1;
+}
+
+static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = {
+ SND_SOC_DAPM_LINE("Audio Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+ SND_SOC_DAPM_LINE("GSM Line In", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Call Mic", NULL),
+};
+
+
+/* example machine audio_mapnections */
+static const char* audio_map[][3] = {
+
+ /* Connections to the lm4857 amp */
+ {"Audio Out", NULL, "LOUT1"},
+ {"Audio Out", NULL, "ROUT1"},
+
+ /* Connections to the GSM Module */
+ {"GSM Line Out", NULL, "MONO1"},
+ {"GSM Line Out", NULL, "MONO2"},
+ {"RXP", NULL, "GSM Line In"},
+ {"RXN", NULL, "GSM Line In"},
+
+ /* Connections to Headset */
+ {"MIC1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Mic"},
+
+ /* Call Mic */
+ {"MIC2", NULL, "Mic Bias"},
+ {"MIC2N", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Call Mic"},
+
+ /* Connect the ALC pins */
+ {"ACIN", NULL, "ACOP"},
+
+ {NULL, NULL, NULL},
+};
+
+static const char *lm4857_mode[] = {
+ "Off",
+ "Call Speaker",
+ "Stereo Speakers",
+ "Stereo Speakers + Headphones",
+ "Headphones"
+};
+
+static const struct soc_enum lm4857_mode_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode),
+};
+
+static const char *neo_scenarios[] = {
+ "Off",
+ "GSM Handset",
+ "GSM Headset",
+ "GSM Bluetooth",
+ "Speakers",
+ "Headphones",
+ "Capture Handset",
+ "Capture Headset",
+ "Capture Bluetooth"
+};
+
+static const struct soc_enum neo_scenario_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios),neo_scenarios),
+};
+
+static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
+ SOC_SINGLE_EXT("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0],
+ lm4857_get_mode, lm4857_set_mode),
+ SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0],
+ neo1973_get_scenario, neo1973_set_scenario),
+ SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+ SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0,
+ lm4857_get_reg, lm4857_set_reg),
+};
+
+/*
+ * This is an example machine initialisation for a wm8753 connected to a
+ * neo1973 II. It is missing logic to detect hp/mic insertions and logic
+ * to re-route the audio in such an event.
+ */
+static int neo1973_wm8753_init(struct snd_soc_codec *codec)
+{
+ int i, err;
+
+ /* set up NC codec pins */
+ snd_soc_dapm_set_endpoint(codec, "LOUT2", 0);
+ snd_soc_dapm_set_endpoint(codec, "ROUT2", 0);
+ snd_soc_dapm_set_endpoint(codec, "OUT3", 0);
+ snd_soc_dapm_set_endpoint(codec, "OUT4", 0);
+ snd_soc_dapm_set_endpoint(codec, "LINE1", 0);
+ snd_soc_dapm_set_endpoint(codec, "LINE2", 0);
+
+
+ /* set endpoints to default mode */
+ set_scenario_endpoints(codec, NEO_AUDIO_OFF);
+
+ /* Add neo1973 specific widgets */
+ for (i = 0; i < ARRAY_SIZE(wm8753_dapm_widgets); i++)
+ snd_soc_dapm_new_control(codec, &wm8753_dapm_widgets[i]);
+
+ /* add neo1973 specific controls */
+ for (i = 0; i < ARRAY_SIZE(wm8753_neo1973_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&wm8753_neo1973_controls[i],
+ codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ /* set up neo1973 specific audio path audio_mapnects */
+ for (i = 0; audio_map[i][0] != NULL; i++) {
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+ }
+
+ snd_soc_dapm_sync_endpoints(codec);
+ return 0;
+}
+
+/*
+ * BT Codec DAI
+ */
+static struct snd_soc_cpu_dai bt_dai =
+{ .name = "Bluetooth",
+ .id = 0,
+ .type = SND_SOC_DAI_PCM,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = SNDRV_PCM_RATE_8000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+};
+
+static struct snd_soc_dai_link neo1973_dai[] = {
+{ /* Hifi Playback - for similatious use with voice below */
+ .name = "WM8753",
+ .stream_name = "WM8753 HiFi",
+ .cpu_dai = &s3c24xx_i2s_dai,
+ .codec_dai = &wm8753_dai[WM8753_DAI_HIFI],
+ .init = neo1973_wm8753_init,
+ .ops = &neo1973_hifi_ops,
+},
+{ /* Voice via BT */
+ .name = "Bluetooth",
+ .stream_name = "Voice",
+ .cpu_dai = &bt_dai,
+ .codec_dai = &wm8753_dai[WM8753_DAI_VOICE],
+ .ops = &neo1973_voice_ops,
+},
+};
+
+static struct snd_soc_machine neo1973 = {
+ .name = "neo1973",
+ .dai_link = neo1973_dai,
+ .num_links = ARRAY_SIZE(neo1973_dai),
+};
+
+static struct wm8753_setup_data neo1973_wm8753_setup = {
+ .i2c_address = 0x1a,
+};
+
+static struct snd_soc_device neo1973_snd_devdata = {
+ .machine = &neo1973,
+ .platform = &s3c24xx_soc_platform,
+ .codec_dev = &soc_codec_dev_wm8753,
+ .codec_data = &neo1973_wm8753_setup,
+};
+
+static struct i2c_client client_template;
+
+static unsigned short normal_i2c[] = { 0x7C, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static int lm4857_amp_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+ int ret;
+
+ client_template.adapter = adap;
+ client_template.addr = addr;
+
+ i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
+ if (i2c == NULL)
+ return -ENOMEM;
+
+ ret = i2c_attach_client(i2c);
+ if (ret < 0) {
+ printk(KERN_ERR "LM4857 failed to attach at addr %x\n", addr);
+ goto exit_err;
+ }
+
+ lm4857_write_regs();
+ return ret;
+
+exit_err:
+ kfree(i2c);
+ return ret;
+}
+
+static int lm4857_i2c_detach(struct i2c_client *client)
+{
+ i2c_detach_client(client);
+ kfree(client);
+ return 0;
+}
+
+static int lm4857_i2c_attach(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, lm4857_amp_probe);
+}
+
+/* corgi i2c codec control layer */
+static struct i2c_driver lm4857_i2c_driver = {
+ .driver = {
+ .name = "LM4857 I2C Amp",
+ .owner = THIS_MODULE,
+ },
+ .id = I2C_DRIVERID_LM4857,
+ .attach_adapter = lm4857_i2c_attach,
+ .detach_client = lm4857_i2c_detach,
+ .command = NULL,
+};
+
+static struct i2c_client client_template = {
+ .name = "LM4857",
+ .driver = &lm4857_i2c_driver,
+};
+
+static struct platform_device *neo1973_snd_device;
+
+static int __init neo1973_init(void)
+{
+ int ret;
+
+ neo1973_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!neo1973_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(neo1973_snd_device, &neo1973_snd_devdata);
+ neo1973_snd_devdata.dev = &neo1973_snd_device->dev;
+ ret = platform_device_add(neo1973_snd_device);
+
+ if (ret)
+ platform_device_put(neo1973_snd_device);
+
+ ret = i2c_add_driver(&lm4857_i2c_driver);
+ if (ret != 0)
+ printk(KERN_ERR "can't add i2c driver");
+
+ return ret;
+}
+
+static void __exit neo1973_exit(void)
+{
+ platform_device_unregister(neo1973_snd_device);
+}
+
+module_init(neo1973_init);
+module_exit(neo1973_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
new file mode 100644
index 000000000000..75acf7ef5528
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -0,0 +1,401 @@
+/*
+ * s3c2443-ac97.c -- ALSA Soc Audio Layer
+ *
+ * (c) 2007 Wolfson Microelectronics PLC.
+ * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * Copyright (C) 2005, Sean Choi <sh428.choi@samsung.com>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Revision history
+ * 21st Mar 2007 Initial Version
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/audio.h>
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+struct s3c24xx_ac97_info {
+ void __iomem *regs;
+ struct clk *ac97_clk;
+};
+static struct s3c24xx_ac97_info s3c24xx_ac97;
+
+DECLARE_COMPLETION(ac97_completion);
+static u32 codec_ready;
+static DECLARE_MUTEX(ac97_mutex);
+
+static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ u32 ac_glbctrl;
+ u32 ac_codec_cmd;
+ u32 stat, addr, data;
+
+ down(&ac97_mutex);
+
+ codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+ ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg);
+ writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ udelay(50);
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+ wait_for_completion(&ac97_completion);
+
+ stat = readl(s3c24xx_ac97.regs + S3C_AC97_STAT);
+ addr = (stat >> 16) & 0x7f;
+ data = (stat & 0xffff);
+
+ if (addr != reg)
+ printk(KERN_ERR "s3c24xx-ac97: req addr = %02x,"
+ " rep addr = %02x\n", reg, addr);
+
+ up(&ac97_mutex);
+
+ return (unsigned short)data;
+}
+
+static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ u32 ac_glbctrl;
+ u32 ac_codec_cmd;
+
+ down(&ac97_mutex);
+
+ codec_ready = S3C_AC97_GLBSTAT_CODECREADY;
+ ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val);
+ writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ udelay(50);
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+ wait_for_completion(&ac97_completion);
+
+ ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+ ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ;
+ writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD);
+
+ up(&ac97_mutex);
+
+}
+
+static void s3c2443_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ u32 ac_glbctrl;
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl = S3C_AC97_GLBCTRL_WARMRESET;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl = 0;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+}
+
+static void s3c2443_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ u32 ac_glbctrl;
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl = 0;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA |
+ S3C_AC97_GLBCTRL_PCMINTM_DMA | S3C_AC97_GLBCTRL_MICINTM_DMA;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+}
+
+static irqreturn_t s3c2443_ac97_irq(int irq, void *dev_id)
+{
+ int status;
+ u32 ac_glbctrl;
+
+ status = readl(s3c24xx_ac97.regs + S3C_AC97_GLBSTAT) & codec_ready;
+
+ if (status) {
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ complete(&ac97_completion);
+ }
+ return IRQ_HANDLED;
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = s3c2443_ac97_read,
+ .write = s3c2443_ac97_write,
+ .warm_reset = s3c2443_ac97_warm_reset,
+ .reset = s3c2443_ac97_cold_reset,
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_out = {
+ .name = "AC97 PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_in = {
+ .name = "AC97 PCM Stereo in"
+};
+
+static struct s3c2410_dma_client s3c2443_dma_client_micin = {
+ .name = "AC97 Mic Mono in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_out = {
+ .client = &s3c2443_dma_client_out,
+ .channel = DMACH_PCM_OUT,
+ .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+ .dma_size = 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_pcm_stereo_in = {
+ .client = &s3c2443_dma_client_in,
+ .channel = DMACH_PCM_IN,
+ .dma_addr = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+ .dma_size = 4,
+};
+
+static struct s3c24xx_pcm_dma_params s3c2443_ac97_mic_mono_in = {
+ .client = &s3c2443_dma_client_micin,
+ .channel = DMACH_MIC_IN,
+ .dma_addr = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
+ .dma_size = 4,
+};
+
+static int s3c2443_ac97_probe(struct platform_device *pdev)
+{
+ int ret;
+ u32 ac_glbctrl;
+
+ s3c24xx_ac97.regs = ioremap(S3C2440_PA_AC97, 0x100);
+ if (s3c24xx_ac97.regs == NULL)
+ return -ENXIO;
+
+ s3c24xx_ac97.ac97_clk = clk_get(&pdev->dev, "ac97");
+ if (s3c24xx_ac97.ac97_clk == NULL) {
+ printk(KERN_ERR "s3c2443-ac97 failed to get ac97_clock\n");
+ iounmap(s3c24xx_ac97.regs);
+ return -ENODEV;
+ }
+ clk_enable(s3c24xx_ac97.ac97_clk);
+
+ s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2443_GPE0_AC_nRESET);
+ s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2443_GPE1_AC_SYNC);
+ s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2443_GPE2_AC_BITCLK);
+ s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2443_GPE3_AC_SDI);
+ s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2443_GPE4_AC_SDO);
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl = S3C_AC97_GLBCTRL_COLDRESET;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl = 0;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ msleep(1);
+
+ ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE;
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+ ret = request_irq(IRQ_S3C2443_AC97, s3c2443_ac97_irq,
+ IRQF_DISABLED, "AC97", NULL);
+ if (ret < 0) {
+ printk(KERN_ERR "s3c24xx-ac97: interrupt request failed.\n");
+ clk_disable(s3c24xx_ac97.ac97_clk);
+ clk_put(s3c24xx_ac97.ac97_clk);
+ iounmap(s3c24xx_ac97.regs);
+ }
+ return ret;
+}
+
+static void s3c2443_ac97_remove(struct platform_device *pdev)
+{
+ free_irq(IRQ_S3C2443_AC97, NULL);
+ clk_disable(s3c24xx_ac97.ac97_clk);
+ clk_put(s3c24xx_ac97.ac97_clk);
+ iounmap(s3c24xx_ac97.regs);
+}
+
+static int s3c2443_ac97_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_out;
+ else
+ cpu_dai->dma_data = &s3c2443_ac97_pcm_stereo_in;
+
+ return 0;
+}
+
+static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ u32 ac_glbctrl;
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ switch(cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+ else
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+ else
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK;
+ break;
+ }
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+ return 0;
+}
+
+static int s3c2443_ac97_hw_mic_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return -ENODEV;
+ else
+ cpu_dai->dma_data = &s3c2443_ac97_mic_mono_in;
+
+ return 0;
+}
+
+static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+{
+ u32 ac_glbctrl;
+
+ ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+ switch(cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK;
+ }
+ writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
+
+ return 0;
+}
+
+#define s3c2443_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+
+struct snd_soc_cpu_dai s3c2443_ac97_dai[] = {
+{
+ .name = "s3c2443-ac97",
+ .id = 0,
+ .type = SND_SOC_DAI_AC97,
+ .probe = s3c2443_ac97_probe,
+ .remove = s3c2443_ac97_remove,
+ .playback = {
+ .stream_name = "AC97 Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = s3c2443_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .stream_name = "AC97 Capture",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = s3c2443_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = s3c2443_ac97_hw_params,
+ .trigger = s3c2443_ac97_trigger},
+},
+{
+ .name = "pxa2xx-ac97-mic",
+ .id = 1,
+ .type = SND_SOC_DAI_AC97,
+ .capture = {
+ .stream_name = "AC97 Mic Capture",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = s3c2443_AC97_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = {
+ .hw_params = s3c2443_ac97_hw_mic_params,
+ .trigger = s3c2443_ac97_mic_trigger,},
+},
+};
+
+EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+MODULE_AUTHOR("Graeme Gregory");
+MODULE_DESCRIPTION("AC97 driver for the Samsung s3c2443 chip");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c24xx-ac97.h b/sound/soc/s3c24xx/s3c24xx-ac97.h
new file mode 100644
index 000000000000..2b835e8260fa
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c24xx-ac97.h
@@ -0,0 +1,25 @@
+/*
+ * s3c24xx-ac97.c -- ALSA Soc Audio Layer
+ *
+ * (c) 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Revision history
+ * 10th Nov 2006 Initial version.
+ */
+
+#ifndef S3C24XXAC97_H_
+#define S3C24XXAC97_H_
+
+#define AC_CMD_ADDR(x) (x << 16)
+#define AC_CMD_DATA(x) (x & 0xffff)
+
+extern struct snd_soc_cpu_dai s3c2443_ac97_dai[];
+
+#endif /*S3C24XXAC97_H_*/
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c
index 8ca314dc8891..39f02462e07d 100644
--- a/sound/soc/s3c24xx/s3c24xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c24xx-i2s.c
@@ -344,11 +344,11 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
DBG("Entered %s\n", __FUNCTION__);
switch (div_id) {
- case S3C24XX_DIV_MCLK:
+ case S3C24XX_DIV_BCLK:
reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK;
writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
break;
- case S3C24XX_DIV_BCLK:
+ case S3C24XX_DIV_MCLK:
reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~(S3C2410_IISMOD_384FS);
writel(reg | div, s3c24xx_i2s.regs + S3C2410_IISMOD);
break;
diff --git a/sound/soc/s3c24xx/smdk2443_wm9710.c b/sound/soc/s3c24xx/smdk2443_wm9710.c
new file mode 100644
index 000000000000..d46cd811ceb3
--- /dev/null
+++ b/sound/soc/s3c24xx/smdk2443_wm9710.c
@@ -0,0 +1,85 @@
+/*
+ * smdk2443_wm9710.c -- SoC audio for smdk2443
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ * Author: Graeme Gregory
+ * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * Revision history
+ * 8th Mar 2007 Initial version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/ac97.h"
+#include "s3c24xx-pcm.h"
+#include "s3c24xx-ac97.h"
+
+static struct snd_soc_machine smdk2443;
+
+static struct snd_soc_dai_link smdk2443_dai[] = {
+{
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &s3c2443_ac97_dai[0],
+ .codec_dai = &ac97_dai,
+},
+};
+
+static struct snd_soc_machine smdk2443 = {
+ .name = "SMDK2443",
+ .dai_link = smdk2443_dai,
+ .num_links = ARRAY_SIZE(smdk2443_dai),
+};
+
+static struct snd_soc_device smdk2443_snd_ac97_devdata = {
+ .machine = &smdk2443,
+ .platform = &s3c24xx_soc_platform,
+ .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *smdk2443_snd_ac97_device;
+
+static int __init smdk2443_init(void)
+{
+ int ret;
+
+ smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+ if (!smdk2443_snd_ac97_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(smdk2443_snd_ac97_device,
+ &smdk2443_snd_ac97_devdata);
+ smdk2443_snd_ac97_devdata.dev = &smdk2443_snd_ac97_device->dev;
+ ret = platform_device_add(smdk2443_snd_ac97_device);
+
+ if (ret)
+ platform_device_put(smdk2443_snd_ac97_device);
+
+ return ret;
+}
+
+static void __exit smdk2443_exit(void)
+{
+ platform_device_unregister(smdk2443_snd_ac97_device);
+}
+
+module_init(smdk2443_init);
+module_exit(smdk2443_exit);
+
+/* Module information */
+MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig
new file mode 100644
index 000000000000..f03220d23e73
--- /dev/null
+++ b/sound/soc/sh/Kconfig
@@ -0,0 +1,38 @@
+menu "SoC Audio support for SuperH"
+
+config SND_SOC_PCM_SH7760
+ tristate "SoC Audio support for Renesas SH7760"
+ depends on CPU_SUBTYPE_SH7760 && SND_SOC && SH_DMABRG
+ help
+ Enable this option for SH7760 AC97/I2S audio support.
+
+
+##
+## Audio unit modules
+##
+
+config SND_SOC_SH4_HAC
+ select AC97_BUS
+ select SND_SOC_AC97_BUS
+ select SND_AC97_CODEC
+ tristate
+
+config SND_SOC_SH4_SSI
+ tristate
+
+
+
+##
+## Boards
+##
+
+config SND_SH7760_AC97
+ tristate "SH7760 AC97 sound support"
+ depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760
+ select SND_SOC_SH4_HAC
+ select SND_SOC_AC97_CODEC
+ help
+ This option enables generic sound support for the first
+ AC97 unit of the SH7760.
+
+endmenu
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile
new file mode 100644
index 000000000000..a8e8ab81cc6a
--- /dev/null
+++ b/sound/soc/sh/Makefile
@@ -0,0 +1,14 @@
+## DMA engines
+snd-soc-dma-sh7760-objs := dma-sh7760.o
+obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o
+
+## audio units found on some SH-4
+snd-soc-hac-objs := hac.o
+snd-soc-ssi-objs := ssi.o
+obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o
+obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
+
+## boards
+snd-soc-sh7760-ac97-objs := sh7760-ac97.o
+
+obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c
new file mode 100644
index 000000000000..cdee374b843e
--- /dev/null
+++ b/sound/soc/sh/dma-sh7760.c
@@ -0,0 +1,354 @@
+/*
+ * SH7760 ("camelot") DMABRG audio DMA unit support
+ *
+ * Copyright (C) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ * licensed under the terms outlined in the file COPYING at the root
+ * of the linux kernel sources.
+ *
+ * The SH7760 DMABRG provides 4 dma channels (2x rec, 2x play), which
+ * trigger an interrupt when one half of the programmed transfer size
+ * has been xmitted.
+ *
+ * FIXME: little-endian only for now
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <asm/dmabrg.h>
+
+
+/* registers and bits */
+#define BRGATXSAR 0x00
+#define BRGARXDAR 0x04
+#define BRGATXTCR 0x08
+#define BRGARXTCR 0x0C
+#define BRGACR 0x10
+#define BRGATXTCNT 0x14
+#define BRGARXTCNT 0x18
+
+#define ACR_RAR (1 << 18)
+#define ACR_RDS (1 << 17)
+#define ACR_RDE (1 << 16)
+#define ACR_TAR (1 << 2)
+#define ACR_TDS (1 << 1)
+#define ACR_TDE (1 << 0)
+
+/* receiver/transmitter data alignment */
+#define ACR_RAM_NONE (0 << 24)
+#define ACR_RAM_4BYTE (1 << 24)
+#define ACR_RAM_2WORD (2 << 24)
+#define ACR_TAM_NONE (0 << 8)
+#define ACR_TAM_4BYTE (1 << 8)
+#define ACR_TAM_2WORD (2 << 8)
+
+
+struct camelot_pcm {
+ unsigned long mmio; /* DMABRG audio channel control reg MMIO */
+ unsigned int txid; /* ID of first DMABRG IRQ for this unit */
+
+ struct snd_pcm_substream *tx_ss;
+ unsigned long tx_period_size;
+ unsigned int tx_period;
+
+ struct snd_pcm_substream *rx_ss;
+ unsigned long rx_period_size;
+ unsigned int rx_period;
+
+} cam_pcm_data[2] = {
+ {
+ .mmio = 0xFE3C0040,
+ .txid = DMABRGIRQ_A0TXF,
+ },
+ {
+ .mmio = 0xFE3C0060,
+ .txid = DMABRGIRQ_A1TXF,
+ },
+};
+
+#define BRGREG(x) (*(unsigned long *)(cam->mmio + (x)))
+
+/*
+ * set a minimum of 16kb per period, to avoid interrupt-"storm" and
+ * resulting skipping. In general, the bigger the minimum size, the
+ * better for overall system performance. (The SH7760 is a puny CPU
+ * with a slow SDRAM interface and poor internal bus bandwidth,
+ * *especially* when the LCDC is active). The minimum for the DMAC
+ * is 8 bytes; 16kbytes are enough to get skip-free playback of a
+ * 44kHz/16bit/stereo MP3 on a lightly loaded system, and maintain
+ * reasonable responsiveness in MPlayer.
+ */
+#define DMABRG_PERIOD_MIN 16 * 1024
+#define DMABRG_PERIOD_MAX 0x03fffffc
+#define DMABRG_PREALLOC_BUFFER 32 * 1024
+#define DMABRG_PREALLOC_BUFFER_MAX 32 * 1024
+
+/* support everything the SSI supports */
+#define DMABRG_RATES \
+ SNDRV_PCM_RATE_8000_192000
+
+#define DMABRG_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
+
+static struct snd_pcm_hardware camelot_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = DMABRG_FMTS,
+ .rates = DMABRG_RATES,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 2,
+ .channels_max = 8, /* max of the SSI */
+ .buffer_bytes_max = DMABRG_PERIOD_MAX,
+ .period_bytes_min = DMABRG_PERIOD_MIN,
+ .period_bytes_max = DMABRG_PERIOD_MAX / 2,
+ .periods_min = 2,
+ .periods_max = 2,
+ .fifo_size = 128,
+};
+
+static void camelot_txdma(void *data)
+{
+ struct camelot_pcm *cam = data;
+ cam->tx_period ^= 1;
+ snd_pcm_period_elapsed(cam->tx_ss);
+}
+
+static void camelot_rxdma(void *data)
+{
+ struct camelot_pcm *cam = data;
+ cam->rx_period ^= 1;
+ snd_pcm_period_elapsed(cam->rx_ss);
+}
+
+static int camelot_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ int ret, dmairq;
+
+ snd_soc_set_runtime_hwparams(substream, &camelot_pcm_hardware);
+
+ /* DMABRG buffer half/full events */
+ dmairq = (recv) ? cam->txid + 2 : cam->txid;
+ if (recv) {
+ cam->rx_ss = substream;
+ ret = dmabrg_request_irq(dmairq, camelot_rxdma, cam);
+ if (unlikely(ret)) {
+ pr_debug("audio unit %d irqs already taken!\n",
+ rtd->dai->cpu_dai->id);
+ return -EBUSY;
+ }
+ (void)dmabrg_request_irq(dmairq + 1,camelot_rxdma, cam);
+ } else {
+ cam->tx_ss = substream;
+ ret = dmabrg_request_irq(dmairq, camelot_txdma, cam);
+ if (unlikely(ret)) {
+ pr_debug("audio unit %d irqs already taken!\n",
+ rtd->dai->cpu_dai->id);
+ return -EBUSY;
+ }
+ (void)dmabrg_request_irq(dmairq + 1, camelot_txdma, cam);
+ }
+ return 0;
+}
+
+static int camelot_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ int dmairq;
+
+ dmairq = (recv) ? cam->txid + 2 : cam->txid;
+
+ if (recv)
+ cam->rx_ss = NULL;
+ else
+ cam->tx_ss = NULL;
+
+ dmabrg_free_irq(dmairq + 1);
+ dmabrg_free_irq(dmairq);
+
+ return 0;
+}
+
+static int camelot_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ int ret;
+
+ ret = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (ret < 0)
+ return ret;
+
+ if (recv) {
+ cam->rx_period_size = params_period_bytes(hw_params);
+ cam->rx_period = 0;
+ } else {
+ cam->tx_period_size = params_period_bytes(hw_params);
+ cam->tx_period = 0;
+ }
+ return 0;
+}
+
+static int camelot_hw_free(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int camelot_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+
+ pr_debug("PCM data: addr 0x%08ulx len %d\n",
+ (u32)runtime->dma_addr, runtime->dma_bytes);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ BRGREG(BRGATXSAR) = (unsigned long)runtime->dma_area;
+ BRGREG(BRGATXTCR) = runtime->dma_bytes;
+ } else {
+ BRGREG(BRGARXDAR) = (unsigned long)runtime->dma_area;
+ BRGREG(BRGARXTCR) = runtime->dma_bytes;
+ }
+
+ return 0;
+}
+
+static inline void dmabrg_play_dma_start(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* start DMABRG engine: XFER start, auto-addr-reload */
+ BRGREG(BRGACR) = acr | ACR_TDE | ACR_TAR | ACR_TAM_2WORD;
+}
+
+static inline void dmabrg_play_dma_stop(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* forcibly terminate data transmission */
+ BRGREG(BRGACR) = acr | ACR_TDS;
+}
+
+static inline void dmabrg_rec_dma_start(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* start DMABRG engine: recv start, auto-reload */
+ BRGREG(BRGACR) = acr | ACR_RDE | ACR_RAR | ACR_RAM_2WORD;
+}
+
+static inline void dmabrg_rec_dma_stop(struct camelot_pcm *cam)
+{
+ unsigned long acr = BRGREG(BRGACR) & ~(ACR_TDS | ACR_RDS);
+ /* forcibly terminate data receiver */
+ BRGREG(BRGACR) = acr | ACR_RDS;
+}
+
+static int camelot_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ if (recv)
+ dmabrg_rec_dma_start(cam);
+ else
+ dmabrg_play_dma_start(cam);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ if (recv)
+ dmabrg_rec_dma_stop(cam);
+ else
+ dmabrg_play_dma_stop(cam);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t camelot_pos(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct camelot_pcm *cam = &cam_pcm_data[rtd->dai->cpu_dai->id];
+ int recv = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0:1;
+ unsigned long pos;
+
+ /* cannot use the DMABRG pointer register: under load, by the
+ * time ALSA comes around to read the register, it is already
+ * far ahead (or worse, already done with the fragment) of the
+ * position at the time the IRQ was triggered, which results in
+ * fast-playback sound in my test application (ScummVM)
+ */
+ if (recv)
+ pos = cam->rx_period ? cam->rx_period_size : 0;
+ else
+ pos = cam->tx_period ? cam->tx_period_size : 0;
+
+ return bytes_to_frames(runtime, pos);
+}
+
+static struct snd_pcm_ops camelot_pcm_ops = {
+ .open = camelot_pcm_open,
+ .close = camelot_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = camelot_hw_params,
+ .hw_free = camelot_hw_free,
+ .prepare = camelot_prepare,
+ .trigger = camelot_trigger,
+ .pointer = camelot_pos,
+};
+
+static void camelot_pcm_free(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static int camelot_pcm_new(struct snd_card *card,
+ struct snd_soc_codec_dai *dai,
+ struct snd_pcm *pcm)
+{
+ /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel
+ * in MMAP mode (i.e. aplay -M)
+ */
+ snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ DMABRG_PREALLOC_BUFFER, DMABRG_PREALLOC_BUFFER_MAX);
+
+ return 0;
+}
+
+struct snd_soc_platform sh7760_soc_platform = {
+ .name = "sh7760-pcm",
+ .pcm_ops = &camelot_pcm_ops,
+ .pcm_new = camelot_pcm_new,
+ .pcm_free = camelot_pcm_free,
+};
+EXPORT_SYMBOL_GPL(sh7760_soc_platform);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SH7760 Audio DMA (DMABRG) driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
new file mode 100644
index 000000000000..8e3f03908cdb
--- /dev/null
+++ b/sound/soc/sh/hac.c
@@ -0,0 +1,322 @@
+/*
+ * Hitachi Audio Controller (AC97) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ * licensed under the terms outlined in the file COPYING at the root
+ * of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable HAC output pins!
+ */
+
+/* BIG FAT FIXME: although the SH7760 has 2 independent AC97 units, only
+ * the FIRST can be used since ASoC does not pass any information to the
+ * ac97_read/write() functions regarding WHICH unit to use. You'll have
+ * to edit the code a bit to use the other AC97 unit. --mlau
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+/* regs and bits */
+#define HACCR 0x08
+#define HACCSAR 0x20
+#define HACCSDR 0x24
+#define HACPCML 0x28
+#define HACPCMR 0x2C
+#define HACTIER 0x50
+#define HACTSR 0x54
+#define HACRIER 0x58
+#define HACRSR 0x5C
+#define HACACR 0x60
+
+#define CR_CR (1 << 15) /* "codec-ready" indicator */
+#define CR_CDRT (1 << 11) /* cold reset */
+#define CR_WMRT (1 << 10) /* warm reset */
+#define CR_B9 (1 << 9) /* the mysterious "bit 9" */
+#define CR_ST (1 << 5) /* AC97 link start bit */
+
+#define CSAR_RD (1 << 19) /* AC97 data read bit */
+#define CSAR_WR (0)
+
+#define TSR_CMDAMT (1 << 31)
+#define TSR_CMDDMT (1 << 30)
+
+#define RSR_STARY (1 << 22)
+#define RSR_STDRY (1 << 21)
+
+#define ACR_DMARX16 (1 << 30)
+#define ACR_DMATX16 (1 << 29)
+#define ACR_TX12ATOM (1 << 26)
+#define ACR_DMARX20 ((1 << 24) | (1 << 22))
+#define ACR_DMATX20 ((1 << 23) | (1 << 21))
+
+#define CSDR_SHIFT 4
+#define CSDR_MASK (0xffff << CSDR_SHIFT)
+#define CSAR_SHIFT 12
+#define CSAR_MASK (0x7f << CSAR_SHIFT)
+
+#define AC97_WRITE_RETRY 1
+#define AC97_READ_RETRY 5
+
+/* manual-suggested AC97 codec access timeouts (us) */
+#define TMO_E1 500 /* 21 < E1 < 1000 */
+#define TMO_E2 13 /* 13 < E2 */
+#define TMO_E3 21 /* 21 < E3 */
+#define TMO_E4 500 /* 21 < E4 < 1000 */
+
+struct hac_priv {
+ unsigned long mmio; /* HAC base address */
+} hac_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+ {
+ .mmio = 0xFE240000,
+ },
+ {
+ .mmio = 0xFE250000,
+ },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ {
+ .mmio = 0xFFE40000,
+ },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+#define HACREG(reg) (*(unsigned long *)(hac->mmio + (reg)))
+
+/*
+ * AC97 read/write flow as outlined in the SH7760 manual (pages 903-906)
+ */
+static int hac_get_codec_data(struct hac_priv *hac, unsigned short r,
+ unsigned short *v)
+{
+ unsigned int to1, to2, i;
+ unsigned short adr;
+
+ for (i = 0; i < AC97_READ_RETRY; ++i) {
+ *v = 0;
+ /* wait for HAC to receive something from the codec */
+ for (to1 = TMO_E4;
+ to1 && !(HACREG(HACRSR) & RSR_STARY);
+ --to1)
+ udelay(1);
+ for (to2 = TMO_E4;
+ to2 && !(HACREG(HACRSR) & RSR_STDRY);
+ --to2)
+ udelay(1);
+
+ if (!to1 && !to2)
+ return 0; /* codec comm is down */
+
+ adr = ((HACREG(HACCSAR) & CSAR_MASK) >> CSAR_SHIFT);
+ *v = ((HACREG(HACCSDR) & CSDR_MASK) >> CSDR_SHIFT);
+
+ HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+
+ if (r == adr)
+ break;
+
+ /* manual says: wait at least 21 usec before retrying */
+ udelay(21);
+ }
+ HACREG(HACRSR) &= ~(RSR_STDRY | RSR_STARY);
+ return (i < AC97_READ_RETRY);
+}
+
+static unsigned short hac_read_codec_aux(struct hac_priv *hac,
+ unsigned short reg)
+{
+ unsigned short val;
+ unsigned int i, to;
+
+ for (i = 0; i < AC97_READ_RETRY; i++) {
+ /* send_read_request */
+ local_irq_disable();
+ HACREG(HACTSR) &= ~(TSR_CMDAMT);
+ HACREG(HACCSAR) = (reg << CSAR_SHIFT) | CSAR_RD;
+ local_irq_enable();
+
+ for (to = TMO_E3;
+ to && !(HACREG(HACTSR) & TSR_CMDAMT);
+ --to)
+ udelay(1);
+
+ HACREG(HACTSR) &= ~TSR_CMDAMT;
+ val = 0;
+ if (hac_get_codec_data(hac, reg, &val) != 0)
+ break;
+ }
+
+ if (i == AC97_READ_RETRY)
+ return ~0;
+
+ return val;
+}
+
+static void hac_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac = &hac_cpu_data[unit_id];
+ unsigned int i, to;
+ /* write_codec_aux */
+ for (i = 0; i < AC97_WRITE_RETRY; i++) {
+ /* send_write_request */
+ local_irq_disable();
+ HACREG(HACTSR) &= ~(TSR_CMDDMT | TSR_CMDAMT);
+ HACREG(HACCSDR) = (val << CSDR_SHIFT);
+ HACREG(HACCSAR) = (reg << CSAR_SHIFT) & (~CSAR_RD);
+ local_irq_enable();
+
+ /* poll-wait for CMDAMT and CMDDMT */
+ for (to = TMO_E1;
+ to && !(HACREG(HACTSR) & (TSR_CMDAMT|TSR_CMDDMT));
+ --to)
+ udelay(1);
+
+ HACREG(HACTSR) &= ~(TSR_CMDAMT | TSR_CMDDMT);
+ if (to)
+ break;
+ /* timeout, try again */
+ }
+}
+
+static unsigned short hac_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac = &hac_cpu_data[unit_id];
+ return hac_read_codec_aux(hac, reg);
+}
+
+static void hac_ac97_warmrst(struct snd_ac97 *ac97)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac = &hac_cpu_data[unit_id];
+ unsigned int tmo;
+
+ HACREG(HACCR) = CR_WMRT | CR_ST | CR_B9;
+ msleep(10);
+ HACREG(HACCR) = CR_ST | CR_B9;
+ for (tmo = 1000; (tmo > 0) && !(HACREG(HACCR) & CR_CR); tmo--)
+ udelay(1);
+
+ if (!tmo)
+ printk(KERN_INFO "hac: reset: AC97 link down!\n");
+ /* settings this bit lets us have a conversation with codec */
+ HACREG(HACACR) |= ACR_TX12ATOM;
+}
+
+static void hac_ac97_coldrst(struct snd_ac97 *ac97)
+{
+ int unit_id = 0 /* ac97->private_data */;
+ struct hac_priv *hac;
+ hac = &hac_cpu_data[unit_id];
+
+ HACREG(HACCR) = 0;
+ HACREG(HACCR) = CR_CDRT | CR_ST | CR_B9;
+ msleep(10);
+ hac_ac97_warmrst(ac97);
+}
+
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = hac_ac97_read,
+ .write = hac_ac97_write,
+ .reset = hac_ac97_coldrst,
+ .warm_reset = hac_ac97_warmrst,
+};
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int hac_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct hac_priv *hac = &hac_cpu_data[rtd->dai->cpu_dai->id];
+ int d = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1;
+
+ switch (params->msbits) {
+ case 16:
+ HACREG(HACACR) |= d ? ACR_DMARX16 : ACR_DMATX16;
+ HACREG(HACACR) &= d ? ~ACR_DMARX20 : ~ACR_DMATX20;
+ break;
+ case 20:
+ HACREG(HACACR) &= d ? ~ACR_DMARX16 : ~ACR_DMATX16;
+ HACREG(HACACR) |= d ? ACR_DMARX20 : ACR_DMATX20;
+ break;
+ default:
+ pr_debug("hac: invalid depth %d bit\n", params->msbits);
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+#define AC97_RATES \
+ SNDRV_PCM_RATE_8000_192000
+
+#define AC97_FMTS \
+ SNDRV_PCM_FMTBIT_S16_LE
+
+struct snd_soc_cpu_dai sh4_hac_dai[] = {
+{
+ .name = "HAC0",
+ .id = 0,
+ .type = SND_SOC_DAI_AC97,
+ .playback = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = {
+ .hw_params = hac_hw_params,
+ },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+ .name = "HAC1",
+ .id = 1,
+ .type = SND_SOC_DAI_AC97,
+ .playback = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = AC97_RATES,
+ .formats = AC97_FMTS,
+ .channels_min = 2,
+ .channels_max = 2,
+ },
+ .ops = {
+ .hw_params = hac_hw_params,
+ },
+
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_hac_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip HAC (AC97) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/sh7760-ac97.c b/sound/soc/sh/sh7760-ac97.c
new file mode 100644
index 000000000000..5563f14511fa
--- /dev/null
+++ b/sound/soc/sh/sh7760-ac97.c
@@ -0,0 +1,92 @@
+/*
+ * Generic AC97 sound support for SH7760
+ *
+ * (c) 2007 Manuel Lauss
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/io.h>
+
+#include "../codecs/ac97.h"
+
+#define IPSEL 0xFE400034
+
+/* platform specific structs can be declared here */
+extern struct snd_soc_cpu_dai sh4_hac_dai[2];
+extern struct snd_soc_platform sh7760_soc_platform;
+
+static int machine_init(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_sync_endpoints(codec);
+ return 0;
+}
+
+static struct snd_soc_dai_link sh7760_ac97_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &sh4_hac_dai[0], /* HAC0 */
+ .codec_dai = &ac97_dai,
+ .init = machine_init,
+ .ops = NULL,
+};
+
+static struct snd_soc_machine sh7760_ac97_soc_machine = {
+ .name = "SH7760 AC97",
+ .dai_link = &sh7760_ac97_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device sh7760_ac97_snd_devdata = {
+ .machine = &sh7760_ac97_soc_machine,
+ .platform = &sh7760_soc_platform,
+ .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *sh7760_ac97_snd_device;
+
+static int __init sh7760_ac97_init(void)
+{
+ int ret;
+ unsigned short ipsel;
+
+ /* enable both AC97 controllers in pinmux reg */
+ ipsel = ctrl_inw(IPSEL);
+ ctrl_outw(ipsel | (3 << 10), IPSEL);
+
+ ret = -ENOMEM;
+ sh7760_ac97_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!sh7760_ac97_snd_device)
+ goto out;
+
+ platform_set_drvdata(sh7760_ac97_snd_device,
+ &sh7760_ac97_snd_devdata);
+ sh7760_ac97_snd_devdata.dev = &sh7760_ac97_snd_device->dev;
+ ret = platform_device_add(sh7760_ac97_snd_device);
+
+ if (ret)
+ platform_device_put(sh7760_ac97_snd_device);
+
+out:
+ return ret;
+}
+
+static void __exit sh7760_ac97_exit(void)
+{
+ platform_device_unregister(sh7760_ac97_snd_device);
+}
+
+module_init(sh7760_ac97_init);
+module_exit(sh7760_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic SH7760 AC97 sound machine");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c
new file mode 100644
index 000000000000..b72bc316cb8e
--- /dev/null
+++ b/sound/soc/sh/ssi.c
@@ -0,0 +1,400 @@
+/*
+ * Serial Sound Interface (I2S) support for SH7760/SH7780
+ *
+ * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net>
+ *
+ * licensed under the terms outlined in the file COPYING at the root
+ * of the linux kernel sources.
+ *
+ * dont forget to set IPSEL/OMSEL register bits (in your board code) to
+ * enable SSI output pins!
+ */
+
+/*
+ * LIMITATIONS:
+ * The SSI unit has only one physical data line, so full duplex is
+ * impossible. This can be remedied on the SH7760 by using the
+ * other SSI unit for recording; however the SH7780 has only 1 SSI
+ * unit, and its pins are shared with the AC97 unit, among others.
+ *
+ * FEATURES:
+ * The SSI features "compressed mode": in this mode it continuously
+ * streams PCM data over the I2S lines and uses LRCK as a handshake
+ * signal. Can be used to send compressed data (AC3/DTS) to a DSP.
+ * The number of bits sent over the wire in a frame can be adjusted
+ * and can be independent from the actual sample bit depth. This is
+ * useful to support TDM mode codecs like the AD1939 which have a
+ * fixed TDM slot size, regardless of sample resolution.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <asm/io.h>
+
+#define SSICR 0x00
+#define SSISR 0x04
+
+#define CR_DMAEN (1 << 28)
+#define CR_CHNL_SHIFT 22
+#define CR_CHNL_MASK (3 << CR_CHNL_SHIFT)
+#define CR_DWL_SHIFT 19
+#define CR_DWL_MASK (7 << CR_DWL_SHIFT)
+#define CR_SWL_SHIFT 16
+#define CR_SWL_MASK (7 << CR_SWL_SHIFT)
+#define CR_SCK_MASTER (1 << 15) /* bitclock master bit */
+#define CR_SWS_MASTER (1 << 14) /* wordselect master bit */
+#define CR_SCKP (1 << 13) /* I2Sclock polarity */
+#define CR_SWSP (1 << 12) /* LRCK polarity */
+#define CR_SPDP (1 << 11)
+#define CR_SDTA (1 << 10) /* i2s alignment (msb/lsb) */
+#define CR_PDTA (1 << 9) /* fifo data alignment */
+#define CR_DEL (1 << 8) /* delay data by 1 i2sclk */
+#define CR_BREN (1 << 7) /* clock gating in burst mode */
+#define CR_CKDIV_SHIFT 4
+#define CR_CKDIV_MASK (7 << CR_CKDIV_SHIFT) /* bitclock divider */
+#define CR_MUTE (1 << 3) /* SSI mute */
+#define CR_CPEN (1 << 2) /* compressed mode */
+#define CR_TRMD (1 << 1) /* transmit/receive select */
+#define CR_EN (1 << 0) /* enable SSI */
+
+#define SSIREG(reg) (*(unsigned long *)(ssi->mmio + (reg)))
+
+struct ssi_priv {
+ unsigned long mmio;
+ unsigned long sysclk;
+ int inuse;
+} ssi_cpu_data[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7760)
+ {
+ .mmio = 0xFE680000,
+ },
+ {
+ .mmio = 0xFE690000,
+ },
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
+ {
+ .mmio = 0xFFE70000,
+ },
+#else
+#error "Unsupported SuperH SoC"
+#endif
+};
+
+/*
+ * track usage of the SSI; it is simplex-only so prevent attempts of
+ * concurrent playback + capture. FIXME: any locking required?
+ */
+static int ssi_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ if (ssi->inuse) {
+ pr_debug("ssi: already in use!\n");
+ return -EBUSY;
+ } else
+ ssi->inuse = 1;
+ return 0;
+}
+
+static void ssi_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+ ssi->inuse = 0;
+}
+
+static int ssi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ SSIREG(SSICR) |= CR_DMAEN | CR_EN;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ SSIREG(SSICR) &= ~(CR_DMAEN | CR_EN);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ssi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ssi_priv *ssi = &ssi_cpu_data[rtd->dai->cpu_dai->id];
+ unsigned long ssicr = SSIREG(SSICR);
+ unsigned int bits, channels, swl, recv, i;
+
+ channels = params_channels(params);
+ bits = params->msbits;
+ recv = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 0 : 1;
+
+ pr_debug("ssi_hw_params() enter\nssicr was %08lx\n", ssicr);
+ pr_debug("bits: %d channels: %d\n", bits, channels);
+
+ ssicr &= ~(CR_TRMD | CR_CHNL_MASK | CR_DWL_MASK | CR_PDTA |
+ CR_SWL_MASK);
+
+ /* direction (send/receive) */
+ if (!recv)
+ ssicr |= CR_TRMD; /* transmit */
+
+ /* channels */
+ if ((channels < 2) || (channels > 8) || (channels & 1)) {
+ pr_debug("ssi: invalid number of channels\n");
+ return -EINVAL;
+ }
+ ssicr |= ((channels >> 1) - 1) << CR_CHNL_SHIFT;
+
+ /* DATA WORD LENGTH (DWL): databits in audio sample */
+ i = 0;
+ switch (bits) {
+ case 32: ++i;
+ case 24: ++i;
+ case 22: ++i;
+ case 20: ++i;
+ case 18: ++i;
+ case 16: ++i;
+ ssicr |= i << CR_DWL_SHIFT;
+ case 8: break;
+ default:
+ pr_debug("ssi: invalid sample width\n");
+ return -EINVAL;
+ }
+
+ /*
+ * SYSTEM WORD LENGTH: size in bits of half a frame over the I2S
+ * wires. This is usually bits_per_sample x channels/2; i.e. in
+ * Stereo mode the SWL equals DWL. SWL can be bigger than the
+ * product of (channels_per_slot x samplebits), e.g. for codecs
+ * like the AD1939 which only accept 32bit wide TDM slots. For
+ * "standard" I2S operation we set SWL = chans / 2 * DWL here.
+ * Waiting for ASoC to get TDM support ;-)
+ */
+ if ((bits > 16) && (bits <= 24)) {
+ bits = 24; /* these are padded by the SSI */
+ /*ssicr |= CR_PDTA;*/ /* cpu/data endianness ? */
+ }
+ i = 0;
+ swl = (bits * channels) / 2;
+ switch (swl) {
+ case 256: ++i;
+ case 128: ++i;
+ case 64: ++i;
+ case 48: ++i;
+ case 32: ++i;
+ case 16: ++i;
+ ssicr |= i << CR_SWL_SHIFT;
+ case 8: break;
+ default:
+ pr_debug("ssi: invalid system word length computed\n");
+ return -EINVAL;
+ }
+
+ SSIREG(SSICR) = ssicr;
+
+ pr_debug("ssi_hw_params() leave\nssicr is now %08lx\n", ssicr);
+ return 0;
+}
+
+static int ssi_set_sysclk(struct snd_soc_cpu_dai *cpu_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct ssi_priv *ssi = &ssi_cpu_data[cpu_dai->id];
+
+ ssi->sysclk = freq;
+
+ return 0;
+}
+
+/*
+ * This divider is used to generate the SSI_SCK (I2S bitclock) from the
+ * clock at the HAC_BIT_CLK ("oversampling clock") pin.
+ */
+static int ssi_set_clkdiv(struct snd_soc_cpu_dai *dai, int did, int div)
+{
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+ unsigned long ssicr;
+ int i;
+
+ i = 0;
+ ssicr = SSIREG(SSICR) & ~CR_CKDIV_MASK;
+ switch (div) {
+ case 16: ++i;
+ case 8: ++i;
+ case 4: ++i;
+ case 2: ++i;
+ SSIREG(SSICR) = ssicr | (i << CR_CKDIV_SHIFT);
+ case 1: break;
+ default:
+ pr_debug("ssi: invalid sck divider %d\n", div);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ssi_set_fmt(struct snd_soc_cpu_dai *dai, unsigned int fmt)
+{
+ struct ssi_priv *ssi = &ssi_cpu_data[dai->id];
+ unsigned long ssicr = SSIREG(SSICR);
+
+ pr_debug("ssi_set_fmt()\nssicr was 0x%08lx\n", ssicr);
+
+ ssicr &= ~(CR_DEL | CR_PDTA | CR_BREN | CR_SWSP | CR_SCKP |
+ CR_SWS_MASTER | CR_SCK_MASTER);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ ssicr |= CR_DEL | CR_PDTA;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ssicr |= CR_DEL;
+ break;
+ default:
+ pr_debug("ssi: unsupported format\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+ case SND_SOC_DAIFMT_CONT:
+ break;
+ case SND_SOC_DAIFMT_GATED:
+ ssicr |= CR_BREN;
+ break;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ ssicr |= CR_SCKP; /* sample data at low clkedge */
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ ssicr |= CR_SCKP | CR_SWSP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ ssicr |= CR_SWSP; /* word select starts low */
+ break;
+ default:
+ pr_debug("ssi: invalid inversion\n");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ break;
+ case SND_SOC_DAIFMT_CBS_CFM:
+ ssicr |= CR_SCK_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ ssicr |= CR_SWS_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ ssicr |= CR_SWS_MASTER | CR_SCK_MASTER;
+ break;
+ default:
+ pr_debug("ssi: invalid master/slave configuration\n");
+ return -EINVAL;
+ }
+
+ SSIREG(SSICR) = ssicr;
+ pr_debug("ssi_set_fmt() leave\nssicr is now 0x%08lx\n", ssicr);
+
+ return 0;
+}
+
+/* the SSI depends on an external clocksource (at HAC_BIT_CLK) even in
+ * Master mode, so really this is board specific; the SSI can do any
+ * rate with the right bitclk and divider settings.
+ */
+#define SSI_RATES \
+ SNDRV_PCM_RATE_8000_192000
+
+/* the SSI can do 8-32 bit samples, with 8 possible channels */
+#define SSI_FMTS \
+ (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_U24_3LE | \
+ SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE)
+
+struct snd_soc_cpu_dai sh4_ssi_dai[] = {
+{
+ .name = "SSI0",
+ .id = 0,
+ .type = SND_SOC_DAI_I2S,
+ .playback = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .capture = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .ops = {
+ .startup = ssi_startup,
+ .shutdown = ssi_shutdown,
+ .trigger = ssi_trigger,
+ .hw_params = ssi_hw_params,
+ },
+ .dai_ops = {
+ .set_sysclk = ssi_set_sysclk,
+ .set_clkdiv = ssi_set_clkdiv,
+ .set_fmt = ssi_set_fmt,
+ },
+},
+#ifdef CONFIG_CPU_SUBTYPE_SH7760
+{
+ .name = "SSI1",
+ .id = 1,
+ .type = SND_SOC_DAI_I2S,
+ .playback = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .capture = {
+ .rates = SSI_RATES,
+ .formats = SSI_FMTS,
+ .channels_min = 2,
+ .channels_max = 8,
+ },
+ .ops = {
+ .startup = ssi_startup,
+ .shutdown = ssi_shutdown,
+ .trigger = ssi_trigger,
+ .hw_params = ssi_hw_params,
+ },
+ .dai_ops = {
+ .set_sysclk = ssi_set_sysclk,
+ .set_clkdiv = ssi_set_clkdiv,
+ .set_fmt = ssi_set_fmt,
+ },
+},
+#endif
+};
+EXPORT_SYMBOL_GPL(sh4_ssi_dai);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SuperH onchip SSI (I2S) audio driver");
+MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 8ebc1adb5ed9..7bd5852fcc0d 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -2350,7 +2350,9 @@ static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *
return 1;
break;
case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
- return 1;
+ if (device_setup[chip->index] == 0x00 ||
+ fp->altsetting==1 || fp->altsetting==2 || fp->altsetting==3)
+ return 1;
}
return 0;
}
@@ -2530,7 +2532,18 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *
* but we give normal PCM format to get the existing
* apps working...
*/
- pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+ switch (chip->usb_id) {
+
+ case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */
+ if (device_setup[chip->index] == 0x00 &&
+ fp->altsetting == 6)
+ pcm_format = SNDRV_PCM_FORMAT_S16_BE;
+ else
+ pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ default:
+ pcm_format = SNDRV_PCM_FORMAT_S16_LE;
+ }
} else {
pcm_format = parse_audio_format_i_type(chip, fp, format, fmt);
if (pcm_format < 0)
@@ -3251,6 +3264,11 @@ static int snd_usb_cm106_boot_quirk(struct usb_device *dev)
static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip,
int iface, int altno)
{
+ /* Reset ALL ifaces to 0 altsetting.
+ * Call it for every possible altsetting of every interface.
+ */
+ usb_set_interface(chip->dev, iface, 0);
+
if (device_setup[chip->index] & AUDIOPHILE_SET) {
if ((device_setup[chip->index] & AUDIOPHILE_SET_DTS)
&& altno != 6)
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h
index 374fbf657a2d..5a2f518c6629 100644
--- a/sound/usb/usbquirks.h
+++ b/sound/usb/usbquirks.h
@@ -57,6 +57,24 @@
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,
.idVendor = 0x046d,
+ .idProduct = 0x08ae,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
+{
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+ USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ .idVendor = 0x046d,
+ .idProduct = 0x08c6,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
+},
+{
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
+ USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ .idVendor = 0x046d,
.idProduct = 0x08f0,
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL
@@ -1051,7 +1069,15 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.type = QUIRK_MIDI_STANDARD_INTERFACE
}
},
- /* TODO: add Roland EXR support */
+{
+ USB_DEVICE(0x0582, 0x0060),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Roland",
+ .product_name = "EXR Series",
+ .ifnum = 0,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ }
+},
{
/* has ID 0x0067 when not in "Advanced Driver" mode */
USB_DEVICE(0x0582, 0x0065),
@@ -1094,6 +1120,19 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+{
+ USB_DEVICE(0x582, 0x00a6),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Roland",
+ .product_name = "Juno-G",
+ .ifnum = 0,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ }
+},
{ /*
* This quirk is for the "Advanced" modes of the Edirol UA-25.
* If the switch is not in an advanced setting, the UA-25 has
@@ -1230,6 +1269,37 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
/* TODO: add Edirol MD-P1 support */
+{
+ /* Roland SH-201 */
+ USB_DEVICE(0x0582, 0x00ad),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Roland",
+ .product_name = "SH-201",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0001,
+ .in_cables = 0x0001
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
/* Guillemot devices */
{
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 0a352e46862f..48e9aa3f18c9 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -935,10 +935,9 @@ static struct snd_pcm_ops snd_usX2Y_pcm_ops =
*/
static void usX2Y_audio_stream_free(struct snd_usX2Y_substream **usX2Y_substream)
{
- if (NULL != usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]) {
- kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
- usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
- }
+ kfree(usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]);
+ usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK] = NULL;
+
kfree(usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]);
usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE] = NULL;
}
diff --git a/usr/.gitignore b/usr/.gitignore
index be186a82e8d0..69b2e89fa165 100644
--- a/usr/.gitignore
+++ b/usr/.gitignore
@@ -5,3 +5,4 @@ gen_init_cpio
initramfs_data.cpio
initramfs_data.cpio.gz
initramfs_list
+include
diff --git a/usr/gen_init_cpio.c b/usr/gen_init_cpio.c
index 8365db6cfe06..7abc07f0fcd2 100644
--- a/usr/gen_init_cpio.c
+++ b/usr/gen_init_cpio.c
@@ -498,7 +498,9 @@ int main (int argc, char *argv[])
exit(1);
}
- if (! (cpio_list = fopen(argv[1], "r"))) {
+ if (!strcmp(argv[1], "-"))
+ cpio_list = stdin;
+ else if (! (cpio_list = fopen(argv[1], "r"))) {
fprintf(stderr, "ERROR: unable to open '%s': %s\n\n",
argv[1], strerror(errno));
usage(argv[0]);